GIT 8a03d9a498eaf02c8a118752050a5154852c13bf git+ssh://master.kernel.org/pub/scm/linux/kernel/git/torvalds/linux-2.6.git commit 0187f221e96e3436d552c0c7143f183eb82fb658 Author: Ben Dooks Date: Fri Feb 16 01:28:42 2007 -0800 [PATCH] s3c2410fb: fix un-initialised dev field The current driver is not setting the dev field in the private data structure, which can lead to an OOPS if the driver tries to report an error. Signed-off-by: Ben Dooks Cc: James Simmons Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit 008983d9669b80ac628b6b09ce4d78e75844b294 Author: Thomas Hisch Date: Fri Feb 16 01:28:41 2007 -0800 [PATCH] ecryptfs: fix forgotten format specifier Add format specifier %d for uid in ecryptfs_printk Signed-off-by: Thomas Hisch Cc: Michael Halcrow Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit eb95e7ffa50fa2921ef1845a5dcb2fe5b21e83a2 Author: Michael Halcrow Date: Fri Feb 16 01:28:40 2007 -0800 [PATCH] eCryptfs: Reduce stack usage in ecryptfs_generate_key_packet_set() eCryptfs is gobbling a lot of stack in ecryptfs_generate_key_packet_set() because it allocates a temporary memory-hungry ecryptfs_key_record struct. This patch introduces a new kmem_cache for that struct and converts ecryptfs_generate_key_packet_set() to use it. Signed-off-by: Michael Halcrow Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit 29dbb3fc8020f025bc38b262ec494e19fd3eac02 Author: NeilBrown Date: Fri Feb 16 01:28:38 2007 -0800 [PATCH] knfsd: stop NFSD writes from being broken into lots of little writes to filesystem When NFSD receives a write request, the data is typically in a number of 1448 byte segments and writev is used to collect them together. Unfortunately, generic_file_buffered_write passes these to the filesystem one at a time, so an e.g. 32K over-write becomes a series of partial-page writes to each page, causing the filesystem to have to pre-read those pages - wasted effort. generic_file_buffered_write handles one segment of the vector at a time as it has to pre-fault in each segment to avoid deadlocks. When writing from kernel-space (and nfsd does) this is not an issue, so generic_file_buffered_write does not need to break and iovec from nfsd into little pieces. This patch avoids the splitting when get_fs is KERNEL_DS as it is from NFSd. This issue was introduced by commit 6527c2bdf1f833cc18e8f42bd97973d583e4aa83 Acked-by: Nick Piggin Cc: Norman Weathers Cc: Vladimir V. Saveliev Signed-off-by: Neil Brown Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit 3160a711ef754758e7f85ae371cf900252c1a392 Author: J. Bruce Fields Date: Fri Feb 16 01:28:37 2007 -0800 [PATCH] knfsd: nfsd4: fix handling of directories without default ACLs When setting an ACL that lacks inheritable ACEs on a directory, we should set a default ACL of zero length, not a default ACL with all bits denied. Signed-off-by: "J. Bruce Fields" Signed-off-by: Neil Brown Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit bec50c47aaf6f1f9247f1860547ab394a0802a4c Author: J. Bruce Fields Date: Fri Feb 16 01:28:36 2007 -0800 [PATCH] knfsd: nfsd4: acls: avoid unnecessary denies We're inserting deny's between some ACEs in order to enforce posix draft acl semantics which prevent permissions from accumulating across entries in an acl. That's fine, but we're doing that by inserting a deny after *every* allow, which is overkill. We shouldn't be adding them in places where they actually make no difference. Also replaced some helper functions for creating acl entries; I prefer just assigning directly to the struct fields--it takes a few more lines, but the field names provide some documentation that I think makes the result easier understand. Signed-off-by: J. Bruce Fields Signed-off-by: Neil Brown Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit f43daf67871d9da5c638994416b4144eac63c992 Author: J. Bruce Fields Date: Fri Feb 16 01:28:34 2007 -0800 [PATCH] knfsd: nfsd4: acls: don't return explicit mask Return just the effective permissions, and forget about the mask. It isn't worth the complexity. WARNING: This breaks backwards compatibility with overly-picky nfsv4->posix acl translation, as may has been included in some patched versions of libacl. To our knowledge no such version was every distributed by anyone outside citi. Signed-off-by: J. Bruce Fields Signed-off-by: Neil Brown Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit f34f924274ad8f84c6d86ea9e52b0682347f5701 Author: J. Bruce Fields Date: Fri Feb 16 01:28:34 2007 -0800 [PATCH] knfsd: nfsd4: fix error return on unsupported acl We should be returning ATTRNOTSUPP, not NOTSUPP, when acls are unsupported. Also fix a comment. Signed-off-by: "J. Bruce Fields" Signed-off-by: Neil Brown Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit a4db5fe5dfb3a5b5b550f1acd95ef3de01a3f063 Author: J. Bruce Fields Date: Fri Feb 16 01:28:30 2007 -0800 [PATCH] knfsd: nfsd4: fix memory leak on kmalloc failure in savemem The wrong pointer is being kfree'd in savemem() when defer_free returns with an error. Signed-off-by: Benny Halevy Signed-off-by: J. Bruce Fields Signed-off-by: Neil Brown Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit 28e05dd8457c7a7fa1c3faac169a95e0ce4b4a12 Author: J. Bruce Fields Date: Fri Feb 16 01:28:30 2007 -0800 [PATCH] knfsd: nfsd4: represent nfsv4 acl with array instead of linked list Simplify the memory management and code a bit by representing acls with an array instead of a linked list. Signed-off-by: J. Bruce Fields Signed-off-by: Neil Brown Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit 575a6290f035b16e3301014d9b176422ec9062bb Author: J. Bruce Fields Date: Fri Feb 16 01:28:29 2007 -0800 [PATCH] knfsd: nfsd4: simplify nfsv4->posix translation The code that splits an incoming nfsv4 ACL into inheritable and effective parts can be combined with the the code that translates each to a posix acl, resulting in simpler code that requires one less pass through the ACL. Signed-off-by: "J. Bruce Fields" Signed-off-by: Neil Brown Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit 7bdfa68c5e70b815e85dab0bdd9f48ec103c4002 Author: J. Bruce Fields Date: Fri Feb 16 01:28:28 2007 -0800 [PATCH] knfsd: nfsd4: relax checking of ACL inheritance bits The rfc allows us to be more permissive about the ACL inheritance bits we accept: "If the server supports a single "inherit ACE" flag that applies to both files and directories, the server may reject the request (i.e., requiring the client to set both the file and directory inheritance flags). The server may also accept the request and silently turn on the ACE4_DIRECTORY_INHERIT_ACE flag." Let's take the latter option--the ACL is a complex attribute that could be rejected for a wide variety of reasons, and the protocol gives us little ability to explain the reason for the rejection, so erroring out is a user-unfriendly last resort. Signed-off-by: J. Bruce Fields Signed-off-by: Neil Brown Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit f534a257acfd9dae0a689be64397919907b283ba Author: J. Bruce Fields Date: Fri Feb 16 01:28:27 2007 -0800 [PATCH] knfsd: nfsd4: fix non-terminated string The server name is expected to be a null-terminated string, so we can't pass in the raw client identifier. What's more, the client identifier is just a binary, not necessarily printable, blob. Let's just use the ip address instead. The server name appears to exist just to help debugging by making some printk's more informative. Note that the string is copies into the rpc client structure, so the pointer to the local variable does not outlive the function call. Signed-off-by: "J. Bruce Fields" Signed-off-by: Neil Brown Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit 5575ddf75ca7e61d6f69b96368e03dd88edd4604 Author: Jan Beulich Date: Fri Feb 16 01:28:26 2007 -0800 [PATCH] small irq management simplification Use mask_ack_irq() where possible. Signed-off-by: Jan Beulich Cc: Thomas Gleixner Cc: Ingo Molnar Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit 472900b8b02bf3782b06dcf0acdef26811c2b995 Author: Randy Dunlap Date: Fri Feb 16 01:28:25 2007 -0800 [PATCH] IRQ kernel-doc fixes Fix kernel-doc warnings in IRQ management. Signed-off-by: Randy Dunlap Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit d7e25f3394ba05a6d64cb2be42c2765fe72ea6b2 Author: Ingo Molnar Date: Fri Feb 16 01:28:24 2007 -0800 [PATCH] genirq: remove IRQ_DISABLED Now that disable_irq() defaults to delayed-disable semantics, the IRQ_DISABLED flag is not needed anymore. Signed-off-by: Ingo Molnar Cc: Thomas Gleixner Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit 76d2160147f43f982dfe881404cfde9fd0a9da21 Author: Ingo Molnar Date: Fri Feb 16 01:28:24 2007 -0800 [PATCH] genirq: do not mask interrupts by default Never mask interrupts immediately upon request. Disabling interrupts in high-performance codepaths is rare, and on the other hand this change could recover lost edges (or even other types of lost interrupts) by conservatively only masking interrupts after they happen. (NOTE: with this change the highlevel irq-disable code still soft-disables this IRQ line - and if such an interrupt happens then the IRQ flow handler keeps the IRQ masked.) Mark i8529A controllers as 'never loses an edge'. Signed-off-by: Ingo Molnar Cc: Thomas Gleixner Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit 1f2ea0837dbc263ce2a2512c4e73c83df68a6a55 Author: Paul E. McKenney Date: Fri Feb 16 01:28:22 2007 -0800 [PATCH] posix timers: RCU optimization for clock_gettime() Use RCU to avoid the need to acquire tasklist_lock in the single-threaded case of clock_gettime(). It still acquires tasklist_lock when for a (potentially multithreaded) process. This change allows realtime applications to frequently monitor CPU consumption of individual tasks, as requested (and now deployed) by some off-list users. This has been in Ingo Molnar's -rt patchset since late 2005 with no problems reported, and tests successfully on 2.6.20-rc6, so I believe that it is long-since ready for mainline adoption. [paulmck@linux.vnet.ibm.com: fix exit()/posix_cpu_clock_get() race spotted by Oleg] Signed-off-by: Paul E. McKenney Signed-off-by: Ingo Molnar Cc: Thomas Gleixner Cc: john stultz Cc: Roman Zippel Cc: Oleg Nesterov Signed-off-by: Paul E. McKenney Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit 7460ed2844ffad7141e30271c0c3da8336e66014 Author: john stultz Date: Fri Feb 16 01:28:21 2007 -0800 [PATCH] time: x86_64: re-enable vsyscall support for x86_64 Cleanup and re-enable vsyscall gettimeofday using the generic clocksource infrastructure. [akpm@osdl.org: cleanup] Signed-off-by: John Stultz Cc: Ingo Molnar Cc: Thomas Gleixner Cc: Andi Kleen Cc: Roman Zippel Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit 1489939f0ab64b96998e04068c516c39afe29654 Author: john stultz Date: Fri Feb 16 01:28:20 2007 -0800 [PATCH] time: x86_64: convert x86_64 to use GENERIC_TIME This patch converts x86_64 to use the GENERIC_TIME infrastructure and adds clocksource structures for both TSC and HPET (ACPI PM is shared w/ i386). [akpm@osdl.org: fix printk timestamps] [akpm@osdl.org: fix printk ckeanups] [akpm@osdl.org: hpet build fix] Signed-off-by: John Stultz Cc: Ingo Molnar Cc: Thomas Gleixner Cc: Andi Kleen Cc: Roman Zippel Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit c37e7bb5d2ce36ef377caabfced0b132bb1bf6a7 Author: john stultz Date: Fri Feb 16 01:28:19 2007 -0800 [PATCH] time: x86_64: split x86_64/kernel/time.c up In preparation for the x86_64 generic time conversion, this patch splits out TSC and HPET related code from arch/x86_64/kernel/time.c into respective hpet.c and tsc.c files. [akpm@osdl.org: fix printk timestamps] [akpm@osdl.org: cleanup] Signed-off-by: John Stultz Cc: Ingo Molnar Cc: Thomas Gleixner Cc: Andi Kleen Cc: Roman Zippel Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit 2d0c87c3bc49c60ab5bbac401fb1ef37ff10bbe2 Author: john stultz Date: Fri Feb 16 01:28:18 2007 -0800 [PATCH] time: x86_64: hpet_address cleanup In preparation for supporting generic timekeeping, this patch cleans up x86-64's use of vxtime.hpet_address, changing it to just hpet_address as is also used in i386. This is necessary since the vxtime structure will be going away. Signed-off-by: John Stultz Cc: Ingo Molnar Cc: Thomas Gleixner Cc: Andi Kleen Cc: Roman Zippel Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit acc9a9dcdd0dd1d295c2f2ee02c27c761bd63cb1 Author: john stultz Date: Fri Feb 16 01:28:17 2007 -0800 [PATCH] generic: vsyscall-gtod support for GENERIC_TIME Provides generic infrastructure for vsyscall-gtod. [akpm@osdl.org: cleanup] Signed-off-by: John Stultz Cc: Ingo Molnar Cc: Thomas Gleixner Cc: Andi Kleen Cc: Roman Zippel Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit 88ad0bf6890505cbd9ca1dbb79944a27b5c8697d Author: Ingo Molnar Date: Fri Feb 16 01:28:16 2007 -0800 [PATCH] Add SysRq-Q to print timer_list debug info Add SysRq-Q to print pending timers and other timer info. Signed-off-by: Ingo Molnar Signed-off-by: Thomas Gleixner Cc: john stultz Cc: Roman Zippel Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit 289f480af87e45f7a6de6ba9b4c061c2e259fe98 Author: Ingo Molnar Date: Fri Feb 16 01:28:15 2007 -0800 [PATCH] Add debugging feature /proc/timer_list add /proc/timer_list, which prints all currently pending (high-res) timers, all clock-event sources and their parameters in a human-readable form. Sample output: Timer List Version: v0.1 HRTIMER_MAX_CLOCK_BASES: 2 now at 4246046273872 nsecs cpu: 0 clock 0: .index: 0 .resolution: 1 nsecs .get_time: ktime_get_real .offset: 1273998312645738432 nsecs active timers: clock 1: .index: 1 .resolution: 1 nsecs .get_time: ktime_get .offset: 0 nsecs active timers: #0: , hrtimer_sched_tick, hrtimer_stop_sched_tick, swapper/0 # expires at 4246432689566 nsecs [in 386415694 nsecs] #1: , hrtimer_wakeup, do_nanosleep, pcscd/2050 # expires at 4247018194689 nsecs [in 971920817 nsecs] #2: , hrtimer_wakeup, do_nanosleep, irqbalance/1909 # expires at 4247351358392 nsecs [in 1305084520 nsecs] #3: , hrtimer_wakeup, do_nanosleep, crond/2157 # expires at 4249097614968 nsecs [in 3051341096 nsecs] #4: , it_real_fn, do_setitimer, syslogd/1888 # expires at 4251329900926 nsecs [in 5283627054 nsecs] .expires_next : 4246432689566 nsecs .hres_active : 1 .check_clocks : 0 .nr_events : 31306 .idle_tick : 4246020791890 nsecs .tick_stopped : 1 .idle_jiffies : 986504 .idle_calls : 40700 .idle_sleeps : 36014 .idle_entrytime : 4246019418883 nsecs .idle_sleeptime : 4178181972709 nsecs cpu: 1 clock 0: .index: 0 .resolution: 1 nsecs .get_time: ktime_get_real .offset: 1273998312645738432 nsecs active timers: clock 1: .index: 1 .resolution: 1 nsecs .get_time: ktime_get .offset: 0 nsecs active timers: #0: , hrtimer_sched_tick, hrtimer_restart_sched_tick, swapper/0 # expires at 4246050084568 nsecs [in 3810696 nsecs] #1: , hrtimer_wakeup, do_nanosleep, atd/2227 # expires at 4261010635003 nsecs [in 14964361131 nsecs] #2: , hrtimer_wakeup, do_nanosleep, smartd/2332 # expires at 5469485798970 nsecs [in 1223439525098 nsecs] .expires_next : 4246050084568 nsecs .hres_active : 1 .check_clocks : 0 .nr_events : 24043 .idle_tick : 4246046084568 nsecs .tick_stopped : 0 .idle_jiffies : 986510 .idle_calls : 26360 .idle_sleeps : 22551 .idle_entrytime : 4246043874339 nsecs .idle_sleeptime : 4170763761184 nsecs tick_broadcast_mask: 00000003 event_broadcast_mask: 00000001 CPU#0's local event device: Clock Event Device: lapic capabilities: 0000000e max_delta_ns: 807385544 min_delta_ns: 1443 mult: 44624025 shift: 32 set_next_event: lapic_next_event set_mode: lapic_timer_setup event_handler: hrtimer_interrupt .installed: 1 .expires: 4246432689566 nsecs CPU#1's local event device: Clock Event Device: lapic capabilities: 0000000e max_delta_ns: 807385544 min_delta_ns: 1443 mult: 44624025 shift: 32 set_next_event: lapic_next_event set_mode: lapic_timer_setup event_handler: hrtimer_interrupt .installed: 1 .expires: 4246050084568 nsecs Clock Event Device: hpet capabilities: 00000007 max_delta_ns: 2147483647 min_delta_ns: 3352 mult: 61496110 shift: 32 set_next_event: hpet_next_event set_mode: hpet_set_mode event_handler: handle_nextevt_broadcast Signed-off-by: Ingo Molnar Signed-off-by: Thomas Gleixner Cc: john stultz Cc: Roman Zippel Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit 82f67cd9fca8c8762c15ba7ed0d5747588c1e221 Author: Ingo Molnar Date: Fri Feb 16 01:28:13 2007 -0800 [PATCH] Add debugging feature /proc/timer_stat Add /proc/timer_stats support: debugging feature to profile timer expiration. Both the starting site, process/PID and the expiration function is captured. This allows the quick identification of timer event sources in a system. Sample output: # echo 1 > /proc/timer_stats # cat /proc/timer_stats Timer Stats Version: v0.1 Sample period: 4.010 s 24, 0 swapper hrtimer_stop_sched_tick (hrtimer_sched_tick) 11, 0 swapper sk_reset_timer (tcp_delack_timer) 6, 0 swapper hrtimer_stop_sched_tick (hrtimer_sched_tick) 2, 1 swapper queue_delayed_work_on (delayed_work_timer_fn) 17, 0 swapper hrtimer_restart_sched_tick (hrtimer_sched_tick) 2, 1 swapper queue_delayed_work_on (delayed_work_timer_fn) 4, 2050 pcscd do_nanosleep (hrtimer_wakeup) 5, 4179 sshd sk_reset_timer (tcp_write_timer) 4, 2248 yum-updatesd schedule_timeout (process_timeout) 18, 0 swapper hrtimer_restart_sched_tick (hrtimer_sched_tick) 3, 0 swapper sk_reset_timer (tcp_delack_timer) 1, 1 swapper neigh_table_init_no_netlink (neigh_periodic_timer) 2, 1 swapper e1000_up (e1000_watchdog) 1, 1 init schedule_timeout (process_timeout) 100 total events, 25.24 events/sec [ cleanups and hrtimers support from Thomas Gleixner ] [bunk@stusta.de: nr_entries can become static] Signed-off-by: Ingo Molnar Signed-off-by: Thomas Gleixner Cc: john stultz Cc: Roman Zippel Cc: Andi Kleen Signed-off-by: Adrian Bunk Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit 8bfd9a7a229b5f3d3eda5d7d45c2eebec5b4ba16 Author: Thomas Gleixner Date: Fri Feb 16 01:28:12 2007 -0800 [PATCH] hrtimers: prevent possible itimer DoS Fix potential setitimer DoS with high-res timers by pushing itimer rearm processing to process context. [Fixes from: Ingo Molnar ] Signed-off-by: Thomas Gleixner Signed-off-by: Ingo Molnar Cc: john stultz Cc: Roman Zippel Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit 54cdfdb47f73b5af3d1ebb0f1e383efbe70fde9e Author: Thomas Gleixner Date: Fri Feb 16 01:28:11 2007 -0800 [PATCH] hrtimers: add high resolution timer support Implement high resolution timers on top of the hrtimers infrastructure and the clockevents / tick-management framework. This provides accurate timers for all hrtimer subsystem users. Signed-off-by: Thomas Gleixner Signed-off-by: Ingo Molnar Cc: john stultz Cc: Roman Zippel Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit d40891e75fc1f646dce57d5d3bd1349a6aaf7a0e Author: Ingo Molnar Date: Fri Feb 16 01:28:10 2007 -0800 [PATCH] i386: enable dynticks in kconfig Enable dynamic ticks selection. Signed-off-by: Ingo Molnar Cc: john stultz Cc: Roman Zippel Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit f8b5035b9abd01b52ec6416f0c6bade7e603742c Author: Thomas Gleixner Date: Fri Feb 16 01:28:09 2007 -0800 [PATCH] i386 prepare nmi watchdog for dynticks The NMI watchdog implementation assumes that the local APIC timer interrupt is happening. This assumption is not longer true when high resolution timers and dynamic ticks come into play, as they may switch off the local APIC timer completely. Take the PIT/HPET interrupts into account too, to avoid false positives. Signed-off-by: Thomas Gleixner Signed-off-by: Ingo Molnar Cc: Andi Kleen Cc: Zachary Amsden Cc: "Eric W. Biederman" Cc: Rohit Seth Cc: john stultz Cc: Roman Zippel Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit 741673473a5b26497d5390f38d478362e27e22ad Author: Ingo Molnar Date: Fri Feb 16 01:28:07 2007 -0800 [PATCH] i386 prepare for dyntick Prepare i386 for dyntick: idle handler callbacks. Signed-off-by: Ingo Molnar Signed-off-by: Thomas Gleixner Cc: john stultz Cc: Roman Zippel Cc: Andi Kleen Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit d36b49b91065dbfa305c5a66010b3497c741eee0 Author: Thomas Gleixner Date: Fri Feb 16 01:28:06 2007 -0800 [PATCH] i386 rework local apic timer calibration The local apic timer calibration has two problem cases: 1. The calibration is based on readout of the PIT/HPET timer to detect the wrap of the periodic tick. It happens that a box gets stuck in the calibration loop due to a PIT with a broken readout function. 2. CoreDuo boxen show a sporadic PIT runs too slow defect, which results in a wrong lapic calibration. The PIT goes back to normal operation once the lapic timer is switched to periodic mode. Both are existing and unfixed problems in the current upstream kernel and prevent certain laptops and other systems from booting Linux. Rework the code to address both problems: - Make the calibration interrupt driven. This removes the wait_timer_tick magic hackery from lapic.c and time_hpet.c. The clockevents framework allows easy substitution of the global tick event handler for the calibration. This is more accurate than monitoring jiffies. At this point of the boot process, nothing disturbes the interrupt delivery, so the results are very accurate. - Verify the calibration against the PM timer, when available by using the early access function. When the measured calibration period is outside of an one percent window, then the lapic timer calibration is adjusted to the pm timer result. - Verify the calibration by running the lapic timer with the calibration handler. Disable lapic timer in case of deviation. This also removes the "synchronization" of the local apic timer to the global tick. This synchronization never worked, as there is no way to synchronize PIT(HPET) and local APIC timer. The synchronization by waiting for the tick just alignes the local APIC timer for the first events, but later the events drift away due to the different clocks. Removing the "sync" is just randomizing the asynchronous behaviour at setup time. Signed-off-by: Thomas Gleixner Signed-off-by: Ingo Molnar Cc: Zachary Amsden Cc: "Eric W. Biederman" Cc: Rohit Seth Cc: Andi Kleen Cc: john stultz Cc: Roman Zippel Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit e9e2cdb412412326c4827fc78ba27f410d837e6e Author: Thomas Gleixner Date: Fri Feb 16 01:28:04 2007 -0800 [PATCH] clockevents: i386 drivers Add clockevent drivers for i386: lapic (local) and PIT/HPET (global). Update the timer IRQ to call into the PIT/HPET driver's event handler and the lapic-timer IRQ to call into the lapic clockevent driver. The assignement of timer functionality is delegated to the core framework code and replaces the compile and runtime evalution in do_timer_interrupt_hook() Use the clockevents broadcast support and implement the lapic_broadcast function for ACPI. No changes to existing functionality. [ kdump fix from Vivek Goyal ] [ fixes based on review feedback from Arjan van de Ven ] Cleanups-from: Adrian Bunk Build-fixes-from: Andrew Morton Signed-off-by: Thomas Gleixner Signed-off-by: Ingo Molnar Cc: john stultz Cc: Roman Zippel Cc: Andi Kleen Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit 79bf2bb335b85db25d27421c798595a2fa2a0e82 Author: Thomas Gleixner Date: Fri Feb 16 01:28:03 2007 -0800 [PATCH] tick-management: dyntick / highres functionality With Ingo Molnar Add functions to provide dynamic ticks and high resolution timers. The code which keeps track of jiffies and handles the long idle periods is shared between tick based and high resolution timer based dynticks. The dyntick functionality can be disabled on the kernel commandline. Provide also the infrastructure to support high resolution timers. Signed-off-by: Thomas Gleixner Signed-off-by: Ingo Molnar Cc: john stultz Cc: Roman Zippel Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit f8381cba04ba8173fd5a2b8e5cd8b3290ee13a98 Author: Thomas Gleixner Date: Fri Feb 16 01:28:02 2007 -0800 [PATCH] tick-management: broadcast functionality With Ingo Molnar Add broadcast functionality, so per cpu clock event devices can be registered as dummy devices or switched from/to broadcast on demand. The broadcast function distributes the events via the broadcast function of the clock event device. This is primarily designed to replace the switch apic timer to / from IPI in power states, where the apic stops. Signed-off-by: Thomas Gleixner Signed-off-by: Ingo Molnar Cc: john stultz Cc: Roman Zippel Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit 906568c9c668ff994f4078932ec6ae1e3950d1af Author: Thomas Gleixner Date: Fri Feb 16 01:28:01 2007 -0800 [PATCH] tick-management: core functionality With Ingo Molnar The tick-management code is the first user of the clockevents layer. It takes clock event devices from the clock events core and uses them to provide the periodic tick. Signed-off-by: Thomas Gleixner Signed-off-by: Ingo Molnar Cc: john stultz Cc: Roman Zippel Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit d316c57ff6bfad9557462b9100f25c6260d2b774 Author: Thomas Gleixner Date: Fri Feb 16 01:28:00 2007 -0800 [PATCH] clockevents: add core functionality Architectures register their clock event devices, in the clock events core. Users of the clockevents core can get clock event devices for their use. The clockevents core code provides notification mechanisms for various clock related management events. This allows to control the clock event devices without the architectures having to worry about the details of function assignment. This is also a preliminary for high resolution timers and dynamic ticks to allow the core code to control the clock functionality without intrusive changes to the architecture code. [Fixes-by: Ingo Molnar ] Signed-off-by: Thomas Gleixner Signed-off-by: Ingo Molnar Cc: Roman Zippel Cc: john stultz Cc: Andi Kleen Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit e05d723f98595b2f4d368f63636a997d98703304 Author: Thomas Gleixner Date: Fri Feb 16 01:27:58 2007 -0800 [PATCH] i386, apic: clean up the APIC code The apic code is quite unstructured and missing a lot of comments. - Restructure the code into helper functions, timer, setup/shutdown, interrupt and power management blocks. - Fixup comments. - Namespace fixups - Inline helpers for version and is_integrated - Combine the ack_bad_irq functions No functional changes. Signed-off-by: Thomas Gleixner Signed-off-by: Ingo Molnar Cc: Zachary Amsden Cc: "Eric W. Biederman" Cc: Rohit Seth Cc: Andi Kleen Cc: john stultz Cc: Roman Zippel Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit d66bea57e779cd592657cca6e61345ae899b78d9 Author: Thomas Gleixner Date: Fri Feb 16 01:27:57 2007 -0800 [PATCH] Allow early access to the power management timer Allow early access to the power management timer by exposing the verified read function and providing a helper function which checks the pmtmr_ioport variable and returns either the pm timer readout or 0 in case the pm timer is not available. Create a new header file and replace also the ifdef'ed extern definition in arch/i386/kernel/acpi/boot.c This is a preperatory patch for the rework of the local apic timer calibration. No functional changes. Signed-off-by: Thomas Gleixner Signed-off-by: Ingo Molnar Cc: john stultz Cc: Roman Zippel Cc: Andi Kleen Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit 169a0abbe32813af4904cc1605c0f7ea0534f77b Author: Thomas Gleixner Date: Fri Feb 16 01:27:55 2007 -0800 [PATCH] ACPI keep track of timer broadcasting This is a preperatory patch for highres/dyntick: - replace the big #ifdef ARCH_APICTIMER_STOPS_ON_C3 hackery by functions - remove the double switch in the power verify function (in the worst case we switched ipi to apic and 20usec later apic to ipi) - keep track of the the state which stops local APIC timer Signed-off-by: Thomas Gleixner Signed-off-by: Ingo Molnar Cc: Len Brown Cc: Cc: Andi Kleen Cc: john stultz Cc: Roman Zippel Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit 3434933b17fa64adddf83059603c61296f6e1ee2 Author: Thomas Gleixner Date: Fri Feb 16 01:27:54 2007 -0800 [PATCH] ACPI: fix missing include for UP apic.h does not get included on UP compiles. That way the APICTIMER_STOPS_ON_C3 is not there and UP boxen have no support for timer broadcasting. This was never noticed, because the lapic timer is only used for profiling on UP. Signed-off-by: Thomas Gleixner Signed-off-by: Ingo Molnar Cc: Roman Zippel Cc: john stultz Cc: Len Brown Cc: Andi Kleen Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit dd3629b5e5f03dde6d8a17bb798bcb0ba6c3f579 Author: Thomas Gleixner Date: Fri Feb 16 01:27:53 2007 -0800 [PATCH] hrtimers: move and add documentation Move the initial hrtimers.txt document to the new directory "Documentation/hrtimers" Add design notes for the high resolution timer and dynamic tick functionality. Signed-off-by: Thomas Gleixner Signed-off-by: Ingo Molnar Cc: Roman Zippel Cc: john stultz Cc: Andi Kleen Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit 5cfb6de7cd7c8f04655c9d23533ca506647beace Author: Thomas Gleixner Date: Fri Feb 16 01:27:52 2007 -0800 [PATCH] hrtimers: clean up callback tracking Reintroduce ktimers feature "optimized away" by the ktimers review process: remove the curr_timer pointer from the cpu-base and use the hrtimer state. No functional changes. Signed-off-by: Thomas Gleixner Signed-off-by: Ingo Molnar Cc: Roman Zippel Cc: john stultz Cc: Andi Kleen Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit 303e967ff90a9d19ad3f8c9028ccbfa7f408fbb3 Author: Thomas Gleixner Date: Fri Feb 16 01:27:51 2007 -0800 [PATCH] hrtimers; add state tracking Reintroduce ktimers feature "optimized away" by the ktimers review process: multiple hrtimer states to enable the running of hrtimers without holding the cpu-base-lock. (The "optimized" rbtree hack carried only 2 states worth of information and we need 4 for high resolution timers and dynamic ticks.) No functional changes. Build-fixes-from: Andrew Morton Signed-off-by: Thomas Gleixner Signed-off-by: Ingo Molnar Cc: Roman Zippel Cc: john stultz Cc: Andi Kleen Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit 3c8aa39d7c445ae2612b6b626f76f077e7a7ab0d Author: Thomas Gleixner Date: Fri Feb 16 01:27:50 2007 -0800 [PATCH] hrtimers: cleanup locking Improve kernel/hrtimers.c locking: use a per-CPU base with a lock to control locking of all clocks belonging to a CPU. This simplifies code that needs to lock all clocks at once. This makes life easier for high-res timers and dyntick. No functional changes. [ optimization change from Andrew Morton ] Signed-off-by: Thomas Gleixner Signed-off-by: Ingo Molnar Cc: john stultz Cc: Roman Zippel Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit c9cb2e3d7c9178ab75d0942f96abb3abe0369906 Author: Thomas Gleixner Date: Fri Feb 16 01:27:49 2007 -0800 [PATCH] hrtimers: namespace and enum cleanup - hrtimers did not use the hrtimer_restart enum and relied on the implict int representation. Fix the prototypes and the functions using the enums. - Use seperate name spaces for the enumerations - Convert hrtimer_restart macro to inline function - Add comments No functional changes. [akpm@osdl.org: fix input driver] Signed-off-by: Thomas Gleixner Signed-off-by: Ingo Molnar Cc: john stultz Cc: Roman Zippel Cc: Dmitry Torokhov Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit fd064b9b7770d5c7705bf9542950c7bd81c30f98 Author: Thomas Gleixner Date: Fri Feb 16 01:27:47 2007 -0800 [PATCH] Extend next_timer_interrupt() to use a reference jiffie For CONFIG_NO_HZ we need to calculate the next timer wheel event based on a given jiffie value. Extend the existing code to allow the extra 'now' argument. Provide a compability function for the existing implementations to call the function with now == jiffies. (This also solves the racyness of the original code vs. jiffies changing during the iteration.) No functional changes to existing users of this infrastructure. [ remove WARN_ON() that triggered on s390, by Carsten Otte ] [ made new helper static, Adrian Bunk ] Signed-off-by: Thomas Gleixner Signed-off-by: Ingo Molnar Cc: john stultz Cc: Roman Zippel Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit 1cfd68496e53f7be09a3c1358d1d389004217541 Author: Thomas Gleixner Date: Fri Feb 16 01:27:46 2007 -0800 [PATCH] Fix cascade lookup of next_timer_interrupt When searching for the next pending timer in the timer wheel we need to take the cascade into account. The current code has several problems: 1. it looks into the previous cascade 2. it ignores a pending cascade 3. it ignores multiple cascades Change the cascade lookup, so it calculates the array index from the point of the next cascade and always look at the cascade buckets, when the cascade is pending, i.e. gets executed in the next timer softirq. When multiple cascades are pending, then lookup the next buckets too. Signed-off-by: Thomas Gleixner Signed-off-by: Ingo Molnar Cc: john stultz Cc: Roman Zippel Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit dde4b2b5f4ed275250488dabdaf282d9c6e7e2b8 Author: Ingo Molnar Date: Fri Feb 16 01:27:45 2007 -0800 [PATCH] uninline irq_enter() Uninline irq_enter(). [dynticks adds more stuff to it] No functional changes. Signed-off-by: Ingo Molnar Signed-off-by: Thomas Gleixner Cc: john stultz Cc: Roman Zippel Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit 07190a08eef3666a8687070226c8d403c1d548b7 Author: Marcelo Tosatti Date: Fri Feb 16 01:27:44 2007 -0800 [PATCH] Mark TSC on GeodeLX reliable The Geode can safely use the TSC for highres, since: 1) Does not support frequency scaling, 2) The TSC _does_ count when the CPU is halted. Furthermore, the Geode supports a mode called "suspension on halt", where Suspend mode (which interacts with the power management states) is entered. TSC counting during suspend mode is controlled by bit 8 of the Bus Controller Configuration Register #0 (thanks Tom!). 3) no SMP :) Check if "RTSC counts during suspension" and remove the requirement for verification, so the clocksource code can safely select it as an timesource for the highres timers subsystem. Signed-off-by: Marcelo Tosatti Signed-off-by: Thomas Gleixner Signed-off-by: Ingo Molnar Cc: john stultz Cc: Roman Zippel Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit 5d8b34fdcb384161552d01ee8f34af5ff11f9684 Author: Thomas Gleixner Date: Fri Feb 16 01:27:43 2007 -0800 [PATCH] clocksource: Add verification (watchdog) helper The TSC needs to be verified against another clocksource. Instead of using hardwired assumptions of available hardware, provide a generic verification mechanism. The verification uses the best available clocksource and handles the usability for high resolution timers / dynticks of the clocksource which needs to be verified. Signed-off-by: Thomas Gleixner Signed-off-by: Ingo Molnar Cc: john stultz Cc: Roman Zippel Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit 7e69f2b1ead2a4c51c12817f18263ff0e59335a6 Author: Thomas Gleixner Date: Fri Feb 16 01:27:42 2007 -0800 [PATCH] clocksource: Remove the update callback The clocksource code allows direct updates of the rating of a given clocksource now. Change TSC unstable tracking to use this interface and remove the update callback. Signed-off-by: Thomas Gleixner Signed-off-by: Ingo Molnar Cc: john stultz Cc: Roman Zippel Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit 877fe38029366c19def24359627db8cc24d9fef6 Author: Thomas Gleixner Date: Fri Feb 16 01:27:40 2007 -0800 [PATCH] clocksource: fixup is_continous changes on MIPS Fixup the is_contionous replacement by a flag field. Signed-off-by: Thomas Gleixner Signed-off-by: Ingo Molnar Cc: Ralf Baechle Cc: john stultz Cc: Roman Zippel Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit cc02d809cc629f4e90b917aa0f9efea85221ccdb Author: Thomas Gleixner Date: Fri Feb 16 01:27:39 2007 -0800 [PATCH] clocksource: fixup is_continous changes on S390 Fixup the is_contionous replacement by a flag field. Signed-off-by: Thomas Gleixner Signed-off-by: Ingo Molnar Cc: Martin Schwidefsky Cc: john stultz Cc: Roman Zippel Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit 2693506c41c20362eefb38005ee34dca7ac8dc71 Author: Thomas Gleixner Date: Fri Feb 16 01:27:38 2007 -0800 [PATCH] clocksource: fixup is_continous changes on AVR32 Fixup the is_contionous replacement by a flag field. Signed-off-by: Thomas Gleixner Signed-off-by: Ingo Molnar Cc: Haavard Skinnemoen Cc: john stultz Cc: Roman Zippel Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit c66699a749eb0d84c6ebc3aac659e9f71d1aba14 Author: Thomas Gleixner Date: Fri Feb 16 01:27:37 2007 -0800 [PATCH] clocksource: fixup is_continous changes on ARM Fixup the is_contionous replacement by a flag field. Signed-off-by: Thomas Gleixner Signed-off-by: Ingo Molnar Cc: Russell King Cc: john stultz Cc: Roman Zippel Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit 73b08d2aa4245806ef1bdd48463e9a0b045c62cf Author: Thomas Gleixner Date: Fri Feb 16 01:27:36 2007 -0800 [PATCH] clocksource: replace is_continuous by a flag field Using a flag filed allows to encode more than one information into a variable. Preparatory patch for the generic clocksource verification. [mingo@elte.hu: convert vmitime.c to the new clocksource flag] Signed-off-by: Thomas Gleixner Signed-off-by: Ingo Molnar Cc: john stultz Cc: Roman Zippel Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit 95492e4646e5de8b43d9a7908d6177fb737b61f0 Author: Ingo Molnar Date: Fri Feb 16 01:27:34 2007 -0800 [PATCH] x86: rewrite SMP TSC sync code make the TSC synchronization code more robust, and unify it between x86_64 and i386. The biggest change is the removal of the 'fix up TSCs' code on x86_64 and i386, in some rare cases it was /causing/ time-warps on SMP systems. The new code only checks for TSC asynchronity - and if it can prove a time-warp (if it can observe the TSC going backwards when going from one CPU to another within a critical section), then the TSC clock-source is turned off. The TSC synchronization-checking code also got moved into a separate file. Signed-off-by: Ingo Molnar Signed-off-by: Thomas Gleixner Cc: john stultz Cc: Roman Zippel Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit 92c7e00254b2d0efc1e36ac3e45474ce1871b6b2 Author: Thomas Gleixner Date: Fri Feb 16 01:27:33 2007 -0800 [PATCH] Simplify the registration of clocksources Enqueue clocksources in rating order to make selection of the clocksource easier. Also check the match with an user override at enqueue time. Preparatory patch for the generic clocksource verification. Signed-off-by: Thomas Gleixner Signed-off-by: Ingo Molnar Cc: john stultz Cc: Roman Zippel Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit 26a08eb301a2e3fce5a501e3dd26cf3ec46591d7 Author: Thomas Gleixner Date: Fri Feb 16 01:27:32 2007 -0800 [PATCH] i386 Remove useless code in tsc.c The delayed work code in arch/i386/kernel/tsc.c is an unused leftover of the GTOD conversion. Remove it. Signed-off-by: Thomas Gleixner Signed-off-by: Ingo Molnar Cc: john stultz Cc: Roman Zippel Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit c1d370e167d66b10bca3b602d3740405469383de Author: John Stultz Date: Fri Feb 16 01:27:31 2007 -0800 [PATCH] i386: use GTOD persistent clock support Persistent clock support: do proper timekeeping across suspend/resume, i386 arch support. [bunk@stusta.de: cleanup] Build-fixes-from: Andrew Morton Signed-off-by: John Stultz Signed-off-by: Thomas Gleixner Signed-off-by: Ingo Molnar Cc: Roman Zippel Cc: Adrian Bunk Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit 411187fb05cd11676b0979d9fbf3291db69dbce2 Author: John Stultz Date: Fri Feb 16 01:27:30 2007 -0800 [PATCH] GTOD: persistent clock support Persistent clock support: do proper timekeeping across suspend/resume. [bunk@stusta.de: cleanup] Signed-off-by: John Stultz Signed-off-by: Thomas Gleixner Signed-off-by: Ingo Molnar Cc: Roman Zippel Cc: Adrian Bunk Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit 9f907c0144496e464bd5ed5a99a51227d63a9c0b Author: Ingo Molnar Date: Fri Feb 16 01:27:29 2007 -0800 [PATCH] Fix timeout overflow with jiffies Prevent timeout overflow if timer ticks are behind jiffies (due to high softirq load or due to dyntick), by limiting the valid timeout range to MAX_LONG/2. Signed-off-by: Ingo Molnar Signed-off-by: Thomas Gleixner Cc: john stultz Cc: Roman Zippel Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit 41cf54455da5e5dc847a9733d49ca23b5e7dd59e Author: Ingo Molnar Date: Fri Feb 16 01:27:28 2007 -0800 [PATCH] Fix multiple conversion bugs in msecs_to_jiffies Fix multiple conversion bugs in msecs_to_jiffies(). The main problem is that this condition: if (m > jiffies_to_msecs(MAX_JIFFY_OFFSET)) overflows if HZ is smaller than 1000! This change is user-visible: for HZ=250 SUS-compliant poll()-timeout value of -20 is mistakenly converted to 'immediate timeout'. (The new dyntick code also triggered this, that's how we noticed.) Signed-off-by: Ingo Molnar Signed-off-by: Thomas Gleixner Cc: john stultz Cc: Roman Zippel Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit 8b9365d753d9870bb6451504c13570b81923228f Author: Ingo Molnar Date: Fri Feb 16 01:27:27 2007 -0800 [PATCH] Uninline jiffies.h functions There are loads of fat functions hidden in jiffies.h. Uninline them. No code changes. [jeremy@goop.org: export fix] Signed-off-by: Ingo Molnar Signed-off-by: Thomas Gleixner Cc: john stultz Cc: Roman Zippel Cc: Jeremy Fitzhardinge Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit f4304ab21513b834c8fe3403927c60c2b81a72d7 Author: john stultz Date: Fri Feb 16 01:27:26 2007 -0800 [PATCH] HZ free ntp Distangle the NTP update from HZ. This is necessary for dynamic tick enabled kernels. Cc: Thomas Gleixner Cc: Ingo Molnar Cc: john stultz Cc: Roman Zippel Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit 771ee3b04eaac6184312825eb600b4c598f027a5 Author: Thomas Gleixner Date: Fri Feb 16 01:27:25 2007 -0800 [PATCH] Add a function to handle interrupt affinity setting Provide funtions to: - check, whether an interrupt can set the affinity - pin the interrupt to a given cpu Necessary for the ability to setup clocksources more flexible (e.g. use the different HPET channels per CPU) [akpm@osdl.org: alpha build fix] Signed-off-by: Thomas Gleixner Signed-off-by: Ingo Molnar Cc: john stultz Cc: Roman Zippel Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit 950f4427c2ddc921164088a20f01304cf231437c Author: Thomas Gleixner Date: Fri Feb 16 01:27:24 2007 -0800 [PATCH] Add irq flag to disable balancing for an interrupt Add a flag so we can prevent the irq balancing of an interrupt. Move the bits, so we have room for more :) Necessary for the ability to setup clocksources more flexible (e.g. use the different HPET channels per CPU) Signed-off-by: Thomas Gleixner Signed-off-by: Ingo Molnar Cc: john stultz Cc: Roman Zippel Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit b463fc60730bea6cdd73fec6edc6ec4658d47d37 Author: Andrew Morton Date: Fri Feb 16 01:27:23 2007 -0800 [PATCH] vmi-versus-hrtimers arch/i386/kernel/built-in.o: In function `vmi_stop_hz_timer': : undefined reference to `next_timer_interrupt' If CONFIG_NO_HZ, next_timer_interrupt() doesn't exist (and presumably doesn't make sense). Perhaps VMI shouildn't be playing with timer internals at this level. Cc: Zachary Amsden Cc: Andi Kleen Cc: Jeremy Fitzhardinge Cc: Rusty Russell Cc: Chris Wright Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit c6025a79f5d438bba0186fbb230dc780e876edf2 Author: Adrian Bunk Date: Fri Feb 16 01:27:22 2007 -0800 [PATCH] correct CONFIG_GIGASET_M101 Makefile entry Advanced Mathematics, lesson 1: 101 != 105 ;-) Signed-off-by: Adrian Bunk Acked-by: Tilman Schmidt Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit 838e56a11cdb2abaf490eb7879ab021db938d47d Author: Jeff Dike Date: Fri Feb 16 01:27:21 2007 -0800 [PATCH] uml: fix 2.6.20 hang A previous cleanup misused need_poll, which had a fairly broken interface. It implemented a growable array, changing the used elements count itself, but leaving it up to the caller to fill in the actual elements, including the entire array if the array had to be reallocated. This worked because the previous users were switching between two such structures, and the elements were copied from the inactive array to the active array after making sure the active array had enough room. maybe_sigio_broken was made to use need_poll, but it was operating on a single array, so when the buffer was reallocated, the previous contents were lost. This patch makes need_poll implement more sane semantics. It merely assures that the array is of the proper size and that the contents are preserved. It is up to the caller to adjust the used elements count and to ensure that the proper elements are resent. This manifested itself as a hang in 2.6.20 as the uninitialized buffer convinced UML that one of its own file descriptors didn't support SIGIO and needed to be watched by poll in a separate thread. The result was an interrupt flood as control traffic over this descriptor sparked interrupts, which resulted in more control traffic, ad nauseum. Signed-off-by: Jeff Dike Cc: Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit beb497ab48b1639282129f7bc18fef311fffff3d Author: Dmitriy Monakhov Date: Fri Feb 16 01:27:18 2007 -0800 [PATCH] __page_symlink retry loop error code fix If prepare_write or commit_write return AOP_TRUNCATED_PAGE we jump to "retry" label and than if find_or_create_page() failed function return incorrect error code. Signed-off-by: Dmitriy Monakhov Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit fb4d64e78ceab77cf20f7796f74aa10ebe862032 Author: Frederik Deweerdt Date: Fri Feb 16 01:27:15 2007 -0800 [PATCH] pci_iomap_regions() error handling fix It appears that the pcim_iomap_regions() function doesn't get the error handling right. It BUGs early at boot with a backtrace along the lines of: ahci_init pci_register_driver driver_register [...] ahci_init_one pcim_iomap_region pcim_iounmap The following patch allows me to boot. Only the if(mask..) continue; part fixes the problem actually, the gotos where changed so that we don't try to unmap something we couldn't map anyway. Signed-off-by: Frederik Deweerdt Cc: Al Viro Cc: Tejun Heo Cc: Jeff Garzik Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit f5de611148c8370cbe50796ca5567ca624b99686 Author: David Brownell Date: Fri Feb 16 01:27:14 2007 -0800 [PATCH] GPIO core documentation Small updates to the GPIO documentation, addressing feedback and fixing a few spelling errors. Signed-off-by: David Brownell Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit 41d8ca452f523b9245704c7dd8ef290fa7b78e6b Author: Haavard Skinnemoen Date: Fri Feb 16 13:56:11 2007 +0100 [AVR32] Use per-controller spi_board_info structures Set up one spi_board_info array per controller and pass this to at32_add_device_spi so that it can set up any GPIO pins for chip selects based on this information. Extracted from a patch by David Brownell and adapted slightly. Signed-off-by: Haavard Skinnemoen commit 23cebe2287474720c2eb0673581056cfb285a69f Author: Haavard Skinnemoen Date: Fri Feb 16 13:19:47 2007 +0100 [AVR32] Warn, don't BUG if clk_disable is called too many times Print a helpful warning along with a stack dump if clk_disable is called on a already-disabled clock. Remove the BUG_ON(). Extracted from a patch by David Brownell. Signed-off-by: Haavard Skinnemoen commit 7a5fe2387925405da0319330986184792ce48ad1 Author: Haavard Skinnemoen Date: Fri Feb 16 13:14:33 2007 +0100 [AVR32] Make sure all genclocks have a parent Initialize the parent field of each generic clock by looking at the PM registers. This means that the genclock operations can always assume that the parent field is non-null, so they don't have to check. Also remove a few unnecessary BUG_ON()s. Extracted from a patch by David Brownell. Signed-off-by: Haavard Skinnemoen commit 160f34531a71fdbbdb593a094273711ffb1257d7 Author: Haavard Skinnemoen Date: Thu Feb 15 16:22:17 2007 +0100 [AVR32] Remove unnecessary sys_nfsservctl conditional kernel/sys_ni.c defines sys_nfsservctl as a weak alias for sys_ni_syscall, so it's always safe to include it in the system call table. Signed-off-by: Haavard Skinnemoen commit 1a6f1436d5fdecd4b395815c130df3c834892ab6 Author: Haavard Skinnemoen Date: Thu Feb 15 10:01:11 2007 +0100 [AVR32] Wire up the SysV IPC calls properly Wire up the individual sysvipc system calls and remove sys_ipc. Strictly speaking, this breaks the ABI, but since sys_ipc never worked anyway due to a silly bug, it isn't actually a regression. Signed-off-by: Haavard Skinnemoen commit 2201ec2b10910c869befb012ae75696a02091e7d Author: Haavard Skinnemoen Date: Fri Feb 16 12:53:57 2007 +0100 [AVR32] Define ioremap_nocache, ioport_map and ioport_unmap These are all defined in terms of ioremap/iounmap since port I/O isn't really different from memory-mapped I/O on AVR32. Signed-off-by: Haavard Skinnemoen commit b60f16eb56ff872a86c55c11bcfd430ce8cec340 Author: Haavard Skinnemoen Date: Fri Feb 16 12:47:40 2007 +0100 [AVR32] Fix prototypes for __raw_writesb and friends The first parameter to __raw_writes[bwl] and __raw_reads[bwl] should be a void __iomem *, not unsigned long. Signed-off-by: Haavard Skinnemoen commit 7de970e11fb832a56c897276967fb0e49f59b313 Author: Nate Dailey Date: Thu Feb 15 18:13:46 2007 -0500 sata_vsc: use default cache line size if non-zero This modifies drivers/ata/sata_vsc.c to only set the cache line size to 0x80 if the default value is zero. Apparently zero isn't allowed due to a bug in the chip, but I've found performance is much better with the (non-zero) default instead of 0x80. [note1: "default" means BIOS-programmed value, in this context -jgarzik] [note2: superfluous braces were removed from the patch -jg] Signed-off-by: Nate Dailey Signed-off-by: Jeremy Higdon Signed-off-by: Jeff Garzik commit 5278b50cea851d8264b7b28212a483328650476f Author: Robert Hancock Date: Sun Feb 11 18:36:56 2007 -0600 sata_nv: handle SError status indication ADMA-capable controllers provide a bit in the status register that appears to indicate that the controller detected an SError condition. Update sata_nv to detect this and trigger error handling in order to handle the fault. Signed-off-by: Robert Hancock Signed-off-by: Jeff Garzik commit 8361cd79f2434d43054be894baf08a74dae5f8c0 Author: Olaf Hering Date: Sat Feb 10 21:36:14 2007 +0100 add delay around sl82c105_reset_engine calls The hald media changed polling does really confuse things. Noone knows why the delays are needed, but they give us access to the CD. An udelay(50) will give reliable access to the drive, but there is still one (or more) EH reset. The drive works without EH resets with udelay(100). Signed-off-by: Olaf Hering Signed-off-by: Jeff Garzik commit 9f271d576a79f74a543c4099a014d8d4eafa737d Author: Zhang, Yanmin Date: Fri Feb 9 11:29:51 2007 +0800 ATA convert GSI to irq on ia64 If an ATA drive uses legacy mode, ata driver will choose 14 and 15 as the fixed irq number. On ia64 platform, such numbers are GSI and should be converted to irq vector. Below patch against kernel 2.6.20 fixes it. Signed-off-by: Zhang Yanmin Signed-off-by: Jeff Garzik commit 81afe893181b283f9d182ea8637ce6ccdbe1a56a Author: Tejun Heo Date: Wed Feb 7 12:37:41 2007 -0800 libata: clear TF before IDENTIFYing Some devices chock if Feature is not clear when IDENTIFY is issued. Set ATA_TFLAG_ISADDR | ATA_TFLAG_DEVICE for IDENTIFY such that whole TF is cleared when reading ID data. Kudos to Art Haas for testing various futile patches over several months and Mark Lord for pointing out the fix. Signed-off-by: Tejun Heo Cc: Art Haas Cc: Mark Lord Signed-off-by: Jeff Garzik commit f834e49f1a09414e9618ff0c9cd83c2114032bb6 Author: Alan Cox Date: Wed Feb 7 13:46:00 2007 -0800 libata: Add a host flag to indicate lack of IORDY capability This is the first preparation to doing the !IORDY cases properly. Further diffs will then add the needed logic to do it right. Signed-off-by: Alan Cox Cc: Jeff Garzik Cc: Tejun Heo Signed-off-by: Andrew Morton Signed-off-by: Jeff Garzik commit 61f216c7196e15e56d97c5a75af01e6684f17fa3 Author: Tejun Heo Date: Mon Feb 5 23:21:19 2007 +0900 libata: fix drive side 80c cable check, take 3 The 80c wire bit is bit 13, not 14. Bit 14 is always 1 if word93 is implemented. This increases the chance of incorrect wire detection especially because host side cable detection is often unreliable and we sometimes soley depend on drive side cable detection. Fix the test and add word93 validity check. Signed-off-by: Tejun Heo Signed-off-by: Jeff Garzik commit 5387373bfe78b7795b96378250f6848f39d78b80 Author: Mikael Pettersson Date: Sun Feb 11 23:19:53 2007 +0100 sata_promise: new EH conversion for 20619 chips, take 2 This patch updates the sata_promise driver to use new-style libata error handling for 20619 (TX4000) chips. sata_promise already uses new EH for the other chips it supports, so the patch is quite simple: * remove ->phy_reset and ->eng_timeout ops from pdc_pata_ops, and instead bind ->freeze, ->thaw, ->error_handler, and ->post_internal_cmd to existing new EH functions * drop ATA_FLAG_SRST from board_20619's flags * remove now unused pdc_pata_phy_reset() and pdc_eng_timeout() Tested on a TX4000 with both modern working disks and old/quirky disks. Also used a CD-RW drive to test reading and writing CDs. Signed-off-by: Mikael Pettersson Signed-off-by: Jeff Garzik commit 2fb8b49fb2eac583f0e8dd0ece06f9ad6d8fd792 Author: Mikael Pettersson Date: Wed Feb 7 22:29:56 2007 +0100 sata_promise: fix missing PATA cable detection This patch fixes an oversight which caused sata_promise to not perform cable detection on the TX2plus chips' PATA ports. Signed-off-by: Mikael Pettersson Signed-off-by: Jeff Garzik commit e0a04cffa4e97e1e53625e40e70895c882e8972f Author: Nick Piggin Date: Wed Feb 14 12:39:01 2007 +0100 [PATCH] mincore: vma crossing fix My mincore also forgot about crossing vmas. Signed-off-by: Nick Piggin Signed-off-by: Linus Torvalds commit 4a76ef036ac415c28d1adbaf2b7a74040b84d4c2 Author: Nick Piggin Date: Wed Feb 14 12:36:32 2007 +0100 [PATCH] mincore: fill in results properly Paper bag time. Thanks to Randy for noticing that I didn't actually assign 'present' to anything. Unfortunately my original patch passed the few simple test cases I gave it, purely by coincidence. Signed-off-by: Nick Piggin Signed-off-by: Linus Torvalds commit 30fcffed8149df18592b3e006b829232b7b3844f Author: Nick Piggin Date: Wed Feb 14 12:35:02 2007 +0100 [PATCH] mincore: CONFIG_SWAP=n fix Fix mincore-anon patch to compile with CONFIG_SWAP=n Signed-off-by: Nick Piggin Signed-off-by: Linus Torvalds commit 9c57548f17806ffd8e4dc4f7973ce78bbfbc2079 Author: Paul Mundt Date: Thu Feb 15 18:20:52 2007 +0900 sh: rts7751r2d board updates. This tidies up some of the rts7751r2d mess and gets it booting again. Update the defconfig, too. Signed-off-by: Masayuki Hosokawa Signed-off-by: Paul Mundt commit 2b8c0e13026c30bd154dc521ffc235360830c712 Author: Rafa³ Bilski Date: Wed Feb 14 22:00:37 2007 +0100 [CPUFREQ] Longhaul - Redo Longhaul ver. 2 Start using v2 version of Longhaul when available. It provides voltage scaling and can use ACPI C3 state. That's curious. CPU will not change frequency on ACPI C3 when v1 is in use, but it will when v2 is used. Driver will return max frequency all the time if this isn't true for all processors. There is strange thing with mobile voltage. Looks like only Nehemiah (C3-M) supports it. Earlier processors have different mobile VRM (in docs), but I can't find any which is using it. Looks like all are using VRM 8.5. So fail for non Nehemiah with mobile VRM. Signed-off-by: Rafal Bilski Signed-off-by: Dave Jones commit 86a71dbd3e81e8870d0f0e56b87875f57e58222b Author: Eric W. Biederman Date: Wed Feb 14 00:34:16 2007 -0800 [PATCH] sysctl: hide the sysctl proc inodes from selinux Since the security checks are applied on each read and write of a sysctl file, just like they are applied when calling sys_sysctl, they are redundant on the standard VFS constructs. Since it is difficult to compute the security labels on the standard VFS constructs we just mark the sysctl inodes in proc private so selinux won't even bother with them. Signed-off-by: Eric W. Biederman Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit bbaca6c2e7ef0f663bc31be4dad7cf530f6c4962 Author: Stephen Smalley Date: Wed Feb 14 00:34:16 2007 -0800 [PATCH] selinux: enhance selinux to always ignore private inodes Hmmm...turns out to not be quite enough, as the /proc/sys inodes aren't truly private to the fs, so we can run into them in a variety of security hooks beyond just the inode hooks, such as security_file_permission (when reading and writing them via the vfs helpers), security_sb_mount (when mounting other filesystems on directories in proc like binfmt_misc), and deeper within the security module itself (as in flush_unauthorized_files upon inheritance across execve). So I think we have to add an IS_PRIVATE() guard within SELinux, as below. Note however that the use of the private flag here could be confusing, as these inodes are _not_ private to the fs, are exposed to userspace, and security modules must implement the sysctl hook to get any access control over them. Signed-off-by: Eric W. Biederman Signed-off-by: Stephen Smalley Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit b599fdfdb4bb4941e9076308efcf3bb89e577db5 Author: Eric W. Biederman Date: Wed Feb 14 00:34:15 2007 -0800 [PATCH] sysctl: fix the selinux_sysctl_get_sid I goofed and when reenabling the fine grained selinux labels for sysctls and forgot to add the "/sys" prefix before consulting the policy database. When computing the same path using proc_dir_entries we got the "/sys" for free as it was part of the tree, but it isn't true for clt_table trees. Signed-off-by: Eric W. Biederman Acked-by: Stephen Smalley Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit 3fbfa98112fc3962c416452a0baf2214381030e6 Author: Eric W. Biederman Date: Wed Feb 14 00:34:14 2007 -0800 [PATCH] sysctl: remove the proc_dir_entry member for the sysctl tables It isn't needed anymore, all of the users are gone, and all of the ctl_table initializers have been converted to use explicit names of the fields they are initializing. [akpm@osdl.org: NTFS fix] Signed-off-by: Eric W. Biederman Acked-by: Stephen Smalley Cc: James Morris Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit d912b0cc1a617d7c590d57b7ea971d50c7f02503 Author: Eric W. Biederman Date: Wed Feb 14 00:34:13 2007 -0800 [PATCH] sysctl: add a parent entry to ctl_table and set the parent entry Add a parent entry into the ctl_table so you can walk the list of parents and find the entire path to a ctl_table entry. Signed-off-by: Eric W. Biederman Cc: Stephen Smalley Cc: James Morris Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit 77b14db502cb85a031fe8fde6c85d52f3e0acb63 Author: Eric W. Biederman Date: Wed Feb 14 00:34:12 2007 -0800 [PATCH] sysctl: reimplement the sysctl proc support With this change the sysctl inodes can be cached and nothing needs to be done when removing a sysctl table. For a cost of 2K code we will save about 4K of static tables (when we remove de from ctl_table) and 70K in proc_dir_entries that we will not allocate, or about half that on a 32bit arch. The speed feels about the same, even though we can now cache the sysctl dentries :( We get the core advantage that we don't need to have a 1 to 1 mapping between ctl table entries and proc files. Making it possible to have /proc/sys vary depending on the namespace you are in. The currently merged namespaces don't have an issue here but the network namespace under /proc/sys/net needs to have different directories depending on which network adapters are visible. By simply being a cache different directories being visible depending on who you are is trivial to implement. [akpm@osdl.org: fix uninitialised var] [akpm@osdl.org: fix ARM build] [bunk@stusta.de: make things static] Signed-off-by: Eric W. Biederman Cc: Russell King Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit 1ff007eb8e8c7c44e9a384a67d0fdd0fd06ba811 Author: Eric W. Biederman Date: Wed Feb 14 00:34:11 2007 -0800 [PATCH] sysctl: allow sysctl_perm to be called from outside of sysctl.c Signed-off-by: Eric W. Biederman Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit 805b5d5e063e7fde5e2eb724e3f4cb18e47cab19 Author: Eric W. Biederman Date: Wed Feb 14 00:34:11 2007 -0800 [PATCH] sysctl: factor out sysctl_head_next from do_sysctl The current logic to walk through the list of sysctl table headers is slightly painful and implement in a way it cannot be used by code outside sysctl.c I am in the process of implementing a version of the sysctl proc support that instead of using the proc generic non-caching monster, just uses the existing sysctl data structure as backing store for building the dcache entries and for doing directory reads. To use the existing data structures however I need a way to get at them. [akpm@osdl.org: warning fix] Signed-off-by: Eric W. Biederman Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit 0b4d414714f0d2f922d39424b0c5c82ad900a381 Author: Eric W. Biederman Date: Wed Feb 14 00:34:09 2007 -0800 [PATCH] sysctl: remove insert_at_head from register_sysctl The semantic effect of insert_at_head is that it would allow new registered sysctl entries to override existing sysctl entries of the same name. Which is pain for caching and the proc interface never implemented. I have done an audit and discovered that none of the current users of register_sysctl care as (excpet for directories) they do not register duplicate sysctl entries. So this patch simply removes the support for overriding existing entries in the sys_sysctl interface since no one uses it or cares and it makes future enhancments harder. Signed-off-by: Eric W. Biederman Acked-by: Ralf Baechle Acked-by: Martin Schwidefsky Cc: Russell King Cc: David Howells Cc: "Luck, Tony" Cc: Ralf Baechle Cc: Paul Mackerras Cc: Martin Schwidefsky Cc: Andi Kleen Cc: Jens Axboe Cc: Corey Minyard Cc: Neil Brown Cc: "John W. Linville" Cc: James Bottomley Cc: Jan Kara Cc: Trond Myklebust Cc: Mark Fasheh Cc: David Chinner Cc: "David S. Miller" Cc: Patrick McHardy Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit ae836810263509ff7a3c2c021754ce6f66b3fab6 Author: Eric W. Biederman Date: Wed Feb 14 00:34:08 2007 -0800 [PATCH] sysctl: remove support for directory strategy routines parse_table has support for calling a strategy routine when descending into a directory. To date no one has used this functionality and the /proc/sys interface has no analog to it. So no one is using this functionality kill it and make the binary sysctl code easier to follow. Signed-off-by: Eric W. Biederman Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit 6703ddfcce61ad66db606085a8d42dcab264f840 Author: Eric W. Biederman Date: Wed Feb 14 00:34:07 2007 -0800 [PATCH] sysctl: remove support for CTL_ANY There are currently no users in the kernel for CTL_ANY and it only has effect on the binary interface which is practically unused. So this complicates sysctl lookups for no good reason so just remove it. Signed-off-by: Eric W. Biederman Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit 2abc26fc6b6f60fc70d6957b842ef4e5f805df7b Author: Eric W. Biederman Date: Wed Feb 14 00:34:07 2007 -0800 [PATCH] sysctl: create sys/fs/binfmt_misc as an ordinary sysctl entry binfmt_misc has a mount point in the middle of the sysctl and that mount point is created as a proc_generic directory. Doing it that way gets in the way of cleaning up the sysctl proc support as it continues the existence of a horrible hack. So instead simply create the directory as an ordinary sysctl directory. At least that removes the magic special case. [akpm@osdl.org: warning fix] Signed-off-by: Eric W. Biederman Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit a5494dcd8b92dce64317f2f7dd0d62747c54980b Author: Eric W. Biederman Date: Wed Feb 14 00:34:06 2007 -0800 [PATCH] sysctl: move SYSV IPC sysctls to their own file This is just a simple cleanup to keep kernel/sysctl.c from getting to crowded with special cases, and by keeping all of the ipc logic to together it makes the code a little more readable. [gcoady.lk@gmail.com: build fix] Signed-off-by: Eric W. Biederman Cc: Serge E. Hallyn Cc: Herbert Poetzl Cc: Kirill Korotaev Signed-off-by: Grant Coady Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit 39732acd968a007036ff3c504f1e6748024ef548 Author: Eric W. Biederman Date: Wed Feb 14 00:33:58 2007 -0800 [PATCH] sysctl: move utsname sysctls to their own file This is just a simple cleanup to keep kernel/sysctl.c from getting to crowded with special cases, and by keeping all of the utsname logic to together it makes the code a little more readable. Signed-off-by: Eric W. Biederman Cc: Serge E. Hallyn Cc: Herbert Poetzl Cc: Kirill Korotaev Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit b04c3afb2b6e2f902b41bb62b73684d92d7e6c34 Author: Eric W. Biederman Date: Wed Feb 14 00:33:57 2007 -0800 [PATCH] sysctl: move init_irq_proc into init/main where it belongs Signed-off-by: Eric W. Biederman Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit 0e03036c97b70b2602f7dedaa3a223ed7563c2c9 Author: Eric W. Biederman Date: Wed Feb 14 00:33:57 2007 -0800 [PATCH] sysctl: register the ocfs2 sysctl numbers ocfs2 was did not have the binary number it uses under CTL_FS registered in sysctl.h. Register it to avoid future conflicts, and change the name of the definition to be in line with the rest of the sysctl numbers. Signed-off-by: Eric W. Biederman Acked-by: Mark Fasheh Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit 4ed075e93bad97d0fdbb8a1be62f2449988496cb Author: Eric W. Biederman Date: Wed Feb 14 00:33:56 2007 -0800 [PATCH] sysctl: C99 convert ctl_tables in NTFS and remove sys_sysctl support Putting ntfs-debug under FS_NRINODE was not a kosher thing to do so don't give it any binary number. [akpm@osdl.org: build fix] Signed-off-by: Eric W. Biederman Cc: Anton Altaparmakov Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit fd6065b4fdcb64c43e400278ebd0cb56989871c3 Author: Eric W. Biederman Date: Wed Feb 14 00:33:55 2007 -0800 [PATCH] sysctl: C99 convert coda ctl_tables and remove binary sysctls Will converting the coda sysctl initializers I discovered that it is yet another user of sysctl that was stomping CTL_KERN. So off with it's sys_sysctl support since it wasn't done in a supportable way. Signed-off-by: Eric W. Biederman Cc: Jan Harkes Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit 2564b7bd9ba4b4bf941b90f1ccd5e2c00e0f83d3 Author: Eric W. Biederman Date: Wed Feb 14 00:33:54 2007 -0800 [PATCH] sysctl: C99 convert ctl_tables in drivers/parport/procfs.c Signed-off-by: Eric W. Biederman Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit 59fc5313b37328f850105d5f1caa18f11089c9ba Author: Eric W. Biederman Date: Wed Feb 14 00:33:53 2007 -0800 [PATCH] sysctl: register the sysctl number used by the arlan driver Signed-off-by: Eric W. Biederman Cc: "John W. Linville" Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit 7735362ac32062725ba08ece014d669b9bede505 Author: Eric W. Biederman Date: Wed Feb 14 00:33:52 2007 -0800 [PATCH] sysctl: remove sys_sysctl support from drivers/char/rtc.c The real time clock driver was using the binary number reserved for cdroms in the sysctl binary number interface, which is a no-no. So since the sysctl binary interface is wrong remove it. Signed-off-by: Eric W. Biederman Cc: Alessandro Zummo Acked-by: Ralf Baechle Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit 22943364cffd404e1bba4f097ac21bc74031eba3 Author: Eric W. Biederman Date: Wed Feb 14 00:33:51 2007 -0800 [PATCH] sysctl: remove sys_sysctl support from the hpet timer driver In the binary sysctl interface the hpet driver was claiming to be the cdrom driver. This is a no-no so remove support for the binary interface. Signed-off-by: Eric W. Biederman Acked-by: Clemens Ladisch Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit c37ce0324962010e768f2570e2603553263ff219 Author: Eric W. Biederman Date: Wed Feb 14 00:33:51 2007 -0800 [PATCH] sysctl: C99 convert ctl_tables in arch/x86_64/mm/init.c Signed-off-by: Eric W. Biederman Acked-by: Andi Kleen Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit 7a44d37d8c633cfee145c7276c0777defd964858 Author: Eric W. Biederman Date: Wed Feb 14 00:33:50 2007 -0800 [PATCH] sysctl: C99 convert ctl_tables in arch/x86_64/kernel/vsyscall.c Basically everything was done but I removed all element initializers from the trailing entries to make it clear the entire last entry should be zero filled. Signed-off-by: Eric W. Biederman Acked-by: Andi Kleen Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit 306421f387ccea0e8eeb04425e674910f100952b Author: Eric W. Biederman Date: Wed Feb 14 00:33:49 2007 -0800 [PATCH] sysctl: C99 convert ctl_tables in arch/x86_64/ia32/ia32_binfmt.c Signed-off-by: Eric W. Biederman Acked-by: Andi Kleen Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit f3854517f3b4cf372d3d5a2a71969c9b26090b7a Author: Eric W. Biederman Date: Wed Feb 14 00:33:49 2007 -0800 [PATCH] sysctl: x86_64: remove unnecessary use of insert_at_head The only sysctl x86_64 provides are not provided elsewhere, so insert_at_head is unnecessary. Signed-off-by: Eric W. Biederman Acked-by: Andi Kleen Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit e3c6449dcdfa023ca45b7ef1f7dce102f34f25ad Author: Eric W. Biederman Date: Wed Feb 14 00:33:48 2007 -0800 [PATCH] sysctl: C99 convert arch/sh64/kernel/traps.c and remove ABI breakage While doing the C99 conversion I notices that the top level sh64 directory was using the binary number for CTL_KERN. That is a no-no so I removed the support for the sysctl binary interface only leaving sysctl /proc support. At least the sysctl tables were placed at the end of the list so user space did not see this mistake. Signed-off-by: Eric W. Biederman Acked-by: Paul Mundt Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit ded2e9bdfc5ac09f29b9f73fc1b75b1080edef90 Author: Eric W. Biederman Date: Wed Feb 14 00:33:47 2007 -0800 [PATCH] sysctl: C99 convert ctl_tables entries in arch/ppc/kernel/ppc_htab.c And make the mode of the kernel directory 0555 no one is allowed to write to sysctl directories. Signed-off-by: Eric W. Biederman Acked-by: Benjamin Herrenschmidt Cc: Paul Mackerras Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit f5f106784eba94a00bbe73be651e423386ebe6d4 Author: Eric W. Biederman Date: Wed Feb 14 00:33:46 2007 -0800 [PATCH] sysctl: C99 convert ctl_tables in arch/powerpc/kernel/idle.c This was partially done already and there was no ABI breakage what a relief. Signed-off-by: Eric W. Biederman Acked-by: Benjamin Herrenschmidt Cc: Paul Mackerras Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit 481f7337a1316c11b357ab838653f7f9254643be Author: Eric W. Biederman Date: Wed Feb 14 00:33:46 2007 -0800 [PATCH] sysctl: s390: remove unnecessary use of insert_at_head Signed-off-by: Eric W. Biederman Acked-by: Martin Schwidefsky Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit feceb63ec589380f2125edcb70127e6a635af1cc Author: Eric W. Biederman Date: Wed Feb 14 00:33:45 2007 -0800 [PATCH] sysctl: s390: move sysctl definitions to sysctl.h We need to have the the definition of all top level sysctl directories registers in sysctl.h so we don't conflict by accident and cause abi problems. Signed-off-by: Eric W. Biederman Acked-by: Martin Schwidefsky Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit 8d8cb8a1bbd92a77208bdeaa25c3f17f5da9297d Author: Eric W. Biederman Date: Wed Feb 14 00:33:44 2007 -0800 [PATCH] sysctl: C99 convert arch/mips/lasat/sysctl.c and remove ABI breakage While C99 converting the ctl_table initializers I realized that the binary sysctl numbers were in conflict with the binary values under CTL_KERN. Including CTL_KERN KERN_VERSION as used by glibc. So I just removed the sysctl binary interface for these values, as it was unsupportable. Luckily these sysctl were inserted at the end of the sysctl list so this bug was not visible to userspace. Signed-off-by: Eric W. Biederman Acked-by: Ralf Baechle Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit 7ed744d1e8faed90aa027c08eeed21c4120e623d Author: Eric W. Biederman Date: Wed Feb 14 00:33:43 2007 -0800 [PATCH] sysctl: C99 convert the ctl_tables in arch/mips/au1000/common/power.c Signed-off-by: Eric W. Biederman Acked-by: Ralf Baechle Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit ee404566f97f9254433399fbbcfa05390c7c55f7 Author: Eric W. Biederman Date: Wed Feb 14 00:33:43 2007 -0800 [PATCH] sysctl: mips/au1000: remove sys_sysctl support The assignment of binary numbers for sys_sysctl use was in shambles and despite requiring methods. Nothing was implemented on the sys_sysctl side. So this patch gives a mercy killing to the sys_sysctl support for powermanagment on mips/au1000. Signed-off-by: Eric W. Biederman Acked-by: Ralf Baechle Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit 4e0099011838cc72ae693ef9c549bdd20704512d Author: Eric W. Biederman Date: Wed Feb 14 00:33:42 2007 -0800 [PATCH] sysctl: C99 convert arch/ia64/kernel/perfmon and remove ABI breakage This convters the sysctl ctl_tables to use C99 initializers. While I was looking at it I discovered it was using a portion of the sysctl binary addresses space under CTL_KERN KERN_OSTYPE which was completely inappropriate. So I completely removed all of the sysctl binary names, to remove and avoid the ABI conflict. Signed-off-by: Eric W. Biederman Cc: "Luck, Tony" Cc: Stephane Eranian Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit 68cbf0753681b3f79437f16d2f9a259b9346cf84 Author: Eric W. Biederman Date: Wed Feb 14 00:33:41 2007 -0800 [PATCH] sysctl: C99 Convert arch/ia64/sn/kernel/xpc_main.c Signed-off-by: Eric W. Biederman Cc: "Luck, Tony" Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit 79eec3d3d928e8ea20160c941236f11ecca99071 Author: Eric W. Biederman Date: Wed Feb 14 00:33:40 2007 -0800 [PATCH] sysctl: sn: remove sysctl ABI BREAKAGE By not using the enumeration in sysctl.h (or even understanding it) the SN platform placed their arch specific xpc directory on top of CTL_KERN and only because they didn't have 4 entries in their xpc directory got lucky and didn't break glibc. This is totally irresponsible. So this patch entirely removes sys_sysctl support from their sysctl code. Hopefully they don't have ascii name conflicts as well. And now that they have no ABI numbers add them to the end instead of the sysctl list instead of the head so nothing else will be overridden. Cc: Tony Luck Signed-off-by: Eric W. Biederman Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit 317ed68c01cd936a3651c2eb63c47ef2a1ff54e5 Author: Eric W. Biederman Date: Wed Feb 14 00:33:39 2007 -0800 [PATCH] sysctl: C99 convert arch/frv/kernel/sysctl.c Signed-off-by: Eric W. Biederman Acked-by: David Howells Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit dfd007a667982372bfb05583c17bf5d4124c3c50 Author: Eric W. Biederman Date: Wed Feb 14 00:33:39 2007 -0800 [PATCH] sysctl: C99 convert arch/frv/kernel/pm.c Signed-off-by: Eric W. Biederman Acked-by: David Howells Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit c8d1a1ac160421fda233def89065149ba7b0a00a Author: Eric W. Biederman Date: Wed Feb 14 00:33:38 2007 -0800 [PATCH] sysctl: frv: remove unnecessary insert_at_head flag Since the binary sysctl numbers are unique putting the registered sysctls at the head of the sysctl list where they can override existing sysctls serves no useful purpose. Signed-off-by: Eric W. Biederman Acked-by: David Howells Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit 77f6dfb1295cae6e4cbbb90fc6da88fdf27ee95e Author: Eric W. Biederman Date: Wed Feb 14 00:33:37 2007 -0800 [PATCH] sysctl: move CTL_FRV into sysctl.h where it belongs Signed-off-by: Eric W. Biederman Acked-by: David Howells Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit febe1c257901c766a938007ed3710e7d54618756 Author: Eric W. Biederman Date: Wed Feb 14 00:33:37 2007 -0800 [PATCH] sysctl: frv: pm remove unnecessary insert_at_head flag With unique binary numbers setting insert_at_head to insert yourself at the head of sysctl list and thus override existing sysctl entries serves no point. Signed-off-by: Eric W. Biederman Acked-by: David Howells Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit 462591b8868a18e52494e223d1a8f13311f50104 Author: Eric W. Biederman Date: Wed Feb 14 00:33:36 2007 -0800 [PATCH] sysctl: move CTL_PM into sysctl.h where it belongs Signed-off-by: Eric W. Biederman Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit 4b998d4f6e559fb8eba8141263b2fddc9556391b Author: Eric W. Biederman Date: Wed Feb 14 00:33:35 2007 -0800 [PATCH] sysctl: cdrom: don't set de->owner There is no need for open files in /proc/sys/XXX to hold a reference count on the module that provides the file to prevent module unload races. While there is code active in the module p->used in the sysctl_table_header is incremented, preventing the sysctl from being unregisted. Once the sysctl is unregistered it cannot be found. Open files are also not a problem as they revalidate the sysctl information and bump p->used before accessing module code. So setting de->owner is unnecessary, makes for a bad example and gets in my way of removing ctl_table->de. Signed-off-by: Eric W. Biederman Acked-by: Jens Axboe Acked-by: James Bottomley Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit 208367eeec8d6f6fcee1a0672af2149aeee7b658 Author: Eric W. Biederman Date: Wed Feb 14 00:33:34 2007 -0800 [PATCH] sysctl: cdrom: remove unnecessary insert_at_head flag With unique binary sysctl numbers setting insert_at_head to override other sysctl entries is pointless. Signed-off-by: Eric W. Biederman Acked-by: James Bottomley Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit bfe1a1e160f89a176efd871e68ef4cb8429bb582 Author: Eric W. Biederman Date: Wed Feb 14 00:33:33 2007 -0800 [PATCH] sysctl: ipmi: remove unnecessary insert_at_head flag With unique sysctl binary numbers setting insert_at_head is pointless. Signed-off-by: Eric W. Biederman Cc: Corey Minyard Acked-by: Benjamin Herrenschmidt Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit 0a4b9b6ec175d17f35ace35bf6e7196a51562a00 Author: Eric W. Biederman Date: Wed Feb 14 00:33:32 2007 -0800 [PATCH] sysctl: mac_hid: remove unnecessary insert_at_head flag With unique sysctl binary numbers setting insert_at_head is pointless. Signed-off-by: Eric W. Biederman Cc: Jiri Kosina Cc: Benjamin Herrenschmidt Cc: Dmitry Torokhov Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit ff1d28efc56432c57f8e46542b4bb2c290b801ad Author: Eric W. Biederman Date: Wed Feb 14 00:33:32 2007 -0800 [PATCH] sysctl: md: remove unnecessary insert_at_head flag The sysctls used by the md driver are have unique binary numbers so remove the insert_at_head flag as it serves no useful purpose. Signed-off-by: Eric W. Biederman Cc: Neil Brown Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit 01879db3f0f8205e04fbce06062349f258469247 Author: Eric W. Biederman Date: Wed Feb 14 00:33:31 2007 -0800 [PATCH] sysctl: scsi: remove unnecessary insert_at_head flag Signed-off-by: Eric W. Biederman Acked-by: James Bottomley Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit 04c5acfb2413af1698ac27dca69b4d7233dc7249 Author: Eric W. Biederman Date: Wed Feb 14 00:33:30 2007 -0800 [PATCH] sysctl: atalk: remove unnecessary insert_at_head flag Signed-off-by: Eric W. Biederman Cc: Arnaldo Carvalho de Melo Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit 28522366f0a2dcb2b1d3ef5eebcc65fcd7c2a422 Author: Eric W. Biederman Date: Wed Feb 14 00:33:30 2007 -0800 [PATCH] sysctl: ax25: remove unnecessary insert_at_head flag Signed-off-by: Eric W. Biederman Acked-by: Ralf Baechle Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit f7d749fa0a4de0a5445a4f023023f9e702238653 Author: Eric W. Biederman Date: Wed Feb 14 00:33:29 2007 -0800 [PATCH] sysctl: dccp: remove unnecessary insert_at_head flag Signed-off-by: Eric W. Biederman Cc: Arnaldo Carvalho de Melo Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit d87abf42762ee3e77b118ea96517cf8c7d33abc1 Author: Eric W. Biederman Date: Wed Feb 14 00:33:28 2007 -0800 [PATCH] sysctl: decnet: remove unnecessary insert_at_head flag The sysctl numbers used are unique so setting the insert_at_head flag does not succeed in overriding any sysctls, and is just confusing because it doesn't. Clear the flag. Signed-off-by: Eric W. Biederman Cc: Patrick Caulfield Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit ecab963ac1aa7d92369564c5dd4ad04ec5853380 Author: Eric W. Biederman Date: Wed Feb 14 00:33:27 2007 -0800 [PATCH] sysctl: ipx: remove unnecessary insert_at_head flag The sysctl numbers used are unique so setting the insert_at_head flag servers no semantic purpose and is just confusing. Signed-off-by: Eric W. Biederman Cc: Arnaldo Carvalho de Melo Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit 9fa7b46d73d2849a7234d0967152c39deb4e815f Author: Eric W. Biederman Date: Wed Feb 14 00:33:26 2007 -0800 [PATCH] sysctl: llc: remove unnecessary insert_at_head flag The sysctl numbers used are unique so setting the insert_at_head flag serves no semantis purpose, and is just confusing. Signed-off-by: Eric W. Biederman Cc: Arnaldo Carvalho de Melo Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit 6fe6b1755c3d234af076c0d264dc8478acf4510c Author: Eric W. Biederman Date: Wed Feb 14 00:33:26 2007 -0800 [PATCH] sysctl: netrom: remove unnecessary insert_at_head flag The sysctl numbers used are unique so setting the insert_at_head flag serves no semantic purpose, so it is just confusing. Signed-off-by: Eric W. Biederman Acked-by: Ralf Baechle Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit 2d4381dec31865d7882312bef4cb8da2b12621ff Author: Eric W. Biederman Date: Wed Feb 14 00:33:25 2007 -0800 [PATCH] sysctl: rose: remove unnecessary insert_at_head flag The sysctl numbers used are unique so setting the insert_at_head flag serves no semantic purpose. Signed-off-by: Eric W. Biederman Acked-by: Ralf Baechle Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit 2b1bec5f52fec033ed0026e7d85f641e20e1cbb9 Author: Eric W. Biederman Date: Wed Feb 14 00:33:24 2007 -0800 [PATCH] sysctl: sunrpc: don't unnecessarily set ctl_table->de We don't need this to prevent module unload races so remove the unnecessary code. Signed-off-by: Eric W. Biederman Cc: Trond Myklebust Cc: Neil Brown Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit 7e35280e517c28b991667a608990227503dd2a30 Author: Eric W. Biederman Date: Wed Feb 14 00:33:23 2007 -0800 [PATCH] sysctl: sunrpc: remove unnecessary insert_at_head flag Because the sunrpc sysctls don't conflict with any other sysctls the setting the insert at head flag to register_sysctl has no semantic meaning. Signed-off-by: Eric W. Biederman Cc: Trond Myklebust Cc: Neil Brown Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit 50d851f7227cf9e7fcc4cd1d2b3c72ddd64c50e6 Author: Eric W. Biederman Date: Wed Feb 14 00:33:22 2007 -0800 [PATCH] sysctl: move CTL_SUNRPC to sysctl.h where it belongs Signed-off-by: Eric W. Biederman Cc: Trond Myklebust Cc: Neil Brown Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit b402f06d6e31b8c3c74bfc3e7d2e292dd4a1b90a Author: Eric W. Biederman Date: Wed Feb 14 00:33:21 2007 -0800 [PATCH] sysctl: x25: remove unnecessary insert_at_head from register_sysctl_table There has not been much maintenance on sysctl in years, and as a result is there is a lot to do to allow future interesting work to happen, and being ambitious I'm trying to do it all at once :) The patches in this series fall into several general categories. - Removal of useless attempts to override the standard sysctls - Registers of sysctl numbers in sysctl.h so someone else does not use the magic number and conflict. - C99 conversions so it becomes possible to change the layout of struct ctl_table without breaking everything. - Removal of useless claims of module ownership, in the proc dir entries - Removal of sys_sysctl support where people had used conflicting sysctl numbers. Trying to break glibc or other applications by changing the ABI is not cool. 9 instances of this in the kernel seems a little extreme. - General enhancements when I got the junk I could see out. This patch: Since x25 uses unique binary numbers inserting yourself at the head of the search list for sysctls so you can override already registered sysctls is pointless. Signed-off-by: Eric W. Biederman Cc: Ralf Baechle Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit aa2e3e4f83590fa4c69fe95f01c1a52557859d19 Author: Andrew Morton Date: Wed Feb 14 00:33:20 2007 -0800 [PATCH] scheduled removal of SA_XXX interrupt flags: ata fix SA_SHIRQ is going away. Cc: Jeff Garzik Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit 2db6346f76ac5bd5b632373240e3e54828111837 Author: Thomas Gleixner Date: Wed Feb 14 00:33:20 2007 -0800 [PATCH] Scheduled removal of SA_xxx interrupt flags fixups 2 The obsolete SA_xxx interrupt flags have been used despite the scheduled removal. Fixup the remaining users in -mm. Signed-off-by: Thomas Gleixner Acked-by: Ingo Molnar Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit 38515e908ba3a9c467ad3bf347b9bce69216df94 Author: Thomas Gleixner Date: Wed Feb 14 00:33:16 2007 -0800 [PATCH] Scheduled removal of SA_xxx interrupt flags fixups The obsolete SA_xxx interrupt flags have been used despite the scheduled removal. Fixup the remaining users. Signed-off-by: Thomas Gleixner Acked-by: Ingo Molnar Cc: "Luck, Tony" Cc: Roman Zippel Cc: Geert Uytterhoeven Cc: Jeff Garzik Cc: Wim Van Sebroeck Cc: Roland Dreier Cc: Alessandro Zummo Cc: James Bottomley Cc: Greg KH Cc: Dave Airlie Cc: James Simmons Cc: "Antonino A. Daplas" Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit 3159f06dc2303630c02d1ad2eeaeaf341414c9df Author: Robert P. J. Day Date: Wed Feb 14 00:33:16 2007 -0800 [PATCH] OSS: replace kmalloc()+memset() combos with kzalloc() Replace kmalloc() + memset() pairs with the appropriate kzalloc() calls. Signed-off-by: Robert P. J. Day Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit cd354f1ae75e6466a7e31b727faede57a1f89ca5 Author: Tim Schmielau Date: Wed Feb 14 00:33:14 2007 -0800 [PATCH] remove many unneeded #includes of sched.h After Al Viro (finally) succeeded in removing the sched.h #include in module.h recently, it makes sense again to remove other superfluous sched.h includes. There are quite a lot of files which include it but don't actually need anything defined in there. Presumably these includes were once needed for macros that used to live in sched.h, but moved to other header files in the course of cleaning it up. To ease the pain, this time I did not fiddle with any header files and only removed #includes from .c-files, which tend to cause less trouble. Compile tested against 2.6.20-rc2 and 2.6.20-rc2-mm2 (with offsets) on alpha, arm, i386, ia64, mips, powerpc, and x86_64 with allnoconfig, defconfig, allmodconfig, and allyesconfig as well as a few randconfigs on x86_64 and all configs in arch/arm/configs on arm. I also checked that no new warnings were introduced by the patch (actually, some warnings are removed that were emitted by unnecessarily included header files). Signed-off-by: Tim Schmielau Acked-by: Russell King Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit 3fc605a2aa38899c12180ca311f1eeb61a6d867e Author: NeilBrown Date: Wed Feb 14 00:33:13 2007 -0800 [PATCH] knfsd: allow the server to provide a gid list when using AUTH_UNIX authentication AUTH_UNIX authentication (the standard with NFS) has a limit of 16 groups ids. This causes problems for people in more than 16 groups. So allow the server to map a uid into a list of group ids based on local knowledge rather depending on the (possibly truncated) list from the client. If there is no process on the server responding to upcalls, the gidlist in the request will still be used. Signed-off-by: Neil Brown Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit af6a4e280e3ff453653f39190b57b345ff0bec16 Author: NeilBrown Date: Wed Feb 14 00:33:12 2007 -0800 [PATCH] knfsd: add some new fsid types Add support for using a filesystem UUID to identify and export point in the filehandle. For NFSv2, this UUID is xor-ed down to 4 or 8 bytes so that it doesn't take up too much room. For NFSv3+, we use the full 16 bytes, and possibly also a 64bit inode number for exports beneath the root of a filesystem. When generating an fsid to return in 'stat' information, use the UUID (hashed down to size) if it is available and a small 'fsid' was not specifically provided. Signed-off-by: Neil Brown Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit 982aedfd091e6d9831216f8519f12242091be4fd Author: NeilBrown Date: Wed Feb 14 00:33:11 2007 -0800 [PATCH] knfsd: tidy up choice of filesystem-identifier when creating a filehandle If we are using the same version/fsid as a current filehandle, then there is no need to verify the the numbers are valid for this export, and they must be (we used them to find this export). This allows us to simplify the fsid selection code. Also change "ref_fh_version" and "ref_fh_fsid_type" to "version" and "fsid_type", as the important thing isn't that they are the version/type of the reference filehandle, but they are the chosen type for the new filehandle. And tidy up some indenting. Signed-off-by: Neil Brown Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit 8971a1016b9db4164c3c1b47ae1fde2818becf91 Author: NeilBrown Date: Wed Feb 14 00:33:11 2007 -0800 [PATCH] knfsd: fix return value for writes to some files in 'nfsd' filesystem Most files in the 'nfsd' filesystem are transactional. When you write, a reply is generated that can be read back only on the same 'file'. If the reply has zero length, the 'write' will incorrectly return a value of '0' instead of the length that was written. This causes 'rpc.nfsd' to give an annoying warning. This patch fixes the test. Signed-off-by: Neil Brown Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit 754ce4f29937ba11f16afa41a648a30b0fc1f075 Author: Haavard Skinnemoen Date: Wed Feb 14 00:33:09 2007 -0800 [PATCH] SPI: atmel_spi driver Driver for the Atmel on-chip SPI master controller. Tested primarily on AVR32/AT32AP7000/ATSTK1000 using mtd_dataflash and the jffs2 filesystem. Should also work fine on various AT91 ARM-based chips like AT91SAM926x and AT91RM9200. Hardware documentation can be found in the AT32AP7000 data sheet, or its AT91 siblings, which can be downloaded from http://www.atmel.com/dyn/products/datasheets.asp?family_id=682 Signed-off-by: Haavard Skinnemoen Signed-off-by: David Brownell Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit de8211b96b8491911bcb222d153c0986cb522bd6 Author: Vitaly Wool Date: Wed Feb 14 00:33:09 2007 -0800 [PATCH] PNX8550 UART driver Add UART support for PNX8330/8550/8950 Philips MIPS-based SoCs. Signed-off-by: Vitaly Wool Cc: Russell King Cc: Alan Cox Cc: Ralf Baechle Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit e6fa0ba304f0642b5e9454c20b07740b8bf2c416 Author: Vitaly Wool Date: Wed Feb 14 00:33:08 2007 -0800 [PATCH] fix PNX8550 serial breakage Fix the serial header breakage for the PNX8550 MIPS platform. Signed-off-by: Vitaly Wool Cc: Ralf Baechle Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit 8f31bb39ec2a5622974666c72257e74c22492602 Author: Burman Yan Date: Wed Feb 14 00:33:07 2007 -0800 [PATCH] serial: replace kmalloc+memset with kzalloc Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit 3689a0ec60bc8f56cc372c1dfa0d89dab48f7c9c Author: George G. Davis Date: Wed Feb 14 00:33:06 2007 -0800 [PATCH] serial: make sure UART is powered up when dumping MCTRL status Since serial devices are powered down when not in use and some of those devices cannot be accessed when powered down, we need to enable power around calls to get_mcrtl() when dumping port state via uart_line_info(). This resolves hangs observed on some machines while reading serial device registers when a port is powered off. Signed-off-by: George G. Davis Cc: Russell King Cc: Alan Cox Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit 9b22271d4b8c1be8a81563c322d3f04e7cbe2153 Author: Bjorn Helgaas Date: Wed Feb 14 00:33:05 2007 -0800 [PATCH] serial: trivial code flow simplification Return failure immediately, so we don't have to test it twice. Signed-off-by: Bjorn Helgaas Cc: Adam Belay Cc: Russell King Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit 40b36daad0ac704e6d5c1b75789f371ef5b053c1 Author: Alex Williamson Date: Wed Feb 14 00:33:04 2007 -0800 [PATCH] 8250 UART backup timer The patch below works around a minor bug found in the UART of the remote management card used in many HP ia64 and parisc servers (aka the Diva UARTs). The problem is that the UART does not reassert the THRE interrupt if it has been previously cleared and the IIR THRI bit is re-enabled. This can produce a very annoying failure mode when used as a serial console, allowing a boot/reboot to hang indefinitely until an RX interrupt kicks it into working again (ie. an unattended reboot could stall). To solve this problem, a backup timer is introduced that runs alongside the standard interrupt driven mechanism. This timer wakes up periodically, checks for a hang condition and gets characters moving again. This backup mechanism is only enabled if the UART is detected as having this problem, so systems without these UARTs will have no additional overhead. This version of the patch incorporates previous comments from Pavel and removes races in the bug detection code. The test is now done before the irq linking to prevent races with interrupt handler clearing the THRE interrupt. Short delays and syncs are also added to ensure the device is able to update register state before the result is tested. Aristeu says: this was tested on the following HP machines and solved the problem: rx2600, rx2620, rx1600 and rx1620s. hpa says: I have seen this same bug in soft UART IP from "a major vendor." Signed-off-by: Alex Williamson Cc: "H. Peter Anvin" Cc: Russell King Acked-by: Aristeu Sergio Rozanski Filho Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit ed8b4d4d7a31923db32f4684535944d69eb43677 Author: Cyrill V. Gorcunov Date: Wed Feb 14 00:33:03 2007 -0800 [PATCH] qconf: hide empty list items This patch fixes showing empty config list items if "Option/Show All Options" is turned on. For example empty items appears on list of 'Block Layer' menu. Signed-off-by: Cyrill V. Gorcunov Cc: Roman Zippel Cc: Sam Ravnborg Cc: Oleg Verych Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit 1f85712e6e1f2450ec4fd2ab18f8887bf7280f8e Author: Mike Frysinger Date: Wed Feb 14 00:33:02 2007 -0800 [PATCH] new toplevel target: headers_check_all Add new headers_check_all target for checking all arches in one go. Useful for distros (and people with too much time on their hands) that support a ton of architectures, headers_check_all is to headers_check as headers_install_all is to headers_install Signed-off-by: Mike Frysinger Cc: David Woodhouse Cc: Sam Ravnborg Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit d395efb544aba803ffe42b16a1862be655aca369 Author: Robert P. J. Day Date: Wed Feb 14 00:33:01 2007 -0800 [PATCH] Kbuild: Remove references to deprecated "prepare-all" target from Makefile Remove references to the deprecated "make prepare-all" target from the top-level Makefile; use just "make prepare" instead. Signed-off-by: Robert P. J. Day Cc: Sam Ravnborg Acked-by: Oleg Verych Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit f253f00003c3fed0355cf49482f24c56bc5dbea6 Author: Cyrill V. Gorcunov Date: Wed Feb 14 00:33:00 2007 -0800 [PATCH] qconf: Back button behaviour normalization Do "Back" button behaviour normalization so it is enabled starting from second-level menu only. Signed-off-by: Cyrill V. Gorcunov Cc: Roman Zippel Cc: Sam Ravnborg Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit 786fb18d015cc5f34284d426e055ddd7a3dbb53b Author: Cyrill V. Gorcunov Date: Wed Feb 14 00:32:59 2007 -0800 [PATCH] qconf: fix showing help info on failed search qconf does not clear help text in search window if previous search has been failed. Signed-off-by: Cyrill V. Gorcunov Cc: Roman Zippel Cc: Sam Ravnborg Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit 66e7c7230fed159e138fc1292ee662b8bbdb74d6 Author: Shlomi Fish Date: Wed Feb 14 00:32:58 2007 -0800 [PATCH] qconf: relocate Search Command Relocate the qconf search command to the "Edit"->"Find" menu option. This is per the discussion on my qconf search dialog patch. Cc: Sam Ravnborg Cc: Roman Zippel Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit 49e5646d6538f3a1c6697770f0bec2b2a0b7f30e Author: Karsten Wiese Date: Wed Feb 14 00:32:57 2007 -0800 [PATCH] qconf: immediately update integer and string values in xconfig display In xconfig's display integer and string values are also shown as part of the config item's descriptive text. This patch updates the descriptive text, when the corresponding value has been changed. Fix for http://bugzilla.kernel.org/show_bug.cgi?id=7744 Take2 uses updateList() so config values dependending on the changed value see the change. Signed-off-by: Karsten Wiese Cc: Roman Zippel Cc: Randy Dunlap Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit e0ab1ec9fcd3799e874ff9086729a480f6c06cd3 Author: Nicolas Pitre Date: Wed Feb 14 00:32:56 2007 -0800 [PATCH] add .mailmap for proper git-shortlog output This list was built into the git-shortlog tool and has been removed in the latest version. It should be maintained separately so this is what this patch does. A couple more entries were added to the original list as well. Signed-off-by: Nicolas Pitre Acked-by: Junio C Hamano Cc: Linus Torvalds Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit 895a39a084e5478121a74752a291165c4502378f Author: s situert Date: Wed Feb 14 00:32:55 2007 -0800 [PATCH] Make mkcompile_h use LANG=C and LC_ALL=C for $CC -v Fix a minor bug in mkcompile_h. As one can see, the current locale is used while getting the version of gcc. This produces problems when a locale other than C or en_US is used. As an example, my /proc/version contains Turkish characters in iso-8859-9 encoding. This patch fixes this issue by making sure that the C locale is used to get gcc's version. Cc: Sam Ravnborg Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit 8c7e4498adfdb4aea5a0d056590ec18d099ba062 Author: Mike Frysinger Date: Wed Feb 14 00:32:54 2007 -0800 [PATCH] search a little harder for mkimage Check to see if `${CROSS_COMPILE}mkimage` exists and if not, fall back to the standard `mkimage` The Blackfin toolchain includes mkimage, but we dont want to namespace collide with any of the user's system setup, so we prefix it with our toolchain name. Signed-off-by: Mike Frysinger Cc: Sam Ravnborg Cc: Oleg Verych Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit b7de8e7e3c7b79a72c20c7fd58bd65df3d146b13 Author: Roland Dreier Date: Wed Feb 14 00:32:53 2007 -0800 [PATCH] ia64: fix noncoherent DMA API so devres builds On ia64, drivers/base/dma-mapping.c doesn't build because it calls dma_alloc_noncoherent() and dma_free_noncoherent(), which appear to be terminally broken; the calls end up generating errors like drivers/base/dma-mapping.c: In function 'dmam_noncoherent_release': drivers/base/dma-mapping.c:32: error: 'struct ia64_machine_vector' has no member named 'platform_dma_free_coherent' because the multiple levels of macro expansion in and end up turning a call to dma_free_noncoherent() into ia64_mv.platform_dma_free_coherent (instead of the intended ia64_mv.dma_free_coherent). This patch fixes this by converting dma_{alloc,free}_noncoherent() into inline functions that call the corresponding coherent functions, instead of trying to do this with macros. Signed-off-by: Roland Dreier Acked-by: Tony Luck Cc: Al Viro Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit ccf2c2229d4473cc1a334200c1b60ab6070adabe Author: Jaroslav Kysela Date: Wed Feb 14 08:42:20 2007 +0100 [ALSA] version 1.0.14rc2 Signed-off-by: Jaroslav Kysela commit 9879951aa1f499e5f9db92f51cd6e7dfb65e78cb Author: Takashi Iwai Date: Tue Feb 13 15:53:22 2007 +0100 [ALSA] Fix a typo in __dev* changes in portman2x4.c Fix a typo in the last __dev* changes in portman2x4.c. Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela commit fa8f878701888666c124e21d77bf7f3ba2dd2359 Author: Frank Mandarino Date: Mon Feb 12 14:06:22 2007 +0100 [ALSA] Change AT91 PDC register defines for 2.6.20 kernel Use the new PDC register name defines that were updated in Linux 2.6.20. Signed-off-by: Frank Mandarino Signed-off-by: Liam Girdwood Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela commit 2a40534348987346dae1c68c225eff7bc19ff529 Author: Jaroslav Kysela Date: Mon Jan 22 12:59:08 2007 +0100 [ALSA] SoC codecs - fix Kconfig - depends -> depends on Signed-off-by: Jaroslav Kysela commit 788c6043335590e0a483fdc18f85b1405a157bf9 Author: Prarit Bhargava Date: Tue Feb 13 13:11:11 2007 +0100 [ALSA] Fix __devinit and __devexit issues with sound drivers Fix __devinit and __devexit issues with sound drivers. Resolves MODPOST warnings similar to: WARNING: sound/drivers/snd-dummy.o - Section mismatch: reference to .init.text:snd_dummy_probe from .data.rel.local between 'snd_dummy_driver' (at offset 0x0) and 'snd_dummy_controls' WARNING: sound/drivers/snd-mtpav.o - Section mismatch: reference to .init.text:snd_mtpav_probe from .data.rel.local between 'snd_mtpav_driver' (at offset 0x0) and 'snd_mtpav_input' WARNING: sound/drivers/snd-virmidi.o - Section mismatch: reference to .init.text:snd_virmidi_probe from .data.rel.local after 'snd_virmidi_driver' (at offset 0x0) Signed-off-by: Prarit Bhargava Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela commit 46f02ca36e9b2b690ebcef18fa0652c586d6c08e Author: Mikael Nilsson Date: Tue Feb 13 12:46:16 2007 +0100 [ALSA] hda-codec - Patch for enabling LFE on more Dell laptops Fix LFE controls for Dell Inspiron E1705/9400 and XPS M1710 laptops. Signed-off-by: Mikael Nilsson Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela commit 82f30040ada635d5d42a244b6eb84607d9881f5a Author: Tobin Davis Date: Tue Feb 13 12:45:44 2007 +0100 [ALSA] hda-codec - More fixes for Conexant HD Audio support Renamed Conexant 5045 to CX20549 (Venice) per Conexant Documentation Renamed Conexant 5047 to CX20551 (Waikiki) per Conexant Documentation Fixed automute on HP Laptops with CX20551 codec. Fixed recording issues on Toshiba Satelite P100/P105 series laptops Added HP DV8000, DV2000Z, Fujitsu Si1520 support More work to be done on CX20549 based systems, but CX20551 Systems are much better now. Signed-off-by: Tobin Davis Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela commit f38cc317c0a7279bb725ec5c2251726eab3c722b Author: Clemens Ladisch Date: Fri Feb 9 20:52:55 2007 +0100 [ALSA] usb-audio: add PCR-A PCM support Add support for the PCM interfaces of the Edirol PCR-A. Signed-off-by: Clemens Ladisch Signed-off-by: Jaroslav Kysela commit 5dc5ebb7bc143fe38a56b9dd9c1d89220e20694a Author: Clemens Ladisch Date: Fri Feb 9 20:51:55 2007 +0100 [ALSA] emu10k1: fix typo fix a typo Signed-off-by: Clemens Ladisch Signed-off-by: Jaroslav Kysela commit 596f967f501799f87fded9e296ce0b14cd233674 Author: Jiri Kosina Date: Fri Feb 9 12:54:44 2007 +0100 [ALSA] usbaudio - remove urb->bandwidth reference Recent changes in usbcore removed the bandwidth field from struct urb. Remove the occurence in usbaudio.c Signed-off-by: Jiri Kosina Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela commit 9e292c0013d7d4158169eb9786aa0f9816eb5b40 Author: Takashi Iwai Date: Fri Feb 9 12:42:03 2007 +0100 [ALSA] ac97 - Fix silent output problem with Cx20551 codec Fixed the silent output problem on laptops with Conexant Cx20551 codec chip, such as Packard-bell EasyNote A* series. The information was taken from ALSA bug#1134. Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela commit 9e507abd87103b5263bb0bbd94a15d74004557e9 Author: Takashi Iwai Date: Thu Feb 8 17:50:10 2007 +0100 [ALSA] hda-codec - Fix Oops with probing sigmatel codec chips When a device is unkown, the driver tries to set up the codec based on the BIOS information. Then it may result in Oops if BIOS is broken. The patch fixes the issue, falling back to a reference model in such a case. Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela commit e65fa9f59e9230b72ac298d445b4a18a4eefeb34 Author: Paul Mundt Date: Wed Feb 14 15:06:09 2007 +0900 sh: Kill off dead bigsur and ec3104 boards. Neither of these have had any maintenance in years, and there's no interest in keeping them straggling along. These have already been slated for removal some time, so finally just get rid of them. Signed-off-by: Paul Mundt commit 71074d3a2c70aa8a213222fef5014bfd9b3daf1f Author: Paul Mundt Date: Wed Feb 14 14:49:04 2007 +0900 sh: Fixup r7780rp pata_platform for devres conversion. Tidy up the R7780RP I/O mapping routines and switch the pata_platform resources to IORESOURCE_MEM types, killing off the useless port->addr conversion. This fixes up R7780RP to boot after the recent devres conversion. Signed-off-by: Paul Mundt commit db2e1fa3f0eefbbe04e90d6e4d290ee176b28248 Author: Paul Mundt Date: Wed Feb 14 14:13:10 2007 +0900 sh: Revert TLB miss fast-path changes that broke PTEA parts. This ended up causing problems for older parts (particularly ones using PTEA). Revert this for now, it can be added back in once it's had some more testing. Signed-off-by: Paul Mundt commit 8af18971584d1e05770560206cfdfd1d6ba8a17f Author: Steve French Date: Wed Feb 14 04:42:51 2007 +0000 [CIFS] on reconnect to Samba - reset the unix capabilities After temporary server or network failure and reconneciton, we were not resending the unix capabilities via SetFSInfo - which confused Samba posix byte range locking code. Discovered by jra Signed-off-by: Steve French commit b6f45a4b071d77777d70e097d429273aeedff717 Author: Rafa³ Bilski Date: Mon Feb 12 22:19:12 2007 +0100 [CPUFREQ] EPS - Correct 2nd brand test Solution for small, but nasty bug: access beyond end of f_table for C7 brand. Signed-off-by: Rafal Bilski Signed-off-by: Dave Jones commit 719c91ccadd3ed26570dbb29d54166914832eee9 Author: David Gibson Date: Tue Feb 13 15:54:22 2007 +1100 [POWERPC] Use udbg_early_init() on ppc32 udbg_early_init() is a function used on 64 bit systems, which initializes whichever early udbg backend is configured. This function is not called on 32-bit, however if btext early debug is enabled it does have an explicit, inline, #ifdef-ed assignment performing analagous initialization. This patch makes things more uniform by folding the btext initialization as an option into udbg_early_init() and calling that from the 32-bit setup path. Signed-off-by: David Gibson Signed-off-by: Paul Mackerras commit 8d38a5b2fab1397d35ba1c92828a91b77ce9f865 Author: Arnd Bergmann Date: Tue Feb 13 21:35:38 2007 +0100 [POWERPC] Open Firmware serial port driver This can be used for serial ports that are connected to an OF platform bus but are not autodetected by the lecacy serial support. It will automatically take over devices that come from the legacy serial detection, which usually is only one device. In some cases, rtas may be set up to use the serial port in the firmware, which allows easier debugging before probing the serial ports. In this case, the "used-by-rtas" property must be set by the firmware. This patch also adds code to the legacy serial driver to check for this. Signed-off-by: Arnd Bergmann Signed-off-by: Paul Mackerras commit 775aeff44774c6933d8f9c14e1f325d8acd03136 Author: Michael Ellerman Date: Thu Feb 8 18:34:04 2007 +1100 [POWERPC] Move MPIC smp routines into mpic.c Move a couple of MPIC smp routines into mpic.c, they're inside an SMP block in mpic.c - so they're still only built for SMP. Signed-off-by: Michael Ellerman Signed-off-by: Paul Mackerras commit dce623e0827e8d0ad60ce7f385c3394bf1b0bae0 Author: Michael Ellerman Date: Thu Feb 8 18:33:55 2007 +1100 [POWERPC] Cleanup pseries kexec code Move all the pseries kexec code into one file, platforms/pseries/kexec.c Provide helpers for setting up ppc_md.kexec_cpu_down, so that we don't have to have #ifdef CONFIG_KEXEC in setup.c Move the initialisation of the ppc_md kexec callbacks into an init routine. This is well and truly early enough to cause no change in behaviour, we can't kexec until userspace has given us a kernel to kexec into. Signed-off-by: Michael Ellerman Signed-off-by: Paul Mackerras commit 8feaeca23ab8f520e7af2a862fd6ea8e7bfd8854 Author: Michael Ellerman Date: Thu Feb 8 18:33:55 2007 +1100 [POWERPC] Cleanup pseries smp initialisation code Move some extern declarations from setup.c into the new pseries.h. While we're at it, provide dummy implementations for !SMP, to avoid cluttering the C file with more #ifdefs. Signed-off-by: Michael Ellerman Signed-off-by: Paul Mackerras commit 577830b034bc11c93d4b9e21e8782900d5485e7f Author: Michael Ellerman Date: Thu Feb 8 18:33:51 2007 +1100 [POWERPC] Consolidate pseries platform header files into pseries.h Following the example of platforms/pasemi, consolidate a couple of tiny header files in platforms/pseries into pseries.h. This gives us a convenient place to put things that need to be available to the platform code, but not public. And hopefully will help people resist the temptation of sticking externs in C files. Signed-off-by: Michael Ellerman Signed-off-by: Paul Mackerras commit 7f1f86a0d04e79f8165e6f50d329a520b8cd11e5 Author: Eric W. Biederman Date: Tue Feb 13 14:38:58 2007 -0700 [PATCH] Fix SAK_work workqueue initialization. Somewhere in the rewrite of the work queues my cleanup of SAK handling got broken. Maybe I didn't retest it properly or possibly the API was changing so fast I missed something. Regardless currently triggering a SAK now generates an ugly BUG_ON and kills the kernel. Thanks to Alexey Dobriyan for spotting this. This modifies the use of SAK_work to initialize it when the data structure it resides in is initialized, and to simply call schedule_work when we need to generate a SAK. I update both data structures that have a SAK_work member for consistency. All of the old PREPARE_WORK calls that are now gone. If we call schedule_work again before it has processed it has generated the first SAK it will simply ignore the duplicate schedule_work request. Signed-off-by: Eric W. Biederman Signed-off-by: Linus Torvalds commit 431dc8040354db65e4f8d4d4e21ae4fab41f5bc3 Author: Ralf Baechle Date: Tue Feb 13 00:05:11 2007 +0000 [MIPS] Fix sigset_t endianess swapping issues in 32-bit compat code. Signed-off-by: Ralf Baechle commit 366d6aef281a670b32a51d289fc07bf0e5e72d9a Author: Andrew Sharp Date: Fri Feb 9 17:35:28 2007 -0800 [MIPS] Fix uniprocessor Sibyte builds. Signed-off-by: Andrew Sharp Signed-off-by: Ralf Baechle commit 7da8a581f5ec0ecac5f0afc9ec26ce13b780d48d Author: Franck Bui-Huu Date: Tue Feb 13 14:50:18 2007 +0100 [MIPS] Make entry.S a little more readable. When CONFIG_PREEMPT is not set, it also moves one branch instruction from ret_from_irq() to ret_from_exception(). Therefore we favour the return from irq case which should be more common than the other one. Signed-off-by: Franck Bui-Huu Acked-by: Atsushi Nemoto Signed-off-by: Ralf Baechle commit 6f3aa38e191326a82d5dcae1f6cdc88b1d9a8d32 Author: Ralf Baechle Date: Tue Feb 13 15:01:21 2007 +0000 [MIPS] Remove stray instruction from __get_user_asm_ll32. This did result in double clearing of the error return value on success only but should make a meassurable overhead for sigreturn. Signed-off-by: Ralf Baechle commit cb66fb3f156b485b22db97db22e96db4786dc68b Author: Ralf Baechle Date: Tue Feb 13 11:45:24 2007 +0000 [MIPS] 32-bit: Fix warning about cast for fetching pointer from userspace. Signed-off-by: Ralf Baechle commit d01f06ef0c783eceb53030fc5407caa94586bd6a Author: Atsushi Nemoto Date: Mon Feb 12 23:48:26 2007 +0900 [MIPS] DECstation: Fix irq handling When I post a patch (commit f431baa55abf8adeed0c718b51deacbc151f58f1), I just tried to not change behavior of existing codes, but it seems dec/int-handler.S had been broken since its previous commit 937a801576f954bd030d7c4a5a94571710d87c0b. The caller of plat_irq_dispatch do setup/restore TI_REGS($28), so dec's plat_irq_dispatch should not do it, and there is no need to adjust RA. Signed-off-by: Atsushi Nemoto Signed-off-by: Ralf Baechle commit 24c556e99ec8a61ce1fbc75bee61dc19edf2c4df Author: Franck Bui-Huu Date: Fri Feb 9 16:07:37 2007 +0100 [MIPS] signals: make common _BLOCKABLE macro Signed-off-by: Franck Bui-Huu Signed-off-by: Ralf Baechle commit 66680583461d7cae281cef63c050c9b6371e3286 Author: Ralf Baechle Date: Tue Feb 13 01:31:48 2007 +0000 [MIPS] signal: Move sigframe definition for native O32/N64 into signal.c Signed-off-by: Ralf Baechle commit 205d84aaea380bbd1cc1079d44086cd50c2c2dad Author: Ralf Baechle Date: Tue Feb 13 01:28:09 2007 +0000 [MIPS] signal: Move {restore,setup}_sigcontext prototypes to their user Signed-off-by: Ralf Baechle commit dd02f06aa96ab4590da12704366450a2d4753d3c Author: Ralf Baechle Date: Tue Feb 13 00:50:57 2007 +0000 [MIPS] signal: Fix warnings in o32 compat code. Signed-off-by: Ralf Baechle commit af3d10d52d38d2c56a8bca9943c07b00031fc718 Author: Ralf Baechle Date: Mon Feb 12 23:26:01 2007 +0000 [MIPS] IP27: Enable N32 support in defconfig. Signed-off-by: Ralf Baechle commit cd1fb9eabea38489579284e0cae0c7019b77b10f Author: Ralf Baechle Date: Mon Feb 12 23:12:38 2007 +0000 Revert "[MIPS] Fix warning in get_user when fetching pointer object from userspace." This reverts commit 4ed3a77f38c023658784804cb39a7ce18063dc88. commit 84b47a959b55930e86d6178d49769bc9ba34bce1 Author: Ralf Baechle Date: Mon Feb 12 22:22:53 2007 +0000 [MIPS] Don't claim we support dma_declare_coherent_memory - we don't. Signed-off-by: Ralf Baechle commit 9a88cbb5227970757881b1a65be01dea61fe2584 Author: Ralf Baechle Date: Thu Nov 16 02:56:12 2006 +0000 [MIPS] Unify dma-{coherent,noncoherent.ip27,ip32} Platforms will now have to supply a function dma_device_is_coherent which returns if a particular device participates in the coherence domain. For most platforms this function will always return 0 or 1. Signed-off-by: Ralf Baechle commit f65e4fa8e0c6022ad58dc88d1b11b12589ed7f9f Author: Ralf Baechle Date: Thu Sep 28 01:45:21 2006 +0100 [MIPS] Improve branch prediction in ll/sc atomic operations. Now that finally all supported versions of binutils have functioning support for .subsection use .subsection to tweak the branch prediction I did not modify the R10000 errata variants because it seems unclear if this will invalidate the workaround which actually relies on the cheesy prediction of branch likely to cause a misspredict if the sc was successful. Signed-off-by: Ralf Baechle commit 02ed82ccc5171bc3c88666568edcb71f3d4a79f6 Author: Becky Bruce Date: Tue Feb 13 16:00:49 2007 -0600 [POWERPC] 85xx: Drop use of SYNC macro in head_fsl_booke.S Eliminate needless invocation of the SYNC macro (which always evaluates to nothing on BookE) from head_fsl_booke.S (for both arch/ppc & arch/powerpc). Signed-off-by: Becky Bruce Signed-off-by: Kumar Gala commit 5dd3ffae0afe355738eca14da1b47284bdae6240 Author: Jean Delvare Date: Tue Feb 13 22:09:04 2007 +0100 i2c: Stop using i2c_adapter.class_dev Stop using i2c_adapter.class_dev, as it is going to be removed soon. Luckily, there are only 4 RTC drivers affected. Signed-off-by: Jean Delvare Cc: Alessandro Zummo commit fe2c8d51af96ef7b8ec0bfd70ec62bbe32c0696e Author: Jean Delvare Date: Tue Feb 13 22:09:04 2007 +0100 i2c: Remove the warning on missing adapter device Now that the i2c_adapter migration plan changed and we are going to keep i2c_adapter.dev, it's no longer that urgent to add a proper device to all i2c_adapter drivers. Thus is seems resonable to degrade the warning asking authors to migrate their driver to a debug message. Signed-off-by: Jean Delvare commit 12a917f69d1468c91d646dbad8408dd0d39d6207 Author: Jean Delvare Date: Tue Feb 13 22:09:03 2007 +0100 i2c: Declare more i2c_adapter parent devices Declare the parent device of i2c_adapter devices each time we can easily do so. It makes the i2c_adapter appear at the right place in the device tree, rather than as a platform device. Signed-off-by: Jean Delvare Cc: David Brownell Cc: Len Brown Cc: Jordan Crouse Cc: Jody McIntyre Cc: Stefan Richter Cc: v4l-dvb-maintainer@linuxtv.org Cc: Petr Vandrovec commit beb58aa39e6e5a52875defe12c7697b0bfa95d4c Author: Olof Johansson Date: Tue Feb 13 22:09:03 2007 +0100 i2c: PA Semi SMBus driver New driver for the PA Semi SMBus interfaces. Signed-off-by: Olof Johansson Signed-off-by: Jean Delvare commit 88b9e750e974febd9128fc622109c526a9d22c10 Author: Jean Delvare Date: Tue Feb 13 22:09:02 2007 +0100 i2c-amd8111: Proposed cleanups Proposed cleanups to the i2c-amd8111 SMBus driver: * Fold long lines. * Add an explicit mask when writing the low byte of a word. * Use I2C_SMBUS_BLOCK_MAX instead of hardcoding 32. * Discard extra blank lines. * Use boolean not instead of bitwise not for bit tests, it's clearer. * Return -EBUSY rather than -1 on I/O resource conflict. * Fix a race on device registration, initialization should be done before the bus is registered. Signed-off-by: Jean Delvare commit 55249cf750e4d9be19c7f8afd502c9ca42de8858 Author: Jonathan McDowell Date: Tue Feb 13 22:09:02 2007 +0100 i2c-parport: Add support for One For All remote JP1 interface This simple patch adds support to i2c-parport for the One For All remote JP1 parallel port interfaces which can be found detailed at: http://www.hifi-remote.com/jp1/hardware.shtml These allow access to the internal configuration EEPROM on various remote controls and there are a variety of Windows tools that make use of this hardware. I have tested this patch with the "simple" parallel port device and a One For All URC-7562 and confirmed that the data read using the eeprom i2c driver matches that returned by the Windows "IR" JP1 tool. Signed-off-by: Jonathan McDowell Signed-off-by: Jean Delvare commit ab6a6ed271c757b429ddc68f5b93a41f9592ab8b Author: Jean Delvare Date: Tue Feb 13 22:09:02 2007 +0100 i2c-viapro: Add support for the VIA CX700 south bridge We do not have any documentation for the CX700, but it was reported to work fine. Thanks to Claas Langbehn for testing. Signed-off-by: Jean Delvare commit 9ace555d7d87c55ceab6999be444c9a17e0e79b4 Author: Stephen Hemminger Date: Tue Feb 13 22:09:01 2007 +0100 i2c: Add IDs to adapters IDs have been defined but not used by most of the I2C adapters. By having a unique ID, clients can check for correct connection during probe. Signed-off-by: Stephen Hemminger Signed-off-by: Jean Delvare commit a394ae15427f215b43fca21f3c9370b0e63ba252 Author: Jean Delvare Date: Tue Feb 13 22:09:01 2007 +0100 i2c: Update the list of bus IDs * The Voodoo3 has no SMBus, it has two bit-banged busses which already have an ID assigned (I2C_HW_B_VOO). * The i2c-ipmi bus driver was a non-sense, it'll never be ported to Linux 2.6. Signed-off-by: Jean Delvare Acked-by: Yani Ioannou commit f37dd80ac2a67e4e4e921f99d34a1ceeb2488abb Author: David Brownell Date: Tue Feb 13 22:09:00 2007 +0100 i2c: Add driver suspend/resume/shutdown support Driver model updates for the I2C core: - Add new suspend(), resume(), and shutdown() methods. Use them in the standard driver model style; document them. - Minor doc updates to highlight zero-initialized fields in drivers, and the driver model accessors for "clientdata". If any i2c drivers were previously using the old suspend/resume calls in "struct driver", they were getting warning messages ... and will now no longer work. Other than that, this patch changes no behaviors; and it lets I2C drivers use conventional PM and shutdown support. Signed-off-by: David Brownell Signed-off-by: Jean Delvare commit b8d6f45b32f6fe72bf7304183275e99332544ce1 Author: Jean Delvare Date: Tue Feb 13 22:09:00 2007 +0100 i2c: completion header cleanups i2c-core and i2c-isa use completions without including . Fix it. i2c-powermac includes but doesn't use any completion. Fix it. Signed-off-by: Jean Delvare Acked-by: Benjamin Herrenschmidt Cc: David Brownell commit 099ab118b6b194ad43865f62776a0d36d4b1c7d2 Author: Jean Delvare Date: Tue Feb 13 22:09:00 2007 +0100 i2c-i801: Document the SMBus unhiding quirk This is a frequently asked question so it deserves a paragraph in the driver documentation. Signed-off-by: Jean Delvare commit fcdd96ecaf04fb4f229ac1a64fe77fda890dffd5 Author: Jean Delvare Date: Tue Feb 13 22:08:59 2007 +0100 i2c-i801: Spelling fix Signed-off-by: Jean Delvare commit 3f9a4790a3818af1228c7fb4286afd66f3201fd0 Author: Mike Frysinger Date: Tue Feb 13 22:08:59 2007 +0100 i2c: Fix typo in SMBus Write Word Data description Write data, don't read it. Signed-off-by: Mike Frysinger Signed-off-by: Jean Delvare commit 4e6697fcc194db8b45559a9863947c6cbfeea363 Author: Jean Delvare Date: Tue Feb 13 22:08:59 2007 +0100 i2c-piix4: Add support for the ATI SB600 Add support for the ATI SB600 SMBus controller. Signed-off-by: Jean Delvare commit 4ef0ce90df3763e277b5307fb580ff1cdaaad7b2 Author: Jean Delvare Date: Tue Feb 13 22:08:58 2007 +0100 i2c-nforce2: Drop unused reference to pci_dev Signed-off-by: Jean Delvare Cc: Hans-Frieder Vogt commit bbeaeef73a0b0a5c43ad2657b61857167d914a55 Author: David Brownell Date: Tue Feb 13 22:08:58 2007 +0100 i2c/vt8231: Remove superfluous initialization Remove a superfluous initialization from the vt8231 hwmon driver; the i2c core does this, and the source field will be vanishing soon. Signed-off-by: David Brownell Signed-off-by: Jean Delvare commit 849be516c57501ec4729bde51babc25a7b073b65 Author: Jean Delvare Date: Tue Feb 13 22:08:57 2007 +0100 i2c-ali1563: Fix device initialization The i2c-ali1563 initialization looks quite broken to me: * If the I/O space isn't enabled, we forcibly set 3 bits in the PCI configuration space instead of just the one enabling the I/O space. * After that we pretend to check if the write worked, but we don't actually read the new value from the register. * It's probably not a good idea to enable the I/O space if no base address has been set. So I propose the following changes to that part of the driver: * Merge ali1563_enable() into ali1563_setup(). * Check the base address before the I/O space enabled bit. Signed-off-by: Jean Delvare Acked-by: Rudolf Marek commit 69735698312f6f5e47001cf62dc678f591b6a6de Author: Jean Delvare Date: Tue Feb 13 22:08:57 2007 +0100 i2c-ali1563: Improve the status messages Improve the status messages printed by the i2c-ali1563 driver. Signed-off-by: Jean Delvare Cc: Rudolf Marek commit c7eb734766217b9ddac217cbccae3aedcfa67520 Author: Maynard Johnson Date: Tue Feb 13 22:02:03 2007 +0100 [POWERPC] cell: pm_rtas_activat_signals routine cleanup The code was setting up the debug bus for group 21 when profiling on the event PPU CYCLES. The debug bus is not actually used by the hardware performance counters when counting PPU CYCLES. Setting up the debug bus for PPU CYCLES causes signal routing conflicts on the debug bus when profiling PPU cycles and another PPU event. This patch fixes the code to only setup the debug bus to route the performance signals for the non PPU CYCLE events. Signed-off-by: Maynard Johnson Signed-off-by: Carl Love Signed-off-by: Arnd Bergmann commit bcb63e25ed3c56ee40cca4d18fbaac1d2a40c1d6 Author: Carl Love Date: Tue Feb 13 22:02:02 2007 +0100 [POWERPC] cell: PPU Oprofile cleanup patch This is a clean up patch that includes the following changes: -Some comments were added to clarify the code based on feedback from the community. -The write_pm_cntrl() and set_count_mode() were passed a structure element from a global variable. The argument was removed so the functions now just operate on the global directly. -The set_pm_event() function call in the cell_virtual_cntr() routine was moved to a for-loop before the for_each_cpu loop Signed-off-by: Carl Love Signed-off-by: Maynard Johnson Signed-off-by: Arnd Bergmann commit 928ba4169dc1d82c83105831f5ddb5472379b440 Author: Kazunori MIYAZAWA Date: Tue Feb 13 12:57:16 2007 -0800 [IPSEC]: Fix the address family to refer encap_family Fix the address family to refer encap_family when comparing with a kernel generated xfrm_state Signed-off-by: Kazunori MIYAZAWA Signed-off-by: David S. Miller commit 73d605d1abbd70ef67b7660cf2ff177259960756 Author: Kazunori MIYAZAWA Date: Tue Feb 13 12:55:55 2007 -0800 [IPSEC]: changing API of xfrm6_tunnel_register This patch changes xfrm6_tunnel register and deregister interface to prepare for solving the conflict of device tunnels with inter address family IPsec tunnel. There is no device which conflicts with IPv4 over IPv6 IPsec tunnel. Signed-off-by: Kazunori MIYAZAWA Signed-off-by: David S. Miller commit 128b8546a83a9e37448bc126e1045dc1db291165 Author: Masato Noguchi Date: Tue Feb 13 21:54:30 2007 +0100 [POWERPC] spufs: avoid accessing kernel memory through mmapped /mem node I found an exploit in current kernel. Currently, there is no range check about mmapping "/mem" node in spufs. Thus, an application can access privilege memory region. In case this kernel already worked on a public server, I send this information only here. If there are such servers in somewhere, please replace it, ASAP. Signed-off-by: Masato Noguchi Signed-off-by: Arnd Bergmann commit 2eb1b12049844a8ebc670e0e4fc908bc3f8933d3 Author: Christoph Hellwig Date: Tue Feb 13 21:54:29 2007 +0100 [POWERPC] spu sched: static timeslicing for SCHED_RR contexts For SCHED_RR tasks we can do some really trivial timeslicing. Basically we fire up a time for every scheduler tick that searches for a higher or same priority thread that is on the runqueue and if there is one context switches to it. Because we can't lock spus from timer context we actually run this from a delayed runqueue instead of a timer. A nice optimization would be to skip the actual priority bitmap search when there are less contexts than physical spus available. To implement this I need a so far unpublished patch from Andre, and it will be added after we have that patch in. Note that right now we only do the time slicing for SCHED_RR tasks. The code would work for SCHED_OTHER tasks aswell, but their prio value is defered from the one the PPU thread has at time of spu_run, and using this for spu scheduling decisions would make the code very unfair. SCHED_OTHER support will be enabled once we the spu scheduler knows how to calculcate cpu_context.prio (very soon) Signed-off-by: Christoph Hellwig Signed-off-by: Arnd Bergmann commit 72cb360839f88c02ccf38f1df214316e05886ff3 Author: Christoph Hellwig Date: Tue Feb 13 21:54:28 2007 +0100 [POWERPC] spu sched: use DECLARE_BITMAP use DECLARE_BITMAP in the spu scheduler instead of reimplementing it. Signed-off-by: Christoph Hellwig Signed-off-by: Arnd Bergmann commit 52f04fcf66a5d5d90790d6cfde52e391ecf2b882 Author: Christoph Hellwig Date: Tue Feb 13 21:54:27 2007 +0100 [POWERPC] spu sched: forced preemption at execution If we start a spu context with realtime priority we want it to run immediately and not wait until some other lower priority thread has finished. Try to find a suitable victim and use it's spu in this case. Signed-off-by: Christoph Hellwig Signed-off-by: Arnd Bergmann commit ae7b4c5284d11d49ed9432c16505fcbeb8d3b8cf Author: Christoph Hellwig Date: Tue Feb 13 21:54:26 2007 +0100 [POWERPC] spu sched: update some comments Give spu_yield a kerneldoc comment and remove the old comment documenting spu_activate, spu_deactive and spu_yield as all of them now have descriptive kerneldoc comments of their own. Signed-off-by: Christoph Hellwig Signed-off-by: Arnd Bergmann commit 678b2ff1e65ecccdb15cbfe97081572fc35944b7 Author: Christoph Hellwig Date: Tue Feb 13 21:54:25 2007 +0100 [POWERPC] spu sched: simplity spu_remove_from_active_list If we call spu_remove_from_active_list that spu is always guaranteed to be on the active list and in runnable state, so we can simply do a list_del to remove it and unconditionally take the was_active codepath. Signed-off-by: Christoph Hellwig Signed-off-by: Arnd Bergmann commit 26bec67386dbf6ef887254e815398842e182cdcd Author: Christoph Hellwig Date: Tue Feb 13 21:54:24 2007 +0100 [POWERPC] spufs: optimize spu_run There is no need to directly wake up contexts in spu_activate when called from spu_run, so add a flag to surpress this wakeup. Signed-off-by: Christoph Hellwig Signed-off-by: Arnd Bergmann commit 079cdb61614c466c939ebf74c7ef6745667bc61e Author: Christoph Hellwig Date: Tue Feb 13 21:54:23 2007 +0100 [POWERPC] spufs: runqueue simplification This is the biggest patch in this series, and it reworks the guts of the spu scheduler runqueue mechanism: - instead of embedding a waitqueue in the runqueue there is now a simple doubly-linked list, the actual wakeups happen by reusing the stop_wq in the spu context (maybe we should rename it one day) - spu_free and spu_prio_wakeup are merged into a single spu_reschedule function - various functionality is split out into small helpers, and kerneldoc comments are added in various places to document what's going on. - spu_activate is rewritten into a tight loop by removing test for various impossible conditions and using the infrastructure in this patch. Signed-off-by: Christoph Hellwig Signed-off-by: Arnd Bergmann commit 8389998ae9ea2888c86c446f7911ddced50052a1 Author: Christoph Hellwig Date: Tue Feb 13 21:54:22 2007 +0100 [POWERPC] spufs: move prio to spu_context It doesn't make any sense to have a priority field in the physical spu structure. Move it into the spu context instead. Signed-off-by: Christoph Hellwig Signed-off-by: Arnd Bergmann commit 6a0641e51011def4e308fd07387047f5ee50647f Author: Christoph Hellwig Date: Tue Feb 13 21:54:21 2007 +0100 [POWERPC] spufs: state_mutex cleanup Various cleanups in code surrounding the state semaphore: - inline spu_acquire/spu_release - cleanup spu_acquire_* and add kerneldoc comments to these functions - remove spu_release_exclusive and replace it with spu_release Signed-off-by: Christoph Hellwig Signed-off-by: Arnd Bergmann commit c73cb5a2d607b5b95a06a54d8291ddb659b348b6 Author: Kazunori MIYAZAWA Date: Tue Feb 13 12:55:25 2007 -0800 [IPSEC]: make sit use the xfrm4_tunnel_register This patch makes sit use xfrm4_tunnel_register instead of inet_add_protocol. It solves conflict of sit device with inter address family IPsec tunnel. Signed-off-by: Kazunori MIYAZAWA Signed-off-by: David S. Miller commit c0d56408e3ff52d635441e0f08d12164a63728cf Author: Kazunori MIYAZAWA Date: Tue Feb 13 12:54:47 2007 -0800 [IPSEC]: Changing API of xfrm4_tunnel_register. This patch changes xfrm4_tunnel register and deregister interface to prepare for solving the conflict of device tunnels with inter address family IPsec tunnel. Signed-off-by: Kazunori MIYAZAWA Signed-off-by: David S. Miller commit 650f8b0291ecd0abdeadbd0ff3d70c3538e55405 Author: Christoph Hellwig Date: Tue Feb 13 21:36:50 2007 +0100 [POWERPC] spufs: simplify state_mutex The r/w semaphore to lock the spus was overkill and can be replaced with a mutex to make it faster, simpler and easier to debug. It also helps to allow making most spufs interruptible in future patches. Signed-off-by: Christoph Hellwig Signed-off-by: Arnd Bergmann commit 202557d29eae528f464652e92085f3b19b05a0a7 Author: Christoph Hellwig Date: Tue Feb 13 21:36:49 2007 +0100 [POWERPC] spufs: sched.c cleanups Various cleanups to sched.c that don't change the global control flow: - add kerneldoc comments to various functions - add spu_ prefixes to various functions - add/remove context from the runqueue in bind/unbind_context as it's part of the logical operation - add a call to put_active_spu to spu_unbind_contex as it's logically part of the unbind operation Signed-off-by: Christoph Hellwig Signed-off-by: Arnd Bergmann commit 81998bafe299b8b675157f0a4dfe8dad43215da9 Author: Christoph Hellwig Date: Tue Feb 13 21:36:48 2007 +0100 [POWERPC] spufs: bind_context sets SPU_STATE_RUNNABLE Only bind_context/unbind_context change the spu context state. Thus we can move all assignents of SPU_STATE_RUNNABLE into bind_context, which parallels the unbind side aswell. Signed-off-by: Christoph Hellwig Signed-off-by: Arnd Bergmann commit aa56c16807ba7b8e801216cab012d2f498755ba5 Author: Christoph Hellwig Date: Tue Feb 13 21:36:47 2007 +0100 [POWERPC] spufs: remove superfluous SPU_STATE_SAVED assignments unbind_context already sets the context state to SPU_STATE_SAVED, thus the spu_deactivate callers don't need to do it again. Signed-off-by: Christoph Hellwig Signed-off-by: Arnd Bergmann commit 5cb23afc9e64841adb43d46160a5c63a80ebfd54 Author: Christoph Hellwig Date: Tue Feb 13 21:36:46 2007 +0100 [POWERPC] spufs: remove empty last line in run.c Remove the empty last line in arch/powerpc/platforms/cell/spufs/run.c. Signed-off-by: Christoph Hellwig Signed-off-by: Arnd Bergmann commit 30a6c337dcefa7583fe9289fedb28783af980c0c Author: Christoph Hellwig Date: Tue Feb 13 21:36:45 2007 +0100 [POWERPC] spufs: remove SPU_CONTEXT_PREEMPT Remove the SPU_CONTEXT_PREEMPT define. It's unused and won't be used in this form after the scheduler rework. Signed-off-by: Christoph Hellwig Signed-off-by: Arnd Bergmann commit 600ff0c24bb71482e7f0da948a931d5c5d72838a Author: Ilpo Järvinen Date: Tue Feb 13 12:42:11 2007 -0800 [TCP]: Prevent pseudo garbage in SYN's advertized window TCP may advertize up to 16-bits window in SYN packets (no window scaling allowed). At the same time, TCP may have rcv_wnd (32-bits) that does not fit to 16-bits without window scaling resulting in pseudo garbage into advertized window from the low-order bits of rcv_wnd. This can happen at least when mss <= (1< Signed-off-by: David S. Miller commit 3d50f23108ff01457d1ca6fb2b5f2da8214e83e4 Author: Patrick McHardy Date: Tue Feb 13 12:36:57 2007 -0800 [NET_SCHED]: sch_hfsc: replace ASSERT macro by WARN_ON Signed-off-by: Patrick McHardy Signed-off-by: David S. Miller commit a10d567c89dfba90dde2e0515e25760fd74cde06 Author: Jarek Poplawski Date: Tue Feb 13 12:35:26 2007 -0800 [BRIDGE] br_if: Fix oops in port_carrier_check Signed-off-by: Jarek Poplawski Acked-by: Stephen Hemminger Signed-off-by: David S. Miller commit bbf4a6bc8c4d59a0a9033fc2cb96ec03430c96e4 Author: Herbert Xu Date: Tue Feb 13 12:32:58 2007 -0800 [NETFILTER]: Clear GSO bits for TCP reset packet The TCP reset packet is copied from the original. This includes all the GSO bits which do not apply to the new packet. So we should clear those bits. Spotted by Patrick McHardy. Signed-off-by: Herbert Xu Signed-off-by: David S. Miller commit 65610fbab35b0570df4a9d0e77e111f85606b312 Author: Michael Chan Date: Tue Feb 13 12:18:46 2007 -0800 [TG3]: Update copyright, version, and reldate. Update version to 3.73. Signed-off-by: Michael Chan Signed-off-by: David S. Miller commit b0408751128edc126eb37798d51891d8d0a41dc6 Author: Michael Chan Date: Tue Feb 13 12:18:30 2007 -0800 [TG3]: Add some tx timeout debug messages. Print the most useful information during tx timeout to help debug. Signed-off-by: Michael Chan Signed-off-by: David S. Miller commit 569a5df8597deeaa39867be73c7305fd82522f57 Author: Michael Chan Date: Tue Feb 13 12:18:15 2007 -0800 [TG3]: Use constant for PHY register 0x1e. Signed-off-by: Michael Chan Signed-off-by: David S. Miller commit 5129724aa5de3a71fc70e71ca49d542ca1a5aa1e Author: Michael Chan Date: Tue Feb 13 12:17:57 2007 -0800 [TG3]: Power down 5704 serdes transceiver when shutting down. Signed-off-by: Michael Chan Signed-off-by: David S. Miller commit d7b0a8573c9ac8923bf6f205f4ce60dd2ac811d5 Author: Michael Chan Date: Tue Feb 13 12:17:38 2007 -0800 [TG3]: 5906 doesn't need to switch to slower clock. Signed-off-by: Michael Chan Signed-off-by: David S. Miller commit d4011adaf8b5ea555357a40388ee9aa7ed2daf9f Author: Michael Chan Date: Tue Feb 13 12:17:25 2007 -0800 [TG3]: 5722/5756 don't need PHY jitter workaround. Signed-off-by: Michael Chan Signed-off-by: David S. Miller commit 49afdeb65bb917e22cf9116bc31380befe9db890 Author: Michael Chan Date: Tue Feb 13 12:17:03 2007 -0800 [TG3]: Use lower DMA watermark for 5703. Set DMA read watermark to 4 on 5703 in PCIX mode. This is needed to prevent some tx timeouts. Signed-off-by: Michael Chan Signed-off-by: David S. Miller commit 436f137975507b0baab0859a253c3c9332c22f62 Author: Michael Chan Date: Tue Feb 13 12:16:45 2007 -0800 [TG3]: Save MSI state before suspend. This fixes the following problem: http://bugzilla.kernel.org/show_bug.cgi?id=7969 The MSI state needs to be saved during suspend. PCI state saved during tg3_init_one() does not contain valid MSI state because MSI hasn't been enabled. Signed-off-by: Michael Chan Signed-off-by: David S. Miller commit 552ce544edfbe9bce79952a8c0f8d65b7f2d16bb Author: Linus Torvalds Date: Tue Feb 13 12:08:18 2007 -0800 Revert "[PATCH] Fix d_path for lazy unmounts" This reverts commit eb3dfb0cb1f4a44e2d0553f89514ce9f2a9fcaf1. It causes some strange Gnome problem with dbus-daemon getting stuck, so we'll revert it until that problem is understood. Reported by both walt and Greg KH, who both independently git-bisected the problem to this commit. Andreas is looking at it. Reported-by: walt Reported-by: Greg KH Acked-by: Andreas Gruenbacher Signed-off-by: Linus Torvalds commit a20d0ce694e56f94857eacdc8534357d798460fd Author: Timur Tabi Date: Fri Feb 9 10:01:50 2007 -0600 [POWERPC] 83xx: Updated mpc834x_itx_defconfig This patch updates the defconfig for the MPC8349E-mITX. In addition to picking up changes from recent kernels, disables support for e100 (which doesn't ship with the system), turns off input devices, turns on some I2C support, turns off HW monitoring (HW not yet supported), turns off OHCI USB (not used), turns off USB gadget support (HW not yet supported), turns on DOS FS support, and turns off kernel debugging. Signed-off-by: Timur Tabi Signed-off-by: Kumar Gala commit 8c4a013da84e69e4d736363921792e1b37525577 Author: Timur Tabi Date: Fri Feb 9 14:00:36 2007 -0600 [POWERPC] 83xx: Add support for MPC8349E-mITX-GP This patch adds a defconfig and a DTS for the MPC8349E-mITX-GP, a variant of the MPC8349E-mITX. USB is disabled because the only USB port is not setup properly by firmware/kernel Signed-off-by: Timur Tabi Signed-off-by: Kumar Gala commit eb11a720a85833bbd9b92628f196583ee1d50d4e Author: Andy Fleming Date: Fri Feb 9 17:30:09 2007 -0600 [POWERPC] 85xx: Add a defconfig for the 8568 MDS Add defconfig for the MPC8568 MDS reference board Signed-off-by: Andrew Fleming Signed-off-by: Kumar Gala commit c2882bb12cbd8a4170e673e6a33c6be047b75bc1 Author: Andy Fleming Date: Fri Feb 9 17:28:31 2007 -0600 [POWERPC] 85xx: Add support for the 8568 MDS board Add support for the MPC8568 MDS reference board Signed-off-by: Andrew Fleming Signed-off-by: Kumar Gala commit 126b1922367fbe5513daa675a2abd13ed3917f4e Author: Andi Kleen Date: Tue Feb 13 13:26:26 2007 +0100 [PATCH] x86-64: Remove mk_pte_phys() - Convert last user to pfn_pte - Remove mk_pte_phys Suggested by Jan Beulich Signed-off-by: Andi Kleen commit 22c5ace7290b792faf64ffe90cf933950fbf52db Author: Jan Beulich Date: Tue Feb 13 13:26:26 2007 +0100 [PATCH] i386: Fix broken CONFIG_COMPAT_VDSO on i386 After updating several machines to 2.6.20, I can't boot anymore the single one of them that supports the NX bit and is configured as a 32-bit system. My understanding is that the VDSO changes in 2.6.20-rc7 were not fully cooked, in that with that config option enabled VDSO_SYM(x) now equals x, meaning that an address in the fixmap area is now being passed to apps via AT_SYSINFO. However, the page is mapped with PAGE_READONLY rather than PAGE_READONLY_EXEC. I'm not certain whether having app code go through the fixmap area is intended, but in case it is here is the simple patch that makes things work again. Signed-off-by: Jan Beulich Signed-off-by: Andi Kleen commit 98838ec984b78c625bbf9a5daaf001cd216b8f86 Author: Giuliano Procida Date: Tue Feb 13 13:26:26 2007 +0100 [PATCH] i386: fix 32-bit ioctls on x64_32 [MTRR] fix 32-bit ioctls on x64_32 Signed-off-by: Giuliano Procida Signed-off-by: Andi Kleen commit 62cc49396e593dd71c6595302bb10b085aefbfa5 Author: Andi Kleen Date: Tue Feb 13 13:26:26 2007 +0100 [PATCH] x86: Unify pcspeaker platform device code between i386/x86-64 Trivial cleanup. Only change is that it is always compiled in now on x86-64 like on i386. Signed-off-by: Andi Kleen commit 40d22c1b5675e428b3f3f9a945d0bd62e94ca2f1 Author: Rusty Russell Date: Tue Feb 13 13:26:26 2007 +0100 [PATCH] i386: Remove extern declaration from mm/discontig.c, put in header. Extern declarations belong in headers. Times, they are a'changin. Signed-off-by: Rusty Russell Signed-off-by: Andi Kleen =================================================================== commit 2a57ff1a7051f0936b57342a57c25658d7ca3cc6 Author: Rusty Russell Date: Tue Feb 13 13:26:26 2007 +0100 [PATCH] i386: Rename cpu_gdt_descr and remove extern declaration from smpboot.c When I implemented the DECLARE_PER_CPU(var) macros, I was careful that people couldn't use "var" in a non-percpu context, by prepending percpu__. I never considered that this would allow them to overload the same name for a per-cpu and a non-percpu variable. It is only one of many horrors in the i386 boot code, but let's rename the non-perpcu cpu_gdt_descr to early_gdt_descr (not boot_gdt_descr, that's something else...) Signed-off-by: Rusty Russell Signed-off-by: Andi Kleen =================================================================== commit 105fddb862d3da2f414329ff7719794fb2bd706b Author: Rusty Russell Date: Tue Feb 13 13:26:26 2007 +0100 [PATCH] i386: Move mce_disabled to asm/mce.h Allows external actors to disable mce. Signed-off-by: Rusty Russell Signed-off-by: Andi Kleen =================================================================== commit 992af68147299bb635be97f789e4f66ba7add477 Author: Rusty Russell Date: Tue Feb 13 13:26:26 2007 +0100 [PATCH] i386: paravirt unhandled fallthrough The current code simply calls "start_kernel" directly if we're under a hypervisor and no paravirt_ops backend wants us, because paravirt.c registers that as a backend. This was always a vain hope; start_kernel won't get far without setup. It's also impossible for paravirt_ops backends which don't sit in the arch/i386/kernel directory: they can't link before paravirt.o anyway. Keep it simple: if we pass all the registered paravirt probes, BUG(). Signed-off-by: Rusty Russell Signed-off-by: Andi Kleen commit 9af3cf054615862c86efcf55a37bb40f0d96e406 Author: Ralf Baechle Date: Tue Feb 13 13:26:26 2007 +0100 [PATCH] x86_64: Wire up compat epoll_pwait > Which remembers me that I think that MIPS is using the non-compat version > of sys_epoll_pwait for compat syscalls. But maybe MIPS doesn't need a compat > syscall for some reason. Dunno. Which reminds me that x86_64 i386 compat doesn't wire up sys_epoll_pwait ;-) Signed-off-by: Ralf Baechle Signed-off-by: Andi Kleen commit 9fbbd4dd17d0712054368e5e939e28b2456bfe1b Author: Andi Kleen Date: Tue Feb 13 13:26:26 2007 +0100 [PATCH] x86: Don't require the vDSO for handling a.out signals and in other strange binfmts. vDSO is not necessarily mapped there. Signed-off-by: Andi Kleen commit 120fad72401ebec2a126c16cc48f56c28f3eefe2 Author: Alan Date: Tue Feb 13 13:26:26 2007 +0100 [PATCH] i386: Fix Cyrix MediaGX detection The old Cyrix 5520 CPU detection code relied upon the PCI layer setup being done earlier than the CPU setup, which is no longer true. Fortunately we know that if the processor is a MediaGX we can do type 1 pci config accesses to check the companion chip. We thus do those directly and from this find the 5520 and implement the workarounds for the timer problem Original report from takada@mbf.nifty.com, I sent a proposed patch which Takara then corrected, tested and sent back to the list on 10th January. Submitting for merging as it seems to have been missed AK: Changed to use pci-direct.h and fix warning for !CONFIG_PCI (later AK: originally from akpm) Signed-off-by: Alan Cox Signed-off-by: Andi Kleen Cc: Andi Kleen Cc: Cc: Jordan Crouse Signed-off-by: Andrew Morton commit 7de6d3618b09c39fdaa6125e23fcf465a65bc266 Author: Andi Kleen Date: Tue Feb 13 13:26:25 2007 +0100 [PATCH] i386: Fix warning in cpu initialization Fix bogus warning linux/arch/i386/kernel/cpu/transmeta.c:12: warning: ‘cpu_freq’ may be used uninitialized in this function Signed-off-by: Andi Kleen commit 2ba1ff2b796746722fc4fe8bdcd1f30a834e3d0a Author: Andi Kleen Date: Tue Feb 13 13:26:25 2007 +0100 [PATCH] i386: Fix warning in microcode.c Fix bogus gcc warning linux/arch/i386/kernel/microcode.c:387: warning: ‘new_mc’ may be used uninitialized in this function Signed-off-by: Andi Kleen commit 0a4599c894d880763eec6cb93f6c246dac6c3269 Author: Andi Kleen Date: Tue Feb 13 13:26:25 2007 +0100 [PATCH] x86: Enable NMI watchdog for AMD Family 0x10 CPUs For i386/x86-64. Straight forward -- just reuse the Family 0xf code. Signed-off-by: Andi Kleen commit f790cd30d002949a12623b2a8cec4d4e5a8887ef Author: Andi Kleen Date: Tue Feb 13 13:26:25 2007 +0100 [PATCH] x86: Add new CPUID bits for AMD Family 10 CPUs in /proc/cpuinfo Just various new acronyms. The new popcnt bit is in the middle of Intel space. This looks a little weird, but I've been assured it's ok. Also I fixed RDTSCP for i386 which was at the wrong place. For i386 and x86-64. Signed-off-by: Andi Kleen commit 1a1eecd1c272f704f135a7d8060ec3da1c201b4c Author: Andi Kleen Date: Tue Feb 13 13:26:25 2007 +0100 [PATCH] i386: Remove fastcall in paravirt.[ch] Not needed because fastcall is always default now Signed-off-by: Andi Kleen commit 9f6026b8c308365d955faaf31dd0f457266d11f8 Author: Andi Kleen Date: Tue Feb 13 13:26:25 2007 +0100 [PATCH] x86-64: Fix wrong gcc check in bitops.h gcc 5.0 will likely not have the constraint problem Signed-off-by: Andi Kleen commit 2fb12a9bca5ad9aa6dcd2c639b4a7656a8843ef8 Author: Eric W. Biederman Date: Tue Feb 13 13:26:25 2007 +0100 [PATCH] x86-64: survive having no irq mapping for a vector Occasionally the kernel has bugs that result in no irq being found for a given cpu vector. If we acknowledge the irq the system has a good chance of continuing even though we dropped an irq message. If we continue to simply print a message and not acknowledge the irq the system is likely to become non-responsive shortly there after. AK: Fixed compilation for UP kernels Signed-off-by: Eric W. Biederman Signed-off-by: Andi Kleen Cc: "Luigi Genoni" Cc: Andi Kleen Signed-off-by: Andrew Morton commit bcde1ebb81c51ebdfa02887703e4d21c1bbc2431 Author: TAKADA Yoshihito Date: Tue Feb 13 13:26:25 2007 +0100 [PATCH] i386: geode configuration fixes Original code doesn't write back to CCR4 register. This patch reflects a value of a register. Cc: Jordan Crouse Acked-by: Alan Cox Cc: Andi Kleen Signed-off-by: Andrew Morton Signed-off-by: Andi Kleen commit 86c418374223be3f328b5522545196db02c8ceda Author: Chuck Ebbert Date: Tue Feb 13 13:26:25 2007 +0100 [PATCH] i386: add option to show more code in oops reports Sometimes developers need to see more object code in an oops report, e.g. when kernel may be corrupted at runtime. Add the "code_bytes" option for this. Signed-off-by: Chuck Ebbert Signed-off-by: Andi Kleen Cc: Andi Kleen Signed-off-by: Andrew Morton commit 8469adde5932f2879688fd5f183a6e9dadbf7b9f Author: Evgeniy Polyakov Date: Tue Feb 13 13:26:25 2007 +0100 [PATCH] x86-64: Minor patch for compilation warning in x86_64 signal code If DEBUG_SIG is enbaled in source code, ia32_signal.c compiles with warning due to wrong format string. Attached patch fixes that. It is quite minor update, since by default DEBUG_SIG is not enabled and can not be turned on without code modification. Signed-off-by: Evgeniy Polyakov Signed-off-by: Andi Kleen Cc: Andi Kleen Signed-off-by: Andrew Morton commit 3e94fb8f54c5305ed472e0867cd67d53e05bfb64 Author: Roland Dreier Date: Tue Feb 13 13:26:25 2007 +0100 [PATCH] x86-64: avoid warning message livelock I've seen my box paralyzed by an endless spew of rtc: lost some interrupts at 1024Hz. messages on the serial console. What seems to be happening is that something real causes an interrupt to be lost and triggers the message. But then printing the message to the serial console (from the hpet interrupt handler) takes more than 1/1024th of a second, and then some more interrupts are lost, so the message triggers again.... Fix this by adding a printk_ratelimit() before printing the warning. Signed-off-by: Roland Dreier Signed-off-by: Andrew Morton Signed-off-by: Andi Kleen commit ee4eff6ff6cbfc8ce38131058a18802bf6206879 Author: Benjamin Romer Date: Tue Feb 13 13:26:25 2007 +0100 [PATCH] x86-64: update IO-APIC dest field to 8-bit for xAPIC On the Unisys ES7000/ONE system, we encountered a problem where performing a kexec reboot or dump on any cell other than cell 0 causes the system timer to stop working, resulting in a hang during timer calibration in the new kernel. We traced the problem to one line of code in disable_IO_APIC(), which needs to restore the timer's IO-APIC configuration before rebooting. The code is currently using the 4-bit physical destination field, rather than using the 8-bit logical destination field, and it cuts off the upper 4 bits of the timer's APIC ID. If we change this to use the logical destination field, the timer works and we can kexec on the upper cells. This was tested on two different cells (0 and 2) in an ES7000/ONE system. For reference, the relevant Intel xAPIC spec is kept at ftp://download.intel.com/design/chipsets/e8501/datashts/30962001.pdf, specifically on page 334. Signed-off-by: Benjamin M Romer Signed-off-by: Andi Kleen Cc: Andi Kleen Cc: "Eric W. Biederman" Cc: Vivek Goyal Signed-off-by: Andrew Morton commit a4af60aa64c828b7c047e7a67b2f896d4bfbd700 Author: Robert P. J. Day Date: Tue Feb 13 13:26:25 2007 +0100 [PATCH] i386: Remove unused kernel config option X86_XADD Remove the unused kernel config option X86_XADD, which is unused in any source or header file. Signed-off-by: Robert P. J. Day Signed-off-by: Andi Kleen Cc: Andi Kleen Signed-off-by: Andrew Morton commit f0a5a58aa812b31fd9f197c4ba48245942364eae Author: Bob Picco Date: Tue Feb 13 13:26:25 2007 +0100 [PATCH] x86-64: clean up sparsemem memory_present call Eliminate arch specific memory_present call x86_64 NUMA by utilizing sparse_memory_present_with_active_regions. Acked-by: Mel Gorman Signed-off-by: Bob Picco Signed-off-by: Andi Kleen Cc: Andi Kleen Signed-off-by: Andrew Morton commit 47a55cd795656d11bb18a7885583361f02a6baa8 Author: Jan Beulich Date: Tue Feb 13 13:26:24 2007 +0100 [PATCH] i386: entry.S END/ENDPROC annotations Annotate i386/kernel/entry.S with END/ENDPROC to assist disassemblers and other analysis tools. Signed-off-by: Jan Beulich Signed-off-by: Andi Kleen Cc: Andi Kleen Signed-off-by: Andrew Morton commit 2632f01a66d75f4ad59653a7efa506c6ea6845d0 Author: takada Date: Tue Feb 13 13:26:24 2007 +0100 [PATCH] i386: support Classic MediaGXm I hope to support "classic" MediaGXm in kernel. The DIR1 register of MediaGXm( or Geode) shows the following values for identify CPU. For example, My MediaGXm shows 0x42. We can read National Semiconductor's datasheet without any NDAs. http://www.national.com/pf/GX/GXLV.html from datasheets: DIR1 0x30 - 0x33 GXm rev. 1.0 - 2.3 0x34 - 0x4f GXm rev. 2.4 - 3.x 0x5x GXm rev. 5.0 - 5.4 0x6x GXLV 0x7x (unknow) 0x8x Gx1 In nsc driver of X, accept 0x30 through 0x82. What will 0x7x mean? Cc: Jordan Crouse Cc: Andi Kleen Cc: Alan Cox Signed-off-by: Andrew Morton Signed-off-by: Andi Kleen commit 3101673b659b916c965271c7f7c9b99cb353c01c Author: Randy Dunlap Date: Tue Feb 13 13:26:24 2007 +0100 [PATCH] i386: avoid gcc extension setcc() in math-emu is written as a gcc extension statement expression macro that returns a value. However, it's not used that way and it's not needed like that, so just make it a inline function so that we don't use an extension when it's not needed. Signed-off-by: Randy Dunlap Signed-off-by: Andi Kleen Cc: Andi Kleen Cc: Christoph Hellwig Cc: Segher Boessenkool Signed-off-by: Andrew Morton commit 30b82ea08c3365a6fc916250ff2ad634717fc81b Author: H. Peter Anvin Date: Tue Feb 13 13:26:24 2007 +0100 [PATCH] i386: All Transmeta CPUs have constant TSCs All Transmeta CPUs ever produced have constant-rate TSCs. Signed-off-by: H. Peter Anvin Signed-off-by: Andi Kleen Cc: Andi Kleen Signed-off-by: Andrew Morton commit 5d0e600d903caa09e790824cc5812f0d97113b23 Author: Ingo Molnar Date: Tue Feb 13 13:26:24 2007 +0100 [PATCH] x86: fix laptop bootup hang in init_acpi() During kernel bootup, a new T60 laptop (CoreDuo, 32-bit) hangs about 10%-20% of the time in acpi_init(): Calling initcall 0xc055ce1a: topology_init+0x0/0x2f() Calling initcall 0xc055d75e: mtrr_init_finialize+0x0/0x2c() Calling initcall 0xc05664f3: param_sysfs_init+0x0/0x175() Calling initcall 0xc014cb65: pm_sysrq_init+0x0/0x17() Calling initcall 0xc0569f99: init_bio+0x0/0xf4() Calling initcall 0xc056b865: genhd_device_init+0x0/0x50() Calling initcall 0xc056c4bd: fbmem_init+0x0/0x87() Calling initcall 0xc056dd74: acpi_init+0x0/0x1ee() It's a hard hang that not even an NMI could punch through! Frustratingly, adding printks or function tracing to the ACPI code made the hangs go away ... After some time an additional detail emerged: disabling the NMI watchdog made these occasional hangs go away. So i spent the better part of today trying to debug this and trying out various theories when i finally found the likely reason for the hang: if acpi_ns_initialize_devices() executes an _INI AML method and an NMI happens to hit that AML execution in the wrong moment, the machine would hang. (my theory is that this must be some sort of chipset setup method doing stores to chipset mmio registers?) Unfortunately given the characteristics of the hang it was sheer impossible to figure out which of the numerous AML methods is impacted by this problem. As a workaround i wrote an interface to disable chipset-based NMIs while executing _INI sections - and indeed this fixed the hang. I did a boot-loop of 100 separate reboots and none hung - while without the patch it would hang every 5-10 attempts. Out of caution i did not touch the nmi_watchdog=2 case (it's not related to the chipset anyway and didnt hang). I implemented this for both x86_64 and i686, tested the i686 laptop both with nmi_watchdog=1 [which triggered the hangs] and nmi_watchdog=2, and tested an Athlon64 box with the 64-bit kernel as well. Everything builds and works with the patch applied. Signed-off-by: Ingo Molnar Signed-off-by: Andi Kleen Cc: Andi Kleen Cc: Len Brown Signed-off-by: Andrew Morton commit 310adfdd9153f6ae818981a38a48dd2330990d8d Author: Muli Ben-Yehuda Date: Tue Feb 13 13:26:24 2007 +0100 [PATCH] x86-64: robustify bad_dma_address handling - set bad_dma_address explicitly to 0x0 - reserve 32 pages from bad_dma_address and up - WARN_ON() a driver feeding us bad_dma_address Thanks to Leo Duran for the suggestion. Signed-off-by: Muli Ben-Yehuda Signed-off-by: Andi Kleen Cc: Leo Duran Cc: Job Mason commit 2fa8a050a0026eadbb39a2f281011991e00fe29a Author: Jeff Garzik Date: Tue Feb 13 13:26:24 2007 +0100 [PATCH] x86-64: define dma noncoherent API functions x86-64 is missing these: Signed-off-by: Jeff Garzik Signed-off-by: Andi Kleen commit fc986db4fc1e773e240a19bc8b407ead88982cea Author: Andi Kleen Date: Tue Feb 13 13:26:24 2007 +0100 [PATCH] x86-64: Don't reserve ROMs We trust the e820 table, so explicitely reserving ROMs shouldn't be needed. Signed-off-by: Andi Kleen commit 00edefae050c2c2d1e26fa9984f8f529fbc45989 Author: Andi Kleen Date: Tue Feb 13 13:26:24 2007 +0100 [PATCH] x86-64: Fix off by one error in IOMMU boundary checking Should be harmless because there is normally no memory there, but technically it was incorrect. Pointed out by Leo Duran Signed-off-by: Andi Kleen commit ffb6017563aa15f9a8cff9a30b861d42c2695894 Author: Zachary Amsden Date: Tue Feb 13 13:26:24 2007 +0100 [PATCH] x86-64: x86_64 - Fix FS/GS registers for VT execution Initialize FS and GS to __KERNEL_DS as well. The actual value of them is not important, but it is important to reload them in protected mode. At this time, they still retain the real mode values from initial boot. VT disallows execution of code under such conditions, which means hardware virtualization can not be used to boot the kernel on Intel platforms, making the boot time painfully slow. This requires moving the GS load before the load of GS_BASE, so just move all the segments loads there to keep them together in the code. Signed-off-by: Zachary Amsden Signed-off-by: Andi Kleen commit 9a11ff68273f440b1d33fcc4d550ffc881e6a0b4 Author: Andi Kleen Date: Tue Feb 13 13:26:24 2007 +0100 [PATCH] x86-64: Unexport __supported_pte_mask The symbol is needed to manipulate page tables, and modules shouldn't do that. Leftover from 2.4, but no in tree module should need it now. Signed-off-by: Andi Kleen commit f49481bc50fce428521497977861b8115666dbe7 Author: Andi Kleen Date: Tue Feb 13 13:26:24 2007 +0100 [PATCH] x86-64: Check return value of putreg in PTRACE_SETREGS This means if an illegal value is set for the segment registers there ptrace will error out now with an errno instead of silently ignoring it. Signed-off-by: Andi Kleen commit 2f7a2a79c3ebb44f8b1b7d9b4fd3a650eb69e544 Author: Jack Steiner Date: Tue Feb 13 13:26:24 2007 +0100 [PATCH] x86-64: - Ignore long SMI interrupts in clock calibration code - update 1 Add failsafe mechanism to HPET/TSC clock calibration. Signed-off-by: Jack Steiner Updated to include failsafe mechanism & additional community feedback. Patch built on latest 2.6.20-rc4-mm1 tree. Signed-off-by: Andi Kleen commit 6c5806cae50717f31878d0da29109b10610ab862 Author: Andreas Herrmann Date: Tue Feb 13 13:26:23 2007 +0100 [PATCH] i386: fix size_or_mask and size_and_mask mtrr: fix size_or_mask and size_and_mask This fixes two bugs in /proc/mtrr interface: o If physical address size crosses the 44 bit boundary size_or_mask is evaluated wrong. o size_and_mask limits width of physical base address for an MTRR to be less than 44 bits. TBD: later patch had one more change, but I think that was bogus. TBD: need to double check Signed-off-by: Andreas Herrmann Signed-off-by: Andi Kleen commit 016d6f35803667ffbe3e7bba8b58a6b611fac998 Author: Alexey Dobriyan Date: Tue Feb 13 13:26:23 2007 +0100 [PATCH] i386: Convert /proc/apm to seqfile Byte-to-byte identical /proc/apm here. Signed-off-by: Alexey Dobriyan Signed-off-by: Andi Kleen commit b0957f1a3a7687bfaf5b0bfe402b50985ea2f06b Author: Josef 'Jeff' Sipek Date: Tue Feb 13 13:26:23 2007 +0100 [PATCH] x86-64: Fix preprocessor condition Old code was legal standard C, but apparently not sparse-C. Signed-off-by: Josef 'Jeff' Sipek Signed-off-by: Andi Kleen commit ad4e680fb2220518de5118a8e734240d4c374fe2 Author: Alexey Dobriyan Date: Tue Feb 13 13:26:23 2007 +0100 [PATCH] i386: use smp_call_function_single() It will execure cpuid only on the cpu we need. Signed-off-by: Alexey Dobriyan Signed-off-by: Andi Kleen commit d958f143329e685d114725b64fe6bef22994c74c Author: Alexey Dobriyan Date: Tue Feb 13 13:26:23 2007 +0100 [PATCH] i386: use smp_call_function_single() It will execute rdmsr and wrmsr only on the cpu we need. Signed-off-by: Alexey Dobriyan Signed-off-by: Andi Kleen commit edf8dd36b53fdd558bc9a8ac5be793d27e110f90 Author: Nicolas Kaiser Date: Tue Feb 13 13:26:23 2007 +0100 [PATCH] x86-64: Kconfig typos Some typos in Kconfig. Signed-off-by: Nicolas Kaiser Signed-off-by: Andi Kleen commit 8c40ad02e5b026902b8ce134f895b3b09803db39 Author: Andi Kleen Date: Tue Feb 13 13:26:23 2007 +0100 [PATCH] i386: Small cleanup to TLB flush code - Remove outdated comment - Use cpu_relax() in a busy loop Signed-off-by: Andi Kleen commit 930f8b8bcde30b501fdf00fb7624aefb9bf35f47 Author: Jan Beulich Date: Tue Feb 13 13:26:23 2007 +0100 [PATCH] x86-64: remove get_pmd() Function is dead. Signed-off-by: Jan Beulich Signed-off-by: Andi Kleen commit a98f0dd34d94ea0b5f3816196bea5dba467827bb Author: Andi Kleen Date: Tue Feb 13 13:26:23 2007 +0100 [PATCH] x86-64: Allow to run a program when a machine check event is detected When a machine check event is detected (including a AMD RevF threshold overflow event) allow to run a "trigger" program. This allows user space to react to such events sooner. The trigger is configured using a new trigger entry in the machinecheck sysfs interface. It is currently shared between all CPUs. I also fixed the AMD threshold handler to run the machine check polling code immediately to actually log any events that might have caused the threshold interrupt. Also added some documentation for the mce sysfs interface. Signed-off-by: Andi Kleen commit 24ce0e96f2dea558762c994d054ea2f3c01fa95a Author: Jan Beulich Date: Tue Feb 13 13:26:23 2007 +0100 [PATCH] x86-64: Tighten mce_amd driver MSR reads while debugging an unrelated problem in Xen, I noticed odd reads from non-existent MSRs. Having now found time to look why these happen, I came up with below patch, which - prevents accessing MCi_MISCj with j > 0 when the block pointer in MCi_MISC0 is zero - accesses only contiguous MCi_MISCj until a non-implemented one is found - doesn't touch unimplemented blocks in mce_threshold_interrupt at all - gives names to two bits previously derived from MASK_VALID_HI (it took me some time to understand the code without this) The first three items, besides being apparently closer to the spec, should namely help cutting down on the time mce_threshold_interrupt() takes. Signed-off-by: Andi Kleen commit 9b355897562fe2291248a7aec8e479c2c98cf117 Author: Jan Beulich Date: Tue Feb 13 13:26:23 2007 +0100 [PATCH] x86: simplify notify_page_fault() Remove all parameters from this function that aren't really variable. Signed-off-by: Jan Beulich Signed-off-by: Andi Kleen commit 6a051565739f9d334ad5c15f691a9699a905897d Author: Randy Dunlap Date: Tue Feb 13 13:26:23 2007 +0100 [PATCH] x86-64: list x86_64 quilt tree List x86_64 quilt tree in MAINTAINERS. Signed-off-by: Randy Dunlap Signed-off-by: Andi Kleen commit 57d307720c9a60038f134b0567ca302b88313a0a Author: Randy Dunlap Date: Tue Feb 13 13:26:23 2007 +0100 [PATCH] x86-64: cleanup Doc/x86_64/ files Fix typos. Lots of whitespace changes for readability and consistency. Signed-off-by: Randy Dunlap Signed-off-by: Andi Kleen commit 44264261d8fb87849118e41b2735bd95db28126f Author: Venkatesh Pallipadi Date: Tue Feb 13 13:26:23 2007 +0100 [PATCH] i386: Handle 32 bit PerfMon Counter writes cleanly in oprofile Handle these 32 bit perfmon counter MSR writes cleanly in oprofile. Signed-off-by: Venkatesh Pallipadi Signed-off-by: Andi Kleen commit 90ce4bc4542c10b63dc6482ac920ff1226a6e5ff Author: Venkatesh Pallipadi Date: Tue Feb 13 13:26:22 2007 +0100 [PATCH] i386: Handle 32 bit PerfMon Counter writes cleanly in i386 nmi_watchdog Change i386 nmi handler to handle 32 bit perfmon counter MSR writes cleanly. Signed-off-by: Venkatesh Pallipadi Signed-off-by: Andi Kleen commit 1676193937a538fdb92a2916a86a705093cfd613 Author: Venkatesh Pallipadi Date: Tue Feb 13 13:26:22 2007 +0100 [PATCH] x86-64: Handle 32 bit PerfMon Counter writes cleanly in x86_64 nmi_watchdog P6 CPUs and Core/Core 2 CPUs which has 'architectural perf mon' feature, only supports write of low 32 bits in Performance Monitoring Counters. Bits 32..39 are sign extended based on bit 31 and bits 40..63 are reserved and should be zero. This patch: Change x86_64 nmi handler to handle this case cleanly. Signed-off-by: Venkatesh Pallipadi Signed-off-by: Andi Kleen commit 4c3cbf75b262433afc90b5c35510d1e5744d3b94 Author: Glauber de Oliveira Costa Date: Tue Feb 13 13:26:22 2007 +0100 [PATCH] x86-64: Use constant instead of raw number in x86_64 ioperm.c This is a tiny cleanup to increase readability Signed-off-by: Glauber de Oliveira Costa Signed-off-by: Andi Kleen Cc: Andi Kleen Signed-off-by: Andrew Morton commit c49c5330c9592f29a69bb2ea8f6e7fd5d9c151e8 Author: Glauber de Oliveira Costa Date: Tue Feb 13 13:26:22 2007 +0100 [PATCH] x86-64: Remove fastcall references in x86_64 code Unlike x86, x86_64 already passes arguments in registers. The use of regparm attribute makes no difference in produced code, and the use of fastcall just bloats the code. Signed-off-by: Glauber de Oliveira Costa Signed-off-by: Andi Kleen Cc: Andi Kleen Signed-off-by: Andrew Morton commit 53fee04f318222a3179ca5933d8bda82c1eef17a Author: Rohit Seth Date: Tue Feb 13 13:26:22 2007 +0100 [PATCH] x86-64: Fix fake numa for x86_64 machines with big IO hole This patch resolves the issue of running with numa=fake=X on kernel command line on x86_64 machines that have big IO hole. While calculating the size of each node now we look at the total hole size in that range. Previously there were nodes that only had IO holes in them causing kernel boot problems. We now use the NODE_MIN_SIZE (64MB) as the minimum size of memory that any node must have. We reduce the number of allocated nodes if the number of nodes specified on kernel command line results in any node getting memory smaller than NODE_MIN_SIZE. This change allows the extra memory to be incremented in NODE_MIN_SIZE granule and uniformly distribute among as many nodes (called big nodes) as possible. [akpm@osdl.org: build fix] Signed-off-by: David Rientjes Signed-off-by: Paul Menage Signed-off-by: Rohit Seth Signed-off-by: Andi Kleen Cc: Andi Kleen Signed-off-by: Andrew Morton commit 3b3d5e1db66cd66148b2cebd2c38aff2a8df03d6 Author: Rene Herman Date: Tue Feb 13 13:26:22 2007 +0100 [PATCH] i386: romsignature/checksum cleanup Use adding __init to romsignature() (it's only called from probe_roms() which is itself __init) as an excuse to submit a pedantic cleanup. Signed-off-by: Rene Herman Signed-off-by: Andi Kleen Cc: Andi Kleen Signed-off-by: Andrew Morton commit f9690982b8c2f9a2c65acdc113e758ec356676a3 Author: Ingo Molnar Date: Tue Feb 13 13:26:22 2007 +0100 [PATCH] i386: improve sched_clock() on i686 Clean up sched_clock() on i686: it will use the TSC if available and falls back to jiffies only if the user asked for it to be disabled via notsc or the CPU calibration code didnt figure out the right cpu_khz. This generally makes the scheduler timestamps more finegrained, on all hardware. (the current scheduler is pretty resistant against asynchronous sched_clock() values on different CPUs, it will allow at most up to a jiffy of jitter.) Also simplify sched_clock()'s check for TSC availability: propagate the desire and ability to use the TSC into the tsc_disable flag, previously this flag only indicated whether the notsc option was passed. This makes the rare low-res sched_clock() codepath a single branch off a read-mostly flag. Signed-off-by: Ingo Molnar Signed-off-by: Andrew Morton Signed-off-by: Andi Kleen commit 2ff2d3d74705d34ab71b21f54634fcf50d57bdd5 Author: Stephane Eranian Date: Tue Feb 13 13:26:22 2007 +0100 [PATCH] i386: add idle notifier Add a notifier mechanism to the low level idle loop. You can register a callback function which gets invoked on entry and exit from the low level idle loop. The low level idle loop is defined as the polling loop, low-power call, or the mwait instruction. Interrupts processed by the idle thread are not considered part of the low level loop. The notifier can be used to measure precisely how much is spent in useless execution (or low power mode). The perfmon subsystem uses it to turn on/off monitoring. Signed-off-by: stephane eranian Signed-off-by: Andrew Morton Signed-off-by: Andi Kleen commit 86a978837ca739842317c4cf433de36aeb85ea3b Author: Adrian Bunk Date: Tue Feb 13 13:26:22 2007 +0100 [PATCH] i386: arch/i386/kernel/cpu/mcheck/mce.c should #include Every file should include the headers containing the prototypes for it's global functions. Signed-off-by: Adrian Bunk Signed-off-by: Andrew Morton Signed-off-by: Andi Kleen commit ee5bfa642a0d4b0f6ec6200bf96e5e647f93fcdb Author: Vivek Goyal Date: Tue Feb 13 13:26:22 2007 +0100 [PATCH] generic: Break init() in two parts to avoid MODPOST warnings o init() is a non __init function in .text section but it calls many functions which are in .init.text section. Hence MODPOST generates lots of cross reference warnings on i386 if compiled with CONFIG_RELOCATABLE=y WARNING: vmlinux - Section mismatch: reference to .init.text:smp_prepare_cpus from .text between 'init' (at offset 0xc0101049) and 'rest_init' WARNING: vmlinux - Section mismatch: reference to .init.text:migration_init from .text between 'init' (at offset 0xc010104e) and 'rest_init' WARNING: vmlinux - Section mismatch: reference to .init.text:spawn_ksoftirqd from .text between 'init' (at offset 0xc0101053) and 'rest_init' o This patch breaks down init() in two parts. One part which can go in .init.text section and can be freed and other part which has to be non __init(init_post()). Now init() calls init_post() and init_post() does not call any functions present in .init sections. Hence getting rid of warnings. Signed-off-by: Vivek Goyal Signed-off-by: Andrew Morton Signed-off-by: Andi Kleen commit f8657e1b55901e6c227094258d1fa3642fa242bd Author: Vivek Goyal Date: Tue Feb 13 13:26:22 2007 +0100 [PATCH] i386: move startup_32() in text.head section o Entry startup_32 was in .text section but it was accessing some init data too and it prompts MODPOST to generate compilation warnings. WARNING: vmlinux - Section mismatch: reference to .init.data:boot_params from .text between '_text' (at offset 0xc0100029) and 'startup_32_smp' WARNING: vmlinux - Section mismatch: reference to .init.data:boot_params from .text between '_text' (at offset 0xc0100037) and 'startup_32_smp' WARNING: vmlinux - Section mismatch: reference to .init.data:init_pg_tables_end from .text between '_text' (at offset 0xc0100099) and 'startup_32_smp' o Can't move startup_32 to .init.text as this entry point has to be at the start of bzImage. Hence moved startup_32 to a new section .text.head and instructed MODPOST to not to generate warnings if init data is being accessed from .text.head section. This code has been audited. o SMP boot up code (startup_32_smp) can go into .init.text if CPU hotplug is not supported. Otherwise it generates more warnings WARNING: vmlinux - Section mismatch: reference to .init.data:new_cpu_data from .text between 'checkCPUtype' (at offset 0xc0100126) and 'is486' WARNING: vmlinux - Section mismatch: reference to .init.data:new_cpu_data from .text between 'checkCPUtype' (at offset 0xc0100130) and 'is486' Signed-off-by: Vivek Goyal Signed-off-by: Andrew Morton Signed-off-by: Andi Kleen commit 7c0b49f9d1d59b3638c884b346a92dcb4ea1560a Author: Zachary Amsden Date: Tue Feb 13 13:26:22 2007 +0100 [PATCH] i386: Paravirt debug defaults off Deliberate register clobber around performance critical inline code is great for testing, bad to leave on by default. Many people ship with DEBUG_KERNEL turned on, so stop making DEBUG_PARAVIRT default on. Signed-off-by: Zachary Amsden Signed-off-by: Andi Kleen commit 90736e20e3805dd1ffff60e4750495944956cd44 Author: Zachary Amsden Date: Tue Feb 13 13:26:21 2007 +0100 [PATCH] i386: Vmi timer race Because timer code moves around, and we might eventually move our init to a late_time_init hook, save and restore IRQs around this code because it is definitely not interrupt safe. Signed-off-by: Zachary Amsden Signed-off-by: Andi Kleen commit ac3b6faff961dd52fde71fb199ec3cf68ba35052 Author: Zachary Amsden Date: Tue Feb 13 13:26:21 2007 +0100 [PATCH] i386: Kprobe rpl fix Kprobes bugfix for paravirt compatibility - RPL on the CS when inserting BPs must match running kernel. Signed-off-by: Zachary Amsden Signed-off-by: Andi Kleen CC: Eric Biederman commit 7b3552024380f306a6c50d5105d18d9d4258fa4e Author: Zachary Amsden Date: Tue Feb 13 13:26:21 2007 +0100 [PATCH] i386: Profile pc badness Profile_pc was broken when using paravirtualization because the assumption the kernel was running at CPL 0 was violated, causing bad logic to read a random value off the stack. The only way to be in kernel lock functions is to be in kernel code, so validate that assumption explicitly by checking the CS value. We don't want to be fooled by BIOS / APM segments and try to read those stacks, so only match KERNEL_CS. I moved some stuff in segment.h to make it prettier. Signed-off-by: Zachary Amsden Signed-off-by: Andi Kleen commit bbab4f3bb7f528d2b8ccb5de9ae5f6ff3fb29684 Author: Zachary Amsden Date: Tue Feb 13 13:26:21 2007 +0100 [PATCH] i386: vMI timer patches VMI timer code. It works by taking over the local APIC clock when APIC is configured, which requires a couple hooks into the APIC code. The backend timer code could be commonized into the timer infrastructure, but there are some pieces missing (stolen time, in particular), and the exact semantics of when to do accounting for NO_IDLE need to be shared between different hypervisors as well. So for now, VMI timer is a separate module. [Adrian Bunk: cleanups] Subject: VMI timer patches Signed-off-by: Zachary Amsden Signed-off-by: Andi Kleen Cc: Andi Kleen Cc: Jeremy Fitzhardinge Cc: Rusty Russell Cc: Chris Wright Signed-off-by: Andrew Morton commit 7ce0bcfd1667736f1293cff845139bbee53186de Author: Zachary Amsden Date: Tue Feb 13 13:26:21 2007 +0100 [PATCH] i386: vMI backend for paravirt-ops Fairly straightforward implementation of VMI backend for paravirt-ops. [Adrian Bunk: some cleanups] Signed-off-by: Zachary Amsden Signed-off-by: Andi Kleen Cc: Andi Kleen Cc: Jeremy Fitzhardinge Cc: Rusty Russell Cc: Chris Wright Signed-off-by: Andrew Morton commit ae5da273fe3352febd38658d8d34484cbcfb3423 Author: Zachary Amsden Date: Tue Feb 13 13:26:21 2007 +0100 [PATCH] i386: SMP boot hook for paravirt Add VMI SMP boot hook. We emulate a regular boot sequence and use the same APIC IPI initiation, we just poke magic values to load into the CPU state when the startup IPI is received, rather than having to jump through a real mode trampoline. This is all that was needed to get SMP to work. Signed-off-by: Zachary Amsden Signed-off-by: Andi Kleen Cc: Andi Kleen Cc: Jeremy Fitzhardinge Cc: Rusty Russell Cc: Chris Wright Signed-off-by: Andrew Morton commit 8b15114434998a78aa50f8559d69c7a400cff267 Author: Zachary Amsden Date: Tue Feb 13 13:26:21 2007 +0100 [PATCH] i386: iOPL handling for paravirt guests I found a clever way to make the extra IOPL switching invisible to non-paravirt compiles - since kernel_rpl is statically defined to be zero there, and only non-zero rpl kernel have a problem restoring IOPL, as popf does not restore IOPL flags unless run at CPL-0. Signed-off-by: Zachary Amsden Signed-off-by: Andi Kleen Cc: Andi Kleen Cc: Jeremy Fitzhardinge Cc: Rusty Russell Cc: Chris Wright Signed-off-by: Andrew Morton commit 9226d125d94c7e4964dd41cc5e9ca2ff84091d01 Author: Zachary Amsden Date: Tue Feb 13 13:26:21 2007 +0100 [PATCH] i386: paravirt CPU hypercall batching mode The VMI ROM has a mode where hypercalls can be queued and batched. This turns out to be a significant win during context switch, but must be done at a specific point before side effects to CPU state are visible to subsequent instructions. This is similar to the MMU batching hooks already provided. The same hooks could be used by the Xen backend to implement a context switch multicall. To explain a bit more about lazy modes in the paravirt patches, basically, the idea is that only one of lazy CPU or MMU mode can be active at any given time. Lazy MMU mode is similar to this lazy CPU mode, and allows for batching of multiple PTE updates (say, inside a remap loop), but to avoid keeping some kind of state machine about when to flush cpu or mmu updates, we just allow one or the other to be active. Although there is no real reason a more comprehensive scheme could not be implemented, there is also no demonstrated need for this extra complexity. Signed-off-by: Zachary Amsden Signed-off-by: Andi Kleen Cc: Andi Kleen Cc: Jeremy Fitzhardinge Cc: Rusty Russell Cc: Chris Wright Signed-off-by: Andrew Morton commit c119ecce894120790903ef535dac3e105f3d6cde Author: Zachary Amsden Date: Tue Feb 13 13:26:21 2007 +0100 [PATCH] MM: page allocation hooks for VMI backend The VMI backend uses explicit page type notification to track shadow page tables. The allocation of page table roots is especially tricky. We need to clone the root for non-PAE mode while it is protected under the pgd lock to correctly copy the shadow. We don't need to allocate pgds in PAE mode, (PDPs in Intel terminology) as they only have 4 entries, and are cached entirely by the processor, which makes shadowing them rather simple. For base page table level allocation, pmd_populate provides the exact hook point we need. Also, we need to allocate pages when splitting a large page, and we must release pages before returning the page to any free pool. Despite being required with these slightly odd semantics for VMI, Xen also uses these hooks to determine the exact moment when page tables are created or released. AK: All nops for other architectures Signed-off-by: Zachary Amsden Signed-off-by: Andi Kleen Cc: Andi Kleen Cc: Jeremy Fitzhardinge Cc: Rusty Russell Cc: Chris Wright Signed-off-by: Andrew Morton commit 90611fe923aa3ac7ffb9e5df45c83860b0f00227 Author: Adrian Bunk Date: Tue Feb 13 13:26:21 2007 +0100 [PATCH] i386: arch/i386/kernel/e820.c should #include Signed-off-by: Andrew Morton Signed-off-by: Andi Kleen commit 006e84ee3a54e393ec6bef2a9bc891dc5bde2843 Author: Catalin Marinas Date: Tue Feb 13 13:26:21 2007 +0100 [PATCH] x86-64: do not always end the stack trace with ULONG_MAX It makes more sense to end the stack trace with ULONG_MAX only if nr_entries < max_entries. Otherwise, we lose one entry in the long stack traces and cannot know whether the trace was complete or not. Signed-off-by: Catalin Marinas Signed-off-by: Andi Kleen Cc: Andi Kleen Cc: Jan Beulich Signed-off-by: Andrew Morton commit 5558870bfbcca10cfc7b13ab866687012ea3c9af Author: Karsten Weiss Date: Tue Feb 13 13:26:21 2007 +0100 [PATCH] x86-64: improved iommu documentation - add SWIOTLB config help text - mention Documentation/x86_64/boot-options.txt in Documentation/kernel-parameters.txt - remove the duplication of the iommu kernel parameter documentation. - Better explanation of some of the iommu kernel parameter options. - "32MB< Signed-off-by: Andi Kleen Acked-by: Muli Ben-Yehuda Cc: Andi Kleen Signed-off-by: Andrew Morton commit 5809f9d442e9dbb23859e2c37d8c47043f6b5cc9 Author: Eric Dumazet Date: Tue Feb 13 13:26:21 2007 +0100 [PATCH] x86-64: get rid of ARCH_HAVE_XTIME_LOCK ARCH_HAVE_XTIME_LOCK is used by x86_64 arch . This arch needs to place a read only copy of xtime_lock into vsyscall page. This read only copy is named __xtime_lock, and xtime_lock is defined in arch/x86_64/kernel/vmlinux.lds.S as an alias. So the declaration of xtime_lock in kernel/timer.c was guarded by ARCH_HAVE_XTIME_LOCK define, defined to true on x86_64. We can get same result with _attribute__((weak)) in the declaration. linker should do the job. Signed-off-by: Eric Dumazet Signed-off-by: Andi Kleen Cc: Andi Kleen Signed-off-by: Andrew Morton commit 26054ed02bb20f5b2e02d92cb6f0be0e2b0196d5 Author: OGAWA Hirofumi Date: Tue Feb 13 13:26:20 2007 +0100 [PATCH] mmconfig: Move e820 check into pci_mmcfg_reject_broken() This is just cleanup. It moves to e820 check into pci_mmcfg_reject_broken(). Signed-off-by: OGAWA Hirofumi Signed-off-by: Andi Kleen commit 56829d1982b6f1150553c049d372728b9eda5aec Author: OGAWA Hirofumi Date: Tue Feb 13 13:26:20 2007 +0100 [PATCH] mmconfig: fix unreachable_devices() Currently, unreachable_devices() compares value of mmconfig and value of conf1. But it doesn't check the device is reachable or not. Signed-off-by: OGAWA Hirofumi Signed-off-by: Andi Kleen commit 429d512e532ec9c969aa6f66ddbc542f3a5fe4da Author: OGAWA Hirofumi Date: Tue Feb 13 13:26:20 2007 +0100 [PATCH] mmconfig: minor cleanup in mmconfig code This just cleans up. Signed-off-by: OGAWA Hirofumi Signed-off-by: Andi Kleen commit a4ec1b2c9fe9492c9ab30261b411d836527fe0b6 Author: OGAWA Hirofumi Date: Tue Feb 13 13:26:20 2007 +0100 [PATCH] mmconfig: remove #define MMCONFIG_APER_XXX MMCONFIG_APER_XXX is unneeded in arch/x86_64/pci/mmconfig.c. Signed-off-by: OGAWA Hirofumi Signed-off-by: Andi Kleen commit 44de0203fab205417b24322272c53ee0883c36e7 Author: OGAWA Hirofumi Date: Tue Feb 13 13:26:20 2007 +0100 [PATCH] mmconfig: Reject a broken MCFG tables on Asus etc This rejects broken MCFG tables on Asus. When the table looks bogus just disable mmconfig Arjan and Andi suggested this. Signed-off-by: OGAWA Hirofumi Signed-off-by: Andi Kleen commit faed197b7b44a6c4e6b81dd2db649fd452b0a7ef Author: OGAWA Hirofumi Date: Tue Feb 13 13:26:20 2007 +0100 [PATCH] mmconfig: Fix x86_64 ioremap base_address Current mmconfig has some problems of remapped range. a) In the case of broken MCFG tables on Asus etc., we need to remap 256M range, but currently only remap 1M. b) The base address always corresponds to bus number 0, but currently we are assuming it corresponds to start bus number. This patch fixes the above problems. (akpm: Arjan suggests that if the MCFG table is broken we just shouldn't use it, rather than try to work around things). Signed-off-by: OGAWA Hirofumi Signed-off-by: Andi Kleen Cc: Arjan van de Ven Cc: Andi Kleen Signed-off-by: Andrew Morton commit 6a0668fc41fa479df617151c2d4e297299a4ffe2 Author: Olivier Galibert Date: Tue Feb 13 13:26:20 2007 +0100 [PATCH] mmconfig: Reserve resources but only when we're sure about them. Put back the resource reservation as per 4c6e052adfe285ede5884e4e8c4d33af33932c13 but use it *only* when the range(s) come from a chipset probe instead of the bios. Signed-off-by: Olivier Galibert Signed-off-by: Andi Kleen Cc: Andi Kleen Signed-off-by: Andrew Morton commit 9358c693c5ac1afde28f24ac651f7903d32a850c Author: Olivier Galibert Date: Tue Feb 13 13:26:20 2007 +0100 [PATCH] mmconfig: Detect and support the E7520 and the 945G/GZ/P/PL It seems that the only way to reliably support mmconfig in the presence of funky biosen is to detect the hostbridge and read where the window is mapped from its registers. Do that for the E7520 and the 945G/GZ/P/PL for a start. Signed-off-by: Olivier Galibert Signed-off-by: Andi Kleen Cc: Andi Kleen Signed-off-by: Andrew Morton commit 5f027387bbdb5a4a4c1babd557fd976cd09d7495 Author: Olivier Galibert Date: Tue Feb 13 13:26:20 2007 +0100 [PATCH] i386: Only call unreachable_devices() when type 1 is available. unreachable_devices compares between the results of pci configuration accesses through type1 and mmconfig, so it should be called only if type1 actually works in the first place. Signed-off-by: Olivier Galibert Signed-off-by: Andi Kleen Cc: Andi Kleen Signed-off-by: Andrew Morton commit b78673944b22b662b270c8bba5c198f19e4ee4e1 Author: Olivier Galibert Date: Tue Feb 13 13:26:20 2007 +0100 [PATCH] mmconfig: Share parts of mmconfig code between i386 and x86-64 i386 and x86-64 pci mmconfig code have a lot in common. So share what's shareable between the two. Signed-off-by: Olivier Galibert Signed-off-by: Andi Kleen Cc: Andi Kleen Signed-off-by: Andrew Morton commit 2e188938ab2358034801938c2329b016ca135823 Author: Maciej W. Rozycki Date: Tue Feb 13 13:26:20 2007 +0100 [PATCH] i386: Fix a typo in an IRQ handler name The "fasteoi" IRQ handler is named "fasteio" incorrectly. This is a fix. Signed-off-by: Maciej W. Rozycki Signed-off-by: Andi Kleen Cc: Andi Kleen Signed-off-by: Andrew Morton commit 464d1a78fbf8cf6c7fd970e7b3e2db50a320ce28 Author: Jeremy Fitzhardinge Date: Tue Feb 13 13:26:20 2007 +0100 [PATCH] i386: Convert i386 PDA code to use %fs Convert the PDA code to use %fs rather than %gs as the segment for per-processor data. This is because some processors show a small but measurable performance gain for reloading a NULL segment selector (as %fs generally is in user-space) versus a non-NULL one (as %gs generally is). On modern processors the difference is very small, perhaps undetectable. Some old AMD "K6 3D+" processors are noticably slower when %fs is used rather than %gs; I have no idea why this might be, but I think they're sufficiently rare that it doesn't matter much. This patch also fixes the math emulator, which had not been adjusted to match the changed struct pt_regs. [frederik.deweerdt@gmail.com: fixit with gdb] [mingo@elte.hu: Fix KVM too] Signed-off-by: Jeremy Fitzhardinge Signed-off-by: Andi Kleen Cc: Ian Campbell Acked-by: Ingo Molnar Acked-by: Zachary Amsden Cc: Eric Dumazet Signed-off-by: Frederik Deweerdt Signed-off-by: Andrew Morton commit 54413927f022292aeccadd268fbf1c0b42129945 Author: Amul Shah Date: Tue Feb 13 13:26:20 2007 +0100 [PATCH] x86-64: x86_64-make-the-numa-hash-function-nodemap-allocation fix fix - Removed an extraneous debug message from allocate_cachealigned_map - Changed extract_lsb_from_nodes to return 63 for the case where there was only one memory node. The prevents the creation of the dynamic hashmap. - Changed extract_lsb_from_nodes to use only the starting memory address of a node. On an ES7000, our nodes overlap the starting and ending address, meaning, that we see nodes like 00000 - 10000 10000 - 20000 But other systems have nodes whose start and end addresses do not overlap. For example: 00000 - 0FFFF 10000 - 1FFFF In this case, using the ending address will result in an LSB much lower than what is possible. In this case an LSB of 1 when in reality it should be 16. Cc: Andi Kleen Cc: Rohit Seth Signed-off-by: Andrew Morton Signed-off-by: Andi Kleen commit 076422d2af7e3d8e72c6e70843f6ea377714b082 Author: Amul Shah Date: Tue Feb 13 13:26:19 2007 +0100 [PATCH] x86-64: Allocate the NUMA hash function nodemap dynamically Remove the statically allocated memory to NUMA node hash map in favor of a dynamically allocated memory to node hash map (it is cache aligned). This patch has the nice side effect in that it allows the hash map to grow for systems with large amounts of memory (256GB - 1TB), but suffer from having small PCI space tacked onto the boot node (which is somewhere between 192MB to 512MB on the ES7000). Signed-off-by: Amul Shah Signed-off-by: Andi Kleen Cc: Andi Kleen Cc: Rohit Seth Signed-off-by: Andrew Morton commit 0812a579c92fefa57506821fa08e90f47cb6dbdd Author: Andi Kleen Date: Tue Feb 13 13:26:19 2007 +0100 [PATCH] x86-64: Add __copy_from_user_nocache This does user copies in fs write() into the page cache with write combining. This pushes the destination out of the CPU's cache, but allows higher bandwidth in some case. The theory is that the page cache data is usually not touched by the CPU again and it's better to not pollute the cache with it. Also it is a little faster. Signed-off-by: Andi Kleen commit ee55c0be30429d7c3e61fa26c7f7e323c80e14f0 Author: Andi Kleen Date: Tue Feb 13 13:26:19 2007 +0100 [PATCH] i386: Update defconfig Signed-off-by: Andi Kleen commit 287eeb5e02bfd9ddcb881f47400510b5cda686d1 Author: Andi Kleen Date: Tue Feb 13 13:26:19 2007 +0100 [PATCH] x86-64: Update defconfig Signed-off-by: Andi Kleen commit 401e9093a326725780aed270a6eb53e7ddab14ff Author: Paul Mundt Date: Tue Feb 13 15:46:39 2007 +0900 sh: Compile fix for heartbeat consolidation. Signed-off-by: Paul Mundt commit 3b4d9539628502768fe7f8fd4b48f2fbf2426255 Author: Paul Mundt Date: Tue Feb 13 15:42:28 2007 +0900 sh: heartbeat consolidation for banked LEDs. This consolidates the various board heartbeat LED implementations, used for strobing the load average across a LED bank. Those boards not implementing a full bank can hook in via the LED class. We leave the compat hook in the machvec for now until those non-banked boards are able to migrate to the drivers/leds. Signed-off-by: Paul Mundt commit 43d78ef2ba5bec26d0315859e8324bfc0be23766 Author: Chuck Lever Date: Tue Feb 6 18:26:11 2007 -0500 NFS: disconnect before retrying NFSv4 requests over TCP RFC3530 section 3.1.1 states an NFSv4 client MUST NOT send a request twice on the same connection unless it is the NULL procedure. Section 3.1.1 suggests that the client should disconnect and reconnect if it wants to retry a request. Implement this by adding an rpc_clnt flag that an ULP can use to specify that the underlying transport should be disconnected on a major timeout. The NFSv4 client asserts this new flag, and requests no retries after a minor retransmit timeout. Note that disconnecting on a retransmit is in general not safe to do if the RPC client does not reuse the TCP port number when reconnecting. See http://bugzilla.linux-nfs.org/show_bug.cgi?id=6 Signed-off-by: Chuck Lever Signed-off-by: Trond Myklebust commit a301b777714087ea1d63dbec0173a13d416cd7a9 Author: Trond Myklebust Date: Tue Feb 6 11:07:15 2007 -0800 NFS: Don't use ClearPageUptodate() when writeback fails ClearPageUptodate() will just cause races here. What we really want to do is to invalidate the page cache. Signed-off-by: Trond Myklebust commit b0c4fddca2bc3967381b728732a8850de35e1b20 Author: Trond Myklebust Date: Mon Feb 5 14:44:22 2007 -0800 NFS: Cleanup - avoid rereading 'jiffies' more than once in the same routine Micro-optimisations for nfs_fhget() and nfs_wcc_update_inode(). Signed-off-by: Trond Myklebust commit 3e7d950a528454ad749a264feef3c8bad3faa108 Author: Trond Myklebust Date: Mon Feb 5 14:26:28 2007 -0800 NFS: Fix a wraparound issue with nfsi->cache_change_attribute Fix wraparound issue with nfsi->cache_change_attribute. If it is found to lie in the future, then update it to lie in the past. Patch based on a suggestion by Neil Brown. ..and minor micro-optimisation: avoid reading 'jiffies' more than once in nfs_update_inode(). Signed-off-by: Trond Myklebust commit 17e0e27020d028a790d97699aff85a43af5be472 Author: Benjamin Herrenschmidt Date: Tue Feb 13 11:46:08 2007 +1100 [POWERPC] spufs: Fix bitrot of the SPU mmap facility It looks like we've had some serious bitrot there mostly due to tracking of address_space's of mmap'ed files getting out of sync with the actual mmap code. The mfc, mss and psmap were not tracked properly and thus not invalidated on context switches (oops !) I also removed the various file->f_mapping = inode->i_mapping; assignments that were done in the other open() routines since that is already done for us by __dentry_open. One improvement we might want to do later is to assign the various ctx-> fields at mmap time instead of file open/close time so that we don't call unmap_mapping_range() on thing that have not been mmap'ed Finally, I added some smp_wmb's after assigning the ctx-> fields to make sure they are visible to other CPUs. I don't think this is really necessary as I suspect locking in the fs layer will make that happen anyway but better safe than sorry. Signed-off-by: Benjamin Herrenschmidt Signed-off-by: Paul Mackerras commit 44430e0d3916ab6aaf0451fdb811f4f1803b741e Author: Benjamin Herrenschmidt Date: Tue Feb 13 11:46:07 2007 +1100 [POWERPC] powerpc: Remove SPU struct pages for PS3 Struct page are no longer needed for SPUs, so let's not create them on PS3 anymore. Signed-off-by: Benjamin Herrenschmidt Signed-off-by: Paul Mackerras commit 78bde53e351bc89cff85d1c2c7e6d7c2ffdf120d Author: Benjamin Herrenschmidt Date: Tue Feb 13 11:46:06 2007 +1100 [POWERPC] spufs: remove need for struct page for SPEs This patch removes the need for struct page for SPE local store and registers from spufs. It also makes the locking much more obvious and no longer relying on the truncate logic black magic for protecting against races between unmap_mapping_range() and new pages faulted in. It does so by switching to a nopfn() handler and using the new vm_insert_pfn() to setup the PTEs itself while holding a lock on the SPE. The nice thing is that this patch actually removes a lot more code than it adds :-) Signed-off-by: Benjamin Herrenschmidt Signed-off-by: Paul Mackerras commit 9724b86f0706ca9b552d82e013cb0c208b4f5529 Author: Sylvain Munaut Date: Mon Feb 12 23:13:24 2007 +0100 [POWERPC] Small cleanup of EFIKA platform The efika platform used three files efika-pci.c efika-setup.c and a 2 line efika.h to link the two. The total of code in those is really not much and therefore, I think they're better merged in a single file. There is absolutely _no_code_change_ at all, just merged the files. Signed-off-by: Sylvain Munaut Acked-by: Grant Likely Signed-off-by: Paul Mackerras commit 46e4cf6c14e0a5b8916a1236a7079ccad3f4352a Author: Sylvain Munaut Date: Mon Feb 12 23:13:23 2007 +0100 [POWERPC] Fix unbalanced of_node_{get,put} in efika-setup.c Signed-off-by: Sylvain Munaut Acked-by: Grant Likely Signed-off-by: Paul Mackerras commit 82a03b92279f2ea80e11dc2c419fdaa3800401a2 Author: Sylvain Munaut Date: Mon Feb 12 23:13:22 2007 +0100 [POWERPC] Use common 52xx of_platform probe code for EFIKA Now that the device tree has the good properties, we can remove all the efika_init code by a single call to common code. While we're modifying that file, a few whitespaces/alignement/typo fixes are made (nothing significant). Signed-off-by: Sylvain Munaut Acked-by: Grant Likely Signed-off-by: Paul Mackerras commit b6a591b2c59935eef5dd31790323ca6014e28f01 Author: Sylvain Munaut Date: Mon Feb 12 23:13:21 2007 +0100 [POWERPC] Restore 'proper' link order in platform The 52xx was put before CHRP to allow EFIKA to be recognized properly. Now the efika tree is fixed up in prom_init so no need for this ugly hack. So we restore the 'normal' order. Signed-off-by: Sylvain Munaut Acked-by: Grant Likely Signed-off-by: Paul Mackerras commit 88fd2a9d681f261ebd55a6843a03ea2a1bb9eb39 Author: Sylvain Munaut Date: Mon Feb 12 23:13:20 2007 +0100 [POWERPC] Add device tree fixups for the EFIKA We make the efika device tree compliant with the defined bindings (at least compliant enough). This is mostly done by mangling the device_type and compatible properties, but also adding some missing bits. Signed-off-by: Sylvain Munaut Acked-by: Grant Likely Signed-off-by: Paul Mackerras commit 05cbbc692f513c0e62372abeab01b04b07096582 Author: Grant Likely Date: Mon Feb 12 13:36:54 2007 -0700 [POWERPC] mpc5200 device tree bindings refinement Much needed refinement of mpc5200 device tree binding specifications. Short list: - drop mpc52xx designator; only two supported chips exist, 5200 and 5200b. It's premature to refer to them as '52xx'. - Specify optional 'model' and 'revision' properties in the soc5200 node - Specify reqiured 'cell-index' property to identify between multiple SOC devices of the same type. (Useful for arbitrating shared register access) - Specify optional 'port-number' property for adjusting the logical serial port assignments. - Specify optional 'has-wdt' property for gpt0 node. - Add system-frequency property to soc5200 node Signed-off-by: Grant Likely Signed-off-by: Paul Mackerras commit e3aba81d154c53a82e2a7e0ff5e7f1162a53cf27 Author: Grant Likely Date: Mon Feb 12 13:36:55 2007 -0700 [POWERPC] Fixup mp5200 drivers to match device tree changes Signed-off-by: Grant Likely Signed-off-by: Paul Mackerras commit 40d244d69a3871dd05a5fdae29f36823a6ee3e33 Author: Stephen Rothwell Date: Mon Feb 12 22:10:48 2007 +1100 [POWERPC] correct a prototype This rids us of a warning. Signed-off-by: Stephen Rothwell Signed-off-by: Paul Mackerras commit 9b96ea662b404b9ed882c78cb844510d804a83e6 Author: Stephen Rothwell Date: Mon Feb 12 22:09:18 2007 +1100 [POWERPC] Wire up sys_getcpu Signed-off-by: Stephen Rothwell Signed-off-by: Paul Mackerras commit ab9367e38fa97c2ed7f72fd5fa29d0d70d58df89 Author: Stefan Roese Date: Mon Feb 12 11:29:04 2007 +0100 [POWERPC] ppc: Add support for AMCC Taishan 440GX eval board This patch adds support for the AMCC Taishan PPC440GX evaluation board. This is still an arch/ppc port. I'm aware that the move of 4xx to arch/powerpc is making good progress right now. So this patch is mainly intended to make the Taishan support available for the community right now. Signed-off-by: Stefan Roese Signed-off-by: Paul Mackerras commit 7ac9a13717c10c5ee074a6b23096c8d277fa5712 Author: Benjamin Herrenschmidt Date: Mon Feb 12 13:31:08 2007 +1100 [POWERPC] Fix vDSO page count calculation The recent vDSO consolidation patches broke powerpc due to a mistake in the definition of MAXPAGES constants. This fixes it by moving to a dynamically allocated array of pages instead as I don't like much hard coded size limits. Also move the vdso initialisation to an initcall since it doesn't really need to be done -that- early. Applogies for not catching the breakage earlier, Roland _did_ CC me on his patches a while ago, I got busy with other things and forgot to test them. Signed-off-by: Benjamin Herrenschmidt Signed-off-by: Paul Mackerras commit a334bdbdda9659b8f50a8620a11249fde62ccfde Author: Olaf Hering Date: Sat Feb 10 21:40:00 2007 +0100 [POWERPC] Correct AC Power: in /proc/pmu/info on ibook1 /proc/pmu/info contains AC Power: 0 when booting without battery. Force AC Power, it will be updated whenever the battery state changes. Signed-off-by: Olaf Hering Signed-off-by: Paul Mackerras commit 2d99c41f05fc2a26737aacf943db03ca89841199 Author: Olaf Hering Date: Sat Feb 10 21:38:37 2007 +0100 [POWERPC] Mark winbond IDE PCI resources with start 0 as unassigned libata calls pci_request_regions to claim PCI BAR 0 - 5 pci_request_regions fails if one of the regions cant be claimed. bar 5 has start == 0, __request_resource will fail. Tested on a p630 in SMP mode with pata_sl82c105 00:03.1 IDE interface: Symphony Labs SL82c105 (rev 05) (prog-if 8f [Master SecP SecO PriP PriO]) Control: I/O+ Mem- BusMaster- SpecCycle- MemWINV- VGASnoop- ParErr+ Stepping- SERR+ FastB2B- Status: Cap- 66MHz- UDF- FastB2B+ ParErr- DEVSEL=medium >TAbort- SERR- Signed-off-by: Paul Mackerras commit 872758563d7f132d25fc06857bd19df06c5c70c7 Author: Olaf Hering Date: Sat Feb 10 21:35:12 2007 +0100 [POWERPC] move variables in drivers/macintosh to bss Move all the initialized variables to bss. Mark a version string as const. Signed-off-by: Olaf Hering Signed-off-by: Paul Mackerras commit 9ea8b7c96f64f68548976ba65062cee2f2b7d831 Author: Pavel Fedin Date: Mon Jan 29 15:13:03 2007 +0300 [POWERPC] Virtual DMA support for floppy driver for new powerpc architecture During ppc64+ppc merge virtual DMA code for floppy driver was not ported. This patch restores virtual DMA support for floppy in new powerpc target. It is necessary at least on Pegasos and AmigaOne machines for the floppy drive to function. ISA DMA controller works incorrectly there due to its addressing limitations. Virtual DMA mode is activated by floppy=nodma option passed to the kernel (or module). There's no automatic switch like on i386. Signed-off-by: Pavel Fedin Signed-off-by: Paul Mackerras commit cbca567ea5b337eaa2685606cbb9183e79b8f97f Author: Akira Iguchi Date: Fri Feb 9 16:53:59 2007 +0900 [POWERPC] Celleb: improve MMU hashtable locking Disabling IRQ is required only in invalidation. This changes "spin_lock_irqsave" to "spin_lock" in other ops. Signed-off-by: Kou Ishizaki Signed-off-by: Akira Iguchi Acked-by: Arnd Bergmann Signed-off-by: Paul Mackerras commit e2e01bfef8399c8f39c9fdf4a5576039069e760c Author: Patrick McHardy Date: Mon Feb 12 20:27:10 2007 -0800 [XFRM]: Fix IPv4 tunnel mode decapsulation with IPV6=n Add missing break when CONFIG_IPV6=n. Signed-off-by: Patrick McHardy Signed-off-by: David S. Miller commit 6e1d9d04c4004361fb327abcbde74a20e8dca2ff Author: YOSHIFUJI Hideaki Date: Mon Feb 12 20:26:39 2007 -0800 [IPV6] HASHTABLES: Use appropriate seed for caluculating ehash index. Tetsuo Handa told me that connect(2) with TCPv6 socket almost always took a few minutes to return when we did not have any ports available in the range of net.ipv4.ip_local_port_range. The reason was that we used incorrect seed for calculating index of hash when we check established sockets in __inet6_check_established(). Signed-off-by: YOSHIFUJI Hideaki Signed-off-by: David S. Miller commit 1f1fec94589ed0b14c749eb9494bb690dbdf8d5a Author: David Gibson Date: Tue Feb 6 12:48:31 2007 +1100 [POWERPC] Remove ibm4{xx,4x}.h from arch/powerpc ARCH=powerpc should not use the ghastly un-multiplatformable tangle of includes that starts with asm-ppc/ibm4xx.h. This patch removes a compile-breaking include of it from head_44x.S. Signed-off-by: David Gibson Signed-off-by: Paul Mackerras commit 8ce0a7df6e6117d8814e976d4b7ce6a6b2c9cf93 Author: Becky Bruce Date: Mon Feb 12 17:43:46 2007 -0600 [POWERPC] 85xx: Don't write reserved values to MAS1[TSIZE] Some of the current tlbwe instructions early on in head_fsl_booke.S take advantage of unarchitected behavior that allows the writing of reserved values to the TSIZE field. This patch corrects that, as well as an error where an uninitialized (by linux) value was written into a MAS register and used for a tlbwe. Correct this for both arch/ppc and arch/powerpc. Signed-off-by: Becky Bruce Signed-off-by: Kumar Gala commit c7666e72cff1a2793055486340ac5f5137494c08 Author: Paul Mundt Date: Tue Feb 13 11:11:22 2007 +0900 sh: define dma noncoherent API functions. sh was missing these, too. Signed-off-by: Paul Mundt commit fe8289175059a807094ba962828318910ea08a37 Author: Paul Mundt Date: Tue Feb 13 11:09:15 2007 +0900 sh: Missing flush_dcache_all() proto in cacheflush.h. Some boards need this, so provide a definition. Signed-off-by: Paul Mundt commit ca43ecbf6e5c7216152e5a388f2ecdd87e07a293 Author: Paul Mundt Date: Wed Feb 7 21:27:50 2007 +0900 sh: Kill dead/unused ISA code from __ioremap(). Signed-off-by: Paul Mundt commit f5df54dc2e1dce80eb7fb45f3f6d5ce096d911f3 Author: Paul Mundt Date: Wed Feb 7 20:00:01 2007 +0900 sh: Add cpu-features header to asm/Kbuild. This is used by the libc for parsing CPU capability flags passed via the ELF auxvt, needed for run-time selection of atomic opcodes amongst other things. Signed-off-by: Paul Mundt commit a5ba7d545364b85c3a97f65d328be55ca933a9c7 Author: Paul Mundt Date: Wed Feb 7 19:58:07 2007 +0900 sh: Move __KERNEL__ up in asm/page.h. This was breaking the uClibc build, which triggered the bogus page size error. Signed-off-by: Paul Mundt commit b37814352d2c4b83e0636e57f997c3a79d33be05 Author: Paul Mundt Date: Wed Feb 7 19:11:35 2007 +0900 sh: Fix syscall numbering breakage. We accidentally broke the inotify syscalls, fix those up again. Signed-off-by: Paul Mundt commit 5904539b7f21ae97f16278ea4bfb81fd19749e1a Author: Paul Mundt Date: Wed Feb 7 18:35:39 2007 +0900 sh: dcache write-back for R7780RP PIO. Signed-off-by: Paul Mundt commit 0072032d7babc4347556c1863919f3c532d9cf5b Author: Paul Mundt Date: Mon Dec 25 19:37:56 2006 +0900 sh: Switch to local TLB flush variants in additional callsites. Convert some of the global flush users over to using the local variants that don't need to use the global routines. Signed-off-by: Paul Mundt commit ea9af69481730e3d712104dfd549ba6c8ddd29f1 Author: Paul Mundt Date: Mon Dec 25 19:28:54 2006 +0900 sh: Local TLB flushing variants for SMP prep. Rename the existing flush routines to local_ variants for use by the IPI-backed global flush routines on SMP. Signed-off-by: Paul Mundt commit 11c1965687b0a472add948d4240dfe65a2fcb298 Author: Paul Mundt Date: Mon Dec 25 10:19:56 2006 +0900 sh: Fixup cpu_data references for the non-boot CPUs. There are a lot of bogus cpu_data-> references that only end up working for the boot CPU, convert these to current_cpu_data to fixup SMP. Signed-off-by: Paul Mundt commit aec5e0e1c179fac4bbca4007a3f0d3107275a73c Author: Paul Mundt Date: Mon Dec 25 09:51:47 2006 +0900 sh: Use a per-cpu ASID cache. Previously this was implemented using a global cache, cache this per-CPU instead and bump up the number of context IDs to match NR_CPUS. Signed-off-by: Paul Mundt commit 506b85f4114b912d2e91fab8da9849289e43857f Author: Andrew Morton Date: Wed Feb 7 13:56:44 2007 +0900 sh: add SH_CLK_MD Kconfig default. This option needs a default - otherwise `make allmodconfig' gets stuck in an infinite loop. Signed-off-by: Andrew Morton Signed-off-by: Paul Mundt commit dbbfa2da27fbf353caa8934768afbbf8d5e73d9b Author: Nobuhiro Iwamatsu Date: Wed Feb 7 13:54:39 2007 +0900 sh: Fixup SHMIN INTC register definitions. Signed-off-by: Nobuhiro Iwamatsu Signed-off-by: Paul Mundt commit 9f8a5e3a44d81bbf19fddeb74645dec6b0e23b23 Author: Manuel Lauss Date: Thu Jan 25 15:22:11 2007 +0900 sh: SH-DMAC compile fixes This patch does the following: - remove the make_ipr_irq stuff from dma-sh.c and replace it with a simple channel<->irq mapping table. - add DMTEx_IRQ constants for sh4 cpus - fix sh7751 DMAE irq number The SH7780 uses the same IRQs for DMA as other SH4 types, so I put the constants on top of the dma.h file. Other CPU types need to #define their own DMTEx_IRQ contants in their appropriate header. Signed-off-by: Manuel Lauss Signed-off-by: Paul Mundt commit 6dcda6f1ecef86209ac161631837bc57172ba049 Author: Manuel Lauss Date: Thu Jan 25 15:21:03 2007 +0900 sh: add SH7760 IPR IRQ data Add SH7760 IPR IRQ data; makes 2.6.20-rc bootable again. Signed-off-by: Manuel Lauss Signed-off-by: Paul Mundt commit 86b67ef7518d1fcd4489dc464d4c33a274a1c635 Author: Nobuhiro Iwamatsu Date: Mon Jan 1 09:21:43 2007 +0900 sh: Fix handle_BUG() compile error. handle_BUG() uses TRAPA_BUG_OPCODE which is only defined for CONFIG_BUG, make sure it's not built when CONFIG_BUG=n. Signed-off-by: Nobuhiro Iwamatsu Signed-off-by: Paul Mundt commit adac9570966eb2eb137209e552b258d4d1d4825b Author: Paul Mundt Date: Thu Dec 28 10:54:01 2006 +0900 sh: Don't set reserved _PAGE_WT bit on SH-3. Only SH-4 needs to set _PAGE_WT when using write-through caching, don't attempt to set it on SH-3 where it ends up being a reserved bit. Signed-off-by: Paul Mundt commit 26b7a78c55fbc0e23a7dc19e89fd50f200efc002 Author: Paul Mundt Date: Thu Dec 28 10:31:48 2006 +0900 sh: Lazy dcache writeback optimizations. This converts the lazy dcache handling to the model described in Documentation/cachetlb.txt and drops the ptep_get_and_clear() hacks used for the aliasing dcaches on SH-4 and SH7705 in 32kB mode. As a bonus, this slightly cuts down on the cache flushing frequency. With that and the PTEA handling out of the way, the update_mmu_cache() implementations can be consolidated, and we no longer have to worry about which configuration the cache is in for the SH7705 case. And finally, explicitly disable the lazy writeback on SMP (SH-4A). Signed-off-by: Paul Mundt commit 7a847f819063b80cc5b38d39e8aad4d60f6ca2fd Author: Paul Mundt Date: Tue Dec 26 15:29:19 2006 +0900 sh: More tidying for large base pages. There were a few more things that needed fixing up, namely THREAD_SIZE and the TLB miss handler where certain PTRS_PER_PGD == PTRS_PER_PTE assumptions were being made. Signed-off-by: Paul Mundt commit aa4a5db52a440d32eab134bfb79d2c9af71eedb4 Author: Nobuhiro Iwamatsu Date: Fri Dec 29 01:50:35 2006 +0900 sh: Solution Engine 770x IPR irq setup. Fixups for external IPR IRQs for the SE770x FPGA. Signed-off-by: Nobuhiro Iwamatsu Signed-off-by: Paul Mundt commit 08d2e099fb19ec2edef548a2988c824c8ec0b071 Author: Nobuhiro Iwamatsu Date: Fri Dec 29 01:44:32 2006 +0900 sh: Solution Engine 7750's defconfig update. Update se7750_defconfig. Signed-off-by: Nobuhiro Iwamatsu Signed-off-by: Paul Mundt commit f725b5ee1e392ab1299c9317236cf736af1183ab Author: Takashi YOSHII Date: Mon Dec 25 18:35:24 2006 +0900 sh: shmin updates. This fixes up shmin (and SH7706/SH7708) IPR support for some of the recent API changes. Signed-off-by: Takashi YOSHII Signed-off-by: Paul Mundt commit 2c081e71baadccb4543815ef42c5290ac2961546 Author: Paul Mundt Date: Mon Dec 25 18:28:33 2006 +0900 sh: Fixup R7780RP iVDR clock enable. The iVDR clock enable bit happens to actually reside in a rather different place than what is documented, so fix it up accordingly. This fixes up SATA boot for some of the R7780RP boards that didn't default-enable the clock in the loader. Signed-off-by: Paul Mundt commit 703404ea441fc198d03ca3e9edbac6e09b5415f4 Author: Jamie Lenehan Date: Tue Dec 19 12:16:06 2006 +0900 sh: allow earlyprintk baud rate to be set via command line This allows the baud rate for earlyprintk for sh4 without the standard BIOS to be set via the command line. This uses the same format as i386 and x86_64, which is: earlyprintk=serial,ttySC1,38400 The second parameter (ttySC1 above) is usually the console device name or the io address of the serial port. I allow that to be specified but ignore it in order to keep the format the same as i386/x86_64. Signed-off-by: Jamie Lenehan Signed-off-by: Paul Mundt commit 106dac130d6fb6670a0bbfa8c714054990b41b03 Author: SUGIOKA Toshinobu Date: Tue Dec 19 12:13:55 2006 +0900 sh: syscall 300 should be __NR_fstatat64. syscall number 300 fails while testing with latest LTP (ltp-full-20061121.tgz) on sh. sys_fstatat64 is called on syscall 300 (see arch/sh/kernel/syscalls.S), and __ARCH_WANT_STAT64 is defined in include/asm-sh/unistd.h, so following patch seems correct. Signed-off-by: SUGIOKA Toshinobu Signed-off-by: Paul Mundt commit 5c67cd05e3e9b6f08c3472dd66f0d8d03e1ee870 Author: Yoshinori Sato Date: Tue Dec 19 12:12:01 2006 +0900 sh: sh7619 / sh7206 IPR initialize update IPR initialize proceduere update. Signed-off-by: Yoshinori Sato Signed-off-by: Paul Mundt commit 4aa362bbdd801dd971acbe3db479fe871f2fed0b Author: Yoshinori Sato Date: Tue Dec 19 12:10:48 2006 +0900 sh: Update SH-2 to use the debug trap jump table. Signed-off-by: Yoshinori Sato Signed-off-by: Paul Mundt commit 702dd80375046d36f892a0f86c83f8549c623b35 Author: Paul Mundt Date: Tue Dec 19 12:05:17 2006 +0900 sh: Use proper SH-2A CFLAGS on newer compilers. -m2 doesn't end up working particularly well when we've got a constrained toolchain target. Switch to the same semantics used by SH-4A to attempt to get it right. Spotted by Alex Song . Signed-off-by: Paul Mundt commit f413d0d9fa7abcecc40e115cf4aead372d164a75 Author: Paul Mundt Date: Wed Dec 13 17:40:05 2006 +0900 sh: Use a jump call table for debug trap handlers. This rips out most of the needlessly complicated sh_bios and kgdb trap handling, and forces it all through a common fast dispatch path. As more debug traps are inserted, it's important to keep them in sync for all of the parts, not just SH-3/4. As the SH-2 parts are unable to do traps in the >= 0x40 range, we restrict the debug traps to the 0x30-0x3f range on all parts, and also bump the kgdb breakpoint trap down in to this range (from 0xff to 0x3c) so it's possible to use for nommu. Optionally, this table can be padded out to catch spurious traps for SH-3/4, but we don't do that yet.. Signed-off-by: Paul Mundt commit b2875d4c39759a732203db32f245cc6d8bbdd7cf Author: Michael S. Tsirkin Date: Sat Feb 10 23:14:25 2007 +0200 IB/mthca: Always fill MTTs from CPU Speed up memory registration by filling in MTTs directly when the CPU can write directly to the whole table (all mem-free cards, and to Tavor mode on 64-bit systems with the patch I posted earlier). This reduces the number of FW commands needed to register an MR by at least a factor of 2 and speeds up memory registration significantly. Signed-off-by: Michael S. Tsirkin Signed-off-by: Roland Dreier commit c20e20ab0f3af9a44842ea11287c9ecd034a5d33 Author: Michael S. Tsirkin Date: Sat Feb 10 23:13:12 2007 +0200 IB/mthca: Merge MR and FMR space on 64-bit systems For Tavor, we currently reserve separate MPT and MTT space for FMRs to avoid abusing the vmalloc space on 32 bit kernels. No such problem exists on 64 bit kernels so let's not do it there. This way we have a shared pool for MR and FMR resources, used on demand. This will also make it possible to write MTTs for regular regions directly from driver. Signed-off-by: Michael S. Tsirkin Signed-off-by: Roland Dreier commit 391e4dea7189eef32b0c2d121e7e047110c1b83c Author: Michael S. Tsirkin Date: Sat Feb 10 23:15:08 2007 +0200 IB/mthca: Fix access to MTT and MPT tables on non-cache-coherent CPUs We allocate the MTT table with alloc_pages() and then do pci_map_sg(), so we must call pci_dma_sync_sg() after the CPU writes to the MTT table. This works since the device will never write MTTs on mem-free HCAs, once we get rid of the use of the WRITE_MTT firmware command. This change is needed to make that work, and is an improvement for now, since it gives FMRs a chance at working. For MPTs, both the device and CPU might write there, so we must allocate DMA coherent memory for these. Signed-off-by: Michael S. Tsirkin Signed-off-by: Roland Dreier commit 1d1f19cfce7687b557cebdc41bf8a5eeba8a9882 Author: Michael S. Tsirkin Date: Sat Feb 10 23:17:26 2007 +0200 IB/mthca: Give reserved MTTs a separate cache line MTTs are allocated in non-cache-coherent memory, so we must give reserved MTTs their own cache line, to prevent both device and CPU from writing into the same cache line at the same time. Signed-off-by: Michael S. Tsirkin Signed-off-by: Roland Dreier commit c7d204e8fdf02f88d91707213f473805bcfb977b Author: Michael S. Tsirkin Date: Sat Feb 10 23:17:26 2007 +0200 IB/mthca: Fix reserved MTTs calculation on mem-free HCAs The reserved_mtts field has different meaning in Tavor and Arbel, so we are wasting mtt entries on memfree. Fix the Arbel case to match Tavor semantics. Signed-off-by: Michael S. Tsirkin Signed-off-by: Roland Dreier commit b038ced7b3705bf0ac9b30e118af0f56ab48b847 Author: Steve Wise Date: Mon Feb 12 16:16:18 2007 -0800 RDMA/cxgb3: Add driver for Chelsio T3 RNIC Add an RDMA/iWARP driver for the Chelsio T3 1GbE and 10GbE adapters. Signed-off-by: Steve Wise Signed-off-by: Roland Dreier commit 34cc560e6a72ff414ff7d107426a411b0a093ad3 Author: David S. Miller Date: Mon Feb 12 15:10:56 2007 -0800 [SPARC]: Re-export saved_command_line to modules. This reverts some bogosity from the dynamic command-line changes made on sparc32 and sparc64. Drivers such as drivers/sbus/char/openprom.c reference saved_command_line, and can be modular. The boot_command_line is __initdata, yet the dynamic command-line changes add modular exports of that symbol, obviously wrong. Signed-off-by: David S. Miller commit b5ba1b31c793185d6e0ee62c1928c84bcff9818e Author: David S. Miller Date: Mon Feb 12 11:01:21 2007 -0800 [SPARC64]: Increase command line size to 2048 like other arches. Signed-off-by: David S. Miller commit 1b51d3a08b6c80a1e47d4c579c41abbe56cd3c44 Author: David S. Miller Date: Mon Feb 12 00:13:31 2007 -0800 [SPARC64]: We do not need ZONE_DMA. Signed-off-by: David S. Miller commit fd19e44f449f7e2e58d42d7bb6813e2292c38fba Author: Linus Torvalds Date: Mon Feb 12 15:05:15 2007 -0800 don't use 'localversion*' files twice Since we look in both source and object directories for localversion* files, we accidentally ended up getting them twice. Use 'sort -u' to avoid that. Reported-by: Tony Luck Signed-off-by: Linus Torvalds commit 13fcfbb0675bf87da694f55dec11cada489a205c Author: David S. Miller Date: Mon Feb 12 13:53:54 2007 -0800 [XFRM]: Fix OOPSes in xfrm_audit_log(). Make sure that this function is called correctly, and add BUG() checking to ensure the arguments are sane. Based upon a patch by Joy Latten. Signed-off-by: David S. Miller commit 82eb7c5059de64bd43f6b3cf3f128470f2b3fb83 Author: Jiri Slaby Date: Thu Feb 8 18:39:36 2007 +0100 [WATCHDOG] timers cleanup - Use timer macros to set function and data members and to modify expiration time. - Use DEFINE_TIMER for single (platform dependent) watchdog timers and do not init them at run-time in these cases. - del_timer_sync is common in most cases -- we want to wait for timer function if it's still running. Signed-off-by: Jiri Slaby Cc: Steve Hill Cc: Heiko Ronsdorf Cc: Fernando Fuganti Cc: Gergely Madarasz Cc: Ken Hollis Cc: Paul Mundt Signed-off-by: Wim Van Sebroeck Signed-off-by: Andrew Morton commit 9121c77706a4bd75a878573c913553ade120e9ce Author: Stephen Hemminger Date: Mon Feb 12 13:34:03 2007 -0800 [TCP]: cleanup of htcp (resend) Minor non-invasive cleanups: * white space around operators and line wrapping * use const * use __read_mostly Signed-off-by: Stephen Hemminger Signed-off-by: David S. Miller commit 59758f44592b0930e83b190cf0206e59d616c983 Author: Stephen Hemminger Date: Mon Feb 12 13:15:20 2007 -0800 [TCP]: Use read mostly for CUBIC parameters. These module parameters should be in the read mostly area to avoid cache pollution. Signed-off-by: Stephen Hemminger Signed-off-by: David S. Miller commit 3aef0fd91c67f4070c8dc607807615c4bdd66bd1 Author: Patrick McHardy Date: Mon Feb 12 11:16:58 2007 -0800 [NETFILTER]: nf_conntrack_tcp: make sysctl variables static sysctls are registered by the protocol module itself since 2.6.19, no need to have them visible to others. Signed-off-by: Patrick McHardy Signed-off-by: David S. Miller commit 138939e0662ccb0e805aefe400bcf9cfcbece8e7 Author: Masahide NAKAMURA Date: Mon Feb 12 11:16:17 2007 -0800 [NETFILTER]: ip6t_mh: drop piggyback payload packet on MH packets Regarding RFC3775, MH payload proto field should be IPPROTO_NONE. Otherwise it must be discarded (and the receiver should send ICMP error). We assume filter should drop such piggyback everytime to disallow slipping through firewall rules, even the final receiver will discard it. Signed-off-by: Masahide NAKAMURA Signed-off-by: Patrick McHardy Signed-off-by: David S. Miller commit 601e68e100b6bf8ba13a32db8faf92d43acaa997 Author: YOSHIFUJI Hideaki Date: Mon Feb 12 11:15:49 2007 -0800 [NETFILTER]: Fix whitespace errors Signed-off-by: YOSHIFUJI Hideaki Signed-off-by: Patrick McHardy Signed-off-by: David S. Miller commit a3c941b08d73e26af9030d34a73a1992cfff1703 Author: Patrick McHardy Date: Mon Feb 12 11:15:02 2007 -0800 [NETFILTER]: Kconfig: improve dependency handling Instead of depending on internally needed options and letting users figure out what is needed, select them when needed: - IP_NF_IPTABLES, IP_NF_ARPTABLES and IP6_NF_IPTABLES select NETFILTER_XTABLES - NETFILTER_XT_TARGET_CONNMARK, NETFILTER_XT_MATCH_CONNMARK and IP_NF_TARGET_CLUSTERIP select NF_CONNTRACK_MARK - NETFILTER_XT_MATCH_CONNBYTES selects NF_CT_ACCT Signed-off-by: Patrick McHardy Signed-off-by: David S. Miller commit 891350c9d168a7d58a193a67a1d107c23f9c2eb1 Author: Patrick McHardy Date: Mon Feb 12 11:14:43 2007 -0800 [NETFILTER]: xt_mac/xt_CLASSIFY: use IPv6 hook names for IPv6 registration Use NF_IP6_ instead of NF_IP_. The values are identical, this is merely cleanup. Signed-off-by: Patrick McHardy Signed-off-by: David S. Miller commit fe3eb20c1ace69e42e6ebf2afd2a904b2ae85cde Author: Patrick McHardy Date: Mon Feb 12 11:14:28 2007 -0800 [NETFILTER]: nf_conntrack: change nf_conntrack_l[34]proto_unregister to void No caller checks the return value, and since its usually called within the module unload path there's nothing a module could do about errors anyway, so BUG on invalid conditions and return void. Signed-off-by: Patrick McHardy Signed-off-by: David S. Miller commit 982d9a9ce389c396bc83ce29d799937f379ddcb7 Author: Patrick McHardy Date: Mon Feb 12 11:14:11 2007 -0800 [NETFILTER]: nf_conntrack: properly use RCU for nf_conntrack_destroyed callback Signed-off-by: Patrick McHardy Signed-off-by: David S. Miller commit 6b48a7d08d1bb2e3932bce1662fe411304acc18f Author: Patrick McHardy Date: Mon Feb 12 11:13:58 2007 -0800 [NETFILTER]: ip_conntrack: properly use RCU for ip_conntrack_destroyed callback Signed-off-by: Patrick McHardy Signed-off-by: David S. Miller commit c0e912d7ed8999f87fa7f084928aac1266e251f3 Author: Patrick McHardy Date: Mon Feb 12 11:13:43 2007 -0800 [NETFILTER]: nf_conntrack: fix invalid conntrack statistics RCU assumption NF_CT_STAT_INC assumes rcu_read_lock in nf_hook_slow disables preemption as well, making it legal to use __get_cpu_var without disabling preemption manually. The assumption is not correct anymore with preemptable RCU, additionally we need to protect against softirqs when not holding nf_conntrack_lock. Add NF_CT_STAT_INC_ATOMIC macro, which disables local softirqs, and use where necessary. Signed-off-by: Patrick McHardy Signed-off-by: David S. Miller commit abbaccda4c364815b8b1a82c45a94f60760e13e1 Author: Patrick McHardy Date: Mon Feb 12 11:13:14 2007 -0800 [NETFILTER]: ip_conntrack: fix invalid conntrack statistics RCU assumption CONNTRACK_STAT_INC assumes rcu_read_lock in nf_hook_slow disables preemption as well, making it legal to use __get_cpu_var without disabling preemption manually. The assumption is not correct anymore with preemptable RCU, additionally we need to protect against softirqs when not holding ip_conntrack_lock. Add CONNTRACK_STAT_INC_ATOMIC macro, which disables local softirqs, and use where necessary. Signed-off-by: Patrick McHardy Signed-off-by: David S. Miller commit 923f4902fefdf4e89b0fb32c4e069d4f57d704f5 Author: Patrick McHardy Date: Mon Feb 12 11:12:57 2007 -0800 [NETFILTER]: nf_conntrack: properly use RCU API for nf_ct_protos/nf_ct_l3protos arrays Replace preempt_{enable,disable} based RCU by proper use of the RCU API and add missing rcu_read_lock/rcu_read_unlock calls in all paths not obviously only used within packet process context (nfnetlink_conntrack). Signed-off-by: Patrick McHardy Signed-off-by: David S. Miller commit 642d628b2c92e5283bbd3c849c7099c64ab68856 Author: Patrick McHardy Date: Mon Feb 12 11:12:40 2007 -0800 [NETFILTER]: ip_conntrack: properly use RCU API for ip_ct_protos array Replace preempt_{enable,disable} based RCU by proper use of the RCU API and add missing rcu_read_lock/rcu_read_unlock calls in all paths not obviously only used within packet process context (nfnetlink_conntrack). Signed-off-by: Patrick McHardy Signed-off-by: David S. Miller commit e22a05486913ccb959281cd6370593bd8e197fa9 Author: Patrick McHardy Date: Mon Feb 12 11:12:26 2007 -0800 [NETFILTER]: nf_nat: properly use RCU API for nf_nat_protos array Replace preempt_{enable,disable} based RCU by proper use of the RCU API and add missing rcu_read_lock/rcu_read_unlock calls in paths used outside of packet processing context (nfnetlink_conntrack). Signed-off-by: Patrick McHardy Signed-off-by: David S. Miller commit a441dfdbb2e54217b8d26a6c129650728d401bf7 Author: Patrick McHardy Date: Mon Feb 12 11:12:09 2007 -0800 [NETFILTER]: ip_nat: properly use RCU API for ip_nat_protos array Replace preempt_{enable,disable} based RCU by proper use of the RCU API and add missing rcu_read_lock/rcu_read_unlock calls in paths used outside of packet processing context (nfnetlink_conntrack). Signed-off-by: Patrick McHardy Signed-off-by: David S. Miller commit e92ad99c78de09a5ba0746e1c0ee27cc7450c64d Author: Patrick McHardy Date: Mon Feb 12 11:11:55 2007 -0800 [NETFILTER]: nf_log: minor cleanups - rename nf_logging to nf_loggers since its an array of registered loggers - rename nf_log_unregister_logger() to nf_log_unregister() to make it symetrical to nf_log_register() and convert all users Signed-off-by: Patrick McHardy Signed-off-by: David S. Miller commit 9b73534dc57fa2fd5ef567586adb83c16e88a52f Author: Patrick McHardy Date: Mon Feb 12 11:11:39 2007 -0800 [NETFILTER]: nf_log: switch logger registration/unregistration to mutex The spinlock is only used in process context (register/unregister), switch to a mutex. Signed-off-by: Patrick McHardy Signed-off-by: David S. Miller commit 9dc6aa5fcfc104becd86c89c5e7ec90e840e0163 Author: Patrick McHardy Date: Mon Feb 12 11:11:24 2007 -0800 [NETFILTER]: nf_log: make nf_log_unregister_pf return void Since the only user of nf_log_unregister_pf (nfnetlink_log) doesn't check the return value, change it to void and bail out silently when a non-existant address family is supplied. Signed-off-by: Patrick McHardy Signed-off-by: David S. Miller commit a5ea6169f294bc33a762f7c1c240e3ac0f045f9e Author: Patrick McHardy Date: Mon Feb 12 11:11:06 2007 -0800 [NETFILTER]: nf_log: use rcu_assign_pointer for RCU protected pointer Also replace synchronize_net() calls by synchronize_rcu() since the RCU protected data is also used for sysfs. Signed-off-by: Patrick McHardy Signed-off-by: David S. Miller commit fd706d6957b3c66ae70b4bbdb9e13993213697f7 Author: Patrick McHardy Date: Mon Feb 12 11:10:14 2007 -0800 [NETFILTER]: Switch nf_register_hook/nf_unregister_hook to mutex The spinlock is only used in process context (register/unregister) since RCU is used for the nf_hook lists, switch to a mutex. Signed-off-by: Patrick McHardy Signed-off-by: David S. Miller commit d486dd1fb8573fad5b8dab61a7d1406116fd4baf Author: Patrick McHardy Date: Mon Feb 12 11:09:55 2007 -0800 [NETFILTER]: Switch nf_register_afinfo/nf_unregister_afinfo to mutex The spinlock is only used in process context (register/unregister), switch to a mutex. Signed-off-by: Patrick McHardy Signed-off-by: David S. Miller commit e4ba13088de7fa384087af398df6629fadb363ba Author: Patrick McHardy Date: Mon Feb 12 11:09:35 2007 -0800 [NETFILTER]: Remove unnecessary synchronize_net() in nf_register_hook We're only adding to the list, no need to synchronize. Signed-off-by: Patrick McHardy Signed-off-by: David S. Miller commit c3a47ab3e5ad62601449e4e5401352271b777e28 Author: Patrick McHardy Date: Mon Feb 12 11:09:19 2007 -0800 [NETFILTER]: Properly use RCU in nf_ct_attach Use rcu_assign_pointer/rcu_dereference for ip_ct_attach pointer instead of self-made RCU and use rcu_read_lock to make sure the conntrack module doesn't disappear below us while calling it, since this function can be called from outside the netfilter hooks. Signed-off-by: Patrick McHardy Signed-off-by: David S. Miller commit ee9b6d61a2a43c5952eb43283f8db284a4e70b8a Author: Josef 'Jeff' Sipek Date: Mon Feb 12 00:55:41 2007 -0800 [PATCH] Mark struct super_operations const This patch is inspired by Arjan's "Patch series to mark struct file_operations and struct inode_operations const". Compile tested with gcc & sparse. Signed-off-by: Josef 'Jeff' Sipek Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit c5ef1c42c51b1b5b4a401a6517bdda30933ddbaf Author: Arjan van de Ven Date: Mon Feb 12 00:55:40 2007 -0800 [PATCH] mark struct inode_operations const 3 Many struct inode_operations in the kernel can be "const". Marking them const moves these to the .rodata section, which avoids false sharing with potential dirty data. In addition it'll catch accidental writes at compile time to these shared resources. Signed-off-by: Arjan van de Ven Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit 92e1d5be91a0e3ffa5c4697eeb09b2aa22792122 Author: Arjan van de Ven Date: Mon Feb 12 00:55:39 2007 -0800 [PATCH] mark struct inode_operations const 2 Many struct inode_operations in the kernel can be "const". Marking them const moves these to the .rodata section, which avoids false sharing with potential dirty data. In addition it'll catch accidental writes at compile time to these shared resources. Signed-off-by: Arjan van de Ven Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit 754661f143e70d66eae6c48532ca245aa05dec0e Author: Arjan van de Ven Date: Mon Feb 12 00:55:38 2007 -0800 [PATCH] mark struct inode_operations const 1 Many struct inode_operations in the kernel can be "const". Marking them const moves these to the .rodata section, which avoids false sharing with potential dirty data. In addition it'll catch accidental writes at compile time to these shared resources. Signed-off-by: Arjan van de Ven Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit 9c2e08c592cd357a8330c34def1e8ecfdcf53275 Author: Arjan van de Ven Date: Mon Feb 12 00:55:37 2007 -0800 [PATCH] mark struct file_operations const 9 Many struct file_operations in the kernel can be "const". Marking them const moves these to the .rodata section, which avoids false sharing with potential dirty data. In addition it'll catch accidental writes at compile time to these shared resources. Signed-off-by: Arjan van de Ven Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit da7071d7e32d15149cc513f096a3638097b66387 Author: Arjan van de Ven Date: Mon Feb 12 00:55:36 2007 -0800 [PATCH] mark struct file_operations const 8 Many struct file_operations in the kernel can be "const". Marking them const moves these to the .rodata section, which avoids false sharing with potential dirty data. In addition it'll catch accidental writes at compile time to these shared resources. Signed-off-by: Arjan van de Ven Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit 9a32144e9d7b4e21341174b1a83b82a82353be86 Author: Arjan van de Ven Date: Mon Feb 12 00:55:35 2007 -0800 [PATCH] mark struct file_operations const 7 Many struct file_operations in the kernel can be "const". Marking them const moves these to the .rodata section, which avoids false sharing with potential dirty data. In addition it'll catch accidental writes at compile time to these shared resources. Signed-off-by: Arjan van de Ven Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit 00977a59b951207d38380c75f03a36829950265c Author: Arjan van de Ven Date: Mon Feb 12 00:55:34 2007 -0800 [PATCH] mark struct file_operations const 6 Many struct file_operations in the kernel can be "const". Marking them const moves these to the .rodata section, which avoids false sharing with potential dirty data. In addition it'll catch accidental writes at compile time to these shared resources. Signed-off-by: Arjan van de Ven Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit d54b1fdb1d9f82e375a299e22bd366aad52d4c34 Author: Arjan van de Ven Date: Mon Feb 12 00:55:34 2007 -0800 [PATCH] mark struct file_operations const 5 Many struct file_operations in the kernel can be "const". Marking them const moves these to the .rodata section, which avoids false sharing with potential dirty data. In addition it'll catch accidental writes at compile time to these shared resources. Signed-off-by: Arjan van de Ven Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit fa027c2a0a0d6d1df6b29ee99048502c93da0dd4 Author: Arjan van de Ven Date: Mon Feb 12 00:55:33 2007 -0800 [PATCH] mark struct file_operations const 4 Many struct file_operations in the kernel can be "const". Marking them const moves these to the .rodata section, which avoids false sharing with potential dirty data. In addition it'll catch accidental writes at compile time to these shared resources. [akpm@sdl.org: dvb fix] Signed-off-by: Arjan van de Ven Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit 2b8693c0617e972fc0b2fd1ebf8de97e15b656c3 Author: Arjan van de Ven Date: Mon Feb 12 00:55:32 2007 -0800 [PATCH] mark struct file_operations const 3 Many struct file_operations in the kernel can be "const". Marking them const moves these to the .rodata section, which avoids false sharing with potential dirty data. In addition it'll catch accidental writes at compile time to these shared resources. Signed-off-by: Arjan van de Ven Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit 5dfe4c964a0dd7bb3a1d64a4166835a153146207 Author: Arjan van de Ven Date: Mon Feb 12 00:55:31 2007 -0800 [PATCH] mark struct file_operations const 2 Many struct file_operations in the kernel can be "const". Marking them const moves these to the .rodata section, which avoids false sharing with potential dirty data. In addition it'll catch accidental writes at compile time to these shared resources. [akpm@osdl.org: sparc64 fix] Signed-off-by: Arjan van de Ven Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit 540473208f8ac71c25a87e1a2670c3c18dd4d6db Author: Arjan van de Ven Date: Mon Feb 12 00:55:28 2007 -0800 [PATCH] mark struct file_operations const 1 Many struct file_operations in the kernel can be "const". Marking them const moves these to the .rodata section, which avoids false sharing with potential dirty data. In addition it'll catch accidental writes at compile time to these shared resources. Signed-off-by: Arjan van de Ven Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit f59e5e82096f81a2cb7d7833001956d81e9fa6fb Author: Geert Uytterhoeven Date: Mon Feb 12 00:55:27 2007 -0800 [PATCH] ps3: ps3av/fb defconfig updates PS3: defconfig updates for ps3av and ps3fb Signed-off-by: Geert Uytterhoeven Cc: James Simmons Cc: Benjamin Herrenschmidt Cc: Paul Mackerras Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit 36dff96b3b83c5d79a45b221adf137b571b03d65 Author: Geert Uytterhoeven Date: Mon Feb 12 00:55:26 2007 -0800 [PATCH] ps3: cleanup ps3fb before clearing HPTE PS3: Cleanup the frame buffer device before clearing the HPTE mapping Signed-off-by: Geert Uytterhoeven Cc: James Simmons Cc: Benjamin Herrenschmidt Cc: Paul Mackerras Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit 0465f790e06d6dbc07d9b569b74ee8154dfca280 Author: Geert Uytterhoeven Date: Mon Feb 12 00:55:25 2007 -0800 [PATCH] ps3: disable display flipping during mode changes If ps3fb is available, we have to disable display flipping while changing the audio or video mode. Signed-off-by: Geert Uytterhoeven Cc: James Simmons Cc: Benjamin Herrenschmidt Cc: Paul Mackerras Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit 310d8c11126d21e417206c874c6382c44ece1baa Author: Geert Uytterhoeven Date: Mon Feb 12 00:55:23 2007 -0800 [PATCH] ps3: Virtual Frame Buffer Driver Add the PS3 Virtual Frame Buffer Driver. As the actual graphics hardware cannot be accessed directly by Linux, ps3fb uses a virtual frame buffer in main memory. The actual screen image is copied to graphics memory by the GPU on every vertical blank, by making a hypervisor call. Signed-off-by: Geert Uytterhoeven Cc: James Simmons Cc: Benjamin Herrenschmidt Cc: Paul Mackerras Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit fbdb3e5be36619c4acf415d870eceab4cbce2850 Author: Geert Uytterhoeven Date: Mon Feb 12 00:55:22 2007 -0800 [PATCH] ps3: Preallocate bootmem memory for ps3fb Preallocate bootmem memory for the PS3 frame buffer device, which needs a large block of physically-contiguous memory. The size of this memory block is configurable: - The config option CONFIG_FB_PS3_DEFAULT_SIZE_M allows to specify the default amount of memory (in MiB) allocated to the virtual frame buffer. - The early boot parameter `ps3fb=xxx' allows to override the default value. It will be rounded up to a multiple of 1 MiB, if needed. Signed-off-by: Geert Uytterhoeven Signed-off-by: Geoff Levand Cc: James Simmons Cc: Benjamin Herrenschmidt Cc: Paul Mackerras Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit dcfe2666ffd6316b764801db82092bc62db56e6f Author: Geert Uytterhoeven Date: Mon Feb 12 00:55:21 2007 -0800 [PATCH] fb_videomode_to_var: reset virtual screen parameters fb_videomode_to_var(): reset the virtual screen parameters when converting from an fb_videomode to an fb_var_screeninfo. Without this the old virtual screen parameters are kept. Hence you cannot switch to a video mode with a lower resolution on frame buffer devices that don't support virtual screens and panning, as values are not supposed to be rounded down when they don't fit. I also reordered the assignments to match the order of the individual members. Signed-off-by: Geert Uytterhoeven Cc: James Simmons Cc: Benjamin Herrenschmidt Cc: Paul Mackerras Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit 9791d763de8cca82b42a7a579e031db78e8011ff Author: Geert Uytterhoeven Date: Mon Feb 12 00:55:19 2007 -0800 [PATCH] fbdev modedb: make more pointer parameters const fbdev modedb: make more input and output pointer parameters const Signed-off-by: Geert Uytterhoeven Cc: James Simmons Cc: Benjamin Herrenschmidt Cc: Paul Mackerras Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit 5c52cbeb7f27e1242e88f99f7f6486a16d5733c7 Author: Geert Uytterhoeven Date: Mon Feb 12 00:55:18 2007 -0800 [PATCH] fbdev modedb: allow refresh rates for named video modes fbdev modedb: Take into account the specified refresh rates for video modes specified by name, so e.g. all of `720p', `720p@60', and `720p@50' work. Signed-off-by: Geert Uytterhoeven Cc: James Simmons Cc: Benjamin Herrenschmidt Cc: Paul Mackerras Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit 11227fd1922dc5dda691586852cfd220dd383f37 Author: Geert Uytterhoeven Date: Mon Feb 12 00:55:16 2007 -0800 [PATCH] ps3: AV Settings Driver Add the PS3 AV Settings Driver. The AV Settings driver is used to control Audio and Video settings. It communicates with the policy manager through the virtual uart. Signed-off-by: Geert Uytterhoeven Cc: James Simmons Cc: Benjamin Herrenschmidt Cc: Paul Mackerras Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit 5b8e8ee6c65a34d8aafaeb8e2eaa97e496c2567c Author: Geert Uytterhoeven Date: Mon Feb 12 00:55:15 2007 -0800 [PATCH] ps3: add shutdown to virtual uart port driver framework PS3: Add a shutdown method to the PS3's virtual uart port driver framework Signed-off-by: Geert Uytterhoeven Signed-off-by: Geoff Levand Cc: James Simmons Cc: Benjamin Herrenschmidt Cc: Paul Mackerras Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit 5e14ab8b5ecca8997406180e23761525f49a09a3 Author: Prarit Bhargava Date: Mon Feb 12 00:55:14 2007 -0800 [PATCH] change nvidiafb_remove to __devexit Change nvidiafb_remove to __devexit to fix MODPOST warnings: WARNING: drivers/video/nvidia/nvidiafb.o - Section mismatch: reference to .exit.text:nvidiafb_remove from .data.rel.local after 'nvidiafb_driver' (at offset 0x28) Signed-off-by: Prarit Bhargava Acked-By: James Simmons Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit f5610b9c3a2896fcaa623b92d0f24d83f10bb2c0 Author: Jiri Slaby Date: Mon Feb 12 00:55:12 2007 -0800 [PATCH] Video: fb, kzalloc changes Use kzalloc instead of kmalloc + memset(0). Signed-off-by: Jiri Slaby Cc: James Simmons Cc: "Antonino A. Daplas" Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit c4f28e54d61278203c2bb2aea0679e0a738235d2 Author: Jiri Slaby Date: Mon Feb 12 00:55:11 2007 -0800 [PATCH] Video: fb, add true ref_count atomicity Some of fb drivers uses atomic_t in bad manner, since there are still some race-prone gaps. Use mutexes to protect open/close code sections with ref_count testing and finally use simple uint. Signed-off-by: Jiri Slaby Acked-by: Denis Oliver Kropp Cc: James Simmons Cc: "Antonino A. Daplas" Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit 52e7c922f37907ab3cf3445b916fbbc53cbd6c75 Author: Adrian Bunk Date: Mon Feb 12 00:55:09 2007 -0800 [PATCH] remove the broken FB_S3TRIO driver The FB_S3TRIO driver: - has been marked as BROKEN for more than two years and - is still marked as BROKEN. Drivers that had been marked as BROKEN for such a long time seem to be unlikely to be revived in the forseeable future. But if anyone wants to ever revive this driver, the code is still present in the older kernel releases. Signed-off-by: Adrian Bunk Acked-by: Geert Uytterhoeven Cc: "Antonino A. Daplas" Cc: James Simmons Acked-by: Alan Cox Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit 2fdbe5cf27aff997e348c5f01b424ad734bd1d25 Author: Jean Delvare Date: Mon Feb 12 00:55:07 2007 -0800 [PATCH] matroxfb: Use kzalloc Use kzalloc instead of kmalloc+memset, twice. Signed-off-by: Jean Delvare Cc: Petr Vandrovec Acked-By: James Simmons Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit c30660ead2dd6ced47ac6ad4c099fb9305263ffb Author: Richard Knutsson Date: Mon Feb 12 00:55:06 2007 -0800 [PATCH] drivers/video/sis: Convert to generic boolean Convert: FALSE -> false TRUE -> true BOOLEAN -> bool Signed-off-by: Richard Knutsson Cc: Thomas Hellstrom Cc: James Simmons Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit 3aebbd8f92ef1aa3048800b4991db60403b85964 Author: Alan Date: Mon Feb 12 00:55:05 2007 -0800 [PATCH] pm3fb: kill pci_find_device usage Signed-off-by: Alan Cox Acked-by: James Simmons Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit 33e321b458ffa09cf0dcc7ff4e35fb31d3a71a49 Author: Robert P. J. Day Date: Mon Feb 12 00:55:03 2007 -0800 [PATCH] Correct apparent typo CONFIG_ATY_CT in ATY video Replace the apparent typo CONFIG_ATY_CT with CONFIG_FB_ATY_CT. Signed-off-by: Robert P. J. Day Cc: James Simmons Cc: Ville Syrjala Cc: Antonino A. Daplas Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit c7b54477d36fc5d6bd3c4e2e025a39ad9ccb5188 Author: Alexey Dobriyan Date: Mon Feb 12 00:55:02 2007 -0800 [PATCH] Recognize video=gx1fb:... option Juergen Beisert reported that the following option doesn't work for him video=gx1fb:1024x768-16@60 though sisfb was able to parse similar option correctly. Signed-off-by: Alexey Dobriyan Cc: Jordan Crouse Cc: "Antonino A. Daplas" Cc: James Simmons Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit f9506a53b446bc942c79584d3ce442d6334de697 Author: Adrian Bunk Date: Mon Feb 12 00:55:01 2007 -0800 [PATCH] proper prototype for tosh_smm() Add a proper prototype for tosh_smm() to include/linux/toshiba.h Signed-off-by: Adrian Bunk Cc: James Simmons Cc: "Antonino A. Daplas" Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit cd792aa896f281a224870eb5f2ee5b24682910a5 Author: Woody Suwalski Date: Mon Feb 12 00:55:00 2007 -0800 [PATCH] cyber2010 framebuffer on ARM Netwinder fix The Netwinder machines with Cyber2010 crash badly when starting Xserver. The workaround is to disable pci burst option for this revision of video chip. [akpm@osdl.org: cleanup] Signed-off-by: Woody Suwalski Cc: "Antonino A. Daplas" Cc: James Simmons Cc: Ralf Baechle Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit 3a0991029b577125ac5b3eedbe366320c581d8d6 Author: Adrian Bunk Date: Mon Feb 12 00:54:59 2007 -0800 [PATCH] remove bogus con_is_present() prototypes Although gcc seems to accept "extern" prototypes after it has seen the "static inline" function, that's not really correct. Signed-off-by: Adrian Bunk Cc: "Antonino A. Daplas" Cc: James Simmons Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit fef459028bd842dde21bf55f83d6399b963f9911 Author: Maciej W. Rozycki Date: Mon Feb 12 00:54:58 2007 -0800 [PATCH] tgafb: Fix the PCI ID table The end marker is missing from the driver's PCI ID table. This set of changes adds the marker, switches to using PCI_DEVICE() and records the table for the use in a module. Signed-off-by: Maciej W. Rozycki Cc: James Simmons Cc: "Antonino A. Daplas" Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit a524d946bdced73c5fbe60170fb33611491c4211 Author: Maciej W. Rozycki Date: Mon Feb 12 00:54:57 2007 -0800 [PATCH] tgafb: sync-on-green support fixes This sets up the deep register of the TGA ASIC as well as the blank pedestal of the Bt463 RAMDAC correctly for the sync-on-green mode. Signed-off-by: Maciej W. Rozycki Cc: James Simmons Cc: "Antonino A. Daplas" Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit 1b2f2fe8ac0273ae9a9b480b799ce62d832168cb Author: Maciej W. Rozycki Date: Mon Feb 12 00:54:56 2007 -0800 [PATCH] tgafb: module support fixes This is a set of clean-ups for the module support in the driver -- __devinit and __devexit classifiers are now specified correctly, initialization functions are marked static and a few unnecessary #ifdefs are removed. Signed-off-by: Maciej W. Rozycki Cc: James Simmons Cc: "Antonino A. Daplas" Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit c7488ce38121fc92aee847c51ac74dced1d48c3a Author: Maciej W. Rozycki Date: Mon Feb 12 00:54:55 2007 -0800 [PATCH] tgafb: fix the mode register setting There is no need to set the GE bit (Win32 compatibility) in the mode register; it shall get cleared with the next subsequent update to the register anyway. Signed-off-by: Maciej W. Rozycki Cc: James Simmons Cc: "Antonino A. Daplas" Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit be6011831c74d5db251b5f9746d259a5f59e71cf Author: Maciej W. Rozycki Date: Mon Feb 12 00:54:54 2007 -0800 [PATCH] tgafb: support the DirectColor visual The 32-plane variations of the TGA use the Bt463 RAMDAC and are therefore DirectColor rather than TrueColor adapters. This is a set of changes to implement the necessary bits to support this model. A couple of fixes to fix accesses to the RAMDAC are included as a side-effect. Signed-off-by: Maciej W. Rozycki Cc: James Simmons Cc: "Antonino A. Daplas" Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit 36f71405e63f3d1e4c2a8dd98523820bbca8e078 Author: Maciej W. Rozycki Date: Mon Feb 12 00:54:53 2007 -0800 [PATCH] tgafb: fix copying overlapping areas The direction of copying in the copyarea functions is selected incorrectly, resulting in corruption. This is a fix. Signed-off-by: Maciej W. Rozycki Cc: James Simmons Cc: "Antonino A. Daplas" Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit ee9a25e5df81f4392439055c28989dfd4b18d894 Author: Maciej W. Rozycki Date: Mon Feb 12 00:54:52 2007 -0800 [PATCH] tgafb: switch to framebuffer_alloc() This is a set of changes to update the driver to the framebuffer_alloc() API. Included, there is also a fix to a memory leak due to the colour map allocation not being freed upon driver's removal. Aside from the fix there are no functional changes. Signed-off-by: Maciej W. Rozycki Cc: James Simmons Cc: "Antonino A. Daplas" Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit e019630e78e3482c2386d18cbdc7a4c54f7a809c Author: Adrian Bunk Date: Mon Feb 12 00:54:50 2007 -0800 [PATCH] remove broken video drivers Remove some video drivers that: - had already been marked as BROKEN in 2.6.0 three years ago and - are still marked as BROKEN. These are the following drivers: - FB_CYBER - FB_VIRGE - FB_RETINAZ3 - FB_SUN3 Drivers that had been marked as BROKEN for such a long time seem to be unlikely to be revived in the forseeable future. But if anyone wants to ever revive any of these drivers, the code is still present in the older kernel releases. Signed-off-by: Adrian Bunk Acked-By: Geert Uytterhoeven Cc: James Simmons Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit a268422de8bf1b4c0cb97987b6c329c9f6a3da4b Author: Ondrej Zajicek Date: Mon Feb 12 00:54:49 2007 -0800 [PATCH] fbdev driver for S3 Trio/Virge Add a driver for S3 Trio / S3 Virge. Driver is tested with most versions of S3 Trio and with S3 Virge/DX, on i386. (akpm: We kind-of have support for this hardware already, but... virgefb.c - amiga/zorro specific, - broken (according to Kconfig), - uses obsolete/nonexistent interface (struct display_switch) - recent Adrian Bunk's patch removes this driver S3triofb.c - ppc/openfirmware specific - minimal functionality - broken (according to Kconfig), - uses obsolete/nonexistent interface (struct display_switch) ) Signed-off-by: Ondrej Zajicek Cc: James Simmons Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit 59ae6c6b87711ceb2d1ea5f9e08bb13aee947a29 Author: Avi Kivity Date: Mon Feb 12 00:54:48 2007 -0800 [PATCH] KVM: Host suspend/resume support Add the necessary callbacks to suspend and resume a host running kvm. This is just a repeat of the cpu hotplug/unplug work. Signed-off-by: Avi Kivity Cc: Ingo Molnar Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit 774c47f1d78e373a6bd2964f4e278d1ce26c21cb Author: Avi Kivity Date: Mon Feb 12 00:54:47 2007 -0800 [PATCH] KVM: cpu hotplug support On hotplug, we execute the hardware extension enable sequence. On unplug, we decache any vcpus that last ran on the exiting cpu, and execute the hardware extension disable sequence. Signed-off-by: Avi Kivity Cc: Ingo Molnar Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit 8d0be2b3bf4a55606967d7d84e56c52521e94333 Author: Avi Kivity Date: Mon Feb 12 00:54:46 2007 -0800 [PATCH] KVM: VMX: add vcpu_clear() Like the inline code it replaces, this function decaches the vmcs from the cpu it last executed on. in addition: - vcpu_clear() works if the last cpu is also the cpu we're running on - it is faster on larger smps by virtue of using smp_call_function_single() Includes fix from Ingo Molnar. Signed-off-by: Ingo Molnar Signed-off-by: Avi Kivity Cc: Ingo Molnar Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit 133de9021d2988f3fbdad84c2d26484c7a757526 Author: Avi Kivity Date: Mon Feb 12 00:54:44 2007 -0800 [PATCH] KVM: Add a global list of all virtual machines This will allow us to iterate over all vcpus and see which cpus they are running on. [akpm@osdl.org: use standard (ugly) initialisers] Signed-off-by: Avi Kivity Cc: Ingo Molnar Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit 47e627bc8c9a70392d2049e6af5bd55fae61fe53 Author: Avi Kivity Date: Mon Feb 12 00:54:43 2007 -0800 [PATCH] hotplug: Allow modules to use the cpu hotplug notifiers even if !CONFIG_HOTPLUG_CPU The following patchset allows a host with running virtual machines to be suspended and, on at least a subset of the machines tested, resumed. Note that this is orthogonal to suspending and resuming an individual guest to a file. A side effect of implementing suspend/resume is that cpu hotplug is now supported. This should please the owners of big iron. This patch: KVM wants the cpu hotplug notifications, both for cpu hotplug itself, but more commonly for host suspend/resume. In order to avoid extensive #ifdefs, provide stubs when CONFIG_CPU_HOTPLUG is not defined. In all, we have four cases: - UP: register and unregister stubbed out - SMP+hotplug: full register and unregister - SMP, no hotplug, core: register as __init, unregister stubbed (cpus are brought up during core initialization) - SMP, no hotplug, module: register and unregister stubbed out (cpus cannot be brought up during module lifetime) Signed-off-by: Avi Kivity Cc: Ingo Molnar Cc: Rusty Russell Cc: Oleg Nesterov Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit 1e8ba6fba5050ec11bba90c8622aa2ed95ff711f Author: Ingo Molnar Date: Mon Feb 12 00:54:42 2007 -0800 [PATCH] kvm: fix vcpu freeing bug vcpu_load() can return NULL and it sometimes does in failure paths (for example when the userspace ABI version is too old) - causing a preemption count underflow in the ->vcpu_free() later on. So check for NULL. Signed-off-by: Ingo Molnar Signed-off-by: Avi Kivity Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit 8cd133073f9b5cd335c0b2e4740aceb025d50ca9 Author: Avi Kivity Date: Mon Feb 12 00:54:41 2007 -0800 [PATCH] kvm: Fix mismatch between 32-bit and 64-bit abi Unfortunately requiring a version bump. Signed-off-by: Avi Kivity Cc: Ingo Molnar Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit 26bb83a755593a53bd248e20d699b0c813f1e238 Author: Avi Kivity Date: Mon Feb 12 00:54:40 2007 -0800 [PATCH] kvm: VMX: Reload ds and es even in 64-bit mode Or 32-bit userspace will get confused. Signed-off-by: Avi Kivity Cc: Ingo Molnar Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit 54810342f1372afdaf6cb9a6aea0c35df187db12 Author: Dor Laor Date: Mon Feb 12 00:54:39 2007 -0800 [PATCH] kvm: Two-way apic tpr synchronization We report the value of cr8 to userspace on an exit. Also let userspace change cr8 when we re-enter the guest. The lets 64-bit guest code maintain the tpr correctly. Thanks for Yaniv Kamay for the idea. Signed-off-by: Dor Laor Signed-off-by: Avi Kivity Cc: Ingo Molnar Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit d92899a0014aa795c21d3cf726ef5ff7684399f4 Author: Avi Kivity Date: Mon Feb 12 00:54:38 2007 -0800 [PATCH] kvm: SVM: Hack initial cpu csbase to be consistent with intel This allows us to run the mmu testsuite on amd. Signed-off-by: Avi Kivity Cc: Ingo Molnar Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit ac6c2bc592b90c7f140fc87c49e21bc82376e2aa Author: Avi Kivity Date: Mon Feb 12 00:54:37 2007 -0800 [PATCH] kvm: Fix mmu going crazy of guest sets cr0.wp == 0 The kvm mmu relies on cr0.wp being set even if the guest does not set it. The vmx code correctly forces cr0.wp at all times, the svm code does not, so it can't boot solaris without this patch. Signed-off-by: Avi Kivity Cc: Ingo Molnar Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit 988ad74ff6107d9a490ee193e41251e27d37c95f Author: Avi Kivity Date: Mon Feb 12 00:54:36 2007 -0800 [PATCH] kvm: vmx: handle triple faults by returning EXIT_REASON_SHUTDOWN to userspace Just like svm. Signed-off-by: Avi Kivity Cc: Ingo Molnar Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit e119d117a1d16e71876144188c0e0b3ecb8aeede Author: Avi Kivity Date: Mon Feb 12 00:54:36 2007 -0800 [PATCH] kvm: Fix gva_to_gpa() gva_to_gpa() needs to be updated to the new walk_addr() calling convention, otherwise it may oops under some circumstances. Use the opportunity to remove all the code duplication in gva_to_gpa(), which essentially repeats the calculations in walk_addr(). Signed-off-by: Avi Kivity Cc: Ingo Molnar Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit a0610ddf6be6465049a5da448d7e6c5e821240e6 Author: S.Caglar Onur Date: Mon Feb 12 00:54:34 2007 -0800 [PATCH] kvm: Fix asm constraint for lldt instruction lldt does not accept immediate operands, which "g" allows. Signed-off-by: S.Caglar Onur Signed-off-by: Avi Kivity Cc: Ingo Molnar Cc: Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit 96958231cea5985e32db2ae1125ec20483e3556b Author: Ingo Molnar Date: Mon Feb 12 00:54:33 2007 -0800 [PATCH] kvm: optimize inline assembly Forms like "0(%rsp)" generate an instruction with an unnecessary one byte displacement under certain circumstances. replace with the equivalent "(%rsp)". Signed-off-by: Avi Kivity Cc: Ingo Molnar Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit 54fb996ac15c4014fa4d6b0ec8e42da134204897 Author: Evgeniy Dushistov Date: Mon Feb 12 00:54:32 2007 -0800 [PATCH] ufs2 write: block allocation update Patch adds ability to work with 64bit metadata, this made by replacing work with 32bit pointers by inline functions. Signed-off-by: Evgeniy Dushistov Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit 3313e29267414e4e3bf0d3de1caf9cb439b64aaf Author: Evgeniy Dushistov Date: Mon Feb 12 00:54:31 2007 -0800 [PATCH] ufs2 write: inodes write This patch adds into write inode path function to write UFS2 inode, and modifys allocate inode path to allocate and init additional inode chunks. Also some cleanups: - remove not used parameters in some functions - remove i_gen field from ufs_inode_info structure, there is i_generation in inode structure with same purposes. Signed-off-by: Evgeniy Dushistov Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit cbcae39fa1cc16c0fb199223f5ec1aea5f4c7b2d Author: Evgeniy Dushistov Date: Mon Feb 12 00:54:30 2007 -0800 [PATCH] ufs2 write: mount as rw These series of patches add UFS2 write-support. UFS2 - is default file system for recent versions of FreeBSD. The main differences from UFS1 from write support point of view are: 1)Not all inodes are allocated during formatation of disk. 2)All meta-data(pointer to data blocks) are 64bit(in UFS1 they are 32bit). So patch series consist of 1)make possible mount UFS2 in read-write mode 2)code to write ufs2 inodes and code to initialize inodes chunks. 3)work with 64bit meta-data I made simple testing like create/deleting/writing/reading/truncating, also I ran fsx-linux and untar and build kernel on UFS1 and UFS2, after that FreeBSD fsck do not find any errors in fs. This patch makes possible to mount ufs2 "rw", and updates UFS2 documentation: remove note about bug(it fixed by reallocate blocks on the fly patch) and add me in the list of people who want receive bug reports. Signed-off-by: Evgeniy Dushistov Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit cca97de1184f6000d22b4106d47687b31cca1fa3 Author: Alon Bar-Lev Date: Mon Feb 12 00:54:29 2007 -0800 [PATCH] ia64: 2048-byte command line Current implementation allows the kernel to receive up to 255 characters from the bootloader. While the boot protocol allows greater buffers to be sent. In current environment, the command-line is used in order to specify many values, including suspend/resume, module arguments, splash, initramfs and more. 255 characters are not enough anymore. After edd issue was fixed, and dynammic kernel command-line patch was accepted, we can extend the COMMAND_LINE_SIZE without runtime memory requirements. Signed-off-by: Alon Bar-Lev Cc: "Luck, Tony" Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit bbd4bb9aa7635063284ffb3470ab24c36c14d935 Author: Alon Bar-Lev Date: Mon Feb 12 00:54:28 2007 -0800 [PATCH] x86_64: 2048-byte command line Current implementation allows the kernel to receive up to 255 characters from the bootloader. While the boot protocol allows greater buffers to be sent. In current environment, the command-line is used in order to specify many values, including suspend/resume, module arguments, splash, initramfs and more. 255 characters are not enough anymore. After edd issue was fixed, and dynammic kernel command-line patch was accepted, we can extend the COMMAND_LINE_SIZE without runtime memory requirements. Signed-off-by: Alon Bar-Lev Cc: Andi Kleen Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit 7bf9f974fbdc16769db3d48f7c31f932b233bcfb Author: Alon Bar-Lev Date: Mon Feb 12 00:54:27 2007 -0800 [PATCH] i386: 2048-byte command line Current implementation allows the kernel to receive up to 255 characters from the bootloader. While the boot protocol allows greater buffers to be sent. In current environment, the command-line is used in order to specify many values, including suspend/resume, module arguments, splash, initramfs and more. 255 characters are not enough anymore. After edd issue was fixed, and dynammic kernel command-line patch was accepted, we can extend the COMMAND_LINE_SIZE without runtime memory requirements. Signed-off-by: Alon Bar-Lev Cc: Andi Kleen Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit 7a3a06d0e158fc82a6bf13e18439285c7791d2b8 Author: Alon Bar-Lev Date: Mon Feb 12 00:54:26 2007 -0800 [PATCH] Dynamic kernel command-line: fixups Remove in-source externs, linux/init.h is included in all cases. This is a fixups for "Dynamic kernel command-line" patch. It also includes some uml __init fixups so that we can __initdata also its command_line. Signed-off-by: Alon Bar-Lev Cc: Jeff Dike Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit d3e9cceafd9c886561f602bcdcb03efd96e187ab Author: Alon Bar-Lev Date: Mon Feb 12 00:54:25 2007 -0800 [PATCH] Dynamic kernel command-line: xtensa 1. Rename saved_command_line into boot_command_line. 2. Set command_line as __initdata. Signed-off-by: Alon Bar-Lev Cc: Chris Zankel Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit adf48856db47f4f0f661f2f4b7004890408135cf Author: Alon Bar-Lev Date: Mon Feb 12 00:54:25 2007 -0800 [PATCH] Dynamic kernel command-line: x86_64 1. Rename saved_command_line into boot_command_line. 2. Set command_line as __initdata. Signed-off-by: Alon Bar-Lev Cc: Andi Kleen Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit 712f77b5659208b43c925e1b28c4f44891c4d94f Author: Alon Bar-Lev Date: Mon Feb 12 00:54:24 2007 -0800 [PATCH] Dynamic kernel command-line: v850 1. Rename saved_command_line into boot_command_line. 2. Set command_line as __initdata. Signed-off-by: Alon Bar-Lev Cc: Miles Bader Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit 19bf7e7a414711dec0058556feda778105798f99 Author: Alon Bar-Lev Date: Mon Feb 12 00:54:23 2007 -0800 [PATCH] Dynamic kernel command-line: um 1. Rename saved_command_line into boot_command_line. 2. Set command_line as __initdata. Signed-off-by: Alon Bar-Lev Cc: Jeff Dike Cc: Paolo 'Blaisorblade' Giarrusso Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit 383464c0fb067f5beb96e28ff376d2280808dd54 Author: Alon Bar-Lev Date: Mon Feb 12 00:54:22 2007 -0800 [PATCH] Dynamic kernel command-line: sparc64 Rename saved_command_line into boot_command_line. Signed-off-by: Alon Bar-Lev Cc: "David S. Miller" Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit 08e7ca11eed86acde42ee97b9392faa10f9c70d1 Author: Alon Bar-Lev Date: Mon Feb 12 00:54:21 2007 -0800 [PATCH] Dynamic kernel command-line: sparc Rename saved_command_line into boot_command_line. Signed-off-by: Alon Bar-Lev Cc: William Lee Irwin III Cc: "David S. Miller" Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit 3e42ff6c65cf40caa1f6ca51a4c3d552803e0957 Author: Alon Bar-Lev Date: Mon Feb 12 00:54:20 2007 -0800 [PATCH] Dynamic kernel command-line: sh64 1. Rename saved_command_line into boot_command_line. 2. Set command_line as __initdata. Signed-off-by: Alon Bar-Lev Acked-by: Paul Mundt Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit 53c82622c2db808c015953336faecefc0ebf29bc Author: Alon Bar-Lev Date: Mon Feb 12 00:54:19 2007 -0800 [PATCH] Dynamic kernel command-line: sh 1. Rename saved_command_line into boot_command_line. 2. Set command_line as __initdata. Signed-off-by: Alon Bar-Lev Acked-by: Paul Mundt Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit e06b1a3513bdd897e3c37c98ed7b16fa237dcb63 Author: Alon Bar-Lev Date: Mon Feb 12 00:54:19 2007 -0800 [PATCH] Dynamic kernel command-line: s390 Rename saved_command_line into boot_command_line. Signed-off-by: Alon Bar-Lev Cc: Heiko Carstens Cc: Martin Schwidefsky Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit bf71cecbe4282fbb8ec035a7199fa4aca64db54c Author: Alon Bar-Lev Date: Mon Feb 12 00:54:18 2007 -0800 [PATCH] Dynamic kernel command-line: ppc Rename saved_command_line into boot_command_line. Signed-off-by: Alon Bar-Lev Cc: Paul Mackerras Cc: Benjamin Herrenschmidt Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit b8757b21f7628c57cb20e55be324fdef283a56e9 Author: Alon Bar-Lev Date: Mon Feb 12 00:54:17 2007 -0800 [PATCH] Dynamic kernel command-line: powerpc Rename saved_command_line into boot_command_line. Signed-off-by: Alon Bar-Lev Cc: Paul Mackerras Cc: Benjamin Herrenschmidt Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit 668f9931c812224ab2a6d57cdf2f0ec3865b68d2 Author: Alon Bar-Lev Date: Mon Feb 12 00:54:16 2007 -0800 [PATCH] Dynamic kernel command-line: parisc 1. Rename saved_command_line into boot_command_line. 2. Set command_line as __initdata. Signed-off-by: Alon Bar-Lev Cc: Ralf Baechle Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit 43cd34645d3bf35cbaa68f28b85d12d0b9e08ab9 Author: Alon Bar-Lev Date: Mon Feb 12 00:54:15 2007 -0800 [PATCH] Dynamic kernel command-line: mips Rename saved_command_line into boot_command_line. Signed-off-by: Alon Bar-Lev Cc: Ralf Baechle Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit f2a09e19cae45b7dfa4b72d70182b5bc9afa2ddb Author: Alon Bar-Lev Date: Mon Feb 12 00:54:14 2007 -0800 [PATCH] Dynamic kernel command-line: m68knommu 1. Rename saved_command_line into boot_command_line. 2. Set command_line as __initdata. Signed-off-by: Alon Bar-Lev Cc: Greg Ungerer Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit 187959f31e92cde16b274f0b61dfaca3a8b14089 Author: Alon Bar-Lev Date: Mon Feb 12 00:54:14 2007 -0800 [PATCH] Dynamic kernel command-line: m68k Rename saved_command_line into boot_command_line. Signed-off-by: Alon Bar-Lev Cc: Geert Uytterhoeven Cc: Roman Zippel Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit 3561794d80843588ed8b47fffb20e2dcd9c40ff3 Author: Alon Bar-Lev Date: Mon Feb 12 00:54:13 2007 -0800 [PATCH] Dynamic kernel command-line: m32r 1. Rename saved_command_line into boot_command_line. 2. Set command_line as __initdata. Signed-off-by: Alon Bar-Lev Cc: Hirokazu Takata Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit a8d91b8477aa433ee0131b031d782411976e1726 Author: Alon Bar-Lev Date: Mon Feb 12 00:54:12 2007 -0800 [PATCH] Dynamic kernel command-line: ia64 1. Rename saved_command_line into boot_command_line. 2. Set command_line as __initdata. [akpm@osdl.org: move some declarations to the right place] Signed-off-by: Alon Bar-Lev Cc: "Luck, Tony" Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit 4e498b66104af914ef04d6e7fbbbc13a4f7c936e Author: Alon Bar-Lev Date: Mon Feb 12 00:54:11 2007 -0800 [PATCH] Dynamic kernel command-line: i386 1. Rename saved_command_line into boot_command_line. 2. Set command_line as __initdata. Signed-off-by: Alon Bar-Lev Cc: Andi Kleen Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit 5ff625904cd4e41d70bc01e6683cbb58f312f709 Author: Alon Bar-Lev Date: Mon Feb 12 00:54:10 2007 -0800 [PATCH] Dynamic kernel command-line: h8300 1. Rename saved_command_line into boot_command_line. 2. Set command_line as __initdata. Signed-off-by: Alon Bar-Lev Cc: Yoshinori Sato Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit 9c00f7613249b3b42782a226308353a4033c11c3 Author: Alon Bar-Lev Date: Mon Feb 12 00:54:09 2007 -0800 [PATCH] Dynamic kernel command-line: frv 1. Rename saved_command_line into boot_command_line. 2. Set command_line as __initdata. Signed-off-by: Alon Bar-Lev Cc: David Howells Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit 87e1f9c6dcb4829fd8a68a3af87098cee8ef955b Author: Alon Bar-Lev Date: Mon Feb 12 00:54:09 2007 -0800 [PATCH] Dynamic kernel command-line: cris 1. Rename saved_command_line into boot_command_line. 2. Set cris_command_line as __initdata. Signed-off-by: Alon Bar-Lev Cc: Mikael Starvik Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit bf4352c0fc82e6dadfa7eea506c19dea0106baac Author: Alon Bar-Lev Date: Mon Feb 12 00:54:08 2007 -0800 [PATCH] Dynamic kernel command-line: avr32 1. Rename saved_command_line into boot_command_line. 2. Set command_line as __initdata. Signed-off-by: Alon Bar-Lev Acked-by: Haavard Skinnemoen Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit 64d5a70f956071f8434f403d44835a4895abb78e Author: Alon Bar-Lev Date: Mon Feb 12 00:54:07 2007 -0800 [PATCH] Dynamic kernel command-line: arm26 1. Rename saved_command_line into boot_command_line. 2. Set command_line as __initdata. Signed-off-by: Alon Bar-Lev Cc: Ian Molton Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit cd81899a7d9e77ffd5280b10d0413fb241b18388 Author: Alon Bar-Lev Date: Mon Feb 12 00:54:06 2007 -0800 [PATCH] Dynamic kernel command-line: arm 1. Rename saved_command_line into boot_command_line. 2. Set command_line as __initdata. Signed-off-by: Alon Bar-Lev Cc: Russell King Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit 3c253ca0f0930b767a5d6ac0c1b3c6f5619e28f9 Author: Alon Bar-Lev Date: Mon Feb 12 00:54:05 2007 -0800 [PATCH] Dynamic kernel command-line: alpha 1. Rename saved_command_line into boot_command_line. 2. Set command_line as __initdata. Signed-off-by: Alon Bar-Lev Cc: Richard Henderson Cc: Ivan Kokshaysky Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit 30d7e0d466b3ac0b5ef77e4062bf9385f0d72270 Author: Alon Bar-Lev Date: Mon Feb 12 00:53:52 2007 -0800 [PATCH] Dynamic kernel command-line: common Current implementation stores a static command-line buffer allocated to COMMAND_LINE_SIZE size. Most architectures stores two copies of this buffer, one for future reference and one for parameter parsing. Current kernel command-line size for most architecture is much too small for module parameters, video settings, initramfs paramters and much more. The problem is that setting COMMAND_LINE_SIZE to a grater value, allocates static buffers. In order to allow a greater command-line size, these buffers should be dynamically allocated or marked as init disposable buffers, so unused memory can be released. This patch renames the static saved_command_line variable into boot_command_line adding __initdata attribute, so that it can be disposed after initialization. This rename is required so applications that use saved_command_line will not be affected by this change. It reintroduces saved_command_line as dynamically allocated buffer to match the data in boot_command_line. It also mark secondary command-line buffer as __initdata, and copies it to dynamically allocated static_command_line buffer components may hold reference to it after initialization. This patch is for linux-2.6.20-rc4-mm1 and is divided to target each architecture. I could not check this in any architecture so please forgive me if I got it wrong. The per-architecture modification is very simple, use boot_command_line in place of saved_command_line. The common code is the change into dynamic command-line. This patch: 1. Rename saved_command_line into boot_command_line, mark as init disposable. 2. Add dynamic allocated saved_command_line. 3. Add dynamic allocated static_command_line. 4. During startup copy: boot_command_line into saved_command_line. arch command_line into static_command_line. 5. Parse static_command_line and not arch command_line, so arch command_line may be freed. Signed-off-by: Alon Bar-Lev Cc: Andi Kleen Cc: Paul Mackerras Cc: Benjamin Herrenschmidt Cc: Richard Henderson Cc: Ivan Kokshaysky Cc: Russell King Cc: Ian Molton Cc: Mikael Starvik Cc: David Howells Cc: Yoshinori Sato Cc: Ralf Baechle Cc: Kyle McMartin Cc: Heiko Carstens Cc: Martin Schwidefsky Cc: Hirokazu Takata Cc: Paul Mundt Cc: Kazumoto Kojima Cc: Richard Curnow Cc: William Lee Irwin III Cc: "David S. Miller" Cc: Jeff Dike Cc: Paolo 'Blaisorblade' Giarrusso Cc: Miles Bader Cc: Chris Zankel Cc: "Luck, Tony" Cc: Geert Uytterhoeven Cc: Roman Zippel Cc: Greg Ungerer Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit ff91691bccdb741efb2df0489058a4961fa79598 Author: Nick Piggin Date: Mon Feb 12 00:53:51 2007 -0800 [PATCH] sched: avoid div in rebalance_tick Avoid expensive integer divide 3 times per CPU per tick. A userspace test of this loop went from 26ns, down to 19ns on a G5; and from 123ns down to 28ns on a P3. (Also avoid a variable bit shift, as suggested by Alan. The effect of this wasn't noticable on the CPUs I tested with). Signed-off-by: Nick Piggin Cc: Ingo Molnar Cc: Alan Cox Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit 0a9ac38246b11892ad20a1eb9deb67adf8c0db2f Author: Michael Halcrow Date: Mon Feb 12 00:53:50 2007 -0800 [PATCH] eCryptfs: add flush_dcache_page() calls Call flush_dcache_page() after modifying a pagecache by hand. Signed-off-by: Michael Halcrow Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit e2bd99ec5c0e20ed6aeb079fa8f975c2dcd78a2c Author: Michael Halcrow Date: Mon Feb 12 00:53:49 2007 -0800 [PATCH] eCryptfs: open-code flag checking and manipulation Open-code flag checking and manipulation. Signed-off-by: Michael Halcrow Signed-off-by: Trevor Highland Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit 9d8b8ce5561890464c54645cdea4d6b157159fec Author: Michael Halcrow Date: Mon Feb 12 00:53:48 2007 -0800 [PATCH] eCryptfs: convert kmap() to kmap_atomic() Replace kmap() with kmap_atomic(). Reduce the amount of time that mappings are held. Signed-off-by: Michael Halcrow Signed-off-by: Trevor Highland Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit 70456600f42f85cfcbdd9d7a6029c03b6f9c5d1e Author: Michael Halcrow Date: Mon Feb 12 00:53:48 2007 -0800 [PATCH] eCryptfs: convert f_op->write() to vfs_write() sys_write() takes a local copy of f_pos and writes that back into the struct file. It does this so that two concurrent write() callers don't make a mess of f_pos, and of the file contents. ecryptfs should be calling vfs_write(). That way we also get the fsnotify notifications, which ecryptfs presently appears to have subverted. Convert direct calls to f_op->write() into calls to vfs_write(). Signed-off-by: Michael Halcrow Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit e77a56ddceeec87575a13a60fc1a394af6a1f4bc Author: Michael Halcrow Date: Mon Feb 12 00:53:47 2007 -0800 [PATCH] eCryptfs: Encrypted passthrough Provide an option to provide a view of the encrypted files such that the metadata is always in the header of the files, regardless of whether the metadata is actually in the header or in the extended attribute. This mode of operation is useful for applications like incremental backup utilities that do not preserve the extended attributes when directly accessing the lower files. With this option enabled, the files under the eCryptfs mount point will be read-only. Signed-off-by: Michael Halcrow Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit dd2a3b7ad98f8482cae481cad89dfed5eee48365 Author: Michael Halcrow Date: Mon Feb 12 00:53:46 2007 -0800 [PATCH] eCryptfs: Generalize metadata read/write Generalize the metadata reading and writing mechanisms, with two targets for now: metadata in file header and metadata in the user.ecryptfs xattr of the lower file. [akpm@osdl.org: printk warning fix] [bunk@stusta.de: make some needlessly global code static] Signed-off-by: Michael Halcrow Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit 17398957aa0a05ef62535060b41d103590dcc533 Author: Michael Halcrow Date: Mon Feb 12 00:53:45 2007 -0800 [PATCH] eCryptfs: xattr flags and mount options This patch set introduces the ability to store cryptographic metadata into an lower file extended attribute rather than the lower file header region. This patch set implements two new mount options: ecryptfs_xattr_metadata - When set, newly created files will have their cryptographic metadata stored in the extended attribute region of the file rather than the header. When storing the data in the file header, there is a minimum of 8KB reserved for the header information for each file, making each file at least 12KB in size. This can take up a lot of extra disk space if the user creates a lot of small files. By storing the data in the extended attribute, each file will only occupy at least of 4KB of space. As the eCryptfs metadata set becomes larger with new features such as multi-key associations, most popular filesystems will not be able to store all of the information in the xattr region in some cases due to space constraints. However, the majority of users will only ever associate one key per file, so most users will be okay with storing their data in the xattr region. This option should be used with caution. I want to emphasize that the xattr must be maintained under all circumstances, or the file will be rendered permanently unrecoverable. The last thing I want is for a user to forget to set an xattr flag in a backup utility, only to later discover that their backups are worthless. ecryptfs_encrypted_view - When set, this option causes eCryptfs to present applications a view of encrypted files as if the cryptographic metadata were stored in the file header, whether the metadata is actually stored in the header or in the extended attributes. No matter what eCryptfs winds up doing in the lower filesystem, I want to preserve a baseline format compatibility for the encrypted files. As of right now, the metadata may be in the file header or in an xattr. There is no reason why the metadata could not be put in a separate file in future versions. Without the compatibility mode, backup utilities would have to know to back up the metadata file along with the files. The semantics of eCryptfs have always been that the lower files are self-contained units of encrypted data, and the only additional information required to decrypt any given eCryptfs file is the key. That is what has always been emphasized about eCryptfs lower files, and that is what users expect. Providing the encrypted view option will provide a way to userspace applications wherein they can always get to the same old familiar eCryptfs encrypted files, regardless of what eCryptfs winds up doing with the metadata behind the scenes. This patch: Add extended attribute support to version bit vector, flags to indicate when xattr or encrypted view modes are enabled, and support for the new mount options. Signed-off-by: Michael Halcrow Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit dddfa461fc8951f9b5f951c13565b6cac678635a Author: Michael Halcrow Date: Mon Feb 12 00:53:44 2007 -0800 [PATCH] eCryptfs: Public key; packet management Public key support code. This reads and writes packets in the header that contain public key encrypted file keys. It calls the messaging code in the previous patch to send and receive encryption and decryption request packets from the userspace daemon. [akpm@osdl.org: cleab fix] Signed-off-by: Michael Halcrow Cc: David Howells Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit 88b4a07e6610f4c93b08b0bb103318218db1e9f6 Author: Michael Halcrow Date: Mon Feb 12 00:53:43 2007 -0800 [PATCH] eCryptfs: Public key transport mechanism This is the transport code for public key functionality in eCryptfs. It manages encryption/decryption request queues with a transport mechanism. Currently, netlink is the only implemented transport. Each inode has a unique File Encryption Key (FEK). Under passphrase, a File Encryption Key Encryption Key (FEKEK) is generated from a salt/passphrase combo on mount. This FEKEK encrypts each FEK and writes it into the header of each file using the packet format specified in RFC 2440. This is all symmetric key encryption, so it can all be done via the kernel crypto API. These new patches introduce public key encryption of the FEK. There is no asymmetric key encryption support in the kernel crypto API, so eCryptfs pushes the FEK encryption and decryption out to a userspace daemon. After considering our requirements and determining the complexity of using various transport mechanisms, we settled on netlink for this communication. eCryptfs stores authentication tokens into the kernel keyring. These tokens correlate with individual keys. For passphrase mode of operation, the authentication token contains the symmetric FEKEK. For public key, the authentication token contains a PKI type and an opaque data blob managed by individual PKI modules in userspace. Each user who opens a file under an eCryptfs partition mounted in public key mode must be running a daemon. That daemon has the user's credentials and has access to all of the keys to which the user should have access. The daemon, when started, initializes the pluggable PKI modules available on the system and registers itself with the eCryptfs kernel module. Userspace utilities register public key authentication tokens into the user session keyring. These authentication tokens correlate key signatures with PKI modules and PKI blobs. The PKI blobs contain PKI-specific information necessary for the PKI module to carry out asymmetric key encryption and decryption. When the eCryptfs module parses the header of an existing file and finds a Tag 1 (Public Key) packet (see RFC 2440), it reads in the public key identifier (signature). The asymmetrically encrypted FEK is in the Tag 1 packet; eCryptfs puts together a decrypt request packet containing the signature and the encrypted FEK, then it passes it to the daemon registered for the current->euid via a netlink unicast to the PID of the daemon, which was registered at the time the daemon was started by the user. The daemon actually just makes calls to libecryptfs, which implements request packet parsing and manages PKI modules. libecryptfs grabs the public key authentication token for the given signature from the user session keyring. This auth tok tells libecryptfs which PKI module should receive the request. libecryptfs then makes a decrypt() call to the PKI module, and it passes along the PKI block from the auth tok. The PKI uses the blob to figure out how it should decrypt the data passed to it; it performs the decryption and passes the decrypted data back to libecryptfs. libecryptfs then puts together a reply packet with the decrypted FEK and passes that back to the eCryptfs module. The eCryptfs module manages these request callouts to userspace code via message context structs. The module maintains an array of message context structs and places the elements of the array on two lists: a free and an allocated list. When eCryptfs wants to make a request, it moves a msg ctx from the free list to the allocated list, sets its state to pending, and fires off the message to the user's registered daemon. When eCryptfs receives a netlink message (via the callback), it correlates the msg ctx struct in the alloc list with the data in the message itself. The msg->index contains the offset of the array of msg ctx structs. It verifies that the registered daemon PID is the same as the PID of the process that sent the message. It also validates a sequence number between the received packet and the msg ctx. Then, it copies the contents of the message (the reply packet) into the msg ctx struct, sets the state in the msg ctx to done, and wakes up the process that was sleeping while waiting for the reply. The sleeping process was whatever was performing the sys_open(). This process originally called ecryptfs_send_message(); it is now in ecryptfs_wait_for_response(). When it wakes up and sees that the msg ctx state was set to done, it returns a pointer to the message contents (the reply packet) and returns. If all went well, this packet contains the decrypted FEK, which is then copied into the crypt_stat struct, and life continues as normal. The case for creation of a new file is very similar, only instead of a decrypt request, eCryptfs sends out an encrypt request. > - We have a great clod of key mangement code in-kernel. Why is that > not suitable (or growable) for public key management? eCryptfs uses Howells' keyring to store persistent key data and PKI state information. It defers public key cryptographic transformations to userspace code. The userspace data manipulation request really is orthogonal to key management in and of itself. What eCryptfs basically needs is a secure way to communicate with a particular daemon for a particular task doing a syscall, based on the UID. Nothing running under another UID should be able to access that channel of communication. > - Is it appropriate that new infrastructure for public key > management be private to a particular fs? The messaging.c file contains a lot of code that, perhaps, could be extracted into a separate kernel service. In essence, this would be a sort of request/reply mechanism that would involve a userspace daemon. I am not aware of anything that does quite what eCryptfs does, so I was not aware of any existing tools to do just what we wanted. > What happens if one of these daemons exits without sending a quit > message? There is a stale uid<->pid association in the hash table for that user. When the user registers a new daemon, eCryptfs cleans up the old association and generates a new one. See ecryptfs_process_helo(). > - _why_ does it use netlink? Netlink provides the transport mechanism that would minimize the complexity of the implementation, given that we can have multiple daemons (one per user). I explored the possibility of using relayfs, but that would involve having to introduce control channels and a protocol for creating and tearing down channels for the daemons. We do not have to worry about any of that with netlink. Signed-off-by: Michael Halcrow Cc: David Howells Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit b5d5dfbd59577aed72263f22e28d3eaf98e1c6e5 Author: Adrian Bunk Date: Mon Feb 12 00:53:40 2007 -0800 [PATCH] include/linux/nfsd/const.h: remove NFS_SUPER_MAGIC NFS_SUPER_MAGIC is already defined in include/linux/magic.h Signed-off-by: Adrian Bunk Cc: Neil Brown Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit 77f1f67a1a56defa210c3d8857f3e5eee3990a99 Author: Chuck Lever Date: Mon Feb 12 00:53:39 2007 -0800 [PATCH] knfsd: SUNRPC: fix up svc_create_socket() to take a sockaddr struct + length Replace existing svc_create_socket() API to allow callers to pass addresses larger than a sockaddr_in. Signed-off-by: Chuck Lever Cc: Aurelien Charbon Signed-off-by: Neil Brown Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit 95756482c9bfa375418c5a32455494a3042f65cd Author: Chuck Lever Date: Mon Feb 12 00:53:38 2007 -0800 [PATCH] knfsd: SUNRPC: support IPv6 addresses in RPC server's UDP receive path Add support for IPv6 addresses in the RPC server's UDP receive path. [akpm@linux-foundation.org: cleanups] Signed-off-by: Chuck Lever Cc: Aurelien Charbon Signed-off-by: Neil Brown Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit cdd88b9f3ed5013de0f1085e0e2f9123c798609d Author: akpm@linux-foundation.org Date: Mon Feb 12 00:53:38 2007 -0800 [PATCH] knfsd: SUNRPC: Support IPv6 addresses in svc_tcp_accept Modify svc_tcp_accept to support connecting on IPv6 sockets. Signed-off-by: Chuck Lever Cc: Aurelien Charbon Signed-off-by: Neil Brown Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit bcdb81ae29091f6a66369aabfd8324e4a53d05dc Author: Chuck Lever Date: Mon Feb 12 00:53:37 2007 -0800 [PATCH] knfsd: SUNRPC: add a "generic" function to see if the peer uses a secure port The only reason svcsock.c looks at a sockaddr's port is to check whether the remote peer is connecting from a privileged port. Refactor this check to hide processing that is specific to address format. Signed-off-by: Chuck Lever Cc: Aurelien Charbon Signed-off-by: Neil Brown Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit b92503b25c3f794cff5f96626ea3ecba8d10d254 Author: Chuck Lever Date: Mon Feb 12 00:53:36 2007 -0800 [PATCH] knfsd: SUNRPC: teach svc_sendto() to deal with IPv6 addresses CMSG_DATA comes in different sizes, depending on address family. [akpm@linux-foundation.org: remove unneeded do/while (0)] Signed-off-by: Chuck Lever Cc: Aurelien Charbon Signed-off-by: Neil Brown Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit 73df0dbaff8d0853387e140f52b6250c486b18a1 Author: Chuck Lever Date: Mon Feb 12 00:53:35 2007 -0800 [PATCH] knfsd: SUNRPC: Make rq_daddr field address-version independent The rq_daddr field must support larger addresses. Signed-off-by: Chuck Lever Cc: Aurelien Charbon Signed-off-by: Neil Brown Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit 27459f0940e16c68e080f5fc7e85aa9eb3f74528 Author: Chuck Lever Date: Mon Feb 12 00:53:34 2007 -0800 [PATCH] knfsd: SUNRPC: Provide room in svc_rqst for larger addresses Expand the rq_addr field to allow it to contain larger addresses. Specifically, we replace a 'sockaddr_in' with a 'sockaddr_storage', then everywhere the 'sockaddr_in' was referenced, we use instead an accessor function (svc_addr_in) which safely casts the _storage to _in. Signed-off-by: Chuck Lever Cc: Aurelien Charbon Signed-off-by: Neil Brown Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit 2442222283918c2d1c20ae651d95fe168757938b Author: Chuck Lever Date: Mon Feb 12 00:53:33 2007 -0800 [PATCH] knfsd: SUNRPC: Use sockaddr_storage to store address in svc_deferred_req Sockaddr_storage will allow us to store arbitrary socket addresses in the svc_deferred_req struct. Signed-off-by: Chuck Lever Cc: Aurelien Charbon Signed-off-by: Neil Brown Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit ad06e4bd62351bc569cca0f25d68c58dbd298146 Author: Chuck Lever Date: Mon Feb 12 00:53:32 2007 -0800 [PATCH] knfsd: SUNRPC: Add a function to format the address in an svc_rqst for printing There are loads of places where the RPC server assumes that the rq_addr fields contains an IPv4 address. Top among these are error and debugging messages that display the server's IP address. Let's refactor the address printing into a separate function that's smart enough to figure out the difference between IPv4 and IPv6 addresses. Signed-off-by: Chuck Lever Cc: Aurelien Charbon Signed-off-by: Neil Brown Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit 1ba951053f07187f6e77be664a4b6f8bf0ba7ae4 Author: Chuck Lever Date: Mon Feb 12 00:53:31 2007 -0800 [PATCH] knfsd: SUNRPC: Don't set msg_name and msg_namelen when calling sock_recvmsg Clean-up: msg_name and msg_namelen are not used by sock_recvmsg, so don't bother to set them in svc_recvfrom. Signed-off-by: Chuck Lever Signed-off-by: Neil Brown Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit 067d7817310569f7b76ca08c4d071ca95ad4c1d3 Author: Chuck Lever Date: Mon Feb 12 00:53:30 2007 -0800 [PATCH] knfsd: SUNRPC: Cache remote peer's address in svc_sock The remote peer's address won't change after the socket has been accepted. We don't need to call ->getname on every incoming request. Signed-off-by: Chuck Lever Cc: Aurelien Charbon Signed-off-by: Neil Brown Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit e79eff1f90826b207b1152fc87aa97fa74fb7f9c Author: NeilBrown Date: Mon Feb 12 00:53:30 2007 -0800 [PATCH] knfsd: SUNRPC: aplit svc_sock_enqueue out of svc_setup_socket Rather than calling svc_sock_enqueue at the end of svc_setup_socket, we now call it (via svc_sock_recieved) after calling svc_setup_socket at each call site. We do this because a subsequent patch will insert some code between the two calls at one call site. Signed-off-by: Neil Brown Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit 482fb94e1b0c2efe8258334aa2a68d4f4a91de9c Author: Chuck Lever Date: Mon Feb 12 00:53:29 2007 -0800 [PATCH] knfsd: SUNRPC: allow creating an RPC service without registering with portmapper Sometimes we need to create an RPC service but not register it with the local portmapper. NFSv4 delegation callback, for example. Change the svc_makesock() API to allow optionally creating temporary or permanent sockets, optionally registering with the local portmapper, and make it return the ephemeral port of the new socket. Signed-off-by: Chuck Lever Cc: Aurelien Charbon Signed-off-by: Neil Brown Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit 6b174337e5126de834a971d3edc3681bbfa45e2c Author: Chuck Lever Date: Mon Feb 12 00:53:28 2007 -0800 [PATCH] knfsd: SUNRPC: update internal API: separate pmap register and temp sockets Currently in the RPC server, registering with the local portmapper and creating "permanent" sockets are tied together. Expand the internal APIs to allow these two socket characteristics to be separately specified. This will be externalized in the next patch. Signed-off-by: Chuck Lever Cc: Aurelien Charbon Signed-off-by: Neil Brown Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit f85aaeba458fda1de199a73566c641516e9a935d Author: Ahmed S. Darwish Date: Mon Feb 12 00:53:27 2007 -0800 [PATCH] isdn-eicon: Use ARRAY_SIZE macro when appropriate Use ARRAY_SIZE macro already defined in kernel.h Signed-off-by: Ahmed S. Darwish Cc: Karsten Keil Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit 053b47ff249b9e0a634dae807f81465205e7c228 Author: Michael Buesch Date: Mon Feb 12 00:53:26 2007 -0800 [PATCH] Workaround CAPI subsystem locking issue I think the following patch should go into the kernel, until the ISDN/CAPI guys create the real fix for this issue. The issue is a concurrency issue with some internal CAPI data structure which can crash the kernel. On my FritzCard DSL with the AVM driver it crashes about once a day without this workaround patch. With this workaround patch it's rock-stable (at least on UP, but I don't see why this shouldn't work on SMP as well. But maybe I'm missing something.) This workaround is kind of a sledgehammer which inserts a global lock to wrap around all the critical sections. Of course, this is a scalability issue, if you have many ISDN/CAPI cards. But it prevents a crash. So I vote for this fix to get merged, until people come up with a better solution. Better have a stable kernel that's less scalable, than a crashing and useless kernel. This bug is in the kernel since 2.6.15 (at least). Signed-off-by: Michael Buesch Cc: Kai Germaschewski Cc: Karsten Keil Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit a871fe858c5437ff8798fbaef52b6a88110b64a1 Author: Richard Knutsson Date: Mon Feb 12 00:53:25 2007 -0800 [PATCH] drivers/isdn/hisax/: Convert to generic boolean-values Signed-off-by: Richard Knutsson Acked-by: Karsten Keil Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit 986c4bb8c4a7bf248378954782553334a003d80a Author: Richard Knutsson Date: Mon Feb 12 00:53:24 2007 -0800 [PATCH] drivers/isdn/hardware/eicon/: convert to generic boolean-values Signed-off-by: Richard Knutsson Acked-by: Karsten Keil Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit 2a8081f99cd2b1f356c1d07c75f5c386c2e54efc Author: Robert P. J. Day Date: Mon Feb 12 00:53:23 2007 -0800 [PATCH] ISDN: Rename special macro CONFIG_HISAX_HFC4S8S_PCIMEM Rename the macro CONFIG_HISAX_HFC4S8S_PCIMEM to simply HISAX_HFC4S8S_PCIMEM so that it no longer resembles a user-settable kernel config macro. Signed-off-by: Robert P. J. Day Acked-by: Karsten Keil Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit f0d8737bf741181aa6a452cffe3b9c074afa0cc1 Author: Robert P. J. Day Date: Mon Feb 12 00:53:22 2007 -0800 [PATCH] ISDN: Remove defunct test emulator Based on advice from K. Keil, get rid of remaining traces of defunct test emulator for HISAX. Signed-off-by: Robert P. J. Day Acked-by: Karsten Keil Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit e3c07b9615ee123113de2e881143eb74442d3bf5 Author: Robert P. J. Day Date: Mon Feb 12 00:53:21 2007 -0800 [PATCH] ISDN: Rename debug option CONFIG_SERIAL_NOPAUSE_IO Based on advice from K. Keil, rename the special debug option CONFIG_SERIAL_NOPAUSE_IO to ELSA_SERIAL_NOPAUSE_IO so it no longer resembles a user-selectable kernel config option. Signed-off-by: Robert P. J. Day Acked-by: Karsten Keil Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit 26fb5c5810afa0d8209ceff7cb267398be53829d Author: Robert P. J. Day Date: Mon Feb 12 00:53:20 2007 -0800 [PATCH] ISDN: Rename some debugging macros to not resemble CONFIG options Rename some of the debugging macros for ISDN AVM so that they don't resemble kernel config settings, as they're primarily for author debugging instead. Signed-off-by: Robert P. J. Day Acked-by: Karsten Keil Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit e3f2769e6e896a5d734593e4842014cab220d027 Author: Robert P. J. Day Date: Mon Feb 12 00:53:19 2007 -0800 [PATCH] ISDN: Fix typo "CONFIG_HISAX_QUADRO" -> "CONFIG_HISAX_SCT_QUADRO". Replace misspelled CONFIG_HISAX_QUADRO with CONFIG_HISAX_SCT_QUADRO. Signed-off-by: Robert P. J. Day Acked-by: Karsten Keil Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit fd863db937c0d30679d4bd5329653adb46b66627 Author: Ahmed S. Darwish Date: Mon Feb 12 00:53:19 2007 -0800 [PATCH] isdn/capi: use ARRAY_SIZE when appropriate Signed-off-by: Ahmed S. Darwish Acked-by: Karsten Keil Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit fc238b3791447b93c69cd50a99dfcaad6162afba Author: Adrian Bunk Date: Mon Feb 12 00:53:18 2007 -0800 [PATCH] drivers/isdn/sc/: proper prototypes Add proper prototypes in a header file for global code under drivers/isdn/sc/. Since the GNU C compiler is now able do tell us that caller and callee disagreed about the number of arguments of setup_buffers(), this patch also fixes this bug. Signed-off-by: Adrian Bunk Cc: Karsten Keil Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit b19a8f0472cf2fc401c47f585fcd42e770124e06 Author: Adrian Bunk Date: Mon Feb 12 00:53:17 2007 -0800 [PATCH] drivers/isdn/hisax/: proper prototypes - add functions prototypes for some global functions to header files - remove unneeded "extern"s from some function prototypes You might note that this patch results in a new warning - that's due to the fact that with a proper prototype gcc is able to discover a broken work_struct conversion. Signed-off-by: Adrian Bunk Cc: Karsten Keil Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit 010046d0c805ac3bfab1740f4a056af70b84ea46 Author: Adrian Bunk Date: Mon Feb 12 00:53:16 2007 -0800 [PATCH] drivers/isdn/pcbit/: proper prototypes Add correct prototypes in header files for global functions and variables. Signed-off-by: Adrian Bunk Cc: Karsten Keil Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit 390414badebe45a2f556a04ece1fd99191aa6397 Author: Philipp Zabel Date: Mon Feb 12 00:53:15 2007 -0800 [PATCH] S3C2410 GPIO wrappers Arch-neutral GPIO calls for S3C24xx. Signed-off-by: David Brownell Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit 920fe7a8d0aba9782d1f924a02ece146acbf6686 Author: Philipp Zabel Date: Mon Feb 12 00:53:14 2007 -0800 [PATCH] SA1100 GPIO wrappers Arch-neutral GPIO calls for SA-1100. Signed-off-by: David Brownell Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit 8a898f1c366c858f8dbcb667c1cfcc282b727795 Author: Philipp Zabel Date: Mon Feb 12 00:53:14 2007 -0800 [PATCH] PXA GPIO wrappers Arch-neutral GPIO calls for PXA. Signed-off-by: David Brownell Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit a31c4eea2127ee52b5c7c1befada4664963ad030 Author: David Brownell Date: Mon Feb 12 00:53:13 2007 -0800 [PATCH] AT91 GPIO wrappers This is a first cut at making the AT91 code use the generic GPIO calls. Note that the original AT91 GPIO calls merged the "mux pin as GPIO" and "set GPIO direction" functionality into one API call, contrary to what's specified as a cross-platform portable model. So this involved a few non-inlinable functions. [akpm@osdl.org: cleanups] Signed-off-by: David Brownell Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit 3c729f1ecd23b86a2d6b211d646f57f9da8dfeb1 Author: David Brownell Date: Mon Feb 12 00:53:12 2007 -0800 [PATCH] OMAP GPIO wrappers This teaches OMAP how to implement the cross-platform GPIO interfaces. [akpm@osdl.org: cleanups] Signed-off-by: David Brownell Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit 4c20386c8d0719b42503efe65abe47ad3fb3d711 Author: David Brownell Date: Mon Feb 12 00:53:11 2007 -0800 [PATCH] GPIO core This defines a simple and minimalist programming interface for GPIO APIs: - Documentation/gpio.txt ... describes things (read it) - include/asm-arm/gpio.h ... defines the ARM hook, which just punts to for any implementation - include/asm-generic/gpio.h ... implement "can sleep" variants as calling the normal ones, for systems that don't handle i2c expanders. The immediate need for such a cross-architecture API convention is to support drivers that work the same on AT91 ARM and AVR32 AP7000 chips, which embed many of the same controllers but have different CPUs. However, several other users have been reported, including a driver for a hardware watchdog chip and some handhelds.org multi-CPU button drivers. Signed-off-by: David Brownell Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit 9794f33ddedd878dd92fcf8b4834391840366919 Author: eric wollesen Date: Mon Feb 12 00:53:08 2007 -0800 [PATCH] EDAC: Add Fully-Buffered DIMM APIs to core Eric Wollesen ported the Bluesmoke Memory Controller driver for the Intel 5000X/V/P (Blackford/Greencreek) chipset to the in kernel EDAC model. This patch incorporates those required changes to the edac_mc.c and edac_mc.h core files by added new Fully Buffered DIMM interface to the EDAC Core module. Signed-off-by: eric wollesen Signed-off-by: doug thompson Acked-by: Alan Cox Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit 4f423ddf56e5ecb1fb2eac83b8e228e3d0aae0f6 Author: Frithiof Jensen Date: Mon Feb 12 00:53:07 2007 -0800 [PATCH] EDAC: Add memory scrubbing controls API to core This is an attempt of providing an interface for memory scrubbing control in EDAC. This patch modifies the EDAC Core to provide the Interface for memory controller modules to implment. The following things are still outstanding: - K8 is the first implemenation, The patch provide a method of configuring the K8 hardware memory scrubber via the 'mcX' sysfs directory. There should be some fallback to a generic scrubber implemented in software if the hardware does not support scrubbing. Or .. the scrubbing sysfs entry should not be visible at all. - Only works with SDRAM, not cache, The K8 can scrub cache and l2cache also - but I think this is not so useful as the cache is busy all the time (one hopes). One would also expect that cache scrubbing requires hardware support. - Error Handling, I would like that errors are returned to the user in "terms of file system". - Presentation, I chose Bandwidth in Bytes/Second as a representation of the scrubbing rate for the following reasons: I like that the sysfs entries are sort-of textual, related to something that makes sense instead of magical values that must be looked up. "My People" wants "% main memory scrubbed per hour" others prefer "% memory bandwidth used" as representation, "bandwith used" makes it easy to calculate both versions in one-liner scripts. If one later wants to scrub cache, the scaling becomes wierd for K8 changing from "blocks of 64 byte memory" to "blocks of 64 cache lines" to "blocks of 64 bit". Using "bandwidth used" makes sense in all three cases, (I.M.O. anyway ;-). - Discovery, There is no way to discover the possible settings and what they do without reading the code and the documentation. *I* do not know how to make that work in a practical way. - Bugs(??), other tools can set invalid values in the memory scrub control register, those will read back as '-1', requiring the user to reset the scrub rate. This is how *I* think it should be. - Afflicting other areas of code, I made changes to edac_mc.c and edac_mc.h which will show up globally - this is not nice, it would be better that the memory scrubbing fuctionality and interface could be entirely contained within the memory controller it applies to. Frithiof Jensen edac_mc.c and its .h file is a CORE helper module for EDAC driver modules. This provides the abstraction for device specific drivers. It is fine to modify this CORE to provide help for new features of the the drivers doug thompson Signed-off-by: Frithiof Jensen Signed-off-by: doug thompson Acked-by: Alan Cox Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit 84db003f249ddbcde1666376b4e3bbe9ee2c7c0c Author: Mike Chan Date: Mon Feb 12 00:53:06 2007 -0800 [PATCH] EDAC: Fix in e752x mc driver This fix/change returns the offset into the page for the ce/ue error, instead of just 0. The e752x dram controller reads 34:6 of the linear address with the error. Signed-off-by: Mike Chan Signed-off-by: doug thompson Acked-by: Alan Cox Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit 9962fd017becf944d671da498ccaaea570452206 Author: Brian Pomerantz Date: Mon Feb 12 00:53:05 2007 -0800 [PATCH] EDAC: e752x byte access fix The reading of the DRA registers should be a byte at a time (one register at a time) instead of 4 bytes at a time (four registers). Reading a dword at a time retrieves erroneous information from all but the first register. A change was made to read in each register in a loop prior to using the data in those registers. Signed-off-by: Brian Pomerantz Signed-off-by: Dave Jiang Signed-off-by: Doug Thompson Cc: Alan Cox Cc: Andi Kleen Cc: "Eric W. Biederman" Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit dfb2a76378f095b0aaa2024ce9a8cfb2ae2354d2 Author: Brian Pomerantz Date: Mon Feb 12 00:53:03 2007 -0800 [PATCH] EDAC: e752x bit mask fix The fatal vs. non-fatal mask for the sysbus FERR status is incorrect according to the E7520 datasheet. This patch corrects the mask to correctly handle fatal and non-fatal errors. Signed-off-by: Brian Pomerantz Signed-off-by: Dave Jiang Signed-off-by: Doug Thompson Cc: Alan Cox Cc: Andi Kleen Cc: "Eric W. Biederman" Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit 27b0b2f44adffe0193a695bb528a83b550b8e54b Author: Eric W. Biederman Date: Mon Feb 12 00:53:02 2007 -0800 [PATCH] pid: remove the now unused kill_pg kill_pg_info and __kill_pg_info Now that I have changed all of the in-tree users remove the old version of these functions. This should make it clear to any out of tree users that they should be using kill_pgrp kill_pgrp_info or __kill_pgrp_info instead. Signed-off-by: Eric W. Biederman Cc: Alan Cox Cc: Oleg Nesterov Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit 9f57a54b6cf3f626334d97e93b5b917ad11e1efc Author: Eric W. Biederman Date: Mon Feb 12 00:53:02 2007 -0800 [PATCH] pid: remove now unused do_each_task_pid and while_each_task_pid Now that I have changed all of the users remove the old version of these functions. This should be a clear hint to any out of tree users that they should use do_each_pid_task and while_each_pid_task for new code. Signed-off-by: Eric W. Biederman Cc: Alan Cox Cc: Oleg Nesterov Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit 41487c65bfcce9c8e4d123da1719fcfd8df6d4d0 Author: Eric W. Biederman Date: Mon Feb 12 00:53:01 2007 -0800 [PATCH] pid: replace do/while_each_task_pid with do/while_each_pid_task There isn't any real advantage to this change except that it allows the old functions to be removed. Which is easier on maintenance and puts the code in a more uniform style. Signed-off-by: Eric W. Biederman Cc: Alan Cox Cc: Oleg Nesterov Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit ab521dc0f8e117fd808d3e425216864d60390500 Author: Eric W. Biederman Date: Mon Feb 12 00:53:00 2007 -0800 [PATCH] tty: update the tty layer to work with struct pid Of kernel subsystems that work with pids the tty layer is probably the largest consumer. But it has the nice virtue that the assiation with a session only lasts until the session leader exits. Which means that no reference counting is required. So using struct pid winds up being a simple optimization to avoid hash table lookups. In the long term the use of pid_nr also ensures that when we have multiple pid spaces mixed everything will work correctly. Signed-off-by: Eric W. Biederman Cc: Alan Cox Cc: Oleg Nesterov Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit 3e7cd6c413c9e6fbb5e1ee2acdadb4ababd2d474 Author: Eric W. Biederman Date: Mon Feb 12 00:52:58 2007 -0800 [PATCH] pid: replace is_orphaned_pgrp with is_current_pgrp_orphaned Every call to is_orphaned_pgrp passed in process_group(current) which is racy with respect to another thread changing our process group. It didn't bite us because we were dealing with integers and the worse we would get would be a stale answer. In switching the checks to use struct pid to be a little more efficient and prepare the way for pid namespaces this race became apparent. So I simplified the calls to the more specialized is_current_pgrp_orphaned so I didn't have to worry about making logic changes to avoid the race. Signed-off-by: Eric W. Biederman Cc: Alan Cox Cc: Oleg Nesterov Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit 0475ac0845f9295bc5f69af45f58dff2c104c8d1 Author: Eric W. Biederman Date: Mon Feb 12 00:52:57 2007 -0800 [PATCH] pid: use struct pid for talking about process groups in exitc Modify has_stopped_jobs and will_become_orphan_pgrp to use struct pid based process groups. This reduces the number of hash tables looks ups and paves the way for multiple pid spaces. Signed-off-by: Eric W. Biederman Cc: Alan Cox Cc: Oleg Nesterov Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit 04a2e6a5cbf84e85fe86de0a18f6509b147e1d89 Author: Eric W. Biederman Date: Mon Feb 12 00:52:56 2007 -0800 [PATCH] pid: make session_of_pgrp use struct pid instead of pid_t To properly implement a pid namespace I need to deal exclusively in terms of struct pid, because pid_t values become ambiguous. To this end session_of_pgrp is transformed to take and return a struct pid pointer. To avoid the need to worry about reference counting I now require my caller to hold the appropriate locks. Leaving callers repsonsible for increasing the reference count if they need access to the result outside of the locks. Since session_of_pgrp currently only has one caller and that caller simply uses only test the result for equality with another process group, the locking change means I don't actually have to acquire the tasklist_lock at all. tiocspgrp is also modified to take and release the lock. The logic there is a little more complicated but nothing I won't need when I convert pgrp of a tty to a struct pid pointer. Signed-off-by: Eric W. Biederman Cc: Alan Cox Cc: Oleg Nesterov Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit 8d42db189ca99703f0f4f91c477cb54808c8eaaa Author: Eric W. Biederman Date: Mon Feb 12 00:52:55 2007 -0800 [PATCH] signal: rewrite kill_something_info so it uses newer helpers The goal is to remove users of the old signal helper functions so they can be removed. Signed-off-by: Eric W. Biederman Cc: Alan Cox Cc: Oleg Nesterov Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit 0e25338bc11fa8e41e44e4db5b5101e3d882dc5b Author: Eric W. Biederman Date: Mon Feb 12 00:52:54 2007 -0800 [PATCH] signal: use kill_pgrp not kill_pg in the sunos compatibility code I am slowly moving to a model where all process killing is struct pid based instead of pid_t based. The sunos compatibility code is one of the last users of the old pid_t based kill_pg in the kernel. By being complete I allow for the future removal of kill_pg from the kernel, which will ensure I don't miss something. Signed-off-by: Eric W. Biederman Cc: Alan Cox Cc: Oleg Nesterov Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit 2ea81868d8fba0bb56d7b45a08cc5f15dd2c6bb2 Author: Eric W. Biederman Date: Mon Feb 12 00:52:53 2007 -0800 [PATCH] tty: fix the locking for signal->session in disassociate_ctty commit 24ec839c431eb79bb8f6abc00c4e1eb3b8c4d517 while fixing the locking for signal->tty got the locking wrong for signal->session. This places our accesses of signal->session back under the tasklist_lock where they belong. Signed-off-by: Eric W. Biederman Cc: Alan Cox Cc: Oleg Nesterov Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit 680a96710041c3c25464b5e093b80ca43cb94f52 Author: Eric W. Biederman Date: Mon Feb 12 00:52:52 2007 -0800 [PATCH] tty: clarify disassociate_ctty The code to look at tty_old_pgrp and send SIGHUP and SIGCONT when it is present only executes when disassociate_ctty is called from do_exit. Make this clear by adding an explict on_exit check, and explicitly setting tty_old_pgrp to 0. In addition fix the locking by reading tty_old_pgrp under the siglock. Signed-off-by: Eric W. Biederman Cc: Alan Cox Cc: Oleg Nesterov Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit cdc623300841bc8f1625c320d5a6cbc52c43c60d Author: Eric W. Biederman Date: Mon Feb 12 00:52:51 2007 -0800 [PATCH] tty: make __proc_set_tty static The aim of this patch set is to start wrapping up the struct pid conversions. As such this patchset culminates with the removal of kill_pg, kill_pg_info, __kill_pg_info, do_each_task_pid, and while_each_task_pid. kill_proc, daemonize, and kernel_thread are still in my sights but there is still work to get to them. The first three are basic cleanups around disassociate_ctty, while working on converting it I found several issues. tty_old_pgrp can be a tricky concept to wrap your head around. 1 tty: Make __proc_set_tty static. 2 tty: Clarify disassociate_ctty 3 tty: Fix the locking for signal->session in disassociate_ctty These just stop using the old helper functions. 4 signal: Use kill_pgrp not kill_pg in the sunos compatibility code. 5 signal: Rewrite kill_something_info so it uses newer helpers. Then the grind to convert the tty layer and all of it's helper functions to struct pid. 6 pid: Make session_of_pgrp use struct pid instead of pid_t. 7 pid: Use struct pid for talking about process groups in exit.c 8 pid: Replace is_orphaned_pgrp with is_current_pgrp_orphaned 9 tty: Update the tty layer to work with struct pid. A final helper function update. 10 pid: Replace do/while_each_task_pid with do/while_each_pid_task And the removal of the functions that are now unused. 11 pid: Remove now unused do_each_task_pid and while_each_task_pid 12 pid: Remove the now unused kill_pg kill_pg_info and __kill_pg_info All of these should be fairly simple and to the point. This patch: Currently all users of __proc_set_tty are in tty_io.c so make the function static. Signed-off-by: Eric W. Biederman Cc: Alan Cox Cc: Oleg Nesterov Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit 939b00df0306bc4b5cd25c3c3c78e89b91e72fc8 Author: Andries Brouwer Date: Mon Feb 12 00:52:49 2007 -0800 [PATCH] Minix V3 support This morning I needed to read a Minix V3 filesystem, but unfortunately my 2.6.19 did not support that, and neither did the downloaded 2.6.20rc4. Fortunately, google told me that Daniel Aragones had already done the work, patch found at http://www.terra.es/personal2/danarag/ Unfortunaly, looking at the patch was painful to my eyes, so I polished it a bit before applying. The resulting kernel boots, and reads the filesystem it needed to read. Signed-off-by: Daniel Aragones Signed-off-by: Andries Brouwer Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit b587b13a4f670ebae79ae6259cf44328455e4e69 Author: David Brownell Date: Mon Feb 12 00:52:48 2007 -0800 [PATCH] SPI eeprom driver This is adds a simple SPI EEPROM driver, providing access to the EEPROM through sysfs much like the I2C "eeprom" driver ... except this driver supports write access, and multiple EEPROM sizes. From: "Tuppa, Walter" Since I have EEPROMs on SPI with different address sizing, I made some changes to your at25.c to support them. Works perfectly. (Also includes a small bugfix for the "what size address" test.) Signed-off-by: David Brownell Signed-off-by: Walter Tuppa Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit 3925a5ce44330767f7f0de5c58c6a797009f0f75 Author: David Brownell Date: Mon Feb 12 00:52:47 2007 -0800 [PATCH] RTC gets sysfs wakealarm attribute This adds a new "wakealarm" sysfs attribute to RTC class devices which support alarm operations and are wakeup-capable: - It reads as either empty, or the scheduled alarm time as seconds since the POSIX epoch. (That time may already have passed, since nothing currently enforces one-shot alarm semantics.) - It can be written with an alarm time in the future, again seconds since the POSIX epoch, which enables the alarm. - It can be written with an alarm time not in the future (such as 0, the start of the POSIX epoch) to disable the alarm. Usage examples (some need GNU date) after "cd /sys/class/rtc/rtcN": alarm after 10 minutes: # echo $(( $(cat since_epoch) + 10 * 60 )) > wakealarm alarm tuesday evening 10pm: # date -d '10pm tuesday' "+%s" > wakealarm disable alarm: # echo 0 > wakealarm This resembles the /proc/acpi/alarm file in that nothing happens when the alarm triggers ... except possibly waking the system from sleep. It's also like that in a nasty way: not much can be done to prevent one task from clobbering another task's alarm settings. It differs from that file in that there's no in-kernel date parser. Note that a few RTCs ignore rtc_wkalrm.enabled when setting alarms, or aren't set up correctly, so they won't yet behave with this attribute. Signed-off-by: David Brownell Acked-by: Pavel Machek Cc: Alessandro Zummo Cc: Greg KH Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit 802245611adea5e5877d8c5d9a20f94d8131bfdd Author: David Brownell Date: Mon Feb 12 00:52:46 2007 -0800 [PATCH] SPI doc clarifications This clarifies some aspects of the SPI programming interface, based on feedback from Hans-Peter Nilsson. The in-memory representation of words is right-aligned, so for example a twelve bit word is stored using sixteen bits with four undefined bits in the MSB. And controller drivers must reject protocol tweaking modes they do not support. Signed-off-by: David Brownell Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit 0ffa0285052607513a29f529ddb5061c907fd8a6 Author: Hans-Peter Nilsson Date: Mon Feb 12 00:52:45 2007 -0800 [PATCH] SPI cleanup() method param becomes non-const I'd like to assign NULL to kfree()d members of a structure. I can't do that without ugly casting (see the PXA patch) when the structure pointed to is const-qualified. I don't really see a reason why the cleanup method isn't allowed to alter the object it should clean up. :-) No, I didn't test the PXA patch, but I verified that the NULL-assignment doesn't stop me from doing rmmod/insmodding my own spi_bitbang-based driver. Signed-off-by: Hans-Peter Nilsson Signed-off-by: David Brownell Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit 7f8c7619ea1ff5ab8e0b08c8120d629834ef4253 Author: Hans-Peter Nilsson Date: Mon Feb 12 00:52:44 2007 -0800 [PATCH] spi_bitbang(): use overridable setup_transfer() method A small bug-fix for spi_bitbang: it must always call the setup_transfer function via the overridable pointer, not assume that its spi_bitbang_setup_transfer is sufficient. Otherwise, if all options in the transfers are default (0), the overrided function will never be called. Granted, the function replacing it must call spi_bitbang_setup_transfer, but it might also have other important things to do, even if the second argument (the spi_transfer) is NULL. Tested together with the other patches on the spi_crisv32_sser and spi_crisv32_gpio drivers (not yet in the kernel, will IIUC be submitted as part of the usual arch-maintainer-pushes). Signed-off-by: Hans-Peter Nilsson Signed-off-by: David Brownell Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit ddc1e9753106cedcca7944d2b068baa2e14640b1 Author: Ben Dooks Date: Mon Feb 12 00:52:43 2007 -0800 [PATCH] spi: remove return in spi_unregister_driver() Make the spi_unregister_driver() code fit in with the rest of the header file, and only do the action if the driver passed is non-NULL. This also makes the code a line smaller. Signed-off-by: Ben Dooks Signed-off-by: David Brownell Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit 14fd9b3f8a0a36e706d144efcd579805a99de594 Author: Ben Dooks Date: Mon Feb 12 00:52:42 2007 -0800 [PATCH] spi: documentation does not need to set driver's bus_type field The spi_register_driver() sets the bus_type field of the spi_driver being registered, so there is no need to have it set in the driver itself. Signed-off-by: Ben Dooks Signed-off-by: David Brownell Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit 9b40ff4d729f4a7a9f832c67aa5de0dfa8ad45c0 Author: Ben Dooks Date: Mon Feb 12 00:52:41 2007 -0800 [PATCH] spi: add spi_set_drvdata() and spi_get_drvdata() Add wrappers for getting and setting the driver data using spi_device instead of using dev_{get|set}_drvdata with &spi->dev, to mirror the platform_{get|set}_drvdata. Signed-off-by: Ben Dooks Signed-off-by: David Brownell Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit 69c202afa8ad6d6c1c673d8f9d47b43a0a3604e5 Author: Andrea Paterniani Date: Mon Feb 12 00:52:39 2007 -0800 [PATCH] SPI: Freescale iMX SPI controller driver (BIS+) Add the SPI controller driver for Freescale i.MX(S/L/1). Main features summary: > Per chip setup via board specific code and/or protocol driver. > Per transfer setup. > PIO transfers. > DMA transfers. > Managing of NULL tx / rx buffer for rd only / wr only transfers. This patch replace patch-2.6.20-rc4-spi_imx with the following changes: > Few cosmetic changes. > Function map_dma_buffers now return 0 for success and -1 for failure. > Solved a bug inside spi_imx_probe function (wrong error path). > Solved a bug inside setup function (bad undo setup for max_speed_hz). > For read-only transfers, always write zero bytes. This is almost the same as the 'BIS' version sent by Andrea, except for updating the 'DUMMY' byte so that read-only transfers shift out zeroes. That part of the API changed recently, since some half duplex peripheral chips require that semantic. Signed-off-by: Andrea Paterniani Signed-off-by: David Brownell Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit fdb3c18d639311287dc4675abe743847a1aa62a8 Author: David Brownell Date: Mon Feb 12 00:52:37 2007 -0800 [PATCH] SPI controller driver for OMAP Microwire This adds a SPI driver for the Microwire controller on OMAP1 chips. This driver has been used in the Linux-OMAP tree for some time now, including with some of those displays using standardized 9-bit commands followed by data with 8-bit words. Microwire only supports half duplex transfers, but that's all that most SPI protocols need. When full duplex, or higher speeds, are needed there are several other controllers that can be used on OMAP. [akpm@osdl.org: cleanups] Signed-off-by: David Brownell Signed-off-by: Imre Deak Signed-off-by: Juha Yrjola Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit 85abfaa78239e63f553cc446f8ae5b955282aa29 Author: David Brownell Date: Mon Feb 12 00:52:36 2007 -0800 [PATCH] SPI Kconfig fix Minor Kconfig cleanup ... put the SPI_S3C24XX entry in the correct location (alphabetical order). Signed-off-by: David Brownell Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit efc47135e4b6f7e7d81332f50ef68e4a42819d20 Author: Jiri Kosina Date: Mon Feb 12 00:52:35 2007 -0800 [PATCH] DS1302: local_irq_disable() is redundant after local_irq_save() drivers/char/ds1302.c::get_rtc_time() contains local_irq_disable() call after local_irq_save(). This looks redundant. drivers/char/ds1302.c::rtc_ioctl() contains local_irq_disable() call after local_irq_save(). This looks redundant. Signed-off-by: Jiri Kosina Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit 2869b23e4b95cbafffcd2fe110d77aff8c218405 Author: Tilman Schmidt Date: Mon Feb 12 00:52:34 2007 -0800 [PATCH] drivers/isdn/gigaset: new M101 driver (v2) This patch adds the line discipline based driver for the Gigaset M101 wireless RS232 adapter. It also improves the documentation a bit. Signed-off-by: Tilman Schmidt Signed-off-by: Hansjoerg Lipp Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit e13df2c58f8e8c72278b61e8f59de9a1403f9426 Author: Richard Knutsson Date: Mon Feb 12 00:52:33 2007 -0800 [PATCH] drivers/telephony/ixj: Convert to generic boolean Convert: BOOL -> bool FALSE -> false TRUE -> true Change a variable ('mContinue') to boolean from char, since it is used as boolean. Signed-off-by: Richard Knutsson Acked-by: Randy Dunlap Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit 40565f1962c5be9b9e285e05af01ab7771534868 Author: Jiri Slaby Date: Mon Feb 12 00:52:31 2007 -0800 [PATCH] Char: timers cleanup - Use timer macros to set function and data members and to modify expiration time. - Use DEFINE_TIMER for global timers and do not init them at run-time in these cases. - del_timer_sync is common in most cases -- we want to wait for timer function if it's still running. Signed-off-by: Jiri Slaby Cc: Dave Airlie Cc: David Woodhouse Cc: Dominik Brodowski Cc: Alessandro Zummo Cc: Paul Fulghum Cc: Kylene Jo Hall Cc: Wim Van Sebroeck Acked-by: Dmitry Torokhov (Input bits) Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit d096f3e9898d469493fc0afe88d7285c4bdc3ce2 Author: Jiri Slaby Date: Mon Feb 12 00:52:30 2007 -0800 [PATCH] Char: specialix, isr have 2 params specialix, isr have 2 params pt_regs are no longer the third parameter of isr, call sx_interrupt without it. Signed-off-by: Jiri Slaby Cc: Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit c239122dec9230af80d0914ba23fefde80fdeffe Author: Prarit Bhargava Date: Mon Feb 12 00:52:29 2007 -0800 [PATCH] change __init to __devinit in 2 rtc drivers Change __init to __devinit in rtc drivers' probe functions. Resolves MODPOST warnings: WARNING: drivers/rtc/rtc-ds1553.o - Section mismatch: reference to .init.text:ds1553_rtc_probe from .data.rel between 'ds1553_rtc_driver' (at offset 0x0) and 'ds1553_nvram_attr' WARNING: drivers/rtc/rtc-ds1742.o - Section mismatch: reference to .init.text:ds1742_rtc_probe from .data.rel between 'ds1742_rtc_driver' (at offset 0x0) and 'ds1742_nvram_attr' Signed-off-by: Prarit Bhargava Cc: Alessandro Zummo Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit eb5857084c8d27764b842025e4c805b174e40cad Author: Mike Frysinger Date: Mon Feb 12 00:52:27 2007 -0800 [PATCH] export ufs_fs.h to userspace Was ufs_fs.h purposefully not exported to userspace or did it just slip through the cracks ? assuming the latter scenario, the attached patch touches up the relationship between ufs_fs.h and its sub headers (like ufs_fs_sb.h) so that we can export it ... the silo bootloader takes advantage of this header for example. Signed-off-by: Mike Frysinger Cc: Evgeniy Dushistov Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit 944be0b224724fcbf63c3a3fe3a5478c325a6547 Author: Ingo Molnar Date: Mon Feb 12 00:52:26 2007 -0800 [PATCH] close_files(): add scheduling point close_files() can sometimes take long enough to trigger the soft lockup detector. Cc: Eric Dumazet Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit 92ba0ee2770ed4954e3f8ba412ef2f37e5519477 Author: Tilman Schmidt Date: Mon Feb 12 00:52:26 2007 -0800 [PATCH] drivers/isdn/gigaset: reduce kernel message spam Reduce the number of kernel messages the Gigaset drivers produce in case of an excessively long device response, from one per character exceeding the limit to one per overlong message. Signed-off-by: Tilman Schmidt Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit 7435f50e1261f569c660efb4ae52e8bc21a92cbd Author: Tilman Schmidt Date: Mon Feb 12 00:52:24 2007 -0800 [PATCH] drivers/isdn/gigaset: reduce mutex scope Do not lock the cardstate structure mutex earlier than necessary. Signed-off-by: Tilman Schmidt Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit 163da958ba5282cbf85e8b3dc08e4f51f8b01c5e Author: Eric Dumazet Date: Mon Feb 12 00:52:24 2007 -0800 [PATCH] FS: speed up rw_verify_area() oprofile hunting showed a stall in rw_verify_area(), because of triple indirection and potential cache misses. (file->f_path.dentry->d_inode->i_flock) By moving initialization of 'struct inode' pointer before the pos/count sanity tests, we allow the compiler and processor to perform two loads by anticipation, reducing stall, without prefetch() hints. Even x86 arch has enough registers to not use temporary variables and not increase text size. I validated this patch running a bench and studied oprofile changes, and absolute perf of the test program. Results of my epoll_pipe_bench (source available on request) on a Pentium-M 1.6 GHz machine Before : # ./epoll_pipe_bench -l 30 -t 20 Avg: 436089 evts/sec read_count=8843037 write_count=8843040 21.218390 samples per call (best value out of 10 runs) After : # ./epoll_pipe_bench -l 30 -t 20 Avg: 470980 evts/sec read_count=9549871 write_count=9549894 21.216694 samples per call (best value out of 10 runs) oprofile CPU_CLK_UNHALTED events gave a reduction from 5.3401 % to 2.5851 % for the rw_verify_area() function. Signed-off-by: Eric Dumazet Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit 2a10387ec463c4fcd3ccc461291ce4d8505827e2 Author: Randy Dunlap Date: Mon Feb 12 00:52:22 2007 -0800 [PATCH] com20020 build fix Need to export com20020 symbols for com20020_cs also. WARNING: "com20020_found" [drivers/net/pcmcia/com20020_cs.ko] undefined! WARNING: "com20020_check" [drivers/net/pcmcia/com20020_cs.ko] undefined! Signed-off-by: Randy Dunlap Cc: Esben Nielsen Cc: Jeff Garzik Cc: Dominik Brodowski Cc: "David S. Miller" Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit a1e96b0310d70b72012b5ecde5e97b8262785aae Author: Heiko Carstens Date: Mon Feb 12 00:52:20 2007 -0800 [PATCH] lockdep: forward declare struct task_struct 3117df0453828bd045c16244e6f50e5714667a8a causes this: In file included from arch/s390/kernel/early.c:13: include/linux/lockdep.h:300: warning: "struct task_struct" declared inside parameter list include/linux/lockdep.h:300: warning: its scope is only this definition or declaration, which is probably not what you want Acked-by: Ingo Molnar Cc: Martin Schwidefsky Signed-off-by: Heiko Carstens Cc: Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit 473e66fd24a230e03f6f164913bedb81c0ba052a Author: Horms Date: Mon Feb 12 00:52:18 2007 -0800 [PATCH] kexec: fix references to init in documentation for kexec I've noticed that the boot options are not correct for in the documentation for kdump. The "init" keyword is not necessary, and causes a kernel panic when booting with an initrd on Fedora 5. [horms@verge.net.au: put original comment with the latest version of the patch] Signed-off-by: Judith Lebzeelter Acked-by: Vivek Goyal Signed-off-by: Simon Horman Cc: "Eric W. Biederman" Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit be6b026785414033aac36887cb9ea0ee1244254c Author: Andrew Morton Date: Mon Feb 12 00:52:17 2007 -0800 [PATCH] swiotlb uninlinings Optimise swiotlb.c for size. text data bss dec hex filename 5009 89 64 5162 142a lib/swiotlb.o-before 4666 89 64 4819 12d3 lib/swiotlb.o-after For some reason my gcc (4.0.2) doesn't want to tailcall these things. swiotlb_sync_sg_for_device: pushq %rbp # movl $1, %r8d #, movq %rsp, %rbp #, call swiotlb_sync_sg # leave ret .size swiotlb_sync_sg_for_device, .-swiotlb_sync_sg_for_device .section .text.swiotlb_sync_sg_for_cpu,"ax",@progbits .globl swiotlb_sync_sg_for_cpu .type swiotlb_sync_sg_for_cpu, @function swiotlb_sync_sg_for_cpu: pushq %rbp # xorl %r8d, %r8d # movq %rsp, %rbp #, call swiotlb_sync_sg # leave ret Cc: Jan Beulich Cc: Andi Kleen Cc: "Luck, Tony" Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit 544fc7283cd6902831d660bd8e1181602bd2b4d2 Author: Haavard Skinnemoen Date: Mon Feb 12 00:52:15 2007 -0800 [PATCH] atmel_serial: Use __raw I/O register access Access to chip-internal registers should always be native-endian. This is especially important for AVR32 since it's a big-endian architecture and the non-raw readl() and writel() macros are defined to do little-endian accesses. Signed-off-by: Haavard Skinnemoen Acked-by: Andrew Victor Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit 3991d3bd1506391d8feec209b1d22ccb1c03a0bf Author: Tomasz Kvarsin Date: Mon Feb 12 00:52:14 2007 -0800 [PATCH] warning fix: unsigned->signed While compiling my code with -Wconversion using gcc-trunk, I always get a bunch of warrning from headers, here is fix for them: __getblk is alawys called with unsigned argument, but it takes signed, the same story with __bread,__breadahead and so on. Signed-off-by: Tomasz Kvarsin Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit bc1fc6d88c646ea071de34250552051a63000d70 Author: Eric W. Biederman Date: Mon Feb 12 00:52:10 2007 -0800 [PATCH] ipc: save the ipc namespace while reading proc files The problem we were assuming that current->nsproxy->ipc_ns would never change while someone has our file in /proc/sysvipc/ file open. Given that this can change with both unshare and by passing the file descriptor to another process that assumption is occasionally wrong. Therefore this patch causes /proc/sysvipc/* to cache the namespace and increment it's count when we open the file and to decrement the count when we close the file, ensuring consistent operation with no surprises. Signed-off-by: Eric W. Biederman Cc: Serge E. Hallyn Cc: Herbert Poetzl Cc: Kirill Korotaev Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit 79a81aef769f3a188988ad16032ccfc445cfaa13 Author: Ahmed S. Darwish Date: Mon Feb 12 00:52:09 2007 -0800 [PATCH] reiserfs: Use ARRAY_SIZE macro when appropriate Use ARRAY_SIZE macro already defined in kernel.h Signed-off-by: Ahmed S. Darwish Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit 8b5925fd5461c9f1ac77ede48945ca1945202ddb Author: Ahmed S. Darwish Date: Mon Feb 12 00:52:08 2007 -0800 [PATCH] OSS: Use ARRAY_SIZE macro when appropriate (2) Use ARRAY_SIZE macro already defined in kernel.h Signed-off-by: Ahmed S. Darwish Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit b322f4095056d6849c49412eb3e36637a062e9c0 Author: Ahmed S. Darwish Date: Mon Feb 12 00:52:07 2007 -0800 [PATCH] OSS: Use ARRAY_SIZE macro when appropriate Use ARRAY_SIZE macro already defined in kernel.h Signed-off-by: Ahmed S. Darwish Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit 9d0094de6dfda8209241787d99f531356469d0f5 Author: Ahmed S. Darwish Date: Mon Feb 12 00:52:05 2007 -0800 [PATCH] w1: Use ARRAY_SIZE macro when appropriate A patch to use ARRAY_SIZE macro already defined in kernel.h Signed-off-by: Ahmed S. Darwish Acked-by: Evgeniy Polyakov Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit 3f0504471536a2b6978b9a99ed1c222950fff07a Author: Alan Cox Date: Mon Feb 12 00:52:04 2007 -0800 [PATCH] kernel: shut up the IRQ mismatch messages The problem is various drivers legally validly and sensibly try to claim IRQs but the kernel insists on vomiting forth a giant irrelevant debugging spew when the types clash. Edit kernel/irq/manage.c go down to mismatch: in setup_irq() and ifdef out the if clause that checks for mismatches. It'll then just do the right thing and work sanely. For the current -mm kernel this will do the trick (and moves it into shared irq debugging as in debug mode the info spew is useful). I've had a variant of this in my private tree for some time as I got fed up on the mess on boxes where old legacy IRQs get reused. Signed-off-by: Alan Cox Cc: Arjan van de Ven Cc: Ingo Molnar Cc: David Woodhouse Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit a304e1b82808904c561b7b149b467e338c53fcce Author: David Woodhouse Date: Mon Feb 12 00:52:00 2007 -0800 [PATCH] Debug shared irqs Drivers registering IRQ handlers with SA_SHIRQ really ought to be able to handle an interrupt happening before request_irq() returns. They also ought to be able to handle an interrupt happening during the start of their call to free_irq(). Let's test that hypothesis.... [bunk@stusta.de: Kconfig fixes] Signed-off-by: David Woodhouse Cc: Arjan van de Ven Signed-off-by: Jesper Juhl Signed-off-by: Ingo Molnar Signed-off-by: Adrian Bunk Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit f9e4acf3befd3b2903e01b3ef1bd344f03299826 Author: Nick Piggin Date: Mon Feb 12 00:51:59 2007 -0800 [PATCH] inotify: read return val fix Fix for inotify read bug (bugzilla.kernel.org #6999) Problem Description: When reading from an inotify device with an insufficient sized buffer, read(2) will return 0 with no errno set. This is because of an logically incorrect action from the user program thus should return an more logical value. My suggestion is return -EINVAL as for bind(2). This patch is based on the proposal from Ryan , and feedback from John McCutchan . Return -EINVAL if we have not passed in enough buffer space to read a single inotify event, rather than 0 which indicates that there is nothing to read. Signed-off-by: Nick Piggin Acked-by: "John McCutchan" Cc: Ryan Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit d003fb70fd356d0684ee0cd37a785e058c8678de Author: Christoph Hellwig Date: Mon Feb 12 00:51:58 2007 -0800 [PATCH] remove sb->s_files and file_list_lock usage in dquot.c Iterate over sb->s_inodes instead of sb->s_files in add_dquot_ref. This reduces list search and lock hold time aswell as getting rid of one of the few uses of file_list_lock which Ingo identified as a scalability problem. Previously we called dq_op->initialize for every inode handing of a writeable file that wasn't initialized before. Now we're calling it for every inode that has a non-zero i_writecount, aka a writeable file descriptor refering to it. Thanks a lot to Jan Kara for running this patch through his quota test harness. Signed-off-by: Christoph Hellwig Signed-off-by: Jan Kara Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit fb58b7316a99703afb8d076b0e5f3e1e387e4b30 Author: Christoph Hellwig Date: Mon Feb 12 00:51:57 2007 -0800 [PATCH] move remove_dquot_ref to dqout.c Remove_dquot_ref can move to dqout.c instead of beeing in inode.c under #ifdef CONFIG_QUOTA. Also clean the resulting code up a tiny little bit by testing sb->dq_op earlier - it's constant over a filesystems lifetime. Signed-off-by: Christoph Hellwig Cc: Jan Kara Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit ea6f3281a145d16ed53e88b0627f78d5cde6068f Author: Martin Peschke Date: Mon Feb 12 00:51:56 2007 -0800 [PATCH] scnprintf(): fix a comment The return value of scnprintf() never exceeds @size. Signed-off-by: Martin Peschke Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit 91dd26ad2c04a1bbf179df4dca98f34db2f70716 Author: Dan Aloni Date: Mon Feb 12 00:51:54 2007 -0800 [PATCH] fix the defaults mentioned in Documentation/nfsroot.txt This patch fixes the documentation of nfsroot to match NFS_DEF_FILE_IO_SIZE. Or perhaps we need to change NFS_DEF_FILE_IO_SIZE to match the documentation? Signed-off-by: Dan Aloni Cc: "David S. Miller" Cc: Trond Myklebust Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit d459883e6c54303a233dec3e4453a356794d8c2d Author: Jiri Slaby Date: Mon Feb 12 00:51:53 2007 -0800 [PATCH] MAINTAINERS: remove two dead e-mail Cyclades no longer serves the 2 e-mails listed in MAINTAINERS. Remove them and mark those entries as Orphaned. Signed-off-by: Jiri Slaby Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit ae4472aa03d38b11f334dc0030b82e0c9f249af9 Author: Robert P. J. Day Date: Mon Feb 12 00:51:52 2007 -0800 [PATCH] QUOTA: Have include explicitly Since quota.h declares a R/W semaphore, it should include rwsem.h explicitly. Signed-off-by: Robert P. J. Day Acked-by: Jan Kara Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit 5be02f1d8af4c7baf3a5a31ab9c0cba9fdc52680 Author: Richard Knutsson Date: Mon Feb 12 00:51:50 2007 -0800 [PATCH] include/linux/kernel.h: Remove labs() Remove labs() since it is not used/needed. Signed-off-by: Richard Knutsson Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit 893de2dffb0923d9bdba4abd66afcec3cf9103ba Author: Jiri Slaby Date: Mon Feb 12 00:51:49 2007 -0800 [PATCH] Char: cyclades, use pci_device_id Use pci_device_id struct instead of ushort array. Add MODULE_DEVICE_TABLE. Signed-off-by: Jiri Slaby Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit 29d73aab3368ff18006c3591bc6d2f54c06c9bcb Author: Jiri Slaby Date: Mon Feb 12 00:51:48 2007 -0800 [PATCH] Char: use more PCI_DEVICE macro Use more PCI_DEVICE macro Signed-off-by: Jiri Slaby Acked-by: Wim Van Sebroeck (alim7101_wdt.c part) Cc: Michael Buesch Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit eb3dfb0cb1f4a44e2d0553f89514ce9f2a9fcaf1 Author: Andreas Gruenbacher Date: Mon Feb 12 00:51:47 2007 -0800 [PATCH] Fix d_path for lazy unmounts Here is a bugfix to d_path. First, when d_path() hits a lazily unmounted mount point, it tries to prepend the name of the lazily unmounted dentry to the path name. It gets this wrong, and also overwrites the slash that separates the name from the following pathname component. This is demonstrated by the attached test case, which prints "getcwd returned d_path-bugsubdir" with the bug. The correct result would be "getcwd returned d_path-bug/subdir". It could be argued that the name of the root dentry should not be part of the result of d_path in the first place. On the other hand, what the unconnected namespace was once reachable as may provide some useful hints to users, and so that seems okay. Second, it isn't always possible to tell from the __d_path result whether the specified root and rootmnt (i.e., the chroot) was reached: lazy unmounts of bind mounts will produce a path that does start with a non-slash so we can tell from that, but other lazy unmounts will produce a path that starts with a slash, just like "ordinary" paths. The attached patch cleans up __d_path() to fix the bug with overlapping pathname components. It also adds a @fail_deleted argument, which allows to get rid of some of the mess in sys_getcwd(). Grabbing the dcache_lock can then also be moved into __d_path(). The patch also makes sure that paths will only start with a slash for paths which are connected to the root and rootmnt. The @fail_deleted argument could be added to d_path() as well: this would allow callers to recognize deleted files, without having to resort to the ambiguous check for the " (deleted)" string at the end of the pathnames. This is not currently done, but it might be worthwhile. Signed-off-by: Andreas Gruenbacher Cc: Neil Brown Cc: Al Viro Cc: Christoph Hellwig Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit 5c3bd438ccb94f5d5bf5d8711330e038dc8dd21b Author: Robert P. J. Day Date: Mon Feb 12 00:51:45 2007 -0800 [PATCH] NTFS: rename incorrect check of NTFS_DEBUG with just DEBUG Replace the incorrect debugging check of "#ifdef NTFS_DEBUG" with just "#ifdef DEBUG". Signed-off-by: Robert P. J. Day Acked-by: Anton Altaparmakov Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit fdf892be32d84a1745fa0aee5fc60517421b8038 Author: Andrew Morton Date: Mon Feb 12 00:51:44 2007 -0800 [PATCH] register_blkdev(): don't hand out the LOCAL/EXPERIMENTAL majors As pointed out in http://bugzilla.kernel.org/show_bug.cgi?id=7922, dynamic blockdev major allocation can hand out majors which LANANA has defined as being for local/experimental use. Cc: Torben Mathiasen Cc: Greg KH Cc: Al Viro Cc: Tomas Klas Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit 215122e1110f97a3f478829049b9840cf8fdde57 Author: Andrew Morton Date: Mon Feb 12 00:51:43 2007 -0800 [PATCH] register_chrdev_region() don't hand out the LOCAL/EXPERIMENTAL majors As pointed out in http://bugzilla.kernel.org/show_bug.cgi?id=7922, dynamic chardev major allocation can hand out majors which LANANA has defined as being for local/experimental use. Cc: Torben Mathiasen Cc: Greg KH Cc: Al Viro Cc: Tomas Klas Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit 6ab8eb1cffcc5640ca5b07c2a0ddfaa8fbbcc754 Author: David Chinner Date: Mon Feb 12 00:51:42 2007 -0800 [PATCH] Make XFS use BH_Unwritten and BH_Delay correctly Don't hide buffer_unwritten behind buffer_delay() and remove the hack that clears unexpected buffer_unwritten() states now that it can't happen. Signed-off-by: Dave Chinner Acked-by: Christoph Hellwig Cc: Timothy Shimmin Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit 33a266dda9fbbe72dd978a451a8ee33c59da5e9c Author: David Chinner Date: Mon Feb 12 00:51:41 2007 -0800 [PATCH] Make BH_Unwritten a first class bufferhead flag V2 Currently, XFS uses BH_PrivateStart for flagging unwritten extent state in a bufferhead. Recently, I found the long standing mmap/unwritten extent conversion bug, and it was to do with partial page invalidation not clearing the unwritten flag from bufferheads attached to the page but beyond EOF. See here for a full explaination: http://oss.sgi.com/archives/xfs/2006-12/msg00196.html The solution I have checked into the XFS dev tree involves duplicating code from block_invalidatepage to clear the unwritten flag from the bufferhead(s), and then calling block_invalidatepage() to do the rest. Christoph suggested that this would be better solved by pushing the unwritten flag into the common buffer head flags and just adding the call to discard_buffer(): http://oss.sgi.com/archives/xfs/2006-12/msg00239.html The following patch makes BH_Unwritten a first class citizen. Signed-off-by: Dave Chinner Acked-by: Christoph Hellwig Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit 42da9cbd3eedde33a42acc2cb06f454814cf5de0 Author: Nick Piggin Date: Mon Feb 12 00:51:39 2007 -0800 [PATCH] mm: mincore anon Make mincore work for anon mappings, nonlinear, and migration entries. Based on patch from Linus Torvalds . Signed-off-by: Nick Piggin Acked-by: Hugh Dickins Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit 22cd25ed31bbf849acaa06ab220dc4f526153f13 Author: Benjamin Herrenschmidt Date: Mon Feb 12 00:51:38 2007 -0800 [PATCH] Add NOPFN_REFAULT result from vm_ops->nopfn() Add a NOPFN_REFAULT return code for vm_ops->nopfn() equivalent to NOPAGE_REFAULT for vmops->nopage() indicating that the handler requests a re-execution of the faulting instruction Signed-off-by: Benjamin Herrenschmidt Cc: Arnd Bergmann Cc: Hugh Dickins Cc: Christoph Hellwig Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit e0dc0d8f4a327d033bfb63d43f113d5f31d11b3c Author: Nick Piggin Date: Mon Feb 12 00:51:36 2007 -0800 [PATCH] add vm_insert_pfn() Add a vm_insert_pfn helper, so that ->fault handlers can have nopfn functionality by installing their own pte and returning NULL. Signed-off-by: Nick Piggin Signed-off-by: Benjamin Herrenschmidt Cc: Arnd Bergmann Cc: Hugh Dickins Cc: Christoph Hellwig Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit 2ca48ed5cc5935cbd2a6f5d14fecd4ddbbdb4315 Author: Michael Hanselmann Date: Mon Feb 12 00:51:34 2007 -0800 [PATCH] null pointer dereference in appledisplay driver Commit 40b20c257a13c5a526ac540bc5e43d0fdf29792a by Len Brown introduced a null pointer dereference in the appledisplay driver. This patch fixes it. Signed-off-by: Michael Hanselmann Cc: Len Brown Cc: Greg KH Cc: Benjamin Herrenschmidt Cc: Richard Purdie Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit 022ae414daadb718130679e4eacc105521f11ec7 Author: Martin Schwidefsky Date: Mon Feb 12 15:49:57 2007 +0100 [S390] remove __io_virt and mmiowb. Signed-off-by: Martin Schwidefsky commit 045236ab190636c989ae8198eca37cfbafc1430b Author: Ahmed S. Darwish Date: Mon Feb 12 15:49:51 2007 +0100 [S390] cio: use ARRAY_SIZE in device_id.c Acked-by: Cornelia Huck Signed-off-by: Ahmed S. Darwish Signed-off-by: Martin Schwidefsky commit 4dd3cc5caf41d55cd5e55f32902c8a2ad3296e19 Author: Cornelia Huck Date: Mon Feb 12 15:47:18 2007 +0100 [S390] cio: Fixup interface for setting options on ccw devices. The current ccw_device_set_options() sets a specified mask of options and clears those not specified, but there is no way to find out which options have already been set. In order to fix this up, introduce the following interface changes: ccw_device_set_options() now only sets the specified bits, but does not clear those that are not specified. ccw_device_clear_options() clears the specified bits. ccw_device_set_options_mask() provides the old semantics (setting only the specified bits and clearing the others). Device drivers now work as expected. qdio has been adapted. Signed-off-by: Cornelia Huck Signed-off-by: Martin Schwidefsky commit 0ec67667ab414b18a0518d5b11c842fd342e9cb1 Author: Heiko Carstens Date: Mon Feb 12 15:47:04 2007 +0100 [S390] smp_call_function/smp_call_function_on locking. smp_call_function and smp_call_function_on share the same lock and smp_call_function_on disables softirq's so it can be called from softirq context as well. Hence smp_call_function muss disable softirqs as well to avoid deadlocks. Signed-off-by: Heiko Carstens Signed-off-by: Martin Schwidefsky commit 509cb37e173d4e39cec47238397e91b718730794 Author: Heiko Carstens Date: Mon Feb 12 00:08:03 2007 +0100 [PATCH] one more iomap s390 build fix Commit 9ac7849e35f705830f7b016ff272b0ff1f7ff759 causes this on S390: drivers/built-in.o: In function `dmam_noncoherent_release': dma-mapping.c:(.text+0x1515c): undefined reference to `dma_free_noncoherent' drivers/built-in.o: In function `dmam_free_noncoherent': undefined reference to `dma_free_noncoherent' drivers/built-in.o: In function `dmam_alloc_noncoherent': undefined reference to `dma_alloc_noncoherent' make: *** [.tmp_vmlinux1] Error 1 Cc: Tejun Heo Acked-by: Jeff Garzik Cc: Martin Schwidefsky Signed-off-by: Heiko Carstens Signed-off-by: Linus Torvalds commit 9ede209e83693cf3f6b64f61ab4b65f2f809cb50 Author: Jens Axboe Date: Fri Jan 19 12:11:44 2007 +1100 cfq-iosched: improve continue or break logic in cfq_dispatch This improves performance considerably for sync requests when you have command queuing enabled. Signed-off-by: Jens Axboe commit 28f95cbc3ec01f2c7d248e1a4a384f37e9c2ab16 Author: Jens Axboe Date: Fri Jan 19 12:09:53 2007 +1100 cfq-iosched: remove the implicit queue kicking in slice expire We only really need it for a process going away, so move it to those locations. Signed-off-by: Jens Axboe commit 3c6bd2f879d2c12ce369fe5f75e608ac7bacf01a Author: Jens Axboe Date: Fri Jan 19 12:06:33 2007 +1100 cfq-iosched: check whether a queue timed out in accounting Makes it more fair for the residual slice count. Signed-off-by: Jens Axboe commit cb8874119e9a3ec38c45942808c91cfbc014f402 Author: Jens Axboe Date: Fri Jan 19 12:01:16 2007 +1100 cfq-iosched: tweak the FIFO checking We currently check the FIFO once per slice. Optimize that a bit and only do it as the first thing for a new slice, so we don't end up doing a single request and then seek to the FIFO requests. Signed-off-by: Jens Axboe commit 1792669cc1acc2069869b7ca41a0195240de05e0 Author: Jens Axboe Date: Fri Jan 19 11:59:30 2007 +1100 cfq-iosched: don't pass in queue for cfq_arm_slice_timer() It must always be the active queue, otherwise it's a bug. So just use the active_queue, don't pass it in explicitly. Signed-off-by: Jens Axboe commit c5b680f3b7593f2b066c683df799d19f807fb23d Author: Jens Axboe Date: Fri Jan 19 11:56:49 2007 +1100 cfq-iosched: account for slice over/under time If a slice uses less than it is entitled to (or perhaps more), include that in the decision on how much time to give it the next time it gets serviced. Signed-off-by: Jens Axboe commit 44f7c16065c83060cbb9dd9b367141682a6e2b8e Author: Jens Axboe Date: Fri Jan 19 11:51:58 2007 +1100 cfq-iosched: defer slice activation to first request being active This better matches what time the queue is actually spending doing IO. Signed-off-by: Jens Axboe commit 99f9628aba4d8fb3b8d955c9efded0d0a1995fad Author: Jens Axboe Date: Mon Feb 5 11:56:25 2007 +0100 [PATCH] cfq-iosched: use last service point as the fairness criteria Right now we use slice_start, which gives async queues an unfair advantage. Chance that to service_last, and base the resorter on that. Signed-off-by: Jens Axboe commit b0b8d74941b7bc67edec26e4c114d27827edfd09 Author: Jens Axboe Date: Fri Jan 19 11:35:30 2007 +1100 cfq-iosched: document the cfqq flags Signed-off-by: Jens Axboe commit 98e41c7dfc90c0e9a1086502d4c4d367e1ad74db Author: Jens Axboe Date: Mon Feb 5 11:55:35 2007 +0100 [PATCH] cfq-iosched: move on_rr check into cfq_resort_rr_list() Move the on_rr check into cfq_resort_rr_list(), every call site needs to check it anyway. Signed-off-by: Jens Axboe commit aaf1228ddfb44f04c87d1e7dfc5ccffdba74363d Author: Jens Axboe Date: Fri Jan 19 11:30:16 2007 +1100 cfq-iosched: remove cfq_io_context last_queue It hasn't been used for a while, kill it off and remove the old if 0 code chunk. Signed-off-by: Jens Axboe commit 783660b2f60418144e168ab75a06786f9695fc70 Author: Jens Axboe Date: Fri Jan 19 11:27:47 2007 +1100 elevator: don't sort reads between writes Don't allow elv_dispatch_sort() to mix reads and writes together, it's rarely a good idea. Signed-off-by: Jens Axboe commit cad9751642b62cbb5f62feedc546b4f7890497d4 Author: Jens Axboe Date: Sun Jan 14 22:26:09 2007 +1100 elevator: abstract out the activate and deactivate functions Signed-off-by: Jens Axboe commit 412ecd7751a2653ab17df39a1dc3565a548633fd Author: Randy Dunlap Date: Sat Feb 10 22:47:33 2007 -0800 [PATCH] fix fatal kernel-doc error Teach kernel-doc to handle functions that look like the new pcim_iomap_table(). Fixes this fatal error in scripts/kernel-doc: DOCPROC Documentation/DocBook/kernel-api.xml Error(/tester/linsrc/linux-2.6.20-git6//drivers/pci/pci.c:1351): cannot understand prototype: 'void __iomem * const * pcim_iomap_table(struct pci_dev *pdev) ' make[1]: *** [Documentation/DocBook/kernel-api.xml] Error 1 make: *** [htmldocs] Error 2 Signed-off-by: Randy Dunlap Signed-off-by: Linus Torvalds commit fdba0f2da4b1db682b829b76302b2f25c376051c Author: Al Viro Date: Sun Feb 11 18:20:38 2007 +0000 [PATCH] add missing io...._rep() on sparc32 same as on sparc64 Signed-off-by: Al Viro Signed-off-by: Linus Torvalds commit 23db764d3db5a4bb1e104ad9310e5dc18e4ffa1b Author: Al Viro Date: Sun Feb 11 18:15:29 2007 +0000 [PATCH] Switch s390 to NO_IOMEM Martin Schwidefsky wrote: "s390 does not even need (in|out)b(_p|). I wondered what else from io.h do we not need. The answer is: almost nothing. With the devres patch from Al and the dma-mapping patch from Heiko we can get rid of iomem and all associated definitions." So we'll just need to replace NO_IOPORT with NO_IOMEM in Kconfig and kill arch/s390/mm/ioremap.c. BTW, there's an annoying bit of junk in there - IO_SPACE_LIMIT. We only need it for /proc/ioports, which AFAICS shouldn't even be there on s390 (or uml). OTOH, removing that thing would mean a user-visible change - we go from "empty file in /proc" to "no such file in /proc"... Signed-off-by: Al Viro Signed-off-by: Linus Torvalds commit 5ea8176994003483a18c8fed580901e2125f8a83 Author: Al Viro Date: Sun Feb 11 15:41:31 2007 +0000 [PATCH] sort the devres mess out * Split the implementation-agnostic stuff in separate files. * Make sure that targets using non-default request_irq() pull kernel/irq/devres.o * Introduce new symbols (HAS_IOPORT and HAS_IOMEM) defaulting to positive; allow architectures to turn them off (we needed these symbols anyway for dependencies of quite a few drivers). * protect the ioport-related parts of lib/devres.o with CONFIG_HAS_IOPORT. Signed-off-by: Al Viro Signed-off-by: Linus Torvalds commit 2835fdfa4a7f1400986d76d054237809a9392406 Author: Al Viro Date: Fri Feb 9 18:13:37 2007 +0000 [PATCH] FRA_{DST,SRC} are le16 for decnet Signed-off-by: Al Viro Signed-off-by: Linus Torvalds commit d88e661fb9d28f1de799d524a8625b35eee94bbb Author: Al Viro Date: Fri Feb 9 18:13:42 2007 +0000 [PATCH] fix misannotation of linkinfo_dn Signed-off-by: Al Viro Signed-off-by: Linus Torvalds commit c67687f36acd5e9f387474547143c12fc9ec2737 Author: Don Mullis Date: Sat Feb 10 01:46:51 2007 -0800 [PATCH] fix DocBook build Fix DocBook build. Regression was introduced by gregkh-usb-usb-linux-usb_ch9h-becomes-linux-usb-ch9h.patch Tested by `make htmldocs`. Signed-off-by: Don Mullis Cc: Greg KH Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit 249b061a9aab247d4daf3a2f28e8836e722c3d99 Author: Andrew Morton Date: Sat Feb 10 01:46:49 2007 -0800 [PATCH] fix gregkh-usb-usbcore-remove-unused-bandwith-related-code drivers/isdn/gigaset/bas-gigaset.c: In function 'dump_urb': drivers/isdn/gigaset/bas-gigaset.c:258: error: 'struct urb' has no member named 'bandwidth' Cc: Alan Stern Cc: Greg KH Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit 3abf3beda75a10988eab4c1deab893e2d38e643e Author: Jiri Kosina Date: Sat Feb 10 01:46:48 2007 -0800 [PATCH] CHAR-Amiserial: turn local_save_flags() + local_irq_disable() into local_irq_save() drivers/char/amiserial.c::rs_write() contains local_irq_disable() after local_save_flags(). Turn it into local_irq_save(). Signed-off-by: Jiri Kosina Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit c70555b051f2a32bf94a7e1c75b6b6759031b989 Author: Alexandre Bounine Date: Sat Feb 10 01:46:47 2007 -0800 [PATCH] rapidio: fix multi-switch enumeration This patch contains two fixes for RapisIO enumeration logic: 1. Fix enumeration in configurations with multiple switches. The patch adds: a. Enumeration of an empty switch. Empty switch is a switch that does not have any endpoint devices attached to it (except host device or previous switch in a chain). New code assigns a phony destination ID associated with the switch and sets up corresponding routes. b. Adds a second pass to the enumeration to setup routes to devices discovered after switch was scanned. 2. Fix enumeration failure when riohdid parameter has non-zero value. Current version fails to setup response path to the host when it has destination ID other that 0. Signed-off-by: Alexandre Bounine Acked-by: Matt Porter Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit d5698c28b6e4711e4747bf155f69936208d60e28 Author: Christoph Hellwig Date: Sat Feb 10 01:46:46 2007 -0800 [PATCH] tty: cleanup release_mem release_mem contains two copies of exactly the same code. Refactor these into a new helper, release_tty. The only change in behaviour is that the driver reference count is now decremented after the master tty has been freed instead of before. [penberg@cs.helsinki.fi: fix use-after-free in release_tty.] Cc: Alan Cox Signed-off-by: Christoph Hellwig Signed-off-by: Pekka Enberg Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit 4b98d11b40f03382918796f3c5c936d5495d20a4 Author: Alexey Dobriyan Date: Sat Feb 10 01:46:45 2007 -0800 [PATCH] ifdef ->rchar, ->wchar, ->syscr, ->syscw from task_struct They are fat: 4x8 bytes in task_struct. They are uncoditionally updated in every fork, read, write and sendfile. They are used only if you have some "extended acct fields feature". And please, please, please, read(2) knows about bytes, not characters, why it is called "rchar"? Signed-off-by: Alexey Dobriyan Cc: Jay Lan Cc: Balbir Singh Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit 18f705f49a5b19206233f7cef8f869ce7291f8c8 Author: Alexey Dobriyan Date: Sat Feb 10 01:46:44 2007 -0800 [PATCH] Move TASK_XACCT, TASK_IO_ACCOUNTING up in menus Since they depends on TASKSTATS, it would be nice to move them closer to another options depending on TASKSTATS. Signed-off-by: Alexey Dobriyan Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit 8d06087714b78e8921bd30b5c64202fe80c47339 Author: Oleg Nesterov Date: Sat Feb 10 01:46:38 2007 -0800 [PATCH] _proc_do_string(): fix short reads If you try to read things like /proc/sys/kernel/osrelease with single-byte reads, you get just one byte and then EOF. This is because _proc_do_string() assumes that the caller is read()ing into a buffer which is large enough to fit the whole string in a single hit. Fix. Cc: "Eric W. Biederman" Cc: Michael Tokarev Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit c75fb88dbcc470e6041a20b1457b4835b9a0a48a Author: Pavel Roskin Date: Sat Feb 10 01:46:37 2007 -0800 [PATCH] Fix sparse annotation of spin unlock macros in one case SMP systems without premption and spinlock debugging enabled use unlock macros that don't tell sparse that the lock is being released. Add sparse annotations in this case. Signed-off-by: Pavel Roskin Acked-by: Ingo Molnar Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit aa0f030374228407bc4e3f5482eeab787ba53c8a Author: Paul E. McKenney Date: Sat Feb 10 01:46:37 2007 -0800 [PATCH] Change constant zero to NOTIFY_DONE in ratelimit_handler() Change a hard-coded constant 0 to the symbolic equivalent NOTIFY_DONE in the ratelimit_handler() CPU notifier handler function. Signed-off-by: Paul E. McKenney Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit 656dad312fb41ed95ef08325e9df9bece3aacbbb Author: Ingo Molnar Date: Sat Feb 10 01:46:36 2007 -0800 [PATCH] highmem: catch illegal nesting Catch illegally nested kmap_atomic()s even if the page that is mapped by the 'inner' instance is from lowmem. This avoids spuriously zapped kmap-atomic ptes and turns hard to find crashes into clear asserts at the bug site. Signed-off-by: Ingo Molnar Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit 3e4fdaf8aebe489e8e59826fdf78cb64356d2ad0 Author: Dmitriy Monakhov Date: Sat Feb 10 01:46:35 2007 -0800 [PATCH] jbd layer function called instead of fs specific one jbd function called instead of fs specific one. Signed-off-by: Dmitriy Monakhov Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit 501b9ebf43f9973c3e246c8fbd17144d81a989ef Author: Robert P. J. Day Date: Sat Feb 10 01:46:34 2007 -0800 [PATCH] Fix apparent typo CONFIG_LOCKDEP_DEBUG Replace the apparent typo CONFIG_LOCKDEP_DEBUG with the correct CONFIG_DEBUG_LOCKDEP. Signed-off-by: Robert P. J. Day Cc: Ingo Molnar Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit 8cddd7076ab440906dcf2831e37a147484af80fc Author: Cedric Le Goater Date: Sat Feb 10 01:46:33 2007 -0800 [PATCH] mxser: remove useless fields the session and pgrp fields in mxser_struct are unused. Signed-off-by: Cedric Le Goater Cc: Jiri Slaby Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit 87d156bfd50ac6e66db981989948b7311a25b6ae Author: Richard Knutsson Date: Sat Feb 10 01:46:31 2007 -0800 [PATCH] drivers/block/DAC960: convert 'boolean' to 'bool' Converts 'boolean' to 'bool' and removes the 'boolean' typedef. Signed-off-by: Richard Knutsson Cc: Jens Axboe Cc: James Bottomley Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit 2b1cd4c43b90059b54baa8d9113365984113c631 Author: Mike Frysinger Date: Sat Feb 10 01:46:30 2007 -0800 [PATCH] some rtc documentation updates Fix typo when describing RTC_WKALM. Add some helpful pointers to people developing their own RTC driver. Change a bunch of the error messages in the test program to be a bit more helpful. Signed-off-by: Mike Frysinger Cc: Alessandro Zummo Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit 1efc5da3cf567d2f6b795f9d2112ed97fec4ee7c Author: Mathieu Desnoyers Date: Sat Feb 10 01:46:29 2007 -0800 [PATCH] order of lockdep off/on in vprintk() should be changed The order of locking between lockdep_off/on() and local_irq_save/restore() in vprintk() should be changed. * In kernel/printk.c : vprintk() does : preempt_disable() local_irq_save() lockdep_off() spin_lock(&logbuf_lock) spin_unlock(&logbuf_lock) if(!down_trylock(&console_sem)) up(&console_sem) lockdep_on() local_irq_restore() preempt_enable() The goals here is to make sure we do not call printk() recursively from kernel/lockdep.c:__lock_acquire() (called from spin_* and down/up) nor from kernel/lockdep.c:trace_hardirqs_on/off() (called from local_irq_restore/save). It can then potentially call printk() through mark_held_locks/mark_lock. It correctly protects against the spin_lock call and the up/down call, but it does not protect against local_irq_restore. It could cause infinite recursive printk/trace_hardirqs_on() calls when printk() is called from the mark_lock() error handing path. We should change the locking so it becomes correct : preempt_disable() lockdep_off() local_irq_save() spin_lock(&logbuf_lock) spin_unlock(&logbuf_lock) if(!down_trylock(&console_sem)) up(&console_sem) local_irq_restore() lockdep_on() preempt_enable() Signed-off-by: Mathieu Desnoyers Acked-by: Ingo Molnar Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit 482a579b370a0bf924b577efd6c750284a95e0fb Author: Robert P. J. Day Date: Sat Feb 10 01:46:28 2007 -0800 [PATCH] Remove unused kernel config option PARIDE_PARPORT Remove the unused kernel config option PARIDE_PARPORT. Signed-off-by: Robert P. J. Day Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit 730c385bc58802b51812bfcd13ae3578d16c1dfd Author: Robert P. J. Day Date: Sat Feb 10 01:46:28 2007 -0800 [PATCH] Remove unused kernel config option ZISOFS_FS Remove the kernel config option ZISOFS_FS, since it appears that the actual option is simply ZISOFS. Signed-off-by: Robert P. J. Day Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit b9b2a700378016cead20f34232be87eea45087d2 Author: Robert P. J. Day Date: Sat Feb 10 01:46:27 2007 -0800 [PATCH] Remove references to obsolete kernel config option DEBUG_RWSEMS Remove the few references to the obsolete kernel config option DEBUG_RWSEMS. Signed-off-by: Robert P. J. Day Cc: Ingo Molnar Cc: David Howells Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit 1c6ae7ecd21fbb655ea96a7e9798bedb2917ef91 Author: Robert P. J. Day Date: Sat Feb 10 01:46:26 2007 -0800 [PATCH] Remove dead kernel config option AEDSP16_MPU401. Remove the dead kernel config option AEDSP16_MPU401. Signed-off-by: Robert P. J. Day Cc: Adrian Bunk Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit b385a144ee790f00e8559bcb8024d042863f9be1 Author: Robert P. J. Day Date: Sat Feb 10 01:46:25 2007 -0800 [PATCH] Replace regular code with appropriate calls to container_of() Replace a small number of expressions with a call to the "container_of()" macro. Signed-off-by: Robert P. J. Day Acked-by: Paul Mackerras Cc: "David S. Miller" Cc: Martin Schwidefsky Cc: Stephen Smalley Cc: James Morris Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit 521dae191e5ba9362152da9fd3a12203e087df83 Author: Adrian Bunk Date: Sat Feb 10 01:46:24 2007 -0800 [PATCH] cleanup include/linux/reiserfs_xattr.h - #ifdef guard this header for multiple inclusion - adjust the #include's to what is actually required by this header - remove an unneeded #ifdef - #endif comments Signed-off-by: Adrian Bunk Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit 5b0a2075adb04846870a7fc1e62b08a532054ba6 Author: Adrian Bunk Date: Sat Feb 10 01:46:24 2007 -0800 [PATCH] cleanup include/linux/xattr.h - reduce the userspace visible part - fix the in-kernel compilation Signed-off-by: Adrian Bunk Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit 842f968f3fcdc475c95ec76a03b29c5147e87b54 Author: Robert P. J. Day Date: Sat Feb 10 01:46:23 2007 -0800 [PATCH] Remove final reference to superfluous smp_commence() Remove the last (and commented out) invocation of the obsolete smp_commence() call. Signed-off-by: Robert P. J. Day Acked-by: Ingo Molnar Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit 72ed3d035855841ad611ee48b20909e9619d4a79 Author: Nick Piggin Date: Sat Feb 10 01:46:22 2007 -0800 [PATCH] buffer: memorder fix unlock_buffer(), like unlock_page(), must not clear the lock without ensuring that the critical section is closed. Mingming later sent the same patch, saying: We are running SDET benchmark and saw double free issue for ext3 extended attributes block, which complains the same xattr block already being freed (in ext3_xattr_release_block()). The problem could also been triggered by multiple threads loop untar/rm a kernel tree. The race is caused by missing a memory barrier at unlock_buffer() before the lock bit being cleared, resulting in possible concurrent h_refcounter update. That causes a reference counter leak, then later leads to the double free that we have seen. Inside unlock_buffer(), there is a memory barrier is placed *after* the lock bit is being cleared, however, there is no memory barrier *before* the bit is cleared. On some arch the h_refcount update instruction and the clear bit instruction could be reordered, thus leave the critical section re-entered. The race is like this: For example, if the h_refcount is initialized as 1, cpu 0: cpu1 -------------------------------------- ----------------------------------- lock_buffer() /* test_and_set_bit */ clear_buffer_locked(bh); lock_buffer() /* test_and_set_bit */ h_refcount = h_refcount+1; /* = 2*/ h_refcount = h_refcount + 1; /*= 2 */ clear_buffer_locked(bh); .... ...... We lost a h_refcount here. We need a memory barrier before the buffer head lock bit being cleared to force the order of the two writes. Please apply. Signed-off-by: Nick Piggin Signed-off-by: Mingming Cao Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit c742b53114f8d1535608dafb6a5690103a0748b5 Author: Rob Landley Date: Sat Feb 10 01:46:20 2007 -0800 [PATCH] Documentation/rbtree.txt Documentation for lib/rbtree.c. Signed-off-by: Rob Landley Cc: "Randy.Dunlap" Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit 82ddcb040570411fc2d421d96b3e69711c670328 Author: Robert P. J. Day Date: Sat Feb 10 01:46:20 2007 -0800 [PATCH] extend the set of "__attribute__" shortcut macros Extend the set of "__attribute__" shortcut macros, and remove identical (and now superfluous) definitions from a couple of source files. based on a page at robert love's blog: http://rlove.org/log/2005102601 extend the set of shortcut macros defined in compiler-gcc.h with the following: #define __packed __attribute__((packed)) #define __weak __attribute__((weak)) #define __naked __attribute__((naked)) #define __noreturn __attribute__((noreturn)) #define __pure __attribute__((pure)) #define __aligned(x) __attribute__((aligned(x))) #define __printf(a,b) __attribute__((format(printf,a,b))) Once these are in place, it's up to subsystem maintainers to decide if they want to take advantage of them. there is already a strong precedent for using shortcuts like this in the source tree. The ones that might give people pause are "__aligned" and "__printf", but shortcuts for both of those are already in use, and in some ways very confusingly. note the two very different definitions for a macro named "ALIGNED": drivers/net/sgiseeq.c:#define ALIGNED(x) ((((unsigned long)(x)) + 0xf) & ~(0xf)) drivers/scsi/ultrastor.c:#define ALIGNED(x) __attribute__((aligned(x))) also: include/acpi/platform/acgcc.h: #define ACPI_PRINTF_LIKE(c) __attribute__ ((__format__ (__printf__, c, c+1))) Given the precedent, then, it seems logical to at least standardize on a consistent set of these macros. Signed-off-by: Robert P. J. Day Acked-by: Ralf Baechle Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit e3e8a75d2acfc61ebf25524666a0a2c6abb0620c Author: Kirill Korotaev Date: Sat Feb 10 01:46:19 2007 -0800 [PATCH] Extract and use wake_up_klogd() Remove hack with printing space to wake up klogd. Use explicit wake_up_klogd(). See earlier discussion http://groups.google.com/group/fa.linux.kernel/browse_frm/thread/75f496668409f58d/1a8f28983a51e1ff?lnk=st&q=wake_up_klogd+group%3Afa.linux.kernel&rnum=2#1a8f28983a51e1ff Signed-off-by: Alexey Dobriyan Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit cefc8be82403cfc4325e7b9b063f77dc0f34e19e Author: Kirill Korotaev Date: Sat Feb 10 01:46:18 2007 -0800 [PATCH] Consolidate bust_spinlocks() Part of long forgotten patch http://groups.google.com/group/fa.linux.kernel/msg/e98e941ce1cf29f6?dmode=source Since then, m32r grabbed two copies. Leave s390 copy because of important absence of CONFIG_VT, but remove references to non-existent timerlist_lock. ia64 also loses timerlist_lock. Signed-off-by: Alexey Dobriyan Acked-by: Martin Schwidefsky Cc: Andi Kleen Cc: "Luck, Tony" Cc: Hirokazu Takata Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit c530cba649692512070e8c0131ba3eccade09269 Author: Robert P. J. Day Date: Sat Feb 10 01:46:17 2007 -0800 [PATCH] Remove the last reference to rwlock_is_locked() macro. Remove the lone, remaining reference to the long-deceased rwlock_is_locked() macro. Signed-off-by: Robert P. J. Day Cc: Russell King Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit 731b9a549882c76189baafccbd068d5785ea2a82 Author: Eric Sandeen Date: Sat Feb 10 01:46:16 2007 -0800 [PATCH] remove ext[34]_inc_count and _dec_count - Naming is confusing, ext3_inc_count manipulates i_nlink not i_count - handle argument passed in is not used - ext3 and ext4 already call inc_nlink and dec_nlink directly in other places Signed-off-by: Eric Sandeen Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit 2988a7740dc0dd9a0cb56576e8fe1d777dff0db3 Author: Eric Sandeen Date: Sat Feb 10 01:46:16 2007 -0800 [PATCH] return ENOENT from ext3_link when racing with unlink Return -ENOENT from ext[34]_link if we've raced with unlink and i_nlink is 0. Doing otherwise has the potential to corrupt the orphan inode list, because we'd wind up with an inode with a non-zero link count on the list, and it will never get properly cleaned up & removed from the orphan list before it is freed. [akpm@osdl.org: build fix] Signed-off-by: Eric Sandeen Cc: Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit 967bb77c69e3bc44dd1128a8b503a205cce3fd4a Author: Alexey Dobriyan Date: Sat Feb 10 01:46:15 2007 -0800 [PATCH] seq_file conversion: toshiba.c Signed-off-by: Alexey Dobriyan Cc: Dmitry Torokhov Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit 2e7842b887627c4319c4625d2b52fa6616fda2cd Author: Hugh Dickins Date: Sat Feb 10 01:46:13 2007 -0800 [PATCH] fix umask when noACL kernel meets extN tuned for ACLs Fix insecure default behaviour reported by Tigran Aivazian: if an ext2 or ext3 or ext4 filesystem is tuned to mount with "acl", but mounted by a kernel built without ACL support, then umask was ignored when creating inodes - though root or user has umask 022, touch creates files as 0666, and mkdir creates directories as 0777. This appears to have worked right until 2.6.11, when a fix to the default mode on symlinks (always 0777) assumed VFS applies umask: which it does, unless the mount is marked for ACLs; but ext[234] set MS_POSIXACL in s_flags according to s_mount_opt set according to def_mount_opts. We could revert to the 2.6.10 ext[234]_init_acl (adding an S_ISLNK test); but other filesystems only set MS_POSIXACL when ACLs are configured. We could fix this at another level; but it seems most robust to avoid setting the s_mount_opt flag in the first place (at the expense of more ifdefs). Likewise don't set the XATTR_USER flag when built without XATTR support. Signed-off-by: Hugh Dickins Cc: Tigran Aivazian Cc: Cc: Andreas Gruenbacher Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit 9bbf81e4830db873300c1d0503b371b4f8a932ce Author: Alexey Dobriyan Date: Sat Feb 10 01:46:11 2007 -0800 [PATCH] seq_file conversion: coda Compile-tested. Signed-off-by: Alexey Dobriyan Cc: Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit 85cc9b11446fb8e2762269cfbc28676bfe2eaa4b Author: Alexey Dobriyan Date: Sat Feb 10 01:46:11 2007 -0800 [PATCH] sn2: use static ->proc_fops fix-rmmod-read-write-races-in-proc-entries.patch doesn't want dynamically allocated ->proc_fops, because it will set it to NULL at module unload time. Regardless of module status, switch to statically allocated ->proc_fops which leads to simpler code without wrappers. AFAICS, also fix the following bug: "sn_force_interrupt" proc entry set ->write for itself, but was created with 0444 permissions. Change to 0644. Signed-off-by: Alexey Dobriyan Cc: Al Viro Cc: "Eric W. Biederman" Cc: "Luck, Tony" Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit 38584c14bbba02d8aedace335073b30e49de66a0 Author: Jeff Moyer Date: Sat Feb 10 01:46:10 2007 -0800 [PATCH] raw: don't allow the creation of a raw device with minor number 0 Minor number 0 (under the raw major) is reserved for the rawctl device file, which is used to query, set, and unset raw device bindings. However, the ioctl interface does not protect the user from specifying a raw device with minor number 0: $ sudo ./raw /dev/raw/raw0 /dev/VolGroup00/swap /dev/raw/raw0: bound to major 253, minor 2 $ ls -l /dev/rawctl ls: /dev/rawctl: No such file or directory $ ls -l /dev/raw/raw0 crw------- 1 root root 162, 0 Jan 12 10:51 /dev/raw/raw0 $ sudo ./raw -qa Cannot open master raw device '/dev/rawctl' (No such file or directory) As you can see, this prevents any further raw operations from succeeding. The fix (from Steve Fernandez) is quite simple--do not allow the allocation of minor number 0. Signed-off-by: Jeff Moyer Cc: Steven Fernandez Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit 11f57cedcf382574a1e41d6cec2349f287fcea67 Author: Ingo Molnar Date: Sat Feb 10 01:46:09 2007 -0800 [PATCH] audit: fix audit_filter_user_rules() initialization bug gcc emits this warning: kernel/auditfilter.c: In function 'audit_filter_user': kernel/auditfilter.c:1611: warning: 'state' is used uninitialized in this function I tend to agree with gcc - there are a couple of plausible exit paths from audit_filter_user_rules() where it does not set 'state', keeping the variable uninitialized. For example if a filter rule has an AUDIT_POSSIBLE action. Initialize to 'wont audit'. Fix whitespace damage too. Signed-off-by: Ingo Molnar Cc: Al Viro Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit ead6596b9e776ac32d82f7d1931d7638e6d4a7bd Author: Eric Sandeen Date: Sat Feb 10 01:46:08 2007 -0800 [PATCH] ext4: refuse ro to rw remount of fs with orphan inodes In the rare case where we have skipped orphan inode processing due to a readonly block device, and the block device subsequently changes back to read-write, disallow a remount,rw transition of the filesystem when we have an unprocessed orphan inodes as this would corrupt the list. Ideally we should process the orphan inode list during the remount, but that's trickier, and this plugs the hole for now. Signed-off-by: Eric Sandeen Cc: "Stephen C. Tweedie" Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit ea9a05a1330053759c02eb2c60547085140a4cbd Author: Eric Sandeen Date: Sat Feb 10 01:46:07 2007 -0800 [PATCH] ext3: refuse ro to rw remount of fs with orphan inodes In the rare case where we have skipped orphan inode processing due to a readonly block device, and the block device subsequently changes back to read-write, disallow a remount,rw transition of the filesystem when we have an unprocessed orphan inodes as this would corrupt the list. Ideally we should process the orphan inode list during the remount, but that's trickier, and this plugs the hole for now. Signed-off-by: Eric Sandeen Cc: "Stephen C. Tweedie" Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit bfb58478fe2f8cbbb776d910ff3549515e3c8f4f Author: Adrian Bunk Date: Sat Feb 10 01:46:06 2007 -0800 [PATCH] cleanup linux/byteorder/swabb.h - no longer a userspace header - add #include for in-kernel compilation Signed-off-by: Adrian Bunk Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit a9cccd34372f7075e8746395609bc78f0fbaf204 Author: Matthias Fuchs Date: Sat Feb 10 01:46:05 2007 -0800 [PATCH] serial: support for new board Add support for the CPCI-ASIO4 quad port CompactPCI UART board from electronic system design gmbh. Signed-off-by: Matthias Fuchs Cc: Russell King Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit 482120084d843d4cbb7ff3eb84510a1471130ce0 Author: Thomas Hoehn Date: Sat Feb 10 01:46:05 2007 -0800 [PATCH] Perle multimodem card (PCI-RAS) detection Get the Perle quad-modem PCI card (PCI-RAS4) detected by serial driver. It may also get the PCI-RAS8 running, but can't guarantee as I didn't had one for testing. Signed-off-by: Thomas Hoehn Cc: Russell King Cc: Alan Cox Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit a21217daae8ce6e841e33d4a2bb24026723cb21d Author: Randy Dunlap Date: Sat Feb 10 01:46:04 2007 -0800 [PATCH] kernel-doc: fix some odd spacing issues - in man and text mode output, if the function return type is empty (like it is for macros), don't print the return type and a following space; this fixes an output malalignment; - in the function short description, strip leading, trailing, and multiple embedded spaces (to one space); this makes function name/description output spacing consistent; - fix a comment typo; Signed-off-by: Randy Dunlap Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit 6e8c818829587f001cacae5af4400e4e3aa90a37 Author: Randy Dunlap Date: Sat Feb 10 01:46:03 2007 -0800 [PATCH] docbook: add edd firmware interfaces Cleanup kernel-doc notation in drivers/firmware/edd.c. Add edd.c to DocBook/kernel-api.tmpl. Signed-off-by: Randy Dunlap Acked-by: Matt Domsch Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit 7be2c7c96aff2871240d61fef508c41176c688b5 Author: David Brownell Date: Sat Feb 10 01:46:02 2007 -0800 [PATCH] RTC framework driver for CMOS RTCs This is an "RTC framework" driver for the "CMOS" RTCs which are standard on PCs and some other platforms. That's MC146818 compatible silicon. Advantages of this vs. drivers/char/rtc.c (use one _or_ the other, only one will be able to claim the RTC irq) include: - This leverages both the new RTC framework and the driver model; both PNPACPI and platform device modes are supported. (A separate patch creates a platform device on PCs where PNPACPI isn't configured.) - It supports common extensions like longer alarms. (A separate patch exports that information from ACPI through platform_data.) - Likewise, system wakeup events use "real driver model support", with policy control via sysfs "wakeup" attributes and and using normal rtc ioctls to manage wakeup. (Patch in the works. The ACPI hooks are known; /proc/acpi/alarm can vanish. Making it work with EFI will be a minor challenge to someone with e.g. a MiniMac.) It's not yet been tested on non-x86 systems, without ACPI, or with HPET. And the RTC framework will surely have teething pains on "mainstream" PC-based systems (though must embedded Linux systems use it heavily), not limited to sorting out the "/dev/rtc0" issue (udev easily tweaked). Also, the ALSA rtctimer code doesn't use the new RTC API. Otherwise, this should be a no-known-regressions replacement for the old drivers/char/rtc.c driver, and should help the non-embedded distros (and the new timekeeping code) start to switch to the framework. Note also that any systems using "rtc-m48t86" are candidates to switch over to this more functional driver; the platform data is different, and the way bytes are read is different, but otherwise those chips should be compatible. [akpm@osdl.org: sparc32 fix] [akpm@osdl.org: sparc64 fix] Signed-off-by: David Brownell Cc: Woody Suwalski Cc: Alessandro Zummo Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit f1f8810cf48dd88ee70e974924f2dd76e5669dd5 Author: Mathieu Desnoyers Date: Sat Feb 10 01:46:01 2007 -0800 [PATCH] local_t: Documentation Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit d4d23add3abcd18d8021b99f230df608ccb2f007 Author: Kyle McMartin Date: Sat Feb 10 01:46:00 2007 -0800 [PATCH] Common compat_sys_sysinfo I noticed that almost all architectures implemented exactly the same sys32_sysinfo... except parisc, where a bug was to be found in handling of the uptime. So let's remove a whole whack of code for fun and profit. Cribbed compat_sys_sysinfo from x86_64's implementation, since I figured it would be the best tested. This patch incorporates Arnd's suggestion of not using set_fs/get_fs, but instead extracting out the common code from sys_sysinfo. Cc: Christoph Hellwig Cc: Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit 72fd4a35a824331d7a0f4168d7576502d95d34b3 Author: Robert P. J. Day Date: Sat Feb 10 01:45:59 2007 -0800 [PATCH] Numerous fixes to kernel-doc info in source files. A variety of (mostly) innocuous fixes to the embedded kernel-doc content in source files, including: * make multi-line initial descriptions single line * denote some function names, constants and structs as such * change erroneous opening '/*' to '/**' in a few places * reword some text for clarity Signed-off-by: Robert P. J. Day Cc: "Randy.Dunlap" Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit 262086cf5b5343c2b81c97b1c606058e921859df Author: Robert P. J. Day Date: Sat Feb 10 01:45:58 2007 -0800 [PATCH] Discuss a couple common errors in kernel-doc usage. Explain a couple of the most common errors in kernel-doc usage. Signed-off-by: Robert P. J. Day Acked-by: Randy Dunlap Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit 78137e3b34e122949e6de36a894fb5843664b8f9 Author: Alan Cox Date: Sat Feb 10 01:45:57 2007 -0800 [PATCH] tty: improve encode_baud_rate logic Mostly so people can see the work in progress. This enhances the encode function which isn't currently used in the base tree but is when using some of the testing tty patches. This resolves a problem with some hardware where applications got confusing information from the tty ioctls. Correct but confusing. In some situations asking for, say, 9600 baud actually gets you 9595 baud or similar near-miss values. With the old code this meant that a request for B9600 got a return of BOTHER, 9595 which programs interpreted as a failure. The new code now works on the following basis - If you ask for specific rate via BOTHER, you get a precise return - If you ask for a standard Bfoo rate and the result is close you get a Bfoo return - If you ask for a standard Bfoo rate and get something way off you get a BOTHER/rate return This seems to fix up the cases I've found where this broke compatibility. Signed-off-by: Alan Cox Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit 996a07bcb62c5935248e238a1150089f3d99a6fb Author: Randy Dunlap Date: Sat Feb 10 01:45:56 2007 -0800 [PATCH] kernel-doc: allow more whitespace Allow whitespace in pointer-to-function [accept "(* done)", not just "(*done)"]. Allow tabs (spaces are already allowed) between "#define" and a macro name. Signed-off-by: Randy Dunlap Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit 78831ba68263d37382d61ea87d738975d992bd0d Author: Randy Dunlap Date: Sat Feb 10 01:45:55 2007 -0800 [PATCH] sysrq: alphabetize command keys doc Alphabetize the sysrq command keys list. Signed-off-by: Randy Dunlap Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit b653d081c17e26101980c858a9808740533b78b4 Author: Alexey Dobriyan Date: Sat Feb 10 01:45:54 2007 -0800 [PATCH] proc: remove useless (and buggy) ->nlink settings Bug: pnx8550 code creates directory but resets ->nlink to 1. create_proc_entry() et al will correctly set ->nlink for you. Signed-off-by: Alexey Dobriyan Cc: Ralf Baechle Cc: Benjamin Herrenschmidt Cc: Paul Mackerras Cc: Jeff Dike Cc: Corey Minyard Cc: Alan Cox Cc: Kyle McMartin Cc: Martin Schwidefsky Cc: Greg KH Cc: Ingo Molnar Cc: Thomas Gleixner Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit 891dcd2f7ab15e2aaad07f6925b3a53fd8d5c02f Author: Randy Dunlap Date: Sat Feb 10 01:45:53 2007 -0800 [PATCH] kernel-doc: allow a little whitespace In kernel-doc syntax, be a little flexible: allow whitespace between a function parameter name and the colon that must follow it, such as: @pdev : PCI device to unplug (This allows lots of megaraid kernel-doc to work without tons of editing.) Signed-off-by: Randy Dunlap Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit 3de3af130b75a79c7381573e5ea69cb59502023f Author: Robert P. J. Day Date: Sat Feb 10 01:45:52 2007 -0800 [PATCH] Remove unnecessary memset(0) calls after kzalloc() calls. Delete the few remaining unnecessary calls to memset(0) after a call to kzalloc(). Signed-off-by: Robert P. J. Day Cc: Andi Kleen Cc: Dmitry Torokhov Cc: Adam Belay Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit 100bb9349ea5cb4e667977de55bd6dc4ac7bc22f Author: Andrew Morton Date: Sat Feb 10 01:45:51 2007 -0800 [PATCH] proc_misc warning fix fs/proc/proc_misc.c: In function 'proc_misc_init': fs/proc/proc_misc.c:764: warning: unused variable 'entry' Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit cb799b8988e40a7871ae8e976248c33c562e3555 Author: Andrew Morton Date: Sat Feb 10 01:45:51 2007 -0800 [PATCH] sysctl warning fix kernel/sysctl.c:2816: warning: 'sysctl_ipc_data' defined but not used Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit 5aab0ad5ed82d6be5173f5d2e9da6be9c1e84a9c Author: Adrian Bunk Date: Sat Feb 10 01:45:50 2007 -0800 [PATCH] schedule obsolete OSS drivers for removal, 3rd round Schedule obsolete OSS drivers (with ALSA drivers that support the same hardware) for removal. A rationale of the patch is in http://lkml.org/lkml/2006/12/18/305 Signed-off-by: Adrian Bunk Acked-By: Thomas Sailer Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit 77adbfbf4cf96fedf9b75bb330704828c187b190 Author: Rolf Eike Beer Date: Sat Feb 10 01:45:49 2007 -0800 [PATCH] Add const for time{spec,val}_compare arguments The arguments are really const. Mark them const to allow these functions being called from places where the arguments are const without getting useless compiler warnings. Signed-off-by: Rolf Eike Beer Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit a470e18f53940e7bd07b09f01c0970f653e268bf Author: Olaf Hering Date: Sat Feb 10 01:45:48 2007 -0800 [PATCH] msdos partitions: fix logic error in AIX detection Correct the AIX magic check to let 'echo > /dev/sdb' actually work. Signed-off-by: Olaf Hering Cc: OGAWA Hirofumi Cc: Anton Blanchard Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit 4419d1ac7def3c2f74cab15e4a1c69cffcaadedd Author: Olaf Hering Date: Sat Feb 10 01:45:47 2007 -0800 [PATCH] relax check for AIX in msdos partition table The patch to identify AIX disks and ignore them has caused at least one machine to fail to find the root partition on 2.6.19. The patch is: http://lkml.org/lkml/2006/7/31/117 The problem is some disk formatters do not blow away the first 4 bytes of the disk. If the disk we are installing to used to have AIX on it, then the first 4 bytes will still have IBMA in EBCDIC. The install in question was debian etch. Im not sure what the best fix is, perhaps the AIX detection code could check more than the first 4 bytes. The whole partition info for primary partitions is in this block: dd if=/dev/sdb count=$(( 4 * 16 )) bs=1 skip=$(( 0x1be )) All other data do not matter, beside the 0x55aa marker at the end of the first block. Signed-off-by: Olaf Hering Cc: OGAWA Hirofumi Cc: Anton Blanchard Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit aa58d61d18b89b98521364550b481fd9bd18c3b6 Author: Robert P. J. Day Date: Sat Feb 10 01:45:46 2007 -0800 [PATCH] Get rid of "double zeroing" of allocated pages Simplify the few instances where a call to "get_zeroed_page()" is closely followed by an unnecessary call to memset() to clear that page. Signed-off-by: Robert P. J. Day Cc: chas williams Acked-by: Mauro Carvalho Chehab Cc: James Bottomley Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit 78ba2faf71c63990cba9997f18cf1d610e06e3f2 Author: Corey Minyard Date: Sat Feb 10 01:45:45 2007 -0800 [PATCH] IPMI: Fix some RCU problems Fix some RCU problem pointed out by Paul McKenney of IBM. These are: The wholesale move of the command receivers list into a new list was not safe because the list will point to the new tail during a traversal, so the traversal will never end on a reader if this happens during a read. Memory barriers were needed to handle proper ordering of the setting of the IPMI interface as valid. Readers might not see proper ordering of data otherwise. In ipmi_smi_watcher_register(), the use of the _rcu suffix on the list is unnecessary. This require the list_splice_init_rcu() patch previously posted. Signed-off-by: Corey Minyard Cc: Paul E. McKenney Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit 3678d62f028689abc8ac5693b254e48f605f94ba Author: Corey Minyard Date: Sat Feb 10 01:45:42 2007 -0800 [PATCH] add an RCU version of list splicing This patch is in support of the IPMI driver. I have tested this with the IPMI driver changes coming in the next patch. Add a list_splice_init_rcu() function to splice an RCU-protected list into another list. This takes the sync function as an argument, so one would do something like: INIT_LIST_HEAD(&list); list_splice_init_rcu(&source, &dest, synchronize_rcu); The idea being to keep the RCU API proliferation down to a dull roar. [akpm@osdl.org: build fix] Signed-off-by: Paul E. McKenney Signed-off-by: Corey Minyard Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit 16cf5b39b81b95d1e3d81df3ba8c82cadf54f551 Author: Tilman Schmidt Date: Sat Feb 10 01:45:41 2007 -0800 [PATCH] fix sparse warnings from {asm,net}/checksum.h Rename the variable "sum" in the __range_ok macros to avoid name collisions causing lots of "symbol shadows an earlier one" warnings by sparse. Signed-off-by: Tilman Schmidt Cc: Russell King Cc: Andi Kleen Cc: Hirokazu Takata Acked-by: Ian Molton Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit 3db5db4fcdafc85b99d171336a7d2f25765ccd13 Author: Helge Deller Date: Sat Feb 10 01:45:40 2007 -0800 [PATCH] use cycle_t instead of u64 in struct time_interpolator The 32bit and 64bit PARISC Linux kernels suffers from the problem, that the gettimeofday() call sometimes returns non-monotonic times. The easiest way to fix this, is to drop the PARISC-specific implementation and switch over to the generic TIME_INTERPOLATION framework. But in order to make it even compile on 32bit PARISC, the patch below which touches the generic Linux code, is mandatory. More information and the full patch with the parisc-specific changes is included in this thread: http://lists.parisc-linux.org/pipermail/parisc-linux/2006-December/031003.html As far as I could see, this patch does not change anything for the existing architectures which use this framework (IA64 and SPARC64), since "cycles_t" is defined there as unsigned 64bit-integer anyway (which then makes this patch a no-change for them). Signed-off-by: Helge Deller Cc: Cc: Thomas Gleixner Cc: Ingo Molnar Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit fc0ecff698165ae8e178efa086e0dd1f385206b1 Author: Andrew Morton Date: Sat Feb 10 01:45:39 2007 -0800 [PATCH] remove invalidate_inode_pages() Convert all calls to invalidate_inode_pages() into open-coded calls to invalidate_mapping_pages(). Leave the invalidate_inode_pages() wrapper in place for now, marked as deprecated. Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit 54bc485522afdac33de5504da2ea8cdcc690674e Author: Anton Altaparmakov Date: Sat Feb 10 01:45:38 2007 -0800 [PATCH] Export invalidate_mapping_pages() to modules It makes no sense to me to export invalidate_inode_pages() and not invalidate_mapping_pages() and I actually need invalidate_mapping_pages() because of its range specification ability... akpm: also remove the export of invalidate_inode_pages() by making it an inlined wrapper. Signed-off-by: Anton Altaparmakov Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit 5449bc94152a6c4700f46786be600141234d8f0f Author: Pavel Pisa Date: Sat Feb 10 01:45:37 2007 -0800 [PATCH] DocBook/HTML: correction of recursive A tags in HTML output The malformed HTML was generated after switch to XSLTPROC from SGML tools. The reference title struct x is converted into two recursive tags struct x There is more possible solutions for this problem. One can be found at http://darkk.livejournal.com/ The proposed solution is based on suggestion provided by Jiri Kosek. Signed-off-by: Pavel Pisa Acked-by: Randy Dunlap Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit 460e79c30b5dd978143e7ea53849043c22d16f73 Author: Pavel Pisa Date: Sat Feb 10 01:45:36 2007 -0800 [PATCH] DocBook/HTML: Generate chapter/section level TOCs for functions Simple increase of section TOC level generation significantly enhances navigation experience through generated kernel API documentation. This change restores back state from SGML tools time. Signed-off-by: Pavel Pisa Acked-by: Randy Dunlap Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit a784bf7c195f9eca1188562c54952e4bf9791437 Author: Jiri Slaby Date: Sat Feb 10 01:45:36 2007 -0800 [PATCH] Char: moxa, pci probing Alter the driver to use the pci probing. Signed-off-by: Jiri Slaby Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit 9cde5bf027556bd1e58caa14bfe8cdba64192edd Author: Jiri Slaby Date: Sat Feb 10 01:45:35 2007 -0800 [PATCH] Char: moxa, pci_probing prepare - change pci conf prototype and rename it to moxa_pci_probe - move some code to moxa_pci_probe - create moxa_pci_remove Signed-off-by: Jiri Slaby Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit 181d6f4fac7f01ede95284954ea1231939dca0d9 Author: Jiri Slaby Date: Sat Feb 10 01:45:34 2007 -0800 [PATCH] Char: moxa, remove useless variables Remove temporary or once used variables, that can be defined locally to save some bytes. Signed-off-by: Jiri Slaby Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit 8f8ecbad09b48e5fe44a8d7f5344e802e9c231c8 Author: Jiri Slaby Date: Sat Feb 10 01:45:33 2007 -0800 [PATCH] Char: moxa, variables cleanup - rename moxaChannels to moxa_port - rename moxa_str to moxa_ports - move board global variables into moxa_board - move port global variables into moxa_port Signed-off-by: Jiri Slaby Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit 889074ee0be9cc6c2a698d95db4d0927485ec139 Author: Jiri Slaby Date: Sat Feb 10 01:45:33 2007 -0800 [PATCH] Char: moxa, remove moxa_pci_devinfo Nothing is used from this struct but *pdev. Remove it and store only pdev. Signed-off-by: Jiri Slaby Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit c251ae0d7514563c7fdace0d390175454761228b Author: Jiri Slaby Date: Sat Feb 10 01:45:32 2007 -0800 [PATCH] Char: moxa, use del_timer_sync Use del_timer_sync in most timer deletions, we don't want to oops in the timer function. Signed-off-by: Jiri Slaby Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit 11324edd4ad34981764b25bed44d46a1507b62e1 Author: Jiri Slaby Date: Sat Feb 10 01:45:31 2007 -0800 [PATCH] Char: moxa, macros cleanup Remove yet defined or unused macros and whitespace cleanup around the rest. Signed-off-by: Jiri Slaby Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit 9dff89cd82af7bccc706fed288b1c33a51c3b937 Author: Jiri Slaby Date: Sat Feb 10 01:45:30 2007 -0800 [PATCH] Char: moxa, eliminate typedefs Do not use typedefs, use directly struct instead. Signed-off-by: Jiri Slaby Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit 5ebb4078af0dab866fdf57f84f72b9e9a7e8c6b8 Author: Jiri Slaby Date: Sat Feb 10 01:45:30 2007 -0800 [PATCH] Char: moxa, use PCI_DEVICE Use PCI_DEVICE macro in pci_device_id list. Signed-off-by: Jiri Slaby Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit 224299d444ce97e0c78a9e8ea930589ff8861404 Author: Jiri Slaby Date: Sat Feb 10 01:45:29 2007 -0800 [PATCH] Char: moxa, devids cleanup Move them to pci_ids.h Signed-off-by: Jiri Slaby Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit c5b466e70fef18f7e0de88f81fad0b83614444a8 Author: Jiri Slaby Date: Sat Feb 10 01:45:28 2007 -0800 [PATCH] Char: moxa, remove unused functions Remove ifdeffed functions and cleanup comments including too long license terms. Signed-off-by: Jiri Slaby Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit ba196df3d6432c5c20429e8e447c5db7abedb8f3 Author: Jiri Slaby Date: Sat Feb 10 01:45:28 2007 -0800 [PATCH] Char: moxa, remove hangup bottomhalf Call tty_hangup directly, we do not need a bottomhalf for this. Signed-off-by: Jiri Slaby Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit aa7e5221fb47badbea618cc62704d6e4a4bcce15 Author: Jiri Slaby Date: Sat Feb 10 01:45:27 2007 -0800 [PATCH] Char: moxa, timers cleanup Use kernel macros and functions for timer encapsulation -- do not access fileds directly. Also del_timer on inactive is legal, so that noting if it runs is senseless, delete these variables. Signed-off-by: Jiri Slaby Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit 9fa372a850b9ffcb177eb9ac0b75963b2f9af233 Author: Jiri Slaby Date: Sat Feb 10 01:45:26 2007 -0800 [PATCH] Char: moxa, do not initialize global static Remove useless initialization of variables a) statically b) dynamically at module_init c) dynamically after kzalloc (those with '= 0/NULL') Signed-off-by: Jiri Slaby Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit f204d2672044f0f7061d645f0f59f8535b63d106 Author: Jiri Slaby Date: Sat Feb 10 01:45:25 2007 -0800 [PATCH] Char: moxa, remove unused allocated page moxaXmitBuff is almost unused -- only one byte from the whole PAGE_SIZE bytes is used. Do not alloc so much space for almost anything. Also remove lock protecting this page allocation. Signed-off-by: Jiri Slaby Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit 34f5a39899f3f3e815da64f48ddb72942d86c366 Author: Theodore Ts'o Date: Sat Feb 10 01:45:24 2007 -0800 [PATCH] Add TAINT_USER and ability to set taint flags from userspace Allow taint flags to be set from userspace by writing to /proc/sys/kernel/tainted, and add a new taint flag, TAINT_USER, to be used when userspace has potentially done something dangerous that might compromise the kernel. This will allow support personnel to ask further questions about what may have caused the user taint flag to have been set. For example, they might examine the logs of the realtime JVM to see if the Java program has used the really silly, stupid, dangerous, and completely-non-portable direct access to physical memory feature which MUST be implemented according to the Real-Time Specification for Java (RTSJ). Sigh. What were those silly people at Sun thinking? [akpm@osdl.org: build fix] [bunk@stusta.de: cleanup] Signed-off-by: "Theodore Ts'o" Signed-off-by: Adrian Bunk Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit a136e99f12cdc967a6f607644e471ed749f963db Author: Jiri Slaby Date: Sat Feb 10 01:45:24 2007 -0800 [PATCH] Char: mxser_new, fix sparse warning Feed NULL instead of 0 where pointer is expected. Signed-off-by: Jiri Slaby Cc: Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit 5ff7205dd9084c96cf2bedc4d0481790c5a7a635 Author: Jiri Slaby Date: Sat Feb 10 01:45:23 2007 -0800 [PATCH] Char: mxser_new, lock count and flags Both open count and INITIALIZED flag should be changed under lock. Signed-off-by: Jiri Slaby Cc: Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit 722d5e4ae89f061582cc46ccbbd3b5ae87a6e165 Author: Jiri Slaby Date: Sat Feb 10 01:45:22 2007 -0800 [PATCH] Char: mxser_new, do not null driver_data driver_data are initialzed to NULL from tty layer, no need to do it in the driver. In this case it cases oops, since driver_data may be NULL for a short while for another closing process. Signed-off-by: Jiri Slaby Cc: Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit f64c84a1668930d1ca2b7dbaa92146c2139cb508 Author: Jiri Slaby Date: Sat Feb 10 01:45:21 2007 -0800 [PATCH] Char: mxser_new, upgrade to 1.9.15 - allow special rates - break when bad status Signed-off-by: Jiri Slaby Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit 1a221026c3de9e6c05e6343e37205b0369ebbeff Author: Jiri Slaby Date: Sat Feb 10 01:45:21 2007 -0800 [PATCH] Char: mxser_new, do not put pdev We don't call pci_dev_get, so do not call pci_dev_put in the pci release function. Signed-off-by: Jiri Slaby Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit 45257fa9a5070e4c0739af1f81848ad557472b40 Author: Jiri Slaby Date: Sat Feb 10 01:45:20 2007 -0800 [PATCH] Char: mxser_new, fix twice resource releasing Because brd->info is not NULLed, resources are released twice. NULL it in pci_remove function. Also take care of retval and releasing in pci_probe -- mxser_initbrd alreasy releases resource, do not do it again in fail path in probe function. Cc: Sergei Organov Signed-off-by: Jiri Slaby Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit 18b95576bc6b9ef9270ec778e1d545c0ca8bbbbb Author: Jiri Slaby Date: Sat Feb 10 01:45:19 2007 -0800 [PATCH] Char: mxser_new, less loops in isr Loop only 100^2 times, not 99999^2 times in isr (at most). Signed-off-by: Jiri Slaby Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit ed79ba12e981538a399012f226360db635b50570 Author: Jiri Slaby Date: Sat Feb 10 01:45:18 2007 -0800 [PATCH] Char: mxser_new, header file cleanup - Remove no longer used macros - Move some macros from the header to the code - Remove c++ comments - Align backslashes to one column Signed-off-by: Jiri Slaby Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit f574874bc861414bbae220b1fe623cbdd098243b Author: Jiri Slaby Date: Sat Feb 10 01:45:18 2007 -0800 [PATCH] Char: mxser_new, alter locking in isr Avoid oopsing when stress-testing open/close -- port->tty is NULL sometimes, but is expected to be non-NULL, since dereferencing. Receive/transmit chars iff ASYNC_CLOSING is not set and ASYNC_INITIALIZED is set. Thanks Sergei for pointing this out and testing. Cc: Sergei Organov Signed-off-by: Jiri Slaby Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit 765d94c1b37d08be02eea6abbff70c0fda0ba984 Author: Jiri Slaby Date: Sat Feb 10 01:45:17 2007 -0800 [PATCH] Doc: isicom, remove reserved ioctl-number Isicom driver no longer registers chardev with ioctl function. It used to use for firmware loading. Remove the reserved letter (M) from ioctl-number, so that the conflict get away. Signed-off-by: Jiri Slaby Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit c493edd13d633ba556cd71eeae9d062b6912c55d Author: Jiri Slaby Date: Sat Feb 10 01:45:16 2007 -0800 [PATCH] Char: mxser_new, clean request_irq call We always set ASYNC_SHARE_IRQ, so do not test against this flag and request shared irq directly. Also remove nonsense comment. Signed-off-by: Jiri Slaby Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit 47c85c0db159bb0e5f8f5cb4ae7cc19a5c3359de Author: Jiri Slaby Date: Sat Feb 10 01:45:15 2007 -0800 [PATCH] Char: mxser_new, remove tty_wakeup bottomhalf It's safe to call tty_wakeup from irq context. Do not schedule it for later calling. Signed-off-by: Jiri Slaby Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit 98c47ea28a7d1b4a3fb003a805c312d5c977b1d2 Author: Jiri Slaby Date: Sat Feb 10 01:45:15 2007 -0800 [PATCH] Char: mxser, obsolete old, nonexperimental new Mark v 1.x as obsolete and v 2.x as non-experimental in Kconfig. Signed-off-by: Jiri Slaby Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit a24f1405b001d70bebaacf91bc66cae447cc15d0 Author: Jiri Slaby Date: Sat Feb 10 01:45:14 2007 -0800 [PATCH] Char: mxser_new, remove unused stuff - nobody waits on close_wait - ASYNC_SPLIT_TERMIOS is not set by anybody, so do not test this flag - process session and pgrp are useless information Signed-off-by: Jiri Slaby Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit cbcdc1debd02e1a2cbc1367ee7e0213e1041f738 Author: David Brownell Date: Sat Feb 10 01:45:13 2007 -0800 [PATCH] PNP: export pnp_bus_type The PNP framework doesn't export "pnp_bus_type", which is an unfortunate exception to the policy followed by pretty much every other bus. I noticed this when I had to find a device in order to provide its platform_data. Note that per advice from Arjan, the "export" scope has been been minimized to avoid the hundred-plus bytes needed to support access from modules. In this case, the symbol is only needed by statically linked kernel code that lives outside the drivers/pnp directory. Signed-off-by: David Brownell Cc: Adam Belay Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit 83f3aa3dc5a5014cb4dc344e503b082344d8fe1e Author: Thomas Maier Date: Sat Feb 10 01:45:11 2007 -0800 [PATCH] pktcdvd: cleanup - update documentation - use clear_bdi_congested/set_bdi_congested functions directly instead of old wrappers - removed DECLARE_BUF_AS_STRING macro Signed-off-by: Thomas Maier Cc: Peter Osterlund Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit b035b6de24932ffd4a2b1c6619a2f5711da6920f Author: Alexey Dobriyan Date: Sat Feb 10 01:45:10 2007 -0800 [PATCH] Consolidate default sched_clock() Use attribute(weak). Signed-off-by: Alexey Dobriyan Acked-by: Ingo Molnar Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit 5e07e1ccb0c0f25dd748ebe2ef83008c2229bf1c Author: Jiri Slaby Date: Sat Feb 10 01:45:09 2007 -0800 [PATCH] Char: n_r3964, cleanup - Lindent the code - allow semicolons after macros by 'do {} while (0)' - eliminate C++ comments Signed-off-by: Jiri Slaby Cc: David Woodhouse Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit 44bafdf37b30234671d4e2fb595dea4c3717d089 Author: Jiri Slaby Date: Sat Feb 10 01:45:08 2007 -0800 [PATCH] Char: serial167, cleanup serial167, cleanup - Lindent the code - remove 3 pointers from paranoia_check Signed-off-by: Jiri Slaby Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit 30a063a900518926966f4d75333c1bfbde1658fa Author: Jiri Slaby Date: Sat Feb 10 01:45:08 2007 -0800 [PATCH] Char: mxser_new, remove useless spinlock gm_lock is useless, since ISA is configured at init time and there it's serialized. Signed-off-by: Jiri Slaby Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit c76b09301eeb844036f17d008e15ff6532d8f33a Author: Jiri Slaby Date: Sat Feb 10 01:45:07 2007 -0800 [PATCH] Char: mxser_new, mark init functions Mark some funcions with __init and __devinit. Signed-off-by: Jiri Slaby Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit d8adb9cef7e406a9a82881695097c702bc98422f Author: Eric Sandeen Date: Sat Feb 10 01:45:06 2007 -0800 [PATCH] ext2: skip pages past number of blocks in ext2_find_entry This one was pointed out on the MOKB site: http://kernelfun.blogspot.com/2006/11/mokb-09-11-2006-linux-26x-ext2checkpage.html If a directory's i_size is corrupted, ext2_find_entry() will keep processing pages until the i_size is reached, even if there are no more blocks associated with the directory inode. This patch puts in some minimal sanity-checking so that we don't keep checking pages (and issuing errors) if we know there can be no more data to read, based on the block count of the directory inode. This is somewhat similar in approach to the ext3 patch I sent earlier this year. Signed-off-by: Eric Sandeen Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit 23c887522e912ca494950796a95df8dd210f4b01 Author: Mathieu Desnoyers Date: Sat Feb 10 01:45:05 2007 -0800 [PATCH] Relay: add CPU hotplug support Mathieu originally needed to add this for tracing Xen, but it's something that's needed for any application that can be tracing while cpus are added. unplug isn't supported by this patch. The thought was that at minumum a new buffer needs to be added when a cpu comes up, but it wasn't worth the effort to remove buffers on cpu down since they'd be freed soon anyway when the channel was closed. [zanussi@us.ibm.com: avoid lock_cpu_hotplug deadlock] Signed-off-by: Mathieu Desnoyers Cc: Tom Zanussi Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit 138c5d258cf06c278f5d7fe0a806e50fe413a08f Author: Atsushi Nemoto Date: Sat Feb 10 01:45:05 2007 -0800 [PATCH] serial: serial_txx9 driver update Update the serial_txx9 driver. * Configurable manumum port number. (SERIAL_TXX9_NR_UARTS) * Remove some code which is unneeded if CONFIG_PM=n. * Use PCI_DEVICE() for pci device id table and make it const. * Do not include Signed-off-by: Atsushi Nemoto Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit c376222960ae91d5ffb9197ee36771aaed1d9f90 Author: Robert P. J. Day Date: Sat Feb 10 01:45:03 2007 -0800 [PATCH] Transform kmem_cache_alloc()+memset(0) -> kmem_cache_zalloc(). Replace appropriate pairs of "kmem_cache_alloc()" + "memset(0)" with the corresponding "kmem_cache_zalloc()" call. Signed-off-by: Robert P. J. Day Cc: "Luck, Tony" Cc: Andi Kleen Cc: Roland McGrath Cc: James Bottomley Cc: Greg KH Acked-by: Joel Becker Cc: Steven Whitehouse Cc: Jan Kara Cc: Michael Halcrow Cc: "David S. Miller" Cc: Stephen Smalley Cc: James Morris Cc: Chris Wright Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit 1b135431abf5ea92e61bf4e91d93726c7b96da5f Author: Adrian Bunk Date: Sat Feb 10 01:45:02 2007 -0800 [PATCH] drivers/char/vc_screen.c: proper prototypes Add proper prototypes for two functions in drivers/char/vc_screen.c Signed-off-by: Adrian Bunk Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit 57a87bb0720a5cf7a9ece49a8c8ed288398fd1bb Author: Mike Frysinger Date: Sat Feb 10 01:45:01 2007 -0800 [PATCH] scrub non-__GLIBC__ checks in linux/socket.h and linux/stat.h Userspace should be worrying about userspace, so having the socket.h and stat.h pollute the namespace in the non-glibc case is wrong and pretty much prevents any other libc from utilizing these headers sanely unless they set up the __GLIBC__ define themselves (which sucks) Cc: "David S. Miller" Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit 4564f9e5fd00767d11fcf61e0d52787706dfcc87 Author: Tilman Schmidt Date: Sat Feb 10 01:45:00 2007 -0800 [PATCH] consolidate line discipline number definitions The line discipline numbers N_* are currently defined for each architecture individually, but (except for a seeming mistake) identically, in asm/termios.h. There is no obvious reason why these numbers should be architecture specific, nor any apparent relationship with the termios structure. The total number of these, NR_LDISCS, is defined in linux/tty.h anyway. So I propose the following patch which moves the definitions of the individual line disciplines to linux/tty.h too. Three of these numbers (N_MASC, N_PROFIBUS_FDL, and N_SMSBLOCK) are unused in the current kernel, but the patch still keeps the complete set in case there are plans to use them yet. Signed-off-by: Tilman Schmidt Cc: Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit 4a3b0a490d49ada8bbf3f426be1a0ace4dcd0a55 Author: Jan Blunck Date: Sat Feb 10 01:44:59 2007 -0800 [PATCH] igrab() should check for I_CLEAR When igrab() is calling __iget() on an inode it should check if clear_inode() has been called on the inode already. Otherwise there is a race window between clear_inode() and destroy_inode() where igrab() calls __iget() which leads to already free inodes on the inode lists. Signed-off-by: Vandana Rungta Signed-off-by: Jan Blunck Cc: Al Viro Cc: Neil Brown Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit 068135e63518314d4efd711142f674ad0841599e Author: Jason Baron Date: Sat Feb 10 01:44:59 2007 -0800 [PATCH] lockdep: add graph depth information to /proc/lockdep Generate locking graph information into /proc/lockdep, for lock hierarchy documentation and visualization purposes. sample output: c089fd5c OPS: 138 FD: 14 BD: 1 --..: &tty->termios_mutex -> [c07a3430] tty_ldisc_lock -> [c07a37f0] &port_lock_key -> [c07afdc0] &rq->rq_lock_key#2 The lock classes listed are all the first-hop lock dependencies that lockdep has seen so far. Signed-off-by: Ingo Molnar Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit 381a229209aa6f7f72375797b7bcfcfe2ae6fcbb Author: Jarek Poplawski Date: Sat Feb 10 01:44:58 2007 -0800 [PATCH] lockdep: more unlock-on-error fixes - returns after DEBUG_LOCKS_WARN_ON added in 3 places - debug_locks checking after lookup_chain_cache() added in __lock_acquire() - locking for testing and changing global variable max_lockdep_depth added in __lock_acquire() From: Ingo Molnar My __acquire_lock() cleanup introduced a locking bug: on SMP systems we'd release a non-owned graph lock. Fix this by moving the graph unlock back, and by leaving the max_lockdep_depth variable update possibly racy. (we dont care, it's just statistics) Also add some minimal debugging code to graph_unlock()/graph_lock(), which caught this locking bug. Signed-off-by: Jarek Poplawski Signed-off-by: Ingo Molnar Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit 898552c9d807fe59f3ecaf9c300c109358375c12 Author: Ingo Molnar Date: Sat Feb 10 01:44:57 2007 -0800 [PATCH] lockdep: also check for freed locks in kmem_cache_free() kmem_cache_free() was missing the check for freeing held locks. Signed-off-by: Ingo Molnar Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit 0c12b51712ced2c0d89a8ec3d546ed810f86d33e Author: Oleg Nesterov Date: Sat Feb 10 01:44:56 2007 -0800 [PATCH] kill_pid_info: kill acquired_tasklist_lock Kill acquired_tasklist_lock, sig_needs_tasklist() is very cheap nowadays. Signed-off-by: Oleg Nesterov Cc: "Eric W. Biederman" Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit b963a8441cb95999c97bea379607071a869c65f0 Author: Jiri Slaby Date: Sat Feb 10 01:44:55 2007 -0800 [PATCH] Char: tty_wakeup cleanup tty_wakeup cleanup - remove wake_up_interruptible(&tty->write_wait) surrounding tty_wakup(tty); - substitute tty->ldisc.write_wakeup(tty) + wake_up() by tty_wakeup(tty); Signed-off-by: Jiri Slaby Cc: Alan Cox Acked-by: Tilman Schmidt Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit 1ed0c0b7306d7c93e83ebe30087a12684b280cdc Author: Jiri Slaby Date: Sat Feb 10 01:44:55 2007 -0800 [PATCH] Char: isicom, correct probing/removing Don't forget to decrease card_count in fail paths and in remove function. Also null board->base in such cases to point out, that this structure is unused and thus can be reassigned. Signed-off-by: Jiri Slaby Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit 7edc136ab688f751037a86e8a051151d7962d33f Author: Jiri Slaby Date: Sat Feb 10 01:44:54 2007 -0800 [PATCH] Char: isicom, support higher rates Add support for higher baud rates (coming from original isi driver). Signed-off-by: Jiri Slaby Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit cb4a10ccb0c5b5b02dec1a4a97cba1e8b2c2a325 Author: Jiri Slaby Date: Sat Feb 10 01:44:53 2007 -0800 [PATCH] Char: isicom, check card state in isr Check if the card really interrupted us by reading its IO space and eventualy return IRQ_NONE. Signed-off-by: Jiri Slaby Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit f0a0ba6d69882ae14f24d7eb6e2ae07f30fbd56a Author: Jiri Slaby Date: Sat Feb 10 01:44:52 2007 -0800 [PATCH] Char: isicom, augment card_reset isicom, augment card_reset - add 0xee to signatures - change long delays to sleeps - make one sleep shorter not to wait 3s - portcount == 16 is also correct Signed-off-by: Jiri Slaby Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit 174f13076717b8c7b70a18a474a0541a31d24527 Author: Jiri Slaby Date: Sat Feb 10 01:44:52 2007 -0800 [PATCH] Char: isicom, fix locking in isr 2 spin_unlocks are omitted in the interrupt handler. Put them there to fix up deadlocking on UP. Signed-off-by: Jiri Slaby Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit 02d3fca0927279d15299e8c2b9e9e42ab29cee7f Author: Adrian Bunk Date: Sat Feb 10 01:44:51 2007 -0800 [PATCH] make drivers/char/mxser_new.c:mxser_hangup() static Signed-off-by: Adrian Bunk Cc: Jiri Slaby Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit a3569958728d511912bbe98f3770aa5ada34bd12 Author: Andreas Jaggi Date: Sat Feb 10 01:44:50 2007 -0800 [PATCH] mxser: remove ambiguous redefinition of INIT_WORK Removes an unused and ambiguous redefinition of INIT_WORK() Signed-off-by: Andreas Jaggi Acked-by: Jiri Slaby Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit 37756ced1f145aec18917812c3b8a96dbb47990d Author: Eric Dumazet Date: Sat Feb 10 01:44:49 2007 -0800 [PATCH] avoid one conditional branch in touch_atime() I added IS_NOATIME(inode) macro definition in include/linux/fs.h, true if the inode superblock is marked readonly or noatime. This new macro is then used in touch_atime() instead of separatly testing MS_RDONLY and MS_NOATIME Signed-off-by: Eric Dumazet Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit 4ba4d4c0c52201009232fe9e781a281054a24e75 Author: Eric Dumazet Date: Sat Feb 10 01:44:48 2007 -0800 [PATCH] struct vfsmount: keep mnt_count & mnt_expiry_mark away from mnt_flags I noticed cache misses in touch_atime() that can be avoided if we keep mnt_count & mnt_expiry_mark in a different cache line than mnt_flags (mostly read) mnt_count & mnt_expiry_mark are modified each time a file is opened/closed in a file system. touch_atime() is called each time a file is read, and generally needs to read mnt_flags. Other fields of struct vfsmount are mostly read so I chose to move mnt_count & mnt_expiry_mark at the end of struct vfsmount. And adding a comment so that nobody tries to re-arrange fields to fill the holes :) On 64bits platforms, the new offsetof(mnt_count) is 0xC0 On 32bits platforms, it is 0x60, so I didnot add a ____cacheline_aligned_in_smp because it would have a too big impact on the size of this object (in particular if CONFIG_X86_L1_CACHE_SHIFT=7) Signed-off-by: Eric Dumazet Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit 0aa5de8590d684274f57647a870851f101bb3543 Author: Jiri Slaby Date: Sat Feb 10 01:44:47 2007 -0800 [PATCH] Char: isicom, remove tty_{hang,wake}up bottomhalves - tty_hangup() itself schedules work, so there is no need to schedule hangup in the driver - tty_wakeup(): it's safe to call it while in atomic, so that its schedule_work might be also wiped out Signed-off-by: Jiri Slaby Acked-by: Alan Cox Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit 52c9ae0ac7576c94f6a2371b44039e7ba12a0439 Author: Brent Casavant Date: Sat Feb 10 01:44:46 2007 -0800 [PATCH] IOC3/IOC4: PCI mem space resources The SGI IOC3 and IOC4 PCI devices implement memory space apertures, not I/O space apertures. Use the appropriate region management functions. Signed-off-by: Brent Casavant Cc: Pat Gefre Cc: Stanislaw Skowronek Cc: Brent Casavant Acked-by: Ralf Baechle Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit 24fa50961451b7b21081e4d16836952b17eb5fb3 Author: Luciano Rocha Date: Sat Feb 10 01:44:45 2007 -0800 [PATCH] usr/gen_init_cpio.c: support for hard links Extend usr/gen_init_cpio.c "file" entry, adding support for hard links. Previous format: file New format: file [] The hard links specification is optional, keeping the previous behaviour. All hard links are defined sequentially in the resulting cpio and the file data is present only in the last link. This is the behaviour of GNU's cpio and is supported by the kernel initramfs extractor. Signed-off-by: Luciano Rocha Cc: Al Viro Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit 67d38229dfa64cf9a75f83746dde345f47bbd8dc Author: Jean-Paul Saman Date: Sat Feb 10 01:44:44 2007 -0800 [PATCH] disable init/initramfs.c: architectures Update all arch/*/kernel/vmlinux.lds.S to not include space for initramfs when CONFIG_BLK_DEV_INITRAMFS is not selected. This saves another 4 kbytes on most platfoms (some reserve PAGE_SIZE for initramfs). Signed-off-by: Jean-Paul Saman Cc: Al Viro Cc: Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit c33df4eaaf41fd3e34837a6ae9a5f9970c393d9f Author: Jean-Paul Saman Date: Sat Feb 10 01:44:43 2007 -0800 [PATCH] disable init/initramfs.c The file init/initramfs.c is always compiled and linked in the kernel vmlinux even when BLK_DEV_RAM and BLK_DEV_INITRD are disabled and the system isn't using any form of an initramfs or initrd. In this situation the code is only used to unpack a (static) default initial rootfilesystem. The current init/initramfs.c code. usr/initramfs_data.o compiles to a size of ~15 kbytes. Disabling BLK_DEV_RAM and BLK_DEV_INTRD shrinks the kernel code size with ~60 Kbytes. This patch avoids compiling in the code and data for initramfs support if CONFIG_BLK_DEV_INITRD is not defined. Instead of the initramfs code and data it uses a small routine in init/noinitramfs.c to setup an initial static default environment for mounting a rootfilesystem later on in the kernel initialisation process. The new code is: 164 bytes of size. The patch is separated in two parts: 1) doesn't compile initramfs code when CONFIG_BLK_DEV_INITRD is not set 2) changing all plaforms vmlinux.lds.S files to not reserve an area of PAGE_SIZE when CONFIG_BLK_DEV_INITRD is not set. [deweerdt@free.fr: warning fix] Signed-off-by: Jean-Paul Saman Cc: Al Viro Cc: Signed-off-by: Frederik Deweerdt Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit dd65aa6690e30fdad84a62191c7ab37da89d9865 Author: Jiri Slaby Date: Sat Feb 10 01:44:42 2007 -0800 [PATCH] Char: tty, delete wake_up_interruptible after tty_wakeup tty_wakeup calls wake_up_interruptible(&tty->write_wait) itself, it's not needed to wake up again after tty_wakeup returns. Signed-off-by: Jiri Slaby Cc: Alan Cox Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit 780a065668b1c6ca6a70c7d36b9f6552ea3bb5f5 Author: Andrew Morton Date: Sat Feb 10 01:44:41 2007 -0800 [PATCH] count_vm_events-warning-fix - Prevent things like this: block/ll_rw_blk.c: In function 'submit_bio': block/ll_rw_blk.c:3222: warning: unused variable 'count' inlines are very, very preferable to macros. - remove unused get_cpu_vm_events() macro Cc: Christoph Lameter Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit 7131b6d167b41593463ce98df17e101e776bf5ec Author: Adrian Bunk Date: Sat Feb 10 01:44:40 2007 -0800 [PATCH] remove include/linux/byteorder/pdp_endian.h include/linux/byteorder/pdp_endian.h is completely unused, and the comment in the file itself states that it's both untested and only a proof-of-concept. Signed-off-by: Adrian Bunk Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit 3ee75ac3c0f4904633322b7d9b111566fbc4a7d3 Author: Alexey Dobriyan Date: Sat Feb 10 01:44:39 2007 -0800 [PATCH] sysctl_{,ms_}jiffies: fix oldlen semantics currently it's 1) if *oldlenp == 0, don't writeback anything 2) if *oldlenp >= table->maxlen, don't writeback more than table->maxlen bytes and rewrite *oldlenp don't look at underlying type granularity 3) if 0 < *oldlenp < table->maxlen, *cough* string sysctls don't writeback more than *oldlenp bytes. OK, that's because sizeof(char) == 1 int sysctls writeback anything in (0, table->maxlen] range Though accept integers divisible by sizeof(int) for writing. sysctl_jiffies and sysctl_ms_jiffies don't writeback anything but sizeof(int), which violates 1) and 2). So, make sysctl_jiffies and sysctl_ms_jiffies accept a) *oldlenp == 0, not doing writeback b) *oldlenp >= sizeof(int), writing one integer. -EINVAL still returned for *oldlenp == 1, 2, 3. Signed-off-by: Alexey Dobriyan Cc: "Eric W. Biederman" Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit 8b6312f4dcc1efe7975731b6c47dd134282bd9ac Author: Eric W. Biederman Date: Sat Feb 10 01:44:34 2007 -0800 [PATCH] vt: refactor console SAK processing This does several things. - It moves looking up of the current foreground console into process context where we can safely take the semaphore that protects this operation. - It uses the new flavor of work queue processing. - This generates a factor of do_SAK, __do_SAK that runs immediately. - This calls __do_SAK with the console semaphore held ensuring nothing else happens to the console while we process the SAK operation. - With the console SAK processing moved into process context this patch removes the xchg operations that I used to attempt to attomically update struct pid, because of the strange locking used in the SAK processing. With SAK using the normal console semaphore nothing special is needed. Cc: Oleg Nesterov Signed-off-by: Eric W. Biederman Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit 0a7b35cb18c52d651f6ed9cd59edc979200ab880 Author: Michael Neuling Date: Sat Feb 10 01:44:33 2007 -0800 [PATCH] Add retain_initrd boot option Add retain_initrd option to control freeing of initrd memory after extraction. By default, free memory as previously. The first boot will need to hold a copy of the in memory fs for the second boot. This image can be large (much larger than the kernel), hence we can save time when the memory loader is slow. Also, it reduces the memory footprint while extracting the first boot since you don't need another copy of the fs. Signed-off-by: Michael Neuling Cc: "Randy.Dunlap" Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit 70e840499aae90be1de542894062ad2899d23642 Author: Miguel Ojeda Sandonis Date: Sat Feb 10 01:44:32 2007 -0800 [PATCH] drivers: add LCD support Add support for auxiliary displays, the ks0108 LCD controller, the cfag12864b LCD and adds a framebuffer device: cfag12864bfb. - Add a "auxdisplay/" folder in "drivers/" for auxiliary display drivers. - Add support for the ks0108 LCD Controller as a device driver. (uses parport interface) - Add support for the cfag12864b LCD as a device driver. (uses ks0108 LCD Controller driver) - Add a framebuffer device called cfag12864bfb. (uses cfag12864b LCD driver) - Add the usual Documentation, includes, Makefiles, Kconfigs, MAINTAINERS, CREDITS... - Miguel Ojeda will maintain all the stuff above. [rdunlap@xenotime.net: workqueue fixups] [akpm@osdl.org: kconfig fix] Signed-off-by: Miguel Ojeda Sandonis Cc: Greg KH Acked-by: Paulo Marques Cc: "Randy.Dunlap" Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit 81d79bec348ab06cba9ae9fc03eb015b6b83703a Author: Ahmed S. Darwish Date: Sat Feb 10 01:44:30 2007 -0800 [PATCH] V850: user ARRAY_SIZE macro when appropriate Use ARRAY_SIZE macro already defined in linux/kernel.h Signed-off-by: Ahmed S. Darwish Cc: Miles Bader Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit 6e6d74cfac782a3a4cb5111bd9c25cd95d6b7c6c Author: Jeff Dike Date: Sat Feb 10 01:44:30 2007 -0800 [PATCH] uml: x86_64 ptrace fixes This patch fixes some missing ptrace bits on x86_64. PTRACE_ARCH_PRCTL is hooked up and implemented. This required generalizing arch_prctl_skas slightly to take a task_struct to modify. Previously, it always operated on current. Reading and writing the debug registers is also enabled by un-ifdefing the code that implements that. It turns out that x86_64 is identical to i386, so the same code can be used. Signed-off-by: Jeff Dike Cc: Paolo 'Blaisorblade' Giarrusso Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit f355559cf78455ed6be103b020e4b800230c64eb Author: Jeff Dike Date: Sat Feb 10 01:44:29 2007 -0800 [PATCH] uml: x86_64 thread fixes x86_64 needs some TLS fixes. What was missing was remembering the child thread id during clone and stuffing it into the child during each context switch. The %fs value is stored separately in the thread structure since the host controls what effect it has on the actual register file. The host also needs to store it in its own thread struct, so we need the value kept outside the register file. arch_prctl_skas was fixed to call PTRACE_ARCH_PRCTL appropriately. There is some saving and restoring of registers in the ARCH_SET_* cases so that the correct set of registers are changed on the host and restored to the process when it runs again. Signed-off-by: Jeff Dike Cc: Paolo 'Blaisorblade' Giarrusso Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit 3a150e1da8bc4e840d5a09fc089052011b5b6503 Author: Jeff Dike Date: Sat Feb 10 01:44:28 2007 -0800 [PATCH] uml: fix error output during early boot The startup code panics a lot if anything goes wrong early on. This is wrong for several reasons, like the kernel isn't running, so you can't really be calling into it yet, but the harm comes from useful error messages being trapped in the printk ring where no one will ever see them. This patch changes these panics to perror and printf in wrappers which also exit. Normal, informational, prints are also wrapped so that fflush(stdout) is called after each one. This is so the output appears in the correct sequence in the event of an error. Signed-off-by: Jeff Dike Cc: Paolo 'Blaisorblade' Giarrusso Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit 9683da91e2db323ee728041576e29ad7fa9547b9 Author: Jeff Dike Date: Sat Feb 10 01:44:27 2007 -0800 [PATCH] uml: AIO locking and tidying Comment the lack of locking of data that's set up once at boot time. Also fixed a couple of bogus printks. Signed-off-by: Jeff Dike Cc: Paolo 'Blaisorblade' Giarrusso Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit 6c59e2f593d0c00c78ec48146de6eaf52a342dd5 Author: Jeff Dike Date: Sat Feb 10 01:44:26 2007 -0800 [PATCH] uml: register handling formatting fixes Formatting fixes in the register handling code. Signed-off-by: Jeff Dike Cc: Paolo 'Blaisorblade' Giarrusso Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit c538b391a7e8f3cb5d7756ec68d1864429d26a0c Author: Jeff Dike Date: Sat Feb 10 01:44:26 2007 -0800 [PATCH] uml: ELF locking commentary Comment the lack of locking of the elf data extracted from the ELF headers passed to UML. Signed-off-by: Jeff Dike Cc: Paolo 'Blaisorblade' Giarrusso Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit de5fe76e436d9e98f8af8005ff23a2e6066aea10 Author: Jeff Dike Date: Sat Feb 10 01:44:25 2007 -0800 [PATCH] uml: umid tidying Add an error message when two umids are put on the command line. umid.h is kind of pointless since it only declares one thing, and that is already declared in os.h. Commented the lack of locking of some data in os-Linux/umid.h. Signed-off-by: Jeff Dike Cc: Paolo 'Blaisorblade' Giarrusso Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit 4cffb7fa69349d48d900d98766dc9ad52d9c851e Author: Jeff Dike Date: Sat Feb 10 01:44:24 2007 -0800 [PATCH] uml: SIGIO formatting fixes Fix formatting in the sigio code. Signed-off-by: Jeff Dike Cc: Paolo 'Blaisorblade' Giarrusso Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit d9f9d31983aac7764d178583d0777199d081cb1a Author: Jeff Dike Date: Sat Feb 10 01:44:23 2007 -0800 [PATCH] uml: SIGIO locking comment Comment the use of a mysterious-looking lock. Signed-off-by: Jeff Dike Cc: Paolo 'Blaisorblade' Giarrusso Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit f2e62992a232544d612b7b95e932fbf3592944e1 Author: Jeff Dike Date: Sat Feb 10 01:44:23 2007 -0800 [PATCH] uml: IRQ handler tidying Tidying the irq code - make a variable static activate_fd can call kmalloc directly since it's now kernel code added a no-locking comment fixed a style violation Signed-off-by: Jeff Dike Cc: Paolo 'Blaisorblade' Giarrusso Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit f688144b827749879279c3ad272b8d874fc17231 Author: Robert P. J. Day Date: Sat Feb 10 01:44:22 2007 -0800 [PATCH] uml: fix apparent "CONFIG_64_BIT" typo. Fix apparent typo, where CONFIG_64_BIT should read CONFIG_64BIT. Signed-off-by: Robert P. J. Day Cc: Jeff Dike Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit 81999a01c786e26c2058968d76b595df60d2f8da Author: Jeff Dike Date: Sat Feb 10 01:44:21 2007 -0800 [PATCH] uml: fix style violations Fix a bunch of style violations in mem.c. Signed-off-by: Jeff Dike Cc: Paolo 'Blaisorblade' Giarrusso Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit 73c8f4441f07dd3b9d198ec0e97ce83138a6224c Author: Jeff Dike Date: Sat Feb 10 01:44:20 2007 -0800 [PATCH] uml: libc-dependent code should call libc directly We shouldn't be using the os wrappers from os code - we can use libc directly. This patch replaces wrapper calls with libc calls. It turns out that os_sigio_async had only one caller, which was in startup.c, so that function is moved there and its name changed. Signed-off-by: Jeff Dike Cc: Paolo 'Blaisorblade' Giarrusso Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit 9eae9b132cd2cebf98cc45550049d421302b9aba Author: Jeff Dike Date: Sat Feb 10 01:44:20 2007 -0800 [PATCH] uml: style fixes in startup code Some style fixes in startup.c. Signed-off-by: Jeff Dike Cc: Paolo 'Blaisorblade' Giarrusso Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit 7242a4005d1c496bc1140d56a0d898cde1b3e3f6 Author: Jeff Dike Date: Sat Feb 10 01:44:19 2007 -0800 [PATCH] uml: locking comments in startup code Add a couple of comments about some non-locked data. Signed-off-by: Jeff Dike Cc: Paolo 'Blaisorblade' Giarrusso Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit 6bf79482f3288e19697d08c456b0bd6b1755d467 Author: Jeff Dike Date: Sat Feb 10 01:44:18 2007 -0800 [PATCH] uml: locking comments in memory and tempfile code Locking comments and emacs comment removal in the low-level memory and temp file code. Signed-off-by: Jeff Dike Cc: Paolo 'Blaisorblade' Giarrusso Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit b8831a1d2c78c03b8193ab3acf56664fa3457265 Author: Jeff Dike Date: Sat Feb 10 01:44:17 2007 -0800 [PATCH] uml: locking fixes in the ubd driver Some small locking and formatting fixes in the ubd driver. Signed-off-by: Jeff Dike Cc: Paolo 'Blaisorblade' Giarrusso Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit 62f96cb01e8de7a5daee472e540f726db2801499 Author: Jeff Dike Date: Sat Feb 10 01:44:16 2007 -0800 [PATCH] uml: add per-device queues and locks to ubd driver Replace global queue and lock with per-device queues and locks. Mostly a straightforward replacement of ubd_io_lock with dev->lock and ubd_queue with dev->queue. Complications - There was no way to get a request struct (and queue) from the structure sent to the io_thread, so a pointer to the request was added. This is needed in ubd_handler in order to kick do_ubd_request to process another request. Queue initialization is moved from ubd_init to ubd_add. Signed-off-by: Jeff Dike Cc: Paolo 'Blaisorblade' Giarrusso Cc: Jens Axboe Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit 92b4202f38cf630350a9e1eb0ab23ca4fc5b687b Author: Jeff Dike Date: Sat Feb 10 01:44:15 2007 -0800 [PATCH] uml: remove code controlled by non-existent config option CONFIG_HOST_TASK_SIZE doesn't exist any more. Signed-off-by: Jeff Dike Cc: Paolo 'Blaisorblade' Giarrusso Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit 0d0d0ed426f8f5ba6b74ba30fcdcd27c54ce4724 Author: Jeff Dike Date: Sat Feb 10 01:44:15 2007 -0800 [PATCH] uml: const a variable kstack_depth_to_print can be made const. Signed-off-by: Jeff Dike Cc: Paolo 'Blaisorblade' Giarrusso Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit 27aa6ef3c0e8220b27b0a8d2d0bae7cd0a6d2f78 Author: Jeff Dike Date: Sat Feb 10 01:44:14 2007 -0800 [PATCH] uml: make signal handlers static A bunch of the signal handlers can be made static. Signed-off-by: Jeff Dike Cc: Paolo 'Blaisorblade' Giarrusso Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit 6d1b18b16fc917e5c9af568a53c7e37923821d70 Author: Jeff Dike Date: Sat Feb 10 01:44:13 2007 -0800 [PATCH] uml: remove unused variable and function syscall_index and next_syscall_index turn out not to be used. Signed-off-by: Jeff Dike Cc: Paolo 'Blaisorblade' Giarrusso Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit b42e1eacc1f245581a2f7580ec1082ff4d6c65cd Author: Jeff Dike Date: Sat Feb 10 01:44:12 2007 -0800 [PATCH] uml: delete unused file It turns out that resource.c isn't needed. Signed-off-by: Jeff Dike Cc: Paolo 'Blaisorblade' Giarrusso Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit 490ba1714b31a131cdc6318231aa227d19bf0761 Author: Jeff Dike Date: Sat Feb 10 01:44:12 2007 -0800 [PATCH] uml: make time data per-cpu prev_nsecs and delta need to be arrays, and indexed by CPU number. Signed-off-by: Jeff Dike Cc: Paolo 'Blaisorblade' Giarrusso Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit c0961c1804c46bf5bb253e1bd6bc93e4627b79a1 Author: Jeff Dike Date: Sat Feb 10 01:44:11 2007 -0800 [PATCH] uml: initialize a list head We need to initialize lists properly. Signed-off-by: Jeff Dike Cc: Paolo 'Blaisorblade' Giarrusso Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit 60678bbc76685bea47043e61981b8fc5cffc10da Author: Jeff Dike Date: Sat Feb 10 01:44:10 2007 -0800 [PATCH] uml: mem.c and physmem.c formatting fixes Fix a bunch of style violations in mem.c and physmem.c Signed-off-by: Jeff Dike Cc: Paolo 'Blaisorblade' Giarrusso Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit 94c282d79e17a83ccc876990e05378ed6dfbccae Author: Jeff Dike Date: Sat Feb 10 01:44:09 2007 -0800 [PATCH] uml: locking comments in iomem driver Comment some lack of locking in the iomem driver. Also, a couple of variables are in the wrong place, so they are moved. Signed-off-by: Jeff Dike Cc: Paolo 'Blaisorblade' Giarrusso Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit c6256c68248cfccbeec07ced442ffe395fa393e8 Author: Jeff Dike Date: Sat Feb 10 01:44:08 2007 -0800 [PATCH] uml: fix previous console locking Eliminate the open_mutex after complaints from Blaisorblade. It turns out that the tty count provides the information needed to tell whether we are the first opener or last closer. Signed-off-by: Jeff Dike Cc: Paolo 'Blaisorblade' Giarrusso Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit d5c9ffc6c6d15d4f655236e26942a21ad61fe3ad Author: Jeff Dike Date: Sat Feb 10 01:44:08 2007 -0800 [PATCH] uml: console locking commentary and code cleanup Remove the last vestiges of devfs from console registration. Change the name of the function, plus remove a couple of unused fields from the line_driver structure. struct lines is no longer needed, all traces of it are gone. The only way that I can see to mark a structure as being almost-const is to individually const the fields. This is the case for the line_driver structure, which has only one modifiable field - a list_head in a sub-structure. Signed-off-by: Jeff Dike Cc: Paolo 'Blaisorblade' Giarrusso Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit b4ac91a0eac36f347a509afda07e4305e931de61 Author: Jeff Dike Date: Sat Feb 10 01:44:07 2007 -0800 [PATCH] uml: chan_user.h formatting fixes Whitespace fixes and emacs comment removal. Signed-off-by: Jeff Dike Cc: Paolo 'Blaisorblade' Giarrusso Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit a52f362f864f56238c9036f5c56f763a80e2ddd5 Author: Jeff Dike Date: Sat Feb 10 01:44:06 2007 -0800 [PATCH] uml: mostly const a structure The chan_opts structure is mostly const, and needs no locking. Comment the lack of locking on the one field that can change. Make all the other fields const. It turned out that console_open_chan didn't use its chan_opts argument, so that is deleted from the function and its callers. Signed-off-by: Jeff Dike Cc: Paolo 'Blaisorblade' Giarrusso Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit 99b0278f95fc9d55adf65133dc678167a88b632a Author: Jeff Dike Date: Sat Feb 10 01:44:05 2007 -0800 [PATCH] uml: locking commentary in the random driver Comment the lack of locking. Signed-off-by: Jeff Dike Cc: Paolo 'Blaisorblade' Giarrusso Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit c59bce6262f9511c8e2504231f60609bf7332833 Author: Jeff Dike Date: Sat Feb 10 01:44:04 2007 -0800 [PATCH] uml: use LIST_HEAD where possible A couple of list_head declarations can be improved through the use of LIST_HEAD(). Signed-off-by: Jeff Dike Cc: Paolo 'Blaisorblade' Giarrusso Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit c862fc32a3ee4319c652f4ff39462d030120c380 Author: Jeff Dike Date: Sat Feb 10 01:44:04 2007 -0800 [PATCH] uml: network driver locking and code cleanup Add some missing locking to walks of the transports and opened lists. Delete some dead code. Comment the lack of some locking. Signed-off-by: Jeff Dike Cc: Paolo 'Blaisorblade' Giarrusso Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit f9795220521e0575dfd4ed0737d3a7848264662c Author: Jeff Dike Date: Sat Feb 10 01:44:03 2007 -0800 [PATCH] uml: Kill a compilation warning Kill a compilation warning. Signed-off-by: Jeff Dike Cc: Paolo 'Blaisorblade' Giarrusso Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit 67608e0c809ceca1b44755ee818199af7478ca77 Author: Jeff Dike Date: Sat Feb 10 01:44:02 2007 -0800 [PATCH] uml: port driver formatting Whitespace and style fixes. Signed-off-by: Jeff Dike Cc: Paolo 'Blaisorblade' Giarrusso Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit d832fc60d533d52da7170cf5f95271c331259bca Author: Jeff Dike Date: Sat Feb 10 01:44:01 2007 -0800 [PATCH] uml: make two variables static Make a couple of variables static. Signed-off-by: Jeff Dike Cc: Paolo 'Blaisorblade' Giarrusso Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit 84f48d4f2b511db15fda67fd38462b91abd0af53 Author: Jeff Dike Date: Sat Feb 10 01:44:01 2007 -0800 [PATCH] uml: mconsole locking Locking fixes. Locking was totally lacking for the mconsole_devices, which got a spin lock, and the unplugged pages data, which got a mutex. The locking of the mconsole console output code was confused. Now, the console_lock (renamed to client_lock) protects the clients list. Signed-off-by: Jeff Dike Cc: Paolo 'Blaisorblade' Giarrusso Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit d471c0fca7eae1ffd4f7d4c11ee835ff70aaa71f Author: Jeff Dike Date: Sat Feb 10 01:44:00 2007 -0800 [PATCH] uml: audio driver formatting Whitespace and style fixes. Signed-off-by: Jeff Dike Cc: Paolo 'Blaisorblade' Giarrusso Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit b612e475e75f860002d88dd8440ce250506c5094 Author: Jeff Dike Date: Sat Feb 10 01:43:59 2007 -0800 [PATCH] uml: audio driver locking Comment the lack of locking and make a couple of variables static. Signed-off-by: Jeff Dike Cc: Paolo 'Blaisorblade' Giarrusso Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit 5bbcbeca2c8933ee2b3402ea5eca523d971a8785 Author: Jeff Dike Date: Sat Feb 10 01:43:58 2007 -0800 [PATCH] uml: watchdog driver formatting Whitespace and style fixes. Signed-off-by: Jeff Dike Cc: Paolo 'Blaisorblade' Giarrusso Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit 42d36115d25725fb551250c8f70602a12aa8dee2 Author: Jeff Dike Date: Sat Feb 10 01:43:57 2007 -0800 [PATCH] uml: watchdog driver locking Replace BKL use with a spinlock. Also fix the control so that open doesn't return holding a lock. Signed-off-by: Jeff Dike Cc: Paolo 'Blaisorblade' Giarrusso Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit 4ea21cd9173a0ffa75dc74cc46d08dfc45654f29 Author: Jeff Dike Date: Sat Feb 10 01:43:56 2007 -0800 [PATCH] uml: network driver whitespace and style fixes Some whitespace and coding style cleanups in the network driver code. Signed-off-by: Jeff Dike Cc: Paolo 'Blaisorblade' Giarrusso Acked-by: Jeff Garzik Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit d3b7f69de2b92e4b6057d81e6c52f629a8663368 Author: Jeff Dike Date: Sat Feb 10 01:43:56 2007 -0800 [PATCH] uml: add locking to network transport registration The registration of host network transports needed some locking. The transport list itself is locked, but calls to the registration routines are not. This is compensated for by checking that a transport structure is not yet on any list. I also took the opportunity to const all fields in the transport structure except the list, which obviously can be modified. Signed-off-by: Jeff Dike Cc: Paolo 'Blaisorblade' Giarrusso Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit 190c3e456325942a17785332fe15b68eeb3775ca Author: Jeff Dike Date: Sat Feb 10 01:43:55 2007 -0800 [PATCH] uml: lock the irqs_to_free list Fix (i.e. add some) the locking around the irqs_to_free list. Signed-off-by: Jeff Dike Cc: Paolo 'Blaisorblade' Giarrusso Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit 894be2a485b75bce9a4d45d3e431aafd4c89f1ea Author: Jeff Dike Date: Sat Feb 10 01:43:54 2007 -0800 [PATCH] uml: console whitespace and comment tidying Some comment and whitespace cleanups in the console and mconsole code. Signed-off-by: Jeff Dike Cc: Paolo 'Blaisorblade' Giarrusso Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit f28169d2000177e8b72ccc6d72887be779dceca8 Author: Jeff Dike Date: Sat Feb 10 01:43:53 2007 -0800 [PATCH] uml: return hotplug errors to host I noticed that errors happening while hotplugging devices from the host were never returned back to the mconsole client. In some cases, success was returned instead of even an information-free error. This patch cleans that up by having the low-level configuration code pass back an error string along with an error code. At the top level, which knows whether it is early boot time or responding to an mconsole request, the string is printk'd or returned to the mconsole client. There are also whitespace and trivial code cleanups in the surrounding code. Signed-off-by: Jeff Dike Cc: Paolo 'Blaisorblade' Giarrusso Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit d79a580936396bbcd2f4fae2c6215f9cf81e3c0d Author: Jeff Dike Date: Sat Feb 10 01:43:52 2007 -0800 [PATCH] uml: console locking fixes Clean up the console driver locking. There are various problems here, including sleeping under a spinlock and spinlock recursion, some of which are fixed here. This patch deals with the locking involved with opens and closes. The problem is that an mconsole request to change a console's configuration can race with an open. Changing a configuration should only be done when a console isn't opened. Also, an open must be looking at a stable configuration. In addition, a get configuration request must observe the same locking since it must also see a stable configuration. With the old locking, it was possible for this to hang indefinitely in some cases because open would block for a long time waiting for a connection from the host while holding the lock needed by the mconsole request. As explained in the long comment, this is fixed by adding a spinlock for the use count and configuration and a mutex for the actual open and close. Signed-off-by: Jeff Dike Cc: Paolo 'Blaisorblade' Giarrusso Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit 5cf885d01f30be710a339976c485f92bb8a8946d Author: Jiri Kosina Date: Sat Feb 10 01:43:51 2007 -0800 [PATCH] CRIS: TLB handling: turn local_save_flags() + local_irq_disable() into local_irq_save() TLB handling for CRIS contains local_irq_disable() after local_save_flags(). Turn this into local_irq_save(). Signed-off-by: Jiri Kosina Cc: Mikael Starvik Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit 8447157a1ac467fae2125074f3693f557c8e05d3 Author: Ahmed S. Darwish Date: Sat Feb 10 01:43:51 2007 -0800 [PATCH] CRIS: user ARRAY_SIZE macro when appropriate Use ARRAY_SIZE macro already defined in linux/kernel.h Signed-off-by: Ahmed S. Darwish Cc: Mikael Starvik Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit 047c7c42327433a13ed2971de41ef7c6943b37ec Author: Jiri Kosina Date: Sat Feb 10 01:43:50 2007 -0800 [PATCH] CRIS: turn local_save_flags() + local_irq_disable() into local_irq_save() in headers Various headers for CRIS architecture contain local_irq_disable() after local_save_flags(). Turn it into local_irq_save(). Signed-off-by: Jiri Kosina Cc: Mikael Starvik Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit 7c101b7b13707f84791441fd04f11cf710d0d2d9 Author: Jiri Kosina Date: Sat Feb 10 01:43:49 2007 -0800 [PATCH] CRIS: local_irq_disable() is redundant after local_irq_save() arch/cris/arch-v10/kernel/time.c::get_ns_in_jiffie() contains local_irq_disable() call after local_irq_save(). This looks redundant. arch/cris/kernel/time.c::do_gettimeofday() contains local_irq_disable() call after local_irq_save(). This looks redundant. Signed-off-by: Jiri Kosina Cc: Mikael Starvik Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit 36dbf95868007b2dd236836f5420d3cb788da029 Author: Mike Frysinger Date: Sat Feb 10 01:43:48 2007 -0800 [PATCH] m68k: don't include asm-m68k/page.h in asm-m68k/user.h We don't actually use anything from asm-m68k/page.h in asm-m68k/user.h, so don't bother including it Signed-off-by: Mike Frysinger Cc: Geert Uytterhoeven Cc: Roman Zippel Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit ea5e1a827abe1e9ba1c8d214b7408b6c363d764a Author: Ahmed S. Darwish Date: Sat Feb 10 01:43:47 2007 -0800 [PATCH] M68K: user ARRAY_SIZE macro when appropriate Use ARRAY_SIZE macro already defined in linux/kernel.h Signed-off-by: Ahmed S. Darwish Cc: Roman Zippel Cc: Geert Uytterhoeven Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit bf0059b23fd2f0b304f647d87fad0aa626ecf0c0 Author: Ahmed S. Darwish Date: Sat Feb 10 01:43:46 2007 -0800 [PATCH] M68KNOMMU: user ARRAY_SIZE macro when appropriate Use ARRAY_SIZE macro already defined in linux/kernel.h Signed-off-by: Ahmed S. Darwish Signed-off-by: Greg Ungerer Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit dc29a3657b52ac687970d81d7194cf4238702124 Author: Mathieu Desnoyers Date: Sat Feb 10 01:43:43 2007 -0800 [PATCH] kernel/time/clocksource.c needs struct task_struct on m68k kernel/time/clocksource.c needs struct task_struct on m68k. Because it uses spin_unlock_irq(), which, on m68k, uses hardirq_count(), which uses preempt_count(), which needs to dereference struct task_struct, we have to include sched.h. Because it would cause a loop inclusion, we cannot include sched.h in any other of asm-m68k/system.h, linux/thread_info.h, linux/hardirq.h, which leaves this ugly include in a C file as the only simple solution. Signed-off-by: Mathieu Desnoyers Cc: Ingo Molnar Cc: Roman Zippel Cc: Thomas Gleixner Cc: Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit 38135614ddef4de16d5cdf03c2717e88b97dd2ab Author: Al Viro Date: Sat Feb 10 01:43:41 2007 -0800 [PATCH] m68k: work around binutils tokenizer change Recent as(1) doesn't think that . terminates a macro name, so getuser.l is _not_ treated as invoking getuser with .l as the first argument. arch/m68k/math-emu relies on old behaviour, so it gets a lot of undefined macros with more or less current binutils. Note that this behaviour remains in all recent versions and is unrelated to another binutils problems we used to have for a while (having (%a0)+ parsed as two arguments). This one is there to stay; it's an intentional and documented change. .irp [text] .endr expands to a copy of text per each word, with \ replaced with corresponding word. Again, what happens depends on whether gas_ident.x is treated as one or as two tokens; in the former case we'll get old_gas incremented once, in the latter - twice. The rest is obvious. Unlike .macro argument list _anything_ is explicitly allowed after .irp ; here we are on very safe ground. And yes, it does work with all gas variants I've got here (including vanilla 2.15, 2.16, 2.16.1 and 2.17, plus debian and FC binutils). Signed-off-by: Al Viro Cc: Roman Zippel Cc: Geert Uytterhoeven Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit fabb626ad6a3744b9f0eaae215a2418d521c1e14 Author: Hirokazu Takata Date: Sat Feb 10 01:43:40 2007 -0800 [PATCH] m32r: cosmetic updates and trivial fixes Cosmetic updates and trivial fixes of m32r arch-dependent files. - Remove RCS ID strings and trailing white lines - Other misc. cosmetic updates Signed-off-by: Hirokazu Takata Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit 3d60f849341ac00e3dc47a3af94aaf9ba46d00fb Author: Hirokazu Takata Date: Sat Feb 10 01:43:39 2007 -0800 [PATCH] m32r: fix kernel entry address of vmlinux This patch fixes the kernel entry point address of vmlinux. The m32r kernel entry address is 0x08002000 (physical). But, so far, the ENTRY point written in vmlinux.lds.S was not point the correct kernel entry address. (before fix) $ objdump -x vmlinux vmlinux: file format elf32-m32r-linux vmlinux architecture: m32r2, flags 0x00000112: EXEC_P, HAS_SYMS, D_PAGED start address 0x88002090 /* NG */ : Sections: Idx Name Size VMA LMA File off Algn 0 .empty_zero_page 00001000 88001000 88001000 00001000 2**12 CONTENTS, ALLOC, LOAD, DATA 1 .boot 0000008c 88002000 88002000 00002000 2**2 CONTENTS, ALLOC, LOAD, READONLY, CODE 2 .text 001ab694 88002090 88002090 00002090 2**4 CONTENTS, ALLOC, LOAD, READONLY, CODE : (after fix) $ objdump -x vmlinux vmlinux: file format elf32-m32r-linux vmlinux architecture: m32r2, flags 0x00000112: EXEC_P, HAS_SYMS, D_PAGED start address 0x08002000 /* OK */ : This fix also remedies the following GDB error message (of gdb-6.4 or after) at the first operation of kernel debugging: "Previous frame identical to this frame (corrupt stack?)". Signed-off-by: Hirokazu Takata Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit 4aa3b3ccfc6abda052a1bbd9cf018d51c1689836 Author: Hirokazu Takata Date: Sat Feb 10 01:43:37 2007 -0800 [PATCH] m32r: update defconfig files for v2.6.19 This patch upgrades defconfig files for all m32r platforms. Signed-off-by: Hirokazu Takata Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit 9b87ed790714bd3a8d492feb24f6c48f8bb59c3a Author: Hirokazu Takata Date: Sat Feb 10 01:43:37 2007 -0800 [PATCH] m32r: fix do_page_fault and update_mmu_cache Fix do_page_fault and update_mmu_cache. * Fix do_page_fault (vmalloc_fault:) to pass error_code correctly to update_mmu_cache by using a thread-fault code for all m32r chips. * Fix update_mmu_cache for OPSP chip - #ifdef CONFIG_CHIP_OPSP portion is a workaround of OPSP; Add a notfound-case operation to update_mmu_cache for OPSP like other m32r chip. - Fix pte_data that was not initialized if no entry found. Signed-off-by: Kazuhiro Inaoka Signed-off-by: Hirokazu Takata Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit 9674dcf795a4c7384e4e42c8f38fcb87517b1a43 Author: Hirokazu Takata Date: Sat Feb 10 01:43:35 2007 -0800 [PATCH] m32r: build fix for processors without ISA_DSP_LEVEL2 Additional fixes for processors without ISA_DSP_LEVEL2. sigcontext_t does not have dummy_acc1h, dummy_acc1l members any longer. Signed-off-by: Hirokazu Takata Cc: Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit 2b5b09b3b576d7323d8b4244429a83f16dc5446a Author: Rafael J. Wysocki Date: Sat Feb 10 01:43:35 2007 -0800 [PATCH] swsusp: Change pm_ops handling by userland interface Make the userland interface of swsusp call pm_ops->finish() after enable_nonboot_cpus() and before resume_device(), as indicated by the recent discussion on Linux-PM (cf. http://lists.osdl.org/pipermail/linux-pm/2006-November/004164.html). This patch changes the SNAPSHOT_PMOPS ioctl so that its first function, PMOPS_PREPARE, only sets a switch turning the platform suspend mode on, and its last function, PMOPS_FINISH, only checks if the platform mode is enabled. This should allow the older userland tools to work with new kernels without any modifications. The changes here only affect the userland interface of swsusp. Signed-off-by: Rafael J. Wysocki Acked-by: Pavel Machek Cc: Greg KH Cc: Nigel Cunningham Cc: Patrick Mochel Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit d12c610e08022a1b84d6bd4412c189214d32e713 Author: Andrew Morton Date: Sat Feb 10 01:43:34 2007 -0800 [PATCH] swsusp-change-code-ordering-in-userc-sanity The compiler will do that. And if it doesn't, we don't want to either ;) Cc: Rafael J. Wysocki Cc: Pavel Machek Cc: Greg KH Cc: Nigel Cunningham Cc: Patrick Mochel Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit 259130526c267550bc365d3015917d90667732f1 Author: Rafael J. Wysocki Date: Sat Feb 10 01:43:33 2007 -0800 [PATCH] swsusp: Change code ordering in user.c Change the ordering of code in kernel/power/user.c so that device_suspend() is called before disable_nonboot_cpus() and device_resume() is called after enable_nonboot_cpus(). This is needed to make the userland suspend call pm_ops->finish() after enable_nonboot_cpus() and before device_resume(), as indicated by the recent discussion on Linux-PM (cf. http://lists.osdl.org/pipermail/linux-pm/2006-November/004164.html). The changes here only affect the userland interface of swsusp. Signed-off-by: Rafael J. Wysocki Acked-by: Pavel Machek Cc: Greg KH Cc: Nigel Cunningham Cc: Patrick Mochel Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit ed746e3b18f4df18afa3763155972c5835f284c5 Author: Rafael J. Wysocki Date: Sat Feb 10 01:43:32 2007 -0800 [PATCH] swsusp: Change code ordering in disk.c Change the ordering of code in kernel/power/disk.c so that device_suspend() is called before disable_nonboot_cpus() and platform_finish() is called after enable_nonboot_cpus() and before device_resume(), as indicated by the recent discussion on Linux-PM (cf. http://lists.osdl.org/pipermail/linux-pm/2006-November/004164.html). The changes here only affect the built-in swsusp. [alexey.y.starikovskiy@linux.intel.com: fix LED blinking during image load] Signed-off-by: Rafael J. Wysocki Acked-by: Pavel Machek Cc: Greg KH Cc: Nigel Cunningham Cc: Patrick Mochel Cc: Alexey Starikovskiy Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit e3c7db621bed4afb8e231cb005057f2feb5db557 Author: Rafael J. Wysocki Date: Sat Feb 10 01:43:31 2007 -0800 [PATCH] PM: Change code ordering in main.c As indicated in a recent thread on Linux-PM, it's necessary to call pm_ops->finish() before devce_resume(), but enable_nonboot_cpus() has to be called before pm_ops->finish() (cf. http://lists.osdl.org/pipermail/linux-pm/2006-November/004164.html). For consistency, it seems reasonable to call disable_nonboot_cpus() after device_suspend(). This way the suspend code will remain symmetrical with respect to the resume code and it may allow us to speed up things in the future by suspending and resuming devices and/or saving the suspend image in many threads. The following series of patches reorders the suspend and resume code so that nonboot CPUs are disabled after devices have been suspended and enabled before the devices are resumed. It also causes pm_ops->finish() to be called after enable_nonboot_cpus() wherever necessary. This patch: Change the ordering of code in kernel/power/main.c so that device_suspend() is called before disable_nonboot_cpus() and pm_ops->finish() is called after enable_nonboot_cpus() and before device_resume(), as indicated by recent discussion on Linux-PM (cf. http://lists.osdl.org/pipermail/linux-pm/2006-November/004164.html). Signed-off-by: Rafael J. Wysocki Acked-by: Pavel Machek Cc: Greg KH Cc: Nigel Cunningham Cc: Patrick Mochel Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit c1725f2af89f1eda3cb9007290971b55084569a4 Author: Ahmed S. Darwish Date: Sat Feb 10 01:43:29 2007 -0800 [PATCH] ARM26: Use ARRAY_SIZE macro when appropriate Use ARRAY_SIZE macro already defined in linux/kernel.h Signed-off-by: Ahmed S. Darwish Acked-by: Ian Molton Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit 65fdc8544f7d27df95256cbcfc2a53fa0fa38134 Author: Aneesh Kumar K.V Date: Sat Feb 10 01:43:22 2007 -0800 [PATCH] Alpha: increase PERCPU_ENOUGH_ROOM Module loading on Alpha was failing with error "Could not allocate 8 bytes percpu data". Looking at dmesg we have the below error "No per-cpu room for modules." Increase the PERCPU_ENOUGH_ROOM in a similar way as x86_64 Signed-off-by: Aneesh Kumar K.V Cc: Cc: Richard Henderson Cc: Ivan Kokshaysky Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit 6ff1b4426e3afc61dcb67299709fde9041d59265 Author: Eric Paris Date: Sat Feb 10 01:43:19 2007 -0800 [PATCH] make reading /proc/sys/kernel/cap-bould not require CAP_SYS_MODULE Reading /proc/sys/kernel/cap-bound requires CAP_SYS_MODULE. (see proc_dointvec_bset in kernel/sysctl.c) sysctl appears to drive all over proc reading everything it can get it's hands on and is complaining when it is being denied access to read cap-bound. Clearly writing to cap-bound should be a sensitive operation but requiring CAP_SYS_MODULE to read cap-bound seems a bit to strong. I believe the information could with reasonable certainty be obtained by looking at a bunch of the output of /proc/pid/status which has very low security protection, so at best we are just getting a little obfuscation of information. Currently SELinux policy has to 'dontaudit' capability checks for CAP_SYS_MODULE for things like sysctl which just want to read cap-bound. In doing so we also as a byproduct have to hide warnings of potential exploits such as if at some time that sysctl actually tried to load a module. I wondered if anyone would have a problem opening cap-bound up to read from anyone? Acked-by: Chris Wright Cc: Stephen Smalley Cc: James Morris Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit daa88c8d214ca4ab2f1764b6e503cef4b3cde9b2 Author: Ken Chen Date: Sat Feb 10 01:43:18 2007 -0800 [PATCH] do not disturb page referenced state when unmapping memory range When kernel unmaps an address range, it needs to transfer PTE state into page struct. Currently, kernel transfer access bit via mark_page_accessed(). The call to mark_page_accessed in the unmap path doesn't look logically correct. At unmap time, calling mark_page_accessed will causes page LRU state to be bumped up one step closer to more recently used state. It is causing quite a bit headache in a scenario when a process creates a shmem segment, touch a whole bunch of pages, then unmaps it. The unmapping takes a long time because mark_page_accessed() will start moving pages from inactive to active list. I'm not too much concerned with moving the page from one list to another in LRU. Sooner or later it might be moved because of multiple mappings from various processes. But it just doesn't look logical that when user asks a range to be unmapped, it's his intention that the process is no longer interested in these pages. Moving those pages to active list (or bumping up a state towards more active) seems to be an over reaction. It also prolongs unmapping latency which is the core issue I'm trying to solve. As suggested by Peter, we should still preserve the info on pte young pages, but not more. Signed-off-by: Peter Zijlstra Acked-by: Ken Chen Cc: Hugh Dickins Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit 46626296314e5679c9aaca36979a50ac20692e0b Author: Ken Chen Date: Sat Feb 10 01:43:17 2007 -0800 [PATCH] convert ramfs to use __set_page_dirty_no_writeback As pointed out by Hugh, ramfs would also benefit from using the new set_page_dirty aop method for memory backed file systems. Signed-off-by: Ken Chen Cc: Peter Zijlstra Cc: Hugh Dickins Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit 767193253bbac889e176f90b6f17b7015f986551 Author: Ken Chen Date: Sat Feb 10 01:43:15 2007 -0800 [PATCH] simplify shmem_aops.set_page_dirty() method shmem backed file does not have page writeback, nor it participates in backing device's dirty or writeback accounting. So using generic __set_page_dirty_nobuffers() for its .set_page_dirty aops method is a bit overkill. It unnecessarily prolongs shm unmap latency. For example, on a densely populated large shm segment (sevearl GBs), the unmapping operation becomes painfully long. Because at unmap, kernel transfers dirty bit in PTE into page struct and to the radix tree tag. The operation of tagging the radix tree is particularly expensive because it has to traverse the tree from the root to the leaf node on every dirty page. What's bothering is that radix tree tag is used for page write back. However, shmem is memory backed and there is no page write back for such file system. And in the end, we spend all that time tagging radix tree and none of that fancy tagging will be used. So let's simplify it by introduce a new aops __set_page_dirty_no_writeback and this will speed up shm unmap. Signed-off-by: Ken Chen Cc: Peter Zijlstra Cc: Hugh Dickins Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit bd8029b66069d29fd02c304599411ca9bb7fa38c Author: Andy Whitcroft Date: Sat Feb 10 01:43:14 2007 -0800 [PATCH] zoneid: fix up calculations for ZONEID_PGSHIFT Currently if we have a non-zero ZONES_SHIFT we assume we are able to rely on that as the bottom edge of the ZONEID, if not then we use the NODES_PGOFF as the right end of either NODES _or_ SECTION. This latter is more luck than judgement and would be incorrect if we reordered the SECTION,NODE,ZONE options in the fields space. Really what we want is the lower of the right hand end of the two fields we are using (either NODE,ZONE or SECTION,ZONE). Codify that explicitly. As always allow for there being no bits in either of the fields, such as might be valid in a non-numa machine with only a zone NORMAL. I have checked that the compiler is still able to constant fold all of this away correctly. Signed-off-by: Andy Whitcroft Acked-by: Christoph Lameter Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit 5ac6da669e2476dbdac89b357b05b5a79bc5b657 Author: Christoph Lameter Date: Sat Feb 10 01:43:14 2007 -0800 [PATCH] Set CONFIG_ZONE_DMA for arches with GENERIC_ISA_DMA As Andi pointed out: CONFIG_GENERIC_ISA_DMA only disables the ISA DMA channel management. Other functionality may still expect GFP_DMA to provide memory below 16M. So we need to make sure that CONFIG_ZONE_DMA is set independent of CONFIG_GENERIC_ISA_DMA. Undo the modifications to mm/Kconfig where we made ZONE_DMA dependent on GENERIC_ISA_DMA and set theses explicitly in each arches Kconfig. Reviews must occur for each arch in order to determine if ZONE_DMA can be switched off. It can only be switched off if we know that all devices supported by a platform are capable of performing DMA transfers to all of memory (Some arches already support this: uml, avr32, sh sh64, parisc and IA64/Altix). In order to switch ZONE_DMA off conditionally, one would have to establish a scheme by which one can assure that no drivers are enabled that are only capable of doing I/O to a part of memory, or one needs to provide an alternate means of performing an allocation from a specific range of memory (like provided by alloc_pages_range()) and insure that all drivers use that call. In that case the arches alloc_dma_coherent() may need to be modified to call alloc_pages_range() instead of relying on GFP_DMA. Signed-off-by: Christoph Lameter Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit 339ba9b15df58199b9783a23af234e947ec9e6ba Author: Christoph Lameter Date: Sat Feb 10 01:43:13 2007 -0800 [PATCH] optional ZONE_DMA: remove ZONE_DMA remains from sh/sh64 sh / sh64: Remove ZONE_DMA remains. Both arches do not need ZONE_DMA Signed-off-by: Paul Mundt Signed-off-by: Christoph Lameter Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit 005928374bf339e0b6783d78da8fd0701631e7ee Author: Christoph Lameter Date: Sat Feb 10 01:43:12 2007 -0800 [PATCH] optional ZONE_DMA: remove ZONE_DMA remains from parisc Remove ZONE_DMA remains from parisc so that kernels are build without ZONE_DMA. Signed-off-by: Christoph Lameter Cc: Kyle McMartin Cc: Matthew Wilcox Cc: James Bottomley Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit 09ae1f585e9def652cdb1d0484611d4f4dc2d5fd Author: Christoph Lameter Date: Sat Feb 10 01:43:11 2007 -0800 [PATCH] optional ZONE_DMA: optional ZONE_DMA for ia64 ZONE_DMA less operation for IA64 SGI platform Disable ZONE_DMA for SGI SN2. All memory is addressable by all devices and we do not need any special memory pool. Signed-off-by: Christoph Lameter Cc: "Luck, Tony" Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit 4b51d66989218aad731a721b5b28c79bf5388c09 Author: Christoph Lameter Date: Sat Feb 10 01:43:10 2007 -0800 [PATCH] optional ZONE_DMA: optional ZONE_DMA in the VM Make ZONE_DMA optional in core code. - ifdef all code for ZONE_DMA and related definitions following the example for ZONE_DMA32 and ZONE_HIGHMEM. - Without ZONE_DMA, ZONE_HIGHMEM and ZONE_DMA32 we get to a ZONES_SHIFT of 0. - Modify the VM statistics to work correctly without a DMA zone. - Modify slab to not create DMA slabs if there is no ZONE_DMA. [akpm@osdl.org: cleanup] [jdike@addtoit.com: build fix] [apw@shadowen.org: Simplify calculation of the number of bits we need for ZONES_SHIFT] Signed-off-by: Christoph Lameter Cc: Andi Kleen Cc: "Luck, Tony" Cc: Kyle McMartin Cc: Matthew Wilcox Cc: James Bottomley Cc: Paul Mundt Signed-off-by: Andy Whitcroft Signed-off-by: Jeff Dike Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit 66701b1499a3ff11882c8c4aef36e8eac86e17b1 Author: Christoph Lameter Date: Sat Feb 10 01:43:09 2007 -0800 [PATCH] optional ZONE_DMA: introduce CONFIG_ZONE_DMA This patch simply defines CONFIG_ZONE_DMA for all arches. We later do special things with CONFIG_ZONE_DMA after the VM and an arch are prepared to work without ZONE_DMA. CONFIG_ZONE_DMA can be defined in two ways depending on how an architecture handles ISA DMA. First if CONFIG_GENERIC_ISA_DMA is set by the arch then we know that the arch needs ZONE_DMA because ISA DMA devices are supported. We can catch this in mm/Kconfig and do not need to modify arch code. Second, arches may use ZONE_DMA in an unknown way. We set CONFIG_ZONE_DMA for all arches that do not set CONFIG_GENERIC_ISA_DMA in order to insure backwards compatibility. The arches may later undefine ZONE_DMA if their arch code has been verified to not depend on ZONE_DMA. Signed-off-by: Christoph Lameter Cc: Andi Kleen Cc: "Luck, Tony" Cc: Kyle McMartin Cc: Matthew Wilcox Cc: James Bottomley Cc: Paul Mundt Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit 6267276f3fdda9ad0d5ca451bdcbdf42b802d64b Author: Christoph Lameter Date: Sat Feb 10 01:43:07 2007 -0800 [PATCH] optional ZONE_DMA: deal with cases of ZONE_DMA meaning the first zone This patchset follows up on the earlier work in Andrew's tree to reduce the number of zones. The patches allow to go to a minimum of 2 zones. This one allows also to make ZONE_DMA optional and therefore the number of zones can be reduced to one. ZONE_DMA is usually used for ISA DMA devices. There are a number of reasons why we would not want to have ZONE_DMA 1. Some arches do not need ZONE_DMA at all. 2. With the advent of IOMMUs DMA zones are no longer needed. The necessity of DMA zones may drastically be reduced in the future. This patchset allows a compilation of a kernel without that overhead. 3. Devices that require ISA DMA get rare these days. All my systems do not have any need for ISA DMA. 4. The presence of an additional zone unecessarily complicates VM operations because it must be scanned and balancing logic must operate on its. 5. With only ZONE_NORMAL one can reach the situation where we have only one zone. This will allow the unrolling of many loops in the VM and allows the optimization of varous code paths in the VM. 6. Having only a single zone in a NUMA system results in a 1-1 correspondence between nodes and zones. Various additional optimizations to critical VM paths become possible. Many systems today can operate just fine with a single zone. If you look at what is in ZONE_DMA then one usually sees that nothing uses it. The DMA slabs are empty (Some arches use ZONE_DMA instead of ZONE_NORMAL, then ZONE_NORMAL will be empty instead). On all of my systems (i386, x86_64, ia64) ZONE_DMA is completely empty. Why constantly look at an empty zone in /proc/zoneinfo and empty slab in /proc/slabinfo? Non i386 also frequently have no need for ZONE_DMA and zones stay empty. The patchset was tested on i386 (UP / SMP), x86_64 (UP, NUMA) and ia64 (NUMA). The RFC posted earlier (see http://marc.theaimsgroup.com/?l=linux-kernel&m=115231723513008&w=2) had lots of #ifdefs in them. An effort has been made to minize the number of #ifdefs and make this as compact as possible. The job was made much easier by the ongoing efforts of others to extract common arch specific functionality. I have been running this for awhile now on my desktop and finally Linux is using all my available RAM instead of leaving the 16MB in ZONE_DMA untouched: christoph@pentium940:~$ cat /proc/zoneinfo Node 0, zone Normal pages free 4435 min 1448 low 1810 high 2172 active 241786 inactive 210170 scanned 0 (a: 0 i: 0) spanned 524224 present 524224 nr_anon_pages 61680 nr_mapped 14271 nr_file_pages 390264 nr_slab_reclaimable 27564 nr_slab_unreclaimable 1793 nr_page_table_pages 449 nr_dirty 39 nr_writeback 0 nr_unstable 0 nr_bounce 0 cpu: 0 pcp: 0 count: 156 high: 186 batch: 31 cpu: 0 pcp: 1 count: 9 high: 62 batch: 15 vm stats threshold: 20 cpu: 1 pcp: 0 count: 177 high: 186 batch: 31 cpu: 1 pcp: 1 count: 12 high: 62 batch: 15 vm stats threshold: 20 all_unreclaimable: 0 prev_priority: 12 temp_priority: 12 start_pfn: 0 This patch: In two places in the VM we use ZONE_DMA to refer to the first zone. If ZONE_DMA is optional then other zones may be first. So simply replace ZONE_DMA with zone 0. This also fixes ZONETABLE_PGSHIFT. If we have only a single zone then ZONES_PGSHIFT may become 0 because there is no need anymore to encode the zone number related to a pgdat. However, we still need a zonetable to index all the zones for each node if this is a NUMA system. Therefore define ZONETABLE_SHIFT unconditionally as the offset of the ZONE field in page flags. [apw@shadowen.org: fix mismerge] Acked-by: Christoph Hellwig Signed-off-by: Christoph Lameter Cc: Andi Kleen Cc: "Luck, Tony" Cc: Kyle McMartin Cc: Matthew Wilcox Cc: James Bottomley Cc: Paul Mundt Signed-off-by: Andy Whitcroft Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit 65e458d43dff872ee560e721fb0fdb367bb5adb0 Author: Christoph Lameter Date: Sat Feb 10 01:43:05 2007 -0800 [PATCH] Drop get_zone_counts() Values are available via ZVC sums. Signed-off-by: Christoph Lameter Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit 05a0416be2b88d859efcbc4a4290555a04d169a1 Author: Christoph Lameter Date: Sat Feb 10 01:43:05 2007 -0800 [PATCH] Drop __get_zone_counts() Values are readily available via ZVC per node and global sums. Signed-off-by: Christoph Lameter Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit 9195481d2f869a2707a272057f3f8664fd277534 Author: Christoph Lameter Date: Sat Feb 10 01:43:04 2007 -0800 [PATCH] Drop nr_free_pages_pgdat() Function is unnecessary now. We can use the summing features of the ZVCs to get the values we need. Signed-off-by: Christoph Lameter Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit 96177299416dbccb73b54e6b344260154a445375 Author: Christoph Lameter Date: Sat Feb 10 01:43:03 2007 -0800 [PATCH] Drop free_pages() nr_free_pages is now a simple access to a global variable. Make it a macro instead of a function. The nr_free_pages now requires vmstat.h to be included. There is one occurrence in power management where we need to add the include. Directly refrer to global_page_state() there to clarify why the #include was added. [akpm@osdl.org: arm build fix] [akpm@osdl.org: sparc64 build fix] Signed-off-by: Christoph Lameter Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit 51ed4491271be8c56bdb2a03481ed34ea4984bc2 Author: Christoph Lameter Date: Sat Feb 10 01:43:02 2007 -0800 [PATCH] Reorder ZVCs according to cacheline The global and per zone counter sums are in arrays of longs. Reorder the ZVCs so that the most frequently used ZVCs are put into the same cacheline. That way calculations of the global, node and per zone vm state touches only a single cacheline. This is mostly important for 64 bit systems were one 128 byte cacheline takes only 8 longs. Signed-off-by: Christoph Lameter Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit d23ad42324cc4378132e51f2fc5c9ba6cbe75182 Author: Christoph Lameter Date: Sat Feb 10 01:43:02 2007 -0800 [PATCH] Use ZVC for free_pages This is again simplifies some of the VM counter calculations through the use of the ZVC consolidated counters. [michal.k.k.piotrowski@gmail.com: build fix] Signed-off-by: Christoph Lameter Signed-off-by: Michal Piotrowski Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit c878538598d1e7ab41ecc0de8894e34e2fdef630 Author: Christoph Lameter Date: Sat Feb 10 01:43:01 2007 -0800 [PATCH] Use ZVC for inactive and active counts The determination of the dirty ratio to determine writeback behavior is currently based on the number of total pages on the system. However, not all pages in the system may be dirtied. Thus the ratio is always too low and can never reach 100%. The ratio may be particularly skewed if large hugepage allocations, slab allocations or device driver buffers make large sections of memory not available anymore. In that case we may get into a situation in which f.e. the background writeback ratio of 40% cannot be reached anymore which leads to undesired writeback behavior. This patchset fixes that issue by determining the ratio based on the actual pages that may potentially be dirty. These are the pages on the active and the inactive list plus free pages. The problem with those counts has so far been that it is expensive to calculate these because counts from multiple nodes and multiple zones will have to be summed up. This patchset makes these counters ZVC counters. This means that a current sum per zone, per node and for the whole system is always available via global variables and not expensive anymore to calculate. The patchset results in some other good side effects: - Removal of the various functions that sum up free, active and inactive page counts - Cleanup of the functions that display information via the proc filesystem. This patch: The use of a ZVC for nr_inactive and nr_active allows a simplification of some counter operations. More ZVC functionality is used for sums etc in the following patches. [akpm@osdl.org: UP build fix] Signed-off-by: Christoph Lameter Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit c3704ceb4ad055b489b143f4e37c57d128908012 Author: Hugh Dickins Date: Sat Feb 10 01:43:00 2007 -0800 [PATCH] page_mkwrite caller race fix After do_wp_page has tested page_mkwrite, it must release old_page after acquiring page table lock, not before: at some stage that ordering got reversed, leaving a (very unlikely) window in which old_page might be truncated, freed, and reused in the same position. Signed-off-by: Hugh Dickins Acked-by: Nick Piggin Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit f05b6284ee5d3be51ebe22284fc4b25fc586f380 Author: Randy Dunlap Date: Sat Feb 10 01:42:59 2007 -0800 [PATCH] typeof __page_to_pfn with SPARSEMEM=y With CONFIG_SPARSEMEM=y: mm/rmap.c:579: warning: format '%lx' expects type 'long unsigned int', but argument 2 has type 'int' Make __page_to_pfn() return unsigned long. Signed-off-by: Randy Dunlap Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit 5a88a13d0624769088ae220e40c2f542f1661eb3 Author: Andrew Morton Date: Sat Feb 10 01:42:58 2007 -0800 [PATCH] /proc/zoneinfo: fix vm stats display This early break prevents us from displaying info for the vm stats thresholds if the zone doesn't have any pages in its per-cpu pagesets. So my 800MB i386 box says: Node 0, zone DMA pages free 2365 min 16 low 20 high 24 active 0 inactive 0 scanned 0 (a: 0 i: 0) spanned 4096 present 4044 nr_anon_pages 0 nr_mapped 1 nr_file_pages 0 nr_slab_reclaimable 0 nr_slab_unreclaimable 0 nr_page_table_pages 0 nr_dirty 0 nr_writeback 0 nr_unstable 0 nr_bounce 0 nr_vmscan_write 0 protection: (0, 868, 868) pagesets all_unreclaimable: 0 prev_priority: 12 start_pfn: 0 Node 0, zone Normal pages free 199713 min 934 low 1167 high 1401 active 10215 inactive 4507 scanned 0 (a: 0 i: 0) spanned 225280 present 222420 nr_anon_pages 2685 nr_mapped 1110 nr_file_pages 12055 nr_slab_reclaimable 2216 nr_slab_unreclaimable 1527 nr_page_table_pages 213 nr_dirty 0 nr_writeback 0 nr_unstable 0 nr_bounce 0 nr_vmscan_write 0 protection: (0, 0, 0) pagesets cpu: 0 pcp: 0 count: 152 high: 186 batch: 31 cpu: 0 pcp: 1 count: 13 high: 62 batch: 15 vm stats threshold: 16 cpu: 1 pcp: 0 count: 34 high: 186 batch: 31 cpu: 1 pcp: 1 count: 10 high: 62 batch: 15 vm stats threshold: 16 all_unreclaimable: 0 prev_priority: 12 start_pfn: 4096 Just nuke all that search-for-the-first-non-empty-pageset code. Dunno why it was there in the first place.. Cc: Christoph Lameter Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit a6af2bc3d5ce8722b9d09c5bdd5383c91c419653 Author: Mel Gorman Date: Sat Feb 10 01:42:57 2007 -0800 [PATCH] Avoid excessive sorting of early_node_map[] find_min_pfn_for_node() and find_min_pfn_with_active_regions() sort early_node_map[] on every call. This is an excessive amount of sorting and that can be avoided. This patch always searches the whole early_node_map[] in find_min_pfn_for_node() instead of returning the first value found. The map is then only sorted once when required. Successfully boot tested on a number of machines. [akpm@osdl.org: cleanup] Signed-off-by: Mel Gorman Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit e10a4437cb37c85f2df95432025b392d98aac2aa Author: Robert P. J. Day Date: Sat Feb 10 01:42:56 2007 -0800 [PATCH] Remove final references to deprecated "MAP_ANON" page protection flag Remove the last vestiges of the long-deprecated "MAP_ANON" page protection flag: use "MAP_ANONYMOUS" instead. Signed-off-by: Robert P. J. Day Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit 7c5cae368a6c44eac0e817ae130301b65ff446dc Author: Christoph Lameter Date: Sat Feb 10 01:42:55 2007 -0800 [PATCH] slab: use parameter passed to cache_reap to determine pointer to work structure Use the pointer passed to cache_reap to determine the work pointer and consolidate exit paths. Signed-off-by: Christoph Lameter Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit 8c8cc2c10c21943dd3499a2df7aac835093b37f3 Author: Pekka Enberg Date: Sat Feb 10 01:42:53 2007 -0800 [PATCH] slab: cache alloc cleanups Clean up __cache_alloc and __cache_alloc_node functions a bit. We no longer need to do NUMA_BUILD tricks and the UMA allocation path is much simpler. No functional changes in this patch. Note: saves few kernel text bytes on x86 NUMA build due to using gotos in __cache_alloc_node() and moving __GFP_THISNODE check in to fallback_alloc(). Cc: Andy Whitcroft Cc: Christoph Hellwig Cc: Manfred Spraul Acked-by: Christoph Lameter Cc: Paul Jackson Signed-off-by: Pekka Enberg Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit 6e40e73097a5e4ad1b9f92fa21757343fdd6a682 Author: Pekka Enberg Date: Sat Feb 10 01:42:52 2007 -0800 [PATCH] slab: remove broken PageSlab check from kfree_debugcheck The PageSlab debug check in kfree_debugcheck() is broken for compound pages. It is also redundant as we already do BUG_ON for non-slab pages in page_get_cache() and page_get_slab() which are always called before we free any actual objects. Signed-off-by: Pekka Enberg Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit 12c834527b85571792f1c4f1d12632185bea44c2 Author: Alex Dubov Date: Sat Feb 10 21:16:40 2007 -0800 tifm_sd: treat "status error" as normal command completion TI FlasMedia controller attempts to validate command responses and issues a "status error" if response does not matches its perceived (by controller) value. As mmc layer does its own validation we can safely ignore the controller's opinion. Signed-off-by: Alex Dubov Signed-off-by: Pierre Ossman commit abc71668b5c99b655c6b2677570748a840d4c713 Author: Pierre Ossman Date: Sun Feb 11 16:27:13 2007 +0100 mmc: wbsd: Remove stray kunmap_atomic() There was one kunmap_atomic() left over from 4a0ddbd25ad4e03a0a1657f5cb2259c9a35fe9e6 that was causing crashes. Signed-off-by: Pierre Ossman commit 784020fb950741cbb7390c6b622321da626fb1e8 Author: David S. Miller Date: Sat Feb 10 23:28:13 2007 -0800 [SPARC64]: Update defconfig. Signed-off-by: David S. Miller commit 35a17eb6a87c9ceb0d35dcb51f464fe6faf584ab Author: David S. Miller Date: Sat Feb 10 17:41:02 2007 -0800 [SPARC64]: Add PCI MSI support on Niagara. This is kind of hokey, we could use the hardware provided facilities much better. MSIs are assosciated with MSI Queues. MSI Queues generate interrupts when any MSI assosciated with it is signalled. This suggests a two-tiered IRQ dispatch scheme: MSI Queue interrupt --> queue interrupt handler MSI dispatch --> driver interrupt handler But we just get one-level under Linux currently. What I'd like to do is possibly stick the IRQ actions into a per-MSI-Queue data structure, and dispatch them form there, but the generic IRQ layer doesn't provide a way to do that right now. So, the current kludge is to "ACK" the interrupt by processing the MSI Queue data structures and ACK'ing them, then we run the actual handler like normal. We are wasting a lot of useful information, for example the MSI data and address are provided with ever MSI, as well as a system tick if available. If we could pass this into the IRQ handler it could help with certain things, in particular for PCI-Express error messages. The MSI entries on sparc64 also tell you exactly which bus/device/fn sent the MSI, which would be great for error handling when no registered IRQ handler can service the interrupt. We override the disable/enable IRQ chip methods in sun4v_msi, so we have to call {mask,unmask}_msi_irq() directly from there. This is another ugly wart. Signed-off-by: David S. Miller commit 68c921869491c119142612fa5796c9f8b4e9970b Author: David S. Miller Date: Mon Jan 29 12:12:28 2007 -0800 [SPARC64] IRQ: Use irq_desc->chip_data instead of irq_desc->handler_data Otherwise we can't use the generic MSI code. Furthermore, properly use the {get,set}_irq_foo() abstracted interfaces instead of direct accesses to irq_desc[]->foo. Signed-off-by: David S. Miller commit cf69eab231bb748b5c34912412a8fc8c763bcf57 Author: Fabio Massimo Di Nitto Date: Wed Dec 20 09:22:28 2006 -0800 [SPARC64]: Add obppath sysfs attribute for SBUS and PCI devices. Signed-off-by: Fabio Massimo Di Nitto Signed-off-by: David S. Miller commit d18d7682c18b617f523df6beea5ea0bd396ed0bd Author: Fabio Massimo Di Nitto Date: Sat Feb 10 23:50:00 2007 -0800 [PARTITION]: Add whole_disk attribute. Some partitioning systems create special partitions that span the entire disk. One example are Sun partitions, and this whole-disk partition exists to tell the firmware the extent of the entire device so it can load the boot block and do other things. Such partitions should not be treated as normal partitions, because all the other partitions overlap this whole-disk one. So we'd see multiple instances of the same UUID etc. which we do not want. udev and friends can thus search for this 'whole_disk' attribute and use it to decide to ignore the partition. Signed-off-by: Fabio Massimo Di Nitto Signed-off-by: David S. Miller commit 5ef213f6842277ee1df5659f59fac0ffc9beb411 Author: Eric Dumazet Date: Sat Feb 10 16:57:03 2007 -0800 [IPV4]: Restore multipath routing after rt_next changes. I forgot to test build this part of the networking code... Sorry guys. This patch renames u.rt_next to u.dst.rt_next Signed-off-by: Eric Dumazet Signed-off-by: David S. Miller commit bda390d5c883d5dff1f3ae2bade4c25869769894 Author: Masahide NAKAMURA Date: Fri Feb 9 21:22:16 2007 -0800 [XFRM] IPV6: Fix outbound RO transformation which is broken by IPsec tunnel patch. It seems to miss RO mode path by IPv6 over IPv4 IPsec tunnel patch when it changed semantics to check the mode from "xfrm[i]->props.mode != XFRM_MODE_TRANSPORT" to "xfrm[i]->props.mode == XFRM_MODE_TUNNEL" before changing address. It also makes two incline functions __xfrm6_bundle_addr_{remote,local} are used by nobody. This patch fixes it. Signed-off-by: Masahide NAKAMURA Signed-off-by: David S. Miller commit 1e19e02ca0c5e33ea73a25127dbe6c3b8fcaac4b Author: Eric Dumazet Date: Fri Feb 9 16:26:55 2007 -0800 [NET]: Reorder fields of struct dst_entry This last patch (but not least :) ) finally moves the next pointer at the end of struct dst_entry. This permits to perform route cache lookups with a minimal cost of one cache line per entry, instead of two. Both 32bits and 64bits platforms benefit from this new layout. Signed-off-by: Eric Dumazet Signed-off-by: David S. Miller commit 0c195c3fc4e95a06b0c0017506f074c94af99c35 Author: Eric Dumazet Date: Fri Feb 9 16:25:52 2007 -0800 [DECNET]: Convert decnet route to use the new dst_entry 'next' pointer This patch removes the next pointer from 'struct dn_route.u' union, and renames u.rt_next to u.dst.dn_next. It also moves 'struct flowi' right after 'struct dst_entry' to prepare speedup lookups. Signed-off-by: Eric Dumazet Signed-off-by: David S. Miller commit 7cc482634f1f1e1db5401007658c8e8d6cf1617d Author: Eric Dumazet Date: Fri Feb 9 16:22:57 2007 -0800 [IPV6]: Convert ipv6 route to use the new dst_entry 'next' pointer This patch removes the next pointer from 'struct rt6_info.u' union, and renames u.next to u.dst.rt6_next. Signed-off-by: Eric Dumazet Signed-off-by: David S. Miller commit 093c2ca4167cf66f69020329d14138da0da8599b Author: Eric Dumazet Date: Fri Feb 9 16:19:26 2007 -0800 [IPV4]: Convert ipv4 route to use the new dst_entry 'next' pointer This patch removes the rt_next pointer from 'struct rtable.u' union, and renames u.rt_next to u.dst_rt_next. It also moves 'struct flowi' right after 'struct dst_entry' to prepare the gain on lookups. Signed-off-by: Eric Dumazet Signed-off-by: David S. Miller commit 75ce7ceaa1221858c0163e75d19eb8a423a212ff Author: Eric Dumazet Date: Fri Feb 9 16:14:24 2007 -0800 [NET]: Introduce union in struct dst_entry to hold 'next' pointer This patch introduces an anonymous union to nicely express the fact that all objects inherited from struct dst_entry should access to the generic 'next' pointer but with appropriate type verification. This patch is a prereq before following patches. Signed-off-by: Eric Dumazet Signed-off-by: David S. Miller commit f7b14315faf62935a791dd67969c4289563058f0 Author: Al Viro Date: Fri Feb 9 15:46:51 2007 -0800 [DECNET]: fix misannotation of linkinfo_dn Signed-off-by: Al Viro Signed-off-by: David S. Miller commit 11a2254716255c6f9cd98e0e0e8f44df9b13b66c Author: Al Viro Date: Fri Feb 9 15:46:30 2007 -0800 [DECNET]: FRA_{DST,SRC} are le16 for decnet Signed-off-by: Al Viro Signed-off-by: David S. Miller commit 95f30b336b944e3e418f825044b4793d9e9aac09 Author: Eric Dumazet Date: Fri Feb 9 15:44:52 2007 -0800 [UDP]: UDP can use sk_hash to speedup lookups In a prior patch, I introduced a sk_hash field (__sk_common.skc_hash) to let tcp lookups use one cache line per unmatched entry instead of two. We can also use sk_hash to speedup UDP part as well. We store in sk_hash the hnum value, and use sk->sk_hash (same cache line than 'next' pointer), instead of inet->num (different cache line) Note : We still have a false sharing problem for SMP machines, because sock_hold(sock) dirties the cache line containing the 'next' pointer. Not counting the udp_hash_lock rwlock. (did someone mentioned RCU ? :) ) Signed-off-by: Eric Dumazet Signed-off-by: David S. Miller commit 4768fbcbcfbbcacb785ae08eef33767a0b4fdcdd Author: YOSHIFUJI Hideaki Date: Fri Feb 9 23:25:31 2007 +0900 [NET]: Fix whitespace errors. Signed-off-by: YOSHIFUJI Hideaki Signed-off-by: David S. Miller commit a716c1197d608c55adfba45692a890ca64e10df0 Author: YOSHIFUJI Hideaki Date: Fri Feb 9 23:25:29 2007 +0900 [NET] XFRM: Fix whitespace errors. Signed-off-by: YOSHIFUJI Hideaki Signed-off-by: David S. Miller commit f8e1d20183bf56f889d60edadd48f54912b9277f Author: YOSHIFUJI Hideaki Date: Fri Feb 9 23:25:27 2007 +0900 [NET] X25: Fix whitespace errors. Signed-off-by: YOSHIFUJI Hideaki Signed-off-by: David S. Miller commit 4ba6122b4e0537858e8579716896f01acf55f745 Author: YOSHIFUJI Hideaki Date: Fri Feb 9 23:25:25 2007 +0900 [NET] WANROUTER: Fix whitespace errors. Signed-off-by: YOSHIFUJI Hideaki Signed-off-by: David S. Miller commit ac7bfa62f3ad06a2a2ac3938b7e6fc4f318a762d Author: YOSHIFUJI Hideaki Date: Fri Feb 9 23:25:23 2007 +0900 [NET] UNIX: Fix whitespace errors. Signed-off-by: YOSHIFUJI Hideaki Signed-off-by: David S. Miller commit c43072852649d8382b81237ce51195bcec36f24a Author: YOSHIFUJI Hideaki Date: Fri Feb 9 23:25:21 2007 +0900 [NET] TIPC: Fix whitespace errors. Signed-off-by: YOSHIFUJI Hideaki Signed-off-by: David S. Miller commit cca5172a7ec10dfdb0b787cd8e9d5b0b8f179793 Author: YOSHIFUJI Hideaki Date: Fri Feb 9 15:38:13 2007 -0800 [NET] SUNRPC: Fix whitespace errors. Signed-off-by: YOSHIFUJI Hideaki Signed-off-by: David S. Miller commit d808ad9ab8b1109239027c248c4652503b9d3029 Author: YOSHIFUJI Hideaki Date: Fri Feb 9 23:25:18 2007 +0900 [NET] SCTP: Fix whitespace errors. Signed-off-by: YOSHIFUJI Hideaki Signed-off-by: David S. Miller commit 10297b99315e5e08fe623ba56da35db1fee69ba9 Author: YOSHIFUJI Hideaki Date: Fri Feb 9 23:25:16 2007 +0900 [NET] SCHED: Fix whitespace errors. Signed-off-by: YOSHIFUJI Hideaki Signed-off-by: David S. Miller commit 7612713fb69a17b79ca7d757df4446700f4afe6c Author: YOSHIFUJI Hideaki Date: Fri Feb 9 23:25:14 2007 +0900 [NET] RXRPC: Fix whitespace errors. Signed-off-by: YOSHIFUJI Hideaki Signed-off-by: David S. Miller commit 3dcf7c5e8b92387e0c63b3c75757fee1991f78f8 Author: YOSHIFUJI Hideaki Date: Fri Feb 9 23:25:12 2007 +0900 [NET] ROSE: Fix whitespace errors. Signed-off-by: YOSHIFUJI Hideaki Signed-off-by: David S. Miller commit 1ce4f28bd761eeb979d29be350f2d22383d4c2f0 Author: YOSHIFUJI Hideaki Date: Fri Feb 9 23:25:10 2007 +0900 [NET] PACKET: Fix whitespace errors. Signed-off-by: YOSHIFUJI Hideaki Signed-off-by: David S. Miller commit 5f8f59d6641a3726985593f3e52430daa90c7933 Author: YOSHIFUJI Hideaki Date: Fri Feb 9 23:25:09 2007 +0900 [NET] NETROM: Fix whitespace errors. Signed-off-by: YOSHIFUJI Hideaki Signed-off-by: David S. Miller commit 746fac4dcd82864c6ecd85d3f09cc173db9b1870 Author: YOSHIFUJI Hideaki Date: Fri Feb 9 23:25:07 2007 +0900 [NET] NETLINK: Fix whitespace errors. Signed-off-by: YOSHIFUJI Hideaki Signed-off-by: David S. Miller commit e1a95265b44ca31456adaacebebcde12714f0c03 Author: YOSHIFUJI Hideaki Date: Fri Feb 9 23:25:05 2007 +0900 [NET] NETLABEL: Fix whitespace errors. Signed-off-by: YOSHIFUJI Hideaki Signed-off-by: David S. Miller commit d57b1869b231c56de441db35c647879d51c5d29e Author: YOSHIFUJI Hideaki Date: Fri Feb 9 23:25:01 2007 +0900 [NET] LLC: Fix whitespace errors. Signed-off-by: YOSHIFUJI Hideaki Signed-off-by: David S. Miller commit 56d6c3d7a7963ee2a480232e5ef6a2f31635e80e Author: YOSHIFUJI Hideaki Date: Fri Feb 9 23:24:59 2007 +0900 [NET] LAPB: Fix whitespace errors. Signed-off-by: YOSHIFUJI Hideaki Signed-off-by: David S. Miller commit 8ff24541d9f80b9161022588b4435a9b54aec2e6 Author: YOSHIFUJI Hideaki Date: Fri Feb 9 23:24:58 2007 +0900 [NET] KEY: Fix whitespace errors. Signed-off-by: YOSHIFUJI Hideaki Signed-off-by: David S. Miller commit 6819bc2e1e46c71711a8dddf4040e706b02973c0 Author: YOSHIFUJI Hideaki Date: Fri Feb 9 23:24:53 2007 +0900 [NET] IRDA: Fix whitespace errors. Signed-off-by: YOSHIFUJI Hideaki Signed-off-by: David S. Miller commit 981c0ff6900c981668a798fe9e0bc5ba32ee3fd4 Author: YOSHIFUJI Hideaki Date: Fri Feb 9 23:24:51 2007 +0900 [NET] IPX: Fix whitespace errors. Signed-off-by: YOSHIFUJI Hideaki Signed-off-by: David S. Miller commit 1ab1457c42bc078e5a9becd82a7f9f940b55c53a Author: YOSHIFUJI Hideaki Date: Fri Feb 9 23:24:49 2007 +0900 [NET] IPV6: Fix whitespace errors. Signed-off-by: YOSHIFUJI Hideaki Signed-off-by: David S. Miller commit e905a9edab7f4f14f9213b52234e4a346c690911 Author: YOSHIFUJI Hideaki Date: Fri Feb 9 23:24:47 2007 +0900 [NET] IPV4: Fix whitespace errors. Signed-off-by: YOSHIFUJI Hideaki Signed-off-by: David S. Miller commit 642656518b2e64fd59d9bbd15b6885cac5fe99b1 Author: YOSHIFUJI Hideaki Date: Fri Feb 9 23:24:46 2007 +0900 [NET] IEEE80211: Fix whitespace errors. Signed-off-by: YOSHIFUJI Hideaki Signed-off-by: David S. Miller commit 03d52d7cfcc7dec2b251f5b02c0638f952ff5d65 Author: YOSHIFUJI Hideaki Date: Fri Feb 9 23:24:44 2007 +0900 [NET] ETHERNET: Fix whitespace errors. Signed-off-by: YOSHIFUJI Hideaki Signed-off-by: David S. Miller commit c9b6aab9cfa32d3be499b43ffcb23a9ac5cbd740 Author: YOSHIFUJI Hideaki Date: Fri Feb 9 23:24:42 2007 +0900 [NET] ECONET: Fix whitespace errors. Signed-off-by: YOSHIFUJI Hideaki Signed-off-by: David S. Miller commit 429eb0fae6c06c9adcda03401c09c2b9ccaa7ebd Author: YOSHIFUJI Hideaki Date: Fri Feb 9 23:24:40 2007 +0900 [NET] DECNET: Fix whitespace errors. Signed-off-by: YOSHIFUJI Hideaki Signed-off-by: David S. Miller commit c9eaf17341834de00351bf79f16b2d879c8aea96 Author: YOSHIFUJI Hideaki Date: Fri Feb 9 23:24:38 2007 +0900 [NET] DCCP: Fix whitespace errors. Signed-off-by: YOSHIFUJI Hideaki Signed-off-by: David S. Miller commit 4ec93edb14fe5fdee9fae6335f2cbba204627eac Author: YOSHIFUJI Hideaki Date: Fri Feb 9 23:24:36 2007 +0900 [NET] CORE: Fix whitespace errors. Signed-off-by: YOSHIFUJI Hideaki Signed-off-by: David S. Miller commit 9d6f229fc45b6ac268020c0c8eff29e94bb34381 Author: YOSHIFUJI Hideaki Date: Fri Feb 9 23:24:35 2007 +0900 [NET] BRIDGE: Fix whitespace errors. Signed-off-by: YOSHIFUJI Hideaki Signed-off-by: David S. Miller commit 8e87d14255acffeee36873de226dc25c11b5f46d Author: YOSHIFUJI Hideaki Date: Fri Feb 9 23:24:33 2007 +0900 [NET] BLUETOOTH: Fix whitespace errors. Signed-off-by: YOSHIFUJI Hideaki Signed-off-by: David S. Miller commit 528930b91ee89a05a6264629cf99109652c19ca8 Author: YOSHIFUJI Hideaki Date: Fri Feb 9 23:24:31 2007 +0900 [NET] AX25: Fix whitespace errors. Signed-off-by: YOSHIFUJI Hideaki Signed-off-by: David S. Miller commit f7d57453d20e27de69ecafd121005e9d13a0f427 Author: YOSHIFUJI Hideaki Date: Fri Feb 9 23:24:29 2007 +0900 [NET] ATM: Fix whitespace errors. Signed-off-by: YOSHIFUJI Hideaki Signed-off-by: David S. Miller commit ed4477b96049fe2908c63f854bf8e37c6df4a635 Author: YOSHIFUJI Hideaki Date: Fri Feb 9 23:24:27 2007 +0900 [NET] APPLETALK: Fix whitespace errors. Signed-off-by: YOSHIFUJI Hideaki Signed-off-by: David S. Miller commit 122952fc2d6b5ca865e8475ec471d8944fa921c7 Author: YOSHIFUJI Hideaki Date: Fri Feb 9 23:24:25 2007 +0900 [NET] 8021Q: Fix whitespace errors. Signed-off-by: YOSHIFUJI Hideaki Signed-off-by: David S. Miller commit 9afa0949eea959f28248b717757c201765f1c19b Author: YOSHIFUJI Hideaki Date: Fri Feb 9 23:24:24 2007 +0900 [NET] 802: Fix whitespace errors. Signed-off-by: YOSHIFUJI Hideaki Signed-off-by: David S. Miller commit 348f31ed2bd18391fe5903aa0ad7bfcda6d8ca0b Author: Rafa³ Bilski Date: Thu Feb 8 18:56:04 2007 +0100 [CPUFREQ] Longhaul - Separate frequency and voltage transition This change should make Longhaul more compatible with both ver. 2 and Powersaver processors. Voltage transitions will be done before or after frequency transition. That depends on direction of change. I don't know how to force conservative governor when voltage scaling is enabled, so there is only a warning for user. Minimal voltage is calculated in different way now because in this way more power is saved at lower multipliers. Signed-off-by: Rafal Bilski Signed-off-by: Dave Jones commit e57501c15f48d6b7a8fe2b023be8f4779484482d Author: Rafa³ Bilski Date: Thu Feb 8 23:12:02 2007 +0100 [CPUFREQ] Longhaul - Models of Nehemiah Borowed from VIA driver. Signed-off-by: Rafal Bilski Signed-off-by: Dave Jones commit c18a1483f478adbeb4cc7148db22c4a9c10aaee3 Author: Dave Jones Date: Sat Feb 10 20:03:51 2007 -0500 [CPUFREQ] Whitespace fixup Signed-off-by: Dave Jones commit 9addf3b6388459f315adc728d27d34603a00d427 Author: Rafa³ Bilski Date: Wed Feb 7 22:53:29 2007 +0100 [CPUFREQ] Longhaul - Simplier minmult Simple cleanup in code which is setting minmult. Signed-off-by: Rafal Bilski Signed-off-by: Dave Jones commit f0ec313a89a7377f440c815f82b0370bd67f62c6 Author: Adrian Bunk Date: Mon Feb 5 16:12:45 2007 -0800 [CPUFREQ] CPU_FREQ_TABLE shouldn't be a def_tristate CPU_FREQ_TABLE enables helper code and gets select'ed when it's required. Building it as a module when it's not required doesn't seem to make much sense. Signed-off-by: Adrian Bunk Signed-off-by: Andrew Morton Signed-off-by: Dave Jones commit 56463b78cdca8e9ff8cc1759bca0c0777a061d6b Author: Venkatesh Pallipadi Date: Mon Feb 5 16:12:45 2007 -0800 [CPUFREQ] ondemand governor use new cpufreq rwsem locking in work callback Eliminate flush_workqueue in cpufreq_governor(STOP) callpath. Using flush there has a deadlock potential as in http://uwsg.iu.edu/hypermail/linux/kernel/0611.3/1223.html Also, cleanup the locking issues with do_dbs_timer delayed_work callback. As it changes the CPU frequency using __cpufreq_target, it needs to have policy_rwsem in write mode, which also protects it from hot plug. Signed-off-by: Venkatesh Pallipadi Cc: Gautham R Shenoy Signed-off-by: Andrew Morton Signed-off-by: Dave Jones commit 529af7a14f04f92213bac371931a2b2b060c63fa Author: Venkatesh Pallipadi Date: Mon Feb 5 16:12:44 2007 -0800 [CPUFREQ] ondemand governor restructure the work callback Restructure the delayed_work callback in ondemand. This eliminates the need for smp_processor_id in the callback function and also helps in proper locking and avoiding flush_workqueue when stopping the governor (done in subsequent patch). Signed-off-by: Venkatesh Pallipadi Cc: Gautham R Shenoy Signed-off-by: Andrew Morton Signed-off-by: Dave Jones commit 5a01f2e8f3ac134e24144d74bb48a60236f7024d Author: Venkatesh Pallipadi Date: Mon Feb 5 16:12:44 2007 -0800 [CPUFREQ] Rewrite lock in cpufreq to eliminate cpufreq/hotplug related issues Yet another attempt to resolve cpufreq and hotplug locking issues. Patchset has 3 patches: * Rewrite the lock infrastructure of cpufreq using a per cpu rwsem. * Minor restructuring of work callback in ondemand driver. * Use the new cpufreq rwsem infrastructure in ondemand work. This patch: Convert policy->lock to rwsem and move it to per_cpu area. This rwsem will protect against both changing/accessing policy related parameters and CPU hot plug/unplug. [malattia@linux.it: fix oops in kref_put()] Cc: Gautham R Shenoy Signed-off-by: Venkatesh Pallipadi Cc: Gautham R Shenoy Signed-off-by: Mattia Dongili Signed-off-by: Andrew Morton Signed-off-by: Dave Jones commit c120069779e3e35917c15393cf2847fa79811eb6 Author: Dave Jones Date: Mon Feb 5 16:12:43 2007 -0800 [CPUFREQ] Remove hotplug cpu crap The hotplug CPU locking in cpufreq is horrendous. No-one seems to care enough to fix it, so just remove it so that the 99.9% of the real world users of this code can use cpufreq without being bothered by warnings. Signed-off-by: Andrew Morton Signed-off-by: Dave Jones commit 86acd49aa128bd7a1d4362c256c21fbdc2d5b1a0 Author: Rafa³ Bilski Date: Mon Feb 5 19:57:25 2007 +0100 [CPUFREQ] Enhanced PowerSaver driver This is driver for Enhanced Powersaver which is present in VIA C7 processors. Beta tested by Jorgen (jorgen (at) greven dot dk). Thanks! Based on documentation provided by Dave Jones (Thanks!) and C7 Eden datasheet available from www.via.com.tw. Looks like all these C7 Eden CPU's don't have P-states in BIOS. I know that 2 p-states is low, but Jorgen finds it usefull anyway because board is passive cooled. There are 3 different types of C7 processors (called brands): 0. C7-M - these processors can set any maultiplier between min and max, any voltage between min and max. 1. C7 - only min and max states are supported. Voltage is different for min and max states. 2. Eden - only min and max states are supported. Looks like this brand can only change multiplier. Voltage seems to be the same for min and max frequency. Signed-off-by: Rafal Bilski Signed-off-by: Dave Jones commit 1c14cfbbe7a9f2240c73f420c3c6336fc521cd64 Author: Andrew Morton Date: Mon Feb 5 16:09:35 2007 -0800 [AGPGART] allow drm populated agp memory types cleanups Fix whitespace, braces, use kzalloc(). Cc: Dave Airlie Cc: Thomas Hellstrom Signed-off-by: Andrew Morton Signed-off-by: Dave Jones commit e692eb30ffc2b99e62f766f9958f46dfdc1013cc Author: Franck Bui-Huu Date: Mon Feb 5 15:24:28 2007 +0100 [MIPS] signal: do not inline handle_signal() Signed-off-by: Franck Bui-Huu Signed-off-by: Ralf Baechle commit f90080a059fc19444b3a63affd1f4ecece62c11c Author: Franck Bui-Huu Date: Mon Feb 5 15:24:27 2007 +0100 [MIPS] signal: do not use save_static_function() anymore This macro was used to save static registers before calling sys_sigsuspend() and sys_sigreturn(). For the sys_sigreturn() case, there's no point to save them since they have been already saved by setup_sigcontext() before calling the signal handler. For the sys_sigsuspend() case, I don't see any reasons... Signed-off-by: Franck Bui-Huu Signed-off-by: Ralf Baechle commit 6bfe96616062acb75c2460f01acc79236a8ba0e8 Author: Franck Bui-Huu Date: Mon Feb 5 15:24:26 2007 +0100 [MIPS] signal32: no need to save c0_status register in setup_sigcontext32() All the information in the MIPS c0_status register is priviledged. Nothing that would constitute part of the thread context. The one flag one could possibly argument about might be c0_status.fr but none of the ABIs or tools or application software can make use of it. So for consistency with restore_sigcontext32(), which does not restore c0_status register, this patch remove the saving part. Signed-off-by: Franck Bui-Huu Signed-off-by: Ralf Baechle commit 9432a9ba96ea8d007341c4e7859d393bfd357c5a Author: Franck Bui-Huu Date: Mon Feb 5 15:24:25 2007 +0100 [MIPS] signal32: reduce {setup,restore}_sigcontext32 sizes This trivial changes should decrease a lot the size of these 2 functions. Signed-off-by: Franck Bui-Huu Signed-off-by: Ralf Baechle commit 722bb63de630f9500db1f12ed32e1dd9349a8049 Author: Franck Bui-Huu Date: Mon Feb 5 15:24:24 2007 +0100 [MIPS] signal: factorize debug code Signed-off-by: Franck Bui-Huu Signed-off-by: Ralf Baechle commit 601dde45f698ee1be5fe03a68b895efe6ca6b858 Author: Franck Bui-Huu Date: Mon Feb 5 15:24:23 2007 +0100 [MIPS] signal: test return value of install_sigtramp() Signed-off-by: Franck Bui-Huu Signed-off-by: Ralf Baechle commit 36a1f2c24f42fc2531d5e21914db56ce8ee346f6 Author: Franck Bui-Huu Date: Mon Feb 5 15:24:22 2007 +0100 [MIPS] signal32: remove duplicate code There's no point for signal32.c to redefine get_sigframe(). It should use the one define in signal.c instead. The same stands for install_sigtramp(). Signed-off-by: Franck Bui-Huu Signed-off-by: Ralf Baechle commit c0b9bae9d18980afa1797fb7b75adb4fbc837b66 Author: Franck Bui-Huu Date: Mon Feb 5 15:24:21 2007 +0100 [MIPS] signal: clean up sigframe structure This patch makes 'struct sigframe' declaration avalaible for all signals code. It allows signal32 to not have its own declaration. This patch also removes all ICACHE_REFILLS_WORKAROUND_WAR tests in structure declaration and hopefully make them more readable. Signed-off-by: Franck Bui-Huu Signed-off-by: Ralf Baechle commit c3fc4ab36d495f50ccc89986fe32eeabc2549fa1 Author: Franck Bui-Huu Date: Mon Feb 5 15:24:20 2007 +0100 [MIPS] signal: do not inline functions in signal-common.h These functions are quite big and there are no points to make them inlined. So this patch moves the functions implementation in signal.c and make them available for others source files which need them. Signed-off-by: Franck Bui-Huu Signed-off-by: Ralf Baechle commit a007b1f1c764c08896bc574fbd33e19ce898a188 Author: Franck Bui-Huu Date: Mon Feb 5 15:24:19 2007 +0100 [MIPS] signals: reduce {setup,restore}_sigcontext sizes This trivial change reduces considerably code size of these 2 functions callers. For instance, here is the figures for arch/kernel/signal.o objects: text data bss dec hex filename 11972 0 0 11972 2ec4 arch/mips/kernel/signal.o~old 5380 0 0 5380 1504 arch/mips/kernel/signal.o~new Signed-off-by: Franck Bui-Huu Signed-off-by: Ralf Baechle commit 4ed3a77f38c023658784804cb39a7ce18063dc88 Author: Ralf Baechle Date: Sat Feb 10 21:43:54 2007 +0000 [MIPS] Fix warning in get_user when fetching pointer object from userspace. Signed-off-by: Ralf Baechle commit 761fc19bdbe33ea8b7b88b88c7ca149a57a9e6b6 Author: Dale Farnsworth Date: Fri Feb 9 13:31:43 2007 -0700 [MIPS] Fix eth2 platform device id for jaguar_atx and ocelot_3 platforms Signed-off-by: Dale Farnsowrth Signed-off-by: Ralf Baechle commit 6a2603a2eaafc5faaae24f7250158a41931f77ee Author: Sergei Shtylyov Date: Wed Feb 7 20:39:05 2007 +0300 [MIPS] JMR3927 and RBTX49x7 support little endian Toshiba JMR3927 (RBHMA3100) and RBTX49[23]7 (RBHMA4[24]00) do support both little and big endian mode (if you flash the right PMON). Signed-off-by: Sergei Shtylyov Signed-off-by: Ralf Baechle commit 57340b2bad1de489902f6947f24fc334737e5b80 Author: Sergei Shtylyov Date: Wed Feb 7 20:41:36 2007 +0300 [MIPS] RBTX49x7: declare prom_getcmdline() Fix a bunch of warnings caused by a missing prom_getcmdline() prototype. Signed-off-by: Sergei Shtylyov Signed-off-by: Ralf Baechle commit bb3d7c7ff1cc18b4cb83820327905f7e1f8dc414 Author: Ralf Baechle Date: Wed Feb 7 15:36:56 2007 +0000 [MIPS] RTLX: Sprinkle device model code into code to make udev happier. Signed-off-by: Ralf Baechle commit 27a3bbaf4b1e23a3afbae4d9f72b51a36859f74a Author: Ralf Baechle Date: Wed Feb 7 13:48:59 2007 +0000 [MIPS] VPE: Sprinkle device model code into code to make udev happier. Signed-off-by: Ralf Baechle commit 98051995ab44b993f992946055edc6115351f725 Author: Swen Schillig Date: Fri Feb 9 10:01:40 2007 +0100 [SCSI] zfcp: removed wrong comment commit 07a105136f07f0cf1b476383e43033b8a65e13ff Author: Swen Schillig Date: Fri Feb 9 09:58:09 2007 +0100 removed wrong comment Signed-off-by: Swen Schillig Signed-off-by: James Bottomley commit ca880cf93361e752d2e0bf6bf73657e2c56a0822 Author: Swen Schillig Date: Fri Feb 9 10:00:14 2007 +0100 [SCSI] zfcp: use of uninitialized variable commit 988d955c3314336d716a9208f3d565b06f262e07 Author: Swen Schillig Date: Fri Feb 9 09:40:11 2007 +0100 Use of uninitialized variable. ERP action might not be finished accordingly. Signed-off-by: Swen Schillig Signed-off-by: James Bottomley commit 6fcc47111ae14f284007e1b9a5002babb01d913c Author: Swen Schillig Date: Wed Feb 7 13:17:57 2007 +0100 [SCSI] zfcp: Invalid locking order Invalid locking order. Kernel hangs after trying to take two locks which are dependend on each other. Introducing temporary variable to free requests. Free lock after requests are copied. Signed-off-by: Swen Schillig Signed-off-by: James Bottomley commit 19966769f9fc1968dcf5bffec2e53f7f40100872 Author: Hannes Reinecke Date: Wed Feb 7 09:47:44 2007 +0100 [SCSI] aic79xx: use dma_get_required_mask() As originally noted by Frederic Temporelli, the aic79xx supports 64 bit addressing, but the initialization code of the driver is wrong: it tests the available memory size instead of testing the maximum available memory address. This patch uses the correct dma_get_required_mask() macros to determine the correct addressing method. Signed-off-by: Hannes Reinecke Cc: Xavier Bru CC: Frederic Temporelli cosmetic fixes Signed-off-by: James Bottomley commit c7f743a669c27f9c392e78fda8829db9d6d50f43 Author: Sean Hefty Date: Thu Feb 1 12:23:37 2007 -0800 IB: Remove redundant "_wq" from workqueue names Signed-off-by: Roland Dreier commit aedec08050255db1989a38b59616dd973dfe660b Author: Sean Hefty Date: Mon Jan 29 16:41:23 2007 -0800 RDMA/cma: Increment port number after close to avoid re-use Randomize the starting port number and avoid re-using port values immediately after they are closed. Instead keep track of the last port value used and increment it every time a new port number is assigned, to better replicate other port spaces. Signed-off-by: Roland Dreier commit 65e5c0262169a92bdec71a8bb9edb32dab2d8d1f Author: Akinobu Mita Date: Mon Feb 5 16:21:09 2007 -0800 IB/ehca: Fix memleak on module unloading Percpu data is not freed on module unloading. Cc: Heiko Carstens Cc: Christoph Raisch Signed-off-by: Akinobu Mita Signed-off-by: Andrew Morton Acked-by: Hoang-Nam Nguyen Signed-off-by: Roland Dreier commit 6bdd61d876e6eacea5c59230b6b2d988b22793e6 Author: David Howells Date: Mon Feb 5 16:21:08 2007 -0800 IB/mthca: Work around gcc bug on sparc64 For some reason gcc-3.4.5 on sparc64 does: WARNING: "____ilog2_NaN" [drivers/infiniband/hw/mthca/ib_mthca.ko] undefined! Points to note: (1) The asm volatile flush/flushw are just markers for viewing what comes out in the assembly; removing them has no effect on the result. (2) Changing almost anything else in dwh__mthca_arbel_init_srq_context() or dwh__mthca_alloc_srq() causes the problem to go away. The compiler command line issued by the kernel build is: /opt/crosstool/gcc-3.4.5-glibc-2.3.6/sparc64-unknown-linux-gnu/bin/sparc64-unknown-linux-gnu-gcc -fno-strict-aliasing -fno-common -Os -m64 -mno-fpu -mcpu=ultrasparc -mcmodel=medlow -ffixed-g4 -ffixed-g5 -fcall-used-g7 -Wa,--undeclared-regs -pg -fno-omit-frame-pointer -fno-optimize-sibling-calls -fasynchronous-unwind-tables -g -c -o drivers/infiniband/hw/mthca/.tmp_mthca_srq.o drivers/infiniband/hw/mthca/mthca_srq.c This can be reduced to this whilst still retaining the problem: /opt/crosstool/gcc-3.4.5-glibc-2.3.6/sparc64-unknown-linux-gnu/bin/sparc64-unknown-linux-gnu-gcc -m64 -c -o drivers/infiniband/hw/mthca/mthca_srq.o drivers/infiniband/hw/mthca/mthca_srq.c -Os Removing -Os or changing it to -O or -O0 thru -O6 gets rid of the problem. This patch to the kernel code fixes the problem: Cc: "David S. Miller" Signed-off-by: Andrew Morton Signed-off-by: Roland Dreier commit 839fcaba355abaffb7b44f0f4504093acb0b11cf Author: Michael S. Tsirkin Date: Mon Feb 5 22:12:23 2007 +0200 IPoIB: Connected mode experimental support The following patch adds experimental support for IPoIB connected mode, as defined by the draft from the IETF ipoib working group. The idea is to increase performance by increasing the MTU from the maximum of 2K (theoretically 4K) supported by IPoIB on top of UD. With this code, I'm able to get 800MByte/sec or more with netperf without options on a Mellanox 4x back-to-back DDR system. Some notes on code: 1. SRQ is used for scalability to large cluster sizes 2. Only RC connections are used (UC does not support SRQ now) 3. Retry count is set to 0 since spec draft warns against retries 4. Each connection is used for data transfers in only 1 direction, so each connection is either active(TX) or passive (RX). 2 sides that want to communicate create 2 connections. 5. Each active (TX) connection has a separate CQ for send completions - this keeps the code simple without CQ resize and other tricks 6. To detect stale passive side connections (where the remote side is down), we keep an LRU list of passive connections (updated once per second per connection) and destroy a connection after it has been unused for several seconds. The LRU rule makes it possible to avoid scanning connections that have recently been active. Signed-off-by: Michael S. Tsirkin Signed-off-by: Roland Dreier commit 9a6b090c0d1cd5c90f21db772dbe2fbcf14366de Author: Ahmed S. Darwish Date: Tue Feb 6 18:07:25 2007 +0200 IB/core: Use ARRAY_SIZE macro for mandatory_table Use ARRAY_SIZE() macro already defined in kernel.h instead of open coding equivalent code. Signed-off-by: Ahmed S. Darwish Signed-off-by: Roland Dreier commit 99d4f22e91d26e0f8b113bf7fde65a335d36ad6b Author: Roland Dreier Date: Sat Feb 10 08:00:47 2007 -0800 IB/mthca: Use correct structure size in call to memset() When clearing the ib_ah_attr parameter in to_ib_ah_attr(), use sizeof *ib_ah_attr instead of sizeof *path. Pointed out by Jack Morgenstein . Signed-off-by: Roland Dreier commit e7ff6aed8761b2c86cd9ab7083e512de2b8cfa48 Author: David Chinner Date: Sat Feb 10 18:37:46 2007 +1100 [XFS] Don't use kmap in xfs_iozero. kmap() is inefficient and does not scale well. kmap_atomic() is a better choice. Use the generic wrapper function instead of open coding the kmap-memset-dcache flush-kunmap stuff. SGI-PV: 960904 SGI-Modid: xfs-linux-melb:xfs-kern:28041a Signed-off-by: David Chinner Signed-off-by: Christoph Hellwig Signed-off-by: Tim Shimmin commit 6be145bfb1ce93b2dbb854fee66fbb8d04916339 Author: Eric Sandeen Date: Sat Feb 10 18:37:40 2007 +1100 [XFS] Remove a bunch of unused functions from XFS. Patch provided by Eric Sandeen (sandeen@sandeen.net). SGI-PV: 960897 SGI-Modid: xfs-linux-melb:xfs-kern:28038a Signed-off-by: Eric Sandeen Signed-off-by: David Chinner Signed-off-by: Tim Shimmin commit 2c36ddeda7f04c085d9a612cf8dab5f0a1cd5224 Author: Eric Sandeen Date: Sat Feb 10 18:37:33 2007 +1100 [XFS] Remove unused arguments from the XFS_BTREE_*_ADDR macros. It makes it incrementally clearer to read the code when the top of a macro spaghetti-pile only receives the 3 arguments it uses, rather than 2 extra ones which are not used. Also when you start pulling this thread out of the sweater (i.e. remove unused args from XFS_BTREE_*_ADDR), a couple other third arms etc fall off too. If they're not used in the macro, then they sometimes don't need to be passed to the function calling the macro either, etc.... Patch provided by Eric Sandeen (sandeen@sandeen.net). SGI-PV: 960197 SGI-Modid: xfs-linux-melb:xfs-kern:28037a Signed-off-by: Eric Sandeen Signed-off-by: David Chinner Signed-off-by: Tim Shimmin commit 7bc5306d74922d9b14f507e1164d8dd852a98ad3 Author: Eric Sandeen Date: Sat Feb 10 18:37:28 2007 +1100 [XFS] Remove unused header files for MAC and CAP checking functionality. xfs_mac.h and xfs_cap.h provide definitions and macros that aren't used anywhere in XFS at all. They are left-overs from "to be implement at some point in the future" functionality that Irix XFS has. If this functionality ever goes into Linux, it will be provided at a different layer, most likely through the security hooks in the kernel so we will never need this functionality in XFS. Patch provided by Eric Sandeen (sandeen@sandeen.net). SGI-PV: 960895 SGI-Modid: xfs-linux-melb:xfs-kern:28036a Signed-off-by: Eric Sandeen Signed-off-by: David Chinner Signed-off-by: Tim Shimmin commit 3c0dc77b42cee99c71e913765073888620d442fa Author: David Chinner Date: Sat Feb 10 18:37:22 2007 +1100 [XFS] Make freeze code a little cleaner. Fixes a few small issues (mostly cosmetic) that were picked up during the review cycle for the last set of freeze path changes. SGI-PV: 959267 SGI-Modid: xfs-linux-melb:xfs-kern:28035a Signed-off-by: David Chinner Signed-off-by: Christoph Hellwig Signed-off-by: Tim Shimmin commit f7c99b6fc7b3791cd24e0763cd4967d744c164a3 Author: Eric Sandeen Date: Sat Feb 10 18:37:16 2007 +1100 [XFS] Remove unused argument to xfs_bmap_finish The firstblock argument to xfs_bmap_finish is not used by that function. Remove it and cleanup the code a bit. Patch provided by Eric Sandeen. SGI-PV: 960196 SGI-Modid: xfs-linux-melb:xfs-kern:28034a Signed-off-by: Eric Sandeen Signed-off-by: David Chinner Signed-off-by: Tim Shimmin commit 39058a0e12a8b2dcb8f9345ecad52dbcfc120ef7 Author: Eric Sandeen Date: Sat Feb 10 18:37:10 2007 +1100 [XFS] Clean up use of VFS attr flags Use the the generic VFS attr flags where appropriate instead of open coding them to the same values. Patch provided by Eric Sandeen. SGI-PV: 960868 SGI-Modid: xfs-linux-melb:xfs-kern:28033a Signed-off-by: Eric Sandeen Signed-off-by: David Chinner Signed-off-by: Christoph Hellwig Signed-off-by: Tim Shimmin commit 4cf3b52080b3d354b10b8b1c9147bf88118b8eef Author: Ralf Baechle Date: Sat Feb 10 18:37:04 2007 +1100 [XFS] Remove useless memory barrier wake_up's implementation does an implicit memory barrier so the explicit memory barrier is not needed in vfs_sync_worker. Patch provided by Ralf Baechle. SGI-PV: 960867 SGI-Modid: xfs-linux-melb:xfs-kern:28032a Signed-off-by: Ralf Baechle Signed-off-by: David Chinner Signed-off-by: Tim Shimmin commit 3a68cbfe0277fb73d5f0c2a433884745fb500c38 Author: Eric W. Biederman Date: Sat Feb 10 18:36:59 2007 +1100 [XFS] XFS sysctl cleanups Removes unneeded sysctl insert at head behaviour. Cleans up sysctl definitions to use C99 initialisers. Patch provided by Eric W. Biederman. SGI-PV: 960192 SGI-Modid: xfs-linux-melb:xfs-kern:28031a Signed-off-by: Eric W. Biederman Signed-off-by: David Chinner Signed-off-by: Tim Shimmin commit c167b77d5e172a2deb058be442ca652ad3a417f9 Author: Lachlan McIlroy Date: Sat Feb 10 18:36:53 2007 +1100 [XFS] Fix assertion in xfs_attr_shortform_remove(). SGI-PV: 960791 SGI-Modid: xfs-linux-melb:xfs-kern:28021a Signed-off-by: Lachlan McIlroy Signed-off-by: Barry Naujok Signed-off-by: Tim Shimmin commit 681601613759accffd8e8ddbc6f942eba7ecbfe5 Author: Lachlan McIlroy Date: Sat Feb 10 18:36:47 2007 +1100 [XFS] Fix callers of xfs_iozero() to zero the correct range. The problem is the two callers of xfs_iozero() are rounding out the range to be zeroed to the end of a fsb and in some cases this extends past the new eof. The call to commit_write() in xfs_iozero() will cause the Linux inode's file size to be set too high. SGI-PV: 960788 SGI-Modid: xfs-linux-melb:xfs-kern:28013a Signed-off-by: Lachlan McIlroy Signed-off-by: David Chinner Signed-off-by: Tim Shimmin commit 2823945fda94e0636be573a037c45cb7b6495af2 Author: David Chinner Date: Sat Feb 10 18:36:40 2007 +1100 [XFS] Ensure a frozen filesystem has a clean log before writing the dummy record. The current Linux XFS freeze code is a mess. We flush the metadata buffers out while we are still allowing new transactions to start and then fail to flush the dirty buffers back out before writing the unmount and dummy records to the log. This leads to problems when the frozen filesystem is used for snapshots - we do log recovery on a readonly image and often it appears that the log image in the snapshot is not correct. Hence we end up with hangs, oops and mount failures when trying to mount a snapshot image that has been created when the filesystem has not been correctly frozen. To fix this, we need to move th metadata flush to after we wait for all current transactions to complete in teh second stage of the freeze. This means that when we write the final log records, the log should be clean and recovery should never occur on a snapshot image created from a frozen filesystem. SGI-PV: 959267 SGI-Modid: xfs-linux-melb:xfs-kern:28010a Signed-off-by: David Chinner Signed-off-by: Donald Douwsma Signed-off-by: Tim Shimmin commit 549054afadae44889c0b40d4c3bfb0207b98d5a0 Author: David Chinner Date: Sat Feb 10 18:36:35 2007 +1100 [XFS] Fix sub-block zeroing for buffered writes into unwritten extents. When writing less than a filesystem block of data into an unwritten extent via buffered I/O, __xfs_get_blocks fails to set the buffer new flag. As a result, the generic code will not zero either edge of the block resulting in garbage being written to disk either side of the real data. Set the buffer new state on bufferd writes to unwritten extents to ensure that zeroing occurs. SGI-PV: 960328 SGI-Modid: xfs-linux-melb:xfs-kern:28000a Signed-off-by: David Chinner Signed-off-by: Lachlan McIlroy Signed-off-by: Tim Shimmin commit 5478eead8528f6cb5ebe3015fb88b68b175e1093 Author: Lachlan McIlroy Date: Sat Feb 10 18:36:29 2007 +1100 [XFS] Re-initialize the per-cpu superblock counters after recovery. After filesystem recovery the superblock is re-read to bring in any changes. If the per-cpu superblock counters are not re-initialized from the superblock then the next time the per-cpu counters are disabled they might overwrite the global counter with a bogus value. SGI-PV: 957348 SGI-Modid: xfs-linux-melb:xfs-kern:27999a Signed-off-by: Lachlan McIlroy Signed-off-by: David Chinner Signed-off-by: Tim Shimmin commit c97be736051dacefb00643095d76fd5b70dfef7b Author: Kevin Jamieson Date: Sat Feb 10 18:36:23 2007 +1100 [XFS] Fix block reservation changes for non-SMP systems. SGI-PV: 956323 SGI-Modid: xfs-linux-melb:xfs-kern:27940a Signed-off-by: Kevin Jamieson Signed-off-by: David Chatterton Signed-off-by: David Chinner Signed-off-by: Tim Shimmin commit dbcabad19aa91dc9bc7176fd2853fa74f724cd2f Author: David Chinner Date: Sat Feb 10 18:36:17 2007 +1100 [XFS] Fix block reservation mechanism. The block reservation mechanism has been broken since the per-cpu superblock counters were introduced. Make the block reservation code work with the per-cpu counters by syncing the counters, snapshotting the amount of available space and then doing a modifcation of the counter state according to the result. Continue in a loop until we either have no space available or we reserve some space. SGI-PV: 956323 SGI-Modid: xfs-linux-melb:xfs-kern:27895a Signed-off-by: David Chinner Signed-off-by: Christoph Hellwig Signed-off-by: Tim Shimmin commit 20f4ebf2bf2f57c1a9abb3655391336cc90314b3 Author: David Chinner Date: Sat Feb 10 18:36:10 2007 +1100 [XFS] Make growfs work for amounts greater than 2TB The free block modification code has a 32bit interface, limiting the size the filesystem can be grown even on 64 bit machines. On 32 bit machines, there are other 32bit variables in transaction structures and interfaces that need to be expanded to allow this to work. SGI-PV: 959978 SGI-Modid: xfs-linux-melb:xfs-kern:27894a Signed-off-by: David Chinner Signed-off-by: Christoph Hellwig Signed-off-by: Tim Shimmin commit f74eaf59b36c0ad01f416b567f89c737bbf82bae Author: David Chinner Date: Sat Feb 10 18:36:04 2007 +1100 [XFS] Fix inode log item use-after-free on forced shutdown SGI-PV: 959388 SGI-Modid: xfs-linux-melb:xfs-kern:27805a Signed-off-by: David Chinner Signed-off-by: Lachlan McIlroy Signed-off-by: Tim Shimmin commit e5889e90dda328443161e9512f1123c9814d03de Author: Barry Naujok Date: Sat Feb 10 18:35:58 2007 +1100 [XFS] Fix attr2 corruption with btree data extents SGI-PV: 958747 SGI-Modid: xfs-linux-melb:xfs-kern:27792a Signed-off-by: Barry Naujok Signed-off-by: Russell Cattelan Signed-off-by: Tim Shimmin commit 7666ab5fb378678a9d5eb3c0dc8d3170e274e7a4 Author: Vlad Apostolov Date: Sat Feb 10 18:35:52 2007 +1100 [XFS] Workaround log space issue by increasing XFS_TRANS_PUSH_AIL_RESTARTS SGI-PV: 959264 SGI-Modid: xfs-linux-melb:xfs-kern:27750a Signed-off-by: Vlad Apostolov Signed-off-by: David Chatterton Signed-off-by: Tim Shimmin commit 5180602e6fd6f7d221e51670567f3809ecfe968f Author: Lachlan McIlroy Date: Sat Feb 10 18:35:46 2007 +1100 [XFS] remove unused filp from ioctl functions SGI-PV: 959140 SGI-Modid: xfs-linux-melb:xfs-kern:27712a Signed-off-by: Lachlan McIlroy Signed-off-by: Eric Sandeen Signed-off-by: Tim Shimmin commit a3227fb99675ebcdbe89e6954a85742c0dd11f0a Author: Lachlan McIlroy Date: Sat Feb 10 18:35:40 2007 +1100 [XFS] mraccessf & mrupdatef are supposed to be the "flags" versions of the functions, but they a) ignore the flags parameter completely, and b) are never called directly, only via the flag-less defines anyway So, drop the #define indirection, and rename mraccessf to mraccess, etc. SGI-PV: 959138 SGI-Modid: xfs-linux-melb:xfs-kern:27711a Signed-off-by: Lachlan McIlroy Signed-off-by: Eric Sandeen Signed-off-by: Tim Shimmin commit 1f9b3b64d417a714eb79d9a4cd4927ab304b0fc0 Author: Lachlan McIlroy Date: Sat Feb 10 18:35:33 2007 +1100 [XFS] remove unused xflags parameter from sync routines SGI-PV: 959137 SGI-Modid: xfs-linux-melb:xfs-kern:27710a Signed-off-by: Lachlan McIlroy Signed-off-by: Eric Sandeen Signed-off-by: Tim Shimmin commit 1c91ad3aedba82a64ae06a5a0a5651105d378112 Author: Lachlan McIlroy Date: Sat Feb 10 18:35:27 2007 +1100 [XFS] fix sparse warning in xfs_da_btree.c SGI-PV: 954580 SGI-Modid: xfs-linux-melb:xfs-kern:27702a Signed-off-by: Lachlan McIlroy Signed-off-by: Christoph Hellwig Signed-off-by: Tim Shimmin commit e5eb7f202b7a1a2d20a0b9866805314bf6464fd0 Author: Lachlan McIlroy Date: Sat Feb 10 18:35:21 2007 +1100 [XFS] use struct kvec in struct uio SGI-PV: 954580 SGI-Modid: xfs-linux-melb:xfs-kern:27701a Signed-off-by: Lachlan McIlroy Signed-off-by: Christoph Hellwig Signed-off-by: Tim Shimmin commit 03135cf72621fccab57728f0ba3ab5a551df1cc1 Author: David Chinner Date: Sat Feb 10 18:35:15 2007 +1100 [XFS] Fix UP build breakage due to undefined m_icsb_mutex. SGI-PV: 952227 SGI-Modid: xfs-linux-melb:xfs-kern:27692a Signed-off-by: David Chinner Signed-off-by: Lachlan McIlroy Signed-off-by: Tim Shimmin commit 20b642858b6bb413976ff13ae6a35cc596967bab Author: David Chinner Date: Sat Feb 10 18:35:09 2007 +1100 [XFS] Reduction global superblock lock contention near ENOSPC. The existing per-cpu superblock counter code uses the global superblock spin lock when we approach ENOSPC for global synchronisation. On larger machines than this code was originally tested on this can still get catastrophic spinlock contention due increasing rebalance frequency near ENOSPC. By introducing a sleeping lock that is used to serialise balances and modifications near ENOSPC we prevent contention from needlessly from wasting the CPU time of potentially hundreds of CPUs. To reduce the number of balances occuring, we separate the need rebalance case from the slow allocate case. Now, a counter running dry will trigger a rebalance during which counters are disabled. Any thread that sees a disabled counter enters a different path where it waits on the new mutex. When it gets the new mutex, it checks if the counter is disabled. If the counter is disabled, then we _know_ that we have to use the global counter and lock and it is safe to do so immediately. Otherwise, we drop the mutex and go back to trying the per-cpu counters which we know were re-enabled. SGI-PV: 952227 SGI-Modid: xfs-linux-melb:xfs-kern:27612a Signed-off-by: David Chinner Signed-off-by: Lachlan McIlroy Signed-off-by: Tim Shimmin commit 804195b63a6dcb767f5fae43b435067079b52903 Author: Eric Sandeen Date: Sat Feb 10 18:35:02 2007 +1100 [XFS] Get rid of old 5.3/6.1 v1 log items. Cleanup patch sent in by Eric Sandeen. SGI-PV: 958736 SGI-Modid: xfs-linux-melb:xfs-kern:27596a Signed-off-by: Eric Sandeen Signed-off-by: Tim Shimmin commit 7989cb8ef5dbc1411d3be48218c7b25ef6e71699 Author: David Chinner Date: Sat Feb 10 18:34:56 2007 +1100 [XFS] Keep stack usage down for 4k stacks by using noinline. gcc-4.1 and more recent aggressively inline static functions which increases XFS stack usage by ~15% in critical paths. Prevent this from occurring by adding noinline to the STATIC definition. Also uninline some functions that are too large to be inlined and were causing problems with CONFIG_FORCED_INLINING=y. Finally, clean up all the different users of inline, __inline and __inline__ and put them under one STATIC_INLINE macro. For debug kernels the STATIC_INLINE macro uninlines those functions. SGI-PV: 957159 SGI-Modid: xfs-linux-melb:xfs-kern:27585a Signed-off-by: David Chinner Signed-off-by: David Chatterton Signed-off-by: Tim Shimmin commit 5e6a07dfe404cd4d8494d842b54706cb007fa04b Author: David Chinner Date: Sat Feb 10 18:34:49 2007 +1100 [XFS] Current usage of buftarg flags is incorrect. The {test,set,clear}_bit() operations take a bit index for the bit to operate on. The XBT_* flags are defined as bit fields which is incorrect, not to mention the way the bit fields are enumerated is broken too. This was only working by chance. Fix the definitions of the flags and make the code using them use the {test,set,clear}_bit() operations correctly. SGI-PV: 958639 SGI-Modid: xfs-linux-melb:xfs-kern:27565a Signed-off-by: David Chinner Signed-off-by: Tim Shimmin commit dc74eaad8cda9f12a885639b4f2513c99e9b483a Author: Lachlan McIlroy Date: Sat Feb 10 18:34:38 2007 +1100 [XFS] Prevent buffer overrun in cmn_err(). The message buffer used by cmn_err() is only 256 bytes and some CXFS messages were exceeding this length. Since we were using vsprintf() and not checking for buffer overruns we were clobbering memory beyond the buffer. The size of the buffer has been increased to 1024 bytes so we can capture these larger messages and we are now using vsnprintf() to prevent overrunning the buffer size. SGI-PV: 958599 SGI-Modid: xfs-linux-melb:xfs-kern:27561a Signed-off-by: Lachlan McIlroy Signed-off-by: Geoffrey Wehrman Signed-off-by: Tim Shimmin commit 585e6d8856526a846b90b485abf37ec40e5da1cf Author: David Chinner Date: Sat Feb 10 18:32:29 2007 +1100 [XFS] Fix a synchronous buftarg flush deadlock when freezing. At the last stage of a freeze, we flush the buftarg synchronously over and over again until it succeeds twice without skipping any buffers. The delwri list flush skips pinned buffers, but tries to flush all others. It removes the buffers from the delwri list, then tries to lock them one at a time as it traverses the list to issue the I/O. It holds them locked until we issue all of the I/O and then unlocks them once we've waited for it to complete. The problem is that during a freeze, the filesystem may still be doing stuff - like flushing delalloc data buffers - in the background and hence we can be trying to lock buffers that were on the delwri list at the same time. Hence we can get ABBA deadlocks between threads doing allocation and the buftarg flush (freeze) thread. Fix it by skipping locked (and pinned) buffers as we traverse the delwri buffer list. SGI-PV: 957195 SGI-Modid: xfs-linux-melb:xfs-kern:27535a Signed-off-by: David Chinner Signed-off-by: Tim Shimmin commit dac61f521b1e4d2c6c48023f2f2743c6096b48ca Author: David Chinner Date: Sat Feb 10 18:27:56 2007 +1100 [XFS] Make quiet mounts quiet The XFS quiet mount logic was inverted making quiet mounts noisy and vice versa. Fix it. SGI-PV: 958469 SGI-Modid: xfs-linux-melb:xfs-kern:27520a Signed-off-by: David Chinner Signed-off-by: Eric Sandeen Signed-off-by: Tim Shimmin commit 2a598df595d33be0f12e37ef5df75eff13511d07 Author: Jiri Slaby Date: Sat Feb 10 01:30:18 2007 -0500 Input: remove scan_keyb driver This driver is currently unused (unreferenced) besides the fact that it's broken. Signed-off-by: Jiri Slaby Signed-off-by: Dmitry Torokhov commit 1e4865f8d469b1795e77877410951e5b808a2c4e Author: Dmitry Torokhov Date: Sat Feb 10 01:29:53 2007 -0500 Input: i8042 - fix AUX IRQ delivery check On boxes that do not implement AUX LOOP command we can not verify AUX IRQ delivery and must assume that it is wired properly. Signed-off-by: Dmitry Torokhov commit 5809d537c1bc7628cee1e580da35f6b4d254e23b Author: Michael Leun Date: Sat Feb 10 01:29:42 2007 -0500 Input: wistron - add support for Fujitsu-Siemens Amilo D88x0 Tested on a Amilo D8820. Signed-off-by: Michael Leun Signed-off-by: Dmitry Torokhov commit 8370a643531699e5076fcac21c281c138bce1c87 Author: Robert P. J. Day Date: Sat Feb 10 01:29:31 2007 -0500 Input: inport - use correct config option for ATIXL Change the apparently incorrect check for CONFIG_INPUT_ATIXL in a source file to be consistent with the kernel config option CONFIG_MOUSE_ATIXL. Signed-off-by: Robert P. J. Day Signed-off-by: Andrew Morton Signed-off-by: Dmitry Torokhov commit b350620cc5e8e62782a4d47bf45952442a18a0b0 Author: Cyrill V. Gorcunov Date: Sat Feb 10 01:29:19 2007 -0500 Input: HIL - handle erros from input_register_device() Also some whitespace cleanup. Signed-off-by: Cyrill V. Gorcunov Signed-off-by: Andrew Morton Signed-off-by: Dmitry Torokhov commit ff141a03e1909db719c6afd3230c2f16a4141860 Author: Richard Purdie Date: Sat Feb 10 01:29:11 2007 -0500 Input: tsdev - schedule removal Compaq touchscreen emulation (drivers/input/tsdev.c) is old, was obsolete when it was written by the authors own admission and much better userspace solutions like tslib now exist. The name is also confusing. Signed-off-by: Richard Purdie Acked-by: James Simmons Signed-off-by: Dmitry Torokhov commit 31ea7ff0f880dc3f4ad94e85c1432d4b910c9fca Author: Jaya Kumar Date: Sat Feb 10 01:29:00 2007 -0500 Input: add Atlas button driver This patch adds support for the buttons on the Atlas wallmount touchscreen. Signed-off-by: Jaya Kumar Acked-by: Len Brown Signed-off-by: Dmitry Torokhov commit 66efc5a7e3061c3597ac43a8bb1026488d57e66b Author: Jeff Garzik Date: Tue Feb 6 22:19:10 2007 -0500 libata: kill ATA_ENABLE_PATA The ATA_ENABLE_PATA define was never meant to be permanent, and in recent kernels, it's already been unconditionally enabled. Remove. Signed-off-by: Jeff Garzik commit 591a6e8ee7c8ffbbeaf23fec23796c0cfa316a41 Author: Jeff Garzik Date: Tue Feb 6 21:08:14 2007 -0500 libata: build fix after dmesg probe output changes Signed-off-by: Jeff Garzik commit 11750a40abddff1e0c6e0924902f914292d12277 Author: Alan Date: Mon Feb 5 16:28:30 2007 +0000 libata: Early CFA adapters are not required to support mode setting If we are doing a PIO setup for a CFA card and it blows up with a device error then assume it is an older CFA card which doesn't support this rather than failing the device out of existance. Stands seperate to the quieting patch but that is obviously useful with this change. Signed-off-by: Alan Cox Signed-off-by: Jeff Garzik commit ce053fa8b532aa038fba6230052daae5cd60eae6 Author: Robert Hancock Date: Mon Feb 5 16:26:04 2007 -0800 sata_nv: propagate ata_pci_device_do_resume return value ata_pci_device_do_resume can fail if the PCI device couldn't be re-enabled. Update sata_nv to propagate the return value from this call and to not try to do any other resume activities if it fails. Fixes a compile warning. Signed-off-by: Robert Hancock Signed-off-by: Andrew Morton Signed-off-by: Jeff Garzik commit a2cfe81a59eea45a3f9afb4f652f7619982eac62 Author: Robert Hancock Date: Mon Feb 5 16:26:03 2007 -0800 sata_nv: wait for response on entering/leaving ADMA mode Update sata_nv to wait for the controller to indicate via the status register that it has entered the requested state when switching between ADMA mode and register mode. This issue came up recently when debugging some problems with cache flush command timeouts and while it didn't appear to fix that problem, this is something we should likely be doing in any case. Signed-off-by: Robert Hancock Cc: Tejun Heo Cc: Jeff Garzik Signed-off-by: Andrew Morton Signed-off-by: Jeff Garzik commit 382a6652e91b34d5480cfc0ed840c196650493d4 Author: Robert Hancock Date: Mon Feb 5 16:26:02 2007 -0800 sata_nv: use ADMA for NODATA commands Some problems showed up recently with cache flush commands timing out on sata_nv. Previously these commands were always handled by transitioning to legacy mode from ADMA mode first. The timeout problem was worked around already by a change to the interrupt handling code for legacy mode, but for non-data commands like these it appears we can handle them in ADMA mode, so the switch to legacy mode is not needed. This patch changes the behavior so that we use ADMA mode to submit interrupt-driven commands with ATA_PROT_NODATA protocol. In addition to avoiding the problem mentioned above entirely, this avoids the overhead of switching to legacy mode and back to ADMA mode for handling cache flushes. When handling non-DMA-mapped commands, we leave the APRD blank and clear the NV_CPB_CTL_APRD_VALID field in the CPB so the controller does not attempt to read it. Signed-off-by: Robert Hancock Cc: Jeff Garzik Cc: Tejun Heo Signed-off-by: Andrew Morton Signed-off-by: Jeff Garzik commit 5bd28a4b6efa73c5d033f3b86201c2c366b170cf Author: Robert Hancock Date: Mon Feb 5 16:26:01 2007 -0800 sata_nv: cleanup ADMA error handling This cleans up a few issues with the error handling in sata_nv in ADMA mode to make it more consistent with other NCQ-capable drivers like ahci and sata_sil24: - When a command failed, we would effectively set AC_ERR_DEV on the queued command always. In the case of NCQ commands this prevents libata from doing a log page query to determine the details of the failed command, since it thinks we've already analyzed. Just set flags in the port ehi->err_mask, then freeze or abort and let libata figure out what went wrong. - The code handled NV_ADMA_STAT_CPBERR as a "really bad error" which caused it to set error flags on every queued command. I don't know exactly what this flag means (no docs, grr!) but from what I can guess from the standard ADMA spec, it just means that one or more of the CPBs had an error, so we just need to go through and do our normal checks in this case. - In the error_handler function the code would always dump the state of all the CPBs. This output seems redundant at this point since libata already dumps the state of all active commands on errors (and it also triggers at times when it shouldn't, like when suspending). Take this out. [akpm@osdl.org: many coding-style fixes] Signed-off-by: Robert Hancock Cc: Jeff Garzik Cc: Tejun Heo Cc: Allen Martin Signed-off-by: Andrew Morton Signed-off-by: Jeff Garzik commit 92ae78493f5f3de323652f3ea0ec8b7b2839c3d2 Author: Sergei Shtylyov Date: Mon Feb 5 21:08:55 2007 +0300 (2.6.20) pata_mpiix: probing cleanup (resend) MPIIX has only single channel IDE which can be configured for either primary or secondary legacy I/O ports and IRQ. So, get rid of the unneeded second probe entry in mpiix_init_one() and of the invalid (but unused anyway) enable bits in mpiix_pre_reset(). Warning: this cleanup has only been compile-tested... Signed-off-by: Sergei Shtylyov Signed-off-by: Jeff Garzik commit 7b4f1a13f708a7b061185d86aae201f3195db47a Author: Sergei Shtylyov Date: Mon Feb 5 20:24:57 2007 +0300 (2.6.20) pata_mpiix: fix PIO setup issues Fix clearing/setting the wrong TIME/IE/PPE bits for a slave drive caused by a wrong shift count. Fix the PIO mode 1 being overclocked by wrongly selecting the fast timing bank. Also, fix/rephrase some comments while at it. Signed-off-by: Sergei Shtylyov Signed-off-by: Jeff Garzik commit 409ba47c297fd13849909adea63f183f55d52418 Author: Sergei Shtylyov Date: Mon Feb 5 19:45:38 2007 +0300 (2.6.20) pata_oldpiix: fix PIO2 underclocking Fix the PIO mode 2 using mode 0 timings -- this driver should enable the fast timing bank starting with PIO2, just like the ata_piix driver does. Also, fix/rephrase some comments while at it. Signed-off-by: Sergei Shtylyov Signed-off-by: Jeff Garzik commit 49554c19569c91d0943b67ca731c9abfc857883f Author: Alan Date: Mon Feb 5 16:17:19 2007 +0000 ata: Add defines for the iordy bits IORDY and IORDY enable/disable flags. Signed-off-by: Alan Cox Signed-off-by: Jeff Garzik commit 2c7620d50c23737728bccfb26ffb94cd51e58007 Author: Alan Date: Mon Feb 5 16:04:10 2007 +0000 Kconfig: clarify ATA_PIIX description People are getting confused about which drivers to enable for PATA PIIX type devices. Change the ATA_PIIX line and help to make it clearer. Signed-off-by: Alan Cox Signed-off-by: Jeff Garzik commit fe334602a83463aff59ae24c4b3e808d650a3c80 Author: Tejun Heo Date: Fri Feb 2 15:29:52 2007 +0900 sata_inic162x: fix a few glitches in hardreset * Hardreset must not exit without actually performing reset regardless of link status. We're resetting the link after all. * Minor message update. * 150ms delay is meaningful iff link is online after reset is complete. Signed-off-by: Tejun Heo Signed-off-by: Jeff Garzik commit 34fee227dd13af593be599b19683464ac4dd4c8b Author: Tejun Heo Date: Fri Feb 2 15:29:27 2007 +0900 libata: add 150ms between completion of hardreset and status checking Follow the old SRST rule and delay 150ms between completion of hardreset and status checking. Debouncing delay should usually cover this but debounce duration could be shorter than 150ms under certain circumstances. Usefulness depends on host controller implementation but it can't hurt and serves as a reminder that 2s delay for GoVault should also be added here. Signed-off-by: Tejun Heo Signed-off-by: Jeff Garzik commit 3f64f565bebbb4a1a4e9ccce5565c9f86458ddb1 Author: Eric D. Mudama Date: Tue Jan 30 23:00:40 2007 -0700 libata: rearrange dmesg info to add full ATA revision Per Jeff's suggestion, this patch rearranges the info printed for ATA drives into dmesg to add the full ATA firmware revision and model information, while keeping the output to 2 lines. Signed-off-by: Eric D. Mudama Signed-off-by: Jeff Garzik commit 24a01453892e0a4a6ad38460541bd0dae9b1837f Author: Sergei Shtylyov Date: Tue Jan 30 20:40:30 2007 +0300 pata_sl82c105: wrong assumptions about compatible PIO modes Fix the wrong "compatible" PIO mode choices: MWDMA0 has 480 ns cycle while PIO1 only has 383 ns cycle, and MWDMA2 timings matchs those of PIO4 exactly. Signed-off-by: Jeff Garzik commit 246ce3b675843e0369643cceb4faeb6cf6d19a30 Author: Akira Iguchi Date: Fri Jan 26 16:27:58 2007 +0900 libata: add another IRQ calls (libata drivers) This patch is against each libata driver. Two IRQ calls are added in ata_port_operations. - irq_on() is used to enable interrupts. - irq_ack() is used to acknowledge a device interrupt. In most drivers, ata_irq_on() and ata_irq_ack() are used for irq_on and irq_ack respectively. In some drivers (ex: ahci, sata_sil24) which cannot use them as is, ata_dummy_irq_on() and ata_dummy_irq_ack() are used. Signed-off-by: Kou Ishizaki Signed-off-by: Akira Iguchi Signed-off-by: Jeff Garzik commit 836250069fc0eeebe8b6aed772281535cc6e34f9 Author: Akira Iguchi Date: Fri Jan 26 16:27:32 2007 +0900 libata: add another IRQ calls (core and headers) This patch is against the libata core and headers. Two IRQ calls are added in ata_port_operations. - irq_on() is used to enable interrupts. - irq_ack() is used to acknowledge a device interrupt. In most drivers, ata_irq_on() and ata_irq_ack() are used for irq_on and irq_ack respectively. In some drivers (ex: ahci, sata_sil24) which cannot use them as is, ata_dummy_irq_on() and ata_dummy_irq_ack() are used. Signed-off-by: Kou Ishizaki Signed-off-by: Akira Iguchi Signed-off-by: Jeff Garzik commit 7f25377043925554cb9f3f9d8ada3390f71a5d10 Author: Andrew Morton Date: Fri Feb 2 18:07:15 2007 -0800 git-libata-all: forward declare struct device In file included from drivers/infiniband/hw/ipath/ipath_diag.c:44: include/linux/io.h:35: warning: 'struct device' declared inside parameter list include/linux/io.h:35: warning: its scope is only this definition or declaration Cc: Jeff Garzik Signed-off-by: Andrew Morton Signed-off-by: Jeff Garzik commit 0d5ff566779f894ca9937231a181eb31e4adff0e Author: Tejun Heo Date: Thu Feb 1 15:06:36 2007 +0900 libata: convert to iomap Convert libata core layer and LLDs to use iomap. * managed iomap is used. Pointer to pcim_iomap_table() is cached at host->iomap and used through out LLDs. This basically replaces host->mmio_base. * if possible, pcim_iomap_regions() is used Most iomap operation conversions are taken from Jeff Garzik 's iomap branch. Signed-off-by: Tejun Heo Signed-off-by: Jeff Garzik commit 1a68ff13c8a9b517de3fd4187dc525412a6eba1b Author: Tejun Heo Date: Thu Feb 1 15:05:22 2007 +0900 pata_platform: fix devres conversion devres updates for pata_platform were dropped while merging devres patches due to merge conflict. This is the updated version. Signed-off-by: Tejun Heo Signed-off-by: Jeff Garzik commit ca2997885219486cf91a369233c909fbd555bdf7 Author: Tejun Heo Date: Wed Jan 31 22:48:06 2007 +0900 iomap: iomap should be in obj-y not in lib-y devres change moved iomap.o from obj-$(CONFIG_GENERIC_IOMAP) to lib-y making it not linked if no in-kernel driver uses it. Fix it. Signed-off-by: Tejun Heo Signed-off-by: Jeff Garzik commit fda0efc5977864a90f365aeeb13f2546854e2aa9 Author: Jeff Garzik Date: Wed Jan 31 07:43:15 2007 -0500 [libata] Shuffle DRV_xxx in core and SiS drivers, to kill warnings Signed-off-by: Jeff Garzik commit d24bbbf251e70bf984cbaa9b1fcadc5f56fc3ae9 Author: Tejun Heo Date: Sat Jan 20 16:00:28 2007 +0900 devres: implement pcim_iomap_regions() Implement pcim_iomap_regions(). This function takes mask of BARs to request and iomap. No BAR should have length of zero. BARs are iomapped using pcim_iomap_table(). Signed-off-by: Tejun Heo Signed-off-by: Jeff Garzik commit b878ca5d37953ad1c4578b225a13a3c3e7e743b7 Author: Tejun Heo Date: Sat Jan 20 16:00:28 2007 +0900 libata: remove unused functions Now that all LLDs are converted to use devres, default stop callbacks are unused. Remove them. Signed-off-by: Tejun Heo Signed-off-by: Jeff Garzik commit 24dc5f33ea4b504cfbd23fa159a4cacba8e4d800 Author: Tejun Heo Date: Sat Jan 20 16:00:28 2007 +0900 libata: update libata LLDs to use devres Update libata LLDs to use devres. Core layer is already converted to support managed LLDs. This patch simplifies initialization and fixes many resource related bugs in init failure and detach path. For example, all converted drivers now handle ata_device_add() failure gracefully without excessive resource rollback code. As most resources are released automatically on driver detach, many drivers don't need or can do with much simpler ->{port|host}_stop(). In general, stop callbacks are need iff port or host needs to be given commands to shut it down. Note that freezing is enough in many cases and ports are automatically frozen before being detached. Signed-off-by: Tejun Heo Signed-off-by: Jeff Garzik commit f0d36efdc624beb3d9e29b9ab9e9537bf0f25d5b Author: Tejun Heo Date: Sat Jan 20 16:00:28 2007 +0900 libata: update libata core layer to use devres Update libata core layer to use devres. * ata_device_add() acquires all resources in managed mode. * ata_host is allocated as devres associated with ata_host_release. * Port attached status is handled as devres associated with ata_host_attach_release(). * Initialization failure and host removal is handedl by releasing devres group. * Except for ata_scsi_release() removal, LLD interface remains the same. Some functions use hacky is_managed test to support both managed and unmanaged devices. These will go away once all LLDs are updated to use devres. Signed-off-by: Tejun Heo Signed-off-by: Jeff Garzik commit 0529c159dbdd79794796c1b50b39442d72efbe97 Author: Tejun Heo Date: Sat Jan 20 16:00:26 2007 +0900 libata: implement ata_host_detach() Implement ata_host_detach() which calls ata_port_detach() for each port in the host and export it. ata_port_detach() is now internal and thus un-exported. ata_host_detach() will be used as the 'deregister from libata layer' function after devres conversion. Signed-off-by: Tejun Heo Signed-off-by: Jeff Garzik commit 9ac7849e35f705830f7b016ff272b0ff1f7ff759 Author: Tejun Heo Date: Sat Jan 20 16:00:26 2007 +0900 devres: device resource management Implement device resource management, in short, devres. A device driver can allocate arbirary size of devres data which is associated with a release function. On driver detach, release function is invoked on the devres data, then, devres data is freed. devreses are typed by associated release functions. Some devreses are better represented by single instance of the type while others need multiple instances sharing the same release function. Both usages are supported. devreses can be grouped using devres group such that a device driver can easily release acquired resources halfway through initialization or selectively release resources (e.g. resources for port 1 out of 4 ports). This patch adds devres core including documentation and the following managed interfaces. * alloc/free : devm_kzalloc(), devm_kzfree() * IO region : devm_request_region(), devm_release_region() * IRQ : devm_request_irq(), devm_free_irq() * DMA : dmam_alloc_coherent(), dmam_free_coherent(), dmam_declare_coherent_memory(), dmam_pool_create(), dmam_pool_destroy() * PCI : pcim_enable_device(), pcim_pin_device(), pci_is_managed() * iomap : devm_ioport_map(), devm_ioport_unmap(), devm_ioremap(), devm_ioremap_nocache(), devm_iounmap(), pcim_iomap_table(), pcim_iomap(), pcim_iounmap() Signed-off-by: Tejun Heo Signed-off-by: Jeff Garzik commit 77a527eadb425b60db3f5f0aae6a4c51c38e35e5 Author: Adrian Bunk Date: Tue Jan 30 00:59:17 2007 -0800 fix CONFIG_SATA_SIS=y compile error Static code shouldn't be used from other modules. drivers/built-in.o: In function `sis_init_one': sata_sis.c:(.text+0x7634cd): undefined reference to `sis_info133' sata_sis.c:(.text+0x7634d6): undefined reference to `sis_info133' While I was at it, I also moved the prototype of this struct to a header file. Signed-off-by: Adrian Bunk Cc: Jeff Garzik Cc: Tejun Heo Signed-off-by: Andrew Morton Signed-off-by: Jeff Garzik commit 9b14dec5adf47287a2b52fc9fdedd6a0e245daca Author: Alan Date: Mon Jan 8 16:11:07 2007 +0000 sata_sis: Support for PATA supports This is quick rework of the patch Uwe proposed but using Kconfig not ifdefs and user selection to sort out PATA support. Instead of ifdefs and requiring the user to select both drivers the SATA driver selects the PATA one. For neatness I've also moved the extern into the function that uses it. Signed-off-by: Alan Cox Signed-off-by: Jeff Garzik commit 5924b74c1cde5ef0246cf0dfbe689b27ffbe815b Author: Tejun Heo Date: Tue Jan 2 20:20:07 2007 +0900 libata: implement HDIO_GET_IDENTITY 'hdparm -I' doesn't work with ATAPI devices and sg_sat is not widely spread yet leaving no easy way to access ATAPI IDENTIFY data. Implement HDIO_GET_IDENTITY such that at least 'hdparm -i' works. Signed-off-by: Tejun Heo Signed-off-by: Jeff Garzik commit 18d90deb07ed6fc1818b0f0b326ecc788cea514e Author: Alan Date: Wed Jan 24 11:42:38 2007 +0000 libata: trivial stuff Readability/typos etc Signed-off-by: Alan Cox Signed-off-by: Jeff Garzik commit 0feb573f1588f3204a4558896c73703bc54d1862 Author: Tejun Heo Date: Sat Jan 20 13:12:46 2007 +0900 sata_promise: kill qc->nsect Merge order left qc->nsect usage in sata_promise dangling. Kill it. Signed-off-by: Tejun Heo Signed-off-by: Jeff Garzik commit dedf61db4f689b12c448b48426330290f98ed321 Author: Andrew Morton Date: Wed Jan 10 17:20:34 2007 -0800 libata piix3 support warning fix Signed-off-by: Andrew Morton Signed-off-by: Jeff Garzik commit d2cdfc0db39247518585db13a3abdc633a158e0e Author: Alan Date: Wed Jan 10 17:13:38 2007 +0000 libata: PIIX3 support This I believe completes the PIIX range of support for libata This adds the table entries needed for the PIIX3, both a new PCI identifier and a new mode list. It also fixes an erroneous access to PCI configuration 0x48 on non UDMA capable chips. Signed-off-by: Alan Cox Signed-off-by: Jeff Garzik commit fba6edbd3bbd5e6c10b8247d3c3794e718bbc811 Author: Mikael Pettersson Date: Sat Jan 13 21:32:30 2007 +0100 sata_promise: handle ATAPI_NODATA ourselves This patch extends sata_promise to handle ATAPI_NODATA commands internally. However, commands destined to ATA_DFLAG_CDB_INTR devices are excluded from this and continue to be returned to libata. Concrete changes: - pdc_atapi_dma_pkt() is renamed to pdc_atapi_pkt(), and is extended to set up correct headers for NODATA packets - pdc_qc_prep() calls pdc_atapi_pkt() for ATAPI_NODATA - pdc_host_intr() handles ATAPI_NODATA - pdc_qc_issue_prot() sends ATAPI_NODATA packets via the chip's packet mechanism, except for CDB_INTR devices Tested on first- and second-generation chips, SATAPI and PATAPI, with no observable regressions. Signed-off-by: Mikael Pettersson Signed-off-by: Jeff Garzik commit 4113bb6b67ced963b3269a72f335dd278543b56d Author: Mikael Pettersson Date: Sat Jan 13 21:31:05 2007 +0100 sata_promise: issue ATAPI commands as normal packets This patch (against libata #upstream + the ATAPI cleanup patch) reimplements sata_promise's ATAPI support to format ATAPI DMA commands as normal packets, and to issue them via the hardware's normal packet machinery. It turns out that the only reason for issuing ATAPI DMA commands via the pdc_issue_atapi_pkt_cmd() procedure was to perform two interrupt-fiddling steps for ATA_DFLAG_CDB_INTR devices. But these steps aren't needed because sata_promise sets ATA_FLAG_PIO_POLLING, which disables DMA for those devices. The remaining steps can easily be done in ATA taskfile packets. Concrete changes: - pdc_atapi_dma_pkt() is extended to program all packet setup steps, and not just contain the CDB; the sequence of steps exactly mirrors what pdc_issue_atapi_pkt_cmd() did - pdc_atapi_dma_pkt() needed more parameters: simplify it by just passing 'qc' and having it extract the data it needs - pdc_issue_atai_pkt_cmd() and its two helper procedures pdc_wait_for_drq() and pdc_wait_on_busy() are removed Tested on first- and second-generation chips, SATAPI and PATAPI, with no observable regressions. Signed-off-by: Mikael Pettersson Signed-off-by: Jeff Garzik commit 73fd456b2dd770ab4fcf14b9d45b7482237a2cf7 Author: Mikael Pettersson Date: Wed Jan 10 09:32:34 2007 +0100 sata_promise: ATAPI cleanup Here's a cleanup for yesterday's sata_promise ATAPI patch: - add and use a symbolic constant for the altstatus register - check return status from ata_busy_wait() - add missing newline in a warning printk() - update comment in pdc_issue_atapi_pkt_cmd() to clarify that the maybe-wait-for-INT issue cannot occur in the current driver, but may occur if the driver starts issuing ATAPI non-DMA commands as PDC packets Signed-off-by: Mikael Pettersson Signed-off-by: Jeff Garzik commit 1fd7a697a37bcd484b130a71326e43cd68ced90c Author: Tejun Heo Date: Wed Jan 3 17:32:45 2007 +0900 sata_inic162x: finally, driver for initio 162x SATA controllers, take #2 Driver for Initio 162x SATA controllers. ATA r/w, ATAPI r, hotplug and suspend/resume work. ATAPI w (recording, that is) broken. Feel free to fix it, but be warned, this controller is weird. Signed-off-by: Tejun Heo Signed-off-by: Jeff Garzik commit 726f0785b608d09bdd64bdbadc09217ebbf9920e Author: Tejun Heo Date: Wed Jan 3 17:30:39 2007 +0900 libata: kill qc->nsect and cursect libata used two separate sets of variables to record request size and current offset for ATA and ATAPI. This is confusing and fragile. This patch replaces qc->nsect/cursect with qc->nbytes/curbytes and kills them. Also, ata_pio_sector() is updated to use bytes for qc->cursg_ofs instead of sectors. The field used to be used in bytes for ATAPI and in sectors for ATA. Signed-off-by: Tejun Heo Signed-off-by: Jeff Garzik commit 16454445e1f0ca21ca2f29accb58478a7ff765a2 Author: Jeff Garzik Date: Tue Jan 9 06:28:24 2007 -0500 [libata] sata_vsc: build fix after PCI MSI feature addition Signed-off-by: Jeff Garzik commit 7cbaa86b937b0b1fab95c159989f6a3c00bbcf78 Author: Dan Wolstenholme Date: Tue Jan 9 05:59:21 2007 -0500 [libata] sata_vsc: support PCI MSI Signed-off-by: Jeff Garzik commit 553c4aa630af7bc885e056d0436e4eb7f238579b Author: Tejun Heo Date: Tue Dec 26 19:39:50 2006 +0900 libata: handle pci_enable_device() failure while resuming Handle pci_enable_device() failure while resuming. This patch kills the "ignoring return value of 'pci_enable_device'" warning message and propagates __must_check through ata_pci_device_do_resume(). Signed-off-by: Tejun Heo Signed-off-by: Jeff Garzik commit 8bfa79fcb81d2bdb043f60ab4171704467808b55 Author: Tejun Heo Date: Tue Jan 2 20:19:40 2007 +0900 libata: use ata_id_c_string() There were several places where ATA ID strings are manually terminated and in some places possibly unterminated strings were passed to string functions which don't limit length like strstr(). This patch converts all of them over to ata_id_c_string(). Signed-off-by: Tejun Heo Signed-off-by: Jeff Garzik commit a0cf733b333eeeafb7324e2897448006c693c26c Author: Tejun Heo Date: Tue Jan 2 20:18:49 2007 +0900 libata: straighten out ATA_ID_* constants * Kill _OFS suffixes in ATA_ID_{SERNO|FW_REV|PROD}_OFS for consistency with other ATA_ID_* constants. * Kill ATA_SERNO_LEN * Add and use ATA_ID_SERNO_LEN, ATA_ID_FW_REV_LEN and ATA_ID_PROD_LEN. This change also makes ata_device_blacklisted() use proper length for fwrev. Signed-off-by: Tejun Heo Signed-off-by: Jeff Garzik commit cdf56bcf14b9d441777703eef95eef807e4136ec Author: Robert Hancock Date: Wed Jan 3 18:13:57 2007 -0600 sata_nv: add suspend/resume support v3 (Resubmit) Thoughts from Jeff & company on merging the patch below into libata-dev? This has been in the -mm tree for over a month now, I haven't heard any complaints about regressions.. Signed-off-by: Jeff Garzik commit 7102d230d6e8cf48ab366fa110c0a7f5ea160d07 Author: Adrian Bunk Date: Thu Jan 4 00:09:36 2007 +0100 drivers/ata/: make 4 functions static This patch makes the following needlessly global functions static: - libata-core.c: ata_qc_complete_internal() - libata-scsi.c: ata_scsi_qc_new() - libata-scsi.c: ata_dump_status() - libata-scsi.c: ata_to_sense_error() Signed-off-by: Adrian Bunk Signed-off-by: Jeff Garzik commit 904dbd1307100edc12e2f98dd12b2338f1914f5b Author: Alan Date: Mon Jan 8 12:07:25 2007 +0000 ahci: Remove jmicron fixup The AHCI set up is handled properly along with the other bits in the JMICRON quirk. Remove the code whacking it in ahci.c as its un-needed and also blindly fiddles with bits it doesn't own. Signed-off-by: Alan Cox Signed-off-by: Jeff Garzik commit 4112e16a7c606a80810d22d55bfc742eaa61fecb Author: Alan Date: Mon Jan 8 12:10:05 2007 +0000 libata-sff: Don't try and activate channels which are not in use An ATA controller in native mode may have one or more channels disabled and not assigned resources. In that case the existing code crashes trying to access I/O ports 0-7. Add the neccessary check. Signed-off-by: Alan Cox Signed-off-by: Jeff Garzik commit d73f30e1c9a9af14757fa5bf4014343926047156 Author: Alan Date: Mon Jan 8 17:11:13 2007 +0000 sata_via: PATA support Signed-off-by: Alan Cox Signed-off-by: Jeff Garzik commit 7dcbc1f2c89b14745ff13eae3e57b72f05161786 Author: Jakub W. Jozwicki J Date: Tue Jan 9 09:01:19 2007 +0900 pata_sis: implement laptop list and add ASUS A6K/A6U In ASUS A6K/A6U hdd is connected to SiS 96x via 40c cable, however it is short cable and is UDMA66 capable. tj: fixed if () conditionals ah: fixed infinite loop Signed-off-by: Jakub W. Jozwicki Cc: Andreas Henriksson Signed-off-by: Tejun Heo Signed-off-by: Jeff Garzik commit babfb682c93ca78b74d7f3bb07ee0e13831c6f46 Author: J J Date: Tue Jan 9 02:26:30 2007 +0900 ata_piix: add ICH7 on Acer 3682WLMi to laptop list In Acer Aspire hdd is connected to ICH7 via 40c cable, however it is short cable and it is UDMA66 capable. Signed-off-by: J J Signed-off-by: Tejun Heo Signed-off-by: Jeff Garzik commit c9f89475a5b184e9a6077b995ce340e6804c1b1a Author: Conke Hu Date: Tue Jan 9 05:32:51 2007 -0500 Add pci class code for SATA & AHCI, and replace some magic numbers. Signed-off-by: Conke Hu Signed-off-by: Jeff Garzik commit 95006188cb1399f1358330503906e5891c129a10 Author: Mikael Pettersson Date: Tue Jan 9 10:51:46 2007 +0100 sata_promise: ATAPI support This patch adds ATAPI support to the sata_promise driver. This has been tested on both first- and second-generation chips (20378 and 20575), and with both SATAPI and PATAPI devices. CD-writing works. SATAPI DMA works on second-generation chips, but on first-generation chips SATAPI is limited to PIO due to what appears to be HW limitations. PATAPI DMA works on both first- and second-generation chips, but requires the separate PATA support patch before it can be used on TX2plus chips. The functional changes to the driver are: - remove ATA_FLAG_NO_ATAPI from PDC_COMMON_FLAGS - add ->check_atapi_dma() operation to enable DMA for bulk data transfers but force PIO for other ATAPI commands; this filter is from Promise's driver and largely matches pata_pdc207x.c - use a more restrictive ->check_atapi_dma() on first-generation chips to force SATAPI to always use PIO - add handling of ATAPI protocols to pdc_qc_prep(), pdc_host_intr(), and pdc_qc_issue_prot(): ATAPI_DMA is handled by the driver while non-DMA protocols are handed over to libata generic code - add pdc_issue_atapi_pkt_cmd() to handle the initial steps in issuing ATAPI DMA commands before sending the actual CDB; this procedure was ported from Promise's driver Signed-off-by: Mikael Pettersson Signed-off-by: Jeff Garzik commit 870ae337d568e8633ec30ca6f6afb7b58a558ba3 Author: Mikael Pettersson Date: Tue Jan 9 10:50:27 2007 +0100 sata_promise: TX2plus PATA support This patch implements a simple way of setting up per-port flags on the SATA+PATA Promise TX2plus chips, which is a prerequisite for supporting the PATA port on those chips. It is based on the observation that ap->flags isn't really used until after ->port_start() has been invoked. So it places the "exceptional" per-port flags array in the driver's private host structure, and uses it in ->port_start() to finalise the port's flags. This patch obsoletes the #promise-sata-pata branch included in the #all branch. Signed-off-by: Mikael Pettersson Signed-off-by: Jeff Garzik commit 7a44e910f43cbb5186e7242f4c32b3a5d2fb6666 Author: Arjan van de Ven Date: Tue Dec 19 13:05:53 2006 -0800 [PATCH] user of the jiffies rounding patch: ATA subsystem This patch introduces users of the round_jiffies() function: ATA subsystem This delayed work is of the "about once a second" variety and can be rounded to coincide with other wakers. Signed-off-by: Arjan van de Ven Cc: Jeff Garzik Signed-off-by: Andrew Morton Signed-off-by: Jeff Garzik commit d4013f07bd5380178bf28ef1cd76649779367288 Author: Alan Cox Date: Fri Dec 15 13:08:50 2006 -0800 [PATCH] pci: Move PCI_VDEVICE from libata to core Updated diff which doesn't move the comment as per Jeff's request and corrects the docs as per report on l/k Signed-off-by: Alan Cox Signed-off-by: Andrew Morton Signed-off-by: Jeff Garzik commit f20b16ff7c19d1c369ee07470952aca093551ed0 Author: Jeff Garzik Date: Mon Dec 11 11:14:06 2006 -0500 [libata] trim trailing whitespace Most of these contributed by that mysterious figger known as A.C. Signed-off-by: Jeff Garzik commit 155d2916d9474f81178f501664499f40833c59b2 Author: Sylvain Munaut Date: Fri Dec 8 00:14:16 2006 +0100 [PATCH] libata: Add support for the MPC52xx ATA controller This patch adds initial libata support for the Freescale MPC5200 integrated IDE controller. Signed-off-by: Sylvain Munaut Signed-off-by: Jeff Garzik commit 9b13b682a68d5bcf09c75da73d4e61d92eba4c84 Author: Alan Date: Thu Dec 7 08:59:14 2006 -0800 [PATCH] pata_it8213: Add new driver for the IT8213 card Add a driver for the IT8213 which is a single channel ICH-ish PATA controller. As it is very different to the IT8211/2 it gets its own driver. There is a legacy drivers/ide driver also available and I'll post that once I get time to test it all out (probably early January). If anyone else needs the drivers/ide driver and wants to do the merge for drivers/ide (Bart ??) then I'll forward it. [akpm@osdl.org: add PCI ID, constify needed_pio[]] Signed-off-by: Alan Cox Cc: Jeff Garzik Signed-off-by: Andrew Morton Signed-off-by: Jeff Garzik commit 3f3e7313e4e45f84c4d6e7b3bf91b5c9ad3e05cf Author: Uwe Koziolek Date: Mon Dec 4 01:34:42 2006 +0100 [PATCH] sata_sis: support SiS966/966L The SiS966/966L has different PCI-IDs for native mode and AHCI mode. The SiS966 supports four SATA ports only in native mode. Added additional PCI-ID 0x0183 for SiS965/965L. this patch is based on the code from David Wang from SiS Corporation published on SiS Website. Signed-off-by: Uwe Koziolek Signed-off-by: Jeff Garzik commit eaefd5fb7d793c9c1bcef1b0c0d5ec3824a85b91 Author: Greg Ungerer Date: Wed Feb 7 12:03:19 2007 +1000 [PATCH] m68knommu: use irq_handler_t for passing handler types Use irq_handler_t for passing clock handler routine around. Signed-off-by: Greg Ungerer Signed-off-by: Linus Torvalds commit 1274c1088e54aa178d8546a3830fb533062d01f4 Author: Greg Ungerer Date: Wed Feb 7 12:03:14 2007 +1000 [PATCH] m68knommu: removed include of system.h from bitops Remove include of asm/system.h, not needed. Signed-off-by: Greg Ungerer Signed-off-by: Linus Torvalds commit 72613e5f44adf2fe2684a5f1c1b62c2ee9984f40 Author: Greg Ungerer Date: Wed Feb 7 12:03:08 2007 +1000 [PATCH] uclinux: correctly remap bin_fmtflat exe allocated mem regions remap() the region we get from mmap() to mark the fact that we are using all of the available slack space. Any slack space is used to form a simple brk region, and potentially more stack space than requested at load time. Any searches of the vma chain may well fail looking for stack (and especially arg) addresses if the remaping is not done. The simplest example is /proc//cmdline, since the args are pretty much always at the top of the data/bss/stack region. Signed-off-by: Greg Ungerer Signed-off-by: Linus Torvalds commit c051b01129560ea02ea2cebdf00db0721cc9a618 Author: Greg Ungerer Date: Wed Feb 7 12:03:01 2007 +1000 [PATCH] m68knommu: use irq_handler_t passing handler to clock init Use irq_handler_t for passing interrupt handler around. Fix optional profiler handler to return a irq_return_t type. Signed-off-by: Greg Ungerer Signed-off-by: Linus Torvalds commit 459c6a9b8ee931e48f6af6637c10ec45521f0536 Author: Greg Ungerer Date: Wed Feb 7 12:02:52 2007 +1000 [PATCH] m68knommu: use irq_handler_t passing handler to PIT init Use irq_handler_t type for passing timer handler to timer init code. Signed-off-by: Greg Ungerer Signed-off-by: Linus Torvalds commit 56591b9961f7fb78c88354e59af7f0800f39dded Author: Greg Ungerer Date: Wed Feb 7 11:45:43 2007 +1000 [PATCH] m68knommu: include unused sections in linker script Include the unused sections in the m68knommu linker scripts. Needed for modules support. Signed-off-by: Greg Ungerer Signed-off-by: Linus Torvalds commit 1f95e49aae68794c4dc0d92fea8b4967dd49ae53 Author: Greg Ungerer Date: Wed Feb 7 11:35:29 2007 +1000 [PATCH] m68knommu: remove regs arg from coldfire timer interrupt Fix coldfire kernel timer to remove regs arg. Signed-off-by: Greg Ungerer Signed-off-by: Linus Torvalds commit beda9f3a13bbb22cde92a45f230a02ef2afef6a9 Author: Roman Zippel Date: Thu Feb 8 22:48:51 2007 +0100 [PATCH] kbuild: more Makefile cleanups This adds the remaining changes which should have been part of the review process. - the define command is inappropriate (it's primarily for rule definitions) - execute commands in the current dir as all other commands - .*.tmp (but not .*.null) files are also removed up by "make clean" - printf has other side effects, just use "echo -e" - proper quoting - proper indentation Signed-off-by: Roman Zippel Signed-off-by: Linus Torvalds commit 8500adc79b15fa85b403dbf04aba3497c1f80e50 Author: Guennadi Liakhovetski Date: Sun Jan 28 23:31:08 2007 +0100 [POWERPC] Update to linkstation / kurobox support Linkstation systems capable of running mainline kernels use u-boot as a bootloader, so, specifying a suitable kernel command is not a problem. Don't guess. Also extend linkstation_defconfig to support the linkstation HS model with a IT8212 IDE controller and kuroboxHD/HD-HLAN linkstation models with a tulip ethernet chip. The latter also require a slightly different .dts file, which is also included with this patch. Signed-off-by: Guennadi Liakhovetski Signed-off-by: Kumar Gala commit 49baa91d6863df480fa05eb57524a274f77fa886 Author: Kumar Gala Date: Thu Feb 8 01:11:00 2007 -0600 [POWERPC] 83xx: Updated and renamed MPC834x SYS to MPC834x MDS The MPC834x SYS board has always been called the MPC834x MDS since its public release. Removed all references to SYS and replaced with MDS. Additionally renamed the .dts to match the defconfig (mpc834x_mds*). Signed-off-by: Kumar Gala commit 2affc857efdf7dacace234b63d289d67260c95a6 Author: Paul Mundt Date: Thu Feb 8 14:20:44 2007 -0800 [PATCH] SH vdso: use install_special_mapping() Signed-off-by: Paul Mundt Cc: Roland McGrath Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit c13e4ca247311c294b032089e0d05e96f2708c16 Author: Roland McGrath Date: Thu Feb 8 14:20:43 2007 -0800 [PATCH] powerpc vDSO: use install_special_mapping This patch uses install_special_mapping for the powerpc vDSO setup, consolidating duplicated code. Signed-off-by: Roland McGrath Cc: Ingo Molnar Cc: Paul Mackerras Cc: Benjamin Herrenschmidt Cc: Andi Kleen Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit dc5882b20a69fb16219cc61ae3d21d73dd6360a7 Author: Roland McGrath Date: Thu Feb 8 14:20:43 2007 -0800 [PATCH] x86_64 ia32 vDSO: use install_special_mapping This patch uses install_special_mapping for the ia32 vDSO setup, consolidating duplicated code. Signed-off-by: Roland McGrath Cc: Ingo Molnar Cc: Paul Mackerras Cc: Benjamin Herrenschmidt Cc: Andi Kleen Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit 7d91d531900bfa1165d445390b3b13a8013f98f7 Author: Roland McGrath Date: Thu Feb 8 14:20:42 2007 -0800 [PATCH] i386 vDSO: use install_special_mapping This patch uses install_special_mapping for the i386 vDSO setup, consolidating duplicated code. Signed-off-by: Roland McGrath Cc: Ingo Molnar Cc: Paul Mackerras Cc: Benjamin Herrenschmidt Cc: Andi Kleen Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit fa5dc22f8586cc3742413dd05f5cd9e039dfab9e Author: Roland McGrath Date: Thu Feb 8 14:20:41 2007 -0800 [PATCH] Add install_special_mapping This patch adds a utility function install_special_mapping, for creating a special vma using a fixed set of preallocated pages as backing, such as for a vDSO. This consolidates some nearly identical code used for vDSO mapping reimplemented for different architectures. Signed-off-by: Roland McGrath Cc: Ingo Molnar Cc: Paul Mackerras Cc: Benjamin Herrenschmidt Cc: Andi Kleen Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit a25700a53f715fde30443e737e52310c6d4a311a Author: Andrew Morton Date: Thu Feb 8 14:20:40 2007 -0800 [PATCH] mm: show bounce pages in oom killer output Also split that long line up - people like to send us wordwrapped oom-kill traces. Cc: Nick Piggin Cc: Christoph Lameter Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit 45941d0481f538324fa21d6450116d13f6e51e91 Author: Soeren Sonnenburg Date: Thu Feb 8 14:20:38 2007 -0800 [PATCH] enable mouse button 2+3 emulation for x86 macs As macbook/macbook pro's also have to live with a single mouse button the following patch just enables the Macintosh device drivers menu in Kconfig + adds the macintosh dir to the obj-* to make macbook* users happy (who use exactly that since months.... Signed-off-by: Soeren Sonnenburg Cc: Benjamin Herrenschmidt Cc: Paul Mackerras Cc: Dmitry Torokhov Cc: Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit 835d90c4218dffe6f9e7ac1ed79795197a4970c4 Author: Adrian Bunk Date: Thu Feb 8 14:20:38 2007 -0800 [PATCH] v9fs_vfs_mkdir(): fix a double free Fix a double free of "dfid" introduced by commit da977b2c7eb4d6312f063a7b486f2aad99809710 and spotted by the Coverity checker. Signed-off-by: Adrian Bunk Cc: Eric Van Hensbergen Cc: Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit da6e1a32fb8d7539a27f699c8671f64d7fefd0cc Author: Neil Brown Date: Thu Feb 8 14:20:37 2007 -0800 [PATCH] md: avoid possible BUG_ON in md bitmap handling md/bitmap tracks how many active write requests are pending on blocks associated with each bit in the bitmap, so that it knows when it can clear the bit (when count hits zero). The counter has 14 bits of space, so if there are ever more than 16383, we cannot cope. Currently the code just calles BUG_ON as "all" drivers have request queue limits much smaller than this. However is seems that some don't. Apparently some multipath configurations can allow more than 16383 concurrent write requests. So, in this unlikely situation, instead of calling BUG_ON we now wait for the count to drop down a bit. This requires a new wait_queue_head, some waiting code, and a wakeup call. Tested by limiting the counter to 20 instead of 16383 (writes go a lot slower in that case...). Signed-off-by: Neil Brown Cc: Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit aaf68cfbf2241d24d46583423f6bff5c47e088b3 Author: NeilBrown Date: Thu Feb 8 14:20:30 2007 -0800 [PATCH] knfsd: fix a race in closing NFSd connections If you lose this race, it can iput a socket inode twice and you get a BUG in fs/inode.c When I added the option for user-space to close a socket, I added some cruft to svc_delete_socket so that I could call that function when closing a socket per user-space request. This was the wrong thing to do. I should have just set SK_CLOSE and let normal mechanisms do the work. Not only wrong, but buggy. The locking is all wrong and it openned up a race where-by a socket could be closed twice. So this patch: Introduces svc_close_socket which sets SK_CLOSE then either leave the close up to a thread, or calls svc_delete_socket if it can get SK_BUSY. Adds a bias to sk_busy which is removed when SK_DEAD is set, This avoid races around shutting down the socket. Changes several 'spin_lock' to 'spin_lock_bh' where the _bh was missing. Bugzilla-url: http://bugzilla.kernel.org/show_bug.cgi?id=7916 Signed-off-by: Neil Brown Cc: Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit 387bb17374c5fa057462d00d4ba941d49f45de4d Author: Neil Brown Date: Thu Feb 8 14:20:29 2007 -0800 [PATCH] md: fix various bugs with aligned reads in RAID5 It is possible for raid5 to be sent a bio that is too big for an underlying device. So if it is a READ that we pass stright down to a device, it will fail and confuse RAID5. So in 'chunk_aligned_read' we check that the bio fits within the parameters for the target device and if it doesn't fit, fall back on reading through the stripe cache and making lots of one-page requests. Note that this is the earliest time we can check against the device because earlier we don't have a lock on the device, so it could change underneath us. Also, the code for handling a retry through the cache when a read fails has not been tested and was badly broken. This patch fixes that code. Signed-off-by: Neil Brown Cc: "Kai" Cc: Cc: Cc: Jens Axboe Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit 6649a3863232eb2e2f15ea6c622bd8ceacf96d76 Author: Ken Chen Date: Thu Feb 8 14:20:27 2007 -0800 [PATCH] hugetlb: preserve hugetlb pte dirty state __unmap_hugepage_range() is buggy that it does not preserve dirty state of huge_pte when unmapping hugepage range. It causes data corruption in the event of dop_caches being used by sys admin. For example, an application creates a hugetlb file, modify pages, then unmap it. While leaving the hugetlb file alive, comes along sys admin doing a "echo 3 > /proc/sys/vm/drop_caches". drop_pagecache_sb() will happily free all pages that aren't marked dirty if there are no active mapping. Later when application remaps the hugetlb file back and all data are gone, triggering catastrophic flip over on application. Not only that, the internal resv_huge_pages count will also get all messed up. Fix it up by marking page dirty appropriately. Signed-off-by: Ken Chen Cc: "Nish Aravamudan" Cc: Adam Litke Cc: David Gibson Cc: William Lee Irwin III Cc: Cc: Hugh Dickins Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit f336953bfdee8d5e7f69cb8e080704546541f04b Author: Evgeniy Dushistov Date: Thu Feb 8 14:20:25 2007 -0800 [PATCH] ufs: restore back support of openstep This is a fix of regression, which triggered by ~2.6.16. Patch with name ufs-directory-and-page-cache-from-blocks-to-pages.patch: in additional to conversation from block to page cache mechanism added new checks of directory integrity, one of them that directory entry do not across directory chunks. But some kinds of UFS: OpenStep UFS and Apple UFS (looks like these are the same filesystems) have different directory chunk size, then common UFSes(BSD and Solaris UFS). So this patch adds ability to works with variable size of directory chunks, and set it for ufstype=openstep to right size. Tested on darwin ufs. Signed-off-by: Evgeniy Dushistov Cc: Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit cbb9450234fb28f60fea36520cd710a988ac5812 Author: Atsushi Nemoto Date: Thu Feb 8 14:20:24 2007 -0800 [PATCH] rtc-pcf8563: detect polarity of century bit automatically The usage of the century bit was inverted on 2.6.19 following to PCF8563's description, but it was not match to usage suggested by RTC8564's datasheet. Anyway what MO_C=1 means can vary on each platform. This patch is to detect its polarity in get_datetime routine. The default value of c_polarity is 0 (MO_C=1 means 19xx) so that this patch does not change current behavior even if get_datetime was not called before set_datetime. Signed-off-by: Atsushi Nemoto Cc: Jean-Baptiste Maneyrol Cc: Cc: David Brownell Cc: Alessandro Zummo Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds commit dcb92f8804717b845db70939b523c5d152a2e0ea Author: Al Viro Date: Fri Feb 9 16:39:00 2007 +0000 [PATCH] uintptr_t is unsigned long, not u32 Signed-off-by: Al Viro Signed-off-by: Linus Torvalds commit bd4f3ae1a1524114f7a8051214bacea2fe7813b8 Author: Al Viro Date: Fri Feb 9 16:40:15 2007 +0000 [PATCH] trivial s2io annotations Signed-off-by: Al Viro Signed-off-by: Linus Torvalds commit b53449725a9a436fb9cc2f2ef8579368a704db03 Author: Al Viro Date: Fri Feb 9 16:40:10 2007 +0000 [PATCH] trivial cxgb3 annotations Signed-off-by: Al Viro Signed-off-by: Linus Torvalds commit 184123dbd6629ef32e9fe4749163701e86f2b02c Author: Al Viro Date: Fri Feb 9 16:40:05 2007 +0000 [PATCH] pc300too annotation fixes Signed-off-by: Al Viro Signed-off-by: Linus Torvalds commit 68f50e52554a0a55dfe2e3fdf659ee0569d73c3f Author: Al Viro Date: Fri Feb 9 16:40:00 2007 +0000 [PATCH] hci_{read,write}l() does force casts to wrong type for no reason readl() et.al. expect iomem pointer, so WTF force-cast it to normal one??? Signed-off-by: Al Viro Signed-off-by: Linus Torvalds commit 53ebb3b8264a77b6214f7a405300de8c24a12554 Author: Al Viro Date: Fri Feb 9 16:39:55 2007 +0000 [PATCH] trivial usb endianness annotations Signed-off-by: Al Viro Signed-off-by: Linus Torvalds commit f1fda89522c5aaa1bd4ef69605e85e6ee9c85faf Author: Al Viro Date: Fri Feb 9 16:39:50 2007 +0000 [PATCH] powerpc: celleb trivial endianness and iomem annotations Signed-off-by: Al Viro Signed-off-by: Linus Torvalds commit 95389b86fd07660970a3e6498405d53037c035e9 Author: Al Viro Date: Fri Feb 9 16:39:45 2007 +0000 [PATCH] osst endianness annotations Signed-off-by: Al Viro Signed-off-by: Linus Torvalds commit b4377356450e2358f5f92d34f130d6cb6574bf76 Author: Al Viro Date: Fri Feb 9 16:39:40 2007 +0000 [PATCH] iscsi endianness annotations Signed-off-by: Al Viro Signed-off-by: Linus Torvalds commit 04d4f7a1143e4fb291cd1584c9ac8de4ba584d34 Author: Al Viro Date: Fri Feb 9 16:39:30 2007 +0000 [PATCH] ahci: trivial endianness annotations Signed-off-by: Al Viro Signed-off-by: Linus Torvalds commit 92ccc5f7558f24edf7129a24a8e2ce338009b0dd Author: Al Viro Date: Fri Feb 9 16:39:35 2007 +0000 [PATCH] sata_svw: trivial iomem annotations Signed-off-by: Al Viro Signed-off-by: Linus Torvalds commit cb468984f624959995f1034197f3bae86108973b Author: Al Viro Date: Fri Feb 9 16:39:25 2007 +0000 [PATCH] io_apic: trivial __iomem annotations Signed-off-by: Al Viro Signed-off-by: Linus Torvalds commit 11718b4d6ba03cf83e4cd856e5eda3a8d0d17652 Author: Al Viro Date: Fri Feb 9 16:39:20 2007 +0000 [PATCH] misc NULL noise removal Signed-off-by: Al Viro Signed-off-by: Linus Torvalds commit 8b6d44c7bde7f927b7b70e9f56c22c66c0066277 Author: Al Viro Date: Fri Feb 9 16:38:40 2007 +0000 [PATCH] kvm: NULL noise removal Signed-off-by: Al Viro Signed-off-by: Linus Torvalds commit 5b71bddb78df5e292ae90f7603a996e51b3ecb88 Author: Al Viro Date: Fri Feb 9 16:39:15 2007 +0000 [PATCH] hpet: trivial __iomem annotations Signed-off-by: Al Viro Signed-off-by: Linus Torvalds commit c3cf83b70c25c2b1d5569d6cc24e879464d1803b Author: Al Viro Date: Fri Feb 9 16:39:10 2007 +0000 [PATCH] misc duplicate field initializers Signed-off-by: Al Viro Signed-off-by: Linus Torvalds commit 2f3669879955e2da10558f39aafe0fe13d639458 Author: Al Viro Date: Fri Feb 9 16:38:35 2007 +0000 [PATCH] kvm: __user annotations Signed-off-by: Al Viro Signed-off-by: Linus Torvalds commit 193d0732920fd09825501136f3a01e9c28a700e6 Author: Al Viro Date: Fri Feb 9 16:39:05 2007 +0000 [PATCH] offsetof is size_t Signed-off-by: Al Viro Signed-off-by: Linus Torvalds commit 4ec031166f6a466a443f462e567f7551096b1741 Author: Al Viro Date: Fri Feb 9 16:38:30 2007 +0000 [PATCH] kill eth_io_copy_and_sum() On all targets that sucker boils down to memcpy_fromio(sbk->data, from, len). The function name is highly misguiding (it _never_ does any checksums), the last argument is just a noise and simply expanding the call to memcpy_fromio() gives shorter and more readable source. For a lot of reasons it has almost no remaining users, so it's better to just outright kill it. Signed-off-by: Al Viro Signed-off-by: Linus Torvalds commit b81831c69afb82c0545d3de729290fab4e50d429 Author: Al Viro Date: Fri Feb 9 16:38:25 2007 +0000 [PATCH] drivers/serial NULL noise removal Signed-off-by: Al Viro Signed-off-by: Linus Torvalds commit f2e97df669d32f74152336f46e4e0e328b993c57 Author: Al Viro Date: Fri Feb 9 16:38:55 2007 +0000 [PATCH] in non-NUMA case mark GFP_THISNODE gfp_t ... operations with it are OK as is, but flags & ~0 will have no idea that this ~0 is meant to be ~gfp_t. Signed-off-by: Al Viro Signed-off-by: Linus Torvalds commit 8a5ab4157b3933d4fa29a1612879ab08f681041a Author: Al Viro Date: Fri Feb 9 16:38:20 2007 +0000 [PATCH] usbvision missing __user Signed-off-by: Al Viro Signed-off-by: Linus Torvalds commit d7bde2fe043c2f7ddcf1d8bec139684ef774c8bc Author: Al Viro Date: Fri Feb 9 16:38:50 2007 +0000 [PATCH] hwmon: ansify Signed-off-by: Al Viro Signed-off-by: Linus Torvalds commit 58addbffdde731da25a2f9eaa1353fc434f3f3c4 Author: Al Viro Date: Fri Feb 9 16:38:45 2007 +0000 [PATCH] dlm: use kern_recvmsg() Signed-off-by: Al Viro Signed-off-by: Linus Torvalds commit 9340b0d356ee52783121af398fa6a332e19e37e2 Author: Al Viro Date: Fri Feb 9 16:38:15 2007 +0000 [PATCH] arch/powerpc trivial annotations Signed-off-by: Al Viro Signed-off-by: Linus Torvalds commit ccbebdaccf53ef21663d3bde0ab7b3806d0aeb94 Author: Al Viro Date: Fri Feb 9 16:38:10 2007 +0000 [PATCH] arch/ia64: ansify Signed-off-by: Al Viro Signed-off-by: Linus Torvalds commit 55e747445beec8df1133bb8681c884500546775c Author: Al Viro Date: Fri Feb 9 16:38:00 2007 +0000 [PATCH] hidp __user annotations Signed-off-by: Al Viro Signed-off-by: Linus Torvalds commit d76fdf754a4b61741d78c545489145919affea4d Author: Al Viro Date: Fri Feb 9 16:38:05 2007 +0000 [PATCH] trivial __user annotations - rtc-dev Signed-off-by: Al Viro Signed-off-by: Linus Torvalds commit 0a9b0db19262dbb09f3a34195e68cafd5dc3fa10 Author: Paul Mundt Date: Wed Jan 24 21:56:20 2007 +0900 [APM] SH: Convert to use shared APM emulation. Signed-off-by: Paul Mundt Signed-off-by: Ralf Baechle commit 2116245ee121af820225834e9695005ab07d1e84 Author: Ralf Baechle Date: Fri Feb 9 17:08:58 2007 +0000 [APM] MIPS: Convert to use shared APM emulation. Also convert to use generic kernel/power/Kconfig to make the use of the shared APM emulation possible. Signed-off-by: Ralf Baechle commit 75e7153abd220f1c4a731a9613fb705485b56aa8 Author: Ralf Baechle Date: Fri Feb 9 17:08:58 2007 +0000 [APM] ARM: Convert to use shared APM emulation. Signed-off-by: Ralf Baechle commit 7726942fb15edd46e4fe8ab37f9a99795191e585 Author: Ralf Baechle Date: Fri Feb 9 17:08:57 2007 +0000 [APM] Add shared version of APM emulation Currently ARM and MIPS both have nearly identical copies of the APM emulation code in their arch code. Add yet another copy of it to drivers char and make it selectable through SYS_SUPPORTS_APM_EMULATION. Signed-off-by: Ralf Baechle commit 427a57a782c3bbd21de0a145662dc8f2f3ac2ea5 Author: Al Viro Date: Fri Feb 9 16:05:22 2007 +0000 [PATCH] missing include in macsonic Acked-by: Jeff Garzik Signed-off-by: Al Viro Signed-off-by: Linus Torvalds commit 97210b5f1c2ca98c62663a38f1d32839031f1c27 Author: Al Viro Date: Fri Feb 9 16:05:12 2007 +0000 [PATCH] spider_net breakage from class_device -> device Acked-by: Jeff Garzik Signed-off-by: Al Viro Signed-off-by: Linus Torvalds commit 9288f5c3f190ef5ee8e50b27e8ae1152f19061e4 Author: Al Viro Date: Fri Feb 9 16:05:27 2007 +0000 [PATCH] ps3: missing exports Signed-off-by: Al Viro Signed-off-by: Linus Torvalds commit 9f3bed5fdb5dbe963fc2c54e7709da96823c404d Author: Al Viro Date: Fri Feb 9 16:05:42 2007 +0000 [PATCH] TIFM should depend on PCI - TIFM_CORE leads to use of pci primitives Signed-off-by: Al Viro Signed-off-by: Linus Torvalds commit ccbe48f76194b8524d6a8b239a70015245fecbc6 Author: Al Viro Date: Fri Feb 9 16:05:37 2007 +0000 [PATCH] m32r: class_device -> device fallout Signed-off-by: Al Viro Signed-off-by: Linus Torvalds commit 72401339b545a8a0a66411c5a2486f602447d924 Author: Al Viro Date: Fri Feb 9 16:05:32 2007 +0000 [PATCH] ps3 usb missed the addition of new argument to ps3_alloc_io_irq() Acked-by: Geoff Levand Signed-off-by: Al Viro Signed-off-by: Linus Torvalds commit ec1c620b1cb43182df5d1a08392f8d68d36cef06 Author: Al Viro Date: Fri Feb 9 16:05:17 2007 +0000 [PATCH] assigning enum constant to char * is vile, even if it happens to be 0 Signed-off-by: Al Viro Signed-off-by: Linus Torvalds commit 35e00fbe48c547002fbfef718fdc67471c403ee8 Author: Al Viro Date: Fri Feb 9 16:05:07 2007 +0000 [PATCH] wrong order of kzalloc arguments Signed-off-by: Al Viro Signed-off-by: Linus Torvalds commit f85da084151c9454891124c999006857a354622a Author: Maciej W. Rozycki Date: Mon Feb 5 16:28:26 2007 -0800 [EISA] EISA registration with !CONFIG_EISA This is a change for the EISA bus support to permit drivers to call un/registration functions even if EISA support has not been enabled. This is similar to what PCI (and now TC) does and reduces the need for #ifdef clutter. Signed-off-by: Maciej W. Rozycki Signed-off-by: Andrew Morton Signed-off-by: Ralf Baechle commit 9084b0058e11378abb43d01e669bac8ac7b593ff Author: Maciej W. Rozycki Date: Mon Feb 5 16:28:29 2007 -0800 [TC] pmagb-b-fb: Convert to the driver model This is a set of changes to convert the driver to the driver model. As a side-effect the driver now supports building as a module. Signed-off-by: Maciej W. Rozycki Cc: James Simmons Cc: "Antonino A. Daplas" Signed-off-by: Andrew Morton Signed-off-by: Ralf Baechle commit 4df4db5c6c6daeb10a8693d09ce872bce8cd84e6 Author: Maciej W. Rozycki Date: Mon Feb 5 16:28:29 2007 -0800 [TC] dec_esp: Driver model for the PMAZ-A This is a set of changes that converts the PMAZ-A support to the driver model. The use of the driver model required switching to the hotplug SCSI initialization model, which in turn required a change to the core NCR53C9x driver. I decided not to break all the frontend drivers and introduced an additional parameter for esp_allocate() to select between the old and the new model. I hope this is OK, but I would be fine with converting NCR53C9x to the new model unconditionally as long as I do not have to fix all the other frontends (OK, perhaps I could do some of them ;-) ). Signed-off-by: Maciej W. Rozycki Cc: James Bottomley Signed-off-by: Andrew Morton Signed-off-by: Ralf Baechle commit 335dc50cec2891026bd51e46769fc12365b6e475 Author: Maciej W. Rozycki Date: Mon Feb 5 16:28:28 2007 -0800 [TC] mips: pmag-ba-fb: Convert to the driver model This is a set of changes to convert the driver to the driver model. As a side-effect the driver now supports building as a module. Signed-off-by: Maciej W. Rozycki Cc: James Simmons Cc: "Antonino A. Daplas" Signed-off-by: Andrew Morton Signed-off-by: Ralf Baechle commit e89a2cfb7d7b5a658295fef9be84b12e813163bd Author: Maciej W. Rozycki Date: Mon Feb 5 16:28:27 2007 -0800 [TC] defxx: TURBOchannel support This is a set of changes to add TURBOchannel support to the defxx driver. As at this point the EISA support in the driver has become the only not having been converted to the driver model, I took the opportunity to convert it as well. Plus support for MMIO in addition to PIO operation as TURBOchannel requires it anyway. Signed-off-by: Maciej W. Rozycki Signed-off-by: Andrew Morton Acked-by: Jeff Garzik Signed-off-by: Ralf Baechle commit 33cf45b90eb73e1f3b784b50691d74f7ea381b21 Author: Maciej W. Rozycki Date: Mon Feb 5 16:28:26 2007 -0800 [TC] TURBOchannel support for the DECstation This is the platform-specific part of TURBOchannel bus support for the DECstation. It implements determining whether the bus is actually there, getting bus parameters, IRQ assignments for devices and protected accesses to possibly unoccupied slots that may trigger bus error exceptions. Signed-off-by: Maciej W. Rozycki Signed-off-by: Andrew Morton Signed-off-by: Ralf Baechle commit 56a47da1b940b6d3812de67fd94af9bfda6ee93a Author: Maciej W. Rozycki Date: Mon Feb 5 16:28:26 2007 -0800 [TC] MIPS: TURBOchannel resources off-by-one fix Fix resource reservation of TURBOchannel areas, where the end is one byte too far. Signed-off-by: Maciej W. Rozycki Signed-off-by: Andrew Morton Signed-off-by: Ralf Baechle commit b454cc6636d254fbf6049b73e9560aee76fb04a3 Author: Maciej W. Rozycki Date: Mon Feb 5 16:28:25 2007 -0800 [TC] MIPS: TURBOchannel update to the driver model This is a set of changes to convert support for the TURBOchannel bus to the driver model. It implements the usual set of calls similar to what other bus drivers have: tc_register_driver(), tc_unregister_driver(), etc. All the platform-specific bits have been removed and headers from asm-mips/dec/ have been merged into linux/tc.h, which should be included by drivers. Signed-off-by: Maciej W. Rozycki Signed-off-by: Andrew Morton Signed-off-by: Ralf Baechle commit 62045305c20a194127ae87ccf963cfe6ffde7c4e Author: Nick Piggin Date: Fri Feb 9 05:28:19 2007 +0100 [PATCH] mm: remove find_trylock_page Remove find_trylock_page as per the removal schedule. Signed-off-by: Nick Piggin [ Let's see if anybody screams ] Signed-off-by: Linus Torvalds commit 862a7284980d809a583e9a34c774fab84e0a46f8 Author: Rojhalat Ibrahim Date: Fri Feb 9 15:10:38 2007 +0100 [PPC] Fix compile error for e500 core based processors We get the following compiler error: CC arch/ppc/kernel/ppc_ksyms.o arch/ppc/kernel/ppc_ksyms.c:275: error: '__mtdcr' undeclared here (not in a function) arch/ppc/kernel/ppc_ksyms.c:275: warning: type defaults to 'int' in declaration of '__mtdcr' arch/ppc/kernel/ppc_ksyms.c:276: error: '__mfdcr' undeclared here (not in a function) arch/ppc/kernel/ppc_ksyms.c:276: warning: type defaults to 'int' in declaration of '__mfdcr' make[1]: *** [arch/ppc/kernel/ppc_ksyms.o] Error 1 This is due to the EXPORT_SYMBOL for __mtdcr/__mfdcr not having the proper CONFIG protection Signed-off-by: Rojhalat Ibrahim Signed-off-by: Kumar Gala commit 27630bec9478a2dd387c68b5e435ed3fdd3a513e Author: Kumar Gala Date: Fri Feb 9 09:30:45 2007 -0600 [POWERPC] 85xx: Marked functions static Marked a number of functions in 85xx board code as static. Also, some minor whitespace cleanup Signed-off-by: Kumar Gala commit 8dabba5d1a8f1893bc3db9bf66007de2020c8b62 Author: Kumar Gala Date: Fri Feb 9 09:30:05 2007 -0600 [POWERPC] Fix is_power_of_4(x) compile error When building an 85xx kernel we get: CC arch/powerpc/mm/pgtable_32.o arch/powerpc/mm/pgtable_32.c: In function 'io_block_mapping': arch/powerpc/mm/pgtable_32.c:330: error: expected identifier before '(' token arch/powerpc/mm/pgtable_32.c:330: error: expected statement before ')' token The is_power_of_2(x) fixup patch left an extra ')' on the is_power_of_4 macro. There is a similiar issue on the arch/ppc side. Signed-off-by: Kumar Gala commit c2902c8ae06762d941fab64198467f78cab6f8cd Author: Takashi Iwai Date: Fri Feb 9 16:25:48 2007 +0100 [PATCH] Fix breakage with CONFIG_SYSFS_DEPRECATED The fix for sysfs breakage with CONFIG_SYSFS_DEPRECATED was flown away by the conflicted merge of the ALSA git tree. The patch below fixes it again. Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela commit 4ffabefb456f140eb47c7294e9158a9027a64ccc Author: Haavard Skinnemoen Date: Fri Feb 9 15:23:46 2007 +0100 [AVR32] Add missing #include arch/avr32/kernel/cpu.c needs THIS_MODULE, so it must include linux/module.h. Signed-off-by: Haavard Skinnemoen commit a3b0277d1c1d754eeb9a8f994339edbd914cacda Author: Haavard Skinnemoen Date: Fri Feb 9 12:01:02 2007 +0100 [AVR32] ssize_t should be long, not int Since size_t is defined as unsigned long, ssize_t ought to be long and not int. It could have been the other way around, but gcc defines size_t as unsigned long, so this is correct. This fixes a couple of printk format warnings. Signed-off-by: Haavard Skinnemoen commit 9d4ad801372c688c6ae7e080f6fc6f802f53cbe3 Author: Haavard Skinnemoen Date: Fri Feb 9 11:43:09 2007 +0100 [AVR32] Remove last remains of libgcc Two libgcc headers were left around even though all the actual code borrowed from libgcc is gone. Delete them. Signed-off-by: Haavard Skinnemoen commit 3d60ee1b04320d0695e071828dbadf3564d4568a Author: Haavard Skinnemoen Date: Wed Jan 10 20:20:02 2007 +0100 [AVR32] SPI platform code update Move stuff in spi.c into ATSTK1002 board code and update SPI platform device definitions according to the new GPIO API. Signed-off-by: Haavard Skinnemoen commit 7f9f4678637f9ee1a999cc0870c4668f32e1a7eb Author: Haavard Skinnemoen Date: Tue Jan 30 11:16:16 2007 +0100 [AVR32] Add PIOE device and reserve SDRAM pins The PIOE device was left out before because it muxes SDRAM pins (and is therefore a bit dangerous to mess with) and because no existing drivers had any use for it. It is needed for CompactFlash, however, and now that we have a way to protect the SDRAM pins, it can be safely added. Signed-off-by: Haavard Skinnemoen commit e7f70b8cc69b1bcc56ed8d70f8e3671ec3956374 Author: Haavard Skinnemoen Date: Tue Jan 30 11:01:23 2007 +0100 [AVR32] Introduce at32_reserve_pin() at32_reserve_pin() can be used for reserving portmux pins without altering their configuration. Useful for e.g. SDRAM pins where we really don't want to change the bootloader-provided configuration. Signed-off-by: Haavard Skinnemoen commit dde251033f3e54619317269a908ce40e6f3a8d04 Author: Haavard Skinnemoen Date: Mon Jan 29 17:59:40 2007 +0100 [AVR32] Don't reset PIO state at bootup Leave the PIO lines as the bootloader left them. This allows us to use PIOE without disturbing the SDRAM muxing. Signed-off-by: Haavard Skinnemoen commit 6a4e5227a33f60f918b30cf2001fb0bb259d9396 Author: Haavard Skinnemoen Date: Mon Feb 5 16:57:13 2007 +0100 [AVR32] GPIO API implementation Arch-neutral GPIO calls for AVR32. GPIO IRQ support written by David Brownell. Signed-off-by: Haavard Skinnemoen commit 10b50b7dd2716b944299d45452d0875dbeb5f0c2 Author: Ahmed S. Darwish Date: Mon Feb 5 04:41:27 2007 +0200 [AVR32] Use ARRAY_SIZE macro when appropriate A patch to use ARRAY_SIZE macro already defined in linux/kernel.h Signed-off-by: Ahmed S. Darwish Signed-off-by: Haavard Skinnemoen commit 6eb484fe92e2f67f888dc87e97bfd938c0f7404e Author: Haavard Skinnemoen Date: Thu Feb 1 16:26:03 2007 +0100 [AVR32] Implement dma_mapping_error() dma_map_single() never fails, so dma_mapping_error() simply returns 0. Signed-off-by: Haavard Skinnemoen commit 212868d387d0033b7e0029326a900126fe5e3d52 Author: David Brownell Date: Sun Jan 28 12:56:42 2007 -0800 [AVR32] Fix incorrect invalidation of shared cachelines Fix bug in dma_map_single(..., DMA_FROM_DEVICE) caused by incorrect invalidation of shared cachelines at the beginning and/or end of the specified buffer. Those shared cachelines need to be flushed, since they may hold valid data (which must not be discarded). Signed-off-by: David Brownell Signed-off-by: Haavard Skinnemoen commit 58febc0b1374de7506277d3aa9e9cddaea62ba65 Author: David Brownell Date: Tue Jan 23 20:21:36 2007 -0800 [AVR32] ext int fixes Bugfixes for external irq handler set_irq_type(): - If set_irq_type() can't set the type, don't change anything! - It's not OK to change the flow handler as part of set_irq_type(), among other issues that violates spinlock rules. Instead, we can call the relevant handler when we demux the external interrupts. - The external irq demux has no need to grab the spinlock. And in fact grabbing it that way was wrong, since that code might be pre-empted by an irq at a different priority level, and that code might then have tried to grab that spinlock... Signed-off-by: David Brownell Signed-off-by: Haavard Skinnemoen commit a3d912c8fa709c4078ceaabf4d71001190e19325 Author: David Brownell Date: Tue Jan 23 20:14:02 2007 -0800 [AVR32] fix serial port setup on ATSTK1000 Fixes to USART setup on the stk-1000 ... don't configure USART 2, since its TXD/RXD are used for INT-A and INT-B buttons; and configure USART 0 (for IRDA, and with corrected IRQ) iff SW2 has a non-default setting. Signed-off-by: David Brownell Signed-off-by: Haavard Skinnemoen commit 914ab06279f15d3f368f4fae74db58fdcf03a2ed Author: David Brownell Date: Tue Jan 23 20:12:15 2007 -0800 [AVR32] /proc/interrupts display The /proc/interrupts file should also display the irq_chip associated with each irq ... e.g. INTC, EIM, GPIO. Signed-off-by: David Brownell Signed-off-by: Haavard Skinnemoen commit 31321bc946527f2e4c50b6b08459d1c0d81fa978 Author: Robert P. J. Day Date: Sun Jan 7 18:43:41 2007 -0500 Remove a couple final references to obsolete verify_area(). Remove a couple final references to the obsolete verify_area() call, which was long ago replaced by access_ok(). Signed-off-by: Robert P. J. Day Acked-by: Jesper Juhl Signed-off-by: Haavard Skinnemoen commit 48ec15dca87805cf771855612d647bfe1a9f617f Author: Jaroslav Kysela Date: Fri Feb 9 14:50:18 2007 +0100 [ALSA] version 1.0.14rc2 Signed-off-by: Jaroslav Kysela commit 10b98527c34dca3f461256f5fcfff9b3790066e0 Author: Liam Girdwood Date: Thu Feb 8 17:06:09 2007 +0100 [ALSA] ASoC documentation updates This patch updates the documentation for ASoC to reflect the recent changes in API between 0.12.x and 0.13.x Changes:- o Removed all reference to old API's. o Removed references and examples of automatic DAI config and matching. o Fixed 80 char line length on some files. Signed-off-by: Liam Girdwood Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela commit c6d6eeeacc2ed0b736f20692ca021324f3b203b3 Author: Takashi Iwai Date: Thu Feb 8 14:50:31 2007 +0100 [ALSA] ca0106 - Add missing sysfs device assignment Added the missing device assignment before creating sysfs tree. This caused the insufficient device permissions. Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela commit 547ac2ae3890b8e17bcfea4ba8840a10f3496da4 Author: Paul Mackerras Date: Thu Feb 8 14:25:39 2007 +0100 [ALSA] aoa i2sbus: Stop Apple i2s DMA gracefully This fixes the problem of getting extra bytes inserted at the beginning of a recording when using the Apple i2s interface and DBDMA controller. It turns out that we can't just abort the DMA; we have to let it stop at the end of a command, and then wait for the S7 bit to be set before turning off the DBDMA controller. Doing that for playback doesn't seem to be necessary, but doesn't hurt either. We use the technique used by the Darwin driver: make each transfer command branch to a stop command if the S0 status bit is set. Thus we can ask the DMA controller to stop at the end of the current command by setting S0. The interrupt routine now looks at and clears the status word of the DBDMA command ring. This is necessary so it can know when the DBDMA controller has seen that S0 is set, and so when it should look for the DBDMA controller being stopped and S7 being set. This also ended up simplifying the calculation in i2sbus_pcm_pointer. Tested on a 15 inch albook. [Addition by Johannes] I modified this patch and added the suspend/resume bits to it to get my powermac into a decent state when playing sound across suspend to disk that has a different bitrate from what the firmware programs the hardware to. I also added the SNDRV_PCM_INFO_JOINT_DUPLEX flag because it seemed the right thing to do and I was looking at the info stuff. Signed-off-by: Paul Mackerras Signed-off-by: Johannes Berg Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela commit 2cf9f0fc69358e15e78f936c220cfe8aa208111d Author: Tobin Davis Date: Wed Feb 7 16:04:25 2007 +0100 [ALSA] hda-codec - Add support for Fujitsu PI1556 Realtek ALC880 This patch adds support for the Fujitsu PI1556 laptop. Issue: Volume knob on system maxes out lower than alsamixer (0x35 vs 0x40). Everything else works, and audio quality is good at 0x35. Signed-off-by: Tobin Davis Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela commit 288e5c35f96fefb6c5e0dc8838834c94cff616f6 Author: Johannes Berg Date: Wed Feb 7 14:07:45 2007 +0100 [ALSA] aoa: remove suspend/resume printks This just removes two useless printks. Signed-off-by: Johannes Berg Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela commit 6116ea0741abf8f1ef9d93642d985f91c58ff6bf Author: Takashi Iwai Date: Wed Feb 7 14:07:08 2007 +0100 [ALSA] Fix possible deadlocks in sequencer at removal of ports Fix possible rwsem deadlocks in sequencer code at removal of sequencer ports. The list_lock of port group can be double locked. Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela commit 2594d960793f13582c0730a99c5396cded7cf9d9 Author: Rolf Stefan Wilke Date: Tue Feb 6 19:18:14 2007 +0100 [ALSA] emu10k1 - Fix STAC9758 front channel For some time now, some users of STAC9758 (emu10k1) would have no sound on their front channels. This can be fixed (at least for me) by unmuting head phone volume and setting it to 0dB before removing the 'Front Playback' control. For details, cf. https://bugtrack.alsa-project.org/alsa-bug/view.php?id=2308 Find the appropriate patch attached. Credits to: Raymond Signed-off-by: Rolf Stefan Wilke Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela commit 88cb42901f1572c95f5933f363cfebd5044c716a Author: Takashi Iwai Date: Mon Feb 5 14:56:20 2007 +0100 [ALSA] soc - Clean up with kmemdup() Clean up by replacing with kmemdup(). Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela commit 1ab774e049085da6facfaf3b24d54158c3f0f5b3 Author: Jean Delvare Date: Mon Feb 5 13:07:04 2007 +0100 [ALSA] snd-ak4114: Fix two array overflows Fix the handling of the TXCSB registers cache. There was one array overflow in reg_write() and one in snd_ak4114_reg_write(). Thanks to David Binderman for reporting the latter. The second overflow probably doesn't matter much, given that the function snd_ak4114_reg_write() appears to be never called. I wonder why it exists and why it is exported. Signed-off-by: Jean Delvare Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela commit 66e27788a33636cf0d9bf22eb9d56a7f4ffa3a84 Author: Martin Langer Date: Mon Feb 5 13:02:35 2007 +0100 [ALSA] ac97_bus power management This patch adds CONFIG_PM to the ac97_bus driver. Signed-off-by: Martin Langer Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela commit d0b0fac14edf81dc62615cd757e7c73d2059152c Author: Bjoern Fay Date: Mon Feb 5 12:27:21 2007 +0100 [ALSA] usbaudio - Add support for Edirol UA-101 Added support for the Edirol UA-101 (only in high-speed mode) by taking the quirks for the UA-1000 and change them accordingly. Changes were made in 'usbaudio.c', 'usbaudio.h', and 'usbquirks.h' MIDI and recording seem to work perfectly (with JACK), but playback gives some few glitches. I think that's the mentioned synchronizing-problem in the UA-1000 quirk ('FIXME: playback must be synchronized to capture'), so I didn't change that. ToDo: Adding Mixer-Support for the built-in control-panel/patch-bay/router. Signed-off-by: Bjoern Fay Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela commit f32610edab47f36946d23b883aeae91e15986121 Author: Jakub Schmidtke Date: Fri Feb 2 18:17:27 2007 +0100 [ALSA] hda-codec - Add ALC861VD/ALC660VD support o Added ALC861VD support to patch_realtek.c under hda-intel o Added ALC660VD as a model of 861VD o Added pci quirks for Asus G1 as well as for two devices found in Realtek's driver to point at ALC660VD model (3stack-660) o Added pci quirk for Lenovo 3000 C200 - although untested, it should work with ALC861VD 3stack model o Changed preset id = 0x10ec0660 to point at new patch_alc861vd instead of patch_861 o Organised the list of presets Signed-off-by: Jakub Schmidtke Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela commit 73f40dc1e147b41eb74bc92ff62bb65cb3260eff Author: Liam Girdwood Date: Fri Feb 2 17:23:42 2007 +0100 [ALSA] soc - ASoC 0.13 Sharp poodle machine This patch updates the Sharp poodle machine driver to the new API in ASoC 0.13. Changes:- o Manually configure DAI hardware format. o Removed config_sysclk() function. No longer needed as clocking is now configured manually. Signed-off-by: Liam Girdwood Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela commit cb4c048b9306555ccbdb97eaf7922624664b0eb1 Author: Liam Girdwood Date: Fri Feb 2 17:23:11 2007 +0100 [ALSA] soc - ASoC 0.13 Sharp tosa machine This patch updates the Sharp tosa machine driver to the new API in ASoC 0.13. Changes:- o Update machine operations to new API. Signed-off-by: Liam Girdwood Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela commit 97952f601e939278df1194bac56b9755338ee7c1 Author: Liam Girdwood Date: Fri Feb 2 17:22:46 2007 +0100 [ALSA] soc - ASoC 0.13 spitz machine This patch updates the Sharp spitz machine driver to the new API in ASoC 0.13. Changes:- o Manually configure DAI hardware format. o Removed config_sysclk() function. No longer needed as clocking is now configured manually. Signed-off-by: Liam Girdwood Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela commit d928b25a89c3154fe6d0e62a83f51c5b621aa099 Author: Liam Girdwood Date: Fri Feb 2 17:22:20 2007 +0100 [ALSA] soc - ASoC Sharp corgi machine This patch updates the Sharp corgi machine driver to the new API in ASoC 0.13. Changes:- o Manually configure DAI hardware format. o Removed config_sysclk() function. No longer needed as clocking is now configured manually. Signed-off-by: Liam Girdwood Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela commit a8f5d0a5d02cda0183c6e68d6a66d4c6641149a9 Author: Andrew Johnson Date: Fri Feb 2 17:21:50 2007 +0100 [ALSA] soc - ASoC 0.13 pxa2xx DMA This patch updates the pxa2xx I2S driver to the new API in ASoC 0.13. Changes:- o Added check in hw_params to detect buffer less pcms (i.e. BT <--> codec). o Updated structures to new API o Removed DAI's and ac97 ops from PCM header. o Integer hardware constraint added for periods. Signed-off-by: Andrew Johnson Signed-off-by: Liam Girdwood Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela commit 596ce32b74dccf53ef59cc9ba2e95a2a34ba921c Author: Liam Girdwood Date: Fri Feb 2 17:21:16 2007 +0100 [ALSA] soc - ASoC 0.13 pxa2xx AC97 driver This patch updates the pxa2xx AC97 driver to the new API in ASoC 0.13. Changes:- o Removed DAI capabilities matching code in favour of manual matching in the machine drivers. o Added DAI operations for codec and CPU interfaces. o Added pxa2xx-ac97.h header Signed-off-by: Liam Girdwood Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela commit eaff2ae702f937020bfde96eea552caae3815784 Author: Philipp Zabel Date: Fri Feb 2 17:20:40 2007 +0100 [ALSA] soc - ASoC 0.13 pxa2xx i2s driver This patch updates the pxa2xx I2S driver to the new API in ASoC 0.13. Changes:- o Removed DAI capabilities matching code in favour of manual matching in the machine drivers. o Added DAI operations for codec and CPU interfaces. o Removed config_sysclk() function and struct snd_soc_clock_info. No longer needed as clocking is now configured manually in the machine drivers. Also removed other clocking data from structures. o Added pxa2xx-i2s.h header Signed-off-by: Philipp Zabel Signed-off-by: Liam Girdwood Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela commit c8044274c7f1e269975b2bd55d057ceb7708e929 Author: Frank Mandarino Date: Fri Feb 2 17:19:58 2007 +0100 [ALSA] soc - ASoC 0.13 AT91xxxx Eti_B1 board support This patch updates the EtI B1 machine driver to the new API in ASoC 0.13. Changes:- o Manually configure DAI hardware format. o Removed config_sysclk() function. No longer needed as clocking is now configured manually. Signed-off-by: Frank Mandarino Signed-off-by: Liam Girdwood Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela commit 6297027629a9349301e08442b67deb9783a5e984 Author: Frank Mandarino Date: Fri Feb 2 17:19:24 2007 +0100 [ALSA] soc - ASoC 0.13 AT91xxxx DMA This patch updates the AT91xxxx audio DMA driver to the new API in ASoC 0.13. Changes:- o Updated to use new 0.13 data structures. o Suspend and Resume now conditionally compiled. o #include guard around at91-pcm.h header. Signed-off-by: Frank Mandarino Signed-off-by: Liam Girdwood Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela commit 171eb8f81d7b0706c1085d272e4955251ed9f05f Author: Frank Mandarino Date: Fri Feb 2 17:18:38 2007 +0100 [ALSA] soc - ASoC 0.13 AT91xxxx I2S This patch updates the AT91xxxx I2S driver to the new API in ASoC 0.13. Changes:- o Removed DAI capabilities matching code in favour of manual matching in the machine drivers. o Added DAI operations for codec and CPU interfaces. o Removed config_sysclk() function and struct snd_soc_clock_info. No longer needed as clocking is now configured manually in the machine drivers. Also removed other clocking data from structures. Signed-off-by: Frank Mandarino Signed-off-by: Liam Girdwood Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela commit d3d35adc79aa2e48e8177a9506e9bcb5eebba406 Author: Frank Mandarino Date: Fri Feb 2 17:17:39 2007 +0100 [ALSA] soc - ASoC 0.13 AT91xxxx slave patch This patch adds support for I2S slave mode for the ETI_B1 machine from Endrelia. Signed-off-by: Frank Mandarino Signed-off-by: Liam Girdwood Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela commit 5a8ec343c5ba1e78ba23bebd9ad4b23f39c50828 Author: Liam Girdwood Date: Fri Feb 2 17:16:41 2007 +0100 [ALSA] soc - ASoC 0.13 generic AC97 codec This patch updates the AC97 codec driver to the new API in ASoC 0.13. Changes:- o Removed DAI capabilities matching code in favour of manual matching in the machine drivers. Signed-off-by: Liam Girdwood Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela commit cbe83b1795feea33803dc89fce18b2b98abbcc9b Author: Liam Girdwood Date: Fri Feb 2 17:16:02 2007 +0100 [ALSA] soc - ASoC 0.13 WM9712 codec driver This patch updates the WM9712 codec driver to the new API in ASoC 0.13. Changes:- o Removed DAI capabilities matching code in favour of manual matching in the machine drivers. o Added DAI operations for codec and CPU interfaces. o Removed config_sysclk() function and struct snd_soc_clock_info. No longer needed as clocking is now configured manually in the machine drivers. Also removed other clocking data from structures. Signed-off-by: Liam Girdwood Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela commit 4422b606bc04eab01dd5cb6f8e6dd0608d65bb11 Author: Liam Girdwood Date: Fri Feb 2 17:15:33 2007 +0100 [ALSA] soc - ASoC 0.13 WM8750 codec driver This patch updates the WM8750 codec driver to the new API in ASoC 0.13. Changes:- o Removed DAI capabilities matching code in favour of manual matching in the machine drivers. o Added DAI operations for codec and CPU interfaces. o Removed config_sysclk() function and struct snd_soc_clock_info. No longer needed as clocking is now configured manually in the machine drivers. Also removed other clocking data from structures. Signed-off-by: Liam Girdwood Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela commit b36d61d45654104c04ff71055ef09c696fea5f89 Author: Frank Mandarino Date: Fri Feb 2 17:14:56 2007 +0100 [ALSA] soc - ASoC 0.13 WM8731 codec This patch updates the WM8731 codec driver to the new API in ASoC 0.13. Changes:- o Removed DAI capabilities matching code in favour of manual matching in the machine drivers. o Added DAI operations for codec and CPU interfaces. o Removed config_sysclk() function and struct snd_soc_clock_info. No longer needed as clocking is now configured manually in the machine drivers. Also removed other clocking data from structures. Signed-off-by: Frank Mandarino Signed-off-by: Liam Girdwood Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela commit 11da21a79048472a14b201120c0c50b10060220b Author: Seth Forshee Date: Fri Feb 2 17:14:19 2007 +0100 [ALSA] soc - 0.13 ASoC DAPM bug fix for unnamed streams This patch fixes a bug whereby an unnamed stream would cause a NULL pointer ref in snd_soc_dapm_stream_event(). Signed-off-by: Seth Forshee Signed-off-by: Liam Girdwood Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela commit cb666e5bd865cc991c0048d6e81581019a141820 Author: Liam Girdwood Date: Fri Feb 2 17:13:49 2007 +0100 [ALSA] soc - ASoC 0.13 core changes This patch updates the ASoC core to the new DAI matching and clocking API in version 0.13 Changes:- o Removed DAI capabilities matching code in favour of manual matching in the machine drivers. o Added DAI operations for codec and CPU interfaces. o Removed config_sysclk() function and struct snd_soc_clock_info. No longer needed as clocking is now configured manually in the machine drivers. Also removed other clocking data from structures. o Added machine driver prepare callback. Signed-off-by: Liam Girdwood Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela commit 1c433fbda4896a6455d97b66a4f2646cbdd52a8c Author: Graeme Gregory Date: Fri Feb 2 17:13:05 2007 +0100 [ALSA] soc - 0.13 ASoC headers This patch updates the API's to include the new DAI configuration and clocking architecture. Changes:- o Removed DAI automatic matching and capabilities structure (struct snd_soc_dai_mode) and macros. o Added DAI operations for codec and CPU interfaces. o Removed config_sysclk() function and struct snd_soc_clock_info. No longer needed as clocking is now configured manually in the machine drivers. Also removed other clocking data from structures. o Updated version to 0.13 o Added shift to SOC_SINGLE_EXT kcontrol macro. Signed-off-by: Graeme Gregory Signed-off-by: Liam Girdwood Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela commit 3372a153c230bd0b28d470118d5a4c5840f8f966 Author: Takashi Iwai Date: Thu Feb 1 15:46:50 2007 +0100 [ALSA] hda-intel - Add black/whitelist for position_fix option Some devices are known to require position_fix=1 or 2 to make the driver working correctly. Otherwise the sound gets weird effects, such as stutters. Now a black/whitelist is introduced to indicate the position_fix value explicitly for such misbehaving hardwares. As a first example, Dell D820 is listed there. More will come later likely... Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela commit 0981a260a1fe4a3f22cc70ef01ce38a73f548745 Author: Takashi Iwai Date: Thu Feb 1 14:53:49 2007 +0100 [ALSA] Fix possible invalid memory access in PCM core snd_internval_list() may access invalid memory in the case count = 0 is given. It shouldn't be passed, but it'd better to make the code a bit more robust. Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela commit bc7320c5c8ddeb3b50c6a24013dab9ba74bce578 Author: Liam Girdwood Date: Thu Feb 1 12:26:07 2007 +0100 [ALSA] ASoC very minor coding style fix for snd_soc_new_pcms() This very minor patch fixes the snd_soc_new_pcms() function to comply with the kernel coding style. Signed-off-by: Liam Girdwood Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela commit 8fec560d9beb3957bf45ac93b1c0c616abd77a07 Author: Takashi Iwai Date: Thu Feb 1 11:50:56 2007 +0100 [ALSA] usbaudio - Fix Oops with unconventional sample rates The patch fixes the memory corruption by the support of unconventional sample rates. Also, it avoids the too restrictive constraints if any of usb descriptions contain continuous rates. Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela commit 3b6baa5a0b0a2877c18a76fa1f508cacdbc08edf Author: Takashi Iwai Date: Wed Jan 31 14:34:38 2007 +0100 [ALSA] Remove delayed work properly at free and suspend Remove delayed work properly at free and suspend in ac97 codec and ak4114 drivers. Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela commit 965ac42ce919db225ee64678f0be02f2fdf5b5e4 Author: Liam Girdwood Date: Wed Jan 31 14:14:57 2007 +0100 [ALSA] ASoC force running of delayed PM work at suspend() and remove() This patch fixes a bug whereby the power management delayed work would never be run at driver suspend() or module remove(). Delayed work would be created (after audio had finished) with a long delay (~5 secs) and was sometimes never queued before flush_scheduled_work() was being called at suspend or module remove. This caused the delayed work to queued after the module had been removed or after resume. This patch forces any delayed work to complete by cancelling it (timer cannot fire and add it to queue later), scheduling it for now and waiting on it's completion. This is something I probably would like to add to workqueue.c in the next merge window, however it's here atm because it can oops. Signed-off-by: Liam Girdwood Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela commit beb60119bcc9cbd80bc5b4f7feec419e067d3e46 Author: Gregor Jasny Date: Wed Jan 31 12:27:39 2007 +0100 [ALSA] usbaudio - Fix Oops with broken usb descriptors This is a patch for ALSA Bug #2724. Some webcams provide bogus settings with no valid rates. With this patch those are skipped. Signed-off-by: Gregor Jasny Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela commit 4147dab62d1b4387c304888488e1f67a83ad53c8 Author: Takashi Iwai Date: Wed Jan 31 10:35:19 2007 +0100 [ALSA] hda-codec - Add model for Uniwill X40AIx Added model=uniwill-m31 for Uniwill X40AIx with ALC861 codec. Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela commit 8fa58af7db56077d6a042fd7b9dd4c9515e1c37b Author: Karsten Wiese Date: Wed Jan 31 10:05:30 2007 +0100 [ALSA] snd_hwdep_release() racefix snd_card_file_remove() can free the snd_card. Touch hw->* only before calling snd_card_file_remove(). Unrelated: Allow hwdep devices not to have own ops.release(); Signed-off-by: Karsten Wiese Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela commit 298a2c753a5ae2f0e230a57e94843d248f0033e2 Author: Frank Mandarino Date: Wed Jan 31 10:02:56 2007 +0100 [ALSA] ASoC WM8731 support for 32k @ 12MHz sysclk This patch adds support for 32k audio on the WM8731 when running from a 12MHz system clock. Signed-off-by: Frank Mandarino Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela commit e35115a58856ced315cb8f75df56e9b9a816e70a Author: Liam Girdwood Date: Wed Jan 31 10:02:23 2007 +0100 [ALSA] ASoC codec error reporting This patch improves the codec probe() error reporting by printing error messages when the card or pcms fail to register. Signed-off-by: Liam Girdwood Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela commit 877b866d86786ac69d3d939905999fe7fe1e23fd Author: Cory T. Tusar Date: Tue Jan 30 17:30:55 2007 +0100 [ALSA] hda-codec - Dell Latitude D820 + D/Port Support port replicator headphone output on Dell Latitude D820 + D/Port. Signed-off-by: Cory T. Tusar Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela commit 18b9b3d99677a758e77682d6849f58fc07e30bef Author: Liam Girdwood Date: Tue Jan 30 17:18:45 2007 +0100 [ALSA] ASoC codec probe failure bug This patch fixes a bug whereby some resources were not being freed when codec probe() failed. Signed-off-by: Liam Girdwood Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela commit 0cb29ea0d449d7c0ecc9649a08ab63476389701d Author: Takashi Iwai Date: Mon Jan 29 15:33:49 2007 +0100 [ALSA] Add even more 'const' to everything related to TLV Mark TLV data as 'const' Signed-of-by: Philipp Matthias Hahn Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela commit 517400cbc75d0604bc34c1866dff7e55ca1be2b4 Author: Takashi Iwai Date: Mon Jan 29 15:27:56 2007 +0100 [ALSA] Add some more 'const', but needs changes in i2c/other/ak4* Make data passed to ak4xxx_create 'const'. Signed-of-by: Philipp Matthias Hahn Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela commit 32b47da03541f97e40f1af5488ef88250459f388 Author: Takashi Iwai Date: Mon Jan 29 15:26:36 2007 +0100 [ALSA] Add 'const' to files in pci/ice1712/ Mark a lot of data as 'const' Signed-of-by: Philipp Matthias Hahn Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela commit 189bc171434e84797f586130fca8eb4df3746e3f Author: Takashi Iwai Date: Mon Jan 29 15:25:40 2007 +0100 [ALSA] ice1712 - Reorganize existing eeprom data Reorganize EEPROM data (in C99 style). Signed-of-by: Philipp Matthias Hahn Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela commit bcb4d788f573805c74ac4f39a622b30955b2f916 Author: Robert P. J. Day Date: Mon Jan 29 14:46:18 2007 +0100 [ALSA] Remove useless reference to obsolete KERNELD Remove the final useless reference to the obsolete KERNELD feature. Signed-off-by: Robert P. J. Day Signed-off-by: Andrew Morton Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela commit 377a4f7ea35d7d6cc05faea7030522d93435dc11 Author: Peter Eriksen Date: Mon Jan 29 14:45:53 2007 +0100 [ALSA] sound/isa/gus/gus_main.c: Use abs() instead of x < 0 ? -x : x. Signed-off-by: Peter Eriksen Signed-off-by: Andrew Morton Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela commit cd7509a43c3047a6339484e5009c2db7ee4c7a51 Author: Kailang Yang Date: Fri Jan 26 18:33:17 2007 +0100 [ALSA] hda-codec - Add HP BPC-D7000 support Add HP BPC-D7000 support. Signed-off-by: Kailang Yang Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela commit 757e119bf52b014b3181eed97b01f87a245b8ff9 Author: Matthias Koenig Date: Thu Jan 25 13:15:05 2007 +0100 [ALSA] Add snd-portman2x4 driver for Midiman Portman 2x4 MIDI device snd-portman2x4 driver supports Midiman Portman 2x4 parallel port MIDI device. Signed-off-by: Matthias Koenig Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela commit 32360416322ddfcd2db2f7655f606c5b86a29102 Author: Thomas De Schampheleire Date: Wed Jan 24 16:13:35 2007 +0100 [ALSA] hda-codec - Missing Mic Boost on Realtek ALC882/883 This patch adds Mic Boost controls for Realtek ALC882 and ALC883 chips. Signed-off-by: Thomas De Schampheleire Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela commit 579c84a9b225d8b9d0f32818b9959ca63b4fb57d Author: Adrian Bunk Date: Tue Jan 23 19:22:26 2007 +0100 [ALSA] echo3g_dsp.c shouldn't include #include Despite being under linux/, linux/irq.h shouldn't be #include'd by arch independent code. Signed-off-by: Adrian Bunk Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela commit 5bda9fa1aefbb873f2bd181e63ce0d4231883c46 Author: Nicolas Kaiser Date: Mon Jan 22 14:54:33 2007 +0100 [ALSA] Documentation/sound/alsa/DocBook: typos Some typos in Documentation/sound/alsa/DocBook. Signed-off-by: Nicolas Kaiser Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela commit f7ba7fc6173a9fb6d8a5bc02bf335cc358f21a09 Author: Takashi Iwai Date: Fri Jan 19 18:34:47 2007 +0100 [ALSA] emu10k1 - Fix ABI for older ld10k1 Fix ABI for older ld10k1. When no EMU10K1_PVERSION ioctl is issued, the driver accepts ioctls with the old struct size without TLV information. Also, changed the struct field to make the conversion easier from the old to the new structs. Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela commit 7ed07a740b886930a299d438947ad322272eece1 Author: Takashi Iwai Date: Fri Jan 19 14:51:57 2007 +0100 [ALSA] hda-intel - Don't try to probe invalid codecs Fix the max number of codecs detected by HD-intel (and compatible) controllers to 3. Some hardware reports extra bits as if connected, and the driver gets confused to probe unexisting codecs. Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela commit 5c33dd70b51be0617a75562aa896d5ccf1840455 Author: Oliver Neukum Date: Tue Jan 16 17:49:21 2007 +0100 [ALSA] cleanup and error reporting for sound/core/init.c Make the control flow clear with indentation, adds some comments and improves error reporting. Signed-off-by: Oliver Neukum Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela commit ad4d1dea62b6981a8c12df529e955424141d4b7a Author: Takashi Iwai Date: Tue Jan 16 17:46:35 2007 +0100 [ALSA] Fix irq handler arguments in documents Fixed the irq handler arguments in documents (removing pt_regs). Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela commit 9f428175a5e486b7142d3217c20481e003f3c275 Author: Daniel Jacobowitz Date: Fri Jan 12 19:11:47 2007 +0100 [ALSA] ac97 - Fix vt1617a build ops This patch connects the extra vt1616 controls for the vt1617a, which is necessary to control the rear speakers on e.g. a Shuttle SN25P. Signed-off-by: Daniel Jacobowitz Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela commit 687a47bd829e040094cbc103126d5f03d46fd2bb Author: Takashi Iwai Date: Wed Jan 10 11:25:58 2007 +0100 [ALSA] Fix a typo in the last patch_realtek.c change Fixed a typo in the last patch_realtek.c change. Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela commit 30e80a279d864385306ed4bf905f00196d1c9656 Author: Jaroslav Kysela Date: Tue Jan 9 09:55:54 2007 +0100 [ALSA] hda-codec - add ASUS W7J (0x1043, 0x1205) to quirk list - 3stack See Novell-bug#228201 . Signed-off-by: Jaroslav Kysela commit 2a296cb6633a719846eaf30fcec7f392c511537d Author: Leonard Norrgard Date: Mon Jan 8 11:28:22 2007 +0100 [ALSA] sound: hda: detect ALC883 on MSI K9A Platinum motherboards (MS-7280) Recognize the Realtek ALC883 chip on MSI K9A Platinum motherboards (model no. MS-7280), enabling full sound capabilities. Error messages seen before this patch: cannot find the slot for index 0 (range 0-0) hda-intel: Error creating card! HDA Intel: probe of 0000:00:14.2 failed with error -12 [akpm@osdl.org: updated to match recent ALSA table changes] Signed-off-by: Leonard Norrgard Signed-off-by: Andrew Morton Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela commit f36090fe04986dbcd304e1f4d9224be00e57ec25 Author: Tobin Davis Date: Mon Jan 8 11:07:12 2007 +0100 [ALSA] hda-codec - Add support for Samsung Q1 Ultra This adds support for the Samsung Q1 Ultra tablet pc. Signed-off-by: Tobin Davis Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela commit 8e21c34cd4742c508dcc307fdbac9b3ba6899002 Author: Tobin Davis Date: Mon Jan 8 11:04:17 2007 +0100 [ALSA] hda-codec - Add support for Sigmatel STAC9202/9250/9251 codecs This patch adds support for Gateway laptops based on the Sigmatel STAC9250 codecs, as well as basic support for STAC9202/9250/9251 codecs. Some Gateway systems require probe_mask=1 to work. More work to be done prior to alsa 1.0.14 final. Signed-off-by: Tobin Davis Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela commit c68487151a0dceea07db8632327e3a0ab9e25e1f Author: Mariusz Kozlowski Date: Mon Jan 8 10:59:51 2007 +0100 [ALSA] sound: aoa of_node_put and kfree cleanup This patch removes redundant argument checks for of_node_put() and kfree(). Acked-by: Johannes Berg Signed-off-by: Mariusz Kozlowski Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela commit ffc26918ab5674b286a4bc07dac7e011cea83e97 Author: Frank Mandarino Date: Mon Jan 8 10:58:47 2007 +0100 [ALSA] ASoC at91 - Fix NULL pointer dereference in at91_i2s_shutdown This patch fixes a NULL pointer exception which occurs when a substream is opened and immediately closed. Signed-off-by: Frank Mandarino Signed-off-by: Liam Girdwood Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela commit ad5e773750aeae3ad980f94b9f3cecad5af7c53d Author: Tobin Davis Date: Mon Jan 8 10:57:32 2007 +0100 [ALSA] hda-codec - Add support for Toshiba M105 to Realtek patch This patch adds support for the Toshiba M105-S3041 laptop (ALC861). Signed-off-by: Tobin Davis Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela commit 751e61c47d3b4e929c93bac61c8dd6c247854993 Author: Raúl Sánchez Siles Date: Mon Jan 8 10:56:48 2007 +0100 [ALSA] Solve typos/compilation problems for debug functions in soc-dapm and at91-i2s soc-dapm ·Removed list_for_each since the loop is list_for_each_entry() and not list_for_each(). Thanks to Liam Girdwood and Seth Forshee. at91-i2s ·Fixed typo in dai modes definition. ·Fixed struct member name in at91_ssc_info->ssc_state. ·Fixed compilation problem, ssc_state is bundled in at91_ssc_info. Signed-off-by: Raúl Sánchez Siles Signed-off-by: Seth Forshee Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela commit 0e4ceb7507111c3910a0d7e19b498b1f6081afcb Author: Tobin Davis Date: Mon Jan 8 10:54:26 2007 +0100 [ALSA] hda-codec - Change default config for Asus P5GD1 This patch changes the default configuration for the Asus P5GD1 motherboard from 5stack to asus, as reported by stelek on linuxquestions.org http://www.linuxquestions.org/questions/showthread.php?p=2556497#post2556497 Signed-off-by: Tobin Davis Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela commit f6cdab5f7ed356e8a259c1f00c7991f56c234643 Author: Clement Guedez Date: Mon Jan 8 10:48:41 2007 +0100 [ALSA] Add support of the ESI Waveterminal 192M to the ice1724 ALSA driver This patch adds the support of the ESI Waveterminal 192M soundcard to the ice1724 familly ALSA driver. It's a semi-professionnal soundcard for home studio : many I/O and a quality of sound is good, better than consumer cards, but less musical than professional cards. It use a Via Envy24ht chipset as ice1724 soundcard, Sigmatel stac9640 ADC/DAC for the analog I/O as Prodigy192, and Atmel ak4114 for S/PDIF as ESI Julia. Is working : the 8 analog outputs, the analog inputs 1&2, the mic input 1, the coaxial & optical digital outputs. Signed-off-by: Clement Guedez Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela commit 7b9470d88492d8be22d1f5307fe28642db9affe5 Author: Tobin Davis Date: Thu Dec 28 13:56:48 2006 +0100 [ALSA] hda-codec - Add Asus P5W DH to alc882_cfg_tbl This patch adds the Asus P5W DH to the ALC882 config table as a 6stack-dig system. Signed-off-by: Tobin Davis Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela commit 518f6a6173e6009f5d380c638ea97a8897ebea9c Author: Tobin Davis Date: Thu Dec 28 13:55:41 2006 +0100 [ALSA] Fix typo and add entry to documentation This patch adds the macpro and fixes a typo in the ALC882 section of ALSA-Configuration.txt. Signed-off-by: Tobin Davis Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela commit 88518275e3eefe0582af1918d59325b16dfde154 Author: John Daiker Date: Thu Dec 28 13:55:05 2006 +0100 [ALSA] usbaudio.c: remove unneeded casts Went rummaging through usbaudio.c and found some castings that aren't needed as far as I can see. Part of the KernelJanitors TODO list. Signed-off-by: John Daiker Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela commit 67e9f4b68c9d1820132c559c0f9b296dafdf631e Author: Randy Cushman Date: Fri Dec 22 12:44:25 2006 +0100 [ALSA] ac97 - fix various issues with AD1986/AD1986A support Previously, ac97_codec.c was coded to support AD1986 and AD1986A CODECs using code written for the AD1985 CODEC. This allowed the LINE_OUT and HEADPHONE jacks to function properly, however register differences between the CODECs prevented line and microphone inputs from functioning. Specifically, this patch fixes issues with the following mixer controls: 'V_REFOUT', 'Spread Front to Surround and Center/LFE', 'Exchange Front/Surround', 'Surround Jack Mode', and 'Channel Mode'. This patch removes the undocumented AD1888 control 'High Pass Filter Enable' and adds the new control 'Exchange Mic/Line In'. Signed-off-by: Randy Cushman Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela commit 6428ea1b733e4795209ff272be32732ec152594a Author: Randy Cushman Date: Thu Dec 21 19:17:29 2006 +0100 [ALSA] ac97 - fix malfunctioning mixer controls for AD1985 This patch replaces the 'V_REFOUT Enable' mixer switch control with a listbox control for the AD1985 CODEC. Previous patch 'AD1888 mixer controls for DC mode' added controls that were propogated to multiple codecs. For the AD1985 codec, the bits VREFH and VREFD function differently, preventing the 'V_REFOUT Enable' control from setting V_REFOUT to Hi-Z. This patch also corrects an issue in which register bits relating to mixer controls 'Surround Jack Mode' and 'Channel Mode'. The register bits controlled by these controls were being set at boot time to states inconsistent with the stored values of these controls. Signed-off-by: Randy Cushman Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela commit 1321b160fa1cf63fa841d954fe31220366b6647a Author: Takashi Iwai Date: Thu Dec 21 11:02:06 2006 +0100 [ALSA] soc - Fix delayed_work related changes on 2.6.20 kernel Fix the changes realted to delayed_work in soc/codecs/wm8750.c. Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela commit 831466f4ad2b5fe23dff77edbe6a7c244435e973 Author: Randy Cushman Date: Tue Dec 19 18:42:16 2006 +0100 [ALSA] ac97 - fix microphone and line_in selection logic This patch fixes the Microphone and LINE_IN select logic for Analog Devices surround codecs with shared jacks. The existing code can never utilize the shared jacks for Microphone and LINE_IN due to the reversed jack selection logic. The patched code correctly selects the shared jack for input if the 'Channel Mode' selector does not specify that the jack is to be used for output. Specifically, in '2ch' mode the Center/LFE jack is used for microphone input and the Surround jack is used for LINE_IN, in '4ch' mode the Center/LFE jack is used for microphone input and the Surround jack is used for output, and in '6ch' mode both jacks are used for output. Signed-off-by: Randy Cushman Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela commit 4bb09523de50dcf1afc5d3099b9da0381f01b04c Author: Takashi Iwai Date: Tue Dec 19 17:16:14 2006 +0100 [ALSA] soc - Use global workqueue Use global workqueue for simplicity instead of own workqueue in SoC core and wm8750 codes. Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela commit 4014c38bd94156c10986a11d890bdae99437dc9a Author: Takashi Iwai Date: Tue Dec 19 17:13:16 2006 +0100 [ALSA] ak4114 - Use global workqueue Use global workqueue for simplicity instead of own workqueue. Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela commit e250af291d6759518b574b33317eb3003012bfa2 Author: Takashi Iwai Date: Tue Dec 19 17:08:52 2006 +0100 [ALSA] hda-codec - Use global workqueue Use global workqueue for simplicity. The unsolicited event frequency isn't so high to have own queue. Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela commit dc041e0b1fc918562aa3803cda166fee219a34d2 Author: Robert P. J. Day Date: Tue Dec 19 14:44:15 2006 +0100 [ALSA] sound: Change final two instances of kcalloc(1,...) to kzalloc() Change the two remaining instances in the tree of kcalloc(1,...) to the corresponding kzalloc() call. Signed-off-by: Robert P. J. Day Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela commit e4c3bf0f65ec9da8b067a722f734d1012ef12ceb Author: James C Georgas Date: Tue Dec 19 11:09:41 2006 +0100 [ALSA] Remove AC97 POP control for STAC9708/11 The STAC9708/11 AC97 codecs implement the PCM Out Path & Mute bit in the General Purpose register (0x20:F), even though they don't implement the actual function in the mixer. Since the alsa tests for the function by toggling the bit and reading it back to see if it changed, it mistakenly creates a useless control. This patch explicitly removes the control when the codec is an STAC9708/11. I put the check in patch_sigmatel_stac9708_specific(), because I have an SBLive with this chip on it. I don't know if the STAC9758 or other codecs also behave this way. If they do, then this check could maybe go in patch_sigmatel_stac97xx_specific(), or some other more general function. Signed-off-by: James C Georgas Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela commit ca40587087fc05c670f4f2650cc466d557377f6d Author: Krzysztof Helt Date: Mon Dec 18 14:41:03 2006 +0100 [ALSA] sparc dbri comment fix This is a comment fix to avoid misleading about locking in the dbri_cmdsend. Signed-off-by: Krzysztof Helt Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela commit 0664d888a55ff99c8556690a3ae7c76dc1389008 Author: Liam Girdwood Date: Mon Dec 18 14:39:02 2006 +0100 [ALSA] Additional credits to soc-core This patch adds copyright and credit for my good friend Richard Purdie from OpenedHand for his help and code contribution throughout the development of the core code. Many thanks Richard (I guess we overlooked this in trying to get everything working well). It also adds some extra comments wrt to DAI clock matching. Signed-off-by: Liam Girdwood Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela commit 659eacc55a378066b60896b2bbd261ca32a10c04 Author: Liam Girdwood Date: Mon Dec 18 14:38:37 2006 +0100 [ALSA] Remove trailing white space from wm9712.c This patch removes some trailing white space from the WM9712 ASoC codec driver. Signed-off-by: Liam Girdwood Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela commit 4dc53e28e2e5cccb3521466be8f2ab4689ca9143 Author: Tobin Davis Date: Mon Dec 18 13:24:37 2006 +0100 [ALSA] hda-codec - Add quirk for Turbo-X Coeus G610P This patch adds the Turbo-X Coeus G610P to the alc880 config table, based on user provided information. Signed-off-by: Tobin Davis Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela commit b0148a98ec5151fec82064d95f11eb9efbc628ea Author: Johannes Berg Date: Mon Dec 18 13:20:06 2006 +0100 [ALSA] snd-aoa: fix onyx resume When the machine resumes the onyx codec might be in a weird state. Hence, simply fully reset it once (and keep the code to take it out of suspend in case the suspend of the codec chip survives a reset). Signed-off-by: Johannes Berg Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela commit 333824034a19baf71b2bd5fe2153630982f379b0 Author: Matt Porter Date: Mon Dec 18 13:17:28 2006 +0100 [ALSA] hda: add sigmatel 9205 eapd support Adds support for handling EAPD on 9205 codecs Signed-off-by: Matt Porter Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela commit cdf88efa03907a884177b226321bb41bc17c407f Author: Toshimune Konno Date: Mon Dec 18 13:12:18 2006 +0100 [ALSA] ice1724 - Add support for Prodigy 7.1 XT This patch supports Audiotrack 7.1 XT. 7.1XT is almost same hardware as 7.1LT. so using 7.1 LT's code. Signed-off-by: Toshimune Konno Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela commit 1a5965b72209db9db453bc0049393e0d54cf85cb Author: Takashi Iwai Date: Mon Dec 18 13:07:35 2006 +0100 [ALSA] Fix AC97_BUS in soc/pxa/Kconfig Fixed the renamed AC97_BUS in soc/pxa/Kconfig file. Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela commit 9102cd1c35c9be223e0f60b7c42cb581f0d42f1a Author: Tobin Davis Date: Fri Dec 15 10:02:12 2006 +0100 [ALSA] hda-codec (realtek): add support for MacPro series workstations This patch adds limited support for Intel-based MacPro workstations. Currently, the front headphone jack is not functioning, but line out and line in are working. S/PDIF not tested. Signed-off-by: Tobin Davis Signed-off-by: Jaroslav Kysela commit 4484bb2e93a9ab636d149edc6515c75ea224e2b0 Author: Andrew Morton Date: Fri Dec 15 09:30:07 2006 +0100 [ALSA] Fix the soc code after dhowells workqueue changes. From: Andrew Morton I converted the workqueues to per-device while I was there. It seems strange to create a new kernel thread (on each CPU!) and to then only have a single global work to ever be queued upon it. Plus without this, I'd have to use the _NAR stuff, gawd help me. Does that workqueue really need to be per-cpu? Does that workqueue really need to exist? Why not use keventd? Cc: Takashi Iwai Cc: David Howells Signed-off-by: Andrew Morton Signed-off-by: Jaroslav Kysela commit ca377fecdd822f9ef5b0a21586040e7d0e1d0c7a Author: Andrew Morton Date: Fri Dec 15 09:26:20 2006 +0100 [ALSA] ucb1400_ts.c compilation fix (struct snd_ac97) From: Andrew Morton Cc: Takashi Iwai Signed-off-by: Andrew Morton Signed-off-by: Jaroslav Kysela commit cbb7d8f9b7b0a9f51c9869d0da63ea75a2c95caf Author: James Courtier-Dutton Date: Wed Dec 13 11:21:55 2006 +0000 [ALSA] emu10k1: Update registers defines for the Audigy 2/emu10k2.5 Signed-off-by: James Courtier-Dutton Signed-off-by: Jaroslav Kysela commit 7c157069bc953c3cfb5926e92d358e46423bf942 Author: James Courtier-Dutton Date: Sun Dec 10 00:00:38 2006 +0000 [ALSA] ca0106: Fix sound capture on Audigy LS via AC97. Fixes ALSA bug#2286 Signed-off-by: James Courtier-Dutton Signed-off-by: Jaroslav Kysela commit a5f65029ad5c5262ee3aff5165698e431415cf7c Author: Andrew Morton Date: Thu Dec 7 08:26:27 2006 +0100 [ALSA] arm header fix Cc: Takashi Iwai Signed-off-by: Andrew Morton Signed-off-by: Jaroslav Kysela commit c17d6fd90a336d2b971dc9f51338f9540479b263 Author: Olaf Hering Date: Thu Dec 7 08:25:01 2006 +0100 [ALSA] create driver symlink in snd-aoa /sys/bus/aoa-soundbus/devices/*/ create sysfs driver symlink for snd-aoa in /sys/bus/aoa-soundbus/devices/*/ Acked-by: Johannes Berg Signed-off-by: Olaf Hering Signed-off-by: Andrew Morton Signed-off-by: Jaroslav Kysela commit 61e77107fa849b69f50ebe96217ba3468a216ba8 Author: Olaf Hering Date: Thu Dec 7 08:24:12 2006 +0100 [ALSA] create device symlink in snd-aoa create sysfs device symlinks for snd-aoa in /sys/class/sound/controlC0 This allows hald to recognize the device as sound device. Furthermore it allows the desktop user to actually access the sound device nodes. hald and related packages will modify the acl attributes. Fixes https://bugzilla.novell.com/show_bug.cgi?id=106294 Acked-by: Johannes Berg Signed-off-by: Olaf Hering Signed-off-by: Andrew Morton Signed-off-by: Jaroslav Kysela commit e0e6ce0380e0c4de35371372bc5b6c2b02458597 Author: Randy Dunlap Date: Thu Dec 7 08:22:50 2006 +0100 [ALSA] add struct snd_pcm_substream forward declaration fixes: include/sound/pcm.h:62: warning: 'struct snd_pcm_substream' declared inside parameter list Signed-off-by: Randy Dunlap Signed-off-by: Andrew Morton Signed-off-by: Jaroslav Kysela commit eb41dab6e10332c1c9008f3cfc5b88ff1e392cb9 Author: James Courtier-Dutton Date: Wed Dec 6 20:38:45 2006 +0000 [ALSA] emu10k1: Rename the digital optical capture control for the Audigy 2 ZS Notebook. Digital playback and capture now works, but it is not bit accurate because it passes through a resampler. Bit accurate playback and capture will be implemented later via the p17v. Signed-off-by: James Courtier-Dutton Signed-off-by: Jaroslav Kysela commit 184c1e2c4c4221c2b8d1e16c33314595373fa73f Author: James Courtier-Dutton Date: Wed Dec 6 15:58:02 2006 +0000 [ALSA] emu10k1: Add Audio capture support for Audigy 2 ZS Notebook. Implement functionallity in order to fixe ALSA bug#2058. Signed-off-by: James Courtier-Dutton Signed-off-by: Jaroslav Kysela commit 9ed1261e3e617d99b0eb74041d0337ff664e4f5b Author: Teru KAMOGASHIRA Date: Mon Dec 4 18:03:53 2006 +0100 [ALSA] Current driver does not utilize 44.1kHz high quality sampling rate converter. Following patch will make the driver to use the 44.1kHz SRC automatically if the pcm source is 44.1kHz signed 16bit stereo. The SRC is available in YMF754 only. Signed-off-by: Teru KAMOGASHIRA Signed-off-by: Clemens Ladisch Signed-off-by: Jaroslav Kysela commit c577b8a16fd19a33a8865ca6451287d284a0faf6 Author: Joseph Chan Date: Wed Nov 29 15:29:40 2006 +0100 [ALSA] hda-codec - Add support for VIA VT1708(A) HD audio codec This patch is VIA first release for HD audio codec, VT1708(A) and it provides geneneral HD audio driver features. Signed-off-by: Joseph Chan Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela commit 6c5cfd9d9d312b279adf9226b7e664f6f4c4cfc7 Author: Takashi Iwai Date: Tue Nov 28 17:18:25 2006 +0100 [ALSA] Add description about spdif_aclink option for snd-intel8x0 Added a description about spdif_aclink option for snd-intel8x0 driver in ALSA-Configuration.txt. Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela commit d9c96cf35b70b484483446c92f27652f3aef977e Author: Adrian Bunk Date: Tue Nov 28 12:10:09 2006 +0100 [ALSA] sound/soc/soc-dapm.c: make 4 functions static Make the following needlessly global functions static: - dapm_power_widgets() - dapm_mux_update_power() - dapm_mixer_update_power() - dapm_free_widgets() Signed-off-by: Adrian Bunk Signed-off-by: Andrew Morton Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela commit bd869485993f73c303b565da5548bb4e77063c54 Author: Jonathan Woithe Date: Tue Nov 28 11:35:52 2006 +0100 [ALSA] hda-codec - Make internal speaker work on Acer C20x tablets The following patch creates a new 'Mono speaker' control in alsamixer when the Realtek 'acer' model is used with hda_intel. This is needed so the internal mono speaker (when present) can be controlled. This new control won't do anything in Acer laptops which are not fitted with a mono speaker. Acer models which are known to have a mono speaker are the C20x tablet series but there may be others. I guess we could define a new model specifically for Acers with mono speakers but this seems a bit silly given that such a model will be identical to the normal 'acer' model except for this added control. This patch also adds the C20x tablets to the list of PCI ids associated with the 'acer' model. This means that owners of C20x machines will no longer have to supply 'model=acer' when loading hda_intel. Signed-off-by: Jonathan Woithe Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela commit 86d72bdfcd34c9cd8acddf749ff130d5365fe279 Author: Takashi Iwai Date: Tue Nov 28 11:33:10 2006 +0100 [ALSA] hda-codec - Fix compile warnings without CONFIG_SND_DEBUG Fix compile warnings (unused variables) in patch_conexant.c without CONFIG_SND_DEBUG. Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela commit 2e26e483694059d63bda7bb89d5a464c952d1d44 Author: Philipp Zabel Date: Mon Nov 27 12:05:04 2006 +0100 [ALSA] ASoC - Bit clock matching error This patch by Philipp Zabel fixes a bug whereby the BCLK matching fails when the Codec BCLK is constant and the CPU BCLK is based upon a divider. Signed-off-by: Philipp Zabel Signed-off-by: Liam Girdwood Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela commit f5fcc13c2fc62da6f75d80189a51c2492afb39c0 Author: Takashi Iwai Date: Fri Nov 24 17:07:44 2006 +0100 [ALSA] hda-codec - Use snd_pci_quirk_lookup() for board config lookup Use snd_pci_quirk_lookup() for looking up a board config table. The config table is sorted in numerical order of PCI SSIDs. Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela commit 0b830bac35dd6e3996bee675c3893857da8a4d0a Author: Takashi Iwai Date: Fri Nov 24 16:13:57 2006 +0100 [ALSA] Clean up serial-u16500.c Remove uesless typedefs and clean up the code a bit to follow the standard coding style. Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela commit 5b78efd2ef206265aa789485580df9799c54b650 Author: Takashi Iwai Date: Fri Nov 24 16:12:50 2006 +0100 [ALSA] Fix documentation of ASoC Fixed obsolete *_t typedefs in ASoC documentation. Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela commit 9f0ac6e1a8677ac509821f4ff0c77d39b1d63125 Author: Frank Mandarino Date: Fri Nov 24 15:49:39 2006 +0100 [ALSA] Update AT91 ASoC driver for 2.6.19 kernel. Changes were required to support latest AT91 header files. Also updated to remove AT91RM9200-specific code in the ASoC platform drivers to support the AT91SAM9260 and AT91SAM9261 chips, but no testing was performed on these chips. Signed-off-by: Frank Mandarino Signed-off-by: Liam Girdwood Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela commit a9e996604f77be6f1f4deb0eb1cc2652000054f1 Author: Takashi Iwai Date: Fri Nov 24 15:42:07 2006 +0100 [ALSA] intel8x0 - Add spdif_aclink option Added spdif_aclink module option to specify whether the board has SPDIF over AC-link or a direct connection from the controller chip. NForce and ICH4 (or newer) boards may be equipped with SPDIF through AC97 codec. In such a case, SPDIF should be handled as if the old ICH style (the same slot for analog and digital). A quirk list is added to detect this automatically for known hardwares. Corresponds to ALSA bug#2637. Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela commit 5da8fa2516388a20a43cd928fda19f6ac2521afc Author: Takashi Iwai Date: Fri Nov 24 15:38:18 2006 +0100 [ALSA] ens1371 - Clean up quirks Clean up quirks in snd-ens1371 driver using snd_pci_quirk_lookup(). Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela commit 9d74958a845b54c8ccfd4c6d14659f601e6ef43b Author: Takashi Iwai Date: Fri Nov 24 15:37:18 2006 +0100 [ALSA] via82xx - Use quirk list helper function Clean up dxs_support quirk list using snd_pci_quirk_lookup(). Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela commit 1061eeb44493176eb1d12b47d619e61c428c4395 Author: Takashi Iwai Date: Fri Nov 24 15:36:46 2006 +0100 [ALSA] maestro3 - Use quirk list helper function Clean up maestro3 amp and GPIO quirks using snd_pci_quirk_lookup(). Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela commit e2b6d13be4ac3b564ac642a76756f6cf1a7b7b99 Author: Takashi Iwai Date: Fri Nov 24 15:36:13 2006 +0100 [ALSA] nm256 - Use quirk list helper function Clean up nm256-quirk lookup using snd_pci_quirk_lookup(). Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela commit f41bea84c030793b502aa2526bb22476788e731e Author: Takashi Iwai Date: Fri Nov 24 15:35:18 2006 +0100 [ALSA] atiixp - Use quirk list helper function Clean up ac97_codec quirk using snd_pci_quirk_lookup(). Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela commit d9ea472c743ccd7344055cb118bc210befbd8007 Author: Takashi Iwai Date: Fri Nov 24 15:34:06 2006 +0100 [ALSA] Add PCI quirk list helper function Added a helper function snd_pci_quirk_lookup() to look up PCI SSID quirk list. Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela commit 048b945077bdc7e8dff5d5810ff2a0ced3590ca9 Author: Giuliano Pochini Date: Fri Nov 24 13:03:58 2006 +0100 [ALSA] echoaudio, add TLV support This patch adds TLV support to the echoaudio driver. All gains are in the range -127dB to +6dB with steps of 1dB, and -128 is mute. VU-meters levels go from -128 to 0dB. The input gain of the Layla20 ranges from -25dB to +25dB in steps of 0.5dB. Signed-off-by: Giuliano Pochini Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela commit d1d985f019c3b290e09881b7b23abdc87aee2895 Author: Takashi Iwai Date: Thu Nov 23 19:27:12 2006 +0100 [ALSA] Fix obsolete *_t typedefs Fixed obsolete *_t typedefs. Now completely removed. Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela commit 59d6e149d9e5c476138911c95f288ec3feb3a34d Author: Takashi Iwai Date: Thu Nov 23 18:37:00 2006 +0100 [ALSA] Remove obsolete typedefs.h Removed obsolete typedefs.h. It existes only for backward compatibility, and now all codes should be free from such typedefs. Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela commit 56bb0cab1c1698544e61409e3727f2b6bc205501 Author: Takashi Iwai Date: Wed Nov 22 11:52:52 2006 +0100 [ALSA] hda-codec - Add asus-laptop model for ALC861 (ALC660) Added a new model 'asus-laptop' for ASUS F2*/F3* laptops with ALC861 (equivalent with ALC660) codec chip. Also fixed the model for PCI SSID 1043:1338. Corresponding to ALSA bug#2480. Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela commit 9fb62c9f23d437241051e27a11de568361a4745d Author: Randy Dunlap Date: Tue Nov 21 19:01:51 2006 +0100 [ALSA] korg1212: fix printk format warning sound/pci/korg1212/korg1212.c:2359: warning: format '%d' expects type 'int', but argument 4 has type 'size_t' Signed-off-by: Randy Dunlap Signed-off-by: Andrew Morton Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela commit 69e134189763341560a5201c2eee9930eeb0b4f1 Author: Takashi Iwai Date: Tue Nov 21 12:10:55 2006 +0100 [ALSA] hda-intel - Disable INTX when MSI is used Call pci_intx() to disable/enable INTX when MSI is used/unused. Nvidia and AMD boards seem to have problems with MSI when INTX isn't disabled. Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela commit 0b51ba07e2e2866bfea40c5551a926dbefae64da Author: Adrian Bunk Date: Mon Nov 20 17:50:17 2006 +0100 [ALSA] make sound/core/control.c:snd_ctl_new() static Now that everyone uses snd_ctl_new1() and noone is using snd_ctl_new() anymore, we can make it static. Signed-off-by: Adrian Bunk Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela commit 5cd575290b4481b3a6ea307afed760df60d01cbc Author: Tobin Davis Date: Mon Nov 20 17:42:09 2006 +0100 [ALSA] hda-codec - Add missing array to conexant driver This patch adds a missing array to the conexant driver. Signed-off-by: Tobin Davis Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela commit 14e1d357e4fed9577d349952b71ec7d81aad710c Author: Dan Carpenter Date: Mon Nov 20 16:35:18 2006 +0100 [ALSA] atiixp - Add a parameter ac97_quirk Add an option to specify the AC'97 codec instead of probing. This is a fix for bugzilla #7467. Signed-off-by: Dan Carpenter Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela commit ddc2cec4dbec157ac7426111205d59ac28f887ee Author: Adrian Bunk Date: Mon Nov 20 12:03:44 2006 +0100 [ALSA] make sound/pci/hda/patch_sigmatel.c:stac92xx_dmic_labels[] static This patch makes the needlessly global stac92xx_dmic_labels[] static. Signed-off-by: Adrian Bunk Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela commit 761ccb24b4cad211295a5abe231f418ad97aac04 Author: Tobin Davis Date: Mon Nov 20 12:02:56 2006 +0100 [ALSA] hda-codec - Add support for Evesham Voyager C530RD laptops This patch adds support for the Evesham Voyager C530RD series laptops. So far, only playback has been tested, but microphone should also work. Signed-off-by: Tobin Davis Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela commit e3a4050cdd7df05fba6512ac71c9360246e19ac4 Author: Takashi Iwai Date: Thu Nov 16 17:24:20 2006 +0100 [ALSA] hda-codec - Add model for ASUS W3j laptop Added a proper model entry (model=laptop-eapd) for ASUS W3j laptop with AD1986A codec. Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela commit 9dece1d74bd41f593cb1d9e387dc894dd826abf7 Author: Takashi Iwai Date: Thu Nov 16 17:12:49 2006 +0100 [ALSA] hda-codec - Fix ALC861 connection of front-output Fix the wrongly set SET_CONNECTION verb for NID 0x0f of ALC861. The widget has only a single connection although the init verb sets to 0x01. Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela commit a2ee47026025a3d1a5c2eccf3b0aa6c9fb02b101 Author: Tobin Davis Date: Thu Nov 16 16:24:35 2006 +0100 [ALSA] hda-codec - Change Gigabyte K8N51 from 6stack to 6stack-digout This patch moves the entry for the Gigabyte K8N51 from the 6stack grouping to the 6stack-digout grouping, allowing for S/PDIF output functionality. Signed-off-by: Tobin Davis Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela commit d1f6754748a6523fcd35be7f4aaaf6fde5e5ca87 Author: Takashi Iwai Date: Tue Nov 14 12:30:52 2006 +0100 [ALSA] hda-codec - Add support for Sony UX-90s Added the model entry (model=hippo) for Sony UX-90s with ALC262 codec. Although the device has no SPDIF output, the hippo model adds a PCM output, but it must be harmless. Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela commit c9b443d4fdf4e84ce1f40e1f507c313f3a8a8294 Author: Tobin Davis Date: Tue Nov 14 12:13:39 2006 +0100 [ALSA] Add Conexant audio support to the HD Audio driver This driver adds limited support for the Conexant 5045 and 5047 HD Audio codecs. Some issues still need to be resolved. The code is based primarily on code from the Analog Devices AD1981 support and the Realtek ALC260 support. Some code came from the original code developed by Alex Pototskiy (see alsa bugtracker 2485). Signed-off-by: Tobin Davis Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela commit e6327cf90b1e5e849ac87fbdaee7822a64b6ff56 Author: James Courtier-Dutton Date: Sat Nov 11 10:52:06 2006 +0000 [ALSA] snd-ca0106: Updated Enum control names. Signed-off-by: James Courtier-Dutton Signed-off-by: Jaroslav Kysela commit 4c07c81832a9303eeb36afb8f76ad0594e66cf5e Author: James Courtier-Dutton Date: Sat Nov 11 10:48:58 2006 +0000 [ALSA] snd-emu10k1: Update Enum naming. Signed-off-by: James Courtier-Dutton Signed-off-by: Jaroslav Kysela commit 56255060ea51984e728223d8056b3faaba0dadf6 Author: Takashi Iwai Date: Thu Nov 9 16:47:26 2006 +0100 [ALSA] ice1724 - Add support of M-Audio Audiophile 192 Added the (experimental) support of M-Audio Audiophile 192 board. Currently, the analog and the digital playbacks seem working fine. The inputs seem not working as far as I've tested yet. Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela commit bd903b6ed7fb107e122682db5ac8aaa323ab84c9 Author: Liam Girdwood Date: Thu Nov 9 16:35:01 2006 +0100 [ALSA] ASoC - mixer name changes for older OSS app support This patch suggested by Richard Purdie changes the names of some WM8731 and WM8750 mixers so that they will be recognised by some older OSS mixer apps. Changes:- o WM8731 Playback changed to Master Playback o WM8750 Out1 changed to Headphone o WM8750 Out2 changed to Speaker Signed-off-by: Liam Girdwood Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela commit b373bdebf57e2ac7994d9be3a68fd5507515caef Author: Andrew L. Neporada Date: Tue Nov 7 11:37:08 2006 +0100 [ALSA] hda-codec - Clevo M540JE, M550JE laptops (Nvidia MCP51 chipset, ALC883 codec) We need to enable External Amplifier on this laptops. This patch basicly adds laptop-eapd model to ALC883 codec. Signed-off-by: Andrew L. Neporada Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela commit 54bf5dd9ccd8c37830d7dae0737466e8fda018aa Author: Takashi Iwai Date: Mon Nov 6 15:38:55 2006 +0100 [ALSA] hdspm - Fix printk warnings sound/pci/rme9652/hdspm.c: In function 'snd_hdspm_hw_params': sound/pci/rme9652/hdspm.c:3681: warning: format '%08X' expects type 'unsigned int', but argument 4 has type 'unsigned char *' sound/pci/rme9652/hdspm.c:3692: warning: format '%08X' expects type 'unsigned int', but argument 4 has type 'unsigned char *' Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela commit 9174140cf383c56bdcabb4caf9c99c5ac8f3fdd7 Author: Takashi Iwai Date: Mon Nov 6 14:45:42 2006 +0100 [ALSA] hda-codec - Fix model for ASUS M2N-MX Add a proper model (3stack) for ASUS M2N-MX with AD1986A codec. Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela commit 81d7724a8ee84693befbd60d730199ffb3988f29 Author: Clemens Ladisch Date: Mon Nov 6 09:26:41 2006 +0100 [ALSA] maestro3: add request_firmware() Load the ASSP codes using request_firmware(), if possible, instead of using the built-in blobs. Signed-off-by: Clemens Ladisch Signed-off-by: Jaroslav Kysela commit 2493a6d18b1f5df59c7bcfeefcbde70bee146490 Author: Clemens Ladisch Date: Mon Nov 6 09:24:29 2006 +0100 [ALSA] korg1212: add request_firmware() Load the DSP code using request_firmware(), if possible, instead of using the built-in blob. Signed-off-by: Clemens Ladisch Signed-off-by: Jaroslav Kysela commit 226968c7afd464b794f34f9ea8cb4bcfe48447dc Author: Clemens Ladisch Date: Mon Nov 6 09:21:58 2006 +0100 [ALSA] wavefront: add request_firmware() Load the YSS225 register initialization data using request_firmware(), if possible, instead of using the built-in data blob. Signed-off-by: Clemens Ladisch Signed-off-by: Jaroslav Kysela commit 59540fe85924ecb7b9760ab422cffaea0c3ce43a Author: Clemens Ladisch Date: Mon Nov 6 09:20:04 2006 +0100 [ALSA] wavefront: simplify YSS225 register initialization Instead of using a somewhat algorithmic approach of initializing the YSS225's registers, just use a simple series of port/value pairs. This makes it easier to later replace or entirely remove the register data blob. Signed-off-by: Clemens Ladisch Signed-off-by: Jaroslav Kysela commit de66d53e46f39de6ea3261609fdb92900bb34a42 Author: Clemens Ladisch Date: Mon Nov 6 09:18:34 2006 +0100 [ALSA] sb16: add request_firmware() Load the CSP programs using request_firmware(), if possible, instead of using the built-in firmware blobs. Signed-off-by: Clemens Ladisch Signed-off-by: Jaroslav Kysela commit 219e281f4627a395aaceff0e4a257cd18608e145 Author: Hubert Kahlert Date: Tue Oct 31 15:31:27 2006 +0100 [ALSA] Fix mask to stop AT91 SSC clock on shutdown This patch by Frank Mandarino and Hubert Kahlert fixes a bug in the AT91 SSC (i2s) shutdown code that would erroneously disable other AT91 peripheral clocks. Signed-off-by: Hubert Kahlert Signed-off-by: Frank Mandarino Signed-off-by: Liam Girdwood Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela commit 8b65727bf07abc0b3fdac4fcf2f90c5882d65f4f Author: Matt Porter Date: Thu Oct 26 17:12:59 2006 +0200 [ALSA] hda: add dig mic support for sigmatel codecs Adds support for digital microphone pin widgets on SigmaTel codecs. Enables support only on the 9205 codecs for now. Signed-off-by: Matt Porter Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela commit 06bf2f495aabfdbe9d5db7b910fa75dd7f72131a Author: Takashi Iwai Date: Tue Oct 24 19:49:39 2006 +0200 [ALSA] hda-codec - Fix model for Lenovo A60 desktop Add a proper model entry (3stack) for Lenovo A60 desktop with AD1986a codec to fix noise problems. Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela commit f1a63a38d2a885cc7e38c67b699171a7c5666d88 Author: Takashi Iwai Date: Tue Oct 24 18:25:29 2006 +0200 [ALSA] ac97 - Suppress power-saving mode on non-supporting drivers Don't enable power-saving mode on drivers that don't support it. The supporting drivers set AC97_SCAP_POWER_SAVE to scaps at creation of ac97 instance. Currently enable on the following drivers: intel8x0, intel8x0m, atiixp, atiixp-modem, via82xx and via82xx-modem. Also, a bit clean up of power-saving stuff: - Don't create an own workq - Remove superfluous ifdefs Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela commit 7cdbff945e9e3bb592dee2f66afbcc2255747f8f Author: Mariusz Domanski Date: Mon Oct 23 13:42:56 2006 +0200 [ALSA] hda-codec - Add asus model to ALC861 codec This patch adds support for Asus laptops (for example: Asus A6Rp-AP002). Signed-off-by: Mariusz Domanski Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela commit a71a468a50f1385855e28864e26251b02df829bb Author: Liam Girdwood Date: Thu Oct 19 20:35:56 2006 +0200 [ALSA] ASoC: Add support for BCLK based on (Rate * Chn * Word Size) This patch adds support for the DAI BCLK to be generated by multiplying Rate * Channels * Word Size (RCW). This now gives 3 options for BCLK clocking and synchronisation :- 1. BCLK = Rate * x 2. BCLK = MCLK / x 3. BCLK = Rate * Chn * Word Size. (New) Changes:- o Add support for RCW generation of BCLK o Update Documentation to include RCW. o Update DAI documentation for label = value DAI modes. o Add RCW support to wm8731, wm8750 and pxa2xx-i2s drivers. Signed-off-by: Liam Girdwood Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela commit 543a0fbe18d0b44f3d037fe6b59458fa0c0d5e4b Author: Frank Mandarino Date: Thu Oct 19 18:22:53 2006 +0200 [ALSA] ASoC AT91 DAI modes update This patch by Frank Mandarino updates the AT91RM9200 I2S DAI audio modes as follows:- o fixes a typo in the 16k mode o removes experimental 24k mode o adds a 32k mode. Signed-off-by: Frank Mandarino Signed-off-by: Liam Girdwood Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela commit d7923b2a816625dc4208d89471da6bdcab188cdb Author: Remy Bruno Date: Tue Oct 17 12:41:56 2006 +0200 [ALSA] hdsp - Add DDS register support for RME9632 rev >= 152 Add DDS register support for RME9632 rev >= 152. This register sets the sample rate for these cards and is required in addition to the standard control register. It corresponds to a quartz divisor. Signed-off-by: Remy Bruno Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela commit ccc656ce5f6627032bd44e660071bb71e65a231a Author: Kailang Yang Date: Tue Oct 17 12:32:26 2006 +0200 [ALSA] hda-codec - Add new modesl for Realtek codecs Changes from Realtek driver: - New models hippo and hippo_1 for ALC262 - New models tagra-dig and tagra-2ch-dig for ALC883 - New id for ALC660 codec chip Signed-off-by: Kailang Yang Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela commit a53d1aece388d940831846f642810e47526883e8 Author: Tobin Davis Date: Tue Oct 17 12:00:28 2006 +0200 [ALSA] hda-codec - Add toshiba model to ALC861 codec This patch adds support for Toshiba laptops. Code is from RealTek's alsa-driver-1.0.12-4.05b tree. Signed-off-by: Tobin Davis Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela commit 12e74f7d430655f541b85018ea62bcd669094bd7 Author: Liam Girdwood Date: Mon Oct 16 21:19:48 2006 +0200 [ALSA] ASoC - Fix build warnings in soc-core.c This patch fixes some build warnings in soc-core.c Changes:- o Check the return value of soc_ac97_dev_register() o Check return value of calls to device_create_file() Signed-off-by: Liam Girdwood Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela commit cbcc2c4c07bd34586c7fd8d7513d3a397d39ce3c Author: Jerome Demange Date: Mon Oct 16 21:08:57 2006 +0200 [ALSA] ac97 - enables sound output through speakers on MSI S250 laptop Signed-off-by: Jerome Demange Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela commit 3cee5a60ce18034a63f70ba2bdd54f85018ce960 Author: Remy Bruno Date: Mon Oct 16 12:46:32 2006 +0200 [ALSA] hdspm: Add support for AES32 Add support for AES32. Difference between MADI and AES32 is done through revision. Master support is not finished for now (RME so-called DDS feature is not supported yet) Signed-off-by: Remy Bruno Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela commit b3b9c1cbb35125f7e43a323ebe89e7a74e3c1ac2 Author: Takashi Iwai Date: Fri Oct 13 20:09:59 2006 +0200 [ALSA] Remove trailing whitespaces from soc/* files Remove trailing whitespaces from soc/* files added by the conversion to C99-style initialization. Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela commit b5c5fd24b9d34e4670cb339e546bfae7ad316354 Author: Liam Girdwood Date: Fri Oct 13 19:13:41 2006 +0200 [ALSA] ASoC debug output build breakage This patch fixes a build failure when ASoC debug is enabled. Signed-off-by: Liam Girdwood Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela commit 35f60839b6158f72d2be0dd2764ad772e1d44e8a Author: Takashi Iwai Date: Fri Oct 13 12:46:10 2006 +0200 [ALSA] hda-codec - Add missing comma Added a missing comma in the medion patch. Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela commit 527541f9a8a83eedb4d732657dbfdcd2c4ca8bb4 Author: Liam Girdwood Date: Fri Oct 13 12:33:56 2006 +0200 [ALSA] ASoC DAI capabilities labelling This patch suggested by Takashi changes the DAI capabilities definitions in pxa-i2s.c, at91rm9200-i2s.c, wm8731.c, wm8750.c and wm9712.c to use a label = value style. Signed-off-by: Liam Girdwood Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela commit c07584c83287ae5a13cc836f69a1d824ad068c66 Author: Tobin Davis Date: Fri Oct 13 12:32:16 2006 +0200 [ALSA] hda-codec - Add support for Medion laptops This patch adds audio support for Medion's line of laptops, based on code shipped with the laptops. Microphone support is still being explored. Signed-off-by: Tobin Davis Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela commit 734c2d4bb7cfccaab79923331efc7422e4e76a8a Author: Liam Girdwood Date: Thu Oct 12 14:34:32 2006 +0200 [ALSA] ASoC pxa2xx build support This patch builds ASoC pxa2xx support for Corgi, Spitz, Tosa and Poodle Zaurus machines. From: Liam Girdwood Signed-off-by: Richard Purdie Signed-off-by: Liam Girdwood Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela commit 6e24dd9310b66d6f500a81ee320a8babec529573 Author: Liam Girdwood Date: Thu Oct 12 14:33:45 2006 +0200 [ALSA] ASoC pxa2xx Poodle machine support This patch adds Alsa audio support to the Sharp Zaurus SL-C5600 (Poodle) machine. From: Liam Girdwood Signed-off-by: Richard Purdie Signed-off-by: Liam Girdwood Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela commit 1b49cb987030c09ca763c1dabd5c5e33f669e530 Author: Liam Girdwood Date: Thu Oct 12 14:33:09 2006 +0200 [ALSA] ASoC pxa2xx Tosa machine support This patch adds Alsa audio support to the Sharp Zaurus SL-C6000 (Tosa) machine. From: Liam Girdwood Signed-off-by: Dirk Opfer Signed-off-by: Richard Purdie Signed-off-by: Liam Girdwood Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela commit 7fb290d03af69bfca5876573ac0eada40bd4e292 Author: Liam Girdwood Date: Thu Oct 12 14:32:13 2006 +0200 [ALSA] ASoC pxa2xx Spitz machine support This patch adds Alsa audio support to the Sharp Zaurus SL-C1000/SL-C3x00 (Akita/Spitz) machines. From: Liam Girdwood Signed-off-by: Richard Purdie Signed-off-by: Liam Girdwood Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela commit a1eb4b3caf3abd0d1a8474f07d29959e1879bb29 Author: Liam Girdwood Date: Thu Oct 12 14:31:16 2006 +0200 [ALSA] ASoC pxa2xx Corgi machine support This patch adds Alsa audio support to the Sharp Zaurus SL-C7x0/C860 (Corgi) machines. From: Liam Girdwood Signed-off-by: Graeme Gregory Signed-off-by: Richard Purdie Signed-off-by: Liam Girdwood Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela commit 75b41027662e29822746342865fa8abd941d2604 Author: Liam Girdwood Date: Thu Oct 12 14:29:03 2006 +0200 [ALSA] ASoC pxa2xx AC97 support This patch adds pxa2xx AC97 ASoC audio support. It's based on sound/arm/pxa-ac97 by Nicolas Pitre with the following differences. o Modified driver structure to use ASoC core PCM callbacks. o Removed AC97 configuration function (all handled in ASoC core) o Added and exported ASoC DAI configuration table. o Added DMA support for AUX DAC and Mic ADC o Separated out AC97 reset into cold and warm reset functions. From: Liam Girdwood Signed-off-by: Nicolas Pitre Signed-off-by: Richard Purdie Signed-off-by: Liam Girdwood Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela commit 3e7cc3d3d1c435f83533b8bf2cf1833855be2901 Author: Liam Girdwood Date: Thu Oct 12 14:28:10 2006 +0200 [ALSA] ASoC pxa2xx I2S support This patch adds pxa2xx I2S ASoC audio support. Features:- o Supports playback/capture o 16 bit PCM o 8k - 96k sample rates o Supports master and slave mode. From: Liam Girdwood Signed-off-by: Richard Purdie Signed-off-by: Liam Girdwood Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela commit f11a96d5cd94202479e603f9dfaff6e92f342135 Author: Liam Girdwood Date: Thu Oct 12 14:26:55 2006 +0200 [ALSA] ASoC pxa2xx DMA support This patch adds pxa2xx ASoC DMA audio support. It's based on sound/arm/pxa-pcm.c by Nicolas Pitre with the following differences. o Modified driver structure to use ASoC core PCM callbacks and data structures. o Registration with ASoC core. From: Liam Girdwood Signed-off-by: Nicolas Pitre Signed-off-by: Richard Purdie Signed-off-by: Liam Girdwood Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela commit 102fa9060e114a53628a6594034b6ecf624dffc6 Author: Clemens Ladisch Date: Wed Oct 11 12:05:59 2006 +0200 [ALSA] ymfpci: add request_firmware() Load the DSP and controller microcode using request_firmware(), if possible, instead of using the built-in firmware. Signed-off-by: Clemens Ladisch Signed-off-by: Jaroslav Kysela commit e40a0b2e9d73c69e6b9e5d55eb56696f81fbf802 Author: James Courtier-Dutton Date: Tue Oct 10 18:44:29 2006 +0100 [ALSA] snd-emu10k1: emu1010: replace long udelay with msleep. Signed-off-by: James Courtier-Dutton Signed-off-by: Jaroslav Kysela commit b0dbdaea55d55c05be972cd2a040acfa073b0509 Author: James Courtier-Dutton Date: Tue Oct 10 18:08:45 2006 +0100 [ALSA] snd-emu10k1: Add emu1010 internal clock rate control for 44100 or 48000. Signed-off-by: James Courtier-Dutton Signed-off-by: Jaroslav Kysela commit 0f71e8b98506252db22a0c4fcfecb0aadcf393cc Author: Takashi Iwai Date: Tue Oct 10 15:59:46 2006 +0200 [ALSA] Fix irq handler in soc/at91/at91rm9200-i2s.c Fixed the irq handler in soc/at91-at91rm9200-i2s.c to follow the new style without pt_regs. Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela commit 9148cc502752b12051760e6c5ba5daaea3367360 Author: James Courtier-Dutton Date: Mon Oct 9 23:08:00 2006 +0100 [ALSA] snd_emu10k1: Added support for 14dB Attenuation PADS on DACs and ADCs. Signed-off-by: James Courtier-Dutton Signed-off-by: Jaroslav Kysela commit 6add0f4242fc52a97a92fca99a39f35298c2b50b Author: Remy Bruno Date: Mon Oct 9 15:52:01 2006 +0200 [ALSA] hdsp: support for mixer matrix of RME9632 rev 152 Added the support for mixer matrix of RME9632 rev 152. Signed-off-by: Remy Bruno Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela commit 9bf5f8aa222e0f943bd5037207628ad70b729576 Author: Clemens Ladisch Date: Mon Oct 9 08:18:26 2006 +0200 [ALSA] emu10k1: select FW_LOADER Let the emu10k1 driver select FW_LOADER because the new Emu1010 support requires it. Signed-off-by: Clemens Ladisch Signed-off-by: Jaroslav Kysela commit 8a89876bc108cacebbe5cc47049c162a8a143b26 Author: Clemens Ladisch Date: Mon Oct 9 08:17:48 2006 +0200 [ALSA] pci: select FW_LOADER instead of depending on it Let the AudioScience, Echoaudio and Riptide drivers select FW_LOADER instead of depending on it so that they can be configured without having to enable FW_LOADER manually. Signed-off-by: Clemens Ladisch Signed-off-by: Jaroslav Kysela commit e117483e3e713c6411968afea825daa1133bc28d Author: Clemens Ladisch Date: Mon Oct 9 08:14:58 2006 +0200 [ALSA] soc-core: fix multi-line string literal Properly quote a string that had an embedded newline. Signed-off-by: Clemens Ladisch Signed-off-by: Jaroslav Kysela commit 8dafc0fb49b903c4e7262b2622bef8342345c700 Author: Frank Mandarino Date: Fri Oct 6 18:41:42 2006 +0200 [ALSA] ASoC AT91RM92000 build This patch adds a Makefile and Kconfig to build the ASoC AT91RM9200 support. Signed-off-by: Frank Mandarino Signed-off-by: Liam Girdwood Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela commit b41bf38a4323a32ec4890c74818c4a3d2661fe6c Author: Frank Mandarino Date: Fri Oct 6 18:41:10 2006 +0200 [ALSA] ASoC AT91RM92000 eti_b1 machine support This patch adds support for the Endrelia ETI_B1 machine using the WM8731 codec and the AT91RM9200 platform. Signed-off-by: Frank Mandarino Signed-off-by: Liam Girdwood Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela commit 0cbbec0984f10f216ed8332e0d39ac93cbe33a0b Author: Frank Mandarino Date: Fri Oct 6 18:40:25 2006 +0200 [ALSA] ASoC AT91RM92000 I2S support This patch adds I2S support to the Atmel AT91RM9200 CPU. Features:- o Playback/Capture supported. o 16 Bit data size. o 8k - 48k sample rates. o ssc0, ssc1 and ssc2 supported as I2S ports. Signed-off-by: Frank Mandarino Signed-off-by: Liam Girdwood Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela commit ff9abf5b0a655b59d59ea61aec5be6285bf3ac30 Author: Frank Mandarino Date: Fri Oct 6 18:39:29 2006 +0200 [ALSA] ASoC AT91RM92000 audio DMA This patch adds ASoC audio DMA support to the Atmel AT91RM9200 CPU. Features:- o Playback/Capture supported. o 16 Bit data size. Signed-off-by: Frank Mandarino Signed-off-by: Liam Girdwood Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela commit 7f137ab673124ee0a210ab5b74c1f7234d6145fa Author: Richard Purdie Date: Fri Oct 6 18:38:37 2006 +0200 [ALSA] ASoC codecs: build files This patch adds an ASoC Makefile and Kconfig for the WM8731, WM8750 and WM9712 codecs. Signed-off-by: Richard Purdie Signed-off-by: Liam Girdwood Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela commit dbc6b6ad767c86907db373e85139b0e975ba7599 Author: Richard Purdie Date: Fri Oct 6 18:38:03 2006 +0200 [ALSA] ASoC codecs: generic AC97 support This patch allows the std Alsa AC97 codec driver to use any AsoC AC97 controller driver. Currently, only HiFi playback and Capture are supported atm. Signed-off-by: Richard Purdie Signed-off-by: Liam Girdwood Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela commit 10c5cf30446fe91b7173436b75c4f00dfb4cd9f8 Author: Richard Purdie Date: Fri Oct 6 18:37:32 2006 +0200 [ALSA] ASoC codecs: WM9712 support This patch adds ASoC support for the WM9712 codec. Supported features:- o Capture/Playback/Sidetone/Bypass. o Aux DAC. o 8k - 48k sample rates. o DAPM. Signed-off-by: Richard Purdie Signed-off-by: Liam Girdwood Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela commit abadfc928a27e1cf27c834e8e29e6b1f64ca2d55 Author: Richard Purdie Date: Fri Oct 6 18:36:39 2006 +0200 [ALSA] ASoC codecs: WM8750 support This patch adds ASoC support for the WM8750 codec. Supported features:- o Capture/Playback/Sidetone/Bypass. o 16 & 24 bit audio. o 8k - 96k sample rates. o DAPM. Signed-off-by: Richard Purdie Signed-off-by: Liam Girdwood Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela commit 40e0aa64660b4e28a9348e57bfbda6c114617969 Author: Richard Purdie Date: Fri Oct 6 18:36:07 2006 +0200 [ALSA] ASoC codecs: WM8731 support This patch adds ASoC support for the WM8731 codec. Supported features:- o Capture/Playback/Sidetone/Bypass. o 16 & 24 bit audio. o 8k - 96k sample rates. o DAPM. Signed-off-by: Richard Purdie Signed-off-by: Liam Girdwood Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela commit eb1a6af39b70375d93ed25e7c916f64463e00614 Author: Liam Girdwood Date: Fri Oct 6 18:34:51 2006 +0200 [ALSA] ASoC: documentation & maintainer This patch adds documentation describing the ASoC architecture and a maintainer entry for ASoC. The documentation includes the following files:- codec.txt: Codec driver internals. DAI.txt: Description of Digital Audio Interface standards and how to configure a DAI within your codec and CPU DAI drivers. dapm.txt: Dynamic Audio Power Management. platform.txt: Platform audio DMA and DAI. machine.txt: Machine driver internals. pop_clicks.txt: How to minimise audio artifacts. clocking.txt: ASoC clocking for best power performance. Signed-off-by: Liam Girdwood Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela commit a3288176de3fdd439d9bca0a0b9ca749c12ac5ac Author: Liam Girdwood Date: Fri Oct 6 18:33:55 2006 +0200 [ALSA] ASoC: Build files This patch adds support for building the ASoC core and the dynamic audio power management support. Signed-off-by: Liam Girdwood Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela commit 2b97eabc09f42d0f63e8053636e34e1afa0d604e Author: Richard Purdie Date: Fri Oct 6 18:32:18 2006 +0200 [ALSA] ASoC: dynamic audio power management (DAPM) This patch adds Dynamic Audio Power Management (DAPM) to ASoC. Dynamic Audio Power Management (DAPM) is designed to allow portable and handheld Linux devices to use the minimum amount of power within the audio subsystem at all times. It is independent of other kernel PM and as such, can easily co-exist with the other PM systems. DAPM is also completely transparent to all user space applications as all power switching is done within the ASoC core. No code changes or recompiling are required for user space applications. DAPM makes power switching decisions based upon any audio stream (capture/playback) activity and audio mixer settings within the device. DAPM spans the whole machine. It covers power control within the entire audio subsystem, this includes internal codec power blocks and machine level power systems. There are 4 power domains within DAPM:- 1. Codec domain - VREF, VMID (core codec and audio power) Usually controlled at codec probe/remove and suspend/resume, although can be set at stream time if power is not needed for sidetone, etc. 2. Platform/Machine domain - physically connected inputs and outputs Is platform/machine and user action specific, is configured by the machine driver and responds to asynchronous events e.g when HP are inserted 3. Path domain - audio subsystem signal paths Automatically set when mixer and mux settings are changed by the user. e.g. alsamixer, amixer. 4. Stream domain - DAC's and ADC's. Enabled and disabled when stream playback/capture is started and stopped respectively. e.g. aplay, arecord. All DAPM power switching decisions are made automatically by consulting an audio routing map of the whole machine. This map is specific to each machine and consists of the interconnections between every audio component (including internal codec components). Signed-off-by: Richard Purdie Signed-off-by: Liam Girdwood Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela commit db2a416556af0313db028147e4a22fef6f214f2f Author: Frank Mandarino Date: Fri Oct 6 18:31:09 2006 +0200 [ALSA] ASoC: core code This patch is the core of ASoC functionality. The ASoC core is designed to provide the following features :- o Codec independence. Allows reuse of codec drivers on other platforms and machines. o Platform driver code reuse. Reuse of platform specific audio DMA and DAI drivers on different machines. o Easy I2S/PCM digital audio interface configuration between codec and SoC. Each SoC interface and codec registers their audio interface capabilities with the core at initialisation. The capabilities are subsequently matched and configured at run time for best power and performance when the application hw params are known. o Machine specific controls/operations: Allow machines to add controls and operations to the audio subsystem. e.g. volume control for speaker amp. To achieve all this, ASoC splits an embedded audio system into 3 components :- 1. Codec driver: The codec driver is platform independent and contains audio controls, audio interface capabilities, codec dapm and codec IO functions. 2. Platform driver: The platform driver contains the audio dma engine and audio interface drivers (e.g. I2S, AC97, PCM) for that platform. 3. Machine driver: The machine driver handles any machine specific controls and audio events. i.e. turning on an amp at start of playback. Signed-off-by: Frank Mandarino Signed-off-by: Richard Purdie Signed-off-by: Liam Girdwood Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela commit 808db4a4512bedd45b62de255f7eedb5d5b788b9 Author: Richard Purdie Date: Fri Oct 6 18:20:14 2006 +0200 [ALSA] ASoC: core and dapm headers This patch adds the ASoC and DAPM headers. Features:- o Defines Digital Audio Interface (DAI) API o Defines Codec, Platform and Machine API o Defines Dynamic Audio Power Management API Signed-off-by: Richard Purdie Signed-off-by: Liam Girdwood Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela commit 3388c37e04ec0e35ebc1b4c732fdefc9ea938f3b Author: Takashi Iwai Date: Fri Oct 6 17:06:39 2006 +0200 [ALSA] intel8x0 - Use pci_iomap Use pci_iomap and ioread*/iowrite*() functions for accessing hardwares. pci_iomap is suitable for hardwares like ICH and compatible that have both PIO and MMIO. Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela commit c7132aeb72ad1106dc76279de4d005f9e1c5815c Author: Jaroslav Kysela Date: Fri Oct 6 15:12:29 2006 +0200 [ALSA] pcm core: add prealloc_max file to substream directory to show maximum DMA size Users ask us many times about the maximum DMA size for PCM devices. This file gives them a hint in KB. Signed-off-by: Jaroslav Kysela commit b66b3cfe6c2f6560f351278883a325b6ebc478f5 Author: Jaroslav Kysela Date: Fri Oct 6 09:34:20 2006 +0200 [ALSA] hda_intel: increase maximum DMA buffer size to 1024MB See ALSA bug#2481 . Signed-off-by: Jaroslav Kysela commit bbb53551e31dce3cdbf61330e135179a55c82fd1 Author: Takashi Iwai Date: Thu Oct 5 16:21:19 2006 +0200 [ALSA] emu10k1 - Fix compile warning Fixed a compile warning regarding print format for size_t. Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela commit 9244b2c3079faac79b3b961116bd548c45087e2c Author: Johannes Berg Date: Thu Oct 5 16:02:22 2006 +0200 [ALSA] alsa core: convert to list_for_each_entry* This patch converts most uses of list_for_each to list_for_each_entry all across alsa. In some place apparently an item can be on a list with different pointers so of course that isn't compatible with list_for_each, I therefore didn't touch those places. Signed-off-by: Johannes Berg Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela commit d595ee7e0162ae66faa8c4c7d8c2069b40d64fed Author: Johannes Berg Date: Thu Oct 5 15:08:23 2006 +0200 [ALSA] aoa: fix up i2sbus_attach_codec This patch changes i2sbus_attach_codec to implement a proper error handling strategy using labels to jump to the right part. Since it has an elaborate set-up sequence it also needs that tear-down, which I had hard-coded inbetween all the checks. This increases readability and should reduce .text size as well. Signed-off-by: Johannes Berg Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela commit 73e85fe8452b950b93cfb61377f749e9b15437fb Author: Johannes Berg Date: Thu Oct 5 15:07:23 2006 +0200 [ALSA] aoa: set device pointer in pcms This patch makes a few whitespace cleanups and makes i2sbus assign the new struct device pointer in struct snd_pcm so that the proper device symlink shows up in sysfs. Signed-off-by: Johannes Berg Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela commit c78085fcd2ce7cd036e1488472eb41a64d70949a Author: Johannes Berg Date: Thu Oct 5 15:06:34 2006 +0200 [ALSA] alsa core: add struct device pointer to struct snd_pcm This patch adds a struct device pointer to struct snd_pcm in order to be able to give it a different device than the card. It defaults to the card's device, however, so it should behave identically for drivers not touching the field. Signed-off-by: Johannes Berg Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela commit 12b131c4cf3eb1dc8a60082a434b7b100774c2e7 Author: Johannes Berg Date: Thu Oct 5 15:05:34 2006 +0200 [ALSA] allow registering an alsa device with struct device pointer This patch adds snd_register_device_for_dev taking a struct device pointer to link the new device to and makes snd_register_device a simple static inline wrapper around it. Signed-off-by: Johannes Berg Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela commit feaa6a74d852be40c0e717471aa92eead012052c Author: Jochen Voss Date: Wed Oct 4 18:08:43 2006 +0200 [ALSA] Enable the analog loopback of the Revolution 5.1 Enable the analog loopback of the Revolution 5.1 card. This patch adds support for the PT2258 volume controller and modifies the Revolution 5.1 driver to make use of this facility. This allows to control the analog loopback of the card. Signed-off-by: Jochen Voss Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela commit a58e7cb16dfae8a3c1c98a7ab7ca02a9e9b38921 Author: Jochen Voss Date: Wed Oct 4 18:04:10 2006 +0200 [ALSA] Enable capture from line-in and CD on Revolution 5.1 Enable capture from line-in and CD on the Revolution 5.1 card. This patch adds support for switching between the 5 input channels of the AK5365 ADC and modifies the Revolution 5.1 driver to make use of this facility. Previously the capture channel was fixed to channel 0 (microphone on the Revolution 5.1 card). Signed-off-by: Jochen Voss Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela commit e4f8e656d8c152c08cd44d0e3c21f009fab09952 Author: Clemens Ladisch Date: Wed Oct 4 13:42:57 2006 +0200 [ALSA] usb-audio: allow pausing Add pause capabilities for both USB playback and capture streams. Signed-off-by: Clemens Ladisch Signed-off-by: Jaroslav Kysela commit 1700f3080d98323e91864d67cb9f6d46f818ccf0 Author: Clemens Ladisch Date: Wed Oct 4 13:41:25 2006 +0200 [ALSA] usb-audio: merge playback/capture hardware information structs The hardware information structures for playback and capture streams, respectively, are the same, so we can use just one structure for both streams. Signed-off-by: Clemens Ladisch Signed-off-by: Jaroslav Kysela commit 9f4bd5dde81b5cb94e4f52f2f05825aa0422f1ff Author: James Courtier-Dutton Date: Sun Oct 1 10:48:04 2006 +0100 [ALSA] snd-emu10k1: Added support for emu1010, including E-Mu 1212m and E-Mu 1820m Signed-off-by: James Courtier-Dutton Signed-off-by: Jaroslav Kysela commit acf1da4522add3771f4851c09c7fe6bcf1dd6636 Author: Pierre Ossman Date: Fri Feb 9 08:29:19 2007 +0100 mmc: sdhci: Stop asking for mail We get enough error reports without having to ask for it. Remove notices about mailing the development list. Signed-off-by: Pierre Ossman commit 52fbf9c976b36654e08e94c3107ddbaac7e2da33 Author: Pierre Ossman Date: Fri Feb 9 08:23:41 2007 +0100 mmc: sdhci: Remove driver version The driver version was only really meaningful when it was an out-of-tree driver. Now we can use the version of the kernel. Signed-off-by: Pierre Ossman commit 1615cc224e5d822c91bf0b8128f54680c6e92d2f Author: Pierre Ossman Date: Fri Feb 9 08:19:07 2007 +0100 mmc: wbsd: Remove driver version The driver version was only really meaningful when it was an out-of-tree driver. Now we can use the version of the kernel. Signed-off-by: Pierre Ossman commit 2cb4abd12bab7efd22a8b69d3b9a739500e8fee5 Author: Randy Dunlap Date: Wed Feb 7 15:52:36 2007 -0800 MAINTAINERS: update DMFE and wireless drivers mailing list List netdev as the mailing list for DMFE (network driver) instead of lkml. List linux-wireless as the mailing list for wireless network drivers. Signed-off-by: Randy Dunlap Signed-off-by: Jeff Garzik commit 9b4c7a4ec988d9b8bbe847f3c983938220e3a38b Author: Li Yang Date: Thu Feb 8 17:35:54 2007 +0800 ucc_geth: Add support to local-mac-address property IEEE-1275 defines “local-mac-address†to be a standard property name to specify preassigned network address. This patch adds support for it. Signed-off-by: Li Yang Signed-off-by: Jeff Garzik commit a1862a53df1a57387aeee059276ba4233e12b4db Author: Li Yang Date: Thu Feb 8 17:34:42 2007 +0800 ucc_geth: Remove obsolete workaround of link speed change The workaround used a long delay of 4s which caused problem when two link-changes happens at the same time. Signed-off-by: Li Yang Signed-off-by: Wu Xiaochuan Signed-off-by: Jeff Garzik commit 0ee8d33c64df9a719fd61ba693203e3b33b9e10a Author: Divy Le Ray Date: Thu Feb 8 16:55:59 2007 -0800 cxgb3: sysfs attributes in -mm tree This patch fixes the usage of sysfs attributes in cxgb3 for the -mm tree. It is built against the driver commited in the -mm tree. Signed-off-by: Divy Le Ray Cc: Greg KH Signed-off-by: Andrew Morton Signed-off-by: Jeff Garzik commit 1539b98b561754252dd520b98fa03a688a4f81b5 Author: Jiri Bohac Date: Thu Feb 8 16:02:21 2007 -0800 [IPX]: Fix NULL pointer dereference on ipx unload Fixes a null pointer dereference when unloading the ipx module. On initialization of the ipx module, registering certain packet types can fail. When this happens, unloading the module later dereferences NULL pointers. This patch fixes that. Please apply. Signed-off-by: Jiri Bohac Signed-off-by: David S. Miller commit 42c05f6e6e3d57495054a4cae35850b3f7d1c343 Author: David S. Miller Date: Thu Feb 8 16:01:09 2007 -0800 [ATM]: atmarp.h needs to always include linux/types.h To provide the __be* types, even for userspace includes. Reported by Andrew Walrond. Signed-off-by: David S. Miller commit 8f34f6cfa27ddae8faf10aef986db2fda1ba6791 Author: Timur Tabi Date: Thu Feb 8 10:47:31 2007 -0600 [POWERPC] QE: Rename ucc_slow_info.us_regs to ucc_slow_info.regs Rename the 'us_regs' field of the ucc_slow_info structure in ucc_slow.h to just 'regs'. The equivalent field in the ucc_fast_info structure is also called 'regs', so this patch makes them comparable, and makes the code a little easier to read, because there already is a 'us_regs' in another ucc_slow structure. Signed-off-by: Timur Tabi Signed-off-by: Kumar Gala commit 4387ff75f29412a234d394b0276c2b239d3d3844 Author: David S. Miller Date: Thu Feb 8 15:06:08 2007 -0800 [NET]: Fix net/socket.c warnings. GCC (correctly) says: net/socket.c: In function ‘sys_sendto’: net/socket.c:1510: warning: ‘err’ may be used uninitialized in this function net/socket.c: In function ‘sys_recvfrom’: net/socket.c:1571: warning: ‘err’ may be used uninitialized in this function sock_from_file() either returns filp->private_data or it sets *err and returns NULL. Callers return "err" on NULL, but filp->private_data could be NULL. Some minor rearrangements of error handling in sys_sendto and sys_recvfrom solves the issue. Signed-off-by: David S. Miller commit 23bb80d2158cf4421fe239d788fd53cafb151050 Author: Eric Dumazet Date: Thu Feb 8 14:59:57 2007 -0800 [NET]: cleanup sock_from_file() I believe dead code from sock_from_file() can be cleaned up. All sockets are now built using sock_attach_fd(), that puts the 'sock' pointer into file->private_data and &socket_file_ops into file->f_op I could not find a place where file->private_data could be set to NULL, keeping opened the file. So to get 'sock' from a 'file' pointer, either : - This is a socket file (f_op == &socket_file_ops), and we can directly get 'sock' from private_data. - This is not a socket, we return -ENOTSOCK and dont even try to find a socket via dentry/inode :) Signed-off-by: Eric Dumazet Signed-off-by: David S. Miller commit dbca9b2750e3b1ee6f56a616160ccfc12e8b161f Author: Eric Dumazet Date: Thu Feb 8 14:16:46 2007 -0800 [NET]: change layout of ehash table ehash table layout is currently this one : First half of this table is used by sockets not in TIME_WAIT state Second half of it is used by sockets in TIME_WAIT state. This is non optimal because of for a given hash or socket, the two chain heads are located in separate cache lines. Moreover the locks of the second half are never used. If instead of this halving, we use two list heads in inet_ehash_bucket instead of only one, we probably can avoid one cache miss, and reduce ram usage, particularly if sizeof(rwlock_t) is big (various CONFIG_DEBUG_SPINLOCK, CONFIG_DEBUG_LOCK_ALLOC settings). So we still halves the table but we keep together related chains to speedup lookups and socket state change. In this patch I did not try to align struct inet_ehash_bucket, but a future patch could try to make this structure have a convenient size (a power of two or a multiple of L1_CACHE_SIZE). I guess rwlock will just vanish as soon as RCU is plugged into ehash :) , so maybe we dont need to scratch our heads to align the bucket... Note : In case struct inet_ehash_bucket is not a power of two, we could probably change alloc_large_system_hash() (in case it use __get_free_pages()) to free the unused space. It currently allocates a big zone, but the last quarter of it could be freed. Again, this should be a temporary 'problem'. Patch tested on ipv4 tcp only, but should be OK for IPV6 and DCCP. Signed-off-by: Eric Dumazet Signed-off-by: David S. Miller commit eac3731bd04c7131478722a3c148b78774553116 Author: Jennifer Hunt Date: Thu Feb 8 13:51:54 2007 -0800 [S390]: Add AF_IUCV socket support From: Jennifer Hunt This patch adds AF_IUCV socket support. Signed-off-by: Frank Pavlic Signed-off-by: Martin Schwidefsky Signed-off-by: David S. Miller commit 5da5e658debb7deddbfe5c133c76db3be0a3e12c Author: Martin Schwidefsky Date: Thu Feb 8 13:51:11 2007 -0800 [S390]: Adapt special message interface to new IUCV API Adapt special message interface to new IUCV API Signed-off-by: Frank Pavlic Signed-off-by: Martin Schwidefsky Signed-off-by: David S. Miller commit eebce38567373e3abbb640ab145d154831cc55df Author: Martin Schwidefsky Date: Thu Feb 8 13:50:33 2007 -0800 [S390]: Adapt netiucv driver to new IUCV API Adapt netiucv network device driver to new IUCV API Signed-off-by: Frank Pavlic Signed-off-by: Martin Schwidefsky Signed-off-by: David S. Miller commit c9101c5b3f1d018efa36d12cdcde89955642c73d Author: Martin Schwidefsky Date: Thu Feb 8 13:40:41 2007 -0800 [S390]: Adapt vmlogrdr driver to new IUCV API Adapt vmlogrdr character device driver to new IUCV API Signed-off-by: Frank Pavlic Signed-off-by: Martin Schwidefsky Signed-off-by: David S. Miller commit c667aac8009b41ecaecb1fc72476553cf12d4732 Author: Martin Schwidefsky Date: Thu Feb 8 13:38:11 2007 -0800 [S390]: Adapt monreader driver to new IUCV API Adapt monreader character device driver to new IUCV API Signed-off-by: Frank Pavlic Signed-off-by: Martin Schwidefsky Signed-off-by: David S. Miller commit 2356f4cb191100a5e92d537f13e5efdbc697e9cb Author: Martin Schwidefsky Date: Thu Feb 8 13:37:42 2007 -0800 [S390]: Rewrite of the IUCV base code, part 2 Add rewritten IUCV base code to net/iucv. Signed-off-by: Frank Pavlic Signed-off-by: Martin Schwidefsky Signed-off-by: David S. Miller commit 33a67fe898dbbe25589d2fca805cb68cfd7d311f Author: Martin Schwidefsky Date: Thu Feb 8 13:36:44 2007 -0800 [S390]: Rewrite of the IUCV base code, part 1 Remove the old IUCV code from drivers/s390/net Remove approprirate IUCV entries from drivers/s390/net/Makefile, drivers/s390/net/Kconfig and arch/s390/defconfig Signed-off-by: Frank Pavlic Signed-off-by: Martin Schwidefsky Signed-off-by: David S. Miller commit c9c2e9dcb82a8d7288c78e7d9a0cf315c456ac54 Author: Andrew Hendry Date: Thu Feb 8 13:35:18 2007 -0800 [X.25]: Adds /proc/net/x25/forward to view active forwarded calls. View the active forwarded calls cat /proc/net/x25/forward Signed-off-by: Andrew Hendry Signed-off-by: David S. Miller commit 39e21c0d34fe769d06839679fa920217359a58b0 Author: Andrew Hendry Date: Thu Feb 8 13:34:36 2007 -0800 [X.25]: Adds /proc/sys/net/x25/x25_forward to control forwarding. echo "1" > /proc/sys/net/x25/x25_forward To turn on x25_forwarding, defaults to off Requires the previous patch. Signed-off-by: Andrew Hendry Signed-off-by: David S. Miller commit 95a9dc4390c8215d922e0ca2ebb95279261fe795 Author: Andrew Hendry Date: Thu Feb 8 13:34:02 2007 -0800 [X.25]: Add call forwarding Adds call forwarding to X.25, allowing it to operate like an X.25 router. Useful if one needs to manipulate X.25 traffic with tools like tc. This is an update/cleanup based off a patch submitted by Daniel Ferenci a few years ago. Thanks Alan for the feedback. Added the null check to the clones. Moved the skb_clone's into the forwarding functions. Worked ok with Cisco XoT, linux X.25 back to back, and some old NTUs/PADs. Signed-off-by: Andrew Hendry Signed-off-by: David S. Miller commit e610e679dd0057403c96cd31f8739792780732ee Author: David S. Miller Date: Thu Feb 8 13:29:15 2007 -0800 [XFRM]: xfrm_migrate() needs exporting to modules. Needed by xfrm_user and af_key. Signed-off-by: David S. Miller commit f6ed0ec0eea644207fa146cb541b99f96a8942f0 Author: Shinta Sugimoto Date: Thu Feb 8 13:15:05 2007 -0800 [PFKEYV2]: CONFIG_NET_KEY_MIGRATE option Add CONFIG_NET_KEY_MIGRATE option which makes it possible for user application to send or receive MIGRATE message to/from PF_KEY socket. Signed-off-by: Shinta Sugimoto Signed-off-by: Masahide NAKAMURA Signed-off-by: YOSHIFUJI Hideaki Signed-off-by: David S. Miller commit 08de61beab8a21c8e0b3906a97defda5f1f66ece Author: Shinta Sugimoto Date: Thu Feb 8 13:14:33 2007 -0800 [PFKEYV2]: Extension for dynamic update of endpoint address(es) Extend PF_KEYv2 framework so that user application can take advantage of MIGRATE feature via PF_KEYv2 interface. User application can either send or receive an MIGRATE message to/from PF_KEY socket. Detail information can be found in the internet-draft . Signed-off-by: Shinta Sugimoto Signed-off-by: Masahide NAKAMURA Signed-off-by: YOSHIFUJI Hideaki Signed-off-by: David S. Miller commit d0473655c8293b49808c9488152573beab4458cf Author: Shinta Sugimoto Date: Thu Feb 8 13:13:07 2007 -0800 [XFRM]: CONFIG_XFRM_MIGRATE option Add CONFIG_XFRM_MIGRATE option which makes it possible for for user application to send or receive MIGRATE message to/from netlink socket. Signed-off-by: Shinta Sugimoto Signed-off-by: Masahide NAKAMURA Signed-off-by: YOSHIFUJI Hideaki Signed-off-by: David S. Miller commit 5c79de6e79cd8ecfbae28886be3ee49044f3a4d4 Author: Shinta Sugimoto Date: Thu Feb 8 13:12:32 2007 -0800 [XFRM]: User interface for handling XFRM_MSG_MIGRATE Add user interface for handling XFRM_MSG_MIGRATE. The message is issued by user application. When kernel receives the message, procedure of updating XFRM databases will take place. Signed-off-by: Shinta Sugimoto Signed-off-by: Masahide NAKAMURA Signed-off-by: YOSHIFUJI Hideaki Signed-off-by: David S. Miller commit 80c9abaabf4283f7cf4a0b3597cd302506635b7f Author: Shinta Sugimoto Date: Thu Feb 8 13:11:42 2007 -0800 [XFRM]: Extension for dynamic update of endpoint address(es) Extend the XFRM framework so that endpoint address(es) in the XFRM databases could be dynamically updated according to a request (MIGRATE message) from user application. Target XFRM policy is first identified by the selector in the MIGRATE message. Next, the endpoint addresses of the matching templates and XFRM states are updated according to the MIGRATE message. Signed-off-by: Shinta Sugimoto Signed-off-by: Masahide NAKAMURA Signed-off-by: YOSHIFUJI Hideaki Signed-off-by: David S. Miller commit 9934e81c8c4981342dab3e386aff5d4499bea0d2 Author: Patrick McHardy Date: Wed Feb 7 15:14:28 2007 -0800 [NETFILTER]: ip6_tables: remove redundant structure definitions Move ip6t_standard/ip6t_error_target/ip6t_error definitions to ip6_tables.h instead of defining them in each table individually. Signed-off-by: Patrick McHardy Signed-off-by: David S. Miller commit c3e79c05b45c3d6115d8c46e3012939c71573f13 Author: Patrick McHardy Date: Wed Feb 7 15:13:20 2007 -0800 [NETFILTER]: ip_tables: remove declaration of non-existant ipt_find_target function Signed-off-by: Patrick McHardy Signed-off-by: David S. Miller commit a0ca215a730b2c4d5024143e64b0d80d50858667 Author: Masahide NAKAMURA Date: Wed Feb 7 15:12:57 2007 -0800 [NETFILTER]: ip6_tables: support MH match This introduces match for Mobility Header (MH) described by Mobile IPv6 specification (RFC3775). User can specify the MH type or its range to be matched. Signed-off-by: Masahide NAKAMURA Signed-off-by: Yasuyuki Kozakai Signed-off-by: Patrick McHardy Signed-off-by: David S. Miller commit e60a13e030867078f3c9fef8dca6cd8a5b883478 Author: Jan Engelhardt Date: Wed Feb 7 15:12:33 2007 -0800 [NETFILTER]: {ip,ip6}_tables: use struct xt_table instead of redefined structure names Signed-off-by: Jan Engelhardt Signed-off-by: Patrick McHardy Signed-off-by: David S. Miller commit 6709dbbb1978abe039ea4b76c364bf003bf40de5 Author: Jan Engelhardt Date: Wed Feb 7 15:11:19 2007 -0800 [NETFILTER]: {ip,ip6}_tables: remove x_tables wrapper functions Use the x_tables functions directly to make it better visible which parts are shared between ip_tables and ip6_tables. Signed-off-by: Jan Engelhardt Signed-off-by: Patrick McHardy Signed-off-by: David S. Miller commit e1fd0586b04d624c597834320d9e57d6f2f4b878 Author: Jan Engelhardt Date: Wed Feb 7 15:10:34 2007 -0800 [NETFILTER]: x_tables: fix return values for LOG/ULOG Signed-off-by: Jan Engelhardt Signed-off-by: Patrick McHardy Signed-off-by: David S. Miller commit 41f4689a7c8cd76b77864461b3c58fde8f322b2c Author: Eric Leblond Date: Wed Feb 7 15:10:09 2007 -0800 [NETFILTER]: NAT: optional source port randomization support This patch adds support to NAT to randomize source ports. Signed-off-by: Eric Leblond Signed-off-by: Patrick McHardy Signed-off-by: David S. Miller commit cdd289a2f833b93e65b9a09a02c37f47a58140a8 Author: Patrick McHardy Date: Wed Feb 7 15:09:46 2007 -0800 [NETFILTER]: add IPv6-capable TCPMSS target Signed-off-by: Patrick McHardy Signed-off-by: David S. Miller commit a8d0f9526ff8510d6fa5e708ef5386af19503299 Author: Patrick McHardy Date: Wed Feb 7 15:07:43 2007 -0800 [NET]: Add UDPLITE support in a few missing spots Signed-off-by: Patrick McHardy Signed-off-by: David S. Miller commit 5eb87f456ebdc983164f0913b53c199ca9673887 Author: Patrick McHardy Date: Wed Feb 7 15:07:22 2007 -0800 [NETFILTER]: bridge-netfilter: use nf_register_hooks/nf_unregister_hooks Additionally mark the init function __init. Signed-off-by: Patrick McHardy Signed-off-by: David S. Miller commit efbc597634f239fa5ce84a131898341791fec1ec Author: Patrick McHardy Date: Wed Feb 7 15:07:08 2007 -0800 [NETFILTER]: nf_nat: remove broken HOOKNAME macro Signed-off-by: Patrick McHardy Signed-off-by: David S. Miller commit 2822b0d92675cd8d4fc73112334f4b113ba7c979 Author: Jan Engelhardt Date: Wed Feb 7 15:06:43 2007 -0800 [NETFILTER]: Remove useless comparisons before assignments Remove unnecessary if() constructs before assignment. Signed-off-by: Jan Engelhardt Signed-off-by: Patrick McHardy Signed-off-by: David S. Miller commit a09113c2c8ec59a5cc228efa5869aade2b8f13f7 Author: Patrick McHardy Date: Wed Feb 7 15:05:33 2007 -0800 [NETFILTER]: tcp conntrack: do liberal tracking for picked up connections Do liberal tracking (only RSTs need to be in-window) for connections picked up without seeing a SYN to deal with window scaling. Also change logging of invalid packets not to log packets accepted by liberal tracking to avoid spamming the logs. Based on suggestion from James Ralston Signed-off-by: Patrick McHardy Signed-off-by: David S. Miller commit 6fecd1985116fb08bdee3b9db6719e159fe5e43d Author: Michal Schmidt Date: Wed Feb 7 15:05:12 2007 -0800 [NETFILTER]: Add SANE connection tracking helper This is nf_conntrack_sane, a netfilter connection tracking helper module for the SANE protocol used by the 'saned' daemon to make scanners available via network. The SANE protocol uses separate control & data connections, similar to passive FTP. The helper module is needed to recognize the data connection as RELATED to the control one. Signed-off-by: Michal Schmidt Signed-off-by: Patrick McHardy Signed-off-by: David S. Miller commit 719647e2131585ea0a82b05d3745b36be32975d8 Author: Akinobu Mita Date: Wed Feb 7 00:12:13 2007 -0800 [IRLAN]: handle out of memory errors This patch checks return values: - irlmp_register_client() - irlmp_register_service() - irlan_open() Signed-off-by: Akinobu Mita Signed-off-by: Samuel Ortiz Signed-off-by: David S. Miller commit bb5aa42734e72b3f02fc0b3cdd6105083f9880f1 Author: Akinobu Mita Date: Wed Feb 7 00:11:11 2007 -0800 [IRDA]: handle out of memory errors This patch checks return value of memory allocation functions for irda subsystem and fixes memory leaks in error cases. Signed-off-by: Akinobu Mita Signed-off-by: Samuel Ortiz Signed-off-by: David S. Miller commit 22f8cde5bc336fd19603bb8c4572b33d14f14f87 Author: Stephen Hemminger Date: Wed Feb 7 00:09:58 2007 -0800 [NET]: unregister_netdevice as void There was no real useful information from the unregister_netdevice() return code, the only error occurred in a situation that was a driver bug. So change it to a void function. Signed-off-by: Stephen Hemminger Signed-off-by: David S. Miller commit f48d5ff1e44562a0ee87ce8ea3b798ce9d84370d Author: Masahide NAKAMURA Date: Wed Feb 7 00:07:39 2007 -0800 [IPV6] RAW: Add checksum default defines for MH. Add checksum default defines for mobility header(MH) which goes through raw socket. As the result kernel's behavior is to handle MH checksum as default. This patch also removes verifying inbound MH checksum at mip6_mh_filter() since it did not consider user specified checksum offset and was redundant check with raw socket code. Signed-off-by: Masahide NAKAMURA Signed-off-by: YOSHIFUJI Hideaki Signed-off-by: David S. Miller commit cc63f70b8b410eb653449151821f6b8b9af6ca42 Author: Alexey Dobriyan Date: Tue Feb 6 14:35:25 2007 -0800 [IPV4/IPV6] multicast: Check add_grhead() return value add_grhead() allocates memory with GFP_ATOMIC and in at least two places skb from it passed to skb_put() without checking. Signed-off-by: Alexey Dobriyan Signed-off-by: David S. Miller commit f2f2102d1a1dbc83b5b37b6596cd8374120cbe16 Author: David S. Miller Date: Tue Feb 6 14:32:42 2007 -0800 [XFRM]: Fix missed error setting in xfrm4_policy.c When we can't find the afinfo we should return EAFNOSUPPORT. GCC warned about the uninitialized 'err' for this path as well. Signed-off-by: David S. Miller commit 4337226228e1cfc1d70ee975789c6bd070fb597c Author: Miika Komu Date: Tue Feb 6 14:27:32 2007 -0800 [IPSEC]: IPv4 over IPv6 IPsec tunnel This is the patch to support IPv4 over IPv6 IPsec. Signed-off-by: Miika Komu Signed-off-by: Diego Beltrami Signed-off-by: Kazunori Miyazawa Signed-off-by: David S. Miller commit c82f963efe823d3cacaf1f1b7f1a35cc9628b188 Author: Miika Komu Date: Tue Feb 6 14:27:02 2007 -0800 [IPSEC]: IPv6 over IPv4 IPsec tunnel This is the patch to support IPv6 over IPv4 IPsec Signed-off-by: Miika Komu Signed-off-by: Diego Beltrami Signed-off-by: Kazunori Miyazawa Signed-off-by: David S. Miller commit cdca72652adf597f7fef821a27595fd0dd5eea19 Author: Miika Komu Date: Tue Feb 6 14:24:56 2007 -0800 [IPSEC]: exporting xfrm_state_afinfo This patch exports xfrm_state_afinfo. Signed-off-by: Miika Komu Signed-off-by: Diego Beltrami Signed-off-by: Kazunori Miyazawa Signed-off-by: David S. Miller commit 243cb4e56061c3f4cb76312c5527840344d57c3b Author: Joe Jin Date: Tue Feb 6 14:16:40 2007 -0800 [BONDING]: Replace kmalloc() + memset() pairs with the appropriate kzalloc() calls Replace kmalloc() + memset() pairs with the appropriate kzalloc() calls in the bonding driver. Signed-off-by: Joe Jin Signed-off-by: Andrew Morton commit 6b31a515e3401685cdab2eeb6692f1a0f53f72ca Author: Eric Dumazet Date: Tue Feb 6 13:29:21 2007 -0800 [TG3]: Avoid an expensive divide. During an oprofile session of linux-2.6.20 on a dual opteron system, I noticed an expensive divide was done in tg3_poll(). I am using gcc-4.1.1, so the following comment from drivers/net/tg3.c seems over-optimistic : /* Do not place this n-ring entries value into the tp struct itself, * we really want to expose these constants to GCC so that modulo et * al. operations are done with shifts and masks instead of with * hw multiply/modulo instructions. Another solution would be to * replace things like '% foo' with '& (foo - 1)'. */ #define TG3_RX_RCB_RING_SIZE(tp) \ ((tp->tg3_flags2 & TG3_FLG2_5705_PLUS) ? 512 : 1024) Assembly code before patch : (oprofile results included) 6434 0.0088 :ffffffff803684b9: mov 0x6f0(%r15),%eax 587 8.0e-04 :ffffffff803684c0: and $0x40000,%eax 2170 0.0030 :ffffffff803684c5: cmp $0x1,%eax :ffffffff803684c8: lea 0x1(%r13),%eax :ffffffff803684cc: sbb %ecx,%ecx 2051 0.0028 :ffffffff803684ce: xor %edx,%edx :ffffffff803684d0: and $0x200,%ecx 20 2.7e-05 :ffffffff803684d6: add $0x200,%ecx 1986 0.0027 :ffffffff803684dc: div %ecx 103427 0.1410 :ffffffff803684de: cmp %edx,0xffffffffffffff7c(%rbp) Assembly code after the suggested patch : ffffffff803684b9: mov 0x6f0(%r15),%eax ffffffff803684c0: and $0x40000,%eax ffffffff803684c5: cmp $0x1,%eax ffffffff803684c8: sbb %eax,%eax ffffffff803684ca: inc %r13d ffffffff803684cd: and $0x200,%eax ffffffff803684d2: add $0x1ff,%eax ffffffff803684d7: and %eax,%r13d ffffffff803684da: cmp %r13d,0xffffffffffffff7c(%rbp) Signed-off-by: Eric Dumazet Acked-by: Michael Chan Signed-off-by: David S. Miller commit 0f08461ebf89e10f7db9042fb028359b810c3c81 Author: Andrew Morton Date: Mon Feb 5 18:18:21 2007 -0800 [DCCP]: Warning fixes. net/dccp/ccids/ccid3.c: In function `ccid3_hc_rx_packet_recv': net/dccp/ccids/ccid3.c:1007: warning: long int format, different type arg (arg 3) net/dccp/ccids/ccid3.c:1007: warning: long int format, different type arg (arg 4) opaque types must be suitably cast for printing. Signed-off-by: Andrew Morton Signed-off-by: David S. Miller commit 919afbd68863550665b328a78107bc2919c5e3f4 Author: Joe Jin Date: Mon Feb 5 18:08:47 2007 -0800 [NET] slip: Replace kmalloc() + memset() pairs with the appropriate kzalloc() calls This patch replace kmalloc() + memset() pairs with the appropriate kzalloc(). Signed-off-by: Joe Jin Signed-off-by: Andrew Morton Signed-off-by: David S. Miller commit 97353cb4c05c2edf260e9d1b19a29d3cc0060a09 Author: Adrian Bunk Date: Mon Feb 5 18:07:27 2007 -0800 [NET] net/wanrouter/wanmain.c: cleanups This patch contains the following cleanups: - make the following needlessly global functions static: - lock_adapter_irq() - unlock_adapter_irq() - #if 0 the following unused global functions: - wanrouter_encapsulate() - wanrouter_type_trans() Signed-off-by: Adrian Bunk Signed-off-by: Andrew Morton Signed-off-by: David S. Miller commit 84ff602efba2664762070add0600aa5c870a2659 Author: Daniel Walker Date: Mon Feb 5 18:04:06 2007 -0800 [ATM]: Fix for crash in adummy_init() This was reported by Ingo Molnar here, http://lkml.org/lkml/2006/12/18/119 The problem is that adummy_init() depends on atm_init() , but adummy_init() is called first. So I put atm_init() into subsys_initcall which seems appropriate, and it will still get module_init() if it becomes a module. Interesting to note that you could crash your system here if you just load the modules in the wrong order. Signed-off-by: Daniel Walker Signed-off-by: Andrew Morton Signed-off-by: David S. Miller commit f5a6e01c093ca60c0cab15c47c8e7e199fbbc9e6 Author: Arjan van de Ven Date: Mon Feb 5 17:59:51 2007 -0800 [NET]: user of the jiffies rounding code: Networking This patch introduces users of the round_jiffies() function in the networking code. These timers all were of the "about once a second" or "about once every X seconds" variety and several showed up in the "what wakes the cpu up" profiles that the tickless patches provide. Some timers are highly dynamic based on network load; but even on low activity systems they still show up so the rounding is done only in cases of low activity, allowing higher frequency timers in the high activity case. The various hardware watchdogs are an obvious case; they run every 2 seconds but aren't otherwise specific of exactly when they need to run. Signed-off-by: Arjan van de Ven Signed-off-by: Andrew Morton Signed-off-by: David S. Miller commit 104439a8876a98eac1b6593907a3c7bc51e362fe Author: John Heffner Date: Mon Feb 5 17:53:11 2007 -0800 [TCP]: Don't apply FIN exception to full TSO segments. Signed-off-by: John Heffner Signed-off-by: David S. Miller commit 8a3c3a972741dec77220a19642bd3331551ad2d9 Author: Baruch Even Date: Sun Feb 4 23:37:41 2007 -0800 [TCP]: Check num sacks in SACK fast path We clear the unused parts of the SACK cache, This prevents us from mistakenly taking the cache data if the old data in the SACK cache is the same as the data in the SACK block. This assumes that we never receive an empty SACK block with start and end both at zero. Signed-off-by: Baruch Even Signed-off-by: David S. Miller commit 6f74651ae626ec672028587bc700538076dfbefb Author: Baruch Even Date: Sun Feb 4 23:36:42 2007 -0800 [TCP]: Seperate DSACK from SACK fast path Move DSACK code outside the SACK fast-path checking code. If the DSACK determined that the information was too old we stayed with a partial cache copied. Most likely this matters very little since the next packet will not be DSACK and we will find it in the cache. but it's still not good form and there is little reason to couple the two checks. Since the SACK receive cache doesn't need the data to be in host order we also remove the ntohl in the checking loop. Signed-off-by: Baruch Even Signed-off-by: David S. Miller commit fda03fbb56bf88f1fb1c57b2474082e5addaa884 Author: Baruch Even Date: Sun Feb 4 23:35:57 2007 -0800 [TCP]: Advance fast path pointer for first block only Only advance the SACK fast-path pointer for the first block, the fast-path assumes that only the first block advances next time so we should not move the cached skb for the next sack blocks. Signed-off-by: Baruch Even Signed-off-by: David S. Miller commit ffbc61117d32dc4e768f999325ecfb2528d6b303 Author: Herbert Xu Date: Sun Feb 4 23:33:10 2007 -0800 [PACKET]: Fix skb->cb clobbering between aux and sockaddr Both aux data and sockaddr tries to use the same buffer which obviously doesn't work. We just happen to have 4 bytes free in the skb->cb if you take away the maximum length of sockaddr_ll. That's just enough to store the one piece of info from aux data that we can't generate at recvmsg(2) time. This is what the following patch does. Signed-off-by: Herbert Xu Signed-off-by: David S. Miller commit 8dc4194474159660d7f37c495e3fc3f10d0db8cc Author: Herbert Xu Date: Sun Feb 4 23:31:32 2007 -0800 [PACKET]: Add optional checksum computation for recvmsg This patch is needed to make ISC's DHCP server (and probably other DHCP servers/clients using AF_PACKET) to be able to serve another client on the same Xen host. The problem is that packets between different domains on the same Xen host only have partial checksums. Unfortunately this piece of information is not passed along in AF_PACKET unless you're using the mmap interface. Since dhcpd doesn't support packet-mmap, UDP packets from the same host come out with apparently bogus checksums. This patch adds a mechanism for AF_PACKET recvmsg(2) to return the status along with the packet. It does so by adding a new cmsg that contains this information along with some other relevant data such as the original packet length. I didn't include the time stamp information since there is already a cmsg for that. This patch also changes the mmap code to set the CSUMNOTREADY flag on all packets instead of just outoing packets on cooked sockets. Signed-off-by: Herbert Xu Signed-off-by: David S. Miller commit 8eb9086f21c73b38b5ca27558db4c91d62d0e70b Author: David S. Miller Date: Thu Feb 8 02:09:21 2007 -0800 [IPV4/IPV6]: Always wait for IPSEC SA resolution in socket contexts. Do this even for non-blocking sockets. This avoids the silly -EAGAIN that applications can see now, even for non-blocking sockets in some cases (f.e. connect()). With help from Venkat Tekkirala. Signed-off-by: David S. Miller commit ba7808eac17360dda459f82222859b0e3879854b Author: Frederik Deweerdt Date: Sun Feb 4 20:15:27 2007 -0800 [TCP]: remove tcp header from tcp_v4_check (take #2) The tcphdr struct passed to tcp_v4_check is not used, the following patch removes it from the parameter list. This adds the netfilter modifications missing in the patch I sent for rc3-mm1. Signed-off-by: Frederik Deweerdt Signed-off-by: David S. Miller commit a0d78ebf3a0e33a1aeacf2fc518ad9273d6a1c2f Author: YOSHIFUJI Hideaki Date: Sun Feb 4 20:15:04 2007 -0800 [IPV6] ROUTE: Do not route packets to link-local address on other device. With help from Wei Dong . Signed-off-by: YOSHIFUJI Hideaki Signed-off-by: David S. Miller commit 26932566a42d46aee7e5d526cb34fba9380cad10 Author: Patrick McHardy Date: Wed Jan 31 23:16:40 2007 -0800 [NETLINK]: Don't BUG on undersized allocations Currently netlink users BUG when the allocated skb for an event notification is undersized. While this is certainly a kernel bug, its not critical and crashing the kernel is too drastic, especially when considering that these errors have appeared multiple times in the past and it BUGs even if no listeners are present. This patch replaces BUG by WARN_ON and changes the notification functions to inform potential listeners of undersized allocations using a unique error code (EMSGSIZE). Signed-off-by: Patrick McHardy Signed-off-by: David S. Miller commit 2cf6c36cb46d69057db2ebae0d8ec352e065f48b Author: Jarek Poplawski Date: Wed Jan 31 12:21:24 2007 -0800 [NET_SCHED] sch_prio: class statistics printing enabled This patch adds a dump_stats callback to enable printing of basic statistics of prio classes. (With help of Patrick McHardy). Signed-off-by: Jarek Poplawski Acked-by: Patrick McHardy Signed-off-by: David S. Miller commit 91efa462054d44ae52b0c6c8325ed5e899f2cd17 Author: Stefan Richter Date: Tue Feb 6 02:34:45 2007 +0100 ieee1394: fix host device registering when nodemgr disabled Since my commit 8252bbb1363b7fe963a3eb6f8a36da619a6f5a65 in 2.6.20-rc1, host devices have a dummy driver attached. Alas the driver was not registered before use if ieee1394 was loaded with disable_nodemgr=1. This resulted in non-functional FireWire drivers or kernel lockup. http://bugzilla.kernel.org/show_bug.cgi?id=7942 Signed-off-by: Stefan Richter commit a5782010b4e75cba571357efaa27df22a89427c2 Author: David Moore Date: Sat Feb 3 03:09:09 2007 -0500 ieee1394: video1394: DMA fix This together with the phys_to_virt fix in lib/swiotlb.c::swiotlb_sync_sg fixes video1394 DMA on machines with DMA bounce buffers, especially Intel x86-64 machines with > 3GB RAM. Signed-off-by: Stefan Richter Signed-off-by: David Moore Tested-by: Nicolas Turro commit 0fe4c6fcacb28bda75b31f63d3629f640a6b9bf9 Author: Stefan Richter Date: Sat Feb 3 16:48:51 2007 +0100 ieee1394: raw1394: prevent unloading of low-level driver Unloading the low-level driver module of a FireWire host can lead to all sorts of trouble if a raw1394 userspace client is using the host. Just disallow it by incrementing the LLD's module reference count on a RAW1394_REQ_SET_CARD write operation. Decrement it when the file is closed. This feature wouldn't be relevant if "modprobe -r video1394" or "modprobe -r dv1394" didn't automatically unload ohci1394 too. http://bugzilla.kernel.org/show_bug.cgi?id=7701 Signed-off-by: Stefan Richter Signed-off-by: Dan Dennedy commit 12ba145c9406da72c8288245f352de7f37188f1f Author: Stefan Richter Date: Sat Jan 27 13:54:23 2007 +0100 ieee1394: dv1394: tidy up card removal small coding style touch-up and terser coding Signed-off-by: Stefan Richter commit 88e7bf2a4c35d1200c2f72f5cd3d9e72c7f6c890 Author: Stefan Richter Date: Sat Jan 27 13:52:52 2007 +0100 ieee1394: dv1394: fix CardBus card ejection Fix NULL pointer dereference on hot ejection of a FireWire card while dv1394 was loaded. http://bugzilla.kernel.org/show_bug.cgi?id=7121 I did not test card ejection with open /dev/dv1394 files yet. Signed-off-by: Stefan Richter commit beb2fdcad14af14fa38d5098003bd0f53e1c1185 Author: Stefan Richter Date: Thu Jan 25 22:35:47 2007 +0100 ieee1394: sbp2: lower block queue alignment requirement The old setting is copy & waste from usb-storage and doesn't apply to sbp2. There is only 4-byte alignment required for everything, except for S/G table elements which have to be 8-byte aligned according to the SBP-2 spec. (They happen to be ____cacheline_aligned in our implementation. Whether that's good is another question.) We now simply don't tune block queue alignment at all. The default alignment would surely never become anything else than a multiple of 4, else tons of calls to blk_queue_dma_alignment would have to be added everywhere in drivers/... Signed-off-by: Stefan Richter commit 9c31b387234287917023e64d1f11aedfd2685dd9 Author: Stefan Richter Date: Sun Jan 14 19:40:41 2007 +0100 ieee1394: sbp2: remove bogus "emulated" host flag There is no emulation going on here. Signed-off-by: Stefan Richter commit d06170a9ba9c39ac0768676e268cb17f9f68a622 Author: Stefan Richter Date: Sun Jan 7 21:51:48 2007 +0100 ieee1394: save one word in struct hpsb_host hpsb_host.config_roms is a bitfield of which only one bit is currently used. hpsb_host.update_config_rom is only a Boolean. Neither one is accessed in hot code paths or with alignment requirements. Signed-off-by: Stefan Richter commit 3360177c62e86f476c4f1a057e13163383652f7b Author: Stefan Richter Date: Sun Jan 7 21:49:27 2007 +0100 ieee1394: restore config ROM when resuming After PM suspend + resume, the local configuration ROM was not restored. This prevented remote nodes from recognizing the resuming machine. Signed-off-by: Stefan Richter commit 083922fe1c277603a03f0ca700fe5a76f11178c7 Author: Stefan Richter Date: Sat Jan 6 15:07:05 2007 +0100 ieee1394: ohci1394: drop pcmcia-cs compatibility code #ifdef PCMCIA is only true if compiled inside pcmcia-cs, isn't it? Signed-off-by: Stefan Richter commit b2051f887351864d862160e75bc24362c7af8914 Author: Stefan Richter Date: Wed Jan 3 19:32:13 2007 +0100 ieee1394: nodemgr: check info_length in ROM header earlier The whole ROM area which is covered by the crc_length field of the ROM header was fetched before the info_length field was checked for correct general ROM format. This might be wasteful or even dangerous with nodes with minimal ROM, nonstandard ROM, or corrupt ROM. Perform this check at the earliest opportunity. Signed-off-by: Stefan Richter commit e658bc556b3b2e699c5d9ba65fcc955f35105f42 Author: Adrian Bunk Date: Tue Jan 2 22:56:53 2007 +0100 the scheduled IEEE1394_OUI_DB removal This patch contains the scheduled IEEE1394_OUI_DB removal. Signed-off-by: Adrian Bunk Update: Also remove drivers/ieee1394/.gitignore. Remove now unused struct members in drivers/ieee1394/nodemgr.h. Signed-off-by: Stefan Richter commit d395a1774f34600d72f7d3796716f350ef29584b Author: Adrian Bunk Date: Tue Jan 2 22:56:57 2007 +0100 the scheduled IEEE1394_EXPORT_FULL_API removal This patch contains the scheduled IEEE1394_EXPORT_FULL_API removal. Signed-off-by: Adrian Bunk Update: Pull proper portion of feature-removal-schedule.txt. Signed-off-by: Stefan Richter commit 4618fd300187132d12c06c64366729dd7a5280f2 Author: Stefan Richter Date: Sat Dec 30 15:37:09 2006 +0100 ieee1394: sbp2: use a better wildcard for blacklist 0x000000 could be a valid value to match against, but anything bigger than 0xffffff cannot. Signed-off-by: Stefan Richter commit dcb71129841e5821c0cbbdd4017a6f202f180108 Author: Kristian Høgsberg Date: Sun Dec 17 14:34:09 2006 -0500 Add PCI class ID for firewire OHCI controllers. Pull this define out of drivers/ieee1394/ohci1394.c and rename to match other PCI class defines. Signed-off-by: Stefan Richter commit 0749aaab4975d741e124c139d40f00853a451f7f Author: Andrea Guzzo Date: Fri Dec 8 00:53:24 2006 +0100 ieee1394: modified csr1212_key_id_type_map to support lisight This patch applies a little change in csr1212.c to fix iSight (firewire digital camera) related issues (but maybe other firewire devices could also need such modification) The actual implementation of the "csr1212_key_id_type_map" table doesn't support some node types used by the iSight for the audio unit. This limit makes the csr scanning routine to never see the audio unit node , and consequently the iSight driver probe() routine to be never called and there is no way to hook an isight device when it is inserted. Signed-off-by: Andrea Guzzo Signed-off-by: Stefan Richter commit 7ba526316ae122e60c0c7a40793491f71b9ec590 Author: Steve French Date: Thu Feb 8 18:14:13 2007 +0000 [CIFS] Allow update of EOF on remote extend of file Signed-off-by: Steve French commit 595dcfecf642c8b0772989ed46f15ee03c25a205 Author: Steve French Date: Thu Feb 8 18:11:42 2007 +0000 [CIFS] POSIX CIFS Extensions (continued) - POSIX Open Signed-off-by: Steve French commit b892afd1e60132a981b963929e352eabf3306ba2 Author: Linus Torvalds Date: Thu Feb 8 08:16:44 2007 -0800 kbuild: fix space for good (take 103) Michal Ostrowski points out what the real problem was: the spaces at the start of the definition of the 'checker-shell' make function. Cc: Michal Ostrowski Acked-by: David Miller Acked-by: Geert Uytterhoeven Acked-by: Oleg Verych Signed-off-by: Linus Torvalds commit f3cc28c797604fa1cda4aef3f250f465de54a0ca Author: Jay Cliburn Date: Thu Feb 8 10:42:37 2007 -0500 Add Attansic L1 ethernet driver. This driver is a modified version of the Attansic reference driver for the L1 ethernet adapter. Attansic has granted permission for its inclusion in the mainline kernel. Signed-off-by: Jeff Garzik commit 97c5a20ae68774b4c9246c4657be0d88317f103f Author: Li Yang Date: Wed Feb 7 13:49:24 2007 +0800 [POWERPC] 83xx: Add platform_device for USB DR peripheral driver Add platform_device setup code for OTG/peripheral mode of 834x DR module. It is needed for USB client driver to work. Signed-off-by: Li Yang Signed-off-by: Kumar Gala commit c161698287f501e7ea229672383af7aefe8a2056 Author: Li Yang Date: Wed Feb 7 13:47:56 2007 +0800 [POWERPC] 83xx: Add USB setup code for MPC8349E MDS-PB Add board specific initialization code for USB to work in both MPH and DR mode for MPC8349E MDS-PB board. Signed-off-by: Li Yang Signed-off-by: Kumar Gala commit ea5b7a61b606854bd17272cb0a751b6d0a8bfa6b Author: Li Yang Date: Wed Feb 7 13:51:09 2007 +0800 [POWERPC] 83xx: Added new dr_mode property for usb controller on 83xx Added a new dr_mode property to describe what mode the DR controller is being used in (host, device, OTG). Updated the MPC8349E MDS dts with this new property. Signed-off-by: Li Yang Signed-off-by: Kumar Gala commit fd9aeb85273e9eb4d1a0b83487576a2e22da67fc Author: Kim Phillips Date: Wed Feb 7 22:19:45 2007 -0600 [POWERPC] 83xx: add the mpc8313erdb defconfig Add the mpc8313erdb defconfig Signed-off-by: Wilson Lo Signed-off-by: Scott Wood Signed-off-by: Kim Phillips Signed-off-by: Kumar Gala commit b359049f270dcaab8a5bbdbb966594c16caba16c Author: Kim Phillips Date: Wed Feb 7 22:19:12 2007 -0600 [POWERPC] 83xx: Add base support for the MPC8313E RDB Add support for the MPC8313E Reference Development Board (RDB). The board is a mini-ITX reference board with 128M DDR2, 8M flash, 32M NAND, USB, PCI, gigabit ethernet, and serial. Signed-off-by: Wilson Lo Signed-off-by: Scott Wood Signed-off-by: Kim Phillips Signed-off-by: Kumar Gala commit 07b2463046247ce580ff9b37e91394f2f6424768 Author: Greg Kroah-Hartman Date: Wed Feb 7 21:34:08 2007 -0800 Revert "Driver core: convert SPI code to use struct device" This reverts commit 2943ecf2ed32632473c06f1975db47a7aa98c10f. This should go through the SPI maintainer, it was my fault that it did not. Especially as it conflicts with other patches he has pending. Signed-off-by: Greg Kroah-Hartman commit 1545085a28f226b59c243f88b82ea25393b0d63f Author: Thomas Hellstrom Date: Thu Feb 8 16:14:05 2007 +1100 drm: Allow for 44 bit user-tokens (or drm_file offsets) commit d003e7a1a569501cbe9a5ca14748177498c4893a Author: Mathieu Desnoyers Date: Wed Feb 7 19:04:44 2007 -0500 [POWERPC] Add export of vgacon_remap_base The following macro : include/asm-powerpc/vga.h:#define VGA_MAP_MEM(x,s) (x + vgacon_remap_base) is used by drivers/video/console/vgacon.c which can be compiled as a module (drivers/video/vga16fb.ko). Therefore, vgacon_remap_base should be exported. Signed-off-by: Mathieu Desnoyers Signed-off-by: Paul Mackerras commit bcff4948c64e1af09e9a986e324626ee873d3a07 Author: Johannes Berg Date: Wed Feb 7 13:45:45 2007 +0100 [POWERPC] Remove bogus comment about page_is_ram arch/powerpc/mm/mem.c states that page_is_ram is called by the code that implements /dev/mem, which isn't true. Remove the comment. Signed-off-by: Johannes Berg Cc: Paul Mackerras Signed-off-by: Paul Mackerras commit 1ed2ddf380e19dafeec2150ca709ef7f4a67cd21 Author: Johannes Berg Date: Mon Feb 5 19:30:29 2007 +0100 [POWERPC] windfarm: don't die on suspend thread signal When the windfarm thread gets a suspend signal it will die instead of freezing. This fixes it. Signed-off-by: Johannes Berg Acked-by: Benjamin Herrenschmidt Signed-off-by: Paul Mackerras commit 92d4dda3332577bc2228b8d436f3d2796c59a520 Author: Johannes Berg Date: Wed Dec 13 13:38:22 2006 +0100 [POWERPC] Fix comment in kernel/irq.c kernel/irq.c contains a comment that speaks of -1 and -2 as interrupt numbers, but this is actually dependent on configuration options now. Replace by NO_IRQ and NO_IRQ_ENABLED. Signed-off-by: Johannes Berg Cc: Benjamin Herrenschmidt Signed-off-by: Paul Mackerras commit f31909c00332b3e8299209eaba6cec80756f802c Author: Stefan Roese Date: Wed Feb 7 09:45:55 2007 +0100 [POWERPC] ppc: Fix booke watchdog initialization Fix two problems in the book-e watchdog driver. a) The 4xx default period was defined wrong b) Clear status before enabling the watchdog exception Signed-off-by: Stefan Roese Signed-off-by: Paul Mackerras commit 2366fb16abcd8dea96820d3cb4f1de3a868d268c Author: Ahmed S. Darwish Date: Mon Feb 5 16:14:10 2007 -0800 [POWERPC] PPC: Use ARRAY_SIZE macro when appropriate Use ARRAY_SIZE macro already defined in linux/kernel.h Signed-off-by: Ahmed S. Darwish Cc: Benjamin Herrenschmidt Acked-by: Kumar Gala Signed-off-by: Andrew Morton Signed-off-by: Paul Mackerras commit 3839a5943977674d224cca541fd0914b942aa466 Author: Ahmed S. Darwish Date: Mon Feb 5 16:14:09 2007 -0800 [POWERPC] Use ARRAY_SIZE macro when appropriate Use ARRAY_SIZE macro already defined in linux/kernel.h Signed-off-by: Ahmed S. Darwish Cc: Benjamin Herrenschmidt Signed-off-by: Andrew Morton Signed-off-by: Paul Mackerras commit 0524aad7b89671bc788d483b2c048ac7b79eefb9 Author: Stephen Rothwell Date: Mon Feb 5 16:14:05 2007 -0800 [POWERPC] Fix ppc64's writing to struct file_operations In preparation for marking file_operations as const. Cc: Benjamin Herrenschmidt Acked-by: Arjan van de Ven Signed-off-by: Stephen Rothwell Signed-off-by: Andrew Morton Signed-off-by: Paul Mackerras commit f8b93a902315aeeedf51c45f01a407d5d8288c72 Author: Robert P. J. Day Date: Mon Feb 5 16:14:04 2007 -0800 [POWERPC] ppc: use syslog macro for the printk log level Use the appropriate logging macro for the priority level for that printk call. Signed-off-by: Robert P. J. Day Signed-off-by: Andrew Morton Signed-off-by: Paul Mackerras commit 64a3de1c3d9c6dfa9be68529a519448e8017ddb0 Author: Mariusz Kozlowski Date: Mon Feb 5 16:14:03 2007 -0800 [POWERPC] ppc: cs4218_tdm remove extra brace Signed-off-by: Mariusz Kozlowski Signed-off-by: Andrew Morton Signed-off-by: Paul Mackerras commit f42963f8646540ac7e5ba016a0ec1cc2e7386b57 Author: Grant Likely Date: Tue Dec 12 15:13:19 2006 -0700 [POWERPC] Add mpc52xx/lite5200 PCI support Signed-off-by: Grant Likely Acked-by: Sylvain Munaut Signed-off-by: Paul Mackerras commit c4184f117af7441fb83bc413d2214d92920e0289 Author: Linus Torvalds Date: Wed Feb 7 20:24:25 2007 -0800 kbuild: make $(checker-shell ) strip spaces around the result It looks like GNU make version 3.80 (but apparently not 3.81) adds leading whitespace to the result of the checker-shell execution. This strips them off explicitly. Also, don't bother symlinking the output file to /dev/null. It's likely as expensive as just writing the temp-file, and we need to remove it anyway afterwards. Signed-off-by: Linus Torvalds commit 12e86f92fcfe4f0bcab0ad7fa4088a64c60d9b38 Author: Paul Mackerras Date: Thu Feb 8 15:02:35 2007 +1100 [POWERPC] Only use H_BULK_REMOVE if the firmware supports it The previous patch changing pSeries to use H_BULK_REMOVE broke the JS20 blade, where the firmware doesn't support H_BULK_REMOVE. This adds a firmware check so that on machines that don't have H_BULK_REMOVE, we just use the H_REMOVE call as before. Signed-off-by: Paul Mackerras commit 756db73df7b7d6b9f6421c1fb2e1cabeaede5846 Author: Thomas Hellstrom Date: Thu Feb 8 12:57:40 2007 +1100 drm/via: Disable AGP DMA for chips with the new 3D engine. commit 1d58420bad15d08f93bf1e0342c1b1d1234d69b7 Author: Thomas Hellstrom Date: Mon Jan 8 22:25:47 2007 +1100 drm: update core memory manager from git drm tree Remove the memory manager parameter from the put_block function, as this makes the client code a lot cleaner. Prepare buffer manager for lock and unlock calls. Fix buggy aligned allocations. Remove the stupid root_node field from the core memory manager. Support multi-page buffer offset alignments Add improved alignment functionality to the core memory manager. This makes an allocated block actually align itself and returns any wasted space to the manager. Signed-off-by: Dave Airlie commit 004a7727421fd202bbdfcc0231a3359085199a52 Author: Christoph Hellwig Date: Mon Jan 8 21:56:59 2007 +1100 drm: remove drm_ioremap and drm_ioremapfree hch originally submitted this for paravirt ops work, airlied took it and cleaned up a lot of unused code caused by using this. Signed-off-by: Christoph Hellwig Signed-off-by: Dave Airlie commit b9094d3aaa9550e740b6fd12b68f485d9979ce27 Author: Dave Airlie Date: Mon Jan 8 21:31:13 2007 +1100 i810/i830: use drm_core_ioremap instead of drm_ioremap This makes the i810/i830 use the drm_core_ioremap functions. Signed-off-by: Dave Airlie commit f239b7b0cac0682d582949087710a9663b1300d5 Author: Thomas Hellstrom Date: Mon Jan 8 21:22:50 2007 +1100 drm: use vmalloc_user instead of vmalloc_32 for DRM_SHM Signed-off-by: Dave Airlie commit 9b8d9d0e0181286c0608e6426da1eac45463ecd2 Author: Thomas Hellstrom Date: Mon Jan 8 21:21:41 2007 +1100 via: allow for npot texture pitch alignment Signed-off-by: Dave Airlie commit 689692e73ea4b95c9fa5d5913eade33147db2e5a Author: Thomas Hellstrom Date: Mon Jan 8 21:19:57 2007 +1100 via: add some new chipsets Disable 3D functionality and AGP DMA for chipsets with the DX9 3D engine. Signed-off-by: Dave Airlie commit 76f625511e61f9d5561885c77d2ff1436ed83797 Author: Thomas Hellstrom Date: Mon Jan 8 21:03:23 2007 +1100 via: some PCI posting flushes Signed-off-by: Dave Airlie commit 14719f325e1cd4ff757587e9a221ebaf394563ee Author: Greg Kroah-Hartman Date: Wed Feb 7 16:17:27 2007 -0800 Revert "PCI: remove duplicate device id from ata_piix" This reverts commit b11056355ea149c37edf0ef54976a49f5258cd54. It was incorrect, the proper fix is coming through the SATA tree, sorry about that. Signed-off-by: Greg Kroah-Hartman commit ac38dfc39e7684f55174742e5f0d6c5a0093bbf6 Author: Stephen Hemminger Date: Wed Feb 7 09:18:30 2007 -0800 sk98lin: planned removal Document planned removal of sk98lin driver. Signed-off-by: Stephen Hemminger Signed-off-by: Jeff Garzik commit 0cc8674f2be3078fb586add1900c7835c977f384 Author: Andrew Victor Date: Wed Feb 7 16:40:44 2007 +0100 AT91: MACB support The Atmel MACB Ethernet peripheral is also integrated in the AT91SAM9260 and AT91SAM9263 processors. The differences from the AVR32 version are: * Single peripheral clock. * MII/RMII selection bit is inverted. * Clock enable bit. Original patch from Patrice Vilchez. Signed-off-by: Andrew Victor Signed-off-by: Haavard Skinnemoen Signed-off-by: Jeff Garzik commit 683349a3fae4896d91b1fe507ebbadb866587cd8 Author: Stephen Hemminger Date: Tue Feb 6 10:45:45 2007 -0800 sky2: version 1.12 Updated version for WOL and new id's Signed-off-by: Stephen Hemminger Signed-off-by: Jeff Garzik commit f1a0b6f56e0126b82d7b9c2afa86613af8ee3146 Author: Stephen Hemminger Date: Tue Feb 6 10:45:44 2007 -0800 sky2: add new chip ids More new chip id's from vendor driver version 10.0.4.3 Signed-off-by: Stephen Hemminger Signed-off-by: Jeff Garzik commit 9374549428820be10f01e217cec1b34cb3e3de6d Author: Stephen Hemminger Date: Tue Feb 6 10:45:43 2007 -0800 sky2: Yukon Extreme support This is basic support for the new Yukon Extreme chip, extracted from the new vendor driver 10.0.4.3. Since this is untested hardware, it has a big fat warning for now. Signed-off-by: Stephen Hemminger Signed-off-by: Jeff Garzik commit 62335ab013d9eaef502bd402eb2eb72e8cff58f1 Author: Stephen Hemminger Date: Tue Feb 6 10:45:42 2007 -0800 sky2: safer transmit timeout Rather than trying to be "smart" about possible transmit timeout causes. Just clear all pending frames and reset the PHY. Signed-off-by: Stephen Hemminger Signed-off-by: Jeff Garzik commit 4a50a876ac325a45de1b582571c1248648801b52 Author: Stephen Hemminger Date: Tue Feb 6 10:45:41 2007 -0800 sky2: TSO support for EC_U The Yukon EC_U chipset apparently supports TSO but only for non-Jumbo frame sizes because it lacks a Ram buffer. Signed-off-by: Stephen Hemminger Signed-off-by: Jeff Garzik commit b02a92586dca362b0b76ad527b91bd44ce58ece5 Author: Stephen Hemminger Date: Tue Feb 6 10:45:40 2007 -0800 sky2: use dev_err for error reports Use the standard dev_xxx functions instead of printk directly for error reports. Fix a bug where the initialization would return 0 if allocation of network device failed. Signed-off-by: Stephen Hemminger Signed-off-by: Jeff Garzik commit f7feaca77d6ad6bcfcc88ac54e3188970448d6fe Author: Eric W. Biederman Date: Sun Jan 28 12:56:37 2007 -0700 msi: Make MSI useable more architectures The arch hooks arch_setup_msi_irq and arch_teardown_msi_irq are now responsible for allocating and freeing the linux irq in addition to setting up the the linux irq to work with the interrupt. arch_setup_msi_irq now takes a pci_device and a msi_desc and returns an irq. With this change in place this code should be useable by all platforms except those that won't let the OS touch the hardware like ppc RTAS. Signed-off-by: Eric W. Biederman Acked-by: Ingo Molnar Signed-off-by: Greg Kroah-Hartman commit 5b912c108c8b1fcecbfe13d6d9a183db97b682d3 Author: Eric W. Biederman Date: Sun Jan 28 12:52:03 2007 -0700 msi: Kill the msi_desc array. We need to be able to get from an irq number to a struct msi_desc. The msi_desc array in msi.c had several short comings the big one was that it could not be used outside of msi.c. Using irq_data in struct irq_desc almost worked except on some architectures irq_data needs to be used for something else. So this patch adds a msi_desc pointer to irq_desc, adds the appropriate wrappers and changes all of the msi code to use them. The dynamic_irq_init/cleanup code was tweaked to ensure the new field is left in a well defined state. Signed-off-by: Eric W. Biederman Acked-by: Ingo Molnar Signed-off-by: Greg Kroah-Hartman commit 1c659d61cfbd8dc3926688c1bbf12d80f4cfb5c2 Author: Eric W. Biederman Date: Sun Jan 28 12:47:52 2007 -0700 msi: Remove attach_msi_entry. The attach_msi_entry has been reduced to a single simple assignment, so for simplicity remove the abstraction and directory perform the assignment. Signed-off-by: Eric W. Biederman Acked-by: Ingo Molnar Signed-off-by: Greg Kroah-Hartman commit 866a8c87c4e51046602387953bbef76992107bcb Author: Eric W. Biederman Date: Sun Jan 28 12:45:54 2007 -0700 msi: Fix msi_remove_pci_irq_vectors. Since msi_remove_pci_irq_vectors is designed to be called during hotplug remove it is actively wrong to query the hardware and expect meaningful results back. To that end remove the pci_find_capability calls. Testing dev->msi_enabled and dev->msix_enabled gives us all of the information we need. Signed-off-by: Eric W. Biederman Acked-by: Ingo Molnar Signed-off-by: Greg Kroah-Hartman commit d40f540ce6d992d4123827dbd62f68c4a39c53d0 Author: Eric W. Biederman Date: Sun Jan 28 12:44:21 2007 -0700 msi: Remove msi_lock. With the removal of msi_lookup_irq all of the functions using msi_lock operated on a single device and none of them could reasonably be called on that device at the same time. Since what little synchronization that needs to happen needs to happen outside of the msi functions, msi_lock could never be contended and as such is useless and just complicates the code. Signed-off-by: Eric W. Biederman Acked-by: Ingo Molnar Signed-off-by: Greg Kroah-Hartman commit ded86d8d37736df67ddeec4ae00e2ec1a5a90b3c Author: Eric W. Biederman Date: Sun Jan 28 12:42:52 2007 -0700 msi: Kill msi_lookup_irq The function msi_lookup_irq was horrible. As a side effect of running it changed dev->irq, and then the callers would need to change it back. In addition it does a global scan through all of the irqs, which seems to be the sole justification of the msi_lock. To remove the neede for msi_lookup_irq I added first_msi_irq to struct pci_dev. Then depending on the context I replaced msi_lookup_irq with dev->first_msi_irq, dev->msi_enabled, or dev->msix_enabled. msi_enabled and msix_enabled were already present in pci_dev for other reasons. Signed-off-by: Eric W. Biederman Acked-by: Ingo Molnar Signed-off-by: Greg Kroah-Hartman commit 8fed4b65236c44d090bd62f2d14938ae791e0260 Author: Michael Ellerman Date: Thu Jan 25 19:34:08 2007 +1100 MSI: Combine pci_(save|restore)_msi/msix_state The PCI save/restore code doesn't need to care about MSI vs MSI-X, all it really wants is to say "save/restore all MSI(-X) info for this device". This is borne out in the code, we call the MSI and MSI-X save routines side by side, and similarly with the restore routines. So combine the MSI/MSI-X routines into pci_save_msi_state() and pci_restore_msi_state(). It is up to those routines to decide what state needs to be saved. Signed-off-by: Michael Ellerman Signed-off-by: Greg Kroah-Hartman commit 0fcfdabbdbedb3bdc63f29209aeeac805df78a92 Author: Michael Ellerman Date: Thu Jan 25 19:34:08 2007 +1100 MSI: Remove pci_scan_msi_device() pci_scan_msi_device() doesn't do anything anymore, so remove it. Signed-off-by: Michael Ellerman Signed-off-by: Greg Kroah-Hartman commit 88187dfa4d8bb565df762f272511d2c91e427e0d Author: Michael Ellerman Date: Thu Jan 25 19:34:07 2007 +1100 MSI: Replace pci_msi_quirk with calls to pci_no_msi() I don't see any reason why we need pci_msi_quirk, quirk code can just call pci_no_msi() instead. Remove the check of pci_msi_quirk in msi_init(). This is safe as all calls to msi_init() are protected by calls to pci_msi_supported(), which checks pci_msi_enable, which is disabled by pci_no_msi(). The pci_disable_msi routines didn't check pci_msi_quirk, only pci_msi_enable, but as far as I can see that was a bug not a feature. Signed-off-by: Michael Ellerman Signed-off-by: Greg Kroah-Hartman commit 89298c7a41e71ecb1e0c3f793655e9ce09662ce0 Author: Greg Kroah-Hartman Date: Thu Jan 25 16:15:24 2007 -0800 PCI: remove duplicate device id from ipr As pointed out by Kay Sievers Signed-off-by: Greg Kroah-Hartman commit b11056355ea149c37edf0ef54976a49f5258cd54 Author: Greg Kroah-Hartman Date: Thu Jan 25 16:15:24 2007 -0800 PCI: remove duplicate device id from ata_piix As pointed out by Kay Sievers Signed-off-by: Greg Kroah-Hartman commit e36c455c2f5fee08fed395e94c7ab156cd159360 Author: Pavel Machek Date: Tue Jan 16 12:17:13 2007 +0100 PCI: power management: remove noise on non-manageable hw Return early from pci_set_power_state() if hardware does not support power management. This way, we do not generate noise in the logs. Signed-off-by: Pavel Machek Signed-off-by: Greg Kroah-Hartman commit c54c18790700b8b2a503945d729aa425c25691fe Author: Satoru Takeuchi Date: Thu Jan 18 13:50:05 2007 +0900 PCI: cleanup MSI code Cleanup MSI code as follows: - fix some types - fix strange local variable definition - delete unnecessary blank line - add comment to #endif which is far from corresponding #ifdef Signed-off-by: Satoru Takeuchi Signed-off-by: Greg Kroah-Hartman commit 8255cf35d503db7c1b26ae53b6b7f23ada82316f Author: Adrian Bunk Date: Sat Jan 6 21:48:41 2007 +0100 PCI: make isa_bridge Alpha-only Since isa_bridge is neither assigned any value !NULL nor used on !Alpha, there's no reason for providing it. Signed-off-by: Adrian Bunk Signed-off-by: Greg Kroah-Hartman commit 1863100a0244828f78e5e47b22b93ca912e80963 Author: Adrian Bunk Date: Sun Jan 14 14:46:32 2007 +0100 PCI: remove quirk_sis_96x_compatible() Since 2.6.0-test10, all quirk_sis_96x_compatible() had any effect on was a printk(). This patch therefore removes it. Signed-off-by: Adrian Bunk Acked-by: Mark M. Hoffman Signed-off-by: Greg Kroah-Hartman commit 2f2d39d2843570e81be6d53da6052f6752dc3c45 Author: Jean Delvare Date: Fri Jan 5 11:23:15 2007 +0100 PCI: Speed up the Intel SMBus unhiding quirk Speed up the Intel SMBus PCI quirk by avoiding tests which can only fail. This also makes the compiled code significantly smaller when using gcc 3.2/3.4. gcc 4.x appears to optimize the code by itself so this change doesn't make a difference there. Signed-off-by: Jean Delvare Signed-off-by: Greg Kroah-Hartman commit 15a260d53f7ca026e45109d2c2bec8c4b087780b Author: Daniel Yeisley Date: Thu Dec 21 14:34:57 2006 -0500 PCI Quirk: 1k I/O space IOBL_ADR fix on P64H2 There's an existing quirk for the kernel to use 1k IO space granularity on the Intel P64H2. It turns out however that pci_setup_bridge() in drivers/pci/setup-bus.c reads in the IO base and limit address register masks it off to the nearest 4k, and writes it back. This causes the kernel to be on 1k boundaries and the hardware to be 4k aligned. The patch below fixes the problem. Signed-off-by: Dan Yeisley Signed-off-by: Greg Kroah-Hartman commit 9f593e30b318719b0e3889c730cc3a2d0729a707 Author: Kenji Kaneshige Date: Tue Jan 9 13:03:10 2007 -0800 shpchp: delete trailing whitespace This patch deletes trailing white space in SHPCHP driver. This has no functional change. Signed-off-by: Kenji Kaneshige Signed-off-by: Kristen Carlson Accardi Signed-off-by: Greg Kroah-Hartman commit 1555b33da0b27f933fbe08679935ce9d83c0e9e9 Author: Kenji Kaneshige Date: Tue Jan 9 13:03:01 2007 -0800 shpchp: remove DBG_XXX_ROUTINE This patch removes DBG_ENTER_ROUTINE, DBG_LEAVE_ROUTINE and related code. Signed-off-by: Kenji Kaneshige Signed-off-by: Kristen Carlson Accardi Signed-off-by: Greg Kroah-Hartman commit 3d9c18872fa1db5c43ab97d8cbca43775998e49c Author: Kenji Kaneshige Date: Tue Jan 9 13:02:48 2007 -0800 shpchp: remove CONFIG_HOTPLUG_PCI_SHPC_POLL_EVENT_MODE The CONFIG_HOTPLUG_PCI_SHPC_POLL_EVENT_MODE config option is not needed because polling mechanism for shpc hotplug events can be enabled through module option 'shpchp_poll_mode'. This patch removes CONFIG_HOTPLUG_PCI_SHPC_POLL_EVENT_MODE. Signed-off-by: Kenji Kaneshige Signed-off-by: Kristen Carlson Accardi Signed-off-by: Greg Kroah-Hartman commit 34d03419f03bcfdf70d9617a9b90b60c93482c4a Author: Kristen Carlson Accardi Date: Tue Jan 9 13:02:36 2007 -0800 PCIEHP: Add Electro Mechanical Interlock (EMI) support to the PCIE hotplug driver. Signed-off-by: Kristen Carlson Accardi Signed-off-by: Greg Kroah-Hartman commit 262303fe329a51463925f3749aafc358a4201397 Author: Kenji Kaneshige Date: Thu Dec 21 17:01:10 2006 -0800 pciehp: fix wait command completion This patch fixes this problem that pciehp driver will sleep unnecessarily long when waiting for command completion. With this patch, modprobe pciehp driver becomes very faster as follows for instance. o Without this patch # time /sbin/modprobe pciehp real 0m4.976s user 0m0.000s sys 0m0.004s o With this patch # time /sbin/modprobe pciehp real 0m0.640s user 0m0.000s sys 0m0.004s Signed-off-by: Kenji Kaneshige Signed-off-by: Kristen Carlson Accardi Signed-off-by: Greg Kroah-Hartman commit 44ef4cefb0168740184ee3d7d18254339741e9d5 Author: Kenji Kaneshige Date: Thu Dec 21 17:01:09 2006 -0800 pciehp: cleanup wait command completion This patch cleans up the code to wait for command completion. Signed-off-by: Kenji Kaneshige Signed-off-by: Kristen Carlson Accardi Signed-off-by: Greg Kroah-Hartman commit 75e13178af33e20b5802885f637af2a82c64ac2c Author: Kenji Kaneshige Date: Thu Dec 21 17:01:08 2006 -0800 pciehp: remove unused pcie_cap_base This patch removes unused pcie_cap_base variable. Signed-off-by: Kenji Kaneshige Signed-off-by: Kristen Carlson Accardi Signed-off-by: Greg Kroah-Hartman commit 15232ece5566710d24c81ac3dd629f7556a92818 Author: Kenji Kaneshige Date: Thu Dec 21 17:01:07 2006 -0800 pciehp: cleanup pciehp.h This patch cleans up pciehp.h. This has no functional change. Signed-off-by: Kenji Kaneshige Signed-off-by: Kristen Carlson Accardi Signed-off-by: Greg Kroah-Hartman commit a0f018daa9955d123b9257b08bcac2d59e295967 Author: Kenji Kaneshige Date: Thu Dec 21 17:01:06 2006 -0800 pciehp: cleanup register access This patch cleans up register access functions. This has no functional change. Signed-off-by: Kenji Kaneshige Signed-off-by: Kristen Carlson Accardi Signed-off-by: Greg Kroah-Hartman commit a8c2b635979823043ea7766dea1d9371773b4d8e Author: Kenji Kaneshige Date: Thu Dec 21 17:01:05 2006 -0800 pciehp: remove unused pci_bus from struct controller This patch removes unused pci_bus member from struct controller. Signed-off-by: Kenji Kaneshige Signed-off-by: Kristen Carlson Accardi Signed-off-by: Greg Kroah-Hartman commit 48fe39151727db350347e1dba09d71c8ca24207a Author: Kenji Kaneshige Date: Thu Dec 21 17:01:04 2006 -0800 pciehp: remove unnecessary php_ctlr The struct php_ctlr seems to be only for complicating codes. This patch removes struct php_ctlr and related codes. Signed-off-by: Kenji Kaneshige Signed-off-by: Kristen Carlson Accardi Signed-off-by: Greg Kroah-Hartman commit 2410fa4eaec4133f9fa8968f277ddb28b89b92b3 Author: Kenji Kaneshige Date: Thu Dec 21 17:01:03 2006 -0800 pciehp: cleanup slot list This patch cleans up slot list handling (use list_head). This has no functional change. Signed-off-by: Kenji Kaneshige Signed-off-by: Kristen Carlson Accardi Signed-off-by: Greg Kroah-Hartman commit a0b1725720d9a023a1dee129234f5972056038c6 Author: Kenji Kaneshige Date: Thu Dec 21 17:01:02 2006 -0800 pciehp: cleanup init_slot() This patch cleans up init_slots() in pciehp_core.c based on pcihp_skeleton.c. This has no functional change. Signed-off-by: Kenji Kaneshige Signed-off-by: Kristen Carlson Accardi Signed-off-by: Greg Kroah-Hartman commit 429538ad3eeffec4199d8adddd1e9e4c80b2c08b Author: Adrian Bunk Date: Sat Nov 18 01:06:29 2006 +0100 PCI: mark pci_find_device() as __deprecated On Fri, Nov 17, 2006 at 09:32:36AM -0500, Alan Cox wrote: > > Soon we should deprecate pci_find_device as well So let's mark it as __deprecated now, which also has the side effect that noone can later whine that removing it might break some shiny external modules. Oh, and if anything starts complaining "But this adds some warnings to my kernel build!", he should either first fix the 200 kB (sic) of warnings I'm getting in 2.6.19-rc5-mm2 starting at MODPOST or go to hell. Signed-off-by: Adrian Bunk Acked-by: Alan Cox Signed-off-by: Greg Kroah-Hartman commit fd9b37cc4e32533214f77b34ea03ee85f6e0a4d2 Author: Adrian Bunk Date: Fri Nov 17 15:21:45 2006 +0100 PCI: remove pci_find_device_reverse() This patch removes the no longer used pci_find_device_reverse(). Signed-off-by: Adrian Bunk Acked-by: Alan Cox Signed-off-by: Greg Kroah-Hartman commit c30ca1db39cecade07143112ecfac09ec6b08e3f Author: Adrian Bunk Date: Tue Dec 19 05:13:15 2006 +0100 PCI: quirks.c: cleanup This patch contains the following cleanups: - move all EXPORT_SYMBOL's directly below the code they are exporting - move all DECLARE_PCI_FIXUP_*'s directly below the functions they are calling Signed-off-by: Adrian Bunk Signed-off-by: Greg Kroah-Hartman commit 81b1955eef786c1b2fe29f6783543ce13d8b0bc4 Author: Linas Vepstas Date: Tue Dec 12 18:29:15 2006 -0600 PCI: Use newly defined PCI channel offline routine Use newly minted routine to access the PCI channel state. Signed-off-by: Linas Vepstas Signed-off-by: Greg Kroah-Hartman commit a7369f1f6533b9efc3209d1df103537bbbf24b8c Author: Linas Vepstas Date: Tue Dec 12 16:55:59 2006 -0600 PCI: define inline for test of channel error state Add very simple routine to indicate the pci channel error state. Signed-off-by: Linas Vepstas Signed-off-by: Greg Kroah-Hartman commit c87deff776feacd05a7411097e8c8c57e549e638 Author: Hidetoshi Seto Date: Mon Dec 18 10:31:06 2006 +0900 PCI : Add selected_regions funcs This patch adds the following changes into generic PCI code especially for PCI legacy I/O port free drivers. - Added new pci_request_selected_regions() and pci_release_selected_regions() for PCI legacy I/O port free drivers in order to request/release only the selected regions. - Added helper routine pci_select_bars() which makes proper mask of BARs from the specified resource type. This would be very helpful for users of pci_enable_device_bars(). Signed-off-by: Kenji Kaneshige Signed-off-by: Hidetoshi Seto Cc: Inaky Perez-Gonzalez Signed-off-by: Greg Kroah-Hartman commit 38cc13022ed3cea949722d5a6f49025da82c9fd0 Author: Hidetoshi Seto Date: Mon Dec 18 10:30:00 2006 +0900 PCI : add extremely specialized __pci_reenable_device for default resume Original patch was posted as "PCI : Move pci_fixup_device and is_enabled". This 3 of 3 patches does: - add __pci_reenable_device (recover former change of 1st patch) Signed-off-by: Kenji Kaneshige Signed-off-by: Hidetoshi Seto Cc: Inaky Perez-Gonzalez Signed-off-by: Greg Kroah-Hartman commit 9fb625c3cc3731097a142ecae79a0369fb854c2d Author: Hidetoshi Seto Date: Mon Dec 18 10:28:43 2006 +0900 PCI : Move pci_fixup_device and is_enabled (originally intended change) Original patch was posted as "PCI : Move pci_fixup_device and is_enabled". This 2 of 3 patches does: - Move pci_fixup_device and enable_cnt (originally intended change) - relocate pci_fixup_device (recover latter change of 1st patch) Signed-off-by: Kenji Kaneshige Signed-off-by: Hidetoshi Seto Cc: Inaky Perez-Gonzalez Signed-off-by: Greg Kroah-Hartman commit 924b08f3ff12eb0e8ecd9e9a9b6a5b884a495c23 Author: Hidetoshi Seto Date: Mon Dec 18 10:27:45 2006 +0900 PCI : remove too specialized __pci_enable_device for default resume Original patch was posted as "PCI : Move pci_fixup_device and is_enabled". This 1 of 3 patches does: - reverts small part of Inaky's patch (remove __pci_enable_device) This change will be recovered by 3rd patch. - temporarily remove pci_fixup_device. This change will be recovered by 2nd patch. Signed-off-by: Kenji Kaneshige Signed-off-by: Hidetoshi Seto Cc: Inaky Perez-Gonzalez Signed-off-by: Greg Kroah-Hartman commit 07eddf3d597f2d009a37a4e8c7c32a1ffe992f3e Author: Yinghai Lu Date: Wed Nov 29 13:53:10 2006 -0800 PCI: check szhi when sz is 0 when 64 bit iomem bigger than 4G For pci mem resource that size is bigger than 4G, the sz returned by pc_size will be 0. So that resource is skipped, and register contained hi address will be treated as another 32bit resource. We need to use sz64 and pci_sz64 for 64 bit resource for clear logical. Typical usages for this: Opteron system with co-processor and the co-processor could take more than 4G RAM as pre-fetchable mem resource. Signed-off-by: Yinghai Lu Cc: Andi Kleen Cc: Andrew Morton Signed-off-by: Greg Kroah-Hartman commit e3173832d7be8f62a181a1888a65f0a3dc58c2e0 Author: Stephen Hemminger Date: Tue Feb 6 10:45:39 2007 -0800 sky2: add Wake On Lan support Adds basic magic packet wake on lan support to the sky2 driver. Note: initial WOL value is based on BIOS settings. Signed-off-by: Stephen Hemminger Signed-off-by: Jeff Garzik commit dde6d43d060bf0e0f38c66f76908e460db3bf0d8 Author: Hennerich, Michael Date: Mon Feb 5 16:41:35 2007 -0800 fix unaligned exception in /drivers/net/wireless/orinoco.c Prevent an unaligned exception to occur. (GCC 4.1) tmp is defined as char pointer while it is later accessed as short. Cc: Jean Tourrilhes Cc: John W. Linville Cc: Jeff Garzik Signed-off-by: Andrew Morton Signed-off-by: Jeff Garzik commit f100ae2ed04d17fb450fe6e3a3780342da60acd0 Author: Robert P. J. Day Date: Mon Feb 5 16:31:06 2007 -0800 Remove unused kernel config option DLCI_COUNT Remove the unused kernel config option DLCI_COUNT. Signed-off-by: Robert P. J. Day Cc: "David S. Miller" Cc: Jeff Garzik Cc: Krzysztof Halasa {khc@pm.waw.pl> Signed-off-by: Andrew Morton Signed-off-by: Jeff Garzik commit 45d3ac4ec31ccf9a39065e8576260c6ac2652c83 Author: Alan Cox Date: Mon Feb 5 16:31:03 2007 -0800 z85230: spinlock logic At some point someone added a spin_lock(&dev->lock) to the IRQ handler for the Z85230 driver. This actually correctly fixes a bug but the necessary changes to remove the chan->lock calls in the event handlers were not made (c->lock is the same lock). Simona Dascenzo reported the problem with the driver and this patch should fix the problem he found. Cc: "David S. Miller" Cc: Jeff Garzik Signed-off-by: Andrew Morton Signed-off-by: Jeff Garzik commit 257b346d20cd309a4c5a13b8de5ad2b7c63b590a Author: Maciej W. Rozycki Date: Mon Feb 5 16:28:27 2007 -0800 mips: declance: Driver model for the PMAD-A This is a set of changes that converts the PMAD-A support to the driver model. Signed-off-by: Maciej W. Rozycki Cc: Ralf Baechle Cc: Jeff Garzik Signed-off-by: Andrew Morton Signed-off-by: Jeff Garzik commit d9a9720eab7437aa7f34dcbb92bb4bc8cc36bba9 Author: Linas Vepstas Date: Mon Feb 5 16:29:43 2007 -0800 Spidernet: Rework RX linked list Make the hardware perceive the RX descriptor ring as a null-terminated linked list, instead of a circular ring. Signed-off-by: Linas Vepstas Cc: James K Lewis Cc: Arnd Bergmann Signed-off-by: Andrew Morton Signed-off-by: Jeff Garzik commit 64358164f5bfe5e11d4040c1eb674c29e1436ce5 Author: Greg Kroah-Hartman Date: Thu Jan 25 16:15:24 2007 -0800 USB: remove duplicate device id from zc0301 As pointed out by Kay Sievers Signed-off-by: Greg Kroah-Hartman commit ab6c41a498cd76085ce45ec407f5fe25968058a6 Author: Greg Kroah-Hartman Date: Thu Jan 25 16:15:24 2007 -0800 USB: remove duplicate device id from usb_storage As pointed out by Kay Sievers Signed-off-by: Greg Kroah-Hartman commit 33c6b7e99fb043b7ae7d3deafb552a179a29b489 Author: Greg Kroah-Hartman Date: Thu Jan 25 16:15:24 2007 -0800 USB: remove duplicate device id from keyspan As pointed out by Kay Sievers Signed-off-by: Greg Kroah-Hartman commit 210b1975795d4661127144365a889a7a4f2cf1fa Author: Greg Kroah-Hartman Date: Thu Jan 25 16:15:24 2007 -0800 USB: remove duplicate device id from ftdi_sio As pointed out by Kay Sievers Signed-off-by: Greg Kroah-Hartman commit 9da88d78bcb5610a4bb9e0e10dfb31cc9b4fdb1b Author: Greg Kroah-Hartman Date: Thu Jan 25 16:15:24 2007 -0800 USB: remove duplicate device id from visor As pointed out by Kay Sievers Signed-off-by: Greg Kroah-Hartman commit 1a68f71d4fe71426a5c9703591e068241c03f896 Author: Oliver Neukum Date: Thu Jan 25 11:17:41 2007 +0100 USB: a bit more coding style cleanup I was sitting in a train threatened to be blocked by ice. I took this as a hint to do some more boring work for the common good. Here's a bit more for coding style. Signed-off-by: Oliver Neukum Signed-off-by: Greg Kroah-Hartman commit 9251644ab33579d80c038b077f78daa23a04fdcd Author: Oliver Neukum Date: Tue Jan 23 15:55:28 2007 -0500 usbcore: trivial whitespace fixes This patch (as844) makes some trivial whitespace fixes to a few files in usbcore. Oliver did most of the work and Alan added some tidying up. Signed-off-by: Oliver Neukum Signed-off-by: Alan Stern Signed-off-by: Greg Kroah-Hartman commit 1096f780d0b9d6bade2d42bf823e81db3e553abe Author: Alan Stern Date: Mon Jan 22 11:58:34 2007 -0500 usb-storage: use first bulk endpoints, not last According to the Bulk-Only spec, usb-storage is supposed to use the _first_ bulk-in and bulk-out endpoints it finds, not the _last_. And while we're at it, we ought to test the direction of the interrupt endpoint as well. This patch (as842) makes both changes. Signed-off-by: Alan Stern Cc: Matthew Dharm Signed-off-by: Greg Kroah-Hartman commit 629e4427aa817d5c9f11885420abf54b8f5967dc Author: Alan Stern Date: Mon Jan 22 16:08:53 2007 -0500 EHCI: fix interrupt-driven remote wakeup Now that port status change notifications are interrupt-driven, ehci-hcd needs to tell usbcore when a remote-wakeup resume operation is finished -- we can no longer rely on the core to poll and find out. This patch (as843) uses the root-hub status timer to force a poll after the resume is complete. The patch also changes the test for detecting when the TDRSMDN resume period has expired. It's necessary to use time_after_eq() instead of time_after(), since the polling is triggered precisely by a timer. The same change is made for TDRSTR reset expiration, for consistency. Signed-off-by: Alan Stern Cc: David Brownell Signed-off-by: Greg Kroah-Hartman commit 1d619f128ba911cd3e6d6ad3475f146eb92f5c27 Author: Marcelo Tosatti Date: Sun Jan 21 19:45:59 2007 -0200 USB: switch ehci-hcd to new polling scheme Switch ehci-hcd to use the new polling scheme, which reports root hub status changes via the interrupt handler, in an asynchronous fashion. Doing so disables polling for status changes (whose handler is rh_timer_func). Tested on a Geode GX machine, which is now capable of running at =~ 5 timer interrupts per second (in the -rt tree), resulting in significant power savings. Signed-off-by: Marcelo Tosatti Cc: David Brownell Signed-off-by: Greg Kroah-Hartman commit d0532184086906889f4a0cd92eade1f7be49fbac Author: Oliver Neukum Date: Thu Jan 18 15:06:07 2007 +0100 USB: autosuspend for usb printer driver this implements autosuspend for usb printers. It compiles and is tested. Signed-off-by: Oliver Neukum Signed-off-by: Greg Kroah-Hartman commit a19ceb56cbd1e1beff3e9cf6042e1f31f6487aa6 Author: Jeremy Roberson Date: Thu Jan 18 08:10:25 2007 -0700 USB Input: Added kernel module to support all GTCO CalComp USB InterWrite School products Added a kernel module (gtco) to the USB Input subsystem. This kernel module adds support for all GTCO CalComp USB InterWrite School products. Signed-off-by: Jeremy A. Roberson Signed-off-by: Greg Kroah-Hartman commit e43062dd208594caa94536b8ba4b762d4a16330d Author: Kevin Lloyd Date: Wed Jan 17 16:04:18 2007 -0800 USB: Sierra Wireless auto set D0 This patch ensures that the device is turned on when inserted into the system. It also adds more VID/PIDs and matches the N_OUT_URB with the airprime driver. Signed-off-by: Kevin Lloyd Signed-off-by: Greg Kroah-Hartman commit ef3ff462a31987629c4d0488550fbbb66fbfcc35 Author: Håvard Skinnemoen Date: Mon Feb 27 18:15:04 2006 +0100 USB: usb ethernet gadget recognizes HUSB2DEV Define DEV_CONFIG_CDC when compiling for HUSB2DEV. From: Håvard Skinnemoen Signed-off-by: David Brownell Signed-off-by: Greg Kroah-Hartman commit 1f5b9cc9e4cf5847e7550c4079cebb80170e71dd Author: Håvard Skinnemoen Date: Wed Jan 17 11:03:29 2007 -0800 USB: list atmel husb2_udc gadget controller This identifies the driver for the Atmel HUSB2 Device Controller, as integrated into the first AVR32 chip, the AT32AP700. From: Håvard Skinnemoen Signed-off-by: David Brownell Signed-off-by: Greg Kroah-Hartman commit 49631ca7f3e2fd05186028b453fa27f75b830de7 Author: Alan Stern Date: Tue Jan 16 23:28:48 2007 -0800 USB: gadgetfs AIO tweaks This patch (as837) fixes several mistakes in the AIO interface of the gadgetfs driver: The ki_retry method is not supposed to do a put on the kiocb. The extra call to aio_put_req() causes memory corruption. (Note: This call was removed before, by patch as691, and then mysteriously re-introduced later.) Even if a read transfer is cancelled, we can and should send to the user all the data that did manage to get transferred. Testing for AIO cancellation in the I/O completion handler is both racy and (now) unnecessary. aio_complete() does its own checking, in a safe manner. Signed-off-by: Alan Stern Signed-off-by: David Brownell Signed-off-by: Greg Kroah-Hartman commit ce46794f77f698eaf3b80922fafac5a9379085e0 Author: David Brownell Date: Tue Jan 16 23:06:07 2007 -0800 USB: gadgetfs behaves better on userspace init bug Resolve an initizlization issue that could come up if the userspace driver wrote invalid descriptors to a dual-speed device. Signed-off-by: David Brownell Signed-off-by: Greg Kroah-Hartman commit 5b89db02a5a7c8bad3c6fb7888778082a441b385 Author: David Brownell Date: Tue Jan 16 22:56:26 2007 -0800 USB: gadgetfs race fix This resolves a race in gadgetfs associated with changing device/ep0 when processing control requests. The fix is to change that state earlier, when the control response is issued, so there's no window in which userspace could see the wrong state; and enlarge the scope of the spinlock during the ep0 request completion handler. Signed-off-by: David Brownell Signed-off-by: Greg Kroah-Hartman commit 0864c7a9286b02319d3db2103bada1c2269c1e1e Author: David Brownell Date: Tue Jan 16 22:53:58 2007 -0800 USB: gadgetfs simplifications This simplifies event reading by eliminating arithmetic and being more direct/obvious, and tweaks some debug messages slightly. The math elimination will change timings, sometimes enough to allow a race to appear. Signed-off-by: David Brownell Signed-off-by: Greg Kroah-Hartman commit 7489d14943181731ef8694e2ea2d5a919b93b956 Author: David Brownell Date: Tue Jan 16 22:51:04 2007 -0800 USB: gadgetfs cleanups Minor gadgetfs cleanups: - EP0 state constants become consistently STATE_DEV_* rather than sometimes omitting the "DEV_"; STATE_EP_* were already consistent. - Comment that ep0 state is protected by the spinlock, and update code that was neglecting that rule. None of this is expected to change behavior. Signed-off-by: David Brownell Signed-off-by: Greg Kroah-Hartman commit 3ff4fd94c86259e44d58946af34231a1586b5d93 Author: Oliver Neukum Date: Sat Jan 13 07:32:27 2007 +0100 USB: race fixes for usb-serial, step 3 - fix an error code returned if a device has been disconnected Signed-off-by: Oliver Neukum Signed-off-by: Greg Kroah-Hartman commit 4b10f0f3a0d4caa8b615cd1f770a70912967a3cd Author: Oliver Neukum Date: Sat Jan 13 07:31:27 2007 +0100 USB: race fixes for usb-serial, step 2 - take BKL before looking up a driver to associate with a device to make sure the module is not unloaded after looking up but before association & bumping module count Signed-off-by: Oliver Neukum Signed-off-by: Greg Kroah-Hartman commit 34ef50e5b1f96c2d8c0f3d28b7d407743806256c Author: Oliver Neukum Date: Sat Jan 13 07:29:26 2007 +0100 USB: race fixes for usb-serial step 1 - introduce a spinlock for serial_table to eliminate the window between looking up a device and getting a reference - delay inscription of a new device into serial_table until it is fully initialised - make sure disconnect() kills all URBs to avoid leckage across a soft unbind Signed-off-by: Oliver Neukum Signed-off-by: Greg Kroah-Hartman commit fdcba53e2d58272bcdb5f1fad694602ccf02ad46 Author: Rainer Weikusat Date: Wed Jan 3 15:36:25 2007 +0100 fix for bugzilla #7544 (keyspan USB-to-serial converter) At least the Keyspan USA-19HS USB-to-serial converter supports two different configurations, one where the input endpoints have interrupt transfer type and one where they are bulk endpoints. The default UHCI configuration uses the interrupt input endpoints. The keyspan driver, OTOH, assumes that the device has only bulk endpoints (all URBs are initialized by calling usb_fill_bulk_urb in keyspan.c/ keyspan_setup_urb). This causes the interval field of the input URBs to have a value of zero instead of one, which 'accidentally' worked with Linux at least up to 2.6.17.11 but stopped to with 2.6.18, which changed the UHCI support code handling URBs for interrupt endpoints. The patch below modifies to driver to initialize its input URBs either as interrupt or as bulk URBs, depending on the transfertype contained in the associated endpoint descriptor (only tested with the default configuration) enabling the driver to again receive data from the serial converter. Greg K-H reworked the patch. Signed-off-by: Rainer Weikusat Signed-off-by: Greg Kroah-Hartman commit 3ede760f0e46317c6716ead8facff88f6a924a49 Author: Oliver Neukum Date: Thu Jan 11 14:35:50 2007 +0100 USB: total removal of multithreaded probing in usb The whole approach is simply wrong. Forking a thread means that - errors are ignored - locking is ignored Doing this correctly would require major surgery for questionable benefit. Signed-off-by: Oliver Neukum Signed-off-by: Greg Kroah-Hartman commit 66e56ce75e39210415fb12ceacd5f3580ad72d50 Author: David Brownell Date: Tue Jan 16 12:46:39 2007 -0800 USB: at91_udc wakeup event updates This updates the AT91 UDC driver's handling of wakeup events: - Fix a bug in the original scheme, which was never updated after the {enable,disable}_irq_wake() semantics were updated to address refcounting issues (i.e. behave for shared irqs). - Couple handling of both type of wakeup events, to be more direct. The controller can be source of wakeup events for cases like bus reset and USB resume. On some boards, VBUS sensing is also IRQ driven. Signed-off-by: David Brownell Signed-off-by: Greg Kroah-Hartman commit 57e06c11372eccf5acebdd4664eb025fee76c561 Author: Alan Stern Date: Tue Jan 16 11:59:45 2007 -0500 EHCI: force high-speed devices to run at full speed This patch (as710) adds a sysfs class-device attribute file named "companion" for EHCI controllers. The file contains a list of port numbers that are dedicated to the companion controller; by writing a port number to the file the user can force a high-speed device attached directly to the computer to run at full speed. (As far as I know it is not possible to do this for a device attached to an external hub.) A port is removed from the file by writing the negative of its port number. Several users have asked for this facility and it seems like a useful thing to have. Every now and then one runs across a device which behaves much better at full speed than at high speed. Signed-off-by: Alan Stern Cc: David Brownell Signed-off-by: Greg Kroah-Hartman commit 625b5c9a0069ef1b61feb3ce599b39f1b04b5666 Author: Alan Stern Date: Tue Jan 16 11:58:47 2007 -0500 EHCI: don't hide ports owned by the companion This patch (as709) changes the way ehci-hcd presents port status values for ports owned by the companion controller. It no longer hides the information; in particular, it allows the core to see the disconnect event that occurs when a full- or low-speed device is switched over to the companion. This is required for the next patch in this series. Signed-off-by: Alan Stern Cc: David Brownell Signed-off-by: Greg Kroah-Hartman commit e6316565e568b3b5733be10cfca3c27259bef499 Author: Alan Stern Date: Tue Jan 16 11:58:00 2007 -0500 EHCI: local variable for port status register This patch (as708) introduces a local variable to hold the port status-register address in ehci-hub.c. There's not much improvement in the object code, but it sure is a lot easier to read. Signed-off-by: Alan Stern Cc: David Brownell Signed-off-by: Greg Kroah-Hartman commit 896fbd7199035958013d106329843d8ae9618753 Author: Alan Stern Date: Tue Jan 16 11:57:13 2007 -0500 usbcore: remove unused bandwith-related code This patch (as841) removes from usbcore a couple of support routines meant to help with bandwidth allocation. With the changes to uhci-hcd in the previous patch, these routines are no longer used anywhere. Also removed is the CONFIG_USB_BANDWIDTH option; it no longer does anything and is no longer needed since the HCDs now handle bandwidth issues correctly. Signed-off-by: Alan Stern Signed-off-by: David Brownell Signed-off-by: Greg Kroah-Hartman commit 3ca2a3211ee5078d49b04fe7149ff2a76473be51 Author: Alan Stern Date: Tue Jan 16 11:56:32 2007 -0500 UHCI: fix bandwidth allocation This patch (as840) fixes the bandwidth allocation mechanism in uhci-hcd. It has never worked correctly. Signed-off-by: Alan Stern Signed-off-by: Greg Kroah-Hartman commit 6a6c957eba20814456bc4bffbd4ec42406f9eb02 Author: Geoff Levand Date: Mon Jan 15 20:12:10 2007 -0800 USB: ps3 ohci bus glue USB OHCI driver bus glue for the PS3 game console. Signed-off-by: Geoff Levand Cc: David Brownell Signed-off-by: Greg Kroah-Hartman commit de44743b033942731f6b898c2d389f7ee5ac890b Author: Benjamin Herrenschmidt Date: Mon Jan 15 20:12:06 2007 -0800 USB: ohci error handling cleanup Restructure the ohci_hcd_mod_init error handling code in to better support the multiple platform drivers. This does not change the functionality. Signed-off-by: Benjamin Herrenschmidt Cc: David Brownell Signed-off-by: Geoff Levand Signed-off-by: Greg Kroah-Hartman commit 4a1a4d8b87389e35c3af04c0d0a95f6a0391b964 Author: Geoff Levand Date: Mon Jan 15 20:11:52 2007 -0800 USB: ps3 controller hid quirk Add the USB HID quirk HID_QUIRK_SONY_PS3_CONTROLLER. This sends an HID_REQ_GET_REPORT to the the PS3 controller to put the device into 'operational mode'. Signed-off-by: Geoff Levand Cc: David Brownell Signed-off-by: Greg Kroah-Hartman commit ad75a41085d80c8ce5e885962c15779935f8267e Author: Geoff Levand Date: Mon Jan 15 20:11:47 2007 -0800 USB: ps3 ehci bus glue USB EHCI driver bus glue for the PS3 game console. Signed-off-by: Geoff Levand Cc: David Brownell Signed-off-by: Greg Kroah-Hartman commit b3ebd5222141efa489d95592b7d4536766530e56 Author: Oliver Neukum Date: Tue Jan 16 12:01:26 2007 +0100 USB: better ethtool support for kaweth this implements enough ethtool support to make NetworkManager happy. Signed-off-by: Oliver Neukum Signed-off-by: Greg Kroah-Hartman commit b98b98f97c519894c64bf1bee6b7957e687dfc41 Author: Oliver Neukum Date: Tue Jan 16 09:47:12 2007 +0100 USB: power management for kaweth - implements suspend when the network interface is down - fixes a typo in comments - adds debugging output for power management - fixes a compiler warning Signed-off-by: Oliver Neukum Signed-off-by: Greg Kroah-Hartman commit 511779fd9eb7ed67116e4a1cad802363d2d58b20 Author: Phil Endecott Date: Mon Jan 15 11:35:01 2007 -0800 usb: gadgetfs remove delayed init mode Gadgetfs had a mode in which endpoint descriptors were written by the user program before connection. This mode had some bugs, and hasn't seen much (if any) use. This patch removes that mode, leaving the mode of operation where the user program waits for endpoint 0 to report a SET_CONFIGURATION, and only then configures the endpoints. From: "Phil Endecott" Signed-off-by: David Brownell Signed-off-by: Greg Kroah-Hartman commit 2505107def8b300576223367e3b603620d825e52 Author: David Brownell Date: Mon Jan 15 11:30:28 2007 -0800 usb: gadgetfs whitespace cleanup Remove some whitespace bugs in gadgetfs (mostly from someone's patch updating the AIO support). Signed-off-by: David Brownell Signed-off-by: Greg Kroah-Hartman commit 6dde896e4eac122f388263f0097b691acdc0396f Author: Marc Pignat Date: Tue Jan 9 14:00:11 2007 -0800 USB: ohci-at91 refcount fix for irq wake enables The attached patch fixes the unbalanced calls to enable_irq_wake() and disable_irq_wake() in the AT91 USB Host driver. It should resolve these kernel messages: Unbalanced IRQ x wake disable BUG: warning at kernel/irq/manage.c:167/set_irq_wake() (The original code was debugged before a bug in the genirq wakeup irq logic was fixed by adding the IRQ wake enable/disable refcounting. Not all code yet uses the bugfixed model.) Signed-off-by: Andrew Victor Signed-off-by: David Brownell Signed-off-by: Greg Kroah-Hartman commit f3f4906516a084bbd9aa3da7592e6b029fe78f5b Author: Alan Stern Date: Mon Jan 8 16:18:05 2007 -0500 usb-storage: SCSI level fixes This patch (as835) removes from usb-storage the code which sets all devices to a SCSI level of at least SCSI-2. The original reasons for doing this no longer apply, and in fact it prevents certain kinds of ATA pass-thru commands from being used. The patch also marks CB and CBI devices that are SCSI-0 (legacy SCSI) as being single-LUN, since the combined SCSI-over-USB transport protocol has no way to convey LUN information to these devices. Signed-off-by: Alan Stern Signed-off-by: Matthew Dharm Signed-off-by: Greg Kroah-Hartman commit 85a975d0ce48dfa8dec5bf1bd970f8fd2c48af32 Author: Alan Stern Date: Mon Jan 8 12:01:43 2007 -0500 UHCI: no dummy TDs for Iso QHs Isochronous queues don't need a dummy TD because the Queue Header isn't managed by the hardware. This patch (as836) removes the unnecessary dummy TDs. The patch also fixes a long-standing typo in a comment (a "don't" was missing -- potentially very confusing!). Signed-off-by: Alan Stern Signed-off-by: Greg Kroah-Hartman commit f3fe239b67424d88104e32076aec902c0642925f Author: Alan Stern Date: Mon Jan 8 12:00:28 2007 -0500 UHCI: improved debugging checks for the frame list This patch (as768) improves the debugging checks for the uhci-hcd frame list. The number of entries displayed is limited to 10, and the driver now checks for the correct Skeleton QH link value at the end of each chain of Isochronous TDs. The code to compute these link values is now used in two spots, so it is moved into its own separate subroutine. Signed-off-by: Alan Stern Signed-off-by: Greg Kroah-Hartman commit f38649fee955c19f4df9b9e7267f87702712d973 Author: Oliver Neukum Date: Fri Jan 5 17:42:35 2007 +0100 USB: race on disconnect in mdc800 I overlooked one. Setting the flag and killing the URBs must be under the lock so that no URB is submitted after usb_kill_urb() Signed-off-by: Oliver Neukum Signed-off-by: Greg Kroah-Hartman commit 6f23ee1fefdc1f80bd8a3ab04a1c41ab2dec14c9 Author: Pete Zaitcev Date: Sat Dec 30 22:43:10 2006 -0800 USB: add binary API to usbmon This patch adds a new, "binary" API in addition to the old, text API usbmon had before. The new API allows for less CPU use, and it allows to capture all data from a packet where old API only captured 32 bytes at most. There are some limitations and conditions to this, e.g. in case someone constructs a URB with 1GB of data, it's not likely to be captured, because even the huge buffers of the new reader are finite. Nonetheless, I expect this new capability to capture all data for all real life scenarios. The downside is, a special user mode application is required where cat(1) worked before. I have sample code at http://people.redhat.com/zaitcev/linux/ and Paolo Abeni is working on patching libpcap. This patch was initially written by Paolo and later I tweaked it, and we had a little back-and-forth. So this is a jointly authored patch, but I am submitting this I am responsible for the bugs. Signed-off-by: Paolo Abeni Signed-off-by: Pete Zaitcev Signed-off-by: Greg Kroah-Hartman commit a8ef36bc0a5fe973bddaa54a5a07cda29e04a602 Author: Sarah Bailey Date: Sat Dec 23 23:14:58 2006 -0800 USB: Add usb_endpoint_xfer_control to usb.h Added a function to check if an endpoint is a control endpoint. There were similar functions for bulk, interrupt, and isoc, but not for control endpoints. Signed-off-by: Sarah Bailey Signed-off-by: Greg Kroah-Hartman commit 7ca46b862f0e30fe0dcc4a4aef5b32f6b6a3fda5 Author: John Daiker Date: Fri Dec 29 19:02:06 2006 -0800 USB Gadget file_storage.c: remove unnecessary casts Went looking through some usb stuff and found some unnecessary casts in file_storage.c This is part of the KernelJanitors TODO list. Signed-off-by: John Daiker Acked-by: Alan Stern Signed-off-by: David Brownell Signed-off-by: Greg Kroah-Hartman commit 52d67f0b5c1b1827cd842020d40bdde4f7d04f59 Author: Johannes Hölzl Date: Sun Dec 17 22:05:09 2006 +0100 USB: Bugfix for aircable: Add module and name to usb_serial_driver While adding the dynamic-id support to usb serial I found a small bug in the air cable driver: Adds module and name information to the usb_serial_driver instance of aircable. So the aircable driver is correctly shown under /sys/bus/usb-serial/drivers/aircable and has the module link. Signed-off-by: Johannes Hölzl Signed-off-by: Greg Kroah-Hartman commit d9b1b787736852f462dbf277b3ca708cbbf693ae Author: Johannes Hölzl Date: Sun Dec 17 21:50:24 2006 +0100 USB serial: add driver pointer to all usb-serial drivers Every usb serial driver should have a pointer to the corresponding usb driver. So the usb serial core can add a new id not only to the usb serial driver, but also to the usb driver. Also the usb drivers of ark3116, mos7720 and mos7840 missed the flag no_dynamic_id=1. This is added now. Signed-off-by: Johannes Hölzl Signed-off-by: Greg Kroah-Hartman commit 93bacefc4cc0b53e1cb6a336d43847154fdf6886 Author: Greg Kroah-Hartman Date: Sun Dec 17 21:50:23 2006 +0100 USB serial: add dynamic id support to usb-serial core Thanks to Johannes Hölzl for fixing a few things and getting it all working properly. This adds support for dynamic usb ids to the usb serial core. The file "new_id" will show up under the usb serial driver, not the usb driver associated with the usb-serial driver (yeah, it can be a bit confusing at first glance...) This patch also modifies the USB core to allow the usb-serial core to reuse much of the dynamic id logic. Signed-off-by: Greg Kroah-Hartman Signed-off-by: Johannes Hölzl commit 495a678fc62e850d15f860d39faee07ba0a8910c Author: Sylvain Munaut Date: Wed Dec 13 21:09:55 2006 +0100 ohci: Add support for OHCI controller on the of_platform bus PPC embedded systems can have a ohci controller builtin. In the new model, it will end up as a driver on the of_platform bus, this patches takes care of them. Signed-off-by: Sylvain Munaut Acked-by: David Brownell Signed-off-by: Greg Kroah-Hartman commit 5e16fabe5dbcff15de6cdcba406195fe6e4380df Author: Sylvain Munaut Date: Wed Dec 13 21:09:54 2006 +0100 ohci: Rework bus glue integration to allow several at once The previous model had the module_init & module_exit function in the bus glue .c files themselves. That's a problem if several glues need to be selected at once and the driver is built has module. This case is quite common in embedded system where you want to handle both the integrated ohci controller and some extra controller on PCI. The ohci-hcd.c file now provide the module_init & module_exit and appropriate driver registering/unregistering is done conditionally, using #ifdefs. Signed-off-by: Sylvain Munaut Acked-by: David Brownell Signed-off-by: Greg Kroah-Hartman commit ad55d71a3d4401f44b4ddee1412283c99eedd05c Author: Ole Andre Vadla Ravnas Date: Thu Dec 14 16:01:28 2006 -0800 rndis_host learns ActiveSync basics Windows Mobile 5 based devices described as supporting "ActiveSync": - Speak RNDIS but lack the CDC and union descriptors. This patch updates the cdc ethernet code to fake ACM descriptors we need. - Require RNDIS_MSG_QUERY messages to include a buffer of the size the response should generate. This patch updates the rndis host code to pass this will-be-ignored data. The resulting RNDIS host code has been reported to work with several WM5 based devices. (Note that a fancier patch is available at synce.sf.net.) Some bugfixes, affecting not just ActiveSync: (a) when cleaning up after RNDS init fails, scrub the second interface just like cdc_ether does, so disconnect won't oops. (b) handle peripherals that use the pad-to-end-of-packet option; some devices can't talk to us if that option doesn't work. (c) when choosing configurations, don't forget about an RNDIS config just because the RNDIS driver is dynamically linked. Cleanup, streamlining, bugfixes, Kconfig, and matching hub driver update. Also for paranoia's sake, refuse to talk to something that looks like a real modem instead of RNDIS. Signed-off-by: Ole Andre Vadla Ravnaas Signed-off-by: David Brownell Signed-off-by: Greg Kroah-Hartman commit 11d5489873facd395653a4ee14669751bfe9bab5 Author: David Brownell Date: Mon Dec 11 15:59:04 2006 -0800 USB: ethernet gadget interop with MCCI Windows driver It turns out that minor tweaks to the "CDC Subset" support in the Ethernet gadget driver, just updating a config descriptor, let it be automagically recognized by a Windows driver supported by MCCI. This patch adds those descriptors, so systems using PXA 255 processors (like Gumstix etc) can interop with those commercial MS-Windows drivers. This is a Good Thing since Microsoft's RNDIS code has bugginess issues, which are unfortunately compounded by "won't fix" issues as well as "the published specs are incomplete and wrong" issues. Being able to talk to the MCCI driver gives Windows users another connectivity option. (MCCI also has CDC Ethernet drivers, which can help most non-PXA processors.) Signed-off-by: David Brownell Signed-off-by: Greg Kroah-Hartman commit 1737bf2c5e78e331ad0a30b8c34edd1016d043c0 Author: Alan Stern Date: Fri Dec 15 16:04:52 2006 -0500 usbcore: remove unneeded error check This patch (as830) removes some unnecessary error checking. According to the kerneldoc, schedule_work() can't fail. Signed-off-by: Alan Stern Signed-off-by: Greg Kroah-Hartman commit 2360e4aa64da412c29136113f8050b6aa9e757b8 Author: David Brownell Date: Wed Dec 13 13:07:10 2006 -0800 USB: indicate active altsetting in proc/bus/usb/devices file Update /proc/bus/usb/devices output to report active altsettings. Signed-off-by: David Brownell Signed-off-by: Greg Kroah-Hartman commit 316547fdfae1be3847add6a18a711703e6d5ebc1 Author: Dan Carpenter Date: Wed Dec 13 00:03:38 2006 -0800 USB: devio.c add missing INIT_LIST_HEAD() It should hopefully fix the list corruption bug on: https://bugzilla.redhat.com/bugzilla/show_bug.cgi?id=214402 Add a missing INIT_LIST_HEAD() Signed-off-by: Dan Carpenter Signed-off-by: Greg Kroah-Hartman commit 2cba72f02559ec0bbbcdba8d2604517515b55f03 Author: Oliver Neukum Date: Fri Dec 15 23:48:56 2006 +0100 USB: mutexification of rio500 this makes the rio500 misc usb driver use mutexes and turns uninterruptible sleep into interruptible sleep where the semantics are not affected. Signed-off-by: Oliver Neukum Signed-off-by: Greg Kroah-Hartman commit 4727810705d3cf8d565a2cd6c1045bc1db7d3532 Author: Tobias Klauser Date: Wed Dec 20 11:42:12 2006 +0100 USB: Remove unneeded void * casts in idmouse.c The patch removes unneeded void * casts for the following (void *) pointers: - struct file: private_data The patch also contains some whitespace and coding style cleanups in the relevant areas. Signed-off-by: Tobias Klauser Signed-off-by: Greg Kroah-Hartman commit e7d8712c15e087ba6201e5988d618ee03dfe693c Author: David Brownell Date: Tue Dec 12 15:12:30 2006 -0800 USB: define USB_CLASS_MISC in Add USB_CLASS_MISC to Signed-off-by: David Brownell Signed-off-by: Greg Kroah-Hartman commit 5f848137744106ee737f559454ce5adfceb38347 Author: David Brownell Date: Sat Dec 16 15:34:53 2006 -0800 USB: becomes This moves to to reduce some of the clutter of usb header files. Signed-off-by: David Brownell Signed-off-by: Greg Kroah-Hartman commit d728e327d4f86df439fa6b6f2f64b278394a58cc Author: Benjamin Herrenschmidt Date: Thu Dec 28 15:27:27 2006 +1100 USB: Fix EHCI warning This patch fixes a warning introduced by the big endian MMIO EHCI support patch on platforms that don't have readl_be/writel_be variants (though mostly harmless as those are called in an if (0) statement, but gcc still warns). Signed-off-by: Benjamin Herrenschmidt commit b32e904d54d163c6f97fc3c7586d381f4f11c3a5 Author: Benjamin Herrenschmidt Date: Thu Dec 28 15:26:59 2006 +1100 USB: Fix OHCI warning This patch fixes a warning introduces by the split endian OHCI support patch on platforms that don't have readl_be/writel_be variants (though mostly harmless as those are called in an if (0) statement, but gcc still warns). Signed-off-by: Benjamin Herrenschmidt Signed-off-by: Greg Kroah-Hartman commit 083522d76662cda71328df1f3d75e5a9057c7c9f Author: Benjamin Herrenschmidt Date: Fri Dec 15 06:54:08 2006 +1100 USB: Implement support for EHCI with big endian MMIO This patch implements supports for EHCI controllers whose MMIO registers are big endian and enables that functionality for the Toshiba SCC chip. It does _not_ add support for big endian in-memory data structures as this is not needed for that chip and I hope it will never be. The guts of the patch are to convert readl(...) to ehci_readl(ehci, ...) and similarly for register writes. Signed-off-by: Kou Ishizaki Signed-off-by: Benjamin Herrenschmidt Acked-by: Geoff Levand Acked-by: David Brownell Signed-off-by: Greg Kroah-Hartman commit 11d1a4aa8d657478cb2e5d33f203ba8f01b9ac24 Author: Benjamin Herrenschmidt Date: Fri Dec 15 06:54:03 2006 +1100 USB: Implement support for "split" endian OHCI This patch separates support for big endian MMIO register access and big endian descriptors in order to support the Toshiba SCC implementation which has big endian registers but little endian in-memory descriptors. It simplifies the access functions a bit in ohci.h while at it. Signed-off-by: Benjamin Herrenschmidt Acked-by: David Brownell Acked-by: Geoff Levand Signed-off-by: Greg Kroah-Hartman commit 4302a595cd9c6363b495460497ecbda49fa16858 Author: Benjamin Herrenschmidt Date: Fri Dec 15 06:53:55 2006 +1100 USB: Rework the OHCI quirk mecanism as suggested by David This patch applies David Brownell's suggestion for reworking the OHCI quirk mechanism via a table of PCI IDs. It adapts the existing quirks to use that mechanism. This also moves the quirks to reset() as suggested by the comment in there. This is necessary as we need to have the endian properly set before we try to init the controller. Signed-off-by: Benjamin Herrenschmidt Acked-by: David Brownell Acked-by: Geoff Levand Signed-off-by: Greg Kroah-Hartman commit 0873c76485c126a4df70a6961fd354b21b7987f7 Author: Greg Kroah-Hartman Date: Tue Jun 20 13:09:50 2006 -0700 USB: convert usb class devices to real devices Signed-off-by: Greg Kroah-Hartman commit 7bc3d635628db100c024aca7f836a18188e9bb62 Author: Greg Kroah-Hartman Date: Mon Jun 19 23:59:31 2006 -0700 USB: move usb_device_class class devices to be real devices This moves the usb class devices that control the usbfs nodes to show up in the proper place in the larger device tree. Cc: Kay Sievers Signed-off-by: Greg Kroah-Hartman commit 6e8cf7751f9fb913095d6142d068f41fbf0424bb Author: Greg Kroah-Hartman Date: Thu Jan 18 00:20:19 2007 -0800 USB: add EPIC support to the io_edgeport driver This patch adds EPiC support to the io_edgeport driver which adds support for a number of NCR printers: - NCR (Axiohm) 7401-K580 printer - NCR (TEC) 7401-K590 printer, 7402-K592 - NCR (TEC) 7167, 7168 printers - NCR (TEC) 7197, 7198, F306, F307, F309 printers - NCR (Axiohm) 7194 printer - NCR (Axiohm) 7158 printer and a few more. It is based on the 2.6.19 kernel. Signed-off-by: Greg Kroah-Hartman commit 20b2e28fc5557cda2cc840f44c6744b61b068ad6 Author: Luiz Fernando N. Capitulino Date: Wed Jan 24 16:19:37 2007 -0200 USB: unusual_devs.h for Sony floppy This patch increases the range for 0x054c:0x002c devices to make the following Sony USB floppy to work: T: Bus=02 Lev=01 Prnt=01 Port=02 Cnt=02 Dev#= 6 Spd=12 MxCh= 0 D: Ver= 1.10 Cls=00(>ifc ) Sub=00 Prot=00 MxPS=64 #Cfgs= 1 P: Vendor=054c ProdID=002c Rev=20.00 S: Manufacturer=SONY S: Product=USB Floppy C:* #Ifs= 1 Cfg#= 1 Atr=80 MxPwr=500mA I: If#= 0 Alt= 0 #EPs= 3 Cls=08(stor.) Sub=04 Prot=00 Driver=usb-storage E: Ad=82(I) Atr=02(Bulk) MxPS= 64 Ivl=0ms E: Ad=01(O) Atr=02(Bulk) MxPS= 64 Ivl=0ms E: Ad=83(I) Atr=03(Int.) MxPS= 2 Ivl=127ms Signed-off-by: Marcelo Ricardo Leitner Signed-off-by: Luiz Fernando N. Capitulino Signed-off-by: Greg Kroah-Hartman commit 55048021177eee956af88333ec4565919c8567e4 Author: Mariusz Kozlowski Date: Mon Feb 5 16:38:53 2007 -0800 [SCSI] aic79xx: fix bracket mismatch in unused macro Signed-off-by: Mariusz Kozlowski Signed-off-by: Andrew Morton Signed-off-by: James Bottomley commit 2065e310cc116e4b2b0f42faaf27f0c9baaca9cd Author: Richard Knutsson Date: Mon Feb 5 16:39:01 2007 -0800 [SCSI] BusLogic: Replace 'boolean' by 'bool' Signed-off-by: Richard Knutsson Signed-off-by: Andrew Morton Signed-off-by: James Bottomley commit bff288c19e8b6217ddd660d4fa42c29a0ab1d58c Author: Oleg Verych Date: Wed Feb 7 23:04:35 2007 +0100 [PATCH] kbuild, Kbuild.include: avoid using spaces in call arguments Do not use whitespace in arguments of functions in makefiles, as they propagate further without notice. Thus we get + echo ' y' instead of + echo y Fix misleading comments. Signed-off-by: Oleg Verych Signed-off-by: Linus Torvalds commit 35d6848322364b396484b5fcc450f6b009a3dac4 Author: Ken Witherow Date: Mon Feb 5 16:38:28 2007 -0800 [SCSI] advansys: clean up warnings Fix typecast warnings and switch from check_region to request_region (akpm: Ken and Jeffrey Phillips Freeman are possible advansys testers) Signed-off-by: Ken Witherow Signed-off-by: Andrew Morton Signed-off-by: James Bottomley commit a84cb1e82dc4ada9f93e708fa606fa918710a338 Author: Mariusz Kozlowski Date: Mon Feb 5 16:38:53 2007 -0800 [SCSI] 53c7xx: brackets fix in uncompiled code Signed-off-by: Mariusz Kozlowski Signed-off-by: Andrew Morton Signed-off-by: James Bottomley commit af0db3a8ab9917e9a0184470a2995dd8fe66c6e2 Author: Michal Piotrowski Date: Mon Feb 5 16:38:36 2007 -0800 [SCSI] nsp_cs: remove old scsi code Signed-off-by: Michal Piotrowski Signed-off-by: Andrew Morton Signed-off-by: James Bottomley commit a76106afbeb0c7d50762e7e5239496e5f7a0a074 Author: Adrian Bunk Date: Mon Feb 5 16:38:27 2007 -0800 [SCSI] aic79xx: make ahd_match_scb() static Signed-off-by: Adrian Bunk Acked-by: Hannes Reinecke Signed-off-by: Andrew Morton Signed-off-by: James Bottomley commit 0a361e31864f0822671703963f52957b3f275b93 Author: Ahmed S. Darwish Date: Mon Feb 5 16:38:55 2007 -0800 [SCSI] DAC960: kmalloc->kzalloc/Casting cleanups A patch to switch kmalloc->kzalloc and to clean unneeded kammloc, pci_alloc_consistent casts Signed-off-by: Ahmed Darwish Signed-off-by: Andrew Morton Signed-off-by: James Bottomley commit 22cfefb56b53103a99908ec63311e61c217eaffe Author: Andrew Morton Date: Mon Feb 5 16:39:03 2007 -0800 [SCSI] scsi_kmap_atomic_sg(): check that local irqs are disabled The KM_BIO_SRC_IRQ kmap slot must be taken with local irqs disabled. Add a check into scsi for this. Cc: James Bottomley Signed-off-by: Andrew Morton Signed-off-by: James Bottomley commit ff05d1c4643dd4260eb699396043d7e8009c0de4 Author: Joel Becker Date: Tue Jan 23 17:00:45 2007 -0800 configfs: Zero terminate data in configfs attribute writes. Attributes in configfs are text files. As such, most handlers expect to be able to call functions like simple_strtoul() without checking the bounds of the buffer. Change the call to zero terminate the buffer before calling the client's ->store() method. This does reduce the attribute size from PAGE_SIZE to PAGE_SIZE-1. Also, change get_zeroed_page() to alloc_page(), as we are handling the termination. Signed-off-by: Joel Becker Signed-off-by: Mark Fasheh commit b559292e066f6d570cd5aa5dbd41de61dd04bdce Author: Philipp Reisner Date: Thu Jan 11 10:58:10 2007 +0100 [PATCH] ocfs2 heartbeat: clean up bio submission code As was already pointed out Mathieu Avila on Thu, 07 Sep 2006 03:15:25 -0700 that OCFS2 is expecting bio_add_page() to add pages to BIOs in an easily predictable manner. That is not true, especially for devices with own merge_bvec_fn(). Therefore OCFS2's heartbeat code is very likely to fail on such devices. Move the bio_put() call into the bio's bi_end_io() function. This makes the whole idea of trying to predict the behaviour of bio_add_page() unnecessary. Removed compute_max_sectors() and o2hb_compute_request_limits(). Signed-off-by: Philipp Reisner Signed-off-by: Mark Fasheh commit 925037bcba7691db2403684141a276930ad184f3 Author: Zhen Wei Date: Tue Jan 23 17:19:59 2007 -0800 ocfs2: introduce sc->sc_send_lock to protect outbound outbound messages When there is a lot of multithreaded I/O usage, two threads can collide while sending out a message to the other nodes. This is due to the lack of locking between threads while sending out the messages. When a connected TCP send(), sendto(), or sendmsg() arrives in the Linux kernel, it eventually comes through tcp_sendmsg(). tcp_sendmsg() protects itself by acquiring a lock at invocation by calling lock_sock(). tcp_sendmsg() then loops over the buffers in the iovec, allocating associated sk_buff's and cache pages for use in the actual send. As it does so, it pushes the data out to tcp for actual transmission. However, if one of those allocation fails (because a large number of large sends is being processed, for example), it must wait for memory to become available. It does so by jumping to wait_for_sndbuf or wait_for_memory, both of which eventually cause a call to sk_stream_wait_memory(). sk_stream_wait_memory() contains a code path that calls sk_wait_event(). Finally, sk_wait_event() contains the call to release_sock(). The following patch adds a lock to the socket container in order to properly serialize outbound requests. From: Zhen Wei Acked-by: Jeff Mahoney Signed-off-by: Mark Fasheh commit f71aa8a55a0ae1a0d06c6079265d16502a678e8e Author: Randy Dunlap Date: Thu Jan 25 14:51:50 2007 -0800 [PATCH] ocfs2: drop INET from Kconfig, not needed OCFS2: drop 'depends on INET' since local mounts are now allowed. Signed-off-by: Randy Dunlap Signed-off-by: Mark Fasheh commit 0dd82141b236ce36253e3056c6068ee3d5732196 Author: Sunil Mushran Date: Mon Jan 29 15:44:27 2007 -0800 ocfs2_dlm: Add timeout to dlm join domain Currently the ocfs2 dlm has no timeout during dlm join domain. While this is not a problem in normal operation, this does become an issue if, say, the other node is refusing to let the node join the domain because of a stuck recovery. This patch adds a 90 sec timeout. Signed-off-by: Sunil Mushran Signed-off-by: Mark Fasheh commit e4968476a9bc5a6b30076076b4f3ce3e692e0d79 Author: Sunil Mushran Date: Mon Jan 29 15:37:02 2007 -0800 ocfs2_dlm: Silence some messages during join domain These messages can easily be activated using the mlog infrastructure and don't need to be enabled by default. Signed-off-by: Sunil Mushran Signed-off-by: Mark Fasheh commit 1faf289454b9eeb6e463da3eee47f7009668370d Author: Srinivas Eeda Date: Mon Jan 29 15:31:35 2007 -0800 ocfs2_dlm: disallow a domain join if node maps mismatch There is a small window where a joining node may not see the node(s) that just died but are still part of the domain. To fix this, we must disallow join requests if the joining node has a different node map. A new field node_map is added to dlm_query_join_request to send the current nodes nodemap along with join request. On the receiving end the nodes that are part of the cluster verifies if this new node sees all the nodes that are still part of the cluster. They disallow the join if the maps mismatch. Signed-off-by: Srinivas Eeda Signed-off-by: Mark Fasheh commit f3f854648de64c4b6f13f6f13113bc9525c621e5 Author: Sunil Mushran Date: Mon Jan 29 15:19:16 2007 -0800 ocfs2_dlm: Ensure correct ordering of set/clear refmap bit on lockres Eventhough the set refmap bit message is sent before the clear refmap message, currently there is no guarentee that the set message will be handled before the clear. This patch prevents the clear refmap to be processed while the node is sending assert master messages to other nodes. (The set refmap message is sent as a response to the assert master request). Signed-off-by: Sunil Mushran Signed-off-by: Mark Fasheh commit ab81afd30bc154bb1e8749e5aeeffe9b93c90834 Author: Sunil Mushran Date: Mon Jan 29 14:57:14 2007 -0800 ocfs2: Binds listener to the configured ip address This patch binds the o2net listener to the configured ip address instead of INADDR_ANY for security. Fixes oss.oracle.com bugzilla#814. Signed-off-by: Sunil Mushran Signed-off-by: Mark Fasheh commit 3b8118cffad224415c6f6f35abe7ca2a1d79c05a Author: Kurt Hackel Date: Wed Jan 17 17:05:53 2007 -0800 ocfs2_dlm: Calling post handler function in assert master handler This patch prevents the dlm from sending the clear refmap message before the set refmap. We use the newly created post function handler routine to accomplish the task. Signed-off-by: Kurt Hackel Signed-off-by: Sunil Mushran Signed-off-by: Mark Fasheh commit d74c9803a90d733f5fb7270475aa6d14b45796c6 Author: Kurt Hackel Date: Wed Jan 17 17:04:25 2007 -0800 ocfs2: Added post handler callable function in o2net message handler Currently o2net allows one handler function per message type. This patch adds the ability to call another function to be called after the handler has returned the message to the other node. Handlers are now given the option of returning a context (in the form of a void **) which will be passed back into the post message handler function. Signed-off-by: Kurt Hackel Signed-off-by: Sunil Mushran Signed-off-by: Mark Fasheh commit 74aa25856c693d20a886cdb31a004aaca411d135 Author: Kurt Hackel Date: Wed Jan 17 15:11:36 2007 -0800 ocfs2_dlm: Cookies in locks not being printed correctly in error messages The dlm encodes the node number and a sequence number in the lock cookie. It also stores the cookie in the lockres in the big endian format to avoid swapping 8 bytes on each lock request. The bug here was that it was assuming the cookie to be in the cpu format when decoding it for printing the error message. This patch swaps the bytes before the print. Signed-off-by: Kurt Hackel Signed-off-by: Sunil Mushran Signed-off-by: Mark Fasheh commit 90aaaf1c235a70daee04e897e9501415b766de69 Author: Kurt Hackel Date: Wed Jan 17 15:01:45 2007 -0800 ocfs2_dlm: Silence a failed convert When the lockres is in migrate or recovery state, all convert requests are denied with the appropriate error status that is handled on the requester node. This patch silences the erroneous error message printed on the master node. Signed-off-by: Kurt Hackel Signed-off-by: Sunil Mushran Signed-off-by: Mark Fasheh commit a6fa36402aba96362311318200d710ea1719e59b Author: Kurt Hackel Date: Wed Jan 17 14:59:12 2007 -0800 ocfs2_dlm: wake up sleepers on the lockres waitqueue The dlm was not waking up threads waiting on the lockres wait queue, waiting for the lockres to be no longer be in the DLM_LOCK_RES_IN_PROGRESS and the DLM_LOCK_RES_MIGRATING states. Signed-off-by: Kurt Hackel Signed-off-by: Sunil Mushran Signed-off-by: Mark Fasheh commit 28b72d9c92ed43e01e4094f57bcad1814b002779 Author: Kurt Hackel Date: Wed Jan 17 14:57:50 2007 -0800 ocfs2_dlm: Dlm dispatch was stopping too early dlm_dispatch_work was not processing the queued up tasks at the first sign of the node leaving the domain leading to not only incompleted tasks but also a mismatch in the dlm refcnt. Signed-off-by: Kurt Hackel Signed-off-by: Sunil Mushran Signed-off-by: Mark Fasheh commit 50635f15b324cbf45a58f103e6b4c7e42502b683 Author: Kurt Hackel Date: Wed Jan 17 14:54:39 2007 -0800 ocfs2_dlm: Drop inflight refmap even if no locks found on the lockres Signed-off-by: Kurt Hackel Signed-off-by: Sunil Mushran Signed-off-by: Mark Fasheh commit 1cd04dbe3364be71b93e3aaf4545daa1e261aaa1 Author: Kurt Hackel Date: Wed Jan 17 14:53:37 2007 -0800 ocfs2_dlm: Flush dlm workqueue before starting to migrate This is to prevent the condition in which a previously queued up assert master asserts after we start the migration. Now migration ensures the workqueue is flushed before proceeding with migrating the lock to another node. This condition is typically encountered during parallel umounts. Signed-off-by: Kurt Hackel Signed-off-by: Sunil Mushran Signed-off-by: Mark Fasheh commit e17e75ecb86b8ce9b51b219b5348517561031f80 Author: Kurt Hackel Date: Fri Jan 5 15:04:49 2007 -0800 ocfs2_dlm: Fix migrate lockres handler queue scanning The migrate lockres handler was only searching for its lock on migrated lockres on the expected queue. This could be problematic as the new master could have also issued a convert request during the migration and thus moved the lock to the convert queue. We now search for the lock on all three queues. Signed-off-by: Kurt Hackel Signed-off-by: Sunil Mushran Signed-off-by: Mark Fasheh commit 71ac1062435ba2d58bf64817b47a6e44f316752e Author: Kurt Hackel Date: Fri Jan 5 15:02:30 2007 -0800 ocfs2_dlm: Make dlmunlock() wait for migration to complete dlmunlock() was not waiting for migration to complete before releasing locks on locally mastered locks. Signed-off-by: Kurt Hackel Signed-off-by: Sunil Mushran Signed-off-by: Mark Fasheh commit ddc09c8ddac8d0f170ba8caa8128801f358dccff Author: Kurt Hackel Date: Fri Jan 5 15:00:17 2007 -0800 ocfs2_dlm: Fixes race between migrate and dirty dlmthread was removing lockres' from the dirty list and resetting the dirty flag before shuffling the list. This patch retains the dirty state flag until the lists are shuffled. Signed-off-by: Kurt Hackel Signed-off-by: Sunil Mushran Signed-off-by: Mark Fasheh commit faf0ec9f13defb57f4269ecb22ed86f2874ee89a Author: Adrian Bunk Date: Thu Dec 14 00:17:32 2006 +0100 [PATCH] fs/ocfs2/dlm/: make functions static This patch makes some needlessly global functions static. Signed-off-by: Adrian Bunk Signed-off-by: Mark Fasheh commit ba2bf2185121db74e075c703fbf986761733dd1d Author: Kurt Hackel Date: Fri Dec 1 14:47:20 2006 -0800 ocfs2_dlm: fix cluster-wide refcounting of lock resources This was previously broken and migration of some locks had to be temporarily disabled. We use a new (and backward-incompatible) set of network messages to account for all references to a lock resources held across the cluster. once these are all freed, the master node may then free the lock resource memory once its local references are dropped. Signed-off-by: Kurt Hackel Signed-off-by: Mark Fasheh commit b592fcfe7f06c15ec11774b5be7ce0de3aa86e73 Author: Eric W. Biederman Date: Wed Jan 24 12:35:52 2007 -0700 sysfs: Shadow directory support The problem. When implementing a network namespace I need to be able to have multiple network devices with the same name. Currently this is a problem for /sys/class/net/*. What I want is a separate /sys/class/net directory in sysfs for each network namespace, and I want to name each of them /sys/class/net. I looked and the VFS actually allows that. All that is needed is for /sys/class/net to implement a follow link method to redirect lookups to the real directory you want. Implementing a follow link method that is sensitive to the current network namespace turns out to be 3 lines of code so it looks like a clean approach. Modifying sysfs so it doesn't get in my was is a bit trickier. I am calling the concept of multiple directories all at the same path in the filesystem shadow directories. With the directory entry really at that location the shadow master. The following patch modifies sysfs so it can handle a directory structure slightly different from the kobject tree so I can implement the shadow directories for handling /sys/class/net/. Signed-off-by: Eric W. Biederman Cc: Maneesh Soni Signed-off-by: Greg Kroah-Hartman commit 2f65168de7d68a5795e945e781d85b313bdc97b9 Author: Dave Jones Date: Thu Jan 25 15:56:15 2007 -0500 Driver Core: Increase the default timeout value of the firmware subsystem https://bugzilla.redhat.com/bugzilla/show_bug.cgi?id=174589 The ipw driver sometimes takes a long time to load its firmware. Whilst the ipw driver should be using the async interface of the firmware loader to make this a non-issue, this is a minimal fix. Signed-off-by: Dave Jones Signed-off-by: Greg Kroah-Hartman commit b7a3e813fb84624166f034e25234f98de5846bfc Author: Kay Sievers Date: Sat Oct 7 21:54:55 2006 +0200 Driver core: allow to delay the uevent at device creation time For the block subsystem, we want to delay all uevents until the disk has been scanned and allpartitons are already created before the first event is sent out. Signed-off-by: Kay Sievers Signed-off-by: Greg Kroah-Hartman commit f9f852df2faf76a2667949ddb4947d4b8f99f02f Author: Kay Sievers Date: Sat Oct 7 21:54:55 2006 +0200 Driver core: add device_type to struct device This allows us to add type specific attributes, uevent vars and release funtions. A subsystem can carry different types of devices like the "block" subsys has disks and partitions. Both types create a different set of attributes, but belong to the same subsystem. This corresponds to the low level objects: kobject -> device (object/device data) kobj_type -> device_type (type of object/device we are embedded in) kset -> class/bus (list of objects/devices of a subsystem) Signed-off-by: Kay Sievers Signed-off-by: Greg Kroah-Hartman commit 239378f16aa1ab5c502e42a06359d2de4f88ebb4 Author: Kay Sievers Date: Sat Oct 7 21:54:55 2006 +0200 Driver core: add uevent vars for devices of a class Devices converted from class_device to device should have the same uevent keys as the original class_device had. We search up the parents until we find the first bus device and add the (already deprecated) PHYDEV* values. Signed-off-by: Kay Sievers Signed-off-by: Greg Kroah-Hartman commit bf0acc330229554c695e4f95e5aa2d2c4f12de1f Author: Frank Haverkamp Date: Wed Jan 17 17:51:18 2007 +0100 SYSFS: Fix missing include of list.h in sysfs.h Sysfs.h uses definitions (e.g. struct list_head s_sibling) from list.h but does not include it. Signed-off-by: Frank Haverkamp Signed-off-by: Greg Kroah-Hartman commit 4de0ca8132861a4255d0a7a991bdfab38378267c Author: Robert P. J. Day Date: Wed Jan 17 04:54:07 2007 -0500 HOWTO: Add a reference to Harbison and Steele Add a reference to Harbison and Steele's C book. Signed-off-by: Robert P. J. Day Signed-off-by: Greg Kroah-Hartman commit 82244b169ed2eee1ef7f97a3a6693f5a6eff8a69 Author: Oliver Neukum Date: Tue Jan 2 08:48:08 2007 +0100 sysfs: error handling in sysfs, fill_read_buffer() if a driver returns an error in fill_read_buffer(), the buffer will be marked as filled. Subsequent reads will return eof. But there is no data because of an error, not because it has been read. Not marking the buffer filled is the obvious fix. Signed-off-by: Oliver Neukum Signed-off-by: Greg Kroah-Hartman commit b067db49e1f4013ef02ef68845701b600e88a722 Author: Mariusz Kozlowski Date: Tue Jan 2 13:44:44 2007 +0100 kobject: kobject_put cleanup This patch removes redundant argument checks for kobject_put(). Signed-off-by: Mariusz Kozlowski Signed-off-by: Greg Kroah-Hartman commit f75065367077bd3b77842a5aa523ecd05d33e82d Author: Mariusz Kozlowski Date: Tue Jan 2 13:41:10 2007 +0100 sysfs: kobject_put cleanup This patch removes redundant argument checks for kobject_put(). Signed-off-by: Mariusz Kozlowski Signed-off-by: Greg Kroah-Hartman commit d3fc373ac5061cab7a654502b942e7d00e77f733 Author: Frederik Deweerdt Date: Fri Jan 5 12:04:33 2007 -0800 sysfs: suppress lockdep warnings Lockdep issues the following warning: [ 9.064000] ============================================= [ 9.064000] [ INFO: possible recursive locking detected ] [ 9.064000] 2.6.20-rc3-mm1 #3 [ 9.064000] --------------------------------------------- [ 9.064000] init/1 is trying to acquire lock: [ 9.064000] (&sysfs_inode_imutex_key){--..}, at: [] mutex_lock+0x1c/0x1f [ 9.064000] [ 9.064000] but task is already holding lock: [ 9.064000] (&sysfs_inode_imutex_key){--..}, at: [] mutex_lock+0x1c/0x1f [ 9.065000] [ 9.065000] other info that might help us debug this: [ 9.065000] 2 locks held by init/1: [ 9.065000] #0: (tty_mutex){--..}, at: [] mutex_lock+0x1c/0x1f [ 9.065000] #1: (&sysfs_inode_imutex_key){--..}, at: [] mutex_lock+0x1c/0x1f [ 9.065000] [ 9.065000] stack backtrace: [ 9.065000] [] show_trace_log_lvl+0x1a/0x30 [ 9.066000] [] show_trace+0x12/0x14 [ 9.066000] [] dump_stack+0x16/0x18 [ 9.066000] [] print_deadlock_bug+0xb9/0xc3 [ 9.066000] [] check_deadlock+0x55/0x5a [ 9.066000] [] __lock_acquire+0x371/0xbf0 [ 9.066000] [] lock_acquire+0x69/0x83 [ 9.066000] [] __mutex_lock_slowpath+0x75/0x2d1 [ 9.066000] [] mutex_lock+0x1c/0x1f [ 9.066000] [] sysfs_drop_dentry+0xb1/0x133 [ 9.066000] [] sysfs_hash_and_remove+0xb3/0x142 [ 9.066000] [] sysfs_remove_file+0xd/0x10 [ 9.067000] [] device_remove_file+0x23/0x2e [ 9.067000] [] device_del+0x188/0x1e6 [ 9.067000] [] device_unregister+0xb/0x15 [ 9.067000] [] device_destroy+0x9c/0xa9 [ 9.067000] [] vcs_remove_sysfs+0x1c/0x3b [ 9.067000] [] con_close+0x5e/0x6b [ 9.067000] [] release_dev+0x4c4/0x6e5 [ 9.067000] [] tty_release+0x12/0x1c [ 9.067000] [] __fput+0x177/0x1a0 [ 9.067000] [] fput+0x3b/0x41 [ 9.068000] [] filp_close+0x36/0x65 [ 9.068000] [] sys_close+0x63/0xa4 [ 9.068000] [] sysenter_past_esp+0x5f/0x99 [ 9.068000] ======================= This is due to sysfs_hash_and_remove() holding dir->d_inode->i_mutex before calling sysfs_drop_dentry() which calls orphan_all_buffers() which in turn takes node->i_mutex. Signed-off-by: Frederik Deweerdt Cc: Oliver Neukum Signed-off-by: Andrew Morton Signed-off-by: Greg Kroah-Hartman commit 94bebf4d1b8e7719f0f3944c037a21cfd99a4af7 Author: Oliver Neukum Date: Wed Dec 20 10:52:44 2006 +0100 Driver core: fix race in sysfs between sysfs_remove_file() and read()/write() This patch prevents a race between IO and removing a file from sysfs. It introduces a list of sysfs_buffers associated with a file at the inode. Upon removal of a file the list is walked and the buffers marked orphaned. IO to orphaned buffers fails with -ENODEV. The driver can safely free associated data structures or be unloaded. Signed-off-by: Oliver Neukum Acked-by: Maneesh Soni Signed-off-by: Greg Kroah-Hartman commit cb986b749c7178422bfbc982cd30e04d5db54bbc Author: Cornelia Huck Date: Mon Nov 27 10:35:12 2006 +0100 driver core: Change function call order in device_bind_driver(). Change function call order in device_bind_driver(). If we create symlinks (which might fail) before adding the device to the list we don't have to clean up afterwards (which we didn't). Signed-off-by: Cornelia Huck Signed-off-by: Greg Kroah-Hartman commit c578abbc20762aa58e390e55252959853eeea17e Author: Cornelia Huck Date: Mon Nov 27 10:35:10 2006 +0100 driver core: Don't stop probing on ->probe errors. Don't stop on the first ->probe error that is not -ENODEV/-ENXIO. There might be a driver registered returning an unresonable return code, and this stops probing completely even though it may make sense to try the next possible driver. At worst, we may end up with an unbound device. Signed-off-by: Cornelia Huck Signed-off-by: Greg Kroah-Hartman commit fbfb14455391b89edcf37327526988dea7849532 Author: Cornelia Huck Date: Mon Nov 27 10:35:08 2006 +0100 driver core fixes: device_register() retval check in platform.c Check the return value of device_register() in platform_bus_init(). Signed-off-by: Cornelia Huck Signed-off-by: Greg Kroah-Hartman commit cb360bbf6352712310a7528137919c626a782744 Author: Cornelia Huck Date: Mon Nov 27 10:35:05 2006 +0100 driver core fixes: make_class_name() retval checks Make make_class_name() return NULL on error and fixup callers in the driver core. Signed-off-by: Cornelia Huck Signed-off-by: Greg Kroah-Hartman commit 270a6c4cad809e92d7b81adde92d0b3d94eeb8ee Author: Kay Sievers Date: Thu Jan 18 13:26:15 2007 +0100 /sys/modules/*/holders /sys/module/usbcore/ |-- drivers | |-- usb:hub -> ../../../subsystem/usb/drivers/hub | |-- usb:usb -> ../../../subsystem/usb/drivers/usb | `-- usb:usbfs -> ../../../subsystem/usb/drivers/usbfs |-- holders | |-- ehci_hcd -> ../../../module/ehci_hcd | |-- uhci_hcd -> ../../../module/uhci_hcd | |-- usb_storage -> ../../../module/usb_storage | `-- usbhid -> ../../../module/usbhid |-- initstate Signed-off-by: Kay Sievers Signed-off-by: Greg Kroah-Hartman commit 80f745fb1b0fb11383cbb8df2c36aaaa0399b6e6 Author: Greg Kroah-Hartman Date: Mon Jan 15 11:50:02 2007 -0800 USB: add the sysfs driver name to all modules This adds the module name to all USB drivers, if they are built into the kernel or not. It will show up in /sys/modules/MODULE_NAME/drivers/ Cc: Kay Sievers Signed-off-by: Greg Kroah-Hartman commit 4b315627e6b894156e235ac905786e7d46aab2e6 Author: Greg Kroah-Hartman Date: Mon Jan 15 11:50:02 2007 -0800 SERIO: add the sysfs driver name to all modules This adds the module name to all SERIO drivers, if they are built into the kernel or not. It will show up in /sys/modules/MODULE_NAME/drivers/ Cc: Kay Sievers Signed-off-by: Greg Kroah-Hartman commit 725522b5453dd680412f2b6463a988e4fd148757 Author: Greg Kroah-Hartman Date: Mon Jan 15 11:50:02 2007 -0800 PCI: add the sysfs driver name to all modules This adds the module name to all PCI drivers, if they are built into the kernel or not. It will show up in /sys/modules/MODULE_NAME/drivers/ It also fixes up the IDE core, which was calling __pci_register_driver() directly. Cc: Kay Sievers Signed-off-by: Greg Kroah-Hartman commit fe480a2675ed236af396597d9f05245c7bbd0149 Author: Greg Kroah-Hartman Date: Mon Jan 15 11:50:02 2007 -0800 Modules: only add drivers/ direcory if needed This changes the module core to only create the drivers/ directory if we are going to put something in it. Cc: Kay Sievers Signed-off-by: Greg Kroah-Hartman commit f30c53a873d0d227493197064b8886af2d57bbd6 Author: Kay Sievers Date: Mon Jan 15 20:22:02 2007 +0100 MODULES: add the module name for built in kernel drivers Signed-off-by: Kay Sievers Signed-off-by: Greg Kroah-Hartman commit c744aeae9d173a953b771a7ad5c872f91fa99dec Author: Cornelia Huck Date: Mon Jan 8 20:16:44 2007 +0100 driver core: Allow device_move(dev, NULL). If we allow NULL as the new parent in device_move(), we need to make sure that the device is placed into the same place as it would if it was newly registered: - Consider the device virtual tree. In order to be able to reuse code, setup_parent() has been tweaked a bit. - kobject_move() can fall back to the kset's kobject. - sysfs_move_dir() uses the sysfs root dir as fallback. Signed-off-by: Cornelia Huck Cc: Marcel Holtmann Signed-off-by: Greg Kroah-Hartman commit 717e48c29d9a58f4d31c1651bec364212da5f6b2 Author: Cornelia Huck Date: Mon Jan 8 20:16:41 2007 +0100 driver core: Remove device_is_registered() in device_move(). device_is_registered() will always be false for a device with no bus. Remove this check and trust the caller to know what they're doing. Signed-off-by: Cornelia Huck Cc: Marcel Holtmann Signed-off-by: Greg Kroah-Hartman commit 43cb76d91ee85f579a69d42bc8efc08bac560278 Author: Greg Kroah-Hartman Date: Tue Apr 9 12:14:34 2002 -0700 Network: convert network devices to use struct device instead of class_device This lets the network core have the ability to handle suspend/resume issues, if it wants to. Thanks to Frederik Deweerdt for the arm driver fixes. Signed-off-by: Greg Kroah-Hartman commit 2943ecf2ed32632473c06f1975db47a7aa98c10f Author: Greg Kroah-Hartman Date: Mon Jan 22 13:45:38 2007 -0800 Driver core: convert SPI code to use struct device Converts from using struct "class_device" to "struct device" making everything show up properly in /sys/devices/ with symlinks from the /sys/class directory. Cc: Signed-off-by: Greg Kroah-Hartman commit 873733188a019acdb7fa253011cbdc0a8afd97f3 Author: Greg Kroah-Hartman Date: Tue Sep 12 17:00:10 2006 +0200 Driver core: convert pcmcia code to use struct device Converts from using struct "class_device" to "struct device" making everything show up properly in /sys/devices/ with symlinks from the /sys/class directory. Cc: Signed-off-by: Greg Kroah-Hartman commit 31b9025aa0f89b392077db3f87458fd46bcc4f58 Author: Greg Kroah-Hartman Date: Thu Jan 18 12:23:51 2007 -0800 Kobject: make kobject apis more robust in handling NULL pointers It should be ok to pass in NULL for some kobject functions, so add error checking for all exported kobject functions to be more robust. Cc: Kay Sievers Signed-off-by: Greg Kroah-Hartman commit 1e8f34f7d88c969a06229a786241839d49dd63e3 Author: Andrew Morton Date: Wed Feb 7 18:19:42 2007 +0100 ide-acpi support warning fix drivers/ide/ide-acpi.c: In function 'ide_acpi_get_timing': drivers/ide/ide-acpi.c:537: warning: format '%x' expects type 'unsigned int', but argument 4 has type 'long unsigned int' Signed-off-by: Andrew Morton Signed-off-by: Hannes Reinecke Signed-off-by: Bartlomiej Zolnierkiewicz commit e3a59b4d9378522479609042836ae930305a67fe Author: Hannes Reinecke Date: Wed Feb 7 18:19:37 2007 +0100 ACPI support for IDE devices This patch implements ACPI integration for generic IDE devices. The ACPI spec mandates that some methods are called during suspend and resume. And consequently there most modern Laptops cannot resume properly without it. According to the spec, we should call '_GTM' (Get Timing) upon suspend to store the current IDE adapter settings. Upon resume we should call '_STM' (Set Timing) to initialize the adapter with the stored settings; afterwards '_GTF' (Get Taskfile) should be called which returns a buffer with some IDE initialisation commands. Those commands should be passed to the drive. There are two module params which control the behaviour of this patch: 'ide=noacpi' Do not call any ACPI methods (Disables any ACPI method calls) 'ide=acpigtf' Enable execution of _GTF methods upon resume. Has no effect if 'ide=noacpi' is set. 'ide=acpionboot' Enable execution of ACPI methods during boot. This might be required on some machines if 'ide=acpigtf' is selected as some machines modify the _GTF information depending on the drive identification passed down with _STM. Signed-off-by: Hannes Reinecke Signed-off-by: Bartlomiej Zolnierkiewicz commit 78281c5350029e3fa21758d6db9b45ffc7bf72a1 Author: Mark Lord Date: Wed Feb 7 18:19:32 2007 +0100 IDE Driver for Delkin/Lexar/etc.. cardbus CF adapter On Thursday 11 January 2007 23:17, Bartlomiej Zolnierkiewicz wrote: > > My working IDE tree (against Linus' tree) now resides here: > > http://kernel.org/pub/linux/kernel/people/bart/pata-2.6/patches/ Bart, here's a driver I've been keeping out-of-tree for the past couple of years. This is for the Delking/Lexar/ASKA/etc.. 32-bit cardbus IDE CompactFlash adapter card. It's probably way out of sync with the latest driver model (??), but it still builds/works. I'm not interested in doing much of a rewrite, other than for libata someday, as I no longer use the card myself. But lots of other people do seem to use it, so it might be nice to see it "in-tree". Signed-off-by: Mark Lord Signed-off-by: Bartlomiej Zolnierkiewicz commit 6788182602f6862688d9a14e6f527449696f65c6 Author: Bartlomiej Zolnierkiewicz Date: Wed Feb 7 18:19:26 2007 +0100 ide: it8213 IDE driver update (version 2) * set ATAPI/IORDY/TIME bits correctly in it8213_tuneproc() * fix UDMA/MWDMA/SWDMA masks in it8213_init_hwif() * in it8213_tune_chipset() SWDMA2 mode should be used instead of MWDMA0 * backport various fixes from piix/slc90e66 drivers: - in it8213_tuneproc() the highest possible PIO mode is PIO4 (not PIO5) - clear ATAPI/IORDY/TIME bits before setting them also for slave device - use ->speedproc in it8213_config_drive_for_dma() - don't try to tune PIO in config_chipset_for_pio() - simplify is_slave calculation in it8213_tuneproc() - misc cleanups * fix it8213_ratemask() and it8213_tuneproc() comments * simplify it8213_init_hwif() * remove init_chipset_it8213() * add missing Copyrights and update MODULE_AUTHOR() * CodingStyle cleanups * remove dead code v2: * PCI_DEVICE_ID_ITE_8213 is only defined in -mm kernels, so just use PCI Device ID (0x8213) directly * fix ->ultra_mask incorrectly changed to 0x3f in v1 version of the patch Signed-off-by: Bartlomiej Zolnierkiewicz commit 9c6712c0bcd2954fb4ca58d31f7316292a4b0945 Author: Jack Lee Date: Wed Feb 7 18:19:09 2007 +0100 ide: add it8213 IDE driver From: Alan Cox Signed-off-by: Bartlomiej Zolnierkiewicz commit a534b68da0471dd9e4e3f7fc922faba74f8f4506 Author: Bartlomiej Zolnierkiewicz Date: Wed Feb 7 18:19:09 2007 +0100 tc86c001: add missing __init tag for tc86c001_ide_init() Signed-off-by: Bartlomiej Zolnierkiewicz commit ba59c4b84a064e3e9d72d98b56f92a5b2aa71c22 Author: Andrew Morton Date: Wed Feb 7 18:19:01 2007 +0100 tc86c001: mark init_chipset_tc86c001() with __devinit tag Signed-off-by: Andrew Morton Cc: Sergei Shtylyov Cc: Adrian Bunk Signed-off-by: Bartlomiej Zolnierkiewicz commit e8ab7f536f014e5d86ce6cf7860d5def6cc5f715 Author: Adrian Bunk Date: Wed Feb 7 18:18:52 2007 +0100 tc86c001: init_hwif_tc86c001() can be static Signed-off-by: Adrian Bunk Cc: Sergei Shtylyov Signed-off-by: Andrew Morton Signed-off-by: Bartlomiej Zolnierkiewicz commit 33dced2ea5ed03dda10e7f9f41f0910f32e02eaa Author: Sergei Shtylyov Date: Wed Feb 7 18:18:45 2007 +0100 ide: add Toshiba TC86C001 IDE driver (take 2) This is the driver for the Toshiba TC86C001 GOKU-S PCI IDE controller, completely reworked from the original brain-damaged Toshiba's 2.4 version. This single channel UltraDMA/66 controller is very simple in programming, yet Toshiba managed to plant many interesting bugs in it. The particularly nasty "limitation 5" (as they call the errata) caused me to abuse the IDE core in a possibly most interesting way so far. However, this is still better than the #ifdef mess in drivers/ide/ide-io.c that the original version included (well, it had much more mess)... Signed-off-by: Sergei Shtylyov Acked-by: Alan Cox Cc: Greg KH Signed-off-by: Andrew Morton Signed-off-by: Bartlomiej Zolnierkiewicz commit d24ec426b3be3a011bc8568d53fea486b604a684 Author: Sergei Shtylyov Date: Wed Feb 7 18:18:39 2007 +0100 pdc202xx_new: remove check_in_drive_lists abomination Fold check_in_drive_lists() into quirkproc() handler in both PDC202xx drivers-- this function was never called with a list other than pdc_quirk_drives and was a bad example of code overall... Signed-off-by: Sergei Shtylyov Cc: Alan Cox Signed-off-by: Andrew Morton Signed-off-by: Bartlomiej Zolnierkiewicz commit 272103144ac1ff937ed22917e1de05da4d6943dd Author: Sergei Shtylyov Date: Wed Feb 7 18:18:37 2007 +0100 pdc202xx_new: remove useless code Remove the following useless fragments from the driver: - the ide_dma_lostirq() and ide_dma_timeout() handlers which boil down to just printing the incoherent reset message and calling their default counterparts; - check for non-NULL drive->id in the ide_dma_check() handler -- this is assumed to be true by all other handlers (also, get rid of unnecessary nesting of the conditional statements there); - the comment before pdcnew_tune_drive() which has nothing to do with the code. Signed-off-by: Sergei Shtylyov Cc: Alan Cox Signed-off-by: Andrew Morton Signed-off-by: Bartlomiej Zolnierkiewicz commit 24e6458d9c0c445141488b70e1a01fa31ed86c8d Author: Sergei Shtylyov Date: Wed Feb 7 18:18:34 2007 +0100 slc90e66: carry over fixes from piix driver Synchronize with version 0.46 of the Intel PIIX/ICH driver: - carry over Alan's and my own fixes in the tuneproc() method and my cleanups both there and in the ratemask() method; - SLC90E66 only supports MW DMA modes 1/2 and SW DMA mode 2 (just like Intel chips), so don't claim support for other MW/SW DMA modes; - don't check dor non-NULL drive->id in the ide_dma_check() method -- this is assumed to be true in all other drivers; - do some coding/formatting cleanups while at it... Signed-off-by: Sergei Shtylyov Cc: Alan Cox Signed-off-by: Andrew Morton Signed-off-by: Bartlomiej Zolnierkiewicz commit 30dfd12f5384d30c0d0de05eb34d0e26352a20ff Author: Sergei Shtylyov Date: Wed Feb 7 18:18:28 2007 +0100 piix: tuneproc() fixes/cleanups Fix/cleanup the driver's tuneproc() and ratemask() methods: - PPE, IE, and TIME bits need to be cleared beforehand for the slave drive as well as master (Alan probably just forgot about it); - this driver only supports PIO modes up to 4, so must pass the correct limit to ide_get_best_pio_mode(); - use min_t() macro instead of min(); - simplify slave vs master drive evaluation; - do come coding and formatting cleanups... Signed-off-by: Sergei Shtylyov Cc: Alan Cox Signed-off-by: Andrew Morton Signed-off-by: Bartlomiej Zolnierkiewicz commit d2872239737ad6394b49c7c9ce9ae8d0f07165e5 Author: Sergei Shtylyov Date: Wed Feb 7 18:18:25 2007 +0100 piix: fix 82371MX enablebits According to the datasheet, Intel 82371MX (MPIIX) actually has only a single IDE channel mapped to the primary or secondary ports depending on the value of the bit 14 of the IDETIM register at PCI config. offset 0x6C (the register at 0x6F which the driver refers to. doesn't exist). So, disguise the controller as dual channel and set enablebits masks/values such that only either primary or secondary channel is detected enabled. Also, preclude the IDE probing code from reading PCI BARs, this controller just doesn't have them (it's not the separate PCI function like the other PCI controllers), it only decodes the legacy addresses. [ Alan sayeth " MPIIX does not work with or without the change. It needs its own different driver and not to use setup-pci. Huge job and since it works well with libata who cares. Ditto the early PIIX chip." ] Signed-off-by: Sergei Shtylyov Cc: Alan Cox Signed-off-by: Andrew Morton Signed-off-by: Bartlomiej Zolnierkiewicz commit 6273d26a5b280cb96b804424de323560b301ca51 Author: Sergei Shtylyov Date: Wed Feb 7 18:18:20 2007 +0100 hpt366: HPT36x PCI clock detection fix Fix minor coding mistake in the HPT36x PCI clock detection code noticed by Bartlomiej Zolnierkiewicz -- it always reported 33 MHz due to the missing 'break' statements. This, however, most probably never mattered -- in fact, I was thinking of removing the 25/40 MHz cases completely since HPT36x BIOSes didn't seem to set any other value than 7 into the 'cmd_high_time' field, i.e. supported only 33 MHz PCI. Note that in the original driver there was another bug: 25 and 40 MHz cases were interchanged. Since the 'cmd_high_time' field is in units of PCI clocks, a lower clock count just *cannot* correspond to a higher frequency, i. e. it should be 5 for 25 MHz PCI and 9 for 40 MHz PCI, not the other way around. Signed-off-by: Sergei Shtylyov Cc: Alan Cox Signed-off-by: Andrew Morton Signed-off-by: Bartlomiej Zolnierkiewicz commit 7b73ee05d0acb926923d43d78b61add776ea4bb1 Author: Sergei Shtylyov Date: Wed Feb 7 18:18:16 2007 +0100 hpt366: init code rewrite Finally, rework the driver init. code to correctly handle all the chip variants HighPoint has created so far. This should cure the rest of the timing issues in the driver (especially, on 66 MHz PCI) caused by the HighPoint's habit of switching the base DPLL clock with every new revision of the chips... - switch to using the enumeration type to differ between the numerous chip variants, matching PCI device/revision ID with the chip type early, at the init_setup stage; - extend the hpt_info structure to hold the DPLL and PCI clock frequencies, stop duplicating it for each channel by storing the pointer in the pci_dev structure: first, at the init_setup stage, point it to a static "template" with only the chip type and its specific base DPLL frequency, the highest supported DMA mode, and the chip settings table pointer filled, then, at the init_chipset stage, allocate per-chip instance and fill it with the rest of the necessary information; - get rid of the constant thresholds in the HPT37x PCI clock detection code, switch to calculating PCI clock frequency based on the chip's base DPLL frequency; - switch to using the DPLL clock and enable UltraATA/133 mode by default on anything newer than HPT370/A; - fold PCI clock detection and DPLL setup code into init_chipset_hpt366(), unify the HPT36x/37x setup code and the speedproc handlers by joining the register setting lists into the table indexed by the clock selected; - add enablebits for all the chips to avoid touching disabled channels (though the HighPoint BIOS seem to only disable the primary one on HPT371/N); - separate the UltraDMA and MWDMA masks there to avoid changing PIO timings when setting an UltraDMA mode in hpt37x_tune_chipset(). This version has been tested on HPT370/302/371N. Thanks to Alan for the inspiration. Hopefully, his libata driver will also benefit from the work done on this "obsolete" driver... Signed-off-by: Sergei Shtylyov Cc: Alan Cox Signed-off-by: Andrew Morton Signed-off-by: Bartlomiej Zolnierkiewicz commit 4bf63de27e9fd9c0926ba3bb773de076b324a955 Author: Sergei Shtylyov Date: Wed Feb 7 18:18:13 2007 +0100 hpt366: clean up DMA timeout handling for HPT370 Clean up DMA timeout handling for HPT370: - hpt370_lostirq_timeout() cleared the DMA status which made __ide_dma_end() called afterwards return the incorrect result, and the DMA engine was reset both before and after stopping DMA while the HighPoint drivers only do it after (which seems logical) -- fix this and also rename the function; - get rid of the needless mutual recursion in hpt370_ide_dma_end() and hpt370_ide_dma_timeout(); - get rid of hpt370_lostirq_timeout() since hwif->ide_dma_end() called from the driver's interrupt handler later does all its work. Signed-off-by: Sergei Shtylyov Cc: Alan Cox Signed-off-by: Andrew Morton Signed-off-by: Bartlomiej Zolnierkiewicz commit 26ccb802ee3f9a1f1fd5bc6abf38f124bfbd9cb2 Author: Sergei Shtylyov Date: Wed Feb 7 18:18:11 2007 +0100 hpt366: merge HPT37x speedproc handlers Continue with the driver rewrite: - move the interrupt twiddling code from the speedproc handlers into the init_hwif_hpt366 which allows to merge the two HPT37x speedproc handlers into one; - get rid of in init_hpt366 which solely consists of the duplicate code, then fold init_hpt37x() into init_chipset_hpt366(); - fix hpt3xx_tune_drive() to always set the PIO mode requested, not the best possible one, change hpt366_config_drive_xfer_rate() accordingly, simplify it a bit; - group all the DMA related code together init_hwif_hpt366(), and generally clean up and beautify it. Signed-off-by: Sergei Shtylyov Cc: Alan Cox Signed-off-by: Andrew Morton Signed-off-by: Bartlomiej Zolnierkiewicz commit abc4ad4c6b3c6a51a0aa633e3d3fbc80b0ecabfe Author: Sergei Shtylyov Date: Wed Feb 7 18:18:05 2007 +0100 hpt366: cache channel's MCR address Begin the real driver redesign. For the starters: - cache the offset of the IDE channel's MISC. control registers which are used throughout the driver in hwif->select_data; - only touch the relevant MCR when detecting the cable type on HPT374's function 1; - make HPT36x's speedproc handler look the same way as HPT37x ones; fix the PIO timing register mask for HPT37x. - rename all the HPT3xx register related variables consistently; clean up the whitespace. Signed-off-by: Sergei Shtylyov Cc: Alan Cox Signed-off-by: Andrew Morton Signed-off-by: Bartlomiej Zolnierkiewicz commit b4586715d7944dfbcb2b6b76a0098413cf3222e4 Author: Sergei Shtylyov Date: Wed Feb 7 18:17:54 2007 +0100 hpt366: switch to using pci_get_slot Switch to using pci_get_slot() to get to the function 1 of HPT36x/374 chips -- there's no need for the driver itself to walk the list of the PCI devices, and it also forgets to check the bus number of the device found. Signed-off-by: Sergei Shtylyov Cc: Alan Cox Signed-off-by: Andrew Morton Signed-off-by: Bartlomiej Zolnierkiewicz commit 90778574c9257ea2d11c433626e1b12ac4135e0a Author: Sergei Shtylyov Date: Wed Feb 7 18:17:51 2007 +0100 hpt366: print the real chip name at startup - Rework the driver setup code so that it prefixes the driver startup messages with the real chip name. - Print the measured f_CNT value and the DPLL setting for non-HPT3xx chips as well. - Claim the extra 240 bytes of I/O space for all chips, not only for those having PCI device ID of 0x0004. Signed-off-by: Sergei Shtylyov Cc: Alan Cox Signed-off-by: Andrew Morton Signed-off-by: Bartlomiej Zolnierkiewicz commit f36702b4de1f7ea57927c8eb88d624504d33fc34 Author: Andrew Morton Date: Wed Feb 7 18:17:37 2007 +0100 hpt366: rework rate filtering tidy Cc: Sergei Shtylyov Cc: Alan Cox Signed-off-by: Andrew Morton Signed-off-by: Bartlomiej Zolnierkiewicz commit e139b0b02fd35a68c4353db34d3380c8a7c9a90d Author: Sergei Shtylyov Date: Wed Feb 7 18:17:37 2007 +0100 hpt366: rework rate filtering - Rework hpt3xx_ratemask() and hpt3xx_ratefilter() so that the former returns the max. mode computed at the load time and doesn't have to do bad Ultra33 drive list lookups anymore; remove the duplicate code from the latter function. Move the quirky drive list lookup into hpt3xx_quirkproc() where it should have been from the start... - Disable UltraATA/100 for HPT370 by default as the 33 MHz ATA clock being used does not allow for it, and this *greatly* increases the transfer speed. - Save some space by using byte-wide fields in struct hpt_info; switch to reading the 8-bit PCI revision ID reg. only, not the whole 32-bit reg. - Start incrementing the driver version number with each patch (should have been done from the first one posted). Signed-off-by: Sergei Shtylyov Cc: Alan Cox Signed-off-by: Andrew Morton Signed-off-by: Bartlomiej Zolnierkiewicz commit a2cf822274b3d58a16a65c8338e299e18b3dc3a4 Author: Adrian Bunk Date: Tue Feb 6 23:12:49 2007 +0100 [GFS2] make gfs2_writepages() static On Mon, Jan 29, 2007 at 08:45:28PM -0800, Andrew Morton wrote: >... > Changes since 2.6.20-rc6-mm2: >... > git-gfs2-nmw.patch >... > git trees >... This patch makes the needlessly global gfs2_writepages() static. Signed-off-by: Adrian Bunk Signed-off-by: Steven Whitehouse commit 2d72e7101cc7fff5c1eb21bfcbba51c8002418d2 Author: Steven Whitehouse Date: Wed Feb 7 10:25:59 2007 -0500 [GFS2] Unlock page on prepare_write try lock failure When the try lock of the glock failed in prepare_write we were incorrectly exiting this function with the page still locked. This was resulting in further I/O to this page hanging. Signed-off-by: Steven Whitehouse commit 5fad293bcbd48d9a2370020cf60e4b4a42559b12 Author: Kumar Gala Date: Wed Feb 7 01:47:59 2007 -0600 [POWERPC] Fixup error handling when emulating a floating point instruction When we do full FP emulation its possible that we need to post a SIGFPE based on the results of the emulation. The previous code ignored this case completely. Additionally, the Soft_emulate_8xx case had two issues. One, we should never generate a SIGFPE since the code only does data movement. Second, we were interpreting the return codes incorrectly, it returns 0 on success, 1 on illop and -EFAULT on a data access error. Signed-off-by: Kumar Gala commit 04903a30a327513b97c1271fc6bc4dad6502d1b8 Author: Kumar Gala Date: Wed Feb 7 01:13:32 2007 -0600 [POWERPC] Enable interrupts if we are doing fp math emulation Anytime we are emulating an instruction we are going to be doing some form of get_user() to get the instruction image to decode. Since get_user() might sleep we need to ensure we have interrupts enabled or we might see something like: Debug: sleeping function called from invalid context at arch/powerpc/kernel/traps.c:697 in_atomic():0, irqs_disabled():1 Call Trace: [D6023EB0] [C0007F84] show_stack+0x58/0x174 (unreliable) [D6023EE0] [C0022C34] __might_sleep+0xbc/0xd0 [D6023EF0] [C000D158] program_check_exception+0x1d8/0x4fc [D6023F40] [C000E744] ret_from_except_full+0x0/0x4c --- Exception: 700 at 0x102a7100 LR = 0xdb9ef04 However, we want to ensure that interrupts are disabled when handling a trap exception that might be used for a kernel breakpoint. This is why ProgramCheck is marked as EXC_XFER_STD instead of EXC_XFER_EE. Signed-off-by: Kumar Gala commit 8209003547c4b1006943eac8dc6c1fb6493cafda Author: Kumar Gala Date: Tue Feb 6 22:55:19 2007 -0600 [POWERPC] Added kprobes support to ppc32 Added kprobes to ppc32 platforms that have use single_step_exception. This excludes 4xx and anything Book-E since their debug mechanisms for single stepping are completely different. Signed-off-by: Kumar Gala commit f03e64f2ca6ee3d0b7824536b1940497701fe766 Author: Paul Mackerras Date: Tue Feb 6 21:10:31 2007 +1100 [POWERPC] Make pSeries use the H_BULK_REMOVE hypervisor call H_BULK_REMOVE lets us remove 4 entries from the MMU hash table with one hypervisor call. This uses it in pSeries_lpar_hpte_invalidate so we can tear down mappings with fewer hypervisor calls. Signed-off-by: Paul Mackerras commit e56a6e20f3029ed5c178dd0328bd688dbbc8272a Author: Paul Mackerras Date: Wed Feb 7 13:13:26 2007 +1100 [POWERPC] Clear RI bit in MSR before restoring r13 when returning to userspace Some instruction tracing tools use the RI (recoverable interrupt) bit in the MSR to indicate when it's safe to single-step. Currently we clear RI after restoring r13 when returning to userspace. However, if we single-step past the point where r13 is restored, we'll corrupt r13 in the exception entry code and not restore it. This moves the clearing of RI to just before r13 is restored so this doesn't happen. Signed-off-by: Paul Mackerras commit 449d846dbcbf61bdf7d50a923e4791102168c292 Author: Livio Soares Date: Wed Feb 7 12:51:36 2007 +1100 [POWERPC] Fix performance monitor exception To the issue: some point during 2.6.20 development, Paul Mackerras introduced the "lazy IRQ disabling" patch (very cool work, BTW). In that patch, the performance monitor unit exception was marked as "maskable", in the sense that if interrupts were soft-disabled, that exception could be ignored. This broke my PowerPC profiling code. The symptom that I see is that a varying number of interrupts (from 0 to $n$, typically closer to 0) get delivered, when, in reality, it should always be very close to $n$. The issue stems from the way masking is being done. Masking in this fashion seems to work well with the decrementer and external interrupts, because they are raised again until "really" handled. For the PMU, however, this does not apply (at least on my Xserver machine with a 970FX processor). If the PMU exception is not handled, it will _not_ be re-raised (at least on my machine). The documentation states that the PMXE bit in MMCR0 is set to 0 when the PMU exception is raised. However, software must re-set the bit to re-enable PMU exceptions. If the exception is ignored (as currently) not only is that interrupt lost, but because software does not re-set PMXE, the PMU registers are "frozen" forever. [This patch means that performance monitor exceptions are taken and handled even if irqs are off, as long as some other interrupt hasn't come along and caused interrupts to be hard-disabled. In this sense the PMU exception becomes like an NMI. The oprofile code for most powerpc processors does nothing that is unsafe in an NMI context, but the Cell oprofile code does a spin_lock_irqsave. However, that turns out to be OK because Cell doesn't actually use the performance monitor exception; performance monitor interrupts come in as a regular interrupt on Cell, so will be disabled when irqs are off. -- paulus.] Signed-off-by: Paul Mackerras commit a2c70211fa072f4076f0e59f909b69105f69072e Author: David Gibson Date: Tue Feb 6 11:48:28 2007 +1100 [POWERPC] Compile fixes for arch/powerpc dcr code The new dcr code does not currently compile when configured for native DCR access on ARCH=powerpc. This patch fixes the problems. Signed-off-by: David Gibson Signed-off-by: Paul Mackerras commit 4297c9869b3452860f1a2c588d43f9e62c701019 Author: Nathan Lynch Date: Mon Feb 5 20:01:15 2007 -0600 [POWERPC] Maple: use mmio nvram Some systems supported by the maple platform (e.g. JS2x blades running SLOF) are able to use the mmio_nvram backend for reading and writing nvram. This is an improvement over the current situation -- no nvram access from userspace at all. Select MMIO_NVRAM for the maple platform. Initialize the mmio_nvram backend from maple setup code. Signed-off-by: Nathan Lynch Signed-off-by: Paul Mackerras commit 721e0c9037ef4e755f3bd87fee92beff452be420 Author: Olof Johansson Date: Sun Feb 4 16:36:56 2007 -0600 [POWERPC] pasemi: defconfig Base pasemi defconfig. Nothing special, just the native drivers plus common PCI-express/PCI cards. Signed-off-by: Olof Johansson Signed-off-by: Paul Mackerras commit 31c56d820e03a2fd47f81d6c826f92caf511f9ee Author: Olof Johansson Date: Sun Feb 4 16:36:55 2007 -0600 [POWERPC] pasemi: iommu support I/O TLB support for PA6T-1682M. Signed-off-by: Olof Johansson Signed-off-by: Paul Mackerras commit f9fba5b72dbedc691dcb10ae666ec03f279b07f4 Author: Olof Johansson Date: Sun Feb 4 16:36:54 2007 -0600 [POWERPC] pasemi: Configure DMA controller interrupts The DMA controller on PWRficient is somewhat special -- has a PCI header so it looks like it's on the root PCI (-Express) root bus, but it uses more than the default number of interrupts (and they are hardwired). We need to wire up all interrupts for the DMA controller. The generic IRQ code will only map the primary interrupt from the PCI header (128), so add 129->211 by hand. Signed-off-by: Olof Johansson Signed-off-by: Paul Mackerras commit c388cfebbf22acd2b6adf757b35e28d4be66ac7c Author: Olof Johansson Date: Sun Feb 4 16:36:53 2007 -0600 [POWERPC] pasemi: SMP timebase sync Timebase update is simple on PA6T, since global updates can be done from one core by writing to an SPR. Signed-off-by: Olof Johansson Signed-off-by: Paul Mackerras commit f620be99e9355c41693f0c748ba9260f69278ee0 Author: Olof Johansson Date: Sun Feb 4 16:36:52 2007 -0600 [POWERPC] pasemi: Implement restart Implement reset on platforms/pasemi. Default is just to reset the cpu using the SDC registers. Signed-off-by: Olof Johansson Signed-off-by: Paul Mackerras commit 1199919b69ff9559a3d3444fb5eb45b7cc48264d Author: Olof Johansson Date: Sun Feb 4 16:36:51 2007 -0600 [POWERPC] pasemi: Idle loops Powersave support on PA6T. Right now it only uses 'doze' mode, and will default to no savings (spin). Signed-off-by: Olof Johansson Acked-by: Arnd Bergmann Signed-off-by: Paul Mackerras commit bfed9d32d968b2054a036d419537e9e9909bb343 Author: Olof Johansson Date: Sun Feb 4 16:36:50 2007 -0600 [POWERPC] pasemi: Machine check handler Print out decoded machine check information on PA6T. Signed-off-by: Olof Johansson Signed-off-by: Paul Mackerras commit 39c870d5b503fa684198baf90bab2daa35ef0151 Author: Olof Johansson Date: Sun Feb 4 16:36:49 2007 -0600 [POWERPC] pasemi: UART udbg support Early debug output for PA Semi UART. Uses the 2.05 CI real mode ops. Signed-off-by: Olof Johansson Signed-off-by: Paul Mackerras commit a1fdf6940a2a3d3c7475755eba5881403473252d Author: Pavel Roskin Date: Sun Feb 4 03:16:08 2007 -0500 [POWERPC] Assign all PCI busses on G3 Blue & White G3 Blue & White is misconfigured by default so that CardBus controllers in PCI slots don't work. The PCI bridge is programmed to only allow access to bus 1 but not higher busses. The patch forces the PCI busses to be reassigned if a Grackle controller is found and the machine identifies itself as "PowerMac1,1" Signed-off-by: Pavel Roskin Acked-by: Benjamin Herrenschmidt Signed-off-by: Paul Mackerras commit 6e47a0f38203656125bb6b81216aa4a4f506e98c Author: Ishizaki Kou Date: Fri Feb 2 16:48:04 2007 +0900 [POWERPC] Celleb: add celleb_defconfig This patch creates defconfig file for Celleb platform. Signed-off-by: Kou Ishizaki Acked-by: Arnd Bergmann Signed-off-by: Paul Mackerras commit c347b7989e4d9e1c23cb5cfba78c63c031b7dcee Author: Ishizaki Kou Date: Fri Feb 2 16:47:17 2007 +0900 [POWERPC] Celleb: basic support This patch adds base support for Celleb platform. Signed-off-by: Kou Ishizaki Acked-by: Arnd Bergmann Acked-by: Benjamin Herrenschmidt Signed-off-by: Paul Mackerras commit e107931956f8327637508b91a9ddd4ba35be289d Author: Ishizaki Kou Date: Fri Feb 2 16:46:22 2007 +0900 [POWERPC] Celleb: support spu priv1 ops SPU support routines for Celleb platform. Signed-off-by: Kou Ishizaki Acked-by: Arnd Bergmann Signed-off-by: Paul Mackerras commit c9868fe0e091f64241a372b45f08097c013e41b2 Author: Ishizaki Kou Date: Fri Feb 2 16:45:33 2007 +0900 [POWERPC] Celleb: consolidate spu management ops Spu management ops in arch/platforms/cell/spu_priv1_mmio.h can be used commonly in of based platform. This patch separates spu management ops from native cell code and uses on celleb platform. Signed-off-by: Arnd Bergmann Signed-off-by: Kou Ishizaki Signed-off-by: Paul Mackerras commit 3cdc20e51791bd2fd67781e65640a4650f99c63e Author: Ishizaki Kou Date: Fri Feb 2 16:44:08 2007 +0900 [POWERPC] Celleb: hypervisor console driver This patch adds hypervisor console driver for Celleb platform. Signed-off-by: Kou Ishizaki Signed-off-by: Paul Mackerras commit d7480a9feaa970d9c37462f21bc27ebab2c56b0b Author: Ishizaki Kou Date: Fri Feb 2 16:43:21 2007 +0900 [POWERPC] Celleb: support udbg This patch adds udbg support for Celleb platform. Signed-off-by: Kou Ishizaki Acked-by: Benjamin Herrenschmidt Signed-off-by: Paul Mackerras commit fe4a0cf1c2e79c3c256992c4f731734ecacb45c3 Author: Ishizaki Kou Date: Fri Feb 2 16:42:28 2007 +0900 [POWERPC] Celleb: htab routines Adds htab routines for Celleb platform. Signed-off-by: Kou Ishizaki Acked-by: Benjamin Herrenschmidt Signed-off-by: Paul Mackerras commit 97a9b58409403baf7a8b0ccbd3d27993790dcdab Author: Ishizaki Kou Date: Fri Feb 2 16:39:34 2007 +0900 [POWERPC] Celleb: support iommu This patch creates Celleb platform dependent file to support iommu. Signed-off-by: Kou Ishizaki Acked-by: Benjamin Herrenschmidt Signed-off-by: Paul Mackerras commit 7163c7c9d266862ad9a0a0203d204113034cb5fb Author: Ishizaki Kou Date: Fri Feb 2 16:38:41 2007 +0900 [POWERPC] Celleb: setup usb host controller in SCC USB host controller in SCC requires enable sequence. It should be done before USB host drivers start. Signed-off-by: Kou Ishizaki Acked-by: Benjamin Herrenschmidt Signed-off-by: Paul Mackerras commit 32f39b055f3b7af4ee76a93ede5450ab2549328a Author: Ishizaki Kou Date: Fri Feb 2 16:37:30 2007 +0900 [POWERPC] Celleb: support interrupts This patch creates Celleb platform dependent files to support interrupts. Signed-off-by: Kou Ishizaki Acked-by: Arnd Bergmann Acked-by: Benjamin Herrenschmidt Signed-off-by: Paul Mackerras commit b8a590c496474ca80a8f1c2b228e8b8e6a33fb9d Author: Ishizaki Kou Date: Fri Feb 2 16:36:27 2007 +0900 [POWERPC] Celleb: interfaces to the hypervisor This patch creates Celleb platform dependent files which add interfaces to call hypervisor. Signed-off-by: Kou Ishizaki Signed-off-by: Paul Mackerras commit c23ef29c1efa6864527fb78249695679810d302e Author: Jiri Kosina Date: Thu Feb 1 16:36:13 2007 +0100 [POWERPC] powermac: local_irq_disable() is redundant after local_irq_save() arch/powerpc/platforms/powermac/smp.c::smp_core99_kick_cpu() contains local_irq_disable() call after local_irq_save(). This looks redundant. Signed-off-by: Jiri Kosina Signed-off-by: Paul Mackerras commit f79ce995d0a7bfc424b1ad8f315e62ff9f67bbfe Author: Jiri Kosina Date: Thu Feb 1 16:36:04 2007 +0100 [POWERPC] 86xx: local_irq_disable() is redundant after local_irq_save() arch/powerpc/platforms/86xx/mpc86xx_smp.c::smp_86xx_kick_cpu() contains local_irq_disable() call after local_irq_save(). This looks redundant. Signed-off-by: Jiri Kosina Acked-by: Benjamin Herrenschmidt Signed-off-by: Paul Mackerras commit c4cbfd64f933414eaa2042adcd276f088995898a Author: Vitaly Bordug Date: Wed Jan 31 02:09:06 2007 +0300 [POWERPC] mpc8272ads: defconfig Default config file for mpc8272ads (powerpc port).Though relevant bits went in, it is required to keep proper default configuration for the target, which seems to be missed initially. Signed-off-by: Vitaly Bordug Signed-off-by: Paul Mackerras commit 5427828e83b7f3c000eaec1cfb09c9bc4d024ad1 Author: Vitaly Bordug Date: Wed Jan 31 02:09:00 2007 +0300 [POWERPC] Fix kernel build errors for mpc8272ads and mpc8560ads Recent update of asm-powerpc/io.h caused cpm-related stuff to break in the current kernel. Current patch fixes it, as well as other inconsistencies expressed, that do not permit targets from working properly: - Updated dts with a chosen node with interrupt controller, - fixed messed device IDs among CPM2 SoC devices, - corrected odd header name and fixed type in defines, - Added 82xx subdir to the powerpc/platforms Makefile, missed during initial commit, - new solely-powerpc header file for 8260 family (was using one from arch/ppc, this one cleaned up from the extra stuff), in fact for now a placeholder to get the board-specific includes for stuff not yet capable to live with devicetree peeks only - Fixed couple of misprints in reference mpc8272 dts. Signed-off-by: Vitaly Bordug Signed-off-by: Paul Mackerras commit 73844ecbaa58885c5e89af7d1b08faaffffa6833 Author: Vitaly Bordug Date: Wed Jan 31 02:08:54 2007 +0300 [POWERPC] cpm2: CPM2 interrupt controller fix This contains important fixes for the CPM2 PIC code. Eliminated CPM_IRQ_OFFSET, pulling the respective interrupt numbers from the interrupt mapping. Updated devicetree files to reflect that. Changed direct IC-related IO accesses to the IO accessors. Fixed all the sense values to keep coherency with ipic. In the current code, CPM2 stuff will have no IRQs and hence could be hardly usable. Signed-off-by: Vitaly Bordug Signed-off-by: Paul Mackerras commit c19cdcb1b8d33a20d372191eced2def7f901806b Author: Geoff Levand Date: Tue Jan 30 15:20:37 2007 -0800 [POWERPC] PS3: Enable USB mass storage Update ps3_defconfig to enable USB mass storage and VFAT. Signed-off-by: Geoff Levand Acked-by: Arnd Bergmann Signed-off-by: Paul Mackerras commit 35063bb2eaf85bd0f6e3acefae2d95cb0120eb3e Author: Geoff Levand Date: Tue Jan 30 15:20:34 2007 -0800 [POWERPC] PS3: Fix DMA scatter-gather Add the missing pieces to support DMA scatter-gather on the PS3 system bus. Signed-off-by: Geoff Levand Acked-by: Benjamin Herrenschmidt Signed-off-by: Paul Mackerras commit 97ec1675999eae96975a30facbedc2e6c0c832bc Author: Geoff Levand Date: Tue Jan 30 15:20:30 2007 -0800 [POWERPC] PS3: Move vuart declarations to ps3.h Move the structures and routines needed for PS3 vuart port device registration to asm-powerpc/ps3.h. Signed-off-by: Geoff Levand Acked-by: Arnd Bergmann Signed-off-by: Paul Mackerras commit 2a08ea69a3e448a5cc94e5da9eccc40cf13f9532 Author: Geoff Levand Date: Tue Jan 30 15:20:27 2007 -0800 [POWERPC] PS3: Move system bus to platform directory Move the PS3 system bus routines from drivers/ps3 to arch/powerpc/platforms/ps3. Signed-off-by: Geoff Levand Acked-by: Benjamin Herrenschmidt Acked-by: Arnd Bergmann Signed-off-by: Paul Mackerras commit 63c2f782e8f6aafbc11b14b2cb291b3dc9fc217d Author: Robert P. J. Day Date: Tue Jan 30 06:06:00 2007 -0500 [POWERPC] Add "is_power_of_2" checking to log2.h. Add the inline function "is_power_of_2()" to log2.h, where the value zero is *not* considered to be a power of two. Signed-off-by: Robert P. J. Day Acked-by: Kumar Gala Signed-off-by: Paul Mackerras commit 7df2457db83bc922fcc8b462526b77f1ffe8c84b Author: Olof Johansson Date: Sun Jan 28 23:33:18 2007 -0600 [POWERPC] MPIC: support more than 256 sources Allow more than the default 256 MPIC sources. Allocates a new flag (MPIC_LARGE_VECTORS) to be used by platform code when instantiating the mpic. I picked 11 bits worth right now since it would cover the number of sources on any hardware I have seen. It can always be increased later if needed. Signed-off-by: Olof Johansson Signed-off-by: Paul Mackerras commit 6529c13dfe413e437ad1ed0e97783dcf69137114 Author: Olof Johansson Date: Sun Jan 28 21:25:57 2007 -0600 [POWERPC] PA6T PMC support Support for PA6T-style PMC registers. PMCs are completely implementation-dependent on PPC, and PA6T numbers them differently from the IBM model. Signed-off-by: Olof Johansson Signed-off-by: Paul Mackerras commit 7583b6e424ebaa278342f6a8c2a61211af56dad1 Author: Olof Johansson Date: Sun Jan 28 21:24:57 2007 -0600 [POWERPC] Introduce _SYSDEV_ATTR Introduce _SYSDEV_ATTR(), to be used to just define the struct, and not a named variable with the attribute. Useful for arrays of sysdev_attributes. Signed-off-by: Olof Johansson Signed-off-by: Greg Kroah-Hartman Signed-off-by: Paul Mackerras commit 1bd2e5ae18a8f93333707d81d3dbd9209a255137 Author: Olof Johansson Date: Sun Jan 28 21:23:54 2007 -0600 [POWERPC] Add PMC type to cputable Add cputable entries for which type of PMC implementation the processor has. I've only filled in the current 64-bit processors, the unfilled default value will have same behaviour as before so it can be done over time as needed. Also tidy up the dummy_perf implementation a bit, aggregating it into one function with ifdefs instead of several. Signed-off-by: Olof Johansson Signed-off-by: Paul Mackerras commit c69b767a2c871bb80cb9e346d6ebce248f711dfb Author: Olof Johansson Date: Sun Jan 28 21:23:14 2007 -0600 [POWERPC] Oprofile cleanup Clean up the ctr_read/write a bit. It's currently defined in the include but only used in one C file each. The only exception is the classic version, so keep that in the include and define in the C file as appropriate. Signed-off-by: Olof Johansson Signed-off-by: Paul Mackerras commit 4942bd80e83d13bf394df4a8109bee39d861820f Author: Timur Tabi Date: Sat Jan 27 17:41:49 2007 -0600 [POWERPC] Fix array indexing error in rheap grow() The grow() function in the rheap library allocates a larger array of blocks, copies the contents of the old blocks array to the newly allocated array and fixes the list_head pointers after the copy. At the end, the new blocks must be enqueued to the empty_list of the rh_info_t structure. This patch fixes a bug where the code was indexing past the end of the array when enqueueing blocks. The UCC ethernet driver, which uses the rheap allocator, experiences kernel panics because of this bug. Signed-off-by: Ionut Nicu Signed-off-by: Timur Tabi Signed-off-by: Paul Mackerras commit 5f3162f0664be49c72c1e6ce4a46848f9d96d790 Author: Geoff Levand Date: Fri Jan 26 19:08:29 2007 -0800 [POWERPC] ps3: ps3_defconfig updates Updates for ps3_defconfig. Signed-off-by: Geoff Levand Acked-by: Arnd Bergmann Signed-off-by: Paul Mackerras commit 8000d49076f5d1767b6fee9c74b452f488ed89ad Author: Geoff Levand Date: Fri Jan 26 19:08:26 2007 -0800 [POWERPC] ps3: remove unneeded header include Remove an unneeded header include from ps3.h. Signed-off-by: Geoff Levand Acked-by: Arnd Bergmann Signed-off-by: Paul Mackerras commit 098e27442713ef7921533130ebba5db6ef64aba6 Author: Geert Uytterhoeven Date: Fri Jan 26 19:08:24 2007 -0800 [POWERPC] ps3: get av_multi_out params Allow the PS3 AV settings driver to access the default video mode stored in the OS area. Signed-off-by: Geert Uytterhoeven Signed-off-by: Geoff Levand Acked-by: Arnd Bergmann Signed-off-by: Paul Mackerras commit 66b44954f8f2129a39d145991c8e635046a71be6 Author: Geoff Levand Date: Fri Jan 26 19:08:21 2007 -0800 [POWERPC] ps3: get firmware version Add a new routine ps3_get_firmware_version() and use it to output the firmware version to dmesg. Signed-off-by: Geoff Levand Acked-by: Arnd Bergmann Signed-off-by: Paul Mackerras commit 73d976b33998bca9aa7300e59f5d6c756be38b87 Author: Geoff Levand Date: Fri Jan 26 19:08:19 2007 -0800 [POWERPC] ps3: remove cpuinfo Remove the unneded routine ps3_show_cpuinfo(). The common platform code now prints the same information. Signed-off-by: Geoff Levand Acked-by: Arnd Bergmann Signed-off-by: Paul Mackerras commit 577157659fb0ace3b88dd75e2c6cb1af84b3040d Author: Geoff Levand Date: Fri Jan 26 19:08:16 2007 -0800 [POWERPC] ps3: fix interrupt bmp Add a comment and a preprocessor macro to help clearify the alignment needs of the PS3 interrupt bitmap. Signed-off-by: Geoff Levand Acked-by: Arnd Bergmann Signed-off-by: Paul Mackerras commit b1eeb38e456281c37bbfc270a6ca08605b7e7045 Author: Geert Uytterhoeven Date: Fri Jan 26 19:08:12 2007 -0800 [POWERPC] ps3: add interrupt alloc for outlets PS3 interrupt core update: - Add ps3_alloc_irq() and ps3_free_irq(), to allocate a virtual interrupt number for an interrupt outlet, which is needed by the PS3 GPU frame buffer device and audio drivers Signed-off-by: Geert Uytterhoeven Signed-off-by: Geoff Levand Acked-by: Arnd Bergmann Signed-off-by: Paul Mackerras commit 861be32ce7f1cf272a3f809e77213b83117a0bd2 Author: Geoff Levand Date: Fri Jan 26 19:08:08 2007 -0800 [POWERPC] ps3: bind interrupt to cpu Change the PS3 irq allocation routines to take an argument indicating which cpu (processor thread) the interrupt should be serviced on. The current system configuration favors device interrupts that are serviced on cpu0, so that is used as the default. Signed-off-by: Geoff Levand Acked-by: Arnd Bergmann Signed-off-by: Paul Mackerras commit 9cf9e19667f6ce01bd509a154157270069f836f9 Author: Benjamin Herrenschmidt Date: Fri Jan 26 19:08:05 2007 -0800 [POWERPC] ps3: cleanup interrupt bmp routines Change the PS3 interrupt bitmask routines to be lockless. Signed-off-by: Benjamin Herrenschmidt Signed-off-by: Geoff Levand Acked-by: Arnd Bergmann Signed-off-by: Paul Mackerras commit 407e24a0c78f585c228ec7e1152a9b23e262b200 Author: Geoff Levand Date: Fri Jan 26 19:08:02 2007 -0800 [POWERPC] ps3: smp interrupt fixes PS3 fixups for interrups on SMP. Fixes the alignment of the interrupt status bitmap, changes the hypervisor interrupt calls to the '_ext' versions that take an explicit processor thread ID. Signed-off-by: Geoff Levand Acked-by: Benjamin Herrenschmidt Signed-off-by: Paul Mackerras commit 9633ac8d172f74b8ee51e0fe85c06eb726039aa8 Author: Geoff Levand Date: Fri Jan 26 19:07:59 2007 -0800 [POWERPC] ps3: rename interrupt symbols Rename some PS3 interrupt symbols to avoid name clashes and aid debugging. No change to code. Signed-off-by: Geoff Levand Acked-by: Benjamin Herrenschmidt Acked-by: Arnd Bergmann Signed-off-by: Paul Mackerras commit a8229a9e5211a52839268b82ae14cdf528d48f58 Author: Geoff Levand Date: Fri Jan 26 19:07:56 2007 -0800 [POWERPC] ps3: fix struct alignment attributes Remove incorrect alignment attributes in PS3 platform code for struct spe_shadow, struct os_area_header, and struct os_area_params. Signed-off-by: Geoff Levand Acked-by: Arnd Bergmann Signed-off-by: Paul Mackerras commit 43d80439c5f619446e174abdbdaff4fc0e539546 Author: Benjamin Herrenschmidt Date: Fri Jan 26 19:07:54 2007 -0800 [POWERPC] ps3: system bus minor mmio fix Fix two minor bugs in the PS3 system bus mmio region code. First, on error or when freeing a region, retain the bus_addr and len fields to allow subsequent calls to create the region. Second, correct the region address argument to the lv1_unmap_device_mmio_region() call. Fixes modprobe/rmmod of some drivers. Signed-off-by: Benjamin Herrenschmidt Signed-off-by: Geoff Levand Acked-by: Arnd Bergmann Signed-off-by: Paul Mackerras commit 6c7be7d385f4911895877e0f0697c598f600136f Author: Geert Uytterhoeven Date: Fri Jan 26 19:07:51 2007 -0800 [POWERPC] ps3: repository storage support Handle storage-related repository data: - Add missing implementations of ps3_repository_read_stor_*() repository accessors. - Dump storage properties in debug mode - Add PS3_DEV_TYPE_STOR_{DISK,ROM,FLASH} device types (which are identical to the corresponding SCSI device types) to enum ps3_dev_type Signed-off-by: Geert Uytterhoeven Signed-off-by: Geoff Levand Acked-by: Arnd Bergmann Signed-off-by: Paul Mackerras commit eebb81c13aa831a623e903bbae97a23fe9be93eb Author: Geoff Levand Date: Fri Jan 26 19:07:47 2007 -0800 [POWERPC] ps3: repository misc fixes Various fixes for the PS3 repository code: - Sync signatures of function prototypes and implementations (enum vs. unsigned int) - Correct references to `regions' as `registers': o Correct enum ps3_region_type as enum ps3_reg_type, o Correct PS3_REGION_TYPE_* as PS3_REG_TYPE_*, o Correct ps3_repository_find_region() as ps3_repository_find_reg(). - Correct function name in pr_debug() call - Minor error condition improvements. Signed-off-by: Geert Uytterhoeven Signed-off-by: Geoff Levand Acked-by: Arnd Bergmann Signed-off-by: Paul Mackerras commit 25c4a46f0ed8ece9ac6699e200fcc83a4642dce7 Author: Linas Vepstas Date: Fri Jan 26 14:55:03 2007 -0600 [POWERPC] pSeries: EEH improperly enabled for some Power4 systems It appears that EEH is improperly enabled for some Power4 systems. On these systems, the ibm,set-eeh-option returns a value of success even when EEH is not supported on the given node. Thus, an explicit check for support is required. During boot, on power4, without this patch, one sees messages similar to: EEH: event on unsupported device, rc=0 dn=/pci@400000000110/IBM,sp@1 EEH: event on unsupported device, rc=0 dn=/pci@400000000110/pci@2 EEH: event on unsupported device, rc=0 dn=/pci@400000000110/pci@2,2 etc. The patch makes these go away. Without this patch, EEH recovery does seem to work correctly for at least some devices (I tested ethernet e1000), but fails to recover others (the Emulex LightPulse LPFC, most notably). Off the top of my head, I don't remember why some devices are affected, but not others. The PAPR indicates that the correct way to test for EEH is as done in this patch; its not clear to me if this was in the PAPR all along, or recently added; if it was there all along, its not clear to me why this hadn't been fixed long ago. I suspect only certain firmware levels are affected. Signed-off-by: Linas Vepstas Signed-off-by: Paul Mackerras commit 2dc08572cc11a1ab2e67b214a4f3d7d0997473f8 Author: Robert P. J. Day Date: Thu Jan 25 19:10:52 2007 -0500 [POWERPC] Fix apparent typo "CONFIG_SERIAL_CPM_SMC". Replace an apparent typo of CONFIG_SERIAL_CPM_SMC with CONFIG_SERIAL_CPM_SMC2. Signed-off-by: Robert P. J. Day Acked-by: Kumar Gala Signed-off-by: Paul Mackerras commit 59eaef9daef35129a982c9d2b464aacb13349cdf Author: Nathan Lynch Date: Wed Jan 24 15:57:06 2007 -0600 [POWERPC] Maple: don't override bus-range supplied by firmware This workaround was copy-pasted from the powermac code. It's not necessary for maple. Signed-off-by: Nathan Lynch Signed-off-by: Paul Mackerras commit 29f1530f1958dc74f021186c9f31ed66a0c7b8ad Author: Vitaly Bordug Date: Wed Jan 24 22:42:10 2007 +0300 [POWERPC] Add mpc866ads board-specific bits to arch/powerpc This add support of the Freescale mpc86xads reference board to arch/powerpc. Supported SMC1 and SMC2 (UART and serial console), FEC 100Mbps Ethernet, SCC1 Ethernet (10Mbps hdx) Signed-off-by: Vitaly Bordug Signed-off-by: Paul Mackerras commit df34403dcaacef541a67c955aebc37c51f53ca7c Author: Vitaly Bordug Date: Wed Jan 24 22:41:42 2007 +0300 [POWERPC] 8xx: Add mpc885ads support and common mpc8xx files This adds the core 8xx stuff and specifically mpc885ads board-specific bits to arch/powerpc. Respective Kconfig has been cleaned up from the stuff not yet ported over to avoid confusion. Updated and cleaned version. Signed-off-by: Vitaly Bordug Signed-off-by: Paul Mackerras commit f2a0bd3753dad7ea4605ebd5435716b39e9f92bb Author: Vitaly Bordug Date: Wed Jan 24 22:41:24 2007 +0300 [POWERPC] 8xx: powerpc port of core CPM PIC This covers common CPM access functions, CPM interrupt controller code, micropatch and a few compatibility things to kee the same driver base working with arch/ppc. This version is refined with all the comments (mostly PIC-related) addressed. Signed-off-by: Vitaly Bordug Signed-off-by: Paul Mackerras commit 88bdc6f061cfb4579d2327fd457d4b7807525a0e Author: Vitaly Bordug Date: Wed Jan 24 22:41:15 2007 +0300 [POWERPC] 8xx: platform related changes to the fsl_soc Added 8xx SoC peripherials: fec for Ethernet and smc for UARTs. Ordinary routines to extract values from the device tree and insert respective platform devices Signed-off-by: Vitaly Bordug Signed-off-by: Paul Mackerras commit 5902ebce22fa5a1ac833565dbc4fde7e8a1bc737 Author: Vitaly Bordug Date: Wed Jan 24 22:41:06 2007 +0300 [POWERPC] 8xx: generic 8xx code arch/powerpc port Including support for non-coherent cache, some mm-related things + relevant field in Kconfig and Makefiles. Also included rheap.o compilation if 8xx is defined. Non-coherent mapping were refined and renamed according to Cristoph Hellwig. Orphaned functions were cleaned up. [Also removed arch/ppc/kernel/dma-mapping.c, because otherwise compiling with ARCH=ppc for a non DMA-cache-coherent platform ends up with two copies of __dma_alloc_coherent etc. -- paulus.] Signed-off-by: Vitaly Bordug Signed-off-by: Paul Mackerras commit dbbb06b7f6ae8037a5f6b4498e492791e1929635 Author: Vitaly Bordug Date: Wed Jan 24 22:40:57 2007 +0300 [POWERPC] 8xx: platform specific mmu updates This is just a straight port of the same done in arch/ppc by Marcelo Tosatti. One used to be [PATCH] ppc32 8xx: update_mmu_cache() needs unconditional tlbie, commit eb07d964b4491d1bb5864cd3d7e7633ccdda9a53 In a nutshell, the board is nearly stuck without this, yet without any visible failure - being just very slow. Signed-off-by: Vitaly Bordug Signed-off-by: Paul Mackerras commit f25222b99542bcadf1cc53cc9aa0e304849242ca Author: Vitaly Bordug Date: Wed Jan 24 22:40:49 2007 +0300 [POWERPC] cpm_uart: OF-related fix for CPM1 This makes cpm uart able to work using OF-passed parameters in case of CPM stuff (found on most mpc8xx reference and custom boards). The idea is to keep ppc stuff working yet making it able to be used for powerpc. Signed-off-by: Vitaly Bordug Signed-off-by: Paul Mackerras commit 1473ae6cab7f47dde4c14f397371b2ad94457d3a Author: Michael Neuling Date: Tue Jan 23 15:59:26 2007 +1100 [POWERPC] remove unused CPU_FTRS_POWER6X CPU_FTRS_POWER6X is unused, hence remove it. Signed-off-by Michael Neuling Signed-off-by: Paul Mackerras commit 87f440e70e07dace7db130f2f9fcea3f132aad8f Author: Steve French Date: Wed Feb 7 00:29:46 2007 +0000 [CIFS] Additional POSIX CIFS Extensions infolevels also includes cleanup of whitespace/80 columns Signed-off-by: Steve French commit b7e36bfa9ffa2f6097b622ba07a95d823db553e4 Author: Jiri Kosina Date: Mon Feb 5 16:29:49 2007 -0800 NET: turn local_save_flags() + local_irq_disable() into local_irq_save() drivers/net/amd8111e.c::amd8111e_poll() contains local_irq_disable() after local_save_flags(). Turn it into local_irq_save(). Signed-off-by: Jiri Kosina Signed-off-by: Andrew Morton Signed-off-by: Jeff Garzik commit 0d38ff1d3d34ca9ae2a61cf98cf47530f9d51dee Author: Jiri Kosina Date: Mon Feb 5 16:29:48 2007 -0800 NET-3c59x: turn local_save_flags() + local_irq_disable() into local_irq_save() drivers/net/3c59x.c::poll_vortex() contains local_irq_disable() after local_save_flags(). Turn it into local_irq_save(). Signed-off-by: Jiri Kosina Signed-off-by: Andrew Morton Signed-off-by: Jeff Garzik commit 7e3e8b05a90bcc5799b0d4525f23c80d661d0194 Author: Richard Knutsson Date: Mon Feb 5 16:29:48 2007 -0800 hp100: convert pci_module_init() to pci_register_driver() Convert pci_module_init() to pci_register_driver(). Signed-off-by: Richard Knutsson Cc: Jeff Garzik Signed-off-by: Andrew Morton Signed-off-by: Jeff Garzik commit 27d2ab54bdfaffdbdc1a81100dc53c6479c9db35 Author: Amit S. Kale Date: Mon Feb 5 07:40:49 2007 -0800 NetXen: Added ethtool support for user level tools. NetXen: Added ethtool support for user level firmware management utilities. Signed-off-by: Amit S. Kale Signed-off-by: Jeff Garzik commit 1fcca1a5fc81689d191b7132318970c969b4b635 Author: Amit S. Kale Date: Mon Feb 5 07:35:26 2007 -0800 NetXen: Firmware crb init changes. NetXen: firmware crb init changes. Signed-off-by: Amit S. Kale Signed-off-by: Jeff Garzik commit 8d5ca6ec4e5c7208fe90aaecab9544bf8c08f0dc Author: Jay Cliburn Date: Sat Feb 3 20:25:10 2007 -0600 maintainers: add atl1 maintainers MAINTAINERS: add atl1 maintainers Add a maintainers entry for atl1. Signed-off-by: Jay Cliburn Signed-off-by: Jeff Garzik commit a407a6a085ed149c479562a658f4a06c5ffd347b Author: Stephen Hemminger Date: Fri Feb 2 08:22:54 2007 -0800 skge: version 1.10 Mark this as 1.10 because WOL now works Signed-off-by: Stephen Hemminger Signed-off-by: Jeff Garzik commit a504e64ab42bcc27074ea37405d06833ed6e0820 Author: Stephen Hemminger Date: Fri Feb 2 08:22:53 2007 -0800 skge: WOL support Add WOL support for Yukon chipsets in skge device. Signed-off-by: Stephen Hemminger Signed-off-by: Jeff Garzik commit 1479d13cb5304c452e6d7398c7771974c1014846 Author: Stephen Hemminger Date: Fri Feb 2 08:22:52 2007 -0800 skge: use dev_printk Use dev_printk related macros for PCI related errors and warnings Signed-off-by: Stephen Hemminger Signed-off-by: Jeff Garzik commit fae87592280039837fdd72c5ecdac2af2eb97f63 Author: Stephen Hemminger Date: Fri Feb 2 08:22:51 2007 -0800 skge: handle zero address at open Some motherboards are broken and have no address set. Failing at probe time prevents the device from ever being used (like to download a fixed BIOS). Instead warn on probe and check again when device is brought up. That way the address can be set. Signed-off-by: Stephen Hemminger Signed-off-by: Jeff Garzik commit a7bed27dc69e3bc9238549a4964ea94ec318362c Author: Al Viro Date: Mon Jan 29 15:36:54 2007 -0500 b44 endian annotations Signed-off-by: Al Viro Signed-off-by: Jeff Garzik commit 9ad0830f307bcd8dc285cfae58998d43b21727f4 Author: David Howells Date: Tue Feb 6 13:45:51 2007 +0000 [PATCH] Keys: Fix key serial number collision handling Fix the key serial number collision avoidance code in key_alloc_serial(). This didn't use to be so much of a problem as the key serial numbers were allocated from a simple incremental counter, and it would have to go through two billion keys before it could possibly encounter a collision. However, now that random numbers are used instead, collisions are much more likely. This is fixed by finding a hole in the rbtree where the next unused serial number ought to be and using that by going almost back to the top of the insertion routine and redoing the insertion with the new serial number rather than trying to be clever and attempting to work out the insertion point pointer directly. This fixes kernel BZ #7727. Signed-off-by: David Howells Signed-off-by: Linus Torvalds commit 76c329563c5b8663ef27eb1bd195885ab826cbd0 Author: Oleg Verych Date: Tue Feb 6 02:18:22 2007 +0100 [PATCH] kbuild: correctly skip tilded backups in localversion files Tildes as in path as in filenames are handled correctly now: only files, containing tilde '~', are backups, thus are not valid. [KJ]: Definition of `space' was removed, scripts/Kbuild.include has one. That definition was taken right from the GNU make manual, while Kbuild's version is original. Cc: Roman Zippel Cc: Bastian Blank Cc: Sam Ravnborg Signed-off-by: Oleg Verych Signed-off-by: Linus Torvalds commit 5de043f4bd11a9e0a3e8daec7d1905da575a76b7 Author: Oleg Verych Date: Tue Feb 6 02:18:21 2007 +0100 [PATCH] kbuild: improve option checking, Kbuild.include cleanup GNU binutils, root users, tmpfiles, external modules ro builds must be fixed to do the right thing now. Cc: Roman Zippel Cc: Sam Ravnborg Cc: Horst Schirmeier Cc: Jan Beulich Cc: Daniel Drake Cc: Andi Kleen Cc: Randy Dunlap Signed-off-by: Oleg Verych Signed-off-by: Linus Torvalds commit f6112ec27a8f0eee6c5a996f65c7bfd9457d9f85 Author: Oleg Verych Date: Tue Feb 6 02:18:20 2007 +0100 [PATCH] kbuild scripts: replace gawk, head, bc with shell, update Replacing overhead of using some (external) programs instead of good old `sh'. Cc: Roman Zippel Cc: Sam Ravnborg Cc: William Stearns Cc: Martin Schlemmer Signed-off-by: Oleg Verych Acked-by: Mark Lord Signed-off-by: Linus Torvalds commit dc2e2f33bbf07344995357314fd8887f6564dba7 Author: Noriaki TAKAMIYA Date: Sun Oct 22 15:06:46 2006 +1000 [CRYPTO] doc: added the developer of Camellia cipher This patch adds the developer of Camellia cipher algorithm. Signed-off-by: Noriaki TAKAMIYA Signed-off-by: Herbert Xu commit 6a0dc8d733de4aca958a73019877f96b4754d671 Author: Noriaki TAKAMIYA Date: Sun Oct 22 15:05:57 2006 +1000 [IPSEC]: added the entry of Camellia cipher algorithm to ealg_list[] This patch adds the entry of Camellia cipher algorithm to ealg_list[]. Signed-off-by: Noriaki TAKAMIYA Signed-off-by: Herbert Xu commit 390fbd1bfaa7b561af8e4f385067c55bdf4100ba Author: Noriaki TAKAMIYA Date: Sun Oct 22 15:02:48 2006 +1000 [IPSEC]: added the definition of Camellia cipher This patch adds the definitions used by pfkeyv2 interface for Camellia cipher algorithm. Signed-off-by: Noriaki TAKAMIYA Signed-off-by: Herbert Xu commit 02ab5a7056bd8441ba6ae8ba8662d4296c202ecb Author: Noriaki TAKAMIYA Date: Wed Jan 24 21:48:19 2007 +1100 [CRYPTO] camellia: added the testing code of Camellia cipher This patch adds the code of Camellia code for testing module. Signed-off-by: Noriaki TAKAMIYA Signed-off-by: Herbert Xu commit d64beac050914de6fe6565741b39905ecd5994b7 Author: Noriaki TAKAMIYA Date: Wed Jan 24 21:47:48 2007 +1100 [CRYPTO] camellia: added the code of Camellia cipher algorithm. This patch adds the main code of Camellia cipher algorithm. Signed-off-by: Noriaki TAKAMIYA Signed-off-by: Herbert Xu commit 04ac7db3f23d98abe5d3c91d21b0e45fc09e74ea Author: Noriaki TAKAMIYA Date: Sun Oct 22 14:49:17 2006 +1000 [CRYPTO] camellia: Add Kconfig entry. This patch adds the Kconfig entry for Camellia. Signed-off-by: Noriaki TAKAMIYA Signed-off-by: Herbert Xu commit 09cb914f096bd38b22341af291236b65cf55ceee Author: Richard Knutsson Date: Wed Jan 24 21:39:34 2007 +1100 [CRYPTO] geode: Convert pci_module_init() to pci_register_driver() Replace uses of the obsolete pci_module_init function. Signed-off-by: Richard Knutsson Signed-off-by: Herbert Xu commit 78a1fe4f242cbe6b4578e072b75e171b92745afa Author: Herbert Xu Date: Sun Dec 24 10:02:00 2006 +1100 [CRYPTO] api: Use structs for cipher/compression Now that all cipher/compression users have switched over to the new allocation scheme, we can get rid of the compatility defines and use proper structs for them. Signed-off-by: Herbert Xu commit 6b701dde8e0584f3bf0b6857d0e92f7ed15ed6f9 Author: Herbert Xu Date: Sun Dec 24 09:59:42 2006 +1100 [CRYPTO] xcbc: Use new cipher interface This patch changes xcbc to use the new cipher encryt_one interface. Signed-off-by: Herbert Xu commit 27d2a3300755387d2fec231d37944907ff992ce8 Author: Herbert Xu Date: Wed Jan 24 20:50:26 2007 +1100 [CRYPTO] api: Allow multiple frontends per backend This patch adds support for multiple frontend types for each backend algorithm by passing the type and mask through to the backend type init function. Signed-off-by: Herbert Xu commit 2e306ee016fd4750289e65c3b1856db569f1f3f2 Author: Herbert Xu Date: Sun Dec 17 10:05:58 2006 +1100 [CRYPTO] api: Add type-safe spawns This patch allows spawns of specific types (e.g., cipher) to be allocated. Signed-off-by: Herbert Xu commit f1ddcaf3393b7a3871809b97fae90fac841a1f39 Author: Herbert Xu Date: Sat Jan 27 10:05:15 2007 +1100 [CRYPTO] api: Remove deprecated interface This patch removes the old cipher interface and related code. Signed-off-by: Herbert Xu commit ba8da2a9485f22455dcb06dd17e2f6d94b81ba89 Author: Herbert Xu Date: Sun Dec 17 08:57:38 2006 +1100 [CRYPTO] tcrypt: Removed vestigial crypto_alloc_tfm call The crypto_comp conversion missed the last remaining crypto_alloc_tfm call. This patch replaces it with crypto_alloc_comp. Signed-off-by: Herbert Xu commit 90831639a65592d6d3dc888dc3341f54ebf932e6 Author: David Howells Date: Sat Dec 16 12:13:14 2006 +1100 [CRYPTO] fcrypt: Add FCrypt from RxRPC Add a crypto module to provide FCrypt encryption as used by RxRPC. Signed-Off-By: David Howells Signed-off-by: Herbert Xu commit 91652be5d1b901673a8e926455f0ed146cfaa588 Author: David Howells Date: Sat Dec 16 12:09:02 2006 +1100 [CRYPTO] pcbc: Add Propagated CBC template Add PCBC crypto template support as used by RxRPC. Signed-Off-By: David Howells Signed-off-by: Herbert Xu commit a28091ae170cd06695bf461905c5b97a165633ba Author: Andrew Donofrio Date: Sun Dec 10 12:10:20 2006 +1100 [CRYPTO] tcrypt: Added test vectors for sha384/sha512 This patch adds tests for SHA384 HMAC and SHA512 HMAC to the tcrypt module. Test data was taken from RFC4231. This patch is a follow-up to the discovery (bug 7646) that the kernel SHA384 HMAC implementation was not generating proper SHA384 HMACs. Signed-off-by: Andrew Donofrio Signed-off-by: Herbert Xu commit fb469840b8c34b2f95b40a64b271f245cc1075b7 Author: Herbert Xu Date: Sun Dec 10 10:45:28 2006 +1100 [CRYPTO] all: Check for usage in hard IRQ context Using blkcipher/hash crypto operations in hard IRQ context can lead to random memory corruption due to the reuse of kmap_atomic slots. Since crypto operations were never meant to be used in hard IRQ contexts, this patch checks for such usage and returns an error before kmap_atomic is performed. Signed-off-by: Herbert Xu commit a850790f6c903f1a89d0dbf953946d231df3fe6b Author: Steve French Date: Tue Feb 6 20:43:30 2007 +0000 [CIFS] Minor cleanup Missing tab. Missing entry in changelog Signed-off-by: Steve French commit 03c6d130f690dba46387480de80acf458a6fd14c Author: Len Brown Date: Tue Feb 6 15:28:23 2007 -0500 ACPICA: reduce table header messages to fit within 80 columns Signed-off-by: Len Brown commit d390008ebf42bdfda106e9de2b2d0abcc9858e26 Author: Ralf Baechle Date: Tue Feb 6 16:43:31 2007 +0000 [MIPS] Yosemite: Fix missing parens in SERIAL_READ_1 macro Signed-off-by: Ralf Baechle commit c55197eb549dc09a52b6d91e6f26709a6d6815e5 Author: Yoichi Yuasa Date: Tue Feb 6 10:59:22 2007 +0900 [MIPS] Fix warnings in run_uncached on 32bit kernel arch/mips/lib/uncached.c: In function 'run_uncached': arch/mips/lib/uncached.c:47: warning: comparison is always true due to limited range of data type arch/mips/lib/uncached.c:48: warning: comparison is always false due to limited range of data type arch/mips/lib/uncached.c:57: warning: comparison is always true due to limited range of data type arch/mips/lib/uncached.c:58: warning: comparison is always false due to limited range of data type Signed-off-by: Yoichi Yuasa Signed-off-by: Ralf Baechle commit 131c1a2b6eef87485f7e280817d97615ea2a1551 Author: Chris Dearman Date: Thu Feb 1 19:54:13 2007 +0000 [MIPS] Comment fix Signed-off-by: Chris Dearman Signed-off-by: Ralf Baechle commit be701306eba49c9157506d4bbe40dbed7969a915 Author: Ralf Baechle Date: Sun Feb 4 23:23:00 2007 +0000 [MIPS] MT: Nuke duplicate mips_mt_regdump() prototype. Signed-off-by: Ralf Baechle commit fd046eb5378f2bc59851fcbc91957d01529fc3db Author: Alexander Bigga Date: Thu Dec 21 11:25:19 2006 +0100 [MIPS] Alchemy: Fix PCI-memory access The problem was introduced in 2.6.18.3 with the casting of some 36bit-defines (PCI memory) in au1000.h to resource_size_t which may be u32 or u64 depending on the experimental CONFIG_RESOURCES_64BIT. With unset CONFIG_RESOURCES_64BIT, the pci-memory cannot be accessed because the ioremap in arch/mips/au1000/common/pci.c already used the truncated addresses. With set CONFIG_RESOURCES_64BIT, things get even worse, because PCI-scan aborts, due to resource conflict: request_resource() in arch/mips/pci/pci.c fails because the maximum iomem-address is 0xffffffff (32bit) but the pci-memory-start-address is 0x440000000 (36bit). To get pci working again, I propose the following patch: 1. remove the resource_size_t-casting from au1000.h again 2. make the casting in arch/mips/au1000/common/pci.c (it's allowed and necessary here. The 36bit-handling will be done in __fixup_bigphys_addr). With this patch pci works again like in 2.6.18.2, the gcc-compile warnings in pci.c are gone and it doesn't depend on CONFIG_EXPERIMENTAL. Signed-off-by: Alexander Bigga Signed-off-by: Ralf Baechle commit 37f26742437df885ddd72150ab352d0a931cd3a7 Author: Chris Dearman Date: Thu Feb 1 19:54:13 2007 +0000 [MIPS] Move .set reorder out of conditional code Signed-off-by: Chris Dearman Signed-off-by: Ralf Baechle commit 6d6671066a311703bca1b91645bb1e04cc983387 Author: Chris Dearman Date: Thu Feb 1 19:54:13 2007 +0000 [MIPS] Check FCSR for pending interrupts before restoring from a context. Signed-off-by: Chris Dearman Signed-off-by: Ralf Baechle commit b86b30f81c7601d9a410d2ce0c64d9ba50d673ae Author: Ralf Baechle Date: Tue Nov 7 09:23:57 2006 +0000 [MIPS] Jaguar ATX: Fix large number of warnings. Signed-off-by: Ralf Baechle commit 3d0f82aea19649a2fd1169cfe63a9b522355386b Author: Ralf Baechle Date: Tue Nov 7 09:25:51 2006 +0000 [MIPS] Jaguar: Fix MAC address detection after platform_device conversion. Signed-off-by: Ralf Baechle commit 5868756dcbf4b585c3c485e43fc36844c038cef5 Author: Ralf Baechle Date: Mon Feb 5 00:33:21 2007 +0000 [MIPS] SMTC: Make a bunch of functions and variables static. Signed-off-by: Ralf Baechle commit 99d233fa9bba1916050dd27d74530342af68b6db Author: Joseph S. Myers Date: Wed Jan 10 12:30:50 2007 +0000 [MIPS] Use compat_sys_pselect6 The N32 and O32 pselect6 syscalls need to use compat_sys_pselect6 to translate arguments from 32-bit to 64-bit layout. Signed-off-by: Joseph Myers Signed-off-by: Ralf Baechle commit 447deafba4de56bfa5ed5d5778e56afe55432394 Author: Ralf Baechle Date: Mon Feb 5 00:34:20 2007 +0000 [MIPS] SMTC: Cleanup idle hook invocation. Signed-off-by: Ralf Baechle commit 7418cb89af6f9e21660d60a4bd088a8b6fd11e81 Author: David Quigley Date: Wed Jun 28 09:36:46 2006 -0400 [MIPS] SELinux: Add security hooks to mips-mt {get,set}affinity This patch adds LSM hooks into the setaffinity and getaffinity functions for the mips architecture to enable security modules to control these operations between tasks with different security attributes. This implementation uses the existing task_setscheduler and task_getscheduler LSM hooks. Signed-Off-By: David Quigley Acked-by: Stephen Smalley Signed-off-by: James Morris Signed-off-by: Ralf Baechle commit c9170617510059c750cb91207b08f35001571a22 Author: Ralf Baechle Date: Mon Feb 5 00:05:08 2007 +0000 [MIPS] IRIX: Linux coding style cleanups. Signed-off-by: Ralf Baechle commit 3f21cdee412089ed7ea12c3650bfb4211cf0b1d0 Author: Ralf Baechle Date: Tue Nov 7 10:19:05 2006 +0000 [MIPS] PB1100: Fix pile of warnings CC arch/mips/au1000/pb1100/board_setup.o arch/mips/au1000/pb1100/board_setup.c: In function ‘board_setup’: arch/mips/au1000/pb1100/board_setup.c:104: warning: passing argument 1 of ‘readb’ makes pointer from integer without a cast arch/mips/au1000/pb1100/board_setup.c:105: warning: passing argument 1 of ‘readb’ makes pointer from integer without a cast arch/mips/au1000/pb1100/board_setup.c:105: warning: passing argument 2 of ‘writeb’ makes pointer from integer without a cast arch/mips/au1000/pb1100/board_setup.c:109: warning: passing argument 1 of ‘readb’ makes pointer from integer without a cast arch/mips/au1000/pb1100/board_setup.c:110: warning: passing argument 1 of ‘readb’ makes pointer from integer without a cast arch/mips/au1000/pb1100/board_setup.c:110: warning: passing argument 2 of ‘writeb’ makes pointer from integer without a cast arch/mips/au1000/pb1100/board_setup.c:51: warning: unused variable ‘sys_clksrc’ arch/mips/au1000/pb1100/board_setup.c:51: warning: unused variable ‘sys_freqctrl’ arch/mips/au1000/pb1100/board_setup.c:50: warning: unused variable ‘pin_func’ Signed-off-by: Ralf Baechle commit 786d7cdd06581773ee7913560838d6f4487d2d9f Author: Ralf Baechle Date: Tue Nov 7 09:58:30 2006 +0000 [MIPS] Alchemy: Fix bunch of warnings CC arch/mips/au1000/common/pci.o arch/mips/au1000/common/pci.c:42: warning: large integer implicitly truncated to unsigned type arch/mips/au1000/common/pci.c:43: warning: large integer implicitly truncated to unsigned type arch/mips/au1000/common/pci.c:49: warning: large integer implicitly truncated to unsigned type arch/mips/au1000/common/pci.c:50: warning: large integer implicitly truncated to unsigned type arch/mips/au1000/common/pci.c: In function ‘au1x_pci_setup’: arch/mips/au1000/common/pci.c:82: warning: ISO C90 forbids mixed declarations and code Signed-off-by: Ralf Baechle commit e0daad449c5195fa4552c60392eeee4e5c58d31c Author: Ralf Baechle Date: Mon Feb 5 00:10:11 2007 +0000 [MIPS] Whitespace cleanups. Signed-off-by: Ralf Baechle commit 722b05a0c1498ef12972bbd5084eded498d75fb4 Author: Ralf Baechle Date: Tue Nov 7 10:22:31 2006 +0000 [MIPS] Alchemy: Fix bunch more warnings. Signed-off-by: Ralf Baechle commit 25b8ac3ba46ee3d586a9c00c1771dca58314714e Author: Ahmed S. Darwish Date: Mon Feb 5 04:42:11 2007 +0200 [MIPS] Use ARRAY_SIZE macro when appropriate Signed-off-by: Ahmed S. Darwish Signed-off-by: Ralf Baechle commit 3e7f9b8254b82f7261b2c56ffaf864198c135ee5 Author: Jan Altenberg Date: Thu Jan 25 20:46:14 2007 +0100 [MIPS] Fix some whitespace damage Signed-off-by: Jan Altenberg Signed-off-by: Ralf Baechle commit 811d944901705b8c14b945ba51caff5e912bb9e3 Author: Mathieu Desnoyers Date: Sat Feb 3 23:16:51 2007 -0500 [MIPS] Add missing ifdef arch/mips/pmc-sierra/yosemite/setup.c early_serial_setup is only defined when CONFIG_SERIAL_8250 is set. Signed-off-by: Mathieu Desnoyers Signed-off-by: Ralf Baechle commit 19487f1e8a288da0d84b48d086167cf328080938 Author: Atsushi Nemoto Date: Sun Feb 4 00:57:25 2007 +0900 [MIPS] Fix pb1200/irqmap.c and apply some missed patches pb1200/irqmap.c had been broken a while due to non-named initializer and had missed some recent IRQ related changes. Apply these commits to this file. [MIPS] IRQ cleanups commit 1603b5aca4f15b34848fb5594d0c7b6333b99144 [MIPS] use generic_handle_irq, handle_level_irq, handle_percpu_irq commit 1417836e81c0ab8f5a0bfeafa90d3eaa41b2a067 [MIPS] Compile __do_IRQ() when really needed commit e77c232cfc6e1250b2916a7c69225d6634d05a49 Signed-off-by: Atsushi Nemoto Signed-off-by: Ralf Baechle commit 06396094b2fad0c429cde795dac4a72bc4d32bf2 Author: Ralf Baechle Date: Fri Feb 2 11:13:35 2007 +0000 [MIPS] Do not allow oprofile to be enabled on SMTC. Oprofile cannot work on SMTC due to the limited number of counters. Signed-off-by: Ralf Baechle commit 4a969e1e223d517dd568c84ba3a66542a72c3680 Author: Robert P. J. Day Date: Thu Feb 1 05:45:14 2007 -0500 [MIPS] Remove superfluous "ifdef CONFIG_KGDB". Given that the Makefiles involved already have conditional compilation of the form: obj-$(CONFIG_KGDB) += dbg_io.o there seems to be little value for the dbg_io.c source files to check that config variable yet again. Signed-off-by: Robert P. J. Day Signed-off-by: Ralf Baechle commit be6e143741226ca59b24e6760de4578a5d4f98d7 Author: Ralf Baechle Date: Tue Feb 6 16:53:17 2007 +0000 [MIPS] vpe_elfload and vpe_run are only used locally, make them static. Signed-off-by: Ralf Baechle commit 418451c17870e56a176aeb4be1bed810f634fb5a Author: Ralf Baechle Date: Tue Feb 6 16:53:16 2007 +0000 [MIPS] SMTC: remove unused atomic_postclear Signed-off-by: Ralf Baechle commit 69a6c312e5ebb2e929ceb67e6246e2d9314f1d29 Author: Atsushi Nemoto Date: Wed Jan 24 01:21:05 2007 +0900 [MIPS] Move some kernel globals from asm file to C file. This get rid of some undesirable hole in BSS section due to random order of placement. Signed-off-by: Atsushi Nemoto Signed-off-by: Ralf Baechle commit 907e193ea798b3f73a71a2a01f938b69fd53b26d Author: Atsushi Nemoto Date: Tue Jan 23 22:29:06 2007 +0900 [MIPS] Remove _fdata from asm-mips/sections.h There is no _fdata symbol in kernel. Signed-off-by: Atsushi Nemoto Signed-off-by: Ralf Baechle commit 130e2fb78305b148b15cd3b5129596844c5f5e4f Author: Ralf Baechle Date: Tue Feb 6 16:53:15 2007 +0000 [MIPS] Kconfig: Provide sane NR_CPUS defaults for more configurations Signed-off-by: Ralf Baechle commit 24d55728dc96d2cb8f49064e012559300eb97610 Author: Yoichi Yuasa Date: Thu Jan 18 22:27:11 2007 +0900 [MIPS] vr41xx: Use symbolic names for IRQ numers Signed-off-by: Yoichi Yuasa Signed-off-by: Ralf Baechle commit 70d21cdeef6331e67ed87262c894cd6601f0dccc Author: Atsushi Nemoto Date: Mon Jan 15 00:07:25 2007 +0900 [MIPS] use name instead of typename for each irq_chip The "typename" field was obsoleted by the "name" field. Signed-off-by: Atsushi Nemoto Signed-off-by: Ralf Baechle commit ea6e942bea55b574bf2118bce8ee73185e754cfb Author: Atsushi Nemoto Date: Tue Jan 16 23:29:11 2007 +0900 [MIPS] Kconfig: Move some entries to appropriate menu Currently KEXEC is in "Machine selection", SECCOMP, PM, APM are in "Executable file formats" menu. Move KEXEC and SECCOMP to "Kernel type" and PM, APM to new "Power management options" menu. Also replace "config PM" with kernel/power/Kconfig. Signed-off-by: Atsushi Nemoto Signed-off-by: Ralf Baechle commit 9a0ad9e9d8cae1087fe7b0b137e1c84d12dc0c76 Author: Yoichi Yuasa Date: Thu Jan 11 23:53:18 2007 +0900 [MIPS] vr41xx: add MACINT controls This patch has added MACINT controls. They are necessary for VR4133 ethernet driver. Signed-off-by: Yoichi Yuasa Signed-off-by: Ralf Baechle commit 6f284a2ce7b8bc49cb8455b1763357897a899abb Author: Franck Bui-Huu Date: Wed Jan 10 09:44:05 2007 +0100 [MIPS] FLATMEM: introduce PHYS_OFFSET. The old code was assuming that min_low_pfn was always 0. This means that platforms having a big hole at their memory start paid the price of wasting some memory for the allocation of unused entries in mem_map[]. This patch prevents this waste. It introduces PHYS_OFFSET define which is the start of the physical memory and uses it wherever needed. Specially when converting physical/virtual addresses into virtual/physical ones. Currently all platforms defines PHYS_OFFSET to 0. Signed-off-by: Franck Bui-Huu Signed-off-by: Ralf Baechle commit db84dc61552ae0d198a8133d28b80c3838930ba8 Author: Franck Bui-Huu Date: Wed Jan 10 09:44:04 2007 +0100 [MIPS] Setup min_low_pfn/max_low_pfn correctly This patch makes a better usage of these two globals. 'min_low_pfn' is now correctly setup for all configs, which allow us to rely on it in boot memory code init. Signed-off-by: Franck Bui-Huu Signed-off-by: Ralf Baechle commit a583158c9ce822c96a718fbf877cec1e5f9ad75d Author: Atsushi Nemoto Date: Mon Dec 18 00:07:40 2006 +0900 [MIPS] Unify memset.S The 32-bit version and 64-bit version are almost equal. Unify them. This makes further improvements (for example, supporting CDEX, etc.) easier. Signed-off-by: Atsushi Nemoto Signed-off-by: Ralf Baechle commit c44e8d5e47b8ba672440b92eab0735628469116c Author: Atsushi Nemoto Date: Sat Dec 30 00:43:59 2006 +0900 [MIPS] prom_free_prom_memory cleanup Current prom_free_prom_memory() implementations are almost same as free_init_pages(), or no-op. Make free_init_pages() extern (again) and make prom_free_prom_memory() use it. Signed-off-by: Atsushi Nemoto Signed-off-by: Ralf Baechle commit 2fa7937bd8922e1fe4aae6a45e7e787fa45d6043 Author: Atsushi Nemoto Date: Sun Jan 14 23:41:42 2007 +0900 [MIPS] Make I8259A_IRQ_BASE customizable Move I8259A_IRQ_BASE from asm/i8259.h to asm/mach-generic/irq.h and make it really customizable. And remove I8259_IRQ_BASE declared on some platforms. Currently only NEC_CMBVR4133 is using custom I8259A_IRQ_BASE value. Signed-off-by: Atsushi Nemoto Signed-off-by: Ralf Baechle commit 97dcb82de6cc99a5669eb8e342efc24cceb1e77e Author: Atsushi Nemoto Date: Mon Jan 8 02:14:29 2007 +0900 [MIPS] Define MIPS_CPU_IRQ_BASE in generic header The irq_base for {mips,rm7k,rm9k}_cpu_irq_init() are constant on all platforms and are same value on most platforms (0 or 16, depends on CONFIG_I8259). Define them in asm-mips/mach-generic/irq.h and make them customizable. This will save a few cycle on each CPU interrupt. A good side effect is removing some dependencies to MALTA in generic SMTC code. Although MIPS_CPU_IRQ_BASE is customizable, this patch changes irq mappings on DDB5477, EMMA2RH and MIPS_SIM, since really customizing them might cause some header dependency problem and there seems no good reason to customize it. So currently only VR41XX is using custom MIPS_CPU_IRQ_BASE value, which is 0 regardless of CONFIG_I8259. Testing this patch on those platforms is greatly appreciated. Thank you. Signed-off-by: Atsushi Nemoto Signed-off-by: Ralf Baechle commit b6ec8f069bf202d2bd888aa9137b2cc3aad4c573 Author: Atsushi Nemoto Date: Mon Jan 8 00:20:24 2007 +0900 [MIPS] Remove unused rm9k_cpu_irq_disable() rm9k_cpu_irq_disable() is unused since commit 1603b5aca4f15b34848fb5594d0c7b6333b99144. Remove it. Signed-off-by: Atsushi Nemoto Signed-off-by: Ralf Baechle commit 1eaf122cda2c135f90b9e610a847e6d4627b577c Author: Ahmed S. Darwish Date: Tue Feb 6 18:08:28 2007 +0200 [AGPGART] intel-agp: Use ARRAY_SIZE macro when appropriate use ARRAY_SIZE macro already defined in kernel.h Signed-off-by: Ahmed S. Darwish Signed-off-by: Dave Jones commit 549ae0ac3d574a682e82b02e79259a65445a675b Author: Wendy Cheng Date: Tue Feb 6 03:52:16 2007 -0500 [GFS2] nfsd readdirplus assertion failure Glock assertion failure found in '07 NFS connectathon. One of the NFSDs is doing a "readdirplus" procedure call. It passes the logic into gfs2_readdir() where it obtains its directory inode glock. This is then followed by filehandle construction that invokes lookup code. It hits the assertion failure while trying to obtain the inode glock again inside gfs2_drevalidate(). This patch bypasses the recursive glock call if caller already holds the lock. Signed-off-by: S. Wendy Cheng Signed-off-by: Steven Whitehouse commit 51099005ab8e09d68a13fea8d55bc739c1040ca6 Author: Jan Beulich Date: Mon Feb 5 18:53:04 2007 -0800 [IA64] swiotlb abstraction (e.g. for Xen) Add abstraction so that the file can be used by environments other than IA64 and EM64T, namely for Xen. Signed-off-by: Jan Beulich Signed-off-by: Andrew Morton Signed-off-by: Tony Luck commit 563aaf064f3776623ff5e7aef511ac2eb7e5f0bb Author: Jan Beulich Date: Mon Feb 5 18:51:25 2007 -0800 [IA64] swiotlb cleanup - add proper __init decoration to swiotlb's init code (and the code calling it, where not already the case) - replace uses of 'unsigned long' with dma_addr_t where appropriate - do miscellaneous simplicfication and cleanup Signed-off-by: Jan Beulich Signed-off-by: Andrew Morton Signed-off-by: Tony Luck commit 93fbff63e62b87fe450814db41f859d60b048fb8 Author: Jan Beulich Date: Mon Feb 5 18:49:45 2007 -0800 [IA64] make swiotlb use bus_to_virt/virt_to_bus Convert all phys_to_virt/virt_to_phys uses to bus_to_virt/virt_to_bus, as is what is meant and what is needed in (at least) some virtualized environments like Xen. Signed-off-by: Jan Beulich Acked-by: Muli Ben-Yehuda Signed-off-by: Andrew Morton Signed-off-by: Tony Luck commit cde14bbfb3aa79b479db35bd29e6c083513d8614 Author: Jan Beulich Date: Mon Feb 5 18:46:40 2007 -0800 [IA64] swiotlb bug fixes This patch fixes - marking I-cache clean of pages DMAed to now only done for IA64 - broken multiple inclusion in include/asm-x86_64/swiotlb.h - missing call to mark_clean in swiotlb_sync_sg() - a (perhaps only theoretical) issue in swiotlb_dma_supported() when io_tlb_end is exactly at the end of memory Signed-off-by: Jan Beulich Signed-off-by: Andrew Morton Signed-off-by: Tony Luck commit 86afa9eb88af2248bcc91d5b3568c63fdea65d6c Author: Fenghua Yu Date: Mon Feb 5 16:07:57 2007 -0800 [IA64] Hook up getcpu system call for IA64 getcpu system call returns cpu# and node# on which this system call and its caller are running. This patch hooks up its implementation on IA64. Signed-off-by: Fenghua Yu Signed-off-by: Tony Luck commit 524fd988bb83153ddc9cfea867129eb6efb7ac23 Author: Bob Picco Date: Mon Feb 5 16:20:08 2007 -0800 [IA64] clean up sparsemem memory_present call Eliminate arch specific memory_present call ia64 NUMA by utilizing sparse_memory_present_with_active_regions. Acked-by: Mel Gorman Signed-off-by: Bob Picco Signed-off-by: Andrew Morton Signed-off-by: Tony Luck commit f1c0afa2e8802c01cf82c915e2bb3cb2a81570d4 Author: George Beshers Date: Mon Feb 5 16:20:04 2007 -0800 [IA64] show_mem() for IA64 sparsemem NUMA On the ia64 architecture only this patch upgrades show_mem() for sparse memory to be the same as it was for discontig memory. It has been shown to work on NUMA and flatmem architectures. Signed-off-by: George Beshers Signed-off-by: Andrew Morton Signed-off-by: Tony Luck commit 671496affdb5228786896864c3f900f66563e8c1 Author: Jan Beulich Date: Mon Feb 5 16:20:03 2007 -0800 [IA64] missing exports hwsw_sync_... Add missing exports to allow several drivers to be built as module with CONFIG_IA64_HP_ZX1_SWIOTLB. Signed-off-by: Jan Beulich Signed-off-by: Andrew Morton Signed-off-by: Tony Luck commit 71120061f271f00d8280659bf12e065ca6533d4d Author: Kirill Korotaev Date: Mon Feb 5 16:20:00 2007 -0800 [IA64] virt_to_page() can be called with NULL arg It does not return NULL when arg is NULL. Signed-off-by: Alexey Kuznetsov Signed-off-by: Kirill Korotaev Signed-off-by: Andrew Morton Signed-off-by: Tony Luck commit d00195ebc18049f067c8e389c186aa6f5d2b659f Author: Kirill Korotaev Date: Mon Feb 5 16:19:59 2007 -0800 [IA64] alignment bug in ldscript Occasionally the FSYS_RETURN patch list can have an odd length, causing other data structures to get out of alignment. In OpenVZ it is odd and we get misaligned kernel image, which does not boot. Signed-off-by: Alexey Kuznetsov Signed-off-by: Kirill Korotaev Signed-off-by: Andrew Morton Signed-off-by: Tony Luck commit 139b830477ccdca21b68c40f9a83ec327e65eb56 Author: Bob Picco Date: Tue Jan 30 02:11:09 2007 -0800 [IA64] register memory ranges in a consistent manner While pursuing and unrelated issue with 64Mb granules I noticed a problem related to inconsistent use of add_active_range. There doesn't appear any reason to me why FLATMEM versus DISCONTIG_MEM should register memory to add_active_range with different code. So I've changed the code into a common implementation. The other subtle issue fixed by this patch was calling add_active_range in count_node_pages before granule aligning is performed. We were lucky with 16MB granules but not so with 64MB granules. count_node_pages has reserved regions filtered out and as a consequence linked kernel text and data aren't covered by calls to count_node_pages. So linked kernel regions wasn't reported to add_active_regions. This resulted in free_initmem causing numerous bad_page reports. This won't occur with this patch because now all known memory regions are reported by register_active_ranges. Acked-by: Mel Gorman Signed-off-by: Bob Picco Acked-by: Simon Horman Signed-off-by: Andrew Morton Signed-off-by: Tony Luck commit d1598e05faa11d9f04e0a226122dd57674fb1dab Author: Jan Beulich Date: Wed Jan 3 09:26:21 2007 +0000 [IA64] Enable SWIOTLB only when needed Don't force CONFIG_SWIOTLB on when not actually needed (i.e. HP_ZX1 and SGI_SN2). Signed-off-by: Jan Beulich Signed-off-by: Tony Luck commit 980dbfd421c8d33edbd2fbc8f5a6233ccbefb052 Author: Russ Anderson Date: Mon Jan 8 16:05:08 2007 -0600 [IA64-SGI] Check for TIO errors on shub2 Altix The shub2 error interrupt handler must check for TIO errors. Signed-off-by: Russ Anderson (rja@sgi.com) Signed-off-by: Tony Luck commit f43691ef8a816018a0294c5a9fa9d22512886c49 Author: Alex Williamson Date: Mon Jan 15 09:33:55 2007 -0700 [IA64] remove bogus prototype ia64_esi_init() This function doesn't exist. Signed-off-by: Alex Williamson Signed-off-by: Tony Luck commit 451fe00cf7fd48ba55acd1c8b891e7a65e1b3f81 Author: Alex Williamson Date: Wed Jan 24 22:48:04 2007 -0700 [IA64] Clear IRQ affinity when unregistered When we offline a CPU, migrate_irqs() tries to determine whether the affinity bits of the IRQ descriptor match any of the remaining online CPUs. If not, it fixes up the interrupt to point somewhere else. Unfortunately, if an IRQ is unregistered the IRQ descriptor may still have affinity to the CPU being offlined, but the no_irq_chip handler doesn't provide a set_affinity function. This causes us to hit the WARN_ON in migrate_irqs(). The easiest solution seems to be setting all the bits in the affinity mask when the last interrupt is removed from the vector. I hit this on an older kernel with Xen/ia64 using driver domains (so it probably needs more testing on upstream). Xen essentially uses the bind/unbind interface in sysfs to unregister a device from a driver and thus unregister the interrupt. Signed-off-by: Alex Williamson Signed-off-by: Tony Luck commit 06f87adff12e52429390b22c57443665b073cd82 Author: Len Brown Date: Fri Jan 26 00:38:53 2007 -0500 [IA64] fix ACPI Kconfig issues All IA64 systems except IA64_HP_SIM include ACPI and PCI. So prevent IA64 Kconfigs that try to do irritating things like building PCI without building ACPI. Signed-off-by: Len Brown Signed-off-by: Tony Luck commit c2c77fe8df3e0322a613ba1540910632ad14d96d Author: Bernhard Walle Date: Sun Jan 28 13:47:02 2007 +0100 [IA64] Fix NULL-pointer dereference in ia64_machine_kexec() This patch fixes a NULL-pointer dereference in ia64_machine_kexec(). The variable ia64_kimage is set in machine_kexec_prepare() which is called from sys_kexec_load(). If kdump wasn't configured before, ia64_kimage is NULL. machine_kdump_on_init() passes ia64_kimage() to machine_kexec() which assumes a valid value. The patch also adds a few sanity checks for the image to simplify debugging of similar problems in future. Signed-off-by: Bernhard Walle Signed-off-by: Tony Luck commit 87f76d3aafe5b5e0a1d6d857088a0263b35afa6b Author: bibo,mao Date: Tue Jan 30 11:02:19 2007 +0800 [IA64] find thread for user rbs address I encountered one problem when running ptrace test case the situation is this: traced process's syscall parameter needs to be accessed, but for sys_clone system call with clone_flag (CLONE_VFORK | CLONE_VM | SIGCHLD) parameter. This syscall's parameter accessing result is wrong. The reason is that vforked child process mm point is the same, but tgid is different. Without this patch find_thread_for_addr will return vforked process if vforked process is also stopped, but not the thread which calls vfork syscall. Signed-off-by: Tony Luck commit f5cd7872768d5856b1b409a33f516e5ac7798f75 Author: Olof Johansson Date: Wed Jan 31 21:43:54 2007 -0600 PA Semi PWRficient Ethernet driver Driver for the PA Semi PWRficient on-chip Ethernet (1/10G) Basic enablement, will be complemented with performance enhancements over time. PHY support will be added as well. Signed-off-by: Olof Johansson Signed-off-by: Jeff Garzik commit 1ee6dd770b2302e32fdae489f4fc58c374399da4 Author: Ralf Baechle Date: Wed Jan 31 14:09:29 2007 -0500 s2io: De-typedef driver. Removed namespace collisions due to usage of nic_t as per Ralf's patch Signed-off-by: Sivakumar Subramani Signed-off-by: Jeff Garzik commit a113ae066de6fc7ed33a6f420ea7dd2716a1920a Author: Sivakumar Subramani Date: Wed Jan 31 14:05:51 2007 -0500 s2io: Removed enabling of some of the unused interrupts. Removed unused code in en_dis_able_nic_intrs(), TX_DMA_INTR, RX_DMA_INTR, TX_XGXS_INTR, MC_INTR Signed-off-by: Sivakumar Subramani Signed-off-by: Jeff Garzik commit 372cc5972de0eb5b15403d37fa63dcb4f9134ee0 Author: Sivakumar Subramani Date: Wed Jan 31 13:32:57 2007 -0500 s2io: Fixes in updating skb->truesize and code cleanup. 1. Fix for updating skb->truesize properly. 2. Disable NAPI only if more than one ring configured in case of MSI/MSI-X interrupts. Previously we were disabling NAPI irrespective of number of rings when MSI/MSI-X interrupts were used. 3. Code cleanup. Signed-off-by: Sivakumar Subramani Signed-off-by: Jeff Garzik commit 19a605220cf83a5ec5f8d9f9943e862ebf18f93f Author: Sivakumar Subramani Date: Wed Jan 31 13:30:49 2007 -0500 S2IO: Fixes for reset and link handling. 1. Fix for reset and link handling. 2. Allow for promiscuos mode and multicast state be maintained through ifconfig up and down. 3. Support to print adapter serial number. Signed-off-by: Sivakumar Subramani Signed-off-by: Jeff Garzik commit db874e65ae93861461f83658fdec08368252cd2e Author: Sivakumar Subramani Date: Wed Jan 31 13:28:08 2007 -0500 s2io: Making LRO and UFO as module loadable parameter. This patch adds two load parameters napi and ufo. Previously NAPI was compilation option with these changes wan enable disable NAPI using load parameter. Also we are introducing ufo load parameter to enable/disable ufo feature Signed-off-by: Sivakumar Subramani Signed-off-by: Jeff Garzik commit 7517c1b78759921daa679f1efba5d5dc0c81930e Author: Krzysztof Halasa Date: Tue Jan 30 16:10:24 2007 +0100 PC300too alternative WAN driver The attached patch adds an alternative driver "pc300too" for PCI WAN cards PC300/RSV and PC300/X21 made by Cyclades Corp. (now Avocent Corp). Signed-off-by: Krzysztof Halasa Signed-off-by: Jeff Garzik commit 1d68e93d65d63814388d1a0b3de028de6dc27ae0 Author: Divy Le Ray Date: Tue Jan 30 19:44:35 2007 -0800 cxgb3 - Add dual licensing Dual licensing, needed for OFED 1.2 Signed-off-by: Divy Le Ray Signed-off-by: Jeff Garzik commit a13fbee086310cb99a73958943d4d8103bf52f3a Author: Divy Le Ray Date: Tue Jan 30 19:44:29 2007 -0800 cxgb3 - Add Include in adapter.h Signed-off-by: Divy Le Ray Signed-off-by: Jeff Garzik commit f2aa52086fef57506980df68b92e6bd6faef3c85 Author: Divy Le Ray Date: Tue Jan 30 19:44:18 2007 -0800 cxgb3 - Remove BUG_ON from t3b_intr_napi In some cases, SG_DATA_INTR won't clear on read and the following interrupt may cause us to assert because NAPI is already scheduled. Remove the assertion, NAPI can handle attempts to rearm it while it's already scheduled. Signed-off-by: Divy Le Ray Signed-off-by: Jeff Garzik commit f2c6879e062071d94d208fb22800410bf8bab294 Author: Divy Le Ray Date: Tue Jan 30 19:44:13 2007 -0800 cxgb3 - white space to tabs Use tabs in comments. Signed-off-by: Divy Le Ray Signed-off-by: Jeff Garzik commit 3b1d307b319cce3d013801b267965ac4c31ce58c Author: Divy Le Ray Date: Tue Jan 30 19:44:07 2007 -0800 cxgb3 - Clean up HW init routine Clean up the tp_config() routine. Signed-off-by: Divy Le Ray Signed-off-by: Jeff Garzik commit b5a44bcbf53f1af1f24e7fe0e5008eca85659220 Author: Divy Le Ray Date: Tue Jan 30 19:44:01 2007 -0800 cxgb3 - bogus status error string Remove a status error string from the pci-x context and add it where it belongs - the pci-e context. Signed-off-by: Divy Le Ray Signed-off-by: Jeff Garzik commit 6195c71d652d337521ec8431c0923a85d6aaaf71 Author: Divy Le Ray Date: Tue Jan 30 19:43:56 2007 -0800 cxgb3 - remove SW Tx credits coalescing Remove tx credit coalescing done in SW. The HW is caring care of it already. Signed-off-by: Divy Le Ray Signed-off-by: Jeff Garzik commit 14ab989245069907622ab9fd930275c086cee069 Author: Divy Le Ray Date: Tue Jan 30 19:43:50 2007 -0800 cxgb3 - bind qsets on multiport adapter Inform FW about the queue set->interface mapping. Signed-off-by: Divy Le Ray Signed-off-by: Jeff Garzik commit 4aac38990843b4f165ccf467b772e18827bff84c Author: Divy Le Ray Date: Tue Jan 30 19:43:45 2007 -0800 cxgb3 - FW versioning Clean up FW version checking. The supported FW version is now 3.1. Signed-off-by: Divy Le Ray Signed-off-by: Jeff Garzik commit b9662d0e9ca3092e1473f27628fd60fa33b1a97a Author: Andrew Morton Date: Tue Jan 30 00:33:04 2007 -0800 git-netdev-all: chelsio fix Cc: "Sunil Naidu" Cc: Jeff Garzik Signed-off-by: Andrew Morton Signed-off-by: Jeff Garzik commit 01243ecb794fc008155f257cc25b98e2b8e855e5 Author: Adrian Bunk Date: Sat Jan 27 00:00:03 2007 -0800 remove one remaining "#define BCM_TSO 1" Since it's no longer used, this "#define BCM_TSO 1" can now be removed. Signed-off-by: Adrian Bunk Cc: Jeff Garzik Signed-off-by: Andrew Morton Signed-off-by: Jeff Garzik commit 04b588d727cf49321458731727737cf330f04cd2 Author: Ahmed S. Darwish Date: Sat Jan 27 00:00:02 2007 -0800 UCC Ether driver: kmalloc casting cleanups A kmalloc casting cleanup patch. Signed-off-by: Ahmed Darwish Cc: Jeff Garzik Signed-off-by: Andrew Morton Signed-off-by: Jeff Garzik commit 7f60c64bd0e7262b51faefcce5d8df9d51d84b60 Author: shemminger@linux-foundation.org Date: Fri Jan 26 11:38:36 2007 -0800 sky2: handle network device allocation failure If alloc_etherdev() failed, then sky2_init_netdev will return NULL, and sky2_probe would end up returning 0 instead of -ENOMEM. Signed-off-by: Stephen Hemminger Signed-off-by: Jeff Garzik commit 2bf56fe25cef2a7652f7b2ab37ac14a336c76c75 Author: shemminger@linux-foundation.org Date: Fri Jan 26 11:38:39 2007 -0800 sky2: software rx/tx stats Maintain packet statistics in software rather than hardware. This is slightly slower, but allows easier debugging of problems where packets are still being received by PHY but not being handled by hardware. Signed-off-by: Stephen Hemminger Signed-off-by: Jeff Garzik commit 285e6ddd013bafa6278a0e4b76a25a075be74e14 Author: shemminger@linux-foundation.org Date: Fri Jan 26 11:38:40 2007 -0800 sky2: version 1.11.1 Version update to 1.11.1. Signed-off-by: Stephen Hemminger Signed-off-by: Jeff Garzik commit e77c2baf75a2ba3d8e7ad8677b193db2d03acace Author: YOSHIFUJI Hideaki / å‰è—¤è‹±æ˜Ž Date: Fri Jan 26 22:59:01 2007 +0900 PEGASUS: Fix typo in Corega products. s/FEter/FEther/. Signed-off-by: YOSHIFUJI Hideaki Signed-off-by: Jeff Garzik commit b29cf31d7ee7da285265577b0df5e62c6b5a6119 Author: YOSHIFUJI Hideaki / å‰è—¤è‹±æ˜Ž Date: Fri Jan 26 22:57:38 2007 +0900 ASIX: Add IO-DATA ETG-US2 Support. Signed-off-by: YOSHIFUJI Hideaki Signed-off-by: Jeff Garzik commit 21828163b2b31e0675cb3e66a2a4a231dec06236 Author: Ayaz Abdulla Date: Tue Jan 23 12:27:21 2007 -0500 forcedeth: statistics optimization This patch optimizes the data paths that can support hw counters. It removes the sw counted statistics. This is the last patch for the optimization set. Bumping up version of driver. Signed-Off-By: Ayaz Abdulla Signed-off-by: Jeff Garzik commit 57fff6986b6daae13947c565786757c05303f0f6 Author: Ayaz Abdulla Date: Tue Jan 23 12:27:00 2007 -0500 forcedeth: statistics supported This patch introduces hw statistics for older devices that supported it. It breaks up the counters supported into separate versions. Signed-Off-By: Ayaz Abdulla Signed-off-by: Jeff Garzik commit 4e16ed1b0e17a3832310031e2ddaeb0914eb837d Author: Ayaz Abdulla Date: Tue Jan 23 12:00:56 2007 -0500 forcedeth: tx max work This patch adds a limit to how much tx work can be done in each iteration of tx processing. If the max limit is reached, remaining tx completions will be handled by timer interrupt. Signed-Off-By: Ayaz Abdulla Signed-off-by: Jeff Garzik commit f0734ab658390380079369f7090dcf7aa226f394 Author: Ayaz Abdulla Date: Sun Jan 21 18:10:57 2007 -0500 forcedeth: irq data path optimization This patch optimizes the irq data paths and cleans up the code. Signed-Off-By: Ayaz Abdulla Signed-off-by: Jeff Garzik commit b01867cbd1853995946c8c838eff93a0885d8bc6 Author: Ayaz Abdulla Date: Sun Jan 21 18:10:52 2007 -0500 forcedeth: rx data path optimization This patch optimizes the rx data paths and cleans up the code. Signed-Off-By: Ayaz Abdulla Signed-off-by: Jeff Garzik commit 445583b89d71b48cf8c64e26acc5a710248feed7 Author: Ayaz Abdulla Date: Sun Jan 21 18:10:47 2007 -0500 forcedeth: tx data path optimization This patch optimizes the tx data paths and cleans up the code (removes vlan from descr1/2 since only valid for desc3, changes to make code easier to read, etc). Signed-Off-By: Ayaz Abdulla Signed-off-by: Jeff Garzik commit aaa37d2d099f97ced415546e285ac901e47a2437 Author: Ayaz Abdulla Date: Sun Jan 21 18:10:42 2007 -0500 forcedeth: tx limiting This patch optimizes the logic for tx limiting. It adds a flag to check on the completion side instead of recalculating the number of empty slots. Also, it removes the fields that were previous used for limiting since they have no value. Signed-Off-By: Ayaz Abdulla Signed-off-by: Jeff Garzik commit 86b22b0dfbf462e6ed75e54fc83575dae01e3c69 Author: Ayaz Abdulla Date: Sun Jan 21 18:10:37 2007 -0500 forcedeth: optimized routines This patch breaks up the routines into two versions, one for legacy descriptor versions (ver 1 and ver 2) and one for desc ver 3. This will make the new desc functions more leaner and further reductions will be made in next few patches. Signed-Off-By: Ayaz Abdulla Signed-off-by: Jeff Garzik commit 658f648ad1c2876e0ce5401e087d2d21d0262441 Author: Jay Vosburgh Date: Fri Jan 19 18:15:56 2007 -0800 bonding: update version Update version number to reflect recent changes. Signed-off-by: Jay Vosburgh Signed-off-by: Jeff Garzik commit 877cbd36b27e073eb78fe7073a433fbe0da7d5f8 Author: Jay Vosburgh Date: Fri Jan 19 18:15:47 2007 -0800 bonding: modify sysfs support to permit multiple loads The existing code would blindly attempt to create the bonding_masters file (in /sys/class/net) every time the module was loaded. When the module is loaded multiple times (which is the historical method used by initscripts and sysconfig to create multiple bonding interfaces), this caused load failure of the second module load attempt, as the creation request would fail. This changes the code to note the failure, arrange to not remove the bonding_masters file upon module exit, and then return success. Bonding interfaces created by the second or subsequent loads of the module will not exist in bonding_masters. This is not a significant change, as previously only the interfaces from the most recent load of the module would be listed. Both situations are less than optimal, but this case permits compatibility with existing distro configuration scripts, and is consistent. Note that previously, the sysfs create request would overwrite the exsting bonding_masters file and succeed, allowing multiple loads of the module. The sysfs code has recently changed to return an error if the file being created already exists. Patrick McHardy , who reported this problem, observed crashes on the old kernel (before sysfs checked for duplicates). I did not experience such crashes, but this change should resolve them. Signed-off-by: Jay Vosburgh Signed-off-by: Jeff Garzik commit 09c892797688312dc8a3c4d8b37dcb7207c1d48a Author: Jay Vosburgh Date: Fri Jan 19 18:15:38 2007 -0800 bonding: fix error check in sysfs creation The existing code did not correctly handle failures to create the per-interface sysfs group for bonding. Modified code to notice errors, and correctly unwind. Signed-off-by: Jay Vosburgh Signed-off-by: Jeff Garzik commit e4b91c484611da385e34ff0f8bb2744ae2c735b7 Author: Jay Vosburgh Date: Fri Jan 19 18:15:31 2007 -0800 bonding: fix device name allocation error The code to select names for the bonding interfaces was, for the non-sysfs creation case, always using a hard-coded set of bond0, bond1, etc, up to max_bonds. This caused conflicts for the second or subsequent loads of the module. Changed the code to obtain device names from dev_alloc_name(). Signed-off-by: Jay Vosburgh Signed-off-by: Jeff Garzik commit bc63eb9c7ec0eb7b091db2d82d46d1e68ff9e231 Author: Akinobu Mita Date: Tue Dec 19 13:09:08 2006 -0800 net: use bitrev8 Use bitrev8 for bmac, mace, macmace, macsonic, and skfp drivers. [akpm@osdl.org: use the API, not the array] Cc: Jeff Garzik Cc: Paul Mackerras Cc: Mirko Lindner Cc: Thomas Bogendoerfer Signed-off-by: Akinobu Mita Signed-off-by: Andrew Morton Signed-off-by: Jeff Garzik commit 079ca7da1e6d05c7cb82e9c4f2e1d98839332664 Author: Adrian Bunk Date: Tue Dec 12 17:24:39 2006 +0100 bonding.h: "extern inline" -> "static inline" "extern inline" generates a warning with -Wmissing-prototypes and I'm currently working on getting the kernel cleaned up for adding this to the CFLAGS since it will help us to avoid a nasty class of runtime errors. If there are places that really need a forced inline, __always_inline would be the correct solution. Signed-off-by: Adrian Bunk Signed-off-by: Jeff Garzik commit bd36b0ac5d06378c95b5149b6df5f413a6c985a5 Author: Ron Mercer Date: Wed Jan 3 16:26:08 2007 -0800 qla3xxx: Add support for Qlogic 4032 chip. Qlogic 4032 chip is an incremental change from the 4022. Signed-off-by: Ron Mercer Signed-off-by: Jeff Garzik commit 83d98b401c053d760e38571595d8f4fa76ee271b Author: Adrian Bunk Date: Thu Jan 4 19:53:30 2007 +0100 remove the broken OAKNET driver The OAKNET driver: - has been marked as BROKEN for more than two years and - is still marked as BROKEN. Drivers that had been marked as BROKEN for such a long time seem to be unlikely to be revived in the forseeable future. But if anyone wants to ever revive this driver, the code is still present in the older kernel releases. Signed-off-by: Adrian Bunk Signed-off-by: Jeff Garzik commit 24a427cf76984726641ea0d8163e61e99119069d Author: Stephen Hemminger Date: Mon Jan 8 11:26:12 2007 -0800 chelsio: more rx speedup Cleanup receive processing some more: * do the reserve padding of skb during setup * don't pass constants to get_packet * do smart prefetch of skb * make copybreak a module parameter Signed-off-by: Stephen Hemminger Signed-off-by: Jeff Garzik commit 3de00b8958b12d62712ae9500968c65d3b43bb27 Author: Stephen Hemminger Date: Mon Jan 8 11:26:30 2007 -0800 chelsio: NAPI speed improvement Speedup and cleanup the receive processing by eliminating the mmio read and a lock round trip. Signed-off-by: Stephen Hemminger Signed-off-by: Jeff Garzik commit 4d22de3e6cc4a09c369b504cd8bcde3385a974cd Author: Divy Le Ray Date: Thu Jan 18 22:04:14 2007 -0500 Add support for the latest 1G/10G Chelsio adapter, T3. This driver is required by the Chelsio T3 RDMA driver posted by Steve Wise. Signed-off-by: Divy Le Ray Signed-off-by: Jeff Garzik commit 0bf94faf64afaba6e7b49fd11541b59d2ba06d0e Author: Adrian Bunk Date: Thu Jan 11 14:48:59 2007 +0100 make hdlc_setup() static again hdlc_setup was exported, but this export was never used. If a driver using it actually shows up it can still be exported again. Signed-off-by: Adrian Bunk Acked-by: Krzysztof Halasa Signed-off-by: Jeff Garzik commit 0d63fb32b2b8c3464d9c1afc3ce3fd3ceec025b6 Author: Ayaz Abdulla Date: Tue Jan 9 13:30:13 2007 -0500 forcedeth: rx skb recycle This patch removes the code that recycled the skb on error. This will help in reducing the branches in the main data paths. Signed-Off-By: Ayaz Abdulla Signed-off-by: Jeff Garzik commit 164a86e40e6c74ec5a91c364ccf7b1a2295b0a52 Author: Ayaz Abdulla Date: Tue Jan 9 13:30:10 2007 -0500 forcedeth: tx locking This patch reduces the amount of code within the lock to only the critical sections. Signed-Off-By: Ayaz Abdulla Signed-off-by: Jeff Garzik commit 761fcd9e3e0aa2a02231d1631f31409be5e890d2 Author: Ayaz Abdulla Date: Tue Jan 9 13:30:07 2007 -0500 forcedeth: ring access This patch modifys ring access by using pointers. This avoids computing the current index and avoids accessing the base address of the rings. Signed-Off-By: Ayaz Abdulla Signed-off-by: Jeff Garzik commit d2f7841277d8613a780ab28d04d8f31a31816153 Author: Ayaz Abdulla Date: Tue Jan 9 13:30:02 2007 -0500 forcedeth: dma access This patch allows the hardware to fetch the tx and rx ring descriptors with 64 bytes per access instead of 32 bytes. Signed-Off-By: Ayaz Abdulla Signed-off-by: Jeff Garzik commit 95f48a71a254fa81ae4be1307ce3bb8361521a7d Author: Adrian Bunk Date: Tue Dec 19 13:08:48 2006 -0800 remove the broken SKMC driver The SKMC driver has: - already been marked as BROKEN in 2.6.0 three years ago and - is still marked as BROKEN. Drivers that had been marked as BROKEN for such a long time seem to be unlikely to be revived in the forseeable future. But if anyone wants to ever revive this driver, the code is still present in the older kernel releases. Signed-off-by: Adrian Bunk Cc: Jeff Garzik Signed-off-by: Andrew Morton Signed-off-by: Jeff Garzik commit bf345707299b34de90fbae062eff51e76561eb40 Author: Cesar Eduardo Barros Date: Tue Dec 19 13:08:47 2006 -0800 driver for Silan SC92031 netdev This is a driver for the Silan SC92031/Rsltek 8139D NIC chip. This chip is found on at least one counterfeit Encore ENL832-TX-RENT NIC [1], which came with a mini-CD with the 2.4 driver. A slightly older version of the driver was found at [2]. The main difference between them is that the newer one has a small bugfix in the RX path, a lot of gratuitous renaming of functions, all the printable strings changed to show as a "Rsltek 8139D" [sic], and a PCI ID of 8139 instead of 2031. The driver on this patch is a rewrite of the vendor drivers (based mostly on the older one). Changes from the previous patch sent to netdev: - Use MMIO instead of PIO - Changed TX bounce buffers allocation - Use skb_copy_and_csum_dev - Several small bug fixes - Tested for more than just a few minutes each time [1] See http://www.encore-usa.com/faq.php under ENL832-TX-RENT for more information [2] Look for SL_LINUX.ZIP (which is really a .tar.gz) at http://broadbandforum.in/dataone_Intex_LAN_cardlinux-t4207-s15.html [3] To compile on 2.6.17, simply add back the last argument to the interrupt handler in two places, and copy the boolean declarations from 2.6.19 [akpm@osdl.org: build fixes] Signed-off-by: Cesar Eduardo Barros Signed-off-by: Andrew Morton Signed-off-by: Jeff Garzik commit ae306cca3ada3c84f3e30e1091a98d99ee1d0557 Author: Stephen Hemminger Date: Wed Dec 20 13:06:36 2006 -0800 sky2: better power state management Improve power management and error handling by using pci_set_power_state(), instead of driver doing PCI PM register changes in the driver. Signed-off-by: Stephen Hemminger Signed-off-by: Jeff Garzik commit 1d39ed565cfcc7c4fe586de621aef495c4f94ffb Author: Arjan van de Ven Date: Tue Dec 12 14:06:23 2006 +0100 remove NETIF_F_TSO ifdefery Remove the NETIF_F_TSO #ifdef-ery in drivers/net; this was for old-old-2.4 compat (even current 2.4 has NETIF_F_TSO) but it's time to get rid of it by now. Signed-off-by: Arjan van de Ven Signed-off-by: Jeff Garzik commit 6d24998f07588ca83ce04e60af5a79e805df7532 Author: Linas Vepstas Date: Wed Dec 13 15:23:56 2006 -0600 Spidernet RX Debugging printout Add some debugging and error printing. The show_rx_chain() prints out the status of the rx chain, which shows that the status of the descriptors gets messed up after the second & subsequent RX ramfulls. Print out contents of bad packets if error occurs. Signed-off-by: Linas Vepstas Cc: James K Lewis Cc: Arnd Bergmann Signed-off-by: Jeff Garzik commit df519ab2c5a774e813459fcb3e3d080276baa7d8 Author: Linas Vepstas Date: Wed Dec 13 15:23:01 2006 -0600 Spidernet Avoid possible RX chain corruption Delete possible source of chain corruption; the hardware already knows the location of the tail, and writing it again is likely to mess it up. Signed-off-by: Linas Vepstas Cc: James K Lewis Cc: Arnd Bergmann Signed-off-by: Jeff Garzik commit 90476a20fa4742c827b437d9814a51d06c153884 Author: Linas Vepstas Date: Wed Dec 13 15:22:04 2006 -0600 Spidernet Memory barrier Add memory barrier to make sure that the rest of the RX descriptor state is flushed to memory before we tell the hardware that its ready to go. Signed-off-by: Linas Vepstas Cc: James K Lewis Cc: Arnd Bergmann Signed-off-by: Jeff Garzik commit 2c307db7e40ff537d39c2e66629ba718ee2a8e51 Author: Linas Vepstas Date: Wed Dec 13 15:20:59 2006 -0600 Spidernet RX Chain tail Tell the hardware the location of the rx ring tail. More punctuation cleanup. Signed-off-by: Linas Vepstas Cc: James K Lewis Cc: Arnd Bergmann Signed-off-by: Jeff Garzik commit a4182c50bcd6a20caae82c202436fe892f642150 Author: Linas Vepstas Date: Wed Dec 13 15:19:54 2006 -0600 Spidernet Remove unused variable Remove unused variable; this makes code easier to read. Tweak commentary. Signed-off-by: Linas Vepstas Cc: James K Lewis Cc: Arnd Bergmann Signed-off-by: Jeff Garzik commit 80dab7c7e5b7c4e53e9423c22375bfd9cbf7f2c3 Author: Linas Vepstas Date: Wed Dec 13 15:18:52 2006 -0600 Spidernet RX Refill The invocation of the rx ring refill routine is haphazard, it can be called from a central location. Signed-off-by: Linas Vepstas Cc: James K Lewis Cc: Arnd Bergmann Signed-off-by: Jeff Garzik commit 7f7223b8f11f9857fba1dbd5474882219a7ae6e9 Author: Linas Vepstas Date: Wed Dec 13 15:17:39 2006 -0600 Spidernet Cleanup return codes Simplify the somewhat convoluted use of return codes in the rx buffer handling. Signed-off-by: Linas Vepstas Cc: James K Lewis Cc: Arnd Bergmann Signed-off-by: Jeff Garzik commit 366684bd0d6bc5b224fc798675b9a85eb9279227 Author: Linas Vepstas Date: Wed Dec 13 15:16:18 2006 -0600 Spidernet another skb mem leak Another skb leak in an error branch. Fix this by adding call to dev_kfree_skb_irq() after moving to a more appropriate spot. Signed-off-by: Linas Vepstas Cc: James K Lewis Cc: Arnd Bergmann Signed-off-by: Jeff Garzik commit 05b346b552e13cc090ea908e2be183b377ff30a2 Author: Linas Vepstas Date: Wed Dec 13 15:15:15 2006 -0600 Spidernet RX skb mem leak One of the unlikely error branches has an skb memory leak. Fix this by handling the error conditions consistently. Signed-off-by: Linas Vepstas Cc: James K Lewis Cc: Arnd Bergmann Signed-off-by: Jeff Garzik commit 1cd173f66c392ede57fa10f614fca22d79501424 Author: Linas Vepstas Date: Wed Dec 13 15:12:26 2006 -0600 Spidernet cleanup un-needed API There is no need to pass a flag into spider_net_decode_one_descr() so remove this, and perform some othre minor cleanup. Signed-off-by: Linas Vepstas Cc: James K Lewis Cc: Arnd Bergmann Signed-off-by: Jeff Garzik commit 75856175c26f89198ec64eb2480ed00c4a39a5d6 Author: Linas Vepstas Date: Wed Dec 13 15:10:06 2006 -0600 Spidernet remove rxramfull tasklet Get rid of the rxramfull tasklet, and let the NAPI poll routine deal with this situation. (The rxramfull interrupt is simply stating that the h/w has run out of room for incoming packets). Signed-off-by: Linas Vepstas Cc: James K Lewis Cc: Arnd Bergmann Signed-off-by: Jeff Garzik commit 5a028877d2a350ebba3cda924cbf7f3bd2eb2135 Author: Linas Vepstas Date: Wed Dec 13 15:08:25 2006 -0600 Spidernet add net_ratelimit to suppress long output This patch adds net_ratelimit to many of the printks in order to limit extraneous warning messages (created in response to Bug 28554). This patch supercedes all previous ratelimit patches. This has been tested, please apply. From: James K Lewis Signed-off-by: James K Lewis Signed-off-by: Linas Vepstas Signed-off-by: Jeff Garzik commit d4ed8f8d1fb7d59eb63d2eada9a32c2f8c3795e2 Author: Linas Vepstas Date: Wed Dec 13 15:06:59 2006 -0600 Spidernet DMA coalescing The current driver code performs 512 DMA mappings of a bunch of 32-byte ring descriptor structures. This is silly, as they are all in contiguous memory. This patch changes the code to dma_map_coherent() each rx/tx ring as a whole. Signed-off-by: Linas Vepstas Cc: James K Lewis Cc: Arnd Bergmann Signed-off-by: Jeff Garzik commit 834324687d08e0f67b167934cb56406aa98ff8c6 Author: Francois Romieu Date: Tue Dec 12 00:13:48 2006 +0100 chelsio: tabulate the update of the statistic counters Let's try to avoid some code duplication. - cxgb2 The data are contiguous. Use plain memcpy. - ixf1010/pm3393/vsc7326 The cast of &mac->stats to (u64 *) is not wonderful but it is not clear if it is worth to add an ad-hoc union under the struct cmac_statistics. vsc7326_reg.h suggests that more statistics could be available. Signed-off-by: Francois Romieu commit 3e0f75be52605a901165fa1d8acf4ffd37a4857b Author: Francois Romieu Date: Tue Dec 5 23:57:41 2006 +0100 chelsio: misc cleanups in sge - duplicated code in sge::free_cmdQ_buffers ; - NET_IP_ALIGN is already defined in (included) ; - pci_alloc_consistent() returns void * ; - pci_alloc_consistent() returns a zeroed chunk of memory ; - early return in restart_tx_queues. Signed-off-by: Francois Romieu commit 47cbe6f47d854410d5c296098d87cf8151517c20 Author: Francois Romieu Date: Tue Dec 5 23:19:06 2006 +0100 chelsio: useless test in cxgb2::remove_one pci_get_drvadata() is necessarily distinct from NULL if cxgb2::init_one succeeded. cxgb2::remove_one is solely issued through the PCI device callback. Signed-off-by: Francois Romieu commit d7487421b629c5ca71ce23b10461ef0c3ad2c741 Author: Francois Romieu Date: Mon Dec 11 23:49:13 2006 +0100 chelsio: useless curly braces Signed-off-by: Francois Romieu commit 356bd1460d1e1c4e433e4114fdac02139bddf17c Author: Francois Romieu Date: Mon Dec 11 23:47:00 2006 +0100 chelsio: spaces, tabs and friends Signed-off-by: Francois Romieu commit b7d58394e65c7d90486026614a6ae26d82dd7756 Author: Francois Romieu Date: Mon Dec 11 23:41:36 2006 +0100 chelsio: the return statement is not a function Signed-off-by: Francois Romieu commit c697f83e8c880a1e69fb2a45a6e4aa0670e10602 Author: Francois Romieu Date: Tue Dec 5 22:38:00 2006 +0100 chelsio: move return, break and continue statements on their own line Signed-off-by: Francois Romieu commit ea8862dc86c0f5a0be012a0f2e9de1b2ccabbaa5 Author: Zhu Yi Date: Thu Jan 11 17:32:54 2007 +0800 [PATCH] ipw2200: add iwconfig rts/frag auto support This patch add ipw2200 support for iwconfig rts/frag auto. Signed-off-by: Zhu Yi Signed-off-by: John W. Linville commit 2e9b2467de69733c9ac455e261aef302d288fb17 Author: Daniel Drake Date: Thu Jan 4 03:33:54 2007 +0000 [PATCH] zd1211rw: Add ID for ZyXEL ZyAIR G-220 v2 Tested by Marijn Schouten zd1211b chip 0586:340f v4810 high 00-13-49 AL2230_RF pa0 g--- FCC ID: I88G220V2 Signed-off-by: Daniel Drake Signed-off-by: John W. Linville commit 6bbdce5ac755e3b3cdcf9bb9fdbcc2af78ad34d0 Author: John W. Linville Date: Tue Jan 2 21:22:05 2007 -0500 [PATCH] softmac: avoid assert in ieee80211softmac_wx_get_rate Unconfigured bcm43xx device can hit an assert() during wx_get_rate queries. This is because bcm43xx calls ieee80211softmac_start late (i.e. during open instead of probe). bcm43xx_net_open -> bcm43xx_init_board -> bcm43xx_select_wireless_core -> ieee80211softmac_start Fix is to check that device is running before completing ieee80211softmac_wx_get_rate. Signed-off-by: John W. Linville commit ff86a543e9de35c5b17a289a58aed0be4e7b9d22 Author: Kai Engert Date: Tue Dec 12 21:09:41 2006 +0100 [PATCH] prism54: add ethtool -i interface Add support for "ethtool -i" to prism54 driver. ethtool -i queries the specified device for associated driver information. This helps tools like Fedora's system-config-network to provide GUI management of network devices. I learned how to write this patch by reading the ipw2100 driver code. Signed-off-by: Kai Engert Signed-off-by: John W. Linville commit 01917382865bb640fc00df7ea476a14c8c539ec3 Author: Larry Finger Date: Sat Dec 30 23:30:32 2006 -0600 [PATCH] bcm43xx: Interrogate hardware-enable switch and update LEDs The current bcm43xx driver ignores any wireless-enable switches on mini-PCI and mini-PCI-E cards. This patch implements a new routine to interrogate the radio hardware enabled bit in the interface, logs the initial state and any changes in the switch (if debugging enabled), activates the LED to show the state, and changes the periodic work handler to provide 1 second response to switch changes and to account for changes in the periodic work specs. Signed-off-by: Larry Finger Signed-off-by: John W. Linville commit 33218ba1d114c2d8ce275b74ad47d0718af99a5a Author: Daniel Drake Date: Sat Dec 30 22:38:23 2006 +0000 [PATCH] zd1211rw: Add ID for Linksys WUSBF54G Tested by Henrik Hjelte zd1211b chip 13b1:0024 v4802 high 00-14-bf AL2230_RF pa0 ---- Signed-off-by: Daniel Drake Signed-off-by: John W. Linville commit c10ca77368a87079ff0303d8b7506f0e8a2be6d1 Author: Michael Buesch Date: Fri Dec 15 21:32:44 2006 +0100 [PATCH] Update Prism54 MAINTAINERS entry prism54-private@prism54.org bounces with SMTP error from remote mailer after RCPT TO:: host mx1.tuxfamily.net [212.85.158.8]: 550 unknown user developers@islsm.org seems to be the new mailing list. Signed-off-by: Michael Buesch Signed-off-by: John W. Linville commit 0ce34bc8f7d906d66ce6803f63399ef9bbe54012 Author: Daniel Drake Date: Tue Dec 12 01:26:11 2006 +0000 [PATCH] zd1211rw: Remove addressing abstraction Instead of passing our own custom 32-bit addresses around and translating them, this patch makes all our register address constants absolute and removes the translation. There are two ugly parts: - fw_reg_addr() is needed to compute addresses of firmware registers, as this is dynamic based upon firmware - inc_addr() needs a small hack to handle byte vs word addressing However, both of those are only small, and we don't use fw_regs a whole lot anyway. The bonuses here include simplicity and improved driver readability. Also, the fact that registers are now referenced by 16-bit absolute addresses (as opposed to 32-bit pseudo addresses) means that over 2kb compiled code size has been shaved off. Includes some touchups and sparse fixes from Ulrich Kunitz. Signed-off-by: Daniel Drake Signed-off-by: John W. Linville commit ee30276774451d657407855d95d9393ee8bc0bac Author: Daniel Drake Date: Tue Dec 12 01:25:52 2006 +0000 [PATCH] zd1211rw: Consistency for address space constants The zd1211rw address space has confused me once too many times. This patch introduces the following naming notation: Memory space is split into segments (cr, fw, eeprom) and segments may contain components (e.g. boot code inside eeprom). These names are arbitrary and only for the description below: x_START: Absolute address of segment start (previously these were named such as CR_BASE_OFFSET, but they weren't really offsets unless you were considering them as an offset to 0) x_LEN: Segment length x_y_LEN: Length of component y of segment x x_y_OFFSET: Relative address of component y into segment x. The absolute address for this component is (x_START + x_y_OFFSET) I also renamed EEPROM registers to EEPROM data. These 'registers' can't be written to using standard I/O and really represent predefined data from the vendor. Signed-off-by: Daniel Drake Signed-off-by: John W. Linville commit a2bdcc679288307f9237c9611a0cc0c3c06669a9 Author: Daniel Drake Date: Tue Dec 12 01:25:37 2006 +0000 [PATCH] zd1211rw: 2 new ZD1211B device ID's Philips SNU5600, tested by unibrow zd1211b chip 0471:1236 v4810 high 00-12-bf AL2230_RF pa0 g-- SMC Ez Connect 802.11g (SMCWUSB-G), tested by Victorino Sanz Prat zd1211b chip 083a:4505 v4810 full 00-13-f7 AL2230_RF pa0 g--N Signed-off-by: Daniel Drake Signed-off-by: John W. Linville commit 34c4491264ceafa5c81f74a5f24f49e8e24f12f2 Author: Daniel Drake Date: Tue Dec 12 01:25:13 2006 +0000 [PATCH] zd1211rw: Generic HMAC initialization Many of the registers written during ZD1211 HMAC initialization are duplicated exactly for ZD1211B. Move the identical ones into a generic part, and write the hardware-specific ones separately. Signed-off-by: Daniel Drake Signed-off-by: John W. Linville commit 7e721579479350b15b2bf1e232cd372c704aff7b Author: Auke Kok Date: Thu Jan 18 09:25:33 2007 -0800 e1000: update version to 7.3.20-k2 Signed-off-by: Auke Kok commit 7753b171c4e7604294060d4039214c8c8319bfca Author: Jesse Brandeburg Date: Thu Jan 18 09:25:31 2007 -0800 e1000: tune our dynamic itr transmit packet accounting The driver was still mis-calculating the number of bytes sent during transmit, now the driver computes what appears to be exactly 100% correct byte counts (not including CRC) when figuring out how many bytes and frames were sent during the current transmit packet. commit f6c57bafcdebed4429cdda206149ddcbb1d46e91 Author: Bruce Allan Date: Thu Jan 18 09:25:28 2007 -0800 e1000: clear ip csum info from context descriptor Since the driver sets the IP checksum insertion bit (IXSM in Status field) in transmit context descriptors, it should clear the IP checksum bits of any garbage so as not to confuse the hardware. Signed-off-by: Bruce Allan Signed-off-by: Auke Kok commit 9669f53b98974ede4728e288316296666722ab8c Author: Auke Kok Date: Thu Jan 18 09:25:26 2007 -0800 e1000: display flow control of link status at link up Print RX/TX flow control setting at link up time to display the actual link FC properties instead of the advertised values. Signed-off-by: Auke Kok commit 60cba200f11b6f90f35634c5cd608773ae3721b7 Author: Jesse Brandeburg Date: Thu Jan 18 09:25:23 2007 -0800 e1000: fix NAPI performance on 4-port adapters This fix attempts to solve a customer (IBM) reported issue with NAPI enabled e1000 having bad performance when transmitting simultaneously on four ports. The issue comes down to an interaction between NAPI, hardware interrupt balancing, and the driver rescheduling poll on the same processor. Try to fix by allowing the driver to re-enable interrupts sooner instead of polling one more time, when there was recently all the work completed in cleanup. Signed-off-by: Jesse Brandeburg Signed-off-by: Auke Kok commit b5fc8f0c43d388d76ebbb5650b20f4ce4420a5ad Author: Jesse Brandeburg Date: Thu Jan 18 09:25:21 2007 -0800 e1000: Fix MSI only interrupt handler routine Unfortunately the read-free MSI interrupt handler needs to flush write the icr register and thus we can't be read-free. Our MSI irq routine thus becomes a lot more simpler since we don't need to track link state anymore. Signed-off-by: Jesse Brandeburg Signed-off-by: Auke Kok commit bf3cea4d8a1a8deb21d247a0622f1aa54270e0f9 Author: Auke Kok Date: Thu Jan 18 09:25:18 2007 -0800 e1000: clean up debug output defines Remove unused MSGOUT macro and add "\n" to function debug output. Signed-off-by: Auke Kok commit 9990fa3cbd35046cce1eb4667bb2e33057c5ca1a Author: Jesse Brandeburg Date: Thu Jan 18 09:25:15 2007 -0800 e1000: simplify case handling gigabit at half duplex Remvoe duplicate code handling erraneous user supplied wrong case of gigabit speed with half duplex. Signed-off-by: Jesse Brandeburg Signed-off-by: Auke Kok commit ae0af3e3462fdada42deba30479aba70c6cf8b72 Author: Aron Griffis Date: Mon Feb 5 13:54:31 2007 -0800 [IA64] use snprintf() on features field of /proc/cpuinfo Some patches have turned up on xen-devel recently to convert strcpy() to safer alternatives and so forth. While reviewing those patches I noticed that the features string building could be cleaned up. This patch uses snprintf() instead of strcpy() and direct character pointer manipulation. It makes the features string building safe and gets rid of the special case for features output in show_cpuinfo() Additionally I removed the (int) cast of ARRAY_SIZE, which seems to serve no purpose. Signed-off-by: Aron Griffis Signed-off-by: Tony Luck commit 90f9d70a582c02f50b4dd847166cd5b037219891 Author: bibo,mao Date: Wed Jan 31 17:50:31 2007 +0800 [IA64] enable singlestep on system call As is pointed out in http://www.gelato.org/community/view_linear.php?id=1_1036&from=authors&value=Ian%20Wienand#1_1039, if single step on break instruction, the break fault has higher priority than the single-step trap. When the break fault handler is entered, it advances the IP by 1 instruction so break instruction single-stepping is skipped, actually it is next instruction which is single stepped. This patch modifies this, it adds TIF_SINGLESTEP bit for thread flags, and generate a fake sigtrap when single stepping break instruction. Test case in attachment can verify this. Any comments is welcome. Signed-off-by: bibo, mao Signed-off-by: Tony Luck commit c237508afa5d47282d3047784864013eebdc68ab Author: Horms Date: Mon Feb 5 13:49:10 2007 -0800 [IA64] kexec: Move machine_shutdown from machine_kexec.c to process.c This moves the ia64 implementation of machine_shutdown() from machine_kexec.c to process.c, which is in keeping with the implelmentation on other architectures, and seems like a much more appropriate home for it. Signed-off-by: Simon Horman Signed-off-by: Tony Luck commit 4d284cac76d0bfebc42d76b428c4e44d921200a9 Author: Heiko Carstens Date: Mon Feb 5 21:18:53 2007 +0100 [S390] Avoid excessive inlining. Signed-off-by: Heiko Carstens Signed-off-by: Martin Schwidefsky commit 162e006ef59266b9ebf34e3d15ca1f3d9ee956d7 Author: Heiko Carstens Date: Mon Feb 5 21:18:41 2007 +0100 [S390] Mark kernel text section read-only. Set read-only flag in the page table entries for the kernel image text section. This will catch all instruction caused corruptions withing the text section. Instruction replacement via kprobes still works, since it bypasses now dynamic address translation. Signed-off-by: Heiko Carstens Signed-off-by: Martin Schwidefsky commit ab14de6c37fae22911ba99f4171613e6d758050b Author: Heiko Carstens Date: Mon Feb 5 21:18:37 2007 +0100 [S390] Convert memory detection into C code. Hopefully this will make it more maintainable and less error prone. Code makes use of search_exception_tables(). Since it calls this function before the kernel exeception table is sorted, there is an early call to sort_main_extable(). This way it's easy to use the already present infrastructure of fixup sections. Also this would allows to easily convert the rest of head[31|64].S into C code. Signed-off-by: Heiko Carstens Signed-off-by: Martin Schwidefsky commit 31ee4b2f40994e8b21691f85cdd4052551a789b7 Author: Martin Schwidefsky Date: Mon Feb 5 21:18:31 2007 +0100 [S390] Calibrate delay and bogomips. Preset the bogomips number to the cpu capacity value reported by store system information in SYSIB 1.2.2. This value is constant for a particular machine model and can be used to determine relative performance differences between machines. Signed-off-by: Martin Schwidefsky commit 31cb4bd31a48f62105d037ad53192b94d4c08f53 Author: Michael Holzheu Date: Mon Feb 5 21:18:29 2007 +0100 [S390] Hypervisor filesystem (s390_hypfs) for z/VM This is an extension of the already existing hypfs for LPAR (DIAG 204). Data returned by DIAG 2fc is exported using the s390_hypfs when Linux is running under z/VM. Information about cpus and memory is provided. Data is put into different virtual files which can be accessed from user space. All values are represented as ASCII strings Signed-off-by: Michael Holzheu Signed-off-by: Martin Schwidefsky commit cced1dd42ebcebc7fa7f02fe487e48aa71752401 Author: Michael Holzheu Date: Mon Feb 5 21:18:26 2007 +0100 [S390] Add crypto support for 3592 tape devices 3592 tape devices are able to write data encrpyted on tape mediums. This z/Linux device driver support includes the following functions: * ioctl to switch on/off encryption * ioctl to query encryption status of drive * ioctls to set and query key encrypting keys (kekls) * long busy interrupt handling Signed-off-by: Michael Holzheu Signed-off-by: Martin Schwidefsky commit fe355b7f1c7400cbb71762a1237461be03f88265 Author: Hongjie Yang Date: Mon Feb 5 21:18:24 2007 +0100 [S390] boot from NSS support Add support to boot from a named saved segment (NSS). Signed-off-by: Hongjie Yang Signed-off-by: Martin Schwidefsky commit 1b2782948997cf5a0d1747de13d43ba7dfa7c543 Author: Jan Glauber Date: Mon Feb 5 21:18:22 2007 +0100 [S390] Support for s390 Pseudo Random Number Generator Starting with the z9 the CPU Cryptographic Assist Facility comes with an integrated Pseudo Random Number Generator. The generator creates random numbers by an algorithm similar to the ANSI X9.17 standard. The pseudo-random numbers can be accessed via a character device driver node called /dev/prandom. Similar to /dev/urandom any amount of bytes can be read from the device without blocking. Signed-off-by: Jan Glauber Signed-off-by: Martin Schwidefsky commit d54853ef8cb17296ac7bce9c77430fb7c80532d0 Author: Martin Schwidefsky Date: Mon Feb 5 21:18:19 2007 +0100 [S390] ETR support. This patch adds support for clock synchronization to an external time reference (ETR). The external time reference sends an oscillator signal and a synchronization signal every 2^20 microseconds to keep the TOD clocks of all connected servers in sync. For availability two ETR units can be connected to a machine. If the clock deviates for more than the sync-check tolerance all cpus get a machine check that indicates that the clock is out of sync. For the lovely details how to get the clock back in sync see the code below. Signed-off-by: Martin Schwidefsky commit c1821c2e9711adc3cd298a16b7237c92a2cee78d Author: Gerald Schaefer Date: Mon Feb 5 21:18:17 2007 +0100 [S390] noexec protection This provides a noexec protection on s390 hardware. Our hardware does not have any bits left in the pte for a hw noexec bit, so this is a different approach using shadow page tables and a special addressing mode that allows separate address spaces for code and data. As a special feature of our "secondary-space" addressing mode, separate page tables can be specified for the translation of data addresses (storage operands) and instruction addresses. The shadow page table is used for the instruction addresses and the standard page table for the data addresses. The shadow page table is linked to the standard page table by a pointer in page->lru.next of the struct page corresponding to the page that contains the standard page table (since page->private is not really private with the pte_lock and the page table pages are not in the LRU list). Depending on the software bits of a pte, it is either inserted into both page tables or just into the standard (data) page table. Pages of a vma that does not have the VM_EXEC bit set get mapped only in the data address space. Any try to execute code on such a page will cause a page translation exception. The standard reaction to this is a SIGSEGV with two exceptions: the two system call opcodes 0x0a77 (sys_sigreturn) and 0x0aad (sys_rt_sigreturn) are allowed. They are stored by the kernel to the signal stack frame. Unfortunately, the signal return mechanism cannot be modified to use an SA_RESTORER because the exception unwinding code depends on the system call opcode stored behind the signal stack frame. This feature requires that user space is executed in secondary-space mode and the kernel in home-space mode, which means that the addressing modes need to be switched and that the noexec protection only works for user space. After switching the addressing modes, we cannot use the mvcp/mvcs instructions anymore to copy between kernel and user space. A new mvcos instruction has been added to the z9 EC/BC hardware which allows to copy between arbitrary address spaces, but on older hardware the page tables need to be walked manually. Signed-off-by: Gerald Schaefer Signed-off-by: Martin Schwidefsky commit 86aa9fc2456d8a662f299a70bdb70987209170f0 Author: Jan Glauber Date: Mon Feb 5 21:18:14 2007 +0100 [S390] move crypto options and some cleanup. This patch moves the config options for the s390 crypto instructions to the standard "Hardware crypto devices" menu. In addition some cleanup has been done: use a flag for supported keylengths, add a warning about machien limitation, return ENOTSUPP in case the hardware has no support, remove superfluous printks and update email addresses. Signed-off-by: Jan Glauber Signed-off-by: Martin Schwidefsky commit 347d59d7e9739ff2acbaa751b6225ecb335c3f29 Author: Cornelia Huck Date: Mon Feb 5 21:17:56 2007 +0100 [S390] cio: Don't spam debug feature. Lower priority of "Blacklisted device detected" messages so we don't overwrite more useful messages. Signed-off-by: Cornelia Huck Signed-off-by: Martin Schwidefsky commit 184357a59669e2b1f9bb684c598458717207793b Author: Peter Oberparleiter Date: Mon Feb 5 21:17:42 2007 +0100 [S390] Cleanup of CHSC event handling. Change CHSC event handling to be more easily extensible. Signed-off-by: Peter Oberparleiter Signed-off-by: Martin Schwidefsky commit 0f008aa300f1a48144a1b988a85db9d330f884b7 Author: Peter Oberparleiter Date: Mon Feb 5 21:17:40 2007 +0100 [S390] cio: declare hardware structures packed. Signed-off-by: Peter Oberparleiter Signed-off-by: Martin Schwidefsky commit 9b241cc862d55038c43feee86670cb7d86cf01c1 Author: Heiko Carstens Date: Mon Feb 5 21:17:38 2007 +0100 [S390] Add set_fs(USER_DS) to start_thread(). Currently works anyway since search_binary_handler has a set_fs(USER_DS). But start_thread() is the place where this should be done. Following all other architectures... Signed-off-by: Heiko Carstens Signed-off-by: Martin Schwidefsky commit 758976f9a55cb22ddc602a0690d67f9546e3e43f Author: Cornelia Huck Date: Mon Feb 5 21:17:36 2007 +0100 [S390] cio: Catch operand exceptions on stsch. If we have a subchannel id which has been generated via for_each_subchannel(), it might contain an invalid subchannel set id. We need to catch the ensuing operand exception by using stsch_err() instead of stsch() in all possible cases. Signed-off-by: Cornelia Huck Signed-off-by: Martin Schwidefsky commit d8c351a97e492dcf24021a0875bf138bfa1374f9 Author: Heiko Carstens Date: Mon Feb 5 21:17:34 2007 +0100 [S390] Fix register usage description. Fix description of register usage as pointed out by Andreas Krebbel. Since this document is completely outdated and would need a lot of fixing, it might be worth considering to get rid of it... Signed-off-by: Heiko Carstens Signed-off-by: Martin Schwidefsky commit d42335a33b2ca2406d57bb8f0cf00adbdda8cede Author: Heiko Carstens Date: Mon Feb 5 21:17:32 2007 +0100 [S390] kretprobe_trampoline_holder() in wrong section. kretprobe_trampoline_holder() is in kprobes section but used to register a kprobe in arch_init_kprobes(). Hence register_kprobe() and therefore arch_init_kprobes() will fail. Signed-off-by: Heiko Carstens Signed-off-by: Martin Schwidefsky commit 35df8d53f5c951ac0cd79f1084e6787ca5980207 Author: Heiko Carstens Date: Mon Feb 5 21:17:29 2007 +0100 [S390] Fix kprobes breakpoint handling. In case of an illegal op the die notifier gets called with DIE_TRAP instead of DIE_BPT first. Signed-off-by: Heiko Carstens Signed-off-by: Martin Schwidefsky commit d58140cc18b3d69e86dead47aab5c838c08dc37e Author: Martin Schwidefsky Date: Mon Feb 5 21:17:27 2007 +0100 [S390] Update maintainers file. Use the new linux-s390@vger.kernel.org mailing list instead of linux-390@vm.marist.edu. Signed-off-by: Martin Schwidefsky commit 336c340b682daa283acf9202a07c4fd5c28e53a5 Author: Horst Hummel Date: Mon Feb 5 21:17:24 2007 +0100 [S390] dasd: fix unconditional reserve handling. The reserve/release IOCTLs sometimes do not work. If second system does a 'steal lock' the pending unit check (Format 3 Msg F) is delivered. Since ERP is disabled for reserve/release, the IOCTL call fails. We have to allow basic ERP (retries) for reserve/release IOCTLs. Signed-off-by: Horst Hummel Signed-off-by: Martin Schwidefsky commit db2738197b52f02f4c599c1ae3f66ae1894406cd Author: Horst Hummel Date: Mon Feb 5 21:17:22 2007 +0100 [S390] Remove dasd_ccw_log function. Logging of relevant information is already done by disciplines dump_sense function. Signed-off-by: Horst Hummel Signed-off-by: Martin Schwidefsky commit c48e09131bd7c632c80a3245688d2d29dbc4f6b5 Author: Heiko Carstens Date: Mon Feb 5 21:17:20 2007 +0100 [S390] Small barrier() and cpu_relax() cleanup. cpu_relax() has barrier() semantics hence there is no need to use both of them in conjunction in sclp_sync_wait(). Also change cpu_relax() so it's more obvious that it has barrier semantics. Signed-off-by: Heiko Carstens Signed-off-by: Martin Schwidefsky commit 1125b4640fea29aafe9bf24672e2da9672f6592e Author: Cornelia Huck Date: Mon Feb 5 21:17:18 2007 +0100 [S390] cio: Use device_{create,remove}_bin_file. Create/remove the channel measurement binary files with device_{create,remove}_bin_file instead of sysfs_{create,remove}_bin_file. Signed-off-by: Cornelia Huck Signed-off-by: Martin Schwidefsky commit c59d744bd8a0e283daf6726881e4c9aa4bd25261 Author: Heiko Carstens Date: Mon Feb 5 21:17:16 2007 +0100 [S390] sclp: don't call local_bh_disable/_local_bh_enable if in_interrupt() local_bh_disable/_local_bh_enable must not be called if in_irq() is true. Besides that if in_interrupt() is true bottom halves are disabled anyway. Signed-off-by: Heiko Carstens Signed-off-by: Martin Schwidefsky commit 444f0e5489e7ac4bca5c4748d7d846c352a5cd03 Author: Gerald Schaefer Date: Mon Feb 5 21:17:11 2007 +0100 [S390] Show loaded DCSS segments under /proc/iomem. Currently loaded DCSS segments are now listed in /proc/iomem with their name followed by a trailing "(DCSS)". Signed-off-by: Gerald Schaefer Signed-off-by: Martin Schwidefsky commit 18374d376c7eb30b6359759e767cd99397b377d2 Author: Cornelia Huck Date: Mon Feb 5 21:17:09 2007 +0100 [S390] cio: Restart path verification after unsolicited interrupt. If we try to start path verification when an unsolicited interrupt is already pending, stctl shows status pending and we delay path verification again. We need to check for the doverify bit when the unsolicited interrupt comes in and then do path verification. Signed-off-by: Cornelia Huck Signed-off-by: Martin Schwidefsky commit b075083f35309c4f3e50886d6f31a3a0e07a29b5 Author: Heiko Carstens Date: Mon Feb 5 21:17:07 2007 +0100 [S390] Fix FCP dump feature detection. FCP dump feature detection works only if the sclp command in head.S was succesful. Since the sclp command is skipped if diag260 works, we don't have any dump feature detection anymore. Bug was introduced with d57de5a36791cb1b7285649c62f183b0d3505f7d. Signed-off-by: Heiko Carstens Signed-off-by: Martin Schwidefsky commit e3c699b38ef3c59521fdd1732efcaaa789d81440 Author: Stefan Weinhuber Date: Mon Feb 5 21:17:04 2007 +0100 [S390] dasd: fix bug in dasd initialization cleanup The initialization of the dasd_eer code is one of the last steps of the dasd driver initialization. When initialization fails in one of the earlier steps, the dasd_exit function is called to clean up what has been done so far. So the dasd_eer_exit function may be called, although the dasd_eer_init function wasn't called before and dasd_eer_exit tries to unregister a misc device that wasn't registered, which results in a BUG. Make sure that dasd_eer_exit can be called without initialization. Use a dynamically allocated struct miscdevice instead of a static one, so we only try to unregister the device if it exists and was actually registered. Signed-off-by: Stefan Weinhuber Signed-off-by: Martin Schwidefsky commit dbd8ae63065189b12c46bdc58799dc353e4b3a53 Author: Peter Oberparleiter Date: Mon Feb 5 21:17:00 2007 +0100 [S390] sclp: invalid handling of temporary 'not operational' status Requests are aborted when the sclp interface reports 'not operational' even though they may still be active at the sclp, leading to concurrent writes to request memory by both the kernel and the sclp interface. Do not abort requests for which the sclp interface reports not operational status during request retry. Signed-off-by: Peter Oberparleiter 5A Signed-off-by: Martin Schwidefsky commit 3b0b4af2c7593af6dfe92afa1033033c4746ec11 Author: Heiko Carstens Date: Mon Feb 5 21:16:58 2007 +0100 [S390] Simplify virt_to_phys. No need to use lrag in 64 bit addressing mode since lra will do the same. Signed-off-by: Heiko Carstens Signed-off-by: Martin Schwidefsky commit 32c5b050927c515cea4083eb8f3a7177dc4279a1 Author: Cornelia Huck Date: Mon Feb 5 21:16:56 2007 +0100 [S390] cio: Remove check for ssd in chpids_show(). Since ssd_info is now available before the subchannel is registered, we don't need to check whether it is available. Signed-off-by: Cornelia Huck Signed-off-by: Martin Schwidefsky commit bda3563fb28e3a4260ac3566cf11700792a336bb Author: Christian Borntraeger Date: Mon Feb 5 21:16:54 2007 +0100 [S390] cpcmd with vmalloc addresses. Change the bounce buffer logic of cpcmd. diag8 needs _real_ memory below 2GB. Therefore vmalloced data does not work. As the data might cross a page boundary, we cannot use virt_to_page either. The solution is to use virt_to_page only in the check for a bounce buffer. There was a redundant check for response==NULL. response < 2GB contains this check as well. I also removed the rlen==0 check, since rlen=0 and response!=NULL would be a caller bug and response==NULL is already checked. Signed-off-by: Christian Borntraeger Signed-off-by: Martin Schwidefsky commit 60383201c2c155fae2aaffd483d09eb4198b6356 Author: Heiko Carstens Date: Mon Feb 5 21:16:52 2007 +0100 [S390] Remove pointless/unreliable kernel messages. Signed-off-by: Heiko Carstens Signed-off-by: Martin Schwidefsky commit b0f1779a878cf15b07181ef31394ecd33b40c470 Author: Akinobu Mita Date: Mon Feb 5 21:16:49 2007 +0100 [S390] Check the return value of kthread_run(). Signed-off-by: Akinobu Mita Signed-off-by: Martin Schwidefsky commit 2b67fc46061b2171fb8fbb55d1ac717abd533569 Author: Heiko Carstens Date: Mon Feb 5 21:16:47 2007 +0100 [S390] Get rid of a lot of sparse warnings. Signed-off-by: Heiko Carstens Signed-off-by: Martin Schwidefsky commit 55dff5224abeb734b12c1661c34ccf534955bee7 Author: Heiko Carstens Date: Mon Feb 5 21:16:44 2007 +0100 [S390] Move init_irq_proc to the other irq related functions. Signed-off-by: Heiko Carstens Signed-off-by: Martin Schwidefsky commit 9473252f20e8482464415d9030b3957b5593796d Author: Horms Date: Mon Feb 5 10:17:38 2007 +0900 [IA64] add newline to PAL-code warning message Signed-off-by: Simon Horman Signed-off-by: Tony Luck commit abac08dbb4739f417f570e5bdf03af36150b28c3 Author: Horms Date: Mon Feb 5 10:16:20 2007 +0900 [IA64] kexec: Remove inline declaration of efi_get_pal_addr() Remove the Remove inline declaration of efi_get_pal_addr() as it is declared in linux/efi.h. Signed-Off-By: Simon Horman Signed-off-by: Tony Luck commit 8a697d0a4c8e7ed51cf71a467ad59c25bfb85b44 Author: Horms Date: Mon Feb 5 10:17:22 2007 +0900 [IA64] kexec: Minor enhancement to includes in crash.c linux/uaccess.h was being included, but it seems that really the following includes are needed. asm/page.h: for __va() and PAGE_SHIFT asm/uaccess.h: for copy_to_user() I guess that linux/uaccess.h pulls in both asm/page.h and asm/uaccess.h. I notices this while backporting the code to xen's linux-2.6.16.33, which does not have linux/uaccess.h. I'm posting it as I think it is a correct, though somewhat cosmetic fix. Signed-off-by: Simon Horman Signed-off-by: Tony Luck commit 233c2f99d6605343fa4a4c68560a4f74882b2693 Author: Horms Date: Mon Feb 5 11:05:29 2007 +0900 [IA64] kexec: typo in the saved_max_pfn description in contig.c Fix a typo in the saved_max_pfn description in contig.c Signed-off-by: Simon Horman Signed-off-by: Tony Luck commit 475c63bded322545d1e9ccc5930c8903d2c97c4c Author: Horms Date: Mon Feb 5 10:59:03 2007 +0900 [IA64] Zero size /proc/vmcore on ia64 Set saved_max_pfn when discontig memory is in use. This sets up saved_max_pfn when disctontig memory is in use. This mirrors the code for contig memory. This patch does not entirely solve the problem of making vmcore work, however it does appear to be neccessary. Please consider applying. Signed-off-by: Simon Horman Signed-off-by: Tony Luck commit bcb9b99d1fb6a1cbe592f131dc95450d2f18c91f Author: Magnus Damm Date: Mon Feb 5 15:43:42 2007 +0900 [IA64] kexec: Fix CONFIG_SMP=n compilation Kexec support for 2.6.20 on ia64 does not build properly using a config made up by CONFIG_SMP=n and CONFIG_HOTPLUG_CPU=n: Signed-off-by: Magnus Damm Acked-by: Simon Horman Acked-by: Jay Lan Signed-off-by: Tony Luck commit a34fbc6363256387372331000462691bc4b3f5a9 Author: Patrick Caulfield Date: Thu Feb 1 16:46:33 2007 +0000 [DLM] fix softlockup in dlm_recv This patch stops the dlm_recv workqueue from busy-waiting when a node disconnects. This can cause soft lockup errors on debug systems and bad performance generally. Signed-Off-By: Patrick Caulfield Signed-off-by: Steven Whitehouse commit 62a0f62369b0fece37f6652d69b918c89d53c3b3 Author: David Teigland Date: Wed Jan 31 13:25:00 2007 -0600 [DLM] zero new user lvbs A new lvb for a userland lock wasn't being initialized to zero. Signed-off-by: David Teigland Signed-off-by: Steven Whitehouse commit 9beeb9f3c5b0401491f59b71521ab2678f584b09 Author: Randy Dunlap Date: Tue Jan 30 14:30:08 2007 -0800 [DLM/GFS2] indent help text Indent help text as expected. Signed-off-by: Randy Dunlap Signed-off-by: Steven Whitehouse commit ddee76089cc9bcbd8ae9ec6c26e726a8ab2fe675 Author: Russell Cattelan Date: Mon Jan 29 17:13:44 2007 -0600 [GFS2] Fix unlink deadlocks Move the glock acquisition to outside of the transactions. Lock odering must be preserved in order to prevent ABBA deadlocks. The current gfs2_change_nlink code would tries to grab the glock after having started a transaction and thus is holding the log lock. This is inconsistent with other code paths in gfs that grab the resource group glock prior to staring a tranactions. One problem with this fix is that the resource group lock is always grabbed now even if the inode still has ref count and can not be marked for unlink. Signed-off-by: Russell Cattelan Signed-off-by: Steven Whitehouse commit 61be084efcc4451934257350281962595418a33c Author: Steven Whitehouse Date: Mon Jan 29 11:51:45 2007 +0000 [GFS2] Put back semaphore to avoid umount problem Dave Teigland fixed this bug a while back, but I managed to mistakenly remove the semaphore during later development. It is required to avoid the list of inodes changing during an invalidate_inodes call. I have made it an rwsem since the read side will be taken frequently during normal filesystem operation. The write site will only happen during umount of the file system. Also the bug only triggers when using the DLM lock manager and only then under certain conditions as its timing related. Signed-off-by: Steven Whitehouse Cc: David Teigland commit bbb28ab7599789740b2233a0805d22aefb97f533 Author: Eric Sandeen Date: Mon Jan 29 11:11:51 2007 -0600 [GFS2] more CURRENT_TIME_SEC Whoops, quilt user error, missed this one in the previous patch. Signed-off-by: Eric Sandeen Signed-off-by: Steven Whitehouse commit 001172778543c6997d3339f43085e43460e5883a Author: Adrian Bunk Date: Sun Jan 28 17:19:50 2007 +0100 [GFS2/DLM] fix GFS2 circular dependency On Sun, Jan 28, 2007 at 11:08:18AM +0100, Jiri Slaby wrote: > Andrew Morton napsal(a): > >Temporarily at > > > > http://userweb.kernel.org/~akpm/2.6.20-rc6-mm1/ > > Unable to select IPV6. Menuconfig doesn't offer it when INET is selected. > When it's not it appears in the menu, but after state change it gets away. > The same behaviour in xconfig, gconfig. > > $ mkdir ../a/tst > $ make O=../a/tst menuconfig > HOSTCC scripts/basic/fixdep > [...] > HOSTLD scripts/kconfig/mconf > scripts/kconfig/mconf arch/i386/Kconfig > Warning! Found recursive dependency: INET GFS2_FS_LOCKING_DLM SYSFS > OCFS2_FS INET > > Maybe this is the problem? Yes, patch below. > regards, cu Adrian <-- snip --> This patch fixes a circular dependency by letting GFS2_FS_LOCKING_DLM and DLM depend on instead of select SYSFS. Since SYSFS depends on EMBEDDED this change shouldn't cause any problems for users. Signed-off-by: Adrian Bunk Acked-by: Randy Dunlap Signed-off-by: Steven Whitehouse commit 67f55897ee5ffa16ca00ed39d176dc52b5066679 Author: Randy Dunlap Date: Thu Jan 25 18:42:39 2007 -0800 [GFS2/DLM] use sysfs With CONFIG_DLM=m, CONFIG_PROC_FS=n, and CONFIG_SYSFS=n, kernel build fails with: WARNING: "kernel_subsys" [fs/gfs2/locking/dlm/lock_dlm.ko] undefined! WARNING: "kernel_subsys" [fs/dlm/dlm.ko] undefined! WARNING: "kernel_subsys" [fs/configfs/configfs.ko] undefined! make[1]: *** [__modpost] Error 1 make: *** [modules] Error 2 Since fs/dlm/lockspace.c and fs/gfs2/locking/dlm/sysfs.c use kernel_subsys, they should either DEPEND on it or SELECT it. Signed-off-by: Randy Dunlap Signed-off-by: Steven Whitehouse commit ee32e4f3d347e4b562de0bd70be99e622d7d1a9f Author: David Teigland Date: Thu Jan 25 14:24:04 2007 -0600 [GFS2] make lock_dlm drop_count tunable in sysfs We want to be able to change or disable the default drop_count (number at which the dlm asks gfs to limit the the number of locks it's holding). Add it to the collection of sysfs tunables for an fs. Signed-off-by: David Teigland Signed-off-by: Steven Whitehouse commit 2f708649baad6350f506e7f5ca6649e32a8e4b49 Author: David Teigland Date: Thu Jan 25 13:50:52 2007 -0600 [GFS2] increase default lock limit Increase the number of locks at which point the dlm begins asking gfs to reduce its lock usage. The default value is largely arbitrary, but the current value of 50,000 ends up limiting performance unnecessarily for too many users. Signed-off-by: David Teigland Signed-off-by: Steven Whitehouse commit 8bd9572769767c6fd164cff4e1202df12cb34b4a Author: Steven Whitehouse Date: Thu Jan 25 10:04:20 2007 +0000 [GFS2] Fix list corruption in lops.c The patch below appears to fix the list corruption that we are seeing on occasion. Although the transaction structure is private to a single thread, when the queued structures are dismantled during an in-core commit, its possible for a different thread to be trying to add the same structure to another, new, transaction at the same time. To avoid this, this patch takes the log spinlock during this operation. Signed-off-by: Steven Whitehouse commit d7c103d0bd29c94f78155a4538faf314e49d9713 Author: Steven Whitehouse Date: Thu Jan 25 17:14:59 2007 +0000 [GFS2] Fix recursive locking attempt with NFS In certain cases, its possible for NFS to call the lookup code while holding the glock (when doing a readdirplus operation) so we need to check for that and not try and lock the glock twice. This also fixes a typo in a previous NFS related GFS2 patch. Signed-off-by: Steven Whitehouse commit b790c3b7c38aae28c497bb363a6fe72f7c96568f Author: David Teigland Date: Wed Jan 24 10:21:33 2007 -0600 [DLM] can miss clearing resend flag A long, complicated sequence of events, beginning with the RESEND flag not being cleared on an lkb, can result in an unlock never completing. - lkb on waiters list for remote lookup - the remote node is both the dir node and the master node, so it optimizes the lookup into a request and sends a request reply back - the request reply is saved on the requestqueue to be processed after recovery - recovery runs dlm_recover_waiters_pre() which sets RESEND flag so the lookup will be resent after recovery - end of recovery: process_requestqueue takes saved request reply which removes the lkb off the waitesr list, _without_ clearing the RESEND flag - end of recovery: dlm_recover_waiters_post() doesn't do anything with the now completed lookup lkb (would usually clear RESEND) - later, the node unmounts, unlocks this lkb that still has RESEND flag set - the lkb is on the waiters list again, now for unlock, when recovery occurs, dlm_recover_waiters_pre() shows the lkb for unlock with RESEND set, doesn't do anything since the master still exists - end of recovery: dlm_recover_waiters_post() takes this lkb off the waiters list because it has the RESEND flag set, then reports an error because unlocks are never supposed to be handled in recover_waiters_post(). - later, the unlock reply is received, doesn't find the lkb on the waiters list because recover_waiters_post() has wrongly removed it. - the unlock operation has been lost, and we're left with a stray granted lock - unmount spins waiting for the unlock to complete The visible evidence of this problem will be a node where gfs umount is spinning, the dlm waiters list will be empty, and the dlm locks list will show a granted lock. The fix is simply to clear the RESEND flag when taking an lkb off the waiters list. Signed-off-by: David Teigland Signed-off-by: Steven Whitehouse commit 8fd3a98f2c22982aff4d29e4ee72959d3032c123 Author: David Teigland Date: Wed Jan 24 10:11:45 2007 -0600 [DLM] saved dlm message can be dropped dlm_receive_message() returns 0 instead of returning 'error'. What would happen is that process_requestqueue would take a saved message off the requestqueue and call receive_message on it. receive_message would then see that recovery had been aborted, set error to EINTR, and 'goto out', expecting that the error would be returned. Instead, 0 was always returned, so process_requestqueue would think that the message had been processed and delete it instead of saving it to process next time. This means the message (usually an unlock in my tests) would be lost. Signed-off-by: David Teigland Signed-off-by: Steven Whitehouse commit f1f1c1ccf7848a6e25db30ee9216e1a1e7eb6bef Author: Patrick Caulfield Date: Wed Jan 24 11:17:59 2007 +0000 [DLM] Make sock_sem into a mutex Now that there can be multiple dlm_recv threads running we need to prevent two recvs running for the same connection - it's unlikely but it can happen and it causes message corruption. Signed-Off-By: Patrick Caulfield Signed-off-by: Steven Whitehouse commit d043e1900c97f7282b71844c8530279913b6ec5a Author: Steven Whitehouse Date: Tue Jan 23 16:56:36 2007 -0500 [GFS2] Fix typo in glock.c This is a one letter typo fix in glock.c, spotted by Rob Kenna. Signed-off-by: Steven Whitehouse commit ddfe0627838ca0c0e8babb0dd2bd7f4b35e25bff Author: Eric Sandeen Date: Thu Jan 18 16:41:23 2007 -0600 [GFS2] use CURRENT_TIME_SEC instead of get_seconds in gfs2 I was looking something else up and came across this... I don't honestly have a good reason to change it other than to make it like every other Linux filesystem in this regard. ;-) It doesn't functionally change anything, but makes some lines shorter. :) I'm also curious; why does gfs2 have 64-bits of on-disk timestamps, but not in timespec_t format, and only stores second resolutions? Seems like you're halfway to sub-second resolutions already. I suppose if that gets implemented then all of the below should instead be CURRENT_TIME not CURRENT_TIME_SEC. Signed-off-by: Eric Sandeen Signed-off-by: Steven Whitehouse commit 90101c31867b7acc44286b425d50e1042aa55b8d Author: Steven Whitehouse Date: Tue Jan 23 13:20:41 2007 -0500 [GFS2] Compile fix for glock.c This one liner got missed from the previous patch. Signed-off-by: Steven Whitehouse commit 12132933c4fdeb458195a9388287d550c8476edf Author: Steven Whitehouse Date: Mon Jan 22 13:09:04 2007 -0500 [GFS2] Remove queue_empty() function This function is not longer required since we do not do recursive locking in the glock layer. As a result all its callers can be replaceed with list_empty() calls. Signed-off-by: Steven Whitehouse commit bd44e2b007bc9024bce3357c185b38c73f87c3dd Author: Patrick Caulfield Date: Mon Jan 22 14:51:33 2007 +0000 [DLM] fix lowcomms receiving This patch fixes a bug whereby data on a newly accepted connection would be ignored if it arrived soon after the accept. Signed-Off-By: Patrick Caulfield Signed-off-by: Steven Whitehouse commit b5d32bead1578afc5ca817d40c320764d50a8600 Author: Steven Whitehouse Date: Mon Jan 22 12:15:34 2007 -0500 [GFS2] Tidy up glops calls This patch doesn't make any changes to the ordering of the various operations related to glocking, but it does tidy up the calls to the glops.c functions to make the structure more obvious. The two functions: gfs2_glock_xmote_th() and gfs2_glock_drop_th() can be made static within glock.c since they are called by every set of glock operations. The xmote_th and drop_th glock operations are then made conditional upon those two routines existing and called from the previously mentioned functions in glock.c respectively. Also it can be seen that the go_sync operation isn't needed since it can easily be replaced by calls to xmote_bh and drop_bh respectively. This results in no longer (confusingly) calling back into routines in glock.c from glops.c and also reducing the glock operations by one member. Signed-off-by: Steven Whitehouse commit f2f5095f9e63db57faa7cb082e958910ecdd7ad4 Author: Patrick Caulfield Date: Mon Jan 22 14:50:10 2007 +0000 [DLM] lowcomms tidy This patch removes some redundant fields from the connection structure and adds some lockdep annotation to remove spurious warnings. Signed-Off-By: Patrick Caulfield Signed-off-by: Steven Whitehouse commit 1c0f4872dc4bbeb2223a300517099786211fce83 Author: Steven Whitehouse Date: Mon Jan 22 12:10:39 2007 -0500 [GFS2] Remove local exclusive glock mode Here is a patch for GFS2 to remove the local exclusive flag. In the places it was used, mutex's are always held earlier in the call path, so it appears redundant in the LM_ST_SHARED case. Also, the GFS2 holders were setting local exclusive in any case where the requested lock was LM_ST_EXCLUSIVE. So the other places in the glock code where the flag was tested have been replaced with tests for the lock state being LM_ST_EXCLUSIVE in order to ensure the logic is the same as before (i.e. LM_ST_EXCLUSIVE is always locally exclusive as well as globally exclusive). Signed-off-by: Steven Whitehouse commit 6bd9c8c2fb99d1f5af6201db2f063c1d754c230a Author: Steven Whitehouse Date: Fri Jan 19 13:57:36 2007 -0500 [GFS2] Remove unused go_callback operation This is never used, so we might as well remove it. Signed-off-by: Steven Whitehouse commit e5dab552c82ce416d7be867b1e5a0fa585dcf590 Author: Steven Whitehouse Date: Thu Jan 18 17:44:20 2007 +0000 [GFS2] Remove the "greedy" function from glock.[ch] The "greedy" code was an attempt to retain glocks for a minimum length of time when they relate to mmap()ed files. The current implementation of this feature is not, however, ideal in that it required allocating memory in order to do this and its overly complicated. It also misses the mark by ignoring the other I/O operations which are just as likely to suffer from the same problem. So the plan is to remove this now and then add the functionality back as part of the glock state machine at a later date (and thus take into account all the possible users of this feature) Signed-off-by: Steven Whitehouse commit fee852e374fb367c5436b1226eb93b35f8355ed9 Author: Steven Whitehouse Date: Wed Jan 17 15:33:23 2007 +0000 [GFS2] Shrink gfs2_inode memory by half Here is something I spotted (while looking for something entirely different) the other day. Rather than using a completion in each and every struct gfs2_holder, this removes it in favour of hashed wait queues, thus saving a considerable amount of memory both on the stack (where a number of gfs2_holder structures are allocated) and in particular in the gfs2_inode which has 8 gfs2_holder structures embedded within it. As a result on x86_64 the gfs2_inode shrinks from 2488 bytes to 1912 bytes, a saving of 576 bytes per inode (no thats not a typo!). In actual practice we get a much better result than that since now that a gfs2_inode is under the 2048 byte barrier, we get two per 4k slab page effectively halving the amount of memory required to store gfs2_inodes. Signed-off-by: Steven Whitehouse commit 330005c2b23e71e54931913e9b63d1712a19e444 Author: Steven Whitehouse Date: Mon Jan 15 16:36:26 2007 -0500 [GFS2] Remove max_atomic_write tunable This removes an unused sysfs tunable parameter. Signed-off-by: Steven Whitehouse commit 3699e3a44bf56e0cd58c97e8655f375ad9b65d9d Author: Steven Whitehouse Date: Wed Jan 17 15:09:20 2007 +0000 [GFS2] Clean up/speed up readdir This removes the extra filldir callback which gfs2 was using to enclose an attempt at readahead for inodes during readdir. The code was too complicated and also hurts performance badly in the case that the getdents64/readdir call isn't being followed by stat() and it wasn't even getting it right all the time when it was. As a result, on my test box an "ls" of a directory containing 250000 files fell from about 7mins (freshly mounted, so nothing cached) to between about 15 to 25 seconds. When the directory content was cached, the time taken fell from about 3mins to about 4 or 5 seconds. Interestingly in the cached case, running "ls -l" once reduced the time taken for subsequent runs of "ls" to about 6 secs even without this patch. Now it turns out that there was a special case of glocks being used for prefetching the metadata, but because of the timeouts for these locks (set to 10 secs) the metadata was being timed out before it was being used and this the prefetch code was constantly trying to prefetch the same data over and over. Calling "ls -l" meant that the inodes were brought into memory and once the inodes are cached, the glocks are not disposed of until the inodes are pushed out of the cache, thus extending the lifetime of the glocks, and thus bringing down the time for subsequent runs of "ls" considerably. Signed-off-by: Steven Whitehouse commit a8d638e30e768adc6956541f79f7bf05139ba475 Author: Steven Whitehouse Date: Mon Jan 15 13:52:17 2007 +0000 [GFS2] Add writepages for "data=writeback" mounts It occurred to me that although a gfs2 specific writepages for ordered writes and journaled data would be tricky, by hooking writepages only for "data=writeback" mounts we could take advantage of not needing buffer heads (we don't use them on the read side, nor have we for some time) and create much larger I/Os for the block layer. Using blktrace both before and after, its possible to see that for large I/Os, most of the requests generated through writepages are now 1024 sectors after this patch is applied as opposed to 8 sectors before. Signed-off-by: Steven Whitehouse commit 222d396092acc11b4af03bede309aa066945e920 Author: David Teigland Date: Mon Jan 15 10:28:22 2007 -0600 [DLM] fix master recovery If master recovery happens on an rsb in one recovery sequence, then that sequence is aborted before lock recovery happens, then in the next sequence, we rely on the previous master recovery (which may now be invalid due to another node ignoring a lookup result) and go on do to the lock recovery where we get stuck due to an invalid master value. recovery cycle begins: master of rsb X has left nodes A and B send node C an rcom lookup for X to find the new master C gets lookup from B first, sets B as new master, and sends reply back to B C gets lookup from A next, and sends reply back to A saying B is master A gets lookup reply from C and sets B as the new master in the rsb recovery cycle on A, B and C is aborted to start a new recovery B gets lookup reply from C and ignores it since there's a new recovery recovery cycle begins: some other node has joined B doesn't think it's the master of X so it doesn't rebuild it in the directory C looks up the master of X, no one is master, so it becomes new master B looks up the master of X, finds it's C A believes that B is the master of X, so it sends its lock to B B sends an error back to A A resends this repeats forever, the incorrect master value on A is never corrected The fix is to do master recovery on an rsb that still has the NEW_MASTER flag set from an earlier recovery sequence, and therefore didn't complete lock recovery. Signed-off-by: David Teigland Signed-off-by: Steven Whitehouse commit a1bc86e6bddd34362ca08a3a4d898eb4b5c15215 Author: David Teigland Date: Mon Jan 15 10:34:52 2007 -0600 [DLM] fix user unlocking When a user process exits, we clear all the locks it holds. There is a problem, though, with locks that the process had begun unlocking before it exited. We couldn't find the lkb's that were in the process of being unlocked remotely, to flag that they are DEAD. To solve this, we move lkb's being unlocked onto a new list in the per-process structure that tracks what locks the process is holding. We can then go through this list to flag the necessary lkb's when clearing locks for a process when it exits. Signed-off-by: David Teigland Signed-off-by: Steven Whitehouse commit 1d6e8131cf0064ef5ab5f3411a82b800afbfadee Author: Patrick Caulfield Date: Mon Jan 15 14:33:34 2007 +0000 [DLM] Use workqueues for dlm lowcomms This patch converts the DLM TCP lowcomms to use workqueues rather than using its own daemon functions. Simultaneously removing a lot of code and making it more scalable on multi-processor machines. Signed-Off-By: Patrick Caulfield Signed-off-by: Steven Whitehouse commit 03dc6a538e42bcc8d5dfabcee208b639db85a80c Author: Adrian Bunk Date: Sat Jan 13 10:56:41 2007 +0100 [GFS2] make gfs2_change_nlink_i() static On Thu, Jan 11, 2007 at 10:26:27PM -0800, Andrew Morton wrote: >... > Changes since 2.6.20-rc3-mm1: >... > git-gfs2-nmw.patch >... > git trees >... This patch makes the needlessly globlal gfs2_change_nlink_i() static. Signed-off-by: Adrian Bunk Signed-off-by: Steven Whitehouse commit 70831465646b1fef9bf7b51b64409276411e9746 Author: Robert Peterson Date: Thu Jan 11 13:25:00 2007 -0600 [GFS2] gfs2 knows of directories which it chooses not to display This is for Red Hat bugzilla bug bz #222302: Moving a virtual IP from node to node between two NFS-over-GFS2 servers was causing one of the GFS2 servers to become confused and reference a deleted inode. The problem was due to vfs dentries that did not reference the gfs2_dops and therefore didn't call the gfs2 revalidate code to revalidate a dentry after a directory had been deleted & recreated. This patch is a crosswrite from a RHEL4 bug found in GFS1 as bz #190756 and it is against the latest -nmw git tree. Signed-off-by: Robert Peterson Signed-off-by: Steven Whitehouse commit d200778e1257eeb92242355de6f191a0a5ad43c4 Author: David Teigland Date: Tue Jan 9 09:46:02 2007 -0600 [DLM] expose dlm_config_info fields in configfs Make the dlm_config_info values readable and writeable via configfs entries. Signed-off-by: David Teigland Signed-off-by: Steven Whitehouse commit 99fc64874aad1ee0aea5c4d8c07e3529f9d03497 Author: David Teigland Date: Tue Jan 9 09:44:01 2007 -0600 [DLM] add config entry to enable log_debug Add a new dlm_config_info field to enable log_debug output and change log_debug() to use it. Signed-off-by: David Teigland Signed-off-by: Steven Whitehouse commit 68c817a1c4e21b893672ac73d8a498e6647453aa Author: David Teigland Date: Tue Jan 9 09:41:48 2007 -0600 [DLM] rename dlm_config_info fields Add a "ci_" prefix to the fields in the dlm_config_info struct so that we can use macros to add configfs functions to access them (in a later patch). No functional changes in this patch, just naming changes. Signed-off-by: David Teigland Signed-off-by: Steven Whitehouse commit 8ec6886748443bec53ce9b9bf50cec92bc417a1b Author: David Teigland Date: Tue Jan 9 09:38:39 2007 -0600 [DLM] change some log_error to log_debug Some common, non-error messages should use log_debug instead of log_error so they can be turned off. Signed-off-by: David Teigland Signed-off-by: Steven Whitehouse commit 87d21e07f3880b8d489f0b4a639deb1362101838 Author: S. Wendy Cheng Date: Thu Jan 18 16:07:03 2007 -0500 [GFS2] Fix gfs2_rename deadlock Second round of gfs2_rename lock re-ordering to allow Anaconda adding root partition on top of gfs2. Previous to this patch the recursive lock detector in glock.c can be triggered due to attempting to lock the rgrp twice. This fixes it by checking to see whether the rgrp is already locked. This fixes Red Hat bugzilla #221237 Signed-off-by: S. Wendy Cheng Signed-off-by: Steven Whitehouse commit 6c93fd1e578669364e026a0d44c669b871e2a8c4 Author: Russell Cattelan Date: Mon Jan 8 17:47:51 2007 -0600 [GFS2] BZ 217008 fsfuzzer fix. Update the quilt header comments to match the code changes. Change gfs2_lookup_simple to return an error in the case of a NULL inode. The callers of gfs2_lookup_simple do not check for NULL in the no entry case and such would end up dereferencing a NULL ptr. This fixes: http://projects.info-pull.com/mokb/MOKB-15-11-2006.html Signed-off-by: Russell Cattelan Signed-off-by: Steven Whitehouse commit 49686f71060e342bce6644a5c69fbc6ad0e75a13 Author: Steven Whitehouse Date: Mon Jan 8 14:31:40 2007 +0000 [GFS2] Fix ordering of page disposal vs. glock_dq In case of unlinked files with dirty pages GFS2 wasn't clearing the pages in quite the right order. This patch clears the pages earlier (before the qlock_dq) to avoid the situation that the release of the glock results in attempting to write back data that has already been deallocated. This fixes Red Hat bugzilla: #220117 Signed-off-by: Steven Whitehouse commit 4edde74eedb8bc4c03adc3602b114b72a7ccd13f Author: Patrick Caulfield Date: Tue Jan 2 17:08:54 2007 +0000 [DLM] Fix spin lock already unlocked bug I just noticed this message when testing some other changes I'd made to lowcomms (to use workqueues) but the problem seems to be in the current git trees too. I'm amazed no-one has seen it. BUG: spinlock already unlocked on CPU#1, dlm_recoverd/16868 Signed-Off-By: Patrick Caulfield Signed-off-by: Steven Whitehouse commit 3fb4a251febe70e4c65ea8250545b391fd414d5a Author: Patrick Caulfield Date: Tue Jan 2 17:01:05 2007 +0000 [DLM] Fix schedule() calls I was a little over-enthusiastic turning schedule() calls int cond_sched() when fixing the DLM for Andrew Morton. These four should really be calls to schedule() or the dlm can busy-wait. Signed-Off-By: Patrick Caulfield Signed-off-by: Steven Whitehouse commit 5509826f1e548d14bb888c1cb6e3bbf23f855770 Author: S. Wendy Cheng Date: Thu Jan 18 15:56:34 2007 -0500 [GFS2] Fix change nlink deadlock Bugzilla 215088 Fix deadlock in gfs2_change_nlink() while installing RHEL5 into GFS2 partition. The gfs2_rename() apparently needs block allocation for the new name (into the directory) where it requires rg locks. At the same time, while updating the nlink count for the replaced file, gfs2_change_nlink() tries to return the inode meta-data back to resource group where it needs rg locks too. Our logic doesn't allow process to acquire these locks recursively by the same process (RHEL installer) that results a BUG call. This only happens within rename code path and only if the destination file exists before the rename operation. Signed-off-by: S. Wendy Cheng Signed-off-by: Steven Whitehouse commit e1d5b18ae92d0bbfe66dc2b4bab65006d32c5f7d Author: Steven Whitehouse Date: Fri Dec 15 16:49:51 2006 -0500 [GFS2] Fail over to readpage for stuffed files This is partially derrived from a patch written by Russell Cattelan. It fixes a bug where there is a race between readpages and truncate by ignoring readpages for stuffed files. This is ok because a stuffed file will never be more than one block (minus sizeof(struct gfs2_dinode)) in size and block size is always less than page size, so we do not lose anything efficiency-wise by not doing readahead for stuffed files. They will have already been "read ahead" by the action of reading the inode in, in the first place. This is the remaining part of the fix for Red Hat bugzilla #218966 which had not yet made it upstream. Signed-off-by: Steven Whitehouse Cc: Russell Cattelan commit c7b3383437ff41781964d1bf7f40ff8d7dd5bc47 Author: Steven Whitehouse Date: Thu Dec 14 18:24:26 2006 +0000 [GFS2] Fix DIO deadlock This patch fixes Red Hat bugzilla #212627 in which a deadlock occurs due to trying to take the i_mutex while holding a glock. The correct locking order is defined as i_mutex -> glock in all cases. I've left dealing with allocating writes. I know that we need to do that, but for now this should do the trick. We don't need to take the i_mutex on write, because the VFS has already taken it for us. On read we don't need it since the glock is enough protection. The reason that I've made some of the checks into a separate function is that we'll need to do the checks again in the allocating write case eventually, so this is partly in preparation for this. Likewise the return value test of != 1 might look a bit odd and thats because we'll need a third return value in case of requiring an allocation. I've made the change to deferred mode on the glock to ensure flushing read caches on other nodes. I notice that (using blktrace to look at whats going on) we appear to do a better job of large I/Os than ext3 after this patch (in terms of not splitting up the I/Os). Signed-off-by: Steven Whitehouse Cc: Wendy Cheng commit 927255f0383342f5d49b82adb6689b9cba52a6f5 Author: Adrian Bunk Date: Tue Dec 19 13:04:03 2006 -0800 [DLM] fs/dlm/lowcomms-tcp.c: remove 2 functions Remove the following unused functions: - lowcomms_send_message() - lowcomms_max_buffer_size() Signed-off-by: Adrian Bunk Signed-off-by: Andrew Morton Signed-off-by: Patrick Caulfield Signed-off-by: Steven Whitehouse commit 075529b5e1ffa8c9864d23930b71b5306a13d9f8 Author: David Teigland Date: Wed Dec 13 10:40:26 2006 -0600 [DLM] fix lost flags in stub replies When the dlm fakes an unlock/cancel reply from a failed node using a stub message struct, it wasn't setting the flags in the stub message. So, in the process of receiving the fake message the lkb flags would be updated and cleared from the zero flags in the message. The problem observed in tests was the loss of the USER flag which caused the dlm to think a user lock was a kernel lock and subsequently fail an assertion checking the validity of the ast/callback field. Signed-off-by: David Teigland Signed-off-by: Steven Whitehouse commit 8d07fd509e9c82a59e37b8b18a2fd0e8ef8fc837 Author: David Teigland Date: Wed Dec 13 10:39:20 2006 -0600 [DLM] fix receive_request() lvb copying LVB's are not sent as part of new requests, but the code receiving the request was copying data into the lvb anyway. The space in the message where it mistakenly thought the lvb lived actually contained the resource name, so it wound up incorrectly copying this name data into the lvb. Fix is to just create the lvb, not copy junk into it. Signed-off-by: David Teigland Signed-off-by: Steven Whitehouse commit da49f36f4f64feb281d7663be99e779b2aecc607 Author: David Teigland Date: Wed Dec 13 10:38:45 2006 -0600 [DLM] fix send_args() lvb copying The send_args() function is used to copy parameters into a message for a number different message types. Only some of those types are set up beforehand (in create_message) to include space for sending lvb data. send_args was wrongly copying the lvb for all message types as long as the lock had an lvb. This means that the lvb data was being written past the end of the message into unknown space. Signed-off-by: David Teigland Signed-off-by: Steven Whitehouse commit 9e971b715dcc3cd5f4383f2815aaa7e5853d1f7b Author: David Teigland Date: Wed Dec 13 10:37:55 2006 -0600 [DLM] add version check Check if we receive a message from another lockspace member running a version of the dlm with an incompatible inter-node message protocol. Signed-off-by: David Teigland Signed-off-by: Steven Whitehouse commit 38aa8b0c59c35d10d15ebf00ceee641f9ed7acba Author: David Teigland Date: Wed Dec 13 10:37:16 2006 -0600 [DLM] fix old rcom messages A reply to a recovery message will often be received after the relevant recovery sequence has aborted and the next recovery sequence has begun. We need to ignore replies to these old messages from the previous recovery. There's already a way to do this for synchronous recovery requests using the rc_id number, but not for async. Each recovery sequence already has a locally unique sequence number associated with it. This patch adds a field to the rcom (recovery message) structure where this recovery sequence number can be placed, rc_seq. When a node sends a reply to a recovery request, it copies the rc_seq number it received into rc_seq_reply. When the first node receives the reply to its recovery message, it will check whether rc_seq_reply matches the current recovery sequence number, ls_recover_seq, and if not then it ignores the old reply. An old, inadequate approach to filtering out old replies (checking if the current stage of recovery has moved back to the start) has been removed from two spots. The protocol version number is changed to reflect the different rcom structures. Signed-off-by: David Teigland Signed-off-by: Steven Whitehouse commit dc200a8848cca8b0e99012996c66f4b379a390ed Author: David Teigland Date: Wed Dec 13 10:36:37 2006 -0600 [DLM] fix resend rcom lock There's a chance the new master of resource hasn't learned it's the new master before another node sends it a lock during recovery. The node sending the lock needs to resend if this happens. - A sends a master lookup for resource R to C - B sends a master lookup for resource R to C - C receives A's lookup, assigns A to be master of R and sends a reply back to A - C receives B's lookup and sends a reply back to B saying that A is the master - B receives lookup reply from C and sends its lock for R to A - A receives lock from B, doesn't think it's the master of R and sends an error back to B - A receives lookup reply from C and becomes master of R - B gets error back from A and resends its lock back to A (this resending is what this patch does) - A receives lock from B, it now sees it's the master of R and takes the lock Signed-off-by: David Teigland Signed-off-by: Steven Whitehouse commit c378051177dce4421428fd1691ffdf15ad57c161 Author: David Teigland Date: Wed Dec 6 11:46:33 2006 -0600 [GFS2] don't try to lockfs after shutdown If an fs has already been shut down, a lockfs callback should do nothing. An fs that's been shut down can't acquire locks or do anything with respect to the cluster. Also, remove FIXME comment in withdraw function. The missing bits of the withdraw procedure are now all done by user space. Signed-off-by: David Teigland Signed-off-by: Steven Whitehouse commit bf1e5989aa5783726c6a94931f92b34aa387ec30 Author: Thomas Hellstrom Date: Mon Feb 5 14:44:23 2007 +0100 [AGPGART] Add agp-type-to-mask-type method missing from some drivers. Signed-off-by: Dave Jones commit a417a21e10831bca695b4ba9c74f4ddf5a95ac06 Author: Soeren Sonnenburg Date: Mon Feb 5 10:06:01 2007 +0100 USB HID: handle multi-interface devices for Apple macbook pro properly Some HID devices by Apple have both keyboard and mouse interfaces; the keyboard interface is handled by usbhid, but the mouse (really touchpad) interface must be handled by the separate 'appletouch' driver. Using HID_QUIRK_IGNORE will make hiddev ignore both interfaces, therefore a new quirk flag to ignore only the mouse interface is required. Signed-off-by: Soeren Sonnenburg Signed-off-by: Sergey Vlasov Signed-off-by: Jiri Kosina commit dd64c151b978dc78ed535433d930c75b5c15deeb Author: Jiri Kosina Date: Tue Jan 30 16:02:24 2007 +0100 HID: move away from DEBUG defines in favor of CONFIG_HID_DEBUG CONFIG_INPUT_DEBUG is non-existent option, so remove anything depending on it. Also, as we have new CONFIG_HID_DEBUG, this should be used on places where ifdef DEBUG was used before. Suggested by Adrian Bunk. Signed-off-by: Jiri Kosina commit 43c7bf0472ec1f813fccc6012654399345898491 Author: Jiri Kosina Date: Fri Jan 26 12:58:24 2007 +0100 USB HID: fix bogus comment in hid_get_class_descriptor() The comment in hid_get_class_descriptor() says a very obvious thing and is also violating codingstyle. Just remove it. Signed-off-by: Jiri Kosina commit 8235ca3c05076f35d22578e8f530fd374104332a Author: Jiri Kosina Date: Fri Jan 26 12:56:16 2007 +0100 USB HID: remove hid_find_field_by_usage() The unused hid_find_field_by_usage() function has been commented out for a pretty long time. Remove it completely. Signed-off-by: Jiri Kosina commit 7c379146005d277982acde02da44c773de5e7e5a Author: Jiri Kosina Date: Wed Jan 24 11:54:19 2007 +0100 HID: API - fix leftovers of hidinput API in USB HID hidinput_{open,close}() functions do not belong to usbhid, but to the generic HID layer. Move them, and fix hooks in struct hid_device, so that now the callbacks are done to transport-specific _open() functions, but not input_open() functions. Signed-off-by: Jiri Kosina commit c080d89ad91e98fec0e8fc5f448a1ad899bd85c7 Author: Jiri Kosina Date: Thu Jan 25 11:43:31 2007 +0100 HID: hid debug from hid-debug.h to hid layer hid-debug.h contains a lot of code, and should not therefore be a header. This patch moves the code to generic hid layer as .c source, and introduces CONFIG_HID_DEBUG to conditionally compile it, instead of playing with #define DEBUG and including hid-debug.h. Signed-off-by: Jiri Kosina commit 20eb12790670985c8e30821218993bd260387b89 Author: Anssi Hannula Date: Thu Jan 11 16:51:18 2007 +0200 hid: force feedback driver for PantherLord USB/PS2 2in1 Adapter Add a force feedback driver for PantherLord USB/PS2 2in1 Adapter, 0810:0001. The device identifies itself as "Twin USB Joystick". Signed-off-by: Anssi Hannula Signed-off-by: Jiri Kosina commit 5556feae1c4e1cf2021b5fb2ef99973125de2250 Author: Anssi Hannula Date: Thu Jan 11 16:51:17 2007 +0200 hid: quirk for multi-input devices with unneeded output reports Add new quirk HID_QUIRK_SKIP_OUTPUT_REPORTS to skip output reports when enumerating reports on a hid-input device. Add this quirk and HID_QUIRK_MULTI_INPUT to 0810:0001. PantherLord Twin USB Joystick, 0810:0001 has separate input reports for 2 distinct game controllers in the same interface, so it needs HID_QUIRK_MULTI_INPUT. However, the device also contains one output report per controller which is used to control the force feedback function, and we do not want those to appear as separate input devices as well. The simplest approach seems to be to add a quirk to skip output reports on 0810:0001, and allow the force feedback driver to handle those. Signed-off-by: Anssi Hannula Signed-off-by: Jiri Kosina commit c4146067fd7889bc6fab6cdfd8b2795d745a2156 Author: Anssi Hannula Date: Thu Jan 11 16:51:16 2007 +0200 hid: allow force feedback for multi-input devices Allow hid devices with HID_QUIRK_MULTI_INPUT to have force feedback. This was previously disabled because there were not any force feedback drivers for such devices. This will change with my upcoming patch. Signed-off-by: Anssi Hannula Signed-off-by: Jiri Kosina commit 786f46b262cb7a491f4b144e42f076d5a1ef8eef Author: Rafa³ Bilski Date: Sun Feb 4 18:43:12 2007 +0100 [CPUFREQ] Longhaul - Add VT8235 support I don't know why it is working and how, but it is working. On my Epia transition time is by default set to 100us. I'm changing it to 200us. After that I can change frequency from min (x4.0) to max (x7.5) without lockup. Many times. There is a paranoid check at a beginning of a patch. Probably dead code, but I don't have better ideas for CL10000 case at the moment. Only way to to detect broken chip seems to be looking in log for spurious interrupts. Signed-off-by: Rafal Bilski Signed-off-by: Dave Jones commit 46ef955f5c9de0507859a3f9a92989b7425b73cc Author: Rafa³ Bilski Date: Sun Feb 4 15:58:46 2007 +0100 [CPUFREQ] Longhaul - Fix guess_fsb function This is bug reported by John-Marc Chandonia: > Detected 1002.292 MHz processor. > longhaul: VIA C3 'Nehemiah B' [C5N] CPU detected. Powersaver supported. > longhaul: Using throttling support. > longhaul: Invalid (reserved) FSB! FSB is correcly guessed for 999.554 MHz CPU. To fix this error: - ROUNDING should be range, not mask - at it's current value it is +7 -8, - more precise calculations inside guess_fsb - 7.5x133MHz is 1000MHz now. Signed-off-by: Rafal Bilski Signed-off-by: Dave Jones commit e4ac5e4f55f55b16e084a46b1b8e233f490ba701 Author: Dave Jones Date: Sun Feb 4 17:37:42 2007 -0500 [AGPGART] Don't try to remap i810 registers on resume. We don't unmap them on the suspend path, so on resume trying to remap will fail, and then result in an oops the next time something tries to access them. Signed-off-by: Dave Jones commit b45bfcc1ae084aa98c0350b8c33c8b57540b0acc Author: Hoang-Nam Nguyen Date: Wed Jan 24 00:14:18 2007 +0100 IB/ehca: Remove obsolete prototypes Remove prototypes for functions that don't exist. Signed-off-by: Hoang-Nam Nguyen Signed-off-by: Roland Dreier commit 4c34bdf58c0a3b305ebd9b5e74011ca1fd6d964d Author: Hoang-Nam Nguyen Date: Wed Jan 24 00:13:35 2007 +0100 IB/ehca: Remove use of do_mmap() This patch removes do_mmap() from ehca: - Call remap_pfn_range() for hardware register block - Use vm_insert_page() to register memory allocated for completion queues and queue pairs - The actual mmap() call/trigger is now controlled by user space, ie. libehca Signed-off-by: Hoang-Nam Nguyen Signed-off-by: Roland Dreier commit 1f12667021c542236b1f10eb5d8b2d8f3a79ab48 Author: Steve Wise Date: Tue Jan 23 19:03:17 2007 -0600 RDMA/addr: Handle ethernet neighbour updates during route resolution The iWARP connection manager uses the ib_addr services to do route resolution (neighbour discovery in the IP world). The ib_addr netevent callback routine, however, currently only acts on InfiniBand neighbour updates. It needs to act on ethernet neighbour updates as well. This patch just removes filtering on device type altogether and will trigger on any neighour updates where the nud_type is valid. This simplifies the code some. Signed-off-by: Steve Wise Signed-off-by: Roland Dreier commit fa7252ed4d92397baf30e4a144af95a33eaa925b Author: Jason Gunthorpe Date: Fri Jan 19 11:58:49 2007 -0700 IB: Make sure struct ib_user_mad.data is aligned Make the untyped data region in ib_user_mad have type u64 so that it gets aligned properly. This avoids alignment faults in ib_umad when casting the data field to an rmpp_mad and accessing the 64-bit tid field on architectures like ia64. Signed-off-by: Jason Gunthorpe Signed-off-by: Roland Dreier commit 1033ff670d49760604f5d4c73a1b60741863a406 Author: Ishai Rabinovitz Date: Tue Jan 16 17:26:22 2007 +0200 IB/srp: Don't wait for response when QP is in error state. When there is a call to send_tsk_mgmt SRP posts a send and waits for 5 seconds to get a response. When the QP is in the error state it is obvious that there will be no response so it is quite useless to wait. In fact, the timeout causes SRP to wait a long time to reconnect when a QP error occurs. (Each abort and each reset_device calls send_tsk_mgmt, which waits for the timeout). The following patch solves this problem by identifying the failure and returning an immediate error code. Signed-off-by: Ishai Rabinovitz Signed-off-by: Roland Dreier commit 062dbb69f32b9ccea701b30f8cc0049482e6211f Author: Michael S. Tsirkin Date: Sun Dec 31 21:09:42 2006 +0200 IB: Return qp pointer as part of ib_wc struct ib_wc currently only includes the local QP number: this matches the IB spec, but seems mostly useless. The following patch replaces this with the pointer to qp itself, and updates all low level drivers and all users. This has the following advantages: - Ability to get a per-qp context through wc->qp->qp_context - Existing drivers already have the qp pointer ready in poll cq, so this change actually saves a tiny bit (extra memory read) on data path (for ehca it would actually be expensive to find the QP pointer when polling a CQ, but ehca does not support SRQ so we can leave wc->qp as NULL for ehca) - Users that need the QP number can still get it through wc->qp->qp_num Use case: In IPoIB connected mode code, I have a common CQ shared by multiple QPs. To track connection usage, I need a way to get at some per-QP context upon the completion, and I would like to avoid allocating context object per work request just to stick a QP pointer into it. With this code, I can just use wc->qp->qp_context. Signed-off-by: Michael S. Tsirkin Signed-off-by: Roland Dreier commit 459d6e2a541a5226825db998e627e0aa046aa257 Author: Michael S. Tsirkin Date: Sun Feb 4 14:11:55 2007 -0800 IB: Include explicitly in uses struct kref, so it should include explicitly to avoid hidden include dependencies. Signed-off-by: Michael S. Tsirkin Signed-off-by: Roland Dreier commit f9d429a2e579ed7c51c49a81265f7e7d2c59c197 Author: Pierre Ossman Date: Sat Feb 3 13:36:41 2007 +0100 mmc: tifm: replace kmap with page_address Since we actively avoid highmem, calling kmap_atomic() instead of page_address() is effectively only obfuscation. Signed-off-by: Pierre Ossman commit c70840e819acdbab96b8cdf71d27cb68c6567efa Author: Pierre Ossman Date: Fri Feb 2 22:41:41 2007 +0100 mmc: sdhci: fix voltage ocr Some bad if-clauses caused the driver to just report the highest supported voltage, not all. Signed-off-by: Pierre Ossman commit 2a22b14edfdf1dce303ec48bb934a6a2edb278b5 Author: Pierre Ossman Date: Fri Feb 2 18:27:42 2007 +0100 mmc: sdhci: replace kmap with page_address Since we actively avoid highmem, calling kmap_atomic() instead of page_address() is effectively only obfuscation. Signed-off-by: Pierre Ossman commit 4a0ddbd25ad4e03a0a1657f5cb2259c9a35fe9e6 Author: Pierre Ossman Date: Wed Jan 31 18:20:48 2007 +0100 mmc: wbsd: replace kmap with page_address Since we actively avoid highmem, calling kmap_atomic() instead of page_address() is effectively only obfuscation. Signed-off-by: Pierre Ossman commit df1c4b7bf7f3b3a48d78c6e5c2fc5b9a1c01b821 Author: Pierre Ossman Date: Tue Jan 30 07:55:15 2007 +0100 mmc: handle pci_enable_device() return value in sdhci Make sure we report back any errors from pci_enable_device(). Signed-off-by: Pierre Ossman commit 397411e67ff473c36161d93e4c7ac6dc53e23503 Author: Pierre Ossman Date: Tue Jan 30 07:48:04 2007 +0100 mmc: Proper unclaim in mmc_block Make sure we release the claim on the host even on failure. Signed-off-by: Pierre Ossman commit fac8899129a0490020a0734cc84c1a94ac72c7e1 Author: Pierre Ossman Date: Sat Jan 27 13:18:26 2007 +0100 mmc: change wbsd mailing list The wbsd-devel list has been shut down. Refer people to LKML instead. Signed-off-by: Pierre Ossman commit ae06eaf9abb1fd00e413753786e13406eda5819a Author: Pierre Ossman Date: Sun Jan 7 16:59:06 2007 +0100 mmc: Graceful fallback for fancy features MMC high-speed, wide bus support and SD high-speed are functions that aren't critical for correct operation of the card. As such, they shouldn't mark the card as bad or dead when there is a failure activating these features. This is needed in particular on some really stupid hardware (e.g. Winbond's) where not all data transfer commands are supported. Signed-off-by: Pierre Ossman commit 5ba593a97206fb96dc0e63f209e6ade86452844f Author: Pierre Ossman Date: Tue Nov 21 17:45:37 2006 +0100 mmc: Handle wbsd's stupid command list The wbsd hardware is so incredibly brain damaged that it has an internal list of commands that result in data transfers. The result being that commands that aren't on this list aren't supported. Instead of locking up, waiting for a data interrupt that will never come, we try to fail a bit more gracefully. Signed-off-by: Pierre Ossman commit 55db890a838c7b37256241b1fc53d6344aa79cc0 Author: Pierre Ossman Date: Tue Nov 21 17:55:45 2006 +0100 mmc: Allow host drivers to specify max block count Many controllers have an upper limit on the number of blocks that can be transferred in one request. Allow the host drivers to specify this and make sure we avoid hitting this limit. Also change the max_sectors field to avoid confusion. This makes it map less directly to the block layer limits, but as they didn't apply directly on MMC cards anyway, this isn't a great loss. Signed-off-by: Pierre Ossman commit fe4a3c7a20f14d86022a8132adbf6ddb98e7197c Author: Pierre Ossman Date: Tue Nov 21 17:54:23 2006 +0100 mmc: Allow host drivers to specify a max block size Most controllers have an upper limit on the block size. Allow the host drivers to specify this and make sure we avoid hitting this limit. Signed-off-by: Pierre Ossman commit dba4accab17bd2e2e09088f746257a8c14af1cc2 Author: Alex Dubov Date: Mon Dec 11 01:55:38 2006 +1100 tifm_sd: add suspend and resume functionality Signed-off-by: Alex Dubov Signed-off-by: Pierre Ossman commit 41d78f7405659b55e082c5f0b3d1b625e75e1294 Author: Alex Dubov Date: Mon Dec 11 01:55:37 2006 +1100 tifm_core: add suspend/resume infrastructure for tifm devices Signed-off-by: Alex Dubov Signed-off-by: Pierre Ossman commit 8b40adab9c6cb63cede72c3ce3c3fee1157719e0 Author: Alex Dubov Date: Mon Dec 11 01:55:36 2006 +1100 tifm_7xx1: prettify Fix some spaces and tabs. No semantic changes are introduced. Signed-off-by: Alex Dubov Signed-off-by: Pierre Ossman commit b5ad6761533c3f7e97c93b2333a0f88490d44f36 Author: Alex Dubov Date: Mon Dec 11 01:55:35 2006 +1100 tifm_7xx1: recognize device 0xac8f as supported This patch also adds symbolic defines for supported pci ids. Signed-off-by: Alex Dubov Signed-off-by: Pierre Ossman commit 7146f0d3bd2bcd0100a5db54f4ba9edc1042fe01 Author: Alex Dubov Date: Mon Dec 18 14:20:06 2006 +1100 tifm_7xx1: switch from workqueue to kthread As there's only one work item (media_switcher) to handle and it's effectively serialized with itself, I found it more convenient to use kthread instead of workqueue. This also allows for a working implementation of suspend/resume, which were totally broken in the past version. Signed-off-by: Alex Dubov Signed-off-by: Pierre Ossman commit 6412d927313f08808d61b7efba8da43717d4e8d2 Author: Alex Dubov Date: Mon Dec 11 01:55:33 2006 +1100 tifm_7xx1: Merge media insert and media remove functions Hardware does not say whether card was inserted or removed when reporting socket events. Moreover, during suspend, media can be removed or switched to some other card type without notification. Therefore, for each socket in the change set the following is performed: 1. If there's active device in the socket it's unregistered 2. Media detection is performed 3. If detection recognizes supportable media, new device is registered This patch also alters some macros and variable names to enhance clarity. Signed-off-by: Alex Dubov Signed-off-by: Pierre Ossman commit 1499ead31ede528a657c50761c4780c40f929d6d Author: Alex Dubov Date: Mon Dec 11 01:55:32 2006 +1100 tifm_7xx1: simplify eject function Eject function can take advantage of the socket_id field instead of explicit pointer comparison. Signed-off-by: Alex Dubov Signed-off-by: Pierre Ossman commit 217334d14d28e6a671e6dd2c7a35c9070b0721ea Author: Alex Dubov Date: Mon Dec 11 01:55:31 2006 +1100 Add dummy_signal_irq function to save check in ISR Signed-off-by: Alex Dubov Signed-off-by: Pierre Ossman commit 50743f4cb1d655c7fbe25af58a9d0db6bf76d687 Author: Alex Dubov Date: Mon Dec 11 01:55:30 2006 +1100 Remove unused return value from signal_irq callback Signed-off-by: Alex Dubov Signed-off-by: Pierre Ossman commit 2e8ce5e7414e74fe8904495b1f22cf00d3349398 Author: Alex Dubov Date: Fri Dec 8 16:50:52 2006 +1100 tifm_sd: prettify This patch introduces no semantic changes - it is here for estetic purposes. Signed-off-by: Alex Dubov Signed-off-by: Pierre Ossman commit 8e02f8581cd2f9c12a03be7641d5c2c427170feb Author: Alex Dubov Date: Fri Dec 8 16:50:51 2006 +1100 tifm_sd: restructure initialization, removal and command handling In order to support correct suspend and resume several changes were needed: 1. Switch from work_struct to tasklet for command handling. When device suspend is called workqueues are already frozen and can not be used. 2. Separate host initialization code from driver's probe and don't rely on interrupts for host initialization. This, in turn, addresses two problems: a) Resume needs to re-initialize the host, but can not assume that device interrupts were already re-armed. b) Previously, probe will return successfully before really knowing the state of the host, as host interrupts were not armed in time. Now it uses polling to determine the real host state before returning. 3. Separate termination code from driver's remove. Termination may be caused by resume, if media changed type or became unavailable during suspend. Signed-off-by: Alex Dubov Signed-off-by: Pierre Ossman commit 83d420ba92bdd52127e4548ae8050a48f655ce3b Author: Alex Dubov Date: Fri Dec 8 16:50:50 2006 +1100 tifm_sd: fix hardware timeout setup The register access order when setting hardware timeout was incorrect and causing problems (wrong timeout intervals). This is now fixed. Signed-off-by: Alex Dubov Signed-off-by: Pierre Ossman commit 0803dd0c2594c7dc70c14ab00ea21e68605f5ba1 Author: Alex Dubov Date: Fri Dec 8 16:50:49 2006 +1100 tifm_sd: Switch software timeout handler from work_struct to timer Two changes are introduced to software timeout handler in order to simplify its management: 1. The implementation is switched from work_struct to timer 2. Previously, software timeout was rearmed with each interrupt. Now, current request must complete entirely within timeout interval. Signed-off-by: Alex Dubov Signed-off-by: Pierre Ossman commit 255ef22e89ecedcc594428444a72a29cb66153f5 Author: Alex Dubov Date: Fri Dec 8 16:50:48 2006 +1100 tifm_sd: use kmap_atomic instead of kmap for PIO data buffer Data buffer for PIO transfer used to be mapped in advance with kmap. Abolish it in favor of on-demand kmap_atomic. Signed-off-by: Alex Dubov Signed-off-by: Pierre Ossman commit 1289335a2ab57d00c638c3954dc86d6c4eab5606 Author: Alex Dubov Date: Fri Dec 8 16:50:47 2006 +1100 tifm_sd: alter order of the states in the command handler Previously, stop command was issued right after BRS (block received/sent) event. Stop command completion event could interfere with the card busy event, causing miscount of the written blocks. This patch ensures that stop command issued as last action for a particular command, after DMA sompletion event and written block count verification. Signed-off-by: Alex Dubov Signed-off-by: Pierre Ossman commit fba68bd2dab1ac99af3c5a963ec9581cfa9f1725 Author: Philip Langdale Date: Thu Jan 4 06:57:32 2007 -0800 mmc: Add support for SDHC cards Thanks to the generous donation of an SDHC card by John Gilmore, and the surprisingly enlightened decision by the SD Card Association to publish useful specs, I've been able to bash out support for SDHC. The changes are not too profound: i) Add a card flag indicating the card uses block level addressing and check it in the block driver. As we never took advantage of byte-level addressing, this simply involves skipping the block -> byte translation when sending commands. ii) The layout of the CSD is changed - a set of fields are discarded to make space for a larger C_SIZE. We did not reference any of the discarded fields except those related to the C_SIZE. iii) Read and write timeouts are fixed values and not calculated from CSD values. iv) Before invoking SEND_APP_OP_COND, we must invoke the new SEND_IF_COND to inform the card we support SDHC. Signed-off-by: Philipl Langdale Signed-off-by: Pierre Ossman commit 9e9dc5f29f2eb65153a15c4fdb12b4382e3a75b2 Author: Darren Salt Date: Sat Jan 27 15:32:31 2007 +0100 mmc: Power quirk for ENE controllers Support for these devices was broken for 2.6.18-rc1 and later by commit 146ad66eac836c0b976c98f428d73e1f6a75270d, which added voltage level support. This restores the previous behaviour for these devices by ensuring that when the voltage is changed, only one write to set the voltage is performed. It may be that both writes are needed if the voltage is being changed between two non-zero values or that it's safe to ensure that only one write is done if the hardware only supports one voltage; I don't know whether either is the case nor can I test since I have only the one SD reader (1524:0550), and it supports just the one voltage. Signed-off-by: Darren Salt Signed-off-by: Pierre Ossman commit 11354d03afe9dd0d114e078057158baad4b4eee9 Author: Pierre Ossman Date: Sun Jan 14 01:41:45 2007 +0100 mmc: let host be parent of cards Change the parent of cards to be a specific host (a class device), not the physical controller. This is particularly useful when the hardware has multiple slots, meaning multiple hosts. Signed-off-by: Pierre Ossman commit f22ee4edf63e7480511112d9965c71e07be3f8b7 Author: Pierre Ossman Date: Tue Dec 26 15:11:23 2006 +0100 mmc: replace host->card_busy As card_busy was only used to indicate if the host was exclusively claimed and not really used to identify a particular card, replacing it with just a boolean makes things a lot more easily understandable. Signed-off-by: Pierre Ossman commit 279bc4450989215e741c2c9d3a726f1ac96ede40 Author: Manuel Lauss Date: Thu Jan 25 10:27:41 2007 +0100 mmc: au1xmmc: return errors for unknown response types au1xmmc: return error when encountering unhandled/unknown response type. Signed-off-by: Manuel Lauss Signed-off-by: Pierre Ossman commit 82999770d6926193f50b42e713a92ee4028398e3 Author: Manuel Lauss Date: Thu Jan 25 10:29:24 2007 +0100 mmc: au1xmmc: implement proper ro switch detection au1xmmc: implement proper R/O switch detection. Signed-off-by: Manuel Lauss Signed-off-by: Pierre Ossman commit 588a700b269b785b19d5d03084bee5e1b74c7758 Author: Trond Myklebust Date: Fri Feb 2 17:41:53 2007 -0800 NFSv4: /proc/mounts displays the wrong server name for referrals Signed-off-by: Trond Myklebust commit 1d21632d366b33b3adf4fa26144edf3162a9715d Author: Trond Myklebust Date: Fri Feb 2 15:56:06 2007 -0800 NFSv4: Ensure non-root user can trigger a referral automount Currently only root can trigger a referral automount because only root can access rpc_pipefs directories. Enabling read access to non-root should be harmless (they can still not access the pipes themselves) and will suffice to fix this problem. Signed-off-by: Trond Myklebust commit 46121cf7d85869bfe9588bac7ccf55aa0bc7f278 Author: Chuck Lever Date: Wed Jan 31 12:14:08 2007 -0500 SUNRPC: fix print format for tk_pid The tk_pid field is an unsigned short. The proper print format specifier for that type is %5u, not %4d. Also clean up some miscellaneous print formatting nits. Signed-off-by: Chuck Lever Signed-off-by: Trond Myklebust commit 8885cb367f86ce02bed3bf18192d74a53ac3b81f Author: Chuck Lever Date: Wed Jan 31 12:14:05 2007 -0500 SUNRPC: fix print format for tk_pid in auth_gss support The tk_pid field is an unsigned short. The proper print format specifier for that type is %5u, not %4d. Also clean up some miscellaneous print formatting nits. Signed-off-by: Chuck Lever Signed-off-by: Trond Myklebust commit a3f565b1e530a756472401835107d08fd291f242 Author: Chuck Lever Date: Wed Jan 31 12:14:01 2007 -0500 NFS: fix print format for tk_pid The tk_pid field is an unsigned short. The proper print format specifier for that type is %5u, not %4d. Also clean up some miscellaneous print formatting nits. Signed-off-by: Chuck Lever Signed-off-by: Trond Myklebust commit 4dc2eaecd4cf0687727e418540bccf956a62ebcf Author: Benny Halevy Date: Wed Dec 20 22:29:46 2006 +0200 NFS: move NFS_DEBUG definition Trond, looks like the changes to include/linux/nfs_fs.h in 2.6.18 that moved the #include's of sunrpc header files into the #ifdef __KERNEL__ block disabled nfs debugging for all nfs c file not including any sunrpc header. The following patch moves the definition down, right before its use for defining ifdebug. Signed-off-by: Benny Halevy (Moved definition further down into the __KERNEL__ section: Trond) Signed-off-by: Trond Myklebust commit e148582e10a2c1a23dfc09210df4a18bc6cca4e9 Author: Trond Myklebust Date: Wed Dec 13 16:43:13 2006 -0500 NFSv4: Add lockdep checks to nfs4_wait_clnt_recover() Attempt to detect deadlocks due to caller holding locks on clp->cl_sem Signed-off-by: Trond Myklebust commit a6a352e93dfa78db8903f0e3610abb76efbf7fc9 Author: Trond Myklebust Date: Wed Dec 13 16:43:06 2006 -0500 NFSv4: Don't start state recovery in nfs4_close_done() We might not even have any open files at this point... Signed-off-by: Trond Myklebust commit 7c85d9007d05436e71d2b805b96c1e36a8193bd4 Author: Trond Myklebust Date: Wed Dec 13 15:23:48 2006 -0500 NFS: Fixup some outdated comments... Signed-off-by: Trond Myklebust commit d30c8348a4ba292a09addd122de2f3189c21a7ff Author: Trond Myklebust Date: Wed Dec 13 15:23:47 2006 -0500 NFS: nfs_writepages() cleanup Strip out the call to nfs_commit_inode(), and allow that to be done by nfs_write_inode(). Signed-off-by: Trond Myklebust commit f40313ac39fedca519c36fdc454acf2632e641da Author: Trond Myklebust Date: Sat Jan 13 02:28:08 2007 -0500 NFS: Micro-optimisation for nfs_wb_page() Signed-off-by: Trond Myklebust commit 02241bc47e8961768de83d855accd0dcad1df045 Author: Trond Myklebust Date: Sat Jan 13 02:28:07 2007 -0500 NFS: Ensure that ->writepage() uses flush_stable() when reclaiming pages Signed-off-by: Trond Myklebust commit 8e0969f0451eaf7cf32f2ec3946196d8d0b1cb2c Author: Trond Myklebust Date: Wed Dec 13 15:23:44 2006 -0500 NFS: Remove nfs_readpage_sync() It makes no sense to maintain 2 parallel systems for reading in pages. Signed-off-by: Trond Myklebust commit c228fd3aeef55637354167faead74c579d5da28b Author: Trond Myklebust Date: Sat Jan 13 02:28:11 2007 -0500 NFSv4: Cleanups for fs_locations code. Start long arduous project... What the hell is struct dentry = {}; all about? Signed-off-by: Trond Myklebust commit faebf4e2bb0efad9dda396ea13d5c6ad15d7d7fb Author: Trond Myklebust Date: Sat Jan 13 02:28:11 2007 -0500 NFSv4: Don't require that NFSv4 mount paths begin with '/' Addresses the regression noted in http://bugzilla.linux-nfs.org/show_bug.cgi?id=134 Also mark a couple of other regressions as requiring fixing. Signed-off-by: Trond Myklebust commit c79ba787c11e767ffaf8d723923afda99ba6c63c Author: Trond Myklebust Date: Wed Jan 31 08:16:24 2007 -0500 NFS: Dont clobber more uptodate values in nfs_set_verifier() nfs_lookup_revalidate and friends are not serialised, so it is currently quite possible for the dentry to be revalidated, and then have the updated verifier replaced with an older value by another process. Signed-off-by: Trond Myklebust commit ef75c7974b383769ae5741cf930b8aa4dcaef395 Author: Trond Myklebust Date: Tue Jan 16 10:09:44 2007 -0500 NFS: Also use readdir info to revalidate positive dentries If the fileid of the cached dentry fails to match that returned by the readdir call, then we should also d_drop. Try to take into account the fact that on NFSv4, readdir may return the "mounted_on_fileid" by looking for submounts. Signed-off-by: Trond Myklebust commit df1d5d23d3a1a713c69b0f9ec67c59aeca3ce6b3 Author: Trond Myklebust Date: Mon Jan 15 13:56:29 2007 -0500 NFS: Fix a readdir/lookup inefficiency. Make sure that nfs_readdir_lookup() handles negative dentries correctly. If d_lookup() returns a negative dentry, then we need to d_drop() that since readdir shows that it should be positive. Signed-off-by: Trond Myklebust commit ccfeb506231348a3c60ab0fdb5753a574653e3c0 Author: Trond Myklebust Date: Sat Jan 13 02:28:12 2007 -0500 NFS: Fix up "rm -rf"... When a file is being scheduled for deletion by means of the sillyrename mechanism, it makes sense to start out writeback of the dirty data as soon as possible in order to ensure that the delete can occur. Examples of cases where this is an issue include "rm -rf", which will busy-wait until the file is closed, and the sillyrename completes. Signed-off-by: Trond Myklebust commit ab91f264cfbafd079dcb1bd02e9803c2dd65de19 Author: Trond Myklebust Date: Fri Feb 2 14:47:17 2007 -0800 NFSv4: Fix NFS4_enc_server_caps_sz/NFS4_dec_server_caps_sz Insert missing encode_putfh_maxsz/decode_putfh_maxsz Signed-off-by: Trond Myklebust commit f2d0d85e58099d518cb50b1c95fc1fc62bbce1b8 Author: Trond Myklebust Date: Fri Feb 2 14:46:09 2007 -0800 NFSv4: Fix Oops in nfs4_create_referral_server The filehandle that is passed into nfs4_create_referral_server is not initialised. The expectation is that nfs4_create_referral_server will initialise it, and return it to the caller. Signed-off-by: Trond Myklebust commit 2efef837fb84f78cee7439804cb3722bffc64e75 Author: Trond Myklebust Date: Sat Feb 3 13:38:41 2007 -0800 RPC: Clean up rpc_execute... The error values are already propagated through task->tk_status, and none of the callers check one without checking the other, so we can drop the return value. Signed-off-by: Trond Myklebust commit 54cc533aaa0dc331ad126f0aacfb19572adee638 Author: Trond Myklebust Date: Sat Feb 3 13:38:40 2007 -0800 RPC: Fix double free in portmapper code rpc_run_task is guaranteed to always call ->rpc_release. Signed-off-by: Trond Myklebust commit a995e9eb3258df6ab2e9f958e08003978e50d568 Author: Trond Myklebust Date: Fri Feb 2 15:37:43 2007 -0800 NLM: Fix double free in __nlm_async_call rpc_call_async() will always call rpc_release_calldata(), so it is an error for __nlm_async_call() to do so as well. Signed-off-by: Trond Myklebust commit 44746438973e4f9ed9bdf3347e75f60f105b325a Author: Jiri Kosina Date: Thu Feb 1 16:43:07 2007 -0800 [SCSI] Buslogic: local_irq_disable() is redundant after local_irq_save() drivers/scsi/BusLogic.c::BusLogic_Command() contains local_irq_disable() call after local_irq_save(). This looks redundant. Signed-off-by: Jiri Kosina Signed-off-by: Andrew Morton Signed-off-by: James Bottomley commit 0d44b2ba287ea98547097ad2b8b0cc5f0589b8d2 Author: Rafa³ Bilski Date: Wed Jan 31 23:50:49 2007 +0100 [CPUFREQ] Longhaul - Remove duplicate tables Now there is no need to depend on -1 in Nehemiah tables. After previous change code is eliminating multipliers lower then 5.0 by minmult for Nehemiah A and B. Signed-off-by: Rafa³ Bilski Signed-off-by: Dave Jones commit 980342a7eb6b4ebcc5feffe6287ad5cda5a68a4b Author: Rafa³ Bilski Date: Wed Jan 31 23:42:47 2007 +0100 [CPUFREQ] Longhaul - Introduce Nehemiah C Looks like some time ago I introduced a bug to Longhaul. I had report that 9x133Mhz CPU is seen as 5x133MHz. So I changed multipliers table. That was a mistake. According to documentation table was correct. So only way to avoid 5 or 9 dilema is not use MaxMHzBR for PowerSaver 1.0. One code that works on all processors. To do it I need also separate flag for Nehemiah C (min = x4.0) and Nehemiah (min = x5.0). Signed-off-by: Rafa³ Bilski Signed-off-by: Dave Jones commit 58389a86df48ff927846df9537ea34d9961b5c44 Author: Joachim Deguara Date: Tue Jan 30 16:53:54 2007 +0100 [CPUFREQ] fix cpuinfo_cur_freq for CPU_HW_PSTATE This fixes the cpuinfo_cur_freq value by using the correct find_khz_freq_from_fiddid() when the CPU uses hardware p-states. Signed-off-by: Joachim Deguara Acked-by: Mark Langsdorf Signed-off-by: Dave Jones commit 14796722839ee50ed2a2c7a6a135e7d0888aaada Author: Rafa³ Bilski Date: Fri Jan 19 22:28:22 2007 +0100 [CPUFREQ] Longhaul - Remove "ignore_latency" option There is no need to have this option in Longhaul anymore. It was for laptop with CLE266 chipset in times, when only ACPI C3 was used to switch frequency. Now we have native support not only for CLE266, but CN400 too. Would be good to have support for PN266, but I can't find datasheet for it. Looks like BIOS for CPU's faster then 1GHz don't support ACPI C2 nor C3. Signed-off-by: Rafa³ Bilski Signed-off-by: Dave Jones commit a030ce4477baa06dd9c037ccd3c8d171aac9ed44 Author: Thomas Hellstrom Date: Tue Jan 23 10:33:43 2007 +0100 [AGPGART] Allow drm-populated agp memory types This patch allows drm to populate an agpgart structure with pages of its own. It's needed for the new drm memory manager which dynamically flips pages in and out of AGP. The patch modifies the generic functions as well as the intel agp driver. The intel drm driver is currently the only one supporting the new memory manager. Other agp drivers may need some minor fixing up once they have a corresponding memory manager enabled drm driver. AGP memory types >= AGP_USER_TYPES are not populated by the agpgart driver, but the drm is expected to do that, as well as taking care of cache- and tlb flushing when needed. It's not possible to request these types from user space using agpgart ioctls. The Intel driver also gets a new memory type for pages that can be bound cached to the intel GTT. Signed-off-by: Thomas Hellstrom Signed-off-by: Dave Jones commit 0316fe8319ff62e527d0d91a3bc7df1c59eafae8 Author: Zwane Mwaikambo Date: Mon Jan 29 21:20:31 2007 -0800 [AGPGART] compat ioctl The following video card requires the agpgart driver ioctl interface in order to detect video memory. 00:02.0 VGA compatible controller: Intel Corporation Mobile 945GM/GMS/940GML Express Integrated Graphics Controller (rev 03) Tested on a Thinkpad Z61t, Xorg.0.log from a 32bit debian Xorg is at; http://montezuma.homeunix.net/Xorg.0.log Signed-off-by: Zwane Mwaikambo Signed-off-by: Dave Jones commit 083d1631be7c36309359792ecf61aaf88559043f Author: Wu, Gilbert Date: Tue Jan 30 15:31:25 2007 -0800 [SCSI] aic94xx: update for v28 firmware These changes work compatibly with the old V17 firmware Contribution: Ed Chim Gilbert Wu Change Log: 1. Use dword instead of qword to display the value of Connection State register for debug purpose. 2. There are some registers location of AIC94xx chip has been changed according to the new V28 firmware. The patch has redefined the register location and provided initialization. 3. The new sequencer firmware v28 for Aic94xx SAS/SATA Linux open source device driver can be downloaded from http://www.adaptec.com/NR/exeres/35B611BC-9789-4B5B-82C6-85A2CCA8A46A.htm Signed-off-by: Gilbert Wu Signed-off-by: James Bottomley commit 292148f8bb2b5d120440e046d24de07a739461aa Author: Brian King Date: Tue Jan 30 17:51:17 2007 -0600 [SCSI] scsi_error: Fix lost EH commands If an EH command times out today, the LLDD's abort handler will be called to abort the command. It is assumed that this completes successfully, which can result in the command getting completed later resulting in an oops. Improve the current implementation by escalating all the way to host reset if necessary in order to clean up the EH command. Signed-off-by: Brian King Signed-off-by: James Bottomley commit 214fbb75075efa677b614be79a2d62dd79785b4f Author: Darrick J. Wong Date: Mon Jan 29 23:48:25 2007 -0800 [SCSI] aic94xx: Add default bus reset handler Signed-off-by: Darrick J. Wong Signed-off-by: James Bottomley commit 058e2c474897dc53c88ac9162f9a9b16a879b8cd Author: Darrick J. Wong Date: Mon Jan 29 23:48:22 2007 -0800 [SCSI] aic94xx: Remove TMF result code munging In asd_initiate_ssp_tmf, the TMF result code is replaced with TMF_RESP_FUNC_FAILED except when the TMF returns a result code immediately. However, TMFs can return result codes via an ESCB... yet these codes are also replaced with "FAILED". The only values that can fall into that case are TMF_* codes anyway, so get rid of this code where COMPLETE and SUCCESS are turned into FAILED. This also lets us propagate those TMF_* codes up to the caller. Signed-off-by: Darrick J. Wong Signed-off-by: James Bottomley commit a9344e68ac0a656475006737dbc258d69fe4f7b0 Author: Darrick J. Wong Date: Mon Jan 29 23:48:19 2007 -0800 [SCSI] libsas: Add an LU reset mechanism to the error handler After discussion with andmike and dougg, it seems that the purpose of eh_device_reset_handler is to issue LU resets, and that eh_bus_reset_handler would be a more appropriate place for a phy reset. Signed-off-by: Darrick J. Wong Signed-off-by: James Bottomley commit 423f7cf467045eab616f97309aed87a54b5e351d Author: Darrick J. Wong Date: Tue Jan 30 12:07:27 2007 -0800 [SCSI] libsas: Don't BUG when connecting two expanders via wide port libsas: Don't BUG when connecting two expanders via wide port When a device is connected to an expander, the discovery process goes through sas_ex_discover_dev to figure out what's attached to the phy. If it is the case that the phy being discovered happens to be the second phy of a wide link to an expander, that discover_dev function will incorrectly call sas_ex_discover_expander, which creates another sas_port and tries to attach the other sas_phys to the new port, thus triggering a BUG. The correct thing to do is to check the other ex_phys of the expander to see if there's a sas_port for this sas_phy, and attach the sas_phy to the existing sas_port. This is easily triggered if one enables the phys of a wide port between expanders one by one. This second version of the patch fixes a small regression in the case where all the phys show up at once and we accidentally try to attach to a port that hasn't been created yet. Signed-off-by: Darrick J. Wong Signed-off-by: James Bottomley commit 9abe16c670bd3d4ab5519257514f9f291383d104 Author: Kai Makisara Date: Sat Feb 3 13:21:29 2007 +0200 [SCSI] st: fix Tape dies if wrong block size used, bug 7919 On Thu, 1 Feb 2007, Andrew Morton wrote: > On Thu, 1 Feb 2007 15:34:29 -0800 > bugme-daemon@bugzilla.kernel.org wrote: > > > http://bugzilla.kernel.org/show_bug.cgi?id=7919 > > > > Summary: Tape dies if wrong block size used > > Kernel Version: 2.6.20-rc5 > > Status: NEW > > Severity: normal > > Owner: scsi_drivers-other@kernel-bugs.osdl.org > > Submitter: dmartin@sccd.ctc.edu > > > > > > Most recent kernel where this bug did *NOT* occur: 2.6.17.14 > > > > Other Kernels Tested and Results: > > > > OK 2.6.15.7 > > OK 2.6.16.37 > > OK 2.6.17.14 > > BAD 2.6.18.6 > > BAD 2.6.18-1.2869.fc6 > > BAD 2.6.19.2 + > > BAD 2.6.20-rc5 > > > > NOTE: 2.6.18-1.2869.fc6 is a Fedora modified kernel, all others are from kernel.org > > ... > > Steps to reproduce: > > Get a Adaptec AHA-2940U/UW/D / AIC-7881U card and a tape drive, > > install a recent kernel > > set the tape block size - mt setblk 4096 > > read from or write to tape using wrong block size - tar -b 7 -cvf /dev/tape foo > > Write does not trigger this bug because the driver refuses in fixed block mode writes that are not a multiple of the block size. Read does trigger it in my system. The bug is not associated with any specific HBA. st tries to do direct i/o in fixed block mode with reads that are not a multiple of tape block size. The patch in this message fixes the st problem by switching to using the driver buffer up to the next close of the device file in fixed block mode if the user asks for a read like this. I don't know why the bug has surfaced only after 2.6.17 although the st problem is old. There may be another bug in the block subsystem and this patch works around it. However, the patch fixes a problem in st and in this way it is a valid fix. This patch may also fix the bug 7900. The patch compiles and is lightly tested. Signed-off-by: Kai Makisara Signed-off-by: James Bottomley commit 894d79bedd8b48fe838083f2d2a42ac09817c530 Author: Len Brown Date: Sat Feb 3 02:13:53 2007 -0500 asus-laptop: merge with ACPICA table update No longer need a buffer for a copy of the DSDT, just a pointer to the mapped table. Signed-off-by: Len Brown commit 547352660506ab99d6b0bad58dea495bf3718cee Author: Zhang Rui Date: Thu Jan 11 02:09:09 2007 -0500 ACPI: bay: Convert ACPI Bay driver to be compatible with sysfs update. Set fake hid for ejectable drive bay. Match bay devices by checking the hid. Remove .match method of Bay driver. Signed-off-by: Zhang Rui Signed-off-by: Len Brown commit 0ed1e38d513ea683ce125e698dd41d31441e0e8c Author: Len Brown Date: Fri Feb 2 22:39:16 2007 -0500 ACPI: bay: new driver is EXPERIMENTAL Signed-off-by: Len Brown commit 5d22e1e83aac1f81f948ac8bff281487c11cc967 Author: Adrian Bunk Date: Mon Dec 4 14:49:39 2006 -0800 ACPI: bay: make drive_bays static Signed-off-by: Adrian Bunk Signed-off-by: Andrew Morton Signed-off-by: Len Brown commit 2b167c01190b647c976e7fab312f2e3d3b3a785f Author: Kristen Carlson Accardi Date: Mon Dec 18 18:07:00 2006 -0500 ACPI: bay: make bay a platform driver Convert the bay driver to be a platform driver, so that we can have sysfs entries. Signed-off-by: Kristen Carlson Accardi Signed-off-by: Len Brown commit e9dd85e5bdff2a3981dfaa55869ba920e985ea8a Author: Kristen Carlson Accardi Date: Mon Dec 18 18:06:00 2006 -0500 ACPI: bay: remove prototype procfs code Remove all the procfs related code. Signed-off-by: Kristen Carlson Accardi Signed-off-by: Len Brown commit 5447cbb278fd01c402180ab1e820b95101e782fa Author: Len Brown Date: Sat Oct 21 01:15:41 2006 -0400 ACPI: bay: delete unused variable drivers/acpi/bay.c: In function ‘bay_notify’: drivers/acpi/bay.c:491: warning: unused variable ‘bay’ Signed-off-by: Len Brown commit 01b57e73728880b787c85e27ad06c249412813b1 Author: Kristen Carlson Accardi Date: Fri Oct 20 14:30:25 2006 -0700 ACPI: bay: new driver adding removable drive bay support Signed-off-by: Kristen Carlson Accardi Signed-off-by: Andrew Morton Signed-off-by: Len Brown commit fe9a2f77e5ad508b18671571c0b3f6f79ea709a8 Author: Kristen Carlson Accardi Date: Fri Feb 2 22:33:00 2007 -0500 ACPI: dock: check if parent is on dock When determining if a device is on a dock station, we should check the parent of the device as well. Signed-off-by: Kristen Carlson Accardi Signed-off-by: Len Brown commit b0b7eaaf0c7aefd118d3ff8640fbed75a9fad9a1 Author: Alexey Starikovskiy Date: Thu Jan 25 22:39:44 2007 -0500 ACPICA: fix gcc build warnings drivers/acpi/namespace/nsparse.c:126: warning: int format, different type arg (arg 7) drivers/acpi/tables/tbfadt.c:224: warning: unsigned int format, different type arg (arg 6) drivers/acpi/utilities/utdebug.c:184: warning: cast from pointer to integer of different size drivers/acpi/utilities/utdebug.c:184: warning: cast from pointer to integer of different size drivers/acpi/utilities/utdebug.c:197: warning: cast from pointer to integer of different size drivers/acpi/processor_idle.c:1093: warning: long long unsigned int format, u64 arg (arg 5) Signed-off-by: Len Brown commit 3e643e77a929202455a0cc868c2030a5ba8d1371 Author: John Keller Date: Tue Jan 30 01:18:38 2007 -0500 Altix: Add ACPI SSDT PCI device support (hotplug) Support for dynamic loading and unloading of ACPI SSDT tables upon slot hotplugs and unplugs. On SN platforms, we now represent every populated root bus slot with a single ACPI SSDT table containing info for every device and PPB attached to the slot. These SSDTs are generated by the prom at initial boot and hotplug time. The info in these SSDT tables is used by the SN kernel IO "fixup" code (which is called at boot and hotplug time). On hotplugs (i.e. enable_slot()), if running with an ACPI capable prom, attempt to obtain a new ACPI SSDT table for the slot being hotplugged. If successful, add the table to the ACPI namespace (acpi_load_table()) and then walk the new devices and add them to the ACPI infrastructure (acpi_bus_add()). On hot unplugs (i.e. disable_slot()), if running with an ACPI capable prom, attempt to remove the SSDT table associated with the slot from the ACPI namespace (acpi_unload_table_id()) and infastructure (acpi_bus_trim()). From: John Keller A bug was fixed where the sgi hotplug driver was removing the slot's SSDT table from the ACPI namespace a bit too early in disable_slot(). Also, we now call acpi_bus_start() subsequent to acpi_bus_add(). Signed-off-by: Aaron Young Cc: Greg KH Cc: "Luck, Tony" Signed-off-by: Andrew Morton Signed-off-by: Len Brown commit 6f09a9250a5d76c0765cd51a33e0a042e9761cfc Author: John Keller Date: Tue Jan 30 01:17:37 2007 -0500 Altix: ACPI SSDT PCI device support Add SN platform support for running with an ACPI capable PROM that defines PCI devices in SSDT tables. There is a SSDT table for every occupied slot on a root bus, containing info for every PPB and/or device on the bus. The SSDTs will be dynamically loaded/unloaded at hotplug enable/disable. Platform specific information that is currently passed via a SAL call, will now be passed via the Vendor resource in the ACPI Device object(s) defined in each SSDT. Signed-off-by: John Keller Cc: Greg KH Cc: "Luck, Tony" Signed-off-by: Andrew Morton Signed-off-by: Len Brown commit 647fb47dfabeffd2f1706013ebf5cfc92b70d273 Author: Len Brown Date: Fri Feb 2 22:14:22 2007 -0500 ACPICA: reduce conflicts with Altix patch series Syntax only -- no functional changes. Signed-off-by: Len Brown commit 07c861d6d9ca3dc58e225bcfe2da0f378af6fa6c Author: Eric Moore Date: Mon Jan 29 09:48:50 2007 -0700 [SCSI] fusion - bump version - 3.04.04 bump version, and fix email addr for lsi support Signed-off-by: Eric Moore Signed-off-by: James Bottomley commit cd2c61911dfe0d87cb872571739d5838cc233747 Author: Eric Moore Date: Mon Jan 29 09:47:47 2007 -0700 [SCSI] fusion - error handling bug fix's misc error handling bug fix's - properly interpret iocstatus returned after task management request - clear tmState after a failed doorbell - cleanup mptscsih_taskmgmt_complete Signed-off-by: Eric Moore Signed-off-by: James Bottomley commit 2ecce492290bf0d5eedc76cf0f4bf45f8c3f42bc Author: Eric Moore Date: Mon Jan 29 09:47:08 2007 -0700 [SCSI] fusion - report wide port sas address's for hba phys Return proper sas address to sas transport layer for parent phys that form a wide port. Current implementation returns a different address for each phy, incremented by one from the base address. Signed-off-by: Eric Moore Signed-off-by: James Bottomley commit defad23020bb7701b3ad414135c73fc03054507b Author: Alexey Starikovskiy Date: Fri Feb 2 22:02:55 2007 -0500 ACPI_NUMA: fix HP IA64 simulator issue with extended memory domain ACPI 3.0 incorporated the SRAT spec, upping the table version to 2, and extending the size of the proximity domain from 1-byte to 4-bytes. This extension was into a reserved field that firmware should set to 0, but the HP simulator had non-zero values there resulting in unexpected huge numbers. So mask the domain down to 8-bits for now. A more general fix will be to check the table version supplied by firmware and get paranoid about reserved fields. Signed-off-by: Alexey Starikovskiy Signed-off-by: Len Brown commit df9e062ad994c4db683377b108c0dbed4690e4b0 Author: Eric Moore Date: Mon Jan 29 09:46:21 2007 -0700 [SCSI] fusion - serialize target resets in mptsas.c Fusion firmware requires target reset following hotplug removal event, with purpose to flush target outstanding request in fw. Current implementation does the target resets from delayed work tasks, that in heavy load conditions, take too long to be invoked, resulting in command time outs This patch will issue target reset immediately from ISR context, and will queue remaining target resets to be issued after the previous one completes. The delayed work tasks are spawned during the target reset completion. Signed-off-by: Eric Moore Signed-off-by: James Bottomley commit b506ade9f3c309ac2ce3ffc4039f731097506038 Author: Eric Moore Date: Mon Jan 29 09:45:37 2007 -0700 [SCSI] fusion - inactive raid support, and raid event bug fix's inactive raid support, e.g. exposing hidden raid components belonging to a volume that are inactive. Also misc bug fix's for various raid asyn events. Signed-off-by: Eric Moore Signed-off-by: James Bottomley commit c6c727a1a0ff90c80425b7226557b2354e00cf7b Author: Eric Moore Date: Mon Jan 29 09:44:54 2007 -0700 [SCSI] fusion - iocstatus, loginfo, and event debug updates various string updates for iocstatus, logingo, and fw asyn events. Signed-off-by: Eric Moore Signed-off-by: James Bottomley commit 873c82ed165a345fa381415b9734d26e9af4ec96 Author: Eric Moore Date: Mon Jan 29 09:44:06 2007 -0700 [SCSI] fusion - added mptspi debug helpful debug for mptspi module Signed-off-by: Eric Moore Signed-off-by: James Bottomley commit 5a9c47b1344b514758d5d7f193c672850390cc36 Author: Eric Moore Date: Mon Jan 29 09:43:17 2007 -0700 [SCSI] fusion - move SPI API over to mptspi.c Move some functions that only apply to the mptspi module over from mptscsih.c Signed-off-by: Eric Moore Signed-off-by: James Bottomley commit 793955f549c710a1b0c18f823d5d710840747b15 Author: Eric Moore Date: Mon Jan 29 09:42:20 2007 -0700 [SCSI] fusion - Greater than 255 target and lun support Add support for greater than 255 target and luns. Kill the hd->Target[] field, and change all references of bus_id/target_id, to channel/id. Signed-off-by: Eric Moore Signed-off-by: James Bottomley commit 45eded8703c0f9d58a8807f80baa9fe98ac0ec67 Author: Alexey Starikovskiy Date: Fri Feb 2 21:48:40 2007 -0500 ACPI: fix HP RX2600 IA64 boot Copy space_id of GAS structure to newly created GAS. The previous FADT conversion code defaulted to IO space. Signed-off-by: Alexey Starikovskiy Signed-off-by: Len Brown commit 0e5683350f5bcd23d5d579f91d488caeda432617 Author: Alexey Starikovskiy Date: Fri Feb 2 21:37:53 2007 -0500 ACPI: build fix for IBM x440 - CONFIG_X86_SUMMIT i386 srat.c broke due to re-names from ACPICA table-manager re-write. Signed-off-by: Alexey Starikovskiy Signed-off-by: Len Brown commit 502c62f17aa7daa78d5da963305251b872885ff9 Author: Eric Moore Date: Mon Jan 29 09:41:12 2007 -0700 [SCSI] spi transport class: export spi_dv_pending Signed-off-by: Eric Moore Signed-off-by: James Bottomley commit 5763d3c7a0c2b165504954b1eeb898fb8d97d8f5 Author: Bob Moore Date: Fri Feb 2 19:48:24 2007 +0300 ACPICA: Update version to 20070126 Signed-off-by: Alexey Starikovskiy Signed-off-by: Len Brown commit 035f994b3ccfcfc555f838e2f33a2e49721e8533 Author: Bob Moore Date: Fri Feb 2 19:48:24 2007 +0300 ACPICA: Fix for incorrect parameter passed to AcpiTbDeleteTable during table load. Bad pointer was passed in the case where the DSDT is overridden. Signed-off-by: Alexey Starikovskiy Signed-off-by: Len Brown commit 6c9deb7201d96733dcd1b4cc44e99232308db359 Author: Bob Moore Date: Fri Feb 2 19:48:24 2007 +0300 ACPICA: Update copyright to 2007. Added 2007 copyright to all module headers and signons. This affects virtually every file in the ACPICA core subsystem, iASL compiler, and the utilities. Signed-off-by: Alexey Starikovskiy Signed-off-by: Len Brown commit 11bf04c44fd284a5f4e2348a04da6f749cace250 Author: Alexey Starikovskiy Date: Fri Feb 2 19:48:23 2007 +0300 ACPICA: Allow processor to be declared with the Device() instead of Processor() Allow processor to be declered with the Device(), such as: Device(CPU1234) { Name(_HID, "ACPI007") Name(_UID, 1234) } Signed-off-by: Len Brown commit f18c5a08bf035b51939281f5b49aa3ae45cea6ce Author: Alexey Starikovskiy Date: Fri Feb 2 19:48:23 2007 +0300 ACPICA: Allow ACPI id to be u32 instead of u8. Allow ACPI id to be u32 instead of u8. Requires drop of conversion tables with the acpiid as index. Signed-off-by: Len Brown commit 5008740e27540e4069a2f8235f8308aba46036a2 Author: Bob Moore Date: Fri Feb 2 19:48:23 2007 +0300 ACPICA: Update version to 20061215 Signed-off-by: Alexey Starikovskiy Signed-off-by: Len Brown commit d41eb99bac4063aa3fac2dbb8ca01bedd9f0b3bf Author: Bob Moore Date: Fri Feb 2 19:48:23 2007 +0300 ACPICA: Added option to display memory statistics upon termination. Signed-off-by: Alexey Starikovskiy Signed-off-by: Len Brown commit afbb9e659d584bd5bf0604848c91afd5761ed7a1 Author: Valery A. Podrezov Date: Fri Feb 2 19:48:23 2007 +0300 ACPICA: Enhance debugger statistics/memory command. Debugger: Enhanced the Statistics/Memory command to emit the total (maximum) memory used during execution, as well as the maximum memory consumed by each of the various object types. Signed-off-by: Alexey Starikovskiy Signed-off-by: Len Brown commit ea5415785146afe37dd2d1179a6c3a34fd26b52f Author: Bob Moore Date: Fri Feb 2 19:48:23 2007 +0300 ACPICA: Update a comment. Signed-off-by: Alexey Starikovskiy Signed-off-by: Len Brown commit 2e23f8513e9d0cc6d07d36e4555badc2518df433 Author: Bob Moore Date: Fri Feb 2 19:48:23 2007 +0300 ACPICA: Debugger multithreading enhancements. Implemented enhancements to the multithreading support within the debugger to enable better multithreading evaluation of the subsystem. Signed-off-by: Alexey Starikovskiy Signed-off-by: Len Brown commit 59fa85057e12ff135df54266722b2064c418fc05 Author: Bob Moore Date: Fri Feb 2 19:48:23 2007 +0300 ACPICA: Removed all 16-bit support. Support for 16-bit ACPICA has been completely removed since it is no longer necessary and it clutters the code. All 16-bit macros, types, and conditional compiles have been removed, cleaning up and simplifying the code across the entire subsystem. DOS support is no longer needed since the Linux firmware kit is now available. Signed-off-by: Alexey Starikovskiy Signed-off-by: Len Brown commit ff40c8a3f258e9a54b0b94b92d5e2d9d88a39954 Author: Bob Moore Date: Fri Feb 2 19:48:23 2007 +0300 ACPICA: Update version to 20061109 Signed-off-by: Alexey Starikovskiy Signed-off-by: Len Brown commit 1a666f8be16a0e1580e0f37e1322d06affb84e1b Author: Bob Moore Date: Fri Feb 2 19:48:23 2007 +0300 ACPICA: Add include of actables.h Signed-off-by: Alexey Starikovskiy Signed-off-by: Len Brown commit c857303ad496e1f52955e95994a67869882e89f9 Author: Bob Moore Date: Fri Feb 2 19:48:23 2007 +0300 ACPICA: Fail AcpiEnable if ACPI tables not loaded. AcpiEnable will now fail if all of the required ACPI tables are not loaded (FADT, FACS, DSDT). BZ 477 Signed-off-by: Alexey Starikovskiy Signed-off-by: Len Brown commit 987c21a0b0081d480ec3cd04875509cdc10e15e7 Author: Bob Moore Date: Fri Feb 2 19:48:23 2007 +0300 ACPICA: Add ACPI_MAX macro Signed-off-by: Alexey Starikovskiy Signed-off-by: Len Brown commit 7c9626bade13de3f160f0926455328650045d6cd Author: Bob Moore Date: Fri Feb 2 19:48:23 2007 +0300 ACPICA: Ensure that all structures in acobject.h are aligned, via #pragma. Thus, even if the default compiler setting is non-aligned, the header is compiled correctly. Signed-off-by: Alexey Starikovskiy Signed-off-by: Len Brown commit 8876016bb384044a59c1e2ddcad4cf41b06344b9 Author: Bob Moore Date: Fri Feb 2 19:48:22 2007 +0300 ACPICA: Remove global lock handler on AcpiTerminate. Added AcpiEvRemoveGlobalLockHandler Signed-off-by: Alexey Starikovskiy Signed-off-by: Len Brown commit a6823e12ca3f79a8c0f8b2d14976ab2152d117e5 Author: Alexey Starikovskiy Date: Fri Feb 2 19:48:22 2007 +0300 ACPICA: Fixes for load() operator. Optimized the Load operator in the case where the source operand is an operation region. Simply map the operation region memory, instead of performing a bytewise read. Signed-off-by: Bob Moore Signed-off-by: Len Brown commit 428f211297bc95fd41f23830eab4180339020dd0 Author: Alexey Starikovskiy Date: Fri Feb 2 19:48:22 2007 +0300 ACPICA: Miscellaneous table manager updates and optimizations Signed-off-by: Bob Moore Signed-off-by: Len Brown commit 77f6a9fca39f4f19d2d9d5fff1ff5c2ccf20629c Author: Bob Moore Date: Fri Feb 2 19:48:22 2007 +0300 ACPICA: Update debug output routines for data structure changes Signed-off-by: Alexey Starikovskiy Signed-off-by: Len Brown commit 15a58ed12142939d51076380e6e58af477ad96ec Author: Alexey Starikovskiy Date: Fri Feb 2 19:48:22 2007 +0300 ACPICA: Remove duplicate table definitions (non-conflicting), cont Signed-off-by: Len Brown commit 5f3b1a8b6737b09ce5df4ec9fad4ad271aecb5fb Author: Alexey Starikovskiy Date: Fri Feb 2 19:48:22 2007 +0300 ACPICA: Remove duplicate table definitions (non-conflicting) Signed-off-by: Len Brown commit ad363f80c386bc4701b1bc2cdf08ca9b96a9337b Author: Alexey Starikovskiy Date: Fri Feb 2 19:48:22 2007 +0300 ACPICA: Remove duplicate table definitions. Signed-off-by: Len Brown commit cee324b145a1e5488b34191de670e5ed1d346ebb Author: Alexey Starikovskiy Date: Fri Feb 2 19:48:22 2007 +0300 ACPICA: use new ACPI headers. Signed-off-by: Len Brown commit ceb6c46839021d5c7c338d48deac616944660124 Author: Alexey Starikovskiy Date: Fri Feb 2 19:48:22 2007 +0300 ACPICA: Remove duplicate table manager Signed-off-by: Len Brown commit a7a22fa9c368ba22f13b87585052b8cdbbc18f7a Author: Bob Moore Date: Fri Feb 2 19:48:22 2007 +0300 ACPICA: Update version to 20061011 Signed-off-by: Alexey Starikovskiy Signed-off-by: Len Brown commit f1c2b1daf040d2feebfbbd4a0cd80cde856fc031 Author: Bob Moore Date: Fri Feb 2 19:48:22 2007 +0300 ACPICA: Fixes for parameter validation. Extra checks for valid handle/path combinations, BZ 478 Signed-off-by: Alexey Starikovskiy Signed-off-by: Len Brown commit c1014629c0fc563be65e675e72bcc9bd7db50195 Author: Bob Moore Date: Fri Feb 2 19:48:21 2007 +0300 ACPICA: Abort downward walk on temporary node detection. Enhancement to code that ignores temporary namespace nodes Signed-off-by: Alexey Starikovskiy Signed-off-by: Len Brown commit 3effba32069514e56bcb778f90cd34fdbac79a50 Author: Bob Moore Date: Fri Feb 2 19:48:21 2007 +0300 ACPICA: Update comments Signed-off-by: Alexey Starikovskiy Signed-off-by: Len Brown commit ec3153fb0e96988dc7e378b3ab01e05131ba713b Author: Bob Moore Date: Fri Feb 2 19:48:21 2007 +0300 ACPICA: Use manifest constants for parse pass number Signed-off-by: Alexey Starikovskiy Signed-off-by: Len Brown commit b7a69806308600711589e4ca306d18dd029ef0cf Author: Bob Moore Date: Fri Feb 2 19:48:21 2007 +0300 ACPICA: _CID support for PCI Root Bridge detection. Implemented _CID support for PCI Root Bridge detection. If the _HID does not match the predefined root bridge IDs, the _CID list (if present) is now obtained and also checked for an ID match Signed-off-by: Alexey Starikovskiy Signed-off-by: Len Brown commit d1fdda83f7c567f376ddd4305833de09f7919ca9 Author: Bob Moore Date: Fri Feb 2 19:48:21 2007 +0300 ACPICA: Fix race condition with AcpiWalkNamespace. Fixed a problem with a possible race condition between threads executing AcpiWalkNamespace and the AML interpreter. This condition was removed by modifying AcpiWalkNamespace to (by default) ignore all temporary namespace entries created during any concurrent control method execution Signed-off-by: Alexey Starikovskiy Signed-off-by: Len Brown commit 9bc75cff4919f9d947982d805aed89582a20d04d Author: Valery Podrezov Date: Fri Feb 2 19:48:21 2007 +0300 ACPICA: Eliminate control method 2-pass parse/execute. Completed an AML interpreter performance enhancement for control method execution. Previously a 2-pass parse/execution, control methods are now completely parsed and executed in single pass. This improves overall interpreter performance by ~25%, reduces code size, and reduces CPU stack use. Signed-off-by: Bob Moore Signed-off-by: Alexey Starikovskiy Signed-off-by: Len Brown commit 4d0b4af958453afe871022e44abd57fac09baf67 Author: Mikhail Kouzmich Date: Fri Feb 2 19:48:21 2007 +0300 ACPICA: Restructured module into multiple functions. Restructured the AML ParseLoop function, breaking it into several subfunctions in order to reduce CPU stack use and improve maintainability Signed-off-by: Bob Moore Signed-off-by: Alexey Starikovskiy Signed-off-by: Len Brown commit 2b705a8abbce1753c1e5af5ae2ed97e374277654 Author: Bob Moore Date: Fri Feb 2 19:48:21 2007 +0300 ACPICA: Update version to 20060927 Signed-off-by: Alexey Starikovskiy Signed-off-by: Len Brown commit cb219bb6bf6f8cabdf07fbbca8487eee5a91ff05 Author: Bob Moore Date: Fri Feb 2 19:48:21 2007 +0300 ACPICA: Add new subsystem state bit that is set after SubsystemInitialize is called Signed-off-by: Alexey Starikovskiy Signed-off-by: Len Brown commit 65e4b9b05dc10ee84b5c9fc3039fbcc6863743d7 Author: Fiodor Suietov Date: Fri Feb 2 19:48:21 2007 +0300 ACPICA: Fix for possible memory leak and fault. Fixed a possible memory leak and fault in acpi_ex_resolve_object_to_value() during a read from a buffer or region field. (BZ 458) Signed-off-by: Bob Moore Signed-off-by: Alexey Starikovskiy Signed-off-by: Len Brown commit 867c9aec576e0c0d89dfa3922019320619002129 Author: Bob Moore Date: Fri Feb 2 19:48:21 2007 +0300 ACPICA: Update interpreter error paths to always report the error Signed-off-by: Alexey Starikovskiy Signed-off-by: Len Brown commit f70a5e7b6c28e0b08f721204f4b98c5d1cfb44d9 Author: Bob Moore Date: Fri Feb 2 19:48:21 2007 +0300 ACPICA: On AML mutex force-release, set depth to zero (was 1). Signed-off-by: Alexey Starikovskiy Signed-off-by: Len Brown commit 310a7f7fee489b7dadd27b0d8487bd0ce66281e7 Author: Bob Moore Date: Fri Feb 2 19:48:21 2007 +0300 ACPICA: Use faster ByIndex interface to get FACS Signed-off-by: Alexey Starikovskiy Signed-off-by: Len Brown commit d8c71b6d3b21cf21ad775e1cf6da95bf87bd5ad4 Author: Bob Moore Date: Fri Feb 2 19:48:21 2007 +0300 ACPICA: Remove obsolete Flags parameter. Remove flags parameter for acpi_{get,set}_register(). It is no longer necessary now that these functions use a spinlock for mutual exclusion. Signed-off-by: Alexey Starikovskiy Signed-off-by: Len Brown commit 73ca0fbcc25a6080db4136f55dbcd5fe7b33398f Author: Bob Moore Date: Fri Feb 2 19:48:21 2007 +0300 ACPICA: Fix for Global Lock semaphore. Fixed a problem with the Global Lock where the lock could appear to be obtained before it is actually obtained, semaphore created with one unit. Signed-off-by: Alexey Starikovskiy Signed-off-by: Len Brown commit 14d64b5e36a82ef21a51d8a15639d26b75a79499 Author: Bob Moore Date: Fri Feb 2 19:48:21 2007 +0300 ACPICA: Add full table name to disassembler output Signed-off-by: Alexey Starikovskiy Signed-off-by: Len Brown commit 4cdf469090f732ab8a45b2d30b43ec5745699285 Author: Bob Moore Date: Fri Feb 2 19:48:20 2007 +0300 ACPICA: Update version to 20060912 Signed-off-by: Alexey Starikovskiy Signed-off-by: Len Brown commit 977a6226feae3e2c10a4d8227625ff0f04b49239 Author: Bob Moore Date: Fri Feb 2 19:48:20 2007 +0300 ACPICA: Fix trace output name and whitespace Signed-off-by: Alexey Starikovskiy Signed-off-by: Len Brown commit 0fab8997f18f71b2391e72e49d8d31a395352dcc Author: Bob Moore Date: Fri Feb 2 19:48:20 2007 +0300 ACPICA: Fix memory leak in table load error path Signed-off-by: Alexey Starikovskiy Signed-off-by: Len Brown commit 7139284460fba90c4dfcfae76680ad36b45f5982 Author: Bob Moore Date: Fri Feb 2 19:48:20 2007 +0300 ACPICA: New common routine for creating and verifying a local FADT. Signed-off-by: Alexey Starikovskiy Signed-off-by: Len Brown commit 13b572a35ed904ae1e162f8ee89ca7fd6992b44c Author: Bob Moore Date: Fri Feb 2 19:48:20 2007 +0300 ACPICA: Report error if method creates 2 objects with the same name Fixed a regression where an error was no longer emitted if a control method attempts to create 2 objects of the same name. This previously and now returns AE_ALREADY_EXISTS. When this exception occurs, it invokes the mechanism that will dynamically serialize the control method to possible prevent future errors. (BZ 440) Signed-off-by: Alexey Starikovskiy Signed-off-by: Len Brown commit ea5d8ebcbb7ca3bcb35a2133805571295f3f06e8 Author: Bob Moore Date: Fri Feb 2 19:48:20 2007 +0300 ACPICA: FADT verification is now table driven. Disassembler now verifies an input Signed-off-by: Alexey Starikovskiy Signed-off-by: Len Brown commit 775d85b6aa33116da8aacad4168c540ce86a1803 Author: Bob Moore Date: Fri Feb 2 19:48:20 2007 +0300 ACPICA: Add declarations for ASF! sub-tables Signed-off-by: Alexey Starikovskiy Signed-off-by: Len Brown commit cc2a472b8411ce0b71738039e15d45917da30fbe Author: Bob Moore Date: Fri Feb 2 19:48:20 2007 +0300 ACPICA: IsResourceTemplate now returns ACPI_STATUS to differentiate the failure modes. Signed-off-by: Alexey Starikovskiy Signed-off-by: Len Brown commit 15f0c0d1ef7804d098fe3eb0a3f350a490ca269c Author: Bob Moore Date: Fri Feb 2 19:48:20 2007 +0300 ACPICA: Allow type ANY to be the target of the Scope operator. Useful during disassembly where the target may be in a different table and thus the type is unknown. Signed-off-by: Alexey Starikovskiy Signed-off-by: Len Brown commit 77389e1263a7c9bc8040bda726e08b6501ba1c8b Author: Bob Moore Date: Fri Feb 2 19:48:20 2007 +0300 ACPICA: re-factor table init routines for benefit of iASL Required new table init interface since iASL does not use RSDP/XSDT. Signed-off-by: Alexey Starikovskiy Signed-off-by: Len Brown commit 694b0b2092bce3f4610626b04158a6f3a95058e6 Author: Bob Moore Date: Fri Feb 2 19:48:20 2007 +0300 ACPICA: add ASF comment Signed-off-by: Alexey Starikovskiy Signed-off-by: Len Brown commit e56b638bbee3c17b0dee39495bd15afe64db1b94 Author: Bob Moore Date: Fri Feb 2 19:48:20 2007 +0300 ACPICA: Update comments in tbfadt.c Signed-off-by: Alexey Starikovskiy Signed-off-by: Len Brown commit 765ec20180fb70b4ee9d730167b2a0b76879f791 Author: Bob Moore Date: Fri Feb 2 19:48:20 2007 +0300 ACPICA: Delete stale FADT functions outside tbfadt.c. Moved all FADT-related functions to a new file, tbfadt.c. Eliminated the acpi_hw_initialize function - the FADT registers are now validated when the table is loaded. Signed-off-by: Alexey Starikovskiy Signed-off-by: Len Brown commit 1ba753acb372c2955a4843302e92e49ce82e2fea Author: Bob Moore Date: Fri Feb 2 19:48:20 2007 +0300 ACPICA: Re-implement interpreters' "serialized mode" Enhanced the implementation of the interpreters' serialized mode (boot with "acpi_serialize" to set acpi_glb_all_methods_serialized flag.) When this mode is specified, instead of creating a serialization semaphore per control method, the interpreter lock is simply no longer released before a blocking operation during control method execution. This effectively makes the AML Interpreter single-threaded. The overhead of a semaphore per-method is eliminated. Signed-off-by: Alexey Starikovskiy Signed-off-by: Len Brown commit 95befdb398e0112ede80529f6770644ecfa5a82e Author: Bob Moore Date: Fri Feb 2 19:48:20 2007 +0300 ACPICA: Create tbfadt.c to hold all FADT-related functions Signed-off-by: Alexey Starikovskiy Signed-off-by: Len Brown commit b89b71a0019660d73e3c9671205c49e443d7085c Author: Bob Moore Date: Fri Feb 2 19:48:20 2007 +0300 ACPICA: Cleanup of FADT verification function. Removed offset display, not needed. Signed-off-by: Alexey Starikovskiy Signed-off-by: Len Brown commit 0eaa14c02809cc93386b907846da5c024fd73012 Author: Bob Moore Date: Fri Feb 2 19:48:20 2007 +0300 ACPICA: Update version to 20060831 Signed-off-by: Alexey Starikovskiy Signed-off-by: Len Brown commit 84fb2c97731c1631c5548c15f3698ad82c274245 Author: Bob Moore Date: Fri Feb 2 19:48:19 2007 +0300 ACPICA: Split acpi_format_exception into two parts Split acpi_format_exception into two parts. New function is acpi_ut_verify_exception and will be used to verify exception codes returned by user. Signed-off-by: Alexey Starikovskiy Signed-off-by: Len Brown commit 69874165ab953a62f9adb3096ccd84ed2561a602 Author: Alexey Starikovskiy Date: Fri Feb 2 19:48:19 2007 +0300 ACPICA: Store GPE number instead of bitmask Update internal GPE data structure to simplify debug, use gpe_number instead of register bitmask. Signed-off-by: Bob Moore Signed-off-by: Len Brown commit 3d81b236a82a26fa8bdef9096829675d81890dc9 Author: Bob Moore Date: Fri Feb 2 19:48:19 2007 +0300 ACPICA: Fix unalignment in acpi_ut_repair_name Update interface to acpi_ut_repair_name() to avoid alignment issues on IA64 Signed-off-by: Alexey Starikovskiy Signed-off-by: Len Brown commit c5a7156959e89b32260ad6072bbf5077bcdfbeee Author: Bob Moore Date: Fri Feb 2 19:48:19 2007 +0300 ACPICA: Disable all wake GPEs after first one recieved Change for GPE support: when a wake GPE is received, now all wake GPEs are immediately disabled to prevent the waking GPE from firing again, and to prevent other wake GPEs from interrupting the wake process. Signed-off-by: Alexey Starikovskiy Signed-off-by: Len Brown commit fdffb72d23172c91af56983f303d1986994df522 Author: Bob Moore Date: Fri Feb 2 19:48:19 2007 +0300 ACPICA: Add acpi_gpe_count global to track the number of GPE events Signed-off-by: Alexey Starikovskiy Signed-off-by: Len Brown commit 2502fffb1958da66fa50a475081cb6827acdd9f3 Author: Bob Moore Date: Fri Feb 2 19:48:19 2007 +0300 ACPICA: Add support for DMAR table Implement support for ACPI DMAR table (DMA Remapping Table) in header files and disassembler. Signed-off-by: Alexey Starikovskiy Signed-off-by: Len Brown commit ad71860a17ba33eb0e673e9e2cf5ba0d8e3e3fdd Author: Alexey Starikovskiy Date: Fri Feb 2 19:48:19 2007 +0300 ACPICA: minimal patch to integrate new tables into Linux Signed-off-by: Len Brown commit a4bbb810dedaecf74d54b16b6dd3c33e95e1024c Author: Bob Moore Date: Fri Feb 2 19:48:19 2007 +0300 ACPICA: Lint changes Lint changes Move RSDT/XSDT pointer extraction to separate function Warning on 32-bit platforms if XSDT pointers use more than 32 bits. Signed-off-by: Alexey Starikovskiy Signed-off-by: Len Brown commit 4bf273939c99fae5bae399f51c417a552d74b97f Author: Bob Moore Date: Fri Feb 2 19:48:19 2007 +0300 ACPICA: Fix for FADT conversion in 64-bit mode Signed-off-by: Alexey Starikovskiy Signed-off-by: Len Brown commit 8f34890dce60f7df6dd23a0d04977c6572adaab8 Author: Bob Moore Date: Fri Feb 2 19:48:19 2007 +0300 ACPICA: Update comments for individual table fields comments only Signed-off-by: Alexey Starikovskiy Signed-off-by: Len Brown commit c5fc42ac4d4d6d3e3f619290b86890cb3725d2f8 Author: Bob Moore Date: Fri Feb 2 19:48:19 2007 +0300 ACPICA: misc fixes for new Table Manager: Signed-off-by: Alexey Starikovskiy Signed-off-by: Len Brown commit f3d2e7865c816258c699ff965768e46b50d536d3 Author: Bob Moore Date: Fri Feb 2 19:48:18 2007 +0300 ACPICA: Implement simplified Table Manager The Table Manager component has been completely redesigned and reimplemented. The new design is much simpler, and reduces the overall code and data size of the kernel-resident ACPICA by approximately 5%. Also, it is now possible to obtain the ACPI tables very early during kernel initialization, even before dynamic memory management is initialized. Signed-off-by: Alexey Starikovskiy Signed-off-by: Len Brown commit 2e42005bcdb4f63bed1cea7f537a5534d4bd7a57 Author: Bob Moore Date: Fri Feb 2 19:48:18 2007 +0300 ACPICA: Update debug output Signed-off-by: Alexey Starikovskiy Signed-off-by: Len Brown commit f93a21c7184de3db962d01f11eb2ddad5396c824 Author: Bob Moore Date: Fri Feb 2 19:48:18 2007 +0300 ACPICA: Update version to 20060721 Signed-off-by: Alexey Starikovskiy Signed-off-by: Len Brown commit 9c52657a2ac8aac5149e11049497b10918e1f58f Author: Bob Moore Date: Fri Feb 2 19:48:18 2007 +0300 ACPICA: Temporary fix for BankValue parameter Temporary fix for BankValue parameter of a Bank Field to support all constant values, including Zero and One. Must eventually be converted to a full TermArg evaluation. Signed-off-by: Alexey Starikovskiy Signed-off-by: Len Brown commit 6b366e2fe1b68bd9af55caf166eaaf0609ba18a9 Author: Fiodor Suietov Date: Fri Feb 2 19:48:18 2007 +0300 ACPICA: fix for object premature deletion Fix for object premature deletion after CopyObject on Operation Region (BZ 350) Signed-off-by: Bob Moore Signed-off-by: Alexey Starikovskiy Signed-off-by: Len Brown commit 0654a6d3c7a777ddccd35c5bbc5765ffbfe3ea96 Author: Bob Moore Date: Fri Feb 2 19:48:18 2007 +0300 ACPICA: Cast acpi_thread_id to UINT32 for debug output only Signed-off-by: Alexey Starikovskiy Signed-off-by: Len Brown commit a72d47563bce9542b9a83521a4e8175076278ee9 Author: Bob Moore Date: Fri Feb 2 19:48:18 2007 +0300 ACPICA: Release global lock from interrupt handler The ACPI Global Lock interrupt handler no longer queues the execution of a separate thread to signal the global lock semaphore. Instead, the semaphore is signaled directly from the interrupt handler. Signed-off-by: Alexey Starikovskiy Signed-off-by: Len Brown commit c81da66608d65dab04730582dfdfcdcab779e2fe Author: Bob Moore Date: Fri Feb 2 19:48:18 2007 +0300 ACPICA: Delete recursive feature of ACPI Global Lock Completed a new design and implementation for the ACPI Global Lock support. On the OS side, the global lock is now treated as a standard AML mutex. Previously, multiple OS threads could acquire the global lock simultaneously, but this could cause the BIOS to be starved by the lock in cases such as the Embedded Controller driver, where there is a tight coupling between the OS and the BIOS. Signed-off-by: Alexey Starikovskiy Signed-off-by: Len Brown commit 8f9337c88335846b01801b1047a4caf10527a320 Author: Bob Moore Date: Fri Feb 2 19:48:18 2007 +0300 ACPICA: Handle case NumElements > Package length Additional update for NumElements fix. Must handle case where NumElements > Package list length, pad package with null elements. Signed-off-by: Alexey Starikovskiy Signed-off-by: Len Brown commit 24058054d781934df526be114c612cf2b29cf4e7 Author: Bob Moore Date: Fri Feb 2 19:48:18 2007 +0300 ACPICA: Handle mis-matched package length Implement support within the AML interpreter for package objects that contain a mismatch between the AML length and package element count. In this case, the lesser of the two is used. Some BIOS code apparently modifies the package length on the fly, and this change supports this. Provides compatibility with the MS AML interpreter. Signed-off-by: Alexey Starikovskiy Signed-off-by: Len Brown commit c9e3ba2c1d178195e17bb4f1d49c32e0be8dbb16 Author: Bob Moore Date: Fri Feb 2 19:48:18 2007 +0300 ACPICA: Update function header Signed-off-by: Alexey Starikovskiy Signed-off-by: Len Brown commit db50342205deabaff9ce1fbe53d5ba351992fa08 Author: Len Brown Date: Fri Feb 2 21:05:04 2007 -0500 ACPI: prevent build failure when CONFIG_X86_NUMAQ=y ...by disabling CONFIG_ACPI when CONFIG_X86_NUMAQ=y otherwise arch/i386/pci/Makefile forgets that it needs to build acpi.o drivers/built-in.o: In function `acpi_pci_root_add': pci_root.c:(.text+0x45ec4): undefined reference to `pci_acpi_scan_root' Signed-off-by: Len Brown commit 914afcf55ae2621a3c5930e8c458d4ae8636c469 Author: Steve French Date: Fri Feb 2 14:42:12 2007 +0000 [CIFS] Missing free in error path Thanks to jra for pointing this out Signed-off-by: Jeremy Allison Signed-off-by: Steve French commit 9a0c8230e84898ed27f790408805e33fa482b2f9 Author: Steve French Date: Fri Feb 2 04:21:57 2007 +0000 [CIFS] Reduce cifs stack space usage The two cifs functions that used the most stack according to "make checkstack" have been changed to use less stack. Thanks to jra and Shaggy for helpful ideas Signed-off-by: Steve French cc: jra@samba.org cc: shaggy@us.ibm.com commit e051fda4fd14fe878e6d2183b3a4640febe9e9a8 Author: Mark Fasheh Date: Thu Feb 1 11:40:16 2007 -0800 ocfs2: ocfs2_link() journal credits update Commit 592282cf2eaa33409c6511ddd3f3ecaa57daeaaa fixed some missing directory c/mtime updates in part by introducing a dinode update in ocfs2_add_entry(). Unfortunately, ocfs2_link() (which didn't update the directory inode before) is now missing a single journal credit. Fix this by doubling the number of inode updates expected during hard link creation. Signed-off-by: Mark Fasheh commit bfd80223d73f80e1d1c69dace9151756b3ef3b49 Author: Alexey Starikovskiy Date: Wed Jan 31 16:00:20 2007 -0800 ACPI: correct id for fixed buttons ACPI_BUTTON_HID_POWERF was changed, but this change was not propogated to button.c, thus breaking detection of fixed power and sleep buttons. Signed-off-by: Alexey Starikovskiy Signed-off-by: Andrew Morton Signed-off-by: Len Brown commit 030e9d8147491a9d2fe1b67882a3720fcf8b95f7 Author: Steve French Date: Thu Feb 1 04:27:59 2007 +0000 [CIFS] lseek polling returned stale EOF Fixes Samba bug 4362 Discovered by Jeremy Allison Clipper database polls on EOF via lseek and can get stale EOF when file is open on different client Signed-off-by: Jeremy Allison Signed-off-by: Steve French commit fd1b494d4a8147da4517fef72d15116bbb1a2dc7 Author: Luben Tuikov Date: Wed Nov 29 19:45:23 2006 -0800 [SCSI] Fix sense key MEDIUM ERROR processing and retry 1) If the device reports an uncorrectable MEDIUM ERROR, such as SK MEDIUM ERROR, ASC UNRECOVERED READ ERR, AMNF DATA FIELD or RECORD NOT FOUND, then: In scsi_check_sense() return SUCCESS so as to not retry -- the error is uncorrectable -- this speeds up total processing time. Signed-off-by: Luben Tuikov Extracted the MEDIUM ERROR piece and Signed-off-by: James Bottomley commit 7b3b92116387fbea7b3b42553180984a544206d9 Author: Andrew Vasquez Date: Mon Jan 29 10:22:31 2007 -0800 [SCSI] qla2xxx: Update version number to 8.01.07-k5. Signed-off-by: Andrew Vasquez Signed-off-by: James Bottomley commit 03c79cc56e4497cbd09d74a73c1bd0d1d9a8a16c Author: Seokmann Ju Date: Mon Jan 29 10:22:30 2007 -0800 [SCSI] qla2xxx: Remove unnecessary spinlock primitive - mbx_reg_lock. Since, mailbox commands are executed in a synchronous manner, there is no need to have a separate spinlock primitive to protect data/register access shared by callers. Signed-off-by: Seokmann Ju Signed-off-by: Andrew Vasquez Signed-off-by: James Bottomley commit 7c98a046b76a3a858c21b75235bf146493b76e11 Author: Andrew Vasquez Date: Mon Jan 29 10:22:29 2007 -0800 [SCSI] qla2xxx: Fixup printk() with proper new-line character. Signed-off-by: Andrew Vasquez Signed-off-by: James Bottomley commit 26b8d34808598aae760091ae551182de91f3e0ae Author: Andrew Vasquez Date: Mon Jan 29 10:22:28 2007 -0800 [SCSI] qla2xxx: Allow NVRAM updates to immediately go into effect. Signed-off-by: Andrew Vasquez Signed-off-by: James Bottomley commit ffec28a3e959b156ea5906838a8897e27c8bbf22 Author: Andrew Vasquez Date: Mon Jan 29 10:22:27 2007 -0800 [SCSI] qla2xxx: Enable queue-full throttling when UNDERRUN detected. As ISP24xx firmware can return a CS_DATA_UNDERRUN completion status when the storage has returned a SAM_STAT_TASK_SET_FULL scsi-status. Signed-off-by: Andrew Vasquez Signed-off-by: James Bottomley commit 7aef45ac92f49e76d990b51b7ecd714b9a608be1 Author: Andrew Vasquez Date: Mon Jan 29 10:22:26 2007 -0800 [SCSI] qla2xxx: Fail initialization when inconsistent NVRAM detected. Signed-off-by: Andrew Vasquez Signed-off-by: James Bottomley commit 178779a6ca7c23b52d5537b972f2b54c830b4480 Author: Andrew Vasquez Date: Mon Jan 29 10:22:25 2007 -0800 [SCSI] qla2xxx: Check loop-state before reading host statistics. Non-ISP24xx cards must have a loop-id in order to query host statistics. Signed-off-by: Andrew Vasquez Signed-off-by: James Bottomley commit 9bb9fcf2f2b4deeb3ae8a44ed4b8686302297030 Author: Andrew Vasquez Date: Mon Jan 29 10:22:24 2007 -0800 [SCSI] qla2xxx: Refactor set-HBA-model/description code. Limit assignments via qla2x00_model_name[] array to HBA subsystem vendor IDs equal to QLogic. Signed-off-by: Andrew Vasquez Signed-off-by: James Bottomley commit 2603221a285e32a1033dcefa8de38a989a7633e0 Author: Andrew Vasquez Date: Mon Jan 29 10:22:23 2007 -0800 [SCSI] qla2xxx: Set correct cabling state during initialization. Previous work to add asynchronous-scsi-scanning support (d19044c32baadeb80e135027124a9e845c6f057c) caused peculiar semantic changes when no cabling was attached to the HBA whereby unneeded and intrusive 'error-handling' would take place due to the initial link state being unset. Signed-off-by: Andrew Vasquez Signed-off-by: James Bottomley commit b1372bc90ffd5e2d2543e10924c1971a86e25310 Author: Lalit Chandivade Date: Mon Jan 29 10:22:22 2007 -0800 [SCSI] qla2xxx: Perform implicit LOGO during fabric logout request. Similarly to previous LOGO requests on non-24xx hardware, perform an implicit-LOGO as to avoid the potential 2 * R_A_TOV delay which can result during an explicit-LOGO request. Signed-off-by: Andrew Vasquez Signed-off-by: James Bottomley commit 30c4766213aeb684ee477ac7f36703f9134ac7ad Author: Andrew Vasquez Date: Mon Jan 29 10:22:21 2007 -0800 [SCSI] qla2xxx: Export OptionROM boot-codes version information. This includes BIOS, EFI, FCODE and firmware versions. Signed-off-by: Andrew Vasquez Signed-off-by: James Bottomley commit d88021a6710e6ed5d1899ba2e54d4638026e277d Author: Andrew Vasquez Date: Mon Jan 29 10:22:20 2007 -0800 [SCSI] qla2xxx: Handle IRQ-0 assignments by the system. No restriction should be placed on the IRQ number assigned to a given ISP. Original code incorrectly assumed a non-zero IRQ number assignment by the system. In these circumstances the proper freeing of the IRQ (via free_irq()) would not take place. Signed-off-by: Andrew Vasquez Signed-off-by: James Bottomley commit a8488abefaa863a0c3a19888f03395adb3f1c6d2 Author: Andrew Vasquez Date: Mon Jan 29 10:22:19 2007 -0800 [SCSI] qla2xxx: Add MSI-X support. Signed-off-by: Andrew Vasquez Signed-off-by: James Bottomley commit 3c6061236801a376d86ca75fd56d61f964611dd5 Author: Andrew Vasquez Date: Mon Jan 29 10:22:18 2007 -0800 [SCSI] qla2xxx: Correct sector-erase issues while writing flash. Signed-off-by: Andrew Vasquez Signed-off-by: James Bottomley commit 18a1e4c3ee67680287bf3c455b5047421eda3c14 Author: Kim Phillips Date: Tue Jan 30 16:09:13 2007 -0600 [POWERPC] 83xx: Add the mpc8323emds.dts Add the mpc8323emds device tree source (dts) Signed-off-by: Scott Wood Signed-off-by: Kim Phillips Signed-off-by: Kumar Gala commit a33a9641c924efbb01ee27af969f47218cab6bd7 Author: Kim Phillips Date: Tue Jan 30 16:09:20 2007 -0600 [POWERPC] 83xx: Add the mpc832xemds defconfig The defconfig for the 8323EMDS is identical to the 8360E MDS defconfig, except CONFIG_MATH_EMULATION is set, since the 8323 doesn't have a FPU. Signed-off-by: Kim Phillips Signed-off-by: Kumar Gala commit 63bb1bf0400414c0bc51cf276daa0fb5168d1e61 Author: FUJITA Tomonori Date: Sun Jan 28 01:19:41 2007 +0900 [SCSI] libsas: fix task attribute Why TASK_ATTR_HOQ? Signed-off-by: FUJITA Tomonori Signed-off-by: James Bottomley commit 20ce791a0e684dceea2b6804a7c7aaa22e8bfa5c Author: Greg Kroah-Hartman Date: Thu Jan 25 18:15:03 2007 -0800 [SCSI] ipr: remove duplicate device id This patch removes a duplicate device id from the IPR driver. Based on the ipr.h file, I'm not so sure this was intended to be a duplicate, and if so, the .h file should be modified to use the proper sub-device id instead. This was pointed out to me by Kay Sievers Signed-off-by: Greg Kroah-Hartman Acked-by: Brian King Signed-off-by: James Bottomley commit 7ac2735462349ca35d8807d93d66cf4d9ea7b729 Author: Len Brown Date: Tue Jan 30 02:13:44 2007 -0500 ACPI: delete unused acpi_device_get_debug_info() Signed-off-by: Len Brown commit 37cabc81640ddba28a2aa7f0d1286a1012eae248 Author: Robert P. J. Day Date: Sat Jan 27 01:55:18 2007 -0500 ACPI: Correct ACPI_DEBUG_OUTPUT typo -#ifdef CONFIG_ACPI_DEBUG_OUTPUT +#ifdef ACPI_DEBUG_OUTPUT As the former doesn't exist. Signed-off-by: Robert P. J. Day Signed-off-by: Len Brown commit 8def05fa82bfa4af0c8e83a00ff377ddd9074480 Author: Len Brown Date: Tue Jan 30 01:46:43 2007 -0500 asus-laptop: Lindent Signed-off-by: Len Brown commit 304df8f7ef4914ad0886cd1eaa03a12dac583be1 Author: Kumar Gala Date: Tue Jan 30 00:45:56 2007 -0600 [POWERPC] Enable stack debug features on ppc32 Enable stack overflow checking (DEBUG_STACKOVERFLOW) and stack usage (DEBUG_STACK_USAGE) on ppc32. Signed-off-by: Kumar Gala commit 8b857353237c144113b9bbbf9e0236b3f0e7d315 Author: Corentin Chary Date: Fri Jan 26 14:04:58 2007 +0100 asus-laptop: add light sensor support /proc/acpi/asus/lslvl is now /sys/.../asus-laptop/ls_level /proc/acpi/asus/lssw is now /sys/.../asus-laptop/ls_switch nothing else .. Signed-off-by: Corentin Chary Signed-off-by: Len Brown commit 722ad97153015aaf5becba3084565e98e71a2aed Author: Corentin Chary Date: Fri Jan 26 14:04:55 2007 +0100 asus-laptop: add ledd support Ledd is a special led ... /sys/.../asus-laptop/ledd works like /proc/acpi/asus/ledd Signed-off-by: Corentin Chary Signed-off-by: Len Brown commit 78127b4a90469d6973de2837d483f80f3709e6e0 Author: Corentin Chary Date: Fri Jan 26 14:04:49 2007 +0100 asus-laptop: add display switching support /sys/.../asus-laptop/display can now be used to switch displays like the old /proc/acpi/asus/disp does Signed-off-by: Corentin Chary Signed-off-by: Len Brown commit 6b7091e74fe176da97917ca60524e2b3554305f0 Author: Corentin Chary Date: Fri Jan 26 14:04:45 2007 +0100 asus-laptop: add backlight support Adds backlight support using backlight class. We now change the brightness *and toggle the backlight !* via /sys/class/backlight/asus-laptop/. If the user switchs the backlight using the keyboard, asus_hotk_notify looks for ATKD_LCD_OFF and ATKD_LCD_ON events, and stores the right state into hotk->status and bd->props->power . Signed-off-by: Corentin Chary Signed-off-by: Len Brown commit 4564de172dcdce641c0d6c689e79e95b5f6bee2c Author: Corentin Chary Date: Fri Jan 26 14:04:40 2007 +0100 asus-laptop: add bluetooth and wlan support WLED and BLED are not handled like other leds (MLED, etc ..), because sometime they also control the wlan/bluetooth device. If the method for wireless_status is found, it's used to get the status, otherwise hotk->status is used. We also use the HWRS method, which tell if the bluetooth/wlan device is present or not. This patch show why we need a ASUS_SET_DEVICE_ATTR macro : if there is a bluetooth device, /sys/dev.../asus-laptop/bluetooth is usable, else it's not but it's clean. Signed-off-by: Corentin Chary Signed-off-by: Len Brown commit be18cdabb8ed40ff4b8a240e0d6f4e6c30ff866d Author: Corentin Chary Date: Fri Jan 26 14:04:35 2007 +0100 asus-laptop: add led support Add led support, using generic led class. Thomas Tuttle's patch was very usefull. We use hotk->status to store led status because it's very hard to find acpi method to get the right status... To reduce the code, I use a lot of macro (ASUS_LED, ASUS_LED_REGISTER, etc ...), because the code is the same for all leds ... Signed-off-by: Corentin Chary Signed-off-by: Len Brown commit 3b6eb6af5f20471a8cb1b8a3d090401e9a8a2bb8 Author: Li Yang Date: Tue Jan 30 13:33:01 2007 +0800 [POWERPC] 83xx: Fix compiler warnings on 836x and 832x Some prototypes are separated from of_device.h into of_platform.h. Add the new include to fix warning. Signed-off-by: Li Yang Signed-off-by: Kumar Gala commit 85091b718969be7b8e6f795af7e264b8afcd7a6d Author: Corentin Chary Date: Fri Jan 26 14:04:30 2007 +0100 asus-laptop: add base driver Adds the new driver and make ASUS_LAPTOP and ACPI_ASUS incompatible. It may be strange to use ASUS_CREATE_DEVICE_ATTR and ASUS_SET_DEVICE_ATTR now, but these macro will be very usefull in next patchs. ASUS_HANDLE and ASUS_HANDLE_INIT comes from IBM_HANDLE and IBM_HANDLE_INIT, with some modification, and will also be used in next patchs. Signed-off-by: Corentin Chary Signed-off-by: Len Brown commit 5bb730fda8aa4e3f7e94b259c468ecd095f60770 Author: Zhang Rui Date: Mon Jan 29 11:02:42 2007 +0800 ACPI: add ACPICA version in sysfs Add an ACPI attribute to indicate ACPICA version. /proc/acpi/version is deprecated by /sys/module/acpi/parameters/acpica_version. Signed-off-by: Zhang Rui Signed-off-by: Len Brown commit 219c3c8e268b9307eae9fae4c765a0c589b98338 Author: Zhang Rui Date: Mon Jan 29 11:02:38 2007 +0800 ACPI: add ACPI debug attribute in sysfs Add ACPI debug attributes in sysfs. /proc/acpi/debug_layer && debug_level are deprecated by /sys/module/acpi/parameters/debug_layer && debug_level. NOTE: The operations to them are quite the same. E.g. if you want to enable ACPI_DB_INFO, ACPI_DB_WARN, ACPI_DB_ERROR and disable the others, #echo 0x13 >/sys/module/acpi/parameters/debug_level is OK, and a boot option "acpi.debug_level = 0x13" also works. Signed-off-by: Zhang Rui Signed-off-by: Len Brown commit b981c591891dc8885de36498d38fa8d8a5481069 Author: Zhang Rui Date: Mon Jan 29 11:02:30 2007 +0800 ACPI: add a Kconfig option for ACPI procfs interface Add a kconfig option CONFIG_ACPI_PROCFS to make procfs interface a configurable attribute of ACPI. No procfs interface is actually deprecated, and no sysfs interface is added in this patch. CONGI_ACPI_PROCFS is used to mark procfs interface as deprecated once the same function is duplicated in sysfs. Signed-off-by: Zhang Rui Signed-off-by: Len Brown commit 35fcf53870eaa6cc966604a6e36df1c2c1577540 Author: Wim Van Sebroeck Date: Sat Jan 27 22:54:18 2007 +0100 [WATCHDOG] ib700wdt.c - convert to platform_device part 2 Convert the reboot_notifier into the platform_device's shutdown method Signed-off-by: Wim Van Sebroeck commit 745ac1ea6e06125cc1326adbec34d756b25678c6 Author: Wim Van Sebroeck Date: Sat Jan 27 22:39:46 2007 +0100 [WATCHDOG] ib700wdt.c - convert to platform_device Convert the ib700wdt watchdog into a platform_device Signed-off-by: Wim Van Sebroeck commit e42162a46d948769c8b45d25ee81827bc7dac435 Author: Wim Van Sebroeck Date: Sat Jan 27 22:12:54 2007 +0100 [WATCHDOG] ib700wdt.c spinlock/WDIOC_SETOPTIONS changes Add the WDIOC_SETOPTIONS ioctl call. Because of this we move the spinlocking to the different watchdog operations. Signed-off-by: Wim Van Sebroeck commit c9d7710ea2b497784314a916a39d4d390855a557 Author: Wim Van Sebroeck Date: Sat Jan 27 22:07:03 2007 +0100 [WATCHDOG] ib700wdt.c small clean-up's * Fix identation * Add watchdog "mandatory" WDIOC_GETBOOTSTATUS ioctl * On unexpected close -> since this is considered as a write to the watchdog device, make sure we ping a last time. Signed-off-by: Wim Van Sebroeck commit f6e4803969ee93bef6aeeb6aff0f9214547d1bb1 Author: Wim Van Sebroeck Date: Sat Jan 27 21:58:08 2007 +0100 [WATCHDOG] ib700wdt.c clean-up init and exit routines clean-up the init and exit routines so that they use the same sequence. Signed-off-by: Wim Van Sebroeck commit 35d55c943117864b9dff0253eb64672f048ac0f8 Author: Wim Van Sebroeck Date: Sat Jan 27 21:50:53 2007 +0100 [WATCHDOG] ib700_wdt.c stop + set_heartbeat operations move the code to stop the watchdog and the code to set the heartbeat of the watchdog to seperate functions. Signed-off-by: Wim Van Sebroeck commit bffda5c87cf60d27a27f2e862c82c474f8e89767 Author: Wim Van Sebroeck Date: Sat Jan 27 20:54:24 2007 +0100 [WATCHDOG] show default value for nowayout in module parameter change default=CONFIG_WATCHDOG_NOWAYOUT in the module parameter for nowayout by it's real value (0 or 1) by using: __MODULE_STRING(WATCHDOG_NOWAYOUT) Signed-off-by: Wim Van Sebroeck commit f27708fc7523a87e3e69cae5628015961f0d3061 Author: Darrick J. Wong Date: Fri Jan 26 14:08:58 2007 -0800 [SCSI] libsas: Enable automatic spin-up of SAS disks Set allow_restart=1 for all SAS disks so that they are spun up when needed. Signed-off-by: Darrick J. Wong Signed-off-by: James Bottomley commit 111367f5c9a0af0f3a42c39dee7360ca217cba1d Author: Darrick J. Wong Date: Fri Jan 26 14:08:55 2007 -0800 [SCSI] aic94xx: Register eh_device_reset_handler Register libsas's default device reset code with the scsi. Signed-off-by: Darrick J. Wong Signed-off-by: James Bottomley commit ad689233bee854dced741c91aff12a8771a22f6f Author: Darrick J. Wong Date: Fri Jan 26 14:08:52 2007 -0800 [SCSI] libsas: Handle SCSI commands that complete with failure codes This patch moves the code that handles SAS failures out of the main EH function and into a separate function. It also detects commands that have no sas_task (i.e. they completed, but with error data) and sends them into scsi_error for processing. This allows us to handle SCSI errors (and enables auto-spinup as a side effect) instead of dropping them on the floor and falling into an infinite loop. It also requires the implementation of a device reset function, which the SAS failure code has been modified to employ for REQ_DEVICE_RESET. Signed-off-by: Darrick J. Wong Signed-off-by: James Bottomley commit dca84e4694419adf61ad052b1e5a50ac82726597 Author: Darrick J. Wong Date: Fri Jan 26 14:08:49 2007 -0800 [SCSI] scsi_error.c: Export some scsi_eh_* functions Export a couple of functions from scsi_error that are needed to handle failed SCSI commands from the SAS EH. Signed-off-by: Darrick J. Wong make exports GPL and Signed-off-by: James Bottomley commit 21434966462d57145c861b43f6206d945ac57630 Author: Darrick J. Wong Date: Fri Jan 26 14:08:46 2007 -0800 [SCSI] libsas: Check return values of sysfs_create_link Get rid of: "warning: ignoring return value of sysfs_create_link..." Signed-off-by: Darrick J. Wong Signed-off-by: James Bottomley commit 6f63caae2172e97e528b58319480217b0b36542e Author: Darrick J. Wong Date: Fri Jan 26 14:08:43 2007 -0800 [SCSI] libsas: Clean up discovery failure handler code sas_rphy_delete does two things: it removes the sas_rphy from the transport layer and frees the sas_rphy. This can be broken down into two functions, sas_rphy_remove and sas_rphy_free; sas_rphy_remove is of interest to sas_discover_root_expander because it calls functions that require sas_rphy_add as a prerequisite and can fail (namely sas_discover_expander). In that case, sas_discover_root_expander needs to be able to undo the effects of sas_rphy_add yet leave the job of freeing the sas_rphy to the caller of sas_discover_root_expander. This patch also removes some unnecessary code from sas_discover_end_dev to eliminate an unnecessary cycle of sas_notify_lldd_gone/found for SAS devices, thus eliminating a sas_rphy_remove call (and fixing a race condition where a SCSI target scan can come in between the gone and found call). It also moves the sas_rphy_free calls into sas_discover_domain and sas_ex_discover_end_dev to complement the sas_rphy_allocation via sas_get_port_device. This patch does not change the semantics of sas_rphy_delete. Signed-off-by: Darrick J. Wong Signed-off-by: James Bottomley commit 3b6e9fafc40e36f50f0bd0f1ee758eecd79f1098 Author: Darrick J. Wong Date: Fri Jan 26 14:08:41 2007 -0800 [SCSI] libsas: Fix incorrect sas_port deformation in sas_form_port Currently, sas_form_port checks the given asd_sas_phy's sas_phy to see if there's already a port attached. If so, the SAS addresses of the port and the phy are compared to determine if we need to detach from the port because the addresses don't match or if we can stop; the SAS address stored in the sas_port reflects whatever device _was_ attached to the port/phy, and the SAS address stored in the sas_port reflects whatever device we just discovered. As written, the code detaches from the port if the addresses _do_ match, and prints an error if they do _not_ match. I believe this to be incorrect, as it seems more logical to keep the port if the addresses match (i.e. the phy was reset but the device didn't change), and detach it they do not (i.e. the device changed). Signed-off-by: Darrick J. Wong Signed-off-by: James Bottomley commit a5364c5a311f73eade88f37bf5b614797ce30ec9 Author: Mark Haverkamp Date: Wed Jan 24 09:31:30 2007 -0800 [SCSI] NCR_D700: fix compile error Fix a typo in NCR_D700 Signed-off-by Mark Haverkamp Signed-off-by: James Bottomley commit e37ee4bec6c6d6d67aebafeecbbb32aa33d502bc Author: Mark Haverkamp Date: Fri Jan 26 09:23:32 2007 -0800 [SCSI] aacraid: expanded expose physical device code (new) Received from Mark Salyzyn, Take the expose_physicals flag and allow the user to select default (physicals available via /dev/sg), exposed (physicals available via /dev/sd for experimental reasons) and hidden (physicals blocked from all access). This expands the functionality of the previous expose_physicals insmod parameter which was added to support some experimental configurations. Signed-off-by Mark Haverkamp Signed-off-by: James Bottomley commit e8f32de52c0d74d397d21afc655a4e2a7dfe1f98 Author: Mark Haverkamp Date: Tue Jan 23 15:00:30 2007 -0800 [SCSI] aacraid: rework packet support code Received from Mark Salyzyn, Replace all if/else packet formations with platform function calls. This is in recognition of the proliferation of read and write packet types, and in the need to migrate to up-and-coming packets for new products. Signed-off-by Mark Haverkamp Signed-off-by: James Bottomley commit 239eab19559b3d74a029dff3f0c792bc0770a062 Author: Mark Haverkamp Date: Tue Jan 23 15:00:13 2007 -0800 [SCSI] aacraid: Begin adding support for new adapter type Received from Mark Salyzyn, Add in the NEMER/ARK physical register mapping, represented in up and coming products currently under test at Adaptec. Signed-off-by Mark Haverkamp Signed-off-by: James Bottomley commit 28713324a0f3c055186ecec27239673c36ba1de5 Author: Mark Haverkamp Date: Tue Jan 23 14:59:20 2007 -0800 [SCSI] aacraid: rework communication support code Received from Mark Salyzyn, Replace all if/else communication transports with a platform function call. This is in recognition of the need to migrate to up-and-coming transports. Currently the Linux driver does not support two available communication transports provided by our products, these will be added in future patches, and will expand the platform function set. Signed-off-by Mark Haverkamp Signed-off-by: James Bottomley commit 9cd065ab80d6c14c6693a93c8f47ef4cb80e770f Author: Brian King Date: Tue Jan 23 11:25:43 2007 -0600 [SCSI] ipr: Driver version 2.3.1 Bump driver version to 2.3.1. Signed-off-by: Brian King Signed-off-by: James Bottomley commit e619e1a7cbf73c27eacf53856443b1aa67cc1234 Author: Brian King Date: Tue Jan 23 11:25:37 2007 -0600 [SCSI] ipr: PCI error recovery fix Since the pci_block_user_cfg_access API was modified to track block/unblocks, it was discovered that the ipr driver had a path through its code (in PCI error recovery) which would unblock when not previously blocked. Signed-off-by: Brian King Signed-off-by: James Bottomley commit 7dce0e1c84cfa8fb2a4b41877c20def386cade2b Author: Brian King Date: Tue Jan 23 11:25:30 2007 -0600 [SCSI] ipr: Tolerate not finding PCI-X registers Don't fail initialization of an adapter if the PCI-X registers cannot be found since it may be a PCI-E adapter. Signed-off-by: Brian King Signed-off-by: James Bottomley commit 6d84c944fa17cf4e65660df50a0772f8a4836e0b Author: Brian King Date: Tue Jan 23 11:25:23 2007 -0600 [SCSI] ipr: Remove usage of pci driver data Since ipr handles dynamic ids, it must handle driver_data not being set, so remove the current usage of driver_data so it can be used for other things in future patches. Signed-off-by: Brian King Signed-off-by: James Bottomley commit eae225eb5947825bc4e845c33ded9aedd74407cf Author: Eric Moore Date: Fri Jan 19 18:46:17 2007 -0700 [SCSI] fusion: mpi header update - version 1.05.14 Here are the lastest mpi headers for mpt fusion driver, which defines the firmware to driver interface. Signed-off-by: Eric Moore Signed-off-by: James Bottomley commit 86b9c4c16a1589d05959af2d96d52a4352c6306e Author: Alexis Bruemmer Date: Tue Jan 16 15:36:12 2007 -0800 [SCSI] aic94xx: fix typos and update verison number fix typos and bump version number Signed-off-by: Darrick J. Wong Acked-by: Alexis Bruemmer Signed-off-by: James Bottomley commit 7220c0177b45600eef2cfd3e5e57ab5b96f3222c Author: Dave Kleikamp Date: Fri Jan 26 10:14:36 2007 -0600 JFS: Remove incorrect kgdb define jfs_debug.h uses an incorrect CONFIG_KERNEL_ASSERT ifdef to redefine the assert macro for kgdb use. I believe the code worked a long time ago, but today it's not a valid config option. Since I'm not aware of anybody interested in debugging jfs with kgdb, it should just be removed. Thanks to Robert P. J. Day for reporting this. Signed-off-by: Dave Kleikamp commit 8943212c97cc56d4dcc853a097740e327fe8a6fe Author: Kumar Gala Date: Fri Jan 26 01:52:27 2007 -0600 [POWERPC] Remove fastcall function attribute fastcall is an x86 specific function attribute and has no business in ppc code Signed-off-by: Kumar Gala commit 126186a055d965d5a7b1ab560e343ef70694f349 Author: Kumar Gala Date: Fri Jan 26 01:45:32 2007 -0600 [POWERPC] 83xx: Return a point to the struct ipic from ipic_init() It's useful to have access to struct ipic handle that just got created in ipic_init(). For example, if we want to setup an external IRQ with out a device node we need access ipic->irqhost to create the virtual to HW IRQ mapping and to set the IRQ sense. With this we can mimic the old sense array concept that existed in arch/ppc. Signed-off-by: Kumar Gala commit fb5c3e1b6d304bcf5f8d697471e36f2fa8d53f1c Author: Bjorn Helgaas Date: Wed Jan 24 00:49:19 2007 -0800 PNPACPI: remove EXPERIMENTAL dependency PNPACPI is pretty widely used and seems fairly stable, so remove the dependency on EXPERIMENTAL. Signed-off-by: Bjorn Helgaas Cc: Adam Belay Signed-off-by: Andrew Morton Signed-off-by: Len Brown commit 5eca338fb510af78eee5372ff6a3525768ab913f Author: Bjorn Helgaas Date: Thu Jan 18 16:44:48 2007 -0700 ACPI: remove motherboard driver (redundant with PNP system driver) The PNP system board driver (drivers/pnp/system.c) contains all the same functionality, so we don't need the ACPI version. Previously, a motherboard device would be claimed by *both* the ACPI and PNP drivers, resulting in stuff like this in /proc/ioports: 1200-121f : motherboard <-- from drivers/acpi/motherboard.c 1200-121f : pnp 00:0d <-- from drivers/pnp/system.c Make sure to enable CONFIG_PNP (and CONFIG_PNPACPI) to include the PNP system board driver. Signed-off-by: Bjorn Helgaas Signed-off-by: Len Brown commit 10fccf5fda7529258325769e9da136064b481aab Author: Bjorn Helgaas Date: Thu Jan 18 16:44:24 2007 -0700 i386: turn on CONFIG_PNP in defconfig I'm trying to remove drivers/acpi/motherboard.c, which is mostly redundant with drivers/pnp/system.c. So make sure that we include the PNP driver in the default config. Most distros enable this already. Turning on CONFIG_PNP also causes the following options to be enabled: CONFIG_PNPACPI CONFIG_SERIAL_8250_PNP CONFIG_SERIAL_8250_PNP causes legacy serial ports to be discovered twice, which is ugly but harmless: serial8250: ttyS0 at I/O 0x3f8 (irq = 4) is a 16550A 00:07: ttyS0 at I/O 0x3f8 (irq = 4) is a 16550A Signed-off-by: Bjorn Helgaas Signed-off-by: Len Brown commit 5859554c3ad31b722f0b5a1d3a40e19d8ccedd0b Author: Bjorn Helgaas Date: Thu Jan 18 16:43:46 2007 -0700 PNP: system.c whitespace cleanup No functional change. Signed-off-by: Bjorn Helgaas Signed-off-by: Len Brown commit a8c78f7fb1571764f48b8af5459abdd2c66a765f Author: Bjorn Helgaas Date: Thu Jan 18 16:43:27 2007 -0700 PNP: reserve system board iomem resources as well as ioport resources Most x86 boxes have no iomem system board resources, but some ia64 boxes do. Signed-off-by: Bjorn Helgaas Signed-off-by: Len Brown commit 9a47cdb1bb85e7944fb7419e4078c46516ef7335 Author: Bjorn Helgaas Date: Thu Jan 18 16:42:55 2007 -0700 ACPI: move FADT resource reservations from motherboard driver to osl Resources described by the FADT aren't really a good fit for the ACPI motherboard driver. The motherboard driver cares about PNP0C01 and PNP0C02 devices and their resources. The FADT describes some resources used by the ACPI core. Often, they are also described by by the _CRS of a motherboard device, but I think it's better to reserve them specifically in the ACPI osl.c because (a) the motherboard driver is optional and ACPI uses the resources even if the driver is absent, and (b) I want to remove the ACPI motherboard driver because it's mostly redundant with the PNP system.c driver. Signed-off-by: Bjorn Helgaas Signed-off-by: Len Brown commit e60bd7f14dbb6239d07676be420a21f8a36d014f Author: Kumar Gala Date: Fri Jan 26 00:41:57 2007 -0600 [POWERPC] 83xx: Make platform *_init_IRQ() static Make the various 83xx *_init_IRQ() functions static Signed-off-by: Kumar Gala commit c75f902b93724ab9ba161f7dfab0fd09c7a8854d Author: Kumar Gala Date: Fri Jan 26 00:37:11 2007 -0600 [POWERPC] 83xx: Don't call ioremap in the reset function It's possibly that we get an reset requestion when interrupts are disabled. (For example an oops in an interrupt handler). Therefor, we can't call ioremap in the reset function. Moving the ioremap of the registers we need access to an arch_initcall helps the problem. However we still have a window between boot and the arch_initcall in which the register pointer will not be setup and thus we spin if the reset function is called. If one needs to ensure even this case is covered, look at use of the watchdog provided on 83xx to reset the processor. Signed-off-by: Kumar Gala commit 4d52719a767455d319263d598e0f59e027895e00 Author: Kumar Gala Date: Fri Jan 26 00:23:34 2007 -0600 [POWERPC] 83xx: Fix Kconfig to only enable FP math emulation for the MPC832x Updated MATH_EMULATION depends to be on PPC_MPC832x instead of PPC_83xx. Only the the MPC832x has no floating point unit in the core. Updated the other 83xx defconfigs that got math emulation turned on incorrectly. Signed-off-by: Kumar Gala commit 8b629a1f01b2c975074c51c752915ad50ee4e5fc Author: Ishizaki Kou Date: Fri Jan 12 10:12:06 2007 +0900 [POWERPC] Celleb: setup sio in SCC This patch setup serial interfaces in SCC to work with serial_txx9 driver. Signed-off-by: Kou Ishizaki Acked-by: Benjamin Herrenschmidt Signed-off-by: Paul Mackerras commit 551a3d87856c67248f9e467a7984865eee4bb0b1 Author: Ishizaki Kou Date: Fri Jan 12 10:03:28 2007 +0900 [POWERPC] Celleb: Support PCI bus and base of I/O This patch includes support for pci buses, base of Celleb specific devices, and etc. It works on of_platform bus. Signed-off-by: Kou Ishizaki Acked-by: Benjamin Herrenschmidt Signed-off-by: Paul Mackerras commit 983e3f6027374bc8b63f05422d281e0d1f2c37f7 Author: Ishizaki Kou Date: Fri Jan 12 10:02:36 2007 +0900 [POWERPC] Celleb: Cell SCC definitions Adds Cell SCC(Super Companion Chip) definitions. Signed-off-by: Kou Ishizaki Acked-by: Benjamin Herrenschmidt Signed-off-by: Paul Mackerras commit ca58b8eb93904453025cab7e01dcad957cf9e25b Author: Ishizaki Kou Date: Fri Jan 12 09:59:41 2007 +0900 [POWERPC] Celleb: hypervisor call numbers This patch creates Celleb platform dependent file to define Beat hypervisor call numbers. Signed-off-by: Kou Ishizaki Acked-by: Arnd Bergmann Signed-off-by: Paul Mackerras commit acc900ef5b6400747e3bafe0017e725b2ba641b8 Author: Ishizaki Kou Date: Fri Jan 12 09:58:39 2007 +0900 [POWERPC] Add IRQ remapping hook This patch adds irq remapping hook. On interrupt mechanism on Beat, when an irq outlet which has an id which is formerly used is created, remapping the irq is required. Signed-off-by: Kou Ishizaki Acked-by: Benjamin Herrenschmidt Signed-off-by: Paul Mackerras commit 5b7c726ff0e8c03bc19bf0d5114d3598efa2fbf2 Author: Ishizaki Kou Date: Fri Jan 12 09:57:37 2007 +0900 [POWERPC] Add a field for each specific bus to struct pci_controller Struct pci_controller doesn't prepare for the dependent data of each specific bus. This patch adds private member to struct pci_controller. Signed-off-by: Kou Ishizaki Acked-by: Arnd Bergmann Signed-off-by: Paul Mackerras commit ef66f796751a214dc8fadaef2f068c3baa8969fa Author: Ishizaki Kou Date: Fri Jan 12 09:56:44 2007 +0900 [POWERPC] Fix oprofile support on Cell LPAR Op_model_cell supports native Cell. By returning -EINVAL, oprofile uses timer interrupt on Cell LPAR. Signed-off-by: Kou Ishizaki Acked-by: Arnd Bergmann Signed-off-by: Paul Mackerras commit d649bd7b766b9c15c9f5f2f6d8ae0e57303285d0 Author: Ishizaki Kou Date: Fri Jan 12 09:54:39 2007 +0900 [POWERPC] TLB insertion cleanup This patch changes handling return value of ppc_md.hpte_insert() into the same way as __hash_page_*(). Signed-off-by: Kou Ishizaki Acked-by: Benjamin Herrenschmidt Signed-off-by: Paul Mackerras commit 3650cfe2e51432030e469afd75a429c199c4e42f Author: Ishizaki Kou Date: Fri Jan 12 09:52:41 2007 +0900 [POWERPC] spufs: Add SPU register lock spu->register_lock should be held before accessing registers. Signed-off-by: Kou Ishizaki Acked-by: Arnd Bergmann Signed-off-by: Paul Mackerras commit c53653130f2868e44c6e8346d110d27d39e7d07b Author: Adrian Bunk Date: Sun Jan 14 10:15:00 2007 +0100 [POWERPC] Remove the broken Gemini support Signed-off-by: Adrian Bunk Signed-off-by: Paul Mackerras commit cfcd1705b61ecce1ab102b9593cf733fef314a19 Author: David Woodhouse Date: Sun Jan 14 09:38:18 2007 +0800 [POWERPC] Mask 32-bit system call arguments to 32 bits on PPC64 in audit code The system call entry code will clear the high bits of argument registers before invoking the system call; don't report whatever noise happens to be in the high bits of the register before that happens. Signed-off-by: David Woodhouse Signed-off-by: Paul Mackerras commit 0e47e3cca100e7c8e8124378e4e44969c2e042fd Author: Paul Gortmaker Date: Tue Jan 9 16:50:10 2007 -0500 [POWERPC] Select DEFAULT_UIMAGE for HPC-NET/8641 I suspect this was meant to be added like it was to a whole slew of other u-boot based boards, but probably just fell through the cracks. Add "select DEFAULT_UIMAGE" for the 8641/HPC-NET. Signed-off-by: Paul Gortmaker Signed-off-by: Paul Mackerras commit 0bcace3b8b07a54ae17b969fa7bbbd4c91f3372c Author: Olaf Hering Date: Thu Jan 4 18:31:55 2007 +0100 [POWERPC] Update fixup_winbond_82c105 comment Note all POWER3/POWER4 systems where fixup_winbond_82c105 will run. Signed-off-by: Olaf Hering Signed-off-by: Paul Mackerras commit f1f003330b4489f0e6502e1315bf9d764ed5f757 Author: Nathan Lynch Date: Wed Jan 3 12:56:28 2007 -0600 [POWERPC] maple: improve CPC9x5 host bridge detection Identify CPC9x5 PCI Express, AGP, and HT host bridges using device_type and compatible properties, which is a more flexible method than using the name property (which can differ between firmwares and models). Signed-off-by: Nathan Lynch Signed-off-by: Paul Mackerras commit 9a3d6458e9dded0a060115b446531cfc77083ebb Author: Simon Vallet Date: Wed Jan 3 07:49:56 2007 +0100 [POWERPC] Add support for R_PPC_ADDR16_HI relocations apply_relocate_add() does not support R_PPC_ADDR16_HI relocations, which prevents some non gcc-built modules to be loaded. Signed-off-by: Simon Vallet Signed-off-by: Paul Mackerras commit 06c3147564cc65f0a5eac8af2b1834a996933e74 Author: Mariusz Kozlowski Date: Tue Jan 2 12:36:20 2007 +0100 [POWERPC] arch/powerpc/sysdev/cpm2_pic.c of_node_get cleanup Remove redundant argument check for of_node_get(). It's ok to remove 'node' check because in real life cpm2_pic_init() never gets called with node == NULL. Signed-off-by: Mariusz Kozlowski Signed-off-by: Paul Mackerras commit a15d5eaa7799cce9cfeec4637db18863e1a89e34 Author: Mariusz Kozlowski Date: Tue Jan 2 13:07:16 2007 +0100 [POWERPC] arch/powerpc/sysdev/qe_lib of_node_get cleanup No need for ?: as of_node_get() can handle NULL argument. Signed-off-by: Mariusz Kozlowski arch/powerpc/sysdev/qe_lib/qe_ic.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) Signed-off-by: Paul Mackerras commit c3bfc3a8dd337e41cf7b64f815e37f6e2cfbfcdc Author: Mariusz Kozlowski Date: Tue Jan 2 12:52:47 2007 +0100 [POWERPC] arch/powerpc/sysdev/mpic.c of_node_get cleanup No need for ?: because of_node_get() can handle NULL argument. Signed-off-by: Mariusz Kozlowski Signed-off-by: Paul Mackerras commit af337c096ca47ac1a776e6f1ea2cde9a85d0e60b Author: Mariusz Kozlowski Date: Tue Jan 2 12:50:20 2007 +0100 [POWERPC] arch/powerpc/sysdev/ipic.c of_node_get cleanup No need for ?: because of_node_get() can handle NULL argument. Signed-off-by: Mariusz Kozlowski Signed-off-by: Paul Mackerras commit 6690faeb3537fe34950bdc3e10fa14ce4102c92f Author: Mariusz Kozlowski Date: Tue Jan 2 12:38:36 2007 +0100 [POWERPC] arch/powerpc/kernel/vio.c of_node_put cleanup Remove redundant argument check for of_node_put(). Signed-off-by: Mariusz Kozlowski Signed-off-by: Paul Mackerras commit b1374051433cc252540058e8a90107c90fa23eb4 Author: Mariusz Kozlowski Date: Tue Jan 2 12:31:47 2007 +0100 [POWERPC] arch/ppc/kernel/prom.c of_node_(get|put) cleanup Remove redundant argument checks for of_node_get() and of_node_put(). Signed-off-by: Mariusz Kozlowski Signed-off-by: Paul Mackerras commit a2894cfb3a6d60980ba85181e31ccc079807e92b Author: Michal Ostrowski Date: Wed Dec 27 22:14:43 2006 -0600 [POWERPC] Do not write virq back to PCI config space - Drivers will not rely on the PCI config space value, as they've already been conditioned to rely on the irq field in "struct pci_dev". - The virq value may not be < 256 as it has been remapped. - The PCI config space should reflect the hardware configuration, which is not being changed. We are only creating a virtual irq mapping that exists in the kernel only. One would never expect the PCI hardware to generate the "virq" interrupt. Signed-off-by: Michal Ostrowski Acked-by: Benjamin Herrenschmidt Signed-off-by: Paul Mackerras commit 7e60d1b427c51cf2525e5d736a71780978cfb828 Author: Anton Blanchard Date: Wed Dec 20 15:58:52 2006 +1100 [POWERPC] Move ELF_ET_DYN_BASE up to 512MB point I often test new versions of glibc by doing: LD_LIBRARY_PATH=/XXX/lib /XXX/lib/ld.so.1 One test case ended up SEGV'ing. Upon closer inspection ld.so was loaded at 0x8000000 (128MB) with the heap right after it. Since we normally link binaries at 0x10000000 (256MB) we only had about 128MB of space for the heap: 00100000-00103000 r-xp 00100000 00:00 0 [vdso] 08000000-0801e000 r-xp 00000000 00:01 33079 /lib/ld-2.5.so 0802d000-0802f000 rwxp 0001d000 00:01 33079 /lib/ld-2.5.so 0802f000-08050000 rwxp 0802f000 00:00 0 [heap] 0fe91000-0ffd9000 r-xp 00000000 00:01 33082 /lib/libc-2.5.so 0ffd9000-0ffe8000 ---p 00148000 00:01 33082 /lib/libc-2.5.so 0ffe8000-0ffea000 r--p 00147000 00:01 33082 /lib/libc-2.5.so 0ffea000-0ffed000 rwxp 00149000 00:01 33082 /lib/libc-2.5.so 10000000-10004000 r-xp 00000000 00:01 76 /bin/sleep 10013000-10014000 rwxp 00003000 00:01 76 /bin/sleep ffb41000-ffb56000 rw-p ffb41000 00:00 0 [stack] One way to fix this is move ELF_ET_DYN_BASE from 0x08000000 to 0x20000000. This allows 128MB for the binary (hopefully enough for even the most crazy c++ apps), and with our current layout we will grow the heap up and the stack down, allowing potentially gigabytes of heap: 00100000-00103000 r-xp 00100000 00:00 0 [vdso] 0fe8a000-0ffd3000 r-xp 00000000 00:01 3350 /lib/tls/libc-2.3.6.so 0ffd3000-0ffe3000 ---p 00149000 00:01 3350 /lib/tls/libc-2.3.6.so 0ffe3000-0ffea000 r--p 00149000 00:01 3350 /lib/tls/libc-2.3.6.so 0ffea000-0ffee000 rwxp 00150000 00:01 3350 /lib/tls/libc-2.3.6.so 10000000-10004000 r-xp 00000000 00:01 76 /bin/sleep 10013000-10014000 rwxp 00003000 00:01 76 /bin/sleep 20000000-20018000 r-xp 00000000 00:01 3478 /lib/ld-2.3.6.so 20028000-20029000 r--p 00018000 00:01 3478 /lib/ld-2.3.6.so 20029000-2002a000 rwxp 00019000 00:01 3478 /lib/ld-2.3.6.so 2002a000-2004b000 rwxp 2002a000 00:00 0 [heap] ffd67000-ffd7c000 rw-p ffd67000 00:00 0 [stack] Signed-off-by: Anton Blanchard Signed-off-by: Paul Mackerras commit a885902de3394ef18ca415f9175da5d8a8406cca Author: Linas Vepstas Date: Tue Dec 19 13:06:17 2006 -0600 [POWERPC] Clarify EEH error message Clarify error message re EEH permanent failure. Signed-off-by: Linas Vepstas Signed-off-by: Paul Mackerras commit 60bccbed6f53c953c62bdc2ac699395a13b6eecc Author: Akinobu Mita Date: Tue Dec 19 17:35:49 2006 +0900 [POWERPC] Use is_init() instead of pid==1 Use is_init() rather than hard coded pid comparison. Cc: Anton Blanchard Signed-off-by: Akinobu Mita Signed-off-by: Paul Mackerras commit 2c8dc071517ec2843869024dc82be2e246f41064 Author: David Brownell Date: Thu Jan 18 00:45:48 2007 -0500 Input: ads7846 - be more compatible with the hwmon framework - Hook up to hwmon * show sensor attributes only if hwmon is present * ... and the board's reference voltage is known * otherwise be just a touchscreen - Report voltages per hwmon convention * measure in millivolts * voltages are named in[0-8]_input (ugh) * for 7846 chips, properly range-adjust vBATT/in1_input Battery measurements help during recharge monitoring. On OSK/Mistral, the measured voltage agreed with a multimeter to several decimal places. Signed-off-by: David Brownell Signed-off-by: Dmitry Torokhov commit 15e3589e59c35ed33823dda3d38ad171222b83b4 Author: Imre Deak Date: Thu Jan 18 00:45:43 2007 -0500 Input: ads7846 - detect pen up from GPIO state We can't depend on the pressure value to determine when the pen was lifted, so use the GPIO line state instead. This also helps with chips (like ads7843) that don't have pressure sensors. Signed-off-by: Imre Deak Signed-off-by: Juha Yrjola Signed-off-by: David Brownell Signed-off-by: Dmitry Torokhov commit 7937e86a70235e1584486654687dc9908a11e00a Author: Imre Deak Date: Thu Jan 18 00:45:38 2007 -0500 Input: ads7846 - select correct SPI mode Talk to ADS7846 chip using SPI mode 1, which is what the chip supports: writes on falling clock edge, reads on rising. Signed-off-by: Imre Deak Signed-off-by: Tony Lindgren Signed-off-by: David Brownell Signed-off-by: Dmitry Torokhov commit 1936d590a9b72ff6a7a0c826bc613e4757cde1c9 Author: Imre Deak Date: Thu Jan 18 00:45:31 2007 -0500 Input: ads7846 - switch to using hrtimer Use hrtimer instead of the normal timer, since it provides better sampling resolution. This will: - avoid a problem where we have a 1 jiffy poll period and dynamic tick on - utilize high resolution HW clocks when they are added to the hrtimer framework Signed-off-by: Imre Deak Signed-off-by: Juha Yrjola Signed-off-by: David Brownell Signed-off-by: Dmitry Torokhov commit de2defd96d7d92fe8b5f9cf2bfd385d8d4819923 Author: Imre Deak Date: Thu Jan 18 00:45:21 2007 -0500 Input: ads7846 - optionally leave Vref on during differential measurements On some LCDs leaving the Vref on provides much better readings. Signed-off-by: Jarkko Oikarinen Signed-off-by: Imre Deak Signed-off-by: Juha Yrjola Signed-off-by: David Brownell Signed-off-by: Dmitry Torokhov commit da970e69efb9fd0be0c23ace5bde42d4caf17b40 Author: Imre Deak Date: Thu Jan 18 00:44:41 2007 -0500 Input: ads7846 - pluggable filtering logic Some LCDs like the LS041Y3 require a customized filtering logic for reliable readings, so make the filtering function replacable through platform specific hooks. Signed-off-by: Imre Deak Signed-off-by: Juha Yrjola Signed-off-by: David Brownell Signed-off-by: Dmitry Torokhov commit 78a56aab11234e53b7e94e5a255cc3d27ab0a62b Author: Phil Blundell Date: Thu Jan 18 00:44:09 2007 -0500 Input: gpio-keys - keyboard driver for GPIO buttons This is an interrupt-driven keyboard driver for simple buttons connected directly to CPU GPIO lines of embedded ARM systems. It supports pxa architectures and is used by a number of PDAs and PocketPC phones in the handhelds.org kernel. Support for other architectures, such as sa11xx and sc2410, will be added once generic GPIO API is available. Signed-off-by: Paul Sokolovsky Signed-off-by: Philipp Zabel Signed-off-by: Dmitry Torokhov commit 285b0b62bc8f1a3cb18ce3f2d9806f1d99736784 Author: Jiri Slaby Date: Thu Jan 18 00:43:41 2007 -0500 Input: hid-ff - add support for Logitech Momo racing wheel Add support for Logitech Momo racing wheel (046d:ca03) to hid force feedback. Signed-off-by: Jiri Slaby Signed-off-by: Andrew Morton Signed-off-by: Dmitry Torokhov commit 19f3c3e37314a234998fd75f5ea9388dfb6ab00a Author: Dmitry Torokhov Date: Thu Jan 18 00:42:31 2007 -0500 Input: i8042 - really suppress ACK/NAK during panic blink On some boxes panic blink procedure manages to send both bytes to keyboard contoller before getting first ACK so we need to make i8042_suppress_kbd_ack a counter instead of boolean. Signed-off-by: Dmitry Torokhov commit 4aa0d230c2cfc1ac4bcf7c5466f9943cf14233a9 Author: Dave Kleikamp Date: Wed Jan 17 21:18:35 2007 -0600 JFS: call io_schedule() instead of schedule() to avoid deadlock The introduction of Jens Axboe's explicit i/o plugging patches introduced a deadlock in jfs. This was caused by the process initiating I/O not unplugging the queue before waiting on the commit thread. The commit thread itself was waiting for that I/O to complete. Calling io_schedule() rather than schedule() unplugs the I/O queue avoiding the deadlock, and it appears to be the right function to call in any case. Signed-off-by: Dave Kleikamp commit d91a0078476ca536d76419f3b53196873b2931bc Author: Justin Chen Date: Wed Dec 6 10:17:10 2006 -0700 ACPI: Optimize acpi_get_pci_rootbridge_handle() to boot faster Move acpi_get_pci_rootbridge_handle() from glue.c to pci_root.c and get the root bridge ACPI handles by searching the &acpi_pci_roots list instead of walking through the ACPI name space. This significantly reduces boot time on large I/O systems. Signed-off-by: Justin Chen Signed-off-by: Bjorn Helgaas Signed-off-by: Len Brown commit 02cd743bb3a37f27681c487608fb819493fa4010 Author: Darrick J. Wong Date: Thu Jan 11 14:15:46 2007 -0800 [SCSI] libsas: Start I_T recovery if ABORT TASK fails The EH should fall into I_T recovery (and potentially stronger remedies) if ABORT TASK fails. Signed-off-by: Alexis Bruemmer Signed-off-by: James Bottomley commit 6b0efb8516a5298e12033df61f9e0c376a306adb Author: Darrick J. Wong Date: Thu Jan 11 14:15:43 2007 -0800 [SCSI] libsas: Add SAS_HA state flags to avoid queueing events while unloading Track sas_ha_struct state so that we ignore events that come in while we're shutting things down. Signed-off-by: Malahal Naineni Signed-off-by: James Bottomley commit 980fa2f9d64b9be96107c89e165953ace311af54 Author: Darrick J. Wong Date: Thu Jan 11 14:15:40 2007 -0800 [SCSI] libsas: phy port lock needs irq spinlocks Convert the phy port locks to use irq spinlocks. Signed-off-by: Darrick J. Wong Signed-off-by: James Bottomley commit e7571c152dea576f8c80ca240befc93d4f16551d Author: Darrick J. Wong Date: Thu Jan 11 14:15:38 2007 -0800 [SCSI] aic94xx: Scan SAS devices asynchronously Add the necessary hooks to the aic94xx driver to support the asynchronous SCSI device scan infrastructure. Signed-off-by: Darrick J. Wong Signed-off-by: Matthew Wilcox Signed-off-by: James Bottomley commit fe3b5bfe73ace420709f0cfb198b0ffc704bd38b Author: Darrick J. Wong Date: Thu Jan 11 14:15:35 2007 -0800 [SCSI] libsas: sysfs phy control attributes should not be S_IWUGO Allowing the phy reset controls to be world-triggerable does not seem like a terribly good idea because SAS devices can be disrupted (and ATA devices are really disrupted) by a phy reset. By default only root should be able to do things like that. Signed-off-by: Darrick J. Wong Signed-off-by: James Bottomley commit 57ba07dc54b7657e69fe8ac42d83df21e415c85b Author: Darrick J. Wong Date: Thu Jan 11 14:15:32 2007 -0800 [SCSI] aic94xx: Lock DDB read/write accesses Extend the use of the DDB lock to include all DDB accesses, because DDB updates now occur from multiple threads. This fixes the SMP timeout problems that we were occasionally seeing with a x260, because the controller got confused when the DDBs got corrupted. Signed-off-by: Darrick J. Wong Signed-off-by: James Bottomley commit 3b709df5f7c83b6b0907217a248a1414a37ffcb6 Author: Darrick J. Wong Date: Thu Jan 11 14:15:29 2007 -0800 [SCSI] aic94xx: Fix DDB and SCB initialization Ed Chim of Adaptec informs us that the DDB registers need to be zeroed at initialization time and that some SCB initializations need to happen even if we don't use the SCB. Signed-off-by: Darrick J. Wong Signed-off-by: James Bottomley commit bf2a1928f3e5d44934e974940a8260a57fcc8a58 Author: Darrick J. Wong Date: Thu Jan 11 14:15:26 2007 -0800 [SCSI] aic94xx: Match request_firmware with release_firmware The vmalloc() blob holding the sequencer firmware wasn't being released at module unload time, which resulted in a memory leak. Signed-off-by: Alexis Bruemmer Acked-by: Darrick J. Wong Signed-off-by: James Bottomley commit 3cd041fb7f50f4cee3bc3a2b0ce02b1562894894 Author: Darrick J. Wong Date: Thu Jan 11 14:15:23 2007 -0800 [SCSI] aic94xx: Remove workqueue code from REQ_TASK_ABORT/REQ_DEVICE_RESET code Now that task aborts and device port resets are done by the EH, we can remove all the code that set up workqueues and such and simply call sas_task_abort and let libsas figure things out. Signed-off-by: James Bottomley commit 396819fba821ad56f1b90090d256f0ab726c89c5 Author: Darrick J. Wong Date: Thu Jan 11 14:15:20 2007 -0800 [SCSI] libsas: Delay issuing ABORT TASK TMF until the error handler sas_task_abort() should simply abort the upper-level SCSI command and wait until the error handler to send the actual ABORT TASK command. By deferring things to the EH we simplify the concurrency coordination and eliminate some race conditions. Note that sas_task_abort has a few hooks to handle libsas internal commands properly too. Also rename do_sas_task_abort to __sas_task_abort just in case we really want to abort the task *right now* and we don't have a scsi_cmnd attached to the command. This is a hook for libata internal commands to abort. Signed-off-by: Darrick J. Wong Signed-off-by: James Bottomley commit 3ebf6922b0833807e54c73f4794c74baf9945fc8 Author: Darrick J. Wong Date: Thu Jan 11 14:15:17 2007 -0800 [SCSI] libsas: Enable the EH strategy handler to reset a phy after a command When a SAS LLDD needs to request a device port reset, it needs to have all commands aborted before it can reset the port. Since commands are put on the EH's list in the order that they were queued, the LLDD can set a "need reset" flag in the last task to be aborted so that the EH can reset the port after all commands are aborted. Signed-off-by: Darrick J. Wong Signed-off-by: James Bottomley commit 37958fb040cf6f88b354b9fa7e846014ffbd3b73 Author: Darrick J. Wong Date: Thu Jan 11 14:15:15 2007 -0800 [SCSI] libsas: Remove SAS_TASK_INITIATOR_ABORTED flag This flag is no longer necessary because we push tasks to be aborted into the EH as soon as we possibly can, and let the SCSI EH code take care of the coordination for which this flag was used. Signed-off-by: Darrick J. Wong Signed-off-by: James Bottomley commit 8f3b8fa9afe75cafc4feb317d305444f6c5271fb Author: Darrick J. Wong Date: Thu Jan 11 14:15:12 2007 -0800 [SCSI] aic94xx: Don't eat TMF_QUERY_TASK results In this driver, TMF_QUERY_TASK translates to QUERY_SSP_TASK. The sequencer, it seems, is perfectly happy sending us a SSP response, which this function promptly "converts" into TMF_RESP_FUNC_FAILED. This leads to the SAS EH making bad decisions based on bad data, so we should not perform the conversion in this case. Signed-off-by: Darrick J. Wong Signed-off-by: James Bottomley commit c8490f3a77805d04321d9e44486a679801a035b8 Author: Darrick J. Wong Date: Thu Jan 11 14:15:09 2007 -0800 [SCSI] libsas: Use SCAN_WILD_CARD instead of ~0 Magic number cleanup. Signed-off-by: Darrick J. Wong Signed-off-by: James Bottomley commit f12164200f09ec10764f2cf96da335fd83062bc4 Author: Darrick J. Wong Date: Thu Jan 11 14:15:06 2007 -0800 [SCSI] aic94xx: Set lldd_max_execute_num in sas_ha The aic94xx module has a parameter that looks like it should set lldd_max_execute_num in the sas_ha, but it never sets this value. Either we should set it or remove the parameter. This allows us to enable task collector mode for this driver, though it is still off by default. Signed-off-by: Darrick J. Wong Signed-off-by: James Bottomley commit cde3f74bac3e4a6bcdc3a6370af38179fd8ef1f2 Author: Darrick J. Wong Date: Thu Jan 11 14:15:03 2007 -0800 [SCSI] libsas: Destroy the task collector thread after releasing ports If we use task collector mode, we can end up destroying the task collector thread before we release the ports, which is bad if a port release causes a disk I/O (such as cache flushing). Signed-off-by: Darrick J. Wong Signed-off-by: James Bottomley commit 6d4dcd4dae25c48e8932326aaedfe560d7f2c7bb Author: Darrick J. Wong Date: Thu Jan 11 14:15:00 2007 -0800 [SCSI] libsas: Reset timer on taskless scsi_cmnds in sas_scsi_timed_out Every so often, a scsi_cmnd will time out, and the libsas timeout handler will discover that the scsi_cmnd does not have a sas_task attached to it. This can happen in two cases: (1) the scsi_cmnd actually made it through libsas to the HBA and is now going through scsi_done, or (2) the scsi_cmnd has been held up (host lock, slab alloc, etc) and libsas has not yet attached a sas_task. In both cases, it is safe to ask SCSI for more time to process the command via EH_RESET_TIMER; we cannot blindly return EH_HANDLED because if (2) happens, we could end up calling scsi_done while another CPU is heading towards sas_queuecommand, which causes slab corruption when sas_task_done updates the freed scsi_cmnd. Signed-off-by: Darrick J. Wong Signed-off-by: James Bottomley commit acbf167d4ad8c27f9743a4b539d51ae9535bf21c Author: Darrick J. Wong Date: Thu Jan 11 14:14:57 2007 -0800 [SCSI] libsas: Add a sysfs knob to enable/disable a phy This patch lets a user arbitrarily enable or disable a phy via sysfs. Potential applications include shutting down a phy to replace one lane of wide port, and (more importantly) providing a method for the libata SATL to control the phy. Signed-off-by: Darrick J. Wong Signed-off-by: James Bottomley commit b218a0d8e250e0ae8fd4d4e45bd66a588b380752 Author: Darrick J. Wong Date: Thu Jan 11 14:14:55 2007 -0800 [SCSI] libsas: Don't give scsi_cmnds to the EH if they never made it to the SAS LLDD or have already returned On a system with many SAS targets, it appears possible that a scsi_cmnd can time out without ever making it to the SAS LLDD or at the same time that a completion is occurring. In both of these cases, telling the LLDD to abort the sas_task makes no sense because the LLDD won't know about the sas_task; what we really want to do is to increase the timer. Note that this involves creating another sas_task bit to indicate whether or not the task has been sent to the LLDD; I could have implemented this by slightly redefining SAS_TASK_STATE_PENDING, but this way seems cleaner. This second version amends the aic94xx portion to set the TASK_AT_INITIATOR flag for all sas_tasks that were passed to lldd_execute_task. Signed-off-by: Darrick J. Wong Signed-off-by: James Bottomley commit bf451207511d049189ddb0a4eae3acdb086a3c82 Author: Darrick J. Wong Date: Thu Jan 11 14:14:52 2007 -0800 [SCSI] libsas: Clean up rphys/port dev list after a discovery error on an expander sas_get_port_device assigns a rphy to a domain device in anticipation of finding a disk. When a discovery error occurs in sas_discover_{sata,sas,expander}*, however, we need to clean up that rphy and the port device list so that we don't GPF. In addition, we need to check the result of the second sas_notify_lldd_dev_found. This patch seems ok on a x260, x366 and x206m. This patch fixes up sas_expander.c separately because jejb has some cleanup patches of his own that are a prerequisite. Signed-off-by: Darrick J. Wong Signed-off-by: James Bottomley commit 8880839815265ccc0edaff52ba08d750eea57acb Author: Darrick J. Wong Date: Thu Jan 11 14:14:49 2007 -0800 [SCSI] libsas: Clean up rphys/port dev list after a discovery error. sas_get_port_device assigns a rphy to a domain device in anticipation of finding a disk. When a discovery error occurs in sas_discover_{sata,sas,expander}*, however, we need to clean up that rphy and the port device list so that we don't GPF. In addition, we need to check the result of the second sas_notify_lldd_dev_found. This patch seems ok on a x260, x366 and x206m. Signed-off-by: Darrick J. Wong Signed-off-by: James Bottomley commit befede3dabd204e9c546cbfbe391b29286c57da2 Author: Seokmann Ju Date: Tue Jan 9 11:37:52 2007 -0800 [SCSI] qla2xxx: correct locking while call starget_for_each_device() Removed spin_unlock_irq()/spin_lock_irq() pairs surrounding starget_for_each_device() calls. As Matthew W. pointed out, starget_for_each_device() can be called under a spinlock being held. The change has been tested and verified on qla2xxx.ko module. Thanks Matthew W. and Hisashi H. for help. Signed-off-by: Andrew Vasquez Signed-off-by: Seokmann Ju Signed-off-by: James Bottomley commit 3424a65d717ca87ce11acfb03cfd2f713886bfb4 Author: Kurt Garloff Date: Tue Jan 9 02:28:54 2007 +0100 [SCSI] scsi_scan message cosmetic error Hi, Minor typo ... In my first iteration of patches (that got merged), the BLIST_ATTACH_PQ3 actually had the value 0x800000, but that got changed later to avoid conflicts. This piece must have been overlooked. You could obviously do something like %x and then add the bitflags, but that looks overkill for something that does not tend to change. Please merge. (Patch applied against latest 2.6.20rc version that I tested.) From: Kurt Garloff Subject: [SCSI SCAN] Fix logging message for PQ3 devices The blacklist flags BLIST_ATTACH_PQ3 has value 0x1000000, not 0x800000. Signed-off-by: Kurt Garloff Signed-off-by: James Bottomley commit 59f19a9efc3949f4e5675186bdcb6db1f46258a1 Author: Randy Dunlap Date: Tue Jan 9 21:40:52 2007 -0800 [SCSI] megaraid: more kernel-doc fixes More megaraid kernel-doc fixes. Signed-off-by: Randy Dunlap Acked-by: Sumant Patro Signed-off-by: James Bottomley commit a69b74d39f50b3e3ca9a6641bd71f3fc55d32d98 Author: Randy Dunlap Date: Fri Jan 5 22:41:48 2007 -0800 [SCSI] megaraid: fix kernel-doc kernel-doc modifications: - change "@param var" notation to @var; - change function/description separator from ':' to '-'; - change var/description separator from '-' to ':'; - fix a few doc. typos; - don't use kernel-doc /** lead-in when the doc. block is not kernel-doc; - use Linux common */ ending comment format instead of **/; - use correct function parameter names; - place function parameters immediately after the function short description; - place kernel-doc immediately before its function or macro; Signed-off-by: Randy Dunlap Acked-by: Sumant Patro Signed-off-by: James Bottomley commit cd96d96f20f2509dfeb302548132e30f471c071a Author: Sumant Patro Date: Fri Jan 5 07:10:09 2007 -0800 [SCSI] megaraid_{mm,mbox}: init fix for kdump 1. Changes in Initialization to fix kdump failure. Send SYNC command on loading. This command clears the pending commands in the adapter and re-initialize its internal RAID structure. Without this change, megaraid driver either panics or fails to initialize the adapter during kdump's second kernel boot if there are pending commands or interrupts from other devices sharing the same IRQ. 2. Authors email-id domain name changed from lsil.com to lsi.com. Also modified the MODULE_AUTHOR to megaraidlinux@lsi.com Signed-off-by: Sumant Patro Signed-off-by: James Bottomley commit 6f3cbf552e0557a463ad421f07b2e873a608406f Author: Douglas Gilbert Date: Fri Jan 5 00:05:25 2007 -0500 [SCSI] scsi_debug: error processing After discussions in the thread titled: [PATCH] scsi_debug: illegal blocking memory allocation here is a patch containing the discussed fix and some other fixes and additions. The patch is against lk 2.6.20-rc3 . The version is bumped to 1.81 . ChangeLog: - Change several GFP_KERNEL allocations to GFP_ATOMIC as they can be called from queuecommand() context - check above allocation returns and if out of memory report DID_REQUEUE in two cases, DID_NO_CONNECT in another, and fail slave configure() in another - add support for WRITE BUFFER command - add aborted_command error injection support (opts mask 0x10), similar mechanism to recovered_error injection. Signed-off-by: Douglas Gilbert Signed-off-by: James Bottomley commit d780c3bf2150264947870bb68c057c26c2aff7cc Author: Douglas Gilbert Date: Thu Jan 4 23:48:54 2007 -0500 [SCSI] mptctl for mptsas This patch makes the mptctl pass through available if the mptsas driver is selected. Without this patch if mptsas is the only fusion driver chosen, then the mptctl is not presented as an option. smp_utils uses the mptctl driver to pass SAS SMP functions through a MPT SAS HBA. Signed-off-by: Douglas Gilbert Acked-by: "Moore, Eric" Signed-off-by: James Bottomley commit 596f482a90ae27ea1b3da6a12ee42909045fbfd0 Author: Christoph Hellwig Date: Tue Jan 2 12:56:00 2007 +0100 [SCSI] kill scsi_rety_command scsi_retry_command only has a single caller, so there is no point in having this function. Additionally the memset of the sense buffer it does is entirely superflous as scsi_request_fn already calls scsi_init_cmd_errh to perform this memset before the command is reissued. Signed-off-by: Christoph Hellwig Signed-off-by: James Bottomley commit c27d85f3f3c5c663d6b6295730e8a7c0c3f9a296 Author: Thomas Bogendoerfer Date: Mon Dec 25 21:32:04 2006 +0100 [SCSI] SNI RM 53c710 driver This patch adds a SCSI driver for the onboard 53c710 chip of some SNI RM machines. Signed-off-by: James Bottomley commit 3b1ca5a12ce9849a794019c4b51cdbd456c1e8e7 Author: James Bottomley Date: Sat Jan 13 13:46:51 2007 -0600 [SCSI] NCR_D700: needs burst length setting to 8 The D700 needs the burst length setting to the previous 53c700 default of 8 otherwise it will be effectively disabled. Signed-off-by: James Bottomley commit f67a9c1592b3a0292376bdcbdcc34cbe353967a8 Author: Thomas Bogendoerfer Date: Mon Dec 25 21:30:08 2006 +0100 [SCSI] 53c700: Allow setting burst length This is a patch, which allows not only disabling bursting but to specify different burst lenghts. This feature is needed to get the 53c700 driver working for the onboard SCSI controller of SNI RM machines, which only work reliably with a 4 word burst length. Signed-off-by: James Bottomley commit 2e9c9cf44b17ef5fa1f360bc175ed7761daf3428 Author: Wim Van Sebroeck Date: Thu Jan 11 22:42:41 2007 +0100 [WATCHDOG] advantechwdt.c - convert to platform_device part 2 Convert the reboot_notifier into the platform_device's shutdown method Signed-off-by: Wim Van Sebroeck commit c2bd11c7cbba45c3a1d850a8a29855cb4d61654c Author: Wim Van Sebroeck Date: Thu Jan 11 22:35:40 2007 +0100 [WATCHDOG] advantechwdt.c - convert to platform_device Convert the advantechwdt watchdog into a platform_device Signed-off-by: Wim Van Sebroeck commit 0349a363e23a0533e081ca320c837bc08247343e Author: Wim Van Sebroeck Date: Thu Jan 11 22:27:51 2007 +0100 [WATCHDOG] advantechwdt.c - move set_heartbeat to a seperate function Put the set_heartbeat/timeout code into a seperate function Signed-off-by: Wim Van Sebroeck commit 1d747be647c2239e39a9b5faa138c1e36222b37e Author: Wim Van Sebroeck Date: Thu Jan 11 22:19:28 2007 +0100 [WATCHDOG] advantechwdt.c - cleanup before platform_device patches This cleanup consists of: - make sure that the printk's use the module/driver-name - do the exit of the module exactly the opposite of the init of the module Signed-off-by: Wim Van Sebroeck commit 98c08e98f8e5af1caf106e9ee3d46f3eb1ba4858 Author: Wim Van Sebroeck Date: Wed Jan 10 23:38:56 2007 +0100 [WATCHDOG] acquirewdt.c - convert to platform_device part 2 Convert the reboot_notifier into the platform_device's shutdown method Signed-off-by: Wim Van Sebroeck commit ad5fe323182fd3adab4225c93eae36f3c555a884 Author: Wim Van Sebroeck Date: Wed Jan 10 23:36:13 2007 +0100 [WATCHDOG] acquirewdt.c - convert to platform_device Convert the acquirewdt watchdog into a platform_device Signed-off-by: Wim Van Sebroeck commit 76c11f0442257099cbb474301f2ffff38649d3d3 Author: Wim Van Sebroeck Date: Wed Jan 10 23:23:44 2007 +0100 [WATCHDOG] acquirewdt.c - clean before platform_device patches Clean the current code before we convert the driver to a platform_device. This clean consists of: - document the includes - make sure that the printk's use the module/driver-name - do the exit of the module exactly the opposite of the init of the module Signed-off-by: Wim Van Sebroeck commit f3dc07330c3e43a8d365eaa74693e320e6ed79d9 Author: Wim Van Sebroeck Date: Tue Jan 9 22:43:49 2007 +0100 [WATCHDOG] pcwd_usb.c - get heartbeat from dip switches The PCWD cards normally use the heartbeat that is set via the dip-switches of the card. There are only 3 switches, thus 8 combinations that each have a certain heartbeat. The card can however be programmed with a heartbeat from 1 till 65535 seconds. This is what our driver does: it programs the heartbeat on the card. There are however a lot of people that don't know that we set the heartbeat of the watchdog card to the value provided by the heartbeat module parameter. Instead they think that the heartbeat value is the same as set by the dip-switches. This patch changes the driver so that at startup you can take the heartbeat from the dip-switches. You do this by setting the heartbeat module parameter to 0. This patch also makes this the default behaviour. Signed-off-by: Wim Van Sebroeck commit f9146f26da9a4336e02e35bf20222dcb2ee62c7f Author: Wim Van Sebroeck Date: Tue Jan 9 22:38:54 2007 +0100 [WATCHDOG] pcwd.c - e-mail adres update update Simon Machell's e-mail adres Signed-off-by: Wim Van Sebroeck commit 82d5b9a7c63054a9a2cd838ffd177697f86e7e34 Author: Dave Kleikamp Date: Tue Jan 9 14:14:48 2007 -0600 JFS: Add lockdep annotations Yeah, it's about time. Signed-off-by: Dave Kleikamp commit 17e6afc75ad0150d265a86a8f155b2871f9c07fe Author: Dave Kleikamp Date: Tue Jan 9 08:57:34 2007 -0600 JFS: Avoid BUG() on a damaged file system On Mon, 2006-12-18 at 19:51 +0100, Eric Sesterhenn wrote: > hi, > > while playing around with fsfuzzer, i got the following oops with jfs: > > [ 851.804875] BUG at fs/jfs/jfs_xtree.c:760 > assert(!BT_STACK_FULL(btstack)) > [ 851.805179] ------------[ cut here ]------------ > [ 851.805238] kernel BUG at fs/jfs/jfs_xtree.c:760! JFS should mark the superblock dirty and return an error rather than calling BUG(). Signed-off-by: Dave Kleikamp commit 2ef473de1ee62eb31b6b98885562cdb4389b01dc Author: Wim Van Sebroeck Date: Mon Jan 8 22:45:30 2007 +0100 [WATCHDOG] pcwd_usb.c - get heartbeat from dip switches The PCWD cards normally use the heartbeat that is set via the dip-switches of the card. There are only 3 switches, thus 8 combinations that each have a certain heartbeat. The card can however be programmed with a heartbeat from 1 till 65535 seconds. This is what our driver does: it programs the heartbeat on the card. There are however a lot of people that don't know that we set the heartbeat of the watchdog card to the value provided by the heartbeat module parameter. Instead they think that the heartbeat value is the same as set by the dip-switches. This patch changes the driver so that at startup you can take the heartbeat from the dip-switches. You do this by setting the heartbeat module parameter to 0. This patch also makes this the default behaviour. Signed-off-by: Wim Van Sebroeck commit d26d90967de9d51c08d5821e362cb2245f83c1a8 Author: Wim Van Sebroeck Date: Mon Jan 8 22:40:33 2007 +0100 [WATCHDOG] pcwd_usb.c - document includes document and review the include files. Signed-off-by: Wim Van Sebroeck commit 045798b56f59d02beef84d5aa7137786c50912c2 Author: Wim Van Sebroeck Date: Sun Jan 7 21:57:03 2007 +0100 [WATCHDOG] pcwd_pci.c - spinlock fixes the keepalive and get_temperature functions should use spinlocks also. Signed-off-by: Wim Van Sebroeck commit 39e3a0556a1e2d33f9491d43bae9fdaa09b0308a Author: Wim Van Sebroeck Date: Sun Jan 7 21:49:11 2007 +0100 [WATCHDOG] pcwd_pci.c - get heartbeat from dip switches The PCWD cards normally use the heartbeat that is set via the dip-switches of the card. There are only 3 switches, thus 8 combinations that each have a certain heartbeat. The card can however be programmed with a heartbeat from 1 till 65535 seconds. This is what our driver does: it programs the heartbeat on the card. There are however a lot of people that don't know that we set the heartbeat of the watchdog card to the value provided by the heartbeat module parameter. Instead they think that the heartbeat value is the same as set by the dip-switches. This patch changes the driver so that at startup you can take the heartbeat from the dip-switches. You do this by setting the heartbeat module parameter to 0. This patch also makes this the default behaviour. Signed-off-by: Wim Van Sebroeck commit bb0958544f3c7c016b2a3025ab3694363e403aa1 Author: Zhang Rui Date: Thu Jan 4 15:03:18 2007 +0800 ACPI: use more understandable bus_id for ACPI devices Some of the ACPI devices use the internal fake hids which are exposed to userspace as devces' bus_id after sysfs conversion. To make it more friendly, we convert them to more understandable strings. For those devices w/o PNPids, we use "device:instance_no" as the bus_id instead of "PNPIDNON:instance_no". Signed-off-by: Zhang Rui Signed-off-by: Len Brown commit 82cae99980c158cb9724415547ca59cf95c58792 Author: Rui Zhang Date: Wed Jan 3 23:40:53 2007 -0500 ACPI: video: fix LCD monitor seen as CRT http://bugzilla.kernel.org/show_bug.cgi?id=7349 Signed-off-by: Len Brown commit 2786f6e388e9dfe9e7b1c3c6bd7fcfba9cfb9831 Author: Rui Zhang Date: Thu Dec 21 02:21:13 2006 -0500 ACPI: fix Supermicro X7DB8+ Boot regression http://bugzilla.kernel.org/show_bug.cgi?id=7695 Originally we converted bind/unbind to use a new pci bridge driver. The driver will add/remove _PRT, so we can eventually remove .bind/.unbind methods. But we found that some of the _ADR-Based devices don't have _PRT, i.e. they are not managed by the new ACPI PCI bridge driver. So that .bind method is not called for some _ADR-Based devices, which leads to a failure. Now we make ACPI PCI Root Bridge Driver scan and binds all _ADR-Based devices once the driver is loaded, in the .add method of ACPI PCI Root Bridge driver. Extra code path for calling .bind/.unbind when _ADR-Based devices are hot added/removed is also added. Signed-off-by: Zhang Rui Signed-off-by: Len Brown commit e49bd2dd5a503bb94fe2f2af45422b610940b75d Author: Zhang Rui Date: Fri Dec 8 17:23:43 2006 +0800 ACPI: use PNPID:instance_no as bus_id of ACPI device Previously we used the device name in the DSDT, but would crash upon encountering a duplicate. Also, exposing the DSDT device name to the user in a patch isn't a good idea, because it is arbitrary. After some discussion, we finally decided to use "PNPID:instance_no" as the bus_id of ACPI devices. Two attributes for each device are added at the same time, the full pathname in ACPI namespace and hardware_id if it has. NOTE: acpi_bus_id_list is used to keep the information of PNPID and instance number of the given PNPID. Loop the acpi_bus_id_list to find the instance_no of the same PNPID when register a device. If failed, i.e. we don't have a node with this PNPID, allocate one and link it to this list. NOTE: Now I don't take the memory free work in charge. If necessary, I can add a reference count in struct acpi_device_bus_id, and check the reference and when unregister a device, i.e. memory is freed when the reference count of a given PNPID is 0. Signed-off-by: Li Shaohua Signed-off-by: Len Brown commit 65a2d2258e0f29371606aa0f7f4258e618ecebe8 Author: Akinobu Mita Date: Thu Dec 21 00:42:55 2006 -0500 Input: pc110pad - return proper error The driver should return -ENODEV rather than -ENOENT when it detects a PCI device in the box. Signed-off-by: Akinobu Mita Signed-off-by: Dmitry Torokhov commit 2f3d000a133f68250635f14f6caf24d32d358090 Author: Yu Luming Date: Sat Nov 11 02:40:34 2006 +0800 ACPI: Adds backlight sysfs support for acpi video driver. Adds backlight sysfs support for acpi video driver. signed-off-by: Luming Yu Signed-off-by: Len Brown commit b03637b8863159a4518cb0a9ab90577460fe3417 Author: Yu Luming Date: Tue Dec 19 12:56:18 2006 -0800 output: Add output class document Signed-off-by: Luming Yu Cc: "Antonino A. Daplas" Cc: Greg KH Signed-off-by: Andrew Morton Signed-off-by: Len Brown commit 2dec3ba8d872aa3ffbcdb8f6f8a2c0bcd44e9910 Author: Yu Luming Date: Tue Dec 19 12:56:17 2006 -0800 output: Add display output class support Add generic abstract layer for display output switch control. The output sysfs class driver provides an abstract video output layer that can be used to hook platform specific methods to enable/disable video output device through common sysfs interface. Signed-off-by: Luming Yu Cc: "Antonino A. Daplas" Cc: Greg KH Signed-off-by: Andrew Morton Signed-off-by: Len Brown commit 9cd446198e7646431a7f2ce7dbeec8df9f77012b Author: Akinobu Mita Date: Tue Dec 19 17:51:44 2006 +0900 [WATCHDOG] fix clk_get() error check The return value of clk_get() should be checked by IS_ERR(). Signed-off-by: Akinobu Mita Signed-off-by: Ben Dooks Signed-off-by: Wim Van Sebroeck commit 0b6dd8a640fbaf73b74949b6dc2be50263532576 Author: Ben Dooks Date: Mon Dec 18 10:31:32 2006 +0000 [WATCHDOG] s3c2410_wdt exit driver via labels Cleanup the s3c2410_wdt driver's exit point by using labels instead of multiple returns. Also remove the checks for the resources having been allocate in the exit, as we will now either have fully allocated or not allocated the resources at-all. Signed-off-by: Ben Dooks Signed-off-by: Wim Van Sebroeck commit ae8433324be16673c75951986dcf85f29c090557 Author: Zhang Rui Date: Thu Dec 7 20:57:10 2006 +0800 ACPI: Set fake hid for non-PNPID ACPI devices We do this mainly because: 1. hid is used to match ACPI devices and drivers. .match method which is incompatible to driver model can be deleted from acpi_driver.ops then. 2. As the .uevent method mark ACPI drivers by PNPID, fake hid is set to non-PNPID devices so that udev script can load the right ACPI driver by looking for "HWID = " or "COMPTID = ". Signed-off-by: Zhang Rui Signed-off-by: Len Brown commit db3e1cc3257758d8a694d0a6ab29f109fb019853 Author: Li Shaohua Date: Thu Dec 7 20:57:05 2006 +0800 ACPI: Convert ACPI PCI .bind/.unbind to use PCI bridge driver acpi_device had a .bind/.unbind methods, but Linux driver model does not. Cut ACPI PCI code over to use the Linux driver model methods. Convert bind/unbind to use a new pci bridge driver. The driver will add/remove _PRT, so we can eventually remove .bind/.unbind methods. Signed-off-by: Zhang Rui Signed-off-by: Len Brown commit 54a07001b9efb6a3bb9a9d8ac9ddb226e29b5406 Author: Li Shaohua Date: Thu Dec 7 20:56:51 2006 +0800 ACPI: consolidate two motherboard drivers into one Consolidate motherboard1 and motherboard2 drivers into one so that driver core doesn't complain that two drivers have the same name. Signed-off-by: Zhang Rui Signed-off-by: Len Brown commit 96333578b023957537c3e98b50af7f3b7e08e411 Author: Li Shaohua Date: Thu Dec 7 20:56:46 2006 +0800 ACPI: add acpi_bus_removal_type in acpi_device Add removal_type in structure acpi_device for hot removal. ACPI_BUS_REMOVAL_EJECT is used for ACPI device hot removal. Only one parameter is allowed in .remove method due to driver model. So removal_type is added to indicate different removal type. Signed-off-by: Zhang Rui Signed-off-by: Len Brown commit c4168bff32e218b8400cb48b48adb9b7f7bb31b8 Author: Li Shaohua Date: Thu Dec 7 20:56:41 2006 +0800 ACPI: add acpi_bus_ops in acpi_device Add acpi_bus_ops in acpi_device to support acpi hot plug. NOTE: Two methods .add and .start in acpi_driver.ops are called separately to probe ACPI devices, while only .probe method is called in driver model. As executing .add and .start separately is critical for ACPI device hot plug, we use acpi_bus_ops to distinguish different code path. Signed-off-by: Zhang Rui Signed-off-by: Len Brown commit f883d9db008deb20d4969c26475100cec2b7f6f8 Author: Patrick Mochel Date: Thu Dec 7 20:56:38 2006 +0800 ACPI: convert to sysfs framework Setup new sysfs framework 1. Remove /sys/firmware/acpi 2. Add ACPI device in device tree. File "eject" for every device that has _EJ0 method is moved from /sys/firmware to /sys/devices. Operation on this file is exactly the same as before. i.e. echo 1 to "eject" will cause hot removal of this device. Corresponding changes should be made in userspace for hot removal. Signed-off-by: Li Shaohua Signed-off-by: Zhang Rui Signed-off-by: Len Brown commit a7178df5e7e5730e5daa6cf6d8b8bf73adbe75c0 Author: Li Shaohua Date: Thu Dec 7 20:56:34 2006 +0800 ACPI: adjust init order Adjust link order to add ACPI devices to global list before PCI devices. In addition, acpi_bus type must be initialized before any driver loads. Signed-off-by: Zhang Rui Signed-off-by: Len Brown commit 1890a97ab3f66d1e99768439f8067608b9b97fe3 Author: Patrick Mochel Date: Thu Dec 7 20:56:31 2006 +0800 ACPI: change registration interface to follow driver model ACPI device/driver registration Interfaces are modified to follow Linux driver model. Signed-off-by: Li Shaohua Signed-off-by: Zhang Rui Signed-off-by: Len Brown commit 5d9464a46918ced087c351a10f38cee95725f85b Author: Patrick Mochel Date: Thu Dec 7 20:56:27 2006 +0800 ACPI: add ACPI bus_type for driver model Add ACPI bus_type for Linux driver model. 1. .shutdown method is added into acpi_driver.ops needed by bus_type operations. 2. remove useless parameter 'int state' in .resume method. 3. change parameter 'int state' to 'pm_message_t state' in .suspend method. Note: The new .uevent method mark ACPI drivers by PNPID instead of by name. Udev script needs to look for "HWID=" or "COMPTID=" to load ACPI drivers as a result. Signed-off-by: Li Shaohua Signed-off-by: Zhang Rui Signed-off-by: Len Brown commit d43ec68e9837dfa6618ab473622683fdbf6e68a9 Author: Patrick Mochel Date: Thu Dec 7 20:56:23 2006 +0800 ACPI: add device_driver and hepler functions Add device_driver into acpi_driver for driver model. Add helper functions 'to_acpi_device' and 'to_acpi_driver' to get structure acpi_device/acpi_driver by device/device_driver. Signed-off-by: Zhang Rui Signed-off-by: Len Brown commit 1d268b0a0f5407138caf0dec9559d68e657a3a74 Author: Zhang Rui Date: Thu Dec 7 20:56:19 2006 +0800 ACPI: rename some functions We want the name 'to_acpi_device'. And the current macro 'to_acpi_device' will be removed after device model is setup. So just simply rename them. Signed-off-by: Zhang Rui Signed-off-by: Len Brown commit 9e89dde2b063ca73fcdc9244fe68e2dea32c5088 Author: Zhang Rui Date: Thu Dec 7 20:56:16 2006 +0800 ACPI: clean up scan.c Adjust the code and make code doing similar things together. No logic changes. Signed-off-by : Zhang Rui Signed-off-by: Len Brown .mailmap | 96 CREDITS | 10 Documentation/ABI/testing/debugfs-pktcdvd | 5 Documentation/ABI/testing/sysfs-class-pktcdvd | 2 Documentation/DocBook/gadget.tmpl | 4 Documentation/DocBook/kernel-api.tmpl | 3 Documentation/DocBook/stylesheet.xsl | 1 Documentation/DocBook/usb.tmpl | 6 Documentation/HOWTO | 1 Documentation/auxdisplay/cfag12864b | 105 Documentation/auxdisplay/cfag12864b-example.c | 282 + Documentation/auxdisplay/ks0108 | 55 Documentation/cdrom/packet-writing.txt | 2 Documentation/crypto/api-intro.txt | 4 Documentation/driver-model/devres.txt | 268 + Documentation/drivers/edac/edac.txt | 16 Documentation/fb/s3fb.txt | 78 Documentation/feature-removal-schedule.txt | 67 Documentation/filesystems/relay.txt | 9 Documentation/filesystems/ufs.txt | 9 Documentation/gpio.txt | 274 + Documentation/hrtimer/timer_stats.txt | 68 Documentation/hrtimers.txt | 178 - Documentation/hrtimers/highres.txt | 249 + Documentation/hrtimers/hrtimers.txt | 178 + Documentation/i2c/busses/i2c-i801 | 60 Documentation/i2c/busses/i2c-parport | 15 Documentation/i2c/busses/i2c-piix4 | 2 Documentation/i2c/busses/i2c-viapro | 7 Documentation/i2c/porting-clients | 6 Documentation/i2c/smbus-protocol | 2 Documentation/i2c/writing-clients | 58 Documentation/ioctl-number.txt | 3 Documentation/isdn/README.gigaset | 65 Documentation/kdump/kdump.txt | 8 Documentation/kernel-doc-nano-HOWTO.txt | 39 Documentation/kernel-parameters.txt | 18 Documentation/local_ops.txt | 163 Documentation/nfsroot.txt | 4 Documentation/powerpc/booting-without-of.txt | 4 .../powerpc/mpc52xx-device-tree-bindings.txt | 183 - Documentation/rbtree.txt | 192 + Documentation/rtc.txt | 46 Documentation/s390/Debugging390.txt | 2 Documentation/scsi/ChangeLog.megaraid | 16 Documentation/sound/alsa/ALSA-Configuration.txt | 60 .../sound/alsa/DocBook/alsa-driver-api.tmpl | 4 .../sound/alsa/DocBook/writing-an-alsa-driver.tmpl | 33 Documentation/sound/alsa/hda_codec.txt | 10 Documentation/sound/alsa/soc/DAI.txt | 56 Documentation/sound/alsa/soc/clocking.txt | 51 Documentation/sound/alsa/soc/codec.txt | 197 + Documentation/sound/alsa/soc/dapm.txt | 297 + Documentation/sound/alsa/soc/machine.txt | 113 Documentation/sound/alsa/soc/overview.txt | 83 Documentation/sound/alsa/soc/platform.txt | 58 Documentation/sound/alsa/soc/pops_clicks.txt | 52 Documentation/spi/spi-summary | 3 Documentation/sysrq.txt | 44 Documentation/usb/proc_usb_info.txt | 21 Documentation/usb/usbmon.txt | 152 Documentation/video-output.txt | 34 Documentation/x86_64/boot-options.txt | 132 Documentation/x86_64/cpu-hotplug-spec | 2 Documentation/x86_64/kernel-stacks | 26 Documentation/x86_64/machinecheck | 70 Documentation/x86_64/mm.txt | 22 MAINTAINERS | 91 Makefile | 28 arch/alpha/Kconfig | 4 arch/alpha/kernel/pci.c | 4 arch/alpha/kernel/setup.c | 6 arch/alpha/kernel/time.c | 11 arch/alpha/kernel/vmlinux.lds.S | 2 arch/arm/Kconfig | 38 arch/arm/common/rtctime.c | 2 arch/arm/common/sharpsl_pm.c | 2 arch/arm/kernel/Makefile | 1 arch/arm/kernel/apm.c | 672 -- arch/arm/kernel/irq.c | 3 arch/arm/kernel/isa.c | 2 arch/arm/kernel/setup.c | 6 arch/arm/kernel/time.c | 10 arch/arm/kernel/vmlinux.lds.S | 2 arch/arm/mach-at91rm9200/clock.c | 2 arch/arm/mach-at91rm9200/gpio.c | 48 arch/arm/mach-imx/time.c | 2 arch/arm/mach-ixp4xx/common.c | 2 arch/arm/mach-netx/time.c | 2 arch/arm/mach-pxa/corgi_pm.c | 2 arch/arm/mach-pxa/sharpsl_pm.c | 2 arch/arm/mach-pxa/spitz_pm.c | 2 arch/arm/mach-pxa/time.c | 2 arch/arm26/Kconfig | 4 arch/arm26/kernel/ecard.c | 2 arch/arm26/kernel/setup.c | 6 arch/arm26/kernel/time.c | 8 arch/arm26/kernel/vmlinux-arm26-xip.lds.in | 2 arch/arm26/kernel/vmlinux-arm26.lds.in | 2 arch/avr32/boards/atstk1000/Makefile | 2 arch/avr32/boards/atstk1000/atstk1002.c | 52 arch/avr32/boards/atstk1000/spi.c | 27 arch/avr32/kernel/cpu.c | 1 arch/avr32/kernel/irq.c | 1 arch/avr32/kernel/setup.c | 10 arch/avr32/kernel/syscall_table.S | 22 arch/avr32/kernel/time.c | 11 arch/avr32/kernel/vmlinux.lds.c | 2 arch/avr32/lib/libgcc.h | 33 arch/avr32/lib/longlong.h | 98 arch/avr32/mach-at32ap/Makefile | 2 arch/avr32/mach-at32ap/at32ap7000.c | 172 arch/avr32/mach-at32ap/clock.c | 6 arch/avr32/mach-at32ap/extint.c | 36 arch/avr32/mach-at32ap/pio.c | 255 + arch/avr32/mm/cache.c | 32 arch/avr32/mm/tlb.c | 2 arch/cris/Kconfig | 7 arch/cris/arch-v10/drivers/axisflashmap.c | 3 arch/cris/arch-v10/drivers/ds1302.c | 2 arch/cris/arch-v10/drivers/eeprom.c | 2 arch/cris/arch-v10/drivers/gpio.c | 2 arch/cris/arch-v10/drivers/i2c.c | 2 arch/cris/arch-v10/drivers/pcf8563.c | 2 arch/cris/arch-v10/kernel/time.c | 1 arch/cris/arch-v10/mm/tlb.c | 9 arch/cris/arch-v10/vmlinux.lds.S | 4 arch/cris/arch-v32/drivers/cryptocop.c | 2 arch/cris/arch-v32/drivers/gpio.c | 2 arch/cris/arch-v32/drivers/i2c.c | 2 arch/cris/arch-v32/drivers/pcf8563.c | 2 arch/cris/arch-v32/drivers/sync_serial.c | 2 arch/cris/arch-v32/mm/tlb.c | 9 arch/cris/arch-v32/vmlinux.lds.S | 2 arch/cris/kernel/profile.c | 2 arch/cris/kernel/setup.c | 6 arch/cris/kernel/time.c | 9 arch/cris/mm/tlb.c | 3 arch/frv/Kconfig | 4 arch/frv/kernel/pm.c | 53 arch/frv/kernel/setup.c | 6 arch/frv/kernel/sysctl.c | 32 arch/frv/kernel/vmlinux.lds.S | 2 arch/h8300/Kconfig | 7 arch/h8300/kernel/Makefile | 4 arch/h8300/kernel/setup.c | 6 arch/h8300/kernel/time.c | 6 arch/h8300/kernel/vmlinux.lds.S | 2 arch/i386/Kconfig | 36 arch/i386/Kconfig.cpu | 5 arch/i386/Kconfig.debug | 2 arch/i386/defconfig | 48 arch/i386/kernel/Makefile | 6 arch/i386/kernel/acpi/boot.c | 246 - arch/i386/kernel/acpi/earlyquirk.c | 4 arch/i386/kernel/apic.c | 1631 ++--- arch/i386/kernel/apm.c | 72 arch/i386/kernel/asm-offsets.c | 2 arch/i386/kernel/cpu/common.c | 14 arch/i386/kernel/cpu/cpufreq/Kconfig | 9 arch/i386/kernel/cpu/cpufreq/Makefile | 1 arch/i386/kernel/cpu/cpufreq/e_powersaver.c | 334 + arch/i386/kernel/cpu/cpufreq/longhaul.c | 374 + arch/i386/kernel/cpu/cpufreq/longhaul.h | 153 arch/i386/kernel/cpu/cpufreq/powernow-k8.c | 6 arch/i386/kernel/cpu/cyrix.c | 52 arch/i386/kernel/cpu/mcheck/mce.c | 1 arch/i386/kernel/cpu/mcheck/mce.h | 2 arch/i386/kernel/cpu/mcheck/p4.c | 2 arch/i386/kernel/cpu/mtrr/if.c | 32 arch/i386/kernel/cpu/mtrr/main.c | 6 arch/i386/kernel/cpu/mtrr/mtrr.h | 2 arch/i386/kernel/cpu/proc.c | 14 arch/i386/kernel/cpu/transmeta.c | 5 arch/i386/kernel/cpuid.c | 9 arch/i386/kernel/e820.c | 18 arch/i386/kernel/entry.S | 78 arch/i386/kernel/head.S | 40 arch/i386/kernel/hpet.c | 499 + arch/i386/kernel/i8253.c | 96 arch/i386/kernel/i8259.c | 7 arch/i386/kernel/io_apic.c | 33 arch/i386/kernel/irq.c | 25 arch/i386/kernel/kprobes.c | 6 arch/i386/kernel/microcode.c | 4 arch/i386/kernel/mpparse.c | 4 arch/i386/kernel/msr.c | 15 arch/i386/kernel/nmi.c | 107 arch/i386/kernel/paravirt.c | 116 arch/i386/kernel/pcspeaker.c | 20 arch/i386/kernel/process.c | 102 arch/i386/kernel/ptrace.c | 16 arch/i386/kernel/setup.c | 39 arch/i386/kernel/signal.c | 16 arch/i386/kernel/smp.c | 7 arch/i386/kernel/smpboot.c | 203 - arch/i386/kernel/srat.c | 84 arch/i386/kernel/sysenter.c | 55 arch/i386/kernel/time.c | 138 arch/i386/kernel/time_hpet.c | 497 - arch/i386/kernel/traps.c | 27 arch/i386/kernel/tsc.c | 195 - arch/i386/kernel/tsc_sync.c | 1 arch/i386/kernel/vm86.c | 33 arch/i386/kernel/vmi.c | 949 +++ arch/i386/kernel/vmitime.c | 499 + arch/i386/kernel/vmlinux.lds.S | 9 arch/i386/mach-default/setup.c | 8 arch/i386/mach-es7000/es7000.h | 9 arch/i386/mach-es7000/es7000plat.c | 53 arch/i386/math-emu/get_address.c | 14 arch/i386/math-emu/status_w.h | 8 arch/i386/mm/discontig.c | 1 arch/i386/mm/fault.c | 44 arch/i386/mm/highmem.c | 7 arch/i386/mm/init.c | 4 arch/i386/mm/pageattr.c | 4 arch/i386/mm/pgtable.c | 26 arch/i386/oprofile/op_model_ppro.c | 9 arch/i386/pci/Makefile | 2 arch/i386/pci/mmconfig-shared.c | 264 + arch/i386/pci/mmconfig.c | 102 arch/i386/pci/pci.h | 10 arch/ia64/Kconfig | 14 arch/ia64/hp/common/hwsw_iommu.c | 4 arch/ia64/hp/common/sba_iommu.c | 2 arch/ia64/ia32/binfmt_elf32.c | 13 arch/ia64/ia32/ia32_entry.S | 2 arch/ia64/ia32/sys_ia32.c | 68 arch/ia64/kernel/acpi.c | 200 - arch/ia64/kernel/crash.c | 20 arch/ia64/kernel/crash_dump.c | 3 arch/ia64/kernel/efi.c | 5 arch/ia64/kernel/entry.S | 2 arch/ia64/kernel/iosapic.c | 5 arch/ia64/kernel/irq_ia64.c | 2 arch/ia64/kernel/machine_kexec.c | 15 arch/ia64/kernel/msi_ia64.c | 19 arch/ia64/kernel/perfmon.c | 67 arch/ia64/kernel/process.c | 16 arch/ia64/kernel/ptrace.c | 14 arch/ia64/kernel/sal.c | 3 arch/ia64/kernel/salinfo.c | 4 arch/ia64/kernel/setup.c | 35 arch/ia64/kernel/smp.c | 4 arch/ia64/kernel/traps.c | 30 arch/ia64/kernel/vmlinux.lds.S | 3 arch/ia64/mm/contig.c | 80 arch/ia64/mm/discontig.c | 52 arch/ia64/mm/init.c | 46 arch/ia64/sn/kernel/huberror.c | 16 arch/ia64/sn/kernel/io_acpi_init.c | 314 + arch/ia64/sn/kernel/io_common.c | 90 arch/ia64/sn/kernel/io_init.c | 54 arch/ia64/sn/kernel/iomv.c | 5 arch/ia64/sn/kernel/msi_sn.c | 20 arch/ia64/sn/kernel/sn2/sn2_smp.c | 2 arch/ia64/sn/kernel/sn2/sn_hwperf.c | 2 arch/ia64/sn/kernel/sn2/sn_proc_fs.c | 105 arch/ia64/sn/kernel/xpc_main.c | 88 arch/ia64/sn/pci/pcibr/pcibr_provider.c | 6 arch/m32r/Kconfig | 7 arch/m32r/Makefile | 2 arch/m32r/defconfig | 525 + arch/m32r/kernel/head.S | 2 arch/m32r/kernel/process.c | 2 arch/m32r/kernel/setup.c | 6 arch/m32r/kernel/signal.c | 26 arch/m32r/kernel/time.c | 8 arch/m32r/kernel/vmlinux.lds.S | 9 arch/m32r/lib/ashxdi3.S | 3 arch/m32r/lib/checksum.S | 3 arch/m32r/lib/delay.c | 2 arch/m32r/lib/memcpy.S | 2 arch/m32r/lib/memset.S | 2 arch/m32r/lib/strlen.S | 2 arch/m32r/m32104ut/defconfig.m32104ut | 752 ++ arch/m32r/m32700ut/defconfig.m32700ut.smp | 519 + arch/m32r/m32700ut/defconfig.m32700ut.up | 516 + arch/m32r/mappi/defconfig.nommu | 366 + arch/m32r/mappi/defconfig.smp | 382 + arch/m32r/mappi/defconfig.up | 380 + arch/m32r/mappi2/defconfig.opsp | 883 +++ arch/m32r/mappi2/defconfig.vdec2 | 388 + arch/m32r/mappi3/defconfig.smp | 373 + arch/m32r/mm/fault-nommu.c | 29 arch/m32r/mm/fault.c | 66 arch/m32r/mm/mmu.S | 5 arch/m32r/oaks32r/defconfig.nommu | 348 + arch/m32r/opsput/defconfig.opsput | 383 + arch/m68k/Kconfig | 7 arch/m68k/atari/stdma.c | 2 arch/m68k/bvme6000/rtc.c | 2 arch/m68k/kernel/Makefile | 4 arch/m68k/kernel/ptrace.c | 4 arch/m68k/kernel/setup.c | 2 arch/m68k/kernel/time.c | 9 arch/m68k/kernel/traps.c | 2 arch/m68k/kernel/vmlinux-std.lds | 2 arch/m68k/kernel/vmlinux-sun3.lds | 2 arch/m68k/mvme16x/rtc.c | 2 arch/m68knommu/Kconfig | 7 arch/m68knommu/kernel/ptrace.c | 4 arch/m68knommu/kernel/setup.c | 6 arch/m68knommu/kernel/time.c | 14 arch/m68knommu/kernel/traps.c | 2 arch/m68knommu/kernel/vmlinux.lds.S | 12 arch/m68knommu/platform/5206/config.c | 2 arch/m68knommu/platform/5206e/config.c | 2 arch/m68knommu/platform/520x/config.c | 3 arch/m68knommu/platform/523x/config.c | 2 arch/m68knommu/platform/5249/config.c | 3 arch/m68knommu/platform/5272/config.c | 2 arch/m68knommu/platform/527x/config.c | 2 arch/m68knommu/platform/528x/config.c | 2 arch/m68knommu/platform/5307/config.c | 2 arch/m68knommu/platform/5307/pit.c | 2 arch/m68knommu/platform/5307/timers.c | 5 arch/m68knommu/platform/532x/config.c | 2 arch/m68knommu/platform/5407/config.c | 2 arch/m68knommu/platform/68328/config.c | 2 arch/mips/Kconfig | 148 arch/mips/Kconfig.debug | 8 arch/mips/arc/identify.c | 2 arch/mips/arc/memory.c | 18 arch/mips/au1000/common/irq.c | 8 arch/mips/au1000/common/pci.c | 18 arch/mips/au1000/common/power.c | 46 arch/mips/au1000/common/prom.c | 3 arch/mips/au1000/common/setup.c | 19 arch/mips/au1000/pb1100/board_setup.c | 93 arch/mips/au1000/pb1200/irqmap.c | 32 arch/mips/basler/excite/excite_irq.c | 6 arch/mips/cobalt/irq.c | 2 arch/mips/cobalt/setup.c | 3 arch/mips/configs/ip27_defconfig | 2 arch/mips/ddb5xxx/common/prom.c | 3 arch/mips/ddb5xxx/ddb5477/irq.c | 9 arch/mips/ddb5xxx/ddb5477/irq_5477.c | 2 arch/mips/dec/Makefile | 1 arch/mips/dec/int-handler.S | 4 arch/mips/dec/ioasic-irq.c | 4 arch/mips/dec/kn02-irq.c | 2 arch/mips/dec/prom/identify.c | 3 arch/mips/dec/prom/memory.c | 17 arch/mips/dec/setup.c | 14 arch/mips/dec/tc.c | 95 arch/mips/emma2rh/common/irq_emma2rh.c | 2 arch/mips/emma2rh/markeins/irq.c | 2 arch/mips/emma2rh/markeins/irq_markeins.c | 4 arch/mips/gt64120/ev64120/irq.c | 2 arch/mips/gt64120/ev64120/setup.c | 3 arch/mips/gt64120/momenco_ocelot/dbg_io.c | 4 arch/mips/gt64120/momenco_ocelot/irq.c | 4 arch/mips/gt64120/momenco_ocelot/prom.c | 3 arch/mips/gt64120/wrppmc/irq.c | 2 arch/mips/gt64120/wrppmc/setup.c | 3 arch/mips/jazz/irq.c | 2 arch/mips/jmr3927/common/prom.c | 3 arch/mips/jmr3927/rbhma3100/irq.c | 2 arch/mips/jmr3927/rbhma3100/setup.c | 2 arch/mips/kernel/Makefile | 2 arch/mips/kernel/apm.c | 604 -- arch/mips/kernel/asm-offsets.c | 5 arch/mips/kernel/cpu-probe.c | 2 arch/mips/kernel/entry.S | 19 arch/mips/kernel/gdb-stub.c | 6 arch/mips/kernel/head.S | 25 arch/mips/kernel/i8259.c | 24 arch/mips/kernel/irixelf.c | 331 + arch/mips/kernel/irq-msc01.c | 4 arch/mips/kernel/irq-mv6434x.c | 14 arch/mips/kernel/irq-rm7000.c | 13 arch/mips/kernel/irq-rm9000.c | 24 arch/mips/kernel/irq_cpu.c | 21 arch/mips/kernel/linux32.c | 101 arch/mips/kernel/mips-mt.c | 28 arch/mips/kernel/proc.c | 8 arch/mips/kernel/process.c | 6 arch/mips/kernel/r4k_fpu.S | 19 arch/mips/kernel/rtlx.c | 29 arch/mips/kernel/scall64-64.S | 2 arch/mips/kernel/scall64-n32.S | 6 arch/mips/kernel/scall64-o32.S | 4 arch/mips/kernel/setup.c | 49 arch/mips/kernel/signal-common.h | 174 arch/mips/kernel/signal.c | 254 + arch/mips/kernel/signal32.c | 380 - arch/mips/kernel/signal_n32.c | 47 arch/mips/kernel/smp-mt.c | 9 arch/mips/kernel/smtc.c | 54 arch/mips/kernel/sysirix.c | 4 arch/mips/kernel/time.c | 7 arch/mips/kernel/vmlinux.lds.S | 2 arch/mips/kernel/vpe.c | 60 arch/mips/lasat/interrupt.c | 2 arch/mips/lasat/prom.c | 3 arch/mips/lasat/sysctl.c | 147 arch/mips/lib-32/Makefile | 2 arch/mips/lib-32/memset.S | 145 arch/mips/lib-64/Makefile | 2 arch/mips/lib-64/memset.S | 142 arch/mips/lib/Makefile | 2 arch/mips/lib/memset.S | 166 arch/mips/lib/uncached.c | 4 arch/mips/mips-boards/atlas/atlas_int.c | 9 arch/mips/mips-boards/generic/memory.c | 18 arch/mips/mips-boards/malta/malta_int.c | 7 arch/mips/mips-boards/sead/sead_int.c | 2 arch/mips/mips-boards/sim/sim_int.c | 6 arch/mips/mips-boards/sim/sim_mem.c | 16 arch/mips/mm/Makefile | 14 arch/mips/mm/c-sb1.c | 6 arch/mips/mm/cache.c | 2 arch/mips/mm/dma-coherent.c | 254 - arch/mips/mm/dma-default.c | 363 + arch/mips/mm/dma-ip27.c | 257 - arch/mips/mm/dma-ip32.c | 383 - arch/mips/mm/dma-noncoherent.c | 370 - arch/mips/mm/init.c | 50 arch/mips/momentum/jaguar_atx/Makefile | 2 arch/mips/momentum/jaguar_atx/irq.c | 4 arch/mips/momentum/jaguar_atx/jaguar_atx_fpga.h | 6 arch/mips/momentum/jaguar_atx/platform.c | 235 + arch/mips/momentum/jaguar_atx/prom.c | 58 arch/mips/momentum/ocelot_3/irq.c | 2 arch/mips/momentum/ocelot_3/platform.c | 2 arch/mips/momentum/ocelot_3/prom.c | 3 arch/mips/momentum/ocelot_c/cpci-irq.c | 2 arch/mips/momentum/ocelot_c/dbg_io.c | 4 arch/mips/momentum/ocelot_c/irq.c | 2 arch/mips/momentum/ocelot_c/prom.c | 3 arch/mips/momentum/ocelot_c/uart-irq.c | 2 arch/mips/momentum/ocelot_g/dbg_io.c | 4 arch/mips/momentum/ocelot_g/irq.c | 4 arch/mips/momentum/ocelot_g/prom.c | 3 arch/mips/oprofile/Kconfig | 2 arch/mips/pci/Makefile | 2 arch/mips/pci/fixup-vr4133.c | 16 arch/mips/pci/pci-dac.c | 79 arch/mips/philips/pnx8550/common/int.c | 2 arch/mips/philips/pnx8550/common/proc.c | 7 arch/mips/philips/pnx8550/common/prom.c | 3 arch/mips/pmc-sierra/yosemite/dbg_io.c | 2 arch/mips/pmc-sierra/yosemite/irq.c | 6 arch/mips/pmc-sierra/yosemite/prom.c | 3 arch/mips/pmc-sierra/yosemite/setup.c | 2 arch/mips/qemu/q-mem.c | 3 arch/mips/sgi-ip22/ip22-eisa.c | 4 arch/mips/sgi-ip22/ip22-int.c | 13 arch/mips/sgi-ip22/ip22-mc.c | 3 arch/mips/sgi-ip27/ip27-irq.c | 2 arch/mips/sgi-ip27/ip27-memory.c | 3 arch/mips/sgi-ip27/ip27-timer.c | 2 arch/mips/sgi-ip32/ip32-irq.c | 10 arch/mips/sgi-ip32/ip32-memory.c | 3 arch/mips/sibyte/bcm1480/irq.c | 2 arch/mips/sibyte/cfe/setup.c | 3 arch/mips/sibyte/sb1250/bcm1250_tbprof.c | 2 arch/mips/sibyte/sb1250/irq.c | 2 arch/mips/sibyte/sb1250/prom.c | 3 arch/mips/sni/irq.c | 2 arch/mips/sni/sniprom.c | 3 arch/mips/tx4927/common/tx4927_irq.c | 4 .../tx4927/toshiba_rbtx4927/toshiba_rbtx4927_irq.c | 12 .../toshiba_rbtx4927/toshiba_rbtx4927_prom.c | 3 .../toshiba_rbtx4927/toshiba_rbtx4927_setup.c | 2 arch/mips/tx4938/common/irq.c | 4 arch/mips/tx4938/toshiba_rbtx4938/irq.c | 2 arch/mips/tx4938/toshiba_rbtx4938/prom.c | 3 arch/mips/vr41xx/common/icu.c | 31 arch/mips/vr41xx/common/init.c | 3 arch/mips/vr41xx/common/irq.c | 18 arch/mips/vr41xx/nec-cmbvr4133/irq.c | 53 arch/parisc/Kconfig | 3 arch/parisc/kernel/perf.c | 2 arch/parisc/kernel/setup.c | 8 arch/parisc/kernel/sys_parisc32.c | 64 arch/parisc/kernel/syscall_table.S | 2 arch/parisc/kernel/time.c | 11 arch/parisc/kernel/vmlinux.lds.S | 2 arch/parisc/mm/init.c | 7 arch/powerpc/Kconfig | 60 arch/powerpc/Kconfig.debug | 18 arch/powerpc/boot/Makefile | 1 arch/powerpc/boot/dts/kuroboxHD.dts | 148 arch/powerpc/boot/dts/lite5200.dts | 135 arch/powerpc/boot/dts/lite5200b.dts | 135 arch/powerpc/boot/dts/mpc8272ads.dts | 55 arch/powerpc/boot/dts/mpc8313erdb.dts | 219 + arch/powerpc/boot/dts/mpc8323emds.dts | 345 + arch/powerpc/boot/dts/mpc8349emds.dts | 328 - arch/powerpc/boot/dts/mpc8349emitxgp.dts | 187 + arch/powerpc/boot/dts/mpc834x_mds.dts | 334 + arch/powerpc/boot/dts/mpc8560ads.dts | 10 arch/powerpc/boot/dts/mpc8568mds.dts | 380 + arch/powerpc/boot/dts/mpc866ads.dts | 162 arch/powerpc/boot/dts/mpc885ads.dts | 185 + arch/powerpc/configs/celleb_defconfig | 1408 ++++ arch/powerpc/configs/linkstation_defconfig | 118 arch/powerpc/configs/mpc8272_ads_defconfig | 848 ++ arch/powerpc/configs/mpc8313_rdb_defconfig | 1409 ++++ arch/powerpc/configs/mpc832xemds_defconfig | 1083 +++ arch/powerpc/configs/mpc834x_itx_defconfig | 237 - arch/powerpc/configs/mpc834x_itxgp_defconfig | 1174 +++ arch/powerpc/configs/mpc834x_mds_defconfig | 10 arch/powerpc/configs/mpc8360emds_defconfig | 3 arch/powerpc/configs/mpc8568mds_defconfig | 992 +++ arch/powerpc/configs/mpc866_ads_defconfig | 829 ++ arch/powerpc/configs/mpc885_ads_defconfig | 827 ++ arch/powerpc/configs/pasemi_defconfig | 1722 +++++ arch/powerpc/configs/ps3_defconfig | 269 + arch/powerpc/kernel/Makefile | 1 arch/powerpc/kernel/btext.c | 9 arch/powerpc/kernel/cpu_setup_pa6t.S | 44 arch/powerpc/kernel/cputable.c | 21 arch/powerpc/kernel/entry_64.S | 59 arch/powerpc/kernel/head_32.S | 5 arch/powerpc/kernel/head_44x.S | 2 arch/powerpc/kernel/head_64.S | 2 arch/powerpc/kernel/head_fsl_booke.S | 7 arch/powerpc/kernel/idle.c | 13 arch/powerpc/kernel/iomap.c | 20 arch/powerpc/kernel/irq.c | 8 arch/powerpc/kernel/kprobes.c | 8 arch/powerpc/kernel/legacy_serial.c | 17 arch/powerpc/kernel/lparcfg.c | 13 arch/powerpc/kernel/misc_64.S | 40 arch/powerpc/kernel/module_32.c | 7 arch/powerpc/kernel/nvram_64.c | 2 arch/powerpc/kernel/pci_32.c | 1 arch/powerpc/kernel/pci_64.c | 3 arch/powerpc/kernel/pmc.c | 37 arch/powerpc/kernel/ppc_ksyms.c | 1 arch/powerpc/kernel/proc_ppc64.c | 3 arch/powerpc/kernel/prom.c | 20 arch/powerpc/kernel/prom_init.c | 81 arch/powerpc/kernel/ptrace.c | 24 arch/powerpc/kernel/rtas-proc.c | 14 arch/powerpc/kernel/rtas_flash.c | 9 arch/powerpc/kernel/setup_32.c | 9 arch/powerpc/kernel/smp.c | 23 arch/powerpc/kernel/sys_ppc32.c | 67 arch/powerpc/kernel/sysfs.c | 141 arch/powerpc/kernel/traps.c | 111 arch/powerpc/kernel/udbg.c | 8 arch/powerpc/kernel/udbg_16550.c | 24 arch/powerpc/kernel/vdso.c | 124 arch/powerpc/kernel/vio.c | 6 arch/powerpc/kernel/vmlinux.lds.S | 4 arch/powerpc/lib/Makefile | 4 arch/powerpc/lib/dma-noncoherent.c | 418 + arch/powerpc/lib/rheap.c | 6 arch/powerpc/mm/hugetlbpage.c | 3 arch/powerpc/mm/mem.c | 27 arch/powerpc/mm/pgtable_32.c | 5 arch/powerpc/oprofile/common.c | 2 arch/powerpc/oprofile/op_model_7450.c | 10 arch/powerpc/oprofile/op_model_cell.c | 149 arch/powerpc/oprofile/op_model_fsl_booke.c | 81 arch/powerpc/oprofile/op_model_power4.c | 10 arch/powerpc/oprofile/op_model_rs64.c | 10 arch/powerpc/platforms/52xx/Makefile | 3 arch/powerpc/platforms/52xx/efika-pci.c | 119 arch/powerpc/platforms/52xx/efika-setup.c | 150 arch/powerpc/platforms/52xx/efika.c | 243 + arch/powerpc/platforms/52xx/efika.h | 19 arch/powerpc/platforms/52xx/lite5200.c | 35 arch/powerpc/platforms/52xx/mpc52xx_common.c | 4 arch/powerpc/platforms/52xx/mpc52xx_pci.c | 412 + arch/powerpc/platforms/52xx/mpc52xx_pic.c | 10 arch/powerpc/platforms/82xx/mpc82xx.c | 2 arch/powerpc/platforms/82xx/mpc82xx_ads.c | 2 arch/powerpc/platforms/82xx/pq2ads.h | 5 arch/powerpc/platforms/83xx/Kconfig | 24 arch/powerpc/platforms/83xx/Makefile | 3 arch/powerpc/platforms/83xx/misc.c | 29 arch/powerpc/platforms/83xx/mpc8313_rdb.c | 99 arch/powerpc/platforms/83xx/mpc832x_mds.c | 3 arch/powerpc/platforms/83xx/mpc834x_itx.c | 4 arch/powerpc/platforms/83xx/mpc834x_mds.c | 213 + arch/powerpc/platforms/83xx/mpc834x_sys.c | 140 arch/powerpc/platforms/83xx/mpc834x_sys.h | 23 arch/powerpc/platforms/83xx/mpc8360e_pb.c | 3 arch/powerpc/platforms/83xx/mpc83xx.h | 18 arch/powerpc/platforms/85xx/Kconfig | 13 arch/powerpc/platforms/85xx/Makefile | 1 arch/powerpc/platforms/85xx/mpc8568_mds.c | 246 + arch/powerpc/platforms/85xx/mpc85xx_ads.c | 7 arch/powerpc/platforms/85xx/mpc85xx_cds.c | 17 arch/powerpc/platforms/86xx/Kconfig | 1 arch/powerpc/platforms/86xx/mpc86xx_smp.c | 1 arch/powerpc/platforms/8xx/Kconfig | 300 - arch/powerpc/platforms/8xx/Makefile | 6 arch/powerpc/platforms/8xx/m8xx_setup.c | 303 + arch/powerpc/platforms/8xx/mpc86xads.h | 95 arch/powerpc/platforms/8xx/mpc86xads_setup.c | 301 + arch/powerpc/platforms/8xx/mpc885ads.h | 95 arch/powerpc/platforms/8xx/mpc885ads_setup.c | 387 + arch/powerpc/platforms/Makefile | 5 arch/powerpc/platforms/cell/Makefile | 7 arch/powerpc/platforms/cell/iommu.c | 5 arch/powerpc/platforms/cell/pmu.c | 14 arch/powerpc/platforms/cell/spu_base.c | 3 arch/powerpc/platforms/cell/spu_manage.c | 366 + arch/powerpc/platforms/cell/spu_priv1_mmio.c | 422 - arch/powerpc/platforms/cell/spufs/context.c | 137 arch/powerpc/platforms/cell/spufs/file.c | 184 - arch/powerpc/platforms/cell/spufs/inode.c | 6 arch/powerpc/platforms/cell/spufs/run.c | 16 arch/powerpc/platforms/cell/spufs/sched.c | 386 + arch/powerpc/platforms/cell/spufs/spufs.h | 52 arch/powerpc/platforms/celleb/Makefile | 9 arch/powerpc/platforms/celleb/beat.c | 163 arch/powerpc/platforms/celleb/beat.h | 40 arch/powerpc/platforms/celleb/beat_syscall.h | 160 arch/powerpc/platforms/celleb/beat_wrapper.h | 220 + arch/powerpc/platforms/celleb/htab.c | 308 + arch/powerpc/platforms/celleb/hvCall.S | 287 + arch/powerpc/platforms/celleb/interrupt.c | 274 + arch/powerpc/platforms/celleb/interrupt.h | 33 arch/powerpc/platforms/celleb/iommu.c | 104 arch/powerpc/platforms/celleb/pci.c | 481 + arch/powerpc/platforms/celleb/pci.h | 35 arch/powerpc/platforms/celleb/scc.h | 145 arch/powerpc/platforms/celleb/scc_epci.c | 409 + arch/powerpc/platforms/celleb/scc_sio.c | 101 arch/powerpc/platforms/celleb/scc_uhc.c | 94 arch/powerpc/platforms/celleb/setup.c | 191 + arch/powerpc/platforms/celleb/smp.c | 124 arch/powerpc/platforms/celleb/spu_priv1.c | 208 + arch/powerpc/platforms/celleb/udbg_beat.c | 97 arch/powerpc/platforms/chrp/setup.c | 4 arch/powerpc/platforms/embedded6xx/Kconfig | 9 arch/powerpc/platforms/embedded6xx/linkstation.c | 12 arch/powerpc/platforms/iseries/lpevents.c | 2 arch/powerpc/platforms/iseries/mf.c | 6 arch/powerpc/platforms/iseries/proc.c | 2 arch/powerpc/platforms/iseries/viopath.c | 2 arch/powerpc/platforms/maple/pci.c | 23 arch/powerpc/platforms/maple/setup.c | 3 arch/powerpc/platforms/pasemi/Kconfig | 10 arch/powerpc/platforms/pasemi/Makefile | 3 arch/powerpc/platforms/pasemi/idle.c | 88 arch/powerpc/platforms/pasemi/iommu.c | 281 + arch/powerpc/platforms/pasemi/pasemi.h | 12 arch/powerpc/platforms/pasemi/pci.c | 13 arch/powerpc/platforms/pasemi/powersave.S | 80 arch/powerpc/platforms/pasemi/setup.c | 105 arch/powerpc/platforms/powermac/pic.c | 2 arch/powerpc/platforms/powermac/setup.c | 4 arch/powerpc/platforms/powermac/smp.c | 1 arch/powerpc/platforms/ps3/Kconfig | 11 arch/powerpc/platforms/ps3/Makefile | 1 arch/powerpc/platforms/ps3/htab.c | 7 arch/powerpc/platforms/ps3/interrupt.c | 444 + arch/powerpc/platforms/ps3/mm.c | 1 arch/powerpc/platforms/ps3/os-area.c | 22 arch/powerpc/platforms/ps3/platform.h | 151 arch/powerpc/platforms/ps3/repository.c | 220 + arch/powerpc/platforms/ps3/setup.c | 61 arch/powerpc/platforms/ps3/smp.c | 3 arch/powerpc/platforms/ps3/spu.c | 62 arch/powerpc/platforms/ps3/system-bus.c | 384 + arch/powerpc/platforms/pseries/Makefile | 1 arch/powerpc/platforms/pseries/eeh.c | 21 arch/powerpc/platforms/pseries/eeh_driver.c | 3 arch/powerpc/platforms/pseries/firmware.c | 1 arch/powerpc/platforms/pseries/firmware.h | 17 arch/powerpc/platforms/pseries/hvCall_inst.c | 2 arch/powerpc/platforms/pseries/kexec.c | 72 arch/powerpc/platforms/pseries/lpar.c | 55 arch/powerpc/platforms/pseries/pci.c | 6 arch/powerpc/platforms/pseries/pseries.h | 36 arch/powerpc/platforms/pseries/ras.c | 2 arch/powerpc/platforms/pseries/ras.h | 9 arch/powerpc/platforms/pseries/reconfig.c | 3 arch/powerpc/platforms/pseries/rtasd.c | 2 arch/powerpc/platforms/pseries/scanlog.c | 2 arch/powerpc/platforms/pseries/setup.c | 60 arch/powerpc/platforms/pseries/smp.c | 1 arch/powerpc/sysdev/Makefile | 2 arch/powerpc/sysdev/commproc.c | 398 + arch/powerpc/sysdev/cpm2_pic.c | 154 arch/powerpc/sysdev/cpm2_pic.h | 2 arch/powerpc/sysdev/fsl_soc.c | 352 + arch/powerpc/sysdev/grackle.c | 2 arch/powerpc/sysdev/ipic.c | 17 arch/powerpc/sysdev/micropatch.c | 743 ++ arch/powerpc/sysdev/mpc8xx_pic.c | 197 + arch/powerpc/sysdev/mpc8xx_pic.h | 12 arch/powerpc/sysdev/mpic.c | 87 arch/powerpc/sysdev/qe_lib/qe_ic.c | 6 arch/powerpc/sysdev/qe_lib/ucc_slow.c | 6 arch/powerpc/xmon/ppc-opc.c | 7 arch/powerpc/xmon/spu-dis.c | 2 arch/powerpc/xmon/spu-opc.c | 4 arch/powerpc/xmon/xmon.c | 1 arch/ppc/8xx_io/cs4218_tdm.c | 7 arch/ppc/Kconfig | 13 arch/ppc/boot/simple/Makefile | 4 arch/ppc/boot/simple/misc.c | 15 arch/ppc/configs/gemini_defconfig | 618 -- arch/ppc/configs/taishan_defconfig | 1077 +++ arch/ppc/kernel/Makefile | 1 arch/ppc/kernel/dma-mapping.c | 442 - arch/ppc/kernel/head.S | 18 arch/ppc/kernel/head_fsl_booke.S | 7 arch/ppc/kernel/ppc_htab.c | 13 arch/ppc/kernel/ppc_ksyms.c | 3 arch/ppc/kernel/setup.c | 2 arch/ppc/kernel/vmlinux.lds.S | 2 arch/ppc/lib/rheap.c | 3 arch/ppc/mm/pgtable.c | 5 arch/ppc/platforms/4xx/Kconfig | 10 arch/ppc/platforms/4xx/Makefile | 1 arch/ppc/platforms/4xx/taishan.c | 395 + arch/ppc/platforms/4xx/taishan.h | 67 arch/ppc/platforms/Makefile | 1 arch/ppc/platforms/gemini.h | 165 arch/ppc/platforms/gemini_pci.c | 41 arch/ppc/platforms/gemini_prom.S | 90 arch/ppc/platforms/gemini_serial.h | 40 arch/ppc/platforms/gemini_setup.c | 577 -- arch/ppc/platforms/lopec.c | 2 arch/ppc/platforms/mpc866ads_setup.c | 2 arch/ppc/platforms/pplus.c | 2 arch/ppc/platforms/prep_setup.c | 4 arch/ppc/syslib/Makefile | 2 arch/ppc/syslib/i8259.c | 2 arch/ppc/syslib/m8260_pci_erratum9.c | 3 arch/ppc/syslib/m8xx_setup.c | 2 arch/ppc/syslib/ppc85xx_rio.c | 2 arch/ppc/xmon/ppc-opc.c | 7 arch/ppc/xmon/start.c | 5 arch/s390/Kconfig | 36 arch/s390/appldata/appldata.h | 3 arch/s390/appldata/appldata_base.c | 6 arch/s390/appldata/appldata_mem.c | 2 arch/s390/appldata/appldata_net_sum.c | 2 arch/s390/crypto/Kconfig | 60 arch/s390/crypto/Makefile | 3 arch/s390/crypto/aes_s390.c | 47 arch/s390/crypto/crypt_s390.h | 281 - arch/s390/crypto/crypt_s390_query.c | 129 arch/s390/crypto/des_check_key.c | 6 arch/s390/crypto/des_s390.c | 8 arch/s390/crypto/prng.c | 213 + arch/s390/crypto/sha1_s390.c | 83 arch/s390/crypto/sha256_s390.c | 11 arch/s390/defconfig | 15 arch/s390/hypfs/Makefile | 2 arch/s390/hypfs/hypfs.h | 9 arch/s390/hypfs/hypfs_diag.h | 16 arch/s390/hypfs/hypfs_vm.c | 231 + arch/s390/hypfs/inode.c | 35 arch/s390/kernel/Makefile | 4 arch/s390/kernel/base.S | 150 arch/s390/kernel/binfmt_elf32.c | 2 arch/s390/kernel/compat_exec_domain.c | 5 arch/s390/kernel/compat_linux.c | 67 arch/s390/kernel/compat_linux.h | 31 arch/s390/kernel/compat_signal.c | 8 arch/s390/kernel/compat_wrapper.S | 6 arch/s390/kernel/cpcmd.c | 14 arch/s390/kernel/crash.c | 1 arch/s390/kernel/debug.c | 23 arch/s390/kernel/early.c | 306 + arch/s390/kernel/ebcdic.c | 1 arch/s390/kernel/head31.S | 194 - arch/s390/kernel/head64.S | 193 - arch/s390/kernel/ipl.c | 106 arch/s390/kernel/irq.c | 15 arch/s390/kernel/kprobes.c | 32 arch/s390/kernel/machine_kexec.c | 1 arch/s390/kernel/module.c | 5 arch/s390/kernel/process.c | 4 arch/s390/kernel/profile.c | 20 arch/s390/kernel/ptrace.c | 46 arch/s390/kernel/reset.S | 90 arch/s390/kernel/s390_ext.c | 8 arch/s390/kernel/setup.c | 157 arch/s390/kernel/signal.c | 2 arch/s390/kernel/smp.c | 47 arch/s390/kernel/stacktrace.c | 10 arch/s390/kernel/syscalls.S | 2 arch/s390/kernel/time.c | 1187 +++ arch/s390/kernel/traps.c | 24 arch/s390/kernel/vmlinux.lds.S | 16 arch/s390/kernel/vtime.c | 10 arch/s390/lib/Makefile | 2 arch/s390/lib/delay.c | 48 arch/s390/lib/qrnnd.S | 77 arch/s390/lib/uaccess.h | 23 arch/s390/lib/uaccess_mvcos.c | 78 arch/s390/lib/uaccess_pt.c | 329 + arch/s390/lib/uaccess_std.c | 23 arch/s390/math-emu/Makefile | 2 arch/s390/math-emu/math.c | 2 arch/s390/math-emu/qrnnd.S | 77 arch/s390/math-emu/sfp-util.h | 66 arch/s390/mm/Makefile | 2 arch/s390/mm/cmm.c | 10 arch/s390/mm/extmem.c | 66 arch/s390/mm/fault.c | 97 arch/s390/mm/init.c | 20 arch/s390/mm/ioremap.c | 58 arch/s390/mm/vmem.c | 14 arch/sh/Kconfig | 24 arch/sh/Makefile | 3 arch/sh/boards/bigsur/Makefile | 6 arch/sh/boards/bigsur/io.c | 120 arch/sh/boards/bigsur/irq.c | 334 - arch/sh/boards/bigsur/led.c | 54 arch/sh/boards/bigsur/setup.c | 88 arch/sh/boards/ec3104/Makefile | 6 arch/sh/boards/ec3104/io.c | 81 arch/sh/boards/ec3104/irq.c | 196 - arch/sh/boards/ec3104/setup.c | 65 arch/sh/boards/hp6xx/hp6xx_apm.c | 68 arch/sh/boards/landisk/landisk_pwb.c | 2 arch/sh/boards/mpc1211/Makefile | 2 arch/sh/boards/mpc1211/led.c | 63 arch/sh/boards/mpc1211/setup.c | 31 arch/sh/boards/renesas/r7780rp/Makefile | 1 arch/sh/boards/renesas/r7780rp/io.c | 152 arch/sh/boards/renesas/r7780rp/led.c | 43 arch/sh/boards/renesas/r7780rp/setup.c | 49 arch/sh/boards/renesas/rts7751r2d/Makefile | 3 arch/sh/boards/renesas/rts7751r2d/io.c | 302 - arch/sh/boards/renesas/rts7751r2d/irq.c | 80 arch/sh/boards/renesas/rts7751r2d/led.c | 44 arch/sh/boards/renesas/rts7751r2d/setup.c | 142 arch/sh/boards/se/7206/Makefile | 2 arch/sh/boards/se/7206/led.c | 57 arch/sh/boards/se/7206/setup.c | 34 arch/sh/boards/se/7300/Makefile | 2 arch/sh/boards/se/7300/led.c | 54 arch/sh/boards/se/7300/setup.c | 36 arch/sh/boards/se/73180/Makefile | 2 arch/sh/boards/se/73180/led.c | 53 arch/sh/boards/se/73180/setup.c | 31 arch/sh/boards/se/7343/Makefile | 2 arch/sh/boards/se/7343/led.c | 44 arch/sh/boards/se/7343/setup.c | 26 arch/sh/boards/se/770x/Makefile | 1 arch/sh/boards/se/770x/irq.c | 108 arch/sh/boards/se/770x/led.c | 52 arch/sh/boards/se/770x/setup.c | 43 arch/sh/boards/se/7751/Makefile | 1 arch/sh/boards/se/7751/led.c | 51 arch/sh/boards/se/7751/setup.c | 36 arch/sh/boards/sh03/Makefile | 1 arch/sh/boards/sh03/led.c | 48 arch/sh/boards/sh03/setup.c | 30 arch/sh/boards/shmin/setup.c | 12 arch/sh/cchips/voyagergx/irq.c | 70 arch/sh/cchips/voyagergx/setup.c | 4 arch/sh/configs/rts7751r2d_defconfig | 308 + arch/sh/configs/se7750_defconfig | 140 arch/sh/drivers/Makefile | 1 arch/sh/drivers/dma/dma-sh.c | 45 arch/sh/drivers/heartbeat.c | 132 arch/sh/drivers/pci/Makefile | 1 arch/sh/drivers/pci/ops-bigsur.c | 83 arch/sh/drivers/pci/pci-sh7751.c | 9 arch/sh/kernel/Makefile | 4 arch/sh/kernel/apm.c | 538 -- arch/sh/kernel/cpu/init.c | 41 arch/sh/kernel/cpu/irq/ipr.c | 19 arch/sh/kernel/cpu/sh2/entry.S | 12 arch/sh/kernel/cpu/sh2/probe.c | 32 arch/sh/kernel/cpu/sh2/setup-sh7619.c | 62 arch/sh/kernel/cpu/sh2a/probe.c | 16 arch/sh/kernel/cpu/sh2a/setup-sh7206.c | 89 arch/sh/kernel/cpu/sh3/entry.S | 207 - arch/sh/kernel/cpu/sh3/probe.c | 42 arch/sh/kernel/cpu/sh3/setup-sh7709.c | 21 arch/sh/kernel/cpu/sh4/probe.c | 183 - arch/sh/kernel/cpu/sh4/setup-sh7750.c | 4 arch/sh/kernel/cpu/sh4/setup-sh7760.c | 66 arch/sh/kernel/debugtraps.S | 41 arch/sh/kernel/early_printk.c | 24 arch/sh/kernel/entry-common.S | 119 arch/sh/kernel/io_generic.c | 12 arch/sh/kernel/kgdb_stub.c | 7 arch/sh/kernel/process.c | 95 arch/sh/kernel/setup.c | 55 arch/sh/kernel/sh_ksyms.c | 1 arch/sh/kernel/signal.c | 6 arch/sh/kernel/syscalls.S | 8 arch/sh/kernel/time.c | 8 arch/sh/kernel/traps.c | 4 arch/sh/kernel/vmlinux.lds.S | 4 arch/sh/kernel/vsyscall/vsyscall.c | 58 arch/sh/mm/Kconfig | 5 arch/sh/mm/cache-debugfs.c | 6 arch/sh/mm/cache-sh3.c | 8 arch/sh/mm/cache-sh4.c | 77 arch/sh/mm/cache-sh7705.c | 29 arch/sh/mm/fault.c | 87 arch/sh/mm/init.c | 24 arch/sh/mm/ioremap.c | 6 arch/sh/mm/pg-sh4.c | 28 arch/sh/mm/pg-sh7705.c | 37 arch/sh/mm/pmb.c | 2 arch/sh/mm/tlb-flush.c | 101 arch/sh/mm/tlb-nommu.c | 19 arch/sh/mm/tlb-sh3.c | 67 arch/sh/mm/tlb-sh4.c | 70 arch/sh/oprofile/op_model_sh7750.c | 4 arch/sh/tools/mach-types | 1 arch/sh64/Kconfig | 3 arch/sh64/kernel/setup.c | 6 arch/sh64/kernel/time.c | 9 arch/sh64/kernel/traps.c | 51 arch/sh64/kernel/vmlinux.lds.S | 4 arch/sh64/mm/init.c | 5 arch/sparc/Kconfig | 4 arch/sparc/kernel/Makefile | 4 arch/sparc/kernel/apc.c | 2 arch/sparc/kernel/setup.c | 2 arch/sparc/kernel/sunos_ioctl.c | 1 arch/sparc/kernel/sys_sunos.c | 10 arch/sparc/kernel/time.c | 9 arch/sparc/kernel/vmlinux.lds.S | 4 arch/sparc64/Kconfig | 4 arch/sparc64/defconfig | 52 arch/sparc64/kernel/irq.c | 146 arch/sparc64/kernel/pci.c | 35 arch/sparc64/kernel/pci_common.c | 25 arch/sparc64/kernel/pci_sun4v.c | 444 + arch/sparc64/kernel/pci_sun4v.h | 61 arch/sparc64/kernel/pci_sun4v_asm.S | 266 + arch/sparc64/kernel/setup.c | 2 arch/sparc64/kernel/sunos_ioctl32.c | 1 arch/sparc64/kernel/sys_sparc32.c | 64 arch/sparc64/kernel/sys_sunos32.c | 11 arch/sparc64/kernel/systbls.S | 2 arch/sparc64/kernel/time.c | 2 arch/sparc64/kernel/vmlinux.lds.S | 4 arch/sparc64/mm/init.c | 8 arch/sparc64/solaris/socksys.c | 2 arch/um/Kconfig | 3 arch/um/drivers/chan_kern.c | 103 arch/um/drivers/harddog_kern.c | 58 arch/um/drivers/harddog_user.c | 23 arch/um/drivers/hostaudio_kern.c | 169 arch/um/drivers/line.c | 209 - arch/um/drivers/mconsole_kern.c | 62 arch/um/drivers/mconsole_user.c | 2 arch/um/drivers/net_kern.c | 172 arch/um/drivers/port_kern.c | 50 arch/um/drivers/port_user.c | 51 arch/um/drivers/random.c | 1 arch/um/drivers/ssl.c | 44 arch/um/drivers/stdio_console.c | 51 arch/um/drivers/ubd_kern.c | 231 - arch/um/include/chan_kern.h | 5 arch/um/include/chan_user.h | 21 arch/um/include/kern_util.h | 5 arch/um/include/line.h | 57 arch/um/include/mconsole_kern.h | 17 arch/um/include/net_kern.h | 14 arch/um/include/os.h | 3 arch/um/include/sigio.h | 11 arch/um/include/tempfile.h | 10 arch/um/include/umid.h | 22 arch/um/include/user_util.h | 2 arch/um/kernel/Makefile | 2 arch/um/kernel/exec.c | 2 arch/um/kernel/irq.c | 7 arch/um/kernel/mem.c | 90 arch/um/kernel/physmem.c | 74 arch/um/kernel/ptrace.c | 7 arch/um/kernel/resource.c | 23 arch/um/kernel/sigio.c | 7 arch/um/kernel/skas/mem.c | 6 arch/um/kernel/syscall.c | 16 arch/um/kernel/sysrq.c | 2 arch/um/kernel/time.c | 24 arch/um/kernel/trap.c | 28 arch/um/kernel/tt/gdb.c | 4 arch/um/kernel/tt/gdb_kern.c | 5 arch/um/kernel/um_arch.c | 9 arch/um/kernel/umid.c | 4 arch/um/os-Linux/aio.c | 16 arch/um/os-Linux/elf_aux.c | 3 arch/um/os-Linux/file.c | 19 arch/um/os-Linux/irq.c | 6 arch/um/os-Linux/mem.c | 16 arch/um/os-Linux/sigio.c | 38 arch/um/os-Linux/start_up.c | 207 - arch/um/os-Linux/sys-i386/registers.c | 14 arch/um/os-Linux/sys-x86_64/Makefile | 2 arch/um/os-Linux/sys-x86_64/prctl.c | 12 arch/um/os-Linux/sys-x86_64/registers.c | 6 arch/um/os-Linux/umid.c | 3 arch/um/sys-x86_64/ptrace.c | 5 arch/um/sys-x86_64/syscalls.c | 75 arch/um/sys-x86_64/tls.c | 11 arch/v850/Kconfig | 3 arch/v850/kernel/anna.c | 2 arch/v850/kernel/as85ep1.c | 2 arch/v850/kernel/fpga85e2c.c | 2 arch/v850/kernel/gbus_int.c | 6 arch/v850/kernel/ma.c | 2 arch/v850/kernel/me2.c | 2 arch/v850/kernel/rte_cb.c | 4 arch/v850/kernel/rte_cb_leds.c | 2 arch/v850/kernel/rte_mb_a_pci.c | 3 arch/v850/kernel/rte_me2_cb.c | 3 arch/v850/kernel/setup.c | 6 arch/v850/kernel/teg.c | 2 arch/v850/kernel/time.c | 8 arch/v850/kernel/vmlinux.lds.S | 4 arch/x86_64/Kconfig | 34 arch/x86_64/defconfig | 45 arch/x86_64/ia32/ia32_binfmt.c | 34 arch/x86_64/ia32/ia32_signal.c | 11 arch/x86_64/ia32/ia32entry.S | 3 arch/x86_64/ia32/sys_ia32.c | 66 arch/x86_64/ia32/syscall32.c | 59 arch/x86_64/kernel/Makefile | 6 arch/x86_64/kernel/acpi/sleep.c | 2 arch/x86_64/kernel/apic.c | 5 arch/x86_64/kernel/e820.c | 38 arch/x86_64/kernel/early-quirks.c | 4 arch/x86_64/kernel/genapic.c | 4 arch/x86_64/kernel/head.S | 20 arch/x86_64/kernel/head64.c | 4 arch/x86_64/kernel/hpet.c | 511 + arch/x86_64/kernel/i8259.c | 1 arch/x86_64/kernel/io_apic.c | 45 arch/x86_64/kernel/ioport.c | 2 arch/x86_64/kernel/irq.c | 12 arch/x86_64/kernel/mce.c | 68 arch/x86_64/kernel/mce_amd.c | 46 arch/x86_64/kernel/mpparse.c | 2 arch/x86_64/kernel/nmi.c | 75 arch/x86_64/kernel/pci-calgary.c | 17 arch/x86_64/kernel/pci-dma.c | 28 arch/x86_64/kernel/pci-gart.c | 4 arch/x86_64/kernel/pci-swiotlb.c | 2 arch/x86_64/kernel/pmtimer.c | 58 arch/x86_64/kernel/ptrace.c | 8 arch/x86_64/kernel/setup.c | 175 arch/x86_64/kernel/setup64.c | 1 arch/x86_64/kernel/smpboot.c | 231 - arch/x86_64/kernel/stacktrace.c | 5 arch/x86_64/kernel/time.c | 971 --- arch/x86_64/kernel/tsc.c | 226 + arch/x86_64/kernel/tsc_sync.c | 187 + arch/x86_64/kernel/vmlinux.lds.S | 32 arch/x86_64/kernel/vsyscall.c | 127 arch/x86_64/kernel/x8664_ksyms.c | 5 arch/x86_64/lib/Makefile | 2 arch/x86_64/lib/copy_user_nocache.S | 217 + arch/x86_64/mm/fault.c | 39 arch/x86_64/mm/init.c | 24 arch/x86_64/mm/numa.c | 202 - arch/x86_64/mm/pageattr.c | 4 arch/x86_64/mm/srat.c | 48 arch/x86_64/pci/Makefile | 3 arch/x86_64/pci/mmconfig.c | 123 arch/xtensa/Kconfig | 7 arch/xtensa/kernel/setup.c | 6 arch/xtensa/kernel/time.c | 9 arch/xtensa/kernel/vmlinux.lds.S | 2 block/blktrace.c | 5 block/cfq-iosched.c | 297 - block/elevator.c | 31 block/genhd.c | 8 block/ioctl.c | 2 block/ll_rw_blk.c | 2 crypto/Kconfig | 72 crypto/Makefile | 3 crypto/algapi.c | 15 crypto/api.c | 80 crypto/blkcipher.c | 9 crypto/camellia.c | 1801 +++++ crypto/cbc.c | 9 crypto/cipher.c | 447 - crypto/compress.c | 5 crypto/digest.c | 24 crypto/ecb.c | 9 crypto/fcrypt.c | 423 + crypto/hash.c | 5 crypto/hmac.c | 9 crypto/internal.h | 27 crypto/lrw.c | 11 crypto/pcbc.c | 349 + crypto/proc.c | 2 crypto/tcrypt.c | 73 crypto/tcrypt.h | 538 ++ crypto/xcbc.c | 60 drivers/Kconfig | 2 drivers/Makefile | 3 drivers/acorn/block/mfmhd.c | 1 drivers/acorn/char/i2c.c | 3 drivers/acpi/Kconfig | 37 drivers/acpi/Makefile | 5 drivers/acpi/asus_acpi.c | 9 drivers/acpi/battery.c | 4 drivers/acpi/bay.c | 490 + drivers/acpi/blacklist.c | 29 drivers/acpi/bus.c | 44 drivers/acpi/button.c | 2 drivers/acpi/container.c | 6 drivers/acpi/debug.c | 62 drivers/acpi/dispatcher/dsfield.c | 32 drivers/acpi/dispatcher/dsinit.c | 25 drivers/acpi/dispatcher/dsmethod.c | 55 drivers/acpi/dispatcher/dsmthdat.c | 2 drivers/acpi/dispatcher/dsobject.c | 78 drivers/acpi/dispatcher/dsopcode.c | 6 drivers/acpi/dispatcher/dsutils.c | 2 drivers/acpi/dispatcher/dswexec.c | 12 drivers/acpi/dispatcher/dswload.c | 19 drivers/acpi/dispatcher/dswscope.c | 2 drivers/acpi/dispatcher/dswstate.c | 2 drivers/acpi/dock.c | 16 drivers/acpi/ec.c | 13 drivers/acpi/events/evevent.c | 17 drivers/acpi/events/evgpe.c | 91 drivers/acpi/events/evgpeblk.c | 64 drivers/acpi/events/evmisc.c | 201 - drivers/acpi/events/evregion.c | 17 drivers/acpi/events/evrgnini.c | 168 drivers/acpi/events/evsci.c | 14 drivers/acpi/events/evxface.c | 8 drivers/acpi/events/evxfevnt.c | 27 drivers/acpi/events/evxfregn.c | 2 drivers/acpi/executer/exconfig.c | 235 - drivers/acpi/executer/exconvrt.c | 2 drivers/acpi/executer/excreate.c | 21 drivers/acpi/executer/exdump.c | 29 drivers/acpi/executer/exfield.c | 2 drivers/acpi/executer/exfldio.c | 7 drivers/acpi/executer/exmisc.c | 2 drivers/acpi/executer/exmutex.c | 86 drivers/acpi/executer/exnames.c | 2 drivers/acpi/executer/exoparg1.c | 4 drivers/acpi/executer/exoparg2.c | 2 drivers/acpi/executer/exoparg3.c | 2 drivers/acpi/executer/exoparg6.c | 2 drivers/acpi/executer/exprep.c | 2 drivers/acpi/executer/exregion.c | 16 drivers/acpi/executer/exresnte.c | 2 drivers/acpi/executer/exresolv.c | 10 drivers/acpi/executer/exresop.c | 12 drivers/acpi/executer/exstore.c | 2 drivers/acpi/executer/exstoren.c | 2 drivers/acpi/executer/exstorob.c | 2 drivers/acpi/executer/exsystem.c | 110 drivers/acpi/executer/exutils.c | 106 drivers/acpi/fan.c | 8 drivers/acpi/glue.c | 123 drivers/acpi/hardware/hwacpi.c | 56 drivers/acpi/hardware/hwgpe.c | 15 drivers/acpi/hardware/hwregs.c | 98 drivers/acpi/hardware/hwsleep.c | 81 drivers/acpi/hardware/hwtimer.c | 9 drivers/acpi/i2c_ec.c | 2 drivers/acpi/motherboard.c | 191 - drivers/acpi/namespace/nsaccess.c | 36 drivers/acpi/namespace/nsalloc.c | 14 drivers/acpi/namespace/nsdump.c | 13 drivers/acpi/namespace/nsdumpdv.c | 2 drivers/acpi/namespace/nseval.c | 13 drivers/acpi/namespace/nsinit.c | 18 drivers/acpi/namespace/nsload.c | 160 drivers/acpi/namespace/nsnames.c | 2 drivers/acpi/namespace/nsobject.c | 2 drivers/acpi/namespace/nsparse.c | 52 drivers/acpi/namespace/nssearch.c | 9 drivers/acpi/namespace/nsutils.c | 9 drivers/acpi/namespace/nswalk.c | 65 drivers/acpi/namespace/nsxfeval.c | 13 drivers/acpi/namespace/nsxfname.c | 47 drivers/acpi/namespace/nsxfobj.c | 2 drivers/acpi/numa.c | 77 drivers/acpi/osl.c | 97 drivers/acpi/parser/psargs.c | 2 drivers/acpi/parser/psloop.c | 1408 ++-- drivers/acpi/parser/psopcode.c | 2 drivers/acpi/parser/psparse.c | 7 drivers/acpi/parser/psscope.c | 2 drivers/acpi/parser/pstree.c | 2 drivers/acpi/parser/psutils.c | 2 drivers/acpi/parser/pswalk.c | 2 drivers/acpi/parser/psxface.c | 116 drivers/acpi/pci_link.c | 4 drivers/acpi/pci_root.c | 38 drivers/acpi/processor_core.c | 189 - drivers/acpi/processor_idle.c | 166 drivers/acpi/processor_perflib.c | 27 drivers/acpi/processor_throttling.c | 4 drivers/acpi/resources/rsaddr.c | 2 drivers/acpi/resources/rscalc.c | 2 drivers/acpi/resources/rscreate.c | 2 drivers/acpi/resources/rsdump.c | 2 drivers/acpi/resources/rsinfo.c | 2 drivers/acpi/resources/rsio.c | 2 drivers/acpi/resources/rsirq.c | 2 drivers/acpi/resources/rslist.c | 2 drivers/acpi/resources/rsmemory.c | 2 drivers/acpi/resources/rsmisc.c | 2 drivers/acpi/resources/rsutils.c | 2 drivers/acpi/resources/rsxface.c | 2 drivers/acpi/scan.c | 1265 ++-- drivers/acpi/sleep/poweroff.c | 1 drivers/acpi/sleep/proc.c | 36 drivers/acpi/system.c | 39 drivers/acpi/tables.c | 509 - drivers/acpi/tables/Makefile | 3 drivers/acpi/tables/tbconvrt.c | 622 -- drivers/acpi/tables/tbfadt.c | 434 + drivers/acpi/tables/tbfind.c | 126 drivers/acpi/tables/tbget.c | 471 - drivers/acpi/tables/tbgetall.c | 311 - drivers/acpi/tables/tbinstal.c | 664 +- drivers/acpi/tables/tbrsdt.c | 307 - drivers/acpi/tables/tbutils.c | 513 + drivers/acpi/tables/tbxface.c | 671 +- drivers/acpi/tables/tbxfroot.c | 552 -- drivers/acpi/thermal.c | 7 drivers/acpi/utilities/utalloc.c | 11 drivers/acpi/utilities/utcache.c | 10 drivers/acpi/utilities/utcopy.c | 11 drivers/acpi/utilities/utdebug.c | 7 drivers/acpi/utilities/utdelete.c | 16 drivers/acpi/utilities/uteval.c | 2 drivers/acpi/utilities/utglobal.c | 199 - drivers/acpi/utilities/utinit.c | 114 drivers/acpi/utilities/utmath.c | 2 drivers/acpi/utilities/utmisc.c | 102 drivers/acpi/utilities/utmutex.c | 2 drivers/acpi/utilities/utobject.c | 2 drivers/acpi/utilities/utresrc.c | 2 drivers/acpi/utilities/utstate.c | 2 drivers/acpi/utilities/utxface.c | 29 drivers/acpi/video.c | 166 drivers/ata/Kconfig | 41 drivers/ata/Makefile | 3 drivers/ata/ahci.c | 239 - drivers/ata/ata_generic.c | 8 drivers/ata/ata_piix.c | 56 drivers/ata/libata-core.c | 602 +- drivers/ata/libata-eh.c | 7 drivers/ata/libata-scsi.c | 98 drivers/ata/libata-sff.c | 641 +- drivers/ata/libata.h | 4 drivers/ata/pata_ali.c | 32 drivers/ata/pata_amd.c | 36 drivers/ata/pata_artop.c | 12 drivers/ata/pata_atiixp.c | 6 drivers/ata/pata_cmd64x.c | 18 drivers/ata/pata_cs5520.c | 41 drivers/ata/pata_cs5530.c | 41 drivers/ata/pata_cs5535.c | 6 drivers/ata/pata_cypress.c | 6 drivers/ata/pata_efar.c | 6 drivers/ata/pata_hpt366.c | 26 drivers/ata/pata_hpt37x.c | 61 drivers/ata/pata_hpt3x2n.c | 26 drivers/ata/pata_hpt3x3.c | 8 drivers/ata/pata_isapnp.c | 21 drivers/ata/pata_it8213.c | 354 + drivers/ata/pata_it821x.c | 58 drivers/ata/pata_ixp4xx_cf.c | 50 drivers/ata/pata_jmicron.c | 8 drivers/ata/pata_legacy.c | 177 - drivers/ata/pata_marvell.c | 12 drivers/ata/pata_mpc52xx.c | 536 ++ drivers/ata/pata_mpiix.c | 113 drivers/ata/pata_netcell.c | 6 drivers/ata/pata_ns87410.c | 6 drivers/ata/pata_oldpiix.c | 24 drivers/ata/pata_opti.c | 24 drivers/ata/pata_optidma.c | 40 drivers/ata/pata_pcmcia.c | 29 drivers/ata/pata_pdc2027x.c | 124 drivers/ata/pata_pdc202xx_old.c | 41 drivers/ata/pata_platform.c | 67 drivers/ata/pata_qdi.c | 54 drivers/ata/pata_radisys.c | 6 drivers/ata/pata_rz1000.c | 6 drivers/ata/pata_sc1200.c | 6 drivers/ata/pata_serverworks.c | 31 drivers/ata/pata_sil680.c | 8 drivers/ata/pata_sis.c | 70 drivers/ata/pata_sl82c105.c | 13 drivers/ata/pata_triflex.c | 6 drivers/ata/pata_via.c | 22 drivers/ata/pata_winbond.c | 49 drivers/ata/pdc_adma.c | 121 drivers/ata/sata_inic162x.c | 781 ++ drivers/ata/sata_mv.c | 201 - drivers/ata/sata_nv.c | 633 +- drivers/ata/sata_promise.c | 444 + drivers/ata/sata_qstor.c | 139 drivers/ata/sata_sil.c | 99 drivers/ata/sata_sil24.c | 178 - drivers/ata/sata_sis.c | 161 drivers/ata/sata_svw.c | 133 drivers/ata/sata_sx4.c | 208 - drivers/ata/sata_uli.c | 66 drivers/ata/sata_via.c | 193 - drivers/ata/sata_vsc.c | 142 drivers/atm/adummy.c | 1 drivers/atm/eni.c | 1 drivers/atm/fore200e.c | 1 drivers/atm/idt77105.c | 1 drivers/atm/uPD98402.c | 1 drivers/atm/zatm.c | 1 drivers/auxdisplay/Kconfig | 109 drivers/auxdisplay/Makefile | 6 drivers/auxdisplay/cfag12864b.c | 383 + drivers/auxdisplay/cfag12864bfb.c | 180 + drivers/auxdisplay/ks0108.c | 166 drivers/base/Kconfig | 12 drivers/base/Makefile | 1 drivers/base/base.h | 1 drivers/base/class.c | 21 drivers/base/core.c | 205 - drivers/base/dd.c | 24 drivers/base/devres.c | 644 ++ drivers/base/dma-mapping.c | 218 + drivers/base/dmapool.c | 59 drivers/base/firmware_class.c | 2 drivers/base/node.c | 9 drivers/base/platform.c | 11 drivers/block/DAC960.c | 101 drivers/block/DAC960.h | 495 + drivers/block/Kconfig | 4 drivers/block/acsi.c | 1 drivers/block/acsi_slm.c | 2 drivers/block/aoe/aoechr.c | 2 drivers/block/paride/Kconfig | 8 drivers/block/paride/pd.c | 1 drivers/block/paride/pg.c | 2 drivers/block/paride/pt.c | 2 drivers/block/pktcdvd.c | 32 drivers/block/umem.c | 1 drivers/bluetooth/bfusb.c | 1 drivers/bluetooth/bt3c_cs.c | 1 drivers/bluetooth/btuart_cs.c | 1 drivers/bluetooth/dtl1_cs.c | 1 drivers/bluetooth/hci_bcsp.c | 1 drivers/bluetooth/hci_h4.c | 1 drivers/bluetooth/hci_ldisc.c | 1 drivers/bluetooth/hci_usb.c | 1 drivers/bluetooth/hci_vhci.c | 2 drivers/cdrom/aztcd.c | 1 drivers/cdrom/cdrom.c | 4 drivers/cdrom/cm206.c | 1 drivers/cdrom/gscd.c | 1 drivers/cdrom/sjcd.c | 1 drivers/cdrom/viocd.c | 2 drivers/char/Kconfig | 11 drivers/char/Makefile | 3 drivers/char/agp/Makefile | 1 drivers/char/agp/agp.h | 12 drivers/char/agp/ali-agp.c | 2 drivers/char/agp/alpha-agp.c | 4 drivers/char/agp/amd-k7-agp.c | 1 drivers/char/agp/amd64-agp.c | 11 drivers/char/agp/ati-agp.c | 1 drivers/char/agp/backend.c | 2 drivers/char/agp/compat_ioctl.c | 282 + drivers/char/agp/compat_ioctl.h | 105 drivers/char/agp/efficeon-agp.c | 1 drivers/char/agp/frontend.c | 34 drivers/char/agp/generic.c | 125 drivers/char/agp/hp-agp.c | 1 drivers/char/agp/i460-agp.c | 7 drivers/char/agp/intel-agp.c | 202 - drivers/char/agp/nvidia-agp.c | 1 drivers/char/agp/parisc-agp.c | 1 drivers/char/agp/sgi-agp.c | 1 drivers/char/agp/sis-agp.c | 1 drivers/char/agp/sworks-agp.c | 1 drivers/char/agp/uninorth-agp.c | 2 drivers/char/agp/via-agp.c | 2 drivers/char/amiserial.c | 8 drivers/char/apm-emulation.c | 672 ++ drivers/char/briq_panel.c | 3 drivers/char/cyclades.c | 24 drivers/char/drm/drmP.h | 36 drivers/char/drm/drm_bufs.c | 19 drivers/char/drm/drm_drv.c | 2 drivers/char/drm/drm_memory.c | 94 drivers/char/drm/drm_memory.h | 20 drivers/char/drm/drm_memory_debug.h | 70 drivers/char/drm/drm_mm.c | 183 - drivers/char/drm/drm_pciids.h | 4 drivers/char/drm/drm_proc.c | 4 drivers/char/drm/drm_sman.c | 3 drivers/char/drm/drm_vm.c | 16 drivers/char/drm/ffb_context.c | 1 drivers/char/drm/ffb_drv.c | 1 drivers/char/drm/i810_dma.c | 36 drivers/char/drm/i810_drv.h | 2 drivers/char/drm/i830_dma.c | 34 drivers/char/drm/i830_drv.h | 2 drivers/char/drm/via_dma.c | 9 drivers/char/drm/via_dmablit.c | 16 drivers/char/drm/via_drv.h | 11 drivers/char/drm/via_irq.c | 16 drivers/char/drm/via_map.c | 3 drivers/char/drm/via_verifier.c | 50 drivers/char/drm/via_verifier.h | 1 drivers/char/ds1302.c | 2 drivers/char/ds1620.c | 1 drivers/char/dsp56k.c | 1 drivers/char/dtlk.c | 8 drivers/char/epca.c | 3 drivers/char/generic_nvram.c | 2 drivers/char/generic_serial.c | 1 drivers/char/hangcheck-timer.c | 2 drivers/char/hpet.c | 6 drivers/char/hvc_beat.c | 134 drivers/char/hvsi.c | 1 drivers/char/hw_random/intel-rng.c | 76 drivers/char/ip2/i2lib.c | 40 drivers/char/ip2/ip2main.c | 4 drivers/char/ipmi/ipmi_devintf.c | 1 drivers/char/ipmi/ipmi_msghandler.c | 31 drivers/char/ipmi/ipmi_poweroff.c | 2 drivers/char/ipmi/ipmi_si_intf.c | 18 drivers/char/isicom.c | 108 drivers/char/istallion.c | 1 drivers/char/keyboard.c | 11 drivers/char/mbcs.c | 2 drivers/char/moxa.c | 927 +-- drivers/char/mspec.c | 6 drivers/char/mxser.c | 11 drivers/char/mxser.h | 8 drivers/char/mxser_new.c | 236 - drivers/char/mxser_new.h | 477 - drivers/char/n_r3964.c | 2095 +++--- drivers/char/n_tty.c | 14 drivers/char/nvram.c | 1 drivers/char/nwbutton.c | 13 drivers/char/nwflash.c | 1 drivers/char/pcmcia/cm4000_cs.c | 10 drivers/char/pcmcia/cm4040_cs.c | 3 drivers/char/pcmcia/synclink_cs.c | 14 drivers/char/pty.c | 1 drivers/char/random.c | 4 drivers/char/raw.c | 2 drivers/char/rio/rio_linux.c | 12 drivers/char/rio/riointr.c | 9 drivers/char/riscom8.c | 5 drivers/char/rocket.c | 13 drivers/char/rtc.c | 20 drivers/char/scan_keyb.c | 149 drivers/char/scan_keyb.h | 15 drivers/char/ser_a2232.c | 1 drivers/char/serial167.c | 3322 +++++---- drivers/char/sonypi.c | 1 drivers/char/specialix.c | 18 drivers/char/synclink.c | 15 drivers/char/synclink_gt.c | 24 drivers/char/synclinkmp.c | 27 drivers/char/sysrq.c | 19 drivers/char/tlclk.c | 1 drivers/char/toshiba.c | 36 drivers/char/tpm/tpm.c | 6 drivers/char/tpm/tpm_bios.c | 12 drivers/char/tty_io.c | 247 - drivers/char/tty_ioctl.c | 45 drivers/char/vc_screen.c | 1 drivers/char/viotape.c | 2 drivers/char/vme_scc.c | 1 drivers/char/vt.c | 12 drivers/char/vt_ioctl.c | 28 drivers/char/watchdog/acquirewdt.c | 155 drivers/char/watchdog/advantechwdt.c | 142 drivers/char/watchdog/alim1535_wdt.c | 2 drivers/char/watchdog/alim7101_wdt.c | 21 drivers/char/watchdog/booke_wdt.c | 20 drivers/char/watchdog/cpu5wdt.c | 13 drivers/char/watchdog/eurotechwdt.c | 2 drivers/char/watchdog/i6300esb.c | 2 drivers/char/watchdog/i8xx_tco.c | 2 drivers/char/watchdog/iTCO_wdt.c | 8 drivers/char/watchdog/ib700wdt.c | 192 - drivers/char/watchdog/ibmasr.c | 2 drivers/char/watchdog/indydog.c | 2 drivers/char/watchdog/machzwd.c | 20 drivers/char/watchdog/mixcomwd.c | 16 drivers/char/watchdog/omap_wdt.c | 2 drivers/char/watchdog/pc87413_wdt.c | 4 drivers/char/watchdog/pcwd.c | 32 drivers/char/watchdog/pcwd_pci.c | 34 drivers/char/watchdog/pcwd_usb.c | 63 drivers/char/watchdog/pnx4008_wdt.c | 5 drivers/char/watchdog/rm9k_wdt.c | 4 drivers/char/watchdog/s3c2410_wdt.c | 62 drivers/char/watchdog/sbc60xxwdt.c | 14 drivers/char/watchdog/sbc8360.c | 2 drivers/char/watchdog/sbc_epx_c3.c | 2 drivers/char/watchdog/sc1200wdt.c | 2 drivers/char/watchdog/sc520_wdt.c | 14 drivers/char/watchdog/shwdt.c | 8 drivers/char/watchdog/smsc37b787_wdt.c | 4 drivers/char/watchdog/softdog.c | 2 drivers/char/watchdog/w83627hf_wdt.c | 2 drivers/char/watchdog/w83697hf_wdt.c | 4 drivers/char/watchdog/w83877f_wdt.c | 14 drivers/char/watchdog/w83977f_wdt.c | 2 drivers/char/watchdog/wafer5823wdt.c | 2 drivers/char/watchdog/wdt.c | 2 drivers/char/watchdog/wdt977.c | 2 drivers/char/watchdog/wdt_pci.c | 2 drivers/clocksource/acpi_pm.c | 20 drivers/clocksource/cyclone.c | 2 drivers/clocksource/scx200_hrt.c | 2 drivers/cpufreq/Kconfig | 2 drivers/cpufreq/cpufreq.c | 258 + drivers/cpufreq/cpufreq_conservative.c | 3 drivers/cpufreq/cpufreq_ondemand.c | 64 drivers/cpufreq/cpufreq_stats.c | 2 drivers/cpufreq/cpufreq_userspace.c | 2 drivers/crypto/Kconfig | 2 drivers/crypto/geode-aes.c | 3 drivers/edac/e752x_edac.c | 40 drivers/edac/edac_mc.c | 175 drivers/edac/edac_mc.h | 28 drivers/fc4/fc_syms.c | 1 drivers/fc4/soc.c | 1 drivers/fc4/socal.c | 1 drivers/firmware/edd.c | 8 drivers/firmware/pcdp.c | 2 drivers/hid/Kconfig | 14 drivers/hid/Makefile | 11 drivers/hid/hid-core.c | 9 drivers/hid/hid-debug.c | 764 ++ drivers/hid/hid-input.c | 35 drivers/hwmon/ams/ams-input.c | 2 drivers/hwmon/vt8231.c | 1 drivers/i2c/busses/Kconfig | 13 drivers/i2c/busses/Makefile | 1 drivers/i2c/busses/i2c-ali1535.c | 2 drivers/i2c/busses/i2c-ali1563.c | 58 drivers/i2c/busses/i2c-ali15x3.c | 2 drivers/i2c/busses/i2c-amd756-s4882.c | 2 drivers/i2c/busses/i2c-amd756.c | 2 drivers/i2c/busses/i2c-amd8111.c | 72 drivers/i2c/busses/i2c-i801.c | 4 drivers/i2c/busses/i2c-i810.c | 2 drivers/i2c/busses/i2c-ibm_iic.c | 1 drivers/i2c/busses/i2c-iop3xx.c | 1 drivers/i2c/busses/i2c-isa.c | 1 drivers/i2c/busses/i2c-mv64xxx.c | 1 drivers/i2c/busses/i2c-nforce2.c | 4 drivers/i2c/busses/i2c-ocores.c | 1 drivers/i2c/busses/i2c-parport.h | 8 drivers/i2c/busses/i2c-pasemi.c | 426 + drivers/i2c/busses/i2c-piix4.c | 5 drivers/i2c/busses/i2c-powermac.c | 1 drivers/i2c/busses/i2c-s3c2410.c | 1 drivers/i2c/busses/i2c-savage4.c | 1 drivers/i2c/busses/i2c-sis5595.c | 1 drivers/i2c/busses/i2c-sis630.c | 1 drivers/i2c/busses/i2c-sis96x.c | 2 drivers/i2c/busses/i2c-via.c | 1 drivers/i2c/busses/i2c-viapro.c | 7 drivers/i2c/busses/i2c-voodoo3.c | 2 drivers/i2c/busses/scx200_acb.c | 7 drivers/i2c/busses/scx200_i2c.c | 1 drivers/i2c/chips/eeprom.c | 1 drivers/i2c/chips/isp1301_omap.c | 2 drivers/i2c/chips/tps65010.c | 2 drivers/i2c/i2c-core.c | 71 drivers/i2c/i2c-dev.c | 2 drivers/ide/Kconfig | 24 drivers/ide/Makefile | 1 drivers/ide/ide-acpi.c | 697 ++ drivers/ide/ide-probe.c | 3 drivers/ide/ide-proc.c | 4 drivers/ide/ide-tape.c | 2 drivers/ide/ide.c | 36 drivers/ide/legacy/ide-cs.c | 1 drivers/ide/pci/Makefile | 4 drivers/ide/pci/delkin_cb.c | 140 drivers/ide/pci/hpt366.c | 1583 ++-- drivers/ide/pci/it8213.c | 362 + drivers/ide/pci/pdc202xx_new.c | 56 drivers/ide/pci/pdc202xx_old.c | 27 drivers/ide/pci/piix.c | 31 drivers/ide/pci/slc90e66.c | 55 drivers/ide/pci/tc86c001.c | 309 + drivers/ide/ppc/mpc8xx.c | 1 drivers/ide/ppc/pmac.c | 1 drivers/ide/setup-pci.c | 7 drivers/ieee1394/.gitignore | 1 drivers/ieee1394/Kconfig | 21 drivers/ieee1394/Makefile | 10 drivers/ieee1394/csr1212.c | 15 drivers/ieee1394/dv1394.c | 48 drivers/ieee1394/eth1394.c | 1 drivers/ieee1394/hosts.c | 13 drivers/ieee1394/hosts.h | 7 drivers/ieee1394/ieee1394_core.c | 23 drivers/ieee1394/iso.c | 1 drivers/ieee1394/nodemgr.c | 63 drivers/ieee1394/nodemgr.h | 3 drivers/ieee1394/ohci1394.c | 18 drivers/ieee1394/oui.db | 7048 -------------------- drivers/ieee1394/oui2c.sh | 22 drivers/ieee1394/pcilynx.c | 1 drivers/ieee1394/raw1394.c | 50 drivers/ieee1394/sbp2.c | 23 drivers/ieee1394/video1394.c | 10 drivers/infiniband/Kconfig | 1 drivers/infiniband/Makefile | 1 drivers/infiniband/core/addr.c | 5 drivers/infiniband/core/cache.c | 1 drivers/infiniband/core/cma.c | 68 drivers/infiniband/core/device.c | 3 drivers/infiniband/core/mad.c | 11 drivers/infiniband/core/ucm.c | 2 drivers/infiniband/core/ucma.c | 2 drivers/infiniband/core/user_mad.c | 4 drivers/infiniband/core/uverbs_cmd.c | 2 drivers/infiniband/core/uverbs_main.c | 6 drivers/infiniband/hw/amso1100/c2.c | 2 drivers/infiniband/hw/amso1100/c2_cq.c | 2 drivers/infiniband/hw/cxgb3/Kconfig | 27 drivers/infiniband/hw/cxgb3/Makefile | 12 drivers/infiniband/hw/cxgb3/cxio_dbg.c | 207 + drivers/infiniband/hw/cxgb3/cxio_hal.c | 1280 ++++ drivers/infiniband/hw/cxgb3/cxio_hal.h | 201 + drivers/infiniband/hw/cxgb3/cxio_resource.c | 331 + drivers/infiniband/hw/cxgb3/cxio_resource.h | 70 drivers/infiniband/hw/cxgb3/cxio_wr.h | 685 ++ drivers/infiniband/hw/cxgb3/iwch.c | 189 + drivers/infiniband/hw/cxgb3/iwch.h | 177 + drivers/infiniband/hw/cxgb3/iwch_cm.c | 2081 ++++++ drivers/infiniband/hw/cxgb3/iwch_cm.h | 223 + drivers/infiniband/hw/cxgb3/iwch_cq.c | 225 + drivers/infiniband/hw/cxgb3/iwch_ev.c | 231 + drivers/infiniband/hw/cxgb3/iwch_mem.c | 172 drivers/infiniband/hw/cxgb3/iwch_provider.c | 1203 +++ drivers/infiniband/hw/cxgb3/iwch_provider.h | 367 + drivers/infiniband/hw/cxgb3/iwch_qp.c | 1007 +++ drivers/infiniband/hw/cxgb3/iwch_user.h | 67 drivers/infiniband/hw/cxgb3/tcb.h | 632 ++ drivers/infiniband/hw/ehca/ehca_classes.h | 29 drivers/infiniband/hw/ehca/ehca_cq.c | 68 drivers/infiniband/hw/ehca/ehca_eq.c | 4 drivers/infiniband/hw/ehca/ehca_irq.c | 2 drivers/infiniband/hw/ehca/ehca_iverbs.h | 8 drivers/infiniband/hw/ehca/ehca_main.c | 6 drivers/infiniband/hw/ehca/ehca_mrmw.c | 6 drivers/infiniband/hw/ehca/ehca_pd.c | 3 drivers/infiniband/hw/ehca/ehca_qp.c | 81 drivers/infiniband/hw/ehca/ehca_reqs.c | 2 drivers/infiniband/hw/ehca/ehca_uverbs.c | 395 - drivers/infiniband/hw/ipath/ipath_diag.c | 4 drivers/infiniband/hw/ipath/ipath_file_ops.c | 6 drivers/infiniband/hw/ipath/ipath_fs.c | 14 drivers/infiniband/hw/ipath/ipath_kernel.h | 2 drivers/infiniband/hw/ipath/ipath_qp.c | 2 drivers/infiniband/hw/ipath/ipath_rc.c | 8 drivers/infiniband/hw/ipath/ipath_ruc.c | 8 drivers/infiniband/hw/ipath/ipath_uc.c | 4 drivers/infiniband/hw/ipath/ipath_ud.c | 8 drivers/infiniband/hw/mthca/mthca_cmd.c | 8 drivers/infiniband/hw/mthca/mthca_cq.c | 2 drivers/infiniband/hw/mthca/mthca_dev.h | 2 drivers/infiniband/hw/mthca/mthca_main.c | 40 drivers/infiniband/hw/mthca/mthca_memfree.c | 127 drivers/infiniband/hw/mthca/mthca_memfree.h | 9 drivers/infiniband/hw/mthca/mthca_mr.c | 110 drivers/infiniband/hw/mthca/mthca_profile.c | 2 drivers/infiniband/hw/mthca/mthca_provider.c | 14 drivers/infiniband/hw/mthca/mthca_provider.h | 1 drivers/infiniband/hw/mthca/mthca_qp.c | 2 drivers/infiniband/hw/mthca/mthca_srq.c | 9 drivers/infiniband/ulp/ipoib/Kconfig | 16 drivers/infiniband/ulp/ipoib/Makefile | 1 drivers/infiniband/ulp/ipoib/ipoib.h | 215 + drivers/infiniband/ulp/ipoib/ipoib_cm.c | 1237 ++++ drivers/infiniband/ulp/ipoib/ipoib_fs.c | 4 drivers/infiniband/ulp/ipoib/ipoib_ib.c | 29 drivers/infiniband/ulp/ipoib/ipoib_main.c | 96 drivers/infiniband/ulp/ipoib/ipoib_multicast.c | 4 drivers/infiniband/ulp/ipoib/ipoib_verbs.c | 40 drivers/infiniband/ulp/ipoib/ipoib_vlan.c | 13 drivers/infiniband/ulp/iser/iser_initiator.c | 4 drivers/infiniband/ulp/srp/ib_srp.c | 7 drivers/infiniband/ulp/srp/ib_srp.h | 1 drivers/input/ff-memless.c | 2 drivers/input/gameport/ns558.c | 1 drivers/input/input.c | 7 drivers/input/keyboard/Kconfig | 19 drivers/input/keyboard/Makefile | 5 drivers/input/keyboard/gpio_keys.c | 147 drivers/input/keyboard/hilkbd.c | 114 drivers/input/misc/Kconfig | 10 drivers/input/misc/Makefile | 1 drivers/input/misc/atlas_btns.c | 170 drivers/input/misc/hp_sdc_rtc.c | 2 drivers/input/misc/uinput.c | 2 drivers/input/misc/wistron_btns.c | 20 drivers/input/mouse/inport.c | 2 drivers/input/mouse/pc110pad.c | 2 drivers/input/mouse/rpcmouse.c | 1 drivers/input/serio/hil_mlc.c | 1 drivers/input/serio/hp_sdc.c | 1 drivers/input/serio/i8042.c | 12 drivers/input/serio/serio.c | 6 drivers/input/serio/serio_raw.c | 2 drivers/input/touchscreen/Kconfig | 9 drivers/input/touchscreen/ads7846.c | 582 +- drivers/input/touchscreen/ucb1400_ts.c | 2 drivers/input/tsdev.c | 4 drivers/isdn/capi/capi.c | 41 drivers/isdn/capi/capidrv.c | 5 drivers/isdn/capi/kcapi_proc.c | 10 drivers/isdn/divert/divert_procfs.c | 2 drivers/isdn/gigaset/Kconfig | 25 drivers/isdn/gigaset/Makefile | 2 drivers/isdn/gigaset/asyncdata.c | 5 drivers/isdn/gigaset/bas-gigaset.c | 4 drivers/isdn/gigaset/common.c | 24 drivers/isdn/gigaset/ev-layer.c | 2 drivers/isdn/gigaset/interface.c | 17 drivers/isdn/gigaset/isocdata.c | 4 drivers/isdn/gigaset/ser-gigaset.c | 837 ++ drivers/isdn/hardware/avm/avm_cs.c | 1 drivers/isdn/hardware/avm/b1dma.c | 14 drivers/isdn/hardware/avm/c4.c | 16 drivers/isdn/hardware/eicon/capifunc.c | 4 drivers/isdn/hardware/eicon/debug.c | 30 drivers/isdn/hardware/eicon/di.c | 16 drivers/isdn/hardware/eicon/divamnt.c | 3 drivers/isdn/hardware/eicon/divasi.c | 2 drivers/isdn/hardware/eicon/divasmain.c | 3 drivers/isdn/hardware/eicon/divasproc.c | 2 drivers/isdn/hardware/eicon/message.c | 383 + drivers/isdn/hardware/eicon/os_pri.c | 4 drivers/isdn/hardware/eicon/platform.h | 12 drivers/isdn/hisax/Kconfig | 2 drivers/isdn/hisax/Makefile | 1 drivers/isdn/hisax/avma1_cs.c | 1 drivers/isdn/hisax/config.c | 11 drivers/isdn/hisax/elsa_cs.c | 1 drivers/isdn/hisax/elsa_ser.c | 8 drivers/isdn/hisax/hfc4s8s_l1.c | 48 drivers/isdn/hisax/hfc_usb.c | 41 drivers/isdn/hisax/hfc_usb.h | 3 drivers/isdn/hisax/hisax.h | 25 drivers/isdn/hisax/isar.c | 1 drivers/isdn/hisax/isdnl1.h | 17 drivers/isdn/hisax/isdnl3.c | 12 drivers/isdn/hisax/isdnl3.h | 26 drivers/isdn/hisax/sedlbauer_cs.c | 1 drivers/isdn/hisax/teles_cs.c | 1 drivers/isdn/hysdn/boardergo.c | 1 drivers/isdn/hysdn/hysdn_procconf.c | 2 drivers/isdn/hysdn/hysdn_proclog.c | 2 drivers/isdn/hysdn/hysdn_sched.c | 1 drivers/isdn/i4l/isdn_bsdcomp.c | 1 drivers/isdn/i4l/isdn_common.c | 2 drivers/isdn/i4l/isdn_tty.c | 1 drivers/isdn/pcbit/callbacks.c | 1 drivers/isdn/pcbit/capi.c | 1 drivers/isdn/pcbit/drv.c | 5 drivers/isdn/pcbit/edss1.c | 7 drivers/isdn/pcbit/edss1.h | 7 drivers/isdn/pcbit/layer2.c | 17 drivers/isdn/pcbit/module.c | 4 drivers/isdn/pcbit/pcbit.h | 8 drivers/isdn/sc/card.h | 30 drivers/isdn/sc/command.c | 17 drivers/isdn/sc/event.c | 3 drivers/isdn/sc/init.c | 6 drivers/isdn/sc/interrupt.c | 10 drivers/isdn/sc/ioctl.c | 10 drivers/isdn/sc/message.c | 10 drivers/isdn/sc/packet.c | 10 drivers/isdn/sc/scioc.h | 6 drivers/isdn/sc/shmem.c | 6 drivers/isdn/sc/timer.c | 8 drivers/kvm/kvm.h | 4 drivers/kvm/kvm_main.c | 186 - drivers/kvm/mmu.c | 2 drivers/kvm/paging_tmpl.h | 28 drivers/kvm/svm.c | 23 drivers/kvm/vmx.c | 57 drivers/kvm/vmx.h | 1 drivers/macintosh/Kconfig | 2 drivers/macintosh/adb.c | 2 drivers/macintosh/adbhid.c | 4 drivers/macintosh/ans-lcd.c | 2 drivers/macintosh/apm_emu.c | 4 drivers/macintosh/mac_hid.c | 6 drivers/macintosh/macio-adb.c | 1 drivers/macintosh/nvram.c | 2 drivers/macintosh/rack-meter.c | 6 drivers/macintosh/smu.c | 2 drivers/macintosh/therm_adt746x.c | 6 drivers/macintosh/via-cuda.c | 3 drivers/macintosh/via-macii.c | 11 drivers/macintosh/via-maciisi.c | 7 drivers/macintosh/via-pmu.c | 16 drivers/macintosh/via-pmu68k.c | 7 drivers/macintosh/windfarm_core.c | 6 drivers/md/bitmap.c | 24 drivers/md/dm-ioctl.c | 2 drivers/md/md.c | 4 drivers/md/raid5.c | 42 drivers/media/common/ir-keymaps.c | 1 drivers/media/common/saa7146_fops.c | 2 drivers/media/dvb/b2c2/flexcop-i2c.c | 1 drivers/media/dvb/dvb-core/dmxdev.c | 1 drivers/media/dvb/dvb-core/dvbdev.c | 1 drivers/media/dvb/dvb-usb/dvb-usb-i2c.c | 1 drivers/media/dvb/ttpci/av7110_av.c | 1 drivers/media/dvb/ttpci/av7110_ca.c | 1 drivers/media/dvb/ttpci/av7110_hw.c | 1 drivers/media/dvb/ttpci/av7110_v4l.c | 1 drivers/media/dvb/ttusb-budget/dvb-ttusb-budget.c | 1 drivers/media/radio/dsbr100.c | 2 drivers/media/radio/miropcm20-radio.c | 2 drivers/media/radio/miropcm20-rds.c | 3 drivers/media/radio/radio-aimslab.c | 2 drivers/media/radio/radio-aztech.c | 2 drivers/media/radio/radio-cadet.c | 2 drivers/media/radio/radio-gemtek-pci.c | 2 drivers/media/radio/radio-gemtek.c | 2 drivers/media/radio/radio-maestro.c | 3 drivers/media/radio/radio-maxiradio.c | 3 drivers/media/radio/radio-rtrack2.c | 2 drivers/media/radio/radio-sf16fmi.c | 2 drivers/media/radio/radio-sf16fmr2.c | 2 drivers/media/radio/radio-terratec.c | 2 drivers/media/radio/radio-trust.c | 2 drivers/media/radio/radio-typhoon.c | 2 drivers/media/radio/radio-zoltrix.c | 2 drivers/media/video/adv7170.c | 1 drivers/media/video/adv7175.c | 1 drivers/media/video/arv.c | 2 drivers/media/video/bt819.c | 1 drivers/media/video/bt856.c | 1 drivers/media/video/bt8xx/bttv-driver.c | 4 drivers/media/video/bt8xx/bttv-vbi.c | 1 drivers/media/video/bw-qcam.c | 2 drivers/media/video/c-qcam.c | 2 drivers/media/video/cafe_ccic.c | 7 drivers/media/video/cpia.c | 2 drivers/media/video/cpia2/cpia2_v4l.c | 2 drivers/media/video/cx88/cx88-blackbird.c | 2 drivers/media/video/cx88/cx88-tvaudio.c | 1 drivers/media/video/cx88/cx88-video.c | 4 drivers/media/video/dabusb.c | 2 drivers/media/video/em28xx/em28xx-input.c | 1 drivers/media/video/em28xx/em28xx-video.c | 2 drivers/media/video/et61x251/et61x251_core.c | 2 drivers/media/video/indycam.c | 1 drivers/media/video/ir-kbd-i2c.c | 1 drivers/media/video/meye.c | 3 drivers/media/video/ov511.c | 2 drivers/media/video/pms.c | 3 drivers/media/video/pvrusb2/pvrusb2-i2c-core.c | 1 drivers/media/video/pvrusb2/pvrusb2-v4l2.c | 2 drivers/media/video/pwc/pwc-if.c | 2 drivers/media/video/saa5246a.c | 3 drivers/media/video/saa5249.c | 2 drivers/media/video/saa7111.c | 1 drivers/media/video/saa7114.c | 1 drivers/media/video/saa711x.c | 1 drivers/media/video/saa7134/saa6752hs.c | 1 drivers/media/video/saa7134/saa7134-empress.c | 2 drivers/media/video/saa7134/saa7134-input.c | 1 drivers/media/video/saa7134/saa7134-oss.c | 4 drivers/media/video/saa7134/saa7134-video.c | 4 drivers/media/video/saa7134/saa7134.h | 4 drivers/media/video/saa7185.c | 1 drivers/media/video/saa7191.c | 1 drivers/media/video/se401.c | 2 drivers/media/video/sn9c102/sn9c102_core.c | 2 drivers/media/video/stradis.c | 2 drivers/media/video/stv680.c | 2 drivers/media/video/tda7432.c | 1 drivers/media/video/tda9875.c | 1 drivers/media/video/tuner-core.c | 1 drivers/media/video/tvmixer.c | 3 drivers/media/video/usbvideo/ibmcam.c | 1 drivers/media/video/usbvideo/ultracam.c | 1 drivers/media/video/usbvideo/usbvideo.c | 2 drivers/media/video/usbvideo/vicam.c | 2 drivers/media/video/usbvision/usbvision-core.c | 1 drivers/media/video/usbvision/usbvision-i2c.c | 2 drivers/media/video/usbvision/usbvision-video.c | 9 drivers/media/video/v4l2-common.c | 1 drivers/media/video/videodev.c | 5 drivers/media/video/vino.c | 2 drivers/media/video/vivi.c | 2 drivers/media/video/w9966.c | 2 drivers/media/video/w9968cf.c | 5 drivers/media/video/zc0301/zc0301_core.c | 2 drivers/media/video/zc0301/zc0301_sensor.h | 1 drivers/media/video/zoran_card.c | 1 drivers/media/video/zoran_driver.c | 3 drivers/media/video/zoran_procfs.c | 2 drivers/message/fusion/Kconfig | 2 drivers/message/fusion/Makefile | 7 drivers/message/fusion/lsi/mpi.h | 7 drivers/message/fusion/lsi/mpi_cnfg.h | 131 drivers/message/fusion/lsi/mpi_history.txt | 77 drivers/message/fusion/lsi/mpi_init.h | 7 drivers/message/fusion/lsi/mpi_ioc.h | 75 drivers/message/fusion/lsi/mpi_log_sas.h | 284 - drivers/message/fusion/lsi/mpi_sas.h | 9 drivers/message/fusion/mptbase.c | 875 ++ drivers/message/fusion/mptbase.h | 47 drivers/message/fusion/mptctl.c | 165 drivers/message/fusion/mptctl.h | 2 drivers/message/fusion/mptfc.c | 54 drivers/message/fusion/mptlan.c | 1 drivers/message/fusion/mptlan.h | 1 drivers/message/fusion/mptsas.c | 720 ++ drivers/message/fusion/mptscsih.c | 998 +-- drivers/message/fusion/mptscsih.h | 44 drivers/message/fusion/mptspi.c | 528 + drivers/message/i2o/i2o_config.c | 2 drivers/message/i2o/i2o_proc.c | 38 drivers/misc/Kconfig | 21 drivers/misc/Makefile | 1 drivers/misc/asus-laptop.c | 1165 +++ drivers/misc/hdpuftrs/hdpu_cpustate.c | 2 drivers/misc/hdpuftrs/hdpu_nexus.c | 2 drivers/misc/ibmasm/ibmasmfs.c | 10 drivers/misc/ioc4.c | 6 drivers/misc/lkdtm.c | 4 drivers/misc/tifm_7xx1.c | 404 + drivers/misc/tifm_core.c | 65 drivers/mmc/Kconfig | 2 drivers/mmc/at91_mci.c | 3 drivers/mmc/au1xmmc.c | 13 drivers/mmc/imxmmc.c | 4 drivers/mmc/mmc.c | 182 - drivers/mmc/mmc_block.c | 16 drivers/mmc/mmc_queue.c | 2 drivers/mmc/mmc_sysfs.c | 2 drivers/mmc/mmci.c | 15 drivers/mmc/omap.c | 6 drivers/mmc/pxamci.c | 10 drivers/mmc/sdhci.c | 131 drivers/mmc/sdhci.h | 2 drivers/mmc/tifm_sd.c | 494 + drivers/mmc/wbsd.c | 108 drivers/mmc/wbsd.h | 1 drivers/mtd/chips/cfi_util.c | 1 drivers/mtd/devices/block2mtd.c | 3 drivers/mtd/devices/doc2001.c | 1 drivers/mtd/devices/doc2001plus.c | 1 drivers/mtd/devices/docecc.c | 1 drivers/mtd/devices/pmc551.c | 1 drivers/mtd/devices/slram.c | 1 drivers/mtd/ftl.c | 1 drivers/mtd/inftlmount.c | 1 drivers/mtd/mtdchar.c | 2 drivers/mtd/mtdcore.c | 1 drivers/mtd/nand/cafe.c | 3 drivers/mtd/nftlcore.c | 1 drivers/net/3c503.c | 3 drivers/net/3c59x.c | 3 drivers/net/7990.c | 2 drivers/net/Kconfig | 108 drivers/net/Makefile | 7 drivers/net/Space.c | 4 drivers/net/ac3200.c | 3 drivers/net/amd8111e.c | 3 drivers/net/arcnet/com20020.c | 3 drivers/net/arm/at91_ether.c | 2 drivers/net/arm/ether1.c | 1 drivers/net/arm/ether3.c | 1 drivers/net/arm/etherh.c | 3 drivers/net/atl1/Makefile | 2 drivers/net/atl1/atl1.h | 283 + drivers/net/atl1/atl1_ethtool.c | 508 + drivers/net/atl1/atl1_hw.c | 718 ++ drivers/net/atl1/atl1_hw.h | 951 +++ drivers/net/atl1/atl1_main.c | 2468 +++++++ drivers/net/atl1/atl1_param.c | 206 + drivers/net/au1000_eth.c | 1 drivers/net/b44.c | 8 drivers/net/b44.h | 10 drivers/net/bmac.c | 20 drivers/net/bnx2.c | 16 drivers/net/bonding/bond_alb.c | 4 drivers/net/bonding/bond_main.c | 30 drivers/net/bonding/bond_sysfs.c | 303 + drivers/net/bonding/bonding.h | 9 drivers/net/chelsio/common.h | 2 drivers/net/chelsio/cpl5_cmd.h | 18 drivers/net/chelsio/cxgb2.c | 149 drivers/net/chelsio/elmer0.h | 40 drivers/net/chelsio/espi.c | 44 drivers/net/chelsio/fpga_defs.h | 6 drivers/net/chelsio/gmac.h | 11 drivers/net/chelsio/ixf1010.c | 100 drivers/net/chelsio/mv88e1xxx.c | 27 drivers/net/chelsio/my3126.c | 16 drivers/net/chelsio/pm3393.c | 91 drivers/net/chelsio/sge.c | 328 - drivers/net/chelsio/subr.c | 89 drivers/net/chelsio/tp.c | 62 drivers/net/chelsio/vsc7326.c | 139 drivers/net/chelsio/vsc7326_reg.h | 139 drivers/net/chelsio/vsc8244.c | 41 drivers/net/cris/eth_v10.c | 1 drivers/net/cxgb3/Makefile | 8 drivers/net/cxgb3/adapter.h | 279 + drivers/net/cxgb3/ael1002.c | 251 + drivers/net/cxgb3/common.h | 729 ++ drivers/net/cxgb3/cxgb3_ctl_defs.h | 164 drivers/net/cxgb3/cxgb3_defs.h | 99 drivers/net/cxgb3/cxgb3_ioctl.h | 185 + drivers/net/cxgb3/cxgb3_main.c | 2520 +++++++ drivers/net/cxgb3/cxgb3_offload.c | 1222 +++ drivers/net/cxgb3/cxgb3_offload.h | 193 + drivers/net/cxgb3/firmware_exports.h | 177 + drivers/net/cxgb3/l2t.c | 450 + drivers/net/cxgb3/l2t.h | 143 drivers/net/cxgb3/mc5.c | 473 + drivers/net/cxgb3/regs.h | 2195 ++++++ drivers/net/cxgb3/sge.c | 2681 ++++++++ drivers/net/cxgb3/sge_defs.h | 251 + drivers/net/cxgb3/t3_cpl.h | 1444 ++++ drivers/net/cxgb3/t3_hw.c | 3375 ++++++++++ drivers/net/cxgb3/t3cdev.h | 73 drivers/net/cxgb3/version.h | 39 drivers/net/cxgb3/vsc8211.c | 228 + drivers/net/cxgb3/xgmac.c | 409 + drivers/net/declance.c | 164 drivers/net/defxx.c | 928 ++- drivers/net/defxx.h | 58 drivers/net/e1000/e1000.h | 7 drivers/net/e1000/e1000_ethtool.c | 6 drivers/net/e1000/e1000_main.c | 130 drivers/net/e1000/e1000_osdep.h | 4 drivers/net/e1000/e1000_param.c | 15 drivers/net/e2100.c | 3 drivers/net/ehea/ehea_main.c | 8 drivers/net/es3210.c | 2 drivers/net/fec_8xx/fec_8xx-netta.c | 1 drivers/net/fec_8xx/fec_main.c | 1 drivers/net/fec_8xx/fec_mii.c | 1 drivers/net/forcedeth.c | 1342 +++- drivers/net/fs_enet/fs_enet-main.c | 1 drivers/net/fs_enet/fs_enet.h | 1 drivers/net/fs_enet/mac-fcc.c | 1 drivers/net/fs_enet/mac-fec.c | 1 drivers/net/fs_enet/mac-scc.c | 1 drivers/net/fs_enet/mii-bitbang.c | 1 drivers/net/fs_enet/mii-fec.c | 1 drivers/net/gianfar.c | 1 drivers/net/gianfar_ethtool.c | 3 drivers/net/gianfar_mii.c | 1 drivers/net/gianfar_sysfs.c | 1 drivers/net/hamradio/bpqether.c | 2 drivers/net/hamradio/scc.c | 2 drivers/net/hamradio/yam.c | 2 drivers/net/hp100.c | 2 drivers/net/ibm_emac/ibm_emac_core.c | 1 drivers/net/ibmveth.c | 2 drivers/net/irda/ma600-sir.c | 1 drivers/net/irda/vlsi_ir.c | 2 drivers/net/iseries_veth.c | 2 drivers/net/ixgb/ixgb.h | 2 drivers/net/ixgb/ixgb_ethtool.c | 6 drivers/net/ixgb/ixgb_main.c | 6 drivers/net/macb.c | 63 drivers/net/macb.h | 8 drivers/net/mace.c | 16 drivers/net/macmace.c | 18 drivers/net/macsonic.c | 7 drivers/net/meth.c | 1 drivers/net/mipsnet.c | 1 drivers/net/mv643xx_eth.c | 1 drivers/net/myri10ge/myri10ge.c | 10 drivers/net/netxen/netxen_nic.h | 17 drivers/net/netxen/netxen_nic_ethtool.c | 96 drivers/net/netxen/netxen_nic_init.c | 279 + drivers/net/netxen/netxen_nic_main.c | 4 drivers/net/oaknet.c | 666 -- drivers/net/pasemi_mac.c | 1019 +++ drivers/net/pasemi_mac.h | 460 + drivers/net/phy/cicada.c | 1 drivers/net/phy/davicom.c | 1 drivers/net/phy/fixed.c | 1 drivers/net/phy/lxt.c | 1 drivers/net/phy/marvell.c | 1 drivers/net/phy/mdio_bus.c | 1 drivers/net/phy/phy.c | 1 drivers/net/phy/phy_device.c | 1 drivers/net/phy/qsemi.c | 1 drivers/net/ppp_generic.c | 4 drivers/net/pppoe.c | 2 drivers/net/qla3xxx.c | 367 + drivers/net/qla3xxx.h | 88 drivers/net/r8169.c | 4 drivers/net/s2io-regs.h | 7 drivers/net/s2io.c | 1181 ++- drivers/net/s2io.h | 227 - drivers/net/sc92031.c | 1620 +++++ drivers/net/sk_mca.c | 1216 --- drivers/net/sk_mca.h | 170 drivers/net/skfp/can.c | 83 drivers/net/skfp/drvfbi.c | 24 drivers/net/skfp/fplustm.c | 4 drivers/net/skfp/smt.c | 10 drivers/net/skge.c | 235 - drivers/net/skge.h | 2 drivers/net/sky2.c | 543 +- drivers/net/sky2.h | 85 drivers/net/slip.c | 5 drivers/net/smc-mca.c | 3 drivers/net/smc-ultra.c | 3 drivers/net/smc-ultra32.c | 3 drivers/net/smc911x.c | 2 drivers/net/smc91x.c | 2 drivers/net/spider_net.c | 315 - drivers/net/spider_net.h | 20 drivers/net/spider_net_ethtool.c | 4 drivers/net/sungem_phy.c | 1 drivers/net/tg3.c | 92 drivers/net/tg3.h | 1 drivers/net/tsi108_eth.c | 1 drivers/net/tun.c | 2 drivers/net/ucc_geth.c | 106 drivers/net/ucc_geth_phy.c | 3 drivers/net/wan/Kconfig | 24 drivers/net/wan/Makefile | 1 drivers/net/wan/cosa.c | 2 drivers/net/wan/cycx_drv.c | 1 drivers/net/wan/hdlc.c | 3 drivers/net/wan/pc300too.c | 565 ++ drivers/net/wan/pci200syn.c | 1 drivers/net/wan/z85230.c | 14 drivers/net/wd.c | 2 drivers/net/wireless/airo.c | 16 drivers/net/wireless/arlan-proc.c | 4 drivers/net/wireless/atmel.c | 1 drivers/net/wireless/bcm43xx/bcm43xx.h | 7 drivers/net/wireless/bcm43xx/bcm43xx_debugfs.c | 12 drivers/net/wireless/bcm43xx/bcm43xx_leds.c | 11 drivers/net/wireless/bcm43xx/bcm43xx_main.c | 36 drivers/net/wireless/bcm43xx/bcm43xx_radio.c | 2 drivers/net/wireless/bcm43xx/bcm43xx_radio.h | 16 drivers/net/wireless/bcm43xx/bcm43xx_wx.c | 1 drivers/net/wireless/hostap/hostap_main.c | 2 drivers/net/wireless/ipw2200.c | 4 drivers/net/wireless/orinoco.c | 6 drivers/net/wireless/orinoco_cs.c | 2 drivers/net/wireless/prism54/islpci_dev.c | 13 drivers/net/wireless/prism54/islpci_dev.h | 4 drivers/net/wireless/prism54/islpci_hotplug.c | 3 drivers/net/wireless/spectrum_cs.c | 2 drivers/net/wireless/strip.c | 2 drivers/net/wireless/zd1211rw/zd_chip.c | 126 drivers/net/wireless/zd1211rw/zd_chip.h | 158 drivers/net/wireless/zd1211rw/zd_def.h | 2 drivers/net/wireless/zd1211rw/zd_ieee80211.h | 1 drivers/net/wireless/zd1211rw/zd_rf.h | 2 drivers/net/wireless/zd1211rw/zd_types.h | 71 drivers/net/wireless/zd1211rw/zd_usb.c | 128 drivers/net/wireless/zd1211rw/zd_usb.h | 6 drivers/oprofile/event_buffer.c | 2 drivers/oprofile/event_buffer.h | 2 drivers/oprofile/oprofile_files.c | 10 drivers/oprofile/oprofilefs.c | 6 drivers/parisc/ccio-dma.c | 4 drivers/parisc/eisa.c | 1 drivers/parisc/eisa_eeprom.c | 2 drivers/parisc/led.c | 2 drivers/parisc/sba_iommu.c | 4 drivers/parport/parport_cs.c | 1 drivers/parport/parport_gsc.c | 1 drivers/parport/procfs.c | 270 + drivers/pci/Kconfig | 2 drivers/pci/hotplug/Kconfig | 9 drivers/pci/hotplug/acpiphp_glue.c | 10 drivers/pci/hotplug/cpqphp_sysfs.c | 2 drivers/pci/hotplug/ibmphp_ebda.c | 1 drivers/pci/hotplug/pciehp.h | 194 - drivers/pci/hotplug/pciehp_core.c | 292 - drivers/pci/hotplug/pciehp_ctrl.c | 223 - drivers/pci/hotplug/pciehp_hpc.c | 827 +- drivers/pci/hotplug/sgi_hotplug.c | 155 drivers/pci/hotplug/shpchp.h | 4 drivers/pci/hotplug/shpchp_core.c | 4 drivers/pci/hotplug/shpchp_ctrl.c | 20 drivers/pci/hotplug/shpchp_hpc.c | 185 - drivers/pci/msi.c | 325 - drivers/pci/pci-driver.c | 7 drivers/pci/pci.c | 298 + drivers/pci/pci.h | 14 drivers/pci/pcie/aer/aerdrv.c | 2 drivers/pci/probe.c | 70 drivers/pci/proc.c | 4 drivers/pci/quirks.c | 133 drivers/pci/search.c | 38 drivers/pci/syscall.c | 1 drivers/pcmcia/at91_cf.c | 1 drivers/pcmcia/cistpl.c | 1 drivers/pcmcia/cs.c | 34 drivers/pcmcia/cs_internal.h | 4 drivers/pcmcia/ds.c | 14 drivers/pcmcia/i82092.c | 2 drivers/pcmcia/i82365.c | 3 drivers/pcmcia/m32r_cfc.c | 1 drivers/pcmcia/m32r_pcc.c | 3 drivers/pcmcia/m8xx_pcmcia.c | 1 drivers/pcmcia/omap_cf.c | 1 drivers/pcmcia/pcmcia_ioctl.c | 3 drivers/pcmcia/pcmcia_resource.c | 1 drivers/pcmcia/pd6729.c | 2 drivers/pcmcia/pxa2xx_lubbock.c | 1 drivers/pcmcia/rsrc_nonstatic.c | 56 drivers/pcmcia/sa1100_badge4.c | 1 drivers/pcmcia/sa1100_cerf.c | 1 drivers/pcmcia/sa1100_h3600.c | 1 drivers/pcmcia/sa1100_jornada720.c | 1 drivers/pcmcia/sa1100_neponset.c | 1 drivers/pcmcia/sa1100_shannon.c | 1 drivers/pcmcia/sa1100_simpad.c | 1 drivers/pcmcia/soc_common.c | 6 drivers/pcmcia/socket_sysfs.c | 104 drivers/pcmcia/tcic.c | 2 drivers/pcmcia/vrc4171_card.c | 1 drivers/pcmcia/yenta_socket.c | 3 drivers/pnp/base.h | 1 drivers/pnp/isapnp/proc.c | 2 drivers/pnp/pnpacpi/Kconfig | 4 drivers/pnp/pnpbios/rsparser.c | 1 drivers/pnp/system.c | 52 drivers/ps3/Makefile | 2 drivers/ps3/ps3av.c | 974 +++ drivers/ps3/ps3av_cmd.c | 1020 +++ drivers/ps3/system-bus.c | 362 - drivers/ps3/vuart.c | 21 drivers/ps3/vuart.h | 39 drivers/rapidio/rio-scan.c | 118 drivers/rapidio/rio-sysfs.c | 1 drivers/rtc/Kconfig | 25 drivers/rtc/Makefile | 1 drivers/rtc/rtc-cmos.c | 725 ++ drivers/rtc/rtc-dev.c | 4 drivers/rtc/rtc-ds1553.c | 2 drivers/rtc/rtc-ds1672.c | 2 drivers/rtc/rtc-ds1742.c | 2 drivers/rtc/rtc-omap.c | 4 drivers/rtc/rtc-pcf8563.c | 42 drivers/rtc/rtc-proc.c | 2 drivers/rtc/rtc-rs5c372.c | 2 drivers/rtc/rtc-s3c.c | 4 drivers/rtc/rtc-sysfs.c | 103 drivers/rtc/rtc-x1205.c | 2 drivers/s390/Kconfig | 8 drivers/s390/Makefile | 2 drivers/s390/block/dasd.c | 33 drivers/s390/block/dasd_3990_erp.c | 5 drivers/s390/block/dasd_devmap.c | 6 drivers/s390/block/dasd_diag.c | 8 drivers/s390/block/dasd_eckd.c | 95 drivers/s390/block/dasd_eer.c | 26 drivers/s390/block/dasd_erp.c | 80 drivers/s390/block/dasd_fba.c | 4 drivers/s390/block/dasd_genhd.c | 2 drivers/s390/block/dasd_int.h | 1 drivers/s390/block/dasd_proc.c | 10 drivers/s390/block/dcssblk.c | 6 drivers/s390/char/Makefile | 4 drivers/s390/char/con3215.c | 2 drivers/s390/char/con3270.c | 3 drivers/s390/char/defkeymap.c | 2 drivers/s390/char/fs3270.c | 6 drivers/s390/char/keyboard.c | 2 drivers/s390/char/monreader.c | 220 - drivers/s390/char/monwriter.c | 6 drivers/s390/char/raw3270.c | 4 drivers/s390/char/sclp.c | 93 drivers/s390/char/sclp.h | 18 drivers/s390/char/sclp_con.c | 2 drivers/s390/char/sclp_cpi.c | 2 drivers/s390/char/sclp_info.c | 57 drivers/s390/char/sclp_rw.c | 2 drivers/s390/char/sclp_tty.c | 3 drivers/s390/char/sclp_vt220.c | 5 drivers/s390/char/tape.h | 22 drivers/s390/char/tape_3590.c | 479 + drivers/s390/char/tape_3590.h | 53 drivers/s390/char/tape_block.c | 4 drivers/s390/char/tape_char.c | 29 drivers/s390/char/tape_class.c | 2 drivers/s390/char/tape_class.h | 2 drivers/s390/char/tape_core.c | 69 drivers/s390/char/tape_proc.c | 2 drivers/s390/char/tty3270.c | 13 drivers/s390/char/vmcp.c | 2 drivers/s390/char/vmlogrdr.c | 286 - drivers/s390/char/vmwatchdog.c | 2 drivers/s390/cio/blacklist.c | 12 drivers/s390/cio/ccwgroup.c | 6 drivers/s390/cio/chsc.c | 270 - drivers/s390/cio/chsc.h | 11 drivers/s390/cio/cio.c | 37 drivers/s390/cio/cmf.c | 4 drivers/s390/cio/css.c | 13 drivers/s390/cio/css.h | 2 drivers/s390/cio/device.c | 12 drivers/s390/cio/device.h | 2 drivers/s390/cio/device_fsm.c | 8 drivers/s390/cio/device_id.c | 3 drivers/s390/cio/device_ops.c | 34 drivers/s390/cio/device_status.c | 8 drivers/s390/cio/qdio.c | 79 drivers/s390/crypto/ap_bus.c | 8 drivers/s390/crypto/zcrypt_api.c | 23 drivers/s390/crypto/zcrypt_pcica.c | 8 drivers/s390/crypto/zcrypt_pcixcc.c | 3 drivers/s390/net/Kconfig | 7 drivers/s390/net/Makefile | 1 drivers/s390/net/claw.c | 16 drivers/s390/net/ctcmain.c | 9 drivers/s390/net/cu3088.c | 2 drivers/s390/net/iucv.c | 2540 ------- drivers/s390/net/iucv.h | 849 -- drivers/s390/net/lcs.c | 12 drivers/s390/net/netiucv.c | 1319 ++-- drivers/s390/net/qeth_eddp.c | 28 drivers/s390/net/qeth_main.c | 92 drivers/s390/net/qeth_proc.c | 4 drivers/s390/net/qeth_sys.c | 30 drivers/s390/net/smsgiucv.c | 147 drivers/s390/s390mach.c | 37 drivers/s390/s390mach.h | 3 drivers/s390/scsi/zfcp_aux.c | 27 drivers/s390/scsi/zfcp_dbf.c | 44 drivers/s390/scsi/zfcp_erp.c | 29 drivers/s390/scsi/zfcp_ext.h | 6 drivers/s390/scsi/zfcp_fsf.c | 25 drivers/s390/scsi/zfcp_qdio.c | 38 drivers/s390/scsi/zfcp_scsi.c | 18 drivers/s390/sysinfo.c | 63 drivers/sbus/char/bpp.c | 2 drivers/sbus/char/cpwatchdog.c | 3 drivers/sbus/char/display7seg.c | 2 drivers/sbus/char/envctrl.c | 2 drivers/sbus/char/flash.c | 2 drivers/sbus/char/jsflash.c | 2 drivers/sbus/char/openprom.c | 3 drivers/sbus/char/riowatchdog.c | 2 drivers/sbus/char/rtc.c | 2 drivers/sbus/char/uctrl.c | 3 drivers/sbus/char/vfc_dev.c | 5 drivers/sbus/sbus.c | 18 drivers/scsi/3w-9xxx.c | 2 drivers/scsi/3w-xxxx.c | 2 drivers/scsi/53c700.c | 25 drivers/scsi/53c700.h | 2 drivers/scsi/53c7xx.c | 5 drivers/scsi/BusLogic.c | 46 drivers/scsi/BusLogic.h | 300 - drivers/scsi/FlashPoint.c | 4 drivers/scsi/Kconfig | 9 drivers/scsi/Makefile | 1 drivers/scsi/NCR53C9x.c | 8 drivers/scsi/NCR53C9x.h | 2 drivers/scsi/NCR53c406a.c | 1 drivers/scsi/NCR_D700.c | 1 drivers/scsi/a2091.c | 1 drivers/scsi/a3000.c | 1 drivers/scsi/aacraid/Makefile | 2 drivers/scsi/aacraid/aachba.c | 603 +- drivers/scsi/aacraid/aacraid.h | 46 drivers/scsi/aacraid/commctrl.c | 1 drivers/scsi/aacraid/comminit.c | 15 drivers/scsi/aacraid/commsup.c | 40 drivers/scsi/aacraid/dpcsup.c | 1 drivers/scsi/aacraid/linit.c | 19 drivers/scsi/aacraid/nark.c | 87 drivers/scsi/aacraid/rkt.c | 64 drivers/scsi/aacraid/rx.c | 264 - drivers/scsi/aacraid/sa.c | 34 drivers/scsi/advansys.c | 7 drivers/scsi/aha152x.c | 1 drivers/scsi/aic7xxx/aic79xx.h | 3 drivers/scsi/aic7xxx/aic79xx_core.c | 5 drivers/scsi/aic7xxx/aic79xx_osm.c | 9 drivers/scsi/aic7xxx/aic79xx_osm.h | 2 drivers/scsi/aic7xxx/aic79xx_osm_pci.c | 19 drivers/scsi/aic7xxx/aic79xx_pci.c | 2 drivers/scsi/aic7xxx_old.c | 1 drivers/scsi/aic94xx/aic94xx_dev.c | 16 drivers/scsi/aic94xx/aic94xx_dump.c | 2 drivers/scsi/aic94xx/aic94xx_hwi.c | 3 drivers/scsi/aic94xx/aic94xx_init.c | 51 drivers/scsi/aic94xx/aic94xx_reg_def.h | 5 drivers/scsi/aic94xx/aic94xx_sas.h | 1 drivers/scsi/aic94xx/aic94xx_scb.c | 122 drivers/scsi/aic94xx/aic94xx_sds.c | 10 drivers/scsi/aic94xx/aic94xx_seq.c | 45 drivers/scsi/aic94xx/aic94xx_seq.h | 1 drivers/scsi/aic94xx/aic94xx_task.c | 9 drivers/scsi/aic94xx/aic94xx_tmf.c | 4 drivers/scsi/amiga7xx.c | 1 drivers/scsi/arcmsr/arcmsr_hba.c | 2 drivers/scsi/arm/acornscsi.c | 1 drivers/scsi/arm/arxescsi.c | 1 drivers/scsi/arm/cumana_1.c | 1 drivers/scsi/arm/cumana_2.c | 1 drivers/scsi/arm/ecoscsi.c | 1 drivers/scsi/arm/eesox.c | 1 drivers/scsi/arm/fas216.c | 1 drivers/scsi/arm/oak.c | 1 drivers/scsi/arm/powertec.c | 1 drivers/scsi/atari_scsi.c | 1 drivers/scsi/blz1230.c | 3 drivers/scsi/blz2060.c | 2 drivers/scsi/bvme6000.c | 1 drivers/scsi/ch.c | 3 drivers/scsi/cyberstorm.c | 2 drivers/scsi/cyberstormII.c | 2 drivers/scsi/dec_esp.c | 355 + drivers/scsi/dpt_i2o.c | 2 drivers/scsi/dtc.c | 1 drivers/scsi/eata_pio.c | 1 drivers/scsi/fastlane.c | 2 drivers/scsi/g_NCR5380.c | 1 drivers/scsi/gdth.c | 3 drivers/scsi/gvp11.c | 1 drivers/scsi/ibmvscsi/ibmvstgt.c | 2 drivers/scsi/initio.c | 1 drivers/scsi/ipr.c | 94 drivers/scsi/ipr.h | 4 drivers/scsi/iscsi_tcp.c | 2 drivers/scsi/jazz_esp.c | 2 drivers/scsi/lasi700.c | 2 drivers/scsi/libiscsi.c | 40 drivers/scsi/libsas/sas_discover.c | 62 drivers/scsi/libsas/sas_event.c | 6 drivers/scsi/libsas/sas_expander.c | 48 drivers/scsi/libsas/sas_init.c | 52 drivers/scsi/libsas/sas_internal.h | 9 drivers/scsi/libsas/sas_port.c | 14 drivers/scsi/libsas/sas_scsi_host.c | 290 + drivers/scsi/mac_esp.c | 2 drivers/scsi/mac_scsi.c | 1 drivers/scsi/mca_53c9x.c | 2 drivers/scsi/megaraid.c | 2 drivers/scsi/megaraid/mbox_defs.h | 2 drivers/scsi/megaraid/mega_common.h | 122 drivers/scsi/megaraid/megaraid_ioctl.h | 36 drivers/scsi/megaraid/megaraid_mbox.c | 421 + drivers/scsi/megaraid/megaraid_mbox.h | 46 drivers/scsi/megaraid/megaraid_mm.c | 67 drivers/scsi/megaraid/megaraid_sas.c | 2 drivers/scsi/megaraid/megaraid_sas.h | 14 drivers/scsi/mvme147.c | 1 drivers/scsi/mvme16x.c | 1 drivers/scsi/nsp32.c | 1 drivers/scsi/oktagon_esp.c | 2 drivers/scsi/osst.c | 10 drivers/scsi/osst.h | 68 drivers/scsi/pas16.c | 1 drivers/scsi/pcmcia/aha152x_stub.c | 1 drivers/scsi/pcmcia/fdomain_stub.c | 1 drivers/scsi/pcmcia/nsp_cs.c | 1 drivers/scsi/pcmcia/nsp_cs.h | 66 drivers/scsi/pcmcia/qlogic_stub.c | 1 drivers/scsi/pcmcia/sym53c500_cs.c | 1 drivers/scsi/qla1280.c | 1 drivers/scsi/qla2xxx/qla_attr.c | 68 drivers/scsi/qla2xxx/qla_def.h | 38 drivers/scsi/qla2xxx/qla_gbl.h | 6 drivers/scsi/qla2xxx/qla_init.c | 218 - drivers/scsi/qla2xxx/qla_isr.c | 245 + drivers/scsi/qla2xxx/qla_mbx.c | 18 drivers/scsi/qla2xxx/qla_os.c | 24 drivers/scsi/qla2xxx/qla_sup.c | 348 + drivers/scsi/qla2xxx/qla_version.h | 2 drivers/scsi/qla4xxx/ql4_os.c | 2 drivers/scsi/scsi.c | 22 drivers/scsi/scsi_debug.c | 43 drivers/scsi/scsi_error.c | 256 - drivers/scsi/scsi_lib.c | 7 drivers/scsi/scsi_priv.h | 6 drivers/scsi/scsi_proc.c | 2 drivers/scsi/scsi_scan.c | 2 drivers/scsi/scsi_sysctl.c | 2 drivers/scsi/scsi_tgt_if.c | 2 drivers/scsi/scsi_transport_fc.c | 1 drivers/scsi/scsi_transport_sas.c | 118 drivers/scsi/scsi_transport_spi.c | 1 drivers/scsi/sd.c | 1 drivers/scsi/sim710.c | 1 drivers/scsi/sni_53c710.c | 159 drivers/scsi/sr.c | 1 drivers/scsi/sr_ioctl.c | 1 drivers/scsi/st.c | 25 drivers/scsi/st.h | 3 drivers/scsi/stex.c | 1 drivers/scsi/sun3_scsi.c | 1 drivers/scsi/sun3_scsi_vme.c | 1 drivers/scsi/sun3x_esp.c | 2 drivers/scsi/sym53c416.c | 1 drivers/scsi/t128.c | 1 drivers/scsi/tmscsim.c | 1 drivers/scsi/wd33c93.c | 1 drivers/serial/8250.c | 186 - drivers/serial/8250_acorn.c | 3 drivers/serial/8250_pci.c | 33 drivers/serial/8250_pnp.c | 8 drivers/serial/Kconfig | 31 drivers/serial/Makefile | 2 drivers/serial/atmel_serial.c | 54 drivers/serial/cpm_uart/cpm_uart_cpm1.c | 15 drivers/serial/cpm_uart/cpm_uart_cpm1.h | 3 drivers/serial/cpm_uart/cpm_uart_cpm2.h | 3 drivers/serial/crisv10.c | 14 drivers/serial/icom.c | 5 drivers/serial/ioc3_serial.c | 6 drivers/serial/ioc4_serial.c | 15 drivers/serial/ip22zilog.c | 9 drivers/serial/jsm/jsm_driver.c | 6 drivers/serial/jsm/jsm_tty.c | 12 drivers/serial/mpc52xx_uart.c | 5 drivers/serial/of_serial.c | 143 drivers/serial/pnx8xxx_uart.c | 852 ++ drivers/serial/serial_core.c | 18 drivers/serial/serial_cs.c | 4 drivers/serial/serial_txx9.c | 23 drivers/serial/sunsab.c | 1 drivers/serial/sunsu.c | 1 drivers/serial/sunzilog.c | 1 drivers/serial/uartlite.c | 6 drivers/sn/ioc3.c | 6 drivers/spi/Kconfig | 45 drivers/spi/Makefile | 4 drivers/spi/at25.c | 381 + drivers/spi/atmel_spi.c | 678 ++ drivers/spi/atmel_spi.h | 167 drivers/spi/omap_uwire.c | 572 ++ drivers/spi/pxa2xx_spi.c | 4 drivers/spi/spi.c | 2 drivers/spi/spi_bitbang.c | 11 drivers/spi/spi_imx.c | 1769 +++++ drivers/tc/Makefile | 2 drivers/tc/lk201.c | 1 drivers/tc/tc-driver.c | 110 drivers/tc/tc.c | 339 - drivers/tc/zs.c | 4 drivers/telephony/ixj.c | 41 drivers/telephony/ixj.h | 4 drivers/telephony/ixj_pcmcia.c | 1 drivers/telephony/phonedev.c | 2 drivers/usb/atm/speedtch.c | 2 drivers/usb/class/usblp.c | 16 drivers/usb/core/Kconfig | 13 drivers/usb/core/buffer.c | 36 drivers/usb/core/devices.c | 22 drivers/usb/core/devio.c | 25 drivers/usb/core/driver.c | 39 drivers/usb/core/file.c | 13 drivers/usb/core/generic.c | 28 drivers/usb/core/hcd.c | 137 drivers/usb/core/hcd.h | 6 drivers/usb/core/hub.c | 64 drivers/usb/core/message.c | 6 drivers/usb/core/sysfs.c | 98 drivers/usb/core/urb.c | 21 drivers/usb/core/usb.c | 96 drivers/usb/gadget/at91_udc.c | 22 drivers/usb/gadget/at91_udc.h | 1 drivers/usb/gadget/config.c | 2 drivers/usb/gadget/dummy_hcd.c | 1 drivers/usb/gadget/epautoconf.c | 2 drivers/usb/gadget/ether.c | 149 drivers/usb/gadget/file_storage.c | 35 drivers/usb/gadget/gadget_chips.h | 8 drivers/usb/gadget/gmidi.c | 2 drivers/usb/gadget/goku_udc.c | 3 drivers/usb/gadget/inode.c | 240 - drivers/usb/gadget/lh7a40x_udc.h | 2 drivers/usb/gadget/net2280.c | 3 drivers/usb/gadget/omap_udc.c | 3 drivers/usb/gadget/pxa2xx_udc.c | 5 drivers/usb/gadget/rndis.c | 1 drivers/usb/gadget/serial.c | 3 drivers/usb/gadget/usbstring.c | 2 drivers/usb/gadget/zero.c | 3 drivers/usb/host/Kconfig | 38 drivers/usb/host/ehci-dbg.c | 24 drivers/usb/host/ehci-fsl.c | 8 drivers/usb/host/ehci-hcd.c | 127 drivers/usb/host/ehci-hub.c | 324 + drivers/usb/host/ehci-pci.c | 38 drivers/usb/host/ehci-ps3.c | 193 + drivers/usb/host/ehci-q.c | 16 drivers/usb/host/ehci-sched.c | 22 drivers/usb/host/ehci.h | 46 drivers/usb/host/hc_crisv10.c | 4 drivers/usb/host/ohci-at91.c | 23 drivers/usb/host/ohci-au1xxx.c | 16 drivers/usb/host/ohci-ep93xx.c | 14 drivers/usb/host/ohci-hcd.c | 128 drivers/usb/host/ohci-lh7a404.c | 16 drivers/usb/host/ohci-omap.c | 19 drivers/usb/host/ohci-pci.c | 219 - drivers/usb/host/ohci-pnx4008.c | 14 drivers/usb/host/ohci-pnx8550.c | 18 drivers/usb/host/ohci-ppc-of.c | 232 + drivers/usb/host/ohci-ppc-soc.c | 18 drivers/usb/host/ohci-ps3.c | 196 + drivers/usb/host/ohci-pxa27x.c | 16 drivers/usb/host/ohci-s3c2410.c | 12 drivers/usb/host/ohci-sa1111.c | 16 drivers/usb/host/ohci.h | 155 drivers/usb/host/sl811_cs.c | 1 drivers/usb/host/uhci-debug.c | 71 drivers/usb/host/uhci-hcd.c | 52 drivers/usb/host/uhci-hcd.h | 8 drivers/usb/host/uhci-q.c | 262 + drivers/usb/image/mdc800.c | 4 drivers/usb/image/microtek.c | 1 drivers/usb/input/Kconfig | 20 drivers/usb/input/Makefile | 4 drivers/usb/input/aiptek.c | 1 drivers/usb/input/gtco.c | 1104 +++ drivers/usb/input/hid-core.c | 117 drivers/usb/input/hid-ff.c | 4 drivers/usb/input/hid-lgff.c | 5 drivers/usb/input/hid-pidff.c | 1 drivers/usb/input/hid-plff.c | 129 drivers/usb/misc/adutux.c | 2 drivers/usb/misc/appledisplay.c | 4 drivers/usb/misc/ftdi-elan.c | 2 drivers/usb/misc/idmouse.c | 10 drivers/usb/misc/rio500.c | 54 drivers/usb/misc/sisusbvga/sisusb.c | 1 drivers/usb/misc/sisusbvga/sisusb_con.c | 1 drivers/usb/mon/Makefile | 2 drivers/usb/mon/mon_bin.c | 1172 +++ drivers/usb/mon/mon_dma.c | 39 drivers/usb/mon/mon_main.c | 97 drivers/usb/mon/mon_text.c | 67 drivers/usb/mon/usb_mon.h | 30 drivers/usb/net/Kconfig | 6 drivers/usb/net/asix.c | 5 drivers/usb/net/cdc_ether.c | 61 drivers/usb/net/cdc_subset.c | 1 drivers/usb/net/gl620a.c | 27 drivers/usb/net/kaweth.c | 38 drivers/usb/net/net1080.c | 1 drivers/usb/net/pegasus.h | 4 drivers/usb/net/plusb.c | 1 drivers/usb/net/rndis_host.c | 82 drivers/usb/net/rtl8150.c | 1 drivers/usb/net/usbnet.c | 1 drivers/usb/net/zaurus.c | 1 drivers/usb/serial/aircable.c | 21 drivers/usb/serial/airprime.c | 1 drivers/usb/serial/ark3116.c | 2 drivers/usb/serial/belkin_sa.c | 1 drivers/usb/serial/bus.c | 45 drivers/usb/serial/cp2101.c | 9 drivers/usb/serial/cyberjack.c | 3 drivers/usb/serial/cypress_m8.c | 3 drivers/usb/serial/digi_acceleport.c | 12 drivers/usb/serial/empeg.c | 1 drivers/usb/serial/ftdi_sio.c | 2 drivers/usb/serial/ftdi_sio.h | 1 drivers/usb/serial/funsoft.c | 1 drivers/usb/serial/garmin_gps.c | 1 drivers/usb/serial/generic.c | 35 drivers/usb/serial/hp4x.c | 1 drivers/usb/serial/io_edgeport.c | 417 + drivers/usb/serial/io_edgeport.h | 6 drivers/usb/serial/io_tables.h | 61 drivers/usb/serial/io_ti.c | 2 drivers/usb/serial/io_usbvend.h | 5 drivers/usb/serial/ipaq.c | 1 drivers/usb/serial/ipw.c | 1 drivers/usb/serial/ir-usb.c | 1 drivers/usb/serial/keyspan.c | 49 drivers/usb/serial/keyspan.h | 7 drivers/usb/serial/keyspan_pda.c | 10 drivers/usb/serial/kl5kusb105.c | 1 drivers/usb/serial/kobil_sct.c | 1 drivers/usb/serial/mct_u232.c | 1 drivers/usb/serial/mos7720.c | 30 drivers/usb/serial/mos7840.c | 30 drivers/usb/serial/navman.c | 1 drivers/usb/serial/omninet.c | 1 drivers/usb/serial/option.c | 1 drivers/usb/serial/pl2303.c | 1 drivers/usb/serial/safe_serial.c | 1 drivers/usb/serial/sierra.c | 29 drivers/usb/serial/ti_usb_3410_5052.c | 2 drivers/usb/serial/usb-serial.c | 102 drivers/usb/serial/visor.c | 6 drivers/usb/serial/visor.h | 1 drivers/usb/serial/whiteheat.c | 2 drivers/usb/storage/datafab.c | 1 drivers/usb/storage/initializers.c | 1 drivers/usb/storage/jumpshot.c | 1 drivers/usb/storage/onetouch.c | 1 drivers/usb/storage/scsiglue.c | 31 drivers/usb/storage/sddr09.c | 1 drivers/usb/storage/shuttle_usbat.c | 1 drivers/usb/storage/unusual_devs.h | 9 drivers/usb/storage/usb.c | 23 drivers/video/Kconfig | 97 drivers/video/Makefile | 8 drivers/video/S3triofb.c | 790 -- drivers/video/atafb.c | 1 drivers/video/aty/atyfb_base.c | 4 drivers/video/aty/mach64_accel.c | 1 drivers/video/aty/mach64_gx.c | 1 drivers/video/aty/radeon_i2c.c | 1 drivers/video/au1100fb.c | 6 drivers/video/console/fbcon.c | 5 drivers/video/console/fbcon.h | 2 drivers/video/console/mdacon.c | 1 drivers/video/console/vgacon.c | 1 drivers/video/controlfb.c | 3 drivers/video/cyber2000fb.c | 19 drivers/video/cyberfb.c | 2295 ------- drivers/video/cyberfb.h | 415 - drivers/video/fbmem.c | 1 drivers/video/fbsysfs.c | 2 drivers/video/g364fb.c | 1 drivers/video/geode/gx1fb_core.c | 29 drivers/video/hitfb.c | 1 drivers/video/hpfb.c | 1 drivers/video/i810/i810-i2c.c | 1 drivers/video/i810/i810.h | 3 drivers/video/i810/i810_main.c | 32 drivers/video/igafb.c | 8 drivers/video/imxfb.c | 1 drivers/video/intelfb/intelfb_i2c.c | 1 drivers/video/intelfb/intelfbdrv.c | 3 drivers/video/intelfb/intelfbhw.c | 3 drivers/video/kyro/fbdev.c | 1 drivers/video/macfb.c | 1 drivers/video/matrox/i2c-matroxfb.c | 5 drivers/video/matrox/matroxfb_crtc2.c | 3 drivers/video/maxinefb.c | 1 drivers/video/mbx/mbxdebugfs.c | 12 drivers/video/modedb.c | 48 drivers/video/neofb.c | 22 drivers/video/nvidia/nv_i2c.c | 1 drivers/video/nvidia/nv_of.c | 1 drivers/video/nvidia/nvidia.c | 16 drivers/video/output.c | 129 drivers/video/pm3fb.c | 29 drivers/video/pmag-aa-fb.c | 1 drivers/video/pmag-ba-fb.c | 95 drivers/video/pmagb-b-fb.c | 98 drivers/video/ps3fb.c | 1229 +++ drivers/video/retz3fb.c | 1588 ----- drivers/video/retz3fb.h | 286 - drivers/video/riva/fbdev.c | 27 drivers/video/riva/rivafb-i2c.c | 1 drivers/video/riva/rivafb.h | 3 drivers/video/s3c2410fb.c | 2 drivers/video/s3fb.c | 1180 +++ drivers/video/sa1100fb.h | 4 drivers/video/savage/savagefb-i2c.c | 1 drivers/video/savage/savagefb_driver.c | 12 drivers/video/sis/init.c | 140 drivers/video/sis/init.h | 36 drivers/video/sis/init301.c | 260 - drivers/video/sis/init301.h | 14 drivers/video/sis/initextlfb.c | 18 drivers/video/sis/sis.h | 2 drivers/video/sis/sis_main.c | 214 - drivers/video/sis/sis_main.h | 112 drivers/video/sis/vgatypes.h | 12 drivers/video/sis/vstruct.h | 44 drivers/video/sun3fb.c | 702 -- drivers/video/svgalib.c | 632 ++ drivers/video/tgafb.c | 186 - drivers/video/vga16fb.c | 23 drivers/video/virgefb.c | 2526 ------- drivers/video/virgefb.h | 288 - drivers/w1/slaves/w1_therm.c | 6 drivers/zorro/proc.c | 2 fs/9p/vfs_file.c | 4 fs/9p/vfs_inode.c | 23 fs/9p/vfs_super.c | 4 fs/Kconfig | 38 fs/adfs/adfs.h | 4 fs/adfs/dir.c | 2 fs/adfs/file.c | 2 fs/adfs/super.c | 2 fs/affs/affs.h | 6 fs/affs/dir.c | 2 fs/affs/file.c | 2 fs/affs/inode.c | 2 fs/affs/super.c | 2 fs/affs/symlink.c | 2 fs/afs/cell.c | 1 fs/afs/dir.c | 3 fs/afs/file.c | 3 fs/afs/inode.c | 1 fs/afs/internal.h | 6 fs/afs/main.c | 1 fs/afs/mntpt.c | 3 fs/afs/proc.c | 1 fs/afs/super.c | 2 fs/aio.c | 5 fs/autofs/autofs_i.h | 4 fs/autofs/inode.c | 2 fs/autofs/root.c | 2 fs/autofs/symlink.c | 2 fs/autofs4/autofs_i.h | 10 fs/autofs4/inode.c | 2 fs/autofs4/root.c | 6 fs/autofs4/symlink.c | 2 fs/bad_inode.c | 2 fs/befs/linuxvfs.c | 4 fs/bfs/bfs.h | 4 fs/bfs/dir.c | 2 fs/bfs/file.c | 2 fs/bfs/inode.c | 2 fs/binfmt_elf.c | 3 fs/binfmt_elf_fdpic.c | 2 fs/binfmt_flat.c | 31 fs/binfmt_misc.c | 2 fs/block_dev.c | 2 fs/buffer.c | 19 fs/char_dev.c | 7 fs/cifs/CHANGES | 9 fs/cifs/TODO | 8 fs/cifs/cifsfs.c | 20 fs/cifs/cifsfs.h | 10 fs/cifs/cifspdu.h | 84 fs/cifs/cifsproto.h | 5 fs/cifs/cifssmb.c | 16 fs/cifs/connect.c | 130 fs/cifs/file.c | 17 fs/cifs/inode.c | 6 fs/cifs/readdir.c | 12 fs/cifs/smbdes.c | 10 fs/coda/cnode.c | 2 fs/coda/dir.c | 2 fs/coda/inode.c | 4 fs/coda/pioctl.c | 2 fs/coda/sysctl.c | 136 fs/configfs/configfs_internal.h | 4 fs/configfs/dir.c | 5 fs/configfs/file.c | 9 fs/configfs/inode.c | 2 fs/configfs/mount.c | 2 fs/configfs/symlink.c | 2 fs/cramfs/inode.c | 8 fs/debugfs/file.c | 2 fs/devpts/inode.c | 2 fs/dlm/Kconfig | 18 fs/dlm/config.c | 154 fs/dlm/config.h | 17 fs/dlm/debug_fs.c | 4 fs/dlm/dlm_internal.h | 20 fs/dlm/lock.c | 87 fs/dlm/lockspace.c | 10 fs/dlm/lowcomms-sctp.c | 151 fs/dlm/lowcomms-tcp.c | 384 - fs/dlm/memory.c | 4 fs/dlm/midcomms.c | 4 fs/dlm/rcom.c | 85 fs/dlm/recover.c | 8 fs/dlm/recoverd.c | 22 fs/dlm/user.c | 15 fs/dlm/util.c | 4 fs/dquot.c | 61 fs/drop_caches.c | 2 fs/ecryptfs/Makefile | 2 fs/ecryptfs/crypto.c | 337 + fs/ecryptfs/debug.c | 6 fs/ecryptfs/ecryptfs_kernel.h | 162 fs/ecryptfs/file.c | 52 fs/ecryptfs/inode.c | 93 fs/ecryptfs/keystore.c | 825 ++ fs/ecryptfs/main.c | 87 fs/ecryptfs/messaging.c | 516 + fs/ecryptfs/mmap.c | 378 + fs/ecryptfs/netlink.c | 255 + fs/ecryptfs/super.c | 2 fs/efs/dir.c | 2 fs/efs/super.c | 2 fs/exec.c | 4 fs/ext2/dir.c | 8 fs/ext2/ext2.h | 10 fs/ext2/file.c | 2 fs/ext2/namei.c | 4 fs/ext2/super.c | 6 fs/ext2/symlink.c | 4 fs/ext3/file.c | 2 fs/ext3/hash.c | 1 fs/ext3/inode.c | 4 fs/ext3/namei.c | 31 fs/ext3/resize.c | 1 fs/ext3/super.c | 22 fs/ext3/symlink.c | 4 fs/ext4/file.c | 2 fs/ext4/hash.c | 1 fs/ext4/inode.c | 4 fs/ext4/namei.c | 31 fs/ext4/resize.c | 1 fs/ext4/super.c | 22 fs/ext4/symlink.c | 4 fs/fat/file.c | 2 fs/fat/inode.c | 4 fs/filesystems.c | 1 fs/freevxfs/vxfs_extern.h | 2 fs/freevxfs/vxfs_immed.c | 2 fs/freevxfs/vxfs_inode.c | 2 fs/freevxfs/vxfs_lookup.c | 2 fs/freevxfs/vxfs_super.c | 2 fs/fuse/control.c | 2 fs/fuse/dir.c | 6 fs/fuse/file.c | 2 fs/fuse/inode.c | 4 fs/gfs2/Kconfig | 47 fs/gfs2/bmap.c | 11 fs/gfs2/dir.c | 26 fs/gfs2/dir.h | 21 fs/gfs2/eaops.c | 1 fs/gfs2/eattr.c | 9 fs/gfs2/glock.c | 316 - fs/gfs2/glock.h | 11 fs/gfs2/glops.c | 137 fs/gfs2/incore.h | 18 fs/gfs2/inode.c | 61 fs/gfs2/lm.c | 9 fs/gfs2/locking/dlm/lock_dlm.h | 2 fs/gfs2/locking/dlm/main.c | 6 fs/gfs2/locking/dlm/mount.c | 6 fs/gfs2/locking/dlm/plock.c | 2 fs/gfs2/locking/dlm/sysfs.c | 13 fs/gfs2/lops.c | 14 fs/gfs2/main.c | 1 fs/gfs2/meta_io.c | 3 fs/gfs2/mount.c | 1 fs/gfs2/ondisk.c | 1 fs/gfs2/ops_address.c | 134 fs/gfs2/ops_dentry.c | 17 fs/gfs2/ops_export.c | 16 fs/gfs2/ops_file.c | 53 fs/gfs2/ops_inode.c | 64 fs/gfs2/ops_inode.h | 8 fs/gfs2/ops_super.c | 13 fs/gfs2/ops_super.h | 2 fs/gfs2/ops_vm.c | 25 fs/gfs2/recovery.c | 1 fs/gfs2/rgrp.c | 1 fs/gfs2/super.c | 16 fs/gfs2/sys.c | 10 fs/gfs2/util.c | 1 fs/hfs/dir.c | 2 fs/hfs/hfs.h | 2 fs/hfs/hfs_fs.h | 2 fs/hfs/inode.c | 4 fs/hfs/super.c | 2 fs/hfsplus/catalog.c | 1 fs/hfsplus/dir.c | 3 fs/hfsplus/hfsplus_raw.h | 2 fs/hfsplus/inode.c | 4 fs/hfsplus/super.c | 3 fs/hostfs/hostfs_kern.c | 10 fs/hpfs/file.c | 2 fs/hpfs/hpfs_fn.h | 4 fs/hpfs/namei.c | 2 fs/hpfs/super.c | 2 fs/hppfs/hppfs_kern.c | 10 fs/hugetlbfs/inode.c | 17 fs/inode.c | 42 fs/inotify_user.c | 10 fs/ioprio.c | 18 fs/isofs/dir.c | 2 fs/isofs/inode.c | 2 fs/isofs/isofs.h | 2 fs/jffs/inode-v23.c | 16 fs/jffs2/compr_zlib.c | 1 fs/jffs2/dir.c | 3 fs/jffs2/file.c | 2 fs/jffs2/os-linux.h | 6 fs/jffs2/summary.c | 1 fs/jffs2/super.c | 2 fs/jffs2/symlink.c | 2 fs/jfs/file.c | 2 fs/jfs/inode.c | 6 fs/jfs/jfs_debug.h | 5 fs/jfs/jfs_dmap.c | 16 fs/jfs/jfs_imap.c | 16 fs/jfs/jfs_incore.h | 29 fs/jfs/jfs_inode.h | 6 fs/jfs/jfs_lock.h | 2 fs/jfs/jfs_metapage.c | 2 fs/jfs/jfs_txnmgr.c | 2 fs/jfs/jfs_xtree.c | 15 fs/jfs/namei.c | 50 fs/jfs/super.c | 4 fs/jfs/symlink.c | 2 fs/libfs.c | 6 fs/lockd/clntproc.c | 9 fs/lockd/host.c | 3 fs/lockd/svc.c | 34 fs/lockd/svc4proc.c | 13 fs/lockd/svclock.c | 4 fs/lockd/svcproc.c | 13 fs/minix/bitmap.c | 69 fs/minix/dir.c | 162 fs/minix/file.c | 2 fs/minix/inode.c | 53 fs/minix/itree_common.c | 16 fs/minix/itree_v1.c | 4 fs/minix/itree_v2.c | 7 fs/minix/minix.h | 16 fs/minix/namei.c | 2 fs/msdos/namei.c | 2 fs/namei.c | 5 fs/namespace.c | 3 fs/ncpfs/dir.c | 2 fs/ncpfs/file.c | 2 fs/ncpfs/inode.c | 4 fs/nfs/callback.c | 34 fs/nfs/callback_xdr.c | 4 fs/nfs/client.c | 22 fs/nfs/dir.c | 43 fs/nfs/direct.c | 8 fs/nfs/file.c | 4 fs/nfs/getroot.c | 11 fs/nfs/inode.c | 50 fs/nfs/internal.h | 4 fs/nfs/namespace.c | 4 fs/nfs/nfs3proc.c | 24 fs/nfs/nfs4_fs.h | 4 fs/nfs/nfs4namespace.c | 16 fs/nfs/nfs4proc.c | 62 fs/nfs/nfs4renewd.c | 1 fs/nfs/nfs4xdr.c | 2 fs/nfs/proc.c | 30 fs/nfs/read.c | 109 fs/nfs/super.c | 7 fs/nfs/symlink.c | 2 fs/nfs/sysctl.c | 2 fs/nfs/write.c | 91 fs/nfsd/export.c | 107 fs/nfsd/nfs3xdr.c | 31 fs/nfsd/nfs4acl.c | 491 + fs/nfsd/nfs4callback.c | 7 fs/nfsd/nfs4idmap.c | 1 fs/nfsd/nfs4state.c | 18 fs/nfsd/nfs4xdr.c | 65 fs/nfsd/nfscache.c | 2 fs/nfsd/nfsctl.c | 2 fs/nfsd/nfsfh.c | 152 fs/nfsd/nfsproc.c | 7 fs/nfsd/nfssvc.c | 6 fs/nfsd/nfsxdr.c | 19 fs/nfsd/vfs.c | 5 fs/ntfs/attrib.c | 2 fs/ntfs/file.c | 4 fs/ntfs/namei.c | 2 fs/ntfs/ntfs.h | 6 fs/ntfs/super.c | 2 fs/ntfs/sysctl.c | 34 fs/ocfs2/cluster/heartbeat.c | 158 fs/ocfs2/cluster/nodemanager.c | 6 fs/ocfs2/cluster/nodemanager.h | 3 fs/ocfs2/cluster/tcp.c | 35 fs/ocfs2/cluster/tcp.h | 6 fs/ocfs2/cluster/tcp_internal.h | 12 fs/ocfs2/dlm/dlmast.c | 14 fs/ocfs2/dlm/dlmcommon.h | 130 fs/ocfs2/dlm/dlmconvert.c | 40 fs/ocfs2/dlm/dlmdebug.c | 30 fs/ocfs2/dlm/dlmdomain.c | 253 + fs/ocfs2/dlm/dlmfs.c | 20 fs/ocfs2/dlm/dlmlock.c | 7 fs/ocfs2/dlm/dlmmaster.c | 579 +- fs/ocfs2/dlm/dlmrecovery.c | 182 - fs/ocfs2/dlm/dlmthread.c | 200 - fs/ocfs2/dlm/dlmunlock.c | 15 fs/ocfs2/file.c | 4 fs/ocfs2/file.h | 4 fs/ocfs2/journal.h | 4 fs/ocfs2/namei.c | 2 fs/ocfs2/namei.h | 2 fs/ocfs2/super.c | 2 fs/ocfs2/symlink.c | 4 fs/ocfs2/symlink.h | 4 fs/ocfs2/vote.c | 8 fs/openpromfs/inode.c | 4 fs/partitions/check.c | 15 fs/partitions/msdos.c | 22 fs/partitions/sgi.c | 2 fs/partitions/sun.c | 5 fs/proc/Makefile | 2 fs/proc/array.c | 2 fs/proc/base.c | 56 fs/proc/generic.c | 12 fs/proc/inode.c | 3 fs/proc/internal.h | 14 fs/proc/nommu.c | 2 fs/proc/proc_misc.c | 54 fs/proc/proc_sysctl.c | 479 + fs/proc/proc_tty.c | 2 fs/proc/root.c | 18 fs/proc/task_mmu.c | 6 fs/proc/task_nommu.c | 2 fs/qnx4/dir.c | 2 fs/qnx4/file.c | 2 fs/qnx4/inode.c | 4 fs/ramfs/file-mmu.c | 4 fs/ramfs/file-nommu.c | 4 fs/ramfs/inode.c | 8 fs/ramfs/internal.h | 2 fs/read_write.c | 26 fs/reiserfs/do_balan.c | 5 fs/reiserfs/file.c | 2 fs/reiserfs/namei.c | 6 fs/reiserfs/super.c | 2 fs/romfs/inode.c | 6 fs/smbfs/dir.c | 4 fs/smbfs/file.c | 2 fs/smbfs/inode.c | 2 fs/smbfs/proto.h | 8 fs/smbfs/request.c | 3 fs/smbfs/symlink.c | 3 fs/super.c | 2 fs/sysfs/bin.c | 6 fs/sysfs/dir.c | 219 + fs/sysfs/file.c | 82 fs/sysfs/group.c | 2 fs/sysfs/inode.c | 38 fs/sysfs/mount.c | 13 fs/sysfs/symlink.c | 3 fs/sysfs/sysfs.h | 25 fs/sysv/file.c | 2 fs/sysv/inode.c | 4 fs/sysv/namei.c | 2 fs/sysv/symlink.c | 2 fs/sysv/sysv.h | 8 fs/udf/file.c | 2 fs/udf/namei.c | 2 fs/udf/super.c | 2 fs/udf/udfdecl.h | 4 fs/ufs/balloc.c | 198 - fs/ufs/dir.c | 22 fs/ufs/ialloc.c | 116 fs/ufs/inode.c | 193 - fs/ufs/namei.c | 2 fs/ufs/super.c | 54 fs/ufs/symlink.c | 2 fs/ufs/truncate.c | 141 fs/ufs/util.h | 57 fs/vfat/namei.c | 2 fs/xattr_acl.c | 1 fs/xfs/linux-2.6/kmem.c | 1 fs/xfs/linux-2.6/mrlock.h | 6 fs/xfs/linux-2.6/xfs_aops.c | 18 fs/xfs/linux-2.6/xfs_buf.c | 142 fs/xfs/linux-2.6/xfs_buf.h | 4 fs/xfs/linux-2.6/xfs_export.c | 2 fs/xfs/linux-2.6/xfs_file.c | 4 fs/xfs/linux-2.6/xfs_ioctl.c | 51 fs/xfs/linux-2.6/xfs_iops.c | 12 fs/xfs/linux-2.6/xfs_iops.h | 6 fs/xfs/linux-2.6/xfs_linux.h | 10 fs/xfs/linux-2.6/xfs_lrw.c | 48 fs/xfs/linux-2.6/xfs_lrw.h | 2 fs/xfs/linux-2.6/xfs_super.c | 33 fs/xfs/linux-2.6/xfs_sysctl.c | 266 + fs/xfs/linux-2.6/xfs_vfs.h | 2 fs/xfs/linux-2.6/xfs_vnode.c | 2 fs/xfs/linux-2.6/xfs_vnode.h | 4 fs/xfs/quota/xfs_dquot.c | 4 fs/xfs/quota/xfs_dquot_item.c | 8 fs/xfs/quota/xfs_qm.c | 8 fs/xfs/quota/xfs_qm_bhv.c | 4 fs/xfs/quota/xfs_qm_stats.c | 2 fs/xfs/quota/xfs_qm_syscalls.c | 4 fs/xfs/quota/xfs_trans_dquot.c | 2 fs/xfs/support/debug.c | 23 fs/xfs/support/debug.h | 30 fs/xfs/support/move.h | 4 fs/xfs/xfs_acl.c | 1 fs/xfs/xfs_alloc_btree.h | 10 fs/xfs/xfs_attr.c | 49 fs/xfs/xfs_attr_leaf.c | 54 fs/xfs/xfs_bit.c | 2 fs/xfs/xfs_bmap.c | 101 fs/xfs/xfs_bmap.h | 1 fs/xfs/xfs_bmap_btree.c | 86 fs/xfs/xfs_bmap_btree.h | 59 fs/xfs/xfs_btree.h | 6 fs/xfs/xfs_buf_item.c | 2 fs/xfs/xfs_buf_item.h | 18 fs/xfs/xfs_cap.h | 70 fs/xfs/xfs_da_btree.c | 18 fs/xfs/xfs_da_btree.h | 1 fs/xfs/xfs_dfrag.c | 1 fs/xfs/xfs_error.c | 26 fs/xfs/xfs_error.h | 3 fs/xfs/xfs_extfree_item.c | 4 fs/xfs/xfs_fsops.c | 60 fs/xfs/xfs_ialloc.c | 2 fs/xfs/xfs_ialloc_btree.h | 10 fs/xfs/xfs_inode.c | 30 fs/xfs/xfs_inode_item.c | 2 fs/xfs/xfs_iomap.c | 10 fs/xfs/xfs_log_recover.c | 61 fs/xfs/xfs_mac.h | 106 fs/xfs/xfs_mount.c | 288 - fs/xfs/xfs_mount.h | 39 fs/xfs/xfs_rename.c | 2 fs/xfs/xfs_rtalloc.c | 110 fs/xfs/xfs_rtalloc.h | 18 fs/xfs/xfs_rw.c | 1 fs/xfs/xfs_trans.c | 32 fs/xfs/xfs_trans.h | 46 fs/xfs/xfs_trans_ail.c | 2 fs/xfs/xfs_vfsops.c | 45 fs/xfs/xfs_vnodeops.c | 22 include/acpi/acconfig.h | 13 include/acpi/acdebug.h | 8 include/acpi/acdisasm.h | 22 include/acpi/acdispat.h | 4 include/acpi/acevents.h | 2 include/acpi/acexcep.h | 10 include/acpi/acglobal.h | 117 include/acpi/achware.h | 6 include/acpi/acinterp.h | 14 include/acpi/aclocal.h | 77 include/acpi/acmacros.h | 71 include/acpi/acnames.h | 2 include/acpi/acnamesp.h | 21 include/acpi/acobject.h | 19 include/acpi/acopcode.h | 4 include/acpi/acoutput.h | 2 include/acpi/acparser.h | 2 include/acpi/acpi.h | 2 include/acpi/acpi_bus.h | 23 include/acpi/acpi_drivers.h | 15 include/acpi/acpiosxf.h | 8 include/acpi/acpixf.h | 34 include/acpi/acresrc.h | 2 include/acpi/acstruct.h | 5 include/acpi/actables.h | 106 include/acpi/actbl.h | 333 - include/acpi/actbl1.h | 568 +- include/acpi/actbl2.h | 49 include/acpi/actbl71.h | 134 include/acpi/actypes.h | 106 include/acpi/acutils.h | 8 include/acpi/amlcode.h | 4 include/acpi/amlresrc.h | 2 include/acpi/platform/acenv.h | 2 include/acpi/platform/acgcc.h | 2 include/acpi/platform/aclinux.h | 2 include/acpi/processor.h | 1 include/asm-alpha/io.h | 9 include/asm-alpha/mman.h | 1 include/asm-alpha/pci.h | 2 include/asm-alpha/percpu.h | 14 include/asm-alpha/termios.h | 18 include/asm-arm/apm.h | 64 include/asm-arm/arch-at91rm9200/gpio.h | 48 include/asm-arm/arch-imx/spi_imx.h | 72 include/asm-arm/arch-ixp4xx/io.h | 3 include/asm-arm/arch-omap/gpio.h | 66 include/asm-arm/arch-pxa/gpio.h | 72 include/asm-arm/arch-s3c2410/gpio.h | 65 include/asm-arm/arch-sa1100/gpio.h | 81 include/asm-arm/gpio.h | 7 include/asm-arm/hardware/gpio_keys.h | 17 include/asm-arm/io.h | 5 include/asm-arm/spinlock.h | 1 include/asm-arm/termios.h | 18 include/asm-arm/uaccess.h | 4 include/asm-arm26/termios.h | 18 include/asm-arm26/uaccess-asm.h | 4 include/asm-avr32/arch-at32ap/at32ap7000.h | 2 include/asm-avr32/arch-at32ap/board.h | 4 include/asm-avr32/arch-at32ap/gpio.h | 27 include/asm-avr32/arch-at32ap/irq.h | 14 include/asm-avr32/arch-at32ap/portmux.h | 8 include/asm-avr32/checksum.h | 2 include/asm-avr32/dma-mapping.h | 8 include/asm-avr32/gpio.h | 6 include/asm-avr32/io.h | 23 include/asm-avr32/irq.h | 8 include/asm-avr32/posix_types.h | 2 include/asm-avr32/termios.h | 18 include/asm-avr32/uaccess.h | 6 include/asm-avr32/unistd.h | 17 include/asm-cris/io.h | 5 include/asm-cris/semaphore-helper.h | 9 include/asm-cris/system.h | 3 include/asm-cris/termios.h | 18 include/asm-frv/termios.h | 18 include/asm-generic/dma-mapping-broken.h | 4 include/asm-generic/gpio.h | 25 include/asm-generic/memory_model.h | 2 include/asm-generic/mman.h | 1 include/asm-generic/pgtable.h | 13 include/asm-h8300/termios.h | 18 include/asm-i386/acpi.h | 24 include/asm-i386/apic.h | 11 include/asm-i386/atomic.h | 4 include/asm-i386/bitops.h | 4 include/asm-i386/bugs.h | 2 include/asm-i386/desc.h | 2 include/asm-i386/elf.h | 4 include/asm-i386/hpet.h | 16 include/asm-i386/i8253.h | 15 include/asm-i386/idle.h | 14 include/asm-i386/io.h | 6 include/asm-i386/mach-default/do_timer.h | 78 include/asm-i386/mach-es7000/mach_mpparse.h | 17 include/asm-i386/mach-voyager/do_timer.h | 27 include/asm-i386/mce.h | 2 include/asm-i386/mmu_context.h | 2 include/asm-i386/mpspec.h | 1 include/asm-i386/msr.h | 3 include/asm-i386/paravirt.h | 168 include/asm-i386/pda.h | 12 include/asm-i386/pgalloc.h | 30 include/asm-i386/processor.h | 14 include/asm-i386/ptrace.h | 8 include/asm-i386/segment.h | 19 include/asm-i386/setup.h | 4 include/asm-i386/smp.h | 5 include/asm-i386/termios.h | 18 include/asm-i386/time.h | 1 include/asm-i386/timer.h | 3 include/asm-i386/tsc.h | 49 include/asm-i386/uaccess.h | 4 include/asm-i386/vmi.h | 262 + include/asm-i386/vmi_time.h | 103 include/asm-ia64/acpi.h | 10 include/asm-ia64/dma-mapping.h | 15 include/asm-ia64/dma.h | 2 include/asm-ia64/esi.h | 1 include/asm-ia64/libata-portmap.h | 12 include/asm-ia64/machvec.h | 3 include/asm-ia64/meminit.h | 3 include/asm-ia64/pgalloc.h | 3 include/asm-ia64/setup.h | 2 include/asm-ia64/sn/acpi.h | 3 include/asm-ia64/sn/pcibr_provider.h | 2 include/asm-ia64/sn/pcidev.h | 8 include/asm-ia64/swiotlb.h | 9 include/asm-ia64/termios.h | 18 include/asm-ia64/thread_info.h | 4 include/asm-ia64/unistd.h | 4 include/asm-m32r/a.out.h | 2 include/asm-m32r/addrspace.h | 1 include/asm-m32r/bugs.h | 2 include/asm-m32r/byteorder.h | 2 include/asm-m32r/cache.h | 2 include/asm-m32r/cacheflush.h | 1 include/asm-m32r/current.h | 3 include/asm-m32r/delay.h | 2 include/asm-m32r/dma.h | 2 include/asm-m32r/errno.h | 3 include/asm-m32r/ide.h | 6 include/asm-m32r/ioctls.h | 5 include/asm-m32r/ipcbuf.h | 4 include/asm-m32r/kmap_types.h | 4 include/asm-m32r/m32104ut/m32104ut_pld.h | 11 include/asm-m32r/m32700ut/m32700ut_lan.h | 13 include/asm-m32r/m32700ut/m32700ut_lcd.h | 13 include/asm-m32r/m32700ut/m32700ut_pld.h | 13 include/asm-m32r/mappi2/mappi2_pld.h | 13 include/asm-m32r/mappi3/mappi3_pld.h | 11 include/asm-m32r/mc146818rtc.h | 3 include/asm-m32r/mman.h | 2 include/asm-m32r/mmu.h | 10 include/asm-m32r/mmu_context.h | 9 include/asm-m32r/module.h | 3 include/asm-m32r/msgbuf.h | 4 include/asm-m32r/namei.h | 4 include/asm-m32r/opsput/opsput_lan.h | 13 include/asm-m32r/opsput/opsput_lcd.h | 13 include/asm-m32r/opsput/opsput_pld.h | 13 include/asm-m32r/page.h | 5 include/asm-m32r/param.h | 4 include/asm-m32r/pci.h | 2 include/asm-m32r/pgalloc.h | 3 include/asm-m32r/pgtable-2level.h | 3 include/asm-m32r/posix_types.h | 4 include/asm-m32r/rtc.h | 4 include/asm-m32r/scatterlist.h | 2 include/asm-m32r/sections.h | 1 include/asm-m32r/segment.h | 4 include/asm-m32r/sembuf.h | 4 include/asm-m32r/setup.h | 4 include/asm-m32r/shmbuf.h | 4 include/asm-m32r/shmparam.h | 2 include/asm-m32r/sigcontext.h | 3 include/asm-m32r/siginfo.h | 2 include/asm-m32r/signal.h | 4 include/asm-m32r/smp.h | 3 include/asm-m32r/sockios.h | 2 include/asm-m32r/spinlock_types.h | 2 include/asm-m32r/stat.h | 4 include/asm-m32r/string.h | 2 include/asm-m32r/syscall.h | 3 include/asm-m32r/system.h | 2 include/asm-m32r/termbits.h | 4 include/asm-m32r/termios.h | 20 include/asm-m32r/timex.h | 3 include/asm-m32r/tlbflush.h | 1 include/asm-m32r/types.h | 6 include/asm-m32r/uaccess.h | 4 include/asm-m32r/ucontext.h | 2 include/asm-m32r/unaligned.h | 8 include/asm-m32r/unistd.h | 2 include/asm-m32r/user.h | 6 include/asm-m32r/vga.h | 4 include/asm-m32r/xor.h | 2 include/asm-m68k/math-emu.h | 15 include/asm-m68k/termios.h | 18 include/asm-m68k/user.h | 2 include/asm-m68knommu/bitops.h | 1 include/asm-mips/apm.h | 64 include/asm-mips/atomic.h | 50 include/asm-mips/bitops.h | 33 include/asm-mips/bootinfo.h | 4 include/asm-mips/compat-signal.h | 55 include/asm-mips/ddb5xxx/ddb5477.h | 41 include/asm-mips/dec/interrupts.h | 3 include/asm-mips/dec/system.h | 3 include/asm-mips/dec/tc.h | 41 include/asm-mips/dec/tcinfo.h | 47 include/asm-mips/dec/tcmodule.h | 39 include/asm-mips/dma-mapping.h | 2 include/asm-mips/dma.h | 1 include/asm-mips/emma2rh/emma2rh.h | 5 include/asm-mips/emma2rh/markeins.h | 1 include/asm-mips/i8259.h | 3 include/asm-mips/io.h | 10 include/asm-mips/irq.h | 2 include/asm-mips/irq_cpu.h | 6 include/asm-mips/mach-au1x00/au1000.h | 1 include/asm-mips/mach-cobalt/cobalt.h | 4 include/asm-mips/mach-emma2rh/irq.h | 2 include/asm-mips/mach-generic/dma-coherence.h | 43 include/asm-mips/mach-generic/irq.h | 32 include/asm-mips/mach-generic/kmalloc.h | 1 include/asm-mips/mach-ip27/dma-coherence.h | 49 include/asm-mips/mach-ip32/dma-coherence.h | 71 include/asm-mips/mach-jazz/dma-coherence.h | 40 include/asm-mips/mach-mips/irq.h | 2 include/asm-mips/mach-vr41xx/irq.h | 11 include/asm-mips/mips-boards/atlasint.h | 4 include/asm-mips/mips-boards/maltaint.h | 4 include/asm-mips/mips-boards/prom.h | 1 include/asm-mips/mips-boards/seadint.h | 4 include/asm-mips/mips-boards/simint.h | 3 include/asm-mips/mips_mt.h | 3 include/asm-mips/mipsmtregs.h | 2 include/asm-mips/mman.h | 1 include/asm-mips/page.h | 25 include/asm-mips/rtlx.h | 3 include/asm-mips/sections.h | 2 include/asm-mips/sgi/ip22.h | 13 include/asm-mips/sigcontext.h | 4 include/asm-mips/smtc_ipi.h | 3 include/asm-mips/spinlock.h | 56 include/asm-mips/system.h | 20 include/asm-mips/termios.h | 18 include/asm-mips/uaccess.h | 14 include/asm-mips/vr41xx/cmbvr4133.h | 5 include/asm-parisc/io.h | 9 include/asm-parisc/mman.h | 1 include/asm-parisc/termios.h | 18 include/asm-powerpc/Kbuild | 1 include/asm-powerpc/cell-pmu.h | 15 include/asm-powerpc/cputable.h | 13 include/asm-powerpc/dcr.h | 1 include/asm-powerpc/elf.h | 2 include/asm-powerpc/firmware.h | 10 include/asm-powerpc/floppy.h | 135 include/asm-powerpc/fs_pd.h | 49 include/asm-powerpc/hvcall.h | 1 include/asm-powerpc/io.h | 6 include/asm-powerpc/iommu.h | 1 include/asm-powerpc/ipic.h | 2 include/asm-powerpc/irq.h | 3 include/asm-powerpc/kprobes.h | 7 include/asm-powerpc/mmu.h | 1 include/asm-powerpc/mpc52xx.h | 2 include/asm-powerpc/mpc8260.h | 24 include/asm-powerpc/mpc8xx.h | 28 include/asm-powerpc/mpic.h | 24 include/asm-powerpc/oprofile_impl.h | 89 include/asm-powerpc/pci-bridge.h | 2 include/asm-powerpc/ps3.h | 234 - include/asm-powerpc/ps3av.h | 738 ++ include/asm-powerpc/ps3fb.h | 56 include/asm-powerpc/reg.h | 14 include/asm-powerpc/smp.h | 1 include/asm-powerpc/spu.h | 14 include/asm-powerpc/spu_priv1.h | 2 include/asm-powerpc/sstep.h | 1 include/asm-powerpc/systbl.h | 1 include/asm-powerpc/termios.h | 18 include/asm-powerpc/time.h | 2 include/asm-powerpc/ucc_slow.h | 2 include/asm-powerpc/udbg.h | 3 include/asm-powerpc/vdso.h | 5 include/asm-ppc/commproc.h | 1 include/asm-ppc/ibm4xx.h | 5 include/asm-ppc/io.h | 2 include/asm-ppc/m48t35.h | 77 include/asm-ppc/reg_booke.h | 2 include/asm-ppc/serial.h | 2 include/asm-s390/ccwdev.h | 2 include/asm-s390/compat.h | 28 include/asm-s390/etr.h | 219 + include/asm-s390/hardirq.h | 2 include/asm-s390/io.h | 75 include/asm-s390/kdebug.h | 3 include/asm-s390/lowcore.h | 6 include/asm-s390/mmu_context.h | 50 include/asm-s390/pgalloc.h | 85 include/asm-s390/pgtable.h | 147 include/asm-s390/processor.h | 27 include/asm-s390/ptrace.h | 11 include/asm-s390/reset.h | 3 include/asm-s390/sclp.h | 39 include/asm-s390/sections.h | 2 include/asm-s390/setup.h | 23 include/asm-s390/sfp-util.h | 66 include/asm-s390/smp.h | 6 include/asm-s390/system.h | 4 include/asm-s390/tape390.h | 72 include/asm-s390/termios.h | 18 include/asm-s390/timer.h | 3 include/asm-s390/timex.h | 50 include/asm-s390/tlbflush.h | 9 include/asm-s390/uaccess.h | 2 include/asm-sh/Kbuild | 2 include/asm-sh/apm.h | 46 include/asm-sh/bigsur/bigsur.h | 80 include/asm-sh/bigsur/io.h | 35 include/asm-sh/bigsur/serial.h | 24 include/asm-sh/bugs.h | 6 include/asm-sh/cacheflush.h | 3 include/asm-sh/cpu-sh3/cacheflush.h | 2 include/asm-sh/cpu-sh4/cacheflush.h | 13 include/asm-sh/cpu-sh4/dma.h | 11 include/asm-sh/dma-mapping.h | 4 include/asm-sh/ec3104/ec3104.h | 43 include/asm-sh/ec3104/io.h | 16 include/asm-sh/ec3104/keyboard.h | 15 include/asm-sh/ec3104/serial.h | 20 include/asm-sh/irq.h | 4 include/asm-sh/kgdb.h | 8 include/asm-sh/mmu.h | 20 include/asm-sh/mmu_context.h | 61 include/asm-sh/page.h | 3 include/asm-sh/pgtable.h | 11 include/asm-sh/processor.h | 6 include/asm-sh/rts7751r2d.h | 4 include/asm-sh/serial.h | 11 include/asm-sh/termios.h | 18 include/asm-sh/thread_info.h | 16 include/asm-sh/tlbflush.h | 38 include/asm-sh/ubc.h | 2 include/asm-sh/unistd.h | 20 include/asm-sh/voyagergx.h | 5 include/asm-sh64/termios.h | 18 include/asm-sparc/io.h | 29 include/asm-sparc/termios.h | 18 include/asm-sparc64/irq.h | 4 include/asm-sparc64/pbm.h | 28 include/asm-sparc64/setup.h | 2 include/asm-sparc64/termios.h | 18 include/asm-um/elf-ppc.h | 2 include/asm-um/processor-x86_64.h | 6 include/asm-um/ptrace-x86_64.h | 9 include/asm-v850/termios.h | 18 include/asm-x86_64/acpi.h | 24 include/asm-x86_64/bitops.h | 2 include/asm-x86_64/bootsetup.h | 2 include/asm-x86_64/dma-mapping.h | 3 include/asm-x86_64/e820.h | 2 include/asm-x86_64/hpet.h | 7 include/asm-x86_64/hw_irq.h | 2 include/asm-x86_64/io.h | 8 include/asm-x86_64/io_apic.h | 14 include/asm-x86_64/mce.h | 2 include/asm-x86_64/mmzone.h | 18 include/asm-x86_64/mutex.h | 6 include/asm-x86_64/pgalloc.h | 5 include/asm-x86_64/pgtable.h | 9 include/asm-x86_64/proto.h | 7 include/asm-x86_64/setup.h | 2 include/asm-x86_64/swiotlb.h | 8 include/asm-x86_64/termios.h | 18 include/asm-x86_64/timex.h | 35 include/asm-x86_64/tsc.h | 66 include/asm-x86_64/uaccess.h | 18 include/asm-x86_64/vsyscall.h | 34 include/asm-xtensa/mman.h | 1 include/asm-xtensa/termios.h | 19 include/crypto/algapi.h | 24 include/linux/Kbuild | 5 include/linux/acpi.h | 339 - include/linux/acpi_pmtmr.h | 38 include/linux/agp_backend.h | 5 include/linux/apm-emulation.h | 62 include/linux/ata.h | 15 include/linux/atalk.h | 2 include/linux/atmarp.h | 2 include/linux/binfmts.h | 1 include/linux/blkdev.h | 1 include/linux/buffer_head.h | 12 include/linux/byteorder/Kbuild | 2 include/linux/byteorder/pdp_endian.h | 88 include/linux/byteorder/swabb.h | 13 include/linux/cfag12864b.h | 77 include/linux/clockchips.h | 142 include/linux/clocksource.h | 39 include/linux/coda_linux.h | 6 include/linux/compiler-gcc.h | 7 include/linux/console.h | 4 include/linux/console_struct.h | 3 include/linux/cpu.h | 12 include/linux/cpufreq.h | 10 include/linux/cpuset.h | 2 include/linux/crypto.h | 148 include/linux/device.h | 50 include/linux/dma-mapping.h | 29 include/linux/dmapool.h | 7 include/linux/dn.h | 2 include/linux/efs_fs.h | 2 include/linux/eisa.h | 10 include/linux/ext3_fs.h | 10 include/linux/ext4_fs.h | 10 include/linux/fb.h | 38 include/linux/fs.h | 22 include/linux/genhd.h | 10 include/linux/gfp.h | 4 include/linux/gigaset_dev.h | 2 include/linux/hardirq.h | 9 include/linux/hid-debug.h | 749 -- include/linux/hid.h | 18 include/linux/hrtimer.h | 260 + include/linux/i2c-id.h | 7 include/linux/i2c.h | 7 include/linux/ide.h | 31 include/linux/if_packet.h | 10 include/linux/init.h | 7 include/linux/init_task.h | 2 include/linux/interrupt.h | 12 include/linux/io.h | 15 include/linux/ioport.h | 20 include/linux/irq.h | 56 include/linux/jiffies.h | 222 - include/linux/kernel.h | 13 include/linux/kfifo.h | 6 include/linux/kobject.h | 4 include/linux/ks0108.h | 46 include/linux/ktime.h | 9 include/linux/kvm.h | 5 include/linux/libata.h | 132 include/linux/list.h | 67 include/linux/lockdep.h | 3 include/linux/log2.h | 11 include/linux/magic.h | 1 include/linux/mc146818rtc.h | 10 include/linux/minix_fs.h | 25 include/linux/mm.h | 18 include/linux/mm_inline.h | 13 include/linux/mmc/card.h | 3 include/linux/mmc/host.h | 10 include/linux/mmc/mmc.h | 1 include/linux/mmc/protocol.h | 13 include/linux/mmzone.h | 42 include/linux/module.h | 3 include/linux/mount.h | 10 include/linux/msdos_fs.h | 6 include/linux/msi.h | 5 include/linux/ncp_fs.h | 4 include/linux/net.h | 2 include/linux/netdevice.h | 7 include/linux/netfilter.h | 4 include/linux/netfilter/Kbuild | 1 include/linux/netfilter/nf_conntrack_sane.h | 21 include/linux/netfilter/nf_conntrack_tcp.h | 4 include/linux/netfilter/xt_TCPMSS.h | 10 include/linux/netfilter_ipv4/ip_conntrack.h | 6 include/linux/netfilter_ipv4/ip_nat.h | 1 include/linux/netfilter_ipv4/ip_tables.h | 22 include/linux/netfilter_ipv4/ipt_TCPMSS.h | 7 include/linux/netfilter_ipv6/ip6_tables.h | 35 include/linux/netfilter_ipv6/ip6t_mh.h | 15 include/linux/netlink.h | 1 include/linux/nfs4.h | 3 include/linux/nfs4_acl.h | 9 include/linux/nfs_fs.h | 31 include/linux/nfs_xdr.h | 5 include/linux/nfsd/const.h | 4 include/linux/nfsd/export.h | 7 include/linux/nfsd/nfsd.h | 12 include/linux/nfsd/nfsfh.h | 99 include/linux/nmi.h | 9 include/linux/pagemap.h | 2 include/linux/pci.h | 41 include/linux/pci_ids.h | 24 include/linux/pfkeyv2.h | 4 include/linux/phonedev.h | 2 include/linux/pid.h | 14 include/linux/pnp.h | 2 include/linux/proc_fs.h | 6 include/linux/qnx4_fs.h | 4 include/linux/quota.h | 1 include/linux/raid/bitmap.h | 1 include/linux/random.h | 2 include/linux/reiserfs_fs.h | 8 include/linux/reiserfs_xattr.h | 24 include/linux/relay.h | 9 include/linux/rio.h | 1 include/linux/sched.h | 45 include/linux/security.h | 4 include/linux/serial_core.h | 2 include/linux/serial_ip3106.h | 81 include/linux/serial_pnx8xxx.h | 81 include/linux/serio.h | 5 include/linux/slab_def.h | 30 include/linux/socket.h | 6 include/linux/spi/ads7846.h | 12 include/linux/spi/eeprom.h | 22 include/linux/spi/spi.h | 37 include/linux/spi/spi_bitbang.h | 2 include/linux/spinlock.h | 33 include/linux/stat.h | 2 include/linux/sunrpc/clnt.h | 2 include/linux/sunrpc/debug.h | 1 include/linux/sunrpc/sched.h | 2 include/linux/sunrpc/svc.h | 45 include/linux/sunrpc/svcsock.h | 14 include/linux/svga.h | 124 include/linux/swap.h | 6 include/linux/sysctl.h | 30 include/linux/sysdev.h | 12 include/linux/sysfs.h | 24 include/linux/tc.h | 141 include/linux/tcp.h | 2 include/linux/tick.h | 109 include/linux/tifm.h | 35 include/linux/time.h | 7 include/linux/timer.h | 66 include/linux/timex.h | 11 include/linux/toshiba.h | 2 include/linux/tty.h | 30 include/linux/ufs_fs.h | 48 include/linux/ufs_fs_i.h | 3 include/linux/ufs_fs_sb.h | 1 include/linux/usb.h | 39 include/linux/usb/Kbuild | 5 include/linux/usb/ch9.h | 563 ++ include/linux/usb/serial.h | 5 include/linux/usb_ch9.h | 562 -- include/linux/usb_gadgetfs.h | 2 include/linux/video_output.h | 42 include/linux/vmstat.h | 72 include/linux/wanrouter.h | 8 include/linux/xattr.h | 8 include/linux/xfrm.h | 19 include/net/ax25.h | 4 include/net/dn_route.h | 5 include/net/dst.h | 15 include/net/inet_hashtables.h | 10 include/net/ip6_fib.h | 1 include/net/iucv/af_iucv.h | 106 include/net/iucv/iucv.h | 415 + include/net/netfilter/nf_conntrack.h | 8 include/net/netfilter/nf_conntrack_expect.h | 2 include/net/netfilter/nf_conntrack_l3proto.h | 4 include/net/netfilter/nf_conntrack_l4proto.h | 2 include/net/netfilter/nf_nat.h | 1 include/net/netrom.h | 4 include/net/rose.h | 6 include/net/route.h | 12 include/net/tcp.h | 5 include/net/x25.h | 18 include/net/xfrm.h | 55 include/pcmcia/ss.h | 2 include/rdma/ib_user_mad.h | 2 include/rdma/ib_verbs.h | 3 include/scsi/iscsi_proto.h | 46 include/scsi/libsas.h | 22 include/scsi/scsi_transport_sas.h | 3 include/scsi/scsi_transport_spi.h | 1 include/sound/ac97_codec.h | 4 include/sound/ad1848.h | 2 include/sound/ak4114.h | 3 include/sound/ak4117.h | 2 include/sound/ak4xxx-adda.h | 6 include/sound/control.h | 5 include/sound/core.h | 62 include/sound/emu10k1.h | 418 + include/sound/pcm.h | 6 include/sound/pt2258.h | 37 include/sound/sb16_csp.h | 14 include/sound/snd_wavefront.h | 2 include/sound/soc-dapm.h | 286 + include/sound/soc.h | 461 + include/sound/typedefs.h | 173 include/sound/version.h | 4 include/sound/vx_core.h | 2 include/sound/ymfpci.h | 6 include/video/neomagic.h | 3 include/video/s3blit.h | 79 init/Kconfig | 46 init/Makefile | 7 init/calibrate.c | 2 init/initramfs.c | 17 init/main.c | 122 init/noinitramfs.c | 52 init/version.c | 1 ipc/Makefile | 1 ipc/ipc_sysctl.c | 183 + ipc/mqueue.c | 10 ipc/shm.c | 4 ipc/util.c | 83 kernel/Makefile | 1 kernel/auditfilter.c | 2 kernel/capability.c | 8 kernel/compat.c | 66 kernel/cpu.c | 2 kernel/cpuset.c | 4 kernel/exit.c | 67 kernel/fork.c | 6 kernel/futex.c | 2 kernel/hrtimer.c | 830 ++ kernel/irq/Makefile | 2 kernel/irq/chip.c | 51 kernel/irq/devres.c | 88 kernel/irq/manage.c | 81 kernel/irq/proc.c | 25 kernel/itimer.c | 18 kernel/kfifo.c | 10 kernel/kmod.c | 44 kernel/kthread.c | 6 kernel/lockdep.c | 42 kernel/lockdep_proc.c | 44 kernel/module.c | 76 kernel/mutex-debug.c | 1 kernel/panic.c | 6 kernel/params.c | 28 kernel/posix-cpu-timers.c | 15 kernel/posix-timers.c | 18 kernel/power/Kconfig | 26 kernel/power/disk.c | 115 kernel/power/main.c | 38 kernel/power/snapshot.c | 4 kernel/power/swsusp.c | 5 kernel/power/user.c | 155 kernel/printk.c | 18 kernel/profile.c | 1 kernel/relay.c | 192 - kernel/resource.c | 63 kernel/rtmutex.c | 2 kernel/sched.c | 34 kernel/signal.c | 110 kernel/softirq.c | 19 kernel/sys.c | 51 kernel/sysctl.c | 676 -- kernel/time.c | 254 + kernel/time/Kconfig | 25 kernel/time/Makefile | 9 kernel/time/clockevents.c | 345 + kernel/time/clocksource.c | 247 + kernel/time/jiffies.c | 1 kernel/time/ntp.c | 30 kernel/time/tick-broadcast.c | 480 + kernel/time/tick-common.c | 346 + kernel/time/tick-internal.h | 110 kernel/time/tick-oneshot.c | 84 kernel/time/tick-sched.c | 563 ++ kernel/time/timer_list.c | 287 + kernel/time/timer_stats.c | 411 + kernel/timer.c | 374 + kernel/tsacct.c | 2 kernel/utsname_sysctl.c | 146 kernel/workqueue.c | 13 lib/Kconfig | 9 lib/Kconfig.debug | 29 lib/Makefile | 8 lib/bitmap.c | 8 lib/bust_spinlocks.c | 12 lib/cmdline.c | 8 lib/devres.c | 300 + lib/idr.c | 4 lib/iomap.c | 3 lib/kobject.c | 78 lib/sha1.c | 9 lib/sort.c | 2 lib/string.c | 8 lib/swiotlb.c | 298 + lib/textsearch.c | 2 lib/vsprintf.c | 15 mm/Kconfig | 6 mm/filemap.c | 56 mm/highmem.c | 3 mm/hugetlb.c | 2 mm/memory.c | 60 mm/mempolicy.c | 2 mm/mempool.c | 6 mm/mincore.c | 118 mm/mmap.c | 72 mm/page-writeback.c | 17 mm/page_alloc.c | 102 mm/readahead.c | 8 mm/shmem.c | 22 mm/slab.c | 246 - mm/truncate.c | 11 mm/vmalloc.c | 2 mm/vmscan.c | 51 mm/vmstat.c | 70 net/802/fc.c | 25 net/802/fddi.c | 27 net/802/hippi.c | 21 net/802/psnap.c | 2 net/802/tr.c | 138 net/8021q/vlan.c | 52 net/8021q/vlan.h | 12 net/8021q/vlan_dev.c | 42 net/8021q/vlanproc.c | 40 net/Kconfig | 1 net/Makefile | 1 net/appletalk/aarp.c | 16 net/appletalk/atalk_proc.c | 8 net/appletalk/ddp.c | 218 - net/appletalk/dev.c | 8 net/appletalk/sysctl_net_atalk.c | 2 net/atm/addr.c | 1 net/atm/atm_sysfs.c | 14 net/atm/br2684.c | 6 net/atm/clip.c | 2 net/atm/common.c | 37 net/atm/common.h | 2 net/atm/ioctl.c | 2 net/atm/lec.c | 23 net/atm/lec.h | 4 net/atm/mpc.c | 130 net/atm/mpc.h | 44 net/atm/mpoa_caches.c | 4 net/atm/mpoa_caches.h | 98 net/atm/mpoa_proc.c | 90 net/atm/proc.c | 70 net/atm/pvc.c | 4 net/atm/raw.c | 7 net/atm/resources.c | 16 net/atm/signaling.h | 4 net/atm/svc.c | 48 net/ax25/af_ax25.c | 116 net/ax25/ax25_addr.c | 7 net/ax25/ax25_dev.c | 1 net/ax25/ax25_ds_in.c | 1 net/ax25/ax25_ds_subr.c | 1 net/ax25/ax25_iface.c | 1 net/ax25/ax25_in.c | 1 net/ax25/ax25_ip.c | 95 net/ax25/ax25_out.c | 1 net/ax25/ax25_route.c | 10 net/ax25/ax25_std_in.c | 1 net/ax25/ax25_std_subr.c | 1 net/ax25/ax25_std_timer.c | 3 net/ax25/ax25_subr.c | 5 net/ax25/ax25_uid.c | 5 net/ax25/sysctl_net_ax25.c | 2 net/bluetooth/af_bluetooth.c | 16 net/bluetooth/bnep/bnep.h | 18 net/bluetooth/bnep/core.c | 52 net/bluetooth/bnep/netdev.c | 34 net/bluetooth/bnep/sock.c | 27 net/bluetooth/cmtp/capi.c | 14 net/bluetooth/cmtp/cmtp.h | 12 net/bluetooth/cmtp/core.c | 14 net/bluetooth/cmtp/sock.c | 15 net/bluetooth/hci_conn.c | 21 net/bluetooth/hci_core.c | 36 net/bluetooth/hci_event.c | 27 net/bluetooth/hci_sock.c | 29 net/bluetooth/hidp/core.c | 14 net/bluetooth/hidp/hidp.h | 14 net/bluetooth/hidp/sock.c | 17 net/bluetooth/l2cap.c | 26 net/bluetooth/lib.c | 12 net/bluetooth/rfcomm/core.c | 56 net/bluetooth/rfcomm/sock.c | 20 net/bluetooth/rfcomm/tty.c | 46 net/bluetooth/sco.c | 30 net/bridge/br_device.c | 8 net/bridge/br_fdb.c | 34 net/bridge/br_forward.c | 4 net/bridge/br_if.c | 36 net/bridge/br_input.c | 4 net/bridge/br_ioctl.c | 18 net/bridge/br_netfilter.c | 45 net/bridge/br_netlink.c | 14 net/bridge/br_notify.c | 14 net/bridge/br_private.h | 4 net/bridge/br_stp.c | 24 net/bridge/br_stp_bpdu.c | 2 net/bridge/br_stp_if.c | 4 net/bridge/br_stp_timer.c | 20 net/bridge/br_sysfs_br.c | 242 - net/bridge/br_sysfs_if.c | 2 net/bridge/netfilter/ebt_802_3.c | 6 net/bridge/netfilter/ebt_among.c | 6 net/bridge/netfilter/ebt_arpreply.c | 2 net/bridge/netfilter/ebt_ip.c | 9 net/bridge/netfilter/ebt_log.c | 9 net/bridge/netfilter/ebt_mark_m.c | 2 net/bridge/netfilter/ebt_stp.c | 4 net/bridge/netfilter/ebt_ulog.c | 18 net/bridge/netfilter/ebt_vlan.c | 6 net/bridge/netfilter/ebtable_filter.c | 4 net/bridge/netfilter/ebtables.c | 17 net/compat.c | 17 net/core/datagram.c | 2 net/core/dev.c | 119 net/core/dev_mcast.c | 31 net/core/dst.c | 19 net/core/ethtool.c | 10 net/core/fib_rules.c | 14 net/core/filter.c | 9 net/core/gen_estimator.c | 6 net/core/gen_stats.c | 2 net/core/iovec.c | 11 net/core/link_watch.c | 4 net/core/neighbour.c | 90 net/core/net-sysfs.c | 185 - net/core/netpoll.c | 18 net/core/pktgen.c | 68 net/core/rtnetlink.c | 26 net/core/scm.c | 12 net/core/skbuff.c | 17 net/core/sock.c | 150 net/core/stream.c | 4 net/core/user_dma.c | 8 net/core/utils.c | 4 net/core/wireless.c | 22 net/dccp/ccids/ccid2.c | 68 net/dccp/ccids/ccid3.c | 19 net/dccp/ccids/lib/packet_history.h | 4 net/dccp/ccids/lib/tfrc_equation.c | 18 net/dccp/dccp.h | 8 net/dccp/feat.c | 8 net/dccp/feat.h | 2 net/dccp/input.c | 14 net/dccp/ipv4.c | 8 net/dccp/ipv6.c | 4 net/dccp/options.c | 4 net/dccp/output.c | 4 net/dccp/probe.c | 2 net/dccp/proto.c | 6 net/dccp/sysctl.c | 2 net/dccp/timer.c | 2 net/decnet/af_decnet.c | 132 net/decnet/dn_dev.c | 125 net/decnet/dn_fib.c | 132 net/decnet/dn_neigh.c | 26 net/decnet/dn_nsp_in.c | 75 net/decnet/dn_nsp_out.c | 57 net/decnet/dn_route.c | 206 - net/decnet/dn_rules.c | 12 net/decnet/dn_table.c | 251 - net/decnet/netfilter/dn_rtmsg.c | 2 net/decnet/sysctl_net_decnet.c | 86 net/econet/af_econet.c | 65 net/ethernet/eth.c | 9 net/ieee80211/ieee80211_crypt_wep.c | 8 net/ieee80211/ieee80211_rx.c | 6 net/ieee80211/ieee80211_tx.c | 6 net/ieee80211/ieee80211_wx.c | 4 net/ieee80211/softmac/ieee80211softmac_assoc.c | 20 net/ieee80211/softmac/ieee80211softmac_auth.c | 78 net/ieee80211/softmac/ieee80211softmac_event.c | 12 net/ieee80211/softmac/ieee80211softmac_io.c | 64 net/ieee80211/softmac/ieee80211softmac_module.c | 48 net/ieee80211/softmac/ieee80211softmac_priv.h | 12 net/ieee80211/softmac/ieee80211softmac_scan.c | 14 net/ieee80211/softmac/ieee80211softmac_wx.c | 24 net/ipv4/af_inet.c | 74 net/ipv4/ah4.c | 20 net/ipv4/arp.c | 69 net/ipv4/datagram.c | 16 net/ipv4/devinet.c | 70 net/ipv4/esp4.c | 8 net/ipv4/fib_frontend.c | 23 net/ipv4/fib_hash.c | 13 net/ipv4/fib_semantics.c | 28 net/ipv4/fib_trie.c | 105 net/ipv4/icmp.c | 16 net/ipv4/igmp.c | 52 net/ipv4/inet_connection_sock.c | 6 net/ipv4/inet_diag.c | 23 net/ipv4/inet_hashtables.c | 106 net/ipv4/inet_timewait_sock.c | 4 net/ipv4/inetpeer.c | 1 net/ipv4/ip_forward.c | 23 net/ipv4/ip_fragment.c | 18 net/ipv4/ip_gre.c | 20 net/ipv4/ip_input.c | 28 net/ipv4/ip_options.c | 14 net/ipv4/ip_output.c | 43 net/ipv4/ip_sockglue.c | 83 net/ipv4/ipcomp.c | 32 net/ipv4/ipconfig.c | 32 net/ipv4/ipip.c | 24 net/ipv4/ipmr.c | 137 net/ipv4/ipvs/ip_vs_app.c | 2 net/ipv4/ipvs/ip_vs_conn.c | 15 net/ipv4/ipvs/ip_vs_core.c | 20 net/ipv4/ipvs/ip_vs_ctl.c | 6 net/ipv4/ipvs/ip_vs_ftp.c | 2 net/ipv4/ipvs/ip_vs_lblc.c | 14 net/ipv4/ipvs/ip_vs_lblcr.c | 10 net/ipv4/ipvs/ip_vs_rr.c | 2 net/ipv4/ipvs/ip_vs_sched.c | 1 net/ipv4/multipath_drr.c | 7 net/ipv4/multipath_random.c | 5 net/ipv4/multipath_rr.c | 3 net/ipv4/multipath_wrandom.c | 7 net/ipv4/netfilter.c | 6 net/ipv4/netfilter/Kconfig | 34 net/ipv4/netfilter/Makefile | 1 net/ipv4/netfilter/arp_tables.c | 6 net/ipv4/netfilter/arpt_mangle.c | 2 net/ipv4/netfilter/ip_conntrack_amanda.c | 4 net/ipv4/netfilter/ip_conntrack_core.c | 128 net/ipv4/netfilter/ip_conntrack_ftp.c | 12 net/ipv4/netfilter/ip_conntrack_helper_h323.c | 2 net/ipv4/netfilter/ip_conntrack_helper_pptp.c | 6 net/ipv4/netfilter/ip_conntrack_irc.c | 18 net/ipv4/netfilter/ip_conntrack_netbios_ns.c | 2 net/ipv4/netfilter/ip_conntrack_netlink.c | 118 net/ipv4/netfilter/ip_conntrack_proto_generic.c | 1 net/ipv4/netfilter/ip_conntrack_proto_icmp.c | 13 net/ipv4/netfilter/ip_conntrack_proto_sctp.c | 97 net/ipv4/netfilter/ip_conntrack_proto_tcp.c | 315 - net/ipv4/netfilter/ip_conntrack_proto_udp.c | 9 net/ipv4/netfilter/ip_conntrack_sip.c | 10 net/ipv4/netfilter/ip_conntrack_standalone.c | 51 net/ipv4/netfilter/ip_conntrack_tftp.c | 4 net/ipv4/netfilter/ip_nat_core.c | 100 net/ipv4/netfilter/ip_nat_ftp.c | 6 net/ipv4/netfilter/ip_nat_helper.c | 36 net/ipv4/netfilter/ip_nat_helper_pptp.c | 10 net/ipv4/netfilter/ip_nat_irc.c | 4 net/ipv4/netfilter/ip_nat_proto_icmp.c | 2 net/ipv4/netfilter/ip_nat_proto_tcp.c | 5 net/ipv4/netfilter/ip_nat_proto_udp.c | 5 net/ipv4/netfilter/ip_nat_rule.c | 38 net/ipv4/netfilter/ip_nat_sip.c | 14 net/ipv4/netfilter/ip_nat_snmp_basic.c | 362 + net/ipv4/netfilter/ip_nat_standalone.c | 22 net/ipv4/netfilter/ip_queue.c | 152 net/ipv4/netfilter/ip_tables.c | 50 net/ipv4/netfilter/ipt_CLUSTERIP.c | 61 net/ipv4/netfilter/ipt_ECN.c | 23 net/ipv4/netfilter/ipt_LOG.c | 28 net/ipv4/netfilter/ipt_MASQUERADE.c | 13 net/ipv4/netfilter/ipt_NETMAP.c | 12 net/ipv4/netfilter/ipt_REDIRECT.c | 10 net/ipv4/netfilter/ipt_REJECT.c | 64 net/ipv4/netfilter/ipt_SAME.c | 24 net/ipv4/netfilter/ipt_TCPMSS.c | 207 - net/ipv4/netfilter/ipt_TOS.c | 15 net/ipv4/netfilter/ipt_TTL.c | 19 net/ipv4/netfilter/ipt_ULOG.c | 50 net/ipv4/netfilter/ipt_addrtype.c | 11 net/ipv4/netfilter/ipt_ah.c | 14 net/ipv4/netfilter/ipt_ecn.c | 10 net/ipv4/netfilter/ipt_iprange.c | 14 net/ipv4/netfilter/ipt_owner.c | 15 net/ipv4/netfilter/ipt_recent.c | 16 net/ipv4/netfilter/ipt_tos.c | 10 net/ipv4/netfilter/ipt_ttl.c | 15 net/ipv4/netfilter/iptable_filter.c | 4 net/ipv4/netfilter/iptable_mangle.c | 8 net/ipv4/netfilter/iptable_raw.c | 28 net/ipv4/netfilter/nf_conntrack_l3proto_ipv4.c | 24 .../netfilter/nf_conntrack_l3proto_ipv4_compat.c | 14 net/ipv4/netfilter/nf_conntrack_proto_icmp.c | 33 net/ipv4/netfilter/nf_nat_core.c | 93 net/ipv4/netfilter/nf_nat_h323.c | 2 net/ipv4/netfilter/nf_nat_helper.c | 12 net/ipv4/netfilter/nf_nat_pptp.c | 10 net/ipv4/netfilter/nf_nat_proto_icmp.c | 2 net/ipv4/netfilter/nf_nat_proto_tcp.c | 4 net/ipv4/netfilter/nf_nat_proto_udp.c | 4 net/ipv4/netfilter/nf_nat_rule.c | 26 net/ipv4/netfilter/nf_nat_sip.c | 14 net/ipv4/netfilter/nf_nat_snmp_basic.c | 98 net/ipv4/netfilter/nf_nat_standalone.c | 26 net/ipv4/proc.c | 16 net/ipv4/protocol.c | 3 net/ipv4/raw.c | 30 net/ipv4/route.c | 174 net/ipv4/syncookies.c | 58 net/ipv4/sysctl_net_ipv4.c | 20 net/ipv4/tcp.c | 19 net/ipv4/tcp_cong.c | 38 net/ipv4/tcp_cubic.c | 68 net/ipv4/tcp_highspeed.c | 4 net/ipv4/tcp_htcp.c | 67 net/ipv4/tcp_input.c | 221 - net/ipv4/tcp_ipv4.c | 38 net/ipv4/tcp_minisocks.c | 12 net/ipv4/tcp_output.c | 69 net/ipv4/tcp_probe.c | 2 net/ipv4/tcp_timer.c | 12 net/ipv4/tcp_vegas.c | 4 net/ipv4/tcp_westwood.c | 24 net/ipv4/tunnel4.c | 50 net/ipv4/udp.c | 111 net/ipv4/udp_impl.h | 2 net/ipv4/xfrm4_input.c | 10 net/ipv4/xfrm4_mode_tunnel.c | 58 net/ipv4/xfrm4_output.c | 8 net/ipv4/xfrm4_policy.c | 59 net/ipv4/xfrm4_state.c | 1 net/ipv4/xfrm4_tunnel.c | 31 net/ipv6/Kconfig | 1 net/ipv6/addrconf.c | 280 - net/ipv6/af_inet6.c | 41 net/ipv6/ah6.c | 40 net/ipv6/anycast.c | 7 net/ipv6/datagram.c | 55 net/ipv6/esp6.c | 30 net/ipv6/exthdrs.c | 15 net/ipv6/exthdrs_core.c | 16 net/ipv6/icmp.c | 39 net/ipv6/inet6_hashtables.c | 104 net/ipv6/ip6_fib.c | 69 net/ipv6/ip6_flowlabel.c | 6 net/ipv6/ip6_input.c | 19 net/ipv6/ip6_output.c | 24 net/ipv6/ip6_tunnel.c | 93 net/ipv6/ipcomp6.c | 22 net/ipv6/ipv6_sockglue.c | 13 net/ipv6/mcast.c | 42 net/ipv6/mip6.c | 28 net/ipv6/ndisc.c | 138 net/ipv6/netfilter.c | 4 net/ipv6/netfilter/Kconfig | 11 net/ipv6/netfilter/Makefile | 1 net/ipv6/netfilter/ip6_queue.c | 154 net/ipv6/netfilter/ip6_tables.c | 52 net/ipv6/netfilter/ip6t_HL.c | 29 net/ipv6/netfilter/ip6t_LOG.c | 27 net/ipv6/netfilter/ip6t_REJECT.c | 46 net/ipv6/netfilter/ip6t_ah.c | 30 net/ipv6/netfilter/ip6t_eui64.c | 8 net/ipv6/netfilter/ip6t_frag.c | 8 net/ipv6/netfilter/ip6t_hbh.c | 1 net/ipv6/netfilter/ip6t_hl.c | 13 net/ipv6/netfilter/ip6t_ipv6header.c | 10 net/ipv6/netfilter/ip6t_mh.c | 115 net/ipv6/netfilter/ip6t_owner.c | 8 net/ipv6/netfilter/ip6t_rt.c | 8 net/ipv6/netfilter/ip6table_filter.c | 21 net/ipv6/netfilter/ip6table_mangle.c | 31 net/ipv6/netfilter/ip6table_raw.c | 35 net/ipv6/netfilter/nf_conntrack_l3proto_ipv6.c | 8 net/ipv6/netfilter/nf_conntrack_proto_icmpv6.c | 8 net/ipv6/netfilter/nf_conntrack_reasm.c | 50 net/ipv6/proc.c | 27 net/ipv6/protocol.c | 3 net/ipv6/raw.c | 96 net/ipv6/reassembly.c | 32 net/ipv6/route.c | 143 net/ipv6/sit.c | 44 net/ipv6/sysctl_net_ipv6.c | 6 net/ipv6/tcp_ipv6.c | 100 net/ipv6/tunnel6.c | 43 net/ipv6/udp.c | 67 net/ipv6/udp_impl.h | 6 net/ipv6/xfrm6_input.c | 21 net/ipv6/xfrm6_mode_tunnel.c | 42 net/ipv6/xfrm6_output.c | 8 net/ipv6/xfrm6_policy.c | 54 net/ipv6/xfrm6_state.c | 3 net/ipv6/xfrm6_tunnel.c | 41 net/ipx/af_ipx.c | 108 net/ipx/ipx_proc.c | 8 net/ipx/ipx_route.c | 4 net/ipx/sysctl_net_ipx.c | 4 net/irda/af_irda.c | 12 net/irda/discovery.c | 60 net/irda/ircomm/ircomm_core.c | 101 net/irda/ircomm/ircomm_event.c | 73 net/irda/ircomm/ircomm_lmp.c | 111 net/irda/ircomm/ircomm_param.c | 95 net/irda/ircomm/ircomm_ttp.c | 89 net/irda/ircomm/ircomm_tty.c | 288 - net/irda/ircomm/ircomm_tty_attach.c | 237 - net/irda/ircomm/ircomm_tty_ioctl.c | 87 net/irda/irda_device.c | 22 net/irda/iriap.c | 22 net/irda/irias_object.c | 46 net/irda/irlan/irlan_client.c | 150 net/irda/irlan/irlan_client_event.c | 190 - net/irda/irlan/irlan_common.c | 343 + net/irda/irlan/irlan_eth.c | 102 net/irda/irlan/irlan_event.c | 26 net/irda/irlan/irlan_filter.c | 48 net/irda/irlan/irlan_provider.c | 102 net/irda/irlan/irlan_provider_event.c | 68 net/irda/irlap.c | 16 net/irda/irlap_event.c | 6 net/irda/irlap_frame.c | 6 net/irda/irlmp.c | 18 net/irda/irlmp_event.c | 2 net/irda/irlmp_frame.c | 122 net/irda/irmod.c | 42 net/irda/irnet/irnet.h | 4 net/irda/irnet/irnet_irda.c | 38 net/irda/irnet/irnet_irda.h | 2 net/irda/irnet/irnet_ppp.c | 10 net/irda/irproc.c | 40 net/irda/irqueue.c | 106 net/irda/irsysctl.c | 26 net/irda/irttp.c | 42 net/irda/parameters.c | 2 net/irda/qos.c | 150 net/irda/timer.c | 62 net/irda/wrapper.c | 2 net/iucv/Kconfig | 15 net/iucv/Makefile | 6 net/iucv/af_iucv.c | 1077 +++ net/iucv/iucv.c | 1619 +++++ net/key/af_key.c | 589 +- net/lapb/lapb_iface.c | 6 net/lapb/lapb_in.c | 1 net/lapb/lapb_out.c | 5 net/lapb/lapb_subr.c | 17 net/lapb/lapb_timer.c | 2 net/llc/af_llc.c | 18 net/llc/llc_conn.c | 2 net/llc/llc_input.c | 8 net/llc/llc_output.c | 2 net/llc/llc_pdu.c | 2 net/llc/llc_proc.c | 20 net/llc/llc_s_st.c | 2 net/llc/llc_sap.c | 6 net/llc/llc_station.c | 22 net/llc/sysctl_net_llc.c | 10 net/netfilter/Kconfig | 51 net/netfilter/Makefile | 2 net/netfilter/core.c | 45 net/netfilter/nf_conntrack_core.c | 70 net/netfilter/nf_conntrack_expect.c | 4 net/netfilter/nf_conntrack_ftp.c | 14 net/netfilter/nf_conntrack_h323_main.c | 20 net/netfilter/nf_conntrack_irc.c | 2 net/netfilter/nf_conntrack_l3proto_generic.c | 2 net/netfilter/nf_conntrack_netbios_ns.c | 2 net/netfilter/nf_conntrack_netlink.c | 106 net/netfilter/nf_conntrack_pptp.c | 2 net/netfilter/nf_conntrack_proto.c | 73 net/netfilter/nf_conntrack_proto_generic.c | 2 net/netfilter/nf_conntrack_proto_sctp.c | 73 net/netfilter/nf_conntrack_proto_tcp.c | 249 - net/netfilter/nf_conntrack_proto_udp.c | 1 net/netfilter/nf_conntrack_sane.c | 242 + net/netfilter/nf_conntrack_sip.c | 6 net/netfilter/nf_conntrack_standalone.c | 8 net/netfilter/nf_conntrack_tftp.c | 2 net/netfilter/nf_internals.h | 2 net/netfilter/nf_log.c | 63 net/netfilter/nf_queue.c | 24 net/netfilter/nf_sockopt.c | 12 net/netfilter/nf_sysctl.c | 2 net/netfilter/nfnetlink.c | 11 net/netfilter/nfnetlink_log.c | 56 net/netfilter/nfnetlink_queue.c | 86 net/netfilter/x_tables.c | 14 net/netfilter/xt_CLASSIFY.c | 14 net/netfilter/xt_CONNMARK.c | 5 net/netfilter/xt_CONNSECMARK.c | 6 net/netfilter/xt_MARK.c | 12 net/netfilter/xt_NFQUEUE.c | 4 net/netfilter/xt_NOTRACK.c | 4 net/netfilter/xt_SECMARK.c | 6 net/netfilter/xt_TCPMSS.c | 296 + net/netfilter/xt_conntrack.c | 32 net/netfilter/xt_dccp.c | 20 net/netfilter/xt_hashlimit.c | 13 net/netfilter/xt_helper.c | 18 net/netfilter/xt_length.c | 4 net/netfilter/xt_limit.c | 2 net/netfilter/xt_mac.c | 7 net/netfilter/xt_mark.c | 6 net/netfilter/xt_multiport.c | 2 net/netfilter/xt_physdev.c | 2 net/netfilter/xt_policy.c | 24 net/netfilter/xt_quota.c | 4 net/netfilter/xt_realm.c | 2 net/netfilter/xt_sctp.c | 30 net/netfilter/xt_string.c | 8 net/netfilter/xt_tcpmss.c | 4 net/netlabel/netlabel_cipso_v4.c | 8 net/netlink/af_netlink.c | 46 net/netlink/genetlink.c | 2 net/netrom/af_netrom.c | 40 net/netrom/nr_dev.c | 1 net/netrom/nr_in.c | 1 net/netrom/nr_out.c | 1 net/netrom/nr_route.c | 23 net/netrom/nr_subr.c | 3 net/netrom/nr_timer.c | 2 net/netrom/sysctl_net_netrom.c | 28 net/packet/af_packet.c | 160 net/rose/af_rose.c | 14 net/rose/rose_dev.c | 1 net/rose/rose_in.c | 1 net/rose/rose_out.c | 1 net/rose/rose_route.c | 43 net/rose/rose_subr.c | 1 net/rose/sysctl_net_rose.c | 22 net/rxrpc/connection.c | 10 net/rxrpc/internal.h | 2 net/rxrpc/krxiod.c | 2 net/rxrpc/krxsecd.c | 2 net/rxrpc/main.c | 44 net/rxrpc/proc.c | 8 net/rxrpc/sysctl.c | 14 net/rxrpc/transport.c | 7 net/sched/act_api.c | 35 net/sched/act_gact.c | 3 net/sched/act_ipt.c | 7 net/sched/act_mirred.c | 1 net/sched/act_pedit.c | 11 net/sched/act_police.c | 13 net/sched/act_simple.c | 6 net/sched/cls_api.c | 15 net/sched/cls_basic.c | 7 net/sched/cls_fw.c | 5 net/sched/cls_route.c | 1 net/sched/cls_rsvp.c | 1 net/sched/cls_rsvp.h | 8 net/sched/cls_rsvp6.c | 1 net/sched/cls_tcindex.c | 12 net/sched/cls_u32.c | 5 net/sched/em_cmp.c | 2 net/sched/em_meta.c | 12 net/sched/em_nbyte.c | 5 net/sched/em_text.c | 5 net/sched/em_u32.c | 6 net/sched/ematch.c | 13 net/sched/sch_api.c | 21 net/sched/sch_atm.c | 22 net/sched/sch_cbq.c | 33 net/sched/sch_dsmark.c | 16 net/sched/sch_generic.c | 30 net/sched/sch_gred.c | 4 net/sched/sch_hfsc.c | 41 net/sched/sch_htb.c | 29 net/sched/sch_ingress.c | 30 net/sched/sch_netem.c | 26 net/sched/sch_prio.c | 22 net/sched/sch_red.c | 2 net/sched/sch_sfq.c | 8 net/sched/sch_tbf.c | 6 net/sched/sch_teql.c | 9 net/sctp/associola.c | 11 net/sctp/bind_addr.c | 13 net/sctp/crc32c.c | 38 net/sctp/debug.c | 32 net/sctp/endpointola.c | 3 net/sctp/input.c | 16 net/sctp/inqueue.c | 34 net/sctp/ipv6.c | 3 net/sctp/objcnt.c | 34 net/sctp/output.c | 12 net/sctp/outqueue.c | 30 net/sctp/primitive.c | 4 net/sctp/proc.c | 10 net/sctp/protocol.c | 24 net/sctp/sm_make_chunk.c | 91 net/sctp/sm_sideeffect.c | 68 net/sctp/sm_statefuns.c | 110 net/sctp/sm_statetable.c | 2 net/sctp/socket.c | 114 net/sctp/sysctl.c | 2 net/sctp/transport.c | 14 net/sctp/tsnmap.c | 2 net/sctp/ulpevent.c | 22 net/sctp/ulpqueue.c | 60 net/socket.c | 33 net/sunrpc/auth.c | 27 net/sunrpc/auth_gss/auth_gss.c | 72 net/sunrpc/auth_gss/gss_generic_token.c | 10 net/sunrpc/auth_gss/gss_krb5_crypto.c | 10 net/sunrpc/auth_gss/gss_krb5_mech.c | 3 net/sunrpc/auth_gss/gss_krb5_seal.c | 2 net/sunrpc/auth_gss/gss_krb5_seqnum.c | 6 net/sunrpc/auth_gss/gss_krb5_unseal.c | 2 net/sunrpc/auth_gss/gss_krb5_wrap.c | 4 net/sunrpc/auth_gss/gss_mech_switch.c | 10 net/sunrpc/auth_gss/gss_spkm3_mech.c | 9 net/sunrpc/auth_gss/gss_spkm3_seal.c | 14 net/sunrpc/auth_gss/gss_spkm3_token.c | 60 net/sunrpc/auth_gss/gss_spkm3_unseal.c | 11 net/sunrpc/auth_gss/svcauth_gss.c | 17 net/sunrpc/auth_null.c | 1 net/sunrpc/auth_unix.c | 9 net/sunrpc/cache.c | 79 net/sunrpc/clnt.c | 157 net/sunrpc/pmap_clnt.c | 30 net/sunrpc/rpc_pipe.c | 6 net/sunrpc/sched.c | 86 net/sunrpc/stats.c | 9 net/sunrpc/sunrpc_syms.c | 6 net/sunrpc/svc.c | 34 net/sunrpc/svcauth.c | 5 net/sunrpc/svcauth_unix.c | 240 + net/sunrpc/svcsock.c | 407 + net/sunrpc/sysctl.c | 18 net/sunrpc/xdr.c | 6 net/sunrpc/xprt.c | 71 net/sunrpc/xprtsock.c | 117 net/tipc/addr.c | 14 net/tipc/addr.h | 6 net/tipc/bcast.c | 98 net/tipc/bcast.h | 6 net/tipc/bearer.c | 58 net/tipc/bearer.h | 22 net/tipc/cluster.c | 22 net/tipc/cluster.h | 4 net/tipc/config.c | 16 net/tipc/config.h | 8 net/tipc/core.c | 18 net/tipc/core.h | 40 net/tipc/dbg.c | 56 net/tipc/dbg.h | 2 net/tipc/discover.c | 50 net/tipc/discover.h | 2 net/tipc/eth_media.c | 58 net/tipc/handler.c | 6 net/tipc/link.c | 394 + net/tipc/link.h | 32 net/tipc/msg.c | 2 net/tipc/msg.h | 138 net/tipc/name_distr.c | 64 net/tipc/name_distr.h | 2 net/tipc/name_table.c | 106 net/tipc/name_table.h | 10 net/tipc/net.c | 74 net/tipc/net.h | 4 net/tipc/netlink.c | 16 net/tipc/node.c | 220 - net/tipc/node.h | 8 net/tipc/node_subscr.c | 6 net/tipc/node_subscr.h | 2 net/tipc/port.c | 226 - net/tipc/port.h | 28 net/tipc/ref.c | 24 net/tipc/ref.h | 8 net/tipc/socket.c | 426 + net/tipc/subscr.c | 82 net/tipc/subscr.h | 16 net/tipc/user_reg.c | 22 net/tipc/user_reg.h | 2 net/tipc/zone.c | 4 net/tipc/zone.h | 4 net/unix/af_unix.c | 48 net/unix/garbage.c | 15 net/unix/sysctl_net_unix.c | 2 net/wanrouter/af_wanpipe.c | 514 + net/wanrouter/wanmain.c | 35 net/wanrouter/wanproc.c | 10 net/x25/Makefile | 2 net/x25/af_x25.c | 96 net/x25/sysctl_net_x25.c | 20 net/x25/x25_dev.c | 19 net/x25/x25_facilities.c | 10 net/x25/x25_forward.c | 163 net/x25/x25_in.c | 8 net/x25/x25_link.c | 6 net/x25/x25_out.c | 10 net/x25/x25_proc.c | 110 net/x25/x25_route.c | 5 net/x25/x25_timer.c | 6 net/xfrm/Kconfig | 26 net/xfrm/xfrm_algo.c | 111 net/xfrm/xfrm_input.c | 2 net/xfrm/xfrm_policy.c | 278 + net/xfrm/xfrm_state.c | 198 + net/xfrm/xfrm_user.c | 191 + scripts/Kbuild.include | 84 scripts/gen_initramfs_list.sh | 43 scripts/kconfig/qconf.cc | 18 scripts/kernel-doc | 51 scripts/makelst | 34 scripts/mkcompile_h | 2 scripts/mkuboot.sh | 11 scripts/mod/modpost.c | 10 security/inode.c | 4 security/keys/compat.c | 1 security/keys/key.c | 33 security/keys/proc.c | 4 security/keys/user_defined.c | 1 security/security.c | 1 security/selinux/avc.c | 3 security/selinux/hooks.c | 53 security/selinux/selinuxfs.c | 26 security/selinux/ss/avtab.c | 3 security/selinux/ss/sidtab.c | 1 sound/Kconfig | 2 sound/Makefile | 2 sound/ac97_bus.c | 4 sound/aoa/aoa.h | 2 sound/aoa/codecs/snd-aoa-codec-onyx.c | 11 sound/aoa/core/snd-aoa-alsa.c | 5 sound/aoa/core/snd-aoa-alsa.h | 2 sound/aoa/core/snd-aoa-core.c | 4 sound/aoa/fabrics/snd-aoa-fabric-layout.c | 13 sound/aoa/soundbus/i2sbus/i2sbus-core.c | 22 sound/aoa/soundbus/i2sbus/i2sbus-pcm.c | 407 + sound/aoa/soundbus/i2sbus/i2sbus.h | 6 sound/arm/aaci.h | 2 sound/arm/pxa2xx-ac97.c | 6 sound/core/control.c | 44 sound/core/control_compat.c | 5 sound/core/device.c | 24 sound/core/hwdep.c | 21 sound/core/info.c | 2 sound/core/init.c | 26 sound/core/memalloc.c | 10 sound/core/misc.c | 29 sound/core/oss/mixer_oss.c | 2 sound/core/oss/pcm_oss.c | 2 sound/core/pcm.c | 50 sound/core/pcm_lib.c | 5 sound/core/pcm_memory.c | 23 sound/core/pcm_native.c | 2 sound/core/rawmidi.c | 31 sound/core/seq/instr/ainstr_fm.c | 1 sound/core/seq/instr/ainstr_gf1.c | 1 sound/core/seq/instr/ainstr_iw.c | 1 sound/core/seq/instr/ainstr_simple.c | 1 sound/core/seq/oss/seq_oss.c | 2 sound/core/seq/seq_clientmgr.c | 16 sound/core/seq/seq_device.c | 25 sound/core/seq/seq_ports.c | 51 sound/core/seq/seq_virmidi.c | 5 sound/core/sound.c | 17 sound/core/timer.c | 82 sound/drivers/Kconfig | 11 sound/drivers/Makefile | 2 sound/drivers/dummy.c | 13 sound/drivers/mtpav.c | 12 sound/drivers/mts64.c | 6 sound/drivers/portman2x4.c | 876 ++ sound/drivers/serial-u16550.c | 231 - sound/drivers/virmidi.c | 7 sound/drivers/vx/vx_mixer.c | 2 sound/i2c/Makefile | 1 sound/i2c/other/Makefile | 4 sound/i2c/other/ak4114.c | 29 sound/i2c/other/ak4117.c | 2 sound/i2c/other/ak4xxx-adda.c | 110 sound/i2c/other/pt2258.c | 233 + sound/isa/Kconfig | 2 sound/isa/ad1816a/ad1816a_lib.c | 10 sound/isa/ad1848/ad1848.c | 2 sound/isa/ad1848/ad1848_lib.c | 6 sound/isa/cmi8330.c | 4 sound/isa/dt019x.c | 1 sound/isa/es1688/es1688.c | 6 sound/isa/gus/gus_main.c | 6 sound/isa/gus/gusclassic.c | 10 sound/isa/gus/gusextreme.c | 12 sound/isa/gus/gusmax.c | 13 sound/isa/opl3sa2.c | 8 sound/isa/sb/sb16_csp.c | 61 sound/isa/sb/sb8.c | 6 sound/isa/wavefront/wavefront.c | 1 sound/isa/wavefront/wavefront_fx.c | 812 -- sound/isa/wavefront/yss225.c | 2739 ++++++++ sound/oss/Kconfig | 28 sound/oss/ac97_codec.c | 3 sound/oss/ad1889.c | 7 sound/oss/au1550_ac97.c | 4 sound/oss/btaudio.c | 9 sound/oss/cs46xx.c | 9 sound/oss/dmasound/Kconfig | 2 sound/oss/dmasound/dac3550a.c | 3 sound/oss/dmasound/dmasound_core.c | 6 sound/oss/dmasound/tas3001c.c | 3 sound/oss/dmasound/tas3004.c | 3 sound/oss/dmasound/tas_common.c | 3 sound/oss/emu10k1/audio.c | 2 sound/oss/emu10k1/main.c | 11 sound/oss/emu10k1/midi.c | 2 sound/oss/emu10k1/mixer.c | 2 sound/oss/es1371.c | 6 sound/oss/hal2.c | 7 sound/oss/i810_audio.c | 9 sound/oss/kahlua.c | 3 sound/oss/msnd_pinnacle.c | 2 sound/oss/nec_vrc5477.c | 7 sound/oss/opl3.c | 3 sound/oss/os.h | 2 sound/oss/sb_card.c | 6 sound/oss/sh_dac_audio.c | 2 sound/oss/soundcard.c | 7 sound/oss/swarm_cs4297a.c | 16 sound/oss/trident.c | 9 sound/oss/via82cxxx_audio.c | 4 sound/oss/vwsnd.c | 4 sound/oss/waveartist.c | 4 sound/pci/Kconfig | 30 sound/pci/ac97/ac97_codec.c | 65 sound/pci/ac97/ac97_patch.c | 555 +- sound/pci/ac97/ac97_patch.h | 2 sound/pci/ac97/ak4531_codec.c | 6 sound/pci/als300.c | 6 sound/pci/atiixp.c | 31 sound/pci/atiixp_modem.c | 2 sound/pci/ca0106/ca0106_main.c | 21 sound/pci/ca0106/ca0106_mixer.c | 50 sound/pci/cs4281.c | 2 sound/pci/echoaudio/darla20.c | 1 sound/pci/echoaudio/darla24.c | 1 sound/pci/echoaudio/echo3g.c | 1 sound/pci/echoaudio/echo3g_dsp.c | 2 sound/pci/echoaudio/echoaudio.c | 18 sound/pci/echoaudio/gina20.c | 1 sound/pci/echoaudio/gina24.c | 1 sound/pci/echoaudio/indigo.c | 1 sound/pci/echoaudio/indigodj.c | 1 sound/pci/echoaudio/indigoio.c | 1 sound/pci/echoaudio/layla20.c | 1 sound/pci/echoaudio/layla24.c | 1 sound/pci/echoaudio/mia.c | 1 sound/pci/echoaudio/mona.c | 1 sound/pci/emu10k1/emu10k1_main.c | 616 +- sound/pci/emu10k1/emu10k1x.c | 6 sound/pci/emu10k1/emufx.c | 204 - sound/pci/emu10k1/emumixer.c | 745 ++ sound/pci/emu10k1/emupcm.c | 147 sound/pci/emu10k1/emuproc.c | 34 sound/pci/emu10k1/io.c | 104 sound/pci/emu10k1/p16v.c | 14 sound/pci/emu10k1/p17v.h | 47 sound/pci/emu10k1/voice.c | 2 sound/pci/ens1370.c | 154 sound/pci/es1938.c | 2 sound/pci/fm801.c | 2 sound/pci/hda/Makefile | 11 sound/pci/hda/hda_codec.c | 68 sound/pci/hda/hda_intel.c | 33 sound/pci/hda/hda_local.h | 12 sound/pci/hda/hda_patch.h | 6 sound/pci/hda/patch_analog.c | 165 sound/pci/hda/patch_cmedia.c | 24 sound/pci/hda/patch_conexant.c | 1410 ++++ sound/pci/hda/patch_realtek.c | 2367 ++++++- sound/pci/hda/patch_sigmatel.c | 736 +- sound/pci/hda/patch_via.c | 1396 ++++ sound/pci/ice1712/Makefile | 2 sound/pci/ice1712/amp.c | 4 sound/pci/ice1712/amp.h | 2 sound/pci/ice1712/aureon.c | 186 - sound/pci/ice1712/aureon.h | 6 sound/pci/ice1712/delta.c | 34 sound/pci/ice1712/delta.h | 2 sound/pci/ice1712/ews.c | 24 sound/pci/ice1712/ews.h | 2 sound/pci/ice1712/hoontech.c | 7 sound/pci/ice1712/hoontech.h | 2 sound/pci/ice1712/ice1712.c | 74 sound/pci/ice1712/ice1712.h | 18 sound/pci/ice1712/ice1724.c | 78 sound/pci/ice1712/juli.c | 36 sound/pci/ice1712/juli.h | 2 sound/pci/ice1712/phase.c | 76 sound/pci/ice1712/phase.h | 2 sound/pci/ice1712/pontis.c | 42 sound/pci/ice1712/pontis.h | 2 sound/pci/ice1712/prodigy192.c | 40 sound/pci/ice1712/prodigy192.h | 2 sound/pci/ice1712/revo.c | 372 + sound/pci/ice1712/revo.h | 13 sound/pci/ice1712/vt1720_mobo.c | 59 sound/pci/ice1712/vt1720_mobo.h | 2 sound/pci/ice1712/wtm.c | 542 ++ sound/pci/ice1712/wtm.h | 20 sound/pci/intel8x0.c | 208 - sound/pci/intel8x0m.c | 120 sound/pci/korg1212/korg1212.c | 45 sound/pci/maestro3.c | 373 + sound/pci/mixart/mixart_mixer.c | 4 sound/pci/nm256/nm256.c | 56 sound/pci/pcxhr/pcxhr_mixer.c | 6 sound/pci/rme9652/hdsp.c | 38 sound/pci/rme9652/hdspm.c | 1242 +++- sound/pci/trident/trident_main.c | 4 sound/pci/via82xx.c | 134 sound/pci/via82xx_modem.c | 2 sound/pci/vx222/vx222.c | 4 sound/pci/vx222/vx222_ops.c | 2 sound/pci/ymfpci/ymfpci_image.h | 6 sound/pci/ymfpci/ymfpci_main.c | 171 sound/pcmcia/vx/vxp_mixer.c | 2 sound/pcmcia/vx/vxpocket.c | 2 sound/soc/Kconfig | 32 sound/soc/Makefile | 4 sound/soc/at91/Kconfig | 32 sound/soc/at91/Makefile | 11 sound/soc/at91/at91-i2s.c | 721 ++ sound/soc/at91/at91-i2s.h | 27 sound/soc/at91/at91-pcm.c | 432 + sound/soc/at91/at91-pcm.h | 72 sound/soc/at91/eti_b1_wm8731.c | 375 + sound/soc/codecs/Kconfig | 15 sound/soc/codecs/Makefile | 9 sound/soc/codecs/ac97.c | 156 sound/soc/codecs/ac97.h | 18 sound/soc/codecs/wm8731.c | 758 ++ sound/soc/codecs/wm8731.h | 44 sound/soc/codecs/wm8750.c | 1049 +++ sound/soc/codecs/wm8750.h | 67 sound/soc/codecs/wm9712.c | 771 ++ sound/soc/codecs/wm9712.h | 14 sound/soc/pxa/Kconfig | 60 sound/soc/pxa/Makefile | 20 sound/soc/pxa/corgi.c | 383 + sound/soc/pxa/poodle.c | 352 + sound/soc/pxa/pxa2xx-ac97.c | 431 + sound/soc/pxa/pxa2xx-ac97.h | 22 sound/soc/pxa/pxa2xx-i2s.c | 318 + sound/soc/pxa/pxa2xx-i2s.h | 20 sound/soc/pxa/pxa2xx-pcm.c | 372 + sound/soc/pxa/pxa2xx-pcm.h | 34 sound/soc/pxa/spitz.c | 394 + sound/soc/pxa/tosa.c | 289 + sound/soc/soc-core.c | 1587 +++++ sound/soc/soc-dapm.c | 1323 ++++ sound/sound_core.c | 2 sound/sparc/dbri.c | 2 sound/synth/emux/emux.c | 1 sound/synth/emux/emux_proc.c | 1 sound/usb/usbaudio.c | 199 - sound/usb/usbaudio.h | 1 sound/usb/usbquirks.h | 55 usr/Makefile | 2 usr/gen_init_cpio.c | 122 4874 files changed, 224698 insertions(+), 109716 deletions(-) diff --git a/.mailmap b/.mailmap new file mode 100644 index 0000000..bf62dbe --- /dev/null +++ b/.mailmap @@ -0,0 +1,96 @@ +# +# This list is used by git-shortlog to fix a few botched name translations +# in the git archive, either because the author's full name was messed up +# and/or not always written the same way, making contributions from the +# same person appearing not to be so or badly displayed. +# +# repo-abbrev: /pub/scm/linux/kernel/git/ +# + +Aaron Durbin +Adam Oldham +Adam Radford +Adrian Bunk +Alan Cox +Alan Cox +Aleksey Gorelov +Al Viro +Al Viro +Andreas Herrmann +Andrew Morton +Andrew Vasquez +Andy Adamson +Arnaud Patard +Arnd Bergmann +Axel Dyks +Ben Gardner +Ben M Cahill +Björn Steinbrink +Brian Avery +Brian King +Christoph Hellwig +Corey Minyard +David Brownell +David Woodhouse +Domen Puncer +Douglas Gilbert +Ed L. Cashin +Evgeniy Polyakov +Felipe W Damasio +Felix Kuhling +Felix Moeller +Filipe Lautert +Franck Bui-Huu +Frank Zago +Greg Kroah-Hartman +Greg Kroah-Hartman +Greg Kroah-Hartman +Henk Vergonet +Henrik Kretzschmar +Herbert Xu +Jacob Shin +James Bottomley +James Bottomley +James E Wilson +James Ketrenos +Jean Tourrilhes +Jeff Garzik +Jens Axboe +Jens Osterkamp +John Stultz +Juha Yrjola +Juha Yrjola +Juha Yrjola +Kay Sievers +Kenneth W Chen +Koushik +Leonid I Ananiev +Linas Vepstas +Matthieu CASTET +Michel Dänzer +Mitesh shah +Morten Welinder +Morten Welinder +Morten Welinder +Morten Welinder +Nguyen Anh Quynh +Paolo 'Blaisorblade' Giarrusso +Patrick Mochel +Peter A Jonsson +Praveen BP +Rajesh Shah +Ralf Baechle +Ralf Wildenhues +Rémi Denis-Courmont +Rudolf Marek +Rui Saraiva +Sachin P Sant +Sam Ravnborg +Simon Kelley +Stéphane Witzmann +Stephen Hemminger +Tejun Heo +Thomas Graf +Tony Luck +Tsuneo Yoshioka +Valdis Kletnieks diff --git a/CREDITS b/CREDITS index ae08e4c..a4e5599 100644 --- a/CREDITS +++ b/CREDITS @@ -2571,6 +2571,16 @@ S: Subiaco, 6008 S: Perth, Western Australia S: Australia +N: Miguel Ojeda Sandonis +E: maxextreme@gmail.com +D: Author: Auxiliary LCD Controller driver (ks0108) +D: Author: Auxiliary LCD driver (cfag12864b) +D: Author: Auxiliary LCD framebuffer driver (cfag12864bfb) +D: Maintainer: Auxiliary display drivers tree (drivers/auxdisplay/*) +S: C/ Mieses 20, 9-B +S: Valladolid 47009 +S: Spain + N: Greg Page E: gpage@sovereign.org D: IPX development and support diff --git a/Documentation/ABI/testing/debugfs-pktcdvd b/Documentation/ABI/testing/debugfs-pktcdvd index 03dbd88..bf9c16b 100644 --- a/Documentation/ABI/testing/debugfs-pktcdvd +++ b/Documentation/ABI/testing/debugfs-pktcdvd @@ -1,6 +1,6 @@ What: /debug/pktcdvd/pktcdvd[0-7] Date: Oct. 2006 -KernelVersion: 2.6.19 +KernelVersion: 2.6.20 Contact: Thomas Maier Description: @@ -11,8 +11,7 @@ The pktcdvd module (packet writing drive these files in debugfs: /debug/pktcdvd/pktcdvd[0-7]/ - info (0444) Lots of human readable driver - statistics and infos. Multiple lines! + info (0444) Lots of driver statistics and infos. Example: ------- diff --git a/Documentation/ABI/testing/sysfs-class-pktcdvd b/Documentation/ABI/testing/sysfs-class-pktcdvd index c4c55ed..b1c3f02 100644 --- a/Documentation/ABI/testing/sysfs-class-pktcdvd +++ b/Documentation/ABI/testing/sysfs-class-pktcdvd @@ -1,6 +1,6 @@ What: /sys/class/pktcdvd/ Date: Oct. 2006 -KernelVersion: 2.6.19 +KernelVersion: 2.6.20 Contact: Thomas Maier Description: diff --git a/Documentation/DocBook/gadget.tmpl b/Documentation/DocBook/gadget.tmpl index a344424..e7fc964 100644 --- a/Documentation/DocBook/gadget.tmpl +++ b/Documentation/DocBook/gadget.tmpl @@ -482,13 +482,13 @@ slightly. Gadget drivers rely on common USB structures and constants defined in the -<linux/usb_ch9.h> +<linux/usb/ch9.h> header file, which is standard in Linux 2.6 kernels. These are the same types and constants used by host side drivers (and usbcore). -!Iinclude/linux/usb_ch9.h +!Iinclude/linux/usb/ch9.h Core Objects and Methods diff --git a/Documentation/DocBook/kernel-api.tmpl b/Documentation/DocBook/kernel-api.tmpl index 3fa0c4b..0bb9023 100644 --- a/Documentation/DocBook/kernel-api.tmpl +++ b/Documentation/DocBook/kernel-api.tmpl @@ -316,6 +316,9 @@ X!Earch/i386/kernel/mca.c DMI Interfaces !Edrivers/firmware/dmi_scan.c + EDD Interfaces +!Idrivers/firmware/edd.c + diff --git a/Documentation/DocBook/stylesheet.xsl b/Documentation/DocBook/stylesheet.xsl index 3ccce88..974e17c 100644 --- a/Documentation/DocBook/stylesheet.xsl +++ b/Documentation/DocBook/stylesheet.xsl @@ -4,4 +4,5 @@ ansi 80 +2 diff --git a/Documentation/DocBook/usb.tmpl b/Documentation/DocBook/usb.tmpl index 143e5ff..a2ebd65 100644 --- a/Documentation/DocBook/usb.tmpl +++ b/Documentation/DocBook/usb.tmpl @@ -187,13 +187,13 @@ USB-Standard Types - In <linux/usb_ch9.h> you will find + In <linux/usb/ch9.h> you will find the USB data types defined in chapter 9 of the USB specification. These data types are used throughout USB, and in APIs including this host side API, gadget APIs, and usbfs. -!Iinclude/linux/usb_ch9.h +!Iinclude/linux/usb/ch9.h @@ -574,7 +574,7 @@ #include <linux/usbdevice_fs.h> #include <asm/byteorder.h> The standard USB device model requests, from "Chapter 9" of the USB 2.0 specification, are automatically included from - the <linux/usb_ch9.h> header. + the <linux/usb/ch9.h> header. Unless noted otherwise, the ioctl requests diff --git a/Documentation/HOWTO b/Documentation/HOWTO index 8d51c14..48123db 100644 --- a/Documentation/HOWTO +++ b/Documentation/HOWTO @@ -30,6 +30,7 @@ are not a good substitute for a solid C experience, the following books are good for, if anything, reference: - "The C Programming Language" by Kernighan and Ritchie [Prentice Hall] - "Practical C Programming" by Steve Oualline [O'Reilly] + - "C: A Reference Manual" by Harbison and Steele [Prentice Hall] The kernel is written using GNU C and the GNU toolchain. While it adheres to the ISO C89 standard, it uses a number of extensions that are diff --git a/Documentation/auxdisplay/cfag12864b b/Documentation/auxdisplay/cfag12864b new file mode 100644 index 0000000..3572b98 --- /dev/null +++ b/Documentation/auxdisplay/cfag12864b @@ -0,0 +1,105 @@ + =================================== + cfag12864b LCD Driver Documentation + =================================== + +License: GPLv2 +Author & Maintainer: Miguel Ojeda Sandonis +Date: 2006-10-27 + + + +-------- +0. INDEX +-------- + + 1. DRIVER INFORMATION + 2. DEVICE INFORMATION + 3. WIRING + 4. USERSPACE PROGRAMMING + + +--------------------- +1. DRIVER INFORMATION +--------------------- + +This driver support one cfag12864b display at time. + + +--------------------- +2. DEVICE INFORMATION +--------------------- + +Manufacturer: Crystalfontz +Device Name: Crystalfontz 12864b LCD Series +Device Code: cfag12864b +Webpage: http://www.crystalfontz.com +Device Webpage: http://www.crystalfontz.com/products/12864b/ +Type: LCD (Liquid Crystal Display) +Width: 128 +Height: 64 +Colors: 2 (B/N) +Controller: ks0108 +Controllers: 2 +Pages: 8 each controller +Addresses: 64 each page +Data size: 1 byte each address +Memory size: 2 * 8 * 64 * 1 = 1024 bytes = 1 Kbyte + + +--------- +3. WIRING +--------- + +The cfag12864b LCD Series don't have official wiring. + +The common wiring is done to the parallel port as shown: + +Parallel Port cfag12864b + + Name Pin# Pin# Name + +Strobe ( 1)------------------------------(17) Enable +Data 0 ( 2)------------------------------( 4) Data 0 +Data 1 ( 3)------------------------------( 5) Data 1 +Data 2 ( 4)------------------------------( 6) Data 2 +Data 3 ( 5)------------------------------( 7) Data 3 +Data 4 ( 6)------------------------------( 8) Data 4 +Data 5 ( 7)------------------------------( 9) Data 5 +Data 6 ( 8)------------------------------(10) Data 6 +Data 7 ( 9)------------------------------(11) Data 7 + (10) [+5v]---( 1) Vdd + (11) [GND]---( 2) Ground + (12) [+5v]---(14) Reset + (13) [GND]---(15) Read / Write + Line (14)------------------------------(13) Controller Select 1 + (15) + Init (16)------------------------------(12) Controller Select 2 +Select (17)------------------------------(16) Data / Instruction +Ground (18)---[GND] [+5v]---(19) LED + +Ground (19)---[GND] +Ground (20)---[GND] E A Values: +Ground (21)---[GND] [GND]---[P1]---(18) Vee · R = Resistor = 22 ohm +Ground (22)---[GND] | · P1 = Preset = 10 Kohm +Ground (23)---[GND] ---- S ------( 3) V0 · P2 = Preset = 1 Kohm +Ground (24)---[GND] | | +Ground (25)---[GND] [GND]---[P2]---[R]---(20) LED - + + +------------------------ +4. USERSPACE PROGRAMMING +------------------------ + +The cfag12864bfb describes a framebuffer device (/dev/fbX). + +It has a size of 1024 bytes = 1 Kbyte. +Each bit represents one pixel. If the bit is high, the pixel will +turn on. If the pixel is low, the pixel will turn off. + +You can use the framebuffer as a file: fopen, fwrite, fclose... +Although the LCD won't get updated until the next refresh time arrives. + +Also, you can mmap the framebuffer: open & mmap, munmap & close... +which is the best option for most uses. + +Check Documentation/auxdisplay/cfag12864b-example.c +for a real working userspace complete program with usage examples. diff --git a/Documentation/auxdisplay/cfag12864b-example.c b/Documentation/auxdisplay/cfag12864b-example.c new file mode 100644 index 0000000..7bfac35 --- /dev/null +++ b/Documentation/auxdisplay/cfag12864b-example.c @@ -0,0 +1,282 @@ +/* + * Filename: cfag12864b-example.c + * Version: 0.1.0 + * Description: cfag12864b LCD userspace example program + * License: GPLv2 + * + * Author: Copyright (C) Miguel Ojeda Sandonis + * Date: 2006-10-31 + * + * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +/* + * ------------------------ + * start of cfag12864b code + * ------------------------ + */ + +#include +#include +#include +#include +#include +#include + +#define CFAG12864B_WIDTH (128) +#define CFAG12864B_HEIGHT (64) +#define CFAG12864B_SIZE (128 * 64 / 8) +#define CFAG12864B_BPB (8) +#define CFAG12864B_ADDRESS(x, y) ((y) * CFAG12864B_WIDTH / \ + CFAG12864B_BPB + (x) / CFAG12864B_BPB) +#define CFAG12864B_BIT(n) (((unsigned char) 1) << (n)) + +#undef CFAG12864B_DOCHECK +#ifdef CFAG12864B_DOCHECK + #define CFAG12864B_CHECK(x, y) ((x) < CFAG12864B_WIDTH && \ + (y) < CFAG12864B_HEIGHT) +#else + #define CFAG12864B_CHECK(x, y) (1) +#endif + +int cfag12864b_fd; +unsigned char * cfag12864b_mem; +unsigned char cfag12864b_buffer[CFAG12864B_SIZE]; + +/* + * init a cfag12864b framebuffer device + * + * No error: return = 0 + * Unable to open: return = -1 + * Unable to mmap: return = -2 + */ +int cfag12864b_init(char *path) +{ + cfag12864b_fd = open(path, O_RDWR); + if (cfag12864b_fd == -1) + return -1; + + cfag12864b_mem = mmap(0, CFAG12864B_SIZE, PROT_READ | PROT_WRITE, + MAP_SHARED, cfag12864b_fd, 0); + if (cfag12864b_mem == MAP_FAILED) { + close(cfag12864b_fd); + return -2; + } + + return 0; +} + +/* + * exit a cfag12864b framebuffer device + */ +void cfag12864b_exit(void) +{ + munmap(cfag12864b_mem, CFAG12864B_SIZE); + close(cfag12864b_fd); +} + +/* + * set (x, y) pixel + */ +void cfag12864b_set(unsigned char x, unsigned char y) +{ + if (CFAG12864B_CHECK(x, y)) + cfag12864b_buffer[CFAG12864B_ADDRESS(x, y)] |= + CFAG12864B_BIT(x % CFAG12864B_BPB); +} + +/* + * unset (x, y) pixel + */ +void cfag12864b_unset(unsigned char x, unsigned char y) +{ + if (CFAG12864B_CHECK(x, y)) + cfag12864b_buffer[CFAG12864B_ADDRESS(x, y)] &= + ~CFAG12864B_BIT(x % CFAG12864B_BPB); +} + +/* + * is set (x, y) pixel? + * + * Pixel off: return = 0 + * Pixel on: return = 1 + */ +unsigned char cfag12864b_isset(unsigned char x, unsigned char y) +{ + if (CFAG12864B_CHECK(x, y)) + if (cfag12864b_buffer[CFAG12864B_ADDRESS(x, y)] & + CFAG12864B_BIT(x % CFAG12864B_BPB)) + return 1; + + return 0; +} + +/* + * not (x, y) pixel + */ +void cfag12864b_not(unsigned char x, unsigned char y) +{ + if (cfag12864b_isset(x, y)) + cfag12864b_unset(x, y); + else + cfag12864b_set(x, y); +} + +/* + * fill (set all pixels) + */ +void cfag12864b_fill(void) +{ + unsigned short i; + + for (i = 0; i < CFAG12864B_SIZE; i++) + cfag12864b_buffer[i] = 0xFF; +} + +/* + * clear (unset all pixels) + */ +void cfag12864b_clear(void) +{ + unsigned short i; + + for (i = 0; i < CFAG12864B_SIZE; i++) + cfag12864b_buffer[i] = 0; +} + +/* + * format a [128*64] matrix + * + * Pixel off: src[i] = 0 + * Pixel on: src[i] > 0 + */ +void cfag12864b_format(unsigned char * matrix) +{ + unsigned char i, j, n; + + for (i = 0; i < CFAG12864B_HEIGHT; i++) + for (j = 0; j < CFAG12864B_WIDTH / CFAG12864B_BPB; j++) { + cfag12864b_buffer[i * CFAG12864B_WIDTH / CFAG12864B_BPB + + j] = 0; + for (n = 0; n < CFAG12864B_BPB; n++) + if (matrix[i * CFAG12864B_WIDTH + + j * CFAG12864B_BPB + n]) + cfag12864b_buffer[i * CFAG12864B_WIDTH / + CFAG12864B_BPB + j] |= + CFAG12864B_BIT(n); + } +} + +/* + * blit buffer to lcd + */ +void cfag12864b_blit(void) +{ + memcpy(cfag12864b_mem, cfag12864b_buffer, CFAG12864B_SIZE); +} + +/* + * ---------------------- + * end of cfag12864b code + * ---------------------- + */ + +#include +#include + +#define EXAMPLES 6 + +void example(unsigned char n) +{ + unsigned short i, j; + unsigned char matrix[CFAG12864B_WIDTH * CFAG12864B_HEIGHT]; + + if (n > EXAMPLES) + return; + + printf("Example %i/%i - ", n, EXAMPLES); + + switch (n) { + case 1: + printf("Draw points setting bits"); + cfag12864b_clear(); + for (i = 0; i < CFAG12864B_WIDTH; i += 2) + for (j = 0; j < CFAG12864B_HEIGHT; j += 2) + cfag12864b_set(i, j); + break; + + case 2: + printf("Clear the LCD"); + cfag12864b_clear(); + break; + + case 3: + printf("Draw rows formatting a [128*64] matrix"); + memset(matrix, 0, CFAG12864B_WIDTH * CFAG12864B_HEIGHT); + for (i = 0; i < CFAG12864B_WIDTH; i++) + for (j = 0; j < CFAG12864B_HEIGHT; j += 2) + matrix[j * CFAG12864B_WIDTH + i] = 1; + cfag12864b_format(matrix); + break; + + case 4: + printf("Fill the lcd"); + cfag12864b_fill(); + break; + + case 5: + printf("Draw columns unsetting bits"); + for (i = 0; i < CFAG12864B_WIDTH; i += 2) + for (j = 0; j < CFAG12864B_HEIGHT; j++) + cfag12864b_unset(i, j); + break; + + case 6: + printf("Do negative not-ing all bits"); + for (i = 0; i < CFAG12864B_WIDTH; i++) + for (j = 0; j < CFAG12864B_HEIGHT; j ++) + cfag12864b_not(i, j); + break; + } + + puts(" - [Press Enter]"); +} + +int main(int argc, char *argv[]) +{ + unsigned char n; + + if (argc != 2) { + printf( + "Sintax: %s fbdev\n" + "Usually: /dev/fb0, /dev/fb1...\n", argv[0]); + return -1; + } + + if (cfag12864b_init(argv[1])) { + printf("Can't init %s fbdev\n", argv[1]); + return -2; + } + + for (n = 1; n <= EXAMPLES; n++) { + example(n); + cfag12864b_blit(); + while (getchar() != '\n'); + } + + cfag12864b_exit(); + + return 0; +} diff --git a/Documentation/auxdisplay/ks0108 b/Documentation/auxdisplay/ks0108 new file mode 100644 index 0000000..92b03b6 --- /dev/null +++ b/Documentation/auxdisplay/ks0108 @@ -0,0 +1,55 @@ + ========================================== + ks0108 LCD Controller Driver Documentation + ========================================== + +License: GPLv2 +Author & Maintainer: Miguel Ojeda Sandonis +Date: 2006-10-27 + + + +-------- +0. INDEX +-------- + + 1. DRIVER INFORMATION + 2. DEVICE INFORMATION + 3. WIRING + + +--------------------- +1. DRIVER INFORMATION +--------------------- + +This driver support the ks0108 LCD controller. + + +--------------------- +2. DEVICE INFORMATION +--------------------- + +Manufacturer: Samsung +Device Name: KS0108 LCD Controller +Device Code: ks0108 +Webpage: - +Device Webpage: - +Type: LCD Controller (Liquid Crystal Display Controller) +Width: 64 +Height: 64 +Colors: 2 (B/N) +Pages: 8 +Addresses: 64 each page +Data size: 1 byte each address +Memory size: 8 * 64 * 1 = 512 bytes + + +--------- +3. WIRING +--------- + +The driver supports data parallel port wiring. + +If you aren't building LCD related hardware, you should check +your LCD specific wiring information in the same folder. + +For example, check Documentation/auxdisplay/cfag12864b. diff --git a/Documentation/cdrom/packet-writing.txt b/Documentation/cdrom/packet-writing.txt index 7715d22..cf1f812 100644 --- a/Documentation/cdrom/packet-writing.txt +++ b/Documentation/cdrom/packet-writing.txt @@ -93,7 +93,7 @@ Notes Using the pktcdvd sysfs interface --------------------------------- -Since Linux 2.6.19, the pktcdvd module has a sysfs interface +Since Linux 2.6.20, the pktcdvd module has a sysfs interface and can be controlled by it. For example the "pktcdvd" tool uses this interface. (see http://people.freenet.de/BalaGi#pktcdvd ) diff --git a/Documentation/crypto/api-intro.txt b/Documentation/crypto/api-intro.txt index 5a03a28..e41a79a 100644 --- a/Documentation/crypto/api-intro.txt +++ b/Documentation/crypto/api-intro.txt @@ -193,6 +193,7 @@ Original developers of the crypto algori Kartikey Mahendra Bhatt (CAST6) Jon Oberheide (ARC4) Jouni Malinen (Michael MIC) + NTT(Nippon Telegraph and Telephone Corporation) (Camellia) SHA1 algorithm contributors: Jean-Francois Dive @@ -246,6 +247,9 @@ Tiger algorithm contributors: VIA PadLock contributors: Michal Ludvig +Camellia algorithm contributors: + NTT(Nippon Telegraph and Telephone Corporation) (Camellia) + Generic scatterwalk code by Adam J. Richter Please send any credits updates or corrections to: diff --git a/Documentation/driver-model/devres.txt b/Documentation/driver-model/devres.txt new file mode 100644 index 0000000..5163b85 --- /dev/null +++ b/Documentation/driver-model/devres.txt @@ -0,0 +1,268 @@ +Devres - Managed Device Resource +================================ + +Tejun Heo + +First draft 10 January 2007 + + +1. Intro : Huh? Devres? +2. Devres : Devres in a nutshell +3. Devres Group : Group devres'es and release them together +4. Details : Life time rules, calling context, ... +5. Overhead : How much do we have to pay for this? +6. List of managed interfaces : Currently implemented managed interfaces + + + 1. Intro + -------- + +devres came up while trying to convert libata to use iomap. Each +iomapped address should be kept and unmapped on driver detach. For +example, a plain SFF ATA controller (that is, good old PCI IDE) in +native mode makes use of 5 PCI BARs and all of them should be +maintained. + +As with many other device drivers, libata low level drivers have +sufficient bugs in ->remove and ->probe failure path. Well, yes, +that's probably because libata low level driver developers are lazy +bunch, but aren't all low level driver developers? After spending a +day fiddling with braindamaged hardware with no document or +braindamaged document, if it's finally working, well, it's working. + +For one reason or another, low level drivers don't receive as much +attention or testing as core code, and bugs on driver detach or +initilaization failure doesn't happen often enough to be noticeable. +Init failure path is worse because it's much less travelled while +needs to handle multiple entry points. + +So, many low level drivers end up leaking resources on driver detach +and having half broken failure path implementation in ->probe() which +would leak resources or even cause oops when failure occurs. iomap +adds more to this mix. So do msi and msix. + + + 2. Devres + --------- + +devres is basically linked list of arbitrarily sized memory areas +associated with a struct device. Each devres entry is associated with +a release function. A devres can be released in several ways. No +matter what, all devres entries are released on driver detach. On +release, the associated release function is invoked and then the +devres entry is freed. + +Managed interface is created for resources commonly used by device +drivers using devres. For example, coherent DMA memory is acquired +using dma_alloc_coherent(). The managed version is called +dmam_alloc_coherent(). It is identical to dma_alloc_coherent() except +for the DMA memory allocated using it is managed and will be +automatically released on driver detach. Implementation looks like +the following. + + struct dma_devres { + size_t size; + void *vaddr; + dma_addr_t dma_handle; + }; + + static void dmam_coherent_release(struct device *dev, void *res) + { + struct dma_devres *this = res; + + dma_free_coherent(dev, this->size, this->vaddr, this->dma_handle); + } + + dmam_alloc_coherent(dev, size, dma_handle, gfp) + { + struct dma_devres *dr; + void *vaddr; + + dr = devres_alloc(dmam_coherent_release, sizeof(*dr), gfp); + ... + + /* alloc DMA memory as usual */ + vaddr = dma_alloc_coherent(...); + ... + + /* record size, vaddr, dma_handle in dr */ + dr->vaddr = vaddr; + ... + + devres_add(dev, dr); + + return vaddr; + } + +If a driver uses dmam_alloc_coherent(), the area is guaranteed to be +freed whether initialization fails half-way or the device gets +detached. If most resources are acquired using managed interface, a +driver can have much simpler init and exit code. Init path basically +looks like the following. + + my_init_one() + { + struct mydev *d; + + d = devm_kzalloc(dev, sizeof(*d), GFP_KERNEL); + if (!d) + return -ENOMEM; + + d->ring = dmam_alloc_coherent(...); + if (!d->ring) + return -ENOMEM; + + if (check something) + return -EINVAL; + ... + + return register_to_upper_layer(d); + } + +And exit path, + + my_remove_one() + { + unregister_from_upper_layer(d); + shutdown_my_hardware(); + } + +As shown above, low level drivers can be simplified a lot by using +devres. Complexity is shifted from less maintained low level drivers +to better maintained higher layer. Also, as init failure path is +shared with exit path, both can get more testing. + + + 3. Devres group + --------------- + +Devres entries can be grouped using devres group. When a group is +released, all contained normal devres entries and properly nested +groups are released. One usage is to rollback series of acquired +resources on failure. For example, + + if (!devres_open_group(dev, NULL, GFP_KERNEL)) + return -ENOMEM; + + acquire A; + if (failed) + goto err; + + acquire B; + if (failed) + goto err; + ... + + devres_remove_group(dev, NULL); + return 0; + + err: + devres_release_group(dev, NULL); + return err_code; + +As resource acquision failure usually means probe failure, constructs +like above are usually useful in midlayer driver (e.g. libata core +layer) where interface function shouldn't have side effect on failure. +For LLDs, just returning error code suffices in most cases. + +Each group is identified by void *id. It can either be explicitly +specified by @id argument to devres_open_group() or automatically +created by passing NULL as @id as in the above example. In both +cases, devres_open_group() returns the group's id. The returned id +can be passed to other devres functions to select the target group. +If NULL is given to those functions, the latest open group is +selected. + +For example, you can do something like the following. + + int my_midlayer_create_something() + { + if (!devres_open_group(dev, my_midlayer_create_something, GFP_KERNEL)) + return -ENOMEM; + + ... + + devres_close_group(dev, my_midlayer_something); + return 0; + } + + void my_midlayer_destroy_something() + { + devres_release_group(dev, my_midlayer_create_soemthing); + } + + + 4. Details + ---------- + +Lifetime of a devres entry begins on devres allocation and finishes +when it is released or destroyed (removed and freed) - no reference +counting. + +devres core guarantees atomicity to all basic devres operations and +has support for single-instance devres types (atomic +lookup-and-add-if-not-found). Other than that, synchronizing +concurrent accesses to allocated devres data is caller's +responsibility. This is usually non-issue because bus ops and +resource allocations already do the job. + +For an example of single-instance devres type, read pcim_iomap_table() +in lib/iomap.c. + +All devres interface functions can be called without context if the +right gfp mask is given. + + + 5. Overhead + ----------- + +Each devres bookkeeping info is allocated together with requested data +area. With debug option turned off, bookkeeping info occupies 16 +bytes on 32bit machines and 24 bytes on 64bit (three pointers rounded +up to ull alignment). If singly linked list is used, it can be +reduced to two pointers (8 bytes on 32bit, 16 bytes on 64bit). + +Each devres group occupies 8 pointers. It can be reduced to 6 if +singly linked list is used. + +Memory space overhead on ahci controller with two ports is between 300 +and 400 bytes on 32bit machine after naive conversion (we can +certainly invest a bit more effort into libata core layer). + + + 6. List of managed interfaces + ----------------------------- + +IO region + devm_request_region() + devm_request_mem_region() + devm_release_region() + devm_release_mem_region() + +IRQ + devm_request_irq() + devm_free_irq() + +DMA + dmam_alloc_coherent() + dmam_free_coherent() + dmam_alloc_noncoherent() + dmam_free_noncoherent() + dmam_declare_coherent_memory() + dmam_pool_create() + dmam_pool_destroy() + +PCI + pcim_enable_device() : after success, all PCI ops become managed + pcim_pin_device() : keep PCI device enabled after release + +IOMAP + devm_ioport_map() + devm_ioport_unmap() + devm_ioremap() + devm_ioremap_nocache() + devm_iounmap() + pcim_iomap() + pcim_iounmap() + pcim_iomap_table() : array of mapped addresses indexed by BAR + pcim_iomap_regions() : do request_region() and iomap() on multiple BARs diff --git a/Documentation/drivers/edac/edac.txt b/Documentation/drivers/edac/edac.txt index 7b3d969..3c5a9e4 100644 --- a/Documentation/drivers/edac/edac.txt +++ b/Documentation/drivers/edac/edac.txt @@ -339,7 +339,21 @@ Device Symlink: 'device' - Symlink to the memory controller device + Symlink to the memory controller device. + +Sdram memory scrubbing rate: + + 'sdram_scrub_rate' + + Read/Write attribute file that controls memory scrubbing. The scrubbing + rate is set by writing a minimum bandwith in bytes/sec to the attribute + file. The rate will be translated to an internal value that gives at + least the specified rate. + + Reading the file will return the actual scrubbing rate employed. + + If configuration fails or memory scrubbing is not implemented, the value + of the attribute file will be -1. diff --git a/Documentation/fb/s3fb.txt b/Documentation/fb/s3fb.txt new file mode 100644 index 0000000..8a04c0d --- /dev/null +++ b/Documentation/fb/s3fb.txt @@ -0,0 +1,78 @@ + + s3fb - fbdev driver for S3 Trio/Virge chips + =========================================== + + +Supported Hardware +================== + + S3 Trio32 + S3 Trio64 (and variants V+, UV+, V2/DX, V2/GX) + S3 Virge (and variants VX, DX, GX and GX2+) + S3 Plato/PX (completely untested) + S3 Aurora64V+ (completely untested) + + - only PCI bus supported + - only BIOS initialized VGA devices supported + - probably not working on big endian + +I tested s3fb on Trio64 (plain, V+ and V2/DX) and Virge (plain, VX, DX), +all on i386. + + +Supported Features +================== + + * 4 bpp pseudocolor modes (with 18bit palette, two variants) + * 8 bpp pseudocolor mode (with 18bit palette) + * 16 bpp truecolor modes (RGB 555 and RGB 565) + * 24 bpp truecolor mode (RGB 888) on (only on Virge VX) + * 32 bpp truecolor mode (RGB 888) on (not on Virge VX) + * text mode (activated by bpp = 0) + * interlaced mode variant (not available in text mode) + * doublescan mode variant (not available in text mode) + * panning in both directions + * suspend/resume support + * DPMS support + +Text mode is supported even in higher resolutions, but there is limitation +to lower pixclocks (maximum between 50-60 MHz, depending on specific hardware). +This limitation is not enforced by driver. Text mode supports 8bit wide fonts +only (hardware limitation) and 16bit tall fonts (driver limitation). + +There are two 4 bpp modes. First mode (selected if nonstd == 0) is mode with +packed pixels, high nibble first. Second mode (selected if nonstd == 1) is mode +with interleaved planes (1 byte interleave), MSB first. Both modes support +8bit wide fonts only (driver limitation). + +Suspend/resume works on systems that initialize video card during resume and +if device is active (for example used by fbcon). + + +Missing Features +================ +(alias TODO list) + + * secondary (not initialized by BIOS) device support + * big endian support + * Zorro bus support + * MMIO support + * 24 bpp mode support on more cards + * support for fontwidths != 8 in 4 bpp modes + * support for fontheight != 16 in text mode + * composite and external sync (is anyone able to test this?) + * hardware cursor + * video overlay support + * vsync synchronization + * feature connector support + * acceleration support (8514-like 2D, Virge 3D, busmaster transfers) + * better values for some magic registers (performance issues) + + +Known bugs +========== + + * cursor disable in text mode doesn't work + +-- +Ondrej Zajicek diff --git a/Documentation/feature-removal-schedule.txt b/Documentation/feature-removal-schedule.txt index 0ba6af0..c585aa8 100644 --- a/Documentation/feature-removal-schedule.txt +++ b/Documentation/feature-removal-schedule.txt @@ -50,22 +50,6 @@ Who: Dan Dennedy , Stef --------------------------- -What: ieee1394 core's unused exports (CONFIG_IEEE1394_EXPORT_FULL_API) -When: January 2007 -Why: There are no projects known to use these exported symbols, except - dfg1394 (uses one symbol whose functionality is core-internal now). -Who: Stefan Richter - ---------------------------- - -What: ieee1394's *_oui sysfs attributes (CONFIG_IEEE1394_OUI_DB) -When: January 2007 -Files: drivers/ieee1394/: oui.db, oui2c.sh -Why: big size, little value -Who: Stefan Richter - ---------------------------- - What: Video4Linux API 1 ioctls and video_decoder.h from Video devices. When: December 2006 Why: V4L1 AP1 was replaced by V4L2 API. during migration from 2.4 to 2.6 @@ -186,18 +170,6 @@ Who: Greg Kroah-Hartman --------------------------- -What: find_trylock_page -When: January 2007 -Why: The interface no longer has any callers left in the kernel. It - is an odd interface (compared with other find_*_page functions), in - that it does not take a refcount to the page, only the page lock. - It should be replaced with find_get_page or find_lock_page if possible. - This feature removal can be reevaluated if users of the interface - cannot cleanly use something else. -Who: Nick Piggin - ---------------------------- - What: Interrupt only SA_* flags When: Januar 2007 Why: The interrupt related SA_* flags are replaced by IRQF_* to move them @@ -243,6 +215,13 @@ Who: Jean Delvare , --------------------------- +What: drivers depending on OBSOLETE_OSS +When: options in 2.6.22, code in 2.6.24 +Why: OSS drivers with ALSA replacements +Who: Adrian Bunk + +--------------------------- + What: IPv4 only connection tracking/NAT/helpers When: 2.6.22 Why: The new layer 3 independant connection tracking replaces the old @@ -274,6 +253,7 @@ Who: Venkatesh Pallipadi --------------------------- +What: ACPI procfs interface +When: July 2007 +Why: After ACPI sysfs conversion, ACPI attributes will be duplicated + in sysfs and the ACPI procfs interface should be removed. +Who: Zhang Rui + +--------------------------- + What: /proc/acpi/button When: August 2007 Why: /proc/acpi/button has been replaced by events to the input layer @@ -325,3 +312,25 @@ Why: Unmaintained for years, superceded Who: Jeff Garzik --------------------------- + +What: sk98lin network driver +When: July 2007 +Why: In kernel tree version of driver is unmaintained. Sk98lin driver + replaced by the skge driver. +Who: Stephen Hemminger + +--------------------------- + +What: Compaq touchscreen device emulation +When: Oct 2007 +Files: drivers/input/tsdev.c +Why: The code says it was obsolete when it was written in 2001. + tslib is a userspace library which does anything tsdev can do and + much more besides in userspace where this code belongs. There is no + longer any need for tsdev and applications should have converted to + use tslib by now. + The name "tsdev" is also extremely confusing and lots of people have + it loaded when they don't need/use it. +Who: Richard Purdie + +--------------------------- diff --git a/Documentation/filesystems/relay.txt b/Documentation/filesystems/relay.txt index d6788da..7fbb6ff 100644 --- a/Documentation/filesystems/relay.txt +++ b/Documentation/filesystems/relay.txt @@ -157,7 +157,7 @@ TBD(curr. line MT:/API/) channel management functions: relay_open(base_filename, parent, subbuf_size, n_subbufs, - callbacks) + callbacks, private_data) relay_close(chan) relay_flush(chan) relay_reset(chan) @@ -251,7 +251,7 @@ static struct rchan_callbacks relay_call And an example relay_open() invocation using them: - chan = relay_open("cpu", NULL, SUBBUF_SIZE, N_SUBBUFS, &relay_callbacks); + chan = relay_open("cpu", NULL, SUBBUF_SIZE, N_SUBBUFS, &relay_callbacks, NULL); If the create_buf_file() callback fails, or isn't defined, channel creation and thus relay_open() will fail. @@ -289,6 +289,11 @@ they use the proper locking for such a b writes in a spinlock, or by copying a write function from relay.h and creating a local version that internally does the proper locking. +The private_data passed into relay_open() allows clients to associate +user-defined data with a channel, and is immediately available +(including in create_buf_file()) via chan->private_data or +buf->chan->private_data. + Channel 'modes' --------------- diff --git a/Documentation/filesystems/ufs.txt b/Documentation/filesystems/ufs.txt index 2b5a56a..7a602ad 100644 --- a/Documentation/filesystems/ufs.txt +++ b/Documentation/filesystems/ufs.txt @@ -21,7 +21,7 @@ ufstype=type_of_ufs supported as read-write ufs2 used in FreeBSD 5.x - supported as read-only + supported as read-write 5xbsd synonym for ufs2 @@ -50,12 +50,11 @@ ufstype=type_of_ufs POSSIBLE PROBLEMS ================= -There is still bug in reallocation of fragment, in file fs/ufs/balloc.c, -line 364. But it seems working on current buffer cache configuration. +See next section, if you have any. BUG REPORTS =========== -Any ufs bug report you can send to daniel.pirkl@email.cz (do not send -partition tables bug reports.) +Any ufs bug report you can send to daniel.pirkl@email.cz or +to dushistov@mail.ru (do not send partition tables bug reports). diff --git a/Documentation/gpio.txt b/Documentation/gpio.txt new file mode 100644 index 0000000..576ce46 --- /dev/null +++ b/Documentation/gpio.txt @@ -0,0 +1,274 @@ +GPIO Interfaces + +This provides an overview of GPIO access conventions on Linux. + + +What is a GPIO? +=============== +A "General Purpose Input/Output" (GPIO) is a flexible software-controlled +digital signal. They are provided from many kinds of chip, and are familiar +to Linux developers working with embedded and custom hardware. Each GPIO +represents a bit connected to a particular pin, or "ball" on Ball Grid Array +(BGA) packages. Board schematics show which external hardware connects to +which GPIOs. Drivers can be written generically, so that board setup code +passes such pin configuration data to drivers. + +System-on-Chip (SOC) processors heavily rely on GPIOs. In some cases, every +non-dedicated pin can be configured as a GPIO; and most chips have at least +several dozen of them. Programmable logic devices (like FPGAs) can easily +provide GPIOs; multifunction chips like power managers, and audio codecs +often have a few such pins to help with pin scarcity on SOCs; and there are +also "GPIO Expander" chips that connect using the I2C or SPI serial busses. +Most PC southbridges have a few dozen GPIO-capable pins (with only the BIOS +firmware knowing how they're used). + +The exact capabilities of GPIOs vary between systems. Common options: + + - Output values are writable (high=1, low=0). Some chips also have + options about how that value is driven, so that for example only one + value might be driven ... supporting "wire-OR" and similar schemes + for the other value. + + - Input values are likewise readable (1, 0). Some chips support readback + of pins configured as "output", which is very useful in such "wire-OR" + cases (to support bidirectional signaling). GPIO controllers may have + input de-glitch logic, sometimes with software controls. + + - Inputs can often be used as IRQ signals, often edge triggered but + sometimes level triggered. Such IRQs may be configurable as system + wakeup events, to wake the system from a low power state. + + - Usually a GPIO will be configurable as either input or output, as needed + by different product boards; single direction ones exist too. + + - Most GPIOs can be accessed while holding spinlocks, but those accessed + through a serial bus normally can't. Some systems support both types. + +On a given board each GPIO is used for one specific purpose like monitoring +MMC/SD card insertion/removal, detecting card writeprotect status, driving +a LED, configuring a transceiver, bitbanging a serial bus, poking a hardware +watchdog, sensing a switch, and so on. + + +GPIO conventions +================ +Note that this is called a "convention" because you don't need to do it this +way, and it's no crime if you don't. There **are** cases where portability +is not the main issue; GPIOs are often used for the kind of board-specific +glue logic that may even change between board revisions, and can't ever be +used on a board that's wired differently. Only least-common-denominator +functionality can be very portable. Other features are platform-specific, +and that can be critical for glue logic. + +Plus, this doesn't define an implementation framework, just an interface. +One platform might implement it as simple inline functions accessing chip +registers; another might implement it by delegating through abstractions +used for several very different kinds of GPIO controller. + +That said, if the convention is supported on their platform, drivers should +use it when possible: + + #include + +If you stick to this convention then it'll be easier for other developers to +see what your code is doing, and help maintain it. + + +Identifying GPIOs +----------------- +GPIOs are identified by unsigned integers in the range 0..MAX_INT. That +reserves "negative" numbers for other purposes like marking signals as +"not available on this board", or indicating faults. Code that doesn't +touch the underlying hardware treats these integers as opaque cookies. + +Platforms define how they use those integers, and usually #define symbols +for the GPIO lines so that board-specific setup code directly corresponds +to the relevant schematics. In contrast, drivers should only use GPIO +numbers passed to them from that setup code, using platform_data to hold +board-specific pin configuration data (along with other board specific +data they need). That avoids portability problems. + +So for example one platform uses numbers 32-159 for GPIOs; while another +uses numbers 0..63 with one set of GPIO controllers, 64-79 with another +type of GPIO controller, and on one particular board 80-95 with an FPGA. +The numbers need not be contiguous; either of those platforms could also +use numbers 2000-2063 to identify GPIOs in a bank of I2C GPIO expanders. + +Whether a platform supports multiple GPIO controllers is currently a +platform-specific implementation issue. + + +Using GPIOs +----------- +One of the first things to do with a GPIO, often in board setup code when +setting up a platform_device using the GPIO, is mark its direction: + + /* set as input or output, returning 0 or negative errno */ + int gpio_direction_input(unsigned gpio); + int gpio_direction_output(unsigned gpio); + +The return value is zero for success, else a negative errno. It should +be checked, since the get/set calls don't have error returns and since +misconfiguration is possible. (These calls could sleep.) + +Setting the direction can fail if the GPIO number is invalid, or when +that particular GPIO can't be used in that mode. It's generally a bad +idea to rely on boot firmware to have set the direction correctly, since +it probably wasn't validated to do more than boot Linux. (Similarly, +that board setup code probably needs to multiplex that pin as a GPIO, +and configure pullups/pulldowns appropriately.) + + +Spinlock-Safe GPIO access +------------------------- +Most GPIO controllers can be accessed with memory read/write instructions. +That doesn't need to sleep, and can safely be done from inside IRQ handlers. + +Use these calls to access such GPIOs: + + /* GPIO INPUT: return zero or nonzero */ + int gpio_get_value(unsigned gpio); + + /* GPIO OUTPUT */ + void gpio_set_value(unsigned gpio, int value); + +The values are boolean, zero for low, nonzero for high. When reading the +value of an output pin, the value returned should be what's seen on the +pin ... that won't always match the specified output value, because of +issues including wire-OR and output latencies. + +The get/set calls have no error returns because "invalid GPIO" should have +been reported earlier in gpio_set_direction(). However, note that not all +platforms can read the value of output pins; those that can't should always +return zero. Also, using these calls for GPIOs that can't safely be accessed +without sleeping (see below) is an error. + +Platform-specific implementations are encouraged to optimize the two +calls to access the GPIO value in cases where the GPIO number (and for +output, value) are constant. It's normal for them to need only a couple +of instructions in such cases (reading or writing a hardware register), +and not to need spinlocks. Such optimized calls can make bitbanging +applications a lot more efficient (in both space and time) than spending +dozens of instructions on subroutine calls. + + +GPIO access that may sleep +-------------------------- +Some GPIO controllers must be accessed using message based busses like I2C +or SPI. Commands to read or write those GPIO values require waiting to +get to the head of a queue to transmit a command and get its response. +This requires sleeping, which can't be done from inside IRQ handlers. + +Platforms that support this type of GPIO distinguish them from other GPIOs +by returning nonzero from this call: + + int gpio_cansleep(unsigned gpio); + +To access such GPIOs, a different set of accessors is defined: + + /* GPIO INPUT: return zero or nonzero, might sleep */ + int gpio_get_value_cansleep(unsigned gpio); + + /* GPIO OUTPUT, might sleep */ + void gpio_set_value_cansleep(unsigned gpio, int value); + +Other than the fact that these calls might sleep, and will not be ignored +for GPIOs that can't be accessed from IRQ handlers, these calls act the +same as the spinlock-safe calls. + + +Claiming and Releasing GPIOs (OPTIONAL) +--------------------------------------- +To help catch system configuration errors, two calls are defined. +However, many platforms don't currently support this mechanism. + + /* request GPIO, returning 0 or negative errno. + * non-null labels may be useful for diagnostics. + */ + int gpio_request(unsigned gpio, const char *label); + + /* release previously-claimed GPIO */ + void gpio_free(unsigned gpio); + +Passing invalid GPIO numbers to gpio_request() will fail, as will requesting +GPIOs that have already been claimed with that call. The return value of +gpio_request() must be checked. (These calls could sleep.) + +These calls serve two basic purposes. One is marking the signals which +are actually in use as GPIOs, for better diagnostics; systems may have +several hundred potential GPIOs, but often only a dozen are used on any +given board. Another is to catch conflicts between drivers, reporting +errors when drivers wrongly think they have exclusive use of that signal. + +These two calls are optional because not not all current Linux platforms +offer such functionality in their GPIO support; a valid implementation +could return success for all gpio_request() calls. Unlike the other calls, +the state they represent doesn't normally match anything from a hardware +register; it's just a software bitmap which clearly is not necessary for +correct operation of hardware or (bug free) drivers. + +Note that requesting a GPIO does NOT cause it to be configured in any +way; it just marks that GPIO as in use. Separate code must handle any +pin setup (e.g. controlling which pin the GPIO uses, pullup/pulldown). + + +GPIOs mapped to IRQs +-------------------- +GPIO numbers are unsigned integers; so are IRQ numbers. These make up +two logically distinct namespaces (GPIO 0 need not use IRQ 0). You can +map between them using calls like: + + /* map GPIO numbers to IRQ numbers */ + int gpio_to_irq(unsigned gpio); + + /* map IRQ numbers to GPIO numbers */ + int irq_to_gpio(unsigned irq); + +Those return either the corresponding number in the other namespace, or +else a negative errno code if the mapping can't be done. (For example, +some GPIOs can't used as IRQs.) It is an unchecked error to use a GPIO +number that hasn't been marked as an input using gpio_set_direction(), or +to use an IRQ number that didn't originally come from gpio_to_irq(). + +These two mapping calls are expected to cost on the order of a single +addition or subtraction. They're not allowed to sleep. + +Non-error values returned from gpio_to_irq() can be passed to request_irq() +or free_irq(). They will often be stored into IRQ resources for platform +devices, by the board-specific initialization code. Note that IRQ trigger +options are part of the IRQ interface, e.g. IRQF_TRIGGER_FALLING, as are +system wakeup capabilities. + +Non-error values returned from irq_to_gpio() would most commonly be used +with gpio_get_value(), for example to initialize or update driver state +when the IRQ is edge-triggered. + + + +What do these conventions omit? +=============================== +One of the biggest things these conventions omit is pin multiplexing, since +this is highly chip-specific and nonportable. One platform might not need +explicit multiplexing; another might have just two options for use of any +given pin; another might have eight options per pin; another might be able +to route a given GPIO to any one of several pins. (Yes, those examples all +come from systems that run Linux today.) + +Related to multiplexing is configuration and enabling of the pullups or +pulldowns integrated on some platforms. Not all platforms support them, +or support them in the same way; and any given board might use external +pullups (or pulldowns) so that the on-chip ones should not be used. + +There are other system-specific mechanisms that are not specified here, +like the aforementioned options for input de-glitching and wire-OR output. +Hardware may support reading or writing GPIOs in gangs, but that's usually +configuration dependent: for GPIOs sharing the same bank. (GPIOs are +commonly grouped in banks of 16 or 32, with a given SOC having several such +banks.) Some systems can trigger IRQs from output GPIOs. Code relying on +such mechanisms will necessarily be nonportable. + +Dynamic definition of GPIOs is not currently supported; for example, as +a side effect of configuring an add-on board with some GPIO expanders. + +These calls are purely for kernel space, but a userspace API could be built +on top of it. diff --git a/Documentation/hrtimer/timer_stats.txt b/Documentation/hrtimer/timer_stats.txt new file mode 100644 index 0000000..27f782e --- /dev/null +++ b/Documentation/hrtimer/timer_stats.txt @@ -0,0 +1,68 @@ +timer_stats - timer usage statistics +------------------------------------ + +timer_stats is a debugging facility to make the timer (ab)usage in a Linux +system visible to kernel and userspace developers. It is not intended for +production usage as it adds significant overhead to the (hr)timer code and the +(hr)timer data structures. + +timer_stats should be used by kernel and userspace developers to verify that +their code does not make unduly use of timers. This helps to avoid unnecessary +wakeups, which should be avoided to optimize power consumption. + +It can be enabled by CONFIG_TIMER_STATS in the "Kernel hacking" configuration +section. + +timer_stats collects information about the timer events which are fired in a +Linux system over a sample period: + +- the pid of the task(process) which initialized the timer +- the name of the process which initialized the timer +- the function where the timer was intialized +- the callback function which is associated to the timer +- the number of events (callbacks) + +timer_stats adds an entry to /proc: /proc/timer_stats + +This entry is used to control the statistics functionality and to read out the +sampled information. + +The timer_stats functionality is inactive on bootup. + +To activate a sample period issue: +# echo 1 >/proc/timer_stats + +To stop a sample period issue: +# echo 0 >/proc/timer_stats + +The statistics can be retrieved by: +# cat /proc/timer_stats + +The readout of /proc/timer_stats automatically disables sampling. The sampled +information is kept until a new sample period is started. This allows multiple +readouts. + +Sample output of /proc/timer_stats: + +Timerstats sample period: 3.888770 s + 12, 0 swapper hrtimer_stop_sched_tick (hrtimer_sched_tick) + 15, 1 swapper hcd_submit_urb (rh_timer_func) + 4, 959 kedac schedule_timeout (process_timeout) + 1, 0 swapper page_writeback_init (wb_timer_fn) + 28, 0 swapper hrtimer_stop_sched_tick (hrtimer_sched_tick) + 22, 2948 IRQ 4 tty_flip_buffer_push (delayed_work_timer_fn) + 3, 3100 bash schedule_timeout (process_timeout) + 1, 1 swapper queue_delayed_work_on (delayed_work_timer_fn) + 1, 1 swapper queue_delayed_work_on (delayed_work_timer_fn) + 1, 1 swapper neigh_table_init_no_netlink (neigh_periodic_timer) + 1, 2292 ip __netdev_watchdog_up (dev_watchdog) + 1, 23 events/1 do_cache_clean (delayed_work_timer_fn) +90 total events, 30.0 events/sec + +The first column is the number of events, the second column the pid, the third +column is the name of the process. The forth column shows the function which +initialized the timer and in parantheses the callback function which was +executed on expiry. + + Thomas, Ingo + diff --git a/Documentation/hrtimers.txt b/Documentation/hrtimers.txt deleted file mode 100644 index ce31f65..0000000 --- a/Documentation/hrtimers.txt +++ /dev/null @@ -1,178 +0,0 @@ - -hrtimers - subsystem for high-resolution kernel timers ----------------------------------------------------- - -This patch introduces a new subsystem for high-resolution kernel timers. - -One might ask the question: we already have a timer subsystem -(kernel/timers.c), why do we need two timer subsystems? After a lot of -back and forth trying to integrate high-resolution and high-precision -features into the existing timer framework, and after testing various -such high-resolution timer implementations in practice, we came to the -conclusion that the timer wheel code is fundamentally not suitable for -such an approach. We initially didn't believe this ('there must be a way -to solve this'), and spent a considerable effort trying to integrate -things into the timer wheel, but we failed. In hindsight, there are -several reasons why such integration is hard/impossible: - -- the forced handling of low-resolution and high-resolution timers in - the same way leads to a lot of compromises, macro magic and #ifdef - mess. The timers.c code is very "tightly coded" around jiffies and - 32-bitness assumptions, and has been honed and micro-optimized for a - relatively narrow use case (jiffies in a relatively narrow HZ range) - for many years - and thus even small extensions to it easily break - the wheel concept, leading to even worse compromises. The timer wheel - code is very good and tight code, there's zero problems with it in its - current usage - but it is simply not suitable to be extended for - high-res timers. - -- the unpredictable [O(N)] overhead of cascading leads to delays which - necessitate a more complex handling of high resolution timers, which - in turn decreases robustness. Such a design still led to rather large - timing inaccuracies. Cascading is a fundamental property of the timer - wheel concept, it cannot be 'designed out' without unevitably - degrading other portions of the timers.c code in an unacceptable way. - -- the implementation of the current posix-timer subsystem on top of - the timer wheel has already introduced a quite complex handling of - the required readjusting of absolute CLOCK_REALTIME timers at - settimeofday or NTP time - further underlying our experience by - example: that the timer wheel data structure is too rigid for high-res - timers. - -- the timer wheel code is most optimal for use cases which can be - identified as "timeouts". Such timeouts are usually set up to cover - error conditions in various I/O paths, such as networking and block - I/O. The vast majority of those timers never expire and are rarely - recascaded because the expected correct event arrives in time so they - can be removed from the timer wheel before any further processing of - them becomes necessary. Thus the users of these timeouts can accept - the granularity and precision tradeoffs of the timer wheel, and - largely expect the timer subsystem to have near-zero overhead. - Accurate timing for them is not a core purpose - in fact most of the - timeout values used are ad-hoc. For them it is at most a necessary - evil to guarantee the processing of actual timeout completions - (because most of the timeouts are deleted before completion), which - should thus be as cheap and unintrusive as possible. - -The primary users of precision timers are user-space applications that -utilize nanosleep, posix-timers and itimer interfaces. Also, in-kernel -users like drivers and subsystems which require precise timed events -(e.g. multimedia) can benefit from the availability of a separate -high-resolution timer subsystem as well. - -While this subsystem does not offer high-resolution clock sources just -yet, the hrtimer subsystem can be easily extended with high-resolution -clock capabilities, and patches for that exist and are maturing quickly. -The increasing demand for realtime and multimedia applications along -with other potential users for precise timers gives another reason to -separate the "timeout" and "precise timer" subsystems. - -Another potential benefit is that such a separation allows even more -special-purpose optimization of the existing timer wheel for the low -resolution and low precision use cases - once the precision-sensitive -APIs are separated from the timer wheel and are migrated over to -hrtimers. E.g. we could decrease the frequency of the timeout subsystem -from 250 Hz to 100 HZ (or even smaller). - -hrtimer subsystem implementation details ----------------------------------------- - -the basic design considerations were: - -- simplicity - -- data structure not bound to jiffies or any other granularity. All the - kernel logic works at 64-bit nanoseconds resolution - no compromises. - -- simplification of existing, timing related kernel code - -another basic requirement was the immediate enqueueing and ordering of -timers at activation time. After looking at several possible solutions -such as radix trees and hashes, we chose the red black tree as the basic -data structure. Rbtrees are available as a library in the kernel and are -used in various performance-critical areas of e.g. memory management and -file systems. The rbtree is solely used for time sorted ordering, while -a separate list is used to give the expiry code fast access to the -queued timers, without having to walk the rbtree. - -(This separate list is also useful for later when we'll introduce -high-resolution clocks, where we need separate pending and expired -queues while keeping the time-order intact.) - -Time-ordered enqueueing is not purely for the purposes of -high-resolution clocks though, it also simplifies the handling of -absolute timers based on a low-resolution CLOCK_REALTIME. The existing -implementation needed to keep an extra list of all armed absolute -CLOCK_REALTIME timers along with complex locking. In case of -settimeofday and NTP, all the timers (!) had to be dequeued, the -time-changing code had to fix them up one by one, and all of them had to -be enqueued again. The time-ordered enqueueing and the storage of the -expiry time in absolute time units removes all this complex and poorly -scaling code from the posix-timer implementation - the clock can simply -be set without having to touch the rbtree. This also makes the handling -of posix-timers simpler in general. - -The locking and per-CPU behavior of hrtimers was mostly taken from the -existing timer wheel code, as it is mature and well suited. Sharing code -was not really a win, due to the different data structures. Also, the -hrtimer functions now have clearer behavior and clearer names - such as -hrtimer_try_to_cancel() and hrtimer_cancel() [which are roughly -equivalent to del_timer() and del_timer_sync()] - so there's no direct -1:1 mapping between them on the algorithmical level, and thus no real -potential for code sharing either. - -Basic data types: every time value, absolute or relative, is in a -special nanosecond-resolution type: ktime_t. The kernel-internal -representation of ktime_t values and operations is implemented via -macros and inline functions, and can be switched between a "hybrid -union" type and a plain "scalar" 64bit nanoseconds representation (at -compile time). The hybrid union type optimizes time conversions on 32bit -CPUs. This build-time-selectable ktime_t storage format was implemented -to avoid the performance impact of 64-bit multiplications and divisions -on 32bit CPUs. Such operations are frequently necessary to convert -between the storage formats provided by kernel and userspace interfaces -and the internal time format. (See include/linux/ktime.h for further -details.) - -hrtimers - rounding of timer values ------------------------------------ - -the hrtimer code will round timer events to lower-resolution clocks -because it has to. Otherwise it will do no artificial rounding at all. - -one question is, what resolution value should be returned to the user by -the clock_getres() interface. This will return whatever real resolution -a given clock has - be it low-res, high-res, or artificially-low-res. - -hrtimers - testing and verification ----------------------------------- - -We used the high-resolution clock subsystem ontop of hrtimers to verify -the hrtimer implementation details in praxis, and we also ran the posix -timer tests in order to ensure specification compliance. We also ran -tests on low-resolution clocks. - -The hrtimer patch converts the following kernel functionality to use -hrtimers: - - - nanosleep - - itimers - - posix-timers - -The conversion of nanosleep and posix-timers enabled the unification of -nanosleep and clock_nanosleep. - -The code was successfully compiled for the following platforms: - - i386, x86_64, ARM, PPC, PPC64, IA64 - -The code was run-tested on the following platforms: - - i386(UP/SMP), x86_64(UP/SMP), ARM, PPC - -hrtimers were also integrated into the -rt tree, along with a -hrtimers-based high-resolution clock implementation, so the hrtimers -code got a healthy amount of testing and use in practice. - - Thomas Gleixner, Ingo Molnar diff --git a/Documentation/hrtimers/highres.txt b/Documentation/hrtimers/highres.txt new file mode 100644 index 0000000..ce0e9a9 --- /dev/null +++ b/Documentation/hrtimers/highres.txt @@ -0,0 +1,249 @@ +High resolution timers and dynamic ticks design notes +----------------------------------------------------- + +Further information can be found in the paper of the OLS 2006 talk "hrtimers +and beyond". The paper is part of the OLS 2006 Proceedings Volume 1, which can +be found on the OLS website: +http://www.linuxsymposium.org/2006/linuxsymposium_procv1.pdf + +The slides to this talk are available from: +http://tglx.de/projects/hrtimers/ols2006-hrtimers.pdf + +The slides contain five figures (pages 2, 15, 18, 20, 22), which illustrate the +changes in the time(r) related Linux subsystems. Figure #1 (p. 2) shows the +design of the Linux time(r) system before hrtimers and other building blocks +got merged into mainline. + +Note: the paper and the slides are talking about "clock event source", while we +switched to the name "clock event devices" in meantime. + +The design contains the following basic building blocks: + +- hrtimer base infrastructure +- timeofday and clock source management +- clock event management +- high resolution timer functionality +- dynamic ticks + + +hrtimer base infrastructure +--------------------------- + +The hrtimer base infrastructure was merged into the 2.6.16 kernel. Details of +the base implementation are covered in Documentation/hrtimers/hrtimer.txt. See +also figure #2 (OLS slides p. 15) + +The main differences to the timer wheel, which holds the armed timer_list type +timers are: + - time ordered enqueueing into a rb-tree + - independent of ticks (the processing is based on nanoseconds) + + +timeofday and clock source management +------------------------------------- + +John Stultz's Generic Time Of Day (GTOD) framework moves a large portion of +code out of the architecture-specific areas into a generic management +framework, as illustrated in figure #3 (OLS slides p. 18). The architecture +specific portion is reduced to the low level hardware details of the clock +sources, which are registered in the framework and selected on a quality based +decision. The low level code provides hardware setup and readout routines and +initializes data structures, which are used by the generic time keeping code to +convert the clock ticks to nanosecond based time values. All other time keeping +related functionality is moved into the generic code. The GTOD base patch got +merged into the 2.6.18 kernel. + +Further information about the Generic Time Of Day framework is available in the +OLS 2005 Proceedings Volume 1: +http://www.linuxsymposium.org/2005/linuxsymposium_procv1.pdf + +The paper "We Are Not Getting Any Younger: A New Approach to Time and +Timers" was written by J. Stultz, D.V. Hart, & N. Aravamudan. + +Figure #3 (OLS slides p.18) illustrates the transformation. + + +clock event management +---------------------- + +While clock sources provide read access to the monotonically increasing time +value, clock event devices are used to schedule the next event +interrupt(s). The next event is currently defined to be periodic, with its +period defined at compile time. The setup and selection of the event device +for various event driven functionalities is hardwired into the architecture +dependent code. This results in duplicated code across all architectures and +makes it extremely difficult to change the configuration of the system to use +event interrupt devices other than those already built into the +architecture. Another implication of the current design is that it is necessary +to touch all the architecture-specific implementations in order to provide new +functionality like high resolution timers or dynamic ticks. + +The clock events subsystem tries to address this problem by providing a generic +solution to manage clock event devices and their usage for the various clock +event driven kernel functionalities. The goal of the clock event subsystem is +to minimize the clock event related architecture dependent code to the pure +hardware related handling and to allow easy addition and utilization of new +clock event devices. It also minimizes the duplicated code across the +architectures as it provides generic functionality down to the interrupt +service handler, which is almost inherently hardware dependent. + +Clock event devices are registered either by the architecture dependent boot +code or at module insertion time. Each clock event device fills a data +structure with clock-specific property parameters and callback functions. The +clock event management decides, by using the specified property parameters, the +set of system functions a clock event device will be used to support. This +includes the distinction of per-CPU and per-system global event devices. + +System-level global event devices are used for the Linux periodic tick. Per-CPU +event devices are used to provide local CPU functionality such as process +accounting, profiling, and high resolution timers. + +The management layer assignes one or more of the folliwing functions to a clock +event device: + - system global periodic tick (jiffies update) + - cpu local update_process_times + - cpu local profiling + - cpu local next event interrupt (non periodic mode) + +The clock event device delegates the selection of those timer interrupt related +functions completely to the management layer. The clock management layer stores +a function pointer in the device description structure, which has to be called +from the hardware level handler. This removes a lot of duplicated code from the +architecture specific timer interrupt handlers and hands the control over the +clock event devices and the assignment of timer interrupt related functionality +to the core code. + +The clock event layer API is rather small. Aside from the clock event device +registration interface it provides functions to schedule the next event +interrupt, clock event device notification service and support for suspend and +resume. + +The framework adds about 700 lines of code which results in a 2KB increase of +the kernel binary size. The conversion of i386 removes about 100 lines of +code. The binary size decrease is in the range of 400 byte. We believe that the +increase of flexibility and the avoidance of duplicated code across +architectures justifies the slight increase of the binary size. + +The conversion of an architecture has no functional impact, but allows to +utilize the high resolution and dynamic tick functionalites without any change +to the clock event device and timer interrupt code. After the conversion the +enabling of high resolution timers and dynamic ticks is simply provided by +adding the kernel/time/Kconfig file to the architecture specific Kconfig and +adding the dynamic tick specific calls to the idle routine (a total of 3 lines +added to the idle function and the Kconfig file) + +Figure #4 (OLS slides p.20) illustrates the transformation. + + +high resolution timer functionality +----------------------------------- + +During system boot it is not possible to use the high resolution timer +functionality, while making it possible would be difficult and would serve no +useful function. The initialization of the clock event device framework, the +clock source framework (GTOD) and hrtimers itself has to be done and +appropriate clock sources and clock event devices have to be registered before +the high resolution functionality can work. Up to the point where hrtimers are +initialized, the system works in the usual low resolution periodic mode. The +clock source and the clock event device layers provide notification functions +which inform hrtimers about availability of new hardware. hrtimers validates +the usability of the registered clock sources and clock event devices before +switching to high resolution mode. This ensures also that a kernel which is +configured for high resolution timers can run on a system which lacks the +necessary hardware support. + +The high resolution timer code does not support SMP machines which have only +global clock event devices. The support of such hardware would involve IPI +calls when an interrupt happens. The overhead would be much larger than the +benefit. This is the reason why we currently disable high resolution and +dynamic ticks on i386 SMP systems which stop the local APIC in C3 power +state. A workaround is available as an idea, but the problem has not been +tackled yet. + +The time ordered insertion of timers provides all the infrastructure to decide +whether the event device has to be reprogrammed when a timer is added. The +decision is made per timer base and synchronized across per-cpu timer bases in +a support function. The design allows the system to utilize separate per-CPU +clock event devices for the per-CPU timer bases, but currently only one +reprogrammable clock event device per-CPU is utilized. + +When the timer interrupt happens, the next event interrupt handler is called +from the clock event distribution code and moves expired timers from the +red-black tree to a separate double linked list and invokes the softirq +handler. An additional mode field in the hrtimer structure allows the system to +execute callback functions directly from the next event interrupt handler. This +is restricted to code which can safely be executed in the hard interrupt +context. This applies, for example, to the common case of a wakeup function as +used by nanosleep. The advantage of executing the handler in the interrupt +context is the avoidance of up to two context switches - from the interrupted +context to the softirq and to the task which is woken up by the expired +timer. + +Once a system has switched to high resolution mode, the periodic tick is +switched off. This disables the per system global periodic clock event device - +e.g. the PIT on i386 SMP systems. + +The periodic tick functionality is provided by an per-cpu hrtimer. The callback +function is executed in the next event interrupt context and updates jiffies +and calls update_process_times and profiling. The implementation of the hrtimer +based periodic tick is designed to be extended with dynamic tick functionality. +This allows to use a single clock event device to schedule high resolution +timer and periodic events (jiffies tick, profiling, process accounting) on UP +systems. This has been proved to work with the PIT on i386 and the Incrementer +on PPC. + +The softirq for running the hrtimer queues and executing the callbacks has been +separated from the tick bound timer softirq to allow accurate delivery of high +resolution timer signals which are used by itimer and POSIX interval +timers. The execution of this softirq can still be delayed by other softirqs, +but the overall latencies have been significantly improved by this separation. + +Figure #5 (OLS slides p.22) illustrates the transformation. + + +dynamic ticks +------------- + +Dynamic ticks are the logical consequence of the hrtimer based periodic tick +replacement (sched_tick). The functionality of the sched_tick hrtimer is +extended by three functions: + +- hrtimer_stop_sched_tick +- hrtimer_restart_sched_tick +- hrtimer_update_jiffies + +hrtimer_stop_sched_tick() is called when a CPU goes into idle state. The code +evaluates the next scheduled timer event (from both hrtimers and the timer +wheel) and in case that the next event is further away than the next tick it +reprograms the sched_tick to this future event, to allow longer idle sleeps +without worthless interruption by the periodic tick. The function is also +called when an interrupt happens during the idle period, which does not cause a +reschedule. The call is necessary as the interrupt handler might have armed a +new timer whose expiry time is before the time which was identified as the +nearest event in the previous call to hrtimer_stop_sched_tick. + +hrtimer_restart_sched_tick() is called when the CPU leaves the idle state before +it calls schedule(). hrtimer_restart_sched_tick() resumes the periodic tick, +which is kept active until the next call to hrtimer_stop_sched_tick(). + +hrtimer_update_jiffies() is called from irq_enter() when an interrupt happens +in the idle period to make sure that jiffies are up to date and the interrupt +handler has not to deal with an eventually stale jiffy value. + +The dynamic tick feature provides statistical values which are exported to +userspace via /proc/stats and can be made available for enhanced power +management control. + +The implementation leaves room for further development like full tickless +systems, where the time slice is controlled by the scheduler, variable +frequency profiling, and a complete removal of jiffies in the future. + + +Aside the current initial submission of i386 support, the patchset has been +extended to x86_64 and ARM already. Initial (work in progress) support is also +available for MIPS and PowerPC. + + Thomas, Ingo + + + diff --git a/Documentation/hrtimers/hrtimers.txt b/Documentation/hrtimers/hrtimers.txt new file mode 100644 index 0000000..ce31f65 --- /dev/null +++ b/Documentation/hrtimers/hrtimers.txt @@ -0,0 +1,178 @@ + +hrtimers - subsystem for high-resolution kernel timers +---------------------------------------------------- + +This patch introduces a new subsystem for high-resolution kernel timers. + +One might ask the question: we already have a timer subsystem +(kernel/timers.c), why do we need two timer subsystems? After a lot of +back and forth trying to integrate high-resolution and high-precision +features into the existing timer framework, and after testing various +such high-resolution timer implementations in practice, we came to the +conclusion that the timer wheel code is fundamentally not suitable for +such an approach. We initially didn't believe this ('there must be a way +to solve this'), and spent a considerable effort trying to integrate +things into the timer wheel, but we failed. In hindsight, there are +several reasons why such integration is hard/impossible: + +- the forced handling of low-resolution and high-resolution timers in + the same way leads to a lot of compromises, macro magic and #ifdef + mess. The timers.c code is very "tightly coded" around jiffies and + 32-bitness assumptions, and has been honed and micro-optimized for a + relatively narrow use case (jiffies in a relatively narrow HZ range) + for many years - and thus even small extensions to it easily break + the wheel concept, leading to even worse compromises. The timer wheel + code is very good and tight code, there's zero problems with it in its + current usage - but it is simply not suitable to be extended for + high-res timers. + +- the unpredictable [O(N)] overhead of cascading leads to delays which + necessitate a more complex handling of high resolution timers, which + in turn decreases robustness. Such a design still led to rather large + timing inaccuracies. Cascading is a fundamental property of the timer + wheel concept, it cannot be 'designed out' without unevitably + degrading other portions of the timers.c code in an unacceptable way. + +- the implementation of the current posix-timer subsystem on top of + the timer wheel has already introduced a quite complex handling of + the required readjusting of absolute CLOCK_REALTIME timers at + settimeofday or NTP time - further underlying our experience by + example: that the timer wheel data structure is too rigid for high-res + timers. + +- the timer wheel code is most optimal for use cases which can be + identified as "timeouts". Such timeouts are usually set up to cover + error conditions in various I/O paths, such as networking and block + I/O. The vast majority of those timers never expire and are rarely + recascaded because the expected correct event arrives in time so they + can be removed from the timer wheel before any further processing of + them becomes necessary. Thus the users of these timeouts can accept + the granularity and precision tradeoffs of the timer wheel, and + largely expect the timer subsystem to have near-zero overhead. + Accurate timing for them is not a core purpose - in fact most of the + timeout values used are ad-hoc. For them it is at most a necessary + evil to guarantee the processing of actual timeout completions + (because most of the timeouts are deleted before completion), which + should thus be as cheap and unintrusive as possible. + +The primary users of precision timers are user-space applications that +utilize nanosleep, posix-timers and itimer interfaces. Also, in-kernel +users like drivers and subsystems which require precise timed events +(e.g. multimedia) can benefit from the availability of a separate +high-resolution timer subsystem as well. + +While this subsystem does not offer high-resolution clock sources just +yet, the hrtimer subsystem can be easily extended with high-resolution +clock capabilities, and patches for that exist and are maturing quickly. +The increasing demand for realtime and multimedia applications along +with other potential users for precise timers gives another reason to +separate the "timeout" and "precise timer" subsystems. + +Another potential benefit is that such a separation allows even more +special-purpose optimization of the existing timer wheel for the low +resolution and low precision use cases - once the precision-sensitive +APIs are separated from the timer wheel and are migrated over to +hrtimers. E.g. we could decrease the frequency of the timeout subsystem +from 250 Hz to 100 HZ (or even smaller). + +hrtimer subsystem implementation details +---------------------------------------- + +the basic design considerations were: + +- simplicity + +- data structure not bound to jiffies or any other granularity. All the + kernel logic works at 64-bit nanoseconds resolution - no compromises. + +- simplification of existing, timing related kernel code + +another basic requirement was the immediate enqueueing and ordering of +timers at activation time. After looking at several possible solutions +such as radix trees and hashes, we chose the red black tree as the basic +data structure. Rbtrees are available as a library in the kernel and are +used in various performance-critical areas of e.g. memory management and +file systems. The rbtree is solely used for time sorted ordering, while +a separate list is used to give the expiry code fast access to the +queued timers, without having to walk the rbtree. + +(This separate list is also useful for later when we'll introduce +high-resolution clocks, where we need separate pending and expired +queues while keeping the time-order intact.) + +Time-ordered enqueueing is not purely for the purposes of +high-resolution clocks though, it also simplifies the handling of +absolute timers based on a low-resolution CLOCK_REALTIME. The existing +implementation needed to keep an extra list of all armed absolute +CLOCK_REALTIME timers along with complex locking. In case of +settimeofday and NTP, all the timers (!) had to be dequeued, the +time-changing code had to fix them up one by one, and all of them had to +be enqueued again. The time-ordered enqueueing and the storage of the +expiry time in absolute time units removes all this complex and poorly +scaling code from the posix-timer implementation - the clock can simply +be set without having to touch the rbtree. This also makes the handling +of posix-timers simpler in general. + +The locking and per-CPU behavior of hrtimers was mostly taken from the +existing timer wheel code, as it is mature and well suited. Sharing code +was not really a win, due to the different data structures. Also, the +hrtimer functions now have clearer behavior and clearer names - such as +hrtimer_try_to_cancel() and hrtimer_cancel() [which are roughly +equivalent to del_timer() and del_timer_sync()] - so there's no direct +1:1 mapping between them on the algorithmical level, and thus no real +potential for code sharing either. + +Basic data types: every time value, absolute or relative, is in a +special nanosecond-resolution type: ktime_t. The kernel-internal +representation of ktime_t values and operations is implemented via +macros and inline functions, and can be switched between a "hybrid +union" type and a plain "scalar" 64bit nanoseconds representation (at +compile time). The hybrid union type optimizes time conversions on 32bit +CPUs. This build-time-selectable ktime_t storage format was implemented +to avoid the performance impact of 64-bit multiplications and divisions +on 32bit CPUs. Such operations are frequently necessary to convert +between the storage formats provided by kernel and userspace interfaces +and the internal time format. (See include/linux/ktime.h for further +details.) + +hrtimers - rounding of timer values +----------------------------------- + +the hrtimer code will round timer events to lower-resolution clocks +because it has to. Otherwise it will do no artificial rounding at all. + +one question is, what resolution value should be returned to the user by +the clock_getres() interface. This will return whatever real resolution +a given clock has - be it low-res, high-res, or artificially-low-res. + +hrtimers - testing and verification +---------------------------------- + +We used the high-resolution clock subsystem ontop of hrtimers to verify +the hrtimer implementation details in praxis, and we also ran the posix +timer tests in order to ensure specification compliance. We also ran +tests on low-resolution clocks. + +The hrtimer patch converts the following kernel functionality to use +hrtimers: + + - nanosleep + - itimers + - posix-timers + +The conversion of nanosleep and posix-timers enabled the unification of +nanosleep and clock_nanosleep. + +The code was successfully compiled for the following platforms: + + i386, x86_64, ARM, PPC, PPC64, IA64 + +The code was run-tested on the following platforms: + + i386(UP/SMP), x86_64(UP/SMP), ARM, PPC + +hrtimers were also integrated into the -rt tree, along with a +hrtimers-based high-resolution clock implementation, so the hrtimers +code got a healthy amount of testing and use in practice. + + Thomas Gleixner, Ingo Molnar diff --git a/Documentation/i2c/busses/i2c-i801 b/Documentation/i2c/busses/i2c-i801 index 3db69a0..c34f0db 100644 --- a/Documentation/i2c/busses/i2c-i801 +++ b/Documentation/i2c/busses/i2c-i801 @@ -48,14 +48,9 @@ following: The SMBus controller is function 3 in device 1f. Class 0c05 is SMBus Serial Controller. -If you do NOT see the 24x3 device at function 3, and you can't figure out -any way in the BIOS to enable it, - The ICH chips are quite similar to Intel's PIIX4 chip, at least in the SMBus controller. -See the file i2c-piix4 for some additional information. - Process Call Support -------------------- @@ -74,6 +69,61 @@ SMBus 2.0 Support The 82801DB (ICH4) and later chips support several SMBus 2.0 features. + +Hidden ICH SMBus +---------------- + +If your system has an Intel ICH south bridge, but you do NOT see the +SMBus device at 00:1f.3 in lspci, and you can't figure out any way in the +BIOS to enable it, it means it has been hidden by the BIOS code. Asus is +well known for first doing this on their P4B motherboard, and many other +boards after that. Some vendor machines are affected as well. + +The first thing to try is the "i2c_ec" ACPI driver. It could be that the +SMBus was hidden on purpose because it'll be driven by ACPI. If the +i2c_ec driver works for you, just forget about the i2c-i801 driver and +don't try to unhide the ICH SMBus. Even if i2c_ec doesn't work, you +better make sure that the SMBus isn't used by the ACPI code. Try loading +the "fan" and "thermal" drivers, and check in /proc/acpi/fan and +/proc/acpi/thermal_zone. If you find anything there, it's likely that +the ACPI is accessing the SMBus and it's safer not to unhide it. Only +once you are certain that ACPI isn't using the SMBus, you can attempt +to unhide it. + +In order to unhide the SMBus, we need to change the value of a PCI +register before the kernel enumerates the PCI devices. This is done in +drivers/pci/quirks.c, where all affected boards must be listed (see +function asus_hides_smbus_hostbridge.) If the SMBus device is missing, +and you think there's something interesting on the SMBus (e.g. a +hardware monitoring chip), you need to add your board to the list. + +The motherboard is identified using the subvendor and subdevice IDs of the +host bridge PCI device. Get yours with "lspci -n -v -s 00:00.0": + +00:00.0 Class 0600: 8086:2570 (rev 02) + Subsystem: 1043:80f2 + Flags: bus master, fast devsel, latency 0 + Memory at fc000000 (32-bit, prefetchable) [size=32M] + Capabilities: [e4] #09 [2106] + Capabilities: [a0] AGP version 3.0 + +Here the host bridge ID is 2570 (82865G/PE/P), the subvendor ID is 1043 +(Asus) and the subdevice ID is 80f2 (P4P800-X). You can find the symbolic +names for the bridge ID and the subvendor ID in include/linux/pci_ids.h, +and then add a case for your subdevice ID at the right place in +drivers/pci/quirks.c. Then please give it very good testing, to make sure +that the unhidden SMBus doesn't conflict with e.g. ACPI. + +If it works, proves useful (i.e. there are usable chips on the SMBus) +and seems safe, please submit a patch for inclusion into the kernel. + +Note: There's a useful script in lm_sensors 2.10.2 and later, named +unhide_ICH_SMBus (in prog/hotplug), which uses the fakephp driver to +temporarily unhide the SMBus without having to patch and recompile your +kernel. It's very convenient if you just want to check if there's +anything interesting on your hidden ICH SMBus. + + ********************** The lm_sensors project gratefully acknowledges the support of Texas Instruments in the initial development of this driver. diff --git a/Documentation/i2c/busses/i2c-parport b/Documentation/i2c/busses/i2c-parport index 77b995d..dceaba1 100644 --- a/Documentation/i2c/busses/i2c-parport +++ b/Documentation/i2c/busses/i2c-parport @@ -19,6 +19,7 @@ It currently supports the following devi * (type=4) Analog Devices ADM1032 evaluation board * (type=5) Analog Devices evaluation boards: ADM1025, ADM1030, ADM1031 * (type=6) Barco LPT->DVI (K5800236) adapter + * (type=7) One For All JP1 parallel port adapter These devices use different pinout configurations, so you have to tell the driver what you have, using the type module parameter. There is no @@ -157,3 +158,17 @@ many more, using /dev/velleman. http://home.wanadoo.nl/hihihi/libk8005.htm http://struyve.mine.nu:8080/index.php?block=k8000 http://sourceforge.net/projects/libk8005/ + + +One For All JP1 parallel port adapter +------------------------------------- + +The JP1 project revolves around a set of remote controls which expose +the I2C bus their internal configuration EEPROM lives on via a 6 pin +jumper in the battery compartment. More details can be found at: + +http://www.hifi-remote.com/jp1/ + +Details of the simple parallel port hardware can be found at: + +http://www.hifi-remote.com/jp1/hardware.shtml diff --git a/Documentation/i2c/busses/i2c-piix4 b/Documentation/i2c/busses/i2c-piix4 index 9214763..7cbe43f 100644 --- a/Documentation/i2c/busses/i2c-piix4 +++ b/Documentation/i2c/busses/i2c-piix4 @@ -6,7 +6,7 @@ Supported adapters: Datasheet: Publicly available at the Intel website * ServerWorks OSB4, CSB5, CSB6 and HT-1000 southbridges Datasheet: Only available via NDA from ServerWorks - * ATI IXP southbridges IXP200, IXP300, IXP400 + * ATI IXP200, IXP300, IXP400 and SB600 southbridges Datasheet: Not publicly available * Standard Microsystems (SMSC) SLC90E66 (Victory66) southbridge Datasheet: Publicly available at the SMSC website http://www.smsc.com diff --git a/Documentation/i2c/busses/i2c-viapro b/Documentation/i2c/busses/i2c-viapro index 2568034..775f489 100644 --- a/Documentation/i2c/busses/i2c-viapro +++ b/Documentation/i2c/busses/i2c-viapro @@ -13,6 +13,9 @@ Supported adapters: * VIA Technologies, Inc. VT8235, VT8237R, VT8237A, VT8251 Datasheet: available on request and under NDA from VIA + * VIA Technologies, Inc. CX700 + Datasheet: available on request and under NDA from VIA + Authors: Kyösti Mälkki , Mark D. Studebaker , @@ -44,6 +47,7 @@ Your lspci -n listing must show one of t device 1106:3227 (VT8237R) device 1106:3337 (VT8237A) device 1106:3287 (VT8251) + device 1106:8324 (CX700) If none of these show up, you should look in the BIOS for settings like enable ACPI / SMBus or even USB. @@ -51,3 +55,6 @@ enable ACPI / SMBus or even USB. Except for the oldest chips (VT82C596A/B, VT82C686A and most probably VT8231), this driver supports I2C block transactions. Such transactions are mainly useful to read from and write to EEPROMs. + +The CX700 additionally appears to support SMBus PEC, although this driver +doesn't implement it yet. diff --git a/Documentation/i2c/porting-clients b/Documentation/i2c/porting-clients index f03c2a0..ca272b2 100644 --- a/Documentation/i2c/porting-clients +++ b/Documentation/i2c/porting-clients @@ -129,6 +129,12 @@ Technical changes: structure, those name member should be initialized to a driver name string. i2c_driver itself has no name member anymore. +* [Driver model] Instead of shutdown or reboot notifiers, provide a + shutdown() method in your driver. + +* [Power management] Use the driver model suspend() and resume() + callbacks instead of the obsolete pm_register() calls. + Coding policy: * [Copyright] Use (C), not (c), for copyright. diff --git a/Documentation/i2c/smbus-protocol b/Documentation/i2c/smbus-protocol index 09f5e5c..8a653c6 100644 --- a/Documentation/i2c/smbus-protocol +++ b/Documentation/i2c/smbus-protocol @@ -97,7 +97,7 @@ SMBus Write Word Data ===================== This is the opposite operation of the Read Word Data command. 16 bits -of data is read from a device, from a designated register that is +of data is written to a device, to the designated register that is specified through the Comm byte. S Addr Wr [A] Comm [A] DataLow [A] DataHigh [A] P diff --git a/Documentation/i2c/writing-clients b/Documentation/i2c/writing-clients index 3a057c8..fbcff96 100644 --- a/Documentation/i2c/writing-clients +++ b/Documentation/i2c/writing-clients @@ -21,20 +21,26 @@ The driver structure Usually, you will implement a single driver structure, and instantiate all clients from it. Remember, a driver structure contains general access -routines, a client structure specific information like the actual I2C -address. +routines, and should be zero-initialized except for fields with data you +provide. A client structure holds device-specific information like the +driver model device node, and its I2C address. static struct i2c_driver foo_driver = { .driver = { .name = "foo", }, - .attach_adapter = &foo_attach_adapter, - .detach_client = &foo_detach_client, - .command = &foo_command /* may be NULL */ + .attach_adapter = foo_attach_adapter, + .detach_client = foo_detach_client, + .shutdown = foo_shutdown, /* optional */ + .suspend = foo_suspend, /* optional */ + .resume = foo_resume, /* optional */ + .command = foo_command, /* optional */ } -The name field must match the driver name, including the case. It must not -contain spaces, and may be up to 31 characters long. +The name field is the driver name, and must not contain spaces. It +should match the module name (if the driver can be compiled as a module), +although you can use MODULE_ALIAS (passing "foo" in this example) to add +another name for the module. All other fields are for call-back functions which will be explained below. @@ -43,11 +49,18 @@ below. Extra client data ================= -The client structure has a special `data' field that can point to any -structure at all. You can use this to keep client-specific data. You +Each client structure has a special `data' field that can point to any +structure at all. You should use this to keep device-specific data, +especially in drivers that handle multiple I2C or SMBUS devices. You do not always need this, but especially for `sensors' drivers, it can be very useful. + /* store the value */ + void i2c_set_clientdata(struct i2c_client *client, void *data); + + /* retrieve the value */ + void *i2c_get_clientdata(struct i2c_client *client); + An example structure is below. struct foo_data { @@ -493,6 +506,33 @@ by `__init_data'. Hose functions and st kernel booting (or module loading) is completed. +Power Management +================ + +If your I2C device needs special handling when entering a system low +power state -- like putting a transceiver into a low power mode, or +activating a system wakeup mechanism -- do that in the suspend() method. +The resume() method should reverse what the suspend() method does. + +These are standard driver model calls, and they work just like they +would for any other driver stack. The calls can sleep, and can use +I2C messaging to the device being suspended or resumed (since their +parent I2C adapter is active when these calls are issued, and IRQs +are still enabled). + + +System Shutdown +=============== + +If your I2C device needs special handling when the system shuts down +or reboots (including kexec) -- like turning something off -- use a +shutdown() method. + +Again, this is a standard driver model call, working just like it +would for any other driver stack: the calls can sleep, and can use +I2C messaging. + + Command function ================ diff --git a/Documentation/ioctl-number.txt b/Documentation/ioctl-number.txt index 5a8bd5b..8f750c0 100644 --- a/Documentation/ioctl-number.txt +++ b/Documentation/ioctl-number.txt @@ -94,8 +94,7 @@ Code Seq# Include File Comments 'L' 00-1F linux/loop.h 'L' E0-FF linux/ppdd.h encrypted disk device driver -'M' all linux/soundcard.h conflict! -'M' 00-1F linux/isicom.h conflict! +'M' all linux/soundcard.h 'N' 00-1F drivers/usb/scanner.h 'P' all linux/soundcard.h 'Q' all linux/soundcard.h diff --git a/Documentation/isdn/README.gigaset b/Documentation/isdn/README.gigaset index fa0d4cc..55b2852 100644 --- a/Documentation/isdn/README.gigaset +++ b/Documentation/isdn/README.gigaset @@ -8,29 +8,33 @@ GigaSet 307x Device Driver This release supports the connection of the Gigaset 307x/417x family of ISDN DECT bases via Gigaset M101 Data, Gigaset M105 Data or direct USB connection. The following devices are reported to be compatible: - 307x/417x: - Gigaset SX255isdn - Gigaset SX353isdn - Sinus 45 [AB] isdn (Deutsche Telekom) - Sinus 721X/XA + + Bases: + Siemens Gigaset 3070/3075 isdn + Siemens Gigaset 4170/4175 isdn + Siemens Gigaset SX205/255 + Siemens Gigaset SX353 + T-Com Sinus 45 [AB] isdn + T-Com Sinus 721X[A] [SE] Vox Chicago 390 ISDN (KPN Telecom) - M101: - Sinus 45 Data 1 (Telekom) - M105: - Gigaset USB Adapter DECT - Sinus 45 Data 2 (Telekom) - Sinus 721 data + + RS232 data boxes: + Siemens Gigaset M101 Data + T-Com Sinus 45 Data 1 + + USB data boxes: + Siemens Gigaset M105 Data + Siemens Gigaset USB Adapter DECT + T-Com Sinus 45 Data 2 + T-Com Sinus 721 data Chicago 390 USB (KPN) + See also http://www.erbze.info/sinus_gigaset.htm and http://gigaset307x.sourceforge.net/ We had also reports from users of Gigaset M105 who could use the drivers with SX 100 and CX 100 ISDN bases (only in unimodem mode, see section 2.4.) If you have another device that works with our driver, please let us know. - For example, Gigaset SX205isdn/Sinus 721 X SE and Gigaset SX303isdn bases - are just versions without answering machine of models known to work, so - they should work just as well; but so far we are lacking positive reports - on these. Chances of getting an USB device to work are good if the output of lsusb @@ -60,14 +64,28 @@ GigaSet 307x Device Driver To get the device working, you have to load the proper kernel module. You can do this using modprobe modulename - where modulename is usb_gigaset (M105) or bas_gigaset (direct USB - connection to the base). + where modulename is ser_gigaset (M101), usb_gigaset (M105), or + bas_gigaset (direct USB connection to the base). + + The module ser_gigaset provides a serial line discipline N_GIGASET_M101 + which drives the device through the regular serial line driver. To use it, + run the Gigaset M101 daemon "gigasetm101d" (also available from + http://sourceforge.net/projects/gigaset307x/) with the device file of the + RS232 port to the M101 as an argument, for example: + gigasetm101d /dev/ttyS1 + This will open the device file, set its line discipline to N_GIGASET_M101, + and then sleep in the background, keeping the device open so that the + line discipline remains active. To deactivate it, kill the daemon, for + example with + killall gigasetm101d + before disconnecting the device. 2.2. Device nodes for user space programs ------------------------------------ The device can be accessed from user space (eg. by the user space tools mentioned in 1.2.) through the device nodes: + - /dev/ttyGS0 for M101 (RS232 data boxes) - /dev/ttyGU0 for M105 (USB data boxes) - /dev/ttyGB0 for the base driver (direct USB connection) @@ -168,6 +186,19 @@ GigaSet 307x Device Driver You can also use /sys/class/tty/ttyGxy/cidmode for changing the CID mode setting (ttyGxy is ttyGU0 or ttyGB0). +2.6. M105 Undocumented USB Requests + ------------------------------ + + The Gigaset M105 USB data box understands a couple of useful, but + undocumented USB commands. These requests are not used in normal + operation (for wireless access to the base), but are needed for access + to the M105's own configuration mode (registration to the base, baudrate + and line format settings, device status queries) via the gigacontr + utility. Their use is disabled in the driver by default for safety + reasons but can be enabled by setting the kernel configuration option + "Support for undocumented USB requests" (GIGASET_UNDOCREQ) to "Y" and + recompiling. + 3. Troubleshooting --------------- diff --git a/Documentation/kdump/kdump.txt b/Documentation/kdump/kdump.txt index 0733068..79775a4 100644 --- a/Documentation/kdump/kdump.txt +++ b/Documentation/kdump/kdump.txt @@ -311,10 +311,10 @@ Following are the arch specific command loading dump-capture kernel. For i386, x86_64 and ia64: - "init 1 irqpoll maxcpus=1" + "1 irqpoll maxcpus=1" For ppc64: - "init 1 maxcpus=1 noirqdistrib" + "1 maxcpus=1 noirqdistrib" Notes on loading the dump-capture kernel: @@ -332,8 +332,8 @@ Notes on loading the dump-capture kernel * You must specify in the format corresponding to the root device name in the output of mount command. -* "init 1" boots the dump-capture kernel into single-user mode without - networking. If you want networking, use "init 3." +* Boot parameter "1" boots the dump-capture kernel into single-user + mode without networking. If you want networking, use "3". * We generally don' have to bring up a SMP kernel just to capture the dump. Hence generally it is useful either to build a UP dump-capture diff --git a/Documentation/kernel-doc-nano-HOWTO.txt b/Documentation/kernel-doc-nano-HOWTO.txt index 284e7e1..2075c06 100644 --- a/Documentation/kernel-doc-nano-HOWTO.txt +++ b/Documentation/kernel-doc-nano-HOWTO.txt @@ -101,16 +101,20 @@ The format of the block comment is like /** * function_name(:)? (- short description)? -(* @parameterx: (description of parameter x)?)* +(* @parameterx(space)*: (description of parameter x)?)* (* a blank line)? * (Description:)? (Description of function)? * (section header: (section description)? )* (*)?*/ -The short function description cannot be multiline, but the other -descriptions can be (and they can contain blank lines). Avoid putting a -spurious blank line after the function name, or else the description will -be repeated! +The short function description ***cannot be multiline***, but the other +descriptions can be (and they can contain blank lines). If you continue +that initial short description onto a second line, that second line will +appear further down at the beginning of the description section, which is +almost certainly not what you had in mind. + +Avoid putting a spurious blank line after the function name, or else the +description will be repeated! All descriptive text is further processed, scanning for the following special patterns, which are highlighted appropriately. @@ -121,6 +125,31 @@ patterns, which are highlighted appropri '@parameter' - name of a parameter '%CONST' - name of a constant. +NOTE 1: The multi-line descriptive text you provide does *not* recognize +line breaks, so if you try to format some text nicely, as in: + + Return codes + 0 - cool + 1 - invalid arg + 2 - out of memory + +this will all run together and produce: + + Return codes 0 - cool 1 - invalid arg 2 - out of memory + +NOTE 2: If the descriptive text you provide has lines that begin with +some phrase followed by a colon, each of those phrases will be taken as +a new section heading, which means you should similarly try to avoid text +like: + + Return codes: + 0: cool + 1: invalid arg + 2: out of memory + +every line of which would start a new section. Again, probably not +what you were after. + Take a look around the source tree for examples. diff --git a/Documentation/kernel-parameters.txt b/Documentation/kernel-parameters.txt index 25d2985..abd575c 100644 --- a/Documentation/kernel-parameters.txt +++ b/Documentation/kernel-parameters.txt @@ -104,6 +104,9 @@ loader, and have no meaning to the kerne Do not modify the syntax of boot loader parameters without extreme need or coordination with . +There are also arch-specific kernel-parameters not documented here. +See for example . + Note that ALL kernel parameters listed below are CASE SENSITIVE, and that a trailing = on the name of any parameter states that that parameter will be entered as an environment variable, whereas its absence indicates that @@ -361,6 +364,11 @@ and is between 256 and 4096 characters. clocksource is not available, it defaults to PIT. Format: { pit | tsc | cyclone | pmtmr } + code_bytes [IA32] How many bytes of object code to print in an + oops report. + Range: 0 - 8192 + Default: 64 + disable_8254_timer enable_8254_timer [IA32/X86_64] Disable/Enable interrupt 0 timer routing @@ -601,6 +609,10 @@ and is between 256 and 4096 characters. highmem otherwise. This also works to reduce highmem size on bigger boxes. + highres= [KNL] Enable/disable high resolution timer mode. + Valid parameters: "on", "off" + Default: "on" + hisax= [HW,ISDN] See Documentation/isdn/README.HiSax. @@ -1070,6 +1082,10 @@ and is between 256 and 4096 characters. in certain environments such as networked servers or real-time systems. + nohz= [KNL] Boottime enable/disable dynamic ticks + Valid arguments: on, off + Default: on + noirqbalance [IA-32,SMP,KNL] Disable kernel irq balancing noirqdebug [IA-32] Disables the code which attempts to detect and @@ -1396,6 +1412,8 @@ and is between 256 and 4096 characters. in units (needed only for swap files). See Documentation/power/swsusp-and-swap-files.txt + retain_initrd [RAM] Keep initrd memory after extraction + rhash_entries= [KNL,NET] Set number of hash buckets for route cache diff --git a/Documentation/local_ops.txt b/Documentation/local_ops.txt new file mode 100644 index 0000000..b0aca07 --- /dev/null +++ b/Documentation/local_ops.txt @@ -0,0 +1,163 @@ + Semantics and Behavior of Local Atomic Operations + + Mathieu Desnoyers + + + This document explains the purpose of the local atomic operations, how +to implement them for any given architecture and shows how they can be used +properly. It also stresses on the precautions that must be taken when reading +those local variables across CPUs when the order of memory writes matters. + + + +* Purpose of local atomic operations + +Local atomic operations are meant to provide fast and highly reentrant per CPU +counters. They minimize the performance cost of standard atomic operations by +removing the LOCK prefix and memory barriers normally required to synchronize +across CPUs. + +Having fast per CPU atomic counters is interesting in many cases : it does not +require disabling interrupts to protect from interrupt handlers and it permits +coherent counters in NMI handlers. It is especially useful for tracing purposes +and for various performance monitoring counters. + +Local atomic operations only guarantee variable modification atomicity wrt the +CPU which owns the data. Therefore, care must taken to make sure that only one +CPU writes to the local_t data. This is done by using per cpu data and making +sure that we modify it from within a preemption safe context. It is however +permitted to read local_t data from any CPU : it will then appear to be written +out of order wrt other memory writes on the owner CPU. + + +* Implementation for a given architecture + +It can be done by slightly modifying the standard atomic operations : only +their UP variant must be kept. It typically means removing LOCK prefix (on +i386 and x86_64) and any SMP sychronization barrier. If the architecture does +not have a different behavior between SMP and UP, including asm-generic/local.h +in your archtecture's local.h is sufficient. + +The local_t type is defined as an opaque signed long by embedding an +atomic_long_t inside a structure. This is made so a cast from this type to a +long fails. The definition looks like : + +typedef struct { atomic_long_t a; } local_t; + + +* How to use local atomic operations + +#include +#include + +static DEFINE_PER_CPU(local_t, counters) = LOCAL_INIT(0); + + +* Counting + +Counting is done on all the bits of a signed long. + +In preemptible context, use get_cpu_var() and put_cpu_var() around local atomic +operations : it makes sure that preemption is disabled around write access to +the per cpu variable. For instance : + + local_inc(&get_cpu_var(counters)); + put_cpu_var(counters); + +If you are already in a preemption-safe context, you can directly use +__get_cpu_var() instead. + + local_inc(&__get_cpu_var(counters)); + + + +* Reading the counters + +Those local counters can be read from foreign CPUs to sum the count. Note that +the data seen by local_read across CPUs must be considered to be out of order +relatively to other memory writes happening on the CPU that owns the data. + + long sum = 0; + for_each_online_cpu(cpu) + sum += local_read(&per_cpu(counters, cpu)); + +If you want to use a remote local_read to synchronize access to a resource +between CPUs, explicit smp_wmb() and smp_rmb() memory barriers must be used +respectively on the writer and the reader CPUs. It would be the case if you use +the local_t variable as a counter of bytes written in a buffer : there should +be a smp_wmb() between the buffer write and the counter increment and also a +smp_rmb() between the counter read and the buffer read. + + +Here is a sample module which implements a basic per cpu counter using local.h. + +--- BEGIN --- +/* test-local.c + * + * Sample module for local.h usage. + */ + + +#include +#include +#include + +static DEFINE_PER_CPU(local_t, counters) = LOCAL_INIT(0); + +static struct timer_list test_timer; + +/* IPI called on each CPU. */ +static void test_each(void *info) +{ + /* Increment the counter from a non preemptible context */ + printk("Increment on cpu %d\n", smp_processor_id()); + local_inc(&__get_cpu_var(counters)); + + /* This is what incrementing the variable would look like within a + * preemptible context (it disables preemption) : + * + * local_inc(&get_cpu_var(counters)); + * put_cpu_var(counters); + */ +} + +static void do_test_timer(unsigned long data) +{ + int cpu; + + /* Increment the counters */ + on_each_cpu(test_each, NULL, 0, 1); + /* Read all the counters */ + printk("Counters read from CPU %d\n", smp_processor_id()); + for_each_online_cpu(cpu) { + printk("Read : CPU %d, count %ld\n", cpu, + local_read(&per_cpu(counters, cpu))); + } + del_timer(&test_timer); + test_timer.expires = jiffies + 1000; + add_timer(&test_timer); +} + +static int __init test_init(void) +{ + /* initialize the timer that will increment the counter */ + init_timer(&test_timer); + test_timer.function = do_test_timer; + test_timer.expires = jiffies + 1; + add_timer(&test_timer); + + return 0; +} + +static void __exit test_exit(void) +{ + del_timer_sync(&test_timer); +} + +module_init(test_init); +module_exit(test_exit); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Mathieu Desnoyers"); +MODULE_DESCRIPTION("Local Atomic Ops"); +--- END --- diff --git a/Documentation/nfsroot.txt b/Documentation/nfsroot.txt index 719f9a9..16a7cae 100644 --- a/Documentation/nfsroot.txt +++ b/Documentation/nfsroot.txt @@ -67,8 +67,8 @@ nfsroot=[:][, Standard NFS options. All options are separated by commas. The following defaults are used: port = as given by server portmap daemon - rsize = 1024 - wsize = 1024 + rsize = 4096 + wsize = 4096 timeo = 7 retrans = 3 acregmin = 3 diff --git a/Documentation/powerpc/booting-without-of.txt b/Documentation/powerpc/booting-without-of.txt index 3399427..3b51467 100644 --- a/Documentation/powerpc/booting-without-of.txt +++ b/Documentation/powerpc/booting-without-of.txt @@ -1334,6 +1334,9 @@ platforms are moved over to use the flat fsl-usb2-mph compatible controllers. Either this property or "port0" (or both) must be defined for "fsl-usb2-mph" compatible controllers. + - dr_mode : indicates the working mode for "fsl-usb2-dr" compatible + controllers. Can be "host", "peripheral", or "otg". Default to + "host" if not defined for backward compatibility. Recommended properties : - interrupts : where a is the interrupt number and b is a @@ -1367,6 +1370,7 @@ platforms are moved over to use the flat #size-cells = <0>; interrupt-parent = <700>; interrupts = <26 1>; + dr_mode = "otg"; phy = "ulpi"; }; diff --git a/Documentation/powerpc/mpc52xx-device-tree-bindings.txt b/Documentation/powerpc/mpc52xx-device-tree-bindings.txt index 69f016f..e59fcbb 100644 --- a/Documentation/powerpc/mpc52xx-device-tree-bindings.txt +++ b/Documentation/powerpc/mpc52xx-device-tree-bindings.txt @@ -1,7 +1,7 @@ -MPC52xx Device Tree Bindings +MPC5200 Device Tree Bindings ---------------------------- -(c) 2006 Secret Lab Technologies Ltd +(c) 2006-2007 Secret Lab Technologies Ltd Grant Likely ********** DRAFT *********** @@ -20,11 +20,11 @@ described in Documentation/powerpc/booti by Open Firmare (IEEE 1275) compatible firmware using an OF compatible client interface API. -This document specifies the requirements on the device-tree for mpc52xx +This document specifies the requirements on the device-tree for mpc5200 based boards. These requirements are above and beyond the details specified in either the OpenFirmware spec or booting-without-of.txt -All new mpc52xx-based boards are expected to match this document. In +All new mpc5200-based boards are expected to match this document. In cases where this document is not sufficient to support a new board port, this document should be updated as part of adding the new board support. @@ -32,26 +32,26 @@ II - Philosophy =============== The core of this document is naming convention. The whole point of defining this convention is to reduce or eliminate the number of -special cases required to support a 52xx board. If all 52xx boards -follow the same convention, then generic 52xx support code will work +special cases required to support a 5200 board. If all 5200 boards +follow the same convention, then generic 5200 support code will work rather than coding special cases for each new board. This section tries to capture the thought process behind why the naming convention is what it is. -1. Node names -------------- +1. names +--------- There is strong convention/requirements already established for children of the root node. 'cpus' describes the processor cores, 'memory' describes memory, and 'chosen' provides boot configuration. Other nodes are added to describe devices attached to the processor local bus. + Following convention already established with other system-on-chip -processors, MPC52xx boards must have an 'soc5200' node as a child of the -root node. +processors, 5200 device trees should use the name 'soc5200' for the +parent node of on chip devices, and the root node should be its parent. -The soc5200 node holds child nodes for all on chip devices. Child nodes -are typically named after the configured function. ie. the FEC node is -named 'ethernet', and a PSC in uart mode is named 'serial'. +Child nodes are typically named after the configured function. ie. +the FEC node is named 'ethernet', and a PSC in uart mode is named 'serial'. 2. device_type property ----------------------- @@ -66,28 +66,47 @@ exactly. Since device_type isn't enough to match devices to drivers, there also needs to be a naming convention for the compatible property. Compatible is an list of device descriptions sorted from specific to generic. For -the mpc52xx, the required format for each compatible value is --[-]. At the minimum, the list shall contain two -items; the first specifying the exact chip, and the second specifying -mpc52xx for the chip. - -ie. ethernet on mpc5200b: compatible = "mpc5200b-ethernet\0mpc52xx-ethernet" - -The idea here is that most drivers will match to the most generic field -in the compatible list (mpc52xx-*), but can also test the more specific -field for enabling bug fixes or extra features. +the mpc5200, the required format for each compatible value is +-[-]. The OS should be able to match a device driver +to the device based solely on the compatible value. If two drivers +match on the compatible list; the 'most compatible' driver should be +selected. + +The split between the MPC5200 and the MPC5200B leaves a bit of a +connundrum. How should the compatible property be set up to provide +maximum compatability information; but still acurately describe the +chip? For the MPC5200; the answer is easy. Most of the SoC devices +originally appeared on the MPC5200. Since they didn't exist anywhere +else; the 5200 compatible properties will contain only one item; +"mpc5200-". + +The 5200B is almost the same as the 5200, but not quite. It fixes +silicon bugs and it adds a small number of enhancements. Most of the +devices either provide exactly the same interface as on the 5200. A few +devices have extra functions but still have a backwards compatible mode. +To express this infomation as completely as possible, 5200B device trees +should have two items in the compatible list; +"mpc5200b-\0mpc5200-". It is *strongly* recommended +that 5200B device trees follow this convention (instead of only listing +the base mpc5200 item). + +If another chip appear on the market with one of the mpc5200 SoC +devices, then the compatible list should include mpc5200-. + +ie. ethernet on mpc5200: compatible = "mpc5200-ethernet" + ethernet on mpc5200b: compatible = "mpc5200b-ethernet\0mpc5200-ethernet" Modal devices, like PSCs, also append the configured function to the end of the compatible field. ie. A PSC in i2s mode would specify -"mpc52xx-psc-i2s", not "mpc52xx-i2s". This convention is chosen to +"mpc5200-psc-i2s", not "mpc5200-i2s". This convention is chosen to avoid naming conflicts with non-psc devices providing the same -function. For example, "mpc52xx-spi" and "mpc52xx-psc-spi" describe +function. For example, "mpc5200-spi" and "mpc5200-psc-spi" describe the mpc5200 simple spi device and a PSC spi mode respectively. If the soc device is more generic and present on other SOCs, the compatible property can specify the more generic device type also. -ie. mscan: compatible = "mpc5200-mscan\0mpc52xx-mscan\0fsl,mscan"; +ie. mscan: compatible = "mpc5200-mscan\0fsl,mscan"; At the time of writing, exact chip may be either 'mpc5200' or 'mpc5200b'. @@ -96,7 +115,7 @@ Device drivers should always try to matc III - Structure =============== -The device tree for an mpc52xx board follows the structure defined in +The device tree for an mpc5200 board follows the structure defined in booting-without-of.txt with the following additional notes: 0) the root node @@ -115,7 +134,7 @@ Typical memory description node; see boo 3) The soc5200 node ------------------- -This node describes the on chip SOC peripherals. Every mpc52xx based +This node describes the on chip SOC peripherals. Every mpc5200 based board will have this node, and as such there is a common naming convention for SOC devices. @@ -125,71 +144,111 @@ name type description device_type string must be "soc" ranges int should be <0 baseaddr baseaddr+10000> reg int must be +compatible string mpc5200: "mpc5200-soc" + mpc5200b: "mpc5200b-soc\0mpc5200-soc" +system-frequency int Fsystem frequency; source of all + other clocks. +bus-frequency int IPB bus frequency in HZ. Clock rate + used by most of the soc devices. +#interrupt-cells int must be <3>. Recommended properties: name type description ---- ---- ----------- -compatible string should be "-soc\0mpc52xx-soc" - ie. "mpc5200b-soc\0mpc52xx-soc" -#interrupt-cells int must be <3>. If it is not defined - here then it must be defined in every - soc device node. -bus-frequency int IPB bus frequency in HZ. Clock rate - used by most of the soc devices. - Defining it here avoids needing it - added to every device node. +model string Exact model of the chip; + ie: model="fsl,mpc5200" +revision string Silicon revision of chip + ie: revision="M08A" + +The 'model' and 'revision' properties are *strongly* recommended. Having +them presence acts as a bit of a safety net for working around as yet +undiscovered bugs on one version of silicon. For example, device drivers +can use the model and revision properties to decide if a bug fix should +be turned on. 4) soc5200 child nodes ---------------------- Any on chip SOC devices available to Linux must appear as soc5200 child nodes. -Note: in the tables below, '*' matches all values. ie. -*-pic would translate to "mpc5200-pic\0mpc52xx-pic" +Note: The tables below show the value for the mpc5200. A mpc5200b device +tree should use the "mpc5200b-\0mpc5200- form. Required soc5200 child nodes: name device_type compatible Description ---- ----------- ---------- ----------- -cdm@ cdm *-cmd Clock Distribution -pic@ interrupt-controller *-pic need an interrupt +cdm@ cdm mpc5200-cmd Clock Distribution +pic@ interrupt-controller mpc5200-pic need an interrupt controller to boot -bestcomm@ dma-controller *-bestcomm 52xx pic also requires - the bestcomm device +bestcomm@ dma-controller mpc5200-bestcomm 5200 pic also requires + the bestcomm device Recommended soc5200 child nodes; populate as needed for your board -name device_type compatible Description ----- ----------- ---------- ----------- -gpt@ gpt *-gpt General purpose timers -rtc@ rtc *-rtc Real time clock -mscan@ mscan *-mscan CAN bus controller -pci@ pci *-pci PCI bridge -serial@ serial *-psc-uart PSC in serial mode -i2s@ sound *-psc-i2s PSC in i2s mode -ac97@ sound *-psc-ac97 PSC in ac97 mode -spi@ spi *-psc-spi PSC in spi mode -irda@ irda *-psc-irda PSC in IrDA mode -spi@ spi *-spi MPC52xx spi device -ethernet@ network *-fec MPC52xx ethernet device -ata@ ata *-ata IDE ATA interface -i2c@ i2c *-i2c I2C controller -usb@ usb-ohci-be *-ohci,ohci-be USB controller -xlb@ xlb *-xlb XLB arbritrator +name device_type compatible Description +---- ----------- ---------- ----------- +gpt@ gpt mpc5200-gpt General purpose timers +rtc@ rtc mpc5200-rtc Real time clock +mscan@ mscan mpc5200-mscan CAN bus controller +pci@ pci mpc5200-pci PCI bridge +serial@ serial mpc5200-psc-uart PSC in serial mode +i2s@ sound mpc5200-psc-i2s PSC in i2s mode +ac97@ sound mpc5200-psc-ac97 PSC in ac97 mode +spi@ spi mpc5200-psc-spi PSC in spi mode +irda@ irda mpc5200-psc-irda PSC in IrDA mode +spi@ spi mpc5200-spi MPC5200 spi device +ethernet@ network mpc5200-fec MPC5200 ethernet device +ata@ ata mpc5200-ata IDE ATA interface +i2c@ i2c mpc5200-i2c I2C controller +usb@ usb-ohci-be mpc5200-ohci,ohci-be USB controller +xlb@ xlb mpc5200-xlb XLB arbritrator + +Important child node properties +name type description +---- ---- ----------- +cell-index int When multiple devices are present, is the + index of the device in the hardware (ie. There + are 6 PSC on the 5200 numbered PSC1 to PSC6) + PSC1 has 'cell-index = <0>' + PSC4 has 'cell-index = <3>' + +5) General Purpose Timer nodes (child of soc5200 node) +On the mpc5200 and 5200b, GPT0 has a watchdog timer function. If the board +design supports the internal wdt, then the device node for GPT0 should +include the empty property 'has-wdt'. + +6) PSC nodes (child of soc5200 node) +PSC nodes can define the optional 'port-number' property to force assignment +order of serial ports. For example, PSC5 might be physically connected to +the port labeled 'COM1' and PSC1 wired to 'COM1'. In this case, PSC5 would +have a "port-number = <0>" property, and PSC1 would have "port-number = <1>". + +PSC in i2s mode: The mpc5200 and mpc5200b PSCs are not compatible when in +i2s mode. An 'mpc5200b-psc-i2s' node cannot include 'mpc5200-psc-i2s' in the +compatible field. IV - Extra Notes ================ 1. Interrupt mapping -------------------- -The mpc52xx pic driver splits hardware IRQ numbers into two levels. The +The mpc5200 pic driver splits hardware IRQ numbers into two levels. The split reflects the layout of the PIC hardware itself, which groups interrupts into one of three groups; CRIT, MAIN or PERP. Also, the Bestcomm dma engine has it's own set of interrupt sources which are cascaded off of peripheral interrupt 0, which the driver interprets as a fourth group, SDMA. -The interrupts property for device nodes using the mpc52xx pic consists +The interrupts property for device nodes using the mpc5200 pic consists of three cells; L1 := [CRIT=0, MAIN=1, PERP=2, SDMA=3] L2 := interrupt number; directly mapped from the value in the "ICTL PerStat, MainStat, CritStat Encoded Register" level := [LEVEL_HIGH=0, EDGE_RISING=1, EDGE_FALLING=2, LEVEL_LOW=3] + +2. Shared registers +------------------- +Some SoC devices share registers between them. ie. the i2c devices use +a single clock control register, and almost all device are affected by +the port_config register. Devices which need to manipulate shared regs +should look to the parent SoC node. The soc node is responsible +for arbitrating all shared register access. diff --git a/Documentation/rbtree.txt b/Documentation/rbtree.txt new file mode 100644 index 0000000..7224459 --- /dev/null +++ b/Documentation/rbtree.txt @@ -0,0 +1,192 @@ +Red-black Trees (rbtree) in Linux +January 18, 2007 +Rob Landley +============================= + +What are red-black trees, and what are they for? +------------------------------------------------ + +Red-black trees are a type of self-balancing binary search tree, used for +storing sortable key/value data pairs. This differs from radix trees (which +are used to efficiently store sparse arrays and thus use long integer indexes +to insert/access/delete nodes) and hash tables (which are not kept sorted to +be easily traversed in order, and must be tuned for a specific size and +hash function where rbtrees scale gracefully storing arbitrary keys). + +Red-black trees are similar to AVL trees, but provide faster real-time bounded +worst case performance for insertion and deletion (at most two rotations and +three rotations, respectively, to balance the tree), with slightly slower +(but still O(log n)) lookup time. + +To quote Linux Weekly News: + + There are a number of red-black trees in use in the kernel. + The anticipatory, deadline, and CFQ I/O schedulers all employ + rbtrees to track requests; the packet CD/DVD driver does the same. + The high-resolution timer code uses an rbtree to organize outstanding + timer requests. The ext3 filesystem tracks directory entries in a + red-black tree. Virtual memory areas (VMAs) are tracked with red-black + trees, as are epoll file descriptors, cryptographic keys, and network + packets in the "hierarchical token bucket" scheduler. + +This document covers use of the Linux rbtree implementation. For more +information on the nature and implementation of Red Black Trees, see: + + Linux Weekly News article on red-black trees + http://lwn.net/Articles/184495/ + + Wikipedia entry on red-black trees + http://en.wikipedia.org/wiki/Red-black_tree + +Linux implementation of red-black trees +--------------------------------------- + +Linux's rbtree implementation lives in the file "lib/rbtree.c". To use it, +"#include ". + +The Linux rbtree implementation is optimized for speed, and thus has one +less layer of indirection (and better cache locality) than more traditional +tree implementations. Instead of using pointers to separate rb_node and data +structures, each instance of struct rb_node is embedded in the data structure +it organizes. And instead of using a comparison callback function pointer, +users are expected to write their own tree search and insert functions +which call the provided rbtree functions. Locking is also left up to the +user of the rbtree code. + +Creating a new rbtree +--------------------- + +Data nodes in an rbtree tree are structures containing a struct rb_node member: + + struct mytype { + struct rb_node node; + char *keystring; + }; + +When dealing with a pointer to the embedded struct rb_node, the containing data +structure may be accessed with the standard container_of() macro. In addition, +individual members may be accessed directly via rb_entry(node, type, member). + +At the root of each rbtree is an rb_root structure, which is initialized to be +empty via: + + struct rb_root mytree = RB_ROOT; + +Searching for a value in an rbtree +---------------------------------- + +Writing a search function for your tree is fairly straightforward: start at the +root, compare each value, and follow the left or right branch as necessary. + +Example: + + struct mytype *my_search(struct rb_root *root, char *string) + { + struct rb_node *node = root->rb_node; + + while (node) { + struct mytype *data = container_of(node, struct mytype, node); + int result; + + result = strcmp(string, data->keystring); + + if (result < 0) + node = node->rb_left; + else if (result > 0) + node = node->rb_right; + else + return data; + } + return NULL; + } + +Inserting data into an rbtree +----------------------------- + +Inserting data in the tree involves first searching for the place to insert the +new node, then inserting the node and rebalancing ("recoloring") the tree. + +The search for insertion differs from the previous search by finding the +location of the pointer on which to graft the new node. The new node also +needs a link to its parent node for rebalancing purposes. + +Example: + + int my_insert(struct rb_root *root, struct mytype *data) + { + struct rb_node **new = &(root->rb_node), *parent = NULL; + + /* Figure out where to put new node */ + while (*new) { + struct mytype *this = container_of(*new, struct mytype, node); + int result = strcmp(data->keystring, this->keystring); + + parent = *new; + if (result < 0) + new = &((*new)->rb_left); + else if (result > 0) + new = &((*new)->rb_right); + else + return FALSE; + } + + /* Add new node and rebalance tree. */ + rb_link_node(data->node, parent, new); + rb_insert_color(data->node, root); + + return TRUE; + } + +Removing or replacing existing data in an rbtree +------------------------------------------------ + +To remove an existing node from a tree, call: + + void rb_erase(struct rb_node *victim, struct rb_root *tree); + +Example: + + struct mytype *data = mysearch(mytree, "walrus"); + + if (data) { + rb_erase(data->node, mytree); + myfree(data); + } + +To replace an existing node in a tree with a new one with the same key, call: + + void rb_replace_node(struct rb_node *old, struct rb_node *new, + struct rb_root *tree); + +Replacing a node this way does not re-sort the tree: If the new node doesn't +have the same key as the old node, the rbtree will probably become corrupted. + +Iterating through the elements stored in an rbtree (in sort order) +------------------------------------------------------------------ + +Four functions are provided for iterating through an rbtree's contents in +sorted order. These work on arbitrary trees, and should not need to be +modified or wrapped (except for locking purposes): + + struct rb_node *rb_first(struct rb_root *tree); + struct rb_node *rb_last(struct rb_root *tree); + struct rb_node *rb_next(struct rb_node *node); + struct rb_node *rb_prev(struct rb_node *node); + +To start iterating, call rb_first() or rb_last() with a pointer to the root +of the tree, which will return a pointer to the node structure contained in +the first or last element in the tree. To continue, fetch the next or previous +node by calling rb_next() or rb_prev() on the current node. This will return +NULL when there are no more nodes left. + +The iterator functions return a pointer to the embedded struct rb_node, from +which the containing data structure may be accessed with the container_of() +macro, and individual members may be accessed directly via +rb_entry(node, type, member). + +Example: + + struct rb_node *node; + for (node = rb_first(&mytree); node; node = rb_next(node)) + printk("key=%s\n", rb_entry(node, int, keystring)); + diff --git a/Documentation/rtc.txt b/Documentation/rtc.txt index 7cf1ec5..1ef6bb8 100644 --- a/Documentation/rtc.txt +++ b/Documentation/rtc.txt @@ -149,7 +149,7 @@ RTC class framework, but can't be suppor is connected to an IRQ line, it can often issue an alarm IRQ up to 24 hours in the future. - * RTC_WKALM_SET, RTC_WKALM_READ ... RTCs that can issue alarms beyond + * RTC_WKALM_SET, RTC_WKALM_RD ... RTCs that can issue alarms beyond the next 24 hours use a slightly more powerful API, which supports setting the longer alarm time and enabling its IRQ using a single request (using the same model as EFI firmware). @@ -167,6 +167,28 @@ Linux out of a low power sleep state (or operational state. For example, a system could enter a deep power saving state until it's time to execute some scheduled tasks. +Note that many of these ioctls need not actually be implemented by your +driver. The common rtc-dev interface handles many of these nicely if your +driver returns ENOIOCTLCMD. Some common examples: + + * RTC_RD_TIME, RTC_SET_TIME: the read_time/set_time functions will be + called with appropriate values. + + * RTC_ALM_SET, RTC_ALM_READ, RTC_WKALM_SET, RTC_WKALM_RD: the + set_alarm/read_alarm functions will be called. To differentiate + between the ALM and WKALM, check the larger fields of the rtc_wkalrm + struct (like tm_year). These will be set to -1 when using ALM and + will be set to proper values when using WKALM. + + * RTC_IRQP_SET, RTC_IRQP_READ: the irq_set_freq function will be called + to set the frequency while the framework will handle the read for you + since the frequency is stored in the irq_freq member of the rtc_device + structure. Also make sure you set the max_user_freq member in your + initialization routines so the framework can sanity check the user + input for you. + +If all else fails, check out the rtc-test.c driver! + -------------------- 8< ---------------- 8< ----------------------------- @@ -237,7 +259,7 @@ int main(int argc, char **argv) "\n...Update IRQs not supported.\n"); goto test_READ; } - perror("ioctl"); + perror("RTC_UIE_ON ioctl"); exit(errno); } @@ -284,7 +306,7 @@ int main(int argc, char **argv) /* Turn off update interrupts */ retval = ioctl(fd, RTC_UIE_OFF, 0); if (retval == -1) { - perror("ioctl"); + perror("RTC_UIE_OFF ioctl"); exit(errno); } @@ -292,7 +314,7 @@ test_READ: /* Read the RTC time/date */ retval = ioctl(fd, RTC_RD_TIME, &rtc_tm); if (retval == -1) { - perror("ioctl"); + perror("RTC_RD_TIME ioctl"); exit(errno); } @@ -320,14 +342,14 @@ test_READ: "\n...Alarm IRQs not supported.\n"); goto test_PIE; } - perror("ioctl"); + perror("RTC_ALM_SET ioctl"); exit(errno); } /* Read the current alarm settings */ retval = ioctl(fd, RTC_ALM_READ, &rtc_tm); if (retval == -1) { - perror("ioctl"); + perror("RTC_ALM_READ ioctl"); exit(errno); } @@ -337,7 +359,7 @@ test_READ: /* Enable alarm interrupts */ retval = ioctl(fd, RTC_AIE_ON, 0); if (retval == -1) { - perror("ioctl"); + perror("RTC_AIE_ON ioctl"); exit(errno); } @@ -355,7 +377,7 @@ test_READ: /* Disable alarm interrupts */ retval = ioctl(fd, RTC_AIE_OFF, 0); if (retval == -1) { - perror("ioctl"); + perror("RTC_AIE_OFF ioctl"); exit(errno); } @@ -368,7 +390,7 @@ test_PIE: fprintf(stderr, "\nNo periodic IRQ support\n"); return 0; } - perror("ioctl"); + perror("RTC_IRQP_READ ioctl"); exit(errno); } fprintf(stderr, "\nPeriodic IRQ rate is %ldHz.\n", tmp); @@ -387,7 +409,7 @@ test_PIE: "\n...Periodic IRQ rate is fixed\n"); goto done; } - perror("ioctl"); + perror("RTC_IRQP_SET ioctl"); exit(errno); } @@ -397,7 +419,7 @@ test_PIE: /* Enable periodic interrupts */ retval = ioctl(fd, RTC_PIE_ON, 0); if (retval == -1) { - perror("ioctl"); + perror("RTC_PIE_ON ioctl"); exit(errno); } @@ -416,7 +438,7 @@ test_PIE: /* Disable periodic interrupts */ retval = ioctl(fd, RTC_PIE_OFF, 0); if (retval == -1) { - perror("ioctl"); + perror("RTC_PIE_OFF ioctl"); exit(errno); } } diff --git a/Documentation/s390/Debugging390.txt b/Documentation/s390/Debugging390.txt index 3f9ddbc..0993969 100644 --- a/Documentation/s390/Debugging390.txt +++ b/Documentation/s390/Debugging390.txt @@ -480,7 +480,7 @@ r2 argument 0 / return value 0 r3 argument 1 / return value 1 (if long long) call-clobbered r4 argument 2 call-clobbered r5 argument 3 call-clobbered -r6 argument 5 saved +r6 argument 4 saved r7 pointer-to arguments 5 to ... saved r8 this & that saved r9 this & that saved diff --git a/Documentation/scsi/ChangeLog.megaraid b/Documentation/scsi/ChangeLog.megaraid index a056bbe..37796fe 100644 --- a/Documentation/scsi/ChangeLog.megaraid +++ b/Documentation/scsi/ChangeLog.megaraid @@ -1,3 +1,19 @@ +Release Date : Thu Nov 16 15:32:35 EST 2006 - + Sumant Patro +Current Version : 2.20.5.1 (scsi module), 2.20.2.6 (cmm module) +Older Version : 2.20.4.9 (scsi module), 2.20.2.6 (cmm module) + +1. Changes in Initialization to fix kdump failure. + Send SYNC command on loading. + This command clears the pending commands in the adapter + and re-initialize its internal RAID structure. + Without this change, megaraid driver either panics or fails to + initialize the adapter during kdump's second kernel boot + if there are pending commands or interrupts from other devices + sharing the same IRQ. +2. Authors email-id domain name changed from lsil.com to lsi.com. + Also modified the MODULE_AUTHOR to megaraidlinux@lsi.com + Release Date : Fri May 19 09:31:45 EST 2006 - Seokmann Ju Current Version : 2.20.4.9 (scsi module), 2.20.2.6 (cmm module) Older Version : 2.20.4.8 (scsi module), 2.20.2.6 (cmm module) diff --git a/Documentation/sound/alsa/ALSA-Configuration.txt b/Documentation/sound/alsa/ALSA-Configuration.txt index 9fef210..c30ff1b 100644 --- a/Documentation/sound/alsa/ALSA-Configuration.txt +++ b/Documentation/sound/alsa/ALSA-Configuration.txt @@ -242,6 +242,12 @@ Prior to version 0.9.0rc4 options had a ac97_clock - AC'97 clock (default = 48000) ac97_quirk - AC'97 workaround for strange hardware See "AC97 Quirk Option" section below. + ac97_codec - Workaround to specify which AC'97 codec + instead of probing. If this works for you + file a bug with your `lspci -vn` output. + -2 -- Force probing. + -1 -- Default behavior. + 0-2 -- Use the specified codec. spdif_aclink - S/PDIF transfer over AC-link (default = 1) This module supports one card and autoprobe. @@ -779,6 +785,7 @@ Prior to version 0.9.0rc4 options had a asus-dig ASUS with SPDIF out asus-dig2 ASUS with SPDIF out (using GPIO2) uniwill 3-jack + fujitsu Fujitsu Laptops (Pi1536) F1734 2-jack lg LG laptop (m1 express dual) lg-lw LG LW20/LW25 laptop @@ -800,14 +807,18 @@ Prior to version 0.9.0rc4 options had a ALC262 fujitsu Fujitsu Laptop hp-bpc HP xw4400/6400/8400/9400 laptops + hp-bpc-d7000 HP BPC D7000 benq Benq ED8 + hippo Hippo (ATI) with jack detection, Sony UX-90s + hippo_1 Hippo (Benq) with jack detection basic fixed pin assignment w/o SPDIF auto auto-config reading BIOS (default) ALC882/885 3stack-dig 3-jack with SPDIF I/O - 6stck-dig 6-jack digital with SPDIF I/O + 6stack-dig 6-jack digital with SPDIF I/O arima Arima W820Di1 + macpro MacPro support auto auto-config reading BIOS (default) ALC883/888 @@ -817,6 +828,10 @@ Prior to version 0.9.0rc4 options had a 3stack-6ch-dig 3-jack 6-channel with SPDIF I/O 6stack-dig-demo 6-jack digital for Intel demo board acer Acer laptops (Travelmate 3012WTMi, Aspire 5600, etc) + medion Medion Laptops + targa-dig Targa/MSI + targa-2ch-dig Targs/MSI with 2-channel + laptop-eapd 3-jack with SPDIF I/O and EAPD (Clevo M540JE, M550JE) auto auto-config reading BIOS (default) ALC861/660 @@ -825,6 +840,16 @@ Prior to version 0.9.0rc4 options had a 6stack-dig 6-jack with SPDIF I/O 3stack-660 3-jack (for ALC660) uniwill-m31 Uniwill M31 laptop + toshiba Toshiba laptop support + asus Asus laptop support + asus-laptop ASUS F2/F3 laptops + auto auto-config reading BIOS (default) + + ALC861VD/660VD + 3stack 3-jack + 3stack-dig 3-jack with SPDIF OUT + 6stack-dig 6-jack with SPDIF OUT + 3stack-660 3-jack (for ALC660VD) auto auto-config reading BIOS (default) CMI9880 @@ -845,6 +870,7 @@ Prior to version 0.9.0rc4 options had a 3stack 3-stack, shared surrounds laptop 2-channel only (FSC V2060, Samsung M50) laptop-eapd 2-channel with EAPD (Samsung R65, ASUS A6J) + ultra 2-channel with EAPD (Samsung Ultra tablet PC) AD1988 6stack 6-jack @@ -854,12 +880,31 @@ Prior to version 0.9.0rc4 options had a laptop 3-jack with hp-jack automute laptop-dig ditto with SPDIF auto auto-config reading BIOS (default) + + Conexant 5045 + laptop Laptop config + test for testing/debugging purpose, almost all controls + can be adjusted. Appearing only when compiled with + $CONFIG_SND_DEBUG=y + + Conexant 5047 + laptop Basic Laptop config + laptop-hp Laptop config for some HP models (subdevice 30A5) + laptop-eapd Laptop config with EAPD support + test for testing/debugging purpose, almost all controls + can be adjusted. Appearing only when compiled with + $CONFIG_SND_DEBUG=y STAC9200/9205/9220/9221/9254 ref Reference board 3stack D945 3stack 5stack D945 5stack + SPDIF + STAC9202/9250/9251 + ref Reference board, base config + m2-2 Some Gateway MX series laptops + m6 Some Gateway NX series laptops + STAC9227/9228/9229/927x ref Reference board 3stack D965 3stack @@ -974,6 +1019,7 @@ Prior to version 0.9.0rc4 options had a Module for Envy24HT (VT/ICE1724), Envy24PT (VT1720) based PCI sound cards. * MidiMan M Audio Revolution 5.1 * MidiMan M Audio Revolution 7.1 + * MidiMan M Audio Audiophile 192 * AMP Ltd AUDIO2000 * TerraTec Aureon 5.1 Sky * TerraTec Aureon 7.1 Space @@ -993,7 +1039,7 @@ Prior to version 0.9.0rc4 options had a model - Use the given board model, one of the following: revo51, revo71, amp2000, prodigy71, prodigy71lt, - prodigy192, aureon51, aureon71, universe, + prodigy192, aureon51, aureon71, universe, ap192, k8x800, phase22, phase28, ms300, av710 This module supports multiple cards and autoprobe. @@ -1049,6 +1095,9 @@ Prior to version 0.9.0rc4 options had a buggy_semaphore - Enable workaround for hardwares with buggy semaphores (e.g. on some ASUS laptops) (default off) + spdif_aclink - Use S/PDIF over AC-link instead of direct connection + from the controller chip + (0 = off, 1 = on, -1 = default) This module supports one chip and autoprobe. @@ -1371,6 +1420,13 @@ Prior to version 0.9.0rc4 options had a This module supports multiple cards. + Module snd-portman2x4 + --------------------- + + Module for Midiman Portman 2x4 parallel port MIDI interface + + This module supports multiple cards. + Module snd-powermac (on ppc only) --------------------------------- diff --git a/Documentation/sound/alsa/DocBook/alsa-driver-api.tmpl b/Documentation/sound/alsa/DocBook/alsa-driver-api.tmpl index 1f3ae3e..c4d2e35 100644 --- a/Documentation/sound/alsa/DocBook/alsa-driver-api.tmpl +++ b/Documentation/sound/alsa/DocBook/alsa-driver-api.tmpl @@ -36,7 +36,7 @@ Management of Cards and Devices - Card Managment + Card Management !Esound/core/init.c Device Components @@ -59,7 +59,7 @@ PCM Format Helpers !Esound/core/pcm_misc.c - PCM Memory Managment + PCM Memory Management !Esound/core/pcm_memory.c diff --git a/Documentation/sound/alsa/DocBook/writing-an-alsa-driver.tmpl b/Documentation/sound/alsa/DocBook/writing-an-alsa-driver.tmpl index ccd0a95..74d3a35 100644 --- a/Documentation/sound/alsa/DocBook/writing-an-alsa-driver.tmpl +++ b/Documentation/sound/alsa/DocBook/writing-an-alsa-driver.tmpl @@ -1360,8 +1360,7 @@ substream->runtime. This runtime pointer holds the various information; it holds the copy of hw_params and sw_params configurations, the buffer - pointers, mmap records, spinlocks, etc. Almost everyhing you + pointers, mmap records, spinlocks, etc. Almost everything you need for controlling the PCM can be found there. @@ -2340,7 +2339,7 @@ #endif When the PCM substreams can be synchronized (typically, - synchorinized start/stop of a playback and a capture streams), + synchronized start/stop of a playback and a capture streams), you can give SNDRV_PCM_INFO_SYNC_START, too. In this case, you'll need to check the linked-list of PCM substreams in the trigger callback. This will be @@ -3062,8 +3061,7 @@ #endif Interrupt Handler Case #1 lock); @@ -3106,8 +3104,7 @@ #endif Interrupt Handler Case #2 lock); @@ -3247,7 +3244,7 @@ #endif You can even define your own constraint rules. For example, let's suppose my_chip can manage a substream of 1 channel if and only if the format is S16_LE, otherwise it supports any format - specified in the snd_pcm_hardware stucture (or in any + specified in the snd_pcm_hardware structure (or in any other constraint_list). You can build a rule like this: @@ -3691,16 +3688,6 @@ #endif - Here, the chip instance is retrieved via - snd_kcontrol_chip() macro. This macro - just accesses to kcontrol->private_data. The - kcontrol->private_data field is - given as the argument of snd_ctl_new() - (see the later subsection - Constructor). - - - The value field is depending on the type of control as well as on info callback. For example, the sb driver uses this field to store the register offset, @@ -3780,7 +3767,7 @@ #endif Like get callback, when the control has more than one elements, - all elemehts must be evaluated in this callback, too. + all elements must be evaluated in this callback, too. @@ -5541,12 +5528,12 @@ #endif #ifdef CONFIG_PM static int snd_my_suspend(struct pci_dev *pci, pm_message_t state) { - .... /* do things for suspsend */ + .... /* do things for suspend */ return 0; } static int snd_my_resume(struct pci_dev *pci) { - .... /* do things for suspsend */ + .... /* do things for suspend */ return 0; } #endif @@ -6111,7 +6098,7 @@ #endif - + Acknowledgments I would like to thank Phil Kerr for his help for improvement and diff --git a/Documentation/sound/alsa/hda_codec.txt b/Documentation/sound/alsa/hda_codec.txt index 0be57ed..4eaae2a 100644 --- a/Documentation/sound/alsa/hda_codec.txt +++ b/Documentation/sound/alsa/hda_codec.txt @@ -277,11 +277,11 @@ Helper Functions snd_hda_get_codec_name() stores the codec name on the given string. snd_hda_check_board_config() can be used to obtain the configuration -information matching with the device. Define the table with struct -hda_board_config entries (zero-terminated), and pass it to the -function. The function checks the modelname given as a module -parameter, and PCI subsystem IDs. If the matching entry is found, it -returns the config field value. +information matching with the device. Define the model string table +and the table with struct snd_pci_quirk entries (zero-terminated), +and pass it to the function. The function checks the modelname given +as a module parameter, and PCI subsystem IDs. If the matching entry +is found, it returns the config field value. snd_hda_add_new_ctls() can be used to create and add control entries. Pass the zero-terminated array of struct snd_kcontrol_new. The same array diff --git a/Documentation/sound/alsa/soc/DAI.txt b/Documentation/sound/alsa/soc/DAI.txt new file mode 100644 index 0000000..58cbfd0 --- /dev/null +++ b/Documentation/sound/alsa/soc/DAI.txt @@ -0,0 +1,56 @@ +ASoC currently supports the three main Digital Audio Interfaces (DAI) found on +SoC controllers and portable audio CODECS today, namely AC97, I2S and PCM. + + +AC97 +==== + + AC97 is a five wire interface commonly found on many PC sound cards. It is +now also popular in many portable devices. This DAI has a reset line and time +multiplexes its data on its SDATA_OUT (playback) and SDATA_IN (capture) lines. +The bit clock (BCLK) is always driven by the CODEC (usually 12.288MHz) and the +frame (FRAME) (usually 48kHz) is always driven by the controller. Each AC97 +frame is 21uS long and is divided into 13 time slots. + +The AC97 specification can be found at :- +http://www.intel.com/design/chipsets/audio/ac97_r23.pdf + + +I2S +=== + + I2S is a common 4 wire DAI used in HiFi, STB and portable devices. The Tx and +Rx lines are used for audio transmision, whilst the bit clock (BCLK) and +left/right clock (LRC) synchronise the link. I2S is flexible in that either the +controller or CODEC can drive (master) the BCLK and LRC clock lines. Bit clock +usually varies depending on the sample rate and the master system clock +(SYSCLK). LRCLK is the same as the sample rate. A few devices support separate +ADC and DAC LRCLK's, this allows for similtanious capture and playback at +different sample rates. + +I2S has several different operating modes:- + + o I2S - MSB is transmitted on the falling edge of the first BCLK after LRC + transition. + + o Left Justified - MSB is transmitted on transition of LRC. + + o Right Justified - MSB is transmitted sample size BCLK's before LRC + transition. + +PCM +=== + +PCM is another 4 wire interface, very similar to I2S, that can support a more +flexible protocol. It has bit clock (BCLK) and sync (SYNC) lines that are used +to synchronise the link whilst the Tx and Rx lines are used to transmit and +receive the audio data. Bit clock usually varies depending on sample rate +whilst sync runs at the sample rate. PCM also supports Time Division +Multiplexing (TDM) in that several devices can use the bus similtaniuosly (This +is sometimes referred to as network mode). + +Common PCM operating modes:- + + o Mode A - MSB is transmitted on falling edge of first BCLK after FRAME/SYNC. + + o Mode B - MSB is transmitted on rising edge of FRAME/SYNC. diff --git a/Documentation/sound/alsa/soc/clocking.txt b/Documentation/sound/alsa/soc/clocking.txt new file mode 100644 index 0000000..e93960d --- /dev/null +++ b/Documentation/sound/alsa/soc/clocking.txt @@ -0,0 +1,51 @@ +Audio Clocking +============== + +This text describes the audio clocking terms in ASoC and digital audio in +general. Note: Audio clocking can be complex ! + + +Master Clock +------------ + +Every audio subsystem is driven by a master clock (sometimes refered to as MCLK +or SYSCLK). This audio master clock can be derived from a number of sources +(e.g. crystal, PLL, CPU clock) and is responsible for producing the correct +audio playback and capture sample rates. + +Some master clocks (e.g. PLL's and CPU based clocks) are configuarble in that +their speed can be altered by software (depending on the system use and to save +power). Other master clocks are fixed at at set frequency (i.e. crystals). + + +DAI Clocks +---------- +The Digital Audio Interface is usually driven by a Bit Clock (often referred to +as BCLK). This clock is used to drive the digital audio data across the link +between the codec and CPU. + +The DAI also has a frame clock to signal the start of each audio frame. This +clock is sometimes referred to as LRC (left right clock) or FRAME. This clock +runs at exactly the sample rate (LRC = Rate). + +Bit Clock can be generated as follows:- + +BCLK = MCLK / x + + or + +BCLK = LRC * x + + or + +BCLK = LRC * Channels * Word Size + +This relationship depends on the codec or SoC CPU in particular. In general +it's best to configure BCLK to the lowest possible speed (depending on your +rate, number of channels and wordsize) to save on power. + +It's also desireable to use the codec (if possible) to drive (or master) the +audio clocks as it's usually gives more accurate sample rates than the CPU. + + + diff --git a/Documentation/sound/alsa/soc/codec.txt b/Documentation/sound/alsa/soc/codec.txt new file mode 100644 index 0000000..48983c7 --- /dev/null +++ b/Documentation/sound/alsa/soc/codec.txt @@ -0,0 +1,197 @@ +ASoC Codec Driver +================= + +The codec driver is generic and hardware independent code that configures the +codec to provide audio capture and playback. It should contain no code that is +specific to the target platform or machine. All platform and machine specific +code should be added to the platform and machine drivers respectively. + +Each codec driver *must* provide the following features:- + + 1) Codec DAI and PCM configuration + 2) Codec control IO - using I2C, 3 Wire(SPI) or both API's + 3) Mixers and audio controls + 4) Codec audio operations + +Optionally, codec drivers can also provide:- + + 5) DAPM description. + 6) DAPM event handler. + 7) DAC Digital mute control. + +It's probably best to use this guide in conjuction with the existing codec +driver code in sound/soc/codecs/ + +ASoC Codec driver breakdown +=========================== + +1 - Codec DAI and PCM configuration +----------------------------------- +Each codec driver must have a struct snd_soc_codec_dai to define it's DAI and +PCM's capablities and operations. This struct is exported so that it can be +registered with the core by your machine driver. + +e.g. + +struct snd_soc_codec_dai wm8731_dai = { + .name = "WM8731", + /* playback capabilities */ + .playback = { + .stream_name = "Playback", + .channels_min = 1, + .channels_max = 2, + .rates = WM8731_RATES, + .formats = WM8731_FORMATS,}, + /* capture capabilities */ + .capture = { + .stream_name = "Capture", + .channels_min = 1, + .channels_max = 2, + .rates = WM8731_RATES, + .formats = WM8731_FORMATS,}, + /* pcm operations - see section 4 below */ + .ops = { + .prepare = wm8731_pcm_prepare, + .hw_params = wm8731_hw_params, + .shutdown = wm8731_shutdown, + }, + /* DAI operations - see DAI.txt */ + .dai_ops = { + .digital_mute = wm8731_mute, + .set_sysclk = wm8731_set_dai_sysclk, + .set_fmt = wm8731_set_dai_fmt, + } +}; +EXPORT_SYMBOL_GPL(wm8731_dai); + + +2 - Codec control IO +-------------------- +The codec can ususally be controlled via an I2C or SPI style interface (AC97 +combines control with data in the DAI). The codec drivers will have to provide +functions to read and write the codec registers along with supplying a register +cache:- + + /* IO control data and register cache */ + void *control_data; /* codec control (i2c/3wire) data */ + void *reg_cache; + +Codec read/write should do any data formatting and call the hardware read write +below to perform the IO. These functions are called by the core and alsa when +performing DAPM or changing the mixer:- + + unsigned int (*read)(struct snd_soc_codec *, unsigned int); + int (*write)(struct snd_soc_codec *, unsigned int, unsigned int); + +Codec hardware IO functions - usually points to either the I2C, SPI or AC97 +read/write:- + + hw_write_t hw_write; + hw_read_t hw_read; + + +3 - Mixers and audio controls +----------------------------- +All the codec mixers and audio controls can be defined using the convenience +macros defined in soc.h. + + #define SOC_SINGLE(xname, reg, shift, mask, invert) + +Defines a single control as follows:- + + xname = Control name e.g. "Playback Volume" + reg = codec register + shift = control bit(s) offset in register + mask = control bit size(s) e.g. mask of 7 = 3 bits + invert = the control is inverted + +Other macros include:- + + #define SOC_DOUBLE(xname, reg, shift_left, shift_right, mask, invert) + +A stereo control + + #define SOC_DOUBLE_R(xname, reg_left, reg_right, shift, mask, invert) + +A stereo control spanning 2 registers + + #define SOC_ENUM_SINGLE(xreg, xshift, xmask, xtexts) + +Defines an single enumerated control as follows:- + + xreg = register + xshift = control bit(s) offset in register + xmask = control bit(s) size + xtexts = pointer to array of strings that describe each setting + + #define SOC_ENUM_DOUBLE(xreg, xshift_l, xshift_r, xmask, xtexts) + +Defines a stereo enumerated control + + +4 - Codec Audio Operations +-------------------------- +The codec driver also supports the following alsa operations:- + +/* SoC audio ops */ +struct snd_soc_ops { + int (*startup)(struct snd_pcm_substream *); + void (*shutdown)(struct snd_pcm_substream *); + int (*hw_params)(struct snd_pcm_substream *, struct snd_pcm_hw_params *); + int (*hw_free)(struct snd_pcm_substream *); + int (*prepare)(struct snd_pcm_substream *); +}; + +Please refer to the alsa driver PCM documentation for details. +http://www.alsa-project.org/~iwai/writing-an-alsa-driver/c436.htm + + +5 - DAPM description. +--------------------- +The Dynamic Audio Power Management description describes the codec's power +components, their relationships and registers to the ASoC core. Please read +dapm.txt for details of building the description. + +Please also see the examples in other codec drivers. + + +6 - DAPM event handler +---------------------- +This function is a callback that handles codec domain PM calls and system +domain PM calls (e.g. suspend and resume). It's used to put the codec to sleep +when not in use. + +Power states:- + + SNDRV_CTL_POWER_D0: /* full On */ + /* vref/mid, clk and osc on, active */ + + SNDRV_CTL_POWER_D1: /* partial On */ + SNDRV_CTL_POWER_D2: /* partial On */ + + SNDRV_CTL_POWER_D3hot: /* Off, with power */ + /* everything off except vref/vmid, inactive */ + + SNDRV_CTL_POWER_D3cold: /* Everything Off, without power */ + + +7 - Codec DAC digital mute control. +------------------------------------ +Most codecs have a digital mute before the DAC's that can be used to minimise +any system noise. The mute stops any digital data from entering the DAC. + +A callback can be created that is called by the core for each codec DAI when the +mute is applied or freed. + +i.e. + +static int wm8974_mute(struct snd_soc_codec *codec, + struct snd_soc_codec_dai *dai, int mute) +{ + u16 mute_reg = wm8974_read_reg_cache(codec, WM8974_DAC) & 0xffbf; + if(mute) + wm8974_write(codec, WM8974_DAC, mute_reg | 0x40); + else + wm8974_write(codec, WM8974_DAC, mute_reg); + return 0; +} diff --git a/Documentation/sound/alsa/soc/dapm.txt b/Documentation/sound/alsa/soc/dapm.txt new file mode 100644 index 0000000..c11877f --- /dev/null +++ b/Documentation/sound/alsa/soc/dapm.txt @@ -0,0 +1,297 @@ +Dynamic Audio Power Management for Portable Devices +=================================================== + +1. Description +============== + +Dynamic Audio Power Management (DAPM) is designed to allow portable Linux devices +to use the minimum amount of power within the audio subsystem at all times. It +is independent of other kernel PM and as such, can easily co-exist with the +other PM systems. + +DAPM is also completely transparent to all user space applications as all power +switching is done within the ASoC core. No code changes or recompiling are +required for user space applications. DAPM makes power switching descisions based +upon any audio stream (capture/playback) activity and audio mixer settings +within the device. + +DAPM spans the whole machine. It covers power control within the entire audio +subsystem, this includes internal codec power blocks and machine level power +systems. + +There are 4 power domains within DAPM + + 1. Codec domain - VREF, VMID (core codec and audio power) + Usually controlled at codec probe/remove and suspend/resume, although + can be set at stream time if power is not needed for sidetone, etc. + + 2. Platform/Machine domain - physically connected inputs and outputs + Is platform/machine and user action specific, is configured by the + machine driver and responds to asynchronous events e.g when HP + are inserted + + 3. Path domain - audio susbsystem signal paths + Automatically set when mixer and mux settings are changed by the user. + e.g. alsamixer, amixer. + + 4. Stream domain - DAC's and ADC's. + Enabled and disabled when stream playback/capture is started and + stopped respectively. e.g. aplay, arecord. + +All DAPM power switching descisons are made automatically by consulting an audio +routing map of the whole machine. This map is specific to each machine and +consists of the interconnections between every audio component (including +internal codec components). All audio components that effect power are called +widgets hereafter. + + +2. DAPM Widgets +=============== + +Audio DAPM widgets fall into a number of types:- + + o Mixer - Mixes several analog signals into a single analog signal. + o Mux - An analog switch that outputs only 1 of it's inputs. + o PGA - A programmable gain amplifier or attenuation widget. + o ADC - Analog to Digital Converter + o DAC - Digital to Analog Converter + o Switch - An analog switch + o Input - A codec input pin + o Output - A codec output pin + o Headphone - Headphone (and optional Jack) + o Mic - Mic (and optional Jack) + o Line - Line Input/Output (and optional Jack) + o Speaker - Speaker + o Pre - Special PRE widget (exec before all others) + o Post - Special POST widget (exec after all others) + +(Widgets are defined in include/sound/soc-dapm.h) + +Widgets are usually added in the codec driver and the machine driver. There are +convience macros defined in soc-dapm.h that can be used to quickly build a +list of widgets of the codecs and machines DAPM widgets. + +Most widgets have a name, register, shift and invert. Some widgets have extra +parameters for stream name and kcontrols. + + +2.1 Stream Domain Widgets +------------------------- + +Stream Widgets relate to the stream power domain and only consist of ADC's +(analog to digital converters) and DAC's (digital to analog converters). + +Stream widgets have the following format:- + +SND_SOC_DAPM_DAC(name, stream name, reg, shift, invert), + +NOTE: the stream name must match the corresponding stream name in your codecs +snd_soc_codec_dai. + +e.g. stream widgets for HiFi playback and capture + +SND_SOC_DAPM_DAC("HiFi DAC", "HiFi Playback", REG, 3, 1), +SND_SOC_DAPM_ADC("HiFi ADC", "HiFi Capture", REG, 2, 1), + + +2.2 Path Domain Widgets +----------------------- + +Path domain widgets have a ability to control or effect the audio signal or +audio paths within the audio subsystem. They have the following form:- + +SND_SOC_DAPM_PGA(name, reg, shift, invert, controls, num_controls) + +Any widget kcontrols can be set using the controls and num_controls members. + +e.g. Mixer widget (the kcontrols are declared first) + +/* Output Mixer */ +static const snd_kcontrol_new_t wm8731_output_mixer_controls[] = { +SOC_DAPM_SINGLE("Line Bypass Switch", WM8731_APANA, 3, 1, 0), +SOC_DAPM_SINGLE("Mic Sidetone Switch", WM8731_APANA, 5, 1, 0), +SOC_DAPM_SINGLE("HiFi Playback Switch", WM8731_APANA, 4, 1, 0), +}; + +SND_SOC_DAPM_MIXER("Output Mixer", WM8731_PWR, 4, 1, wm8731_output_mixer_controls, + ARRAY_SIZE(wm8731_output_mixer_controls)), + + +2.3 Platform/Machine domain Widgets +----------------------------------- + +Machine widgets are different from codec widgets in that they don't have a +codec register bit associated with them. A machine widget is assigned to each +machine audio component (non codec) that can be independently powered. e.g. + + o Speaker Amp + o Microphone Bias + o Jack connectors + +A machine widget can have an optional call back. + +e.g. Jack connector widget for an external Mic that enables Mic Bias +when the Mic is inserted:- + +static int spitz_mic_bias(struct snd_soc_dapm_widget* w, int event) +{ + if(SND_SOC_DAPM_EVENT_ON(event)) + set_scoop_gpio(&spitzscoop2_device.dev, SPITZ_SCP2_MIC_BIAS); + else + reset_scoop_gpio(&spitzscoop2_device.dev, SPITZ_SCP2_MIC_BIAS); + + return 0; +} + +SND_SOC_DAPM_MIC("Mic Jack", spitz_mic_bias), + + +2.4 Codec Domain +---------------- + +The Codec power domain has no widgets and is handled by the codecs DAPM event +handler. This handler is called when the codec powerstate is changed wrt to any +stream event or by kernel PM events. + + +2.5 Virtual Widgets +------------------- + +Sometimes widgets exist in the codec or machine audio map that don't have any +corresponding register bit for power control. In this case it's necessary to +create a virtual widget - a widget with no control bits e.g. + +SND_SOC_DAPM_MIXER("AC97 Mixer", SND_SOC_DAPM_NOPM, 0, 0, NULL, 0), + +This can be used to merge to signal paths together in software. + +After all the widgets have been defined, they can then be added to the DAPM +subsystem individually with a call to snd_soc_dapm_new_control(). + + +3. Codec Widget Interconnections +================================ + +Widgets are connected to each other within the codec and machine by audio +paths (called interconnections). Each interconnection must be defined in order +to create a map of all audio paths between widgets. +This is easiest with a diagram of the codec (and schematic of the machine audio +system), as it requires joining widgets together via their audio signal paths. + +i.e. from the WM8731 codec's output mixer (wm8731.c) + +The WM8731 output mixer has 3 inputs (sources) + + 1. Line Bypass Input + 2. DAC (HiFi playback) + 3. Mic Sidetone Input + +Each input in this example has a kcontrol associated with it (defined in example +above) and is connected to the output mixer via it's kcontrol name. We can now +connect the destination widget (wrt audio signal) with it's source widgets. + + /* output mixer */ + {"Output Mixer", "Line Bypass Switch", "Line Input"}, + {"Output Mixer", "HiFi Playback Switch", "DAC"}, + {"Output Mixer", "Mic Sidetone Switch", "Mic Bias"}, + +So we have :- + + Destination Widget <=== Path Name <=== Source Widget + +Or:- + + Sink, Path, Source + +Or :- + + "Output Mixer" is connected to the "DAC" via the "HiFi Playback Switch". + +When there is no path name connecting widgets (e.g. a direct connection) we +pass NULL for the path name. + +Interconnections are created with a call to:- + +snd_soc_dapm_connect_input(codec, sink, path, source); + +Finally, snd_soc_dapm_new_widgets(codec) must be called after all widgets and +interconnections have been registered with the core. This causes the core to +scan the codec and machine so that the internal DAPM state matches the +physical state of the machine. + + +3.1 Machine Widget Interconnections +----------------------------------- +Machine widget interconnections are created in the same way as codec ones and +directly connect the codec pins to machine level widgets. + +e.g. connects the speaker out codec pins to the internal speaker. + + /* ext speaker connected to codec pins LOUT2, ROUT2 */ + {"Ext Spk", NULL , "ROUT2"}, + {"Ext Spk", NULL , "LOUT2"}, + +This allows the DAPM to power on and off pins that are connected (and in use) +and pins that are NC respectively. + + +4 Endpoint Widgets +=================== +An endpoint is a start or end point (widget) of an audio signal within the +machine and includes the codec. e.g. + + o Headphone Jack + o Internal Speaker + o Internal Mic + o Mic Jack + o Codec Pins + +When a codec pin is NC it can be marked as not used with a call to + +snd_soc_dapm_set_endpoint(codec, "Widget Name", 0); + +The last argument is 0 for inactive and 1 for active. This way the pin and its +input widget will never be powered up and consume power. + +This also applies to machine widgets. e.g. if a headphone is connected to a +jack then the jack can be marked active. If the headphone is removed, then +the headphone jack can be marked inactive. + + +5 DAPM Widget Events +==================== + +Some widgets can register their interest with the DAPM core in PM events. +e.g. A Speaker with an amplifier registers a widget so the amplifier can be +powered only when the spk is in use. + +/* turn speaker amplifier on/off depending on use */ +static int corgi_amp_event(struct snd_soc_dapm_widget *w, int event) +{ + if (SND_SOC_DAPM_EVENT_ON(event)) + set_scoop_gpio(&corgiscoop_device.dev, CORGI_SCP_APM_ON); + else + reset_scoop_gpio(&corgiscoop_device.dev, CORGI_SCP_APM_ON); + + return 0; +} + +/* corgi machine dapm widgets */ +static const struct snd_soc_dapm_widget wm8731_dapm_widgets = + SND_SOC_DAPM_SPK("Ext Spk", corgi_amp_event); + +Please see soc-dapm.h for all other widgets that support events. + + +5.1 Event types +--------------- + +The following event types are supported by event widgets. + +/* dapm event types */ +#define SND_SOC_DAPM_PRE_PMU 0x1 /* before widget power up */ +#define SND_SOC_DAPM_POST_PMU 0x2 /* after widget power up */ +#define SND_SOC_DAPM_PRE_PMD 0x4 /* before widget power down */ +#define SND_SOC_DAPM_POST_PMD 0x8 /* after widget power down */ +#define SND_SOC_DAPM_PRE_REG 0x10 /* before audio path setup */ +#define SND_SOC_DAPM_POST_REG 0x20 /* after audio path setup */ diff --git a/Documentation/sound/alsa/soc/machine.txt b/Documentation/sound/alsa/soc/machine.txt new file mode 100644 index 0000000..72bd222 --- /dev/null +++ b/Documentation/sound/alsa/soc/machine.txt @@ -0,0 +1,113 @@ +ASoC Machine Driver +=================== + +The ASoC machine (or board) driver is the code that glues together the platform +and codec drivers. + +The machine driver can contain codec and platform specific code. It registers +the audio subsystem with the kernel as a platform device and is represented by +the following struct:- + +/* SoC machine */ +struct snd_soc_machine { + char *name; + + int (*probe)(struct platform_device *pdev); + int (*remove)(struct platform_device *pdev); + + /* the pre and post PM functions are used to do any PM work before and + * after the codec and DAI's do any PM work. */ + int (*suspend_pre)(struct platform_device *pdev, pm_message_t state); + int (*suspend_post)(struct platform_device *pdev, pm_message_t state); + int (*resume_pre)(struct platform_device *pdev); + int (*resume_post)(struct platform_device *pdev); + + /* machine stream operations */ + struct snd_soc_ops *ops; + + /* CPU <--> Codec DAI links */ + struct snd_soc_dai_link *dai_link; + int num_links; +}; + +probe()/remove() +---------------- +probe/remove are optional. Do any machine specific probe here. + + +suspend()/resume() +------------------ +The machine driver has pre and post versions of suspend and resume to take care +of any machine audio tasks that have to be done before or after the codec, DAI's +and DMA is suspended and resumed. Optional. + + +Machine operations +------------------ +The machine specific audio operations can be set here. Again this is optional. + + +Machine DAI Configuration +------------------------- +The machine DAI configuration glues all the codec and CPU DAI's together. It can +also be used to set up the DAI system clock and for any machine related DAI +initialisation e.g. the machine audio map can be connected to the codec audio +map, unconnnected codec pins can be set as such. Please see corgi.c, spitz.c +for examples. + +struct snd_soc_dai_link is used to set up each DAI in your machine. e.g. + +/* corgi digital audio interface glue - connects codec <--> CPU */ +static struct snd_soc_dai_link corgi_dai = { + .name = "WM8731", + .stream_name = "WM8731", + .cpu_dai = &pxa_i2s_dai, + .codec_dai = &wm8731_dai, + .init = corgi_wm8731_init, + .ops = &corgi_ops, +}; + +struct snd_soc_machine then sets up the machine with it's DAI's. e.g. + +/* corgi audio machine driver */ +static struct snd_soc_machine snd_soc_machine_corgi = { + .name = "Corgi", + .dai_link = &corgi_dai, + .num_links = 1, +}; + + +Machine Audio Subsystem +----------------------- + +The machine soc device glues the platform, machine and codec driver together. +Private data can also be set here. e.g. + +/* corgi audio private data */ +static struct wm8731_setup_data corgi_wm8731_setup = { + .i2c_address = 0x1b, +}; + +/* corgi audio subsystem */ +static struct snd_soc_device corgi_snd_devdata = { + .machine = &snd_soc_machine_corgi, + .platform = &pxa2xx_soc_platform, + .codec_dev = &soc_codec_dev_wm8731, + .codec_data = &corgi_wm8731_setup, +}; + + +Machine Power Map +----------------- + +The machine driver can optionally extend the codec power map and to become an +audio power map of the audio subsystem. This allows for automatic power up/down +of speaker/HP amplifiers, etc. Codec pins can be connected to the machines jack +sockets in the machine init function. See soc/pxa/spitz.c and dapm.txt for +details. + + +Machine Controls +---------------- + +Machine specific audio mixer controls can be added in the dai init function. \ No newline at end of file diff --git a/Documentation/sound/alsa/soc/overview.txt b/Documentation/sound/alsa/soc/overview.txt new file mode 100644 index 0000000..753c5cc --- /dev/null +++ b/Documentation/sound/alsa/soc/overview.txt @@ -0,0 +1,83 @@ +ALSA SoC Layer +============== + +The overall project goal of the ALSA System on Chip (ASoC) layer is to provide +better ALSA support for embedded system on chip procesors (e.g. pxa2xx, au1x00, +iMX, etc) and portable audio codecs. Currently there is some support in the +kernel for SoC audio, however it has some limitations:- + + * Currently, codec drivers are often tightly coupled to the underlying SoC + cpu. This is not ideal and leads to code duplication i.e. Linux now has 4 + different wm8731 drivers for 4 different SoC platforms. + + * There is no standard method to signal user initiated audio events. + e.g. Headphone/Mic insertion, Headphone/Mic detection after an insertion + event. These are quite common events on portable devices and ofter require + machine specific code to re route audio, enable amps etc after such an event. + + * Current drivers tend to power up the entire codec when playing + (or recording) audio. This is fine for a PC, but tends to waste a lot of + power on portable devices. There is also no support for saving power via + changing codec oversampling rates, bias currents, etc. + + +ASoC Design +=========== + +The ASoC layer is designed to address these issues and provide the following +features :- + + * Codec independence. Allows reuse of codec drivers on other platforms + and machines. + + * Easy I2S/PCM audio interface setup between codec and SoC. Each SoC interface + and codec registers it's audio interface capabilities with the core and are + subsequently matched and configured when the application hw params are known. + + * Dynamic Audio Power Management (DAPM). DAPM automatically sets the codec to + it's minimum power state at all times. This includes powering up/down + internal power blocks depending on the internal codec audio routing and any + active streams. + + * Pop and click reduction. Pops and clicks can be reduced by powering the + codec up/down in the correct sequence (including using digital mute). ASoC + signals the codec when to change power states. + + * Machine specific controls: Allow machines to add controls to the sound card + e.g. volume control for speaker amp. + +To achieve all this, ASoC basically splits an embedded audio system into 3 +components :- + + * Codec driver: The codec driver is platform independent and contains audio + controls, audio interface capabilities, codec dapm definition and codec IO + functions. + + * Platform driver: The platform driver contains the audio dma engine and audio + interface drivers (e.g. I2S, AC97, PCM) for that platform. + + * Machine driver: The machine driver handles any machine specific controls and + audio events. i.e. turing on an amp at start of playback. + + +Documentation +============= + +The documentation is spilt into the following sections:- + +overview.txt: This file. + +codec.txt: Codec driver internals. + +DAI.txt: Description of Digital Audio Interface standards and how to configure +a DAI within your codec and CPU DAI drivers. + +dapm.txt: Dynamic Audio Power Management + +platform.txt: Platform audio DMA and DAI. + +machine.txt: Machine driver internals. + +pop_clicks.txt: How to minimise audio artifacts. + +clocking.txt: ASoC clocking for best power performance. \ No newline at end of file diff --git a/Documentation/sound/alsa/soc/platform.txt b/Documentation/sound/alsa/soc/platform.txt new file mode 100644 index 0000000..e95b16d --- /dev/null +++ b/Documentation/sound/alsa/soc/platform.txt @@ -0,0 +1,58 @@ +ASoC Platform Driver +==================== + +An ASoC platform driver can be divided into audio DMA and SoC DAI configuration +and control. The platform drivers only target the SoC CPU and must have no board +specific code. + +Audio DMA +========= + +The platform DMA driver optionally supports the following alsa operations:- + +/* SoC audio ops */ +struct snd_soc_ops { + int (*startup)(struct snd_pcm_substream *); + void (*shutdown)(struct snd_pcm_substream *); + int (*hw_params)(struct snd_pcm_substream *, struct snd_pcm_hw_params *); + int (*hw_free)(struct snd_pcm_substream *); + int (*prepare)(struct snd_pcm_substream *); + int (*trigger)(struct snd_pcm_substream *, int); +}; + +The platform driver exports it's DMA functionailty via struct snd_soc_platform:- + +struct snd_soc_platform { + char *name; + + int (*probe)(struct platform_device *pdev); + int (*remove)(struct platform_device *pdev); + int (*suspend)(struct platform_device *pdev, struct snd_soc_cpu_dai *cpu_dai); + int (*resume)(struct platform_device *pdev, struct snd_soc_cpu_dai *cpu_dai); + + /* pcm creation and destruction */ + int (*pcm_new)(struct snd_card *, struct snd_soc_codec_dai *, struct snd_pcm *); + void (*pcm_free)(struct snd_pcm *); + + /* platform stream ops */ + struct snd_pcm_ops *pcm_ops; +}; + +Please refer to the alsa driver documentation for details of audio DMA. +http://www.alsa-project.org/~iwai/writing-an-alsa-driver/c436.htm + +An example DMA driver is soc/pxa/pxa2xx-pcm.c + + +SoC DAI Drivers +=============== + +Each SoC DAI driver must provide the following features:- + + 1) Digital audio interface (DAI) description + 2) Digital audio interface configuration + 3) PCM's description + 4) Sysclk configuration + 5) Suspend and resume (optional) + +Please see codec.txt for a description of items 1 - 4. diff --git a/Documentation/sound/alsa/soc/pops_clicks.txt b/Documentation/sound/alsa/soc/pops_clicks.txt new file mode 100644 index 0000000..2cf7ee5 --- /dev/null +++ b/Documentation/sound/alsa/soc/pops_clicks.txt @@ -0,0 +1,52 @@ +Audio Pops and Clicks +===================== + +Pops and clicks are unwanted audio artifacts caused by the powering up and down +of components within the audio subsystem. This is noticable on PC's when an +audio module is either loaded or unloaded (at module load time the sound card is +powered up and causes a popping noise on the speakers). + +Pops and clicks can be more frequent on portable systems with DAPM. This is +because the components within the subsystem are being dynamically powered +depending on the audio usage and this can subsequently cause a small pop or +click every time a component power state is changed. + + +Minimising Playback Pops and Clicks +=================================== + +Playback pops in portable audio subsystems cannot be completely eliminated atm, +however future audio codec hardware will have better pop and click supression. +Pops can be reduced within playback by powering the audio components in a +specific order. This order is different for startup and shutdown and follows +some basic rules:- + + Startup Order :- DAC --> Mixers --> Output PGA --> Digital Unmute + + Shutdown Order :- Digital Mute --> Output PGA --> Mixers --> DAC + +This assumes that the codec PCM output path from the DAC is via a mixer and then +a PGA (programmable gain amplifier) before being output to the speakers. + + +Minimising Capture Pops and Clicks +================================== + +Capture artifacts are somewhat easier to get rid as we can delay activating the +ADC until all the pops have occured. This follows similar power rules to +playback in that components are powered in a sequence depending upon stream +startup or shutdown. + + Startup Order - Input PGA --> Mixers --> ADC + + Shutdown Order - ADC --> Mixers --> Input PGA + + +Zipper Noise +============ +An unwanted zipper noise can occur within the audio playback or capture stream +when a volume control is changed near its maximum gain value. The zipper noise +is heard when the gain increase or decrease changes the mean audio signal +amplitude too quickly. It can be minimised by enabling the zero cross setting +for each volume control. The ZC forces the gain change to occur when the signal +crosses the zero amplitude line. diff --git a/Documentation/spi/spi-summary b/Documentation/spi/spi-summary index 7279579..ecc7c9e 100644 --- a/Documentation/spi/spi-summary +++ b/Documentation/spi/spi-summary @@ -284,7 +284,6 @@ SPI protocol drivers somewhat resemble p static struct spi_driver CHIP_driver = { .driver = { .name = "CHIP", - .bus = &spi_bus_type, .owner = THIS_MODULE, }, @@ -312,7 +311,7 @@ might look like this unless you're creat chip = kzalloc(sizeof *chip, GFP_KERNEL); if (!chip) return -ENOMEM; - dev_set_drvdata(&spi->dev, chip); + spi_set_drvdata(spi, chip); ... etc return 0; diff --git a/Documentation/sysrq.txt b/Documentation/sysrq.txt index 6161316..452c0f1 100644 --- a/Documentation/sysrq.txt +++ b/Documentation/sysrq.txt @@ -64,11 +64,6 @@ On all - write a character to /proc/sys * What are the 'command' keys? ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -'r' - Turns off keyboard raw mode and sets it to XLATE. - -'k' - Secure Access Key (SAK) Kills all programs on the current virtual - console. NOTE: See important comments below in SAK section. - 'b' - Will immediately reboot the system without syncing or unmounting your disks. @@ -76,21 +71,37 @@ On all - write a character to /proc/sys 'd' - Shows all locks that are held. -'o' - Will shut your system off (if configured and supported). +'e' - Send a SIGTERM to all processes, except for init. -'s' - Will attempt to sync all mounted filesystems. +'f' - Will call oom_kill to kill a memory hog process. -'u' - Will attempt to remount all mounted filesystems read-only. +'g' - Used by kgdb on ppc platforms. -'p' - Will dump the current registers and flags to your console. +'h' - Will display help (actually any other key than those listed + above will display help. but 'h' is easy to remember :-) -'t' - Will dump a list of current tasks and their information to your - console. +'i' - Send a SIGKILL to all processes, except for init. + +'k' - Secure Access Key (SAK) Kills all programs on the current virtual + console. NOTE: See important comments below in SAK section. 'm' - Will dump current memory info to your console. 'n' - Used to make RT tasks nice-able +'o' - Will shut your system off (if configured and supported). + +'p' - Will dump the current registers and flags to your console. + +'r' - Turns off keyboard raw mode and sets it to XLATE. + +'s' - Will attempt to sync all mounted filesystems. + +'t' - Will dump a list of current tasks and their information to your + console. + +'u' - Will attempt to remount all mounted filesystems read-only. + 'v' - Dumps Voyager SMP processor info to your console. 'w' - Dumps tasks that are in uninterruptable (blocked) state. @@ -102,17 +113,6 @@ On all - write a character to /proc/sys it so that only emergency messages like PANICs or OOPSes would make it to your console.) -'f' - Will call oom_kill to kill a memory hog process. - -'e' - Send a SIGTERM to all processes, except for init. - -'g' - Used by kgdb on ppc platforms. - -'i' - Send a SIGKILL to all processes, except for init. - -'h' - Will display help (actually any other key than those listed - above will display help. but 'h' is easy to remember :-) - * Okay, so what can I use them for? ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Well, un'R'aw is very handy when your X server or a svgalib program crashes. diff --git a/Documentation/usb/proc_usb_info.txt b/Documentation/usb/proc_usb_info.txt index 22c5331..077e903 100644 --- a/Documentation/usb/proc_usb_info.txt +++ b/Documentation/usb/proc_usb_info.txt @@ -213,15 +213,16 @@ C:* #Ifs=dd Cfg#=dd Atr=xx MPwr=dddmA Interface descriptor info (can be multiple per Config): -I: If#=dd Alt=dd #EPs=dd Cls=xx(sssss) Sub=xx Prot=xx Driver=ssss -| | | | | | | |__Driver name -| | | | | | | or "(none)" -| | | | | | |__InterfaceProtocol -| | | | | |__InterfaceSubClass -| | | | |__InterfaceClass -| | | |__NumberOfEndpoints -| | |__AlternateSettingNumber -| |__InterfaceNumber +I:* If#=dd Alt=dd #EPs=dd Cls=xx(sssss) Sub=xx Prot=xx Driver=ssss +| | | | | | | | |__Driver name +| | | | | | | | or "(none)" +| | | | | | | |__InterfaceProtocol +| | | | | | |__InterfaceSubClass +| | | | | |__InterfaceClass +| | | | |__NumberOfEndpoints +| | | |__AlternateSettingNumber +| | |__InterfaceNumber +| |__ "*" indicates the active altsetting (others are " ") |__Interface info tag A given interface may have one or more "alternate" settings. @@ -277,7 +278,7 @@ of the USB devices on a system's root hu on how to do this.) The Interface lines can be used to determine what driver is -being used for each device. +being used for each device, and which altsetting it activated. The Configuration lines could be used to list maximum power (in milliamps) that a system's USB devices are using. diff --git a/Documentation/usb/usbmon.txt b/Documentation/usb/usbmon.txt index e65ec82..0f6808a 100644 --- a/Documentation/usb/usbmon.txt +++ b/Documentation/usb/usbmon.txt @@ -77,7 +77,7 @@ that the file size is not excessive for The '1t' type data consists of a stream of events, such as URB submission, URB callback, submission error. Every event is a text line, which consists -of whitespace separated words. The number of position of words may depend +of whitespace separated words. The number or position of words may depend on the event type, but there is a set of words, common for all types. Here is the list of words, from left to right: @@ -170,4 +170,152 @@ dd65f0e8 4128379808 C Bo:005:02 0 31 > * Raw binary format and API -TBD +The overall architecture of the API is about the same as the one above, +only the events are delivered in binary format. Each event is sent in +the following structure (its name is made up, so that we can refer to it): + +struct usbmon_packet { + u64 id; /* 0: URB ID - from submission to callback */ + unsigned char type; /* 8: Same as text; extensible. */ + unsigned char xfer_type; /* ISO (0), Intr, Control, Bulk (3) */ + unsigned char epnum; /* Endpoint number and transfer direction */ + unsigned char devnum; /* Device address */ + u16 busnum; /* 12: Bus number */ + char flag_setup; /* 14: Same as text */ + char flag_data; /* 15: Same as text; Binary zero is OK. */ + s64 ts_sec; /* 16: gettimeofday */ + s32 ts_usec; /* 24: gettimeofday */ + int status; /* 28: */ + unsigned int length; /* 32: Length of data (submitted or actual) */ + unsigned int len_cap; /* 36: Delivered length */ + unsigned char setup[8]; /* 40: Only for Control 'S' */ +}; /* 48 bytes total */ + +These events can be received from a character device by reading with read(2), +with an ioctl(2), or by accessing the buffer with mmap. + +The character device is usually called /dev/usbmonN, where N is the USB bus +number. Number zero (/dev/usbmon0) is special and means "all buses". +However, this feature is not implemented yet. Note that specific naming +policy is set by your Linux distribution. + +If you create /dev/usbmon0 by hand, make sure that it is owned by root +and has mode 0600. Otherwise, unpriviledged users will be able to snoop +keyboard traffic. + +The following ioctl calls are available, with MON_IOC_MAGIC 0x92: + + MON_IOCQ_URB_LEN, defined as _IO(MON_IOC_MAGIC, 1) + +This call returns the length of data in the next event. Note that majority of +events contain no data, so if this call returns zero, it does not mean that +no events are available. + + MON_IOCG_STATS, defined as _IOR(MON_IOC_MAGIC, 3, struct mon_bin_stats) + +The argument is a pointer to the following structure: + +struct mon_bin_stats { + u32 queued; + u32 dropped; +}; + +The member "queued" refers to the number of events currently queued in the +buffer (and not to the number of events processed since the last reset). + +The member "dropped" is the number of events lost since the last call +to MON_IOCG_STATS. + + MON_IOCT_RING_SIZE, defined as _IO(MON_IOC_MAGIC, 4) + +This call sets the buffer size. The argument is the size in bytes. +The size may be rounded down to the next chunk (or page). If the requested +size is out of [unspecified] bounds for this kernel, the call fails with +-EINVAL. + + MON_IOCQ_RING_SIZE, defined as _IO(MON_IOC_MAGIC, 5) + +This call returns the current size of the buffer in bytes. + + MON_IOCX_GET, defined as _IOW(MON_IOC_MAGIC, 6, struct mon_get_arg) + +This call waits for events to arrive if none were in the kernel buffer, +then returns the first event. Its argument is a pointer to the following +structure: + +struct mon_get_arg { + struct usbmon_packet *hdr; + void *data; + size_t alloc; /* Length of data (can be zero) */ +}; + +Before the call, hdr, data, and alloc should be filled. Upon return, the area +pointed by hdr contains the next event structure, and the data buffer contains +the data, if any. The event is removed from the kernel buffer. + + MON_IOCX_MFETCH, defined as _IOWR(MON_IOC_MAGIC, 7, struct mon_mfetch_arg) + +This ioctl is primarily used when the application accesses the buffer +with mmap(2). Its argument is a pointer to the following structure: + +struct mon_mfetch_arg { + uint32_t *offvec; /* Vector of events fetched */ + uint32_t nfetch; /* Number of events to fetch (out: fetched) */ + uint32_t nflush; /* Number of events to flush */ +}; + +The ioctl operates in 3 stages. + +First, it removes and discards up to nflush events from the kernel buffer. +The actual number of events discarded is returned in nflush. + +Second, it waits for an event to be present in the buffer, unless the pseudo- +device is open with O_NONBLOCK. + +Third, it extracts up to nfetch offsets into the mmap buffer, and stores +them into the offvec. The actual number of event offsets is stored into +the nfetch. + + MON_IOCH_MFLUSH, defined as _IO(MON_IOC_MAGIC, 8) + +This call removes a number of events from the kernel buffer. Its argument +is the number of events to remove. If the buffer contains fewer events +than requested, all events present are removed, and no error is reported. +This works when no events are available too. + + FIONBIO + +The ioctl FIONBIO may be implemented in the future, if there's a need. + +In addition to ioctl(2) and read(2), the special file of binary API can +be polled with select(2) and poll(2). But lseek(2) does not work. + +* Memory-mapped access of the kernel buffer for the binary API + +The basic idea is simple: + +To prepare, map the buffer by getting the current size, then using mmap(2). +Then, execute a loop similar to the one written in pseudo-code below: + + struct mon_mfetch_arg fetch; + struct usbmon_packet *hdr; + int nflush = 0; + for (;;) { + fetch.offvec = vec; // Has N 32-bit words + fetch.nfetch = N; // Or less than N + fetch.nflush = nflush; + ioctl(fd, MON_IOCX_MFETCH, &fetch); // Process errors, too + nflush = fetch.nfetch; // This many packets to flush when done + for (i = 0; i < nflush; i++) { + hdr = (struct ubsmon_packet *) &mmap_area[vec[i]]; + if (hdr->type == '@') // Filler packet + continue; + caddr_t data = &mmap_area[vec[i]] + 64; + process_packet(hdr, data); + } + } + +Thus, the main idea is to execute only one ioctl per N events. + +Although the buffer is circular, the returned headers and data do not cross +the end of the buffer, so the above pseudo-code does not need any gathering. diff --git a/Documentation/video-output.txt b/Documentation/video-output.txt new file mode 100644 index 0000000..e517011 --- /dev/null +++ b/Documentation/video-output.txt @@ -0,0 +1,34 @@ + + Video Output Switcher Control + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + 2006 luming.yu@intel.com + +The output sysfs class driver provides an abstract video output layer that +can be used to hook platform specific methods to enable/disable video output +device through common sysfs interface. For example, on my IBM ThinkPad T42 +laptop, The ACPI video driver registered its output devices and read/write +method for 'state' with output sysfs class. The user interface under sysfs is: + +linux:/sys/class/video_output # tree . +. +|-- CRT0 +| |-- device -> ../../../devices/pci0000:00/0000:00:01.0 +| |-- state +| |-- subsystem -> ../../../class/video_output +| `-- uevent +|-- DVI0 +| |-- device -> ../../../devices/pci0000:00/0000:00:01.0 +| |-- state +| |-- subsystem -> ../../../class/video_output +| `-- uevent +|-- LCD0 +| |-- device -> ../../../devices/pci0000:00/0000:00:01.0 +| |-- state +| |-- subsystem -> ../../../class/video_output +| `-- uevent +`-- TV0 + |-- device -> ../../../devices/pci0000:00/0000:00:01.0 + |-- state + |-- subsystem -> ../../../class/video_output + `-- uevent + diff --git a/Documentation/x86_64/boot-options.txt b/Documentation/x86_64/boot-options.txt index 5c86ed6..625a21d 100644 --- a/Documentation/x86_64/boot-options.txt +++ b/Documentation/x86_64/boot-options.txt @@ -180,40 +180,81 @@ PCI pci=lastbus=NUMBER Scan upto NUMBER busses, no matter what the mptable says. pci=noacpi Don't use ACPI to set up PCI interrupt routing. -IOMMU - - iommu=[size][,noagp][,off][,force][,noforce][,leak][,memaper[=order]][,merge] - [,forcesac][,fullflush][,nomerge][,noaperture][,calgary] - size set size of iommu (in bytes) - noagp don't initialize the AGP driver and use full aperture. - off don't use the IOMMU - leak turn on simple iommu leak tracing (only when CONFIG_IOMMU_LEAK is on) - memaper[=order] allocate an own aperture over RAM with size 32MB^order. - noforce don't force IOMMU usage. Default. - force Force IOMMU. - merge Do SG merging. Implies force (experimental) - nomerge Don't do SG merging. - forcesac For SAC mode for masks <40bits (experimental) - fullflush Flush IOMMU on each allocation (default) - nofullflush Don't use IOMMU fullflush - allowed overwrite iommu off workarounds for specific chipsets. - soft Use software bounce buffering (default for Intel machines) - noaperture Don't touch the aperture for AGP. - allowdac Allow DMA >4GB - When off all DMA over >4GB is forced through an IOMMU or bounce - buffering. - nodac Forbid DMA >4GB - panic Always panic when IOMMU overflows - calgary Use the Calgary IOMMU if it is available - - swiotlb=pages[,force] - - pages Prereserve that many 128K pages for the software IO bounce buffering. - force Force all IO through the software TLB. - - calgary=[64k,128k,256k,512k,1M,2M,4M,8M] - calgary=[translate_empty_slots] - calgary=[disable=] +IOMMU (input/output memory management unit) + + Currently four x86-64 PCI-DMA mapping implementations exist: + + 1. : use no hardware/software IOMMU at all + (e.g. because you have < 3 GB memory). + Kernel boot message: "PCI-DMA: Disabling IOMMU" + + 2. : AMD GART based hardware IOMMU. + Kernel boot message: "PCI-DMA: using GART IOMMU" + + 3. : Software IOMMU implementation. Used + e.g. if there is no hardware IOMMU in the system and it is need because + you have >3GB memory or told the kernel to us it (iommu=soft)) + Kernel boot message: "PCI-DMA: Using software bounce buffering + for IO (SWIOTLB)" + + 4. : IBM Calgary hardware IOMMU. Used in IBM + pSeries and xSeries servers. This hardware IOMMU supports DMA address + mapping with memory protection, etc. + Kernel boot message: "PCI-DMA: Using Calgary IOMMU" + + iommu=[][,noagp][,off][,force][,noforce][,leak[=] + [,memaper[=]][,merge][,forcesac][,fullflush][,nomerge] + [,noaperture][,calgary] + + General iommu options: + off Don't initialize and use any kind of IOMMU. + noforce Don't force hardware IOMMU usage when it is not needed. + (default). + force Force the use of the hardware IOMMU even when it is + not actually needed (e.g. because < 3 GB memory). + soft Use software bounce buffering (SWIOTLB) (default for + Intel machines). This can be used to prevent the usage + of an available hardware IOMMU. + + iommu options only relevant to the AMD GART hardware IOMMU: + Set the size of the remapping area in bytes. + allowed Overwrite iommu off workarounds for specific chipsets. + fullflush Flush IOMMU on each allocation (default). + nofullflush Don't use IOMMU fullflush. + leak Turn on simple iommu leak tracing (only when + CONFIG_IOMMU_LEAK is on). Default number of leak pages + is 20. + memaper[=] Allocate an own aperture over RAM with size 32MB<4GB. + DAC is used with 32-bit PCI to push a 64-bit address in + two cycles. When off all DMA over >4GB is forced through + an IOMMU or software bounce buffering. + nodac Forbid DAC mode, i.e. DMA >4GB. + panic Always panic when IOMMU overflows. + calgary Use the Calgary IOMMU if it is available + + iommu options only relevant to the software bounce buffering (SWIOTLB) IOMMU + implementation: + swiotlb=[,force] + Prereserve that many 128K pages for the software IO + bounce buffering. + force Force all IO through the software TLB. + + Settings for the IBM Calgary hardware IOMMU currently found in IBM + pSeries and xSeries machines: + + calgary=[64k,128k,256k,512k,1M,2M,4M,8M] + calgary=[translate_empty_slots] + calgary=[disable=] + panic Always panic when IOMMU overflows 64k,...,8M - Set the size of each PCI slot's translation table when using the Calgary IOMMU. This is the size of the translation @@ -234,14 +275,14 @@ IOMMU Debugging - oops=panic Always panic on oopses. Default is to just kill the process, - but there is a small probability of deadlocking the machine. - This will also cause panics on machine check exceptions. - Useful together with panic=30 to trigger a reboot. + oops=panic Always panic on oopses. Default is to just kill the process, + but there is a small probability of deadlocking the machine. + This will also cause panics on machine check exceptions. + Useful together with panic=30 to trigger a reboot. - kstack=N Print that many words from the kernel stack in oops dumps. + kstack=N Print N words from the kernel stack in oops dumps. - pagefaulttrace Dump all page faults. Only useful for extreme debugging + pagefaulttrace Dump all page faults. Only useful for extreme debugging and will create a lot of output. call_trace=[old|both|newfallback|new] @@ -251,15 +292,8 @@ Debugging newfallback: use new unwinder but fall back to old if it gets stuck (default) - call_trace=[old|both|newfallback|new] - old: use old inexact backtracer - new: use new exact dwarf2 unwinder - both: print entries from both - newfallback: use new unwinder but fall back to old if it gets - stuck (default) - -Misc +Miscellaneous noreplacement Don't replace instructions with more appropriate ones for the CPU. This may be useful on asymmetric MP systems - where some CPU have less capabilities than the others. + where some CPUs have less capabilities than others. diff --git a/Documentation/x86_64/cpu-hotplug-spec b/Documentation/x86_64/cpu-hotplug-spec index 5c0fa34..3c23e05 100644 --- a/Documentation/x86_64/cpu-hotplug-spec +++ b/Documentation/x86_64/cpu-hotplug-spec @@ -2,7 +2,7 @@ Firmware support for CPU hotplug under L --------------------------------------------------- Linux/x86-64 supports CPU hotplug now. For various reasons Linux wants to -know in advance boot time the maximum number of CPUs that could be plugged +know in advance of boot time the maximum number of CPUs that could be plugged into the system. ACPI 3.0 currently has no official way to supply this information from the firmware to the operating system. diff --git a/Documentation/x86_64/kernel-stacks b/Documentation/x86_64/kernel-stacks index bddfddd..5ad65d5 100644 --- a/Documentation/x86_64/kernel-stacks +++ b/Documentation/x86_64/kernel-stacks @@ -9,9 +9,9 @@ zombie. While the thread is in user spac except for the thread_info structure at the bottom. In addition to the per thread stacks, there are specialized stacks -associated with each cpu. These stacks are only used while the kernel -is in control on that cpu, when a cpu returns to user space the -specialized stacks contain no useful data. The main cpu stacks is +associated with each CPU. These stacks are only used while the kernel +is in control on that CPU; when a CPU returns to user space the +specialized stacks contain no useful data. The main CPU stacks are: * Interrupt stack. IRQSTACKSIZE @@ -32,17 +32,17 @@ x86_64 also has a feature which is not a to automatically switch to a new stack for designated events such as double fault or NMI, which makes it easier to handle these unusual events on x86_64. This feature is called the Interrupt Stack Table -(IST). There can be up to 7 IST entries per cpu. The IST code is an -index into the Task State Segment (TSS), the IST entries in the TSS -point to dedicated stacks, each stack can be a different size. +(IST). There can be up to 7 IST entries per CPU. The IST code is an +index into the Task State Segment (TSS). The IST entries in the TSS +point to dedicated stacks; each stack can be a different size. -An IST is selected by an non-zero value in the IST field of an +An IST is selected by a non-zero value in the IST field of an interrupt-gate descriptor. When an interrupt occurs and the hardware loads such a descriptor, the hardware automatically sets the new stack pointer based on the IST value, then invokes the interrupt handler. If software wants to allow nested IST interrupts then the handler must adjust the IST values on entry to and exit from the interrupt handler. -(this is occasionally done, e.g. for debug exceptions) +(This is occasionally done, e.g. for debug exceptions.) Events with different IST codes (i.e. with different stacks) can be nested. For example, a debug interrupt can safely be interrupted by an @@ -58,17 +58,17 @@ The currently assigned IST stacks are :- Used for interrupt 12 - Stack Fault Exception (#SS). - This allows to recover from invalid stack segments. Rarely + This allows the CPU to recover from invalid stack segments. Rarely happens. * DOUBLEFAULT_STACK. EXCEPTION_STKSZ (PAGE_SIZE). Used for interrupt 8 - Double Fault Exception (#DF). - Invoked when handling a exception causes another exception. Happens - when the kernel is very confused (e.g. kernel stack pointer corrupt) - Using a separate stack allows to recover from it well enough in many - cases to still output an oops. + Invoked when handling one exception causes another exception. Happens + when the kernel is very confused (e.g. kernel stack pointer corrupt). + Using a separate stack allows the kernel to recover from it well enough + in many cases to still output an oops. * NMI_STACK. EXCEPTION_STKSZ (PAGE_SIZE). diff --git a/Documentation/x86_64/machinecheck b/Documentation/x86_64/machinecheck new file mode 100644 index 0000000..068a6d9 --- /dev/null +++ b/Documentation/x86_64/machinecheck @@ -0,0 +1,70 @@ + +Configurable sysfs parameters for the x86-64 machine check code. + +Machine checks report internal hardware error conditions detected +by the CPU. Uncorrected errors typically cause a machine check +(often with panic), corrected ones cause a machine check log entry. + +Machine checks are organized in banks (normally associated with +a hardware subsystem) and subevents in a bank. The exact meaning +of the banks and subevent is CPU specific. + +mcelog knows how to decode them. + +When you see the "Machine check errors logged" message in the system +log then mcelog should run to collect and decode machine check entries +from /dev/mcelog. Normally mcelog should be run regularly from a cronjob. + +Each CPU has a directory in /sys/devices/system/machinecheck/machinecheckN +(N = CPU number) + +The directory contains some configurable entries: + +Entries: + +bankNctl +(N bank number) + 64bit Hex bitmask enabling/disabling specific subevents for bank N + When a bit in the bitmask is zero then the respective + subevent will not be reported. + By default all events are enabled. + Note that BIOS maintain another mask to disable specific events + per bank. This is not visible here + +The following entries appear for each CPU, but they are truly shared +between all CPUs. + +check_interval + How often to poll for corrected machine check errors, in seconds + (Note output is hexademical). Default 5 minutes. + +tolerant + Tolerance level. When a machine check exception occurs for a non + corrected machine check the kernel can take different actions. + Since machine check exceptions can happen any time it is sometimes + risky for the kernel to kill a process because it defies + normal kernel locking rules. The tolerance level configures + how hard the kernel tries to recover even at some risk of deadlock. + + 0: always panic, + 1: panic if deadlock possible, + 2: try to avoid panic, + 3: never panic or exit (for testing only) + + Default: 1 + + Note this only makes a difference if the CPU allows recovery + from a machine check exception. Current x86 CPUs generally do not. + +trigger + Program to run when a machine check event is detected. + This is an alternative to running mcelog regularly from cron + and allows to detect events faster. + +TBD document entries for AMD threshold interrupt configuration + +For more details about the x86 machine check architecture +see the Intel and AMD architecture manuals from their developer websites. + +For more details about the architecture see +see http://one.firstfloor.org/~andi/mce.pdf diff --git a/Documentation/x86_64/mm.txt b/Documentation/x86_64/mm.txt index 133561b..f42798e 100644 --- a/Documentation/x86_64/mm.txt +++ b/Documentation/x86_64/mm.txt @@ -3,26 +3,26 @@ Virtual memory map with 4 level page tables: -0000000000000000 - 00007fffffffffff (=47bits) user space, different per mm +0000000000000000 - 00007fffffffffff (=47 bits) user space, different per mm hole caused by [48:63] sign extension -ffff800000000000 - ffff80ffffffffff (=40bits) guard hole -ffff810000000000 - ffffc0ffffffffff (=46bits) direct mapping of all phys. memory -ffffc10000000000 - ffffc1ffffffffff (=40bits) hole -ffffc20000000000 - ffffe1ffffffffff (=45bits) vmalloc/ioremap space +ffff800000000000 - ffff80ffffffffff (=40 bits) guard hole +ffff810000000000 - ffffc0ffffffffff (=46 bits) direct mapping of all phys. memory +ffffc10000000000 - ffffc1ffffffffff (=40 bits) hole +ffffc20000000000 - ffffe1ffffffffff (=45 bits) vmalloc/ioremap space ... unused hole ... -ffffffff80000000 - ffffffff82800000 (=40MB) kernel text mapping, from phys 0 +ffffffff80000000 - ffffffff82800000 (=40 MB) kernel text mapping, from phys 0 ... unused hole ... -ffffffff88000000 - fffffffffff00000 (=1919MB) module mapping space +ffffffff88000000 - fffffffffff00000 (=1919 MB) module mapping space -The direct mapping covers all memory in the system upto the highest +The direct mapping covers all memory in the system up to the highest memory address (this means in some cases it can also include PCI memory -holes) +holes). vmalloc space is lazily synchronized into the different PML4 pages of the processes using the page fault handler, with init_level4_pgt as reference. -Current X86-64 implementations only support 40 bit of address space, -but we support upto 46bits. This expands into MBZ space in the page tables. +Current X86-64 implementations only support 40 bits of address space, +but we support up to 46 bits. This expands into MBZ space in the page tables. -Andi Kleen, Jul 2004 diff --git a/MAINTAINERS b/MAINTAINERS index 0ad8803..b0fd71b 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -584,12 +584,30 @@ W: http://sourceforge.net/projects/acpi4 W: http://xf.iksaif.net/acpi4asus S: Maintained +ASUS LAPTOP EXTRAS DRIVER +P: Corentin Chary +M: corentincj@iksaif.net +L: acpi4asus-user@lists.sourceforge.net +W: http://sourceforge.net/projects/acpi4asus +W: http://xf.iksaif.net/acpi4asus +S: Maintained + ATA OVER ETHERNET DRIVER P: Ed L. Cashin M: ecashin@coraid.com W: http://www.coraid.com/support/linux S: Supported +ATL1 ETHERNET DRIVER +P: Jay Cliburn +M: jcliburn@gmail.com +P: Chris Snook +M: csnook@redhat.com +L: atl1-devel@lists.sourceforge.net +W: http://sourceforge.net/projects/atl1 +W: http://atl1.sourceforge.net +S: Maintained + ATM P: Chas Williams M: chas@cmf.nrl.navy.mil @@ -602,6 +620,11 @@ P: Haavard Skinnemoen M: hskinnemoen@atmel.com S: Supported +ATMEL SPI DRIVER +P: Haavard Skinnemoen +M: hskinnemoen@atmel.com +S: Supported + ATMEL WIRELESS DRIVER P: Simon Kelley M: simon@thekelleys.org.uk @@ -617,6 +640,12 @@ W: http://people.redhat.com/sgrubb/audit T: git kernel.org:/pub/scm/linux/kernel/git/dwmw2/audit-2.6.git S: Maintained +AUXILIARY DISPLAY DRIVERS +P: Miguel Ojeda Sandonis +M: maxextreme@gmail.com +L: linux-kernel@vger.kernel.org +S: Maintained + AVR32 ARCHITECTURE P: Haavard Skinnemoen M: hskinnemoen@atmel.com @@ -818,6 +847,18 @@ L: linux-kernel@vger.kernel.org L: discuss@x86-64.org S: Maintained +CFAG12864B LCD DRIVER +P: Miguel Ojeda Sandonis +M: maxextreme@gmail.com +L: linux-kernel@vger.kernel.org +S: Maintained + +CFAG12864BFB LCD FRAMEBUFFER DRIVER +P: Miguel Ojeda Sandonis +M: maxextreme@gmail.com +L: linux-kernel@vger.kernel.org +S: Maintained + COMMON INTERNET FILE SYSTEM (CIFS) P: Steve French M: sfrench@samba.org @@ -966,14 +1007,12 @@ L: cycsyn-devel@bazar.conectiva.com.br S: Maintained CYCLADES ASYNC MUX DRIVER -M: async@cyclades.com W: http://www.cyclades.com/ -S: Supported +S: Orphan CYCLADES PC300 DRIVER -M: pc300@cyclades.com W: http://www.cyclades.com/ -S: Supported +S: Orphan DAMA SLAVE for AX.25 P: Joerg Reuter @@ -1096,7 +1135,7 @@ S: Supported DAVICOM FAST ETHERNET (DMFE) NETWORK DRIVER P: Tobias Ringstrom M: tori@unhappy.mine.nu -L: linux-kernel@vger.kernel.org +L: netdev@vger.kernel.org S: Maintained DOCBOOK FOR DOCUMENTATION @@ -1953,6 +1992,12 @@ M: davem@davemloft.net L: linux-kernel@vger.kernel.org S: Maintained +KS0108 LCD CONTROLLER DRIVER +P: Miguel Ojeda Sandonis +M: maxextreme@gmail.com +L: linux-kernel@vger.kernel.org +S: Maintained + LAPB module L: linux-x25@vger.kernel.org S: Orphan @@ -2343,7 +2388,7 @@ S: Maintained NETWORKING [WIRELESS] P: John W. Linville M: linville@tuxdriver.com -L: netdev@vger.kernel.org +L: linux-wireless@vger.kernel.org T: git kernel.org:/pub/scm/linux/kernel/git/linville/wireless-2.6.git S: Maintained @@ -2477,6 +2522,18 @@ L: orinoco-devel@lists.sourceforge.net W: http://www.nongnu.org/orinoco/ S: Maintained +PA SEMI ETHERNET DRIVER +P: Olof Johansson +M: olof@lixom.net +L: netdev@vger.kernel.org +S: Maintained + +PA SEMI SMBUS DRIVER +P: Olof Johansson +M: olof@lixom.net +L: i2c@lm-sensors.org +S: Maintained + PARALLEL PORT SUPPORT P: Phil Blundell M: philb@gnu.org @@ -2646,7 +2703,7 @@ S: Supported PRISM54 WIRELESS DRIVER P: Prism54 Development Team -M: prism54-private@prism54.org +M: developers@islsm.org L: netdev@vger.kernel.org W: http://prism54.org S: Maintained @@ -2791,7 +2848,7 @@ M: schwidefsky@de.ibm.com P: Heiko Carstens M: heiko.carstens@de.ibm.com M: linux390@de.ibm.com -L: linux-390@vm.marist.edu +L: linux-s390@vger.kernel.org W: http://www.ibm.com/developerworks/linux/linux390/ S: Supported @@ -2799,7 +2856,7 @@ S390 NETWORK DRIVERS P: Frank Pavlic M: fpavlic@de.ibm.com M: linux390@de.ibm.com -L: linux-390@vm.marist.edu +L: linux-s390@vger.kernel.org W: http://www.ibm.com/developerworks/linux/linux390/ S: Supported @@ -2807,7 +2864,7 @@ S390 ZFCP DRIVER P: Swen Schillig M: swen@vnet.ibm.com M: linux390@de.ibm.com -L: linux-390@vm.marist.edu +L: linux-s390@vger.kernel.org W: http://www.ibm.com/developerworks/linux/linux390/ S: Supported @@ -3013,6 +3070,12 @@ M: perex@suse.cz L: alsa-devel@alsa-project.org S: Maintained +SOUND - SOC LAYER / DYNAMIC AUDIO POWER MANAGEMENT +P: Liam Girdwood +M: liam.girdwood@wolfsonmicro.com +L: alsa-devel@alsa-project.org +S: Supported + SPI SUBSYSTEM P: David Brownell M: dbrownell@users.sourceforge.net @@ -3263,6 +3326,11 @@ L: vtun@office.satix.net W: http://vtun.sourceforge.net/tun S: Maintained +TURBOCHANNEL SUBSYSTEM +P: Maciej W. Rozycki +M: macro@linux-mips.org +S: Maintained + U14-34F SCSI DRIVER P: Dario Ballabio M: ballabio_dario@emc.com @@ -3647,7 +3715,7 @@ S: Maintained W83L51xD SD/MMC CARD INTERFACE DRIVER P: Pierre Ossman M: drzeus-wbsd@drzeus.cx -L: wbsd-devel@list.drzeus.cx +L: linux-kernel@vger.kernel.org W: http://projects.drzeus.cx/wbsd S: Maintained @@ -3711,6 +3779,7 @@ P: Andi Kleen M: ak@suse.de L: discuss@x86-64.org W: http://www.x86-64.org +T: quilt ftp://ftp.firstfloor.org/pub/ak/x86_64/quilt-current S: Maintained YAM DRIVER FOR AX.25 diff --git a/Makefile b/Makefile index 7e2750f..b6c8790 100644 --- a/Makefile +++ b/Makefile @@ -776,7 +776,7 @@ # $(SUBLEVEL) eg, 18 # $(EXTRAVERSION) eg, -rc6 # $(localver-full) # $(localver) -# localversion* (all localversion* files) +# localversion* (files without backups, containing '~') # $(CONFIG_LOCALVERSION) (from kernel config setting) # $(localver-auto) (only if CONFIG_LOCALVERSION_AUTO is set) # ./scripts/setlocalversion (SCM tag, if one exists) @@ -787,17 +787,12 @@ # kernel config option CONFIG_LOCALVERSI # moment, only git is supported but other SCMs can edit the script # scripts/setlocalversion and add the appropriate checks as needed. -nullstring := -space := $(nullstring) # end of line +pattern = ".*/localversion[^~]*" +string = $(shell cat /dev/null \ + `find $(objtree) $(srctree) -maxdepth 1 -regex $(pattern) | sort -u`) -___localver = $(objtree)/localversion* $(srctree)/localversion* -__localver = $(sort $(wildcard $(___localver))) -# skip backup files (containing '~') -_localver = $(foreach f, $(__localver), $(if $(findstring ~, $(f)),,$(f))) - -localver = $(subst $(space),, \ - $(shell cat /dev/null $(_localver)) \ - $(patsubst "%",%,$(CONFIG_LOCALVERSION))) +localver = $(subst $(space),, $(string) \ + $(patsubst "%",%,$(CONFIG_LOCALVERSION))) # If CONFIG_LOCALVERSION_AUTO is set scripts/setlocalversion is called # and if the SCM is know a tag from the SCM is appended. @@ -830,9 +825,6 @@ # version.h and scripts_basic is process # Listed in dependency order PHONY += prepare archprepare prepare0 prepare1 prepare2 prepare3 -# prepare-all is deprecated, use prepare as valid replacement -PHONY += prepare-all - # prepare3 is used to check if we are building in a separate output directory, # and if so do: # 1) Check that make has not been executed in the kernel src $(srctree) @@ -865,7 +857,7 @@ prepare0: archprepare FORCE $(Q)$(MAKE) $(build)=. # All the preparing.. -prepare prepare-all: prepare0 +prepare: prepare0 # Leave this as default for preprocessing vmlinux.lds.S, which is now # done in arch/$(ARCH)/kernel/Makefile @@ -936,6 +928,12 @@ headers_install: include/linux/version.h $(Q)$(MAKE) $(build)=scripts scripts/unifdef $(Q)$(MAKE) -f $(srctree)/scripts/Makefile.headersinst obj=include +PHONY += headers_check_all +headers_check_all: headers_install_all + $(Q)for arch in $(HDRARCHES); do \ + $(MAKE) ARCH=$$arch -f $(srctree)/scripts/Makefile.headersinst obj=include BIASMDIR=-bi-$$arch HDRCHECK=1 ;\ + done + PHONY += headers_check headers_check: headers_install $(Q)$(MAKE) -f $(srctree)/scripts/Makefile.headersinst obj=include HDRCHECK=1 diff --git a/arch/alpha/Kconfig b/arch/alpha/Kconfig index 84caf50..770f717 100644 --- a/arch/alpha/Kconfig +++ b/arch/alpha/Kconfig @@ -41,6 +41,10 @@ config GENERIC_CALIBRATE_DELAY bool default y +config ZONE_DMA + bool + default y + config GENERIC_ISA_DMA bool default y diff --git a/arch/alpha/kernel/pci.c b/arch/alpha/kernel/pci.c index 3c10b9a..ab642a4 100644 --- a/arch/alpha/kernel/pci.c +++ b/arch/alpha/kernel/pci.c @@ -575,3 +575,7 @@ void pci_iounmap(struct pci_dev *dev, vo EXPORT_SYMBOL(pci_iomap); EXPORT_SYMBOL(pci_iounmap); + +/* FIXME: Some boxes have multiple ISA bridges! */ +struct pci_dev *isa_bridge; +EXPORT_SYMBOL(isa_bridge); diff --git a/arch/alpha/kernel/setup.c b/arch/alpha/kernel/setup.c index 1aea7c7..d352c2b 100644 --- a/arch/alpha/kernel/setup.c +++ b/arch/alpha/kernel/setup.c @@ -122,7 +122,7 @@ static void get_sysnames(unsigned long, char **, char **); static void determine_cpu_caches (unsigned int); -static char command_line[COMMAND_LINE_SIZE]; +static char __initdata command_line[COMMAND_LINE_SIZE]; /* * The format of "screen_info" is strange, and due to early @@ -547,7 +547,7 @@ #endif } else { strlcpy(command_line, COMMAND_LINE, sizeof command_line); } - strcpy(saved_command_line, command_line); + strcpy(boot_command_line, command_line); *cmdline_p = command_line; /* @@ -589,7 +589,7 @@ #endif } /* Replace the command line, now that we've killed it with strsep. */ - strcpy(command_line, saved_command_line); + strcpy(command_line, boot_command_line); /* If we want SRM console printk echoing early, do it now. */ if (alpha_using_srm && srmcons_output) { diff --git a/arch/alpha/kernel/time.c b/arch/alpha/kernel/time.c index d7053eb..4748e14 100644 --- a/arch/alpha/kernel/time.c +++ b/arch/alpha/kernel/time.c @@ -91,17 +91,6 @@ static inline __u32 rpcc(void) } /* - * Scheduler clock - returns current time in nanosec units. - * - * Copied from ARM code for expediency... ;-} - */ -unsigned long long sched_clock(void) -{ - return (unsigned long long)jiffies * (1000000000 / HZ); -} - - -/* * timer_interrupt() needs to keep up the real-time clock, * as well as call the "do_timer()" routine every clocktick */ diff --git a/arch/alpha/kernel/vmlinux.lds.S b/arch/alpha/kernel/vmlinux.lds.S index 76bf071..4cc44bd 100644 --- a/arch/alpha/kernel/vmlinux.lds.S +++ b/arch/alpha/kernel/vmlinux.lds.S @@ -52,10 +52,12 @@ #endif } __initcall_end = .; +#ifdef CONFIG_BLK_DEV_INITRD . = ALIGN(8192); __initramfs_start = .; .init.ramfs : { *(.init.ramfs) } __initramfs_end = .; +#endif . = ALIGN(8); .con_initcall.init : { diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig index 6783c2e..5c79519 100644 --- a/arch/arm/Kconfig +++ b/arch/arm/Kconfig @@ -9,6 +9,7 @@ config ARM bool default y select RTC_LIB + select SYS_SUPPORTS_APM_EMULATION help The ARM series is a line of low-power-consumption RISC chip designs licensed by ARM Ltd and targeted at embedded applications and @@ -17,6 +18,9 @@ config ARM Europe. There is an ARM Linux project with a web page at . +config SYS_SUPPORTS_APM_EMULATION + bool + config GENERIC_TIME bool default n @@ -25,6 +29,10 @@ config MMU bool default y +config NO_IOPORT + bool + default n + config EISA bool ---help--- @@ -96,6 +104,10 @@ config GENERIC_BUST_SPINLOCK config ARCH_MAY_HAVE_PC_FDC bool +config ZONE_DMA + bool + default y + config GENERIC_ISA_DMA bool @@ -290,6 +302,7 @@ config ARCH_RPC select TIMER_ACORN select ARCH_MAY_HAVE_PC_FDC select ISA_DMA_API + select NO_IOPORT help On the Acorn Risc-PC, Linux can support the internal IDE disk and CD-ROM interface, serial and parallel port, and the floppy drive. @@ -856,31 +869,6 @@ menu "Power management options" source "kernel/power/Kconfig" -config APM - tristate "Advanced Power Management Emulation" - ---help--- - APM is a BIOS specification for saving power using several different - techniques. This is mostly useful for battery powered laptops with - APM compliant BIOSes. If you say Y here, the system time will be - reset after a RESUME operation, the /proc/apm device will provide - battery status information, and user-space programs will receive - notification of APM "events" (e.g. battery status change). - - In order to use APM, you will need supporting software. For location - and more information, read and the - Battery Powered Linux mini-HOWTO, available from - . - - This driver does not spin down disk drives (see the hdparm(8) - manpage ("man 8 hdparm") for that), and it doesn't turn off - VESA-compliant "green" monitors. - - Generally, if you don't have a battery in your machine, there isn't - much point in using this driver and you should say N. If you get - random kernel OOPSes or reboots that don't seem to be related to - anything, try disabling/enabling this option (or disabling/enabling - APM in your BIOS). - endmenu source "net/Kconfig" diff --git a/arch/arm/common/rtctime.c b/arch/arm/common/rtctime.c index 4e5445c..bf1075e 100644 --- a/arch/arm/common/rtctime.c +++ b/arch/arm/common/rtctime.c @@ -329,7 +329,7 @@ static int rtc_fasync(int fd, struct fil return fasync_helper(fd, file, on, &rtc_async_queue); } -static struct file_operations rtc_fops = { +static const struct file_operations rtc_fops = { .owner = THIS_MODULE, .llseek = no_llseek, .read = rtc_read, diff --git a/arch/arm/common/sharpsl_pm.c b/arch/arm/common/sharpsl_pm.c index b359974..a3b450f 100644 --- a/arch/arm/common/sharpsl_pm.c +++ b/arch/arm/common/sharpsl_pm.c @@ -27,7 +27,7 @@ #include #include #include #include -#include +#include #include #include #include diff --git a/arch/arm/kernel/Makefile b/arch/arm/kernel/Makefile index ab06a86..1b935fb 100644 --- a/arch/arm/kernel/Makefile +++ b/arch/arm/kernel/Makefile @@ -10,7 +10,6 @@ obj-y := compat.o entry-armv.o entry-co process.o ptrace.o semaphore.o setup.o signal.o sys_arm.o \ time.o traps.o -obj-$(CONFIG_APM) += apm.o obj-$(CONFIG_ISA_DMA_API) += dma.o obj-$(CONFIG_ARCH_ACORN) += ecard.o obj-$(CONFIG_FIQ) += fiq.o diff --git a/arch/arm/kernel/apm.c b/arch/arm/kernel/apm.c deleted file mode 100644 index 2c37b70..0000000 --- a/arch/arm/kernel/apm.c +++ /dev/null @@ -1,672 +0,0 @@ -/* - * bios-less APM driver for ARM Linux - * Jamey Hicks - * adapted from the APM BIOS driver for Linux by Stephen Rothwell (sfr@linuxcare.com) - * - * APM 1.2 Reference: - * Intel Corporation, Microsoft Corporation. Advanced Power Management - * (APM) BIOS Interface Specification, Revision 1.2, February 1996. - * - * [This document is available from Microsoft at: - * http://www.microsoft.com/hwdev/busbios/amp_12.htm] - */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include /* apm_power_info */ -#include - -/* - * The apm_bios device is one of the misc char devices. - * This is its minor number. - */ -#define APM_MINOR_DEV 134 - -/* - * See Documentation/Config.help for the configuration options. - * - * Various options can be changed at boot time as follows: - * (We allow underscores for compatibility with the modules code) - * apm=on/off enable/disable APM - */ - -/* - * Maximum number of events stored - */ -#define APM_MAX_EVENTS 16 - -struct apm_queue { - unsigned int event_head; - unsigned int event_tail; - apm_event_t events[APM_MAX_EVENTS]; -}; - -/* - * The per-file APM data - */ -struct apm_user { - struct list_head list; - - unsigned int suser: 1; - unsigned int writer: 1; - unsigned int reader: 1; - - int suspend_result; - unsigned int suspend_state; -#define SUSPEND_NONE 0 /* no suspend pending */ -#define SUSPEND_PENDING 1 /* suspend pending read */ -#define SUSPEND_READ 2 /* suspend read, pending ack */ -#define SUSPEND_ACKED 3 /* suspend acked */ -#define SUSPEND_WAIT 4 /* waiting for suspend */ -#define SUSPEND_DONE 5 /* suspend completed */ - - struct apm_queue queue; -}; - -/* - * Local variables - */ -static int suspends_pending; -static int apm_disabled; -static struct task_struct *kapmd_tsk; - -static DECLARE_WAIT_QUEUE_HEAD(apm_waitqueue); -static DECLARE_WAIT_QUEUE_HEAD(apm_suspend_waitqueue); - -/* - * This is a list of everyone who has opened /dev/apm_bios - */ -static DECLARE_RWSEM(user_list_lock); -static LIST_HEAD(apm_user_list); - -/* - * kapmd info. kapmd provides us a process context to handle - * "APM" events within - specifically necessary if we're going - * to be suspending the system. - */ -static DECLARE_WAIT_QUEUE_HEAD(kapmd_wait); -static DEFINE_SPINLOCK(kapmd_queue_lock); -static struct apm_queue kapmd_queue; - -static DEFINE_MUTEX(state_lock); - -static const char driver_version[] = "1.13"; /* no spaces */ - - - -/* - * Compatibility cruft until the IPAQ people move over to the new - * interface. - */ -static void __apm_get_power_status(struct apm_power_info *info) -{ -} - -/* - * This allows machines to provide their own "apm get power status" function. - */ -void (*apm_get_power_status)(struct apm_power_info *) = __apm_get_power_status; -EXPORT_SYMBOL(apm_get_power_status); - - -/* - * APM event queue management. - */ -static inline int queue_empty(struct apm_queue *q) -{ - return q->event_head == q->event_tail; -} - -static inline apm_event_t queue_get_event(struct apm_queue *q) -{ - q->event_tail = (q->event_tail + 1) % APM_MAX_EVENTS; - return q->events[q->event_tail]; -} - -static void queue_add_event(struct apm_queue *q, apm_event_t event) -{ - q->event_head = (q->event_head + 1) % APM_MAX_EVENTS; - if (q->event_head == q->event_tail) { - static int notified; - - if (notified++ == 0) - printk(KERN_ERR "apm: an event queue overflowed\n"); - q->event_tail = (q->event_tail + 1) % APM_MAX_EVENTS; - } - q->events[q->event_head] = event; -} - -static void queue_event(apm_event_t event) -{ - struct apm_user *as; - - down_read(&user_list_lock); - list_for_each_entry(as, &apm_user_list, list) { - if (as->reader) - queue_add_event(&as->queue, event); - } - up_read(&user_list_lock); - wake_up_interruptible(&apm_waitqueue); -} - -/* - * queue_suspend_event - queue an APM suspend event. - * - * Check that we're in a state where we can suspend. If not, - * return -EBUSY. Otherwise, queue an event to all "writer" - * users. If there are no "writer" users, return '1' to - * indicate that we can immediately suspend. - */ -static int queue_suspend_event(apm_event_t event, struct apm_user *sender) -{ - struct apm_user *as; - int ret = 1; - - mutex_lock(&state_lock); - down_read(&user_list_lock); - - /* - * If a thread is still processing, we can't suspend, so reject - * the request. - */ - list_for_each_entry(as, &apm_user_list, list) { - if (as != sender && as->reader && as->writer && as->suser && - as->suspend_state != SUSPEND_NONE) { - ret = -EBUSY; - goto out; - } - } - - list_for_each_entry(as, &apm_user_list, list) { - if (as != sender && as->reader && as->writer && as->suser) { - as->suspend_state = SUSPEND_PENDING; - suspends_pending++; - queue_add_event(&as->queue, event); - ret = 0; - } - } - out: - up_read(&user_list_lock); - mutex_unlock(&state_lock); - wake_up_interruptible(&apm_waitqueue); - return ret; -} - -static void apm_suspend(void) -{ - struct apm_user *as; - int err = pm_suspend(PM_SUSPEND_MEM); - - /* - * Anyone on the APM queues will think we're still suspended. - * Send a message so everyone knows we're now awake again. - */ - queue_event(APM_NORMAL_RESUME); - - /* - * Finally, wake up anyone who is sleeping on the suspend. - */ - mutex_lock(&state_lock); - down_read(&user_list_lock); - list_for_each_entry(as, &apm_user_list, list) { - if (as->suspend_state == SUSPEND_WAIT || - as->suspend_state == SUSPEND_ACKED) { - as->suspend_result = err; - as->suspend_state = SUSPEND_DONE; - } - } - up_read(&user_list_lock); - mutex_unlock(&state_lock); - - wake_up(&apm_suspend_waitqueue); -} - -static ssize_t apm_read(struct file *fp, char __user *buf, size_t count, loff_t *ppos) -{ - struct apm_user *as = fp->private_data; - apm_event_t event; - int i = count, ret = 0; - - if (count < sizeof(apm_event_t)) - return -EINVAL; - - if (queue_empty(&as->queue) && fp->f_flags & O_NONBLOCK) - return -EAGAIN; - - wait_event_interruptible(apm_waitqueue, !queue_empty(&as->queue)); - - while ((i >= sizeof(event)) && !queue_empty(&as->queue)) { - event = queue_get_event(&as->queue); - - ret = -EFAULT; - if (copy_to_user(buf, &event, sizeof(event))) - break; - - mutex_lock(&state_lock); - if (as->suspend_state == SUSPEND_PENDING && - (event == APM_SYS_SUSPEND || event == APM_USER_SUSPEND)) - as->suspend_state = SUSPEND_READ; - mutex_unlock(&state_lock); - - buf += sizeof(event); - i -= sizeof(event); - } - - if (i < count) - ret = count - i; - - return ret; -} - -static unsigned int apm_poll(struct file *fp, poll_table * wait) -{ - struct apm_user *as = fp->private_data; - - poll_wait(fp, &apm_waitqueue, wait); - return queue_empty(&as->queue) ? 0 : POLLIN | POLLRDNORM; -} - -/* - * apm_ioctl - handle APM ioctl - * - * APM_IOC_SUSPEND - * This IOCTL is overloaded, and performs two functions. It is used to: - * - initiate a suspend - * - acknowledge a suspend read from /dev/apm_bios. - * Only when everyone who has opened /dev/apm_bios with write permission - * has acknowledge does the actual suspend happen. - */ -static int -apm_ioctl(struct inode * inode, struct file *filp, u_int cmd, u_long arg) -{ - struct apm_user *as = filp->private_data; - unsigned long flags; - int err = -EINVAL; - - if (!as->suser || !as->writer) - return -EPERM; - - switch (cmd) { - case APM_IOC_SUSPEND: - mutex_lock(&state_lock); - - as->suspend_result = -EINTR; - - if (as->suspend_state == SUSPEND_READ) { - int pending; - - /* - * If we read a suspend command from /dev/apm_bios, - * then the corresponding APM_IOC_SUSPEND ioctl is - * interpreted as an acknowledge. - */ - as->suspend_state = SUSPEND_ACKED; - suspends_pending--; - pending = suspends_pending == 0; - mutex_unlock(&state_lock); - - /* - * If there are no further acknowledges required, - * suspend the system. - */ - if (pending) - apm_suspend(); - - /* - * Wait for the suspend/resume to complete. If there - * are pending acknowledges, we wait here for them. - * - * Note: we need to ensure that the PM subsystem does - * not kick us out of the wait when it suspends the - * threads. - */ - flags = current->flags; - current->flags |= PF_NOFREEZE; - - wait_event(apm_suspend_waitqueue, - as->suspend_state == SUSPEND_DONE); - } else { - as->suspend_state = SUSPEND_WAIT; - mutex_unlock(&state_lock); - - /* - * Otherwise it is a request to suspend the system. - * Queue an event for all readers, and expect an - * acknowledge from all writers who haven't already - * acknowledged. - */ - err = queue_suspend_event(APM_USER_SUSPEND, as); - if (err < 0) { - /* - * Avoid taking the lock here - this - * should be fine. - */ - as->suspend_state = SUSPEND_NONE; - break; - } - - if (err > 0) - apm_suspend(); - - /* - * Wait for the suspend/resume to complete. If there - * are pending acknowledges, we wait here for them. - * - * Note: we need to ensure that the PM subsystem does - * not kick us out of the wait when it suspends the - * threads. - */ - flags = current->flags; - current->flags |= PF_NOFREEZE; - - wait_event_interruptible(apm_suspend_waitqueue, - as->suspend_state == SUSPEND_DONE); - } - - current->flags = flags; - - mutex_lock(&state_lock); - err = as->suspend_result; - as->suspend_state = SUSPEND_NONE; - mutex_unlock(&state_lock); - break; - } - - return err; -} - -static int apm_release(struct inode * inode, struct file * filp) -{ - struct apm_user *as = filp->private_data; - int pending = 0; - - filp->private_data = NULL; - - down_write(&user_list_lock); - list_del(&as->list); - up_write(&user_list_lock); - - /* - * We are now unhooked from the chain. As far as new - * events are concerned, we no longer exist. However, we - * need to balance suspends_pending, which means the - * possibility of sleeping. - */ - mutex_lock(&state_lock); - if (as->suspend_state != SUSPEND_NONE) { - suspends_pending -= 1; - pending = suspends_pending == 0; - } - mutex_unlock(&state_lock); - if (pending) - apm_suspend(); - - kfree(as); - return 0; -} - -static int apm_open(struct inode * inode, struct file * filp) -{ - struct apm_user *as; - - as = kzalloc(sizeof(*as), GFP_KERNEL); - if (as) { - /* - * XXX - this is a tiny bit broken, when we consider BSD - * process accounting. If the device is opened by root, we - * instantly flag that we used superuser privs. Who knows, - * we might close the device immediately without doing a - * privileged operation -- cevans - */ - as->suser = capable(CAP_SYS_ADMIN); - as->writer = (filp->f_mode & FMODE_WRITE) == FMODE_WRITE; - as->reader = (filp->f_mode & FMODE_READ) == FMODE_READ; - - down_write(&user_list_lock); - list_add(&as->list, &apm_user_list); - up_write(&user_list_lock); - - filp->private_data = as; - } - - return as ? 0 : -ENOMEM; -} - -static struct file_operations apm_bios_fops = { - .owner = THIS_MODULE, - .read = apm_read, - .poll = apm_poll, - .ioctl = apm_ioctl, - .open = apm_open, - .release = apm_release, -}; - -static struct miscdevice apm_device = { - .minor = APM_MINOR_DEV, - .name = "apm_bios", - .fops = &apm_bios_fops -}; - - -#ifdef CONFIG_PROC_FS -/* - * Arguments, with symbols from linux/apm_bios.h. - * - * 0) Linux driver version (this will change if format changes) - * 1) APM BIOS Version. Usually 1.0, 1.1 or 1.2. - * 2) APM flags from APM Installation Check (0x00): - * bit 0: APM_16_BIT_SUPPORT - * bit 1: APM_32_BIT_SUPPORT - * bit 2: APM_IDLE_SLOWS_CLOCK - * bit 3: APM_BIOS_DISABLED - * bit 4: APM_BIOS_DISENGAGED - * 3) AC line status - * 0x00: Off-line - * 0x01: On-line - * 0x02: On backup power (BIOS >= 1.1 only) - * 0xff: Unknown - * 4) Battery status - * 0x00: High - * 0x01: Low - * 0x02: Critical - * 0x03: Charging - * 0x04: Selected battery not present (BIOS >= 1.2 only) - * 0xff: Unknown - * 5) Battery flag - * bit 0: High - * bit 1: Low - * bit 2: Critical - * bit 3: Charging - * bit 7: No system battery - * 0xff: Unknown - * 6) Remaining battery life (percentage of charge): - * 0-100: valid - * -1: Unknown - * 7) Remaining battery life (time units): - * Number of remaining minutes or seconds - * -1: Unknown - * 8) min = minutes; sec = seconds - */ -static int apm_get_info(char *buf, char **start, off_t fpos, int length) -{ - struct apm_power_info info; - char *units; - int ret; - - info.ac_line_status = 0xff; - info.battery_status = 0xff; - info.battery_flag = 0xff; - info.battery_life = -1; - info.time = -1; - info.units = -1; - - if (apm_get_power_status) - apm_get_power_status(&info); - - switch (info.units) { - default: units = "?"; break; - case 0: units = "min"; break; - case 1: units = "sec"; break; - } - - ret = sprintf(buf, "%s 1.2 0x%02x 0x%02x 0x%02x 0x%02x %d%% %d %s\n", - driver_version, APM_32_BIT_SUPPORT, - info.ac_line_status, info.battery_status, - info.battery_flag, info.battery_life, - info.time, units); - - return ret; -} -#endif - -static int kapmd(void *arg) -{ - do { - apm_event_t event; - int ret; - - wait_event_interruptible(kapmd_wait, - !queue_empty(&kapmd_queue) || kthread_should_stop()); - - if (kthread_should_stop()) - break; - - spin_lock_irq(&kapmd_queue_lock); - event = 0; - if (!queue_empty(&kapmd_queue)) - event = queue_get_event(&kapmd_queue); - spin_unlock_irq(&kapmd_queue_lock); - - switch (event) { - case 0: - break; - - case APM_LOW_BATTERY: - case APM_POWER_STATUS_CHANGE: - queue_event(event); - break; - - case APM_USER_SUSPEND: - case APM_SYS_SUSPEND: - ret = queue_suspend_event(event, NULL); - if (ret < 0) { - /* - * We were busy. Try again in 50ms. - */ - queue_add_event(&kapmd_queue, event); - msleep(50); - } - if (ret > 0) - apm_suspend(); - break; - - case APM_CRITICAL_SUSPEND: - apm_suspend(); - break; - } - } while (1); - - return 0; -} - -static int __init apm_init(void) -{ - int ret; - - if (apm_disabled) { - printk(KERN_NOTICE "apm: disabled on user request.\n"); - return -ENODEV; - } - - kapmd_tsk = kthread_create(kapmd, NULL, "kapmd"); - if (IS_ERR(kapmd_tsk)) { - ret = PTR_ERR(kapmd_tsk); - kapmd_tsk = NULL; - return ret; - } - kapmd_tsk->flags |= PF_NOFREEZE; - wake_up_process(kapmd_tsk); - -#ifdef CONFIG_PROC_FS - create_proc_info_entry("apm", 0, NULL, apm_get_info); -#endif - - ret = misc_register(&apm_device); - if (ret != 0) { - remove_proc_entry("apm", NULL); - kthread_stop(kapmd_tsk); - } - - return ret; -} - -static void __exit apm_exit(void) -{ - misc_deregister(&apm_device); - remove_proc_entry("apm", NULL); - - kthread_stop(kapmd_tsk); -} - -module_init(apm_init); -module_exit(apm_exit); - -MODULE_AUTHOR("Stephen Rothwell"); -MODULE_DESCRIPTION("Advanced Power Management"); -MODULE_LICENSE("GPL"); - -#ifndef MODULE -static int __init apm_setup(char *str) -{ - while ((str != NULL) && (*str != '\0')) { - if (strncmp(str, "off", 3) == 0) - apm_disabled = 1; - if (strncmp(str, "on", 2) == 0) - apm_disabled = 0; - str = strchr(str, ','); - if (str != NULL) - str += strspn(str, ", \t"); - } - return 1; -} - -__setup("apm=", apm_setup); -#endif - -/** - * apm_queue_event - queue an APM event for kapmd - * @event: APM event - * - * Queue an APM event for kapmd to process and ultimately take the - * appropriate action. Only a subset of events are handled: - * %APM_LOW_BATTERY - * %APM_POWER_STATUS_CHANGE - * %APM_USER_SUSPEND - * %APM_SYS_SUSPEND - * %APM_CRITICAL_SUSPEND - */ -void apm_queue_event(apm_event_t event) -{ - unsigned long flags; - - spin_lock_irqsave(&kapmd_queue_lock, flags); - queue_add_event(&kapmd_queue, event); - spin_unlock_irqrestore(&kapmd_queue_lock, flags); - - wake_up_interruptible(&kapmd_wait); -} -EXPORT_SYMBOL(apm_queue_event); diff --git a/arch/arm/kernel/irq.c b/arch/arm/kernel/irq.c index ec01f08..e101846 100644 --- a/arch/arm/kernel/irq.c +++ b/arch/arm/kernel/irq.c @@ -159,8 +159,7 @@ void __init init_IRQ(void) int irq; for (irq = 0; irq < NR_IRQS; irq++) - irq_desc[irq].status |= IRQ_NOREQUEST | IRQ_DELAYED_DISABLE | - IRQ_NOPROBE; + irq_desc[irq].status |= IRQ_NOREQUEST | IRQ_NOPROBE; #ifdef CONFIG_SMP bad_irq_desc.affinity = CPU_MASK_ALL; diff --git a/arch/arm/kernel/isa.c b/arch/arm/kernel/isa.c index 54bbd9f..50a30bc 100644 --- a/arch/arm/kernel/isa.c +++ b/arch/arm/kernel/isa.c @@ -70,5 +70,5 @@ register_isa_ports(unsigned int membase, isa_membase = membase; isa_portbase = portbase; isa_portshift = portshift; - isa_sysctl_header = register_sysctl_table(ctl_bus, 0); + isa_sysctl_header = register_sysctl_table(ctl_bus); } diff --git a/arch/arm/kernel/setup.c b/arch/arm/kernel/setup.c index bbab134..ed52215 100644 --- a/arch/arm/kernel/setup.c +++ b/arch/arm/kernel/setup.c @@ -106,7 +106,7 @@ unsigned long phys_initrd_size __initdat static struct meminfo meminfo __initdata = { 0, }; static const char *cpu_name; static const char *machine_name; -static char command_line[COMMAND_LINE_SIZE]; +static char __initdata command_line[COMMAND_LINE_SIZE]; static char default_command_line[COMMAND_LINE_SIZE] __initdata = CONFIG_CMDLINE; static union { char c[4]; unsigned long l; } endian_test __initdata = { { 'l', '?', '?', 'b' } }; @@ -803,8 +803,8 @@ void __init setup_arch(char **cmdline_p) init_mm.end_data = (unsigned long) &_edata; init_mm.brk = (unsigned long) &_end; - memcpy(saved_command_line, from, COMMAND_LINE_SIZE); - saved_command_line[COMMAND_LINE_SIZE-1] = '\0'; + memcpy(boot_command_line, from, COMMAND_LINE_SIZE); + boot_command_line[COMMAND_LINE_SIZE-1] = '\0'; parse_cmdline(cmdline_p, from); paging_init(&meminfo, mdesc); request_standard_resources(&meminfo, mdesc); diff --git a/arch/arm/kernel/time.c b/arch/arm/kernel/time.c index 3c8cdcf..ee47c53 100644 --- a/arch/arm/kernel/time.c +++ b/arch/arm/kernel/time.c @@ -78,16 +78,6 @@ static unsigned long dummy_gettimeoffset #endif /* - * Scheduler clock - returns current time in nanosec units. - * This is the default implementation. Sub-architecture - * implementations can override this. - */ -unsigned long long __attribute__((weak)) sched_clock(void) -{ - return (unsigned long long)jiffies * (1000000000 / HZ); -} - -/* * An implementation of printk_clock() independent from * sched_clock(). This avoids non-bootable kernels when * printk_clock is enabled. diff --git a/arch/arm/kernel/vmlinux.lds.S b/arch/arm/kernel/vmlinux.lds.S index a8fa75e..b929a60 100644 --- a/arch/arm/kernel/vmlinux.lds.S +++ b/arch/arm/kernel/vmlinux.lds.S @@ -53,10 +53,12 @@ #endif __security_initcall_start = .; *(.security_initcall.init) __security_initcall_end = .; +#ifdef CONFIG_BLK_DEV_INITRD . = ALIGN(32); __initramfs_start = .; usr/built-in.o(.init.ramfs) __initramfs_end = .; +#endif . = ALIGN(64); __per_cpu_start = .; *(.data.percpu) diff --git a/arch/arm/mach-at91rm9200/clock.c b/arch/arm/mach-at91rm9200/clock.c index 4dee21f..36a8e4d 100644 --- a/arch/arm/mach-at91rm9200/clock.c +++ b/arch/arm/mach-at91rm9200/clock.c @@ -407,7 +407,7 @@ static int at91_clk_open(struct inode *i return single_open(file, at91_clk_show, NULL); } -static struct file_operations at91_clk_operations = { +static const struct file_operations at91_clk_operations = { .open = at91_clk_open, .read = seq_read, .llseek = seq_lseek, diff --git a/arch/arm/mach-at91rm9200/gpio.c b/arch/arm/mach-at91rm9200/gpio.c index af22659..15eb5b6 100644 --- a/arch/arm/mach-at91rm9200/gpio.c +++ b/arch/arm/mach-at91rm9200/gpio.c @@ -65,6 +65,24 @@ static inline unsigned pin_to_mask(unsig /* + * mux the pin to the "GPIO" peripheral role. + */ +int __init_or_module at91_set_GPIO_periph(unsigned pin, int use_pullup) +{ + void __iomem *pio = pin_to_controller(pin); + unsigned mask = pin_to_mask(pin); + + if (!pio) + return -EINVAL; + __raw_writel(mask, pio + PIO_IDR); + __raw_writel(mask, pio + (use_pullup ? PIO_PUER : PIO_PUDR)); + __raw_writel(mask, pio + PIO_PER); + return 0; +} +EXPORT_SYMBOL(at91_set_GPIO_periph); + + +/* * mux the pin to the "A" internal peripheral role. */ int __init_or_module at91_set_A_periph(unsigned pin, int use_pullup) @@ -181,6 +199,36 @@ EXPORT_SYMBOL(at91_set_multi_drive); /*--------------------------------------------------------------------------*/ +/* new-style GPIO calls; these expect at91_set_GPIO_periph to have been + * called, and maybe at91_set_multi_drive() for putout pins. + */ + +int gpio_direction_input(unsigned pin) +{ + void __iomem *pio = pin_to_controller(pin); + unsigned mask = pin_to_mask(pin); + + if (!pio || !(__raw_readl(pio + PIO_PSR) & mask)) + return -EINVAL; + __raw_writel(mask, pio + PIO_OER); + return 0; +} +EXPORT_SYMBOL(gpio_direction_input); + +int gpio_direction_output(unsigned pin) +{ + void __iomem *pio = pin_to_controller(pin); + unsigned mask = pin_to_mask(pin); + + if (!pio || !(__raw_readl(pio + PIO_PSR) & mask)) + return -EINVAL; + __raw_writel(mask, pio + PIO_OER); + return 0; +} +EXPORT_SYMBOL(gpio_direction_output); + +/*--------------------------------------------------------------------------*/ + /* * assuming the pin is muxed as a gpio output, set its value. */ diff --git a/arch/arm/mach-imx/time.c b/arch/arm/mach-imx/time.c index 40039b2..2703a73 100644 --- a/arch/arm/mach-imx/time.c +++ b/arch/arm/mach-imx/time.c @@ -87,7 +87,7 @@ static struct clocksource clocksource_im .read = imx_get_cycles, .mask = 0xFFFFFFFF, .shift = 20, - .is_continuous = 1, + .flags = CLOCK_SOURCE_IS_CONTINUOUS, }; static int __init imx_clocksource_init(void) diff --git a/arch/arm/mach-ixp4xx/common.c b/arch/arm/mach-ixp4xx/common.c index 2ec9a9e..45068c3 100644 --- a/arch/arm/mach-ixp4xx/common.c +++ b/arch/arm/mach-ixp4xx/common.c @@ -395,7 +395,7 @@ static struct clocksource clocksource_ix .read = ixp4xx_get_cycles, .mask = CLOCKSOURCE_MASK(32), .shift = 20, - .is_continuous = 1, + .flags = CLOCK_SOURCE_IS_CONTINUOUS, }; unsigned long ixp4xx_timer_freq = FREQ; diff --git a/arch/arm/mach-netx/time.c b/arch/arm/mach-netx/time.c index 5773b55..7e132fc 100644 --- a/arch/arm/mach-netx/time.c +++ b/arch/arm/mach-netx/time.c @@ -62,7 +62,7 @@ static struct clocksource clocksource_ne .read = netx_get_cycles, .mask = CLOCKSOURCE_MASK(32), .shift = 20, - .is_continuous = 1, + .flags = CLOCK_SOURCE_IS_CONTINUOUS, }; /* diff --git a/arch/arm/mach-pxa/corgi_pm.c b/arch/arm/mach-pxa/corgi_pm.c index 4c3de40..165017d 100644 --- a/arch/arm/mach-pxa/corgi_pm.c +++ b/arch/arm/mach-pxa/corgi_pm.c @@ -16,7 +16,7 @@ #include #include #include #include -#include +#include #include #include #include diff --git a/arch/arm/mach-pxa/sharpsl_pm.c b/arch/arm/mach-pxa/sharpsl_pm.c index db6e8f5..b1d8cfc 100644 --- a/arch/arm/mach-pxa/sharpsl_pm.c +++ b/arch/arm/mach-pxa/sharpsl_pm.c @@ -23,7 +23,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/arch/arm/mach-pxa/spitz_pm.c b/arch/arm/mach-pxa/spitz_pm.c index 40be833..b97d543 100644 --- a/arch/arm/mach-pxa/spitz_pm.c +++ b/arch/arm/mach-pxa/spitz_pm.c @@ -16,7 +16,7 @@ #include #include #include #include -#include +#include #include #include #include diff --git a/arch/arm/mach-pxa/time.c b/arch/arm/mach-pxa/time.c index ee2beb4..fc3b82a 100644 --- a/arch/arm/mach-pxa/time.c +++ b/arch/arm/mach-pxa/time.c @@ -112,7 +112,7 @@ static struct clocksource clocksource_px .read = pxa_get_cycles, .mask = CLOCKSOURCE_MASK(32), .shift = 20, - .is_continuous = 1, + .flags = CLOCK_SOURCE_IS_CONTINUOUS, }; static void __init pxa_timer_init(void) diff --git a/arch/arm26/Kconfig b/arch/arm26/Kconfig index 74eba8b..989113d 100644 --- a/arch/arm26/Kconfig +++ b/arch/arm26/Kconfig @@ -60,6 +60,10 @@ config GENERIC_CALIBRATE_DELAY config GENERIC_BUST_SPINLOCK bool +config ZONE_DMA + bool + default y + config GENERIC_ISA_DMA bool diff --git a/arch/arm26/kernel/ecard.c b/arch/arm26/kernel/ecard.c index 9dbc172..e2bcefc 100644 --- a/arch/arm26/kernel/ecard.c +++ b/arch/arm26/kernel/ecard.c @@ -665,7 +665,7 @@ ecard_probe(int slot, card_type_t type) ec->fiqmask = 4; } - for (i = 0; i < sizeof(blacklist) / sizeof(*blacklist); i++) + for (i = 0; i < ARRAY_SIZE(blacklist); i++) if (blacklist[i].manufacturer == ec->cid.manufacturer && blacklist[i].product == ec->cid.product) { ec->card_desc = blacklist[i].type; diff --git a/arch/arm26/kernel/setup.c b/arch/arm26/kernel/setup.c index 466ddb5..0e006c6 100644 --- a/arch/arm26/kernel/setup.c +++ b/arch/arm26/kernel/setup.c @@ -80,7 +80,7 @@ unsigned long phys_initrd_size __initdat static struct meminfo meminfo __initdata = { 0, }; static struct proc_info_item proc_info; static const char *machine_name; -static char command_line[COMMAND_LINE_SIZE]; +static char __initdata command_line[COMMAND_LINE_SIZE]; static char default_command_line[COMMAND_LINE_SIZE] __initdata = CONFIG_CMDLINE; @@ -492,8 +492,8 @@ #endif init_mm.end_data = (unsigned long) &_edata; init_mm.brk = (unsigned long) &_end; - memcpy(saved_command_line, from, COMMAND_LINE_SIZE); - saved_command_line[COMMAND_LINE_SIZE-1] = '\0'; + memcpy(boot_command_line, from, COMMAND_LINE_SIZE); + boot_command_line[COMMAND_LINE_SIZE-1] = '\0'; parse_cmdline(&meminfo, cmdline_p, from); bootmem_init(&meminfo); paging_init(&meminfo); diff --git a/arch/arm26/kernel/time.c b/arch/arm26/kernel/time.c index 1206469..0f1d57f 100644 --- a/arch/arm26/kernel/time.c +++ b/arch/arm26/kernel/time.c @@ -89,14 +89,6 @@ static unsigned long gettimeoffset(void) return (offset + LATCH/2) / LATCH; } -/* - * Scheduler clock - returns current time in nanosec units. - */ -unsigned long long sched_clock(void) -{ - return (unsigned long long)jiffies * (1000000000 / HZ); -} - static unsigned long next_rtc_update; /* diff --git a/arch/arm26/kernel/vmlinux-arm26-xip.lds.in b/arch/arm26/kernel/vmlinux-arm26-xip.lds.in index ca61ec8..046a850 100644 --- a/arch/arm26/kernel/vmlinux-arm26-xip.lds.in +++ b/arch/arm26/kernel/vmlinux-arm26-xip.lds.in @@ -46,10 +46,12 @@ SECTIONS __con_initcall_start = .; *(.con_initcall.init) __con_initcall_end = .; +#ifdef CONFIG_BLK_DEV_INITRD . = ALIGN(32); __initramfs_start = .; usr/built-in.o(.init.ramfs) __initramfs_end = .; +#endif . = ALIGN(32768); __init_end = .; } diff --git a/arch/arm26/kernel/vmlinux-arm26.lds.in b/arch/arm26/kernel/vmlinux-arm26.lds.in index d1d3418..1d2949e 100644 --- a/arch/arm26/kernel/vmlinux-arm26.lds.in +++ b/arch/arm26/kernel/vmlinux-arm26.lds.in @@ -47,10 +47,12 @@ SECTIONS __con_initcall_start = .; *(.con_initcall.init) __con_initcall_end = .; +#ifdef CONFIG_BLK_DEV_INITRD . = ALIGN(32); __initramfs_start = .; usr/built-in.o(.init.ramfs) __initramfs_end = .; +#endif . = ALIGN(32768); __init_end = .; } diff --git a/arch/avr32/boards/atstk1000/Makefile b/arch/avr32/boards/atstk1000/Makefile index df94994..8e09922 100644 --- a/arch/avr32/boards/atstk1000/Makefile +++ b/arch/avr32/boards/atstk1000/Makefile @@ -1,2 +1,2 @@ -obj-y += setup.o spi.o flash.o +obj-y += setup.o flash.o obj-$(CONFIG_BOARD_ATSTK1002) += atstk1002.o diff --git a/arch/avr32/boards/atstk1000/atstk1002.c b/arch/avr32/boards/atstk1000/atstk1002.c index 32b361f..5974768 100644 --- a/arch/avr32/boards/atstk1000/atstk1002.c +++ b/arch/avr32/boards/atstk1000/atstk1002.c @@ -14,11 +14,17 @@ #include #include #include #include +#include #include #include +#include #include #include +#include + + +#define SW2_DEFAULT /* MMCI and UART_A available */ struct eth_addr { u8 addr[6]; @@ -29,6 +35,15 @@ static struct eth_addr __initdata hw_add static struct eth_platform_data __initdata eth_data[2]; extern struct lcdc_platform_data atstk1000_fb0_data; +static struct spi_board_info spi0_board_info[] __initdata = { + { + /* QVGA display */ + .modalias = "ltv350qv", + .max_speed_hz = 16000000, + .chip_select = 1, + }, +}; + /* * The next two functions should go away as the boot loader is * supposed to initialize the macb address registers with a valid @@ -86,24 +101,53 @@ static void __init set_hw_addr(struct pl void __init setup_board(void) { - at32_map_usart(1, 0); /* /dev/ttyS0 */ - at32_map_usart(2, 1); /* /dev/ttyS1 */ - at32_map_usart(3, 2); /* /dev/ttyS2 */ +#ifdef SW2_DEFAULT + at32_map_usart(1, 0); /* USART 1/A: /dev/ttyS0, DB9 */ +#else + at32_map_usart(0, 1); /* USART 0/B: /dev/ttyS1, IRDA */ +#endif + /* USART 2/unused: expansion connector */ + at32_map_usart(3, 2); /* USART 3/C: /dev/ttyS2, DB9 */ at32_setup_serial_console(0); } static int __init atstk1002_init(void) { + /* + * ATSTK1000 uses 32-bit SDRAM interface. Reserve the + * SDRAM-specific pins so that nobody messes with them. + */ + at32_reserve_pin(GPIO_PIN_PE(0)); /* DATA[16] */ + at32_reserve_pin(GPIO_PIN_PE(1)); /* DATA[17] */ + at32_reserve_pin(GPIO_PIN_PE(2)); /* DATA[18] */ + at32_reserve_pin(GPIO_PIN_PE(3)); /* DATA[19] */ + at32_reserve_pin(GPIO_PIN_PE(4)); /* DATA[20] */ + at32_reserve_pin(GPIO_PIN_PE(5)); /* DATA[21] */ + at32_reserve_pin(GPIO_PIN_PE(6)); /* DATA[22] */ + at32_reserve_pin(GPIO_PIN_PE(7)); /* DATA[23] */ + at32_reserve_pin(GPIO_PIN_PE(8)); /* DATA[24] */ + at32_reserve_pin(GPIO_PIN_PE(9)); /* DATA[25] */ + at32_reserve_pin(GPIO_PIN_PE(10)); /* DATA[26] */ + at32_reserve_pin(GPIO_PIN_PE(11)); /* DATA[27] */ + at32_reserve_pin(GPIO_PIN_PE(12)); /* DATA[28] */ + at32_reserve_pin(GPIO_PIN_PE(13)); /* DATA[29] */ + at32_reserve_pin(GPIO_PIN_PE(14)); /* DATA[30] */ + at32_reserve_pin(GPIO_PIN_PE(15)); /* DATA[31] */ + at32_reserve_pin(GPIO_PIN_PE(26)); /* SDCS */ + at32_add_system_devices(); +#ifdef SW2_DEFAULT at32_add_device_usart(0); +#else at32_add_device_usart(1); +#endif at32_add_device_usart(2); set_hw_addr(at32_add_device_eth(0, ð_data[0])); - at32_add_device_spi(0); + at32_add_device_spi(0, spi0_board_info, ARRAY_SIZE(spi0_board_info)); at32_add_device_lcdc(0, &atstk1000_fb0_data); return 0; diff --git a/arch/avr32/boards/atstk1000/spi.c b/arch/avr32/boards/atstk1000/spi.c deleted file mode 100644 index 567726c..0000000 --- a/arch/avr32/boards/atstk1000/spi.c +++ /dev/null @@ -1,27 +0,0 @@ -/* - * ATSTK1000 SPI devices - * - * Copyright (C) 2005 Atmel Norway - * - * 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 - -static struct spi_board_info spi_board_info[] __initdata = { - { - .modalias = "ltv350qv", - .max_speed_hz = 16000000, - .bus_num = 0, - .chip_select = 1, - }, -}; - -static int board_init_spi(void) -{ - spi_register_board_info(spi_board_info, ARRAY_SIZE(spi_board_info)); - return 0; -} -arch_initcall(board_init_spi); diff --git a/arch/avr32/kernel/cpu.c b/arch/avr32/kernel/cpu.c index 342452b..2e72fd2 100644 --- a/arch/avr32/kernel/cpu.c +++ b/arch/avr32/kernel/cpu.c @@ -9,6 +9,7 @@ #include #include #include #include +#include #include #include #include diff --git a/arch/avr32/kernel/irq.c b/arch/avr32/kernel/irq.c index 856f354..fd31124 100644 --- a/arch/avr32/kernel/irq.c +++ b/arch/avr32/kernel/irq.c @@ -57,6 +57,7 @@ int show_interrupts(struct seq_file *p, seq_printf(p, "%3d: ", i); for_each_online_cpu(cpu) seq_printf(p, "%10u ", kstat_cpu(cpu).irqs[i]); + seq_printf(p, " %8s", irq_desc[i].chip->name ? : "-"); seq_printf(p, " %s", action->name); for (action = action->next; action; action = action->next) seq_printf(p, ", %s", action->name); diff --git a/arch/avr32/kernel/setup.c b/arch/avr32/kernel/setup.c index a342116..a1a7c3c 100644 --- a/arch/avr32/kernel/setup.c +++ b/arch/avr32/kernel/setup.c @@ -16,6 +16,7 @@ #include #include #include #include +#include #include #include @@ -44,7 +45,7 @@ struct avr32_cpuinfo boot_cpu_data = { }; EXPORT_SYMBOL(boot_cpu_data); -static char command_line[COMMAND_LINE_SIZE]; +static char __initdata command_line[COMMAND_LINE_SIZE]; /* * Should be more than enough, but if you have a _really_ complex @@ -174,8 +175,7 @@ static int __init parse_tag_mem_range(st * Copy the data so the bootmem init code doesn't need to care * about it. */ - if (mem_range_next_free >= - (sizeof(mem_range_cache) / sizeof(mem_range_cache[0]))) + if (mem_range_next_free >= ARRAY_SIZE(mem_range_cache)) panic("Physical memory map too complex!\n"); new = &mem_range_cache[mem_range_next_free++]; @@ -202,7 +202,7 @@ __tagtable(ATAG_MEM, parse_tag_mem); static int __init parse_tag_cmdline(struct tag *tag) { - strlcpy(saved_command_line, tag->u.cmdline.cmdline, COMMAND_LINE_SIZE); + strlcpy(boot_command_line, tag->u.cmdline.cmdline, COMMAND_LINE_SIZE); return 0; } __tagtable(ATAG_CMDLINE, parse_tag_cmdline); @@ -294,7 +294,7 @@ void __init setup_arch (char **cmdline_p init_mm.end_data = (unsigned long) &_edata; init_mm.brk = (unsigned long) &_end; - strlcpy(command_line, saved_command_line, COMMAND_LINE_SIZE); + strlcpy(command_line, boot_command_line, COMMAND_LINE_SIZE); *cmdline_p = command_line; parse_early_param(); diff --git a/arch/avr32/kernel/syscall_table.S b/arch/avr32/kernel/syscall_table.S index db8f8b5..7c27958 100644 --- a/arch/avr32/kernel/syscall_table.S +++ b/arch/avr32/kernel/syscall_table.S @@ -8,14 +8,6 @@ * published by the Free Software Foundation. */ -#if !defined(CONFIG_NFSD) && !defined(CONFIG_NFSD_MODULE) -#define sys_nfsservctl sys_ni_syscall -#endif - -#if !defined(CONFIG_SYSV_IPC) -# define sys_ipc sys_ni_syscall -#endif - .section .rodata,"a",@progbits .type sys_call_table,@object .global sys_call_table @@ -129,7 +121,7 @@ sys_call_table: .long sys_getitimer /* 105 */ .long sys_swapoff .long sys_sysinfo - .long sys_ipc + .long sys_ni_syscall /* was sys_ipc briefly */ .long sys_sendfile .long sys_setdomainname /* 110 */ .long sys_newuname @@ -287,4 +279,16 @@ sys_call_table: .long sys_tee .long sys_vmsplice .long __sys_epoll_pwait /* 265 */ + .long sys_msgget + .long sys_msgsnd + .long sys_msgrcv + .long sys_msgctl + .long sys_semget /* 270 */ + .long sys_semop + .long sys_semctl + .long sys_semtimedop + .long sys_shmat + .long sys_shmget /* 275 */ + .long sys_shmdt + .long sys_shmctl .long sys_ni_syscall /* r8 is saturated at nr_syscalls */ diff --git a/arch/avr32/kernel/time.c b/arch/avr32/kernel/time.c index 5a247ba..c10833f 100644 --- a/arch/avr32/kernel/time.c +++ b/arch/avr32/kernel/time.c @@ -37,7 +37,7 @@ static struct clocksource clocksource_av .read = read_cycle_count, .mask = CLOCKSOURCE_MASK(32), .shift = 16, - .is_continuous = 1, + .flags = CLOCK_SOURCE_IS_CONTINUOUS, }; /* @@ -110,15 +110,6 @@ static void avr32_hpt_init(unsigned int } /* - * Scheduler clock - returns current time in nanosec units. - */ -unsigned long long sched_clock(void) -{ - /* There must be better ways...? */ - return (unsigned long long)jiffies * (1000000000 / HZ); -} - -/* * local_timer_interrupt() does profiling and process accounting on a * per-CPU basis. * diff --git a/arch/avr32/kernel/vmlinux.lds.c b/arch/avr32/kernel/vmlinux.lds.c index 5c4424e..ef13b7c 100644 --- a/arch/avr32/kernel/vmlinux.lds.c +++ b/arch/avr32/kernel/vmlinux.lds.c @@ -46,10 +46,12 @@ SECTIONS __security_initcall_start = .; *(.security_initcall.init) __security_initcall_end = .; +#ifdef CONFIG_BLK_DEV_INITRD . = ALIGN(32); __initramfs_start = .; *(.init.ramfs) __initramfs_end = .; +#endif . = ALIGN(4096); __init_end = .; } diff --git a/arch/avr32/lib/libgcc.h b/arch/avr32/lib/libgcc.h deleted file mode 100644 index 5a091b5..0000000 --- a/arch/avr32/lib/libgcc.h +++ /dev/null @@ -1,33 +0,0 @@ -/* Definitions for various functions 'borrowed' from gcc-3.4.3 */ - -#define BITS_PER_UNIT 8 - -typedef int QItype __attribute__ ((mode (QI))); -typedef unsigned int UQItype __attribute__ ((mode (QI))); -typedef int HItype __attribute__ ((mode (HI))); -typedef unsigned int UHItype __attribute__ ((mode (HI))); -typedef int SItype __attribute__ ((mode (SI))); -typedef unsigned int USItype __attribute__ ((mode (SI))); -typedef int DItype __attribute__ ((mode (DI))); -typedef unsigned int UDItype __attribute__ ((mode (DI))); -typedef float SFtype __attribute__ ((mode (SF))); -typedef float DFtype __attribute__ ((mode (DF))); -typedef int word_type __attribute__ ((mode (__word__))); - -#define W_TYPE_SIZE (4 * BITS_PER_UNIT) -#define Wtype SItype -#define UWtype USItype -#define HWtype SItype -#define UHWtype USItype -#define DWtype DItype -#define UDWtype UDItype -#define __NW(a,b) __ ## a ## si ## b -#define __NDW(a,b) __ ## a ## di ## b - -struct DWstruct {Wtype high, low;}; - -typedef union -{ - struct DWstruct s; - DWtype ll; -} DWunion; diff --git a/arch/avr32/lib/longlong.h b/arch/avr32/lib/longlong.h deleted file mode 100644 index cd5e369..0000000 --- a/arch/avr32/lib/longlong.h +++ /dev/null @@ -1,98 +0,0 @@ -/* longlong.h -- definitions for mixed size 32/64 bit arithmetic. - Copyright (C) 1991, 1992, 1994, 1995, 1996, 1997, 1998, 1999, 2000 - Free Software Foundation, Inc. - - This definition file 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, or (at your option) any later version. - - This definition file 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. */ - -/* Borrowed from gcc-3.4.3 */ - -#define __BITS4 (W_TYPE_SIZE / 4) -#define __ll_B ((UWtype) 1 << (W_TYPE_SIZE / 2)) -#define __ll_lowpart(t) ((UWtype) (t) & (__ll_B - 1)) -#define __ll_highpart(t) ((UWtype) (t) >> (W_TYPE_SIZE / 2)) - -#define count_leading_zeros(count, x) ((count) = __builtin_clz(x)) - -#define __udiv_qrnnd_c(q, r, n1, n0, d) \ - do { \ - UWtype __d1, __d0, __q1, __q0; \ - UWtype __r1, __r0, __m; \ - __d1 = __ll_highpart (d); \ - __d0 = __ll_lowpart (d); \ - \ - __r1 = (n1) % __d1; \ - __q1 = (n1) / __d1; \ - __m = (UWtype) __q1 * __d0; \ - __r1 = __r1 * __ll_B | __ll_highpart (n0); \ - if (__r1 < __m) \ - { \ - __q1--, __r1 += (d); \ - if (__r1 >= (d)) /* i.e. we didn't get carry when adding to __r1 */\ - if (__r1 < __m) \ - __q1--, __r1 += (d); \ - } \ - __r1 -= __m; \ - \ - __r0 = __r1 % __d1; \ - __q0 = __r1 / __d1; \ - __m = (UWtype) __q0 * __d0; \ - __r0 = __r0 * __ll_B | __ll_lowpart (n0); \ - if (__r0 < __m) \ - { \ - __q0--, __r0 += (d); \ - if (__r0 >= (d)) \ - if (__r0 < __m) \ - __q0--, __r0 += (d); \ - } \ - __r0 -= __m; \ - \ - (q) = (UWtype) __q1 * __ll_B | __q0; \ - (r) = __r0; \ - } while (0) - -#define udiv_qrnnd __udiv_qrnnd_c - -#define sub_ddmmss(sh, sl, ah, al, bh, bl) \ - do { \ - UWtype __x; \ - __x = (al) - (bl); \ - (sh) = (ah) - (bh) - (__x > (al)); \ - (sl) = __x; \ - } while (0) - -#define umul_ppmm(w1, w0, u, v) \ - do { \ - UWtype __x0, __x1, __x2, __x3; \ - UHWtype __ul, __vl, __uh, __vh; \ - \ - __ul = __ll_lowpart (u); \ - __uh = __ll_highpart (u); \ - __vl = __ll_lowpart (v); \ - __vh = __ll_highpart (v); \ - \ - __x0 = (UWtype) __ul * __vl; \ - __x1 = (UWtype) __ul * __vh; \ - __x2 = (UWtype) __uh * __vl; \ - __x3 = (UWtype) __uh * __vh; \ - \ - __x1 += __ll_highpart (__x0);/* this can't give carry */ \ - __x1 += __x2; /* but this indeed can */ \ - if (__x1 < __x2) /* did we get it? */ \ - __x3 += __ll_B; /* yes, add it in the proper pos. */ \ - \ - (w1) = __x3 + __ll_highpart (__x1); \ - (w0) = __ll_lowpart (__x1) * __ll_B + __ll_lowpart (__x0); \ - } while (0) diff --git a/arch/avr32/mach-at32ap/Makefile b/arch/avr32/mach-at32ap/Makefile index f62eb69..b21bea9 100644 --- a/arch/avr32/mach-at32ap/Makefile +++ b/arch/avr32/mach-at32ap/Makefile @@ -1,2 +1,2 @@ -obj-y += at32ap.o clock.o pio.o intc.o extint.o hsmc.o +obj-y += at32ap.o clock.o intc.o extint.o pio.o hsmc.o obj-$(CONFIG_CPU_AT32AP7000) += at32ap7000.o diff --git a/arch/avr32/mach-at32ap/at32ap7000.c b/arch/avr32/mach-at32ap/at32ap7000.c index 48f4ef3..bc23550 100644 --- a/arch/avr32/mach-at32ap/at32ap7000.c +++ b/arch/avr32/mach-at32ap/at32ap7000.c @@ -8,6 +8,7 @@ #include #include #include +#include #include @@ -310,8 +311,6 @@ static void genclk_mode(struct clk *clk, { u32 control; - BUG_ON(clk->index > 7); - control = sm_readl(&system_manager, PM_GCCTRL + 4 * clk->index); if (enabled) control |= SM_BIT(CEN); @@ -325,11 +324,6 @@ static unsigned long genclk_get_rate(str u32 control; unsigned long div = 1; - BUG_ON(clk->index > 7); - - if (!clk->parent) - return 0; - control = sm_readl(&system_manager, PM_GCCTRL + 4 * clk->index); if (control & SM_BIT(DIVEN)) div = 2 * (SM_BFEXT(DIV, control) + 1); @@ -342,11 +336,6 @@ static long genclk_set_rate(struct clk * u32 control; unsigned long parent_rate, actual_rate, div; - BUG_ON(clk->index > 7); - - if (!clk->parent) - return 0; - parent_rate = clk->parent->get_rate(clk->parent); control = sm_readl(&system_manager, PM_GCCTRL + 4 * clk->index); @@ -373,11 +362,8 @@ int genclk_set_parent(struct clk *clk, s { u32 control; - BUG_ON(clk->index > 7); - printk("clk %s: new parent %s (was %s)\n", - clk->name, parent->name, - clk->parent ? clk->parent->name : "(null)"); + clk->name, parent->name, clk->parent->name); control = sm_readl(&system_manager, PM_GCCTRL + 4 * clk->index); @@ -399,6 +385,22 @@ int genclk_set_parent(struct clk *clk, s return 0; } +static void __init genclk_init_parent(struct clk *clk) +{ + u32 control; + struct clk *parent; + + BUG_ON(clk->index > 7); + + control = sm_readl(&system_manager, PM_GCCTRL + 4 * clk->index); + if (control & SM_BIT(OSCSEL)) + parent = (control & SM_BIT(PLLSEL)) ? &pll1 : &osc1; + else + parent = (control & SM_BIT(PLLSEL)) ? &pll0 : &osc0; + + clk->parent = parent; +} + /* -------------------------------------------------------------------- * System peripherals * -------------------------------------------------------------------- */ @@ -496,9 +498,16 @@ static struct resource pio3_resource[] = DEFINE_DEV(pio, 3); DEV_CLK(mck, pio3, pba, 13); +static struct resource pio4_resource[] = { + PBMEM(0xffe03800), + IRQ(17), +}; +DEFINE_DEV(pio, 4); +DEV_CLK(mck, pio4, pba, 14); + void __init at32_add_system_devices(void) { - system_manager.eim_first_irq = NR_INTERNAL_IRQS; + system_manager.eim_first_irq = EIM_IRQ_BASE; platform_device_register(&at32_sm_device); platform_device_register(&at32_intc0_device); @@ -509,6 +518,7 @@ void __init at32_add_system_devices(void platform_device_register(&pio1_device); platform_device_register(&pio2_device); platform_device_register(&pio3_device); + platform_device_register(&pio4_device); } /* -------------------------------------------------------------------- @@ -521,7 +531,7 @@ static struct atmel_uart_data atmel_usar }; static struct resource atmel_usart0_resource[] = { PBMEM(0xffe00c00), - IRQ(7), + IRQ(6), }; DEFINE_DEV_DATA(atmel_usart, 0); DEV_CLK(usart, atmel_usart0, pba, 4); @@ -583,7 +593,7 @@ static inline void configure_usart3_pins select_peripheral(PB(17), PERIPH_B, 0); /* TXD */ } -static struct platform_device *at32_usarts[4]; +static struct platform_device *__initdata at32_usarts[4]; void __init at32_map_usart(unsigned int hw_id, unsigned int line) { @@ -728,32 +738,79 @@ at32_add_device_eth(unsigned int id, str /* -------------------------------------------------------------------- * SPI * -------------------------------------------------------------------- */ -static struct resource spi0_resource[] = { +static struct resource atmel_spi0_resource[] = { PBMEM(0xffe00000), IRQ(3), }; -DEFINE_DEV(spi, 0); -DEV_CLK(mck, spi0, pba, 0); +DEFINE_DEV(atmel_spi, 0); +DEV_CLK(spi_clk, atmel_spi0, pba, 0); + +static struct resource atmel_spi1_resource[] = { + PBMEM(0xffe00400), + IRQ(4), +}; +DEFINE_DEV(atmel_spi, 1); +DEV_CLK(spi_clk, atmel_spi1, pba, 1); -struct platform_device *__init at32_add_device_spi(unsigned int id) +static void +at32_spi_setup_slaves(unsigned int bus_num, struct spi_board_info *b, + unsigned int n, const u8 *pins) { + unsigned int pin, mode; + + for (; n; n--, b++) { + b->bus_num = bus_num; + if (b->chip_select >= 4) + continue; + pin = (unsigned)b->controller_data; + if (!pin) { + pin = pins[b->chip_select]; + b->controller_data = (void *)pin; + } + mode = AT32_GPIOF_OUTPUT; + if (!(b->mode & SPI_CS_HIGH)) + mode |= AT32_GPIOF_HIGH; + at32_select_gpio(pin, mode); + } +} + +struct platform_device *__init +at32_add_device_spi(unsigned int id, struct spi_board_info *b, unsigned int n) +{ + /* + * Manage the chipselects as GPIOs, normally using the same pins + * the SPI controller expects; but boards can use other pins. + */ + static u8 __initdata spi0_pins[] = + { GPIO_PIN_PA(3), GPIO_PIN_PA(4), + GPIO_PIN_PA(5), GPIO_PIN_PA(20), }; + static u8 __initdata spi1_pins[] = + { GPIO_PIN_PB(2), GPIO_PIN_PB(3), + GPIO_PIN_PB(4), GPIO_PIN_PA(27), }; struct platform_device *pdev; switch (id) { case 0: - pdev = &spi0_device; + pdev = &atmel_spi0_device; select_peripheral(PA(0), PERIPH_A, 0); /* MISO */ select_peripheral(PA(1), PERIPH_A, 0); /* MOSI */ select_peripheral(PA(2), PERIPH_A, 0); /* SCK */ - select_peripheral(PA(3), PERIPH_A, 0); /* NPCS0 */ - select_peripheral(PA(4), PERIPH_A, 0); /* NPCS1 */ - select_peripheral(PA(5), PERIPH_A, 0); /* NPCS2 */ + at32_spi_setup_slaves(0, b, n, spi0_pins); + break; + + case 1: + pdev = &atmel_spi1_device; + select_peripheral(PB(0), PERIPH_B, 0); /* MISO */ + select_peripheral(PB(1), PERIPH_B, 0); /* MOSI */ + select_peripheral(PB(5), PERIPH_B, 0); /* SCK */ + at32_spi_setup_slaves(1, b, n, spi1_pins); break; default: return NULL; } + spi_register_board_info(b, n); platform_device_register(pdev); return pdev; } @@ -837,6 +894,50 @@ at32_add_device_lcdc(unsigned int id, st return pdev; } +/* -------------------------------------------------------------------- + * GCLK + * -------------------------------------------------------------------- */ +static struct clk gclk0 = { + .name = "gclk0", + .mode = genclk_mode, + .get_rate = genclk_get_rate, + .set_rate = genclk_set_rate, + .set_parent = genclk_set_parent, + .index = 0, +}; +static struct clk gclk1 = { + .name = "gclk1", + .mode = genclk_mode, + .get_rate = genclk_get_rate, + .set_rate = genclk_set_rate, + .set_parent = genclk_set_parent, + .index = 1, +}; +static struct clk gclk2 = { + .name = "gclk2", + .mode = genclk_mode, + .get_rate = genclk_get_rate, + .set_rate = genclk_set_rate, + .set_parent = genclk_set_parent, + .index = 2, +}; +static struct clk gclk3 = { + .name = "gclk3", + .mode = genclk_mode, + .get_rate = genclk_get_rate, + .set_rate = genclk_set_rate, + .set_parent = genclk_set_parent, + .index = 3, +}; +static struct clk gclk4 = { + .name = "gclk4", + .mode = genclk_mode, + .get_rate = genclk_get_rate, + .set_rate = genclk_set_rate, + .set_parent = genclk_set_parent, + .index = 4, +}; + struct clk *at32_clock_list[] = { &osc32k, &osc0, @@ -860,6 +961,7 @@ struct clk *at32_clock_list[] = { &pio1_mck, &pio2_mck, &pio3_mck, + &pio4_mck, &atmel_usart0_usart, &atmel_usart1_usart, &atmel_usart2_usart, @@ -868,9 +970,15 @@ struct clk *at32_clock_list[] = { &macb0_pclk, &macb1_hclk, &macb1_pclk, - &spi0_mck, + &atmel_spi0_spi_clk, + &atmel_spi1_spi_clk, &lcdc0_hclk, &lcdc0_pixclk, + &gclk0, + &gclk1, + &gclk2, + &gclk3, + &gclk4, }; unsigned int at32_nr_clocks = ARRAY_SIZE(at32_clock_list); @@ -880,6 +988,7 @@ void __init at32_portmux_init(void) at32_init_pio(&pio1_device); at32_init_pio(&pio2_device); at32_init_pio(&pio3_device); + at32_init_pio(&pio4_device); } void __init at32_clock_init(void) @@ -898,6 +1007,13 @@ void __init at32_clock_init(void) if (sm_readl(sm, PM_PLL1) & SM_BIT(PLLOSC)) pll1.parent = &osc1; + genclk_init_parent(&gclk0); + genclk_init_parent(&gclk1); + genclk_init_parent(&gclk2); + genclk_init_parent(&gclk3); + genclk_init_parent(&gclk4); + genclk_init_parent(&lcdc0_pixclk); + /* * Turn on all clocks that have at least one user already, and * turn off everything else. We only do this for module diff --git a/arch/avr32/mach-at32ap/clock.c b/arch/avr32/mach-at32ap/clock.c index 3d0d109..49e7b12 100644 --- a/arch/avr32/mach-at32ap/clock.c +++ b/arch/avr32/mach-at32ap/clock.c @@ -63,7 +63,11 @@ EXPORT_SYMBOL(clk_enable); static void __clk_disable(struct clk *clk) { - BUG_ON(clk->users == 0); + if (clk->users == 0) { + printk(KERN_ERR "%s: mismatched disable\n", clk->name); + WARN_ON(1); + return; + } if (--clk->users == 0 && clk->mode) clk->mode(clk, 0); diff --git a/arch/avr32/mach-at32ap/extint.c b/arch/avr32/mach-at32ap/extint.c index b59272e..4a60ecc 100644 --- a/arch/avr32/mach-at32ap/extint.c +++ b/arch/avr32/mach-at32ap/extint.c @@ -55,20 +55,11 @@ static int eim_set_irq_type(unsigned int unsigned long flags; int ret = 0; + flow_type &= IRQ_TYPE_SENSE_MASK; if (flow_type == IRQ_TYPE_NONE) flow_type = IRQ_TYPE_LEVEL_LOW; desc = &irq_desc[irq]; - desc->status &= ~(IRQ_TYPE_SENSE_MASK | IRQ_LEVEL); - desc->status |= flow_type & IRQ_TYPE_SENSE_MASK; - - if (flow_type & (IRQ_TYPE_LEVEL_LOW | IRQ_TYPE_LEVEL_HIGH)) { - desc->status |= IRQ_LEVEL; - set_irq_handler(irq, handle_level_irq); - } else { - set_irq_handler(irq, handle_edge_irq); - } - spin_lock_irqsave(&sm->lock, flags); mode = sm_readl(sm, EIM_MODE); @@ -97,9 +88,16 @@ static int eim_set_irq_type(unsigned int break; } - sm_writel(sm, EIM_MODE, mode); - sm_writel(sm, EIM_EDGE, edge); - sm_writel(sm, EIM_LEVEL, level); + if (ret == 0) { + sm_writel(sm, EIM_MODE, mode); + sm_writel(sm, EIM_EDGE, edge); + sm_writel(sm, EIM_LEVEL, level); + + if (flow_type & (IRQ_TYPE_LEVEL_LOW | IRQ_TYPE_LEVEL_HIGH)) + flow_type |= IRQ_LEVEL; + desc->status &= ~(IRQ_TYPE_SENSE_MASK | IRQ_LEVEL); + desc->status |= flow_type; + } spin_unlock_irqrestore(&sm->lock, flags); @@ -122,8 +120,6 @@ static void demux_eim_irq(unsigned int i unsigned long status, pending; unsigned int i, ext_irq; - spin_lock(&sm->lock); - status = sm_readl(sm, EIM_ISR); pending = status & sm_readl(sm, EIM_IMR); @@ -133,10 +129,11 @@ static void demux_eim_irq(unsigned int i ext_irq = i + sm->eim_first_irq; ext_desc = irq_desc + ext_irq; - ext_desc->handle_irq(ext_irq, ext_desc); + if (ext_desc->status & IRQ_LEVEL) + handle_level_irq(ext_irq, ext_desc); + else + handle_edge_irq(ext_irq, ext_desc); } - - spin_unlock(&sm->lock); } static int __init eim_init(void) @@ -168,8 +165,9 @@ static int __init eim_init(void) sm->eim_chip = &eim_chip; for (i = 0; i < nr_irqs; i++) { + /* NOTE the handler we set here is ignored by the demux */ set_irq_chip_and_handler(sm->eim_first_irq + i, &eim_chip, - handle_edge_irq); + handle_level_irq); set_irq_chip_data(sm->eim_first_irq + i, sm); } diff --git a/arch/avr32/mach-at32ap/pio.c b/arch/avr32/mach-at32ap/pio.c index f1280ed..9ba5654 100644 --- a/arch/avr32/mach-at32ap/pio.c +++ b/arch/avr32/mach-at32ap/pio.c @@ -12,7 +12,9 @@ #include #include #include #include +#include +#include #include #include @@ -26,7 +28,8 @@ struct pio_device { const struct platform_device *pdev; struct clk *clk; u32 pinmux_mask; - char name[32]; + u32 gpio_mask; + char name[8]; }; static struct pio_device pio_dev[MAX_NR_PIO_DEVICES]; @@ -76,6 +79,9 @@ void __init at32_select_periph(unsigned if (!(flags & AT32_GPIOF_PULLUP)) pio_writel(pio, PUDR, mask); + /* gpio_request NOT allowed */ + set_bit(pin_index, &pio->gpio_mask); + return; fail: @@ -99,19 +105,52 @@ void __init at32_select_gpio(unsigned in goto fail; } - pio_writel(pio, PUER, mask); - if (flags & AT32_GPIOF_HIGH) - pio_writel(pio, SODR, mask); - else - pio_writel(pio, CODR, mask); - if (flags & AT32_GPIOF_OUTPUT) + if (flags & AT32_GPIOF_OUTPUT) { + if (flags & AT32_GPIOF_HIGH) + pio_writel(pio, SODR, mask); + else + pio_writel(pio, CODR, mask); + pio_writel(pio, PUDR, mask); pio_writel(pio, OER, mask); - else + } else { + if (flags & AT32_GPIOF_PULLUP) + pio_writel(pio, PUER, mask); + else + pio_writel(pio, PUDR, mask); + if (flags & AT32_GPIOF_DEGLITCH) + pio_writel(pio, IFER, mask); + else + pio_writel(pio, IFDR, mask); pio_writel(pio, ODR, mask); + } pio_writel(pio, PER, mask); - if (!(flags & AT32_GPIOF_PULLUP)) - pio_writel(pio, PUDR, mask); + + /* gpio_request now allowed */ + clear_bit(pin_index, &pio->gpio_mask); + + return; + +fail: + dump_stack(); +} + +/* Reserve a pin, preventing anyone else from changing its configuration. */ +void __init at32_reserve_pin(unsigned int pin) +{ + struct pio_device *pio; + unsigned int pin_index = pin & 0x1f; + + pio = gpio_to_pio(pin); + if (unlikely(!pio)) { + printk("pio: invalid pin %u\n", pin); + goto fail; + } + + if (unlikely(test_and_set_bit(pin_index, &pio->pinmux_mask))) { + printk("%s: pin %u is busy\n", pio->name, pin_index); + goto fail; + } return; @@ -119,20 +158,197 @@ fail: dump_stack(); } +/*--------------------------------------------------------------------------*/ + +/* GPIO API */ + +int gpio_request(unsigned int gpio, const char *label) +{ + struct pio_device *pio; + unsigned int pin; + + pio = gpio_to_pio(gpio); + if (!pio) + return -ENODEV; + + pin = gpio & 0x1f; + if (test_and_set_bit(pin, &pio->gpio_mask)) + return -EBUSY; + + return 0; +} +EXPORT_SYMBOL(gpio_request); + +void gpio_free(unsigned int gpio) +{ + struct pio_device *pio; + unsigned int pin; + + pio = gpio_to_pio(gpio); + if (!pio) { + printk(KERN_ERR + "gpio: attempted to free invalid pin %u\n", gpio); + return; + } + + pin = gpio & 0x1f; + if (!test_and_clear_bit(pin, &pio->gpio_mask)) + printk(KERN_ERR "gpio: freeing free or non-gpio pin %s-%u\n", + pio->name, pin); +} +EXPORT_SYMBOL(gpio_free); + +int gpio_direction_input(unsigned int gpio) +{ + struct pio_device *pio; + unsigned int pin; + + pio = gpio_to_pio(gpio); + if (!pio) + return -ENODEV; + + pin = gpio & 0x1f; + pio_writel(pio, ODR, 1 << pin); + + return 0; +} +EXPORT_SYMBOL(gpio_direction_input); + +int gpio_direction_output(unsigned int gpio) +{ + struct pio_device *pio; + unsigned int pin; + + pio = gpio_to_pio(gpio); + if (!pio) + return -ENODEV; + + pin = gpio & 0x1f; + pio_writel(pio, OER, 1 << pin); + + return 0; +} +EXPORT_SYMBOL(gpio_direction_output); + +int gpio_get_value(unsigned int gpio) +{ + struct pio_device *pio = &pio_dev[gpio >> 5]; + + return (pio_readl(pio, PDSR) >> (gpio & 0x1f)) & 1; +} +EXPORT_SYMBOL(gpio_get_value); + +void gpio_set_value(unsigned int gpio, int value) +{ + struct pio_device *pio = &pio_dev[gpio >> 5]; + u32 mask; + + mask = 1 << (gpio & 0x1f); + if (value) + pio_writel(pio, SODR, mask); + else + pio_writel(pio, CODR, mask); +} +EXPORT_SYMBOL(gpio_set_value); + +/*--------------------------------------------------------------------------*/ + +/* GPIO IRQ support */ + +static void gpio_irq_mask(unsigned irq) +{ + unsigned gpio = irq_to_gpio(irq); + struct pio_device *pio = &pio_dev[gpio >> 5]; + + pio_writel(pio, IDR, 1 << (gpio & 0x1f)); +} + +static void gpio_irq_unmask(unsigned irq) +{ + unsigned gpio = irq_to_gpio(irq); + struct pio_device *pio = &pio_dev[gpio >> 5]; + + pio_writel(pio, IER, 1 << (gpio & 0x1f)); +} + +static int gpio_irq_type(unsigned irq, unsigned type) +{ + if (type != IRQ_TYPE_EDGE_BOTH && type != IRQ_TYPE_NONE) + return -EINVAL; + + return 0; +} + +static struct irq_chip gpio_irqchip = { + .name = "gpio", + .mask = gpio_irq_mask, + .unmask = gpio_irq_unmask, + .set_type = gpio_irq_type, +}; + +static void gpio_irq_handler(unsigned irq, struct irq_desc *desc) +{ + struct pio_device *pio = get_irq_chip_data(irq); + unsigned gpio_irq; + + gpio_irq = (unsigned) get_irq_data(irq); + for (;;) { + u32 isr; + struct irq_desc *d; + + /* ack pending GPIO interrupts */ + isr = pio_readl(pio, ISR) & pio_readl(pio, IMR); + if (!isr) + break; + do { + int i; + + i = ffs(isr) - 1; + isr &= ~(1 << i); + + i += gpio_irq; + d = &irq_desc[i]; + + d->handle_irq(i, d); + } while (isr); + } +} + +static void __init +gpio_irq_setup(struct pio_device *pio, int irq, int gpio_irq) +{ + unsigned i; + + set_irq_chip_data(irq, pio); + set_irq_data(irq, (void *) gpio_irq); + + for (i = 0; i < 32; i++, gpio_irq++) { + set_irq_chip_data(gpio_irq, pio); + set_irq_chip_and_handler(gpio_irq, &gpio_irqchip, + handle_simple_irq); + } + + set_irq_chained_handler(irq, gpio_irq_handler); +} + +/*--------------------------------------------------------------------------*/ + static int __init pio_probe(struct platform_device *pdev) { struct pio_device *pio = NULL; + int irq = platform_get_irq(pdev, 0); + int gpio_irq_base = GPIO_IRQ_BASE + pdev->id * 32; BUG_ON(pdev->id >= MAX_NR_PIO_DEVICES); pio = &pio_dev[pdev->id]; BUG_ON(!pio->regs); - /* TODO: Interrupts */ + gpio_irq_setup(pio, irq, gpio_irq_base); platform_set_drvdata(pdev, pio); - printk(KERN_INFO "%s: Atmel Port Multiplexer at 0x%p (irq %d)\n", - pio->name, pio->regs, platform_get_irq(pdev, 0)); + printk(KERN_DEBUG "%s: base 0x%p, irq %d chains %d..%d\n", + pio->name, pio->regs, irq, gpio_irq_base, gpio_irq_base + 31); return 0; } @@ -148,7 +364,7 @@ static int __init pio_init(void) { return platform_driver_register(&pio_driver); } -subsys_initcall(pio_init); +postcore_initcall(pio_init); void __init at32_init_pio(struct platform_device *pdev) { @@ -184,6 +400,13 @@ void __init at32_init_pio(struct platfor pio->pdev = pdev; pio->regs = ioremap(regs->start, regs->end - regs->start + 1); - pio_writel(pio, ODR, ~0UL); - pio_writel(pio, PER, ~0UL); + /* + * request_gpio() is only valid for pins that have been + * explicitly configured as GPIO and not previously requested + */ + pio->gpio_mask = ~0UL; + + /* start with irqs disabled and acked */ + pio_writel(pio, IDR, ~0UL); + (void) pio_readl(pio, ISR); } diff --git a/arch/avr32/mm/cache.c b/arch/avr32/mm/cache.c index 450515b..fb13f72 100644 --- a/arch/avr32/mm/cache.c +++ b/arch/avr32/mm/cache.c @@ -22,18 +22,34 @@ #define CACHEFLUSH_MAX_LEN 1024 void invalidate_dcache_region(void *start, size_t size) { - unsigned long v, begin, end, linesz; + unsigned long v, begin, end, linesz, mask; + int flush = 0; linesz = boot_cpu_data.dcache.linesz; + mask = linesz - 1; + + /* when first and/or last cachelines are shared, flush them + * instead of invalidating ... never discard valid data! + */ + begin = (unsigned long)start; + end = begin + size - 1; + + if (begin & mask) { + flush_dcache_line(start); + begin += linesz; + flush = 1; + } + if ((end & mask) != mask) { + flush_dcache_line((void *)end); + end -= linesz; + flush = 1; + } - //printk("invalidate dcache: %p + %u\n", start, size); - - /* You asked for it, you got it */ - begin = (unsigned long)start & ~(linesz - 1); - end = ((unsigned long)start + size + linesz - 1) & ~(linesz - 1); - - for (v = begin; v < end; v += linesz) + /* remaining cachelines only need invalidation */ + for (v = begin; v <= end; v += linesz) invalidate_dcache_line((void *)v); + if (flush) + flush_write_buffer(); } void clean_dcache_region(void *start, size_t size) diff --git a/arch/avr32/mm/tlb.c b/arch/avr32/mm/tlb.c index 7b07305..5667201 100644 --- a/arch/avr32/mm/tlb.c +++ b/arch/avr32/mm/tlb.c @@ -360,7 +360,7 @@ static int tlb_open(struct inode *inode, return seq_open(file, &tlb_ops); } -static struct file_operations proc_tlb_operations = { +static const struct file_operations proc_tlb_operations = { .open = tlb_open, .read = seq_read, .llseek = seq_lseek, diff --git a/arch/cris/Kconfig b/arch/cris/Kconfig index 3474309..4b41248 100644 --- a/arch/cris/Kconfig +++ b/arch/cris/Kconfig @@ -9,6 +9,10 @@ config MMU bool default y +config ZONE_DMA + bool + default y + config RWSEM_GENERIC_SPINLOCK bool default y @@ -40,6 +44,9 @@ config IRQ_PER_CPU bool default y +config NO_IOPORT + def_bool y + config CRIS bool default y diff --git a/arch/cris/arch-v10/drivers/axisflashmap.c b/arch/cris/arch-v10/drivers/axisflashmap.c index ffade19..efd7b0f 100644 --- a/arch/cris/arch-v10/drivers/axisflashmap.c +++ b/arch/cris/arch-v10/drivers/axisflashmap.c @@ -359,8 +359,7 @@ #ifdef CONFIG_MTD_CONCAT * So we use the MTD concatenation layer instead of further * complicating the probing procedure. */ - mtd_cse = mtd_concat_create(mtds, - sizeof(mtds) / sizeof(mtds[0]), + mtd_cse = mtd_concat_create(mtds, ARRAY_SIZE(mtds), "cse0+cse1"); #else printk(KERN_ERR "%s and %s: Cannot concatenate due to kernel " diff --git a/arch/cris/arch-v10/drivers/ds1302.c b/arch/cris/arch-v10/drivers/ds1302.c index 3cf4f23..88eff7f 100644 --- a/arch/cris/arch-v10/drivers/ds1302.c +++ b/arch/cris/arch-v10/drivers/ds1302.c @@ -499,7 +499,7 @@ print_rtc_status(void) /* The various file operations we support. */ -static struct file_operations rtc_fops = { +static const struct file_operations rtc_fops = { .owner = THIS_MODULE, .ioctl = rtc_ioctl, }; diff --git a/arch/cris/arch-v10/drivers/eeprom.c b/arch/cris/arch-v10/drivers/eeprom.c index 284ebfd..be35a70 100644 --- a/arch/cris/arch-v10/drivers/eeprom.c +++ b/arch/cris/arch-v10/drivers/eeprom.c @@ -172,7 +172,7 @@ static const char eeprom_name[] = "eepro static struct eeprom_type eeprom; /* This is the exported file-operations structure for this device. */ -struct file_operations eeprom_fops = +const struct file_operations eeprom_fops = { .llseek = eeprom_lseek, .read = eeprom_read, diff --git a/arch/cris/arch-v10/drivers/gpio.c b/arch/cris/arch-v10/drivers/gpio.c index 9aba18b..f389ed6 100644 --- a/arch/cris/arch-v10/drivers/gpio.c +++ b/arch/cris/arch-v10/drivers/gpio.c @@ -838,7 +838,7 @@ gpio_leds_ioctl(unsigned int cmd, unsign return 0; } -struct file_operations gpio_fops = { +const struct file_operations gpio_fops = { .owner = THIS_MODULE, .poll = gpio_poll, .ioctl = gpio_ioctl, diff --git a/arch/cris/arch-v10/drivers/i2c.c b/arch/cris/arch-v10/drivers/i2c.c index 092c724..aca81dd 100644 --- a/arch/cris/arch-v10/drivers/i2c.c +++ b/arch/cris/arch-v10/drivers/i2c.c @@ -692,7 +692,7 @@ i2c_ioctl(struct inode *inode, struct fi return 0; } -static struct file_operations i2c_fops = { +static const struct file_operations i2c_fops = { .owner = THIS_MODULE, .ioctl = i2c_ioctl, .open = i2c_open, diff --git a/arch/cris/arch-v10/drivers/pcf8563.c b/arch/cris/arch-v10/drivers/pcf8563.c index 8c830ee..107796e 100644 --- a/arch/cris/arch-v10/drivers/pcf8563.c +++ b/arch/cris/arch-v10/drivers/pcf8563.c @@ -56,7 +56,7 @@ static const unsigned char days_in_month int pcf8563_ioctl(struct inode *, struct file *, unsigned int, unsigned long); -static struct file_operations pcf8563_fops = { +static const struct file_operations pcf8563_fops = { .owner = THIS_MODULE, .ioctl = pcf8563_ioctl, }; diff --git a/arch/cris/arch-v10/kernel/time.c b/arch/cris/arch-v10/kernel/time.c index ebacf14..077e973 100644 --- a/arch/cris/arch-v10/kernel/time.c +++ b/arch/cris/arch-v10/kernel/time.c @@ -38,7 +38,6 @@ unsigned long get_ns_in_jiffie(void) unsigned long flags; local_irq_save(flags); - local_irq_disable(); timer_count = *R_TIMER0_DATA; presc_count = *R_TIM_PRESC_STATUS; /* presc_count might be wrapped */ diff --git a/arch/cris/arch-v10/mm/tlb.c b/arch/cris/arch-v10/mm/tlb.c index 70a5523..7d9fec8 100644 --- a/arch/cris/arch-v10/mm/tlb.c +++ b/arch/cris/arch-v10/mm/tlb.c @@ -42,8 +42,7 @@ flush_tlb_all(void) * in the same 4-way entry group. details.. */ - local_save_flags(flags); - local_irq_disable(); + local_irq_save(flags); for(i = 0; i < NUM_TLB_ENTRIES; i++) { *R_TLB_SELECT = ( IO_FIELD(R_TLB_SELECT, index, i) ); *R_TLB_HI = ( IO_FIELD(R_TLB_HI, page_id, INVALID_PAGEID ) | @@ -78,8 +77,7 @@ flush_tlb_mm(struct mm_struct *mm) * global pages. is it worth the extra I/O ? */ - local_save_flags(flags); - local_irq_disable(); + local_irq_save(flags); for(i = 0; i < NUM_TLB_ENTRIES; i++) { *R_TLB_SELECT = IO_FIELD(R_TLB_SELECT, index, i); if (IO_EXTRACT(R_TLB_HI, page_id, *R_TLB_HI) == page_id) { @@ -118,8 +116,7 @@ flush_tlb_page(struct vm_area_struct *vm * and the virtual address requested */ - local_save_flags(flags); - local_irq_disable(); + local_irq_save(flags); for(i = 0; i < NUM_TLB_ENTRIES; i++) { unsigned long tlb_hi; *R_TLB_SELECT = IO_FIELD(R_TLB_SELECT, index, i); diff --git a/arch/cris/arch-v10/vmlinux.lds.S b/arch/cris/arch-v10/vmlinux.lds.S index 689729a..4b348b3 100644 --- a/arch/cris/arch-v10/vmlinux.lds.S +++ b/arch/cris/arch-v10/vmlinux.lds.S @@ -82,7 +82,8 @@ SECTIONS __con_initcall_end = .; } SECURITY_INIT - + +#ifdef CONFIG_BLK_DEV_INITRD .init.ramfs : { __initramfs_start = .; *(.init.ramfs) @@ -93,6 +94,7 @@ SECTIONS FILL (0); . = ALIGN (8192); } +#endif __vmlinux_end = .; /* last address of the physical file */ __init_end = .; diff --git a/arch/cris/arch-v32/drivers/cryptocop.c b/arch/cris/arch-v32/drivers/cryptocop.c index 2449637..1a071f1 100644 --- a/arch/cris/arch-v32/drivers/cryptocop.c +++ b/arch/cris/arch-v32/drivers/cryptocop.c @@ -266,7 +266,7 @@ #define CRYPTOCOP_MINOR (0) -struct file_operations cryptocop_fops = { +const struct file_operations cryptocop_fops = { owner: THIS_MODULE, open: cryptocop_open, release: cryptocop_release, diff --git a/arch/cris/arch-v32/drivers/gpio.c b/arch/cris/arch-v32/drivers/gpio.c index 08d36f0..d82c5c5 100644 --- a/arch/cris/arch-v32/drivers/gpio.c +++ b/arch/cris/arch-v32/drivers/gpio.c @@ -705,7 +705,7 @@ gpio_leds_ioctl(unsigned int cmd, unsign return 0; } -struct file_operations gpio_fops = { +const struct file_operations gpio_fops = { .owner = THIS_MODULE, .poll = gpio_poll, .ioctl = gpio_ioctl, diff --git a/arch/cris/arch-v32/drivers/i2c.c b/arch/cris/arch-v32/drivers/i2c.c index 95f0018..5d6c527 100644 --- a/arch/cris/arch-v32/drivers/i2c.c +++ b/arch/cris/arch-v32/drivers/i2c.c @@ -573,7 +573,7 @@ i2c_ioctl(struct inode *inode, struct fi return 0; } -static struct file_operations i2c_fops = { +static const struct file_operations i2c_fops = { owner: THIS_MODULE, ioctl: i2c_ioctl, open: i2c_open, diff --git a/arch/cris/arch-v32/drivers/pcf8563.c b/arch/cris/arch-v32/drivers/pcf8563.c index 2fc7d75..544ab01 100644 --- a/arch/cris/arch-v32/drivers/pcf8563.c +++ b/arch/cris/arch-v32/drivers/pcf8563.c @@ -50,7 +50,7 @@ int pcf8563_ioctl(struct inode *, struct int pcf8563_open(struct inode *, struct file *); int pcf8563_release(struct inode *, struct file *); -static struct file_operations pcf8563_fops = { +static const struct file_operations pcf8563_fops = { owner: THIS_MODULE, ioctl: pcf8563_ioctl, open: pcf8563_open, diff --git a/arch/cris/arch-v32/drivers/sync_serial.c b/arch/cris/arch-v32/drivers/sync_serial.c index 424eb0e..df89298 100644 --- a/arch/cris/arch-v32/drivers/sync_serial.c +++ b/arch/cris/arch-v32/drivers/sync_serial.c @@ -187,7 +187,7 @@ #endif #define NUMBER_OF_PORTS (sizeof(ports)/sizeof(sync_port)) -static struct file_operations sync_serial_fops = { +static const struct file_operations sync_serial_fops = { .owner = THIS_MODULE, .write = sync_serial_write, .read = sync_serial_read, diff --git a/arch/cris/arch-v32/mm/tlb.c b/arch/cris/arch-v32/mm/tlb.c index 9d75d76..c2d12e9 100644 --- a/arch/cris/arch-v32/mm/tlb.c +++ b/arch/cris/arch-v32/mm/tlb.c @@ -54,8 +54,7 @@ __flush_tlb_all(void) * Mask with 0xf so similar TLB entries aren't written in the same 4-way * entry group. */ - local_save_flags(flags); - local_irq_disable(); + local_irq_save(flags); for (mmu = 1; mmu <= 2; mmu++) { SUPP_BANK_SEL(mmu); /* Select the MMU */ @@ -92,8 +91,7 @@ __flush_tlb_mm(struct mm_struct *mm) return; /* Mark the TLB entries that match the page_id as invalid. */ - local_save_flags(flags); - local_irq_disable(); + local_irq_save(flags); for (mmu = 1; mmu <= 2; mmu++) { SUPP_BANK_SEL(mmu); @@ -140,8 +138,7 @@ __flush_tlb_page(struct vm_area_struct * * Invalidate those TLB entries that match both the mm context and the * requested virtual address. */ - local_save_flags(flags); - local_irq_disable(); + local_irq_save(flags); for (mmu = 1; mmu <= 2; mmu++) { SUPP_BANK_SEL(mmu); diff --git a/arch/cris/arch-v32/vmlinux.lds.S b/arch/cris/arch-v32/vmlinux.lds.S index 472d4b3..e124fcd 100644 --- a/arch/cris/arch-v32/vmlinux.lds.S +++ b/arch/cris/arch-v32/vmlinux.lds.S @@ -95,6 +95,7 @@ SECTIONS .data.percpu : { *(.data.percpu) } __per_cpu_end = .; +#ifdef CONFIG_BLK_DEV_INITRD .init.ramfs : { __initramfs_start = .; *(.init.ramfs) @@ -107,6 +108,7 @@ SECTIONS FILL (0); . = ALIGN (8192); } +#endif __vmlinux_end = .; /* Last address of the physical file. */ __init_end = .; diff --git a/arch/cris/kernel/profile.c b/arch/cris/kernel/profile.c index f60ab78..4cfcae6 100644 --- a/arch/cris/kernel/profile.c +++ b/arch/cris/kernel/profile.c @@ -50,7 +50,7 @@ write_cris_profile(struct file *file, co memset(sample_buffer, 0, SAMPLE_BUFFER_SIZE); } -static struct file_operations cris_proc_profile_operations = { +static const struct file_operations cris_proc_profile_operations = { .read = read_cris_profile, .write = write_cris_profile, }; diff --git a/arch/cris/kernel/setup.c b/arch/cris/kernel/setup.c index ca8b45a..65466c4 100644 --- a/arch/cris/kernel/setup.c +++ b/arch/cris/kernel/setup.c @@ -29,7 +29,7 @@ struct screen_info screen_info; extern int root_mountflags; extern char _etext, _edata, _end; -char cris_command_line[COMMAND_LINE_SIZE] = { 0, }; +char __initdata cris_command_line[COMMAND_LINE_SIZE] = { 0, }; extern const unsigned long text_start, edata; /* set by the linker script */ extern unsigned long dram_start, dram_end; @@ -153,8 +153,8 @@ #ifdef CONFIG_ETRAX_CMDLINE #endif /* Save command line for future references. */ - memcpy(saved_command_line, cris_command_line, COMMAND_LINE_SIZE); - saved_command_line[COMMAND_LINE_SIZE - 1] = '\0'; + memcpy(boot_command_line, cris_command_line, COMMAND_LINE_SIZE); + boot_command_line[COMMAND_LINE_SIZE - 1] = '\0'; /* give credit for the CRIS port */ show_etrax_copyright(); diff --git a/arch/cris/kernel/time.c b/arch/cris/kernel/time.c index 0f9213c..acfd045 100644 --- a/arch/cris/kernel/time.c +++ b/arch/cris/kernel/time.c @@ -55,7 +55,6 @@ void do_gettimeofday(struct timeval *tv) unsigned long flags; signed long usec, sec; local_irq_save(flags); - local_irq_disable(); usec = do_gettimeoffset(); /* @@ -217,14 +216,6 @@ #if CONFIG_PROFILING #endif } -/* - * Scheduler clock - returns current time in nanosec units. - */ -unsigned long long sched_clock(void) -{ - return (unsigned long long)jiffies * (1000000000 / HZ); -} - static int __init init_udelay(void) { diff --git a/arch/cris/mm/tlb.c b/arch/cris/mm/tlb.c index 0df390a..c4a98e2 100644 --- a/arch/cris/mm/tlb.c +++ b/arch/cris/mm/tlb.c @@ -8,6 +8,7 @@ */ #include +#include #include #define D(x) @@ -100,7 +101,7 @@ tlb_init(void) /* clear the page_id map */ - for (i = 1; i < sizeof (page_id_map) / sizeof (page_id_map[0]); i++) + for (i = 1; i < ARRAY_SIZE(page_id_map); i++) page_id_map[i] = NULL; /* invalidate the entire TLB */ diff --git a/arch/frv/Kconfig b/arch/frv/Kconfig index 7561d7b..cea2374 100644 --- a/arch/frv/Kconfig +++ b/arch/frv/Kconfig @@ -6,6 +6,10 @@ config FRV bool default y +config ZONE_DMA + bool + default y + config RWSEM_GENERIC_SPINLOCK bool default y diff --git a/arch/frv/kernel/pm.c b/arch/frv/kernel/pm.c index ee677ce..c57ce3f 100644 --- a/arch/frv/kernel/pm.c +++ b/arch/frv/kernel/pm.c @@ -125,7 +125,6 @@ #ifdef CONFIG_SYSCTL * Use a temporary sysctl number. Horrid, but will be cleaned up in 2.6 * when all the PM interfaces exist nicely. */ -#define CTL_PM 9899 #define CTL_PM_SUSPEND 1 #define CTL_PM_CMODE 2 #define CTL_PM_P0 4 @@ -402,17 +401,53 @@ static int cm_sysctl(ctl_table *table, i static struct ctl_table pm_table[] = { - {CTL_PM_SUSPEND, "suspend", NULL, 0, 0200, NULL, &sysctl_pm_do_suspend}, - {CTL_PM_CMODE, "cmode", &clock_cmode_current, sizeof(int), 0644, NULL, &cmode_procctl, &cmode_sysctl, NULL}, - {CTL_PM_P0, "p0", &clock_p0_current, sizeof(int), 0644, NULL, &p0_procctl, &p0_sysctl, NULL}, - {CTL_PM_CM, "cm", &clock_cm_current, sizeof(int), 0644, NULL, &cm_procctl, &cm_sysctl, NULL}, - {0} + { + .ctl_name = CTL_PM_SUSPEND, + .procname = "suspend", + .data = NULL, + .maxlen = 0, + .mode = 0200, + .proc_handler = &sysctl_pm_do_suspend, + }, + { + .ctl_name = CTL_PM_CMODE, + .procname = "cmode", + .data = &clock_cmode_current, + .maxlen = sizeof(int), + .mode = 0644, + .proc_handler = &cmode_procctl, + .strategy = &cmode_sysctl, + }, + { + .ctl_name = CTL_PM_P0, + .procname = "p0", + .data = &clock_p0_current, + .maxlen = sizeof(int), + .mode = 0644, + .proc_handler = &p0_procctl, + .strategy = &p0_sysctl, + }, + { + .ctl_name = CTL_PM_CM, + .procname = "cm", + .data = &clock_cm_current, + .maxlen = sizeof(int), + .mode = 0644, + .proc_handler = &cm_procctl, + .strategy = &cm_sysctl, + }, + { .ctl_name = 0} }; static struct ctl_table pm_dir_table[] = { - {CTL_PM, "pm", NULL, 0, 0555, pm_table}, - {0} + { + .ctl_name = CTL_PM, + .procname = "pm", + .mode = 0555, + .child = pm_table, + }, + { .ctl_name = 0} }; /* @@ -420,7 +455,7 @@ static struct ctl_table pm_dir_table[] = */ static int __init pm_init(void) { - register_sysctl_table(pm_dir_table, 1); + register_sysctl_table(pm_dir_table); return 0; } diff --git a/arch/frv/kernel/setup.c b/arch/frv/kernel/setup.c index 1a5eb6c..8ea3ca2 100644 --- a/arch/frv/kernel/setup.c +++ b/arch/frv/kernel/setup.c @@ -110,7 +110,7 @@ unsigned long __initdata num_mappedpages struct cpuinfo_frv __nongprelbss boot_cpu_data; -char command_line[COMMAND_LINE_SIZE]; +char __initdata command_line[COMMAND_LINE_SIZE]; char __initdata redboot_command_line[COMMAND_LINE_SIZE]; #ifdef CONFIG_PM @@ -762,7 +762,7 @@ #else printk("uClinux FR-V port done by Red Hat Inc \n"); #endif - memcpy(saved_command_line, redboot_command_line, COMMAND_LINE_SIZE); + memcpy(boot_command_line, redboot_command_line, COMMAND_LINE_SIZE); determine_cpu(); determine_clocks(1); @@ -803,7 +803,7 @@ #if defined(CONFIG_CHR_DEV_FLASH) || def #endif /* deal with the command line - RedBoot may have passed one to the kernel */ - memcpy(command_line, saved_command_line, sizeof(command_line)); + memcpy(command_line, boot_command_line, sizeof(command_line)); *cmdline_p = &command_line[0]; parse_cmdline_early(command_line); diff --git a/arch/frv/kernel/sysctl.c b/arch/frv/kernel/sysctl.c index ce67680..3e9d7e0 100644 --- a/arch/frv/kernel/sysctl.c +++ b/arch/frv/kernel/sysctl.c @@ -175,22 +175,40 @@ #endif */ static struct ctl_table frv_table[] = { - { 1, "cache-mode", NULL, 0, 0644, NULL, &procctl_frv_cachemode }, + { + .ctl_name = 1, + .procname = "cache-mode", + .data = NULL, + .maxlen = 0, + .mode = 0644, + .proc_handler = &procctl_frv_cachemode, + }, #ifdef CONFIG_MMU - { 2, "pin-cxnr", NULL, 0, 0644, NULL, &procctl_frv_pin_cxnr }, + { + .ctl_name = 2, + .procname = "pin-cxnr", + .data = NULL, + .maxlen = 0, + .mode = 0644, + .proc_handler = &procctl_frv_pin_cxnr + }, #endif - { 0 } + {} }; /* * Use a temporary sysctl number. Horrid, but will be cleaned up in 2.6 * when all the PM interfaces exist nicely. */ -#define CTL_FRV 9898 static struct ctl_table frv_dir_table[] = { - {CTL_FRV, "frv", NULL, 0, 0555, frv_table}, - {0} + { + .ctl_name = CTL_FRV, + .procname = "frv", + .mode = 0555, + .child = frv_table + }, + {} }; /* @@ -198,7 +216,7 @@ static struct ctl_table frv_dir_table[] */ static int __init frv_sysctl_init(void) { - register_sysctl_table(frv_dir_table, 1); + register_sysctl_table(frv_dir_table); return 0; } diff --git a/arch/frv/kernel/vmlinux.lds.S b/arch/frv/kernel/vmlinux.lds.S index 9c1fb12..97910e0 100644 --- a/arch/frv/kernel/vmlinux.lds.S +++ b/arch/frv/kernel/vmlinux.lds.S @@ -61,10 +61,12 @@ #endif .data.percpu : { *(.data.percpu) } __per_cpu_end = .; +#ifdef CONFIG_BLK_DEV_INITRD . = ALIGN(4096); __initramfs_start = .; .init.ramfs : { *(.init.ramfs) } __initramfs_end = .; +#endif . = ALIGN(THREAD_SIZE); __init_end = .; diff --git a/arch/h8300/Kconfig b/arch/h8300/Kconfig index 34a84bc..1734d96 100644 --- a/arch/h8300/Kconfig +++ b/arch/h8300/Kconfig @@ -17,6 +17,10 @@ config SWAP bool default n +config ZONE_DMA + bool + default y + config FPU bool default n @@ -53,6 +57,9 @@ config TIME_LOW_RES bool default y +config NO_IOPORT + def_bool y + config ISA bool default y diff --git a/arch/h8300/kernel/Makefile b/arch/h8300/kernel/Makefile index 71b6131..4edbc2e 100644 --- a/arch/h8300/kernel/Makefile +++ b/arch/h8300/kernel/Makefile @@ -6,6 +6,8 @@ extra-y := vmlinux.lds obj-y := process.o traps.o ptrace.o ints.o \ sys_h8300.o time.o semaphore.o signal.o \ - setup.o gpio.o init_task.o syscalls.o + setup.o gpio.o init_task.o syscalls.o devres.o + +devres-y = ../../../kernel/irq/devres.o obj-$(CONFIG_MODULES) += module.o h8300_ksyms.o diff --git a/arch/h8300/kernel/setup.c b/arch/h8300/kernel/setup.c index 6adf8f4..313cd80 100644 --- a/arch/h8300/kernel/setup.c +++ b/arch/h8300/kernel/setup.c @@ -54,7 +54,7 @@ unsigned long rom_length; unsigned long memory_start; unsigned long memory_end; -char command_line[COMMAND_LINE_SIZE]; +char __initdata command_line[COMMAND_LINE_SIZE]; extern int _stext, _etext, _sdata, _edata, _sbss, _ebss, _end; extern int _ramstart, _ramend; @@ -154,8 +154,8 @@ #ifdef CONFIG_DEFAULT_CMDLINE #endif /* Keep a copy of command line */ *cmdline_p = &command_line[0]; - memcpy(saved_command_line, command_line, COMMAND_LINE_SIZE); - saved_command_line[COMMAND_LINE_SIZE-1] = 0; + memcpy(boot_command_line, command_line, COMMAND_LINE_SIZE); + boot_command_line[COMMAND_LINE_SIZE-1] = 0; #ifdef DEBUG if (strlen(*cmdline_p)) diff --git a/arch/h8300/kernel/time.c b/arch/h8300/kernel/time.c index 8abab3b..d1ef615 100644 --- a/arch/h8300/kernel/time.c +++ b/arch/h8300/kernel/time.c @@ -118,9 +118,3 @@ int do_settimeofday(struct timespec *tv) } EXPORT_SYMBOL(do_settimeofday); - -unsigned long long sched_clock(void) -{ - return (unsigned long long)jiffies * (1000000000 / HZ); - -} diff --git a/arch/h8300/kernel/vmlinux.lds.S b/arch/h8300/kernel/vmlinux.lds.S index f05288b..65f1cdc 100644 --- a/arch/h8300/kernel/vmlinux.lds.S +++ b/arch/h8300/kernel/vmlinux.lds.S @@ -126,10 +126,12 @@ #endif ___con_initcall_end = .; *(.exit.text) *(.exit.data) +#if defined(CONFIG_BLK_DEV_INITRD) . = ALIGN(4); ___initramfs_start = .; *(.init.ramfs) ___initramfs_end = .; +#endif . = ALIGN(0x4) ; ___init_end = .; __edata = . ; diff --git a/arch/i386/Kconfig b/arch/i386/Kconfig index 0dfee81..1df4a1f 100644 --- a/arch/i386/Kconfig +++ b/arch/i386/Kconfig @@ -18,6 +18,18 @@ config GENERIC_TIME bool default y +config CLOCKSOURCE_WATCHDOG + bool + default y + +config GENERIC_CLOCKEVENTS + bool + default y + +config GENERIC_CLOCKEVENTS_BROADCAST + bool + default y + config LOCKDEP_SUPPORT bool default y @@ -38,6 +50,10 @@ config MMU bool default y +config ZONE_DMA + bool + default y + config SBUS bool @@ -70,6 +86,8 @@ source "init/Kconfig" menu "Processor type and features" +source "kernel/time/Kconfig" + config SMP bool "Symmetric multi-processing support" ---help--- @@ -199,6 +217,15 @@ config PARAVIRT However, when run without a hypervisor the kernel is theoretically slower. If in doubt, say N. +config VMI + bool "VMI Paravirt-ops support" + depends on PARAVIRT && !NO_HZ + default y + help + VMI provides a paravirtualized interface to multiple hypervisors + include VMware ESX server and Xen by connecting to a ROM module + provided by the hypervisor. + config ACPI_SRAT bool default y @@ -1259,3 +1286,12 @@ config X86_TRAMPOLINE config KTIME_SCALAR bool default y + +config NO_IDLE_HZ + bool + depends on PARAVIRT + default y + help + Switches the regular HZ timer off when the system is going idle. + This helps a hypervisor detect that the Linux system is idle, + reducing the overhead of idle systems. diff --git a/arch/i386/Kconfig.cpu b/arch/i386/Kconfig.cpu index 2aecfba..b99c0e2 100644 --- a/arch/i386/Kconfig.cpu +++ b/arch/i386/Kconfig.cpu @@ -226,11 +226,6 @@ config X86_CMPXCHG depends on !M386 default y -config X86_XADD - bool - depends on !M386 - default y - config X86_L1_CACHE_SHIFT int default "7" if MPENTIUM4 || X86_GENERIC diff --git a/arch/i386/Kconfig.debug b/arch/i386/Kconfig.debug index f68cc6f..458bc16 100644 --- a/arch/i386/Kconfig.debug +++ b/arch/i386/Kconfig.debug @@ -87,7 +87,7 @@ config DOUBLEFAULT config DEBUG_PARAVIRT bool "Enable some paravirtualization debugging" - default y + default n depends on PARAVIRT && DEBUG_KERNEL help Currently deliberately clobbers regs which are allowed to be diff --git a/arch/i386/defconfig b/arch/i386/defconfig index 5d80edf..5ae1e0b 100644 --- a/arch/i386/defconfig +++ b/arch/i386/defconfig @@ -1,7 +1,7 @@ # # Automatically generated make config: don't edit -# Linux kernel version: 2.6.20-rc3 -# Fri Jan 5 11:54:46 2007 +# Linux kernel version: 2.6.20-git8 +# Tue Feb 13 11:25:18 2007 # CONFIG_X86_32=y CONFIG_GENERIC_TIME=y @@ -10,6 +10,7 @@ CONFIG_STACKTRACE_SUPPORT=y CONFIG_SEMAPHORE_SLEEPERS=y CONFIG_X86=y CONFIG_MMU=y +CONFIG_ZONE_DMA=y CONFIG_GENERIC_ISA_DMA=y CONFIG_GENERIC_IOMAP=y CONFIG_GENERIC_BUG=y @@ -139,7 +140,6 @@ # CONFIG_MCYRIXIII is not set # CONFIG_MVIAC3_2 is not set CONFIG_X86_GENERIC=y CONFIG_X86_CMPXCHG=y -CONFIG_X86_XADD=y CONFIG_X86_L1_CACHE_SHIFT=7 CONFIG_RWSEM_XCHGADD_ALGORITHM=y # CONFIG_ARCH_HAS_ILOG2_U32 is not set @@ -198,6 +198,7 @@ CONFIG_FLAT_NODE_MEM_MAP=y # CONFIG_SPARSEMEM_STATIC is not set CONFIG_SPLIT_PTLOCK_CPUS=4 CONFIG_RESOURCES_64BIT=y +CONFIG_ZONE_DMA_FLAG=1 # CONFIG_HIGHPTE is not set # CONFIG_MATH_EMULATION is not set CONFIG_MTRR=y @@ -211,6 +212,7 @@ # CONFIG_HZ_1000 is not set CONFIG_HZ=250 # CONFIG_KEXEC is not set # CONFIG_CRASH_DUMP is not set +CONFIG_PHYSICAL_START=0x100000 # CONFIG_RELOCATABLE is not set CONFIG_PHYSICAL_ALIGN=0x100000 # CONFIG_HOTPLUG_CPU is not set @@ -229,13 +231,14 @@ # # ACPI (Advanced Configuration and Power Interface) Support # CONFIG_ACPI=y +CONFIG_ACPI_PROCFS=y CONFIG_ACPI_AC=y CONFIG_ACPI_BATTERY=y CONFIG_ACPI_BUTTON=y -# CONFIG_ACPI_VIDEO is not set # CONFIG_ACPI_HOTKEY is not set CONFIG_ACPI_FAN=y # CONFIG_ACPI_DOCK is not set +# CONFIG_ACPI_BAY is not set CONFIG_ACPI_PROCESSOR=y CONFIG_ACPI_THERMAL=y # CONFIG_ACPI_ASUS is not set @@ -306,7 +309,6 @@ CONFIG_PCI_DIRECT=y CONFIG_PCI_MMCONFIG=y # CONFIG_PCIEPORTBUS is not set CONFIG_PCI_MSI=y -# CONFIG_PCI_MULTITHREAD_PROBE is not set # CONFIG_PCI_DEBUG is not set # CONFIG_HT_IRQ is not set CONFIG_ISA_DMA_API=y @@ -347,6 +349,7 @@ CONFIG_UNIX=y CONFIG_XFRM=y # CONFIG_XFRM_USER is not set # CONFIG_XFRM_SUB_POLICY is not set +# CONFIG_XFRM_MIGRATE is not set # CONFIG_NET_KEY is not set CONFIG_INET=y CONFIG_IP_MULTICAST=y @@ -446,6 +449,7 @@ CONFIG_STANDALONE=y CONFIG_PREVENT_FIRMWARE_BUILD=y CONFIG_FW_LOADER=y # CONFIG_DEBUG_DRIVER is not set +# CONFIG_DEBUG_DEVRES is not set # CONFIG_SYS_HYPERVISOR is not set # @@ -514,6 +518,7 @@ CONFIG_BLK_DEV_IDECD=y # CONFIG_BLK_DEV_IDETAPE is not set # CONFIG_BLK_DEV_IDEFLOPPY is not set # CONFIG_BLK_DEV_IDESCSI is not set +CONFIG_BLK_DEV_IDEACPI=y # CONFIG_IDE_TASK_IOCTL is not set # @@ -546,6 +551,7 @@ # CONFIG_BLK_DEV_HPT366 is not set # CONFIG_BLK_DEV_JMICRON is not set # CONFIG_BLK_DEV_SC1200 is not set CONFIG_BLK_DEV_PIIX=y +# CONFIG_BLK_DEV_IT8213 is not set # CONFIG_BLK_DEV_IT821X is not set # CONFIG_BLK_DEV_NS87415 is not set # CONFIG_BLK_DEV_PDC202XX_OLD is not set @@ -556,6 +562,7 @@ # CONFIG_BLK_DEV_SIS5513 is not set # CONFIG_BLK_DEV_SLC90E66 is not set # CONFIG_BLK_DEV_TRM290 is not set # CONFIG_BLK_DEV_VIA82CXXX is not set +# CONFIG_BLK_DEV_TC86C001 is not set # CONFIG_IDE_ARM is not set CONFIG_BLK_DEV_IDEDMA=y # CONFIG_IDEDMA_IVB is not set @@ -654,6 +661,7 @@ # # Serial ATA (prod) and Parallel ATA (experimental) drivers # CONFIG_ATA=y +# CONFIG_ATA_NONSTANDARD is not set CONFIG_SATA_AHCI=y CONFIG_SATA_SVW=y CONFIG_ATA_PIIX=y @@ -669,6 +677,7 @@ # CONFIG_SATA_SIS is not set # CONFIG_SATA_ULI is not set CONFIG_SATA_VIA=y # CONFIG_SATA_VITESSE is not set +# CONFIG_SATA_INIC162X is not set CONFIG_SATA_INTEL_COMBINED=y # CONFIG_PATA_ALI is not set # CONFIG_PATA_AMD is not set @@ -686,6 +695,7 @@ # CONFIG_PATA_HPT37X is not set # CONFIG_PATA_HPT3X2N is not set # CONFIG_PATA_HPT3X3 is not set # CONFIG_PATA_IT821X is not set +# CONFIG_PATA_IT8213 is not set # CONFIG_PATA_JMICRON is not set # CONFIG_PATA_TRIFLEX is not set # CONFIG_PATA_MARVELL is not set @@ -738,9 +748,7 @@ # # Subsystem Options # # CONFIG_IEEE1394_VERBOSEDEBUG is not set -# CONFIG_IEEE1394_OUI_DB is not set # CONFIG_IEEE1394_EXTRA_CONFIG_ROMS is not set -# CONFIG_IEEE1394_EXPORT_FULL_API is not set # # Device Drivers @@ -766,6 +774,11 @@ # # CONFIG_I2O is not set # +# Macintosh device drivers +# +# CONFIG_MAC_EMUMOUSEBTN is not set + +# # Network device support # CONFIG_NETDEVICES=y @@ -832,6 +845,7 @@ # CONFIG_EPIC100 is not set # CONFIG_SUNDANCE is not set # CONFIG_TLAN is not set # CONFIG_VIA_RHINE is not set +# CONFIG_SC92031 is not set # # Ethernet (1000 Mbit) @@ -854,11 +868,13 @@ # CONFIG_VIA_VELOCITY is not set CONFIG_TIGON3=y CONFIG_BNX2=y # CONFIG_QLA3XXX is not set +# CONFIG_ATL1 is not set # # Ethernet (10000 Mbit) # # CONFIG_CHELSIO_T1 is not set +# CONFIG_CHELSIO_T3 is not set # CONFIG_IXGB is not set # CONFIG_S2IO is not set # CONFIG_MYRI10GE is not set @@ -1089,6 +1105,7 @@ # # Open Sound System # CONFIG_SOUND_PRIME=y +CONFIG_OBSOLETE_OSS=y # CONFIG_SOUND_BT878 is not set # CONFIG_SOUND_ES1371 is not set CONFIG_SOUND_ICH=y @@ -1102,6 +1119,7 @@ # # HID Devices # CONFIG_HID=y +# CONFIG_HID_DEBUG is not set # # USB support @@ -1116,10 +1134,8 @@ # # Miscellaneous USB options # CONFIG_USB_DEVICEFS=y -# CONFIG_USB_BANDWIDTH is not set # CONFIG_USB_DYNAMIC_MINORS is not set # CONFIG_USB_SUSPEND is not set -# CONFIG_USB_MULTITHREAD_PROBE is not set # CONFIG_USB_OTG is not set # @@ -1129,9 +1145,11 @@ CONFIG_USB_EHCI_HCD=y # CONFIG_USB_EHCI_SPLIT_ISO is not set # CONFIG_USB_EHCI_ROOT_HUB_TT is not set # CONFIG_USB_EHCI_TT_NEWSCHED is not set +# CONFIG_USB_EHCI_BIG_ENDIAN_MMIO is not set # CONFIG_USB_ISP116X_HCD is not set CONFIG_USB_OHCI_HCD=y -# CONFIG_USB_OHCI_BIG_ENDIAN is not set +# CONFIG_USB_OHCI_BIG_ENDIAN_DESC is not set +# CONFIG_USB_OHCI_BIG_ENDIAN_MMIO is not set CONFIG_USB_OHCI_LITTLE_ENDIAN=y CONFIG_USB_UHCI_HCD=y # CONFIG_USB_SL811_HCD is not set @@ -1182,6 +1200,7 @@ # CONFIG_USB_ATI_REMOTE is not set # CONFIG_USB_ATI_REMOTE2 is not set # CONFIG_USB_KEYSPAN_REMOTE is not set # CONFIG_USB_APPLETOUCH is not set +# CONFIG_USB_GTCO is not set # # USB Imaging devices @@ -1287,6 +1306,10 @@ # DMA Devices # # +# Auxiliary Display support +# + +# # Virtualization # # CONFIG_KVM is not set @@ -1479,6 +1502,7 @@ CONFIG_UNUSED_SYMBOLS=y # CONFIG_DEBUG_FS is not set # CONFIG_HEADERS_CHECK is not set CONFIG_DEBUG_KERNEL=y +# CONFIG_DEBUG_SHIRQ is not set CONFIG_LOG_BUF_SHIFT=18 CONFIG_DETECT_SOFTLOCKUP=y # CONFIG_SCHEDSTATS is not set @@ -1487,7 +1511,6 @@ # CONFIG_DEBUG_RT_MUTEXES is not set # CONFIG_RT_MUTEX_TESTER is not set # CONFIG_DEBUG_SPINLOCK is not set # CONFIG_DEBUG_MUTEXES is not set -# CONFIG_DEBUG_RWSEMS is not set # CONFIG_DEBUG_LOCK_ALLOC is not set # CONFIG_PROVE_LOCKING is not set # CONFIG_DEBUG_SPINLOCK_SLEEP is not set @@ -1532,7 +1555,8 @@ CONFIG_CRC32=y # CONFIG_LIBCRC32C is not set CONFIG_ZLIB_INFLATE=y CONFIG_PLIST=y -CONFIG_IOMAP_COPY=y +CONFIG_HAS_IOMEM=y +CONFIG_HAS_IOPORT=y CONFIG_GENERIC_HARDIRQS=y CONFIG_GENERIC_IRQ_PROBE=y CONFIG_GENERIC_PENDING_IRQ=y diff --git a/arch/i386/kernel/Makefile b/arch/i386/kernel/Makefile index 1e8988e..4ae3dcf 100644 --- a/arch/i386/kernel/Makefile +++ b/arch/i386/kernel/Makefile @@ -18,7 +18,7 @@ obj-$(CONFIG_X86_MSR) += msr.o obj-$(CONFIG_X86_CPUID) += cpuid.o obj-$(CONFIG_MICROCODE) += microcode.o obj-$(CONFIG_APM) += apm.o -obj-$(CONFIG_X86_SMP) += smp.o smpboot.o +obj-$(CONFIG_X86_SMP) += smp.o smpboot.o tsc_sync.o obj-$(CONFIG_X86_TRAMPOLINE) += trampoline.o obj-$(CONFIG_X86_MPPARSE) += mpparse.o obj-$(CONFIG_X86_LOCAL_APIC) += apic.o nmi.o @@ -32,7 +32,6 @@ obj-$(CONFIG_KPROBES) += kprobes.o obj-$(CONFIG_MODULES) += module.o obj-y += sysenter.o vsyscall.o obj-$(CONFIG_ACPI_SRAT) += srat.o -obj-$(CONFIG_HPET_TIMER) += time_hpet.o obj-$(CONFIG_EFI) += efi.o efi_stub.o obj-$(CONFIG_DOUBLEFAULT) += doublefault.o obj-$(CONFIG_VM86) += vm86.o @@ -40,8 +39,9 @@ obj-$(CONFIG_EARLY_PRINTK) += early_prin obj-$(CONFIG_HPET_TIMER) += hpet.o obj-$(CONFIG_K8_NB) += k8.o -# Make sure this is linked after any other paravirt_ops structs: see head.S +obj-$(CONFIG_VMI) += vmi.o vmitime.o obj-$(CONFIG_PARAVIRT) += paravirt.o +obj-y += pcspeaker.o EXTRA_AFLAGS := -traditional diff --git a/arch/i386/kernel/acpi/boot.c b/arch/i386/kernel/acpi/boot.c index cbcb2c2..fb3e723 100644 --- a/arch/i386/kernel/acpi/boot.c +++ b/arch/i386/kernel/acpi/boot.c @@ -25,6 +25,7 @@ #include #include +#include #include #include #include @@ -66,7 +67,7 @@ #endif /* X86 */ #define BAD_MADT_ENTRY(entry, end) ( \ (!entry) || (unsigned long)entry + sizeof(*entry) > end || \ - ((acpi_table_entry_header *)entry)->length < sizeof(*entry)) + ((struct acpi_subtable_header *)entry)->length < sizeof(*entry)) #define PREFIX "ACPI: " @@ -79,7 +80,7 @@ int acpi_ioapic; int acpi_strict; EXPORT_SYMBOL(acpi_strict); -acpi_interrupt_flags acpi_sci_flags __initdata; +u8 acpi_sci_flags __initdata; int acpi_sci_override_gsi __initdata; int acpi_skip_timer_override __initdata; int acpi_use_timer_override __initdata; @@ -92,11 +93,6 @@ #ifndef __HAVE_ARCH_CMPXCHG #warning ACPI uses CMPXCHG, i486 and later hardware #endif -#define MAX_MADT_ENTRIES 256 -u8 x86_acpiid_to_apicid[MAX_MADT_ENTRIES] = - {[0 ... MAX_MADT_ENTRIES - 1] = 0xff }; -EXPORT_SYMBOL(x86_acpiid_to_apicid); - /* -------------------------------------------------------------------------- Boot-time Configuration -------------------------------------------------------------------------- */ @@ -166,30 +162,26 @@ #endif #ifdef CONFIG_PCI_MMCONFIG /* The physical address of the MMCONFIG aperture. Set from ACPI tables. */ -struct acpi_table_mcfg_config *pci_mmcfg_config; +struct acpi_mcfg_allocation *pci_mmcfg_config; int pci_mmcfg_config_num; -int __init acpi_parse_mcfg(unsigned long phys_addr, unsigned long size) +int __init acpi_parse_mcfg(struct acpi_table_header *header) { struct acpi_table_mcfg *mcfg; unsigned long i; int config_size; - if (!phys_addr || !size) + if (!header) return -EINVAL; - mcfg = (struct acpi_table_mcfg *)__acpi_map_table(phys_addr, size); - if (!mcfg) { - printk(KERN_WARNING PREFIX "Unable to map MCFG\n"); - return -ENODEV; - } + mcfg = (struct acpi_table_mcfg *)header; /* how many config structures do we have */ pci_mmcfg_config_num = 0; - i = size - sizeof(struct acpi_table_mcfg); - while (i >= sizeof(struct acpi_table_mcfg_config)) { + i = header->length - sizeof(struct acpi_table_mcfg); + while (i >= sizeof(struct acpi_mcfg_allocation)) { ++pci_mmcfg_config_num; - i -= sizeof(struct acpi_table_mcfg_config); + i -= sizeof(struct acpi_mcfg_allocation); }; if (pci_mmcfg_config_num == 0) { printk(KERN_ERR PREFIX "MMCONFIG has no entries\n"); @@ -204,9 +196,9 @@ int __init acpi_parse_mcfg(unsigned long return -ENOMEM; } - memcpy(pci_mmcfg_config, &mcfg->config, config_size); + memcpy(pci_mmcfg_config, &mcfg[1], config_size); for (i = 0; i < pci_mmcfg_config_num; ++i) { - if (mcfg->config[i].base_reserved) { + if (pci_mmcfg_config[i].address > 0xFFFFFFFF) { printk(KERN_ERR PREFIX "MMCONFIG not in low 4GB of memory\n"); kfree(pci_mmcfg_config); @@ -220,24 +212,24 @@ int __init acpi_parse_mcfg(unsigned long #endif /* CONFIG_PCI_MMCONFIG */ #ifdef CONFIG_X86_LOCAL_APIC -static int __init acpi_parse_madt(unsigned long phys_addr, unsigned long size) +static int __init acpi_parse_madt(struct acpi_table_header *table) { struct acpi_table_madt *madt = NULL; - if (!phys_addr || !size || !cpu_has_apic) + if (!cpu_has_apic) return -EINVAL; - madt = (struct acpi_table_madt *)__acpi_map_table(phys_addr, size); + madt = (struct acpi_table_madt *)table; if (!madt) { printk(KERN_WARNING PREFIX "Unable to map MADT\n"); return -ENODEV; } - if (madt->lapic_address) { - acpi_lapic_addr = (u64) madt->lapic_address; + if (madt->address) { + acpi_lapic_addr = (u64) madt->address; printk(KERN_DEBUG PREFIX "Local APIC address 0x%08x\n", - madt->lapic_address); + madt->address); } acpi_madt_oem_check(madt->header.oem_id, madt->header.oem_table_id); @@ -246,21 +238,17 @@ static int __init acpi_parse_madt(unsign } static int __init -acpi_parse_lapic(acpi_table_entry_header * header, const unsigned long end) +acpi_parse_lapic(struct acpi_subtable_header * header, const unsigned long end) { - struct acpi_table_lapic *processor = NULL; + struct acpi_madt_local_apic *processor = NULL; - processor = (struct acpi_table_lapic *)header; + processor = (struct acpi_madt_local_apic *)header; if (BAD_MADT_ENTRY(processor, end)) return -EINVAL; acpi_table_print_madt_entry(header); - /* Record local apic id only when enabled */ - if (processor->flags.enabled) - x86_acpiid_to_apicid[processor->acpi_id] = processor->id; - /* * We need to register disabled CPU as well to permit * counting disabled CPUs. This allows us to size @@ -269,18 +257,18 @@ acpi_parse_lapic(acpi_table_entry_header * when we use CPU hotplug. */ mp_register_lapic(processor->id, /* APIC ID */ - processor->flags.enabled); /* Enabled? */ + processor->lapic_flags & ACPI_MADT_ENABLED); /* Enabled? */ return 0; } static int __init -acpi_parse_lapic_addr_ovr(acpi_table_entry_header * header, +acpi_parse_lapic_addr_ovr(struct acpi_subtable_header * header, const unsigned long end) { - struct acpi_table_lapic_addr_ovr *lapic_addr_ovr = NULL; + struct acpi_madt_local_apic_override *lapic_addr_ovr = NULL; - lapic_addr_ovr = (struct acpi_table_lapic_addr_ovr *)header; + lapic_addr_ovr = (struct acpi_madt_local_apic_override *)header; if (BAD_MADT_ENTRY(lapic_addr_ovr, end)) return -EINVAL; @@ -291,11 +279,11 @@ acpi_parse_lapic_addr_ovr(acpi_table_ent } static int __init -acpi_parse_lapic_nmi(acpi_table_entry_header * header, const unsigned long end) +acpi_parse_lapic_nmi(struct acpi_subtable_header * header, const unsigned long end) { - struct acpi_table_lapic_nmi *lapic_nmi = NULL; + struct acpi_madt_local_apic_nmi *lapic_nmi = NULL; - lapic_nmi = (struct acpi_table_lapic_nmi *)header; + lapic_nmi = (struct acpi_madt_local_apic_nmi *)header; if (BAD_MADT_ENTRY(lapic_nmi, end)) return -EINVAL; @@ -313,11 +301,11 @@ #endif /*CONFIG_X86_LOCAL_APIC */ #ifdef CONFIG_X86_IO_APIC static int __init -acpi_parse_ioapic(acpi_table_entry_header * header, const unsigned long end) +acpi_parse_ioapic(struct acpi_subtable_header * header, const unsigned long end) { - struct acpi_table_ioapic *ioapic = NULL; + struct acpi_madt_io_apic *ioapic = NULL; - ioapic = (struct acpi_table_ioapic *)header; + ioapic = (struct acpi_madt_io_apic *)header; if (BAD_MADT_ENTRY(ioapic, end)) return -EINVAL; @@ -342,11 +330,11 @@ static void __init acpi_sci_ioapic_setup polarity = 3; /* Command-line over-ride via acpi_sci= */ - if (acpi_sci_flags.trigger) - trigger = acpi_sci_flags.trigger; + if (acpi_sci_flags & ACPI_MADT_TRIGGER_MASK) + trigger = (acpi_sci_flags & ACPI_MADT_TRIGGER_MASK) >> 2; - if (acpi_sci_flags.polarity) - polarity = acpi_sci_flags.polarity; + if (acpi_sci_flags & ACPI_MADT_POLARITY_MASK) + polarity = acpi_sci_flags & ACPI_MADT_POLARITY_MASK; /* * mp_config_acpi_legacy_irqs() already setup IRQs < 16 @@ -357,51 +345,52 @@ static void __init acpi_sci_ioapic_setup /* * stash over-ride to indicate we've been here - * and for later update of acpi_fadt + * and for later update of acpi_gbl_FADT */ acpi_sci_override_gsi = gsi; return; } static int __init -acpi_parse_int_src_ovr(acpi_table_entry_header * header, +acpi_parse_int_src_ovr(struct acpi_subtable_header * header, const unsigned long end) { - struct acpi_table_int_src_ovr *intsrc = NULL; + struct acpi_madt_interrupt_override *intsrc = NULL; - intsrc = (struct acpi_table_int_src_ovr *)header; + intsrc = (struct acpi_madt_interrupt_override *)header; if (BAD_MADT_ENTRY(intsrc, end)) return -EINVAL; acpi_table_print_madt_entry(header); - if (intsrc->bus_irq == acpi_fadt.sci_int) { + if (intsrc->source_irq == acpi_gbl_FADT.sci_interrupt) { acpi_sci_ioapic_setup(intsrc->global_irq, - intsrc->flags.polarity, - intsrc->flags.trigger); + intsrc->inti_flags & ACPI_MADT_POLARITY_MASK, + (intsrc->inti_flags & ACPI_MADT_TRIGGER_MASK) >> 2); return 0; } if (acpi_skip_timer_override && - intsrc->bus_irq == 0 && intsrc->global_irq == 2) { + intsrc->source_irq == 0 && intsrc->global_irq == 2) { printk(PREFIX "BIOS IRQ0 pin2 override ignored.\n"); return 0; } - mp_override_legacy_irq(intsrc->bus_irq, - intsrc->flags.polarity, - intsrc->flags.trigger, intsrc->global_irq); + mp_override_legacy_irq(intsrc->source_irq, + intsrc->inti_flags & ACPI_MADT_POLARITY_MASK, + (intsrc->inti_flags & ACPI_MADT_TRIGGER_MASK) >> 2, + intsrc->global_irq); return 0; } static int __init -acpi_parse_nmi_src(acpi_table_entry_header * header, const unsigned long end) +acpi_parse_nmi_src(struct acpi_subtable_header * header, const unsigned long end) { - struct acpi_table_nmi_src *nmi_src = NULL; + struct acpi_madt_nmi_source *nmi_src = NULL; - nmi_src = (struct acpi_table_nmi_src *)header; + nmi_src = (struct acpi_madt_nmi_source *)header; if (BAD_MADT_ENTRY(nmi_src, end)) return -EINVAL; @@ -417,7 +406,7 @@ #endif /* CONFIG_X86_IO_APIC */ /* * acpi_pic_sci_set_trigger() - * + * * use ELCR to set PIC-mode trigger type for SCI * * If a PIC-mode SCI is not recognized or gives spurious IRQ7's @@ -511,7 +500,7 @@ int acpi_map_lsapic(acpi_handle handle, { struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL }; union acpi_object *obj; - struct acpi_table_lapic *lapic; + struct acpi_madt_local_apic *lapic; cpumask_t tmp_map, new_map; u8 physid; int cpu; @@ -529,10 +518,10 @@ int acpi_map_lsapic(acpi_handle handle, return -EINVAL; } - lapic = (struct acpi_table_lapic *)obj->buffer.pointer; + lapic = (struct acpi_madt_local_apic *)obj->buffer.pointer; - if ((lapic->header.type != ACPI_MADT_LAPIC) || - (!lapic->flags.enabled)) { + if (lapic->header.type != ACPI_MADT_TYPE_LOCAL_APIC || + !(lapic->lapic_flags & ACPI_MADT_ENABLED)) { kfree(buffer.pointer); return -EINVAL; } @@ -544,7 +533,7 @@ int acpi_map_lsapic(acpi_handle handle, buffer.pointer = NULL; tmp_map = cpu_present_map; - mp_register_lapic(physid, lapic->flags.enabled); + mp_register_lapic(physid, lapic->lapic_flags & ACPI_MADT_ENABLED); /* * If mp_register_lapic successfully generates a new logical cpu @@ -566,14 +555,6 @@ EXPORT_SYMBOL(acpi_map_lsapic); int acpi_unmap_lsapic(int cpu) { - int i; - - for_each_possible_cpu(i) { - if (x86_acpiid_to_apicid[i] == x86_cpu_to_apicid[cpu]) { - x86_acpiid_to_apicid[i] = -1; - break; - } - } x86_cpu_to_apicid[cpu] = -1; cpu_clear(cpu, cpu_present_map); num_processors--; @@ -619,42 +600,37 @@ acpi_scan_rsdp(unsigned long start, unsi return 0; } -static int __init acpi_parse_sbf(unsigned long phys_addr, unsigned long size) +static int __init acpi_parse_sbf(struct acpi_table_header *table) { - struct acpi_table_sbf *sb; - - if (!phys_addr || !size) - return -EINVAL; + struct acpi_table_boot *sb; - sb = (struct acpi_table_sbf *)__acpi_map_table(phys_addr, size); + sb = (struct acpi_table_boot *)table; if (!sb) { printk(KERN_WARNING PREFIX "Unable to map SBF\n"); return -ENODEV; } - sbf_port = sb->sbf_cmos; /* Save CMOS port */ + sbf_port = sb->cmos_index; /* Save CMOS port */ return 0; } #ifdef CONFIG_HPET_TIMER +#include -static int __init acpi_parse_hpet(unsigned long phys, unsigned long size) +static int __init acpi_parse_hpet(struct acpi_table_header *table) { struct acpi_table_hpet *hpet_tbl; struct resource *hpet_res; resource_size_t res_start; - if (!phys || !size) - return -EINVAL; - - hpet_tbl = (struct acpi_table_hpet *)__acpi_map_table(phys, size); + hpet_tbl = (struct acpi_table_hpet *)table; if (!hpet_tbl) { printk(KERN_WARNING PREFIX "Unable to map HPET\n"); return -ENODEV; } - if (hpet_tbl->addr.space_id != ACPI_SPACE_MEM) { + if (hpet_tbl->address.space_id != ACPI_SPACE_MEM) { printk(KERN_WARNING PREFIX "HPET timers must be located in " "memory.\n"); return -1; @@ -667,29 +643,15 @@ #define HPET_RESOURCE_NAME_SIZE 9 hpet_res->name = (void *)&hpet_res[1]; hpet_res->flags = IORESOURCE_MEM | IORESOURCE_BUSY; snprintf((char *)hpet_res->name, HPET_RESOURCE_NAME_SIZE, - "HPET %u", hpet_tbl->number); + "HPET %u", hpet_tbl->sequence); hpet_res->end = (1 * 1024) - 1; } -#ifdef CONFIG_X86_64 - vxtime.hpet_address = hpet_tbl->addr.addrl | - ((long)hpet_tbl->addr.addrh << 32); - + hpet_address = hpet_tbl->address.address; printk(KERN_INFO PREFIX "HPET id: %#x base: %#lx\n", - hpet_tbl->id, vxtime.hpet_address); + hpet_tbl->id, hpet_address); - res_start = vxtime.hpet_address; -#else /* X86 */ - { - extern unsigned long hpet_address; - - hpet_address = hpet_tbl->addr.addrl; - printk(KERN_INFO PREFIX "HPET id: %#x base: %#lx\n", - hpet_tbl->id, hpet_address); - - res_start = hpet_address; - } -#endif /* X86 */ + res_start = hpet_address; if (hpet_res) { hpet_res->start = res_start; @@ -703,46 +665,28 @@ #else #define acpi_parse_hpet NULL #endif -#ifdef CONFIG_X86_PM_TIMER -extern u32 pmtmr_ioport; -#endif - -static int __init acpi_parse_fadt(unsigned long phys, unsigned long size) +static int __init acpi_parse_fadt(struct acpi_table_header *table) { - struct fadt_descriptor *fadt = NULL; - - fadt = (struct fadt_descriptor *)__acpi_map_table(phys, size); - if (!fadt) { - printk(KERN_WARNING PREFIX "Unable to map FADT\n"); - return 0; - } - /* initialize sci_int early for INT_SRC_OVR MADT parsing */ - acpi_fadt.sci_int = fadt->sci_int; - - /* initialize rev and apic_phys_dest_mode for x86_64 genapic */ - acpi_fadt.revision = fadt->revision; - acpi_fadt.force_apic_physical_destination_mode = - fadt->force_apic_physical_destination_mode; #ifdef CONFIG_X86_PM_TIMER /* detect the location of the ACPI PM Timer */ - if (fadt->revision >= FADT2_REVISION_ID) { + if (acpi_gbl_FADT.header.revision >= FADT2_REVISION_ID) { /* FADT rev. 2 */ - if (fadt->xpm_tmr_blk.address_space_id != + if (acpi_gbl_FADT.xpm_timer_block.space_id != ACPI_ADR_SPACE_SYSTEM_IO) return 0; - pmtmr_ioport = fadt->xpm_tmr_blk.address; + pmtmr_ioport = acpi_gbl_FADT.xpm_timer_block.address; /* * "X" fields are optional extensions to the original V1.0 * fields, so we must selectively expand V1.0 fields if the * corresponding X field is zero. */ if (!pmtmr_ioport) - pmtmr_ioport = fadt->V1_pm_tmr_blk; + pmtmr_ioport = acpi_gbl_FADT.pm_timer_block; } else { /* FADT rev. 1 */ - pmtmr_ioport = fadt->V1_pm_tmr_blk; + pmtmr_ioport = acpi_gbl_FADT.pm_timer_block; } if (pmtmr_ioport) printk(KERN_INFO PREFIX "PM-Timer IO Port: %#x\n", @@ -784,13 +728,13 @@ static int __init acpi_parse_madt_lapic_ if (!cpu_has_apic) return -ENODEV; - /* + /* * Note that the LAPIC address is obtained from the MADT (32-bit value) * and (optionally) overriden by a LAPIC_ADDR_OVR entry (64-bit value). */ count = - acpi_table_parse_madt(ACPI_MADT_LAPIC_ADDR_OVR, + acpi_table_parse_madt(ACPI_MADT_TYPE_LOCAL_APIC_OVERRIDE, acpi_parse_lapic_addr_ovr, 0); if (count < 0) { printk(KERN_ERR PREFIX @@ -800,7 +744,7 @@ static int __init acpi_parse_madt_lapic_ mp_register_lapic_address(acpi_lapic_addr); - count = acpi_table_parse_madt(ACPI_MADT_LAPIC, acpi_parse_lapic, + count = acpi_table_parse_madt(ACPI_MADT_TYPE_LOCAL_APIC, acpi_parse_lapic, MAX_APICS); if (!count) { printk(KERN_ERR PREFIX "No LAPIC entries present\n"); @@ -813,7 +757,7 @@ static int __init acpi_parse_madt_lapic_ } count = - acpi_table_parse_madt(ACPI_MADT_LAPIC_NMI, acpi_parse_lapic_nmi, 0); + acpi_table_parse_madt(ACPI_MADT_TYPE_LOCAL_APIC_NMI, acpi_parse_lapic_nmi, 0); if (count < 0) { printk(KERN_ERR PREFIX "Error parsing LAPIC NMI entry\n"); /* TBD: Cleanup to allow fallback to MPS */ @@ -842,7 +786,7 @@ static int __init acpi_parse_madt_ioapic return -ENODEV; } - if (!cpu_has_apic) + if (!cpu_has_apic) return -ENODEV; /* @@ -855,7 +799,7 @@ static int __init acpi_parse_madt_ioapic } count = - acpi_table_parse_madt(ACPI_MADT_IOAPIC, acpi_parse_ioapic, + acpi_table_parse_madt(ACPI_MADT_TYPE_IO_APIC, acpi_parse_ioapic, MAX_IO_APICS); if (!count) { printk(KERN_ERR PREFIX "No IOAPIC entries present\n"); @@ -866,7 +810,7 @@ static int __init acpi_parse_madt_ioapic } count = - acpi_table_parse_madt(ACPI_MADT_INT_SRC_OVR, acpi_parse_int_src_ovr, + acpi_table_parse_madt(ACPI_MADT_TYPE_INTERRUPT_OVERRIDE, acpi_parse_int_src_ovr, NR_IRQ_VECTORS); if (count < 0) { printk(KERN_ERR PREFIX @@ -880,13 +824,13 @@ static int __init acpi_parse_madt_ioapic * pretend we got one so we can set the SCI flags. */ if (!acpi_sci_override_gsi) - acpi_sci_ioapic_setup(acpi_fadt.sci_int, 0, 0); + acpi_sci_ioapic_setup(acpi_gbl_FADT.sci_interrupt, 0, 0); /* Fill in identity legacy mapings where no override */ mp_config_acpi_legacy_irqs(); count = - acpi_table_parse_madt(ACPI_MADT_NMI_SRC, acpi_parse_nmi_src, + acpi_table_parse_madt(ACPI_MADT_TYPE_NMI_SOURCE, acpi_parse_nmi_src, NR_IRQ_VECTORS); if (count < 0) { printk(KERN_ERR PREFIX "Error parsing NMI SRC entry\n"); @@ -908,7 +852,7 @@ static void __init acpi_process_madt(voi #ifdef CONFIG_X86_LOCAL_APIC int count, error; - count = acpi_table_parse(ACPI_APIC, acpi_parse_madt); + count = acpi_table_parse(ACPI_SIG_MADT, acpi_parse_madt); if (count >= 1) { /* @@ -1195,7 +1139,7 @@ #endif if (acpi_disabled && !acpi_ht) return 1; - /* + /* * Initialize the ACPI boot-time table parser. */ error = acpi_table_init(); @@ -1204,7 +1148,7 @@ #endif return error; } - acpi_table_parse(ACPI_BOOT, acpi_parse_sbf); + acpi_table_parse(ACPI_SIG_BOOT, acpi_parse_sbf); /* * blacklist may disable ACPI entirely @@ -1232,19 +1176,19 @@ int __init acpi_boot_init(void) if (acpi_disabled && !acpi_ht) return 1; - acpi_table_parse(ACPI_BOOT, acpi_parse_sbf); + acpi_table_parse(ACPI_SIG_BOOT, acpi_parse_sbf); /* * set sci_int and PM timer address */ - acpi_table_parse(ACPI_FADT, acpi_parse_fadt); + acpi_table_parse(ACPI_SIG_FADT, acpi_parse_fadt); /* * Process the Multiple APIC Description Table (MADT), if present */ acpi_process_madt(); - acpi_table_parse(ACPI_HPET, acpi_parse_hpet); + acpi_table_parse(ACPI_SIG_HPET, acpi_parse_hpet); return 0; } @@ -1315,13 +1259,17 @@ static int __init setup_acpi_sci(char *s if (!s) return -EINVAL; if (!strcmp(s, "edge")) - acpi_sci_flags.trigger = 1; + acpi_sci_flags = ACPI_MADT_TRIGGER_EDGE | + (acpi_sci_flags & ~ACPI_MADT_TRIGGER_MASK); else if (!strcmp(s, "level")) - acpi_sci_flags.trigger = 3; + acpi_sci_flags = ACPI_MADT_TRIGGER_LEVEL | + (acpi_sci_flags & ~ACPI_MADT_TRIGGER_MASK); else if (!strcmp(s, "high")) - acpi_sci_flags.polarity = 1; + acpi_sci_flags = ACPI_MADT_POLARITY_ACTIVE_HIGH | + (acpi_sci_flags & ~ACPI_MADT_POLARITY_MASK); else if (!strcmp(s, "low")) - acpi_sci_flags.polarity = 3; + acpi_sci_flags = ACPI_MADT_POLARITY_ACTIVE_LOW | + (acpi_sci_flags & ~ACPI_MADT_POLARITY_MASK); else return -EINVAL; return 0; diff --git a/arch/i386/kernel/acpi/earlyquirk.c b/arch/i386/kernel/acpi/earlyquirk.c index 4b60af7..bf86f76 100644 --- a/arch/i386/kernel/acpi/earlyquirk.c +++ b/arch/i386/kernel/acpi/earlyquirk.c @@ -16,7 +16,7 @@ #ifdef CONFIG_ACPI static int nvidia_hpet_detected __initdata; -static int __init nvidia_hpet_check(unsigned long phys, unsigned long size) +static int __init nvidia_hpet_check(struct acpi_table_header *header) { nvidia_hpet_detected = 1; return 0; @@ -30,7 +30,7 @@ #ifdef CONFIG_ACPI is enabled. */ if (!acpi_use_timer_override && vendor == PCI_VENDOR_ID_NVIDIA) { nvidia_hpet_detected = 0; - acpi_table_parse(ACPI_HPET, nvidia_hpet_check); + acpi_table_parse(ACPI_SIG_HPET, nvidia_hpet_check); if (nvidia_hpet_detected == 0) { acpi_skip_timer_override = 1; printk(KERN_INFO "Nvidia board " diff --git a/arch/i386/kernel/apic.c b/arch/i386/kernel/apic.c index 776d9be..9655c23 100644 --- a/arch/i386/kernel/apic.c +++ b/arch/i386/kernel/apic.c @@ -25,6 +25,8 @@ #include #include #include #include +#include +#include #include #include @@ -36,6 +38,7 @@ #include #include #include #include +#include #include #include @@ -44,128 +47,549 @@ #include #include "io_ports.h" /* - * cpu_mask that denotes the CPUs that needs timer interrupt coming in as - * IPIs in place of local APIC timers + * Sanity check */ -static cpumask_t timer_bcast_ipi; +#if (SPURIOUS_APIC_VECTOR & 0x0F) != 0x0F +# error SPURIOUS_APIC_VECTOR definition error +#endif /* * Knob to control our willingness to enable the local APIC. + * + * -1=force-disable, +1=force-enable */ -static int enable_local_apic __initdata = 0; /* -1=force-disable, +1=force-enable */ - -static inline void lapic_disable(void) -{ - enable_local_apic = -1; - clear_bit(X86_FEATURE_APIC, boot_cpu_data.x86_capability); -} +static int enable_local_apic __initdata = 0; -static inline void lapic_enable(void) -{ - enable_local_apic = 1; -} +/* Local APIC timer verification ok */ +static int local_apic_timer_verify_ok; /* - * Debug level + * Debug level, exported for io_apic.c */ int apic_verbosity; +static unsigned int calibration_result; +static int lapic_next_event(unsigned long delta, + struct clock_event_device *evt); +static void lapic_timer_setup(enum clock_event_mode mode, + struct clock_event_device *evt); +static void lapic_timer_broadcast(cpumask_t mask); static void apic_pm_activate(void); +/* + * The local apic timer can be used for any function which is CPU local. + */ +static struct clock_event_device lapic_clockevent = { + .name = "lapic", + .features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT + | CLOCK_EVT_FEAT_C3STOP | CLOCK_EVT_FEAT_DUMMY, + .shift = 32, + .set_mode = lapic_timer_setup, + .set_next_event = lapic_next_event, + .broadcast = lapic_timer_broadcast, + .rating = 100, + .irq = -1, +}; +static DEFINE_PER_CPU(struct clock_event_device, lapic_events); + +/* Local APIC was disabled by the BIOS and enabled by the kernel */ +static int enabled_via_apicbase; + +/* + * Get the LAPIC version + */ +static inline int lapic_get_version(void) +{ + return GET_APIC_VERSION(apic_read(APIC_LVR)); +} + +/* + * Check, if the APIC is integrated or a seperate chip + */ +static inline int lapic_is_integrated(void) +{ + return APIC_INTEGRATED(lapic_get_version()); +} + +/* + * Check, whether this is a modern or a first generation APIC + */ static int modern_apic(void) { - unsigned int lvr, version; /* AMD systems use old APIC versions, so check the CPU */ if (boot_cpu_data.x86_vendor == X86_VENDOR_AMD && - boot_cpu_data.x86 >= 0xf) + boot_cpu_data.x86 >= 0xf) return 1; - lvr = apic_read(APIC_LVR); - version = GET_APIC_VERSION(lvr); - return version >= 0x14; + return lapic_get_version() >= 0x14; } +/** + * enable_NMI_through_LVT0 - enable NMI through local vector table 0 + */ +void enable_NMI_through_LVT0 (void * dummy) +{ + unsigned int v = APIC_DM_NMI; + + /* Level triggered for 82489DX */ + if (!lapic_is_integrated()) + v |= APIC_LVT_LEVEL_TRIGGER; + apic_write_around(APIC_LVT0, v); +} + +/** + * get_physical_broadcast - Get number of physical broadcast IDs + */ +int get_physical_broadcast(void) +{ + return modern_apic() ? 0xff : 0xf; +} + +/** + * lapic_get_maxlvt - get the maximum number of local vector table entries + */ +int lapic_get_maxlvt(void) +{ + unsigned int v = apic_read(APIC_LVR); + + /* 82489DXs do not report # of LVT entries. */ + return APIC_INTEGRATED(GET_APIC_VERSION(v)) ? GET_APIC_MAXLVT(v) : 2; +} + +/* + * Local APIC timer + */ + +/* Clock divisor is set to 16 */ +#define APIC_DIVISOR 16 + /* - * 'what should we do if we get a hw irq event on an illegal vector'. - * each architecture has to answer this themselves. + * This function sets up the local APIC timer, with a timeout of + * 'clocks' APIC bus clock. During calibration we actually call + * this function twice on the boot CPU, once with a bogus timeout + * value, second time for real. The other (noncalibrating) CPUs + * call this function only once, with the real, calibrated value. + * + * We do reads before writes even if unnecessary, to get around the + * P5 APIC double write bug. */ -void ack_bad_irq(unsigned int irq) +static void __setup_APIC_LVTT(unsigned int clocks, int oneshot, int irqen) { - printk("unexpected IRQ trap at vector %02x\n", irq); + unsigned int lvtt_value, tmp_value; + + lvtt_value = LOCAL_TIMER_VECTOR; + if (!oneshot) + lvtt_value |= APIC_LVT_TIMER_PERIODIC; + if (!lapic_is_integrated()) + lvtt_value |= SET_APIC_TIMER_BASE(APIC_TIMER_BASE_DIV); + + if (!irqen) + lvtt_value |= APIC_LVT_MASKED; + + apic_write_around(APIC_LVTT, lvtt_value); + /* - * Currently unexpected vectors happen only on SMP and APIC. - * We _must_ ack these because every local APIC has only N - * irq slots per priority level, and a 'hanging, unacked' IRQ - * holds up an irq slot - in excessive cases (when multiple - * unexpected vectors occur) that might lock up the APIC - * completely. - * But only ack when the APIC is enabled -AK + * Divide PICLK by 16 */ - if (cpu_has_apic) - ack_APIC_irq(); + tmp_value = apic_read(APIC_TDCR); + apic_write_around(APIC_TDCR, (tmp_value + & ~(APIC_TDR_DIV_1 | APIC_TDR_DIV_TMBASE)) + | APIC_TDR_DIV_16); + + if (!oneshot) + apic_write_around(APIC_TMICT, clocks/APIC_DIVISOR); } -void __init apic_intr_init(void) +/* + * Program the next event, relative to now + */ +static int lapic_next_event(unsigned long delta, + struct clock_event_device *evt) +{ + apic_write_around(APIC_TMICT, delta); + return 0; +} + +/* + * Setup the lapic timer in periodic or oneshot mode + */ +static void lapic_timer_setup(enum clock_event_mode mode, + struct clock_event_device *evt) +{ + unsigned long flags; + unsigned int v; + + /* Lapic used for broadcast ? */ + if (!local_apic_timer_verify_ok) + return; + + local_irq_save(flags); + + switch (mode) { + case CLOCK_EVT_MODE_PERIODIC: + case CLOCK_EVT_MODE_ONESHOT: + __setup_APIC_LVTT(calibration_result, + mode != CLOCK_EVT_MODE_PERIODIC, 1); + break; + case CLOCK_EVT_MODE_UNUSED: + case CLOCK_EVT_MODE_SHUTDOWN: + v = apic_read(APIC_LVTT); + v |= (APIC_LVT_MASKED | LOCAL_TIMER_VECTOR); + apic_write_around(APIC_LVTT, v); + break; + } + + local_irq_restore(flags); +} + +/* + * Local APIC timer broadcast function + */ +static void lapic_timer_broadcast(cpumask_t mask) { #ifdef CONFIG_SMP - smp_intr_init(); + send_IPI_mask(mask, LOCAL_TIMER_VECTOR); #endif - /* self generated IPI for local APIC timer */ - set_intr_gate(LOCAL_TIMER_VECTOR, apic_timer_interrupt); +} - /* IPI vectors for APIC spurious and error interrupts */ - set_intr_gate(SPURIOUS_APIC_VECTOR, spurious_interrupt); - set_intr_gate(ERROR_APIC_VECTOR, error_interrupt); +/* + * Setup the local APIC timer for this CPU. Copy the initilized values + * of the boot CPU and register the clock event in the framework. + */ +static void __devinit setup_APIC_timer(void) +{ + struct clock_event_device *levt = &__get_cpu_var(lapic_events); - /* thermal monitor LVT interrupt */ -#ifdef CONFIG_X86_MCE_P4THERMAL - set_intr_gate(THERMAL_APIC_VECTOR, thermal_interrupt); -#endif + memcpy(levt, &lapic_clockevent, sizeof(*levt)); + levt->cpumask = cpumask_of_cpu(smp_processor_id()); + + clockevents_register_device(levt); } -/* Using APIC to generate smp_local_timer_interrupt? */ -int using_apic_timer __read_mostly = 0; +/* + * In this functions we calibrate APIC bus clocks to the external timer. + * + * We want to do the calibration only once since we want to have local timer + * irqs syncron. CPUs connected by the same APIC bus have the very same bus + * frequency. + * + * This was previously done by reading the PIT/HPET and waiting for a wrap + * around to find out, that a tick has elapsed. I have a box, where the PIT + * readout is broken, so it never gets out of the wait loop again. This was + * also reported by others. + * + * Monitoring the jiffies value is inaccurate and the clockevents + * infrastructure allows us to do a simple substitution of the interrupt + * handler. + * + * The calibration routine also uses the pm_timer when possible, as the PIT + * happens to run way too slow (factor 2.3 on my VAIO CoreDuo, which goes + * back to normal later in the boot process). + */ + +#define LAPIC_CAL_LOOPS (HZ/10) -static int enabled_via_apicbase; +static __initdata volatile int lapic_cal_loops = -1; +static __initdata long lapic_cal_t1, lapic_cal_t2; +static __initdata unsigned long long lapic_cal_tsc1, lapic_cal_tsc2; +static __initdata unsigned long lapic_cal_pm1, lapic_cal_pm2; +static __initdata unsigned long lapic_cal_j1, lapic_cal_j2; -void enable_NMI_through_LVT0 (void * dummy) +/* + * Temporary interrupt handler. + */ +static void __init lapic_cal_handler(struct clock_event_device *dev) { - unsigned int v, ver; + unsigned long long tsc = 0; + long tapic = apic_read(APIC_TMCCT); + unsigned long pm = acpi_pm_read_early(); - ver = apic_read(APIC_LVR); - ver = GET_APIC_VERSION(ver); - v = APIC_DM_NMI; /* unmask and set to NMI */ - if (!APIC_INTEGRATED(ver)) /* 82489DX */ - v |= APIC_LVT_LEVEL_TRIGGER; - apic_write_around(APIC_LVT0, v); + if (cpu_has_tsc) + rdtscll(tsc); + + switch (lapic_cal_loops++) { + case 0: + lapic_cal_t1 = tapic; + lapic_cal_tsc1 = tsc; + lapic_cal_pm1 = pm; + lapic_cal_j1 = jiffies; + break; + + case LAPIC_CAL_LOOPS: + lapic_cal_t2 = tapic; + lapic_cal_tsc2 = tsc; + if (pm < lapic_cal_pm1) + pm += ACPI_PM_OVRRUN; + lapic_cal_pm2 = pm; + lapic_cal_j2 = jiffies; + break; + } } -int get_physical_broadcast(void) +/* + * Setup the boot APIC + * + * Calibrate and verify the result. + */ +void __init setup_boot_APIC_clock(void) { - if (modern_apic()) - return 0xff; - else - return 0xf; + struct clock_event_device *levt = &__get_cpu_var(lapic_events); + const long pm_100ms = PMTMR_TICKS_PER_SEC/10; + const long pm_thresh = pm_100ms/100; + void (*real_handler)(struct clock_event_device *dev); + unsigned long deltaj; + long delta, deltapm; + + apic_printk(APIC_VERBOSE, "Using local APIC timer interrupts.\n" + "calibrating APIC timer ...\n"); + + local_irq_disable(); + + /* Replace the global interrupt handler */ + real_handler = global_clock_event->event_handler; + global_clock_event->event_handler = lapic_cal_handler; + + /* + * Setup the APIC counter to 1e9. There is no way the lapic + * can underflow in the 100ms detection time frame + */ + __setup_APIC_LVTT(1000000000, 0, 0); + + /* Let the interrupts run */ + local_irq_enable(); + + while(lapic_cal_loops <= LAPIC_CAL_LOOPS); + + local_irq_disable(); + + /* Restore the real event handler */ + global_clock_event->event_handler = real_handler; + + /* Build delta t1-t2 as apic timer counts down */ + delta = lapic_cal_t1 - lapic_cal_t2; + apic_printk(APIC_VERBOSE, "... lapic delta = %ld\n", delta); + + /* Check, if the PM timer is available */ + deltapm = lapic_cal_pm2 - lapic_cal_pm1; + apic_printk(APIC_VERBOSE, "... PM timer delta = %ld\n", deltapm); + + if (deltapm) { + unsigned long mult; + u64 res; + + mult = clocksource_hz2mult(PMTMR_TICKS_PER_SEC, 22); + + if (deltapm > (pm_100ms - pm_thresh) && + deltapm < (pm_100ms + pm_thresh)) { + apic_printk(APIC_VERBOSE, "... PM timer result ok\n"); + } else { + res = (((u64) deltapm) * mult) >> 22; + do_div(res, 1000000); + printk(KERN_WARNING "APIC calibration not consistent " + "with PM Timer: %ldms instead of 100ms\n", + (long)res); + /* Correct the lapic counter value */ + res = (((u64) delta ) * pm_100ms); + do_div(res, deltapm); + printk(KERN_INFO "APIC delta adjusted to PM-Timer: " + "%lu (%ld)\n", (unsigned long) res, delta); + delta = (long) res; + } + } + + /* Calculate the scaled math multiplication factor */ + lapic_clockevent.mult = div_sc(delta, TICK_NSEC * LAPIC_CAL_LOOPS, 32); + lapic_clockevent.max_delta_ns = + clockevent_delta2ns(0x7FFFFF, &lapic_clockevent); + lapic_clockevent.min_delta_ns = + clockevent_delta2ns(0xF, &lapic_clockevent); + + calibration_result = (delta * APIC_DIVISOR) / LAPIC_CAL_LOOPS; + + apic_printk(APIC_VERBOSE, "..... delta %ld\n", delta); + apic_printk(APIC_VERBOSE, "..... mult: %ld\n", lapic_clockevent.mult); + apic_printk(APIC_VERBOSE, "..... calibration result: %u\n", + calibration_result); + + if (cpu_has_tsc) { + delta = (long)(lapic_cal_tsc2 - lapic_cal_tsc1); + apic_printk(APIC_VERBOSE, "..... CPU clock speed is " + "%ld.%04ld MHz.\n", + (delta / LAPIC_CAL_LOOPS) / (1000000 / HZ), + (delta / LAPIC_CAL_LOOPS) % (1000000 / HZ)); + } + + apic_printk(APIC_VERBOSE, "..... host bus clock speed is " + "%u.%04u MHz.\n", + calibration_result / (1000000 / HZ), + calibration_result % (1000000 / HZ)); + + + apic_printk(APIC_VERBOSE, "... verify APIC timer\n"); + + /* + * Setup the apic timer manually + */ + local_apic_timer_verify_ok = 1; + levt->event_handler = lapic_cal_handler; + lapic_timer_setup(CLOCK_EVT_MODE_PERIODIC, levt); + lapic_cal_loops = -1; + + /* Let the interrupts run */ + local_irq_enable(); + + while(lapic_cal_loops <= LAPIC_CAL_LOOPS); + + local_irq_disable(); + + /* Stop the lapic timer */ + lapic_timer_setup(CLOCK_EVT_MODE_SHUTDOWN, levt); + + local_irq_enable(); + + /* Jiffies delta */ + deltaj = lapic_cal_j2 - lapic_cal_j1; + apic_printk(APIC_VERBOSE, "... jiffies delta = %lu\n", deltaj); + + /* Check, if the PM timer is available */ + deltapm = lapic_cal_pm2 - lapic_cal_pm1; + apic_printk(APIC_VERBOSE, "... PM timer delta = %ld\n", deltapm); + + local_apic_timer_verify_ok = 0; + + if (deltapm) { + if (deltapm > (pm_100ms - pm_thresh) && + deltapm < (pm_100ms + pm_thresh)) { + apic_printk(APIC_VERBOSE, "... PM timer result ok\n"); + /* Check, if the jiffies result is consistent */ + if (deltaj < LAPIC_CAL_LOOPS-2 || + deltaj > LAPIC_CAL_LOOPS+2) { + /* + * Not sure, what we can do about this one. + * When high resultion timers are active + * and the lapic timer does not stop in C3 + * we are fine. Otherwise more trouble might + * be waiting. -- tglx + */ + printk(KERN_WARNING "Global event device %s " + "has wrong frequency " + "(%lu ticks instead of %d)\n", + global_clock_event->name, deltaj, + LAPIC_CAL_LOOPS); + } + local_apic_timer_verify_ok = 1; + } + } else { + /* Check, if the jiffies result is consistent */ + if (deltaj >= LAPIC_CAL_LOOPS-2 && + deltaj <= LAPIC_CAL_LOOPS+2) { + apic_printk(APIC_VERBOSE, "... jiffies result ok\n"); + local_apic_timer_verify_ok = 1; + } + } + + if (!local_apic_timer_verify_ok) { + printk(KERN_WARNING + "APIC timer disabled due to verification failure.\n"); + /* No broadcast on UP ! */ + if (num_possible_cpus() == 1) + return; + } else + lapic_clockevent.features &= ~CLOCK_EVT_FEAT_DUMMY; + + /* Setup the lapic or request the broadcast */ + setup_APIC_timer(); +} + +void __devinit setup_secondary_APIC_clock(void) +{ + setup_APIC_timer(); } -int get_maxlvt(void) +/* + * The guts of the apic timer interrupt + */ +static void local_apic_timer_interrupt(void) { - unsigned int v, ver, maxlvt; + int cpu = smp_processor_id(); + struct clock_event_device *evt = &per_cpu(lapic_events, cpu); - v = apic_read(APIC_LVR); - ver = GET_APIC_VERSION(v); - /* 82489DXs do not report # of LVT entries. */ - maxlvt = APIC_INTEGRATED(ver) ? GET_APIC_MAXLVT(v) : 2; - return maxlvt; + /* + * Normally we should not be here till LAPIC has been initialized but + * in some cases like kdump, its possible that there is a pending LAPIC + * timer interrupt from previous kernel's context and is delivered in + * new kernel the moment interrupts are enabled. + * + * Interrupts are enabled early and LAPIC is setup much later, hence + * its possible that when we get here evt->event_handler is NULL. + * Check for event_handler being NULL and discard the interrupt as + * spurious. + */ + if (!evt->event_handler) { + printk(KERN_WARNING + "Spurious LAPIC timer interrupt on cpu %d\n", cpu); + /* Switch it off */ + lapic_timer_setup(CLOCK_EVT_MODE_SHUTDOWN, evt); + return; + } + + per_cpu(irq_stat, cpu).apic_timer_irqs++; + + evt->event_handler(evt); } +/* + * Local APIC timer interrupt. This is the most natural way for doing + * local interrupts, but local timer interrupts can be emulated by + * broadcast interrupts too. [in case the hw doesn't support APIC timers] + * + * [ if a single-CPU system runs an SMP kernel then we call the local + * interrupt as well. Thus we cannot inline the local irq ... ] + */ + +void fastcall smp_apic_timer_interrupt(struct pt_regs *regs) +{ + struct pt_regs *old_regs = set_irq_regs(regs); + + /* + * NOTE! We'd better ACK the irq immediately, + * because timer handling can be slow. + */ + ack_APIC_irq(); + /* + * update_process_times() expects us to have done irq_enter(). + * Besides, if we don't timer interrupts ignore the global + * interrupt lock, which is the WrongThing (tm) to do. + */ + exit_idle(); + irq_enter(); + local_apic_timer_interrupt(); + irq_exit(); + + set_irq_regs(old_regs); +} + +int setup_profiling_timer(unsigned int multiplier) +{ + return -EINVAL; +} + +/* + * Local APIC start and shutdown + */ + +/** + * clear_local_APIC - shutdown the local APIC + * + * This is called, when a CPU is disabled and before rebooting, so the state of + * the local APIC has no dangling leftovers. Also used to cleanout any BIOS + * leftovers during boot. + */ void clear_local_APIC(void) { - int maxlvt; + int maxlvt = lapic_get_maxlvt(); unsigned long v; - maxlvt = get_maxlvt(); - /* * Masking an LVT entry can trigger a local APIC error * if the vector is zero. Mask LVTERR first to prevent this. @@ -189,7 +613,7 @@ void clear_local_APIC(void) apic_write_around(APIC_LVTPC, v | APIC_LVT_MASKED); } -/* lets not touch this if we didn't frob it */ + /* lets not touch this if we didn't frob it */ #ifdef CONFIG_X86_MCE_P4THERMAL if (maxlvt >= 5) { v = apic_read(APIC_LVTTHMR); @@ -211,85 +635,18 @@ #ifdef CONFIG_X86_MCE_P4THERMAL if (maxlvt >= 5) apic_write_around(APIC_LVTTHMR, APIC_LVT_MASKED); #endif - v = GET_APIC_VERSION(apic_read(APIC_LVR)); - if (APIC_INTEGRATED(v)) { /* !82489DX */ - if (maxlvt > 3) /* Due to Pentium errata 3AP and 11AP. */ + /* Integrated APIC (!82489DX) ? */ + if (lapic_is_integrated()) { + if (maxlvt > 3) + /* Clear ESR due to Pentium errata 3AP and 11AP */ apic_write(APIC_ESR, 0); apic_read(APIC_ESR); } } -void __init connect_bsp_APIC(void) -{ - if (pic_mode) { - /* - * Do not trust the local APIC being empty at bootup. - */ - clear_local_APIC(); - /* - * PIC mode, enable APIC mode in the IMCR, i.e. - * connect BSP's local APIC to INT and NMI lines. - */ - apic_printk(APIC_VERBOSE, "leaving PIC mode, " - "enabling APIC mode.\n"); - outb(0x70, 0x22); - outb(0x01, 0x23); - } - enable_apic_mode(); -} - -void disconnect_bsp_APIC(int virt_wire_setup) -{ - if (pic_mode) { - /* - * Put the board back into PIC mode (has an effect - * only on certain older boards). Note that APIC - * interrupts, including IPIs, won't work beyond - * this point! The only exception are INIT IPIs. - */ - apic_printk(APIC_VERBOSE, "disabling APIC mode, " - "entering PIC mode.\n"); - outb(0x70, 0x22); - outb(0x00, 0x23); - } - else { - /* Go back to Virtual Wire compatibility mode */ - unsigned long value; - - /* For the spurious interrupt use vector F, and enable it */ - value = apic_read(APIC_SPIV); - value &= ~APIC_VECTOR_MASK; - value |= APIC_SPIV_APIC_ENABLED; - value |= 0xf; - apic_write_around(APIC_SPIV, value); - - if (!virt_wire_setup) { - /* For LVT0 make it edge triggered, active high, external and enabled */ - value = apic_read(APIC_LVT0); - value &= ~(APIC_MODE_MASK | APIC_SEND_PENDING | - APIC_INPUT_POLARITY | APIC_LVT_REMOTE_IRR | - APIC_LVT_LEVEL_TRIGGER | APIC_LVT_MASKED ); - value |= APIC_LVT_REMOTE_IRR | APIC_SEND_PENDING; - value = SET_APIC_DELIVERY_MODE(value, APIC_MODE_EXTINT); - apic_write_around(APIC_LVT0, value); - } - else { - /* Disable LVT0 */ - apic_write_around(APIC_LVT0, APIC_LVT_MASKED); - } - - /* For LVT1 make it edge triggered, active high, nmi and enabled */ - value = apic_read(APIC_LVT1); - value &= ~( - APIC_MODE_MASK | APIC_SEND_PENDING | - APIC_INPUT_POLARITY | APIC_LVT_REMOTE_IRR | - APIC_LVT_LEVEL_TRIGGER | APIC_LVT_MASKED); - value |= APIC_LVT_REMOTE_IRR | APIC_SEND_PENDING; - value = SET_APIC_DELIVERY_MODE(value, APIC_MODE_NMI); - apic_write_around(APIC_LVT1, value); - } -} - +/** + * disable_local_APIC - clear and disable the local APIC + */ void disable_local_APIC(void) { unsigned long value; @@ -304,8 +661,13 @@ void disable_local_APIC(void) value &= ~APIC_SPIV_APIC_ENABLED; apic_write_around(APIC_SPIV, value); + /* + * When LAPIC was disabled by the BIOS and enabled by the kernel, + * restore the disabled state. + */ if (enabled_via_apicbase) { unsigned int l, h; + rdmsr(MSR_IA32_APICBASE, l, h); l &= ~MSR_IA32_APICBASE_ENABLE; wrmsr(MSR_IA32_APICBASE, l, h); @@ -313,6 +675,28 @@ void disable_local_APIC(void) } /* + * If Linux enabled the LAPIC against the BIOS default disable it down before + * re-entering the BIOS on shutdown. Otherwise the BIOS may get confused and + * not power-off. Additionally clear all LVT entries before disable_local_APIC + * for the case where Linux didn't enable the LAPIC. + */ +void lapic_shutdown(void) +{ + unsigned long flags; + + if (!cpu_has_apic) + return; + + local_irq_save(flags); + clear_local_APIC(); + + if (enabled_via_apicbase) + disable_local_APIC(); + + local_irq_restore(flags); +} + +/* * This is to verify that we're looking at a real local APIC. * Check these against your board if the CPUs aren't getting * started for no apparent reason. @@ -344,7 +728,7 @@ int __init verify_local_APIC(void) reg1 = GET_APIC_VERSION(reg0); if (reg1 == 0x00 || reg1 == 0xff) return 0; - reg1 = get_maxlvt(); + reg1 = lapic_get_maxlvt(); if (reg1 < 0x02 || reg1 == 0xff) return 0; @@ -367,10 +751,15 @@ int __init verify_local_APIC(void) return 1; } +/** + * sync_Arb_IDs - synchronize APIC bus arbitration IDs + */ void __init sync_Arb_IDs(void) { - /* Unsupported on P4 - see Intel Dev. Manual Vol. 3, Ch. 8.6.1 - And not needed on AMD */ + /* + * Unsupported on P4 - see Intel Dev. Manual Vol. 3, Ch. 8.6.1 And not + * needed on AMD. + */ if (modern_apic()) return; /* @@ -383,14 +772,12 @@ void __init sync_Arb_IDs(void) | APIC_DM_INIT); } -extern void __error_in_apic_c (void); - /* * An initial setup of the virtual wire mode. */ void __init init_bsp_APIC(void) { - unsigned long value, ver; + unsigned long value; /* * Don't do the setup now if we have a SMP BIOS as the @@ -399,9 +786,6 @@ void __init init_bsp_APIC(void) if (smp_found_config || !cpu_has_apic) return; - value = apic_read(APIC_LVR); - ver = GET_APIC_VERSION(value); - /* * Do not trust the local APIC being empty at bootup. */ @@ -413,9 +797,10 @@ void __init init_bsp_APIC(void) value = apic_read(APIC_SPIV); value &= ~APIC_VECTOR_MASK; value |= APIC_SPIV_APIC_ENABLED; - + /* This bit is reserved on P4/Xeon and should be cleared */ - if ((boot_cpu_data.x86_vendor == X86_VENDOR_INTEL) && (boot_cpu_data.x86 == 15)) + if ((boot_cpu_data.x86_vendor == X86_VENDOR_INTEL) && + (boot_cpu_data.x86 == 15)) value &= ~APIC_SPIV_FOCUS_DISABLED; else value |= APIC_SPIV_FOCUS_DISABLED; @@ -427,14 +812,17 @@ void __init init_bsp_APIC(void) */ apic_write_around(APIC_LVT0, APIC_DM_EXTINT); value = APIC_DM_NMI; - if (!APIC_INTEGRATED(ver)) /* 82489DX */ + if (!lapic_is_integrated()) /* 82489DX */ value |= APIC_LVT_LEVEL_TRIGGER; apic_write_around(APIC_LVT1, value); } +/** + * setup_local_APIC - setup the local APIC + */ void __devinit setup_local_APIC(void) { - unsigned long oldvalue, value, ver, maxlvt; + unsigned long oldvalue, value, maxlvt, integrated; int i, j; /* Pound the ESR really hard over the head with a big hammer - mbligh */ @@ -445,11 +833,7 @@ void __devinit setup_local_APIC(void) apic_write(APIC_ESR, 0); } - value = apic_read(APIC_LVR); - ver = GET_APIC_VERSION(value); - - if ((SPURIOUS_APIC_VECTOR & 0x0f) != 0x0f) - __error_in_apic_c(); + integrated = lapic_is_integrated(); /* * Double-check whether this APIC is really registered. @@ -520,13 +904,10 @@ void __devinit setup_local_APIC(void) * like LRU than MRU (the short-term load is more even across CPUs). * See also the comment in end_level_ioapic_irq(). --macro */ -#if 1 + /* Enable focus processor (bit==0) */ value &= ~APIC_SPIV_FOCUS_DISABLED; -#else - /* Disable focus processor (bit==1) */ - value |= APIC_SPIV_FOCUS_DISABLED; -#endif + /* * Set spurious IRQ vector */ @@ -562,17 +943,18 @@ #endif value = APIC_DM_NMI; else value = APIC_DM_NMI | APIC_LVT_MASKED; - if (!APIC_INTEGRATED(ver)) /* 82489DX */ + if (!integrated) /* 82489DX */ value |= APIC_LVT_LEVEL_TRIGGER; apic_write_around(APIC_LVT1, value); - if (APIC_INTEGRATED(ver) && !esr_disable) { /* !82489DX */ - maxlvt = get_maxlvt(); + if (integrated && !esr_disable) { /* !82489DX */ + maxlvt = lapic_get_maxlvt(); if (maxlvt > 3) /* Due to the Pentium erratum 3AP. */ apic_write(APIC_ESR, 0); oldvalue = apic_read(APIC_ESR); - value = ERROR_APIC_VECTOR; // enables sending errors + /* enables sending errors */ + value = ERROR_APIC_VECTOR; apic_write_around(APIC_LVTERR, value); /* * spec says clear errors after enabling vector. @@ -585,207 +967,30 @@ #endif "vector: 0x%08lx after: 0x%08lx\n", oldvalue, value); } else { - if (esr_disable) - /* - * Something untraceble is creating bad interrupts on + if (esr_disable) + /* + * Something untraceble is creating bad interrupts on * secondary quads ... for the moment, just leave the * ESR disabled - we can't do anything useful with the * errors anyway - mbligh */ - printk("Leaving ESR disabled.\n"); - else - printk("No ESR for 82489DX.\n"); + printk(KERN_INFO "Leaving ESR disabled.\n"); + else + printk(KERN_INFO "No ESR for 82489DX.\n"); } + /* Disable the local apic timer */ + value = apic_read(APIC_LVTT); + value |= (APIC_LVT_MASKED | LOCAL_TIMER_VECTOR); + apic_write_around(APIC_LVTT, value); + setup_apic_nmi_watchdog(NULL); apic_pm_activate(); } /* - * If Linux enabled the LAPIC against the BIOS default - * disable it down before re-entering the BIOS on shutdown. - * Otherwise the BIOS may get confused and not power-off. - * Additionally clear all LVT entries before disable_local_APIC - * for the case where Linux didn't enable the LAPIC. + * Detect and initialize APIC */ -void lapic_shutdown(void) -{ - unsigned long flags; - - if (!cpu_has_apic) - return; - - local_irq_save(flags); - clear_local_APIC(); - - if (enabled_via_apicbase) - disable_local_APIC(); - - local_irq_restore(flags); -} - -#ifdef CONFIG_PM - -static struct { - int active; - /* r/w apic fields */ - unsigned int apic_id; - unsigned int apic_taskpri; - unsigned int apic_ldr; - unsigned int apic_dfr; - unsigned int apic_spiv; - unsigned int apic_lvtt; - unsigned int apic_lvtpc; - unsigned int apic_lvt0; - unsigned int apic_lvt1; - unsigned int apic_lvterr; - unsigned int apic_tmict; - unsigned int apic_tdcr; - unsigned int apic_thmr; -} apic_pm_state; - -static int lapic_suspend(struct sys_device *dev, pm_message_t state) -{ - unsigned long flags; - int maxlvt; - - if (!apic_pm_state.active) - return 0; - - maxlvt = get_maxlvt(); - - apic_pm_state.apic_id = apic_read(APIC_ID); - apic_pm_state.apic_taskpri = apic_read(APIC_TASKPRI); - apic_pm_state.apic_ldr = apic_read(APIC_LDR); - apic_pm_state.apic_dfr = apic_read(APIC_DFR); - apic_pm_state.apic_spiv = apic_read(APIC_SPIV); - apic_pm_state.apic_lvtt = apic_read(APIC_LVTT); - if (maxlvt >= 4) - apic_pm_state.apic_lvtpc = apic_read(APIC_LVTPC); - apic_pm_state.apic_lvt0 = apic_read(APIC_LVT0); - apic_pm_state.apic_lvt1 = apic_read(APIC_LVT1); - apic_pm_state.apic_lvterr = apic_read(APIC_LVTERR); - apic_pm_state.apic_tmict = apic_read(APIC_TMICT); - apic_pm_state.apic_tdcr = apic_read(APIC_TDCR); -#ifdef CONFIG_X86_MCE_P4THERMAL - if (maxlvt >= 5) - apic_pm_state.apic_thmr = apic_read(APIC_LVTTHMR); -#endif - - local_irq_save(flags); - disable_local_APIC(); - local_irq_restore(flags); - return 0; -} - -static int lapic_resume(struct sys_device *dev) -{ - unsigned int l, h; - unsigned long flags; - int maxlvt; - - if (!apic_pm_state.active) - return 0; - - maxlvt = get_maxlvt(); - - local_irq_save(flags); - - /* - * Make sure the APICBASE points to the right address - * - * FIXME! This will be wrong if we ever support suspend on - * SMP! We'll need to do this as part of the CPU restore! - */ - rdmsr(MSR_IA32_APICBASE, l, h); - l &= ~MSR_IA32_APICBASE_BASE; - l |= MSR_IA32_APICBASE_ENABLE | mp_lapic_addr; - wrmsr(MSR_IA32_APICBASE, l, h); - - apic_write(APIC_LVTERR, ERROR_APIC_VECTOR | APIC_LVT_MASKED); - apic_write(APIC_ID, apic_pm_state.apic_id); - apic_write(APIC_DFR, apic_pm_state.apic_dfr); - apic_write(APIC_LDR, apic_pm_state.apic_ldr); - apic_write(APIC_TASKPRI, apic_pm_state.apic_taskpri); - apic_write(APIC_SPIV, apic_pm_state.apic_spiv); - apic_write(APIC_LVT0, apic_pm_state.apic_lvt0); - apic_write(APIC_LVT1, apic_pm_state.apic_lvt1); -#ifdef CONFIG_X86_MCE_P4THERMAL - if (maxlvt >= 5) - apic_write(APIC_LVTTHMR, apic_pm_state.apic_thmr); -#endif - if (maxlvt >= 4) - apic_write(APIC_LVTPC, apic_pm_state.apic_lvtpc); - apic_write(APIC_LVTT, apic_pm_state.apic_lvtt); - apic_write(APIC_TDCR, apic_pm_state.apic_tdcr); - apic_write(APIC_TMICT, apic_pm_state.apic_tmict); - apic_write(APIC_ESR, 0); - apic_read(APIC_ESR); - apic_write(APIC_LVTERR, apic_pm_state.apic_lvterr); - apic_write(APIC_ESR, 0); - apic_read(APIC_ESR); - local_irq_restore(flags); - return 0; -} - -/* - * This device has no shutdown method - fully functioning local APICs - * are needed on every CPU up until machine_halt/restart/poweroff. - */ - -static struct sysdev_class lapic_sysclass = { - set_kset_name("lapic"), - .resume = lapic_resume, - .suspend = lapic_suspend, -}; - -static struct sys_device device_lapic = { - .id = 0, - .cls = &lapic_sysclass, -}; - -static void __devinit apic_pm_activate(void) -{ - apic_pm_state.active = 1; -} - -static int __init init_lapic_sysfs(void) -{ - int error; - - if (!cpu_has_apic) - return 0; - /* XXX: remove suspend/resume procs if !apic_pm_state.active? */ - - error = sysdev_class_register(&lapic_sysclass); - if (!error) - error = sysdev_register(&device_lapic); - return error; -} -device_initcall(init_lapic_sysfs); - -#else /* CONFIG_PM */ - -static void apic_pm_activate(void) { } - -#endif /* CONFIG_PM */ - -/* - * Detect and enable local APICs on non-SMP boards. - * Original code written by Keir Fraser. - */ - -static int __init apic_set_verbosity(char *str) -{ - if (strcmp("debug", str) == 0) - apic_verbosity = APIC_DEBUG; - else if (strcmp("verbose", str) == 0) - apic_verbosity = APIC_VERBOSE; - return 1; -} - -__setup("apic=", apic_set_verbosity); - static int __init detect_init_APIC (void) { u32 h, l, features; @@ -797,7 +1002,7 @@ static int __init detect_init_APIC (void switch (boot_cpu_data.x86_vendor) { case X86_VENDOR_AMD: if ((boot_cpu_data.x86 == 6 && boot_cpu_data.x86_model > 1) || - (boot_cpu_data.x86 == 15)) + (boot_cpu_data.x86 == 15)) break; goto no_apic; case X86_VENDOR_INTEL: @@ -811,23 +1016,23 @@ static int __init detect_init_APIC (void if (!cpu_has_apic) { /* - * Over-ride BIOS and try to enable the local - * APIC only if "lapic" specified. + * Over-ride BIOS and try to enable the local APIC only if + * "lapic" specified. */ if (enable_local_apic <= 0) { - printk("Local APIC disabled by BIOS -- " + printk(KERN_INFO "Local APIC disabled by BIOS -- " "you can enable it with \"lapic\"\n"); return -1; } /* - * Some BIOSes disable the local APIC in the - * APIC_BASE MSR. This can only be done in - * software for Intel P6 or later and AMD K7 - * (Model > 1) or later. + * Some BIOSes disable the local APIC in the APIC_BASE + * MSR. This can only be done in software for Intel P6 or later + * and AMD K7 (Model > 1) or later. */ rdmsr(MSR_IA32_APICBASE, l, h); if (!(l & MSR_IA32_APICBASE_ENABLE)) { - printk("Local APIC disabled by BIOS -- reenabling.\n"); + printk(KERN_INFO + "Local APIC disabled by BIOS -- reenabling.\n"); l &= ~MSR_IA32_APICBASE_BASE; l |= MSR_IA32_APICBASE_ENABLE | APIC_DEFAULT_PHYS_BASE; wrmsr(MSR_IA32_APICBASE, l, h); @@ -840,7 +1045,7 @@ static int __init detect_init_APIC (void */ features = cpuid_edx(1); if (!(features & (1 << X86_FEATURE_APIC))) { - printk("Could not enable APIC!\n"); + printk(KERN_WARNING "Could not enable APIC!\n"); return -1; } set_bit(X86_FEATURE_APIC, boot_cpu_data.x86_capability); @@ -854,17 +1059,20 @@ static int __init detect_init_APIC (void if (nmi_watchdog != NMI_NONE) nmi_watchdog = NMI_LOCAL_APIC; - printk("Found and enabled local APIC!\n"); + printk(KERN_INFO "Found and enabled local APIC!\n"); apic_pm_activate(); return 0; no_apic: - printk("No local APIC present or hardware disabled\n"); + printk(KERN_INFO "No local APIC present or hardware disabled\n"); return -1; } +/** + * init_apic_mappings - initialize APIC mappings + */ void __init init_apic_mappings(void) { unsigned long apic_phys; @@ -924,387 +1132,96 @@ #endif } /* - * This part sets up the APIC 32 bit clock in LVTT1, with HZ interrupts - * per second. We assume that the caller has already set up the local - * APIC. - * - * The APIC timer is not exactly sync with the external timer chip, it - * closely follows bus clocks. - */ - -/* - * The timer chip is already set up at HZ interrupts per second here, - * but we do not accept timer interrupts yet. We only allow the BP - * to calibrate. - */ -static unsigned int __devinit get_8254_timer_count(void) -{ - unsigned long flags; - - unsigned int count; - - spin_lock_irqsave(&i8253_lock, flags); - - outb_p(0x00, PIT_MODE); - count = inb_p(PIT_CH0); - count |= inb_p(PIT_CH0) << 8; - - spin_unlock_irqrestore(&i8253_lock, flags); - - return count; -} - -/* next tick in 8254 can be caught by catching timer wraparound */ -static void __devinit wait_8254_wraparound(void) -{ - unsigned int curr_count, prev_count; - - curr_count = get_8254_timer_count(); - do { - prev_count = curr_count; - curr_count = get_8254_timer_count(); - - /* workaround for broken Mercury/Neptune */ - if (prev_count >= curr_count + 0x100) - curr_count = get_8254_timer_count(); - - } while (prev_count >= curr_count); -} - -/* - * Default initialization for 8254 timers. If we use other timers like HPET, - * we override this later - */ -void (*wait_timer_tick)(void) __devinitdata = wait_8254_wraparound; - -/* - * This function sets up the local APIC timer, with a timeout of - * 'clocks' APIC bus clock. During calibration we actually call - * this function twice on the boot CPU, once with a bogus timeout - * value, second time for real. The other (noncalibrating) CPUs - * call this function only once, with the real, calibrated value. - * - * We do reads before writes even if unnecessary, to get around the - * P5 APIC double write bug. + * This initializes the IO-APIC and APIC hardware if this is + * a UP kernel. */ - -#define APIC_DIVISOR 16 - -static void __setup_APIC_LVTT(unsigned int clocks) +int __init APIC_init_uniprocessor (void) { - unsigned int lvtt_value, tmp_value, ver; - int cpu = smp_processor_id(); - - ver = GET_APIC_VERSION(apic_read(APIC_LVR)); - lvtt_value = APIC_LVT_TIMER_PERIODIC | LOCAL_TIMER_VECTOR; - if (!APIC_INTEGRATED(ver)) - lvtt_value |= SET_APIC_TIMER_BASE(APIC_TIMER_BASE_DIV); - - if (cpu_isset(cpu, timer_bcast_ipi)) - lvtt_value |= APIC_LVT_MASKED; + if (enable_local_apic < 0) + clear_bit(X86_FEATURE_APIC, boot_cpu_data.x86_capability); - apic_write_around(APIC_LVTT, lvtt_value); + if (!smp_found_config && !cpu_has_apic) + return -1; /* - * Divide PICLK by 16 + * Complain if the BIOS pretends there is one. */ - tmp_value = apic_read(APIC_TDCR); - apic_write_around(APIC_TDCR, (tmp_value - & ~(APIC_TDR_DIV_1 | APIC_TDR_DIV_TMBASE)) - | APIC_TDR_DIV_16); - - apic_write_around(APIC_TMICT, clocks/APIC_DIVISOR); -} + if (!cpu_has_apic && + APIC_INTEGRATED(apic_version[boot_cpu_physical_apicid])) { + printk(KERN_ERR "BIOS bug, local APIC #%d not detected!...\n", + boot_cpu_physical_apicid); + clear_bit(X86_FEATURE_APIC, boot_cpu_data.x86_capability); + return -1; + } -static void __devinit setup_APIC_timer(unsigned int clocks) -{ - unsigned long flags; + verify_local_APIC(); - local_irq_save(flags); + connect_bsp_APIC(); /* - * Wait for IRQ0's slice: + * Hack: In case of kdump, after a crash, kernel might be booting + * on a cpu with non-zero lapic id. But boot_cpu_physical_apicid + * might be zero if read from MP tables. Get it from LAPIC. */ - wait_timer_tick(); +#ifdef CONFIG_CRASH_DUMP + boot_cpu_physical_apicid = GET_APIC_ID(apic_read(APIC_ID)); +#endif + phys_cpu_present_map = physid_mask_of_physid(boot_cpu_physical_apicid); - __setup_APIC_LVTT(clocks); + setup_local_APIC(); - local_irq_restore(flags); +#ifdef CONFIG_X86_IO_APIC + if (smp_found_config) + if (!skip_ioapic_setup && nr_ioapics) + setup_IO_APIC(); +#endif + setup_boot_clock(); + + return 0; } /* - * In this function we calibrate APIC bus clocks to the external - * timer. Unfortunately we cannot use jiffies and the timer irq - * to calibrate, since some later bootup code depends on getting - * the first irq? Ugh. - * - * We want to do the calibration only once since we - * want to have local timer irqs syncron. CPUs connected - * by the same APIC bus have the very same bus frequency. - * And we want to have irqs off anyways, no accidental - * APIC irq that way. + * APIC command line parameters */ - -static int __init calibrate_APIC_clock(void) -{ - unsigned long long t1 = 0, t2 = 0; - long tt1, tt2; - long result; - int i; - const int LOOPS = HZ/10; - - apic_printk(APIC_VERBOSE, "calibrating APIC timer ...\n"); - - /* - * Put whatever arbitrary (but long enough) timeout - * value into the APIC clock, we just want to get the - * counter running for calibration. - */ - __setup_APIC_LVTT(1000000000); - - /* - * The timer chip counts down to zero. Let's wait - * for a wraparound to start exact measurement: - * (the current tick might have been already half done) - */ - - wait_timer_tick(); - - /* - * We wrapped around just now. Let's start: - */ - if (cpu_has_tsc) - rdtscll(t1); - tt1 = apic_read(APIC_TMCCT); - - /* - * Let's wait LOOPS wraprounds: - */ - for (i = 0; i < LOOPS; i++) - wait_timer_tick(); - - tt2 = apic_read(APIC_TMCCT); - if (cpu_has_tsc) - rdtscll(t2); - - /* - * The APIC bus clock counter is 32 bits only, it - * might have overflown, but note that we use signed - * longs, thus no extra care needed. - * - * underflown to be exact, as the timer counts down ;) - */ - - result = (tt1-tt2)*APIC_DIVISOR/LOOPS; - - if (cpu_has_tsc) - apic_printk(APIC_VERBOSE, "..... CPU clock speed is " - "%ld.%04ld MHz.\n", - ((long)(t2-t1)/LOOPS)/(1000000/HZ), - ((long)(t2-t1)/LOOPS)%(1000000/HZ)); - - apic_printk(APIC_VERBOSE, "..... host bus clock speed is " - "%ld.%04ld MHz.\n", - result/(1000000/HZ), - result%(1000000/HZ)); - - return result; -} - -static unsigned int calibration_result; - -void __init setup_boot_APIC_clock(void) -{ - unsigned long flags; - apic_printk(APIC_VERBOSE, "Using local APIC timer interrupts.\n"); - using_apic_timer = 1; - - local_irq_save(flags); - - calibration_result = calibrate_APIC_clock(); - /* - * Now set up the timer for real. - */ - setup_APIC_timer(calibration_result); - - local_irq_restore(flags); -} - -void __devinit setup_secondary_APIC_clock(void) -{ - setup_APIC_timer(calibration_result); -} - -void disable_APIC_timer(void) -{ - if (using_apic_timer) { - unsigned long v; - - v = apic_read(APIC_LVTT); - /* - * When an illegal vector value (0-15) is written to an LVT - * entry and delivery mode is Fixed, the APIC may signal an - * illegal vector error, with out regard to whether the mask - * bit is set or whether an interrupt is actually seen on input. - * - * Boot sequence might call this function when the LVTT has - * '0' vector value. So make sure vector field is set to - * valid value. - */ - v |= (APIC_LVT_MASKED | LOCAL_TIMER_VECTOR); - apic_write_around(APIC_LVTT, v); - } -} - -void enable_APIC_timer(void) +static int __init parse_lapic(char *arg) { - int cpu = smp_processor_id(); - - if (using_apic_timer && - !cpu_isset(cpu, timer_bcast_ipi)) { - unsigned long v; - - v = apic_read(APIC_LVTT); - apic_write_around(APIC_LVTT, v & ~APIC_LVT_MASKED); - } + enable_local_apic = 1; + return 0; } +early_param("lapic", parse_lapic); -void switch_APIC_timer_to_ipi(void *cpumask) +static int __init parse_nolapic(char *arg) { - cpumask_t mask = *(cpumask_t *)cpumask; - int cpu = smp_processor_id(); - - if (cpu_isset(cpu, mask) && - !cpu_isset(cpu, timer_bcast_ipi)) { - disable_APIC_timer(); - cpu_set(cpu, timer_bcast_ipi); - } + enable_local_apic = -1; + clear_bit(X86_FEATURE_APIC, boot_cpu_data.x86_capability); + return 0; } -EXPORT_SYMBOL(switch_APIC_timer_to_ipi); +early_param("nolapic", parse_nolapic); -void switch_ipi_to_APIC_timer(void *cpumask) +static int __init apic_set_verbosity(char *str) { - cpumask_t mask = *(cpumask_t *)cpumask; - int cpu = smp_processor_id(); - - if (cpu_isset(cpu, mask) && - cpu_isset(cpu, timer_bcast_ipi)) { - cpu_clear(cpu, timer_bcast_ipi); - enable_APIC_timer(); - } + if (strcmp("debug", str) == 0) + apic_verbosity = APIC_DEBUG; + else if (strcmp("verbose", str) == 0) + apic_verbosity = APIC_VERBOSE; + return 1; } -EXPORT_SYMBOL(switch_ipi_to_APIC_timer); - -#undef APIC_DIVISOR -/* - * Local timer interrupt handler. It does both profiling and - * process statistics/rescheduling. - * - * We do profiling in every local tick, statistics/rescheduling - * happen only every 'profiling multiplier' ticks. The default - * multiplier is 1 and it can be changed by writing the new multiplier - * value into /proc/profile. - */ - -inline void smp_local_timer_interrupt(void) -{ - profile_tick(CPU_PROFILING); -#ifdef CONFIG_SMP - update_process_times(user_mode_vm(get_irq_regs())); -#endif +__setup("apic=", apic_set_verbosity); - /* - * We take the 'long' return path, and there every subsystem - * grabs the apropriate locks (kernel lock/ irq lock). - * - * we might want to decouple profiling from the 'long path', - * and do the profiling totally in assembly. - * - * Currently this isn't too much of an issue (performance wise), - * we can take more than 100K local irqs per second on a 100 MHz P5. - */ -} /* - * Local APIC timer interrupt. This is the most natural way for doing - * local interrupts, but local timer interrupts can be emulated by - * broadcast interrupts too. [in case the hw doesn't support APIC timers] - * - * [ if a single-CPU system runs an SMP kernel then we call the local - * interrupt as well. Thus we cannot inline the local irq ... ] + * Local APIC interrupts */ -fastcall void smp_apic_timer_interrupt(struct pt_regs *regs) -{ - struct pt_regs *old_regs = set_irq_regs(regs); - int cpu = smp_processor_id(); - - /* - * the NMI deadlock-detector uses this. - */ - per_cpu(irq_stat, cpu).apic_timer_irqs++; - - /* - * NOTE! We'd better ACK the irq immediately, - * because timer handling can be slow. - */ - ack_APIC_irq(); - /* - * update_process_times() expects us to have done irq_enter(). - * Besides, if we don't timer interrupts ignore the global - * interrupt lock, which is the WrongThing (tm) to do. - */ - irq_enter(); - smp_local_timer_interrupt(); - irq_exit(); - set_irq_regs(old_regs); -} - -#ifndef CONFIG_SMP -static void up_apic_timer_interrupt_call(void) -{ - int cpu = smp_processor_id(); - - /* - * the NMI deadlock-detector uses this. - */ - per_cpu(irq_stat, cpu).apic_timer_irqs++; - - smp_local_timer_interrupt(); -} -#endif - -void smp_send_timer_broadcast_ipi(void) -{ - cpumask_t mask; - - cpus_and(mask, cpu_online_map, timer_bcast_ipi); - if (!cpus_empty(mask)) { -#ifdef CONFIG_SMP - send_IPI_mask(mask, LOCAL_TIMER_VECTOR); -#else - /* - * We can directly call the apic timer interrupt handler - * in UP case. Minus all irq related functions - */ - up_apic_timer_interrupt_call(); -#endif - } -} - -int setup_profiling_timer(unsigned int multiplier) -{ - return -EINVAL; -} - /* * This interrupt should _never_ happen with our APIC/SMP architecture */ -fastcall void smp_spurious_interrupt(struct pt_regs *regs) +void smp_spurious_interrupt(struct pt_regs *regs) { unsigned long v; + exit_idle(); irq_enter(); /* * Check if this really is a spurious interrupt and ACK it @@ -1316,19 +1233,19 @@ fastcall void smp_spurious_interrupt(str ack_APIC_irq(); /* see sw-dev-man vol 3, chapter 7.4.13.5 */ - printk(KERN_INFO "spurious APIC interrupt on CPU#%d, should never happen.\n", - smp_processor_id()); + printk(KERN_INFO "spurious APIC interrupt on CPU#%d, " + "should never happen.\n", smp_processor_id()); irq_exit(); } /* * This interrupt should never happen with our APIC/SMP architecture */ - -fastcall void smp_error_interrupt(struct pt_regs *regs) +void smp_error_interrupt(struct pt_regs *regs) { unsigned long v, v1; + exit_idle(); irq_enter(); /* First tickle the hardware, only then report what went on. -- REW */ v = apic_read(APIC_ESR); @@ -1348,69 +1265,261 @@ fastcall void smp_error_interrupt(struct 7: Illegal register address */ printk (KERN_DEBUG "APIC error on CPU%d: %02lx(%02lx)\n", - smp_processor_id(), v , v1); + smp_processor_id(), v , v1); irq_exit(); } /* - * This initializes the IO-APIC and APIC hardware if this is - * a UP kernel. + * Initialize APIC interrupts */ -int __init APIC_init_uniprocessor (void) +void __init apic_intr_init(void) { - if (enable_local_apic < 0) - clear_bit(X86_FEATURE_APIC, boot_cpu_data.x86_capability); +#ifdef CONFIG_SMP + smp_intr_init(); +#endif + /* self generated IPI for local APIC timer */ + set_intr_gate(LOCAL_TIMER_VECTOR, apic_timer_interrupt); - if (!smp_found_config && !cpu_has_apic) - return -1; + /* IPI vectors for APIC spurious and error interrupts */ + set_intr_gate(SPURIOUS_APIC_VECTOR, spurious_interrupt); + set_intr_gate(ERROR_APIC_VECTOR, error_interrupt); - /* - * Complain if the BIOS pretends there is one. - */ - if (!cpu_has_apic && APIC_INTEGRATED(apic_version[boot_cpu_physical_apicid])) { - printk(KERN_ERR "BIOS bug, local APIC #%d not detected!...\n", - boot_cpu_physical_apicid); - clear_bit(X86_FEATURE_APIC, boot_cpu_data.x86_capability); - return -1; + /* thermal monitor LVT interrupt */ +#ifdef CONFIG_X86_MCE_P4THERMAL + set_intr_gate(THERMAL_APIC_VECTOR, thermal_interrupt); +#endif +} + +/** + * connect_bsp_APIC - attach the APIC to the interrupt system + */ +void __init connect_bsp_APIC(void) +{ + if (pic_mode) { + /* + * Do not trust the local APIC being empty at bootup. + */ + clear_local_APIC(); + /* + * PIC mode, enable APIC mode in the IMCR, i.e. connect BSP's + * local APIC to INT and NMI lines. + */ + apic_printk(APIC_VERBOSE, "leaving PIC mode, " + "enabling APIC mode.\n"); + outb(0x70, 0x22); + outb(0x01, 0x23); } + enable_apic_mode(); +} - verify_local_APIC(); +/** + * disconnect_bsp_APIC - detach the APIC from the interrupt system + * @virt_wire_setup: indicates, whether virtual wire mode is selected + * + * Virtual wire mode is necessary to deliver legacy interrupts even when the + * APIC is disabled. + */ +void disconnect_bsp_APIC(int virt_wire_setup) +{ + if (pic_mode) { + /* + * Put the board back into PIC mode (has an effect only on + * certain older boards). Note that APIC interrupts, including + * IPIs, won't work beyond this point! The only exception are + * INIT IPIs. + */ + apic_printk(APIC_VERBOSE, "disabling APIC mode, " + "entering PIC mode.\n"); + outb(0x70, 0x22); + outb(0x00, 0x23); + } else { + /* Go back to Virtual Wire compatibility mode */ + unsigned long value; - connect_bsp_APIC(); + /* For the spurious interrupt use vector F, and enable it */ + value = apic_read(APIC_SPIV); + value &= ~APIC_VECTOR_MASK; + value |= APIC_SPIV_APIC_ENABLED; + value |= 0xf; + apic_write_around(APIC_SPIV, value); - /* - * Hack: In case of kdump, after a crash, kernel might be booting - * on a cpu with non-zero lapic id. But boot_cpu_physical_apicid - * might be zero if read from MP tables. Get it from LAPIC. - */ -#ifdef CONFIG_CRASH_DUMP - boot_cpu_physical_apicid = GET_APIC_ID(apic_read(APIC_ID)); -#endif - phys_cpu_present_map = physid_mask_of_physid(boot_cpu_physical_apicid); + if (!virt_wire_setup) { + /* + * For LVT0 make it edge triggered, active high, + * external and enabled + */ + value = apic_read(APIC_LVT0); + value &= ~(APIC_MODE_MASK | APIC_SEND_PENDING | + APIC_INPUT_POLARITY | APIC_LVT_REMOTE_IRR | + APIC_LVT_LEVEL_TRIGGER | APIC_LVT_MASKED ); + value |= APIC_LVT_REMOTE_IRR | APIC_SEND_PENDING; + value = SET_APIC_DELIVERY_MODE(value, APIC_MODE_EXTINT); + apic_write_around(APIC_LVT0, value); + } else { + /* Disable LVT0 */ + apic_write_around(APIC_LVT0, APIC_LVT_MASKED); + } - setup_local_APIC(); + /* + * For LVT1 make it edge triggered, active high, nmi and + * enabled + */ + value = apic_read(APIC_LVT1); + value &= ~( + APIC_MODE_MASK | APIC_SEND_PENDING | + APIC_INPUT_POLARITY | APIC_LVT_REMOTE_IRR | + APIC_LVT_LEVEL_TRIGGER | APIC_LVT_MASKED); + value |= APIC_LVT_REMOTE_IRR | APIC_SEND_PENDING; + value = SET_APIC_DELIVERY_MODE(value, APIC_MODE_NMI); + apic_write_around(APIC_LVT1, value); + } +} -#ifdef CONFIG_X86_IO_APIC - if (smp_found_config) - if (!skip_ioapic_setup && nr_ioapics) - setup_IO_APIC(); +/* + * Power management + */ +#ifdef CONFIG_PM + +static struct { + int active; + /* r/w apic fields */ + unsigned int apic_id; + unsigned int apic_taskpri; + unsigned int apic_ldr; + unsigned int apic_dfr; + unsigned int apic_spiv; + unsigned int apic_lvtt; + unsigned int apic_lvtpc; + unsigned int apic_lvt0; + unsigned int apic_lvt1; + unsigned int apic_lvterr; + unsigned int apic_tmict; + unsigned int apic_tdcr; + unsigned int apic_thmr; +} apic_pm_state; + +static int lapic_suspend(struct sys_device *dev, pm_message_t state) +{ + unsigned long flags; + int maxlvt; + + if (!apic_pm_state.active) + return 0; + + maxlvt = lapic_get_maxlvt(); + + apic_pm_state.apic_id = apic_read(APIC_ID); + apic_pm_state.apic_taskpri = apic_read(APIC_TASKPRI); + apic_pm_state.apic_ldr = apic_read(APIC_LDR); + apic_pm_state.apic_dfr = apic_read(APIC_DFR); + apic_pm_state.apic_spiv = apic_read(APIC_SPIV); + apic_pm_state.apic_lvtt = apic_read(APIC_LVTT); + if (maxlvt >= 4) + apic_pm_state.apic_lvtpc = apic_read(APIC_LVTPC); + apic_pm_state.apic_lvt0 = apic_read(APIC_LVT0); + apic_pm_state.apic_lvt1 = apic_read(APIC_LVT1); + apic_pm_state.apic_lvterr = apic_read(APIC_LVTERR); + apic_pm_state.apic_tmict = apic_read(APIC_TMICT); + apic_pm_state.apic_tdcr = apic_read(APIC_TDCR); +#ifdef CONFIG_X86_MCE_P4THERMAL + if (maxlvt >= 5) + apic_pm_state.apic_thmr = apic_read(APIC_LVTTHMR); #endif - setup_boot_APIC_clock(); + local_irq_save(flags); + disable_local_APIC(); + local_irq_restore(flags); return 0; } -static int __init parse_lapic(char *arg) +static int lapic_resume(struct sys_device *dev) { - lapic_enable(); + unsigned int l, h; + unsigned long flags; + int maxlvt; + + if (!apic_pm_state.active) + return 0; + + maxlvt = lapic_get_maxlvt(); + + local_irq_save(flags); + + /* + * Make sure the APICBASE points to the right address + * + * FIXME! This will be wrong if we ever support suspend on + * SMP! We'll need to do this as part of the CPU restore! + */ + rdmsr(MSR_IA32_APICBASE, l, h); + l &= ~MSR_IA32_APICBASE_BASE; + l |= MSR_IA32_APICBASE_ENABLE | mp_lapic_addr; + wrmsr(MSR_IA32_APICBASE, l, h); + + apic_write(APIC_LVTERR, ERROR_APIC_VECTOR | APIC_LVT_MASKED); + apic_write(APIC_ID, apic_pm_state.apic_id); + apic_write(APIC_DFR, apic_pm_state.apic_dfr); + apic_write(APIC_LDR, apic_pm_state.apic_ldr); + apic_write(APIC_TASKPRI, apic_pm_state.apic_taskpri); + apic_write(APIC_SPIV, apic_pm_state.apic_spiv); + apic_write(APIC_LVT0, apic_pm_state.apic_lvt0); + apic_write(APIC_LVT1, apic_pm_state.apic_lvt1); +#ifdef CONFIG_X86_MCE_P4THERMAL + if (maxlvt >= 5) + apic_write(APIC_LVTTHMR, apic_pm_state.apic_thmr); +#endif + if (maxlvt >= 4) + apic_write(APIC_LVTPC, apic_pm_state.apic_lvtpc); + apic_write(APIC_LVTT, apic_pm_state.apic_lvtt); + apic_write(APIC_TDCR, apic_pm_state.apic_tdcr); + apic_write(APIC_TMICT, apic_pm_state.apic_tmict); + apic_write(APIC_ESR, 0); + apic_read(APIC_ESR); + apic_write(APIC_LVTERR, apic_pm_state.apic_lvterr); + apic_write(APIC_ESR, 0); + apic_read(APIC_ESR); + local_irq_restore(flags); return 0; } -early_param("lapic", parse_lapic); -static int __init parse_nolapic(char *arg) +/* + * This device has no shutdown method - fully functioning local APICs + * are needed on every CPU up until machine_halt/restart/poweroff. + */ + +static struct sysdev_class lapic_sysclass = { + set_kset_name("lapic"), + .resume = lapic_resume, + .suspend = lapic_suspend, +}; + +static struct sys_device device_lapic = { + .id = 0, + .cls = &lapic_sysclass, +}; + +static void __devinit apic_pm_activate(void) { - lapic_disable(); - return 0; + apic_pm_state.active = 1; } -early_param("nolapic", parse_nolapic); +static int __init init_lapic_sysfs(void) +{ + int error; + + if (!cpu_has_apic) + return 0; + /* XXX: remove suspend/resume procs if !apic_pm_state.active? */ + + error = sysdev_class_register(&lapic_sysclass); + if (!error) + error = sysdev_register(&device_lapic); + return error; +} +device_initcall(init_lapic_sysfs); + +#else /* CONFIG_PM */ + +static void apic_pm_activate(void) { } + +#endif /* CONFIG_PM */ diff --git a/arch/i386/kernel/apm.c b/arch/i386/kernel/apm.c index 1990169..064bbf2 100644 --- a/arch/i386/kernel/apm.c +++ b/arch/i386/kernel/apm.c @@ -211,6 +211,7 @@ #include #include #include #include +#include #include #include #include @@ -235,7 +236,6 @@ #include #include "io_ports.h" -extern unsigned long get_cmos_time(void); extern void machine_real_restart(unsigned char *, int); #if defined(CONFIG_APM_DISPLAY_BLANK) && defined(CONFIG_VT) @@ -1175,28 +1175,6 @@ out: spin_unlock(&user_list_lock); } -static void set_time(void) -{ - struct timespec ts; - if (got_clock_diff) { /* Must know time zone in order to set clock */ - ts.tv_sec = get_cmos_time() + clock_cmos_diff; - ts.tv_nsec = 0; - do_settimeofday(&ts); - } -} - -static void get_time_diff(void) -{ -#ifndef CONFIG_APM_RTC_IS_GMT - /* - * Estimate time zone so that set_time can update the clock - */ - clock_cmos_diff = -get_cmos_time(); - clock_cmos_diff += get_seconds(); - got_clock_diff = 1; -#endif -} - static void reinit_timer(void) { #ifdef INIT_TIMER_AFTER_SUSPEND @@ -1236,19 +1214,6 @@ static int suspend(int vetoable) local_irq_disable(); device_power_down(PMSG_SUSPEND); - /* serialize with the timer interrupt */ - write_seqlock(&xtime_lock); - - /* protect against access to timer chip registers */ - spin_lock(&i8253_lock); - - get_time_diff(); - /* - * Irq spinlock must be dropped around set_system_power_state. - * We'll undo any timer changes due to interrupts below. - */ - spin_unlock(&i8253_lock); - write_sequnlock(&xtime_lock); local_irq_enable(); save_processor_state(); @@ -1257,7 +1222,6 @@ static int suspend(int vetoable) restore_processor_state(); local_irq_disable(); - set_time(); reinit_timer(); if (err == APM_NO_ERROR) @@ -1287,11 +1251,6 @@ static void standby(void) local_irq_disable(); device_power_down(PMSG_SUSPEND); - /* serialize with the timer interrupt */ - write_seqlock(&xtime_lock); - /* If needed, notify drivers here */ - get_time_diff(); - write_sequnlock(&xtime_lock); local_irq_enable(); err = set_system_power_state(APM_STATE_STANDBY); @@ -1385,7 +1344,6 @@ #endif ignore_bounce = 1; if ((event != APM_NORMAL_RESUME) || (ignore_normal_resume == 0)) { - set_time(); device_resume(); pm_send_all(PM_RESUME, (void *)0); queue_event(event, NULL); @@ -1401,7 +1359,6 @@ #endif break; case APM_UPDATE_TIME: - set_time(); break; case APM_CRITICAL_SUSPEND: @@ -1636,9 +1593,8 @@ static int do_open(struct inode * inode, return 0; } -static int apm_get_info(char *buf, char **start, off_t fpos, int length) +static int proc_apm_show(struct seq_file *m, void *v) { - char * p; unsigned short bx; unsigned short cx; unsigned short dx; @@ -1650,8 +1606,6 @@ static int apm_get_info(char *buf, char int time_units = -1; char *units = "?"; - p = buf; - if ((num_online_cpus() == 1) && !(error = apm_get_power_status(&bx, &cx, &dx))) { ac_line_status = (bx >> 8) & 0xff; @@ -1705,7 +1659,7 @@ static int apm_get_info(char *buf, char -1: Unknown 8) min = minutes; sec = seconds */ - p += sprintf(p, "%s %d.%d 0x%02x 0x%02x 0x%02x 0x%02x %d%% %d %s\n", + seq_printf(m, "%s %d.%d 0x%02x 0x%02x 0x%02x 0x%02x %d%% %d %s\n", driver_version, (apm_info.bios.version >> 8) & 0xff, apm_info.bios.version & 0xff, @@ -1716,10 +1670,22 @@ static int apm_get_info(char *buf, char percentage, time_units, units); + return 0; +} - return p - buf; +static int proc_apm_open(struct inode *inode, struct file *file) +{ + return single_open(file, proc_apm_show, NULL); } +static const struct file_operations apm_file_ops = { + .owner = THIS_MODULE, + .open = proc_apm_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, +}; + static int apm(void *unused) { unsigned short bx; @@ -1894,7 +1860,7 @@ static int __init apm_setup(char *str) __setup("apm=", apm_setup); #endif -static struct file_operations apm_bios_fops = { +static const struct file_operations apm_bios_fops = { .owner = THIS_MODULE, .read = do_read, .poll = do_poll, @@ -2341,9 +2307,9 @@ #endif set_base(gdt[APM_DS >> 3], __va((unsigned long)apm_info.bios.dseg << 4)); - apm_proc = create_proc_info_entry("apm", 0, NULL, apm_get_info); + apm_proc = create_proc_entry("apm", 0, NULL); if (apm_proc) - apm_proc->owner = THIS_MODULE; + apm_proc->proc_fops = &apm_file_ops; kapmd_task = kthread_create(apm, NULL, "kapmd"); if (IS_ERR(kapmd_task)) { diff --git a/arch/i386/kernel/asm-offsets.c b/arch/i386/kernel/asm-offsets.c index 1b2f3cd..c375351 100644 --- a/arch/i386/kernel/asm-offsets.c +++ b/arch/i386/kernel/asm-offsets.c @@ -72,7 +72,7 @@ void foo(void) OFFSET(PT_EAX, pt_regs, eax); OFFSET(PT_DS, pt_regs, xds); OFFSET(PT_ES, pt_regs, xes); - OFFSET(PT_GS, pt_regs, xgs); + OFFSET(PT_FS, pt_regs, xfs); OFFSET(PT_ORIG_EAX, pt_regs, orig_eax); OFFSET(PT_EIP, pt_regs, eip); OFFSET(PT_CS, pt_regs, xcs); diff --git a/arch/i386/kernel/cpu/common.c b/arch/i386/kernel/cpu/common.c index 8a8bbda..dcbbd0a 100644 --- a/arch/i386/kernel/cpu/common.c +++ b/arch/i386/kernel/cpu/common.c @@ -605,7 +605,7 @@ #endif struct pt_regs * __devinit idle_regs(struct pt_regs *regs) { memset(regs, 0, sizeof(struct pt_regs)); - regs->xgs = __KERNEL_PDA; + regs->xfs = __KERNEL_PDA; return regs; } @@ -662,12 +662,12 @@ struct i386_pda boot_pda = { .pcurrent = &init_task, }; -static inline void set_kernel_gs(void) +static inline void set_kernel_fs(void) { - /* Set %gs for this CPU's PDA. Memory clobber is to create a + /* Set %fs for this CPU's PDA. Memory clobber is to create a barrier with respect to any PDA operations, so the compiler doesn't move any before here. */ - asm volatile ("mov %0, %%gs" : : "r" (__KERNEL_PDA) : "memory"); + asm volatile ("mov %0, %%fs" : : "r" (__KERNEL_PDA) : "memory"); } /* Initialize the CPU's GDT and PDA. The boot CPU does this for @@ -718,7 +718,7 @@ void __cpuinit cpu_set_gdt(int cpu) the boot CPU, this will transition from the boot gdt+pda to the real ones). */ load_gdt(cpu_gdt_descr); - set_kernel_gs(); + set_kernel_fs(); } /* Common CPU init for both boot and secondary CPUs */ @@ -764,8 +764,8 @@ #ifdef CONFIG_DOUBLEFAULT __set_tss_desc(cpu, GDT_ENTRY_DOUBLEFAULT_TSS, &doublefault_tss); #endif - /* Clear %fs. */ - asm volatile ("mov %0, %%fs" : : "r" (0)); + /* Clear %gs. */ + asm volatile ("mov %0, %%gs" : : "r" (0)); /* Clear all 6 debug registers: */ set_debugreg(0, 0); diff --git a/arch/i386/kernel/cpu/cpufreq/Kconfig b/arch/i386/kernel/cpu/cpufreq/Kconfig index 5299c5b..6c52182 100644 --- a/arch/i386/kernel/cpu/cpufreq/Kconfig +++ b/arch/i386/kernel/cpu/cpufreq/Kconfig @@ -217,6 +217,15 @@ config X86_LONGHAUL If in doubt, say N. +config X86_E_POWERSAVER + tristate "VIA C7 Enhanced PowerSaver (EXPERIMENTAL)" + select CPU_FREQ_TABLE + depends on EXPERIMENTAL + help + This adds the CPUFreq driver for VIA C7 processors. + + If in doubt, say N. + comment "shared options" config X86_ACPI_CPUFREQ_PROC_INTF diff --git a/arch/i386/kernel/cpu/cpufreq/Makefile b/arch/i386/kernel/cpu/cpufreq/Makefile index 8de3abe..560f776 100644 --- a/arch/i386/kernel/cpu/cpufreq/Makefile +++ b/arch/i386/kernel/cpu/cpufreq/Makefile @@ -2,6 +2,7 @@ obj-$(CONFIG_X86_POWERNOW_K6) += powern obj-$(CONFIG_X86_POWERNOW_K7) += powernow-k7.o obj-$(CONFIG_X86_POWERNOW_K8) += powernow-k8.o obj-$(CONFIG_X86_LONGHAUL) += longhaul.o +obj-$(CONFIG_X86_E_POWERSAVER) += e_powersaver.o obj-$(CONFIG_ELAN_CPUFREQ) += elanfreq.o obj-$(CONFIG_SC520_CPUFREQ) += sc520_freq.o obj-$(CONFIG_X86_LONGRUN) += longrun.o diff --git a/arch/i386/kernel/cpu/cpufreq/e_powersaver.c b/arch/i386/kernel/cpu/cpufreq/e_powersaver.c new file mode 100644 index 0000000..f43d98e --- /dev/null +++ b/arch/i386/kernel/cpu/cpufreq/e_powersaver.c @@ -0,0 +1,334 @@ +/* + * Based on documentation provided by Dave Jones. Thanks! + * + * Licensed under the terms of the GNU GPL License version 2. + * + * BIG FAT DISCLAIMER: Work in progress code. Possibly *dangerous* + */ + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#define EPS_BRAND_C7M 0 +#define EPS_BRAND_C7 1 +#define EPS_BRAND_EDEN 2 +#define EPS_BRAND_C3 3 + +struct eps_cpu_data { + u32 fsb; + struct cpufreq_frequency_table freq_table[]; +}; + +static struct eps_cpu_data *eps_cpu[NR_CPUS]; + + +static unsigned int eps_get(unsigned int cpu) +{ + struct eps_cpu_data *centaur; + u32 lo, hi; + + if (cpu) + return 0; + centaur = eps_cpu[cpu]; + if (centaur == NULL) + return 0; + + /* Return current frequency */ + rdmsr(MSR_IA32_PERF_STATUS, lo, hi); + return centaur->fsb * ((lo >> 8) & 0xff); +} + +static int eps_set_state(struct eps_cpu_data *centaur, + unsigned int cpu, + u32 dest_state) +{ + struct cpufreq_freqs freqs; + u32 lo, hi; + int err = 0; + int i; + + freqs.old = eps_get(cpu); + freqs.new = centaur->fsb * ((dest_state >> 8) & 0xff); + freqs.cpu = cpu; + cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE); + + /* Wait while CPU is busy */ + rdmsr(MSR_IA32_PERF_STATUS, lo, hi); + i = 0; + while (lo & ((1 << 16) | (1 << 17))) { + udelay(16); + rdmsr(MSR_IA32_PERF_STATUS, lo, hi); + i++; + if (unlikely(i > 64)) { + err = -ENODEV; + goto postchange; + } + } + /* Set new multiplier and voltage */ + wrmsr(MSR_IA32_PERF_CTL, dest_state & 0xffff, 0); + /* Wait until transition end */ + i = 0; + do { + udelay(16); + rdmsr(MSR_IA32_PERF_STATUS, lo, hi); + i++; + if (unlikely(i > 64)) { + err = -ENODEV; + goto postchange; + } + } while (lo & ((1 << 16) | (1 << 17))); + + /* Return current frequency */ +postchange: + rdmsr(MSR_IA32_PERF_STATUS, lo, hi); + freqs.new = centaur->fsb * ((lo >> 8) & 0xff); + + cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE); + return err; +} + +static int eps_target(struct cpufreq_policy *policy, + unsigned int target_freq, + unsigned int relation) +{ + struct eps_cpu_data *centaur; + unsigned int newstate = 0; + unsigned int cpu = policy->cpu; + unsigned int dest_state; + int ret; + + if (unlikely(eps_cpu[cpu] == NULL)) + return -ENODEV; + centaur = eps_cpu[cpu]; + + if (unlikely(cpufreq_frequency_table_target(policy, + &eps_cpu[cpu]->freq_table[0], + target_freq, + relation, + &newstate))) { + return -EINVAL; + } + + /* Make frequency transition */ + dest_state = centaur->freq_table[newstate].index & 0xffff; + ret = eps_set_state(centaur, cpu, dest_state); + if (ret) + printk(KERN_ERR "eps: Timeout!\n"); + return ret; +} + +static int eps_verify(struct cpufreq_policy *policy) +{ + return cpufreq_frequency_table_verify(policy, + &eps_cpu[policy->cpu]->freq_table[0]); +} + +static int eps_cpu_init(struct cpufreq_policy *policy) +{ + unsigned int i; + u32 lo, hi; + u64 val; + u8 current_multiplier, current_voltage; + u8 max_multiplier, max_voltage; + u8 min_multiplier, min_voltage; + u8 brand; + u32 fsb; + struct eps_cpu_data *centaur; + struct cpufreq_frequency_table *f_table; + int k, step, voltage; + int ret; + int states; + + if (policy->cpu != 0) + return -ENODEV; + + /* Check brand */ + printk("eps: Detected VIA "); + rdmsr(0x1153, lo, hi); + brand = (((lo >> 2) ^ lo) >> 18) & 3; + switch(brand) { + case EPS_BRAND_C7M: + printk("C7-M\n"); + break; + case EPS_BRAND_C7: + printk("C7\n"); + break; + case EPS_BRAND_EDEN: + printk("Eden\n"); + break; + case EPS_BRAND_C3: + printk("C3\n"); + return -ENODEV; + break; + } + /* Enable Enhanced PowerSaver */ + rdmsrl(MSR_IA32_MISC_ENABLE, val); + if (!(val & 1 << 16)) { + val |= 1 << 16; + wrmsrl(MSR_IA32_MISC_ENABLE, val); + /* Can be locked at 0 */ + rdmsrl(MSR_IA32_MISC_ENABLE, val); + if (!(val & 1 << 16)) { + printk("eps: Can't enable Enhanced PowerSaver\n"); + return -ENODEV; + } + } + + /* Print voltage and multiplier */ + rdmsr(MSR_IA32_PERF_STATUS, lo, hi); + current_voltage = lo & 0xff; + printk("eps: Current voltage = %dmV\n", current_voltage * 16 + 700); + current_multiplier = (lo >> 8) & 0xff; + printk("eps: Current multiplier = %d\n", current_multiplier); + + /* Print limits */ + max_voltage = hi & 0xff; + printk("eps: Highest voltage = %dmV\n", max_voltage * 16 + 700); + max_multiplier = (hi >> 8) & 0xff; + printk("eps: Highest multiplier = %d\n", max_multiplier); + min_voltage = (hi >> 16) & 0xff; + printk("eps: Lowest voltage = %dmV\n", min_voltage * 16 + 700); + min_multiplier = (hi >> 24) & 0xff; + printk("eps: Lowest multiplier = %d\n", min_multiplier); + + /* Sanity checks */ + if (current_multiplier == 0 || max_multiplier == 0 + || min_multiplier == 0) + return -EINVAL; + if (current_multiplier > max_multiplier + || max_multiplier <= min_multiplier) + return -EINVAL; + if (current_voltage > 0x1c || max_voltage > 0x1c) + return -EINVAL; + if (max_voltage < min_voltage) + return -EINVAL; + + /* Calc FSB speed */ + fsb = cpu_khz / current_multiplier; + /* Calc number of p-states supported */ + if (brand == EPS_BRAND_C7M) + states = max_multiplier - min_multiplier + 1; + else + states = 2; + + /* Allocate private data and frequency table for current cpu */ + centaur = kzalloc(sizeof(struct eps_cpu_data) + + (states + 1) * sizeof(struct cpufreq_frequency_table), + GFP_KERNEL); + if (!centaur) + return -ENOMEM; + eps_cpu[0] = centaur; + + /* Copy basic values */ + centaur->fsb = fsb; + + /* Fill frequency and MSR value table */ + f_table = ¢aur->freq_table[0]; + if (brand != EPS_BRAND_C7M) { + f_table[0].frequency = fsb * min_multiplier; + f_table[0].index = (min_multiplier << 8) | min_voltage; + f_table[1].frequency = fsb * max_multiplier; + f_table[1].index = (max_multiplier << 8) | max_voltage; + f_table[2].frequency = CPUFREQ_TABLE_END; + } else { + k = 0; + step = ((max_voltage - min_voltage) * 256) + / (max_multiplier - min_multiplier); + for (i = min_multiplier; i <= max_multiplier; i++) { + voltage = (k * step) / 256 + min_voltage; + f_table[k].frequency = fsb * i; + f_table[k].index = (i << 8) | voltage; + k++; + } + f_table[k].frequency = CPUFREQ_TABLE_END; + } + + policy->governor = CPUFREQ_DEFAULT_GOVERNOR; + policy->cpuinfo.transition_latency = 140000; /* 844mV -> 700mV in ns */ + policy->cur = fsb * current_multiplier; + + ret = cpufreq_frequency_table_cpuinfo(policy, ¢aur->freq_table[0]); + if (ret) { + kfree(centaur); + return ret; + } + + cpufreq_frequency_table_get_attr(¢aur->freq_table[0], policy->cpu); + return 0; +} + +static int eps_cpu_exit(struct cpufreq_policy *policy) +{ + unsigned int cpu = policy->cpu; + struct eps_cpu_data *centaur; + u32 lo, hi; + + if (eps_cpu[cpu] == NULL) + return -ENODEV; + centaur = eps_cpu[cpu]; + + /* Get max frequency */ + rdmsr(MSR_IA32_PERF_STATUS, lo, hi); + /* Set max frequency */ + eps_set_state(centaur, cpu, hi & 0xffff); + /* Bye */ + cpufreq_frequency_table_put_attr(policy->cpu); + kfree(eps_cpu[cpu]); + eps_cpu[cpu] = NULL; + return 0; +} + +static struct freq_attr* eps_attr[] = { + &cpufreq_freq_attr_scaling_available_freqs, + NULL, +}; + +static struct cpufreq_driver eps_driver = { + .verify = eps_verify, + .target = eps_target, + .init = eps_cpu_init, + .exit = eps_cpu_exit, + .get = eps_get, + .name = "e_powersaver", + .owner = THIS_MODULE, + .attr = eps_attr, +}; + +static int __init eps_init(void) +{ + struct cpuinfo_x86 *c = cpu_data; + + /* This driver will work only on Centaur C7 processors with + * Enhanced SpeedStep/PowerSaver registers */ + if (c->x86_vendor != X86_VENDOR_CENTAUR + || c->x86 != 6 || c->x86_model != 10) + return -ENODEV; + if (!cpu_has(c, X86_FEATURE_EST)) + return -ENODEV; + + if (cpufreq_register_driver(&eps_driver)) + return -EINVAL; + return 0; +} + +static void __exit eps_exit(void) +{ + cpufreq_unregister_driver(&eps_driver); +} + +MODULE_AUTHOR("Rafa³ Bilski "); +MODULE_DESCRIPTION("Enhanced PowerSaver driver for VIA C7 CPU's."); +MODULE_LICENSE("GPL"); + +module_init(eps_init); +module_exit(eps_exit); diff --git a/arch/i386/kernel/cpu/cpufreq/longhaul.c b/arch/i386/kernel/cpu/cpufreq/longhaul.c index e940e00..b59878a 100644 --- a/arch/i386/kernel/cpu/cpufreq/longhaul.c +++ b/arch/i386/kernel/cpu/cpufreq/longhaul.c @@ -8,12 +8,11 @@ * VIA have currently 3 different versions of Longhaul. * Version 1 (Longhaul) uses the BCR2 MSR at 0x1147. * It is present only in Samuel 1 (C5A), Samuel 2 (C5B) stepping 0. - * Version 2 of longhaul is the same as v1, but adds voltage scaling. - * Present in Samuel 2 (steppings 1-7 only) (C5B), and Ezra (C5C) - * voltage scaling support has currently been disabled in this driver - * until we have code that gets it right. + * Version 2 of longhaul is backward compatible with v1, but adds + * LONGHAUL MSR for purpose of both frequency and voltage scaling. + * Present in Samuel 2 (steppings 1-7 only) (C5B), and Ezra (C5C). * Version 3 of longhaul got renamed to Powersaver and redesigned - * to use the POWERSAVER MSR at 0x110a. + * to use only the POWERSAVER MSR at 0x110a. * It is present in Ezra-T (C5M), Nehemiah (C5X) and above. * It's pretty much the same feature wise to longhaul v2, though * there is provision for scaling FSB too, but this doesn't work @@ -51,10 +50,12 @@ #define CPU_SAMUEL2 2 #define CPU_EZRA 3 #define CPU_EZRA_T 4 #define CPU_NEHEMIAH 5 +#define CPU_NEHEMIAH_C 6 /* Flags */ #define USE_ACPI_C3 (1 << 1) #define USE_NORTHBRIDGE (1 << 2) +#define USE_VT8235 (1 << 3) static int cpu_model; static unsigned int numscales=16; @@ -63,7 +64,8 @@ static unsigned int fsb; static struct mV_pos *vrm_mV_table; static unsigned char *mV_vrm_table; struct f_msr { - unsigned char vrm; + u8 vrm; + u8 pos; }; static struct f_msr f_msr_table[32]; @@ -73,10 +75,10 @@ static int can_scale_voltage; static struct acpi_processor *pr = NULL; static struct acpi_processor_cx *cx = NULL; static u8 longhaul_flags; +static u8 longhaul_pos; /* Module parameters */ static int scale_voltage; -static int ignore_latency; #define dprintk(msg...) cpufreq_debug_printk(CPUFREQ_DEBUG_DRIVER, "longhaul", msg) @@ -164,41 +166,79 @@ static void do_longhaul1(unsigned int cl static void do_powersaver(int cx_address, unsigned int clock_ratio_index) { union msr_longhaul longhaul; + u8 dest_pos; u32 t; + dest_pos = f_msr_table[clock_ratio_index].pos; + rdmsrl(MSR_VIA_LONGHAUL, longhaul.val); + /* Setup new frequency */ longhaul.bits.RevisionKey = longhaul.bits.RevisionID; longhaul.bits.SoftBusRatio = clock_ratio_index & 0xf; longhaul.bits.SoftBusRatio4 = (clock_ratio_index & 0x10) >> 4; - longhaul.bits.EnableSoftBusRatio = 1; - - if (can_scale_voltage) { + /* Setup new voltage */ + if (can_scale_voltage) longhaul.bits.SoftVID = f_msr_table[clock_ratio_index].vrm; + /* Sync to timer tick */ + safe_halt(); + /* Raise voltage if necessary */ + if (can_scale_voltage && longhaul_pos < dest_pos) { longhaul.bits.EnableSoftVID = 1; + wrmsrl(MSR_VIA_LONGHAUL, longhaul.val); + /* Change voltage */ + if (!cx_address) { + ACPI_FLUSH_CPU_CACHE(); + halt(); + } else { + ACPI_FLUSH_CPU_CACHE(); + /* Invoke C3 */ + inb(cx_address); + /* Dummy op - must do something useless after P_LVL3 + * read */ + t = inl(acpi_gbl_FADT.xpm_timer_block.address); + } + longhaul.bits.EnableSoftVID = 0; + wrmsrl(MSR_VIA_LONGHAUL, longhaul.val); + longhaul_pos = dest_pos; } - /* Sync to timer tick */ - safe_halt(); /* Change frequency on next halt or sleep */ + longhaul.bits.EnableSoftBusRatio = 1; wrmsrl(MSR_VIA_LONGHAUL, longhaul.val); if (!cx_address) { ACPI_FLUSH_CPU_CACHE(); - /* Invoke C1 */ halt(); } else { ACPI_FLUSH_CPU_CACHE(); /* Invoke C3 */ inb(cx_address); /* Dummy op - must do something useless after P_LVL3 read */ - t = inl(acpi_fadt.xpm_tmr_blk.address); + t = inl(acpi_gbl_FADT.xpm_timer_block.address); } /* Disable bus ratio bit */ - local_irq_disable(); - longhaul.bits.RevisionKey = longhaul.bits.RevisionID; longhaul.bits.EnableSoftBusRatio = 0; - longhaul.bits.EnableSoftBSEL = 0; - longhaul.bits.EnableSoftVID = 0; wrmsrl(MSR_VIA_LONGHAUL, longhaul.val); + + /* Reduce voltage if necessary */ + if (can_scale_voltage && longhaul_pos > dest_pos) { + longhaul.bits.EnableSoftVID = 1; + wrmsrl(MSR_VIA_LONGHAUL, longhaul.val); + /* Change voltage */ + if (!cx_address) { + ACPI_FLUSH_CPU_CACHE(); + halt(); + } else { + ACPI_FLUSH_CPU_CACHE(); + /* Invoke C3 */ + inb(cx_address); + /* Dummy op - must do something useless after P_LVL3 + * read */ + t = inl(acpi_gbl_FADT.xpm_timer_block.address); + } + longhaul.bits.EnableSoftVID = 0; + wrmsrl(MSR_VIA_LONGHAUL, longhaul.val); + longhaul_pos = dest_pos; + } } /** @@ -250,39 +290,30 @@ static void longhaul_setstate(unsigned i outb(3, 0x22); } else if ((pr != NULL) && pr->flags.bm_control) { /* Disable bus master arbitration */ - acpi_set_register(ACPI_BITREG_ARB_DISABLE, 1, - ACPI_MTX_DO_NOT_LOCK); + acpi_set_register(ACPI_BITREG_ARB_DISABLE, 1); } switch (longhaul_version) { /* * Longhaul v1. (Samuel[C5A] and Samuel2 stepping 0[C5B]) * Software controlled multipliers only. - * - * *NB* Until we get voltage scaling working v1 & v2 are the same code. - * Longhaul v2 appears in Samuel2 Steppings 1->7 [C5b] and Ezra [C5C] */ case TYPE_LONGHAUL_V1: - case TYPE_LONGHAUL_V2: do_longhaul1(clock_ratio_index); break; /* + * Longhaul v2 appears in Samuel2 Steppings 1->7 [C5B] and Ezra [C5C] + * * Longhaul v3 (aka Powersaver). (Ezra-T [C5M] & Nehemiah [C5N]) - * We can scale voltage with this too, but that's currently - * disabled until we come up with a decent 'match freq to voltage' - * algorithm. - * When we add voltage scaling, we will also need to do the - * voltage/freq setting in order depending on the direction - * of scaling (like we do in powernow-k7.c) * Nehemiah can do FSB scaling too, but this has never been proven * to work in practice. */ + case TYPE_LONGHAUL_V2: case TYPE_POWERSAVER: if (longhaul_flags & USE_ACPI_C3) { /* Don't allow wakeup */ - acpi_set_register(ACPI_BITREG_BUS_MASTER_RLD, 0, - ACPI_MTX_DO_NOT_LOCK); + acpi_set_register(ACPI_BITREG_BUS_MASTER_RLD, 0); do_powersaver(cx->address, clock_ratio_index); } else { do_powersaver(0, clock_ratio_index); @@ -295,8 +326,7 @@ static void longhaul_setstate(unsigned i outb(0, 0x22); } else if ((pr != NULL) && pr->flags.bm_control) { /* Enable bus master arbitration */ - acpi_set_register(ACPI_BITREG_ARB_DISABLE, 0, - ACPI_MTX_DO_NOT_LOCK); + acpi_set_register(ACPI_BITREG_ARB_DISABLE, 0); } outb(pic2_mask,0xA1); /* restore mask */ outb(pic1_mask,0x21); @@ -304,6 +334,7 @@ static void longhaul_setstate(unsigned i local_irq_restore(flags); preempt_enable(); + freqs.new = calc_speed(longhaul_get_cpu_mult()); cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE); } @@ -318,31 +349,19 @@ static void longhaul_setstate(unsigned i #define ROUNDING 0xf -static int _guess(int guess, int mult) -{ - int target; - - target = ((mult/10)*guess); - if (mult%10 != 0) - target += (guess/2); - target += ROUNDING/2; - target &= ~ROUNDING; - return target; -} - - static int guess_fsb(int mult) { - int speed = (cpu_khz/1000); + int speed = cpu_khz / 1000; int i; - int speeds[] = { 66, 100, 133, 200 }; - - speed += ROUNDING/2; - speed &= ~ROUNDING; - - for (i=0; i<4; i++) { - if (_guess(speeds[i], mult) == speed) - return speeds[i]; + int speeds[] = { 666, 1000, 1333, 2000 }; + int f_max, f_min; + + for (i = 0; i < 4; i++) { + f_max = ((speeds[i] * mult) + 50) / 100; + f_max += (ROUNDING / 2); + f_min = f_max - ROUNDING; + if ((speed <= f_max) && (speed >= f_min)) + return speeds[i] / 10; } return 0; } @@ -350,71 +369,44 @@ static int guess_fsb(int mult) static int __init longhaul_get_ranges(void) { - unsigned long invalue; - unsigned int ezra_t_multipliers[32]= { - 90, 30, 40, 100, 55, 35, 45, 95, - 50, 70, 80, 60, 120, 75, 85, 65, - -1, 110, 120, -1, 135, 115, 125, 105, - 130, 150, 160, 140, -1, 155, -1, 145 }; unsigned int j, k = 0; - union msr_longhaul longhaul; - int mult = 0; + int mult; - switch (longhaul_version) { - case TYPE_LONGHAUL_V1: - case TYPE_LONGHAUL_V2: - /* Ugh, Longhaul v1 didn't have the min/max MSRs. - Assume min=3.0x & max = whatever we booted at. */ + /* Get current frequency */ + mult = longhaul_get_cpu_mult(); + if (mult == -1) { + printk(KERN_INFO PFX "Invalid (reserved) multiplier!\n"); + return -EINVAL; + } + fsb = guess_fsb(mult); + if (fsb == 0) { + printk(KERN_INFO PFX "Invalid (reserved) FSB!\n"); + return -EINVAL; + } + /* Get max multiplier - as we always did. + * Longhaul MSR is usefull only when voltage scaling is enabled. + * C3 is booting at max anyway. */ + maxmult = mult; + /* Get min multiplier */ + switch (cpu_model) { + case CPU_NEHEMIAH: + minmult = 50; + break; + case CPU_NEHEMIAH_C: + minmult = 40; + break; + default: minmult = 30; - maxmult = mult = longhaul_get_cpu_mult(); break; - - case TYPE_POWERSAVER: - /* Ezra-T */ - if (cpu_model==CPU_EZRA_T) { - minmult = 30; - rdmsrl (MSR_VIA_LONGHAUL, longhaul.val); - invalue = longhaul.bits.MaxMHzBR; - if (longhaul.bits.MaxMHzBR4) - invalue += 16; - maxmult = mult = ezra_t_multipliers[invalue]; - break; - } - - /* Nehemiah */ - if (cpu_model==CPU_NEHEMIAH) { - rdmsrl (MSR_VIA_LONGHAUL, longhaul.val); - - /* - * TODO: This code works, but raises a lot of questions. - * - Some Nehemiah's seem to have broken Min/MaxMHzBR's. - * We get around this by using a hardcoded multiplier of 4.0x - * for the minimimum speed, and the speed we booted up at for the max. - * This is done in longhaul_get_cpu_mult() by reading the EBLCR register. - * - According to some VIA documentation EBLCR is only - * in pre-Nehemiah C3s. How this still works is a mystery. - * We're possibly using something undocumented and unsupported, - * But it works, so we don't grumble. - */ - minmult=40; - maxmult = mult = longhaul_get_cpu_mult(); - break; - } } - fsb = guess_fsb(mult); dprintk ("MinMult:%d.%dx MaxMult:%d.%dx\n", minmult/10, minmult%10, maxmult/10, maxmult%10); - if (fsb == 0) { - printk (KERN_INFO PFX "Invalid (reserved) FSB!\n"); - return -EINVAL; - } - highest_speed = calc_speed(maxmult); lowest_speed = calc_speed(minmult); dprintk ("FSB:%dMHz Lowest speed: %s Highest speed:%s\n", fsb, - print_speed(lowest_speed/1000), + print_speed(lowest_speed/1000), print_speed(highest_speed/1000)); if (lowest_speed == highest_speed) { @@ -458,6 +450,7 @@ static void __init longhaul_setup_voltag union msr_longhaul longhaul; struct mV_pos minvid, maxvid; unsigned int j, speed, pos, kHz_step, numvscales; + int min_vid_speed; rdmsrl(MSR_VIA_LONGHAUL, longhaul.val); if (!(longhaul.bits.RevisionID & 1)) { @@ -471,14 +464,14 @@ static void __init longhaul_setup_voltag mV_vrm_table = &mV_vrm85[0]; } else { printk (KERN_INFO PFX "Mobile VRM\n"); + if (cpu_model < CPU_NEHEMIAH) + return; vrm_mV_table = &mobilevrm_mV[0]; mV_vrm_table = &mV_mobilevrm[0]; } minvid = vrm_mV_table[longhaul.bits.MinimumVID]; maxvid = vrm_mV_table[longhaul.bits.MaximumVID]; - numvscales = maxvid.pos - minvid.pos + 1; - kHz_step = (highest_speed - lowest_speed) / numvscales; if (minvid.mV == 0 || maxvid.mV == 0 || minvid.mV > maxvid.mV) { printk (KERN_INFO PFX "Bogus values Min:%d.%03d Max:%d.%03d. " @@ -494,20 +487,59 @@ static void __init longhaul_setup_voltag return; } - printk(KERN_INFO PFX "Max VID=%d.%03d Min VID=%d.%03d, %d possible voltage scales\n", + /* How many voltage steps */ + numvscales = maxvid.pos - minvid.pos + 1; + printk(KERN_INFO PFX + "Max VID=%d.%03d " + "Min VID=%d.%03d, " + "%d possible voltage scales\n", maxvid.mV/1000, maxvid.mV%1000, minvid.mV/1000, minvid.mV%1000, numvscales); - + + /* Calculate max frequency at min voltage */ + j = longhaul.bits.MinMHzBR; + if (longhaul.bits.MinMHzBR4) + j += 16; + min_vid_speed = eblcr_table[j]; + if (min_vid_speed == -1) + return; + switch (longhaul.bits.MinMHzFSB) { + case 0: + min_vid_speed *= 13333; + break; + case 1: + min_vid_speed *= 10000; + break; + case 3: + min_vid_speed *= 6666; + break; + default: + return; + break; + } + if (min_vid_speed >= highest_speed) + return; + /* Calculate kHz for one voltage step */ + kHz_step = (highest_speed - min_vid_speed) / numvscales; + + j = 0; while (longhaul_table[j].frequency != CPUFREQ_TABLE_END) { speed = longhaul_table[j].frequency; - pos = (speed - lowest_speed) / kHz_step + minvid.pos; + if (speed > min_vid_speed) + pos = (speed - min_vid_speed) / kHz_step + minvid.pos; + else + pos = minvid.pos; f_msr_table[longhaul_table[j].index].vrm = mV_vrm_table[pos]; + f_msr_table[longhaul_table[j].index].pos = pos; j++; } + longhaul_pos = maxvid.pos; can_scale_voltage = 1; + printk(KERN_INFO PFX "Voltage scaling enabled. " + "Use of \"conservative\" governor is highly recommended.\n"); } @@ -576,20 +608,51 @@ static int enable_arbiter_disable(void) if (dev != NULL) { /* Enable access to port 0x22 */ pci_read_config_byte(dev, reg, &pci_cmd); - if ( !(pci_cmd & 1<<7) ) { + if (!(pci_cmd & 1<<7)) { pci_cmd |= 1<<7; pci_write_config_byte(dev, reg, pci_cmd); + pci_read_config_byte(dev, reg, &pci_cmd); + if (!(pci_cmd & 1<<7)) { + printk(KERN_ERR PFX + "Can't enable access to port 0x22.\n"); + return 0; + } } return 1; } return 0; } +static int longhaul_setup_vt8235(void) +{ + struct pci_dev *dev; + u8 pci_cmd; + + /* Find VT8235 southbridge */ + dev = pci_find_device(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8235, NULL); + if (dev != NULL) { + /* Set transition time to max */ + pci_read_config_byte(dev, 0xec, &pci_cmd); + pci_cmd &= ~(1 << 2); + pci_write_config_byte(dev, 0xec, pci_cmd); + pci_read_config_byte(dev, 0xe4, &pci_cmd); + pci_cmd &= ~(1 << 7); + pci_write_config_byte(dev, 0xe4, pci_cmd); + pci_read_config_byte(dev, 0xe5, &pci_cmd); + pci_cmd |= 1 << 7; + pci_write_config_byte(dev, 0xe5, pci_cmd); + return 1; + } + return 0; +} + static int __init longhaul_cpu_init(struct cpufreq_policy *policy) { struct cpuinfo_x86 *c = cpu_data; char *cpuname=NULL; int ret; + u32 lo, hi; + int vt8235_present; /* Check what we have on this motherboard */ switch (c->x86_model) { @@ -602,16 +665,20 @@ static int __init longhaul_cpu_init(stru break; case 7: - longhaul_version = TYPE_LONGHAUL_V1; switch (c->x86_mask) { case 0: + longhaul_version = TYPE_LONGHAUL_V1; cpu_model = CPU_SAMUEL2; cpuname = "C3 'Samuel 2' [C5B]"; - /* Note, this is not a typo, early Samuel2's had Samuel1 ratios. */ - memcpy (clock_ratio, samuel1_clock_ratio, sizeof(samuel1_clock_ratio)); - memcpy (eblcr_table, samuel2_eblcr, sizeof(samuel2_eblcr)); + /* Note, this is not a typo, early Samuel2's had + * Samuel1 ratios. */ + memcpy(clock_ratio, samuel1_clock_ratio, + sizeof(samuel1_clock_ratio)); + memcpy(eblcr_table, samuel2_eblcr, + sizeof(samuel2_eblcr)); break; case 1 ... 15: + longhaul_version = TYPE_LONGHAUL_V2; if (c->x86_mask < 8) { cpu_model = CPU_SAMUEL2; cpuname = "C3 'Samuel 2' [C5B]"; @@ -619,8 +686,10 @@ static int __init longhaul_cpu_init(stru cpu_model = CPU_EZRA; cpuname = "C3 'Ezra' [C5C]"; } - memcpy (clock_ratio, ezra_clock_ratio, sizeof(ezra_clock_ratio)); - memcpy (eblcr_table, ezra_eblcr, sizeof(ezra_eblcr)); + memcpy(clock_ratio, ezra_clock_ratio, + sizeof(ezra_clock_ratio)); + memcpy(eblcr_table, ezra_eblcr, + sizeof(ezra_eblcr)); break; } break; @@ -635,24 +704,24 @@ static int __init longhaul_cpu_init(stru break; case 9: - cpu_model = CPU_NEHEMIAH; longhaul_version = TYPE_POWERSAVER; - numscales=32; + numscales = 32; + memcpy(clock_ratio, + nehemiah_clock_ratio, + sizeof(nehemiah_clock_ratio)); + memcpy(eblcr_table, nehemiah_eblcr, sizeof(nehemiah_eblcr)); switch (c->x86_mask) { case 0 ... 1: - cpuname = "C3 'Nehemiah A' [C5N]"; - memcpy (clock_ratio, nehemiah_a_clock_ratio, sizeof(nehemiah_a_clock_ratio)); - memcpy (eblcr_table, nehemiah_a_eblcr, sizeof(nehemiah_a_eblcr)); + cpu_model = CPU_NEHEMIAH; + cpuname = "C3 'Nehemiah A' [C5XLOE]"; break; case 2 ... 4: - cpuname = "C3 'Nehemiah B' [C5N]"; - memcpy (clock_ratio, nehemiah_b_clock_ratio, sizeof(nehemiah_b_clock_ratio)); - memcpy (eblcr_table, nehemiah_b_eblcr, sizeof(nehemiah_b_eblcr)); + cpu_model = CPU_NEHEMIAH; + cpuname = "C3 'Nehemiah B' [C5XLOH]"; break; case 5 ... 15: - cpuname = "C3 'Nehemiah C' [C5N]"; - memcpy (clock_ratio, nehemiah_c_clock_ratio, sizeof(nehemiah_c_clock_ratio)); - memcpy (eblcr_table, nehemiah_c_eblcr, sizeof(nehemiah_c_eblcr)); + cpu_model = CPU_NEHEMIAH_C; + cpuname = "C3 'Nehemiah C' [C5P]"; break; } break; @@ -661,6 +730,13 @@ static int __init longhaul_cpu_init(stru cpuname = "Unknown"; break; } + /* Check Longhaul ver. 2 */ + if (longhaul_version == TYPE_LONGHAUL_V2) { + rdmsr(MSR_VIA_LONGHAUL, lo, hi); + if (lo == 0 && hi == 0) + /* Looks like MSR isn't present */ + longhaul_version = TYPE_LONGHAUL_V1; + } printk (KERN_INFO PFX "VIA %s CPU detected. ", cpuname); switch (longhaul_version) { @@ -673,15 +749,18 @@ static int __init longhaul_cpu_init(stru break; }; + /* Doesn't hurt */ + vt8235_present = longhaul_setup_vt8235(); + /* Find ACPI data for processor */ - acpi_walk_namespace(ACPI_TYPE_PROCESSOR, ACPI_ROOT_OBJECT, ACPI_UINT32_MAX, - &longhaul_walk_callback, NULL, (void *)&pr); + acpi_walk_namespace(ACPI_TYPE_PROCESSOR, ACPI_ROOT_OBJECT, + ACPI_UINT32_MAX, &longhaul_walk_callback, + NULL, (void *)&pr); /* Check ACPI support for C3 state */ - if ((pr != NULL) && (longhaul_version == TYPE_POWERSAVER)) { + if (pr != NULL && longhaul_version != TYPE_LONGHAUL_V1) { cx = &pr->power.states[ACPI_STATE_C3]; - if (cx->address > 0 && - (cx->latency <= 1000 || ignore_latency != 0) ) { + if (cx->address > 0 && cx->latency <= 1000) { longhaul_flags |= USE_ACPI_C3; goto print_support_type; } @@ -691,8 +770,11 @@ static int __init longhaul_cpu_init(stru longhaul_flags |= USE_NORTHBRIDGE; goto print_support_type; } - - /* No ACPI C3 or we can't use it */ + /* Use VT8235 southbridge if present */ + if (longhaul_version == TYPE_POWERSAVER && vt8235_present) { + longhaul_flags |= USE_VT8235; + goto print_support_type; + } /* Check ACPI support for bus master arbiter disable */ if ((pr == NULL) || !(pr->flags.bm_control)) { printk(KERN_ERR PFX @@ -701,18 +783,18 @@ static int __init longhaul_cpu_init(stru } print_support_type: - if (!(longhaul_flags & USE_NORTHBRIDGE)) { - printk (KERN_INFO PFX "Using ACPI support.\n"); - } else { + if (longhaul_flags & USE_NORTHBRIDGE) printk (KERN_INFO PFX "Using northbridge support.\n"); - } + else if (longhaul_flags & USE_VT8235) + printk (KERN_INFO PFX "Using VT8235 support.\n"); + else + printk (KERN_INFO PFX "Using ACPI support.\n"); ret = longhaul_get_ranges(); if (ret != 0) return ret; - if ((longhaul_version==TYPE_LONGHAUL_V2 || longhaul_version==TYPE_POWERSAVER) && - (scale_voltage != 0)) + if ((longhaul_version != TYPE_LONGHAUL_V1) && (scale_voltage != 0)) longhaul_setup_voltagescaling(); policy->governor = CPUFREQ_DEFAULT_GOVERNOR; @@ -800,8 +882,6 @@ static void __exit longhaul_exit(void) module_param (scale_voltage, int, 0644); MODULE_PARM_DESC(scale_voltage, "Scale voltage of processor"); -module_param(ignore_latency, int, 0644); -MODULE_PARM_DESC(ignore_latency, "Skip ACPI C3 latency test"); MODULE_AUTHOR ("Dave Jones "); MODULE_DESCRIPTION ("Longhaul driver for VIA Cyrix processors."); diff --git a/arch/i386/kernel/cpu/cpufreq/longhaul.h b/arch/i386/kernel/cpu/cpufreq/longhaul.h index bc4682a..bb0a04b 100644 --- a/arch/i386/kernel/cpu/cpufreq/longhaul.h +++ b/arch/i386/kernel/cpu/cpufreq/longhaul.h @@ -235,84 +235,14 @@ static int __initdata ezrat_eblcr[32] = /* * VIA C3 Nehemiah */ -static int __initdata nehemiah_a_clock_ratio[32] = { +static int __initdata nehemiah_clock_ratio[32] = { 100, /* 0000 -> 10.0x */ 160, /* 0001 -> 16.0x */ - -1, /* 0010 -> RESERVED */ - 90, /* 0011 -> 9.0x */ - 95, /* 0100 -> 9.5x */ - -1, /* 0101 -> RESERVED */ - -1, /* 0110 -> RESERVED */ - 55, /* 0111 -> 5.5x */ - 60, /* 1000 -> 6.0x */ - 70, /* 1001 -> 7.0x */ - 80, /* 1010 -> 8.0x */ - 50, /* 1011 -> 5.0x */ - 65, /* 1100 -> 6.5x */ - 75, /* 1101 -> 7.5x */ - 85, /* 1110 -> 8.5x */ - 120, /* 1111 -> 12.0x */ - 100, /* 0000 -> 10.0x */ - -1, /* 0001 -> RESERVED */ - 120, /* 0010 -> 12.0x */ - 90, /* 0011 -> 9.0x */ - 105, /* 0100 -> 10.5x */ - 115, /* 0101 -> 11.5x */ - 125, /* 0110 -> 12.5x */ - 135, /* 0111 -> 13.5x */ - 140, /* 1000 -> 14.0x */ - 150, /* 1001 -> 15.0x */ - 160, /* 1010 -> 16.0x */ - 130, /* 1011 -> 13.0x */ - 145, /* 1100 -> 14.5x */ - 155, /* 1101 -> 15.5x */ - -1, /* 1110 -> RESERVED (13.0x) */ - 120, /* 1111 -> 12.0x */ -}; - -static int __initdata nehemiah_b_clock_ratio[32] = { - 100, /* 0000 -> 10.0x */ - 160, /* 0001 -> 16.0x */ - -1, /* 0010 -> RESERVED */ - 90, /* 0011 -> 9.0x */ - 95, /* 0100 -> 9.5x */ - -1, /* 0101 -> RESERVED */ - -1, /* 0110 -> RESERVED */ - 55, /* 0111 -> 5.5x */ - 60, /* 1000 -> 6.0x */ - 70, /* 1001 -> 7.0x */ - 80, /* 1010 -> 8.0x */ - 50, /* 1011 -> 5.0x */ - 65, /* 1100 -> 6.5x */ - 75, /* 1101 -> 7.5x */ - 85, /* 1110 -> 8.5x */ - 120, /* 1111 -> 12.0x */ - 100, /* 0000 -> 10.0x */ - 110, /* 0001 -> 11.0x */ - 120, /* 0010 -> 12.0x */ - 90, /* 0011 -> 9.0x */ - 105, /* 0100 -> 10.5x */ - 115, /* 0101 -> 11.5x */ - 125, /* 0110 -> 12.5x */ - 135, /* 0111 -> 13.5x */ - 140, /* 1000 -> 14.0x */ - 150, /* 1001 -> 15.0x */ - 160, /* 1010 -> 16.0x */ - 130, /* 1011 -> 13.0x */ - 145, /* 1100 -> 14.5x */ - 155, /* 1101 -> 15.5x */ - -1, /* 1110 -> RESERVED (13.0x) */ - 120, /* 1111 -> 12.0x */ -}; - -static int __initdata nehemiah_c_clock_ratio[32] = { - 100, /* 0000 -> 10.0x */ - 160, /* 0001 -> 16.0x */ - 40, /* 0010 -> RESERVED */ + 40, /* 0010 -> 4.0x */ 90, /* 0011 -> 9.0x */ 95, /* 0100 -> 9.5x */ -1, /* 0101 -> RESERVED */ - 45, /* 0110 -> RESERVED */ + 45, /* 0110 -> 4.5x */ 55, /* 0111 -> 5.5x */ 60, /* 1000 -> 6.0x */ 70, /* 1001 -> 7.0x */ @@ -340,84 +270,14 @@ static int __initdata nehemiah_c_clock_ 120, /* 1111 -> 12.0x */ }; -static int __initdata nehemiah_a_eblcr[32] = { - 50, /* 0000 -> 5.0x */ - 160, /* 0001 -> 16.0x */ - -1, /* 0010 -> RESERVED */ - 100, /* 0011 -> 10.0x */ - 55, /* 0100 -> 5.5x */ - -1, /* 0101 -> RESERVED */ - -1, /* 0110 -> RESERVED */ - 95, /* 0111 -> 9.5x */ - 90, /* 1000 -> 9.0x */ - 70, /* 1001 -> 7.0x */ - 80, /* 1010 -> 8.0x */ - 60, /* 1011 -> 6.0x */ - 120, /* 1100 -> 12.0x */ - 75, /* 1101 -> 7.5x */ - 85, /* 1110 -> 8.5x */ - 65, /* 1111 -> 6.5x */ - 90, /* 0000 -> 9.0x */ - -1, /* 0001 -> RESERVED */ - 120, /* 0010 -> 12.0x */ - 100, /* 0011 -> 10.0x */ - 135, /* 0100 -> 13.5x */ - 115, /* 0101 -> 11.5x */ - 125, /* 0110 -> 12.5x */ - 105, /* 0111 -> 10.5x */ - 130, /* 1000 -> 13.0x */ - 150, /* 1001 -> 15.0x */ - 160, /* 1010 -> 16.0x */ - 140, /* 1011 -> 14.0x */ - 120, /* 1100 -> 12.0x */ - 155, /* 1101 -> 15.5x */ - -1, /* 1110 -> RESERVED (13.0x) */ - 145 /* 1111 -> 14.5x */ - /* end of table */ -}; -static int __initdata nehemiah_b_eblcr[32] = { - 50, /* 0000 -> 5.0x */ - 160, /* 0001 -> 16.0x */ - -1, /* 0010 -> RESERVED */ - 100, /* 0011 -> 10.0x */ - 55, /* 0100 -> 5.5x */ - -1, /* 0101 -> RESERVED */ - -1, /* 0110 -> RESERVED */ - 95, /* 0111 -> 9.5x */ - 90, /* 1000 -> 9.0x */ - 70, /* 1001 -> 7.0x */ - 80, /* 1010 -> 8.0x */ - 60, /* 1011 -> 6.0x */ - 120, /* 1100 -> 12.0x */ - 75, /* 1101 -> 7.5x */ - 85, /* 1110 -> 8.5x */ - 65, /* 1111 -> 6.5x */ - 90, /* 0000 -> 9.0x */ - 110, /* 0001 -> 11.0x */ - 120, /* 0010 -> 12.0x */ - 100, /* 0011 -> 10.0x */ - 135, /* 0100 -> 13.5x */ - 115, /* 0101 -> 11.5x */ - 125, /* 0110 -> 12.5x */ - 105, /* 0111 -> 10.5x */ - 130, /* 1000 -> 13.0x */ - 150, /* 1001 -> 15.0x */ - 160, /* 1010 -> 16.0x */ - 140, /* 1011 -> 14.0x */ - 120, /* 1100 -> 12.0x */ - 155, /* 1101 -> 15.5x */ - -1, /* 1110 -> RESERVED (13.0x) */ - 145 /* 1111 -> 14.5x */ - /* end of table */ -}; -static int __initdata nehemiah_c_eblcr[32] = { +static int __initdata nehemiah_eblcr[32] = { 50, /* 0000 -> 5.0x */ 160, /* 0001 -> 16.0x */ - 40, /* 0010 -> RESERVED */ + 40, /* 0010 -> 4.0x */ 100, /* 0011 -> 10.0x */ 55, /* 0100 -> 5.5x */ -1, /* 0101 -> RESERVED */ - 45, /* 0110 -> RESERVED */ + 45, /* 0110 -> 4.5x */ 95, /* 0111 -> 9.5x */ 90, /* 1000 -> 9.0x */ 70, /* 1001 -> 7.0x */ @@ -443,7 +303,6 @@ static int __initdata nehemiah_c_eblcr[3 155, /* 1101 -> 15.5x */ -1, /* 1110 -> RESERVED (13.0x) */ 145 /* 1111 -> 14.5x */ - /* end of table */ }; /* diff --git a/arch/i386/kernel/cpu/cpufreq/powernow-k8.c b/arch/i386/kernel/cpu/cpufreq/powernow-k8.c index 2d64916..fe3b670 100644 --- a/arch/i386/kernel/cpu/cpufreq/powernow-k8.c +++ b/arch/i386/kernel/cpu/cpufreq/powernow-k8.c @@ -1289,7 +1289,11 @@ static unsigned int powernowk8_get (unsi if (query_current_values_with_pending_wait(data)) goto out; - khz = find_khz_freq_from_fid(data->currfid); + if (cpu_family == CPU_HW_PSTATE) + khz = find_khz_freq_from_fiddid(data->currfid, data->currdid); + else + khz = find_khz_freq_from_fid(data->currfid); + out: set_cpus_allowed(current, oldmask); diff --git a/arch/i386/kernel/cpu/cyrix.c b/arch/i386/kernel/cpu/cyrix.c index c0c3b59..de27bd0 100644 --- a/arch/i386/kernel/cpu/cyrix.c +++ b/arch/i386/kernel/cpu/cyrix.c @@ -6,6 +6,7 @@ #include #include #include #include +#include #include "cpu.h" @@ -161,19 +162,19 @@ static void __cpuinit set_cx86_inc(void) static void __cpuinit geode_configure(void) { unsigned long flags; - u8 ccr3, ccr4; + u8 ccr3; local_irq_save(flags); /* Suspend on halt power saving and enable #SUSP pin */ setCx86(CX86_CCR2, getCx86(CX86_CCR2) | 0x88); ccr3 = getCx86(CX86_CCR3); - setCx86(CX86_CCR3, (ccr3 & 0x0f) | 0x10); /* Enable */ - - ccr4 = getCx86(CX86_CCR4); - ccr4 |= 0x38; /* FPU fast, DTE cache, Mem bypass */ + setCx86(CX86_CCR3, (ccr3 & 0x0f) | 0x10); /* enable MAPEN */ - setCx86(CX86_CCR3, ccr3); + + /* FPU fast, DTE cache, Mem bypass */ + setCx86(CX86_CCR4, getCx86(CX86_CCR4) | 0x38); + setCx86(CX86_CCR3, ccr3); /* disable MAPEN */ set_cx86_memwb(); set_cx86_reorder(); @@ -183,14 +184,6 @@ static void __cpuinit geode_configure(vo } -#ifdef CONFIG_PCI -static struct pci_device_id __cpuinitdata cyrix_55x0[] = { - { PCI_DEVICE(PCI_VENDOR_ID_CYRIX, PCI_DEVICE_ID_CYRIX_5510) }, - { PCI_DEVICE(PCI_VENDOR_ID_CYRIX, PCI_DEVICE_ID_CYRIX_5520) }, - { }, -}; -#endif - static void __cpuinit init_cyrix(struct cpuinfo_x86 *c) { unsigned char dir0, dir0_msn, dir0_lsn, dir1 = 0; @@ -258,6 +251,8 @@ static void __cpuinit init_cyrix(struct case 4: /* MediaGX/GXm or Geode GXM/GXLV/GX1 */ #ifdef CONFIG_PCI + { + u32 vendor, device; /* It isn't really a PCI quirk directly, but the cure is the same. The MediaGX has deep magic SMM stuff that handles the SB emulation. It thows away the fifo on disable_dma() which @@ -273,22 +268,34 @@ #ifdef CONFIG_PCI printk(KERN_INFO "Working around Cyrix MediaGX virtual DMA bugs.\n"); isa_dma_bridge_buggy = 2; + /* We do this before the PCI layer is running. However we + are safe here as we know the bridge must be a Cyrix + companion and must be present */ + vendor = read_pci_config_16(0, 0, 0x12, PCI_VENDOR_ID); + device = read_pci_config_16(0, 0, 0x12, PCI_DEVICE_ID); /* * The 5510/5520 companion chips have a funky PIT. */ - if (pci_dev_present(cyrix_55x0)) + if (vendor == PCI_VENDOR_ID_CYRIX && + (device == PCI_DEVICE_ID_CYRIX_5510 || device == PCI_DEVICE_ID_CYRIX_5520)) pit_latch_buggy = 1; + } #endif c->x86_cache_size=16; /* Yep 16K integrated cache thats it */ /* GXm supports extended cpuid levels 'ala' AMD */ if (c->cpuid_level == 2) { /* Enable cxMMX extensions (GX1 Datasheet 54) */ - setCx86(CX86_CCR7, getCx86(CX86_CCR7)|1); + setCx86(CX86_CCR7, getCx86(CX86_CCR7) | 1); - /* GXlv/GXm/GX1 */ - if((dir1 >= 0x50 && dir1 <= 0x54) || dir1 >= 0x63) + /* + * GXm : 0x30 ... 0x5f GXm datasheet 51 + * GXlv: 0x6x GXlv datasheet 54 + * ? : 0x7x + * GX1 : 0x8x GX1 datasheet 56 + */ + if((0x30 <= dir1 && dir1 <= 0x6f) || (0x80 <=dir1 && dir1 <= 0x8f)) geode_configure(); get_model_name(c); /* get CPU marketing name */ return; @@ -415,15 +422,14 @@ static void __cpuinit cyrix_identify(str if (dir0 == 5 || dir0 == 3) { - unsigned char ccr3, ccr4; + unsigned char ccr3; unsigned long flags; printk(KERN_INFO "Enabling CPUID on Cyrix processor.\n"); local_irq_save(flags); ccr3 = getCx86(CX86_CCR3); - setCx86(CX86_CCR3, (ccr3 & 0x0f) | 0x10); /* enable MAPEN */ - ccr4 = getCx86(CX86_CCR4); - setCx86(CX86_CCR4, ccr4 | 0x80); /* enable cpuid */ - setCx86(CX86_CCR3, ccr3); /* disable MAPEN */ + setCx86(CX86_CCR3, (ccr3 & 0x0f) | 0x10); /* enable MAPEN */ + setCx86(CX86_CCR4, getCx86(CX86_CCR4) | 0x80); /* enable cpuid */ + setCx86(CX86_CCR3, ccr3); /* disable MAPEN */ local_irq_restore(flags); } } diff --git a/arch/i386/kernel/cpu/mcheck/mce.c b/arch/i386/kernel/cpu/mcheck/mce.c index d555bec..4f10c62 100644 --- a/arch/i386/kernel/cpu/mcheck/mce.c +++ b/arch/i386/kernel/cpu/mcheck/mce.c @@ -12,6 +12,7 @@ #include #include #include +#include #include "mce.h" diff --git a/arch/i386/kernel/cpu/mcheck/mce.h b/arch/i386/kernel/cpu/mcheck/mce.h index 84fd4cf..81fb6e2 100644 --- a/arch/i386/kernel/cpu/mcheck/mce.h +++ b/arch/i386/kernel/cpu/mcheck/mce.h @@ -1,4 +1,5 @@ #include +#include void amd_mcheck_init(struct cpuinfo_x86 *c); void intel_p4_mcheck_init(struct cpuinfo_x86 *c); @@ -9,6 +10,5 @@ void winchip_mcheck_init(struct cpuinfo_ /* Call the installed machine check handler for this CPU setup. */ extern fastcall void (*machine_check_vector)(struct pt_regs *, long error_code); -extern int mce_disabled; extern int nr_mce_banks; diff --git a/arch/i386/kernel/cpu/mcheck/p4.c b/arch/i386/kernel/cpu/mcheck/p4.c index 504434a..8359c19 100644 --- a/arch/i386/kernel/cpu/mcheck/p4.c +++ b/arch/i386/kernel/cpu/mcheck/p4.c @@ -12,6 +12,7 @@ #include #include #include #include +#include #include @@ -59,6 +60,7 @@ static void (*vendor_thermal_interrupt)( fastcall void smp_thermal_interrupt(struct pt_regs *regs) { + exit_idle(); irq_enter(); vendor_thermal_interrupt(regs); irq_exit(); diff --git a/arch/i386/kernel/cpu/mtrr/if.c b/arch/i386/kernel/cpu/mtrr/if.c index 5ae1705..c7d8f17 100644 --- a/arch/i386/kernel/cpu/mtrr/if.c +++ b/arch/i386/kernel/cpu/mtrr/if.c @@ -211,6 +211,9 @@ #endif default: return -ENOTTY; case MTRRIOC_ADD_ENTRY: +#ifdef CONFIG_COMPAT + case MTRRIOC32_ADD_ENTRY: +#endif if (!capable(CAP_SYS_ADMIN)) return -EPERM; err = @@ -218,21 +221,33 @@ #endif file, 0); break; case MTRRIOC_SET_ENTRY: +#ifdef CONFIG_COMPAT + case MTRRIOC32_SET_ENTRY: +#endif if (!capable(CAP_SYS_ADMIN)) return -EPERM; err = mtrr_add(sentry.base, sentry.size, sentry.type, 0); break; case MTRRIOC_DEL_ENTRY: +#ifdef CONFIG_COMPAT + case MTRRIOC32_DEL_ENTRY: +#endif if (!capable(CAP_SYS_ADMIN)) return -EPERM; err = mtrr_file_del(sentry.base, sentry.size, file, 0); break; case MTRRIOC_KILL_ENTRY: +#ifdef CONFIG_COMPAT + case MTRRIOC32_KILL_ENTRY: +#endif if (!capable(CAP_SYS_ADMIN)) return -EPERM; err = mtrr_del(-1, sentry.base, sentry.size); break; case MTRRIOC_GET_ENTRY: +#ifdef CONFIG_COMPAT + case MTRRIOC32_GET_ENTRY: +#endif if (gentry.regnum >= num_var_ranges) return -EINVAL; mtrr_if->get(gentry.regnum, &gentry.base, &size, &type); @@ -249,6 +264,9 @@ #endif break; case MTRRIOC_ADD_PAGE_ENTRY: +#ifdef CONFIG_COMPAT + case MTRRIOC32_ADD_PAGE_ENTRY: +#endif if (!capable(CAP_SYS_ADMIN)) return -EPERM; err = @@ -256,21 +274,33 @@ #endif file, 1); break; case MTRRIOC_SET_PAGE_ENTRY: +#ifdef CONFIG_COMPAT + case MTRRIOC32_SET_PAGE_ENTRY: +#endif if (!capable(CAP_SYS_ADMIN)) return -EPERM; err = mtrr_add_page(sentry.base, sentry.size, sentry.type, 0); break; case MTRRIOC_DEL_PAGE_ENTRY: +#ifdef CONFIG_COMPAT + case MTRRIOC32_DEL_PAGE_ENTRY: +#endif if (!capable(CAP_SYS_ADMIN)) return -EPERM; err = mtrr_file_del(sentry.base, sentry.size, file, 1); break; case MTRRIOC_KILL_PAGE_ENTRY: +#ifdef CONFIG_COMPAT + case MTRRIOC32_KILL_PAGE_ENTRY: +#endif if (!capable(CAP_SYS_ADMIN)) return -EPERM; err = mtrr_del_page(-1, sentry.base, sentry.size); break; case MTRRIOC_GET_PAGE_ENTRY: +#ifdef CONFIG_COMPAT + case MTRRIOC32_GET_PAGE_ENTRY: +#endif if (gentry.regnum >= num_var_ranges) return -EINVAL; mtrr_if->get(gentry.regnum, &gentry.base, &size, &type); @@ -339,7 +369,7 @@ static int mtrr_open(struct inode *inode return single_open(file, mtrr_seq_show, NULL); } -static struct file_operations mtrr_fops = { +static const struct file_operations mtrr_fops = { .owner = THIS_MODULE, .open = mtrr_open, .read = seq_read, diff --git a/arch/i386/kernel/cpu/mtrr/main.c b/arch/i386/kernel/cpu/mtrr/main.c index 16bb7ea..0acfb6a 100644 --- a/arch/i386/kernel/cpu/mtrr/main.c +++ b/arch/i386/kernel/cpu/mtrr/main.c @@ -50,7 +50,7 @@ u32 num_var_ranges = 0; unsigned int *usage_table; static DEFINE_MUTEX(mtrr_mutex); -u32 size_or_mask, size_and_mask; +u64 size_or_mask, size_and_mask; static struct mtrr_ops * mtrr_ops[X86_VENDOR_NUM] = {}; @@ -662,8 +662,8 @@ void __init mtrr_bp_init(void) boot_cpu_data.x86_mask == 0x4)) phys_addr = 36; - size_or_mask = ~((1 << (phys_addr - PAGE_SHIFT)) - 1); - size_and_mask = ~size_or_mask & 0xfff00000; + size_or_mask = ~((1ULL << (phys_addr - PAGE_SHIFT)) - 1); + size_and_mask = ~size_or_mask & 0xfffff00000ULL; } else if (boot_cpu_data.x86_vendor == X86_VENDOR_CENTAUR && boot_cpu_data.x86 == 6) { /* VIA C* family have Intel style MTRRs, but diff --git a/arch/i386/kernel/cpu/mtrr/mtrr.h b/arch/i386/kernel/cpu/mtrr/mtrr.h index d61ea9d..289dfe6 100644 --- a/arch/i386/kernel/cpu/mtrr/mtrr.h +++ b/arch/i386/kernel/cpu/mtrr/mtrr.h @@ -84,7 +84,7 @@ void get_mtrr_state(void); extern void set_mtrr_ops(struct mtrr_ops * ops); -extern u32 size_or_mask, size_and_mask; +extern u64 size_or_mask, size_and_mask; extern struct mtrr_ops * mtrr_if; #define is_cpu(vnd) (mtrr_if && mtrr_if->vendor == X86_VENDOR_##vnd) diff --git a/arch/i386/kernel/cpu/proc.c b/arch/i386/kernel/cpu/proc.c index 6624d85..47e3ebb 100644 --- a/arch/i386/kernel/cpu/proc.c +++ b/arch/i386/kernel/cpu/proc.c @@ -29,7 +29,7 @@ static int show_cpuinfo(struct seq_file NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, "syscall", NULL, NULL, NULL, NULL, NULL, NULL, NULL, "mp", "nx", NULL, "mmxext", NULL, - NULL, "fxsr_opt", "rdtscp", NULL, NULL, "lm", "3dnowext", "3dnow", + NULL, "fxsr_opt", "pdpe1gb", "rdtscp", NULL, "lm", "3dnowext", "3dnow", /* Transmeta-defined */ "recovery", "longrun", NULL, "lrti", NULL, NULL, NULL, NULL, @@ -47,7 +47,7 @@ static int show_cpuinfo(struct seq_file /* Intel-defined (#2) */ "pni", NULL, NULL, "monitor", "ds_cpl", "vmx", "smx", "est", "tm2", "ssse3", "cid", NULL, NULL, "cx16", "xtpr", NULL, - NULL, NULL, "dca", NULL, NULL, NULL, NULL, NULL, + NULL, NULL, "dca", NULL, NULL, NULL, NULL, "popcnt", NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, /* VIA/Cyrix/Centaur-defined */ @@ -57,8 +57,9 @@ static int show_cpuinfo(struct seq_file NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, /* AMD-defined (#2) */ - "lahf_lm", "cmp_legacy", "svm", NULL, "cr8legacy", NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + "lahf_lm", "cmp_legacy", "svm", "extapic", "cr8legacy", "abm", + "sse4a", "misalignsse", + "3dnowprefetch", "osvw", "ibs", NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, }; @@ -69,8 +70,11 @@ static int show_cpuinfo(struct seq_file "ttp", /* thermal trip */ "tm", "stc", + "100mhzsteps", + "hwpstate", NULL, - /* nothing */ /* constant_tsc - moved to flags */ + NULL, /* constant_tsc - moved to flags */ + /* nothing */ }; struct cpuinfo_x86 *c = v; int i, n = c - cpu_data; diff --git a/arch/i386/kernel/cpu/transmeta.c b/arch/i386/kernel/cpu/transmeta.c index 4056fb7..5678d46 100644 --- a/arch/i386/kernel/cpu/transmeta.c +++ b/arch/i386/kernel/cpu/transmeta.c @@ -9,7 +9,7 @@ static void __cpuinit init_transmeta(str { unsigned int cap_mask, uk, max, dummy; unsigned int cms_rev1, cms_rev2; - unsigned int cpu_rev, cpu_freq, cpu_flags, new_cpu_rev; + unsigned int cpu_rev, cpu_freq = 0, cpu_flags, new_cpu_rev; char cpu_info[65]; get_model_name(c); /* Same as AMD/Cyrix */ @@ -72,6 +72,9 @@ static void __cpuinit init_transmeta(str wrmsr(0x80860004, ~0, uk); c->x86_capability[0] = cpuid_edx(0x00000001); wrmsr(0x80860004, cap_mask, uk); + + /* All Transmeta CPUs have a constant TSC */ + set_bit(X86_FEATURE_CONSTANT_TSC, c->x86_capability); /* If we can run i686 user-space code, call us an i686 */ #define USER686 (X86_FEATURE_TSC|X86_FEATURE_CX8|X86_FEATURE_CMOV) diff --git a/arch/i386/kernel/cpuid.c b/arch/i386/kernel/cpuid.c index 51130b3..eeae0d9 100644 --- a/arch/i386/kernel/cpuid.c +++ b/arch/i386/kernel/cpuid.c @@ -48,7 +48,6 @@ static struct class *cpuid_class; #ifdef CONFIG_SMP struct cpuid_command { - int cpu; u32 reg; u32 *data; }; @@ -57,8 +56,7 @@ static void cpuid_smp_cpuid(void *cmd_bl { struct cpuid_command *cmd = (struct cpuid_command *)cmd_block; - if (cmd->cpu == smp_processor_id()) - cpuid(cmd->reg, &cmd->data[0], &cmd->data[1], &cmd->data[2], + cpuid(cmd->reg, &cmd->data[0], &cmd->data[1], &cmd->data[2], &cmd->data[3]); } @@ -70,11 +68,10 @@ static inline void do_cpuid(int cpu, u32 if (cpu == smp_processor_id()) { cpuid(reg, &data[0], &data[1], &data[2], &data[3]); } else { - cmd.cpu = cpu; cmd.reg = reg; cmd.data = data; - smp_call_function(cpuid_smp_cpuid, &cmd, 1, 1); + smp_call_function_single(cpu, cpuid_smp_cpuid, &cmd, 1, 1); } preempt_enable(); } @@ -148,7 +145,7 @@ static int cpuid_open(struct inode *inod /* * File operations we support */ -static struct file_operations cpuid_fops = { +static const struct file_operations cpuid_fops = { .owner = THIS_MODULE, .llseek = cpuid_seek, .read = cpuid_read, diff --git a/arch/i386/kernel/e820.c b/arch/i386/kernel/e820.c index f391abc..70f3956 100644 --- a/arch/i386/kernel/e820.c +++ b/arch/i386/kernel/e820.c @@ -14,6 +14,7 @@ #include #include #include #include +#include #ifdef CONFIG_EFI int efi_enabled = 0; @@ -156,21 +157,22 @@ static struct resource standard_io_resou .flags = IORESOURCE_BUSY | IORESOURCE_IO } }; -static int romsignature(const unsigned char *x) +#define ROMSIGNATURE 0xaa55 + +static int __init romsignature(const unsigned char *rom) { unsigned short sig; - int ret = 0; - if (probe_kernel_address((const unsigned short *)x, sig) == 0) - ret = (sig == 0xaa55); - return ret; + + return probe_kernel_address((const unsigned short *)rom, sig) == 0 && + sig == ROMSIGNATURE; } static int __init romchecksum(unsigned char *rom, unsigned long length) { - unsigned char *p, sum = 0; + unsigned char sum; - for (p = rom; p < rom + length; p++) - sum += *p; + for (sum = 0; length; length--) + sum += *rom++; return sum == 0; } diff --git a/arch/i386/kernel/entry.S b/arch/i386/kernel/entry.S index 5e47683..18bddcb 100644 --- a/arch/i386/kernel/entry.S +++ b/arch/i386/kernel/entry.S @@ -30,7 +30,7 @@ * 18(%esp) - %eax * 1C(%esp) - %ds * 20(%esp) - %es - * 24(%esp) - %gs + * 24(%esp) - %fs * 28(%esp) - orig_eax * 2C(%esp) - %eip * 30(%esp) - %cs @@ -99,9 +99,9 @@ #endif #define SAVE_ALL \ cld; \ - pushl %gs; \ + pushl %fs; \ CFI_ADJUST_CFA_OFFSET 4;\ - /*CFI_REL_OFFSET gs, 0;*/\ + /*CFI_REL_OFFSET fs, 0;*/\ pushl %es; \ CFI_ADJUST_CFA_OFFSET 4;\ /*CFI_REL_OFFSET es, 0;*/\ @@ -133,7 +133,7 @@ #define SAVE_ALL \ movl %edx, %ds; \ movl %edx, %es; \ movl $(__KERNEL_PDA), %edx; \ - movl %edx, %gs + movl %edx, %fs #define RESTORE_INT_REGS \ popl %ebx; \ @@ -166,9 +166,9 @@ #define RESTORE_REGS \ 2: popl %es; \ CFI_ADJUST_CFA_OFFSET -4;\ /*CFI_RESTORE es;*/\ -3: popl %gs; \ +3: popl %fs; \ CFI_ADJUST_CFA_OFFSET -4;\ - /*CFI_RESTORE gs;*/\ + /*CFI_RESTORE fs;*/\ .pushsection .fixup,"ax"; \ 4: movl $0,(%esp); \ jmp 1b; \ @@ -227,6 +227,7 @@ ENTRY(ret_from_fork) CFI_ADJUST_CFA_OFFSET -4 jmp syscall_exit CFI_ENDPROC +END(ret_from_fork) /* * Return to user mode is not as complex as all this looks, @@ -258,6 +259,7 @@ ENTRY(resume_userspace) # int/exception return? jne work_pending jmp restore_all +END(ret_from_exception) #ifdef CONFIG_PREEMPT ENTRY(resume_kernel) @@ -272,6 +274,7 @@ need_resched: jz restore_all call preempt_schedule_irq jmp need_resched +END(resume_kernel) #endif CFI_ENDPROC @@ -349,16 +352,17 @@ #endif movl PT_OLDESP(%esp), %ecx xorl %ebp,%ebp TRACE_IRQS_ON -1: mov PT_GS(%esp), %gs +1: mov PT_FS(%esp), %fs ENABLE_INTERRUPTS_SYSEXIT CFI_ENDPROC .pushsection .fixup,"ax" -2: movl $0,PT_GS(%esp) +2: movl $0,PT_FS(%esp) jmp 1b .section __ex_table,"a" .align 4 .long 1b,2b .popsection +ENDPROC(sysenter_entry) # system call handler stub ENTRY(system_call) @@ -459,6 +463,7 @@ #endif CFI_ADJUST_CFA_OFFSET -8 jmp restore_nocheck CFI_ENDPROC +ENDPROC(system_call) # perform work that needs to be done immediately before resumption ALIGN @@ -504,6 +509,7 @@ #endif xorl %edx, %edx call do_notify_resume jmp resume_userspace_sig +END(work_pending) # perform syscall exit tracing ALIGN @@ -519,6 +525,7 @@ syscall_trace_entry: cmpl $(nr_syscalls), %eax jnae syscall_call jmp syscall_exit +END(syscall_trace_entry) # perform syscall exit tracing ALIGN @@ -532,6 +539,7 @@ syscall_exit_work: movl $1, %edx call do_syscall_trace jmp resume_userspace +END(syscall_exit_work) CFI_ENDPROC RING0_INT_FRAME # can't unwind into user space anyway @@ -542,15 +550,17 @@ syscall_fault: GET_THREAD_INFO(%ebp) movl $-EFAULT,PT_EAX(%esp) jmp resume_userspace +END(syscall_fault) syscall_badsys: movl $-ENOSYS,PT_EAX(%esp) jmp resume_userspace +END(syscall_badsys) CFI_ENDPROC #define FIXUP_ESPFIX_STACK \ /* since we are on a wrong stack, we cant make it a C code :( */ \ - movl %gs:PDA_cpu, %ebx; \ + movl %fs:PDA_cpu, %ebx; \ PER_CPU(cpu_gdt_descr, %ebx); \ movl GDS_address(%ebx), %ebx; \ GET_DESC_BASE(GDT_ENTRY_ESPFIX_SS, %ebx, %eax, %ax, %al, %ah); \ @@ -581,9 +591,9 @@ #define UNWIND_ESPFIX_STACK \ ENTRY(interrupt) .text -vector=0 ENTRY(irq_entries_start) RING0_INT_FRAME +vector=0 .rept NR_IRQS ALIGN .if vector @@ -592,11 +602,16 @@ ENTRY(irq_entries_start) 1: pushl $~(vector) CFI_ADJUST_CFA_OFFSET 4 jmp common_interrupt -.data + .previous .long 1b -.text + .text vector=vector+1 .endr +END(irq_entries_start) + +.previous +END(interrupt) +.previous /* * the CPU automatically disables interrupts when executing an IRQ vector, @@ -609,6 +624,7 @@ common_interrupt: movl %esp,%eax call do_IRQ jmp ret_from_intr +ENDPROC(common_interrupt) CFI_ENDPROC #define BUILD_INTERRUPT(name, nr) \ @@ -621,18 +637,24 @@ ENTRY(name) \ movl %esp,%eax; \ call smp_/**/name; \ jmp ret_from_intr; \ - CFI_ENDPROC + CFI_ENDPROC; \ +ENDPROC(name) /* The include is where all of the SMP etc. interrupts come from */ #include "entry_arch.h" +/* This alternate entry is needed because we hijack the apic LVTT */ +#if defined(CONFIG_VMI) && defined(CONFIG_X86_LOCAL_APIC) +BUILD_INTERRUPT(apic_vmi_timer_interrupt,LOCAL_TIMER_VECTOR) +#endif + KPROBE_ENTRY(page_fault) RING0_EC_FRAME pushl $do_page_fault CFI_ADJUST_CFA_OFFSET 4 ALIGN error_code: - /* the function address is in %gs's slot on the stack */ + /* the function address is in %fs's slot on the stack */ pushl %es CFI_ADJUST_CFA_OFFSET 4 /*CFI_REL_OFFSET es, 0*/ @@ -661,20 +683,20 @@ error_code: CFI_ADJUST_CFA_OFFSET 4 CFI_REL_OFFSET ebx, 0 cld - pushl %gs + pushl %fs CFI_ADJUST_CFA_OFFSET 4 - /*CFI_REL_OFFSET gs, 0*/ + /*CFI_REL_OFFSET fs, 0*/ movl $(__KERNEL_PDA), %ecx - movl %ecx, %gs + movl %ecx, %fs UNWIND_ESPFIX_STACK popl %ecx CFI_ADJUST_CFA_OFFSET -4 /*CFI_REGISTER es, ecx*/ - movl PT_GS(%esp), %edi # get the function address + movl PT_FS(%esp), %edi # get the function address movl PT_ORIG_EAX(%esp), %edx # get the error code movl $-1, PT_ORIG_EAX(%esp) # no syscall to restart - mov %ecx, PT_GS(%esp) - /*CFI_REL_OFFSET gs, ES*/ + mov %ecx, PT_FS(%esp) + /*CFI_REL_OFFSET fs, ES*/ movl $(__USER_DS), %ecx movl %ecx, %ds movl %ecx, %es @@ -692,6 +714,7 @@ ENTRY(coprocessor_error) CFI_ADJUST_CFA_OFFSET 4 jmp error_code CFI_ENDPROC +END(coprocessor_error) ENTRY(simd_coprocessor_error) RING0_INT_FRAME @@ -701,6 +724,7 @@ ENTRY(simd_coprocessor_error) CFI_ADJUST_CFA_OFFSET 4 jmp error_code CFI_ENDPROC +END(simd_coprocessor_error) ENTRY(device_not_available) RING0_INT_FRAME @@ -721,6 +745,7 @@ device_not_available_emulate: CFI_ADJUST_CFA_OFFSET -4 jmp ret_from_exception CFI_ENDPROC +END(device_not_available) /* * Debug traps and NMI can happen at the one SYSENTER instruction @@ -864,10 +889,12 @@ ENTRY(native_iret) .align 4 .long 1b,iret_exc .previous +END(native_iret) ENTRY(native_irq_enable_sysexit) sti sysexit +END(native_irq_enable_sysexit) #endif KPROBE_ENTRY(int3) @@ -890,6 +917,7 @@ ENTRY(overflow) CFI_ADJUST_CFA_OFFSET 4 jmp error_code CFI_ENDPROC +END(overflow) ENTRY(bounds) RING0_INT_FRAME @@ -899,6 +927,7 @@ ENTRY(bounds) CFI_ADJUST_CFA_OFFSET 4 jmp error_code CFI_ENDPROC +END(bounds) ENTRY(invalid_op) RING0_INT_FRAME @@ -908,6 +937,7 @@ ENTRY(invalid_op) CFI_ADJUST_CFA_OFFSET 4 jmp error_code CFI_ENDPROC +END(invalid_op) ENTRY(coprocessor_segment_overrun) RING0_INT_FRAME @@ -917,6 +947,7 @@ ENTRY(coprocessor_segment_overrun) CFI_ADJUST_CFA_OFFSET 4 jmp error_code CFI_ENDPROC +END(coprocessor_segment_overrun) ENTRY(invalid_TSS) RING0_EC_FRAME @@ -924,6 +955,7 @@ ENTRY(invalid_TSS) CFI_ADJUST_CFA_OFFSET 4 jmp error_code CFI_ENDPROC +END(invalid_TSS) ENTRY(segment_not_present) RING0_EC_FRAME @@ -931,6 +963,7 @@ ENTRY(segment_not_present) CFI_ADJUST_CFA_OFFSET 4 jmp error_code CFI_ENDPROC +END(segment_not_present) ENTRY(stack_segment) RING0_EC_FRAME @@ -938,6 +971,7 @@ ENTRY(stack_segment) CFI_ADJUST_CFA_OFFSET 4 jmp error_code CFI_ENDPROC +END(stack_segment) KPROBE_ENTRY(general_protection) RING0_EC_FRAME @@ -953,6 +987,7 @@ ENTRY(alignment_check) CFI_ADJUST_CFA_OFFSET 4 jmp error_code CFI_ENDPROC +END(alignment_check) ENTRY(divide_error) RING0_INT_FRAME @@ -962,6 +997,7 @@ ENTRY(divide_error) CFI_ADJUST_CFA_OFFSET 4 jmp error_code CFI_ENDPROC +END(divide_error) #ifdef CONFIG_X86_MCE ENTRY(machine_check) @@ -972,6 +1008,7 @@ ENTRY(machine_check) CFI_ADJUST_CFA_OFFSET 4 jmp error_code CFI_ENDPROC +END(machine_check) #endif ENTRY(spurious_interrupt_bug) @@ -982,6 +1019,7 @@ ENTRY(spurious_interrupt_bug) CFI_ADJUST_CFA_OFFSET 4 jmp error_code CFI_ENDPROC +END(spurious_interrupt_bug) ENTRY(kernel_thread_helper) pushl $0 # fake return address for unwinder diff --git a/arch/i386/kernel/head.S b/arch/i386/kernel/head.S index edef508..3fa7f93 100644 --- a/arch/i386/kernel/head.S +++ b/arch/i386/kernel/head.S @@ -53,6 +53,7 @@ #define INIT_MAP_BEYOND_END (128*1024) * any particular GDT layout, because we load our own as soon as we * can. */ +.section .text.head,"ax",@progbits ENTRY(startup_32) #ifdef CONFIG_PARAVIRT @@ -103,7 +104,7 @@ #endif movzwl OLD_CL_OFFSET,%esi addl $(OLD_CL_BASE_ADDR),%esi 2: - movl $(saved_command_line - __PAGE_OFFSET),%edi + movl $(boot_command_line - __PAGE_OFFSET),%edi movl $(COMMAND_LINE_SIZE/4),%ecx rep movsl @@ -141,16 +142,25 @@ page_pde_offset = (__PAGE_OFFSET >> 20); jb 10b movl %edi,(init_pg_tables_end - __PAGE_OFFSET) -#ifdef CONFIG_SMP xorl %ebx,%ebx /* This is the boot CPU (BSP) */ jmp 3f - /* * Non-boot CPU entry point; entered from trampoline.S * We can't lgdt here, because lgdt itself uses a data segment, but * we know the trampoline has already loaded the boot_gdt_table GDT * for us. + * + * If cpu hotplug is not supported then this code can go in init section + * which will be freed later */ + +#ifdef CONFIG_HOTPLUG_CPU +.section .text,"ax",@progbits +#else +.section .init.text,"ax",@progbits +#endif + +#ifdef CONFIG_SMP ENTRY(startup_32_smp) cld movl $(__BOOT_DS),%eax @@ -208,8 +218,8 @@ #define cr4_bits mmu_cr4_features-__PAGE xorl %ebx,%ebx incl %ebx -3: #endif /* CONFIG_SMP */ +3: /* * Enable paging @@ -309,7 +319,7 @@ is386: movl $2,%ecx # set MP call check_x87 call setup_pda - lgdt cpu_gdt_descr + lgdt early_gdt_descr lidt idt_descr ljmp $(__KERNEL_CS),$1f 1: movl $(__KERNEL_DS),%eax # reload all the segment registers @@ -319,12 +329,12 @@ is386: movl $2,%ecx # set MP movl %eax,%ds movl %eax,%es - xorl %eax,%eax # Clear FS and LDT - movl %eax,%fs + xorl %eax,%eax # Clear GS and LDT + movl %eax,%gs lldt %ax movl $(__KERNEL_PDA),%eax - mov %eax,%gs + mov %eax,%fs cld # gcc2 wants the direction flag cleared at all times pushl $0 # fake return address for unwinder @@ -360,12 +370,12 @@ check_x87: * cpu_gdt_table and boot_pda; for secondary CPUs, these will be * that CPU's GDT and PDA. */ -setup_pda: +ENTRY(setup_pda) /* get the PDA pointer */ movl start_pda, %eax /* slot the PDA address into the GDT */ - mov cpu_gdt_descr+2, %ecx + mov early_gdt_descr+2, %ecx mov %ax, (__KERNEL_PDA+0+2)(%ecx) /* base & 0x0000ffff */ shr $16, %eax mov %al, (__KERNEL_PDA+4+0)(%ecx) /* base & 0x00ff0000 */ @@ -492,6 +502,7 @@ #endif #endif iret +.section .text #ifdef CONFIG_PARAVIRT startup_paravirt: cld @@ -502,10 +513,11 @@ startup_paravirt: pushl %ecx pushl %eax - /* paravirt.o is last in link, and that probe fn never returns */ pushl $__start_paravirtprobe 1: movl 0(%esp), %eax + cmpl $__stop_paravirtprobe, %eax + je unhandled_paravirt pushl (%eax) movl 8(%esp), %eax call *(%esp) @@ -517,6 +529,10 @@ startup_paravirt: addl $4, (%esp) jmp 1b + +unhandled_paravirt: + /* Nothing wanted us: we're screwed. */ + ud2 #endif /* @@ -581,7 +597,7 @@ idt_descr: # boot GDT descriptor (later on used by CPU#0): .word 0 # 32 bit align gdt_desc.address -ENTRY(cpu_gdt_descr) +ENTRY(early_gdt_descr) .word GDT_ENTRIES*8-1 .long cpu_gdt_table diff --git a/arch/i386/kernel/hpet.c b/arch/i386/kernel/hpet.c index 45a8685..e1006b7 100644 --- a/arch/i386/kernel/hpet.c +++ b/arch/i386/kernel/hpet.c @@ -1,4 +1,5 @@ #include +#include #include #include #include @@ -6,17 +7,278 @@ #include #include #include +extern struct clock_event_device *global_clock_event; + #define HPET_MASK CLOCKSOURCE_MASK(32) #define HPET_SHIFT 22 /* FSEC = 10^-15 NSEC = 10^-9 */ #define FSEC_PER_NSEC 1000000 -static void *hpet_ptr; +/* + * HPET address is set in acpi/boot.c, when an ACPI entry exists + */ +unsigned long hpet_address; +static void __iomem * hpet_virt_address; + +static inline unsigned long hpet_readl(unsigned long a) +{ + return readl(hpet_virt_address + a); +} + +static inline void hpet_writel(unsigned long d, unsigned long a) +{ + writel(d, hpet_virt_address + a); +} + +/* + * HPET command line enable / disable + */ +static int boot_hpet_disable; + +static int __init hpet_setup(char* str) +{ + if (str) { + if (!strncmp("disable", str, 7)) + boot_hpet_disable = 1; + } + return 1; +} +__setup("hpet=", hpet_setup); + +static inline int is_hpet_capable(void) +{ + return (!boot_hpet_disable && hpet_address); +} + +/* + * HPET timer interrupt enable / disable + */ +static int hpet_legacy_int_enabled; + +/** + * is_hpet_enabled - check whether the hpet timer interrupt is enabled + */ +int is_hpet_enabled(void) +{ + return is_hpet_capable() && hpet_legacy_int_enabled; +} + +/* + * When the hpet driver (/dev/hpet) is enabled, we need to reserve + * timer 0 and timer 1 in case of RTC emulation. + */ +#ifdef CONFIG_HPET +static void hpet_reserve_platform_timers(unsigned long id) +{ + struct hpet __iomem *hpet = hpet_virt_address; + struct hpet_timer __iomem *timer = &hpet->hpet_timers[2]; + unsigned int nrtimers, i; + struct hpet_data hd; + + nrtimers = ((id & HPET_ID_NUMBER) >> HPET_ID_NUMBER_SHIFT) + 1; + + memset(&hd, 0, sizeof (hd)); + hd.hd_phys_address = hpet_address; + hd.hd_address = hpet_virt_address; + hd.hd_nirqs = nrtimers; + hd.hd_flags = HPET_DATA_PLATFORM; + hpet_reserve_timer(&hd, 0); + +#ifdef CONFIG_HPET_EMULATE_RTC + hpet_reserve_timer(&hd, 1); +#endif + + hd.hd_irq[0] = HPET_LEGACY_8254; + hd.hd_irq[1] = HPET_LEGACY_RTC; + + for (i = 2; i < nrtimers; timer++, i++) + hd.hd_irq[i] = (timer->hpet_config & Tn_INT_ROUTE_CNF_MASK) >> + Tn_INT_ROUTE_CNF_SHIFT; + + hpet_alloc(&hd); + +} +#else +static void hpet_reserve_platform_timers(unsigned long id) { } +#endif + +/* + * Common hpet info + */ +static unsigned long hpet_period; + +static void hpet_set_mode(enum clock_event_mode mode, + struct clock_event_device *evt); +static int hpet_next_event(unsigned long delta, + struct clock_event_device *evt); + +/* + * The hpet clock event device + */ +static struct clock_event_device hpet_clockevent = { + .name = "hpet", + .features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT, + .set_mode = hpet_set_mode, + .set_next_event = hpet_next_event, + .shift = 32, + .irq = 0, +}; + +static void hpet_start_counter(void) +{ + unsigned long cfg = hpet_readl(HPET_CFG); + + cfg &= ~HPET_CFG_ENABLE; + hpet_writel(cfg, HPET_CFG); + hpet_writel(0, HPET_COUNTER); + hpet_writel(0, HPET_COUNTER + 4); + cfg |= HPET_CFG_ENABLE; + hpet_writel(cfg, HPET_CFG); +} + +static void hpet_enable_int(void) +{ + unsigned long cfg = hpet_readl(HPET_CFG); + + cfg |= HPET_CFG_LEGACY; + hpet_writel(cfg, HPET_CFG); + hpet_legacy_int_enabled = 1; +} + +static void hpet_set_mode(enum clock_event_mode mode, + struct clock_event_device *evt) +{ + unsigned long cfg, cmp, now; + uint64_t delta; + + switch(mode) { + case CLOCK_EVT_MODE_PERIODIC: + delta = ((uint64_t)(NSEC_PER_SEC/HZ)) * hpet_clockevent.mult; + delta >>= hpet_clockevent.shift; + now = hpet_readl(HPET_COUNTER); + cmp = now + (unsigned long) delta; + cfg = hpet_readl(HPET_T0_CFG); + cfg |= HPET_TN_ENABLE | HPET_TN_PERIODIC | + HPET_TN_SETVAL | HPET_TN_32BIT; + hpet_writel(cfg, HPET_T0_CFG); + /* + * The first write after writing TN_SETVAL to the + * config register sets the counter value, the second + * write sets the period. + */ + hpet_writel(cmp, HPET_T0_CMP); + udelay(1); + hpet_writel((unsigned long) delta, HPET_T0_CMP); + break; + + case CLOCK_EVT_MODE_ONESHOT: + cfg = hpet_readl(HPET_T0_CFG); + cfg &= ~HPET_TN_PERIODIC; + cfg |= HPET_TN_ENABLE | HPET_TN_32BIT; + hpet_writel(cfg, HPET_T0_CFG); + break; + + case CLOCK_EVT_MODE_UNUSED: + case CLOCK_EVT_MODE_SHUTDOWN: + cfg = hpet_readl(HPET_T0_CFG); + cfg &= ~HPET_TN_ENABLE; + hpet_writel(cfg, HPET_T0_CFG); + break; + } +} + +static int hpet_next_event(unsigned long delta, + struct clock_event_device *evt) +{ + unsigned long cnt; + + cnt = hpet_readl(HPET_COUNTER); + cnt += delta; + hpet_writel(cnt, HPET_T0_CMP); + + return ((long)(hpet_readl(HPET_COUNTER) - cnt ) > 0); +} + +/* + * Try to setup the HPET timer + */ +int __init hpet_enable(void) +{ + unsigned long id; + uint64_t hpet_freq; + + if (!is_hpet_capable()) + return 0; + + hpet_virt_address = ioremap_nocache(hpet_address, HPET_MMAP_SIZE); + + /* + * Read the period and check for a sane value: + */ + hpet_period = hpet_readl(HPET_PERIOD); + if (hpet_period < HPET_MIN_PERIOD || hpet_period > HPET_MAX_PERIOD) + goto out_nohpet; + + /* + * The period is a femto seconds value. We need to calculate the + * scaled math multiplication factor for nanosecond to hpet tick + * conversion. + */ + hpet_freq = 1000000000000000ULL; + do_div(hpet_freq, hpet_period); + hpet_clockevent.mult = div_sc((unsigned long) hpet_freq, + NSEC_PER_SEC, 32); + /* Calculate the min / max delta */ + hpet_clockevent.max_delta_ns = clockevent_delta2ns(0x7FFFFFFF, + &hpet_clockevent); + hpet_clockevent.min_delta_ns = clockevent_delta2ns(0x30, + &hpet_clockevent); + + /* + * Read the HPET ID register to retrieve the IRQ routing + * information and the number of channels + */ + id = hpet_readl(HPET_ID); + +#ifdef CONFIG_HPET_EMULATE_RTC + /* + * The legacy routing mode needs at least two channels, tick timer + * and the rtc emulation channel. + */ + if (!(id & HPET_ID_NUMBER)) + goto out_nohpet; +#endif + + /* Start the counter */ + hpet_start_counter(); + + if (id & HPET_ID_LEGSUP) { + hpet_enable_int(); + hpet_reserve_platform_timers(id); + /* + * Start hpet with the boot cpu mask and make it + * global after the IO_APIC has been initialized. + */ + hpet_clockevent.cpumask =cpumask_of_cpu(0); + clockevents_register_device(&hpet_clockevent); + global_clock_event = &hpet_clockevent; + return 1; + } + return 0; +out_nohpet: + iounmap(hpet_virt_address); + hpet_virt_address = NULL; + return 0; +} + +/* + * Clock source related code + */ static cycle_t read_hpet(void) { - return (cycle_t)readl(hpet_ptr); + return (cycle_t)hpet_readl(HPET_COUNTER); } static struct clocksource clocksource_hpet = { @@ -24,29 +286,17 @@ static struct clocksource clocksource_hp .rating = 250, .read = read_hpet, .mask = HPET_MASK, - .mult = 0, /* set below */ .shift = HPET_SHIFT, - .is_continuous = 1, + .flags = CLOCK_SOURCE_IS_CONTINUOUS, }; static int __init init_hpet_clocksource(void) { - unsigned long hpet_period; - void __iomem* hpet_base; u64 tmp; - int err; - if (!is_hpet_enabled()) + if (!hpet_virt_address) return -ENODEV; - /* calculate the hpet address: */ - hpet_base = - (void __iomem*)ioremap_nocache(hpet_address, HPET_MMAP_SIZE); - hpet_ptr = hpet_base + HPET_COUNTER; - - /* calculate the frequency: */ - hpet_period = readl(hpet_base + HPET_PERIOD); - /* * hpet period is in femto seconds per cycle * so we need to convert this to ns/cyc units @@ -62,11 +312,218 @@ static int __init init_hpet_clocksource( do_div(tmp, FSEC_PER_NSEC); clocksource_hpet.mult = (u32)tmp; - err = clocksource_register(&clocksource_hpet); - if (err) - iounmap(hpet_base); - - return err; + return clocksource_register(&clocksource_hpet); } module_init(init_hpet_clocksource); + +#ifdef CONFIG_HPET_EMULATE_RTC + +/* HPET in LegacyReplacement Mode eats up RTC interrupt line. When, HPET + * is enabled, we support RTC interrupt functionality in software. + * RTC has 3 kinds of interrupts: + * 1) Update Interrupt - generate an interrupt, every sec, when RTC clock + * is updated + * 2) Alarm Interrupt - generate an interrupt at a specific time of day + * 3) Periodic Interrupt - generate periodic interrupt, with frequencies + * 2Hz-8192Hz (2Hz-64Hz for non-root user) (all freqs in powers of 2) + * (1) and (2) above are implemented using polling at a frequency of + * 64 Hz. The exact frequency is a tradeoff between accuracy and interrupt + * overhead. (DEFAULT_RTC_INT_FREQ) + * For (3), we use interrupts at 64Hz or user specified periodic + * frequency, whichever is higher. + */ +#include +#include + +#define DEFAULT_RTC_INT_FREQ 64 +#define DEFAULT_RTC_SHIFT 6 +#define RTC_NUM_INTS 1 + +static unsigned long hpet_rtc_flags; +static unsigned long hpet_prev_update_sec; +static struct rtc_time hpet_alarm_time; +static unsigned long hpet_pie_count; +static unsigned long hpet_t1_cmp; +static unsigned long hpet_default_delta; +static unsigned long hpet_pie_delta; +static unsigned long hpet_pie_limit; + +/* + * Timer 1 for RTC emulation. We use one shot mode, as periodic mode + * is not supported by all HPET implementations for timer 1. + * + * hpet_rtc_timer_init() is called when the rtc is initialized. + */ +int hpet_rtc_timer_init(void) +{ + unsigned long cfg, cnt, delta, flags; + + if (!is_hpet_enabled()) + return 0; + + if (!hpet_default_delta) { + uint64_t clc; + + clc = (uint64_t) hpet_clockevent.mult * NSEC_PER_SEC; + clc >>= hpet_clockevent.shift + DEFAULT_RTC_SHIFT; + hpet_default_delta = (unsigned long) clc; + } + + if (!(hpet_rtc_flags & RTC_PIE) || hpet_pie_limit) + delta = hpet_default_delta; + else + delta = hpet_pie_delta; + + local_irq_save(flags); + + cnt = delta + hpet_readl(HPET_COUNTER); + hpet_writel(cnt, HPET_T1_CMP); + hpet_t1_cmp = cnt; + + cfg = hpet_readl(HPET_T1_CFG); + cfg &= ~HPET_TN_PERIODIC; + cfg |= HPET_TN_ENABLE | HPET_TN_32BIT; + hpet_writel(cfg, HPET_T1_CFG); + + local_irq_restore(flags); + + return 1; +} + +/* + * The functions below are called from rtc driver. + * Return 0 if HPET is not being used. + * Otherwise do the necessary changes and return 1. + */ +int hpet_mask_rtc_irq_bit(unsigned long bit_mask) +{ + if (!is_hpet_enabled()) + return 0; + + hpet_rtc_flags &= ~bit_mask; + return 1; +} + +int hpet_set_rtc_irq_bit(unsigned long bit_mask) +{ + unsigned long oldbits = hpet_rtc_flags; + + if (!is_hpet_enabled()) + return 0; + + hpet_rtc_flags |= bit_mask; + + if (!oldbits) + hpet_rtc_timer_init(); + + return 1; +} + +int hpet_set_alarm_time(unsigned char hrs, unsigned char min, + unsigned char sec) +{ + if (!is_hpet_enabled()) + return 0; + + hpet_alarm_time.tm_hour = hrs; + hpet_alarm_time.tm_min = min; + hpet_alarm_time.tm_sec = sec; + + return 1; +} + +int hpet_set_periodic_freq(unsigned long freq) +{ + uint64_t clc; + + if (!is_hpet_enabled()) + return 0; + + if (freq <= DEFAULT_RTC_INT_FREQ) + hpet_pie_limit = DEFAULT_RTC_INT_FREQ / freq; + else { + clc = (uint64_t) hpet_clockevent.mult * NSEC_PER_SEC; + do_div(clc, freq); + clc >>= hpet_clockevent.shift; + hpet_pie_delta = (unsigned long) clc; + } + return 1; +} + +int hpet_rtc_dropped_irq(void) +{ + return is_hpet_enabled(); +} + +static void hpet_rtc_timer_reinit(void) +{ + unsigned long cfg, delta; + int lost_ints = -1; + + if (unlikely(!hpet_rtc_flags)) { + cfg = hpet_readl(HPET_T1_CFG); + cfg &= ~HPET_TN_ENABLE; + hpet_writel(cfg, HPET_T1_CFG); + return; + } + + if (!(hpet_rtc_flags & RTC_PIE) || hpet_pie_limit) + delta = hpet_default_delta; + else + delta = hpet_pie_delta; + + /* + * Increment the comparator value until we are ahead of the + * current count. + */ + do { + hpet_t1_cmp += delta; + hpet_writel(hpet_t1_cmp, HPET_T1_CMP); + lost_ints++; + } while ((long)(hpet_readl(HPET_COUNTER) - hpet_t1_cmp) > 0); + + if (lost_ints) { + if (hpet_rtc_flags & RTC_PIE) + hpet_pie_count += lost_ints; + if (printk_ratelimit()) + printk(KERN_WARNING "rtc: lost %d interrupts\n", + lost_ints); + } +} + +irqreturn_t hpet_rtc_interrupt(int irq, void *dev_id) +{ + struct rtc_time curr_time; + unsigned long rtc_int_flag = 0; + + hpet_rtc_timer_reinit(); + + if (hpet_rtc_flags & (RTC_UIE | RTC_AIE)) + rtc_get_rtc_time(&curr_time); + + if (hpet_rtc_flags & RTC_UIE && + curr_time.tm_sec != hpet_prev_update_sec) { + rtc_int_flag = RTC_UF; + hpet_prev_update_sec = curr_time.tm_sec; + } + + if (hpet_rtc_flags & RTC_PIE && + ++hpet_pie_count >= hpet_pie_limit) { + rtc_int_flag |= RTC_PF; + hpet_pie_count = 0; + } + + if (hpet_rtc_flags & RTC_PIE && + (curr_time.tm_sec == hpet_alarm_time.tm_sec) && + (curr_time.tm_min == hpet_alarm_time.tm_min) && + (curr_time.tm_hour == hpet_alarm_time.tm_hour)) + rtc_int_flag |= RTC_AF; + + if (rtc_int_flag) { + rtc_int_flag |= (RTC_IRQF | (RTC_NUM_INTS << 8)); + rtc_interrupt(rtc_int_flag, dev_id); + } + return IRQ_HANDLED; +} +#endif diff --git a/arch/i386/kernel/i8253.c b/arch/i386/kernel/i8253.c index 9a0060b..a6bc7bb 100644 --- a/arch/i386/kernel/i8253.c +++ b/arch/i386/kernel/i8253.c @@ -2,7 +2,7 @@ * i8253.c 8253/PIT functions * */ -#include +#include #include #include #include @@ -19,17 +19,97 @@ #include "io_ports.h" DEFINE_SPINLOCK(i8253_lock); EXPORT_SYMBOL(i8253_lock); -void setup_pit_timer(void) +/* + * 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) +{ + unsigned long flags; + + spin_lock_irqsave(&i8253_lock, flags); + + switch(mode) { + case CLOCK_EVT_MODE_PERIODIC: + /* binary, mode 2, LSB/MSB, ch 0 */ + outb_p(0x34, PIT_MODE); + udelay(10); + outb_p(LATCH & 0xff , PIT_CH0); /* LSB */ + udelay(10); + outb(LATCH >> 8 , PIT_CH0); /* MSB */ + break; + + case CLOCK_EVT_MODE_ONESHOT: + case CLOCK_EVT_MODE_SHUTDOWN: + case CLOCK_EVT_MODE_UNUSED: + /* One shot setup */ + outb_p(0x38, PIT_MODE); + udelay(10); + break; + } + spin_unlock_irqrestore(&i8253_lock, flags); +} + +/* + * 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) { unsigned long flags; spin_lock_irqsave(&i8253_lock, flags); - outb_p(0x34,PIT_MODE); /* binary, mode 2, LSB/MSB, ch 0 */ - udelay(10); - outb_p(LATCH & 0xff , PIT_CH0); /* LSB */ - udelay(10); - outb(LATCH >> 8 , PIT_CH0); /* MSB */ + outb_p(delta & 0xff , PIT_CH0); /* LSB */ + outb(delta >> 8 , PIT_CH0); /* MSB */ spin_unlock_irqrestore(&i8253_lock, flags); + + 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() + */ +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, + .shift = 32, + .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) +{ + /* + * Start pit with the boot cpu mask and make it global after the + * IO_APIC has been initialized. + */ + pit_clockevent.cpumask = cpumask_of_cpu(0); + pit_clockevent.mult = div_sc(CLOCK_TICK_RATE, NSEC_PER_SEC, 32); + pit_clockevent.max_delta_ns = + clockevent_delta2ns(0x7FFF, &pit_clockevent); + pit_clockevent.min_delta_ns = + clockevent_delta2ns(0xF, &pit_clockevent); + clockevents_register_device(&pit_clockevent); + global_clock_event = &pit_clockevent; } /* @@ -46,7 +126,7 @@ static cycle_t pit_read(void) static u32 old_jifs; spin_lock_irqsave(&i8253_lock, flags); - /* + /* * Although our caller may have the read side of xtime_lock, * this is now a seqlock, and we are cheating in this routine * by having side effects on state that we cannot undo if diff --git a/arch/i386/kernel/i8259.c b/arch/i386/kernel/i8259.c index c8d4582..03abfdb 100644 --- a/arch/i386/kernel/i8259.c +++ b/arch/i386/kernel/i8259.c @@ -41,6 +41,7 @@ static void mask_and_ack_8259A(unsigned static struct irq_chip i8259A_chip = { .name = "XT-PIC", .mask = disable_8259A_irq, + .disable = disable_8259A_irq, .unmask = enable_8259A_irq, .mask_ack = mask_and_ack_8259A, }; @@ -410,12 +411,6 @@ void __init native_init_IRQ(void) intr_init_hook(); /* - * Set the clock to HZ Hz, we already have a valid - * vector now: - */ - setup_pit_timer(); - - /* * External FPU? Set up irq13 if so, for * original braindamaged IBM FERR coupling. */ diff --git a/arch/i386/kernel/io_apic.c b/arch/i386/kernel/io_apic.c index 6a3875f..4ccebd4 100644 --- a/arch/i386/kernel/io_apic.c +++ b/arch/i386/kernel/io_apic.c @@ -126,7 +126,7 @@ static inline void io_apic_write(unsigne */ static inline void io_apic_modify(unsigned int apic, unsigned int reg, unsigned int value) { - volatile struct io_apic *io_apic = io_apic_base(apic); + volatile struct io_apic __iomem *io_apic = io_apic_base(apic); if (sis_apic_bug) writel(reg, &io_apic->index); writel(value, &io_apic->data); @@ -482,8 +482,8 @@ static void do_irq_balance(void) package_index = CPU_TO_PACKAGEINDEX(i); for (j = 0; j < NR_IRQS; j++) { unsigned long value_now, delta; - /* Is this an active IRQ? */ - if (!irq_desc[j].action) + /* Is this an active IRQ or balancing disabled ? */ + if (!irq_desc[j].action || irq_balancing_disabled(j)) continue; if ( package_index == i ) IRQ_DELTA(package_index,j) = 0; @@ -1281,11 +1281,9 @@ static void ioapic_register_intr(int irq trigger == IOAPIC_LEVEL) set_irq_chip_and_handler_name(irq, &ioapic_chip, handle_fasteoi_irq, "fasteoi"); - else { - irq_desc[irq].status |= IRQ_DELAYED_DISABLE; + else set_irq_chip_and_handler_name(irq, &ioapic_chip, handle_edge_irq, "edge"); - } set_intr_gate(vector, interrupt[irq]); } @@ -1588,7 +1586,7 @@ void /*__init*/ print_local_APIC(void * v = apic_read(APIC_LVR); printk(KERN_INFO "... APIC VERSION: %08x\n", v); ver = GET_APIC_VERSION(v); - maxlvt = get_maxlvt(); + maxlvt = lapic_get_maxlvt(); v = apic_read(APIC_TASKPRI); printk(KERN_DEBUG "... APIC TASKPRI: %08x (%02x)\n", v, v & APIC_TPRI_MASK); @@ -1920,7 +1918,7 @@ #else static void __init setup_ioapic_ids_from_mpc(void) { } #endif -static int no_timer_check __initdata; +int no_timer_check __initdata; static int __init notimercheck(char *s) { @@ -2310,7 +2308,7 @@ static inline void __init check_timer(vo disable_8259A_irq(0); set_irq_chip_and_handler_name(0, &lapic_chip, handle_fasteoi_irq, - "fasteio"); + "fasteoi"); apic_write_around(APIC_LVT0, APIC_DM_FIXED | vector); /* Fixed mode */ enable_8259A_irq(0); @@ -2606,25 +2604,32 @@ #endif .retrigger = ioapic_retrigger_irq, }; -int arch_setup_msi_irq(unsigned int irq, struct pci_dev *dev) +int arch_setup_msi_irq(struct pci_dev *dev, struct msi_desc *desc) { struct msi_msg msg; - int ret; + int irq, ret; + irq = create_irq(); + if (irq < 0) + return irq; + + set_irq_msi(irq, desc); ret = msi_compose_msg(dev, irq, &msg); - if (ret < 0) + if (ret < 0) { + destroy_irq(irq); return ret; + } write_msi_msg(irq, &msg); set_irq_chip_and_handler_name(irq, &msi_chip, handle_edge_irq, "edge"); - return 0; + return irq; } void arch_teardown_msi_irq(unsigned int irq) { - return; + destroy_irq(irq); } #endif /* CONFIG_PCI_MSI */ diff --git a/arch/i386/kernel/irq.c b/arch/i386/kernel/irq.c index 3201d42..0f2ca59 100644 --- a/arch/i386/kernel/irq.c +++ b/arch/i386/kernel/irq.c @@ -10,7 +10,6 @@ * io_apic.c.) */ -#include #include #include #include @@ -19,19 +18,36 @@ #include #include #include +#include + +#include +#include + DEFINE_PER_CPU(irq_cpustat_t, irq_stat) ____cacheline_internodealigned_in_smp; EXPORT_PER_CPU_SYMBOL(irq_stat); -#ifndef CONFIG_X86_LOCAL_APIC /* * 'what should we do if we get a hw irq event on an illegal vector'. * each architecture has to answer this themselves. */ void ack_bad_irq(unsigned int irq) { - printk("unexpected IRQ trap at vector %02x\n", irq); -} + printk(KERN_ERR "unexpected IRQ trap at vector %02x\n", irq); + +#ifdef CONFIG_X86_LOCAL_APIC + /* + * Currently unexpected vectors happen only on SMP and APIC. + * We _must_ ack these because every local APIC has only N + * irq slots per priority level, and a 'hanging, unacked' IRQ + * holds up an irq slot - in excessive cases (when multiple + * unexpected vectors occur) that might lock up the APIC + * completely. + * But only ack when the APIC is enabled -AK + */ + if (cpu_has_apic) + ack_APIC_irq(); #endif +} #ifdef CONFIG_4KSTACKS /* @@ -61,6 +77,7 @@ #ifdef CONFIG_4KSTACKS union irq_ctx *curctx, *irqctx; u32 *isp; #endif + exit_idle(); if (unlikely((unsigned)irq >= NR_IRQS)) { printk(KERN_EMERG "%s: cannot handle IRQ %d\n", diff --git a/arch/i386/kernel/kprobes.c b/arch/i386/kernel/kprobes.c index af1d533..b545bc7 100644 --- a/arch/i386/kernel/kprobes.c +++ b/arch/i386/kernel/kprobes.c @@ -363,7 +363,7 @@ no_kprobe: " pushf\n" /* skip cs, eip, orig_eax */ " subl $12, %esp\n" - " pushl %gs\n" + " pushl %fs\n" " pushl %ds\n" " pushl %es\n" " pushl %eax\n" @@ -387,7 +387,7 @@ no_kprobe: " popl %edi\n" " popl %ebp\n" " popl %eax\n" - /* skip eip, orig_eax, es, ds, gs */ + /* skip eip, orig_eax, es, ds, fs */ " addl $20, %esp\n" " popf\n" " ret\n"); @@ -408,7 +408,7 @@ fastcall void *__kprobes trampoline_hand spin_lock_irqsave(&kretprobe_lock, flags); head = kretprobe_inst_table_head(current); /* fixup registers */ - regs->xcs = __KERNEL_CS; + regs->xcs = __KERNEL_CS | get_kernel_rpl(); regs->eip = trampoline_address; regs->orig_eax = 0xffffffff; diff --git a/arch/i386/kernel/microcode.c b/arch/i386/kernel/microcode.c index c8fa137..b8f1663 100644 --- a/arch/i386/kernel/microcode.c +++ b/arch/i386/kernel/microcode.c @@ -384,7 +384,7 @@ static int do_microcode_update (void) { long cursor = 0; int error = 0; - void *new_mc; + void *new_mc = NULL; int cpu; cpumask_t old; @@ -451,7 +451,7 @@ static ssize_t microcode_write (struct f return ret; } -static struct file_operations microcode_fops = { +static const struct file_operations microcode_fops = { .owner = THIS_MODULE, .write = microcode_write, .open = microcode_open, diff --git a/arch/i386/kernel/mpparse.c b/arch/i386/kernel/mpparse.c index 49bff35..4f5983c 100644 --- a/arch/i386/kernel/mpparse.c +++ b/arch/i386/kernel/mpparse.c @@ -1057,7 +1057,7 @@ int mp_register_gsi(u32 gsi, int trigger static int gsi_to_irq[MAX_GSI_NUM]; /* Don't set up the ACPI SCI because it's already set up */ - if (acpi_fadt.sci_int == gsi) + if (acpi_gbl_FADT.sci_interrupt == gsi) return gsi; ioapic = mp_find_ioapic(gsi); @@ -1114,7 +1114,7 @@ int mp_register_gsi(u32 gsi, int trigger /* * Don't assign IRQ used by ACPI SCI */ - if (gsi == acpi_fadt.sci_int) + if (gsi == acpi_gbl_FADT.sci_interrupt) gsi = pci_irq++; gsi_to_irq[irq] = gsi; } else { diff --git a/arch/i386/kernel/msr.c b/arch/i386/kernel/msr.c index 4a472a1..bcaa6e9 100644 --- a/arch/i386/kernel/msr.c +++ b/arch/i386/kernel/msr.c @@ -68,7 +68,6 @@ static inline int rdmsr_eio(u32 reg, u32 #ifdef CONFIG_SMP struct msr_command { - int cpu; int err; u32 reg; u32 data[2]; @@ -78,16 +77,14 @@ static void msr_smp_wrmsr(void *cmd_bloc { struct msr_command *cmd = (struct msr_command *)cmd_block; - if (cmd->cpu == smp_processor_id()) - cmd->err = wrmsr_eio(cmd->reg, cmd->data[0], cmd->data[1]); + cmd->err = wrmsr_eio(cmd->reg, cmd->data[0], cmd->data[1]); } static void msr_smp_rdmsr(void *cmd_block) { struct msr_command *cmd = (struct msr_command *)cmd_block; - if (cmd->cpu == smp_processor_id()) - cmd->err = rdmsr_eio(cmd->reg, &cmd->data[0], &cmd->data[1]); + cmd->err = rdmsr_eio(cmd->reg, &cmd->data[0], &cmd->data[1]); } static inline int do_wrmsr(int cpu, u32 reg, u32 eax, u32 edx) @@ -99,12 +96,11 @@ static inline int do_wrmsr(int cpu, u32 if (cpu == smp_processor_id()) { ret = wrmsr_eio(reg, eax, edx); } else { - cmd.cpu = cpu; cmd.reg = reg; cmd.data[0] = eax; cmd.data[1] = edx; - smp_call_function(msr_smp_wrmsr, &cmd, 1, 1); + smp_call_function_single(cpu, msr_smp_wrmsr, &cmd, 1, 1); ret = cmd.err; } preempt_enable(); @@ -120,10 +116,9 @@ static inline int do_rdmsr(int cpu, u32 if (cpu == smp_processor_id()) { ret = rdmsr_eio(reg, eax, edx); } else { - cmd.cpu = cpu; cmd.reg = reg; - smp_call_function(msr_smp_rdmsr, &cmd, 1, 1); + smp_call_function_single(cpu, msr_smp_rdmsr, &cmd, 1, 1); *eax = cmd.data[0]; *edx = cmd.data[1]; @@ -230,7 +225,7 @@ static int msr_open(struct inode *inode, /* * File operations we support */ -static struct file_operations msr_fops = { +static const struct file_operations msr_fops = { .owner = THIS_MODULE, .llseek = msr_seek, .read = msr_read, diff --git a/arch/i386/kernel/nmi.c b/arch/i386/kernel/nmi.c index 1a6f8bb..821df34 100644 --- a/arch/i386/kernel/nmi.c +++ b/arch/i386/kernel/nmi.c @@ -23,6 +23,7 @@ #include #include #include #include +#include #include #include @@ -185,7 +186,8 @@ static __cpuinit inline int nmi_known_cp { switch (boot_cpu_data.x86_vendor) { case X86_VENDOR_AMD: - return ((boot_cpu_data.x86 == 15) || (boot_cpu_data.x86 == 6)); + return ((boot_cpu_data.x86 == 15) || (boot_cpu_data.x86 == 6) + || (boot_cpu_data.x86 == 16)); case X86_VENDOR_INTEL: if (cpu_has(&boot_cpu_data, X86_FEATURE_ARCH_PERFMON)) return 1; @@ -216,6 +218,28 @@ static __init void nmi_cpu_busy(void *da } #endif +static unsigned int adjust_for_32bit_ctr(unsigned int hz) +{ + u64 counter_val; + unsigned int retval = hz; + + /* + * On Intel CPUs with P6/ARCH_PERFMON only 32 bits in the counter + * are writable, with higher bits sign extending from bit 31. + * So, we can only program the counter with 31 bit values and + * 32nd bit should be 1, for 33.. to be 1. + * Find the appropriate nmi_hz + */ + counter_val = (u64)cpu_khz * 1000; + do_div(counter_val, retval); + if (counter_val > 0x7fffffffULL) { + u64 count = (u64)cpu_khz * 1000; + do_div(count, 0x7fffffffUL); + retval = count + 1; + } + return retval; +} + static int __init check_nmi_watchdog(void) { unsigned int *prev_nmi_count; @@ -281,18 +305,10 @@ #endif struct nmi_watchdog_ctlblk *wd = &__get_cpu_var(nmi_watchdog_ctlblk); nmi_hz = 1; - /* - * On Intel CPUs with ARCH_PERFMON only 32 bits in the counter - * are writable, with higher bits sign extending from bit 31. - * So, we can only program the counter with 31 bit values and - * 32nd bit should be 1, for 33.. to be 1. - * Find the appropriate nmi_hz - */ - if (wd->perfctr_msr == MSR_ARCH_PERFMON_PERFCTR0 && - ((u64)cpu_khz * 1000) > 0x7fffffffULL) { - u64 count = (u64)cpu_khz * 1000; - do_div(count, 0x7fffffffUL); - nmi_hz = count + 1; + + if (wd->perfctr_msr == MSR_P6_PERFCTR0 || + wd->perfctr_msr == MSR_ARCH_PERFMON_PERFCTR0) { + nmi_hz = adjust_for_32bit_ctr(nmi_hz); } } @@ -369,6 +385,34 @@ void enable_timer_nmi_watchdog(void) } } +static void __acpi_nmi_disable(void *__unused) +{ + apic_write_around(APIC_LVT0, APIC_DM_NMI | APIC_LVT_MASKED); +} + +/* + * Disable timer based NMIs on all CPUs: + */ +void acpi_nmi_disable(void) +{ + if (atomic_read(&nmi_active) && nmi_watchdog == NMI_IO_APIC) + on_each_cpu(__acpi_nmi_disable, NULL, 0, 1); +} + +static void __acpi_nmi_enable(void *__unused) +{ + apic_write_around(APIC_LVT0, APIC_DM_NMI); +} + +/* + * Enable timer based NMIs on all CPUs: + */ +void acpi_nmi_enable(void) +{ + if (atomic_read(&nmi_active) && nmi_watchdog == NMI_IO_APIC) + on_each_cpu(__acpi_nmi_enable, NULL, 0, 1); +} + #ifdef CONFIG_PM static int nmi_pm_active; /* nmi_active before suspend */ @@ -442,6 +486,17 @@ static void write_watchdog_counter(unsig wrmsrl(perfctr_msr, 0 - count); } +static void write_watchdog_counter32(unsigned int perfctr_msr, + const char *descr) +{ + u64 count = (u64)cpu_khz * 1000; + + do_div(count, nmi_hz); + if(descr) + Dprintk("setting %s to -0x%08Lx\n", descr, count); + wrmsr(perfctr_msr, (u32)(-count), 0); +} + /* Note that these events don't tick when the CPU idles. This means the frequency varies with CPU load. */ @@ -531,7 +586,8 @@ static int setup_p6_watchdog(void) /* setup the timer */ wrmsr(evntsel_msr, evntsel, 0); - write_watchdog_counter(perfctr_msr, "P6_PERFCTR0"); + nmi_hz = adjust_for_32bit_ctr(nmi_hz); + write_watchdog_counter32(perfctr_msr, "P6_PERFCTR0"); apic_write(APIC_LVTPC, APIC_DM_NMI); evntsel |= P6_EVNTSEL0_ENABLE; wrmsr(evntsel_msr, evntsel, 0); @@ -704,7 +760,8 @@ static int setup_intel_arch_watchdog(voi /* setup the timer */ wrmsr(evntsel_msr, evntsel, 0); - write_watchdog_counter(perfctr_msr, "INTEL_ARCH_PERFCTR0"); + nmi_hz = adjust_for_32bit_ctr(nmi_hz); + write_watchdog_counter32(perfctr_msr, "INTEL_ARCH_PERFCTR0"); apic_write(APIC_LVTPC, APIC_DM_NMI); evntsel |= ARCH_PERFMON_EVENTSEL0_ENABLE; wrmsr(evntsel_msr, evntsel, 0); @@ -762,7 +819,8 @@ void setup_apic_nmi_watchdog (void *unus if (nmi_watchdog == NMI_LOCAL_APIC) { switch (boot_cpu_data.x86_vendor) { case X86_VENDOR_AMD: - if (boot_cpu_data.x86 != 6 && boot_cpu_data.x86 != 15) + if (boot_cpu_data.x86 != 6 && boot_cpu_data.x86 != 15 && + boot_cpu_data.x86 != 16) return; if (!setup_k7_watchdog()) return; @@ -916,9 +974,13 @@ __kprobes int nmi_watchdog_tick(struct p cpu_clear(cpu, backtrace_mask); } - sum = per_cpu(irq_stat, cpu).apic_timer_irqs; + /* + * Take the local apic timer and PIT/HPET into account. We don't + * know which one is active, when we have highres/dyntick on + */ + sum = per_cpu(irq_stat, cpu).apic_timer_irqs + kstat_irqs(0); - /* if the apic timer isn't firing, this cpu isn't doing much */ + /* if the none of the timers isn't firing, this cpu isn't doing much */ if (!touched && last_irq_sums[cpu] == sum) { /* * Ayiee, looks like this CPU is stuck ... @@ -956,6 +1018,8 @@ __kprobes int nmi_watchdog_tick(struct p dummy &= ~P4_CCCR_OVF; wrmsrl(wd->cccr_msr, dummy); apic_write(APIC_LVTPC, APIC_DM_NMI); + /* start the cycle over again */ + write_watchdog_counter(wd->perfctr_msr, NULL); } else if (wd->perfctr_msr == MSR_P6_PERFCTR0 || wd->perfctr_msr == MSR_ARCH_PERFMON_PERFCTR0) { @@ -964,9 +1028,12 @@ __kprobes int nmi_watchdog_tick(struct p * other P6 variant. * ArchPerfom/Core Duo also needs this */ apic_write(APIC_LVTPC, APIC_DM_NMI); + /* P6/ARCH_PERFMON has 32 bit counter write */ + write_watchdog_counter32(wd->perfctr_msr, NULL); + } else { + /* start the cycle over again */ + write_watchdog_counter(wd->perfctr_msr, NULL); } - /* start the cycle over again */ - write_watchdog_counter(wd->perfctr_msr, NULL); rc = 1; } else if (nmi_watchdog == NMI_IO_APIC) { /* don't know how to accurately check for this. diff --git a/arch/i386/kernel/paravirt.c b/arch/i386/kernel/paravirt.c index e55fd05..c156ecf 100644 --- a/arch/i386/kernel/paravirt.c +++ b/arch/i386/kernel/paravirt.c @@ -92,7 +92,7 @@ static unsigned native_patch(u8 type, u1 return insn_len; } -static fastcall unsigned long native_get_debugreg(int regno) +static unsigned long native_get_debugreg(int regno) { unsigned long val = 0; /* Damn you, gcc! */ @@ -115,7 +115,7 @@ static fastcall unsigned long native_get return val; } -static fastcall void native_set_debugreg(int regno, unsigned long value) +static void native_set_debugreg(int regno, unsigned long value) { switch (regno) { case 0: @@ -146,55 +146,55 @@ void init_IRQ(void) paravirt_ops.init_IRQ(); } -static fastcall void native_clts(void) +static void native_clts(void) { asm volatile ("clts"); } -static fastcall unsigned long native_read_cr0(void) +static unsigned long native_read_cr0(void) { unsigned long val; asm volatile("movl %%cr0,%0\n\t" :"=r" (val)); return val; } -static fastcall void native_write_cr0(unsigned long val) +static void native_write_cr0(unsigned long val) { asm volatile("movl %0,%%cr0": :"r" (val)); } -static fastcall unsigned long native_read_cr2(void) +static unsigned long native_read_cr2(void) { unsigned long val; asm volatile("movl %%cr2,%0\n\t" :"=r" (val)); return val; } -static fastcall void native_write_cr2(unsigned long val) +static void native_write_cr2(unsigned long val) { asm volatile("movl %0,%%cr2": :"r" (val)); } -static fastcall unsigned long native_read_cr3(void) +static unsigned long native_read_cr3(void) { unsigned long val; asm volatile("movl %%cr3,%0\n\t" :"=r" (val)); return val; } -static fastcall void native_write_cr3(unsigned long val) +static void native_write_cr3(unsigned long val) { asm volatile("movl %0,%%cr3": :"r" (val)); } -static fastcall unsigned long native_read_cr4(void) +static unsigned long native_read_cr4(void) { unsigned long val; asm volatile("movl %%cr4,%0\n\t" :"=r" (val)); return val; } -static fastcall unsigned long native_read_cr4_safe(void) +static unsigned long native_read_cr4_safe(void) { unsigned long val; /* This could fault if %cr4 does not exist */ @@ -207,51 +207,51 @@ static fastcall unsigned long native_rea return val; } -static fastcall void native_write_cr4(unsigned long val) +static void native_write_cr4(unsigned long val) { asm volatile("movl %0,%%cr4": :"r" (val)); } -static fastcall unsigned long native_save_fl(void) +static unsigned long native_save_fl(void) { unsigned long f; asm volatile("pushfl ; popl %0":"=g" (f): /* no input */); return f; } -static fastcall void native_restore_fl(unsigned long f) +static void native_restore_fl(unsigned long f) { asm volatile("pushl %0 ; popfl": /* no output */ :"g" (f) :"memory", "cc"); } -static fastcall void native_irq_disable(void) +static void native_irq_disable(void) { asm volatile("cli": : :"memory"); } -static fastcall void native_irq_enable(void) +static void native_irq_enable(void) { asm volatile("sti": : :"memory"); } -static fastcall void native_safe_halt(void) +static void native_safe_halt(void) { asm volatile("sti; hlt": : :"memory"); } -static fastcall void native_halt(void) +static void native_halt(void) { asm volatile("hlt": : :"memory"); } -static fastcall void native_wbinvd(void) +static void native_wbinvd(void) { asm volatile("wbinvd": : :"memory"); } -static fastcall unsigned long long native_read_msr(unsigned int msr, int *err) +static unsigned long long native_read_msr(unsigned int msr, int *err) { unsigned long long val; @@ -270,7 +270,7 @@ static fastcall unsigned long long nativ return val; } -static fastcall int native_write_msr(unsigned int msr, unsigned long long val) +static int native_write_msr(unsigned int msr, unsigned long long val) { int err; asm volatile("2: wrmsr ; xorl %0,%0\n" @@ -288,53 +288,53 @@ static fastcall int native_write_msr(uns return err; } -static fastcall unsigned long long native_read_tsc(void) +static unsigned long long native_read_tsc(void) { unsigned long long val; asm volatile("rdtsc" : "=A" (val)); return val; } -static fastcall unsigned long long native_read_pmc(void) +static unsigned long long native_read_pmc(void) { unsigned long long val; asm volatile("rdpmc" : "=A" (val)); return val; } -static fastcall void native_load_tr_desc(void) +static void native_load_tr_desc(void) { asm volatile("ltr %w0"::"q" (GDT_ENTRY_TSS*8)); } -static fastcall void native_load_gdt(const struct Xgt_desc_struct *dtr) +static void native_load_gdt(const struct Xgt_desc_struct *dtr) { asm volatile("lgdt %0"::"m" (*dtr)); } -static fastcall void native_load_idt(const struct Xgt_desc_struct *dtr) +static void native_load_idt(const struct Xgt_desc_struct *dtr) { asm volatile("lidt %0"::"m" (*dtr)); } -static fastcall void native_store_gdt(struct Xgt_desc_struct *dtr) +static void native_store_gdt(struct Xgt_desc_struct *dtr) { asm ("sgdt %0":"=m" (*dtr)); } -static fastcall void native_store_idt(struct Xgt_desc_struct *dtr) +static void native_store_idt(struct Xgt_desc_struct *dtr) { asm ("sidt %0":"=m" (*dtr)); } -static fastcall unsigned long native_store_tr(void) +static unsigned long native_store_tr(void) { unsigned long tr; asm ("str %0":"=r" (tr)); return tr; } -static fastcall void native_load_tls(struct thread_struct *t, unsigned int cpu) +static void native_load_tls(struct thread_struct *t, unsigned int cpu) { #define C(i) get_cpu_gdt_table(cpu)[GDT_ENTRY_TLS_MIN + i] = t->tls_array[i] C(0); C(1); C(2); @@ -348,22 +348,22 @@ static inline void native_write_dt_entry lp[1] = entry_high; } -static fastcall void native_write_ldt_entry(void *dt, int entrynum, u32 low, u32 high) +static void native_write_ldt_entry(void *dt, int entrynum, u32 low, u32 high) { native_write_dt_entry(dt, entrynum, low, high); } -static fastcall void native_write_gdt_entry(void *dt, int entrynum, u32 low, u32 high) +static void native_write_gdt_entry(void *dt, int entrynum, u32 low, u32 high) { native_write_dt_entry(dt, entrynum, low, high); } -static fastcall void native_write_idt_entry(void *dt, int entrynum, u32 low, u32 high) +static void native_write_idt_entry(void *dt, int entrynum, u32 low, u32 high) { native_write_dt_entry(dt, entrynum, low, high); } -static fastcall void native_load_esp0(struct tss_struct *tss, +static void native_load_esp0(struct tss_struct *tss, struct thread_struct *thread) { tss->esp0 = thread->esp0; @@ -375,12 +375,12 @@ static fastcall void native_load_esp0(st } } -static fastcall void native_io_delay(void) +static void native_io_delay(void) { asm volatile("outb %al,$0x80"); } -static fastcall void native_flush_tlb(void) +static void native_flush_tlb(void) { __native_flush_tlb(); } @@ -389,49 +389,49 @@ static fastcall void native_flush_tlb(vo * Global pages have to be flushed a bit differently. Not a real * performance problem because this does not happen often. */ -static fastcall void native_flush_tlb_global(void) +static void native_flush_tlb_global(void) { __native_flush_tlb_global(); } -static fastcall void native_flush_tlb_single(u32 addr) +static void native_flush_tlb_single(u32 addr) { __native_flush_tlb_single(addr); } #ifndef CONFIG_X86_PAE -static fastcall void native_set_pte(pte_t *ptep, pte_t pteval) +static void native_set_pte(pte_t *ptep, pte_t pteval) { *ptep = pteval; } -static fastcall void native_set_pte_at(struct mm_struct *mm, u32 addr, pte_t *ptep, pte_t pteval) +static void native_set_pte_at(struct mm_struct *mm, u32 addr, pte_t *ptep, pte_t pteval) { *ptep = pteval; } -static fastcall void native_set_pmd(pmd_t *pmdp, pmd_t pmdval) +static void native_set_pmd(pmd_t *pmdp, pmd_t pmdval) { *pmdp = pmdval; } #else /* CONFIG_X86_PAE */ -static fastcall void native_set_pte(pte_t *ptep, pte_t pte) +static void native_set_pte(pte_t *ptep, pte_t pte) { ptep->pte_high = pte.pte_high; smp_wmb(); ptep->pte_low = pte.pte_low; } -static fastcall void native_set_pte_at(struct mm_struct *mm, u32 addr, pte_t *ptep, pte_t pte) +static void native_set_pte_at(struct mm_struct *mm, u32 addr, pte_t *ptep, pte_t pte) { ptep->pte_high = pte.pte_high; smp_wmb(); ptep->pte_low = pte.pte_low; } -static fastcall void native_set_pte_present(struct mm_struct *mm, unsigned long addr, pte_t *ptep, pte_t pte) +static void native_set_pte_present(struct mm_struct *mm, unsigned long addr, pte_t *ptep, pte_t pte) { ptep->pte_low = 0; smp_wmb(); @@ -440,29 +440,29 @@ static fastcall void native_set_pte_pres ptep->pte_low = pte.pte_low; } -static fastcall void native_set_pte_atomic(pte_t *ptep, pte_t pteval) +static void native_set_pte_atomic(pte_t *ptep, pte_t pteval) { set_64bit((unsigned long long *)ptep,pte_val(pteval)); } -static fastcall void native_set_pmd(pmd_t *pmdp, pmd_t pmdval) +static void native_set_pmd(pmd_t *pmdp, pmd_t pmdval) { set_64bit((unsigned long long *)pmdp,pmd_val(pmdval)); } -static fastcall void native_set_pud(pud_t *pudp, pud_t pudval) +static void native_set_pud(pud_t *pudp, pud_t pudval) { *pudp = pudval; } -static fastcall void native_pte_clear(struct mm_struct *mm, unsigned long addr, pte_t *ptep) +static void native_pte_clear(struct mm_struct *mm, unsigned long addr, pte_t *ptep) { ptep->pte_low = 0; smp_wmb(); ptep->pte_high = 0; } -static fastcall void native_pmd_clear(pmd_t *pmd) +static void native_pmd_clear(pmd_t *pmd) { u32 *tmp = (u32 *)pmd; *tmp = 0; @@ -472,8 +472,8 @@ static fastcall void native_pmd_clear(pm #endif /* CONFIG_X86_PAE */ /* These are in entry.S */ -extern fastcall void native_iret(void); -extern fastcall void native_irq_enable_sysexit(void); +extern void native_iret(void); +extern void native_irq_enable_sysexit(void); static int __init print_banner(void) { @@ -482,9 +482,6 @@ static int __init print_banner(void) } core_initcall(print_banner); -/* We simply declare start_kernel to be the paravirt probe of last resort. */ -paravirt_probe(start_kernel); - struct paravirt_ops paravirt_ops = { .name = "bare hardware", .paravirt_enabled = 0, @@ -544,12 +541,21 @@ #ifdef CONFIG_X86_LOCAL_APIC .apic_write = native_apic_write, .apic_write_atomic = native_apic_write_atomic, .apic_read = native_apic_read, + .setup_boot_clock = setup_boot_APIC_clock, + .setup_secondary_clock = setup_secondary_APIC_clock, #endif + .set_lazy_mode = (void *)native_nop, .flush_tlb_user = native_flush_tlb, .flush_tlb_kernel = native_flush_tlb_global, .flush_tlb_single = native_flush_tlb_single, + .alloc_pt = (void *)native_nop, + .alloc_pd = (void *)native_nop, + .alloc_pd_clone = (void *)native_nop, + .release_pt = (void *)native_nop, + .release_pd = (void *)native_nop, + .set_pte = native_set_pte, .set_pte_at = native_set_pte_at, .set_pmd = native_set_pmd, @@ -565,6 +571,8 @@ #endif .irq_enable_sysexit = native_irq_enable_sysexit, .iret = native_iret, + + .startup_ipi_hook = (void *)native_nop, }; /* diff --git a/arch/i386/kernel/pcspeaker.c b/arch/i386/kernel/pcspeaker.c new file mode 100644 index 0000000..bc1f2d3 --- /dev/null +++ b/arch/i386/kernel/pcspeaker.c @@ -0,0 +1,20 @@ +#include +#include +#include + +static __init int add_pcspkr(void) +{ + struct platform_device *pd; + int ret; + + pd = platform_device_alloc("pcspkr", -1); + if (!pd) + return -ENOMEM; + + ret = platform_device_add(pd); + if (ret) + platform_device_put(pd); + + return ret; +} +device_initcall(add_pcspkr); diff --git a/arch/i386/kernel/process.c b/arch/i386/kernel/process.c index c641056..bea304d 100644 --- a/arch/i386/kernel/process.c +++ b/arch/i386/kernel/process.c @@ -38,6 +38,7 @@ #include #include #include #include +#include #include #include @@ -48,6 +49,7 @@ #include #include #include #include +#include #ifdef CONFIG_MATH_EMULATION #include #endif @@ -80,6 +82,42 @@ void (*pm_idle)(void); EXPORT_SYMBOL(pm_idle); static DEFINE_PER_CPU(unsigned int, cpu_idle_state); +static ATOMIC_NOTIFIER_HEAD(idle_notifier); + +void idle_notifier_register(struct notifier_block *n) +{ + atomic_notifier_chain_register(&idle_notifier, n); +} + +void idle_notifier_unregister(struct notifier_block *n) +{ + atomic_notifier_chain_unregister(&idle_notifier, n); +} + +static DEFINE_PER_CPU(volatile unsigned long, idle_state); + +void enter_idle(void) +{ + /* needs to be atomic w.r.t. interrupts, not against other CPUs */ + __set_bit(0, &__get_cpu_var(idle_state)); + atomic_notifier_call_chain(&idle_notifier, IDLE_START, NULL); +} + +static void __exit_idle(void) +{ + /* needs to be atomic w.r.t. interrupts, not against other CPUs */ + if (__test_and_clear_bit(0, &__get_cpu_var(idle_state)) == 0) + return; + atomic_notifier_call_chain(&idle_notifier, IDLE_END, NULL); +} + +void exit_idle(void) +{ + if (current->pid) + return; + __exit_idle(); +} + void disable_hlt(void) { hlt_counter++; @@ -130,6 +168,7 @@ #endif */ static void poll_idle (void) { + local_irq_enable(); cpu_relax(); } @@ -173,6 +212,7 @@ void cpu_idle(void) /* endless idle loop with no priority at all */ while (1) { + tick_nohz_stop_sched_tick(); while (!need_resched()) { void (*idle)(void); @@ -189,8 +229,18 @@ void cpu_idle(void) play_dead(); __get_cpu_var(irq_stat).idle_timestamp = jiffies; + + /* + * Idle routines should keep interrupts disabled + * from here on, until they go to idle. + * Otherwise, idle callbacks can misfire. + */ + local_irq_disable(); + enter_idle(); idle(); + __exit_idle(); } + tick_nohz_restart_sched_tick(); preempt_enable_no_resched(); schedule(); preempt_disable(); @@ -243,7 +293,11 @@ void mwait_idle_with_hints(unsigned long __monitor((void *)¤t_thread_info()->flags, 0, 0); smp_mb(); if (!need_resched()) - __mwait(eax, ecx); + __sti_mwait(eax, ecx); + else + local_irq_enable(); + } else { + local_irq_enable(); } } @@ -308,8 +362,8 @@ void show_regs(struct pt_regs * regs) regs->eax,regs->ebx,regs->ecx,regs->edx); printk("ESI: %08lx EDI: %08lx EBP: %08lx", regs->esi, regs->edi, regs->ebp); - printk(" DS: %04x ES: %04x GS: %04x\n", - 0xffff & regs->xds,0xffff & regs->xes, 0xffff & regs->xgs); + printk(" DS: %04x ES: %04x FS: %04x\n", + 0xffff & regs->xds,0xffff & regs->xes, 0xffff & regs->xfs); cr0 = read_cr0(); cr2 = read_cr2(); @@ -340,7 +394,7 @@ int kernel_thread(int (*fn)(void *), voi regs.xds = __USER_DS; regs.xes = __USER_DS; - regs.xgs = __KERNEL_PDA; + regs.xfs = __KERNEL_PDA; regs.orig_eax = -1; regs.eip = (unsigned long) kernel_thread_helper; regs.xcs = __KERNEL_CS | get_kernel_rpl(); @@ -425,7 +479,7 @@ int copy_thread(int nr, unsigned long cl p->thread.eip = (unsigned long) ret_from_fork; - savesegment(fs,p->thread.fs); + savesegment(gs,p->thread.gs); tsk = current; if (unlikely(test_tsk_thread_flag(tsk, TIF_IO_BITMAP))) { @@ -501,8 +555,8 @@ void dump_thread(struct pt_regs * regs, dump->regs.eax = regs->eax; dump->regs.ds = regs->xds; dump->regs.es = regs->xes; - savesegment(fs,dump->regs.fs); - dump->regs.gs = regs->xgs; + dump->regs.fs = regs->xfs; + savesegment(gs,dump->regs.gs); dump->regs.orig_eax = regs->orig_eax; dump->regs.eip = regs->eip; dump->regs.cs = regs->xcs; @@ -653,7 +707,7 @@ struct task_struct fastcall * __switch_t load_esp0(tss, next); /* - * Save away %fs. No need to save %gs, as it was saved on the + * Save away %gs. No need to save %fs, as it was saved on the * stack on entry. No need to save %es and %ds, as those are * always kernel segments while inside the kernel. Doing this * before setting the new TLS descriptors avoids the situation @@ -662,7 +716,7 @@ struct task_struct fastcall * __switch_t * used %fs or %gs (it does not today), or if the kernel is * running inside of a hypervisor layer. */ - savesegment(fs, prev->fs); + savesegment(gs, prev->gs); /* * Load the per-thread Thread-Local Storage descriptor. @@ -670,14 +724,13 @@ struct task_struct fastcall * __switch_t load_TLS(next, cpu); /* - * Restore %fs if needed. - * - * Glibc normally makes %fs be zero. + * Restore IOPL if needed. In normal use, the flags restore + * in the switch assembly will handle this. But if the kernel + * is running virtualized at a non-zero CPL, the popf will + * not restore flags, so it must be done in a separate step. */ - if (unlikely(prev->fs | next->fs)) - loadsegment(fs, next->fs); - - write_pda(pcurrent, next_p); + if (get_kernel_rpl() && unlikely(prev->iopl != next->iopl)) + set_iopl_mask(next->iopl); /* * Now maybe handle debug registers and/or IO bitmaps @@ -688,6 +741,15 @@ struct task_struct fastcall * __switch_t disable_tsc(prev_p, next_p); + /* + * Leave lazy mode, flushing any hypercalls made here. + * This must be done before restoring TLS segments so + * the GDT and LDT are properly updated, and must be + * done before math_state_restore, so the TS bit is up + * to date. + */ + arch_leave_lazy_cpu_mode(); + /* If the task has used fpu the last 5 timeslices, just do a full * restore of the math state immediately to avoid the trap; the * chances of needing FPU soon are obviously high now @@ -695,6 +757,14 @@ struct task_struct fastcall * __switch_t if (next_p->fpu_counter > 5) math_state_restore(); + /* + * Restore %gs if needed (which is common) + */ + if (prev->gs | next->gs) + loadsegment(gs, next->gs); + + write_pda(pcurrent, next_p); + return prev_p; } diff --git a/arch/i386/kernel/ptrace.c b/arch/i386/kernel/ptrace.c index af8aabe..4a8f8a2 100644 --- a/arch/i386/kernel/ptrace.c +++ b/arch/i386/kernel/ptrace.c @@ -89,14 +89,14 @@ static int putreg(struct task_struct *ch unsigned long regno, unsigned long value) { switch (regno >> 2) { - case FS: + case GS: if (value && (value & 3) != 3) return -EIO; - child->thread.fs = value; + child->thread.gs = value; return 0; case DS: case ES: - case GS: + case FS: if (value && (value & 3) != 3) return -EIO; value &= 0xffff; @@ -112,7 +112,7 @@ static int putreg(struct task_struct *ch value |= get_stack_long(child, EFL_OFFSET) & ~FLAG_MASK; break; } - if (regno > ES*4) + if (regno > FS*4) regno -= 1*4; put_stack_long(child, regno, value); return 0; @@ -124,18 +124,18 @@ static unsigned long getreg(struct task_ unsigned long retval = ~0UL; switch (regno >> 2) { - case FS: - retval = child->thread.fs; + case GS: + retval = child->thread.gs; break; case DS: case ES: - case GS: + case FS: case SS: case CS: retval = 0xffff; /* fall through */ default: - if (regno > ES*4) + if (regno > FS*4) regno -= 1*4; retval &= get_stack_long(child, regno); } diff --git a/arch/i386/kernel/setup.c b/arch/i386/kernel/setup.c index 4b31ad7..122623d 100644 --- a/arch/i386/kernel/setup.c +++ b/arch/i386/kernel/setup.c @@ -33,7 +33,6 @@ #include #include #include #include -#include #include #include #include @@ -60,6 +59,7 @@ #include #include #include #include +#include #include #include @@ -132,7 +132,7 @@ #define RAMDISK_IMAGE_START_MASK 0x07F #define RAMDISK_PROMPT_FLAG 0x8000 #define RAMDISK_LOAD_FLAG 0x4000 -static char command_line[COMMAND_LINE_SIZE]; +static char __initdata command_line[COMMAND_LINE_SIZE]; unsigned char __initdata boot_params[PARAM_SIZE]; @@ -576,11 +576,19 @@ #endif print_memory_map("user"); } - strlcpy(command_line, saved_command_line, COMMAND_LINE_SIZE); + strlcpy(command_line, boot_command_line, COMMAND_LINE_SIZE); *cmdline_p = command_line; max_low_pfn = setup_memory(); +#ifdef CONFIG_VMI + /* + * Must be after max_low_pfn is determined, and before kernel + * pagetables are setup. + */ + vmi_init(); +#endif + /* * NOTE: before this point _nobody_ is allowed to allocate * any memory using the bootmem allocator. Although the @@ -651,28 +659,3 @@ #endif #endif tsc_init(); } - -static __init int add_pcspkr(void) -{ - struct platform_device *pd; - int ret; - - pd = platform_device_alloc("pcspkr", -1); - if (!pd) - return -ENOMEM; - - ret = platform_device_add(pd); - if (ret) - platform_device_put(pd); - - return ret; -} -device_initcall(add_pcspkr); - -/* - * Local Variables: - * mode:c - * c-file-style:"k&r" - * c-basic-offset:8 - * End: - */ diff --git a/arch/i386/kernel/signal.c b/arch/i386/kernel/signal.c index 65d7620..4f99e87 100644 --- a/arch/i386/kernel/signal.c +++ b/arch/i386/kernel/signal.c @@ -21,6 +21,7 @@ #include #include #include #include +#include #include #include #include @@ -128,8 +129,8 @@ #define FIX_EFLAGS (X86_EFLAGS_AC | X86_ X86_EFLAGS_TF | X86_EFLAGS_SF | X86_EFLAGS_ZF | \ X86_EFLAGS_AF | X86_EFLAGS_PF | X86_EFLAGS_CF) - COPY_SEG(gs); - GET_SEG(fs); + GET_SEG(gs); + COPY_SEG(fs); COPY_SEG(es); COPY_SEG(ds); COPY(edi); @@ -244,9 +245,9 @@ setup_sigcontext(struct sigcontext __use { int tmp, err = 0; - err |= __put_user(regs->xgs, (unsigned int __user *)&sc->gs); - savesegment(fs, tmp); - err |= __put_user(tmp, (unsigned int __user *)&sc->fs); + err |= __put_user(regs->xfs, (unsigned int __user *)&sc->fs); + savesegment(gs, tmp); + err |= __put_user(tmp, (unsigned int __user *)&sc->gs); err |= __put_user(regs->xes, (unsigned int __user *)&sc->es); err |= __put_user(regs->xds, (unsigned int __user *)&sc->ds); @@ -349,7 +350,10 @@ static int setup_frame(int sig, struct k goto give_sigsegv; } - restorer = (void *)VDSO_SYM(&__kernel_sigreturn); + if (current->binfmt->hasvdso) + restorer = (void *)VDSO_SYM(&__kernel_sigreturn); + else + restorer = (void *)&frame->retcode; if (ka->sa.sa_flags & SA_RESTORER) restorer = ka->sa.sa_restorer; diff --git a/arch/i386/kernel/smp.c b/arch/i386/kernel/smp.c index 5285aff..9bd9637 100644 --- a/arch/i386/kernel/smp.c +++ b/arch/i386/kernel/smp.c @@ -23,6 +23,7 @@ #include #include #include +#include #include /* @@ -374,8 +375,7 @@ static void flush_tlb_others(cpumask_t c /* * i'm not happy about this global shared spinlock in the * MM hot path, but we'll see how contended it is. - * Temporarily this turns IRQs off, so that lockups are - * detected by the NMI watchdog. + * AK: x86-64 has a faster method that could be ported. */ spin_lock(&tlbstate_lock); @@ -400,7 +400,7 @@ #endif while (!cpus_empty(flush_cpumask)) /* nothing. lockup detection does not belong here */ - mb(); + cpu_relax(); flush_mm = NULL; flush_va = 0; @@ -624,6 +624,7 @@ fastcall void smp_call_function_interrup /* * At this point the info structure may be out of scope unless wait==1 */ + exit_idle(); irq_enter(); (*func)(info); irq_exit(); diff --git a/arch/i386/kernel/smpboot.c b/arch/i386/kernel/smpboot.c index 8c6c8c5..48bfcaa 100644 --- a/arch/i386/kernel/smpboot.c +++ b/arch/i386/kernel/smpboot.c @@ -63,6 +63,7 @@ #include #include #include #include +#include /* Set if we find a B stepping CPU */ static int __devinitdata smp_b_stepping; @@ -93,12 +94,6 @@ cpumask_t cpu_possible_map; EXPORT_SYMBOL(cpu_possible_map); static cpumask_t smp_commenced_mask; -/* TSC's upper 32 bits can't be written in eariler CPU (before prescott), there - * is no way to resync one AP against BP. TBD: for prescott and above, we - * should use IA64's algorithm - */ -static int __devinitdata tsc_sync_disabled; - /* Per CPU bogomips and other parameters */ struct cpuinfo_x86 cpu_data[NR_CPUS] __cacheline_aligned; EXPORT_SYMBOL(cpu_data); @@ -215,151 +210,6 @@ valid_k7: ; } -/* - * TSC synchronization. - * - * We first check whether all CPUs have their TSC's synchronized, - * then we print a warning if not, and always resync. - */ - -static struct { - atomic_t start_flag; - atomic_t count_start; - atomic_t count_stop; - unsigned long long values[NR_CPUS]; -} tsc __cpuinitdata = { - .start_flag = ATOMIC_INIT(0), - .count_start = ATOMIC_INIT(0), - .count_stop = ATOMIC_INIT(0), -}; - -#define NR_LOOPS 5 - -static void __init synchronize_tsc_bp(void) -{ - int i; - unsigned long long t0; - unsigned long long sum, avg; - long long delta; - unsigned int one_usec; - int buggy = 0; - - printk(KERN_INFO "checking TSC synchronization across %u CPUs: ", num_booting_cpus()); - - /* convert from kcyc/sec to cyc/usec */ - one_usec = cpu_khz / 1000; - - atomic_set(&tsc.start_flag, 1); - wmb(); - - /* - * We loop a few times to get a primed instruction cache, - * then the last pass is more or less synchronized and - * the BP and APs set their cycle counters to zero all at - * once. This reduces the chance of having random offsets - * between the processors, and guarantees that the maximum - * delay between the cycle counters is never bigger than - * the latency of information-passing (cachelines) between - * two CPUs. - */ - for (i = 0; i < NR_LOOPS; i++) { - /* - * all APs synchronize but they loop on '== num_cpus' - */ - while (atomic_read(&tsc.count_start) != num_booting_cpus()-1) - cpu_relax(); - atomic_set(&tsc.count_stop, 0); - wmb(); - /* - * this lets the APs save their current TSC: - */ - atomic_inc(&tsc.count_start); - - rdtscll(tsc.values[smp_processor_id()]); - /* - * We clear the TSC in the last loop: - */ - if (i == NR_LOOPS-1) - write_tsc(0, 0); - - /* - * Wait for all APs to leave the synchronization point: - */ - while (atomic_read(&tsc.count_stop) != num_booting_cpus()-1) - cpu_relax(); - atomic_set(&tsc.count_start, 0); - wmb(); - atomic_inc(&tsc.count_stop); - } - - sum = 0; - for (i = 0; i < NR_CPUS; i++) { - if (cpu_isset(i, cpu_callout_map)) { - t0 = tsc.values[i]; - sum += t0; - } - } - avg = sum; - do_div(avg, num_booting_cpus()); - - for (i = 0; i < NR_CPUS; i++) { - if (!cpu_isset(i, cpu_callout_map)) - continue; - delta = tsc.values[i] - avg; - if (delta < 0) - delta = -delta; - /* - * We report bigger than 2 microseconds clock differences. - */ - if (delta > 2*one_usec) { - long long realdelta; - - if (!buggy) { - buggy = 1; - printk("\n"); - } - realdelta = delta; - do_div(realdelta, one_usec); - if (tsc.values[i] < avg) - realdelta = -realdelta; - - if (realdelta) - printk(KERN_INFO "CPU#%d had %Ld usecs TSC " - "skew, fixed it up.\n", i, realdelta); - } - } - if (!buggy) - printk("passed.\n"); -} - -static void __cpuinit synchronize_tsc_ap(void) -{ - int i; - - /* - * Not every cpu is online at the time - * this gets called, so we first wait for the BP to - * finish SMP initialization: - */ - while (!atomic_read(&tsc.start_flag)) - cpu_relax(); - - for (i = 0; i < NR_LOOPS; i++) { - atomic_inc(&tsc.count_start); - while (atomic_read(&tsc.count_start) != num_booting_cpus()) - cpu_relax(); - - rdtscll(tsc.values[smp_processor_id()]); - if (i == NR_LOOPS-1) - write_tsc(0, 0); - - atomic_inc(&tsc.count_stop); - while (atomic_read(&tsc.count_stop) != num_booting_cpus()) - cpu_relax(); - } -} -#undef NR_LOOPS - extern void calibrate_delay(void); static atomic_t init_deasserted; @@ -437,20 +287,12 @@ static void __cpuinit smp_callin(void) /* * Save our processor parameters */ - smp_store_cpu_info(cpuid); - - disable_APIC_timer(); + smp_store_cpu_info(cpuid); /* * Allow the master to continue. */ cpu_set(cpuid, cpu_callin_map); - - /* - * Synchronize the TSC with the BP - */ - if (cpu_has_tsc && cpu_khz && !tsc_sync_disabled) - synchronize_tsc_ap(); } static int cpucount; @@ -545,18 +387,25 @@ static void __cpuinit start_secondary(vo * booting is too fragile that we want to limit the * things done here to the most necessary things. */ +#ifdef CONFIG_VMI + vmi_bringup(); +#endif secondary_cpu_init(); preempt_disable(); smp_callin(); while (!cpu_isset(smp_processor_id(), smp_commenced_mask)) rep_nop(); - setup_secondary_APIC_clock(); + /* + * Check TSC synchronization with the BP: + */ + check_tsc_sync_target(); + + setup_secondary_clock(); if (nmi_watchdog == NMI_IO_APIC) { disable_8259A_irq(0); enable_NMI_through_LVT0(NULL); enable_8259A_irq(0); } - enable_APIC_timer(); /* * low-memory mappings have been cleared, flush them from * the local TLBs too. @@ -619,7 +468,6 @@ extern struct { unsigned short ss; } stack_start; extern struct i386_pda *start_pda; -extern struct Xgt_desc_struct cpu_gdt_descr; #ifdef CONFIG_NUMA @@ -749,7 +597,7 @@ wakeup_secondary_cpu(int logical_apicid, /* * Due to the Pentium erratum 3AP. */ - maxlvt = get_maxlvt(); + maxlvt = lapic_get_maxlvt(); if (maxlvt > 3) { apic_read_around(APIC_SPIV); apic_write(APIC_ESR, 0); @@ -835,11 +683,18 @@ wakeup_secondary_cpu(int phys_apicid, un num_starts = 0; /* + * Paravirt / VMI wants a startup IPI hook here to set up the + * target processor state. + */ + startup_ipi_hook(phys_apicid, (unsigned long) start_secondary, + (unsigned long) stack_start.esp); + + /* * Run STARTUP IPI loop. */ Dprintk("#startup loops: %d.\n", num_starts); - maxlvt = get_maxlvt(); + maxlvt = lapic_get_maxlvt(); for (j = 1; j <= num_starts; j++) { Dprintk("Sending STARTUP #%d.\n",j); @@ -1115,8 +970,6 @@ static int __cpuinit __smp_prepare_cpu(i info.cpu = cpu; INIT_WORK(&info.task, do_warm_boot_cpu); - tsc_sync_disabled = 1; - /* init low mem mapping */ clone_pgd_range(swapper_pg_dir, swapper_pg_dir + USER_PGD_PTRS, min_t(unsigned long, KERNEL_PGD_PTRS, USER_PGD_PTRS)); @@ -1124,7 +977,6 @@ static int __cpuinit __smp_prepare_cpu(i schedule_work(&info.task); wait_for_completion(&done); - tsc_sync_disabled = 0; zap_low_mappings(); ret = 0; exit: @@ -1320,13 +1172,7 @@ static void __init smp_boot_cpus(unsigne smpboot_setup_io_apic(); - setup_boot_APIC_clock(); - - /* - * Synchronize the TSC with the AP - */ - if (cpu_has_tsc && cpucount && cpu_khz) - synchronize_tsc_bp(); + setup_boot_clock(); } /* These are wrappers to interface to the new boot process. Someone @@ -1461,9 +1307,16 @@ #endif } local_irq_enable(); + per_cpu(cpu_state, cpu) = CPU_UP_PREPARE; /* Unleash the CPU! */ cpu_set(cpu, smp_commenced_mask); + + /* + * Check TSC synchronization with the AP: + */ + check_tsc_sync_source(cpu); + while (!cpu_isset(cpu, cpu_online_map)) cpu_relax(); diff --git a/arch/i386/kernel/srat.c b/arch/i386/kernel/srat.c index f7e735c..2a8713e 100644 --- a/arch/i386/kernel/srat.c +++ b/arch/i386/kernel/srat.c @@ -62,19 +62,19 @@ extern void * boot_ioremap(unsigned long /* Identify CPU proximity domains */ static void __init parse_cpu_affinity_structure(char *p) { - struct acpi_table_processor_affinity *cpu_affinity = - (struct acpi_table_processor_affinity *) p; + struct acpi_srat_cpu_affinity *cpu_affinity = + (struct acpi_srat_cpu_affinity *) p; - if (!cpu_affinity->flags.enabled) + if ((cpu_affinity->flags & ACPI_SRAT_CPU_ENABLED) == 0) return; /* empty entry */ /* mark this node as "seen" in node bitmap */ - BMAP_SET(pxm_bitmap, cpu_affinity->proximity_domain); + BMAP_SET(pxm_bitmap, cpu_affinity->proximity_domain_lo); - apicid_to_pxm[cpu_affinity->apic_id] = cpu_affinity->proximity_domain; + apicid_to_pxm[cpu_affinity->apic_id] = cpu_affinity->proximity_domain_lo; printk("CPU 0x%02X in proximity domain 0x%02X\n", - cpu_affinity->apic_id, cpu_affinity->proximity_domain); + cpu_affinity->apic_id, cpu_affinity->proximity_domain_lo); } /* @@ -84,28 +84,27 @@ static void __init parse_cpu_affinity_st static void __init parse_memory_affinity_structure (char *sratp) { unsigned long long paddr, size; - unsigned long start_pfn, end_pfn; + unsigned long start_pfn, end_pfn; u8 pxm; struct node_memory_chunk_s *p, *q, *pend; - struct acpi_table_memory_affinity *memory_affinity = - (struct acpi_table_memory_affinity *) sratp; + struct acpi_srat_mem_affinity *memory_affinity = + (struct acpi_srat_mem_affinity *) sratp; - if (!memory_affinity->flags.enabled) + if ((memory_affinity->flags & ACPI_SRAT_MEM_ENABLED) == 0) return; /* empty entry */ + pxm = memory_affinity->proximity_domain & 0xff; + /* mark this node as "seen" in node bitmap */ - BMAP_SET(pxm_bitmap, memory_affinity->proximity_domain); + BMAP_SET(pxm_bitmap, pxm); /* calculate info for memory chunk structure */ - paddr = memory_affinity->base_addr_hi; - paddr = (paddr << 32) | memory_affinity->base_addr_lo; - size = memory_affinity->length_hi; - size = (size << 32) | memory_affinity->length_lo; - + paddr = memory_affinity->base_address; + size = memory_affinity->length; + start_pfn = paddr >> PAGE_SHIFT; end_pfn = (paddr + size) >> PAGE_SHIFT; - - pxm = memory_affinity->proximity_domain; + if (num_memory_chunks >= MAXCHUNKS) { printk("Too many mem chunks in SRAT. Ignoring %lld MBytes at %llx\n", @@ -132,8 +131,8 @@ static void __init parse_memory_affinity printk("Memory range 0x%lX to 0x%lX (type 0x%X) in proximity domain 0x%02X %s\n", start_pfn, end_pfn, memory_affinity->memory_type, - memory_affinity->proximity_domain, - (memory_affinity->flags.hot_pluggable ? + pxm, + ((memory_affinity->flags & ACPI_SRAT_MEM_HOT_PLUGGABLE) ? "enabled and removable" : "enabled" ) ); } @@ -185,10 +184,10 @@ static int __init acpi20_parse_srat(stru num_memory_chunks = 0; while (p < end) { switch (*p) { - case ACPI_SRAT_PROCESSOR_AFFINITY: + case ACPI_SRAT_TYPE_CPU_AFFINITY: parse_cpu_affinity_structure(p); break; - case ACPI_SRAT_MEMORY_AFFINITY: + case ACPI_SRAT_TYPE_MEMORY_AFFINITY: parse_memory_affinity_structure(p); break; default: @@ -262,31 +261,30 @@ out_fail: return 0; } +struct acpi_static_rsdt { + struct acpi_table_rsdt table; + u32 padding[7]; /* Allow for 7 more table entries */ +}; + int __init get_memcfg_from_srat(void) { struct acpi_table_header *header = NULL; struct acpi_table_rsdp *rsdp = NULL; struct acpi_table_rsdt *rsdt = NULL; - struct acpi_pointer *rsdp_address = NULL; - struct acpi_table_rsdt saved_rsdt; + acpi_native_uint rsdp_address = 0; + struct acpi_static_rsdt saved_rsdt; int tables = 0; int i = 0; - if (ACPI_FAILURE(acpi_find_root_pointer(ACPI_PHYSICAL_ADDRESSING, - rsdp_address))) { + rsdp_address = acpi_find_rsdp(); + if (!rsdp_address) { printk("%s: System description tables not found\n", __FUNCTION__); goto out_err; } - if (rsdp_address->pointer_type == ACPI_PHYSICAL_POINTER) { - printk("%s: assigning address to rsdp\n", __FUNCTION__); - rsdp = (struct acpi_table_rsdp *) - (u32)rsdp_address->pointer.physical; - } else { - printk("%s: rsdp_address is not a physical pointer\n", __FUNCTION__); - goto out_err; - } + printk("%s: assigning address to rsdp\n", __FUNCTION__); + rsdp = (struct acpi_table_rsdp *)(u32)rsdp_address; if (!rsdp) { printk("%s: Didn't find ACPI root!\n", __FUNCTION__); goto out_err; @@ -295,13 +293,13 @@ int __init get_memcfg_from_srat(void) printk(KERN_INFO "%.8s v%d [%.6s]\n", rsdp->signature, rsdp->revision, rsdp->oem_id); - if (strncmp(rsdp->signature, RSDP_SIG,strlen(RSDP_SIG))) { + if (strncmp(rsdp->signature, ACPI_SIG_RSDP,strlen(ACPI_SIG_RSDP))) { printk(KERN_WARNING "%s: RSDP table signature incorrect\n", __FUNCTION__); goto out_err; } rsdt = (struct acpi_table_rsdt *) - boot_ioremap(rsdp->rsdt_address, sizeof(struct acpi_table_rsdt)); + boot_ioremap(rsdp->rsdt_physical_address, sizeof(struct acpi_table_rsdt)); if (!rsdt) { printk(KERN_WARNING @@ -310,9 +308,9 @@ int __init get_memcfg_from_srat(void) goto out_err; } - header = & rsdt->header; + header = &rsdt->header; - if (strncmp(header->signature, RSDT_SIG, strlen(RSDT_SIG))) { + if (strncmp(header->signature, ACPI_SIG_RSDT, strlen(ACPI_SIG_RSDT))) { printk(KERN_WARNING "ACPI: RSDT signature incorrect\n"); goto out_err; } @@ -330,9 +328,9 @@ int __init get_memcfg_from_srat(void) memcpy(&saved_rsdt, rsdt, sizeof(saved_rsdt)); - if (saved_rsdt.header.length > sizeof(saved_rsdt)) { + if (saved_rsdt.table.header.length > sizeof(saved_rsdt)) { printk(KERN_WARNING "ACPI: Too big length in RSDT: %d\n", - saved_rsdt.header.length); + saved_rsdt.table.header.length); goto out_err; } @@ -341,15 +339,15 @@ int __init get_memcfg_from_srat(void) for (i = 0; i < tables; i++) { /* Map in header, then map in full table length. */ header = (struct acpi_table_header *) - boot_ioremap(saved_rsdt.entry[i], sizeof(struct acpi_table_header)); + boot_ioremap(saved_rsdt.table.table_offset_entry[i], sizeof(struct acpi_table_header)); if (!header) break; header = (struct acpi_table_header *) - boot_ioremap(saved_rsdt.entry[i], header->length); + boot_ioremap(saved_rsdt.table.table_offset_entry[i], header->length); if (!header) break; - if (strncmp((char *) &header->signature, "SRAT", 4)) + if (strncmp((char *) &header->signature, ACPI_SIG_SRAT, 4)) continue; /* we've found the srat table. don't need to look at any more tables */ diff --git a/arch/i386/kernel/sysenter.c b/arch/i386/kernel/sysenter.c index 5da7442..13ca54a 100644 --- a/arch/i386/kernel/sysenter.c +++ b/arch/i386/kernel/sysenter.c @@ -70,14 +70,15 @@ void enable_sep_cpu(void) */ extern const char vsyscall_int80_start, vsyscall_int80_end; extern const char vsyscall_sysenter_start, vsyscall_sysenter_end; -static void *syscall_page; +static struct page *syscall_pages[1]; int __init sysenter_setup(void) { - syscall_page = (void *)get_zeroed_page(GFP_ATOMIC); + void *syscall_page = (void *)get_zeroed_page(GFP_ATOMIC); + syscall_pages[0] = virt_to_page(syscall_page); #ifdef CONFIG_COMPAT_VDSO - __set_fixmap(FIX_VDSO, __pa(syscall_page), PAGE_READONLY); + __set_fixmap(FIX_VDSO, __pa(syscall_page), PAGE_READONLY_EXEC); printk("Compat vDSO mapped to %08lx.\n", __fix_to_virt(FIX_VDSO)); #endif @@ -96,31 +97,12 @@ #endif } #ifndef CONFIG_COMPAT_VDSO -static struct page *syscall_nopage(struct vm_area_struct *vma, - unsigned long adr, int *type) -{ - struct page *p = virt_to_page(adr - vma->vm_start + syscall_page); - get_page(p); - return p; -} - -/* Prevent VMA merging */ -static void syscall_vma_close(struct vm_area_struct *vma) -{ -} - -static struct vm_operations_struct syscall_vm_ops = { - .close = syscall_vma_close, - .nopage = syscall_nopage, -}; - /* Defined in vsyscall-sysenter.S */ extern void SYSENTER_RETURN; /* Setup a VMA at program startup for the vsyscall page */ int arch_setup_additional_pages(struct linux_binprm *bprm, int exstack) { - struct vm_area_struct *vma; struct mm_struct *mm = current->mm; unsigned long addr; int ret; @@ -132,38 +114,25 @@ int arch_setup_additional_pages(struct l goto up_fail; } - vma = kmem_cache_zalloc(vm_area_cachep, GFP_KERNEL); - if (!vma) { - ret = -ENOMEM; - goto up_fail; - } - - vma->vm_start = addr; - vma->vm_end = addr + PAGE_SIZE; - /* MAYWRITE to allow gdb to COW and set breakpoints */ - vma->vm_flags = VM_READ|VM_EXEC|VM_MAYREAD|VM_MAYEXEC|VM_MAYWRITE; /* + * MAYWRITE to allow gdb to COW and set breakpoints + * * Make sure the vDSO gets into every core dump. * Dumping its contents makes post-mortem fully interpretable later * without matching up the same kernel and hardware config to see * what PC values meant. */ - vma->vm_flags |= VM_ALWAYSDUMP; - vma->vm_flags |= mm->def_flags; - vma->vm_page_prot = protection_map[vma->vm_flags & 7]; - vma->vm_ops = &syscall_vm_ops; - vma->vm_mm = mm; - - ret = insert_vm_struct(mm, vma); - if (unlikely(ret)) { - kmem_cache_free(vm_area_cachep, vma); + ret = install_special_mapping(mm, addr, PAGE_SIZE, + VM_READ|VM_EXEC| + VM_MAYREAD|VM_MAYWRITE|VM_MAYEXEC| + VM_ALWAYSDUMP, + syscall_pages); + if (ret) goto up_fail; - } current->mm->context.vdso = (void *)addr; current_thread_info()->sysenter_return = (void *)VDSO_SYM(&SYSENTER_RETURN); - mm->total_vm++; up_fail: up_write(&mm->mmap_sem); return ret; diff --git a/arch/i386/kernel/time.c b/arch/i386/kernel/time.c index c505b16..a535005 100644 --- a/arch/i386/kernel/time.c +++ b/arch/i386/kernel/time.c @@ -131,15 +131,13 @@ unsigned long profile_pc(struct pt_regs unsigned long pc = instruction_pointer(regs); #ifdef CONFIG_SMP - if (!user_mode_vm(regs) && in_lock_functions(pc)) { + if (!v8086_mode(regs) && SEGMENT_IS_KERNEL_CODE(regs->xcs) && + in_lock_functions(pc)) { #ifdef CONFIG_FRAME_POINTER return *(unsigned long *)(regs->ebp + 4); #else - unsigned long *sp; - if ((regs->xcs & 3) == 0) - sp = (unsigned long *)®s->esp; - else - sp = (unsigned long *)regs->esp; + unsigned long *sp = (unsigned long *)®s->esp; + /* Return address is either directly at stack pointer or above a saved eflags. Eflags has bits 22-31 zero, kernel addresses don't. */ @@ -161,15 +159,6 @@ EXPORT_SYMBOL(profile_pc); */ irqreturn_t timer_interrupt(int irq, void *dev_id) { - /* - * Here we are in the timer irq handler. We just have irqs locally - * disabled but we don't know if the timer_bh is running on the other - * CPU. We need to avoid to SMP race with it. NOTE: we don' t need - * the irq version of write_lock because as just said we have irq - * locally disabled. -arca - */ - write_seqlock(&xtime_lock); - #ifdef CONFIG_X86_IO_APIC if (timer_ack) { /* @@ -188,7 +177,6 @@ #endif do_timer_interrupt_hook(); - if (MCA_bus) { /* The PS/2 uses level-triggered interrupts. You can't turn them off, nor would you want to (any attempt to @@ -203,18 +191,11 @@ #endif outb_p( irq_v|0x80, 0x61 ); /* reset the IRQ */ } - write_sequnlock(&xtime_lock); - -#ifdef CONFIG_X86_LOCAL_APIC - if (using_apic_timer) - smp_send_timer_broadcast_ipi(); -#endif - return IRQ_HANDLED; } /* not static: needed by APM */ -unsigned long get_cmos_time(void) +unsigned long read_persistent_clock(void) { unsigned long retval; unsigned long flags; @@ -227,11 +208,11 @@ unsigned long get_cmos_time(void) return retval; } -EXPORT_SYMBOL(get_cmos_time); static void sync_cmos_clock(unsigned long dummy); static DEFINE_TIMER(sync_cmos_timer, sync_cmos_clock, 0, 0); +int no_sync_cmos_clock; static void sync_cmos_clock(unsigned long dummy) { @@ -275,117 +256,20 @@ static void sync_cmos_clock(unsigned lon void notify_arch_cmos_timer(void) { - mod_timer(&sync_cmos_timer, jiffies + 1); -} - -static long clock_cmos_diff; -static unsigned long sleep_start; - -static int timer_suspend(struct sys_device *dev, pm_message_t state) -{ - /* - * Estimate time zone so that set_time can update the clock - */ - unsigned long ctime = get_cmos_time(); - - clock_cmos_diff = -ctime; - clock_cmos_diff += get_seconds(); - sleep_start = ctime; - return 0; -} - -static int timer_resume(struct sys_device *dev) -{ - unsigned long flags; - unsigned long sec; - unsigned long ctime = get_cmos_time(); - long sleep_length = (ctime - sleep_start) * HZ; - struct timespec ts; - - if (sleep_length < 0) { - printk(KERN_WARNING "CMOS clock skew detected in timer resume!\n"); - /* The time after the resume must not be earlier than the time - * before the suspend or some nasty things will happen - */ - sleep_length = 0; - ctime = sleep_start; - } -#ifdef CONFIG_HPET_TIMER - if (is_hpet_enabled()) - hpet_reenable(); -#endif - setup_pit_timer(); - - sec = ctime + clock_cmos_diff; - ts.tv_sec = sec; - ts.tv_nsec = 0; - do_settimeofday(&ts); - write_seqlock_irqsave(&xtime_lock, flags); - jiffies_64 += sleep_length; - write_sequnlock_irqrestore(&xtime_lock, flags); - touch_softlockup_watchdog(); - return 0; -} - -static struct sysdev_class timer_sysclass = { - .resume = timer_resume, - .suspend = timer_suspend, - set_kset_name("timer"), -}; - - -/* XXX this driverfs stuff should probably go elsewhere later -john */ -static struct sys_device device_timer = { - .id = 0, - .cls = &timer_sysclass, -}; - -static int time_init_device(void) -{ - int error = sysdev_class_register(&timer_sysclass); - if (!error) - error = sysdev_register(&device_timer); - return error; + if (!no_sync_cmos_clock) + mod_timer(&sync_cmos_timer, jiffies + 1); } -device_initcall(time_init_device); - -#ifdef CONFIG_HPET_TIMER extern void (*late_time_init)(void); /* Duplicate of time_init() below, with hpet_enable part added */ static void __init hpet_time_init(void) { - struct timespec ts; - ts.tv_sec = get_cmos_time(); - ts.tv_nsec = (INITIAL_JIFFIES % HZ) * (NSEC_PER_SEC / HZ); - - do_settimeofday(&ts); - - if ((hpet_enable() >= 0) && hpet_use_timer) { - printk("Using HPET for base-timer\n"); - } - + if (!hpet_enable()) + setup_pit_timer(); do_time_init(); } -#endif void __init time_init(void) { - struct timespec ts; -#ifdef CONFIG_HPET_TIMER - if (is_hpet_capable()) { - /* - * HPET initialization needs to do memory-mapped io. So, let - * us do a late initialization after mem_init(). - */ - late_time_init = hpet_time_init; - return; - } -#endif - ts.tv_sec = get_cmos_time(); - ts.tv_nsec = (INITIAL_JIFFIES % HZ) * (NSEC_PER_SEC / HZ); - - do_settimeofday(&ts); - - do_time_init(); + late_time_init = hpet_time_init; } diff --git a/arch/i386/kernel/time_hpet.c b/arch/i386/kernel/time_hpet.c deleted file mode 100644 index 1e4702d..0000000 --- a/arch/i386/kernel/time_hpet.c +++ /dev/null @@ -1,497 +0,0 @@ -/* - * linux/arch/i386/kernel/time_hpet.c - * This code largely copied from arch/x86_64/kernel/time.c - * See that file for credits. - * - * 2003-06-30 Venkatesh Pallipadi - Additional changes for HPET support - */ - -#include -#include -#include -#include -#include -#include - -#include -#include -#include - -#include - -#include -#include - -static unsigned long hpet_period; /* fsecs / HPET clock */ -unsigned long hpet_tick; /* hpet clks count per tick */ -unsigned long hpet_address; /* hpet memory map physical address */ -int hpet_use_timer; - -static int use_hpet; /* can be used for runtime check of hpet */ -static int boot_hpet_disable; /* boottime override for HPET timer */ -static void __iomem * hpet_virt_address; /* hpet kernel virtual address */ - -#define FSEC_TO_USEC (1000000000UL) - -int hpet_readl(unsigned long a) -{ - return readl(hpet_virt_address + a); -} - -static void hpet_writel(unsigned long d, unsigned long a) -{ - writel(d, hpet_virt_address + a); -} - -#ifdef CONFIG_X86_LOCAL_APIC -/* - * HPET counters dont wrap around on every tick. They just change the - * comparator value and continue. Next tick can be caught by checking - * for a change in the comparator value. Used in apic.c. - */ -static void __devinit wait_hpet_tick(void) -{ - unsigned int start_cmp_val, end_cmp_val; - - start_cmp_val = hpet_readl(HPET_T0_CMP); - do { - end_cmp_val = hpet_readl(HPET_T0_CMP); - } while (start_cmp_val == end_cmp_val); -} -#endif - -static int hpet_timer_stop_set_go(unsigned long tick) -{ - unsigned int cfg; - - /* - * Stop the timers and reset the main counter. - */ - cfg = hpet_readl(HPET_CFG); - cfg &= ~HPET_CFG_ENABLE; - hpet_writel(cfg, HPET_CFG); - hpet_writel(0, HPET_COUNTER); - hpet_writel(0, HPET_COUNTER + 4); - - if (hpet_use_timer) { - /* - * Set up timer 0, as periodic with first interrupt to happen at - * hpet_tick, and period also hpet_tick. - */ - cfg = hpet_readl(HPET_T0_CFG); - cfg |= HPET_TN_ENABLE | HPET_TN_PERIODIC | - HPET_TN_SETVAL | HPET_TN_32BIT; - hpet_writel(cfg, HPET_T0_CFG); - - /* - * The first write after writing TN_SETVAL to the config register sets - * the counter value, the second write sets the threshold. - */ - hpet_writel(tick, HPET_T0_CMP); - hpet_writel(tick, HPET_T0_CMP); - } - /* - * Go! - */ - cfg = hpet_readl(HPET_CFG); - if (hpet_use_timer) - cfg |= HPET_CFG_LEGACY; - cfg |= HPET_CFG_ENABLE; - hpet_writel(cfg, HPET_CFG); - - return 0; -} - -/* - * Check whether HPET was found by ACPI boot parse. If yes setup HPET - * counter 0 for kernel base timer. - */ -int __init hpet_enable(void) -{ - unsigned int id; - unsigned long tick_fsec_low, tick_fsec_high; /* tick in femto sec */ - unsigned long hpet_tick_rem; - - if (boot_hpet_disable) - return -1; - - if (!hpet_address) { - return -1; - } - hpet_virt_address = ioremap_nocache(hpet_address, HPET_MMAP_SIZE); - /* - * Read the period, compute tick and quotient. - */ - id = hpet_readl(HPET_ID); - - /* - * We are checking for value '1' or more in number field if - * CONFIG_HPET_EMULATE_RTC is set because we will need an - * additional timer for RTC emulation. - * However, we can do with one timer otherwise using the - * the single HPET timer for system time. - */ -#ifdef CONFIG_HPET_EMULATE_RTC - if (!(id & HPET_ID_NUMBER)) { - iounmap(hpet_virt_address); - hpet_virt_address = NULL; - return -1; - } -#endif - - - hpet_period = hpet_readl(HPET_PERIOD); - if ((hpet_period < HPET_MIN_PERIOD) || (hpet_period > HPET_MAX_PERIOD)) { - iounmap(hpet_virt_address); - hpet_virt_address = NULL; - return -1; - } - - /* - * 64 bit math - * First changing tick into fsec - * Then 64 bit div to find number of hpet clk per tick - */ - ASM_MUL64_REG(tick_fsec_low, tick_fsec_high, - KERNEL_TICK_USEC, FSEC_TO_USEC); - ASM_DIV64_REG(hpet_tick, hpet_tick_rem, - hpet_period, tick_fsec_low, tick_fsec_high); - - if (hpet_tick_rem > (hpet_period >> 1)) - hpet_tick++; /* rounding the result */ - - hpet_use_timer = id & HPET_ID_LEGSUP; - - if (hpet_timer_stop_set_go(hpet_tick)) { - iounmap(hpet_virt_address); - hpet_virt_address = NULL; - return -1; - } - - use_hpet = 1; - -#ifdef CONFIG_HPET - { - struct hpet_data hd; - unsigned int ntimer; - - memset(&hd, 0, sizeof (hd)); - - ntimer = hpet_readl(HPET_ID); - ntimer = (ntimer & HPET_ID_NUMBER) >> HPET_ID_NUMBER_SHIFT; - ntimer++; - - /* - * Register with driver. - * Timer0 and Timer1 is used by platform. - */ - hd.hd_phys_address = hpet_address; - hd.hd_address = hpet_virt_address; - hd.hd_nirqs = ntimer; - hd.hd_flags = HPET_DATA_PLATFORM; - hpet_reserve_timer(&hd, 0); -#ifdef CONFIG_HPET_EMULATE_RTC - hpet_reserve_timer(&hd, 1); -#endif - hd.hd_irq[0] = HPET_LEGACY_8254; - hd.hd_irq[1] = HPET_LEGACY_RTC; - if (ntimer > 2) { - struct hpet __iomem *hpet; - struct hpet_timer __iomem *timer; - int i; - - hpet = hpet_virt_address; - - for (i = 2, timer = &hpet->hpet_timers[2]; i < ntimer; - timer++, i++) - hd.hd_irq[i] = (timer->hpet_config & - Tn_INT_ROUTE_CNF_MASK) >> - Tn_INT_ROUTE_CNF_SHIFT; - - } - - hpet_alloc(&hd); - } -#endif - -#ifdef CONFIG_X86_LOCAL_APIC - if (hpet_use_timer) - wait_timer_tick = wait_hpet_tick; -#endif - return 0; -} - -int hpet_reenable(void) -{ - return hpet_timer_stop_set_go(hpet_tick); -} - -int is_hpet_enabled(void) -{ - return use_hpet; -} - -int is_hpet_capable(void) -{ - if (!boot_hpet_disable && hpet_address) - return 1; - return 0; -} - -static int __init hpet_setup(char* str) -{ - if (str) { - if (!strncmp("disable", str, 7)) - boot_hpet_disable = 1; - } - return 1; -} - -__setup("hpet=", hpet_setup); - -#ifdef CONFIG_HPET_EMULATE_RTC -/* HPET in LegacyReplacement Mode eats up RTC interrupt line. When, HPET - * is enabled, we support RTC interrupt functionality in software. - * RTC has 3 kinds of interrupts: - * 1) Update Interrupt - generate an interrupt, every sec, when RTC clock - * is updated - * 2) Alarm Interrupt - generate an interrupt at a specific time of day - * 3) Periodic Interrupt - generate periodic interrupt, with frequencies - * 2Hz-8192Hz (2Hz-64Hz for non-root user) (all freqs in powers of 2) - * (1) and (2) above are implemented using polling at a frequency of - * 64 Hz. The exact frequency is a tradeoff between accuracy and interrupt - * overhead. (DEFAULT_RTC_INT_FREQ) - * For (3), we use interrupts at 64Hz or user specified periodic - * frequency, whichever is higher. - */ -#include -#include - -#define DEFAULT_RTC_INT_FREQ 64 -#define RTC_NUM_INTS 1 - -static unsigned long UIE_on; -static unsigned long prev_update_sec; - -static unsigned long AIE_on; -static struct rtc_time alarm_time; - -static unsigned long PIE_on; -static unsigned long PIE_freq = DEFAULT_RTC_INT_FREQ; -static unsigned long PIE_count; - -static unsigned long hpet_rtc_int_freq; /* RTC interrupt frequency */ -static unsigned int hpet_t1_cmp; /* cached comparator register */ - -/* - * Timer 1 for RTC, we do not use periodic interrupt feature, - * even if HPET supports periodic interrupts on Timer 1. - * The reason being, to set up a periodic interrupt in HPET, we need to - * stop the main counter. And if we do that everytime someone diables/enables - * RTC, we will have adverse effect on main kernel timer running on Timer 0. - * So, for the time being, simulate the periodic interrupt in software. - * - * hpet_rtc_timer_init() is called for the first time and during subsequent - * interuppts reinit happens through hpet_rtc_timer_reinit(). - */ -int hpet_rtc_timer_init(void) -{ - unsigned int cfg, cnt; - unsigned long flags; - - if (!is_hpet_enabled()) - return 0; - /* - * Set the counter 1 and enable the interrupts. - */ - if (PIE_on && (PIE_freq > DEFAULT_RTC_INT_FREQ)) - hpet_rtc_int_freq = PIE_freq; - else - hpet_rtc_int_freq = DEFAULT_RTC_INT_FREQ; - - local_irq_save(flags); - - cnt = hpet_readl(HPET_COUNTER); - cnt += ((hpet_tick*HZ)/hpet_rtc_int_freq); - hpet_writel(cnt, HPET_T1_CMP); - hpet_t1_cmp = cnt; - - cfg = hpet_readl(HPET_T1_CFG); - cfg &= ~HPET_TN_PERIODIC; - cfg |= HPET_TN_ENABLE | HPET_TN_32BIT; - hpet_writel(cfg, HPET_T1_CFG); - - local_irq_restore(flags); - - return 1; -} - -static void hpet_rtc_timer_reinit(void) -{ - unsigned int cfg, cnt, ticks_per_int, lost_ints; - - if (unlikely(!(PIE_on | AIE_on | UIE_on))) { - cfg = hpet_readl(HPET_T1_CFG); - cfg &= ~HPET_TN_ENABLE; - hpet_writel(cfg, HPET_T1_CFG); - return; - } - - if (PIE_on && (PIE_freq > DEFAULT_RTC_INT_FREQ)) - hpet_rtc_int_freq = PIE_freq; - else - hpet_rtc_int_freq = DEFAULT_RTC_INT_FREQ; - - /* It is more accurate to use the comparator value than current count.*/ - ticks_per_int = hpet_tick * HZ / hpet_rtc_int_freq; - hpet_t1_cmp += ticks_per_int; - hpet_writel(hpet_t1_cmp, HPET_T1_CMP); - - /* - * If the interrupt handler was delayed too long, the write above tries - * to schedule the next interrupt in the past and the hardware would - * not interrupt until the counter had wrapped around. - * So we have to check that the comparator wasn't set to a past time. - */ - cnt = hpet_readl(HPET_COUNTER); - if (unlikely((int)(cnt - hpet_t1_cmp) > 0)) { - lost_ints = (cnt - hpet_t1_cmp) / ticks_per_int + 1; - /* Make sure that, even with the time needed to execute - * this code, the next scheduled interrupt has been moved - * back to the future: */ - lost_ints++; - - hpet_t1_cmp += lost_ints * ticks_per_int; - hpet_writel(hpet_t1_cmp, HPET_T1_CMP); - - if (PIE_on) - PIE_count += lost_ints; - - printk(KERN_WARNING "rtc: lost some interrupts at %ldHz.\n", - hpet_rtc_int_freq); - } -} - -/* - * The functions below are called from rtc driver. - * Return 0 if HPET is not being used. - * Otherwise do the necessary changes and return 1. - */ -int hpet_mask_rtc_irq_bit(unsigned long bit_mask) -{ - if (!is_hpet_enabled()) - return 0; - - if (bit_mask & RTC_UIE) - UIE_on = 0; - if (bit_mask & RTC_PIE) - PIE_on = 0; - if (bit_mask & RTC_AIE) - AIE_on = 0; - - return 1; -} - -int hpet_set_rtc_irq_bit(unsigned long bit_mask) -{ - int timer_init_reqd = 0; - - if (!is_hpet_enabled()) - return 0; - - if (!(PIE_on | AIE_on | UIE_on)) - timer_init_reqd = 1; - - if (bit_mask & RTC_UIE) { - UIE_on = 1; - } - if (bit_mask & RTC_PIE) { - PIE_on = 1; - PIE_count = 0; - } - if (bit_mask & RTC_AIE) { - AIE_on = 1; - } - - if (timer_init_reqd) - hpet_rtc_timer_init(); - - return 1; -} - -int hpet_set_alarm_time(unsigned char hrs, unsigned char min, unsigned char sec) -{ - if (!is_hpet_enabled()) - return 0; - - alarm_time.tm_hour = hrs; - alarm_time.tm_min = min; - alarm_time.tm_sec = sec; - - return 1; -} - -int hpet_set_periodic_freq(unsigned long freq) -{ - if (!is_hpet_enabled()) - return 0; - - PIE_freq = freq; - PIE_count = 0; - - return 1; -} - -int hpet_rtc_dropped_irq(void) -{ - if (!is_hpet_enabled()) - return 0; - - return 1; -} - -irqreturn_t hpet_rtc_interrupt(int irq, void *dev_id) -{ - struct rtc_time curr_time; - unsigned long rtc_int_flag = 0; - int call_rtc_interrupt = 0; - - hpet_rtc_timer_reinit(); - - if (UIE_on | AIE_on) { - rtc_get_rtc_time(&curr_time); - } - if (UIE_on) { - if (curr_time.tm_sec != prev_update_sec) { - /* Set update int info, call real rtc int routine */ - call_rtc_interrupt = 1; - rtc_int_flag = RTC_UF; - prev_update_sec = curr_time.tm_sec; - } - } - if (PIE_on) { - PIE_count++; - if (PIE_count >= hpet_rtc_int_freq/PIE_freq) { - /* Set periodic int info, call real rtc int routine */ - call_rtc_interrupt = 1; - rtc_int_flag |= RTC_PF; - PIE_count = 0; - } - } - if (AIE_on) { - if ((curr_time.tm_sec == alarm_time.tm_sec) && - (curr_time.tm_min == alarm_time.tm_min) && - (curr_time.tm_hour == alarm_time.tm_hour)) { - /* Set alarm int info, call real rtc int routine */ - call_rtc_interrupt = 1; - rtc_int_flag |= RTC_AF; - } - } - if (call_rtc_interrupt) { - rtc_int_flag |= (RTC_IRQF | (RTC_NUM_INTS << 8)); - rtc_interrupt(rtc_int_flag, dev_id); - } - return IRQ_HANDLED; -} -#endif - diff --git a/arch/i386/kernel/traps.c b/arch/i386/kernel/traps.c index 0efad8a..af0d3f7 100644 --- a/arch/i386/kernel/traps.c +++ b/arch/i386/kernel/traps.c @@ -94,6 +94,7 @@ asmlinkage void spurious_interrupt_bug(v asmlinkage void machine_check(void); int kstack_depth_to_print = 24; +static unsigned int code_bytes = 64; ATOMIC_NOTIFIER_HEAD(i386die_chain); int register_die_notifier(struct notifier_block *nb) @@ -291,10 +292,11 @@ void show_registers(struct pt_regs *regs int i; int in_kernel = 1; unsigned long esp; - unsigned short ss; + unsigned short ss, gs; esp = (unsigned long) (®s->esp); savesegment(ss, ss); + savesegment(gs, gs); if (user_mode_vm(regs)) { in_kernel = 0; esp = regs->esp; @@ -313,8 +315,8 @@ void show_registers(struct pt_regs *regs regs->eax, regs->ebx, regs->ecx, regs->edx); printk(KERN_EMERG "esi: %08lx edi: %08lx ebp: %08lx esp: %08lx\n", regs->esi, regs->edi, regs->ebp, esp); - printk(KERN_EMERG "ds: %04x es: %04x ss: %04x\n", - regs->xds & 0xffff, regs->xes & 0xffff, ss); + printk(KERN_EMERG "ds: %04x es: %04x fs: %04x gs: %04x ss: %04x\n", + regs->xds & 0xffff, regs->xes & 0xffff, regs->xfs & 0xffff, gs, ss); printk(KERN_EMERG "Process %.*s (pid: %d, ti=%p task=%p task.ti=%p)", TASK_COMM_LEN, current->comm, current->pid, current_thread_info(), current, current->thread_info); @@ -324,7 +326,8 @@ void show_registers(struct pt_regs *regs */ if (in_kernel) { u8 *eip; - int code_bytes = 64; + unsigned int code_prologue = code_bytes * 43 / 64; + unsigned int code_len = code_bytes; unsigned char c; printk("\n" KERN_EMERG "Stack: "); @@ -332,14 +335,14 @@ void show_registers(struct pt_regs *regs printk(KERN_EMERG "Code: "); - eip = (u8 *)regs->eip - 43; + eip = (u8 *)regs->eip - code_prologue; if (eip < (u8 *)PAGE_OFFSET || probe_kernel_address(eip, c)) { /* try starting at EIP */ eip = (u8 *)regs->eip; - code_bytes = 32; + code_len = code_len - code_prologue + 1; } - for (i = 0; i < code_bytes; i++, eip++) { + for (i = 0; i < code_len; i++, eip++) { if (eip < (u8 *)PAGE_OFFSET || probe_kernel_address(eip, c)) { printk(" Bad EIP value."); @@ -1191,3 +1194,13 @@ static int __init kstack_setup(char *s) return 1; } __setup("kstack=", kstack_setup); + +static int __init code_bytes_setup(char *s) +{ + code_bytes = simple_strtoul(s, NULL, 0); + if (code_bytes > 8192) + code_bytes = 8192; + + return 1; +} +__setup("code_bytes=", code_bytes_setup); diff --git a/arch/i386/kernel/tsc.c b/arch/i386/kernel/tsc.c index 2cfc7b0..3082a41 100644 --- a/arch/i386/kernel/tsc.c +++ b/arch/i386/kernel/tsc.c @@ -23,6 +23,7 @@ #include "mach_timer.h" * an extra value to store the TSC freq */ unsigned int tsc_khz; +unsigned long long (*custom_sched_clock)(void); int tsc_disable; @@ -59,12 +60,6 @@ static inline int check_tsc_unstable(voi return tsc_unstable; } -void mark_tsc_unstable(void) -{ - tsc_unstable = 1; -} -EXPORT_SYMBOL_GPL(mark_tsc_unstable); - /* Accellerators for sched_clock() * convert from cycles(64bits) => nanoseconds (64bits) * basic equation: @@ -107,14 +102,14 @@ unsigned long long sched_clock(void) { unsigned long long this_offset; + if (unlikely(custom_sched_clock)) + return (*custom_sched_clock)(); + /* - * in the NUMA case we dont use the TSC as they are not - * synchronized across all CPUs. + * Fall back to jiffies if there's no TSC available: */ -#ifndef CONFIG_NUMA - if (!cpu_khz || check_tsc_unstable()) -#endif - /* no locking but a rare wrong value is not a big deal */ + if (unlikely(tsc_disable)) + /* No locking but a rare wrong value is not a big deal: */ return (jiffies_64 - INITIAL_JIFFIES) * (1000000000 / HZ); /* read the Time Stamp Counter: */ @@ -194,13 +189,13 @@ EXPORT_SYMBOL(recalibrate_cpu_khz); void __init tsc_init(void) { if (!cpu_has_tsc || tsc_disable) - return; + goto out_no_tsc; cpu_khz = calculate_cpu_khz(); tsc_khz = cpu_khz; if (!cpu_khz) - return; + goto out_no_tsc; printk("Detected %lu.%03lu MHz processor.\n", (unsigned long)cpu_khz / 1000, @@ -208,37 +203,18 @@ void __init tsc_init(void) set_cyc2ns_scale(cpu_khz); use_tsc_delay(); -} + return; -#ifdef CONFIG_CPU_FREQ - -static unsigned int cpufreq_delayed_issched = 0; -static unsigned int cpufreq_init = 0; -static struct work_struct cpufreq_delayed_get_work; - -static void handle_cpufreq_delayed_get(struct work_struct *work) -{ - unsigned int cpu; - - for_each_online_cpu(cpu) - cpufreq_get(cpu); - - cpufreq_delayed_issched = 0; +out_no_tsc: + /* + * Set the tsc_disable flag if there's no TSC support, this + * makes it a fast flag for the kernel to see whether it + * should be using the TSC. + */ + tsc_disable = 1; } -/* - * if we notice cpufreq oddness, schedule a call to cpufreq_get() as it tries - * to verify the CPU frequency the timing core thinks the CPU is running - * at is still correct. - */ -static inline void cpufreq_delayed_get(void) -{ - if (cpufreq_init && !cpufreq_delayed_issched) { - cpufreq_delayed_issched = 1; - printk(KERN_DEBUG "Checking if CPU frequency changed.\n"); - schedule_work(&cpufreq_delayed_get_work); - } -} +#ifdef CONFIG_CPU_FREQ /* * if the CPU frequency is scaled, TSC-based delays will need a different @@ -303,17 +279,9 @@ static struct notifier_block time_cpufre static int __init cpufreq_tsc(void) { - int ret; - - INIT_WORK(&cpufreq_delayed_get_work, handle_cpufreq_delayed_get); - ret = cpufreq_register_notifier(&time_cpufreq_notifier_block, - CPUFREQ_TRANSITION_NOTIFIER); - if (!ret) - cpufreq_init = 1; - - return ret; + return cpufreq_register_notifier(&time_cpufreq_notifier_block, + CPUFREQ_TRANSITION_NOTIFIER); } - core_initcall(cpufreq_tsc); #endif @@ -321,7 +289,6 @@ #endif /* clock source code */ static unsigned long current_tsc_khz = 0; -static int tsc_update_callback(void); static cycle_t read_tsc(void) { @@ -339,37 +306,28 @@ static struct clocksource clocksource_ts .mask = CLOCKSOURCE_MASK(64), .mult = 0, /* to be set */ .shift = 22, - .update_callback = tsc_update_callback, - .is_continuous = 1, + .flags = CLOCK_SOURCE_IS_CONTINUOUS | + CLOCK_SOURCE_MUST_VERIFY, }; -static int tsc_update_callback(void) +void mark_tsc_unstable(void) { - int change = 0; - - /* check to see if we should switch to the safe clocksource: */ - if (clocksource_tsc.rating != 0 && check_tsc_unstable()) { - clocksource_tsc.rating = 0; - clocksource_reselect(); - change = 1; - } - - /* only update if tsc_khz has changed: */ - if (current_tsc_khz != tsc_khz) { - current_tsc_khz = tsc_khz; - clocksource_tsc.mult = clocksource_khz2mult(current_tsc_khz, - clocksource_tsc.shift); - change = 1; + if (!tsc_unstable) { + tsc_unstable = 1; + /* Can be called before registration */ + if (clocksource_tsc.mult) + clocksource_change_rating(&clocksource_tsc, 0); + else + clocksource_tsc.rating = 0; } - - return change; } +EXPORT_SYMBOL_GPL(mark_tsc_unstable); static int __init dmi_mark_tsc_unstable(struct dmi_system_id *d) { printk(KERN_NOTICE "%s detected: marking TSC unstable.\n", d->ident); - mark_tsc_unstable(); + tsc_unstable = 1; return 0; } @@ -386,65 +344,44 @@ static struct dmi_system_id __initdata b {} }; -#define TSC_FREQ_CHECK_INTERVAL (10*MSEC_PER_SEC) /* 10sec in MS */ -static struct timer_list verify_tsc_freq_timer; - -/* XXX - Probably should add locking */ -static void verify_tsc_freq(unsigned long unused) -{ - static u64 last_tsc; - static unsigned long last_jiffies; - - u64 now_tsc, interval_tsc; - unsigned long now_jiffies, interval_jiffies; - - - if (check_tsc_unstable()) - return; - - rdtscll(now_tsc); - now_jiffies = jiffies; - - if (!last_jiffies) { - goto out; - } - - interval_jiffies = now_jiffies - last_jiffies; - interval_tsc = now_tsc - last_tsc; - interval_tsc *= HZ; - do_div(interval_tsc, cpu_khz*1000); - - if (interval_tsc < (interval_jiffies * 3 / 4)) { - printk("TSC appears to be running slowly. " - "Marking it as unstable\n"); - mark_tsc_unstable(); - return; - } - -out: - last_tsc = now_tsc; - last_jiffies = now_jiffies; - /* set us up to go off on the next interval: */ - mod_timer(&verify_tsc_freq_timer, - jiffies + msecs_to_jiffies(TSC_FREQ_CHECK_INTERVAL)); -} - /* * Make an educated guess if the TSC is trustworthy and synchronized * over all CPUs. */ -static __init int unsynchronized_tsc(void) +__cpuinit int unsynchronized_tsc(void) { + if (!cpu_has_tsc || tsc_unstable) + return 1; /* * Intel systems are normally all synchronized. * Exceptions must mark TSC as unstable: */ - if (boot_cpu_data.x86_vendor == X86_VENDOR_INTEL) - return 0; + if (boot_cpu_data.x86_vendor != X86_VENDOR_INTEL) { + /* assume multi socket systems are not synchronized: */ + if (num_possible_cpus() > 1) + tsc_unstable = 1; + } + return tsc_unstable; +} + +/* + * Geode_LX - the OLPC CPU has a possibly a very reliable TSC + */ +#ifdef CONFIG_MGEODE_LX +/* RTSC counts during suspend */ +#define RTSC_SUSP 0x100 + +static void __init check_geode_tsc_reliable(void) +{ + unsigned long val; - /* assume multi socket systems are not synchronized: */ - return num_possible_cpus() > 1; + rdmsrl(MSR_GEODE_BUSCONT_CONF0, val); + if ((val & RTSC_SUSP)) + clocksource_tsc.flags &= ~CLOCK_SOURCE_MUST_VERIFY; } +#else +static inline void check_geode_tsc_reliable(void) { } +#endif static int __init init_tsc_clocksource(void) { @@ -453,20 +390,16 @@ static int __init init_tsc_clocksource(v /* check blacklist */ dmi_check_system(bad_tsc_dmi_table); - if (unsynchronized_tsc()) /* mark unstable if unsynced */ - mark_tsc_unstable(); + unsynchronized_tsc(); + check_geode_tsc_reliable(); current_tsc_khz = tsc_khz; clocksource_tsc.mult = clocksource_khz2mult(current_tsc_khz, clocksource_tsc.shift); /* lower the rating if we already know its unstable: */ - if (check_tsc_unstable()) + if (check_tsc_unstable()) { clocksource_tsc.rating = 0; - - init_timer(&verify_tsc_freq_timer); - verify_tsc_freq_timer.function = verify_tsc_freq; - verify_tsc_freq_timer.expires = - jiffies + msecs_to_jiffies(TSC_FREQ_CHECK_INTERVAL); - add_timer(&verify_tsc_freq_timer); + clocksource_tsc.flags &= ~CLOCK_SOURCE_IS_CONTINUOUS; + } return clocksource_register(&clocksource_tsc); } diff --git a/arch/i386/kernel/tsc_sync.c b/arch/i386/kernel/tsc_sync.c new file mode 100644 index 0000000..1242462 --- /dev/null +++ b/arch/i386/kernel/tsc_sync.c @@ -0,0 +1 @@ +#include "../../x86_64/kernel/tsc_sync.c" diff --git a/arch/i386/kernel/vm86.c b/arch/i386/kernel/vm86.c index be2f96e..d1b8f2b 100644 --- a/arch/i386/kernel/vm86.c +++ b/arch/i386/kernel/vm86.c @@ -96,12 +96,12 @@ static int copy_vm86_regs_to_user(struct { int ret = 0; - /* kernel_vm86_regs is missing xfs, so copy everything up to - (but not including) xgs, and then rest after xgs. */ - ret += copy_to_user(user, regs, offsetof(struct kernel_vm86_regs, pt.xgs)); - ret += copy_to_user(&user->__null_gs, ®s->pt.xgs, + /* kernel_vm86_regs is missing xgs, so copy everything up to + (but not including) orig_eax, and then rest including orig_eax. */ + ret += copy_to_user(user, regs, offsetof(struct kernel_vm86_regs, pt.orig_eax)); + ret += copy_to_user(&user->orig_eax, ®s->pt.orig_eax, sizeof(struct kernel_vm86_regs) - - offsetof(struct kernel_vm86_regs, pt.xgs)); + offsetof(struct kernel_vm86_regs, pt.orig_eax)); return ret; } @@ -113,12 +113,13 @@ static int copy_vm86_regs_from_user(stru { int ret = 0; - ret += copy_from_user(regs, user, offsetof(struct kernel_vm86_regs, pt.xgs)); - ret += copy_from_user(®s->pt.xgs, &user->__null_gs, + /* copy eax-xfs inclusive */ + ret += copy_from_user(regs, user, offsetof(struct kernel_vm86_regs, pt.orig_eax)); + /* copy orig_eax-__gsh+extra */ + ret += copy_from_user(®s->pt.orig_eax, &user->orig_eax, sizeof(struct kernel_vm86_regs) - - offsetof(struct kernel_vm86_regs, pt.xgs) + + offsetof(struct kernel_vm86_regs, pt.orig_eax) + extra); - return ret; } @@ -157,8 +158,8 @@ struct pt_regs * fastcall save_v86_state ret = KVM86->regs32; - loadsegment(fs, current->thread.saved_fs); - ret->xgs = current->thread.saved_gs; + ret->xfs = current->thread.saved_fs; + loadsegment(gs, current->thread.saved_gs); return ret; } @@ -285,9 +286,9 @@ static void do_sys_vm86(struct kernel_vm */ info->regs.pt.xds = 0; info->regs.pt.xes = 0; - info->regs.pt.xgs = 0; + info->regs.pt.xfs = 0; -/* we are clearing fs later just before "jmp resume_userspace", +/* we are clearing gs later just before "jmp resume_userspace", * because it is not saved/restored. */ @@ -321,8 +322,8 @@ static void do_sys_vm86(struct kernel_vm */ info->regs32->eax = 0; tsk->thread.saved_esp0 = tsk->thread.esp0; - savesegment(fs, tsk->thread.saved_fs); - tsk->thread.saved_gs = info->regs32->xgs; + tsk->thread.saved_fs = info->regs32->xfs; + savesegment(gs, tsk->thread.saved_gs); tss = &per_cpu(init_tss, get_cpu()); tsk->thread.esp0 = (unsigned long) &info->VM86_TSS_ESP0; @@ -342,7 +343,7 @@ static void do_sys_vm86(struct kernel_vm __asm__ __volatile__( "movl %0,%%esp\n\t" "movl %1,%%ebp\n\t" - "mov %2, %%fs\n\t" + "mov %2, %%gs\n\t" "jmp resume_userspace" : /* no outputs */ :"r" (&info->regs), "r" (task_thread_info(tsk)), "r" (0)); diff --git a/arch/i386/kernel/vmi.c b/arch/i386/kernel/vmi.c new file mode 100644 index 0000000..bb5a7ab --- /dev/null +++ b/arch/i386/kernel/vmi.c @@ -0,0 +1,949 @@ +/* + * VMI specific paravirt-ops implementation + * + * Copyright (C) 2005, VMware, 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. + * + * 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, GOOD TITLE or + * NON INFRINGEMENT. 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., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * Send feedback to zach@vmware.com + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* Convenient for calling VMI functions indirectly in the ROM */ +typedef u32 __attribute__((regparm(1))) (VROMFUNC)(void); +typedef u64 __attribute__((regparm(2))) (VROMLONGFUNC)(int); + +#define call_vrom_func(rom,func) \ + (((VROMFUNC *)(rom->func))()) + +#define call_vrom_long_func(rom,func,arg) \ + (((VROMLONGFUNC *)(rom->func)) (arg)) + +static struct vrom_header *vmi_rom; +static int license_gplok; +static int disable_nodelay; +static int disable_pge; +static int disable_pse; +static int disable_sep; +static int disable_tsc; +static int disable_mtrr; + +/* Cached VMI operations */ +struct { + void (*cpuid)(void /* non-c */); + void (*_set_ldt)(u32 selector); + void (*set_tr)(u32 selector); + void (*set_kernel_stack)(u32 selector, u32 esp0); + void (*allocate_page)(u32, u32, u32, u32, u32); + void (*release_page)(u32, u32); + void (*set_pte)(pte_t, pte_t *, unsigned); + void (*update_pte)(pte_t *, unsigned); + void (*set_linear_mapping)(int, u32, u32, u32); + void (*flush_tlb)(int); + void (*set_initial_ap_state)(int, int); + void (*halt)(void); +} vmi_ops; + +/* XXX move this to alternative.h */ +extern struct paravirt_patch __start_parainstructions[], + __stop_parainstructions[]; + +/* + * VMI patching routines. + */ +#define MNEM_CALL 0xe8 +#define MNEM_JMP 0xe9 +#define MNEM_RET 0xc3 + +static char irq_save_disable_callout[] = { + MNEM_CALL, 0, 0, 0, 0, + MNEM_CALL, 0, 0, 0, 0, + MNEM_RET +}; +#define IRQ_PATCH_INT_MASK 0 +#define IRQ_PATCH_DISABLE 5 + +static inline void patch_offset(unsigned char *eip, unsigned char *dest) +{ + *(unsigned long *)(eip+1) = dest-eip-5; +} + +static unsigned patch_internal(int call, unsigned len, void *insns) +{ + u64 reloc; + struct vmi_relocation_info *const rel = (struct vmi_relocation_info *)&reloc; + reloc = call_vrom_long_func(vmi_rom, get_reloc, call); + switch(rel->type) { + case VMI_RELOCATION_CALL_REL: + BUG_ON(len < 5); + *(char *)insns = MNEM_CALL; + patch_offset(insns, rel->eip); + return 5; + + case VMI_RELOCATION_JUMP_REL: + BUG_ON(len < 5); + *(char *)insns = MNEM_JMP; + patch_offset(insns, rel->eip); + return 5; + + case VMI_RELOCATION_NOP: + /* obliterate the whole thing */ + return 0; + + case VMI_RELOCATION_NONE: + /* leave native code in place */ + break; + + default: + BUG(); + } + return len; +} + +/* + * Apply patch if appropriate, return length of new instruction + * sequence. The callee does nop padding for us. + */ +static unsigned vmi_patch(u8 type, u16 clobbers, void *insns, unsigned len) +{ + switch (type) { + case PARAVIRT_IRQ_DISABLE: + return patch_internal(VMI_CALL_DisableInterrupts, len, insns); + case PARAVIRT_IRQ_ENABLE: + return patch_internal(VMI_CALL_EnableInterrupts, len, insns); + case PARAVIRT_RESTORE_FLAGS: + return patch_internal(VMI_CALL_SetInterruptMask, len, insns); + case PARAVIRT_SAVE_FLAGS: + return patch_internal(VMI_CALL_GetInterruptMask, len, insns); + case PARAVIRT_SAVE_FLAGS_IRQ_DISABLE: + if (len >= 10) { + patch_internal(VMI_CALL_GetInterruptMask, len, insns); + patch_internal(VMI_CALL_DisableInterrupts, len-5, insns+5); + return 10; + } else { + /* + * You bastards didn't leave enough room to + * patch save_flags_irq_disable inline. Patch + * to a helper + */ + BUG_ON(len < 5); + *(char *)insns = MNEM_CALL; + patch_offset(insns, irq_save_disable_callout); + return 5; + } + case PARAVIRT_INTERRUPT_RETURN: + return patch_internal(VMI_CALL_IRET, len, insns); + case PARAVIRT_STI_SYSEXIT: + return patch_internal(VMI_CALL_SYSEXIT, len, insns); + default: + break; + } + return len; +} + +/* CPUID has non-C semantics, and paravirt-ops API doesn't match hardware ISA */ +static void vmi_cpuid(unsigned int *eax, unsigned int *ebx, + unsigned int *ecx, unsigned int *edx) +{ + int override = 0; + if (*eax == 1) + override = 1; + asm volatile ("call *%6" + : "=a" (*eax), + "=b" (*ebx), + "=c" (*ecx), + "=d" (*edx) + : "0" (*eax), "2" (*ecx), "r" (vmi_ops.cpuid)); + if (override) { + if (disable_pse) + *edx &= ~X86_FEATURE_PSE; + if (disable_pge) + *edx &= ~X86_FEATURE_PGE; + if (disable_sep) + *edx &= ~X86_FEATURE_SEP; + if (disable_tsc) + *edx &= ~X86_FEATURE_TSC; + if (disable_mtrr) + *edx &= ~X86_FEATURE_MTRR; + } +} + +static inline void vmi_maybe_load_tls(struct desc_struct *gdt, int nr, struct desc_struct *new) +{ + if (gdt[nr].a != new->a || gdt[nr].b != new->b) + write_gdt_entry(gdt, nr, new->a, new->b); +} + +static void vmi_load_tls(struct thread_struct *t, unsigned int cpu) +{ + struct desc_struct *gdt = get_cpu_gdt_table(cpu); + vmi_maybe_load_tls(gdt, GDT_ENTRY_TLS_MIN + 0, &t->tls_array[0]); + vmi_maybe_load_tls(gdt, GDT_ENTRY_TLS_MIN + 1, &t->tls_array[1]); + vmi_maybe_load_tls(gdt, GDT_ENTRY_TLS_MIN + 2, &t->tls_array[2]); +} + +static void vmi_set_ldt(const void *addr, unsigned entries) +{ + unsigned cpu = smp_processor_id(); + u32 low, high; + + pack_descriptor(&low, &high, (unsigned long)addr, + entries * sizeof(struct desc_struct) - 1, + DESCTYPE_LDT, 0); + write_gdt_entry(get_cpu_gdt_table(cpu), GDT_ENTRY_LDT, low, high); + vmi_ops._set_ldt(entries ? GDT_ENTRY_LDT*sizeof(struct desc_struct) : 0); +} + +static void vmi_set_tr(void) +{ + vmi_ops.set_tr(GDT_ENTRY_TSS*sizeof(struct desc_struct)); +} + +static void vmi_load_esp0(struct tss_struct *tss, + struct thread_struct *thread) +{ + tss->esp0 = thread->esp0; + + /* This can only happen when SEP is enabled, no need to test "SEP"arately */ + if (unlikely(tss->ss1 != thread->sysenter_cs)) { + tss->ss1 = thread->sysenter_cs; + wrmsr(MSR_IA32_SYSENTER_CS, thread->sysenter_cs, 0); + } + vmi_ops.set_kernel_stack(__KERNEL_DS, tss->esp0); +} + +static void vmi_flush_tlb_user(void) +{ + vmi_ops.flush_tlb(VMI_FLUSH_TLB); +} + +static void vmi_flush_tlb_kernel(void) +{ + vmi_ops.flush_tlb(VMI_FLUSH_TLB | VMI_FLUSH_GLOBAL); +} + +/* Stub to do nothing at all; used for delays and unimplemented calls */ +static void vmi_nop(void) +{ +} + +/* For NO_IDLE_HZ, we stop the clock when halting the kernel */ +#ifdef CONFIG_NO_IDLE_HZ +static fastcall void vmi_safe_halt(void) +{ + int idle = vmi_stop_hz_timer(); + vmi_ops.halt(); + if (idle) { + local_irq_disable(); + vmi_account_time_restart_hz_timer(); + local_irq_enable(); + } +} +#endif + +#ifdef CONFIG_DEBUG_PAGE_TYPE + +#ifdef CONFIG_X86_PAE +#define MAX_BOOT_PTS (2048+4+1) +#else +#define MAX_BOOT_PTS (1024+1) +#endif + +/* + * During boot, mem_map is not yet available in paging_init, so stash + * all the boot page allocations here. + */ +static struct { + u32 pfn; + int type; +} boot_page_allocations[MAX_BOOT_PTS]; +static int num_boot_page_allocations; +static int boot_allocations_applied; + +void vmi_apply_boot_page_allocations(void) +{ + int i; + BUG_ON(!mem_map); + for (i = 0; i < num_boot_page_allocations; i++) { + struct page *page = pfn_to_page(boot_page_allocations[i].pfn); + page->type = boot_page_allocations[i].type; + page->type = boot_page_allocations[i].type & + ~(VMI_PAGE_ZEROED | VMI_PAGE_CLONE); + } + boot_allocations_applied = 1; +} + +static void record_page_type(u32 pfn, int type) +{ + BUG_ON(num_boot_page_allocations >= MAX_BOOT_PTS); + boot_page_allocations[num_boot_page_allocations].pfn = pfn; + boot_page_allocations[num_boot_page_allocations].type = type; + num_boot_page_allocations++; +} + +static void check_zeroed_page(u32 pfn, int type, struct page *page) +{ + u32 *ptr; + int i; + int limit = PAGE_SIZE / sizeof(int); + + if (page_address(page)) + ptr = (u32 *)page_address(page); + else + ptr = (u32 *)__va(pfn << PAGE_SHIFT); + /* + * When cloning the root in non-PAE mode, only the userspace + * pdes need to be zeroed. + */ + if (type & VMI_PAGE_CLONE) + limit = USER_PTRS_PER_PGD; + for (i = 0; i < limit; i++) + BUG_ON(ptr[i]); +} + +/* + * We stash the page type into struct page so we can verify the page + * types are used properly. + */ +static void vmi_set_page_type(u32 pfn, int type) +{ + /* PAE can have multiple roots per page - don't track */ + if (PTRS_PER_PMD > 1 && (type & VMI_PAGE_PDP)) + return; + + if (boot_allocations_applied) { + struct page *page = pfn_to_page(pfn); + if (type != VMI_PAGE_NORMAL) + BUG_ON(page->type); + else + BUG_ON(page->type == VMI_PAGE_NORMAL); + page->type = type & ~(VMI_PAGE_ZEROED | VMI_PAGE_CLONE); + if (type & VMI_PAGE_ZEROED) + check_zeroed_page(pfn, type, page); + } else { + record_page_type(pfn, type); + } +} + +static void vmi_check_page_type(u32 pfn, int type) +{ + /* PAE can have multiple roots per page - skip checks */ + if (PTRS_PER_PMD > 1 && (type & VMI_PAGE_PDP)) + return; + + type &= ~(VMI_PAGE_ZEROED | VMI_PAGE_CLONE); + if (boot_allocations_applied) { + struct page *page = pfn_to_page(pfn); + BUG_ON((page->type ^ type) & VMI_PAGE_PAE); + BUG_ON(type == VMI_PAGE_NORMAL && page->type); + BUG_ON((type & page->type) == 0); + } +} +#else +#define vmi_set_page_type(p,t) do { } while (0) +#define vmi_check_page_type(p,t) do { } while (0) +#endif + +static void vmi_allocate_pt(u32 pfn) +{ + vmi_set_page_type(pfn, VMI_PAGE_L1); + vmi_ops.allocate_page(pfn, VMI_PAGE_L1, 0, 0, 0); +} + +static void vmi_allocate_pd(u32 pfn) +{ + /* + * This call comes in very early, before mem_map is setup. + * It is called only for swapper_pg_dir, which already has + * data on it. + */ + vmi_set_page_type(pfn, VMI_PAGE_L2); + vmi_ops.allocate_page(pfn, VMI_PAGE_L2, 0, 0, 0); +} + +static void vmi_allocate_pd_clone(u32 pfn, u32 clonepfn, u32 start, u32 count) +{ + vmi_set_page_type(pfn, VMI_PAGE_L2 | VMI_PAGE_CLONE); + vmi_check_page_type(clonepfn, VMI_PAGE_L2); + vmi_ops.allocate_page(pfn, VMI_PAGE_L2 | VMI_PAGE_CLONE, clonepfn, start, count); +} + +static void vmi_release_pt(u32 pfn) +{ + vmi_ops.release_page(pfn, VMI_PAGE_L1); + vmi_set_page_type(pfn, VMI_PAGE_NORMAL); +} + +static void vmi_release_pd(u32 pfn) +{ + vmi_ops.release_page(pfn, VMI_PAGE_L2); + vmi_set_page_type(pfn, VMI_PAGE_NORMAL); +} + +/* + * Helper macros for MMU update flags. We can defer updates until a flush + * or page invalidation only if the update is to the current address space + * (otherwise, there is no flush). We must check against init_mm, since + * this could be a kernel update, which usually passes init_mm, although + * sometimes this check can be skipped if we know the particular function + * is only called on user mode PTEs. We could change the kernel to pass + * current->active_mm here, but in particular, I was unsure if changing + * mm/highmem.c to do this would still be correct on other architectures. + */ +#define is_current_as(mm, mustbeuser) ((mm) == current->active_mm || \ + (!mustbeuser && (mm) == &init_mm)) +#define vmi_flags_addr(mm, addr, level, user) \ + ((level) | (is_current_as(mm, user) ? \ + (VMI_PAGE_CURRENT_AS | ((addr) & VMI_PAGE_VA_MASK)) : 0)) +#define vmi_flags_addr_defer(mm, addr, level, user) \ + ((level) | (is_current_as(mm, user) ? \ + (VMI_PAGE_DEFER | VMI_PAGE_CURRENT_AS | ((addr) & VMI_PAGE_VA_MASK)) : 0)) + +static void vmi_update_pte(struct mm_struct *mm, u32 addr, pte_t *ptep) +{ + vmi_check_page_type(__pa(ptep) >> PAGE_SHIFT, VMI_PAGE_PTE); + vmi_ops.update_pte(ptep, vmi_flags_addr(mm, addr, VMI_PAGE_PT, 0)); +} + +static void vmi_update_pte_defer(struct mm_struct *mm, u32 addr, pte_t *ptep) +{ + vmi_check_page_type(__pa(ptep) >> PAGE_SHIFT, VMI_PAGE_PTE); + vmi_ops.update_pte(ptep, vmi_flags_addr_defer(mm, addr, VMI_PAGE_PT, 0)); +} + +static void vmi_set_pte(pte_t *ptep, pte_t pte) +{ + /* XXX because of set_pmd_pte, this can be called on PT or PD layers */ + vmi_check_page_type(__pa(ptep) >> PAGE_SHIFT, VMI_PAGE_PTE | VMI_PAGE_PD); + vmi_ops.set_pte(pte, ptep, VMI_PAGE_PT); +} + +static void vmi_set_pte_at(struct mm_struct *mm, u32 addr, pte_t *ptep, pte_t pte) +{ + vmi_check_page_type(__pa(ptep) >> PAGE_SHIFT, VMI_PAGE_PTE); + vmi_ops.set_pte(pte, ptep, vmi_flags_addr(mm, addr, VMI_PAGE_PT, 0)); +} + +static void vmi_set_pmd(pmd_t *pmdp, pmd_t pmdval) +{ +#ifdef CONFIG_X86_PAE + const pte_t pte = { pmdval.pmd, pmdval.pmd >> 32 }; + vmi_check_page_type(__pa(pmdp) >> PAGE_SHIFT, VMI_PAGE_PMD); +#else + const pte_t pte = { pmdval.pud.pgd.pgd }; + vmi_check_page_type(__pa(pmdp) >> PAGE_SHIFT, VMI_PAGE_PGD); +#endif + vmi_ops.set_pte(pte, (pte_t *)pmdp, VMI_PAGE_PD); +} + +#ifdef CONFIG_X86_PAE + +static void vmi_set_pte_atomic(pte_t *ptep, pte_t pteval) +{ + /* + * XXX This is called from set_pmd_pte, but at both PT + * and PD layers so the VMI_PAGE_PT flag is wrong. But + * it is only called for large page mapping changes, + * the Xen backend, doesn't support large pages, and the + * ESX backend doesn't depend on the flag. + */ + set_64bit((unsigned long long *)ptep,pte_val(pteval)); + vmi_ops.update_pte(ptep, VMI_PAGE_PT); +} + +static void vmi_set_pte_present(struct mm_struct *mm, unsigned long addr, pte_t *ptep, pte_t pte) +{ + vmi_check_page_type(__pa(ptep) >> PAGE_SHIFT, VMI_PAGE_PTE); + vmi_ops.set_pte(pte, ptep, vmi_flags_addr_defer(mm, addr, VMI_PAGE_PT, 1)); +} + +static void vmi_set_pud(pud_t *pudp, pud_t pudval) +{ + /* Um, eww */ + const pte_t pte = { pudval.pgd.pgd, pudval.pgd.pgd >> 32 }; + vmi_check_page_type(__pa(pudp) >> PAGE_SHIFT, VMI_PAGE_PGD); + vmi_ops.set_pte(pte, (pte_t *)pudp, VMI_PAGE_PDP); +} + +static void vmi_pte_clear(struct mm_struct *mm, unsigned long addr, pte_t *ptep) +{ + const pte_t pte = { 0 }; + vmi_check_page_type(__pa(ptep) >> PAGE_SHIFT, VMI_PAGE_PTE); + vmi_ops.set_pte(pte, ptep, vmi_flags_addr(mm, addr, VMI_PAGE_PT, 0)); +} + +void vmi_pmd_clear(pmd_t *pmd) +{ + const pte_t pte = { 0 }; + vmi_check_page_type(__pa(pmd) >> PAGE_SHIFT, VMI_PAGE_PMD); + vmi_ops.set_pte(pte, (pte_t *)pmd, VMI_PAGE_PD); +} +#endif + +#ifdef CONFIG_SMP +struct vmi_ap_state ap; +extern void setup_pda(void); + +static void __init /* XXX cpu hotplug */ +vmi_startup_ipi_hook(int phys_apicid, unsigned long start_eip, + unsigned long start_esp) +{ + /* Default everything to zero. This is fine for most GPRs. */ + memset(&ap, 0, sizeof(struct vmi_ap_state)); + + ap.gdtr_limit = GDT_SIZE - 1; + ap.gdtr_base = (unsigned long) get_cpu_gdt_table(phys_apicid); + + ap.idtr_limit = IDT_ENTRIES * 8 - 1; + ap.idtr_base = (unsigned long) idt_table; + + ap.ldtr = 0; + + ap.cs = __KERNEL_CS; + ap.eip = (unsigned long) start_eip; + ap.ss = __KERNEL_DS; + ap.esp = (unsigned long) start_esp; + + ap.ds = __USER_DS; + ap.es = __USER_DS; + ap.fs = __KERNEL_PDA; + ap.gs = 0; + + ap.eflags = 0; + + setup_pda(); + +#ifdef CONFIG_X86_PAE + /* efer should match BSP efer. */ + if (cpu_has_nx) { + unsigned l, h; + rdmsr(MSR_EFER, l, h); + ap.efer = (unsigned long long) h << 32 | l; + } +#endif + + ap.cr3 = __pa(swapper_pg_dir); + /* Protected mode, paging, AM, WP, NE, MP. */ + ap.cr0 = 0x80050023; + ap.cr4 = mmu_cr4_features; + vmi_ops.set_initial_ap_state(__pa(&ap), phys_apicid); +} +#endif + +static inline int __init check_vmi_rom(struct vrom_header *rom) +{ + struct pci_header *pci; + struct pnp_header *pnp; + const char *manufacturer = "UNKNOWN"; + const char *product = "UNKNOWN"; + const char *license = "unspecified"; + + if (rom->rom_signature != 0xaa55) + return 0; + if (rom->vrom_signature != VMI_SIGNATURE) + return 0; + if (rom->api_version_maj != VMI_API_REV_MAJOR || + rom->api_version_min+1 < VMI_API_REV_MINOR+1) { + printk(KERN_WARNING "VMI: Found mismatched rom version %d.%d\n", + rom->api_version_maj, + rom->api_version_min); + return 0; + } + + /* + * Relying on the VMI_SIGNATURE field is not 100% safe, so check + * the PCI header and device type to make sure this is really a + * VMI device. + */ + if (!rom->pci_header_offs) { + printk(KERN_WARNING "VMI: ROM does not contain PCI header.\n"); + return 0; + } + + pci = (struct pci_header *)((char *)rom+rom->pci_header_offs); + if (pci->vendorID != PCI_VENDOR_ID_VMWARE || + pci->deviceID != PCI_DEVICE_ID_VMWARE_VMI) { + /* Allow it to run... anyways, but warn */ + printk(KERN_WARNING "VMI: ROM from unknown manufacturer\n"); + } + + if (rom->pnp_header_offs) { + pnp = (struct pnp_header *)((char *)rom+rom->pnp_header_offs); + if (pnp->manufacturer_offset) + manufacturer = (const char *)rom+pnp->manufacturer_offset; + if (pnp->product_offset) + product = (const char *)rom+pnp->product_offset; + } + + if (rom->license_offs) + license = (char *)rom+rom->license_offs; + + printk(KERN_INFO "VMI: Found %s %s, API version %d.%d, ROM version %d.%d\n", + manufacturer, product, + rom->api_version_maj, rom->api_version_min, + pci->rom_version_maj, pci->rom_version_min); + + license_gplok = license_is_gpl_compatible(license); + if (!license_gplok) { + printk(KERN_WARNING "VMI: ROM license '%s' taints kernel... " + "inlining disabled\n", + license); + add_taint(TAINT_PROPRIETARY_MODULE); + } + return 1; +} + +/* + * Probe for the VMI option ROM + */ +static inline int __init probe_vmi_rom(void) +{ + unsigned long base; + + /* VMI ROM is in option ROM area, check signature */ + for (base = 0xC0000; base < 0xE0000; base += 2048) { + struct vrom_header *romstart; + romstart = (struct vrom_header *)isa_bus_to_virt(base); + if (check_vmi_rom(romstart)) { + vmi_rom = romstart; + return 1; + } + } + return 0; +} + +/* + * VMI setup common to all processors + */ +void vmi_bringup(void) +{ + /* We must establish the lowmem mapping for MMU ops to work */ + if (vmi_rom) + vmi_ops.set_linear_mapping(0, __PAGE_OFFSET, max_low_pfn, 0); +} + +/* + * Return a pointer to the VMI function or a NOP stub + */ +static void *vmi_get_function(int vmicall) +{ + u64 reloc; + const struct vmi_relocation_info *rel = (struct vmi_relocation_info *)&reloc; + reloc = call_vrom_long_func(vmi_rom, get_reloc, vmicall); + BUG_ON(rel->type == VMI_RELOCATION_JUMP_REL); + if (rel->type == VMI_RELOCATION_CALL_REL) + return (void *)rel->eip; + else + return (void *)vmi_nop; +} + +/* + * Helper macro for making the VMI paravirt-ops fill code readable. + * For unimplemented operations, fall back to default. + */ +#define para_fill(opname, vmicall) \ +do { \ + reloc = call_vrom_long_func(vmi_rom, get_reloc, \ + VMI_CALL_##vmicall); \ + if (rel->type != VMI_RELOCATION_NONE) { \ + BUG_ON(rel->type != VMI_RELOCATION_CALL_REL); \ + paravirt_ops.opname = (void *)rel->eip; \ + } \ +} while (0) + +/* + * Activate the VMI interface and switch into paravirtualized mode + */ +static inline int __init activate_vmi(void) +{ + short kernel_cs; + u64 reloc; + const struct vmi_relocation_info *rel = (struct vmi_relocation_info *)&reloc; + + if (call_vrom_func(vmi_rom, vmi_init) != 0) { + printk(KERN_ERR "VMI ROM failed to initialize!"); + return 0; + } + savesegment(cs, kernel_cs); + + paravirt_ops.paravirt_enabled = 1; + paravirt_ops.kernel_rpl = kernel_cs & SEGMENT_RPL_MASK; + + paravirt_ops.patch = vmi_patch; + paravirt_ops.name = "vmi"; + + /* + * Many of these operations are ABI compatible with VMI. + * This means we can fill in the paravirt-ops with direct + * pointers into the VMI ROM. If the calling convention for + * these operations changes, this code needs to be updated. + * + * Exceptions + * CPUID paravirt-op uses pointers, not the native ISA + * halt has no VMI equivalent; all VMI halts are "safe" + * no MSR support yet - just trap and emulate. VMI uses the + * same ABI as the native ISA, but Linux wants exceptions + * from bogus MSR read / write handled + * rdpmc is not yet used in Linux + */ + + /* CPUID is special, so very special */ + reloc = call_vrom_long_func(vmi_rom, get_reloc, VMI_CALL_CPUID); + if (rel->type != VMI_RELOCATION_NONE) { + BUG_ON(rel->type != VMI_RELOCATION_CALL_REL); + vmi_ops.cpuid = (void *)rel->eip; + paravirt_ops.cpuid = vmi_cpuid; + } + + para_fill(clts, CLTS); + para_fill(get_debugreg, GetDR); + para_fill(set_debugreg, SetDR); + para_fill(read_cr0, GetCR0); + para_fill(read_cr2, GetCR2); + para_fill(read_cr3, GetCR3); + para_fill(read_cr4, GetCR4); + para_fill(write_cr0, SetCR0); + para_fill(write_cr2, SetCR2); + para_fill(write_cr3, SetCR3); + para_fill(write_cr4, SetCR4); + para_fill(save_fl, GetInterruptMask); + para_fill(restore_fl, SetInterruptMask); + para_fill(irq_disable, DisableInterrupts); + para_fill(irq_enable, EnableInterrupts); + /* irq_save_disable !!! sheer pain */ + patch_offset(&irq_save_disable_callout[IRQ_PATCH_INT_MASK], + (char *)paravirt_ops.save_fl); + patch_offset(&irq_save_disable_callout[IRQ_PATCH_DISABLE], + (char *)paravirt_ops.irq_disable); +#ifndef CONFIG_NO_IDLE_HZ + para_fill(safe_halt, Halt); +#else + vmi_ops.halt = vmi_get_function(VMI_CALL_Halt); + paravirt_ops.safe_halt = vmi_safe_halt; +#endif + para_fill(wbinvd, WBINVD); + /* paravirt_ops.read_msr = vmi_rdmsr */ + /* paravirt_ops.write_msr = vmi_wrmsr */ + para_fill(read_tsc, RDTSC); + /* paravirt_ops.rdpmc = vmi_rdpmc */ + + /* TR interface doesn't pass TR value */ + reloc = call_vrom_long_func(vmi_rom, get_reloc, VMI_CALL_SetTR); + if (rel->type != VMI_RELOCATION_NONE) { + BUG_ON(rel->type != VMI_RELOCATION_CALL_REL); + vmi_ops.set_tr = (void *)rel->eip; + paravirt_ops.load_tr_desc = vmi_set_tr; + } + + /* LDT is special, too */ + reloc = call_vrom_long_func(vmi_rom, get_reloc, VMI_CALL_SetLDT); + if (rel->type != VMI_RELOCATION_NONE) { + BUG_ON(rel->type != VMI_RELOCATION_CALL_REL); + vmi_ops._set_ldt = (void *)rel->eip; + paravirt_ops.set_ldt = vmi_set_ldt; + } + + para_fill(load_gdt, SetGDT); + para_fill(load_idt, SetIDT); + para_fill(store_gdt, GetGDT); + para_fill(store_idt, GetIDT); + para_fill(store_tr, GetTR); + paravirt_ops.load_tls = vmi_load_tls; + para_fill(write_ldt_entry, WriteLDTEntry); + para_fill(write_gdt_entry, WriteGDTEntry); + para_fill(write_idt_entry, WriteIDTEntry); + reloc = call_vrom_long_func(vmi_rom, get_reloc, + VMI_CALL_UpdateKernelStack); + if (rel->type != VMI_RELOCATION_NONE) { + BUG_ON(rel->type != VMI_RELOCATION_CALL_REL); + vmi_ops.set_kernel_stack = (void *)rel->eip; + paravirt_ops.load_esp0 = vmi_load_esp0; + } + + para_fill(set_iopl_mask, SetIOPLMask); + paravirt_ops.io_delay = (void *)vmi_nop; + if (!disable_nodelay) { + paravirt_ops.const_udelay = (void *)vmi_nop; + } + + para_fill(set_lazy_mode, SetLazyMode); + + reloc = call_vrom_long_func(vmi_rom, get_reloc, VMI_CALL_FlushTLB); + if (rel->type != VMI_RELOCATION_NONE) { + vmi_ops.flush_tlb = (void *)rel->eip; + paravirt_ops.flush_tlb_user = vmi_flush_tlb_user; + paravirt_ops.flush_tlb_kernel = vmi_flush_tlb_kernel; + } + para_fill(flush_tlb_single, InvalPage); + + /* + * Until a standard flag format can be agreed on, we need to + * implement these as wrappers in Linux. Get the VMI ROM + * function pointers for the two backend calls. + */ +#ifdef CONFIG_X86_PAE + vmi_ops.set_pte = vmi_get_function(VMI_CALL_SetPxELong); + vmi_ops.update_pte = vmi_get_function(VMI_CALL_UpdatePxELong); +#else + vmi_ops.set_pte = vmi_get_function(VMI_CALL_SetPxE); + vmi_ops.update_pte = vmi_get_function(VMI_CALL_UpdatePxE); +#endif + vmi_ops.set_linear_mapping = vmi_get_function(VMI_CALL_SetLinearMapping); + vmi_ops.allocate_page = vmi_get_function(VMI_CALL_AllocatePage); + vmi_ops.release_page = vmi_get_function(VMI_CALL_ReleasePage); + + paravirt_ops.alloc_pt = vmi_allocate_pt; + paravirt_ops.alloc_pd = vmi_allocate_pd; + paravirt_ops.alloc_pd_clone = vmi_allocate_pd_clone; + paravirt_ops.release_pt = vmi_release_pt; + paravirt_ops.release_pd = vmi_release_pd; + paravirt_ops.set_pte = vmi_set_pte; + paravirt_ops.set_pte_at = vmi_set_pte_at; + paravirt_ops.set_pmd = vmi_set_pmd; + paravirt_ops.pte_update = vmi_update_pte; + paravirt_ops.pte_update_defer = vmi_update_pte_defer; +#ifdef CONFIG_X86_PAE + paravirt_ops.set_pte_atomic = vmi_set_pte_atomic; + paravirt_ops.set_pte_present = vmi_set_pte_present; + paravirt_ops.set_pud = vmi_set_pud; + paravirt_ops.pte_clear = vmi_pte_clear; + paravirt_ops.pmd_clear = vmi_pmd_clear; +#endif + /* + * These MUST always be patched. Don't support indirect jumps + * through these operations, as the VMI interface may use either + * a jump or a call to get to these operations, depending on + * the backend. They are performance critical anyway, so requiring + * a patch is not a big problem. + */ + paravirt_ops.irq_enable_sysexit = (void *)0xfeedbab0; + paravirt_ops.iret = (void *)0xbadbab0; + +#ifdef CONFIG_SMP + paravirt_ops.startup_ipi_hook = vmi_startup_ipi_hook; + vmi_ops.set_initial_ap_state = vmi_get_function(VMI_CALL_SetInitialAPState); +#endif + +#ifdef CONFIG_X86_LOCAL_APIC + paravirt_ops.apic_read = vmi_get_function(VMI_CALL_APICRead); + paravirt_ops.apic_write = vmi_get_function(VMI_CALL_APICWrite); + paravirt_ops.apic_write_atomic = vmi_get_function(VMI_CALL_APICWrite); +#endif + + /* + * Check for VMI timer functionality by probing for a cycle frequency method + */ + reloc = call_vrom_long_func(vmi_rom, get_reloc, VMI_CALL_GetCycleFrequency); + if (rel->type != VMI_RELOCATION_NONE) { + vmi_timer_ops.get_cycle_frequency = (void *)rel->eip; + vmi_timer_ops.get_cycle_counter = + vmi_get_function(VMI_CALL_GetCycleCounter); + vmi_timer_ops.get_wallclock = + vmi_get_function(VMI_CALL_GetWallclockTime); + vmi_timer_ops.wallclock_updated = + vmi_get_function(VMI_CALL_WallclockUpdated); + vmi_timer_ops.set_alarm = vmi_get_function(VMI_CALL_SetAlarm); + vmi_timer_ops.cancel_alarm = + vmi_get_function(VMI_CALL_CancelAlarm); + paravirt_ops.time_init = vmi_time_init; + paravirt_ops.get_wallclock = vmi_get_wallclock; + paravirt_ops.set_wallclock = vmi_set_wallclock; +#ifdef CONFIG_X86_LOCAL_APIC + paravirt_ops.setup_boot_clock = vmi_timer_setup_boot_alarm; + paravirt_ops.setup_secondary_clock = vmi_timer_setup_secondary_alarm; +#endif + custom_sched_clock = vmi_sched_clock; + } + + /* + * Alternative instruction rewriting doesn't happen soon enough + * to convert VMI_IRET to a call instead of a jump; so we have + * to do this before IRQs get reenabled. Fortunately, it is + * idempotent. + */ + apply_paravirt(__start_parainstructions, __stop_parainstructions); + + vmi_bringup(); + + return 1; +} + +#undef para_fill + +void __init vmi_init(void) +{ + unsigned long flags; + + if (!vmi_rom) + probe_vmi_rom(); + else + check_vmi_rom(vmi_rom); + + /* In case probing for or validating the ROM failed, basil */ + if (!vmi_rom) + return; + + reserve_top_address(-vmi_rom->virtual_top); + + local_irq_save(flags); + activate_vmi(); +#ifdef CONFIG_SMP + no_timer_check = 1; +#endif + local_irq_restore(flags & X86_EFLAGS_IF); +} + +static int __init parse_vmi(char *arg) +{ + if (!arg) + return -EINVAL; + + if (!strcmp(arg, "disable_nodelay")) + disable_nodelay = 1; + else if (!strcmp(arg, "disable_pge")) { + clear_bit(X86_FEATURE_PGE, boot_cpu_data.x86_capability); + disable_pge = 1; + } else if (!strcmp(arg, "disable_pse")) { + clear_bit(X86_FEATURE_PSE, boot_cpu_data.x86_capability); + disable_pse = 1; + } else if (!strcmp(arg, "disable_sep")) { + clear_bit(X86_FEATURE_SEP, boot_cpu_data.x86_capability); + disable_sep = 1; + } else if (!strcmp(arg, "disable_tsc")) { + clear_bit(X86_FEATURE_TSC, boot_cpu_data.x86_capability); + disable_tsc = 1; + } else if (!strcmp(arg, "disable_mtrr")) { + clear_bit(X86_FEATURE_MTRR, boot_cpu_data.x86_capability); + disable_mtrr = 1; + } + return 0; +} + +early_param("vmi", parse_vmi); diff --git a/arch/i386/kernel/vmitime.c b/arch/i386/kernel/vmitime.c new file mode 100644 index 0000000..76d2adc --- /dev/null +++ b/arch/i386/kernel/vmitime.c @@ -0,0 +1,499 @@ +/* + * VMI paravirtual timer support routines. + * + * Copyright (C) 2005, VMware, 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. + * + * 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, GOOD TITLE or + * NON INFRINGEMENT. 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., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * Send feedback to dhecht@vmware.com + * + */ + +/* + * Portions of this code from arch/i386/kernel/timers/timer_tsc.c. + * Portions of the CONFIG_NO_IDLE_HZ code from arch/s390/kernel/time.c. + * See comments there for proper credits. + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include + +#ifdef CONFIG_X86_LOCAL_APIC +#define VMI_ALARM_WIRING VMI_ALARM_WIRED_LVTT +#else +#define VMI_ALARM_WIRING VMI_ALARM_WIRED_IRQ0 +#endif + +/* Cached VMI operations */ +struct vmi_timer_ops vmi_timer_ops; + +#ifdef CONFIG_NO_IDLE_HZ + +/* /proc/sys/kernel/hz_timer state. */ +int sysctl_hz_timer; + +/* Some stats */ +static DEFINE_PER_CPU(unsigned long, vmi_idle_no_hz_irqs); +static DEFINE_PER_CPU(unsigned long, vmi_idle_no_hz_jiffies); +static DEFINE_PER_CPU(unsigned long, idle_start_jiffies); + +#endif /* CONFIG_NO_IDLE_HZ */ + +/* Number of alarms per second. By default this is CONFIG_VMI_ALARM_HZ. */ +static int alarm_hz = CONFIG_VMI_ALARM_HZ; + +/* Cache of the value get_cycle_frequency / HZ. */ +static signed long long cycles_per_jiffy; + +/* Cache of the value get_cycle_frequency / alarm_hz. */ +static signed long long cycles_per_alarm; + +/* The number of cycles accounted for by the 'jiffies'/'xtime' count. + * Protected by xtime_lock. */ +static unsigned long long real_cycles_accounted_system; + +/* The number of cycles accounted for by update_process_times(), per cpu. */ +static DEFINE_PER_CPU(unsigned long long, process_times_cycles_accounted_cpu); + +/* The number of stolen cycles accounted, per cpu. */ +static DEFINE_PER_CPU(unsigned long long, stolen_cycles_accounted_cpu); + +/* Clock source. */ +static cycle_t read_real_cycles(void) +{ + return vmi_timer_ops.get_cycle_counter(VMI_CYCLES_REAL); +} + +static cycle_t read_available_cycles(void) +{ + return vmi_timer_ops.get_cycle_counter(VMI_CYCLES_AVAILABLE); +} + +#if 0 +static cycle_t read_stolen_cycles(void) +{ + return vmi_timer_ops.get_cycle_counter(VMI_CYCLES_STOLEN); +} +#endif /* 0 */ + +static struct clocksource clocksource_vmi = { + .name = "vmi-timer", + .rating = 450, + .read = read_real_cycles, + .mask = CLOCKSOURCE_MASK(64), + .mult = 0, /* to be set */ + .shift = 22, + .flags = CLOCK_SOURCE_IS_CONTINUOUS, +}; + + +/* Timer interrupt handler. */ +static irqreturn_t vmi_timer_interrupt(int irq, void *dev_id); + +static struct irqaction vmi_timer_irq = { + vmi_timer_interrupt, + SA_INTERRUPT, + CPU_MASK_NONE, + "VMI-alarm", + NULL, + NULL +}; + +/* Alarm rate */ +static int __init vmi_timer_alarm_rate_setup(char* str) +{ + int alarm_rate; + if (get_option(&str, &alarm_rate) == 1 && alarm_rate > 0) { + alarm_hz = alarm_rate; + printk(KERN_WARNING "VMI timer alarm HZ set to %d\n", alarm_hz); + } + return 1; +} +__setup("vmi_timer_alarm_hz=", vmi_timer_alarm_rate_setup); + + +/* Initialization */ +static void vmi_get_wallclock_ts(struct timespec *ts) +{ + unsigned long long wallclock; + wallclock = vmi_timer_ops.get_wallclock(); // nsec units + ts->tv_nsec = do_div(wallclock, 1000000000); + ts->tv_sec = wallclock; +} + +static void update_xtime_from_wallclock(void) +{ + struct timespec ts; + vmi_get_wallclock_ts(&ts); + do_settimeofday(&ts); +} + +unsigned long vmi_get_wallclock(void) +{ + struct timespec ts; + vmi_get_wallclock_ts(&ts); + return ts.tv_sec; +} + +int vmi_set_wallclock(unsigned long now) +{ + return -1; +} + +unsigned long long vmi_sched_clock(void) +{ + return read_available_cycles(); +} + +void __init vmi_time_init(void) +{ + unsigned long long cycles_per_sec, cycles_per_msec; + unsigned long flags; + + local_irq_save(flags); + setup_irq(0, &vmi_timer_irq); +#ifdef CONFIG_X86_LOCAL_APIC + set_intr_gate(LOCAL_TIMER_VECTOR, apic_vmi_timer_interrupt); +#endif + + no_sync_cmos_clock = 1; + + vmi_get_wallclock_ts(&xtime); + set_normalized_timespec(&wall_to_monotonic, + -xtime.tv_sec, -xtime.tv_nsec); + + real_cycles_accounted_system = read_real_cycles(); + update_xtime_from_wallclock(); + per_cpu(process_times_cycles_accounted_cpu, 0) = read_available_cycles(); + + cycles_per_sec = vmi_timer_ops.get_cycle_frequency(); + + cycles_per_jiffy = cycles_per_sec; + (void)do_div(cycles_per_jiffy, HZ); + cycles_per_alarm = cycles_per_sec; + (void)do_div(cycles_per_alarm, alarm_hz); + cycles_per_msec = cycles_per_sec; + (void)do_div(cycles_per_msec, 1000); + cpu_khz = cycles_per_msec; + + printk(KERN_WARNING "VMI timer cycles/sec = %llu ; cycles/jiffy = %llu ;" + "cycles/alarm = %llu\n", cycles_per_sec, cycles_per_jiffy, + cycles_per_alarm); + + clocksource_vmi.mult = clocksource_khz2mult(cycles_per_msec, + clocksource_vmi.shift); + if (clocksource_register(&clocksource_vmi)) + printk(KERN_WARNING "Error registering VMITIME clocksource."); + + /* Disable PIT. */ + outb_p(0x3a, PIT_MODE); /* binary, mode 5, LSB/MSB, ch 0 */ + + /* schedule the alarm. do this in phase with process_times_cycles_accounted_cpu + * reduce the latency calling update_process_times. */ + vmi_timer_ops.set_alarm( + VMI_ALARM_WIRED_IRQ0 | VMI_ALARM_IS_PERIODIC | VMI_CYCLES_AVAILABLE, + per_cpu(process_times_cycles_accounted_cpu, 0) + cycles_per_alarm, + cycles_per_alarm); + + local_irq_restore(flags); +} + +#ifdef CONFIG_X86_LOCAL_APIC + +void __init vmi_timer_setup_boot_alarm(void) +{ + local_irq_disable(); + + /* Route the interrupt to the correct vector. */ + apic_write_around(APIC_LVTT, LOCAL_TIMER_VECTOR); + + /* Cancel the IRQ0 wired alarm, and setup the LVTT alarm. */ + vmi_timer_ops.cancel_alarm(VMI_CYCLES_AVAILABLE); + vmi_timer_ops.set_alarm( + VMI_ALARM_WIRED_LVTT | VMI_ALARM_IS_PERIODIC | VMI_CYCLES_AVAILABLE, + per_cpu(process_times_cycles_accounted_cpu, 0) + cycles_per_alarm, + cycles_per_alarm); + local_irq_enable(); +} + +/* Initialize the time accounting variables for an AP on an SMP system. + * Also, set the local alarm for the AP. */ +void __init vmi_timer_setup_secondary_alarm(void) +{ + int cpu = smp_processor_id(); + + /* Route the interrupt to the correct vector. */ + apic_write_around(APIC_LVTT, LOCAL_TIMER_VECTOR); + + per_cpu(process_times_cycles_accounted_cpu, cpu) = read_available_cycles(); + + vmi_timer_ops.set_alarm( + VMI_ALARM_WIRED_LVTT | VMI_ALARM_IS_PERIODIC | VMI_CYCLES_AVAILABLE, + per_cpu(process_times_cycles_accounted_cpu, cpu) + cycles_per_alarm, + cycles_per_alarm); +} + +#endif + +/* Update system wide (real) time accounting (e.g. jiffies, xtime). */ +static void vmi_account_real_cycles(unsigned long long cur_real_cycles) +{ + long long cycles_not_accounted; + + write_seqlock(&xtime_lock); + + cycles_not_accounted = cur_real_cycles - real_cycles_accounted_system; + while (cycles_not_accounted >= cycles_per_jiffy) { + /* systems wide jiffies and wallclock. */ + do_timer(1); + + cycles_not_accounted -= cycles_per_jiffy; + real_cycles_accounted_system += cycles_per_jiffy; + } + + if (vmi_timer_ops.wallclock_updated()) + update_xtime_from_wallclock(); + + write_sequnlock(&xtime_lock); +} + +/* Update per-cpu process times. */ +static void vmi_account_process_times_cycles(struct pt_regs *regs, int cpu, + unsigned long long cur_process_times_cycles) +{ + long long cycles_not_accounted; + cycles_not_accounted = cur_process_times_cycles - + per_cpu(process_times_cycles_accounted_cpu, cpu); + + while (cycles_not_accounted >= cycles_per_jiffy) { + /* Account time to the current process. This includes + * calling into the scheduler to decrement the timeslice + * and possibly reschedule.*/ + update_process_times(user_mode(regs)); + /* XXX handle /proc/profile multiplier. */ + profile_tick(CPU_PROFILING); + + cycles_not_accounted -= cycles_per_jiffy; + per_cpu(process_times_cycles_accounted_cpu, cpu) += cycles_per_jiffy; + } +} + +#ifdef CONFIG_NO_IDLE_HZ +/* Update per-cpu idle times. Used when a no-hz halt is ended. */ +static void vmi_account_no_hz_idle_cycles(int cpu, + unsigned long long cur_process_times_cycles) +{ + long long cycles_not_accounted; + unsigned long no_idle_hz_jiffies = 0; + + cycles_not_accounted = cur_process_times_cycles - + per_cpu(process_times_cycles_accounted_cpu, cpu); + + while (cycles_not_accounted >= cycles_per_jiffy) { + no_idle_hz_jiffies++; + cycles_not_accounted -= cycles_per_jiffy; + per_cpu(process_times_cycles_accounted_cpu, cpu) += cycles_per_jiffy; + } + /* Account time to the idle process. */ + account_steal_time(idle_task(cpu), jiffies_to_cputime(no_idle_hz_jiffies)); +} +#endif + +/* Update per-cpu stolen time. */ +static void vmi_account_stolen_cycles(int cpu, + unsigned long long cur_real_cycles, + unsigned long long cur_avail_cycles) +{ + long long stolen_cycles_not_accounted; + unsigned long stolen_jiffies = 0; + + if (cur_real_cycles < cur_avail_cycles) + return; + + stolen_cycles_not_accounted = cur_real_cycles - cur_avail_cycles - + per_cpu(stolen_cycles_accounted_cpu, cpu); + + while (stolen_cycles_not_accounted >= cycles_per_jiffy) { + stolen_jiffies++; + stolen_cycles_not_accounted -= cycles_per_jiffy; + per_cpu(stolen_cycles_accounted_cpu, cpu) += cycles_per_jiffy; + } + /* HACK: pass NULL to force time onto cpustat->steal. */ + account_steal_time(NULL, jiffies_to_cputime(stolen_jiffies)); +} + +/* Body of either IRQ0 interrupt handler (UP no local-APIC) or + * local-APIC LVTT interrupt handler (UP & local-APIC or SMP). */ +static void vmi_local_timer_interrupt(int cpu) +{ + unsigned long long cur_real_cycles, cur_process_times_cycles; + + cur_real_cycles = read_real_cycles(); + cur_process_times_cycles = read_available_cycles(); + /* Update system wide (real) time state (xtime, jiffies). */ + vmi_account_real_cycles(cur_real_cycles); + /* Update per-cpu process times. */ + vmi_account_process_times_cycles(get_irq_regs(), cpu, cur_process_times_cycles); + /* Update time stolen from this cpu by the hypervisor. */ + vmi_account_stolen_cycles(cpu, cur_real_cycles, cur_process_times_cycles); +} + +#ifdef CONFIG_NO_IDLE_HZ + +/* Must be called only from idle loop, with interrupts disabled. */ +int vmi_stop_hz_timer(void) +{ + /* Note that cpu_set, cpu_clear are (SMP safe) atomic on x86. */ + + unsigned long seq, next; + unsigned long long real_cycles_expiry; + int cpu = smp_processor_id(); + int idle; + + BUG_ON(!irqs_disabled()); + if (sysctl_hz_timer != 0) + return 0; + + cpu_set(cpu, nohz_cpu_mask); + smp_mb(); + if (rcu_needs_cpu(cpu) || local_softirq_pending() || + (next = next_timer_interrupt(), time_before_eq(next, jiffies))) { + cpu_clear(cpu, nohz_cpu_mask); + next = jiffies; + idle = 0; + } else + idle = 1; + + /* Convert jiffies to the real cycle counter. */ + do { + seq = read_seqbegin(&xtime_lock); + real_cycles_expiry = real_cycles_accounted_system + + (long)(next - jiffies) * cycles_per_jiffy; + } while (read_seqretry(&xtime_lock, seq)); + + /* This cpu is going idle. Disable the periodic alarm. */ + if (idle) { + vmi_timer_ops.cancel_alarm(VMI_CYCLES_AVAILABLE); + per_cpu(idle_start_jiffies, cpu) = jiffies; + } + + /* Set the real time alarm to expire at the next event. */ + vmi_timer_ops.set_alarm( + VMI_ALARM_WIRING | VMI_ALARM_IS_ONESHOT | VMI_CYCLES_REAL, + real_cycles_expiry, 0); + + return idle; +} + +static void vmi_reenable_hz_timer(int cpu) +{ + /* For /proc/vmi/info idle_hz stat. */ + per_cpu(vmi_idle_no_hz_jiffies, cpu) += jiffies - per_cpu(idle_start_jiffies, cpu); + per_cpu(vmi_idle_no_hz_irqs, cpu)++; + + /* Don't bother explicitly cancelling the one-shot alarm -- at + * worse we will receive a spurious timer interrupt. */ + vmi_timer_ops.set_alarm( + VMI_ALARM_WIRING | VMI_ALARM_IS_PERIODIC | VMI_CYCLES_AVAILABLE, + per_cpu(process_times_cycles_accounted_cpu, cpu) + cycles_per_alarm, + cycles_per_alarm); + /* Indicate this cpu is no longer nohz idle. */ + cpu_clear(cpu, nohz_cpu_mask); +} + +/* Called from interrupt handlers when (local) HZ timer is disabled. */ +void vmi_account_time_restart_hz_timer(void) +{ + unsigned long long cur_real_cycles, cur_process_times_cycles; + int cpu = smp_processor_id(); + + BUG_ON(!irqs_disabled()); + /* Account the time during which the HZ timer was disabled. */ + cur_real_cycles = read_real_cycles(); + cur_process_times_cycles = read_available_cycles(); + /* Update system wide (real) time state (xtime, jiffies). */ + vmi_account_real_cycles(cur_real_cycles); + /* Update per-cpu idle times. */ + vmi_account_no_hz_idle_cycles(cpu, cur_process_times_cycles); + /* Update time stolen from this cpu by the hypervisor. */ + vmi_account_stolen_cycles(cpu, cur_real_cycles, cur_process_times_cycles); + /* Reenable the hz timer. */ + vmi_reenable_hz_timer(cpu); +} + +#endif /* CONFIG_NO_IDLE_HZ */ + +/* UP (and no local-APIC) VMI-timer alarm interrupt handler. + * Handler for IRQ0. Not used when SMP or X86_LOCAL_APIC after + * APIC setup and setup_boot_vmi_alarm() is called. */ +static irqreturn_t vmi_timer_interrupt(int irq, void *dev_id) +{ + vmi_local_timer_interrupt(smp_processor_id()); + return IRQ_HANDLED; +} + +#ifdef CONFIG_X86_LOCAL_APIC + +/* SMP VMI-timer alarm interrupt handler. Handler for LVTT vector. + * Also used in UP when CONFIG_X86_LOCAL_APIC. + * The wrapper code is from arch/i386/kernel/apic.c#smp_apic_timer_interrupt. */ +void smp_apic_vmi_timer_interrupt(struct pt_regs *regs) +{ + struct pt_regs *old_regs = set_irq_regs(regs); + int cpu = smp_processor_id(); + + /* + * the NMI deadlock-detector uses this. + */ + per_cpu(irq_stat,cpu).apic_timer_irqs++; + + /* + * NOTE! We'd better ACK the irq immediately, + * because timer handling can be slow. + */ + ack_APIC_irq(); + + /* + * update_process_times() expects us to have done irq_enter(). + * Besides, if we don't timer interrupts ignore the global + * interrupt lock, which is the WrongThing (tm) to do. + */ + irq_enter(); + vmi_local_timer_interrupt(cpu); + irq_exit(); + set_irq_regs(old_regs); +} + +#endif /* CONFIG_X86_LOCAL_APIC */ diff --git a/arch/i386/kernel/vmlinux.lds.S b/arch/i386/kernel/vmlinux.lds.S index a53c8b1..ca51610 100644 --- a/arch/i386/kernel/vmlinux.lds.S +++ b/arch/i386/kernel/vmlinux.lds.S @@ -37,9 +37,14 @@ SECTIONS { . = LOAD_OFFSET + LOAD_PHYSICAL_ADDR; phys_startup_32 = startup_32 - LOAD_OFFSET; + + .text.head : AT(ADDR(.text.head) - LOAD_OFFSET) { + _text = .; /* Text and read-only data */ + *(.text.head) + } :text = 0x9090 + /* read-only */ .text : AT(ADDR(.text) - LOAD_OFFSET) { - _text = .; /* Text and read-only data */ *(.text) SCHED_TEXT LOCK_TEXT @@ -181,12 +186,14 @@ SECTIONS from .altinstructions and .eh_frame */ .exit.text : AT(ADDR(.exit.text) - LOAD_OFFSET) { *(.exit.text) } .exit.data : AT(ADDR(.exit.data) - LOAD_OFFSET) { *(.exit.data) } +#if defined(CONFIG_BLK_DEV_INITRD) . = ALIGN(4096); .init.ramfs : AT(ADDR(.init.ramfs) - LOAD_OFFSET) { __initramfs_start = .; *(.init.ramfs) __initramfs_end = .; } +#endif . = ALIGN(L1_CACHE_BYTES); .data.percpu : AT(ADDR(.data.percpu) - LOAD_OFFSET) { __per_cpu_start = .; diff --git a/arch/i386/mach-default/setup.c b/arch/i386/mach-default/setup.c index cc2f519..c788162 100644 --- a/arch/i386/mach-default/setup.c +++ b/arch/i386/mach-default/setup.c @@ -79,7 +79,12 @@ void __init trap_init_hook(void) { } -static struct irqaction irq0 = { timer_interrupt, IRQF_DISABLED, CPU_MASK_NONE, "timer", NULL, NULL}; +static struct irqaction irq0 = { + .handler = timer_interrupt, + .flags = IRQF_DISABLED | IRQF_NOBALANCING, + .mask = CPU_MASK_NONE, + .name = "timer" +}; /** * time_init_hook - do any specific initialisations for the system timer. @@ -90,6 +95,7 @@ static struct irqaction irq0 = { timer_ **/ void __init time_init_hook(void) { + irq0.mask = cpumask_of_cpu(0); setup_irq(0, &irq0); } diff --git a/arch/i386/mach-es7000/es7000.h b/arch/i386/mach-es7000/es7000.h index 80566ca..c8d5aa1 100644 --- a/arch/i386/mach-es7000/es7000.h +++ b/arch/i386/mach-es7000/es7000.h @@ -84,15 +84,6 @@ struct es7000_oem_table { }; #ifdef CONFIG_ACPI -struct acpi_table_sdt { - unsigned long pa; - unsigned long count; - struct { - unsigned long pa; - enum acpi_table_id id; - unsigned long size; - } entry[50]; -}; struct oem_table { struct acpi_table_header Header; diff --git a/arch/i386/mach-es7000/es7000plat.c b/arch/i386/mach-es7000/es7000plat.c index 3d0fc85..9be6cea 100644 --- a/arch/i386/mach-es7000/es7000plat.c +++ b/arch/i386/mach-es7000/es7000plat.c @@ -160,51 +160,14 @@ #ifdef CONFIG_ACPI int __init find_unisys_acpi_oem_table(unsigned long *oem_addr) { - struct acpi_table_rsdp *rsdp = NULL; - unsigned long rsdp_phys = 0; - struct acpi_table_header *header = NULL; - int i; - struct acpi_table_sdt sdt; - - rsdp_phys = acpi_find_rsdp(); - rsdp = __va(rsdp_phys); - if (rsdp->rsdt_address) { - struct acpi_table_rsdt *mapped_rsdt = NULL; - sdt.pa = rsdp->rsdt_address; - - header = (struct acpi_table_header *) - __acpi_map_table(sdt.pa, sizeof(struct acpi_table_header)); - if (!header) - return -ENODEV; - - sdt.count = (header->length - sizeof(struct acpi_table_header)) >> 3; - mapped_rsdt = (struct acpi_table_rsdt *) - __acpi_map_table(sdt.pa, header->length); - if (!mapped_rsdt) - return -ENODEV; - - header = &mapped_rsdt->header; - - for (i = 0; i < sdt.count; i++) - sdt.entry[i].pa = (unsigned long) mapped_rsdt->entry[i]; - }; - for (i = 0; i < sdt.count; i++) { - - header = (struct acpi_table_header *) - __acpi_map_table(sdt.entry[i].pa, - sizeof(struct acpi_table_header)); - if (!header) - continue; - if (!strncmp((char *) &header->signature, "OEM1", 4)) { - if (!strncmp((char *) &header->oem_id, "UNISYS", 6)) { - void *addr; - struct oem_table *t; - acpi_table_print(header, sdt.entry[i].pa); - t = (struct oem_table *) __acpi_map_table(sdt.entry[i].pa, header->length); - addr = (void *) __acpi_map_table(t->OEMTableAddr, t->OEMTableSize); - *oem_addr = (unsigned long) addr; - return 0; - } + struct acpi_table_header *header = NULL; + int i = 0; + while (ACPI_SUCCESS(acpi_get_table("OEM1", i++, &header))) { + if (!memcmp((char *) &header->oem_id, "UNISYS", 6)) { + struct oem_table *t = (struct oem_table *)header; + *oem_addr = (unsigned long)__acpi_map_table(t->OEMTableAddr, + t->OEMTableSize); + return 0; } } return -1; diff --git a/arch/i386/math-emu/get_address.c b/arch/i386/math-emu/get_address.c index 9819b70..2e2c51a 100644 --- a/arch/i386/math-emu/get_address.c +++ b/arch/i386/math-emu/get_address.c @@ -56,15 +56,14 @@ static int reg_offset_vm86[] = { #define VM86_REG_(x) (*(unsigned short *) \ (reg_offset_vm86[((unsigned)x)]+(u_char *) FPU_info)) -/* These are dummy, fs and gs are not saved on the stack. */ -#define ___FS ___ds +/* This dummy, gs is not saved on the stack. */ #define ___GS ___ds static int reg_offset_pm[] = { offsetof(struct info,___cs), offsetof(struct info,___ds), offsetof(struct info,___es), - offsetof(struct info,___FS), + offsetof(struct info,___fs), offsetof(struct info,___GS), offsetof(struct info,___ss), offsetof(struct info,___ds) @@ -169,13 +168,10 @@ #endif /* PARANOID */ switch ( segment ) { - /* fs and gs aren't used by the kernel, so they still have their - user-space values. */ - case PREFIX_FS_-1: - /* N.B. - movl %seg, mem is a 2 byte write regardless of prefix */ - savesegment(fs, addr->selector); - break; + /* gs isn't used by the kernel, so it still has its + user-space value. */ case PREFIX_GS_-1: + /* N.B. - movl %seg, mem is a 2 byte write regardless of prefix */ savesegment(gs, addr->selector); break; default: diff --git a/arch/i386/math-emu/status_w.h b/arch/i386/math-emu/status_w.h index 78d7b76..59e7330 100644 --- a/arch/i386/math-emu/status_w.h +++ b/arch/i386/math-emu/status_w.h @@ -48,9 +48,11 @@ #define COMP_SNaN 0x80 #define status_word() \ ((partial_status & ~SW_Top & 0xffff) | ((top << SW_Top_Shift) & SW_Top)) -#define setcc(cc) ({ \ - partial_status &= ~(SW_C0|SW_C1|SW_C2|SW_C3); \ - partial_status |= (cc) & (SW_C0|SW_C1|SW_C2|SW_C3); }) +static inline void setcc(int cc) +{ + partial_status &= ~(SW_C0|SW_C1|SW_C2|SW_C3); + partial_status |= (cc) & (SW_C0|SW_C1|SW_C2|SW_C3); +} #ifdef PECULIAR_486 /* Default, this conveys no information, but an 80486 does it. */ diff --git a/arch/i386/mm/discontig.c b/arch/i386/mm/discontig.c index e0c390d..aa58720 100644 --- a/arch/i386/mm/discontig.c +++ b/arch/i386/mm/discontig.c @@ -101,7 +101,6 @@ extern void find_max_pfn(void); extern void add_one_highpage_init(struct page *, int, int); extern struct e820map e820; -extern unsigned long init_pg_tables_end; extern unsigned long highend_pfn, highstart_pfn; extern unsigned long max_low_pfn; extern unsigned long totalram_pages; diff --git a/arch/i386/mm/fault.c b/arch/i386/mm/fault.c index aaaa4d2..b8c4e25 100644 --- a/arch/i386/mm/fault.c +++ b/arch/i386/mm/fault.c @@ -46,43 +46,17 @@ int unregister_page_fault_notifier(struc } EXPORT_SYMBOL_GPL(unregister_page_fault_notifier); -static inline int notify_page_fault(enum die_val val, const char *str, - struct pt_regs *regs, long err, int trap, int sig) +static inline int notify_page_fault(struct pt_regs *regs, long err) { struct die_args args = { .regs = regs, - .str = str, + .str = "page fault", .err = err, - .trapnr = trap, - .signr = sig + .trapnr = 14, + .signr = SIGSEGV }; - return atomic_notifier_call_chain(¬ify_page_fault_chain, val, &args); -} - -/* - * Unlock any spinlocks which will prevent us from getting the - * message out - */ -void bust_spinlocks(int yes) -{ - int loglevel_save = console_loglevel; - - if (yes) { - oops_in_progress = 1; - return; - } -#ifdef CONFIG_VT - unblank_screen(); -#endif - oops_in_progress = 0; - /* - * OK, the message is on the console. Now we call printk() - * without oops_in_progress set so that printk will give klogd - * a poke. Hold onto your hats... - */ - console_loglevel = 15; /* NMI oopser may have shut the console up */ - printk(" "); - console_loglevel = loglevel_save; + return atomic_notifier_call_chain(¬ify_page_fault_chain, + DIE_PAGE_FAULT, &args); } /* @@ -353,8 +327,7 @@ fastcall void __kprobes do_page_fault(st if (unlikely(address >= TASK_SIZE)) { if (!(error_code & 0x0000000d) && vmalloc_fault(address) >= 0) return; - if (notify_page_fault(DIE_PAGE_FAULT, "page fault", regs, error_code, 14, - SIGSEGV) == NOTIFY_STOP) + if (notify_page_fault(regs, error_code) == NOTIFY_STOP) return; /* * Don't take the mm semaphore here. If we fixup a prefetch @@ -363,8 +336,7 @@ fastcall void __kprobes do_page_fault(st goto bad_area_nosemaphore; } - if (notify_page_fault(DIE_PAGE_FAULT, "page fault", regs, error_code, 14, - SIGSEGV) == NOTIFY_STOP) + if (notify_page_fault(regs, error_code) == NOTIFY_STOP) return; /* It's safe to allow irq's after cr2 has been saved and the vmalloc diff --git a/arch/i386/mm/highmem.c b/arch/i386/mm/highmem.c index e0fa6cb..bb2de10 100644 --- a/arch/i386/mm/highmem.c +++ b/arch/i386/mm/highmem.c @@ -33,13 +33,14 @@ void *kmap_atomic(struct page *page, enu /* even !CONFIG_PREEMPT needs this, for in_atomic in do_page_fault */ pagefault_disable(); + + idx = type + KM_TYPE_NR*smp_processor_id(); + BUG_ON(!pte_none(*(kmap_pte-idx))); + if (!PageHighMem(page)) return page_address(page); - idx = type + KM_TYPE_NR*smp_processor_id(); vaddr = __fix_to_virt(FIX_KMAP_BEGIN + idx); - if (!pte_none(*(kmap_pte-idx))) - BUG(); set_pte(kmap_pte-idx, mk_pte(page, kmap_prot)); return (void*) vaddr; diff --git a/arch/i386/mm/init.c b/arch/i386/mm/init.c index c5c5ea7..ae43688 100644 --- a/arch/i386/mm/init.c +++ b/arch/i386/mm/init.c @@ -62,6 +62,7 @@ static pmd_t * __init one_md_table_init( #ifdef CONFIG_X86_PAE pmd_table = (pmd_t *) alloc_bootmem_low_pages(PAGE_SIZE); + paravirt_alloc_pd(__pa(pmd_table) >> PAGE_SHIFT); set_pgd(pgd, __pgd(__pa(pmd_table) | _PAGE_PRESENT)); pud = pud_offset(pgd, 0); if (pmd_table != pmd_offset(pud, 0)) @@ -82,6 +83,7 @@ static pte_t * __init one_page_table_ini { if (pmd_none(*pmd)) { pte_t *page_table = (pte_t *) alloc_bootmem_low_pages(PAGE_SIZE); + paravirt_alloc_pt(__pa(page_table) >> PAGE_SHIFT); set_pmd(pmd, __pmd(__pa(page_table) | _PAGE_TABLE)); if (page_table != pte_offset_kernel(pmd, 0)) BUG(); @@ -345,6 +347,8 @@ #ifdef CONFIG_X86_PAE /* Init entries of the first-level page table to the zero page */ for (i = 0; i < PTRS_PER_PGD; i++) set_pgd(pgd_base + i, __pgd(__pa(empty_zero_page) | _PAGE_PRESENT)); +#else + paravirt_alloc_pd(__pa(swapper_pg_dir) >> PAGE_SHIFT); #endif /* Enable PSE if available */ diff --git a/arch/i386/mm/pageattr.c b/arch/i386/mm/pageattr.c index ad91528..412ebbd 100644 --- a/arch/i386/mm/pageattr.c +++ b/arch/i386/mm/pageattr.c @@ -60,6 +60,7 @@ static struct page *split_large_page(uns address = __pa(address); addr = address & LARGE_PAGE_MASK; pbase = (pte_t *)page_address(base); + paravirt_alloc_pt(page_to_pfn(base)); for (i = 0; i < PTRS_PER_PTE; i++, addr += PAGE_SIZE) { set_pte(&pbase[i], pfn_pte(addr >> PAGE_SHIFT, addr == address ? prot : ref_prot)); @@ -172,6 +173,7 @@ __change_page_attr(struct page *page, pg if (!PageReserved(kpte_page)) { if (cpu_has_pse && (page_private(kpte_page) == 0)) { ClearPagePrivate(kpte_page); + paravirt_release_pt(page_to_pfn(kpte_page)); list_add(&kpte_page->lru, &df_list); revert_page(kpte_page, address); } @@ -224,7 +226,7 @@ void global_flush_tlb(void) list_replace_init(&df_list, &l); spin_unlock_irq(&cpa_lock); if (!cpu_has_clflush) - flush_map(0); + flush_map(NULL); list_for_each_entry_safe(pg, next, &l, lru) { if (cpu_has_clflush) flush_map(page_address(pg)); diff --git a/arch/i386/mm/pgtable.c b/arch/i386/mm/pgtable.c index f349eaf..fa0cfbd 100644 --- a/arch/i386/mm/pgtable.c +++ b/arch/i386/mm/pgtable.c @@ -171,6 +171,8 @@ void __set_fixmap (enum fixed_addresses void reserve_top_address(unsigned long reserve) { BUG_ON(fixmaps > 0); + printk(KERN_INFO "Reserving virtual address space above 0x%08x\n", + (int)-reserve); #ifdef CONFIG_COMPAT_VDSO BUG_ON(reserve != 0); #else @@ -248,9 +250,15 @@ void pgd_ctor(void *pgd, struct kmem_cac clone_pgd_range((pgd_t *)pgd + USER_PTRS_PER_PGD, swapper_pg_dir + USER_PTRS_PER_PGD, KERNEL_PGD_PTRS); + if (PTRS_PER_PMD > 1) return; + /* must happen under lock */ + paravirt_alloc_pd_clone(__pa(pgd) >> PAGE_SHIFT, + __pa(swapper_pg_dir) >> PAGE_SHIFT, + USER_PTRS_PER_PGD, PTRS_PER_PGD - USER_PTRS_PER_PGD); + pgd_list_add(pgd); spin_unlock_irqrestore(&pgd_lock, flags); } @@ -260,6 +268,7 @@ void pgd_dtor(void *pgd, struct kmem_cac { unsigned long flags; /* can be called from interrupt context */ + paravirt_release_pd(__pa(pgd) >> PAGE_SHIFT); spin_lock_irqsave(&pgd_lock, flags); pgd_list_del(pgd); spin_unlock_irqrestore(&pgd_lock, flags); @@ -277,13 +286,18 @@ pgd_t *pgd_alloc(struct mm_struct *mm) pmd_t *pmd = kmem_cache_alloc(pmd_cache, GFP_KERNEL); if (!pmd) goto out_oom; + paravirt_alloc_pd(__pa(pmd) >> PAGE_SHIFT); set_pgd(&pgd[i], __pgd(1 + __pa(pmd))); } return pgd; out_oom: - for (i--; i >= 0; i--) - kmem_cache_free(pmd_cache, (void *)__va(pgd_val(pgd[i])-1)); + for (i--; i >= 0; i--) { + pgd_t pgdent = pgd[i]; + void* pmd = (void *)__va(pgd_val(pgdent)-1); + paravirt_release_pd(__pa(pmd) >> PAGE_SHIFT); + kmem_cache_free(pmd_cache, pmd); + } kmem_cache_free(pgd_cache, pgd); return NULL; } @@ -294,8 +308,12 @@ void pgd_free(pgd_t *pgd) /* in the PAE case user pgd entries are overwritten before usage */ if (PTRS_PER_PMD > 1) - for (i = 0; i < USER_PTRS_PER_PGD; ++i) - kmem_cache_free(pmd_cache, (void *)__va(pgd_val(pgd[i])-1)); + for (i = 0; i < USER_PTRS_PER_PGD; ++i) { + pgd_t pgdent = pgd[i]; + void* pmd = (void *)__va(pgd_val(pgdent)-1); + paravirt_release_pd(__pa(pmd) >> PAGE_SHIFT); + kmem_cache_free(pmd_cache, pmd); + } /* in the non-PAE case, free_pgtables() clears user pgd entries */ kmem_cache_free(pgd_cache, pgd); } diff --git a/arch/i386/oprofile/op_model_ppro.c b/arch/i386/oprofile/op_model_ppro.c index ca2447e..c554f52 100644 --- a/arch/i386/oprofile/op_model_ppro.c +++ b/arch/i386/oprofile/op_model_ppro.c @@ -24,7 +24,8 @@ #define NUM_CONTROLS 2 #define CTR_IS_RESERVED(msrs,c) (msrs->counters[(c)].addr ? 1 : 0) #define CTR_READ(l,h,msrs,c) do {rdmsr(msrs->counters[(c)].addr, (l), (h));} while (0) -#define CTR_WRITE(l,msrs,c) do {wrmsr(msrs->counters[(c)].addr, -(u32)(l), -1);} while (0) +#define CTR_32BIT_WRITE(l,msrs,c) \ + do {wrmsr(msrs->counters[(c)].addr, -(u32)(l), 0);} while (0) #define CTR_OVERFLOWED(n) (!((n) & (1U<<31))) #define CTRL_IS_RESERVED(msrs,c) (msrs->controls[(c)].addr ? 1 : 0) @@ -79,7 +80,7 @@ static void ppro_setup_ctrs(struct op_ms for (i = 0; i < NUM_COUNTERS; ++i) { if (unlikely(!CTR_IS_RESERVED(msrs,i))) continue; - CTR_WRITE(1, msrs, i); + CTR_32BIT_WRITE(1, msrs, i); } /* enable active counters */ @@ -87,7 +88,7 @@ static void ppro_setup_ctrs(struct op_ms if ((counter_config[i].enabled) && (CTR_IS_RESERVED(msrs,i))) { reset_value[i] = counter_config[i].count; - CTR_WRITE(counter_config[i].count, msrs, i); + CTR_32BIT_WRITE(counter_config[i].count, msrs, i); CTRL_READ(low, high, msrs, i); CTRL_CLEAR(low); @@ -116,7 +117,7 @@ static int ppro_check_ctrs(struct pt_reg CTR_READ(low, high, msrs, i); if (CTR_OVERFLOWED(low)) { oprofile_add_sample(regs, i); - CTR_WRITE(reset_value[i], msrs, i); + CTR_32BIT_WRITE(reset_value[i], msrs, i); } } diff --git a/arch/i386/pci/Makefile b/arch/i386/pci/Makefile index 1594d2f..44650e0 100644 --- a/arch/i386/pci/Makefile +++ b/arch/i386/pci/Makefile @@ -1,7 +1,7 @@ obj-y := i386.o init.o obj-$(CONFIG_PCI_BIOS) += pcbios.o -obj-$(CONFIG_PCI_MMCONFIG) += mmconfig.o direct.o +obj-$(CONFIG_PCI_MMCONFIG) += mmconfig.o direct.o mmconfig-shared.o obj-$(CONFIG_PCI_DIRECT) += direct.o pci-y := fixup.o diff --git a/arch/i386/pci/mmconfig-shared.c b/arch/i386/pci/mmconfig-shared.c new file mode 100644 index 0000000..747d8c6 --- /dev/null +++ b/arch/i386/pci/mmconfig-shared.c @@ -0,0 +1,264 @@ +/* + * mmconfig-shared.c - Low-level direct PCI config space access via + * MMCONFIG - common code between i386 and x86-64. + * + * This code does: + * - known chipset handling + * - ACPI decoding and validation + * + * Per-architecture code takes care of the mappings and accesses + * themselves. + */ + +#include +#include +#include +#include +#include + +#include "pci.h" + +/* aperture is up to 256MB but BIOS may reserve less */ +#define MMCONFIG_APER_MIN (2 * 1024*1024) +#define MMCONFIG_APER_MAX (256 * 1024*1024) + +DECLARE_BITMAP(pci_mmcfg_fallback_slots, 32*PCI_MMCFG_MAX_CHECK_BUS); + +/* K8 systems have some devices (typically in the builtin northbridge) + that are only accessible using type1 + Normally this can be expressed in the MCFG by not listing them + and assigning suitable _SEGs, but this isn't implemented in some BIOS. + Instead try to discover all devices on bus 0 that are unreachable using MM + and fallback for them. */ +static void __init unreachable_devices(void) +{ + int i, bus; + /* Use the max bus number from ACPI here? */ + for (bus = 0; bus < PCI_MMCFG_MAX_CHECK_BUS; bus++) { + for (i = 0; i < 32; i++) { + unsigned int devfn = PCI_DEVFN(i, 0); + u32 val1, val2; + + pci_conf1_read(0, bus, devfn, 0, 4, &val1); + if (val1 == 0xffffffff) + continue; + + if (pci_mmcfg_arch_reachable(0, bus, devfn)) { + raw_pci_ops->read(0, bus, devfn, 0, 4, &val2); + if (val1 == val2) + continue; + } + set_bit(i + 32 * bus, pci_mmcfg_fallback_slots); + printk(KERN_NOTICE "PCI: No mmconfig possible on device" + " %02x:%02x\n", bus, i); + } + } +} + +static const char __init *pci_mmcfg_e7520(void) +{ + u32 win; + pci_conf1_read(0, 0, PCI_DEVFN(0,0), 0xce, 2, &win); + + pci_mmcfg_config_num = 1; + pci_mmcfg_config = kzalloc(sizeof(pci_mmcfg_config[0]), GFP_KERNEL); + if (!pci_mmcfg_config) + return NULL; + pci_mmcfg_config[0].address = (win & 0xf000) << 16; + pci_mmcfg_config[0].pci_segment = 0; + pci_mmcfg_config[0].start_bus_number = 0; + pci_mmcfg_config[0].end_bus_number = 255; + + return "Intel Corporation E7520 Memory Controller Hub"; +} + +static const char __init *pci_mmcfg_intel_945(void) +{ + u32 pciexbar, mask = 0, len = 0; + + pci_mmcfg_config_num = 1; + + pci_conf1_read(0, 0, PCI_DEVFN(0,0), 0x48, 4, &pciexbar); + + /* Enable bit */ + if (!(pciexbar & 1)) + pci_mmcfg_config_num = 0; + + /* Size bits */ + switch ((pciexbar >> 1) & 3) { + case 0: + mask = 0xf0000000U; + len = 0x10000000U; + break; + case 1: + mask = 0xf8000000U; + len = 0x08000000U; + break; + case 2: + mask = 0xfc000000U; + len = 0x04000000U; + break; + default: + pci_mmcfg_config_num = 0; + } + + /* Errata #2, things break when not aligned on a 256Mb boundary */ + /* Can only happen in 64M/128M mode */ + + if ((pciexbar & mask) & 0x0fffffffU) + pci_mmcfg_config_num = 0; + + if (pci_mmcfg_config_num) { + pci_mmcfg_config = kzalloc(sizeof(pci_mmcfg_config[0]), GFP_KERNEL); + if (!pci_mmcfg_config) + return NULL; + pci_mmcfg_config[0].address = pciexbar & mask; + pci_mmcfg_config[0].pci_segment = 0; + pci_mmcfg_config[0].start_bus_number = 0; + pci_mmcfg_config[0].end_bus_number = (len >> 20) - 1; + } + + return "Intel Corporation 945G/GZ/P/PL Express Memory Controller Hub"; +} + +struct pci_mmcfg_hostbridge_probe { + u32 vendor; + u32 device; + const char *(*probe)(void); +}; + +static struct pci_mmcfg_hostbridge_probe pci_mmcfg_probes[] __initdata = { + { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_E7520_MCH, pci_mmcfg_e7520 }, + { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82945G_HB, pci_mmcfg_intel_945 }, +}; + +static int __init pci_mmcfg_check_hostbridge(void) +{ + u32 l; + u16 vendor, device; + int i; + const char *name; + + pci_conf1_read(0, 0, PCI_DEVFN(0,0), 0, 4, &l); + vendor = l & 0xffff; + device = (l >> 16) & 0xffff; + + pci_mmcfg_config_num = 0; + pci_mmcfg_config = NULL; + name = NULL; + + for (i = 0; !name && i < ARRAY_SIZE(pci_mmcfg_probes); i++) { + if (pci_mmcfg_probes[i].vendor == vendor && + pci_mmcfg_probes[i].device == device) + name = pci_mmcfg_probes[i].probe(); + } + + if (name) { + printk(KERN_INFO "PCI: Found %s %s MMCONFIG support.\n", + name, pci_mmcfg_config_num ? "with" : "without"); + } + + return name != NULL; +} + +static void __init pci_mmcfg_insert_resources(void) +{ +#define PCI_MMCFG_RESOURCE_NAME_LEN 19 + int i; + struct resource *res; + char *names; + unsigned num_buses; + + res = kcalloc(PCI_MMCFG_RESOURCE_NAME_LEN + sizeof(*res), + pci_mmcfg_config_num, GFP_KERNEL); + if (!res) { + printk(KERN_ERR "PCI: Unable to allocate MMCONFIG resources\n"); + return; + } + + names = (void *)&res[pci_mmcfg_config_num]; + for (i = 0; i < pci_mmcfg_config_num; i++, res++) { + struct acpi_mcfg_allocation *cfg = &pci_mmcfg_config[i]; + num_buses = cfg->end_bus_number - cfg->start_bus_number + 1; + res->name = names; + snprintf(names, PCI_MMCFG_RESOURCE_NAME_LEN, "PCI MMCONFIG %u", + cfg->pci_segment); + res->start = cfg->address; + res->end = res->start + (num_buses << 20) - 1; + res->flags = IORESOURCE_MEM | IORESOURCE_BUSY; + insert_resource(&iomem_resource, res); + names += PCI_MMCFG_RESOURCE_NAME_LEN; + } +} + +static void __init pci_mmcfg_reject_broken(int type) +{ + typeof(pci_mmcfg_config[0]) *cfg; + + if ((pci_mmcfg_config_num == 0) || + (pci_mmcfg_config == NULL) || + (pci_mmcfg_config[0].address == 0)) + return; + + cfg = &pci_mmcfg_config[0]; + + /* + * Handle more broken MCFG tables on Asus etc. + * They only contain a single entry for bus 0-0. + */ + if (pci_mmcfg_config_num == 1 && + cfg->pci_segment == 0 && + (cfg->start_bus_number | cfg->end_bus_number) == 0) { + printk(KERN_ERR "PCI: start and end of bus number is 0. " + "Rejected as broken MCFG.\n"); + goto reject; + } + + /* + * Only do this check when type 1 works. If it doesn't work + * assume we run on a Mac and always use MCFG + */ + if (type == 1 && !e820_all_mapped(cfg->address, + cfg->address + MMCONFIG_APER_MIN, + E820_RESERVED)) { + printk(KERN_ERR "PCI: BIOS Bug: MCFG area at %Lx is not" + " E820-reserved\n", cfg->address); + goto reject; + } + return; + +reject: + printk(KERN_ERR "PCI: Not using MMCONFIG.\n"); + kfree(pci_mmcfg_config); + pci_mmcfg_config = NULL; + pci_mmcfg_config_num = 0; +} + +void __init pci_mmcfg_init(int type) +{ + int known_bridge = 0; + + if ((pci_probe & PCI_PROBE_MMCONF) == 0) + return; + + if (type == 1 && pci_mmcfg_check_hostbridge()) + known_bridge = 1; + + if (!known_bridge) { + acpi_table_parse(ACPI_SIG_MCFG, acpi_parse_mcfg); + pci_mmcfg_reject_broken(type); + } + + if ((pci_mmcfg_config_num == 0) || + (pci_mmcfg_config == NULL) || + (pci_mmcfg_config[0].address == 0)) + return; + + if (pci_mmcfg_arch_init()) { + if (type == 1) + unreachable_devices(); + if (known_bridge) + pci_mmcfg_insert_resources(); + pci_probe = (pci_probe & ~PCI_PROBE_MASK) | PCI_PROBE_MMCONF; + } +} diff --git a/arch/i386/pci/mmconfig.c b/arch/i386/pci/mmconfig.c index e2616a2..bb1afd9 100644 --- a/arch/i386/pci/mmconfig.c +++ b/arch/i386/pci/mmconfig.c @@ -15,55 +15,33 @@ #include #include #include "pci.h" -/* aperture is up to 256MB but BIOS may reserve less */ -#define MMCONFIG_APER_MIN (2 * 1024*1024) -#define MMCONFIG_APER_MAX (256 * 1024*1024) - /* Assume systems with more busses have correct MCFG */ -#define MAX_CHECK_BUS 16 - #define mmcfg_virt_addr ((void __iomem *) fix_to_virt(FIX_PCIE_MCFG)) /* The base address of the last MMCONFIG device accessed */ static u32 mmcfg_last_accessed_device; static int mmcfg_last_accessed_cpu; -static DECLARE_BITMAP(fallback_slots, MAX_CHECK_BUS*32); - /* * Functions for accessing PCI configuration space with MMCONFIG accesses */ static u32 get_base_addr(unsigned int seg, int bus, unsigned devfn) { - int cfg_num = -1; - struct acpi_table_mcfg_config *cfg; + struct acpi_mcfg_allocation *cfg; + int cfg_num; - if (seg == 0 && bus < MAX_CHECK_BUS && - test_bit(PCI_SLOT(devfn) + 32*bus, fallback_slots)) + if (seg == 0 && bus < PCI_MMCFG_MAX_CHECK_BUS && + test_bit(PCI_SLOT(devfn) + 32*bus, pci_mmcfg_fallback_slots)) return 0; - while (1) { - ++cfg_num; - if (cfg_num >= pci_mmcfg_config_num) { - break; - } + for (cfg_num = 0; cfg_num < pci_mmcfg_config_num; cfg_num++) { cfg = &pci_mmcfg_config[cfg_num]; - if (cfg->pci_segment_group_number != seg) - continue; - if ((cfg->start_bus_number <= bus) && + if (cfg->pci_segment == seg && + (cfg->start_bus_number <= bus) && (cfg->end_bus_number >= bus)) - return cfg->base_address; + return cfg->address; } - /* Handle more broken MCFG tables on Asus etc. - They only contain a single entry for bus 0-0. Assume - this applies to all busses. */ - cfg = &pci_mmcfg_config[0]; - if (pci_mmcfg_config_num == 1 && - cfg->pci_segment_group_number == 0 && - (cfg->start_bus_number | cfg->end_bus_number) == 0) - return cfg->base_address; - /* Fall back to type 0 */ return 0; } @@ -125,7 +103,7 @@ static int pci_mmcfg_write(unsigned int unsigned long flags; u32 base; - if ((bus > 255) || (devfn > 255) || (reg > 4095)) + if ((bus > 255) || (devfn > 255) || (reg > 4095)) return -EINVAL; base = get_base_addr(seg, bus, devfn); @@ -158,67 +136,15 @@ static struct pci_raw_ops pci_mmcfg = { .write = pci_mmcfg_write, }; -/* K8 systems have some devices (typically in the builtin northbridge) - that are only accessible using type1 - Normally this can be expressed in the MCFG by not listing them - and assigning suitable _SEGs, but this isn't implemented in some BIOS. - Instead try to discover all devices on bus 0 that are unreachable using MM - and fallback for them. */ -static __init void unreachable_devices(void) +int __init pci_mmcfg_arch_reachable(unsigned int seg, unsigned int bus, + unsigned int devfn) { - int i, k; - unsigned long flags; - - for (k = 0; k < MAX_CHECK_BUS; k++) { - for (i = 0; i < 32; i++) { - u32 val1; - u32 addr; - - pci_conf1_read(0, k, PCI_DEVFN(i, 0), 0, 4, &val1); - if (val1 == 0xffffffff) - continue; - - /* Locking probably not needed, but safer */ - spin_lock_irqsave(&pci_config_lock, flags); - addr = get_base_addr(0, k, PCI_DEVFN(i, 0)); - if (addr != 0) - pci_exp_set_dev_base(addr, k, PCI_DEVFN(i, 0)); - if (addr == 0 || - readl((u32 __iomem *)mmcfg_virt_addr) != val1) { - set_bit(i + 32*k, fallback_slots); - printk(KERN_NOTICE - "PCI: No mmconfig possible on %x:%x\n", k, i); - } - spin_unlock_irqrestore(&pci_config_lock, flags); - } - } + return get_base_addr(seg, bus, devfn) != 0; } -void __init pci_mmcfg_init(int type) +int __init pci_mmcfg_arch_init(void) { - if ((pci_probe & PCI_PROBE_MMCONF) == 0) - return; - - acpi_table_parse(ACPI_MCFG, acpi_parse_mcfg); - if ((pci_mmcfg_config_num == 0) || - (pci_mmcfg_config == NULL) || - (pci_mmcfg_config[0].base_address == 0)) - return; - - /* Only do this check when type 1 works. If it doesn't work - assume we run on a Mac and always use MCFG */ - if (type == 1 && !e820_all_mapped(pci_mmcfg_config[0].base_address, - pci_mmcfg_config[0].base_address + MMCONFIG_APER_MIN, - E820_RESERVED)) { - printk(KERN_ERR "PCI: BIOS Bug: MCFG area at %x is not E820-reserved\n", - pci_mmcfg_config[0].base_address); - printk(KERN_ERR "PCI: Not using MMCONFIG.\n"); - return; - } - printk(KERN_INFO "PCI: Using MMCONFIG\n"); raw_pci_ops = &pci_mmcfg; - pci_probe = (pci_probe & ~PCI_PROBE_MASK) | PCI_PROBE_MMCONF; - - unreachable_devices(); + return 1; } diff --git a/arch/i386/pci/pci.h b/arch/i386/pci/pci.h index a0a2518..e58bae2 100644 --- a/arch/i386/pci/pci.h +++ b/arch/i386/pci/pci.h @@ -94,3 +94,13 @@ extern void pci_pcbios_init(void); extern void pci_mmcfg_init(int type); extern void pcibios_sort(void); +/* pci-mmconfig.c */ + +/* Verify the first 16 busses. We assume that systems with more busses + get MCFG right. */ +#define PCI_MMCFG_MAX_CHECK_BUS 16 +extern DECLARE_BITMAP(pci_mmcfg_fallback_slots, 32*PCI_MMCFG_MAX_CHECK_BUS); + +extern int __init pci_mmcfg_arch_reachable(unsigned int seg, unsigned int bus, + unsigned int devfn); +extern int __init pci_mmcfg_arch_init(void); diff --git a/arch/ia64/Kconfig b/arch/ia64/Kconfig index fcacfe2..d51f0f1 100644 --- a/arch/ia64/Kconfig +++ b/arch/ia64/Kconfig @@ -11,6 +11,8 @@ menu "Processor type and features" config IA64 bool + select PCI if (!IA64_HP_SIM) + select ACPI if (!IA64_HP_SIM) default y help The Itanium Processor Family is Intel's 64-bit successor to @@ -20,15 +22,19 @@ config IA64 config 64BIT bool + select ATA_NONSTANDARD if ATA default y +config ZONE_DMA + def_bool y + depends on !IA64_SGI_SN2 + config MMU bool default y config SWIOTLB bool - default y config RWSEM_XCHGADD_ALGORITHM bool @@ -84,10 +90,9 @@ choice config IA64_GENERIC bool "generic" - select ACPI - select PCI select NUMA select ACPI_NUMA + select SWIOTLB help This selects the system type of your hardware. A "generic" kernel will run on any supported IA-64 system. However, if you configure @@ -104,6 +109,7 @@ config IA64_GENERIC config IA64_DIG bool "DIG-compliant" + select SWIOTLB config IA64_HP_ZX1 bool "HP-zx1/sx1000" @@ -113,6 +119,7 @@ config IA64_HP_ZX1 config IA64_HP_ZX1_SWIOTLB bool "HP-zx1/sx1000 with software I/O TLB" + select SWIOTLB help Build a kernel that runs on HP zx1 and sx1000 systems even when they have broken PCI devices which cannot DMA to full 32 bits. Apart @@ -131,6 +138,7 @@ config IA64_SGI_SN2 config IA64_HP_SIM bool "Ski-simulator" + select SWIOTLB endchoice diff --git a/arch/ia64/hp/common/hwsw_iommu.c b/arch/ia64/hp/common/hwsw_iommu.c index a5a5637..2153bca 100644 --- a/arch/ia64/hp/common/hwsw_iommu.c +++ b/arch/ia64/hp/common/hwsw_iommu.c @@ -192,3 +192,7 @@ EXPORT_SYMBOL(hwsw_unmap_sg); EXPORT_SYMBOL(hwsw_dma_supported); EXPORT_SYMBOL(hwsw_alloc_coherent); EXPORT_SYMBOL(hwsw_free_coherent); +EXPORT_SYMBOL(hwsw_sync_single_for_cpu); +EXPORT_SYMBOL(hwsw_sync_single_for_device); +EXPORT_SYMBOL(hwsw_sync_sg_for_cpu); +EXPORT_SYMBOL(hwsw_sync_sg_for_device); diff --git a/arch/ia64/hp/common/sba_iommu.c b/arch/ia64/hp/common/sba_iommu.c index ce49fe3..c1dca22 100644 --- a/arch/ia64/hp/common/sba_iommu.c +++ b/arch/ia64/hp/common/sba_iommu.c @@ -1881,7 +1881,7 @@ ioc_open(struct inode *inode, struct fil return seq_open(file, &ioc_seq_ops); } -static struct file_operations ioc_fops = { +static const struct file_operations ioc_fops = { .open = ioc_open, .read = seq_read, .llseek = seq_lseek, diff --git a/arch/ia64/ia32/binfmt_elf32.c b/arch/ia64/ia32/binfmt_elf32.c index 578737e..c05bda6 100644 --- a/arch/ia64/ia32/binfmt_elf32.c +++ b/arch/ia64/ia32/binfmt_elf32.c @@ -91,9 +91,8 @@ ia64_elf32_init (struct pt_regs *regs) * it with privilege level 3 because the IVE uses non-privileged accesses to these * tables. IA-32 segmentation is used to protect against IA-32 accesses to them. */ - vma = kmem_cache_alloc(vm_area_cachep, GFP_KERNEL); + vma = kmem_cache_zalloc(vm_area_cachep, GFP_KERNEL); if (vma) { - memset(vma, 0, sizeof(*vma)); vma->vm_mm = current->mm; vma->vm_start = IA32_GDT_OFFSET; vma->vm_end = vma->vm_start + PAGE_SIZE; @@ -117,9 +116,8 @@ ia64_elf32_init (struct pt_regs *regs) * code is locked in specific gate page, which is pointed by pretcode * when setup_frame_ia32 */ - vma = kmem_cache_alloc(vm_area_cachep, GFP_KERNEL); + vma = kmem_cache_zalloc(vm_area_cachep, GFP_KERNEL); if (vma) { - memset(vma, 0, sizeof(*vma)); vma->vm_mm = current->mm; vma->vm_start = IA32_GATE_OFFSET; vma->vm_end = vma->vm_start + PAGE_SIZE; @@ -142,9 +140,8 @@ ia64_elf32_init (struct pt_regs *regs) * Install LDT as anonymous memory. This gives us all-zero segment descriptors * until a task modifies them via modify_ldt(). */ - vma = kmem_cache_alloc(vm_area_cachep, GFP_KERNEL); + vma = kmem_cache_zalloc(vm_area_cachep, GFP_KERNEL); if (vma) { - memset(vma, 0, sizeof(*vma)); vma->vm_mm = current->mm; vma->vm_start = IA32_LDT_OFFSET; vma->vm_end = vma->vm_start + PAGE_ALIGN(IA32_LDT_ENTRIES*IA32_LDT_ENTRY_SIZE); @@ -214,12 +211,10 @@ ia32_setup_arg_pages (struct linux_binpr bprm->loader += stack_base; bprm->exec += stack_base; - mpnt = kmem_cache_alloc(vm_area_cachep, GFP_KERNEL); + mpnt = kmem_cache_zalloc(vm_area_cachep, GFP_KERNEL); if (!mpnt) return -ENOMEM; - memset(mpnt, 0, sizeof(*mpnt)); - down_write(¤t->mm->mmap_sem); { mpnt->vm_mm = current->mm; diff --git a/arch/ia64/ia32/ia32_entry.S b/arch/ia64/ia32/ia32_entry.S index a32cd59..687e5fd 100644 --- a/arch/ia64/ia32/ia32_entry.S +++ b/arch/ia64/ia32/ia32_entry.S @@ -326,7 +326,7 @@ ia32_syscall_table: data8 sys_ni_syscall data8 compat_sys_wait4 data8 sys_swapoff /* 115 */ - data8 sys32_sysinfo + data8 compat_sys_sysinfo data8 sys32_ipc data8 sys_fsync data8 sys32_sigreturn diff --git a/arch/ia64/ia32/sys_ia32.c b/arch/ia64/ia32/sys_ia32.c index 957681c..d430d36 100644 --- a/arch/ia64/ia32/sys_ia32.c +++ b/arch/ia64/ia32/sys_ia32.c @@ -2209,74 +2209,6 @@ sys32_fstat64 (unsigned int fd, struct s return ret; } -struct sysinfo32 { - s32 uptime; - u32 loads[3]; - u32 totalram; - u32 freeram; - u32 sharedram; - u32 bufferram; - u32 totalswap; - u32 freeswap; - u16 procs; - u16 pad; - u32 totalhigh; - u32 freehigh; - u32 mem_unit; - char _f[8]; -}; - -asmlinkage long -sys32_sysinfo (struct sysinfo32 __user *info) -{ - struct sysinfo s; - long ret, err; - int bitcount = 0; - mm_segment_t old_fs = get_fs(); - - set_fs(KERNEL_DS); - ret = sys_sysinfo((struct sysinfo __user *) &s); - set_fs(old_fs); - /* Check to see if any memory value is too large for 32-bit and - * scale down if needed. - */ - if ((s.totalram >> 32) || (s.totalswap >> 32)) { - while (s.mem_unit < PAGE_SIZE) { - s.mem_unit <<= 1; - bitcount++; - } - s.totalram >>= bitcount; - s.freeram >>= bitcount; - s.sharedram >>= bitcount; - s.bufferram >>= bitcount; - s.totalswap >>= bitcount; - s.freeswap >>= bitcount; - s.totalhigh >>= bitcount; - s.freehigh >>= bitcount; - } - - if (!access_ok(VERIFY_WRITE, info, sizeof(*info))) - return -EFAULT; - - err = __put_user(s.uptime, &info->uptime); - err |= __put_user(s.loads[0], &info->loads[0]); - err |= __put_user(s.loads[1], &info->loads[1]); - err |= __put_user(s.loads[2], &info->loads[2]); - err |= __put_user(s.totalram, &info->totalram); - err |= __put_user(s.freeram, &info->freeram); - err |= __put_user(s.sharedram, &info->sharedram); - err |= __put_user(s.bufferram, &info->bufferram); - err |= __put_user(s.totalswap, &info->totalswap); - err |= __put_user(s.freeswap, &info->freeswap); - err |= __put_user(s.procs, &info->procs); - err |= __put_user (s.totalhigh, &info->totalhigh); - err |= __put_user (s.freehigh, &info->freehigh); - err |= __put_user (s.mem_unit, &info->mem_unit); - if (err) - return -EFAULT; - return ret; -} - asmlinkage long sys32_sched_rr_get_interval (pid_t pid, struct compat_timespec __user *interval) { diff --git a/arch/ia64/kernel/acpi.c b/arch/ia64/kernel/acpi.c index 29f05d4..9197d7b 100644 --- a/arch/ia64/kernel/acpi.c +++ b/arch/ia64/kernel/acpi.c @@ -55,7 +55,7 @@ #include #define BAD_MADT_ENTRY(entry, end) ( \ (!entry) || (unsigned long)entry + sizeof(*entry) > end || \ - ((acpi_table_entry_header *)entry)->length < sizeof(*entry)) + ((struct acpi_subtable_header *)entry)->length < sizeof(*entry)) #define PREFIX "ACPI: " @@ -67,16 +67,11 @@ EXPORT_SYMBOL(pm_power_off); unsigned int acpi_cpei_override; unsigned int acpi_cpei_phys_cpuid; -#define MAX_SAPICS 256 -u16 ia64_acpiid_to_sapicid[MAX_SAPICS] = {[0 ... MAX_SAPICS - 1] = -1 }; - -EXPORT_SYMBOL(ia64_acpiid_to_sapicid); - const char *acpi_get_sysname(void) { #ifdef CONFIG_IA64_GENERIC unsigned long rsdp_phys; - struct acpi20_table_rsdp *rsdp; + struct acpi_table_rsdp *rsdp; struct acpi_table_xsdt *xsdt; struct acpi_table_header *hdr; @@ -87,16 +82,16 @@ #ifdef CONFIG_IA64_GENERIC return "dig"; } - rsdp = (struct acpi20_table_rsdp *)__va(rsdp_phys); - if (strncmp(rsdp->signature, RSDP_SIG, sizeof(RSDP_SIG) - 1)) { + rsdp = (struct acpi_table_rsdp *)__va(rsdp_phys); + if (strncmp(rsdp->signature, ACPI_SIG_RSDP, sizeof(ACPI_SIG_RSDP) - 1)) { printk(KERN_ERR "ACPI 2.0 RSDP signature incorrect, default to \"dig\"\n"); return "dig"; } - xsdt = (struct acpi_table_xsdt *)__va(rsdp->xsdt_address); + xsdt = (struct acpi_table_xsdt *)__va(rsdp->xsdt_physical_address); hdr = &xsdt->header; - if (strncmp(hdr->signature, XSDT_SIG, sizeof(XSDT_SIG) - 1)) { + if (strncmp(hdr->signature, ACPI_SIG_XSDT, sizeof(ACPI_SIG_XSDT) - 1)) { printk(KERN_ERR "ACPI 2.0 XSDT signature incorrect, default to \"dig\"\n"); return "dig"; @@ -169,12 +164,12 @@ struct acpi_table_madt *acpi_madt __init static u8 has_8259; static int __init -acpi_parse_lapic_addr_ovr(acpi_table_entry_header * header, +acpi_parse_lapic_addr_ovr(struct acpi_subtable_header * header, const unsigned long end) { - struct acpi_table_lapic_addr_ovr *lapic; + struct acpi_madt_local_apic_override *lapic; - lapic = (struct acpi_table_lapic_addr_ovr *)header; + lapic = (struct acpi_madt_local_apic_override *)header; if (BAD_MADT_ENTRY(lapic, end)) return -EINVAL; @@ -187,22 +182,19 @@ acpi_parse_lapic_addr_ovr(acpi_table_ent } static int __init -acpi_parse_lsapic(acpi_table_entry_header * header, const unsigned long end) +acpi_parse_lsapic(struct acpi_subtable_header * header, const unsigned long end) { - struct acpi_table_lsapic *lsapic; + struct acpi_madt_local_sapic *lsapic; - lsapic = (struct acpi_table_lsapic *)header; + lsapic = (struct acpi_madt_local_sapic *)header; - if (BAD_MADT_ENTRY(lsapic, end)) - return -EINVAL; + /*Skip BAD_MADT_ENTRY check, as lsapic size could vary */ - if (lsapic->flags.enabled) { + if (lsapic->lapic_flags & ACPI_MADT_ENABLED) { #ifdef CONFIG_SMP smp_boot_data.cpu_phys_id[available_cpus] = (lsapic->id << 8) | lsapic->eid; #endif - ia64_acpiid_to_sapicid[lsapic->acpi_id] = - (lsapic->id << 8) | lsapic->eid; ++available_cpus; } @@ -211,11 +203,11 @@ #endif } static int __init -acpi_parse_lapic_nmi(acpi_table_entry_header * header, const unsigned long end) +acpi_parse_lapic_nmi(struct acpi_subtable_header * header, const unsigned long end) { - struct acpi_table_lapic_nmi *lacpi_nmi; + struct acpi_madt_local_apic_nmi *lacpi_nmi; - lacpi_nmi = (struct acpi_table_lapic_nmi *)header; + lacpi_nmi = (struct acpi_madt_local_apic_nmi *)header; if (BAD_MADT_ENTRY(lacpi_nmi, end)) return -EINVAL; @@ -225,11 +217,11 @@ acpi_parse_lapic_nmi(acpi_table_entry_he } static int __init -acpi_parse_iosapic(acpi_table_entry_header * header, const unsigned long end) +acpi_parse_iosapic(struct acpi_subtable_header * header, const unsigned long end) { - struct acpi_table_iosapic *iosapic; + struct acpi_madt_io_sapic *iosapic; - iosapic = (struct acpi_table_iosapic *)header; + iosapic = (struct acpi_madt_io_sapic *)header; if (BAD_MADT_ENTRY(iosapic, end)) return -EINVAL; @@ -240,13 +232,13 @@ acpi_parse_iosapic(acpi_table_entry_head static unsigned int __initdata acpi_madt_rev; static int __init -acpi_parse_plat_int_src(acpi_table_entry_header * header, +acpi_parse_plat_int_src(struct acpi_subtable_header * header, const unsigned long end) { - struct acpi_table_plat_int_src *plintsrc; + struct acpi_madt_interrupt_source *plintsrc; int vector; - plintsrc = (struct acpi_table_plat_int_src *)header; + plintsrc = (struct acpi_madt_interrupt_source *)header; if (BAD_MADT_ENTRY(plintsrc, end)) return -EINVAL; @@ -257,19 +249,19 @@ acpi_parse_plat_int_src(acpi_table_entry */ vector = iosapic_register_platform_intr(plintsrc->type, plintsrc->global_irq, - plintsrc->iosapic_vector, + plintsrc->io_sapic_vector, plintsrc->eid, plintsrc->id, - (plintsrc->flags.polarity == - 1) ? IOSAPIC_POL_HIGH : - IOSAPIC_POL_LOW, - (plintsrc->flags.trigger == - 1) ? IOSAPIC_EDGE : - IOSAPIC_LEVEL); + ((plintsrc->inti_flags & ACPI_MADT_POLARITY_MASK) == + ACPI_MADT_POLARITY_ACTIVE_HIGH) ? + IOSAPIC_POL_HIGH : IOSAPIC_POL_LOW, + ((plintsrc->inti_flags & ACPI_MADT_TRIGGER_MASK) == + ACPI_MADT_TRIGGER_EDGE) ? + IOSAPIC_EDGE : IOSAPIC_LEVEL); platform_intr_list[plintsrc->type] = vector; if (acpi_madt_rev > 1) { - acpi_cpei_override = plintsrc->plint_flags.cpei_override_flag; + acpi_cpei_override = plintsrc->flags & ACPI_MADT_CPEI_OVERRIDE; } /* @@ -324,30 +316,32 @@ unsigned int get_cpei_target_cpu(void) } static int __init -acpi_parse_int_src_ovr(acpi_table_entry_header * header, +acpi_parse_int_src_ovr(struct acpi_subtable_header * header, const unsigned long end) { - struct acpi_table_int_src_ovr *p; + struct acpi_madt_interrupt_override *p; - p = (struct acpi_table_int_src_ovr *)header; + p = (struct acpi_madt_interrupt_override *)header; if (BAD_MADT_ENTRY(p, end)) return -EINVAL; - iosapic_override_isa_irq(p->bus_irq, p->global_irq, - (p->flags.polarity == - 1) ? IOSAPIC_POL_HIGH : IOSAPIC_POL_LOW, - (p->flags.trigger == - 1) ? IOSAPIC_EDGE : IOSAPIC_LEVEL); + iosapic_override_isa_irq(p->source_irq, p->global_irq, + ((p->inti_flags & ACPI_MADT_POLARITY_MASK) == + ACPI_MADT_POLARITY_ACTIVE_HIGH) ? + IOSAPIC_POL_HIGH : IOSAPIC_POL_LOW, + ((p->inti_flags & ACPI_MADT_TRIGGER_MASK) == + ACPI_MADT_TRIGGER_EDGE) ? + IOSAPIC_EDGE : IOSAPIC_LEVEL); return 0; } static int __init -acpi_parse_nmi_src(acpi_table_entry_header * header, const unsigned long end) +acpi_parse_nmi_src(struct acpi_subtable_header * header, const unsigned long end) { - struct acpi_table_nmi_src *nmi_src; + struct acpi_madt_nmi_source *nmi_src; - nmi_src = (struct acpi_table_nmi_src *)header; + nmi_src = (struct acpi_madt_nmi_source *)header; if (BAD_MADT_ENTRY(nmi_src, end)) return -EINVAL; @@ -371,12 +365,12 @@ static void __init acpi_madt_oem_check(c } } -static int __init acpi_parse_madt(unsigned long phys_addr, unsigned long size) +static int __init acpi_parse_madt(struct acpi_table_header *table) { - if (!phys_addr || !size) + if (!table) return -EINVAL; - acpi_madt = (struct acpi_table_madt *)__va(phys_addr); + acpi_madt = (struct acpi_table_madt *)table; acpi_madt_rev = acpi_madt->header.revision; @@ -384,14 +378,14 @@ static int __init acpi_parse_madt(unsign #ifdef CONFIG_ITANIUM has_8259 = 1; /* Firmware on old Itanium systems is broken */ #else - has_8259 = acpi_madt->flags.pcat_compat; + has_8259 = acpi_madt->flags & ACPI_MADT_PCAT_COMPAT; #endif iosapic_system_init(has_8259); /* Get base address of IPI Message Block */ - if (acpi_madt->lapic_address) - ipi_base_addr = ioremap(acpi_madt->lapic_address, 0); + if (acpi_madt->address) + ipi_base_addr = ioremap(acpi_madt->address, 0); printk(KERN_INFO PREFIX "Local APIC address %p\n", ipi_base_addr); @@ -413,23 +407,24 @@ #define pxm_bit_set(bit) (set_bit(bit,(v #define pxm_bit_test(bit) (test_bit(bit,(void *)pxm_flag)) static struct acpi_table_slit __initdata *slit_table; -static int get_processor_proximity_domain(struct acpi_table_processor_affinity *pa) +static int get_processor_proximity_domain(struct acpi_srat_cpu_affinity *pa) { int pxm; - pxm = pa->proximity_domain; + pxm = pa->proximity_domain_lo; if (ia64_platform_is("sn2")) - pxm += pa->reserved[0] << 8; + pxm += pa->proximity_domain_hi[0] << 8; return pxm; } -static int get_memory_proximity_domain(struct acpi_table_memory_affinity *ma) +static int get_memory_proximity_domain(struct acpi_srat_mem_affinity *ma) { int pxm; pxm = ma->proximity_domain; - if (ia64_platform_is("sn2")) - pxm += ma->reserved1[0] << 8; + if (!ia64_platform_is("sn2")) + pxm &= 0xff; + return pxm; } @@ -442,7 +437,7 @@ void __init acpi_numa_slit_init(struct a u32 len; len = sizeof(struct acpi_table_header) + 8 - + slit->localities * slit->localities; + + slit->locality_count * slit->locality_count; if (slit->header.length != len) { printk(KERN_ERR "ACPI 2.0 SLIT: size mismatch: %d expected, %d actual\n", @@ -454,11 +449,11 @@ void __init acpi_numa_slit_init(struct a } void __init -acpi_numa_processor_affinity_init(struct acpi_table_processor_affinity *pa) +acpi_numa_processor_affinity_init(struct acpi_srat_cpu_affinity *pa) { int pxm; - if (!pa->flags.enabled) + if (!(pa->flags & ACPI_SRAT_CPU_ENABLED)) return; pxm = get_processor_proximity_domain(pa); @@ -467,14 +462,14 @@ acpi_numa_processor_affinity_init(struct pxm_bit_set(pxm); node_cpuid[srat_num_cpus].phys_id = - (pa->apic_id << 8) | (pa->lsapic_eid); + (pa->apic_id << 8) | (pa->local_sapic_eid); /* nid should be overridden as logical node id later */ node_cpuid[srat_num_cpus].nid = pxm; srat_num_cpus++; } void __init -acpi_numa_memory_affinity_init(struct acpi_table_memory_affinity *ma) +acpi_numa_memory_affinity_init(struct acpi_srat_mem_affinity *ma) { unsigned long paddr, size; int pxm; @@ -483,13 +478,11 @@ acpi_numa_memory_affinity_init(struct ac pxm = get_memory_proximity_domain(ma); /* fill node memory chunk structure */ - paddr = ma->base_addr_hi; - paddr = (paddr << 32) | ma->base_addr_lo; - size = ma->length_hi; - size = (size << 32) | ma->length_lo; + paddr = ma->base_address; + size = ma->length; /* Ignore disabled entries */ - if (!ma->flags.enabled) + if (!(ma->flags & ACPI_SRAT_MEM_ENABLED)) return; /* record this node in proximity bitmap */ @@ -560,16 +553,16 @@ void __init acpi_numa_arch_fixup(void) if (!slit_table) return; memset(numa_slit, -1, sizeof(numa_slit)); - for (i = 0; i < slit_table->localities; i++) { + for (i = 0; i < slit_table->locality_count; i++) { if (!pxm_bit_test(i)) continue; node_from = pxm_to_node(i); - for (j = 0; j < slit_table->localities; j++) { + for (j = 0; j < slit_table->locality_count; j++) { if (!pxm_bit_test(j)) continue; node_to = pxm_to_node(j); node_distance(node_from, node_to) = - slit_table->entry[i * slit_table->localities + j]; + slit_table->entry[i * slit_table->locality_count + j]; } } @@ -617,21 +610,21 @@ void acpi_unregister_gsi(u32 gsi) EXPORT_SYMBOL(acpi_unregister_gsi); -static int __init acpi_parse_fadt(unsigned long phys_addr, unsigned long size) +static int __init acpi_parse_fadt(struct acpi_table_header *table) { struct acpi_table_header *fadt_header; - struct fadt_descriptor *fadt; + struct acpi_table_fadt *fadt; - if (!phys_addr || !size) + if (!table) return -EINVAL; - fadt_header = (struct acpi_table_header *)__va(phys_addr); + fadt_header = (struct acpi_table_header *)table; if (fadt_header->revision != 3) return -ENODEV; /* Only deal with ACPI 2.0 FADT */ - fadt = (struct fadt_descriptor *)fadt_header; + fadt = (struct acpi_table_fadt *)fadt_header; - acpi_register_gsi(fadt->sci_int, ACPI_LEVEL_SENSITIVE, ACPI_ACTIVE_LOW); + acpi_register_gsi(fadt->sci_interrupt, ACPI_LEVEL_SENSITIVE, ACPI_ACTIVE_LOW); return 0; } @@ -658,7 +651,7 @@ int __init acpi_boot_init(void) * information -- the successor to MPS tables. */ - if (acpi_table_parse(ACPI_APIC, acpi_parse_madt) < 1) { + if (acpi_table_parse(ACPI_SIG_MADT, acpi_parse_madt) < 1) { printk(KERN_ERR PREFIX "Can't find MADT\n"); goto skip_madt; } @@ -666,40 +659,40 @@ int __init acpi_boot_init(void) /* Local APIC */ if (acpi_table_parse_madt - (ACPI_MADT_LAPIC_ADDR_OVR, acpi_parse_lapic_addr_ovr, 0) < 0) + (ACPI_MADT_TYPE_LOCAL_APIC_OVERRIDE, acpi_parse_lapic_addr_ovr, 0) < 0) printk(KERN_ERR PREFIX "Error parsing LAPIC address override entry\n"); - if (acpi_table_parse_madt(ACPI_MADT_LSAPIC, acpi_parse_lsapic, NR_CPUS) + if (acpi_table_parse_madt(ACPI_MADT_TYPE_LOCAL_SAPIC, acpi_parse_lsapic, NR_CPUS) < 1) printk(KERN_ERR PREFIX "Error parsing MADT - no LAPIC entries\n"); - if (acpi_table_parse_madt(ACPI_MADT_LAPIC_NMI, acpi_parse_lapic_nmi, 0) + if (acpi_table_parse_madt(ACPI_MADT_TYPE_LOCAL_APIC_NMI, acpi_parse_lapic_nmi, 0) < 0) printk(KERN_ERR PREFIX "Error parsing LAPIC NMI entry\n"); /* I/O APIC */ if (acpi_table_parse_madt - (ACPI_MADT_IOSAPIC, acpi_parse_iosapic, NR_IOSAPICS) < 1) + (ACPI_MADT_TYPE_IO_SAPIC, acpi_parse_iosapic, NR_IOSAPICS) < 1) printk(KERN_ERR PREFIX "Error parsing MADT - no IOSAPIC entries\n"); /* System-Level Interrupt Routing */ if (acpi_table_parse_madt - (ACPI_MADT_PLAT_INT_SRC, acpi_parse_plat_int_src, + (ACPI_MADT_TYPE_INTERRUPT_SOURCE, acpi_parse_plat_int_src, ACPI_MAX_PLATFORM_INTERRUPTS) < 0) printk(KERN_ERR PREFIX "Error parsing platform interrupt source entry\n"); if (acpi_table_parse_madt - (ACPI_MADT_INT_SRC_OVR, acpi_parse_int_src_ovr, 0) < 0) + (ACPI_MADT_TYPE_INTERRUPT_OVERRIDE, acpi_parse_int_src_ovr, 0) < 0) printk(KERN_ERR PREFIX "Error parsing interrupt source overrides entry\n"); - if (acpi_table_parse_madt(ACPI_MADT_NMI_SRC, acpi_parse_nmi_src, 0) < 0) + if (acpi_table_parse_madt(ACPI_MADT_TYPE_NMI_SOURCE, acpi_parse_nmi_src, 0) < 0) printk(KERN_ERR PREFIX "Error parsing NMI SRC entry\n"); skip_madt: @@ -709,7 +702,7 @@ int __init acpi_boot_init(void) * gets interrupts such as power and sleep buttons. If it's not * on a Legacy interrupt, it needs to be setup. */ - if (acpi_table_parse(ACPI_FADT, acpi_parse_fadt) < 1) + if (acpi_table_parse(ACPI_SIG_FADT, acpi_parse_fadt) < 1) printk(KERN_ERR PREFIX "Can't find FADT\n"); #ifdef CONFIG_SMP @@ -842,7 +835,7 @@ int acpi_map_lsapic(acpi_handle handle, { struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL }; union acpi_object *obj; - struct acpi_table_lsapic *lsapic; + struct acpi_madt_local_sapic *lsapic; cpumask_t tmp_map; long physid; int cpu; @@ -854,16 +847,16 @@ int acpi_map_lsapic(acpi_handle handle, return -EINVAL; obj = buffer.pointer; - if (obj->type != ACPI_TYPE_BUFFER || - obj->buffer.length < sizeof(*lsapic)) { + if (obj->type != ACPI_TYPE_BUFFER) + { kfree(buffer.pointer); return -EINVAL; } - lsapic = (struct acpi_table_lsapic *)obj->buffer.pointer; + lsapic = (struct acpi_madt_local_sapic *)obj->buffer.pointer; - if ((lsapic->header.type != ACPI_MADT_LSAPIC) || - (!lsapic->flags.enabled)) { + if ((lsapic->header.type != ACPI_MADT_TYPE_LOCAL_SAPIC) || + (!lsapic->lapic_flags & ACPI_MADT_ENABLED)) { kfree(buffer.pointer); return -EINVAL; } @@ -883,7 +876,6 @@ int acpi_map_lsapic(acpi_handle handle, cpu_set(cpu, cpu_present_map); ia64_cpu_to_sapicid[cpu] = physid; - ia64_acpiid_to_sapicid[lsapic->acpi_id] = ia64_cpu_to_sapicid[cpu]; *pcpu = cpu; return (0); @@ -893,14 +885,6 @@ EXPORT_SYMBOL(acpi_map_lsapic); int acpi_unmap_lsapic(int cpu) { - int i; - - for (i = 0; i < MAX_SAPICS; i++) { - if (ia64_acpiid_to_sapicid[i] == ia64_cpu_to_sapicid[cpu]) { - ia64_acpiid_to_sapicid[i] = -1; - break; - } - } ia64_cpu_to_sapicid[cpu] = -1; cpu_clear(cpu, cpu_present_map); @@ -920,7 +904,7 @@ acpi_map_iosapic(acpi_handle handle, u32 { struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL }; union acpi_object *obj; - struct acpi_table_iosapic *iosapic; + struct acpi_madt_io_sapic *iosapic; unsigned int gsi_base; int pxm, node; @@ -938,9 +922,9 @@ acpi_map_iosapic(acpi_handle handle, u32 return AE_OK; } - iosapic = (struct acpi_table_iosapic *)obj->buffer.pointer; + iosapic = (struct acpi_madt_io_sapic *)obj->buffer.pointer; - if (iosapic->header.type != ACPI_MADT_IOSAPIC) { + if (iosapic->header.type != ACPI_MADT_TYPE_IO_SAPIC) { kfree(buffer.pointer); return AE_OK; } diff --git a/arch/ia64/kernel/crash.c b/arch/ia64/kernel/crash.c index bc2f64d..5cdd2f5 100644 --- a/arch/ia64/kernel/crash.c +++ b/arch/ia64/kernel/crash.c @@ -52,7 +52,7 @@ extern void ia64_dump_cpu_regs(void *); static DEFINE_PER_CPU(struct elf_prstatus, elf_prstatus); void -crash_save_this_cpu() +crash_save_this_cpu(void) { void *buf; unsigned long cfm, sof, sol; @@ -79,6 +79,7 @@ crash_save_this_cpu() final_note(buf); } +#ifdef CONFIG_SMP static int kdump_wait_cpu_freeze(void) { @@ -91,6 +92,7 @@ kdump_wait_cpu_freeze(void) } return 1; } +#endif void machine_crash_shutdown(struct pt_regs *pt) @@ -116,6 +118,11 @@ #endif static void machine_kdump_on_init(void) { + if (!ia64_kimage) { + printk(KERN_NOTICE "machine_kdump_on_init(): " + "kdump not configured\n"); + return; + } local_irq_disable(); kexec_disable_iosapic(); machine_kexec(ia64_kimage); @@ -132,11 +139,12 @@ kdump_cpu_freeze(struct unw_frame_info * atomic_inc(&kdump_cpu_freezed); kdump_status[cpuid] = 1; mb(); - if (cpuid == 0) { - for (;;) - cpu_relax(); - } else +#ifdef CONFIG_HOTPLUG_CPU + if (cpuid != 0) ia64_jump_to_sal(&sal_boot_rendez_state[cpuid]); +#endif + for (;;) + cpu_relax(); } static int @@ -214,7 +222,7 @@ machine_crash_setup(void) if((ret = register_die_notifier(&kdump_init_notifier_nb)) != 0) return ret; #ifdef CONFIG_SYSCTL - register_sysctl_table(sys_table, 0); + register_sysctl_table(sys_table); #endif return 0; } diff --git a/arch/ia64/kernel/crash_dump.c b/arch/ia64/kernel/crash_dump.c index 83b8c91..da60e90 100644 --- a/arch/ia64/kernel/crash_dump.c +++ b/arch/ia64/kernel/crash_dump.c @@ -9,7 +9,8 @@ #include #include -#include +#include +#include /** * copy_oldmem_page - copy one page from "oldmem" diff --git a/arch/ia64/kernel/efi.c b/arch/ia64/kernel/efi.c index 0b25a7d..772ba6f 100644 --- a/arch/ia64/kernel/efi.c +++ b/arch/ia64/kernel/efi.c @@ -380,7 +380,7 @@ #if EFI_DEBUG #endif return __va(md->phys_addr); } - printk(KERN_WARNING "%s: no PAL-code memory-descriptor found", + printk(KERN_WARNING "%s: no PAL-code memory-descriptor found\n", __FUNCTION__); return NULL; } @@ -413,11 +413,10 @@ efi_init (void) efi_char16_t *c16; u64 efi_desc_size; char *cp, vendor[100] = "unknown"; - extern char saved_command_line[]; int i; /* it's too early to be able to use the standard kernel command line support... */ - for (cp = saved_command_line; *cp; ) { + for (cp = boot_command_line; *cp; ) { if (memcmp(cp, "mem=", 4) == 0) { mem_limit = memparse(cp + 4, &cp); } else if (memcmp(cp, "max_addr=", 9) == 0) { diff --git a/arch/ia64/kernel/entry.S b/arch/ia64/kernel/entry.S index 15234ed..e7873ee 100644 --- a/arch/ia64/kernel/entry.S +++ b/arch/ia64/kernel/entry.S @@ -1610,5 +1610,7 @@ sys_call_table: data8 sys_sync_file_range // 1300 data8 sys_tee data8 sys_vmsplice + data8 sys_ni_syscall // reserved for move_pages + data8 sys_getcpu .org sys_call_table + 8*NR_syscalls // guard against failures to increase NR_syscalls diff --git a/arch/ia64/kernel/iosapic.c b/arch/ia64/kernel/iosapic.c index 0fc5fb7..d6aab40 100644 --- a/arch/ia64/kernel/iosapic.c +++ b/arch/ia64/kernel/iosapic.c @@ -925,6 +925,11 @@ iosapic_unregister_intr (unsigned int gs /* Clear the interrupt controller descriptor */ idesc->chip = &no_irq_type; +#ifdef CONFIG_SMP + /* Clear affinity */ + cpus_setall(idesc->affinity); +#endif + /* Clear the interrupt information */ memset(&iosapic_intr_info[vector], 0, sizeof(struct iosapic_intr_info)); diff --git a/arch/ia64/kernel/irq_ia64.c b/arch/ia64/kernel/irq_ia64.c index ba3ba8b..456f57b 100644 --- a/arch/ia64/kernel/irq_ia64.c +++ b/arch/ia64/kernel/irq_ia64.c @@ -275,7 +275,7 @@ static struct irqaction ipi_irqaction = static struct irqaction resched_irqaction = { .handler = dummy_handler, - .flags = SA_INTERRUPT, + .flags = IRQF_DISABLED, .name = "resched" }; #endif diff --git a/arch/ia64/kernel/machine_kexec.c b/arch/ia64/kernel/machine_kexec.c index e2ccc9f..4f0f3b8 100644 --- a/arch/ia64/kernel/machine_kexec.c +++ b/arch/ia64/kernel/machine_kexec.c @@ -14,6 +14,7 @@ #include #include #include #include +#include #include #include #include @@ -68,22 +69,10 @@ void machine_kexec_cleanup(struct kimage { } -void machine_shutdown(void) -{ - int cpu; - - for_each_online_cpu(cpu) { - if (cpu != smp_processor_id()) - cpu_down(cpu); - } - kexec_disable_iosapic(); -} - /* * Do not allocate memory (or fail in any way) in machine_kexec(). * We are past the point of no return, committed to rebooting now. */ -extern void *efi_get_pal_addr(void); static void ia64_machine_kexec(struct unw_frame_info *info, void *arg) { struct kimage *image = arg; @@ -93,6 +82,7 @@ static void ia64_machine_kexec(struct un unsigned long vector; int ii; + BUG_ON(!image); if (image->type == KEXEC_TYPE_CRASH) { crash_save_this_cpu(); current->thread.ksp = (__u64)info->sw - 16; @@ -131,6 +121,7 @@ static void ia64_machine_kexec(struct un void machine_kexec(struct kimage *image) { + BUG_ON(!image); unw_init_running(ia64_machine_kexec, image); for(;;); } diff --git a/arch/ia64/kernel/msi_ia64.c b/arch/ia64/kernel/msi_ia64.c index 822e59a..0d05450 100644 --- a/arch/ia64/kernel/msi_ia64.c +++ b/arch/ia64/kernel/msi_ia64.c @@ -64,12 +64,17 @@ static void ia64_set_msi_irq_affinity(un } #endif /* CONFIG_SMP */ -int ia64_setup_msi_irq(unsigned int irq, struct pci_dev *pdev) +int ia64_setup_msi_irq(struct pci_dev *pdev, struct msi_desc *desc) { struct msi_msg msg; unsigned long dest_phys_id; - unsigned int vector; + unsigned int irq, vector; + irq = create_irq(); + if (irq < 0) + return irq; + + set_irq_msi(irq, desc); dest_phys_id = cpu_physical_id(first_cpu(cpu_online_map)); vector = irq; @@ -89,12 +94,12 @@ int ia64_setup_msi_irq(unsigned int irq, write_msi_msg(irq, &msg); set_irq_chip_and_handler(irq, &ia64_msi_chip, handle_edge_irq); - return 0; + return irq; } void ia64_teardown_msi_irq(unsigned int irq) { - return; /* no-op */ + destroy_irq(irq); } static void ia64_ack_msi_irq(unsigned int irq) @@ -126,12 +131,12 @@ #endif }; -int arch_setup_msi_irq(unsigned int irq, struct pci_dev *pdev) +int arch_setup_msi_irq(struct pci_dev *pdev, struct msi_desc *desc) { if (platform_setup_msi_irq) - return platform_setup_msi_irq(irq, pdev); + return platform_setup_msi_irq(pdev, desc); - return ia64_setup_msi_irq(irq, pdev); + return ia64_setup_msi_irq(pdev, desc); } void arch_teardown_msi_irq(unsigned int irq) diff --git a/arch/ia64/kernel/perfmon.c b/arch/ia64/kernel/perfmon.c index aa94f60..2ecb20b 100644 --- a/arch/ia64/kernel/perfmon.c +++ b/arch/ia64/kernel/perfmon.c @@ -521,19 +521,57 @@ pfm_sysctl_t pfm_sysctl; EXPORT_SYMBOL(pfm_sysctl); static ctl_table pfm_ctl_table[]={ - {1, "debug", &pfm_sysctl.debug, sizeof(int), 0666, NULL, &proc_dointvec, NULL,}, - {2, "debug_ovfl", &pfm_sysctl.debug_ovfl, sizeof(int), 0666, NULL, &proc_dointvec, NULL,}, - {3, "fastctxsw", &pfm_sysctl.fastctxsw, sizeof(int), 0600, NULL, &proc_dointvec, NULL,}, - {4, "expert_mode", &pfm_sysctl.expert_mode, sizeof(int), 0600, NULL, &proc_dointvec, NULL,}, - { 0, }, + { + .ctl_name = CTL_UNNUMBERED, + .procname = "debug", + .data = &pfm_sysctl.debug, + .maxlen = sizeof(int), + .mode = 0666, + .proc_handler = &proc_dointvec, + }, + { + .ctl_name = CTL_UNNUMBERED, + .procname = "debug_ovfl", + .data = &pfm_sysctl.debug_ovfl, + .maxlen = sizeof(int), + .mode = 0666, + .proc_handler = &proc_dointvec, + }, + { + .ctl_name = CTL_UNNUMBERED, + .procname = "fastctxsw", + .data = &pfm_sysctl.fastctxsw, + .maxlen = sizeof(int), + .mode = 0600, + .proc_handler = &proc_dointvec, + }, + { + .ctl_name = CTL_UNNUMBERED, + .procname = "expert_mode", + .data = &pfm_sysctl.expert_mode, + .maxlen = sizeof(int), + .mode = 0600, + .proc_handler = &proc_dointvec, + }, + {} }; static ctl_table pfm_sysctl_dir[] = { - {1, "perfmon", NULL, 0, 0755, pfm_ctl_table, }, - {0,}, + { + .ctl_name = CTL_UNNUMBERED, + .procname = "perfmon", + .mode = 0755, + .child = pfm_ctl_table, + }, + {} }; static ctl_table pfm_sysctl_root[] = { - {1, "kernel", NULL, 0, 0755, pfm_sysctl_dir, }, - {0,}, + { + .ctl_name = CTL_KERN, + .procname = "kernel", + .mode = 0755, + .child = pfm_sysctl_dir, + }, + {} }; static struct ctl_table_header *pfm_sysctl_header; @@ -621,7 +659,7 @@ EXPORT_PER_CPU_SYMBOL_GPL(pfm_syst_info) /* forward declaration */ -static struct file_operations pfm_file_ops; +static const struct file_operations pfm_file_ops; /* * forward declarations @@ -2126,7 +2164,7 @@ pfm_no_open(struct inode *irrelevant, st -static struct file_operations pfm_file_ops = { +static const struct file_operations pfm_file_ops = { .llseek = no_llseek, .read = pfm_read, .write = pfm_write, @@ -2301,12 +2339,11 @@ pfm_smpl_buffer_alloc(struct task_struct DPRINT(("smpl_buf @%p\n", smpl_buf)); /* allocate vma */ - vma = kmem_cache_alloc(vm_area_cachep, GFP_KERNEL); + vma = kmem_cache_zalloc(vm_area_cachep, GFP_KERNEL); if (!vma) { DPRINT(("Cannot allocate vma\n")); goto error_kmem; } - memset(vma, 0, sizeof(*vma)); /* * partially initialize the vma for the sampling buffer @@ -6597,7 +6634,7 @@ found: return 0; } -static struct file_operations pfm_proc_fops = { +static const struct file_operations pfm_proc_fops = { .open = pfm_proc_open, .read = seq_read, .llseek = seq_lseek, @@ -6689,7 +6726,7 @@ pfm_init(void) /* * create /proc/sys/kernel/perfmon (for debugging purposes) */ - pfm_sysctl_header = register_sysctl_table(pfm_sysctl_root, 0); + pfm_sysctl_header = register_sysctl_table(pfm_sysctl_root); /* * initialize all our spinlocks diff --git a/arch/ia64/kernel/process.c b/arch/ia64/kernel/process.c index 17685ab..ae96d41 100644 --- a/arch/ia64/kernel/process.c +++ b/arch/ia64/kernel/process.c @@ -34,6 +34,7 @@ #include #include #include #include +#include #include #include #include @@ -803,6 +804,21 @@ cpu_halt (void) ia64_pal_halt(min_power_state); } +void machine_shutdown(void) +{ +#ifdef CONFIG_HOTPLUG_CPU + int cpu; + + for_each_online_cpu(cpu) { + if (cpu != smp_processor_id()) + cpu_down(cpu); + } +#endif +#ifdef CONFIG_KEXEC + kexec_disable_iosapic(); +#endif +} + void machine_restart (char *restart_cmd) { diff --git a/arch/ia64/kernel/ptrace.c b/arch/ia64/kernel/ptrace.c index aa705e4..3f89187 100644 --- a/arch/ia64/kernel/ptrace.c +++ b/arch/ia64/kernel/ptrace.c @@ -607,7 +607,7 @@ find_thread_for_addr (struct task_struct */ list_for_each_safe(this, next, ¤t->children) { p = list_entry(this, struct task_struct, sibling); - if (p->mm != mm) + if (p->tgid != child->tgid) continue; if (thread_matches(p, addr)) { child = p; @@ -1405,6 +1405,7 @@ ptrace_disable (struct task_struct *chil struct ia64_psr *child_psr = ia64_psr(task_pt_regs(child)); /* make sure the single step/taken-branch trap bits are not set: */ + clear_tsk_thread_flag(child, TIF_SINGLESTEP); child_psr->ss = 0; child_psr->tb = 0; } @@ -1525,6 +1526,7 @@ sys_ptrace (long request, pid_t pid, uns * Make sure the single step/taken-branch trap bits * are not set: */ + clear_tsk_thread_flag(child, TIF_SINGLESTEP); ia64_psr(pt)->ss = 0; ia64_psr(pt)->tb = 0; @@ -1556,6 +1558,7 @@ sys_ptrace (long request, pid_t pid, uns goto out_tsk; clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE); + set_tsk_thread_flag(child, TIF_SINGLESTEP); if (request == PTRACE_SINGLESTEP) { ia64_psr(pt)->ss = 1; } else { @@ -1595,13 +1598,9 @@ sys_ptrace (long request, pid_t pid, uns } -void +static void syscall_trace (void) { - if (!test_thread_flag(TIF_SYSCALL_TRACE)) - return; - if (!(current->ptrace & PT_PTRACED)) - return; /* * The 0x80 provides a way for the tracing parent to * distinguish between a syscall stop and SIGTRAP delivery. @@ -1664,7 +1663,8 @@ syscall_trace_leave (long arg0, long arg audit_syscall_exit(success, result); } - if (test_thread_flag(TIF_SYSCALL_TRACE) + if ((test_thread_flag(TIF_SYSCALL_TRACE) + || test_thread_flag(TIF_SINGLESTEP)) && (current->ptrace & PT_PTRACED)) syscall_trace(); } diff --git a/arch/ia64/kernel/sal.c b/arch/ia64/kernel/sal.c index 20bad78..37c876f 100644 --- a/arch/ia64/kernel/sal.c +++ b/arch/ia64/kernel/sal.c @@ -194,9 +194,8 @@ static void __init chk_nointroute_opt(void) { char *cp; - extern char saved_command_line[]; - for (cp = saved_command_line; *cp; ) { + for (cp = boot_command_line; *cp; ) { if (memcmp(cp, "nointroute", 10) == 0) { no_int_routing = 1; printk ("no_int_routing on\n"); diff --git a/arch/ia64/kernel/salinfo.c b/arch/ia64/kernel/salinfo.c index e375a2f..af9f875 100644 --- a/arch/ia64/kernel/salinfo.c +++ b/arch/ia64/kernel/salinfo.c @@ -352,7 +352,7 @@ retry: return size; } -static struct file_operations salinfo_event_fops = { +static const struct file_operations salinfo_event_fops = { .open = salinfo_event_open, .read = salinfo_event_read, }; @@ -568,7 +568,7 @@ salinfo_log_write(struct file *file, con return count; } -static struct file_operations salinfo_data_fops = { +static const struct file_operations salinfo_data_fops = { .open = salinfo_log_open, .release = salinfo_log_release, .read = salinfo_log_read, diff --git a/arch/ia64/kernel/setup.c b/arch/ia64/kernel/setup.c index ad567b8..5fa09d1 100644 --- a/arch/ia64/kernel/setup.c +++ b/arch/ia64/kernel/setup.c @@ -262,7 +262,7 @@ #ifdef CONFIG_KEXEC * appropriate after a kernel panic. */ { - char *from = strstr(saved_command_line, "crashkernel="); + char *from = strstr(boot_command_line, "crashkernel="); unsigned long base, size; if (from) { size = memparse(from + 12, &from); @@ -463,7 +463,7 @@ setup_arch (char **cmdline_p) ia64_patch_vtop((u64) __start___vtop_patchlist, (u64) __end___vtop_patchlist); *cmdline_p = __va(ia64_boot_param->command_line); - strlcpy(saved_command_line, *cmdline_p, COMMAND_LINE_SIZE); + strlcpy(boot_command_line, *cmdline_p, COMMAND_LINE_SIZE); efi_init(); io_port_init(); @@ -569,34 +569,31 @@ #endif { 1UL << 1, "spontaneous deferral"}, { 1UL << 2, "16-byte atomic ops" } }; - char features[128], *cp, sep; + char features[128], *cp, *sep; struct cpuinfo_ia64 *c = v; unsigned long mask; unsigned long proc_freq; - int i; + int i, size; mask = c->features; /* build the feature string: */ - memcpy(features, " standard", 10); + memcpy(features, "standard", 9); cp = features; - sep = 0; - for (i = 0; i < (int) ARRAY_SIZE(feature_bits); ++i) { + size = sizeof(features); + sep = ""; + for (i = 0; i < ARRAY_SIZE(feature_bits) && size > 1; ++i) { if (mask & feature_bits[i].mask) { - if (sep) - *cp++ = sep; - sep = ','; - *cp++ = ' '; - strcpy(cp, feature_bits[i].feature_name); - cp += strlen(feature_bits[i].feature_name); + cp += snprintf(cp, size, "%s%s", sep, + feature_bits[i].feature_name), + sep = ", "; mask &= ~feature_bits[i].mask; + size = sizeof(features) - (cp - features); } } - if (mask) { - /* print unknown features as a hex value: */ - if (sep) - *cp++ = sep; - sprintf(cp, " 0x%lx", mask); + if (mask && size > 1) { + /* print unknown features as a hex value */ + snprintf(cp, size, "%s0x%lx", sep, mask); } proc_freq = cpufreq_quick_get(cpunum); @@ -612,7 +609,7 @@ #endif "model name : %s\n" "revision : %u\n" "archrev : %u\n" - "features :%s\n" /* don't change this---it _is_ right! */ + "features : %s\n" "cpu number : %lu\n" "cpu regs : %u\n" "cpu MHz : %lu.%06lu\n" diff --git a/arch/ia64/kernel/smp.c b/arch/ia64/kernel/smp.c index f4c7f77..55ddd80 100644 --- a/arch/ia64/kernel/smp.c +++ b/arch/ia64/kernel/smp.c @@ -221,13 +221,13 @@ send_IPI_self (int op) #ifdef CONFIG_KEXEC void -kdump_smp_send_stop() +kdump_smp_send_stop(void) { send_IPI_allbutself(IPI_KDUMP_CPU_STOP); } void -kdump_smp_send_init() +kdump_smp_send_init(void) { unsigned int cpu, self_cpu; self_cpu = smp_processor_id(); diff --git a/arch/ia64/kernel/traps.c b/arch/ia64/kernel/traps.c index ab68474..765cbe5 100644 --- a/arch/ia64/kernel/traps.c +++ b/arch/ia64/kernel/traps.c @@ -24,8 +24,6 @@ #include #include #include -extern spinlock_t timerlist_lock; - fpswa_interface_t *fpswa_interface; EXPORT_SYMBOL(fpswa_interface); @@ -53,34 +51,6 @@ trap_init (void) fpswa_interface = __va(ia64_boot_param->fpswa); } -/* - * Unlock any spinlocks which will prevent us from getting the message out (timerlist_lock - * is acquired through the console unblank code) - */ -void -bust_spinlocks (int yes) -{ - int loglevel_save = console_loglevel; - - if (yes) { - oops_in_progress = 1; - return; - } - -#ifdef CONFIG_VT - unblank_screen(); -#endif - oops_in_progress = 0; - /* - * OK, the message is on the console. Now we call printk() without - * oops_in_progress set so that printk will give klogd a poke. Hold onto - * your hats... - */ - console_loglevel = 15; /* NMI oopser may have shut the console up */ - printk(" "); - console_loglevel = loglevel_save; -} - void die (const char *str, struct pt_regs *regs, long err) { diff --git a/arch/ia64/kernel/vmlinux.lds.S b/arch/ia64/kernel/vmlinux.lds.S index d6083a0..25dd55e 100644 --- a/arch/ia64/kernel/vmlinux.lds.S +++ b/arch/ia64/kernel/vmlinux.lds.S @@ -111,12 +111,14 @@ #endif .init.data : AT(ADDR(.init.data) - LOAD_OFFSET) { *(.init.data) } +#ifdef CONFIG_BLK_DEV_INITRD .init.ramfs : AT(ADDR(.init.ramfs) - LOAD_OFFSET) { __initramfs_start = .; *(.init.ramfs) __initramfs_end = .; } +#endif . = ALIGN(16); .init.setup : AT(ADDR(.init.setup) - LOAD_OFFSET) @@ -157,6 +159,7 @@ #if defined(CONFIG_IA64_GENERIC) } #endif + . = ALIGN(8); __con_initcall_start = .; .con_initcall.init : AT(ADDR(.con_initcall.init) - LOAD_OFFSET) { *(.con_initcall.init) } diff --git a/arch/ia64/mm/contig.c b/arch/ia64/mm/contig.c index 1e79551..ca4d41e 100644 --- a/arch/ia64/mm/contig.c +++ b/arch/ia64/mm/contig.c @@ -30,47 +30,69 @@ static unsigned long max_gap; #endif /** - * show_mem - display a memory statistics summary + * show_mem - give short summary of memory stats * - * Just walks the pages in the system and describes where they're allocated. + * Shows a simple page count of reserved and used pages in the system. + * For discontig machines, it does this on a per-pgdat basis. */ -void -show_mem (void) +void show_mem(void) { - int i, total = 0, reserved = 0; - int shared = 0, cached = 0; + int i, total_reserved = 0; + int total_shared = 0, total_cached = 0; + unsigned long total_present = 0; + pg_data_t *pgdat; printk(KERN_INFO "Mem-info:\n"); show_free_areas(); - printk(KERN_INFO "Free swap: %6ldkB\n", nr_swap_pages<<(PAGE_SHIFT-10)); - i = max_mapnr; - for (i = 0; i < max_mapnr; i++) { - if (!pfn_valid(i)) { + printk(KERN_INFO "Node memory in pages:\n"); + for_each_online_pgdat(pgdat) { + unsigned long present; + unsigned long flags; + int shared = 0, cached = 0, reserved = 0; + + pgdat_resize_lock(pgdat, &flags); + present = pgdat->node_present_pages; + for(i = 0; i < pgdat->node_spanned_pages; i++) { + struct page *page; + if (pfn_valid(pgdat->node_start_pfn + i)) + page = pfn_to_page(pgdat->node_start_pfn + i); + else { #ifdef CONFIG_VIRTUAL_MEM_MAP - if (max_gap < LARGE_GAP) - continue; - i = vmemmap_find_next_valid_pfn(0, i) - 1; + if (max_gap < LARGE_GAP) + continue; #endif - continue; + i = vmemmap_find_next_valid_pfn(pgdat->node_id, + i) - 1; + continue; + } + if (PageReserved(page)) + reserved++; + else if (PageSwapCache(page)) + cached++; + else if (page_count(page)) + shared += page_count(page)-1; } - total++; - if (PageReserved(mem_map+i)) - reserved++; - else if (PageSwapCache(mem_map+i)) - cached++; - else if (page_count(mem_map + i)) - shared += page_count(mem_map + i) - 1; + pgdat_resize_unlock(pgdat, &flags); + total_present += present; + total_reserved += reserved; + total_cached += cached; + total_shared += shared; + printk(KERN_INFO "Node %4d: RAM: %11ld, rsvd: %8d, " + "shrd: %10d, swpd: %10d\n", pgdat->node_id, + present, reserved, shared, cached); } - printk(KERN_INFO "%d pages of RAM\n", total); - printk(KERN_INFO "%d reserved pages\n", reserved); - printk(KERN_INFO "%d pages shared\n", shared); - printk(KERN_INFO "%d pages swap cached\n", cached); - printk(KERN_INFO "%ld pages in page table cache\n", + printk(KERN_INFO "%ld pages of RAM\n", total_present); + printk(KERN_INFO "%d reserved pages\n", total_reserved); + printk(KERN_INFO "%d pages shared\n", total_shared); + printk(KERN_INFO "%d pages swap cached\n", total_cached); + printk(KERN_INFO "Total of %ld pages in page table cache\n", pgtable_quicklist_total_size()); + printk(KERN_INFO "%d free buffer pages\n", nr_free_buffer_pages()); } + /* physical address where the bootmem map is located */ unsigned long bootmap_start; @@ -177,7 +199,7 @@ find_memory (void) #ifdef CONFIG_CRASH_DUMP /* If we are doing a crash dump, we still need to know the real mem - * size before original memory map is * reset. */ + * size before original memory map is reset. */ saved_max_pfn = max_pfn; #endif } @@ -237,9 +259,11 @@ paging_init (void) num_physpages = 0; efi_memmap_walk(count_pages, &num_physpages); - max_dma = virt_to_phys((void *) MAX_DMA_ADDRESS) >> PAGE_SHIFT; memset(max_zone_pfns, 0, sizeof(max_zone_pfns)); +#ifdef CONFIG_ZONE_DMA + max_dma = virt_to_phys((void *) MAX_DMA_ADDRESS) >> PAGE_SHIFT; max_zone_pfns[ZONE_DMA] = max_dma; +#endif max_zone_pfns[ZONE_NORMAL] = max_low_pfn; #ifdef CONFIG_VIRTUAL_MEM_MAP diff --git a/arch/ia64/mm/discontig.c b/arch/ia64/mm/discontig.c index 96722cb..1683510 100644 --- a/arch/ia64/mm/discontig.c +++ b/arch/ia64/mm/discontig.c @@ -37,7 +37,9 @@ struct early_node_data { unsigned long pernode_size; struct bootmem_data bootmem_data; unsigned long num_physpages; +#ifdef CONFIG_ZONE_DMA unsigned long num_dma_physpages; +#endif unsigned long min_pfn; unsigned long max_pfn; }; @@ -412,37 +414,6 @@ static void __init memory_less_nodes(voi return; } -#ifdef CONFIG_SPARSEMEM -/** - * register_sparse_mem - notify SPARSEMEM that this memory range exists. - * @start: physical start of range - * @end: physical end of range - * @arg: unused - * - * Simply calls SPARSEMEM to register memory section(s). - */ -static int __init register_sparse_mem(unsigned long start, unsigned long end, - void *arg) -{ - int nid; - - start = __pa(start) >> PAGE_SHIFT; - end = __pa(end) >> PAGE_SHIFT; - nid = early_pfn_to_nid(start); - memory_present(nid, start, end); - - return 0; -} - -static void __init arch_sparse_init(void) -{ - efi_memmap_walk(register_sparse_mem, NULL); - sparse_init(); -} -#else -#define arch_sparse_init() do {} while (0) -#endif - /** * find_memory - walk the EFI memory map and setup the bootmem allocator * @@ -473,6 +444,9 @@ void __init find_memory(void) node_clear(node, memory_less_mask); mem_data[node].min_pfn = ~0UL; } + + efi_memmap_walk(register_active_ranges, NULL); + /* * Initialize the boot memory maps in reverse order since that's * what the bootmem allocator expects @@ -506,6 +480,12 @@ void __init find_memory(void) max_pfn = max_low_pfn; find_initrd(); + +#ifdef CONFIG_CRASH_DUMP + /* If we are doing a crash dump, we still need to know the real mem + * size before original memory map is reset. */ + saved_max_pfn = max_pfn; +#endif } #ifdef CONFIG_SMP @@ -654,11 +634,12 @@ static __init int count_node_pages(unsig { unsigned long end = start + len; - add_active_range(node, start >> PAGE_SHIFT, end >> PAGE_SHIFT); mem_data[node].num_physpages += len >> PAGE_SHIFT; +#ifdef CONFIG_ZONE_DMA if (start <= __pa(MAX_DMA_ADDRESS)) mem_data[node].num_dma_physpages += (min(end, __pa(MAX_DMA_ADDRESS)) - start) >>PAGE_SHIFT; +#endif start = GRANULEROUNDDOWN(start); start = ORDERROUNDDOWN(start); end = GRANULEROUNDUP(end); @@ -686,10 +667,11 @@ void __init paging_init(void) max_dma = virt_to_phys((void *) MAX_DMA_ADDRESS) >> PAGE_SHIFT; - arch_sparse_init(); - efi_memmap_walk(filter_rsvd_memory, count_node_pages); + sparse_memory_present_with_active_regions(MAX_NUMNODES); + sparse_init(); + #ifdef CONFIG_VIRTUAL_MEM_MAP vmalloc_end -= PAGE_ALIGN(ALIGN(max_low_pfn, MAX_ORDER_NR_PAGES) * sizeof(struct page)); @@ -710,7 +692,9 @@ #endif } memset(max_zone_pfns, 0, sizeof(max_zone_pfns)); +#ifdef CONFIG_ZONE_DMA max_zone_pfns[ZONE_DMA] = max_dma; +#endif max_zone_pfns[ZONE_NORMAL] = max_pfn; free_area_init_nodes(max_zone_pfns); diff --git a/arch/ia64/mm/init.c b/arch/ia64/mm/init.c index 1373fae..f225dd7 100644 --- a/arch/ia64/mm/init.c +++ b/arch/ia64/mm/init.c @@ -19,6 +19,7 @@ #include #include #include #include +#include #include #include @@ -67,7 +68,7 @@ max_pgt_pages(void) #ifndef CONFIG_NUMA node_free_pages = nr_free_pages(); #else - node_free_pages = nr_free_pages_pgdat(NODE_DATA(numa_node_id())); + node_free_pages = node_page_state(numa_node_id(), NR_FREE_PAGES); #endif max_pgt_pages = node_free_pages / PGT_FRACTION_OF_NODE_MEM; max_pgt_pages = max(max_pgt_pages, MIN_PGT_PAGES); @@ -128,6 +129,25 @@ lazy_mmu_prot_update (pte_t pte) set_bit(PG_arch_1, &page->flags); /* mark page as clean */ } +/* + * Since DMA is i-cache coherent, any (complete) pages that were written via + * DMA can be marked as "clean" so that lazy_mmu_prot_update() doesn't have to + * flush them when they get mapped into an executable vm-area. + */ +void +dma_mark_clean(void *addr, size_t size) +{ + unsigned long pg_addr, end; + + pg_addr = PAGE_ALIGN((unsigned long) addr); + end = (unsigned long) addr + size; + while (pg_addr + PAGE_SIZE <= end) { + struct page *page = virt_to_page(pg_addr); + set_bit(PG_arch_1, &page->flags); + pg_addr += PAGE_SIZE; + } +} + inline void ia64_set_rbs_bot (void) { @@ -156,9 +176,8 @@ ia64_init_addr_space (void) * the problem. When the process attempts to write to the register backing store * for the first time, it will get a SEGFAULT in this case. */ - vma = kmem_cache_alloc(vm_area_cachep, GFP_KERNEL); + vma = kmem_cache_zalloc(vm_area_cachep, GFP_KERNEL); if (vma) { - memset(vma, 0, sizeof(*vma)); vma->vm_mm = current->mm; vma->vm_start = current->thread.rbs_bot & PAGE_MASK; vma->vm_end = vma->vm_start + PAGE_SIZE; @@ -175,9 +194,8 @@ ia64_init_addr_space (void) /* map NaT-page at address zero to speed up speculative dereferencing of NULL: */ if (!(current->personality & MMAP_PAGE_ZERO)) { - vma = kmem_cache_alloc(vm_area_cachep, GFP_KERNEL); + vma = kmem_cache_zalloc(vm_area_cachep, GFP_KERNEL); if (vma) { - memset(vma, 0, sizeof(*vma)); vma->vm_mm = current->mm; vma->vm_end = PAGE_SIZE; vma->vm_page_prot = __pgprot(pgprot_val(PAGE_READONLY) | _PAGE_MA_NAT); @@ -595,13 +613,27 @@ find_largest_hole (u64 start, u64 end, v return 0; } +#endif /* CONFIG_VIRTUAL_MEM_MAP */ + int __init register_active_ranges(u64 start, u64 end, void *arg) { - add_active_range(0, __pa(start) >> PAGE_SHIFT, __pa(end) >> PAGE_SHIFT); + int nid = paddr_to_nid(__pa(start)); + + if (nid < 0) + nid = 0; +#ifdef CONFIG_KEXEC + if (start > crashk_res.start && start < crashk_res.end) + start = crashk_res.end; + if (end > crashk_res.start && end < crashk_res.end) + end = crashk_res.start; +#endif + + if (start < end) + add_active_range(nid, __pa(start) >> PAGE_SHIFT, + __pa(end) >> PAGE_SHIFT); return 0; } -#endif /* CONFIG_VIRTUAL_MEM_MAP */ static int __init count_reserved_pages (u64 start, u64 end, void *arg) diff --git a/arch/ia64/sn/kernel/huberror.c b/arch/ia64/sn/kernel/huberror.c index abca6bd..fcf7f93 100644 --- a/arch/ia64/sn/kernel/huberror.c +++ b/arch/ia64/sn/kernel/huberror.c @@ -3,7 +3,7 @@ * License. See the file "COPYING" in the main directory of this archive * for more details. * - * Copyright (C) 1992 - 1997, 2000,2002-2005 Silicon Graphics, Inc. All rights reserved. + * Copyright (C) 1992 - 1997, 2000,2002-2007 Silicon Graphics, Inc. All rights reserved. */ #include @@ -38,12 +38,20 @@ static irqreturn_t hub_eint_handler(int (u64) nasid, 0, 0, 0, 0, 0, 0); if ((int)ret_stuff.v0) - panic("hubii_eint_handler(): Fatal TIO Error"); + panic("%s: Fatal %s Error", __FUNCTION__, + ((nasid & 1) ? "TIO" : "HUBII")); if (!(nasid & 1)) /* Not a TIO, handle CRB errors */ (void)hubiio_crb_error_handler(hubdev_info); - } else - bte_error_handler((unsigned long)NODEPDA(nasid_to_cnodeid(nasid))); + } else + if (nasid & 1) { /* TIO errors */ + SAL_CALL_NOLOCK(ret_stuff, SN_SAL_HUB_ERROR_INTERRUPT, + (u64) nasid, 0, 0, 0, 0, 0, 0); + + if ((int)ret_stuff.v0) + panic("%s: Fatal TIO Error", __FUNCTION__); + } else + bte_error_handler((unsigned long)NODEPDA(nasid_to_cnodeid(nasid))); return IRQ_HANDLED; } diff --git a/arch/ia64/sn/kernel/io_acpi_init.c b/arch/ia64/sn/kernel/io_acpi_init.c index cb96b4e..8c331ca 100644 --- a/arch/ia64/sn/kernel/io_acpi_init.c +++ b/arch/ia64/sn/kernel/io_acpi_init.c @@ -13,6 +13,7 @@ #include #include #include "xtalk/hubdev.h" #include +#include /* @@ -31,6 +32,12 @@ struct acpi_vendor_uuid sn_uuid = { 0xa2, 0x7c, 0x08, 0x00, 0x69, 0x13, 0xea, 0x51 }, }; +struct sn_pcidev_match { + u8 bus; + unsigned int devfn; + acpi_handle handle; +}; + /* * Perform the early IO init in PROM. */ @@ -119,9 +126,11 @@ sn_get_bussoft_ptr(struct pci_bus *bus) status = acpi_get_vendor_resource(handle, METHOD_NAME__CRS, &sn_uuid, &buffer); if (ACPI_FAILURE(status)) { - printk(KERN_ERR "get_acpi_pcibus_ptr: " - "get_acpi_bussoft_info() failed: %d\n", - status); + printk(KERN_ERR "%s: " + "acpi_get_vendor_resource() failed (0x%x) for: ", + __FUNCTION__, status); + acpi_ns_print_node_pathname(handle, NULL); + printk("\n"); return NULL; } resource = buffer.pointer; @@ -130,8 +139,8 @@ sn_get_bussoft_ptr(struct pci_bus *bus) if ((vendor->byte_length - sizeof(struct acpi_vendor_uuid)) != sizeof(struct pcibus_bussoft *)) { printk(KERN_ERR - "get_acpi_bussoft_ptr: Invalid vendor data " - "length %d\n", vendor->byte_length); + "%s: Invalid vendor data length %d\n", + __FUNCTION__, vendor->byte_length); kfree(buffer.pointer); return NULL; } @@ -143,34 +152,254 @@ sn_get_bussoft_ptr(struct pci_bus *bus) } /* - * sn_acpi_bus_fixup + * sn_extract_device_info - Extract the pcidev_info and the sn_irq_info + * pointers from the vendor resource using the + * provided acpi handle, and copy the structures + * into the argument buffers. */ -void -sn_acpi_bus_fixup(struct pci_bus *bus) +static int +sn_extract_device_info(acpi_handle handle, struct pcidev_info **pcidev_info, + struct sn_irq_info **sn_irq_info) { - struct pci_dev *pci_dev = NULL; - struct pcibus_bussoft *prom_bussoft_ptr; - extern void sn_common_bus_fixup(struct pci_bus *, - struct pcibus_bussoft *); + u64 addr; + struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL }; + struct sn_irq_info *irq_info, *irq_info_prom; + struct pcidev_info *pcidev_ptr, *pcidev_prom_ptr; + struct acpi_resource *resource; + int ret = 0; + acpi_status status; + struct acpi_resource_vendor_typed *vendor; - if (!bus->parent) { /* If root bus */ - prom_bussoft_ptr = sn_get_bussoft_ptr(bus); - if (prom_bussoft_ptr == NULL) { + /* + * The pointer to this device's pcidev_info structure in + * the PROM, is in the vendor resource. + */ + status = acpi_get_vendor_resource(handle, METHOD_NAME__CRS, + &sn_uuid, &buffer); + if (ACPI_FAILURE(status)) { + printk(KERN_ERR + "%s: acpi_get_vendor_resource() failed (0x%x) for: ", + __FUNCTION__, status); + acpi_ns_print_node_pathname(handle, NULL); + printk("\n"); + return 1; + } + + resource = buffer.pointer; + vendor = &resource->data.vendor_typed; + if ((vendor->byte_length - sizeof(struct acpi_vendor_uuid)) != + sizeof(struct pci_devdev_info *)) { + printk(KERN_ERR + "%s: Invalid vendor data length: %d for: ", + __FUNCTION__, vendor->byte_length); + acpi_ns_print_node_pathname(handle, NULL); + printk("\n"); + ret = 1; + goto exit; + } + + pcidev_ptr = kzalloc(sizeof(struct pcidev_info), GFP_KERNEL); + if (!pcidev_ptr) + panic("%s: Unable to alloc memory for pcidev_info", __FUNCTION__); + + memcpy(&addr, vendor->byte_data, sizeof(struct pcidev_info *)); + pcidev_prom_ptr = __va(addr); + memcpy(pcidev_ptr, pcidev_prom_ptr, sizeof(struct pcidev_info)); + + /* Get the IRQ info */ + irq_info = kzalloc(sizeof(struct sn_irq_info), GFP_KERNEL); + if (!irq_info) + panic("%s: Unable to alloc memory for sn_irq_info", __FUNCTION__); + + if (pcidev_ptr->pdi_sn_irq_info) { + irq_info_prom = __va(pcidev_ptr->pdi_sn_irq_info); + memcpy(irq_info, irq_info_prom, sizeof(struct sn_irq_info)); + } + + *pcidev_info = pcidev_ptr; + *sn_irq_info = irq_info; + +exit: + kfree(buffer.pointer); + return ret; +} + +static unsigned int +get_host_devfn(acpi_handle device_handle, acpi_handle rootbus_handle) +{ + unsigned long adr; + acpi_handle child; + unsigned int devfn; + int function; + acpi_handle parent; + int slot; + acpi_status status; + + /* + * Do an upward search to find the root bus device, and + * obtain the host devfn from the previous child device. + */ + child = device_handle; + while (child) { + status = acpi_get_parent(child, &parent); + if (ACPI_FAILURE(status)) { + printk(KERN_ERR "%s: acpi_get_parent() failed " + "(0x%x) for: ", __FUNCTION__, status); + acpi_ns_print_node_pathname(child, NULL); + printk("\n"); + panic("%s: Unable to find host devfn\n", __FUNCTION__); + } + if (parent == rootbus_handle) + break; + child = parent; + } + if (!child) { + printk(KERN_ERR "%s: Unable to find root bus for: ", + __FUNCTION__); + acpi_ns_print_node_pathname(device_handle, NULL); + printk("\n"); + BUG(); + } + + status = acpi_evaluate_integer(child, METHOD_NAME__ADR, NULL, &adr); + if (ACPI_FAILURE(status)) { + printk(KERN_ERR "%s: Unable to get _ADR (0x%x) for: ", + __FUNCTION__, status); + acpi_ns_print_node_pathname(child, NULL); + printk("\n"); + panic("%s: Unable to find host devfn\n", __FUNCTION__); + } + + slot = (adr >> 16) & 0xffff; + function = adr & 0xffff; + devfn = PCI_DEVFN(slot, function); + return devfn; +} + +/* + * find_matching_device - Callback routine to find the ACPI device + * that matches up with our pci_dev device. + * Matching is done on bus number and devfn. + * To find the bus number for a particular + * ACPI device, we must look at the _BBN method + * of its parent. + */ +static acpi_status +find_matching_device(acpi_handle handle, u32 lvl, void *context, void **rv) +{ + unsigned long bbn = -1; + unsigned long adr; + acpi_handle parent = NULL; + acpi_status status; + unsigned int devfn; + int function; + int slot; + struct sn_pcidev_match *info = context; + + status = acpi_evaluate_integer(handle, METHOD_NAME__ADR, NULL, + &adr); + if (ACPI_SUCCESS(status)) { + status = acpi_get_parent(handle, &parent); + if (ACPI_FAILURE(status)) { printk(KERN_ERR - "sn_pci_fixup_bus: 0x%04x:0x%02x Unable to " - "obtain prom_bussoft_ptr\n", - pci_domain_nr(bus), bus->number); - return; + "%s: acpi_get_parent() failed (0x%x) for: ", + __FUNCTION__, status); + acpi_ns_print_node_pathname(handle, NULL); + printk("\n"); + return AE_OK; + } + status = acpi_evaluate_integer(parent, METHOD_NAME__BBN, + NULL, &bbn); + if (ACPI_FAILURE(status)) { + printk(KERN_ERR + "%s: Failed to find _BBN in parent of: ", + __FUNCTION__); + acpi_ns_print_node_pathname(handle, NULL); + printk("\n"); + return AE_OK; + } + + slot = (adr >> 16) & 0xffff; + function = adr & 0xffff; + devfn = PCI_DEVFN(slot, function); + if ((info->devfn == devfn) && (info->bus == bbn)) { + /* We have a match! */ + info->handle = handle; + return 1; } - sn_common_bus_fixup(bus, prom_bussoft_ptr); } - list_for_each_entry(pci_dev, &bus->devices, bus_list) { - sn_pci_fixup_slot(pci_dev); + return AE_OK; +} + +/* + * sn_acpi_get_pcidev_info - Search ACPI namespace for the acpi + * device matching the specified pci_dev, + * and return the pcidev info and irq info. + */ +int +sn_acpi_get_pcidev_info(struct pci_dev *dev, struct pcidev_info **pcidev_info, + struct sn_irq_info **sn_irq_info) +{ + unsigned int host_devfn; + struct sn_pcidev_match pcidev_match; + acpi_handle rootbus_handle; + unsigned long segment; + acpi_status status; + + rootbus_handle = PCI_CONTROLLER(dev)->acpi_handle; + status = acpi_evaluate_integer(rootbus_handle, METHOD_NAME__SEG, NULL, + &segment); + if (ACPI_SUCCESS(status)) { + if (segment != pci_domain_nr(dev)) { + printk(KERN_ERR + "%s: Segment number mismatch, 0x%lx vs 0x%x for: ", + __FUNCTION__, segment, pci_domain_nr(dev)); + acpi_ns_print_node_pathname(rootbus_handle, NULL); + printk("\n"); + return 1; + } + } else { + printk(KERN_ERR "%s: Unable to get __SEG from: ", + __FUNCTION__); + acpi_ns_print_node_pathname(rootbus_handle, NULL); + printk("\n"); + return 1; + } + + /* + * We want to search all devices in this segment/domain + * of the ACPI namespace for the matching ACPI device, + * which holds the pcidev_info pointer in its vendor resource. + */ + pcidev_match.bus = dev->bus->number; + pcidev_match.devfn = dev->devfn; + pcidev_match.handle = NULL; + + acpi_walk_namespace(ACPI_TYPE_DEVICE, rootbus_handle, ACPI_UINT32_MAX, + find_matching_device, &pcidev_match, NULL); + + if (!pcidev_match.handle) { + printk(KERN_ERR + "%s: Could not find matching ACPI device for %s.\n", + __FUNCTION__, pci_name(dev)); + return 1; } + + if (sn_extract_device_info(pcidev_match.handle, pcidev_info, sn_irq_info)) + return 1; + + /* Build up the pcidev_info.pdi_slot_host_handle */ + host_devfn = get_host_devfn(pcidev_match.handle, rootbus_handle); + (*pcidev_info)->pdi_slot_host_handle = + ((unsigned long) pci_domain_nr(dev) << 40) | + /* bus == 0 */ + host_devfn; + return 0; } /* - * sn_acpi_slot_fixup - Perform any SN specific slot fixup. + * sn_acpi_slot_fixup - Obtain the pcidev_info and sn_irq_info. + * Perform any SN specific slot fixup. * At present there does not appear to be * any generic way to handle a ROM image * that has been shadowed by the PROM, so @@ -179,11 +408,18 @@ sn_acpi_bus_fixup(struct pci_bus *bus) */ void -sn_acpi_slot_fixup(struct pci_dev *dev, struct pcidev_info *pcidev_info) +sn_acpi_slot_fixup(struct pci_dev *dev) { void __iomem *addr; + struct pcidev_info *pcidev_info = NULL; + struct sn_irq_info *sn_irq_info = NULL; size_t size; + if (sn_acpi_get_pcidev_info(dev, &pcidev_info, &sn_irq_info)) { + panic("%s: Failure obtaining pcidev_info for %s\n", + __FUNCTION__, pci_name(dev)); + } + if (pcidev_info->pdi_pio_mapped_addr[PCI_ROM_RESOURCE]) { /* * A valid ROM image exists and has been shadowed by the @@ -200,8 +436,11 @@ sn_acpi_slot_fixup(struct pci_dev *dev, (unsigned long) addr + size; dev->resource[PCI_ROM_RESOURCE].flags |= IORESOURCE_ROM_BIOS_COPY; } + sn_pci_fixup_slot(dev, pcidev_info, sn_irq_info); } +EXPORT_SYMBOL(sn_acpi_slot_fixup); + static struct acpi_driver acpi_sn_hubdev_driver = { .name = "SGI HUBDEV Driver", .ids = "SGIHUB,SGITIO", @@ -212,6 +451,33 @@ static struct acpi_driver acpi_sn_hubdev /* + * sn_acpi_bus_fixup - Perform SN specific setup of software structs + * (pcibus_bussoft, pcidev_info) and hardware + * registers, for the specified bus and devices under it. + */ +void +sn_acpi_bus_fixup(struct pci_bus *bus) +{ + struct pci_dev *pci_dev = NULL; + struct pcibus_bussoft *prom_bussoft_ptr; + + if (!bus->parent) { /* If root bus */ + prom_bussoft_ptr = sn_get_bussoft_ptr(bus); + if (prom_bussoft_ptr == NULL) { + printk(KERN_ERR + "%s: 0x%04x:0x%02x Unable to " + "obtain prom_bussoft_ptr\n", + __FUNCTION__, pci_domain_nr(bus), bus->number); + return; + } + sn_common_bus_fixup(bus, prom_bussoft_ptr); + } + list_for_each_entry(pci_dev, &bus->devices, bus_list) { + sn_acpi_slot_fixup(pci_dev); + } +} + +/* * sn_io_acpi_init - PROM has ACPI support for IO, defining at a minimum the * nodes and root buses in the DSDT. As a result, bus scanning * will be initiated by the Linux ACPI code. diff --git a/arch/ia64/sn/kernel/io_common.c b/arch/ia64/sn/kernel/io_common.c index d4dd8f4..d48bcd8 100644 --- a/arch/ia64/sn/kernel/io_common.c +++ b/arch/ia64/sn/kernel/io_common.c @@ -26,14 +26,10 @@ #include "xtalk/xwidgetdev.h" #include #include #include +#include "acpi/acglobal.h" extern void sn_init_cpei_timer(void); extern void register_sn_procfs(void); -extern void sn_acpi_bus_fixup(struct pci_bus *); -extern void sn_bus_fixup(struct pci_bus *); -extern void sn_acpi_slot_fixup(struct pci_dev *, struct pcidev_info *); -extern void sn_more_slot_fixup(struct pci_dev *, struct pcidev_info *); -extern void sn_legacy_pci_window_fixup(struct pci_controller *, u64, u64); extern void sn_io_acpi_init(void); extern void sn_io_init(void); @@ -48,6 +44,9 @@ struct sysdata_el { int sn_ioif_inited; /* SN I/O infrastructure initialized? */ +int sn_acpi_rev; /* SN ACPI revision */ +EXPORT_SYMBOL_GPL(sn_acpi_rev); + struct sn_pcibus_provider *sn_pci_provider[PCIIO_ASIC_MAX_TYPES]; /* indexed by asic type */ /* @@ -99,25 +98,6 @@ sal_get_device_dmaflush_list(u64 nasid, } /* - * Retrieve the pci device information given the bus and device|function number. - */ -static inline u64 -sal_get_pcidev_info(u64 segment, u64 bus_number, u64 devfn, u64 pci_dev, - u64 sn_irq_info) -{ - struct ia64_sal_retval ret_stuff; - ret_stuff.status = 0; - ret_stuff.v0 = 0; - - SAL_CALL_NOLOCK(ret_stuff, - (u64) SN_SAL_IOIF_GET_PCIDEV_INFO, - (u64) segment, (u64) bus_number, (u64) devfn, - (u64) pci_dev, - sn_irq_info, 0, 0); - return ret_stuff.v0; -} - -/* * sn_pcidev_info_get() - Retrieve the pcidev_info struct for the specified * device. */ @@ -249,50 +229,25 @@ void sn_pci_unfixup_slot(struct pci_dev } /* - * sn_pci_fixup_slot() - This routine sets up a slot's resources consistent - * with the Linux PCI abstraction layer. Resources - * acquired from our PCI provider include PIO maps - * to BAR space and interrupt objects. + * sn_pci_fixup_slot() */ -void sn_pci_fixup_slot(struct pci_dev *dev) +void sn_pci_fixup_slot(struct pci_dev *dev, struct pcidev_info *pcidev_info, + struct sn_irq_info *sn_irq_info) { int segment = pci_domain_nr(dev->bus); - int status = 0; struct pcibus_bussoft *bs; - struct pci_bus *host_pci_bus; - struct pci_dev *host_pci_dev; - struct pcidev_info *pcidev_info; - struct sn_irq_info *sn_irq_info; - unsigned int bus_no, devfn; + struct pci_bus *host_pci_bus; + struct pci_dev *host_pci_dev; + unsigned int bus_no, devfn; pci_dev_get(dev); /* for the sysdata pointer */ - pcidev_info = kzalloc(sizeof(struct pcidev_info), GFP_KERNEL); - if (!pcidev_info) - BUG(); /* Cannot afford to run out of memory */ - - sn_irq_info = kzalloc(sizeof(struct sn_irq_info), GFP_KERNEL); - if (!sn_irq_info) - BUG(); /* Cannot afford to run out of memory */ - - /* Call to retrieve pci device information needed by kernel. */ - status = sal_get_pcidev_info((u64) segment, (u64) dev->bus->number, - dev->devfn, - (u64) __pa(pcidev_info), - (u64) __pa(sn_irq_info)); - if (status) - BUG(); /* Cannot get platform pci device information */ /* Add pcidev_info to list in pci_controller.platform_data */ list_add_tail(&pcidev_info->pdi_list, &(SN_PLATFORM_DATA(dev->bus)->pcidev_info)); - - if (SN_ACPI_BASE_SUPPORT()) - sn_acpi_slot_fixup(dev, pcidev_info); - else - sn_more_slot_fixup(dev, pcidev_info); /* * Using the PROMs values for the PCI host bus, get the Linux - * PCI host_pci_dev struct and set up host bus linkages + * PCI host_pci_dev struct and set up host bus linkages */ bus_no = (pcidev_info->pdi_slot_host_handle >> 32) & 0xff; @@ -489,11 +444,6 @@ void sn_generate_path(struct pci_bus *pc sprintf(address, "%s^%d", address, geo_slot(geoid)); } -/* - * sn_pci_fixup_bus() - Perform SN specific setup of software structs - * (pcibus_bussoft, pcidev_info) and hardware - * registers, for the specified bus and devices under it. - */ void __devinit sn_pci_fixup_bus(struct pci_bus *bus) { @@ -519,6 +469,15 @@ sn_io_early_init(void) if (!ia64_platform_is("sn2") || IS_RUNNING_ON_FAKE_PROM()) return 0; + /* we set the acpi revision to that of the DSDT table OEM rev. */ + { + struct acpi_table_header *header = NULL; + + acpi_get_table_by_index(ACPI_TABLE_INDEX_DSDT, &header); + BUG_ON(header == NULL); + sn_acpi_rev = header->oem_revision; + } + /* * prime sn_pci_provider[]. Individial provider init routines will * override their respective default entries. @@ -544,8 +503,12 @@ #ifdef CONFIG_PROC_FS register_sn_procfs(); #endif - printk(KERN_INFO "ACPI DSDT OEM Rev 0x%x\n", - acpi_gbl_DSDT->oem_revision); + { + struct acpi_table_header *header; + (void)acpi_get_table_by_index(ACPI_TABLE_INDEX_DSDT, &header); + printk(KERN_INFO "ACPI DSDT OEM Rev 0x%x\n", + header->oem_revision); + } if (SN_ACPI_BASE_SUPPORT()) sn_io_acpi_init(); else @@ -605,7 +568,6 @@ sn_io_late_init(void) fs_initcall(sn_io_late_init); -EXPORT_SYMBOL(sn_pci_fixup_slot); EXPORT_SYMBOL(sn_pci_unfixup_slot); EXPORT_SYMBOL(sn_bus_store_sysdata); EXPORT_SYMBOL(sn_bus_free_sysdata); diff --git a/arch/ia64/sn/kernel/io_init.c b/arch/ia64/sn/kernel/io_init.c index 9ad843e..600be3e 100644 --- a/arch/ia64/sn/kernel/io_init.c +++ b/arch/ia64/sn/kernel/io_init.c @@ -56,6 +56,25 @@ static inline u64 sal_get_pcibus_info(u6 return ret_stuff.v0; } +/* + * Retrieve the pci device information given the bus and device|function number. + */ +static inline u64 +sal_get_pcidev_info(u64 segment, u64 bus_number, u64 devfn, u64 pci_dev, + u64 sn_irq_info) +{ + struct ia64_sal_retval ret_stuff; + ret_stuff.status = 0; + ret_stuff.v0 = 0; + + SAL_CALL_NOLOCK(ret_stuff, + (u64) SN_SAL_IOIF_GET_PCIDEV_INFO, + (u64) segment, (u64) bus_number, (u64) devfn, + (u64) pci_dev, + sn_irq_info, 0, 0); + return ret_stuff.v0; +} + /* * sn_fixup_ionodes() - This routine initializes the HUB data structure for @@ -172,18 +191,40 @@ sn_pci_window_fixup(struct pci_dev *dev, } /* - * sn_more_slot_fixup() - We are not running with an ACPI capable PROM, + * sn_io_slot_fixup() - We are not running with an ACPI capable PROM, * and need to convert the pci_dev->resource * 'start' and 'end' addresses to mapped addresses, * and setup the pci_controller->window array entries. */ void -sn_more_slot_fixup(struct pci_dev *dev, struct pcidev_info *pcidev_info) +sn_io_slot_fixup(struct pci_dev *dev) { unsigned int count = 0; int idx; s64 pci_addrs[PCI_ROM_RESOURCE + 1]; unsigned long addr, end, size, start; + struct pcidev_info *pcidev_info; + struct sn_irq_info *sn_irq_info; + int status; + + pcidev_info = kzalloc(sizeof(struct pcidev_info), GFP_KERNEL); + if (!pcidev_info) + panic("%s: Unable to alloc memory for pcidev_info", __FUNCTION__); + + sn_irq_info = kzalloc(sizeof(struct sn_irq_info), GFP_KERNEL); + if (!sn_irq_info) + panic("%s: Unable to alloc memory for sn_irq_info", __FUNCTION__); + + /* Call to retrieve pci device information needed by kernel. */ + status = sal_get_pcidev_info((u64) pci_domain_nr(dev), + (u64) dev->bus->number, + dev->devfn, + (u64) __pa(pcidev_info), + (u64) __pa(sn_irq_info)); + + if (status) + BUG(); /* Cannot get platform pci device information */ + /* Copy over PIO Mapped Addresses */ for (idx = 0; idx <= PCI_ROM_RESOURCE; idx++) { @@ -219,8 +260,12 @@ sn_more_slot_fixup(struct pci_dev *dev, */ if (count > 0) sn_pci_window_fixup(dev, count, pci_addrs); + + sn_pci_fixup_slot(dev, pcidev_info, sn_irq_info); } +EXPORT_SYMBOL(sn_io_slot_fixup); + /* * sn_pci_controller_fixup() - This routine sets up a bus's resources * consistent with the Linux PCI abstraction layer. @@ -272,9 +317,6 @@ sn_bus_fixup(struct pci_bus *bus) { struct pci_dev *pci_dev = NULL; struct pcibus_bussoft *prom_bussoft_ptr; - extern void sn_common_bus_fixup(struct pci_bus *, - struct pcibus_bussoft *); - if (!bus->parent) { /* If root bus */ prom_bussoft_ptr = PCI_CONTROLLER(bus)->platform_data; @@ -291,7 +333,7 @@ sn_bus_fixup(struct pci_bus *bus) prom_bussoft_ptr->bs_legacy_mem); } list_for_each_entry(pci_dev, &bus->devices, bus_list) { - sn_pci_fixup_slot(pci_dev); + sn_io_slot_fixup(pci_dev); } } diff --git a/arch/ia64/sn/kernel/iomv.c b/arch/ia64/sn/kernel/iomv.c index 4aa4f30..ab7e2fd 100644 --- a/arch/ia64/sn/kernel/iomv.c +++ b/arch/ia64/sn/kernel/iomv.c @@ -1,4 +1,4 @@ -/* +/* * 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. @@ -26,9 +26,10 @@ #define IS_LEGACY_VGA_IOPORT(p) \ * @port: port to convert * * Legacy in/out instructions are converted to ld/st instructions - * on IA64. This routine will convert a port number into a valid + * on IA64. This routine will convert a port number into a valid * SN i/o address. Used by sn_in*() and sn_out*(). */ + void *sn_io_addr(unsigned long port) { if (!IS_RUNNING_ON_SIMULATOR()) { diff --git a/arch/ia64/sn/kernel/msi_sn.c b/arch/ia64/sn/kernel/msi_sn.c index b3a435f..ea3dc38 100644 --- a/arch/ia64/sn/kernel/msi_sn.c +++ b/arch/ia64/sn/kernel/msi_sn.c @@ -59,13 +59,12 @@ void sn_teardown_msi_irq(unsigned int ir sn_intr_free(nasid, widget, sn_irq_info); sn_msi_info[irq].sn_irq_info = NULL; - return; + destroy_irq(irq); } -int sn_setup_msi_irq(unsigned int irq, struct pci_dev *pdev) +int sn_setup_msi_irq(struct pci_dev *pdev, struct msi_desc *entry) { struct msi_msg msg; - struct msi_desc *entry; int widget; int status; nasid_t nasid; @@ -73,8 +72,8 @@ int sn_setup_msi_irq(unsigned int irq, s struct sn_irq_info *sn_irq_info; struct pcibus_bussoft *bussoft = SN_PCIDEV_BUSSOFT(pdev); struct sn_pcibus_provider *provider = SN_PCIDEV_BUSPROVIDER(pdev); + int irq; - entry = get_irq_data(irq); if (!entry->msi_attrib.is_64) return -EINVAL; @@ -84,6 +83,11 @@ int sn_setup_msi_irq(unsigned int irq, s if (provider == NULL || provider->dma_map_consistent == NULL) return -EINVAL; + irq = create_irq(); + if (irq < 0) + return irq; + + set_irq_msi(irq, entry); /* * Set up the vector plumbing. Let the prom (via sn_intr_alloc) * decide which cpu to direct this msi at by default. @@ -95,12 +99,15 @@ int sn_setup_msi_irq(unsigned int irq, s SWIN_WIDGETNUM(bussoft->bs_base); sn_irq_info = kzalloc(sizeof(struct sn_irq_info), GFP_KERNEL); - if (! sn_irq_info) + if (! sn_irq_info) { + destroy_irq(irq); return -ENOMEM; + } status = sn_intr_alloc(nasid, widget, sn_irq_info, irq, -1, -1); if (status) { kfree(sn_irq_info); + destroy_irq(irq); return -ENOMEM; } @@ -121,6 +128,7 @@ int sn_setup_msi_irq(unsigned int irq, s if (! bus_addr) { sn_intr_free(nasid, widget, sn_irq_info); kfree(sn_irq_info); + destroy_irq(irq); return -ENOMEM; } @@ -139,7 +147,7 @@ int sn_setup_msi_irq(unsigned int irq, s write_msi_msg(irq, &msg); set_irq_chip_and_handler(irq, &sn_msi_chip, handle_edge_irq); - return 0; + return irq; } #ifdef CONFIG_SMP diff --git a/arch/ia64/sn/kernel/sn2/sn2_smp.c b/arch/ia64/sn/kernel/sn2/sn2_smp.c index d9d306c..601747b 100644 --- a/arch/ia64/sn/kernel/sn2/sn2_smp.c +++ b/arch/ia64/sn/kernel/sn2/sn2_smp.c @@ -455,7 +455,7 @@ static int sn2_ptc_proc_open(struct inod return seq_open(file, &sn2_ptc_seq_ops); } -static struct file_operations proc_sn2_ptc_operations = { +static const struct file_operations proc_sn2_ptc_operations = { .open = sn2_ptc_proc_open, .read = seq_read, .llseek = seq_lseek, diff --git a/arch/ia64/sn/kernel/sn2/sn_hwperf.c b/arch/ia64/sn/kernel/sn2/sn_hwperf.c index 3336799..6da9854 100644 --- a/arch/ia64/sn/kernel/sn2/sn_hwperf.c +++ b/arch/ia64/sn/kernel/sn2/sn_hwperf.c @@ -865,7 +865,7 @@ error: return r; } -static struct file_operations sn_hwperf_fops = { +static const struct file_operations sn_hwperf_fops = { .ioctl = sn_hwperf_ioctl, }; diff --git a/arch/ia64/sn/kernel/sn2/sn_proc_fs.c b/arch/ia64/sn/kernel/sn2/sn_proc_fs.c index 43ddc2e..62b3e9a 100644 --- a/arch/ia64/sn/kernel/sn2/sn_proc_fs.c +++ b/arch/ia64/sn/kernel/sn2/sn_proc_fs.c @@ -89,61 +89,80 @@ static int coherence_id_open(struct inod return single_open(file, coherence_id_show, NULL); } -static struct proc_dir_entry -*sn_procfs_create_entry(const char *name, struct proc_dir_entry *parent, - int (*openfunc)(struct inode *, struct file *), - int (*releasefunc)(struct inode *, struct file *), - ssize_t (*write) (struct file *, const char __user *, size_t, loff_t *)) -{ - struct proc_dir_entry *e = create_proc_entry(name, 0444, parent); - - if (e) { - struct file_operations *f; - - f = kzalloc(sizeof(*f), GFP_KERNEL); - if (f) { - f->open = openfunc; - f->read = seq_read; - f->llseek = seq_lseek; - f->release = releasefunc; - f->write = write; - e->proc_fops = f; - } - } - - return e; -} - /* /proc/sgi_sn/sn_topology uses seq_file, see sn_hwperf.c */ extern int sn_topology_open(struct inode *, struct file *); extern int sn_topology_release(struct inode *, struct file *); +static const struct file_operations proc_partition_id_fops = { + .open = partition_id_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, +}; + +static const struct file_operations proc_system_sn_fops = { + .open = system_serial_number_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, +}; + +static const struct file_operations proc_license_id_fops = { + .open = licenseID_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, +}; + +static const struct file_operations proc_sn_force_intr_fops = { + .open = sn_force_interrupt_open, + .read = seq_read, + .write = sn_force_interrupt_write_proc, + .llseek = seq_lseek, + .release = single_release, +}; + +static const struct file_operations proc_coherence_id_fops = { + .open = coherence_id_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, +}; + +static const struct file_operations proc_sn_topo_fops = { + .open = sn_topology_open, + .read = seq_read, + .llseek = seq_lseek, + .release = sn_topology_release, +}; + void register_sn_procfs(void) { static struct proc_dir_entry *sgi_proc_dir = NULL; + struct proc_dir_entry *pde; BUG_ON(sgi_proc_dir != NULL); if (!(sgi_proc_dir = proc_mkdir("sgi_sn", NULL))) return; - sn_procfs_create_entry("partition_id", sgi_proc_dir, - partition_id_open, single_release, NULL); - - sn_procfs_create_entry("system_serial_number", sgi_proc_dir, - system_serial_number_open, single_release, NULL); - - sn_procfs_create_entry("licenseID", sgi_proc_dir, - licenseID_open, single_release, NULL); - - sn_procfs_create_entry("sn_force_interrupt", sgi_proc_dir, - sn_force_interrupt_open, single_release, - sn_force_interrupt_write_proc); - - sn_procfs_create_entry("coherence_id", sgi_proc_dir, - coherence_id_open, single_release, NULL); - - sn_procfs_create_entry("sn_topology", sgi_proc_dir, - sn_topology_open, sn_topology_release, NULL); + pde = create_proc_entry("partition_id", 0444, sgi_proc_dir); + if (pde) + pde->proc_fops = &proc_partition_id_fops; + pde = create_proc_entry("system_serial_number", 0444, sgi_proc_dir); + if (pde) + pde->proc_fops = &proc_system_sn_fops; + pde = create_proc_entry("licenseID", 0444, sgi_proc_dir); + if (pde) + pde->proc_fops = &proc_license_id_fops; + pde = create_proc_entry("sn_force_interrupt", 0644, sgi_proc_dir); + if (pde) + pde->proc_fops = &proc_sn_force_intr_fops; + pde = create_proc_entry("coherence_id", 0444, sgi_proc_dir); + if (pde) + pde->proc_fops = &proc_coherence_id_fops; + pde = create_proc_entry("sn_topology", 0444, sgi_proc_dir); + if (pde) + pde->proc_fops = &proc_sn_topo_fops; } #endif /* CONFIG_PROC_FS */ diff --git a/arch/ia64/sn/kernel/xpc_main.c b/arch/ia64/sn/kernel/xpc_main.c index 7a387d2..68355ef 100644 --- a/arch/ia64/sn/kernel/xpc_main.c +++ b/arch/ia64/sn/kernel/xpc_main.c @@ -101,67 +101,57 @@ static int xpc_disengage_request_max_tim static ctl_table xpc_sys_xpc_hb_dir[] = { { - 1, - "hb_interval", - &xpc_hb_interval, - sizeof(int), - 0644, - NULL, - &proc_dointvec_minmax, - &sysctl_intvec, - NULL, - &xpc_hb_min_interval, - &xpc_hb_max_interval + .ctl_name = CTL_UNNUMBERED, + .procname = "hb_interval", + .data = &xpc_hb_interval, + .maxlen = sizeof(int), + .mode = 0644, + .proc_handler = &proc_dointvec_minmax, + .strategy = &sysctl_intvec, + .extra1 = &xpc_hb_min_interval, + .extra2 = &xpc_hb_max_interval }, { - 2, - "hb_check_interval", - &xpc_hb_check_interval, - sizeof(int), - 0644, - NULL, - &proc_dointvec_minmax, - &sysctl_intvec, - NULL, - &xpc_hb_check_min_interval, - &xpc_hb_check_max_interval + .ctl_name = CTL_UNNUMBERED, + .procname = "hb_check_interval", + .data = &xpc_hb_check_interval, + .maxlen = sizeof(int), + .mode = 0644, + .proc_handler = &proc_dointvec_minmax, + .strategy = &sysctl_intvec, + .extra1 = &xpc_hb_check_min_interval, + .extra2 = &xpc_hb_check_max_interval }, - {0} + {} }; static ctl_table xpc_sys_xpc_dir[] = { { - 1, - "hb", - NULL, - 0, - 0555, - xpc_sys_xpc_hb_dir + .ctl_name = CTL_UNNUMBERED, + .procname = "hb", + .mode = 0555, + .child = xpc_sys_xpc_hb_dir }, { - 2, - "disengage_request_timelimit", - &xpc_disengage_request_timelimit, - sizeof(int), - 0644, - NULL, - &proc_dointvec_minmax, - &sysctl_intvec, - NULL, - &xpc_disengage_request_min_timelimit, - &xpc_disengage_request_max_timelimit + .ctl_name = CTL_UNNUMBERED, + .procname = "disengage_request_timelimit", + .data = &xpc_disengage_request_timelimit, + .maxlen = sizeof(int), + .mode = 0644, + .proc_handler = &proc_dointvec_minmax, + .strategy = &sysctl_intvec, + .extra1 = &xpc_disengage_request_min_timelimit, + .extra2 = &xpc_disengage_request_max_timelimit }, - {0} + {} }; static ctl_table xpc_sys_dir[] = { { - 1, - "xpc", - NULL, - 0, - 0555, - xpc_sys_xpc_dir + .ctl_name = CTL_UNNUMBERED, + .procname = "xpc", + .mode = 0555, + .child = xpc_sys_xpc_dir }, - {0} + {} }; static struct ctl_table_header *xpc_sysctl; @@ -1251,7 +1241,7 @@ xpc_init(void) snprintf(xpc_part->bus_id, BUS_ID_SIZE, "part"); snprintf(xpc_chan->bus_id, BUS_ID_SIZE, "chan"); - xpc_sysctl = register_sysctl_table(xpc_sys_dir, 1); + xpc_sysctl = register_sysctl_table(xpc_sys_dir); /* * The first few fields of each entry of xpc_partitions[] need to diff --git a/arch/ia64/sn/pci/pcibr/pcibr_provider.c b/arch/ia64/sn/pci/pcibr/pcibr_provider.c index 6846dc9..04a8256 100644 --- a/arch/ia64/sn/pci/pcibr/pcibr_provider.c +++ b/arch/ia64/sn/pci/pcibr/pcibr_provider.c @@ -20,7 +20,8 @@ #include "xtalk/xwidgetdev.h" #include "xtalk/hubdev.h" int -sal_pcibr_slot_enable(struct pcibus_info *soft, int device, void *resp) +sal_pcibr_slot_enable(struct pcibus_info *soft, int device, void *resp, + char **ssdt) { struct ia64_sal_retval ret_stuff; u64 busnum; @@ -32,7 +33,8 @@ sal_pcibr_slot_enable(struct pcibus_info segment = soft->pbi_buscommon.bs_persist_segment; busnum = soft->pbi_buscommon.bs_persist_busnum; SAL_CALL_NOLOCK(ret_stuff, (u64) SN_SAL_IOIF_SLOT_ENABLE, segment, - busnum, (u64) device, (u64) resp, 0, 0, 0); + busnum, (u64) device, (u64) resp, (u64)ia64_tpa(ssdt), + 0, 0); return (int)ret_stuff.v0; } diff --git a/arch/m32r/Kconfig b/arch/m32r/Kconfig index f383dab..9740d6b 100644 --- a/arch/m32r/Kconfig +++ b/arch/m32r/Kconfig @@ -16,6 +16,10 @@ config GENERIC_ISA_DMA bool default y +config ZONE_DMA + bool + default y + config GENERIC_HARDIRQS bool default y @@ -24,6 +28,9 @@ config GENERIC_IRQ_PROBE bool default y +config NO_IOPORT + def_bool y + source "init/Kconfig" diff --git a/arch/m32r/Makefile b/arch/m32r/Makefile index f219c47..cdf63b2 100644 --- a/arch/m32r/Makefile +++ b/arch/m32r/Makefile @@ -7,7 +7,7 @@ # LDFLAGS := OBJCOPYFLAGS := -O binary -R .note -R .comment -S -LDFLAGS_vmlinux := -e startup_32 +LDFLAGS_vmlinux := CFLAGS += -pipe -fno-schedule-insns CFLAGS_KERNEL += -mmodel=medium diff --git a/arch/m32r/defconfig b/arch/m32r/defconfig index 8530930..1357991 100644 --- a/arch/m32r/defconfig +++ b/arch/m32r/defconfig @@ -1,20 +1,18 @@ # # Automatically generated make config: don't edit -# Linux kernel version: 2.6.12-rc5 -# Fri Jun 3 16:20:11 2005 +# Linux kernel version: 2.6.19 +# Tue Dec 12 17:52:38 2006 # CONFIG_M32R=y -# CONFIG_UID16 is not set CONFIG_GENERIC_ISA_DMA=y CONFIG_GENERIC_HARDIRQS=y CONFIG_GENERIC_IRQ_PROBE=y +CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config" # # Code maturity level options # CONFIG_EXPERIMENTAL=y -CONFIG_CLEAN_COMPILE=y -CONFIG_BROKEN_ON_SMP=y CONFIG_LOCK_KERNEL=y CONFIG_INIT_ENV_ARG_LIMIT=32 @@ -22,32 +20,40 @@ # # General setup # CONFIG_LOCALVERSION="" +CONFIG_LOCALVERSION_AUTO=y CONFIG_SWAP=y CONFIG_SYSVIPC=y +# CONFIG_IPC_NS is not set # CONFIG_POSIX_MQUEUE is not set CONFIG_BSD_PROCESS_ACCT=y # CONFIG_BSD_PROCESS_ACCT_V3 is not set -CONFIG_SYSCTL=y +# CONFIG_TASKSTATS is not set +# CONFIG_UTS_NS is not set # CONFIG_AUDIT is not set -CONFIG_HOTPLUG=y -CONFIG_KOBJECT_UEVENT=y CONFIG_IKCONFIG=y -# CONFIG_IKCONFIG_PROC is not set +CONFIG_IKCONFIG_PROC=y +# CONFIG_CPUSETS is not set +CONFIG_SYSFS_DEPRECATED=y +# CONFIG_RELAY is not set +CONFIG_INITRAMFS_SOURCE="" +# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set +CONFIG_SYSCTL=y CONFIG_EMBEDDED=y +CONFIG_SYSCTL_SYSCALL=y # CONFIG_KALLSYMS is not set +CONFIG_HOTPLUG=y CONFIG_PRINTK=y CONFIG_BUG=y +CONFIG_ELF_CORE=y CONFIG_BASE_FULL=y # CONFIG_FUTEX is not set # CONFIG_EPOLL is not set -# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set CONFIG_SHMEM=y -CONFIG_CC_ALIGN_FUNCTIONS=0 -CONFIG_CC_ALIGN_LABELS=0 -CONFIG_CC_ALIGN_LOOPS=0 -CONFIG_CC_ALIGN_JUMPS=0 +CONFIG_SLAB=y +CONFIG_VM_EVENT_COUNTERS=y # CONFIG_TINY_SHMEM is not set CONFIG_BASE_SMALL=0 +# CONFIG_SLOB is not set # # Loadable module support @@ -55,10 +61,29 @@ # CONFIG_MODULES=y CONFIG_MODULE_UNLOAD=y # CONFIG_MODULE_FORCE_UNLOAD is not set -CONFIG_OBSOLETE_MODPARM=y # CONFIG_MODVERSIONS is not set # CONFIG_MODULE_SRCVERSION_ALL is not set CONFIG_KMOD=y +CONFIG_STOP_MACHINE=y + +# +# Block layer +# +CONFIG_BLOCK=y +# CONFIG_BLK_DEV_IO_TRACE is not set + +# +# IO Schedulers +# +CONFIG_IOSCHED_NOOP=y +# CONFIG_IOSCHED_AS is not set +CONFIG_IOSCHED_DEADLINE=y +CONFIG_IOSCHED_CFQ=y +# CONFIG_DEFAULT_AS is not set +# CONFIG_DEFAULT_DEADLINE is not set +CONFIG_DEFAULT_CFQ=y +# CONFIG_DEFAULT_NOOP is not set +CONFIG_DEFAULT_IOSCHED="cfq" # # Processor type and features @@ -70,8 +95,10 @@ # CONFIG_PLAT_OPSPUT is not set # CONFIG_PLAT_OAKS32R is not set # CONFIG_PLAT_MAPPI2 is not set # CONFIG_PLAT_MAPPI3 is not set +# CONFIG_PLAT_M32104UT is not set CONFIG_CHIP_M32700=y # CONFIG_CHIP_M32102 is not set +# CONFIG_CHIP_M32104 is not set # CONFIG_CHIP_VDEC2 is not set # CONFIG_CHIP_OPSP is not set CONFIG_MMU=y @@ -85,34 +112,39 @@ # CONFIG_CPU_LITTLE_ENDIAN is not set CONFIG_MEMORY_START=0x08000000 CONFIG_MEMORY_SIZE=0x01000000 CONFIG_NOHIGHMEM=y -# CONFIG_DISCONTIGMEM is not set +CONFIG_ARCH_DISCONTIGMEM_ENABLE=y +CONFIG_SELECT_MEMORY_MODEL=y +# CONFIG_FLATMEM_MANUAL is not set +CONFIG_DISCONTIGMEM_MANUAL=y +# CONFIG_SPARSEMEM_MANUAL is not set +CONFIG_DISCONTIGMEM=y +CONFIG_FLAT_NODE_MEM_MAP=y +CONFIG_NEED_MULTIPLE_NODES=y +# CONFIG_SPARSEMEM_STATIC is not set +CONFIG_SPLIT_PTLOCK_CPUS=4 +# CONFIG_RESOURCES_64BIT is not set +CONFIG_IRAM_START=0x00f00000 +CONFIG_IRAM_SIZE=0x00080000 CONFIG_RWSEM_GENERIC_SPINLOCK=y # CONFIG_RWSEM_XCHGADD_ALGORITHM is not set +CONFIG_GENERIC_FIND_NEXT_BIT=y +CONFIG_GENERIC_HWEIGHT=y CONFIG_GENERIC_CALIBRATE_DELAY=y CONFIG_PREEMPT=y -# CONFIG_HAVE_DEC_LOCK is not set -# CONFIG_SMP is not set +CONFIG_SMP=y +# CONFIG_CHIP_M32700_TS1 is not set +CONFIG_NR_CPUS=2 +CONFIG_NODES_SHIFT=1 # # Bus options (PCI, PCMCIA, EISA, MCA, ISA) # -# CONFIG_PCI is not set # CONFIG_ISA is not set # # PCCARD (PCMCIA/CardBus) support # -CONFIG_PCCARD=y -# CONFIG_PCMCIA_DEBUG is not set -CONFIG_PCMCIA=y - -# -# PC-card bridges -# -# CONFIG_TCIC is not set -# CONFIG_M32R_PCC is not set -CONFIG_M32R_CFC=y -CONFIG_M32R_CFC_NUM=1 +# CONFIG_PCCARD is not set # # PCI Hotplug Support @@ -125,6 +157,94 @@ CONFIG_BINFMT_ELF=y # CONFIG_BINFMT_MISC is not set # +# Networking +# +CONFIG_NET=y + +# +# Networking options +# +# CONFIG_NETDEBUG is not set +CONFIG_PACKET=y +# CONFIG_PACKET_MMAP is not set +CONFIG_UNIX=y +CONFIG_XFRM=y +# CONFIG_XFRM_USER is not set +# CONFIG_XFRM_SUB_POLICY is not set +# CONFIG_NET_KEY is not set +CONFIG_INET=y +# CONFIG_IP_MULTICAST is not set +# CONFIG_IP_ADVANCED_ROUTER is not set +CONFIG_IP_FIB_HASH=y +CONFIG_IP_PNP=y +CONFIG_IP_PNP_DHCP=y +# CONFIG_IP_PNP_BOOTP is not set +# CONFIG_IP_PNP_RARP is not set +# CONFIG_NET_IPIP is not set +# CONFIG_NET_IPGRE is not set +# CONFIG_ARPD is not set +# CONFIG_SYN_COOKIES is not set +# CONFIG_INET_AH is not set +# CONFIG_INET_ESP is not set +# CONFIG_INET_IPCOMP is not set +# CONFIG_INET_XFRM_TUNNEL is not set +# CONFIG_INET_TUNNEL is not set +CONFIG_INET_XFRM_MODE_TRANSPORT=y +CONFIG_INET_XFRM_MODE_TUNNEL=y +CONFIG_INET_XFRM_MODE_BEET=y +CONFIG_INET_DIAG=y +CONFIG_INET_TCP_DIAG=y +# CONFIG_TCP_CONG_ADVANCED is not set +CONFIG_TCP_CONG_CUBIC=y +CONFIG_DEFAULT_TCP_CONG="cubic" +# CONFIG_TCP_MD5SIG is not set +# CONFIG_IPV6 is not set +# CONFIG_INET6_XFRM_TUNNEL is not set +# CONFIG_INET6_TUNNEL is not set +# CONFIG_NETWORK_SECMARK is not set +# CONFIG_NETFILTER is not set + +# +# DCCP Configuration (EXPERIMENTAL) +# +# CONFIG_IP_DCCP is not set + +# +# SCTP Configuration (EXPERIMENTAL) +# +# CONFIG_IP_SCTP is not set + +# +# TIPC Configuration (EXPERIMENTAL) +# +# CONFIG_TIPC is not set +# CONFIG_ATM is not set +# CONFIG_BRIDGE is not set +# CONFIG_VLAN_8021Q is not set +# CONFIG_DECNET is not set +# CONFIG_LLC2 is not set +# CONFIG_IPX is not set +# CONFIG_ATALK is not set +# CONFIG_X25 is not set +# CONFIG_LAPB is not set +# CONFIG_ECONET is not set +# CONFIG_WAN_ROUTER is not set + +# +# QoS and/or fair queueing +# +# CONFIG_NET_SCHED is not set + +# +# Network testing +# +# CONFIG_NET_PKTGEN is not set +# CONFIG_HAMRADIO is not set +# CONFIG_IRDA is not set +# CONFIG_BT is not set +# CONFIG_IEEE80211 is not set + +# # Device Drivers # @@ -133,12 +253,100 @@ # Generic Driver Options # CONFIG_STANDALONE=y CONFIG_PREVENT_FIRMWARE_BUILD=y -# CONFIG_FW_LOADER is not set +CONFIG_FW_LOADER=y +# CONFIG_SYS_HYPERVISOR is not set + +# +# Connector - unified userspace <-> kernelspace linker +# +# CONFIG_CONNECTOR is not set # # Memory Technology Devices (MTD) # -# CONFIG_MTD is not set +CONFIG_MTD=y +# CONFIG_MTD_DEBUG is not set +# CONFIG_MTD_CONCAT is not set +CONFIG_MTD_PARTITIONS=y +CONFIG_MTD_REDBOOT_PARTS=y +CONFIG_MTD_REDBOOT_DIRECTORY_BLOCK=-1 +# CONFIG_MTD_REDBOOT_PARTS_UNALLOCATED is not set +# CONFIG_MTD_REDBOOT_PARTS_READONLY is not set +# CONFIG_MTD_CMDLINE_PARTS is not set + +# +# User Modules And Translation Layers +# +# CONFIG_MTD_CHAR is not set +CONFIG_MTD_BLOCK=y +# CONFIG_FTL is not set +# CONFIG_NFTL is not set +# CONFIG_INFTL is not set +# CONFIG_RFD_FTL is not set +# CONFIG_SSFDC is not set + +# +# RAM/ROM/Flash chip drivers +# +CONFIG_MTD_CFI=m +CONFIG_MTD_JEDECPROBE=m +CONFIG_MTD_GEN_PROBE=m +CONFIG_MTD_CFI_ADV_OPTIONS=y +# CONFIG_MTD_CFI_NOSWAP is not set +CONFIG_MTD_CFI_BE_BYTE_SWAP=y +# CONFIG_MTD_CFI_LE_BYTE_SWAP is not set +CONFIG_MTD_CFI_GEOMETRY=y +CONFIG_MTD_MAP_BANK_WIDTH_1=y +CONFIG_MTD_MAP_BANK_WIDTH_2=y +CONFIG_MTD_MAP_BANK_WIDTH_4=y +# CONFIG_MTD_MAP_BANK_WIDTH_8 is not set +# CONFIG_MTD_MAP_BANK_WIDTH_16 is not set +# CONFIG_MTD_MAP_BANK_WIDTH_32 is not set +CONFIG_MTD_CFI_I1=y +# CONFIG_MTD_CFI_I2 is not set +# CONFIG_MTD_CFI_I4 is not set +# CONFIG_MTD_CFI_I8 is not set +# CONFIG_MTD_OTP is not set +# CONFIG_MTD_CFI_INTELEXT is not set +CONFIG_MTD_CFI_AMDSTD=m +# CONFIG_MTD_CFI_STAA is not set +CONFIG_MTD_CFI_UTIL=m +# CONFIG_MTD_RAM is not set +# CONFIG_MTD_ROM is not set +# CONFIG_MTD_ABSENT is not set +# CONFIG_MTD_OBSOLETE_CHIPS is not set + +# +# Mapping drivers for chip access +# +# CONFIG_MTD_COMPLEX_MAPPINGS is not set +# CONFIG_MTD_PHYSMAP is not set +# CONFIG_MTD_PLATRAM is not set + +# +# Self-contained MTD device drivers +# +# CONFIG_MTD_SLRAM is not set +# CONFIG_MTD_PHRAM is not set +# CONFIG_MTD_MTDRAM is not set +# CONFIG_MTD_BLOCK2MTD is not set + +# +# Disk-On-Chip Device Drivers +# +# CONFIG_MTD_DOC2000 is not set +# CONFIG_MTD_DOC2001 is not set +# CONFIG_MTD_DOC2001PLUS is not set + +# +# NAND Flash Device Drivers +# +# CONFIG_MTD_NAND is not set + +# +# OneNAND Flash Device Drivers +# +# CONFIG_MTD_ONENAND is not set # # Parallel port support @@ -152,7 +360,6 @@ # # # Block devices # -# CONFIG_BLK_DEV_FD is not set # CONFIG_BLK_DEV_COW_COMMON is not set CONFIG_BLK_DEV_LOOP=y # CONFIG_BLK_DEV_CRYPTOLOOP is not set @@ -160,23 +367,21 @@ CONFIG_BLK_DEV_NBD=y CONFIG_BLK_DEV_RAM=y CONFIG_BLK_DEV_RAM_COUNT=16 CONFIG_BLK_DEV_RAM_SIZE=4096 +CONFIG_BLK_DEV_RAM_BLOCKSIZE=1024 # CONFIG_BLK_DEV_INITRD is not set -CONFIG_INITRAMFS_SOURCE="" # CONFIG_CDROM_PKTCDVD is not set +CONFIG_ATA_OVER_ETH=m # -# IO Schedulers +# Misc devices # -CONFIG_IOSCHED_NOOP=y -# CONFIG_IOSCHED_AS is not set -CONFIG_IOSCHED_DEADLINE=y -CONFIG_IOSCHED_CFQ=y -# CONFIG_ATA_OVER_ETH is not set +# CONFIG_TIFM_CORE is not set # # ATA/ATAPI/MFM/RLL support # CONFIG_IDE=y +CONFIG_IDE_MAX_HWIFS=4 CONFIG_BLK_DEV_IDE=y # @@ -185,7 +390,6 @@ # # CONFIG_BLK_DEV_IDE_SATA is not set CONFIG_BLK_DEV_IDEDISK=y # CONFIG_IDEDISK_MULTI_MODE is not set -CONFIG_BLK_DEV_IDECS=y CONFIG_BLK_DEV_IDECD=m # CONFIG_BLK_DEV_IDETAPE is not set # CONFIG_BLK_DEV_IDEFLOPPY is not set @@ -204,7 +408,9 @@ # CONFIG_BLK_DEV_HD is not set # # SCSI device support # +# CONFIG_RAID_ATTRS is not set CONFIG_SCSI=m +# CONFIG_SCSI_NETLINK is not set CONFIG_SCSI_PROC_FS=y # @@ -216,6 +422,7 @@ # CONFIG_CHR_DEV_OSST is not set CONFIG_BLK_DEV_SR=m # CONFIG_BLK_DEV_SR_VENDOR is not set CONFIG_CHR_DEV_SG=m +# CONFIG_CHR_DEV_SCH is not set # # Some SCSI devices (e.g. CD jukebox) support multiple LUNs @@ -225,26 +432,23 @@ # CONFIG_SCSI_CONSTANTS is not set # CONFIG_SCSI_LOGGING is not set # -# SCSI Transport Attributes +# SCSI Transports # # CONFIG_SCSI_SPI_ATTRS is not set # CONFIG_SCSI_FC_ATTRS is not set # CONFIG_SCSI_ISCSI_ATTRS is not set +# CONFIG_SCSI_SAS_ATTRS is not set +# CONFIG_SCSI_SAS_LIBSAS is not set # # SCSI low-level drivers # -# CONFIG_SCSI_SATA is not set +# CONFIG_ISCSI_TCP is not set # CONFIG_SCSI_DEBUG is not set # -# PCMCIA SCSI adapter support +# Serial ATA (prod) and Parallel ATA (experimental) drivers # -# CONFIG_PCMCIA_AHA152X is not set -# CONFIG_PCMCIA_FDOMAIN is not set -# CONFIG_PCMCIA_NINJA_SCSI is not set -# CONFIG_PCMCIA_QLOGIC is not set -# CONFIG_PCMCIA_SYM53C500 is not set # # Multi-device support (RAID and LVM) @@ -254,6 +458,7 @@ # CONFIG_MD is not set # # Fusion MPT device support # +# CONFIG_FUSION is not set # # IEEE 1394 (FireWire) support @@ -264,69 +469,8 @@ # I2O device support # # -# Networking support -# -CONFIG_NET=y - -# -# Networking options -# -CONFIG_PACKET=y -# CONFIG_PACKET_MMAP is not set -CONFIG_UNIX=y -# CONFIG_NET_KEY is not set -CONFIG_INET=y -# CONFIG_IP_MULTICAST is not set -# CONFIG_IP_ADVANCED_ROUTER is not set -CONFIG_IP_PNP=y -CONFIG_IP_PNP_DHCP=y -# CONFIG_IP_PNP_BOOTP is not set -# CONFIG_IP_PNP_RARP is not set -# CONFIG_NET_IPIP is not set -# CONFIG_NET_IPGRE is not set -# CONFIG_ARPD is not set -# CONFIG_SYN_COOKIES is not set -# CONFIG_INET_AH is not set -# CONFIG_INET_ESP is not set -# CONFIG_INET_IPCOMP is not set -# CONFIG_INET_TUNNEL is not set -CONFIG_IP_TCPDIAG=y -# CONFIG_IP_TCPDIAG_IPV6 is not set -# CONFIG_IPV6 is not set -# CONFIG_NETFILTER is not set - -# -# SCTP Configuration (EXPERIMENTAL) -# -# CONFIG_IP_SCTP is not set -# CONFIG_ATM is not set -# CONFIG_BRIDGE is not set -# CONFIG_VLAN_8021Q is not set -# CONFIG_DECNET is not set -# CONFIG_LLC2 is not set -# CONFIG_IPX is not set -# CONFIG_ATALK is not set -# CONFIG_X25 is not set -# CONFIG_LAPB is not set -# CONFIG_NET_DIVERT is not set -# CONFIG_ECONET is not set -# CONFIG_WAN_ROUTER is not set - -# -# QoS and/or fair queueing -# -# CONFIG_NET_SCHED is not set -# CONFIG_NET_CLS_ROUTE is not set - -# -# Network testing +# Network device support # -# CONFIG_NET_PKTGEN is not set -# CONFIG_NETPOLL is not set -# CONFIG_NET_POLL_CONTROLLER is not set -# CONFIG_HAMRADIO is not set -# CONFIG_IRDA is not set -# CONFIG_BT is not set CONFIG_NETDEVICES=y # CONFIG_DUMMY is not set # CONFIG_BONDING is not set @@ -334,6 +478,11 @@ # CONFIG_EQUALIZER is not set # CONFIG_TUN is not set # +# PHY device support +# +# CONFIG_PHYLIB is not set + +# # Ethernet (10 or 100Mbit) # CONFIG_NET_ETHERNET=y @@ -359,11 +508,6 @@ # # CONFIG_NET_RADIO is not set # -# PCMCIA network device support -# -# CONFIG_NET_PCMCIA is not set - -# # Wan interfaces # # CONFIG_WAN is not set @@ -371,6 +515,8 @@ # CONFIG_PPP is not set # CONFIG_SLIP is not set # CONFIG_SHAPER is not set # CONFIG_NETCONSOLE is not set +# CONFIG_NETPOLL is not set +# CONFIG_NET_POLL_CONTROLLER is not set # # ISDN subsystem @@ -386,6 +532,7 @@ # # Input device support # CONFIG_INPUT=y +# CONFIG_INPUT_FF_MEMLESS is not set # # Userland interfaces @@ -414,7 +561,6 @@ CONFIG_SERIO_SERPORT=y # CONFIG_SERIO_LIBPS2 is not set # CONFIG_SERIO_RAW is not set # CONFIG_GAMEPORT is not set -CONFIG_SOUND_GAMEPORT=y # # Character devices @@ -422,6 +568,7 @@ # CONFIG_VT=y CONFIG_VT_CONSOLE=y CONFIG_HW_CONSOLE=y +# CONFIG_VT_HW_CONSOLE_BINDING is not set # CONFIG_SERIAL_NONSTANDARD is not set # @@ -450,8 +597,8 @@ # # Watchdog Cards # # CONFIG_WATCHDOG is not set +CONFIG_HW_RANDOM=y # CONFIG_RTC is not set -# CONFIG_GEN_RTC is not set CONFIG_DS1302=y # CONFIG_DTLK is not set # CONFIG_R3964 is not set @@ -459,17 +606,12 @@ # CONFIG_R3964 is not set # # Ftape, the floppy tape device driver # -# CONFIG_DRM is not set - -# -# PCMCIA character devices -# -# CONFIG_SYNCLINK_CS is not set # CONFIG_RAW_DRIVER is not set # # TPM devices # +# CONFIG_TCG_TPM is not set # # I2C support @@ -477,34 +619,51 @@ # # CONFIG_I2C is not set # +# SPI support +# +# CONFIG_SPI is not set +# CONFIG_SPI_MASTER is not set + +# # Dallas's 1-wire bus # # CONFIG_W1 is not set # -# Misc devices +# Hardware Monitoring support # +CONFIG_HWMON=y +# CONFIG_HWMON_VID is not set +# CONFIG_SENSORS_ABITUGURU is not set +# CONFIG_SENSORS_F71805F is not set +# CONFIG_SENSORS_VT1211 is not set +# CONFIG_HWMON_DEBUG_CHIP is not set # # Multimedia devices # -CONFIG_VIDEO_DEV=y +CONFIG_VIDEO_DEV=m +CONFIG_VIDEO_V4L1=y +CONFIG_VIDEO_V4L1_COMPAT=y +CONFIG_VIDEO_V4L2=y # -# Video For Linux +# Video Capture Adapters # # -# Video Adapters +# Video Capture Adapters # +# CONFIG_VIDEO_ADV_DEBUG is not set +CONFIG_VIDEO_HELPER_CHIPS_AUTO=y +# CONFIG_VIDEO_VIVI is not set # CONFIG_VIDEO_CPIA is not set -CONFIG_VIDEO_M32R_AR=y -CONFIG_VIDEO_M32R_AR_M64278=y +CONFIG_VIDEO_M32R_AR=m +CONFIG_VIDEO_M32R_AR_M64278=m # # Radio Adapters # -# CONFIG_RADIO_MAESTRO is not set # # Digital Video Broadcasting Devices @@ -514,15 +673,16 @@ # CONFIG_DVB is not set # # Graphics support # +CONFIG_FIRMWARE_EDID=y CONFIG_FB=y -# CONFIG_FB_CFB_FILLRECT is not set -# CONFIG_FB_CFB_COPYAREA is not set -# CONFIG_FB_CFB_IMAGEBLIT is not set -# CONFIG_FB_SOFT_CURSOR is not set +CONFIG_FB_CFB_FILLRECT=y +CONFIG_FB_CFB_COPYAREA=y +CONFIG_FB_CFB_IMAGEBLIT=y # CONFIG_FB_MACMODES is not set +# CONFIG_FB_BACKLIGHT is not set # CONFIG_FB_MODE_HELPERS is not set # CONFIG_FB_TILEBLITTING is not set -# CONFIG_FB_S1D13XXX is not set +CONFIG_FB_S1D13XXX=y # CONFIG_FB_VIRTUAL is not set # @@ -531,6 +691,7 @@ # # CONFIG_VGA_CONSOLE is not set CONFIG_DUMMY_CONSOLE=y CONFIG_FRAMEBUFFER_CONSOLE=y +# CONFIG_FRAMEBUFFER_CONSOLE_ROTATION is not set # CONFIG_FONTS is not set CONFIG_FONT_8x8=y CONFIG_FONT_8x16=y @@ -542,6 +703,7 @@ CONFIG_LOGO=y CONFIG_LOGO_LINUX_MONO=y CONFIG_LOGO_LINUX_VGA16=y CONFIG_LOGO_LINUX_CLUT224=y +CONFIG_LOGO_M32R_CLUT224=y # CONFIG_BACKLIGHT_LCD_SUPPORT is not set # @@ -554,6 +716,11 @@ # USB support # # CONFIG_USB_ARCH_HAS_HCD is not set # CONFIG_USB_ARCH_HAS_OHCI is not set +# CONFIG_USB_ARCH_HAS_EHCI is not set + +# +# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support' +# # # USB Gadget Support @@ -563,23 +730,62 @@ # CONFIG_USB_GADGET is not set # # MMC/SD Card support # -# CONFIG_MMC is not set +CONFIG_MMC=y +CONFIG_MMC_DEBUG=y +CONFIG_MMC_BLOCK=y +# CONFIG_MMC_TIFM_SD is not set + +# +# LED devices +# +# CONFIG_NEW_LEDS is not set + +# +# LED drivers +# + +# +# LED Triggers +# # # InfiniBand support # -# CONFIG_INFINIBAND is not set + +# +# EDAC - error detection and reporting (RAS) (EXPERIMENTAL) +# + +# +# Real Time Clock +# +# CONFIG_RTC_CLASS is not set + +# +# DMA Engine support +# +# CONFIG_DMA_ENGINE is not set + +# +# DMA Clients +# + +# +# DMA Devices +# # # File systems # CONFIG_EXT2_FS=y # CONFIG_EXT2_FS_XATTR is not set -CONFIG_EXT3_FS=m +# CONFIG_EXT2_FS_XIP is not set +CONFIG_EXT3_FS=y CONFIG_EXT3_FS_XATTR=y # CONFIG_EXT3_FS_POSIX_ACL is not set # CONFIG_EXT3_FS_SECURITY is not set -CONFIG_JBD=m +# CONFIG_EXT4DEV_FS is not set +CONFIG_JBD=y CONFIG_JBD_DEBUG=y CONFIG_FS_MBCACHE=y CONFIG_REISERFS_FS=m @@ -587,17 +793,19 @@ # CONFIG_REISERFS_CHECK is not set # CONFIG_REISERFS_PROC_INFO is not set # CONFIG_REISERFS_FS_XATTR is not set # CONFIG_JFS_FS is not set - -# -# XFS support -# +# CONFIG_FS_POSIX_ACL is not set # CONFIG_XFS_FS is not set +# CONFIG_GFS2_FS is not set +# CONFIG_OCFS2_FS is not set # CONFIG_MINIX_FS is not set # CONFIG_ROMFS_FS is not set +CONFIG_INOTIFY=y +CONFIG_INOTIFY_USER=y # CONFIG_QUOTA is not set CONFIG_DNOTIFY=y # CONFIG_AUTOFS_FS is not set # CONFIG_AUTOFS4_FS is not set +# CONFIG_FUSE_FS is not set # # CD-ROM/DVD Filesystems @@ -623,15 +831,13 @@ # Pseudo filesystems # CONFIG_PROC_FS=y CONFIG_PROC_KCORE=y +CONFIG_PROC_SYSCTL=y CONFIG_SYSFS=y -CONFIG_DEVFS_FS=y -CONFIG_DEVFS_MOUNT=y -# CONFIG_DEVFS_DEBUG is not set -# CONFIG_DEVPTS_FS_XATTR is not set CONFIG_TMPFS=y -# CONFIG_TMPFS_XATTR is not set +# CONFIG_TMPFS_POSIX_ACL is not set # CONFIG_HUGETLB_PAGE is not set CONFIG_RAMFS=y +# CONFIG_CONFIGFS_FS is not set # # Miscellaneous filesystems @@ -643,6 +849,8 @@ # CONFIG_HFSPLUS_FS is not set # CONFIG_BEFS_FS is not set # CONFIG_BFS_FS is not set # CONFIG_EFS_FS is not set +# CONFIG_JFFS_FS is not set +# CONFIG_JFFS2_FS is not set # CONFIG_CRAMFS is not set # CONFIG_VXFS_FS is not set # CONFIG_HPFS_FS is not set @@ -655,12 +863,14 @@ # Network File Systems # CONFIG_NFS_FS=y CONFIG_NFS_V3=y +# CONFIG_NFS_V3_ACL is not set # CONFIG_NFS_V4 is not set # CONFIG_NFS_DIRECTIO is not set # CONFIG_NFSD is not set CONFIG_ROOT_NFS=y CONFIG_LOCKD=y CONFIG_LOCKD_V4=y +CONFIG_NFS_COMMON=y CONFIG_SUNRPC=y # CONFIG_RPCSEC_GSS_KRB5 is not set # CONFIG_RPCSEC_GSS_SPKM3 is not set @@ -669,6 +879,7 @@ # CONFIG_CIFS is not set # CONFIG_NCP_FS is not set # CONFIG_CODA_FS is not set # CONFIG_AFS_FS is not set +# CONFIG_9P_FS is not set # # Partition Types @@ -723,16 +934,23 @@ # CONFIG_NLS_UTF8 is not set # # Profiling support # -# CONFIG_PROFILING is not set +CONFIG_PROFILING=y +CONFIG_OPROFILE=y # # Kernel hacking # # CONFIG_PRINTK_TIME is not set +CONFIG_ENABLE_MUST_CHECK=y +# CONFIG_MAGIC_SYSRQ is not set +# CONFIG_UNUSED_SYMBOLS is not set # CONFIG_DEBUG_KERNEL is not set -CONFIG_LOG_BUF_SHIFT=14 +CONFIG_LOG_BUF_SHIFT=15 # CONFIG_DEBUG_BUGVERBOSE is not set +# CONFIG_DEBUG_FS is not set # CONFIG_FRAME_POINTER is not set +# CONFIG_UNWIND_INFO is not set +# CONFIG_HEADERS_CHECK is not set # # Security options @@ -746,12 +964,9 @@ # # CONFIG_CRYPTO is not set # -# Hardware crypto devices -# - -# # Library routines # # CONFIG_CRC_CCITT is not set +# CONFIG_CRC16 is not set CONFIG_CRC32=y # CONFIG_LIBCRC32C is not set diff --git a/arch/m32r/kernel/head.S b/arch/m32r/kernel/head.S index 0d3c8ee..dab7436 100644 --- a/arch/m32r/kernel/head.S +++ b/arch/m32r/kernel/head.S @@ -7,8 +7,6 @@ * Hitoshi Yamamoto */ -/* $Id$ */ - #include __INIT __INITDATA diff --git a/arch/m32r/kernel/process.c b/arch/m32r/kernel/process.c index 44cbe0c..a689e29 100644 --- a/arch/m32r/kernel/process.c +++ b/arch/m32r/kernel/process.c @@ -174,7 +174,7 @@ #if defined(CONFIG_ISA_M32R2) && defined regs->acc1h, regs->acc1l); #elif defined(CONFIG_ISA_M32R2) || defined(CONFIG_ISA_M32R) printk("ACCH[%08lx]:ACCL[%08lx]\n", \ - regs->acch, regs->accl); + regs->acc0h, regs->acc0l); #else #error unknown isa configuration #endif diff --git a/arch/m32r/kernel/setup.c b/arch/m32r/kernel/setup.c index 936205f..d648143 100644 --- a/arch/m32r/kernel/setup.c +++ b/arch/m32r/kernel/setup.c @@ -64,7 +64,7 @@ #endif extern int root_mountflags; -static char command_line[COMMAND_LINE_SIZE]; +static char __initdata command_line[COMMAND_LINE_SIZE]; static struct resource data_resource = { .name = "Kernel data", @@ -95,8 +95,8 @@ static __inline__ void parse_mem_cmdline int usermem = 0; /* Save unparsed command line copy for /proc/cmdline */ - memcpy(saved_command_line, COMMAND_LINE, COMMAND_LINE_SIZE); - saved_command_line[COMMAND_LINE_SIZE-1] = '\0'; + memcpy(boot_command_line, COMMAND_LINE, COMMAND_LINE_SIZE); + boot_command_line[COMMAND_LINE_SIZE-1] = '\0'; memory_start = (unsigned long)CONFIG_MEMORY_START+PAGE_OFFSET; memory_end = memory_start+(unsigned long)CONFIG_MEMORY_SIZE; diff --git a/arch/m32r/kernel/signal.c b/arch/m32r/kernel/signal.c index 092ea86..4b15605 100644 --- a/arch/m32r/kernel/signal.c +++ b/arch/m32r/kernel/signal.c @@ -109,19 +109,10 @@ #define COPY(x) err |= __get_user(regs- COPY(r10); COPY(r11); COPY(r12); -#if defined(CONFIG_ISA_M32R2) && defined(CONFIG_ISA_DSP_LEVEL2) COPY(acc0h); COPY(acc0l); - COPY(acc1h); - COPY(acc1l); -#elif defined(CONFIG_ISA_M32R2) || defined(CONFIG_ISA_M32R) - COPY(acch); - COPY(accl); - COPY(dummy_acc1h); - COPY(dummy_acc1l); -#else -#error unknown isa configuration -#endif + COPY(acc1h); /* ISA_DSP_LEVEL2 only */ + COPY(acc1l); /* ISA_DSP_LEVEL2 only */ COPY(psw); COPY(bpc); COPY(bbpsw); @@ -196,19 +187,10 @@ #define COPY(x) err |= __put_user(regs-> COPY(r10); COPY(r11); COPY(r12); -#if defined(CONFIG_ISA_M32R2) && defined(CONFIG_ISA_DSP_LEVEL2) COPY(acc0h); COPY(acc0l); - COPY(acc1h); - COPY(acc1l); -#elif defined(CONFIG_ISA_M32R2) || defined(CONFIG_ISA_M32R) - COPY(acch); - COPY(accl); - COPY(dummy_acc1h); - COPY(dummy_acc1l); -#else -#error unknown isa configuration -#endif + COPY(acc1h); /* ISA_DSP_LEVEL2 only */ + COPY(acc1l); /* ISA_DSP_LEVEL2 only */ COPY(psw); COPY(bpc); COPY(bbpsw); diff --git a/arch/m32r/kernel/time.c b/arch/m32r/kernel/time.c index a090382..3858c9f 100644 --- a/arch/m32r/kernel/time.c +++ b/arch/m32r/kernel/time.c @@ -286,11 +286,3 @@ #else #error no chip configuration #endif } - -/* - * Scheduler clock - returns current time in nanosec units. - */ -unsigned long long sched_clock(void) -{ - return (unsigned long long)jiffies * (1000000000 / HZ); -} diff --git a/arch/m32r/kernel/vmlinux.lds.S b/arch/m32r/kernel/vmlinux.lds.S index 358b9ce..439cc25 100644 --- a/arch/m32r/kernel/vmlinux.lds.S +++ b/arch/m32r/kernel/vmlinux.lds.S @@ -6,12 +6,15 @@ #include #include OUTPUT_ARCH(m32r) -ENTRY(startup_32) #if defined(__LITTLE_ENDIAN__) jiffies = jiffies_64; #else jiffies = jiffies_64 + 4; #endif + +kernel_entry = boot - 0x80000000; +ENTRY(kernel_entry) + SECTIONS { . = CONFIG_MEMORY_START + __PAGE_OFFSET; @@ -99,10 +102,14 @@ #endif from .altinstructions and .eh_frame */ .exit.text : { *(.exit.text) } .exit.data : { *(.exit.data) } + +#ifdef CONFIG_BLK_DEV_INITRD . = ALIGN(4096); __initramfs_start = .; .init.ramfs : { *(.init.ramfs) } __initramfs_end = .; +#endif + . = ALIGN(32); __per_cpu_start = .; .data.percpu : { *(.data.percpu) } diff --git a/arch/m32r/lib/ashxdi3.S b/arch/m32r/lib/ashxdi3.S index 107594b..7fc0c19 100644 --- a/arch/m32r/lib/ashxdi3.S +++ b/arch/m32r/lib/ashxdi3.S @@ -4,8 +4,6 @@ * Copyright (C) 2001,2002 Hiroyuki Kondo, and Hirokazu Takata * */ -/* $Id$ */ - ; ; input (r0,r1) src @@ -293,4 +291,3 @@ #endif #endif /* not CONFIG_ISA_DUAL_ISSUE */ .end - diff --git a/arch/m32r/lib/checksum.S b/arch/m32r/lib/checksum.S index cfbe00e..0af0360 100644 --- a/arch/m32r/lib/checksum.S +++ b/arch/m32r/lib/checksum.S @@ -25,8 +25,6 @@ * as published by the Free Software Foundation; either version * 2 of the License, or (at your option) any later version. */ -/* $Id$ */ - #include #include @@ -319,3 +317,4 @@ ENTRY(csum_partial_copy_generic) nop nop + .end diff --git a/arch/m32r/lib/delay.c b/arch/m32r/lib/delay.c index 06382a3..59bfc34 100644 --- a/arch/m32r/lib/delay.c +++ b/arch/m32r/lib/delay.c @@ -5,8 +5,6 @@ * Copyright (c) 2004 Hirokazu Takata */ -/* $Id$ */ - #include #ifdef CONFIG_SMP #include diff --git a/arch/m32r/lib/memcpy.S b/arch/m32r/lib/memcpy.S index 2089a21..05987cd 100644 --- a/arch/m32r/lib/memcpy.S +++ b/arch/m32r/lib/memcpy.S @@ -10,8 +10,6 @@ * src: r1 * n : r2 */ -/* $Id$ */ - .text #include diff --git a/arch/m32r/lib/memset.S b/arch/m32r/lib/memset.S index b47fa35..2b2831a 100644 --- a/arch/m32r/lib/memset.S +++ b/arch/m32r/lib/memset.S @@ -12,8 +12,6 @@ * ret: r0 * */ -/* $Id$ */ - .text .global memset diff --git a/arch/m32r/lib/strlen.S b/arch/m32r/lib/strlen.S index 5f41aac..916de9e 100644 --- a/arch/m32r/lib/strlen.S +++ b/arch/m32r/lib/strlen.S @@ -6,8 +6,6 @@ * size_t strlen(const char *s); * */ -/* $Id$ */ - #include #include diff --git a/arch/m32r/m32104ut/defconfig.m32104ut b/arch/m32r/m32104ut/defconfig.m32104ut index 454de33..7b68fe8 100644 --- a/arch/m32r/m32104ut/defconfig.m32104ut +++ b/arch/m32r/m32104ut/defconfig.m32104ut @@ -1,20 +1,20 @@ # # Automatically generated make config: don't edit -# Linux kernel version: 2.6.14 -# Wed Nov 9 16:04:51 2005 +# Linux kernel version: 2.6.19 +# Wed Dec 13 17:22:20 2006 # CONFIG_M32R=y -# CONFIG_UID16 is not set CONFIG_GENERIC_ISA_DMA=y CONFIG_GENERIC_HARDIRQS=y CONFIG_GENERIC_IRQ_PROBE=y +CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config" # # Code maturity level options # CONFIG_EXPERIMENTAL=y -CONFIG_CLEAN_COMPILE=y CONFIG_BROKEN_ON_SMP=y +CONFIG_LOCK_KERNEL=y CONFIG_INIT_ENV_ARG_LIMIT=32 # @@ -22,33 +22,66 @@ # General setup # CONFIG_LOCALVERSION="" CONFIG_LOCALVERSION_AUTO=y +CONFIG_SYSVIPC=y +# CONFIG_IPC_NS is not set # CONFIG_POSIX_MQUEUE is not set # CONFIG_BSD_PROCESS_ACCT is not set -CONFIG_SYSCTL=y +# CONFIG_TASKSTATS is not set +# CONFIG_UTS_NS is not set # CONFIG_AUDIT is not set -CONFIG_HOTPLUG=y -# CONFIG_KOBJECT_UEVENT is not set -# CONFIG_IKCONFIG is not set +CONFIG_IKCONFIG=y +CONFIG_IKCONFIG_PROC=y +CONFIG_SYSFS_DEPRECATED=y +# CONFIG_RELAY is not set CONFIG_INITRAMFS_SOURCE="" -CONFIG_EMBEDDED=y -# CONFIG_KALLSYMS is not set +CONFIG_CC_OPTIMIZE_FOR_SIZE=y +CONFIG_SYSCTL=y +# CONFIG_EMBEDDED is not set +CONFIG_SYSCTL_SYSCALL=y +CONFIG_KALLSYMS=y +# CONFIG_KALLSYMS_EXTRA_PASS is not set +CONFIG_HOTPLUG=y CONFIG_PRINTK=y CONFIG_BUG=y +CONFIG_ELF_CORE=y CONFIG_BASE_FULL=y -# CONFIG_FUTEX is not set -# CONFIG_EPOLL is not set -# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set -CONFIG_CC_ALIGN_FUNCTIONS=0 -CONFIG_CC_ALIGN_LABELS=0 -CONFIG_CC_ALIGN_LOOPS=0 -CONFIG_CC_ALIGN_JUMPS=0 +CONFIG_FUTEX=y +CONFIG_EPOLL=y +CONFIG_SLAB=y +CONFIG_VM_EVENT_COUNTERS=y +CONFIG_RT_MUTEXES=y CONFIG_TINY_SHMEM=y CONFIG_BASE_SMALL=0 +# CONFIG_SLOB is not set # # Loadable module support # -# CONFIG_MODULES is not set +CONFIG_MODULES=y +CONFIG_MODULE_UNLOAD=y +CONFIG_MODULE_FORCE_UNLOAD=y +# CONFIG_MODVERSIONS is not set +# CONFIG_MODULE_SRCVERSION_ALL is not set +CONFIG_KMOD=y + +# +# Block layer +# +CONFIG_BLOCK=y +# CONFIG_BLK_DEV_IO_TRACE is not set + +# +# IO Schedulers +# +CONFIG_IOSCHED_NOOP=y +CONFIG_IOSCHED_AS=y +CONFIG_IOSCHED_DEADLINE=y +CONFIG_IOSCHED_CFQ=y +CONFIG_DEFAULT_AS=y +# CONFIG_DEFAULT_DEADLINE is not set +# CONFIG_DEFAULT_CFQ is not set +# CONFIG_DEFAULT_NOOP is not set +CONFIG_DEFAULT_IOSCHED="anticipatory" # # Processor type and features @@ -70,40 +103,40 @@ CONFIG_ISA_M32R=y CONFIG_BUS_CLOCK=54000000 CONFIG_TIMER_DIVIDE=128 # CONFIG_CPU_LITTLE_ENDIAN is not set -CONFIG_MEMORY_START=04000000 -CONFIG_MEMORY_SIZE=01000000 +CONFIG_MEMORY_START=0x04000000 +CONFIG_MEMORY_SIZE=0x01000000 CONFIG_NOHIGHMEM=y -# CONFIG_ARCH_DISCONTIGMEM_ENABLE is not set +CONFIG_ARCH_DISCONTIGMEM_ENABLE=y CONFIG_SELECT_MEMORY_MODEL=y -CONFIG_FLATMEM_MANUAL=y -# CONFIG_DISCONTIGMEM_MANUAL is not set +# CONFIG_FLATMEM_MANUAL is not set +CONFIG_DISCONTIGMEM_MANUAL=y # CONFIG_SPARSEMEM_MANUAL is not set -CONFIG_FLATMEM=y +CONFIG_DISCONTIGMEM=y CONFIG_FLAT_NODE_MEM_MAP=y +CONFIG_NEED_MULTIPLE_NODES=y # CONFIG_SPARSEMEM_STATIC is not set +CONFIG_SPLIT_PTLOCK_CPUS=4 +# CONFIG_RESOURCES_64BIT is not set +CONFIG_IRAM_START=0x00700000 +CONFIG_IRAM_SIZE=0x00010000 CONFIG_RWSEM_GENERIC_SPINLOCK=y # CONFIG_RWSEM_XCHGADD_ALGORITHM is not set +CONFIG_GENERIC_FIND_NEXT_BIT=y +CONFIG_GENERIC_HWEIGHT=y CONFIG_GENERIC_CALIBRATE_DELAY=y -# CONFIG_PREEMPT is not set +CONFIG_PREEMPT=y # CONFIG_SMP is not set +CONFIG_NODES_SHIFT=1 # # Bus options (PCI, PCMCIA, EISA, MCA, ISA) # -# CONFIG_ISA is not set +CONFIG_ISA=y # # PCCARD (PCMCIA/CardBus) support # -CONFIG_PCCARD=y -# CONFIG_PCMCIA_DEBUG is not set -CONFIG_PCMCIA=y -CONFIG_PCMCIA_LOAD_CIS=y -CONFIG_PCMCIA_IOCTL=y - -# -# PC-card bridges -# +# CONFIG_PCCARD is not set # # PCI Hotplug Support @@ -112,10 +145,8 @@ # # # Executable file formats # -CONFIG_BINFMT_FLAT=y -# CONFIG_BINFMT_ZFLAT is not set -# CONFIG_BINFMT_SHARED_FLAT is not set -# CONFIG_BINFMT_MISC is not set +# CONFIG_BINFMT_FLAT is not set +CONFIG_BINFMT_MISC=y # # Networking @@ -125,17 +156,19 @@ CONFIG_NET=y # # Networking options # -# CONFIG_PACKET is not set +# CONFIG_NETDEBUG is not set +CONFIG_PACKET=y +# CONFIG_PACKET_MMAP is not set CONFIG_UNIX=y +CONFIG_XFRM=y +# CONFIG_XFRM_USER is not set +# CONFIG_XFRM_SUB_POLICY is not set # CONFIG_NET_KEY is not set CONFIG_INET=y # CONFIG_IP_MULTICAST is not set # CONFIG_IP_ADVANCED_ROUTER is not set CONFIG_IP_FIB_HASH=y -CONFIG_IP_PNP=y -CONFIG_IP_PNP_DHCP=y -# CONFIG_IP_PNP_BOOTP is not set -# CONFIG_IP_PNP_RARP is not set +# CONFIG_IP_PNP is not set # CONFIG_NET_IPIP is not set # CONFIG_NET_IPGRE is not set # CONFIG_ARPD is not set @@ -143,13 +176,87 @@ # CONFIG_SYN_COOKIES is not set # CONFIG_INET_AH is not set # CONFIG_INET_ESP is not set # CONFIG_INET_IPCOMP is not set +# CONFIG_INET_XFRM_TUNNEL is not set # CONFIG_INET_TUNNEL is not set +CONFIG_INET_XFRM_MODE_TRANSPORT=y +CONFIG_INET_XFRM_MODE_TUNNEL=y +CONFIG_INET_XFRM_MODE_BEET=y CONFIG_INET_DIAG=y CONFIG_INET_TCP_DIAG=y # CONFIG_TCP_CONG_ADVANCED is not set -CONFIG_TCP_CONG_BIC=y +CONFIG_TCP_CONG_CUBIC=y +CONFIG_DEFAULT_TCP_CONG="cubic" +# CONFIG_TCP_MD5SIG is not set + +# +# IP: Virtual Server Configuration +# +# CONFIG_IP_VS is not set # CONFIG_IPV6 is not set -# CONFIG_NETFILTER is not set +# CONFIG_INET6_XFRM_TUNNEL is not set +# CONFIG_INET6_TUNNEL is not set +# CONFIG_NETWORK_SECMARK is not set +CONFIG_NETFILTER=y +# CONFIG_NETFILTER_DEBUG is not set + +# +# Core Netfilter Configuration +# +CONFIG_NETFILTER_NETLINK=m +CONFIG_NETFILTER_NETLINK_QUEUE=m +CONFIG_NETFILTER_NETLINK_LOG=m +# CONFIG_NF_CONNTRACK_ENABLED is not set +CONFIG_NETFILTER_XTABLES=m +CONFIG_NETFILTER_XT_TARGET_CLASSIFY=m +# CONFIG_NETFILTER_XT_TARGET_DSCP is not set +CONFIG_NETFILTER_XT_TARGET_MARK=m +CONFIG_NETFILTER_XT_TARGET_NFQUEUE=m +# CONFIG_NETFILTER_XT_TARGET_NFLOG is not set +CONFIG_NETFILTER_XT_MATCH_COMMENT=m +CONFIG_NETFILTER_XT_MATCH_DCCP=m +# CONFIG_NETFILTER_XT_MATCH_DSCP is not set +# CONFIG_NETFILTER_XT_MATCH_ESP is not set +CONFIG_NETFILTER_XT_MATCH_LENGTH=m +CONFIG_NETFILTER_XT_MATCH_LIMIT=m +CONFIG_NETFILTER_XT_MATCH_MAC=m +CONFIG_NETFILTER_XT_MATCH_MARK=m +# CONFIG_NETFILTER_XT_MATCH_POLICY is not set +# CONFIG_NETFILTER_XT_MATCH_MULTIPORT is not set +CONFIG_NETFILTER_XT_MATCH_PKTTYPE=m +# CONFIG_NETFILTER_XT_MATCH_QUOTA is not set +CONFIG_NETFILTER_XT_MATCH_REALM=m +CONFIG_NETFILTER_XT_MATCH_SCTP=m +# CONFIG_NETFILTER_XT_MATCH_STATISTIC is not set +CONFIG_NETFILTER_XT_MATCH_STRING=m +CONFIG_NETFILTER_XT_MATCH_TCPMSS=m +# CONFIG_NETFILTER_XT_MATCH_HASHLIMIT is not set + +# +# IP: Netfilter Configuration +# +CONFIG_IP_NF_QUEUE=m +CONFIG_IP_NF_IPTABLES=m +CONFIG_IP_NF_MATCH_IPRANGE=m +CONFIG_IP_NF_MATCH_TOS=m +CONFIG_IP_NF_MATCH_RECENT=m +CONFIG_IP_NF_MATCH_ECN=m +# CONFIG_IP_NF_MATCH_AH is not set +CONFIG_IP_NF_MATCH_TTL=m +CONFIG_IP_NF_MATCH_OWNER=m +CONFIG_IP_NF_MATCH_ADDRTYPE=m +CONFIG_IP_NF_FILTER=m +CONFIG_IP_NF_TARGET_REJECT=m +CONFIG_IP_NF_TARGET_LOG=m +CONFIG_IP_NF_TARGET_ULOG=m +CONFIG_IP_NF_TARGET_TCPMSS=m +CONFIG_IP_NF_MANGLE=m +CONFIG_IP_NF_TARGET_TOS=m +CONFIG_IP_NF_TARGET_ECN=m +CONFIG_IP_NF_TARGET_TTL=m +CONFIG_IP_NF_RAW=m +CONFIG_IP_NF_ARPTABLES=m +CONFIG_IP_NF_ARPFILTER=m +CONFIG_IP_NF_ARP_MANGLE=m # # DCCP Configuration (EXPERIMENTAL) @@ -160,6 +267,11 @@ # # SCTP Configuration (EXPERIMENTAL) # # CONFIG_IP_SCTP is not set + +# +# TIPC Configuration (EXPERIMENTAL) +# +# CONFIG_TIPC is not set # CONFIG_ATM is not set # CONFIG_BRIDGE is not set # CONFIG_VLAN_8021Q is not set @@ -169,11 +281,14 @@ # CONFIG_IPX is not set # CONFIG_ATALK is not set # CONFIG_X25 is not set # CONFIG_LAPB is not set -# CONFIG_NET_DIVERT is not set # CONFIG_ECONET is not set # CONFIG_WAN_ROUTER is not set + +# +# QoS and/or fair queueing +# # CONFIG_NET_SCHED is not set -# CONFIG_NET_CLS_ROUTE is not set +CONFIG_NET_CLS_ROUTE=y # # Network testing @@ -193,8 +308,8 @@ # Generic Driver Options # CONFIG_STANDALONE=y CONFIG_PREVENT_FIRMWARE_BUILD=y -CONFIG_FW_LOADER=y -# CONFIG_DEBUG_DRIVER is not set +# CONFIG_FW_LOADER is not set +# CONFIG_SYS_HYPERVISOR is not set # # Connector - unified userspace <-> kernelspace linker @@ -209,11 +324,21 @@ # CONFIG_MTD is not set # # Parallel port support # -# CONFIG_PARPORT is not set +CONFIG_PARPORT=m +# CONFIG_PARPORT_GSC is not set +# CONFIG_PARPORT_AX88796 is not set +CONFIG_PARPORT_1284=y # # Plug and Play support # +CONFIG_PNP=y +# CONFIG_PNP_DEBUG is not set + +# +# Protocols +# +CONFIG_ISAPNP=y # # Block devices @@ -221,37 +346,130 @@ # # CONFIG_BLK_DEV_COW_COMMON is not set CONFIG_BLK_DEV_LOOP=y # CONFIG_BLK_DEV_CRYPTOLOOP is not set -CONFIG_BLK_DEV_NBD=y -CONFIG_BLK_DEV_RAM=y -CONFIG_BLK_DEV_RAM_COUNT=16 -CONFIG_BLK_DEV_RAM_SIZE=4096 -CONFIG_BLK_DEV_INITRD=y -# CONFIG_CDROM_PKTCDVD is not set +CONFIG_BLK_DEV_NBD=m +# CONFIG_BLK_DEV_RAM is not set +# CONFIG_BLK_DEV_INITRD is not set +CONFIG_CDROM_PKTCDVD=m +CONFIG_CDROM_PKTCDVD_BUFFERS=8 +CONFIG_CDROM_PKTCDVD_WCACHE=y +# CONFIG_ATA_OVER_ETH is not set # -# IO Schedulers +# Misc devices # -CONFIG_IOSCHED_NOOP=y -# CONFIG_IOSCHED_AS is not set -# CONFIG_IOSCHED_DEADLINE is not set -# CONFIG_IOSCHED_CFQ is not set -# CONFIG_ATA_OVER_ETH is not set +# CONFIG_TIFM_CORE is not set # # ATA/ATAPI/MFM/RLL support # -# CONFIG_IDE is not set +CONFIG_IDE=y +CONFIG_BLK_DEV_IDE=y + +# +# Please see Documentation/ide.txt for help/info on IDE drives +# +# CONFIG_BLK_DEV_IDE_SATA is not set +CONFIG_BLK_DEV_IDEDISK=y +# CONFIG_IDEDISK_MULTI_MODE is not set +CONFIG_BLK_DEV_IDECD=y +# CONFIG_BLK_DEV_IDETAPE is not set +# CONFIG_BLK_DEV_IDEFLOPPY is not set +# CONFIG_BLK_DEV_IDESCSI is not set +# CONFIG_IDE_TASK_IOCTL is not set + +# +# IDE chipset support/bugfixes +# +CONFIG_IDE_GENERIC=y +# CONFIG_BLK_DEV_IDEPNP is not set +# CONFIG_IDE_ARM is not set +# CONFIG_IDE_CHIPSETS is not set +# CONFIG_BLK_DEV_IDEDMA is not set +# CONFIG_IDEDMA_AUTO is not set +# CONFIG_BLK_DEV_HD is not set # # SCSI device support # # CONFIG_RAID_ATTRS is not set -# CONFIG_SCSI is not set +CONFIG_SCSI=y +# CONFIG_SCSI_NETLINK is not set +CONFIG_SCSI_PROC_FS=y + +# +# SCSI support type (disk, tape, CD-ROM) +# +CONFIG_BLK_DEV_SD=y +CONFIG_CHR_DEV_ST=m +# CONFIG_CHR_DEV_OSST is not set +CONFIG_BLK_DEV_SR=m +# CONFIG_BLK_DEV_SR_VENDOR is not set +CONFIG_CHR_DEV_SG=m +# CONFIG_CHR_DEV_SCH is not set + +# +# Some SCSI devices (e.g. CD jukebox) support multiple LUNs +# +CONFIG_SCSI_MULTI_LUN=y +CONFIG_SCSI_CONSTANTS=y +# CONFIG_SCSI_LOGGING is not set + +# +# SCSI Transports +# +CONFIG_SCSI_SPI_ATTRS=y +# CONFIG_SCSI_FC_ATTRS is not set +# CONFIG_SCSI_ISCSI_ATTRS is not set +# CONFIG_SCSI_SAS_ATTRS is not set +# CONFIG_SCSI_SAS_LIBSAS is not set + +# +# SCSI low-level drivers +# +# CONFIG_ISCSI_TCP is not set +# CONFIG_SCSI_AHA152X is not set +# CONFIG_SCSI_AIC7XXX_OLD is not set +# CONFIG_SCSI_IN2000 is not set +# CONFIG_SCSI_DTC3280 is not set +# CONFIG_SCSI_FUTURE_DOMAIN is not set +# CONFIG_SCSI_GENERIC_NCR5380 is not set +# CONFIG_SCSI_GENERIC_NCR5380_MMIO is not set +# CONFIG_SCSI_NCR53C406A is not set +# CONFIG_SCSI_PAS16 is not set +# CONFIG_SCSI_PSI240I is not set +# CONFIG_SCSI_QLOGIC_FAS is not set +# CONFIG_SCSI_SYM53C416 is not set +# CONFIG_SCSI_T128 is not set +# CONFIG_SCSI_DEBUG is not set + +# +# Serial ATA (prod) and Parallel ATA (experimental) drivers +# + +# +# Old CD-ROM drivers (not SCSI, not IDE) +# +# CONFIG_CD_NO_IDESCSI is not set # # Multi-device support (RAID and LVM) # -# CONFIG_MD is not set +CONFIG_MD=y +CONFIG_BLK_DEV_MD=y +# CONFIG_MD_LINEAR is not set +# CONFIG_MD_RAID0 is not set +CONFIG_MD_RAID1=y +# CONFIG_MD_RAID10 is not set +# CONFIG_MD_RAID456 is not set +# CONFIG_MD_MULTIPATH is not set +# CONFIG_MD_FAULTY is not set +CONFIG_BLK_DEV_DM=m +# CONFIG_DM_DEBUG is not set +CONFIG_DM_CRYPT=m +CONFIG_DM_SNAPSHOT=m +# CONFIG_DM_MIRROR is not set +# CONFIG_DM_ZERO is not set +# CONFIG_DM_MULTIPATH is not set # # Fusion MPT device support @@ -270,10 +488,16 @@ # # Network device support # CONFIG_NETDEVICES=y -CONFIG_DUMMY=y +CONFIG_DUMMY=m # CONFIG_BONDING is not set # CONFIG_EQUALIZER is not set # CONFIG_TUN is not set +# CONFIG_NET_SB1000 is not set + +# +# ARCnet devices +# +# CONFIG_ARCNET is not set # # PHY device support @@ -285,8 +509,33 @@ # Ethernet (10 or 100Mbit) # CONFIG_NET_ETHERNET=y CONFIG_MII=y -CONFIG_SMC91X=y -# CONFIG_NE2000 is not set +CONFIG_NET_VENDOR_3COM=y +# CONFIG_EL1 is not set +# CONFIG_EL2 is not set +# CONFIG_EL16 is not set +# CONFIG_EL3 is not set +# CONFIG_NET_VENDOR_SMC is not set +# CONFIG_SMC91X is not set +# CONFIG_NET_VENDOR_RACAL is not set +# CONFIG_AT1700 is not set +# CONFIG_DEPCA is not set +# CONFIG_HP100 is not set +CONFIG_NET_ISA=y +# CONFIG_E2100 is not set +# CONFIG_EWRK3 is not set +# CONFIG_EEXPRESS is not set +# CONFIG_EEXPRESS_PRO is not set +# CONFIG_HPLAN_PLUS is not set +# CONFIG_HPLAN is not set +# CONFIG_LP486E is not set +# CONFIG_ETH16I is not set +CONFIG_NE2000=m +# CONFIG_SEEQ8005 is not set +CONFIG_NET_PCI=y +# CONFIG_AC3200 is not set +# CONFIG_APRICOT is not set +# CONFIG_CS89x0 is not set +# CONFIG_NET_POCKET is not set # # Ethernet (1000 Mbit) @@ -299,6 +548,7 @@ # # # Token Ring devices # +# CONFIG_TR is not set # # Wireless LAN (non-hamradio) @@ -306,14 +556,10 @@ # # CONFIG_NET_RADIO is not set # -# PCMCIA network device support -# -# CONFIG_NET_PCMCIA is not set - -# # Wan interfaces # # CONFIG_WAN is not set +# CONFIG_PLIP is not set # CONFIG_PPP is not set # CONFIG_SLIP is not set # CONFIG_SHAPER is not set @@ -334,35 +580,83 @@ # CONFIG_PHONE is not set # # Input device support # -# CONFIG_INPUT is not set +CONFIG_INPUT=y +# CONFIG_INPUT_FF_MEMLESS is not set + +# +# Userland interfaces +# +CONFIG_INPUT_MOUSEDEV=y +CONFIG_INPUT_MOUSEDEV_PSAUX=y +CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024 +CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768 +# CONFIG_INPUT_JOYDEV is not set +# CONFIG_INPUT_TSDEV is not set +# CONFIG_INPUT_EVDEV is not set +# CONFIG_INPUT_EVBUG is not set + +# +# Input Device Drivers +# +CONFIG_INPUT_KEYBOARD=y +CONFIG_KEYBOARD_ATKBD=y +# CONFIG_KEYBOARD_SUNKBD is not set +# CONFIG_KEYBOARD_LKKBD is not set +# CONFIG_KEYBOARD_XTKBD is not set +# CONFIG_KEYBOARD_NEWTON is not set +# CONFIG_KEYBOARD_STOWAWAY is not set +CONFIG_INPUT_MOUSE=y +CONFIG_MOUSE_PS2=y +# CONFIG_MOUSE_SERIAL is not set +# CONFIG_MOUSE_INPORT is not set +# CONFIG_MOUSE_LOGIBM is not set +# CONFIG_MOUSE_PC110PAD is not set +# CONFIG_MOUSE_VSXXXAA is not set +# CONFIG_INPUT_JOYSTICK is not set +# CONFIG_INPUT_TOUCHSCREEN is not set +# CONFIG_INPUT_MISC is not set # # Hardware I/O ports # -# CONFIG_SERIO is not set +CONFIG_SERIO=y +CONFIG_SERIO_I8042=y +CONFIG_SERIO_SERPORT=y +# CONFIG_SERIO_PARKBD is not set +CONFIG_SERIO_LIBPS2=y +# CONFIG_SERIO_RAW is not set # CONFIG_GAMEPORT is not set # # Character devices # -# CONFIG_VT is not set +CONFIG_VT=y +CONFIG_VT_CONSOLE=y +CONFIG_HW_CONSOLE=y +# CONFIG_VT_HW_CONSOLE_BINDING is not set # CONFIG_SERIAL_NONSTANDARD is not set # # Serial drivers # -# CONFIG_SERIAL_8250 is not set +CONFIG_SERIAL_8250=m +CONFIG_SERIAL_8250_PNP=m +CONFIG_SERIAL_8250_NR_UARTS=4 +CONFIG_SERIAL_8250_RUNTIME_UARTS=4 +# CONFIG_SERIAL_8250_EXTENDED is not set # # Non-8250 serial port support # CONFIG_SERIAL_CORE=y -CONFIG_SERIAL_CORE_CONSOLE=y CONFIG_SERIAL_M32R_SIO=y -CONFIG_SERIAL_M32R_SIO_CONSOLE=y +# CONFIG_SERIAL_M32R_SIO_CONSOLE is not set CONFIG_UNIX98_PTYS=y CONFIG_LEGACY_PTYS=y CONFIG_LEGACY_PTY_COUNT=256 +# CONFIG_PRINTER is not set +# CONFIG_PPDEV is not set +# CONFIG_TIPAR is not set # # IPMI @@ -372,13 +666,8 @@ # CONFIG_IPMI_HANDLER is not set # # Watchdog Cards # -CONFIG_WATCHDOG=y -# CONFIG_WATCHDOG_NOWAYOUT is not set - -# -# Watchdog Device Drivers -# -CONFIG_SOFT_WATCHDOG=y +# CONFIG_WATCHDOG is not set +# CONFIG_HW_RANDOM is not set # CONFIG_RTC is not set # CONFIG_DTLK is not set # CONFIG_R3964 is not set @@ -386,21 +675,57 @@ # CONFIG_R3964 is not set # # Ftape, the floppy tape device driver # - -# -# PCMCIA character devices -# -# CONFIG_SYNCLINK_CS is not set # CONFIG_RAW_DRIVER is not set # # TPM devices # +# CONFIG_TCG_TPM is not set # # I2C support # -# CONFIG_I2C is not set +CONFIG_I2C=m +CONFIG_I2C_CHARDEV=m + +# +# I2C Algorithms +# +CONFIG_I2C_ALGOBIT=m +CONFIG_I2C_ALGOPCF=m +# CONFIG_I2C_ALGOPCA is not set + +# +# I2C Hardware Bus support +# +CONFIG_I2C_ELEKTOR=m +CONFIG_I2C_ISA=m +# CONFIG_I2C_OCORES is not set +# CONFIG_I2C_PARPORT is not set +# CONFIG_I2C_PARPORT_LIGHT is not set +# CONFIG_I2C_STUB is not set +# CONFIG_I2C_PCA_ISA is not set + +# +# Miscellaneous I2C Chip support +# +# CONFIG_SENSORS_DS1337 is not set +# CONFIG_SENSORS_DS1374 is not set +# CONFIG_SENSORS_EEPROM is not set +# CONFIG_SENSORS_PCF8574 is not set +# CONFIG_SENSORS_PCA9539 is not set +# CONFIG_SENSORS_PCF8591 is not set +# CONFIG_SENSORS_MAX6875 is not set +# CONFIG_I2C_DEBUG_CORE is not set +# CONFIG_I2C_DEBUG_ALGO is not set +# CONFIG_I2C_DEBUG_BUS is not set +# CONFIG_I2C_DEBUG_CHIP is not set + +# +# SPI support +# +# CONFIG_SPI is not set +# CONFIG_SPI_MASTER is not set # # Dallas's 1-wire bus @@ -410,21 +735,89 @@ # CONFIG_W1 is not set # # Hardware Monitoring support # -# CONFIG_HWMON is not set -# CONFIG_HWMON_VID is not set +CONFIG_HWMON=y +CONFIG_HWMON_VID=m +# CONFIG_SENSORS_ABITUGURU is not set +CONFIG_SENSORS_ADM1021=m +CONFIG_SENSORS_ADM1025=m +# CONFIG_SENSORS_ADM1026 is not set +CONFIG_SENSORS_ADM1031=m +# CONFIG_SENSORS_ADM9240 is not set +CONFIG_SENSORS_ASB100=m +# CONFIG_SENSORS_ATXP1 is not set +CONFIG_SENSORS_DS1621=m +# CONFIG_SENSORS_F71805F is not set +CONFIG_SENSORS_FSCHER=m +# CONFIG_SENSORS_FSCPOS is not set +CONFIG_SENSORS_GL518SM=m +# CONFIG_SENSORS_GL520SM is not set +CONFIG_SENSORS_IT87=m +# CONFIG_SENSORS_LM63 is not set +CONFIG_SENSORS_LM75=m +CONFIG_SENSORS_LM77=m +CONFIG_SENSORS_LM78=m +CONFIG_SENSORS_LM80=m +CONFIG_SENSORS_LM83=m +CONFIG_SENSORS_LM85=m +# CONFIG_SENSORS_LM87 is not set +CONFIG_SENSORS_LM90=m +# CONFIG_SENSORS_LM92 is not set +CONFIG_SENSORS_MAX1619=m +# CONFIG_SENSORS_PC87360 is not set +CONFIG_SENSORS_SMSC47M1=m +# CONFIG_SENSORS_SMSC47M192 is not set +# CONFIG_SENSORS_SMSC47B397 is not set +# CONFIG_SENSORS_VT1211 is not set +CONFIG_SENSORS_W83781D=m +# CONFIG_SENSORS_W83791D is not set +# CONFIG_SENSORS_W83792D is not set +CONFIG_SENSORS_W83L785TS=m +CONFIG_SENSORS_W83627HF=m +# CONFIG_SENSORS_W83627EHF is not set +# CONFIG_HWMON_DEBUG_CHIP is not set # -# Misc devices +# Multimedia devices # +CONFIG_VIDEO_DEV=m +CONFIG_VIDEO_V4L1=y +CONFIG_VIDEO_V4L1_COMPAT=y +CONFIG_VIDEO_V4L2=y # -# Multimedia Capabilities Port drivers +# Video Capture Adapters # # -# Multimedia devices +# Video Capture Adapters # -# CONFIG_VIDEO_DEV is not set +# CONFIG_VIDEO_ADV_DEBUG is not set +CONFIG_VIDEO_HELPER_CHIPS_AUTO=y +# CONFIG_VIDEO_VIVI is not set +# CONFIG_VIDEO_PMS is not set +CONFIG_VIDEO_BWQCAM=m +CONFIG_VIDEO_CQCAM=m +# CONFIG_VIDEO_W9966 is not set +# CONFIG_VIDEO_CPIA is not set +# CONFIG_VIDEO_SAA5246A is not set +# CONFIG_VIDEO_SAA5249 is not set +# CONFIG_TUNER_3036 is not set +# CONFIG_VIDEO_M32R_AR is not set + +# +# Radio Adapters +# +# CONFIG_RADIO_CADET is not set +# CONFIG_RADIO_RTRACK is not set +# CONFIG_RADIO_RTRACK2 is not set +# CONFIG_RADIO_AZTECH is not set +# CONFIG_RADIO_GEMTEK is not set +# CONFIG_RADIO_SF16FMI is not set +# CONFIG_RADIO_SF16FMR2 is not set +# CONFIG_RADIO_TERRATEC is not set +# CONFIG_RADIO_TRUST is not set +# CONFIG_RADIO_TYPHOON is not set +# CONFIG_RADIO_ZOLTRIX is not set # # Digital Video Broadcasting Devices @@ -434,9 +827,19 @@ # CONFIG_DVB is not set # # Graphics support # +CONFIG_FIRMWARE_EDID=y # CONFIG_FB is not set # +# Console display driver support +# +CONFIG_VGA_CONSOLE=y +# CONFIG_VGACON_SOFT_SCROLLBACK is not set +# CONFIG_MDA_CONSOLE is not set +CONFIG_DUMMY_CONSOLE=y +# CONFIG_BACKLIGHT_LCD_SUPPORT is not set + +# # Sound # # CONFIG_SOUND is not set @@ -446,6 +849,11 @@ # USB support # # CONFIG_USB_ARCH_HAS_HCD is not set # CONFIG_USB_ARCH_HAS_OHCI is not set +# CONFIG_USB_ARCH_HAS_EHCI is not set + +# +# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support' +# # # USB Gadget Support @@ -458,33 +866,69 @@ # # CONFIG_MMC is not set # +# LED devices +# +# CONFIG_NEW_LEDS is not set + +# +# LED drivers +# + +# +# LED Triggers +# + +# # InfiniBand support # # -# SN Devices +# EDAC - error detection and reporting (RAS) (EXPERIMENTAL) +# + +# +# Real Time Clock +# +# CONFIG_RTC_CLASS is not set + +# +# DMA Engine support +# +# CONFIG_DMA_ENGINE is not set + +# +# DMA Clients +# + +# +# DMA Devices # # # File systems # CONFIG_EXT2_FS=y -# CONFIG_EXT2_FS_XATTR is not set -# CONFIG_EXT2_FS_XIP is not set +CONFIG_EXT2_FS_XATTR=y +CONFIG_EXT2_FS_POSIX_ACL=y +CONFIG_EXT2_FS_SECURITY=y CONFIG_EXT3_FS=y CONFIG_EXT3_FS_XATTR=y CONFIG_EXT3_FS_POSIX_ACL=y -# CONFIG_EXT3_FS_SECURITY is not set +CONFIG_EXT3_FS_SECURITY=y +# CONFIG_EXT4DEV_FS is not set CONFIG_JBD=y -# CONFIG_JBD_DEBUG is not set +CONFIG_JBD_DEBUG=y CONFIG_FS_MBCACHE=y # CONFIG_REISERFS_FS is not set # CONFIG_JFS_FS is not set CONFIG_FS_POSIX_ACL=y # CONFIG_XFS_FS is not set +# CONFIG_GFS2_FS is not set +# CONFIG_OCFS2_FS is not set # CONFIG_MINIX_FS is not set -# CONFIG_ROMFS_FS is not set -# CONFIG_INOTIFY is not set +CONFIG_ROMFS_FS=y +CONFIG_INOTIFY=y +CONFIG_INOTIFY_USER=y # CONFIG_QUOTA is not set CONFIG_DNOTIFY=y # CONFIG_AUTOFS_FS is not set @@ -494,8 +938,11 @@ # CONFIG_FUSE_FS is not set # # CD-ROM/DVD Filesystems # -# CONFIG_ISO9660_FS is not set -# CONFIG_UDF_FS is not set +CONFIG_ISO9660_FS=y +CONFIG_JOLIET=y +# CONFIG_ZISOFS is not set +CONFIG_UDF_FS=m +CONFIG_UDF_NLS=y # # DOS/FAT/NT Filesystems @@ -503,7 +950,7 @@ # CONFIG_FAT_FS=y CONFIG_MSDOS_FS=y CONFIG_VFAT_FS=y -CONFIG_FAT_DEFAULT_CODEPAGE=932 +CONFIG_FAT_DEFAULT_CODEPAGE=437 CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1" # CONFIG_NTFS_FS is not set @@ -511,11 +958,13 @@ # # Pseudo filesystems # CONFIG_PROC_FS=y +CONFIG_PROC_SYSCTL=y CONFIG_SYSFS=y CONFIG_TMPFS=y +# CONFIG_TMPFS_POSIX_ACL is not set # CONFIG_HUGETLB_PAGE is not set CONFIG_RAMFS=y -# CONFIG_RELAYFS_FS is not set +CONFIG_CONFIGFS_FS=m # # Miscellaneous filesystems @@ -527,7 +976,7 @@ # CONFIG_HFSPLUS_FS is not set # CONFIG_BEFS_FS is not set # CONFIG_BFS_FS is not set # CONFIG_EFS_FS is not set -CONFIG_CRAMFS=y +# CONFIG_CRAMFS is not set # CONFIG_VXFS_FS is not set # CONFIG_HPFS_FS is not set # CONFIG_QNX4FS_FS is not set @@ -542,10 +991,14 @@ CONFIG_NFS_V3=y # CONFIG_NFS_V3_ACL is not set # CONFIG_NFS_V4 is not set # CONFIG_NFS_DIRECTIO is not set -# CONFIG_NFSD is not set -CONFIG_ROOT_NFS=y +CONFIG_NFSD=m +CONFIG_NFSD_V3=y +# CONFIG_NFSD_V3_ACL is not set +# CONFIG_NFSD_V4 is not set +# CONFIG_NFSD_TCP is not set CONFIG_LOCKD=y CONFIG_LOCKD_V4=y +CONFIG_EXPORTFS=m CONFIG_NFS_COMMON=y CONFIG_SUNRPC=y # CONFIG_RPCSEC_GSS_KRB5 is not set @@ -567,7 +1020,7 @@ # # Native Language Support # CONFIG_NLS=y -CONFIG_NLS_DEFAULT="iso8859-1" +CONFIG_NLS_DEFAULT="cp437" CONFIG_NLS_CODEPAGE_437=y # CONFIG_NLS_CODEPAGE_737 is not set # CONFIG_NLS_CODEPAGE_775 is not set @@ -592,7 +1045,7 @@ # CONFIG_NLS_ISO8859_8 is not set # CONFIG_NLS_CODEPAGE_1250 is not set # CONFIG_NLS_CODEPAGE_1251 is not set # CONFIG_NLS_ASCII is not set -# CONFIG_NLS_ISO8859_1 is not set +CONFIG_NLS_ISO8859_1=y # CONFIG_NLS_ISO8859_2 is not set # CONFIG_NLS_ISO8859_3 is not set # CONFIG_NLS_ISO8859_4 is not set @@ -605,32 +1058,28 @@ # CONFIG_NLS_ISO8859_14 is not set # CONFIG_NLS_ISO8859_15 is not set # CONFIG_NLS_KOI8_R is not set # CONFIG_NLS_KOI8_U is not set -CONFIG_NLS_UTF8=y +# CONFIG_NLS_UTF8 is not set # # Profiling support # -# CONFIG_PROFILING is not set +CONFIG_PROFILING=y +CONFIG_OPROFILE=m # # Kernel hacking # # CONFIG_PRINTK_TIME is not set -CONFIG_DEBUG_KERNEL=y -CONFIG_MAGIC_SYSRQ=y +CONFIG_ENABLE_MUST_CHECK=y +# CONFIG_MAGIC_SYSRQ is not set +# CONFIG_UNUSED_SYMBOLS is not set +# CONFIG_DEBUG_KERNEL is not set CONFIG_LOG_BUF_SHIFT=14 -CONFIG_DETECT_SOFTLOCKUP=y -# CONFIG_SCHEDSTATS is not set -# CONFIG_DEBUG_SLAB is not set -# CONFIG_DEBUG_SPINLOCK is not set -# CONFIG_DEBUG_SPINLOCK_SLEEP is not set -# CONFIG_DEBUG_KOBJECT is not set -# CONFIG_DEBUG_BUGVERBOSE is not set -CONFIG_DEBUG_INFO=y +CONFIG_DEBUG_BUGVERBOSE=y # CONFIG_DEBUG_FS is not set # CONFIG_FRAME_POINTER is not set -# CONFIG_DEBUG_STACKOVERFLOW is not set -# CONFIG_DEBUG_STACK_USAGE is not set +# CONFIG_UNWIND_INFO is not set +# CONFIG_HEADERS_CHECK is not set # # Security options @@ -641,7 +1090,38 @@ # CONFIG_SECURITY is not set # # Cryptographic options # -# CONFIG_CRYPTO is not set +CONFIG_CRYPTO=y +CONFIG_CRYPTO_ALGAPI=y +CONFIG_CRYPTO_BLKCIPHER=m +CONFIG_CRYPTO_HASH=y +CONFIG_CRYPTO_MANAGER=y +CONFIG_CRYPTO_HMAC=y +CONFIG_CRYPTO_NULL=m +CONFIG_CRYPTO_MD4=m +CONFIG_CRYPTO_MD5=m +CONFIG_CRYPTO_SHA1=m +CONFIG_CRYPTO_SHA256=m +CONFIG_CRYPTO_SHA512=m +CONFIG_CRYPTO_WP512=m +# CONFIG_CRYPTO_TGR192 is not set +CONFIG_CRYPTO_ECB=m +CONFIG_CRYPTO_CBC=m +CONFIG_CRYPTO_DES=m +CONFIG_CRYPTO_BLOWFISH=m +CONFIG_CRYPTO_TWOFISH=m +CONFIG_CRYPTO_TWOFISH_COMMON=m +CONFIG_CRYPTO_SERPENT=m +CONFIG_CRYPTO_AES=m +# CONFIG_CRYPTO_CAST5 is not set +# CONFIG_CRYPTO_CAST6 is not set +# CONFIG_CRYPTO_TEA is not set +# CONFIG_CRYPTO_ARC4 is not set +# CONFIG_CRYPTO_KHAZAD is not set +# CONFIG_CRYPTO_ANUBIS is not set +# CONFIG_CRYPTO_DEFLATE is not set +# CONFIG_CRYPTO_MICHAEL_MIC is not set +CONFIG_CRYPTO_CRC32C=m +# CONFIG_CRYPTO_TEST is not set # # Hardware crypto devices @@ -650,8 +1130,12 @@ # # # Library routines # -# CONFIG_CRC_CCITT is not set -# CONFIG_CRC16 is not set +CONFIG_CRC_CCITT=m +CONFIG_CRC16=m CONFIG_CRC32=y -CONFIG_LIBCRC32C=y -CONFIG_ZLIB_INFLATE=y +CONFIG_LIBCRC32C=m +CONFIG_TEXTSEARCH=y +CONFIG_TEXTSEARCH_KMP=m +CONFIG_TEXTSEARCH_BM=m +CONFIG_TEXTSEARCH_FSM=m +CONFIG_PLIST=y diff --git a/arch/m32r/m32700ut/defconfig.m32700ut.smp b/arch/m32r/m32700ut/defconfig.m32700ut.smp index 3e607d9..1357991 100644 --- a/arch/m32r/m32700ut/defconfig.m32700ut.smp +++ b/arch/m32r/m32700ut/defconfig.m32700ut.smp @@ -1,19 +1,18 @@ # # Automatically generated make config: don't edit -# Linux kernel version: 2.6.12-rc5 -# Fri Jun 3 16:20:58 2005 +# Linux kernel version: 2.6.19 +# Tue Dec 12 17:52:38 2006 # CONFIG_M32R=y -# CONFIG_UID16 is not set CONFIG_GENERIC_ISA_DMA=y CONFIG_GENERIC_HARDIRQS=y CONFIG_GENERIC_IRQ_PROBE=y +CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config" # # Code maturity level options # CONFIG_EXPERIMENTAL=y -CONFIG_CLEAN_COMPILE=y CONFIG_LOCK_KERNEL=y CONFIG_INIT_ENV_ARG_LIMIT=32 @@ -21,33 +20,40 @@ # # General setup # CONFIG_LOCALVERSION="" +CONFIG_LOCALVERSION_AUTO=y CONFIG_SWAP=y CONFIG_SYSVIPC=y +# CONFIG_IPC_NS is not set # CONFIG_POSIX_MQUEUE is not set CONFIG_BSD_PROCESS_ACCT=y # CONFIG_BSD_PROCESS_ACCT_V3 is not set -CONFIG_SYSCTL=y +# CONFIG_TASKSTATS is not set +# CONFIG_UTS_NS is not set # CONFIG_AUDIT is not set -CONFIG_HOTPLUG=y -CONFIG_KOBJECT_UEVENT=y CONFIG_IKCONFIG=y -# CONFIG_IKCONFIG_PROC is not set +CONFIG_IKCONFIG_PROC=y # CONFIG_CPUSETS is not set +CONFIG_SYSFS_DEPRECATED=y +# CONFIG_RELAY is not set +CONFIG_INITRAMFS_SOURCE="" +# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set +CONFIG_SYSCTL=y CONFIG_EMBEDDED=y +CONFIG_SYSCTL_SYSCALL=y # CONFIG_KALLSYMS is not set +CONFIG_HOTPLUG=y CONFIG_PRINTK=y CONFIG_BUG=y +CONFIG_ELF_CORE=y CONFIG_BASE_FULL=y # CONFIG_FUTEX is not set # CONFIG_EPOLL is not set -# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set CONFIG_SHMEM=y -CONFIG_CC_ALIGN_FUNCTIONS=0 -CONFIG_CC_ALIGN_LABELS=0 -CONFIG_CC_ALIGN_LOOPS=0 -CONFIG_CC_ALIGN_JUMPS=0 +CONFIG_SLAB=y +CONFIG_VM_EVENT_COUNTERS=y # CONFIG_TINY_SHMEM is not set CONFIG_BASE_SMALL=0 +# CONFIG_SLOB is not set # # Loadable module support @@ -55,13 +61,31 @@ # CONFIG_MODULES=y CONFIG_MODULE_UNLOAD=y # CONFIG_MODULE_FORCE_UNLOAD is not set -CONFIG_OBSOLETE_MODPARM=y # CONFIG_MODVERSIONS is not set # CONFIG_MODULE_SRCVERSION_ALL is not set CONFIG_KMOD=y CONFIG_STOP_MACHINE=y # +# Block layer +# +CONFIG_BLOCK=y +# CONFIG_BLK_DEV_IO_TRACE is not set + +# +# IO Schedulers +# +CONFIG_IOSCHED_NOOP=y +# CONFIG_IOSCHED_AS is not set +CONFIG_IOSCHED_DEADLINE=y +CONFIG_IOSCHED_CFQ=y +# CONFIG_DEFAULT_AS is not set +# CONFIG_DEFAULT_DEADLINE is not set +CONFIG_DEFAULT_CFQ=y +# CONFIG_DEFAULT_NOOP is not set +CONFIG_DEFAULT_IOSCHED="cfq" + +# # Processor type and features # # CONFIG_PLAT_MAPPI is not set @@ -71,8 +95,10 @@ # CONFIG_PLAT_OPSPUT is not set # CONFIG_PLAT_OAKS32R is not set # CONFIG_PLAT_MAPPI2 is not set # CONFIG_PLAT_MAPPI3 is not set +# CONFIG_PLAT_M32104UT is not set CONFIG_CHIP_M32700=y # CONFIG_CHIP_M32102 is not set +# CONFIG_CHIP_M32104 is not set # CONFIG_CHIP_VDEC2 is not set # CONFIG_CHIP_OPSP is not set CONFIG_MMU=y @@ -86,37 +112,39 @@ # CONFIG_CPU_LITTLE_ENDIAN is not set CONFIG_MEMORY_START=0x08000000 CONFIG_MEMORY_SIZE=0x01000000 CONFIG_NOHIGHMEM=y -# CONFIG_DISCONTIGMEM is not set +CONFIG_ARCH_DISCONTIGMEM_ENABLE=y +CONFIG_SELECT_MEMORY_MODEL=y +# CONFIG_FLATMEM_MANUAL is not set +CONFIG_DISCONTIGMEM_MANUAL=y +# CONFIG_SPARSEMEM_MANUAL is not set +CONFIG_DISCONTIGMEM=y +CONFIG_FLAT_NODE_MEM_MAP=y +CONFIG_NEED_MULTIPLE_NODES=y +# CONFIG_SPARSEMEM_STATIC is not set +CONFIG_SPLIT_PTLOCK_CPUS=4 +# CONFIG_RESOURCES_64BIT is not set +CONFIG_IRAM_START=0x00f00000 +CONFIG_IRAM_SIZE=0x00080000 CONFIG_RWSEM_GENERIC_SPINLOCK=y # CONFIG_RWSEM_XCHGADD_ALGORITHM is not set +CONFIG_GENERIC_FIND_NEXT_BIT=y +CONFIG_GENERIC_HWEIGHT=y CONFIG_GENERIC_CALIBRATE_DELAY=y CONFIG_PREEMPT=y -# CONFIG_HAVE_DEC_LOCK is not set CONFIG_SMP=y -CONFIG_CHIP_M32700_TS1=y +# CONFIG_CHIP_M32700_TS1 is not set CONFIG_NR_CPUS=2 -# CONFIG_NUMA is not set +CONFIG_NODES_SHIFT=1 # # Bus options (PCI, PCMCIA, EISA, MCA, ISA) # -# CONFIG_PCI is not set # CONFIG_ISA is not set # # PCCARD (PCMCIA/CardBus) support # -CONFIG_PCCARD=y -# CONFIG_PCMCIA_DEBUG is not set -CONFIG_PCMCIA=y - -# -# PC-card bridges -# -# CONFIG_TCIC is not set -# CONFIG_M32R_PCC is not set -CONFIG_M32R_CFC=y -CONFIG_M32R_CFC_NUM=1 +# CONFIG_PCCARD is not set # # PCI Hotplug Support @@ -129,6 +157,94 @@ CONFIG_BINFMT_ELF=y # CONFIG_BINFMT_MISC is not set # +# Networking +# +CONFIG_NET=y + +# +# Networking options +# +# CONFIG_NETDEBUG is not set +CONFIG_PACKET=y +# CONFIG_PACKET_MMAP is not set +CONFIG_UNIX=y +CONFIG_XFRM=y +# CONFIG_XFRM_USER is not set +# CONFIG_XFRM_SUB_POLICY is not set +# CONFIG_NET_KEY is not set +CONFIG_INET=y +# CONFIG_IP_MULTICAST is not set +# CONFIG_IP_ADVANCED_ROUTER is not set +CONFIG_IP_FIB_HASH=y +CONFIG_IP_PNP=y +CONFIG_IP_PNP_DHCP=y +# CONFIG_IP_PNP_BOOTP is not set +# CONFIG_IP_PNP_RARP is not set +# CONFIG_NET_IPIP is not set +# CONFIG_NET_IPGRE is not set +# CONFIG_ARPD is not set +# CONFIG_SYN_COOKIES is not set +# CONFIG_INET_AH is not set +# CONFIG_INET_ESP is not set +# CONFIG_INET_IPCOMP is not set +# CONFIG_INET_XFRM_TUNNEL is not set +# CONFIG_INET_TUNNEL is not set +CONFIG_INET_XFRM_MODE_TRANSPORT=y +CONFIG_INET_XFRM_MODE_TUNNEL=y +CONFIG_INET_XFRM_MODE_BEET=y +CONFIG_INET_DIAG=y +CONFIG_INET_TCP_DIAG=y +# CONFIG_TCP_CONG_ADVANCED is not set +CONFIG_TCP_CONG_CUBIC=y +CONFIG_DEFAULT_TCP_CONG="cubic" +# CONFIG_TCP_MD5SIG is not set +# CONFIG_IPV6 is not set +# CONFIG_INET6_XFRM_TUNNEL is not set +# CONFIG_INET6_TUNNEL is not set +# CONFIG_NETWORK_SECMARK is not set +# CONFIG_NETFILTER is not set + +# +# DCCP Configuration (EXPERIMENTAL) +# +# CONFIG_IP_DCCP is not set + +# +# SCTP Configuration (EXPERIMENTAL) +# +# CONFIG_IP_SCTP is not set + +# +# TIPC Configuration (EXPERIMENTAL) +# +# CONFIG_TIPC is not set +# CONFIG_ATM is not set +# CONFIG_BRIDGE is not set +# CONFIG_VLAN_8021Q is not set +# CONFIG_DECNET is not set +# CONFIG_LLC2 is not set +# CONFIG_IPX is not set +# CONFIG_ATALK is not set +# CONFIG_X25 is not set +# CONFIG_LAPB is not set +# CONFIG_ECONET is not set +# CONFIG_WAN_ROUTER is not set + +# +# QoS and/or fair queueing +# +# CONFIG_NET_SCHED is not set + +# +# Network testing +# +# CONFIG_NET_PKTGEN is not set +# CONFIG_HAMRADIO is not set +# CONFIG_IRDA is not set +# CONFIG_BT is not set +# CONFIG_IEEE80211 is not set + +# # Device Drivers # @@ -137,12 +253,100 @@ # Generic Driver Options # CONFIG_STANDALONE=y CONFIG_PREVENT_FIRMWARE_BUILD=y -# CONFIG_FW_LOADER is not set +CONFIG_FW_LOADER=y +# CONFIG_SYS_HYPERVISOR is not set + +# +# Connector - unified userspace <-> kernelspace linker +# +# CONFIG_CONNECTOR is not set # # Memory Technology Devices (MTD) # -# CONFIG_MTD is not set +CONFIG_MTD=y +# CONFIG_MTD_DEBUG is not set +# CONFIG_MTD_CONCAT is not set +CONFIG_MTD_PARTITIONS=y +CONFIG_MTD_REDBOOT_PARTS=y +CONFIG_MTD_REDBOOT_DIRECTORY_BLOCK=-1 +# CONFIG_MTD_REDBOOT_PARTS_UNALLOCATED is not set +# CONFIG_MTD_REDBOOT_PARTS_READONLY is not set +# CONFIG_MTD_CMDLINE_PARTS is not set + +# +# User Modules And Translation Layers +# +# CONFIG_MTD_CHAR is not set +CONFIG_MTD_BLOCK=y +# CONFIG_FTL is not set +# CONFIG_NFTL is not set +# CONFIG_INFTL is not set +# CONFIG_RFD_FTL is not set +# CONFIG_SSFDC is not set + +# +# RAM/ROM/Flash chip drivers +# +CONFIG_MTD_CFI=m +CONFIG_MTD_JEDECPROBE=m +CONFIG_MTD_GEN_PROBE=m +CONFIG_MTD_CFI_ADV_OPTIONS=y +# CONFIG_MTD_CFI_NOSWAP is not set +CONFIG_MTD_CFI_BE_BYTE_SWAP=y +# CONFIG_MTD_CFI_LE_BYTE_SWAP is not set +CONFIG_MTD_CFI_GEOMETRY=y +CONFIG_MTD_MAP_BANK_WIDTH_1=y +CONFIG_MTD_MAP_BANK_WIDTH_2=y +CONFIG_MTD_MAP_BANK_WIDTH_4=y +# CONFIG_MTD_MAP_BANK_WIDTH_8 is not set +# CONFIG_MTD_MAP_BANK_WIDTH_16 is not set +# CONFIG_MTD_MAP_BANK_WIDTH_32 is not set +CONFIG_MTD_CFI_I1=y +# CONFIG_MTD_CFI_I2 is not set +# CONFIG_MTD_CFI_I4 is not set +# CONFIG_MTD_CFI_I8 is not set +# CONFIG_MTD_OTP is not set +# CONFIG_MTD_CFI_INTELEXT is not set +CONFIG_MTD_CFI_AMDSTD=m +# CONFIG_MTD_CFI_STAA is not set +CONFIG_MTD_CFI_UTIL=m +# CONFIG_MTD_RAM is not set +# CONFIG_MTD_ROM is not set +# CONFIG_MTD_ABSENT is not set +# CONFIG_MTD_OBSOLETE_CHIPS is not set + +# +# Mapping drivers for chip access +# +# CONFIG_MTD_COMPLEX_MAPPINGS is not set +# CONFIG_MTD_PHYSMAP is not set +# CONFIG_MTD_PLATRAM is not set + +# +# Self-contained MTD device drivers +# +# CONFIG_MTD_SLRAM is not set +# CONFIG_MTD_PHRAM is not set +# CONFIG_MTD_MTDRAM is not set +# CONFIG_MTD_BLOCK2MTD is not set + +# +# Disk-On-Chip Device Drivers +# +# CONFIG_MTD_DOC2000 is not set +# CONFIG_MTD_DOC2001 is not set +# CONFIG_MTD_DOC2001PLUS is not set + +# +# NAND Flash Device Drivers +# +# CONFIG_MTD_NAND is not set + +# +# OneNAND Flash Device Drivers +# +# CONFIG_MTD_ONENAND is not set # # Parallel port support @@ -156,7 +360,6 @@ # # # Block devices # -# CONFIG_BLK_DEV_FD is not set # CONFIG_BLK_DEV_COW_COMMON is not set CONFIG_BLK_DEV_LOOP=y # CONFIG_BLK_DEV_CRYPTOLOOP is not set @@ -164,23 +367,21 @@ CONFIG_BLK_DEV_NBD=y CONFIG_BLK_DEV_RAM=y CONFIG_BLK_DEV_RAM_COUNT=16 CONFIG_BLK_DEV_RAM_SIZE=4096 +CONFIG_BLK_DEV_RAM_BLOCKSIZE=1024 # CONFIG_BLK_DEV_INITRD is not set -CONFIG_INITRAMFS_SOURCE="" # CONFIG_CDROM_PKTCDVD is not set +CONFIG_ATA_OVER_ETH=m # -# IO Schedulers +# Misc devices # -CONFIG_IOSCHED_NOOP=y -# CONFIG_IOSCHED_AS is not set -CONFIG_IOSCHED_DEADLINE=y -CONFIG_IOSCHED_CFQ=y -# CONFIG_ATA_OVER_ETH is not set +# CONFIG_TIFM_CORE is not set # # ATA/ATAPI/MFM/RLL support # CONFIG_IDE=y +CONFIG_IDE_MAX_HWIFS=4 CONFIG_BLK_DEV_IDE=y # @@ -189,7 +390,6 @@ # # CONFIG_BLK_DEV_IDE_SATA is not set CONFIG_BLK_DEV_IDEDISK=y # CONFIG_IDEDISK_MULTI_MODE is not set -CONFIG_BLK_DEV_IDECS=y CONFIG_BLK_DEV_IDECD=m # CONFIG_BLK_DEV_IDETAPE is not set # CONFIG_BLK_DEV_IDEFLOPPY is not set @@ -208,7 +408,9 @@ # CONFIG_BLK_DEV_HD is not set # # SCSI device support # +# CONFIG_RAID_ATTRS is not set CONFIG_SCSI=m +# CONFIG_SCSI_NETLINK is not set CONFIG_SCSI_PROC_FS=y # @@ -220,6 +422,7 @@ # CONFIG_CHR_DEV_OSST is not set CONFIG_BLK_DEV_SR=m # CONFIG_BLK_DEV_SR_VENDOR is not set CONFIG_CHR_DEV_SG=m +# CONFIG_CHR_DEV_SCH is not set # # Some SCSI devices (e.g. CD jukebox) support multiple LUNs @@ -229,26 +432,23 @@ # CONFIG_SCSI_CONSTANTS is not set # CONFIG_SCSI_LOGGING is not set # -# SCSI Transport Attributes +# SCSI Transports # # CONFIG_SCSI_SPI_ATTRS is not set # CONFIG_SCSI_FC_ATTRS is not set # CONFIG_SCSI_ISCSI_ATTRS is not set +# CONFIG_SCSI_SAS_ATTRS is not set +# CONFIG_SCSI_SAS_LIBSAS is not set # # SCSI low-level drivers # -# CONFIG_SCSI_SATA is not set +# CONFIG_ISCSI_TCP is not set # CONFIG_SCSI_DEBUG is not set # -# PCMCIA SCSI adapter support +# Serial ATA (prod) and Parallel ATA (experimental) drivers # -# CONFIG_PCMCIA_AHA152X is not set -# CONFIG_PCMCIA_FDOMAIN is not set -# CONFIG_PCMCIA_NINJA_SCSI is not set -# CONFIG_PCMCIA_QLOGIC is not set -# CONFIG_PCMCIA_SYM53C500 is not set # # Multi-device support (RAID and LVM) @@ -258,6 +458,7 @@ # CONFIG_MD is not set # # Fusion MPT device support # +# CONFIG_FUSION is not set # # IEEE 1394 (FireWire) support @@ -268,69 +469,8 @@ # I2O device support # # -# Networking support -# -CONFIG_NET=y - -# -# Networking options -# -CONFIG_PACKET=y -# CONFIG_PACKET_MMAP is not set -CONFIG_UNIX=y -# CONFIG_NET_KEY is not set -CONFIG_INET=y -# CONFIG_IP_MULTICAST is not set -# CONFIG_IP_ADVANCED_ROUTER is not set -CONFIG_IP_PNP=y -CONFIG_IP_PNP_DHCP=y -# CONFIG_IP_PNP_BOOTP is not set -# CONFIG_IP_PNP_RARP is not set -# CONFIG_NET_IPIP is not set -# CONFIG_NET_IPGRE is not set -# CONFIG_ARPD is not set -# CONFIG_SYN_COOKIES is not set -# CONFIG_INET_AH is not set -# CONFIG_INET_ESP is not set -# CONFIG_INET_IPCOMP is not set -# CONFIG_INET_TUNNEL is not set -CONFIG_IP_TCPDIAG=y -# CONFIG_IP_TCPDIAG_IPV6 is not set -# CONFIG_IPV6 is not set -# CONFIG_NETFILTER is not set - -# -# SCTP Configuration (EXPERIMENTAL) -# -# CONFIG_IP_SCTP is not set -# CONFIG_ATM is not set -# CONFIG_BRIDGE is not set -# CONFIG_VLAN_8021Q is not set -# CONFIG_DECNET is not set -# CONFIG_LLC2 is not set -# CONFIG_IPX is not set -# CONFIG_ATALK is not set -# CONFIG_X25 is not set -# CONFIG_LAPB is not set -# CONFIG_NET_DIVERT is not set -# CONFIG_ECONET is not set -# CONFIG_WAN_ROUTER is not set - -# -# QoS and/or fair queueing -# -# CONFIG_NET_SCHED is not set -# CONFIG_NET_CLS_ROUTE is not set - -# -# Network testing +# Network device support # -# CONFIG_NET_PKTGEN is not set -# CONFIG_NETPOLL is not set -# CONFIG_NET_POLL_CONTROLLER is not set -# CONFIG_HAMRADIO is not set -# CONFIG_IRDA is not set -# CONFIG_BT is not set CONFIG_NETDEVICES=y # CONFIG_DUMMY is not set # CONFIG_BONDING is not set @@ -338,6 +478,11 @@ # CONFIG_EQUALIZER is not set # CONFIG_TUN is not set # +# PHY device support +# +# CONFIG_PHYLIB is not set + +# # Ethernet (10 or 100Mbit) # CONFIG_NET_ETHERNET=y @@ -363,11 +508,6 @@ # # CONFIG_NET_RADIO is not set # -# PCMCIA network device support -# -# CONFIG_NET_PCMCIA is not set - -# # Wan interfaces # # CONFIG_WAN is not set @@ -375,6 +515,8 @@ # CONFIG_PPP is not set # CONFIG_SLIP is not set # CONFIG_SHAPER is not set # CONFIG_NETCONSOLE is not set +# CONFIG_NETPOLL is not set +# CONFIG_NET_POLL_CONTROLLER is not set # # ISDN subsystem @@ -390,6 +532,7 @@ # # Input device support # CONFIG_INPUT=y +# CONFIG_INPUT_FF_MEMLESS is not set # # Userland interfaces @@ -418,7 +561,6 @@ CONFIG_SERIO_SERPORT=y # CONFIG_SERIO_LIBPS2 is not set # CONFIG_SERIO_RAW is not set # CONFIG_GAMEPORT is not set -CONFIG_SOUND_GAMEPORT=y # # Character devices @@ -426,6 +568,7 @@ # CONFIG_VT=y CONFIG_VT_CONSOLE=y CONFIG_HW_CONSOLE=y +# CONFIG_VT_HW_CONSOLE_BINDING is not set # CONFIG_SERIAL_NONSTANDARD is not set # @@ -454,8 +597,8 @@ # # Watchdog Cards # # CONFIG_WATCHDOG is not set +CONFIG_HW_RANDOM=y # CONFIG_RTC is not set -# CONFIG_GEN_RTC is not set CONFIG_DS1302=y # CONFIG_DTLK is not set # CONFIG_R3964 is not set @@ -463,17 +606,12 @@ # CONFIG_R3964 is not set # # Ftape, the floppy tape device driver # -# CONFIG_DRM is not set - -# -# PCMCIA character devices -# -# CONFIG_SYNCLINK_CS is not set # CONFIG_RAW_DRIVER is not set # # TPM devices # +# CONFIG_TCG_TPM is not set # # I2C support @@ -481,34 +619,51 @@ # # CONFIG_I2C is not set # +# SPI support +# +# CONFIG_SPI is not set +# CONFIG_SPI_MASTER is not set + +# # Dallas's 1-wire bus # # CONFIG_W1 is not set # -# Misc devices +# Hardware Monitoring support # +CONFIG_HWMON=y +# CONFIG_HWMON_VID is not set +# CONFIG_SENSORS_ABITUGURU is not set +# CONFIG_SENSORS_F71805F is not set +# CONFIG_SENSORS_VT1211 is not set +# CONFIG_HWMON_DEBUG_CHIP is not set # # Multimedia devices # -CONFIG_VIDEO_DEV=y +CONFIG_VIDEO_DEV=m +CONFIG_VIDEO_V4L1=y +CONFIG_VIDEO_V4L1_COMPAT=y +CONFIG_VIDEO_V4L2=y # -# Video For Linux +# Video Capture Adapters # # -# Video Adapters +# Video Capture Adapters # +# CONFIG_VIDEO_ADV_DEBUG is not set +CONFIG_VIDEO_HELPER_CHIPS_AUTO=y +# CONFIG_VIDEO_VIVI is not set # CONFIG_VIDEO_CPIA is not set -CONFIG_VIDEO_M32R_AR=y -CONFIG_VIDEO_M32R_AR_M64278=y +CONFIG_VIDEO_M32R_AR=m +CONFIG_VIDEO_M32R_AR_M64278=m # # Radio Adapters # -# CONFIG_RADIO_MAESTRO is not set # # Digital Video Broadcasting Devices @@ -518,15 +673,16 @@ # CONFIG_DVB is not set # # Graphics support # +CONFIG_FIRMWARE_EDID=y CONFIG_FB=y -# CONFIG_FB_CFB_FILLRECT is not set -# CONFIG_FB_CFB_COPYAREA is not set -# CONFIG_FB_CFB_IMAGEBLIT is not set -# CONFIG_FB_SOFT_CURSOR is not set +CONFIG_FB_CFB_FILLRECT=y +CONFIG_FB_CFB_COPYAREA=y +CONFIG_FB_CFB_IMAGEBLIT=y # CONFIG_FB_MACMODES is not set +# CONFIG_FB_BACKLIGHT is not set # CONFIG_FB_MODE_HELPERS is not set # CONFIG_FB_TILEBLITTING is not set -# CONFIG_FB_S1D13XXX is not set +CONFIG_FB_S1D13XXX=y # CONFIG_FB_VIRTUAL is not set # @@ -535,6 +691,7 @@ # # CONFIG_VGA_CONSOLE is not set CONFIG_DUMMY_CONSOLE=y CONFIG_FRAMEBUFFER_CONSOLE=y +# CONFIG_FRAMEBUFFER_CONSOLE_ROTATION is not set # CONFIG_FONTS is not set CONFIG_FONT_8x8=y CONFIG_FONT_8x16=y @@ -546,6 +703,7 @@ CONFIG_LOGO=y CONFIG_LOGO_LINUX_MONO=y CONFIG_LOGO_LINUX_VGA16=y CONFIG_LOGO_LINUX_CLUT224=y +CONFIG_LOGO_M32R_CLUT224=y # CONFIG_BACKLIGHT_LCD_SUPPORT is not set # @@ -558,6 +716,11 @@ # USB support # # CONFIG_USB_ARCH_HAS_HCD is not set # CONFIG_USB_ARCH_HAS_OHCI is not set +# CONFIG_USB_ARCH_HAS_EHCI is not set + +# +# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support' +# # # USB Gadget Support @@ -567,23 +730,62 @@ # CONFIG_USB_GADGET is not set # # MMC/SD Card support # -# CONFIG_MMC is not set +CONFIG_MMC=y +CONFIG_MMC_DEBUG=y +CONFIG_MMC_BLOCK=y +# CONFIG_MMC_TIFM_SD is not set + +# +# LED devices +# +# CONFIG_NEW_LEDS is not set + +# +# LED drivers +# + +# +# LED Triggers +# # # InfiniBand support # -# CONFIG_INFINIBAND is not set + +# +# EDAC - error detection and reporting (RAS) (EXPERIMENTAL) +# + +# +# Real Time Clock +# +# CONFIG_RTC_CLASS is not set + +# +# DMA Engine support +# +# CONFIG_DMA_ENGINE is not set + +# +# DMA Clients +# + +# +# DMA Devices +# # # File systems # CONFIG_EXT2_FS=y # CONFIG_EXT2_FS_XATTR is not set -CONFIG_EXT3_FS=m +# CONFIG_EXT2_FS_XIP is not set +CONFIG_EXT3_FS=y CONFIG_EXT3_FS_XATTR=y # CONFIG_EXT3_FS_POSIX_ACL is not set # CONFIG_EXT3_FS_SECURITY is not set -CONFIG_JBD=m +# CONFIG_EXT4DEV_FS is not set +CONFIG_JBD=y CONFIG_JBD_DEBUG=y CONFIG_FS_MBCACHE=y CONFIG_REISERFS_FS=m @@ -591,17 +793,19 @@ # CONFIG_REISERFS_CHECK is not set # CONFIG_REISERFS_PROC_INFO is not set # CONFIG_REISERFS_FS_XATTR is not set # CONFIG_JFS_FS is not set - -# -# XFS support -# +# CONFIG_FS_POSIX_ACL is not set # CONFIG_XFS_FS is not set +# CONFIG_GFS2_FS is not set +# CONFIG_OCFS2_FS is not set # CONFIG_MINIX_FS is not set # CONFIG_ROMFS_FS is not set +CONFIG_INOTIFY=y +CONFIG_INOTIFY_USER=y # CONFIG_QUOTA is not set CONFIG_DNOTIFY=y # CONFIG_AUTOFS_FS is not set # CONFIG_AUTOFS4_FS is not set +# CONFIG_FUSE_FS is not set # # CD-ROM/DVD Filesystems @@ -627,15 +831,13 @@ # Pseudo filesystems # CONFIG_PROC_FS=y CONFIG_PROC_KCORE=y +CONFIG_PROC_SYSCTL=y CONFIG_SYSFS=y -CONFIG_DEVFS_FS=y -CONFIG_DEVFS_MOUNT=y -# CONFIG_DEVFS_DEBUG is not set -# CONFIG_DEVPTS_FS_XATTR is not set CONFIG_TMPFS=y -# CONFIG_TMPFS_XATTR is not set +# CONFIG_TMPFS_POSIX_ACL is not set # CONFIG_HUGETLB_PAGE is not set CONFIG_RAMFS=y +# CONFIG_CONFIGFS_FS is not set # # Miscellaneous filesystems @@ -647,6 +849,8 @@ # CONFIG_HFSPLUS_FS is not set # CONFIG_BEFS_FS is not set # CONFIG_BFS_FS is not set # CONFIG_EFS_FS is not set +# CONFIG_JFFS_FS is not set +# CONFIG_JFFS2_FS is not set # CONFIG_CRAMFS is not set # CONFIG_VXFS_FS is not set # CONFIG_HPFS_FS is not set @@ -659,12 +863,14 @@ # Network File Systems # CONFIG_NFS_FS=y CONFIG_NFS_V3=y +# CONFIG_NFS_V3_ACL is not set # CONFIG_NFS_V4 is not set # CONFIG_NFS_DIRECTIO is not set # CONFIG_NFSD is not set CONFIG_ROOT_NFS=y CONFIG_LOCKD=y CONFIG_LOCKD_V4=y +CONFIG_NFS_COMMON=y CONFIG_SUNRPC=y # CONFIG_RPCSEC_GSS_KRB5 is not set # CONFIG_RPCSEC_GSS_SPKM3 is not set @@ -673,6 +879,7 @@ # CONFIG_CIFS is not set # CONFIG_NCP_FS is not set # CONFIG_CODA_FS is not set # CONFIG_AFS_FS is not set +# CONFIG_9P_FS is not set # # Partition Types @@ -727,16 +934,23 @@ # CONFIG_NLS_UTF8 is not set # # Profiling support # -# CONFIG_PROFILING is not set +CONFIG_PROFILING=y +CONFIG_OPROFILE=y # # Kernel hacking # # CONFIG_PRINTK_TIME is not set +CONFIG_ENABLE_MUST_CHECK=y +# CONFIG_MAGIC_SYSRQ is not set +# CONFIG_UNUSED_SYMBOLS is not set # CONFIG_DEBUG_KERNEL is not set CONFIG_LOG_BUF_SHIFT=15 # CONFIG_DEBUG_BUGVERBOSE is not set +# CONFIG_DEBUG_FS is not set # CONFIG_FRAME_POINTER is not set +# CONFIG_UNWIND_INFO is not set +# CONFIG_HEADERS_CHECK is not set # # Security options @@ -750,12 +964,9 @@ # # CONFIG_CRYPTO is not set # -# Hardware crypto devices -# - -# # Library routines # # CONFIG_CRC_CCITT is not set +# CONFIG_CRC16 is not set CONFIG_CRC32=y # CONFIG_LIBCRC32C is not set diff --git a/arch/m32r/m32700ut/defconfig.m32700ut.up b/arch/m32r/m32700ut/defconfig.m32700ut.up index 2d3e7cd..190f961 100644 --- a/arch/m32r/m32700ut/defconfig.m32700ut.up +++ b/arch/m32r/m32700ut/defconfig.m32700ut.up @@ -1,19 +1,18 @@ # # Automatically generated make config: don't edit -# Linux kernel version: 2.6.12-rc5 -# Fri Jun 3 16:21:34 2005 +# Linux kernel version: 2.6.19 +# Tue Dec 12 12:07:08 2006 # CONFIG_M32R=y -# CONFIG_UID16 is not set CONFIG_GENERIC_ISA_DMA=y CONFIG_GENERIC_HARDIRQS=y CONFIG_GENERIC_IRQ_PROBE=y +CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config" # # Code maturity level options # CONFIG_EXPERIMENTAL=y -CONFIG_CLEAN_COMPILE=y CONFIG_BROKEN_ON_SMP=y CONFIG_LOCK_KERNEL=y CONFIG_INIT_ENV_ARG_LIMIT=32 @@ -22,32 +21,39 @@ # # General setup # CONFIG_LOCALVERSION="" +CONFIG_LOCALVERSION_AUTO=y CONFIG_SWAP=y CONFIG_SYSVIPC=y +# CONFIG_IPC_NS is not set # CONFIG_POSIX_MQUEUE is not set CONFIG_BSD_PROCESS_ACCT=y # CONFIG_BSD_PROCESS_ACCT_V3 is not set -CONFIG_SYSCTL=y +# CONFIG_TASKSTATS is not set +# CONFIG_UTS_NS is not set # CONFIG_AUDIT is not set -CONFIG_HOTPLUG=y -CONFIG_KOBJECT_UEVENT=y CONFIG_IKCONFIG=y -# CONFIG_IKCONFIG_PROC is not set +CONFIG_IKCONFIG_PROC=y +CONFIG_SYSFS_DEPRECATED=y +# CONFIG_RELAY is not set +CONFIG_INITRAMFS_SOURCE="" +# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set +CONFIG_SYSCTL=y CONFIG_EMBEDDED=y +CONFIG_SYSCTL_SYSCALL=y # CONFIG_KALLSYMS is not set +CONFIG_HOTPLUG=y CONFIG_PRINTK=y CONFIG_BUG=y +CONFIG_ELF_CORE=y CONFIG_BASE_FULL=y # CONFIG_FUTEX is not set # CONFIG_EPOLL is not set -# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set CONFIG_SHMEM=y -CONFIG_CC_ALIGN_FUNCTIONS=0 -CONFIG_CC_ALIGN_LABELS=0 -CONFIG_CC_ALIGN_LOOPS=0 -CONFIG_CC_ALIGN_JUMPS=0 +CONFIG_SLAB=y +CONFIG_VM_EVENT_COUNTERS=y # CONFIG_TINY_SHMEM is not set CONFIG_BASE_SMALL=0 +# CONFIG_SLOB is not set # # Loadable module support @@ -55,12 +61,30 @@ # CONFIG_MODULES=y CONFIG_MODULE_UNLOAD=y # CONFIG_MODULE_FORCE_UNLOAD is not set -CONFIG_OBSOLETE_MODPARM=y # CONFIG_MODVERSIONS is not set # CONFIG_MODULE_SRCVERSION_ALL is not set CONFIG_KMOD=y # +# Block layer +# +CONFIG_BLOCK=y +# CONFIG_BLK_DEV_IO_TRACE is not set + +# +# IO Schedulers +# +CONFIG_IOSCHED_NOOP=y +# CONFIG_IOSCHED_AS is not set +CONFIG_IOSCHED_DEADLINE=y +CONFIG_IOSCHED_CFQ=y +# CONFIG_DEFAULT_AS is not set +# CONFIG_DEFAULT_DEADLINE is not set +CONFIG_DEFAULT_CFQ=y +# CONFIG_DEFAULT_NOOP is not set +CONFIG_DEFAULT_IOSCHED="cfq" + +# # Processor type and features # # CONFIG_PLAT_MAPPI is not set @@ -70,8 +94,10 @@ # CONFIG_PLAT_OPSPUT is not set # CONFIG_PLAT_OAKS32R is not set # CONFIG_PLAT_MAPPI2 is not set # CONFIG_PLAT_MAPPI3 is not set +# CONFIG_PLAT_M32104UT is not set CONFIG_CHIP_M32700=y # CONFIG_CHIP_M32102 is not set +# CONFIG_CHIP_M32104 is not set # CONFIG_CHIP_VDEC2 is not set # CONFIG_CHIP_OPSP is not set CONFIG_MMU=y @@ -85,34 +111,37 @@ # CONFIG_CPU_LITTLE_ENDIAN is not set CONFIG_MEMORY_START=0x08000000 CONFIG_MEMORY_SIZE=0x01000000 CONFIG_NOHIGHMEM=y -# CONFIG_DISCONTIGMEM is not set +CONFIG_ARCH_DISCONTIGMEM_ENABLE=y +CONFIG_SELECT_MEMORY_MODEL=y +# CONFIG_FLATMEM_MANUAL is not set +CONFIG_DISCONTIGMEM_MANUAL=y +# CONFIG_SPARSEMEM_MANUAL is not set +CONFIG_DISCONTIGMEM=y +CONFIG_FLAT_NODE_MEM_MAP=y +CONFIG_NEED_MULTIPLE_NODES=y +# CONFIG_SPARSEMEM_STATIC is not set +CONFIG_SPLIT_PTLOCK_CPUS=4 +# CONFIG_RESOURCES_64BIT is not set +CONFIG_IRAM_START=0x00f00000 +CONFIG_IRAM_SIZE=0x00080000 CONFIG_RWSEM_GENERIC_SPINLOCK=y # CONFIG_RWSEM_XCHGADD_ALGORITHM is not set +CONFIG_GENERIC_FIND_NEXT_BIT=y +CONFIG_GENERIC_HWEIGHT=y CONFIG_GENERIC_CALIBRATE_DELAY=y CONFIG_PREEMPT=y -# CONFIG_HAVE_DEC_LOCK is not set # CONFIG_SMP is not set +CONFIG_NODES_SHIFT=1 # # Bus options (PCI, PCMCIA, EISA, MCA, ISA) # -# CONFIG_PCI is not set # CONFIG_ISA is not set # # PCCARD (PCMCIA/CardBus) support # -CONFIG_PCCARD=y -# CONFIG_PCMCIA_DEBUG is not set -CONFIG_PCMCIA=y - -# -# PC-card bridges -# -# CONFIG_TCIC is not set -# CONFIG_M32R_PCC is not set -CONFIG_M32R_CFC=y -CONFIG_M32R_CFC_NUM=1 +# CONFIG_PCCARD is not set # # PCI Hotplug Support @@ -125,6 +154,94 @@ CONFIG_BINFMT_ELF=y # CONFIG_BINFMT_MISC is not set # +# Networking +# +CONFIG_NET=y + +# +# Networking options +# +# CONFIG_NETDEBUG is not set +CONFIG_PACKET=y +# CONFIG_PACKET_MMAP is not set +CONFIG_UNIX=y +CONFIG_XFRM=y +# CONFIG_XFRM_USER is not set +# CONFIG_XFRM_SUB_POLICY is not set +# CONFIG_NET_KEY is not set +CONFIG_INET=y +# CONFIG_IP_MULTICAST is not set +# CONFIG_IP_ADVANCED_ROUTER is not set +CONFIG_IP_FIB_HASH=y +CONFIG_IP_PNP=y +CONFIG_IP_PNP_DHCP=y +# CONFIG_IP_PNP_BOOTP is not set +# CONFIG_IP_PNP_RARP is not set +# CONFIG_NET_IPIP is not set +# CONFIG_NET_IPGRE is not set +# CONFIG_ARPD is not set +# CONFIG_SYN_COOKIES is not set +# CONFIG_INET_AH is not set +# CONFIG_INET_ESP is not set +# CONFIG_INET_IPCOMP is not set +# CONFIG_INET_XFRM_TUNNEL is not set +# CONFIG_INET_TUNNEL is not set +CONFIG_INET_XFRM_MODE_TRANSPORT=y +CONFIG_INET_XFRM_MODE_TUNNEL=y +CONFIG_INET_XFRM_MODE_BEET=y +CONFIG_INET_DIAG=y +CONFIG_INET_TCP_DIAG=y +# CONFIG_TCP_CONG_ADVANCED is not set +CONFIG_TCP_CONG_CUBIC=y +CONFIG_DEFAULT_TCP_CONG="cubic" +# CONFIG_TCP_MD5SIG is not set +# CONFIG_IPV6 is not set +# CONFIG_INET6_XFRM_TUNNEL is not set +# CONFIG_INET6_TUNNEL is not set +# CONFIG_NETWORK_SECMARK is not set +# CONFIG_NETFILTER is not set + +# +# DCCP Configuration (EXPERIMENTAL) +# +# CONFIG_IP_DCCP is not set + +# +# SCTP Configuration (EXPERIMENTAL) +# +# CONFIG_IP_SCTP is not set + +# +# TIPC Configuration (EXPERIMENTAL) +# +# CONFIG_TIPC is not set +# CONFIG_ATM is not set +# CONFIG_BRIDGE is not set +# CONFIG_VLAN_8021Q is not set +# CONFIG_DECNET is not set +# CONFIG_LLC2 is not set +# CONFIG_IPX is not set +# CONFIG_ATALK is not set +# CONFIG_X25 is not set +# CONFIG_LAPB is not set +# CONFIG_ECONET is not set +# CONFIG_WAN_ROUTER is not set + +# +# QoS and/or fair queueing +# +# CONFIG_NET_SCHED is not set + +# +# Network testing +# +# CONFIG_NET_PKTGEN is not set +# CONFIG_HAMRADIO is not set +# CONFIG_IRDA is not set +# CONFIG_BT is not set +# CONFIG_IEEE80211 is not set + +# # Device Drivers # @@ -133,12 +250,100 @@ # Generic Driver Options # CONFIG_STANDALONE=y CONFIG_PREVENT_FIRMWARE_BUILD=y -# CONFIG_FW_LOADER is not set +CONFIG_FW_LOADER=y +# CONFIG_SYS_HYPERVISOR is not set + +# +# Connector - unified userspace <-> kernelspace linker +# +# CONFIG_CONNECTOR is not set # # Memory Technology Devices (MTD) # -# CONFIG_MTD is not set +CONFIG_MTD=y +# CONFIG_MTD_DEBUG is not set +# CONFIG_MTD_CONCAT is not set +CONFIG_MTD_PARTITIONS=y +CONFIG_MTD_REDBOOT_PARTS=y +CONFIG_MTD_REDBOOT_DIRECTORY_BLOCK=-1 +# CONFIG_MTD_REDBOOT_PARTS_UNALLOCATED is not set +# CONFIG_MTD_REDBOOT_PARTS_READONLY is not set +# CONFIG_MTD_CMDLINE_PARTS is not set + +# +# User Modules And Translation Layers +# +# CONFIG_MTD_CHAR is not set +CONFIG_MTD_BLOCK=y +# CONFIG_FTL is not set +# CONFIG_NFTL is not set +# CONFIG_INFTL is not set +# CONFIG_RFD_FTL is not set +# CONFIG_SSFDC is not set + +# +# RAM/ROM/Flash chip drivers +# +CONFIG_MTD_CFI=m +CONFIG_MTD_JEDECPROBE=m +CONFIG_MTD_GEN_PROBE=m +CONFIG_MTD_CFI_ADV_OPTIONS=y +# CONFIG_MTD_CFI_NOSWAP is not set +CONFIG_MTD_CFI_BE_BYTE_SWAP=y +# CONFIG_MTD_CFI_LE_BYTE_SWAP is not set +CONFIG_MTD_CFI_GEOMETRY=y +CONFIG_MTD_MAP_BANK_WIDTH_1=y +CONFIG_MTD_MAP_BANK_WIDTH_2=y +CONFIG_MTD_MAP_BANK_WIDTH_4=y +# CONFIG_MTD_MAP_BANK_WIDTH_8 is not set +# CONFIG_MTD_MAP_BANK_WIDTH_16 is not set +# CONFIG_MTD_MAP_BANK_WIDTH_32 is not set +CONFIG_MTD_CFI_I1=y +# CONFIG_MTD_CFI_I2 is not set +# CONFIG_MTD_CFI_I4 is not set +# CONFIG_MTD_CFI_I8 is not set +# CONFIG_MTD_OTP is not set +# CONFIG_MTD_CFI_INTELEXT is not set +CONFIG_MTD_CFI_AMDSTD=m +# CONFIG_MTD_CFI_STAA is not set +CONFIG_MTD_CFI_UTIL=m +# CONFIG_MTD_RAM is not set +# CONFIG_MTD_ROM is not set +# CONFIG_MTD_ABSENT is not set +# CONFIG_MTD_OBSOLETE_CHIPS is not set + +# +# Mapping drivers for chip access +# +# CONFIG_MTD_COMPLEX_MAPPINGS is not set +# CONFIG_MTD_PHYSMAP is not set +# CONFIG_MTD_PLATRAM is not set + +# +# Self-contained MTD device drivers +# +# CONFIG_MTD_SLRAM is not set +# CONFIG_MTD_PHRAM is not set +# CONFIG_MTD_MTDRAM is not set +# CONFIG_MTD_BLOCK2MTD is not set + +# +# Disk-On-Chip Device Drivers +# +# CONFIG_MTD_DOC2000 is not set +# CONFIG_MTD_DOC2001 is not set +# CONFIG_MTD_DOC2001PLUS is not set + +# +# NAND Flash Device Drivers +# +# CONFIG_MTD_NAND is not set + +# +# OneNAND Flash Device Drivers +# +# CONFIG_MTD_ONENAND is not set # # Parallel port support @@ -152,7 +357,6 @@ # # # Block devices # -# CONFIG_BLK_DEV_FD is not set # CONFIG_BLK_DEV_COW_COMMON is not set CONFIG_BLK_DEV_LOOP=y # CONFIG_BLK_DEV_CRYPTOLOOP is not set @@ -160,23 +364,21 @@ CONFIG_BLK_DEV_NBD=y CONFIG_BLK_DEV_RAM=y CONFIG_BLK_DEV_RAM_COUNT=16 CONFIG_BLK_DEV_RAM_SIZE=4096 +CONFIG_BLK_DEV_RAM_BLOCKSIZE=1024 # CONFIG_BLK_DEV_INITRD is not set -CONFIG_INITRAMFS_SOURCE="" # CONFIG_CDROM_PKTCDVD is not set +CONFIG_ATA_OVER_ETH=m # -# IO Schedulers +# Misc devices # -CONFIG_IOSCHED_NOOP=y -# CONFIG_IOSCHED_AS is not set -CONFIG_IOSCHED_DEADLINE=y -CONFIG_IOSCHED_CFQ=y -# CONFIG_ATA_OVER_ETH is not set +# CONFIG_TIFM_CORE is not set # # ATA/ATAPI/MFM/RLL support # CONFIG_IDE=y +CONFIG_IDE_MAX_HWIFS=4 CONFIG_BLK_DEV_IDE=y # @@ -185,7 +387,6 @@ # # CONFIG_BLK_DEV_IDE_SATA is not set CONFIG_BLK_DEV_IDEDISK=y # CONFIG_IDEDISK_MULTI_MODE is not set -CONFIG_BLK_DEV_IDECS=y CONFIG_BLK_DEV_IDECD=m # CONFIG_BLK_DEV_IDETAPE is not set # CONFIG_BLK_DEV_IDEFLOPPY is not set @@ -204,7 +405,9 @@ # CONFIG_BLK_DEV_HD is not set # # SCSI device support # +# CONFIG_RAID_ATTRS is not set CONFIG_SCSI=m +# CONFIG_SCSI_NETLINK is not set CONFIG_SCSI_PROC_FS=y # @@ -216,6 +419,7 @@ # CONFIG_CHR_DEV_OSST is not set CONFIG_BLK_DEV_SR=m # CONFIG_BLK_DEV_SR_VENDOR is not set CONFIG_CHR_DEV_SG=m +# CONFIG_CHR_DEV_SCH is not set # # Some SCSI devices (e.g. CD jukebox) support multiple LUNs @@ -225,26 +429,23 @@ # CONFIG_SCSI_CONSTANTS is not set # CONFIG_SCSI_LOGGING is not set # -# SCSI Transport Attributes +# SCSI Transports # # CONFIG_SCSI_SPI_ATTRS is not set # CONFIG_SCSI_FC_ATTRS is not set # CONFIG_SCSI_ISCSI_ATTRS is not set +# CONFIG_SCSI_SAS_ATTRS is not set +# CONFIG_SCSI_SAS_LIBSAS is not set # # SCSI low-level drivers # -# CONFIG_SCSI_SATA is not set +# CONFIG_ISCSI_TCP is not set # CONFIG_SCSI_DEBUG is not set # -# PCMCIA SCSI adapter support +# Serial ATA (prod) and Parallel ATA (experimental) drivers # -# CONFIG_PCMCIA_AHA152X is not set -# CONFIG_PCMCIA_FDOMAIN is not set -# CONFIG_PCMCIA_NINJA_SCSI is not set -# CONFIG_PCMCIA_QLOGIC is not set -# CONFIG_PCMCIA_SYM53C500 is not set # # Multi-device support (RAID and LVM) @@ -254,6 +455,7 @@ # CONFIG_MD is not set # # Fusion MPT device support # +# CONFIG_FUSION is not set # # IEEE 1394 (FireWire) support @@ -264,69 +466,8 @@ # I2O device support # # -# Networking support -# -CONFIG_NET=y - -# -# Networking options -# -CONFIG_PACKET=y -# CONFIG_PACKET_MMAP is not set -CONFIG_UNIX=y -# CONFIG_NET_KEY is not set -CONFIG_INET=y -# CONFIG_IP_MULTICAST is not set -# CONFIG_IP_ADVANCED_ROUTER is not set -CONFIG_IP_PNP=y -CONFIG_IP_PNP_DHCP=y -# CONFIG_IP_PNP_BOOTP is not set -# CONFIG_IP_PNP_RARP is not set -# CONFIG_NET_IPIP is not set -# CONFIG_NET_IPGRE is not set -# CONFIG_ARPD is not set -# CONFIG_SYN_COOKIES is not set -# CONFIG_INET_AH is not set -# CONFIG_INET_ESP is not set -# CONFIG_INET_IPCOMP is not set -# CONFIG_INET_TUNNEL is not set -CONFIG_IP_TCPDIAG=y -# CONFIG_IP_TCPDIAG_IPV6 is not set -# CONFIG_IPV6 is not set -# CONFIG_NETFILTER is not set - -# -# SCTP Configuration (EXPERIMENTAL) -# -# CONFIG_IP_SCTP is not set -# CONFIG_ATM is not set -# CONFIG_BRIDGE is not set -# CONFIG_VLAN_8021Q is not set -# CONFIG_DECNET is not set -# CONFIG_LLC2 is not set -# CONFIG_IPX is not set -# CONFIG_ATALK is not set -# CONFIG_X25 is not set -# CONFIG_LAPB is not set -# CONFIG_NET_DIVERT is not set -# CONFIG_ECONET is not set -# CONFIG_WAN_ROUTER is not set - -# -# QoS and/or fair queueing -# -# CONFIG_NET_SCHED is not set -# CONFIG_NET_CLS_ROUTE is not set - -# -# Network testing +# Network device support # -# CONFIG_NET_PKTGEN is not set -# CONFIG_NETPOLL is not set -# CONFIG_NET_POLL_CONTROLLER is not set -# CONFIG_HAMRADIO is not set -# CONFIG_IRDA is not set -# CONFIG_BT is not set CONFIG_NETDEVICES=y # CONFIG_DUMMY is not set # CONFIG_BONDING is not set @@ -334,6 +475,11 @@ # CONFIG_EQUALIZER is not set # CONFIG_TUN is not set # +# PHY device support +# +# CONFIG_PHYLIB is not set + +# # Ethernet (10 or 100Mbit) # CONFIG_NET_ETHERNET=y @@ -359,11 +505,6 @@ # # CONFIG_NET_RADIO is not set # -# PCMCIA network device support -# -# CONFIG_NET_PCMCIA is not set - -# # Wan interfaces # # CONFIG_WAN is not set @@ -371,6 +512,8 @@ # CONFIG_PPP is not set # CONFIG_SLIP is not set # CONFIG_SHAPER is not set # CONFIG_NETCONSOLE is not set +# CONFIG_NETPOLL is not set +# CONFIG_NET_POLL_CONTROLLER is not set # # ISDN subsystem @@ -386,6 +529,7 @@ # # Input device support # CONFIG_INPUT=y +# CONFIG_INPUT_FF_MEMLESS is not set # # Userland interfaces @@ -414,7 +558,6 @@ CONFIG_SERIO_SERPORT=y # CONFIG_SERIO_LIBPS2 is not set # CONFIG_SERIO_RAW is not set # CONFIG_GAMEPORT is not set -CONFIG_SOUND_GAMEPORT=y # # Character devices @@ -422,6 +565,7 @@ # CONFIG_VT=y CONFIG_VT_CONSOLE=y CONFIG_HW_CONSOLE=y +# CONFIG_VT_HW_CONSOLE_BINDING is not set # CONFIG_SERIAL_NONSTANDARD is not set # @@ -450,8 +594,8 @@ # # Watchdog Cards # # CONFIG_WATCHDOG is not set +CONFIG_HW_RANDOM=y # CONFIG_RTC is not set -# CONFIG_GEN_RTC is not set CONFIG_DS1302=y # CONFIG_DTLK is not set # CONFIG_R3964 is not set @@ -459,17 +603,12 @@ # CONFIG_R3964 is not set # # Ftape, the floppy tape device driver # -# CONFIG_DRM is not set - -# -# PCMCIA character devices -# -# CONFIG_SYNCLINK_CS is not set # CONFIG_RAW_DRIVER is not set # # TPM devices # +# CONFIG_TCG_TPM is not set # # I2C support @@ -477,34 +616,51 @@ # # CONFIG_I2C is not set # +# SPI support +# +# CONFIG_SPI is not set +# CONFIG_SPI_MASTER is not set + +# # Dallas's 1-wire bus # # CONFIG_W1 is not set # -# Misc devices +# Hardware Monitoring support # +CONFIG_HWMON=y +# CONFIG_HWMON_VID is not set +# CONFIG_SENSORS_ABITUGURU is not set +# CONFIG_SENSORS_F71805F is not set +# CONFIG_SENSORS_VT1211 is not set +# CONFIG_HWMON_DEBUG_CHIP is not set # # Multimedia devices # -CONFIG_VIDEO_DEV=y +CONFIG_VIDEO_DEV=m +CONFIG_VIDEO_V4L1=y +CONFIG_VIDEO_V4L1_COMPAT=y +CONFIG_VIDEO_V4L2=y # -# Video For Linux +# Video Capture Adapters # # -# Video Adapters +# Video Capture Adapters # +# CONFIG_VIDEO_ADV_DEBUG is not set +CONFIG_VIDEO_HELPER_CHIPS_AUTO=y +# CONFIG_VIDEO_VIVI is not set # CONFIG_VIDEO_CPIA is not set -CONFIG_VIDEO_M32R_AR=y -CONFIG_VIDEO_M32R_AR_M64278=y +CONFIG_VIDEO_M32R_AR=m +CONFIG_VIDEO_M32R_AR_M64278=m # # Radio Adapters # -# CONFIG_RADIO_MAESTRO is not set # # Digital Video Broadcasting Devices @@ -514,15 +670,16 @@ # CONFIG_DVB is not set # # Graphics support # +CONFIG_FIRMWARE_EDID=y CONFIG_FB=y -# CONFIG_FB_CFB_FILLRECT is not set -# CONFIG_FB_CFB_COPYAREA is not set -# CONFIG_FB_CFB_IMAGEBLIT is not set -# CONFIG_FB_SOFT_CURSOR is not set +CONFIG_FB_CFB_FILLRECT=y +CONFIG_FB_CFB_COPYAREA=y +CONFIG_FB_CFB_IMAGEBLIT=y # CONFIG_FB_MACMODES is not set +# CONFIG_FB_BACKLIGHT is not set # CONFIG_FB_MODE_HELPERS is not set # CONFIG_FB_TILEBLITTING is not set -# CONFIG_FB_S1D13XXX is not set +CONFIG_FB_S1D13XXX=y # CONFIG_FB_VIRTUAL is not set # @@ -531,6 +688,7 @@ # # CONFIG_VGA_CONSOLE is not set CONFIG_DUMMY_CONSOLE=y CONFIG_FRAMEBUFFER_CONSOLE=y +# CONFIG_FRAMEBUFFER_CONSOLE_ROTATION is not set # CONFIG_FONTS is not set CONFIG_FONT_8x8=y CONFIG_FONT_8x16=y @@ -542,6 +700,7 @@ CONFIG_LOGO=y CONFIG_LOGO_LINUX_MONO=y CONFIG_LOGO_LINUX_VGA16=y CONFIG_LOGO_LINUX_CLUT224=y +CONFIG_LOGO_M32R_CLUT224=y # CONFIG_BACKLIGHT_LCD_SUPPORT is not set # @@ -554,6 +713,11 @@ # USB support # # CONFIG_USB_ARCH_HAS_HCD is not set # CONFIG_USB_ARCH_HAS_OHCI is not set +# CONFIG_USB_ARCH_HAS_EHCI is not set + +# +# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support' +# # # USB Gadget Support @@ -563,23 +727,62 @@ # CONFIG_USB_GADGET is not set # # MMC/SD Card support # -# CONFIG_MMC is not set +CONFIG_MMC=y +CONFIG_MMC_DEBUG=y +CONFIG_MMC_BLOCK=y +# CONFIG_MMC_TIFM_SD is not set + +# +# LED devices +# +# CONFIG_NEW_LEDS is not set + +# +# LED drivers +# + +# +# LED Triggers +# # # InfiniBand support # -# CONFIG_INFINIBAND is not set + +# +# EDAC - error detection and reporting (RAS) (EXPERIMENTAL) +# + +# +# Real Time Clock +# +# CONFIG_RTC_CLASS is not set + +# +# DMA Engine support +# +# CONFIG_DMA_ENGINE is not set + +# +# DMA Clients +# + +# +# DMA Devices +# # # File systems # CONFIG_EXT2_FS=y # CONFIG_EXT2_FS_XATTR is not set -CONFIG_EXT3_FS=m +# CONFIG_EXT2_FS_XIP is not set +CONFIG_EXT3_FS=y CONFIG_EXT3_FS_XATTR=y # CONFIG_EXT3_FS_POSIX_ACL is not set # CONFIG_EXT3_FS_SECURITY is not set -CONFIG_JBD=m +# CONFIG_EXT4DEV_FS is not set +CONFIG_JBD=y CONFIG_JBD_DEBUG=y CONFIG_FS_MBCACHE=y CONFIG_REISERFS_FS=m @@ -587,17 +790,19 @@ # CONFIG_REISERFS_CHECK is not set # CONFIG_REISERFS_PROC_INFO is not set # CONFIG_REISERFS_FS_XATTR is not set # CONFIG_JFS_FS is not set - -# -# XFS support -# +# CONFIG_FS_POSIX_ACL is not set # CONFIG_XFS_FS is not set +# CONFIG_GFS2_FS is not set +# CONFIG_OCFS2_FS is not set # CONFIG_MINIX_FS is not set # CONFIG_ROMFS_FS is not set +CONFIG_INOTIFY=y +CONFIG_INOTIFY_USER=y # CONFIG_QUOTA is not set CONFIG_DNOTIFY=y # CONFIG_AUTOFS_FS is not set # CONFIG_AUTOFS4_FS is not set +# CONFIG_FUSE_FS is not set # # CD-ROM/DVD Filesystems @@ -623,15 +828,13 @@ # Pseudo filesystems # CONFIG_PROC_FS=y CONFIG_PROC_KCORE=y +CONFIG_PROC_SYSCTL=y CONFIG_SYSFS=y -CONFIG_DEVFS_FS=y -CONFIG_DEVFS_MOUNT=y -# CONFIG_DEVFS_DEBUG is not set -# CONFIG_DEVPTS_FS_XATTR is not set CONFIG_TMPFS=y -# CONFIG_TMPFS_XATTR is not set +# CONFIG_TMPFS_POSIX_ACL is not set # CONFIG_HUGETLB_PAGE is not set CONFIG_RAMFS=y +# CONFIG_CONFIGFS_FS is not set # # Miscellaneous filesystems @@ -643,6 +846,8 @@ # CONFIG_HFSPLUS_FS is not set # CONFIG_BEFS_FS is not set # CONFIG_BFS_FS is not set # CONFIG_EFS_FS is not set +# CONFIG_JFFS_FS is not set +# CONFIG_JFFS2_FS is not set # CONFIG_CRAMFS is not set # CONFIG_VXFS_FS is not set # CONFIG_HPFS_FS is not set @@ -655,12 +860,14 @@ # Network File Systems # CONFIG_NFS_FS=y CONFIG_NFS_V3=y +# CONFIG_NFS_V3_ACL is not set # CONFIG_NFS_V4 is not set # CONFIG_NFS_DIRECTIO is not set # CONFIG_NFSD is not set CONFIG_ROOT_NFS=y CONFIG_LOCKD=y CONFIG_LOCKD_V4=y +CONFIG_NFS_COMMON=y CONFIG_SUNRPC=y # CONFIG_RPCSEC_GSS_KRB5 is not set # CONFIG_RPCSEC_GSS_SPKM3 is not set @@ -669,6 +876,7 @@ # CONFIG_CIFS is not set # CONFIG_NCP_FS is not set # CONFIG_CODA_FS is not set # CONFIG_AFS_FS is not set +# CONFIG_9P_FS is not set # # Partition Types @@ -723,16 +931,23 @@ # CONFIG_NLS_UTF8 is not set # # Profiling support # -# CONFIG_PROFILING is not set +CONFIG_PROFILING=y +CONFIG_OPROFILE=y # # Kernel hacking # # CONFIG_PRINTK_TIME is not set +CONFIG_ENABLE_MUST_CHECK=y +# CONFIG_MAGIC_SYSRQ is not set +# CONFIG_UNUSED_SYMBOLS is not set # CONFIG_DEBUG_KERNEL is not set CONFIG_LOG_BUF_SHIFT=14 # CONFIG_DEBUG_BUGVERBOSE is not set +# CONFIG_DEBUG_FS is not set # CONFIG_FRAME_POINTER is not set +# CONFIG_UNWIND_INFO is not set +# CONFIG_HEADERS_CHECK is not set # # Security options @@ -746,12 +961,9 @@ # # CONFIG_CRYPTO is not set # -# Hardware crypto devices -# - -# # Library routines # # CONFIG_CRC_CCITT is not set +# CONFIG_CRC16 is not set CONFIG_CRC32=y # CONFIG_LIBCRC32C is not set diff --git a/arch/m32r/mappi/defconfig.nommu b/arch/m32r/mappi/defconfig.nommu index a8425fb..fbf6c38 100644 --- a/arch/m32r/mappi/defconfig.nommu +++ b/arch/m32r/mappi/defconfig.nommu @@ -1,19 +1,18 @@ # # Automatically generated make config: don't edit -# Linux kernel version: 2.6.12-rc5 -# Fri Jun 3 16:21:46 2005 +# Linux kernel version: 2.6.19 +# Wed Dec 13 17:57:45 2006 # CONFIG_M32R=y -# CONFIG_UID16 is not set CONFIG_GENERIC_ISA_DMA=y CONFIG_GENERIC_HARDIRQS=y CONFIG_GENERIC_IRQ_PROBE=y +CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config" # # Code maturity level options # CONFIG_EXPERIMENTAL=y -CONFIG_CLEAN_COMPILE=y CONFIG_BROKEN_ON_SMP=y CONFIG_LOCK_KERNEL=y CONFIG_INIT_ENV_ARG_LIMIT=32 @@ -22,29 +21,36 @@ # # General setup # CONFIG_LOCALVERSION="" +CONFIG_LOCALVERSION_AUTO=y +# CONFIG_SYSVIPC is not set # CONFIG_POSIX_MQUEUE is not set CONFIG_BSD_PROCESS_ACCT=y # CONFIG_BSD_PROCESS_ACCT_V3 is not set -CONFIG_SYSCTL=y +# CONFIG_TASKSTATS is not set +# CONFIG_UTS_NS is not set # CONFIG_AUDIT is not set -CONFIG_HOTPLUG=y -CONFIG_KOBJECT_UEVENT=y CONFIG_IKCONFIG=y # CONFIG_IKCONFIG_PROC is not set +CONFIG_SYSFS_DEPRECATED=y +# CONFIG_RELAY is not set +CONFIG_INITRAMFS_SOURCE="" +# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set +CONFIG_SYSCTL=y CONFIG_EMBEDDED=y +CONFIG_SYSCTL_SYSCALL=y # CONFIG_KALLSYMS is not set +CONFIG_HOTPLUG=y CONFIG_PRINTK=y CONFIG_BUG=y +CONFIG_ELF_CORE=y CONFIG_BASE_FULL=y # CONFIG_FUTEX is not set # CONFIG_EPOLL is not set -# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set -CONFIG_CC_ALIGN_FUNCTIONS=0 -CONFIG_CC_ALIGN_LABELS=0 -CONFIG_CC_ALIGN_LOOPS=0 -CONFIG_CC_ALIGN_JUMPS=0 +CONFIG_SLAB=y +CONFIG_VM_EVENT_COUNTERS=y CONFIG_TINY_SHMEM=y CONFIG_BASE_SMALL=0 +# CONFIG_SLOB is not set # # Loadable module support @@ -52,12 +58,30 @@ # CONFIG_MODULES=y CONFIG_MODULE_UNLOAD=y # CONFIG_MODULE_FORCE_UNLOAD is not set -CONFIG_OBSOLETE_MODPARM=y # CONFIG_MODVERSIONS is not set # CONFIG_MODULE_SRCVERSION_ALL is not set CONFIG_KMOD=y # +# Block layer +# +CONFIG_BLOCK=y +# CONFIG_BLK_DEV_IO_TRACE is not set + +# +# IO Schedulers +# +CONFIG_IOSCHED_NOOP=y +# CONFIG_IOSCHED_AS is not set +CONFIG_IOSCHED_DEADLINE=y +CONFIG_IOSCHED_CFQ=y +# CONFIG_DEFAULT_AS is not set +# CONFIG_DEFAULT_DEADLINE is not set +CONFIG_DEFAULT_CFQ=y +# CONFIG_DEFAULT_NOOP is not set +CONFIG_DEFAULT_IOSCHED="cfq" + +# # Processor type and features # CONFIG_PLAT_MAPPI=y @@ -67,8 +91,10 @@ # CONFIG_PLAT_OPSPUT is not set # CONFIG_PLAT_OAKS32R is not set # CONFIG_PLAT_MAPPI2 is not set # CONFIG_PLAT_MAPPI3 is not set +# CONFIG_PLAT_M32104UT is not set CONFIG_CHIP_M32700=y # CONFIG_CHIP_M32102 is not set +# CONFIG_CHIP_M32104 is not set # CONFIG_CHIP_VDEC2 is not set # CONFIG_CHIP_OPSP is not set # CONFIG_MMU is not set @@ -82,18 +108,31 @@ # CONFIG_CPU_LITTLE_ENDIAN is not set CONFIG_MEMORY_START=0x00000000 CONFIG_MEMORY_SIZE=0x00E00000 CONFIG_NOHIGHMEM=y -# CONFIG_DISCONTIGMEM is not set +CONFIG_ARCH_DISCONTIGMEM_ENABLE=y +CONFIG_SELECT_MEMORY_MODEL=y +# CONFIG_FLATMEM_MANUAL is not set +CONFIG_DISCONTIGMEM_MANUAL=y +# CONFIG_SPARSEMEM_MANUAL is not set +CONFIG_DISCONTIGMEM=y +CONFIG_FLAT_NODE_MEM_MAP=y +CONFIG_NEED_MULTIPLE_NODES=y +# CONFIG_SPARSEMEM_STATIC is not set +CONFIG_SPLIT_PTLOCK_CPUS=4 +# CONFIG_RESOURCES_64BIT is not set +CONFIG_IRAM_START=0x00f00000 +CONFIG_IRAM_SIZE=0x00080000 CONFIG_RWSEM_GENERIC_SPINLOCK=y # CONFIG_RWSEM_XCHGADD_ALGORITHM is not set +CONFIG_GENERIC_FIND_NEXT_BIT=y +CONFIG_GENERIC_HWEIGHT=y CONFIG_GENERIC_CALIBRATE_DELAY=y CONFIG_PREEMPT=y -# CONFIG_HAVE_DEC_LOCK is not set # CONFIG_SMP is not set +CONFIG_NODES_SHIFT=1 # # Bus options (PCI, PCMCIA, EISA, MCA, ISA) # -# CONFIG_PCI is not set # CONFIG_ISA is not set # @@ -102,12 +141,14 @@ # CONFIG_PCCARD=y # CONFIG_PCMCIA_DEBUG is not set CONFIG_PCMCIA=y +CONFIG_PCMCIA_LOAD_CIS=y +CONFIG_PCMCIA_IOCTL=y # # PC-card bridges # -# CONFIG_TCIC is not set CONFIG_M32R_PCC=y +CONFIG_PCCARD_NONSTATIC=y # # PCI Hotplug Support @@ -122,6 +163,94 @@ # CONFIG_BINFMT_SHARED_FLAT is not set # CONFIG_BINFMT_MISC is not set # +# Networking +# +CONFIG_NET=y + +# +# Networking options +# +# CONFIG_NETDEBUG is not set +CONFIG_PACKET=y +# CONFIG_PACKET_MMAP is not set +CONFIG_UNIX=y +CONFIG_XFRM=y +# CONFIG_XFRM_USER is not set +# CONFIG_XFRM_SUB_POLICY is not set +# CONFIG_NET_KEY is not set +CONFIG_INET=y +# CONFIG_IP_MULTICAST is not set +# CONFIG_IP_ADVANCED_ROUTER is not set +CONFIG_IP_FIB_HASH=y +CONFIG_IP_PNP=y +CONFIG_IP_PNP_DHCP=y +# CONFIG_IP_PNP_BOOTP is not set +# CONFIG_IP_PNP_RARP is not set +# CONFIG_NET_IPIP is not set +# CONFIG_NET_IPGRE is not set +# CONFIG_ARPD is not set +# CONFIG_SYN_COOKIES is not set +# CONFIG_INET_AH is not set +# CONFIG_INET_ESP is not set +# CONFIG_INET_IPCOMP is not set +# CONFIG_INET_XFRM_TUNNEL is not set +# CONFIG_INET_TUNNEL is not set +CONFIG_INET_XFRM_MODE_TRANSPORT=y +CONFIG_INET_XFRM_MODE_TUNNEL=y +CONFIG_INET_XFRM_MODE_BEET=y +CONFIG_INET_DIAG=y +CONFIG_INET_TCP_DIAG=y +# CONFIG_TCP_CONG_ADVANCED is not set +CONFIG_TCP_CONG_CUBIC=y +CONFIG_DEFAULT_TCP_CONG="cubic" +# CONFIG_TCP_MD5SIG is not set +# CONFIG_IPV6 is not set +# CONFIG_INET6_XFRM_TUNNEL is not set +# CONFIG_INET6_TUNNEL is not set +# CONFIG_NETWORK_SECMARK is not set +# CONFIG_NETFILTER is not set + +# +# DCCP Configuration (EXPERIMENTAL) +# +# CONFIG_IP_DCCP is not set + +# +# SCTP Configuration (EXPERIMENTAL) +# +# CONFIG_IP_SCTP is not set + +# +# TIPC Configuration (EXPERIMENTAL) +# +# CONFIG_TIPC is not set +# CONFIG_ATM is not set +# CONFIG_BRIDGE is not set +# CONFIG_VLAN_8021Q is not set +# CONFIG_DECNET is not set +# CONFIG_LLC2 is not set +# CONFIG_IPX is not set +# CONFIG_ATALK is not set +# CONFIG_X25 is not set +# CONFIG_LAPB is not set +# CONFIG_ECONET is not set +# CONFIG_WAN_ROUTER is not set + +# +# QoS and/or fair queueing +# +# CONFIG_NET_SCHED is not set + +# +# Network testing +# +# CONFIG_NET_PKTGEN is not set +# CONFIG_HAMRADIO is not set +# CONFIG_IRDA is not set +# CONFIG_BT is not set +# CONFIG_IEEE80211 is not set + +# # Device Drivers # @@ -130,7 +259,13 @@ # Generic Driver Options # CONFIG_STANDALONE=y CONFIG_PREVENT_FIRMWARE_BUILD=y -# CONFIG_FW_LOADER is not set +CONFIG_FW_LOADER=y +# CONFIG_SYS_HYPERVISOR is not set + +# +# Connector - unified userspace <-> kernelspace linker +# +# CONFIG_CONNECTOR is not set # # Memory Technology Devices (MTD) @@ -149,7 +284,6 @@ # # # Block devices # -# CONFIG_BLK_DEV_FD is not set # CONFIG_BLK_DEV_COW_COMMON is not set CONFIG_BLK_DEV_LOOP=y # CONFIG_BLK_DEV_CRYPTOLOOP is not set @@ -157,18 +291,15 @@ CONFIG_BLK_DEV_NBD=y CONFIG_BLK_DEV_RAM=y CONFIG_BLK_DEV_RAM_COUNT=16 CONFIG_BLK_DEV_RAM_SIZE=4096 +CONFIG_BLK_DEV_RAM_BLOCKSIZE=1024 # CONFIG_BLK_DEV_INITRD is not set -CONFIG_INITRAMFS_SOURCE="" # CONFIG_CDROM_PKTCDVD is not set +# CONFIG_ATA_OVER_ETH is not set # -# IO Schedulers +# Misc devices # -CONFIG_IOSCHED_NOOP=y -# CONFIG_IOSCHED_AS is not set -CONFIG_IOSCHED_DEADLINE=y -CONFIG_IOSCHED_CFQ=y -# CONFIG_ATA_OVER_ETH is not set +# CONFIG_TIFM_CORE is not set # # ATA/ATAPI/MFM/RLL support @@ -178,7 +309,13 @@ # CONFIG_IDE is not set # # SCSI device support # +# CONFIG_RAID_ATTRS is not set # CONFIG_SCSI is not set +# CONFIG_SCSI_NETLINK is not set + +# +# Serial ATA (prod) and Parallel ATA (experimental) drivers +# # # Multi-device support (RAID and LVM) @@ -188,6 +325,7 @@ # CONFIG_MD is not set # # Fusion MPT device support # +# CONFIG_FUSION is not set # # IEEE 1394 (FireWire) support @@ -198,69 +336,8 @@ # I2O device support # # -# Networking support -# -CONFIG_NET=y - -# -# Networking options -# -CONFIG_PACKET=y -# CONFIG_PACKET_MMAP is not set -CONFIG_UNIX=y -# CONFIG_NET_KEY is not set -CONFIG_INET=y -# CONFIG_IP_MULTICAST is not set -# CONFIG_IP_ADVANCED_ROUTER is not set -CONFIG_IP_PNP=y -CONFIG_IP_PNP_DHCP=y -# CONFIG_IP_PNP_BOOTP is not set -# CONFIG_IP_PNP_RARP is not set -# CONFIG_NET_IPIP is not set -# CONFIG_NET_IPGRE is not set -# CONFIG_ARPD is not set -# CONFIG_SYN_COOKIES is not set -# CONFIG_INET_AH is not set -# CONFIG_INET_ESP is not set -# CONFIG_INET_IPCOMP is not set -# CONFIG_INET_TUNNEL is not set -CONFIG_IP_TCPDIAG=y -# CONFIG_IP_TCPDIAG_IPV6 is not set -# CONFIG_IPV6 is not set -# CONFIG_NETFILTER is not set - -# -# SCTP Configuration (EXPERIMENTAL) -# -# CONFIG_IP_SCTP is not set -# CONFIG_ATM is not set -# CONFIG_BRIDGE is not set -# CONFIG_VLAN_8021Q is not set -# CONFIG_DECNET is not set -# CONFIG_LLC2 is not set -# CONFIG_IPX is not set -# CONFIG_ATALK is not set -# CONFIG_X25 is not set -# CONFIG_LAPB is not set -# CONFIG_NET_DIVERT is not set -# CONFIG_ECONET is not set -# CONFIG_WAN_ROUTER is not set - -# -# QoS and/or fair queueing -# -# CONFIG_NET_SCHED is not set -# CONFIG_NET_CLS_ROUTE is not set - -# -# Network testing +# Network device support # -# CONFIG_NET_PKTGEN is not set -# CONFIG_NETPOLL is not set -# CONFIG_NET_POLL_CONTROLLER is not set -# CONFIG_HAMRADIO is not set -# CONFIG_IRDA is not set -# CONFIG_BT is not set CONFIG_NETDEVICES=y # CONFIG_DUMMY is not set # CONFIG_BONDING is not set @@ -268,6 +345,10 @@ # CONFIG_EQUALIZER is not set # CONFIG_TUN is not set # +# PHY device support +# + +# # Ethernet (10 or 100Mbit) # # CONFIG_NET_ETHERNET is not set @@ -303,6 +384,8 @@ # CONFIG_PPP is not set # CONFIG_SLIP is not set # CONFIG_SHAPER is not set # CONFIG_NETCONSOLE is not set +# CONFIG_NETPOLL is not set +# CONFIG_NET_POLL_CONTROLLER is not set # # ISDN subsystem @@ -318,6 +401,7 @@ # # Input device support # CONFIG_INPUT=y +# CONFIG_INPUT_FF_MEMLESS is not set # # Userland interfaces @@ -346,7 +430,6 @@ CONFIG_SERIO_SERPORT=y # CONFIG_SERIO_LIBPS2 is not set # CONFIG_SERIO_RAW is not set # CONFIG_GAMEPORT is not set -CONFIG_SOUND_GAMEPORT=y # # Character devices @@ -366,7 +449,6 @@ CONFIG_SERIAL_CORE=y CONFIG_SERIAL_CORE_CONSOLE=y CONFIG_SERIAL_M32R_SIO=y CONFIG_SERIAL_M32R_SIO_CONSOLE=y -# CONFIG_SERIAL_M32R_PLDSIO is not set CONFIG_UNIX98_PTYS=y CONFIG_LEGACY_PTYS=y CONFIG_LEGACY_PTY_COUNT=256 @@ -380,25 +462,27 @@ # # Watchdog Cards # # CONFIG_WATCHDOG is not set +CONFIG_HW_RANDOM=y # CONFIG_RTC is not set -# CONFIG_GEN_RTC is not set # CONFIG_DTLK is not set # CONFIG_R3964 is not set # # Ftape, the floppy tape device driver # -# CONFIG_DRM is not set # # PCMCIA character devices # # CONFIG_SYNCLINK_CS is not set +# CONFIG_CARDMAN_4000 is not set +# CONFIG_CARDMAN_4040 is not set # CONFIG_RAW_DRIVER is not set # # TPM devices # +# CONFIG_TCG_TPM is not set # # I2C support @@ -406,13 +490,25 @@ # # CONFIG_I2C is not set # +# SPI support +# +# CONFIG_SPI is not set +# CONFIG_SPI_MASTER is not set + +# # Dallas's 1-wire bus # # CONFIG_W1 is not set # -# Misc devices +# Hardware Monitoring support # +CONFIG_HWMON=y +# CONFIG_HWMON_VID is not set +# CONFIG_SENSORS_ABITUGURU is not set +# CONFIG_SENSORS_F71805F is not set +# CONFIG_SENSORS_VT1211 is not set +# CONFIG_HWMON_DEBUG_CHIP is not set # # Multimedia devices @@ -427,7 +523,9 @@ # CONFIG_DVB is not set # # Graphics support # +CONFIG_FIRMWARE_EDID=y # CONFIG_FB is not set +# CONFIG_BACKLIGHT_LCD_SUPPORT is not set # # Sound @@ -439,6 +537,11 @@ # USB support # # CONFIG_USB_ARCH_HAS_HCD is not set # CONFIG_USB_ARCH_HAS_OHCI is not set +# CONFIG_USB_ARCH_HAS_EHCI is not set + +# +# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support' +# # # USB Gadget Support @@ -451,30 +554,72 @@ # # CONFIG_MMC is not set # +# LED devices +# +# CONFIG_NEW_LEDS is not set + +# +# LED drivers +# + +# +# LED Triggers +# + +# # InfiniBand support # -# CONFIG_INFINIBAND is not set + +# +# EDAC - error detection and reporting (RAS) (EXPERIMENTAL) +# + +# +# Real Time Clock +# +# CONFIG_RTC_CLASS is not set + +# +# DMA Engine support +# +# CONFIG_DMA_ENGINE is not set + +# +# DMA Clients +# + +# +# DMA Devices +# # # File systems # CONFIG_EXT2_FS=y # CONFIG_EXT2_FS_XATTR is not set -# CONFIG_EXT3_FS is not set -# CONFIG_JBD is not set +CONFIG_EXT3_FS=y +CONFIG_EXT3_FS_XATTR=y +# CONFIG_EXT3_FS_POSIX_ACL is not set +# CONFIG_EXT3_FS_SECURITY is not set +# CONFIG_EXT4DEV_FS is not set +CONFIG_JBD=y +# CONFIG_JBD_DEBUG is not set +CONFIG_FS_MBCACHE=y # CONFIG_REISERFS_FS is not set # CONFIG_JFS_FS is not set - -# -# XFS support -# +# CONFIG_FS_POSIX_ACL is not set # CONFIG_XFS_FS is not set +# CONFIG_GFS2_FS is not set +# CONFIG_OCFS2_FS is not set # CONFIG_MINIX_FS is not set # CONFIG_ROMFS_FS is not set +CONFIG_INOTIFY=y +CONFIG_INOTIFY_USER=y # CONFIG_QUOTA is not set CONFIG_DNOTIFY=y # CONFIG_AUTOFS_FS is not set # CONFIG_AUTOFS4_FS is not set +# CONFIG_FUSE_FS is not set # # CD-ROM/DVD Filesystems @@ -493,15 +638,12 @@ # # Pseudo filesystems # CONFIG_PROC_FS=y +CONFIG_PROC_SYSCTL=y CONFIG_SYSFS=y -CONFIG_DEVFS_FS=y -CONFIG_DEVFS_MOUNT=y -# CONFIG_DEVFS_DEBUG is not set -CONFIG_DEVPTS_FS_XATTR=y -CONFIG_DEVPTS_FS_SECURITY=y # CONFIG_TMPFS is not set # CONFIG_HUGETLB_PAGE is not set CONFIG_RAMFS=y +# CONFIG_CONFIGFS_FS is not set # # Miscellaneous filesystems @@ -525,12 +667,14 @@ # Network File Systems # CONFIG_NFS_FS=y CONFIG_NFS_V3=y +# CONFIG_NFS_V3_ACL is not set # CONFIG_NFS_V4 is not set # CONFIG_NFS_DIRECTIO is not set # CONFIG_NFSD is not set CONFIG_ROOT_NFS=y CONFIG_LOCKD=y CONFIG_LOCKD_V4=y +CONFIG_NFS_COMMON=y CONFIG_SUNRPC=y # CONFIG_RPCSEC_GSS_KRB5 is not set # CONFIG_RPCSEC_GSS_SPKM3 is not set @@ -539,6 +683,7 @@ # CONFIG_CIFS is not set # CONFIG_NCP_FS is not set # CONFIG_CODA_FS is not set # CONFIG_AFS_FS is not set +# CONFIG_9P_FS is not set # # Partition Types @@ -599,10 +744,16 @@ # # Kernel hacking # # CONFIG_PRINTK_TIME is not set +CONFIG_ENABLE_MUST_CHECK=y +# CONFIG_MAGIC_SYSRQ is not set +# CONFIG_UNUSED_SYMBOLS is not set # CONFIG_DEBUG_KERNEL is not set CONFIG_LOG_BUF_SHIFT=14 # CONFIG_DEBUG_BUGVERBOSE is not set +# CONFIG_DEBUG_FS is not set # CONFIG_FRAME_POINTER is not set +# CONFIG_UNWIND_INFO is not set +# CONFIG_HEADERS_CHECK is not set # # Security options @@ -616,12 +767,9 @@ # # CONFIG_CRYPTO is not set # -# Hardware crypto devices -# - -# # Library routines # # CONFIG_CRC_CCITT is not set +# CONFIG_CRC16 is not set CONFIG_CRC32=y # CONFIG_LIBCRC32C is not set diff --git a/arch/m32r/mappi/defconfig.smp b/arch/m32r/mappi/defconfig.smp index 1a7f3cd..1686692 100644 --- a/arch/m32r/mappi/defconfig.smp +++ b/arch/m32r/mappi/defconfig.smp @@ -1,21 +1,18 @@ # # Automatically generated make config: don't edit -# Linux kernel version: 2.6.12-rc5 -# Fri Jun 3 16:21:52 2005 +# Linux kernel version: 2.6.19 +# Wed Dec 13 17:50:59 2006 # CONFIG_M32R=y -# CONFIG_UID16 is not set CONFIG_GENERIC_ISA_DMA=y CONFIG_GENERIC_HARDIRQS=y CONFIG_GENERIC_IRQ_PROBE=y +CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config" # # Code maturity level options # CONFIG_EXPERIMENTAL=y -# CONFIG_CLEAN_COMPILE is not set -CONFIG_BROKEN=y -CONFIG_BROKEN_ON_SMP=y CONFIG_LOCK_KERNEL=y CONFIG_INIT_ENV_ARG_LIMIT=32 @@ -23,32 +20,39 @@ # # General setup # CONFIG_LOCALVERSION="" +CONFIG_LOCALVERSION_AUTO=y CONFIG_SWAP=y CONFIG_SYSVIPC=y +# CONFIG_IPC_NS is not set # CONFIG_POSIX_MQUEUE is not set # CONFIG_BSD_PROCESS_ACCT is not set -CONFIG_SYSCTL=y +# CONFIG_TASKSTATS is not set +# CONFIG_UTS_NS is not set # CONFIG_AUDIT is not set -CONFIG_HOTPLUG=y -CONFIG_KOBJECT_UEVENT=y CONFIG_IKCONFIG=y CONFIG_IKCONFIG_PROC=y # CONFIG_CPUSETS is not set +CONFIG_SYSFS_DEPRECATED=y +# CONFIG_RELAY is not set +CONFIG_INITRAMFS_SOURCE="" +# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set +CONFIG_SYSCTL=y CONFIG_EMBEDDED=y +CONFIG_SYSCTL_SYSCALL=y # CONFIG_KALLSYMS is not set +CONFIG_HOTPLUG=y CONFIG_PRINTK=y CONFIG_BUG=y +CONFIG_ELF_CORE=y CONFIG_BASE_FULL=y # CONFIG_FUTEX is not set # CONFIG_EPOLL is not set -# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set CONFIG_SHMEM=y -CONFIG_CC_ALIGN_FUNCTIONS=0 -CONFIG_CC_ALIGN_LABELS=0 -CONFIG_CC_ALIGN_LOOPS=0 -CONFIG_CC_ALIGN_JUMPS=0 +CONFIG_SLAB=y +CONFIG_VM_EVENT_COUNTERS=y # CONFIG_TINY_SHMEM is not set CONFIG_BASE_SMALL=0 +# CONFIG_SLOB is not set # # Loadable module support @@ -56,13 +60,31 @@ # CONFIG_MODULES=y CONFIG_MODULE_UNLOAD=y # CONFIG_MODULE_FORCE_UNLOAD is not set -CONFIG_OBSOLETE_MODPARM=y # CONFIG_MODVERSIONS is not set # CONFIG_MODULE_SRCVERSION_ALL is not set CONFIG_KMOD=y CONFIG_STOP_MACHINE=y # +# Block layer +# +CONFIG_BLOCK=y +# CONFIG_BLK_DEV_IO_TRACE is not set + +# +# IO Schedulers +# +CONFIG_IOSCHED_NOOP=y +# CONFIG_IOSCHED_AS is not set +CONFIG_IOSCHED_DEADLINE=y +CONFIG_IOSCHED_CFQ=y +# CONFIG_DEFAULT_AS is not set +# CONFIG_DEFAULT_DEADLINE is not set +CONFIG_DEFAULT_CFQ=y +# CONFIG_DEFAULT_NOOP is not set +CONFIG_DEFAULT_IOSCHED="cfq" + +# # Processor type and features # CONFIG_PLAT_MAPPI=y @@ -72,8 +94,10 @@ # CONFIG_PLAT_OPSPUT is not set # CONFIG_PLAT_OAKS32R is not set # CONFIG_PLAT_MAPPI2 is not set # CONFIG_PLAT_MAPPI3 is not set +# CONFIG_PLAT_M32104UT is not set CONFIG_CHIP_M32700=y # CONFIG_CHIP_M32102 is not set +# CONFIG_CHIP_M32104 is not set # CONFIG_CHIP_VDEC2 is not set # CONFIG_CHIP_OPSP is not set CONFIG_MMU=y @@ -87,23 +111,33 @@ # CONFIG_CPU_LITTLE_ENDIAN is not set CONFIG_MEMORY_START=0x08000000 CONFIG_MEMORY_SIZE=0x04000000 CONFIG_NOHIGHMEM=y +CONFIG_ARCH_DISCONTIGMEM_ENABLE=y +CONFIG_SELECT_MEMORY_MODEL=y +# CONFIG_FLATMEM_MANUAL is not set +CONFIG_DISCONTIGMEM_MANUAL=y +# CONFIG_SPARSEMEM_MANUAL is not set CONFIG_DISCONTIGMEM=y +CONFIG_FLAT_NODE_MEM_MAP=y +CONFIG_NEED_MULTIPLE_NODES=y +# CONFIG_SPARSEMEM_STATIC is not set +CONFIG_SPLIT_PTLOCK_CPUS=4 +# CONFIG_RESOURCES_64BIT is not set CONFIG_IRAM_START=0x00f00000 CONFIG_IRAM_SIZE=0x00080000 CONFIG_RWSEM_GENERIC_SPINLOCK=y # CONFIG_RWSEM_XCHGADD_ALGORITHM is not set +CONFIG_GENERIC_FIND_NEXT_BIT=y +CONFIG_GENERIC_HWEIGHT=y CONFIG_GENERIC_CALIBRATE_DELAY=y CONFIG_PREEMPT=y -# CONFIG_HAVE_DEC_LOCK is not set CONFIG_SMP=y CONFIG_CHIP_M32700_TS1=y CONFIG_NR_CPUS=2 -# CONFIG_NUMA is not set +CONFIG_NODES_SHIFT=1 # # Bus options (PCI, PCMCIA, EISA, MCA, ISA) # -# CONFIG_PCI is not set # CONFIG_ISA is not set # @@ -112,12 +146,14 @@ # CONFIG_PCCARD=y # CONFIG_PCMCIA_DEBUG is not set CONFIG_PCMCIA=y +CONFIG_PCMCIA_LOAD_CIS=y +CONFIG_PCMCIA_IOCTL=y # # PC-card bridges # -# CONFIG_TCIC is not set CONFIG_M32R_PCC=y +CONFIG_PCCARD_NONSTATIC=y # # PCI Hotplug Support @@ -130,6 +166,93 @@ CONFIG_BINFMT_ELF=y # CONFIG_BINFMT_MISC is not set # +# Networking +# +CONFIG_NET=y + +# +# Networking options +# +# CONFIG_NETDEBUG is not set +# CONFIG_PACKET is not set +CONFIG_UNIX=y +CONFIG_XFRM=y +# CONFIG_XFRM_USER is not set +# CONFIG_XFRM_SUB_POLICY is not set +# CONFIG_NET_KEY is not set +CONFIG_INET=y +# CONFIG_IP_MULTICAST is not set +# CONFIG_IP_ADVANCED_ROUTER is not set +CONFIG_IP_FIB_HASH=y +CONFIG_IP_PNP=y +CONFIG_IP_PNP_DHCP=y +# CONFIG_IP_PNP_BOOTP is not set +# CONFIG_IP_PNP_RARP is not set +# CONFIG_NET_IPIP is not set +# CONFIG_NET_IPGRE is not set +# CONFIG_ARPD is not set +# CONFIG_SYN_COOKIES is not set +# CONFIG_INET_AH is not set +# CONFIG_INET_ESP is not set +# CONFIG_INET_IPCOMP is not set +# CONFIG_INET_XFRM_TUNNEL is not set +# CONFIG_INET_TUNNEL is not set +CONFIG_INET_XFRM_MODE_TRANSPORT=y +CONFIG_INET_XFRM_MODE_TUNNEL=y +CONFIG_INET_XFRM_MODE_BEET=y +CONFIG_INET_DIAG=y +CONFIG_INET_TCP_DIAG=y +# CONFIG_TCP_CONG_ADVANCED is not set +CONFIG_TCP_CONG_CUBIC=y +CONFIG_DEFAULT_TCP_CONG="cubic" +# CONFIG_TCP_MD5SIG is not set +# CONFIG_IPV6 is not set +# CONFIG_INET6_XFRM_TUNNEL is not set +# CONFIG_INET6_TUNNEL is not set +# CONFIG_NETWORK_SECMARK is not set +# CONFIG_NETFILTER is not set + +# +# DCCP Configuration (EXPERIMENTAL) +# +# CONFIG_IP_DCCP is not set + +# +# SCTP Configuration (EXPERIMENTAL) +# +# CONFIG_IP_SCTP is not set + +# +# TIPC Configuration (EXPERIMENTAL) +# +# CONFIG_TIPC is not set +# CONFIG_ATM is not set +# CONFIG_BRIDGE is not set +# CONFIG_VLAN_8021Q is not set +# CONFIG_DECNET is not set +# CONFIG_LLC2 is not set +# CONFIG_IPX is not set +# CONFIG_ATALK is not set +# CONFIG_X25 is not set +# CONFIG_LAPB is not set +# CONFIG_ECONET is not set +# CONFIG_WAN_ROUTER is not set + +# +# QoS and/or fair queueing +# +# CONFIG_NET_SCHED is not set + +# +# Network testing +# +# CONFIG_NET_PKTGEN is not set +# CONFIG_HAMRADIO is not set +# CONFIG_IRDA is not set +# CONFIG_BT is not set +# CONFIG_IEEE80211 is not set + +# # Device Drivers # @@ -138,7 +261,13 @@ # Generic Driver Options # # CONFIG_STANDALONE is not set CONFIG_PREVENT_FIRMWARE_BUILD=y -# CONFIG_FW_LOADER is not set +CONFIG_FW_LOADER=y +# CONFIG_SYS_HYPERVISOR is not set + +# +# Connector - unified userspace <-> kernelspace linker +# +# CONFIG_CONNECTOR is not set # # Memory Technology Devices (MTD) @@ -161,6 +290,8 @@ CONFIG_MTD_BLOCK=y # CONFIG_FTL is not set # CONFIG_NFTL is not set # CONFIG_INFTL is not set +# CONFIG_RFD_FTL is not set +# CONFIG_SSFDC is not set # # RAM/ROM/Flash chip drivers @@ -186,6 +317,7 @@ # # Mapping drivers for chip access # # CONFIG_MTD_COMPLEX_MAPPINGS is not set +# CONFIG_MTD_PLATRAM is not set # # Self-contained MTD device drivers @@ -193,7 +325,6 @@ # # CONFIG_MTD_SLRAM is not set # CONFIG_MTD_PHRAM is not set # CONFIG_MTD_MTDRAM is not set -# CONFIG_MTD_BLKMTD is not set # CONFIG_MTD_BLOCK2MTD is not set # @@ -209,6 +340,11 @@ # # CONFIG_MTD_NAND is not set # +# OneNAND Flash Device Drivers +# +# CONFIG_MTD_ONENAND is not set + +# # Parallel port support # # CONFIG_PARPORT is not set @@ -220,7 +356,6 @@ # # # Block devices # -# CONFIG_BLK_DEV_FD is not set # CONFIG_BLK_DEV_COW_COMMON is not set CONFIG_BLK_DEV_LOOP=y # CONFIG_BLK_DEV_CRYPTOLOOP is not set @@ -228,23 +363,21 @@ CONFIG_BLK_DEV_NBD=m CONFIG_BLK_DEV_RAM=y CONFIG_BLK_DEV_RAM_COUNT=16 CONFIG_BLK_DEV_RAM_SIZE=4096 +CONFIG_BLK_DEV_RAM_BLOCKSIZE=1024 CONFIG_BLK_DEV_INITRD=y -CONFIG_INITRAMFS_SOURCE="" # CONFIG_CDROM_PKTCDVD is not set +# CONFIG_ATA_OVER_ETH is not set # -# IO Schedulers +# Misc devices # -CONFIG_IOSCHED_NOOP=y -# CONFIG_IOSCHED_AS is not set -CONFIG_IOSCHED_DEADLINE=y -CONFIG_IOSCHED_CFQ=y -# CONFIG_ATA_OVER_ETH is not set +# CONFIG_TIFM_CORE is not set # # ATA/ATAPI/MFM/RLL support # CONFIG_IDE=m +CONFIG_IDE_MAX_HWIFS=4 CONFIG_BLK_DEV_IDE=m # @@ -271,7 +404,13 @@ # CONFIG_BLK_DEV_HD is not set # # SCSI device support # +# CONFIG_RAID_ATTRS is not set # CONFIG_SCSI is not set +# CONFIG_SCSI_NETLINK is not set + +# +# Serial ATA (prod) and Parallel ATA (experimental) drivers +# # # Multi-device support (RAID and LVM) @@ -281,79 +420,19 @@ # CONFIG_MD is not set # # Fusion MPT device support # +# CONFIG_FUSION is not set # # IEEE 1394 (FireWire) support # -# CONFIG_IEEE1394 is not set # # I2O device support # # -# Networking support +# Network device support # -CONFIG_NET=y - -# -# Networking options -# -# CONFIG_PACKET is not set -CONFIG_UNIX=y -# CONFIG_NET_KEY is not set -CONFIG_INET=y -# CONFIG_IP_MULTICAST is not set -# CONFIG_IP_ADVANCED_ROUTER is not set -CONFIG_IP_PNP=y -CONFIG_IP_PNP_DHCP=y -# CONFIG_IP_PNP_BOOTP is not set -# CONFIG_IP_PNP_RARP is not set -# CONFIG_NET_IPIP is not set -# CONFIG_NET_IPGRE is not set -# CONFIG_ARPD is not set -# CONFIG_SYN_COOKIES is not set -# CONFIG_INET_AH is not set -# CONFIG_INET_ESP is not set -# CONFIG_INET_IPCOMP is not set -# CONFIG_INET_TUNNEL is not set -CONFIG_IP_TCPDIAG=y -# CONFIG_IP_TCPDIAG_IPV6 is not set -# CONFIG_IPV6 is not set -# CONFIG_NETFILTER is not set - -# -# SCTP Configuration (EXPERIMENTAL) -# -# CONFIG_IP_SCTP is not set -# CONFIG_ATM is not set -# CONFIG_BRIDGE is not set -# CONFIG_VLAN_8021Q is not set -# CONFIG_DECNET is not set -# CONFIG_LLC2 is not set -# CONFIG_IPX is not set -# CONFIG_ATALK is not set -# CONFIG_X25 is not set -# CONFIG_LAPB is not set -# CONFIG_NET_DIVERT is not set -# CONFIG_ECONET is not set -# CONFIG_WAN_ROUTER is not set - -# -# QoS and/or fair queueing -# -# CONFIG_NET_SCHED is not set -# CONFIG_NET_CLS_ROUTE is not set - -# -# Network testing -# -# CONFIG_NET_PKTGEN is not set -# CONFIG_NETPOLL is not set -# CONFIG_NET_POLL_CONTROLLER is not set -# CONFIG_HAMRADIO is not set -# CONFIG_IRDA is not set -# CONFIG_BT is not set CONFIG_NETDEVICES=y # CONFIG_DUMMY is not set # CONFIG_BONDING is not set @@ -361,6 +440,10 @@ # CONFIG_EQUALIZER is not set # CONFIG_TUN is not set # +# PHY device support +# + +# # Ethernet (10 or 100Mbit) # # CONFIG_NET_ETHERNET is not set @@ -396,6 +479,8 @@ # CONFIG_PPP is not set # CONFIG_SLIP is not set # CONFIG_SHAPER is not set # CONFIG_NETCONSOLE is not set +# CONFIG_NETPOLL is not set +# CONFIG_NET_POLL_CONTROLLER is not set # # ISDN subsystem @@ -411,6 +496,7 @@ # # Input device support # CONFIG_INPUT=y +# CONFIG_INPUT_FF_MEMLESS is not set # # Userland interfaces @@ -442,7 +528,6 @@ # CONFIG_SERIO_SERPORT is not set # CONFIG_SERIO_LIBPS2 is not set # CONFIG_SERIO_RAW is not set # CONFIG_GAMEPORT is not set -CONFIG_SOUND_GAMEPORT=y # # Character devices @@ -462,7 +547,6 @@ CONFIG_SERIAL_CORE=y CONFIG_SERIAL_CORE_CONSOLE=y CONFIG_SERIAL_M32R_SIO=y CONFIG_SERIAL_M32R_SIO_CONSOLE=y -# CONFIG_SERIAL_M32R_PLDSIO is not set CONFIG_UNIX98_PTYS=y CONFIG_LEGACY_PTYS=y CONFIG_LEGACY_PTY_COUNT=256 @@ -476,25 +560,27 @@ # # Watchdog Cards # # CONFIG_WATCHDOG is not set +CONFIG_HW_RANDOM=y # CONFIG_RTC is not set -# CONFIG_GEN_RTC is not set # CONFIG_DTLK is not set # CONFIG_R3964 is not set # # Ftape, the floppy tape device driver # -# CONFIG_DRM is not set # # PCMCIA character devices # # CONFIG_SYNCLINK_CS is not set +# CONFIG_CARDMAN_4000 is not set +# CONFIG_CARDMAN_4040 is not set # CONFIG_RAW_DRIVER is not set # # TPM devices # +# CONFIG_TCG_TPM is not set # # I2C support @@ -502,13 +588,25 @@ # # CONFIG_I2C is not set # +# SPI support +# +# CONFIG_SPI is not set +# CONFIG_SPI_MASTER is not set + +# # Dallas's 1-wire bus # # CONFIG_W1 is not set # -# Misc devices +# Hardware Monitoring support # +CONFIG_HWMON=y +# CONFIG_HWMON_VID is not set +# CONFIG_SENSORS_ABITUGURU is not set +# CONFIG_SENSORS_F71805F is not set +# CONFIG_SENSORS_VT1211 is not set +# CONFIG_HWMON_DEBUG_CHIP is not set # # Multimedia devices @@ -523,7 +621,9 @@ # CONFIG_DVB is not set # # Graphics support # +CONFIG_FIRMWARE_EDID=y # CONFIG_FB is not set +# CONFIG_BACKLIGHT_LCD_SUPPORT is not set # # Sound @@ -535,6 +635,11 @@ # USB support # # CONFIG_USB_ARCH_HAS_HCD is not set # CONFIG_USB_ARCH_HAS_OHCI is not set +# CONFIG_USB_ARCH_HAS_EHCI is not set + +# +# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support' +# # # USB Gadget Support @@ -547,30 +652,73 @@ # # CONFIG_MMC is not set # +# LED devices +# +# CONFIG_NEW_LEDS is not set + +# +# LED drivers +# + +# +# LED Triggers +# + +# # InfiniBand support # -# CONFIG_INFINIBAND is not set + +# +# EDAC - error detection and reporting (RAS) (EXPERIMENTAL) +# + +# +# Real Time Clock +# +# CONFIG_RTC_CLASS is not set + +# +# DMA Engine support +# +# CONFIG_DMA_ENGINE is not set + +# +# DMA Clients +# + +# +# DMA Devices +# # # File systems # CONFIG_EXT2_FS=y # CONFIG_EXT2_FS_XATTR is not set -# CONFIG_EXT3_FS is not set -# CONFIG_JBD is not set +# CONFIG_EXT2_FS_XIP is not set +CONFIG_EXT3_FS=y +CONFIG_EXT3_FS_XATTR=y +# CONFIG_EXT3_FS_POSIX_ACL is not set +# CONFIG_EXT3_FS_SECURITY is not set +# CONFIG_EXT4DEV_FS is not set +CONFIG_JBD=y +# CONFIG_JBD_DEBUG is not set +CONFIG_FS_MBCACHE=y # CONFIG_REISERFS_FS is not set # CONFIG_JFS_FS is not set - -# -# XFS support -# +# CONFIG_FS_POSIX_ACL is not set # CONFIG_XFS_FS is not set +# CONFIG_GFS2_FS is not set +# CONFIG_OCFS2_FS is not set # CONFIG_MINIX_FS is not set CONFIG_ROMFS_FS=y +CONFIG_INOTIFY=y +CONFIG_INOTIFY_USER=y # CONFIG_QUOTA is not set CONFIG_DNOTIFY=y # CONFIG_AUTOFS_FS is not set # CONFIG_AUTOFS4_FS is not set +# CONFIG_FUSE_FS is not set # # CD-ROM/DVD Filesystems @@ -595,16 +743,13 @@ # Pseudo filesystems # CONFIG_PROC_FS=y CONFIG_PROC_KCORE=y +CONFIG_PROC_SYSCTL=y CONFIG_SYSFS=y -CONFIG_DEVFS_FS=y -CONFIG_DEVFS_MOUNT=y -# CONFIG_DEVFS_DEBUG is not set -# CONFIG_DEVPTS_FS_XATTR is not set CONFIG_TMPFS=y -# CONFIG_TMPFS_XATTR is not set -# CONFIG_HUGETLBFS is not set +# CONFIG_TMPFS_POSIX_ACL is not set # CONFIG_HUGETLB_PAGE is not set CONFIG_RAMFS=y +# CONFIG_CONFIGFS_FS is not set # # Miscellaneous filesystems @@ -621,8 +766,9 @@ CONFIG_JFFS_FS_VERBOSE=0 CONFIG_JFFS_PROC_FS=y CONFIG_JFFS2_FS=y CONFIG_JFFS2_FS_DEBUG=0 -# CONFIG_JFFS2_FS_NAND is not set -# CONFIG_JFFS2_FS_NOR_ECC is not set +CONFIG_JFFS2_FS_WRITEBUFFER=y +# CONFIG_JFFS2_SUMMARY is not set +# CONFIG_JFFS2_FS_XATTR is not set # CONFIG_JFFS2_COMPRESSION_OPTIONS is not set CONFIG_JFFS2_ZLIB=y CONFIG_JFFS2_RTIME=y @@ -639,12 +785,14 @@ # Network File Systems # CONFIG_NFS_FS=y CONFIG_NFS_V3=y +# CONFIG_NFS_V3_ACL is not set # CONFIG_NFS_V4 is not set # CONFIG_NFS_DIRECTIO is not set # CONFIG_NFSD is not set CONFIG_ROOT_NFS=y CONFIG_LOCKD=y CONFIG_LOCKD_V4=y +CONFIG_NFS_COMMON=y CONFIG_SUNRPC=y # CONFIG_RPCSEC_GSS_KRB5 is not set # CONFIG_RPCSEC_GSS_SPKM3 is not set @@ -653,6 +801,7 @@ # CONFIG_CIFS is not set # CONFIG_NCP_FS is not set # CONFIG_CODA_FS is not set # CONFIG_AFS_FS is not set +# CONFIG_9P_FS is not set # # Partition Types @@ -713,10 +862,16 @@ # # Kernel hacking # # CONFIG_PRINTK_TIME is not set +CONFIG_ENABLE_MUST_CHECK=y +# CONFIG_MAGIC_SYSRQ is not set +# CONFIG_UNUSED_SYMBOLS is not set # CONFIG_DEBUG_KERNEL is not set CONFIG_LOG_BUF_SHIFT=15 # CONFIG_DEBUG_BUGVERBOSE is not set +# CONFIG_DEBUG_FS is not set # CONFIG_FRAME_POINTER is not set +# CONFIG_UNWIND_INFO is not set +# CONFIG_HEADERS_CHECK is not set # # Security options @@ -730,13 +885,10 @@ # # CONFIG_CRYPTO is not set # -# Hardware crypto devices -# - -# # Library routines # # CONFIG_CRC_CCITT is not set +# CONFIG_CRC16 is not set CONFIG_CRC32=y # CONFIG_LIBCRC32C is not set CONFIG_ZLIB_INFLATE=y diff --git a/arch/m32r/mappi/defconfig.up b/arch/m32r/mappi/defconfig.up index 38910fb..5ba0060 100644 --- a/arch/m32r/mappi/defconfig.up +++ b/arch/m32r/mappi/defconfig.up @@ -1,20 +1,18 @@ # # Automatically generated make config: don't edit -# Linux kernel version: 2.6.12-rc5 -# Fri Jun 3 16:21:59 2005 +# Linux kernel version: 2.6.19 +# Wed Dec 13 17:51:20 2006 # CONFIG_M32R=y -# CONFIG_UID16 is not set CONFIG_GENERIC_ISA_DMA=y CONFIG_GENERIC_HARDIRQS=y CONFIG_GENERIC_IRQ_PROBE=y +CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config" # # Code maturity level options # CONFIG_EXPERIMENTAL=y -# CONFIG_CLEAN_COMPILE is not set -CONFIG_BROKEN=y CONFIG_BROKEN_ON_SMP=y CONFIG_LOCK_KERNEL=y CONFIG_INIT_ENV_ARG_LIMIT=32 @@ -23,31 +21,38 @@ # # General setup # CONFIG_LOCALVERSION="" +CONFIG_LOCALVERSION_AUTO=y CONFIG_SWAP=y CONFIG_SYSVIPC=y +# CONFIG_IPC_NS is not set # CONFIG_POSIX_MQUEUE is not set # CONFIG_BSD_PROCESS_ACCT is not set -CONFIG_SYSCTL=y +# CONFIG_TASKSTATS is not set +# CONFIG_UTS_NS is not set # CONFIG_AUDIT is not set -CONFIG_HOTPLUG=y -CONFIG_KOBJECT_UEVENT=y CONFIG_IKCONFIG=y CONFIG_IKCONFIG_PROC=y +CONFIG_SYSFS_DEPRECATED=y +# CONFIG_RELAY is not set +CONFIG_INITRAMFS_SOURCE="" +# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set +CONFIG_SYSCTL=y CONFIG_EMBEDDED=y +CONFIG_SYSCTL_SYSCALL=y # CONFIG_KALLSYMS is not set +CONFIG_HOTPLUG=y CONFIG_PRINTK=y CONFIG_BUG=y +CONFIG_ELF_CORE=y CONFIG_BASE_FULL=y # CONFIG_FUTEX is not set # CONFIG_EPOLL is not set -# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set CONFIG_SHMEM=y -CONFIG_CC_ALIGN_FUNCTIONS=0 -CONFIG_CC_ALIGN_LABELS=0 -CONFIG_CC_ALIGN_LOOPS=0 -CONFIG_CC_ALIGN_JUMPS=0 +CONFIG_SLAB=y +CONFIG_VM_EVENT_COUNTERS=y # CONFIG_TINY_SHMEM is not set CONFIG_BASE_SMALL=0 +# CONFIG_SLOB is not set # # Loadable module support @@ -55,12 +60,30 @@ # CONFIG_MODULES=y CONFIG_MODULE_UNLOAD=y # CONFIG_MODULE_FORCE_UNLOAD is not set -CONFIG_OBSOLETE_MODPARM=y # CONFIG_MODVERSIONS is not set # CONFIG_MODULE_SRCVERSION_ALL is not set CONFIG_KMOD=y # +# Block layer +# +CONFIG_BLOCK=y +# CONFIG_BLK_DEV_IO_TRACE is not set + +# +# IO Schedulers +# +CONFIG_IOSCHED_NOOP=y +# CONFIG_IOSCHED_AS is not set +CONFIG_IOSCHED_DEADLINE=y +CONFIG_IOSCHED_CFQ=y +# CONFIG_DEFAULT_AS is not set +# CONFIG_DEFAULT_DEADLINE is not set +CONFIG_DEFAULT_CFQ=y +# CONFIG_DEFAULT_NOOP is not set +CONFIG_DEFAULT_IOSCHED="cfq" + +# # Processor type and features # CONFIG_PLAT_MAPPI=y @@ -70,8 +93,10 @@ # CONFIG_PLAT_OPSPUT is not set # CONFIG_PLAT_OAKS32R is not set # CONFIG_PLAT_MAPPI2 is not set # CONFIG_PLAT_MAPPI3 is not set +# CONFIG_PLAT_M32104UT is not set CONFIG_CHIP_M32700=y # CONFIG_CHIP_M32102 is not set +# CONFIG_CHIP_M32104 is not set # CONFIG_CHIP_VDEC2 is not set # CONFIG_CHIP_OPSP is not set CONFIG_MMU=y @@ -85,20 +110,31 @@ # CONFIG_CPU_LITTLE_ENDIAN is not set CONFIG_MEMORY_START=0x08000000 CONFIG_MEMORY_SIZE=0x04000000 CONFIG_NOHIGHMEM=y +CONFIG_ARCH_DISCONTIGMEM_ENABLE=y +CONFIG_SELECT_MEMORY_MODEL=y +# CONFIG_FLATMEM_MANUAL is not set +CONFIG_DISCONTIGMEM_MANUAL=y +# CONFIG_SPARSEMEM_MANUAL is not set CONFIG_DISCONTIGMEM=y +CONFIG_FLAT_NODE_MEM_MAP=y +CONFIG_NEED_MULTIPLE_NODES=y +# CONFIG_SPARSEMEM_STATIC is not set +CONFIG_SPLIT_PTLOCK_CPUS=4 +# CONFIG_RESOURCES_64BIT is not set CONFIG_IRAM_START=0x00f00000 CONFIG_IRAM_SIZE=0x00080000 CONFIG_RWSEM_GENERIC_SPINLOCK=y # CONFIG_RWSEM_XCHGADD_ALGORITHM is not set +CONFIG_GENERIC_FIND_NEXT_BIT=y +CONFIG_GENERIC_HWEIGHT=y CONFIG_GENERIC_CALIBRATE_DELAY=y CONFIG_PREEMPT=y -# CONFIG_HAVE_DEC_LOCK is not set # CONFIG_SMP is not set +CONFIG_NODES_SHIFT=1 # # Bus options (PCI, PCMCIA, EISA, MCA, ISA) # -# CONFIG_PCI is not set # CONFIG_ISA is not set # @@ -107,12 +143,14 @@ # CONFIG_PCCARD=y # CONFIG_PCMCIA_DEBUG is not set CONFIG_PCMCIA=y +CONFIG_PCMCIA_LOAD_CIS=y +CONFIG_PCMCIA_IOCTL=y # # PC-card bridges # -# CONFIG_TCIC is not set CONFIG_M32R_PCC=y +CONFIG_PCCARD_NONSTATIC=y # # PCI Hotplug Support @@ -125,6 +163,93 @@ CONFIG_BINFMT_ELF=y # CONFIG_BINFMT_MISC is not set # +# Networking +# +CONFIG_NET=y + +# +# Networking options +# +# CONFIG_NETDEBUG is not set +# CONFIG_PACKET is not set +CONFIG_UNIX=y +CONFIG_XFRM=y +# CONFIG_XFRM_USER is not set +# CONFIG_XFRM_SUB_POLICY is not set +# CONFIG_NET_KEY is not set +CONFIG_INET=y +# CONFIG_IP_MULTICAST is not set +# CONFIG_IP_ADVANCED_ROUTER is not set +CONFIG_IP_FIB_HASH=y +CONFIG_IP_PNP=y +CONFIG_IP_PNP_DHCP=y +# CONFIG_IP_PNP_BOOTP is not set +# CONFIG_IP_PNP_RARP is not set +# CONFIG_NET_IPIP is not set +# CONFIG_NET_IPGRE is not set +# CONFIG_ARPD is not set +# CONFIG_SYN_COOKIES is not set +# CONFIG_INET_AH is not set +# CONFIG_INET_ESP is not set +# CONFIG_INET_IPCOMP is not set +# CONFIG_INET_XFRM_TUNNEL is not set +# CONFIG_INET_TUNNEL is not set +CONFIG_INET_XFRM_MODE_TRANSPORT=y +CONFIG_INET_XFRM_MODE_TUNNEL=y +CONFIG_INET_XFRM_MODE_BEET=y +CONFIG_INET_DIAG=y +CONFIG_INET_TCP_DIAG=y +# CONFIG_TCP_CONG_ADVANCED is not set +CONFIG_TCP_CONG_CUBIC=y +CONFIG_DEFAULT_TCP_CONG="cubic" +# CONFIG_TCP_MD5SIG is not set +# CONFIG_IPV6 is not set +# CONFIG_INET6_XFRM_TUNNEL is not set +# CONFIG_INET6_TUNNEL is not set +# CONFIG_NETWORK_SECMARK is not set +# CONFIG_NETFILTER is not set + +# +# DCCP Configuration (EXPERIMENTAL) +# +# CONFIG_IP_DCCP is not set + +# +# SCTP Configuration (EXPERIMENTAL) +# +# CONFIG_IP_SCTP is not set + +# +# TIPC Configuration (EXPERIMENTAL) +# +# CONFIG_TIPC is not set +# CONFIG_ATM is not set +# CONFIG_BRIDGE is not set +# CONFIG_VLAN_8021Q is not set +# CONFIG_DECNET is not set +# CONFIG_LLC2 is not set +# CONFIG_IPX is not set +# CONFIG_ATALK is not set +# CONFIG_X25 is not set +# CONFIG_LAPB is not set +# CONFIG_ECONET is not set +# CONFIG_WAN_ROUTER is not set + +# +# QoS and/or fair queueing +# +# CONFIG_NET_SCHED is not set + +# +# Network testing +# +# CONFIG_NET_PKTGEN is not set +# CONFIG_HAMRADIO is not set +# CONFIG_IRDA is not set +# CONFIG_BT is not set +# CONFIG_IEEE80211 is not set + +# # Device Drivers # @@ -133,7 +258,13 @@ # Generic Driver Options # # CONFIG_STANDALONE is not set CONFIG_PREVENT_FIRMWARE_BUILD=y -# CONFIG_FW_LOADER is not set +CONFIG_FW_LOADER=y +# CONFIG_SYS_HYPERVISOR is not set + +# +# Connector - unified userspace <-> kernelspace linker +# +# CONFIG_CONNECTOR is not set # # Memory Technology Devices (MTD) @@ -156,6 +287,8 @@ CONFIG_MTD_BLOCK=y # CONFIG_FTL is not set # CONFIG_NFTL is not set # CONFIG_INFTL is not set +# CONFIG_RFD_FTL is not set +# CONFIG_SSFDC is not set # # RAM/ROM/Flash chip drivers @@ -181,6 +314,7 @@ # # Mapping drivers for chip access # # CONFIG_MTD_COMPLEX_MAPPINGS is not set +# CONFIG_MTD_PLATRAM is not set # # Self-contained MTD device drivers @@ -188,7 +322,6 @@ # # CONFIG_MTD_SLRAM is not set # CONFIG_MTD_PHRAM is not set # CONFIG_MTD_MTDRAM is not set -# CONFIG_MTD_BLKMTD is not set # CONFIG_MTD_BLOCK2MTD is not set # @@ -204,6 +337,11 @@ # # CONFIG_MTD_NAND is not set # +# OneNAND Flash Device Drivers +# +# CONFIG_MTD_ONENAND is not set + +# # Parallel port support # # CONFIG_PARPORT is not set @@ -215,7 +353,6 @@ # # # Block devices # -# CONFIG_BLK_DEV_FD is not set # CONFIG_BLK_DEV_COW_COMMON is not set CONFIG_BLK_DEV_LOOP=y # CONFIG_BLK_DEV_CRYPTOLOOP is not set @@ -223,23 +360,21 @@ CONFIG_BLK_DEV_NBD=m CONFIG_BLK_DEV_RAM=y CONFIG_BLK_DEV_RAM_COUNT=16 CONFIG_BLK_DEV_RAM_SIZE=4096 +CONFIG_BLK_DEV_RAM_BLOCKSIZE=1024 CONFIG_BLK_DEV_INITRD=y -CONFIG_INITRAMFS_SOURCE="" # CONFIG_CDROM_PKTCDVD is not set +# CONFIG_ATA_OVER_ETH is not set # -# IO Schedulers +# Misc devices # -CONFIG_IOSCHED_NOOP=y -# CONFIG_IOSCHED_AS is not set -CONFIG_IOSCHED_DEADLINE=y -CONFIG_IOSCHED_CFQ=y -# CONFIG_ATA_OVER_ETH is not set +# CONFIG_TIFM_CORE is not set # # ATA/ATAPI/MFM/RLL support # CONFIG_IDE=m +CONFIG_IDE_MAX_HWIFS=4 CONFIG_BLK_DEV_IDE=m # @@ -266,7 +401,13 @@ # CONFIG_BLK_DEV_HD is not set # # SCSI device support # +# CONFIG_RAID_ATTRS is not set # CONFIG_SCSI is not set +# CONFIG_SCSI_NETLINK is not set + +# +# Serial ATA (prod) and Parallel ATA (experimental) drivers +# # # Multi-device support (RAID and LVM) @@ -276,79 +417,19 @@ # CONFIG_MD is not set # # Fusion MPT device support # +# CONFIG_FUSION is not set # # IEEE 1394 (FireWire) support # -# CONFIG_IEEE1394 is not set # # I2O device support # # -# Networking support +# Network device support # -CONFIG_NET=y - -# -# Networking options -# -# CONFIG_PACKET is not set -CONFIG_UNIX=y -# CONFIG_NET_KEY is not set -CONFIG_INET=y -# CONFIG_IP_MULTICAST is not set -# CONFIG_IP_ADVANCED_ROUTER is not set -CONFIG_IP_PNP=y -CONFIG_IP_PNP_DHCP=y -# CONFIG_IP_PNP_BOOTP is not set -# CONFIG_IP_PNP_RARP is not set -# CONFIG_NET_IPIP is not set -# CONFIG_NET_IPGRE is not set -# CONFIG_ARPD is not set -# CONFIG_SYN_COOKIES is not set -# CONFIG_INET_AH is not set -# CONFIG_INET_ESP is not set -# CONFIG_INET_IPCOMP is not set -# CONFIG_INET_TUNNEL is not set -CONFIG_IP_TCPDIAG=y -# CONFIG_IP_TCPDIAG_IPV6 is not set -# CONFIG_IPV6 is not set -# CONFIG_NETFILTER is not set - -# -# SCTP Configuration (EXPERIMENTAL) -# -# CONFIG_IP_SCTP is not set -# CONFIG_ATM is not set -# CONFIG_BRIDGE is not set -# CONFIG_VLAN_8021Q is not set -# CONFIG_DECNET is not set -# CONFIG_LLC2 is not set -# CONFIG_IPX is not set -# CONFIG_ATALK is not set -# CONFIG_X25 is not set -# CONFIG_LAPB is not set -# CONFIG_NET_DIVERT is not set -# CONFIG_ECONET is not set -# CONFIG_WAN_ROUTER is not set - -# -# QoS and/or fair queueing -# -# CONFIG_NET_SCHED is not set -# CONFIG_NET_CLS_ROUTE is not set - -# -# Network testing -# -# CONFIG_NET_PKTGEN is not set -# CONFIG_NETPOLL is not set -# CONFIG_NET_POLL_CONTROLLER is not set -# CONFIG_HAMRADIO is not set -# CONFIG_IRDA is not set -# CONFIG_BT is not set CONFIG_NETDEVICES=y # CONFIG_DUMMY is not set # CONFIG_BONDING is not set @@ -356,6 +437,10 @@ # CONFIG_EQUALIZER is not set # CONFIG_TUN is not set # +# PHY device support +# + +# # Ethernet (10 or 100Mbit) # # CONFIG_NET_ETHERNET is not set @@ -391,6 +476,8 @@ # CONFIG_PPP is not set # CONFIG_SLIP is not set # CONFIG_SHAPER is not set # CONFIG_NETCONSOLE is not set +# CONFIG_NETPOLL is not set +# CONFIG_NET_POLL_CONTROLLER is not set # # ISDN subsystem @@ -406,6 +493,7 @@ # # Input device support # CONFIG_INPUT=y +# CONFIG_INPUT_FF_MEMLESS is not set # # Userland interfaces @@ -437,7 +525,6 @@ # CONFIG_SERIO_SERPORT is not set # CONFIG_SERIO_LIBPS2 is not set # CONFIG_SERIO_RAW is not set # CONFIG_GAMEPORT is not set -CONFIG_SOUND_GAMEPORT=y # # Character devices @@ -457,7 +544,6 @@ CONFIG_SERIAL_CORE=y CONFIG_SERIAL_CORE_CONSOLE=y CONFIG_SERIAL_M32R_SIO=y CONFIG_SERIAL_M32R_SIO_CONSOLE=y -# CONFIG_SERIAL_M32R_PLDSIO is not set CONFIG_UNIX98_PTYS=y CONFIG_LEGACY_PTYS=y CONFIG_LEGACY_PTY_COUNT=256 @@ -471,25 +557,27 @@ # # Watchdog Cards # # CONFIG_WATCHDOG is not set +CONFIG_HW_RANDOM=y # CONFIG_RTC is not set -# CONFIG_GEN_RTC is not set # CONFIG_DTLK is not set # CONFIG_R3964 is not set # # Ftape, the floppy tape device driver # -# CONFIG_DRM is not set # # PCMCIA character devices # # CONFIG_SYNCLINK_CS is not set +# CONFIG_CARDMAN_4000 is not set +# CONFIG_CARDMAN_4040 is not set # CONFIG_RAW_DRIVER is not set # # TPM devices # +# CONFIG_TCG_TPM is not set # # I2C support @@ -497,13 +585,25 @@ # # CONFIG_I2C is not set # +# SPI support +# +# CONFIG_SPI is not set +# CONFIG_SPI_MASTER is not set + +# # Dallas's 1-wire bus # # CONFIG_W1 is not set # -# Misc devices +# Hardware Monitoring support # +CONFIG_HWMON=y +# CONFIG_HWMON_VID is not set +# CONFIG_SENSORS_ABITUGURU is not set +# CONFIG_SENSORS_F71805F is not set +# CONFIG_SENSORS_VT1211 is not set +# CONFIG_HWMON_DEBUG_CHIP is not set # # Multimedia devices @@ -518,7 +618,9 @@ # CONFIG_DVB is not set # # Graphics support # +CONFIG_FIRMWARE_EDID=y # CONFIG_FB is not set +# CONFIG_BACKLIGHT_LCD_SUPPORT is not set # # Sound @@ -530,6 +632,11 @@ # USB support # # CONFIG_USB_ARCH_HAS_HCD is not set # CONFIG_USB_ARCH_HAS_OHCI is not set +# CONFIG_USB_ARCH_HAS_EHCI is not set + +# +# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support' +# # # USB Gadget Support @@ -542,30 +649,73 @@ # # CONFIG_MMC is not set # +# LED devices +# +# CONFIG_NEW_LEDS is not set + +# +# LED drivers +# + +# +# LED Triggers +# + +# # InfiniBand support # -# CONFIG_INFINIBAND is not set + +# +# EDAC - error detection and reporting (RAS) (EXPERIMENTAL) +# + +# +# Real Time Clock +# +# CONFIG_RTC_CLASS is not set + +# +# DMA Engine support +# +# CONFIG_DMA_ENGINE is not set + +# +# DMA Clients +# + +# +# DMA Devices +# # # File systems # CONFIG_EXT2_FS=y # CONFIG_EXT2_FS_XATTR is not set -# CONFIG_EXT3_FS is not set -# CONFIG_JBD is not set +# CONFIG_EXT2_FS_XIP is not set +CONFIG_EXT3_FS=y +CONFIG_EXT3_FS_XATTR=y +# CONFIG_EXT3_FS_POSIX_ACL is not set +# CONFIG_EXT3_FS_SECURITY is not set +# CONFIG_EXT4DEV_FS is not set +CONFIG_JBD=y +# CONFIG_JBD_DEBUG is not set +CONFIG_FS_MBCACHE=y # CONFIG_REISERFS_FS is not set # CONFIG_JFS_FS is not set - -# -# XFS support -# +# CONFIG_FS_POSIX_ACL is not set # CONFIG_XFS_FS is not set +# CONFIG_GFS2_FS is not set +# CONFIG_OCFS2_FS is not set # CONFIG_MINIX_FS is not set CONFIG_ROMFS_FS=y +CONFIG_INOTIFY=y +CONFIG_INOTIFY_USER=y # CONFIG_QUOTA is not set CONFIG_DNOTIFY=y # CONFIG_AUTOFS_FS is not set # CONFIG_AUTOFS4_FS is not set +# CONFIG_FUSE_FS is not set # # CD-ROM/DVD Filesystems @@ -590,16 +740,13 @@ # Pseudo filesystems # CONFIG_PROC_FS=y CONFIG_PROC_KCORE=y +CONFIG_PROC_SYSCTL=y CONFIG_SYSFS=y -CONFIG_DEVFS_FS=y -CONFIG_DEVFS_MOUNT=y -# CONFIG_DEVFS_DEBUG is not set -# CONFIG_DEVPTS_FS_XATTR is not set CONFIG_TMPFS=y -# CONFIG_TMPFS_XATTR is not set -# CONFIG_HUGETLBFS is not set +# CONFIG_TMPFS_POSIX_ACL is not set # CONFIG_HUGETLB_PAGE is not set CONFIG_RAMFS=y +# CONFIG_CONFIGFS_FS is not set # # Miscellaneous filesystems @@ -616,8 +763,9 @@ CONFIG_JFFS_FS_VERBOSE=0 CONFIG_JFFS_PROC_FS=y CONFIG_JFFS2_FS=y CONFIG_JFFS2_FS_DEBUG=0 -# CONFIG_JFFS2_FS_NAND is not set -# CONFIG_JFFS2_FS_NOR_ECC is not set +CONFIG_JFFS2_FS_WRITEBUFFER=y +# CONFIG_JFFS2_SUMMARY is not set +# CONFIG_JFFS2_FS_XATTR is not set # CONFIG_JFFS2_COMPRESSION_OPTIONS is not set CONFIG_JFFS2_ZLIB=y CONFIG_JFFS2_RTIME=y @@ -634,12 +782,14 @@ # Network File Systems # CONFIG_NFS_FS=y CONFIG_NFS_V3=y +# CONFIG_NFS_V3_ACL is not set # CONFIG_NFS_V4 is not set # CONFIG_NFS_DIRECTIO is not set # CONFIG_NFSD is not set CONFIG_ROOT_NFS=y CONFIG_LOCKD=y CONFIG_LOCKD_V4=y +CONFIG_NFS_COMMON=y CONFIG_SUNRPC=y # CONFIG_RPCSEC_GSS_KRB5 is not set # CONFIG_RPCSEC_GSS_SPKM3 is not set @@ -648,6 +798,7 @@ # CONFIG_CIFS is not set # CONFIG_NCP_FS is not set # CONFIG_CODA_FS is not set # CONFIG_AFS_FS is not set +# CONFIG_9P_FS is not set # # Partition Types @@ -708,10 +859,16 @@ # # Kernel hacking # # CONFIG_PRINTK_TIME is not set +CONFIG_ENABLE_MUST_CHECK=y +# CONFIG_MAGIC_SYSRQ is not set +# CONFIG_UNUSED_SYMBOLS is not set # CONFIG_DEBUG_KERNEL is not set CONFIG_LOG_BUF_SHIFT=14 # CONFIG_DEBUG_BUGVERBOSE is not set +# CONFIG_DEBUG_FS is not set # CONFIG_FRAME_POINTER is not set +# CONFIG_UNWIND_INFO is not set +# CONFIG_HEADERS_CHECK is not set # # Security options @@ -725,13 +882,10 @@ # # CONFIG_CRYPTO is not set # -# Hardware crypto devices -# - -# # Library routines # # CONFIG_CRC_CCITT is not set +# CONFIG_CRC16 is not set CONFIG_CRC32=y # CONFIG_LIBCRC32C is not set CONFIG_ZLIB_INFLATE=y diff --git a/arch/m32r/mappi2/defconfig.opsp b/arch/m32r/mappi2/defconfig.opsp new file mode 100644 index 0000000..b379ae9 --- /dev/null +++ b/arch/m32r/mappi2/defconfig.opsp @@ -0,0 +1,883 @@ +# +# Automatically generated make config: don't edit +# Linux kernel version: 2.6.19 +# Wed Dec 13 19:40:30 2006 +# +CONFIG_M32R=y +CONFIG_GENERIC_ISA_DMA=y +CONFIG_GENERIC_HARDIRQS=y +CONFIG_GENERIC_IRQ_PROBE=y +CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config" + +# +# Code maturity level options +# +CONFIG_EXPERIMENTAL=y +CONFIG_BROKEN_ON_SMP=y +CONFIG_LOCK_KERNEL=y +CONFIG_INIT_ENV_ARG_LIMIT=32 + +# +# General setup +# +CONFIG_LOCALVERSION="" +CONFIG_LOCALVERSION_AUTO=y +CONFIG_SWAP=y +CONFIG_SYSVIPC=y +# CONFIG_IPC_NS is not set +# CONFIG_POSIX_MQUEUE is not set +CONFIG_BSD_PROCESS_ACCT=y +# CONFIG_BSD_PROCESS_ACCT_V3 is not set +# CONFIG_TASKSTATS is not set +# CONFIG_UTS_NS is not set +# CONFIG_AUDIT is not set +CONFIG_IKCONFIG=y +# CONFIG_IKCONFIG_PROC is not set +CONFIG_SYSFS_DEPRECATED=y +# CONFIG_RELAY is not set +CONFIG_INITRAMFS_SOURCE="" +# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set +CONFIG_SYSCTL=y +CONFIG_EMBEDDED=y +CONFIG_SYSCTL_SYSCALL=y +# CONFIG_KALLSYMS is not set +CONFIG_HOTPLUG=y +CONFIG_PRINTK=y +CONFIG_BUG=y +CONFIG_ELF_CORE=y +CONFIG_BASE_FULL=y +# CONFIG_FUTEX is not set +# CONFIG_EPOLL is not set +CONFIG_SHMEM=y +CONFIG_SLAB=y +CONFIG_VM_EVENT_COUNTERS=y +# CONFIG_TINY_SHMEM is not set +CONFIG_BASE_SMALL=0 +# CONFIG_SLOB is not set + +# +# Loadable module support +# +CONFIG_MODULES=y +CONFIG_MODULE_UNLOAD=y +# CONFIG_MODULE_FORCE_UNLOAD is not set +# CONFIG_MODVERSIONS is not set +# CONFIG_MODULE_SRCVERSION_ALL is not set +CONFIG_KMOD=y + +# +# Block layer +# +CONFIG_BLOCK=y +# CONFIG_BLK_DEV_IO_TRACE is not set + +# +# IO Schedulers +# +CONFIG_IOSCHED_NOOP=y +# CONFIG_IOSCHED_AS is not set +CONFIG_IOSCHED_DEADLINE=y +CONFIG_IOSCHED_CFQ=y +# CONFIG_DEFAULT_AS is not set +# CONFIG_DEFAULT_DEADLINE is not set +CONFIG_DEFAULT_CFQ=y +# CONFIG_DEFAULT_NOOP is not set +CONFIG_DEFAULT_IOSCHED="cfq" + +# +# Processor type and features +# +# CONFIG_PLAT_MAPPI is not set +# CONFIG_PLAT_USRV is not set +# CONFIG_PLAT_M32700UT is not set +# CONFIG_PLAT_OPSPUT is not set +# CONFIG_PLAT_OAKS32R is not set +CONFIG_PLAT_MAPPI2=y +# CONFIG_PLAT_MAPPI3 is not set +# CONFIG_PLAT_M32104UT is not set +# CONFIG_CHIP_M32700 is not set +# CONFIG_CHIP_M32102 is not set +# CONFIG_CHIP_M32104 is not set +# CONFIG_CHIP_VDEC2 is not set +CONFIG_CHIP_OPSP=y +CONFIG_MMU=y +CONFIG_TLB_ENTRIES=16 +CONFIG_ISA_M32R2=y +CONFIG_ISA_DSP_LEVEL2=y +CONFIG_ISA_DUAL_ISSUE=y +CONFIG_BUS_CLOCK=50000000 +CONFIG_TIMER_DIVIDE=128 +# CONFIG_CPU_LITTLE_ENDIAN is not set +CONFIG_MEMORY_START=0x08000000 +CONFIG_MEMORY_SIZE=0x01000000 +CONFIG_NOHIGHMEM=y +CONFIG_ARCH_DISCONTIGMEM_ENABLE=y +CONFIG_SELECT_MEMORY_MODEL=y +# CONFIG_FLATMEM_MANUAL is not set +CONFIG_DISCONTIGMEM_MANUAL=y +# CONFIG_SPARSEMEM_MANUAL is not set +CONFIG_DISCONTIGMEM=y +CONFIG_FLAT_NODE_MEM_MAP=y +CONFIG_NEED_MULTIPLE_NODES=y +# CONFIG_SPARSEMEM_STATIC is not set +CONFIG_SPLIT_PTLOCK_CPUS=4 +# CONFIG_RESOURCES_64BIT is not set +CONFIG_IRAM_START=0x00f00000 +CONFIG_IRAM_SIZE=0x00008000 +CONFIG_RWSEM_GENERIC_SPINLOCK=y +# CONFIG_RWSEM_XCHGADD_ALGORITHM is not set +CONFIG_GENERIC_FIND_NEXT_BIT=y +CONFIG_GENERIC_HWEIGHT=y +CONFIG_GENERIC_CALIBRATE_DELAY=y +CONFIG_PREEMPT=y +# CONFIG_SMP is not set +CONFIG_NODES_SHIFT=1 + +# +# Bus options (PCI, PCMCIA, EISA, MCA, ISA) +# +# CONFIG_ISA is not set + +# +# PCCARD (PCMCIA/CardBus) support +# +CONFIG_PCCARD=y +# CONFIG_PCMCIA_DEBUG is not set +CONFIG_PCMCIA=y +CONFIG_PCMCIA_LOAD_CIS=y +CONFIG_PCMCIA_IOCTL=y + +# +# PC-card bridges +# +# CONFIG_M32R_CFC is not set + +# +# PCI Hotplug Support +# + +# +# Executable file formats +# +CONFIG_BINFMT_ELF=y +# CONFIG_BINFMT_MISC is not set + +# +# Networking +# +CONFIG_NET=y + +# +# Networking options +# +# CONFIG_NETDEBUG is not set +CONFIG_PACKET=y +# CONFIG_PACKET_MMAP is not set +CONFIG_UNIX=y +CONFIG_XFRM=y +# CONFIG_XFRM_USER is not set +# CONFIG_XFRM_SUB_POLICY is not set +# CONFIG_NET_KEY is not set +CONFIG_INET=y +# CONFIG_IP_MULTICAST is not set +# CONFIG_IP_ADVANCED_ROUTER is not set +CONFIG_IP_FIB_HASH=y +CONFIG_IP_PNP=y +CONFIG_IP_PNP_DHCP=y +# CONFIG_IP_PNP_BOOTP is not set +# CONFIG_IP_PNP_RARP is not set +# CONFIG_NET_IPIP is not set +# CONFIG_NET_IPGRE is not set +# CONFIG_ARPD is not set +# CONFIG_SYN_COOKIES is not set +# CONFIG_INET_AH is not set +# CONFIG_INET_ESP is not set +# CONFIG_INET_IPCOMP is not set +# CONFIG_INET_XFRM_TUNNEL is not set +# CONFIG_INET_TUNNEL is not set +CONFIG_INET_XFRM_MODE_TRANSPORT=y +CONFIG_INET_XFRM_MODE_TUNNEL=y +CONFIG_INET_XFRM_MODE_BEET=y +CONFIG_INET_DIAG=y +CONFIG_INET_TCP_DIAG=y +# CONFIG_TCP_CONG_ADVANCED is not set +CONFIG_TCP_CONG_CUBIC=y +CONFIG_DEFAULT_TCP_CONG="cubic" +# CONFIG_TCP_MD5SIG is not set +# CONFIG_IPV6 is not set +# CONFIG_INET6_XFRM_TUNNEL is not set +# CONFIG_INET6_TUNNEL is not set +# CONFIG_NETWORK_SECMARK is not set +# CONFIG_NETFILTER is not set + +# +# DCCP Configuration (EXPERIMENTAL) +# +# CONFIG_IP_DCCP is not set + +# +# SCTP Configuration (EXPERIMENTAL) +# +# CONFIG_IP_SCTP is not set + +# +# TIPC Configuration (EXPERIMENTAL) +# +# CONFIG_TIPC is not set +# CONFIG_ATM is not set +# CONFIG_BRIDGE is not set +# CONFIG_VLAN_8021Q is not set +# CONFIG_DECNET is not set +# CONFIG_LLC2 is not set +# CONFIG_IPX is not set +# CONFIG_ATALK is not set +# CONFIG_X25 is not set +# CONFIG_LAPB is not set +# CONFIG_ECONET is not set +# CONFIG_WAN_ROUTER is not set + +# +# QoS and/or fair queueing +# +# CONFIG_NET_SCHED is not set + +# +# Network testing +# +# CONFIG_NET_PKTGEN is not set +# CONFIG_HAMRADIO is not set +# CONFIG_IRDA is not set +# CONFIG_BT is not set +# CONFIG_IEEE80211 is not set + +# +# Device Drivers +# + +# +# Generic Driver Options +# +CONFIG_STANDALONE=y +CONFIG_PREVENT_FIRMWARE_BUILD=y +CONFIG_FW_LOADER=y +# CONFIG_SYS_HYPERVISOR is not set + +# +# Connector - unified userspace <-> kernelspace linker +# +# CONFIG_CONNECTOR is not set + +# +# Memory Technology Devices (MTD) +# +# CONFIG_MTD is not set + +# +# Parallel port support +# +# CONFIG_PARPORT is not set + +# +# Plug and Play support +# + +# +# Block devices +# +# CONFIG_BLK_DEV_COW_COMMON is not set +CONFIG_BLK_DEV_LOOP=y +# CONFIG_BLK_DEV_CRYPTOLOOP is not set +CONFIG_BLK_DEV_NBD=y +CONFIG_BLK_DEV_RAM=y +CONFIG_BLK_DEV_RAM_COUNT=16 +CONFIG_BLK_DEV_RAM_SIZE=4096 +CONFIG_BLK_DEV_RAM_BLOCKSIZE=1024 +# CONFIG_BLK_DEV_INITRD is not set +# CONFIG_CDROM_PKTCDVD is not set +# CONFIG_ATA_OVER_ETH is not set + +# +# Misc devices +# +# CONFIG_TIFM_CORE is not set + +# +# ATA/ATAPI/MFM/RLL support +# +CONFIG_IDE=y +CONFIG_IDE_MAX_HWIFS=4 +CONFIG_BLK_DEV_IDE=y + +# +# Please see Documentation/ide.txt for help/info on IDE drives +# +# CONFIG_BLK_DEV_IDE_SATA is not set +CONFIG_BLK_DEV_IDEDISK=y +# CONFIG_IDEDISK_MULTI_MODE is not set +CONFIG_BLK_DEV_IDECS=y +CONFIG_BLK_DEV_IDECD=m +# CONFIG_BLK_DEV_IDETAPE is not set +# CONFIG_BLK_DEV_IDEFLOPPY is not set +# CONFIG_BLK_DEV_IDESCSI is not set +# CONFIG_IDE_TASK_IOCTL is not set + +# +# IDE chipset support/bugfixes +# +CONFIG_IDE_GENERIC=y +# CONFIG_IDE_ARM is not set +# CONFIG_BLK_DEV_IDEDMA is not set +# CONFIG_IDEDMA_AUTO is not set +# CONFIG_BLK_DEV_HD is not set + +# +# SCSI device support +# +# CONFIG_RAID_ATTRS is not set +CONFIG_SCSI=m +# CONFIG_SCSI_NETLINK is not set +CONFIG_SCSI_PROC_FS=y + +# +# SCSI support type (disk, tape, CD-ROM) +# +CONFIG_BLK_DEV_SD=m +# CONFIG_CHR_DEV_ST is not set +# CONFIG_CHR_DEV_OSST is not set +CONFIG_BLK_DEV_SR=m +# CONFIG_BLK_DEV_SR_VENDOR is not set +CONFIG_CHR_DEV_SG=m +# CONFIG_CHR_DEV_SCH is not set + +# +# Some SCSI devices (e.g. CD jukebox) support multiple LUNs +# +CONFIG_SCSI_MULTI_LUN=y +# CONFIG_SCSI_CONSTANTS is not set +# CONFIG_SCSI_LOGGING is not set + +# +# SCSI Transports +# +# CONFIG_SCSI_SPI_ATTRS is not set +# CONFIG_SCSI_FC_ATTRS is not set +# CONFIG_SCSI_ISCSI_ATTRS is not set +# CONFIG_SCSI_SAS_ATTRS is not set +# CONFIG_SCSI_SAS_LIBSAS is not set + +# +# SCSI low-level drivers +# +# CONFIG_ISCSI_TCP is not set +# CONFIG_SCSI_DEBUG is not set + +# +# PCMCIA SCSI adapter support +# +# CONFIG_PCMCIA_AHA152X is not set +# CONFIG_PCMCIA_FDOMAIN is not set +# CONFIG_PCMCIA_NINJA_SCSI is not set +# CONFIG_PCMCIA_QLOGIC is not set +# CONFIG_PCMCIA_SYM53C500 is not set + +# +# Serial ATA (prod) and Parallel ATA (experimental) drivers +# + +# +# Multi-device support (RAID and LVM) +# +# CONFIG_MD is not set + +# +# Fusion MPT device support +# +# CONFIG_FUSION is not set + +# +# IEEE 1394 (FireWire) support +# + +# +# I2O device support +# + +# +# Network device support +# +CONFIG_NETDEVICES=y +# CONFIG_DUMMY is not set +# CONFIG_BONDING is not set +# CONFIG_EQUALIZER is not set +# CONFIG_TUN is not set + +# +# PHY device support +# +# CONFIG_PHYLIB is not set + +# +# Ethernet (10 or 100Mbit) +# +CONFIG_NET_ETHERNET=y +CONFIG_MII=y +CONFIG_SMC91X=y +# CONFIG_NE2000 is not set + +# +# Ethernet (1000 Mbit) +# + +# +# Ethernet (10000 Mbit) +# + +# +# Token Ring devices +# + +# +# Wireless LAN (non-hamradio) +# +# CONFIG_NET_RADIO is not set + +# +# PCMCIA network device support +# +# CONFIG_NET_PCMCIA is not set + +# +# Wan interfaces +# +# CONFIG_WAN is not set +# CONFIG_PPP is not set +# CONFIG_SLIP is not set +# CONFIG_SHAPER is not set +# CONFIG_NETCONSOLE is not set +# CONFIG_NETPOLL is not set +# CONFIG_NET_POLL_CONTROLLER is not set + +# +# ISDN subsystem +# +# CONFIG_ISDN is not set + +# +# Telephony Support +# +# CONFIG_PHONE is not set + +# +# Input device support +# +CONFIG_INPUT=y +# CONFIG_INPUT_FF_MEMLESS is not set + +# +# Userland interfaces +# +# CONFIG_INPUT_MOUSEDEV is not set +# CONFIG_INPUT_JOYDEV is not set +# CONFIG_INPUT_TSDEV is not set +# CONFIG_INPUT_EVDEV is not set +# CONFIG_INPUT_EVBUG is not set + +# +# Input Device Drivers +# +# CONFIG_INPUT_KEYBOARD is not set +# CONFIG_INPUT_MOUSE is not set +# CONFIG_INPUT_JOYSTICK is not set +# CONFIG_INPUT_TOUCHSCREEN is not set +# CONFIG_INPUT_MISC is not set + +# +# Hardware I/O ports +# +CONFIG_SERIO=y +# CONFIG_SERIO_I8042 is not set +CONFIG_SERIO_SERPORT=y +# CONFIG_SERIO_LIBPS2 is not set +# CONFIG_SERIO_RAW is not set +# CONFIG_GAMEPORT is not set + +# +# Character devices +# +CONFIG_VT=y +CONFIG_VT_CONSOLE=y +CONFIG_HW_CONSOLE=y +# CONFIG_VT_HW_CONSOLE_BINDING is not set +# CONFIG_SERIAL_NONSTANDARD is not set + +# +# Serial drivers +# +# CONFIG_SERIAL_8250 is not set + +# +# Non-8250 serial port support +# +CONFIG_SERIAL_CORE=y +CONFIG_SERIAL_CORE_CONSOLE=y +CONFIG_SERIAL_M32R_SIO=y +CONFIG_SERIAL_M32R_SIO_CONSOLE=y +CONFIG_UNIX98_PTYS=y +CONFIG_LEGACY_PTYS=y +CONFIG_LEGACY_PTY_COUNT=256 + +# +# IPMI +# +# CONFIG_IPMI_HANDLER is not set + +# +# Watchdog Cards +# +# CONFIG_WATCHDOG is not set +CONFIG_HW_RANDOM=y +# CONFIG_RTC is not set +# CONFIG_DTLK is not set +# CONFIG_R3964 is not set + +# +# Ftape, the floppy tape device driver +# + +# +# PCMCIA character devices +# +# CONFIG_SYNCLINK_CS is not set +# CONFIG_CARDMAN_4000 is not set +# CONFIG_CARDMAN_4040 is not set +# CONFIG_RAW_DRIVER is not set + +# +# TPM devices +# +# CONFIG_TCG_TPM is not set + +# +# I2C support +# +# CONFIG_I2C is not set + +# +# SPI support +# +# CONFIG_SPI is not set +# CONFIG_SPI_MASTER is not set + +# +# Dallas's 1-wire bus +# +# CONFIG_W1 is not set + +# +# Hardware Monitoring support +# +CONFIG_HWMON=y +# CONFIG_HWMON_VID is not set +# CONFIG_SENSORS_ABITUGURU is not set +# CONFIG_SENSORS_F71805F is not set +# CONFIG_SENSORS_VT1211 is not set +# CONFIG_HWMON_DEBUG_CHIP is not set + +# +# Multimedia devices +# +CONFIG_VIDEO_DEV=y +CONFIG_VIDEO_V4L1=y +CONFIG_VIDEO_V4L1_COMPAT=y +CONFIG_VIDEO_V4L2=y + +# +# Video Capture Adapters +# + +# +# Video Capture Adapters +# +# CONFIG_VIDEO_ADV_DEBUG is not set +CONFIG_VIDEO_HELPER_CHIPS_AUTO=y +# CONFIG_VIDEO_VIVI is not set +# CONFIG_VIDEO_CPIA is not set +# CONFIG_VIDEO_M32R_AR is not set + +# +# Radio Adapters +# + +# +# Digital Video Broadcasting Devices +# +# CONFIG_DVB is not set + +# +# Graphics support +# +CONFIG_FIRMWARE_EDID=y +# CONFIG_FB is not set + +# +# Console display driver support +# +# CONFIG_VGA_CONSOLE is not set +CONFIG_DUMMY_CONSOLE=y +# CONFIG_BACKLIGHT_LCD_SUPPORT is not set + +# +# Sound +# +# CONFIG_SOUND is not set + +# +# USB support +# +# CONFIG_USB_ARCH_HAS_HCD is not set +# CONFIG_USB_ARCH_HAS_OHCI is not set +# CONFIG_USB_ARCH_HAS_EHCI is not set + +# +# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support' +# + +# +# USB Gadget Support +# +# CONFIG_USB_GADGET is not set + +# +# MMC/SD Card support +# +# CONFIG_MMC is not set + +# +# LED devices +# +# CONFIG_NEW_LEDS is not set + +# +# LED drivers +# + +# +# LED Triggers +# + +# +# InfiniBand support +# + +# +# EDAC - error detection and reporting (RAS) (EXPERIMENTAL) +# + +# +# Real Time Clock +# +# CONFIG_RTC_CLASS is not set + +# +# DMA Engine support +# +# CONFIG_DMA_ENGINE is not set + +# +# DMA Clients +# + +# +# DMA Devices +# + +# +# File systems +# +CONFIG_EXT2_FS=y +# CONFIG_EXT2_FS_XATTR is not set +# CONFIG_EXT2_FS_XIP is not set +CONFIG_EXT3_FS=y +CONFIG_EXT3_FS_XATTR=y +# CONFIG_EXT3_FS_POSIX_ACL is not set +# CONFIG_EXT3_FS_SECURITY is not set +# CONFIG_EXT4DEV_FS is not set +CONFIG_JBD=y +CONFIG_JBD_DEBUG=y +CONFIG_FS_MBCACHE=y +# CONFIG_REISERFS_FS is not set +# CONFIG_JFS_FS is not set +# CONFIG_FS_POSIX_ACL is not set +# CONFIG_XFS_FS is not set +# CONFIG_GFS2_FS is not set +# CONFIG_OCFS2_FS is not set +# CONFIG_MINIX_FS is not set +# CONFIG_ROMFS_FS is not set +CONFIG_INOTIFY=y +CONFIG_INOTIFY_USER=y +# CONFIG_QUOTA is not set +CONFIG_DNOTIFY=y +# CONFIG_AUTOFS_FS is not set +# CONFIG_AUTOFS4_FS is not set +# CONFIG_FUSE_FS is not set + +# +# CD-ROM/DVD Filesystems +# +CONFIG_ISO9660_FS=m +CONFIG_JOLIET=y +# CONFIG_ZISOFS is not set +CONFIG_UDF_FS=m +CONFIG_UDF_NLS=y + +# +# DOS/FAT/NT Filesystems +# +CONFIG_FAT_FS=m +CONFIG_MSDOS_FS=m +CONFIG_VFAT_FS=m +CONFIG_FAT_DEFAULT_CODEPAGE=437 +CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1" +# CONFIG_NTFS_FS is not set + +# +# Pseudo filesystems +# +CONFIG_PROC_FS=y +CONFIG_PROC_KCORE=y +CONFIG_PROC_SYSCTL=y +CONFIG_SYSFS=y +CONFIG_TMPFS=y +# CONFIG_TMPFS_POSIX_ACL is not set +# CONFIG_HUGETLB_PAGE is not set +CONFIG_RAMFS=y +# CONFIG_CONFIGFS_FS is not set + +# +# Miscellaneous filesystems +# +# CONFIG_ADFS_FS is not set +# CONFIG_AFFS_FS is not set +# CONFIG_HFS_FS is not set +# CONFIG_HFSPLUS_FS is not set +# CONFIG_BEFS_FS is not set +# CONFIG_BFS_FS is not set +# CONFIG_EFS_FS is not set +# CONFIG_CRAMFS is not set +# CONFIG_VXFS_FS is not set +# CONFIG_HPFS_FS is not set +# CONFIG_QNX4FS_FS is not set +# CONFIG_SYSV_FS is not set +# CONFIG_UFS_FS is not set + +# +# Network File Systems +# +CONFIG_NFS_FS=y +CONFIG_NFS_V3=y +# CONFIG_NFS_V3_ACL is not set +# CONFIG_NFS_V4 is not set +# CONFIG_NFS_DIRECTIO is not set +# CONFIG_NFSD is not set +CONFIG_ROOT_NFS=y +CONFIG_LOCKD=y +CONFIG_LOCKD_V4=y +CONFIG_NFS_COMMON=y +CONFIG_SUNRPC=y +# CONFIG_RPCSEC_GSS_KRB5 is not set +# CONFIG_RPCSEC_GSS_SPKM3 is not set +# CONFIG_SMB_FS is not set +# CONFIG_CIFS is not set +# CONFIG_NCP_FS is not set +# CONFIG_CODA_FS is not set +# CONFIG_AFS_FS is not set +# CONFIG_9P_FS is not set + +# +# Partition Types +# +# CONFIG_PARTITION_ADVANCED is not set +CONFIG_MSDOS_PARTITION=y + +# +# Native Language Support +# +CONFIG_NLS=y +CONFIG_NLS_DEFAULT="iso8859-1" +# CONFIG_NLS_CODEPAGE_437 is not set +# CONFIG_NLS_CODEPAGE_737 is not set +# CONFIG_NLS_CODEPAGE_775 is not set +# CONFIG_NLS_CODEPAGE_850 is not set +# CONFIG_NLS_CODEPAGE_852 is not set +# CONFIG_NLS_CODEPAGE_855 is not set +# CONFIG_NLS_CODEPAGE_857 is not set +# CONFIG_NLS_CODEPAGE_860 is not set +# CONFIG_NLS_CODEPAGE_861 is not set +# CONFIG_NLS_CODEPAGE_862 is not set +# CONFIG_NLS_CODEPAGE_863 is not set +# CONFIG_NLS_CODEPAGE_864 is not set +# CONFIG_NLS_CODEPAGE_865 is not set +# CONFIG_NLS_CODEPAGE_866 is not set +# CONFIG_NLS_CODEPAGE_869 is not set +# CONFIG_NLS_CODEPAGE_936 is not set +# CONFIG_NLS_CODEPAGE_950 is not set +# CONFIG_NLS_CODEPAGE_932 is not set +# CONFIG_NLS_CODEPAGE_949 is not set +# CONFIG_NLS_CODEPAGE_874 is not set +# CONFIG_NLS_ISO8859_8 is not set +# CONFIG_NLS_CODEPAGE_1250 is not set +# CONFIG_NLS_CODEPAGE_1251 is not set +# CONFIG_NLS_ASCII is not set +# CONFIG_NLS_ISO8859_1 is not set +# CONFIG_NLS_ISO8859_2 is not set +# CONFIG_NLS_ISO8859_3 is not set +# CONFIG_NLS_ISO8859_4 is not set +# CONFIG_NLS_ISO8859_5 is not set +# CONFIG_NLS_ISO8859_6 is not set +# CONFIG_NLS_ISO8859_7 is not set +# CONFIG_NLS_ISO8859_9 is not set +# CONFIG_NLS_ISO8859_13 is not set +# CONFIG_NLS_ISO8859_14 is not set +# CONFIG_NLS_ISO8859_15 is not set +# CONFIG_NLS_KOI8_R is not set +# CONFIG_NLS_KOI8_U is not set +# CONFIG_NLS_UTF8 is not set + +# +# Profiling support +# +# CONFIG_PROFILING is not set + +# +# Kernel hacking +# +# CONFIG_PRINTK_TIME is not set +CONFIG_ENABLE_MUST_CHECK=y +# CONFIG_MAGIC_SYSRQ is not set +# CONFIG_UNUSED_SYMBOLS is not set +# CONFIG_DEBUG_KERNEL is not set +CONFIG_LOG_BUF_SHIFT=14 +# CONFIG_DEBUG_BUGVERBOSE is not set +# CONFIG_DEBUG_FS is not set +# CONFIG_FRAME_POINTER is not set +# CONFIG_UNWIND_INFO is not set +# CONFIG_HEADERS_CHECK is not set + +# +# Security options +# +# CONFIG_KEYS is not set +# CONFIG_SECURITY is not set + +# +# Cryptographic options +# +# CONFIG_CRYPTO is not set + +# +# Library routines +# +# CONFIG_CRC_CCITT is not set +# CONFIG_CRC16 is not set +CONFIG_CRC32=y +# CONFIG_LIBCRC32C is not set diff --git a/arch/m32r/mappi2/defconfig.vdec2 b/arch/m32r/mappi2/defconfig.vdec2 index 56f287b..fe5b2a6 100644 --- a/arch/m32r/mappi2/defconfig.vdec2 +++ b/arch/m32r/mappi2/defconfig.vdec2 @@ -1,19 +1,18 @@ # # Automatically generated make config: don't edit -# Linux kernel version: 2.6.12-rc5 -# Fri Jun 3 16:22:02 2005 +# Linux kernel version: 2.6.19 +# Wed Dec 13 19:31:44 2006 # CONFIG_M32R=y -# CONFIG_UID16 is not set CONFIG_GENERIC_ISA_DMA=y CONFIG_GENERIC_HARDIRQS=y CONFIG_GENERIC_IRQ_PROBE=y +CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config" # # Code maturity level options # CONFIG_EXPERIMENTAL=y -CONFIG_CLEAN_COMPILE=y CONFIG_BROKEN_ON_SMP=y CONFIG_LOCK_KERNEL=y CONFIG_INIT_ENV_ARG_LIMIT=32 @@ -22,32 +21,39 @@ # # General setup # CONFIG_LOCALVERSION="" +CONFIG_LOCALVERSION_AUTO=y CONFIG_SWAP=y CONFIG_SYSVIPC=y +# CONFIG_IPC_NS is not set # CONFIG_POSIX_MQUEUE is not set CONFIG_BSD_PROCESS_ACCT=y # CONFIG_BSD_PROCESS_ACCT_V3 is not set -CONFIG_SYSCTL=y +# CONFIG_TASKSTATS is not set +# CONFIG_UTS_NS is not set # CONFIG_AUDIT is not set -CONFIG_HOTPLUG=y -CONFIG_KOBJECT_UEVENT=y CONFIG_IKCONFIG=y # CONFIG_IKCONFIG_PROC is not set +CONFIG_SYSFS_DEPRECATED=y +# CONFIG_RELAY is not set +CONFIG_INITRAMFS_SOURCE="" +# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set +CONFIG_SYSCTL=y CONFIG_EMBEDDED=y +CONFIG_SYSCTL_SYSCALL=y # CONFIG_KALLSYMS is not set +CONFIG_HOTPLUG=y CONFIG_PRINTK=y CONFIG_BUG=y +CONFIG_ELF_CORE=y CONFIG_BASE_FULL=y # CONFIG_FUTEX is not set # CONFIG_EPOLL is not set -# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set CONFIG_SHMEM=y -CONFIG_CC_ALIGN_FUNCTIONS=0 -CONFIG_CC_ALIGN_LABELS=0 -CONFIG_CC_ALIGN_LOOPS=0 -CONFIG_CC_ALIGN_JUMPS=0 +CONFIG_SLAB=y +CONFIG_VM_EVENT_COUNTERS=y # CONFIG_TINY_SHMEM is not set CONFIG_BASE_SMALL=0 +# CONFIG_SLOB is not set # # Loadable module support @@ -55,12 +61,30 @@ # CONFIG_MODULES=y CONFIG_MODULE_UNLOAD=y # CONFIG_MODULE_FORCE_UNLOAD is not set -CONFIG_OBSOLETE_MODPARM=y # CONFIG_MODVERSIONS is not set # CONFIG_MODULE_SRCVERSION_ALL is not set CONFIG_KMOD=y # +# Block layer +# +CONFIG_BLOCK=y +# CONFIG_BLK_DEV_IO_TRACE is not set + +# +# IO Schedulers +# +CONFIG_IOSCHED_NOOP=y +# CONFIG_IOSCHED_AS is not set +CONFIG_IOSCHED_DEADLINE=y +CONFIG_IOSCHED_CFQ=y +# CONFIG_DEFAULT_AS is not set +# CONFIG_DEFAULT_DEADLINE is not set +CONFIG_DEFAULT_CFQ=y +# CONFIG_DEFAULT_NOOP is not set +CONFIG_DEFAULT_IOSCHED="cfq" + +# # Processor type and features # # CONFIG_PLAT_MAPPI is not set @@ -70,8 +94,10 @@ # CONFIG_PLAT_OPSPUT is not set # CONFIG_PLAT_OAKS32R is not set CONFIG_PLAT_MAPPI2=y # CONFIG_PLAT_MAPPI3 is not set +# CONFIG_PLAT_M32104UT is not set # CONFIG_CHIP_M32700 is not set # CONFIG_CHIP_M32102 is not set +# CONFIG_CHIP_M32104 is not set CONFIG_CHIP_VDEC2=y # CONFIG_CHIP_OPSP is not set CONFIG_MMU=y @@ -83,18 +109,31 @@ # CONFIG_CPU_LITTLE_ENDIAN is not set CONFIG_MEMORY_START=0x08000000 CONFIG_MEMORY_SIZE=0x01000000 CONFIG_NOHIGHMEM=y -# CONFIG_DISCONTIGMEM is not set +CONFIG_ARCH_DISCONTIGMEM_ENABLE=y +CONFIG_SELECT_MEMORY_MODEL=y +# CONFIG_FLATMEM_MANUAL is not set +CONFIG_DISCONTIGMEM_MANUAL=y +# CONFIG_SPARSEMEM_MANUAL is not set +CONFIG_DISCONTIGMEM=y +CONFIG_FLAT_NODE_MEM_MAP=y +CONFIG_NEED_MULTIPLE_NODES=y +# CONFIG_SPARSEMEM_STATIC is not set +CONFIG_SPLIT_PTLOCK_CPUS=4 +# CONFIG_RESOURCES_64BIT is not set +CONFIG_IRAM_START=0x00f00000 +CONFIG_IRAM_SIZE=0x00008000 CONFIG_RWSEM_GENERIC_SPINLOCK=y # CONFIG_RWSEM_XCHGADD_ALGORITHM is not set +CONFIG_GENERIC_FIND_NEXT_BIT=y +CONFIG_GENERIC_HWEIGHT=y CONFIG_GENERIC_CALIBRATE_DELAY=y CONFIG_PREEMPT=y -# CONFIG_HAVE_DEC_LOCK is not set # CONFIG_SMP is not set +CONFIG_NODES_SHIFT=1 # # Bus options (PCI, PCMCIA, EISA, MCA, ISA) # -# CONFIG_PCI is not set # CONFIG_ISA is not set # @@ -103,11 +142,12 @@ # CONFIG_PCCARD=y # CONFIG_PCMCIA_DEBUG is not set CONFIG_PCMCIA=y +CONFIG_PCMCIA_LOAD_CIS=y +CONFIG_PCMCIA_IOCTL=y # # PC-card bridges # -# CONFIG_TCIC is not set # CONFIG_M32R_CFC is not set # @@ -121,6 +161,94 @@ CONFIG_BINFMT_ELF=y # CONFIG_BINFMT_MISC is not set # +# Networking +# +CONFIG_NET=y + +# +# Networking options +# +# CONFIG_NETDEBUG is not set +CONFIG_PACKET=y +# CONFIG_PACKET_MMAP is not set +CONFIG_UNIX=y +CONFIG_XFRM=y +# CONFIG_XFRM_USER is not set +# CONFIG_XFRM_SUB_POLICY is not set +# CONFIG_NET_KEY is not set +CONFIG_INET=y +# CONFIG_IP_MULTICAST is not set +# CONFIG_IP_ADVANCED_ROUTER is not set +CONFIG_IP_FIB_HASH=y +CONFIG_IP_PNP=y +CONFIG_IP_PNP_DHCP=y +# CONFIG_IP_PNP_BOOTP is not set +# CONFIG_IP_PNP_RARP is not set +# CONFIG_NET_IPIP is not set +# CONFIG_NET_IPGRE is not set +# CONFIG_ARPD is not set +# CONFIG_SYN_COOKIES is not set +# CONFIG_INET_AH is not set +# CONFIG_INET_ESP is not set +# CONFIG_INET_IPCOMP is not set +# CONFIG_INET_XFRM_TUNNEL is not set +# CONFIG_INET_TUNNEL is not set +CONFIG_INET_XFRM_MODE_TRANSPORT=y +CONFIG_INET_XFRM_MODE_TUNNEL=y +CONFIG_INET_XFRM_MODE_BEET=y +CONFIG_INET_DIAG=y +CONFIG_INET_TCP_DIAG=y +# CONFIG_TCP_CONG_ADVANCED is not set +CONFIG_TCP_CONG_CUBIC=y +CONFIG_DEFAULT_TCP_CONG="cubic" +# CONFIG_TCP_MD5SIG is not set +# CONFIG_IPV6 is not set +# CONFIG_INET6_XFRM_TUNNEL is not set +# CONFIG_INET6_TUNNEL is not set +# CONFIG_NETWORK_SECMARK is not set +# CONFIG_NETFILTER is not set + +# +# DCCP Configuration (EXPERIMENTAL) +# +# CONFIG_IP_DCCP is not set + +# +# SCTP Configuration (EXPERIMENTAL) +# +# CONFIG_IP_SCTP is not set + +# +# TIPC Configuration (EXPERIMENTAL) +# +# CONFIG_TIPC is not set +# CONFIG_ATM is not set +# CONFIG_BRIDGE is not set +# CONFIG_VLAN_8021Q is not set +# CONFIG_DECNET is not set +# CONFIG_LLC2 is not set +# CONFIG_IPX is not set +# CONFIG_ATALK is not set +# CONFIG_X25 is not set +# CONFIG_LAPB is not set +# CONFIG_ECONET is not set +# CONFIG_WAN_ROUTER is not set + +# +# QoS and/or fair queueing +# +# CONFIG_NET_SCHED is not set + +# +# Network testing +# +# CONFIG_NET_PKTGEN is not set +# CONFIG_HAMRADIO is not set +# CONFIG_IRDA is not set +# CONFIG_BT is not set +# CONFIG_IEEE80211 is not set + +# # Device Drivers # @@ -129,7 +257,13 @@ # Generic Driver Options # CONFIG_STANDALONE=y CONFIG_PREVENT_FIRMWARE_BUILD=y -# CONFIG_FW_LOADER is not set +CONFIG_FW_LOADER=y +# CONFIG_SYS_HYPERVISOR is not set + +# +# Connector - unified userspace <-> kernelspace linker +# +# CONFIG_CONNECTOR is not set # # Memory Technology Devices (MTD) @@ -148,7 +282,6 @@ # # # Block devices # -# CONFIG_BLK_DEV_FD is not set # CONFIG_BLK_DEV_COW_COMMON is not set CONFIG_BLK_DEV_LOOP=y # CONFIG_BLK_DEV_CRYPTOLOOP is not set @@ -156,23 +289,21 @@ CONFIG_BLK_DEV_NBD=y CONFIG_BLK_DEV_RAM=y CONFIG_BLK_DEV_RAM_COUNT=16 CONFIG_BLK_DEV_RAM_SIZE=4096 +CONFIG_BLK_DEV_RAM_BLOCKSIZE=1024 # CONFIG_BLK_DEV_INITRD is not set -CONFIG_INITRAMFS_SOURCE="" # CONFIG_CDROM_PKTCDVD is not set +# CONFIG_ATA_OVER_ETH is not set # -# IO Schedulers +# Misc devices # -CONFIG_IOSCHED_NOOP=y -# CONFIG_IOSCHED_AS is not set -CONFIG_IOSCHED_DEADLINE=y -CONFIG_IOSCHED_CFQ=y -# CONFIG_ATA_OVER_ETH is not set +# CONFIG_TIFM_CORE is not set # # ATA/ATAPI/MFM/RLL support # CONFIG_IDE=y +CONFIG_IDE_MAX_HWIFS=4 CONFIG_BLK_DEV_IDE=y # @@ -200,7 +331,9 @@ # CONFIG_BLK_DEV_HD is not set # # SCSI device support # +# CONFIG_RAID_ATTRS is not set CONFIG_SCSI=m +# CONFIG_SCSI_NETLINK is not set CONFIG_SCSI_PROC_FS=y # @@ -212,6 +345,7 @@ # CONFIG_CHR_DEV_OSST is not set CONFIG_BLK_DEV_SR=m # CONFIG_BLK_DEV_SR_VENDOR is not set CONFIG_CHR_DEV_SG=m +# CONFIG_CHR_DEV_SCH is not set # # Some SCSI devices (e.g. CD jukebox) support multiple LUNs @@ -221,16 +355,18 @@ # CONFIG_SCSI_CONSTANTS is not set # CONFIG_SCSI_LOGGING is not set # -# SCSI Transport Attributes +# SCSI Transports # # CONFIG_SCSI_SPI_ATTRS is not set # CONFIG_SCSI_FC_ATTRS is not set # CONFIG_SCSI_ISCSI_ATTRS is not set +# CONFIG_SCSI_SAS_ATTRS is not set +# CONFIG_SCSI_SAS_LIBSAS is not set # # SCSI low-level drivers # -# CONFIG_SCSI_SATA is not set +# CONFIG_ISCSI_TCP is not set # CONFIG_SCSI_DEBUG is not set # @@ -243,6 +379,10 @@ # CONFIG_PCMCIA_QLOGIC is not set # CONFIG_PCMCIA_SYM53C500 is not set # +# Serial ATA (prod) and Parallel ATA (experimental) drivers +# + +# # Multi-device support (RAID and LVM) # # CONFIG_MD is not set @@ -250,6 +390,7 @@ # CONFIG_MD is not set # # Fusion MPT device support # +# CONFIG_FUSION is not set # # IEEE 1394 (FireWire) support @@ -260,69 +401,8 @@ # I2O device support # # -# Networking support -# -CONFIG_NET=y - -# -# Networking options -# -CONFIG_PACKET=y -# CONFIG_PACKET_MMAP is not set -CONFIG_UNIX=y -# CONFIG_NET_KEY is not set -CONFIG_INET=y -# CONFIG_IP_MULTICAST is not set -# CONFIG_IP_ADVANCED_ROUTER is not set -CONFIG_IP_PNP=y -CONFIG_IP_PNP_DHCP=y -# CONFIG_IP_PNP_BOOTP is not set -# CONFIG_IP_PNP_RARP is not set -# CONFIG_NET_IPIP is not set -# CONFIG_NET_IPGRE is not set -# CONFIG_ARPD is not set -# CONFIG_SYN_COOKIES is not set -# CONFIG_INET_AH is not set -# CONFIG_INET_ESP is not set -# CONFIG_INET_IPCOMP is not set -# CONFIG_INET_TUNNEL is not set -CONFIG_IP_TCPDIAG=y -# CONFIG_IP_TCPDIAG_IPV6 is not set -# CONFIG_IPV6 is not set -# CONFIG_NETFILTER is not set - -# -# SCTP Configuration (EXPERIMENTAL) -# -# CONFIG_IP_SCTP is not set -# CONFIG_ATM is not set -# CONFIG_BRIDGE is not set -# CONFIG_VLAN_8021Q is not set -# CONFIG_DECNET is not set -# CONFIG_LLC2 is not set -# CONFIG_IPX is not set -# CONFIG_ATALK is not set -# CONFIG_X25 is not set -# CONFIG_LAPB is not set -# CONFIG_NET_DIVERT is not set -# CONFIG_ECONET is not set -# CONFIG_WAN_ROUTER is not set - -# -# QoS and/or fair queueing -# -# CONFIG_NET_SCHED is not set -# CONFIG_NET_CLS_ROUTE is not set - -# -# Network testing +# Network device support # -# CONFIG_NET_PKTGEN is not set -# CONFIG_NETPOLL is not set -# CONFIG_NET_POLL_CONTROLLER is not set -# CONFIG_HAMRADIO is not set -# CONFIG_IRDA is not set -# CONFIG_BT is not set CONFIG_NETDEVICES=y # CONFIG_DUMMY is not set # CONFIG_BONDING is not set @@ -330,6 +410,11 @@ # CONFIG_EQUALIZER is not set # CONFIG_TUN is not set # +# PHY device support +# +# CONFIG_PHYLIB is not set + +# # Ethernet (10 or 100Mbit) # CONFIG_NET_ETHERNET=y @@ -367,6 +452,8 @@ # CONFIG_PPP is not set # CONFIG_SLIP is not set # CONFIG_SHAPER is not set # CONFIG_NETCONSOLE is not set +# CONFIG_NETPOLL is not set +# CONFIG_NET_POLL_CONTROLLER is not set # # ISDN subsystem @@ -382,6 +469,7 @@ # # Input device support # CONFIG_INPUT=y +# CONFIG_INPUT_FF_MEMLESS is not set # # Userland interfaces @@ -410,7 +498,6 @@ CONFIG_SERIO_SERPORT=y # CONFIG_SERIO_LIBPS2 is not set # CONFIG_SERIO_RAW is not set # CONFIG_GAMEPORT is not set -CONFIG_SOUND_GAMEPORT=y # # Character devices @@ -418,6 +505,7 @@ # CONFIG_VT=y CONFIG_VT_CONSOLE=y CONFIG_HW_CONSOLE=y +# CONFIG_VT_HW_CONSOLE_BINDING is not set # CONFIG_SERIAL_NONSTANDARD is not set # @@ -432,7 +520,6 @@ CONFIG_SERIAL_CORE=y CONFIG_SERIAL_CORE_CONSOLE=y CONFIG_SERIAL_M32R_SIO=y CONFIG_SERIAL_M32R_SIO_CONSOLE=y -# CONFIG_SERIAL_M32R_PLDSIO is not set CONFIG_UNIX98_PTYS=y CONFIG_LEGACY_PTYS=y CONFIG_LEGACY_PTY_COUNT=256 @@ -446,25 +533,27 @@ # # Watchdog Cards # # CONFIG_WATCHDOG is not set +CONFIG_HW_RANDOM=y # CONFIG_RTC is not set -# CONFIG_GEN_RTC is not set # CONFIG_DTLK is not set # CONFIG_R3964 is not set # # Ftape, the floppy tape device driver # -# CONFIG_DRM is not set # # PCMCIA character devices # # CONFIG_SYNCLINK_CS is not set +# CONFIG_CARDMAN_4000 is not set +# CONFIG_CARDMAN_4040 is not set # CONFIG_RAW_DRIVER is not set # # TPM devices # +# CONFIG_TCG_TPM is not set # # I2C support @@ -472,33 +561,50 @@ # # CONFIG_I2C is not set # +# SPI support +# +# CONFIG_SPI is not set +# CONFIG_SPI_MASTER is not set + +# # Dallas's 1-wire bus # # CONFIG_W1 is not set # -# Misc devices +# Hardware Monitoring support # +CONFIG_HWMON=y +# CONFIG_HWMON_VID is not set +# CONFIG_SENSORS_ABITUGURU is not set +# CONFIG_SENSORS_F71805F is not set +# CONFIG_SENSORS_VT1211 is not set +# CONFIG_HWMON_DEBUG_CHIP is not set # # Multimedia devices # CONFIG_VIDEO_DEV=y +CONFIG_VIDEO_V4L1=y +CONFIG_VIDEO_V4L1_COMPAT=y +CONFIG_VIDEO_V4L2=y # -# Video For Linux +# Video Capture Adapters # # -# Video Adapters +# Video Capture Adapters # +# CONFIG_VIDEO_ADV_DEBUG is not set +CONFIG_VIDEO_HELPER_CHIPS_AUTO=y +# CONFIG_VIDEO_VIVI is not set # CONFIG_VIDEO_CPIA is not set # CONFIG_VIDEO_M32R_AR is not set # # Radio Adapters # -# CONFIG_RADIO_MAESTRO is not set # # Digital Video Broadcasting Devices @@ -508,6 +614,7 @@ # CONFIG_DVB is not set # # Graphics support # +CONFIG_FIRMWARE_EDID=y # CONFIG_FB is not set # @@ -515,6 +622,7 @@ # Console display driver support # # CONFIG_VGA_CONSOLE is not set CONFIG_DUMMY_CONSOLE=y +# CONFIG_BACKLIGHT_LCD_SUPPORT is not set # # Sound @@ -526,6 +634,11 @@ # USB support # # CONFIG_USB_ARCH_HAS_HCD is not set # CONFIG_USB_ARCH_HAS_OHCI is not set +# CONFIG_USB_ARCH_HAS_EHCI is not set + +# +# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support' +# # # USB Gadget Support @@ -538,38 +651,73 @@ # # CONFIG_MMC is not set # +# LED devices +# +# CONFIG_NEW_LEDS is not set + +# +# LED drivers +# + +# +# LED Triggers +# + +# # InfiniBand support # -# CONFIG_INFINIBAND is not set + +# +# EDAC - error detection and reporting (RAS) (EXPERIMENTAL) +# + +# +# Real Time Clock +# +# CONFIG_RTC_CLASS is not set + +# +# DMA Engine support +# +# CONFIG_DMA_ENGINE is not set + +# +# DMA Clients +# + +# +# DMA Devices +# # # File systems # CONFIG_EXT2_FS=y # CONFIG_EXT2_FS_XATTR is not set -CONFIG_EXT3_FS=m +# CONFIG_EXT2_FS_XIP is not set +CONFIG_EXT3_FS=y CONFIG_EXT3_FS_XATTR=y # CONFIG_EXT3_FS_POSIX_ACL is not set # CONFIG_EXT3_FS_SECURITY is not set -CONFIG_JBD=m +# CONFIG_EXT4DEV_FS is not set +CONFIG_JBD=y CONFIG_JBD_DEBUG=y CONFIG_FS_MBCACHE=y -CONFIG_REISERFS_FS=m -# CONFIG_REISERFS_CHECK is not set -# CONFIG_REISERFS_PROC_INFO is not set -# CONFIG_REISERFS_FS_XATTR is not set +# CONFIG_REISERFS_FS is not set # CONFIG_JFS_FS is not set - -# -# XFS support -# +# CONFIG_FS_POSIX_ACL is not set # CONFIG_XFS_FS is not set +# CONFIG_GFS2_FS is not set +# CONFIG_OCFS2_FS is not set # CONFIG_MINIX_FS is not set # CONFIG_ROMFS_FS is not set +CONFIG_INOTIFY=y +CONFIG_INOTIFY_USER=y # CONFIG_QUOTA is not set CONFIG_DNOTIFY=y # CONFIG_AUTOFS_FS is not set # CONFIG_AUTOFS4_FS is not set +# CONFIG_FUSE_FS is not set # # CD-ROM/DVD Filesystems @@ -595,15 +743,13 @@ # Pseudo filesystems # CONFIG_PROC_FS=y CONFIG_PROC_KCORE=y +CONFIG_PROC_SYSCTL=y CONFIG_SYSFS=y -CONFIG_DEVFS_FS=y -CONFIG_DEVFS_MOUNT=y -# CONFIG_DEVFS_DEBUG is not set -# CONFIG_DEVPTS_FS_XATTR is not set CONFIG_TMPFS=y -# CONFIG_TMPFS_XATTR is not set +# CONFIG_TMPFS_POSIX_ACL is not set # CONFIG_HUGETLB_PAGE is not set CONFIG_RAMFS=y +# CONFIG_CONFIGFS_FS is not set # # Miscellaneous filesystems @@ -627,12 +773,14 @@ # Network File Systems # CONFIG_NFS_FS=y CONFIG_NFS_V3=y +# CONFIG_NFS_V3_ACL is not set # CONFIG_NFS_V4 is not set # CONFIG_NFS_DIRECTIO is not set # CONFIG_NFSD is not set CONFIG_ROOT_NFS=y CONFIG_LOCKD=y CONFIG_LOCKD_V4=y +CONFIG_NFS_COMMON=y CONFIG_SUNRPC=y # CONFIG_RPCSEC_GSS_KRB5 is not set # CONFIG_RPCSEC_GSS_SPKM3 is not set @@ -641,6 +789,7 @@ # CONFIG_CIFS is not set # CONFIG_NCP_FS is not set # CONFIG_CODA_FS is not set # CONFIG_AFS_FS is not set +# CONFIG_9P_FS is not set # # Partition Types @@ -701,10 +850,16 @@ # # Kernel hacking # # CONFIG_PRINTK_TIME is not set +CONFIG_ENABLE_MUST_CHECK=y +# CONFIG_MAGIC_SYSRQ is not set +# CONFIG_UNUSED_SYMBOLS is not set # CONFIG_DEBUG_KERNEL is not set CONFIG_LOG_BUF_SHIFT=14 # CONFIG_DEBUG_BUGVERBOSE is not set +# CONFIG_DEBUG_FS is not set # CONFIG_FRAME_POINTER is not set +# CONFIG_UNWIND_INFO is not set +# CONFIG_HEADERS_CHECK is not set # # Security options @@ -718,12 +873,9 @@ # # CONFIG_CRYPTO is not set # -# Hardware crypto devices -# - -# # Library routines # # CONFIG_CRC_CCITT is not set +# CONFIG_CRC16 is not set CONFIG_CRC32=y # CONFIG_LIBCRC32C is not set diff --git a/arch/m32r/mappi3/defconfig.smp b/arch/m32r/mappi3/defconfig.smp index 2eebe75..2f35226 100644 --- a/arch/m32r/mappi3/defconfig.smp +++ b/arch/m32r/mappi3/defconfig.smp @@ -1,21 +1,18 @@ # # Automatically generated make config: don't edit -# Linux kernel version: 2.6.12-rc5 -# Tue May 31 17:55:34 2005 +# Linux kernel version: 2.6.19 +# Mon Dec 11 19:57:33 2006 # CONFIG_M32R=y -# CONFIG_UID16 is not set CONFIG_GENERIC_ISA_DMA=y CONFIG_GENERIC_HARDIRQS=y CONFIG_GENERIC_IRQ_PROBE=y +CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config" # # Code maturity level options # CONFIG_EXPERIMENTAL=y -# CONFIG_CLEAN_COMPILE is not set -CONFIG_BROKEN=y -CONFIG_BROKEN_ON_SMP=y CONFIG_LOCK_KERNEL=y CONFIG_INIT_ENV_ARG_LIMIT=32 @@ -23,32 +20,39 @@ # # General setup # CONFIG_LOCALVERSION="" +CONFIG_LOCALVERSION_AUTO=y CONFIG_SWAP=y CONFIG_SYSVIPC=y +# CONFIG_IPC_NS is not set # CONFIG_POSIX_MQUEUE is not set # CONFIG_BSD_PROCESS_ACCT is not set -CONFIG_SYSCTL=y +# CONFIG_TASKSTATS is not set +# CONFIG_UTS_NS is not set # CONFIG_AUDIT is not set -CONFIG_HOTPLUG=y -CONFIG_KOBJECT_UEVENT=y CONFIG_IKCONFIG=y CONFIG_IKCONFIG_PROC=y # CONFIG_CPUSETS is not set +CONFIG_SYSFS_DEPRECATED=y +# CONFIG_RELAY is not set +CONFIG_INITRAMFS_SOURCE="" +# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set +CONFIG_SYSCTL=y CONFIG_EMBEDDED=y +CONFIG_SYSCTL_SYSCALL=y # CONFIG_KALLSYMS is not set +CONFIG_HOTPLUG=y CONFIG_PRINTK=y CONFIG_BUG=y +CONFIG_ELF_CORE=y CONFIG_BASE_FULL=y # CONFIG_FUTEX is not set # CONFIG_EPOLL is not set -# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set CONFIG_SHMEM=y -CONFIG_CC_ALIGN_FUNCTIONS=0 -CONFIG_CC_ALIGN_LABELS=0 -CONFIG_CC_ALIGN_LOOPS=0 -CONFIG_CC_ALIGN_JUMPS=0 +CONFIG_SLAB=y +CONFIG_VM_EVENT_COUNTERS=y # CONFIG_TINY_SHMEM is not set CONFIG_BASE_SMALL=0 +# CONFIG_SLOB is not set # # Loadable module support @@ -56,13 +60,31 @@ # CONFIG_MODULES=y CONFIG_MODULE_UNLOAD=y # CONFIG_MODULE_FORCE_UNLOAD is not set -CONFIG_OBSOLETE_MODPARM=y # CONFIG_MODVERSIONS is not set # CONFIG_MODULE_SRCVERSION_ALL is not set CONFIG_KMOD=y CONFIG_STOP_MACHINE=y # +# Block layer +# +CONFIG_BLOCK=y +# CONFIG_BLK_DEV_IO_TRACE is not set + +# +# IO Schedulers +# +CONFIG_IOSCHED_NOOP=y +# CONFIG_IOSCHED_AS is not set +CONFIG_IOSCHED_DEADLINE=y +CONFIG_IOSCHED_CFQ=y +# CONFIG_DEFAULT_AS is not set +# CONFIG_DEFAULT_DEADLINE is not set +CONFIG_DEFAULT_CFQ=y +# CONFIG_DEFAULT_NOOP is not set +CONFIG_DEFAULT_IOSCHED="cfq" + +# # Processor type and features # # CONFIG_PLAT_MAPPI is not set @@ -72,8 +94,10 @@ # CONFIG_PLAT_OPSPUT is not set # CONFIG_PLAT_OAKS32R is not set # CONFIG_PLAT_MAPPI2 is not set CONFIG_PLAT_MAPPI3=y +# CONFIG_PLAT_M32104UT is not set CONFIG_CHIP_M32700=y # CONFIG_CHIP_M32102 is not set +# CONFIG_CHIP_M32104 is not set # CONFIG_CHIP_VDEC2 is not set # CONFIG_CHIP_OPSP is not set CONFIG_MMU=y @@ -87,23 +111,33 @@ # CONFIG_CPU_LITTLE_ENDIAN is not set CONFIG_MEMORY_START=0x08000000 CONFIG_MEMORY_SIZE=0x08000000 CONFIG_NOHIGHMEM=y +CONFIG_ARCH_DISCONTIGMEM_ENABLE=y +CONFIG_SELECT_MEMORY_MODEL=y +# CONFIG_FLATMEM_MANUAL is not set +CONFIG_DISCONTIGMEM_MANUAL=y +# CONFIG_SPARSEMEM_MANUAL is not set CONFIG_DISCONTIGMEM=y +CONFIG_FLAT_NODE_MEM_MAP=y +CONFIG_NEED_MULTIPLE_NODES=y +# CONFIG_SPARSEMEM_STATIC is not set +CONFIG_SPLIT_PTLOCK_CPUS=4 +# CONFIG_RESOURCES_64BIT is not set CONFIG_IRAM_START=0x00f00000 CONFIG_IRAM_SIZE=0x00080000 CONFIG_RWSEM_GENERIC_SPINLOCK=y # CONFIG_RWSEM_XCHGADD_ALGORITHM is not set +CONFIG_GENERIC_FIND_NEXT_BIT=y +CONFIG_GENERIC_HWEIGHT=y CONFIG_GENERIC_CALIBRATE_DELAY=y CONFIG_PREEMPT=y -# CONFIG_HAVE_DEC_LOCK is not set CONFIG_SMP=y # CONFIG_CHIP_M32700_TS1 is not set CONFIG_NR_CPUS=2 -# CONFIG_NUMA is not set +CONFIG_NODES_SHIFT=1 # # Bus options (PCI, PCMCIA, EISA, MCA, ISA) # -# CONFIG_PCI is not set # CONFIG_ISA is not set # @@ -112,11 +146,12 @@ # CONFIG_PCCARD=y # CONFIG_PCMCIA_DEBUG is not set CONFIG_PCMCIA=y +CONFIG_PCMCIA_LOAD_CIS=y +CONFIG_PCMCIA_IOCTL=y # # PC-card bridges # -# CONFIG_TCIC is not set # CONFIG_M32R_PCC is not set # CONFIG_M32R_CFC is not set @@ -131,6 +166,93 @@ CONFIG_BINFMT_ELF=y # CONFIG_BINFMT_MISC is not set # +# Networking +# +CONFIG_NET=y + +# +# Networking options +# +# CONFIG_NETDEBUG is not set +# CONFIG_PACKET is not set +CONFIG_UNIX=y +CONFIG_XFRM=y +# CONFIG_XFRM_USER is not set +# CONFIG_XFRM_SUB_POLICY is not set +# CONFIG_NET_KEY is not set +CONFIG_INET=y +# CONFIG_IP_MULTICAST is not set +# CONFIG_IP_ADVANCED_ROUTER is not set +CONFIG_IP_FIB_HASH=y +CONFIG_IP_PNP=y +CONFIG_IP_PNP_DHCP=y +# CONFIG_IP_PNP_BOOTP is not set +# CONFIG_IP_PNP_RARP is not set +# CONFIG_NET_IPIP is not set +# CONFIG_NET_IPGRE is not set +# CONFIG_ARPD is not set +# CONFIG_SYN_COOKIES is not set +# CONFIG_INET_AH is not set +# CONFIG_INET_ESP is not set +# CONFIG_INET_IPCOMP is not set +# CONFIG_INET_XFRM_TUNNEL is not set +# CONFIG_INET_TUNNEL is not set +CONFIG_INET_XFRM_MODE_TRANSPORT=y +CONFIG_INET_XFRM_MODE_TUNNEL=y +CONFIG_INET_XFRM_MODE_BEET=y +CONFIG_INET_DIAG=y +CONFIG_INET_TCP_DIAG=y +# CONFIG_TCP_CONG_ADVANCED is not set +CONFIG_TCP_CONG_CUBIC=y +CONFIG_DEFAULT_TCP_CONG="cubic" +# CONFIG_TCP_MD5SIG is not set +# CONFIG_IPV6 is not set +# CONFIG_INET6_XFRM_TUNNEL is not set +# CONFIG_INET6_TUNNEL is not set +# CONFIG_NETWORK_SECMARK is not set +# CONFIG_NETFILTER is not set + +# +# DCCP Configuration (EXPERIMENTAL) +# +# CONFIG_IP_DCCP is not set + +# +# SCTP Configuration (EXPERIMENTAL) +# +# CONFIG_IP_SCTP is not set + +# +# TIPC Configuration (EXPERIMENTAL) +# +# CONFIG_TIPC is not set +# CONFIG_ATM is not set +# CONFIG_BRIDGE is not set +# CONFIG_VLAN_8021Q is not set +# CONFIG_DECNET is not set +# CONFIG_LLC2 is not set +# CONFIG_IPX is not set +# CONFIG_ATALK is not set +# CONFIG_X25 is not set +# CONFIG_LAPB is not set +# CONFIG_ECONET is not set +# CONFIG_WAN_ROUTER is not set + +# +# QoS and/or fair queueing +# +# CONFIG_NET_SCHED is not set + +# +# Network testing +# +# CONFIG_NET_PKTGEN is not set +# CONFIG_HAMRADIO is not set +# CONFIG_IRDA is not set +# CONFIG_BT is not set +# CONFIG_IEEE80211 is not set + +# # Device Drivers # @@ -140,6 +262,12 @@ # CONFIG_STANDALONE=y CONFIG_PREVENT_FIRMWARE_BUILD=y CONFIG_FW_LOADER=y +# CONFIG_SYS_HYPERVISOR is not set + +# +# Connector - unified userspace <-> kernelspace linker +# +# CONFIG_CONNECTOR is not set # # Memory Technology Devices (MTD) @@ -162,6 +290,8 @@ CONFIG_MTD_BLOCK=y # CONFIG_FTL is not set # CONFIG_NFTL is not set # CONFIG_INFTL is not set +# CONFIG_RFD_FTL is not set +# CONFIG_SSFDC is not set # # RAM/ROM/Flash chip drivers @@ -187,6 +317,7 @@ # # Mapping drivers for chip access # # CONFIG_MTD_COMPLEX_MAPPINGS is not set +# CONFIG_MTD_PLATRAM is not set # # Self-contained MTD device drivers @@ -194,7 +325,6 @@ # # CONFIG_MTD_SLRAM is not set # CONFIG_MTD_PHRAM is not set # CONFIG_MTD_MTDRAM is not set -# CONFIG_MTD_BLKMTD is not set # CONFIG_MTD_BLOCK2MTD is not set # @@ -210,6 +340,11 @@ # # CONFIG_MTD_NAND is not set # +# OneNAND Flash Device Drivers +# +# CONFIG_MTD_ONENAND is not set + +# # Parallel port support # # CONFIG_PARPORT is not set @@ -221,7 +356,6 @@ # # # Block devices # -# CONFIG_BLK_DEV_FD is not set # CONFIG_BLK_DEV_COW_COMMON is not set CONFIG_BLK_DEV_LOOP=y # CONFIG_BLK_DEV_CRYPTOLOOP is not set @@ -229,23 +363,21 @@ CONFIG_BLK_DEV_NBD=m CONFIG_BLK_DEV_RAM=y CONFIG_BLK_DEV_RAM_COUNT=16 CONFIG_BLK_DEV_RAM_SIZE=4096 +CONFIG_BLK_DEV_RAM_BLOCKSIZE=1024 CONFIG_BLK_DEV_INITRD=y -CONFIG_INITRAMFS_SOURCE="" # CONFIG_CDROM_PKTCDVD is not set +# CONFIG_ATA_OVER_ETH is not set # -# IO Schedulers +# Misc devices # -CONFIG_IOSCHED_NOOP=y -# CONFIG_IOSCHED_AS is not set -CONFIG_IOSCHED_DEADLINE=y -CONFIG_IOSCHED_CFQ=y -# CONFIG_ATA_OVER_ETH is not set +# CONFIG_TIFM_CORE is not set # # ATA/ATAPI/MFM/RLL support # CONFIG_IDE=y +CONFIG_IDE_MAX_HWIFS=4 CONFIG_BLK_DEV_IDE=y # @@ -254,7 +386,7 @@ # # CONFIG_BLK_DEV_IDE_SATA is not set CONFIG_BLK_DEV_IDEDISK=y # CONFIG_IDEDISK_MULTI_MODE is not set -CONFIG_BLK_DEV_IDECS=y +CONFIG_BLK_DEV_IDECS=m CONFIG_BLK_DEV_IDECD=m # CONFIG_BLK_DEV_IDETAPE is not set # CONFIG_BLK_DEV_IDEFLOPPY is not set @@ -272,7 +404,13 @@ # CONFIG_BLK_DEV_HD is not set # # SCSI device support # +# CONFIG_RAID_ATTRS is not set # CONFIG_SCSI is not set +# CONFIG_SCSI_NETLINK is not set + +# +# Serial ATA (prod) and Parallel ATA (experimental) drivers +# # # Multi-device support (RAID and LVM) @@ -282,79 +420,19 @@ # CONFIG_MD is not set # # Fusion MPT device support # +# CONFIG_FUSION is not set # # IEEE 1394 (FireWire) support # -# CONFIG_IEEE1394 is not set # # I2O device support # # -# Networking support +# Network device support # -CONFIG_NET=y - -# -# Networking options -# -# CONFIG_PACKET is not set -CONFIG_UNIX=y -# CONFIG_NET_KEY is not set -CONFIG_INET=y -# CONFIG_IP_MULTICAST is not set -# CONFIG_IP_ADVANCED_ROUTER is not set -CONFIG_IP_PNP=y -CONFIG_IP_PNP_DHCP=y -# CONFIG_IP_PNP_BOOTP is not set -# CONFIG_IP_PNP_RARP is not set -# CONFIG_NET_IPIP is not set -# CONFIG_NET_IPGRE is not set -# CONFIG_ARPD is not set -# CONFIG_SYN_COOKIES is not set -# CONFIG_INET_AH is not set -# CONFIG_INET_ESP is not set -# CONFIG_INET_IPCOMP is not set -# CONFIG_INET_TUNNEL is not set -CONFIG_IP_TCPDIAG=y -# CONFIG_IP_TCPDIAG_IPV6 is not set -# CONFIG_IPV6 is not set -# CONFIG_NETFILTER is not set - -# -# SCTP Configuration (EXPERIMENTAL) -# -# CONFIG_IP_SCTP is not set -# CONFIG_ATM is not set -# CONFIG_BRIDGE is not set -# CONFIG_VLAN_8021Q is not set -# CONFIG_DECNET is not set -# CONFIG_LLC2 is not set -# CONFIG_IPX is not set -# CONFIG_ATALK is not set -# CONFIG_X25 is not set -# CONFIG_LAPB is not set -# CONFIG_NET_DIVERT is not set -# CONFIG_ECONET is not set -# CONFIG_WAN_ROUTER is not set - -# -# QoS and/or fair queueing -# -# CONFIG_NET_SCHED is not set -# CONFIG_NET_CLS_ROUTE is not set - -# -# Network testing -# -# CONFIG_NET_PKTGEN is not set -# CONFIG_NETPOLL is not set -# CONFIG_NET_POLL_CONTROLLER is not set -# CONFIG_HAMRADIO is not set -# CONFIG_IRDA is not set -# CONFIG_BT is not set CONFIG_NETDEVICES=y # CONFIG_DUMMY is not set # CONFIG_BONDING is not set @@ -362,6 +440,11 @@ # CONFIG_EQUALIZER is not set # CONFIG_TUN is not set # +# PHY device support +# +# CONFIG_PHYLIB is not set + +# # Ethernet (10 or 100Mbit) # CONFIG_NET_ETHERNET=y @@ -399,6 +482,8 @@ # CONFIG_PPP is not set # CONFIG_SLIP is not set # CONFIG_SHAPER is not set # CONFIG_NETCONSOLE is not set +# CONFIG_NETPOLL is not set +# CONFIG_NET_POLL_CONTROLLER is not set # # ISDN subsystem @@ -414,6 +499,7 @@ # # Input device support # CONFIG_INPUT=y +# CONFIG_INPUT_FF_MEMLESS is not set # # Userland interfaces @@ -445,7 +531,6 @@ # CONFIG_SERIO_SERPORT is not set # CONFIG_SERIO_LIBPS2 is not set # CONFIG_SERIO_RAW is not set # CONFIG_GAMEPORT is not set -CONFIG_SOUND_GAMEPORT=y # # Character devices @@ -465,7 +550,6 @@ CONFIG_SERIAL_CORE=y CONFIG_SERIAL_CORE_CONSOLE=y CONFIG_SERIAL_M32R_SIO=y CONFIG_SERIAL_M32R_SIO_CONSOLE=y -# CONFIG_SERIAL_M32R_PLDSIO is not set CONFIG_UNIX98_PTYS=y CONFIG_LEGACY_PTYS=y CONFIG_LEGACY_PTY_COUNT=256 @@ -479,25 +563,27 @@ # # Watchdog Cards # # CONFIG_WATCHDOG is not set +CONFIG_HW_RANDOM=y # CONFIG_RTC is not set -# CONFIG_GEN_RTC is not set # CONFIG_DTLK is not set # CONFIG_R3964 is not set # # Ftape, the floppy tape device driver # -# CONFIG_DRM is not set # # PCMCIA character devices # # CONFIG_SYNCLINK_CS is not set +# CONFIG_CARDMAN_4000 is not set +# CONFIG_CARDMAN_4040 is not set # CONFIG_RAW_DRIVER is not set # # TPM devices # +# CONFIG_TCG_TPM is not set # # I2C support @@ -505,13 +591,25 @@ # # CONFIG_I2C is not set # +# SPI support +# +# CONFIG_SPI is not set +# CONFIG_SPI_MASTER is not set + +# # Dallas's 1-wire bus # # CONFIG_W1 is not set # -# Misc devices +# Hardware Monitoring support # +CONFIG_HWMON=y +# CONFIG_HWMON_VID is not set +# CONFIG_SENSORS_ABITUGURU is not set +# CONFIG_SENSORS_F71805F is not set +# CONFIG_SENSORS_VT1211 is not set +# CONFIG_HWMON_DEBUG_CHIP is not set # # Multimedia devices @@ -526,7 +624,9 @@ # CONFIG_DVB is not set # # Graphics support # +CONFIG_FIRMWARE_EDID=y # CONFIG_FB is not set +# CONFIG_BACKLIGHT_LCD_SUPPORT is not set # # Sound @@ -538,6 +638,11 @@ # USB support # # CONFIG_USB_ARCH_HAS_HCD is not set # CONFIG_USB_ARCH_HAS_OHCI is not set +# CONFIG_USB_ARCH_HAS_EHCI is not set + +# +# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support' +# # # USB Gadget Support @@ -550,35 +655,73 @@ # # CONFIG_MMC is not set # +# LED devices +# +# CONFIG_NEW_LEDS is not set + +# +# LED drivers +# + +# +# LED Triggers +# + +# # InfiniBand support # -# CONFIG_INFINIBAND is not set + +# +# EDAC - error detection and reporting (RAS) (EXPERIMENTAL) +# + +# +# Real Time Clock +# +# CONFIG_RTC_CLASS is not set + +# +# DMA Engine support +# +# CONFIG_DMA_ENGINE is not set + +# +# DMA Clients +# + +# +# DMA Devices +# # # File systems # CONFIG_EXT2_FS=y # CONFIG_EXT2_FS_XATTR is not set +# CONFIG_EXT2_FS_XIP is not set CONFIG_EXT3_FS=y CONFIG_EXT3_FS_XATTR=y # CONFIG_EXT3_FS_POSIX_ACL is not set # CONFIG_EXT3_FS_SECURITY is not set +# CONFIG_EXT4DEV_FS is not set CONFIG_JBD=y # CONFIG_JBD_DEBUG is not set CONFIG_FS_MBCACHE=y # CONFIG_REISERFS_FS is not set # CONFIG_JFS_FS is not set - -# -# XFS support -# +# CONFIG_FS_POSIX_ACL is not set # CONFIG_XFS_FS is not set +# CONFIG_GFS2_FS is not set +# CONFIG_OCFS2_FS is not set # CONFIG_MINIX_FS is not set CONFIG_ROMFS_FS=y +CONFIG_INOTIFY=y +CONFIG_INOTIFY_USER=y # CONFIG_QUOTA is not set CONFIG_DNOTIFY=y # CONFIG_AUTOFS_FS is not set # CONFIG_AUTOFS4_FS is not set +# CONFIG_FUSE_FS is not set # # CD-ROM/DVD Filesystems @@ -603,16 +746,13 @@ # Pseudo filesystems # CONFIG_PROC_FS=y CONFIG_PROC_KCORE=y +CONFIG_PROC_SYSCTL=y CONFIG_SYSFS=y -CONFIG_DEVFS_FS=y -CONFIG_DEVFS_MOUNT=y -# CONFIG_DEVFS_DEBUG is not set -# CONFIG_DEVPTS_FS_XATTR is not set CONFIG_TMPFS=y -# CONFIG_TMPFS_XATTR is not set -# CONFIG_HUGETLBFS is not set +# CONFIG_TMPFS_POSIX_ACL is not set # CONFIG_HUGETLB_PAGE is not set CONFIG_RAMFS=y +# CONFIG_CONFIGFS_FS is not set # # Miscellaneous filesystems @@ -629,8 +769,9 @@ CONFIG_JFFS_FS_VERBOSE=0 CONFIG_JFFS_PROC_FS=y CONFIG_JFFS2_FS=y CONFIG_JFFS2_FS_DEBUG=0 -# CONFIG_JFFS2_FS_NAND is not set -# CONFIG_JFFS2_FS_NOR_ECC is not set +CONFIG_JFFS2_FS_WRITEBUFFER=y +# CONFIG_JFFS2_SUMMARY is not set +# CONFIG_JFFS2_FS_XATTR is not set # CONFIG_JFFS2_COMPRESSION_OPTIONS is not set CONFIG_JFFS2_ZLIB=y CONFIG_JFFS2_RTIME=y @@ -647,12 +788,14 @@ # Network File Systems # CONFIG_NFS_FS=y CONFIG_NFS_V3=y +# CONFIG_NFS_V3_ACL is not set # CONFIG_NFS_V4 is not set # CONFIG_NFS_DIRECTIO is not set # CONFIG_NFSD is not set CONFIG_ROOT_NFS=y CONFIG_LOCKD=y CONFIG_LOCKD_V4=y +CONFIG_NFS_COMMON=y CONFIG_SUNRPC=y # CONFIG_RPCSEC_GSS_KRB5 is not set # CONFIG_RPCSEC_GSS_SPKM3 is not set @@ -661,6 +804,7 @@ # CONFIG_CIFS is not set # CONFIG_NCP_FS is not set # CONFIG_CODA_FS is not set # CONFIG_AFS_FS is not set +# CONFIG_9P_FS is not set # # Partition Types @@ -721,10 +865,16 @@ # # Kernel hacking # # CONFIG_PRINTK_TIME is not set +CONFIG_ENABLE_MUST_CHECK=y +# CONFIG_MAGIC_SYSRQ is not set +# CONFIG_UNUSED_SYMBOLS is not set # CONFIG_DEBUG_KERNEL is not set CONFIG_LOG_BUF_SHIFT=15 # CONFIG_DEBUG_BUGVERBOSE is not set +# CONFIG_DEBUG_FS is not set # CONFIG_FRAME_POINTER is not set +# CONFIG_UNWIND_INFO is not set +# CONFIG_HEADERS_CHECK is not set # # Security options @@ -738,13 +888,10 @@ # # CONFIG_CRYPTO is not set # -# Hardware crypto devices -# - -# # Library routines # # CONFIG_CRC_CCITT is not set +# CONFIG_CRC16 is not set CONFIG_CRC32=y # CONFIG_LIBCRC32C is not set CONFIG_ZLIB_INFLATE=y diff --git a/arch/m32r/mm/fault-nommu.c b/arch/m32r/mm/fault-nommu.c index 03fc4c8..9880aba 100644 --- a/arch/m32r/mm/fault-nommu.c +++ b/arch/m32r/mm/fault-nommu.c @@ -7,8 +7,6 @@ * Copyright (C) 1995 Linus Torvalds */ -/* $Id: fault-nommu.c,v 1.1 2004/03/30 06:40:59 sakugawa Exp $ */ - #include #include #include @@ -46,32 +44,6 @@ #define tlb_entry_i tlb_entry_i_dat[smp_ #define tlb_entry_d tlb_entry_d_dat[smp_processor_id()] #endif -/* - * Unlock any spinlocks which will prevent us from getting the - * message out - */ -void bust_spinlocks(int yes) -{ - int loglevel_save = console_loglevel; - - if (yes) { - oops_in_progress = 1; - return; - } -#ifdef CONFIG_VT - unblank_screen(); -#endif - oops_in_progress = 0; - /* - * OK, the message is on the console. Now we call printk() - * without oops_in_progress set so that printk will give klogd - * a poke. Hold onto your hats... - */ - console_loglevel = 15; /* NMI oopser may have shut the console up */ - printk(" "); - console_loglevel = loglevel_save; -} - void do_BUG(const char *file, int line) { bust_spinlocks(1); @@ -161,4 +133,3 @@ void local_flush_tlb_all(void) { BUG(); } - diff --git a/arch/m32r/mm/fault.c b/arch/m32r/mm/fault.c index 9b9feb0..037d58e 100644 --- a/arch/m32r/mm/fault.c +++ b/arch/m32r/mm/fault.c @@ -49,32 +49,6 @@ #endif extern void init_tlb(void); -/* - * Unlock any spinlocks which will prevent us from getting the - * message out - */ -void bust_spinlocks(int yes) -{ - int loglevel_save = console_loglevel; - - if (yes) { - oops_in_progress = 1; - return; - } -#ifdef CONFIG_VT - unblank_screen(); -#endif - oops_in_progress = 0; - /* - * OK, the message is on the console. Now we call printk() - * without oops_in_progress set so that printk will give klogd - * a poke. Hold onto your hats... - */ - console_loglevel = 15; /* NMI oopser may have shut the console up */ - printk(" "); - console_loglevel = loglevel_save; -} - /*======================================================================* * do_page_fault() *======================================================================* @@ -362,8 +336,10 @@ vmalloc_fault: if (!pte_present(*pte_k)) goto no_context; - addr = (address & PAGE_MASK) | (error_code & ACE_INSTRUCTION); + addr = (address & PAGE_MASK); + set_thread_fault_code(error_code); update_mmu_cache(NULL, addr, *pte_k); + set_thread_fault_code(0); return; } } @@ -377,7 +353,7 @@ #define DTLB_END (unsigned long *)(DTLB_ void update_mmu_cache(struct vm_area_struct *vma, unsigned long vaddr, pte_t pte) { - unsigned long *entry1, *entry2; + volatile unsigned long *entry1, *entry2; unsigned long pte_data, flags; unsigned int *entry_dat; int inst = get_thread_fault_code() & ACE_INSTRUCTION; @@ -391,30 +367,26 @@ void update_mmu_cache(struct vm_area_str vaddr = (vaddr & PAGE_MASK) | get_asid(); + pte_data = pte_val(pte); + #ifdef CONFIG_CHIP_OPSP entry1 = (unsigned long *)ITLB_BASE; - for(i = 0 ; i < NR_TLB_ENTRIES; i++) { - if(*entry1++ == vaddr) { - pte_data = pte_val(pte); - set_tlb_data(entry1, pte_data); - break; - } - entry1++; + for (i = 0; i < NR_TLB_ENTRIES; i++) { + if (*entry1++ == vaddr) { + set_tlb_data(entry1, pte_data); + break; + } + entry1++; } entry2 = (unsigned long *)DTLB_BASE; - for(i = 0 ; i < NR_TLB_ENTRIES ; i++) { - if(*entry2++ == vaddr) { - pte_data = pte_val(pte); - set_tlb_data(entry2, pte_data); - break; - } - entry2++; + for (i = 0; i < NR_TLB_ENTRIES; i++) { + if (*entry2++ == vaddr) { + set_tlb_data(entry2, pte_data); + break; + } + entry2++; } - local_irq_restore(flags); - return; #else - pte_data = pte_val(pte); - /* * Update TLB entries * entry1: ITLB entry address @@ -439,6 +411,7 @@ #else "i" (MSVA_offset), "i" (MTOP_offset), "i" (MIDXI_offset) : "r4", "memory" ); +#endif if ((!inst && entry2 >= DTLB_END) || (inst && entry1 >= ITLB_END)) goto notfound; @@ -482,7 +455,6 @@ notfound: set_tlb_data(entry1, pte_data); goto found; -#endif } /*======================================================================* diff --git a/arch/m32r/mm/mmu.S b/arch/m32r/mm/mmu.S index 9a4d40b..8bb74b1 100644 --- a/arch/m32r/mm/mmu.S +++ b/arch/m32r/mm/mmu.S @@ -4,8 +4,6 @@ * Copyright (C) 2001 by Hiroyuki Kondo */ -/* $Id: mmu.S,v 1.15 2004/03/16 02:56:27 takata Exp $ */ - #include #include #include @@ -345,5 +343,4 @@ ENTRY(m32r_otlb_entrys) #endif /* CONFIG_MMU */ -.end - + .end diff --git a/arch/m32r/oaks32r/defconfig.nommu b/arch/m32r/oaks32r/defconfig.nommu index 3f9fe51..aaa0082 100644 --- a/arch/m32r/oaks32r/defconfig.nommu +++ b/arch/m32r/oaks32r/defconfig.nommu @@ -1,19 +1,18 @@ # # Automatically generated make config: don't edit -# Linux kernel version: 2.6.12-rc5 -# Fri Jun 3 16:22:04 2005 +# Linux kernel version: 2.6.19 +# Tue Dec 12 12:09:17 2006 # CONFIG_M32R=y -# CONFIG_UID16 is not set CONFIG_GENERIC_ISA_DMA=y CONFIG_GENERIC_HARDIRQS=y CONFIG_GENERIC_IRQ_PROBE=y +CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config" # # Code maturity level options # CONFIG_EXPERIMENTAL=y -CONFIG_CLEAN_COMPILE=y CONFIG_BROKEN_ON_SMP=y CONFIG_LOCK_KERNEL=y CONFIG_INIT_ENV_ARG_LIMIT=32 @@ -22,28 +21,35 @@ # # General setup # CONFIG_LOCALVERSION="" +CONFIG_LOCALVERSION_AUTO=y +# CONFIG_SYSVIPC is not set # CONFIG_POSIX_MQUEUE is not set CONFIG_BSD_PROCESS_ACCT=y # CONFIG_BSD_PROCESS_ACCT_V3 is not set -CONFIG_SYSCTL=y +# CONFIG_TASKSTATS is not set +# CONFIG_UTS_NS is not set # CONFIG_AUDIT is not set -CONFIG_HOTPLUG=y -CONFIG_KOBJECT_UEVENT=y # CONFIG_IKCONFIG is not set +CONFIG_SYSFS_DEPRECATED=y +# CONFIG_RELAY is not set +CONFIG_INITRAMFS_SOURCE="" +# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set +CONFIG_SYSCTL=y CONFIG_EMBEDDED=y +CONFIG_SYSCTL_SYSCALL=y # CONFIG_KALLSYMS is not set +CONFIG_HOTPLUG=y CONFIG_PRINTK=y CONFIG_BUG=y +CONFIG_ELF_CORE=y CONFIG_BASE_FULL=y # CONFIG_FUTEX is not set # CONFIG_EPOLL is not set -# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set -CONFIG_CC_ALIGN_FUNCTIONS=0 -CONFIG_CC_ALIGN_LABELS=0 -CONFIG_CC_ALIGN_LOOPS=0 -CONFIG_CC_ALIGN_JUMPS=0 +CONFIG_SLAB=y +CONFIG_VM_EVENT_COUNTERS=y CONFIG_TINY_SHMEM=y CONFIG_BASE_SMALL=0 +# CONFIG_SLOB is not set # # Loadable module support @@ -51,12 +57,30 @@ # CONFIG_MODULES=y CONFIG_MODULE_UNLOAD=y # CONFIG_MODULE_FORCE_UNLOAD is not set -CONFIG_OBSOLETE_MODPARM=y # CONFIG_MODVERSIONS is not set # CONFIG_MODULE_SRCVERSION_ALL is not set CONFIG_KMOD=y # +# Block layer +# +CONFIG_BLOCK=y +# CONFIG_BLK_DEV_IO_TRACE is not set + +# +# IO Schedulers +# +CONFIG_IOSCHED_NOOP=y +# CONFIG_IOSCHED_AS is not set +CONFIG_IOSCHED_DEADLINE=y +CONFIG_IOSCHED_CFQ=y +# CONFIG_DEFAULT_AS is not set +# CONFIG_DEFAULT_DEADLINE is not set +CONFIG_DEFAULT_CFQ=y +# CONFIG_DEFAULT_NOOP is not set +CONFIG_DEFAULT_IOSCHED="cfq" + +# # Processor type and features # # CONFIG_PLAT_MAPPI is not set @@ -66,8 +90,10 @@ # CONFIG_PLAT_OPSPUT is not set CONFIG_PLAT_OAKS32R=y # CONFIG_PLAT_MAPPI2 is not set # CONFIG_PLAT_MAPPI3 is not set +# CONFIG_PLAT_M32104UT is not set # CONFIG_CHIP_M32700 is not set CONFIG_CHIP_M32102=y +# CONFIG_CHIP_M32104 is not set # CONFIG_CHIP_VDEC2 is not set # CONFIG_CHIP_OPSP is not set CONFIG_ISA_M32R=y @@ -77,18 +103,31 @@ # CONFIG_CPU_LITTLE_ENDIAN is not set CONFIG_MEMORY_START=0x01000000 CONFIG_MEMORY_SIZE=0x00800000 CONFIG_NOHIGHMEM=y -# CONFIG_DISCONTIGMEM is not set +CONFIG_ARCH_DISCONTIGMEM_ENABLE=y +CONFIG_SELECT_MEMORY_MODEL=y +# CONFIG_FLATMEM_MANUAL is not set +CONFIG_DISCONTIGMEM_MANUAL=y +# CONFIG_SPARSEMEM_MANUAL is not set +CONFIG_DISCONTIGMEM=y +CONFIG_FLAT_NODE_MEM_MAP=y +CONFIG_NEED_MULTIPLE_NODES=y +# CONFIG_SPARSEMEM_STATIC is not set +CONFIG_SPLIT_PTLOCK_CPUS=4 +# CONFIG_RESOURCES_64BIT is not set +CONFIG_IRAM_START=0x00f00000 +CONFIG_IRAM_SIZE=0x00010000 CONFIG_RWSEM_GENERIC_SPINLOCK=y # CONFIG_RWSEM_XCHGADD_ALGORITHM is not set +CONFIG_GENERIC_FIND_NEXT_BIT=y +CONFIG_GENERIC_HWEIGHT=y CONFIG_GENERIC_CALIBRATE_DELAY=y CONFIG_PREEMPT=y -# CONFIG_HAVE_DEC_LOCK is not set # CONFIG_SMP is not set +CONFIG_NODES_SHIFT=1 # # Bus options (PCI, PCMCIA, EISA, MCA, ISA) # -# CONFIG_PCI is not set # CONFIG_ISA is not set # @@ -109,6 +148,94 @@ # CONFIG_BINFMT_SHARED_FLAT is not set # CONFIG_BINFMT_MISC is not set # +# Networking +# +CONFIG_NET=y + +# +# Networking options +# +# CONFIG_NETDEBUG is not set +CONFIG_PACKET=y +# CONFIG_PACKET_MMAP is not set +CONFIG_UNIX=y +CONFIG_XFRM=y +# CONFIG_XFRM_USER is not set +# CONFIG_XFRM_SUB_POLICY is not set +# CONFIG_NET_KEY is not set +CONFIG_INET=y +# CONFIG_IP_MULTICAST is not set +# CONFIG_IP_ADVANCED_ROUTER is not set +CONFIG_IP_FIB_HASH=y +CONFIG_IP_PNP=y +CONFIG_IP_PNP_DHCP=y +# CONFIG_IP_PNP_BOOTP is not set +# CONFIG_IP_PNP_RARP is not set +# CONFIG_NET_IPIP is not set +# CONFIG_NET_IPGRE is not set +# CONFIG_ARPD is not set +# CONFIG_SYN_COOKIES is not set +# CONFIG_INET_AH is not set +# CONFIG_INET_ESP is not set +# CONFIG_INET_IPCOMP is not set +# CONFIG_INET_XFRM_TUNNEL is not set +# CONFIG_INET_TUNNEL is not set +CONFIG_INET_XFRM_MODE_TRANSPORT=y +CONFIG_INET_XFRM_MODE_TUNNEL=y +CONFIG_INET_XFRM_MODE_BEET=y +CONFIG_INET_DIAG=y +CONFIG_INET_TCP_DIAG=y +# CONFIG_TCP_CONG_ADVANCED is not set +CONFIG_TCP_CONG_CUBIC=y +CONFIG_DEFAULT_TCP_CONG="cubic" +# CONFIG_TCP_MD5SIG is not set +# CONFIG_IPV6 is not set +# CONFIG_INET6_XFRM_TUNNEL is not set +# CONFIG_INET6_TUNNEL is not set +# CONFIG_NETWORK_SECMARK is not set +# CONFIG_NETFILTER is not set + +# +# DCCP Configuration (EXPERIMENTAL) +# +# CONFIG_IP_DCCP is not set + +# +# SCTP Configuration (EXPERIMENTAL) +# +# CONFIG_IP_SCTP is not set + +# +# TIPC Configuration (EXPERIMENTAL) +# +# CONFIG_TIPC is not set +# CONFIG_ATM is not set +# CONFIG_BRIDGE is not set +# CONFIG_VLAN_8021Q is not set +# CONFIG_DECNET is not set +# CONFIG_LLC2 is not set +# CONFIG_IPX is not set +# CONFIG_ATALK is not set +# CONFIG_X25 is not set +# CONFIG_LAPB is not set +# CONFIG_ECONET is not set +# CONFIG_WAN_ROUTER is not set + +# +# QoS and/or fair queueing +# +# CONFIG_NET_SCHED is not set + +# +# Network testing +# +# CONFIG_NET_PKTGEN is not set +# CONFIG_HAMRADIO is not set +# CONFIG_IRDA is not set +# CONFIG_BT is not set +# CONFIG_IEEE80211 is not set + +# # Device Drivers # @@ -118,6 +245,12 @@ # CONFIG_STANDALONE=y CONFIG_PREVENT_FIRMWARE_BUILD=y # CONFIG_FW_LOADER is not set +# CONFIG_SYS_HYPERVISOR is not set + +# +# Connector - unified userspace <-> kernelspace linker +# +# CONFIG_CONNECTOR is not set # # Memory Technology Devices (MTD) @@ -136,7 +269,6 @@ # # # Block devices # -# CONFIG_BLK_DEV_FD is not set # CONFIG_BLK_DEV_COW_COMMON is not set CONFIG_BLK_DEV_LOOP=y # CONFIG_BLK_DEV_CRYPTOLOOP is not set @@ -144,18 +276,15 @@ CONFIG_BLK_DEV_NBD=y CONFIG_BLK_DEV_RAM=y CONFIG_BLK_DEV_RAM_COUNT=16 CONFIG_BLK_DEV_RAM_SIZE=4096 +CONFIG_BLK_DEV_RAM_BLOCKSIZE=1024 # CONFIG_BLK_DEV_INITRD is not set -CONFIG_INITRAMFS_SOURCE="" # CONFIG_CDROM_PKTCDVD is not set +# CONFIG_ATA_OVER_ETH is not set # -# IO Schedulers +# Misc devices # -CONFIG_IOSCHED_NOOP=y -# CONFIG_IOSCHED_AS is not set -CONFIG_IOSCHED_DEADLINE=y -CONFIG_IOSCHED_CFQ=y -# CONFIG_ATA_OVER_ETH is not set +# CONFIG_TIFM_CORE is not set # # ATA/ATAPI/MFM/RLL support @@ -165,7 +294,13 @@ # CONFIG_IDE is not set # # SCSI device support # +# CONFIG_RAID_ATTRS is not set # CONFIG_SCSI is not set +# CONFIG_SCSI_NETLINK is not set + +# +# Serial ATA (prod) and Parallel ATA (experimental) drivers +# # # Multi-device support (RAID and LVM) @@ -175,6 +310,7 @@ # CONFIG_MD is not set # # Fusion MPT device support # +# CONFIG_FUSION is not set # # IEEE 1394 (FireWire) support @@ -185,69 +321,8 @@ # I2O device support # # -# Networking support -# -CONFIG_NET=y - -# -# Networking options -# -CONFIG_PACKET=y -# CONFIG_PACKET_MMAP is not set -CONFIG_UNIX=y -# CONFIG_NET_KEY is not set -CONFIG_INET=y -# CONFIG_IP_MULTICAST is not set -# CONFIG_IP_ADVANCED_ROUTER is not set -CONFIG_IP_PNP=y -CONFIG_IP_PNP_DHCP=y -# CONFIG_IP_PNP_BOOTP is not set -# CONFIG_IP_PNP_RARP is not set -# CONFIG_NET_IPIP is not set -# CONFIG_NET_IPGRE is not set -# CONFIG_ARPD is not set -# CONFIG_SYN_COOKIES is not set -# CONFIG_INET_AH is not set -# CONFIG_INET_ESP is not set -# CONFIG_INET_IPCOMP is not set -# CONFIG_INET_TUNNEL is not set -CONFIG_IP_TCPDIAG=y -# CONFIG_IP_TCPDIAG_IPV6 is not set -# CONFIG_IPV6 is not set -# CONFIG_NETFILTER is not set - -# -# SCTP Configuration (EXPERIMENTAL) -# -# CONFIG_IP_SCTP is not set -# CONFIG_ATM is not set -# CONFIG_BRIDGE is not set -# CONFIG_VLAN_8021Q is not set -# CONFIG_DECNET is not set -# CONFIG_LLC2 is not set -# CONFIG_IPX is not set -# CONFIG_ATALK is not set -# CONFIG_X25 is not set -# CONFIG_LAPB is not set -# CONFIG_NET_DIVERT is not set -# CONFIG_ECONET is not set -# CONFIG_WAN_ROUTER is not set - -# -# QoS and/or fair queueing -# -# CONFIG_NET_SCHED is not set -# CONFIG_NET_CLS_ROUTE is not set - -# -# Network testing +# Network device support # -# CONFIG_NET_PKTGEN is not set -# CONFIG_NETPOLL is not set -# CONFIG_NET_POLL_CONTROLLER is not set -# CONFIG_HAMRADIO is not set -# CONFIG_IRDA is not set -# CONFIG_BT is not set CONFIG_NETDEVICES=y # CONFIG_DUMMY is not set # CONFIG_BONDING is not set @@ -255,6 +330,10 @@ # CONFIG_EQUALIZER is not set # CONFIG_TUN is not set # +# PHY device support +# + +# # Ethernet (10 or 100Mbit) # # CONFIG_NET_ETHERNET is not set @@ -285,6 +364,8 @@ # CONFIG_PPP is not set # CONFIG_SLIP is not set # CONFIG_SHAPER is not set # CONFIG_NETCONSOLE is not set +# CONFIG_NETPOLL is not set +# CONFIG_NET_POLL_CONTROLLER is not set # # ISDN subsystem @@ -300,6 +381,7 @@ # # Input device support # CONFIG_INPUT=y +# CONFIG_INPUT_FF_MEMLESS is not set # # Userland interfaces @@ -328,7 +410,6 @@ CONFIG_SERIO_SERPORT=y # CONFIG_SERIO_LIBPS2 is not set # CONFIG_SERIO_RAW is not set # CONFIG_GAMEPORT is not set -CONFIG_SOUND_GAMEPORT=y # # Character devices @@ -348,7 +429,6 @@ CONFIG_SERIAL_CORE=y CONFIG_SERIAL_CORE_CONSOLE=y CONFIG_SERIAL_M32R_SIO=y CONFIG_SERIAL_M32R_SIO_CONSOLE=y -# CONFIG_SERIAL_M32R_PLDSIO is not set CONFIG_UNIX98_PTYS=y CONFIG_LEGACY_PTYS=y CONFIG_LEGACY_PTY_COUNT=256 @@ -362,20 +442,20 @@ # # Watchdog Cards # # CONFIG_WATCHDOG is not set +CONFIG_HW_RANDOM=y # CONFIG_RTC is not set -# CONFIG_GEN_RTC is not set # CONFIG_DTLK is not set # CONFIG_R3964 is not set # # Ftape, the floppy tape device driver # -# CONFIG_DRM is not set # CONFIG_RAW_DRIVER is not set # # TPM devices # +# CONFIG_TCG_TPM is not set # # I2C support @@ -383,13 +463,25 @@ # # CONFIG_I2C is not set # +# SPI support +# +# CONFIG_SPI is not set +# CONFIG_SPI_MASTER is not set + +# # Dallas's 1-wire bus # # CONFIG_W1 is not set # -# Misc devices +# Hardware Monitoring support # +CONFIG_HWMON=y +# CONFIG_HWMON_VID is not set +# CONFIG_SENSORS_ABITUGURU is not set +# CONFIG_SENSORS_F71805F is not set +# CONFIG_SENSORS_VT1211 is not set +# CONFIG_HWMON_DEBUG_CHIP is not set # # Multimedia devices @@ -404,7 +496,9 @@ # CONFIG_DVB is not set # # Graphics support # +CONFIG_FIRMWARE_EDID=y # CONFIG_FB is not set +# CONFIG_BACKLIGHT_LCD_SUPPORT is not set # # Sound @@ -416,6 +510,11 @@ # USB support # # CONFIG_USB_ARCH_HAS_HCD is not set # CONFIG_USB_ARCH_HAS_OHCI is not set +# CONFIG_USB_ARCH_HAS_EHCI is not set + +# +# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support' +# # # USB Gadget Support @@ -428,9 +527,43 @@ # # CONFIG_MMC is not set # +# LED devices +# +# CONFIG_NEW_LEDS is not set + +# +# LED drivers +# + +# +# LED Triggers +# + +# # InfiniBand support # -# CONFIG_INFINIBAND is not set + +# +# EDAC - error detection and reporting (RAS) (EXPERIMENTAL) +# + +# +# Real Time Clock +# +# CONFIG_RTC_CLASS is not set + +# +# DMA Engine support +# +# CONFIG_DMA_ENGINE is not set + +# +# DMA Clients +# + +# +# DMA Devices +# # # File systems @@ -438,20 +571,22 @@ # CONFIG_EXT2_FS=y # CONFIG_EXT2_FS_XATTR is not set # CONFIG_EXT3_FS is not set -# CONFIG_JBD is not set +# CONFIG_EXT4DEV_FS is not set # CONFIG_REISERFS_FS is not set # CONFIG_JFS_FS is not set - -# -# XFS support -# +# CONFIG_FS_POSIX_ACL is not set # CONFIG_XFS_FS is not set +# CONFIG_GFS2_FS is not set +# CONFIG_OCFS2_FS is not set # CONFIG_MINIX_FS is not set # CONFIG_ROMFS_FS is not set +CONFIG_INOTIFY=y +CONFIG_INOTIFY_USER=y # CONFIG_QUOTA is not set CONFIG_DNOTIFY=y # CONFIG_AUTOFS_FS is not set # CONFIG_AUTOFS4_FS is not set +# CONFIG_FUSE_FS is not set # # CD-ROM/DVD Filesystems @@ -470,13 +605,12 @@ # # Pseudo filesystems # CONFIG_PROC_FS=y +CONFIG_PROC_SYSCTL=y CONFIG_SYSFS=y -# CONFIG_DEVFS_FS is not set -CONFIG_DEVPTS_FS_XATTR=y -CONFIG_DEVPTS_FS_SECURITY=y # CONFIG_TMPFS is not set # CONFIG_HUGETLB_PAGE is not set CONFIG_RAMFS=y +# CONFIG_CONFIGFS_FS is not set # # Miscellaneous filesystems @@ -500,12 +634,14 @@ # Network File Systems # CONFIG_NFS_FS=y CONFIG_NFS_V3=y +# CONFIG_NFS_V3_ACL is not set # CONFIG_NFS_V4 is not set # CONFIG_NFS_DIRECTIO is not set # CONFIG_NFSD is not set CONFIG_ROOT_NFS=y CONFIG_LOCKD=y CONFIG_LOCKD_V4=y +CONFIG_NFS_COMMON=y CONFIG_SUNRPC=y # CONFIG_RPCSEC_GSS_KRB5 is not set # CONFIG_RPCSEC_GSS_SPKM3 is not set @@ -514,6 +650,7 @@ # CONFIG_CIFS is not set # CONFIG_NCP_FS is not set # CONFIG_CODA_FS is not set # CONFIG_AFS_FS is not set +# CONFIG_9P_FS is not set # # Partition Types @@ -574,10 +711,16 @@ # # Kernel hacking # # CONFIG_PRINTK_TIME is not set +CONFIG_ENABLE_MUST_CHECK=y +# CONFIG_MAGIC_SYSRQ is not set +# CONFIG_UNUSED_SYMBOLS is not set # CONFIG_DEBUG_KERNEL is not set CONFIG_LOG_BUF_SHIFT=14 # CONFIG_DEBUG_BUGVERBOSE is not set +# CONFIG_DEBUG_FS is not set # CONFIG_FRAME_POINTER is not set +# CONFIG_UNWIND_INFO is not set +# CONFIG_HEADERS_CHECK is not set # # Security options @@ -591,12 +734,9 @@ # # CONFIG_CRYPTO is not set # -# Hardware crypto devices -# - -# # Library routines # # CONFIG_CRC_CCITT is not set +# CONFIG_CRC16 is not set CONFIG_CRC32=y # CONFIG_LIBCRC32C is not set diff --git a/arch/m32r/opsput/defconfig.opsput b/arch/m32r/opsput/defconfig.opsput index 66adec6..461f95e 100644 --- a/arch/m32r/opsput/defconfig.opsput +++ b/arch/m32r/opsput/defconfig.opsput @@ -1,19 +1,18 @@ # # Automatically generated make config: don't edit -# Linux kernel version: 2.6.12-rc5 -# Fri Jun 3 16:22:06 2005 +# Linux kernel version: 2.6.19 +# Wed Dec 13 18:34:36 2006 # CONFIG_M32R=y -# CONFIG_UID16 is not set CONFIG_GENERIC_ISA_DMA=y CONFIG_GENERIC_HARDIRQS=y CONFIG_GENERIC_IRQ_PROBE=y +CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config" # # Code maturity level options # CONFIG_EXPERIMENTAL=y -CONFIG_CLEAN_COMPILE=y CONFIG_BROKEN_ON_SMP=y CONFIG_INIT_ENV_ARG_LIMIT=32 @@ -21,32 +20,39 @@ # # General setup # CONFIG_LOCALVERSION="" +CONFIG_LOCALVERSION_AUTO=y CONFIG_SWAP=y CONFIG_SYSVIPC=y +# CONFIG_IPC_NS is not set # CONFIG_POSIX_MQUEUE is not set CONFIG_BSD_PROCESS_ACCT=y # CONFIG_BSD_PROCESS_ACCT_V3 is not set -CONFIG_SYSCTL=y +# CONFIG_TASKSTATS is not set +# CONFIG_UTS_NS is not set # CONFIG_AUDIT is not set -CONFIG_HOTPLUG=y -CONFIG_KOBJECT_UEVENT=y CONFIG_IKCONFIG=y # CONFIG_IKCONFIG_PROC is not set +CONFIG_SYSFS_DEPRECATED=y +# CONFIG_RELAY is not set +CONFIG_INITRAMFS_SOURCE="" +# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set +CONFIG_SYSCTL=y CONFIG_EMBEDDED=y +CONFIG_SYSCTL_SYSCALL=y # CONFIG_KALLSYMS is not set +CONFIG_HOTPLUG=y CONFIG_PRINTK=y CONFIG_BUG=y +CONFIG_ELF_CORE=y CONFIG_BASE_FULL=y # CONFIG_FUTEX is not set # CONFIG_EPOLL is not set -# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set CONFIG_SHMEM=y -CONFIG_CC_ALIGN_FUNCTIONS=0 -CONFIG_CC_ALIGN_LABELS=0 -CONFIG_CC_ALIGN_LOOPS=0 -CONFIG_CC_ALIGN_JUMPS=0 +CONFIG_SLAB=y +CONFIG_VM_EVENT_COUNTERS=y # CONFIG_TINY_SHMEM is not set CONFIG_BASE_SMALL=0 +# CONFIG_SLOB is not set # # Loadable module support @@ -54,12 +60,30 @@ # CONFIG_MODULES=y CONFIG_MODULE_UNLOAD=y # CONFIG_MODULE_FORCE_UNLOAD is not set -CONFIG_OBSOLETE_MODPARM=y # CONFIG_MODVERSIONS is not set # CONFIG_MODULE_SRCVERSION_ALL is not set CONFIG_KMOD=y # +# Block layer +# +CONFIG_BLOCK=y +# CONFIG_BLK_DEV_IO_TRACE is not set + +# +# IO Schedulers +# +CONFIG_IOSCHED_NOOP=y +# CONFIG_IOSCHED_AS is not set +CONFIG_IOSCHED_DEADLINE=y +CONFIG_IOSCHED_CFQ=y +# CONFIG_DEFAULT_AS is not set +# CONFIG_DEFAULT_DEADLINE is not set +CONFIG_DEFAULT_CFQ=y +# CONFIG_DEFAULT_NOOP is not set +CONFIG_DEFAULT_IOSCHED="cfq" + +# # Processor type and features # # CONFIG_PLAT_MAPPI is not set @@ -69,8 +93,10 @@ CONFIG_PLAT_OPSPUT=y # CONFIG_PLAT_OAKS32R is not set # CONFIG_PLAT_MAPPI2 is not set # CONFIG_PLAT_MAPPI3 is not set +# CONFIG_PLAT_M32104UT is not set # CONFIG_CHIP_M32700 is not set # CONFIG_CHIP_M32102 is not set +# CONFIG_CHIP_M32104 is not set # CONFIG_CHIP_VDEC2 is not set CONFIG_CHIP_OPSP=y CONFIG_MMU=y @@ -84,17 +110,31 @@ # CONFIG_CPU_LITTLE_ENDIAN is not set CONFIG_MEMORY_START=0x08000000 CONFIG_MEMORY_SIZE=0x01000000 CONFIG_NOHIGHMEM=y -# CONFIG_DISCONTIGMEM is not set +CONFIG_ARCH_DISCONTIGMEM_ENABLE=y +CONFIG_SELECT_MEMORY_MODEL=y +# CONFIG_FLATMEM_MANUAL is not set +CONFIG_DISCONTIGMEM_MANUAL=y +# CONFIG_SPARSEMEM_MANUAL is not set +CONFIG_DISCONTIGMEM=y +CONFIG_FLAT_NODE_MEM_MAP=y +CONFIG_NEED_MULTIPLE_NODES=y +# CONFIG_SPARSEMEM_STATIC is not set +CONFIG_SPLIT_PTLOCK_CPUS=4 +# CONFIG_RESOURCES_64BIT is not set +CONFIG_IRAM_START=0x00f00000 +CONFIG_IRAM_SIZE=0x00010000 CONFIG_RWSEM_GENERIC_SPINLOCK=y # CONFIG_RWSEM_XCHGADD_ALGORITHM is not set +CONFIG_GENERIC_FIND_NEXT_BIT=y +CONFIG_GENERIC_HWEIGHT=y CONFIG_GENERIC_CALIBRATE_DELAY=y # CONFIG_PREEMPT is not set # CONFIG_SMP is not set +CONFIG_NODES_SHIFT=1 # # Bus options (PCI, PCMCIA, EISA, MCA, ISA) # -# CONFIG_PCI is not set # CONFIG_ISA is not set # @@ -103,13 +143,15 @@ # CONFIG_PCCARD=y # CONFIG_PCMCIA_DEBUG is not set CONFIG_PCMCIA=y +CONFIG_PCMCIA_LOAD_CIS=y +CONFIG_PCMCIA_IOCTL=y # # PC-card bridges # -# CONFIG_TCIC is not set CONFIG_M32R_CFC=y CONFIG_M32R_CFC_NUM=1 +CONFIG_PCCARD_NONSTATIC=y # # PCI Hotplug Support @@ -122,6 +164,94 @@ CONFIG_BINFMT_ELF=y # CONFIG_BINFMT_MISC is not set # +# Networking +# +CONFIG_NET=y + +# +# Networking options +# +# CONFIG_NETDEBUG is not set +CONFIG_PACKET=y +# CONFIG_PACKET_MMAP is not set +CONFIG_UNIX=y +CONFIG_XFRM=y +# CONFIG_XFRM_USER is not set +# CONFIG_XFRM_SUB_POLICY is not set +# CONFIG_NET_KEY is not set +CONFIG_INET=y +# CONFIG_IP_MULTICAST is not set +# CONFIG_IP_ADVANCED_ROUTER is not set +CONFIG_IP_FIB_HASH=y +CONFIG_IP_PNP=y +CONFIG_IP_PNP_DHCP=y +# CONFIG_IP_PNP_BOOTP is not set +# CONFIG_IP_PNP_RARP is not set +# CONFIG_NET_IPIP is not set +# CONFIG_NET_IPGRE is not set +# CONFIG_ARPD is not set +# CONFIG_SYN_COOKIES is not set +# CONFIG_INET_AH is not set +# CONFIG_INET_ESP is not set +# CONFIG_INET_IPCOMP is not set +# CONFIG_INET_XFRM_TUNNEL is not set +# CONFIG_INET_TUNNEL is not set +CONFIG_INET_XFRM_MODE_TRANSPORT=y +CONFIG_INET_XFRM_MODE_TUNNEL=y +CONFIG_INET_XFRM_MODE_BEET=y +CONFIG_INET_DIAG=y +CONFIG_INET_TCP_DIAG=y +# CONFIG_TCP_CONG_ADVANCED is not set +CONFIG_TCP_CONG_CUBIC=y +CONFIG_DEFAULT_TCP_CONG="cubic" +# CONFIG_TCP_MD5SIG is not set +# CONFIG_IPV6 is not set +# CONFIG_INET6_XFRM_TUNNEL is not set +# CONFIG_INET6_TUNNEL is not set +# CONFIG_NETWORK_SECMARK is not set +# CONFIG_NETFILTER is not set + +# +# DCCP Configuration (EXPERIMENTAL) +# +# CONFIG_IP_DCCP is not set + +# +# SCTP Configuration (EXPERIMENTAL) +# +# CONFIG_IP_SCTP is not set + +# +# TIPC Configuration (EXPERIMENTAL) +# +# CONFIG_TIPC is not set +# CONFIG_ATM is not set +# CONFIG_BRIDGE is not set +# CONFIG_VLAN_8021Q is not set +# CONFIG_DECNET is not set +# CONFIG_LLC2 is not set +# CONFIG_IPX is not set +# CONFIG_ATALK is not set +# CONFIG_X25 is not set +# CONFIG_LAPB is not set +# CONFIG_ECONET is not set +# CONFIG_WAN_ROUTER is not set + +# +# QoS and/or fair queueing +# +# CONFIG_NET_SCHED is not set + +# +# Network testing +# +# CONFIG_NET_PKTGEN is not set +# CONFIG_HAMRADIO is not set +# CONFIG_IRDA is not set +# CONFIG_BT is not set +# CONFIG_IEEE80211 is not set + +# # Device Drivers # @@ -130,8 +260,14 @@ # Generic Driver Options # CONFIG_STANDALONE=y CONFIG_PREVENT_FIRMWARE_BUILD=y -# CONFIG_FW_LOADER is not set +CONFIG_FW_LOADER=y # CONFIG_DEBUG_DRIVER is not set +# CONFIG_SYS_HYPERVISOR is not set + +# +# Connector - unified userspace <-> kernelspace linker +# +# CONFIG_CONNECTOR is not set # # Memory Technology Devices (MTD) @@ -150,7 +286,6 @@ # # # Block devices # -# CONFIG_BLK_DEV_FD is not set # CONFIG_BLK_DEV_COW_COMMON is not set CONFIG_BLK_DEV_LOOP=y # CONFIG_BLK_DEV_CRYPTOLOOP is not set @@ -158,18 +293,15 @@ # CONFIG_BLK_DEV_NBD is not set CONFIG_BLK_DEV_RAM=y CONFIG_BLK_DEV_RAM_COUNT=16 CONFIG_BLK_DEV_RAM_SIZE=4096 +CONFIG_BLK_DEV_RAM_BLOCKSIZE=1024 # CONFIG_BLK_DEV_INITRD is not set -CONFIG_INITRAMFS_SOURCE="" # CONFIG_CDROM_PKTCDVD is not set +# CONFIG_ATA_OVER_ETH is not set # -# IO Schedulers +# Misc devices # -CONFIG_IOSCHED_NOOP=y -# CONFIG_IOSCHED_AS is not set -CONFIG_IOSCHED_DEADLINE=y -CONFIG_IOSCHED_CFQ=y -# CONFIG_ATA_OVER_ETH is not set +# CONFIG_TIFM_CORE is not set # # ATA/ATAPI/MFM/RLL support @@ -179,7 +311,9 @@ # CONFIG_IDE is not set # # SCSI device support # +# CONFIG_RAID_ATTRS is not set CONFIG_SCSI=m +# CONFIG_SCSI_NETLINK is not set CONFIG_SCSI_PROC_FS=y # @@ -191,6 +325,7 @@ # CONFIG_CHR_DEV_OSST is not set CONFIG_BLK_DEV_SR=m # CONFIG_BLK_DEV_SR_VENDOR is not set CONFIG_CHR_DEV_SG=m +# CONFIG_CHR_DEV_SCH is not set # # Some SCSI devices (e.g. CD jukebox) support multiple LUNs @@ -200,16 +335,18 @@ # CONFIG_SCSI_CONSTANTS is not set # CONFIG_SCSI_LOGGING is not set # -# SCSI Transport Attributes +# SCSI Transports # # CONFIG_SCSI_SPI_ATTRS is not set # CONFIG_SCSI_FC_ATTRS is not set # CONFIG_SCSI_ISCSI_ATTRS is not set +# CONFIG_SCSI_SAS_ATTRS is not set +# CONFIG_SCSI_SAS_LIBSAS is not set # # SCSI low-level drivers # -# CONFIG_SCSI_SATA is not set +# CONFIG_ISCSI_TCP is not set # CONFIG_SCSI_DEBUG is not set # @@ -222,6 +359,10 @@ # CONFIG_PCMCIA_QLOGIC is not set # CONFIG_PCMCIA_SYM53C500 is not set # +# Serial ATA (prod) and Parallel ATA (experimental) drivers +# + +# # Multi-device support (RAID and LVM) # # CONFIG_MD is not set @@ -229,6 +370,7 @@ # CONFIG_MD is not set # # Fusion MPT device support # +# CONFIG_FUSION is not set # # IEEE 1394 (FireWire) support @@ -239,69 +381,8 @@ # I2O device support # # -# Networking support -# -CONFIG_NET=y - -# -# Networking options -# -CONFIG_PACKET=y -# CONFIG_PACKET_MMAP is not set -CONFIG_UNIX=y -# CONFIG_NET_KEY is not set -CONFIG_INET=y -# CONFIG_IP_MULTICAST is not set -# CONFIG_IP_ADVANCED_ROUTER is not set -CONFIG_IP_PNP=y -CONFIG_IP_PNP_DHCP=y -# CONFIG_IP_PNP_BOOTP is not set -# CONFIG_IP_PNP_RARP is not set -# CONFIG_NET_IPIP is not set -# CONFIG_NET_IPGRE is not set -# CONFIG_ARPD is not set -# CONFIG_SYN_COOKIES is not set -# CONFIG_INET_AH is not set -# CONFIG_INET_ESP is not set -# CONFIG_INET_IPCOMP is not set -# CONFIG_INET_TUNNEL is not set -CONFIG_IP_TCPDIAG=y -# CONFIG_IP_TCPDIAG_IPV6 is not set -# CONFIG_IPV6 is not set -# CONFIG_NETFILTER is not set - -# -# SCTP Configuration (EXPERIMENTAL) +# Network device support # -# CONFIG_IP_SCTP is not set -# CONFIG_ATM is not set -# CONFIG_BRIDGE is not set -# CONFIG_VLAN_8021Q is not set -# CONFIG_DECNET is not set -# CONFIG_LLC2 is not set -# CONFIG_IPX is not set -# CONFIG_ATALK is not set -# CONFIG_X25 is not set -# CONFIG_LAPB is not set -# CONFIG_NET_DIVERT is not set -# CONFIG_ECONET is not set -# CONFIG_WAN_ROUTER is not set - -# -# QoS and/or fair queueing -# -# CONFIG_NET_SCHED is not set -# CONFIG_NET_CLS_ROUTE is not set - -# -# Network testing -# -# CONFIG_NET_PKTGEN is not set -# CONFIG_NETPOLL is not set -# CONFIG_NET_POLL_CONTROLLER is not set -# CONFIG_HAMRADIO is not set -# CONFIG_IRDA is not set -# CONFIG_BT is not set CONFIG_NETDEVICES=y # CONFIG_DUMMY is not set # CONFIG_BONDING is not set @@ -309,6 +390,11 @@ # CONFIG_EQUALIZER is not set # CONFIG_TUN is not set # +# PHY device support +# +# CONFIG_PHYLIB is not set + +# # Ethernet (10 or 100Mbit) # CONFIG_NET_ETHERNET=y @@ -346,6 +432,8 @@ # CONFIG_PPP is not set # CONFIG_SLIP is not set # CONFIG_SHAPER is not set # CONFIG_NETCONSOLE is not set +# CONFIG_NETPOLL is not set +# CONFIG_NET_POLL_CONTROLLER is not set # # ISDN subsystem @@ -361,6 +449,7 @@ # # Input device support # CONFIG_INPUT=y +# CONFIG_INPUT_FF_MEMLESS is not set # # Userland interfaces @@ -389,7 +478,6 @@ CONFIG_SERIO_SERPORT=y # CONFIG_SERIO_LIBPS2 is not set # CONFIG_SERIO_RAW is not set # CONFIG_GAMEPORT is not set -CONFIG_SOUND_GAMEPORT=y # # Character devices @@ -423,8 +511,8 @@ # # Watchdog Cards # # CONFIG_WATCHDOG is not set +CONFIG_HW_RANDOM=y # CONFIG_RTC is not set -# CONFIG_GEN_RTC is not set CONFIG_DS1302=y # CONFIG_DTLK is not set # CONFIG_R3964 is not set @@ -432,17 +520,19 @@ # CONFIG_R3964 is not set # # Ftape, the floppy tape device driver # -# CONFIG_DRM is not set # # PCMCIA character devices # # CONFIG_SYNCLINK_CS is not set +# CONFIG_CARDMAN_4000 is not set +# CONFIG_CARDMAN_4040 is not set # CONFIG_RAW_DRIVER is not set # # TPM devices # +# CONFIG_TCG_TPM is not set # # I2C support @@ -450,13 +540,25 @@ # # CONFIG_I2C is not set # +# SPI support +# +# CONFIG_SPI is not set +# CONFIG_SPI_MASTER is not set + +# # Dallas's 1-wire bus # # CONFIG_W1 is not set # -# Misc devices +# Hardware Monitoring support # +CONFIG_HWMON=y +# CONFIG_HWMON_VID is not set +# CONFIG_SENSORS_ABITUGURU is not set +# CONFIG_SENSORS_F71805F is not set +# CONFIG_SENSORS_VT1211 is not set +# CONFIG_HWMON_DEBUG_CHIP is not set # # Multimedia devices @@ -471,7 +573,9 @@ # CONFIG_DVB is not set # # Graphics support # +CONFIG_FIRMWARE_EDID=y # CONFIG_FB is not set +# CONFIG_BACKLIGHT_LCD_SUPPORT is not set # # Sound @@ -483,6 +587,11 @@ # USB support # # CONFIG_USB_ARCH_HAS_HCD is not set # CONFIG_USB_ARCH_HAS_OHCI is not set +# CONFIG_USB_ARCH_HAS_EHCI is not set + +# +# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support' +# # # USB Gadget Support @@ -495,38 +604,73 @@ # # CONFIG_MMC is not set # +# LED devices +# +# CONFIG_NEW_LEDS is not set + +# +# LED drivers +# + +# +# LED Triggers +# + +# # InfiniBand support # -# CONFIG_INFINIBAND is not set + +# +# EDAC - error detection and reporting (RAS) (EXPERIMENTAL) +# + +# +# Real Time Clock +# +# CONFIG_RTC_CLASS is not set + +# +# DMA Engine support +# +# CONFIG_DMA_ENGINE is not set + +# +# DMA Clients +# + +# +# DMA Devices +# # # File systems # CONFIG_EXT2_FS=y # CONFIG_EXT2_FS_XATTR is not set -CONFIG_EXT3_FS=m +# CONFIG_EXT2_FS_XIP is not set +CONFIG_EXT3_FS=y CONFIG_EXT3_FS_XATTR=y # CONFIG_EXT3_FS_POSIX_ACL is not set # CONFIG_EXT3_FS_SECURITY is not set -CONFIG_JBD=m +# CONFIG_EXT4DEV_FS is not set +CONFIG_JBD=y CONFIG_JBD_DEBUG=y CONFIG_FS_MBCACHE=y -CONFIG_REISERFS_FS=m -# CONFIG_REISERFS_CHECK is not set -# CONFIG_REISERFS_PROC_INFO is not set -# CONFIG_REISERFS_FS_XATTR is not set +# CONFIG_REISERFS_FS is not set # CONFIG_JFS_FS is not set - -# -# XFS support -# +# CONFIG_FS_POSIX_ACL is not set # CONFIG_XFS_FS is not set +# CONFIG_GFS2_FS is not set +# CONFIG_OCFS2_FS is not set # CONFIG_MINIX_FS is not set # CONFIG_ROMFS_FS is not set +CONFIG_INOTIFY=y +CONFIG_INOTIFY_USER=y # CONFIG_QUOTA is not set CONFIG_DNOTIFY=y # CONFIG_AUTOFS_FS is not set # CONFIG_AUTOFS4_FS is not set +# CONFIG_FUSE_FS is not set # # CD-ROM/DVD Filesystems @@ -552,15 +696,13 @@ # Pseudo filesystems # CONFIG_PROC_FS=y CONFIG_PROC_KCORE=y +CONFIG_PROC_SYSCTL=y CONFIG_SYSFS=y -CONFIG_DEVFS_FS=y -CONFIG_DEVFS_MOUNT=y -# CONFIG_DEVFS_DEBUG is not set -# CONFIG_DEVPTS_FS_XATTR is not set CONFIG_TMPFS=y -# CONFIG_TMPFS_XATTR is not set +# CONFIG_TMPFS_POSIX_ACL is not set # CONFIG_HUGETLB_PAGE is not set CONFIG_RAMFS=y +# CONFIG_CONFIGFS_FS is not set # # Miscellaneous filesystems @@ -584,12 +726,14 @@ # Network File Systems # CONFIG_NFS_FS=y CONFIG_NFS_V3=y +# CONFIG_NFS_V3_ACL is not set # CONFIG_NFS_V4 is not set # CONFIG_NFS_DIRECTIO is not set # CONFIG_NFSD is not set CONFIG_ROOT_NFS=y CONFIG_LOCKD=y CONFIG_LOCKD_V4=y +CONFIG_NFS_COMMON=y CONFIG_SUNRPC=y # CONFIG_RPCSEC_GSS_KRB5 is not set # CONFIG_RPCSEC_GSS_SPKM3 is not set @@ -598,6 +742,7 @@ # CONFIG_CIFS is not set # CONFIG_NCP_FS is not set # CONFIG_CODA_FS is not set # CONFIG_AFS_FS is not set +# CONFIG_9P_FS is not set # # Partition Types @@ -658,21 +803,32 @@ # # Kernel hacking # # CONFIG_PRINTK_TIME is not set -CONFIG_DEBUG_KERNEL=y +CONFIG_ENABLE_MUST_CHECK=y # CONFIG_MAGIC_SYSRQ is not set +# CONFIG_UNUSED_SYMBOLS is not set +CONFIG_DEBUG_KERNEL=y CONFIG_LOG_BUF_SHIFT=14 +CONFIG_DETECT_SOFTLOCKUP=y # CONFIG_SCHEDSTATS is not set # CONFIG_DEBUG_SLAB is not set # CONFIG_DEBUG_SPINLOCK is not set +# CONFIG_DEBUG_MUTEXES is not set +# CONFIG_DEBUG_RWSEMS is not set # CONFIG_DEBUG_SPINLOCK_SLEEP is not set +# CONFIG_DEBUG_LOCKING_API_SELFTESTS is not set # CONFIG_DEBUG_KOBJECT is not set # CONFIG_DEBUG_BUGVERBOSE is not set CONFIG_DEBUG_INFO=y # CONFIG_DEBUG_FS is not set +# CONFIG_DEBUG_VM is not set +# CONFIG_DEBUG_LIST is not set # CONFIG_FRAME_POINTER is not set +# CONFIG_UNWIND_INFO is not set +CONFIG_FORCED_INLINING=y +# CONFIG_HEADERS_CHECK is not set +# CONFIG_RCU_TORTURE_TEST is not set # CONFIG_DEBUG_STACKOVERFLOW is not set # CONFIG_DEBUG_STACK_USAGE is not set -# CONFIG_DEBUG_PAGEALLOC is not set # # Security options @@ -686,12 +842,9 @@ # # CONFIG_CRYPTO is not set # -# Hardware crypto devices -# - -# # Library routines # # CONFIG_CRC_CCITT is not set +# CONFIG_CRC16 is not set CONFIG_CRC32=y # CONFIG_LIBCRC32C is not set diff --git a/arch/m68k/Kconfig b/arch/m68k/Kconfig index 70a577c..a8e1e60 100644 --- a/arch/m68k/Kconfig +++ b/arch/m68k/Kconfig @@ -42,6 +42,9 @@ config ARCH_MAY_HAVE_PC_FDC depends on Q40 || (BROKEN && SUN3X) default y +config NO_IOPORT + def_bool y + mainmenu "Linux/68k Kernel Configuration" source "init/Kconfig" @@ -439,6 +442,10 @@ config GENERIC_ISA_DMA depends on Q40 || AMIGA_PCMCIA || GG2 default y +config ZONE_DMA + bool + default y + source "drivers/pci/Kconfig" source "drivers/zorro/Kconfig" diff --git a/arch/m68k/atari/stdma.c b/arch/m68k/atari/stdma.c index d01deb4..ab3fd52 100644 --- a/arch/m68k/atari/stdma.c +++ b/arch/m68k/atari/stdma.c @@ -174,7 +174,7 @@ int stdma_islocked(void) void __init stdma_init(void) { stdma_isr = NULL; - request_irq(IRQ_MFP_FDC, stdma_int, IRQ_TYPE_SLOW | SA_SHIRQ, + request_irq(IRQ_MFP_FDC, stdma_int, IRQ_TYPE_SLOW | IRQF_SHARED, "ST-DMA: floppy/ACSI/IDE/Falcon-SCSI", stdma_int); } diff --git a/arch/m68k/bvme6000/rtc.c b/arch/m68k/bvme6000/rtc.c index 15c16b6..a812d03 100644 --- a/arch/m68k/bvme6000/rtc.c +++ b/arch/m68k/bvme6000/rtc.c @@ -159,7 +159,7 @@ static int rtc_release(struct inode *ino * The various file operations we support. */ -static struct file_operations rtc_fops = { +static const struct file_operations rtc_fops = { .ioctl = rtc_ioctl, .open = rtc_open, .release = rtc_release, diff --git a/arch/m68k/kernel/Makefile b/arch/m68k/kernel/Makefile index 1c9ecaa..0b68ab8 100644 --- a/arch/m68k/kernel/Makefile +++ b/arch/m68k/kernel/Makefile @@ -10,7 +10,9 @@ endif extra-y += vmlinux.lds obj-y := entry.o process.o traps.o ints.o signal.o ptrace.o \ - sys_m68k.o time.o semaphore.o setup.o m68k_ksyms.o + sys_m68k.o time.o semaphore.o setup.o m68k_ksyms.o devres.o + +devres-y = ../../../kernel/irq/devres.o obj-$(CONFIG_PCI) += bios32.o obj-$(CONFIG_MODULES) += module.o diff --git a/arch/m68k/kernel/ptrace.c b/arch/m68k/kernel/ptrace.c index ef89060..7fd2720 100644 --- a/arch/m68k/kernel/ptrace.c +++ b/arch/m68k/kernel/ptrace.c @@ -76,7 +76,7 @@ static inline long get_reg(struct task_s if (regno == PT_USP) addr = &task->thread.usp; - else if (regno < sizeof(regoff)/sizeof(regoff[0])) + else if (regno < ARRAY_SIZE(regoff)) addr = (unsigned long *)(task->thread.esp0 + regoff[regno]); else return 0; @@ -93,7 +93,7 @@ static inline int put_reg(struct task_st if (regno == PT_USP) addr = &task->thread.usp; - else if (regno < sizeof(regoff)/sizeof(regoff[0])) + else if (regno < ARRAY_SIZE(regoff)) addr = (unsigned long *)(task->thread.esp0 + regoff[regno]); else return -1; diff --git a/arch/m68k/kernel/setup.c b/arch/m68k/kernel/setup.c index 9af3ee0..42b8fd0 100644 --- a/arch/m68k/kernel/setup.c +++ b/arch/m68k/kernel/setup.c @@ -256,7 +256,7 @@ #endif init_mm.brk = (unsigned long) &_end; *cmdline_p = m68k_command_line; - memcpy(saved_command_line, *cmdline_p, CL_SIZE); + memcpy(boot_command_line, *cmdline_p, CL_SIZE); /* Parse the command line for arch-specific options. * For the m68k, this is currently only "debug=xxx" to enable printing diff --git a/arch/m68k/kernel/time.c b/arch/m68k/kernel/time.c index 2a599c3..4c065f9 100644 --- a/arch/m68k/kernel/time.c +++ b/arch/m68k/kernel/time.c @@ -159,12 +159,3 @@ int do_settimeofday(struct timespec *tv) } EXPORT_SYMBOL(do_settimeofday); - -/* - * Scheduler clock - returns current time in ns units. - */ -unsigned long long sched_clock(void) -{ - return (unsigned long long)jiffies*(1000000000/HZ); -} - diff --git a/arch/m68k/kernel/traps.c b/arch/m68k/kernel/traps.c index 759fa24..a27a4fa 100644 --- a/arch/m68k/kernel/traps.c +++ b/arch/m68k/kernel/traps.c @@ -1011,7 +1011,7 @@ EXPORT_SYMBOL(dump_stack); void bad_super_trap (struct frame *fp) { console_verbose(); - if (fp->ptregs.vector < 4*sizeof(vec_names)/sizeof(vec_names[0])) + if (fp->ptregs.vector < 4 * ARRAY_SIZE(vec_names)) printk ("*** %s *** FORMAT=%X\n", vec_names[(fp->ptregs.vector) >> 2], fp->ptregs.format); diff --git a/arch/m68k/kernel/vmlinux-std.lds b/arch/m68k/kernel/vmlinux-std.lds index d279445..437b4f8 100644 --- a/arch/m68k/kernel/vmlinux-std.lds +++ b/arch/m68k/kernel/vmlinux-std.lds @@ -61,10 +61,12 @@ SECTIONS .con_initcall.init : { *(.con_initcall.init) } __con_initcall_end = .; SECURITY_INIT +#ifdef CONFIG_BLK_DEV_INITRD . = ALIGN(8192); __initramfs_start = .; .init.ramfs : { *(.init.ramfs) } __initramfs_end = .; +#endif . = ALIGN(8192); __init_end = .; diff --git a/arch/m68k/kernel/vmlinux-sun3.lds b/arch/m68k/kernel/vmlinux-sun3.lds index 8c7eccb..2868e20 100644 --- a/arch/m68k/kernel/vmlinux-sun3.lds +++ b/arch/m68k/kernel/vmlinux-sun3.lds @@ -55,10 +55,12 @@ __init_begin = .; .con_initcall.init : { *(.con_initcall.init) } __con_initcall_end = .; SECURITY_INIT +#ifdef CONFIG_BLK_DEV_INITRD . = ALIGN(8192); __initramfs_start = .; .init.ramfs : { *(.init.ramfs) } __initramfs_end = .; +#endif . = ALIGN(8192); __init_end = .; .data.init.task : { *(.data.init_task) } diff --git a/arch/m68k/mvme16x/rtc.c b/arch/m68k/mvme16x/rtc.c index b0e4c08..272d47e 100644 --- a/arch/m68k/mvme16x/rtc.c +++ b/arch/m68k/mvme16x/rtc.c @@ -147,7 +147,7 @@ static int rtc_release(struct inode *ino * The various file operations we support. */ -static struct file_operations rtc_fops = { +static const struct file_operations rtc_fops = { .ioctl = rtc_ioctl, .open = rtc_open, .release = rtc_release, diff --git a/arch/m68knommu/Kconfig b/arch/m68knommu/Kconfig index 25993c2..823f737 100644 --- a/arch/m68knommu/Kconfig +++ b/arch/m68knommu/Kconfig @@ -17,6 +17,10 @@ config FPU bool default n +config ZONE_DMA + bool + default y + config RWSEM_GENERIC_SPINLOCK bool default y @@ -49,6 +53,9 @@ config TIME_LOW_RES bool default y +config NO_IOPORT + def_bool y + source "init/Kconfig" menu "Processor type and features" diff --git a/arch/m68knommu/kernel/ptrace.c b/arch/m68knommu/kernel/ptrace.c index 9130119..72d3496 100644 --- a/arch/m68knommu/kernel/ptrace.c +++ b/arch/m68knommu/kernel/ptrace.c @@ -62,7 +62,7 @@ static inline long get_reg(struct task_s if (regno == PT_USP) addr = &task->thread.usp; - else if (regno < sizeof(regoff)/sizeof(regoff[0])) + else if (regno < ARRAY_SIZE(regoff)) addr = (unsigned long *)(task->thread.esp0 + regoff[regno]); else return 0; @@ -79,7 +79,7 @@ static inline int put_reg(struct task_st if (regno == PT_USP) addr = &task->thread.usp; - else if (regno < sizeof(regoff)/sizeof(regoff[0])) + else if (regno < ARRAY_SIZE(regoff)) addr = (unsigned long *) (task->thread.esp0 + regoff[regno]); else return -1; diff --git a/arch/m68knommu/kernel/setup.c b/arch/m68knommu/kernel/setup.c index 9cf2e4d..d5c25d2 100644 --- a/arch/m68knommu/kernel/setup.c +++ b/arch/m68knommu/kernel/setup.c @@ -44,7 +44,7 @@ unsigned long memory_end; EXPORT_SYMBOL(memory_start); EXPORT_SYMBOL(memory_end); -char command_line[COMMAND_LINE_SIZE]; +char __initdata command_line[COMMAND_LINE_SIZE]; /* setup some dummy routines */ static void dummy_waitbut(void) @@ -231,8 +231,8 @@ #endif /* Keep a copy of command line */ *cmdline_p = &command_line[0]; - memcpy(saved_command_line, command_line, COMMAND_LINE_SIZE); - saved_command_line[COMMAND_LINE_SIZE-1] = 0; + memcpy(boot_command_line, command_line, COMMAND_LINE_SIZE); + boot_command_line[COMMAND_LINE_SIZE-1] = 0; #ifdef DEBUG if (strlen(*cmdline_p)) diff --git a/arch/m68knommu/kernel/time.c b/arch/m68knommu/kernel/time.c index 9226264..467053d 100644 --- a/arch/m68knommu/kernel/time.c +++ b/arch/m68knommu/kernel/time.c @@ -23,6 +23,7 @@ #include #include #include +#include #define TICK_SIZE (tick_nsec / 1000) @@ -38,7 +39,7 @@ static inline int set_rtc_mmss(unsigned * timer_interrupt() needs to keep up the real-time clock, * as well as call the "do_timer()" routine every clocktick */ -static irqreturn_t timer_interrupt(int irq, void *dummy, struct pt_regs * regs) +static irqreturn_t timer_interrupt(int irq, void *dummy) { /* last time the cmos clock got updated */ static long last_rtc_update=0; @@ -51,7 +52,7 @@ static irqreturn_t timer_interrupt(int i do_timer(1); #ifndef CONFIG_SMP - update_process_times(user_mode(regs)); + update_process_times(user_mode(get_irq_regs())); #endif if (current->pid) profile_tick(CPU_PROFILING); @@ -173,13 +174,4 @@ int do_settimeofday(struct timespec *tv) clock_was_set(); return 0; } - -/* - * Scheduler clock - returns current time in nanosec units. - */ -unsigned long long sched_clock(void) -{ - return (unsigned long long)jiffies * (1000000000 / HZ); -} - EXPORT_SYMBOL(do_settimeofday); diff --git a/arch/m68knommu/kernel/traps.c b/arch/m68knommu/kernel/traps.c index 9129b3a..bed5f47 100644 --- a/arch/m68knommu/kernel/traps.c +++ b/arch/m68knommu/kernel/traps.c @@ -158,7 +158,7 @@ void show_stack(struct task_struct *task void bad_super_trap(struct frame *fp) { console_verbose(); - if (fp->ptregs.vector < 4*sizeof(vec_names)/sizeof(vec_names[0])) + if (fp->ptregs.vector < 4 * ARRAY_SIZE(vec_names)) printk (KERN_WARNING "*** %s *** FORMAT=%X\n", vec_names[(fp->ptregs.vector) >> 2], fp->ptregs.format); diff --git a/arch/m68knommu/kernel/vmlinux.lds.S b/arch/m68knommu/kernel/vmlinux.lds.S index 2b2a10d..c86a1bf 100644 --- a/arch/m68knommu/kernel/vmlinux.lds.S +++ b/arch/m68knommu/kernel/vmlinux.lds.S @@ -87,6 +87,16 @@ #endif *(__ksymtab_gpl) __stop___ksymtab_gpl = .; + /* Kernel symbol table: Normal unused symbols */ + __start___ksymtab_unused = .; + *(__ksymtab_unused) + __stop___ksymtab_unused = .; + + /* Kernel symbol table: GPL-only unused symbols */ + __start___ksymtab_unused_gpl = .; + *(__ksymtab_unused_gpl) + __stop___ksymtab_unused_gpl = .; + /* Kernel symbol table: GPL-future symbols */ __start___ksymtab_gpl_future = .; *(__ksymtab_gpl_future) @@ -149,10 +159,12 @@ #endif __security_initcall_start = .; *(.security_initcall.init) __security_initcall_end = .; +#ifdef CONFIG_BLK_DEV_INITRD . = ALIGN(4); __initramfs_start = .; *(.init.ramfs) __initramfs_end = .; +#endif . = ALIGN(4096); __init_end = .; } > INIT diff --git a/arch/m68knommu/platform/5206/config.c b/arch/m68knommu/platform/5206/config.c index 34657f8..3343830 100644 --- a/arch/m68knommu/platform/5206/config.c +++ b/arch/m68knommu/platform/5206/config.c @@ -26,7 +26,7 @@ #include /***************************************************************************/ void coldfire_tick(void); -void coldfire_timer_init(irqreturn_t (*handler)(int, void *, struct pt_regs *)); +void coldfire_timer_init(irq_handler_t handler); unsigned long coldfire_timer_offset(void); void coldfire_trap_init(void); void coldfire_reset(void); diff --git a/arch/m68knommu/platform/5206e/config.c b/arch/m68knommu/platform/5206e/config.c index 48e4d62..0f67320 100644 --- a/arch/m68knommu/platform/5206e/config.c +++ b/arch/m68knommu/platform/5206e/config.c @@ -25,7 +25,7 @@ #include /***************************************************************************/ void coldfire_tick(void); -void coldfire_timer_init(irqreturn_t (*handler)(int, void *, struct pt_regs *)); +void coldfire_timer_init(irq_handler_t handler); unsigned long coldfire_timer_offset(void); void coldfire_trap_init(void); void coldfire_reset(void); diff --git a/arch/m68knommu/platform/520x/config.c b/arch/m68knommu/platform/520x/config.c index 823f561..58b2878 100644 --- a/arch/m68knommu/platform/520x/config.c +++ b/arch/m68knommu/platform/520x/config.c @@ -13,6 +13,7 @@ #include #include +#include #include #include @@ -27,7 +28,7 @@ unsigned int dma_device_address[MAX_M68K /***************************************************************************/ void coldfire_pit_tick(void); -void coldfire_pit_init(irqreturn_t (*handler)(int, void *, struct pt_regs *)); +void coldfire_pit_init(irq_handler_t handler); unsigned long coldfire_pit_offset(void); void coldfire_trap_init(void); void coldfire_reset(void); diff --git a/arch/m68knommu/platform/523x/config.c b/arch/m68knommu/platform/523x/config.c index 85de817..9b054e6 100644 --- a/arch/m68knommu/platform/523x/config.c +++ b/arch/m68knommu/platform/523x/config.c @@ -27,7 +27,7 @@ #include /***************************************************************************/ void coldfire_pit_tick(void); -void coldfire_pit_init(irqreturn_t (*handler)(int, void *, struct pt_regs *)); +void coldfire_pit_init(irq_handler_t handler); unsigned long coldfire_pit_offset(void); void coldfire_trap_init(void); void coldfire_reset(void); diff --git a/arch/m68knommu/platform/5249/config.c b/arch/m68knommu/platform/5249/config.c index 9d19d5b..d670607 100644 --- a/arch/m68knommu/platform/5249/config.c +++ b/arch/m68knommu/platform/5249/config.c @@ -12,6 +12,7 @@ #include #include #include #include +#include #include #include #include @@ -24,7 +25,7 @@ #include /***************************************************************************/ void coldfire_tick(void); -void coldfire_timer_init(irqreturn_t (*handler)(int, void *, struct pt_regs *)); +void coldfire_timer_init(irq_handler_t handler); unsigned long coldfire_timer_offset(void); void coldfire_trap_init(void); void coldfire_reset(void); diff --git a/arch/m68knommu/platform/5272/config.c b/arch/m68knommu/platform/5272/config.c index d500e27..6b437cc 100644 --- a/arch/m68knommu/platform/5272/config.c +++ b/arch/m68knommu/platform/5272/config.c @@ -26,7 +26,7 @@ #include /***************************************************************************/ void coldfire_tick(void); -void coldfire_timer_init(irqreturn_t (*handler)(int, void *, struct pt_regs *)); +void coldfire_timer_init(irq_handler_t handler); unsigned long coldfire_timer_offset(void); void coldfire_trap_init(void); void coldfire_reset(void); diff --git a/arch/m68knommu/platform/527x/config.c b/arch/m68knommu/platform/527x/config.c index bbae515..28e7d96 100644 --- a/arch/m68knommu/platform/527x/config.c +++ b/arch/m68knommu/platform/527x/config.c @@ -27,7 +27,7 @@ #include /***************************************************************************/ void coldfire_pit_tick(void); -void coldfire_pit_init(irqreturn_t (*handler)(int, void *, struct pt_regs *)); +void coldfire_pit_init(irq_handler_t handler); unsigned long coldfire_pit_offset(void); void coldfire_trap_init(void); void coldfire_reset(void); diff --git a/arch/m68knommu/platform/528x/config.c b/arch/m68knommu/platform/528x/config.c index 18dad90..805b4f7 100644 --- a/arch/m68knommu/platform/528x/config.c +++ b/arch/m68knommu/platform/528x/config.c @@ -27,7 +27,7 @@ #include /***************************************************************************/ void coldfire_pit_tick(void); -void coldfire_pit_init(irqreturn_t (*handler)(int, void *, struct pt_regs *)); +void coldfire_pit_init(irq_handler_t handler); unsigned long coldfire_pit_offset(void); void coldfire_trap_init(void); void coldfire_reset(void); diff --git a/arch/m68knommu/platform/5307/config.c b/arch/m68knommu/platform/5307/config.c index 8074ac5..e04b84d 100644 --- a/arch/m68knommu/platform/5307/config.c +++ b/arch/m68knommu/platform/5307/config.c @@ -27,7 +27,7 @@ #include /***************************************************************************/ void coldfire_tick(void); -void coldfire_timer_init(irqreturn_t (*handler)(int, void *, struct pt_regs *)); +void coldfire_timer_init(irq_handler_t handler); unsigned long coldfire_timer_offset(void); void coldfire_trap_init(void); void coldfire_reset(void); diff --git a/arch/m68knommu/platform/5307/pit.c b/arch/m68knommu/platform/5307/pit.c index 9dc5688..aa15bee 100644 --- a/arch/m68knommu/platform/5307/pit.c +++ b/arch/m68knommu/platform/5307/pit.c @@ -43,7 +43,7 @@ void coldfire_pit_tick(void) /***************************************************************************/ -void coldfire_pit_init(irqreturn_t (*handler)(int, void *, struct pt_regs *)) +void coldfire_pit_init(irq_handler_t handler) { volatile unsigned char *icrp; volatile unsigned long *imrp; diff --git a/arch/m68knommu/platform/5307/timers.c b/arch/m68knommu/platform/5307/timers.c index e5668af..87b112b 100644 --- a/arch/m68knommu/platform/5307/timers.c +++ b/arch/m68knommu/platform/5307/timers.c @@ -62,7 +62,7 @@ void coldfire_tick(void) /***************************************************************************/ -void coldfire_timer_init(irqreturn_t (*handler)(int, void *, struct pt_regs *)) +void coldfire_timer_init(irq_handler_t handler) { __raw_writew(MCFTIMER_TMR_DISABLE, TA(MCFTIMER_TMR)); __raw_writetrr(((MCF_BUSCLK / 16) / HZ), TA(MCFTIMER_TRR)); @@ -111,12 +111,13 @@ #define PROFILEHZ 1013 /* * Use the other timer to provide high accuracy profiling info. */ -void coldfire_profile_tick(int irq, void *dummy, struct pt_regs *regs) +irqreturn_t coldfire_profile_tick(int irq, void *dummy) { /* Reset ColdFire timer2 */ __raw_writeb(MCFTIMER_TER_CAP | MCFTIMER_TER_REF, PA(MCFTIMER_TER)); if (current->pid) profile_tick(CPU_PROFILING, regs); + return IRQ_HANDLED; } /***************************************************************************/ diff --git a/arch/m68knommu/platform/532x/config.c b/arch/m68knommu/platform/532x/config.c index c7d6ad5..664c3a1 100644 --- a/arch/m68knommu/platform/532x/config.c +++ b/arch/m68knommu/platform/532x/config.c @@ -35,7 +35,7 @@ #include /***************************************************************************/ void coldfire_tick(void); -void coldfire_timer_init(irqreturn_t (*handler)(int, void *, struct pt_regs *)); +void coldfire_timer_init(irq_handler_t handler); unsigned long coldfire_timer_offset(void); void coldfire_trap_init(void); void coldfire_reset(void); diff --git a/arch/m68knommu/platform/5407/config.c b/arch/m68knommu/platform/5407/config.c index 5aad264..036f628 100644 --- a/arch/m68knommu/platform/5407/config.c +++ b/arch/m68knommu/platform/5407/config.c @@ -26,7 +26,7 @@ #include /***************************************************************************/ void coldfire_tick(void); -void coldfire_timer_init(irqreturn_t (*handler)(int, void *, struct pt_regs *)); +void coldfire_timer_init(irq_handler_t handler); unsigned long coldfire_timer_offset(void); void coldfire_trap_init(void); void coldfire_reset(void); diff --git a/arch/m68knommu/platform/68328/config.c b/arch/m68knommu/platform/68328/config.c index 26ffeba..e5c537d 100644 --- a/arch/m68knommu/platform/68328/config.c +++ b/arch/m68knommu/platform/68328/config.c @@ -34,7 +34,7 @@ #include /***************************************************************************/ -void m68328_timer_init(irqreturn_t (*timer_routine) (int, void *, struct pt_regs *)); +void m68328_timer_init(irq_handler_t timer_routine); void m68328_timer_tick(void); unsigned long m68328_timer_gettimeoffset(void); void m68328_timer_gettod(int *year, int *mon, int *day, int *hour, int *min, int *sec); diff --git a/arch/mips/Kconfig b/arch/mips/Kconfig index bbd386f..a92ce6b 100644 --- a/arch/mips/Kconfig +++ b/arch/mips/Kconfig @@ -8,6 +8,10 @@ mainmenu "Linux/MIPS Kernel Configuratio menu "Machine selection" +config ZONE_DMA + bool + default y + choice prompt "System type" default SGI_IP22 @@ -575,6 +579,7 @@ config SGI_IP27 select DMA_IP27 select EARLY_PRINTK select HW_HAS_PCI + select NR_CPUS_DEFAULT_64 select PCI_DOMAINS select SYS_HAS_CPU_R10000 select SYS_SUPPORTS_64BIT_KERNEL @@ -593,8 +598,6 @@ config SGI_IP32 select ARC select ARC32 select BOOT_ELF32 - select OWN_DMA - select DMA_IP32 select DMA_NONCOHERENT select HW_HAS_PCI select R5000_CPU_SCACHE @@ -612,6 +615,7 @@ config SIBYTE_BIGSUR bool "Sibyte BCM91480B-BigSur" select BOOT_ELF32 select DMA_COHERENT + select NR_CPUS_DEFAULT_4 select PCI_DOMAINS select SIBYTE_BCM1x80 select SWAP_IO_SPACE @@ -623,6 +627,7 @@ config SIBYTE_SWARM bool "Sibyte BCM91250A-SWARM" select BOOT_ELF32 select DMA_COHERENT + select NR_CPUS_DEFAULT_2 select SIBYTE_SB1250 select SWAP_IO_SPACE select SYS_HAS_CPU_SB1 @@ -635,6 +640,7 @@ config SIBYTE_SENTOSA depends on EXPERIMENTAL select BOOT_ELF32 select DMA_COHERENT + select NR_CPUS_DEFAULT_2 select SIBYTE_SB1250 select SWAP_IO_SPACE select SYS_HAS_CPU_SB1 @@ -668,6 +674,7 @@ config SIBYTE_PTSWARM depends on EXPERIMENTAL select BOOT_ELF32 select DMA_COHERENT + select NR_CPUS_DEFAULT_2 select SIBYTE_SB1250 select SWAP_IO_SPACE select SYS_HAS_CPU_SB1 @@ -680,6 +687,7 @@ config SIBYTE_LITTLESUR depends on EXPERIMENTAL select BOOT_ELF32 select DMA_COHERENT + select NR_CPUS_DEFAULT_2 select SIBYTE_SB1250 select SWAP_IO_SPACE select SYS_HAS_CPU_SB1 @@ -747,6 +755,7 @@ config TOSHIBA_JMR3927 select SWAP_IO_SPACE select SYS_HAS_CPU_TX39XX select SYS_SUPPORTS_32BIT_KERNEL + select SYS_SUPPORTS_LITTLE_ENDIAN select SYS_SUPPORTS_BIG_ENDIAN select TOSHIBA_BOARDS @@ -761,6 +770,7 @@ config TOSHIBA_RBTX4927 select SYS_HAS_CPU_TX49XX select SYS_SUPPORTS_32BIT_KERNEL select SYS_SUPPORTS_64BIT_KERNEL + select SYS_SUPPORTS_LITTLE_ENDIAN select SYS_SUPPORTS_BIG_ENDIAN select TOSHIBA_BOARDS select GENERIC_HARDIRQS_NO__DO_IRQ @@ -790,23 +800,6 @@ config TOSHIBA_RBTX4938 endchoice -config KEXEC - bool "Kexec system call (EXPERIMENTAL)" - depends on EXPERIMENTAL - help - kexec is a system call that implements the ability to shutdown your - current kernel, and to start another kernel. It is like a reboot - but it is indepedent of the system firmware. And like a reboot - you can start any kernel with it, not just Linux. - - The name comes from the similiarity to the exec system call. - - It is an ongoing process to be certain the hardware in a machine - is properly shutdown, so do not be surprised if this code does not - initially work for you. It may help to enable device hotplugging - support. As of this writing the exact hardware interface is - strongly in flux, so no good recommendation can be made. - source "arch/mips/ddb5xxx/Kconfig" source "arch/mips/gt64120/ev64120/Kconfig" source "arch/mips/jazz/Kconfig" @@ -888,9 +881,6 @@ config DMA_NONCOHERENT config DMA_NEED_PCI_MAP_STATE bool -config OWN_DMA - bool - config EARLY_PRINTK bool @@ -945,6 +935,9 @@ config CPU_LITTLE_ENDIAN endchoice +config SYS_SUPPORTS_APM_EMULATION + bool + config SYS_SUPPORTS_BIG_ENDIAN bool @@ -1012,6 +1005,7 @@ config SOC_AU1X00 bool select SYS_HAS_CPU_MIPS32_R1 select SYS_SUPPORTS_32BIT_KERNEL + select SYS_SUPPORTS_APM_EMULATION config PNX8550 bool @@ -1541,6 +1535,8 @@ config MIPS_MT_SMTC select CPU_MIPSR2_IRQ_VI select CPU_MIPSR2_SRS select MIPS_MT + select NR_CPUS_DEFAULT_2 + select NR_CPUS_DEFAULT_8 select SMP select SYS_SUPPORTS_SMP help @@ -1756,13 +1752,34 @@ config SMP config SYS_SUPPORTS_SMP bool +config NR_CPUS_DEFAULT_2 + bool + +config NR_CPUS_DEFAULT_4 + bool + +config NR_CPUS_DEFAULT_8 + bool + +config NR_CPUS_DEFAULT_16 + bool + +config NR_CPUS_DEFAULT_32 + bool + +config NR_CPUS_DEFAULT_64 + bool + config NR_CPUS int "Maximum number of CPUs (2-64)" range 2 64 depends on SMP - default "64" if SGI_IP27 - default "2" - default "8" if MIPS_MT_SMTC + default "2" if NR_CPUS_DEFAULT_2 + default "4" if NR_CPUS_DEFAULT_4 + default "8" if NR_CPUS_DEFAULT_8 + default "16" if NR_CPUS_DEFAULT_16 + default "32" if NR_CPUS_DEFAULT_32 + default "64" if NR_CPUS_DEFAULT_64 help This allows you to specify the maximum number of CPUs which this kernel will support. The maximum supported value is 32 for 32-bit @@ -1859,6 +1876,40 @@ config MIPS_INSANE_LARGE This will result in additional memory usage, so it is not recommended for normal users. +config KEXEC + bool "Kexec system call (EXPERIMENTAL)" + depends on EXPERIMENTAL + help + kexec is a system call that implements the ability to shutdown your + current kernel, and to start another kernel. It is like a reboot + but it is indepedent of the system firmware. And like a reboot + you can start any kernel with it, not just Linux. + + The name comes from the similiarity to the exec system call. + + It is an ongoing process to be certain the hardware in a machine + is properly shutdown, so do not be surprised if this code does not + initially work for you. It may help to enable device hotplugging + support. As of this writing the exact hardware interface is + strongly in flux, so no good recommendation can be made. + +config SECCOMP + bool "Enable seccomp to safely compute untrusted bytecode" + depends on PROC_FS && BROKEN + default y + help + This kernel feature is useful for number crunching applications + that may need to compute untrusted bytecode during their + execution. By using pipes or other transports made available to + the process as file descriptors supporting the read/write + syscalls, it's possible to isolate those applications in + their own address space using seccomp. Once seccomp is + enabled via /proc//seccomp, it cannot be disabled + and the task is only allowed to execute a few safe syscalls + defined by each seccomp mode. + + If unsure, say Y. Only embedded should say N here. + endmenu config RWSEM_GENERIC_SPINLOCK @@ -2025,52 +2076,11 @@ config BINFMT_ELF32 bool default y if MIPS32_O32 || MIPS32_N32 -config SECCOMP - bool "Enable seccomp to safely compute untrusted bytecode" - depends on PROC_FS && BROKEN - default y - help - This kernel feature is useful for number crunching applications - that may need to compute untrusted bytecode during their - execution. By using pipes or other transports made available to - the process as file descriptors supporting the read/write - syscalls, it's possible to isolate those applications in - their own address space using seccomp. Once seccomp is - enabled via /proc//seccomp, it cannot be disabled - and the task is only allowed to execute a few safe syscalls - defined by each seccomp mode. +endmenu - If unsure, say Y. Only embedded should say N here. +menu "Power management options" -config PM - bool "Power Management support (EXPERIMENTAL)" - depends on EXPERIMENTAL && SOC_AU1X00 - -config APM - tristate "Advanced Power Management Emulation" - depends on PM - ---help--- - APM is a BIOS specification for saving power using several different - techniques. This is mostly useful for battery powered systems with - APM compliant BIOSes. If you say Y here, the system time will be - reset after a RESUME operation, the /proc/apm device will provide - battery status information, and user-space programs will receive - notification of APM "events" (e.g. battery status change). - - In order to use APM, you will need supporting software. For location - and more information, read and the - Battery Powered Linux mini-HOWTO, available from - . - - This driver does not spin down disk drives (see the hdparm(8) - manpage ("man 8 hdparm") for that), and it doesn't turn off - VESA-compliant "green" monitors. - - Generally, if you don't have a battery in your machine, there isn't - much point in using this driver and you should say N. If you get - random kernel OOPSes or reboots that don't seem to be related to - anything, try disabling/enabling this option (or disabling/enabling - APM in your BIOS). +source "kernel/power/Kconfig" endmenu diff --git a/arch/mips/Kconfig.debug b/arch/mips/Kconfig.debug index 5d6afb5..9351f1c 100644 --- a/arch/mips/Kconfig.debug +++ b/arch/mips/Kconfig.debug @@ -22,10 +22,10 @@ config CMDLINE string "Default kernel command string" default "" help - On some platforms, there is currently no way for the boot loader to - pass arguments to the kernel. For these platforms, you can supply - some command-line options at build time by entering them here. In - other cases you can specify kernel args so that you don't have + On some platforms, there is currently no way for the boot loader to + pass arguments to the kernel. For these platforms, you can supply + some command-line options at build time by entering them here. In + other cases you can specify kernel args so that you don't have to set them up in board prom initialization routines. config DEBUG_STACK_USAGE diff --git a/arch/mips/arc/identify.c b/arch/mips/arc/identify.c index 3ba7c47..4b90736 100644 --- a/arch/mips/arc/identify.c +++ b/arch/mips/arc/identify.c @@ -77,7 +77,7 @@ static struct smatch * __init string_to_ { int i; - for (i = 0; i < (sizeof(mach_table) / sizeof (mach_table[0])); i++) { + for (i = 0; i < ARRAY_SIZE(mach_table); i++) { if (!strcmp(s, mach_table[i].arcname)) return &mach_table[i]; } diff --git a/arch/mips/arc/memory.c b/arch/mips/arc/memory.c index 8a9ef58..456cb81 100644 --- a/arch/mips/arc/memory.c +++ b/arch/mips/arc/memory.c @@ -141,30 +141,20 @@ #endif } } -unsigned long __init prom_free_prom_memory(void) +void __init prom_free_prom_memory(void) { - unsigned long freed = 0; unsigned long addr; int i; if (prom_flags & PROM_FLAG_DONT_FREE_TEMP) - return 0; + return; for (i = 0; i < boot_mem_map.nr_map; i++) { if (boot_mem_map.map[i].type != BOOT_MEM_ROM_DATA) continue; addr = boot_mem_map.map[i].addr; - while (addr < boot_mem_map.map[i].addr - + boot_mem_map.map[i].size) { - ClearPageReserved(virt_to_page(__va(addr))); - init_page_count(virt_to_page(__va(addr))); - free_page((unsigned long)__va(addr)); - addr += PAGE_SIZE; - freed += PAGE_SIZE; - } + free_init_pages("prom memory", + addr, addr + boot_mem_map.map[i].size); } - printk(KERN_INFO "Freeing prom memory: %ldkb freed\n", freed >> 10); - - return freed; } diff --git a/arch/mips/au1000/common/irq.c b/arch/mips/au1000/common/irq.c index 9cf7b67..ea6e99f 100644 --- a/arch/mips/au1000/common/irq.c +++ b/arch/mips/au1000/common/irq.c @@ -233,7 +233,7 @@ void restore_local_and_enable(int contro static struct irq_chip rise_edge_irq_type = { - .typename = "Au1000 Rise Edge", + .name = "Au1000 Rise Edge", .ack = mask_and_ack_rise_edge_irq, .mask = local_disable_irq, .mask_ack = mask_and_ack_rise_edge_irq, @@ -242,7 +242,7 @@ static struct irq_chip rise_edge_irq_typ }; static struct irq_chip fall_edge_irq_type = { - .typename = "Au1000 Fall Edge", + .name = "Au1000 Fall Edge", .ack = mask_and_ack_fall_edge_irq, .mask = local_disable_irq, .mask_ack = mask_and_ack_fall_edge_irq, @@ -251,7 +251,7 @@ static struct irq_chip fall_edge_irq_typ }; static struct irq_chip either_edge_irq_type = { - .typename = "Au1000 Rise or Fall Edge", + .name = "Au1000 Rise or Fall Edge", .ack = mask_and_ack_either_edge_irq, .mask = local_disable_irq, .mask_ack = mask_and_ack_either_edge_irq, @@ -260,7 +260,7 @@ static struct irq_chip either_edge_irq_t }; static struct irq_chip level_irq_type = { - .typename = "Au1000 Level", + .name = "Au1000 Level", .ack = mask_and_ack_level_irq, .mask = local_disable_irq, .mask_ack = mask_and_ack_level_irq, diff --git a/arch/mips/au1000/common/pci.c b/arch/mips/au1000/common/pci.c index 9f8ce08..6c25e6c 100644 --- a/arch/mips/au1000/common/pci.c +++ b/arch/mips/au1000/common/pci.c @@ -76,13 +76,17 @@ #if defined(CONFIG_SOC_AU1500) || define } #ifdef CONFIG_DMA_NONCOHERENT - /* - * Set the NC bit in controller for Au1500 pre-AC silicon - */ - u32 prid = read_c0_prid(); - if ( (prid & 0xFF000000) == 0x01000000 && prid < 0x01030202) { - au_writel( 1<<16 | au_readl(Au1500_PCI_CFG), Au1500_PCI_CFG); - printk("Non-coherent PCI accesses enabled\n"); + { + /* + * Set the NC bit in controller for Au1500 pre-AC silicon + */ + u32 prid = read_c0_prid(); + + if ((prid & 0xFF000000) == 0x01000000 && prid < 0x01030202) { + au_writel((1 << 16) | au_readl(Au1500_PCI_CFG), + Au1500_PCI_CFG); + printk("Non-coherent PCI accesses enabled\n"); + } } #endif diff --git a/arch/mips/au1000/common/power.c b/arch/mips/au1000/common/power.c index 7504a63..3901e8e 100644 --- a/arch/mips/au1000/common/power.c +++ b/arch/mips/au1000/common/power.c @@ -62,12 +62,6 @@ extern unsigned long save_local_and_disa extern void restore_local_and_enable(int controller, unsigned long mask); extern void local_enable_irq(unsigned int irq_nr); -/* Quick acpi hack. This will have to change! */ -#define CTL_ACPI 9999 -#define ACPI_S1_SLP_TYP 19 -#define ACPI_SLEEP 21 - - static DEFINE_SPINLOCK(pm_lock); /* We need to save/restore a bunch of core registers that are @@ -425,15 +419,41 @@ #define MAX_CPU_FREQ 396 static struct ctl_table pm_table[] = { - {ACPI_S1_SLP_TYP, "suspend", NULL, 0, 0600, NULL, &pm_do_suspend}, - {ACPI_SLEEP, "sleep", NULL, 0, 0600, NULL, &pm_do_sleep}, - {CTL_ACPI, "freq", NULL, 0, 0600, NULL, &pm_do_freq}, - {0} + { + .ctl_name = CTL_UNNUMBERED, + .procname = "suspend", + .data = NULL, + .maxlen = 0, + .mode = 0600, + .proc_handler = &pm_do_suspend + }, + { + .ctl_name = CTL_UNNUMBERED, + .procname = "sleep", + .data = NULL, + .maxlen = 0, + .mode = 0600, + .proc_handler = &pm_do_sleep + }, + { + .ctl_name = CTL_UNNUMBERED, + .procname = "freq", + .data = NULL, + .maxlen = 0, + .mode = 0600, + .proc_handler = &pm_do_freq + }, + {} }; static struct ctl_table pm_dir_table[] = { - {CTL_ACPI, "pm", NULL, 0, 0555, pm_table}, - {0} + { + .ctl_name = CTL_UNNUMBERED, + .procname = "pm", + .mode = 0555, + .child = pm_table + }, + {} }; /* @@ -441,7 +461,7 @@ static struct ctl_table pm_dir_table[] = */ static int __init pm_init(void) { - register_sysctl_table(pm_dir_table, 1); + register_sysctl_table(pm_dir_table); return 0; } diff --git a/arch/mips/au1000/common/prom.c b/arch/mips/au1000/common/prom.c index 6fce60a..a8637cd 100644 --- a/arch/mips/au1000/common/prom.c +++ b/arch/mips/au1000/common/prom.c @@ -149,9 +149,8 @@ #endif return 0; } -unsigned long __init prom_free_prom_memory(void) +void __init prom_free_prom_memory(void) { - return 0; } EXPORT_SYMBOL(prom_getcmdline); diff --git a/arch/mips/au1000/common/setup.c b/arch/mips/au1000/common/setup.c index 919172d..13fe187 100644 --- a/arch/mips/au1000/common/setup.c +++ b/arch/mips/au1000/common/setup.c @@ -141,17 +141,20 @@ #if defined(CONFIG_64BIT_PHYS_ADDR) /* This routine should be valid for all Au1x based boards */ phys_t __fixup_bigphys_addr(phys_t phys_addr, phys_t size) { - u32 start, end; - /* Don't fixup 36 bit addresses */ - if ((phys_addr >> 32) != 0) return phys_addr; + if ((phys_addr >> 32) != 0) + return phys_addr; #ifdef CONFIG_PCI - start = (u32)Au1500_PCI_MEM_START; - end = (u32)Au1500_PCI_MEM_END; - /* check for pci memory window */ - if ((phys_addr >= start) && ((phys_addr + size) < end)) { - return (phys_t)((phys_addr - start) + Au1500_PCI_MEM_START); + { + u32 start, end; + + start = (u32)Au1500_PCI_MEM_START; + end = (u32)Au1500_PCI_MEM_END; + /* check for pci memory window */ + if ((phys_addr >= start) && ((phys_addr + size) < end)) + return (phys_t) + ((phys_addr - start) + Au1500_PCI_MEM_START); } #endif diff --git a/arch/mips/au1000/pb1100/board_setup.c b/arch/mips/au1000/pb1100/board_setup.c index 2d1533f..6bc1f8e 100644 --- a/arch/mips/au1000/pb1100/board_setup.c +++ b/arch/mips/au1000/pb1100/board_setup.c @@ -47,8 +47,7 @@ void board_reset (void) void __init board_setup(void) { - u32 pin_func; - u32 sys_freqctrl, sys_clksrc; + volatile void __iomem * base = (volatile void __iomem *) 0xac000000UL; // set AUX clock to 12MHz * 8 = 96 MHz au_writel(8, SYS_AUXPLL); @@ -56,58 +55,62 @@ void __init board_setup(void) udelay(100); #ifdef CONFIG_USB_OHCI - // configure pins GPIO[14:9] as GPIO - pin_func = au_readl(SYS_PINFUNC) & (u32)(~0x80); - - /* zero and disable FREQ2 */ - sys_freqctrl = au_readl(SYS_FREQCTRL0); - sys_freqctrl &= ~0xFFF00000; - au_writel(sys_freqctrl, SYS_FREQCTRL0); - - /* zero and disable USBH/USBD/IrDA clock */ - sys_clksrc = au_readl(SYS_CLKSRC); - sys_clksrc &= ~0x0000001F; - au_writel(sys_clksrc, SYS_CLKSRC); - - sys_freqctrl = au_readl(SYS_FREQCTRL0); - sys_freqctrl &= ~0xFFF00000; - - sys_clksrc = au_readl(SYS_CLKSRC); - sys_clksrc &= ~0x0000001F; - - // FREQ2 = aux/2 = 48 MHz - sys_freqctrl |= ((0<<22) | (1<<21) | (1<<20)); - au_writel(sys_freqctrl, SYS_FREQCTRL0); - - /* - * Route 48MHz FREQ2 into USBH/USBD/IrDA - */ - sys_clksrc |= ((4<<2) | (0<<1) | 0 ); - au_writel(sys_clksrc, SYS_CLKSRC); - - /* setup the static bus controller */ - au_writel(0x00000002, MEM_STCFG3); /* type = PCMCIA */ - au_writel(0x280E3D07, MEM_STTIME3); /* 250ns cycle time */ - au_writel(0x10000000, MEM_STADDR3); /* any PCMCIA select */ - - // get USB Functionality pin state (device vs host drive pins) - pin_func = au_readl(SYS_PINFUNC) & (u32)(~0x8000); - // 2nd USB port is USB host - pin_func |= 0x8000; - au_writel(pin_func, SYS_PINFUNC); + { + u32 pin_func, sys_freqctrl, sys_clksrc; + + // configure pins GPIO[14:9] as GPIO + pin_func = au_readl(SYS_PINFUNC) & (u32)(~0x80); + + /* zero and disable FREQ2 */ + sys_freqctrl = au_readl(SYS_FREQCTRL0); + sys_freqctrl &= ~0xFFF00000; + au_writel(sys_freqctrl, SYS_FREQCTRL0); + + /* zero and disable USBH/USBD/IrDA clock */ + sys_clksrc = au_readl(SYS_CLKSRC); + sys_clksrc &= ~0x0000001F; + au_writel(sys_clksrc, SYS_CLKSRC); + + sys_freqctrl = au_readl(SYS_FREQCTRL0); + sys_freqctrl &= ~0xFFF00000; + + sys_clksrc = au_readl(SYS_CLKSRC); + sys_clksrc &= ~0x0000001F; + + // FREQ2 = aux/2 = 48 MHz + sys_freqctrl |= ((0<<22) | (1<<21) | (1<<20)); + au_writel(sys_freqctrl, SYS_FREQCTRL0); + + /* + * Route 48MHz FREQ2 into USBH/USBD/IrDA + */ + sys_clksrc |= ((4<<2) | (0<<1) | 0 ); + au_writel(sys_clksrc, SYS_CLKSRC); + + /* setup the static bus controller */ + au_writel(0x00000002, MEM_STCFG3); /* type = PCMCIA */ + au_writel(0x280E3D07, MEM_STTIME3); /* 250ns cycle time */ + au_writel(0x10000000, MEM_STADDR3); /* any PCMCIA select */ + + // get USB Functionality pin state (device vs host drive pins) + pin_func = au_readl(SYS_PINFUNC) & (u32)(~0x8000); + // 2nd USB port is USB host + pin_func |= 0x8000; + au_writel(pin_func, SYS_PINFUNC); + } #endif // defined (CONFIG_USB_OHCI) /* Enable sys bus clock divider when IDLE state or no bus activity. */ au_writel(au_readl(SYS_POWERCTRL) | (0x3 << 5), SYS_POWERCTRL); // Enable the RTC if not already enabled - if (!(readb(0xac000028) & 0x20)) { - writeb(readb(0xac000028) | 0x20, 0xac000028); + if (!(readb(base + 0x28) & 0x20)) { + writeb(readb(base + 0x28) | 0x20, base + 0x28); au_sync(); } // Put the clock in BCD mode - if (readb(0xac00002C) & 0x4) { /* reg B */ - writeb(readb(0xac00002c) & ~0x4, 0xac00002c); + if (readb(base + 0x2C) & 0x4) { /* reg B */ + writeb(readb(base + 0x2c) & ~0x4, base + 0x2c); au_sync(); } } diff --git a/arch/mips/au1000/pb1200/irqmap.c b/arch/mips/au1000/pb1200/irqmap.c index 91983ba..b73b2d1 100644 --- a/arch/mips/au1000/pb1200/irqmap.c +++ b/arch/mips/au1000/pb1200/irqmap.c @@ -137,33 +137,20 @@ static void pb1200_shutdown_irq( unsigne return; } -static inline void pb1200_mask_and_ack_irq(unsigned int irq_nr) -{ - pb1200_disable_irq( irq_nr ); -} - -static void pb1200_end_irq(unsigned int irq_nr) -{ - if (!(irq_desc[irq_nr].status & (IRQ_DISABLED|IRQ_INPROGRESS))) { - pb1200_enable_irq(irq_nr); - } -} - static struct irq_chip external_irq_type = { #ifdef CONFIG_MIPS_PB1200 - "Pb1200 Ext", + .name = "Pb1200 Ext", #endif #ifdef CONFIG_MIPS_DB1200 - "Db1200 Ext", + .name = "Db1200 Ext", #endif - pb1200_startup_irq, - pb1200_shutdown_irq, - pb1200_enable_irq, - pb1200_disable_irq, - pb1200_mask_and_ack_irq, - pb1200_end_irq, - NULL + .startup = pb1200_startup_irq, + .shutdown = pb1200_shutdown_irq, + .ack = pb1200_disable_irq, + .mask = pb1200_disable_irq, + .mask_ack = pb1200_disable_irq, + .unmask = pb1200_enable_irq, }; void _board_init_irq(void) @@ -172,7 +159,8 @@ void _board_init_irq(void) for (irq_nr = PB1200_INT_BEGIN; irq_nr <= PB1200_INT_END; irq_nr++) { - irq_desc[irq_nr].chip = &external_irq_type; + set_irq_chip_and_handler(irq_nr, &external_irq_type, + handle_level_irq); pb1200_disable_irq(irq_nr); } diff --git a/arch/mips/basler/excite/excite_irq.c b/arch/mips/basler/excite/excite_irq.c index 2e2061a..1ecab63 100644 --- a/arch/mips/basler/excite/excite_irq.c +++ b/arch/mips/basler/excite/excite_irq.c @@ -47,9 +47,9 @@ extern asmlinkage void excite_handle_int */ void __init arch_init_irq(void) { - mips_cpu_irq_init(0); - rm7k_cpu_irq_init(8); - rm9k_cpu_irq_init(12); + mips_cpu_irq_init(); + rm7k_cpu_irq_init(); + rm9k_cpu_irq_init(); #ifdef CONFIG_KGDB excite_kgdb_init(); diff --git a/arch/mips/cobalt/irq.c b/arch/mips/cobalt/irq.c index 4c46f0e..fe93b84 100644 --- a/arch/mips/cobalt/irq.c +++ b/arch/mips/cobalt/irq.c @@ -104,7 +104,7 @@ void __init arch_init_irq(void) GT_WRITE(GT_INTRMASK_OFS, 0); init_i8259_irqs(); /* 0 ... 15 */ - mips_cpu_irq_init(COBALT_CPU_IRQ); /* 16 ... 23 */ + mips_cpu_irq_init(); /* 16 ... 23 */ /* * Mask all cpu interrupts diff --git a/arch/mips/cobalt/setup.c b/arch/mips/cobalt/setup.c index e8f0f20..a4b69b5 100644 --- a/arch/mips/cobalt/setup.c +++ b/arch/mips/cobalt/setup.c @@ -204,8 +204,7 @@ void __init prom_init(void) add_memory_region(0x0, memsz, BOOT_MEM_RAM); } -unsigned long __init prom_free_prom_memory(void) +void __init prom_free_prom_memory(void) { /* Nothing to do! */ - return 0; } diff --git a/arch/mips/configs/ip27_defconfig b/arch/mips/configs/ip27_defconfig index 96090f2..f21186c 100644 --- a/arch/mips/configs/ip27_defconfig +++ b/arch/mips/configs/ip27_defconfig @@ -264,7 +264,7 @@ # CONFIG_BUILD_ELF64 is not set CONFIG_MIPS32_COMPAT=y CONFIG_COMPAT=y CONFIG_MIPS32_O32=y -# CONFIG_MIPS32_N32 is not set +CONFIG_MIPS32_N32=y CONFIG_BINFMT_ELF32=y # diff --git a/arch/mips/ddb5xxx/common/prom.c b/arch/mips/ddb5xxx/common/prom.c index efef0f5..54a857b 100644 --- a/arch/mips/ddb5xxx/common/prom.c +++ b/arch/mips/ddb5xxx/common/prom.c @@ -59,9 +59,8 @@ #if defined(CONFIG_DDB5477) #endif } -unsigned long __init prom_free_prom_memory(void) +void __init prom_free_prom_memory(void) { - return 0; } #if defined(CONFIG_DDB5477) diff --git a/arch/mips/ddb5xxx/ddb5477/irq.c b/arch/mips/ddb5xxx/ddb5477/irq.c index a8bd2e6..2b23234 100644 --- a/arch/mips/ddb5xxx/ddb5477/irq.c +++ b/arch/mips/ddb5xxx/ddb5477/irq.c @@ -17,6 +17,7 @@ #include #include #include +#include #include #include #include @@ -73,7 +74,6 @@ set_pci_int_attr(u32 pci, u32 intn, u32 } extern void vrc5477_irq_init(u32 base); -extern void mips_cpu_irq_init(u32 base); static struct irqaction irq_cascade = { no_action, 0, CPU_MASK_NONE, "cascade", NULL, NULL }; void __init arch_init_irq(void) @@ -125,7 +125,7 @@ void __init arch_init_irq(void) /* init all controllers */ init_i8259_irqs(); - mips_cpu_irq_init(CPU_IRQ_BASE); + mips_cpu_irq_init(); vrc5477_irq_init(VRC5477_IRQ_BASE); @@ -146,8 +146,7 @@ u8 i8259_interrupt_ack(void) irq = *(volatile u8 *) KSEG1ADDR(DDB_PCI_IACK_BASE); ddb_out32(DDB_PCIINIT10, reg); - /* i8259.c set the base vector to be 0x0 */ - return irq + I8259_IRQ_BASE; + return irq; } /* * the first level int-handler will jump here if it is a vrc5477 irq @@ -177,7 +176,7 @@ #endif /* check for i8259 interrupts */ if (intStatus & (1 << VRC5477_I8259_CASCADE)) { int i8259_irq = i8259_interrupt_ack(); - do_IRQ(I8259_IRQ_BASE + i8259_irq); + do_IRQ(i8259_irq); return; } } diff --git a/arch/mips/ddb5xxx/ddb5477/irq_5477.c b/arch/mips/ddb5xxx/ddb5477/irq_5477.c index 96249aa..98c3b15 100644 --- a/arch/mips/ddb5xxx/ddb5477/irq_5477.c +++ b/arch/mips/ddb5xxx/ddb5477/irq_5477.c @@ -82,7 +82,7 @@ vrc5477_irq_end(unsigned int irq) } struct irq_chip vrc5477_irq_controller = { - .typename = "vrc5477_irq", + .name = "vrc5477_irq", .ack = vrc5477_irq_ack, .mask = vrc5477_irq_disable, .mask_ack = vrc5477_irq_ack, diff --git a/arch/mips/dec/Makefile b/arch/mips/dec/Makefile index ed181fd..8b790c2 100644 --- a/arch/mips/dec/Makefile +++ b/arch/mips/dec/Makefile @@ -6,6 +6,7 @@ obj-y := ecc-berr.o int-handler.o ioasi kn02-irq.o kn02xa-berr.o reset.o setup.o time.o obj-$(CONFIG_PROM_CONSOLE) += promcon.o +obj-$(CONFIG_TC) += tc.o obj-$(CONFIG_CPU_HAS_WB) += wbflush.o EXTRA_AFLAGS := $(CFLAGS) diff --git a/arch/mips/dec/int-handler.S b/arch/mips/dec/int-handler.S index b251ef8..00cecdc 100644 --- a/arch/mips/dec/int-handler.S +++ b/arch/mips/dec/int-handler.S @@ -264,9 +264,6 @@ #endif srlv t3,t1,t2 handle_it: - LONG_L s0, TI_REGS($28) - LONG_S sp, TI_REGS($28) - PTR_LA ra, ret_from_irq j dec_irq_dispatch nop @@ -277,7 +274,6 @@ fpu: #endif spurious: - PTR_LA ra, _ret_from_irq j spurious_interrupt nop END(plat_irq_dispatch) diff --git a/arch/mips/dec/ioasic-irq.c b/arch/mips/dec/ioasic-irq.c index 4c7cb40..3acb133 100644 --- a/arch/mips/dec/ioasic-irq.c +++ b/arch/mips/dec/ioasic-irq.c @@ -62,7 +62,7 @@ static inline void end_ioasic_irq(unsign } static struct irq_chip ioasic_irq_type = { - .typename = "IO-ASIC", + .name = "IO-ASIC", .ack = ack_ioasic_irq, .mask = mask_ioasic_irq, .mask_ack = ack_ioasic_irq, @@ -84,7 +84,7 @@ static inline void end_ioasic_dma_irq(un } static struct irq_chip ioasic_dma_irq_type = { - .typename = "IO-ASIC-DMA", + .name = "IO-ASIC-DMA", .ack = ack_ioasic_dma_irq, .mask = mask_ioasic_dma_irq, .mask_ack = ack_ioasic_dma_irq, diff --git a/arch/mips/dec/kn02-irq.c b/arch/mips/dec/kn02-irq.c index 916e46b..02439dc 100644 --- a/arch/mips/dec/kn02-irq.c +++ b/arch/mips/dec/kn02-irq.c @@ -58,7 +58,7 @@ static void ack_kn02_irq(unsigned int ir } static struct irq_chip kn02_irq_type = { - .typename = "KN02-CSR", + .name = "KN02-CSR", .ack = ack_kn02_irq, .mask = mask_kn02_irq, .mask_ack = ack_kn02_irq, diff --git a/arch/mips/dec/prom/identify.c b/arch/mips/dec/prom/identify.c index 81d5e87..c4e3c1e 100644 --- a/arch/mips/dec/prom/identify.c +++ b/arch/mips/dec/prom/identify.c @@ -88,6 +88,7 @@ static inline void prom_init_kn02(void) { dec_kn_slot_base = KN02_SLOT_BASE; dec_kn_slot_size = KN02_SLOT_SIZE; + dec_tc_bus = 1; dec_rtc_base = (void *)CKSEG1ADDR(dec_kn_slot_base + KN02_RTC); } @@ -96,6 +97,7 @@ static inline void prom_init_kn02xa(void { dec_kn_slot_base = KN02XA_SLOT_BASE; dec_kn_slot_size = IOASIC_SLOT_SIZE; + dec_tc_bus = 1; ioasic_base = (void *)CKSEG1ADDR(dec_kn_slot_base + IOASIC_IOCTL); dec_rtc_base = (void *)CKSEG1ADDR(dec_kn_slot_base + IOASIC_TOY); @@ -105,6 +107,7 @@ static inline void prom_init_kn03(void) { dec_kn_slot_base = KN03_SLOT_BASE; dec_kn_slot_size = IOASIC_SLOT_SIZE; + dec_tc_bus = 1; ioasic_base = (void *)CKSEG1ADDR(dec_kn_slot_base + IOASIC_IOCTL); dec_rtc_base = (void *)CKSEG1ADDR(dec_kn_slot_base + IOASIC_TOY); diff --git a/arch/mips/dec/prom/memory.c b/arch/mips/dec/prom/memory.c index 3aa01d2..5a557e2 100644 --- a/arch/mips/dec/prom/memory.c +++ b/arch/mips/dec/prom/memory.c @@ -92,9 +92,9 @@ void __init prom_meminit(u32 magic) rex_setup_memory_region(); } -unsigned long __init prom_free_prom_memory(void) +void __init prom_free_prom_memory(void) { - unsigned long addr, end; + unsigned long end; /* * Free everything below the kernel itself but leave @@ -114,16 +114,5 @@ #if defined(CONFIG_DECLANCE) || defined( #endif end = __pa(&_text); - addr = PAGE_SIZE; - while (addr < end) { - ClearPageReserved(virt_to_page(__va(addr))); - init_page_count(virt_to_page(__va(addr))); - free_page((unsigned long)__va(addr)); - addr += PAGE_SIZE; - } - - printk("Freeing unused PROM memory: %ldkb freed\n", - (end - PAGE_SIZE) >> 10); - - return end - PAGE_SIZE; + free_init_pages("unused PROM memory", PAGE_SIZE, end); } diff --git a/arch/mips/dec/setup.c b/arch/mips/dec/setup.c index d34032a..b8a5e75 100644 --- a/arch/mips/dec/setup.c +++ b/arch/mips/dec/setup.c @@ -53,6 +53,8 @@ unsigned long dec_kn_slot_base, dec_kn_s EXPORT_SYMBOL(dec_kn_slot_base); EXPORT_SYMBOL(dec_kn_slot_size); +int dec_tc_bus; + spinlock_t ioasic_ssr_lock; volatile u32 *ioasic_base; @@ -234,7 +236,7 @@ static void __init dec_init_kn01(void) memcpy(&cpu_mask_nr_tbl, &kn01_cpu_mask_nr_tbl, sizeof(kn01_cpu_mask_nr_tbl)); - mips_cpu_irq_init(DEC_CPU_IRQ_BASE); + mips_cpu_irq_init(); } /* dec_init_kn01 */ @@ -309,7 +311,7 @@ static void __init dec_init_kn230(void) memcpy(&cpu_mask_nr_tbl, &kn230_cpu_mask_nr_tbl, sizeof(kn230_cpu_mask_nr_tbl)); - mips_cpu_irq_init(DEC_CPU_IRQ_BASE); + mips_cpu_irq_init(); } /* dec_init_kn230 */ @@ -403,7 +405,7 @@ static void __init dec_init_kn02(void) memcpy(&asic_mask_nr_tbl, &kn02_asic_mask_nr_tbl, sizeof(kn02_asic_mask_nr_tbl)); - mips_cpu_irq_init(DEC_CPU_IRQ_BASE); + mips_cpu_irq_init(); init_kn02_irqs(KN02_IRQ_BASE); } /* dec_init_kn02 */ @@ -504,7 +506,7 @@ static void __init dec_init_kn02ba(void) memcpy(&asic_mask_nr_tbl, &kn02ba_asic_mask_nr_tbl, sizeof(kn02ba_asic_mask_nr_tbl)); - mips_cpu_irq_init(DEC_CPU_IRQ_BASE); + mips_cpu_irq_init(); init_ioasic_irqs(IO_IRQ_BASE); } /* dec_init_kn02ba */ @@ -601,7 +603,7 @@ static void __init dec_init_kn02ca(void) memcpy(&asic_mask_nr_tbl, &kn02ca_asic_mask_nr_tbl, sizeof(kn02ca_asic_mask_nr_tbl)); - mips_cpu_irq_init(DEC_CPU_IRQ_BASE); + mips_cpu_irq_init(); init_ioasic_irqs(IO_IRQ_BASE); } /* dec_init_kn02ca */ @@ -702,7 +704,7 @@ static void __init dec_init_kn03(void) memcpy(&asic_mask_nr_tbl, &kn03_asic_mask_nr_tbl, sizeof(kn03_asic_mask_nr_tbl)); - mips_cpu_irq_init(DEC_CPU_IRQ_BASE); + mips_cpu_irq_init(); init_ioasic_irqs(IO_IRQ_BASE); } /* dec_init_kn03 */ diff --git a/arch/mips/dec/tc.c b/arch/mips/dec/tc.c new file mode 100644 index 0000000..732027c --- /dev/null +++ b/arch/mips/dec/tc.c @@ -0,0 +1,95 @@ +/* + * TURBOchannel architecture calls. + * + * Copyright (c) Harald Koerfgen, 1998 + * Copyright (c) 2001, 2003, 2005, 2006 Maciej W. Rozycki + * Copyright (c) 2005 James Simmons + * + * This file is subject to the terms and conditions of the GNU + * General Public License. See the file "COPYING" in the main + * directory of this archive for more details. + */ +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include +#include + +/* + * Protected read byte from TURBOchannel slot space. + */ +int tc_preadb(u8 *valp, void __iomem *addr) +{ + return get_dbe(*valp, (u8 *)addr); +} + +/* + * Get TURBOchannel bus information as specified by the spec, plus + * the slot space base address and the number of slots. + */ +int __init tc_bus_get_info(struct tc_bus *tbus) +{ + if (!dec_tc_bus) + return -ENXIO; + + memcpy(&tbus->info, rex_gettcinfo(), sizeof(tbus->info)); + tbus->slot_base = CPHYSADDR((long)rex_slot_address(0)); + + switch (mips_machtype) { + case MACH_DS5000_200: + tbus->num_tcslots = 7; + break; + case MACH_DS5000_2X0: + case MACH_DS5900: + tbus->ext_slot_base = 0x20000000; + tbus->ext_slot_size = 0x20000000; + /* fall through */ + case MACH_DS5000_1XX: + tbus->num_tcslots = 3; + break; + case MACH_DS5000_XX: + tbus->num_tcslots = 2; + default: + break; + } + return 0; +} + +/* + * Get the IRQ for the specified slot. + */ +void __init tc_device_get_irq(struct tc_dev *tdev) +{ + switch (tdev->slot) { + case 0: + tdev->interrupt = dec_interrupt[DEC_IRQ_TC0]; + break; + case 1: + tdev->interrupt = dec_interrupt[DEC_IRQ_TC1]; + break; + case 2: + tdev->interrupt = dec_interrupt[DEC_IRQ_TC2]; + break; + /* + * Yuck! DS5000/200 onboard devices + */ + case 5: + tdev->interrupt = dec_interrupt[DEC_IRQ_TC5]; + break; + case 6: + tdev->interrupt = dec_interrupt[DEC_IRQ_TC6]; + break; + default: + tdev->interrupt = -1; + break; + } +} diff --git a/arch/mips/emma2rh/common/irq_emma2rh.c b/arch/mips/emma2rh/common/irq_emma2rh.c index 8d880f0..96df37b 100644 --- a/arch/mips/emma2rh/common/irq_emma2rh.c +++ b/arch/mips/emma2rh/common/irq_emma2rh.c @@ -57,7 +57,7 @@ static void emma2rh_irq_disable(unsigned } struct irq_chip emma2rh_irq_controller = { - .typename = "emma2rh_irq", + .name = "emma2rh_irq", .ack = emma2rh_irq_disable, .mask = emma2rh_irq_disable, .mask_ack = emma2rh_irq_disable, diff --git a/arch/mips/emma2rh/markeins/irq.c b/arch/mips/emma2rh/markeins/irq.c index c93369c..3299b6d 100644 --- a/arch/mips/emma2rh/markeins/irq.c +++ b/arch/mips/emma2rh/markeins/irq.c @@ -106,7 +106,7 @@ #define GPIO_PCI (0xf<<15) emma2rh_irq_init(EMMA2RH_IRQ_BASE); emma2rh_sw_irq_init(EMMA2RH_SW_IRQ_BASE); emma2rh_gpio_irq_init(EMMA2RH_GPIO_IRQ_BASE); - mips_cpu_irq_init(CPU_IRQ_BASE); + mips_cpu_irq_init(); /* setup cascade interrupts */ setup_irq(EMMA2RH_IRQ_BASE + EMMA2RH_SW_CASCADE, &irq_cascade); diff --git a/arch/mips/emma2rh/markeins/irq_markeins.c b/arch/mips/emma2rh/markeins/irq_markeins.c index 2116d9b..fba5c15 100644 --- a/arch/mips/emma2rh/markeins/irq_markeins.c +++ b/arch/mips/emma2rh/markeins/irq_markeins.c @@ -49,7 +49,7 @@ static void emma2rh_sw_irq_disable(unsig } struct irq_chip emma2rh_sw_irq_controller = { - .typename = "emma2rh_sw_irq", + .name = "emma2rh_sw_irq", .ack = emma2rh_sw_irq_disable, .mask = emma2rh_sw_irq_disable, .mask_ack = emma2rh_sw_irq_disable, @@ -115,7 +115,7 @@ static void emma2rh_gpio_irq_end(unsigne } struct irq_chip emma2rh_gpio_irq_controller = { - .typename = "emma2rh_gpio_irq", + .name = "emma2rh_gpio_irq", .ack = emma2rh_gpio_irq_ack, .mask = emma2rh_gpio_irq_disable, .mask_ack = emma2rh_gpio_irq_ack, diff --git a/arch/mips/gt64120/ev64120/irq.c b/arch/mips/gt64120/ev64120/irq.c index b3e5796..04572b9 100644 --- a/arch/mips/gt64120/ev64120/irq.c +++ b/arch/mips/gt64120/ev64120/irq.c @@ -88,7 +88,7 @@ static void end_ev64120_irq(unsigned int } static struct irq_chip ev64120_irq_type = { - .typename = "EV64120", + .name = "EV64120", .ack = disable_ev64120_irq, .mask = disable_ev64120_irq, .mask_ack = disable_ev64120_irq, diff --git a/arch/mips/gt64120/ev64120/setup.c b/arch/mips/gt64120/ev64120/setup.c index 99c8d42..477848c 100644 --- a/arch/mips/gt64120/ev64120/setup.c +++ b/arch/mips/gt64120/ev64120/setup.c @@ -59,9 +59,8 @@ extern void galileo_machine_power_off(vo */ extern struct pci_ops galileo_pci_ops; -unsigned long __init prom_free_prom_memory(void) +void __init prom_free_prom_memory(void) { - return 0; } /* diff --git a/arch/mips/gt64120/momenco_ocelot/dbg_io.c b/arch/mips/gt64120/momenco_ocelot/dbg_io.c index 2128684..32d6fb4 100644 --- a/arch/mips/gt64120/momenco_ocelot/dbg_io.c +++ b/arch/mips/gt64120/momenco_ocelot/dbg_io.c @@ -1,6 +1,4 @@ -#ifdef CONFIG_KGDB - #include /* For the serial port location and base baud */ /* --- CONFIG --- */ @@ -121,5 +119,3 @@ int putDebugChar(uint8 byte) UART16550_WRITE(OFS_SEND_BUFFER, byte); return 1; } - -#endif diff --git a/arch/mips/gt64120/momenco_ocelot/irq.c b/arch/mips/gt64120/momenco_ocelot/irq.c index d929440..2585d9d 100644 --- a/arch/mips/gt64120/momenco_ocelot/irq.c +++ b/arch/mips/gt64120/momenco_ocelot/irq.c @@ -90,6 +90,6 @@ void __init arch_init_irq(void) clear_c0_status(ST0_IM); local_irq_disable(); - mips_cpu_irq_init(0); - rm7k_cpu_irq_init(8); + mips_cpu_irq_init(); + rm7k_cpu_irq_init(); } diff --git a/arch/mips/gt64120/momenco_ocelot/prom.c b/arch/mips/gt64120/momenco_ocelot/prom.c index 8677b6d..78f393b 100644 --- a/arch/mips/gt64120/momenco_ocelot/prom.c +++ b/arch/mips/gt64120/momenco_ocelot/prom.c @@ -67,7 +67,6 @@ void __init prom_init(void) add_memory_region(0, 64 << 20, BOOT_MEM_RAM); } -unsigned long __init prom_free_prom_memory(void) +void __init prom_free_prom_memory(void) { - return 0; } diff --git a/arch/mips/gt64120/wrppmc/irq.c b/arch/mips/gt64120/wrppmc/irq.c index eedfc24..d3d9659 100644 --- a/arch/mips/gt64120/wrppmc/irq.c +++ b/arch/mips/gt64120/wrppmc/irq.c @@ -63,7 +63,7 @@ void gt64120_init_pic(void) void __init arch_init_irq(void) { /* IRQ 0 - 7 are for MIPS common irq_cpu controller */ - mips_cpu_irq_init(0); + mips_cpu_irq_init(); gt64120_init_pic(); } diff --git a/arch/mips/gt64120/wrppmc/setup.c b/arch/mips/gt64120/wrppmc/setup.c index 429afc4..121188d 100644 --- a/arch/mips/gt64120/wrppmc/setup.c +++ b/arch/mips/gt64120/wrppmc/setup.c @@ -93,9 +93,8 @@ void __init wrppmc_early_printk(const ch } #endif /* WRPPMC_EARLY_DEBUG */ -unsigned long __init prom_free_prom_memory(void) +void __init prom_free_prom_memory(void) { - return 0; } #ifdef CONFIG_SERIAL_8250 diff --git a/arch/mips/jazz/irq.c b/arch/mips/jazz/irq.c index f8d417b..295892e 100644 --- a/arch/mips/jazz/irq.c +++ b/arch/mips/jazz/irq.c @@ -40,7 +40,7 @@ void disable_r4030_irq(unsigned int irq) } static struct irq_chip r4030_irq_type = { - .typename = "R4030", + .name = "R4030", .ack = disable_r4030_irq, .mask = disable_r4030_irq, .mask_ack = disable_r4030_irq, diff --git a/arch/mips/jmr3927/common/prom.c b/arch/mips/jmr3927/common/prom.c index 5d5838f..aa481b7 100644 --- a/arch/mips/jmr3927/common/prom.c +++ b/arch/mips/jmr3927/common/prom.c @@ -75,7 +75,6 @@ void __init prom_init_cmdline(void) *cp = '\0'; } -unsigned long __init prom_free_prom_memory(void) +void __init prom_free_prom_memory(void) { - return 0; } diff --git a/arch/mips/jmr3927/rbhma3100/irq.c b/arch/mips/jmr3927/rbhma3100/irq.c index 3da49c5..7d2c203 100644 --- a/arch/mips/jmr3927/rbhma3100/irq.c +++ b/arch/mips/jmr3927/rbhma3100/irq.c @@ -439,7 +439,7 @@ #endif } static struct irq_chip jmr3927_irq_controller = { - .typename = "jmr3927_irq", + .name = "jmr3927_irq", .ack = jmr3927_irq_ack, .mask = jmr3927_irq_disable, .mask_ack = jmr3927_irq_ack, diff --git a/arch/mips/jmr3927/rbhma3100/setup.c b/arch/mips/jmr3927/rbhma3100/setup.c index 138f25e..7ca3d6d 100644 --- a/arch/mips/jmr3927/rbhma3100/setup.c +++ b/arch/mips/jmr3927/rbhma3100/setup.c @@ -434,7 +434,7 @@ #endif /* DMA */ tx3927_dmaptr->mcr = 0; - for (i = 0; i < sizeof(tx3927_dmaptr->ch) / sizeof(tx3927_dmaptr->ch[0]); i++) { + for (i = 0; i < ARRAY_SIZE(tx3927_dmaptr->ch); i++) { /* reset channel */ tx3927_dmaptr->ch[i].ccr = TX3927_DMA_CCR_CHRST; tx3927_dmaptr->ch[i].ccr = 0; diff --git a/arch/mips/kernel/Makefile b/arch/mips/kernel/Makefile index bbbb8d7..1bf2c84 100644 --- a/arch/mips/kernel/Makefile +++ b/arch/mips/kernel/Makefile @@ -14,8 +14,6 @@ binfmt_irix-objs := irixelf.o irixinv.o obj-$(CONFIG_STACKTRACE) += stacktrace.o obj-$(CONFIG_MODULES) += mips_ksyms.o module.o -obj-$(CONFIG_APM) += apm.o - obj-$(CONFIG_CPU_R3000) += r2300_fpu.o r2300_switch.o obj-$(CONFIG_CPU_TX39XX) += r2300_fpu.o r2300_switch.o obj-$(CONFIG_CPU_TX49XX) += r4k_fpu.o r4k_switch.o diff --git a/arch/mips/kernel/apm.c b/arch/mips/kernel/apm.c deleted file mode 100644 index ba16d07..0000000 --- a/arch/mips/kernel/apm.c +++ /dev/null @@ -1,604 +0,0 @@ -/* - * bios-less APM driver for MIPS Linux - * Jamey Hicks - * adapted from the APM BIOS driver for Linux by Stephen Rothwell (sfr@linuxcare.com) - * - * APM 1.2 Reference: - * Intel Corporation, Microsoft Corporation. Advanced Power Management - * (APM) BIOS Interface Specification, Revision 1.2, February 1996. - * - * [This document is available from Microsoft at: - * http://www.microsoft.com/hwdev/busbios/amp_12.htm] - */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include /* apm_power_info */ -#include - -/* - * The apm_bios device is one of the misc char devices. - * This is its minor number. - */ -#define APM_MINOR_DEV 134 - -/* - * See Documentation/Config.help for the configuration options. - * - * Various options can be changed at boot time as follows: - * (We allow underscores for compatibility with the modules code) - * apm=on/off enable/disable APM - */ - -/* - * Maximum number of events stored - */ -#define APM_MAX_EVENTS 16 - -struct apm_queue { - unsigned int event_head; - unsigned int event_tail; - apm_event_t events[APM_MAX_EVENTS]; -}; - -/* - * The per-file APM data - */ -struct apm_user { - struct list_head list; - - unsigned int suser: 1; - unsigned int writer: 1; - unsigned int reader: 1; - - int suspend_result; - unsigned int suspend_state; -#define SUSPEND_NONE 0 /* no suspend pending */ -#define SUSPEND_PENDING 1 /* suspend pending read */ -#define SUSPEND_READ 2 /* suspend read, pending ack */ -#define SUSPEND_ACKED 3 /* suspend acked */ -#define SUSPEND_DONE 4 /* suspend completed */ - - struct apm_queue queue; -}; - -/* - * Local variables - */ -static int suspends_pending; -static int apm_disabled; -static int mips_apm_active; - -static DECLARE_WAIT_QUEUE_HEAD(apm_waitqueue); -static DECLARE_WAIT_QUEUE_HEAD(apm_suspend_waitqueue); - -/* - * This is a list of everyone who has opened /dev/apm_bios - */ -static DECLARE_RWSEM(user_list_lock); -static LIST_HEAD(apm_user_list); - -/* - * kapmd info. kapmd provides us a process context to handle - * "APM" events within - specifically necessary if we're going - * to be suspending the system. - */ -static DECLARE_WAIT_QUEUE_HEAD(kapmd_wait); -static DECLARE_COMPLETION(kapmd_exit); -static DEFINE_SPINLOCK(kapmd_queue_lock); -static struct apm_queue kapmd_queue; - - -static const char driver_version[] = "1.13"; /* no spaces */ - - - -/* - * Compatibility cruft until the IPAQ people move over to the new - * interface. - */ -static void __apm_get_power_status(struct apm_power_info *info) -{ -} - -/* - * This allows machines to provide their own "apm get power status" function. - */ -void (*apm_get_power_status)(struct apm_power_info *) = __apm_get_power_status; -EXPORT_SYMBOL(apm_get_power_status); - - -/* - * APM event queue management. - */ -static inline int queue_empty(struct apm_queue *q) -{ - return q->event_head == q->event_tail; -} - -static inline apm_event_t queue_get_event(struct apm_queue *q) -{ - q->event_tail = (q->event_tail + 1) % APM_MAX_EVENTS; - return q->events[q->event_tail]; -} - -static void queue_add_event(struct apm_queue *q, apm_event_t event) -{ - q->event_head = (q->event_head + 1) % APM_MAX_EVENTS; - if (q->event_head == q->event_tail) { - static int notified; - - if (notified++ == 0) - printk(KERN_ERR "apm: an event queue overflowed\n"); - q->event_tail = (q->event_tail + 1) % APM_MAX_EVENTS; - } - q->events[q->event_head] = event; -} - -static void queue_event_one_user(struct apm_user *as, apm_event_t event) -{ - if (as->suser && as->writer) { - switch (event) { - case APM_SYS_SUSPEND: - case APM_USER_SUSPEND: - /* - * If this user already has a suspend pending, - * don't queue another one. - */ - if (as->suspend_state != SUSPEND_NONE) - return; - - as->suspend_state = SUSPEND_PENDING; - suspends_pending++; - break; - } - } - queue_add_event(&as->queue, event); -} - -static void queue_event(apm_event_t event, struct apm_user *sender) -{ - struct apm_user *as; - - down_read(&user_list_lock); - list_for_each_entry(as, &apm_user_list, list) { - if (as != sender && as->reader) - queue_event_one_user(as, event); - } - up_read(&user_list_lock); - wake_up_interruptible(&apm_waitqueue); -} - -static void apm_suspend(void) -{ - struct apm_user *as; - int err = pm_suspend(PM_SUSPEND_MEM); - - /* - * Anyone on the APM queues will think we're still suspended. - * Send a message so everyone knows we're now awake again. - */ - queue_event(APM_NORMAL_RESUME, NULL); - - /* - * Finally, wake up anyone who is sleeping on the suspend. - */ - down_read(&user_list_lock); - list_for_each_entry(as, &apm_user_list, list) { - as->suspend_result = err; - as->suspend_state = SUSPEND_DONE; - } - up_read(&user_list_lock); - - wake_up(&apm_suspend_waitqueue); -} - -static ssize_t apm_read(struct file *fp, char __user *buf, size_t count, loff_t *ppos) -{ - struct apm_user *as = fp->private_data; - apm_event_t event; - int i = count, ret = 0; - - if (count < sizeof(apm_event_t)) - return -EINVAL; - - if (queue_empty(&as->queue) && fp->f_flags & O_NONBLOCK) - return -EAGAIN; - - wait_event_interruptible(apm_waitqueue, !queue_empty(&as->queue)); - - while ((i >= sizeof(event)) && !queue_empty(&as->queue)) { - event = queue_get_event(&as->queue); - - ret = -EFAULT; - if (copy_to_user(buf, &event, sizeof(event))) - break; - - if (event == APM_SYS_SUSPEND || event == APM_USER_SUSPEND) - as->suspend_state = SUSPEND_READ; - - buf += sizeof(event); - i -= sizeof(event); - } - - if (i < count) - ret = count - i; - - return ret; -} - -static unsigned int apm_poll(struct file *fp, poll_table * wait) -{ - struct apm_user *as = fp->private_data; - - poll_wait(fp, &apm_waitqueue, wait); - return queue_empty(&as->queue) ? 0 : POLLIN | POLLRDNORM; -} - -/* - * apm_ioctl - handle APM ioctl - * - * APM_IOC_SUSPEND - * This IOCTL is overloaded, and performs two functions. It is used to: - * - initiate a suspend - * - acknowledge a suspend read from /dev/apm_bios. - * Only when everyone who has opened /dev/apm_bios with write permission - * has acknowledge does the actual suspend happen. - */ -static int -apm_ioctl(struct inode * inode, struct file *filp, unsigned int cmd, unsigned long arg) -{ - struct apm_user *as = filp->private_data; - unsigned long flags; - int err = -EINVAL; - - if (!as->suser || !as->writer) - return -EPERM; - - switch (cmd) { - case APM_IOC_SUSPEND: - as->suspend_result = -EINTR; - - if (as->suspend_state == SUSPEND_READ) { - /* - * If we read a suspend command from /dev/apm_bios, - * then the corresponding APM_IOC_SUSPEND ioctl is - * interpreted as an acknowledge. - */ - as->suspend_state = SUSPEND_ACKED; - suspends_pending--; - } else { - /* - * Otherwise it is a request to suspend the system. - * Queue an event for all readers, and expect an - * acknowledge from all writers who haven't already - * acknowledged. - */ - queue_event(APM_USER_SUSPEND, as); - } - - /* - * If there are no further acknowledges required, suspend - * the system. - */ - if (suspends_pending == 0) - apm_suspend(); - - /* - * Wait for the suspend/resume to complete. If there are - * pending acknowledges, we wait here for them. - * - * Note that we need to ensure that the PM subsystem does - * not kick us out of the wait when it suspends the threads. - */ - flags = current->flags; - current->flags |= PF_NOFREEZE; - - /* - * Note: do not allow a thread which is acking the suspend - * to escape until the resume is complete. - */ - if (as->suspend_state == SUSPEND_ACKED) - wait_event(apm_suspend_waitqueue, - as->suspend_state == SUSPEND_DONE); - else - wait_event_interruptible(apm_suspend_waitqueue, - as->suspend_state == SUSPEND_DONE); - - current->flags = flags; - err = as->suspend_result; - as->suspend_state = SUSPEND_NONE; - break; - } - - return err; -} - -static int apm_release(struct inode * inode, struct file * filp) -{ - struct apm_user *as = filp->private_data; - filp->private_data = NULL; - - down_write(&user_list_lock); - list_del(&as->list); - up_write(&user_list_lock); - - /* - * We are now unhooked from the chain. As far as new - * events are concerned, we no longer exist. However, we - * need to balance suspends_pending, which means the - * possibility of sleeping. - */ - if (as->suspend_state != SUSPEND_NONE) { - suspends_pending -= 1; - if (suspends_pending == 0) - apm_suspend(); - } - - kfree(as); - return 0; -} - -static int apm_open(struct inode * inode, struct file * filp) -{ - struct apm_user *as; - - as = kzalloc(sizeof(*as), GFP_KERNEL); - if (as) { - /* - * XXX - this is a tiny bit broken, when we consider BSD - * process accounting. If the device is opened by root, we - * instantly flag that we used superuser privs. Who knows, - * we might close the device immediately without doing a - * privileged operation -- cevans - */ - as->suser = capable(CAP_SYS_ADMIN); - as->writer = (filp->f_mode & FMODE_WRITE) == FMODE_WRITE; - as->reader = (filp->f_mode & FMODE_READ) == FMODE_READ; - - down_write(&user_list_lock); - list_add(&as->list, &apm_user_list); - up_write(&user_list_lock); - - filp->private_data = as; - } - - return as ? 0 : -ENOMEM; -} - -static struct file_operations apm_bios_fops = { - .owner = THIS_MODULE, - .read = apm_read, - .poll = apm_poll, - .ioctl = apm_ioctl, - .open = apm_open, - .release = apm_release, -}; - -static struct miscdevice apm_device = { - .minor = APM_MINOR_DEV, - .name = "apm_bios", - .fops = &apm_bios_fops -}; - - -#ifdef CONFIG_PROC_FS -/* - * Arguments, with symbols from linux/apm_bios.h. - * - * 0) Linux driver version (this will change if format changes) - * 1) APM BIOS Version. Usually 1.0, 1.1 or 1.2. - * 2) APM flags from APM Installation Check (0x00): - * bit 0: APM_16_BIT_SUPPORT - * bit 1: APM_32_BIT_SUPPORT - * bit 2: APM_IDLE_SLOWS_CLOCK - * bit 3: APM_BIOS_DISABLED - * bit 4: APM_BIOS_DISENGAGED - * 3) AC line status - * 0x00: Off-line - * 0x01: On-line - * 0x02: On backup power (BIOS >= 1.1 only) - * 0xff: Unknown - * 4) Battery status - * 0x00: High - * 0x01: Low - * 0x02: Critical - * 0x03: Charging - * 0x04: Selected battery not present (BIOS >= 1.2 only) - * 0xff: Unknown - * 5) Battery flag - * bit 0: High - * bit 1: Low - * bit 2: Critical - * bit 3: Charging - * bit 7: No system battery - * 0xff: Unknown - * 6) Remaining battery life (percentage of charge): - * 0-100: valid - * -1: Unknown - * 7) Remaining battery life (time units): - * Number of remaining minutes or seconds - * -1: Unknown - * 8) min = minutes; sec = seconds - */ -static int apm_get_info(char *buf, char **start, off_t fpos, int length) -{ - struct apm_power_info info; - char *units; - int ret; - - info.ac_line_status = 0xff; - info.battery_status = 0xff; - info.battery_flag = 0xff; - info.battery_life = -1; - info.time = -1; - info.units = -1; - - if (apm_get_power_status) - apm_get_power_status(&info); - - switch (info.units) { - default: units = "?"; break; - case 0: units = "min"; break; - case 1: units = "sec"; break; - } - - ret = sprintf(buf, "%s 1.2 0x%02x 0x%02x 0x%02x 0x%02x %d%% %d %s\n", - driver_version, APM_32_BIT_SUPPORT, - info.ac_line_status, info.battery_status, - info.battery_flag, info.battery_life, - info.time, units); - - return ret; -} -#endif - -static int kapmd(void *arg) -{ - daemonize("kapmd"); - current->flags |= PF_NOFREEZE; - - do { - apm_event_t event; - - wait_event_interruptible(kapmd_wait, - !queue_empty(&kapmd_queue) || !mips_apm_active); - - if (!mips_apm_active) - break; - - spin_lock_irq(&kapmd_queue_lock); - event = 0; - if (!queue_empty(&kapmd_queue)) - event = queue_get_event(&kapmd_queue); - spin_unlock_irq(&kapmd_queue_lock); - - switch (event) { - case 0: - break; - - case APM_LOW_BATTERY: - case APM_POWER_STATUS_CHANGE: - queue_event(event, NULL); - break; - - case APM_USER_SUSPEND: - case APM_SYS_SUSPEND: - queue_event(event, NULL); - if (suspends_pending == 0) - apm_suspend(); - break; - - case APM_CRITICAL_SUSPEND: - apm_suspend(); - break; - } - } while (1); - - complete_and_exit(&kapmd_exit, 0); -} - -static int __init apm_init(void) -{ - int ret; - - if (apm_disabled) { - printk(KERN_NOTICE "apm: disabled on user request.\n"); - return -ENODEV; - } - - mips_apm_active = 1; - - ret = kernel_thread(kapmd, NULL, CLONE_KERNEL); - if (ret < 0) { - mips_apm_active = 0; - return ret; - } - -#ifdef CONFIG_PROC_FS - create_proc_info_entry("apm", 0, NULL, apm_get_info); -#endif - - ret = misc_register(&apm_device); - if (ret != 0) { - remove_proc_entry("apm", NULL); - - mips_apm_active = 0; - wake_up(&kapmd_wait); - wait_for_completion(&kapmd_exit); - } - - return ret; -} - -static void __exit apm_exit(void) -{ - misc_deregister(&apm_device); - remove_proc_entry("apm", NULL); - - mips_apm_active = 0; - wake_up(&kapmd_wait); - wait_for_completion(&kapmd_exit); -} - -module_init(apm_init); -module_exit(apm_exit); - -MODULE_AUTHOR("Stephen Rothwell"); -MODULE_DESCRIPTION("Advanced Power Management"); -MODULE_LICENSE("GPL"); - -#ifndef MODULE -static int __init apm_setup(char *str) -{ - while ((str != NULL) && (*str != '\0')) { - if (strncmp(str, "off", 3) == 0) - apm_disabled = 1; - if (strncmp(str, "on", 2) == 0) - apm_disabled = 0; - str = strchr(str, ','); - if (str != NULL) - str += strspn(str, ", \t"); - } - return 1; -} - -__setup("apm=", apm_setup); -#endif - -/** - * apm_queue_event - queue an APM event for kapmd - * @event: APM event - * - * Queue an APM event for kapmd to process and ultimately take the - * appropriate action. Only a subset of events are handled: - * %APM_LOW_BATTERY - * %APM_POWER_STATUS_CHANGE - * %APM_USER_SUSPEND - * %APM_SYS_SUSPEND - * %APM_CRITICAL_SUSPEND - */ -void apm_queue_event(apm_event_t event) -{ - unsigned long flags; - - spin_lock_irqsave(&kapmd_queue_lock, flags); - queue_add_event(&kapmd_queue, event); - spin_unlock_irqrestore(&kapmd_queue_lock, flags); - - wake_up_interruptible(&kapmd_wait); -} -EXPORT_SYMBOL(apm_queue_event); diff --git a/arch/mips/kernel/asm-offsets.c b/arch/mips/kernel/asm-offsets.c index ff88b06..c0b089d 100644 --- a/arch/mips/kernel/asm-offsets.c +++ b/arch/mips/kernel/asm-offsets.c @@ -234,10 +234,6 @@ void output_mm_defines(void) constant("#define _PMD_SHIFT ", PMD_SHIFT); constant("#define _PGDIR_SHIFT ", PGDIR_SHIFT); linefeed; - constant("#define _PGD_ORDER ", PGD_ORDER); - constant("#define _PMD_ORDER ", PMD_ORDER); - constant("#define _PTE_ORDER ", PTE_ORDER); - linefeed; constant("#define _PTRS_PER_PGD ", PTRS_PER_PGD); constant("#define _PTRS_PER_PMD ", PTRS_PER_PMD); constant("#define _PTRS_PER_PTE ", PTRS_PER_PTE); @@ -253,7 +249,6 @@ void output_sc_defines(void) offset("#define SC_MDHI ", struct sigcontext, sc_mdhi); offset("#define SC_MDLO ", struct sigcontext, sc_mdlo); offset("#define SC_PC ", struct sigcontext, sc_pc); - offset("#define SC_STATUS ", struct sigcontext, sc_status); offset("#define SC_FPC_CSR ", struct sigcontext, sc_fpc_csr); offset("#define SC_FPC_EIR ", struct sigcontext, sc_fpc_eir); offset("#define SC_HI1 ", struct sigcontext, sc_hi1); diff --git a/arch/mips/kernel/cpu-probe.c b/arch/mips/kernel/cpu-probe.c index 442839e..f59ef27 100644 --- a/arch/mips/kernel/cpu-probe.c +++ b/arch/mips/kernel/cpu-probe.c @@ -565,7 +565,7 @@ static inline unsigned int decode_config if (config3 & MIPS_CONF3_VEIC) c->options |= MIPS_CPU_VEIC; if (config3 & MIPS_CONF3_MT) - c->ases |= MIPS_ASE_MIPSMT; + c->ases |= MIPS_ASE_MIPSMT; return config3 & MIPS_CONF_M; } diff --git a/arch/mips/kernel/entry.S b/arch/mips/kernel/entry.S index f10b6a1..0b78fcb 100644 --- a/arch/mips/kernel/entry.S +++ b/arch/mips/kernel/entry.S @@ -21,24 +21,21 @@ #include #endif #ifndef CONFIG_PREEMPT - .macro preempt_stop - local_irq_disable - .endm #define resume_kernel restore_all +#else +#define __ret_from_irq ret_from_exception #endif .text .align 5 -FEXPORT(ret_from_irq) - LONG_S s0, TI_REGS($28) -#ifdef CONFIG_PREEMPT -FEXPORT(ret_from_exception) -#else - b _ret_from_irq +#ifndef CONFIG_PREEMPT FEXPORT(ret_from_exception) - preempt_stop + local_irq_disable # preempt stop + b __ret_from_irq #endif -FEXPORT(_ret_from_irq) +FEXPORT(ret_from_irq) + LONG_S s0, TI_REGS($28) +FEXPORT(__ret_from_irq) LONG_L t0, PT_STATUS(sp) # returning to kernel mode? andi t0, t0, KU_USER beqz t0, resume_kernel diff --git a/arch/mips/kernel/gdb-stub.c b/arch/mips/kernel/gdb-stub.c index 719d269..7bc8820 100644 --- a/arch/mips/kernel/gdb-stub.c +++ b/arch/mips/kernel/gdb-stub.c @@ -505,13 +505,13 @@ void show_gdbregs(struct gdb_regs * regs */ printk("$0 : %08lx %08lx %08lx %08lx %08lx %08lx %08lx %08lx\n", regs->reg0, regs->reg1, regs->reg2, regs->reg3, - regs->reg4, regs->reg5, regs->reg6, regs->reg7); + regs->reg4, regs->reg5, regs->reg6, regs->reg7); printk("$8 : %08lx %08lx %08lx %08lx %08lx %08lx %08lx %08lx\n", regs->reg8, regs->reg9, regs->reg10, regs->reg11, - regs->reg12, regs->reg13, regs->reg14, regs->reg15); + regs->reg12, regs->reg13, regs->reg14, regs->reg15); printk("$16: %08lx %08lx %08lx %08lx %08lx %08lx %08lx %08lx\n", regs->reg16, regs->reg17, regs->reg18, regs->reg19, - regs->reg20, regs->reg21, regs->reg22, regs->reg23); + regs->reg20, regs->reg21, regs->reg22, regs->reg23); printk("$24: %08lx %08lx %08lx %08lx %08lx %08lx %08lx %08lx\n", regs->reg24, regs->reg25, regs->reg26, regs->reg27, regs->reg28, regs->reg29, regs->reg30, regs->reg31); diff --git a/arch/mips/kernel/head.S b/arch/mips/kernel/head.S index 9a7811d..6f57ca4 100644 --- a/arch/mips/kernel/head.S +++ b/arch/mips/kernel/head.S @@ -231,28 +231,3 @@ #endif /* CONFIG_MIPS_MT_SMTC */ #endif /* CONFIG_SMP */ __FINIT - - .comm kernelsp, NR_CPUS * 8, 8 - .comm pgd_current, NR_CPUS * 8, 8 - - .comm fw_arg0, SZREG, SZREG # firmware arguments - .comm fw_arg1, SZREG, SZREG - .comm fw_arg2, SZREG, SZREG - .comm fw_arg3, SZREG, SZREG - - .macro page name, order - .comm \name, (_PAGE_SIZE << \order), (_PAGE_SIZE << \order) - .endm - - /* - * On 64-bit we've got three-level pagetables with a slightly - * different layout ... - */ - page swapper_pg_dir, _PGD_ORDER -#ifdef CONFIG_64BIT -#if defined(CONFIG_MODULES) && !defined(CONFIG_BUILD_ELF64) - page module_pg_dir, _PGD_ORDER -#endif - page invalid_pmd_table, _PMD_ORDER -#endif - page invalid_pte_table, _PTE_ORDER diff --git a/arch/mips/kernel/i8259.c b/arch/mips/kernel/i8259.c index b59a676..b33ba6c 100644 --- a/arch/mips/kernel/i8259.c +++ b/arch/mips/kernel/i8259.c @@ -54,9 +54,11 @@ #define cached_slave_mask (cached_irq_ma void disable_8259A_irq(unsigned int irq) { - unsigned int mask = 1 << irq; + unsigned int mask; unsigned long flags; + irq -= I8259A_IRQ_BASE; + mask = 1 << irq; spin_lock_irqsave(&i8259A_lock, flags); cached_irq_mask |= mask; if (irq & 8) @@ -68,9 +70,11 @@ void disable_8259A_irq(unsigned int irq) void enable_8259A_irq(unsigned int irq) { - unsigned int mask = ~(1 << irq); + unsigned int mask; unsigned long flags; + irq -= I8259A_IRQ_BASE; + mask = ~(1 << irq); spin_lock_irqsave(&i8259A_lock, flags); cached_irq_mask &= mask; if (irq & 8) @@ -82,10 +86,12 @@ void enable_8259A_irq(unsigned int irq) int i8259A_irq_pending(unsigned int irq) { - unsigned int mask = 1 << irq; + unsigned int mask; unsigned long flags; int ret; + irq -= I8259A_IRQ_BASE; + mask = 1 << irq; spin_lock_irqsave(&i8259A_lock, flags); if (irq < 8) ret = inb(PIC_MASTER_CMD) & mask; @@ -134,9 +140,11 @@ static inline int i8259A_irq_real(unsign */ void mask_and_ack_8259A(unsigned int irq) { - unsigned int irqmask = 1 << irq; + unsigned int irqmask; unsigned long flags; + irq -= I8259A_IRQ_BASE; + irqmask = 1 << irq; spin_lock_irqsave(&i8259A_lock, flags); /* * Lightweight spurious IRQ detection. We do not want @@ -169,8 +177,8 @@ handle_real_irq: outb(0x60+irq,PIC_MASTER_CMD); /* 'Specific EOI to master */ } #ifdef CONFIG_MIPS_MT_SMTC - if (irq_hwmask[irq] & ST0_IM) - set_c0_status(irq_hwmask[irq] & ST0_IM); + if (irq_hwmask[irq] & ST0_IM) + set_c0_status(irq_hwmask[irq] & ST0_IM); #endif /* CONFIG_MIPS_MT_SMTC */ spin_unlock_irqrestore(&i8259A_lock, flags); return; @@ -322,8 +330,8 @@ void __init init_i8259_irqs (void) init_8259A(0); - for (i = 0; i < 16; i++) + for (i = I8259A_IRQ_BASE; i < I8259A_IRQ_BASE + 16; i++) set_irq_chip_and_handler(i, &i8259A_chip, handle_level_irq); - setup_irq(PIC_CASCADE_IR, &irq2); + setup_irq(I8259A_IRQ_BASE + PIC_CASCADE_IR, &irq2); } diff --git a/arch/mips/kernel/irixelf.c b/arch/mips/kernel/irixelf.c index 37cad5d..3cc25c0 100644 --- a/arch/mips/kernel/irixelf.c +++ b/arch/mips/kernel/irixelf.c @@ -10,6 +10,8 @@ * Copyright (C) 1996 - 2004 David S. Miller * Copyright (C) 2004 - 2005 Steven J. Hill */ +#undef DEBUG + #include #include #include @@ -40,8 +42,6 @@ #define DLINFO_ITEMS 12 #include -#undef DEBUG - static int load_irix_binary(struct linux_binprm * bprm, struct pt_regs * regs); static int load_irix_library(struct file *); static int irix_core_dump(long signr, struct pt_regs * regs, @@ -52,72 +52,102 @@ static struct linux_binfmt irix_format = irix_core_dump, PAGE_SIZE }; -#ifdef DEBUG /* Debugging routines. */ static char *get_elf_p_type(Elf32_Word p_type) { - int i = (int) p_type; - - switch(i) { - case PT_NULL: return("PT_NULL"); break; - case PT_LOAD: return("PT_LOAD"); break; - case PT_DYNAMIC: return("PT_DYNAMIC"); break; - case PT_INTERP: return("PT_INTERP"); break; - case PT_NOTE: return("PT_NOTE"); break; - case PT_SHLIB: return("PT_SHLIB"); break; - case PT_PHDR: return("PT_PHDR"); break; - case PT_LOPROC: return("PT_LOPROC/REGINFO"); break; - case PT_HIPROC: return("PT_HIPROC"); break; - default: return("PT_BOGUS"); break; +#ifdef DEBUG + switch (p_type) { + case PT_NULL: + return "PT_NULL"; + break; + + case PT_LOAD: + return "PT_LOAD"; + break; + + case PT_DYNAMIC: + return "PT_DYNAMIC"; + break; + + case PT_INTERP: + return "PT_INTERP"; + break; + + case PT_NOTE: + return "PT_NOTE"; + break; + + case PT_SHLIB: + return "PT_SHLIB"; + break; + + case PT_PHDR: + return "PT_PHDR"; + break; + + case PT_LOPROC: + return "PT_LOPROC/REGINFO"; + break; + + case PT_HIPROC: + return "PT_HIPROC"; + break; + + default: + return "PT_BOGUS"; + break; } +#endif } static void print_elfhdr(struct elfhdr *ehp) { int i; - printk("ELFHDR: e_ident<"); - for(i = 0; i < (EI_NIDENT - 1); i++) printk("%x ", ehp->e_ident[i]); - printk("%x>\n", ehp->e_ident[i]); - printk(" e_type[%04x] e_machine[%04x] e_version[%08lx]\n", - (unsigned short) ehp->e_type, (unsigned short) ehp->e_machine, - (unsigned long) ehp->e_version); - printk(" e_entry[%08lx] e_phoff[%08lx] e_shoff[%08lx] " - "e_flags[%08lx]\n", - (unsigned long) ehp->e_entry, (unsigned long) ehp->e_phoff, - (unsigned long) ehp->e_shoff, (unsigned long) ehp->e_flags); - printk(" e_ehsize[%04x] e_phentsize[%04x] e_phnum[%04x]\n", - (unsigned short) ehp->e_ehsize, (unsigned short) ehp->e_phentsize, - (unsigned short) ehp->e_phnum); - printk(" e_shentsize[%04x] e_shnum[%04x] e_shstrndx[%04x]\n", - (unsigned short) ehp->e_shentsize, (unsigned short) ehp->e_shnum, - (unsigned short) ehp->e_shstrndx); + pr_debug("ELFHDR: e_ident<"); + for (i = 0; i < (EI_NIDENT - 1); i++) + pr_debug("%x ", ehp->e_ident[i]); + pr_debug("%x>\n", ehp->e_ident[i]); + pr_debug(" e_type[%04x] e_machine[%04x] e_version[%08lx]\n", + (unsigned short) ehp->e_type, (unsigned short) ehp->e_machine, + (unsigned long) ehp->e_version); + pr_debug(" e_entry[%08lx] e_phoff[%08lx] e_shoff[%08lx] " + "e_flags[%08lx]\n", + (unsigned long) ehp->e_entry, (unsigned long) ehp->e_phoff, + (unsigned long) ehp->e_shoff, (unsigned long) ehp->e_flags); + pr_debug(" e_ehsize[%04x] e_phentsize[%04x] e_phnum[%04x]\n", + (unsigned short) ehp->e_ehsize, + (unsigned short) ehp->e_phentsize, + (unsigned short) ehp->e_phnum); + pr_debug(" e_shentsize[%04x] e_shnum[%04x] e_shstrndx[%04x]\n", + (unsigned short) ehp->e_shentsize, + (unsigned short) ehp->e_shnum, + (unsigned short) ehp->e_shstrndx); } static void print_phdr(int i, struct elf_phdr *ep) { - printk("PHDR[%d]: p_type[%s] p_offset[%08lx] p_vaddr[%08lx] " - "p_paddr[%08lx]\n", i, get_elf_p_type(ep->p_type), - (unsigned long) ep->p_offset, (unsigned long) ep->p_vaddr, - (unsigned long) ep->p_paddr); - printk(" p_filesz[%08lx] p_memsz[%08lx] p_flags[%08lx] " - "p_align[%08lx]\n", (unsigned long) ep->p_filesz, - (unsigned long) ep->p_memsz, (unsigned long) ep->p_flags, - (unsigned long) ep->p_align); + pr_debug("PHDR[%d]: p_type[%s] p_offset[%08lx] p_vaddr[%08lx] " + "p_paddr[%08lx]\n", i, get_elf_p_type(ep->p_type), + (unsigned long) ep->p_offset, (unsigned long) ep->p_vaddr, + (unsigned long) ep->p_paddr); + pr_debug(" p_filesz[%08lx] p_memsz[%08lx] p_flags[%08lx] " + "p_align[%08lx]\n", (unsigned long) ep->p_filesz, + (unsigned long) ep->p_memsz, (unsigned long) ep->p_flags, + (unsigned long) ep->p_align); } static void dump_phdrs(struct elf_phdr *ep, int pnum) { int i; - for(i = 0; i < pnum; i++, ep++) { - if((ep->p_type == PT_LOAD) || - (ep->p_type == PT_INTERP) || - (ep->p_type == PT_PHDR)) + for (i = 0; i < pnum; i++, ep++) { + if ((ep->p_type == PT_LOAD) || + (ep->p_type == PT_INTERP) || + (ep->p_type == PT_PHDR)) print_phdr(i, ep); } } -#endif /* DEBUG */ static void set_brk(unsigned long start, unsigned long end) { @@ -156,11 +186,10 @@ static unsigned long * create_irix_table elf_addr_t *envp; elf_addr_t *sp, *csp; -#ifdef DEBUG - printk("create_irix_tables: p[%p] argc[%d] envc[%d] " - "load_addr[%08x] interp_load_addr[%08x]\n", - p, argc, envc, load_addr, interp_load_addr); -#endif + pr_debug("create_irix_tables: p[%p] argc[%d] envc[%d] " + "load_addr[%08x] interp_load_addr[%08x]\n", + p, argc, envc, load_addr, interp_load_addr); + sp = (elf_addr_t *) (~15UL & (unsigned long) p); csp = sp; csp -= exec ? DLINFO_ITEMS*2 : 2; @@ -181,7 +210,7 @@ #define NEW_AUX_ENT(nr, id, val) \ sp -= 2; NEW_AUX_ENT(0, AT_NULL, 0); - if(exec) { + if (exec) { sp -= 11*2; NEW_AUX_ENT (0, AT_PHDR, load_addr + exec->e_phoff); @@ -245,9 +274,7 @@ static unsigned int load_irix_interp(str last_bss = 0; error = load_addr = 0; -#ifdef DEBUG print_elfhdr(interp_elf_ex); -#endif /* First of all, some simple consistency checks */ if ((interp_elf_ex->e_type != ET_EXEC && @@ -258,7 +285,7 @@ #endif } /* Now read in all of the header information */ - if(sizeof(struct elf_phdr) * interp_elf_ex->e_phnum > PAGE_SIZE) { + if (sizeof(struct elf_phdr) * interp_elf_ex->e_phnum > PAGE_SIZE) { printk("IRIX interp header bigger than a page (%d)\n", (sizeof(struct elf_phdr) * interp_elf_ex->e_phnum)); return 0xffffffff; @@ -267,15 +294,15 @@ #endif elf_phdata = kmalloc(sizeof(struct elf_phdr) * interp_elf_ex->e_phnum, GFP_KERNEL); - if(!elf_phdata) { - printk("Cannot kmalloc phdata for IRIX interp.\n"); - return 0xffffffff; + if (!elf_phdata) { + printk("Cannot kmalloc phdata for IRIX interp.\n"); + return 0xffffffff; } /* If the size of this structure has changed, then punt, since * we will be doing the wrong thing. */ - if(interp_elf_ex->e_phentsize != 32) { + if (interp_elf_ex->e_phentsize != 32) { printk("IRIX interp e_phentsize == %d != 32 ", interp_elf_ex->e_phentsize); kfree(elf_phdata); @@ -286,61 +313,71 @@ #endif (char *) elf_phdata, sizeof(struct elf_phdr) * interp_elf_ex->e_phnum); -#ifdef DEBUG dump_phdrs(elf_phdata, interp_elf_ex->e_phnum); -#endif eppnt = elf_phdata; - for(i=0; ie_phnum; i++, eppnt++) { - if(eppnt->p_type == PT_LOAD) { - int elf_type = MAP_PRIVATE | MAP_DENYWRITE; - int elf_prot = 0; - unsigned long vaddr = 0; - if (eppnt->p_flags & PF_R) elf_prot = PROT_READ; - if (eppnt->p_flags & PF_W) elf_prot |= PROT_WRITE; - if (eppnt->p_flags & PF_X) elf_prot |= PROT_EXEC; - elf_type |= MAP_FIXED; - vaddr = eppnt->p_vaddr; - - pr_debug("INTERP do_mmap(%p, %08lx, %08lx, %08lx, %08lx, %08lx) ", - interpreter, vaddr, - (unsigned long) (eppnt->p_filesz + (eppnt->p_vaddr & 0xfff)), - (unsigned long) elf_prot, (unsigned long) elf_type, - (unsigned long) (eppnt->p_offset & 0xfffff000)); - down_write(¤t->mm->mmap_sem); - error = do_mmap(interpreter, vaddr, - eppnt->p_filesz + (eppnt->p_vaddr & 0xfff), - elf_prot, elf_type, - eppnt->p_offset & 0xfffff000); - up_write(¤t->mm->mmap_sem); - - if(error < 0 && error > -1024) { - printk("Aieee IRIX interp mmap error=%d\n", error); - break; /* Real error */ - } - pr_debug("error=%08lx ", (unsigned long) error); - if(!load_addr && interp_elf_ex->e_type == ET_DYN) { - load_addr = error; - pr_debug("load_addr = error "); - } - - /* Find the end of the file mapping for this phdr, and keep - * track of the largest address we see for this. - */ - k = eppnt->p_vaddr + eppnt->p_filesz; - if(k > elf_bss) elf_bss = k; - - /* Do the same thing for the memory mapping - between - * elf_bss and last_bss is the bss section. - */ - k = eppnt->p_memsz + eppnt->p_vaddr; - if(k > last_bss) last_bss = k; - pr_debug("\n"); - } + for (i = 0; i < interp_elf_ex->e_phnum; i++, eppnt++) { + if (eppnt->p_type == PT_LOAD) { + int elf_type = MAP_PRIVATE | MAP_DENYWRITE; + int elf_prot = 0; + unsigned long vaddr = 0; + if (eppnt->p_flags & PF_R) + elf_prot = PROT_READ; + if (eppnt->p_flags & PF_W) + elf_prot |= PROT_WRITE; + if (eppnt->p_flags & PF_X) + elf_prot |= PROT_EXEC; + elf_type |= MAP_FIXED; + vaddr = eppnt->p_vaddr; + + pr_debug("INTERP do_mmap" + "(%p, %08lx, %08lx, %08lx, %08lx, %08lx) ", + interpreter, vaddr, + (unsigned long) + (eppnt->p_filesz + (eppnt->p_vaddr & 0xfff)), + (unsigned long) + elf_prot, (unsigned long) elf_type, + (unsigned long) + (eppnt->p_offset & 0xfffff000)); + + down_write(¤t->mm->mmap_sem); + error = do_mmap(interpreter, vaddr, + eppnt->p_filesz + (eppnt->p_vaddr & 0xfff), + elf_prot, elf_type, + eppnt->p_offset & 0xfffff000); + up_write(¤t->mm->mmap_sem); + + if (error < 0 && error > -1024) { + printk("Aieee IRIX interp mmap error=%d\n", + error); + break; /* Real error */ + } + pr_debug("error=%08lx ", (unsigned long) error); + if (!load_addr && interp_elf_ex->e_type == ET_DYN) { + load_addr = error; + pr_debug("load_addr = error "); + } + + /* + * Find the end of the file mapping for this phdr, and + * keep track of the largest address we see for this. + */ + k = eppnt->p_vaddr + eppnt->p_filesz; + if (k > elf_bss) + elf_bss = k; + + /* Do the same thing for the memory mapping - between + * elf_bss and last_bss is the bss section. + */ + k = eppnt->p_memsz + eppnt->p_vaddr; + if (k > last_bss) + last_bss = k; + pr_debug("\n"); + } } /* Now use mmap to map the library into memory. */ - if(error < 0 && error > -1024) { + if (error < 0 && error > -1024) { pr_debug("got error %d\n", error); kfree(elf_phdata); return 0xffffffff; @@ -377,7 +414,7 @@ static int verify_binary(struct elfhdr * return -ENOEXEC; /* First of all, some simple consistency checks */ - if((ehp->e_type != ET_EXEC && ehp->e_type != ET_DYN) || + if ((ehp->e_type != ET_EXEC && ehp->e_type != ET_DYN) || !bprm->file->f_op->mmap) { return -ENOEXEC; } @@ -388,7 +425,7 @@ static int verify_binary(struct elfhdr * * XXX all registers as 64bits on cpu's capable of this at * XXX exception time plus frob the XTLB exception vector. */ - if((ehp->e_flags & EF_MIPS_ABI2)) + if ((ehp->e_flags & EF_MIPS_ABI2)) return -ENOEXEC; return 0; @@ -410,7 +447,7 @@ static inline int look_for_irix_interpre struct file *file = NULL; *name = NULL; - for(i = 0; i < pnum; i++, epp++) { + for (i = 0; i < pnum; i++, epp++) { if (epp->p_type != PT_INTERP) continue; @@ -467,8 +504,8 @@ static inline void map_executable(struct unsigned int tmp; int i, prot; - for(i = 0; i < pnum; i++, epp++) { - if(epp->p_type != PT_LOAD) + for (i = 0; i < pnum; i++, epp++) { + if (epp->p_type != PT_LOAD) continue; /* Map it. */ @@ -483,23 +520,23 @@ static inline void map_executable(struct up_write(¤t->mm->mmap_sem); /* Fixup location tracking vars. */ - if((epp->p_vaddr & 0xfffff000) < *estack) + if ((epp->p_vaddr & 0xfffff000) < *estack) *estack = (epp->p_vaddr & 0xfffff000); - if(!*laddr) + if (!*laddr) *laddr = epp->p_vaddr - epp->p_offset; - if(epp->p_vaddr < *scode) + if (epp->p_vaddr < *scode) *scode = epp->p_vaddr; tmp = epp->p_vaddr + epp->p_filesz; - if(tmp > *ebss) + if (tmp > *ebss) *ebss = tmp; - if((epp->p_flags & PF_X) && *ecode < tmp) + if ((epp->p_flags & PF_X) && *ecode < tmp) *ecode = tmp; - if(*edata < tmp) + if (*edata < tmp) *edata = tmp; tmp = epp->p_vaddr + epp->p_memsz; - if(tmp > *ebrk) + if (tmp > *ebrk) *ebrk = tmp; } @@ -513,12 +550,12 @@ static inline int map_interpreter(struct int i; *eentry = 0xffffffff; - for(i = 0; i < pnum; i++, epp++) { - if(epp->p_type != PT_INTERP) + for (i = 0; i < pnum; i++, epp++) { + if (epp->p_type != PT_INTERP) continue; /* We should have fielded this error elsewhere... */ - if(*eentry != 0xffffffff) + if (*eentry != 0xffffffff) return -1; set_fs(old_fs); @@ -604,9 +641,7 @@ static int load_irix_binary(struct linux if (elf_ex.e_shnum > 20) goto out; -#ifdef DEBUG print_elfhdr(&elf_ex); -#endif /* Now read in all of the header information */ size = elf_ex.e_phentsize * elf_ex.e_phnum; @@ -622,13 +657,11 @@ #endif if (retval < 0) goto out_free_ph; -#ifdef DEBUG dump_phdrs(elf_phdata, elf_ex.e_phnum); -#endif /* Set some things for later. */ - for(i = 0; i < elf_ex.e_phnum; i++) { - switch(elf_phdata[i].p_type) { + for (i = 0; i < elf_ex.e_phnum; i++) { + switch (elf_phdata[i].p_type) { case PT_INTERP: has_interp = 1; elf_ihdr = &elf_phdata[i]; @@ -667,7 +700,7 @@ #endif if (elf_interpreter) { retval = verify_irix_interpreter(&interp_elf_ex); - if(retval) + if (retval) goto out_free_interp; } @@ -706,12 +739,12 @@ #endif &load_addr, &start_code, &elf_bss, &end_code, &end_data, &elf_brk); - if(elf_interpreter) { + if (elf_interpreter) { retval = map_interpreter(elf_phdata, &interp_elf_ex, interpreter, &interp_load_addr, elf_ex.e_phnum, old_fs, &elf_entry); kfree(elf_interpreter); - if(retval) { + if (retval) { set_fs(old_fs); printk("Unable to load IRIX ELF interpreter\n"); send_sig(SIGSEGV, current, 0); @@ -809,12 +842,12 @@ static int load_irix_library(struct file return -ENOEXEC; /* First of all, some simple consistency checks. */ - if(elf_ex.e_type != ET_EXEC || elf_ex.e_phnum > 2 || + if (elf_ex.e_type != ET_EXEC || elf_ex.e_phnum > 2 || !file->f_op->mmap) return -ENOEXEC; /* Now read in all of the header information. */ - if(sizeof(struct elf_phdr) * elf_ex.e_phnum > PAGE_SIZE) + if (sizeof(struct elf_phdr) * elf_ex.e_phnum > PAGE_SIZE) return -ENOEXEC; elf_phdata = kmalloc(sizeof(struct elf_phdr) * elf_ex.e_phnum, GFP_KERNEL); @@ -825,15 +858,15 @@ static int load_irix_library(struct file sizeof(struct elf_phdr) * elf_ex.e_phnum); j = 0; - for(i=0; ip_type == PT_LOAD) j++; + for (i=0; ip_type == PT_LOAD) j++; - if(j != 1) { + if (j != 1) { kfree(elf_phdata); return -ENOEXEC; } - while(elf_phdata->p_type != PT_LOAD) elf_phdata++; + while (elf_phdata->p_type != PT_LOAD) elf_phdata++; /* Now use mmap to map the library into memory. */ down_write(¤t->mm->mmap_sem); @@ -889,9 +922,7 @@ unsigned long irix_mapelf(int fd, struct return -EFAULT; } -#ifdef DEBUG dump_phdrs(user_phdrp, cnt); -#endif for (i = 0; i < cnt; i++, hp++) { if (__get_user(type, &hp->p_type)) @@ -905,14 +936,14 @@ #endif filp = fget(fd); if (!filp) return -EACCES; - if(!filp->f_op) { + if (!filp->f_op) { printk("irix_mapelf: Bogon filp!\n"); fput(filp); return -EACCES; } hp = user_phdrp; - for(i = 0; i < cnt; i++, hp++) { + for (i = 0; i < cnt; i++, hp++) { int prot; retval = __get_user(vaddr, &hp->p_vaddr); @@ -1015,8 +1046,6 @@ static int notesize(struct memelfnote *e return sz; } -/* #define DEBUG */ - #define DUMP_WRITE(addr, nr) \ if (!dump_write(file, (addr), (nr))) \ goto end_coredump; @@ -1093,9 +1122,7 @@ static int irix_core_dump(long signr, st segs++; } -#ifdef DEBUG - printk("irix_core_dump: %d segs taking %d bytes\n", segs, size); -#endif + pr_debug("irix_core_dump: %d segs taking %d bytes\n", segs, size); /* Set up header. */ memcpy(elf.e_ident, ELFMAG, SELFMAG); @@ -1221,7 +1248,7 @@ #endif struct elf_phdr phdr; int sz = 0; - for(i = 0; i < numnote; i++) + for (i = 0; i < numnote; i++) sz += notesize(¬es[i]); phdr.p_type = PT_NOTE; @@ -1241,7 +1268,7 @@ #endif dataoff = offset = roundup(offset, PAGE_SIZE); /* Write program headers for segments dump. */ - for(vma = current->mm->mmap, i = 0; + for (vma = current->mm->mmap, i = 0; i < segs && vma != NULL; vma = vma->vm_next) { struct elf_phdr phdr; size_t sz; @@ -1267,7 +1294,7 @@ #endif DUMP_WRITE(&phdr, sizeof(phdr)); } - for(i = 0; i < numnote; i++) + for (i = 0; i < numnote; i++) if (!writenote(¬es[i], file)) goto end_coredump; @@ -1275,7 +1302,7 @@ #endif DUMP_SEEK(dataoff); - for(i = 0, vma = current->mm->mmap; + for (i = 0, vma = current->mm->mmap; i < segs && vma != NULL; vma = vma->vm_next) { unsigned long addr = vma->vm_start; @@ -1284,9 +1311,7 @@ #endif if (!maydump(vma)) continue; i++; -#ifdef DEBUG - printk("elf_core_dump: writing %08lx %lx\n", addr, len); -#endif + pr_debug("elf_core_dump: writing %08lx %lx\n", addr, len); DUMP_WRITE((void __user *)addr, len); } diff --git a/arch/mips/kernel/irq-msc01.c b/arch/mips/kernel/irq-msc01.c index bcaad66..2967537 100644 --- a/arch/mips/kernel/irq-msc01.c +++ b/arch/mips/kernel/irq-msc01.c @@ -112,7 +112,7 @@ msc_bind_eic_interrupt (unsigned int irq } struct irq_chip msc_levelirq_type = { - .typename = "SOC-it-Level", + .name = "SOC-it-Level", .ack = level_mask_and_ack_msc_irq, .mask = mask_msc_irq, .mask_ack = level_mask_and_ack_msc_irq, @@ -122,7 +122,7 @@ struct irq_chip msc_levelirq_type = { }; struct irq_chip msc_edgeirq_type = { - .typename = "SOC-it-Edge", + .name = "SOC-it-Edge", .ack = edge_mask_and_ack_msc_irq, .mask = mask_msc_irq, .mask_ack = edge_mask_and_ack_msc_irq, diff --git a/arch/mips/kernel/irq-mv6434x.c b/arch/mips/kernel/irq-mv6434x.c index efbd219..3dd5618 100644 --- a/arch/mips/kernel/irq-mv6434x.c +++ b/arch/mips/kernel/irq-mv6434x.c @@ -23,13 +23,13 @@ static unsigned int irq_base; static inline int ls1bit32(unsigned int x) { - int b = 31, s; + int b = 31, s; - s = 16; if (x << 16 == 0) s = 0; b -= s; x <<= s; - s = 8; if (x << 8 == 0) s = 0; b -= s; x <<= s; - s = 4; if (x << 4 == 0) s = 0; b -= s; x <<= s; - s = 2; if (x << 2 == 0) s = 0; b -= s; x <<= s; - s = 1; if (x << 1 == 0) s = 0; b -= s; + s = 16; if (x << 16 == 0) s = 0; b -= s; x <<= s; + s = 8; if (x << 8 == 0) s = 0; b -= s; x <<= s; + s = 4; if (x << 4 == 0) s = 0; b -= s; x <<= s; + s = 2; if (x << 2 == 0) s = 0; b -= s; x <<= s; + s = 1; if (x << 1 == 0) s = 0; b -= s; return b; } @@ -92,7 +92,7 @@ void ll_mv64340_irq(void) } struct irq_chip mv64340_irq_type = { - .typename = "MV-64340", + .name = "MV-64340", .ack = mask_mv64340_irq, .mask = mask_mv64340_irq, .mask_ack = mask_mv64340_irq, diff --git a/arch/mips/kernel/irq-rm7000.c b/arch/mips/kernel/irq-rm7000.c index 123324b..2507328 100644 --- a/arch/mips/kernel/irq-rm7000.c +++ b/arch/mips/kernel/irq-rm7000.c @@ -17,28 +17,27 @@ #include #include #include -static int irq_base; - static inline void unmask_rm7k_irq(unsigned int irq) { - set_c0_intcontrol(0x100 << (irq - irq_base)); + set_c0_intcontrol(0x100 << (irq - RM7K_CPU_IRQ_BASE)); } static inline void mask_rm7k_irq(unsigned int irq) { - clear_c0_intcontrol(0x100 << (irq - irq_base)); + clear_c0_intcontrol(0x100 << (irq - RM7K_CPU_IRQ_BASE)); } static struct irq_chip rm7k_irq_controller = { - .typename = "RM7000", + .name = "RM7000", .ack = mask_rm7k_irq, .mask = mask_rm7k_irq, .mask_ack = mask_rm7k_irq, .unmask = unmask_rm7k_irq, }; -void __init rm7k_cpu_irq_init(int base) +void __init rm7k_cpu_irq_init(void) { + int base = RM7K_CPU_IRQ_BASE; int i; clear_c0_intcontrol(0x00000f00); /* Mask all */ @@ -46,6 +45,4 @@ void __init rm7k_cpu_irq_init(int base) for (i = base; i < base + 4; i++) set_irq_chip_and_handler(i, &rm7k_irq_controller, handle_level_irq); - - irq_base = base; } diff --git a/arch/mips/kernel/irq-rm9000.c b/arch/mips/kernel/irq-rm9000.c index 0e6f4c5..ae83d2d 100644 --- a/arch/mips/kernel/irq-rm9000.c +++ b/arch/mips/kernel/irq-rm9000.c @@ -18,16 +18,14 @@ #include #include #include -static int irq_base; - static inline void unmask_rm9k_irq(unsigned int irq) { - set_c0_intcontrol(0x1000 << (irq - irq_base)); + set_c0_intcontrol(0x1000 << (irq - RM9K_CPU_IRQ_BASE)); } static inline void mask_rm9k_irq(unsigned int irq) { - clear_c0_intcontrol(0x1000 << (irq - irq_base)); + clear_c0_intcontrol(0x1000 << (irq - RM9K_CPU_IRQ_BASE)); } static inline void rm9k_cpu_irq_enable(unsigned int irq) @@ -39,15 +37,6 @@ static inline void rm9k_cpu_irq_enable(u local_irq_restore(flags); } -static void rm9k_cpu_irq_disable(unsigned int irq) -{ - unsigned long flags; - - local_irq_save(flags); - mask_rm9k_irq(irq); - local_irq_restore(flags); -} - /* * Performance counter interrupts are global on all processors. */ @@ -81,7 +70,7 @@ static void rm9k_perfcounter_irq_shutdow } static struct irq_chip rm9k_irq_controller = { - .typename = "RM9000", + .name = "RM9000", .ack = mask_rm9k_irq, .mask = mask_rm9k_irq, .mask_ack = mask_rm9k_irq, @@ -89,7 +78,7 @@ static struct irq_chip rm9k_irq_controll }; static struct irq_chip rm9k_perfcounter_irq = { - .typename = "RM9000", + .name = "RM9000", .startup = rm9k_perfcounter_irq_startup, .shutdown = rm9k_perfcounter_irq_shutdown, .ack = mask_rm9k_irq, @@ -102,8 +91,9 @@ unsigned int rm9000_perfcount_irq; EXPORT_SYMBOL(rm9000_perfcount_irq); -void __init rm9k_cpu_irq_init(int base) +void __init rm9k_cpu_irq_init(void) { + int base = RM9K_CPU_IRQ_BASE; int i; clear_c0_intcontrol(0x0000f000); /* Mask all */ @@ -115,6 +105,4 @@ void __init rm9k_cpu_irq_init(int base) rm9000_perfcount_irq = base + 1; set_irq_chip_and_handler(rm9000_perfcount_irq, &rm9k_perfcounter_irq, handle_level_irq); - - irq_base = base; } diff --git a/arch/mips/kernel/irq_cpu.c b/arch/mips/kernel/irq_cpu.c index fcc86b9..7b66e03 100644 --- a/arch/mips/kernel/irq_cpu.c +++ b/arch/mips/kernel/irq_cpu.c @@ -25,7 +25,7 @@ * Don't even think about using this on SMP. You have been warned. * * This file exports one global function: - * void mips_cpu_irq_init(int irq_base); + * void mips_cpu_irq_init(void); */ #include #include @@ -36,22 +36,20 @@ #include #include #include -static int mips_cpu_irq_base; - static inline void unmask_mips_irq(unsigned int irq) { - set_c0_status(0x100 << (irq - mips_cpu_irq_base)); + set_c0_status(0x100 << (irq - MIPS_CPU_IRQ_BASE)); irq_enable_hazard(); } static inline void mask_mips_irq(unsigned int irq) { - clear_c0_status(0x100 << (irq - mips_cpu_irq_base)); + clear_c0_status(0x100 << (irq - MIPS_CPU_IRQ_BASE)); irq_disable_hazard(); } static struct irq_chip mips_cpu_irq_controller = { - .typename = "MIPS", + .name = "MIPS", .ack = mask_mips_irq, .mask = mask_mips_irq, .mask_ack = mask_mips_irq, @@ -70,7 +68,7 @@ static unsigned int mips_mt_cpu_irq_star { unsigned int vpflags = dvpe(); - clear_c0_cause(0x100 << (irq - mips_cpu_irq_base)); + clear_c0_cause(0x100 << (irq - MIPS_CPU_IRQ_BASE)); evpe(vpflags); unmask_mips_mt_irq(irq); @@ -84,13 +82,13 @@ static unsigned int mips_mt_cpu_irq_star static void mips_mt_cpu_irq_ack(unsigned int irq) { unsigned int vpflags = dvpe(); - clear_c0_cause(0x100 << (irq - mips_cpu_irq_base)); + clear_c0_cause(0x100 << (irq - MIPS_CPU_IRQ_BASE)); evpe(vpflags); mask_mips_mt_irq(irq); } static struct irq_chip mips_mt_cpu_irq_controller = { - .typename = "MIPS", + .name = "MIPS", .startup = mips_mt_cpu_irq_startup, .ack = mips_mt_cpu_irq_ack, .mask = mask_mips_mt_irq, @@ -99,8 +97,9 @@ static struct irq_chip mips_mt_cpu_irq_c .eoi = unmask_mips_mt_irq, }; -void __init mips_cpu_irq_init(int irq_base) +void __init mips_cpu_irq_init(void) { + int irq_base = MIPS_CPU_IRQ_BASE; int i; /* Mask interrupts. */ @@ -118,6 +117,4 @@ void __init mips_cpu_irq_init(int irq_ba for (i = irq_base + 2; i < irq_base + 8; i++) set_irq_chip_and_handler(i, &mips_cpu_irq_controller, handle_level_irq); - - mips_cpu_irq_base = irq_base; } diff --git a/arch/mips/kernel/linux32.c b/arch/mips/kernel/linux32.c index de3fae2..fc4dd6c 100644 --- a/arch/mips/kernel/linux32.c +++ b/arch/mips/kernel/linux32.c @@ -39,6 +39,7 @@ #include #include #include +#include #include #include #include @@ -193,50 +194,6 @@ sysn32_waitid(int which, compat_pid_t pi return ret; } -struct sysinfo32 { - s32 uptime; - u32 loads[3]; - u32 totalram; - u32 freeram; - u32 sharedram; - u32 bufferram; - u32 totalswap; - u32 freeswap; - u16 procs; - u32 totalhigh; - u32 freehigh; - u32 mem_unit; - char _f[8]; -}; - -asmlinkage int sys32_sysinfo(struct sysinfo32 __user *info) -{ - struct sysinfo s; - int ret, err; - mm_segment_t old_fs = get_fs (); - - set_fs (KERNEL_DS); - ret = sys_sysinfo((struct sysinfo __user *)&s); - set_fs (old_fs); - err = put_user (s.uptime, &info->uptime); - err |= __put_user (s.loads[0], &info->loads[0]); - err |= __put_user (s.loads[1], &info->loads[1]); - err |= __put_user (s.loads[2], &info->loads[2]); - err |= __put_user (s.totalram, &info->totalram); - err |= __put_user (s.freeram, &info->freeram); - err |= __put_user (s.sharedram, &info->sharedram); - err |= __put_user (s.bufferram, &info->bufferram); - err |= __put_user (s.totalswap, &info->totalswap); - err |= __put_user (s.freeswap, &info->freeswap); - err |= __put_user (s.procs, &info->procs); - err |= __put_user (s.totalhigh, &info->totalhigh); - err |= __put_user (s.freehigh, &info->freehigh); - err |= __put_user (s.mem_unit, &info->mem_unit); - if (err) - return -EFAULT; - return ret; -} - #define RLIM_INFINITY32 0x7fffffff #define RESOURCE32(x) ((x > RLIM_INFINITY32) ? RLIM_INFINITY32 : x) @@ -558,7 +515,7 @@ extern asmlinkage long sys_ustat(dev_t d asmlinkage int sys32_ustat(dev_t dev, struct ustat32 __user * ubuf32) { int err; - struct ustat tmp; + struct ustat tmp; struct ustat32 tmp32; mm_segment_t old_fs = get_fs(); @@ -569,11 +526,11 @@ asmlinkage int sys32_ustat(dev_t dev, st if (err) goto out; - memset(&tmp32,0,sizeof(struct ustat32)); - tmp32.f_tfree = tmp.f_tfree; - tmp32.f_tinode = tmp.f_tinode; + memset(&tmp32,0,sizeof(struct ustat32)); + tmp32.f_tfree = tmp.f_tfree; + tmp32.f_tinode = tmp.f_tinode; - err = copy_to_user(ubuf32,&tmp32,sizeof(struct ustat32)) ? -EFAULT : 0; + err = copy_to_user(ubuf32,&tmp32,sizeof(struct ustat32)) ? -EFAULT : 0; out: return err; @@ -780,3 +737,49 @@ _sys32_clone(nabi_no_regargs struct pt_r return do_fork(clone_flags, newsp, ®s, 0, parent_tidptr, child_tidptr); } + +/* + * Implement the event wait interface for the eventpoll file. It is the kernel + * part of the user space epoll_pwait(2). + */ +asmlinkage long compat_sys_epoll_pwait(int epfd, + struct epoll_event __user *events, int maxevents, int timeout, + const compat_sigset_t __user *sigmask, size_t sigsetsize) +{ + int error; + sigset_t ksigmask, sigsaved; + + /* + * If the caller wants a certain signal mask to be set during the wait, + * we apply it here. + */ + if (sigmask) { + if (sigsetsize != sizeof(sigset_t)) + return -EINVAL; + if (!access_ok(VERIFY_READ, sigmask, sizeof(ksigmask))) + return -EFAULT; + if (__copy_conv_sigset_from_user(&ksigmask, sigmask)) + return -EFAULT; + sigdelsetmask(&ksigmask, sigmask(SIGKILL) | sigmask(SIGSTOP)); + sigprocmask(SIG_SETMASK, &ksigmask, &sigsaved); + } + + error = sys_epoll_wait(epfd, events, maxevents, timeout); + + /* + * If we changed the signal mask, we need to restore the original one. + * In case we've got a signal while waiting, we do not restore the + * signal mask yet, and we allow do_signal() to deliver the signal on + * the way back to userspace, before the signal mask is restored. + */ + if (sigmask) { + if (error == -EINTR) { + memcpy(¤t->saved_sigmask, &sigsaved, + sizeof(sigsaved)); + set_thread_flag(TIF_RESTORE_SIGMASK); + } else + sigprocmask(SIG_SETMASK, &sigsaved, NULL); + } + + return error; +} diff --git a/arch/mips/kernel/mips-mt.c b/arch/mips/kernel/mips-mt.c index c1373a6..ba01800 100644 --- a/arch/mips/kernel/mips-mt.c +++ b/arch/mips/kernel/mips-mt.c @@ -3,9 +3,11 @@ * Copyright (C) 2005 Mips Technologies, Inc */ +#include #include #include #include +#include #include #include @@ -96,6 +98,10 @@ asmlinkage long mipsmt_sys_sched_setaffi goto out_unlock; } + retval = security_task_setscheduler(p, 0, NULL); + if (retval) + goto out_unlock; + /* Record new user-specified CPU set for future reference */ p->thread.user_cpus_allowed = new_mask; @@ -141,8 +147,9 @@ asmlinkage long mipsmt_sys_sched_getaffi p = find_process_by_pid(pid); if (!p) goto out_unlock; - - retval = 0; + retval = security_task_getscheduler(p); + if (retval) + goto out_unlock; cpus_and(mask, p->thread.user_cpus_allowed, cpu_possible_map); @@ -448,3 +455,20 @@ #ifdef CONFIG_MIPS_MT_SMTC #endif /* CONFIG_MIPS_MT_SMTC */ /* FILL IN VSMP and AP/SP VERSIONS HERE */ } + +struct class *mt_class; + +static int __init mt_init(void) +{ + struct class *mtc; + + mtc = class_create(THIS_MODULE, "mt"); + if (IS_ERR(mtc)) + return PTR_ERR(mtc); + + mt_class = mtc; + + return 0; +} + +subsys_initcall(mt_init); diff --git a/arch/mips/kernel/proc.c b/arch/mips/kernel/proc.c index 4ed37ba..5ddc2e9 100644 --- a/arch/mips/kernel/proc.c +++ b/arch/mips/kernel/proc.c @@ -31,13 +31,13 @@ static const char *cpu_name[] = { [CPU_R4000PC] = "R4000PC", [CPU_R4000SC] = "R4000SC", [CPU_R4000MC] = "R4000MC", - [CPU_R4200] = "R4200", + [CPU_R4200] = "R4200", [CPU_R4400PC] = "R4400PC", [CPU_R4400SC] = "R4400SC", [CPU_R4400MC] = "R4400MC", [CPU_R4600] = "R4600", [CPU_R6000] = "R6000", - [CPU_R6000A] = "R6000A", + [CPU_R6000A] = "R6000A", [CPU_R8000] = "R8000", [CPU_R10000] = "R10000", [CPU_R12000] = "R12000", @@ -46,14 +46,14 @@ static const char *cpu_name[] = { [CPU_R4650] = "R4650", [CPU_R4700] = "R4700", [CPU_R5000] = "R5000", - [CPU_R5000A] = "R5000A", + [CPU_R5000A] = "R5000A", [CPU_R4640] = "R4640", [CPU_NEVADA] = "Nevada", [CPU_RM7000] = "RM7000", [CPU_RM9000] = "RM9000", [CPU_R5432] = "R5432", [CPU_4KC] = "MIPS 4Kc", - [CPU_5KC] = "MIPS 5Kc", + [CPU_5KC] = "MIPS 5Kc", [CPU_R4310] = "R4310", [CPU_SB1] = "SiByte SB1", [CPU_SB1A] = "SiByte SB1A", diff --git a/arch/mips/kernel/process.c b/arch/mips/kernel/process.c index ec8209f..04e5b38 100644 --- a/arch/mips/kernel/process.c +++ b/arch/mips/kernel/process.c @@ -41,10 +41,6 @@ #include #include #include #include -#ifdef CONFIG_MIPS_MT_SMTC -#include -extern void smtc_idle_loop_hook(void); -#endif /* CONFIG_MIPS_MT_SMTC */ /* * The idle thread. There's no useful work to be done, so just try to conserve @@ -57,6 +53,8 @@ ATTRIB_NORET void cpu_idle(void) while (1) { while (!need_resched()) { #ifdef CONFIG_MIPS_MT_SMTC + extern void smtc_idle_loop_hook(void); + smtc_idle_loop_hook(); #endif /* CONFIG_MIPS_MT_SMTC */ if (cpu_wait) diff --git a/arch/mips/kernel/r4k_fpu.S b/arch/mips/kernel/r4k_fpu.S index 880fa6e..59c1577 100644 --- a/arch/mips/kernel/r4k_fpu.S +++ b/arch/mips/kernel/r4k_fpu.S @@ -114,6 +114,14 @@ #endif */ LEAF(_restore_fp_context) EX lw t0, SC_FPC_CSR(a0) + + /* Fail if the CSR has exceptions pending */ + srl t1, t0, 5 + and t1, t0 + andi t1, 0x1f << 7 + bnez t1, fault + nop + #ifdef CONFIG_64BIT EX ldc1 $f1, SC_FPREGS+8(a0) EX ldc1 $f3, SC_FPREGS+24(a0) @@ -157,6 +165,14 @@ #ifdef CONFIG_MIPS32_COMPAT LEAF(_restore_fp_context32) /* Restore an o32 sigcontext. */ EX lw t0, SC32_FPC_CSR(a0) + + /* Fail if the CSR has exceptions pending */ + srl t1, t0, 5 + and t1, t0 + andi t1, 0x1f << 7 + bnez t1, fault + nop + EX ldc1 $f0, SC32_FPREGS+0(a0) EX ldc1 $f2, SC32_FPREGS+16(a0) EX ldc1 $f4, SC32_FPREGS+32(a0) @@ -177,9 +193,10 @@ LEAF(_restore_fp_context32) jr ra li v0, 0 # success END(_restore_fp_context32) - .set reorder #endif + .set reorder + .type fault@function .ent fault fault: li v0, -EFAULT # failure diff --git a/arch/mips/kernel/rtlx.c b/arch/mips/kernel/rtlx.c index 5a99e3e..d92c48e 100644 --- a/arch/mips/kernel/rtlx.c +++ b/arch/mips/kernel/rtlx.c @@ -17,6 +17,7 @@ * */ +#include #include #include #include @@ -34,6 +35,7 @@ #include #include #include #include +#include #include #include #include @@ -63,7 +65,7 @@ extern void *vpe_get_shared(int index); static void rtlx_dispatch(void) { - do_IRQ(MIPSCPU_INT_BASE + MIPS_CPU_RTLX_IRQ); + do_IRQ(MIPS_CPU_IRQ_BASE + MIPS_CPU_RTLX_IRQ); } @@ -476,7 +478,7 @@ static ssize_t file_write(struct file *f return rtlx_write(minor, (void *)buffer, count, 1); } -static struct file_operations rtlx_fops = { +static const struct file_operations rtlx_fops = { .owner = THIS_MODULE, .open = file_open, .release = file_release, @@ -491,14 +493,15 @@ static struct irqaction rtlx_irq = { .name = "RTLX", }; -static int rtlx_irq_num = MIPSCPU_INT_BASE + MIPS_CPU_RTLX_IRQ; +static int rtlx_irq_num = MIPS_CPU_IRQ_BASE + MIPS_CPU_RTLX_IRQ; static char register_chrdev_failed[] __initdata = KERN_ERR "rtlx_module_init: unable to register device\n"; static int rtlx_module_init(void) { - int i; + struct device *dev; + int i, err; major = register_chrdev(0, module_name, &rtlx_fops); if (major < 0) { @@ -511,6 +514,13 @@ static int rtlx_module_init(void) init_waitqueue_head(&channel_wqs[i].rt_queue); init_waitqueue_head(&channel_wqs[i].lx_queue); channel_wqs[i].in_open = 0; + + dev = device_create(mt_class, NULL, MKDEV(major, i), + "%s%d", module_name, i); + if (IS_ERR(dev)) { + err = PTR_ERR(dev); + goto out_chrdev; + } } /* set up notifiers */ @@ -525,10 +535,21 @@ static int rtlx_module_init(void) setup_irq(rtlx_irq_num, &rtlx_irq); return 0; + +out_chrdev: + for (i = 0; i < RTLX_CHANNELS; i++) + device_destroy(mt_class, MKDEV(major, i)); + + return err; } static void __exit rtlx_module_exit(void) { + int i; + + for (i = 0; i < RTLX_CHANNELS; i++) + device_destroy(mt_class, MKDEV(major, i)); + unregister_chrdev(major, module_name); } diff --git a/arch/mips/kernel/scall64-64.S b/arch/mips/kernel/scall64-64.S index e569b84..10e9a18 100644 --- a/arch/mips/kernel/scall64-64.S +++ b/arch/mips/kernel/scall64-64.S @@ -470,4 +470,4 @@ sys_call_table: PTR sys_get_robust_list PTR sys_kexec_load /* 5270 */ PTR sys_getcpu - PTR sys_epoll_pwait + PTR compat_sys_epoll_pwait diff --git a/arch/mips/kernel/scall64-n32.S b/arch/mips/kernel/scall64-n32.S index a7bff2a..2ceda46 100644 --- a/arch/mips/kernel/scall64-n32.S +++ b/arch/mips/kernel/scall64-n32.S @@ -217,7 +217,7 @@ EXPORT(sysn32_call_table) PTR sys32_gettimeofday PTR compat_sys_getrlimit /* 6095 */ PTR compat_sys_getrusage - PTR sys32_sysinfo + PTR compat_sys_sysinfo PTR compat_sys_times PTR sys32_ptrace PTR sys_getuid /* 6100 */ @@ -384,7 +384,7 @@ EXPORT(sysn32_call_table) PTR sys_readlinkat PTR sys_fchmodat PTR sys_faccessat - PTR sys_pselect6 + PTR compat_sys_pselect6 PTR sys_ppoll /* 6265 */ PTR sys_unshare PTR sys_splice @@ -396,4 +396,4 @@ EXPORT(sysn32_call_table) PTR compat_sys_get_robust_list PTR compat_sys_kexec_load PTR sys_getcpu - PTR sys_epoll_pwait + PTR compat_sys_epoll_pwait diff --git a/arch/mips/kernel/scall64-o32.S b/arch/mips/kernel/scall64-o32.S index e91379c..c5f590c 100644 --- a/arch/mips/kernel/scall64-o32.S +++ b/arch/mips/kernel/scall64-o32.S @@ -321,7 +321,7 @@ sys_call_table: PTR sys_ni_syscall /* sys_vm86 */ PTR compat_sys_wait4 PTR sys_swapoff /* 4115 */ - PTR sys32_sysinfo + PTR compat_sys_sysinfo PTR sys32_ipc PTR sys_fsync PTR sys32_sigreturn @@ -506,7 +506,7 @@ sys_call_table: PTR sys_readlinkat PTR sys_fchmodat PTR sys_faccessat /* 4300 */ - PTR sys_pselect6 + PTR compat_sys_pselect6 PTR sys_ppoll PTR sys_unshare PTR sys_splice diff --git a/arch/mips/kernel/setup.c b/arch/mips/kernel/setup.c index 89440a0..394540f 100644 --- a/arch/mips/kernel/setup.c +++ b/arch/mips/kernel/setup.c @@ -271,8 +271,7 @@ #else /* !CONFIG_SGI_IP27 */ static void __init bootmem_init(void) { unsigned long reserved_end; - unsigned long highest = 0; - unsigned long mapstart = -1UL; + unsigned long mapstart = ~0UL; unsigned long bootmap_size; int i; @@ -284,6 +283,13 @@ static void __init bootmem_init(void) reserved_end = max(init_initrd(), PFN_UP(__pa_symbol(&_end))); /* + * max_low_pfn is not a number of pages. The number of pages + * of the system is given by 'max_low_pfn - min_low_pfn'. + */ + min_low_pfn = ~0UL; + max_low_pfn = 0; + + /* * Find the highest page frame number we have available. */ for (i = 0; i < boot_mem_map.nr_map; i++) { @@ -296,8 +302,10 @@ static void __init bootmem_init(void) end = PFN_DOWN(boot_mem_map.map[i].addr + boot_mem_map.map[i].size); - if (end > highest) - highest = end; + if (end > max_low_pfn) + max_low_pfn = end; + if (start < min_low_pfn) + min_low_pfn = start; if (end <= reserved_end) continue; if (start >= mapstart) @@ -305,22 +313,36 @@ static void __init bootmem_init(void) mapstart = max(reserved_end, start); } + if (min_low_pfn >= max_low_pfn) + panic("Incorrect memory mapping !!!"); + if (min_low_pfn > ARCH_PFN_OFFSET) { + printk(KERN_INFO + "Wasting %lu bytes for tracking %lu unused pages\n", + (min_low_pfn - ARCH_PFN_OFFSET) * sizeof(struct page), + min_low_pfn - ARCH_PFN_OFFSET); + } else if (min_low_pfn < ARCH_PFN_OFFSET) { + printk(KERN_INFO + "%lu free pages won't be used\n", + ARCH_PFN_OFFSET - min_low_pfn); + } + min_low_pfn = ARCH_PFN_OFFSET; + /* * Determine low and high memory ranges */ - if (highest > PFN_DOWN(HIGHMEM_START)) { + if (max_low_pfn > PFN_DOWN(HIGHMEM_START)) { #ifdef CONFIG_HIGHMEM highstart_pfn = PFN_DOWN(HIGHMEM_START); - highend_pfn = highest; + highend_pfn = max_low_pfn; #endif - highest = PFN_DOWN(HIGHMEM_START); + max_low_pfn = PFN_DOWN(HIGHMEM_START); } /* * Initialize the boot-time allocator with low memory only. */ - bootmap_size = init_bootmem(mapstart, highest); - + bootmap_size = init_bootmem_node(NODE_DATA(0), mapstart, + min_low_pfn, max_low_pfn); /* * Register fully available low RAM pages with the bootmem allocator. */ @@ -430,7 +452,7 @@ static void __init arch_mem_init(char ** print_memory_map(); strlcpy(command_line, arcs_cmdline, sizeof(command_line)); - strlcpy(saved_command_line, command_line, COMMAND_LINE_SIZE); + strlcpy(boot_command_line, command_line, COMMAND_LINE_SIZE); *cmdline_p = command_line; @@ -507,9 +529,9 @@ void __init setup_arch(char **cmdline_p) #if defined(CONFIG_VT) #if defined(CONFIG_VGA_CONSOLE) - conswitchp = &vga_con; + conswitchp = &vga_con; #elif defined(CONFIG_DUMMY_CONSOLE) - conswitchp = &dummy_con; + conswitchp = &dummy_con; #endif #endif @@ -541,3 +563,6 @@ int __init dsp_disable(char *s) } __setup("nodsp", dsp_disable); + +unsigned long kernelsp[NR_CPUS]; +unsigned long fw_arg0, fw_arg1, fw_arg2, fw_arg3; diff --git a/arch/mips/kernel/signal-common.h b/arch/mips/kernel/signal-common.h index b1f09d5..fdbdbdc 100644 --- a/arch/mips/kernel/signal-common.h +++ b/arch/mips/kernel/signal-common.h @@ -8,169 +8,27 @@ * Copyright (C) 1999, 2000 Silicon Graphics, Inc. */ +#ifndef __SIGNAL_COMMON_H +#define __SIGNAL_COMMON_H -static inline int -setup_sigcontext(struct pt_regs *regs, struct sigcontext __user *sc) -{ - int err = 0; +/* #define DEBUG_SIG */ - err |= __put_user(regs->cp0_epc, &sc->sc_pc); +#ifdef DEBUG_SIG +# define DEBUGP(fmt, args...) printk("%s: " fmt, __FUNCTION__ , ##args) +#else +# define DEBUGP(fmt, args...) +#endif -#define save_gp_reg(i) do { \ - err |= __put_user(regs->regs[i], &sc->sc_regs[i]); \ -} while(0) - __put_user(0, &sc->sc_regs[0]); save_gp_reg(1); save_gp_reg(2); - save_gp_reg(3); save_gp_reg(4); save_gp_reg(5); save_gp_reg(6); - save_gp_reg(7); save_gp_reg(8); save_gp_reg(9); save_gp_reg(10); - save_gp_reg(11); save_gp_reg(12); save_gp_reg(13); save_gp_reg(14); - save_gp_reg(15); save_gp_reg(16); save_gp_reg(17); save_gp_reg(18); - save_gp_reg(19); save_gp_reg(20); save_gp_reg(21); save_gp_reg(22); - save_gp_reg(23); save_gp_reg(24); save_gp_reg(25); save_gp_reg(26); - save_gp_reg(27); save_gp_reg(28); save_gp_reg(29); save_gp_reg(30); - save_gp_reg(31); -#undef save_gp_reg - - err |= __put_user(regs->hi, &sc->sc_mdhi); - err |= __put_user(regs->lo, &sc->sc_mdlo); - if (cpu_has_dsp) { - err |= __put_user(mfhi1(), &sc->sc_hi1); - err |= __put_user(mflo1(), &sc->sc_lo1); - err |= __put_user(mfhi2(), &sc->sc_hi2); - err |= __put_user(mflo2(), &sc->sc_lo2); - err |= __put_user(mfhi3(), &sc->sc_hi3); - err |= __put_user(mflo3(), &sc->sc_lo3); - err |= __put_user(rddsp(DSP_MASK), &sc->sc_dsp); - } - - err |= __put_user(!!used_math(), &sc->sc_used_math); - - if (!used_math()) - goto out; - - /* - * Save FPU state to signal context. Signal handler will "inherit" - * current FPU state. - */ - preempt_disable(); - - if (!is_fpu_owner()) { - own_fpu(); - restore_fp(current); - } - err |= save_fp_context(sc); - - preempt_enable(); - -out: - return err; -} - -static inline int -restore_sigcontext(struct pt_regs *regs, struct sigcontext __user *sc) -{ - unsigned int used_math; - unsigned long treg; - int err = 0; - - /* Always make any pending restarted system calls return -EINTR */ - current_thread_info()->restart_block.fn = do_no_restart_syscall; - - err |= __get_user(regs->cp0_epc, &sc->sc_pc); - err |= __get_user(regs->hi, &sc->sc_mdhi); - err |= __get_user(regs->lo, &sc->sc_mdlo); - if (cpu_has_dsp) { - err |= __get_user(treg, &sc->sc_hi1); mthi1(treg); - err |= __get_user(treg, &sc->sc_lo1); mtlo1(treg); - err |= __get_user(treg, &sc->sc_hi2); mthi2(treg); - err |= __get_user(treg, &sc->sc_lo2); mtlo2(treg); - err |= __get_user(treg, &sc->sc_hi3); mthi3(treg); - err |= __get_user(treg, &sc->sc_lo3); mtlo3(treg); - err |= __get_user(treg, &sc->sc_dsp); wrdsp(treg, DSP_MASK); - } - -#define restore_gp_reg(i) do { \ - err |= __get_user(regs->regs[i], &sc->sc_regs[i]); \ -} while(0) - restore_gp_reg( 1); restore_gp_reg( 2); restore_gp_reg( 3); - restore_gp_reg( 4); restore_gp_reg( 5); restore_gp_reg( 6); - restore_gp_reg( 7); restore_gp_reg( 8); restore_gp_reg( 9); - restore_gp_reg(10); restore_gp_reg(11); restore_gp_reg(12); - restore_gp_reg(13); restore_gp_reg(14); restore_gp_reg(15); - restore_gp_reg(16); restore_gp_reg(17); restore_gp_reg(18); - restore_gp_reg(19); restore_gp_reg(20); restore_gp_reg(21); - restore_gp_reg(22); restore_gp_reg(23); restore_gp_reg(24); - restore_gp_reg(25); restore_gp_reg(26); restore_gp_reg(27); - restore_gp_reg(28); restore_gp_reg(29); restore_gp_reg(30); - restore_gp_reg(31); -#undef restore_gp_reg - - err |= __get_user(used_math, &sc->sc_used_math); - conditional_used_math(used_math); - - preempt_disable(); - - if (used_math()) { - /* restore fpu context if we have used it before */ - own_fpu(); - err |= restore_fp_context(sc); - } else { - /* signal handler may have used FPU. Give it up. */ - lose_fpu(); - } - - preempt_enable(); - - return err; -} +#define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP))) /* * Determine which stack to use.. */ -static inline void __user * -get_sigframe(struct k_sigaction *ka, struct pt_regs *regs, size_t frame_size) -{ - unsigned long sp; - - /* Default to using normal stack */ - sp = regs->regs[29]; - - /* - * FPU emulator may have it's own trampoline active just - * above the user stack, 16-bytes before the next lowest - * 16 byte boundary. Try to avoid trashing it. - */ - sp -= 32; - - /* This is the X/Open sanctioned signal stack switching. */ - if ((ka->sa.sa_flags & SA_ONSTACK) && (sas_ss_flags (sp) == 0)) - sp = current->sas_ss_sp + current->sas_ss_size; - - return (void __user *)((sp - frame_size) & (ICACHE_REFILLS_WORKAROUND_WAR ? ~(cpu_icache_line_size()-1) : ALMASK)); -} - -static inline int install_sigtramp(unsigned int __user *tramp, - unsigned int syscall) -{ - int err; - - /* - * Set up the return code ... - * - * li v0, __NR__foo_sigreturn - * syscall - */ - - err = __put_user(0x24020000 + syscall, tramp + 0); - err |= __put_user(0x0000000c , tramp + 1); - if (ICACHE_REFILLS_WORKAROUND_WAR) { - err |= __put_user(0, tramp + 2); - err |= __put_user(0, tramp + 3); - err |= __put_user(0, tramp + 4); - err |= __put_user(0, tramp + 5); - err |= __put_user(0, tramp + 6); - err |= __put_user(0, tramp + 7); - } - flush_cache_sigtramp((unsigned long) tramp); +extern void __user *get_sigframe(struct k_sigaction *ka, struct pt_regs *regs, + size_t frame_size); +/* + * install trampoline code to get back from the sig handler + */ +extern int install_sigtramp(unsigned int __user *tramp, unsigned int syscall); - return err; -} +#endif /* __SIGNAL_COMMON_H */ diff --git a/arch/mips/kernel/signal.c b/arch/mips/kernel/signal.c index b9d358e..b2e9ab1 100644 --- a/arch/mips/kernel/signal.c +++ b/arch/mips/kernel/signal.c @@ -34,18 +34,192 @@ #include #include "signal-common.h" -#define DEBUG_SIG 0 +/* + * Horribly complicated - with the bloody RM9000 workarounds enabled + * the signal trampolines is moving to the end of the structure so we can + * increase the alignment without breaking software compatibility. + */ +#if ICACHE_REFILLS_WORKAROUND_WAR == 0 -#define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP))) +struct sigframe { + u32 sf_ass[4]; /* argument save space for o32 */ + u32 sf_code[2]; /* signal trampoline */ + struct sigcontext sf_sc; + sigset_t sf_mask; +}; + +struct rt_sigframe { + u32 rs_ass[4]; /* argument save space for o32 */ + u32 rs_code[2]; /* signal trampoline */ + struct siginfo rs_info; + struct ucontext rs_uc; +}; + +#else + +struct sigframe { + u32 sf_ass[4]; /* argument save space for o32 */ + u32 sf_pad[2]; + struct sigcontext sf_sc; /* hw context */ + sigset_t sf_mask; + u32 sf_code[8] ____cacheline_aligned; /* signal trampoline */ +}; + +struct rt_sigframe { + u32 rs_ass[4]; /* argument save space for o32 */ + u32 rs_pad[2]; + struct siginfo rs_info; + struct ucontext rs_uc; + u32 rs_code[8] ____cacheline_aligned; /* signal trampoline */ +}; + +#endif + +/* + * Helper routines + */ +int setup_sigcontext(struct pt_regs *regs, struct sigcontext __user *sc) +{ + int err = 0; + int i; + + err |= __put_user(regs->cp0_epc, &sc->sc_pc); + + err |= __put_user(0, &sc->sc_regs[0]); + for (i = 1; i < 32; i++) + err |= __put_user(regs->regs[i], &sc->sc_regs[i]); + + err |= __put_user(regs->hi, &sc->sc_mdhi); + err |= __put_user(regs->lo, &sc->sc_mdlo); + if (cpu_has_dsp) { + err |= __put_user(mfhi1(), &sc->sc_hi1); + err |= __put_user(mflo1(), &sc->sc_lo1); + err |= __put_user(mfhi2(), &sc->sc_hi2); + err |= __put_user(mflo2(), &sc->sc_lo2); + err |= __put_user(mfhi3(), &sc->sc_hi3); + err |= __put_user(mflo3(), &sc->sc_lo3); + err |= __put_user(rddsp(DSP_MASK), &sc->sc_dsp); + } + + err |= __put_user(!!used_math(), &sc->sc_used_math); + + if (used_math()) { + /* + * Save FPU state to signal context. Signal handler + * will "inherit" current FPU state. + */ + preempt_disable(); + + if (!is_fpu_owner()) { + own_fpu(); + restore_fp(current); + } + err |= save_fp_context(sc); + + preempt_enable(); + } + return err; +} + +int restore_sigcontext(struct pt_regs *regs, struct sigcontext __user *sc) +{ + unsigned int used_math; + unsigned long treg; + int err = 0; + int i; + + /* Always make any pending restarted system calls return -EINTR */ + current_thread_info()->restart_block.fn = do_no_restart_syscall; + + err |= __get_user(regs->cp0_epc, &sc->sc_pc); + err |= __get_user(regs->hi, &sc->sc_mdhi); + err |= __get_user(regs->lo, &sc->sc_mdlo); + if (cpu_has_dsp) { + err |= __get_user(treg, &sc->sc_hi1); mthi1(treg); + err |= __get_user(treg, &sc->sc_lo1); mtlo1(treg); + err |= __get_user(treg, &sc->sc_hi2); mthi2(treg); + err |= __get_user(treg, &sc->sc_lo2); mtlo2(treg); + err |= __get_user(treg, &sc->sc_hi3); mthi3(treg); + err |= __get_user(treg, &sc->sc_lo3); mtlo3(treg); + err |= __get_user(treg, &sc->sc_dsp); wrdsp(treg, DSP_MASK); + } + + for (i = 1; i < 32; i++) + err |= __get_user(regs->regs[i], &sc->sc_regs[i]); + + err |= __get_user(used_math, &sc->sc_used_math); + conditional_used_math(used_math); + + preempt_disable(); + + if (used_math()) { + /* restore fpu context if we have used it before */ + own_fpu(); + err |= restore_fp_context(sc); + } else { + /* signal handler may have used FPU. Give it up. */ + lose_fpu(); + } + + preempt_enable(); + + return err; +} + +void __user *get_sigframe(struct k_sigaction *ka, struct pt_regs *regs, + size_t frame_size) +{ + unsigned long sp; + + /* Default to using normal stack */ + sp = regs->regs[29]; + + /* + * FPU emulator may have it's own trampoline active just + * above the user stack, 16-bytes before the next lowest + * 16 byte boundary. Try to avoid trashing it. + */ + sp -= 32; + + /* This is the X/Open sanctioned signal stack switching. */ + if ((ka->sa.sa_flags & SA_ONSTACK) && (sas_ss_flags (sp) == 0)) + sp = current->sas_ss_sp + current->sas_ss_size; + + return (void __user *)((sp - frame_size) & (ICACHE_REFILLS_WORKAROUND_WAR ? ~(cpu_icache_line_size()-1) : ALMASK)); +} + +int install_sigtramp(unsigned int __user *tramp, unsigned int syscall) +{ + int err; + + /* + * Set up the return code ... + * + * li v0, __NR__foo_sigreturn + * syscall + */ + + err = __put_user(0x24020000 + syscall, tramp + 0); + err |= __put_user(0x0000000c , tramp + 1); + if (ICACHE_REFILLS_WORKAROUND_WAR) { + err |= __put_user(0, tramp + 2); + err |= __put_user(0, tramp + 3); + err |= __put_user(0, tramp + 4); + err |= __put_user(0, tramp + 5); + err |= __put_user(0, tramp + 6); + err |= __put_user(0, tramp + 7); + } + flush_cache_sigtramp((unsigned long) tramp); + + return err; +} /* * Atomically swap in the new signal mask, and wait for a signal. */ #ifdef CONFIG_TRAD_SIGNALS -save_static_function(sys_sigsuspend); -__attribute_used__ noinline static int -_sys_sigsuspend(nabi_no_regargs struct pt_regs regs) +asmlinkage int sys_sigsuspend(nabi_no_regargs struct pt_regs regs) { sigset_t newset; sigset_t __user *uset; @@ -68,9 +242,7 @@ _sys_sigsuspend(nabi_no_regargs struct p } #endif -save_static_function(sys_rt_sigsuspend); -__attribute_used__ noinline static int -_sys_rt_sigsuspend(nabi_no_regargs struct pt_regs regs) +asmlinkage int sys_rt_sigsuspend(nabi_no_regargs struct pt_regs regs) { sigset_t newset; sigset_t __user *unewset; @@ -89,7 +261,7 @@ _sys_rt_sigsuspend(nabi_no_regargs struc spin_lock_irq(¤t->sighand->siglock); current->saved_sigmask = current->blocked; current->blocked = newset; - recalc_sigpending(); + recalc_sigpending(); spin_unlock_irq(¤t->sighand->siglock); current->state = TASK_INTERRUPTIBLE; @@ -124,7 +296,7 @@ asmlinkage int sys_sigaction(int sig, co if (!ret && oact) { if (!access_ok(VERIFY_WRITE, oact, sizeof(*oact))) - return -EFAULT; + return -EFAULT; err |= __put_user(old_ka.sa.sa_flags, &oact->sa_flags); err |= __put_user(old_ka.sa.sa_handler, &oact->sa_handler); err |= __put_user(old_ka.sa.sa_mask.sig[0], oact->sa_mask.sig); @@ -148,45 +320,8 @@ asmlinkage int sys_sigaltstack(nabi_no_r return do_sigaltstack(uss, uoss, usp); } -/* - * Horribly complicated - with the bloody RM9000 workarounds enabled - * the signal trampolines is moving to the end of the structure so we can - * increase the alignment without breaking software compatibility. - */ -#ifdef CONFIG_TRAD_SIGNALS -struct sigframe { - u32 sf_ass[4]; /* argument save space for o32 */ -#if ICACHE_REFILLS_WORKAROUND_WAR - u32 sf_pad[2]; -#else - u32 sf_code[2]; /* signal trampoline */ -#endif - struct sigcontext sf_sc; - sigset_t sf_mask; -#if ICACHE_REFILLS_WORKAROUND_WAR - u32 sf_code[8] ____cacheline_aligned; /* signal trampoline */ -#endif -}; -#endif - -struct rt_sigframe { - u32 rs_ass[4]; /* argument save space for o32 */ -#if ICACHE_REFILLS_WORKAROUND_WAR - u32 rs_pad[2]; -#else - u32 rs_code[2]; /* signal trampoline */ -#endif - struct siginfo rs_info; - struct ucontext rs_uc; -#if ICACHE_REFILLS_WORKAROUND_WAR - u32 rs_code[8] ____cacheline_aligned; /* signal trampoline */ -#endif -}; - #ifdef CONFIG_TRAD_SIGNALS -save_static_function(sys_sigreturn); -__attribute_used__ noinline static void -_sys_sigreturn(nabi_no_regargs struct pt_regs regs) +asmlinkage void sys_sigreturn(nabi_no_regargs struct pt_regs regs) { struct sigframe __user *frame; sigset_t blocked; @@ -221,9 +356,7 @@ badframe: } #endif /* CONFIG_TRAD_SIGNALS */ -save_static_function(sys_rt_sigreturn); -__attribute_used__ noinline static void -_sys_rt_sigreturn(nabi_no_regargs struct pt_regs regs) +asmlinkage void sys_rt_sigreturn(nabi_no_regargs struct pt_regs regs) { struct rt_sigframe __user *frame; sigset_t set; @@ -275,7 +408,7 @@ int setup_frame(struct k_sigaction * ka, if (!access_ok(VERIFY_WRITE, frame, sizeof (*frame))) goto give_sigsegv; - install_sigtramp(frame->sf_code, __NR_sigreturn); + err |= install_sigtramp(frame->sf_code, __NR_sigreturn); err |= setup_sigcontext(regs, &frame->sf_sc); err |= __copy_to_user(&frame->sf_mask, set, sizeof(*set)); @@ -299,12 +432,10 @@ int setup_frame(struct k_sigaction * ka, regs->regs[31] = (unsigned long) frame->sf_code; regs->cp0_epc = regs->regs[25] = (unsigned long) ka->sa.sa_handler; -#if DEBUG_SIG - printk("SIG deliver (%s:%d): sp=0x%p pc=0x%lx ra=0x%p\n", + DEBUGP("SIG deliver (%s:%d): sp=0x%p pc=0x%lx ra=0x%lx\n", current->comm, current->pid, - frame, regs->cp0_epc, frame->regs[31]); -#endif - return 0; + frame, regs->cp0_epc, regs->regs[31]); + return 0; give_sigsegv: force_sigsegv(signr, current); @@ -322,7 +453,7 @@ int setup_rt_frame(struct k_sigaction * if (!access_ok(VERIFY_WRITE, frame, sizeof (*frame))) goto give_sigsegv; - install_sigtramp(frame->rs_code, __NR_rt_sigreturn); + err |= install_sigtramp(frame->rs_code, __NR_rt_sigreturn); /* Create siginfo. */ err |= copy_siginfo_to_user(&frame->rs_info, info); @@ -359,11 +490,10 @@ int setup_rt_frame(struct k_sigaction * regs->regs[31] = (unsigned long) frame->rs_code; regs->cp0_epc = regs->regs[25] = (unsigned long) ka->sa.sa_handler; -#if DEBUG_SIG - printk("SIG deliver (%s:%d): sp=0x%p pc=0x%lx ra=0x%p\n", + DEBUGP("SIG deliver (%s:%d): sp=0x%p pc=0x%lx ra=0x%lx\n", current->comm, current->pid, frame, regs->cp0_epc, regs->regs[31]); -#endif + return 0; give_sigsegv: @@ -371,7 +501,7 @@ give_sigsegv: return -EFAULT; } -static inline int handle_signal(unsigned long sig, siginfo_t *info, +static int handle_signal(unsigned long sig, siginfo_t *info, struct k_sigaction *ka, sigset_t *oldset, struct pt_regs *regs) { int ret; diff --git a/arch/mips/kernel/signal32.c b/arch/mips/kernel/signal32.c index c86a5dd..c28cb21 100644 --- a/arch/mips/kernel/signal32.c +++ b/arch/mips/kernel/signal32.c @@ -8,6 +8,7 @@ * Copyright (C) 1999, 2000 Silicon Graphics, Inc. */ #include +#include #include #include #include @@ -24,6 +25,7 @@ #include #include #include +#include #include #include #include @@ -33,6 +35,8 @@ #include #include #include +#include "signal-common.h" + #define SI_PAD_SIZE32 ((SI_MAX_SIZE/sizeof(int)) - 3) typedef struct compat_siginfo { @@ -102,10 +106,6 @@ #define __NR_O32_sigreturn 4119 #define __NR_O32_rt_sigreturn 4193 #define __NR_O32_restart_syscall 4253 -#define DEBUG_SIG 0 - -#define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP))) - /* 32-bit compatibility types */ #define _NSIG_BPW32 32 @@ -139,6 +139,143 @@ struct ucontext32 { sigset_t32 uc_sigmask; /* mask last for extensibility */ }; +/* + * Horribly complicated - with the bloody RM9000 workarounds enabled + * the signal trampolines is moving to the end of the structure so we can + * increase the alignment without breaking software compatibility. + */ +#if ICACHE_REFILLS_WORKAROUND_WAR == 0 + +struct sigframe32 { + u32 sf_ass[4]; /* argument save space for o32 */ + u32 sf_code[2]; /* signal trampoline */ + struct sigcontext32 sf_sc; + sigset_t sf_mask; +}; + +struct rt_sigframe32 { + u32 rs_ass[4]; /* argument save space for o32 */ + u32 rs_code[2]; /* signal trampoline */ + compat_siginfo_t rs_info; + struct ucontext32 rs_uc; +}; + +#else /* ICACHE_REFILLS_WORKAROUND_WAR */ + +struct sigframe32 { + u32 sf_ass[4]; /* argument save space for o32 */ + u32 sf_pad[2]; + struct sigcontext32 sf_sc; /* hw context */ + sigset_t sf_mask; + u32 sf_code[8] ____cacheline_aligned; /* signal trampoline */ +}; + +struct rt_sigframe32 { + u32 rs_ass[4]; /* argument save space for o32 */ + u32 rs_pad[2]; + compat_siginfo_t rs_info; + struct ucontext32 rs_uc; + u32 rs_code[8] __attribute__((aligned(32))); /* signal trampoline */ +}; + +#endif /* !ICACHE_REFILLS_WORKAROUND_WAR */ + +/* + * sigcontext handlers + */ +static int setup_sigcontext32(struct pt_regs *regs, + struct sigcontext32 __user *sc) +{ + int err = 0; + int i; + + err |= __put_user(regs->cp0_epc, &sc->sc_pc); + + err |= __put_user(0, &sc->sc_regs[0]); + for (i = 1; i < 32; i++) + err |= __put_user(regs->regs[i], &sc->sc_regs[i]); + + err |= __put_user(regs->hi, &sc->sc_mdhi); + err |= __put_user(regs->lo, &sc->sc_mdlo); + if (cpu_has_dsp) { + err |= __put_user(rddsp(DSP_MASK), &sc->sc_dsp); + err |= __put_user(mfhi1(), &sc->sc_hi1); + err |= __put_user(mflo1(), &sc->sc_lo1); + err |= __put_user(mfhi2(), &sc->sc_hi2); + err |= __put_user(mflo2(), &sc->sc_lo2); + err |= __put_user(mfhi3(), &sc->sc_hi3); + err |= __put_user(mflo3(), &sc->sc_lo3); + } + + err |= __put_user(!!used_math(), &sc->sc_used_math); + + if (used_math()) { + /* + * Save FPU state to signal context. Signal handler + * will "inherit" current FPU state. + */ + preempt_disable(); + + if (!is_fpu_owner()) { + own_fpu(); + restore_fp(current); + } + err |= save_fp_context32(sc); + + preempt_enable(); + } + return err; +} + +static int restore_sigcontext32(struct pt_regs *regs, + struct sigcontext32 __user *sc) +{ + u32 used_math; + int err = 0; + s32 treg; + int i; + + /* Always make any pending restarted system calls return -EINTR */ + current_thread_info()->restart_block.fn = do_no_restart_syscall; + + err |= __get_user(regs->cp0_epc, &sc->sc_pc); + err |= __get_user(regs->hi, &sc->sc_mdhi); + err |= __get_user(regs->lo, &sc->sc_mdlo); + if (cpu_has_dsp) { + err |= __get_user(treg, &sc->sc_hi1); mthi1(treg); + err |= __get_user(treg, &sc->sc_lo1); mtlo1(treg); + err |= __get_user(treg, &sc->sc_hi2); mthi2(treg); + err |= __get_user(treg, &sc->sc_lo2); mtlo2(treg); + err |= __get_user(treg, &sc->sc_hi3); mthi3(treg); + err |= __get_user(treg, &sc->sc_lo3); mtlo3(treg); + err |= __get_user(treg, &sc->sc_dsp); wrdsp(treg, DSP_MASK); + } + + for (i = 1; i < 32; i++) + err |= __get_user(regs->regs[i], &sc->sc_regs[i]); + + err |= __get_user(used_math, &sc->sc_used_math); + conditional_used_math(used_math); + + preempt_disable(); + + if (used_math()) { + /* restore fpu context if we have used it before */ + own_fpu(); + err |= restore_fp_context32(sc); + } else { + /* signal handler may have used FPU. Give it up. */ + lose_fpu(); + } + + preempt_enable(); + + return err; +} + +/* + * + */ extern void __put_sigset_unknown_nsig(void); extern void __get_sigset_unknown_nsig(void); @@ -191,9 +328,7 @@ static inline int get_sigset(sigset_t *k * Atomically swap in the new signal mask, and wait for a signal. */ -save_static_function(sys32_sigsuspend); -__attribute_used__ noinline static int -_sys32_sigsuspend(nabi_no_regargs struct pt_regs regs) +asmlinkage int sys32_sigsuspend(nabi_no_regargs struct pt_regs regs) { compat_sigset_t __user *uset; sigset_t newset; @@ -215,9 +350,7 @@ _sys32_sigsuspend(nabi_no_regargs struct return -ERESTARTNOHAND; } -save_static_function(sys32_rt_sigsuspend); -__attribute_used__ noinline static int -_sys32_rt_sigsuspend(nabi_no_regargs struct pt_regs regs) +asmlinkage int sys32_rt_sigsuspend(nabi_no_regargs struct pt_regs regs) { compat_sigset_t __user *uset; sigset_t newset; @@ -326,91 +459,6 @@ asmlinkage int sys32_sigaltstack(nabi_no return ret; } -static int restore_sigcontext32(struct pt_regs *regs, struct sigcontext32 __user *sc) -{ - u32 used_math; - int err = 0; - s32 treg; - - /* Always make any pending restarted system calls return -EINTR */ - current_thread_info()->restart_block.fn = do_no_restart_syscall; - - err |= __get_user(regs->cp0_epc, &sc->sc_pc); - err |= __get_user(regs->hi, &sc->sc_mdhi); - err |= __get_user(regs->lo, &sc->sc_mdlo); - if (cpu_has_dsp) { - err |= __get_user(treg, &sc->sc_hi1); mthi1(treg); - err |= __get_user(treg, &sc->sc_lo1); mtlo1(treg); - err |= __get_user(treg, &sc->sc_hi2); mthi2(treg); - err |= __get_user(treg, &sc->sc_lo2); mtlo2(treg); - err |= __get_user(treg, &sc->sc_hi3); mthi3(treg); - err |= __get_user(treg, &sc->sc_lo3); mtlo3(treg); - err |= __get_user(treg, &sc->sc_dsp); wrdsp(treg, DSP_MASK); - } - -#define restore_gp_reg(i) do { \ - err |= __get_user(regs->regs[i], &sc->sc_regs[i]); \ -} while(0) - restore_gp_reg( 1); restore_gp_reg( 2); restore_gp_reg( 3); - restore_gp_reg( 4); restore_gp_reg( 5); restore_gp_reg( 6); - restore_gp_reg( 7); restore_gp_reg( 8); restore_gp_reg( 9); - restore_gp_reg(10); restore_gp_reg(11); restore_gp_reg(12); - restore_gp_reg(13); restore_gp_reg(14); restore_gp_reg(15); - restore_gp_reg(16); restore_gp_reg(17); restore_gp_reg(18); - restore_gp_reg(19); restore_gp_reg(20); restore_gp_reg(21); - restore_gp_reg(22); restore_gp_reg(23); restore_gp_reg(24); - restore_gp_reg(25); restore_gp_reg(26); restore_gp_reg(27); - restore_gp_reg(28); restore_gp_reg(29); restore_gp_reg(30); - restore_gp_reg(31); -#undef restore_gp_reg - - err |= __get_user(used_math, &sc->sc_used_math); - conditional_used_math(used_math); - - preempt_disable(); - - if (used_math()) { - /* restore fpu context if we have used it before */ - own_fpu(); - err |= restore_fp_context32(sc); - } else { - /* signal handler may have used FPU. Give it up. */ - lose_fpu(); - } - - preempt_enable(); - - return err; -} - -struct sigframe { - u32 sf_ass[4]; /* argument save space for o32 */ -#if ICACHE_REFILLS_WORKAROUND_WAR - u32 sf_pad[2]; -#else - u32 sf_code[2]; /* signal trampoline */ -#endif - struct sigcontext32 sf_sc; - sigset_t sf_mask; -#if ICACHE_REFILLS_WORKAROUND_WAR - u32 sf_code[8] ____cacheline_aligned; /* signal trampoline */ -#endif -}; - -struct rt_sigframe32 { - u32 rs_ass[4]; /* argument save space for o32 */ -#if ICACHE_REFILLS_WORKAROUND_WAR - u32 rs_pad[2]; -#else - u32 rs_code[2]; /* signal trampoline */ -#endif - compat_siginfo_t rs_info; - struct ucontext32 rs_uc; -#if ICACHE_REFILLS_WORKAROUND_WAR - u32 rs_code[8] __attribute__((aligned(32))); /* signal trampoline */ -#endif -}; - int copy_siginfo_to_user32(compat_siginfo_t __user *to, siginfo_t *from) { int err; @@ -463,17 +511,15 @@ int copy_siginfo_to_user32(compat_siginf return err; } -save_static_function(sys32_sigreturn); -__attribute_used__ noinline static void -_sys32_sigreturn(nabi_no_regargs struct pt_regs regs) +asmlinkage void sys32_sigreturn(nabi_no_regargs struct pt_regs regs) { - struct sigframe __user *frame; + struct sigframe32 __user *frame; sigset_t blocked; - frame = (struct sigframe __user *) regs.regs[29]; + frame = (struct sigframe32 __user *) regs.regs[29]; if (!access_ok(VERIFY_READ, frame, sizeof(*frame))) goto badframe; - if (__copy_from_user(&blocked, &frame->sf_mask, sizeof(blocked))) + if (__copy_conv_sigset_from_user(&blocked, &frame->sf_mask)) goto badframe; sigdelsetmask(&blocked, ~_BLOCKABLE); @@ -499,9 +545,7 @@ badframe: force_sig(SIGSEGV, current); } -save_static_function(sys32_rt_sigreturn); -__attribute_used__ noinline static void -_sys32_rt_sigreturn(nabi_no_regargs struct pt_regs regs) +asmlinkage void sys32_rt_sigreturn(nabi_no_regargs struct pt_regs regs) { struct rt_sigframe32 __user *frame; mm_segment_t old_fs; @@ -512,7 +556,7 @@ _sys32_rt_sigreturn(nabi_no_regargs stru frame = (struct rt_sigframe32 __user *) regs.regs[29]; if (!access_ok(VERIFY_READ, frame, sizeof(*frame))) goto badframe; - if (__copy_from_user(&set, &frame->rs_uc.uc_sigmask, sizeof(set))) + if (__copy_conv_sigset_from_user(&set, &frame->rs_uc.uc_sigmask)) goto badframe; sigdelsetmask(&set, ~_BLOCKABLE); @@ -554,111 +598,21 @@ badframe: force_sig(SIGSEGV, current); } -static inline int setup_sigcontext32(struct pt_regs *regs, - struct sigcontext32 __user *sc) -{ - int err = 0; - - err |= __put_user(regs->cp0_epc, &sc->sc_pc); - err |= __put_user(regs->cp0_status, &sc->sc_status); - -#define save_gp_reg(i) { \ - err |= __put_user(regs->regs[i], &sc->sc_regs[i]); \ -} while(0) - __put_user(0, &sc->sc_regs[0]); save_gp_reg(1); save_gp_reg(2); - save_gp_reg(3); save_gp_reg(4); save_gp_reg(5); save_gp_reg(6); - save_gp_reg(7); save_gp_reg(8); save_gp_reg(9); save_gp_reg(10); - save_gp_reg(11); save_gp_reg(12); save_gp_reg(13); save_gp_reg(14); - save_gp_reg(15); save_gp_reg(16); save_gp_reg(17); save_gp_reg(18); - save_gp_reg(19); save_gp_reg(20); save_gp_reg(21); save_gp_reg(22); - save_gp_reg(23); save_gp_reg(24); save_gp_reg(25); save_gp_reg(26); - save_gp_reg(27); save_gp_reg(28); save_gp_reg(29); save_gp_reg(30); - save_gp_reg(31); -#undef save_gp_reg - - err |= __put_user(regs->hi, &sc->sc_mdhi); - err |= __put_user(regs->lo, &sc->sc_mdlo); - if (cpu_has_dsp) { - err |= __put_user(rddsp(DSP_MASK), &sc->sc_dsp); - err |= __put_user(mfhi1(), &sc->sc_hi1); - err |= __put_user(mflo1(), &sc->sc_lo1); - err |= __put_user(mfhi2(), &sc->sc_hi2); - err |= __put_user(mflo2(), &sc->sc_lo2); - err |= __put_user(mfhi3(), &sc->sc_hi3); - err |= __put_user(mflo3(), &sc->sc_lo3); - } - - err |= __put_user(!!used_math(), &sc->sc_used_math); - - if (!used_math()) - goto out; - - /* - * Save FPU state to signal context. Signal handler will "inherit" - * current FPU state. - */ - preempt_disable(); - - if (!is_fpu_owner()) { - own_fpu(); - restore_fp(current); - } - err |= save_fp_context32(sc); - - preempt_enable(); - -out: - return err; -} - -/* - * Determine which stack to use.. - */ -static inline void __user *get_sigframe(struct k_sigaction *ka, - struct pt_regs *regs, - size_t frame_size) -{ - unsigned long sp; - - /* Default to using normal stack */ - sp = regs->regs[29]; - - /* - * FPU emulator may have it's own trampoline active just - * above the user stack, 16-bytes before the next lowest - * 16 byte boundary. Try to avoid trashing it. - */ - sp -= 32; - - /* This is the X/Open sanctioned signal stack switching. */ - if ((ka->sa.sa_flags & SA_ONSTACK) && (sas_ss_flags (sp) == 0)) - sp = current->sas_ss_sp + current->sas_ss_size; - - return (void __user *)((sp - frame_size) & ALMASK); -} - int setup_frame_32(struct k_sigaction * ka, struct pt_regs *regs, int signr, sigset_t *set) { - struct sigframe __user *frame; + struct sigframe32 __user *frame; int err = 0; frame = get_sigframe(ka, regs, sizeof(*frame)); if (!access_ok(VERIFY_WRITE, frame, sizeof (*frame))) goto give_sigsegv; - /* - * Set up the return code ... - * - * li v0, __NR_O32_sigreturn - * syscall - */ - err |= __put_user(0x24020000 + __NR_O32_sigreturn, frame->sf_code + 0); - err |= __put_user(0x0000000c , frame->sf_code + 1); - flush_cache_sigtramp((unsigned long) frame->sf_code); + err |= install_sigtramp(frame->sf_code, __NR_O32_sigreturn); err |= setup_sigcontext32(regs, &frame->sf_sc); - err |= __copy_to_user(&frame->sf_mask, set, sizeof(*set)); + err |= __copy_conv_sigset_to_user(&frame->sf_mask, set); + if (err) goto give_sigsegv; @@ -679,11 +633,10 @@ int setup_frame_32(struct k_sigaction * regs->regs[31] = (unsigned long) frame->sf_code; regs->cp0_epc = regs->regs[25] = (unsigned long) ka->sa.sa_handler; -#if DEBUG_SIG - printk("SIG deliver (%s:%d): sp=0x%p pc=0x%lx ra=0x%p\n", + DEBUGP("SIG deliver (%s:%d): sp=0x%p pc=0x%lx ra=0x%lx\n", current->comm, current->pid, - frame, regs->cp0_epc, frame->sf_code); -#endif + frame, regs->cp0_epc, regs->regs[31]); + return 0; give_sigsegv: @@ -702,17 +655,7 @@ int setup_rt_frame_32(struct k_sigaction if (!access_ok(VERIFY_WRITE, frame, sizeof (*frame))) goto give_sigsegv; - /* Set up to return from userspace. If provided, use a stub already - in userspace. */ - /* - * Set up the return code ... - * - * li v0, __NR_O32_rt_sigreturn - * syscall - */ - err |= __put_user(0x24020000 + __NR_O32_rt_sigreturn, frame->rs_code + 0); - err |= __put_user(0x0000000c , frame->rs_code + 1); - flush_cache_sigtramp((unsigned long) frame->rs_code); + err |= install_sigtramp(frame->rs_code, __NR_O32_rt_sigreturn); /* Convert (siginfo_t -> compat_siginfo_t) and copy to user. */ err |= copy_siginfo_to_user32(&frame->rs_info, info); @@ -728,7 +671,7 @@ int setup_rt_frame_32(struct k_sigaction err |= __put_user(current->sas_ss_size, &frame->rs_uc.uc_stack.ss_size); err |= setup_sigcontext32(regs, &frame->rs_uc.uc_mcontext); - err |= __copy_to_user(&frame->rs_uc.uc_sigmask, set, sizeof(*set)); + err |= __copy_conv_sigset_to_user(&frame->rs_uc.uc_sigmask, set); if (err) goto give_sigsegv; @@ -750,11 +693,10 @@ int setup_rt_frame_32(struct k_sigaction regs->regs[31] = (unsigned long) frame->rs_code; regs->cp0_epc = regs->regs[25] = (unsigned long) ka->sa.sa_handler; -#if DEBUG_SIG - printk("SIG deliver (%s:%d): sp=0x%p pc=0x%lx ra=0x%p\n", + DEBUGP("SIG deliver (%s:%d): sp=0x%p pc=0x%lx ra=0x%lx\n", current->comm, current->pid, - frame, regs->cp0_epc, frame->rs_code); -#endif + frame, regs->cp0_epc, regs->regs[31]); + return 0; give_sigsegv: diff --git a/arch/mips/kernel/signal_n32.c b/arch/mips/kernel/signal_n32.c index a67c185..7ca2a07 100644 --- a/arch/mips/kernel/signal_n32.c +++ b/arch/mips/kernel/signal_n32.c @@ -31,6 +31,7 @@ #include #include #include +#include #include #include #include @@ -47,9 +48,9 @@ #include "signal-common.h" #define __NR_N32_rt_sigreturn 6211 #define __NR_N32_restart_syscall 6214 -#define DEBUG_SIG 0 +extern int setup_sigcontext(struct pt_regs *, struct sigcontext __user *); +extern int restore_sigcontext(struct pt_regs *, struct sigcontext __user *); -#define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP))) /* IRIX compatible stack_t */ typedef struct sigaltstack32 { @@ -63,28 +64,33 @@ struct ucontextn32 { s32 uc_link; stack32_t uc_stack; struct sigcontext uc_mcontext; - sigset_t uc_sigmask; /* mask last for extensibility */ + compat_sigset_t uc_sigmask; /* mask last for extensibility */ }; +#if ICACHE_REFILLS_WORKAROUND_WAR == 0 + struct rt_sigframe_n32 { u32 rs_ass[4]; /* argument save space for o32 */ -#if ICACHE_REFILLS_WORKAROUND_WAR - u32 rs_pad[2]; -#else u32 rs_code[2]; /* signal trampoline */ -#endif struct siginfo rs_info; struct ucontextn32 rs_uc; -#if ICACHE_REFILLS_WORKAROUND_WAR +}; + +#else /* ICACHE_REFILLS_WORKAROUND_WAR */ + +struct rt_sigframe_n32 { + u32 rs_ass[4]; /* argument save space for o32 */ + u32 rs_pad[2]; + struct siginfo rs_info; + struct ucontextn32 rs_uc; u32 rs_code[8] ____cacheline_aligned; /* signal trampoline */ -#endif }; +#endif /* !ICACHE_REFILLS_WORKAROUND_WAR */ + extern void sigset_from_compat (sigset_t *set, compat_sigset_t *compat); -save_static_function(sysn32_rt_sigsuspend); -__attribute_used__ noinline static int -_sysn32_rt_sigsuspend(nabi_no_regargs struct pt_regs regs) +asmlinkage int sysn32_rt_sigsuspend(nabi_no_regargs struct pt_regs regs) { compat_sigset_t __user *unewset; compat_sigset_t uset; @@ -105,7 +111,7 @@ _sysn32_rt_sigsuspend(nabi_no_regargs st spin_lock_irq(¤t->sighand->siglock); current->saved_sigmask = current->blocked; current->blocked = newset; - recalc_sigpending(); + recalc_sigpending(); spin_unlock_irq(¤t->sighand->siglock); current->state = TASK_INTERRUPTIBLE; @@ -114,9 +120,7 @@ _sysn32_rt_sigsuspend(nabi_no_regargs st return -ERESTARTNOHAND; } -save_static_function(sysn32_rt_sigreturn); -__attribute_used__ noinline static void -_sysn32_rt_sigreturn(nabi_no_regargs struct pt_regs regs) +asmlinkage void sysn32_rt_sigreturn(nabi_no_regargs struct pt_regs regs) { struct rt_sigframe_n32 __user *frame; sigset_t set; @@ -126,7 +130,7 @@ _sysn32_rt_sigreturn(nabi_no_regargs str frame = (struct rt_sigframe_n32 __user *) regs.regs[29]; if (!access_ok(VERIFY_READ, frame, sizeof(*frame))) goto badframe; - if (__copy_from_user(&set, &frame->rs_uc.uc_sigmask, sizeof(set))) + if (__copy_conv_sigset_from_user(&set, &frame->rs_uc.uc_sigmask)) goto badframe; sigdelsetmask(&set, ~_BLOCKABLE); @@ -184,7 +188,7 @@ int setup_rt_frame_n32(struct k_sigactio /* Create the ucontext. */ err |= __put_user(0, &frame->rs_uc.uc_flags); err |= __put_user(0, &frame->rs_uc.uc_link); - sp = (int) (long) current->sas_ss_sp; + sp = (int) (long) current->sas_ss_sp; err |= __put_user(sp, &frame->rs_uc.uc_stack.ss_sp); err |= __put_user(sas_ss_flags(regs->regs[29]), @@ -192,7 +196,7 @@ int setup_rt_frame_n32(struct k_sigactio err |= __put_user(current->sas_ss_size, &frame->rs_uc.uc_stack.ss_size); err |= setup_sigcontext(regs, &frame->rs_uc.uc_mcontext); - err |= __copy_to_user(&frame->rs_uc.uc_sigmask, set, sizeof(*set)); + err |= __copy_conv_sigset_to_user(&frame->rs_uc.uc_sigmask, set); if (err) goto give_sigsegv; @@ -214,11 +218,10 @@ int setup_rt_frame_n32(struct k_sigactio regs->regs[31] = (unsigned long) frame->rs_code; regs->cp0_epc = regs->regs[25] = (unsigned long) ka->sa.sa_handler; -#if DEBUG_SIG - printk("SIG deliver (%s:%d): sp=0x%p pc=0x%lx ra=0x%p\n", + DEBUGP("SIG deliver (%s:%d): sp=0x%p pc=0x%lx ra=0x%lx\n", current->comm, current->pid, frame, regs->cp0_epc, regs->regs[31]); -#endif + return 0; give_sigsegv: diff --git a/arch/mips/kernel/smp-mt.c b/arch/mips/kernel/smp-mt.c index 1ee689c..64b62bd 100644 --- a/arch/mips/kernel/smp-mt.c +++ b/arch/mips/kernel/smp-mt.c @@ -35,7 +35,6 @@ #include #include #include #include -#include /* This is f*cking wrong */ #define MIPS_CPU_IPI_RESCHED_IRQ 0 #define MIPS_CPU_IPI_CALL_IRQ 1 @@ -108,12 +107,12 @@ void __init sanitize_tlb_entries(void) static void ipi_resched_dispatch(void) { - do_IRQ(MIPSCPU_INT_BASE + MIPS_CPU_IPI_RESCHED_IRQ); + do_IRQ(MIPS_CPU_IRQ_BASE + MIPS_CPU_IPI_RESCHED_IRQ); } static void ipi_call_dispatch(void) { - do_IRQ(MIPSCPU_INT_BASE + MIPS_CPU_IPI_CALL_IRQ); + do_IRQ(MIPS_CPU_IRQ_BASE + MIPS_CPU_IPI_CALL_IRQ); } static irqreturn_t ipi_resched_interrupt(int irq, void *dev_id) @@ -270,8 +269,8 @@ void __init plat_prepare_cpus(unsigned i set_vi_handler(MIPS_CPU_IPI_CALL_IRQ, ipi_call_dispatch); } - cpu_ipi_resched_irq = MIPSCPU_INT_BASE + MIPS_CPU_IPI_RESCHED_IRQ; - cpu_ipi_call_irq = MIPSCPU_INT_BASE + MIPS_CPU_IPI_CALL_IRQ; + cpu_ipi_resched_irq = MIPS_CPU_IRQ_BASE + MIPS_CPU_IPI_RESCHED_IRQ; + cpu_ipi_call_irq = MIPS_CPU_IRQ_BASE + MIPS_CPU_IPI_CALL_IRQ; setup_irq(cpu_ipi_resched_irq, &irq_resched); setup_irq(cpu_ipi_call_irq, &irq_call); diff --git a/arch/mips/kernel/smtc.c b/arch/mips/kernel/smtc.c index 6a857bf..9251ea8 100644 --- a/arch/mips/kernel/smtc.c +++ b/arch/mips/kernel/smtc.c @@ -26,16 +26,6 @@ #include * This file should be built into the kernel only if CONFIG_MIPS_MT_SMTC is set. */ -/* - * MIPSCPU_INT_BASE is identically defined in both - * asm-mips/mips-boards/maltaint.h and asm-mips/mips-boards/simint.h, - * but as yet there's no properly organized include structure that - * will ensure that the right *int.h file will be included for a - * given platform build. - */ - -#define MIPSCPU_INT_BASE 16 - #define MIPS_CPU_IPI_IRQ 1 #define LOCK_MT_PRA() \ @@ -77,15 +67,15 @@ unsigned int ipi_timer_latch[NR_CPUS]; #define IPIBUF_PER_CPU 4 -struct smtc_ipi_q IPIQ[NR_CPUS]; -struct smtc_ipi_q freeIPIq; +static struct smtc_ipi_q IPIQ[NR_CPUS]; +static struct smtc_ipi_q freeIPIq; /* Forward declarations */ void ipi_decode(struct smtc_ipi *); -void post_direct_ipi(int cpu, struct smtc_ipi *pipi); -void setup_cross_vpe_interrupts(void); +static void post_direct_ipi(int cpu, struct smtc_ipi *pipi); +static void setup_cross_vpe_interrupts(void); void init_smtc_stats(void); /* Global SMTC Status */ @@ -200,7 +190,7 @@ void __init sanitize_tlb_entries(void) * Configure shared TLB - VPC configuration bit must be set by caller */ -void smtc_configure_tlb(void) +static void smtc_configure_tlb(void) { int i,tlbsiz,vpes; unsigned long mvpconf0; @@ -648,7 +638,7 @@ int setup_irq_smtc(unsigned int irq, str * the VPE. */ -void smtc_ipi_qdump(void) +static void smtc_ipi_qdump(void) { int i; @@ -686,28 +676,6 @@ static __inline__ int atomic_postincreme return result; } -/* No longer used in IPI dispatch, but retained for future recycling */ - -static __inline__ int atomic_postclear(unsigned int *pv) -{ - unsigned long result; - - unsigned long temp; - - __asm__ __volatile__( - "1: ll %0, %2 \n" - " or %1, $0, $0 \n" - " sc %1, %2 \n" - " beqz %1, 1b \n" - " sync \n" - : "=&r" (result), "=&r" (temp), "=m" (*pv) - : "m" (*pv) - : "memory"); - - return result; -} - - void smtc_send_ipi(int cpu, int type, unsigned int action) { int tcstatus; @@ -781,7 +749,7 @@ void smtc_send_ipi(int cpu, int type, un /* * Send IPI message to Halted TC, TargTC/TargVPE already having been set */ -void post_direct_ipi(int cpu, struct smtc_ipi *pipi) +static void post_direct_ipi(int cpu, struct smtc_ipi *pipi) { struct pt_regs *kstack; unsigned long tcstatus; @@ -921,7 +889,7 @@ void smtc_timer_broadcast(int vpe) * interrupts. */ -static int cpu_ipi_irq = MIPSCPU_INT_BASE + MIPS_CPU_IPI_IRQ; +static int cpu_ipi_irq = MIPS_CPU_IRQ_BASE + MIPS_CPU_IPI_IRQ; static irqreturn_t ipi_interrupt(int irq, void *dev_idm) { @@ -1000,7 +968,7 @@ static void ipi_irq_dispatch(void) static struct irqaction irq_ipi; -void setup_cross_vpe_interrupts(void) +static void setup_cross_vpe_interrupts(void) { if (!cpu_has_vint) panic("SMTC Kernel requires Vectored Interupt support"); @@ -1191,7 +1159,7 @@ void smtc_get_new_mmu_context(struct mm_ * It would be nice to be able to use a spinlock here, * but this is invoked from within TLB flush routines * that protect themselves with DVPE, so if a lock is - * held by another TC, it'll never be freed. + * held by another TC, it'll never be freed. * * DVPE/DMT must not be done with interrupts enabled, * so even so most callers will already have disabled @@ -1296,7 +1264,7 @@ void smtc_flush_tlb_asid(unsigned long a * Support for single-threading cache flush operations. */ -int halt_state_save[NR_CPUS]; +static int halt_state_save[NR_CPUS]; /* * To really, really be sure that nothing is being done diff --git a/arch/mips/kernel/sysirix.c b/arch/mips/kernel/sysirix.c index 6c2406a..93a1484 100644 --- a/arch/mips/kernel/sysirix.c +++ b/arch/mips/kernel/sysirix.c @@ -669,7 +669,7 @@ asmlinkage int irix_mount(char __user *d struct irix_statfs { short f_type; - long f_bsize, f_frsize, f_blocks, f_bfree, f_files, f_ffree; + long f_bsize, f_frsize, f_blocks, f_bfree, f_files, f_ffree; char f_fname[6], f_fpack[6]; }; @@ -959,7 +959,7 @@ static inline loff_t llseek(struct file fn = default_llseek; if (file->f_op && file->f_op->llseek) - fn = file->f_op->llseek; + fn = file->f_op->llseek; lock_kernel(); retval = fn(file, offset, origin); unlock_kernel(); diff --git a/arch/mips/kernel/time.c b/arch/mips/kernel/time.c index 8aa544f..e5e56bd 100644 --- a/arch/mips/kernel/time.c +++ b/arch/mips/kernel/time.c @@ -307,7 +307,7 @@ static unsigned int __init calibrate_hpt struct clocksource clocksource_mips = { .name = "MIPS", .mask = 0xffffffff, - .is_continuous = 1, + .flags = CLOCK_SOURCE_IS_CONTINUOUS, }; static void __init init_mips_clocksource(void) @@ -455,8 +455,3 @@ EXPORT_SYMBOL(rtc_lock); EXPORT_SYMBOL(to_tm); EXPORT_SYMBOL(rtc_mips_set_time); EXPORT_SYMBOL(rtc_mips_get_time); - -unsigned long long sched_clock(void) -{ - return (unsigned long long)jiffies*(1000000000/HZ); -} diff --git a/arch/mips/kernel/vmlinux.lds.S b/arch/mips/kernel/vmlinux.lds.S index cecff24..c76b793 100644 --- a/arch/mips/kernel/vmlinux.lds.S +++ b/arch/mips/kernel/vmlinux.lds.S @@ -113,10 +113,12 @@ #endif references from .rodata */ .exit.text : { *(.exit.text) } .exit.data : { *(.exit.data) } +#if defined(CONFIG_BLK_DEV_INITRD) . = ALIGN(_PAGE_SIZE); __initramfs_start = .; .init.ramfs : { *(.init.ramfs) } __initramfs_end = .; +#endif . = ALIGN(32); __per_cpu_start = .; .data.percpu : { *(.data.percpu) } diff --git a/arch/mips/kernel/vpe.c b/arch/mips/kernel/vpe.c index 458fccf..9aca871 100644 --- a/arch/mips/kernel/vpe.c +++ b/arch/mips/kernel/vpe.c @@ -29,6 +29,7 @@ */ #include +#include #include #include #include @@ -48,6 +49,7 @@ #include #include #include #include +#include #include #include #include @@ -64,6 +66,7 @@ #define INIT_OFFSET_MASK (1UL << (BITS_P static char module_name[] = "vpe"; static int major; +static const int minor = 1; /* fixed for now */ #ifdef CONFIG_MIPS_APSP_KSPD static struct kspd_notifications kspd_events; @@ -522,7 +525,7 @@ static int (*reloc_handlers[]) (struct m }; static char *rstrs[] = { - [R_MIPS_NONE] = "MIPS_NONE", + [R_MIPS_NONE] = "MIPS_NONE", [R_MIPS_32] = "MIPS_32", [R_MIPS_26] = "MIPS_26", [R_MIPS_HI16] = "MIPS_HI16", @@ -695,7 +698,7 @@ static void dump_tclist(void) } /* We are prepared so configure and start the VPE... */ -int vpe_run(struct vpe * v) +static int vpe_run(struct vpe * v) { struct vpe_notifications *n; unsigned long val, dmt_flag; @@ -713,16 +716,16 @@ int vpe_run(struct vpe * v) dvpe(); if (!list_empty(&v->tc)) { - if ((t = list_entry(v->tc.next, struct tc, tc)) == NULL) { - printk(KERN_WARNING "VPE loader: TC %d is already in use.\n", - t->index); - return -ENOEXEC; - } - } else { - printk(KERN_WARNING "VPE loader: No TC's associated with VPE %d\n", - v->minor); - return -ENOEXEC; - } + if ((t = list_entry(v->tc.next, struct tc, tc)) == NULL) { + printk(KERN_WARNING "VPE loader: TC %d is already in use.\n", + t->index); + return -ENOEXEC; + } + } else { + printk(KERN_WARNING "VPE loader: No TC's associated with VPE %d\n", + v->minor); + return -ENOEXEC; + } /* Put MVPE's into 'configuration state' */ set_c0_mvpcontrol(MVPCONTROL_VPC); @@ -775,14 +778,14 @@ int vpe_run(struct vpe * v) back_to_back_c0_hazard(); - /* Set up the XTC bit in vpeconf0 to point at our tc */ - write_vpe_c0_vpeconf0( (read_vpe_c0_vpeconf0() & ~(VPECONF0_XTC)) - | (t->index << VPECONF0_XTC_SHIFT)); + /* Set up the XTC bit in vpeconf0 to point at our tc */ + write_vpe_c0_vpeconf0( (read_vpe_c0_vpeconf0() & ~(VPECONF0_XTC)) + | (t->index << VPECONF0_XTC_SHIFT)); back_to_back_c0_hazard(); - /* enable this VPE */ - write_vpe_c0_vpeconf0(read_vpe_c0_vpeconf0() | VPECONF0_VPA); + /* enable this VPE */ + write_vpe_c0_vpeconf0(read_vpe_c0_vpeconf0() | VPECONF0_VPA); /* clear out any left overs from a previous program */ write_vpe_c0_status(0); @@ -832,7 +835,7 @@ static int find_vpe_symbols(struct vpe * * contents of the program (p)buffer performing relocatations/etc, free's it * when finished. */ -int vpe_elfload(struct vpe * v) +static int vpe_elfload(struct vpe * v) { Elf_Ehdr *hdr; Elf_Shdr *sechdrs; @@ -1205,7 +1208,7 @@ static ssize_t vpe_write(struct file *fi return ret; } -static struct file_operations vpe_fops = { +static const struct file_operations vpe_fops = { .owner = THIS_MODULE, .open = vpe_open, .release = vpe_release, @@ -1365,12 +1368,15 @@ static void kspd_sp_exit( int sp_id) } #endif +static struct device *vpe_dev; + static int __init vpe_module_init(void) { struct vpe *v = NULL; + struct device *dev; struct tc *t; unsigned long val; - int i; + int i, err; if (!cpu_has_mipsmt) { printk("VPE loader: not a MIPS MT capable processor\n"); @@ -1383,6 +1389,14 @@ static int __init vpe_module_init(void) return major; } + dev = device_create(mt_class, NULL, MKDEV(major, minor), + "tc%d", minor); + if (IS_ERR(dev)) { + err = PTR_ERR(dev); + goto out_chrdev; + } + vpe_dev = dev; + dmt(); dvpe(); @@ -1478,6 +1492,11 @@ #ifdef CONFIG_MIPS_APSP_KSPD kspd_events.kspd_sp_exit = kspd_sp_exit; #endif return 0; + +out_chrdev: + unregister_chrdev(major, module_name); + + return err; } static void __exit vpe_module_exit(void) @@ -1490,6 +1509,7 @@ static void __exit vpe_module_exit(void) } } + device_destroy(mt_class, MKDEV(major, minor)); unregister_chrdev(major, module_name); } diff --git a/arch/mips/lasat/interrupt.c b/arch/mips/lasat/interrupt.c index 2affa5f..9a622b9 100644 --- a/arch/mips/lasat/interrupt.c +++ b/arch/mips/lasat/interrupt.c @@ -45,7 +45,7 @@ void enable_lasat_irq(unsigned int irq_n } static struct irq_chip lasat_irq_type = { - .typename = "Lasat", + .name = "Lasat", .ack = disable_lasat_irq, .mask = disable_lasat_irq, .mask_ack = disable_lasat_irq, diff --git a/arch/mips/lasat/prom.c b/arch/mips/lasat/prom.c index 88c7ab8..d47692f 100644 --- a/arch/mips/lasat/prom.c +++ b/arch/mips/lasat/prom.c @@ -132,9 +132,8 @@ void __init prom_init(void) add_memory_region(0, lasat_board_info.li_memsize, BOOT_MEM_RAM); } -unsigned long __init prom_free_prom_memory(void) +void __init prom_free_prom_memory(void) { - return 0; } const char *get_system_type(void) diff --git a/arch/mips/lasat/sysctl.c b/arch/mips/lasat/sysctl.c index 1287835..699ab18 100644 --- a/arch/mips/lasat/sysctl.c +++ b/arch/mips/lasat/sysctl.c @@ -302,42 +302,129 @@ extern int lasat_boot_to_service; #ifdef CONFIG_SYSCTL static ctl_table lasat_table[] = { - {LASAT_CPU_HZ, "cpu-hz", &lasat_board_info.li_cpu_hz, sizeof(int), - 0444, NULL, &proc_dointvec, &sysctl_intvec}, - {LASAT_BUS_HZ, "bus-hz", &lasat_board_info.li_bus_hz, sizeof(int), - 0444, NULL, &proc_dointvec, &sysctl_intvec}, - {LASAT_MODEL, "bmid", &lasat_board_info.li_bmid, sizeof(int), - 0444, NULL, &proc_dointvec, &sysctl_intvec}, - {LASAT_PRID, "prid", &lasat_board_info.li_prid, sizeof(int), - 0644, NULL, &proc_lasat_eeprom_value, &sysctl_lasat_eeprom_value}, + { + .ctl_name = CTL_UNNUMBERED, + .procname = "cpu-hz", + .data = &lasat_board_info.li_cpu_hz, + .maxlen = sizeof(int), + .mode = 0444, + .proc_handler = &proc_dointvec, + .strategy = &sysctl_intvec + }, + { + .ctl_name = CTL_UNNUMBERED, + .procname = "bus-hz", + .data = &lasat_board_info.li_bus_hz, + .maxlen = sizeof(int), + .mode = 0444, + .proc_handler = &proc_dointvec, + .strategy = &sysctl_intvec + }, + { + .ctl_name = CTL_UNNUMBERED, + .procname = "bmid", + .data = &lasat_board_info.li_bmid, + .maxlen = sizeof(int), + .mode = 0444, + .proc_handler = &proc_dointvec, + .strategy = &sysctl_intvec + }, + { + .ctl_name = CTL_UNNUMBERED, + .procname = "prid", + .data = &lasat_board_info.li_prid, + .maxlen = sizeof(int), + .mode = 0644, + .proc_handler = &proc_lasat_eeprom_value, + .strategy = &sysctl_lasat_eeprom_value + }, #ifdef CONFIG_INET - {LASAT_IPADDR, "ipaddr", &lasat_board_info.li_eeprom_info.ipaddr, sizeof(int), - 0644, NULL, &proc_lasat_ip, &sysctl_lasat_intvec}, - {LASAT_NETMASK, "netmask", &lasat_board_info.li_eeprom_info.netmask, sizeof(int), - 0644, NULL, &proc_lasat_ip, &sysctl_lasat_intvec}, - {LASAT_BCAST, "bcastaddr", &lasat_bcastaddr, - sizeof(lasat_bcastaddr), 0600, NULL, - &proc_dostring, &sysctl_string}, + { + .ctl_name = CTL_UNNUMBERED, + .procname = "ipaddr", + .data = &lasat_board_info.li_eeprom_info.ipaddr, + .maxlen = sizeof(int), + .mode = 0644, + .proc_handler = &proc_lasat_ip, + .strategy = &sysctl_lasat_intvec + }, + { + .ctl_name = LASAT_NETMASK, + .procname = "netmask", + .data = &lasat_board_info.li_eeprom_info.netmask, + .maxlen = sizeof(int), + .mode = 0644, + .proc_handler = &proc_lasat_ip, + .strategy = &sysctl_lasat_intvec + }, + { + .ctl_name = CTL_UNNUMBERED, + .procname = "bcastaddr", + .data = &lasat_bcastaddr, + .maxlen = sizeof(lasat_bcastaddr), + .mode = 0600, + .proc_handler = &proc_dostring, + .strategy = &sysctl_string + }, #endif - {LASAT_PASSWORD, "passwd_hash", &lasat_board_info.li_eeprom_info.passwd_hash, sizeof(lasat_board_info.li_eeprom_info.passwd_hash), - 0600, NULL, &proc_dolasatstring, &sysctl_lasatstring}, - {LASAT_SBOOT, "boot-service", &lasat_boot_to_service, sizeof(int), - 0644, NULL, &proc_dointvec, &sysctl_intvec}, + { + .ctl_name = CTL_UNNUMBERED, + .procname = "passwd_hash", + .data = &lasat_board_info.li_eeprom_info.passwd_hash, + .maxlen = sizeof(lasat_board_info.li_eeprom_info.passwd_hash), + .mode = 0600, + .proc_handler = &proc_dolasatstring, + .strategy = &sysctl_lasatstring + }, + { + .ctl_name = CTL_UNNUMBERED, + .procname = "boot-service", + .data = &lasat_boot_to_service, + .maxlen = sizeof(int), + .mode = 0644, + .proc_handler = &proc_dointvec, + .strategy = &sysctl_intvec + }, #ifdef CONFIG_DS1603 - {LASAT_RTC, "rtc", &rtctmp, sizeof(int), - 0644, NULL, &proc_dolasatrtc, &sysctl_lasat_rtc}, + { + .ctl_name = CTL_UNNUMBERED, + .procname = "rtc", + .data = &rtctmp, + .maxlen = sizeof(int), + .mode = 0644, + .proc_handler = &proc_dolasatrtc, + .strategy = &sysctl_lasat_rtc + }, #endif - {LASAT_NAMESTR, "namestr", &lasat_board_info.li_namestr, sizeof(lasat_board_info.li_namestr), - 0444, NULL, &proc_dostring, &sysctl_string}, - {LASAT_TYPESTR, "typestr", &lasat_board_info.li_typestr, sizeof(lasat_board_info.li_typestr), - 0444, NULL, &proc_dostring, &sysctl_string}, - {0} + { + .ctl_name = CTL_UNNUMBERED, + .procname = "namestr", + .data = &lasat_board_info.li_namestr, + .maxlen = sizeof(lasat_board_info.li_namestr), + .mode = 0444, + .proc_handler = &proc_dostring, + .strategy = &sysctl_string + }, + { + .ctl_name = CTL_UNNUMBERED, + .procname = "typestr", + .data = &lasat_board_info.li_typestr, + .maxlen = sizeof(lasat_board_info.li_typestr), + .mode = 0444, + .proc_handler = &proc_dostring, + .strategy = &sysctl_string + }, + {} }; -#define CTL_LASAT 1 // CTL_ANY ??? static ctl_table lasat_root_table[] = { - { CTL_LASAT, "lasat", NULL, 0, 0555, lasat_table }, - { 0 } + { + .ctl_name = CTL_UNNUMBERED, + .procname = "lasat", + .mode = 0555, + .child = lasat_table + }, + {} }; static int __init lasat_register_sysctl(void) @@ -345,7 +432,7 @@ static int __init lasat_register_sysctl( struct ctl_table_header *lasat_table_header; lasat_table_header = - register_sysctl_table(lasat_root_table, 0); + register_sysctl_table(lasat_root_table); return 0; } diff --git a/arch/mips/lib-32/Makefile b/arch/mips/lib-32/Makefile index dcd4d2e..2036cf5 100644 --- a/arch/mips/lib-32/Makefile +++ b/arch/mips/lib-32/Makefile @@ -2,7 +2,7 @@ # # Makefile for MIPS-specific library files.. # -lib-y += memset.o watch.o +lib-y += watch.o obj-$(CONFIG_CPU_MIPS32) += dump_tlb.o obj-$(CONFIG_CPU_MIPS64) += dump_tlb.o diff --git a/arch/mips/lib-32/memset.S b/arch/mips/lib-32/memset.S deleted file mode 100644 index 1981485..0000000 --- a/arch/mips/lib-32/memset.S +++ /dev/null @@ -1,145 +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. - * - * Copyright (C) 1998, 1999, 2000 by Ralf Baechle - * Copyright (C) 1999, 2000 Silicon Graphics, Inc. - */ -#include -#include -#include - -#define EX(insn,reg,addr,handler) \ -9: insn reg, addr; \ - .section __ex_table,"a"; \ - PTR 9b, handler; \ - .previous - - .macro f_fill64 dst, offset, val, fixup - EX(LONG_S, \val, (\offset + 0 * LONGSIZE)(\dst), \fixup) - EX(LONG_S, \val, (\offset + 1 * LONGSIZE)(\dst), \fixup) - EX(LONG_S, \val, (\offset + 2 * LONGSIZE)(\dst), \fixup) - EX(LONG_S, \val, (\offset + 3 * LONGSIZE)(\dst), \fixup) - EX(LONG_S, \val, (\offset + 4 * LONGSIZE)(\dst), \fixup) - EX(LONG_S, \val, (\offset + 5 * LONGSIZE)(\dst), \fixup) - EX(LONG_S, \val, (\offset + 6 * LONGSIZE)(\dst), \fixup) - EX(LONG_S, \val, (\offset + 7 * LONGSIZE)(\dst), \fixup) - EX(LONG_S, \val, (\offset + 8 * LONGSIZE)(\dst), \fixup) - EX(LONG_S, \val, (\offset + 9 * LONGSIZE)(\dst), \fixup) - EX(LONG_S, \val, (\offset + 10 * LONGSIZE)(\dst), \fixup) - EX(LONG_S, \val, (\offset + 11 * LONGSIZE)(\dst), \fixup) - EX(LONG_S, \val, (\offset + 12 * LONGSIZE)(\dst), \fixup) - EX(LONG_S, \val, (\offset + 13 * LONGSIZE)(\dst), \fixup) - EX(LONG_S, \val, (\offset + 14 * LONGSIZE)(\dst), \fixup) - EX(LONG_S, \val, (\offset + 15 * LONGSIZE)(\dst), \fixup) - .endm - -/* - * memset(void *s, int c, size_t n) - * - * a0: start of area to clear - * a1: char to fill with - * a2: size of area to clear - */ - .set noreorder - .align 5 -LEAF(memset) - beqz a1, 1f - move v0, a0 /* result */ - - andi a1, 0xff /* spread fillword */ - sll t1, a1, 8 - or a1, t1 - sll t1, a1, 16 - or a1, t1 -1: - -FEXPORT(__bzero) - sltiu t0, a2, LONGSIZE /* very small region? */ - bnez t0, small_memset - andi t0, a0, LONGMASK /* aligned? */ - - beqz t0, 1f - PTR_SUBU t0, LONGSIZE /* alignment in bytes */ - -#ifdef __MIPSEB__ - EX(swl, a1, (a0), first_fixup) /* make word aligned */ -#endif -#ifdef __MIPSEL__ - EX(swr, a1, (a0), first_fixup) /* make word aligned */ -#endif - PTR_SUBU a0, t0 /* long align ptr */ - PTR_ADDU a2, t0 /* correct size */ - -1: ori t1, a2, 0x3f /* # of full blocks */ - xori t1, 0x3f - beqz t1, memset_partial /* no block to fill */ - andi t0, a2, 0x3c - - PTR_ADDU t1, a0 /* end address */ - .set reorder -1: PTR_ADDIU a0, 64 - f_fill64 a0, -64, a1, fwd_fixup - bne t1, a0, 1b - .set noreorder - -memset_partial: - PTR_LA t1, 2f /* where to start */ - PTR_SUBU t1, t0 - jr t1 - PTR_ADDU a0, t0 /* dest ptr */ - - .set push - .set noreorder - .set nomacro - f_fill64 a0, -64, a1, partial_fixup /* ... but first do longs ... */ -2: .set pop - andi a2, LONGMASK /* At most one long to go */ - - beqz a2, 1f - PTR_ADDU a0, a2 /* What's left */ -#ifdef __MIPSEB__ - EX(swr, a1, -1(a0), last_fixup) -#endif -#ifdef __MIPSEL__ - EX(swl, a1, -1(a0), last_fixup) -#endif -1: jr ra - move a2, zero - -small_memset: - beqz a2, 2f - PTR_ADDU t1, a0, a2 - -1: PTR_ADDIU a0, 1 /* fill bytewise */ - bne t1, a0, 1b - sb a1, -1(a0) - -2: jr ra /* done */ - move a2, zero - END(memset) - -first_fixup: - jr ra - nop - -fwd_fixup: - PTR_L t0, TI_TASK($28) - LONG_L t0, THREAD_BUADDR(t0) - andi a2, 0x3f - LONG_ADDU a2, t1 - jr ra - LONG_SUBU a2, t0 - -partial_fixup: - PTR_L t0, TI_TASK($28) - LONG_L t0, THREAD_BUADDR(t0) - andi a2, LONGMASK - LONG_ADDU a2, t1 - jr ra - LONG_SUBU a2, t0 - -last_fixup: - jr ra - andi v1, a2, LONGMASK diff --git a/arch/mips/lib-64/Makefile b/arch/mips/lib-64/Makefile index dcd4d2e..2036cf5 100644 --- a/arch/mips/lib-64/Makefile +++ b/arch/mips/lib-64/Makefile @@ -2,7 +2,7 @@ # # Makefile for MIPS-specific library files.. # -lib-y += memset.o watch.o +lib-y += watch.o obj-$(CONFIG_CPU_MIPS32) += dump_tlb.o obj-$(CONFIG_CPU_MIPS64) += dump_tlb.o diff --git a/arch/mips/lib-64/memset.S b/arch/mips/lib-64/memset.S deleted file mode 100644 index e2c42c8..0000000 --- a/arch/mips/lib-64/memset.S +++ /dev/null @@ -1,142 +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. - * - * Copyright (C) 1998, 1999, 2000 by Ralf Baechle - * Copyright (C) 1999, 2000 Silicon Graphics, Inc. - */ -#include -#include -#include - -#define EX(insn,reg,addr,handler) \ -9: insn reg, addr; \ - .section __ex_table,"a"; \ - PTR 9b, handler; \ - .previous - - .macro f_fill64 dst, offset, val, fixup - EX(LONG_S, \val, (\offset + 0 * LONGSIZE)(\dst), \fixup) - EX(LONG_S, \val, (\offset + 1 * LONGSIZE)(\dst), \fixup) - EX(LONG_S, \val, (\offset + 2 * LONGSIZE)(\dst), \fixup) - EX(LONG_S, \val, (\offset + 3 * LONGSIZE)(\dst), \fixup) - EX(LONG_S, \val, (\offset + 4 * LONGSIZE)(\dst), \fixup) - EX(LONG_S, \val, (\offset + 5 * LONGSIZE)(\dst), \fixup) - EX(LONG_S, \val, (\offset + 6 * LONGSIZE)(\dst), \fixup) - EX(LONG_S, \val, (\offset + 7 * LONGSIZE)(\dst), \fixup) - .endm - -/* - * memset(void *s, int c, size_t n) - * - * a0: start of area to clear - * a1: char to fill with - * a2: size of area to clear - */ - .set noreorder - .align 5 -LEAF(memset) - beqz a1, 1f - move v0, a0 /* result */ - - andi a1, 0xff /* spread fillword */ - dsll t1, a1, 8 - or a1, t1 - dsll t1, a1, 16 - or a1, t1 - dsll t1, a1, 32 - or a1, t1 -1: - -FEXPORT(__bzero) - sltiu t0, a2, LONGSIZE /* very small region? */ - bnez t0, small_memset - andi t0, a0, LONGMASK /* aligned? */ - - beqz t0, 1f - PTR_SUBU t0, LONGSIZE /* alignment in bytes */ - -#ifdef __MIPSEB__ - EX(sdl, a1, (a0), first_fixup) /* make dword aligned */ -#endif -#ifdef __MIPSEL__ - EX(sdr, a1, (a0), first_fixup) /* make dword aligned */ -#endif - PTR_SUBU a0, t0 /* long align ptr */ - PTR_ADDU a2, t0 /* correct size */ - -1: ori t1, a2, 0x3f /* # of full blocks */ - xori t1, 0x3f - beqz t1, memset_partial /* no block to fill */ - andi t0, a2, 0x38 - - PTR_ADDU t1, a0 /* end address */ - .set reorder -1: PTR_ADDIU a0, 64 - f_fill64 a0, -64, a1, fwd_fixup - bne t1, a0, 1b - .set noreorder - -memset_partial: - PTR_LA t1, 2f /* where to start */ - .set noat - dsrl AT, t0, 1 - PTR_SUBU t1, AT - .set noat - jr t1 - PTR_ADDU a0, t0 /* dest ptr */ - - .set push - .set noreorder - .set nomacro - f_fill64 a0, -64, a1, partial_fixup /* ... but first do longs ... */ -2: .set pop - andi a2, LONGMASK /* At most one long to go */ - - beqz a2, 1f - PTR_ADDU a0, a2 /* What's left */ -#ifdef __MIPSEB__ - EX(sdr, a1, -1(a0), last_fixup) -#endif -#ifdef __MIPSEL__ - EX(sdl, a1, -1(a0), last_fixup) -#endif -1: jr ra - move a2, zero - -small_memset: - beqz a2, 2f - PTR_ADDU t1, a0, a2 - -1: PTR_ADDIU a0, 1 /* fill bytewise */ - bne t1, a0, 1b - sb a1, -1(a0) - -2: jr ra /* done */ - move a2, zero - END(memset) - -first_fixup: - jr ra - nop - -fwd_fixup: - PTR_L t0, TI_TASK($28) - LONG_L t0, THREAD_BUADDR(t0) - andi a2, 0x3f - LONG_ADDU a2, t1 - jr ra - LONG_SUBU a2, t0 - -partial_fixup: - PTR_L t0, TI_TASK($28) - LONG_L t0, THREAD_BUADDR(t0) - andi a2, LONGMASK - LONG_ADDU a2, t1 - jr ra - LONG_SUBU a2, t0 - -last_fixup: - jr ra - andi v1, a2, LONGMASK diff --git a/arch/mips/lib/Makefile b/arch/mips/lib/Makefile index 989c900..5ad501b 100644 --- a/arch/mips/lib/Makefile +++ b/arch/mips/lib/Makefile @@ -2,7 +2,7 @@ # # Makefile for MIPS-specific library files.. # -lib-y += csum_partial.o memcpy.o promlib.o \ +lib-y += csum_partial.o memcpy.o memset.o promlib.o \ strlen_user.o strncpy_user.o strnlen_user.o uncached.o obj-y += iomap.o diff --git a/arch/mips/lib/memset.S b/arch/mips/lib/memset.S new file mode 100644 index 0000000..3f8b8b3 --- /dev/null +++ b/arch/mips/lib/memset.S @@ -0,0 +1,166 @@ +/* + * 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) 1998, 1999, 2000 by Ralf Baechle + * Copyright (C) 1999, 2000 Silicon Graphics, Inc. + */ +#include +#include +#include + +#if LONGSIZE == 4 +#define LONG_S_L swl +#define LONG_S_R swr +#else +#define LONG_S_L sdl +#define LONG_S_R sdr +#endif + +#define EX(insn,reg,addr,handler) \ +9: insn reg, addr; \ + .section __ex_table,"a"; \ + PTR 9b, handler; \ + .previous + + .macro f_fill64 dst, offset, val, fixup + EX(LONG_S, \val, (\offset + 0 * LONGSIZE)(\dst), \fixup) + EX(LONG_S, \val, (\offset + 1 * LONGSIZE)(\dst), \fixup) + EX(LONG_S, \val, (\offset + 2 * LONGSIZE)(\dst), \fixup) + EX(LONG_S, \val, (\offset + 3 * LONGSIZE)(\dst), \fixup) + EX(LONG_S, \val, (\offset + 4 * LONGSIZE)(\dst), \fixup) + EX(LONG_S, \val, (\offset + 5 * LONGSIZE)(\dst), \fixup) + EX(LONG_S, \val, (\offset + 6 * LONGSIZE)(\dst), \fixup) + EX(LONG_S, \val, (\offset + 7 * LONGSIZE)(\dst), \fixup) +#if LONGSIZE == 4 + EX(LONG_S, \val, (\offset + 8 * LONGSIZE)(\dst), \fixup) + EX(LONG_S, \val, (\offset + 9 * LONGSIZE)(\dst), \fixup) + EX(LONG_S, \val, (\offset + 10 * LONGSIZE)(\dst), \fixup) + EX(LONG_S, \val, (\offset + 11 * LONGSIZE)(\dst), \fixup) + EX(LONG_S, \val, (\offset + 12 * LONGSIZE)(\dst), \fixup) + EX(LONG_S, \val, (\offset + 13 * LONGSIZE)(\dst), \fixup) + EX(LONG_S, \val, (\offset + 14 * LONGSIZE)(\dst), \fixup) + EX(LONG_S, \val, (\offset + 15 * LONGSIZE)(\dst), \fixup) +#endif + .endm + +/* + * memset(void *s, int c, size_t n) + * + * a0: start of area to clear + * a1: char to fill with + * a2: size of area to clear + */ + .set noreorder + .align 5 +LEAF(memset) + beqz a1, 1f + move v0, a0 /* result */ + + andi a1, 0xff /* spread fillword */ + LONG_SLL t1, a1, 8 + or a1, t1 + LONG_SLL t1, a1, 16 +#if LONGSIZE == 8 + or a1, t1 + LONG_SLL t1, a1, 32 +#endif + or a1, t1 +1: + +FEXPORT(__bzero) + sltiu t0, a2, LONGSIZE /* very small region? */ + bnez t0, small_memset + andi t0, a0, LONGMASK /* aligned? */ + + beqz t0, 1f + PTR_SUBU t0, LONGSIZE /* alignment in bytes */ + +#ifdef __MIPSEB__ + EX(LONG_S_L, a1, (a0), first_fixup) /* make word/dword aligned */ +#endif +#ifdef __MIPSEL__ + EX(LONG_S_R, a1, (a0), first_fixup) /* make word/dword aligned */ +#endif + PTR_SUBU a0, t0 /* long align ptr */ + PTR_ADDU a2, t0 /* correct size */ + +1: ori t1, a2, 0x3f /* # of full blocks */ + xori t1, 0x3f + beqz t1, memset_partial /* no block to fill */ + andi t0, a2, 0x40-LONGSIZE + + PTR_ADDU t1, a0 /* end address */ + .set reorder +1: PTR_ADDIU a0, 64 + f_fill64 a0, -64, a1, fwd_fixup + bne t1, a0, 1b + .set noreorder + +memset_partial: + PTR_LA t1, 2f /* where to start */ +#if LONGSIZE == 4 + PTR_SUBU t1, t0 +#else + .set noat + LONG_SRL AT, t0, 1 + PTR_SUBU t1, AT + .set noat +#endif + jr t1 + PTR_ADDU a0, t0 /* dest ptr */ + + .set push + .set noreorder + .set nomacro + f_fill64 a0, -64, a1, partial_fixup /* ... but first do longs ... */ +2: .set pop + andi a2, LONGMASK /* At most one long to go */ + + beqz a2, 1f + PTR_ADDU a0, a2 /* What's left */ +#ifdef __MIPSEB__ + EX(LONG_S_R, a1, -1(a0), last_fixup) +#endif +#ifdef __MIPSEL__ + EX(LONG_S_L, a1, -1(a0), last_fixup) +#endif +1: jr ra + move a2, zero + +small_memset: + beqz a2, 2f + PTR_ADDU t1, a0, a2 + +1: PTR_ADDIU a0, 1 /* fill bytewise */ + bne t1, a0, 1b + sb a1, -1(a0) + +2: jr ra /* done */ + move a2, zero + END(memset) + +first_fixup: + jr ra + nop + +fwd_fixup: + PTR_L t0, TI_TASK($28) + LONG_L t0, THREAD_BUADDR(t0) + andi a2, 0x3f + LONG_ADDU a2, t1 + jr ra + LONG_SUBU a2, t0 + +partial_fixup: + PTR_L t0, TI_TASK($28) + LONG_L t0, THREAD_BUADDR(t0) + andi a2, LONGMASK + LONG_ADDU a2, t1 + jr ra + LONG_SUBU a2, t0 + +last_fixup: + jr ra + andi v1, a2, LONGMASK diff --git a/arch/mips/lib/uncached.c b/arch/mips/lib/uncached.c index 98ce89f..2388f7f 100644 --- a/arch/mips/lib/uncached.c +++ b/arch/mips/lib/uncached.c @@ -44,20 +44,24 @@ unsigned long __init run_uncached(void * if (sp >= (long)CKSEG0 && sp < (long)CKSEG2) usp = CKSEG1ADDR(sp); +#ifdef CONFIG_64BIT else if ((long long)sp >= (long long)PHYS_TO_XKPHYS(0LL, 0) && (long long)sp < (long long)PHYS_TO_XKPHYS(8LL, 0)) usp = PHYS_TO_XKPHYS((long long)K_CALG_UNCACHED, XKPHYS_TO_PHYS((long long)sp)); +#endif else { BUG(); usp = sp; } if (lfunc >= (long)CKSEG0 && lfunc < (long)CKSEG2) ufunc = CKSEG1ADDR(lfunc); +#ifdef CONFIG_64BIT else if ((long long)lfunc >= (long long)PHYS_TO_XKPHYS(0LL, 0) && (long long)lfunc < (long long)PHYS_TO_XKPHYS(8LL, 0)) ufunc = PHYS_TO_XKPHYS((long long)K_CALG_UNCACHED, XKPHYS_TO_PHYS((long long)lfunc)); +#endif else { BUG(); ufunc = lfunc; diff --git a/arch/mips/mips-boards/atlas/atlas_int.c b/arch/mips/mips-boards/atlas/atlas_int.c index 43dba6c..dfa0acb 100644 --- a/arch/mips/mips-boards/atlas/atlas_int.c +++ b/arch/mips/mips-boards/atlas/atlas_int.c @@ -32,6 +32,7 @@ #include #include #include #include +#include #include #include @@ -69,7 +70,7 @@ static void end_atlas_irq(unsigned int i } static struct irq_chip atlas_irq_type = { - .typename = "Atlas", + .name = "Atlas", .ack = disable_atlas_irq, .mask = disable_atlas_irq, .mask_ack = disable_atlas_irq, @@ -220,7 +221,7 @@ msc_irqmap_t __initdata msc_irqmap[] = { {MSC01C_INT_TMR, MSC01_IRQ_EDGE, 0}, {MSC01C_INT_PCI, MSC01_IRQ_LEVEL, 0}, }; -int __initdata msc_nr_irqs = sizeof(msc_irqmap) / sizeof(*msc_irqmap); +int __initdata msc_nr_irqs = ARRAY_SIZE(msc_irqmap); msc_irqmap_t __initdata msc_eicirqmap[] = { {MSC01E_INT_SW0, MSC01_IRQ_LEVEL, 0}, @@ -231,14 +232,14 @@ msc_irqmap_t __initdata msc_eicirqmap[] {MSC01E_INT_PERFCTR, MSC01_IRQ_LEVEL, 0}, {MSC01E_INT_CPUCTR, MSC01_IRQ_LEVEL, 0} }; -int __initdata msc_nr_eicirqs = sizeof(msc_eicirqmap) / sizeof(*msc_eicirqmap); +int __initdata msc_nr_eicirqs = ARRAY_SIZE(msc_eicirqmap); void __init arch_init_irq(void) { init_atlas_irqs(ATLAS_INT_BASE); if (!cpu_has_veic) - mips_cpu_irq_init(MIPSCPU_INT_BASE); + mips_cpu_irq_init(); switch(mips_revision_corid) { case MIPS_REVISION_CORID_CORE_MSC: diff --git a/arch/mips/mips-boards/generic/memory.c b/arch/mips/mips-boards/generic/memory.c index eeed944..ebf0e16 100644 --- a/arch/mips/mips-boards/generic/memory.c +++ b/arch/mips/mips-boards/generic/memory.c @@ -166,9 +166,8 @@ #endif } } -unsigned long __init prom_free_prom_memory(void) +void __init prom_free_prom_memory(void) { - unsigned long freed = 0; unsigned long addr; int i; @@ -176,17 +175,8 @@ unsigned long __init prom_free_prom_memo if (boot_mem_map.map[i].type != BOOT_MEM_ROM_DATA) continue; - addr = PAGE_ALIGN(boot_mem_map.map[i].addr); - while (addr < boot_mem_map.map[i].addr - + boot_mem_map.map[i].size) { - ClearPageReserved(virt_to_page(__va(addr))); - init_page_count(virt_to_page(__va(addr))); - free_page((unsigned long)__va(addr)); - addr += PAGE_SIZE; - freed += PAGE_SIZE; - } + addr = boot_mem_map.map[i].addr; + free_init_pages("prom memory", + addr, addr + boot_mem_map.map[i].size); } - printk("Freeing prom memory: %ldkb freed\n", freed >> 10); - - return freed; } diff --git a/arch/mips/mips-boards/malta/malta_int.c b/arch/mips/mips-boards/malta/malta_int.c index 90ad5bf..3c206bb 100644 --- a/arch/mips/mips-boards/malta/malta_int.c +++ b/arch/mips/mips-boards/malta/malta_int.c @@ -27,6 +27,7 @@ #include #include #include #include +#include #include #include @@ -289,7 +290,7 @@ msc_irqmap_t __initdata msc_irqmap[] = { {MSC01C_INT_TMR, MSC01_IRQ_EDGE, 0}, {MSC01C_INT_PCI, MSC01_IRQ_LEVEL, 0}, }; -int __initdata msc_nr_irqs = sizeof(msc_irqmap)/sizeof(msc_irqmap_t); +int __initdata msc_nr_irqs = ARRAY_SIZE(msc_irqmap); msc_irqmap_t __initdata msc_eicirqmap[] = { {MSC01E_INT_SW0, MSC01_IRQ_LEVEL, 0}, @@ -303,14 +304,14 @@ msc_irqmap_t __initdata msc_eicirqmap[] {MSC01E_INT_PERFCTR, MSC01_IRQ_LEVEL, 0}, {MSC01E_INT_CPUCTR, MSC01_IRQ_LEVEL, 0} }; -int __initdata msc_nr_eicirqs = sizeof(msc_eicirqmap)/sizeof(msc_irqmap_t); +int __initdata msc_nr_eicirqs = ARRAY_SIZE(msc_eicirqmap); void __init arch_init_irq(void) { init_i8259_irqs(); if (!cpu_has_veic) - mips_cpu_irq_init (MIPSCPU_INT_BASE); + mips_cpu_irq_init(); switch(mips_revision_corid) { case MIPS_REVISION_CORID_CORE_MSC: diff --git a/arch/mips/mips-boards/sead/sead_int.c b/arch/mips/mips-boards/sead/sead_int.c index 874ccb0..c4b9de3 100644 --- a/arch/mips/mips-boards/sead/sead_int.c +++ b/arch/mips/mips-boards/sead/sead_int.c @@ -113,5 +113,5 @@ asmlinkage void plat_irq_dispatch(void) void __init arch_init_irq(void) { - mips_cpu_irq_init(MIPSCPU_INT_BASE); + mips_cpu_irq_init(); } diff --git a/arch/mips/mips-boards/sim/sim_int.c b/arch/mips/mips-boards/sim/sim_int.c index 2ce449d..15ac065 100644 --- a/arch/mips/mips-boards/sim/sim_int.c +++ b/arch/mips/mips-boards/sim/sim_int.c @@ -21,9 +21,7 @@ #include #include #include #include - - -extern void mips_cpu_irq_init(int); +#include static inline int clz(unsigned long x) { @@ -86,5 +84,5 @@ asmlinkage void plat_irq_dispatch(void) void __init arch_init_irq(void) { - mips_cpu_irq_init(MIPSCPU_INT_BASE); + mips_cpu_irq_init(); } diff --git a/arch/mips/mips-boards/sim/sim_mem.c b/arch/mips/mips-boards/sim/sim_mem.c index f7ce769..46bc16f 100644 --- a/arch/mips/mips-boards/sim/sim_mem.c +++ b/arch/mips/mips-boards/sim/sim_mem.c @@ -99,10 +99,9 @@ void __init prom_meminit(void) } } -unsigned long __init prom_free_prom_memory(void) +void __init prom_free_prom_memory(void) { int i; - unsigned long freed = 0; unsigned long addr; for (i = 0; i < boot_mem_map.nr_map; i++) { @@ -110,16 +109,7 @@ unsigned long __init prom_free_prom_memo continue; addr = boot_mem_map.map[i].addr; - while (addr < boot_mem_map.map[i].addr - + boot_mem_map.map[i].size) { - ClearPageReserved(virt_to_page(__va(addr))); - init_page_count(virt_to_page(__va(addr))); - free_page((unsigned long)__va(addr)); - addr += PAGE_SIZE; - freed += PAGE_SIZE; - } + free_init_pages("prom memory", + addr, addr + boot_mem_map.map[i].size); } - printk("Freeing prom memory: %ldkb freed\n", freed >> 10); - - return freed; } diff --git a/arch/mips/mm/Makefile b/arch/mips/mm/Makefile index 19e41fd..de57273 100644 --- a/arch/mips/mm/Makefile +++ b/arch/mips/mm/Makefile @@ -2,8 +2,8 @@ # # Makefile for the Linux/MIPS-specific parts of the memory manager. # -obj-y += cache.o extable.o fault.o init.o pgtable.o \ - tlbex.o tlbex-fault.o +obj-y += cache.o dma-default.o extable.o fault.o \ + init.o pgtable.o tlbex.o tlbex-fault.o obj-$(CONFIG_32BIT) += ioremap.o pgtable-32.o obj-$(CONFIG_64BIT) += pgtable-64.o @@ -32,14 +32,4 @@ obj-$(CONFIG_R5000_CPU_SCACHE) += sc-r5 obj-$(CONFIG_RM7000_CPU_SCACHE) += sc-rm7k.o obj-$(CONFIG_MIPS_CPU_SCACHE) += sc-mips.o -# -# Choose one DMA coherency model -# -ifndef CONFIG_OWN_DMA -obj-$(CONFIG_DMA_COHERENT) += dma-coherent.o -obj-$(CONFIG_DMA_NONCOHERENT) += dma-noncoherent.o -endif -obj-$(CONFIG_DMA_IP27) += dma-ip27.o -obj-$(CONFIG_DMA_IP32) += dma-ip32.o - EXTRA_AFLAGS := $(CFLAGS) diff --git a/arch/mips/mm/c-sb1.c b/arch/mips/mm/c-sb1.c index 3a8afd4..9ea460b 100644 --- a/arch/mips/mm/c-sb1.c +++ b/arch/mips/mm/c-sb1.c @@ -259,6 +259,12 @@ static void sb1_flush_cache_data_page(un on_each_cpu(sb1_flush_cache_data_page_ipi, (void *) addr, 1, 1); } #else + +static void local_sb1_flush_cache_data_page(unsigned long addr) +{ + __sb1_writeback_inv_dcache_range(addr, addr + PAGE_SIZE); +} + void sb1_flush_cache_data_page(unsigned long) __attribute__((alias("local_sb1_flush_cache_data_page"))); #endif diff --git a/arch/mips/mm/cache.c b/arch/mips/mm/cache.c index 1f954a2..31819c5 100644 --- a/arch/mips/mm/cache.c +++ b/arch/mips/mm/cache.c @@ -107,8 +107,6 @@ void __update_cache(struct vm_area_struc } } -#define __weak __attribute__((weak)) - static char cache_panic[] __initdata = "Yeee, unsupported cache architecture."; void __init cpu_cache_init(void) diff --git a/arch/mips/mm/dma-coherent.c b/arch/mips/mm/dma-coherent.c deleted file mode 100644 index 5697c6e..0000000 --- a/arch/mips/mm/dma-coherent.c +++ /dev/null @@ -1,254 +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. - * - * Copyright (C) 2000 Ani Joshi - * Copyright (C) 2000, 2001 Ralf Baechle - * swiped from i386, and cloned for MIPS by Geert, polished by Ralf. - */ -#include -#include -#include -#include -#include - -#include -#include - -void *dma_alloc_noncoherent(struct device *dev, size_t size, - dma_addr_t * dma_handle, gfp_t gfp) -{ - void *ret; - /* ignore region specifiers */ - gfp &= ~(__GFP_DMA | __GFP_HIGHMEM); - - if (dev == NULL || (dev->coherent_dma_mask < 0xffffffff)) - gfp |= GFP_DMA; - ret = (void *) __get_free_pages(gfp, get_order(size)); - - if (ret != NULL) { - memset(ret, 0, size); - *dma_handle = virt_to_phys(ret); - } - - return ret; -} - -EXPORT_SYMBOL(dma_alloc_noncoherent); - -void *dma_alloc_coherent(struct device *dev, size_t size, - dma_addr_t * dma_handle, gfp_t gfp) - __attribute__((alias("dma_alloc_noncoherent"))); - -EXPORT_SYMBOL(dma_alloc_coherent); - -void dma_free_noncoherent(struct device *dev, size_t size, void *vaddr, - dma_addr_t dma_handle) -{ - unsigned long addr = (unsigned long) vaddr; - - free_pages(addr, get_order(size)); -} - -EXPORT_SYMBOL(dma_free_noncoherent); - -void dma_free_coherent(struct device *dev, size_t size, void *vaddr, - dma_addr_t dma_handle) __attribute__((alias("dma_free_noncoherent"))); - -EXPORT_SYMBOL(dma_free_coherent); - -dma_addr_t dma_map_single(struct device *dev, void *ptr, size_t size, - enum dma_data_direction direction) -{ - BUG_ON(direction == DMA_NONE); - - return __pa(ptr); -} - -EXPORT_SYMBOL(dma_map_single); - -void dma_unmap_single(struct device *dev, dma_addr_t dma_addr, size_t size, - enum dma_data_direction direction) -{ - BUG_ON(direction == DMA_NONE); -} - -EXPORT_SYMBOL(dma_unmap_single); - -int dma_map_sg(struct device *dev, struct scatterlist *sg, int nents, - enum dma_data_direction direction) -{ - int i; - - BUG_ON(direction == DMA_NONE); - - for (i = 0; i < nents; i++, sg++) { - sg->dma_address = (dma_addr_t)page_to_phys(sg->page) + sg->offset; - } - - return nents; -} - -EXPORT_SYMBOL(dma_map_sg); - -dma_addr_t dma_map_page(struct device *dev, struct page *page, - unsigned long offset, size_t size, enum dma_data_direction direction) -{ - BUG_ON(direction == DMA_NONE); - - return page_to_phys(page) + offset; -} - -EXPORT_SYMBOL(dma_map_page); - -void dma_unmap_page(struct device *dev, dma_addr_t dma_address, size_t size, - enum dma_data_direction direction) -{ - BUG_ON(direction == DMA_NONE); -} - -EXPORT_SYMBOL(dma_unmap_page); - -void dma_unmap_sg(struct device *dev, struct scatterlist *sg, int nhwentries, - enum dma_data_direction direction) -{ - BUG_ON(direction == DMA_NONE); -} - -EXPORT_SYMBOL(dma_unmap_sg); - -void dma_sync_single_for_cpu(struct device *dev, dma_addr_t dma_handle, - size_t size, enum dma_data_direction direction) -{ - BUG_ON(direction == DMA_NONE); -} - -EXPORT_SYMBOL(dma_sync_single_for_cpu); - -void dma_sync_single_for_device(struct device *dev, dma_addr_t dma_handle, - size_t size, enum dma_data_direction direction) -{ - BUG_ON(direction == DMA_NONE); -} - -EXPORT_SYMBOL(dma_sync_single_for_device); - -void dma_sync_single_range_for_cpu(struct device *dev, dma_addr_t dma_handle, - unsigned long offset, size_t size, - enum dma_data_direction direction) -{ - BUG_ON(direction == DMA_NONE); -} - -EXPORT_SYMBOL(dma_sync_single_range_for_cpu); - -void dma_sync_single_range_for_device(struct device *dev, dma_addr_t dma_handle, - unsigned long offset, size_t size, - enum dma_data_direction direction) -{ - BUG_ON(direction == DMA_NONE); -} - -EXPORT_SYMBOL(dma_sync_single_range_for_device); - -void dma_sync_sg_for_cpu(struct device *dev, struct scatterlist *sg, int nelems, - enum dma_data_direction direction) -{ - BUG_ON(direction == DMA_NONE); -} - -EXPORT_SYMBOL(dma_sync_sg_for_cpu); - -void dma_sync_sg_for_device(struct device *dev, struct scatterlist *sg, int nelems, - enum dma_data_direction direction) -{ - BUG_ON(direction == DMA_NONE); -} - -EXPORT_SYMBOL(dma_sync_sg_for_device); - -int dma_mapping_error(dma_addr_t dma_addr) -{ - return 0; -} - -EXPORT_SYMBOL(dma_mapping_error); - -int dma_supported(struct device *dev, u64 mask) -{ - /* - * we fall back to GFP_DMA when the mask isn't all 1s, - * so we can't guarantee allocations that must be - * within a tighter range than GFP_DMA.. - */ - if (mask < 0x00ffffff) - return 0; - - return 1; -} - -EXPORT_SYMBOL(dma_supported); - -int dma_is_consistent(struct device *dev, dma_addr_t dma_addr) -{ - return 1; -} - -EXPORT_SYMBOL(dma_is_consistent); - -void dma_cache_sync(struct device *dev, void *vaddr, size_t size, - enum dma_data_direction direction) -{ - BUG_ON(direction == DMA_NONE); -} - -EXPORT_SYMBOL(dma_cache_sync); - -/* The DAC routines are a PCIism.. */ - -#ifdef CONFIG_PCI - -#include - -dma64_addr_t pci_dac_page_to_dma(struct pci_dev *pdev, - struct page *page, unsigned long offset, int direction) -{ - return (dma64_addr_t)page_to_phys(page) + offset; -} - -EXPORT_SYMBOL(pci_dac_page_to_dma); - -struct page *pci_dac_dma_to_page(struct pci_dev *pdev, - dma64_addr_t dma_addr) -{ - return mem_map + (dma_addr >> PAGE_SHIFT); -} - -EXPORT_SYMBOL(pci_dac_dma_to_page); - -unsigned long pci_dac_dma_to_offset(struct pci_dev *pdev, - dma64_addr_t dma_addr) -{ - return dma_addr & ~PAGE_MASK; -} - -EXPORT_SYMBOL(pci_dac_dma_to_offset); - -void pci_dac_dma_sync_single_for_cpu(struct pci_dev *pdev, - dma64_addr_t dma_addr, size_t len, int direction) -{ - BUG_ON(direction == PCI_DMA_NONE); -} - -EXPORT_SYMBOL(pci_dac_dma_sync_single_for_cpu); - -void pci_dac_dma_sync_single_for_device(struct pci_dev *pdev, - dma64_addr_t dma_addr, size_t len, int direction) -{ - BUG_ON(direction == PCI_DMA_NONE); -} - -EXPORT_SYMBOL(pci_dac_dma_sync_single_for_device); - -#endif /* CONFIG_PCI */ diff --git a/arch/mips/mm/dma-default.c b/arch/mips/mm/dma-default.c new file mode 100644 index 0000000..4a32e93 --- /dev/null +++ b/arch/mips/mm/dma-default.c @@ -0,0 +1,363 @@ +/* + * 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) 2000 Ani Joshi + * Copyright (C) 2000, 2001, 06 Ralf Baechle + * swiped from i386, and cloned for MIPS by Geert, polished by Ralf. + */ + +#include +#include +#include +#include +#include + +#include +#include + +#include + +/* + * Warning on the terminology - Linux calls an uncached area coherent; + * MIPS terminology calls memory areas with hardware maintained coherency + * coherent. + */ + +static inline int cpu_is_noncoherent_r10000(struct device *dev) +{ + return !plat_device_is_coherent(dev) && + (current_cpu_data.cputype == CPU_R10000 && + current_cpu_data.cputype == CPU_R12000); +} + +void *dma_alloc_noncoherent(struct device *dev, size_t size, + dma_addr_t * dma_handle, gfp_t gfp) +{ + void *ret; + + /* ignore region specifiers */ + gfp &= ~(__GFP_DMA | __GFP_HIGHMEM); + + if (dev == NULL || (dev->coherent_dma_mask < 0xffffffff)) + gfp |= GFP_DMA; + ret = (void *) __get_free_pages(gfp, get_order(size)); + + if (ret != NULL) { + memset(ret, 0, size); + *dma_handle = plat_map_dma_mem(dev, ret, size); + } + + return ret; +} + +EXPORT_SYMBOL(dma_alloc_noncoherent); + +void *dma_alloc_coherent(struct device *dev, size_t size, + dma_addr_t * dma_handle, gfp_t gfp) +{ + void *ret; + + /* ignore region specifiers */ + gfp &= ~(__GFP_DMA | __GFP_HIGHMEM); + + if (dev == NULL || (dev->coherent_dma_mask < 0xffffffff)) + gfp |= GFP_DMA; + ret = (void *) __get_free_pages(gfp, get_order(size)); + + if (ret) { + memset(ret, 0, size); + *dma_handle = plat_map_dma_mem(dev, ret, size); + + if (!plat_device_is_coherent(dev)) { + dma_cache_wback_inv((unsigned long) ret, size); + ret = UNCAC_ADDR(ret); + } + } + + return ret; +} + +EXPORT_SYMBOL(dma_alloc_coherent); + +void dma_free_noncoherent(struct device *dev, size_t size, void *vaddr, + dma_addr_t dma_handle) +{ + free_pages((unsigned long) vaddr, get_order(size)); +} + +EXPORT_SYMBOL(dma_free_noncoherent); + +void dma_free_coherent(struct device *dev, size_t size, void *vaddr, + dma_addr_t dma_handle) +{ + unsigned long addr = (unsigned long) vaddr; + + if (!plat_device_is_coherent(dev)) + addr = CAC_ADDR(addr); + + free_pages(addr, get_order(size)); +} + +EXPORT_SYMBOL(dma_free_coherent); + +static inline void __dma_sync(unsigned long addr, size_t size, + enum dma_data_direction direction) +{ + switch (direction) { + case DMA_TO_DEVICE: + dma_cache_wback(addr, size); + break; + + case DMA_FROM_DEVICE: + dma_cache_inv(addr, size); + break; + + case DMA_BIDIRECTIONAL: + dma_cache_wback_inv(addr, size); + break; + + default: + BUG(); + } +} + +dma_addr_t dma_map_single(struct device *dev, void *ptr, size_t size, + enum dma_data_direction direction) +{ + unsigned long addr = (unsigned long) ptr; + + if (!plat_device_is_coherent(dev)) + __dma_sync(addr, size, direction); + + return plat_map_dma_mem(dev, ptr, size); +} + +EXPORT_SYMBOL(dma_map_single); + +void dma_unmap_single(struct device *dev, dma_addr_t dma_addr, size_t size, + enum dma_data_direction direction) +{ + if (cpu_is_noncoherent_r10000(dev)) + __dma_sync(plat_dma_addr_to_phys(dma_addr) + PAGE_OFFSET, size, + direction); + + plat_unmap_dma_mem(dma_addr); +} + +EXPORT_SYMBOL(dma_unmap_single); + +int dma_map_sg(struct device *dev, struct scatterlist *sg, int nents, + enum dma_data_direction direction) +{ + int i; + + BUG_ON(direction == DMA_NONE); + + for (i = 0; i < nents; i++, sg++) { + unsigned long addr; + + addr = (unsigned long) page_address(sg->page); + if (!plat_device_is_coherent(dev) && addr) + __dma_sync(addr + sg->offset, sg->length, direction); + sg->dma_address = plat_map_dma_mem_page(dev, sg->page) + + sg->offset; + } + + return nents; +} + +EXPORT_SYMBOL(dma_map_sg); + +dma_addr_t dma_map_page(struct device *dev, struct page *page, + unsigned long offset, size_t size, enum dma_data_direction direction) +{ + BUG_ON(direction == DMA_NONE); + + if (!plat_device_is_coherent(dev)) { + unsigned long addr; + + addr = (unsigned long) page_address(page) + offset; + dma_cache_wback_inv(addr, size); + } + + return plat_map_dma_mem_page(dev, page) + offset; +} + +EXPORT_SYMBOL(dma_map_page); + +void dma_unmap_page(struct device *dev, dma_addr_t dma_address, size_t size, + enum dma_data_direction direction) +{ + BUG_ON(direction == DMA_NONE); + + if (!plat_device_is_coherent(dev) && direction != DMA_TO_DEVICE) { + unsigned long addr; + + addr = plat_dma_addr_to_phys(dma_address); + dma_cache_wback_inv(addr, size); + } + + plat_unmap_dma_mem(dma_address); +} + +EXPORT_SYMBOL(dma_unmap_page); + +void dma_unmap_sg(struct device *dev, struct scatterlist *sg, int nhwentries, + enum dma_data_direction direction) +{ + unsigned long addr; + int i; + + BUG_ON(direction == DMA_NONE); + + for (i = 0; i < nhwentries; i++, sg++) { + if (!plat_device_is_coherent(dev) && + direction != DMA_TO_DEVICE) { + addr = (unsigned long) page_address(sg->page); + if (addr) + __dma_sync(addr + sg->offset, sg->length, + direction); + } + plat_unmap_dma_mem(sg->dma_address); + } +} + +EXPORT_SYMBOL(dma_unmap_sg); + +void dma_sync_single_for_cpu(struct device *dev, dma_addr_t dma_handle, + size_t size, enum dma_data_direction direction) +{ + BUG_ON(direction == DMA_NONE); + + if (cpu_is_noncoherent_r10000(dev)) { + unsigned long addr; + + addr = PAGE_OFFSET + plat_dma_addr_to_phys(dma_handle); + __dma_sync(addr, size, direction); + } +} + +EXPORT_SYMBOL(dma_sync_single_for_cpu); + +void dma_sync_single_for_device(struct device *dev, dma_addr_t dma_handle, + size_t size, enum dma_data_direction direction) +{ + BUG_ON(direction == DMA_NONE); + + if (cpu_is_noncoherent_r10000(dev)) { + unsigned long addr; + + addr = plat_dma_addr_to_phys(dma_handle); + __dma_sync(addr, size, direction); + } +} + +EXPORT_SYMBOL(dma_sync_single_for_device); + +void dma_sync_single_range_for_cpu(struct device *dev, dma_addr_t dma_handle, + unsigned long offset, size_t size, enum dma_data_direction direction) +{ + BUG_ON(direction == DMA_NONE); + + if (cpu_is_noncoherent_r10000(dev)) { + unsigned long addr; + + addr = PAGE_OFFSET + plat_dma_addr_to_phys(dma_handle); + __dma_sync(addr + offset, size, direction); + } +} + +EXPORT_SYMBOL(dma_sync_single_range_for_cpu); + +void dma_sync_single_range_for_device(struct device *dev, dma_addr_t dma_handle, + unsigned long offset, size_t size, enum dma_data_direction direction) +{ + BUG_ON(direction == DMA_NONE); + + if (cpu_is_noncoherent_r10000(dev)) { + unsigned long addr; + + addr = PAGE_OFFSET + plat_dma_addr_to_phys(dma_handle); + __dma_sync(addr + offset, size, direction); + } +} + +EXPORT_SYMBOL(dma_sync_single_range_for_device); + +void dma_sync_sg_for_cpu(struct device *dev, struct scatterlist *sg, int nelems, + enum dma_data_direction direction) +{ + int i; + + BUG_ON(direction == DMA_NONE); + + /* Make sure that gcc doesn't leave the empty loop body. */ + for (i = 0; i < nelems; i++, sg++) { + if (!plat_device_is_coherent(dev)) + __dma_sync((unsigned long)page_address(sg->page), + sg->length, direction); + plat_unmap_dma_mem(sg->dma_address); + } +} + +EXPORT_SYMBOL(dma_sync_sg_for_cpu); + +void dma_sync_sg_for_device(struct device *dev, struct scatterlist *sg, int nelems, + enum dma_data_direction direction) +{ + int i; + + BUG_ON(direction == DMA_NONE); + + /* Make sure that gcc doesn't leave the empty loop body. */ + for (i = 0; i < nelems; i++, sg++) { + if (!plat_device_is_coherent(dev)) + __dma_sync((unsigned long)page_address(sg->page), + sg->length, direction); + plat_unmap_dma_mem(sg->dma_address); + } +} + +EXPORT_SYMBOL(dma_sync_sg_for_device); + +int dma_mapping_error(dma_addr_t dma_addr) +{ + return 0; +} + +EXPORT_SYMBOL(dma_mapping_error); + +int dma_supported(struct device *dev, u64 mask) +{ + /* + * we fall back to GFP_DMA when the mask isn't all 1s, + * so we can't guarantee allocations that must be + * within a tighter range than GFP_DMA.. + */ + if (mask < 0x00ffffff) + return 0; + + return 1; +} + +EXPORT_SYMBOL(dma_supported); + +int dma_is_consistent(struct device *dev, dma_addr_t dma_addr) +{ + return plat_device_is_coherent(dev); +} + +EXPORT_SYMBOL(dma_is_consistent); + +void dma_cache_sync(struct device *dev, void *vaddr, size_t size, + enum dma_data_direction direction) +{ + BUG_ON(direction == DMA_NONE); + + if (!plat_device_is_coherent(dev)) + dma_cache_wback_inv((unsigned long)vaddr, size); +} + +EXPORT_SYMBOL(dma_cache_sync); diff --git a/arch/mips/mm/dma-ip27.c b/arch/mips/mm/dma-ip27.c deleted file mode 100644 index f088344..0000000 --- a/arch/mips/mm/dma-ip27.c +++ /dev/null @@ -1,257 +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. - * - * Copyright (C) 2000 Ani Joshi - * Copyright (C) 2000, 2001 Ralf Baechle - * swiped from i386, and cloned for MIPS by Geert, polished by Ralf. - */ -#include -#include -#include -#include -#include - -#include -#include - -#define pdev_to_baddr(pdev, addr) \ - (BRIDGE_CONTROLLER(pdev->bus)->baddr + (addr)) -#define dev_to_baddr(dev, addr) \ - pdev_to_baddr(to_pci_dev(dev), (addr)) - -void *dma_alloc_noncoherent(struct device *dev, size_t size, - dma_addr_t * dma_handle, gfp_t gfp) -{ - void *ret; - - /* ignore region specifiers */ - gfp &= ~(__GFP_DMA | __GFP_HIGHMEM); - - if (dev == NULL || (dev->coherent_dma_mask < 0xffffffff)) - gfp |= GFP_DMA; - ret = (void *) __get_free_pages(gfp, get_order(size)); - - if (ret != NULL) { - memset(ret, 0, size); - *dma_handle = dev_to_baddr(dev, virt_to_phys(ret)); - } - - return ret; -} - -EXPORT_SYMBOL(dma_alloc_noncoherent); - -void *dma_alloc_coherent(struct device *dev, size_t size, - dma_addr_t * dma_handle, gfp_t gfp) - __attribute__((alias("dma_alloc_noncoherent"))); - -EXPORT_SYMBOL(dma_alloc_coherent); - -void dma_free_noncoherent(struct device *dev, size_t size, void *vaddr, - dma_addr_t dma_handle) -{ - unsigned long addr = (unsigned long) vaddr; - - free_pages(addr, get_order(size)); -} - -EXPORT_SYMBOL(dma_free_noncoherent); - -void dma_free_coherent(struct device *dev, size_t size, void *vaddr, - dma_addr_t dma_handle) __attribute__((alias("dma_free_noncoherent"))); - -EXPORT_SYMBOL(dma_free_coherent); - -dma_addr_t dma_map_single(struct device *dev, void *ptr, size_t size, - enum dma_data_direction direction) -{ - BUG_ON(direction == DMA_NONE); - - return dev_to_baddr(dev, __pa(ptr)); -} - -EXPORT_SYMBOL(dma_map_single); - -void dma_unmap_single(struct device *dev, dma_addr_t dma_addr, size_t size, - enum dma_data_direction direction) -{ - BUG_ON(direction == DMA_NONE); -} - -EXPORT_SYMBOL(dma_unmap_single); - -int dma_map_sg(struct device *dev, struct scatterlist *sg, int nents, - enum dma_data_direction direction) -{ - int i; - - BUG_ON(direction == DMA_NONE); - - for (i = 0; i < nents; i++, sg++) { - sg->dma_address = (dma_addr_t) dev_to_baddr(dev, - page_to_phys(sg->page) + sg->offset); - } - - return nents; -} - -EXPORT_SYMBOL(dma_map_sg); - -dma_addr_t dma_map_page(struct device *dev, struct page *page, - unsigned long offset, size_t size, enum dma_data_direction direction) -{ - BUG_ON(direction == DMA_NONE); - - return dev_to_baddr(dev, page_to_phys(page) + offset); -} - -EXPORT_SYMBOL(dma_map_page); - -void dma_unmap_page(struct device *dev, dma_addr_t dma_address, size_t size, - enum dma_data_direction direction) -{ - BUG_ON(direction == DMA_NONE); -} - -EXPORT_SYMBOL(dma_unmap_page); - -void dma_unmap_sg(struct device *dev, struct scatterlist *sg, int nhwentries, - enum dma_data_direction direction) -{ - BUG_ON(direction == DMA_NONE); -} - -EXPORT_SYMBOL(dma_unmap_sg); - -void dma_sync_single_for_cpu(struct device *dev, dma_addr_t dma_handle, size_t size, - enum dma_data_direction direction) -{ - BUG_ON(direction == DMA_NONE); -} - -EXPORT_SYMBOL(dma_sync_single_for_cpu); - -void dma_sync_single_for_device(struct device *dev, dma_addr_t dma_handle, size_t size, - enum dma_data_direction direction) -{ - BUG_ON(direction == DMA_NONE); -} - -EXPORT_SYMBOL(dma_sync_single_for_device); - -void dma_sync_single_range_for_cpu(struct device *dev, dma_addr_t dma_handle, - unsigned long offset, size_t size, - enum dma_data_direction direction) -{ - BUG_ON(direction == DMA_NONE); -} - -EXPORT_SYMBOL(dma_sync_single_range_for_cpu); - -void dma_sync_single_range_for_device(struct device *dev, dma_addr_t dma_handle, - unsigned long offset, size_t size, - enum dma_data_direction direction) -{ - BUG_ON(direction == DMA_NONE); -} - -EXPORT_SYMBOL(dma_sync_single_range_for_device); - -void dma_sync_sg_for_cpu(struct device *dev, struct scatterlist *sg, int nelems, - enum dma_data_direction direction) -{ - BUG_ON(direction == DMA_NONE); -} - -EXPORT_SYMBOL(dma_sync_sg_for_cpu); - -void dma_sync_sg_for_device(struct device *dev, struct scatterlist *sg, int nelems, - enum dma_data_direction direction) -{ - BUG_ON(direction == DMA_NONE); -} - -EXPORT_SYMBOL(dma_sync_sg_for_device); - -int dma_mapping_error(dma_addr_t dma_addr) -{ - return 0; -} - -EXPORT_SYMBOL(dma_mapping_error); - -int dma_supported(struct device *dev, u64 mask) -{ - /* - * we fall back to GFP_DMA when the mask isn't all 1s, - * so we can't guarantee allocations that must be - * within a tighter range than GFP_DMA.. - */ - if (mask < 0x00ffffff) - return 0; - - return 1; -} - -EXPORT_SYMBOL(dma_supported); - -int dma_is_consistent(struct device *dev, dma_addr_t dma_addr) -{ - return 1; -} - -EXPORT_SYMBOL(dma_is_consistent); - -void dma_cache_sync(struct device *dev, void *vaddr, size_t size, - enum dma_data_direction direction) -{ - BUG_ON(direction == DMA_NONE); -} - -EXPORT_SYMBOL(dma_cache_sync); - -dma64_addr_t pci_dac_page_to_dma(struct pci_dev *pdev, - struct page *page, unsigned long offset, int direction) -{ - dma64_addr_t addr = page_to_phys(page) + offset; - - return (dma64_addr_t) pdev_to_baddr(pdev, addr); -} - -EXPORT_SYMBOL(pci_dac_page_to_dma); - -struct page *pci_dac_dma_to_page(struct pci_dev *pdev, - dma64_addr_t dma_addr) -{ - struct bridge_controller *bc = BRIDGE_CONTROLLER(pdev->bus); - - return pfn_to_page((dma_addr - bc->baddr) >> PAGE_SHIFT); -} - -EXPORT_SYMBOL(pci_dac_dma_to_page); - -unsigned long pci_dac_dma_to_offset(struct pci_dev *pdev, - dma64_addr_t dma_addr) -{ - return dma_addr & ~PAGE_MASK; -} - -EXPORT_SYMBOL(pci_dac_dma_to_offset); - -void pci_dac_dma_sync_single_for_cpu(struct pci_dev *pdev, - dma64_addr_t dma_addr, size_t len, int direction) -{ - BUG_ON(direction == PCI_DMA_NONE); -} - -EXPORT_SYMBOL(pci_dac_dma_sync_single_for_cpu); - -void pci_dac_dma_sync_single_for_device(struct pci_dev *pdev, - dma64_addr_t dma_addr, size_t len, int direction) -{ - BUG_ON(direction == PCI_DMA_NONE); -} - -EXPORT_SYMBOL(pci_dac_dma_sync_single_for_device); diff --git a/arch/mips/mm/dma-ip32.c b/arch/mips/mm/dma-ip32.c deleted file mode 100644 index b42b6f7..0000000 --- a/arch/mips/mm/dma-ip32.c +++ /dev/null @@ -1,383 +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. - * - * Copyright (C) 2000 Ani Joshi - * Copyright (C) 2000, 2001 Ralf Baechle - * Copyright (C) 2005 Ilya A. Volynets-Evenbakh - * swiped from i386, and cloned for MIPS by Geert, polished by Ralf. - * IP32 changes by Ilya. - */ -#include -#include -#include -#include -#include - -#include -#include -#include - -/* - * Warning on the terminology - Linux calls an uncached area coherent; - * MIPS terminology calls memory areas with hardware maintained coherency - * coherent. - */ - -/* - * Few notes. - * 1. CPU sees memory as two chunks: 0-256M@0x0, and the rest @0x40000000+256M - * 2. PCI sees memory as one big chunk @0x0 (or we could use 0x40000000 for native-endian) - * 3. All other devices see memory as one big chunk at 0x40000000 - * 4. Non-PCI devices will pass NULL as struct device* - * Thus we translate differently, depending on device. - */ - -#define RAM_OFFSET_MASK 0x3fffffff - -void *dma_alloc_noncoherent(struct device *dev, size_t size, - dma_addr_t * dma_handle, gfp_t gfp) -{ - void *ret; - /* ignore region specifiers */ - gfp &= ~(__GFP_DMA | __GFP_HIGHMEM); - - if (dev == NULL || (dev->coherent_dma_mask < 0xffffffff)) - gfp |= GFP_DMA; - ret = (void *) __get_free_pages(gfp, get_order(size)); - - if (ret != NULL) { - unsigned long addr = virt_to_phys(ret)&RAM_OFFSET_MASK; - memset(ret, 0, size); - if(dev==NULL) - addr+= CRIME_HI_MEM_BASE; - *dma_handle = addr; - } - - return ret; -} - -EXPORT_SYMBOL(dma_alloc_noncoherent); - -void *dma_alloc_coherent(struct device *dev, size_t size, - dma_addr_t * dma_handle, gfp_t gfp) -{ - void *ret; - - ret = dma_alloc_noncoherent(dev, size, dma_handle, gfp); - if (ret) { - dma_cache_wback_inv((unsigned long) ret, size); - ret = UNCAC_ADDR(ret); - } - - return ret; -} - -EXPORT_SYMBOL(dma_alloc_coherent); - -void dma_free_noncoherent(struct device *dev, size_t size, void *vaddr, - dma_addr_t dma_handle) -{ - free_pages((unsigned long) vaddr, get_order(size)); -} - -EXPORT_SYMBOL(dma_free_noncoherent); - -void dma_free_coherent(struct device *dev, size_t size, void *vaddr, - dma_addr_t dma_handle) -{ - unsigned long addr = (unsigned long) vaddr; - - addr = CAC_ADDR(addr); - free_pages(addr, get_order(size)); -} - -EXPORT_SYMBOL(dma_free_coherent); - -static inline void __dma_sync(unsigned long addr, size_t size, - enum dma_data_direction direction) -{ - switch (direction) { - case DMA_TO_DEVICE: - dma_cache_wback(addr, size); - break; - - case DMA_FROM_DEVICE: - dma_cache_inv(addr, size); - break; - - case DMA_BIDIRECTIONAL: - dma_cache_wback_inv(addr, size); - break; - - default: - BUG(); - } -} - -dma_addr_t dma_map_single(struct device *dev, void *ptr, size_t size, - enum dma_data_direction direction) -{ - unsigned long addr = (unsigned long) ptr; - - switch (direction) { - case DMA_TO_DEVICE: - dma_cache_wback(addr, size); - break; - - case DMA_FROM_DEVICE: - dma_cache_inv(addr, size); - break; - - case DMA_BIDIRECTIONAL: - dma_cache_wback_inv(addr, size); - break; - - default: - BUG(); - } - - addr = virt_to_phys(ptr)&RAM_OFFSET_MASK; - if(dev == NULL) - addr+=CRIME_HI_MEM_BASE; - return (dma_addr_t)addr; -} - -EXPORT_SYMBOL(dma_map_single); - -void dma_unmap_single(struct device *dev, dma_addr_t dma_addr, size_t size, - enum dma_data_direction direction) -{ - switch (direction) { - case DMA_TO_DEVICE: - break; - - case DMA_FROM_DEVICE: - break; - - case DMA_BIDIRECTIONAL: - break; - - default: - BUG(); - } -} - -EXPORT_SYMBOL(dma_unmap_single); - -int dma_map_sg(struct device *dev, struct scatterlist *sg, int nents, - enum dma_data_direction direction) -{ - int i; - - BUG_ON(direction == DMA_NONE); - - for (i = 0; i < nents; i++, sg++) { - unsigned long addr; - - addr = (unsigned long) page_address(sg->page)+sg->offset; - if (addr) - __dma_sync(addr, sg->length, direction); - addr = __pa(addr)&RAM_OFFSET_MASK; - if(dev == NULL) - addr += CRIME_HI_MEM_BASE; - sg->dma_address = (dma_addr_t)addr; - } - - return nents; -} - -EXPORT_SYMBOL(dma_map_sg); - -dma_addr_t dma_map_page(struct device *dev, struct page *page, - unsigned long offset, size_t size, enum dma_data_direction direction) -{ - unsigned long addr; - - BUG_ON(direction == DMA_NONE); - - addr = (unsigned long) page_address(page) + offset; - dma_cache_wback_inv(addr, size); - addr = __pa(addr)&RAM_OFFSET_MASK; - if(dev == NULL) - addr += CRIME_HI_MEM_BASE; - - return (dma_addr_t)addr; -} - -EXPORT_SYMBOL(dma_map_page); - -void dma_unmap_page(struct device *dev, dma_addr_t dma_address, size_t size, - enum dma_data_direction direction) -{ - BUG_ON(direction == DMA_NONE); - - if (direction != DMA_TO_DEVICE) { - unsigned long addr; - - dma_address&=RAM_OFFSET_MASK; - addr = dma_address + PAGE_OFFSET; - if(dma_address>=256*1024*1024) - addr+=CRIME_HI_MEM_BASE; - dma_cache_wback_inv(addr, size); - } -} - -EXPORT_SYMBOL(dma_unmap_page); - -void dma_unmap_sg(struct device *dev, struct scatterlist *sg, int nhwentries, - enum dma_data_direction direction) -{ - unsigned long addr; - int i; - - BUG_ON(direction == DMA_NONE); - - if (direction == DMA_TO_DEVICE) - return; - - for (i = 0; i < nhwentries; i++, sg++) { - addr = (unsigned long) page_address(sg->page); - if (!addr) - continue; - dma_cache_wback_inv(addr + sg->offset, sg->length); - } -} - -EXPORT_SYMBOL(dma_unmap_sg); - -void dma_sync_single_for_cpu(struct device *dev, dma_addr_t dma_handle, - size_t size, enum dma_data_direction direction) -{ - unsigned long addr; - - BUG_ON(direction == DMA_NONE); - - dma_handle&=RAM_OFFSET_MASK; - addr = dma_handle + PAGE_OFFSET; - if(dma_handle>=256*1024*1024) - addr+=CRIME_HI_MEM_BASE; - __dma_sync(addr, size, direction); -} - -EXPORT_SYMBOL(dma_sync_single_for_cpu); - -void dma_sync_single_for_device(struct device *dev, dma_addr_t dma_handle, - size_t size, enum dma_data_direction direction) -{ - unsigned long addr; - - BUG_ON(direction == DMA_NONE); - - dma_handle&=RAM_OFFSET_MASK; - addr = dma_handle + PAGE_OFFSET; - if(dma_handle>=256*1024*1024) - addr+=CRIME_HI_MEM_BASE; - __dma_sync(addr, size, direction); -} - -EXPORT_SYMBOL(dma_sync_single_for_device); - -void dma_sync_single_range_for_cpu(struct device *dev, dma_addr_t dma_handle, - unsigned long offset, size_t size, enum dma_data_direction direction) -{ - unsigned long addr; - - BUG_ON(direction == DMA_NONE); - - dma_handle&=RAM_OFFSET_MASK; - addr = dma_handle + offset + PAGE_OFFSET; - if(dma_handle>=256*1024*1024) - addr+=CRIME_HI_MEM_BASE; - __dma_sync(addr, size, direction); -} - -EXPORT_SYMBOL(dma_sync_single_range_for_cpu); - -void dma_sync_single_range_for_device(struct device *dev, dma_addr_t dma_handle, - unsigned long offset, size_t size, enum dma_data_direction direction) -{ - unsigned long addr; - - BUG_ON(direction == DMA_NONE); - - dma_handle&=RAM_OFFSET_MASK; - addr = dma_handle + offset + PAGE_OFFSET; - if(dma_handle>=256*1024*1024) - addr+=CRIME_HI_MEM_BASE; - __dma_sync(addr, size, direction); -} - -EXPORT_SYMBOL(dma_sync_single_range_for_device); - -void dma_sync_sg_for_cpu(struct device *dev, struct scatterlist *sg, int nelems, - enum dma_data_direction direction) -{ - int i; - - BUG_ON(direction == DMA_NONE); - - /* Make sure that gcc doesn't leave the empty loop body. */ - for (i = 0; i < nelems; i++, sg++) - __dma_sync((unsigned long)page_address(sg->page), - sg->length, direction); -} - -EXPORT_SYMBOL(dma_sync_sg_for_cpu); - -void dma_sync_sg_for_device(struct device *dev, struct scatterlist *sg, int nelems, - enum dma_data_direction direction) -{ - int i; - - BUG_ON(direction == DMA_NONE); - - /* Make sure that gcc doesn't leave the empty loop body. */ - for (i = 0; i < nelems; i++, sg++) - __dma_sync((unsigned long)page_address(sg->page), - sg->length, direction); -} - -EXPORT_SYMBOL(dma_sync_sg_for_device); - -int dma_mapping_error(dma_addr_t dma_addr) -{ - return 0; -} - -EXPORT_SYMBOL(dma_mapping_error); - -int dma_supported(struct device *dev, u64 mask) -{ - /* - * we fall back to GFP_DMA when the mask isn't all 1s, - * so we can't guarantee allocations that must be - * within a tighter range than GFP_DMA.. - */ - if (mask < 0x00ffffff) - return 0; - - return 1; -} - -EXPORT_SYMBOL(dma_supported); - -int dma_is_consistent(struct device *dev, dma_addr_t dma_addr) -{ - return 1; -} - -EXPORT_SYMBOL(dma_is_consistent); - -void dma_cache_sync(struct device *dev, void *vaddr, size_t size, - enum dma_data_direction direction) -{ - if (direction == DMA_NONE) - return; - - dma_cache_wback_inv((unsigned long)vaddr, size); -} - -EXPORT_SYMBOL(dma_cache_sync); - diff --git a/arch/mips/mm/dma-noncoherent.c b/arch/mips/mm/dma-noncoherent.c deleted file mode 100644 index 8cecef0..0000000 --- a/arch/mips/mm/dma-noncoherent.c +++ /dev/null @@ -1,370 +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. - * - * Copyright (C) 2000 Ani Joshi - * Copyright (C) 2000, 2001 Ralf Baechle - * swiped from i386, and cloned for MIPS by Geert, polished by Ralf. - */ -#include -#include -#include -#include -#include - -#include -#include - -/* - * Warning on the terminology - Linux calls an uncached area coherent; - * MIPS terminology calls memory areas with hardware maintained coherency - * coherent. - */ - -void *dma_alloc_noncoherent(struct device *dev, size_t size, - dma_addr_t * dma_handle, gfp_t gfp) -{ - void *ret; - /* ignore region specifiers */ - gfp &= ~(__GFP_DMA | __GFP_HIGHMEM); - - if (dev == NULL || (dev->coherent_dma_mask < 0xffffffff)) - gfp |= GFP_DMA; - ret = (void *) __get_free_pages(gfp, get_order(size)); - - if (ret != NULL) { - memset(ret, 0, size); - *dma_handle = virt_to_phys(ret); - } - - return ret; -} - -EXPORT_SYMBOL(dma_alloc_noncoherent); - -void *dma_alloc_coherent(struct device *dev, size_t size, - dma_addr_t * dma_handle, gfp_t gfp) -{ - void *ret; - - ret = dma_alloc_noncoherent(dev, size, dma_handle, gfp); - if (ret) { - dma_cache_wback_inv((unsigned long) ret, size); - ret = UNCAC_ADDR(ret); - } - - return ret; -} - -EXPORT_SYMBOL(dma_alloc_coherent); - -void dma_free_noncoherent(struct device *dev, size_t size, void *vaddr, - dma_addr_t dma_handle) -{ - free_pages((unsigned long) vaddr, get_order(size)); -} - -EXPORT_SYMBOL(dma_free_noncoherent); - -void dma_free_coherent(struct device *dev, size_t size, void *vaddr, - dma_addr_t dma_handle) -{ - unsigned long addr = (unsigned long) vaddr; - - addr = CAC_ADDR(addr); - free_pages(addr, get_order(size)); -} - -EXPORT_SYMBOL(dma_free_coherent); - -static inline void __dma_sync(unsigned long addr, size_t size, - enum dma_data_direction direction) -{ - switch (direction) { - case DMA_TO_DEVICE: - dma_cache_wback(addr, size); - break; - - case DMA_FROM_DEVICE: - dma_cache_inv(addr, size); - break; - - case DMA_BIDIRECTIONAL: - dma_cache_wback_inv(addr, size); - break; - - default: - BUG(); - } -} - -dma_addr_t dma_map_single(struct device *dev, void *ptr, size_t size, - enum dma_data_direction direction) -{ - unsigned long addr = (unsigned long) ptr; - - __dma_sync(addr, size, direction); - - return virt_to_phys(ptr); -} - -EXPORT_SYMBOL(dma_map_single); - -void dma_unmap_single(struct device *dev, dma_addr_t dma_addr, size_t size, - enum dma_data_direction direction) -{ - unsigned long addr; - addr = dma_addr + PAGE_OFFSET; - - //__dma_sync(addr, size, direction); -} - -EXPORT_SYMBOL(dma_unmap_single); - -int dma_map_sg(struct device *dev, struct scatterlist *sg, int nents, - enum dma_data_direction direction) -{ - int i; - - BUG_ON(direction == DMA_NONE); - - for (i = 0; i < nents; i++, sg++) { - unsigned long addr; - - addr = (unsigned long) page_address(sg->page); - if (addr) { - __dma_sync(addr + sg->offset, sg->length, direction); - sg->dma_address = (dma_addr_t)page_to_phys(sg->page) - + sg->offset; - } - } - - return nents; -} - -EXPORT_SYMBOL(dma_map_sg); - -dma_addr_t dma_map_page(struct device *dev, struct page *page, - unsigned long offset, size_t size, enum dma_data_direction direction) -{ - unsigned long addr; - - BUG_ON(direction == DMA_NONE); - - addr = (unsigned long) page_address(page) + offset; - dma_cache_wback_inv(addr, size); - - return page_to_phys(page) + offset; -} - -EXPORT_SYMBOL(dma_map_page); - -void dma_unmap_page(struct device *dev, dma_addr_t dma_address, size_t size, - enum dma_data_direction direction) -{ - BUG_ON(direction == DMA_NONE); - - if (direction != DMA_TO_DEVICE) { - unsigned long addr; - - addr = dma_address + PAGE_OFFSET; - dma_cache_wback_inv(addr, size); - } -} - -EXPORT_SYMBOL(dma_unmap_page); - -void dma_unmap_sg(struct device *dev, struct scatterlist *sg, int nhwentries, - enum dma_data_direction direction) -{ - unsigned long addr; - int i; - - BUG_ON(direction == DMA_NONE); - - if (direction == DMA_TO_DEVICE) - return; - - for (i = 0; i < nhwentries; i++, sg++) { - addr = (unsigned long) page_address(sg->page); - if (addr) - __dma_sync(addr + sg->offset, sg->length, direction); - } -} - -EXPORT_SYMBOL(dma_unmap_sg); - -void dma_sync_single_for_cpu(struct device *dev, dma_addr_t dma_handle, - size_t size, enum dma_data_direction direction) -{ - unsigned long addr; - - BUG_ON(direction == DMA_NONE); - - addr = dma_handle + PAGE_OFFSET; - __dma_sync(addr, size, direction); -} - -EXPORT_SYMBOL(dma_sync_single_for_cpu); - -void dma_sync_single_for_device(struct device *dev, dma_addr_t dma_handle, - size_t size, enum dma_data_direction direction) -{ - unsigned long addr; - - BUG_ON(direction == DMA_NONE); - - addr = dma_handle + PAGE_OFFSET; - __dma_sync(addr, size, direction); -} - -EXPORT_SYMBOL(dma_sync_single_for_device); - -void dma_sync_single_range_for_cpu(struct device *dev, dma_addr_t dma_handle, - unsigned long offset, size_t size, enum dma_data_direction direction) -{ - unsigned long addr; - - BUG_ON(direction == DMA_NONE); - - addr = dma_handle + offset + PAGE_OFFSET; - __dma_sync(addr, size, direction); -} - -EXPORT_SYMBOL(dma_sync_single_range_for_cpu); - -void dma_sync_single_range_for_device(struct device *dev, dma_addr_t dma_handle, - unsigned long offset, size_t size, enum dma_data_direction direction) -{ - unsigned long addr; - - BUG_ON(direction == DMA_NONE); - - addr = dma_handle + offset + PAGE_OFFSET; - __dma_sync(addr, size, direction); -} - -EXPORT_SYMBOL(dma_sync_single_range_for_device); - -void dma_sync_sg_for_cpu(struct device *dev, struct scatterlist *sg, int nelems, - enum dma_data_direction direction) -{ - int i; - - BUG_ON(direction == DMA_NONE); - - /* Make sure that gcc doesn't leave the empty loop body. */ - for (i = 0; i < nelems; i++, sg++) - __dma_sync((unsigned long)page_address(sg->page), - sg->length, direction); -} - -EXPORT_SYMBOL(dma_sync_sg_for_cpu); - -void dma_sync_sg_for_device(struct device *dev, struct scatterlist *sg, int nelems, - enum dma_data_direction direction) -{ - int i; - - BUG_ON(direction == DMA_NONE); - - /* Make sure that gcc doesn't leave the empty loop body. */ - for (i = 0; i < nelems; i++, sg++) - __dma_sync((unsigned long)page_address(sg->page), - sg->length, direction); -} - -EXPORT_SYMBOL(dma_sync_sg_for_device); - -int dma_mapping_error(dma_addr_t dma_addr) -{ - return 0; -} - -EXPORT_SYMBOL(dma_mapping_error); - -int dma_supported(struct device *dev, u64 mask) -{ - /* - * we fall back to GFP_DMA when the mask isn't all 1s, - * so we can't guarantee allocations that must be - * within a tighter range than GFP_DMA.. - */ - if (mask < 0x00ffffff) - return 0; - - return 1; -} - -EXPORT_SYMBOL(dma_supported); - -int dma_is_consistent(struct device *dev, dma_addr_t dma_addr) -{ - return 1; -} - -EXPORT_SYMBOL(dma_is_consistent); - -void dma_cache_sync(struct device *dev, void *vaddr, size_t size, - enum dma_data_direction direction) -{ - if (direction == DMA_NONE) - return; - - dma_cache_wback_inv((unsigned long)vaddr, size); -} - -EXPORT_SYMBOL(dma_cache_sync); - -/* The DAC routines are a PCIism.. */ - -#ifdef CONFIG_PCI - -#include - -dma64_addr_t pci_dac_page_to_dma(struct pci_dev *pdev, - struct page *page, unsigned long offset, int direction) -{ - return (dma64_addr_t)page_to_phys(page) + offset; -} - -EXPORT_SYMBOL(pci_dac_page_to_dma); - -struct page *pci_dac_dma_to_page(struct pci_dev *pdev, - dma64_addr_t dma_addr) -{ - return mem_map + (dma_addr >> PAGE_SHIFT); -} - -EXPORT_SYMBOL(pci_dac_dma_to_page); - -unsigned long pci_dac_dma_to_offset(struct pci_dev *pdev, - dma64_addr_t dma_addr) -{ - return dma_addr & ~PAGE_MASK; -} - -EXPORT_SYMBOL(pci_dac_dma_to_offset); - -void pci_dac_dma_sync_single_for_cpu(struct pci_dev *pdev, - dma64_addr_t dma_addr, size_t len, int direction) -{ - BUG_ON(direction == PCI_DMA_NONE); - - dma_cache_wback_inv(dma_addr + PAGE_OFFSET, len); -} - -EXPORT_SYMBOL(pci_dac_dma_sync_single_for_cpu); - -void pci_dac_dma_sync_single_for_device(struct pci_dev *pdev, - dma64_addr_t dma_addr, size_t len, int direction) -{ - BUG_ON(direction == PCI_DMA_NONE); - - dma_cache_wback_inv(dma_addr + PAGE_OFFSET, len); -} - -EXPORT_SYMBOL(pci_dac_dma_sync_single_for_device); - -#endif /* CONFIG_PCI */ diff --git a/arch/mips/mm/init.c b/arch/mips/mm/init.c index 49065c1..125a4a8 100644 --- a/arch/mips/mm/init.c +++ b/arch/mips/mm/init.c @@ -341,7 +341,6 @@ static int __init page_is_ram(unsigned l void __init paging_init(void) { unsigned long zones_size[MAX_NR_ZONES] = { 0, }; - unsigned long max_dma, low; #ifndef CONFIG_FLATMEM unsigned long zholes_size[MAX_NR_ZONES] = { 0, }; unsigned long i, j, pfn; @@ -354,19 +353,19 @@ #ifdef CONFIG_HIGHMEM #endif kmap_coherent_init(); - max_dma = virt_to_phys((char *)MAX_DMA_ADDRESS) >> PAGE_SHIFT; - low = max_low_pfn; - #ifdef CONFIG_ISA - if (low < max_dma) - zones_size[ZONE_DMA] = low; - else { - zones_size[ZONE_DMA] = max_dma; - zones_size[ZONE_NORMAL] = low - max_dma; - } -#else - zones_size[ZONE_DMA] = low; + if (max_low_pfn >= MAX_DMA_PFN) + if (min_low_pfn >= MAX_DMA_PFN) { + zones_size[ZONE_DMA] = 0; + zones_size[ZONE_NORMAL] = max_low_pfn - min_low_pfn; + } else { + zones_size[ZONE_DMA] = MAX_DMA_PFN - min_low_pfn; + zones_size[ZONE_NORMAL] = max_low_pfn - MAX_DMA_PFN; + } + else #endif + zones_size[ZONE_DMA] = max_low_pfn - min_low_pfn; + #ifdef CONFIG_HIGHMEM zones_size[ZONE_HIGHMEM] = highend_pfn - highstart_pfn; @@ -467,7 +466,7 @@ #endif } #endif /* !CONFIG_NEED_MULTIPLE_NODES */ -static void free_init_pages(char *what, unsigned long begin, unsigned long end) +void free_init_pages(const char *what, unsigned long begin, unsigned long end) { unsigned long pfn; @@ -493,18 +492,25 @@ void free_initrd_mem(unsigned long start } #endif -extern unsigned long prom_free_prom_memory(void); - void free_initmem(void) { - unsigned long freed; - - freed = prom_free_prom_memory(); - if (freed) - printk(KERN_INFO "Freeing firmware memory: %ldkb freed\n", - freed >> 10); - + prom_free_prom_memory(); free_init_pages("unused kernel memory", __pa_symbol(&__init_begin), __pa_symbol(&__init_end)); } + +unsigned long pgd_current[NR_CPUS]; +/* + * On 64-bit we've got three-level pagetables with a slightly + * different layout ... + */ +#define __page_aligned(order) __attribute__((__aligned__(PAGE_SIZE< +#include +#include +#include +#include + +#include "jaguar_atx_fpga.h" + +#if defined(CONFIG_MV643XX_ETH) || defined(CONFIG_MV643XX_ETH_MODULE) + +static struct resource mv643xx_eth_shared_resources[] = { + [0] = { + .name = "ethernet shared base", + .start = 0xf1000000 + MV643XX_ETH_SHARED_REGS, + .end = 0xf1000000 + MV643XX_ETH_SHARED_REGS + + MV643XX_ETH_SHARED_REGS_SIZE - 1, + .flags = IORESOURCE_MEM, + }, +}; + +static struct platform_device mv643xx_eth_shared_device = { + .name = MV643XX_ETH_SHARED_NAME, + .id = 0, + .num_resources = ARRAY_SIZE(mv643xx_eth_shared_resources), + .resource = mv643xx_eth_shared_resources, +}; + +#define MV_SRAM_BASE 0xfe000000UL +#define MV_SRAM_SIZE (256 * 1024) + +#define MV_SRAM_RXRING_SIZE (MV_SRAM_SIZE / 4) +#define MV_SRAM_TXRING_SIZE (MV_SRAM_SIZE / 4) + +#define MV_SRAM_BASE_ETH0 MV_SRAM_BASE +#define MV_SRAM_BASE_ETH1 (MV_SRAM_BASE + (MV_SRAM_SIZE / 2)) + +#define MV64x60_IRQ_ETH_0 48 +#define MV64x60_IRQ_ETH_1 49 +#define MV64x60_IRQ_ETH_2 50 + +#ifdef CONFIG_MV643XX_ETH_0 + +static struct resource mv64x60_eth0_resources[] = { + [0] = { + .name = "eth0 irq", + .start = MV64x60_IRQ_ETH_0, + .end = MV64x60_IRQ_ETH_0, + .flags = IORESOURCE_IRQ, + }, +}; + +static char eth0_mac_addr[ETH_ALEN]; + +static struct mv643xx_eth_platform_data eth0_pd = { + .mac_addr = eth0_mac_addr, + + .tx_sram_addr = MV_SRAM_BASE_ETH0, + .tx_sram_size = MV_SRAM_TXRING_SIZE, + .tx_queue_size = MV_SRAM_TXRING_SIZE / 16, + + .rx_sram_addr = MV_SRAM_BASE_ETH0 + MV_SRAM_TXRING_SIZE, + .rx_sram_size = MV_SRAM_RXRING_SIZE, + .rx_queue_size = MV_SRAM_RXRING_SIZE / 16, +}; + +static struct platform_device eth0_device = { + .name = MV643XX_ETH_NAME, + .id = 0, + .num_resources = ARRAY_SIZE(mv64x60_eth0_resources), + .resource = mv64x60_eth0_resources, + .dev = { + .platform_data = ð0_pd, + }, +}; +#endif /* CONFIG_MV643XX_ETH_0 */ + +#ifdef CONFIG_MV643XX_ETH_1 + +static struct resource mv64x60_eth1_resources[] = { + [0] = { + .name = "eth1 irq", + .start = MV64x60_IRQ_ETH_1, + .end = MV64x60_IRQ_ETH_1, + .flags = IORESOURCE_IRQ, + }, +}; + +static char eth1_mac_addr[ETH_ALEN]; + +static struct mv643xx_eth_platform_data eth1_pd = { + .mac_addr = eth1_mac_addr, + + .tx_sram_addr = MV_SRAM_BASE_ETH1, + .tx_sram_size = MV_SRAM_TXRING_SIZE, + .tx_queue_size = MV_SRAM_TXRING_SIZE / 16, + + .rx_sram_addr = MV_SRAM_BASE_ETH1 + MV_SRAM_TXRING_SIZE, + .rx_sram_size = MV_SRAM_RXRING_SIZE, + .rx_queue_size = MV_SRAM_RXRING_SIZE / 16, +}; + +static struct platform_device eth1_device = { + .name = MV643XX_ETH_NAME, + .id = 1, + .num_resources = ARRAY_SIZE(mv64x60_eth1_resources), + .resource = mv64x60_eth1_resources, + .dev = { + .platform_data = ð1_pd, + }, +}; +#endif /* CONFIG_MV643XX_ETH_1 */ + +#ifdef CONFIG_MV643XX_ETH_2 + +static struct resource mv64x60_eth2_resources[] = { + [0] = { + .name = "eth2 irq", + .start = MV64x60_IRQ_ETH_2, + .end = MV64x60_IRQ_ETH_2, + .flags = IORESOURCE_IRQ, + }, +}; + +static char eth2_mac_addr[ETH_ALEN]; + +static struct mv643xx_eth_platform_data eth2_pd = { + .mac_addr = eth2_mac_addr, +}; + +static struct platform_device eth2_device = { + .name = MV643XX_ETH_NAME, + .id = 2, + .num_resources = ARRAY_SIZE(mv64x60_eth2_resources), + .resource = mv64x60_eth2_resources, + .dev = { + .platform_data = ð2_pd, + }, +}; +#endif /* CONFIG_MV643XX_ETH_2 */ + +static struct platform_device *mv643xx_eth_pd_devs[] __initdata = { + &mv643xx_eth_shared_device, +#ifdef CONFIG_MV643XX_ETH_0 + ð0_device, +#endif +#ifdef CONFIG_MV643XX_ETH_1 + ð1_device, +#endif +#ifdef CONFIG_MV643XX_ETH_2 + ð2_device, +#endif +}; + +static u8 __init exchange_bit(u8 val, u8 cs) +{ + /* place the data */ + JAGUAR_FPGA_WRITE((val << 2) | cs, EEPROM_MODE); + udelay(1); + + /* turn the clock on */ + JAGUAR_FPGA_WRITE((val << 2) | cs | 0x2, EEPROM_MODE); + udelay(1); + + /* turn the clock off and read-strobe */ + JAGUAR_FPGA_WRITE((val << 2) | cs | 0x10, EEPROM_MODE); + + /* return the data */ + return (JAGUAR_FPGA_READ(EEPROM_MODE) >> 3) & 0x1; +} + +static void __init get_mac(char dest[6]) +{ + u8 read_opcode[12] = {1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; + int i,j; + + for (i = 0; i < 12; i++) + exchange_bit(read_opcode[i], 1); + + for (j = 0; j < 6; j++) { + dest[j] = 0; + for (i = 0; i < 8; i++) { + dest[j] <<= 1; + dest[j] |= exchange_bit(0, 1); + } + } + + /* turn off CS */ + exchange_bit(0,0); +} + +/* + * Copy and increment ethernet MAC address by a small value. + * + * This is useful for systems where the only one MAC address is stored in + * non-volatile memory for multiple ports. + */ +static inline void eth_mac_add(unsigned char *dst, unsigned char *src, + unsigned int add) +{ + int i; + + BUG_ON(add >= 256); + + for (i = ETH_ALEN; i >= 0; i--) { + dst[i] = src[i] + add; + add = dst[i] < src[i]; /* compute carry */ + } + + WARN_ON(add); +} + +static int __init mv643xx_eth_add_pds(void) +{ + unsigned char mac[ETH_ALEN]; + int ret; + + get_mac(mac); +#ifdef CONFIG_MV643XX_ETH_0 + eth_mac_add(eth1_mac_addr, mac, 0); +#endif +#ifdef CONFIG_MV643XX_ETH_1 + eth_mac_add(eth1_mac_addr, mac, 1); +#endif +#ifdef CONFIG_MV643XX_ETH_2 + eth_mac_add(eth2_mac_addr, mac, 2); +#endif + ret = platform_add_devices(mv643xx_eth_pd_devs, + ARRAY_SIZE(mv643xx_eth_pd_devs)); + + return ret; +} + +device_initcall(mv643xx_eth_add_pds); + +#endif /* defined(CONFIG_MV643XX_ETH) || defined(CONFIG_MV643XX_ETH_MODULE) */ diff --git a/arch/mips/momentum/jaguar_atx/prom.c b/arch/mips/momentum/jaguar_atx/prom.c index 3d27129..5dd154e 100644 --- a/arch/mips/momentum/jaguar_atx/prom.c +++ b/arch/mips/momentum/jaguar_atx/prom.c @@ -39,56 +39,6 @@ const char *get_system_type(void) return "Momentum Jaguar-ATX"; } -#ifdef CONFIG_MV643XX_ETH -extern unsigned char prom_mac_addr_base[6]; - -static void burn_clocks(void) -{ - int i; - - /* this loop should burn at least 1us -- this should be plenty */ - for (i = 0; i < 0x10000; i++) - ; -} - -static u8 exchange_bit(u8 val, u8 cs) -{ - /* place the data */ - JAGUAR_FPGA_WRITE((val << 2) | cs, EEPROM_MODE); - burn_clocks(); - - /* turn the clock on */ - JAGUAR_FPGA_WRITE((val << 2) | cs | 0x2, EEPROM_MODE); - burn_clocks(); - - /* turn the clock off and read-strobe */ - JAGUAR_FPGA_WRITE((val << 2) | cs | 0x10, EEPROM_MODE); - - /* return the data */ - return ((JAGUAR_FPGA_READ(EEPROM_MODE) >> 3) & 0x1); -} - -void get_mac(char dest[6]) -{ - u8 read_opcode[12] = {1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; - int i,j; - - for (i = 0; i < 12; i++) - exchange_bit(read_opcode[i], 1); - - for (j = 0; j < 6; j++) { - dest[j] = 0; - for (i = 0; i < 8; i++) { - dest[j] <<= 1; - dest[j] |= exchange_bit(0, 1); - } - } - - /* turn off CS */ - exchange_bit(0,0); -} -#endif - #ifdef CONFIG_64BIT unsigned long signext(unsigned long addr) @@ -228,16 +178,10 @@ #else /* CONFIG_64BIT */ #endif /* CONFIG_64BIT */ mips_machgroup = MACH_GROUP_MOMENCO; mips_machtype = MACH_MOMENCO_JAGUAR_ATX; - -#ifdef CONFIG_MV643XX_ETH - /* get the base MAC address for on-board ethernet ports */ - get_mac(prom_mac_addr_base); -#endif } -unsigned long __init prom_free_prom_memory(void) +void __init prom_free_prom_memory(void) { - return 0; } void __init prom_fixup_mem_map(unsigned long start, unsigned long end) diff --git a/arch/mips/momentum/ocelot_3/irq.c b/arch/mips/momentum/ocelot_3/irq.c index cea0e5d..3862d1d 100644 --- a/arch/mips/momentum/ocelot_3/irq.c +++ b/arch/mips/momentum/ocelot_3/irq.c @@ -65,7 +65,7 @@ void __init arch_init_irq(void) */ clear_c0_status(ST0_IM | ST0_BEV); - rm7k_cpu_irq_init(8); + rm7k_cpu_irq_init(); /* set up the cascading interrupts */ setup_irq(8, &cascade_mv64340); /* unmask intControl IM8, IRQ 9 */ diff --git a/arch/mips/momentum/ocelot_3/platform.c b/arch/mips/momentum/ocelot_3/platform.c index eefe584..57cfe5c 100644 --- a/arch/mips/momentum/ocelot_3/platform.c +++ b/arch/mips/momentum/ocelot_3/platform.c @@ -129,7 +129,7 @@ static struct mv643xx_eth_platform_data static struct platform_device eth2_device = { .name = MV643XX_ETH_NAME, - .id = 1, + .id = 2, .num_resources = ARRAY_SIZE(mv64x60_eth2_resources), .resource = mv64x60_eth2_resources, .dev = { diff --git a/arch/mips/momentum/ocelot_3/prom.c b/arch/mips/momentum/ocelot_3/prom.c index 6ce9b7f..8e02df6 100644 --- a/arch/mips/momentum/ocelot_3/prom.c +++ b/arch/mips/momentum/ocelot_3/prom.c @@ -180,9 +180,8 @@ #ifndef CONFIG_64BIT #endif } -unsigned long __init prom_free_prom_memory(void) +void __init prom_free_prom_memory(void) { - return 0; } void __init prom_fixup_mem_map(unsigned long start, unsigned long end) diff --git a/arch/mips/momentum/ocelot_c/cpci-irq.c b/arch/mips/momentum/ocelot_c/cpci-irq.c index bb11fef..186a140 100644 --- a/arch/mips/momentum/ocelot_c/cpci-irq.c +++ b/arch/mips/momentum/ocelot_c/cpci-irq.c @@ -84,7 +84,7 @@ void ll_cpci_irq(void) } struct irq_chip cpci_irq_type = { - .typename = "CPCI/FPGA", + .name = "CPCI/FPGA", .ack = mask_cpci_irq, .mask = mask_cpci_irq, .mask_ack = mask_cpci_irq, diff --git a/arch/mips/momentum/ocelot_c/dbg_io.c b/arch/mips/momentum/ocelot_c/dbg_io.c index 2128684..32d6fb4 100644 --- a/arch/mips/momentum/ocelot_c/dbg_io.c +++ b/arch/mips/momentum/ocelot_c/dbg_io.c @@ -1,6 +1,4 @@ -#ifdef CONFIG_KGDB - #include /* For the serial port location and base baud */ /* --- CONFIG --- */ @@ -121,5 +119,3 @@ int putDebugChar(uint8 byte) UART16550_WRITE(OFS_SEND_BUFFER, byte); return 1; } - -#endif diff --git a/arch/mips/momentum/ocelot_c/irq.c b/arch/mips/momentum/ocelot_c/irq.c index ea65223..40472f7 100644 --- a/arch/mips/momentum/ocelot_c/irq.c +++ b/arch/mips/momentum/ocelot_c/irq.c @@ -94,7 +94,7 @@ void __init arch_init_irq(void) */ clear_c0_status(ST0_IM); - mips_cpu_irq_init(0); + mips_cpu_irq_init(); /* set up the cascading interrupts */ setup_irq(3, &cascade_fpga); diff --git a/arch/mips/momentum/ocelot_c/prom.c b/arch/mips/momentum/ocelot_c/prom.c index d0b77e1..b689cee 100644 --- a/arch/mips/momentum/ocelot_c/prom.c +++ b/arch/mips/momentum/ocelot_c/prom.c @@ -178,7 +178,6 @@ #ifndef CONFIG_64BIT #endif } -unsigned long __init prom_free_prom_memory(void) +void __init prom_free_prom_memory(void) { - return 0; } diff --git a/arch/mips/momentum/ocelot_c/uart-irq.c b/arch/mips/momentum/ocelot_c/uart-irq.c index a7a80c0..de1a31e 100644 --- a/arch/mips/momentum/ocelot_c/uart-irq.c +++ b/arch/mips/momentum/ocelot_c/uart-irq.c @@ -77,7 +77,7 @@ void ll_uart_irq(void) } struct irq_chip uart_irq_type = { - .typename = "UART/FPGA", + .name = "UART/FPGA", .ack = mask_uart_irq, .mask = mask_uart_irq, .mask_ack = mask_uart_irq, diff --git a/arch/mips/momentum/ocelot_g/dbg_io.c b/arch/mips/momentum/ocelot_g/dbg_io.c index 2128684..32d6fb4 100644 --- a/arch/mips/momentum/ocelot_g/dbg_io.c +++ b/arch/mips/momentum/ocelot_g/dbg_io.c @@ -1,6 +1,4 @@ -#ifdef CONFIG_KGDB - #include /* For the serial port location and base baud */ /* --- CONFIG --- */ @@ -121,5 +119,3 @@ int putDebugChar(uint8 byte) UART16550_WRITE(OFS_SEND_BUFFER, byte); return 1; } - -#endif diff --git a/arch/mips/momentum/ocelot_g/irq.c b/arch/mips/momentum/ocelot_g/irq.c index da46524..273541f 100644 --- a/arch/mips/momentum/ocelot_g/irq.c +++ b/arch/mips/momentum/ocelot_g/irq.c @@ -94,8 +94,8 @@ void __init arch_init_irq(void) clear_c0_status(ST0_IM); local_irq_disable(); - mips_cpu_irq_init(0); - rm7k_cpu_irq_init(8); + mips_cpu_irq_init(); + rm7k_cpu_irq_init(); gt64240_irq_init(); } diff --git a/arch/mips/momentum/ocelot_g/prom.c b/arch/mips/momentum/ocelot_g/prom.c index 2f75c6b..836d083 100644 --- a/arch/mips/momentum/ocelot_g/prom.c +++ b/arch/mips/momentum/ocelot_g/prom.c @@ -79,7 +79,6 @@ #endif } } -unsigned long __init prom_free_prom_memory(void) +void __init prom_free_prom_memory(void) { - return 0; } diff --git a/arch/mips/oprofile/Kconfig b/arch/mips/oprofile/Kconfig index 55feaf7..ca395ef 100644 --- a/arch/mips/oprofile/Kconfig +++ b/arch/mips/oprofile/Kconfig @@ -11,7 +11,7 @@ config PROFILING config OPROFILE tristate "OProfile system profiling (EXPERIMENTAL)" - depends on PROFILING && EXPERIMENTAL + depends on PROFILING && !!MIPS_MT_SMTC && EXPERIMENTAL help OProfile is a profiling system capable of profiling the whole system, include the kernel, kernel modules, libraries, diff --git a/arch/mips/pci/Makefile b/arch/mips/pci/Makefile index 82b20c2..bf85995 100644 --- a/arch/mips/pci/Makefile +++ b/arch/mips/pci/Makefile @@ -2,7 +2,7 @@ # # Makefile for the PCI specific kernel interface routines under Linux. # -obj-y += pci.o +obj-y += pci.o pci-dac.o # # PCI bus host bridge specific code diff --git a/arch/mips/pci/fixup-vr4133.c b/arch/mips/pci/fixup-vr4133.c index 597b897..a8d9d22 100644 --- a/arch/mips/pci/fixup-vr4133.c +++ b/arch/mips/pci/fixup-vr4133.c @@ -17,8 +17,10 @@ */ #include #include +#include #include +#include #include extern int vr4133_rockhopper; @@ -142,7 +144,7 @@ int rockhopper_get_irq(struct pci_dev *d if (bus == NULL) return -1; - for (i = 0; i < sizeof (int_map) / sizeof (int_map[0]); i++) { + for (i = 0; i < ARRAY_SIZE(int_map); i++) { if (int_map[i].bus == bus->number && int_map[i].slot == slot) { int line; for (line = 0; line < 4; line++) @@ -160,17 +162,7 @@ int rockhopper_get_irq(struct pci_dev *d #ifdef CONFIG_ROCKHOPPER void i8259_init(void) { - outb(0x11, 0x20); /* Master ICW1 */ - outb(I8259_IRQ_BASE, 0x21); /* Master ICW2 */ - outb(0x04, 0x21); /* Master ICW3 */ - outb(0x01, 0x21); /* Master ICW4 */ - outb(0xff, 0x21); /* Master IMW */ - - outb(0x11, 0xa0); /* Slave ICW1 */ - outb(I8259_IRQ_BASE + 8, 0xa1); /* Slave ICW2 */ - outb(0x02, 0xa1); /* Slave ICW3 */ - outb(0x01, 0xa1); /* Slave ICW4 */ - outb(0xff, 0xa1); /* Slave IMW */ + init_i8259_irqs(); outb(0x00, 0x4d0); outb(0x02, 0x4d1); /* USB IRQ9 is level */ diff --git a/arch/mips/pci/pci-dac.c b/arch/mips/pci/pci-dac.c new file mode 100644 index 0000000..0f0ea1b --- /dev/null +++ b/arch/mips/pci/pci-dac.c @@ -0,0 +1,79 @@ +/* + * 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) 2000 Ani Joshi + * Copyright (C) 2000, 2001, 06 Ralf Baechle + * swiped from i386, and cloned for MIPS by Geert, polished by Ralf. + */ + +#include +#include +#include +#include +#include + +#include +#include + +#include + +#include + +dma64_addr_t pci_dac_page_to_dma(struct pci_dev *pdev, + struct page *page, unsigned long offset, int direction) +{ + struct device *dev = &pdev->dev; + + BUG_ON(direction == DMA_NONE); + + if (!plat_device_is_coherent(dev)) { + unsigned long addr; + + addr = (unsigned long) page_address(page) + offset; + dma_cache_wback_inv(addr, PAGE_SIZE); + } + + return plat_map_dma_mem_page(dev, page) + offset; +} + +EXPORT_SYMBOL(pci_dac_page_to_dma); + +struct page *pci_dac_dma_to_page(struct pci_dev *pdev, + dma64_addr_t dma_addr) +{ + return pfn_to_page(plat_dma_addr_to_phys(dma_addr) >> PAGE_SHIFT); +} + +EXPORT_SYMBOL(pci_dac_dma_to_page); + +unsigned long pci_dac_dma_to_offset(struct pci_dev *pdev, + dma64_addr_t dma_addr) +{ + return dma_addr & ~PAGE_MASK; +} + +EXPORT_SYMBOL(pci_dac_dma_to_offset); + +void pci_dac_dma_sync_single_for_cpu(struct pci_dev *pdev, + dma64_addr_t dma_addr, size_t len, int direction) +{ + BUG_ON(direction == PCI_DMA_NONE); + + if (!plat_device_is_coherent(&pdev->dev)) + dma_cache_wback_inv(dma_addr + PAGE_OFFSET, len); +} + +EXPORT_SYMBOL(pci_dac_dma_sync_single_for_cpu); + +void pci_dac_dma_sync_single_for_device(struct pci_dev *pdev, + dma64_addr_t dma_addr, size_t len, int direction) +{ + BUG_ON(direction == PCI_DMA_NONE); + + if (!plat_device_is_coherent(&pdev->dev)) + dma_cache_wback_inv(dma_addr + PAGE_OFFSET, len); +} + +EXPORT_SYMBOL(pci_dac_dma_sync_single_for_device); diff --git a/arch/mips/philips/pnx8550/common/int.c b/arch/mips/philips/pnx8550/common/int.c index 2c36c10..d48665e 100644 --- a/arch/mips/philips/pnx8550/common/int.c +++ b/arch/mips/philips/pnx8550/common/int.c @@ -159,7 +159,7 @@ int pnx8550_set_gic_priority(int irq, in } static struct irq_chip level_irq_type = { - .typename = "PNX Level IRQ", + .name = "PNX Level IRQ", .ack = mask_irq, .mask = mask_irq, .mask_ack = mask_irq, diff --git a/arch/mips/philips/pnx8550/common/proc.c b/arch/mips/philips/pnx8550/common/proc.c index 72a0167..3f09755 100644 --- a/arch/mips/philips/pnx8550/common/proc.c +++ b/arch/mips/philips/pnx8550/common/proc.c @@ -79,10 +79,7 @@ static int pnx8550_proc_init( void ) // Create /proc/pnx8550 pnx8550_dir = create_proc_entry("pnx8550", S_IFDIR|S_IRUGO, NULL); - if (pnx8550_dir){ - pnx8550_dir->nlink = 1; - } - else { + if (!pnx8550_dir) { printk(KERN_ERR "Can't create pnx8550 proc dir\n"); return -1; } @@ -90,7 +87,6 @@ static int pnx8550_proc_init( void ) // Create /proc/pnx8550/timers pnx8550_timers = create_proc_entry("timers", S_IFREG|S_IRUGO, pnx8550_dir ); if (pnx8550_timers){ - pnx8550_timers->nlink = 1; pnx8550_timers->read_proc = pnx8550_timers_read; } else { @@ -100,7 +96,6 @@ static int pnx8550_proc_init( void ) // Create /proc/pnx8550/registers pnx8550_registers = create_proc_entry("registers", S_IFREG|S_IRUGO, pnx8550_dir ); if (pnx8550_registers){ - pnx8550_registers->nlink = 1; pnx8550_registers->read_proc = pnx8550_registers_read; } else { diff --git a/arch/mips/philips/pnx8550/common/prom.c b/arch/mips/philips/pnx8550/common/prom.c index eb6ec11..8aeed6c 100644 --- a/arch/mips/philips/pnx8550/common/prom.c +++ b/arch/mips/philips/pnx8550/common/prom.c @@ -106,9 +106,8 @@ int get_ethernet_addr(char *ethernet_add return 0; } -unsigned long __init prom_free_prom_memory(void) +void __init prom_free_prom_memory(void) { - return 0; } extern int pnx8550_console_port; diff --git a/arch/mips/pmc-sierra/yosemite/dbg_io.c b/arch/mips/pmc-sierra/yosemite/dbg_io.c index 0f659c9..6362c70 100644 --- a/arch/mips/pmc-sierra/yosemite/dbg_io.c +++ b/arch/mips/pmc-sierra/yosemite/dbg_io.c @@ -93,7 +93,7 @@ #define SERIAL_WRITE(ofs, val) ((*((vol * Functions to READ and WRITE to serial port 1 */ #define SERIAL_READ_1(ofs) (*((volatile unsigned char*) \ - (TITAN_SERIAL_BASE_1 + ofs) + (TITAN_SERIAL_BASE_1 + ofs))) #define SERIAL_WRITE_1(ofs, val) ((*((volatile unsigned char*) \ (TITAN_SERIAL_BASE_1 + ofs))) = val) diff --git a/arch/mips/pmc-sierra/yosemite/irq.c b/arch/mips/pmc-sierra/yosemite/irq.c index adb0485..428d1f4 100644 --- a/arch/mips/pmc-sierra/yosemite/irq.c +++ b/arch/mips/pmc-sierra/yosemite/irq.c @@ -148,9 +148,9 @@ void __init arch_init_irq(void) { clear_c0_status(ST0_IM); - mips_cpu_irq_init(0); - rm7k_cpu_irq_init(8); - rm9k_cpu_irq_init(12); + mips_cpu_irq_init(); + rm7k_cpu_irq_init(); + rm9k_cpu_irq_init(); #ifdef CONFIG_KGDB /* At this point, initialize the second serial port */ diff --git a/arch/mips/pmc-sierra/yosemite/prom.c b/arch/mips/pmc-sierra/yosemite/prom.c index 9fe4973..1e1685e 100644 --- a/arch/mips/pmc-sierra/yosemite/prom.c +++ b/arch/mips/pmc-sierra/yosemite/prom.c @@ -132,9 +132,8 @@ #endif prom_grab_secondary(); } -unsigned long __init prom_free_prom_memory(void) +void __init prom_free_prom_memory(void) { - return 0; } void __init prom_fixup_mem_map(unsigned long start, unsigned long end) diff --git a/arch/mips/pmc-sierra/yosemite/setup.c b/arch/mips/pmc-sierra/yosemite/setup.c index 1b9b0d3..6a6e15e 100644 --- a/arch/mips/pmc-sierra/yosemite/setup.c +++ b/arch/mips/pmc-sierra/yosemite/setup.c @@ -171,6 +171,7 @@ static void __init py_map_ocd(void) static void __init py_uart_setup(void) { +#ifdef CONFIG_SERIAL_8250 struct uart_port up; /* @@ -188,6 +189,7 @@ static void __init py_uart_setup(void) if (early_serial_setup(&up)) printk(KERN_ERR "Early serial init of port 0 failed\n"); +#endif /* CONFIG_SERIAL_8250 */ } static void __init py_rtc_setup(void) diff --git a/arch/mips/qemu/q-mem.c b/arch/mips/qemu/q-mem.c index d174fac..dae39b5 100644 --- a/arch/mips/qemu/q-mem.c +++ b/arch/mips/qemu/q-mem.c @@ -1,6 +1,5 @@ #include -unsigned long __init prom_free_prom_memory(void) +void __init prom_free_prom_memory(void) { - return 0UL; } diff --git a/arch/mips/sgi-ip22/ip22-eisa.c b/arch/mips/sgi-ip22/ip22-eisa.c index a1a9af6..6b6e97b 100644 --- a/arch/mips/sgi-ip22/ip22-eisa.c +++ b/arch/mips/sgi-ip22/ip22-eisa.c @@ -139,7 +139,7 @@ static void end_eisa1_irq(unsigned int i } static struct irq_chip ip22_eisa1_irq_type = { - .typename = "IP22 EISA", + .name = "IP22 EISA", .startup = startup_eisa1_irq, .ack = mask_and_ack_eisa1_irq, .mask = disable_eisa1_irq, @@ -194,7 +194,7 @@ static void end_eisa2_irq(unsigned int i } static struct irq_chip ip22_eisa2_irq_type = { - .typename = "IP22 EISA", + .name = "IP22 EISA", .startup = startup_eisa2_irq, .ack = mask_and_ack_eisa2_irq, .mask = disable_eisa2_irq, diff --git a/arch/mips/sgi-ip22/ip22-int.c b/arch/mips/sgi-ip22/ip22-int.c index c44f8be..b454924 100644 --- a/arch/mips/sgi-ip22/ip22-int.c +++ b/arch/mips/sgi-ip22/ip22-int.c @@ -19,6 +19,7 @@ #include #include #include +#include #include #include @@ -52,7 +53,7 @@ static void disable_local0_irq(unsigned } static struct irq_chip ip22_local0_irq_type = { - .typename = "IP22 local 0", + .name = "IP22 local 0", .ack = disable_local0_irq, .mask = disable_local0_irq, .mask_ack = disable_local0_irq, @@ -73,7 +74,7 @@ void disable_local1_irq(unsigned int irq } static struct irq_chip ip22_local1_irq_type = { - .typename = "IP22 local 1", + .name = "IP22 local 1", .ack = disable_local1_irq, .mask = disable_local1_irq, .mask_ack = disable_local1_irq, @@ -94,7 +95,7 @@ void disable_local2_irq(unsigned int irq } static struct irq_chip ip22_local2_irq_type = { - .typename = "IP22 local 2", + .name = "IP22 local 2", .ack = disable_local2_irq, .mask = disable_local2_irq, .mask_ack = disable_local2_irq, @@ -115,7 +116,7 @@ void disable_local3_irq(unsigned int irq } static struct irq_chip ip22_local3_irq_type = { - .typename = "IP22 local 3", + .name = "IP22 local 3", .ack = disable_local3_irq, .mask = disable_local3_irq, .mask_ack = disable_local3_irq, @@ -253,8 +254,6 @@ asmlinkage void plat_irq_dispatch(void) indy_8254timer_irq(); } -extern void mips_cpu_irq_init(unsigned int irq_base); - void __init arch_init_irq(void) { int i; @@ -316,7 +315,7 @@ void __init arch_init_irq(void) sgint->cmeimask1 = 0; /* init CPU irqs */ - mips_cpu_irq_init(SGINT_CPU); + mips_cpu_irq_init(); for (i = SGINT_LOCAL0; i < SGI_INTERRUPTS; i++) { struct irq_chip *handler; diff --git a/arch/mips/sgi-ip22/ip22-mc.c b/arch/mips/sgi-ip22/ip22-mc.c index b58bd52..ddb6506 100644 --- a/arch/mips/sgi-ip22/ip22-mc.c +++ b/arch/mips/sgi-ip22/ip22-mc.c @@ -202,7 +202,6 @@ void __init sgimc_init(void) } void __init prom_meminit(void) {} -unsigned long __init prom_free_prom_memory(void) +void __init prom_free_prom_memory(void) { - return 0; } diff --git a/arch/mips/sgi-ip27/ip27-irq.c b/arch/mips/sgi-ip27/ip27-irq.c index 319f880..60ade76 100644 --- a/arch/mips/sgi-ip27/ip27-irq.c +++ b/arch/mips/sgi-ip27/ip27-irq.c @@ -333,7 +333,7 @@ static inline void disable_bridge_irq(un } static struct irq_chip bridge_irq_type = { - .typename = "bridge", + .name = "bridge", .startup = startup_bridge_irq, .shutdown = shutdown_bridge_irq, .ack = disable_bridge_irq, diff --git a/arch/mips/sgi-ip27/ip27-memory.c b/arch/mips/sgi-ip27/ip27-memory.c index 16e5682..0e3d535 100644 --- a/arch/mips/sgi-ip27/ip27-memory.c +++ b/arch/mips/sgi-ip27/ip27-memory.c @@ -498,10 +498,9 @@ void __init prom_meminit(void) } } -unsigned long __init prom_free_prom_memory(void) +void __init prom_free_prom_memory(void) { /* We got nothing to free here ... */ - return 0; } extern void pagetable_init(void); diff --git a/arch/mips/sgi-ip27/ip27-timer.c b/arch/mips/sgi-ip27/ip27-timer.c index c20e989..9ce5136 100644 --- a/arch/mips/sgi-ip27/ip27-timer.c +++ b/arch/mips/sgi-ip27/ip27-timer.c @@ -181,7 +181,7 @@ static void disable_rt_irq(unsigned int } static struct irq_chip rt_irq_type = { - .typename = "SN HUB RT timer", + .name = "SN HUB RT timer", .ack = disable_rt_irq, .mask = disable_rt_irq, .mask_ack = disable_rt_irq, diff --git a/arch/mips/sgi-ip32/ip32-irq.c b/arch/mips/sgi-ip32/ip32-irq.c index ae06386..8c450d9 100644 --- a/arch/mips/sgi-ip32/ip32-irq.c +++ b/arch/mips/sgi-ip32/ip32-irq.c @@ -144,7 +144,7 @@ static void end_cpu_irq(unsigned int irq } static struct irq_chip ip32_cpu_interrupt = { - .typename = "IP32 CPU", + .name = "IP32 CPU", .ack = disable_cpu_irq, .mask = disable_cpu_irq, .mask_ack = disable_cpu_irq, @@ -193,7 +193,7 @@ static void end_crime_irq(unsigned int i } static struct irq_chip ip32_crime_interrupt = { - .typename = "IP32 CRIME", + .name = "IP32 CRIME", .ack = mask_and_ack_crime_irq, .mask = disable_crime_irq, .mask_ack = mask_and_ack_crime_irq, @@ -234,7 +234,7 @@ static void end_macepci_irq(unsigned int } static struct irq_chip ip32_macepci_interrupt = { - .typename = "IP32 MACE PCI", + .name = "IP32 MACE PCI", .ack = disable_macepci_irq, .mask = disable_macepci_irq, .mask_ack = disable_macepci_irq, @@ -347,7 +347,7 @@ static void end_maceisa_irq(unsigned irq } static struct irq_chip ip32_maceisa_interrupt = { - .typename = "IP32 MACE ISA", + .name = "IP32 MACE ISA", .ack = mask_and_ack_maceisa_irq, .mask = disable_maceisa_irq, .mask_ack = mask_and_ack_maceisa_irq, @@ -379,7 +379,7 @@ static void end_mace_irq(unsigned int ir } static struct irq_chip ip32_mace_interrupt = { - .typename = "IP32 MACE", + .name = "IP32 MACE", .ack = disable_mace_irq, .mask = disable_mace_irq, .mask_ack = disable_mace_irq, diff --git a/arch/mips/sgi-ip32/ip32-memory.c b/arch/mips/sgi-ip32/ip32-memory.c index d37d40a..849d392 100644 --- a/arch/mips/sgi-ip32/ip32-memory.c +++ b/arch/mips/sgi-ip32/ip32-memory.c @@ -43,7 +43,6 @@ void __init prom_meminit (void) } -unsigned long __init prom_free_prom_memory (void) +void __init prom_free_prom_memory(void) { - return 0; } diff --git a/arch/mips/sibyte/bcm1480/irq.c b/arch/mips/sibyte/bcm1480/irq.c index 2e8f6b2..1dc5d05 100644 --- a/arch/mips/sibyte/bcm1480/irq.c +++ b/arch/mips/sibyte/bcm1480/irq.c @@ -82,7 +82,7 @@ #endif #endif static struct irq_chip bcm1480_irq_type = { - .typename = "BCM1480-IMR", + .name = "BCM1480-IMR", .ack = ack_bcm1480_irq, .mask = disable_bcm1480_irq, .mask_ack = ack_bcm1480_irq, diff --git a/arch/mips/sibyte/cfe/setup.c b/arch/mips/sibyte/cfe/setup.c index 6e8952d..9e6099e 100644 --- a/arch/mips/sibyte/cfe/setup.c +++ b/arch/mips/sibyte/cfe/setup.c @@ -343,10 +343,9 @@ #endif /* CONFIG_BLK_DEV_INITRD */ prom_meminit(); } -unsigned long __init prom_free_prom_memory(void) +void __init prom_free_prom_memory(void) { /* Not sure what I'm supposed to do here. Nothing, I think */ - return 0; } void prom_putchar(char c) diff --git a/arch/mips/sibyte/sb1250/bcm1250_tbprof.c b/arch/mips/sibyte/sb1250/bcm1250_tbprof.c index d1a906e..212547c 100644 --- a/arch/mips/sibyte/sb1250/bcm1250_tbprof.c +++ b/arch/mips/sibyte/sb1250/bcm1250_tbprof.c @@ -374,7 +374,7 @@ static long sbprof_tb_ioctl(struct file return error; } -static struct file_operations sbprof_tb_fops = { +static const struct file_operations sbprof_tb_fops = { .owner = THIS_MODULE, .open = sbprof_tb_open, .release = sbprof_tb_release, diff --git a/arch/mips/sibyte/sb1250/irq.c b/arch/mips/sibyte/sb1250/irq.c index 82ce753..1482394 100644 --- a/arch/mips/sibyte/sb1250/irq.c +++ b/arch/mips/sibyte/sb1250/irq.c @@ -67,7 +67,7 @@ #endif #endif static struct irq_chip sb1250_irq_type = { - .typename = "SB1250-IMR", + .name = "SB1250-IMR", .ack = ack_sb1250_irq, .mask = disable_sb1250_irq, .mask_ack = ack_sb1250_irq, diff --git a/arch/mips/sibyte/sb1250/prom.c b/arch/mips/sibyte/sb1250/prom.c index 3c33a45..257c4e6 100644 --- a/arch/mips/sibyte/sb1250/prom.c +++ b/arch/mips/sibyte/sb1250/prom.c @@ -87,10 +87,9 @@ void __init prom_init(void) prom_meminit(); } -unsigned long __init prom_free_prom_memory(void) +void __init prom_free_prom_memory(void) { /* Not sure what I'm supposed to do here. Nothing, I think */ - return 0; } void prom_putchar(char c) diff --git a/arch/mips/sni/irq.c b/arch/mips/sni/irq.c index 8511bcc..039e8e5 100644 --- a/arch/mips/sni/irq.c +++ b/arch/mips/sni/irq.c @@ -37,7 +37,7 @@ static void end_pciasic_irq(unsigned int } static struct irq_chip pciasic_irq_type = { - .typename = "ASIC-PCI", + .name = "ASIC-PCI", .ack = disable_pciasic_irq, .mask = disable_pciasic_irq, .mask_ack = disable_pciasic_irq, diff --git a/arch/mips/sni/sniprom.c b/arch/mips/sni/sniprom.c index d1d0f1f..1213d16 100644 --- a/arch/mips/sni/sniprom.c +++ b/arch/mips/sni/sniprom.c @@ -67,9 +67,8 @@ void prom_printf(char *fmt, ...) va_end(args); } -unsigned long prom_free_prom_memory(void) +void __init prom_free_prom_memory(void) { - return 0; } /* diff --git a/arch/mips/tx4927/common/tx4927_irq.c b/arch/mips/tx4927/common/tx4927_irq.c index ed4a19a..e7f3e5b 100644 --- a/arch/mips/tx4927/common/tx4927_irq.c +++ b/arch/mips/tx4927/common/tx4927_irq.c @@ -120,7 +120,7 @@ static void tx4927_irq_pic_disable(unsig #define TX4927_CP0_NAME "TX4927-CP0" static struct irq_chip tx4927_irq_cp0_type = { - .typename = TX4927_CP0_NAME, + .name = TX4927_CP0_NAME, .ack = tx4927_irq_cp0_disable, .mask = tx4927_irq_cp0_disable, .mask_ack = tx4927_irq_cp0_disable, @@ -129,7 +129,7 @@ static struct irq_chip tx4927_irq_cp0_ty #define TX4927_PIC_NAME "TX4927-PIC" static struct irq_chip tx4927_irq_pic_type = { - .typename = TX4927_PIC_NAME, + .name = TX4927_PIC_NAME, .ack = tx4927_irq_pic_disable, .mask = tx4927_irq_pic_disable, .mask_ack = tx4927_irq_pic_disable, diff --git a/arch/mips/tx4927/toshiba_rbtx4927/toshiba_rbtx4927_irq.c b/arch/mips/tx4927/toshiba_rbtx4927/toshiba_rbtx4927_irq.c index b54b529..dcce88f 100644 --- a/arch/mips/tx4927/toshiba_rbtx4927/toshiba_rbtx4927_irq.c +++ b/arch/mips/tx4927/toshiba_rbtx4927/toshiba_rbtx4927_irq.c @@ -228,7 +228,7 @@ #endif #define TOSHIBA_RBTX4927_IOC_NAME "RBTX4927-IOC" static struct irq_chip toshiba_rbtx4927_irq_ioc_type = { - .typename = TOSHIBA_RBTX4927_IOC_NAME, + .name = TOSHIBA_RBTX4927_IOC_NAME, .ack = toshiba_rbtx4927_irq_ioc_disable, .mask = toshiba_rbtx4927_irq_ioc_disable, .mask_ack = toshiba_rbtx4927_irq_ioc_disable, @@ -241,7 +241,7 @@ #define TOSHIBA_RBTX4927_IOC_INTR_STAT 0 #ifdef CONFIG_TOSHIBA_FPCIB0 #define TOSHIBA_RBTX4927_ISA_NAME "RBTX4927-ISA" static struct irq_chip toshiba_rbtx4927_irq_isa_type = { - .typename = TOSHIBA_RBTX4927_ISA_NAME, + .name = TOSHIBA_RBTX4927_ISA_NAME, .ack = toshiba_rbtx4927_irq_isa_mask_and_ack, .mask = toshiba_rbtx4927_irq_isa_disable, .mask_ack = toshiba_rbtx4927_irq_isa_mask_and_ack, @@ -490,13 +490,13 @@ #ifdef TOSHIBA_RBTX4927_IRQ_DEBUG { u32 i, j = 0; for (i = 0; i < NR_IRQS; i++) { - if (strcmp(irq_desc[i].chip->typename, "none") + if (strcmp(irq_desc[i].chip->name, "none") == 0) continue; if ((i >= 1) - && (irq_desc[i - 1].chip->typename == - irq_desc[i].chip->typename)) { + && (irq_desc[i - 1].chip->name == + irq_desc[i].chip->name)) { j++; } else { j = 0; @@ -510,7 +510,7 @@ #ifdef TOSHIBA_RBTX4927_IRQ_DEBUG (u32) (irq_desc[i].action ? irq_desc[i]. action->handler : 0), irq_desc[i].depth, - irq_desc[i].chip->typename, j); + irq_desc[i].chip->name, j); } } #endif diff --git a/arch/mips/tx4927/toshiba_rbtx4927/toshiba_rbtx4927_prom.c b/arch/mips/tx4927/toshiba_rbtx4927/toshiba_rbtx4927_prom.c index efe5056..9a3a5ba 100644 --- a/arch/mips/tx4927/toshiba_rbtx4927/toshiba_rbtx4927_prom.c +++ b/arch/mips/tx4927/toshiba_rbtx4927/toshiba_rbtx4927_prom.c @@ -80,9 +80,8 @@ void __init prom_init(void) add_memory_region(0, msize << 20, BOOT_MEM_RAM); } -unsigned long __init prom_free_prom_memory(void) +void __init prom_free_prom_memory(void) { - return 0; } const char *get_system_type(void) diff --git a/arch/mips/tx4927/toshiba_rbtx4927/toshiba_rbtx4927_setup.c b/arch/mips/tx4927/toshiba_rbtx4927/toshiba_rbtx4927_setup.c index 735cb87..7316a78 100644 --- a/arch/mips/tx4927/toshiba_rbtx4927/toshiba_rbtx4927_setup.c +++ b/arch/mips/tx4927/toshiba_rbtx4927/toshiba_rbtx4927_setup.c @@ -137,6 +137,8 @@ int tx4927_using_backplane = 0; extern void gt64120_time_init(void); extern void toshiba_rbtx4927_irq_setup(void); +char *prom_getcmdline(void); + #ifdef CONFIG_PCI #define CONFIG_TX4927BUG_WORKAROUND #undef TX4927_SUPPORT_COMMAND_IO diff --git a/arch/mips/tx4938/common/irq.c b/arch/mips/tx4938/common/irq.c index a347b42..3a2dbfc 100644 --- a/arch/mips/tx4938/common/irq.c +++ b/arch/mips/tx4938/common/irq.c @@ -49,7 +49,7 @@ static void tx4938_irq_pic_disable(unsig #define TX4938_CP0_NAME "TX4938-CP0" static struct irq_chip tx4938_irq_cp0_type = { - .typename = TX4938_CP0_NAME, + .name = TX4938_CP0_NAME, .ack = tx4938_irq_cp0_disable, .mask = tx4938_irq_cp0_disable, .mask_ack = tx4938_irq_cp0_disable, @@ -58,7 +58,7 @@ static struct irq_chip tx4938_irq_cp0_ty #define TX4938_PIC_NAME "TX4938-PIC" static struct irq_chip tx4938_irq_pic_type = { - .typename = TX4938_PIC_NAME, + .name = TX4938_PIC_NAME, .ack = tx4938_irq_pic_disable, .mask = tx4938_irq_pic_disable, .mask_ack = tx4938_irq_pic_disable, diff --git a/arch/mips/tx4938/toshiba_rbtx4938/irq.c b/arch/mips/tx4938/toshiba_rbtx4938/irq.c index b6f363d..2e96dbb 100644 --- a/arch/mips/tx4938/toshiba_rbtx4938/irq.c +++ b/arch/mips/tx4938/toshiba_rbtx4938/irq.c @@ -92,7 +92,7 @@ static void toshiba_rbtx4938_irq_ioc_dis #define TOSHIBA_RBTX4938_IOC_NAME "RBTX4938-IOC" static struct irq_chip toshiba_rbtx4938_irq_ioc_type = { - .typename = TOSHIBA_RBTX4938_IOC_NAME, + .name = TOSHIBA_RBTX4938_IOC_NAME, .ack = toshiba_rbtx4938_irq_ioc_disable, .mask = toshiba_rbtx4938_irq_ioc_disable, .mask_ack = toshiba_rbtx4938_irq_ioc_disable, diff --git a/arch/mips/tx4938/toshiba_rbtx4938/prom.c b/arch/mips/tx4938/toshiba_rbtx4938/prom.c index e44daf3..7dc6a0a 100644 --- a/arch/mips/tx4938/toshiba_rbtx4938/prom.c +++ b/arch/mips/tx4938/toshiba_rbtx4938/prom.c @@ -56,9 +56,8 @@ #endif return; } -unsigned long __init prom_free_prom_memory(void) +void __init prom_free_prom_memory(void) { - return 0; } void __init prom_fixup_mem_map(unsigned long start, unsigned long end) diff --git a/arch/mips/vr41xx/common/icu.c b/arch/mips/vr41xx/common/icu.c index c075261..adabc6b 100644 --- a/arch/mips/vr41xx/common/icu.c +++ b/arch/mips/vr41xx/common/icu.c @@ -3,7 +3,7 @@ * * Copyright (C) 2001-2002 MontaVista Software Inc. * Author: Yoichi Yuasa - * Copyright (C) 2003-2005 Yoichi Yuasa + * Copyright (C) 2003-2006 Yoichi Yuasa * * 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 @@ -68,6 +68,7 @@ #define MSYSINT1REG 0x0c #define MPIUINTREG 0x0e #define MAIUINTREG 0x10 #define MKIUINTREG 0x12 +#define MMACINTREG 0x12 #define MGIUINTLREG 0x14 #define MDSIUINTREG 0x16 #define NMIREG 0x18 @@ -241,6 +242,30 @@ void vr41xx_disable_kiuint(uint16_t mask EXPORT_SYMBOL(vr41xx_disable_kiuint); +void vr41xx_enable_macint(uint16_t mask) +{ + struct irq_desc *desc = irq_desc + ETHERNET_IRQ; + unsigned long flags; + + spin_lock_irqsave(&desc->lock, flags); + icu1_set(MMACINTREG, mask); + spin_unlock_irqrestore(&desc->lock, flags); +} + +EXPORT_SYMBOL(vr41xx_enable_macint); + +void vr41xx_disable_macint(uint16_t mask) +{ + struct irq_desc *desc = irq_desc + ETHERNET_IRQ; + unsigned long flags; + + spin_lock_irqsave(&desc->lock, flags); + icu1_clear(MMACINTREG, mask); + spin_unlock_irqrestore(&desc->lock, flags); +} + +EXPORT_SYMBOL(vr41xx_disable_macint); + void vr41xx_enable_dsiuint(uint16_t mask) { struct irq_desc *desc = irq_desc + DSIU_IRQ; @@ -428,7 +453,7 @@ static void enable_sysint1_irq(unsigned } static struct irq_chip sysint1_irq_type = { - .typename = "SYSINT1", + .name = "SYSINT1", .ack = disable_sysint1_irq, .mask = disable_sysint1_irq, .mask_ack = disable_sysint1_irq, @@ -446,7 +471,7 @@ static void enable_sysint2_irq(unsigned } static struct irq_chip sysint2_irq_type = { - .typename = "SYSINT2", + .name = "SYSINT2", .ack = disable_sysint2_irq, .mask = disable_sysint2_irq, .mask_ack = disable_sysint2_irq, diff --git a/arch/mips/vr41xx/common/init.c b/arch/mips/vr41xx/common/init.c index a2e285c..4f97e0b 100644 --- a/arch/mips/vr41xx/common/init.c +++ b/arch/mips/vr41xx/common/init.c @@ -81,7 +81,6 @@ void __init prom_init(void) } } -unsigned long __init prom_free_prom_memory (void) +void __init prom_free_prom_memory(void) { - return 0UL; } diff --git a/arch/mips/vr41xx/common/irq.c b/arch/mips/vr41xx/common/irq.c index 16decf4..cba36a2 100644 --- a/arch/mips/vr41xx/common/irq.c +++ b/arch/mips/vr41xx/common/irq.c @@ -95,27 +95,27 @@ asmlinkage void plat_irq_dispatch(void) unsigned int pending = read_c0_cause() & read_c0_status() & ST0_IM; if (pending & CAUSEF_IP7) - do_IRQ(7); + do_IRQ(TIMER_IRQ); else if (pending & 0x7800) { if (pending & CAUSEF_IP3) - irq_dispatch(3); + irq_dispatch(INT1_IRQ); else if (pending & CAUSEF_IP4) - irq_dispatch(4); + irq_dispatch(INT2_IRQ); else if (pending & CAUSEF_IP5) - irq_dispatch(5); + irq_dispatch(INT3_IRQ); else if (pending & CAUSEF_IP6) - irq_dispatch(6); + irq_dispatch(INT4_IRQ); } else if (pending & CAUSEF_IP2) - irq_dispatch(2); + irq_dispatch(INT0_IRQ); else if (pending & CAUSEF_IP0) - do_IRQ(0); + do_IRQ(MIPS_SOFTINT0_IRQ); else if (pending & CAUSEF_IP1) - do_IRQ(1); + do_IRQ(MIPS_SOFTINT1_IRQ); else spurious_interrupt(); } void __init arch_init_irq(void) { - mips_cpu_irq_init(MIPS_CPU_IRQ_BASE); + mips_cpu_irq_init(); } diff --git a/arch/mips/vr41xx/nec-cmbvr4133/irq.c b/arch/mips/vr41xx/nec-cmbvr4133/irq.c index 128ed8d..7d2d076 100644 --- a/arch/mips/vr41xx/nec-cmbvr4133/irq.c +++ b/arch/mips/vr41xx/nec-cmbvr4133/irq.c @@ -21,60 +21,16 @@ #include #include #include +#include #include -extern void enable_8259A_irq(unsigned int irq); -extern void disable_8259A_irq(unsigned int irq); -extern void mask_and_ack_8259A(unsigned int irq); -extern void init_8259A(int hoge); - extern int vr4133_rockhopper; -static void enable_i8259_irq(unsigned int irq) -{ - enable_8259A_irq(irq - I8259_IRQ_BASE); -} - -static void disable_i8259_irq(unsigned int irq) -{ - disable_8259A_irq(irq - I8259_IRQ_BASE); -} - -static void ack_i8259_irq(unsigned int irq) -{ - mask_and_ack_8259A(irq - I8259_IRQ_BASE); -} - -static struct irq_chip i8259_irq_type = { - .typename = "XT-PIC", - .ack = ack_i8259_irq, - .mask = disable_i8259_irq, - .mask_ack = ack_i8259_irq, - .unmask = enable_i8259_irq, -}; - static int i8259_get_irq_number(int irq) { - unsigned long isr; - - isr = inb(0x20); - irq = ffz(~isr); - if (irq == 2) { - isr = inb(0xa0); - irq = 8 + ffz(~isr); - } - - if (irq < 0 || irq > 15) - return -EINVAL; - - return I8259_IRQ_BASE + irq; + return i8259_irq(); } -static struct irqaction i8259_slave_cascade = { - .handler = &no_action, - .name = "cascade", -}; - void __init rockhopper_init_irq(void) { int i; @@ -84,11 +40,6 @@ void __init rockhopper_init_irq(void) return; } - for (i = I8259_IRQ_BASE; i <= I8259_IRQ_LAST; i++) - set_irq_chip_and_handler(i, &i8259_irq_type, handle_level_irq); - - setup_irq(I8259_SLAVE_IRQ, &i8259_slave_cascade); - vr41xx_set_irq_trigger(CMBVR41XX_INTC_PIN, TRIGGER_LEVEL, SIGNAL_THROUGH); vr41xx_set_irq_level(CMBVR41XX_INTC_PIN, LEVEL_HIGH); vr41xx_cascade_irq(CMBVR41XX_INTC_IRQ, i8259_get_irq_number); diff --git a/arch/parisc/Kconfig b/arch/parisc/Kconfig index 0f9ff61..28da4e7 100644 --- a/arch/parisc/Kconfig +++ b/arch/parisc/Kconfig @@ -50,9 +50,6 @@ config TIME_LOW_RES depends on SMP default y -config GENERIC_ISA_DMA - bool - config GENERIC_HARDIRQS def_bool y diff --git a/arch/parisc/kernel/perf.c b/arch/parisc/kernel/perf.c index ac8ee20..a46bc62 100644 --- a/arch/parisc/kernel/perf.c +++ b/arch/parisc/kernel/perf.c @@ -479,7 +479,7 @@ static long perf_ioctl(struct file *file return error; } -static struct file_operations perf_fops = { +static const struct file_operations perf_fops = { .llseek = no_llseek, .read = perf_read, .write = perf_write, diff --git a/arch/parisc/kernel/setup.c b/arch/parisc/kernel/setup.c index 3c7a3fa..74b3686 100644 --- a/arch/parisc/kernel/setup.c +++ b/arch/parisc/kernel/setup.c @@ -45,7 +45,7 @@ #include #include #include -char command_line[COMMAND_LINE_SIZE] __read_mostly; +char __initdata command_line[COMMAND_LINE_SIZE] __read_mostly; /* Intended for ccio/sba/cpu statistics under /proc/bus/{runway|gsc} */ struct proc_dir_entry * proc_runway_root __read_mostly = NULL; @@ -71,9 +71,9 @@ void __init setup_cmdline(char **cmdline /* boot_args[0] is free-mem start, boot_args[1] is ptr to command line */ if (boot_args[0] < 64) { /* called from hpux boot loader */ - saved_command_line[0] = '\0'; + boot_command_line[0] = '\0'; } else { - strcpy(saved_command_line, (char *)__va(boot_args[1])); + strcpy(boot_command_line, (char *)__va(boot_args[1])); #ifdef CONFIG_BLK_DEV_INITRD if (boot_args[2] != 0) /* did palo pass us a ramdisk? */ @@ -84,7 +84,7 @@ #ifdef CONFIG_BLK_DEV_INITRD #endif } - strcpy(command_line, saved_command_line); + strcpy(command_line, boot_command_line); *cmdline_p = command_line; } diff --git a/arch/parisc/kernel/sys_parisc32.c b/arch/parisc/kernel/sys_parisc32.c index 29be437..ce3245f 100644 --- a/arch/parisc/kernel/sys_parisc32.c +++ b/arch/parisc/kernel/sys_parisc32.c @@ -579,70 +579,6 @@ asmlinkage int sys32_sendfile64(int out_ } -struct sysinfo32 { - s32 uptime; - u32 loads[3]; - u32 totalram; - u32 freeram; - u32 sharedram; - u32 bufferram; - u32 totalswap; - u32 freeswap; - unsigned short procs; - u32 totalhigh; - u32 freehigh; - u32 mem_unit; - char _f[12]; -}; - -/* We used to call sys_sysinfo and translate the result. But sys_sysinfo - * undoes the good work done elsewhere, and rather than undoing the - * damage, I decided to just duplicate the code from sys_sysinfo here. - */ - -asmlinkage int sys32_sysinfo(struct sysinfo32 __user *info) -{ - struct sysinfo val; - int err; - unsigned long seq; - - /* We don't need a memset here because we copy the - * struct to userspace once element at a time. - */ - - do { - seq = read_seqbegin(&xtime_lock); - val.uptime = jiffies / HZ; - - val.loads[0] = avenrun[0] << (SI_LOAD_SHIFT - FSHIFT); - val.loads[1] = avenrun[1] << (SI_LOAD_SHIFT - FSHIFT); - val.loads[2] = avenrun[2] << (SI_LOAD_SHIFT - FSHIFT); - - val.procs = nr_threads; - } while (read_seqretry(&xtime_lock, seq)); - - - si_meminfo(&val); - si_swapinfo(&val); - - err = put_user (val.uptime, &info->uptime); - err |= __put_user (val.loads[0], &info->loads[0]); - err |= __put_user (val.loads[1], &info->loads[1]); - err |= __put_user (val.loads[2], &info->loads[2]); - err |= __put_user (val.totalram, &info->totalram); - err |= __put_user (val.freeram, &info->freeram); - err |= __put_user (val.sharedram, &info->sharedram); - err |= __put_user (val.bufferram, &info->bufferram); - err |= __put_user (val.totalswap, &info->totalswap); - err |= __put_user (val.freeswap, &info->freeswap); - err |= __put_user (val.procs, &info->procs); - err |= __put_user (val.totalhigh, &info->totalhigh); - err |= __put_user (val.freehigh, &info->freehigh); - err |= __put_user (val.mem_unit, &info->mem_unit); - return err ? -EFAULT : 0; -} - - /* lseek() needs a wrapper because 'offset' can be negative, but the top * half of the argument has been zeroed by syscall.S. */ diff --git a/arch/parisc/kernel/syscall_table.S b/arch/parisc/kernel/syscall_table.S index 701d66a..be8eb9a 100644 --- a/arch/parisc/kernel/syscall_table.S +++ b/arch/parisc/kernel/syscall_table.S @@ -197,7 +197,7 @@ #endif /* struct rusage contains longs... */ ENTRY_COMP(wait4) ENTRY_SAME(swapoff) /* 115 */ - ENTRY_DIFF(sysinfo) + ENTRY_COMP(sysinfo) ENTRY_SAME(shutdown) ENTRY_SAME(fsync) ENTRY_SAME(madvise) diff --git a/arch/parisc/kernel/time.c b/arch/parisc/kernel/time.c index bad7d1e..5f1b51a 100644 --- a/arch/parisc/kernel/time.c +++ b/arch/parisc/kernel/time.c @@ -288,17 +288,6 @@ do_settimeofday (struct timespec *tv) } EXPORT_SYMBOL(do_settimeofday); -/* - * XXX: We can do better than this. - * Returns nanoseconds - */ - -unsigned long long sched_clock(void) -{ - return (unsigned long long)jiffies * (1000000000 / HZ); -} - - void __init start_cpu_itimer(void) { unsigned int cpu = smp_processor_id(); diff --git a/arch/parisc/kernel/vmlinux.lds.S b/arch/parisc/kernel/vmlinux.lds.S index 7b943b4..3b78c27 100644 --- a/arch/parisc/kernel/vmlinux.lds.S +++ b/arch/parisc/kernel/vmlinux.lds.S @@ -173,10 +173,12 @@ #endif from .altinstructions and .eh_frame */ .exit.text : { *(.exit.text) } .exit.data : { *(.exit.data) } +#ifdef CONFIG_BLK_DEV_INITRD . = ALIGN(ASM_PAGE_SIZE); __initramfs_start = .; .init.ramfs : { *(.init.ramfs) } __initramfs_end = .; +#endif . = ALIGN(32); __per_cpu_start = .; .data.percpu : { *(.data.percpu) } diff --git a/arch/parisc/mm/init.c b/arch/parisc/mm/init.c index 0667f2b..12117db 100644 --- a/arch/parisc/mm/init.c +++ b/arch/parisc/mm/init.c @@ -77,12 +77,11 @@ static void __init mem_limit_func(void) { char *cp, *end; unsigned long limit; - extern char saved_command_line[]; /* We need this before __setup() functions are called */ limit = MAX_MEM; - for (cp = saved_command_line; *cp; ) { + for (cp = boot_command_line; *cp; ) { if (memcmp(cp, "mem=", 4) == 0) { cp += 4; limit = memparse(cp, &end); @@ -808,9 +807,7 @@ void __init paging_init(void) for (i = 0; i < npmem_ranges; i++) { unsigned long zones_size[MAX_NR_ZONES] = { 0, }; - /* We have an IOMMU, so all memory can go into a single - ZONE_DMA zone. */ - zones_size[ZONE_DMA] = pmem_ranges[i].pages; + zones_size[ZONE_NORMAL] = pmem_ranges[i].pages; #ifdef CONFIG_DISCONTIGMEM /* Need to initialize the pfnnid_map before we can initialize diff --git a/arch/powerpc/Kconfig b/arch/powerpc/Kconfig index d6abe49..340d9be 100644 --- a/arch/powerpc/Kconfig +++ b/arch/powerpc/Kconfig @@ -173,6 +173,11 @@ config PPC_86xx help The Freescale E600 SoCs have 74xx cores. +config PPC_8xx + bool "Freescale 8xx" + select FSL_SOC + select 8xx + config 40x bool "AMCC 40x" select PPC_DCR_NATIVE @@ -181,8 +186,6 @@ config 44x bool "AMCC 44x" select PPC_DCR_NATIVE -config 8xx - bool "Freescale 8xx" config E200 bool "Freescale e200" @@ -211,6 +214,10 @@ config 6xx bool # this is temp to handle compat with arch=ppc +config 8xx + bool + +# this is temp to handle compat with arch=ppc config 83xx bool @@ -429,6 +436,21 @@ config PPC_MPC52xx bool default n +config PPC_MPC5200 + bool + select PPC_MPC52xx + default n + +config PPC_MPC5200_BUGFIX + bool "MPC5200 (L25R) bugfix support" + depends on PPC_MPC5200 + default n + help + Enable workarounds for original MPC5200 errata. This is not required + for MPC5200B based boards. + + It is safe to say 'Y' here + config PPC_EFIKA bool "bPlan Efika 5k2. MPC5200B based computer" depends on PPC_MULTIPLATFORM && PPC32 @@ -441,7 +463,7 @@ config PPC_EFIKA config PPC_LITE5200 bool "Freescale Lite5200 Eval Board" depends on PPC_MULTIPLATFORM && PPC32 - select PPC_MPC52xx + select PPC_MPC5200 default n config PPC_PMAC @@ -484,6 +506,7 @@ config PPC_MAPLE select PPC_970_NAP select PPC_NATIVE select PPC_RTAS + select MMIO_NVRAM select ATA_NONSTANDARD if ATA default n help @@ -529,6 +552,11 @@ config PPC_PS3 bool "Sony PS3 (incomplete)" depends on PPC_MULTIPLATFORM && PPC64 select PPC_CELL + select USB_ARCH_HAS_OHCI + select USB_OHCI_LITTLE_ENDIAN + select USB_OHCI_BIG_ENDIAN_MMIO + select USB_ARCH_HAS_EHCI + select USB_EHCI_BIG_ENDIAN_MMIO help This option enables support for the Sony PS3 game console and other platforms using the PS3 hypervisor. @@ -536,6 +564,16 @@ config PPC_PS3 enabling this will not result in a bootable kernel on a PS3 system. +config PPC_CELLEB + bool "Toshiba's Cell Reference Set 'Celleb' Architecture" + depends on PPC_MULTIPLATFORM && PPC64 + select PPC_CELL + select PPC_OF_PLATFORM_PCI + select HAS_TXX9_SERIAL + select PPC_UDBG_BEAT + select USB_OHCI_BIG_ENDIAN_MMIO + select USB_EHCI_BIG_ENDIAN_MMIO + config PPC_NATIVE bool depends on PPC_MULTIPLATFORM @@ -549,6 +587,11 @@ config UDBG_RTAS_CONSOLE depends on PPC_RTAS default n +config PPC_UDBG_BEAT + bool "BEAT based debug console" + depends on PPC_CELLEB + default n + config XICS depends on PPC_PSERIES bool @@ -702,6 +745,7 @@ source arch/powerpc/platforms/86xx/Kconf source arch/powerpc/platforms/8xx/Kconfig source arch/powerpc/platforms/cell/Kconfig source arch/powerpc/platforms/ps3/Kconfig +source arch/powerpc/platforms/pasemi/Kconfig menu "Kernel options" @@ -724,7 +768,7 @@ config FORCE_MAX_ZONEORDER config MATH_EMULATION bool "Math emulation" - depends on 4xx || 8xx || E200 || PPC_83xx || E500 + depends on 4xx || 8xx || E200 || PPC_MPC832x || E500 ---help--- Some PowerPC chips designed for embedded applications do not have a floating-point unit and therefore do not implement the @@ -832,7 +876,7 @@ config ARCH_SPARSEMEM_ENABLE config ARCH_SPARSEMEM_DEFAULT def_bool y - depends on (SMP && PPC_PSERIES) || PPC_CELL + depends on (SMP && PPC_PSERIES) || PPC_PS3 config ARCH_POPULATES_NODE_MAP def_bool y @@ -933,6 +977,10 @@ config ISA have an IBM RS/6000 or pSeries machine or a PReP machine, say Y. If you have an embedded board, consult your board documentation. +config ZONE_DMA + bool + default y + config GENERIC_ISA_DMA bool depends on PPC64 || POWER4 || 6xx && !CPM2 @@ -1182,7 +1230,7 @@ source "arch/powerpc/oprofile/Kconfig" config KPROBES bool "Kprobes (EXPERIMENTAL)" - depends on PPC64 && KALLSYMS && EXPERIMENTAL && MODULES + depends on !BOOKE && !4xx && KALLSYMS && EXPERIMENTAL && MODULES help Kprobes allows you to trap at almost any kernel address and execute a callback function. register_kprobe() establishes diff --git a/arch/powerpc/Kconfig.debug b/arch/powerpc/Kconfig.debug index f0e51ed..d39d133 100644 --- a/arch/powerpc/Kconfig.debug +++ b/arch/powerpc/Kconfig.debug @@ -4,14 +4,14 @@ source "lib/Kconfig.debug" config DEBUG_STACKOVERFLOW bool "Check for stack overflows" - depends on DEBUG_KERNEL && PPC64 + depends on DEBUG_KERNEL help This option will cause messages to be printed if free stack space drops below a certain limit. config DEBUG_STACK_USAGE bool "Stack utilization instrumentation" - depends on DEBUG_KERNEL && PPC64 + depends on DEBUG_KERNEL help Enables the display of the minimum amount of free stack which each task has ever had available in the sysrq-T and sysrq-P debug output. @@ -185,6 +185,20 @@ config PPC_EARLY_DEBUG_ISERIES Select this to enable early debugging for legacy iSeries. You need to hit "Ctrl-x Ctrl-x" to see the messages on the console. +config PPC_EARLY_DEBUG_PAS_REALMODE + bool "PA Semi real mode" + depends on PPC_PASEMI + help + Select this to enable early debugging for PA Semi. + Output will be on UART0. + +config PPC_EARLY_DEBUG_BEAT + bool "Beat HV Console" + depends on PPC_CELLEB + select PPC_UDBG_BEAT + help + Select this to enable early debugging for Celleb with Beat. + endchoice endmenu diff --git a/arch/powerpc/boot/Makefile b/arch/powerpc/boot/Makefile index 98392fb..dc77940 100644 --- a/arch/powerpc/boot/Makefile +++ b/arch/powerpc/boot/Makefile @@ -162,6 +162,7 @@ image-$(CONFIG_PPC_PSERIES) += zImage.p image-$(CONFIG_PPC_MAPLE) += zImage.pseries image-$(CONFIG_PPC_IBM_CELL_BLADE) += zImage.pseries image-$(CONFIG_PPC_PS3) += zImage.ps3 +image-$(CONFIG_PPC_CELLEB) += zImage.pseries image-$(CONFIG_PPC_CHRP) += zImage.chrp image-$(CONFIG_PPC_EFIKA) += zImage.chrp image-$(CONFIG_PPC_PMAC) += zImage.pmac diff --git a/arch/powerpc/boot/dts/kuroboxHD.dts b/arch/powerpc/boot/dts/kuroboxHD.dts new file mode 100644 index 0000000..096e94a --- /dev/null +++ b/arch/powerpc/boot/dts/kuroboxHD.dts @@ -0,0 +1,148 @@ +/* + * Device Tree Souce for Buffalo KuroboxHD + * + * Choose CONFIG_LINKSTATION to build a kernel for KuroboxHD, or use + * the default configuration linkstation_defconfig. + * + * Based on sandpoint.dts + * + * 2006 (c) G. Liakhovetski + * + * This file is licensed under + * the terms of the GNU General Public License version 2. This program + * is licensed "as is" without any warranty of any kind, whether express + * or implied. + +XXXX add flash parts, rtc, ?? + +build with: "dtc -f -I dts -O dtb -o kuroboxHD.dtb -V 16 kuroboxHD.dts" + + + */ + +/ { + linux,phandle = <1000>; + model = "KuroboxHD"; + compatible = "linkstation"; + #address-cells = <1>; + #size-cells = <1>; + + cpus { + linux,phandle = <2000>; + #cpus = <1>; + #address-cells = <1>; + #size-cells = <0>; + + PowerPC,603e { /* Really 8241 */ + linux,phandle = <2100>; + linux,boot-cpu; + device_type = "cpu"; + reg = <0>; + clock-frequency = ; /* Fixed by bootwrapper */ + timebase-frequency = <1743000>; /* Fixed by bootwrapper */ + bus-frequency = <0>; /* From bootloader */ + /* Following required by dtc but not used */ + i-cache-line-size = <0>; + d-cache-line-size = <0>; + i-cache-size = <4000>; + d-cache-size = <4000>; + }; + }; + + memory { + linux,phandle = <3000>; + device_type = "memory"; + reg = <00000000 04000000>; + }; + + soc10x { /* AFAICT need to make soc for 8245's uarts to be defined */ + linux,phandle = <4000>; + #address-cells = <1>; + #size-cells = <1>; + #interrupt-cells = <2>; + device_type = "soc"; + compatible = "mpc10x"; + store-gathering = <0>; /* 0 == off, !0 == on */ + reg = <80000000 00100000>; + ranges = <80000000 80000000 70000000 /* pci mem space */ + fc000000 fc000000 00100000 /* EUMB */ + fe000000 fe000000 00c00000 /* pci i/o space */ + fec00000 fec00000 00300000 /* pci cfg regs */ + fef00000 fef00000 00100000>; /* pci iack */ + + i2c@80003000 { + linux,phandle = <4300>; + device_type = "i2c"; + compatible = "fsl-i2c"; + reg = <80003000 1000>; + interrupts = <5 2>; + interrupt-parent = <4400>; + }; + + serial@80004500 { + linux,phandle = <4511>; + device_type = "serial"; + compatible = "ns16550"; + reg = <80004500 8>; + clock-frequency = <5d08d88>; + current-speed = <2580>; + interrupts = <9 2>; + interrupt-parent = <4400>; + }; + + serial@80004600 { + linux,phandle = <4512>; + device_type = "serial"; + compatible = "ns16550"; + reg = <80004600 8>; + clock-frequency = <5d08d88>; + current-speed = ; + interrupts = ; + interrupt-parent = <4400>; + }; + + pic@80040000 { + linux,phandle = <4400>; + #interrupt-cells = <2>; + #address-cells = <0>; + device_type = "open-pic"; + compatible = "chrp,open-pic"; + interrupt-controller; + reg = <80040000 40000>; + built-in; + }; + + pci@fec00000 { + linux,phandle = <4500>; + #address-cells = <3>; + #size-cells = <2>; + #interrupt-cells = <1>; + device_type = "pci"; + compatible = "mpc10x-pci"; + reg = ; + ranges = <01000000 0 0 fe000000 0 00c00000 + 02000000 0 80000000 80000000 0 70000000>; + bus-range = <0 ff>; + clock-frequency = <7f28155>; + interrupt-parent = <4400>; + interrupt-map-mask = ; + interrupt-map = < + /* IDSEL 0x11 - IRQ0 ETH */ + 5800 0 0 1 4400 0 1 + 5800 0 0 2 4400 1 1 + 5800 0 0 3 4400 2 1 + 5800 0 0 4 4400 3 1 + /* IDSEL 0x12 - IRQ1 IDE0 */ + 6000 0 0 1 4400 1 1 + 6000 0 0 2 4400 2 1 + 6000 0 0 3 4400 3 1 + 6000 0 0 4 4400 0 1 + /* IDSEL 0x14 - IRQ3 USB2.0 */ + 7000 0 0 1 4400 3 1 + 7000 0 0 2 4400 3 1 + 7000 0 0 3 4400 3 1 + 7000 0 0 4 4400 3 1 + >; + }; + }; +}; diff --git a/arch/powerpc/boot/dts/lite5200.dts b/arch/powerpc/boot/dts/lite5200.dts index 1868707..c03103c 100644 --- a/arch/powerpc/boot/dts/lite5200.dts +++ b/arch/powerpc/boot/dts/lite5200.dts @@ -1,7 +1,7 @@ /* * Lite5200 board Device Tree Source * - * Copyright 2006 Secret Lab Technologies Ltd. + * Copyright 2006-2007 Secret Lab Technologies Ltd. * Grant Likely * * This program is free software; you can redistribute it and/or modify it @@ -17,8 +17,9 @@ */ / { - model = "Lite5200"; - compatible = "lite5200\0lite52xx\0mpc5200\0mpc52xx"; + model = "fsl,lite5200"; + // revision = "1.0"; + compatible = "fsl,lite5200\0generic-mpc5200"; #address-cells = <1>; #size-cells = <1>; @@ -47,14 +48,17 @@ }; soc5200@f0000000 { + model = "fsl,mpc5200"; + revision = "" // from bootloader #interrupt-cells = <3>; device_type = "soc"; ranges = <0 f0000000 f0010000>; reg = ; bus-frequency = <0>; // from bootloader + system-frequency = <0>; // from bootloader cdm@200 { - compatible = "mpc5200-cdm\0mpc52xx-cdm"; + compatible = "mpc5200-cdm"; reg = <200 38>; }; @@ -64,77 +68,86 @@ interrupt-controller; #interrupt-cells = <3>; device_type = "interrupt-controller"; - compatible = "mpc5200-pic\0mpc52xx-pic"; + compatible = "mpc5200-pic"; reg = <500 80>; built-in; }; gpt@600 { // General Purpose Timer - compatible = "mpc5200-gpt\0mpc52xx-gpt"; + compatible = "mpc5200-gpt"; device_type = "gpt"; + cell-index = <0>; reg = <600 10>; interrupts = <1 9 0>; interrupt-parent = <500>; + has-wdt; }; gpt@610 { // General Purpose Timer - compatible = "mpc5200-gpt\0mpc52xx-gpt"; + compatible = "mpc5200-gpt"; device_type = "gpt"; + cell-index = <1>; reg = <610 10>; interrupts = <1 a 0>; interrupt-parent = <500>; }; gpt@620 { // General Purpose Timer - compatible = "mpc5200-gpt\0mpc52xx-gpt"; + compatible = "mpc5200-gpt"; device_type = "gpt"; + cell-index = <2>; reg = <620 10>; interrupts = <1 b 0>; interrupt-parent = <500>; }; gpt@630 { // General Purpose Timer - compatible = "mpc5200-gpt\0mpc52xx-gpt"; + compatible = "mpc5200-gpt"; device_type = "gpt"; + cell-index = <3>; reg = <630 10>; interrupts = <1 c 0>; interrupt-parent = <500>; }; gpt@640 { // General Purpose Timer - compatible = "mpc5200-gpt\0mpc52xx-gpt"; + compatible = "mpc5200-gpt"; device_type = "gpt"; + cell-index = <4>; reg = <640 10>; interrupts = <1 d 0>; interrupt-parent = <500>; }; gpt@650 { // General Purpose Timer - compatible = "mpc5200-gpt\0mpc52xx-gpt"; + compatible = "mpc5200-gpt"; device_type = "gpt"; + cell-index = <5>; reg = <650 10>; interrupts = <1 e 0>; interrupt-parent = <500>; }; gpt@660 { // General Purpose Timer - compatible = "mpc5200-gpt\0mpc52xx-gpt"; + compatible = "mpc5200-gpt"; device_type = "gpt"; + cell-index = <6>; reg = <660 10>; interrupts = <1 f 0>; interrupt-parent = <500>; }; gpt@670 { // General Purpose Timer - compatible = "mpc5200-gpt\0mpc52xx-gpt"; + compatible = "mpc5200-gpt"; device_type = "gpt"; + cell-index = <7>; reg = <670 10>; interrupts = <1 10 0>; interrupt-parent = <500>; }; rtc@800 { // Real time clock - compatible = "mpc5200-rtc\0mpc52xx-rtc"; + compatible = "mpc5200-rtc"; device_type = "rtc"; reg = <800 100>; interrupts = <1 5 0 1 6 0>; @@ -143,7 +156,8 @@ mscan@900 { device_type = "mscan"; - compatible = "mpc5200-mscan\0mpc52xx-mscan"; + compatible = "mpc5200-mscan"; + cell-index = <0>; interrupts = <2 11 0>; interrupt-parent = <500>; reg = <900 80>; @@ -151,21 +165,22 @@ mscan@980 { device_type = "mscan"; - compatible = "mpc5200-mscan\0mpc52xx-mscan"; + compatible = "mpc5200-mscan"; + cell-index = <1>; interrupts = <1 12 0>; interrupt-parent = <500>; reg = <980 80>; }; gpio@b00 { - compatible = "mpc5200-gpio\0mpc52xx-gpio"; + compatible = "mpc5200-gpio"; reg = ; interrupts = <1 7 0>; interrupt-parent = <500>; }; gpio-wkup@b00 { - compatible = "mpc5200-gpio-wkup\0mpc52xx-gpio-wkup"; + compatible = "mpc5200-gpio-wkup"; reg = ; interrupts = <1 8 0 0 3 0>; interrupt-parent = <500>; @@ -176,7 +191,7 @@ #size-cells = <2>; #address-cells = <3>; device_type = "pci"; - compatible = "mpc5200-pci\0mpc52xx-pci"; + compatible = "mpc5200-pci"; reg = ; interrupt-map-mask = ; interrupt-map = ; interrupts = <2 d 0 2 e 0>; interrupt-parent = <500>; @@ -202,7 +217,7 @@ usb@1000 { device_type = "usb-ohci-be"; - compatible = "mpc5200-ohci\0mpc52xx-ohci\0ohci-be"; + compatible = "mpc5200-ohci\0ohci-be"; reg = <1000 ff>; interrupts = <2 6 0>; interrupt-parent = <500>; @@ -210,7 +225,7 @@ bestcomm@1200 { device_type = "dma-controller"; - compatible = "mpc5200-bestcomm\0mpc52xx-bestcomm"; + compatible = "mpc5200-bestcomm"; reg = <1200 80>; interrupts = <3 0 0 3 1 0 3 2 0 3 3 0 3 4 0 3 5 0 3 6 0 3 7 0 @@ -220,67 +235,73 @@ }; xlb@1f00 { - compatible = "mpc5200-xlb\0mpc52xx-xlb"; + compatible = "mpc5200-xlb"; reg = <1f00 100>; }; serial@2000 { // PSC1 device_type = "serial"; - compatible = "mpc5200-psc-uart\0mpc52xx-psc-uart"; + compatible = "mpc5200-psc-uart"; port-number = <0>; // Logical port assignment + cell-index = <0>; reg = <2000 100>; interrupts = <2 1 0>; interrupt-parent = <500>; }; - // PSC2 in spi mode example - spi@2200 { // PSC2 - device_type = "spi"; - compatible = "mpc5200-psc-spi\0mpc52xx-psc-spi"; - reg = <2200 100>; - interrupts = <2 2 0>; - interrupt-parent = <500>; - }; + // PSC2 in ac97 mode example + //ac97@2200 { // PSC2 + // device_type = "sound"; + // compatible = "mpc5200-psc-ac97"; + // cell-index = <1>; + // reg = <2200 100>; + // interrupts = <2 2 0>; + // interrupt-parent = <500>; + //}; // PSC3 in CODEC mode example - i2s@2400 { // PSC3 - device_type = "sound"; - compatible = "mpc5200-psc-i2s\0mpc52xx-psc-i2s"; - reg = <2400 100>; - interrupts = <2 3 0>; - interrupt-parent = <500>; - }; + //i2s@2400 { // PSC3 + // device_type = "sound"; + // compatible = "mpc5200-psc-i2s"; + // cell-index = <2>; + // reg = <2400 100>; + // interrupts = <2 3 0>; + // interrupt-parent = <500>; + //}; - // PSC4 unconfigured + // PSC4 in uart mode example //serial@2600 { // PSC4 // device_type = "serial"; - // compatible = "mpc5200-psc-uart\0mpc52xx-psc-uart"; + // compatible = "mpc5200-psc-uart"; + // cell-index = <3>; // reg = <2600 100>; // interrupts = <2 b 0>; // interrupt-parent = <500>; //}; - // PSC5 unconfigured + // PSC5 in uart mode example //serial@2800 { // PSC5 // device_type = "serial"; - // compatible = "mpc5200-psc-uart\0mpc52xx-psc-uart"; + // compatible = "mpc5200-psc-uart"; + // cell-index = <4>; // reg = <2800 100>; // interrupts = <2 c 0>; // interrupt-parent = <500>; //}; - // PSC6 in AC97 mode example - ac97@2c00 { // PSC6 - device_type = "sound"; - compatible = "mpc5200-psc-ac97\0mpc52xx-psc-ac97"; - reg = <2c00 100>; - interrupts = <2 4 0>; - interrupt-parent = <500>; - }; + // PSC6 in spi mode example + //spi@2c00 { // PSC6 + // device_type = "spi"; + // compatible = "mpc5200-psc-spi"; + // cell-index = <5>; + // reg = <2c00 100>; + // interrupts = <2 4 0>; + // interrupt-parent = <500>; + //}; ethernet@3000 { device_type = "network"; - compatible = "mpc5200-fec\0mpc52xx-fec"; + compatible = "mpc5200-fec"; reg = <3000 800>; mac-address = [ 02 03 04 05 06 07 ]; // Bad! interrupts = <2 5 0>; @@ -289,7 +310,7 @@ ata@3a00 { device_type = "ata"; - compatible = "mpc5200-ata\0mpc52xx-ata"; + compatible = "mpc5200-ata"; reg = <3a00 100>; interrupts = <2 7 0>; interrupt-parent = <500>; @@ -297,7 +318,8 @@ i2c@3d00 { device_type = "i2c"; - compatible = "mpc5200-i2c\0mpc52xx-i2c"; + compatible = "mpc5200-i2c"; + cell-index = <0>; reg = <3d00 40>; interrupts = <2 f 0>; interrupt-parent = <500>; @@ -305,14 +327,15 @@ i2c@3d40 { device_type = "i2c"; - compatible = "mpc5200-i2c\0mpc52xx-i2c"; + compatible = "mpc5200-i2c"; + cell-index = <1>; reg = <3d40 40>; interrupts = <2 10 0>; interrupt-parent = <500>; }; sram@8000 { device_type = "sram"; - compatible = "mpc5200-sram\0mpc52xx-sram\0sram"; + compatible = "mpc5200-sram\0sram"; reg = <8000 4000>; }; }; diff --git a/arch/powerpc/boot/dts/lite5200b.dts b/arch/powerpc/boot/dts/lite5200b.dts index 5bb2760..3875ca9 100644 --- a/arch/powerpc/boot/dts/lite5200b.dts +++ b/arch/powerpc/boot/dts/lite5200b.dts @@ -1,7 +1,7 @@ /* * Lite5200B board Device Tree Source * - * Copyright 2006 Secret Lab Technologies Ltd. + * Copyright 2006-2007 Secret Lab Technologies Ltd. * Grant Likely * * This program is free software; you can redistribute it and/or modify it @@ -17,8 +17,9 @@ */ / { - model = "Lite5200b"; - compatible = "lite5200b\0lite52xx\0mpc5200b\0mpc52xx"; + model = "fsl,lite5200b"; + // revision = "1.0"; + compatible = "fsl,lite5200b\0generic-mpc5200"; #address-cells = <1>; #size-cells = <1>; @@ -47,14 +48,17 @@ }; soc5200@f0000000 { + model = "fsl,mpc5200b"; + revision = ""; // from bootloader #interrupt-cells = <3>; device_type = "soc"; ranges = <0 f0000000 f0010000>; reg = ; bus-frequency = <0>; // from bootloader + system-frequency = <0>; // from bootloader cdm@200 { - compatible = "mpc5200b-cdm\0mpc52xx-cdm"; + compatible = "mpc5200b-cdm\0mpc5200-cdm"; reg = <200 38>; }; @@ -64,77 +68,86 @@ interrupt-controller; #interrupt-cells = <3>; device_type = "interrupt-controller"; - compatible = "mpc5200b-pic\0mpc52xx-pic"; + compatible = "mpc5200b-pic\0mpc5200-pic"; reg = <500 80>; built-in; }; gpt@600 { // General Purpose Timer - compatible = "mpc5200b-gpt\0mpc52xx-gpt"; + compatible = "mpc5200b-gpt\0mpc5200-gpt"; device_type = "gpt"; + cell-index = <0>; reg = <600 10>; interrupts = <1 9 0>; interrupt-parent = <500>; + has-wdt; }; gpt@610 { // General Purpose Timer - compatible = "mpc5200b-gpt\0mpc52xx-gpt"; + compatible = "mpc5200b-gpt\0mpc5200-gpt"; device_type = "gpt"; + cell-index = <1>; reg = <610 10>; interrupts = <1 a 0>; interrupt-parent = <500>; }; gpt@620 { // General Purpose Timer - compatible = "mpc5200b-gpt\0mpc52xx-gpt"; + compatible = "mpc5200b-gpt\0mpc5200-gpt"; device_type = "gpt"; + cell-index = <2>; reg = <620 10>; interrupts = <1 b 0>; interrupt-parent = <500>; }; gpt@630 { // General Purpose Timer - compatible = "mpc5200b-gpt\0mpc52xx-gpt"; + compatible = "mpc5200b-gpt\0mpc5200-gpt"; device_type = "gpt"; + cell-index = <3>; reg = <630 10>; interrupts = <1 c 0>; interrupt-parent = <500>; }; gpt@640 { // General Purpose Timer - compatible = "mpc5200b-gpt\0mpc52xx-gpt"; + compatible = "mpc5200b-gpt\0mpc5200-gpt"; device_type = "gpt"; + cell-index = <4>; reg = <640 10>; interrupts = <1 d 0>; interrupt-parent = <500>; }; gpt@650 { // General Purpose Timer - compatible = "mpc5200b-gpt\0mpc52xx-gpt"; + compatible = "mpc5200b-gpt\0mpc5200-gpt"; device_type = "gpt"; + cell-index = <5>; reg = <650 10>; interrupts = <1 e 0>; interrupt-parent = <500>; }; gpt@660 { // General Purpose Timer - compatible = "mpc5200b-gpt\0mpc52xx-gpt"; + compatible = "mpc5200b-gpt\0mpc5200-gpt"; device_type = "gpt"; + cell-index = <6>; reg = <660 10>; interrupts = <1 f 0>; interrupt-parent = <500>; }; gpt@670 { // General Purpose Timer - compatible = "mpc5200b-gpt\0mpc52xx-gpt"; + compatible = "mpc5200b-gpt\0mpc5200-gpt"; device_type = "gpt"; + cell-index = <7>; reg = <670 10>; interrupts = <1 10 0>; interrupt-parent = <500>; }; rtc@800 { // Real time clock - compatible = "mpc5200b-rtc\0mpc52xx-rtc"; + compatible = "mpc5200b-rtc\0mpc5200-rtc"; device_type = "rtc"; reg = <800 100>; interrupts = <1 5 0 1 6 0>; @@ -143,7 +156,8 @@ mscan@900 { device_type = "mscan"; - compatible = "mpc5200b-mscan\0mpc52xx-mscan"; + compatible = "mpc5200b-mscan\0mpc5200-mscan"; + cell-index = <0>; interrupts = <2 11 0>; interrupt-parent = <500>; reg = <900 80>; @@ -151,21 +165,22 @@ mscan@980 { device_type = "mscan"; - compatible = "mpc5200b-mscan\0mpc52xx-mscan"; + compatible = "mpc5200b-mscan\0mpc5200-mscan"; + cell-index = <1>; interrupts = <1 12 0>; interrupt-parent = <500>; reg = <980 80>; }; gpio@b00 { - compatible = "mpc5200b-gpio\0mpc52xx-gpio"; + compatible = "mpc5200b-gpio\0mpc5200-gpio"; reg = ; interrupts = <1 7 0>; interrupt-parent = <500>; }; gpio-wkup@b00 { - compatible = "mpc5200b-gpio-wkup\0mpc52xx-gpio-wkup"; + compatible = "mpc5200b-gpio-wkup\0mpc5200-gpio-wkup"; reg = ; interrupts = <1 8 0 0 3 0>; interrupt-parent = <500>; @@ -176,7 +191,7 @@ #size-cells = <2>; #address-cells = <3>; device_type = "pci"; - compatible = "mpc5200b-pci\0mpc52xx-pci"; + compatible = "mpc5200b-pci\0mpc5200-pci"; reg = ; interrupt-map-mask = ; interrupt-map = ; interrupts = <2 d 0 2 e 0>; interrupt-parent = <500>; @@ -207,7 +222,7 @@ usb@1000 { device_type = "usb-ohci-be"; - compatible = "mpc5200b-ohci\0mpc52xx-ohci\0ohci-be"; + compatible = "mpc5200b-ohci\0mpc5200-ohci\0ohci-be"; reg = <1000 ff>; interrupts = <2 6 0>; interrupt-parent = <500>; @@ -215,7 +230,7 @@ bestcomm@1200 { device_type = "dma-controller"; - compatible = "mpc5200b-bestcomm\0mpc52xx-bestcomm"; + compatible = "mpc5200b-bestcomm\0mpc5200-bestcomm"; reg = <1200 80>; interrupts = <3 0 0 3 1 0 3 2 0 3 3 0 3 4 0 3 5 0 3 6 0 3 7 0 @@ -225,67 +240,73 @@ }; xlb@1f00 { - compatible = "mpc5200b-xlb\0mpc52xx-xlb"; + compatible = "mpc5200b-xlb\0mpc5200-xlb"; reg = <1f00 100>; }; serial@2000 { // PSC1 device_type = "serial"; - compatible = "mpc5200b-psc-uart\0mpc52xx-psc-uart"; + compatible = "mpc5200b-psc-uart\0mpc5200-psc-uart"; port-number = <0>; // Logical port assignment + cell-index = <0>; reg = <2000 100>; interrupts = <2 1 0>; interrupt-parent = <500>; }; - // PSC2 in spi mode example - spi@2200 { // PSC2 - device_type = "spi"; - compatible = "mpc5200b-psc-spi\0mpc52xx-psc-spi"; - reg = <2200 100>; - interrupts = <2 2 0>; - interrupt-parent = <500>; - }; + // PSC2 in ac97 mode example + //ac97@2200 { // PSC2 + // device_type = "sound"; + // compatible = "mpc5200b-psc-ac97\0mpc5200-psc-ac97"; + // cell-index = <1>; + // reg = <2200 100>; + // interrupts = <2 2 0>; + // interrupt-parent = <500>; + //}; // PSC3 in CODEC mode example - i2s@2400 { // PSC3 - device_type = "sound"; - compatible = "mpc5200b-psc-i2s\0mpc52xx-psc-i2s"; - reg = <2400 100>; - interrupts = <2 3 0>; - interrupt-parent = <500>; - }; + //i2s@2400 { // PSC3 + // device_type = "sound"; + // compatible = "mpc5200b-psc-i2s"; //not 5200 compatible + // cell-index = <2>; + // reg = <2400 100>; + // interrupts = <2 3 0>; + // interrupt-parent = <500>; + //}; - // PSC4 unconfigured + // PSC4 in uart mode example //serial@2600 { // PSC4 // device_type = "serial"; - // compatible = "mpc5200b-psc-uart\0mpc52xx-psc-uart"; + // compatible = "mpc5200b-psc-uart\0mpc5200-psc-uart"; + // cell-index = <3>; // reg = <2600 100>; // interrupts = <2 b 0>; // interrupt-parent = <500>; //}; - // PSC5 unconfigured + // PSC5 in uart mode example //serial@2800 { // PSC5 // device_type = "serial"; - // compatible = "mpc5200b-psc-uart\0mpc52xx-psc-uart"; + // compatible = "mpc5200b-psc-uart\0mpc5200-psc-uart"; + // cell-index = <4>; // reg = <2800 100>; // interrupts = <2 c 0>; // interrupt-parent = <500>; //}; - // PSC6 in AC97 mode example - ac97@2c00 { // PSC6 - device_type = "sound"; - compatible = "mpc5200b-psc-ac97\0mpc52xx-psc-ac97"; - reg = <2c00 100>; - interrupts = <2 4 0>; - interrupt-parent = <500>; - }; + // PSC6 in spi mode example + //spi@2c00 { // PSC6 + // device_type = "spi"; + // compatible = "mpc5200b-psc-spi\0mpc5200-psc-spi"; + // cell-index = <5>; + // reg = <2c00 100>; + // interrupts = <2 4 0>; + // interrupt-parent = <500>; + //}; ethernet@3000 { device_type = "network"; - compatible = "mpc5200b-fec\0mpc52xx-fec"; + compatible = "mpc5200b-fec\0mpc5200-fec"; reg = <3000 800>; mac-address = [ 02 03 04 05 06 07 ]; // Bad! interrupts = <2 5 0>; @@ -294,7 +315,7 @@ ata@3a00 { device_type = "ata"; - compatible = "mpc5200b-ata\0mpc52xx-ata"; + compatible = "mpc5200b-ata\0mpc5200-ata"; reg = <3a00 100>; interrupts = <2 7 0>; interrupt-parent = <500>; @@ -302,7 +323,8 @@ i2c@3d00 { device_type = "i2c"; - compatible = "mpc5200b-i2c\0mpc52xx-i2c"; + compatible = "mpc5200b-i2c\0mpc5200-i2c"; + cell-index = <0>; reg = <3d00 40>; interrupts = <2 f 0>; interrupt-parent = <500>; @@ -310,14 +332,15 @@ i2c@3d40 { device_type = "i2c"; - compatible = "mpc5200b-i2c\0mpc52xx-i2c"; + compatible = "mpc5200b-i2c\0mpc5200-i2c"; + cell-index = <1>; reg = <3d40 40>; interrupts = <2 10 0>; interrupt-parent = <500>; }; sram@8000 { device_type = "sram"; - compatible = "mpc5200b-sram\0mpc52xx-sram\0sram"; + compatible = "mpc5200b-sram\0mpc5200-sram\0sram"; reg = <8000 4000>; }; }; diff --git a/arch/powerpc/boot/dts/mpc8272ads.dts b/arch/powerpc/boot/dts/mpc8272ads.dts index 34efdd0..26b44f7 100644 --- a/arch/powerpc/boot/dts/mpc8272ads.dts +++ b/arch/powerpc/boot/dts/mpc8272ads.dts @@ -53,13 +53,20 @@ reg = <00000000 4000000 f4500000 00000020>; }; + chosen { + name = "chosen"; + linux,platform = <0>; + interrupt-controller = <10c00>; + linux,phandle = <400>; + }; + soc8272@f0000000 { #address-cells = <1>; #size-cells = <1>; #interrupt-cells = <2>; device_type = "soc"; - ranges = < 0 0 2 00000000 f0000000 00053000>; - reg = ; + ranges = <00000000 f0000000 00053000>; + reg = ; mdio@0 { device_type = "mdio"; @@ -71,7 +78,7 @@ ethernet-phy@0 { linux,phandle = <2452000>; interrupt-parent = <10c00>; - interrupts = <19 1>; + interrupts = <17 4>; reg = <0>; bitbang = [ 12 12 13 02 02 01 ]; device_type = "ethernet-phy"; @@ -79,7 +86,7 @@ ethernet-phy@1 { linux,phandle = <2452001>; interrupt-parent = <10c00>; - interrupts = <19 1>; + interrupts = <17 4>; bitbang = [ 12 12 13 02 02 01 ]; reg = <3>; device_type = "ethernet-phy"; @@ -90,7 +97,7 @@ #address-cells = <1>; #size-cells = <0>; device_type = "network"; - device-id = <2>; + device-id = <1>; compatible = "fs_enet"; model = "FCC"; reg = <11300 20 8400 100 11380 30>; @@ -104,7 +111,7 @@ ethernet@25000 { device_type = "network"; - device-id = <3>; + device-id = <2>; compatible = "fs_enet"; model = "FCC"; reg = <11320 20 8500 100 113b0 30>; @@ -123,8 +130,8 @@ #interrupt-cells = <2>; device_type = "cpm"; model = "CPM2"; - ranges = <00000000 00000000 3ffff>; - reg = <10d80 3280>; + ranges = <00000000 00000000 20000>; + reg = <0 20000>; command-proc = <119c0>; brg-frequency = <17D7840>; cpm_clk = ; @@ -133,7 +140,7 @@ device_type = "serial"; compatible = "cpm_uart"; model = "SCC"; - device-id = <2>; + device-id = <1>; reg = <11a00 20 8000 100>; current-speed = <1c200>; interrupts = <28 2>; @@ -147,7 +154,7 @@ device_type = "serial"; compatible = "cpm_uart"; model = "SCC"; - device-id = <5>; + device-id = <4>; reg = <11a60 20 8300 100>; current-speed = <1c200>; interrupts = <2b 2>; @@ -181,24 +188,24 @@ interrupt-map = < /* IDSEL 0x16 */ - b000 0 0 1 f8200000 40 0 - b000 0 0 2 f8200000 41 0 - b000 0 0 3 f8200000 42 0 - b000 0 0 4 f8200000 43 0 + b000 0 0 1 f8200000 40 8 + b000 0 0 2 f8200000 41 8 + b000 0 0 3 f8200000 42 8 + b000 0 0 4 f8200000 43 8 /* IDSEL 0x17 */ - b800 0 0 1 f8200000 43 0 - b800 0 0 2 f8200000 40 0 - b800 0 0 3 f8200000 41 0 - b800 0 0 4 f8200000 42 0 + b800 0 0 1 f8200000 43 8 + b800 0 0 2 f8200000 40 8 + b800 0 0 3 f8200000 41 8 + b800 0 0 4 f8200000 42 8 /* IDSEL 0x18 */ - c000 0 0 1 f8200000 42 0 - c000 0 0 2 f8200000 43 0 - c000 0 0 3 f8200000 40 0 - c000 0 0 4 f8200000 41 0>; + c000 0 0 1 f8200000 42 8 + c000 0 0 2 f8200000 43 8 + c000 0 0 3 f8200000 40 8 + c000 0 0 4 f8200000 41 8>; interrupt-parent = <10c00>; - interrupts = <14 3>; + interrupts = <14 8>; bus-range = <0 0>; ranges = <02000000 0 80000000 80000000 0 40000000 01000000 0 00000000 f6000000 0 02000000>; @@ -210,7 +217,7 @@ model = "SEC2"; compatible = "talitos"; reg = <30000 10000>; - interrupts = ; + interrupts = ; interrupt-parent = <10c00>; num-channels = <4>; channel-fifo-len = <18>; diff --git a/arch/powerpc/boot/dts/mpc8313erdb.dts b/arch/powerpc/boot/dts/mpc8313erdb.dts new file mode 100644 index 0000000..3d2f5a0 --- /dev/null +++ b/arch/powerpc/boot/dts/mpc8313erdb.dts @@ -0,0 +1,219 @@ +/* + * MPC8313E RDB Device Tree Source + * + * Copyright 2005, 2006, 2007 Freescale Semiconductor Inc. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + */ + +/ { + model = "MPC8313ERDB"; + compatible = "MPC83xx"; + #address-cells = <1>; + #size-cells = <1>; + + cpus { + #cpus = <1>; + #address-cells = <1>; + #size-cells = <0>; + + PowerPC,8313@0 { + device_type = "cpu"; + reg = <0>; + d-cache-line-size = <20>; // 32 bytes + i-cache-line-size = <20>; // 32 bytes + d-cache-size = <4000>; // L1, 16K + i-cache-size = <4000>; // L1, 16K + timebase-frequency = <0>; // from bootloader + bus-frequency = <0>; // from bootloader + clock-frequency = <0>; // from bootloader + 32-bit; + }; + }; + + memory { + device_type = "memory"; + reg = <00000000 08000000>; // 128MB at 0 + }; + + soc8313@e0000000 { + #address-cells = <1>; + #size-cells = <1>; + #interrupt-cells = <2>; + device_type = "soc"; + ranges = <0 e0000000 00100000>; + reg = ; + bus-frequency = <0>; + + wdt@200 { + device_type = "watchdog"; + compatible = "mpc83xx_wdt"; + reg = <200 100>; + }; + + i2c@3000 { + device_type = "i2c"; + compatible = "fsl-i2c"; + reg = <3000 100>; + interrupts = ; + interrupt-parent = <700>; + dfsrr; + }; + + i2c@3100 { + device_type = "i2c"; + compatible = "fsl-i2c"; + reg = <3100 100>; + interrupts = ; + interrupt-parent = <700>; + dfsrr; + }; + + spi@7000 { + device_type = "spi"; + compatible = "mpc83xx_spi"; + reg = <7000 1000>; + interrupts = <10 8>; + interrupt-parent = <700>; + mode = <0>; + }; + + /* phy type (ULPI, UTMI, UTMI_WIDE, SERIAL) */ + usb@23000 { + device_type = "usb"; + compatible = "fsl-usb2-dr"; + reg = <23000 1000>; + #address-cells = <1>; + #size-cells = <0>; + interrupt-parent = <700>; + interrupts = <26 2>; + phy_type = "utmi_wide"; + }; + + mdio@24520 { + device_type = "mdio"; + compatible = "gianfar"; + reg = <24520 20>; + #address-cells = <1>; + #size-cells = <0>; + linux,phandle = <24520>; + ethernet-phy@1 { + linux,phandle = <2452001>; + interrupt-parent = <700>; + interrupts = <13 2>; + reg = <1>; + device_type = "ethernet-phy"; + }; + ethernet-phy@4 { + linux,phandle = <2452004>; + interrupt-parent = <700>; + interrupts = <14 2>; + reg = <4>; + device_type = "ethernet-phy"; + }; + }; + + ethernet@24000 { + device_type = "network"; + model = "eTSEC"; + compatible = "gianfar"; + reg = <24000 1000>; + local-mac-address = [ 00 00 00 00 00 00 ]; + interrupts = <25 8 24 8 23 8>; + interrupt-parent = <700>; + phy-handle = <2452001>; + }; + + ethernet@25000 { + device_type = "network"; + model = "eTSEC"; + compatible = "gianfar"; + reg = <25000 1000>; + local-mac-address = [ 00 00 00 00 00 00 ]; + interrupts = <22 8 21 8 20 8>; + interrupt-parent = <700>; + phy-handle = <2452004>; + }; + + serial@4500 { + device_type = "serial"; + compatible = "ns16550"; + reg = <4500 100>; + clock-frequency = <0>; + interrupts = <9 8>; + interrupt-parent = <700>; + }; + + serial@4600 { + device_type = "serial"; + compatible = "ns16550"; + reg = <4600 100>; + clock-frequency = <0>; + interrupts = ; + interrupt-parent = <700>; + }; + + pci@8500 { + interrupt-map-mask = ; + interrupt-map = < + + /* IDSEL 0x0E -mini PCI */ + 7000 0 0 1 700 12 8 + 7000 0 0 2 700 12 8 + 7000 0 0 3 700 12 8 + 7000 0 0 4 700 12 8 + + /* IDSEL 0x0F - PCI slot */ + 7800 0 0 1 700 11 8 + 7800 0 0 2 700 12 8 + 7800 0 0 3 700 11 8 + 7800 0 0 4 700 12 8>; + interrupt-parent = <700>; + interrupts = <42 8>; + bus-range = <0 0>; + ranges = <02000000 0 90000000 90000000 0 10000000 + 42000000 0 80000000 80000000 0 10000000 + 01000000 0 00000000 e2000000 0 00100000>; + clock-frequency = <3f940aa>; + #interrupt-cells = <1>; + #size-cells = <2>; + #address-cells = <3>; + reg = <8500 100>; + compatible = "83xx"; + device_type = "pci"; + }; + + crypto@30000 { + device_type = "crypto"; + model = "SEC2"; + compatible = "talitos"; + reg = <30000 7000>; + interrupts = ; + interrupt-parent = <700>; + /* Rev. 2.2 */ + num-channels = <1>; + channel-fifo-len = <18>; + exec-units-mask = <0000004c>; + descriptor-types-mask = <0122003f>; + }; + + /* IPIC + * interrupts cell = + * sense values match linux IORESOURCE_IRQ_* defines: + * sense == 8: Level, low assertion + * sense == 2: Edge, high-to-low change + */ + pic@700 { + linux,phandle = <700>; + interrupt-controller; + #address-cells = <0>; + #interrupt-cells = <2>; + reg = <700 100>; + built-in; + device_type = "ipic"; + }; + }; +}; diff --git a/arch/powerpc/boot/dts/mpc8323emds.dts b/arch/powerpc/boot/dts/mpc8323emds.dts new file mode 100644 index 0000000..fa7ef24 --- /dev/null +++ b/arch/powerpc/boot/dts/mpc8323emds.dts @@ -0,0 +1,345 @@ +/* + * MPC8323E EMDS Device Tree Source + * + * Copyright 2006 Freescale Semiconductor Inc. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + */ + +/ { + model = "MPC8323EMDS"; + compatible = "MPC83xx"; + #address-cells = <1>; + #size-cells = <1>; + linux,phandle = <100>; + + cpus { + #cpus = <1>; + #address-cells = <1>; + #size-cells = <0>; + linux,phandle = <200>; + + PowerPC,8323@0 { + device_type = "cpu"; + reg = <0>; + d-cache-line-size = <20>; // 32 bytes + i-cache-line-size = <20>; // 32 bytes + d-cache-size = <4000>; // L1, 16K + i-cache-size = <4000>; // L1, 16K + timebase-frequency = <0>; + bus-frequency = <0>; + clock-frequency = <0>; + 32-bit; + linux,phandle = <201>; + linux,boot-cpu; + }; + }; + + memory { + device_type = "memory"; + linux,phandle = <300>; + reg = <00000000 08000000>; + }; + + bcsr@f8000000 { + device_type = "board-control"; + reg = ; + }; + + soc8323@e0000000 { + #address-cells = <1>; + #size-cells = <1>; + #interrupt-cells = <2>; + device_type = "soc"; + ranges = <0 e0000000 00100000>; + reg = ; + bus-frequency = <7DE2900>; + + wdt@200 { + device_type = "watchdog"; + compatible = "mpc83xx_wdt"; + reg = <200 100>; + }; + + i2c@3000 { + device_type = "i2c"; + compatible = "fsl-i2c"; + reg = <3000 100>; + interrupts = ; + interrupt-parent = <700>; + dfsrr; + }; + + serial@4500 { + device_type = "serial"; + compatible = "ns16550"; + reg = <4500 100>; + clock-frequency = <0>; + interrupts = <9 8>; + interrupt-parent = <700>; + }; + + serial@4600 { + device_type = "serial"; + compatible = "ns16550"; + reg = <4600 100>; + clock-frequency = <0>; + interrupts = ; + interrupt-parent = <700>; + }; + + crypto@30000 { + device_type = "crypto"; + model = "SEC2"; + compatible = "talitos"; + reg = <30000 7000>; + interrupts = ; + interrupt-parent = <700>; + /* Rev. 2.2 */ + num-channels = <1>; + channel-fifo-len = <18>; + exec-units-mask = <0000004c>; + descriptor-types-mask = <0122003f>; + }; + + pci@8500 { + linux,phandle = <8500>; + interrupt-map-mask = ; + interrupt-map = < + /* IDSEL 0x11 AD17 */ + 8800 0 0 1 700 14 8 + 8800 0 0 2 700 15 8 + 8800 0 0 3 700 16 8 + 8800 0 0 4 700 17 8 + + /* IDSEL 0x12 AD18 */ + 9000 0 0 1 700 16 8 + 9000 0 0 2 700 17 8 + 9000 0 0 3 700 14 8 + 9000 0 0 4 700 15 8 + + /* IDSEL 0x13 AD19 */ + 9800 0 0 1 700 17 8 + 9800 0 0 2 700 14 8 + 9800 0 0 3 700 15 8 + 9800 0 0 4 700 16 8 + + /* IDSEL 0x15 AD21*/ + a800 0 0 1 700 14 8 + a800 0 0 2 700 15 8 + a800 0 0 3 700 16 8 + a800 0 0 4 700 17 8 + + /* IDSEL 0x16 AD22*/ + b000 0 0 1 700 17 8 + b000 0 0 2 700 14 8 + b000 0 0 3 700 15 8 + b000 0 0 4 700 16 8 + + /* IDSEL 0x17 AD23*/ + b800 0 0 1 700 16 8 + b800 0 0 2 700 17 8 + b800 0 0 3 700 14 8 + b800 0 0 4 700 15 8 + + /* IDSEL 0x18 AD24*/ + c000 0 0 1 700 15 8 + c000 0 0 2 700 16 8 + c000 0 0 3 700 17 8 + c000 0 0 4 700 14 8>; + interrupt-parent = <700>; + interrupts = <42 8>; + bus-range = <0 0>; + ranges = <02000000 0 a0000000 90000000 0 10000000 + 42000000 0 80000000 80000000 0 10000000 + 01000000 0 00000000 d0000000 0 00100000>; + clock-frequency = <0>; + #interrupt-cells = <1>; + #size-cells = <2>; + #address-cells = <3>; + reg = <8500 100>; + compatible = "83xx"; + device_type = "pci"; + }; + + pic@700 { + linux,phandle = <700>; + interrupt-controller; + #address-cells = <0>; + #interrupt-cells = <2>; + reg = <700 100>; + built-in; + device_type = "ipic"; + }; + + par_io@1400 { + reg = <1400 100>; + device_type = "par_io"; + num-ports = <7>; + + ucc_pin@03 { + linux,phandle = <140003>; + pio-map = < + /* port pin dir open_drain assignment has_irq */ + 3 4 3 0 2 0 /* MDIO */ + 3 5 1 0 2 0 /* MDC */ + 0 d 2 0 1 0 /* RX_CLK (CLK9) */ + 3 18 2 0 1 0 /* TX_CLK (CLK10) */ + 1 1 1 0 1 0 /* TxD1 */ + 1 0 1 0 1 0 /* TxD0 */ + 1 1 1 0 1 0 /* TxD1 */ + 1 2 1 0 1 0 /* TxD2 */ + 1 3 1 0 1 0 /* TxD3 */ + 1 4 2 0 1 0 /* RxD0 */ + 1 5 2 0 1 0 /* RxD1 */ + 1 6 2 0 1 0 /* RxD2 */ + 1 7 2 0 1 0 /* RxD3 */ + 1 8 2 0 1 0 /* RX_ER */ + 1 9 1 0 1 0 /* TX_ER */ + 1 a 2 0 1 0 /* RX_DV */ + 1 b 2 0 1 0 /* COL */ + 1 c 1 0 1 0 /* TX_EN */ + 1 d 2 0 1 0>;/* CRS */ + }; + ucc_pin@04 { + linux,phandle = <140004>; + pio-map = < + /* port pin dir open_drain assignment has_irq */ + 3 1f 2 0 1 0 /* RX_CLK (CLK7) */ + 3 6 2 0 1 0 /* TX_CLK (CLK8) */ + 1 12 1 0 1 0 /* TxD0 */ + 1 13 1 0 1 0 /* TxD1 */ + 1 14 1 0 1 0 /* TxD2 */ + 1 15 1 0 1 0 /* TxD3 */ + 1 16 2 0 1 0 /* RxD0 */ + 1 17 2 0 1 0 /* RxD1 */ + 1 18 2 0 1 0 /* RxD2 */ + 1 19 2 0 1 0 /* RxD3 */ + 1 1a 2 0 1 0 /* RX_ER */ + 1 1b 1 0 1 0 /* TX_ER */ + 1 1c 2 0 1 0 /* RX_DV */ + 1 1d 2 0 1 0 /* COL */ + 1 1e 1 0 1 0 /* TX_EN */ + 1 1f 2 0 1 0>;/* CRS */ + }; + }; + }; + + qe@e0100000 { + #address-cells = <1>; + #size-cells = <1>; + device_type = "qe"; + model = "QE"; + ranges = <0 e0100000 00100000>; + reg = ; + brg-frequency = <0>; + bus-frequency = ; + + muram@10000 { + device_type = "muram"; + ranges = <0 00010000 00004000>; + + data-only@0 { + reg = <0 4000>; + }; + }; + + spi@4c0 { + device_type = "spi"; + compatible = "fsl_spi"; + reg = <4c0 40>; + interrupts = <2>; + interrupt-parent = <80>; + mode = "cpu"; + }; + + spi@500 { + device_type = "spi"; + compatible = "fsl_spi"; + reg = <500 40>; + interrupts = <1>; + interrupt-parent = <80>; + mode = "cpu"; + }; + + usb@6c0 { + device_type = "usb"; + compatible = "qe_udc"; + reg = <6c0 40 8B00 100>; + interrupts = ; + interrupt-parent = <80>; + mode = "slave"; + }; + + ucc@2200 { + device_type = "network"; + compatible = "ucc_geth"; + model = "UCC"; + device-id = <3>; + reg = <2200 200>; + interrupts = <22>; + interrupt-parent = <80>; + mac-address = [ 00 04 9f 00 23 23 ]; + rx-clock = <19>; + tx-clock = <1a>; + phy-handle = <212003>; + pio-handle = <140003>; + }; + + ucc@3200 { + device_type = "network"; + compatible = "ucc_geth"; + model = "UCC"; + device-id = <4>; + reg = <3000 200>; + interrupts = <23>; + interrupt-parent = <80>; + mac-address = [ 00 11 22 33 44 55 ]; + rx-clock = <17>; + tx-clock = <18>; + phy-handle = <212004>; + pio-handle = <140004>; + }; + + mdio@2320 { + #address-cells = <1>; + #size-cells = <0>; + reg = <2320 18>; + device_type = "mdio"; + compatible = "ucc_geth_phy"; + + ethernet-phy@03 { + linux,phandle = <212003>; + interrupt-parent = <700>; + interrupts = <11 2>; + reg = <3>; + device_type = "ethernet-phy"; + interface = <3>; //ENET_100_MII + }; + ethernet-phy@04 { + linux,phandle = <212004>; + interrupt-parent = <700>; + interrupts = <12 2>; + reg = <4>; + device_type = "ethernet-phy"; + interface = <3>; + }; + }; + + qeic@80 { + linux,phandle = <80>; + interrupt-controller; + device_type = "qeic"; + #address-cells = <0>; + #interrupt-cells = <1>; + reg = <80 80>; + built-in; + big-endian; + interrupts = <20 8 21 8>; //high:32 low:33 + interrupt-parent = <700>; + }; + }; +}; diff --git a/arch/powerpc/boot/dts/mpc8349emds.dts b/arch/powerpc/boot/dts/mpc8349emds.dts deleted file mode 100644 index efceb34..0000000 --- a/arch/powerpc/boot/dts/mpc8349emds.dts +++ /dev/null @@ -1,328 +0,0 @@ -/* - * MPC8349E MDS Device Tree Source - * - * Copyright 2005, 2006 Freescale Semiconductor Inc. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. - */ - -/ { - model = "MPC8349EMDS"; - compatible = "MPC834xMDS"; - #address-cells = <1>; - #size-cells = <1>; - - cpus { - #cpus = <1>; - #address-cells = <1>; - #size-cells = <0>; - - PowerPC,8349@0 { - device_type = "cpu"; - reg = <0>; - d-cache-line-size = <20>; // 32 bytes - i-cache-line-size = <20>; // 32 bytes - d-cache-size = <8000>; // L1, 32K - i-cache-size = <8000>; // L1, 32K - timebase-frequency = <0>; // from bootloader - bus-frequency = <0>; // from bootloader - clock-frequency = <0>; // from bootloader - 32-bit; - }; - }; - - memory { - device_type = "memory"; - reg = <00000000 10000000>; // 256MB at 0 - }; - - soc8349@e0000000 { - #address-cells = <1>; - #size-cells = <1>; - #interrupt-cells = <2>; - device_type = "soc"; - ranges = <0 e0000000 00100000>; - reg = ; - bus-frequency = <0>; - - wdt@200 { - device_type = "watchdog"; - compatible = "mpc83xx_wdt"; - reg = <200 100>; - }; - - i2c@3000 { - device_type = "i2c"; - compatible = "fsl-i2c"; - reg = <3000 100>; - interrupts = ; - interrupt-parent = <700>; - dfsrr; - }; - - i2c@3100 { - device_type = "i2c"; - compatible = "fsl-i2c"; - reg = <3100 100>; - interrupts = ; - interrupt-parent = <700>; - dfsrr; - }; - - spi@7000 { - device_type = "spi"; - compatible = "mpc83xx_spi"; - reg = <7000 1000>; - interrupts = <10 8>; - interrupt-parent = <700>; - mode = <0>; - }; - - /* phy type (ULPI or SERIAL) are only types supportted for MPH */ - /* port = 0 or 1 */ - usb@22000 { - device_type = "usb"; - compatible = "fsl-usb2-mph"; - reg = <22000 1000>; - #address-cells = <1>; - #size-cells = <0>; - interrupt-parent = <700>; - interrupts = <27 2>; - phy_type = "ulpi"; - port1; - }; - /* phy type (ULPI, UTMI, UTMI_WIDE, SERIAL) */ - usb@23000 { - device_type = "usb"; - compatible = "fsl-usb2-dr"; - reg = <23000 1000>; - #address-cells = <1>; - #size-cells = <0>; - interrupt-parent = <700>; - interrupts = <26 2>; - phy_type = "ulpi"; - }; - - mdio@24520 { - device_type = "mdio"; - compatible = "gianfar"; - reg = <24520 20>; - #address-cells = <1>; - #size-cells = <0>; - linux,phandle = <24520>; - ethernet-phy@0 { - linux,phandle = <2452000>; - interrupt-parent = <700>; - interrupts = <11 2>; - reg = <0>; - device_type = "ethernet-phy"; - }; - ethernet-phy@1 { - linux,phandle = <2452001>; - interrupt-parent = <700>; - interrupts = <12 2>; - reg = <1>; - device_type = "ethernet-phy"; - }; - }; - - ethernet@24000 { - device_type = "network"; - model = "TSEC"; - compatible = "gianfar"; - reg = <24000 1000>; - address = [ 00 00 00 00 00 00 ]; - local-mac-address = [ 00 00 00 00 00 00 ]; - interrupts = <20 8 21 8 22 8>; - interrupt-parent = <700>; - phy-handle = <2452000>; - }; - - ethernet@25000 { - #address-cells = <1>; - #size-cells = <0>; - device_type = "network"; - model = "TSEC"; - compatible = "gianfar"; - reg = <25000 1000>; - address = [ 00 00 00 00 00 00 ]; - local-mac-address = [ 00 00 00 00 00 00 ]; - interrupts = <23 8 24 8 25 8>; - interrupt-parent = <700>; - phy-handle = <2452001>; - }; - - serial@4500 { - device_type = "serial"; - compatible = "ns16550"; - reg = <4500 100>; - clock-frequency = <0>; - interrupts = <9 8>; - interrupt-parent = <700>; - }; - - serial@4600 { - device_type = "serial"; - compatible = "ns16550"; - reg = <4600 100>; - clock-frequency = <0>; - interrupts = ; - interrupt-parent = <700>; - }; - - pci@8500 { - interrupt-map-mask = ; - interrupt-map = < - - /* IDSEL 0x11 */ - 8800 0 0 1 700 14 8 - 8800 0 0 2 700 15 8 - 8800 0 0 3 700 16 8 - 8800 0 0 4 700 17 8 - - /* IDSEL 0x12 */ - 9000 0 0 1 700 16 8 - 9000 0 0 2 700 17 8 - 9000 0 0 3 700 14 8 - 9000 0 0 4 700 15 8 - - /* IDSEL 0x13 */ - 9800 0 0 1 700 17 8 - 9800 0 0 2 700 14 8 - 9800 0 0 3 700 15 8 - 9800 0 0 4 700 16 8 - - /* IDSEL 0x15 */ - a800 0 0 1 700 14 8 - a800 0 0 2 700 15 8 - a800 0 0 3 700 16 8 - a800 0 0 4 700 17 8 - - /* IDSEL 0x16 */ - b000 0 0 1 700 17 8 - b000 0 0 2 700 14 8 - b000 0 0 3 700 15 8 - b000 0 0 4 700 16 8 - - /* IDSEL 0x17 */ - b800 0 0 1 700 16 8 - b800 0 0 2 700 17 8 - b800 0 0 3 700 14 8 - b800 0 0 4 700 15 8 - - /* IDSEL 0x18 */ - c000 0 0 1 700 15 8 - c000 0 0 2 700 16 8 - c000 0 0 3 700 17 8 - c000 0 0 4 700 14 8>; - interrupt-parent = <700>; - interrupts = <42 8>; - bus-range = <0 0>; - ranges = <02000000 0 a0000000 a0000000 0 10000000 - 42000000 0 80000000 80000000 0 10000000 - 01000000 0 00000000 e2000000 0 00100000>; - clock-frequency = <3f940aa>; - #interrupt-cells = <1>; - #size-cells = <2>; - #address-cells = <3>; - reg = <8500 100>; - compatible = "83xx"; - device_type = "pci"; - }; - - pci@8600 { - interrupt-map-mask = ; - interrupt-map = < - - /* IDSEL 0x11 */ - 8800 0 0 1 700 14 8 - 8800 0 0 2 700 15 8 - 8800 0 0 3 700 16 8 - 8800 0 0 4 700 17 8 - - /* IDSEL 0x12 */ - 9000 0 0 1 700 16 8 - 9000 0 0 2 700 17 8 - 9000 0 0 3 700 14 8 - 9000 0 0 4 700 15 8 - - /* IDSEL 0x13 */ - 9800 0 0 1 700 17 8 - 9800 0 0 2 700 14 8 - 9800 0 0 3 700 15 8 - 9800 0 0 4 700 16 8 - - /* IDSEL 0x15 */ - a800 0 0 1 700 14 8 - a800 0 0 2 700 15 8 - a800 0 0 3 700 16 8 - a800 0 0 4 700 17 8 - - /* IDSEL 0x16 */ - b000 0 0 1 700 17 8 - b000 0 0 2 700 14 8 - b000 0 0 3 700 15 8 - b000 0 0 4 700 16 8 - - /* IDSEL 0x17 */ - b800 0 0 1 700 16 8 - b800 0 0 2 700 17 8 - b800 0 0 3 700 14 8 - b800 0 0 4 700 15 8 - - /* IDSEL 0x18 */ - c000 0 0 1 700 15 8 - c000 0 0 2 700 16 8 - c000 0 0 3 700 17 8 - c000 0 0 4 700 14 8>; - interrupt-parent = <700>; - interrupts = <42 8>; - bus-range = <0 0>; - ranges = <02000000 0 b0000000 b0000000 0 10000000 - 42000000 0 90000000 90000000 0 10000000 - 01000000 0 00000000 e2100000 0 00100000>; - clock-frequency = <3f940aa>; - #interrupt-cells = <1>; - #size-cells = <2>; - #address-cells = <3>; - reg = <8600 100>; - compatible = "83xx"; - device_type = "pci"; - }; - - /* May need to remove if on a part without crypto engine */ - crypto@30000 { - device_type = "crypto"; - model = "SEC2"; - compatible = "talitos"; - reg = <30000 10000>; - interrupts = ; - interrupt-parent = <700>; - num-channels = <4>; - channel-fifo-len = <18>; - exec-units-mask = <0000007e>; - /* desc mask is for rev2.0, - * we need runtime fixup for >2.0 */ - descriptor-types-mask = <01010ebf>; - }; - - /* IPIC - * interrupts cell = - * sense values match linux IORESOURCE_IRQ_* defines: - * sense == 8: Level, low assertion - * sense == 2: Edge, high-to-low change - */ - pic@700 { - linux,phandle = <700>; - interrupt-controller; - #address-cells = <0>; - #interrupt-cells = <2>; - reg = <700 100>; - built-in; - device_type = "ipic"; - }; - }; -}; diff --git a/arch/powerpc/boot/dts/mpc8349emitxgp.dts b/arch/powerpc/boot/dts/mpc8349emitxgp.dts new file mode 100644 index 0000000..3190774 --- /dev/null +++ b/arch/powerpc/boot/dts/mpc8349emitxgp.dts @@ -0,0 +1,187 @@ +/* + * MPC8349E-mITX-GP Device Tree Source + * + * Copyright 2007 Freescale Semiconductor Inc. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + */ +/ { + model = "MPC8349EMITXGP"; + compatible = "MPC834xMITXGP"; + #address-cells = <1>; + #size-cells = <1>; + + cpus { + #cpus = <1>; + #address-cells = <1>; + #size-cells = <0>; + + PowerPC,8349@0 { + device_type = "cpu"; + reg = <0>; + d-cache-line-size = <20>; + i-cache-line-size = <20>; + d-cache-size = <8000>; + i-cache-size = <8000>; + timebase-frequency = <0>; // from bootloader + bus-frequency = <0>; // from bootloader + clock-frequency = <0>; // from bootloader + 32-bit; + }; + }; + + memory { + device_type = "memory"; + reg = <00000000 10000000>; + }; + + soc8349@e0000000 { + #address-cells = <1>; + #size-cells = <1>; + #interrupt-cells = <2>; + device_type = "soc"; + ranges = <0 e0000000 00100000>; + reg = ; + bus-frequency = <0>; // from bootloader + + wdt@200 { + device_type = "watchdog"; + compatible = "mpc83xx_wdt"; + reg = <200 100>; + }; + + i2c@3000 { + device_type = "i2c"; + compatible = "fsl-i2c"; + reg = <3000 100>; + interrupts = ; + interrupt-parent = <700>; + dfsrr; + }; + + i2c@3100 { + device_type = "i2c"; + compatible = "fsl-i2c"; + reg = <3100 100>; + interrupts = ; + interrupt-parent = <700>; + dfsrr; + }; + + spi@7000 { + device_type = "spi"; + compatible = "mpc83xx_spi"; + reg = <7000 1000>; + interrupts = <10 8>; + interrupt-parent = <700>; + mode = <0>; + }; + + usb@23000 { + device_type = "usb"; + compatible = "fsl-usb2-dr"; + reg = <23000 1000>; + #address-cells = <1>; + #size-cells = <0>; + interrupt-parent = <700>; + interrupts = <26 2>; + dr_mode = "otg"; + phy_type = "ulpi"; + }; + + mdio@24520 { + device_type = "mdio"; + compatible = "gianfar"; + reg = <24520 20>; + #address-cells = <1>; + #size-cells = <0>; + linux,phandle = <24520>; + + /* Vitesse 8201 */ + ethernet-phy@1c { + linux,phandle = <245201c>; + interrupt-parent = <700>; + interrupts = <12 2>; + reg = <1c>; + device_type = "ethernet-phy"; + }; + }; + + ethernet@24000 { + device_type = "network"; + model = "TSEC"; + compatible = "gianfar"; + reg = <24000 1000>; + local-mac-address = [ 00 00 00 00 00 00 ]; + interrupts = <20 8 21 8 22 8>; + interrupt-parent = <700>; + phy-handle = <245201c>; + }; + + serial@4500 { + device_type = "serial"; + compatible = "ns16550"; + reg = <4500 100>; + clock-frequency = <0>; // from bootloader + interrupts = <9 8>; + interrupt-parent = <700>; + }; + + serial@4600 { + device_type = "serial"; + compatible = "ns16550"; + reg = <4600 100>; + clock-frequency = <0>; // from bootloader + interrupts = ; + interrupt-parent = <700>; + }; + + pci@8600 { + interrupt-map-mask = ; + interrupt-map = < + /* IDSEL 0x0F - PCI Slot */ + 7800 0 0 1 700 14 8 /* PCI_INTA */ + 7800 0 0 2 700 15 8 /* PCI_INTB */ + >; + interrupt-parent = <700>; + interrupts = <43 8>; + bus-range = <1 1>; + ranges = <42000000 0 a0000000 a0000000 0 10000000 + 02000000 0 b0000000 b0000000 0 10000000 + 01000000 0 00000000 e3000000 0 01000000>; + clock-frequency = <3f940aa>; + #interrupt-cells = <1>; + #size-cells = <2>; + #address-cells = <3>; + reg = <8600 100>; + compatible = "83xx"; + device_type = "pci"; + }; + + crypto@30000 { + device_type = "crypto"; + model = "SEC2"; + compatible = "talitos"; + reg = <30000 10000>; + interrupts = ; + interrupt-parent = <700>; + num-channels = <4>; + channel-fifo-len = <18>; + exec-units-mask = <0000007e>; + descriptor-types-mask = <01010ebf>; + }; + + pic@700 { + linux,phandle = <700>; + interrupt-controller; + #address-cells = <0>; + #interrupt-cells = <2>; + reg = <700 100>; + built-in; + device_type = "ipic"; + }; + }; +}; diff --git a/arch/powerpc/boot/dts/mpc834x_mds.dts b/arch/powerpc/boot/dts/mpc834x_mds.dts new file mode 100644 index 0000000..dc121b3 --- /dev/null +++ b/arch/powerpc/boot/dts/mpc834x_mds.dts @@ -0,0 +1,334 @@ +/* + * MPC8349E MDS Device Tree Source + * + * Copyright 2005, 2006 Freescale Semiconductor Inc. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + */ + +/ { + model = "MPC8349EMDS"; + compatible = "MPC834xMDS"; + #address-cells = <1>; + #size-cells = <1>; + + cpus { + #cpus = <1>; + #address-cells = <1>; + #size-cells = <0>; + + PowerPC,8349@0 { + device_type = "cpu"; + reg = <0>; + d-cache-line-size = <20>; // 32 bytes + i-cache-line-size = <20>; // 32 bytes + d-cache-size = <8000>; // L1, 32K + i-cache-size = <8000>; // L1, 32K + timebase-frequency = <0>; // from bootloader + bus-frequency = <0>; // from bootloader + clock-frequency = <0>; // from bootloader + 32-bit; + }; + }; + + memory { + device_type = "memory"; + reg = <00000000 10000000>; // 256MB at 0 + }; + + bcsr@e2400000 { + device_type = "board-control"; + reg = ; + }; + + soc8349@e0000000 { + #address-cells = <1>; + #size-cells = <1>; + #interrupt-cells = <2>; + device_type = "soc"; + ranges = <0 e0000000 00100000>; + reg = ; + bus-frequency = <0>; + + wdt@200 { + device_type = "watchdog"; + compatible = "mpc83xx_wdt"; + reg = <200 100>; + }; + + i2c@3000 { + device_type = "i2c"; + compatible = "fsl-i2c"; + reg = <3000 100>; + interrupts = ; + interrupt-parent = <700>; + dfsrr; + }; + + i2c@3100 { + device_type = "i2c"; + compatible = "fsl-i2c"; + reg = <3100 100>; + interrupts = ; + interrupt-parent = <700>; + dfsrr; + }; + + spi@7000 { + device_type = "spi"; + compatible = "mpc83xx_spi"; + reg = <7000 1000>; + interrupts = <10 8>; + interrupt-parent = <700>; + mode = <0>; + }; + + /* phy type (ULPI or SERIAL) are only types supportted for MPH */ + /* port = 0 or 1 */ + usb@22000 { + device_type = "usb"; + compatible = "fsl-usb2-mph"; + reg = <22000 1000>; + #address-cells = <1>; + #size-cells = <0>; + interrupt-parent = <700>; + interrupts = <27 2>; + phy_type = "ulpi"; + port1; + }; + /* phy type (ULPI, UTMI, UTMI_WIDE, SERIAL) */ + usb@23000 { + device_type = "usb"; + compatible = "fsl-usb2-dr"; + reg = <23000 1000>; + #address-cells = <1>; + #size-cells = <0>; + interrupt-parent = <700>; + interrupts = <26 2>; + dr_mode = "otg"; + phy_type = "ulpi"; + }; + + mdio@24520 { + device_type = "mdio"; + compatible = "gianfar"; + reg = <24520 20>; + #address-cells = <1>; + #size-cells = <0>; + linux,phandle = <24520>; + ethernet-phy@0 { + linux,phandle = <2452000>; + interrupt-parent = <700>; + interrupts = <11 2>; + reg = <0>; + device_type = "ethernet-phy"; + }; + ethernet-phy@1 { + linux,phandle = <2452001>; + interrupt-parent = <700>; + interrupts = <12 2>; + reg = <1>; + device_type = "ethernet-phy"; + }; + }; + + ethernet@24000 { + device_type = "network"; + model = "TSEC"; + compatible = "gianfar"; + reg = <24000 1000>; + address = [ 00 00 00 00 00 00 ]; + local-mac-address = [ 00 00 00 00 00 00 ]; + interrupts = <20 8 21 8 22 8>; + interrupt-parent = <700>; + phy-handle = <2452000>; + }; + + ethernet@25000 { + #address-cells = <1>; + #size-cells = <0>; + device_type = "network"; + model = "TSEC"; + compatible = "gianfar"; + reg = <25000 1000>; + address = [ 00 00 00 00 00 00 ]; + local-mac-address = [ 00 00 00 00 00 00 ]; + interrupts = <23 8 24 8 25 8>; + interrupt-parent = <700>; + phy-handle = <2452001>; + }; + + serial@4500 { + device_type = "serial"; + compatible = "ns16550"; + reg = <4500 100>; + clock-frequency = <0>; + interrupts = <9 8>; + interrupt-parent = <700>; + }; + + serial@4600 { + device_type = "serial"; + compatible = "ns16550"; + reg = <4600 100>; + clock-frequency = <0>; + interrupts = ; + interrupt-parent = <700>; + }; + + pci@8500 { + interrupt-map-mask = ; + interrupt-map = < + + /* IDSEL 0x11 */ + 8800 0 0 1 700 14 8 + 8800 0 0 2 700 15 8 + 8800 0 0 3 700 16 8 + 8800 0 0 4 700 17 8 + + /* IDSEL 0x12 */ + 9000 0 0 1 700 16 8 + 9000 0 0 2 700 17 8 + 9000 0 0 3 700 14 8 + 9000 0 0 4 700 15 8 + + /* IDSEL 0x13 */ + 9800 0 0 1 700 17 8 + 9800 0 0 2 700 14 8 + 9800 0 0 3 700 15 8 + 9800 0 0 4 700 16 8 + + /* IDSEL 0x15 */ + a800 0 0 1 700 14 8 + a800 0 0 2 700 15 8 + a800 0 0 3 700 16 8 + a800 0 0 4 700 17 8 + + /* IDSEL 0x16 */ + b000 0 0 1 700 17 8 + b000 0 0 2 700 14 8 + b000 0 0 3 700 15 8 + b000 0 0 4 700 16 8 + + /* IDSEL 0x17 */ + b800 0 0 1 700 16 8 + b800 0 0 2 700 17 8 + b800 0 0 3 700 14 8 + b800 0 0 4 700 15 8 + + /* IDSEL 0x18 */ + c000 0 0 1 700 15 8 + c000 0 0 2 700 16 8 + c000 0 0 3 700 17 8 + c000 0 0 4 700 14 8>; + interrupt-parent = <700>; + interrupts = <42 8>; + bus-range = <0 0>; + ranges = <02000000 0 a0000000 a0000000 0 10000000 + 42000000 0 80000000 80000000 0 10000000 + 01000000 0 00000000 e2000000 0 00100000>; + clock-frequency = <3f940aa>; + #interrupt-cells = <1>; + #size-cells = <2>; + #address-cells = <3>; + reg = <8500 100>; + compatible = "83xx"; + device_type = "pci"; + }; + + pci@8600 { + interrupt-map-mask = ; + interrupt-map = < + + /* IDSEL 0x11 */ + 8800 0 0 1 700 14 8 + 8800 0 0 2 700 15 8 + 8800 0 0 3 700 16 8 + 8800 0 0 4 700 17 8 + + /* IDSEL 0x12 */ + 9000 0 0 1 700 16 8 + 9000 0 0 2 700 17 8 + 9000 0 0 3 700 14 8 + 9000 0 0 4 700 15 8 + + /* IDSEL 0x13 */ + 9800 0 0 1 700 17 8 + 9800 0 0 2 700 14 8 + 9800 0 0 3 700 15 8 + 9800 0 0 4 700 16 8 + + /* IDSEL 0x15 */ + a800 0 0 1 700 14 8 + a800 0 0 2 700 15 8 + a800 0 0 3 700 16 8 + a800 0 0 4 700 17 8 + + /* IDSEL 0x16 */ + b000 0 0 1 700 17 8 + b000 0 0 2 700 14 8 + b000 0 0 3 700 15 8 + b000 0 0 4 700 16 8 + + /* IDSEL 0x17 */ + b800 0 0 1 700 16 8 + b800 0 0 2 700 17 8 + b800 0 0 3 700 14 8 + b800 0 0 4 700 15 8 + + /* IDSEL 0x18 */ + c000 0 0 1 700 15 8 + c000 0 0 2 700 16 8 + c000 0 0 3 700 17 8 + c000 0 0 4 700 14 8>; + interrupt-parent = <700>; + interrupts = <42 8>; + bus-range = <0 0>; + ranges = <02000000 0 b0000000 b0000000 0 10000000 + 42000000 0 90000000 90000000 0 10000000 + 01000000 0 00000000 e2100000 0 00100000>; + clock-frequency = <3f940aa>; + #interrupt-cells = <1>; + #size-cells = <2>; + #address-cells = <3>; + reg = <8600 100>; + compatible = "83xx"; + device_type = "pci"; + }; + + /* May need to remove if on a part without crypto engine */ + crypto@30000 { + device_type = "crypto"; + model = "SEC2"; + compatible = "talitos"; + reg = <30000 10000>; + interrupts = ; + interrupt-parent = <700>; + num-channels = <4>; + channel-fifo-len = <18>; + exec-units-mask = <0000007e>; + /* desc mask is for rev2.0, + * we need runtime fixup for >2.0 */ + descriptor-types-mask = <01010ebf>; + }; + + /* IPIC + * interrupts cell = + * sense values match linux IORESOURCE_IRQ_* defines: + * sense == 8: Level, low assertion + * sense == 2: Edge, high-to-low change + */ + pic@700 { + linux,phandle = <700>; + interrupt-controller; + #address-cells = <0>; + #interrupt-cells = <2>; + reg = <700 100>; + built-in; + device_type = "ipic"; + }; + }; +}; diff --git a/arch/powerpc/boot/dts/mpc8560ads.dts b/arch/powerpc/boot/dts/mpc8560ads.dts index 2b16848..119bd5d 100644 --- a/arch/powerpc/boot/dts/mpc8560ads.dts +++ b/arch/powerpc/boot/dts/mpc8560ads.dts @@ -200,7 +200,7 @@ a800 0 0 4 40000 31 1>; interrupt-parent = <40000>; - interrupts = <42 0>; + interrupts = <8 0>; bus-range = <0 0>; ranges = <02000000 0 80000000 80000000 0 20000000 01000000 0 00000000 e2000000 0 01000000>; @@ -250,7 +250,7 @@ rx-clock = <1>; tx-clock = <1>; current-speed = <1c200>; - interrupts = <64 1>; + interrupts = <28 8>; interrupt-parent = <90c00>; }; @@ -264,7 +264,7 @@ rx-clock = <2>; tx-clock = <2>; current-speed = <1c200>; - interrupts = <65 1>; + interrupts = <29 8>; interrupt-parent = <90c00>; }; @@ -278,7 +278,7 @@ clock-setup = ; rx-clock = <15>; tx-clock = <16>; - interrupts = <5d 1>; + interrupts = <21 8>; interrupt-parent = <90c00>; phy-handle = <2452002>; }; @@ -293,7 +293,7 @@ clock-setup = ; rx-clock = <17>; tx-clock = <18>; - interrupts = <5e 1>; + interrupts = <22 8>; interrupt-parent = <90c00>; phy-handle = <2452003>; }; diff --git a/arch/powerpc/boot/dts/mpc8568mds.dts b/arch/powerpc/boot/dts/mpc8568mds.dts new file mode 100644 index 0000000..06d2465 --- /dev/null +++ b/arch/powerpc/boot/dts/mpc8568mds.dts @@ -0,0 +1,380 @@ +/* + * MPC8568E MDS Device Tree Source + * + * Copyright 2007 Freescale Semiconductor Inc. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + */ + + +/* +/memreserve/ 00000000 1000000; +*/ + +/ { + model = "MPC8568EMDS"; + compatible = "MPC85xxMDS"; + #address-cells = <1>; + #size-cells = <1>; + linux,phandle = <100>; + + cpus { + #cpus = <1>; + #address-cells = <1>; + #size-cells = <0>; + linux,phandle = <200>; + + PowerPC,8568@0 { + device_type = "cpu"; + reg = <0>; + d-cache-line-size = <20>; // 32 bytes + i-cache-line-size = <20>; // 32 bytes + d-cache-size = <8000>; // L1, 32K + i-cache-size = <8000>; // L1, 32K + timebase-frequency = <0>; + bus-frequency = <0>; + clock-frequency = <0>; + 32-bit; + linux,phandle = <201>; + }; + }; + + memory { + device_type = "memory"; + linux,phandle = <300>; + reg = <00000000 10000000>; + }; + + bcsr@f8000000 { + device_type = "board-control"; + reg = ; + }; + + soc8568@e0000000 { + #address-cells = <1>; + #size-cells = <1>; + #interrupt-cells = <2>; + device_type = "soc"; + ranges = <0 e0000000 00100000>; + reg = ; + bus-frequency = <0>; + + i2c@3000 { + device_type = "i2c"; + compatible = "fsl-i2c"; + reg = <3000 100>; + interrupts = <1b 2>; + interrupt-parent = <40000>; + dfsrr; + }; + + i2c@3100 { + device_type = "i2c"; + compatible = "fsl-i2c"; + reg = <3100 100>; + interrupts = <1b 2>; + interrupt-parent = <40000>; + dfsrr; + }; + + mdio@24520 { + #address-cells = <1>; + #size-cells = <0>; + device_type = "mdio"; + compatible = "gianfar"; + reg = <24520 20>; + linux,phandle = <24520>; + ethernet-phy@0 { + linux,phandle = <2452000>; + interrupt-parent = <40000>; + interrupts = <31 1>; + reg = <0>; + device_type = "ethernet-phy"; + }; + ethernet-phy@1 { + linux,phandle = <2452001>; + interrupt-parent = <40000>; + interrupts = <32 1>; + reg = <1>; + device_type = "ethernet-phy"; + }; + + ethernet-phy@2 { + linux,phandle = <2452002>; + interrupt-parent = <40000>; + interrupts = <31 1>; + reg = <2>; + device_type = "ethernet-phy"; + }; + ethernet-phy@3 { + linux,phandle = <2452003>; + interrupt-parent = <40000>; + interrupts = <32 1>; + reg = <3>; + device_type = "ethernet-phy"; + }; + }; + + ethernet@24000 { + #address-cells = <1>; + #size-cells = <0>; + device_type = "network"; + model = "eTSEC"; + compatible = "gianfar"; + reg = <24000 1000>; + mac-address = [ 00 00 00 00 00 00 ]; + interrupts = ; + interrupt-parent = <40000>; + phy-handle = <2452002>; + }; + + ethernet@25000 { + #address-cells = <1>; + #size-cells = <0>; + device_type = "network"; + model = "eTSEC"; + compatible = "gianfar"; + reg = <25000 1000>; + mac-address = [ 00 00 00 00 00 00]; + interrupts = <13 2 14 2 18 2>; + interrupt-parent = <40000>; + phy-handle = <2452003>; + }; + + serial@4500 { + device_type = "serial"; + compatible = "ns16550"; + reg = <4500 100>; + clock-frequency = <0>; + interrupts = <1a 2>; + interrupt-parent = <40000>; + }; + + serial@4600 { + device_type = "serial"; + compatible = "ns16550"; + reg = <4600 100>; + clock-frequency = <0>; + interrupts = <1a 2>; + interrupt-parent = <40000>; + }; + + crypto@30000 { + device_type = "crypto"; + model = "SEC2"; + compatible = "talitos"; + reg = <30000 f000>; + interrupts = <1d 2>; + interrupt-parent = <40000>; + num-channels = <4>; + channel-fifo-len = <18>; + exec-units-mask = <000000fe>; + descriptor-types-mask = <012b0ebf>; + }; + + pic@40000 { + linux,phandle = <40000>; + clock-frequency = <0>; + interrupt-controller; + #address-cells = <0>; + #interrupt-cells = <2>; + reg = <40000 40000>; + built-in; + compatible = "chrp,open-pic"; + device_type = "open-pic"; + big-endian; + }; + par_io@e0100 { + reg = ; + device_type = "par_io"; + num-ports = <7>; + + ucc_pin@01 { + linux,phandle = ; + pio-map = < + /* port pin dir open_drain assignment has_irq */ + 4 0a 1 0 2 0 /* TxD0 */ + 4 09 1 0 2 0 /* TxD1 */ + 4 08 1 0 2 0 /* TxD2 */ + 4 07 1 0 2 0 /* TxD3 */ + 4 17 1 0 2 0 /* TxD4 */ + 4 16 1 0 2 0 /* TxD5 */ + 4 15 1 0 2 0 /* TxD6 */ + 4 14 1 0 2 0 /* TxD7 */ + 4 0f 2 0 2 0 /* RxD0 */ + 4 0e 2 0 2 0 /* RxD1 */ + 4 0d 2 0 2 0 /* RxD2 */ + 4 0c 2 0 2 0 /* RxD3 */ + 4 1d 2 0 2 0 /* RxD4 */ + 4 1c 2 0 2 0 /* RxD5 */ + 4 1b 2 0 2 0 /* RxD6 */ + 4 1a 2 0 2 0 /* RxD7 */ + 4 0b 1 0 2 0 /* TX_EN */ + 4 18 1 0 2 0 /* TX_ER */ + 4 0f 2 0 2 0 /* RX_DV */ + 4 1e 2 0 2 0 /* RX_ER */ + 4 11 2 0 2 0 /* RX_CLK */ + 4 13 1 0 2 0 /* GTX_CLK */ + 1 1f 2 0 3 0>; /* GTX125 */ + }; + ucc_pin@02 { + linux,phandle = ; + pio-map = < + /* port pin dir open_drain assignment has_irq */ + 5 0a 1 0 2 0 /* TxD0 */ + 5 09 1 0 2 0 /* TxD1 */ + 5 08 1 0 2 0 /* TxD2 */ + 5 07 1 0 2 0 /* TxD3 */ + 5 17 1 0 2 0 /* TxD4 */ + 5 16 1 0 2 0 /* TxD5 */ + 5 15 1 0 2 0 /* TxD6 */ + 5 14 1 0 2 0 /* TxD7 */ + 5 0f 2 0 2 0 /* RxD0 */ + 5 0e 2 0 2 0 /* RxD1 */ + 5 0d 2 0 2 0 /* RxD2 */ + 5 0c 2 0 2 0 /* RxD3 */ + 5 1d 2 0 2 0 /* RxD4 */ + 5 1c 2 0 2 0 /* RxD5 */ + 5 1b 2 0 2 0 /* RxD6 */ + 5 1a 2 0 2 0 /* RxD7 */ + 5 0b 1 0 2 0 /* TX_EN */ + 5 18 1 0 2 0 /* TX_ER */ + 5 10 2 0 2 0 /* RX_DV */ + 5 1e 2 0 2 0 /* RX_ER */ + 5 11 2 0 2 0 /* RX_CLK */ + 5 13 1 0 2 0 /* GTX_CLK */ + 1 1f 2 0 3 0 /* GTX125 */ + 4 06 3 0 2 0 /* MDIO */ + 4 05 1 0 2 0>; /* MDC */ + }; + }; + }; + + qe@e0080000 { + #address-cells = <1>; + #size-cells = <1>; + device_type = "qe"; + model = "QE"; + ranges = <0 e0080000 00040000>; + reg = ; + brg-frequency = <0>; + bus-frequency = <179A7B00>; + + muram@10000 { + device_type = "muram"; + ranges = <0 00010000 0000c000>; + + data-only@0{ + reg = <0 c000>; + }; + }; + + spi@4c0 { + device_type = "spi"; + compatible = "fsl_spi"; + reg = <4c0 40>; + interrupts = <2>; + interrupt-parent = <80>; + mode = "cpu"; + }; + + spi@500 { + device_type = "spi"; + compatible = "fsl_spi"; + reg = <500 40>; + interrupts = <1>; + interrupt-parent = <80>; + mode = "cpu"; + }; + + ucc@2000 { + device_type = "network"; + compatible = "ucc_geth"; + model = "UCC"; + device-id = <1>; + reg = <2000 200>; + interrupts = <20>; + interrupt-parent = <80>; + mac-address = [ 00 04 9f 00 23 23 ]; + rx-clock = <0>; + tx-clock = <19>; + phy-handle = <212000>; + pio-handle = ; + }; + + ucc@3000 { + device_type = "network"; + compatible = "ucc_geth"; + model = "UCC"; + device-id = <2>; + reg = <3000 200>; + interrupts = <21>; + interrupt-parent = <80>; + mac-address = [ 00 11 22 33 44 55 ]; + rx-clock = <0>; + tx-clock = <14>; + phy-handle = <212001>; + pio-handle = ; + }; + + mdio@2120 { + #address-cells = <1>; + #size-cells = <0>; + reg = <2120 18>; + device_type = "mdio"; + compatible = "ucc_geth_phy"; + + /* These are the same PHYs as on + * gianfar's MDIO bus */ + ethernet-phy@00 { + linux,phandle = <212000>; + interrupt-parent = <40000>; + interrupts = <31 1>; + reg = <0>; + device_type = "ethernet-phy"; + interface = <6>; //ENET_1000_GMII + }; + ethernet-phy@01 { + linux,phandle = <212001>; + interrupt-parent = <40000>; + interrupts = <32 1>; + reg = <1>; + device_type = "ethernet-phy"; + interface = <6>; + }; + ethernet-phy@02 { + linux,phandle = <212002>; + interrupt-parent = <40000>; + interrupts = <31 1>; + reg = <2>; + device_type = "ethernet-phy"; + interface = <6>; //ENET_1000_GMII + }; + ethernet-phy@03 { + linux,phandle = <212003>; + interrupt-parent = <40000>; + interrupts = <32 1>; + reg = <3>; + device_type = "ethernet-phy"; + interface = <6>; //ENET_1000_GMII + }; + }; + + qeic@80 { + linux,phandle = <80>; + interrupt-controller; + device_type = "qeic"; + #address-cells = <0>; + #interrupt-cells = <1>; + reg = <80 80>; + built-in; + big-endian; + interrupts = <1e 2 1e 2>; //high:30 low:30 + interrupt-parent = <40000>; + }; + + }; +}; diff --git a/arch/powerpc/boot/dts/mpc866ads.dts b/arch/powerpc/boot/dts/mpc866ads.dts new file mode 100644 index 0000000..5d40052 --- /dev/null +++ b/arch/powerpc/boot/dts/mpc866ads.dts @@ -0,0 +1,162 @@ +/* + * MPC866 ADS Device Tree Source + * + * Copyright 2006 MontaVista Software, 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. + */ + + +/ { + model = "MPC866ADS"; + compatible = "mpc8xx"; + #address-cells = <1>; + #size-cells = <1>; + linux,phandle = <100>; + + cpus { + #cpus = <1>; + #address-cells = <1>; + #size-cells = <0>; + linux,phandle = <200>; + + PowerPC,866@0 { + device_type = "cpu"; + reg = <0>; + d-cache-line-size = <20>; // 32 bytes + i-cache-line-size = <20>; // 32 bytes + d-cache-size = <2000>; // L1, 8K + i-cache-size = <4000>; // L1, 16K + timebase-frequency = <0>; + bus-frequency = <0>; + clock-frequency = <0>; + 32-bit; + interrupts = ; // decrementer interrupt + interrupt-parent = ; + linux,phandle = <201>; + linux,boot-cpu; + }; + }; + + memory { + device_type = "memory"; + linux,phandle = <300>; + reg = <00000000 800000>; + }; + + soc866@ff000000 { + #address-cells = <1>; + #size-cells = <1>; + #interrupt-cells = <2>; + device_type = "soc"; + ranges = <0 ff000000 00100000>; + reg = ; + bus-frequency = <0>; + mdio@e80 { + device_type = "mdio"; + compatible = "fs_enet"; + reg = ; + linux,phandle = ; + #address-cells = <1>; + #size-cells = <0>; + ethernet-phy@f { + linux,phandle = ; + reg = ; + device_type = "ethernet-phy"; + }; + }; + + fec@e00 { + device_type = "network"; + compatible = "fs_enet"; + model = "FEC"; + device-id = <1>; + reg = ; + mac-address = [ 00 00 0C 00 01 FD ]; + interrupts = <3 1>; + interrupt-parent = ; + phy-handle = ; + }; + + pic@ff000000 { + linux,phandle = ; + interrupt-controller; + #address-cells = <0>; + #interrupt-cells = <2>; + reg = <0 24>; + built-in; + device_type = "mpc8xx-pic"; + compatible = "CPM"; + }; + + cpm@ff000000 { + linux,phandle = ; + #address-cells = <1>; + #size-cells = <1>; + #interrupt-cells = <2>; + device_type = "cpm"; + model = "CPM"; + ranges = <0 0 4000>; + reg = <860 f0>; + command-proc = <9c0>; + brg-frequency = <0>; + interrupts = <0 2>; // cpm error interrupt + interrupt-parent = <930>; + + pic@930 { + linux,phandle = <930>; + interrupt-controller; + #address-cells = <0>; + #interrupt-cells = <2>; + interrupts = <5 2 0 2>; + interrupt-parent = ; + reg = <930 20>; + built-in; + device_type = "cpm-pic"; + compatible = "CPM"; + }; + + smc@a80 { + device_type = "serial"; + compatible = "cpm_uart"; + model = "SMC"; + device-id = <1>; + reg = ; + clock-setup = <00ffffff 0>; + rx-clock = <1>; + tx-clock = <1>; + current-speed = <0>; + interrupts = <4 3>; + interrupt-parent = <930>; + }; + + smc@a90 { + device_type = "serial"; + compatible = "cpm_uart"; + model = "SMC"; + device-id = <2>; + reg = ; + clock-setup = ; + rx-clock = <2>; + tx-clock = <2>; + current-speed = <0>; + interrupts = <3 3>; + interrupt-parent = <930>; + }; + + scc@a00 { + device_type = "network"; + compatible = "fs_enet"; + model = "SCC"; + device-id = <1>; + reg = ; + mac-address = [ 00 00 0C 00 03 FD ]; + interrupts = <1e 3>; + interrupt-parent = <930>; + }; + }; + }; +}; diff --git a/arch/powerpc/boot/dts/mpc885ads.dts b/arch/powerpc/boot/dts/mpc885ads.dts new file mode 100644 index 0000000..cf1a19f --- /dev/null +++ b/arch/powerpc/boot/dts/mpc885ads.dts @@ -0,0 +1,185 @@ +/* + * MPC885 ADS Device Tree Source + * + * Copyright 2006 MontaVista Software, 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. + */ + + +/ { + model = "MPC885ADS"; + compatible = "mpc8xx"; + #address-cells = <1>; + #size-cells = <1>; + linux,phandle = <100>; + + cpus { + #cpus = <1>; + #address-cells = <1>; + #size-cells = <0>; + linux,phandle = <200>; + + PowerPC,885@0 { + device_type = "cpu"; + reg = <0>; + d-cache-line-size = <20>; // 32 bytes + i-cache-line-size = <20>; // 32 bytes + d-cache-size = <2000>; // L1, 8K + i-cache-size = <2000>; // L1, 8K + timebase-frequency = <0>; + bus-frequency = <0>; + clock-frequency = <0>; + 32-bit; + interrupts = ; // decrementer interrupt + interrupt-parent = ; + linux,phandle = <201>; + linux,boot-cpu; + }; + }; + + memory { + device_type = "memory"; + linux,phandle = <300>; + reg = <00000000 800000>; + }; + + soc885@ff000000 { + #address-cells = <1>; + #size-cells = <1>; + #interrupt-cells = <2>; + device_type = "soc"; + ranges = <0 ff000000 00100000>; + reg = ; + bus-frequency = <0>; + mdio@e80 { + device_type = "mdio"; + compatible = "fs_enet"; + reg = ; + linux,phandle = ; + #address-cells = <1>; + #size-cells = <0>; + ethernet-phy@0 { + linux,phandle = ; + reg = <0>; + device_type = "ethernet-phy"; + }; + ethernet-phy@1 { + linux,phandle = ; + reg = <1>; + device_type = "ethernet-phy"; + }; + ethernet-phy@2 { + linux,phandle = ; + reg = <2>; + device_type = "ethernet-phy"; + }; + }; + + fec@e00 { + device_type = "network"; + compatible = "fs_enet"; + model = "FEC"; + device-id = <1>; + reg = ; + mac-address = [ 00 00 0C 00 01 FD ]; + interrupts = <3 1>; + interrupt-parent = ; + phy-handle = ; + }; + + fec@1e00 { + device_type = "network"; + compatible = "fs_enet"; + model = "FEC"; + device-id = <2>; + reg = <1e00 188>; + mac-address = [ 00 00 0C 00 02 FD ]; + interrupts = <7 1>; + interrupt-parent = ; + phy-handle = ; + }; + + pic@ff000000 { + linux,phandle = ; + interrupt-controller; + #address-cells = <0>; + #interrupt-cells = <2>; + reg = <0 24>; + built-in; + device_type = "mpc8xx-pic"; + compatible = "CPM"; + }; + + cpm@ff000000 { + linux,phandle = ; + #address-cells = <1>; + #size-cells = <1>; + #interrupt-cells = <2>; + device_type = "cpm"; + model = "CPM"; + ranges = <0 0 4000>; + reg = <860 f0>; + command-proc = <9c0>; + brg-frequency = <0>; + interrupts = <0 2>; // cpm error interrupt + interrupt-parent = <930>; + + pic@930 { + linux,phandle = <930>; + interrupt-controller; + #address-cells = <0>; + #interrupt-cells = <2>; + interrupts = <5 2 0 2>; + interrupt-parent = ; + reg = <930 20>; + built-in; + device_type = "cpm-pic"; + compatible = "CPM"; + }; + + smc@a80 { + device_type = "serial"; + compatible = "cpm_uart"; + model = "SMC"; + device-id = <1>; + reg = ; + clock-setup = <00ffffff 0>; + rx-clock = <1>; + tx-clock = <1>; + current-speed = <0>; + interrupts = <4 3>; + interrupt-parent = <930>; + }; + + smc@a90 { + device_type = "serial"; + compatible = "cpm_uart"; + model = "SMC"; + device-id = <2>; + reg = ; + clock-setup = ; + rx-clock = <2>; + tx-clock = <2>; + current-speed = <0>; + interrupts = <3 3>; + interrupt-parent = <930>; + }; + + scc@a40 { + device_type = "network"; + compatible = "fs_enet"; + model = "SCC"; + device-id = <3>; + reg = ; + mac-address = [ 00 00 0C 00 03 FD ]; + interrupts = <1c 3>; + interrupt-parent = <930>; + phy-handle = ; + }; + }; + }; +}; diff --git a/arch/powerpc/configs/celleb_defconfig b/arch/powerpc/configs/celleb_defconfig new file mode 100644 index 0000000..a1fe971 --- /dev/null +++ b/arch/powerpc/configs/celleb_defconfig @@ -0,0 +1,1408 @@ +# +# Automatically generated make config: don't edit +# Linux kernel version: 2.6.20-rc4 +# Thu Jan 11 20:55:33 2007 +# +CONFIG_PPC64=y +CONFIG_64BIT=y +CONFIG_PPC_MERGE=y +CONFIG_MMU=y +CONFIG_GENERIC_HARDIRQS=y +CONFIG_IRQ_PER_CPU=y +CONFIG_RWSEM_XCHGADD_ALGORITHM=y +CONFIG_ARCH_HAS_ILOG2_U32=y +CONFIG_ARCH_HAS_ILOG2_U64=y +CONFIG_GENERIC_HWEIGHT=y +CONFIG_GENERIC_CALIBRATE_DELAY=y +CONFIG_GENERIC_FIND_NEXT_BIT=y +CONFIG_PPC=y +CONFIG_EARLY_PRINTK=y +CONFIG_COMPAT=y +CONFIG_SYSVIPC_COMPAT=y +CONFIG_SCHED_NO_NO_OMIT_FRAME_POINTER=y +CONFIG_ARCH_MAY_HAVE_PC_FDC=y +CONFIG_PPC_OF=y +# CONFIG_PPC_UDBG_16550 is not set +# CONFIG_GENERIC_TBSYNC is not set +CONFIG_AUDIT_ARCH=y +CONFIG_GENERIC_BUG=y +# CONFIG_DEFAULT_UIMAGE is not set + +# +# Processor support +# +# CONFIG_POWER4_ONLY is not set +CONFIG_POWER3=y +CONFIG_POWER4=y +CONFIG_PPC_FPU=y +# CONFIG_PPC_DCR_NATIVE is not set +# CONFIG_PPC_DCR_MMIO is not set +CONFIG_PPC_OF_PLATFORM_PCI=y +CONFIG_ALTIVEC=y +CONFIG_PPC_STD_MMU=y +CONFIG_VIRT_CPU_ACCOUNTING=y +CONFIG_SMP=y +CONFIG_NR_CPUS=4 +CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config" + +# +# Code maturity level options +# +CONFIG_EXPERIMENTAL=y +CONFIG_LOCK_KERNEL=y +CONFIG_INIT_ENV_ARG_LIMIT=32 + +# +# General setup +# +CONFIG_LOCALVERSION="" +CONFIG_LOCALVERSION_AUTO=y +CONFIG_SWAP=y +CONFIG_SYSVIPC=y +# CONFIG_IPC_NS is not set +# CONFIG_POSIX_MQUEUE is not set +# CONFIG_BSD_PROCESS_ACCT is not set +# CONFIG_TASKSTATS is not set +# CONFIG_UTS_NS is not set +# CONFIG_AUDIT is not set +CONFIG_IKCONFIG=y +CONFIG_IKCONFIG_PROC=y +# CONFIG_CPUSETS is not set +CONFIG_SYSFS_DEPRECATED=y +# CONFIG_RELAY is not set +CONFIG_INITRAMFS_SOURCE="" +CONFIG_CC_OPTIMIZE_FOR_SIZE=y +CONFIG_SYSCTL=y +# CONFIG_EMBEDDED is not set +CONFIG_SYSCTL_SYSCALL=y +CONFIG_KALLSYMS=y +# CONFIG_KALLSYMS_ALL is not set +# CONFIG_KALLSYMS_EXTRA_PASS is not set +CONFIG_HOTPLUG=y +CONFIG_PRINTK=y +CONFIG_BUG=y +CONFIG_ELF_CORE=y +CONFIG_BASE_FULL=y +CONFIG_FUTEX=y +CONFIG_EPOLL=y +CONFIG_SHMEM=y +CONFIG_SLAB=y +CONFIG_VM_EVENT_COUNTERS=y +CONFIG_RT_MUTEXES=y +# CONFIG_TINY_SHMEM is not set +CONFIG_BASE_SMALL=0 +# CONFIG_SLOB is not set + +# +# Loadable module support +# +CONFIG_MODULES=y +CONFIG_MODULE_UNLOAD=y +# CONFIG_MODULE_FORCE_UNLOAD is not set +CONFIG_MODVERSIONS=y +CONFIG_MODULE_SRCVERSION_ALL=y +CONFIG_KMOD=y +CONFIG_STOP_MACHINE=y + +# +# Block layer +# +CONFIG_BLOCK=y +# CONFIG_BLK_DEV_IO_TRACE is not set + +# +# IO Schedulers +# +CONFIG_IOSCHED_NOOP=y +CONFIG_IOSCHED_AS=y +CONFIG_IOSCHED_DEADLINE=y +CONFIG_IOSCHED_CFQ=y +CONFIG_DEFAULT_AS=y +# CONFIG_DEFAULT_DEADLINE is not set +# CONFIG_DEFAULT_CFQ is not set +# CONFIG_DEFAULT_NOOP is not set +CONFIG_DEFAULT_IOSCHED="anticipatory" + +# +# Platform support +# +CONFIG_PPC_MULTIPLATFORM=y +# CONFIG_EMBEDDED6xx is not set +# CONFIG_APUS is not set +# CONFIG_PPC_PSERIES is not set +# CONFIG_PPC_ISERIES is not set +# CONFIG_PPC_MPC52xx is not set +# CONFIG_PPC_PMAC is not set +# CONFIG_PPC_MAPLE is not set +# CONFIG_PPC_PASEMI is not set +CONFIG_PPC_CELL=y +# CONFIG_PPC_CELL_NATIVE is not set +# CONFIG_PPC_IBM_CELL_BLADE is not set +# CONFIG_PPC_PS3 is not set +CONFIG_PPC_CELLEB=y +CONFIG_PPC_UDBG_BEAT=y +# CONFIG_U3_DART is not set +# CONFIG_PPC_RTAS is not set +# CONFIG_MMIO_NVRAM is not set +# CONFIG_PPC_MPC106 is not set +# CONFIG_PPC_970_NAP is not set +# CONFIG_PPC_INDIRECT_IO is not set +# CONFIG_GENERIC_IOMAP is not set +# CONFIG_CPU_FREQ is not set +# CONFIG_WANT_EARLY_SERIAL is not set +# CONFIG_MPIC is not set + +# +# Cell Broadband Engine options +# +CONFIG_SPU_FS=y +CONFIG_SPU_BASE=y +# CONFIG_CBE_RAS is not set + +# +# Kernel options +# +# CONFIG_HZ_100 is not set +CONFIG_HZ_250=y +# CONFIG_HZ_300 is not set +# CONFIG_HZ_1000 is not set +CONFIG_HZ=250 +CONFIG_PREEMPT_NONE=y +# CONFIG_PREEMPT_VOLUNTARY is not set +# CONFIG_PREEMPT is not set +CONFIG_PREEMPT_BKL=y +CONFIG_BINFMT_ELF=y +CONFIG_BINFMT_MISC=m +CONFIG_FORCE_MAX_ZONEORDER=13 +# CONFIG_IOMMU_VMERGE is not set +CONFIG_ARCH_ENABLE_MEMORY_HOTPLUG=y +CONFIG_KEXEC=y +# CONFIG_CRASH_DUMP is not set +# CONFIG_IRQ_ALL_CPUS is not set +CONFIG_NUMA=y +CONFIG_NODES_SHIFT=4 +CONFIG_ARCH_SELECT_MEMORY_MODEL=y +CONFIG_ARCH_SPARSEMEM_ENABLE=y +CONFIG_ARCH_SPARSEMEM_DEFAULT=y +CONFIG_ARCH_POPULATES_NODE_MAP=y +CONFIG_SELECT_MEMORY_MODEL=y +# CONFIG_FLATMEM_MANUAL is not set +# CONFIG_DISCONTIGMEM_MANUAL is not set +CONFIG_SPARSEMEM_MANUAL=y +CONFIG_SPARSEMEM=y +CONFIG_NEED_MULTIPLE_NODES=y +CONFIG_HAVE_MEMORY_PRESENT=y +# CONFIG_SPARSEMEM_STATIC is not set +CONFIG_SPARSEMEM_EXTREME=y +CONFIG_MEMORY_HOTPLUG=y +CONFIG_MEMORY_HOTPLUG_SPARSE=y +CONFIG_SPLIT_PTLOCK_CPUS=4 +CONFIG_MIGRATION=y +CONFIG_RESOURCES_64BIT=y +CONFIG_ARCH_MEMORY_PROBE=y +CONFIG_NODES_SPAN_OTHER_NODES=y +# CONFIG_PPC_64K_PAGES is not set +# CONFIG_SCHED_SMT is not set +CONFIG_PROC_DEVICETREE=y +# CONFIG_CMDLINE_BOOL is not set +# CONFIG_PM is not set +CONFIG_SECCOMP=y +CONFIG_ISA_DMA_API=y + +# +# Bus options +# +CONFIG_GENERIC_ISA_DMA=y +# CONFIG_MPIC_WEIRD is not set +# CONFIG_PPC_I8259 is not set +# CONFIG_PPC_INDIRECT_PCI is not set +CONFIG_PCI=y +CONFIG_PCI_DOMAINS=y +# CONFIG_PCIEPORTBUS is not set +# CONFIG_PCI_DEBUG is not set + +# +# PCCARD (PCMCIA/CardBus) support +# +# CONFIG_PCCARD is not set + +# +# PCI Hotplug Support +# +# CONFIG_HOTPLUG_PCI is not set +CONFIG_KERNEL_START=0xc000000000000000 + +# +# Networking +# +CONFIG_NET=y + +# +# Networking options +# +# CONFIG_NETDEBUG is not set +CONFIG_PACKET=y +# CONFIG_PACKET_MMAP is not set +CONFIG_UNIX=y +CONFIG_XFRM=y +# CONFIG_XFRM_USER is not set +# CONFIG_XFRM_SUB_POLICY is not set +# CONFIG_NET_KEY is not set +CONFIG_INET=y +CONFIG_IP_MULTICAST=y +# CONFIG_IP_ADVANCED_ROUTER is not set +CONFIG_IP_FIB_HASH=y +# CONFIG_IP_PNP is not set +# CONFIG_NET_IPIP is not set +# CONFIG_NET_IPGRE is not set +# CONFIG_IP_MROUTE is not set +# CONFIG_ARPD is not set +CONFIG_SYN_COOKIES=y +# CONFIG_INET_AH is not set +# CONFIG_INET_ESP is not set +# CONFIG_INET_IPCOMP is not set +# CONFIG_INET_XFRM_TUNNEL is not set +# CONFIG_INET_TUNNEL is not set +CONFIG_INET_XFRM_MODE_TRANSPORT=y +CONFIG_INET_XFRM_MODE_TUNNEL=y +CONFIG_INET_XFRM_MODE_BEET=y +CONFIG_INET_DIAG=y +CONFIG_INET_TCP_DIAG=y +# CONFIG_TCP_CONG_ADVANCED is not set +CONFIG_TCP_CONG_CUBIC=y +CONFIG_DEFAULT_TCP_CONG="cubic" +# CONFIG_TCP_MD5SIG is not set + +# +# IP: Virtual Server Configuration +# +# CONFIG_IP_VS is not set +CONFIG_IPV6=y +# CONFIG_IPV6_PRIVACY is not set +# CONFIG_IPV6_ROUTER_PREF is not set +CONFIG_INET6_AH=m +CONFIG_INET6_ESP=m +CONFIG_INET6_IPCOMP=m +# CONFIG_IPV6_MIP6 is not set +CONFIG_INET6_XFRM_TUNNEL=m +CONFIG_INET6_TUNNEL=m +CONFIG_INET6_XFRM_MODE_TRANSPORT=y +CONFIG_INET6_XFRM_MODE_TUNNEL=y +CONFIG_INET6_XFRM_MODE_BEET=y +# CONFIG_INET6_XFRM_MODE_ROUTEOPTIMIZATION is not set +CONFIG_IPV6_SIT=y +CONFIG_IPV6_TUNNEL=m +# CONFIG_IPV6_MULTIPLE_TABLES is not set +# CONFIG_NETWORK_SECMARK is not set +CONFIG_NETFILTER=y +# CONFIG_NETFILTER_DEBUG is not set + +# +# Core Netfilter Configuration +# +# CONFIG_NETFILTER_NETLINK is not set +# CONFIG_NF_CONNTRACK_ENABLED is not set +# CONFIG_NETFILTER_XTABLES is not set + +# +# IP: Netfilter Configuration +# +CONFIG_IP_NF_QUEUE=m + +# +# IPv6: Netfilter Configuration (EXPERIMENTAL) +# +# CONFIG_IP6_NF_QUEUE is not set + +# +# DCCP Configuration (EXPERIMENTAL) +# +# CONFIG_IP_DCCP is not set + +# +# SCTP Configuration (EXPERIMENTAL) +# +# CONFIG_IP_SCTP is not set + +# +# TIPC Configuration (EXPERIMENTAL) +# +# CONFIG_TIPC is not set +# CONFIG_ATM is not set +# CONFIG_BRIDGE is not set +# CONFIG_VLAN_8021Q is not set +# CONFIG_DECNET is not set +# CONFIG_LLC2 is not set +# CONFIG_IPX is not set +# CONFIG_ATALK is not set +# CONFIG_X25 is not set +# CONFIG_LAPB is not set +# CONFIG_ECONET is not set +# CONFIG_WAN_ROUTER is not set + +# +# QoS and/or fair queueing +# +# CONFIG_NET_SCHED is not set + +# +# Network testing +# +# CONFIG_NET_PKTGEN is not set +# CONFIG_HAMRADIO is not set +# CONFIG_IRDA is not set +# CONFIG_BT is not set +# CONFIG_IEEE80211 is not set + +# +# Device Drivers +# + +# +# Generic Driver Options +# +CONFIG_STANDALONE=y +CONFIG_PREVENT_FIRMWARE_BUILD=y +CONFIG_FW_LOADER=y +# CONFIG_DEBUG_DRIVER is not set +# CONFIG_SYS_HYPERVISOR is not set + +# +# Connector - unified userspace <-> kernelspace linker +# +# CONFIG_CONNECTOR is not set + +# +# Memory Technology Devices (MTD) +# +# CONFIG_MTD is not set + +# +# Parallel port support +# +# CONFIG_PARPORT is not set + +# +# Plug and Play support +# + +# +# Block devices +# +# CONFIG_BLK_DEV_FD is not set +# CONFIG_BLK_CPQ_DA is not set +# CONFIG_BLK_CPQ_CISS_DA is not set +# CONFIG_BLK_DEV_DAC960 is not set +# CONFIG_BLK_DEV_UMEM is not set +# CONFIG_BLK_DEV_COW_COMMON is not set +CONFIG_BLK_DEV_LOOP=y +# CONFIG_BLK_DEV_CRYPTOLOOP is not set +# CONFIG_BLK_DEV_NBD is not set +# CONFIG_BLK_DEV_SX8 is not set +# CONFIG_BLK_DEV_UB is not set +CONFIG_BLK_DEV_RAM=y +CONFIG_BLK_DEV_RAM_COUNT=16 +CONFIG_BLK_DEV_RAM_SIZE=131072 +CONFIG_BLK_DEV_RAM_BLOCKSIZE=1024 +CONFIG_BLK_DEV_INITRD=y +# CONFIG_CDROM_PKTCDVD is not set +# CONFIG_ATA_OVER_ETH is not set + +# +# Misc devices +# +# CONFIG_SGI_IOC4 is not set +# CONFIG_TIFM_CORE is not set + +# +# ATA/ATAPI/MFM/RLL support +# +CONFIG_IDE=y +CONFIG_BLK_DEV_IDE=y + +# +# Please see Documentation/ide.txt for help/info on IDE drives +# +# CONFIG_BLK_DEV_IDE_SATA is not set +CONFIG_BLK_DEV_IDEDISK=y +CONFIG_IDEDISK_MULTI_MODE=y +CONFIG_BLK_DEV_IDECD=m +# CONFIG_BLK_DEV_IDETAPE is not set +# CONFIG_BLK_DEV_IDEFLOPPY is not set +# CONFIG_BLK_DEV_IDESCSI is not set +# CONFIG_IDE_TASK_IOCTL is not set + +# +# IDE chipset support/bugfixes +# +CONFIG_IDE_GENERIC=y +CONFIG_BLK_DEV_IDEPCI=y +CONFIG_IDEPCI_SHARE_IRQ=y +# CONFIG_BLK_DEV_OFFBOARD is not set +CONFIG_BLK_DEV_GENERIC=y +# CONFIG_BLK_DEV_OPTI621 is not set +CONFIG_BLK_DEV_IDEDMA_PCI=y +# CONFIG_BLK_DEV_IDEDMA_FORCED is not set +CONFIG_IDEDMA_PCI_AUTO=y +# CONFIG_IDEDMA_ONLYDISK is not set +# CONFIG_BLK_DEV_AEC62XX is not set +# CONFIG_BLK_DEV_ALI15X3 is not set +# CONFIG_BLK_DEV_AMD74XX is not set +# CONFIG_BLK_DEV_CMD64X is not set +# CONFIG_BLK_DEV_TRIFLEX is not set +# CONFIG_BLK_DEV_CY82C693 is not set +# CONFIG_BLK_DEV_CS5520 is not set +# CONFIG_BLK_DEV_CS5530 is not set +# CONFIG_BLK_DEV_HPT34X is not set +# CONFIG_BLK_DEV_HPT366 is not set +# CONFIG_BLK_DEV_JMICRON is not set +# CONFIG_BLK_DEV_SC1200 is not set +# CONFIG_BLK_DEV_PIIX is not set +# CONFIG_BLK_DEV_IT821X is not set +# CONFIG_BLK_DEV_NS87415 is not set +# CONFIG_BLK_DEV_PDC202XX_OLD is not set +# CONFIG_BLK_DEV_PDC202XX_NEW is not set +# CONFIG_BLK_DEV_SVWKS is not set +# CONFIG_BLK_DEV_SIIMAGE is not set +# CONFIG_BLK_DEV_SL82C105 is not set +# CONFIG_BLK_DEV_SLC90E66 is not set +# CONFIG_BLK_DEV_TRM290 is not set +# CONFIG_BLK_DEV_VIA82CXXX is not set +CONFIG_BLK_DEV_IDE_CELLEB=y +# CONFIG_IDE_ARM is not set +CONFIG_BLK_DEV_IDEDMA=y +# CONFIG_IDEDMA_IVB is not set +CONFIG_IDEDMA_AUTO=y +# CONFIG_BLK_DEV_HD is not set + +# +# SCSI device support +# +# CONFIG_RAID_ATTRS is not set +CONFIG_SCSI=m +# CONFIG_SCSI_TGT is not set +# CONFIG_SCSI_NETLINK is not set +# CONFIG_SCSI_PROC_FS is not set + +# +# SCSI support type (disk, tape, CD-ROM) +# +CONFIG_BLK_DEV_SD=m +# CONFIG_CHR_DEV_ST is not set +# CONFIG_CHR_DEV_OSST is not set +CONFIG_BLK_DEV_SR=m +# CONFIG_BLK_DEV_SR_VENDOR is not set +CONFIG_CHR_DEV_SG=m +# CONFIG_CHR_DEV_SCH is not set + +# +# Some SCSI devices (e.g. CD jukebox) support multiple LUNs +# +CONFIG_SCSI_MULTI_LUN=y +# CONFIG_SCSI_CONSTANTS is not set +# CONFIG_SCSI_LOGGING is not set +# CONFIG_SCSI_SCAN_ASYNC is not set + +# +# SCSI Transports +# +# CONFIG_SCSI_SPI_ATTRS is not set +# CONFIG_SCSI_FC_ATTRS is not set +# CONFIG_SCSI_ISCSI_ATTRS is not set +# CONFIG_SCSI_SAS_ATTRS is not set +# CONFIG_SCSI_SAS_LIBSAS is not set + +# +# SCSI low-level drivers +# +# CONFIG_ISCSI_TCP is not set +# CONFIG_BLK_DEV_3W_XXXX_RAID is not set +# CONFIG_SCSI_3W_9XXX is not set +# CONFIG_SCSI_ACARD is not set +# CONFIG_SCSI_AACRAID is not set +# CONFIG_SCSI_AIC7XXX is not set +# CONFIG_SCSI_AIC7XXX_OLD is not set +# CONFIG_SCSI_AIC79XX is not set +# CONFIG_SCSI_AIC94XX is not set +# CONFIG_SCSI_ARCMSR is not set +# CONFIG_MEGARAID_NEWGEN is not set +# CONFIG_MEGARAID_LEGACY is not set +# CONFIG_MEGARAID_SAS is not set +# CONFIG_SCSI_HPTIOP is not set +# CONFIG_SCSI_BUSLOGIC is not set +# CONFIG_SCSI_DMX3191D is not set +# CONFIG_SCSI_EATA is not set +# CONFIG_SCSI_FUTURE_DOMAIN is not set +# CONFIG_SCSI_GDTH is not set +# CONFIG_SCSI_IPS is not set +# CONFIG_SCSI_INITIO is not set +# CONFIG_SCSI_INIA100 is not set +# CONFIG_SCSI_STEX is not set +# CONFIG_SCSI_SYM53C8XX_2 is not set +# CONFIG_SCSI_QLOGIC_1280 is not set +# CONFIG_SCSI_QLA_FC is not set +# CONFIG_SCSI_QLA_ISCSI is not set +# CONFIG_SCSI_LPFC is not set +# CONFIG_SCSI_DC395x is not set +# CONFIG_SCSI_DC390T is not set +# CONFIG_SCSI_DEBUG is not set +# CONFIG_SCSI_SRP is not set + +# +# Serial ATA (prod) and Parallel ATA (experimental) drivers +# +# CONFIG_ATA is not set + +# +# Multi-device support (RAID and LVM) +# +CONFIG_MD=y +CONFIG_BLK_DEV_MD=m +CONFIG_MD_LINEAR=m +CONFIG_MD_RAID0=m +CONFIG_MD_RAID1=m +# CONFIG_MD_RAID10 is not set +# CONFIG_MD_RAID456 is not set +# CONFIG_MD_MULTIPATH is not set +# CONFIG_MD_FAULTY is not set +CONFIG_BLK_DEV_DM=m +# CONFIG_DM_DEBUG is not set +CONFIG_DM_CRYPT=m +CONFIG_DM_SNAPSHOT=m +CONFIG_DM_MIRROR=m +CONFIG_DM_ZERO=m +CONFIG_DM_MULTIPATH=m +# CONFIG_DM_MULTIPATH_EMC is not set + +# +# Fusion MPT device support +# +# CONFIG_FUSION is not set +# CONFIG_FUSION_SPI is not set +# CONFIG_FUSION_FC is not set +# CONFIG_FUSION_SAS is not set + +# +# IEEE 1394 (FireWire) support +# +# CONFIG_IEEE1394 is not set + +# +# I2O device support +# +# CONFIG_I2O is not set + +# +# Macintosh device drivers +# +# CONFIG_MAC_EMUMOUSEBTN is not set +# CONFIG_WINDFARM is not set + +# +# Network device support +# +CONFIG_NETDEVICES=y +# CONFIG_DUMMY is not set +# CONFIG_BONDING is not set +# CONFIG_EQUALIZER is not set +# CONFIG_TUN is not set + +# +# ARCnet devices +# +# CONFIG_ARCNET is not set + +# +# PHY device support +# +# CONFIG_PHYLIB is not set + +# +# Ethernet (10 or 100Mbit) +# +CONFIG_NET_ETHERNET=y +CONFIG_MII=y +# CONFIG_HAPPYMEAL is not set +# CONFIG_SUNGEM is not set +# CONFIG_CASSINI is not set +# CONFIG_NET_VENDOR_3COM is not set + +# +# Tulip family network device support +# +# CONFIG_NET_TULIP is not set +# CONFIG_HP100 is not set +# CONFIG_NET_PCI is not set + +# +# Ethernet (1000 Mbit) +# +# CONFIG_ACENIC is not set +# CONFIG_DL2K is not set +# CONFIG_E1000 is not set +# CONFIG_NS83820 is not set +# CONFIG_HAMACHI is not set +# CONFIG_YELLOWFIN is not set +# CONFIG_R8169 is not set +# CONFIG_SIS190 is not set +# CONFIG_SKGE is not set +# CONFIG_SKY2 is not set +# CONFIG_SK98LIN is not set +# CONFIG_TIGON3 is not set +# CONFIG_BNX2 is not set +CONFIG_SPIDER_NET=y +# CONFIG_QLA3XXX is not set + +# +# Ethernet (10000 Mbit) +# +# CONFIG_CHELSIO_T1 is not set +# CONFIG_IXGB is not set +# CONFIG_S2IO is not set +# CONFIG_MYRI10GE is not set +# CONFIG_NETXEN_NIC is not set + +# +# Token Ring devices +# +# CONFIG_TR is not set + +# +# Wireless LAN (non-hamradio) +# +# CONFIG_NET_RADIO is not set + +# +# Wan interfaces +# +# CONFIG_WAN is not set +# CONFIG_FDDI is not set +# CONFIG_HIPPI is not set +# CONFIG_PPP is not set +# CONFIG_SLIP is not set +# CONFIG_NET_FC is not set +# CONFIG_SHAPER is not set +# CONFIG_NETCONSOLE is not set +# CONFIG_NETPOLL is not set +# CONFIG_NET_POLL_CONTROLLER is not set + +# +# ISDN subsystem +# +# CONFIG_ISDN is not set + +# +# Telephony Support +# +# CONFIG_PHONE is not set + +# +# Input device support +# +CONFIG_INPUT=y +# CONFIG_INPUT_FF_MEMLESS is not set + +# +# Userland interfaces +# +CONFIG_INPUT_MOUSEDEV=y +# CONFIG_INPUT_MOUSEDEV_PSAUX is not set +CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024 +CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768 +# CONFIG_INPUT_JOYDEV is not set +# CONFIG_INPUT_TSDEV is not set +# CONFIG_INPUT_EVDEV is not set +# CONFIG_INPUT_EVBUG is not set + +# +# Input Device Drivers +# +# CONFIG_INPUT_KEYBOARD is not set +# CONFIG_INPUT_MOUSE is not set +# CONFIG_INPUT_JOYSTICK is not set +# CONFIG_INPUT_TOUCHSCREEN is not set +# CONFIG_INPUT_MISC is not set + +# +# Hardware I/O ports +# +CONFIG_SERIO=y +# CONFIG_SERIO_I8042 is not set +CONFIG_SERIO_SERPORT=y +# CONFIG_SERIO_PCIPS2 is not set +# CONFIG_SERIO_RAW is not set +# CONFIG_GAMEPORT is not set + +# +# Character devices +# +CONFIG_VT=y +CONFIG_VT_CONSOLE=y +CONFIG_HW_CONSOLE=y +# CONFIG_VT_HW_CONSOLE_BINDING is not set +CONFIG_SERIAL_NONSTANDARD=y +# CONFIG_COMPUTONE is not set +# CONFIG_ROCKETPORT is not set +# CONFIG_CYCLADES is not set +# CONFIG_DIGIEPCA is not set +# CONFIG_MOXA_INTELLIO is not set +# CONFIG_MOXA_SMARTIO is not set +# CONFIG_MOXA_SMARTIO_NEW is not set +# CONFIG_ISI is not set +# CONFIG_SYNCLINK is not set +# CONFIG_SYNCLINKMP is not set +# CONFIG_SYNCLINK_GT is not set +# CONFIG_N_HDLC is not set +# CONFIG_SPECIALIX is not set +# CONFIG_SX is not set +# CONFIG_RIO is not set +# CONFIG_STALDRV is not set + +# +# Serial drivers +# +# CONFIG_SERIAL_8250 is not set + +# +# Non-8250 serial port support +# +CONFIG_SERIAL_CORE=y +CONFIG_SERIAL_CORE_CONSOLE=y +CONFIG_SERIAL_TXX9=y +CONFIG_HAS_TXX9_SERIAL=y +CONFIG_SERIAL_TXX9_CONSOLE=y +# CONFIG_SERIAL_TXX9_STDSERIAL is not set +# CONFIG_SERIAL_JSM is not set +CONFIG_UNIX98_PTYS=y +# CONFIG_LEGACY_PTYS is not set +CONFIG_HVC_DRIVER=y +CONFIG_HVC_BEAT=y + +# +# IPMI +# +# CONFIG_IPMI_HANDLER is not set + +# +# Watchdog Cards +# +CONFIG_WATCHDOG=y +# CONFIG_WATCHDOG_NOWAYOUT is not set + +# +# Watchdog Device Drivers +# +# CONFIG_SOFT_WATCHDOG is not set + +# +# PCI-based Watchdog Cards +# +# CONFIG_PCIPCWATCHDOG is not set +# CONFIG_WDTPCI is not set + +# +# USB-based Watchdog Cards +# +# CONFIG_USBPCWATCHDOG is not set +# CONFIG_HW_RANDOM is not set +CONFIG_GEN_RTC=y +# CONFIG_GEN_RTC_X is not set +# CONFIG_DTLK is not set +# CONFIG_R3964 is not set +# CONFIG_APPLICOM is not set +# CONFIG_AGP is not set +# CONFIG_DRM is not set +# CONFIG_RAW_DRIVER is not set +# CONFIG_HANGCHECK_TIMER is not set + +# +# TPM devices +# +# CONFIG_TCG_TPM is not set + +# +# I2C support +# +CONFIG_I2C=y +# CONFIG_I2C_CHARDEV is not set + +# +# I2C Algorithms +# +CONFIG_I2C_ALGOBIT=y +# CONFIG_I2C_ALGOPCF is not set +# CONFIG_I2C_ALGOPCA is not set + +# +# I2C Hardware Bus support +# +# CONFIG_I2C_ALI1535 is not set +# CONFIG_I2C_ALI1563 is not set +# CONFIG_I2C_ALI15X3 is not set +# CONFIG_I2C_AMD756 is not set +# CONFIG_I2C_AMD8111 is not set +# CONFIG_I2C_I801 is not set +# CONFIG_I2C_I810 is not set +# CONFIG_I2C_PIIX4 is not set +# CONFIG_I2C_NFORCE2 is not set +# CONFIG_I2C_OCORES is not set +# CONFIG_I2C_PARPORT_LIGHT is not set +# CONFIG_I2C_PROSAVAGE is not set +# CONFIG_I2C_SAVAGE4 is not set +# CONFIG_I2C_SIS5595 is not set +# CONFIG_I2C_SIS630 is not set +# CONFIG_I2C_SIS96X is not set +# CONFIG_I2C_STUB is not set +# CONFIG_I2C_VIA is not set +# CONFIG_I2C_VIAPRO is not set +# CONFIG_I2C_VOODOO3 is not set +# CONFIG_I2C_PCA_ISA is not set + +# +# Miscellaneous I2C Chip support +# +# CONFIG_SENSORS_DS1337 is not set +# CONFIG_SENSORS_DS1374 is not set +# CONFIG_SENSORS_EEPROM is not set +# CONFIG_SENSORS_PCF8574 is not set +# CONFIG_SENSORS_PCA9539 is not set +# CONFIG_SENSORS_PCF8591 is not set +# CONFIG_SENSORS_MAX6875 is not set +# CONFIG_I2C_DEBUG_CORE is not set +# CONFIG_I2C_DEBUG_ALGO is not set +# CONFIG_I2C_DEBUG_BUS is not set +# CONFIG_I2C_DEBUG_CHIP is not set + +# +# SPI support +# +# CONFIG_SPI is not set +# CONFIG_SPI_MASTER is not set + +# +# Dallas's 1-wire bus +# +# CONFIG_W1 is not set + +# +# Hardware Monitoring support +# +# CONFIG_HWMON is not set +# CONFIG_HWMON_VID is not set + +# +# Multimedia devices +# +# CONFIG_VIDEO_DEV is not set + +# +# Digital Video Broadcasting Devices +# +# CONFIG_DVB is not set +# CONFIG_USB_DABUSB is not set + +# +# Graphics support +# +# CONFIG_FIRMWARE_EDID is not set +# CONFIG_FB is not set +# CONFIG_FB_IBM_GXT4500 is not set + +# +# Console display driver support +# +# CONFIG_VGA_CONSOLE is not set +CONFIG_DUMMY_CONSOLE=y +# CONFIG_BACKLIGHT_LCD_SUPPORT is not set + +# +# Sound +# +# CONFIG_SOUND is not set + +# +# HID Devices +# +CONFIG_HID=y + +# +# USB support +# +CONFIG_USB_ARCH_HAS_HCD=y +CONFIG_USB_ARCH_HAS_OHCI=y +CONFIG_USB_ARCH_HAS_EHCI=y +CONFIG_USB=y +# CONFIG_USB_DEBUG is not set + +# +# Miscellaneous USB options +# +CONFIG_USB_DEVICEFS=y +# CONFIG_USB_BANDWIDTH is not set +# CONFIG_USB_DYNAMIC_MINORS is not set +# CONFIG_USB_MULTITHREAD_PROBE is not set +# CONFIG_USB_OTG is not set + +# +# USB Host Controller Drivers +# +CONFIG_USB_EHCI_HCD=m +# CONFIG_USB_EHCI_SPLIT_ISO is not set +# CONFIG_USB_EHCI_ROOT_HUB_TT is not set +# CONFIG_USB_EHCI_TT_NEWSCHED is not set +CONFIG_USB_EHCI_BIG_ENDIAN_MMIO=y +# CONFIG_USB_ISP116X_HCD is not set +CONFIG_USB_OHCI_HCD=m +# CONFIG_USB_OHCI_BIG_ENDIAN_DESC is not set +CONFIG_USB_OHCI_BIG_ENDIAN_MMIO=y +CONFIG_USB_OHCI_LITTLE_ENDIAN=y +# CONFIG_USB_UHCI_HCD is not set +# CONFIG_USB_SL811_HCD is not set + +# +# USB Device Class drivers +# +# CONFIG_USB_ACM is not set +# CONFIG_USB_PRINTER is not set + +# +# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support' +# + +# +# may also be needed; see USB_STORAGE Help for more information +# +CONFIG_USB_STORAGE=m +# CONFIG_USB_STORAGE_DEBUG is not set +# CONFIG_USB_STORAGE_DATAFAB is not set +# CONFIG_USB_STORAGE_FREECOM is not set +# CONFIG_USB_STORAGE_ISD200 is not set +# CONFIG_USB_STORAGE_DPCM is not set +# CONFIG_USB_STORAGE_USBAT is not set +# CONFIG_USB_STORAGE_SDDR09 is not set +# CONFIG_USB_STORAGE_SDDR55 is not set +# CONFIG_USB_STORAGE_JUMPSHOT is not set +# CONFIG_USB_STORAGE_ALAUDA is not set +# CONFIG_USB_STORAGE_KARMA is not set +# CONFIG_USB_LIBUSUAL is not set + +# +# USB Input Devices +# +CONFIG_USB_HID=y +# CONFIG_USB_HIDINPUT_POWERBOOK is not set +# CONFIG_HID_FF is not set +CONFIG_USB_HIDDEV=y +# CONFIG_USB_AIPTEK is not set +# CONFIG_USB_WACOM is not set +# CONFIG_USB_ACECAD is not set +# CONFIG_USB_KBTAB is not set +# CONFIG_USB_POWERMATE is not set +# CONFIG_USB_TOUCHSCREEN is not set +# CONFIG_USB_YEALINK is not set +# CONFIG_USB_XPAD is not set +# CONFIG_USB_ATI_REMOTE is not set +# CONFIG_USB_ATI_REMOTE2 is not set +# CONFIG_USB_KEYSPAN_REMOTE is not set +# CONFIG_USB_APPLETOUCH is not set + +# +# USB Imaging devices +# +# CONFIG_USB_MDC800 is not set +# CONFIG_USB_MICROTEK is not set + +# +# USB Network Adapters +# +# CONFIG_USB_CATC is not set +# CONFIG_USB_KAWETH is not set +# CONFIG_USB_PEGASUS is not set +# CONFIG_USB_RTL8150 is not set +# CONFIG_USB_USBNET_MII is not set +# CONFIG_USB_USBNET is not set +CONFIG_USB_MON=y + +# +# USB port drivers +# + +# +# USB Serial Converter support +# +# CONFIG_USB_SERIAL is not set + +# +# USB Miscellaneous drivers +# +# CONFIG_USB_EMI62 is not set +# CONFIG_USB_EMI26 is not set +# CONFIG_USB_ADUTUX is not set +# CONFIG_USB_AUERSWALD is not set +# CONFIG_USB_RIO500 is not set +# CONFIG_USB_LEGOTOWER is not set +# CONFIG_USB_LCD is not set +# CONFIG_USB_LED is not set +# CONFIG_USB_CYPRESS_CY7C63 is not set +# CONFIG_USB_CYTHERM is not set +# CONFIG_USB_PHIDGET is not set +# CONFIG_USB_IDMOUSE is not set +# CONFIG_USB_FTDI_ELAN is not set +# CONFIG_USB_APPLEDISPLAY is not set +# CONFIG_USB_SISUSBVGA is not set +# CONFIG_USB_LD is not set +# CONFIG_USB_TRANCEVIBRATOR is not set +# CONFIG_USB_TEST is not set + +# +# USB DSL modem support +# + +# +# USB Gadget Support +# +# CONFIG_USB_GADGET is not set + +# +# MMC/SD Card support +# +# CONFIG_MMC is not set + +# +# LED devices +# +# CONFIG_NEW_LEDS is not set + +# +# LED drivers +# + +# +# LED Triggers +# + +# +# InfiniBand support +# +# CONFIG_INFINIBAND is not set + +# +# EDAC - error detection and reporting (RAS) (EXPERIMENTAL) +# + +# +# Real Time Clock +# +# CONFIG_RTC_CLASS is not set + +# +# DMA Engine support +# +# CONFIG_DMA_ENGINE is not set + +# +# DMA Clients +# + +# +# DMA Devices +# + +# +# Virtualization +# + +# +# File systems +# +CONFIG_EXT2_FS=y +CONFIG_EXT2_FS_XATTR=y +CONFIG_EXT2_FS_POSIX_ACL=y +CONFIG_EXT2_FS_SECURITY=y +CONFIG_EXT2_FS_XIP=y +CONFIG_FS_XIP=y +CONFIG_EXT3_FS=y +CONFIG_EXT3_FS_XATTR=y +CONFIG_EXT3_FS_POSIX_ACL=y +CONFIG_EXT3_FS_SECURITY=y +# CONFIG_EXT4DEV_FS is not set +CONFIG_JBD=y +# CONFIG_JBD_DEBUG is not set +CONFIG_FS_MBCACHE=y +# CONFIG_REISERFS_FS is not set +# CONFIG_JFS_FS is not set +CONFIG_FS_POSIX_ACL=y +# CONFIG_XFS_FS is not set +# CONFIG_GFS2_FS is not set +# CONFIG_OCFS2_FS is not set +# CONFIG_MINIX_FS is not set +# CONFIG_ROMFS_FS is not set +CONFIG_INOTIFY=y +CONFIG_INOTIFY_USER=y +# CONFIG_QUOTA is not set +CONFIG_DNOTIFY=y +# CONFIG_AUTOFS_FS is not set +# CONFIG_AUTOFS4_FS is not set +# CONFIG_FUSE_FS is not set + +# +# CD-ROM/DVD Filesystems +# +CONFIG_ISO9660_FS=m +CONFIG_JOLIET=y +# CONFIG_ZISOFS is not set +CONFIG_UDF_FS=m +CONFIG_UDF_NLS=y + +# +# DOS/FAT/NT Filesystems +# +CONFIG_FAT_FS=m +CONFIG_MSDOS_FS=m +CONFIG_VFAT_FS=m +CONFIG_FAT_DEFAULT_CODEPAGE=437 +CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1" +# CONFIG_NTFS_FS is not set + +# +# Pseudo filesystems +# +CONFIG_PROC_FS=y +CONFIG_PROC_KCORE=y +CONFIG_PROC_SYSCTL=y +CONFIG_SYSFS=y +CONFIG_TMPFS=y +# CONFIG_TMPFS_POSIX_ACL is not set +CONFIG_HUGETLBFS=y +CONFIG_HUGETLB_PAGE=y +CONFIG_RAMFS=y +# CONFIG_CONFIGFS_FS is not set + +# +# Miscellaneous filesystems +# +# CONFIG_ADFS_FS is not set +# CONFIG_AFFS_FS is not set +# CONFIG_HFS_FS is not set +# CONFIG_HFSPLUS_FS is not set +# CONFIG_BEFS_FS is not set +# CONFIG_BFS_FS is not set +# CONFIG_EFS_FS is not set +# CONFIG_CRAMFS is not set +# CONFIG_VXFS_FS is not set +# CONFIG_HPFS_FS is not set +# CONFIG_QNX4FS_FS is not set +# CONFIG_SYSV_FS is not set +# CONFIG_UFS_FS is not set + +# +# Network File Systems +# +CONFIG_NFS_FS=m +CONFIG_NFS_V3=y +CONFIG_NFS_V3_ACL=y +# CONFIG_NFS_V4 is not set +# CONFIG_NFS_DIRECTIO is not set +CONFIG_NFSD=m +CONFIG_NFSD_V2_ACL=y +CONFIG_NFSD_V3=y +CONFIG_NFSD_V3_ACL=y +# CONFIG_NFSD_V4 is not set +CONFIG_NFSD_TCP=y +CONFIG_LOCKD=m +CONFIG_LOCKD_V4=y +CONFIG_EXPORTFS=m +CONFIG_NFS_ACL_SUPPORT=m +CONFIG_NFS_COMMON=y +CONFIG_SUNRPC=m +# CONFIG_RPCSEC_GSS_KRB5 is not set +# CONFIG_RPCSEC_GSS_SPKM3 is not set +# CONFIG_SMB_FS is not set +# CONFIG_CIFS is not set +# CONFIG_NCP_FS is not set +# CONFIG_CODA_FS is not set +# CONFIG_AFS_FS is not set +# CONFIG_9P_FS is not set + +# +# Partition Types +# +CONFIG_PARTITION_ADVANCED=y +# CONFIG_ACORN_PARTITION is not set +# CONFIG_OSF_PARTITION is not set +# CONFIG_AMIGA_PARTITION is not set +# CONFIG_ATARI_PARTITION is not set +# CONFIG_MAC_PARTITION is not set +CONFIG_MSDOS_PARTITION=y +# CONFIG_BSD_DISKLABEL is not set +# CONFIG_MINIX_SUBPARTITION is not set +# CONFIG_SOLARIS_X86_PARTITION is not set +# CONFIG_UNIXWARE_DISKLABEL is not set +# CONFIG_LDM_PARTITION is not set +# CONFIG_SGI_PARTITION is not set +# CONFIG_ULTRIX_PARTITION is not set +# CONFIG_SUN_PARTITION is not set +# CONFIG_KARMA_PARTITION is not set +CONFIG_EFI_PARTITION=y + +# +# Native Language Support +# +CONFIG_NLS=m +CONFIG_NLS_DEFAULT="iso8859-1" +# CONFIG_NLS_CODEPAGE_437 is not set +# CONFIG_NLS_CODEPAGE_737 is not set +# CONFIG_NLS_CODEPAGE_775 is not set +# CONFIG_NLS_CODEPAGE_850 is not set +# CONFIG_NLS_CODEPAGE_852 is not set +# CONFIG_NLS_CODEPAGE_855 is not set +# CONFIG_NLS_CODEPAGE_857 is not set +# CONFIG_NLS_CODEPAGE_860 is not set +# CONFIG_NLS_CODEPAGE_861 is not set +# CONFIG_NLS_CODEPAGE_862 is not set +# CONFIG_NLS_CODEPAGE_863 is not set +# CONFIG_NLS_CODEPAGE_864 is not set +# CONFIG_NLS_CODEPAGE_865 is not set +# CONFIG_NLS_CODEPAGE_866 is not set +# CONFIG_NLS_CODEPAGE_869 is not set +# CONFIG_NLS_CODEPAGE_936 is not set +# CONFIG_NLS_CODEPAGE_950 is not set +# CONFIG_NLS_CODEPAGE_932 is not set +# CONFIG_NLS_CODEPAGE_949 is not set +# CONFIG_NLS_CODEPAGE_874 is not set +# CONFIG_NLS_ISO8859_8 is not set +# CONFIG_NLS_CODEPAGE_1250 is not set +# CONFIG_NLS_CODEPAGE_1251 is not set +# CONFIG_NLS_ASCII is not set +CONFIG_NLS_ISO8859_1=m +CONFIG_NLS_ISO8859_2=m +CONFIG_NLS_ISO8859_3=m +CONFIG_NLS_ISO8859_4=m +CONFIG_NLS_ISO8859_5=m +CONFIG_NLS_ISO8859_6=m +CONFIG_NLS_ISO8859_7=m +CONFIG_NLS_ISO8859_9=m +CONFIG_NLS_ISO8859_13=m +CONFIG_NLS_ISO8859_14=m +CONFIG_NLS_ISO8859_15=m +# CONFIG_NLS_KOI8_R is not set +# CONFIG_NLS_KOI8_U is not set +# CONFIG_NLS_UTF8 is not set + +# +# Distributed Lock Manager +# +# CONFIG_DLM is not set + +# +# Library routines +# +CONFIG_BITREVERSE=y +# CONFIG_CRC_CCITT is not set +# CONFIG_CRC16 is not set +CONFIG_CRC32=y +CONFIG_LIBCRC32C=m +CONFIG_ZLIB_INFLATE=m +CONFIG_ZLIB_DEFLATE=m +CONFIG_PLIST=y +CONFIG_IOMAP_COPY=y + +# +# Instrumentation Support +# +# CONFIG_PROFILING is not set +# CONFIG_KPROBES is not set + +# +# Kernel hacking +# +# CONFIG_PRINTK_TIME is not set +CONFIG_ENABLE_MUST_CHECK=y +CONFIG_MAGIC_SYSRQ=y +# CONFIG_UNUSED_SYMBOLS is not set +CONFIG_DEBUG_FS=y +# CONFIG_HEADERS_CHECK is not set +CONFIG_DEBUG_KERNEL=y +CONFIG_LOG_BUF_SHIFT=15 +CONFIG_DETECT_SOFTLOCKUP=y +# CONFIG_SCHEDSTATS is not set +# CONFIG_DEBUG_SLAB is not set +# CONFIG_DEBUG_RT_MUTEXES is not set +# CONFIG_RT_MUTEX_TESTER is not set +# CONFIG_DEBUG_SPINLOCK is not set +CONFIG_DEBUG_MUTEXES=y +# CONFIG_DEBUG_RWSEMS is not set +CONFIG_DEBUG_SPINLOCK_SLEEP=y +# CONFIG_DEBUG_LOCKING_API_SELFTESTS is not set +# CONFIG_DEBUG_KOBJECT is not set +CONFIG_DEBUG_BUGVERBOSE=y +# CONFIG_DEBUG_INFO is not set +# CONFIG_DEBUG_VM is not set +# CONFIG_DEBUG_LIST is not set +# CONFIG_FORCED_INLINING is not set +# CONFIG_RCU_TORTURE_TEST is not set +# CONFIG_DEBUG_STACKOVERFLOW is not set +# CONFIG_DEBUG_STACK_USAGE is not set +CONFIG_DEBUGGER=y +CONFIG_XMON=y +CONFIG_XMON_DEFAULT=y +CONFIG_XMON_DISASSEMBLY=y +CONFIG_IRQSTACKS=y +# CONFIG_BOOTX_TEXT is not set +CONFIG_PPC_EARLY_DEBUG=y +# CONFIG_PPC_EARLY_DEBUG_LPAR is not set +# CONFIG_PPC_EARLY_DEBUG_G5 is not set +# CONFIG_PPC_EARLY_DEBUG_RTAS_PANEL is not set +# CONFIG_PPC_EARLY_DEBUG_RTAS_CONSOLE is not set +# CONFIG_PPC_EARLY_DEBUG_MAPLE is not set +# CONFIG_PPC_EARLY_DEBUG_ISERIES is not set +CONFIG_PPC_EARLY_DEBUG_BEAT=y + +# +# Security options +# +# CONFIG_KEYS is not set +# CONFIG_SECURITY is not set + +# +# Cryptographic options +# +CONFIG_CRYPTO=y +CONFIG_CRYPTO_ALGAPI=y +CONFIG_CRYPTO_BLKCIPHER=m +CONFIG_CRYPTO_HASH=y +CONFIG_CRYPTO_MANAGER=y +CONFIG_CRYPTO_HMAC=y +# CONFIG_CRYPTO_XCBC is not set +CONFIG_CRYPTO_NULL=m +CONFIG_CRYPTO_MD4=m +CONFIG_CRYPTO_MD5=y +CONFIG_CRYPTO_SHA1=m +CONFIG_CRYPTO_SHA256=m +CONFIG_CRYPTO_SHA512=m +CONFIG_CRYPTO_WP512=m +CONFIG_CRYPTO_TGR192=m +# CONFIG_CRYPTO_GF128MUL is not set +CONFIG_CRYPTO_ECB=m +CONFIG_CRYPTO_CBC=m +# CONFIG_CRYPTO_LRW is not set +CONFIG_CRYPTO_DES=m +CONFIG_CRYPTO_BLOWFISH=m +CONFIG_CRYPTO_TWOFISH=m +CONFIG_CRYPTO_TWOFISH_COMMON=m +CONFIG_CRYPTO_SERPENT=m +CONFIG_CRYPTO_AES=m +CONFIG_CRYPTO_CAST5=m +CONFIG_CRYPTO_CAST6=m +CONFIG_CRYPTO_TEA=m +CONFIG_CRYPTO_ARC4=m +CONFIG_CRYPTO_KHAZAD=m +CONFIG_CRYPTO_ANUBIS=m +CONFIG_CRYPTO_DEFLATE=m +CONFIG_CRYPTO_MICHAEL_MIC=m +CONFIG_CRYPTO_CRC32C=m +CONFIG_CRYPTO_TEST=m + +# +# Hardware crypto devices +# diff --git a/arch/powerpc/configs/linkstation_defconfig b/arch/powerpc/configs/linkstation_defconfig index 405c1c9..dde66a5 100644 --- a/arch/powerpc/configs/linkstation_defconfig +++ b/arch/powerpc/configs/linkstation_defconfig @@ -1,7 +1,7 @@ # # Automatically generated make config: don't edit -# Linux kernel version: 2.6.20-rc5 -# Mon Jan 22 22:17:58 2007 +# Linux kernel version: 2.6.20-rc6 +# Sun Jan 28 23:13:56 2007 # # CONFIG_PPC64 is not set CONFIG_PPC32=y @@ -58,7 +58,7 @@ CONFIG_INIT_ENV_ARG_LIMIT=32 # # General setup # -CONFIG_LOCALVERSION="-kuroboxHG" +CONFIG_LOCALVERSION="" CONFIG_LOCALVERSION_AUTO=y CONFIG_SWAP=y CONFIG_SYSVIPC=y @@ -206,7 +206,7 @@ # CONFIG_RESOURCES_64BIT is not set CONFIG_PROC_DEVICETREE=y # CONFIG_CMDLINE_BOOL is not set # CONFIG_PM is not set -# CONFIG_SECCOMP is not set +CONFIG_SECCOMP=y CONFIG_ISA_DMA_API=y # @@ -312,39 +312,40 @@ CONFIG_NF_CONNTRACK=m # CONFIG_NF_CT_ACCT is not set # CONFIG_NF_CONNTRACK_MARK is not set # CONFIG_NF_CONNTRACK_EVENTS is not set -# CONFIG_NF_CT_PROTO_SCTP is not set -# CONFIG_NF_CONNTRACK_AMANDA is not set +CONFIG_NF_CT_PROTO_GRE=m +CONFIG_NF_CT_PROTO_SCTP=m +CONFIG_NF_CONNTRACK_AMANDA=m CONFIG_NF_CONNTRACK_FTP=m -# CONFIG_NF_CONNTRACK_H323 is not set +CONFIG_NF_CONNTRACK_H323=m CONFIG_NF_CONNTRACK_IRC=m -# CONFIG_NF_CONNTRACK_NETBIOS_NS is not set -# CONFIG_NF_CONNTRACK_PPTP is not set -# CONFIG_NF_CONNTRACK_SIP is not set +CONFIG_NF_CONNTRACK_NETBIOS_NS=m +CONFIG_NF_CONNTRACK_PPTP=m +CONFIG_NF_CONNTRACK_SIP=m CONFIG_NF_CONNTRACK_TFTP=m CONFIG_NETFILTER_XTABLES=m -CONFIG_NETFILTER_XT_TARGET_CLASSIFY=m +# CONFIG_NETFILTER_XT_TARGET_CLASSIFY is not set # CONFIG_NETFILTER_XT_TARGET_DSCP is not set -CONFIG_NETFILTER_XT_TARGET_MARK=m +# CONFIG_NETFILTER_XT_TARGET_MARK is not set # CONFIG_NETFILTER_XT_TARGET_NFQUEUE is not set -CONFIG_NETFILTER_XT_TARGET_NFLOG=m +# CONFIG_NETFILTER_XT_TARGET_NFLOG is not set # CONFIG_NETFILTER_XT_TARGET_NOTRACK is not set # CONFIG_NETFILTER_XT_MATCH_COMMENT is not set -CONFIG_NETFILTER_XT_MATCH_CONNTRACK=m +# CONFIG_NETFILTER_XT_MATCH_CONNTRACK is not set # CONFIG_NETFILTER_XT_MATCH_DCCP is not set # CONFIG_NETFILTER_XT_MATCH_DSCP is not set -CONFIG_NETFILTER_XT_MATCH_ESP=m -CONFIG_NETFILTER_XT_MATCH_HELPER=m -CONFIG_NETFILTER_XT_MATCH_LENGTH=m -CONFIG_NETFILTER_XT_MATCH_LIMIT=m +# CONFIG_NETFILTER_XT_MATCH_ESP is not set +# CONFIG_NETFILTER_XT_MATCH_HELPER is not set +# CONFIG_NETFILTER_XT_MATCH_LENGTH is not set +# CONFIG_NETFILTER_XT_MATCH_LIMIT is not set CONFIG_NETFILTER_XT_MATCH_MAC=m -CONFIG_NETFILTER_XT_MATCH_MARK=m +# CONFIG_NETFILTER_XT_MATCH_MARK is not set # CONFIG_NETFILTER_XT_MATCH_POLICY is not set -CONFIG_NETFILTER_XT_MATCH_MULTIPORT=m +# CONFIG_NETFILTER_XT_MATCH_MULTIPORT is not set CONFIG_NETFILTER_XT_MATCH_PKTTYPE=m # CONFIG_NETFILTER_XT_MATCH_QUOTA is not set # CONFIG_NETFILTER_XT_MATCH_REALM is not set # CONFIG_NETFILTER_XT_MATCH_SCTP is not set -# CONFIG_NETFILTER_XT_MATCH_STATE is not set +CONFIG_NETFILTER_XT_MATCH_STATE=m # CONFIG_NETFILTER_XT_MATCH_STATISTIC is not set # CONFIG_NETFILTER_XT_MATCH_STRING is not set # CONFIG_NETFILTER_XT_MATCH_TCPMSS is not set @@ -359,12 +360,12 @@ # CONFIG_IP_NF_QUEUE is not set CONFIG_IP_NF_IPTABLES=m CONFIG_IP_NF_MATCH_IPRANGE=m # CONFIG_IP_NF_MATCH_TOS is not set -# CONFIG_IP_NF_MATCH_RECENT is not set +CONFIG_IP_NF_MATCH_RECENT=m # CONFIG_IP_NF_MATCH_ECN is not set # CONFIG_IP_NF_MATCH_AH is not set # CONFIG_IP_NF_MATCH_TTL is not set -# CONFIG_IP_NF_MATCH_OWNER is not set -# CONFIG_IP_NF_MATCH_ADDRTYPE is not set +CONFIG_IP_NF_MATCH_OWNER=m +CONFIG_IP_NF_MATCH_ADDRTYPE=m CONFIG_IP_NF_FILTER=m CONFIG_IP_NF_TARGET_REJECT=m # CONFIG_IP_NF_TARGET_LOG is not set @@ -374,16 +375,17 @@ CONFIG_NF_NAT=m CONFIG_NF_NAT_NEEDED=y CONFIG_IP_NF_TARGET_MASQUERADE=m CONFIG_IP_NF_TARGET_REDIRECT=m -CONFIG_IP_NF_TARGET_NETMAP=m -CONFIG_IP_NF_TARGET_SAME=m +# CONFIG_IP_NF_TARGET_NETMAP is not set +# CONFIG_IP_NF_TARGET_SAME is not set # CONFIG_NF_NAT_SNMP_BASIC is not set +CONFIG_NF_NAT_PROTO_GRE=m CONFIG_NF_NAT_FTP=m CONFIG_NF_NAT_IRC=m CONFIG_NF_NAT_TFTP=m -# CONFIG_NF_NAT_AMANDA is not set -# CONFIG_NF_NAT_PPTP is not set -# CONFIG_NF_NAT_H323 is not set -# CONFIG_NF_NAT_SIP is not set +CONFIG_NF_NAT_AMANDA=m +CONFIG_NF_NAT_PPTP=m +CONFIG_NF_NAT_H323=m +CONFIG_NF_NAT_SIP=m CONFIG_IP_NF_MANGLE=m CONFIG_IP_NF_TARGET_TOS=m CONFIG_IP_NF_TARGET_ECN=m @@ -472,6 +474,7 @@ # # User Modules And Translation Layers # CONFIG_MTD_CHAR=y +CONFIG_MTD_BLKDEVS=y CONFIG_MTD_BLOCK=y # CONFIG_FTL is not set # CONFIG_NFTL is not set @@ -518,6 +521,7 @@ CONFIG_MTD_PHYSMAP=y CONFIG_MTD_PHYSMAP_START=0xffc00000 CONFIG_MTD_PHYSMAP_LEN=0x400000 CONFIG_MTD_PHYSMAP_BANKWIDTH=1 +# CONFIG_MTD_PHYSMAP_OF is not set # CONFIG_MTD_PLATRAM is not set # @@ -540,6 +544,7 @@ # # NAND Flash Device Drivers # # CONFIG_MTD_NAND is not set +# CONFIG_MTD_NAND_CAFE is not set # # OneNAND Flash Device Drivers @@ -696,7 +701,7 @@ # CONFIG_PATA_HPT366 is not set # CONFIG_PATA_HPT37X is not set # CONFIG_PATA_HPT3X2N is not set # CONFIG_PATA_HPT3X3 is not set -# CONFIG_PATA_IT821X is not set +CONFIG_PATA_IT821X=y # CONFIG_PATA_JMICRON is not set # CONFIG_PATA_TRIFLEX is not set # CONFIG_PATA_MARVELL is not set @@ -763,11 +768,33 @@ # CONFIG_ARCNET is not set # # PHY device support # +# CONFIG_PHYLIB is not set # # Ethernet (10 or 100Mbit) # -# CONFIG_NET_ETHERNET is not set +CONFIG_NET_ETHERNET=y +# CONFIG_MII is not set +# CONFIG_HAPPYMEAL is not set +# CONFIG_SUNGEM is not set +# CONFIG_CASSINI is not set +# CONFIG_NET_VENDOR_3COM is not set + +# +# Tulip family network device support +# +CONFIG_NET_TULIP=y +# CONFIG_DE2104X is not set +CONFIG_TULIP=y +# CONFIG_TULIP_MWI is not set +CONFIG_TULIP_MMIO=y +# CONFIG_TULIP_NAPI is not set +# CONFIG_DE4X5 is not set +# CONFIG_WINBOND_840 is not set +# CONFIG_DM9102 is not set +# CONFIG_ULI526X is not set +# CONFIG_HP100 is not set +# CONFIG_NET_PCI is not set # # Ethernet (1000 Mbit) @@ -829,7 +856,8 @@ # CONFIG_PRISM54 is not set # CONFIG_USB_ZD1201 is not set # CONFIG_HOSTAP is not set # CONFIG_BCM43XX is not set -# CONFIG_ZD1211RW is not set +CONFIG_ZD1211RW=m +# CONFIG_ZD1211RW_DEBUG is not set CONFIG_NET_WIRELESS=y # @@ -1098,7 +1126,7 @@ # CONFIG_SOUND is not set # # HID Devices # -CONFIG_HID=y +CONFIG_HID=m # # USB support @@ -1115,7 +1143,6 @@ # CONFIG_USB_DEVICEFS=y # CONFIG_USB_BANDWIDTH is not set # CONFIG_USB_DYNAMIC_MINORS is not set -# CONFIG_USB_MULTITHREAD_PROBE is not set # CONFIG_USB_OTG is not set # @@ -1136,7 +1163,7 @@ # # USB Device Class drivers # # CONFIG_USB_ACM is not set -# CONFIG_USB_PRINTER is not set +CONFIG_USB_PRINTER=m # # NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support' @@ -1371,7 +1398,11 @@ CONFIG_FS_MBCACHE=y # CONFIG_REISERFS_FS is not set # CONFIG_JFS_FS is not set CONFIG_FS_POSIX_ACL=y -# CONFIG_XFS_FS is not set +CONFIG_XFS_FS=m +# CONFIG_XFS_QUOTA is not set +# CONFIG_XFS_SECURITY is not set +# CONFIG_XFS_POSIX_ACL is not set +# CONFIG_XFS_RT is not set # CONFIG_GFS2_FS is not set # CONFIG_OCFS2_FS is not set # CONFIG_MINIX_FS is not set @@ -1461,7 +1492,12 @@ CONFIG_SUNRPC_GSS=y CONFIG_RPCSEC_GSS_KRB5=y # CONFIG_RPCSEC_GSS_SPKM3 is not set # CONFIG_SMB_FS is not set -# CONFIG_CIFS is not set +CONFIG_CIFS=m +# CONFIG_CIFS_STATS is not set +# CONFIG_CIFS_WEAK_PW_HASH is not set +# CONFIG_CIFS_XATTR is not set +# CONFIG_CIFS_DEBUG2 is not set +# CONFIG_CIFS_EXPERIMENTAL is not set # CONFIG_NCP_FS is not set # CONFIG_CODA_FS is not set # CONFIG_AFS_FS is not set @@ -1495,7 +1531,7 @@ # CONFIG_NLS_CODEPAGE_866 is not set # CONFIG_NLS_CODEPAGE_869 is not set # CONFIG_NLS_CODEPAGE_936 is not set # CONFIG_NLS_CODEPAGE_950 is not set -# CONFIG_NLS_CODEPAGE_932 is not set +CONFIG_NLS_CODEPAGE_932=m # CONFIG_NLS_CODEPAGE_949 is not set # CONFIG_NLS_CODEPAGE_874 is not set # CONFIG_NLS_ISO8859_8 is not set @@ -1526,12 +1562,14 @@ # # Library routines # CONFIG_BITREVERSE=y -# CONFIG_CRC_CCITT is not set +CONFIG_CRC_CCITT=m # CONFIG_CRC16 is not set CONFIG_CRC32=y CONFIG_LIBCRC32C=m CONFIG_ZLIB_INFLATE=m CONFIG_ZLIB_DEFLATE=m +CONFIG_TEXTSEARCH=y +CONFIG_TEXTSEARCH_KMP=m CONFIG_PLIST=y CONFIG_IOMAP_COPY=y diff --git a/arch/powerpc/configs/mpc8272_ads_defconfig b/arch/powerpc/configs/mpc8272_ads_defconfig new file mode 100644 index 0000000..2af4502 --- /dev/null +++ b/arch/powerpc/configs/mpc8272_ads_defconfig @@ -0,0 +1,848 @@ +# +# Automatically generated make config: don't edit +# Linux kernel version: 2.6.17-rc5 +# Fri Jul 14 20:36:35 2006 +# +# CONFIG_PPC64 is not set +CONFIG_PPC32=y +CONFIG_PPC_MERGE=y +CONFIG_MMU=y +CONFIG_GENERIC_HARDIRQS=y +CONFIG_IRQ_PER_CPU=y +CONFIG_RWSEM_XCHGADD_ALGORITHM=y +CONFIG_GENERIC_HWEIGHT=y +CONFIG_GENERIC_CALIBRATE_DELAY=y +CONFIG_GENERIC_FIND_NEXT_BIT=y +CONFIG_PPC=y +CONFIG_EARLY_PRINTK=y +CONFIG_GENERIC_NVRAM=y +CONFIG_SCHED_NO_NO_OMIT_FRAME_POINTER=y +CONFIG_ARCH_MAY_HAVE_PC_FDC=y +CONFIG_PPC_OF=y +# CONFIG_PPC_UDBG_16550 is not set +# CONFIG_GENERIC_TBSYNC is not set +# CONFIG_DEFAULT_UIMAGE is not set + +# +# Processor support +# +# CONFIG_CLASSIC32 is not set +# CONFIG_PPC_52xx is not set +CONFIG_PPC_82xx=y +# CONFIG_PPC_83xx is not set +# CONFIG_PPC_85xx is not set +# CONFIG_40x is not set +# CONFIG_44x is not set +# CONFIG_8xx is not set +# CONFIG_E200 is not set +CONFIG_6xx=y +CONFIG_PPC_FPU=y +CONFIG_PPC_STD_MMU=y +CONFIG_PPC_STD_MMU_32=y +# CONFIG_SMP is not set + +# +# Code maturity level options +# +# CONFIG_EXPERIMENTAL is not set +CONFIG_BROKEN_ON_SMP=y +CONFIG_INIT_ENV_ARG_LIMIT=32 + +# +# General setup +# +CONFIG_LOCALVERSION="powerpc8272" +CONFIG_LOCALVERSION_AUTO=y +CONFIG_SWAP=y +CONFIG_SYSVIPC=y +# CONFIG_BSD_PROCESS_ACCT is not set +CONFIG_SYSCTL=y +# CONFIG_AUDIT is not set +CONFIG_IKCONFIG=y +CONFIG_IKCONFIG_PROC=y +# CONFIG_RELAY is not set +CONFIG_INITRAMFS_SOURCE="" +CONFIG_EMBEDDED=y +CONFIG_KALLSYMS=y +CONFIG_KALLSYMS_ALL=y +CONFIG_KALLSYMS_EXTRA_PASS=y +CONFIG_HOTPLUG=y +CONFIG_PRINTK=y +CONFIG_BUG=y +CONFIG_ELF_CORE=y +CONFIG_BASE_FULL=y +CONFIG_FUTEX=y +CONFIG_EPOLL=y +CONFIG_SHMEM=y +CONFIG_SLAB=y +# CONFIG_TINY_SHMEM is not set +CONFIG_BASE_SMALL=0 +# CONFIG_SLOB is not set + +# +# Loadable module support +# +# CONFIG_MODULES is not set + +# +# Block layer +# +# CONFIG_LBD is not set +# CONFIG_BLK_DEV_IO_TRACE is not set +# CONFIG_LSF is not set + +# +# IO Schedulers +# +CONFIG_IOSCHED_NOOP=y +CONFIG_IOSCHED_AS=y +CONFIG_IOSCHED_DEADLINE=y +CONFIG_IOSCHED_CFQ=y +CONFIG_DEFAULT_AS=y +# CONFIG_DEFAULT_DEADLINE is not set +# CONFIG_DEFAULT_CFQ is not set +# CONFIG_DEFAULT_NOOP is not set +CONFIG_DEFAULT_IOSCHED="anticipatory" +CONFIG_PQ2ADS=y +CONFIG_8260=y +CONFIG_8272=y +CONFIG_CPM2=y +# CONFIG_WANT_EARLY_SERIAL is not set +CONFIG_EMBEDDEDBOOT=y + +# +# Platform support +# +CONFIG_ADS8272=y + +# +# Kernel options +# +# CONFIG_HIGHMEM is not set +# CONFIG_HZ_100 is not set +CONFIG_HZ_250=y +# CONFIG_HZ_1000 is not set +CONFIG_HZ=250 +CONFIG_PREEMPT_NONE=y +# CONFIG_PREEMPT_VOLUNTARY is not set +# CONFIG_PREEMPT is not set +CONFIG_BINFMT_ELF=y +CONFIG_BINFMT_MISC=y +# CONFIG_PC_KEYBOARD is not set +CONFIG_ARCH_FLATMEM_ENABLE=y +CONFIG_FLATMEM=y +CONFIG_FLAT_NODE_MEM_MAP=y +# CONFIG_SPARSEMEM_STATIC is not set +CONFIG_SPLIT_PTLOCK_CPUS=4 +CONFIG_PROC_DEVICETREE=y +# CONFIG_CMDLINE_BOOL is not set +# CONFIG_PM is not set +# CONFIG_SOFTWARE_SUSPEND is not set +CONFIG_SECCOMP=y +CONFIG_ISA_DMA_API=y + +# +# Bus options +# +# CONFIG_PPC_I8259 is not set +CONFIG_FSL_SOC=y +# CONFIG_PCI is not set +# CONFIG_PCI_DOMAINS is not set + +# +# PCCARD (PCMCIA/CardBus) support +# +# CONFIG_PCCARD is not set + +# +# PCI Hotplug Support +# + +# +# Advanced setup +# +# CONFIG_ADVANCED_OPTIONS is not set + +# +# Default settings for advanced configuration options are used +# +CONFIG_HIGHMEM_START=0xfe000000 +CONFIG_LOWMEM_SIZE=0x30000000 +CONFIG_KERNEL_START=0xc0000000 +CONFIG_TASK_SIZE=0x80000000 +CONFIG_BOOT_LOAD=0x00400000 + +# +# Networking +# +CONFIG_NET=y + +# +# Networking options +# +# CONFIG_NETDEBUG is not set +CONFIG_PACKET=y +# CONFIG_PACKET_MMAP is not set +CONFIG_UNIX=y +# CONFIG_NET_KEY is not set +CONFIG_INET=y +CONFIG_IP_MULTICAST=y +# CONFIG_IP_ADVANCED_ROUTER is not set +CONFIG_IP_FIB_HASH=y +CONFIG_IP_PNP=y +CONFIG_IP_PNP_DHCP=y +CONFIG_IP_PNP_BOOTP=y +# CONFIG_IP_PNP_RARP is not set +# CONFIG_NET_IPIP is not set +# CONFIG_NET_IPGRE is not set +# CONFIG_IP_MROUTE is not set +CONFIG_SYN_COOKIES=y +# CONFIG_INET_AH is not set +# CONFIG_INET_ESP is not set +# CONFIG_INET_IPCOMP is not set +# CONFIG_INET_XFRM_TUNNEL is not set +# CONFIG_INET_TUNNEL is not set +CONFIG_INET_DIAG=y +CONFIG_INET_TCP_DIAG=y +# CONFIG_TCP_CONG_ADVANCED is not set +CONFIG_TCP_CONG_BIC=y + +# +# IP: Virtual Server Configuration +# +# CONFIG_IP_VS is not set +CONFIG_IPV6=y +# CONFIG_IPV6_PRIVACY is not set +# CONFIG_IPV6_ROUTER_PREF is not set +# CONFIG_INET6_AH is not set +# CONFIG_INET6_ESP is not set +# CONFIG_INET6_IPCOMP is not set +# CONFIG_INET6_XFRM_TUNNEL is not set +# CONFIG_INET6_TUNNEL is not set +# CONFIG_IPV6_TUNNEL is not set +CONFIG_NETFILTER=y +# CONFIG_NETFILTER_DEBUG is not set + +# +# Core Netfilter Configuration +# +# CONFIG_NETFILTER_NETLINK is not set +# CONFIG_NETFILTER_XTABLES is not set + +# +# IP: Netfilter Configuration +# +# CONFIG_IP_NF_CONNTRACK is not set +# CONFIG_IP_NF_QUEUE is not set +# CONFIG_BRIDGE is not set +# CONFIG_VLAN_8021Q is not set +# CONFIG_DECNET is not set +# CONFIG_LLC2 is not set +# CONFIG_IPX is not set +# CONFIG_ATALK is not set + +# +# QoS and/or fair queueing +# +# CONFIG_NET_SCHED is not set + +# +# Network testing +# +# CONFIG_NET_PKTGEN is not set +# CONFIG_HAMRADIO is not set +# CONFIG_IRDA is not set +# CONFIG_BT is not set +# CONFIG_IEEE80211 is not set + +# +# Device Drivers +# + +# +# Generic Driver Options +# +CONFIG_STANDALONE=y +CONFIG_PREVENT_FIRMWARE_BUILD=y +# CONFIG_FW_LOADER is not set +# CONFIG_DEBUG_DRIVER is not set + +# +# Connector - unified userspace <-> kernelspace linker +# +# CONFIG_CONNECTOR is not set + +# +# Memory Technology Devices (MTD) +# +# CONFIG_MTD is not set + +# +# Parallel port support +# +# CONFIG_PARPORT is not set + +# +# Plug and Play support +# + +# +# Block devices +# +# CONFIG_BLK_DEV_FD is not set +# CONFIG_BLK_DEV_COW_COMMON is not set +CONFIG_BLK_DEV_LOOP=y +# CONFIG_BLK_DEV_CRYPTOLOOP is not set +# CONFIG_BLK_DEV_NBD is not set +# CONFIG_BLK_DEV_RAM is not set +# CONFIG_BLK_DEV_INITRD is not set +# CONFIG_CDROM_PKTCDVD is not set +# CONFIG_ATA_OVER_ETH is not set + +# +# ATA/ATAPI/MFM/RLL support +# +CONFIG_IDE=y +CONFIG_BLK_DEV_IDE=y + +# +# Please see Documentation/ide.txt for help/info on IDE drives +# +# CONFIG_BLK_DEV_IDE_SATA is not set +CONFIG_BLK_DEV_IDEDISK=y +# CONFIG_IDEDISK_MULTI_MODE is not set +# CONFIG_BLK_DEV_IDECD is not set +# CONFIG_BLK_DEV_IDEFLOPPY is not set +# CONFIG_IDE_TASK_IOCTL is not set + +# +# IDE chipset support/bugfixes +# +# CONFIG_IDE_GENERIC is not set +# CONFIG_IDE_ARM is not set +# CONFIG_BLK_DEV_IDEDMA is not set +# CONFIG_IDEDMA_AUTO is not set +# CONFIG_BLK_DEV_HD is not set + +# +# SCSI device support +# +# CONFIG_RAID_ATTRS is not set +# CONFIG_SCSI is not set + +# +# Multi-device support (RAID and LVM) +# +# CONFIG_MD is not set + +# +# Fusion MPT device support +# +# CONFIG_FUSION is not set + +# +# IEEE 1394 (FireWire) support +# + +# +# I2O device support +# + +# +# Macintosh device drivers +# +# CONFIG_WINDFARM is not set + +# +# Network device support +# +CONFIG_NETDEVICES=y +# CONFIG_DUMMY is not set +# CONFIG_BONDING is not set +# CONFIG_EQUALIZER is not set +CONFIG_TUN=y + +# +# PHY device support +# +CONFIG_PHYLIB=y + +# +# MII PHY device drivers +# +# CONFIG_MARVELL_PHY is not set +CONFIG_DAVICOM_PHY=y +# CONFIG_QSEMI_PHY is not set +# CONFIG_LXT_PHY is not set +# CONFIG_CICADA_PHY is not set +# CONFIG_FIXED_PHY is not set + +# +# Ethernet (10 or 100Mbit) +# +CONFIG_NET_ETHERNET=y +CONFIG_MII=y +CONFIG_FS_ENET=y +# CONFIG_FS_ENET_HAS_SCC is not set +CONFIG_FS_ENET_HAS_FCC=y + +# +# Ethernet (1000 Mbit) +# + +# +# Ethernet (10000 Mbit) +# + +# +# Token Ring devices +# + +# +# Wireless LAN (non-hamradio) +# +# CONFIG_NET_RADIO is not set + +# +# Wan interfaces +# +# CONFIG_WAN is not set +CONFIG_PPP=y +# CONFIG_PPP_FILTER is not set +CONFIG_PPP_ASYNC=y +CONFIG_PPP_SYNC_TTY=y +CONFIG_PPP_DEFLATE=y +# CONFIG_PPP_BSDCOMP is not set +# CONFIG_SLIP is not set +# CONFIG_NETPOLL is not set +# CONFIG_NET_POLL_CONTROLLER is not set + +# +# ISDN subsystem +# +# CONFIG_ISDN is not set + +# +# Telephony Support +# +# CONFIG_PHONE is not set + +# +# Input device support +# +CONFIG_INPUT=y + +# +# Userland interfaces +# +CONFIG_INPUT_MOUSEDEV=y +CONFIG_INPUT_MOUSEDEV_PSAUX=y +CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024 +CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768 +# CONFIG_INPUT_JOYDEV is not set +# CONFIG_INPUT_TSDEV is not set +CONFIG_INPUT_EVDEV=y +# CONFIG_INPUT_EVBUG is not set + +# +# Input Device Drivers +# +CONFIG_INPUT_KEYBOARD=y +CONFIG_KEYBOARD_ATKBD=y +# CONFIG_KEYBOARD_SUNKBD is not set +# CONFIG_KEYBOARD_LKKBD is not set +# CONFIG_KEYBOARD_XTKBD is not set +# CONFIG_KEYBOARD_NEWTON is not set +CONFIG_INPUT_MOUSE=y +CONFIG_MOUSE_PS2=y +# CONFIG_MOUSE_SERIAL is not set +# CONFIG_MOUSE_VSXXXAA is not set +# CONFIG_INPUT_JOYSTICK is not set +# CONFIG_INPUT_TOUCHSCREEN is not set +# CONFIG_INPUT_MISC is not set + +# +# Hardware I/O ports +# +CONFIG_SERIO=y +# CONFIG_SERIO_I8042 is not set +CONFIG_SERIO_SERPORT=y +CONFIG_SERIO_LIBPS2=y +# CONFIG_SERIO_RAW is not set +# CONFIG_GAMEPORT is not set + +# +# Character devices +# +# CONFIG_VT is not set +# CONFIG_SERIAL_NONSTANDARD is not set + +# +# Serial drivers +# +# CONFIG_SERIAL_8250 is not set + +# +# Non-8250 serial port support +# +CONFIG_SERIAL_CORE=y +CONFIG_SERIAL_CORE_CONSOLE=y +CONFIG_SERIAL_CPM=y +CONFIG_SERIAL_CPM_CONSOLE=y +CONFIG_SERIAL_CPM_SCC1=y +# CONFIG_SERIAL_CPM_SCC2 is not set +# CONFIG_SERIAL_CPM_SCC3 is not set +CONFIG_SERIAL_CPM_SCC4=y +# CONFIG_SERIAL_CPM_SMC1 is not set +# CONFIG_SERIAL_CPM_SMC2 is not set +CONFIG_UNIX98_PTYS=y +CONFIG_LEGACY_PTYS=y +CONFIG_LEGACY_PTY_COUNT=256 + +# +# IPMI +# +# CONFIG_IPMI_HANDLER is not set + +# +# Watchdog Cards +# +# CONFIG_WATCHDOG is not set +# CONFIG_NVRAM is not set +# CONFIG_GEN_RTC is not set +# CONFIG_DTLK is not set +# CONFIG_R3964 is not set + +# +# Ftape, the floppy tape device driver +# +# CONFIG_AGP is not set +# CONFIG_RAW_DRIVER is not set + +# +# TPM devices +# + +# +# I2C support +# +# CONFIG_I2C is not set + +# +# SPI support +# +# CONFIG_SPI is not set +# CONFIG_SPI_MASTER is not set + +# +# Dallas's 1-wire bus +# +# CONFIG_W1 is not set + +# +# Hardware Monitoring support +# +# CONFIG_HWMON is not set +# CONFIG_HWMON_VID is not set + +# +# Misc devices +# + +# +# Multimedia devices +# +# CONFIG_VIDEO_DEV is not set +CONFIG_VIDEO_V4L2=y + +# +# Digital Video Broadcasting Devices +# +# CONFIG_DVB is not set + +# +# Graphics support +# +# CONFIG_FB is not set + +# +# Sound +# +# CONFIG_SOUND is not set + +# +# USB support +# +# CONFIG_USB_ARCH_HAS_HCD is not set +# CONFIG_USB_ARCH_HAS_OHCI is not set +# CONFIG_USB_ARCH_HAS_EHCI is not set + +# +# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support' +# + +# +# USB Gadget Support +# +CONFIG_USB_GADGET=y +# CONFIG_USB_GADGET_DEBUG_FILES is not set +# CONFIG_USB_GADGET_NET2280 is not set +# CONFIG_USB_GADGET_PXA2XX is not set +# CONFIG_USB_GADGET_GOKU is not set +# CONFIG_USB_GADGET_LH7A40X is not set +# CONFIG_USB_GADGET_OMAP is not set +# CONFIG_USB_GADGET_AT91 is not set +# CONFIG_USB_GADGET_DUMMY_HCD is not set +# CONFIG_USB_GADGET_DUALSPEED is not set + +# +# MMC/SD Card support +# +# CONFIG_MMC is not set + +# +# LED devices +# +# CONFIG_NEW_LEDS is not set + +# +# LED drivers +# + +# +# LED Triggers +# + +# +# InfiniBand support +# + +# +# EDAC - error detection and reporting (RAS) (EXPERIMENTAL) +# + +# +# Real Time Clock +# + +# +# File systems +# +CONFIG_EXT2_FS=y +# CONFIG_EXT2_FS_XATTR is not set +# CONFIG_EXT2_FS_XIP is not set +CONFIG_EXT3_FS=y +CONFIG_EXT3_FS_XATTR=y +# CONFIG_EXT3_FS_POSIX_ACL is not set +# CONFIG_EXT3_FS_SECURITY is not set +CONFIG_JBD=y +# CONFIG_JBD_DEBUG is not set +CONFIG_FS_MBCACHE=y +# CONFIG_REISERFS_FS is not set +# CONFIG_JFS_FS is not set +CONFIG_FS_POSIX_ACL=y +CONFIG_XFS_FS=y +# CONFIG_XFS_QUOTA is not set +# CONFIG_XFS_SECURITY is not set +# CONFIG_XFS_POSIX_ACL is not set +# CONFIG_MINIX_FS is not set +# CONFIG_ROMFS_FS is not set +CONFIG_INOTIFY=y +# CONFIG_QUOTA is not set +CONFIG_DNOTIFY=y +# CONFIG_AUTOFS_FS is not set +CONFIG_AUTOFS4_FS=y +# CONFIG_FUSE_FS is not set + +# +# CD-ROM/DVD Filesystems +# +# CONFIG_ISO9660_FS is not set +# CONFIG_UDF_FS is not set + +# +# DOS/FAT/NT Filesystems +# +# CONFIG_MSDOS_FS is not set +# CONFIG_VFAT_FS is not set +# CONFIG_NTFS_FS is not set + +# +# Pseudo filesystems +# +CONFIG_PROC_FS=y +CONFIG_PROC_KCORE=y +CONFIG_SYSFS=y +CONFIG_TMPFS=y +# CONFIG_HUGETLB_PAGE is not set +CONFIG_RAMFS=y + +# +# Miscellaneous filesystems +# +# CONFIG_HFSPLUS_FS is not set +CONFIG_CRAMFS=y +# CONFIG_VXFS_FS is not set +# CONFIG_HPFS_FS is not set +# CONFIG_QNX4FS_FS is not set +# CONFIG_SYSV_FS is not set +# CONFIG_UFS_FS is not set + +# +# Network File Systems +# +CONFIG_NFS_FS=y +CONFIG_NFS_V3=y +CONFIG_NFS_V3_ACL=y +# CONFIG_NFSD is not set +CONFIG_ROOT_NFS=y +CONFIG_LOCKD=y +CONFIG_LOCKD_V4=y +CONFIG_NFS_ACL_SUPPORT=y +CONFIG_NFS_COMMON=y +CONFIG_SUNRPC=y +CONFIG_SMB_FS=y +# CONFIG_SMB_NLS_DEFAULT is not set +# CONFIG_CIFS is not set +# CONFIG_NCP_FS is not set +# CONFIG_CODA_FS is not set + +# +# Partition Types +# +CONFIG_PARTITION_ADVANCED=y +# CONFIG_ACORN_PARTITION is not set +# CONFIG_OSF_PARTITION is not set +# CONFIG_AMIGA_PARTITION is not set +# CONFIG_ATARI_PARTITION is not set +# CONFIG_MAC_PARTITION is not set +CONFIG_MSDOS_PARTITION=y +# CONFIG_BSD_DISKLABEL is not set +# CONFIG_MINIX_SUBPARTITION is not set +# CONFIG_SOLARIS_X86_PARTITION is not set +# CONFIG_UNIXWARE_DISKLABEL is not set +# CONFIG_LDM_PARTITION is not set +# CONFIG_SGI_PARTITION is not set +# CONFIG_ULTRIX_PARTITION is not set +# CONFIG_SUN_PARTITION is not set +# CONFIG_KARMA_PARTITION is not set +# CONFIG_EFI_PARTITION is not set + +# +# Native Language Support +# +CONFIG_NLS=y +CONFIG_NLS_DEFAULT="iso8859-1" +CONFIG_NLS_CODEPAGE_437=y +# CONFIG_NLS_CODEPAGE_737 is not set +# CONFIG_NLS_CODEPAGE_775 is not set +# CONFIG_NLS_CODEPAGE_850 is not set +# CONFIG_NLS_CODEPAGE_852 is not set +# CONFIG_NLS_CODEPAGE_855 is not set +# CONFIG_NLS_CODEPAGE_857 is not set +# CONFIG_NLS_CODEPAGE_860 is not set +# CONFIG_NLS_CODEPAGE_861 is not set +# CONFIG_NLS_CODEPAGE_862 is not set +# CONFIG_NLS_CODEPAGE_863 is not set +# CONFIG_NLS_CODEPAGE_864 is not set +# CONFIG_NLS_CODEPAGE_865 is not set +# CONFIG_NLS_CODEPAGE_866 is not set +# CONFIG_NLS_CODEPAGE_869 is not set +# CONFIG_NLS_CODEPAGE_936 is not set +# CONFIG_NLS_CODEPAGE_950 is not set +# CONFIG_NLS_CODEPAGE_932 is not set +# CONFIG_NLS_CODEPAGE_949 is not set +# CONFIG_NLS_CODEPAGE_874 is not set +# CONFIG_NLS_ISO8859_8 is not set +# CONFIG_NLS_CODEPAGE_1250 is not set +# CONFIG_NLS_CODEPAGE_1251 is not set +CONFIG_NLS_ASCII=y +CONFIG_NLS_ISO8859_1=y +# CONFIG_NLS_ISO8859_2 is not set +# CONFIG_NLS_ISO8859_3 is not set +# CONFIG_NLS_ISO8859_4 is not set +# CONFIG_NLS_ISO8859_5 is not set +# CONFIG_NLS_ISO8859_6 is not set +# CONFIG_NLS_ISO8859_7 is not set +# CONFIG_NLS_ISO8859_9 is not set +# CONFIG_NLS_ISO8859_13 is not set +# CONFIG_NLS_ISO8859_14 is not set +# CONFIG_NLS_ISO8859_15 is not set +# CONFIG_NLS_KOI8_R is not set +# CONFIG_NLS_KOI8_U is not set +CONFIG_NLS_UTF8=y + +# +# Library routines +# +CONFIG_CRC_CCITT=y +# CONFIG_CRC16 is not set +CONFIG_CRC32=y +# CONFIG_LIBCRC32C is not set +CONFIG_ZLIB_INFLATE=y +CONFIG_ZLIB_DEFLATE=y + +# +# Kernel hacking +# +# CONFIG_PRINTK_TIME is not set +# CONFIG_MAGIC_SYSRQ is not set +CONFIG_DEBUG_KERNEL=y +CONFIG_LOG_BUF_SHIFT=14 +CONFIG_DETECT_SOFTLOCKUP=y +# CONFIG_SCHEDSTATS is not set +# CONFIG_DEBUG_SLAB is not set +# CONFIG_DEBUG_MUTEXES is not set +# CONFIG_DEBUG_SPINLOCK is not set +# CONFIG_DEBUG_SPINLOCK_SLEEP is not set +# CONFIG_DEBUG_KOBJECT is not set +CONFIG_DEBUG_INFO=y +# CONFIG_DEBUG_FS is not set +# CONFIG_DEBUG_VM is not set +# CONFIG_UNWIND_INFO is not set +CONFIG_FORCED_INLINING=y +# CONFIG_RCU_TORTURE_TEST is not set +# CONFIG_DEBUGGER is not set +# CONFIG_KGDB_CONSOLE is not set +CONFIG_BDI_SWITCH=y +# CONFIG_BOOTX_TEXT is not set +# CONFIG_PPC_EARLY_DEBUG is not set + +# +# Security options +# +# CONFIG_KEYS is not set +# CONFIG_SECURITY is not set + +# +# Cryptographic options +# +CONFIG_CRYPTO=y +# CONFIG_CRYPTO_HMAC is not set +# CONFIG_CRYPTO_NULL is not set +# CONFIG_CRYPTO_MD4 is not set +CONFIG_CRYPTO_MD5=y +# CONFIG_CRYPTO_SHA1 is not set +# CONFIG_CRYPTO_SHA256 is not set +# CONFIG_CRYPTO_SHA512 is not set +# CONFIG_CRYPTO_WP512 is not set +# CONFIG_CRYPTO_TGR192 is not set +CONFIG_CRYPTO_DES=y +# CONFIG_CRYPTO_BLOWFISH is not set +# CONFIG_CRYPTO_TWOFISH is not set +# CONFIG_CRYPTO_SERPENT is not set +# CONFIG_CRYPTO_AES is not set +# CONFIG_CRYPTO_CAST5 is not set +# CONFIG_CRYPTO_CAST6 is not set +# CONFIG_CRYPTO_TEA is not set +# CONFIG_CRYPTO_ARC4 is not set +# CONFIG_CRYPTO_KHAZAD is not set +# CONFIG_CRYPTO_ANUBIS is not set +# CONFIG_CRYPTO_DEFLATE is not set +# CONFIG_CRYPTO_MICHAEL_MIC is not set +# CONFIG_CRYPTO_CRC32C is not set +# CONFIG_CRYPTO_TEST is not set + +# +# Hardware crypto devices +# diff --git a/arch/powerpc/configs/mpc8313_rdb_defconfig b/arch/powerpc/configs/mpc8313_rdb_defconfig new file mode 100644 index 0000000..f875237 --- /dev/null +++ b/arch/powerpc/configs/mpc8313_rdb_defconfig @@ -0,0 +1,1409 @@ +# +# Automatically generated make config: don't edit +# Linux kernel version: 2.6.20 +# Wed Feb 7 22:08:04 2007 +# +# CONFIG_PPC64 is not set +CONFIG_PPC32=y +CONFIG_PPC_MERGE=y +CONFIG_MMU=y +CONFIG_GENERIC_HARDIRQS=y +CONFIG_IRQ_PER_CPU=y +CONFIG_RWSEM_XCHGADD_ALGORITHM=y +CONFIG_ARCH_HAS_ILOG2_U32=y +CONFIG_GENERIC_HWEIGHT=y +CONFIG_GENERIC_CALIBRATE_DELAY=y +CONFIG_GENERIC_FIND_NEXT_BIT=y +CONFIG_PPC=y +CONFIG_EARLY_PRINTK=y +CONFIG_GENERIC_NVRAM=y +CONFIG_SCHED_NO_NO_OMIT_FRAME_POINTER=y +CONFIG_ARCH_MAY_HAVE_PC_FDC=y +CONFIG_PPC_OF=y +CONFIG_PPC_UDBG_16550=y +# CONFIG_GENERIC_TBSYNC is not set +CONFIG_AUDIT_ARCH=y +CONFIG_GENERIC_BUG=y +CONFIG_DEFAULT_UIMAGE=y + +# +# Processor support +# +# CONFIG_CLASSIC32 is not set +# CONFIG_PPC_82xx is not set +CONFIG_PPC_83xx=y +# CONFIG_PPC_85xx is not set +# CONFIG_PPC_86xx is not set +# CONFIG_PPC_8xx is not set +# CONFIG_40x is not set +# CONFIG_44x is not set +# CONFIG_E200 is not set +CONFIG_6xx=y +CONFIG_83xx=y +CONFIG_PPC_FPU=y +# CONFIG_PPC_DCR_NATIVE is not set +# CONFIG_PPC_DCR_MMIO is not set +CONFIG_PPC_STD_MMU=y +CONFIG_PPC_STD_MMU_32=y +# CONFIG_SMP is not set +CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config" + +# +# Code maturity level options +# +CONFIG_EXPERIMENTAL=y +CONFIG_BROKEN_ON_SMP=y +CONFIG_INIT_ENV_ARG_LIMIT=32 + +# +# General setup +# +CONFIG_LOCALVERSION="" +CONFIG_LOCALVERSION_AUTO=y +CONFIG_SWAP=y +CONFIG_SYSVIPC=y +# CONFIG_IPC_NS is not set +# CONFIG_POSIX_MQUEUE is not set +# CONFIG_BSD_PROCESS_ACCT is not set +# CONFIG_TASKSTATS is not set +# CONFIG_UTS_NS is not set +# CONFIG_AUDIT is not set +# CONFIG_IKCONFIG is not set +CONFIG_SYSFS_DEPRECATED=y +# CONFIG_RELAY is not set +CONFIG_INITRAMFS_SOURCE="" +# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set +CONFIG_SYSCTL=y +CONFIG_EMBEDDED=y +CONFIG_SYSCTL_SYSCALL=y +# CONFIG_KALLSYMS is not set +CONFIG_HOTPLUG=y +CONFIG_PRINTK=y +CONFIG_BUG=y +CONFIG_ELF_CORE=y +CONFIG_BASE_FULL=y +CONFIG_FUTEX=y +# CONFIG_EPOLL is not set +CONFIG_SHMEM=y +CONFIG_SLAB=y +CONFIG_VM_EVENT_COUNTERS=y +CONFIG_RT_MUTEXES=y +# CONFIG_TINY_SHMEM is not set +CONFIG_BASE_SMALL=0 +# CONFIG_SLOB is not set + +# +# Loadable module support +# +CONFIG_MODULES=y +CONFIG_MODULE_UNLOAD=y +# CONFIG_MODULE_FORCE_UNLOAD is not set +# CONFIG_MODVERSIONS is not set +# CONFIG_MODULE_SRCVERSION_ALL is not set +# CONFIG_KMOD is not set + +# +# Block layer +# +CONFIG_BLOCK=y +# CONFIG_LBD is not set +# CONFIG_BLK_DEV_IO_TRACE is not set +# CONFIG_LSF is not set + +# +# IO Schedulers +# +CONFIG_IOSCHED_NOOP=y +CONFIG_IOSCHED_AS=y +CONFIG_IOSCHED_DEADLINE=y +CONFIG_IOSCHED_CFQ=y +CONFIG_DEFAULT_AS=y +# CONFIG_DEFAULT_DEADLINE is not set +# CONFIG_DEFAULT_CFQ is not set +# CONFIG_DEFAULT_NOOP is not set +CONFIG_DEFAULT_IOSCHED="anticipatory" +CONFIG_PPC_GEN550=y +# CONFIG_WANT_EARLY_SERIAL is not set + +# +# Platform support +# +CONFIG_MPC8313_RDB=y +# CONFIG_MPC832x_MDS is not set +# CONFIG_MPC834x_SYS is not set +# CONFIG_MPC834x_ITX is not set +# CONFIG_MPC8360E_PB is not set +CONFIG_PPC_MPC831x=y +# CONFIG_MPIC is not set + +# +# Kernel options +# +# CONFIG_HIGHMEM is not set +# CONFIG_HZ_100 is not set +CONFIG_HZ_250=y +# CONFIG_HZ_300 is not set +# CONFIG_HZ_1000 is not set +CONFIG_HZ=250 +CONFIG_PREEMPT_NONE=y +# CONFIG_PREEMPT_VOLUNTARY is not set +# CONFIG_PREEMPT is not set +CONFIG_BINFMT_ELF=y +# CONFIG_BINFMT_MISC is not set +CONFIG_ARCH_ENABLE_MEMORY_HOTPLUG=y +CONFIG_ARCH_FLATMEM_ENABLE=y +CONFIG_ARCH_POPULATES_NODE_MAP=y +CONFIG_SELECT_MEMORY_MODEL=y +CONFIG_FLATMEM_MANUAL=y +# CONFIG_DISCONTIGMEM_MANUAL is not set +# CONFIG_SPARSEMEM_MANUAL is not set +CONFIG_FLATMEM=y +CONFIG_FLAT_NODE_MEM_MAP=y +# CONFIG_SPARSEMEM_STATIC is not set +CONFIG_SPLIT_PTLOCK_CPUS=4 +# CONFIG_RESOURCES_64BIT is not set +CONFIG_PROC_DEVICETREE=y +# CONFIG_CMDLINE_BOOL is not set +# CONFIG_PM is not set +CONFIG_SECCOMP=y +CONFIG_ISA_DMA_API=y + +# +# Bus options +# +CONFIG_GENERIC_ISA_DMA=y +# CONFIG_MPIC_WEIRD is not set +# CONFIG_PPC_I8259 is not set +CONFIG_PPC_INDIRECT_PCI=y +CONFIG_FSL_SOC=y +CONFIG_PCI=y +CONFIG_PCI_DOMAINS=y +# CONFIG_PCIEPORTBUS is not set +# CONFIG_PCI_DEBUG is not set + +# +# PCCARD (PCMCIA/CardBus) support +# +# CONFIG_PCCARD is not set + +# +# PCI Hotplug Support +# +# CONFIG_HOTPLUG_PCI is not set + +# +# Advanced setup +# +# CONFIG_ADVANCED_OPTIONS is not set + +# +# Default settings for advanced configuration options are used +# +CONFIG_HIGHMEM_START=0xfe000000 +CONFIG_LOWMEM_SIZE=0x30000000 +CONFIG_KERNEL_START=0xc0000000 +CONFIG_TASK_SIZE=0x80000000 +CONFIG_BOOT_LOAD=0x00800000 + +# +# Networking +# +CONFIG_NET=y + +# +# Networking options +# +# CONFIG_NETDEBUG is not set +CONFIG_PACKET=y +# CONFIG_PACKET_MMAP is not set +CONFIG_UNIX=y +CONFIG_XFRM=y +# CONFIG_XFRM_USER is not set +# CONFIG_XFRM_SUB_POLICY is not set +# CONFIG_NET_KEY is not set +CONFIG_INET=y +CONFIG_IP_MULTICAST=y +# CONFIG_IP_ADVANCED_ROUTER is not set +CONFIG_IP_FIB_HASH=y +CONFIG_IP_PNP=y +CONFIG_IP_PNP_DHCP=y +CONFIG_IP_PNP_BOOTP=y +# CONFIG_IP_PNP_RARP is not set +# CONFIG_NET_IPIP is not set +# CONFIG_NET_IPGRE is not set +# CONFIG_IP_MROUTE is not set +# CONFIG_ARPD is not set +CONFIG_SYN_COOKIES=y +# CONFIG_INET_AH is not set +# CONFIG_INET_ESP is not set +# CONFIG_INET_IPCOMP is not set +# CONFIG_INET_XFRM_TUNNEL is not set +# CONFIG_INET_TUNNEL is not set +CONFIG_INET_XFRM_MODE_TRANSPORT=y +CONFIG_INET_XFRM_MODE_TUNNEL=y +CONFIG_INET_XFRM_MODE_BEET=y +CONFIG_INET_DIAG=y +CONFIG_INET_TCP_DIAG=y +# CONFIG_TCP_CONG_ADVANCED is not set +CONFIG_TCP_CONG_CUBIC=y +CONFIG_DEFAULT_TCP_CONG="cubic" +# CONFIG_TCP_MD5SIG is not set +# CONFIG_IPV6 is not set +# CONFIG_INET6_XFRM_TUNNEL is not set +# CONFIG_INET6_TUNNEL is not set +# CONFIG_NETWORK_SECMARK is not set +# CONFIG_NETFILTER is not set + +# +# DCCP Configuration (EXPERIMENTAL) +# +# CONFIG_IP_DCCP is not set + +# +# SCTP Configuration (EXPERIMENTAL) +# +# CONFIG_IP_SCTP is not set + +# +# TIPC Configuration (EXPERIMENTAL) +# +# CONFIG_TIPC is not set +# CONFIG_ATM is not set +# CONFIG_BRIDGE is not set +# CONFIG_VLAN_8021Q is not set +# CONFIG_DECNET is not set +# CONFIG_LLC2 is not set +# CONFIG_IPX is not set +# CONFIG_ATALK is not set +# CONFIG_X25 is not set +# CONFIG_LAPB is not set +# CONFIG_ECONET is not set +# CONFIG_WAN_ROUTER is not set + +# +# QoS and/or fair queueing +# +# CONFIG_NET_SCHED is not set + +# +# Network testing +# +# CONFIG_NET_PKTGEN is not set +# CONFIG_HAMRADIO is not set +# CONFIG_IRDA is not set +# CONFIG_BT is not set +# CONFIG_IEEE80211 is not set + +# +# Device Drivers +# + +# +# Generic Driver Options +# +CONFIG_STANDALONE=y +CONFIG_PREVENT_FIRMWARE_BUILD=y +# CONFIG_FW_LOADER is not set +# CONFIG_DEBUG_DRIVER is not set +# CONFIG_SYS_HYPERVISOR is not set + +# +# Connector - unified userspace <-> kernelspace linker +# +# CONFIG_CONNECTOR is not set + +# +# Memory Technology Devices (MTD) +# +CONFIG_MTD=y +# CONFIG_MTD_DEBUG is not set +# CONFIG_MTD_CONCAT is not set +# CONFIG_MTD_PARTITIONS is not set + +# +# User Modules And Translation Layers +# +CONFIG_MTD_CHAR=y +# CONFIG_MTD_BLKDEVS is not set +# CONFIG_MTD_BLOCK is not set +# CONFIG_MTD_BLOCK_RO is not set +# CONFIG_FTL is not set +# CONFIG_NFTL is not set +# CONFIG_INFTL is not set +# CONFIG_RFD_FTL is not set +# CONFIG_SSFDC is not set + +# +# RAM/ROM/Flash chip drivers +# +CONFIG_MTD_CFI=y +# CONFIG_MTD_JEDECPROBE is not set +CONFIG_MTD_GEN_PROBE=y +# CONFIG_MTD_CFI_ADV_OPTIONS is not set +CONFIG_MTD_MAP_BANK_WIDTH_1=y +CONFIG_MTD_MAP_BANK_WIDTH_2=y +CONFIG_MTD_MAP_BANK_WIDTH_4=y +# CONFIG_MTD_MAP_BANK_WIDTH_8 is not set +# CONFIG_MTD_MAP_BANK_WIDTH_16 is not set +# CONFIG_MTD_MAP_BANK_WIDTH_32 is not set +CONFIG_MTD_CFI_I1=y +CONFIG_MTD_CFI_I2=y +# CONFIG_MTD_CFI_I4 is not set +# CONFIG_MTD_CFI_I8 is not set +# CONFIG_MTD_CFI_INTELEXT is not set +CONFIG_MTD_CFI_AMDSTD=y +# CONFIG_MTD_CFI_STAA is not set +CONFIG_MTD_CFI_UTIL=y +# CONFIG_MTD_RAM is not set +# CONFIG_MTD_ROM is not set +# CONFIG_MTD_ABSENT is not set +# CONFIG_MTD_OBSOLETE_CHIPS is not set + +# +# Mapping drivers for chip access +# +# CONFIG_MTD_COMPLEX_MAPPINGS is not set +CONFIG_MTD_PHYSMAP=y +CONFIG_MTD_PHYSMAP_START=0xfe000000 +CONFIG_MTD_PHYSMAP_LEN=0x1000000 +CONFIG_MTD_PHYSMAP_BANKWIDTH=2 +# CONFIG_MTD_PHYSMAP_OF is not set +# CONFIG_MTD_PLATRAM is not set + +# +# Self-contained MTD device drivers +# +# CONFIG_MTD_PMC551 is not set +# CONFIG_MTD_DATAFLASH is not set +# CONFIG_MTD_M25P80 is not set +# CONFIG_MTD_SLRAM is not set +# CONFIG_MTD_PHRAM is not set +# CONFIG_MTD_MTDRAM is not set +# CONFIG_MTD_BLOCK2MTD is not set + +# +# Disk-On-Chip Device Drivers +# +# CONFIG_MTD_DOC2000 is not set +# CONFIG_MTD_DOC2001 is not set +# CONFIG_MTD_DOC2001PLUS is not set + +# +# NAND Flash Device Drivers +# +# CONFIG_MTD_NAND is not set +# CONFIG_MTD_NAND_CAFE is not set + +# +# OneNAND Flash Device Drivers +# +# CONFIG_MTD_ONENAND is not set + +# +# Parallel port support +# +# CONFIG_PARPORT is not set + +# +# Plug and Play support +# + +# +# Block devices +# +# CONFIG_BLK_DEV_FD is not set +# CONFIG_BLK_CPQ_DA is not set +# CONFIG_BLK_CPQ_CISS_DA is not set +# CONFIG_BLK_DEV_DAC960 is not set +# CONFIG_BLK_DEV_UMEM is not set +# CONFIG_BLK_DEV_COW_COMMON is not set +CONFIG_BLK_DEV_LOOP=y +# CONFIG_BLK_DEV_CRYPTOLOOP is not set +# CONFIG_BLK_DEV_NBD is not set +# CONFIG_BLK_DEV_SX8 is not set +# CONFIG_BLK_DEV_UB is not set +CONFIG_BLK_DEV_RAM=y +CONFIG_BLK_DEV_RAM_COUNT=16 +CONFIG_BLK_DEV_RAM_SIZE=32768 +CONFIG_BLK_DEV_RAM_BLOCKSIZE=1024 +CONFIG_BLK_DEV_INITRD=y +# CONFIG_CDROM_PKTCDVD is not set +# CONFIG_ATA_OVER_ETH is not set + +# +# Misc devices +# +# CONFIG_SGI_IOC4 is not set +# CONFIG_TIFM_CORE is not set + +# +# ATA/ATAPI/MFM/RLL support +# +# CONFIG_IDE is not set + +# +# SCSI device support +# +# CONFIG_RAID_ATTRS is not set +CONFIG_SCSI=y +# CONFIG_SCSI_TGT is not set +# CONFIG_SCSI_NETLINK is not set +CONFIG_SCSI_PROC_FS=y + +# +# SCSI support type (disk, tape, CD-ROM) +# +# CONFIG_BLK_DEV_SD is not set +# CONFIG_CHR_DEV_ST is not set +# CONFIG_CHR_DEV_OSST is not set +# CONFIG_BLK_DEV_SR is not set +CONFIG_CHR_DEV_SG=y +# CONFIG_CHR_DEV_SCH is not set + +# +# Some SCSI devices (e.g. CD jukebox) support multiple LUNs +# +# CONFIG_SCSI_MULTI_LUN is not set +# CONFIG_SCSI_CONSTANTS is not set +# CONFIG_SCSI_LOGGING is not set +# CONFIG_SCSI_SCAN_ASYNC is not set + +# +# SCSI Transports +# +CONFIG_SCSI_SPI_ATTRS=y +# CONFIG_SCSI_FC_ATTRS is not set +# CONFIG_SCSI_ISCSI_ATTRS is not set +# CONFIG_SCSI_SAS_ATTRS is not set +# CONFIG_SCSI_SAS_LIBSAS is not set + +# +# SCSI low-level drivers +# +# CONFIG_ISCSI_TCP is not set +# CONFIG_BLK_DEV_3W_XXXX_RAID is not set +# CONFIG_SCSI_3W_9XXX is not set +# CONFIG_SCSI_ACARD is not set +# CONFIG_SCSI_AACRAID is not set +# CONFIG_SCSI_AIC7XXX is not set +# CONFIG_SCSI_AIC7XXX_OLD is not set +# CONFIG_SCSI_AIC79XX is not set +# CONFIG_SCSI_AIC94XX is not set +# CONFIG_SCSI_DPT_I2O is not set +# CONFIG_SCSI_ARCMSR is not set +# CONFIG_MEGARAID_NEWGEN is not set +# CONFIG_MEGARAID_LEGACY is not set +# CONFIG_MEGARAID_SAS is not set +# CONFIG_SCSI_HPTIOP is not set +# CONFIG_SCSI_BUSLOGIC is not set +# CONFIG_SCSI_DMX3191D is not set +# CONFIG_SCSI_EATA is not set +# CONFIG_SCSI_FUTURE_DOMAIN is not set +# CONFIG_SCSI_GDTH is not set +# CONFIG_SCSI_IPS is not set +# CONFIG_SCSI_INITIO is not set +# CONFIG_SCSI_INIA100 is not set +# CONFIG_SCSI_STEX is not set +# CONFIG_SCSI_SYM53C8XX_2 is not set +# CONFIG_SCSI_QLOGIC_1280 is not set +# CONFIG_SCSI_QLA_FC is not set +# CONFIG_SCSI_QLA_ISCSI is not set +# CONFIG_SCSI_LPFC is not set +# CONFIG_SCSI_DC395x is not set +# CONFIG_SCSI_DC390T is not set +# CONFIG_SCSI_NSP32 is not set +# CONFIG_SCSI_DEBUG is not set +# CONFIG_SCSI_SRP is not set + +# +# Serial ATA (prod) and Parallel ATA (experimental) drivers +# +# CONFIG_ATA is not set + +# +# Multi-device support (RAID and LVM) +# +CONFIG_MD=y +CONFIG_BLK_DEV_MD=y +CONFIG_MD_LINEAR=y +CONFIG_MD_RAID0=y +CONFIG_MD_RAID1=y +# CONFIG_MD_RAID10 is not set +# CONFIG_MD_RAID456 is not set +# CONFIG_MD_MULTIPATH is not set +# CONFIG_MD_FAULTY is not set +# CONFIG_BLK_DEV_DM is not set + +# +# Fusion MPT device support +# +# CONFIG_FUSION is not set +# CONFIG_FUSION_SPI is not set +# CONFIG_FUSION_FC is not set +# CONFIG_FUSION_SAS is not set + +# +# IEEE 1394 (FireWire) support +# +# CONFIG_IEEE1394 is not set + +# +# I2O device support +# +# CONFIG_I2O is not set + +# +# Macintosh device drivers +# +# CONFIG_MAC_EMUMOUSEBTN is not set +# CONFIG_WINDFARM is not set + +# +# Network device support +# +CONFIG_NETDEVICES=y +# CONFIG_DUMMY is not set +# CONFIG_BONDING is not set +# CONFIG_EQUALIZER is not set +# CONFIG_TUN is not set + +# +# ARCnet devices +# +# CONFIG_ARCNET is not set + +# +# PHY device support +# +CONFIG_PHYLIB=y + +# +# MII PHY device drivers +# +# CONFIG_MARVELL_PHY is not set +# CONFIG_DAVICOM_PHY is not set +# CONFIG_QSEMI_PHY is not set +# CONFIG_LXT_PHY is not set +CONFIG_CICADA_PHY=y +# CONFIG_VITESSE_PHY is not set +# CONFIG_SMSC_PHY is not set +# CONFIG_BROADCOM_PHY is not set +# CONFIG_FIXED_PHY is not set + +# +# Ethernet (10 or 100Mbit) +# +CONFIG_NET_ETHERNET=y +CONFIG_MII=y +# CONFIG_HAPPYMEAL is not set +# CONFIG_SUNGEM is not set +# CONFIG_CASSINI is not set +# CONFIG_NET_VENDOR_3COM is not set + +# +# Tulip family network device support +# +# CONFIG_NET_TULIP is not set +# CONFIG_HP100 is not set +CONFIG_NET_PCI=y +# CONFIG_PCNET32 is not set +# CONFIG_AMD8111_ETH is not set +# CONFIG_ADAPTEC_STARFIRE is not set +# CONFIG_B44 is not set +# CONFIG_FORCEDETH is not set +# CONFIG_DGRS is not set +# CONFIG_EEPRO100 is not set +CONFIG_E100=y +# CONFIG_FEALNX is not set +# CONFIG_NATSEMI is not set +# CONFIG_NE2K_PCI is not set +# CONFIG_8139CP is not set +# CONFIG_8139TOO is not set +# CONFIG_SIS900 is not set +# CONFIG_EPIC100 is not set +# CONFIG_SUNDANCE is not set +# CONFIG_TLAN is not set +# CONFIG_VIA_RHINE is not set + +# +# Ethernet (1000 Mbit) +# +# CONFIG_ACENIC is not set +# CONFIG_DL2K is not set +# CONFIG_E1000 is not set +# CONFIG_NS83820 is not set +# CONFIG_HAMACHI is not set +# CONFIG_YELLOWFIN is not set +# CONFIG_R8169 is not set +# CONFIG_SIS190 is not set +# CONFIG_SKGE is not set +# CONFIG_SKY2 is not set +# CONFIG_SK98LIN is not set +# CONFIG_VIA_VELOCITY is not set +# CONFIG_TIGON3 is not set +# CONFIG_BNX2 is not set +CONFIG_GIANFAR=y +CONFIG_GFAR_NAPI=y +# CONFIG_QLA3XXX is not set + +# +# Ethernet (10000 Mbit) +# +# CONFIG_CHELSIO_T1 is not set +# CONFIG_IXGB is not set +# CONFIG_S2IO is not set +# CONFIG_MYRI10GE is not set +# CONFIG_NETXEN_NIC is not set + +# +# Token Ring devices +# +# CONFIG_TR is not set + +# +# Wireless LAN (non-hamradio) +# +# CONFIG_NET_RADIO is not set + +# +# Wan interfaces +# +# CONFIG_WAN is not set +# CONFIG_FDDI is not set +# CONFIG_HIPPI is not set +# CONFIG_PPP is not set +# CONFIG_SLIP is not set +# CONFIG_NET_FC is not set +# CONFIG_SHAPER is not set +# CONFIG_NETCONSOLE is not set +# CONFIG_NETPOLL is not set +# CONFIG_NET_POLL_CONTROLLER is not set + +# +# ISDN subsystem +# +# CONFIG_ISDN is not set + +# +# Telephony Support +# +# CONFIG_PHONE is not set + +# +# Input device support +# +CONFIG_INPUT=y +# CONFIG_INPUT_FF_MEMLESS is not set + +# +# Userland interfaces +# +# CONFIG_INPUT_MOUSEDEV is not set +# CONFIG_INPUT_JOYDEV is not set +# CONFIG_INPUT_TSDEV is not set +# CONFIG_INPUT_EVDEV is not set +# CONFIG_INPUT_EVBUG is not set + +# +# Input Device Drivers +# +# CONFIG_INPUT_KEYBOARD is not set +# CONFIG_INPUT_MOUSE is not set +# CONFIG_INPUT_JOYSTICK is not set +# CONFIG_INPUT_TOUCHSCREEN is not set +# CONFIG_INPUT_MISC is not set + +# +# Hardware I/O ports +# +# CONFIG_SERIO is not set +# CONFIG_GAMEPORT is not set + +# +# Character devices +# +# CONFIG_VT is not set +# CONFIG_SERIAL_NONSTANDARD is not set + +# +# Serial drivers +# +CONFIG_SERIAL_8250=y +CONFIG_SERIAL_8250_CONSOLE=y +CONFIG_SERIAL_8250_PCI=y +CONFIG_SERIAL_8250_NR_UARTS=4 +CONFIG_SERIAL_8250_RUNTIME_UARTS=4 +# CONFIG_SERIAL_8250_EXTENDED is not set + +# +# Non-8250 serial port support +# +# CONFIG_SERIAL_UARTLITE is not set +CONFIG_SERIAL_CORE=y +CONFIG_SERIAL_CORE_CONSOLE=y +# CONFIG_SERIAL_JSM is not set +CONFIG_UNIX98_PTYS=y +CONFIG_LEGACY_PTYS=y +CONFIG_LEGACY_PTY_COUNT=256 + +# +# IPMI +# +# CONFIG_IPMI_HANDLER is not set + +# +# Watchdog Cards +# +CONFIG_WATCHDOG=y +# CONFIG_WATCHDOG_NOWAYOUT is not set + +# +# Watchdog Device Drivers +# +# CONFIG_SOFT_WATCHDOG is not set +CONFIG_83xx_WDT=y + +# +# PCI-based Watchdog Cards +# +# CONFIG_PCIPCWATCHDOG is not set +# CONFIG_WDTPCI is not set + +# +# USB-based Watchdog Cards +# +# CONFIG_USBPCWATCHDOG is not set +CONFIG_HW_RANDOM=y +# CONFIG_NVRAM is not set +# CONFIG_GEN_RTC is not set +# CONFIG_DTLK is not set +# CONFIG_R3964 is not set +# CONFIG_APPLICOM is not set +# CONFIG_AGP is not set +# CONFIG_DRM is not set +# CONFIG_RAW_DRIVER is not set + +# +# TPM devices +# +# CONFIG_TCG_TPM is not set + +# +# I2C support +# +CONFIG_I2C=y +CONFIG_I2C_CHARDEV=y + +# +# I2C Algorithms +# +# CONFIG_I2C_ALGOBIT is not set +# CONFIG_I2C_ALGOPCF is not set +# CONFIG_I2C_ALGOPCA is not set + +# +# I2C Hardware Bus support +# +# CONFIG_I2C_ALI1535 is not set +# CONFIG_I2C_ALI1563 is not set +# CONFIG_I2C_ALI15X3 is not set +# CONFIG_I2C_AMD756 is not set +# CONFIG_I2C_AMD8111 is not set +# CONFIG_I2C_I801 is not set +# CONFIG_I2C_I810 is not set +# CONFIG_I2C_PIIX4 is not set +CONFIG_I2C_MPC=y +# CONFIG_I2C_NFORCE2 is not set +# CONFIG_I2C_OCORES is not set +# CONFIG_I2C_PARPORT_LIGHT is not set +# CONFIG_I2C_PROSAVAGE is not set +# CONFIG_I2C_SAVAGE4 is not set +# CONFIG_I2C_SIS5595 is not set +# CONFIG_I2C_SIS630 is not set +# CONFIG_I2C_SIS96X is not set +# CONFIG_I2C_STUB is not set +# CONFIG_I2C_VIA is not set +# CONFIG_I2C_VIAPRO is not set +# CONFIG_I2C_VOODOO3 is not set +# CONFIG_I2C_PCA_ISA is not set + +# +# Miscellaneous I2C Chip support +# +# CONFIG_SENSORS_DS1337 is not set +# CONFIG_SENSORS_DS1374 is not set +# CONFIG_SENSORS_EEPROM is not set +# CONFIG_SENSORS_PCF8574 is not set +# CONFIG_SENSORS_PCA9539 is not set +# CONFIG_SENSORS_PCF8591 is not set +# CONFIG_SENSORS_M41T00 is not set +# CONFIG_SENSORS_MAX6875 is not set +# CONFIG_I2C_DEBUG_CORE is not set +# CONFIG_I2C_DEBUG_ALGO is not set +# CONFIG_I2C_DEBUG_BUS is not set +# CONFIG_I2C_DEBUG_CHIP is not set + +# +# SPI support +# +CONFIG_SPI=y +# CONFIG_SPI_DEBUG is not set +CONFIG_SPI_MASTER=y + +# +# SPI Master Controller Drivers +# +CONFIG_SPI_BITBANG=y +CONFIG_SPI_MPC83xx=y + +# +# SPI Protocol Masters +# + +# +# Dallas's 1-wire bus +# +# CONFIG_W1 is not set + +# +# Hardware Monitoring support +# +CONFIG_HWMON=y +# CONFIG_HWMON_VID is not set +# CONFIG_SENSORS_ABITUGURU is not set +# CONFIG_SENSORS_ADM1021 is not set +# CONFIG_SENSORS_ADM1025 is not set +# CONFIG_SENSORS_ADM1026 is not set +# CONFIG_SENSORS_ADM1031 is not set +# CONFIG_SENSORS_ADM9240 is not set +# CONFIG_SENSORS_ASB100 is not set +# CONFIG_SENSORS_ATXP1 is not set +# CONFIG_SENSORS_DS1621 is not set +# CONFIG_SENSORS_F71805F is not set +# CONFIG_SENSORS_FSCHER is not set +# CONFIG_SENSORS_FSCPOS is not set +# CONFIG_SENSORS_GL518SM is not set +# CONFIG_SENSORS_GL520SM is not set +# CONFIG_SENSORS_IT87 is not set +# CONFIG_SENSORS_LM63 is not set +# CONFIG_SENSORS_LM70 is not set +# CONFIG_SENSORS_LM75 is not set +# CONFIG_SENSORS_LM77 is not set +# CONFIG_SENSORS_LM78 is not set +# CONFIG_SENSORS_LM80 is not set +# CONFIG_SENSORS_LM83 is not set +# CONFIG_SENSORS_LM85 is not set +# CONFIG_SENSORS_LM87 is not set +# CONFIG_SENSORS_LM90 is not set +# CONFIG_SENSORS_LM92 is not set +# CONFIG_SENSORS_MAX1619 is not set +# CONFIG_SENSORS_PC87360 is not set +# CONFIG_SENSORS_PC87427 is not set +# CONFIG_SENSORS_SIS5595 is not set +# CONFIG_SENSORS_SMSC47M1 is not set +# CONFIG_SENSORS_SMSC47M192 is not set +# CONFIG_SENSORS_SMSC47B397 is not set +# CONFIG_SENSORS_VIA686A is not set +# CONFIG_SENSORS_VT1211 is not set +# CONFIG_SENSORS_VT8231 is not set +# CONFIG_SENSORS_W83781D is not set +# CONFIG_SENSORS_W83791D is not set +# CONFIG_SENSORS_W83792D is not set +# CONFIG_SENSORS_W83793 is not set +# CONFIG_SENSORS_W83L785TS is not set +# CONFIG_SENSORS_W83627HF is not set +# CONFIG_SENSORS_W83627EHF is not set +# CONFIG_HWMON_DEBUG_CHIP is not set + +# +# Multimedia devices +# +# CONFIG_VIDEO_DEV is not set + +# +# Digital Video Broadcasting Devices +# +# CONFIG_DVB is not set +# CONFIG_USB_DABUSB is not set + +# +# Graphics support +# +CONFIG_FIRMWARE_EDID=y +# CONFIG_FB is not set +# CONFIG_FB_IBM_GXT4500 is not set +# CONFIG_BACKLIGHT_LCD_SUPPORT is not set + +# +# Sound +# +# CONFIG_SOUND is not set + +# +# HID Devices +# +CONFIG_HID=y + +# +# USB support +# +CONFIG_USB_ARCH_HAS_HCD=y +CONFIG_USB_ARCH_HAS_OHCI=y +CONFIG_USB_ARCH_HAS_EHCI=y +CONFIG_USB=y +# CONFIG_USB_DEBUG is not set + +# +# Miscellaneous USB options +# +CONFIG_USB_DEVICEFS=y +# CONFIG_USB_BANDWIDTH is not set +# CONFIG_USB_DYNAMIC_MINORS is not set +# CONFIG_USB_OTG is not set + +# +# USB Host Controller Drivers +# +CONFIG_USB_EHCI_HCD=y +# CONFIG_USB_EHCI_SPLIT_ISO is not set +# CONFIG_USB_EHCI_ROOT_HUB_TT is not set +# CONFIG_USB_EHCI_TT_NEWSCHED is not set +# CONFIG_USB_ISP116X_HCD is not set +CONFIG_USB_OHCI_HCD=y +# CONFIG_USB_OHCI_BIG_ENDIAN is not set +CONFIG_USB_OHCI_LITTLE_ENDIAN=y +CONFIG_USB_UHCI_HCD=y +# CONFIG_USB_SL811_HCD is not set + +# +# USB Device Class drivers +# +# CONFIG_USB_ACM is not set +# CONFIG_USB_PRINTER is not set + +# +# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support' +# + +# +# may also be needed; see USB_STORAGE Help for more information +# +CONFIG_USB_STORAGE=y +# CONFIG_USB_STORAGE_DEBUG is not set +# CONFIG_USB_STORAGE_DATAFAB is not set +# CONFIG_USB_STORAGE_FREECOM is not set +# CONFIG_USB_STORAGE_DPCM is not set +# CONFIG_USB_STORAGE_USBAT is not set +# CONFIG_USB_STORAGE_SDDR09 is not set +# CONFIG_USB_STORAGE_SDDR55 is not set +# CONFIG_USB_STORAGE_JUMPSHOT is not set +# CONFIG_USB_STORAGE_ALAUDA is not set +# CONFIG_USB_STORAGE_KARMA is not set +# CONFIG_USB_LIBUSUAL is not set + +# +# USB Input Devices +# +# CONFIG_USB_HID is not set + +# +# USB HID Boot Protocol drivers +# +# CONFIG_USB_KBD is not set +# CONFIG_USB_MOUSE is not set +# CONFIG_USB_AIPTEK is not set +# CONFIG_USB_WACOM is not set +# CONFIG_USB_ACECAD is not set +# CONFIG_USB_KBTAB is not set +# CONFIG_USB_POWERMATE is not set +# CONFIG_USB_TOUCHSCREEN is not set +# CONFIG_USB_YEALINK is not set +# CONFIG_USB_XPAD is not set +# CONFIG_USB_ATI_REMOTE is not set +# CONFIG_USB_ATI_REMOTE2 is not set +# CONFIG_USB_KEYSPAN_REMOTE is not set +# CONFIG_USB_APPLETOUCH is not set + +# +# USB Imaging devices +# +# CONFIG_USB_MDC800 is not set +# CONFIG_USB_MICROTEK is not set + +# +# USB Network Adapters +# +# CONFIG_USB_CATC is not set +# CONFIG_USB_KAWETH is not set +# CONFIG_USB_PEGASUS is not set +# CONFIG_USB_RTL8150 is not set +# CONFIG_USB_USBNET_MII is not set +# CONFIG_USB_USBNET is not set +CONFIG_USB_MON=y + +# +# USB port drivers +# + +# +# USB Serial Converter support +# +# CONFIG_USB_SERIAL is not set + +# +# USB Miscellaneous drivers +# +# CONFIG_USB_EMI62 is not set +# CONFIG_USB_EMI26 is not set +# CONFIG_USB_ADUTUX is not set +# CONFIG_USB_AUERSWALD is not set +# CONFIG_USB_RIO500 is not set +# CONFIG_USB_LEGOTOWER is not set +# CONFIG_USB_LCD is not set +# CONFIG_USB_LED is not set +# CONFIG_USB_CYPRESS_CY7C63 is not set +# CONFIG_USB_CYTHERM is not set +# CONFIG_USB_PHIDGET is not set +# CONFIG_USB_IDMOUSE is not set +# CONFIG_USB_FTDI_ELAN is not set +# CONFIG_USB_APPLEDISPLAY is not set +# CONFIG_USB_SISUSBVGA is not set +# CONFIG_USB_LD is not set +# CONFIG_USB_TRANCEVIBRATOR is not set +# CONFIG_USB_TEST is not set + +# +# USB DSL modem support +# + +# +# USB Gadget Support +# +CONFIG_USB_GADGET=y +# CONFIG_USB_GADGET_DEBUG_FILES is not set +CONFIG_USB_GADGET_SELECTED=y +CONFIG_USB_GADGET_NET2280=y +CONFIG_USB_NET2280=y +# CONFIG_USB_GADGET_PXA2XX is not set +# CONFIG_USB_GADGET_GOKU is not set +# CONFIG_USB_GADGET_LH7A40X is not set +# CONFIG_USB_GADGET_OMAP is not set +# CONFIG_USB_GADGET_AT91 is not set +# CONFIG_USB_GADGET_DUMMY_HCD is not set +CONFIG_USB_GADGET_DUALSPEED=y +# CONFIG_USB_ZERO is not set +CONFIG_USB_ETH=y +CONFIG_USB_ETH_RNDIS=y +# CONFIG_USB_GADGETFS is not set +# CONFIG_USB_FILE_STORAGE is not set +# CONFIG_USB_G_SERIAL is not set +# CONFIG_USB_MIDI_GADGET is not set + +# +# MMC/SD Card support +# +# CONFIG_MMC is not set + +# +# LED devices +# +# CONFIG_NEW_LEDS is not set + +# +# LED drivers +# + +# +# LED Triggers +# + +# +# InfiniBand support +# +# CONFIG_INFINIBAND is not set + +# +# EDAC - error detection and reporting (RAS) (EXPERIMENTAL) +# + +# +# Real Time Clock +# +CONFIG_RTC_LIB=y +CONFIG_RTC_CLASS=y +CONFIG_RTC_HCTOSYS=y +CONFIG_RTC_HCTOSYS_DEVICE="rtc0" +# CONFIG_RTC_DEBUG is not set + +# +# RTC interfaces +# +CONFIG_RTC_INTF_SYSFS=y +CONFIG_RTC_INTF_PROC=y +CONFIG_RTC_INTF_DEV=y +CONFIG_RTC_INTF_DEV_UIE_EMUL=y + +# +# RTC drivers +# +# CONFIG_RTC_DRV_X1205 is not set +CONFIG_RTC_DRV_DS1307=y +# CONFIG_RTC_DRV_DS1553 is not set +# CONFIG_RTC_DRV_ISL1208 is not set +# CONFIG_RTC_DRV_DS1672 is not set +# CONFIG_RTC_DRV_DS1742 is not set +# CONFIG_RTC_DRV_PCF8563 is not set +# CONFIG_RTC_DRV_PCF8583 is not set +# CONFIG_RTC_DRV_RS5C348 is not set +# CONFIG_RTC_DRV_RS5C372 is not set +# CONFIG_RTC_DRV_M48T86 is not set +# CONFIG_RTC_DRV_TEST is not set +# CONFIG_RTC_DRV_MAX6902 is not set +# CONFIG_RTC_DRV_V3020 is not set + +# +# DMA Engine support +# +CONFIG_DMA_ENGINE=y + +# +# DMA Clients +# +CONFIG_NET_DMA=y + +# +# DMA Devices +# +CONFIG_INTEL_IOATDMA=y + +# +# Virtualization +# + +# +# File systems +# +CONFIG_EXT2_FS=y +# CONFIG_EXT2_FS_XATTR is not set +# CONFIG_EXT2_FS_XIP is not set +CONFIG_EXT3_FS=y +CONFIG_EXT3_FS_XATTR=y +# CONFIG_EXT3_FS_POSIX_ACL is not set +# CONFIG_EXT3_FS_SECURITY is not set +# CONFIG_EXT4DEV_FS is not set +CONFIG_JBD=y +# CONFIG_JBD_DEBUG is not set +CONFIG_FS_MBCACHE=y +# CONFIG_REISERFS_FS is not set +# CONFIG_JFS_FS is not set +# CONFIG_FS_POSIX_ACL is not set +# CONFIG_XFS_FS is not set +# CONFIG_GFS2_FS is not set +# CONFIG_OCFS2_FS is not set +# CONFIG_MINIX_FS is not set +# CONFIG_ROMFS_FS is not set +CONFIG_INOTIFY=y +CONFIG_INOTIFY_USER=y +# CONFIG_QUOTA is not set +CONFIG_DNOTIFY=y +# CONFIG_AUTOFS_FS is not set +# CONFIG_AUTOFS4_FS is not set +# CONFIG_FUSE_FS is not set + +# +# CD-ROM/DVD Filesystems +# +# CONFIG_ISO9660_FS is not set +# CONFIG_UDF_FS is not set + +# +# DOS/FAT/NT Filesystems +# +# CONFIG_MSDOS_FS is not set +# CONFIG_VFAT_FS is not set +# CONFIG_NTFS_FS is not set + +# +# Pseudo filesystems +# +CONFIG_PROC_FS=y +CONFIG_PROC_KCORE=y +CONFIG_PROC_SYSCTL=y +CONFIG_SYSFS=y +CONFIG_TMPFS=y +# CONFIG_TMPFS_POSIX_ACL is not set +# CONFIG_HUGETLB_PAGE is not set +CONFIG_RAMFS=y +# CONFIG_CONFIGFS_FS is not set + +# +# Miscellaneous filesystems +# +# CONFIG_ADFS_FS is not set +# CONFIG_AFFS_FS is not set +# CONFIG_HFS_FS is not set +# CONFIG_HFSPLUS_FS is not set +# CONFIG_BEFS_FS is not set +# CONFIG_BFS_FS is not set +# CONFIG_EFS_FS is not set +# CONFIG_JFFS2_FS is not set +# CONFIG_CRAMFS is not set +# CONFIG_VXFS_FS is not set +# CONFIG_HPFS_FS is not set +# CONFIG_QNX4FS_FS is not set +# CONFIG_SYSV_FS is not set +# CONFIG_UFS_FS is not set + +# +# Network File Systems +# +CONFIG_NFS_FS=y +CONFIG_NFS_V3=y +# CONFIG_NFS_V3_ACL is not set +CONFIG_NFS_V4=y +# CONFIG_NFS_DIRECTIO is not set +# CONFIG_NFSD is not set +CONFIG_ROOT_NFS=y +CONFIG_LOCKD=y +CONFIG_LOCKD_V4=y +CONFIG_NFS_COMMON=y +CONFIG_SUNRPC=y +CONFIG_SUNRPC_GSS=y +CONFIG_RPCSEC_GSS_KRB5=y +# CONFIG_RPCSEC_GSS_SPKM3 is not set +# CONFIG_SMB_FS is not set +# CONFIG_CIFS is not set +# CONFIG_NCP_FS is not set +# CONFIG_CODA_FS is not set +# CONFIG_AFS_FS is not set +# CONFIG_9P_FS is not set + +# +# Partition Types +# +CONFIG_PARTITION_ADVANCED=y +# CONFIG_ACORN_PARTITION is not set +# CONFIG_OSF_PARTITION is not set +# CONFIG_AMIGA_PARTITION is not set +# CONFIG_ATARI_PARTITION is not set +# CONFIG_MAC_PARTITION is not set +CONFIG_MSDOS_PARTITION=y +# CONFIG_BSD_DISKLABEL is not set +# CONFIG_MINIX_SUBPARTITION is not set +# CONFIG_SOLARIS_X86_PARTITION is not set +# CONFIG_UNIXWARE_DISKLABEL is not set +# CONFIG_LDM_PARTITION is not set +# CONFIG_SGI_PARTITION is not set +# CONFIG_ULTRIX_PARTITION is not set +# CONFIG_SUN_PARTITION is not set +# CONFIG_KARMA_PARTITION is not set +# CONFIG_EFI_PARTITION is not set + +# +# Native Language Support +# +# CONFIG_NLS is not set + +# +# Distributed Lock Manager +# +# CONFIG_DLM is not set + +# +# Library routines +# +CONFIG_BITREVERSE=y +# CONFIG_CRC_CCITT is not set +# CONFIG_CRC16 is not set +CONFIG_CRC32=y +# CONFIG_LIBCRC32C is not set +CONFIG_PLIST=y +CONFIG_IOMAP_COPY=y + +# +# Instrumentation Support +# +# CONFIG_PROFILING is not set + +# +# Kernel hacking +# +# CONFIG_PRINTK_TIME is not set +CONFIG_ENABLE_MUST_CHECK=y +# CONFIG_MAGIC_SYSRQ is not set +# CONFIG_UNUSED_SYMBOLS is not set +# CONFIG_DEBUG_FS is not set +# CONFIG_HEADERS_CHECK is not set +CONFIG_DEBUG_KERNEL=y +CONFIG_LOG_BUF_SHIFT=14 +CONFIG_DETECT_SOFTLOCKUP=y +# CONFIG_SCHEDSTATS is not set +# CONFIG_DEBUG_SLAB is not set +# CONFIG_DEBUG_RT_MUTEXES is not set +# CONFIG_RT_MUTEX_TESTER is not set +# CONFIG_DEBUG_SPINLOCK is not set +# CONFIG_DEBUG_MUTEXES is not set +# CONFIG_DEBUG_RWSEMS is not set +# CONFIG_DEBUG_SPINLOCK_SLEEP is not set +# CONFIG_DEBUG_LOCKING_API_SELFTESTS is not set +# CONFIG_DEBUG_KOBJECT is not set +# CONFIG_DEBUG_BUGVERBOSE is not set +# CONFIG_DEBUG_INFO is not set +# CONFIG_DEBUG_VM is not set +# CONFIG_DEBUG_LIST is not set +CONFIG_FORCED_INLINING=y +# CONFIG_RCU_TORTURE_TEST is not set +# CONFIG_DEBUG_STACKOVERFLOW is not set +# CONFIG_DEBUG_STACK_USAGE is not set +# CONFIG_DEBUGGER is not set +# CONFIG_BDI_SWITCH is not set +# CONFIG_BOOTX_TEXT is not set +# CONFIG_SERIAL_TEXT_DEBUG is not set +# CONFIG_PPC_EARLY_DEBUG is not set + +# +# Security options +# +# CONFIG_KEYS is not set +# CONFIG_SECURITY is not set + +# +# Cryptographic options +# +CONFIG_CRYPTO=y +CONFIG_CRYPTO_ALGAPI=y +CONFIG_CRYPTO_BLKCIPHER=y +CONFIG_CRYPTO_MANAGER=y +# CONFIG_CRYPTO_HMAC is not set +# CONFIG_CRYPTO_XCBC is not set +# CONFIG_CRYPTO_NULL is not set +# CONFIG_CRYPTO_MD4 is not set +CONFIG_CRYPTO_MD5=y +# CONFIG_CRYPTO_SHA1 is not set +# CONFIG_CRYPTO_SHA256 is not set +# CONFIG_CRYPTO_SHA512 is not set +# CONFIG_CRYPTO_WP512 is not set +# CONFIG_CRYPTO_TGR192 is not set +# CONFIG_CRYPTO_GF128MUL is not set +# CONFIG_CRYPTO_ECB is not set +CONFIG_CRYPTO_CBC=y +# CONFIG_CRYPTO_LRW is not set +CONFIG_CRYPTO_DES=y +# CONFIG_CRYPTO_BLOWFISH is not set +# CONFIG_CRYPTO_TWOFISH is not set +# CONFIG_CRYPTO_SERPENT is not set +# CONFIG_CRYPTO_AES is not set +# CONFIG_CRYPTO_CAST5 is not set +# CONFIG_CRYPTO_CAST6 is not set +# CONFIG_CRYPTO_TEA is not set +# CONFIG_CRYPTO_ARC4 is not set +# CONFIG_CRYPTO_KHAZAD is not set +# CONFIG_CRYPTO_ANUBIS is not set +# CONFIG_CRYPTO_DEFLATE is not set +# CONFIG_CRYPTO_MICHAEL_MIC is not set +# CONFIG_CRYPTO_CRC32C is not set +# CONFIG_CRYPTO_TEST is not set + +# +# Hardware crypto devices +# diff --git a/arch/powerpc/configs/mpc832xemds_defconfig b/arch/powerpc/configs/mpc832xemds_defconfig new file mode 100644 index 0000000..e1b36de --- /dev/null +++ b/arch/powerpc/configs/mpc832xemds_defconfig @@ -0,0 +1,1083 @@ +# +# Automatically generated make config: don't edit +# Linux kernel version: 2.6.20-rc5 +# Tue Jan 30 14:27:25 2007 +# +# CONFIG_PPC64 is not set +CONFIG_PPC32=y +CONFIG_PPC_MERGE=y +CONFIG_MMU=y +CONFIG_GENERIC_HARDIRQS=y +CONFIG_IRQ_PER_CPU=y +CONFIG_RWSEM_XCHGADD_ALGORITHM=y +CONFIG_ARCH_HAS_ILOG2_U32=y +CONFIG_GENERIC_HWEIGHT=y +CONFIG_GENERIC_CALIBRATE_DELAY=y +CONFIG_GENERIC_FIND_NEXT_BIT=y +CONFIG_PPC=y +CONFIG_EARLY_PRINTK=y +CONFIG_GENERIC_NVRAM=y +CONFIG_SCHED_NO_NO_OMIT_FRAME_POINTER=y +CONFIG_ARCH_MAY_HAVE_PC_FDC=y +CONFIG_PPC_OF=y +CONFIG_PPC_UDBG_16550=y +# CONFIG_GENERIC_TBSYNC is not set +CONFIG_AUDIT_ARCH=y +CONFIG_GENERIC_BUG=y +CONFIG_DEFAULT_UIMAGE=y + +# +# Processor support +# +# CONFIG_CLASSIC32 is not set +# CONFIG_PPC_82xx is not set +CONFIG_PPC_83xx=y +# CONFIG_PPC_85xx is not set +# CONFIG_PPC_86xx is not set +# CONFIG_40x is not set +# CONFIG_44x is not set +# CONFIG_8xx is not set +# CONFIG_E200 is not set +CONFIG_6xx=y +CONFIG_83xx=y +CONFIG_PPC_FPU=y +# CONFIG_PPC_DCR_NATIVE is not set +# CONFIG_PPC_DCR_MMIO is not set +CONFIG_PPC_STD_MMU=y +CONFIG_PPC_STD_MMU_32=y +# CONFIG_SMP is not set +CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config" + +# +# Code maturity level options +# +CONFIG_EXPERIMENTAL=y +CONFIG_BROKEN_ON_SMP=y +CONFIG_INIT_ENV_ARG_LIMIT=32 + +# +# General setup +# +CONFIG_LOCALVERSION="" +CONFIG_LOCALVERSION_AUTO=y +CONFIG_SWAP=y +CONFIG_SYSVIPC=y +# CONFIG_IPC_NS is not set +# CONFIG_POSIX_MQUEUE is not set +# CONFIG_BSD_PROCESS_ACCT is not set +# CONFIG_TASKSTATS is not set +# CONFIG_UTS_NS is not set +# CONFIG_AUDIT is not set +# CONFIG_IKCONFIG is not set +CONFIG_SYSFS_DEPRECATED=y +# CONFIG_RELAY is not set +CONFIG_INITRAMFS_SOURCE="" +# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set +CONFIG_SYSCTL=y +CONFIG_EMBEDDED=y +CONFIG_SYSCTL_SYSCALL=y +# CONFIG_KALLSYMS is not set +CONFIG_HOTPLUG=y +CONFIG_PRINTK=y +CONFIG_BUG=y +CONFIG_ELF_CORE=y +CONFIG_BASE_FULL=y +CONFIG_FUTEX=y +# CONFIG_EPOLL is not set +CONFIG_SHMEM=y +CONFIG_SLAB=y +CONFIG_VM_EVENT_COUNTERS=y +CONFIG_RT_MUTEXES=y +# CONFIG_TINY_SHMEM is not set +CONFIG_BASE_SMALL=0 +# CONFIG_SLOB is not set + +# +# Loadable module support +# +CONFIG_MODULES=y +CONFIG_MODULE_UNLOAD=y +# CONFIG_MODULE_FORCE_UNLOAD is not set +# CONFIG_MODVERSIONS is not set +# CONFIG_MODULE_SRCVERSION_ALL is not set +# CONFIG_KMOD is not set + +# +# Block layer +# +CONFIG_BLOCK=y +# CONFIG_LBD is not set +# CONFIG_BLK_DEV_IO_TRACE is not set +# CONFIG_LSF is not set + +# +# IO Schedulers +# +CONFIG_IOSCHED_NOOP=y +CONFIG_IOSCHED_AS=y +CONFIG_IOSCHED_DEADLINE=y +CONFIG_IOSCHED_CFQ=y +CONFIG_DEFAULT_AS=y +# CONFIG_DEFAULT_DEADLINE is not set +# CONFIG_DEFAULT_CFQ is not set +# CONFIG_DEFAULT_NOOP is not set +CONFIG_DEFAULT_IOSCHED="anticipatory" +CONFIG_QUICC_ENGINE=y +CONFIG_PPC_GEN550=y +# CONFIG_WANT_EARLY_SERIAL is not set + +# +# Platform support +# +CONFIG_MPC832x_MDS=y +# CONFIG_MPC834x_SYS is not set +# CONFIG_MPC834x_ITX is not set +# CONFIG_MPC8360E_PB is not set +CONFIG_PPC_MPC832x=y +# CONFIG_MPIC is not set + +# +# Kernel options +# +# CONFIG_HIGHMEM is not set +# CONFIG_HZ_100 is not set +CONFIG_HZ_250=y +# CONFIG_HZ_300 is not set +# CONFIG_HZ_1000 is not set +CONFIG_HZ=250 +CONFIG_PREEMPT_NONE=y +# CONFIG_PREEMPT_VOLUNTARY is not set +# CONFIG_PREEMPT is not set +CONFIG_BINFMT_ELF=y +# CONFIG_BINFMT_MISC is not set +CONFIG_MATH_EMULATION=y +CONFIG_ARCH_ENABLE_MEMORY_HOTPLUG=y +CONFIG_ARCH_FLATMEM_ENABLE=y +CONFIG_ARCH_POPULATES_NODE_MAP=y +CONFIG_SELECT_MEMORY_MODEL=y +CONFIG_FLATMEM_MANUAL=y +# CONFIG_DISCONTIGMEM_MANUAL is not set +# CONFIG_SPARSEMEM_MANUAL is not set +CONFIG_FLATMEM=y +CONFIG_FLAT_NODE_MEM_MAP=y +# CONFIG_SPARSEMEM_STATIC is not set +CONFIG_SPLIT_PTLOCK_CPUS=4 +# CONFIG_RESOURCES_64BIT is not set +CONFIG_PROC_DEVICETREE=y +# CONFIG_CMDLINE_BOOL is not set +# CONFIG_PM is not set +CONFIG_SECCOMP=y +CONFIG_ISA_DMA_API=y + +# +# Bus options +# +CONFIG_GENERIC_ISA_DMA=y +# CONFIG_MPIC_WEIRD is not set +# CONFIG_PPC_I8259 is not set +CONFIG_PPC_INDIRECT_PCI=y +CONFIG_FSL_SOC=y +CONFIG_PCI=y +CONFIG_PCI_DOMAINS=y +# CONFIG_PCIEPORTBUS is not set + +# +# PCCARD (PCMCIA/CardBus) support +# +# CONFIG_PCCARD is not set + +# +# PCI Hotplug Support +# +# CONFIG_HOTPLUG_PCI is not set + +# +# Advanced setup +# +# CONFIG_ADVANCED_OPTIONS is not set + +# +# Default settings for advanced configuration options are used +# +CONFIG_HIGHMEM_START=0xfe000000 +CONFIG_LOWMEM_SIZE=0x30000000 +CONFIG_KERNEL_START=0xc0000000 +CONFIG_TASK_SIZE=0x80000000 +CONFIG_BOOT_LOAD=0x00800000 + +# +# Networking +# +CONFIG_NET=y + +# +# Networking options +# +# CONFIG_NETDEBUG is not set +CONFIG_PACKET=y +# CONFIG_PACKET_MMAP is not set +CONFIG_UNIX=y +CONFIG_XFRM=y +# CONFIG_XFRM_USER is not set +# CONFIG_XFRM_SUB_POLICY is not set +# CONFIG_NET_KEY is not set +CONFIG_INET=y +CONFIG_IP_MULTICAST=y +# CONFIG_IP_ADVANCED_ROUTER is not set +CONFIG_IP_FIB_HASH=y +CONFIG_IP_PNP=y +CONFIG_IP_PNP_DHCP=y +CONFIG_IP_PNP_BOOTP=y +# CONFIG_IP_PNP_RARP is not set +# CONFIG_NET_IPIP is not set +# CONFIG_NET_IPGRE is not set +# CONFIG_IP_MROUTE is not set +# CONFIG_ARPD is not set +CONFIG_SYN_COOKIES=y +# CONFIG_INET_AH is not set +# CONFIG_INET_ESP is not set +# CONFIG_INET_IPCOMP is not set +# CONFIG_INET_XFRM_TUNNEL is not set +# CONFIG_INET_TUNNEL is not set +CONFIG_INET_XFRM_MODE_TRANSPORT=y +CONFIG_INET_XFRM_MODE_TUNNEL=y +CONFIG_INET_XFRM_MODE_BEET=y +CONFIG_INET_DIAG=y +CONFIG_INET_TCP_DIAG=y +# CONFIG_TCP_CONG_ADVANCED is not set +CONFIG_TCP_CONG_CUBIC=y +CONFIG_DEFAULT_TCP_CONG="cubic" +# CONFIG_TCP_MD5SIG is not set +# CONFIG_IPV6 is not set +# CONFIG_INET6_XFRM_TUNNEL is not set +# CONFIG_INET6_TUNNEL is not set +# CONFIG_NETWORK_SECMARK is not set +# CONFIG_NETFILTER is not set + +# +# DCCP Configuration (EXPERIMENTAL) +# +# CONFIG_IP_DCCP is not set + +# +# SCTP Configuration (EXPERIMENTAL) +# +# CONFIG_IP_SCTP is not set + +# +# TIPC Configuration (EXPERIMENTAL) +# +# CONFIG_TIPC is not set +# CONFIG_ATM is not set +# CONFIG_BRIDGE is not set +# CONFIG_VLAN_8021Q is not set +# CONFIG_DECNET is not set +# CONFIG_LLC2 is not set +# CONFIG_IPX is not set +# CONFIG_ATALK is not set +# CONFIG_X25 is not set +# CONFIG_LAPB is not set +# CONFIG_ECONET is not set +# CONFIG_WAN_ROUTER is not set + +# +# QoS and/or fair queueing +# +# CONFIG_NET_SCHED is not set + +# +# Network testing +# +# CONFIG_NET_PKTGEN is not set +# CONFIG_HAMRADIO is not set +# CONFIG_IRDA is not set +# CONFIG_BT is not set +# CONFIG_IEEE80211 is not set + +# +# Device Drivers +# + +# +# Generic Driver Options +# +CONFIG_STANDALONE=y +CONFIG_PREVENT_FIRMWARE_BUILD=y +# CONFIG_FW_LOADER is not set +# CONFIG_SYS_HYPERVISOR is not set + +# +# Connector - unified userspace <-> kernelspace linker +# +# CONFIG_CONNECTOR is not set + +# +# Memory Technology Devices (MTD) +# +# CONFIG_MTD is not set + +# +# Parallel port support +# +# CONFIG_PARPORT is not set + +# +# Plug and Play support +# + +# +# Block devices +# +# CONFIG_BLK_DEV_FD is not set +# CONFIG_BLK_CPQ_DA is not set +# CONFIG_BLK_CPQ_CISS_DA is not set +# CONFIG_BLK_DEV_DAC960 is not set +# CONFIG_BLK_DEV_UMEM is not set +# CONFIG_BLK_DEV_COW_COMMON is not set +CONFIG_BLK_DEV_LOOP=y +# CONFIG_BLK_DEV_CRYPTOLOOP is not set +# CONFIG_BLK_DEV_NBD is not set +# CONFIG_BLK_DEV_SX8 is not set +CONFIG_BLK_DEV_RAM=y +CONFIG_BLK_DEV_RAM_COUNT=16 +CONFIG_BLK_DEV_RAM_SIZE=32768 +CONFIG_BLK_DEV_RAM_BLOCKSIZE=1024 +CONFIG_BLK_DEV_INITRD=y +# CONFIG_CDROM_PKTCDVD is not set +# CONFIG_ATA_OVER_ETH is not set + +# +# Misc devices +# +# CONFIG_SGI_IOC4 is not set +# CONFIG_TIFM_CORE is not set + +# +# ATA/ATAPI/MFM/RLL support +# +# CONFIG_IDE is not set + +# +# SCSI device support +# +# CONFIG_RAID_ATTRS is not set +CONFIG_SCSI=y +# CONFIG_SCSI_TGT is not set +# CONFIG_SCSI_NETLINK is not set +CONFIG_SCSI_PROC_FS=y + +# +# SCSI support type (disk, tape, CD-ROM) +# +# CONFIG_BLK_DEV_SD is not set +# CONFIG_CHR_DEV_ST is not set +# CONFIG_CHR_DEV_OSST is not set +# CONFIG_BLK_DEV_SR is not set +# CONFIG_CHR_DEV_SG is not set +# CONFIG_CHR_DEV_SCH is not set + +# +# Some SCSI devices (e.g. CD jukebox) support multiple LUNs +# +# CONFIG_SCSI_MULTI_LUN is not set +# CONFIG_SCSI_CONSTANTS is not set +# CONFIG_SCSI_LOGGING is not set +# CONFIG_SCSI_SCAN_ASYNC is not set + +# +# SCSI Transports +# +# CONFIG_SCSI_SPI_ATTRS is not set +# CONFIG_SCSI_FC_ATTRS is not set +# CONFIG_SCSI_ISCSI_ATTRS is not set +# CONFIG_SCSI_SAS_ATTRS is not set +# CONFIG_SCSI_SAS_LIBSAS is not set + +# +# SCSI low-level drivers +# +# CONFIG_ISCSI_TCP is not set +# CONFIG_BLK_DEV_3W_XXXX_RAID is not set +# CONFIG_SCSI_3W_9XXX is not set +# CONFIG_SCSI_ACARD is not set +# CONFIG_SCSI_AACRAID is not set +# CONFIG_SCSI_AIC7XXX is not set +# CONFIG_SCSI_AIC7XXX_OLD is not set +# CONFIG_SCSI_AIC79XX is not set +# CONFIG_SCSI_AIC94XX is not set +# CONFIG_SCSI_DPT_I2O is not set +# CONFIG_SCSI_ARCMSR is not set +# CONFIG_MEGARAID_NEWGEN is not set +# CONFIG_MEGARAID_LEGACY is not set +# CONFIG_MEGARAID_SAS is not set +# CONFIG_SCSI_HPTIOP is not set +# CONFIG_SCSI_BUSLOGIC is not set +# CONFIG_SCSI_DMX3191D is not set +# CONFIG_SCSI_EATA is not set +# CONFIG_SCSI_FUTURE_DOMAIN is not set +# CONFIG_SCSI_GDTH is not set +# CONFIG_SCSI_IPS is not set +# CONFIG_SCSI_INITIO is not set +# CONFIG_SCSI_INIA100 is not set +# CONFIG_SCSI_STEX is not set +# CONFIG_SCSI_SYM53C8XX_2 is not set +# CONFIG_SCSI_QLOGIC_1280 is not set +# CONFIG_SCSI_QLA_FC is not set +# CONFIG_SCSI_QLA_ISCSI is not set +# CONFIG_SCSI_LPFC is not set +# CONFIG_SCSI_DC395x is not set +# CONFIG_SCSI_DC390T is not set +# CONFIG_SCSI_NSP32 is not set +# CONFIG_SCSI_DEBUG is not set +# CONFIG_SCSI_SRP is not set + +# +# Serial ATA (prod) and Parallel ATA (experimental) drivers +# +# CONFIG_ATA is not set + +# +# Multi-device support (RAID and LVM) +# +# CONFIG_MD is not set + +# +# Fusion MPT device support +# +# CONFIG_FUSION is not set +# CONFIG_FUSION_SPI is not set +# CONFIG_FUSION_FC is not set +# CONFIG_FUSION_SAS is not set + +# +# IEEE 1394 (FireWire) support +# +# CONFIG_IEEE1394 is not set + +# +# I2O device support +# +# CONFIG_I2O is not set + +# +# Macintosh device drivers +# +# CONFIG_MAC_EMUMOUSEBTN is not set +# CONFIG_WINDFARM is not set + +# +# Network device support +# +CONFIG_NETDEVICES=y +# CONFIG_DUMMY is not set +# CONFIG_BONDING is not set +# CONFIG_EQUALIZER is not set +# CONFIG_TUN is not set + +# +# ARCnet devices +# +# CONFIG_ARCNET is not set + +# +# PHY device support +# +# CONFIG_PHYLIB is not set + +# +# Ethernet (10 or 100Mbit) +# +CONFIG_NET_ETHERNET=y +CONFIG_MII=y +# CONFIG_HAPPYMEAL is not set +# CONFIG_SUNGEM is not set +# CONFIG_CASSINI is not set +# CONFIG_NET_VENDOR_3COM is not set + +# +# Tulip family network device support +# +# CONFIG_NET_TULIP is not set +# CONFIG_HP100 is not set +# CONFIG_NET_PCI is not set + +# +# Ethernet (1000 Mbit) +# +# CONFIG_ACENIC is not set +# CONFIG_DL2K is not set +# CONFIG_E1000 is not set +# CONFIG_NS83820 is not set +# CONFIG_HAMACHI is not set +# CONFIG_YELLOWFIN is not set +# CONFIG_R8169 is not set +# CONFIG_SIS190 is not set +# CONFIG_SKGE is not set +# CONFIG_SKY2 is not set +# CONFIG_SK98LIN is not set +# CONFIG_TIGON3 is not set +# CONFIG_BNX2 is not set +# CONFIG_GIANFAR is not set +CONFIG_UCC_GETH=y +# CONFIG_UGETH_NAPI is not set +# CONFIG_UGETH_MAGIC_PACKET is not set +# CONFIG_UGETH_FILTERING is not set +# CONFIG_UGETH_TX_ON_DEMOND is not set +# CONFIG_QLA3XXX is not set + +# +# Ethernet (10000 Mbit) +# +# CONFIG_CHELSIO_T1 is not set +# CONFIG_IXGB is not set +# CONFIG_S2IO is not set +# CONFIG_MYRI10GE is not set +# CONFIG_NETXEN_NIC is not set + +# +# Token Ring devices +# +# CONFIG_TR is not set + +# +# Wireless LAN (non-hamradio) +# +# CONFIG_NET_RADIO is not set + +# +# Wan interfaces +# +# CONFIG_WAN is not set +# CONFIG_FDDI is not set +# CONFIG_HIPPI is not set +# CONFIG_PPP is not set +# CONFIG_SLIP is not set +# CONFIG_NET_FC is not set +# CONFIG_SHAPER is not set +# CONFIG_NETCONSOLE is not set +# CONFIG_NETPOLL is not set +# CONFIG_NET_POLL_CONTROLLER is not set + +# +# ISDN subsystem +# +# CONFIG_ISDN is not set + +# +# Telephony Support +# +# CONFIG_PHONE is not set + +# +# Input device support +# +CONFIG_INPUT=y +# CONFIG_INPUT_FF_MEMLESS is not set + +# +# Userland interfaces +# +# CONFIG_INPUT_MOUSEDEV is not set +# CONFIG_INPUT_JOYDEV is not set +# CONFIG_INPUT_TSDEV is not set +# CONFIG_INPUT_EVDEV is not set +# CONFIG_INPUT_EVBUG is not set + +# +# Input Device Drivers +# +# CONFIG_INPUT_KEYBOARD is not set +# CONFIG_INPUT_MOUSE is not set +# CONFIG_INPUT_JOYSTICK is not set +# CONFIG_INPUT_TOUCHSCREEN is not set +# CONFIG_INPUT_MISC is not set + +# +# Hardware I/O ports +# +# CONFIG_SERIO is not set +# CONFIG_GAMEPORT is not set + +# +# Character devices +# +# CONFIG_VT is not set +# CONFIG_SERIAL_NONSTANDARD is not set + +# +# Serial drivers +# +CONFIG_SERIAL_8250=y +CONFIG_SERIAL_8250_CONSOLE=y +CONFIG_SERIAL_8250_PCI=y +CONFIG_SERIAL_8250_NR_UARTS=4 +CONFIG_SERIAL_8250_RUNTIME_UARTS=4 +# CONFIG_SERIAL_8250_EXTENDED is not set + +# +# Non-8250 serial port support +# +# CONFIG_SERIAL_UARTLITE is not set +CONFIG_SERIAL_CORE=y +CONFIG_SERIAL_CORE_CONSOLE=y +# CONFIG_SERIAL_JSM is not set +CONFIG_UNIX98_PTYS=y +CONFIG_LEGACY_PTYS=y +CONFIG_LEGACY_PTY_COUNT=256 + +# +# IPMI +# +# CONFIG_IPMI_HANDLER is not set + +# +# Watchdog Cards +# +CONFIG_WATCHDOG=y +# CONFIG_WATCHDOG_NOWAYOUT is not set + +# +# Watchdog Device Drivers +# +# CONFIG_SOFT_WATCHDOG is not set +CONFIG_83xx_WDT=y + +# +# PCI-based Watchdog Cards +# +# CONFIG_PCIPCWATCHDOG is not set +# CONFIG_WDTPCI is not set +CONFIG_HW_RANDOM=y +# CONFIG_NVRAM is not set +CONFIG_GEN_RTC=y +# CONFIG_GEN_RTC_X is not set +# CONFIG_DTLK is not set +# CONFIG_R3964 is not set +# CONFIG_APPLICOM is not set +# CONFIG_AGP is not set +# CONFIG_DRM is not set +# CONFIG_RAW_DRIVER is not set + +# +# TPM devices +# +# CONFIG_TCG_TPM is not set + +# +# I2C support +# +CONFIG_I2C=y +CONFIG_I2C_CHARDEV=y + +# +# I2C Algorithms +# +# CONFIG_I2C_ALGOBIT is not set +# CONFIG_I2C_ALGOPCF is not set +# CONFIG_I2C_ALGOPCA is not set + +# +# I2C Hardware Bus support +# +# CONFIG_I2C_ALI1535 is not set +# CONFIG_I2C_ALI1563 is not set +# CONFIG_I2C_ALI15X3 is not set +# CONFIG_I2C_AMD756 is not set +# CONFIG_I2C_AMD8111 is not set +# CONFIG_I2C_I801 is not set +# CONFIG_I2C_I810 is not set +# CONFIG_I2C_PIIX4 is not set +CONFIG_I2C_MPC=y +# CONFIG_I2C_NFORCE2 is not set +# CONFIG_I2C_OCORES is not set +# CONFIG_I2C_PARPORT_LIGHT is not set +# CONFIG_I2C_PROSAVAGE is not set +# CONFIG_I2C_SAVAGE4 is not set +# CONFIG_I2C_SIS5595 is not set +# CONFIG_I2C_SIS630 is not set +# CONFIG_I2C_SIS96X is not set +# CONFIG_I2C_STUB is not set +# CONFIG_I2C_VIA is not set +# CONFIG_I2C_VIAPRO is not set +# CONFIG_I2C_VOODOO3 is not set +# CONFIG_I2C_PCA_ISA is not set + +# +# Miscellaneous I2C Chip support +# +# CONFIG_SENSORS_DS1337 is not set +# CONFIG_SENSORS_DS1374 is not set +# CONFIG_SENSORS_EEPROM is not set +# CONFIG_SENSORS_PCF8574 is not set +# CONFIG_SENSORS_PCA9539 is not set +# CONFIG_SENSORS_PCF8591 is not set +# CONFIG_SENSORS_M41T00 is not set +# CONFIG_SENSORS_MAX6875 is not set +# CONFIG_I2C_DEBUG_CORE is not set +# CONFIG_I2C_DEBUG_ALGO is not set +# CONFIG_I2C_DEBUG_BUS is not set +# CONFIG_I2C_DEBUG_CHIP is not set + +# +# SPI support +# +# CONFIG_SPI is not set +# CONFIG_SPI_MASTER is not set + +# +# Dallas's 1-wire bus +# +# CONFIG_W1 is not set + +# +# Hardware Monitoring support +# +CONFIG_HWMON=y +# CONFIG_HWMON_VID is not set +# CONFIG_SENSORS_ABITUGURU is not set +# CONFIG_SENSORS_ADM1021 is not set +# CONFIG_SENSORS_ADM1025 is not set +# CONFIG_SENSORS_ADM1026 is not set +# CONFIG_SENSORS_ADM1031 is not set +# CONFIG_SENSORS_ADM9240 is not set +# CONFIG_SENSORS_ASB100 is not set +# CONFIG_SENSORS_ATXP1 is not set +# CONFIG_SENSORS_DS1621 is not set +# CONFIG_SENSORS_F71805F is not set +# CONFIG_SENSORS_FSCHER is not set +# CONFIG_SENSORS_FSCPOS is not set +# CONFIG_SENSORS_GL518SM is not set +# CONFIG_SENSORS_GL520SM is not set +# CONFIG_SENSORS_IT87 is not set +# CONFIG_SENSORS_LM63 is not set +# CONFIG_SENSORS_LM75 is not set +# CONFIG_SENSORS_LM77 is not set +# CONFIG_SENSORS_LM78 is not set +# CONFIG_SENSORS_LM80 is not set +# CONFIG_SENSORS_LM83 is not set +# CONFIG_SENSORS_LM85 is not set +# CONFIG_SENSORS_LM87 is not set +# CONFIG_SENSORS_LM90 is not set +# CONFIG_SENSORS_LM92 is not set +# CONFIG_SENSORS_MAX1619 is not set +# CONFIG_SENSORS_PC87360 is not set +# CONFIG_SENSORS_PC87427 is not set +# CONFIG_SENSORS_SIS5595 is not set +# CONFIG_SENSORS_SMSC47M1 is not set +# CONFIG_SENSORS_SMSC47M192 is not set +# CONFIG_SENSORS_SMSC47B397 is not set +# CONFIG_SENSORS_VIA686A is not set +# CONFIG_SENSORS_VT1211 is not set +# CONFIG_SENSORS_VT8231 is not set +# CONFIG_SENSORS_W83781D is not set +# CONFIG_SENSORS_W83791D is not set +# CONFIG_SENSORS_W83792D is not set +# CONFIG_SENSORS_W83793 is not set +# CONFIG_SENSORS_W83L785TS is not set +# CONFIG_SENSORS_W83627HF is not set +# CONFIG_SENSORS_W83627EHF is not set +# CONFIG_HWMON_DEBUG_CHIP is not set + +# +# Multimedia devices +# +# CONFIG_VIDEO_DEV is not set + +# +# Digital Video Broadcasting Devices +# +# CONFIG_DVB is not set + +# +# Graphics support +# +CONFIG_FIRMWARE_EDID=y +# CONFIG_FB is not set +# CONFIG_FB_IBM_GXT4500 is not set +# CONFIG_BACKLIGHT_LCD_SUPPORT is not set + +# +# Sound +# +# CONFIG_SOUND is not set + +# +# HID Devices +# +CONFIG_HID=y + +# +# USB support +# +CONFIG_USB_ARCH_HAS_HCD=y +CONFIG_USB_ARCH_HAS_OHCI=y +CONFIG_USB_ARCH_HAS_EHCI=y +# CONFIG_USB is not set + +# +# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support' +# + +# +# USB Gadget Support +# +# CONFIG_USB_GADGET is not set + +# +# MMC/SD Card support +# +# CONFIG_MMC is not set + +# +# LED devices +# +# CONFIG_NEW_LEDS is not set + +# +# LED drivers +# + +# +# LED Triggers +# + +# +# InfiniBand support +# +# CONFIG_INFINIBAND is not set + +# +# EDAC - error detection and reporting (RAS) (EXPERIMENTAL) +# + +# +# Real Time Clock +# +# CONFIG_RTC_CLASS is not set + +# +# DMA Engine support +# +# CONFIG_DMA_ENGINE is not set + +# +# DMA Clients +# + +# +# DMA Devices +# + +# +# Virtualization +# + +# +# File systems +# +CONFIG_EXT2_FS=y +# CONFIG_EXT2_FS_XATTR is not set +# CONFIG_EXT2_FS_XIP is not set +CONFIG_EXT3_FS=y +CONFIG_EXT3_FS_XATTR=y +# CONFIG_EXT3_FS_POSIX_ACL is not set +# CONFIG_EXT3_FS_SECURITY is not set +# CONFIG_EXT4DEV_FS is not set +CONFIG_JBD=y +# CONFIG_JBD_DEBUG is not set +CONFIG_FS_MBCACHE=y +# CONFIG_REISERFS_FS is not set +# CONFIG_JFS_FS is not set +# CONFIG_FS_POSIX_ACL is not set +# CONFIG_XFS_FS is not set +# CONFIG_GFS2_FS is not set +# CONFIG_OCFS2_FS is not set +# CONFIG_MINIX_FS is not set +# CONFIG_ROMFS_FS is not set +CONFIG_INOTIFY=y +CONFIG_INOTIFY_USER=y +# CONFIG_QUOTA is not set +CONFIG_DNOTIFY=y +# CONFIG_AUTOFS_FS is not set +# CONFIG_AUTOFS4_FS is not set +# CONFIG_FUSE_FS is not set + +# +# CD-ROM/DVD Filesystems +# +# CONFIG_ISO9660_FS is not set +# CONFIG_UDF_FS is not set + +# +# DOS/FAT/NT Filesystems +# +# CONFIG_MSDOS_FS is not set +# CONFIG_VFAT_FS is not set +# CONFIG_NTFS_FS is not set + +# +# Pseudo filesystems +# +CONFIG_PROC_FS=y +CONFIG_PROC_KCORE=y +CONFIG_PROC_SYSCTL=y +CONFIG_SYSFS=y +CONFIG_TMPFS=y +# CONFIG_TMPFS_POSIX_ACL is not set +# CONFIG_HUGETLB_PAGE is not set +CONFIG_RAMFS=y +# CONFIG_CONFIGFS_FS is not set + +# +# Miscellaneous filesystems +# +# CONFIG_ADFS_FS is not set +# CONFIG_AFFS_FS is not set +# CONFIG_HFS_FS is not set +# CONFIG_HFSPLUS_FS is not set +# CONFIG_BEFS_FS is not set +# CONFIG_BFS_FS is not set +# CONFIG_EFS_FS is not set +# CONFIG_CRAMFS is not set +# CONFIG_VXFS_FS is not set +# CONFIG_HPFS_FS is not set +# CONFIG_QNX4FS_FS is not set +# CONFIG_SYSV_FS is not set +# CONFIG_UFS_FS is not set + +# +# Network File Systems +# +CONFIG_NFS_FS=y +CONFIG_NFS_V3=y +# CONFIG_NFS_V3_ACL is not set +CONFIG_NFS_V4=y +# CONFIG_NFS_DIRECTIO is not set +# CONFIG_NFSD is not set +CONFIG_ROOT_NFS=y +CONFIG_LOCKD=y +CONFIG_LOCKD_V4=y +CONFIG_NFS_COMMON=y +CONFIG_SUNRPC=y +CONFIG_SUNRPC_GSS=y +CONFIG_RPCSEC_GSS_KRB5=y +# CONFIG_RPCSEC_GSS_SPKM3 is not set +# CONFIG_SMB_FS is not set +# CONFIG_CIFS is not set +# CONFIG_NCP_FS is not set +# CONFIG_CODA_FS is not set +# CONFIG_AFS_FS is not set +# CONFIG_9P_FS is not set + +# +# Partition Types +# +CONFIG_PARTITION_ADVANCED=y +# CONFIG_ACORN_PARTITION is not set +# CONFIG_OSF_PARTITION is not set +# CONFIG_AMIGA_PARTITION is not set +# CONFIG_ATARI_PARTITION is not set +# CONFIG_MAC_PARTITION is not set +# CONFIG_MSDOS_PARTITION is not set +# CONFIG_LDM_PARTITION is not set +# CONFIG_SGI_PARTITION is not set +# CONFIG_ULTRIX_PARTITION is not set +# CONFIG_SUN_PARTITION is not set +# CONFIG_KARMA_PARTITION is not set +# CONFIG_EFI_PARTITION is not set + +# +# Native Language Support +# +# CONFIG_NLS is not set + +# +# Distributed Lock Manager +# +# CONFIG_DLM is not set + +# +# QE Options +# +CONFIG_UCC_SLOW=y +CONFIG_UCC_FAST=y +CONFIG_UCC=y + +# +# Library routines +# +CONFIG_BITREVERSE=y +# CONFIG_CRC_CCITT is not set +# CONFIG_CRC16 is not set +CONFIG_CRC32=y +# CONFIG_LIBCRC32C is not set +CONFIG_PLIST=y +CONFIG_IOMAP_COPY=y + +# +# Instrumentation Support +# +# CONFIG_PROFILING is not set + +# +# Kernel hacking +# +# CONFIG_PRINTK_TIME is not set +CONFIG_ENABLE_MUST_CHECK=y +# CONFIG_MAGIC_SYSRQ is not set +# CONFIG_UNUSED_SYMBOLS is not set +# CONFIG_DEBUG_FS is not set +# CONFIG_HEADERS_CHECK is not set +# CONFIG_DEBUG_KERNEL is not set +CONFIG_LOG_BUF_SHIFT=14 +# CONFIG_DEBUG_BUGVERBOSE is not set +# CONFIG_BOOTX_TEXT is not set +# CONFIG_SERIAL_TEXT_DEBUG is not set +# CONFIG_PPC_EARLY_DEBUG is not set + +# +# Security options +# +# CONFIG_KEYS is not set +# CONFIG_SECURITY is not set + +# +# Cryptographic options +# +CONFIG_CRYPTO=y +CONFIG_CRYPTO_ALGAPI=y +CONFIG_CRYPTO_BLKCIPHER=y +CONFIG_CRYPTO_MANAGER=y +# CONFIG_CRYPTO_HMAC is not set +# CONFIG_CRYPTO_XCBC is not set +# CONFIG_CRYPTO_NULL is not set +# CONFIG_CRYPTO_MD4 is not set +CONFIG_CRYPTO_MD5=y +# CONFIG_CRYPTO_SHA1 is not set +# CONFIG_CRYPTO_SHA256 is not set +# CONFIG_CRYPTO_SHA512 is not set +# CONFIG_CRYPTO_WP512 is not set +# CONFIG_CRYPTO_TGR192 is not set +# CONFIG_CRYPTO_GF128MUL is not set +CONFIG_CRYPTO_ECB=m +CONFIG_CRYPTO_CBC=y +# CONFIG_CRYPTO_LRW is not set +CONFIG_CRYPTO_DES=y +# CONFIG_CRYPTO_BLOWFISH is not set +# CONFIG_CRYPTO_TWOFISH is not set +# CONFIG_CRYPTO_SERPENT is not set +# CONFIG_CRYPTO_AES is not set +# CONFIG_CRYPTO_CAST5 is not set +# CONFIG_CRYPTO_CAST6 is not set +# CONFIG_CRYPTO_TEA is not set +# CONFIG_CRYPTO_ARC4 is not set +# CONFIG_CRYPTO_KHAZAD is not set +# CONFIG_CRYPTO_ANUBIS is not set +# CONFIG_CRYPTO_DEFLATE is not set +# CONFIG_CRYPTO_MICHAEL_MIC is not set +# CONFIG_CRYPTO_CRC32C is not set +# CONFIG_CRYPTO_TEST is not set + +# +# Hardware crypto devices +# diff --git a/arch/powerpc/configs/mpc834x_itx_defconfig b/arch/powerpc/configs/mpc834x_itx_defconfig index 45757b6..23d8964 100644 --- a/arch/powerpc/configs/mpc834x_itx_defconfig +++ b/arch/powerpc/configs/mpc834x_itx_defconfig @@ -1,7 +1,7 @@ # # Automatically generated make config: don't edit -# Linux kernel version: 2.6.20-rc5 -# Mon Jan 22 22:23:43 2007 +# Linux kernel version: 2.6.20 +# Wed Feb 7 13:12:18 2007 # # CONFIG_PPC64 is not set CONFIG_PPC32=y @@ -34,9 +34,9 @@ # CONFIG_PPC_82xx is not set CONFIG_PPC_83xx=y # CONFIG_PPC_85xx is not set # CONFIG_PPC_86xx is not set +# CONFIG_PPC_8xx is not set # CONFIG_40x is not set # CONFIG_44x is not set -# CONFIG_8xx is not set # CONFIG_E200 is not set CONFIG_6xx=y CONFIG_83xx=y @@ -149,7 +149,6 @@ # CONFIG_PREEMPT_VOLUNTARY is not set # CONFIG_PREEMPT is not set CONFIG_BINFMT_ELF=y # CONFIG_BINFMT_MISC is not set -CONFIG_MATH_EMULATION=y CONFIG_ARCH_ENABLE_MEMORY_HOTPLUG=y CONFIG_ARCH_FLATMEM_ENABLE=y CONFIG_ARCH_POPULATES_NODE_MAP=y @@ -179,7 +178,6 @@ CONFIG_FSL_SOC=y CONFIG_PCI=y CONFIG_PCI_DOMAINS=y # CONFIG_PCIEPORTBUS is not set -# CONFIG_PCI_DEBUG is not set # # PCCARD (PCMCIA/CardBus) support @@ -304,7 +302,6 @@ # CONFIG_STANDALONE=y CONFIG_PREVENT_FIRMWARE_BUILD=y # CONFIG_FW_LOADER is not set -# CONFIG_DEBUG_DRIVER is not set # CONFIG_SYS_HYPERVISOR is not set # @@ -324,6 +321,7 @@ # # User Modules And Translation Layers # CONFIG_MTD_CHAR=y +# CONFIG_MTD_BLKDEVS is not set # CONFIG_MTD_BLOCK is not set # CONFIG_MTD_BLOCK_RO is not set # CONFIG_FTL is not set @@ -366,6 +364,7 @@ CONFIG_MTD_PHYSMAP=y CONFIG_MTD_PHYSMAP_START=0xfe000000 CONFIG_MTD_PHYSMAP_LEN=0x1000000 CONFIG_MTD_PHYSMAP_BANKWIDTH=2 +# CONFIG_MTD_PHYSMAP_OF is not set # CONFIG_MTD_PLATRAM is not set # @@ -390,6 +389,7 @@ # # NAND Flash Device Drivers # # CONFIG_MTD_NAND is not set +# CONFIG_MTD_NAND_CAFE is not set # # OneNAND Flash Device Drivers @@ -521,6 +521,7 @@ # # Serial ATA (prod) and Parallel ATA (experimental) drivers # CONFIG_ATA=y +# CONFIG_ATA_NONSTANDARD is not set # CONFIG_SATA_AHCI is not set # CONFIG_SATA_SVW is not set # CONFIG_ATA_PIIX is not set @@ -645,37 +646,7 @@ # CONFIG_FIXED_PHY is not set # # Ethernet (10 or 100Mbit) # -CONFIG_NET_ETHERNET=y -CONFIG_MII=y -# CONFIG_HAPPYMEAL is not set -# CONFIG_SUNGEM is not set -# CONFIG_CASSINI is not set -# CONFIG_NET_VENDOR_3COM is not set - -# -# Tulip family network device support -# -# CONFIG_NET_TULIP is not set -# CONFIG_HP100 is not set -CONFIG_NET_PCI=y -# CONFIG_PCNET32 is not set -# CONFIG_AMD8111_ETH is not set -# CONFIG_ADAPTEC_STARFIRE is not set -# CONFIG_B44 is not set -# CONFIG_FORCEDETH is not set -# CONFIG_DGRS is not set -# CONFIG_EEPRO100 is not set -CONFIG_E100=y -# CONFIG_FEALNX is not set -# CONFIG_NATSEMI is not set -# CONFIG_NE2K_PCI is not set -# CONFIG_8139CP is not set -# CONFIG_8139TOO is not set -# CONFIG_SIS900 is not set -# CONFIG_EPIC100 is not set -# CONFIG_SUNDANCE is not set -# CONFIG_TLAN is not set -# CONFIG_VIA_RHINE is not set +# CONFIG_NET_ETHERNET is not set # # Ethernet (1000 Mbit) @@ -691,7 +662,6 @@ # CONFIG_SIS190 is not set # CONFIG_SKGE is not set # CONFIG_SKY2 is not set # CONFIG_SK98LIN is not set -# CONFIG_VIA_VELOCITY is not set # CONFIG_TIGON3 is not set # CONFIG_BNX2 is not set CONFIG_GIANFAR=y @@ -744,26 +714,7 @@ # CONFIG_PHONE is not set # # Input device support # -CONFIG_INPUT=y -# CONFIG_INPUT_FF_MEMLESS is not set - -# -# Userland interfaces -# -# CONFIG_INPUT_MOUSEDEV is not set -# CONFIG_INPUT_JOYDEV is not set -# CONFIG_INPUT_TSDEV is not set -# CONFIG_INPUT_EVDEV is not set -# CONFIG_INPUT_EVBUG is not set - -# -# Input Device Drivers -# -# CONFIG_INPUT_KEYBOARD is not set -# CONFIG_INPUT_MOUSE is not set -# CONFIG_INPUT_JOYSTICK is not set -# CONFIG_INPUT_TOUCHSCREEN is not set -# CONFIG_INPUT_MISC is not set +# CONFIG_INPUT is not set # # Hardware I/O ports @@ -782,7 +733,7 @@ # Serial drivers # CONFIG_SERIAL_8250=y CONFIG_SERIAL_8250_CONSOLE=y -CONFIG_SERIAL_8250_PCI=y +# CONFIG_SERIAL_8250_PCI is not set CONFIG_SERIAL_8250_NR_UARTS=4 CONFIG_SERIAL_8250_RUNTIME_UARTS=4 # CONFIG_SERIAL_8250_EXTENDED is not set @@ -885,7 +836,7 @@ # # CONFIG_SENSORS_DS1337 is not set # CONFIG_SENSORS_DS1374 is not set # CONFIG_SENSORS_EEPROM is not set -# CONFIG_SENSORS_PCF8574 is not set +CONFIG_SENSORS_PCF8574=y # CONFIG_SENSORS_PCA9539 is not set # CONFIG_SENSORS_PCF8591 is not set # CONFIG_SENSORS_M41T00 is not set @@ -899,7 +850,6 @@ # # SPI support # CONFIG_SPI=y -# CONFIG_SPI_DEBUG is not set CONFIG_SPI_MASTER=y # @@ -920,52 +870,8 @@ # CONFIG_W1 is not set # # Hardware Monitoring support # -CONFIG_HWMON=y +# CONFIG_HWMON is not set # CONFIG_HWMON_VID is not set -# CONFIG_SENSORS_ABITUGURU is not set -# CONFIG_SENSORS_ADM1021 is not set -# CONFIG_SENSORS_ADM1025 is not set -# CONFIG_SENSORS_ADM1026 is not set -# CONFIG_SENSORS_ADM1031 is not set -# CONFIG_SENSORS_ADM9240 is not set -# CONFIG_SENSORS_ASB100 is not set -# CONFIG_SENSORS_ATXP1 is not set -# CONFIG_SENSORS_DS1621 is not set -# CONFIG_SENSORS_F71805F is not set -# CONFIG_SENSORS_FSCHER is not set -# CONFIG_SENSORS_FSCPOS is not set -# CONFIG_SENSORS_GL518SM is not set -# CONFIG_SENSORS_GL520SM is not set -# CONFIG_SENSORS_IT87 is not set -# CONFIG_SENSORS_LM63 is not set -# CONFIG_SENSORS_LM70 is not set -# CONFIG_SENSORS_LM75 is not set -# CONFIG_SENSORS_LM77 is not set -# CONFIG_SENSORS_LM78 is not set -# CONFIG_SENSORS_LM80 is not set -# CONFIG_SENSORS_LM83 is not set -# CONFIG_SENSORS_LM85 is not set -# CONFIG_SENSORS_LM87 is not set -# CONFIG_SENSORS_LM90 is not set -# CONFIG_SENSORS_LM92 is not set -# CONFIG_SENSORS_MAX1619 is not set -# CONFIG_SENSORS_PC87360 is not set -# CONFIG_SENSORS_PC87427 is not set -# CONFIG_SENSORS_SIS5595 is not set -# CONFIG_SENSORS_SMSC47M1 is not set -# CONFIG_SENSORS_SMSC47M192 is not set -# CONFIG_SENSORS_SMSC47B397 is not set -# CONFIG_SENSORS_VIA686A is not set -# CONFIG_SENSORS_VT1211 is not set -# CONFIG_SENSORS_VT8231 is not set -# CONFIG_SENSORS_W83781D is not set -# CONFIG_SENSORS_W83791D is not set -# CONFIG_SENSORS_W83792D is not set -# CONFIG_SENSORS_W83793 is not set -# CONFIG_SENSORS_W83L785TS is not set -# CONFIG_SENSORS_W83627HF is not set -# CONFIG_SENSORS_W83627EHF is not set -# CONFIG_HWMON_DEBUG_CHIP is not set # # Multimedia devices @@ -981,7 +887,7 @@ # CONFIG_USB_DABUSB is not set # # Graphics support # -CONFIG_FIRMWARE_EDID=y +# CONFIG_FIRMWARE_EDID is not set # CONFIG_FB is not set # CONFIG_FB_IBM_GXT4500 is not set # CONFIG_BACKLIGHT_LCD_SUPPORT is not set @@ -992,11 +898,6 @@ # # CONFIG_SOUND is not set # -# HID Devices -# -CONFIG_HID=y - -# # USB support # CONFIG_USB_ARCH_HAS_HCD=y @@ -1011,7 +912,6 @@ # CONFIG_USB_DEVICEFS=y # CONFIG_USB_BANDWIDTH is not set # CONFIG_USB_DYNAMIC_MINORS is not set -# CONFIG_USB_MULTITHREAD_PROBE is not set # CONFIG_USB_OTG is not set # @@ -1022,10 +922,8 @@ # CONFIG_USB_EHCI_SPLIT_ISO is not set # CONFIG_USB_EHCI_ROOT_HUB_TT is not set # CONFIG_USB_EHCI_TT_NEWSCHED is not set # CONFIG_USB_ISP116X_HCD is not set -CONFIG_USB_OHCI_HCD=y -# CONFIG_USB_OHCI_BIG_ENDIAN is not set -CONFIG_USB_OHCI_LITTLE_ENDIAN=y -CONFIG_USB_UHCI_HCD=y +# CONFIG_USB_OHCI_HCD is not set +# CONFIG_USB_UHCI_HCD is not set # CONFIG_USB_SL811_HCD is not set # @@ -1057,25 +955,10 @@ # CONFIG_USB_LIBUSUAL is not set # # USB Input Devices # -# CONFIG_USB_HID is not set # # USB HID Boot Protocol drivers # -# CONFIG_USB_KBD is not set -# CONFIG_USB_MOUSE is not set -# CONFIG_USB_AIPTEK is not set -# CONFIG_USB_WACOM is not set -# CONFIG_USB_ACECAD is not set -# CONFIG_USB_KBTAB is not set -# CONFIG_USB_POWERMATE is not set -# CONFIG_USB_TOUCHSCREEN is not set -# CONFIG_USB_YEALINK is not set -# CONFIG_USB_XPAD is not set -# CONFIG_USB_ATI_REMOTE is not set -# CONFIG_USB_ATI_REMOTE2 is not set -# CONFIG_USB_KEYSPAN_REMOTE is not set -# CONFIG_USB_APPLETOUCH is not set # # USB Imaging devices @@ -1132,25 +1015,7 @@ # # # USB Gadget Support # -CONFIG_USB_GADGET=y -# CONFIG_USB_GADGET_DEBUG_FILES is not set -CONFIG_USB_GADGET_SELECTED=y -CONFIG_USB_GADGET_NET2280=y -CONFIG_USB_NET2280=y -# CONFIG_USB_GADGET_PXA2XX is not set -# CONFIG_USB_GADGET_GOKU is not set -# CONFIG_USB_GADGET_LH7A40X is not set -# CONFIG_USB_GADGET_OMAP is not set -# CONFIG_USB_GADGET_AT91 is not set -# CONFIG_USB_GADGET_DUMMY_HCD is not set -CONFIG_USB_GADGET_DUALSPEED=y -# CONFIG_USB_ZERO is not set -CONFIG_USB_ETH=y -CONFIG_USB_ETH_RNDIS=y -# CONFIG_USB_GADGETFS is not set -# CONFIG_USB_FILE_STORAGE is not set -# CONFIG_USB_G_SERIAL is not set -# CONFIG_USB_MIDI_GADGET is not set +# CONFIG_USB_GADGET is not set # # MMC/SD Card support @@ -1272,8 +1137,11 @@ # CONFIG_UDF_FS is not set # # DOS/FAT/NT Filesystems # -# CONFIG_MSDOS_FS is not set -# CONFIG_VFAT_FS is not set +CONFIG_FAT_FS=y +CONFIG_MSDOS_FS=y +CONFIG_VFAT_FS=y +CONFIG_FAT_DEFAULT_CODEPAGE=437 +CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1" # CONFIG_NTFS_FS is not set # @@ -1339,7 +1207,7 @@ # CONFIG_ACORN_PARTITION is not set # CONFIG_OSF_PARTITION is not set # CONFIG_AMIGA_PARTITION is not set # CONFIG_ATARI_PARTITION is not set -# CONFIG_MAC_PARTITION is not set +CONFIG_MAC_PARTITION=y CONFIG_MSDOS_PARTITION=y # CONFIG_BSD_DISKLABEL is not set # CONFIG_MINIX_SUBPARTITION is not set @@ -1355,7 +1223,46 @@ # CONFIG_EFI_PARTITION is not set # # Native Language Support # -# CONFIG_NLS is not set +CONFIG_NLS=y +CONFIG_NLS_DEFAULT="iso8859-1" +# CONFIG_NLS_CODEPAGE_437 is not set +# CONFIG_NLS_CODEPAGE_737 is not set +# CONFIG_NLS_CODEPAGE_775 is not set +# CONFIG_NLS_CODEPAGE_850 is not set +# CONFIG_NLS_CODEPAGE_852 is not set +# CONFIG_NLS_CODEPAGE_855 is not set +# CONFIG_NLS_CODEPAGE_857 is not set +# CONFIG_NLS_CODEPAGE_860 is not set +# CONFIG_NLS_CODEPAGE_861 is not set +# CONFIG_NLS_CODEPAGE_862 is not set +# CONFIG_NLS_CODEPAGE_863 is not set +# CONFIG_NLS_CODEPAGE_864 is not set +# CONFIG_NLS_CODEPAGE_865 is not set +# CONFIG_NLS_CODEPAGE_866 is not set +# CONFIG_NLS_CODEPAGE_869 is not set +# CONFIG_NLS_CODEPAGE_936 is not set +# CONFIG_NLS_CODEPAGE_950 is not set +# CONFIG_NLS_CODEPAGE_932 is not set +# CONFIG_NLS_CODEPAGE_949 is not set +# CONFIG_NLS_CODEPAGE_874 is not set +# CONFIG_NLS_ISO8859_8 is not set +# CONFIG_NLS_CODEPAGE_1250 is not set +# CONFIG_NLS_CODEPAGE_1251 is not set +# CONFIG_NLS_ASCII is not set +# CONFIG_NLS_ISO8859_1 is not set +# CONFIG_NLS_ISO8859_2 is not set +# CONFIG_NLS_ISO8859_3 is not set +# CONFIG_NLS_ISO8859_4 is not set +# CONFIG_NLS_ISO8859_5 is not set +# CONFIG_NLS_ISO8859_6 is not set +# CONFIG_NLS_ISO8859_7 is not set +# CONFIG_NLS_ISO8859_9 is not set +# CONFIG_NLS_ISO8859_13 is not set +# CONFIG_NLS_ISO8859_14 is not set +# CONFIG_NLS_ISO8859_15 is not set +# CONFIG_NLS_KOI8_R is not set +# CONFIG_NLS_KOI8_U is not set +# CONFIG_NLS_UTF8 is not set # # Distributed Lock Manager @@ -1387,27 +1294,9 @@ # CONFIG_MAGIC_SYSRQ is not set # CONFIG_UNUSED_SYMBOLS is not set # CONFIG_DEBUG_FS is not set # CONFIG_HEADERS_CHECK is not set -CONFIG_DEBUG_KERNEL=y +# CONFIG_DEBUG_KERNEL is not set CONFIG_LOG_BUF_SHIFT=14 -CONFIG_DETECT_SOFTLOCKUP=y -# CONFIG_SCHEDSTATS is not set -# CONFIG_DEBUG_SLAB is not set -# CONFIG_DEBUG_RT_MUTEXES is not set -# CONFIG_RT_MUTEX_TESTER is not set -# CONFIG_DEBUG_SPINLOCK is not set -# CONFIG_DEBUG_MUTEXES is not set -# CONFIG_DEBUG_RWSEMS is not set -# CONFIG_DEBUG_SPINLOCK_SLEEP is not set -# CONFIG_DEBUG_LOCKING_API_SELFTESTS is not set -# CONFIG_DEBUG_KOBJECT is not set # CONFIG_DEBUG_BUGVERBOSE is not set -# CONFIG_DEBUG_INFO is not set -# CONFIG_DEBUG_VM is not set -# CONFIG_DEBUG_LIST is not set -CONFIG_FORCED_INLINING=y -# CONFIG_RCU_TORTURE_TEST is not set -# CONFIG_DEBUGGER is not set -# CONFIG_BDI_SWITCH is not set # CONFIG_BOOTX_TEXT is not set # CONFIG_SERIAL_TEXT_DEBUG is not set # CONFIG_PPC_EARLY_DEBUG is not set diff --git a/arch/powerpc/configs/mpc834x_itxgp_defconfig b/arch/powerpc/configs/mpc834x_itxgp_defconfig new file mode 100644 index 0000000..4aa666c --- /dev/null +++ b/arch/powerpc/configs/mpc834x_itxgp_defconfig @@ -0,0 +1,1174 @@ +# +# Automatically generated make config: don't edit +# Linux kernel version: 2.6.20 +# Fri Feb 9 13:28:19 2007 +# +# CONFIG_PPC64 is not set +CONFIG_PPC32=y +CONFIG_PPC_MERGE=y +CONFIG_MMU=y +CONFIG_GENERIC_HARDIRQS=y +CONFIG_IRQ_PER_CPU=y +CONFIG_RWSEM_XCHGADD_ALGORITHM=y +CONFIG_ARCH_HAS_ILOG2_U32=y +CONFIG_GENERIC_HWEIGHT=y +CONFIG_GENERIC_CALIBRATE_DELAY=y +CONFIG_GENERIC_FIND_NEXT_BIT=y +CONFIG_PPC=y +CONFIG_EARLY_PRINTK=y +CONFIG_GENERIC_NVRAM=y +CONFIG_SCHED_NO_NO_OMIT_FRAME_POINTER=y +CONFIG_ARCH_MAY_HAVE_PC_FDC=y +CONFIG_PPC_OF=y +CONFIG_PPC_UDBG_16550=y +# CONFIG_GENERIC_TBSYNC is not set +CONFIG_AUDIT_ARCH=y +CONFIG_GENERIC_BUG=y +CONFIG_DEFAULT_UIMAGE=y + +# +# Processor support +# +# CONFIG_CLASSIC32 is not set +# CONFIG_PPC_82xx is not set +CONFIG_PPC_83xx=y +# CONFIG_PPC_85xx is not set +# CONFIG_PPC_86xx is not set +# CONFIG_PPC_8xx is not set +# CONFIG_40x is not set +# CONFIG_44x is not set +# CONFIG_E200 is not set +CONFIG_6xx=y +CONFIG_83xx=y +CONFIG_PPC_FPU=y +# CONFIG_PPC_DCR_NATIVE is not set +# CONFIG_PPC_DCR_MMIO is not set +CONFIG_PPC_STD_MMU=y +CONFIG_PPC_STD_MMU_32=y +# CONFIG_SMP is not set +CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config" + +# +# Code maturity level options +# +CONFIG_EXPERIMENTAL=y +CONFIG_BROKEN_ON_SMP=y +CONFIG_INIT_ENV_ARG_LIMIT=32 + +# +# General setup +# +CONFIG_LOCALVERSION="" +CONFIG_LOCALVERSION_AUTO=y +CONFIG_SWAP=y +CONFIG_SYSVIPC=y +# CONFIG_IPC_NS is not set +# CONFIG_POSIX_MQUEUE is not set +# CONFIG_BSD_PROCESS_ACCT is not set +# CONFIG_TASKSTATS is not set +# CONFIG_UTS_NS is not set +# CONFIG_AUDIT is not set +# CONFIG_IKCONFIG is not set +CONFIG_SYSFS_DEPRECATED=y +# CONFIG_RELAY is not set +CONFIG_INITRAMFS_SOURCE="" +# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set +CONFIG_SYSCTL=y +CONFIG_EMBEDDED=y +CONFIG_SYSCTL_SYSCALL=y +# CONFIG_KALLSYMS is not set +CONFIG_HOTPLUG=y +CONFIG_PRINTK=y +CONFIG_BUG=y +CONFIG_ELF_CORE=y +CONFIG_BASE_FULL=y +CONFIG_FUTEX=y +# CONFIG_EPOLL is not set +CONFIG_SHMEM=y +CONFIG_SLAB=y +CONFIG_VM_EVENT_COUNTERS=y +CONFIG_RT_MUTEXES=y +# CONFIG_TINY_SHMEM is not set +CONFIG_BASE_SMALL=0 +# CONFIG_SLOB is not set + +# +# Loadable module support +# +CONFIG_MODULES=y +CONFIG_MODULE_UNLOAD=y +# CONFIG_MODULE_FORCE_UNLOAD is not set +# CONFIG_MODVERSIONS is not set +# CONFIG_MODULE_SRCVERSION_ALL is not set +# CONFIG_KMOD is not set + +# +# Block layer +# +CONFIG_BLOCK=y +# CONFIG_LBD is not set +# CONFIG_BLK_DEV_IO_TRACE is not set +# CONFIG_LSF is not set + +# +# IO Schedulers +# +CONFIG_IOSCHED_NOOP=y +CONFIG_IOSCHED_AS=y +CONFIG_IOSCHED_DEADLINE=y +CONFIG_IOSCHED_CFQ=y +CONFIG_DEFAULT_AS=y +# CONFIG_DEFAULT_DEADLINE is not set +# CONFIG_DEFAULT_CFQ is not set +# CONFIG_DEFAULT_NOOP is not set +CONFIG_DEFAULT_IOSCHED="anticipatory" +CONFIG_PPC_GEN550=y +# CONFIG_WANT_EARLY_SERIAL is not set + +# +# Platform support +# +# CONFIG_MPC832x_MDS is not set +# CONFIG_MPC834x_SYS is not set +CONFIG_MPC834x_ITX=y +# CONFIG_MPC8360E_PB is not set +CONFIG_MPC834x=y +# CONFIG_MPIC is not set + +# +# Kernel options +# +# CONFIG_HIGHMEM is not set +# CONFIG_HZ_100 is not set +CONFIG_HZ_250=y +# CONFIG_HZ_300 is not set +# CONFIG_HZ_1000 is not set +CONFIG_HZ=250 +CONFIG_PREEMPT_NONE=y +# CONFIG_PREEMPT_VOLUNTARY is not set +# CONFIG_PREEMPT is not set +CONFIG_BINFMT_ELF=y +# CONFIG_BINFMT_MISC is not set +CONFIG_ARCH_ENABLE_MEMORY_HOTPLUG=y +CONFIG_ARCH_FLATMEM_ENABLE=y +CONFIG_ARCH_POPULATES_NODE_MAP=y +CONFIG_SELECT_MEMORY_MODEL=y +CONFIG_FLATMEM_MANUAL=y +# CONFIG_DISCONTIGMEM_MANUAL is not set +# CONFIG_SPARSEMEM_MANUAL is not set +CONFIG_FLATMEM=y +CONFIG_FLAT_NODE_MEM_MAP=y +# CONFIG_SPARSEMEM_STATIC is not set +CONFIG_SPLIT_PTLOCK_CPUS=4 +# CONFIG_RESOURCES_64BIT is not set +CONFIG_PROC_DEVICETREE=y +# CONFIG_CMDLINE_BOOL is not set +# CONFIG_PM is not set +CONFIG_SECCOMP=y +CONFIG_ISA_DMA_API=y + +# +# Bus options +# +CONFIG_GENERIC_ISA_DMA=y +# CONFIG_MPIC_WEIRD is not set +# CONFIG_PPC_I8259 is not set +CONFIG_PPC_INDIRECT_PCI=y +CONFIG_FSL_SOC=y +CONFIG_PCI=y +CONFIG_PCI_DOMAINS=y +# CONFIG_PCIEPORTBUS is not set + +# +# PCCARD (PCMCIA/CardBus) support +# +# CONFIG_PCCARD is not set + +# +# PCI Hotplug Support +# +# CONFIG_HOTPLUG_PCI is not set + +# +# Advanced setup +# +# CONFIG_ADVANCED_OPTIONS is not set + +# +# Default settings for advanced configuration options are used +# +CONFIG_HIGHMEM_START=0xfe000000 +CONFIG_LOWMEM_SIZE=0x30000000 +CONFIG_KERNEL_START=0xc0000000 +CONFIG_TASK_SIZE=0x80000000 +CONFIG_BOOT_LOAD=0x00800000 + +# +# Networking +# +CONFIG_NET=y + +# +# Networking options +# +# CONFIG_NETDEBUG is not set +CONFIG_PACKET=y +# CONFIG_PACKET_MMAP is not set +CONFIG_UNIX=y +CONFIG_XFRM=y +# CONFIG_XFRM_USER is not set +# CONFIG_XFRM_SUB_POLICY is not set +# CONFIG_NET_KEY is not set +CONFIG_INET=y +CONFIG_IP_MULTICAST=y +# CONFIG_IP_ADVANCED_ROUTER is not set +CONFIG_IP_FIB_HASH=y +CONFIG_IP_PNP=y +CONFIG_IP_PNP_DHCP=y +CONFIG_IP_PNP_BOOTP=y +# CONFIG_IP_PNP_RARP is not set +# CONFIG_NET_IPIP is not set +# CONFIG_NET_IPGRE is not set +# CONFIG_IP_MROUTE is not set +# CONFIG_ARPD is not set +CONFIG_SYN_COOKIES=y +# CONFIG_INET_AH is not set +# CONFIG_INET_ESP is not set +# CONFIG_INET_IPCOMP is not set +# CONFIG_INET_XFRM_TUNNEL is not set +# CONFIG_INET_TUNNEL is not set +CONFIG_INET_XFRM_MODE_TRANSPORT=y +CONFIG_INET_XFRM_MODE_TUNNEL=y +CONFIG_INET_XFRM_MODE_BEET=y +CONFIG_INET_DIAG=y +CONFIG_INET_TCP_DIAG=y +# CONFIG_TCP_CONG_ADVANCED is not set +CONFIG_TCP_CONG_CUBIC=y +CONFIG_DEFAULT_TCP_CONG="cubic" +# CONFIG_TCP_MD5SIG is not set +# CONFIG_IPV6 is not set +# CONFIG_INET6_XFRM_TUNNEL is not set +# CONFIG_INET6_TUNNEL is not set +# CONFIG_NETWORK_SECMARK is not set +# CONFIG_NETFILTER is not set + +# +# DCCP Configuration (EXPERIMENTAL) +# +# CONFIG_IP_DCCP is not set + +# +# SCTP Configuration (EXPERIMENTAL) +# +# CONFIG_IP_SCTP is not set + +# +# TIPC Configuration (EXPERIMENTAL) +# +# CONFIG_TIPC is not set +# CONFIG_ATM is not set +# CONFIG_BRIDGE is not set +# CONFIG_VLAN_8021Q is not set +# CONFIG_DECNET is not set +# CONFIG_LLC2 is not set +# CONFIG_IPX is not set +# CONFIG_ATALK is not set +# CONFIG_X25 is not set +# CONFIG_LAPB is not set +# CONFIG_ECONET is not set +# CONFIG_WAN_ROUTER is not set + +# +# QoS and/or fair queueing +# +# CONFIG_NET_SCHED is not set + +# +# Network testing +# +# CONFIG_NET_PKTGEN is not set +# CONFIG_HAMRADIO is not set +# CONFIG_IRDA is not set +# CONFIG_BT is not set +# CONFIG_IEEE80211 is not set + +# +# Device Drivers +# + +# +# Generic Driver Options +# +CONFIG_STANDALONE=y +CONFIG_PREVENT_FIRMWARE_BUILD=y +# CONFIG_FW_LOADER is not set +# CONFIG_SYS_HYPERVISOR is not set + +# +# Connector - unified userspace <-> kernelspace linker +# +# CONFIG_CONNECTOR is not set + +# +# Memory Technology Devices (MTD) +# +CONFIG_MTD=y +# CONFIG_MTD_DEBUG is not set +# CONFIG_MTD_CONCAT is not set +# CONFIG_MTD_PARTITIONS is not set + +# +# User Modules And Translation Layers +# +CONFIG_MTD_CHAR=y +# CONFIG_MTD_BLKDEVS is not set +# CONFIG_MTD_BLOCK is not set +# CONFIG_MTD_BLOCK_RO is not set +# CONFIG_FTL is not set +# CONFIG_NFTL is not set +# CONFIG_INFTL is not set +# CONFIG_RFD_FTL is not set +# CONFIG_SSFDC is not set + +# +# RAM/ROM/Flash chip drivers +# +CONFIG_MTD_CFI=y +# CONFIG_MTD_JEDECPROBE is not set +CONFIG_MTD_GEN_PROBE=y +# CONFIG_MTD_CFI_ADV_OPTIONS is not set +CONFIG_MTD_MAP_BANK_WIDTH_1=y +CONFIG_MTD_MAP_BANK_WIDTH_2=y +CONFIG_MTD_MAP_BANK_WIDTH_4=y +# CONFIG_MTD_MAP_BANK_WIDTH_8 is not set +# CONFIG_MTD_MAP_BANK_WIDTH_16 is not set +# CONFIG_MTD_MAP_BANK_WIDTH_32 is not set +CONFIG_MTD_CFI_I1=y +CONFIG_MTD_CFI_I2=y +# CONFIG_MTD_CFI_I4 is not set +# CONFIG_MTD_CFI_I8 is not set +# CONFIG_MTD_CFI_INTELEXT is not set +CONFIG_MTD_CFI_AMDSTD=y +# CONFIG_MTD_CFI_STAA is not set +CONFIG_MTD_CFI_UTIL=y +# CONFIG_MTD_RAM is not set +# CONFIG_MTD_ROM is not set +# CONFIG_MTD_ABSENT is not set +# CONFIG_MTD_OBSOLETE_CHIPS is not set + +# +# Mapping drivers for chip access +# +# CONFIG_MTD_COMPLEX_MAPPINGS is not set +CONFIG_MTD_PHYSMAP=y +CONFIG_MTD_PHYSMAP_START=0xfe000000 +CONFIG_MTD_PHYSMAP_LEN=0x800000 +CONFIG_MTD_PHYSMAP_BANKWIDTH=2 +# CONFIG_MTD_PHYSMAP_OF is not set +# CONFIG_MTD_PLATRAM is not set + +# +# Self-contained MTD device drivers +# +# CONFIG_MTD_PMC551 is not set +# CONFIG_MTD_DATAFLASH is not set +# CONFIG_MTD_M25P80 is not set +# CONFIG_MTD_SLRAM is not set +# CONFIG_MTD_PHRAM is not set +# CONFIG_MTD_MTDRAM is not set +# CONFIG_MTD_BLOCK2MTD is not set + +# +# Disk-On-Chip Device Drivers +# +# CONFIG_MTD_DOC2000 is not set +# CONFIG_MTD_DOC2001 is not set +# CONFIG_MTD_DOC2001PLUS is not set + +# +# NAND Flash Device Drivers +# +# CONFIG_MTD_NAND is not set +# CONFIG_MTD_NAND_CAFE is not set + +# +# OneNAND Flash Device Drivers +# +# CONFIG_MTD_ONENAND is not set + +# +# Parallel port support +# +# CONFIG_PARPORT is not set + +# +# Plug and Play support +# + +# +# Block devices +# +# CONFIG_BLK_DEV_FD is not set +# CONFIG_BLK_CPQ_DA is not set +# CONFIG_BLK_CPQ_CISS_DA is not set +# CONFIG_BLK_DEV_DAC960 is not set +# CONFIG_BLK_DEV_UMEM is not set +# CONFIG_BLK_DEV_COW_COMMON is not set +CONFIG_BLK_DEV_LOOP=y +# CONFIG_BLK_DEV_CRYPTOLOOP is not set +# CONFIG_BLK_DEV_NBD is not set +# CONFIG_BLK_DEV_SX8 is not set +CONFIG_BLK_DEV_RAM=y +CONFIG_BLK_DEV_RAM_COUNT=16 +CONFIG_BLK_DEV_RAM_SIZE=32768 +CONFIG_BLK_DEV_RAM_BLOCKSIZE=1024 +CONFIG_BLK_DEV_INITRD=y +# CONFIG_CDROM_PKTCDVD is not set +# CONFIG_ATA_OVER_ETH is not set + +# +# Misc devices +# +# CONFIG_SGI_IOC4 is not set +# CONFIG_TIFM_CORE is not set + +# +# ATA/ATAPI/MFM/RLL support +# +# CONFIG_IDE is not set + +# +# SCSI device support +# +# CONFIG_RAID_ATTRS is not set +CONFIG_SCSI=y +# CONFIG_SCSI_TGT is not set +# CONFIG_SCSI_NETLINK is not set +CONFIG_SCSI_PROC_FS=y + +# +# SCSI support type (disk, tape, CD-ROM) +# +CONFIG_BLK_DEV_SD=y +# CONFIG_CHR_DEV_ST is not set +# CONFIG_CHR_DEV_OSST is not set +# CONFIG_BLK_DEV_SR is not set +CONFIG_CHR_DEV_SG=y +# CONFIG_CHR_DEV_SCH is not set + +# +# Some SCSI devices (e.g. CD jukebox) support multiple LUNs +# +# CONFIG_SCSI_MULTI_LUN is not set +# CONFIG_SCSI_CONSTANTS is not set +# CONFIG_SCSI_LOGGING is not set +# CONFIG_SCSI_SCAN_ASYNC is not set + +# +# SCSI Transports +# +CONFIG_SCSI_SPI_ATTRS=y +# CONFIG_SCSI_FC_ATTRS is not set +# CONFIG_SCSI_ISCSI_ATTRS is not set +# CONFIG_SCSI_SAS_ATTRS is not set +# CONFIG_SCSI_SAS_LIBSAS is not set + +# +# SCSI low-level drivers +# +# CONFIG_ISCSI_TCP is not set +# CONFIG_BLK_DEV_3W_XXXX_RAID is not set +# CONFIG_SCSI_3W_9XXX is not set +# CONFIG_SCSI_ACARD is not set +# CONFIG_SCSI_AACRAID is not set +# CONFIG_SCSI_AIC7XXX is not set +# CONFIG_SCSI_AIC7XXX_OLD is not set +# CONFIG_SCSI_AIC79XX is not set +# CONFIG_SCSI_AIC94XX is not set +# CONFIG_SCSI_DPT_I2O is not set +# CONFIG_SCSI_ARCMSR is not set +# CONFIG_MEGARAID_NEWGEN is not set +# CONFIG_MEGARAID_LEGACY is not set +# CONFIG_MEGARAID_SAS is not set +# CONFIG_SCSI_HPTIOP is not set +# CONFIG_SCSI_BUSLOGIC is not set +# CONFIG_SCSI_DMX3191D is not set +# CONFIG_SCSI_EATA is not set +# CONFIG_SCSI_FUTURE_DOMAIN is not set +# CONFIG_SCSI_GDTH is not set +# CONFIG_SCSI_IPS is not set +# CONFIG_SCSI_INITIO is not set +# CONFIG_SCSI_INIA100 is not set +# CONFIG_SCSI_STEX is not set +# CONFIG_SCSI_SYM53C8XX_2 is not set +# CONFIG_SCSI_QLOGIC_1280 is not set +# CONFIG_SCSI_QLA_FC is not set +# CONFIG_SCSI_QLA_ISCSI is not set +# CONFIG_SCSI_LPFC is not set +# CONFIG_SCSI_DC395x is not set +# CONFIG_SCSI_DC390T is not set +# CONFIG_SCSI_NSP32 is not set +# CONFIG_SCSI_DEBUG is not set +# CONFIG_SCSI_SRP is not set + +# +# Serial ATA (prod) and Parallel ATA (experimental) drivers +# +# CONFIG_ATA is not set + +# +# Multi-device support (RAID and LVM) +# +# CONFIG_MD is not set + +# +# Fusion MPT device support +# +# CONFIG_FUSION is not set +# CONFIG_FUSION_SPI is not set +# CONFIG_FUSION_FC is not set +# CONFIG_FUSION_SAS is not set + +# +# IEEE 1394 (FireWire) support +# +# CONFIG_IEEE1394 is not set + +# +# I2O device support +# +# CONFIG_I2O is not set + +# +# Macintosh device drivers +# +# CONFIG_MAC_EMUMOUSEBTN is not set +# CONFIG_WINDFARM is not set + +# +# Network device support +# +CONFIG_NETDEVICES=y +# CONFIG_DUMMY is not set +# CONFIG_BONDING is not set +# CONFIG_EQUALIZER is not set +# CONFIG_TUN is not set + +# +# ARCnet devices +# +# CONFIG_ARCNET is not set + +# +# PHY device support +# +CONFIG_PHYLIB=y + +# +# MII PHY device drivers +# +# CONFIG_MARVELL_PHY is not set +# CONFIG_DAVICOM_PHY is not set +# CONFIG_QSEMI_PHY is not set +# CONFIG_LXT_PHY is not set +CONFIG_CICADA_PHY=y +# CONFIG_VITESSE_PHY is not set +# CONFIG_SMSC_PHY is not set +# CONFIG_BROADCOM_PHY is not set +# CONFIG_FIXED_PHY is not set + +# +# Ethernet (10 or 100Mbit) +# +# CONFIG_NET_ETHERNET is not set + +# +# Ethernet (1000 Mbit) +# +# CONFIG_ACENIC is not set +# CONFIG_DL2K is not set +# CONFIG_E1000 is not set +# CONFIG_NS83820 is not set +# CONFIG_HAMACHI is not set +# CONFIG_YELLOWFIN is not set +# CONFIG_R8169 is not set +# CONFIG_SIS190 is not set +# CONFIG_SKGE is not set +# CONFIG_SKY2 is not set +# CONFIG_SK98LIN is not set +# CONFIG_TIGON3 is not set +# CONFIG_BNX2 is not set +CONFIG_GIANFAR=y +CONFIG_GFAR_NAPI=y +# CONFIG_QLA3XXX is not set + +# +# Ethernet (10000 Mbit) +# +# CONFIG_CHELSIO_T1 is not set +# CONFIG_IXGB is not set +# CONFIG_S2IO is not set +# CONFIG_MYRI10GE is not set +# CONFIG_NETXEN_NIC is not set + +# +# Token Ring devices +# +# CONFIG_TR is not set + +# +# Wireless LAN (non-hamradio) +# +# CONFIG_NET_RADIO is not set + +# +# Wan interfaces +# +# CONFIG_WAN is not set +# CONFIG_FDDI is not set +# CONFIG_HIPPI is not set +# CONFIG_PPP is not set +# CONFIG_SLIP is not set +# CONFIG_NET_FC is not set +# CONFIG_SHAPER is not set +# CONFIG_NETCONSOLE is not set +# CONFIG_NETPOLL is not set +# CONFIG_NET_POLL_CONTROLLER is not set + +# +# ISDN subsystem +# +# CONFIG_ISDN is not set + +# +# Telephony Support +# +# CONFIG_PHONE is not set + +# +# Input device support +# +# CONFIG_INPUT is not set + +# +# Hardware I/O ports +# +# CONFIG_SERIO is not set +# CONFIG_GAMEPORT is not set + +# +# Character devices +# +# CONFIG_VT is not set +# CONFIG_SERIAL_NONSTANDARD is not set + +# +# Serial drivers +# +CONFIG_SERIAL_8250=y +CONFIG_SERIAL_8250_CONSOLE=y +# CONFIG_SERIAL_8250_PCI is not set +CONFIG_SERIAL_8250_NR_UARTS=4 +CONFIG_SERIAL_8250_RUNTIME_UARTS=4 +# CONFIG_SERIAL_8250_EXTENDED is not set + +# +# Non-8250 serial port support +# +# CONFIG_SERIAL_UARTLITE is not set +CONFIG_SERIAL_CORE=y +CONFIG_SERIAL_CORE_CONSOLE=y +# CONFIG_SERIAL_JSM is not set +CONFIG_UNIX98_PTYS=y +CONFIG_LEGACY_PTYS=y +CONFIG_LEGACY_PTY_COUNT=256 + +# +# IPMI +# +# CONFIG_IPMI_HANDLER is not set + +# +# Watchdog Cards +# +CONFIG_WATCHDOG=y +# CONFIG_WATCHDOG_NOWAYOUT is not set + +# +# Watchdog Device Drivers +# +# CONFIG_SOFT_WATCHDOG is not set +CONFIG_83xx_WDT=y + +# +# PCI-based Watchdog Cards +# +# CONFIG_PCIPCWATCHDOG is not set +# CONFIG_WDTPCI is not set +CONFIG_HW_RANDOM=y +# CONFIG_NVRAM is not set +# CONFIG_GEN_RTC is not set +# CONFIG_DTLK is not set +# CONFIG_R3964 is not set +# CONFIG_APPLICOM is not set +# CONFIG_AGP is not set +# CONFIG_DRM is not set +# CONFIG_RAW_DRIVER is not set + +# +# TPM devices +# +# CONFIG_TCG_TPM is not set + +# +# I2C support +# +CONFIG_I2C=y +CONFIG_I2C_CHARDEV=y + +# +# I2C Algorithms +# +# CONFIG_I2C_ALGOBIT is not set +# CONFIG_I2C_ALGOPCF is not set +# CONFIG_I2C_ALGOPCA is not set + +# +# I2C Hardware Bus support +# +# CONFIG_I2C_ALI1535 is not set +# CONFIG_I2C_ALI1563 is not set +# CONFIG_I2C_ALI15X3 is not set +# CONFIG_I2C_AMD756 is not set +# CONFIG_I2C_AMD8111 is not set +# CONFIG_I2C_I801 is not set +# CONFIG_I2C_I810 is not set +# CONFIG_I2C_PIIX4 is not set +CONFIG_I2C_MPC=y +# CONFIG_I2C_NFORCE2 is not set +# CONFIG_I2C_OCORES is not set +# CONFIG_I2C_PARPORT_LIGHT is not set +# CONFIG_I2C_PROSAVAGE is not set +# CONFIG_I2C_SAVAGE4 is not set +# CONFIG_I2C_SIS5595 is not set +# CONFIG_I2C_SIS630 is not set +# CONFIG_I2C_SIS96X is not set +# CONFIG_I2C_STUB is not set +# CONFIG_I2C_VIA is not set +# CONFIG_I2C_VIAPRO is not set +# CONFIG_I2C_VOODOO3 is not set +# CONFIG_I2C_PCA_ISA is not set + +# +# Miscellaneous I2C Chip support +# +# CONFIG_SENSORS_DS1337 is not set +# CONFIG_SENSORS_DS1374 is not set +# CONFIG_SENSORS_EEPROM is not set +CONFIG_SENSORS_PCF8574=y +# CONFIG_SENSORS_PCA9539 is not set +# CONFIG_SENSORS_PCF8591 is not set +# CONFIG_SENSORS_M41T00 is not set +# CONFIG_SENSORS_MAX6875 is not set +# CONFIG_I2C_DEBUG_CORE is not set +# CONFIG_I2C_DEBUG_ALGO is not set +# CONFIG_I2C_DEBUG_BUS is not set +# CONFIG_I2C_DEBUG_CHIP is not set + +# +# SPI support +# +CONFIG_SPI=y +CONFIG_SPI_MASTER=y + +# +# SPI Master Controller Drivers +# +CONFIG_SPI_BITBANG=y +CONFIG_SPI_MPC83xx=y + +# +# SPI Protocol Masters +# + +# +# Dallas's 1-wire bus +# +# CONFIG_W1 is not set + +# +# Hardware Monitoring support +# +# CONFIG_HWMON is not set +# CONFIG_HWMON_VID is not set + +# +# Multimedia devices +# +# CONFIG_VIDEO_DEV is not set + +# +# Digital Video Broadcasting Devices +# +# CONFIG_DVB is not set + +# +# Graphics support +# +# CONFIG_FIRMWARE_EDID is not set +# CONFIG_FB is not set +# CONFIG_FB_IBM_GXT4500 is not set +# CONFIG_BACKLIGHT_LCD_SUPPORT is not set + +# +# Sound +# +# CONFIG_SOUND is not set + +# +# USB support +# +CONFIG_USB_ARCH_HAS_HCD=y +CONFIG_USB_ARCH_HAS_OHCI=y +CONFIG_USB_ARCH_HAS_EHCI=y +# CONFIG_USB is not set + +# +# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support' +# + +# +# USB Gadget Support +# +# CONFIG_USB_GADGET is not set + +# +# MMC/SD Card support +# +# CONFIG_MMC is not set + +# +# LED devices +# +# CONFIG_NEW_LEDS is not set + +# +# LED drivers +# + +# +# LED Triggers +# + +# +# InfiniBand support +# +# CONFIG_INFINIBAND is not set + +# +# EDAC - error detection and reporting (RAS) (EXPERIMENTAL) +# + +# +# Real Time Clock +# +CONFIG_RTC_LIB=y +CONFIG_RTC_CLASS=y +CONFIG_RTC_HCTOSYS=y +CONFIG_RTC_HCTOSYS_DEVICE="rtc0" +# CONFIG_RTC_DEBUG is not set + +# +# RTC interfaces +# +CONFIG_RTC_INTF_SYSFS=y +CONFIG_RTC_INTF_PROC=y +CONFIG_RTC_INTF_DEV=y +CONFIG_RTC_INTF_DEV_UIE_EMUL=y + +# +# RTC drivers +# +# CONFIG_RTC_DRV_X1205 is not set +CONFIG_RTC_DRV_DS1307=y +# CONFIG_RTC_DRV_DS1553 is not set +# CONFIG_RTC_DRV_ISL1208 is not set +# CONFIG_RTC_DRV_DS1672 is not set +# CONFIG_RTC_DRV_DS1742 is not set +# CONFIG_RTC_DRV_PCF8563 is not set +# CONFIG_RTC_DRV_PCF8583 is not set +# CONFIG_RTC_DRV_RS5C348 is not set +# CONFIG_RTC_DRV_RS5C372 is not set +# CONFIG_RTC_DRV_M48T86 is not set +# CONFIG_RTC_DRV_TEST is not set +# CONFIG_RTC_DRV_MAX6902 is not set +# CONFIG_RTC_DRV_V3020 is not set + +# +# DMA Engine support +# +CONFIG_DMA_ENGINE=y + +# +# DMA Clients +# +CONFIG_NET_DMA=y + +# +# DMA Devices +# +CONFIG_INTEL_IOATDMA=y + +# +# Virtualization +# + +# +# File systems +# +CONFIG_EXT2_FS=y +# CONFIG_EXT2_FS_XATTR is not set +# CONFIG_EXT2_FS_XIP is not set +CONFIG_EXT3_FS=y +CONFIG_EXT3_FS_XATTR=y +# CONFIG_EXT3_FS_POSIX_ACL is not set +# CONFIG_EXT3_FS_SECURITY is not set +# CONFIG_EXT4DEV_FS is not set +CONFIG_JBD=y +# CONFIG_JBD_DEBUG is not set +CONFIG_FS_MBCACHE=y +# CONFIG_REISERFS_FS is not set +# CONFIG_JFS_FS is not set +# CONFIG_FS_POSIX_ACL is not set +# CONFIG_XFS_FS is not set +# CONFIG_GFS2_FS is not set +# CONFIG_OCFS2_FS is not set +# CONFIG_MINIX_FS is not set +# CONFIG_ROMFS_FS is not set +CONFIG_INOTIFY=y +CONFIG_INOTIFY_USER=y +# CONFIG_QUOTA is not set +CONFIG_DNOTIFY=y +# CONFIG_AUTOFS_FS is not set +# CONFIG_AUTOFS4_FS is not set +# CONFIG_FUSE_FS is not set + +# +# CD-ROM/DVD Filesystems +# +# CONFIG_ISO9660_FS is not set +# CONFIG_UDF_FS is not set + +# +# DOS/FAT/NT Filesystems +# +CONFIG_FAT_FS=y +CONFIG_MSDOS_FS=y +CONFIG_VFAT_FS=y +CONFIG_FAT_DEFAULT_CODEPAGE=437 +CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1" +# CONFIG_NTFS_FS is not set + +# +# Pseudo filesystems +# +CONFIG_PROC_FS=y +CONFIG_PROC_KCORE=y +CONFIG_PROC_SYSCTL=y +CONFIG_SYSFS=y +CONFIG_TMPFS=y +# CONFIG_TMPFS_POSIX_ACL is not set +# CONFIG_HUGETLB_PAGE is not set +CONFIG_RAMFS=y +# CONFIG_CONFIGFS_FS is not set + +# +# Miscellaneous filesystems +# +# CONFIG_ADFS_FS is not set +# CONFIG_AFFS_FS is not set +# CONFIG_HFS_FS is not set +# CONFIG_HFSPLUS_FS is not set +# CONFIG_BEFS_FS is not set +# CONFIG_BFS_FS is not set +# CONFIG_EFS_FS is not set +# CONFIG_JFFS2_FS is not set +# CONFIG_CRAMFS is not set +# CONFIG_VXFS_FS is not set +# CONFIG_HPFS_FS is not set +# CONFIG_QNX4FS_FS is not set +# CONFIG_SYSV_FS is not set +# CONFIG_UFS_FS is not set + +# +# Network File Systems +# +CONFIG_NFS_FS=y +CONFIG_NFS_V3=y +# CONFIG_NFS_V3_ACL is not set +CONFIG_NFS_V4=y +# CONFIG_NFS_DIRECTIO is not set +# CONFIG_NFSD is not set +CONFIG_ROOT_NFS=y +CONFIG_LOCKD=y +CONFIG_LOCKD_V4=y +CONFIG_NFS_COMMON=y +CONFIG_SUNRPC=y +CONFIG_SUNRPC_GSS=y +CONFIG_RPCSEC_GSS_KRB5=y +# CONFIG_RPCSEC_GSS_SPKM3 is not set +# CONFIG_SMB_FS is not set +# CONFIG_CIFS is not set +# CONFIG_NCP_FS is not set +# CONFIG_CODA_FS is not set +# CONFIG_AFS_FS is not set +# CONFIG_9P_FS is not set + +# +# Partition Types +# +CONFIG_PARTITION_ADVANCED=y +# CONFIG_ACORN_PARTITION is not set +# CONFIG_OSF_PARTITION is not set +# CONFIG_AMIGA_PARTITION is not set +# CONFIG_ATARI_PARTITION is not set +CONFIG_MAC_PARTITION=y +CONFIG_MSDOS_PARTITION=y +# CONFIG_BSD_DISKLABEL is not set +# CONFIG_MINIX_SUBPARTITION is not set +# CONFIG_SOLARIS_X86_PARTITION is not set +# CONFIG_UNIXWARE_DISKLABEL is not set +# CONFIG_LDM_PARTITION is not set +# CONFIG_SGI_PARTITION is not set +# CONFIG_ULTRIX_PARTITION is not set +# CONFIG_SUN_PARTITION is not set +# CONFIG_KARMA_PARTITION is not set +# CONFIG_EFI_PARTITION is not set + +# +# Native Language Support +# +CONFIG_NLS=y +CONFIG_NLS_DEFAULT="iso8859-1" +# CONFIG_NLS_CODEPAGE_437 is not set +# CONFIG_NLS_CODEPAGE_737 is not set +# CONFIG_NLS_CODEPAGE_775 is not set +# CONFIG_NLS_CODEPAGE_850 is not set +# CONFIG_NLS_CODEPAGE_852 is not set +# CONFIG_NLS_CODEPAGE_855 is not set +# CONFIG_NLS_CODEPAGE_857 is not set +# CONFIG_NLS_CODEPAGE_860 is not set +# CONFIG_NLS_CODEPAGE_861 is not set +# CONFIG_NLS_CODEPAGE_862 is not set +# CONFIG_NLS_CODEPAGE_863 is not set +# CONFIG_NLS_CODEPAGE_864 is not set +# CONFIG_NLS_CODEPAGE_865 is not set +# CONFIG_NLS_CODEPAGE_866 is not set +# CONFIG_NLS_CODEPAGE_869 is not set +# CONFIG_NLS_CODEPAGE_936 is not set +# CONFIG_NLS_CODEPAGE_950 is not set +# CONFIG_NLS_CODEPAGE_932 is not set +# CONFIG_NLS_CODEPAGE_949 is not set +# CONFIG_NLS_CODEPAGE_874 is not set +# CONFIG_NLS_ISO8859_8 is not set +# CONFIG_NLS_CODEPAGE_1250 is not set +# CONFIG_NLS_CODEPAGE_1251 is not set +# CONFIG_NLS_ASCII is not set +# CONFIG_NLS_ISO8859_1 is not set +# CONFIG_NLS_ISO8859_2 is not set +# CONFIG_NLS_ISO8859_3 is not set +# CONFIG_NLS_ISO8859_4 is not set +# CONFIG_NLS_ISO8859_5 is not set +# CONFIG_NLS_ISO8859_6 is not set +# CONFIG_NLS_ISO8859_7 is not set +# CONFIG_NLS_ISO8859_9 is not set +# CONFIG_NLS_ISO8859_13 is not set +# CONFIG_NLS_ISO8859_14 is not set +# CONFIG_NLS_ISO8859_15 is not set +# CONFIG_NLS_KOI8_R is not set +# CONFIG_NLS_KOI8_U is not set +# CONFIG_NLS_UTF8 is not set + +# +# Distributed Lock Manager +# +# CONFIG_DLM is not set + +# +# Library routines +# +CONFIG_BITREVERSE=y +# CONFIG_CRC_CCITT is not set +# CONFIG_CRC16 is not set +CONFIG_CRC32=y +# CONFIG_LIBCRC32C is not set +CONFIG_PLIST=y +CONFIG_IOMAP_COPY=y + +# +# Instrumentation Support +# +# CONFIG_PROFILING is not set + +# +# Kernel hacking +# +# CONFIG_PRINTK_TIME is not set +CONFIG_ENABLE_MUST_CHECK=y +# CONFIG_MAGIC_SYSRQ is not set +# CONFIG_UNUSED_SYMBOLS is not set +# CONFIG_DEBUG_FS is not set +# CONFIG_HEADERS_CHECK is not set +# CONFIG_DEBUG_KERNEL is not set +CONFIG_LOG_BUF_SHIFT=14 +# CONFIG_DEBUG_BUGVERBOSE is not set +# CONFIG_BOOTX_TEXT is not set +# CONFIG_SERIAL_TEXT_DEBUG is not set +# CONFIG_PPC_EARLY_DEBUG is not set + +# +# Security options +# +# CONFIG_KEYS is not set +# CONFIG_SECURITY is not set + +# +# Cryptographic options +# +CONFIG_CRYPTO=y +CONFIG_CRYPTO_ALGAPI=y +CONFIG_CRYPTO_BLKCIPHER=y +CONFIG_CRYPTO_MANAGER=y +# CONFIG_CRYPTO_HMAC is not set +# CONFIG_CRYPTO_XCBC is not set +# CONFIG_CRYPTO_NULL is not set +# CONFIG_CRYPTO_MD4 is not set +CONFIG_CRYPTO_MD5=y +# CONFIG_CRYPTO_SHA1 is not set +# CONFIG_CRYPTO_SHA256 is not set +# CONFIG_CRYPTO_SHA512 is not set +# CONFIG_CRYPTO_WP512 is not set +# CONFIG_CRYPTO_TGR192 is not set +# CONFIG_CRYPTO_GF128MUL is not set +# CONFIG_CRYPTO_ECB is not set +CONFIG_CRYPTO_CBC=y +# CONFIG_CRYPTO_LRW is not set +CONFIG_CRYPTO_DES=y +# CONFIG_CRYPTO_BLOWFISH is not set +# CONFIG_CRYPTO_TWOFISH is not set +# CONFIG_CRYPTO_SERPENT is not set +# CONFIG_CRYPTO_AES is not set +# CONFIG_CRYPTO_CAST5 is not set +# CONFIG_CRYPTO_CAST6 is not set +# CONFIG_CRYPTO_TEA is not set +# CONFIG_CRYPTO_ARC4 is not set +# CONFIG_CRYPTO_KHAZAD is not set +# CONFIG_CRYPTO_ANUBIS is not set +# CONFIG_CRYPTO_DEFLATE is not set +# CONFIG_CRYPTO_MICHAEL_MIC is not set +# CONFIG_CRYPTO_CRC32C is not set +# CONFIG_CRYPTO_TEST is not set + +# +# Hardware crypto devices +# diff --git a/arch/powerpc/configs/mpc834x_mds_defconfig b/arch/powerpc/configs/mpc834x_mds_defconfig index c24db58..2e3f8ef 100644 --- a/arch/powerpc/configs/mpc834x_mds_defconfig +++ b/arch/powerpc/configs/mpc834x_mds_defconfig @@ -1,7 +1,7 @@ # # Automatically generated make config: don't edit -# Linux kernel version: 2.6.20-rc5 -# Mon Jan 22 22:24:10 2007 +# Linux kernel version: 2.6.20 +# Thu Feb 8 01:00:48 2007 # # CONFIG_PPC64 is not set CONFIG_PPC32=y @@ -34,9 +34,9 @@ # CONFIG_PPC_82xx is not set CONFIG_PPC_83xx=y # CONFIG_PPC_85xx is not set # CONFIG_PPC_86xx is not set +# CONFIG_PPC_8xx is not set # CONFIG_40x is not set # CONFIG_44x is not set -# CONFIG_8xx is not set # CONFIG_E200 is not set CONFIG_6xx=y CONFIG_83xx=y @@ -128,8 +128,9 @@ # CONFIG_WANT_EARLY_SERIAL is not set # # Platform support # +# CONFIG_MPC8313_RDB is not set # CONFIG_MPC832x_MDS is not set -CONFIG_MPC834x_SYS=y +CONFIG_MPC834x_MDS=y # CONFIG_MPC834x_ITX is not set # CONFIG_MPC8360E_PB is not set CONFIG_MPC834x=y @@ -149,7 +150,6 @@ # CONFIG_PREEMPT_VOLUNTARY is not set # CONFIG_PREEMPT is not set CONFIG_BINFMT_ELF=y # CONFIG_BINFMT_MISC is not set -CONFIG_MATH_EMULATION=y CONFIG_ARCH_ENABLE_MEMORY_HOTPLUG=y CONFIG_ARCH_FLATMEM_ENABLE=y CONFIG_ARCH_POPULATES_NODE_MAP=y diff --git a/arch/powerpc/configs/mpc8360emds_defconfig b/arch/powerpc/configs/mpc8360emds_defconfig index 58e6795..bbe38cc 100644 --- a/arch/powerpc/configs/mpc8360emds_defconfig +++ b/arch/powerpc/configs/mpc8360emds_defconfig @@ -1,7 +1,7 @@ # # Automatically generated make config: don't edit # Linux kernel version: 2.6.20-rc5 -# Mon Jan 22 22:24:40 2007 +# Fri Jan 26 00:19:45 2007 # # CONFIG_PPC64 is not set CONFIG_PPC32=y @@ -150,7 +150,6 @@ # CONFIG_PREEMPT_VOLUNTARY is not set # CONFIG_PREEMPT is not set CONFIG_BINFMT_ELF=y # CONFIG_BINFMT_MISC is not set -CONFIG_MATH_EMULATION=y CONFIG_ARCH_ENABLE_MEMORY_HOTPLUG=y CONFIG_ARCH_FLATMEM_ENABLE=y CONFIG_ARCH_POPULATES_NODE_MAP=y diff --git a/arch/powerpc/configs/mpc8568mds_defconfig b/arch/powerpc/configs/mpc8568mds_defconfig new file mode 100644 index 0000000..058e06d --- /dev/null +++ b/arch/powerpc/configs/mpc8568mds_defconfig @@ -0,0 +1,992 @@ +# +# Automatically generated make config: don't edit +# Linux kernel version: 2.6.20-rc5 +# Wed Feb 7 23:54:25 2007 +# +# CONFIG_PPC64 is not set +CONFIG_PPC32=y +CONFIG_PPC_MERGE=y +CONFIG_MMU=y +CONFIG_GENERIC_HARDIRQS=y +CONFIG_IRQ_PER_CPU=y +CONFIG_RWSEM_XCHGADD_ALGORITHM=y +CONFIG_ARCH_HAS_ILOG2_U32=y +CONFIG_GENERIC_HWEIGHT=y +CONFIG_GENERIC_CALIBRATE_DELAY=y +CONFIG_GENERIC_FIND_NEXT_BIT=y +CONFIG_PPC=y +CONFIG_EARLY_PRINTK=y +CONFIG_GENERIC_NVRAM=y +CONFIG_SCHED_NO_NO_OMIT_FRAME_POINTER=y +CONFIG_ARCH_MAY_HAVE_PC_FDC=y +CONFIG_PPC_OF=y +CONFIG_PPC_UDBG_16550=y +# CONFIG_GENERIC_TBSYNC is not set +CONFIG_AUDIT_ARCH=y +CONFIG_GENERIC_BUG=y +CONFIG_DEFAULT_UIMAGE=y + +# +# Processor support +# +# CONFIG_CLASSIC32 is not set +# CONFIG_PPC_82xx is not set +# CONFIG_PPC_83xx is not set +CONFIG_PPC_85xx=y +# CONFIG_PPC_86xx is not set +# CONFIG_40x is not set +# CONFIG_44x is not set +# CONFIG_8xx is not set +# CONFIG_E200 is not set +CONFIG_85xx=y +CONFIG_E500=y +# CONFIG_PPC_DCR_NATIVE is not set +# CONFIG_PPC_DCR_MMIO is not set +CONFIG_BOOKE=y +CONFIG_FSL_BOOKE=y +# CONFIG_PHYS_64BIT is not set +CONFIG_SPE=y +CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config" + +# +# Code maturity level options +# +CONFIG_EXPERIMENTAL=y +CONFIG_BROKEN_ON_SMP=y +CONFIG_INIT_ENV_ARG_LIMIT=32 + +# +# General setup +# +CONFIG_LOCALVERSION="" +CONFIG_LOCALVERSION_AUTO=y +CONFIG_SWAP=y +CONFIG_SYSVIPC=y +# CONFIG_IPC_NS is not set +# CONFIG_POSIX_MQUEUE is not set +# CONFIG_BSD_PROCESS_ACCT is not set +# CONFIG_TASKSTATS is not set +# CONFIG_UTS_NS is not set +# CONFIG_AUDIT is not set +# CONFIG_IKCONFIG is not set +CONFIG_SYSFS_DEPRECATED=y +# CONFIG_RELAY is not set +CONFIG_INITRAMFS_SOURCE="" +# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set +CONFIG_SYSCTL=y +CONFIG_EMBEDDED=y +CONFIG_SYSCTL_SYSCALL=y +# CONFIG_KALLSYMS is not set +CONFIG_HOTPLUG=y +CONFIG_PRINTK=y +CONFIG_BUG=y +CONFIG_ELF_CORE=y +CONFIG_BASE_FULL=y +CONFIG_FUTEX=y +# CONFIG_EPOLL is not set +CONFIG_SHMEM=y +CONFIG_SLAB=y +CONFIG_VM_EVENT_COUNTERS=y +CONFIG_RT_MUTEXES=y +# CONFIG_TINY_SHMEM is not set +CONFIG_BASE_SMALL=0 +# CONFIG_SLOB is not set + +# +# Loadable module support +# +CONFIG_MODULES=y +CONFIG_MODULE_UNLOAD=y +# CONFIG_MODULE_FORCE_UNLOAD is not set +# CONFIG_MODVERSIONS is not set +# CONFIG_MODULE_SRCVERSION_ALL is not set +# CONFIG_KMOD is not set + +# +# Block layer +# +CONFIG_BLOCK=y +# CONFIG_LBD is not set +# CONFIG_BLK_DEV_IO_TRACE is not set +# CONFIG_LSF is not set + +# +# IO Schedulers +# +CONFIG_IOSCHED_NOOP=y +CONFIG_IOSCHED_AS=y +CONFIG_IOSCHED_DEADLINE=y +CONFIG_IOSCHED_CFQ=y +CONFIG_DEFAULT_AS=y +# CONFIG_DEFAULT_DEADLINE is not set +# CONFIG_DEFAULT_CFQ is not set +# CONFIG_DEFAULT_NOOP is not set +CONFIG_DEFAULT_IOSCHED="anticipatory" +# CONFIG_WANT_EARLY_SERIAL is not set + +# +# Platform support +# +# CONFIG_MPC8540_ADS is not set +# CONFIG_MPC8560_ADS is not set +# CONFIG_MPC85xx_CDS is not set +CONFIG_MPC8568_MDS=y +CONFIG_MPC85xx=y +CONFIG_PPC_INDIRECT_PCI_BE=y +CONFIG_MPIC=y + +# +# Kernel options +# +# CONFIG_HIGHMEM is not set +# CONFIG_HZ_100 is not set +CONFIG_HZ_250=y +# CONFIG_HZ_300 is not set +# CONFIG_HZ_1000 is not set +CONFIG_HZ=250 +CONFIG_PREEMPT_NONE=y +# CONFIG_PREEMPT_VOLUNTARY is not set +# CONFIG_PREEMPT is not set +CONFIG_BINFMT_ELF=y +# CONFIG_BINFMT_MISC is not set +CONFIG_MATH_EMULATION=y +CONFIG_ARCH_ENABLE_MEMORY_HOTPLUG=y +CONFIG_ARCH_FLATMEM_ENABLE=y +CONFIG_ARCH_POPULATES_NODE_MAP=y +CONFIG_SELECT_MEMORY_MODEL=y +CONFIG_FLATMEM_MANUAL=y +# CONFIG_DISCONTIGMEM_MANUAL is not set +# CONFIG_SPARSEMEM_MANUAL is not set +CONFIG_FLATMEM=y +CONFIG_FLAT_NODE_MEM_MAP=y +# CONFIG_SPARSEMEM_STATIC is not set +CONFIG_SPLIT_PTLOCK_CPUS=4 +# CONFIG_RESOURCES_64BIT is not set +CONFIG_PROC_DEVICETREE=y +# CONFIG_CMDLINE_BOOL is not set +# CONFIG_PM is not set +CONFIG_SECCOMP=y +CONFIG_ISA_DMA_API=y + +# +# Bus options +# +# CONFIG_MPIC_WEIRD is not set +# CONFIG_PPC_I8259 is not set +CONFIG_PPC_INDIRECT_PCI=y +CONFIG_FSL_SOC=y +# CONFIG_PCI is not set +# CONFIG_PCI_DOMAINS is not set + +# +# PCCARD (PCMCIA/CardBus) support +# +# CONFIG_PCCARD is not set + +# +# PCI Hotplug Support +# + +# +# Advanced setup +# +# CONFIG_ADVANCED_OPTIONS is not set + +# +# Default settings for advanced configuration options are used +# +CONFIG_HIGHMEM_START=0xfe000000 +CONFIG_LOWMEM_SIZE=0x30000000 +CONFIG_KERNEL_START=0xc0000000 +CONFIG_TASK_SIZE=0x80000000 +CONFIG_BOOT_LOAD=0x00800000 + +# +# Networking +# +CONFIG_NET=y + +# +# Networking options +# +# CONFIG_NETDEBUG is not set +CONFIG_PACKET=y +# CONFIG_PACKET_MMAP is not set +CONFIG_UNIX=y +CONFIG_XFRM=y +# CONFIG_XFRM_USER is not set +# CONFIG_XFRM_SUB_POLICY is not set +# CONFIG_NET_KEY is not set +CONFIG_INET=y +CONFIG_IP_MULTICAST=y +# CONFIG_IP_ADVANCED_ROUTER is not set +CONFIG_IP_FIB_HASH=y +CONFIG_IP_PNP=y +CONFIG_IP_PNP_DHCP=y +CONFIG_IP_PNP_BOOTP=y +# CONFIG_IP_PNP_RARP is not set +# CONFIG_NET_IPIP is not set +# CONFIG_NET_IPGRE is not set +# CONFIG_IP_MROUTE is not set +# CONFIG_ARPD is not set +CONFIG_SYN_COOKIES=y +# CONFIG_INET_AH is not set +# CONFIG_INET_ESP is not set +# CONFIG_INET_IPCOMP is not set +# CONFIG_INET_XFRM_TUNNEL is not set +# CONFIG_INET_TUNNEL is not set +CONFIG_INET_XFRM_MODE_TRANSPORT=y +CONFIG_INET_XFRM_MODE_TUNNEL=y +CONFIG_INET_XFRM_MODE_BEET=y +CONFIG_INET_DIAG=y +CONFIG_INET_TCP_DIAG=y +# CONFIG_TCP_CONG_ADVANCED is not set +CONFIG_TCP_CONG_CUBIC=y +CONFIG_DEFAULT_TCP_CONG="cubic" +# CONFIG_TCP_MD5SIG is not set +# CONFIG_IPV6 is not set +# CONFIG_INET6_XFRM_TUNNEL is not set +# CONFIG_INET6_TUNNEL is not set +# CONFIG_NETWORK_SECMARK is not set +# CONFIG_NETFILTER is not set + +# +# DCCP Configuration (EXPERIMENTAL) +# +# CONFIG_IP_DCCP is not set + +# +# SCTP Configuration (EXPERIMENTAL) +# +# CONFIG_IP_SCTP is not set + +# +# TIPC Configuration (EXPERIMENTAL) +# +# CONFIG_TIPC is not set +# CONFIG_ATM is not set +# CONFIG_BRIDGE is not set +# CONFIG_VLAN_8021Q is not set +# CONFIG_DECNET is not set +# CONFIG_LLC2 is not set +# CONFIG_IPX is not set +# CONFIG_ATALK is not set +# CONFIG_X25 is not set +# CONFIG_LAPB is not set +# CONFIG_ECONET is not set +# CONFIG_WAN_ROUTER is not set + +# +# QoS and/or fair queueing +# +# CONFIG_NET_SCHED is not set + +# +# Network testing +# +# CONFIG_NET_PKTGEN is not set +# CONFIG_HAMRADIO is not set +# CONFIG_IRDA is not set +# CONFIG_BT is not set +# CONFIG_IEEE80211 is not set + +# +# Device Drivers +# + +# +# Generic Driver Options +# +CONFIG_STANDALONE=y +CONFIG_PREVENT_FIRMWARE_BUILD=y +# CONFIG_FW_LOADER is not set +# CONFIG_DEBUG_DRIVER is not set +# CONFIG_SYS_HYPERVISOR is not set + +# +# Connector - unified userspace <-> kernelspace linker +# +# CONFIG_CONNECTOR is not set + +# +# Memory Technology Devices (MTD) +# +# CONFIG_MTD is not set + +# +# Parallel port support +# +# CONFIG_PARPORT is not set + +# +# Plug and Play support +# + +# +# Block devices +# +# CONFIG_BLK_DEV_FD is not set +# CONFIG_BLK_DEV_COW_COMMON is not set +CONFIG_BLK_DEV_LOOP=y +# CONFIG_BLK_DEV_CRYPTOLOOP is not set +# CONFIG_BLK_DEV_NBD is not set +CONFIG_BLK_DEV_RAM=y +CONFIG_BLK_DEV_RAM_COUNT=16 +CONFIG_BLK_DEV_RAM_SIZE=32768 +CONFIG_BLK_DEV_RAM_BLOCKSIZE=1024 +CONFIG_BLK_DEV_INITRD=y +# CONFIG_CDROM_PKTCDVD is not set +# CONFIG_ATA_OVER_ETH is not set + +# +# Misc devices +# +# CONFIG_TIFM_CORE is not set + +# +# ATA/ATAPI/MFM/RLL support +# +# CONFIG_IDE is not set + +# +# SCSI device support +# +# CONFIG_RAID_ATTRS is not set +CONFIG_SCSI=y +# CONFIG_SCSI_TGT is not set +# CONFIG_SCSI_NETLINK is not set +CONFIG_SCSI_PROC_FS=y + +# +# SCSI support type (disk, tape, CD-ROM) +# +# CONFIG_BLK_DEV_SD is not set +# CONFIG_CHR_DEV_ST is not set +# CONFIG_CHR_DEV_OSST is not set +# CONFIG_BLK_DEV_SR is not set +# CONFIG_CHR_DEV_SG is not set +# CONFIG_CHR_DEV_SCH is not set + +# +# Some SCSI devices (e.g. CD jukebox) support multiple LUNs +# +# CONFIG_SCSI_MULTI_LUN is not set +# CONFIG_SCSI_CONSTANTS is not set +# CONFIG_SCSI_LOGGING is not set +# CONFIG_SCSI_SCAN_ASYNC is not set + +# +# SCSI Transports +# +# CONFIG_SCSI_SPI_ATTRS is not set +# CONFIG_SCSI_FC_ATTRS is not set +# CONFIG_SCSI_ISCSI_ATTRS is not set +# CONFIG_SCSI_SAS_ATTRS is not set +# CONFIG_SCSI_SAS_LIBSAS is not set + +# +# SCSI low-level drivers +# +# CONFIG_ISCSI_TCP is not set +# CONFIG_SCSI_DEBUG is not set + +# +# Serial ATA (prod) and Parallel ATA (experimental) drivers +# +# CONFIG_ATA is not set + +# +# Multi-device support (RAID and LVM) +# +# CONFIG_MD is not set + +# +# Fusion MPT device support +# +# CONFIG_FUSION is not set + +# +# IEEE 1394 (FireWire) support +# + +# +# I2O device support +# + +# +# Macintosh device drivers +# +# CONFIG_MAC_EMUMOUSEBTN is not set +# CONFIG_WINDFARM is not set + +# +# Network device support +# +CONFIG_NETDEVICES=y +# CONFIG_DUMMY is not set +# CONFIG_BONDING is not set +# CONFIG_EQUALIZER is not set +# CONFIG_TUN is not set + +# +# PHY device support +# +CONFIG_PHYLIB=y + +# +# MII PHY device drivers +# +CONFIG_MARVELL_PHY=y +# CONFIG_DAVICOM_PHY is not set +# CONFIG_QSEMI_PHY is not set +# CONFIG_LXT_PHY is not set +# CONFIG_CICADA_PHY is not set +# CONFIG_VITESSE_PHY is not set +# CONFIG_SMSC_PHY is not set +# CONFIG_BROADCOM_PHY is not set +# CONFIG_FIXED_PHY is not set + +# +# Ethernet (10 or 100Mbit) +# +CONFIG_NET_ETHERNET=y +CONFIG_MII=y + +# +# Ethernet (1000 Mbit) +# +CONFIG_GIANFAR=y +CONFIG_GFAR_NAPI=y + +# +# Ethernet (10000 Mbit) +# + +# +# Token Ring devices +# + +# +# Wireless LAN (non-hamradio) +# +# CONFIG_NET_RADIO is not set + +# +# Wan interfaces +# +# CONFIG_WAN is not set +# CONFIG_PPP is not set +# CONFIG_SLIP is not set +# CONFIG_SHAPER is not set +# CONFIG_NETCONSOLE is not set +# CONFIG_NETPOLL is not set +# CONFIG_NET_POLL_CONTROLLER is not set + +# +# ISDN subsystem +# +# CONFIG_ISDN is not set + +# +# Telephony Support +# +# CONFIG_PHONE is not set + +# +# Input device support +# +CONFIG_INPUT=y +# CONFIG_INPUT_FF_MEMLESS is not set + +# +# Userland interfaces +# +# CONFIG_INPUT_MOUSEDEV is not set +# CONFIG_INPUT_JOYDEV is not set +# CONFIG_INPUT_TSDEV is not set +# CONFIG_INPUT_EVDEV is not set +# CONFIG_INPUT_EVBUG is not set + +# +# Input Device Drivers +# +# CONFIG_INPUT_KEYBOARD is not set +# CONFIG_INPUT_MOUSE is not set +# CONFIG_INPUT_JOYSTICK is not set +# CONFIG_INPUT_TOUCHSCREEN is not set +# CONFIG_INPUT_MISC is not set + +# +# Hardware I/O ports +# +# CONFIG_SERIO is not set +# CONFIG_GAMEPORT is not set + +# +# Character devices +# +# CONFIG_VT is not set +# CONFIG_SERIAL_NONSTANDARD is not set + +# +# Serial drivers +# +CONFIG_SERIAL_8250=y +CONFIG_SERIAL_8250_CONSOLE=y +CONFIG_SERIAL_8250_NR_UARTS=4 +CONFIG_SERIAL_8250_RUNTIME_UARTS=4 +# CONFIG_SERIAL_8250_EXTENDED is not set + +# +# Non-8250 serial port support +# +# CONFIG_SERIAL_UARTLITE is not set +CONFIG_SERIAL_CORE=y +CONFIG_SERIAL_CORE_CONSOLE=y +CONFIG_UNIX98_PTYS=y +CONFIG_LEGACY_PTYS=y +CONFIG_LEGACY_PTY_COUNT=256 + +# +# IPMI +# +# CONFIG_IPMI_HANDLER is not set + +# +# Watchdog Cards +# +CONFIG_WATCHDOG=y +# CONFIG_WATCHDOG_NOWAYOUT is not set + +# +# Watchdog Device Drivers +# +# CONFIG_SOFT_WATCHDOG is not set +# CONFIG_BOOKE_WDT is not set +CONFIG_HW_RANDOM=y +# CONFIG_NVRAM is not set +CONFIG_GEN_RTC=y +# CONFIG_GEN_RTC_X is not set +# CONFIG_DTLK is not set +# CONFIG_R3964 is not set +# CONFIG_RAW_DRIVER is not set + +# +# TPM devices +# +# CONFIG_TCG_TPM is not set + +# +# I2C support +# +CONFIG_I2C=y +CONFIG_I2C_CHARDEV=y + +# +# I2C Algorithms +# +# CONFIG_I2C_ALGOBIT is not set +# CONFIG_I2C_ALGOPCF is not set +# CONFIG_I2C_ALGOPCA is not set + +# +# I2C Hardware Bus support +# +CONFIG_I2C_MPC=y +# CONFIG_I2C_OCORES is not set +# CONFIG_I2C_PARPORT_LIGHT is not set +# CONFIG_I2C_STUB is not set +# CONFIG_I2C_PCA_ISA is not set + +# +# Miscellaneous I2C Chip support +# +# CONFIG_SENSORS_DS1337 is not set +# CONFIG_SENSORS_DS1374 is not set +# CONFIG_SENSORS_EEPROM is not set +# CONFIG_SENSORS_PCF8574 is not set +# CONFIG_SENSORS_PCA9539 is not set +# CONFIG_SENSORS_PCF8591 is not set +# CONFIG_SENSORS_M41T00 is not set +# CONFIG_SENSORS_MAX6875 is not set +# CONFIG_I2C_DEBUG_CORE is not set +# CONFIG_I2C_DEBUG_ALGO is not set +# CONFIG_I2C_DEBUG_BUS is not set +# CONFIG_I2C_DEBUG_CHIP is not set + +# +# SPI support +# +# CONFIG_SPI is not set +# CONFIG_SPI_MASTER is not set + +# +# Dallas's 1-wire bus +# +# CONFIG_W1 is not set + +# +# Hardware Monitoring support +# +CONFIG_HWMON=y +# CONFIG_HWMON_VID is not set +# CONFIG_SENSORS_ABITUGURU is not set +# CONFIG_SENSORS_ADM1021 is not set +# CONFIG_SENSORS_ADM1025 is not set +# CONFIG_SENSORS_ADM1026 is not set +# CONFIG_SENSORS_ADM1031 is not set +# CONFIG_SENSORS_ADM9240 is not set +# CONFIG_SENSORS_ASB100 is not set +# CONFIG_SENSORS_ATXP1 is not set +# CONFIG_SENSORS_DS1621 is not set +# CONFIG_SENSORS_F71805F is not set +# CONFIG_SENSORS_FSCHER is not set +# CONFIG_SENSORS_FSCPOS is not set +# CONFIG_SENSORS_GL518SM is not set +# CONFIG_SENSORS_GL520SM is not set +# CONFIG_SENSORS_IT87 is not set +# CONFIG_SENSORS_LM63 is not set +# CONFIG_SENSORS_LM75 is not set +# CONFIG_SENSORS_LM77 is not set +# CONFIG_SENSORS_LM78 is not set +# CONFIG_SENSORS_LM80 is not set +# CONFIG_SENSORS_LM83 is not set +# CONFIG_SENSORS_LM85 is not set +# CONFIG_SENSORS_LM87 is not set +# CONFIG_SENSORS_LM90 is not set +# CONFIG_SENSORS_LM92 is not set +# CONFIG_SENSORS_MAX1619 is not set +# CONFIG_SENSORS_PC87360 is not set +# CONFIG_SENSORS_PC87427 is not set +# CONFIG_SENSORS_SMSC47M1 is not set +# CONFIG_SENSORS_SMSC47M192 is not set +# CONFIG_SENSORS_SMSC47B397 is not set +# CONFIG_SENSORS_VT1211 is not set +# CONFIG_SENSORS_W83781D is not set +# CONFIG_SENSORS_W83791D is not set +# CONFIG_SENSORS_W83792D is not set +# CONFIG_SENSORS_W83793 is not set +# CONFIG_SENSORS_W83L785TS is not set +# CONFIG_SENSORS_W83627HF is not set +# CONFIG_SENSORS_W83627EHF is not set +# CONFIG_HWMON_DEBUG_CHIP is not set + +# +# Multimedia devices +# +# CONFIG_VIDEO_DEV is not set + +# +# Digital Video Broadcasting Devices +# +# CONFIG_DVB is not set + +# +# Graphics support +# +CONFIG_FIRMWARE_EDID=y +# CONFIG_FB is not set +# CONFIG_FB_IBM_GXT4500 is not set +# CONFIG_BACKLIGHT_LCD_SUPPORT is not set + +# +# Sound +# +# CONFIG_SOUND is not set + +# +# HID Devices +# +CONFIG_HID=y + +# +# USB support +# +# CONFIG_USB_ARCH_HAS_HCD is not set +# CONFIG_USB_ARCH_HAS_OHCI is not set +# CONFIG_USB_ARCH_HAS_EHCI is not set + +# +# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support' +# + +# +# USB Gadget Support +# +# CONFIG_USB_GADGET is not set + +# +# MMC/SD Card support +# +# CONFIG_MMC is not set + +# +# LED devices +# +# CONFIG_NEW_LEDS is not set + +# +# LED drivers +# + +# +# LED Triggers +# + +# +# InfiniBand support +# + +# +# EDAC - error detection and reporting (RAS) (EXPERIMENTAL) +# + +# +# Real Time Clock +# +# CONFIG_RTC_CLASS is not set + +# +# DMA Engine support +# +# CONFIG_DMA_ENGINE is not set + +# +# DMA Clients +# + +# +# DMA Devices +# + +# +# Virtualization +# + +# +# File systems +# +CONFIG_EXT2_FS=y +# CONFIG_EXT2_FS_XATTR is not set +# CONFIG_EXT2_FS_XIP is not set +CONFIG_EXT3_FS=y +CONFIG_EXT3_FS_XATTR=y +# CONFIG_EXT3_FS_POSIX_ACL is not set +# CONFIG_EXT3_FS_SECURITY is not set +# CONFIG_EXT4DEV_FS is not set +CONFIG_JBD=y +# CONFIG_JBD_DEBUG is not set +CONFIG_FS_MBCACHE=y +# CONFIG_REISERFS_FS is not set +# CONFIG_JFS_FS is not set +# CONFIG_FS_POSIX_ACL is not set +# CONFIG_XFS_FS is not set +# CONFIG_GFS2_FS is not set +# CONFIG_OCFS2_FS is not set +# CONFIG_MINIX_FS is not set +# CONFIG_ROMFS_FS is not set +CONFIG_INOTIFY=y +CONFIG_INOTIFY_USER=y +# CONFIG_QUOTA is not set +CONFIG_DNOTIFY=y +# CONFIG_AUTOFS_FS is not set +# CONFIG_AUTOFS4_FS is not set +# CONFIG_FUSE_FS is not set + +# +# CD-ROM/DVD Filesystems +# +# CONFIG_ISO9660_FS is not set +# CONFIG_UDF_FS is not set + +# +# DOS/FAT/NT Filesystems +# +# CONFIG_MSDOS_FS is not set +# CONFIG_VFAT_FS is not set +# CONFIG_NTFS_FS is not set + +# +# Pseudo filesystems +# +CONFIG_PROC_FS=y +CONFIG_PROC_KCORE=y +CONFIG_PROC_SYSCTL=y +CONFIG_SYSFS=y +CONFIG_TMPFS=y +# CONFIG_TMPFS_POSIX_ACL is not set +# CONFIG_HUGETLB_PAGE is not set +CONFIG_RAMFS=y +# CONFIG_CONFIGFS_FS is not set + +# +# Miscellaneous filesystems +# +# CONFIG_ADFS_FS is not set +# CONFIG_AFFS_FS is not set +# CONFIG_HFS_FS is not set +# CONFIG_HFSPLUS_FS is not set +# CONFIG_BEFS_FS is not set +# CONFIG_BFS_FS is not set +# CONFIG_EFS_FS is not set +# CONFIG_CRAMFS is not set +# CONFIG_VXFS_FS is not set +# CONFIG_HPFS_FS is not set +# CONFIG_QNX4FS_FS is not set +# CONFIG_SYSV_FS is not set +# CONFIG_UFS_FS is not set + +# +# Network File Systems +# +CONFIG_NFS_FS=y +CONFIG_NFS_V3=y +# CONFIG_NFS_V3_ACL is not set +CONFIG_NFS_V4=y +# CONFIG_NFS_DIRECTIO is not set +# CONFIG_NFSD is not set +CONFIG_ROOT_NFS=y +CONFIG_LOCKD=y +CONFIG_LOCKD_V4=y +CONFIG_NFS_COMMON=y +CONFIG_SUNRPC=y +CONFIG_SUNRPC_GSS=y +CONFIG_RPCSEC_GSS_KRB5=y +# CONFIG_RPCSEC_GSS_SPKM3 is not set +# CONFIG_SMB_FS is not set +# CONFIG_CIFS is not set +# CONFIG_NCP_FS is not set +# CONFIG_CODA_FS is not set +# CONFIG_AFS_FS is not set +# CONFIG_9P_FS is not set + +# +# Partition Types +# +CONFIG_PARTITION_ADVANCED=y +# CONFIG_ACORN_PARTITION is not set +# CONFIG_OSF_PARTITION is not set +# CONFIG_AMIGA_PARTITION is not set +# CONFIG_ATARI_PARTITION is not set +# CONFIG_MAC_PARTITION is not set +# CONFIG_MSDOS_PARTITION is not set +# CONFIG_LDM_PARTITION is not set +# CONFIG_SGI_PARTITION is not set +# CONFIG_ULTRIX_PARTITION is not set +# CONFIG_SUN_PARTITION is not set +# CONFIG_KARMA_PARTITION is not set +# CONFIG_EFI_PARTITION is not set + +# +# Native Language Support +# +# CONFIG_NLS is not set + +# +# Distributed Lock Manager +# +# CONFIG_DLM is not set + +# +# Library routines +# +CONFIG_BITREVERSE=y +# CONFIG_CRC_CCITT is not set +# CONFIG_CRC16 is not set +CONFIG_CRC32=y +# CONFIG_LIBCRC32C is not set +CONFIG_PLIST=y +CONFIG_IOMAP_COPY=y + +# +# Instrumentation Support +# +CONFIG_PROFILING=y +CONFIG_OPROFILE=y + +# +# Kernel hacking +# +# CONFIG_PRINTK_TIME is not set +CONFIG_ENABLE_MUST_CHECK=y +# CONFIG_MAGIC_SYSRQ is not set +# CONFIG_UNUSED_SYMBOLS is not set +# CONFIG_DEBUG_FS is not set +# CONFIG_HEADERS_CHECK is not set +CONFIG_DEBUG_KERNEL=y +CONFIG_LOG_BUF_SHIFT=14 +CONFIG_DETECT_SOFTLOCKUP=y +# CONFIG_SCHEDSTATS is not set +# CONFIG_DEBUG_SLAB is not set +# CONFIG_DEBUG_RT_MUTEXES is not set +# CONFIG_RT_MUTEX_TESTER is not set +# CONFIG_DEBUG_SPINLOCK is not set +# CONFIG_DEBUG_MUTEXES is not set +# CONFIG_DEBUG_RWSEMS is not set +# CONFIG_DEBUG_SPINLOCK_SLEEP is not set +# CONFIG_DEBUG_LOCKING_API_SELFTESTS is not set +# CONFIG_DEBUG_KOBJECT is not set +# CONFIG_DEBUG_BUGVERBOSE is not set +# CONFIG_DEBUG_INFO is not set +# CONFIG_DEBUG_VM is not set +# CONFIG_DEBUG_LIST is not set +CONFIG_FORCED_INLINING=y +# CONFIG_RCU_TORTURE_TEST is not set +CONFIG_DEBUGGER=y +# CONFIG_XMON is not set +# CONFIG_BDI_SWITCH is not set +CONFIG_BOOTX_TEXT=y +CONFIG_PPC_EARLY_DEBUG=y +# CONFIG_PPC_EARLY_DEBUG_LPAR is not set +# CONFIG_PPC_EARLY_DEBUG_G5 is not set +# CONFIG_PPC_EARLY_DEBUG_RTAS_PANEL is not set +# CONFIG_PPC_EARLY_DEBUG_RTAS_CONSOLE is not set +# CONFIG_PPC_EARLY_DEBUG_MAPLE is not set +# CONFIG_PPC_EARLY_DEBUG_ISERIES is not set + +# +# Security options +# +# CONFIG_KEYS is not set +# CONFIG_SECURITY is not set + +# +# Cryptographic options +# +CONFIG_CRYPTO=y +CONFIG_CRYPTO_ALGAPI=y +CONFIG_CRYPTO_BLKCIPHER=y +CONFIG_CRYPTO_MANAGER=y +# CONFIG_CRYPTO_HMAC is not set +# CONFIG_CRYPTO_XCBC is not set +# CONFIG_CRYPTO_NULL is not set +# CONFIG_CRYPTO_MD4 is not set +CONFIG_CRYPTO_MD5=y +# CONFIG_CRYPTO_SHA1 is not set +# CONFIG_CRYPTO_SHA256 is not set +# CONFIG_CRYPTO_SHA512 is not set +# CONFIG_CRYPTO_WP512 is not set +# CONFIG_CRYPTO_TGR192 is not set +# CONFIG_CRYPTO_GF128MUL is not set +CONFIG_CRYPTO_ECB=m +CONFIG_CRYPTO_CBC=y +# CONFIG_CRYPTO_LRW is not set +CONFIG_CRYPTO_DES=y +# CONFIG_CRYPTO_BLOWFISH is not set +# CONFIG_CRYPTO_TWOFISH is not set +# CONFIG_CRYPTO_SERPENT is not set +# CONFIG_CRYPTO_AES is not set +# CONFIG_CRYPTO_CAST5 is not set +# CONFIG_CRYPTO_CAST6 is not set +# CONFIG_CRYPTO_TEA is not set +# CONFIG_CRYPTO_ARC4 is not set +# CONFIG_CRYPTO_KHAZAD is not set +# CONFIG_CRYPTO_ANUBIS is not set +# CONFIG_CRYPTO_DEFLATE is not set +# CONFIG_CRYPTO_MICHAEL_MIC is not set +# CONFIG_CRYPTO_CRC32C is not set +# CONFIG_CRYPTO_TEST is not set + +# +# Hardware crypto devices +# diff --git a/arch/powerpc/configs/mpc866_ads_defconfig b/arch/powerpc/configs/mpc866_ads_defconfig new file mode 100644 index 0000000..539d9e3 --- /dev/null +++ b/arch/powerpc/configs/mpc866_ads_defconfig @@ -0,0 +1,829 @@ +# +# Automatically generated make config: don't edit +# Linux kernel version: 2.6.19-rc6 +# Fri Nov 24 21:13:55 2006 +# +# CONFIG_PPC64 is not set +CONFIG_PPC32=y +CONFIG_PPC_MERGE=y +CONFIG_MMU=y +CONFIG_GENERIC_HARDIRQS=y +CONFIG_IRQ_PER_CPU=y +CONFIG_RWSEM_XCHGADD_ALGORITHM=y +CONFIG_GENERIC_HWEIGHT=y +CONFIG_GENERIC_CALIBRATE_DELAY=y +CONFIG_GENERIC_FIND_NEXT_BIT=y +CONFIG_PPC=y +CONFIG_EARLY_PRINTK=y +CONFIG_GENERIC_NVRAM=y +CONFIG_SCHED_NO_NO_OMIT_FRAME_POINTER=y +CONFIG_ARCH_MAY_HAVE_PC_FDC=y +CONFIG_PPC_OF=y +# CONFIG_PPC_UDBG_16550 is not set +# CONFIG_GENERIC_TBSYNC is not set +CONFIG_AUDIT_ARCH=y +# CONFIG_DEFAULT_UIMAGE is not set + +# +# Processor support +# +# CONFIG_CLASSIC32 is not set +# CONFIG_PPC_52xx is not set +# CONFIG_PPC_82xx is not set +# CONFIG_PPC_83xx is not set +# CONFIG_PPC_85xx is not set +# CONFIG_PPC_86xx is not set +CONFIG_PPC_8xx=y +# CONFIG_40x is not set +# CONFIG_44x is not set +# CONFIG_E200 is not set +CONFIG_8xx=y +# CONFIG_PPC_DCR_NATIVE is not set +# CONFIG_PPC_DCR_MMIO is not set +CONFIG_NOT_COHERENT_CACHE=y +CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config" + +# +# Code maturity level options +# +CONFIG_EXPERIMENTAL=y +CONFIG_BROKEN_ON_SMP=y +CONFIG_INIT_ENV_ARG_LIMIT=32 + +# +# General setup +# +CONFIG_LOCALVERSION="" +CONFIG_LOCALVERSION_AUTO=y +# CONFIG_SWAP is not set +CONFIG_SYSVIPC=y +# CONFIG_IPC_NS is not set +# CONFIG_POSIX_MQUEUE is not set +# CONFIG_BSD_PROCESS_ACCT is not set +# CONFIG_TASKSTATS is not set +# CONFIG_UTS_NS is not set +# CONFIG_AUDIT is not set +# CONFIG_IKCONFIG is not set +# CONFIG_RELAY is not set +CONFIG_INITRAMFS_SOURCE="" +# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set +CONFIG_SYSCTL=y +CONFIG_EMBEDDED=y +# CONFIG_SYSCTL_SYSCALL is not set +CONFIG_KALLSYMS=y +# CONFIG_KALLSYMS_EXTRA_PASS is not set +# CONFIG_HOTPLUG is not set +CONFIG_PRINTK=y +# CONFIG_BUG is not set +CONFIG_ELF_CORE=y +# CONFIG_BASE_FULL is not set +CONFIG_FUTEX=y +# CONFIG_EPOLL is not set +CONFIG_SHMEM=y +CONFIG_SLAB=y +# CONFIG_VM_EVENT_COUNTERS is not set +CONFIG_RT_MUTEXES=y +# CONFIG_TINY_SHMEM is not set +CONFIG_BASE_SMALL=1 +# CONFIG_SLOB is not set + +# +# Loadable module support +# +# CONFIG_MODULES is not set + +# +# Block layer +# +CONFIG_BLOCK=y +# CONFIG_LBD is not set +# CONFIG_BLK_DEV_IO_TRACE is not set +# CONFIG_LSF is not set + +# +# IO Schedulers +# +CONFIG_IOSCHED_NOOP=y +CONFIG_IOSCHED_AS=y +CONFIG_IOSCHED_DEADLINE=y +CONFIG_IOSCHED_CFQ=y +CONFIG_DEFAULT_AS=y +# CONFIG_DEFAULT_DEADLINE is not set +# CONFIG_DEFAULT_CFQ is not set +# CONFIG_DEFAULT_NOOP is not set +CONFIG_DEFAULT_IOSCHED="anticipatory" +# CONFIG_WANT_EARLY_SERIAL is not set +CONFIG_EMBEDDEDBOOT=y +# CONFIG_MPIC is not set + +# +# Platform support +# +CONFIG_CPM1=y +# CONFIG_MPC8XXFADS is not set +CONFIG_MPC86XADS=y +# CONFIG_MPC885ADS is not set + +# +# MPC8xx CPM Options +# + +# +# Generic MPC8xx Options +# +CONFIG_8xx_COPYBACK=y +CONFIG_8xx_CPU6=y +CONFIG_NO_UCODE_PATCH=y +# CONFIG_USB_SOF_UCODE_PATCH is not set +# CONFIG_I2C_SPI_UCODE_PATCH is not set +# CONFIG_I2C_SPI_SMC1_UCODE_PATCH is not set + +# +# Kernel options +# +# CONFIG_HIGHMEM is not set +# CONFIG_HZ_100 is not set +# CONFIG_HZ_250 is not set +CONFIG_HZ_1000=y +CONFIG_HZ=1000 +CONFIG_PREEMPT_NONE=y +# CONFIG_PREEMPT_VOLUNTARY is not set +# CONFIG_PREEMPT is not set +CONFIG_BINFMT_ELF=y +# CONFIG_BINFMT_MISC is not set +CONFIG_MATH_EMULATION=y +CONFIG_ARCH_ENABLE_MEMORY_HOTPLUG=y +CONFIG_ARCH_FLATMEM_ENABLE=y +CONFIG_ARCH_POPULATES_NODE_MAP=y +CONFIG_SELECT_MEMORY_MODEL=y +CONFIG_FLATMEM_MANUAL=y +# CONFIG_DISCONTIGMEM_MANUAL is not set +# CONFIG_SPARSEMEM_MANUAL is not set +CONFIG_FLATMEM=y +CONFIG_FLAT_NODE_MEM_MAP=y +# CONFIG_SPARSEMEM_STATIC is not set +CONFIG_SPLIT_PTLOCK_CPUS=4 +# CONFIG_RESOURCES_64BIT is not set +# CONFIG_PROC_DEVICETREE is not set +# CONFIG_CMDLINE_BOOL is not set +# CONFIG_PM is not set +# CONFIG_SECCOMP is not set +CONFIG_ISA_DMA_API=y + +# +# Bus options +# +# CONFIG_MPIC_WEIRD is not set +# CONFIG_PPC_I8259 is not set +CONFIG_FSL_SOC=y +# CONFIG_PCI is not set +# CONFIG_PCI_DOMAINS is not set +# CONFIG_PCI_QSPAN is not set + +# +# PCCARD (PCMCIA/CardBus) support +# + +# +# PCI Hotplug Support +# + +# +# Advanced setup +# +# CONFIG_ADVANCED_OPTIONS is not set + +# +# Default settings for advanced configuration options are used +# +CONFIG_HIGHMEM_START=0xfe000000 +CONFIG_LOWMEM_SIZE=0x30000000 +CONFIG_KERNEL_START=0xc0000000 +CONFIG_TASK_SIZE=0x80000000 +CONFIG_CONSISTENT_START=0xff100000 +CONFIG_CONSISTENT_SIZE=0x00200000 +CONFIG_BOOT_LOAD=0x00400000 + +# +# Networking +# +CONFIG_NET=y + +# +# Networking options +# +# CONFIG_NETDEBUG is not set +CONFIG_PACKET=y +# CONFIG_PACKET_MMAP is not set +CONFIG_UNIX=y +CONFIG_XFRM=y +# CONFIG_XFRM_USER is not set +# CONFIG_XFRM_SUB_POLICY is not set +# CONFIG_NET_KEY is not set +CONFIG_INET=y +CONFIG_IP_MULTICAST=y +# CONFIG_IP_ADVANCED_ROUTER is not set +CONFIG_IP_FIB_HASH=y +CONFIG_IP_PNP=y +# CONFIG_IP_PNP_DHCP is not set +# CONFIG_IP_PNP_BOOTP is not set +# CONFIG_IP_PNP_RARP is not set +# CONFIG_NET_IPIP is not set +# CONFIG_NET_IPGRE is not set +# CONFIG_IP_MROUTE is not set +# CONFIG_ARPD is not set +CONFIG_SYN_COOKIES=y +# CONFIG_INET_AH is not set +# CONFIG_INET_ESP is not set +# CONFIG_INET_IPCOMP is not set +# CONFIG_INET_XFRM_TUNNEL is not set +# CONFIG_INET_TUNNEL is not set +CONFIG_INET_XFRM_MODE_TRANSPORT=y +CONFIG_INET_XFRM_MODE_TUNNEL=y +CONFIG_INET_XFRM_MODE_BEET=y +CONFIG_INET_DIAG=y +CONFIG_INET_TCP_DIAG=y +# CONFIG_TCP_CONG_ADVANCED is not set +CONFIG_TCP_CONG_CUBIC=y +CONFIG_DEFAULT_TCP_CONG="cubic" +# CONFIG_IPV6 is not set +# CONFIG_INET6_XFRM_TUNNEL is not set +# CONFIG_INET6_TUNNEL is not set +# CONFIG_NETWORK_SECMARK is not set +# CONFIG_NETFILTER is not set + +# +# DCCP Configuration (EXPERIMENTAL) +# +# CONFIG_IP_DCCP is not set + +# +# SCTP Configuration (EXPERIMENTAL) +# +# CONFIG_IP_SCTP is not set + +# +# TIPC Configuration (EXPERIMENTAL) +# +# CONFIG_TIPC is not set +# CONFIG_ATM is not set +# CONFIG_BRIDGE is not set +# CONFIG_VLAN_8021Q is not set +# CONFIG_DECNET is not set +# CONFIG_LLC2 is not set +# CONFIG_IPX is not set +# CONFIG_ATALK is not set +# CONFIG_X25 is not set +# CONFIG_LAPB is not set +# CONFIG_ECONET is not set +# CONFIG_WAN_ROUTER is not set + +# +# QoS and/or fair queueing +# +# CONFIG_NET_SCHED is not set + +# +# Network testing +# +# CONFIG_NET_PKTGEN is not set +# CONFIG_HAMRADIO is not set +# CONFIG_IRDA is not set +# CONFIG_BT is not set +# CONFIG_IEEE80211 is not set + +# +# Device Drivers +# + +# +# Generic Driver Options +# +CONFIG_STANDALONE=y +CONFIG_PREVENT_FIRMWARE_BUILD=y +# CONFIG_SYS_HYPERVISOR is not set + +# +# Connector - unified userspace <-> kernelspace linker +# +# CONFIG_CONNECTOR is not set + +# +# Memory Technology Devices (MTD) +# +# CONFIG_MTD is not set + +# +# Parallel port support +# +# CONFIG_PARPORT is not set + +# +# Plug and Play support +# + +# +# Block devices +# +# CONFIG_BLK_DEV_FD is not set +# CONFIG_BLK_DEV_COW_COMMON is not set +CONFIG_BLK_DEV_LOOP=y +# CONFIG_BLK_DEV_CRYPTOLOOP is not set +# CONFIG_BLK_DEV_NBD is not set +# CONFIG_BLK_DEV_RAM is not set +# CONFIG_BLK_DEV_INITRD is not set +# CONFIG_CDROM_PKTCDVD is not set +# CONFIG_ATA_OVER_ETH is not set + +# +# Misc devices +# +# CONFIG_TIFM_CORE is not set + +# +# ATA/ATAPI/MFM/RLL support +# +# CONFIG_IDE is not set + +# +# SCSI device support +# +# CONFIG_RAID_ATTRS is not set +# CONFIG_SCSI is not set +# CONFIG_SCSI_NETLINK is not set + +# +# Serial ATA (prod) and Parallel ATA (experimental) drivers +# +# CONFIG_ATA is not set + +# +# Multi-device support (RAID and LVM) +# +# CONFIG_MD is not set + +# +# Fusion MPT device support +# +# CONFIG_FUSION is not set + +# +# IEEE 1394 (FireWire) support +# + +# +# I2O device support +# + +# +# Macintosh device drivers +# +# CONFIG_WINDFARM is not set + +# +# Network device support +# +CONFIG_NETDEVICES=y +# CONFIG_DUMMY is not set +# CONFIG_BONDING is not set +# CONFIG_EQUALIZER is not set +# CONFIG_TUN is not set + +# +# PHY device support +# +CONFIG_PHYLIB=y + +# +# MII PHY device drivers +# +# CONFIG_MARVELL_PHY is not set +# CONFIG_DAVICOM_PHY is not set +# CONFIG_QSEMI_PHY is not set +# CONFIG_LXT_PHY is not set +# CONFIG_CICADA_PHY is not set +# CONFIG_VITESSE_PHY is not set +# CONFIG_SMSC_PHY is not set +CONFIG_FIXED_PHY=y +CONFIG_FIXED_MII_10_FDX=y +CONFIG_FIXED_MII_100_FDX=y + +# +# Ethernet (10 or 100Mbit) +# +CONFIG_NET_ETHERNET=y +CONFIG_MII=y +# CONFIG_FEC_8XX is not set +CONFIG_FS_ENET=y +CONFIG_FS_ENET_HAS_SCC=y +CONFIG_FS_ENET_HAS_FEC=y + +# +# Ethernet (1000 Mbit) +# + +# +# Ethernet (10000 Mbit) +# + +# +# Token Ring devices +# + +# +# Wireless LAN (non-hamradio) +# +# CONFIG_NET_RADIO is not set + +# +# Wan interfaces +# +# CONFIG_WAN is not set +# CONFIG_PPP is not set +# CONFIG_SLIP is not set +# CONFIG_SHAPER is not set +# CONFIG_NETCONSOLE is not set +# CONFIG_NETPOLL is not set +# CONFIG_NET_POLL_CONTROLLER is not set + +# +# ISDN subsystem +# +# CONFIG_ISDN is not set + +# +# Telephony Support +# +# CONFIG_PHONE is not set + +# +# Input device support +# +CONFIG_INPUT=y +# CONFIG_INPUT_FF_MEMLESS is not set + +# +# Userland interfaces +# +CONFIG_INPUT_MOUSEDEV=y +CONFIG_INPUT_MOUSEDEV_PSAUX=y +CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024 +CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768 +# CONFIG_INPUT_JOYDEV is not set +# CONFIG_INPUT_TSDEV is not set +# CONFIG_INPUT_EVDEV is not set +# CONFIG_INPUT_EVBUG is not set + +# +# Input Device Drivers +# +CONFIG_INPUT_KEYBOARD=y +CONFIG_KEYBOARD_ATKBD=y +# CONFIG_KEYBOARD_SUNKBD is not set +# CONFIG_KEYBOARD_LKKBD is not set +# CONFIG_KEYBOARD_XTKBD is not set +# CONFIG_KEYBOARD_NEWTON is not set +# CONFIG_KEYBOARD_STOWAWAY is not set +CONFIG_INPUT_MOUSE=y +CONFIG_MOUSE_PS2=y +# CONFIG_MOUSE_SERIAL is not set +# CONFIG_MOUSE_VSXXXAA is not set +# CONFIG_INPUT_JOYSTICK is not set +# CONFIG_INPUT_TOUCHSCREEN is not set +# CONFIG_INPUT_MISC is not set + +# +# Hardware I/O ports +# +CONFIG_SERIO=y +CONFIG_SERIO_I8042=y +CONFIG_SERIO_SERPORT=y +CONFIG_SERIO_LIBPS2=y +# CONFIG_SERIO_RAW is not set +# CONFIG_GAMEPORT is not set + +# +# Character devices +# +# CONFIG_VT is not set +# CONFIG_SERIAL_NONSTANDARD is not set + +# +# Serial drivers +# +# CONFIG_SERIAL_8250 is not set + +# +# Non-8250 serial port support +# +CONFIG_SERIAL_CORE=y +CONFIG_SERIAL_CORE_CONSOLE=y +CONFIG_SERIAL_CPM=y +CONFIG_SERIAL_CPM_CONSOLE=y +# CONFIG_SERIAL_CPM_SCC1 is not set +# CONFIG_SERIAL_CPM_SCC2 is not set +# CONFIG_SERIAL_CPM_SCC3 is not set +# CONFIG_SERIAL_CPM_SCC4 is not set +CONFIG_SERIAL_CPM_SMC1=y +CONFIG_SERIAL_CPM_SMC2=y +CONFIG_UNIX98_PTYS=y +# CONFIG_LEGACY_PTYS is not set + +# +# IPMI +# +# CONFIG_IPMI_HANDLER is not set + +# +# Watchdog Cards +# +# CONFIG_WATCHDOG is not set +CONFIG_HW_RANDOM=y +# CONFIG_NVRAM is not set +CONFIG_GEN_RTC=y +# CONFIG_GEN_RTC_X is not set +# CONFIG_DTLK is not set +# CONFIG_R3964 is not set + +# +# Ftape, the floppy tape device driver +# +# CONFIG_RAW_DRIVER is not set + +# +# TPM devices +# +# CONFIG_TCG_TPM is not set + +# +# I2C support +# +# CONFIG_I2C is not set + +# +# SPI support +# +# CONFIG_SPI is not set +# CONFIG_SPI_MASTER is not set + +# +# Dallas's 1-wire bus +# +# CONFIG_W1 is not set + +# +# Hardware Monitoring support +# +CONFIG_HWMON=y +# CONFIG_HWMON_VID is not set +# CONFIG_SENSORS_ABITUGURU is not set +# CONFIG_SENSORS_F71805F is not set +# CONFIG_SENSORS_VT1211 is not set +# CONFIG_HWMON_DEBUG_CHIP is not set + +# +# Multimedia devices +# +# CONFIG_VIDEO_DEV is not set + +# +# Digital Video Broadcasting Devices +# +# CONFIG_DVB is not set + +# +# Graphics support +# +CONFIG_FIRMWARE_EDID=y +# CONFIG_FB is not set +# CONFIG_BACKLIGHT_LCD_SUPPORT is not set + +# +# Sound +# +# CONFIG_SOUND is not set + +# +# USB support +# +# CONFIG_USB_ARCH_HAS_HCD is not set +# CONFIG_USB_ARCH_HAS_OHCI is not set +# CONFIG_USB_ARCH_HAS_EHCI is not set + +# +# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support' +# + +# +# USB Gadget Support +# +# CONFIG_USB_GADGET is not set + +# +# MMC/SD Card support +# +# CONFIG_MMC is not set + +# +# LED devices +# +# CONFIG_NEW_LEDS is not set + +# +# LED drivers +# + +# +# LED Triggers +# + +# +# InfiniBand support +# + +# +# EDAC - error detection and reporting (RAS) (EXPERIMENTAL) +# + +# +# Real Time Clock +# +# CONFIG_RTC_CLASS is not set + +# +# DMA Engine support +# +# CONFIG_DMA_ENGINE is not set + +# +# DMA Clients +# + +# +# DMA Devices +# + +# +# File systems +# +CONFIG_EXT2_FS=y +CONFIG_EXT2_FS_XATTR=y +# CONFIG_EXT2_FS_POSIX_ACL is not set +# CONFIG_EXT2_FS_SECURITY is not set +# CONFIG_EXT2_FS_XIP is not set +CONFIG_EXT3_FS=y +CONFIG_EXT3_FS_XATTR=y +# CONFIG_EXT3_FS_POSIX_ACL is not set +# CONFIG_EXT3_FS_SECURITY is not set +# CONFIG_EXT4DEV_FS is not set +CONFIG_JBD=y +# CONFIG_JBD_DEBUG is not set +CONFIG_FS_MBCACHE=y +# CONFIG_REISERFS_FS is not set +# CONFIG_JFS_FS is not set +# CONFIG_FS_POSIX_ACL is not set +# CONFIG_XFS_FS is not set +# CONFIG_GFS2_FS is not set +# CONFIG_OCFS2_FS is not set +# CONFIG_MINIX_FS is not set +# CONFIG_ROMFS_FS is not set +CONFIG_INOTIFY=y +CONFIG_INOTIFY_USER=y +# CONFIG_QUOTA is not set +CONFIG_DNOTIFY=y +# CONFIG_AUTOFS_FS is not set +# CONFIG_AUTOFS4_FS is not set +# CONFIG_FUSE_FS is not set + +# +# CD-ROM/DVD Filesystems +# +# CONFIG_ISO9660_FS is not set +# CONFIG_UDF_FS is not set + +# +# DOS/FAT/NT Filesystems +# +# CONFIG_MSDOS_FS is not set +# CONFIG_VFAT_FS is not set +# CONFIG_NTFS_FS is not set + +# +# Pseudo filesystems +# +CONFIG_PROC_FS=y +# CONFIG_PROC_KCORE is not set +CONFIG_PROC_SYSCTL=y +CONFIG_SYSFS=y +CONFIG_TMPFS=y +# CONFIG_TMPFS_POSIX_ACL is not set +# CONFIG_HUGETLB_PAGE is not set +CONFIG_RAMFS=y +# CONFIG_CONFIGFS_FS is not set + +# +# Miscellaneous filesystems +# +# CONFIG_ADFS_FS is not set +# CONFIG_AFFS_FS is not set +# CONFIG_HFS_FS is not set +# CONFIG_HFSPLUS_FS is not set +# CONFIG_BEFS_FS is not set +# CONFIG_BFS_FS is not set +# CONFIG_EFS_FS is not set +CONFIG_CRAMFS=y +# CONFIG_VXFS_FS is not set +# CONFIG_HPFS_FS is not set +# CONFIG_QNX4FS_FS is not set +# CONFIG_SYSV_FS is not set +# CONFIG_UFS_FS is not set + +# +# Network File Systems +# +CONFIG_NFS_FS=y +CONFIG_NFS_V3=y +# CONFIG_NFS_V3_ACL is not set +# CONFIG_NFS_V4 is not set +# CONFIG_NFS_DIRECTIO is not set +# CONFIG_NFSD is not set +CONFIG_ROOT_NFS=y +CONFIG_LOCKD=y +CONFIG_LOCKD_V4=y +CONFIG_NFS_COMMON=y +CONFIG_SUNRPC=y +# CONFIG_RPCSEC_GSS_KRB5 is not set +# CONFIG_RPCSEC_GSS_SPKM3 is not set +# CONFIG_SMB_FS is not set +# CONFIG_CIFS is not set +# CONFIG_NCP_FS is not set +# CONFIG_CODA_FS is not set +# CONFIG_AFS_FS is not set +# CONFIG_9P_FS is not set + +# +# Partition Types +# +CONFIG_PARTITION_ADVANCED=y +# CONFIG_ACORN_PARTITION is not set +# CONFIG_OSF_PARTITION is not set +# CONFIG_AMIGA_PARTITION is not set +# CONFIG_ATARI_PARTITION is not set +# CONFIG_MAC_PARTITION is not set +CONFIG_MSDOS_PARTITION=y +# CONFIG_BSD_DISKLABEL is not set +# CONFIG_MINIX_SUBPARTITION is not set +# CONFIG_SOLARIS_X86_PARTITION is not set +# CONFIG_UNIXWARE_DISKLABEL is not set +# CONFIG_LDM_PARTITION is not set +# CONFIG_SGI_PARTITION is not set +# CONFIG_ULTRIX_PARTITION is not set +# CONFIG_SUN_PARTITION is not set +# CONFIG_KARMA_PARTITION is not set +# CONFIG_EFI_PARTITION is not set + +# +# Native Language Support +# +# CONFIG_NLS is not set + +# +# Library routines +# +CONFIG_CRC_CCITT=y +# CONFIG_CRC16 is not set +CONFIG_CRC32=y +# CONFIG_LIBCRC32C is not set +CONFIG_ZLIB_INFLATE=y +CONFIG_PLIST=y + +# +# Instrumentation Support +# +# CONFIG_PROFILING is not set + +# +# Kernel hacking +# +# CONFIG_PRINTK_TIME is not set +CONFIG_ENABLE_MUST_CHECK=y +# CONFIG_MAGIC_SYSRQ is not set +# CONFIG_UNUSED_SYMBOLS is not set +# CONFIG_DEBUG_KERNEL is not set +CONFIG_LOG_BUF_SHIFT=14 +# CONFIG_DEBUG_FS is not set +# CONFIG_UNWIND_INFO is not set +# CONFIG_HEADERS_CHECK is not set +# CONFIG_BOOTX_TEXT is not set +# CONFIG_PPC_EARLY_DEBUG is not set + +# +# Security options +# +# CONFIG_KEYS is not set +# CONFIG_SECURITY is not set + +# +# Cryptographic options +# +# CONFIG_CRYPTO is not set diff --git a/arch/powerpc/configs/mpc885_ads_defconfig b/arch/powerpc/configs/mpc885_ads_defconfig new file mode 100644 index 0000000..e2c17d8 --- /dev/null +++ b/arch/powerpc/configs/mpc885_ads_defconfig @@ -0,0 +1,827 @@ +# +# Automatically generated make config: don't edit +# Linux kernel version: 2.6.19-rc4 +# Fri Nov 10 21:30:40 2006 +# +# CONFIG_PPC64 is not set +CONFIG_PPC32=y +CONFIG_PPC_MERGE=y +CONFIG_MMU=y +CONFIG_GENERIC_HARDIRQS=y +CONFIG_IRQ_PER_CPU=y +CONFIG_RWSEM_XCHGADD_ALGORITHM=y +CONFIG_GENERIC_HWEIGHT=y +CONFIG_GENERIC_CALIBRATE_DELAY=y +CONFIG_GENERIC_FIND_NEXT_BIT=y +CONFIG_PPC=y +CONFIG_EARLY_PRINTK=y +CONFIG_GENERIC_NVRAM=y +CONFIG_SCHED_NO_NO_OMIT_FRAME_POINTER=y +CONFIG_ARCH_MAY_HAVE_PC_FDC=y +CONFIG_PPC_OF=y +# CONFIG_PPC_UDBG_16550 is not set +# CONFIG_GENERIC_TBSYNC is not set +CONFIG_AUDIT_ARCH=y +# CONFIG_DEFAULT_UIMAGE is not set + +# +# Processor support +# +# CONFIG_CLASSIC32 is not set +# CONFIG_PPC_52xx is not set +# CONFIG_PPC_82xx is not set +# CONFIG_PPC_83xx is not set +# CONFIG_PPC_85xx is not set +# CONFIG_PPC_86xx is not set +CONFIG_PPC_8xx=y +# CONFIG_40x is not set +# CONFIG_44x is not set +# CONFIG_E200 is not set +CONFIG_8xx=y +CONFIG_NOT_COHERENT_CACHE=y +CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config" + +# +# Code maturity level options +# +CONFIG_EXPERIMENTAL=y +CONFIG_BROKEN_ON_SMP=y +CONFIG_INIT_ENV_ARG_LIMIT=32 + +# +# General setup +# +CONFIG_LOCALVERSION="" +CONFIG_LOCALVERSION_AUTO=y +# CONFIG_SWAP is not set +CONFIG_SYSVIPC=y +# CONFIG_IPC_NS is not set +# CONFIG_POSIX_MQUEUE is not set +# CONFIG_BSD_PROCESS_ACCT is not set +# CONFIG_TASKSTATS is not set +# CONFIG_UTS_NS is not set +# CONFIG_AUDIT is not set +# CONFIG_IKCONFIG is not set +# CONFIG_RELAY is not set +CONFIG_INITRAMFS_SOURCE="" +# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set +CONFIG_SYSCTL=y +CONFIG_EMBEDDED=y +# CONFIG_SYSCTL_SYSCALL is not set +CONFIG_KALLSYMS=y +# CONFIG_KALLSYMS_EXTRA_PASS is not set +# CONFIG_HOTPLUG is not set +CONFIG_PRINTK=y +# CONFIG_BUG is not set +CONFIG_ELF_CORE=y +# CONFIG_BASE_FULL is not set +CONFIG_FUTEX=y +# CONFIG_EPOLL is not set +CONFIG_SHMEM=y +CONFIG_SLAB=y +# CONFIG_VM_EVENT_COUNTERS is not set +CONFIG_RT_MUTEXES=y +# CONFIG_TINY_SHMEM is not set +CONFIG_BASE_SMALL=1 +# CONFIG_SLOB is not set + +# +# Loadable module support +# +# CONFIG_MODULES is not set + +# +# Block layer +# +CONFIG_BLOCK=y +# CONFIG_LBD is not set +# CONFIG_BLK_DEV_IO_TRACE is not set +# CONFIG_LSF is not set + +# +# IO Schedulers +# +CONFIG_IOSCHED_NOOP=y +CONFIG_IOSCHED_AS=y +CONFIG_IOSCHED_DEADLINE=y +CONFIG_IOSCHED_CFQ=y +CONFIG_DEFAULT_AS=y +# CONFIG_DEFAULT_DEADLINE is not set +# CONFIG_DEFAULT_CFQ is not set +# CONFIG_DEFAULT_NOOP is not set +CONFIG_DEFAULT_IOSCHED="anticipatory" +# CONFIG_WANT_EARLY_SERIAL is not set +CONFIG_EMBEDDEDBOOT=y +# CONFIG_MPIC is not set + +# +# Platform support +# +CONFIG_CPM1=y +# CONFIG_MPC8XXFADS is not set +# CONFIG_MPC86XADS is not set +CONFIG_MPC885ADS=y + +# +# MPC8xx CPM Options +# + +# +# Generic MPC8xx Options +# +CONFIG_8xx_COPYBACK=y +# CONFIG_8xx_CPU6 is not set +CONFIG_NO_UCODE_PATCH=y +# CONFIG_USB_SOF_UCODE_PATCH is not set +# CONFIG_I2C_SPI_UCODE_PATCH is not set +# CONFIG_I2C_SPI_SMC1_UCODE_PATCH is not set + +# +# Kernel options +# +# CONFIG_HIGHMEM is not set +# CONFIG_HZ_100 is not set +# CONFIG_HZ_250 is not set +CONFIG_HZ_1000=y +CONFIG_HZ=1000 +CONFIG_PREEMPT_NONE=y +# CONFIG_PREEMPT_VOLUNTARY is not set +# CONFIG_PREEMPT is not set +CONFIG_BINFMT_ELF=y +# CONFIG_BINFMT_MISC is not set +CONFIG_MATH_EMULATION=y +CONFIG_ARCH_ENABLE_MEMORY_HOTPLUG=y +CONFIG_ARCH_FLATMEM_ENABLE=y +CONFIG_ARCH_POPULATES_NODE_MAP=y +CONFIG_SELECT_MEMORY_MODEL=y +CONFIG_FLATMEM_MANUAL=y +# CONFIG_DISCONTIGMEM_MANUAL is not set +# CONFIG_SPARSEMEM_MANUAL is not set +CONFIG_FLATMEM=y +CONFIG_FLAT_NODE_MEM_MAP=y +# CONFIG_SPARSEMEM_STATIC is not set +CONFIG_SPLIT_PTLOCK_CPUS=4 +# CONFIG_RESOURCES_64BIT is not set +# CONFIG_PROC_DEVICETREE is not set +# CONFIG_CMDLINE_BOOL is not set +# CONFIG_PM is not set +# CONFIG_SECCOMP is not set +CONFIG_ISA_DMA_API=y + +# +# Bus options +# +# CONFIG_MPIC_WEIRD is not set +# CONFIG_PPC_I8259 is not set +CONFIG_FSL_SOC=y +# CONFIG_PCI is not set +# CONFIG_PCI_DOMAINS is not set +# CONFIG_PCI_QSPAN is not set + +# +# PCCARD (PCMCIA/CardBus) support +# + +# +# PCI Hotplug Support +# + +# +# Advanced setup +# +# CONFIG_ADVANCED_OPTIONS is not set + +# +# Default settings for advanced configuration options are used +# +CONFIG_HIGHMEM_START=0xfe000000 +CONFIG_LOWMEM_SIZE=0x30000000 +CONFIG_KERNEL_START=0xc0000000 +CONFIG_TASK_SIZE=0x80000000 +CONFIG_CONSISTENT_START=0xff100000 +CONFIG_CONSISTENT_SIZE=0x00200000 +CONFIG_BOOT_LOAD=0x00400000 + +# +# Networking +# +CONFIG_NET=y + +# +# Networking options +# +# CONFIG_NETDEBUG is not set +CONFIG_PACKET=y +# CONFIG_PACKET_MMAP is not set +CONFIG_UNIX=y +CONFIG_XFRM=y +# CONFIG_XFRM_USER is not set +# CONFIG_XFRM_SUB_POLICY is not set +# CONFIG_NET_KEY is not set +CONFIG_INET=y +CONFIG_IP_MULTICAST=y +# CONFIG_IP_ADVANCED_ROUTER is not set +CONFIG_IP_FIB_HASH=y +CONFIG_IP_PNP=y +# CONFIG_IP_PNP_DHCP is not set +# CONFIG_IP_PNP_BOOTP is not set +# CONFIG_IP_PNP_RARP is not set +# CONFIG_NET_IPIP is not set +# CONFIG_NET_IPGRE is not set +# CONFIG_IP_MROUTE is not set +# CONFIG_ARPD is not set +CONFIG_SYN_COOKIES=y +# CONFIG_INET_AH is not set +# CONFIG_INET_ESP is not set +# CONFIG_INET_IPCOMP is not set +# CONFIG_INET_XFRM_TUNNEL is not set +# CONFIG_INET_TUNNEL is not set +CONFIG_INET_XFRM_MODE_TRANSPORT=y +CONFIG_INET_XFRM_MODE_TUNNEL=y +CONFIG_INET_XFRM_MODE_BEET=y +CONFIG_INET_DIAG=y +CONFIG_INET_TCP_DIAG=y +# CONFIG_TCP_CONG_ADVANCED is not set +CONFIG_TCP_CONG_CUBIC=y +CONFIG_DEFAULT_TCP_CONG="cubic" +# CONFIG_IPV6 is not set +# CONFIG_INET6_XFRM_TUNNEL is not set +# CONFIG_INET6_TUNNEL is not set +# CONFIG_NETWORK_SECMARK is not set +# CONFIG_NETFILTER is not set + +# +# DCCP Configuration (EXPERIMENTAL) +# +# CONFIG_IP_DCCP is not set + +# +# SCTP Configuration (EXPERIMENTAL) +# +# CONFIG_IP_SCTP is not set + +# +# TIPC Configuration (EXPERIMENTAL) +# +# CONFIG_TIPC is not set +# CONFIG_ATM is not set +# CONFIG_BRIDGE is not set +# CONFIG_VLAN_8021Q is not set +# CONFIG_DECNET is not set +# CONFIG_LLC2 is not set +# CONFIG_IPX is not set +# CONFIG_ATALK is not set +# CONFIG_X25 is not set +# CONFIG_LAPB is not set +# CONFIG_ECONET is not set +# CONFIG_WAN_ROUTER is not set + +# +# QoS and/or fair queueing +# +# CONFIG_NET_SCHED is not set + +# +# Network testing +# +# CONFIG_NET_PKTGEN is not set +# CONFIG_HAMRADIO is not set +# CONFIG_IRDA is not set +# CONFIG_BT is not set +# CONFIG_IEEE80211 is not set + +# +# Device Drivers +# + +# +# Generic Driver Options +# +CONFIG_STANDALONE=y +CONFIG_PREVENT_FIRMWARE_BUILD=y +# CONFIG_SYS_HYPERVISOR is not set + +# +# Connector - unified userspace <-> kernelspace linker +# +# CONFIG_CONNECTOR is not set + +# +# Memory Technology Devices (MTD) +# +# CONFIG_MTD is not set + +# +# Parallel port support +# +# CONFIG_PARPORT is not set + +# +# Plug and Play support +# + +# +# Block devices +# +# CONFIG_BLK_DEV_FD is not set +# CONFIG_BLK_DEV_COW_COMMON is not set +CONFIG_BLK_DEV_LOOP=y +# CONFIG_BLK_DEV_CRYPTOLOOP is not set +# CONFIG_BLK_DEV_NBD is not set +# CONFIG_BLK_DEV_RAM is not set +# CONFIG_BLK_DEV_INITRD is not set +# CONFIG_CDROM_PKTCDVD is not set +# CONFIG_ATA_OVER_ETH is not set + +# +# Misc devices +# +# CONFIG_TIFM_CORE is not set + +# +# ATA/ATAPI/MFM/RLL support +# +# CONFIG_IDE is not set + +# +# SCSI device support +# +# CONFIG_RAID_ATTRS is not set +# CONFIG_SCSI is not set +# CONFIG_SCSI_NETLINK is not set + +# +# Serial ATA (prod) and Parallel ATA (experimental) drivers +# +# CONFIG_ATA is not set + +# +# Multi-device support (RAID and LVM) +# +# CONFIG_MD is not set + +# +# Fusion MPT device support +# +# CONFIG_FUSION is not set + +# +# IEEE 1394 (FireWire) support +# + +# +# I2O device support +# + +# +# Macintosh device drivers +# +# CONFIG_WINDFARM is not set + +# +# Network device support +# +CONFIG_NETDEVICES=y +# CONFIG_DUMMY is not set +# CONFIG_BONDING is not set +# CONFIG_EQUALIZER is not set +# CONFIG_TUN is not set + +# +# PHY device support +# +CONFIG_PHYLIB=y + +# +# MII PHY device drivers +# +# CONFIG_MARVELL_PHY is not set +CONFIG_DAVICOM_PHY=y +# CONFIG_QSEMI_PHY is not set +# CONFIG_LXT_PHY is not set +# CONFIG_CICADA_PHY is not set +# CONFIG_VITESSE_PHY is not set +# CONFIG_SMSC_PHY is not set +CONFIG_FIXED_PHY=y +CONFIG_FIXED_MII_10_FDX=y +# CONFIG_FIXED_MII_100_FDX is not set + +# +# Ethernet (10 or 100Mbit) +# +CONFIG_NET_ETHERNET=y +CONFIG_MII=y +# CONFIG_FEC_8XX is not set +CONFIG_FS_ENET=y +CONFIG_FS_ENET_HAS_SCC=y +CONFIG_FS_ENET_HAS_FEC=y + +# +# Ethernet (1000 Mbit) +# + +# +# Ethernet (10000 Mbit) +# + +# +# Token Ring devices +# + +# +# Wireless LAN (non-hamradio) +# +# CONFIG_NET_RADIO is not set + +# +# Wan interfaces +# +# CONFIG_WAN is not set +# CONFIG_PPP is not set +# CONFIG_SLIP is not set +# CONFIG_SHAPER is not set +# CONFIG_NETCONSOLE is not set +# CONFIG_NETPOLL is not set +# CONFIG_NET_POLL_CONTROLLER is not set + +# +# ISDN subsystem +# +# CONFIG_ISDN is not set + +# +# Telephony Support +# +# CONFIG_PHONE is not set + +# +# Input device support +# +CONFIG_INPUT=y +# CONFIG_INPUT_FF_MEMLESS is not set + +# +# Userland interfaces +# +CONFIG_INPUT_MOUSEDEV=y +CONFIG_INPUT_MOUSEDEV_PSAUX=y +CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024 +CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768 +# CONFIG_INPUT_JOYDEV is not set +# CONFIG_INPUT_TSDEV is not set +# CONFIG_INPUT_EVDEV is not set +# CONFIG_INPUT_EVBUG is not set + +# +# Input Device Drivers +# +CONFIG_INPUT_KEYBOARD=y +CONFIG_KEYBOARD_ATKBD=y +# CONFIG_KEYBOARD_SUNKBD is not set +# CONFIG_KEYBOARD_LKKBD is not set +# CONFIG_KEYBOARD_XTKBD is not set +# CONFIG_KEYBOARD_NEWTON is not set +# CONFIG_KEYBOARD_STOWAWAY is not set +CONFIG_INPUT_MOUSE=y +CONFIG_MOUSE_PS2=y +# CONFIG_MOUSE_SERIAL is not set +# CONFIG_MOUSE_VSXXXAA is not set +# CONFIG_INPUT_JOYSTICK is not set +# CONFIG_INPUT_TOUCHSCREEN is not set +# CONFIG_INPUT_MISC is not set + +# +# Hardware I/O ports +# +CONFIG_SERIO=y +CONFIG_SERIO_I8042=y +CONFIG_SERIO_SERPORT=y +CONFIG_SERIO_LIBPS2=y +# CONFIG_SERIO_RAW is not set +# CONFIG_GAMEPORT is not set + +# +# Character devices +# +# CONFIG_VT is not set +# CONFIG_SERIAL_NONSTANDARD is not set + +# +# Serial drivers +# +# CONFIG_SERIAL_8250 is not set + +# +# Non-8250 serial port support +# +CONFIG_SERIAL_CORE=y +CONFIG_SERIAL_CORE_CONSOLE=y +CONFIG_SERIAL_CPM=y +CONFIG_SERIAL_CPM_CONSOLE=y +# CONFIG_SERIAL_CPM_SCC1 is not set +# CONFIG_SERIAL_CPM_SCC2 is not set +# CONFIG_SERIAL_CPM_SCC3 is not set +# CONFIG_SERIAL_CPM_SCC4 is not set +CONFIG_SERIAL_CPM_SMC1=y +CONFIG_SERIAL_CPM_SMC2=y +CONFIG_UNIX98_PTYS=y +# CONFIG_LEGACY_PTYS is not set + +# +# IPMI +# +# CONFIG_IPMI_HANDLER is not set + +# +# Watchdog Cards +# +# CONFIG_WATCHDOG is not set +CONFIG_HW_RANDOM=y +# CONFIG_NVRAM is not set +CONFIG_GEN_RTC=y +# CONFIG_GEN_RTC_X is not set +# CONFIG_DTLK is not set +# CONFIG_R3964 is not set + +# +# Ftape, the floppy tape device driver +# +# CONFIG_RAW_DRIVER is not set + +# +# TPM devices +# +# CONFIG_TCG_TPM is not set + +# +# I2C support +# +# CONFIG_I2C is not set + +# +# SPI support +# +# CONFIG_SPI is not set +# CONFIG_SPI_MASTER is not set + +# +# Dallas's 1-wire bus +# +# CONFIG_W1 is not set + +# +# Hardware Monitoring support +# +CONFIG_HWMON=y +# CONFIG_HWMON_VID is not set +# CONFIG_SENSORS_ABITUGURU is not set +# CONFIG_SENSORS_F71805F is not set +# CONFIG_SENSORS_VT1211 is not set +# CONFIG_HWMON_DEBUG_CHIP is not set + +# +# Multimedia devices +# +# CONFIG_VIDEO_DEV is not set + +# +# Digital Video Broadcasting Devices +# +# CONFIG_DVB is not set + +# +# Graphics support +# +CONFIG_FIRMWARE_EDID=y +# CONFIG_FB is not set +# CONFIG_BACKLIGHT_LCD_SUPPORT is not set + +# +# Sound +# +# CONFIG_SOUND is not set + +# +# USB support +# +# CONFIG_USB_ARCH_HAS_HCD is not set +# CONFIG_USB_ARCH_HAS_OHCI is not set +# CONFIG_USB_ARCH_HAS_EHCI is not set + +# +# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support' +# + +# +# USB Gadget Support +# +# CONFIG_USB_GADGET is not set + +# +# MMC/SD Card support +# +# CONFIG_MMC is not set + +# +# LED devices +# +# CONFIG_NEW_LEDS is not set + +# +# LED drivers +# + +# +# LED Triggers +# + +# +# InfiniBand support +# + +# +# EDAC - error detection and reporting (RAS) (EXPERIMENTAL) +# + +# +# Real Time Clock +# +# CONFIG_RTC_CLASS is not set + +# +# DMA Engine support +# +# CONFIG_DMA_ENGINE is not set + +# +# DMA Clients +# + +# +# DMA Devices +# + +# +# File systems +# +CONFIG_EXT2_FS=y +CONFIG_EXT2_FS_XATTR=y +# CONFIG_EXT2_FS_POSIX_ACL is not set +# CONFIG_EXT2_FS_SECURITY is not set +# CONFIG_EXT2_FS_XIP is not set +CONFIG_EXT3_FS=y +CONFIG_EXT3_FS_XATTR=y +# CONFIG_EXT3_FS_POSIX_ACL is not set +# CONFIG_EXT3_FS_SECURITY is not set +# CONFIG_EXT4DEV_FS is not set +CONFIG_JBD=y +# CONFIG_JBD_DEBUG is not set +CONFIG_FS_MBCACHE=y +# CONFIG_REISERFS_FS is not set +# CONFIG_JFS_FS is not set +# CONFIG_FS_POSIX_ACL is not set +# CONFIG_XFS_FS is not set +# CONFIG_GFS2_FS is not set +# CONFIG_OCFS2_FS is not set +# CONFIG_MINIX_FS is not set +# CONFIG_ROMFS_FS is not set +CONFIG_INOTIFY=y +CONFIG_INOTIFY_USER=y +# CONFIG_QUOTA is not set +CONFIG_DNOTIFY=y +# CONFIG_AUTOFS_FS is not set +# CONFIG_AUTOFS4_FS is not set +# CONFIG_FUSE_FS is not set + +# +# CD-ROM/DVD Filesystems +# +# CONFIG_ISO9660_FS is not set +# CONFIG_UDF_FS is not set + +# +# DOS/FAT/NT Filesystems +# +# CONFIG_MSDOS_FS is not set +# CONFIG_VFAT_FS is not set +# CONFIG_NTFS_FS is not set + +# +# Pseudo filesystems +# +CONFIG_PROC_FS=y +# CONFIG_PROC_KCORE is not set +CONFIG_PROC_SYSCTL=y +CONFIG_SYSFS=y +CONFIG_TMPFS=y +# CONFIG_TMPFS_POSIX_ACL is not set +# CONFIG_HUGETLB_PAGE is not set +CONFIG_RAMFS=y +# CONFIG_CONFIGFS_FS is not set + +# +# Miscellaneous filesystems +# +# CONFIG_ADFS_FS is not set +# CONFIG_AFFS_FS is not set +# CONFIG_HFS_FS is not set +# CONFIG_HFSPLUS_FS is not set +# CONFIG_BEFS_FS is not set +# CONFIG_BFS_FS is not set +# CONFIG_EFS_FS is not set +CONFIG_CRAMFS=y +# CONFIG_VXFS_FS is not set +# CONFIG_HPFS_FS is not set +# CONFIG_QNX4FS_FS is not set +# CONFIG_SYSV_FS is not set +# CONFIG_UFS_FS is not set + +# +# Network File Systems +# +CONFIG_NFS_FS=y +CONFIG_NFS_V3=y +# CONFIG_NFS_V3_ACL is not set +# CONFIG_NFS_V4 is not set +# CONFIG_NFS_DIRECTIO is not set +# CONFIG_NFSD is not set +CONFIG_ROOT_NFS=y +CONFIG_LOCKD=y +CONFIG_LOCKD_V4=y +CONFIG_NFS_COMMON=y +CONFIG_SUNRPC=y +# CONFIG_RPCSEC_GSS_KRB5 is not set +# CONFIG_RPCSEC_GSS_SPKM3 is not set +# CONFIG_SMB_FS is not set +# CONFIG_CIFS is not set +# CONFIG_NCP_FS is not set +# CONFIG_CODA_FS is not set +# CONFIG_AFS_FS is not set +# CONFIG_9P_FS is not set + +# +# Partition Types +# +CONFIG_PARTITION_ADVANCED=y +# CONFIG_ACORN_PARTITION is not set +# CONFIG_OSF_PARTITION is not set +# CONFIG_AMIGA_PARTITION is not set +# CONFIG_ATARI_PARTITION is not set +# CONFIG_MAC_PARTITION is not set +CONFIG_MSDOS_PARTITION=y +# CONFIG_BSD_DISKLABEL is not set +# CONFIG_MINIX_SUBPARTITION is not set +# CONFIG_SOLARIS_X86_PARTITION is not set +# CONFIG_UNIXWARE_DISKLABEL is not set +# CONFIG_LDM_PARTITION is not set +# CONFIG_SGI_PARTITION is not set +# CONFIG_ULTRIX_PARTITION is not set +# CONFIG_SUN_PARTITION is not set +# CONFIG_KARMA_PARTITION is not set +# CONFIG_EFI_PARTITION is not set + +# +# Native Language Support +# +# CONFIG_NLS is not set + +# +# Library routines +# +CONFIG_CRC_CCITT=y +# CONFIG_CRC16 is not set +CONFIG_CRC32=y +# CONFIG_LIBCRC32C is not set +CONFIG_ZLIB_INFLATE=y +CONFIG_PLIST=y + +# +# Instrumentation Support +# +# CONFIG_PROFILING is not set + +# +# Kernel hacking +# +# CONFIG_PRINTK_TIME is not set +CONFIG_ENABLE_MUST_CHECK=y +# CONFIG_MAGIC_SYSRQ is not set +# CONFIG_UNUSED_SYMBOLS is not set +# CONFIG_DEBUG_KERNEL is not set +CONFIG_LOG_BUF_SHIFT=14 +# CONFIG_DEBUG_FS is not set +# CONFIG_UNWIND_INFO is not set +# CONFIG_HEADERS_CHECK is not set +# CONFIG_BOOTX_TEXT is not set +# CONFIG_PPC_EARLY_DEBUG is not set + +# +# Security options +# +# CONFIG_KEYS is not set +# CONFIG_SECURITY is not set + +# +# Cryptographic options +# +# CONFIG_CRYPTO is not set diff --git a/arch/powerpc/configs/pasemi_defconfig b/arch/powerpc/configs/pasemi_defconfig new file mode 100644 index 0000000..97a57e9 --- /dev/null +++ b/arch/powerpc/configs/pasemi_defconfig @@ -0,0 +1,1722 @@ +# +# Automatically generated make config: don't edit +# Linux kernel version: 2.6.20-rc6 +# Thu Feb 1 22:54:15 2007 +# +CONFIG_PPC64=y +CONFIG_64BIT=y +CONFIG_PPC_MERGE=y +CONFIG_MMU=y +CONFIG_GENERIC_HARDIRQS=y +CONFIG_IRQ_PER_CPU=y +CONFIG_RWSEM_XCHGADD_ALGORITHM=y +CONFIG_ARCH_HAS_ILOG2_U32=y +CONFIG_ARCH_HAS_ILOG2_U64=y +CONFIG_GENERIC_HWEIGHT=y +CONFIG_GENERIC_CALIBRATE_DELAY=y +CONFIG_GENERIC_FIND_NEXT_BIT=y +CONFIG_PPC=y +CONFIG_EARLY_PRINTK=y +CONFIG_COMPAT=y +CONFIG_SYSVIPC_COMPAT=y +CONFIG_SCHED_NO_NO_OMIT_FRAME_POINTER=y +CONFIG_ARCH_MAY_HAVE_PC_FDC=y +CONFIG_PPC_OF=y +CONFIG_PPC_UDBG_16550=y +CONFIG_GENERIC_TBSYNC=y +CONFIG_AUDIT_ARCH=y +CONFIG_GENERIC_BUG=y +# CONFIG_DEFAULT_UIMAGE is not set + +# +# Processor support +# +CONFIG_POWER4_ONLY=y +CONFIG_POWER4=y +CONFIG_PPC_FPU=y +# CONFIG_PPC_DCR_NATIVE is not set +# CONFIG_PPC_DCR_MMIO is not set +# CONFIG_PPC_OF_PLATFORM_PCI is not set +CONFIG_ALTIVEC=y +CONFIG_PPC_STD_MMU=y +# CONFIG_VIRT_CPU_ACCOUNTING is not set +CONFIG_SMP=y +CONFIG_NR_CPUS=2 +CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config" + +# +# Code maturity level options +# +CONFIG_EXPERIMENTAL=y +CONFIG_LOCK_KERNEL=y +CONFIG_INIT_ENV_ARG_LIMIT=32 + +# +# General setup +# +CONFIG_LOCALVERSION="" +CONFIG_LOCALVERSION_AUTO=y +CONFIG_SWAP=y +CONFIG_SYSVIPC=y +# CONFIG_IPC_NS is not set +# CONFIG_POSIX_MQUEUE is not set +# CONFIG_BSD_PROCESS_ACCT is not set +# CONFIG_TASKSTATS is not set +# CONFIG_UTS_NS is not set +# CONFIG_AUDIT is not set +# CONFIG_IKCONFIG is not set +# CONFIG_CPUSETS is not set +CONFIG_SYSFS_DEPRECATED=y +# CONFIG_RELAY is not set +CONFIG_INITRAMFS_SOURCE="" +# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set +CONFIG_SYSCTL=y +# CONFIG_EMBEDDED is not set +CONFIG_SYSCTL_SYSCALL=y +CONFIG_KALLSYMS=y +# CONFIG_KALLSYMS_ALL is not set +# CONFIG_KALLSYMS_EXTRA_PASS is not set +CONFIG_HOTPLUG=y +CONFIG_PRINTK=y +CONFIG_BUG=y +CONFIG_ELF_CORE=y +CONFIG_BASE_FULL=y +CONFIG_FUTEX=y +CONFIG_EPOLL=y +CONFIG_SHMEM=y +CONFIG_SLAB=y +CONFIG_VM_EVENT_COUNTERS=y +CONFIG_RT_MUTEXES=y +# CONFIG_TINY_SHMEM is not set +CONFIG_BASE_SMALL=0 +# CONFIG_SLOB is not set + +# +# Loadable module support +# +CONFIG_MODULES=y +CONFIG_MODULE_UNLOAD=y +# CONFIG_MODULE_FORCE_UNLOAD is not set +# CONFIG_MODVERSIONS is not set +# CONFIG_MODULE_SRCVERSION_ALL is not set +# CONFIG_KMOD is not set +CONFIG_STOP_MACHINE=y + +# +# Block layer +# +CONFIG_BLOCK=y +# CONFIG_BLK_DEV_IO_TRACE is not set + +# +# IO Schedulers +# +CONFIG_IOSCHED_NOOP=y +CONFIG_IOSCHED_AS=y +# CONFIG_IOSCHED_DEADLINE is not set +# CONFIG_IOSCHED_CFQ is not set +CONFIG_DEFAULT_AS=y +# CONFIG_DEFAULT_DEADLINE is not set +# CONFIG_DEFAULT_CFQ is not set +# CONFIG_DEFAULT_NOOP is not set +CONFIG_DEFAULT_IOSCHED="anticipatory" + +# +# Platform support +# +CONFIG_PPC_MULTIPLATFORM=y +# CONFIG_EMBEDDED6xx is not set +# CONFIG_APUS is not set +CONFIG_PPC_PSERIES=y +# CONFIG_PPC_ISERIES is not set +# CONFIG_PPC_MPC52xx is not set +# CONFIG_PPC_PMAC is not set +# CONFIG_PPC_MAPLE is not set +CONFIG_PPC_PASEMI=y +# CONFIG_PPC_CELL is not set +# CONFIG_PPC_CELL_NATIVE is not set +# CONFIG_PPC_IBM_CELL_BLADE is not set +# CONFIG_PPC_PS3 is not set +CONFIG_PPC_NATIVE=y +# CONFIG_UDBG_RTAS_CONSOLE is not set +CONFIG_XICS=y +# CONFIG_U3_DART is not set +CONFIG_PPC_RTAS=y +CONFIG_RTAS_ERROR_LOGGING=y +CONFIG_RTAS_PROC=y +# CONFIG_RTAS_FLASH is not set +# CONFIG_MMIO_NVRAM is not set +CONFIG_IBMVIO=y +# CONFIG_IBMEBUS is not set +# CONFIG_PPC_MPC106 is not set +# CONFIG_PPC_970_NAP is not set +# CONFIG_PPC_INDIRECT_IO is not set +# CONFIG_GENERIC_IOMAP is not set +# CONFIG_CPU_FREQ is not set +# CONFIG_WANT_EARLY_SERIAL is not set +CONFIG_MPIC=y + +# +# PA Semi PWRficient options +# +CONFIG_PPC_PASEMI_IOMMU=y + +# +# Kernel options +# +CONFIG_HZ_100=y +# CONFIG_HZ_250 is not set +# CONFIG_HZ_300 is not set +# CONFIG_HZ_1000 is not set +CONFIG_HZ=100 +CONFIG_PREEMPT_NONE=y +# CONFIG_PREEMPT_VOLUNTARY is not set +# CONFIG_PREEMPT is not set +CONFIG_PREEMPT_BKL=y +CONFIG_BINFMT_ELF=y +# CONFIG_BINFMT_MISC is not set +CONFIG_FORCE_MAX_ZONEORDER=13 +CONFIG_IOMMU_VMERGE=y +# CONFIG_HOTPLUG_CPU is not set +CONFIG_ARCH_ENABLE_MEMORY_HOTPLUG=y +# CONFIG_KEXEC is not set +# CONFIG_CRASH_DUMP is not set +# CONFIG_IRQ_ALL_CPUS is not set +# CONFIG_PPC_SPLPAR is not set +CONFIG_EEH=y +# CONFIG_SCANLOG is not set +# CONFIG_LPARCFG is not set +# CONFIG_NUMA is not set +CONFIG_ARCH_SELECT_MEMORY_MODEL=y +CONFIG_ARCH_FLATMEM_ENABLE=y +CONFIG_ARCH_SPARSEMEM_ENABLE=y +CONFIG_ARCH_SPARSEMEM_DEFAULT=y +CONFIG_ARCH_POPULATES_NODE_MAP=y +CONFIG_SELECT_MEMORY_MODEL=y +CONFIG_FLATMEM_MANUAL=y +# CONFIG_DISCONTIGMEM_MANUAL is not set +# CONFIG_SPARSEMEM_MANUAL is not set +CONFIG_FLATMEM=y +CONFIG_FLAT_NODE_MEM_MAP=y +# CONFIG_SPARSEMEM_STATIC is not set +CONFIG_SPLIT_PTLOCK_CPUS=4 +CONFIG_RESOURCES_64BIT=y +# CONFIG_PPC_64K_PAGES is not set +# CONFIG_SCHED_SMT is not set +CONFIG_PROC_DEVICETREE=y +# CONFIG_CMDLINE_BOOL is not set +# CONFIG_PM is not set +# CONFIG_SECCOMP is not set +CONFIG_ISA_DMA_API=y + +# +# Bus options +# +CONFIG_GENERIC_ISA_DMA=y +# CONFIG_MPIC_WEIRD is not set +CONFIG_PPC_I8259=y +# CONFIG_PPC_INDIRECT_PCI is not set +CONFIG_PCI=y +CONFIG_PCI_DOMAINS=y +# CONFIG_PCIEPORTBUS is not set +# CONFIG_PCI_DEBUG is not set + +# +# PCCARD (PCMCIA/CardBus) support +# +CONFIG_PCCARD=y +CONFIG_PCMCIA_DEBUG=y +CONFIG_PCMCIA=y +CONFIG_PCMCIA_LOAD_CIS=y +CONFIG_PCMCIA_IOCTL=y +CONFIG_CARDBUS=y + +# +# PC-card bridges +# +# CONFIG_YENTA is not set +# CONFIG_PD6729 is not set +# CONFIG_I82092 is not set + +# +# PCI Hotplug Support +# +# CONFIG_HOTPLUG_PCI is not set +CONFIG_KERNEL_START=0xc000000000000000 + +# +# Networking +# +CONFIG_NET=y + +# +# Networking options +# +# CONFIG_NETDEBUG is not set +CONFIG_PACKET=y +# CONFIG_PACKET_MMAP is not set +CONFIG_UNIX=y +CONFIG_XFRM=y +# CONFIG_XFRM_USER is not set +# CONFIG_XFRM_SUB_POLICY is not set +CONFIG_NET_KEY=y +CONFIG_INET=y +CONFIG_IP_MULTICAST=y +# CONFIG_IP_ADVANCED_ROUTER is not set +CONFIG_IP_FIB_HASH=y +CONFIG_IP_PNP=y +CONFIG_IP_PNP_DHCP=y +CONFIG_IP_PNP_BOOTP=y +CONFIG_IP_PNP_RARP=y +CONFIG_NET_IPIP=y +# CONFIG_NET_IPGRE is not set +# CONFIG_IP_MROUTE is not set +# CONFIG_ARPD is not set +CONFIG_SYN_COOKIES=y +CONFIG_INET_AH=y +CONFIG_INET_ESP=y +# CONFIG_INET_IPCOMP is not set +# CONFIG_INET_XFRM_TUNNEL is not set +CONFIG_INET_TUNNEL=y +CONFIG_INET_XFRM_MODE_TRANSPORT=y +CONFIG_INET_XFRM_MODE_TUNNEL=y +CONFIG_INET_XFRM_MODE_BEET=y +CONFIG_INET_DIAG=y +CONFIG_INET_TCP_DIAG=y +# CONFIG_TCP_CONG_ADVANCED is not set +CONFIG_TCP_CONG_CUBIC=y +CONFIG_DEFAULT_TCP_CONG="cubic" +# CONFIG_TCP_MD5SIG is not set +# CONFIG_IPV6 is not set +# CONFIG_INET6_XFRM_TUNNEL is not set +# CONFIG_INET6_TUNNEL is not set +# CONFIG_NETWORK_SECMARK is not set +# CONFIG_NETFILTER is not set + +# +# DCCP Configuration (EXPERIMENTAL) +# +# CONFIG_IP_DCCP is not set + +# +# SCTP Configuration (EXPERIMENTAL) +# +# CONFIG_IP_SCTP is not set + +# +# TIPC Configuration (EXPERIMENTAL) +# +# CONFIG_TIPC is not set +# CONFIG_ATM is not set +# CONFIG_BRIDGE is not set +# CONFIG_VLAN_8021Q is not set +# CONFIG_DECNET is not set +# CONFIG_LLC2 is not set +# CONFIG_IPX is not set +# CONFIG_ATALK is not set +# CONFIG_X25 is not set +# CONFIG_LAPB is not set +# CONFIG_ECONET is not set +# CONFIG_WAN_ROUTER is not set + +# +# QoS and/or fair queueing +# +# CONFIG_NET_SCHED is not set + +# +# Network testing +# +# CONFIG_NET_PKTGEN is not set +# CONFIG_HAMRADIO is not set +# CONFIG_IRDA is not set +# CONFIG_BT is not set +# CONFIG_IEEE80211 is not set + +# +# Device Drivers +# + +# +# Generic Driver Options +# +CONFIG_STANDALONE=y +CONFIG_PREVENT_FIRMWARE_BUILD=y +CONFIG_FW_LOADER=y +# CONFIG_DEBUG_DRIVER is not set +# CONFIG_SYS_HYPERVISOR is not set + +# +# Connector - unified userspace <-> kernelspace linker +# +# CONFIG_CONNECTOR is not set + +# +# Memory Technology Devices (MTD) +# +CONFIG_MTD=y +# CONFIG_MTD_DEBUG is not set +CONFIG_MTD_CONCAT=y +# CONFIG_MTD_PARTITIONS is not set + +# +# User Modules And Translation Layers +# +CONFIG_MTD_CHAR=y +CONFIG_MTD_BLKDEVS=y +CONFIG_MTD_BLOCK=y +# CONFIG_FTL is not set +# CONFIG_NFTL is not set +# CONFIG_INFTL is not set +# CONFIG_RFD_FTL is not set +# CONFIG_SSFDC is not set + +# +# RAM/ROM/Flash chip drivers +# +# CONFIG_MTD_CFI is not set +# CONFIG_MTD_JEDECPROBE is not set +CONFIG_MTD_MAP_BANK_WIDTH_1=y +CONFIG_MTD_MAP_BANK_WIDTH_2=y +CONFIG_MTD_MAP_BANK_WIDTH_4=y +# CONFIG_MTD_MAP_BANK_WIDTH_8 is not set +# CONFIG_MTD_MAP_BANK_WIDTH_16 is not set +# CONFIG_MTD_MAP_BANK_WIDTH_32 is not set +CONFIG_MTD_CFI_I1=y +CONFIG_MTD_CFI_I2=y +# CONFIG_MTD_CFI_I4 is not set +# CONFIG_MTD_CFI_I8 is not set +# CONFIG_MTD_RAM is not set +# CONFIG_MTD_ROM is not set +# CONFIG_MTD_ABSENT is not set +# CONFIG_MTD_OBSOLETE_CHIPS is not set + +# +# Mapping drivers for chip access +# +# CONFIG_MTD_COMPLEX_MAPPINGS is not set +# CONFIG_MTD_PLATRAM is not set + +# +# Self-contained MTD device drivers +# +# CONFIG_MTD_PMC551 is not set +CONFIG_MTD_SLRAM=y +CONFIG_MTD_PHRAM=y +# CONFIG_MTD_MTDRAM is not set +# CONFIG_MTD_BLOCK2MTD is not set + +# +# Disk-On-Chip Device Drivers +# +# CONFIG_MTD_DOC2000 is not set +# CONFIG_MTD_DOC2001 is not set +# CONFIG_MTD_DOC2001PLUS is not set + +# +# NAND Flash Device Drivers +# +# CONFIG_MTD_NAND is not set +# CONFIG_MTD_NAND_CAFE is not set + +# +# OneNAND Flash Device Drivers +# +# CONFIG_MTD_ONENAND is not set + +# +# Parallel port support +# +# CONFIG_PARPORT is not set + +# +# Plug and Play support +# + +# +# Block devices +# +# CONFIG_BLK_DEV_FD is not set +# CONFIG_BLK_CPQ_DA is not set +# CONFIG_BLK_CPQ_CISS_DA is not set +# CONFIG_BLK_DEV_DAC960 is not set +# CONFIG_BLK_DEV_UMEM is not set +# CONFIG_BLK_DEV_COW_COMMON is not set +CONFIG_BLK_DEV_LOOP=y +# CONFIG_BLK_DEV_CRYPTOLOOP is not set +# CONFIG_BLK_DEV_NBD is not set +# CONFIG_BLK_DEV_SX8 is not set +# CONFIG_BLK_DEV_UB is not set +CONFIG_BLK_DEV_RAM=y +CONFIG_BLK_DEV_RAM_COUNT=16 +CONFIG_BLK_DEV_RAM_SIZE=16384 +CONFIG_BLK_DEV_RAM_BLOCKSIZE=1024 +CONFIG_BLK_DEV_INITRD=y +# CONFIG_CDROM_PKTCDVD is not set +# CONFIG_ATA_OVER_ETH is not set + +# +# Misc devices +# +# CONFIG_SGI_IOC4 is not set +# CONFIG_TIFM_CORE is not set + +# +# ATA/ATAPI/MFM/RLL support +# +CONFIG_IDE=y +CONFIG_BLK_DEV_IDE=y + +# +# Please see Documentation/ide.txt for help/info on IDE drives +# +# CONFIG_BLK_DEV_IDE_SATA is not set +CONFIG_BLK_DEV_IDEDISK=y +CONFIG_IDEDISK_MULTI_MODE=y +# CONFIG_BLK_DEV_IDECS is not set +CONFIG_BLK_DEV_IDECD=y +# CONFIG_BLK_DEV_IDETAPE is not set +# CONFIG_BLK_DEV_IDEFLOPPY is not set +CONFIG_BLK_DEV_IDESCSI=y +CONFIG_IDE_TASK_IOCTL=y + +# +# IDE chipset support/bugfixes +# +# CONFIG_IDE_GENERIC is not set +# CONFIG_BLK_DEV_IDEPCI is not set +# CONFIG_IDE_ARM is not set +# CONFIG_BLK_DEV_IDEDMA is not set +# CONFIG_IDEDMA_AUTO is not set +# CONFIG_BLK_DEV_HD is not set + +# +# SCSI device support +# +# CONFIG_RAID_ATTRS is not set +CONFIG_SCSI=y +# CONFIG_SCSI_TGT is not set +# CONFIG_SCSI_NETLINK is not set +CONFIG_SCSI_PROC_FS=y + +# +# SCSI support type (disk, tape, CD-ROM) +# +CONFIG_BLK_DEV_SD=y +CONFIG_CHR_DEV_ST=y +CONFIG_CHR_DEV_OSST=y +CONFIG_BLK_DEV_SR=y +CONFIG_BLK_DEV_SR_VENDOR=y +CONFIG_CHR_DEV_SG=y +CONFIG_CHR_DEV_SCH=y + +# +# Some SCSI devices (e.g. CD jukebox) support multiple LUNs +# +CONFIG_SCSI_MULTI_LUN=y +CONFIG_SCSI_CONSTANTS=y +CONFIG_SCSI_LOGGING=y +# CONFIG_SCSI_SCAN_ASYNC is not set + +# +# SCSI Transports +# +# CONFIG_SCSI_SPI_ATTRS is not set +# CONFIG_SCSI_FC_ATTRS is not set +# CONFIG_SCSI_ISCSI_ATTRS is not set +# CONFIG_SCSI_SAS_ATTRS is not set +# CONFIG_SCSI_SAS_LIBSAS is not set + +# +# SCSI low-level drivers +# +# CONFIG_ISCSI_TCP is not set +CONFIG_BLK_DEV_3W_XXXX_RAID=y +CONFIG_SCSI_3W_9XXX=y +# CONFIG_SCSI_ACARD is not set +# CONFIG_SCSI_AACRAID is not set +# CONFIG_SCSI_AIC7XXX is not set +# CONFIG_SCSI_AIC7XXX_OLD is not set +# CONFIG_SCSI_AIC79XX is not set +# CONFIG_SCSI_AIC94XX is not set +# CONFIG_SCSI_ARCMSR is not set +# CONFIG_MEGARAID_NEWGEN is not set +# CONFIG_MEGARAID_LEGACY is not set +# CONFIG_MEGARAID_SAS is not set +# CONFIG_SCSI_HPTIOP is not set +# CONFIG_SCSI_BUSLOGIC is not set +# CONFIG_SCSI_DMX3191D is not set +# CONFIG_SCSI_EATA is not set +# CONFIG_SCSI_FUTURE_DOMAIN is not set +# CONFIG_SCSI_GDTH is not set +# CONFIG_SCSI_IPS is not set +# CONFIG_SCSI_IBMVSCSI is not set +# CONFIG_SCSI_INITIO is not set +# CONFIG_SCSI_INIA100 is not set +# CONFIG_SCSI_STEX is not set +# CONFIG_SCSI_SYM53C8XX_2 is not set +# CONFIG_SCSI_IPR is not set +# CONFIG_SCSI_QLOGIC_1280 is not set +# CONFIG_SCSI_QLA_FC is not set +# CONFIG_SCSI_QLA_ISCSI is not set +# CONFIG_SCSI_LPFC is not set +# CONFIG_SCSI_DC395x is not set +# CONFIG_SCSI_DC390T is not set +# CONFIG_SCSI_DEBUG is not set +# CONFIG_SCSI_SRP is not set + +# +# PCMCIA SCSI adapter support +# +# CONFIG_PCMCIA_FDOMAIN is not set +# CONFIG_PCMCIA_QLOGIC is not set +# CONFIG_PCMCIA_SYM53C500 is not set + +# +# Serial ATA (prod) and Parallel ATA (experimental) drivers +# +CONFIG_ATA=y +# CONFIG_ATA_NONSTANDARD is not set +# CONFIG_SATA_AHCI is not set +CONFIG_SATA_SVW=y +# CONFIG_ATA_PIIX is not set +CONFIG_SATA_MV=y +# CONFIG_SATA_NV is not set +# CONFIG_PDC_ADMA is not set +# CONFIG_SATA_QSTOR is not set +# CONFIG_SATA_PROMISE is not set +# CONFIG_SATA_SX4 is not set +CONFIG_SATA_SIL=y +CONFIG_SATA_SIL24=y +# CONFIG_SATA_SIS is not set +# CONFIG_SATA_ULI is not set +# CONFIG_SATA_VIA is not set +# CONFIG_SATA_VITESSE is not set +# CONFIG_PATA_ALI is not set +# CONFIG_PATA_AMD is not set +# CONFIG_PATA_ARTOP is not set +# CONFIG_PATA_ATIIXP is not set +# CONFIG_PATA_CMD64X is not set +# CONFIG_PATA_CS5520 is not set +# CONFIG_PATA_CS5530 is not set +# CONFIG_PATA_CYPRESS is not set +# CONFIG_PATA_EFAR is not set +CONFIG_ATA_GENERIC=y +# CONFIG_PATA_HPT366 is not set +# CONFIG_PATA_HPT37X is not set +# CONFIG_PATA_HPT3X2N is not set +# CONFIG_PATA_HPT3X3 is not set +# CONFIG_PATA_IT821X is not set +# CONFIG_PATA_JMICRON is not set +# CONFIG_PATA_TRIFLEX is not set +# CONFIG_PATA_MARVELL is not set +# CONFIG_PATA_MPIIX is not set +# CONFIG_PATA_OLDPIIX is not set +# CONFIG_PATA_NETCELL is not set +# CONFIG_PATA_NS87410 is not set +# CONFIG_PATA_OPTI is not set +# CONFIG_PATA_OPTIDMA is not set +# CONFIG_PATA_PCMCIA is not set +# CONFIG_PATA_PDC_OLD is not set +# CONFIG_PATA_RADISYS is not set +# CONFIG_PATA_RZ1000 is not set +# CONFIG_PATA_SC1200 is not set +# CONFIG_PATA_SERVERWORKS is not set +# CONFIG_PATA_PDC2027X is not set +# CONFIG_PATA_SIL680 is not set +# CONFIG_PATA_SIS is not set +# CONFIG_PATA_VIA is not set +# CONFIG_PATA_WINBOND is not set + +# +# Multi-device support (RAID and LVM) +# +# CONFIG_MD is not set + +# +# Fusion MPT device support +# +# CONFIG_FUSION is not set +# CONFIG_FUSION_SPI is not set +# CONFIG_FUSION_FC is not set +# CONFIG_FUSION_SAS is not set + +# +# IEEE 1394 (FireWire) support +# +CONFIG_IEEE1394=y + +# +# Subsystem Options +# +# CONFIG_IEEE1394_VERBOSEDEBUG is not set +# CONFIG_IEEE1394_OUI_DB is not set +# CONFIG_IEEE1394_EXTRA_CONFIG_ROMS is not set +# CONFIG_IEEE1394_EXPORT_FULL_API is not set + +# +# Device Drivers +# +CONFIG_IEEE1394_PCILYNX=y +CONFIG_IEEE1394_OHCI1394=y + +# +# Protocol Drivers +# +# CONFIG_IEEE1394_VIDEO1394 is not set +CONFIG_IEEE1394_SBP2=y +# CONFIG_IEEE1394_ETH1394 is not set +# CONFIG_IEEE1394_DV1394 is not set +CONFIG_IEEE1394_RAWIO=y + +# +# I2O device support +# +# CONFIG_I2O is not set + +# +# Macintosh device drivers +# +# CONFIG_MAC_EMUMOUSEBTN is not set +# CONFIG_WINDFARM is not set + +# +# Network device support +# +CONFIG_NETDEVICES=y +CONFIG_DUMMY=y +# CONFIG_BONDING is not set +# CONFIG_EQUALIZER is not set +# CONFIG_TUN is not set + +# +# ARCnet devices +# +# CONFIG_ARCNET is not set + +# +# PHY device support +# +# CONFIG_PHYLIB is not set + +# +# Ethernet (10 or 100Mbit) +# +CONFIG_NET_ETHERNET=y +CONFIG_MII=y +# CONFIG_HAPPYMEAL is not set +# CONFIG_SUNGEM is not set +# CONFIG_CASSINI is not set +# CONFIG_NET_VENDOR_3COM is not set + +# +# Tulip family network device support +# +# CONFIG_NET_TULIP is not set +# CONFIG_HP100 is not set +CONFIG_IBMVETH=y +CONFIG_NET_PCI=y +# CONFIG_PCNET32 is not set +# CONFIG_AMD8111_ETH is not set +# CONFIG_ADAPTEC_STARFIRE is not set +# CONFIG_B44 is not set +# CONFIG_FORCEDETH is not set +# CONFIG_DGRS is not set +CONFIG_EEPRO100=y +# CONFIG_E100 is not set +# CONFIG_FEALNX is not set +# CONFIG_NATSEMI is not set +# CONFIG_NE2K_PCI is not set +# CONFIG_8139CP is not set +# CONFIG_8139TOO is not set +# CONFIG_SIS900 is not set +# CONFIG_EPIC100 is not set +# CONFIG_SUNDANCE is not set +# CONFIG_VIA_RHINE is not set + +# +# Ethernet (1000 Mbit) +# +# CONFIG_ACENIC is not set +# CONFIG_DL2K is not set +CONFIG_E1000=y +CONFIG_E1000_NAPI=y +# CONFIG_E1000_DISABLE_PACKET_SPLIT is not set +# CONFIG_NS83820 is not set +# CONFIG_HAMACHI is not set +# CONFIG_YELLOWFIN is not set +# CONFIG_R8169 is not set +# CONFIG_SIS190 is not set +# CONFIG_SKGE is not set +# CONFIG_SKY2 is not set +# CONFIG_SK98LIN is not set +# CONFIG_VIA_VELOCITY is not set +CONFIG_TIGON3=y +# CONFIG_BNX2 is not set +# CONFIG_QLA3XXX is not set + +# +# Ethernet (10000 Mbit) +# +# CONFIG_CHELSIO_T1 is not set +# CONFIG_IXGB is not set +# CONFIG_S2IO is not set +# CONFIG_MYRI10GE is not set +# CONFIG_NETXEN_NIC is not set + +# +# Token Ring devices +# +# CONFIG_TR is not set + +# +# Wireless LAN (non-hamradio) +# +# CONFIG_NET_RADIO is not set + +# +# PCMCIA network device support +# +# CONFIG_NET_PCMCIA is not set + +# +# Wan interfaces +# +# CONFIG_WAN is not set +# CONFIG_FDDI is not set +# CONFIG_HIPPI is not set +# CONFIG_PPP is not set +# CONFIG_SLIP is not set +# CONFIG_NET_FC is not set +# CONFIG_SHAPER is not set +# CONFIG_NETCONSOLE is not set +# CONFIG_NETPOLL is not set +# CONFIG_NET_POLL_CONTROLLER is not set + +# +# ISDN subsystem +# +# CONFIG_ISDN is not set + +# +# Telephony Support +# +# CONFIG_PHONE is not set + +# +# Input device support +# +CONFIG_INPUT=y +# CONFIG_INPUT_FF_MEMLESS is not set + +# +# Userland interfaces +# +CONFIG_INPUT_MOUSEDEV=y +CONFIG_INPUT_MOUSEDEV_PSAUX=y +CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024 +CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768 +CONFIG_INPUT_JOYDEV=y +# CONFIG_INPUT_TSDEV is not set +CONFIG_INPUT_EVDEV=y +# CONFIG_INPUT_EVBUG is not set + +# +# Input Device Drivers +# +CONFIG_INPUT_KEYBOARD=y +# CONFIG_KEYBOARD_ATKBD is not set +# CONFIG_KEYBOARD_SUNKBD is not set +# CONFIG_KEYBOARD_LKKBD is not set +# CONFIG_KEYBOARD_XTKBD is not set +# CONFIG_KEYBOARD_NEWTON is not set +# CONFIG_KEYBOARD_STOWAWAY is not set +CONFIG_INPUT_MOUSE=y +# CONFIG_MOUSE_PS2 is not set +# CONFIG_MOUSE_SERIAL is not set +# CONFIG_MOUSE_VSXXXAA is not set +# CONFIG_INPUT_JOYSTICK is not set +# CONFIG_INPUT_TOUCHSCREEN is not set +# CONFIG_INPUT_MISC is not set + +# +# Hardware I/O ports +# +# CONFIG_SERIO is not set +# CONFIG_GAMEPORT is not set + +# +# Character devices +# +CONFIG_VT=y +CONFIG_VT_CONSOLE=y +CONFIG_HW_CONSOLE=y +# CONFIG_VT_HW_CONSOLE_BINDING is not set +# CONFIG_SERIAL_NONSTANDARD is not set + +# +# Serial drivers +# +CONFIG_SERIAL_8250=y +CONFIG_SERIAL_8250_CONSOLE=y +CONFIG_SERIAL_8250_PCI=y +# CONFIG_SERIAL_8250_CS is not set +CONFIG_SERIAL_8250_NR_UARTS=4 +CONFIG_SERIAL_8250_RUNTIME_UARTS=4 +# CONFIG_SERIAL_8250_EXTENDED is not set + +# +# Non-8250 serial port support +# +CONFIG_SERIAL_CORE=y +CONFIG_SERIAL_CORE_CONSOLE=y +# CONFIG_SERIAL_ICOM is not set +# CONFIG_SERIAL_JSM is not set +CONFIG_UNIX98_PTYS=y +CONFIG_LEGACY_PTYS=y +CONFIG_LEGACY_PTY_COUNT=4 +CONFIG_HVC_DRIVER=y +CONFIG_HVC_CONSOLE=y +CONFIG_HVC_RTAS=y +# CONFIG_HVCS is not set + +# +# IPMI +# +# CONFIG_IPMI_HANDLER is not set + +# +# Watchdog Cards +# +# CONFIG_WATCHDOG is not set +CONFIG_HW_RANDOM=y +CONFIG_GEN_RTC=y +CONFIG_GEN_RTC_X=y +# CONFIG_DTLK is not set +# CONFIG_R3964 is not set +# CONFIG_APPLICOM is not set +# CONFIG_AGP is not set +# CONFIG_DRM is not set + +# +# PCMCIA character devices +# +# CONFIG_SYNCLINK_CS is not set +# CONFIG_CARDMAN_4000 is not set +# CONFIG_CARDMAN_4040 is not set +CONFIG_RAW_DRIVER=y +CONFIG_MAX_RAW_DEVS=256 +# CONFIG_HANGCHECK_TIMER is not set + +# +# TPM devices +# +# CONFIG_TCG_TPM is not set + +# +# I2C support +# +CONFIG_I2C=y +CONFIG_I2C_CHARDEV=y + +# +# I2C Algorithms +# +CONFIG_I2C_ALGOBIT=y +CONFIG_I2C_ALGOPCF=y +CONFIG_I2C_ALGOPCA=y + +# +# I2C Hardware Bus support +# +# CONFIG_I2C_ALI1535 is not set +# CONFIG_I2C_ALI1563 is not set +# CONFIG_I2C_ALI15X3 is not set +# CONFIG_I2C_AMD756 is not set +# CONFIG_I2C_AMD8111 is not set +# CONFIG_I2C_I801 is not set +# CONFIG_I2C_I810 is not set +# CONFIG_I2C_PIIX4 is not set +# CONFIG_I2C_NFORCE2 is not set +# CONFIG_I2C_OCORES is not set +# CONFIG_I2C_PARPORT_LIGHT is not set +# CONFIG_I2C_PROSAVAGE is not set +# CONFIG_I2C_SAVAGE4 is not set +# CONFIG_I2C_SIS5595 is not set +# CONFIG_I2C_SIS630 is not set +# CONFIG_I2C_SIS96X is not set +# CONFIG_I2C_STUB is not set +# CONFIG_I2C_VIA is not set +# CONFIG_I2C_VIAPRO is not set +# CONFIG_I2C_VOODOO3 is not set +# CONFIG_I2C_PCA_ISA is not set + +# +# Miscellaneous I2C Chip support +# +# CONFIG_SENSORS_DS1337 is not set +# CONFIG_SENSORS_DS1374 is not set +CONFIG_SENSORS_EEPROM=y +# CONFIG_SENSORS_PCF8574 is not set +# CONFIG_SENSORS_PCA9539 is not set +# CONFIG_SENSORS_PCF8591 is not set +# CONFIG_SENSORS_MAX6875 is not set +# CONFIG_I2C_DEBUG_CORE is not set +# CONFIG_I2C_DEBUG_ALGO is not set +CONFIG_I2C_DEBUG_BUS=y +# CONFIG_I2C_DEBUG_CHIP is not set + +# +# SPI support +# +# CONFIG_SPI is not set +# CONFIG_SPI_MASTER is not set + +# +# Dallas's 1-wire bus +# +# CONFIG_W1 is not set + +# +# Hardware Monitoring support +# +CONFIG_HWMON=y +CONFIG_HWMON_VID=y +# CONFIG_SENSORS_ABITUGURU is not set +# CONFIG_SENSORS_ADM1021 is not set +# CONFIG_SENSORS_ADM1025 is not set +# CONFIG_SENSORS_ADM1026 is not set +# CONFIG_SENSORS_ADM1031 is not set +# CONFIG_SENSORS_ADM9240 is not set +# CONFIG_SENSORS_ASB100 is not set +# CONFIG_SENSORS_ATXP1 is not set +# CONFIG_SENSORS_DS1621 is not set +# CONFIG_SENSORS_F71805F is not set +# CONFIG_SENSORS_FSCHER is not set +# CONFIG_SENSORS_FSCPOS is not set +# CONFIG_SENSORS_GL518SM is not set +# CONFIG_SENSORS_GL520SM is not set +# CONFIG_SENSORS_IT87 is not set +# CONFIG_SENSORS_LM63 is not set +# CONFIG_SENSORS_LM75 is not set +# CONFIG_SENSORS_LM77 is not set +# CONFIG_SENSORS_LM78 is not set +# CONFIG_SENSORS_LM80 is not set +# CONFIG_SENSORS_LM83 is not set +CONFIG_SENSORS_LM85=y +# CONFIG_SENSORS_LM87 is not set +CONFIG_SENSORS_LM90=y +# CONFIG_SENSORS_LM92 is not set +# CONFIG_SENSORS_MAX1619 is not set +# CONFIG_SENSORS_PC87360 is not set +# CONFIG_SENSORS_PC87427 is not set +# CONFIG_SENSORS_SIS5595 is not set +# CONFIG_SENSORS_SMSC47M1 is not set +# CONFIG_SENSORS_SMSC47M192 is not set +# CONFIG_SENSORS_SMSC47B397 is not set +# CONFIG_SENSORS_VIA686A is not set +# CONFIG_SENSORS_VT1211 is not set +# CONFIG_SENSORS_VT8231 is not set +# CONFIG_SENSORS_W83781D is not set +# CONFIG_SENSORS_W83791D is not set +# CONFIG_SENSORS_W83792D is not set +# CONFIG_SENSORS_W83793 is not set +# CONFIG_SENSORS_W83L785TS is not set +# CONFIG_SENSORS_W83627HF is not set +# CONFIG_SENSORS_W83627EHF is not set +# CONFIG_HWMON_DEBUG_CHIP is not set + +# +# Multimedia devices +# +# CONFIG_VIDEO_DEV is not set + +# +# Digital Video Broadcasting Devices +# +# CONFIG_DVB is not set +# CONFIG_USB_DABUSB is not set + +# +# Graphics support +# +CONFIG_FIRMWARE_EDID=y +CONFIG_FB=y +CONFIG_FB_DDC=y +CONFIG_FB_CFB_FILLRECT=y +CONFIG_FB_CFB_COPYAREA=y +CONFIG_FB_CFB_IMAGEBLIT=y +CONFIG_FB_MACMODES=y +# CONFIG_FB_BACKLIGHT is not set +CONFIG_FB_MODE_HELPERS=y +CONFIG_FB_TILEBLITTING=y +# CONFIG_FB_CIRRUS is not set +# CONFIG_FB_PM2 is not set +# CONFIG_FB_CYBER2000 is not set +# CONFIG_FB_OF is not set +# CONFIG_FB_ASILIANT is not set +# CONFIG_FB_IMSTT is not set +CONFIG_FB_VGA16=y +# CONFIG_FB_S1D13XXX is not set +CONFIG_FB_NVIDIA=y +CONFIG_FB_NVIDIA_I2C=y +CONFIG_FB_RIVA=y +CONFIG_FB_RIVA_I2C=y +# CONFIG_FB_RIVA_DEBUG is not set +CONFIG_FB_MATROX=y +CONFIG_FB_MATROX_MILLENIUM=y +CONFIG_FB_MATROX_MYSTIQUE=y +CONFIG_FB_MATROX_G=y +CONFIG_FB_MATROX_I2C=y +CONFIG_FB_MATROX_MAVEN=y +CONFIG_FB_MATROX_MULTIHEAD=y +CONFIG_FB_RADEON=y +CONFIG_FB_RADEON_I2C=y +# CONFIG_FB_RADEON_DEBUG is not set +# CONFIG_FB_ATY128 is not set +# CONFIG_FB_ATY is not set +# CONFIG_FB_SAVAGE is not set +# CONFIG_FB_SIS is not set +# CONFIG_FB_NEOMAGIC is not set +# CONFIG_FB_KYRO is not set +# CONFIG_FB_3DFX is not set +# CONFIG_FB_VOODOO1 is not set +# CONFIG_FB_TRIDENT is not set +# CONFIG_FB_IBM_GXT4500 is not set +# CONFIG_FB_VIRTUAL is not set + +# +# Console display driver support +# +CONFIG_VGA_CONSOLE=y +CONFIG_VGACON_SOFT_SCROLLBACK=y +CONFIG_VGACON_SOFT_SCROLLBACK_SIZE=64 +CONFIG_DUMMY_CONSOLE=y +CONFIG_FRAMEBUFFER_CONSOLE=y +# CONFIG_FRAMEBUFFER_CONSOLE_ROTATION is not set +# CONFIG_FONTS is not set +CONFIG_FONT_8x8=y +CONFIG_FONT_8x16=y + +# +# Logo configuration +# +CONFIG_LOGO=y +CONFIG_LOGO_LINUX_MONO=y +CONFIG_LOGO_LINUX_VGA16=y +CONFIG_LOGO_LINUX_CLUT224=y +# CONFIG_BACKLIGHT_LCD_SUPPORT is not set + +# +# Sound +# +CONFIG_SOUND=y + +# +# Advanced Linux Sound Architecture +# +CONFIG_SND=y +CONFIG_SND_TIMER=y +CONFIG_SND_PCM=y +CONFIG_SND_HWDEP=y +CONFIG_SND_RAWMIDI=y +CONFIG_SND_SEQUENCER=y +# CONFIG_SND_SEQ_DUMMY is not set +CONFIG_SND_OSSEMUL=y +CONFIG_SND_MIXER_OSS=y +CONFIG_SND_PCM_OSS=y +CONFIG_SND_PCM_OSS_PLUGINS=y +CONFIG_SND_SEQUENCER_OSS=y +# CONFIG_SND_DYNAMIC_MINORS is not set +CONFIG_SND_SUPPORT_OLD_API=y +CONFIG_SND_VERBOSE_PROCFS=y +# CONFIG_SND_VERBOSE_PRINTK is not set +# CONFIG_SND_DEBUG is not set + +# +# Generic devices +# +# CONFIG_SND_DUMMY is not set +# CONFIG_SND_VIRMIDI is not set +# CONFIG_SND_MTPAV is not set +# CONFIG_SND_SERIAL_U16550 is not set +# CONFIG_SND_MPU401 is not set + +# +# PCI devices +# +# CONFIG_SND_AD1889 is not set +# CONFIG_SND_ALS300 is not set +# CONFIG_SND_ALS4000 is not set +# CONFIG_SND_ALI5451 is not set +# CONFIG_SND_ATIIXP is not set +# CONFIG_SND_ATIIXP_MODEM is not set +# CONFIG_SND_AU8810 is not set +# CONFIG_SND_AU8820 is not set +# CONFIG_SND_AU8830 is not set +# CONFIG_SND_AZT3328 is not set +# CONFIG_SND_BT87X is not set +# CONFIG_SND_CA0106 is not set +# CONFIG_SND_CMIPCI is not set +# CONFIG_SND_CS4281 is not set +# CONFIG_SND_CS46XX is not set +# CONFIG_SND_DARLA20 is not set +# CONFIG_SND_GINA20 is not set +# CONFIG_SND_LAYLA20 is not set +# CONFIG_SND_DARLA24 is not set +# CONFIG_SND_GINA24 is not set +# CONFIG_SND_LAYLA24 is not set +# CONFIG_SND_MONA is not set +# CONFIG_SND_MIA is not set +# CONFIG_SND_ECHO3G is not set +# CONFIG_SND_INDIGO is not set +# CONFIG_SND_INDIGOIO is not set +# CONFIG_SND_INDIGODJ is not set +# CONFIG_SND_EMU10K1 is not set +# CONFIG_SND_EMU10K1X is not set +# CONFIG_SND_ENS1370 is not set +# CONFIG_SND_ENS1371 is not set +# CONFIG_SND_ES1938 is not set +# CONFIG_SND_ES1968 is not set +# CONFIG_SND_FM801 is not set +# CONFIG_SND_HDA_INTEL is not set +# CONFIG_SND_HDSP is not set +# CONFIG_SND_HDSPM is not set +# CONFIG_SND_ICE1712 is not set +# CONFIG_SND_ICE1724 is not set +# CONFIG_SND_INTEL8X0 is not set +# CONFIG_SND_INTEL8X0M is not set +# CONFIG_SND_KORG1212 is not set +# CONFIG_SND_MAESTRO3 is not set +# CONFIG_SND_MIXART is not set +# CONFIG_SND_NM256 is not set +# CONFIG_SND_PCXHR is not set +# CONFIG_SND_RIPTIDE is not set +# CONFIG_SND_RME32 is not set +# CONFIG_SND_RME96 is not set +# CONFIG_SND_RME9652 is not set +# CONFIG_SND_SONICVIBES is not set +# CONFIG_SND_TRIDENT is not set +# CONFIG_SND_VIA82XX is not set +# CONFIG_SND_VIA82XX_MODEM is not set +# CONFIG_SND_VX222 is not set +# CONFIG_SND_YMFPCI is not set + +# +# ALSA PowerMac devices +# + +# +# USB devices +# +CONFIG_SND_USB_AUDIO=y +CONFIG_SND_USB_USX2Y=y + +# +# PCMCIA devices +# +# CONFIG_SND_VXPOCKET is not set +# CONFIG_SND_PDAUDIOCF is not set + +# +# Open Sound System +# +# CONFIG_SOUND_PRIME is not set + +# +# HID Devices +# +CONFIG_HID=y + +# +# USB support +# +CONFIG_USB_ARCH_HAS_HCD=y +CONFIG_USB_ARCH_HAS_OHCI=y +CONFIG_USB_ARCH_HAS_EHCI=y +CONFIG_USB=y +# CONFIG_USB_DEBUG is not set + +# +# Miscellaneous USB options +# +CONFIG_USB_DEVICEFS=y +# CONFIG_USB_BANDWIDTH is not set +# CONFIG_USB_DYNAMIC_MINORS is not set +# CONFIG_USB_OTG is not set + +# +# USB Host Controller Drivers +# +CONFIG_USB_EHCI_HCD=y +# CONFIG_USB_EHCI_SPLIT_ISO is not set +# CONFIG_USB_EHCI_ROOT_HUB_TT is not set +# CONFIG_USB_EHCI_TT_NEWSCHED is not set +# CONFIG_USB_ISP116X_HCD is not set +CONFIG_USB_OHCI_HCD=y +# CONFIG_USB_OHCI_BIG_ENDIAN is not set +CONFIG_USB_OHCI_LITTLE_ENDIAN=y +CONFIG_USB_UHCI_HCD=y +CONFIG_USB_SL811_HCD=y +# CONFIG_USB_SL811_CS is not set + +# +# USB Device Class drivers +# +# CONFIG_USB_ACM is not set +# CONFIG_USB_PRINTER is not set + +# +# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support' +# + +# +# may also be needed; see USB_STORAGE Help for more information +# +CONFIG_USB_STORAGE=y +# CONFIG_USB_STORAGE_DEBUG is not set +# CONFIG_USB_STORAGE_DATAFAB is not set +# CONFIG_USB_STORAGE_FREECOM is not set +# CONFIG_USB_STORAGE_ISD200 is not set +# CONFIG_USB_STORAGE_DPCM is not set +# CONFIG_USB_STORAGE_USBAT is not set +# CONFIG_USB_STORAGE_SDDR09 is not set +# CONFIG_USB_STORAGE_SDDR55 is not set +# CONFIG_USB_STORAGE_JUMPSHOT is not set +# CONFIG_USB_STORAGE_ALAUDA is not set +# CONFIG_USB_STORAGE_ONETOUCH is not set +# CONFIG_USB_STORAGE_KARMA is not set +CONFIG_USB_LIBUSUAL=y + +# +# USB Input Devices +# +CONFIG_USB_HID=y +# CONFIG_USB_HIDINPUT_POWERBOOK is not set +# CONFIG_HID_FF is not set +# CONFIG_USB_HIDDEV is not set +# CONFIG_USB_AIPTEK is not set +# CONFIG_USB_WACOM is not set +# CONFIG_USB_ACECAD is not set +# CONFIG_USB_KBTAB is not set +# CONFIG_USB_POWERMATE is not set +# CONFIG_USB_TOUCHSCREEN is not set +# CONFIG_USB_YEALINK is not set +# CONFIG_USB_XPAD is not set +# CONFIG_USB_ATI_REMOTE is not set +# CONFIG_USB_ATI_REMOTE2 is not set +# CONFIG_USB_KEYSPAN_REMOTE is not set +# CONFIG_USB_APPLETOUCH is not set + +# +# USB Imaging devices +# +# CONFIG_USB_MDC800 is not set +# CONFIG_USB_MICROTEK is not set + +# +# USB Network Adapters +# +# CONFIG_USB_CATC is not set +# CONFIG_USB_KAWETH is not set +# CONFIG_USB_PEGASUS is not set +# CONFIG_USB_RTL8150 is not set +# CONFIG_USB_USBNET_MII is not set +# CONFIG_USB_USBNET is not set +CONFIG_USB_MON=y + +# +# USB port drivers +# + +# +# USB Serial Converter support +# +# CONFIG_USB_SERIAL is not set + +# +# USB Miscellaneous drivers +# +# CONFIG_USB_EMI62 is not set +# CONFIG_USB_EMI26 is not set +# CONFIG_USB_ADUTUX is not set +# CONFIG_USB_AUERSWALD is not set +# CONFIG_USB_RIO500 is not set +# CONFIG_USB_LEGOTOWER is not set +# CONFIG_USB_LCD is not set +# CONFIG_USB_LED is not set +# CONFIG_USB_CYPRESS_CY7C63 is not set +# CONFIG_USB_CYTHERM is not set +# CONFIG_USB_PHIDGET is not set +# CONFIG_USB_IDMOUSE is not set +# CONFIG_USB_FTDI_ELAN is not set +# CONFIG_USB_APPLEDISPLAY is not set +# CONFIG_USB_SISUSBVGA is not set +# CONFIG_USB_LD is not set +# CONFIG_USB_TRANCEVIBRATOR is not set +# CONFIG_USB_TEST is not set + +# +# USB DSL modem support +# + +# +# USB Gadget Support +# +# CONFIG_USB_GADGET is not set + +# +# MMC/SD Card support +# +# CONFIG_MMC is not set + +# +# LED devices +# +# CONFIG_NEW_LEDS is not set + +# +# LED drivers +# + +# +# LED Triggers +# + +# +# InfiniBand support +# +# CONFIG_INFINIBAND is not set + +# +# EDAC - error detection and reporting (RAS) (EXPERIMENTAL) +# + +# +# Real Time Clock +# +CONFIG_RTC_LIB=y +CONFIG_RTC_CLASS=y +CONFIG_RTC_HCTOSYS=y +CONFIG_RTC_HCTOSYS_DEVICE="rtc0" +# CONFIG_RTC_DEBUG is not set + +# +# RTC interfaces +# +CONFIG_RTC_INTF_SYSFS=y +CONFIG_RTC_INTF_PROC=y +CONFIG_RTC_INTF_DEV=y +# CONFIG_RTC_INTF_DEV_UIE_EMUL is not set + +# +# RTC drivers +# +# CONFIG_RTC_DRV_X1205 is not set +CONFIG_RTC_DRV_DS1307=y +# CONFIG_RTC_DRV_DS1553 is not set +# CONFIG_RTC_DRV_ISL1208 is not set +# CONFIG_RTC_DRV_DS1672 is not set +# CONFIG_RTC_DRV_DS1742 is not set +# CONFIG_RTC_DRV_PCF8563 is not set +# CONFIG_RTC_DRV_PCF8583 is not set +# CONFIG_RTC_DRV_RS5C372 is not set +# CONFIG_RTC_DRV_M48T86 is not set +# CONFIG_RTC_DRV_TEST is not set +# CONFIG_RTC_DRV_V3020 is not set + +# +# DMA Engine support +# +# CONFIG_DMA_ENGINE is not set + +# +# DMA Clients +# + +# +# DMA Devices +# + +# +# Virtualization +# + +# +# File systems +# +CONFIG_EXT2_FS=y +CONFIG_EXT2_FS_XATTR=y +CONFIG_EXT2_FS_POSIX_ACL=y +# CONFIG_EXT2_FS_SECURITY is not set +# CONFIG_EXT2_FS_XIP is not set +CONFIG_EXT3_FS=y +CONFIG_EXT3_FS_XATTR=y +# CONFIG_EXT3_FS_POSIX_ACL is not set +# CONFIG_EXT3_FS_SECURITY is not set +# CONFIG_EXT4DEV_FS is not set +CONFIG_JBD=y +# CONFIG_JBD_DEBUG is not set +CONFIG_FS_MBCACHE=y +# CONFIG_REISERFS_FS is not set +# CONFIG_JFS_FS is not set +CONFIG_FS_POSIX_ACL=y +# CONFIG_XFS_FS is not set +# CONFIG_GFS2_FS is not set +# CONFIG_OCFS2_FS is not set +# CONFIG_MINIX_FS is not set +# CONFIG_ROMFS_FS is not set +# CONFIG_INOTIFY is not set +# CONFIG_QUOTA is not set +CONFIG_DNOTIFY=y +CONFIG_AUTOFS_FS=y +CONFIG_AUTOFS4_FS=y +# CONFIG_FUSE_FS is not set + +# +# CD-ROM/DVD Filesystems +# +CONFIG_ISO9660_FS=y +# CONFIG_JOLIET is not set +# CONFIG_ZISOFS is not set +CONFIG_UDF_FS=y +CONFIG_UDF_NLS=y + +# +# DOS/FAT/NT Filesystems +# +CONFIG_FAT_FS=y +CONFIG_MSDOS_FS=y +CONFIG_VFAT_FS=y +CONFIG_FAT_DEFAULT_CODEPAGE=437 +CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1" +# CONFIG_NTFS_FS is not set + +# +# Pseudo filesystems +# +CONFIG_PROC_FS=y +CONFIG_PROC_KCORE=y +CONFIG_PROC_SYSCTL=y +CONFIG_SYSFS=y +CONFIG_TMPFS=y +# CONFIG_TMPFS_POSIX_ACL is not set +CONFIG_HUGETLBFS=y +CONFIG_HUGETLB_PAGE=y +CONFIG_RAMFS=y +CONFIG_CONFIGFS_FS=y + +# +# Miscellaneous filesystems +# +# CONFIG_ADFS_FS is not set +# CONFIG_AFFS_FS is not set +# CONFIG_HFS_FS is not set +# CONFIG_HFSPLUS_FS is not set +# CONFIG_BEFS_FS is not set +# CONFIG_BFS_FS is not set +# CONFIG_EFS_FS is not set +# CONFIG_JFFS2_FS is not set +# CONFIG_CRAMFS is not set +# CONFIG_VXFS_FS is not set +# CONFIG_HPFS_FS is not set +# CONFIG_QNX4FS_FS is not set +# CONFIG_SYSV_FS is not set +# CONFIG_UFS_FS is not set + +# +# Network File Systems +# +CONFIG_NFS_FS=y +CONFIG_NFS_V3=y +# CONFIG_NFS_V3_ACL is not set +# CONFIG_NFS_V4 is not set +# CONFIG_NFS_DIRECTIO is not set +# CONFIG_NFSD is not set +CONFIG_ROOT_NFS=y +CONFIG_LOCKD=y +CONFIG_LOCKD_V4=y +CONFIG_NFS_COMMON=y +CONFIG_SUNRPC=y +# CONFIG_RPCSEC_GSS_KRB5 is not set +# CONFIG_RPCSEC_GSS_SPKM3 is not set +# CONFIG_SMB_FS is not set +# CONFIG_CIFS is not set +# CONFIG_NCP_FS is not set +# CONFIG_CODA_FS is not set +# CONFIG_AFS_FS is not set +# CONFIG_9P_FS is not set + +# +# Partition Types +# +CONFIG_PARTITION_ADVANCED=y +# CONFIG_ACORN_PARTITION is not set +# CONFIG_OSF_PARTITION is not set +# CONFIG_AMIGA_PARTITION is not set +# CONFIG_ATARI_PARTITION is not set +CONFIG_MAC_PARTITION=y +CONFIG_MSDOS_PARTITION=y +# CONFIG_BSD_DISKLABEL is not set +# CONFIG_MINIX_SUBPARTITION is not set +# CONFIG_SOLARIS_X86_PARTITION is not set +# CONFIG_UNIXWARE_DISKLABEL is not set +# CONFIG_LDM_PARTITION is not set +# CONFIG_SGI_PARTITION is not set +# CONFIG_ULTRIX_PARTITION is not set +# CONFIG_SUN_PARTITION is not set +# CONFIG_KARMA_PARTITION is not set +# CONFIG_EFI_PARTITION is not set + +# +# Native Language Support +# +CONFIG_NLS=y +CONFIG_NLS_DEFAULT="iso8859-1" +CONFIG_NLS_CODEPAGE_437=y +# CONFIG_NLS_CODEPAGE_737 is not set +# CONFIG_NLS_CODEPAGE_775 is not set +# CONFIG_NLS_CODEPAGE_850 is not set +# CONFIG_NLS_CODEPAGE_852 is not set +# CONFIG_NLS_CODEPAGE_855 is not set +# CONFIG_NLS_CODEPAGE_857 is not set +# CONFIG_NLS_CODEPAGE_860 is not set +# CONFIG_NLS_CODEPAGE_861 is not set +# CONFIG_NLS_CODEPAGE_862 is not set +# CONFIG_NLS_CODEPAGE_863 is not set +# CONFIG_NLS_CODEPAGE_864 is not set +# CONFIG_NLS_CODEPAGE_865 is not set +# CONFIG_NLS_CODEPAGE_866 is not set +# CONFIG_NLS_CODEPAGE_869 is not set +# CONFIG_NLS_CODEPAGE_936 is not set +# CONFIG_NLS_CODEPAGE_950 is not set +# CONFIG_NLS_CODEPAGE_932 is not set +# CONFIG_NLS_CODEPAGE_949 is not set +# CONFIG_NLS_CODEPAGE_874 is not set +# CONFIG_NLS_ISO8859_8 is not set +# CONFIG_NLS_CODEPAGE_1250 is not set +# CONFIG_NLS_CODEPAGE_1251 is not set +# CONFIG_NLS_ASCII is not set +CONFIG_NLS_ISO8859_1=y +# CONFIG_NLS_ISO8859_2 is not set +# CONFIG_NLS_ISO8859_3 is not set +# CONFIG_NLS_ISO8859_4 is not set +# CONFIG_NLS_ISO8859_5 is not set +# CONFIG_NLS_ISO8859_6 is not set +# CONFIG_NLS_ISO8859_7 is not set +# CONFIG_NLS_ISO8859_9 is not set +# CONFIG_NLS_ISO8859_13 is not set +# CONFIG_NLS_ISO8859_14 is not set +# CONFIG_NLS_ISO8859_15 is not set +# CONFIG_NLS_KOI8_R is not set +# CONFIG_NLS_KOI8_U is not set +# CONFIG_NLS_UTF8 is not set + +# +# Distributed Lock Manager +# +# CONFIG_DLM is not set + +# +# Library routines +# +CONFIG_BITREVERSE=y +CONFIG_CRC_CCITT=y +# CONFIG_CRC16 is not set +CONFIG_CRC32=y +# CONFIG_LIBCRC32C is not set +CONFIG_PLIST=y +CONFIG_IOMAP_COPY=y + +# +# Instrumentation Support +# +CONFIG_PROFILING=y +CONFIG_OPROFILE=y +# CONFIG_KPROBES is not set + +# +# Kernel hacking +# +# CONFIG_PRINTK_TIME is not set +CONFIG_ENABLE_MUST_CHECK=y +CONFIG_MAGIC_SYSRQ=y +# CONFIG_UNUSED_SYMBOLS is not set +# CONFIG_DEBUG_FS is not set +# CONFIG_HEADERS_CHECK is not set +CONFIG_DEBUG_KERNEL=y +CONFIG_LOG_BUF_SHIFT=17 +CONFIG_DETECT_SOFTLOCKUP=y +# CONFIG_SCHEDSTATS is not set +# CONFIG_DEBUG_SLAB is not set +# CONFIG_DEBUG_RT_MUTEXES is not set +# CONFIG_RT_MUTEX_TESTER is not set +# CONFIG_DEBUG_SPINLOCK is not set +# CONFIG_DEBUG_MUTEXES is not set +# CONFIG_DEBUG_RWSEMS is not set +# CONFIG_DEBUG_SPINLOCK_SLEEP is not set +# CONFIG_DEBUG_LOCKING_API_SELFTESTS is not set +# CONFIG_DEBUG_KOBJECT is not set +CONFIG_DEBUG_BUGVERBOSE=y +CONFIG_DEBUG_INFO=y +# CONFIG_DEBUG_VM is not set +# CONFIG_DEBUG_LIST is not set +CONFIG_FORCED_INLINING=y +# CONFIG_RCU_TORTURE_TEST is not set +# CONFIG_DEBUG_STACKOVERFLOW is not set +# CONFIG_DEBUG_STACK_USAGE is not set +CONFIG_DEBUGGER=y +CONFIG_XMON=y +CONFIG_XMON_DEFAULT=y +CONFIG_XMON_DISASSEMBLY=y +# CONFIG_IRQSTACKS is not set +CONFIG_BOOTX_TEXT=y +# CONFIG_PPC_EARLY_DEBUG is not set + +# +# Security options +# +# CONFIG_KEYS is not set +# CONFIG_SECURITY is not set + +# +# Cryptographic options +# +CONFIG_CRYPTO=y +CONFIG_CRYPTO_ALGAPI=y +CONFIG_CRYPTO_BLKCIPHER=y +CONFIG_CRYPTO_HASH=y +CONFIG_CRYPTO_MANAGER=y +CONFIG_CRYPTO_HMAC=y +# CONFIG_CRYPTO_XCBC is not set +# CONFIG_CRYPTO_NULL is not set +# CONFIG_CRYPTO_MD4 is not set +CONFIG_CRYPTO_MD5=y +CONFIG_CRYPTO_SHA1=y +# CONFIG_CRYPTO_SHA256 is not set +# CONFIG_CRYPTO_SHA512 is not set +# CONFIG_CRYPTO_WP512 is not set +# CONFIG_CRYPTO_TGR192 is not set +# CONFIG_CRYPTO_GF128MUL is not set +CONFIG_CRYPTO_ECB=m +CONFIG_CRYPTO_CBC=y +# CONFIG_CRYPTO_LRW is not set +CONFIG_CRYPTO_DES=y +# CONFIG_CRYPTO_BLOWFISH is not set +# CONFIG_CRYPTO_TWOFISH is not set +# CONFIG_CRYPTO_SERPENT is not set +# CONFIG_CRYPTO_AES is not set +# CONFIG_CRYPTO_CAST5 is not set +# CONFIG_CRYPTO_CAST6 is not set +# CONFIG_CRYPTO_TEA is not set +# CONFIG_CRYPTO_ARC4 is not set +# CONFIG_CRYPTO_KHAZAD is not set +# CONFIG_CRYPTO_ANUBIS is not set +# CONFIG_CRYPTO_DEFLATE is not set +# CONFIG_CRYPTO_MICHAEL_MIC is not set +# CONFIG_CRYPTO_CRC32C is not set +# CONFIG_CRYPTO_TEST is not set + +# +# Hardware crypto devices +# diff --git a/arch/powerpc/configs/ps3_defconfig b/arch/powerpc/configs/ps3_defconfig index 3256087..0345a2c 100644 --- a/arch/powerpc/configs/ps3_defconfig +++ b/arch/powerpc/configs/ps3_defconfig @@ -1,7 +1,7 @@ # # Automatically generated make config: don't edit -# Linux kernel version: 2.6.20-rc5 -# Mon Jan 22 22:29:11 2007 +# Linux kernel version: 2.6.20-rc6 +# Thu Jan 25 13:35:34 2007 # CONFIG_PPC64=y CONFIG_64BIT=y @@ -70,10 +70,10 @@ # CONFIG_CPUSETS is not set CONFIG_SYSFS_DEPRECATED=y # CONFIG_RELAY is not set CONFIG_INITRAMFS_SOURCE="" -# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set +CONFIG_CC_OPTIMIZE_FOR_SIZE=y CONFIG_SYSCTL=y -CONFIG_EMBEDDED=y -# CONFIG_SYSCTL_SYSCALL is not set +# CONFIG_EMBEDDED is not set +CONFIG_SYSCTL_SYSCALL=y CONFIG_KALLSYMS=y CONFIG_KALLSYMS_ALL=y CONFIG_KALLSYMS_EXTRA_PASS=y @@ -160,9 +160,10 @@ # # PS3 Platform Options # CONFIG_PS3_HTAB_SIZE=20 -CONFIG_PS3_DYNAMIC_DMA=y +# CONFIG_PS3_DYNAMIC_DMA is not set CONFIG_PS3_USE_LPAR_ADDR=y CONFIG_PS3_VUART=y +CONFIG_PS3_PS3AV=y # # Kernel options @@ -207,7 +208,7 @@ CONFIG_PPC_64K_PAGES=y # CONFIG_SCHED_SMT is not set CONFIG_PROC_DEVICETREE=y CONFIG_CMDLINE_BOOL=y -CONFIG_CMDLINE="root=/dev/nfs rw ip=dhcp" +CONFIG_CMDLINE="root=/dev/sda1 ip=dhcp" # CONFIG_PM is not set # CONFIG_SECCOMP is not set CONFIG_ISA_DMA_API=y @@ -240,7 +241,8 @@ # # Networking options # # CONFIG_NETDEBUG is not set -# CONFIG_PACKET is not set +CONFIG_PACKET=y +CONFIG_PACKET_MMAP=y CONFIG_UNIX=y # CONFIG_NET_KEY is not set CONFIG_INET=y @@ -353,6 +355,7 @@ # CONFIG_BLK_DEV_FD is not set # CONFIG_BLK_DEV_COW_COMMON is not set # CONFIG_BLK_DEV_LOOP is not set # CONFIG_BLK_DEV_NBD is not set +# CONFIG_BLK_DEV_UB is not set # CONFIG_BLK_DEV_RAM is not set # CONFIG_BLK_DEV_INITRD is not set # CONFIG_CDROM_PKTCDVD is not set @@ -380,10 +383,11 @@ CONFIG_SCSI_PROC_FS=y # # SCSI support type (disk, tape, CD-ROM) # -# CONFIG_BLK_DEV_SD is not set +CONFIG_BLK_DEV_SD=y # CONFIG_CHR_DEV_ST is not set # CONFIG_CHR_DEV_OSST is not set -# CONFIG_BLK_DEV_SR is not set +CONFIG_BLK_DEV_SR=y +# CONFIG_BLK_DEV_SR_VENDOR is not set # CONFIG_CHR_DEV_SG is not set # CONFIG_CHR_DEV_SCH is not set @@ -456,6 +460,7 @@ # # Ethernet (10 or 100Mbit) # # CONFIG_NET_ETHERNET is not set +CONFIG_MII=y # # Ethernet (1000 Mbit) @@ -504,10 +509,13 @@ # CONFIG_INPUT_FF_MEMLESS is not set # # Userland interfaces # -# CONFIG_INPUT_MOUSEDEV is not set +CONFIG_INPUT_MOUSEDEV=y +# CONFIG_INPUT_MOUSEDEV_PSAUX is not set +CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024 +CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768 # CONFIG_INPUT_JOYDEV is not set # CONFIG_INPUT_TSDEV is not set -CONFIG_INPUT_EVDEV=y +# CONFIG_INPUT_EVDEV is not set # CONFIG_INPUT_EVBUG is not set # @@ -598,19 +606,46 @@ # # Digital Video Broadcasting Devices # # CONFIG_DVB is not set +# CONFIG_USB_DABUSB is not set # # Graphics support # # CONFIG_FIRMWARE_EDID is not set -# CONFIG_FB is not set +CONFIG_FB=y +CONFIG_FB_CFB_FILLRECT=y +CONFIG_FB_CFB_COPYAREA=y +CONFIG_FB_CFB_IMAGEBLIT=y +# CONFIG_FB_MACMODES is not set +# CONFIG_FB_BACKLIGHT is not set +# CONFIG_FB_MODE_HELPERS is not set +# CONFIG_FB_TILEBLITTING is not set +# CONFIG_FB_OF is not set +# CONFIG_FB_VGA16 is not set +# CONFIG_FB_S1D13XXX is not set # CONFIG_FB_IBM_GXT4500 is not set +CONFIG_FB_PS3=y +CONFIG_FB_PS3_DEFAULT_SIZE_M=18 +# CONFIG_FB_VIRTUAL is not set # # Console display driver support # # CONFIG_VGA_CONSOLE is not set CONFIG_DUMMY_CONSOLE=y +CONFIG_FRAMEBUFFER_CONSOLE=y +# CONFIG_FRAMEBUFFER_CONSOLE_ROTATION is not set +# CONFIG_FONTS is not set +CONFIG_FONT_8x8=y +CONFIG_FONT_8x16=y + +# +# Logo configuration +# +CONFIG_LOGO=y +# CONFIG_LOGO_LINUX_MONO is not set +# CONFIG_LOGO_LINUX_VGA16 is not set +CONFIG_LOGO_LINUX_CLUT224=y # CONFIG_BACKLIGHT_LCD_SUPPORT is not set # @@ -626,15 +661,142 @@ CONFIG_HID=y # # USB support # -# CONFIG_USB_ARCH_HAS_HCD is not set -# CONFIG_USB_ARCH_HAS_OHCI is not set -# CONFIG_USB_ARCH_HAS_EHCI is not set +CONFIG_USB_ARCH_HAS_HCD=y +CONFIG_USB_ARCH_HAS_OHCI=y +CONFIG_USB_ARCH_HAS_EHCI=y +CONFIG_USB=y +CONFIG_USB_DEBUG=y + +# +# Miscellaneous USB options +# +# CONFIG_USB_DEVICEFS is not set +# CONFIG_USB_BANDWIDTH is not set +# CONFIG_USB_DYNAMIC_MINORS is not set +# CONFIG_USB_OTG is not set + +# +# USB Host Controller Drivers +# +CONFIG_USB_EHCI_HCD=y +# CONFIG_USB_EHCI_SPLIT_ISO is not set +# CONFIG_USB_EHCI_ROOT_HUB_TT is not set +# CONFIG_USB_EHCI_TT_NEWSCHED is not set +CONFIG_USB_EHCI_BIG_ENDIAN_MMIO=y +# CONFIG_USB_ISP116X_HCD is not set +CONFIG_USB_OHCI_HCD=y +# CONFIG_USB_OHCI_HCD_PPC_OF is not set +# CONFIG_USB_OHCI_BIG_ENDIAN_DESC is not set +CONFIG_USB_OHCI_BIG_ENDIAN_MMIO=y +CONFIG_USB_OHCI_LITTLE_ENDIAN=y +# CONFIG_USB_SL811_HCD is not set + +# +# USB Device Class drivers +# +# CONFIG_USB_ACM is not set +# CONFIG_USB_PRINTER is not set # # NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support' # # +# may also be needed; see USB_STORAGE Help for more information +# +CONFIG_USB_STORAGE=y +# CONFIG_USB_STORAGE_DEBUG is not set +# CONFIG_USB_STORAGE_DATAFAB is not set +# CONFIG_USB_STORAGE_FREECOM is not set +# CONFIG_USB_STORAGE_DPCM is not set +# CONFIG_USB_STORAGE_USBAT is not set +# CONFIG_USB_STORAGE_SDDR09 is not set +# CONFIG_USB_STORAGE_SDDR55 is not set +# CONFIG_USB_STORAGE_JUMPSHOT is not set +# CONFIG_USB_STORAGE_ALAUDA is not set +# CONFIG_USB_STORAGE_KARMA is not set +# CONFIG_USB_LIBUSUAL is not set + +# +# USB Input Devices +# +CONFIG_USB_HID=y +# CONFIG_USB_HIDINPUT_POWERBOOK is not set +# CONFIG_HID_FF is not set +# CONFIG_USB_HIDDEV is not set +# CONFIG_USB_AIPTEK is not set +# CONFIG_USB_WACOM is not set +# CONFIG_USB_ACECAD is not set +# CONFIG_USB_KBTAB is not set +# CONFIG_USB_POWERMATE is not set +# CONFIG_USB_TOUCHSCREEN is not set +# CONFIG_USB_YEALINK is not set +# CONFIG_USB_XPAD is not set +# CONFIG_USB_ATI_REMOTE is not set +# CONFIG_USB_ATI_REMOTE2 is not set +# CONFIG_USB_KEYSPAN_REMOTE is not set +# CONFIG_USB_APPLETOUCH is not set + +# +# USB Imaging devices +# +# CONFIG_USB_MDC800 is not set +# CONFIG_USB_MICROTEK is not set + +# +# USB Network Adapters +# +# CONFIG_USB_CATC is not set +# CONFIG_USB_KAWETH is not set +# CONFIG_USB_PEGASUS is not set +# CONFIG_USB_RTL8150 is not set +CONFIG_USB_USBNET_MII=y +CONFIG_USB_USBNET=y +CONFIG_USB_NET_CDCETHER=y +# CONFIG_USB_NET_GL620A is not set +# CONFIG_USB_NET_NET1080 is not set +# CONFIG_USB_NET_PLUSB is not set +CONFIG_USB_NET_MCS7830=y +# CONFIG_USB_NET_RNDIS_HOST is not set +# CONFIG_USB_NET_CDC_SUBSET is not set +# CONFIG_USB_NET_ZAURUS is not set +CONFIG_USB_MON=y + +# +# USB port drivers +# + +# +# USB Serial Converter support +# +# CONFIG_USB_SERIAL is not set + +# +# USB Miscellaneous drivers +# +# CONFIG_USB_EMI62 is not set +# CONFIG_USB_EMI26 is not set +# CONFIG_USB_ADUTUX is not set +# CONFIG_USB_AUERSWALD is not set +# CONFIG_USB_RIO500 is not set +# CONFIG_USB_LEGOTOWER is not set +# CONFIG_USB_LCD is not set +# CONFIG_USB_LED is not set +# CONFIG_USB_CYPRESS_CY7C63 is not set +# CONFIG_USB_CYTHERM is not set +# CONFIG_USB_PHIDGET is not set +# CONFIG_USB_IDMOUSE is not set +# CONFIG_USB_FTDI_ELAN is not set +# CONFIG_USB_APPLEDISPLAY is not set +# CONFIG_USB_SISUSBVGA is not set +# CONFIG_USB_LD is not set +# CONFIG_USB_TRANCEVIBRATOR is not set + +# +# USB DSL modem support +# + +# # USB Gadget Support # # CONFIG_USB_GADGET is not set @@ -691,8 +853,14 @@ # # File systems # # CONFIG_EXT2_FS is not set -# CONFIG_EXT3_FS is not set +CONFIG_EXT3_FS=y +CONFIG_EXT3_FS_XATTR=y +# CONFIG_EXT3_FS_POSIX_ACL is not set +# CONFIG_EXT3_FS_SECURITY is not set # CONFIG_EXT4DEV_FS is not set +CONFIG_JBD=y +# CONFIG_JBD_DEBUG is not set +CONFIG_FS_MBCACHE=y # CONFIG_REISERFS_FS is not set # CONFIG_JFS_FS is not set # CONFIG_FS_POSIX_ACL is not set @@ -712,14 +880,20 @@ # CONFIG_FUSE_FS is not set # # CD-ROM/DVD Filesystems # -# CONFIG_ISO9660_FS is not set -# CONFIG_UDF_FS is not set +CONFIG_ISO9660_FS=y +CONFIG_JOLIET=y +# CONFIG_ZISOFS is not set +CONFIG_UDF_FS=y +CONFIG_UDF_NLS=y # # DOS/FAT/NT Filesystems # +CONFIG_FAT_FS=y # CONFIG_MSDOS_FS is not set -# CONFIG_VFAT_FS is not set +CONFIG_VFAT_FS=y +CONFIG_FAT_DEFAULT_CODEPAGE=437 +CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1" # CONFIG_NTFS_FS is not set # @@ -785,7 +959,46 @@ CONFIG_MSDOS_PARTITION=y # # Native Language Support # -# CONFIG_NLS is not set +CONFIG_NLS=y +CONFIG_NLS_DEFAULT="iso8859-1" +CONFIG_NLS_CODEPAGE_437=y +# CONFIG_NLS_CODEPAGE_737 is not set +# CONFIG_NLS_CODEPAGE_775 is not set +# CONFIG_NLS_CODEPAGE_850 is not set +# CONFIG_NLS_CODEPAGE_852 is not set +# CONFIG_NLS_CODEPAGE_855 is not set +# CONFIG_NLS_CODEPAGE_857 is not set +# CONFIG_NLS_CODEPAGE_860 is not set +# CONFIG_NLS_CODEPAGE_861 is not set +# CONFIG_NLS_CODEPAGE_862 is not set +# CONFIG_NLS_CODEPAGE_863 is not set +# CONFIG_NLS_CODEPAGE_864 is not set +# CONFIG_NLS_CODEPAGE_865 is not set +# CONFIG_NLS_CODEPAGE_866 is not set +# CONFIG_NLS_CODEPAGE_869 is not set +# CONFIG_NLS_CODEPAGE_936 is not set +# CONFIG_NLS_CODEPAGE_950 is not set +# CONFIG_NLS_CODEPAGE_932 is not set +# CONFIG_NLS_CODEPAGE_949 is not set +# CONFIG_NLS_CODEPAGE_874 is not set +# CONFIG_NLS_ISO8859_8 is not set +# CONFIG_NLS_CODEPAGE_1250 is not set +# CONFIG_NLS_CODEPAGE_1251 is not set +# CONFIG_NLS_ASCII is not set +CONFIG_NLS_ISO8859_1=y +# CONFIG_NLS_ISO8859_2 is not set +# CONFIG_NLS_ISO8859_3 is not set +# CONFIG_NLS_ISO8859_4 is not set +# CONFIG_NLS_ISO8859_5 is not set +# CONFIG_NLS_ISO8859_6 is not set +# CONFIG_NLS_ISO8859_7 is not set +# CONFIG_NLS_ISO8859_9 is not set +# CONFIG_NLS_ISO8859_13 is not set +# CONFIG_NLS_ISO8859_14 is not set +# CONFIG_NLS_ISO8859_15 is not set +# CONFIG_NLS_KOI8_R is not set +# CONFIG_NLS_KOI8_U is not set +# CONFIG_NLS_UTF8 is not set # # Distributed Lock Manager @@ -795,9 +1008,10 @@ # CONFIG_DLM is not set # # Library routines # +CONFIG_BITREVERSE=y # CONFIG_CRC_CCITT is not set # CONFIG_CRC16 is not set -# CONFIG_CRC32 is not set +CONFIG_CRC32=y # CONFIG_LIBCRC32C is not set CONFIG_PLIST=y CONFIG_IOMAP_COPY=y @@ -821,22 +1035,23 @@ CONFIG_DEBUG_KERNEL=y CONFIG_LOG_BUF_SHIFT=17 CONFIG_DETECT_SOFTLOCKUP=y # CONFIG_SCHEDSTATS is not set -# CONFIG_DEBUG_SLAB is not set +CONFIG_DEBUG_SLAB=y +# CONFIG_DEBUG_SLAB_LEAK is not set # CONFIG_DEBUG_RT_MUTEXES is not set # CONFIG_RT_MUTEX_TESTER is not set CONFIG_DEBUG_SPINLOCK=y -# CONFIG_DEBUG_MUTEXES is not set -# CONFIG_DEBUG_RWSEMS is not set +CONFIG_DEBUG_MUTEXES=y +CONFIG_DEBUG_RWSEMS=y CONFIG_DEBUG_SPINLOCK_SLEEP=y # CONFIG_DEBUG_LOCKING_API_SELFTESTS is not set # CONFIG_DEBUG_KOBJECT is not set -# CONFIG_DEBUG_BUGVERBOSE is not set +CONFIG_DEBUG_BUGVERBOSE=y CONFIG_DEBUG_INFO=y # CONFIG_DEBUG_VM is not set CONFIG_DEBUG_LIST=y CONFIG_FORCED_INLINING=y # CONFIG_RCU_TORTURE_TEST is not set -# CONFIG_DEBUG_STACKOVERFLOW is not set +CONFIG_DEBUG_STACKOVERFLOW=y # CONFIG_DEBUG_STACK_USAGE is not set # CONFIG_DEBUGGER is not set CONFIG_IRQSTACKS=y diff --git a/arch/powerpc/kernel/Makefile b/arch/powerpc/kernel/Makefile index d2ded19..8120d42 100644 --- a/arch/powerpc/kernel/Makefile +++ b/arch/powerpc/kernel/Makefile @@ -17,6 +17,7 @@ obj-y += vdso32/ obj-$(CONFIG_PPC64) += setup_64.o binfmt_elf32.o sys_ppc32.o \ signal_64.o ptrace32.o \ paca.o cpu_setup_ppc970.o \ + cpu_setup_pa6t.o \ firmware.o sysfs.o nvram_64.o obj-$(CONFIG_PPC64) += vdso64/ obj-$(CONFIG_ALTIVEC) += vecemu.o vector.o diff --git a/arch/powerpc/kernel/btext.c b/arch/powerpc/kernel/btext.c index 93f21aa..3678997 100644 --- a/arch/powerpc/kernel/btext.c +++ b/arch/powerpc/kernel/btext.c @@ -18,6 +18,7 @@ #include #include #include #include +#include #define NO_SCROLL @@ -912,3 +913,11 @@ static unsigned char vga_font[cmapsz] = 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, }; + +void __init udbg_init_btext(void) +{ + /* If btext is enabled, we might have a BAT setup for early display, + * thus we do enable some very basic udbg output + */ + udbg_putc = btext_drawchar; +} diff --git a/arch/powerpc/kernel/cpu_setup_pa6t.S b/arch/powerpc/kernel/cpu_setup_pa6t.S new file mode 100644 index 0000000..4047be2 --- /dev/null +++ b/arch/powerpc/kernel/cpu_setup_pa6t.S @@ -0,0 +1,44 @@ +/* + * Copyright (C) 2006-2007 PA Semi, Inc + * + * Maintained by: Olof Johansson + * + * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +#include +#include +#include +#include +#include +#include + +/* Right now, restore and setup are the same thing */ +_GLOBAL(__restore_cpu_pa6t) +_GLOBAL(__setup_cpu_pa6t) + /* Do nothing if not running in HV mode */ + mfmsr r0 + rldicl. r0,r0,4,63 + beqlr + + mfspr r0,SPRN_HID5 + ori r0,r0,0x30 + mtspr SPRN_HID5,r0 + + mfspr r0,SPRN_LPCR + ori r0,r0,0x7000 + mtspr SPRN_LPCR,r0 + + blr diff --git a/arch/powerpc/kernel/cputable.c b/arch/powerpc/kernel/cputable.c index b742013..7ec4ac7 100644 --- a/arch/powerpc/kernel/cputable.c +++ b/arch/powerpc/kernel/cputable.c @@ -43,6 +43,8 @@ #endif /* CONFIG_PPC32 */ #ifdef CONFIG_PPC64 extern void __setup_cpu_ppc970(unsigned long offset, struct cpu_spec* spec); extern void __setup_cpu_ppc970MP(unsigned long offset, struct cpu_spec* spec); +extern void __setup_cpu_pa6t(unsigned long offset, struct cpu_spec* spec); +extern void __restore_cpu_pa6t(void); extern void __restore_cpu_ppc970(void); #endif /* CONFIG_PPC64 */ @@ -86,6 +88,7 @@ #ifdef CONFIG_PPC64 .icache_bsize = 128, .dcache_bsize = 128, .num_pmcs = 8, + .pmc_type = PPC_PMC_IBM, .oprofile_cpu_type = "ppc64/power3", .oprofile_type = PPC_OPROFILE_RS64, .platform = "power3", @@ -99,6 +102,7 @@ #ifdef CONFIG_PPC64 .icache_bsize = 128, .dcache_bsize = 128, .num_pmcs = 8, + .pmc_type = PPC_PMC_IBM, .oprofile_cpu_type = "ppc64/power3", .oprofile_type = PPC_OPROFILE_RS64, .platform = "power3", @@ -112,6 +116,7 @@ #ifdef CONFIG_PPC64 .icache_bsize = 128, .dcache_bsize = 128, .num_pmcs = 8, + .pmc_type = PPC_PMC_IBM, .oprofile_cpu_type = "ppc64/rs64", .oprofile_type = PPC_OPROFILE_RS64, .platform = "rs64", @@ -125,6 +130,7 @@ #ifdef CONFIG_PPC64 .icache_bsize = 128, .dcache_bsize = 128, .num_pmcs = 8, + .pmc_type = PPC_PMC_IBM, .oprofile_cpu_type = "ppc64/rs64", .oprofile_type = PPC_OPROFILE_RS64, .platform = "rs64", @@ -138,6 +144,7 @@ #ifdef CONFIG_PPC64 .icache_bsize = 128, .dcache_bsize = 128, .num_pmcs = 8, + .pmc_type = PPC_PMC_IBM, .oprofile_cpu_type = "ppc64/rs64", .oprofile_type = PPC_OPROFILE_RS64, .platform = "rs64", @@ -151,6 +158,7 @@ #ifdef CONFIG_PPC64 .icache_bsize = 128, .dcache_bsize = 128, .num_pmcs = 8, + .pmc_type = PPC_PMC_IBM, .oprofile_cpu_type = "ppc64/rs64", .oprofile_type = PPC_OPROFILE_RS64, .platform = "rs64", @@ -164,6 +172,7 @@ #ifdef CONFIG_PPC64 .icache_bsize = 128, .dcache_bsize = 128, .num_pmcs = 8, + .pmc_type = PPC_PMC_IBM, .oprofile_cpu_type = "ppc64/power4", .oprofile_type = PPC_OPROFILE_POWER4, .platform = "power4", @@ -177,6 +186,7 @@ #ifdef CONFIG_PPC64 .icache_bsize = 128, .dcache_bsize = 128, .num_pmcs = 8, + .pmc_type = PPC_PMC_IBM, .oprofile_cpu_type = "ppc64/power4", .oprofile_type = PPC_OPROFILE_POWER4, .platform = "power4", @@ -191,6 +201,7 @@ #ifdef CONFIG_PPC64 .icache_bsize = 128, .dcache_bsize = 128, .num_pmcs = 8, + .pmc_type = PPC_PMC_IBM, .cpu_setup = __setup_cpu_ppc970, .cpu_restore = __restore_cpu_ppc970, .oprofile_cpu_type = "ppc64/970", @@ -207,6 +218,7 @@ #ifdef CONFIG_PPC64 .icache_bsize = 128, .dcache_bsize = 128, .num_pmcs = 8, + .pmc_type = PPC_PMC_IBM, .cpu_setup = __setup_cpu_ppc970, .cpu_restore = __restore_cpu_ppc970, .oprofile_cpu_type = "ppc64/970", @@ -239,6 +251,7 @@ #ifdef CONFIG_PPC64 .icache_bsize = 128, .dcache_bsize = 128, .num_pmcs = 8, + .pmc_type = PPC_PMC_IBM, .cpu_setup = __setup_cpu_ppc970, .oprofile_cpu_type = "ppc64/970", .oprofile_type = PPC_OPROFILE_POWER4, @@ -253,6 +266,7 @@ #ifdef CONFIG_PPC64 .icache_bsize = 128, .dcache_bsize = 128, .num_pmcs = 6, + .pmc_type = PPC_PMC_IBM, .oprofile_cpu_type = "ppc64/power5", .oprofile_type = PPC_OPROFILE_POWER4, /* SIHV / SIPR bits are implemented on POWER4+ (GQ) @@ -271,6 +285,7 @@ #ifdef CONFIG_PPC64 .icache_bsize = 128, .dcache_bsize = 128, .num_pmcs = 6, + .pmc_type = PPC_PMC_IBM, .oprofile_cpu_type = "ppc64/power5+", .oprofile_type = PPC_OPROFILE_POWER4, .oprofile_mmcra_sihv = MMCRA_SIHV, @@ -321,6 +336,7 @@ #ifdef CONFIG_PPC64 .icache_bsize = 128, .dcache_bsize = 128, .num_pmcs = 6, + .pmc_type = PPC_PMC_IBM, .oprofile_cpu_type = "ppc64/power6", .oprofile_type = PPC_OPROFILE_POWER4, .oprofile_mmcra_sihv = POWER6_MMCRA_SIHV, @@ -340,6 +356,7 @@ #ifdef CONFIG_PPC64 .icache_bsize = 128, .dcache_bsize = 128, .num_pmcs = 4, + .pmc_type = PPC_PMC_IBM, .oprofile_cpu_type = "ppc64/cell-be", .oprofile_type = PPC_OPROFILE_CELL, .platform = "ppc-cell-be", @@ -353,6 +370,9 @@ #ifdef CONFIG_PPC64 .icache_bsize = 64, .dcache_bsize = 64, .num_pmcs = 6, + .pmc_type = PPC_PMC_PA6T, + .cpu_setup = __setup_cpu_pa6t, + .cpu_restore = __restore_cpu_pa6t, .platform = "pa6t", }, { /* default match */ @@ -364,6 +384,7 @@ #ifdef CONFIG_PPC64 .icache_bsize = 128, .dcache_bsize = 128, .num_pmcs = 6, + .pmc_type = PPC_PMC_IBM, .platform = "power4", } #endif /* CONFIG_PPC64 */ diff --git a/arch/powerpc/kernel/entry_64.S b/arch/powerpc/kernel/entry_64.S index 2551c08..2b66d53 100644 --- a/arch/powerpc/kernel/entry_64.S +++ b/arch/powerpc/kernel/entry_64.S @@ -172,13 +172,18 @@ syscall_error_cont: stdcx. r0,0,r1 /* to clear the reservation */ andi. r6,r8,MSR_PR ld r4,_LINK(r1) + /* + * Clear RI before restoring r13. If we are returning to + * userspace and we take an exception after restoring r13, + * we end up corrupting the userspace r13 value. + */ + li r12,MSR_RI + andc r11,r10,r12 + mtmsrd r11,1 /* clear MSR.RI */ beq- 1f ACCOUNT_CPU_USER_EXIT(r11, r12) ld r13,GPR13(r1) /* only restore r13 if returning to usermode */ 1: ld r2,GPR2(r1) - li r12,MSR_RI - andc r11,r10,r12 - mtmsrd r11,1 /* clear MSR.RI */ ld r1,GPR1(r1) mtlr r4 mtcr r5 @@ -488,42 +493,44 @@ END_FW_FTR_SECTION_IFSET(FW_FEATURE_ISER #endif stb r5,PACASOFTIRQEN(r13) + /* extract EE bit and use it to restore paca->hard_enabled */ ld r3,_MSR(r1) + rldicl r4,r3,49,63 /* r0 = (r3 >> 15) & 1 */ + stb r4,PACAHARDIRQEN(r13) + + ld r4,_CTR(r1) + ld r0,_LINK(r1) + mtctr r4 + mtlr r0 + ld r4,_XER(r1) + mtspr SPRN_XER,r4 + + REST_8GPRS(5, r1) + andi. r0,r3,MSR_RI beq- unrecov_restore - /* extract EE bit and use it to restore paca->hard_enabled */ - rldicl r4,r3,49,63 /* r0 = (r3 >> 15) & 1 */ - stb r4,PACAHARDIRQEN(r13) + stdcx. r0,0,r1 /* to clear the reservation */ - andi. r0,r3,MSR_PR + /* + * Clear RI before restoring r13. If we are returning to + * userspace and we take an exception after restoring r13, + * we end up corrupting the userspace r13 value. + */ + mfmsr r4 + andc r4,r4,r0 /* r0 contains MSR_RI here */ + mtmsrd r4,1 /* * r13 is our per cpu area, only restore it if we are returning to * userspace */ + andi. r0,r3,MSR_PR beq 1f - ACCOUNT_CPU_USER_EXIT(r3, r4) + ACCOUNT_CPU_USER_EXIT(r2, r4) REST_GPR(13, r1) 1: - ld r3,_CTR(r1) - ld r0,_LINK(r1) - mtctr r3 - mtlr r0 - ld r3,_XER(r1) - mtspr SPRN_XER,r3 - - REST_8GPRS(5, r1) - - stdcx. r0,0,r1 /* to clear the reservation */ - - mfmsr r0 - li r2, MSR_RI - andc r0,r0,r2 - mtmsrd r0,1 - - ld r0,_MSR(r1) - mtspr SPRN_SRR1,r0 + mtspr SPRN_SRR1,r3 ld r2,_CCR(r1) mtcrf 0xFF,r2 diff --git a/arch/powerpc/kernel/head_32.S b/arch/powerpc/kernel/head_32.S index 9417cf5..c897203 100644 --- a/arch/powerpc/kernel/head_32.S +++ b/arch/powerpc/kernel/head_32.S @@ -344,12 +344,7 @@ #define EXC_XFER_EE_LITE(n, hdlr) \ /* System reset */ /* core99 pmac starts the seconary here by changing the vector, and putting it back to what it was (unknown_exception) when done. */ -#if defined(CONFIG_GEMINI) && defined(CONFIG_SMP) - . = 0x100 - b __secondary_start_gemini -#else EXCEPTION(0x100, Reset, unknown_exception, EXC_XFER_STD) -#endif /* Machine check */ /* diff --git a/arch/powerpc/kernel/head_44x.S b/arch/powerpc/kernel/head_44x.S index accb39d..a15d4b8 100644 --- a/arch/powerpc/kernel/head_44x.S +++ b/arch/powerpc/kernel/head_44x.S @@ -32,8 +32,6 @@ #include #include #include #include -#include -#include #include #include #include diff --git a/arch/powerpc/kernel/head_64.S b/arch/powerpc/kernel/head_64.S index 71b1fe5..97cedcd 100644 --- a/arch/powerpc/kernel/head_64.S +++ b/arch/powerpc/kernel/head_64.S @@ -613,7 +613,7 @@ #endif /* CONFIG_CBE_RAS */ /*** pSeries interrupt support ***/ /* moved from 0xf00 */ - MASKABLE_EXCEPTION_PSERIES(., performance_monitor) + STD_EXCEPTION_PSERIES(., performance_monitor) /* * An interrupt came in while soft-disabled; clear EE in SRR1, diff --git a/arch/powerpc/kernel/head_fsl_booke.S b/arch/powerpc/kernel/head_fsl_booke.S index 66877bd..1f155d3 100644 --- a/arch/powerpc/kernel/head_fsl_booke.S +++ b/arch/powerpc/kernel/head_fsl_booke.S @@ -206,7 +206,8 @@ #endif rlwimi r7,r3,16,4,15 /* Setup MAS0 = TLBSEL | ESEL(r3) */ mtspr SPRN_MAS0,r7 tlbre - li r6,0 + mfspr r6,SPRN_MAS1 + rlwinm r6,r6,0,2,0 /* clear IPROT */ mtspr SPRN_MAS1,r6 tlbwe /* Invalidate TLB1 */ @@ -248,6 +249,8 @@ #endif rlwimi r7,r5,16,4,15 /* Setup MAS0 = TLBSEL | ESEL(r5) */ mtspr SPRN_MAS0,r7 tlbre + mfspr r8,SPRN_MAS1 + rlwinm r8,r8,0,2,0 /* clear IPROT */ mtspr SPRN_MAS1,r8 tlbwe /* Invalidate TLB1 */ @@ -889,7 +892,6 @@ #endif /* CONFIG_SMP */ REST_GPR(9, r11) REST_GPR(12, r11) lwz r11,GPR11(r11) - SYNC rfi /* @@ -953,7 +955,6 @@ #ifdef CONFIG_SPE _GLOBAL(giveup_spe) mfmsr r5 oris r5,r5,MSR_SPE@h - SYNC mtmsr r5 /* enable use of SPE now */ isync cmpi 0,r3,0 diff --git a/arch/powerpc/kernel/idle.c b/arch/powerpc/kernel/idle.c index 8994af3..6e7f509 100644 --- a/arch/powerpc/kernel/idle.c +++ b/arch/powerpc/kernel/idle.c @@ -110,17 +110,22 @@ static ctl_table powersave_nap_ctl_table .mode = 0644, .proc_handler = &proc_dointvec, }, - { 0, }, + {} }; static ctl_table powersave_nap_sysctl_root[] = { - { 1, "kernel", NULL, 0, 0755, powersave_nap_ctl_table, }, - { 0,}, + { + .ctl_name = CTL_KERN, + .procname = "kernel", + .mode = 0755, + .child = powersave_nap_ctl_table, + }, + {} }; static int __init register_powersave_nap_sysctl(void) { - register_sysctl_table(powersave_nap_sysctl_root, 0); + register_sysctl_table(powersave_nap_sysctl_root); return 0; } diff --git a/arch/powerpc/kernel/iomap.c b/arch/powerpc/kernel/iomap.c index c681133..601ef79 100644 --- a/arch/powerpc/kernel/iomap.c +++ b/arch/powerpc/kernel/iomap.c @@ -12,23 +12,23 @@ #include * Here comes the ppc64 implementation of the IOMAP * interfaces. */ -unsigned int fastcall ioread8(void __iomem *addr) +unsigned int ioread8(void __iomem *addr) { return readb(addr); } -unsigned int fastcall ioread16(void __iomem *addr) +unsigned int ioread16(void __iomem *addr) { return readw(addr); } -unsigned int fastcall ioread16be(void __iomem *addr) +unsigned int ioread16be(void __iomem *addr) { return in_be16(addr); } -unsigned int fastcall ioread32(void __iomem *addr) +unsigned int ioread32(void __iomem *addr) { return readl(addr); } -unsigned int fastcall ioread32be(void __iomem *addr) +unsigned int ioread32be(void __iomem *addr) { return in_be32(addr); } @@ -38,23 +38,23 @@ EXPORT_SYMBOL(ioread16be); EXPORT_SYMBOL(ioread32); EXPORT_SYMBOL(ioread32be); -void fastcall iowrite8(u8 val, void __iomem *addr) +void iowrite8(u8 val, void __iomem *addr) { writeb(val, addr); } -void fastcall iowrite16(u16 val, void __iomem *addr) +void iowrite16(u16 val, void __iomem *addr) { writew(val, addr); } -void fastcall iowrite16be(u16 val, void __iomem *addr) +void iowrite16be(u16 val, void __iomem *addr) { out_be16(addr, val); } -void fastcall iowrite32(u32 val, void __iomem *addr) +void iowrite32(u32 val, void __iomem *addr) { writel(val, addr); } -void fastcall iowrite32be(u32 val, void __iomem *addr) +void iowrite32be(u32 val, void __iomem *addr) { out_be32(addr, val); } diff --git a/arch/powerpc/kernel/irq.c b/arch/powerpc/kernel/irq.c index 0bd8c76..919fbf5 100644 --- a/arch/powerpc/kernel/irq.c +++ b/arch/powerpc/kernel/irq.c @@ -281,10 +281,10 @@ #endif /* * Every platform is required to implement ppc_md.get_irq. - * This function will either return an irq number or -1 to + * This function will either return an irq number or NO_IRQ to * indicate there are no more pending. - * The value -2 is for buggy hardware and means that this IRQ - * has already been handled. -- Tom + * The value NO_IRQ_IGNORE is for buggy hardware and means that this + * IRQ has already been handled. -- Tom */ irq = ppc_md.get_irq(); @@ -604,6 +604,8 @@ unsigned int irq_create_mapping(struct i */ virq = irq_find_mapping(host, hwirq); if (virq != IRQ_NONE) { + if (host->ops->remap) + host->ops->remap(host, virq, hwirq); pr_debug("irq: -> existing mapping on virq %d\n", virq); return virq; } diff --git a/arch/powerpc/kernel/kprobes.c b/arch/powerpc/kernel/kprobes.c index 4657563..dd2886f 100644 --- a/arch/powerpc/kernel/kprobes.c +++ b/arch/powerpc/kernel/kprobes.c @@ -46,8 +46,8 @@ int __kprobes arch_prepare_kprobe(struct if ((unsigned long)p->addr & 0x03) { printk("Attempt to register kprobe at an unaligned address\n"); ret = -EINVAL; - } else if (IS_MTMSRD(insn) || IS_RFID(insn)) { - printk("Cannot register a kprobe on rfid or mtmsrd\n"); + } else if (IS_MTMSRD(insn) || IS_RFID(insn) || IS_RFI(insn)) { + printk("Cannot register a kprobe on rfi/rfid or mtmsr[d]\n"); ret = -EINVAL; } @@ -483,8 +483,12 @@ int __kprobes setjmp_pre_handler(struct memcpy(&kcb->jprobe_saved_regs, regs, sizeof(struct pt_regs)); /* setup return addr to the jprobe handler routine */ +#ifdef CONFIG_PPC64 regs->nip = (unsigned long)(((func_descr_t *)jp->entry)->entry); regs->gpr[2] = (unsigned long)(((func_descr_t *)jp->entry)->toc); +#else + regs->nip = (unsigned long)jp->entry; +#endif return 1; } diff --git a/arch/powerpc/kernel/legacy_serial.c b/arch/powerpc/kernel/legacy_serial.c index 5e6ddfa..325f490 100644 --- a/arch/powerpc/kernel/legacy_serial.c +++ b/arch/powerpc/kernel/legacy_serial.c @@ -124,6 +124,10 @@ static int __init add_legacy_soc_port(st if (get_property(np, "clock-frequency", NULL) == NULL) return -1; + /* if rtas uses this device, don't try to use it as well */ + if (get_property(np, "used-by-rtas", NULL) != NULL) + return -1; + /* Get the address */ addrp = of_get_address(soc_dev, 0, NULL, NULL); if (addrp == NULL) @@ -334,6 +338,17 @@ void __init find_legacy_serial_ports(voi of_node_put(tsi); } + /* First fill our array with opb bus ports */ + for (np = NULL; (np = of_find_compatible_node(np, "serial", "ns16750")) != NULL;) { + struct device_node *opb = of_get_parent(np); + if (opb && !strcmp(opb->type, "opb")) { + index = add_legacy_soc_port(np, np); + if (index >= 0 && np == stdout) + legacy_serial_console = index; + } + of_node_put(opb); + } + #ifdef CONFIG_PCI /* Next, try to locate PCI ports */ for (np = NULL; (np = of_find_all_nodes(np));) { @@ -498,7 +513,7 @@ static int __init check_legacy_serial_co DBG(" -> check_legacy_serial_console()\n"); /* The user has requested a console so this is already set up. */ - if (strstr(saved_command_line, "console=")) { + if (strstr(boot_command_line, "console=")) { DBG(" console was specified !\n"); return -EBUSY; } diff --git a/arch/powerpc/kernel/lparcfg.c b/arch/powerpc/kernel/lparcfg.c index 41c05dc..89486b6 100644 --- a/arch/powerpc/kernel/lparcfg.c +++ b/arch/powerpc/kernel/lparcfg.c @@ -439,6 +439,10 @@ static ssize_t lparcfg_write(struct file ssize_t retval = -ENOMEM; + if (!firmware_has_feature(FW_FEATURE_SPLPAR) || + firmware_has_feature(FW_FEATURE_ISERIES)) + return -EINVAL; + kbuf = kmalloc(count, GFP_KERNEL); if (!kbuf) goto out; @@ -517,7 +521,7 @@ static int pseries_lparcfg_data(struct s static ssize_t lparcfg_write(struct file *file, const char __user * buf, size_t count, loff_t * off) { - return count; + return -EINVAL; } #endif /* CONFIG_PPC_PSERIES */ @@ -567,9 +571,10 @@ static int lparcfg_open(struct inode *in return single_open(file, lparcfg_data, NULL); } -struct file_operations lparcfg_fops = { +const struct file_operations lparcfg_fops = { .owner = THIS_MODULE, .read = seq_read, + .write = lparcfg_write, .open = lparcfg_open, .release = single_release, }; @@ -581,10 +586,8 @@ int __init lparcfg_init(void) /* Allow writing if we have FW_FEATURE_SPLPAR */ if (firmware_has_feature(FW_FEATURE_SPLPAR) && - !firmware_has_feature(FW_FEATURE_ISERIES)) { - lparcfg_fops.write = lparcfg_write; + !firmware_has_feature(FW_FEATURE_ISERIES)) mode |= S_IWUSR; - } ent = create_proc_entry("ppc64/lparcfg", mode, NULL); if (ent) { diff --git a/arch/powerpc/kernel/misc_64.S b/arch/powerpc/kernel/misc_64.S index 21fd2c6..519861d 100644 --- a/arch/powerpc/kernel/misc_64.S +++ b/arch/powerpc/kernel/misc_64.S @@ -311,6 +311,46 @@ _GLOBAL(real_writeb) blr #endif /* defined(CONFIG_PPC_PMAC) || defined(CONFIG_PPC_MAPLE) */ +#ifdef CONFIG_PPC_PASEMI + +/* No support in all binutils for these yet, so use defines */ +#define LBZCIX(RT,RA,RB) .long (0x7c0006aa|(RT<<21)|(RA<<16)|(RB << 11)) +#define STBCIX(RS,RA,RB) .long (0x7c0007aa|(RS<<21)|(RA<<16)|(RB << 11)) + + +_GLOBAL(real_205_readb) + mfmsr r7 + ori r0,r7,MSR_DR + xori r0,r0,MSR_DR + sync + mtmsrd r0 + sync + isync + LBZCIX(r3,0,r3) + isync + mtmsrd r7 + sync + isync + blr + +_GLOBAL(real_205_writeb) + mfmsr r7 + ori r0,r7,MSR_DR + xori r0,r0,MSR_DR + sync + mtmsrd r0 + sync + isync + STBCIX(r3,0,r4) + isync + mtmsrd r7 + sync + isync + blr + +#endif /* CONFIG_PPC_PASEMI */ + + #ifdef CONFIG_CPU_FREQ_PMAC64 /* * SCOM access functions for 970 (FX only for now) diff --git a/arch/powerpc/kernel/module_32.c b/arch/powerpc/kernel/module_32.c index 8339fd6..07a89a3 100644 --- a/arch/powerpc/kernel/module_32.c +++ b/arch/powerpc/kernel/module_32.c @@ -224,7 +224,12 @@ int apply_relocate_add(Elf32_Shdr *sechd /* Low half of the symbol */ *(uint16_t *)location = value; break; - + + case R_PPC_ADDR16_HI: + /* Higher half of the symbol */ + *(uint16_t *)location = (value >> 16); + break; + case R_PPC_ADDR16_HA: /* Sign-adjusted lower 16 bits: PPC ELF ABI says: (((x >> 16) + ((x & 0x8000) ? 1 : 0))) & 0xFFFF. diff --git a/arch/powerpc/kernel/nvram_64.c b/arch/powerpc/kernel/nvram_64.c index 869cebb..f9676f5 100644 --- a/arch/powerpc/kernel/nvram_64.c +++ b/arch/powerpc/kernel/nvram_64.c @@ -179,7 +179,7 @@ #endif /* CONFIG_PPC_PMAC */ } } -struct file_operations nvram_fops = { +const struct file_operations nvram_fops = { .owner = THIS_MODULE, .llseek = dev_nvram_llseek, .read = dev_nvram_read, diff --git a/arch/powerpc/kernel/pci_32.c b/arch/powerpc/kernel/pci_32.c index c54f363..d8ef2e1 100644 --- a/arch/powerpc/kernel/pci_32.c +++ b/arch/powerpc/kernel/pci_32.c @@ -1450,7 +1450,6 @@ int pci_read_irq_line(struct pci_dev *pc return -1; } pci_dev->irq = virq; - pci_write_config_byte(pci_dev, PCI_INTERRUPT_LINE, virq); return 0; } diff --git a/arch/powerpc/kernel/pci_64.c b/arch/powerpc/kernel/pci_64.c index 01f18c6..7e97d71 100644 --- a/arch/powerpc/kernel/pci_64.c +++ b/arch/powerpc/kernel/pci_64.c @@ -381,8 +381,6 @@ struct pci_dev *of_create_pci_dev(struct pci_device_add(dev, bus); - /* XXX pci_scan_msi_device(dev); */ - return dev; } EXPORT_SYMBOL(of_create_pci_dev); @@ -1325,7 +1323,6 @@ #endif DBG(" -> mapped to linux irq %d\n", virq); pci_dev->irq = virq; - pci_write_config_byte(pci_dev, PCI_INTERRUPT_LINE, virq); return 0; } diff --git a/arch/powerpc/kernel/pmc.c b/arch/powerpc/kernel/pmc.c index 3d8f6f4..24d7b7c 100644 --- a/arch/powerpc/kernel/pmc.c +++ b/arch/powerpc/kernel/pmc.c @@ -17,40 +17,25 @@ #include #include #include +#include #include -#if defined(CONFIG_FSL_BOOKE) && !defined(CONFIG_E200) -static void dummy_perf(struct pt_regs *regs) -{ - unsigned int pmgc0 = mfpmr(PMRN_PMGC0); - - pmgc0 &= ~PMGC0_PMIE; - mtpmr(PMRN_PMGC0, pmgc0); -} -#elif defined(CONFIG_PPC64) || defined(CONFIG_6xx) - -#ifndef MMCR0_PMAO -#define MMCR0_PMAO 0 +#ifndef MMCR0_PMA0 +#define MMCR0_PMA0 0 #endif -/* Ensure exceptions are disabled */ static void dummy_perf(struct pt_regs *regs) { - unsigned int mmcr0 = mfspr(SPRN_MMCR0); - - mmcr0 &= ~(MMCR0_PMXE|MMCR0_PMAO); - mtspr(SPRN_MMCR0, mmcr0); -} +#if defined(CONFIG_FSL_BOOKE) && !defined(CONFIG_E200) + mtpmr(PMRN_PMGC0, mfpmr(PMRN_PMGC0) & ~PMGC0_PMIE); +#elif defined(CONFIG_PPC64) || defined(CONFIG_6xx) + if (cur_cpu_spec->pmc_type == PPC_PMC_IBM) + mtspr(SPRN_MMCR0, mfspr(SPRN_MMCR0) & ~(MMCR0_PMXE|MMCR0_PMA0)); #else -/* Ensure exceptions are disabled */ -static void dummy_perf(struct pt_regs *regs) -{ - unsigned int mmcr0 = mfspr(SPRN_MMCR0); - - mmcr0 &= ~(MMCR0_PMXE); - mtspr(SPRN_MMCR0, mmcr0); -} + mtspr(SPRN_MMCR0, mfspr(SPRN_MMCR0) & ~MMCR0_PMXE); #endif +} + static DEFINE_SPINLOCK(pmc_owner_lock); static void *pmc_owner_caller; /* mostly for debugging */ diff --git a/arch/powerpc/kernel/ppc_ksyms.c b/arch/powerpc/kernel/ppc_ksyms.c index 95776b6..ecee596 100644 --- a/arch/powerpc/kernel/ppc_ksyms.c +++ b/arch/powerpc/kernel/ppc_ksyms.c @@ -44,6 +44,7 @@ #include #include #include #include +#include #ifdef CONFIG_8xx #include diff --git a/arch/powerpc/kernel/proc_ppc64.c b/arch/powerpc/kernel/proc_ppc64.c index dd7001c..f78dfce 100644 --- a/arch/powerpc/kernel/proc_ppc64.c +++ b/arch/powerpc/kernel/proc_ppc64.c @@ -33,7 +33,7 @@ static ssize_t page_map_read( struct fil loff_t *ppos); static int page_map_mmap( struct file *file, struct vm_area_struct *vma ); -static struct file_operations page_map_fops = { +static const struct file_operations page_map_fops = { .llseek = page_map_seek, .read = page_map_read, .mmap = page_map_mmap @@ -71,7 +71,6 @@ static int __init proc_ppc64_init(void) pde = create_proc_entry("ppc64/systemcfg", S_IFREG|S_IRUGO, NULL); if (!pde) return 1; - pde->nlink = 1; pde->data = vdso_data; pde->size = PAGE_SIZE; pde->proc_fops = &page_map_fops; diff --git a/arch/powerpc/kernel/prom.c b/arch/powerpc/kernel/prom.c index 1fc732a..3e86e6e 100644 --- a/arch/powerpc/kernel/prom.c +++ b/arch/powerpc/kernel/prom.c @@ -991,7 +991,7 @@ #endif of_scan_flat_dt(early_init_dt_scan_memory, NULL); /* Save command line for /proc/cmdline and then parse parameters */ - strlcpy(saved_command_line, cmd_line, COMMAND_LINE_SIZE); + strlcpy(boot_command_line, cmd_line, COMMAND_LINE_SIZE); parse_early_param(); /* Reserve LMB regions used by kernel, initrd, dt, etc... */ @@ -1221,8 +1221,7 @@ struct device_node *of_find_node_by_name if (np->name != NULL && strcasecmp(np->name, name) == 0 && of_node_get(np)) break; - if (from) - of_node_put(from); + of_node_put(from); read_unlock(&devtree_lock); return np; } @@ -1250,8 +1249,7 @@ struct device_node *of_find_node_by_type if (np->type != 0 && strcasecmp(np->type, type) == 0 && of_node_get(np)) break; - if (from) - of_node_put(from); + of_node_put(from); read_unlock(&devtree_lock); return np; } @@ -1285,8 +1283,7 @@ struct device_node *of_find_compatible_n if (device_is_compatible(np, compatible) && of_node_get(np)) break; } - if (from) - of_node_put(from); + of_node_put(from); read_unlock(&devtree_lock); return np; } @@ -1329,8 +1326,7 @@ struct device_node *of_find_node_by_phan for (np = allnodes; np != 0; np = np->allnext) if (np->linux_phandle == handle) break; - if (np) - of_node_get(np); + of_node_get(np); read_unlock(&devtree_lock); return np; } @@ -1353,8 +1349,7 @@ struct device_node *of_find_all_nodes(st for (; np != 0; np = np->allnext) if (of_node_get(np)) break; - if (prev) - of_node_put(prev); + of_node_put(prev); read_unlock(&devtree_lock); return np; } @@ -1399,8 +1394,7 @@ struct device_node *of_get_next_child(co for (; next != 0; next = next->sibling) if (of_node_get(next)) break; - if (prev) - of_node_put(prev); + of_node_put(prev); read_unlock(&devtree_lock); return next; } diff --git a/arch/powerpc/kernel/prom_init.c b/arch/powerpc/kernel/prom_init.c index 520ef42..4fb5938 100644 --- a/arch/powerpc/kernel/prom_init.c +++ b/arch/powerpc/kernel/prom_init.c @@ -2117,11 +2117,92 @@ #else #define fixup_device_tree_pmac() #endif +#ifdef CONFIG_PPC_EFIKA +/* The current fw of the Efika has a device tree needs quite a few + * fixups to be compliant with the mpc52xx bindings. It's currently + * unknown if it will ever be compliant (come on bPlan ...) so we do fixups. + * NOTE that we (barely) tolerate it because the EFIKA was out before + * the bindings were finished, for any new boards -> RTFM ! */ + +struct subst_entry { + char *path; + char *property; + void *value; + int value_len; +}; + +static void __init fixup_device_tree_efika(void) +{ + /* Substitution table */ + #define prop_cstr(x) x, sizeof(x) + int prop_sound_irq[3] = { 2, 2, 0 }; + int prop_bcomm_irq[3*16] = { 3,0,0, 3,1,0, 3,2,0, 3,3,0, + 3,4,0, 3,5,0, 3,6,0, 3,7,0, + 3,8,0, 3,9,0, 3,10,0, 3,11,0, + 3,12,0, 3,13,0, 3,14,0, 3,15,0 }; + struct subst_entry efika_subst_table[] = { + { "/", "device_type", prop_cstr("efika") }, + { "/builtin", "compatible", prop_cstr("soc") }, + { "/builtin/ata", "compatible", prop_cstr("mpc5200b-ata\0mpc5200-ata"), }, + { "/builtin/bestcomm", "compatible", prop_cstr("mpc5200b-bestcomm\0mpc5200-bestcomm") }, + { "/builtin/bestcomm", "interrupts", prop_bcomm_irq, sizeof(prop_bcomm_irq) }, + { "/builtin/ethernet", "compatible", prop_cstr("mpc5200b-fec\0mpc5200-fec") }, + { "/builtin/pic", "compatible", prop_cstr("mpc5200b-pic\0mpc5200-pic") }, + { "/builtin/serial", "compatible", prop_cstr("mpc5200b-psc-uart\0mpc5200-psc-uart") }, + { "/builtin/sound", "compatible", prop_cstr("mpc5200b-psc-ac97\0mpc5200-psc-ac97") }, + { "/builtin/sound", "interrupts", prop_sound_irq, sizeof(prop_sound_irq) }, + { "/builtin/sram", "compatible", prop_cstr("mpc5200b-sram\0mpc5200-sram") }, + { "/builtin/sram", "device_type", prop_cstr("sram") }, + {} + }; + #undef prop_cstr + + /* Vars */ + u32 node; + char prop[64]; + int rv, i; + + /* Check if we're really running on a EFIKA */ + node = call_prom("finddevice", 1, 1, ADDR("/")); + if (!PHANDLE_VALID(node)) + return; + + rv = prom_getprop(node, "model", prop, sizeof(prop)); + if (rv == PROM_ERROR) + return; + if (strcmp(prop, "EFIKA5K2")) + return; + + prom_printf("Applying EFIKA device tree fixups\n"); + + /* Process substitution table */ + for (i=0; efika_subst_table[i].path; i++) { + struct subst_entry *se = &efika_subst_table[i]; + + node = call_prom("finddevice", 1, 1, ADDR(se->path)); + if (!PHANDLE_VALID(node)) { + prom_printf("fixup_device_tree_efika: ", + "skipped entry %x - not found\n", i); + continue; + } + + rv = prom_setprop(node, se->path, se->property, + se->value, se->value_len ); + if (rv == PROM_ERROR) + prom_printf("fixup_device_tree_efika: ", + "skipped entry %x - setprop error\n", i); + } +} +#else +#define fixup_device_tree_efika() +#endif + static void __init fixup_device_tree(void) { fixup_device_tree_maple(); fixup_device_tree_chrp(); fixup_device_tree_pmac(); + fixup_device_tree_efika(); } static void __init prom_find_boot_cpu(void) diff --git a/arch/powerpc/kernel/ptrace.c b/arch/powerpc/kernel/ptrace.c index 975102a..cc44c7b 100644 --- a/arch/powerpc/kernel/ptrace.c +++ b/arch/powerpc/kernel/ptrace.c @@ -532,16 +532,22 @@ void do_syscall_trace_enter(struct pt_re && (current->ptrace & PT_PTRACED)) do_syscall_trace(); - if (unlikely(current->audit_context)) - audit_syscall_entry( -#ifdef CONFIG_PPC32 - AUDIT_ARCH_PPC, -#else - test_thread_flag(TIF_32BIT)?AUDIT_ARCH_PPC:AUDIT_ARCH_PPC64, + if (unlikely(current->audit_context)) { +#ifdef CONFIG_PPC64 + if (!test_thread_flag(TIF_32BIT)) + audit_syscall_entry(AUDIT_ARCH_PPC64, + regs->gpr[0], + regs->gpr[3], regs->gpr[4], + regs->gpr[5], regs->gpr[6]); + else #endif - regs->gpr[0], - regs->gpr[3], regs->gpr[4], - regs->gpr[5], regs->gpr[6]); + audit_syscall_entry(AUDIT_ARCH_PPC, + regs->gpr[0], + regs->gpr[3] & 0xffffffff, + regs->gpr[4] & 0xffffffff, + regs->gpr[5] & 0xffffffff, + regs->gpr[6] & 0xffffffff); + } } void do_syscall_trace_leave(struct pt_regs *regs) diff --git a/arch/powerpc/kernel/rtas-proc.c b/arch/powerpc/kernel/rtas-proc.c index 2fe82ab..6cbf2ae 100644 --- a/arch/powerpc/kernel/rtas-proc.c +++ b/arch/powerpc/kernel/rtas-proc.c @@ -160,7 +160,7 @@ static int sensors_open(struct inode *in return single_open(file, ppc_rtas_sensors_show, NULL); } -struct file_operations ppc_rtas_sensors_operations = { +const struct file_operations ppc_rtas_sensors_operations = { .open = sensors_open, .read = seq_read, .llseek = seq_lseek, @@ -172,7 +172,7 @@ static int poweron_open(struct inode *in return single_open(file, ppc_rtas_poweron_show, NULL); } -struct file_operations ppc_rtas_poweron_operations = { +const struct file_operations ppc_rtas_poweron_operations = { .open = poweron_open, .read = seq_read, .llseek = seq_lseek, @@ -185,7 +185,7 @@ static int progress_open(struct inode *i return single_open(file, ppc_rtas_progress_show, NULL); } -struct file_operations ppc_rtas_progress_operations = { +const struct file_operations ppc_rtas_progress_operations = { .open = progress_open, .read = seq_read, .llseek = seq_lseek, @@ -198,7 +198,7 @@ static int clock_open(struct inode *inod return single_open(file, ppc_rtas_clock_show, NULL); } -struct file_operations ppc_rtas_clock_operations = { +const struct file_operations ppc_rtas_clock_operations = { .open = clock_open, .read = seq_read, .llseek = seq_lseek, @@ -211,7 +211,7 @@ static int tone_freq_open(struct inode * return single_open(file, ppc_rtas_tone_freq_show, NULL); } -struct file_operations ppc_rtas_tone_freq_operations = { +const struct file_operations ppc_rtas_tone_freq_operations = { .open = tone_freq_open, .read = seq_read, .llseek = seq_lseek, @@ -224,7 +224,7 @@ static int tone_volume_open(struct inode return single_open(file, ppc_rtas_tone_volume_show, NULL); } -struct file_operations ppc_rtas_tone_volume_operations = { +const struct file_operations ppc_rtas_tone_volume_operations = { .open = tone_volume_open, .read = seq_read, .llseek = seq_lseek, @@ -237,7 +237,7 @@ static int rmo_buf_open(struct inode *in return single_open(file, ppc_rtas_rmo_buf_show, NULL); } -struct file_operations ppc_rtas_rmo_buf_ops = { +const struct file_operations ppc_rtas_rmo_buf_ops = { .open = rmo_buf_open, .read = seq_read, .llseek = seq_lseek, diff --git a/arch/powerpc/kernel/rtas_flash.c b/arch/powerpc/kernel/rtas_flash.c index 0c4fcd3..f72118c 100644 --- a/arch/powerpc/kernel/rtas_flash.c +++ b/arch/powerpc/kernel/rtas_flash.c @@ -702,13 +702,12 @@ static int initialize_flash_pde_data(con } static struct proc_dir_entry *create_flash_pde(const char *filename, - struct file_operations *fops) + const struct file_operations *fops) { struct proc_dir_entry *ent = NULL; ent = create_proc_entry(filename, S_IRUSR | S_IWUSR, NULL); if (ent != NULL) { - ent->nlink = 1; ent->proc_fops = fops; ent->owner = THIS_MODULE; } @@ -716,21 +715,21 @@ static struct proc_dir_entry *create_fla return ent; } -static struct file_operations rtas_flash_operations = { +static const struct file_operations rtas_flash_operations = { .read = rtas_flash_read, .write = rtas_flash_write, .open = rtas_excl_open, .release = rtas_flash_release, }; -static struct file_operations manage_flash_operations = { +static const struct file_operations manage_flash_operations = { .read = manage_flash_read, .write = manage_flash_write, .open = rtas_excl_open, .release = rtas_excl_release, }; -static struct file_operations validate_flash_operations = { +static const struct file_operations validate_flash_operations = { .read = validate_flash_read, .write = validate_flash_write, .open = rtas_excl_open, diff --git a/arch/powerpc/kernel/setup_32.c b/arch/powerpc/kernel/setup_32.c index 61c65d1..44a6a3c 100644 --- a/arch/powerpc/kernel/setup_32.c +++ b/arch/powerpc/kernel/setup_32.c @@ -65,6 +65,7 @@ int have_of = 1; #ifdef CONFIG_VGA_CONSOLE unsigned long vgacon_remap_base; +EXPORT_SYMBOL(vgacon_remap_base); #endif /* @@ -115,12 +116,8 @@ unsigned long __init early_init(unsigned */ void __init machine_init(unsigned long dt_ptr, unsigned long phys) { - /* If btext is enabled, we might have a BAT setup for early display, - * thus we do enable some very basic udbg output - */ -#ifdef CONFIG_BOOTX_TEXT - udbg_putc = btext_drawchar; -#endif + /* Enable early debugging if any specified (see udbg.h) */ + udbg_early_init(); /* Do some early initialization based on the flat device tree */ early_init_devtree(__va(dt_ptr)); diff --git a/arch/powerpc/kernel/smp.c b/arch/powerpc/kernel/smp.c index 0e8beca..924d692 100644 --- a/arch/powerpc/kernel/smp.c +++ b/arch/powerpc/kernel/smp.c @@ -78,29 +78,6 @@ int smt_enabled_at_boot = 1; static void (*crash_ipi_function_ptr)(struct pt_regs *) = NULL; -#ifdef CONFIG_MPIC -int __init smp_mpic_probe(void) -{ - int nr_cpus; - - DBG("smp_mpic_probe()...\n"); - - nr_cpus = cpus_weight(cpu_possible_map); - - DBG("nr_cpus: %d\n", nr_cpus); - - if (nr_cpus > 1) - mpic_request_ipis(); - - return nr_cpus; -} - -void __devinit smp_mpic_setup_cpu(int cpu) -{ - mpic_setup_this_cpu(); -} -#endif /* CONFIG_MPIC */ - #ifdef CONFIG_PPC64 void __devinit smp_generic_kick_cpu(int nr) { diff --git a/arch/powerpc/kernel/sys_ppc32.c b/arch/powerpc/kernel/sys_ppc32.c index 03a2a2f..673e8d9 100644 --- a/arch/powerpc/kernel/sys_ppc32.c +++ b/arch/powerpc/kernel/sys_ppc32.c @@ -198,73 +198,6 @@ static inline long put_tv32(struct compa __put_user(i->tv_usec, &o->tv_usec))); } -struct sysinfo32 { - s32 uptime; - u32 loads[3]; - u32 totalram; - u32 freeram; - u32 sharedram; - u32 bufferram; - u32 totalswap; - u32 freeswap; - unsigned short procs; - unsigned short pad; - u32 totalhigh; - u32 freehigh; - u32 mem_unit; - char _f[20-2*sizeof(int)-sizeof(int)]; -}; - -asmlinkage long compat_sys_sysinfo(struct sysinfo32 __user *info) -{ - struct sysinfo s; - int ret, err; - int bitcount=0; - mm_segment_t old_fs = get_fs (); - - /* The __user cast is valid due to set_fs() */ - set_fs (KERNEL_DS); - ret = sys_sysinfo((struct sysinfo __user *)&s); - set_fs (old_fs); - - /* Check to see if any memory value is too large for 32-bit and - * scale down if needed. - */ - if ((s.totalram >> 32) || (s.totalswap >> 32)) { - while (s.mem_unit < PAGE_SIZE) { - s.mem_unit <<= 1; - bitcount++; - } - s.totalram >>=bitcount; - s.freeram >>= bitcount; - s.sharedram >>= bitcount; - s.bufferram >>= bitcount; - s.totalswap >>= bitcount; - s.freeswap >>= bitcount; - s.totalhigh >>= bitcount; - s.freehigh >>= bitcount; - } - - err = put_user (s.uptime, &info->uptime); - err |= __put_user (s.loads[0], &info->loads[0]); - err |= __put_user (s.loads[1], &info->loads[1]); - err |= __put_user (s.loads[2], &info->loads[2]); - err |= __put_user (s.totalram, &info->totalram); - err |= __put_user (s.freeram, &info->freeram); - err |= __put_user (s.sharedram, &info->sharedram); - err |= __put_user (s.bufferram, &info->bufferram); - err |= __put_user (s.totalswap, &info->totalswap); - err |= __put_user (s.freeswap, &info->freeswap); - err |= __put_user (s.procs, &info->procs); - err |= __put_user (s.totalhigh, &info->totalhigh); - err |= __put_user (s.freehigh, &info->freehigh); - err |= __put_user (s.mem_unit, &info->mem_unit); - if (err) - return -EFAULT; - - return ret; -} - diff --git a/arch/powerpc/kernel/sysfs.c b/arch/powerpc/kernel/sysfs.c index 400ab2b..d57818a 100644 --- a/arch/powerpc/kernel/sysfs.c +++ b/arch/powerpc/kernel/sysfs.c @@ -169,6 +169,11 @@ static ssize_t __attribute_used__ \ return count; \ } + +/* Let's define all possible registers, we'll only hook up the ones + * that are implemented on the current processor + */ + SYSFS_PMCSETUP(mmcr0, SPRN_MMCR0); SYSFS_PMCSETUP(mmcr1, SPRN_MMCR1); SYSFS_PMCSETUP(mmcra, SPRN_MMCRA); @@ -184,55 +189,87 @@ SYSFS_PMCSETUP(purr, SPRN_PURR); SYSFS_PMCSETUP(spurr, SPRN_SPURR); SYSFS_PMCSETUP(dscr, SPRN_DSCR); -static SYSDEV_ATTR(mmcr0, 0600, show_mmcr0, store_mmcr0); -static SYSDEV_ATTR(mmcr1, 0600, show_mmcr1, store_mmcr1); +SYSFS_PMCSETUP(pa6t_pmc0, PA6T_SPRN_PMC0); +SYSFS_PMCSETUP(pa6t_pmc1, PA6T_SPRN_PMC1); +SYSFS_PMCSETUP(pa6t_pmc2, PA6T_SPRN_PMC2); +SYSFS_PMCSETUP(pa6t_pmc3, PA6T_SPRN_PMC3); +SYSFS_PMCSETUP(pa6t_pmc4, PA6T_SPRN_PMC4); +SYSFS_PMCSETUP(pa6t_pmc5, PA6T_SPRN_PMC5); + + static SYSDEV_ATTR(mmcra, 0600, show_mmcra, store_mmcra); -static SYSDEV_ATTR(pmc1, 0600, show_pmc1, store_pmc1); -static SYSDEV_ATTR(pmc2, 0600, show_pmc2, store_pmc2); -static SYSDEV_ATTR(pmc3, 0600, show_pmc3, store_pmc3); -static SYSDEV_ATTR(pmc4, 0600, show_pmc4, store_pmc4); -static SYSDEV_ATTR(pmc5, 0600, show_pmc5, store_pmc5); -static SYSDEV_ATTR(pmc6, 0600, show_pmc6, store_pmc6); -static SYSDEV_ATTR(pmc7, 0600, show_pmc7, store_pmc7); -static SYSDEV_ATTR(pmc8, 0600, show_pmc8, store_pmc8); -static SYSDEV_ATTR(purr, 0600, show_purr, NULL); static SYSDEV_ATTR(spurr, 0600, show_spurr, NULL); static SYSDEV_ATTR(dscr, 0600, show_dscr, store_dscr); +static SYSDEV_ATTR(purr, 0600, show_purr, store_purr); + +static struct sysdev_attribute ibm_common_attrs[] = { + _SYSDEV_ATTR(mmcr0, 0600, show_mmcr0, store_mmcr0), + _SYSDEV_ATTR(mmcr1, 0600, show_mmcr1, store_mmcr1), +}; + +static struct sysdev_attribute ibm_pmc_attrs[] = { + _SYSDEV_ATTR(pmc1, 0600, show_pmc1, store_pmc1), + _SYSDEV_ATTR(pmc2, 0600, show_pmc2, store_pmc2), + _SYSDEV_ATTR(pmc3, 0600, show_pmc3, store_pmc3), + _SYSDEV_ATTR(pmc4, 0600, show_pmc4, store_pmc4), + _SYSDEV_ATTR(pmc5, 0600, show_pmc5, store_pmc5), + _SYSDEV_ATTR(pmc6, 0600, show_pmc6, store_pmc6), + _SYSDEV_ATTR(pmc7, 0600, show_pmc7, store_pmc7), + _SYSDEV_ATTR(pmc8, 0600, show_pmc8, store_pmc8), +}; + +static struct sysdev_attribute pa6t_attrs[] = { + _SYSDEV_ATTR(mmcr0, 0600, show_mmcr0, store_mmcr0), + _SYSDEV_ATTR(mmcr1, 0600, show_mmcr1, store_mmcr1), + _SYSDEV_ATTR(pmc0, 0600, show_pa6t_pmc0, store_pa6t_pmc0), + _SYSDEV_ATTR(pmc1, 0600, show_pa6t_pmc1, store_pa6t_pmc1), + _SYSDEV_ATTR(pmc2, 0600, show_pa6t_pmc2, store_pa6t_pmc2), + _SYSDEV_ATTR(pmc3, 0600, show_pa6t_pmc3, store_pa6t_pmc3), + _SYSDEV_ATTR(pmc4, 0600, show_pa6t_pmc4, store_pa6t_pmc4), + _SYSDEV_ATTR(pmc5, 0600, show_pa6t_pmc5, store_pa6t_pmc5), +}; + static void register_cpu_online(unsigned int cpu) { struct cpu *c = &per_cpu(cpu_devices, cpu); struct sys_device *s = &c->sysdev; + struct sysdev_attribute *attrs, *pmc_attrs; + int i, nattrs; if (!firmware_has_feature(FW_FEATURE_ISERIES) && cpu_has_feature(CPU_FTR_SMT)) sysdev_create_file(s, &attr_smt_snooze_delay); /* PMC stuff */ + switch (cur_cpu_spec->pmc_type) { + case PPC_PMC_IBM: + attrs = ibm_common_attrs; + nattrs = sizeof(ibm_common_attrs) / sizeof(struct sysdev_attribute); + pmc_attrs = ibm_pmc_attrs; + break; + case PPC_PMC_PA6T: + /* PA Semi starts counting at PMC0 */ + attrs = pa6t_attrs; + nattrs = sizeof(pa6t_attrs) / sizeof(struct sysdev_attribute); + pmc_attrs = NULL; + break; + default: + attrs = NULL; + nattrs = 0; + pmc_attrs = NULL; + } + + for (i = 0; i < nattrs; i++) + sysdev_create_file(s, &attrs[i]); - sysdev_create_file(s, &attr_mmcr0); - sysdev_create_file(s, &attr_mmcr1); + if (pmc_attrs) + for (i = 0; i < cur_cpu_spec->num_pmcs; i++) + sysdev_create_file(s, &pmc_attrs[i]); if (cpu_has_feature(CPU_FTR_MMCRA)) sysdev_create_file(s, &attr_mmcra); - if (cur_cpu_spec->num_pmcs >= 1) - sysdev_create_file(s, &attr_pmc1); - if (cur_cpu_spec->num_pmcs >= 2) - sysdev_create_file(s, &attr_pmc2); - if (cur_cpu_spec->num_pmcs >= 3) - sysdev_create_file(s, &attr_pmc3); - if (cur_cpu_spec->num_pmcs >= 4) - sysdev_create_file(s, &attr_pmc4); - if (cur_cpu_spec->num_pmcs >= 5) - sysdev_create_file(s, &attr_pmc5); - if (cur_cpu_spec->num_pmcs >= 6) - sysdev_create_file(s, &attr_pmc6); - if (cur_cpu_spec->num_pmcs >= 7) - sysdev_create_file(s, &attr_pmc7); - if (cur_cpu_spec->num_pmcs >= 8) - sysdev_create_file(s, &attr_pmc8); - if (cpu_has_feature(CPU_FTR_PURR)) sysdev_create_file(s, &attr_purr); @@ -248,6 +285,8 @@ static void unregister_cpu_online(unsign { struct cpu *c = &per_cpu(cpu_devices, cpu); struct sys_device *s = &c->sysdev; + struct sysdev_attribute *attrs, *pmc_attrs; + int i, nattrs; BUG_ON(!c->hotpluggable); @@ -256,30 +295,34 @@ static void unregister_cpu_online(unsign sysdev_remove_file(s, &attr_smt_snooze_delay); /* PMC stuff */ + switch (cur_cpu_spec->pmc_type) { + case PPC_PMC_IBM: + attrs = ibm_common_attrs; + nattrs = sizeof(ibm_common_attrs) / sizeof(struct sysdev_attribute); + pmc_attrs = ibm_pmc_attrs; + break; + case PPC_PMC_PA6T: + /* PA Semi starts counting at PMC0 */ + attrs = pa6t_attrs; + nattrs = sizeof(pa6t_attrs) / sizeof(struct sysdev_attribute); + pmc_attrs = NULL; + break; + default: + attrs = NULL; + nattrs = 0; + pmc_attrs = NULL; + } - sysdev_remove_file(s, &attr_mmcr0); - sysdev_remove_file(s, &attr_mmcr1); + for (i = 0; i < nattrs; i++) + sysdev_remove_file(s, &attrs[i]); + + if (pmc_attrs) + for (i = 0; i < cur_cpu_spec->num_pmcs; i++) + sysdev_remove_file(s, &pmc_attrs[i]); if (cpu_has_feature(CPU_FTR_MMCRA)) sysdev_remove_file(s, &attr_mmcra); - if (cur_cpu_spec->num_pmcs >= 1) - sysdev_remove_file(s, &attr_pmc1); - if (cur_cpu_spec->num_pmcs >= 2) - sysdev_remove_file(s, &attr_pmc2); - if (cur_cpu_spec->num_pmcs >= 3) - sysdev_remove_file(s, &attr_pmc3); - if (cur_cpu_spec->num_pmcs >= 4) - sysdev_remove_file(s, &attr_pmc4); - if (cur_cpu_spec->num_pmcs >= 5) - sysdev_remove_file(s, &attr_pmc5); - if (cur_cpu_spec->num_pmcs >= 6) - sysdev_remove_file(s, &attr_pmc6); - if (cur_cpu_spec->num_pmcs >= 7) - sysdev_remove_file(s, &attr_pmc7); - if (cur_cpu_spec->num_pmcs >= 8) - sysdev_remove_file(s, &attr_pmc8); - if (cpu_has_feature(CPU_FTR_PURR)) sysdev_remove_file(s, &attr_purr); diff --git a/arch/powerpc/kernel/traps.c b/arch/powerpc/kernel/traps.c index 535f506..dcc6f15 100644 --- a/arch/powerpc/kernel/traps.c +++ b/arch/powerpc/kernel/traps.c @@ -174,7 +174,7 @@ void _exception(int signr, struct pt_reg * generate the same exception over and over again and we get * nowhere. Better to kill it and let the kernel panic. */ - if (current->pid == 1) { + if (is_init(current)) { __sighandler_t handler; spin_lock_irq(¤t->sighand->siglock); @@ -535,34 +535,40 @@ static void emulate_single_step(struct p } } -static void parse_fpe(struct pt_regs *regs) +static inline int __parse_fpscr(unsigned long fpscr) { - int code = 0; - unsigned long fpscr; - - flush_fp_to_thread(current); - - fpscr = current->thread.fpscr.val; + int ret = 0; /* Invalid operation */ if ((fpscr & FPSCR_VE) && (fpscr & FPSCR_VX)) - code = FPE_FLTINV; + ret = FPE_FLTINV; /* Overflow */ else if ((fpscr & FPSCR_OE) && (fpscr & FPSCR_OX)) - code = FPE_FLTOVF; + ret = FPE_FLTOVF; /* Underflow */ else if ((fpscr & FPSCR_UE) && (fpscr & FPSCR_UX)) - code = FPE_FLTUND; + ret = FPE_FLTUND; /* Divide by zero */ else if ((fpscr & FPSCR_ZE) && (fpscr & FPSCR_ZX)) - code = FPE_FLTDIV; + ret = FPE_FLTDIV; /* Inexact result */ else if ((fpscr & FPSCR_XE) && (fpscr & FPSCR_XX)) - code = FPE_FLTRES; + ret = FPE_FLTRES; + + return ret; +} + +static void parse_fpe(struct pt_regs *regs) +{ + int code = 0; + + flush_fp_to_thread(current); + + code = __parse_fpscr(current->thread.fpscr.val); _exception(SIGFPE, regs, code, regs->nip); } @@ -739,20 +745,7 @@ void __kprobes program_check_exception(s extern int do_mathemu(struct pt_regs *regs); /* We can now get here via a FP Unavailable exception if the core - * has no FPU, in that case no reason flags will be set */ -#ifdef CONFIG_MATH_EMULATION - /* (reason & REASON_ILLEGAL) would be the obvious thing here, - * but there seems to be a hardware bug on the 405GP (RevD) - * that means ESR is sometimes set incorrectly - either to - * ESR_DST (!?) or 0. In the process of chasing this with the - * hardware people - not sure if it can happen on any illegal - * instruction or only on FP instructions, whether there is a - * pattern to occurences etc. -dgibson 31/Mar/2003 */ - if (!(reason & REASON_TRAP) && do_mathemu(regs) == 0) { - emulate_single_step(regs); - return; - } -#endif /* CONFIG_MATH_EMULATION */ + * has no FPU, in that case the reason flags will be 0 */ if (reason & REASON_FP) { /* IEEE FP exception */ @@ -778,6 +771,31 @@ #endif /* CONFIG_MATH_EMULATION */ local_irq_enable(); +#ifdef CONFIG_MATH_EMULATION + /* (reason & REASON_ILLEGAL) would be the obvious thing here, + * but there seems to be a hardware bug on the 405GP (RevD) + * that means ESR is sometimes set incorrectly - either to + * ESR_DST (!?) or 0. In the process of chasing this with the + * hardware people - not sure if it can happen on any illegal + * instruction or only on FP instructions, whether there is a + * pattern to occurences etc. -dgibson 31/Mar/2003 */ + switch (do_mathemu(regs)) { + case 0: + emulate_single_step(regs); + return; + case 1: { + int code = 0; + code = __parse_fpscr(current->thread.fpscr.val); + _exception(SIGFPE, regs, code, regs->nip); + return; + } + case -EFAULT: + _exception(SIGSEGV, regs, SEGV_MAPERR, regs->nip); + return; + } + /* fall through on any other errors */ +#endif /* CONFIG_MATH_EMULATION */ + /* Try to emulate it if we should. */ if (reason & (REASON_ILLEGAL | REASON_PRIVILEGED)) { switch (emulate_instruction(regs)) { @@ -891,18 +909,39 @@ void SoftwareEmulation(struct pt_regs *r #ifdef CONFIG_MATH_EMULATION errcode = do_mathemu(regs); + + switch (errcode) { + case 0: + emulate_single_step(regs); + return; + case 1: { + int code = 0; + code = __parse_fpscr(current->thread.fpscr.val); + _exception(SIGFPE, regs, code, regs->nip); + return; + } + case -EFAULT: + _exception(SIGSEGV, regs, SEGV_MAPERR, regs->nip); + return; + default: + _exception(SIGILL, regs, ILL_ILLOPC, regs->nip); + return; + } + #else errcode = Soft_emulate_8xx(regs); -#endif - if (errcode) { - if (errcode > 0) - _exception(SIGFPE, regs, 0, 0); - else if (errcode == -EFAULT) - _exception(SIGSEGV, regs, 0, 0); - else - _exception(SIGILL, regs, ILL_ILLOPC, regs->nip); - } else + switch (errcode) { + case 0: emulate_single_step(regs); + return; + case 1: + _exception(SIGILL, regs, ILL_ILLOPC, regs->nip); + return; + case -EFAULT: + _exception(SIGSEGV, regs, SEGV_MAPERR, regs->nip); + return; + } +#endif } #endif /* CONFIG_8xx */ diff --git a/arch/powerpc/kernel/udbg.c b/arch/powerpc/kernel/udbg.c index 5730906..7e09718 100644 --- a/arch/powerpc/kernel/udbg.c +++ b/arch/powerpc/kernel/udbg.c @@ -45,6 +45,12 @@ #elif defined(CONFIG_PPC_EARLY_DEBUG_MAP #elif defined(CONFIG_PPC_EARLY_DEBUG_ISERIES) /* For iSeries - hit Ctrl-x Ctrl-x to see the output */ udbg_init_iseries(); +#elif defined(CONFIG_PPC_EARLY_DEBUG_BEAT) + udbg_init_debug_beat(); +#elif defined(CONFIG_PPC_EARLY_DEBUG_PAS_REALMODE) + udbg_init_pas_realmode(); +#elif defined(CONFIG_BOOTX_TEXT) + udbg_init_btext(); #endif } @@ -146,7 +152,7 @@ void __init disable_early_printk(void) { if (!early_console_initialized) return; - if (strstr(saved_command_line, "udbg-immortal")) { + if (strstr(boot_command_line, "udbg-immortal")) { printk(KERN_INFO "early console immortal !\n"); return; } diff --git a/arch/powerpc/kernel/udbg_16550.c b/arch/powerpc/kernel/udbg_16550.c index 2d17f2b..e738f93 100644 --- a/arch/powerpc/kernel/udbg_16550.c +++ b/arch/powerpc/kernel/udbg_16550.c @@ -14,6 +14,8 @@ #include extern u8 real_readb(volatile u8 __iomem *addr); extern void real_writeb(u8 data, volatile u8 __iomem *addr); +extern u8 real_205_readb(volatile u8 __iomem *addr); +extern void real_205_writeb(u8 data, volatile u8 __iomem *addr); struct NS16550 { /* this struct must be packed */ @@ -167,3 +169,25 @@ void __init udbg_init_maple_realmode(voi udbg_getc_poll = NULL; } #endif /* CONFIG_PPC_MAPLE */ + +#ifdef CONFIG_PPC_PASEMI +void udbg_pas_real_putc(char c) +{ + if (udbg_comport) { + while ((real_205_readb(&udbg_comport->lsr) & LSR_THRE) == 0) + /* wait for idle */; + real_205_writeb(c, &udbg_comport->thr); eieio(); + if (c == '\n') + udbg_pas_real_putc('\r'); + } +} + +void udbg_init_pas_realmode(void) +{ + udbg_comport = (volatile struct NS16550 __iomem *)0xfcff03f8; + + udbg_putc = udbg_pas_real_putc; + udbg_getc = NULL; + udbg_getc_poll = NULL; +} +#endif /* CONFIG_PPC_MAPLE */ diff --git a/arch/powerpc/kernel/vdso.c b/arch/powerpc/kernel/vdso.c index ae0ede1..e46c31b 100644 --- a/arch/powerpc/kernel/vdso.c +++ b/arch/powerpc/kernel/vdso.c @@ -51,17 +51,21 @@ #define MAX_SYMNAME 64 extern char vdso32_start, vdso32_end; static void *vdso32_kbase = &vdso32_start; -unsigned int vdso32_pages; +static unsigned int vdso32_pages; +static struct page **vdso32_pagelist; unsigned long vdso32_sigtramp; unsigned long vdso32_rt_sigtramp; #ifdef CONFIG_PPC64 extern char vdso64_start, vdso64_end; static void *vdso64_kbase = &vdso64_start; -unsigned int vdso64_pages; +static unsigned int vdso64_pages; +static struct page **vdso64_pagelist; unsigned long vdso64_rt_sigtramp; #endif /* CONFIG_PPC64 */ +static int vdso_ready; + /* * The vdso data page (aka. systemcfg for old ppc64 fans) is here. * Once the early boot kernel code no longer needs to muck around @@ -165,55 +169,6 @@ static void dump_vdso_pages(struct vm_ar #endif /* DEBUG */ /* - * Keep a dummy vma_close for now, it will prevent VMA merging. - */ -static void vdso_vma_close(struct vm_area_struct * vma) -{ -} - -/* - * Our nopage() function, maps in the actual vDSO kernel pages, they will - * be mapped read-only by do_no_page(), and eventually COW'ed, either - * right away for an initial write access, or by do_wp_page(). - */ -static struct page * vdso_vma_nopage(struct vm_area_struct * vma, - unsigned long address, int *type) -{ - unsigned long offset = address - vma->vm_start; - struct page *pg; -#ifdef CONFIG_PPC64 - void *vbase = (vma->vm_mm->task_size > TASK_SIZE_USER32) ? - vdso64_kbase : vdso32_kbase; -#else - void *vbase = vdso32_kbase; -#endif - - DBG("vdso_vma_nopage(current: %s, address: %016lx, off: %lx)\n", - current->comm, address, offset); - - if (address < vma->vm_start || address > vma->vm_end) - return NOPAGE_SIGBUS; - - /* - * Last page is systemcfg. - */ - if ((vma->vm_end - address) <= PAGE_SIZE) - pg = virt_to_page(vdso_data); - else - pg = virt_to_page(vbase + offset); - - get_page(pg); - DBG(" ->page count: %d\n", page_count(pg)); - - return pg; -} - -static struct vm_operations_struct vdso_vmops = { - .close = vdso_vma_close, - .nopage = vdso_vma_nopage, -}; - -/* * This is called from binfmt_elf, we create the special vma for the * vDSO and insert it into the mm struct tree */ @@ -221,20 +176,26 @@ int arch_setup_additional_pages(struct l int executable_stack) { struct mm_struct *mm = current->mm; - struct vm_area_struct *vma; + struct page **vdso_pagelist; unsigned long vdso_pages; unsigned long vdso_base; int rc; + if (!vdso_ready) + return 0; + #ifdef CONFIG_PPC64 if (test_thread_flag(TIF_32BIT)) { + vdso_pagelist = vdso32_pagelist; vdso_pages = vdso32_pages; vdso_base = VDSO32_MBASE; } else { + vdso_pagelist = vdso64_pagelist; vdso_pages = vdso64_pages; vdso_base = VDSO64_MBASE; } #else + vdso_pagelist = vdso32_pagelist; vdso_pages = vdso32_pages; vdso_base = VDSO32_MBASE; #endif @@ -262,17 +223,6 @@ #endif goto fail_mmapsem; } - - /* Allocate a VMA structure and fill it up */ - vma = kmem_cache_zalloc(vm_area_cachep, GFP_KERNEL); - if (vma == NULL) { - rc = -ENOMEM; - goto fail_mmapsem; - } - vma->vm_mm = mm; - vma->vm_start = vdso_base; - vma->vm_end = vma->vm_start + (vdso_pages << PAGE_SHIFT); - /* * our vma flags don't have VM_WRITE so by default, the process isn't * allowed to write those pages. @@ -282,32 +232,26 @@ #endif * and your nice userland gettimeofday will be totally dead. * It's fine to use that for setting breakpoints in the vDSO code * pages though - */ - vma->vm_flags = VM_READ|VM_EXEC|VM_MAYREAD|VM_MAYWRITE|VM_MAYEXEC; - /* + * * Make sure the vDSO gets into every core dump. * Dumping its contents makes post-mortem fully interpretable later * without matching up the same kernel and hardware config to see * what PC values meant. */ - vma->vm_flags |= VM_ALWAYSDUMP; - vma->vm_flags |= mm->def_flags; - vma->vm_page_prot = protection_map[vma->vm_flags & 0x7]; - vma->vm_ops = &vdso_vmops; - - /* Insert new VMA */ - rc = insert_vm_struct(mm, vma); + rc = install_special_mapping(mm, vdso_base, vdso_pages << PAGE_SHIFT, + VM_READ|VM_EXEC| + VM_MAYREAD|VM_MAYWRITE|VM_MAYEXEC| + VM_ALWAYSDUMP, + vdso_pagelist); if (rc) - goto fail_vma; + goto fail_mmapsem; - /* Put vDSO base into mm struct and account for memory usage */ + /* Put vDSO base into mm struct */ current->mm->context.vdso_base = vdso_base; - mm->total_vm += (vma->vm_end - vma->vm_start) >> PAGE_SHIFT; + up_write(&mm->mmap_sem); return 0; - fail_vma: - kmem_cache_free(vm_area_cachep, vma); fail_mmapsem: up_write(&mm->mmap_sem); return rc; @@ -719,7 +663,7 @@ #endif /* CONFIG_PPC64 */ } -void __init vdso_init(void) +static int __init vdso_init(void) { int i; @@ -774,26 +718,44 @@ #endif /* CONFIG_PPC64 */ #ifdef CONFIG_PPC64 vdso64_pages = 0; #endif - return; + return 0; } /* Make sure pages are in the correct state */ + vdso32_pagelist = kzalloc(sizeof(struct page *) * (vdso32_pages + 2), + GFP_KERNEL); + BUG_ON(vdso32_pagelist == NULL); for (i = 0; i < vdso32_pages; i++) { struct page *pg = virt_to_page(vdso32_kbase + i*PAGE_SIZE); ClearPageReserved(pg); get_page(pg); - + vdso32_pagelist[i] = pg; } + vdso32_pagelist[i++] = virt_to_page(vdso_data); + vdso32_pagelist[i] = NULL; + #ifdef CONFIG_PPC64 + vdso64_pagelist = kzalloc(sizeof(struct page *) * (vdso64_pages + 2), + GFP_KERNEL); + BUG_ON(vdso64_pagelist == NULL); for (i = 0; i < vdso64_pages; i++) { struct page *pg = virt_to_page(vdso64_kbase + i*PAGE_SIZE); ClearPageReserved(pg); get_page(pg); + vdso64_pagelist[i] = pg; } + vdso64_pagelist[i++] = virt_to_page(vdso_data); + vdso64_pagelist[i] = NULL; #endif /* CONFIG_PPC64 */ get_page(virt_to_page(vdso_data)); + + smp_wmb(); + vdso_ready = 1; + + return 0; } +arch_initcall(vdso_init); int in_gate_area_no_task(unsigned long addr) { diff --git a/arch/powerpc/kernel/vio.c b/arch/powerpc/kernel/vio.c index a80f8f1..2968ffe 100644 --- a/arch/powerpc/kernel/vio.c +++ b/arch/powerpc/kernel/vio.c @@ -199,10 +199,8 @@ EXPORT_SYMBOL(vio_unregister_driver); /* vio_dev refcount hit 0 */ static void __devinit vio_dev_release(struct device *dev) { - if (dev->archdata.of_node) { - /* XXX should free TCE table */ - of_node_put(dev->archdata.of_node); - } + /* XXX should free TCE table */ + of_node_put(dev->archdata.of_node); kfree(to_vio_dev(dev)); } diff --git a/arch/powerpc/kernel/vmlinux.lds.S b/arch/powerpc/kernel/vmlinux.lds.S index 04b8e71..7eefeb4 100644 --- a/arch/powerpc/kernel/vmlinux.lds.S +++ b/arch/powerpc/kernel/vmlinux.lds.S @@ -131,14 +131,14 @@ #ifdef CONFIG_PPC64 __stop___fw_ftr_fixup = .; } #endif - +#ifdef CONFIG_BLK_DEV_INITRD . = ALIGN(PAGE_SIZE); .init.ramfs : { __initramfs_start = .; *(.init.ramfs) __initramfs_end = .; } - +#endif #ifdef CONFIG_PPC32 . = ALIGN(32); #else diff --git a/arch/powerpc/lib/Makefile b/arch/powerpc/lib/Makefile index a0360ae..4b1ba49 100644 --- a/arch/powerpc/lib/Makefile +++ b/arch/powerpc/lib/Makefile @@ -16,13 +16,15 @@ obj-$(CONFIG_PPC64) += checksum_64.o cop strcase.o obj-$(CONFIG_QUICC_ENGINE) += rheap.o obj-$(CONFIG_XMON) += sstep.o +obj-$(CONFIG_KPROBES) += sstep.o +obj-$(CONFIG_NOT_COHERENT_CACHE) += dma-noncoherent.o ifeq ($(CONFIG_PPC64),y) obj-$(CONFIG_SMP) += locks.o -obj-$(CONFIG_DEBUG_KERNEL) += sstep.o endif # Temporary hack until we have migrated to asm-powerpc ifeq ($(CONFIG_PPC_MERGE),y) +obj-$(CONFIG_8xx) += rheap.o obj-$(CONFIG_CPM2) += rheap.o endif diff --git a/arch/powerpc/lib/dma-noncoherent.c b/arch/powerpc/lib/dma-noncoherent.c new file mode 100644 index 0000000..48f3d13 --- /dev/null +++ b/arch/powerpc/lib/dma-noncoherent.c @@ -0,0 +1,418 @@ +/* + * PowerPC version derived from arch/arm/mm/consistent.c + * Copyright (C) 2001 Dan Malek (dmalek@jlc.net) + * + * Copyright (C) 2000 Russell King + * + * Consistent memory allocators. Used for DMA devices that want to + * share uncached memory with the processor core. The function return + * is the virtual address and 'dma_handle' is the physical address. + * Mostly stolen from the ARM port, with some changes for PowerPC. + * -- Dan + * + * Reorganized to get rid of the arch-specific consistent_* functions + * and provide non-coherent implementations for the DMA API. -Matt + * + * Added in_interrupt() safe dma_alloc_coherent()/dma_free_coherent() + * implementation. This is pulled straight from ARM and barely + * modified. -Matt + * + * 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 + +/* + * This address range defaults to a value that is safe for all + * platforms which currently set CONFIG_NOT_COHERENT_CACHE. It + * can be further configured for specific applications under + * the "Advanced Setup" menu. -Matt + */ +#define CONSISTENT_BASE (CONFIG_CONSISTENT_START) +#define CONSISTENT_END (CONFIG_CONSISTENT_START + CONFIG_CONSISTENT_SIZE) +#define CONSISTENT_OFFSET(x) (((unsigned long)(x) - CONSISTENT_BASE) >> PAGE_SHIFT) + +/* + * This is the page table (2MB) covering uncached, DMA consistent allocations + */ +static pte_t *consistent_pte; +static DEFINE_SPINLOCK(consistent_lock); + +/* + * VM region handling support. + * + * This should become something generic, handling VM region allocations for + * vmalloc and similar (ioremap, module space, etc). + * + * I envisage vmalloc()'s supporting vm_struct becoming: + * + * struct vm_struct { + * struct vm_region region; + * unsigned long flags; + * struct page **pages; + * unsigned int nr_pages; + * unsigned long phys_addr; + * }; + * + * get_vm_area() would then call vm_region_alloc with an appropriate + * struct vm_region head (eg): + * + * struct vm_region vmalloc_head = { + * .vm_list = LIST_HEAD_INIT(vmalloc_head.vm_list), + * .vm_start = VMALLOC_START, + * .vm_end = VMALLOC_END, + * }; + * + * However, vmalloc_head.vm_start is variable (typically, it is dependent on + * the amount of RAM found at boot time.) I would imagine that get_vm_area() + * would have to initialise this each time prior to calling vm_region_alloc(). + */ +struct vm_region { + struct list_head vm_list; + unsigned long vm_start; + unsigned long vm_end; +}; + +static struct vm_region consistent_head = { + .vm_list = LIST_HEAD_INIT(consistent_head.vm_list), + .vm_start = CONSISTENT_BASE, + .vm_end = CONSISTENT_END, +}; + +static struct vm_region * +vm_region_alloc(struct vm_region *head, size_t size, gfp_t gfp) +{ + unsigned long addr = head->vm_start, end = head->vm_end - size; + unsigned long flags; + struct vm_region *c, *new; + + new = kmalloc(sizeof(struct vm_region), gfp); + if (!new) + goto out; + + spin_lock_irqsave(&consistent_lock, flags); + + list_for_each_entry(c, &head->vm_list, vm_list) { + if ((addr + size) < addr) + goto nospc; + if ((addr + size) <= c->vm_start) + goto found; + addr = c->vm_end; + if (addr > end) + goto nospc; + } + + found: + /* + * Insert this entry _before_ the one we found. + */ + list_add_tail(&new->vm_list, &c->vm_list); + new->vm_start = addr; + new->vm_end = addr + size; + + spin_unlock_irqrestore(&consistent_lock, flags); + return new; + + nospc: + spin_unlock_irqrestore(&consistent_lock, flags); + kfree(new); + out: + return NULL; +} + +static struct vm_region *vm_region_find(struct vm_region *head, unsigned long addr) +{ + struct vm_region *c; + + list_for_each_entry(c, &head->vm_list, vm_list) { + if (c->vm_start == addr) + goto out; + } + c = NULL; + out: + return c; +} + +/* + * Allocate DMA-coherent memory space and return both the kernel remapped + * virtual and bus address for that space. + */ +void * +__dma_alloc_coherent(size_t size, dma_addr_t *handle, gfp_t gfp) +{ + struct page *page; + struct vm_region *c; + unsigned long order; + u64 mask = 0x00ffffff, limit; /* ISA default */ + + if (!consistent_pte) { + printk(KERN_ERR "%s: not initialised\n", __func__); + dump_stack(); + return NULL; + } + + size = PAGE_ALIGN(size); + limit = (mask + 1) & ~mask; + if ((limit && size >= limit) || size >= (CONSISTENT_END - CONSISTENT_BASE)) { + printk(KERN_WARNING "coherent allocation too big (requested %#x mask %#Lx)\n", + size, mask); + return NULL; + } + + order = get_order(size); + + if (mask != 0xffffffff) + gfp |= GFP_DMA; + + page = alloc_pages(gfp, order); + if (!page) + goto no_page; + + /* + * Invalidate any data that might be lurking in the + * kernel direct-mapped region for device DMA. + */ + { + unsigned long kaddr = (unsigned long)page_address(page); + memset(page_address(page), 0, size); + flush_dcache_range(kaddr, kaddr + size); + } + + /* + * Allocate a virtual address in the consistent mapping region. + */ + c = vm_region_alloc(&consistent_head, size, + gfp & ~(__GFP_DMA | __GFP_HIGHMEM)); + if (c) { + unsigned long vaddr = c->vm_start; + pte_t *pte = consistent_pte + CONSISTENT_OFFSET(vaddr); + struct page *end = page + (1 << order); + + split_page(page, order); + + /* + * Set the "dma handle" + */ + *handle = page_to_bus(page); + + do { + BUG_ON(!pte_none(*pte)); + + SetPageReserved(page); + set_pte_at(&init_mm, vaddr, + pte, mk_pte(page, pgprot_noncached(PAGE_KERNEL))); + page++; + pte++; + vaddr += PAGE_SIZE; + } while (size -= PAGE_SIZE); + + /* + * Free the otherwise unused pages. + */ + while (page < end) { + __free_page(page); + page++; + } + + return (void *)c->vm_start; + } + + if (page) + __free_pages(page, order); + no_page: + return NULL; +} +EXPORT_SYMBOL(__dma_alloc_coherent); + +/* + * free a page as defined by the above mapping. + */ +void __dma_free_coherent(size_t size, void *vaddr) +{ + struct vm_region *c; + unsigned long flags, addr; + pte_t *ptep; + + size = PAGE_ALIGN(size); + + spin_lock_irqsave(&consistent_lock, flags); + + c = vm_region_find(&consistent_head, (unsigned long)vaddr); + if (!c) + goto no_area; + + if ((c->vm_end - c->vm_start) != size) { + printk(KERN_ERR "%s: freeing wrong coherent size (%ld != %d)\n", + __func__, c->vm_end - c->vm_start, size); + dump_stack(); + size = c->vm_end - c->vm_start; + } + + ptep = consistent_pte + CONSISTENT_OFFSET(c->vm_start); + addr = c->vm_start; + do { + pte_t pte = ptep_get_and_clear(&init_mm, addr, ptep); + unsigned long pfn; + + ptep++; + addr += PAGE_SIZE; + + if (!pte_none(pte) && pte_present(pte)) { + pfn = pte_pfn(pte); + + if (pfn_valid(pfn)) { + struct page *page = pfn_to_page(pfn); + ClearPageReserved(page); + + __free_page(page); + continue; + } + } + + printk(KERN_CRIT "%s: bad page in kernel page table\n", + __func__); + } while (size -= PAGE_SIZE); + + flush_tlb_kernel_range(c->vm_start, c->vm_end); + + list_del(&c->vm_list); + + spin_unlock_irqrestore(&consistent_lock, flags); + + kfree(c); + return; + + no_area: + spin_unlock_irqrestore(&consistent_lock, flags); + printk(KERN_ERR "%s: trying to free invalid coherent area: %p\n", + __func__, vaddr); + dump_stack(); +} +EXPORT_SYMBOL(__dma_free_coherent); + +/* + * Initialise the consistent memory allocation. + */ +static int __init dma_alloc_init(void) +{ + pgd_t *pgd; + pmd_t *pmd; + pte_t *pte; + int ret = 0; + + do { + pgd = pgd_offset(&init_mm, CONSISTENT_BASE); + pmd = pmd_alloc(&init_mm, pgd, CONSISTENT_BASE); + if (!pmd) { + printk(KERN_ERR "%s: no pmd tables\n", __func__); + ret = -ENOMEM; + break; + } + WARN_ON(!pmd_none(*pmd)); + + pte = pte_alloc_kernel(pmd, CONSISTENT_BASE); + if (!pte) { + printk(KERN_ERR "%s: no pte tables\n", __func__); + ret = -ENOMEM; + break; + } + + consistent_pte = pte; + } while (0); + + return ret; +} + +core_initcall(dma_alloc_init); + +/* + * make an area consistent. + */ +void __dma_sync(void *vaddr, size_t size, int direction) +{ + unsigned long start = (unsigned long)vaddr; + unsigned long end = start + size; + + switch (direction) { + case DMA_NONE: + BUG(); + case DMA_FROM_DEVICE: /* invalidate only */ + invalidate_dcache_range(start, end); + break; + case DMA_TO_DEVICE: /* writeback only */ + clean_dcache_range(start, end); + break; + case DMA_BIDIRECTIONAL: /* writeback and invalidate */ + flush_dcache_range(start, end); + break; + } +} +EXPORT_SYMBOL(__dma_sync); + +#ifdef CONFIG_HIGHMEM +/* + * __dma_sync_page() implementation for systems using highmem. + * In this case, each page of a buffer must be kmapped/kunmapped + * in order to have a virtual address for __dma_sync(). This must + * not sleep so kmap_atomic()/kunmap_atomic() are used. + * + * Note: yes, it is possible and correct to have a buffer extend + * beyond the first page. + */ +static inline void __dma_sync_page_highmem(struct page *page, + unsigned long offset, size_t size, int direction) +{ + size_t seg_size = min((size_t)(PAGE_SIZE - offset), size); + size_t cur_size = seg_size; + unsigned long flags, start, seg_offset = offset; + int nr_segs = 1 + ((size - seg_size) + PAGE_SIZE - 1)/PAGE_SIZE; + int seg_nr = 0; + + local_irq_save(flags); + + do { + start = (unsigned long)kmap_atomic(page + seg_nr, + KM_PPC_SYNC_PAGE) + seg_offset; + + /* Sync this buffer segment */ + __dma_sync((void *)start, seg_size, direction); + kunmap_atomic((void *)start, KM_PPC_SYNC_PAGE); + seg_nr++; + + /* Calculate next buffer segment size */ + seg_size = min((size_t)PAGE_SIZE, size - cur_size); + + /* Add the segment size to our running total */ + cur_size += seg_size; + seg_offset = 0; + } while (seg_nr < nr_segs); + + local_irq_restore(flags); +} +#endif /* CONFIG_HIGHMEM */ + +/* + * __dma_sync_page makes memory consistent. identical to __dma_sync, but + * takes a struct page instead of a virtual address + */ +void __dma_sync_page(struct page *page, unsigned long offset, + size_t size, int direction) +{ +#ifdef CONFIG_HIGHMEM + __dma_sync_page_highmem(page, offset, size, direction); +#else + unsigned long start = (unsigned long)page_address(page) + offset; + __dma_sync((void *)start, size, direction); +#endif +} +EXPORT_SYMBOL(__dma_sync_page); diff --git a/arch/powerpc/lib/rheap.c b/arch/powerpc/lib/rheap.c index 57bf991..6c5c5dd 100644 --- a/arch/powerpc/lib/rheap.c +++ b/arch/powerpc/lib/rheap.c @@ -14,6 +14,7 @@ */ #include #include +#include #include #include @@ -85,7 +86,8 @@ static int grow(rh_info_t * info, int ma info->flags &= ~RHIF_STATIC_BLOCK; /* add all new blocks to the free list */ - for (i = 0, blk = block + info->max_blocks; i < new_blocks; i++, blk++) + blk = block + info->max_blocks - new_blocks; + for (i = 0; i < new_blocks; i++, blk++) list_add(&blk->list, &info->empty_list); return 0; @@ -670,7 +672,7 @@ void rh_dump(rh_info_t * info) int maxnr; int i, nr; - maxnr = sizeof(st) / sizeof(st[0]); + maxnr = ARRAY_SIZE(st); printk(KERN_INFO "info @0x%p (%d slots empty / %d max)\n", diff --git a/arch/powerpc/mm/hugetlbpage.c b/arch/powerpc/mm/hugetlbpage.c index 1bb20d8..8c77c79 100644 --- a/arch/powerpc/mm/hugetlbpage.c +++ b/arch/powerpc/mm/hugetlbpage.c @@ -1014,7 +1014,6 @@ repeat: /* Primary is full, try the secondary */ if (unlikely(slot == -1)) { - new_pte |= _PAGE_F_SECOND; hpte_group = ((~hash & htab_hash_mask) * HPTES_PER_GROUP) & ~0x7UL; slot = ppc_md.hpte_insert(hpte_group, va, pa, rflags, @@ -1033,7 +1032,7 @@ repeat: if (unlikely(slot == -2)) panic("hash_huge_page: pte_insert failed\n"); - new_pte |= (slot << 12) & _PAGE_F_GIX; + new_pte |= (slot << 12) & (_PAGE_F_SECOND | _PAGE_F_GIX); } /* diff --git a/arch/powerpc/mm/mem.c b/arch/powerpc/mm/mem.c index d1c0758..52f397c 100644 --- a/arch/powerpc/mm/mem.c +++ b/arch/powerpc/mm/mem.c @@ -61,10 +61,6 @@ unsigned long memory_limit; extern void hash_preload(struct mm_struct *mm, unsigned long ea, unsigned long access, unsigned long trap); -/* - * This is called by /dev/mem to know if a given address has to - * be mapped non-cacheable or not - */ int page_is_ram(unsigned long pfn) { unsigned long paddr = (pfn << PAGE_SHIFT); @@ -388,9 +384,6 @@ #endif /* CONFIG_HIGHMEM */ initsize >> 10); mem_init_done = 1; - - /* Initialize the vDSO */ - vdso_init(); } /* @@ -490,19 +483,19 @@ #endif !cpu_has_feature(CPU_FTR_NOEXECUTE) && pfn_valid(pfn)) { struct page *page = pfn_to_page(pfn); +#ifdef CONFIG_8xx + /* On 8xx, cache control instructions (particularly + * "dcbst" from flush_dcache_icache) fault as write + * operation if there is an unpopulated TLB entry + * for the address in question. To workaround that, + * we invalidate the TLB here, thus avoiding dcbst + * misbehaviour. + */ + _tlbie(address); +#endif if (!PageReserved(page) && !test_bit(PG_arch_1, &page->flags)) { if (vma->vm_mm == current->active_mm) { -#ifdef CONFIG_8xx - /* On 8xx, cache control instructions (particularly - * "dcbst" from flush_dcache_icache) fault as write - * operation if there is an unpopulated TLB entry - * for the address in question. To workaround that, - * we invalidate the TLB here, thus avoiding dcbst - * misbehaviour. - */ - _tlbie(address); -#endif __flush_dcache_icache((void *) address); } else flush_dcache_icache_page(page); diff --git a/arch/powerpc/mm/pgtable_32.c b/arch/powerpc/mm/pgtable_32.c index 1891dbe..c284bda 100644 --- a/arch/powerpc/mm/pgtable_32.c +++ b/arch/powerpc/mm/pgtable_32.c @@ -294,11 +294,8 @@ void __init mapin_ram(void) } } -/* is x a power of 2? */ -#define is_power_of_2(x) ((x) != 0 && (((x) & ((x) - 1)) == 0)) - /* is x a power of 4? */ -#define is_power_of_4(x) ((x) != 0 && (((x) & (x-1)) == 0) && (ffs(x) & 1)) +#define is_power_of_4(x) is_power_of_2(x) && (ffs(x) & 1) /* * Set up a mapping for a block of I/O. diff --git a/arch/powerpc/oprofile/common.c b/arch/powerpc/oprofile/common.c index b6d8239..fbd62ea 100644 --- a/arch/powerpc/oprofile/common.c +++ b/arch/powerpc/oprofile/common.c @@ -149,6 +149,8 @@ int __init oprofile_arch_init(struct opr #ifdef CONFIG_PPC64 #ifdef CONFIG_PPC_CELL_NATIVE case PPC_OPROFILE_CELL: + if (firmware_has_feature(FW_FEATURE_LPAR)) + return -ENODEV; model = &op_model_cell; break; #endif diff --git a/arch/powerpc/oprofile/op_model_7450.c b/arch/powerpc/oprofile/op_model_7450.c index f481c0e..5d1bbaf 100644 --- a/arch/powerpc/oprofile/op_model_7450.c +++ b/arch/powerpc/oprofile/op_model_7450.c @@ -137,9 +137,9 @@ static void fsl7450_start(struct op_coun for (i = 0; i < NUM_CTRS; ++i) { if (ctr[i].enabled) - ctr_write(i, reset_value[i]); + classic_ctr_write(i, reset_value[i]); else - ctr_write(i, 0); + classic_ctr_write(i, 0); } /* Clear the freeze bit, and enable the interrupt. @@ -179,13 +179,13 @@ static void fsl7450_handle_interrupt(str is_kernel = is_kernel_addr(pc); for (i = 0; i < NUM_CTRS; ++i) { - val = ctr_read(i); + val = classic_ctr_read(i); if (val < 0) { if (oprofile_running && ctr[i].enabled) { oprofile_add_ext_sample(pc, regs, i, is_kernel); - ctr_write(i, reset_value[i]); + classic_ctr_write(i, reset_value[i]); } else { - ctr_write(i, 0); + classic_ctr_write(i, 0); } } } diff --git a/arch/powerpc/oprofile/op_model_cell.c b/arch/powerpc/oprofile/op_model_cell.c index 2eb15f3..e08e1d7 100644 --- a/arch/powerpc/oprofile/op_model_cell.c +++ b/arch/powerpc/oprofile/op_model_cell.c @@ -39,10 +39,17 @@ #include #include "../platforms/cell/interrupt.h" #define PPU_CYCLES_EVENT_NUM 1 /* event number for CYCLES */ +#define PPU_CYCLES_GRP_NUM 1 /* special group number for identifying + * PPU_CYCLES event + */ #define CBE_COUNT_ALL_CYCLES 0x42800000 /* PPU cycle event specifier */ -#define NUM_THREADS 2 -#define VIRT_CNTR_SW_TIME_NS 100000000 // 0.5 seconds +#define NUM_THREADS 2 /* number of physical threads in + * physical processor + */ +#define NUM_TRACE_BUS_WORDS 4 +#define NUM_INPUT_BUS_WORDS 2 + struct pmc_cntrl_data { unsigned long vcntr; @@ -58,7 +65,7 @@ struct pmc_cntrl_data { struct pm_signal { u16 cpu; /* Processor to modify */ u16 sub_unit; /* hw subunit this applies to (if applicable) */ - u16 signal_group; /* Signal Group to Enable/Disable */ + short int signal_group; /* Signal Group to Enable/Disable */ u8 bus_word; /* Enable/Disable on this Trace/Trigger/Event * Bus Word(s) (bitmask) */ @@ -93,7 +100,6 @@ static struct { u32 pm07_cntrl[NR_PHYS_CTRS]; } pm_regs; - #define GET_SUB_UNIT(x) ((x & 0x0000f000) >> 12) #define GET_BUS_WORD(x) ((x & 0x000000f0) >> 4) #define GET_BUS_TYPE(x) ((x & 0x00000300) >> 8) @@ -101,7 +107,6 @@ #define GET_POLARITY(x) ((x & 0x00000002 #define GET_COUNT_CYCLES(x) (x & 0x00000001) #define GET_INPUT_CONTROL(x) ((x & 0x00000004) >> 2) - static DEFINE_PER_CPU(unsigned long[NR_PHYS_CTRS], pmc_values); static struct pmc_cntrl_data pmc_cntrl[NUM_THREADS][NR_PHYS_CTRS]; @@ -129,8 +134,8 @@ static spinlock_t virt_cntr_lock = SPIN_ static u32 ctr_enabled; -static unsigned char trace_bus[4]; -static unsigned char input_bus[2]; +static unsigned char trace_bus[NUM_TRACE_BUS_WORDS]; +static unsigned char input_bus[NUM_INPUT_BUS_WORDS]; /* * Firmware interface functions @@ -177,25 +182,40 @@ static void pm_rtas_reset_signals(u32 no static void pm_rtas_activate_signals(u32 node, u32 count) { int ret; - int j; + int i, j; struct pm_signal pm_signal_local[NR_PHYS_CTRS]; + /* There is no debug setup required for the cycles event. + * Note that only events in the same group can be used. + * Otherwise, there will be conflicts in correctly routing + * the signals on the debug bus. It is the responsiblity + * of the OProfile user tool to check the events are in + * the same group. + */ + i = 0; for (j = 0; j < count; j++) { - /* fw expects physical cpu # */ - pm_signal_local[j].cpu = node; - pm_signal_local[j].signal_group = pm_signal[j].signal_group; - pm_signal_local[j].bus_word = pm_signal[j].bus_word; - pm_signal_local[j].sub_unit = pm_signal[j].sub_unit; - pm_signal_local[j].bit = pm_signal[j].bit; + if (pm_signal[j].signal_group != PPU_CYCLES_GRP_NUM) { + + /* fw expects physical cpu # */ + pm_signal_local[i].cpu = node; + pm_signal_local[i].signal_group + = pm_signal[j].signal_group; + pm_signal_local[i].bus_word = pm_signal[j].bus_word; + pm_signal_local[i].sub_unit = pm_signal[j].sub_unit; + pm_signal_local[i].bit = pm_signal[j].bit; + i++; + } } - ret = rtas_ibm_cbe_perftools(SUBFUNC_ACTIVATE, PASSTHRU_ENABLE, - pm_signal_local, - count * sizeof(struct pm_signal)); + if (i != 0) { + ret = rtas_ibm_cbe_perftools(SUBFUNC_ACTIVATE, PASSTHRU_ENABLE, + pm_signal_local, + i * sizeof(struct pm_signal)); - if (ret) - printk(KERN_WARNING "%s: rtas returned: %d\n", - __FUNCTION__, ret); + if (ret) + printk(KERN_WARNING "%s: rtas returned: %d\n", + __FUNCTION__, ret); + } } /* @@ -212,7 +232,7 @@ static void set_pm_event(u32 ctr, int ev /* Special Event: Count all cpu cycles */ pm_regs.pm07_cntrl[ctr] = CBE_COUNT_ALL_CYCLES; p = &(pm_signal[ctr]); - p->signal_group = 21; + p->signal_group = PPU_CYCLES_GRP_NUM; p->bus_word = 1; p->sub_unit = 0; p->bit = 0; @@ -232,13 +252,21 @@ static void set_pm_event(u32 ctr, int ev p->signal_group = event / 100; p->bus_word = bus_word; - p->sub_unit = unit_mask & 0x0000f000; + p->sub_unit = (unit_mask & 0x0000f000) >> 12; pm_regs.pm07_cntrl[ctr] = 0; pm_regs.pm07_cntrl[ctr] |= PM07_CTR_COUNT_CYCLES(count_cycles); pm_regs.pm07_cntrl[ctr] |= PM07_CTR_POLARITY(polarity); pm_regs.pm07_cntrl[ctr] |= PM07_CTR_INPUT_CONTROL(input_control); + /* Some of the islands signal selection is based on 64 bit words. + * The debug bus words are 32 bits, the input words to the performance + * counters are defined as 32 bits. Need to convert the 64 bit island + * specification to the appropriate 32 input bit and bus word for the + * performance counter event selection. See the CELL Performance + * monitoring signals manual and the Perf cntr hardware descriptions + * for the details. + */ if (input_control == 0) { if (signal_bit > 31) { signal_bit -= 32; @@ -259,12 +287,12 @@ static void set_pm_event(u32 ctr, int ev p->bit = signal_bit; } - for (i = 0; i < 4; i++) { + for (i = 0; i < NUM_TRACE_BUS_WORDS; i++) { if (bus_word & (1 << i)) { pm_regs.debug_bus_control |= (bus_type << (31 - (2 * i) + 1)); - for (j = 0; j < 2; j++) { + for (j = 0; j < NUM_INPUT_BUS_WORDS; j++) { if (input_bus[j] == 0xff) { input_bus[j] = i; pm_regs.group_control |= @@ -278,52 +306,58 @@ out: ; } -static void write_pm_cntrl(int cpu, struct pm_cntrl *pm_cntrl) +static void write_pm_cntrl(int cpu) { - /* Oprofile will use 32 bit counters, set bits 7:10 to 0 */ + /* Oprofile will use 32 bit counters, set bits 7:10 to 0 + * pmregs.pm_cntrl is a global + */ + u32 val = 0; - if (pm_cntrl->enable == 1) + if (pm_regs.pm_cntrl.enable == 1) val |= CBE_PM_ENABLE_PERF_MON; - if (pm_cntrl->stop_at_max == 1) + if (pm_regs.pm_cntrl.stop_at_max == 1) val |= CBE_PM_STOP_AT_MAX; - if (pm_cntrl->trace_mode == 1) - val |= CBE_PM_TRACE_MODE_SET(pm_cntrl->trace_mode); + if (pm_regs.pm_cntrl.trace_mode == 1) + val |= CBE_PM_TRACE_MODE_SET(pm_regs.pm_cntrl.trace_mode); - if (pm_cntrl->freeze == 1) + if (pm_regs.pm_cntrl.freeze == 1) val |= CBE_PM_FREEZE_ALL_CTRS; /* Routine set_count_mode must be called previously to set * the count mode based on the user selection of user and kernel. */ - val |= CBE_PM_COUNT_MODE_SET(pm_cntrl->count_mode); + val |= CBE_PM_COUNT_MODE_SET(pm_regs.pm_cntrl.count_mode); cbe_write_pm(cpu, pm_control, val); } static inline void -set_count_mode(u32 kernel, u32 user, struct pm_cntrl *pm_cntrl) +set_count_mode(u32 kernel, u32 user) { /* The user must specify user and kernel if they want them. If - * neither is specified, OProfile will count in hypervisor mode + * neither is specified, OProfile will count in hypervisor mode. + * pm_regs.pm_cntrl is a global */ if (kernel) { if (user) - pm_cntrl->count_mode = CBE_COUNT_ALL_MODES; + pm_regs.pm_cntrl.count_mode = CBE_COUNT_ALL_MODES; else - pm_cntrl->count_mode = CBE_COUNT_SUPERVISOR_MODE; + pm_regs.pm_cntrl.count_mode = + CBE_COUNT_SUPERVISOR_MODE; } else { if (user) - pm_cntrl->count_mode = CBE_COUNT_PROBLEM_MODE; + pm_regs.pm_cntrl.count_mode = CBE_COUNT_PROBLEM_MODE; else - pm_cntrl->count_mode = CBE_COUNT_HYPERVISOR_MODE; + pm_regs.pm_cntrl.count_mode = + CBE_COUNT_HYPERVISOR_MODE; } } static inline void enable_ctr(u32 cpu, u32 ctr, u32 * pm07_cntrl) { - pm07_cntrl[ctr] |= PM07_CTR_ENABLE(1); + pm07_cntrl[ctr] |= CBE_PM_CTR_ENABLE; cbe_write_pm07_control(cpu, ctr, pm07_cntrl[ctr]); } @@ -365,6 +399,14 @@ static void cell_virtual_cntr(unsigned l hdw_thread = 1 ^ hdw_thread; next_hdw_thread = hdw_thread; + for (i = 0; i < num_counters; i++) + /* There are some per thread events. Must do the + * set event, for the thread that is being started + */ + set_pm_event(i, + pmc_cntrl[next_hdw_thread][i].evnts, + pmc_cntrl[next_hdw_thread][i].masks); + /* The following is done only once per each node, but * we need cpu #, not node #, to pass to the cbe_xxx functions. */ @@ -385,12 +427,13 @@ static void cell_virtual_cntr(unsigned l == 0xFFFFFFFF) /* If the cntr value is 0xffffffff, we must * reset that to 0xfffffff0 when the current - * thread is restarted. This will generate a new - * interrupt and make sure that we never restore - * the counters to the max value. If the counters - * were restored to the max value, they do not - * increment and no interrupts are generated. Hence - * no more samples will be collected on that cpu. + * thread is restarted. This will generate a + * new interrupt and make sure that we never + * restore the counters to the max value. If + * the counters were restored to the max value, + * they do not increment and no interrupts are + * generated. Hence no more samples will be + * collected on that cpu. */ cbe_write_ctr(cpu, i, 0xFFFFFFF0); else @@ -410,9 +453,6 @@ static void cell_virtual_cntr(unsigned l * Must do the set event, enable_cntr * for each cpu. */ - set_pm_event(i, - pmc_cntrl[next_hdw_thread][i].evnts, - pmc_cntrl[next_hdw_thread][i].masks); enable_ctr(cpu, i, pm_regs.pm07_cntrl); } else { @@ -465,8 +505,7 @@ cell_reg_setup(struct op_counter_config pm_regs.pm_cntrl.trace_mode = 0; pm_regs.pm_cntrl.freeze = 1; - set_count_mode(sys->enable_kernel, sys->enable_user, - &pm_regs.pm_cntrl); + set_count_mode(sys->enable_kernel, sys->enable_user); /* Setup the thread 0 events */ for (i = 0; i < num_ctrs; ++i) { @@ -498,10 +537,10 @@ cell_reg_setup(struct op_counter_config pmc_cntrl[1][i].vcntr = i; } - for (i = 0; i < 4; i++) + for (i = 0; i < NUM_TRACE_BUS_WORDS; i++) trace_bus[i] = 0xff; - for (i = 0; i < 2; i++) + for (i = 0; i < NUM_INPUT_BUS_WORDS; i++) input_bus[i] = 0xff; /* Our counters count up, and "count" refers to @@ -560,7 +599,7 @@ static void cell_cpu_setup(struct op_cou cbe_write_pm(cpu, pm_start_stop, 0); cbe_write_pm(cpu, group_control, pm_regs.group_control); cbe_write_pm(cpu, debug_bus_control, pm_regs.debug_bus_control); - write_pm_cntrl(cpu, &pm_regs.pm_cntrl); + write_pm_cntrl(cpu); for (i = 0; i < num_counters; ++i) { if (ctr_enabled & (1 << i)) { @@ -602,7 +641,7 @@ static void cell_global_start(struct op_ } } - cbe_clear_pm_interrupts(cpu); + cbe_get_and_clear_pm_interrupts(cpu); cbe_enable_pm_interrupts(cpu, hdw_thread, interrupt_mask); cbe_enable_pm(cpu); } @@ -672,7 +711,7 @@ cell_handle_interrupt(struct pt_regs *re cbe_disable_pm(cpu); - interrupt_mask = cbe_clear_pm_interrupts(cpu); + interrupt_mask = cbe_get_and_clear_pm_interrupts(cpu); /* If the interrupt mask has been cleared, then the virt cntr * has cleared the interrupt. When the thread that generated diff --git a/arch/powerpc/oprofile/op_model_fsl_booke.c b/arch/powerpc/oprofile/op_model_fsl_booke.c index 0b3c31f..2267eb8 100644 --- a/arch/powerpc/oprofile/op_model_fsl_booke.c +++ b/arch/powerpc/oprofile/op_model_fsl_booke.c @@ -32,6 +32,87 @@ static unsigned long reset_value[OP_MAX_ static int num_counters; static int oprofile_running; +static inline u32 get_pmlca(int ctr) +{ + u32 pmlca; + + switch (ctr) { + case 0: + pmlca = mfpmr(PMRN_PMLCA0); + break; + case 1: + pmlca = mfpmr(PMRN_PMLCA1); + break; + case 2: + pmlca = mfpmr(PMRN_PMLCA2); + break; + case 3: + pmlca = mfpmr(PMRN_PMLCA3); + break; + default: + panic("Bad ctr number\n"); + } + + return pmlca; +} + +static inline void set_pmlca(int ctr, u32 pmlca) +{ + switch (ctr) { + case 0: + mtpmr(PMRN_PMLCA0, pmlca); + break; + case 1: + mtpmr(PMRN_PMLCA1, pmlca); + break; + case 2: + mtpmr(PMRN_PMLCA2, pmlca); + break; + case 3: + mtpmr(PMRN_PMLCA3, pmlca); + break; + default: + panic("Bad ctr number\n"); + } +} + +static inline unsigned int ctr_read(unsigned int i) +{ + switch(i) { + case 0: + return mfpmr(PMRN_PMC0); + case 1: + return mfpmr(PMRN_PMC1); + case 2: + return mfpmr(PMRN_PMC2); + case 3: + return mfpmr(PMRN_PMC3); + default: + return 0; + } +} + +static inline void ctr_write(unsigned int i, unsigned int val) +{ + switch(i) { + case 0: + mtpmr(PMRN_PMC0, val); + break; + case 1: + mtpmr(PMRN_PMC1, val); + break; + case 2: + mtpmr(PMRN_PMC2, val); + break; + case 3: + mtpmr(PMRN_PMC3, val); + break; + default: + break; + } +} + + static void init_pmc_stop(int ctr) { u32 pmlca = (PMLCA_FC | PMLCA_FCS | PMLCA_FCU | diff --git a/arch/powerpc/oprofile/op_model_power4.c b/arch/powerpc/oprofile/op_model_power4.c index 356709d..fe597a1 100644 --- a/arch/powerpc/oprofile/op_model_power4.c +++ b/arch/powerpc/oprofile/op_model_power4.c @@ -121,9 +121,9 @@ static void power4_start(struct op_count for (i = 0; i < cur_cpu_spec->num_pmcs; ++i) { if (ctr[i].enabled) { - ctr_write(i, reset_value[i]); + classic_ctr_write(i, reset_value[i]); } else { - ctr_write(i, 0); + classic_ctr_write(i, 0); } } @@ -254,13 +254,13 @@ static void power4_handle_interrupt(stru mtmsrd(mfmsr() | MSR_PMM); for (i = 0; i < cur_cpu_spec->num_pmcs; ++i) { - val = ctr_read(i); + val = classic_ctr_read(i); if (val < 0) { if (oprofile_running && ctr[i].enabled) { oprofile_add_ext_sample(pc, regs, i, is_kernel); - ctr_write(i, reset_value[i]); + classic_ctr_write(i, reset_value[i]); } else { - ctr_write(i, 0); + classic_ctr_write(i, 0); } } } diff --git a/arch/powerpc/oprofile/op_model_rs64.c b/arch/powerpc/oprofile/op_model_rs64.c index 19c5ee0..c731acb 100644 --- a/arch/powerpc/oprofile/op_model_rs64.c +++ b/arch/powerpc/oprofile/op_model_rs64.c @@ -137,10 +137,10 @@ static void rs64_start(struct op_counter for (i = 0; i < num_counters; ++i) { if (ctr[i].enabled) { - ctr_write(i, reset_value[i]); + classic_ctr_write(i, reset_value[i]); ctrl_write(i, ctr[i].event); } else { - ctr_write(i, 0); + classic_ctr_write(i, 0); } } @@ -186,13 +186,13 @@ static void rs64_handle_interrupt(struct mtmsrd(mfmsr() | MSR_PMM); for (i = 0; i < num_counters; ++i) { - val = ctr_read(i); + val = classic_ctr_read(i); if (val < 0) { if (ctr[i].enabled) { oprofile_add_ext_sample(pc, regs, i, is_kernel); - ctr_write(i, reset_value[i]); + classic_ctr_write(i, reset_value[i]); } else { - ctr_write(i, 0); + classic_ctr_write(i, 0); } } } diff --git a/arch/powerpc/platforms/52xx/Makefile b/arch/powerpc/platforms/52xx/Makefile index a46184a..07cdbca 100644 --- a/arch/powerpc/platforms/52xx/Makefile +++ b/arch/powerpc/platforms/52xx/Makefile @@ -3,7 +3,8 @@ # Makefile for 52xx based boards # ifeq ($(CONFIG_PPC_MERGE),y) obj-y += mpc52xx_pic.o mpc52xx_common.o +obj-$(CONFIG_PCI) += mpc52xx_pci.o endif -obj-$(CONFIG_PPC_EFIKA) += efika-setup.o efika-pci.o +obj-$(CONFIG_PPC_EFIKA) += efika.o obj-$(CONFIG_PPC_LITE5200) += lite5200.o diff --git a/arch/powerpc/platforms/52xx/efika-pci.c b/arch/powerpc/platforms/52xx/efika-pci.c deleted file mode 100644 index 62e05b2..0000000 --- a/arch/powerpc/platforms/52xx/efika-pci.c +++ /dev/null @@ -1,119 +0,0 @@ - -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include - -#include "efika.h" - -#ifdef CONFIG_PCI -/* - * Access functions for PCI config space using RTAS calls. - */ -static int rtas_read_config(struct pci_bus *bus, unsigned int devfn, int offset, - int len, u32 * val) -{ - struct pci_controller *hose = bus->sysdata; - unsigned long addr = (offset & 0xff) | ((devfn & 0xff) << 8) - | (((bus->number - hose->first_busno) & 0xff) << 16) - | (hose->index << 24); - int ret = -1; - int rval; - - rval = rtas_call(rtas_token("read-pci-config"), 2, 2, &ret, addr, len); - *val = ret; - return rval ? PCIBIOS_DEVICE_NOT_FOUND : PCIBIOS_SUCCESSFUL; -} - -static int rtas_write_config(struct pci_bus *bus, unsigned int devfn, - int offset, int len, u32 val) -{ - struct pci_controller *hose = bus->sysdata; - unsigned long addr = (offset & 0xff) | ((devfn & 0xff) << 8) - | (((bus->number - hose->first_busno) & 0xff) << 16) - | (hose->index << 24); - int rval; - - rval = rtas_call(rtas_token("write-pci-config"), 3, 1, NULL, - addr, len, val); - return rval ? PCIBIOS_DEVICE_NOT_FOUND : PCIBIOS_SUCCESSFUL; -} - -static struct pci_ops rtas_pci_ops = { - rtas_read_config, - rtas_write_config -}; - -void __init efika_pcisetup(void) -{ - const int *bus_range; - int len; - struct pci_controller *hose; - struct device_node *root; - struct device_node *pcictrl; - - root = of_find_node_by_path("/"); - if (root == NULL) { - printk(KERN_WARNING EFIKA_PLATFORM_NAME - ": Unable to find the root node\n"); - return; - } - - for (pcictrl = NULL;;) { - pcictrl = of_get_next_child(root, pcictrl); - if ((pcictrl == NULL) || (strcmp(pcictrl->name, "pci") == 0)) - break; - } - - of_node_put(root); - - if (pcictrl == NULL) { - printk(KERN_WARNING EFIKA_PLATFORM_NAME - ": Unable to find the PCI bridge node\n"); - return; - } - - bus_range = get_property(pcictrl, "bus-range", &len); - if (bus_range == NULL || len < 2 * sizeof(int)) { - printk(KERN_WARNING EFIKA_PLATFORM_NAME - ": Can't get bus-range for %s\n", pcictrl->full_name); - return; - } - - if (bus_range[1] == bus_range[0]) - printk(KERN_INFO EFIKA_PLATFORM_NAME ": PCI bus %d", - bus_range[0]); - else - printk(KERN_INFO EFIKA_PLATFORM_NAME ": PCI buses %d..%d", - bus_range[0], bus_range[1]); - printk(" controlled by %s\n", pcictrl->full_name); - printk("\n"); - - hose = pcibios_alloc_controller(); - if (!hose) { - printk(KERN_WARNING EFIKA_PLATFORM_NAME - ": Can't allocate PCI controller structure for %s\n", - pcictrl->full_name); - return; - } - - hose->arch_data = of_node_get(pcictrl); - hose->first_busno = bus_range[0]; - hose->last_busno = bus_range[1]; - hose->ops = &rtas_pci_ops; - - pci_process_bridge_OF_ranges(hose, pcictrl, 0); -} - -#else -void __init efika_pcisetup(void) -{} -#endif diff --git a/arch/powerpc/platforms/52xx/efika-setup.c b/arch/powerpc/platforms/52xx/efika-setup.c deleted file mode 100644 index 110c980..0000000 --- a/arch/powerpc/platforms/52xx/efika-setup.c +++ /dev/null @@ -1,150 +0,0 @@ -/* - * - * Efika 5K2 platform setup - * Some code really inspired from the lite5200b platform. - * - * Copyright (C) 2006 bplan GmbH - * - * This file is licensed under the terms of the GNU General Public License - * version 2. This program is licensed "as is" without any warranty of any - * kind, whether express or implied. - * - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include - -#include "efika.h" - -static void efika_show_cpuinfo(struct seq_file *m) -{ - struct device_node *root; - const char *revision = NULL; - const char *codegendescription = NULL; - const char *codegenvendor = NULL; - - root = of_find_node_by_path("/"); - if (root) { - revision = get_property(root, "revision", NULL); - codegendescription = - get_property(root, "CODEGEN,description", NULL); - codegenvendor = get_property(root, "CODEGEN,vendor", NULL); - - of_node_put(root); - } - - if (codegendescription) - seq_printf(m, "machine\t\t: %s\n", codegendescription); - else - seq_printf(m, "machine\t\t: Efika\n"); - - if (revision) - seq_printf(m, "revision\t: %s\n", revision); - - if (codegenvendor) - seq_printf(m, "vendor\t\t: %s\n", codegenvendor); - - of_node_put(root); -} - -static void __init efika_setup_arch(void) -{ - rtas_initialize(); - -#ifdef CONFIG_BLK_DEV_INITRD - initrd_below_start_ok = 1; - - if (initrd_start) - ROOT_DEV = Root_RAM0; - else -#endif - ROOT_DEV = Root_SDA2; /* sda2 (sda1 is for the kernel) */ - - efika_pcisetup(); - - if (ppc_md.progress) - ppc_md.progress("Linux/PPC " UTS_RELEASE " runnung on Efika ;-)\n", 0x0); -} - -static void __init efika_init(void) -{ - struct device_node *np; - struct device_node *cnp = NULL; - const u32 *base; - - /* Find every child of the SOC node and add it to of_platform */ - np = of_find_node_by_name(NULL, "builtin"); - if (np) { - char name[BUS_ID_SIZE]; - while ((cnp = of_get_next_child(np, cnp))) { - strcpy(name, cnp->name); - - base = get_property(cnp, "reg", NULL); - if (base == NULL) - continue; - - snprintf(name+strlen(name), BUS_ID_SIZE, "@%x", *base); - of_platform_device_create(cnp, name, NULL); - - printk(KERN_INFO EFIKA_PLATFORM_NAME" : Added %s (type '%s' at '%s') to the known devices\n", name, cnp->type, cnp->full_name); - } - } - - if (ppc_md.progress) - ppc_md.progress(" Have fun with your Efika! ", 0x7777); -} - -static int __init efika_probe(void) -{ - char *model = of_get_flat_dt_prop(of_get_flat_dt_root(), - "model", NULL); - - if (model == NULL) - return 0; - if (strcmp(model, "EFIKA5K2")) - return 0; - - ISA_DMA_THRESHOLD = ~0L; - DMA_MODE_READ = 0x44; - DMA_MODE_WRITE = 0x48; - - return 1; -} - -define_machine(efika) -{ - .name = EFIKA_PLATFORM_NAME, - .probe = efika_probe, - .setup_arch = efika_setup_arch, - .init = efika_init, - .show_cpuinfo = efika_show_cpuinfo, - .init_IRQ = mpc52xx_init_irq, - .get_irq = mpc52xx_get_irq, - .restart = rtas_restart, - .power_off = rtas_power_off, - .halt = rtas_halt, - .set_rtc_time = rtas_set_rtc_time, - .get_rtc_time = rtas_get_rtc_time, - .progress = rtas_progress, - .get_boot_time = rtas_get_boot_time, - .calibrate_decr = generic_calibrate_decr, - .phys_mem_access_prot = pci_phys_mem_access_prot, -}; diff --git a/arch/powerpc/platforms/52xx/efika.c b/arch/powerpc/platforms/52xx/efika.c new file mode 100644 index 0000000..8de0341 --- /dev/null +++ b/arch/powerpc/platforms/52xx/efika.c @@ -0,0 +1,243 @@ +/* + * Efika 5K2 platform code + * Some code really inspired from the lite5200b platform. + * + * Copyright (C) 2006 bplan GmbH + * + * This file is licensed under the terms of the GNU General Public License + * version 2. This program is licensed "as is" without any warranty of any + * kind, whether express or implied. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +#define EFIKA_PLATFORM_NAME "Efika" + + +/* ------------------------------------------------------------------------ */ +/* PCI accesses thru RTAS */ +/* ------------------------------------------------------------------------ */ + +#ifdef CONFIG_PCI + +/* + * Access functions for PCI config space using RTAS calls. + */ +static int rtas_read_config(struct pci_bus *bus, unsigned int devfn, int offset, + int len, u32 * val) +{ + struct pci_controller *hose = bus->sysdata; + unsigned long addr = (offset & 0xff) | ((devfn & 0xff) << 8) + | (((bus->number - hose->first_busno) & 0xff) << 16) + | (hose->index << 24); + int ret = -1; + int rval; + + rval = rtas_call(rtas_token("read-pci-config"), 2, 2, &ret, addr, len); + *val = ret; + return rval ? PCIBIOS_DEVICE_NOT_FOUND : PCIBIOS_SUCCESSFUL; +} + +static int rtas_write_config(struct pci_bus *bus, unsigned int devfn, + int offset, int len, u32 val) +{ + struct pci_controller *hose = bus->sysdata; + unsigned long addr = (offset & 0xff) | ((devfn & 0xff) << 8) + | (((bus->number - hose->first_busno) & 0xff) << 16) + | (hose->index << 24); + int rval; + + rval = rtas_call(rtas_token("write-pci-config"), 3, 1, NULL, + addr, len, val); + return rval ? PCIBIOS_DEVICE_NOT_FOUND : PCIBIOS_SUCCESSFUL; +} + +static struct pci_ops rtas_pci_ops = { + rtas_read_config, + rtas_write_config +}; + + +void __init efika_pcisetup(void) +{ + const int *bus_range; + int len; + struct pci_controller *hose; + struct device_node *root; + struct device_node *pcictrl; + + root = of_find_node_by_path("/"); + if (root == NULL) { + printk(KERN_WARNING EFIKA_PLATFORM_NAME + ": Unable to find the root node\n"); + return; + } + + for (pcictrl = NULL;;) { + pcictrl = of_get_next_child(root, pcictrl); + if ((pcictrl == NULL) || (strcmp(pcictrl->name, "pci") == 0)) + break; + } + + of_node_put(root); + + if (pcictrl == NULL) { + printk(KERN_WARNING EFIKA_PLATFORM_NAME + ": Unable to find the PCI bridge node\n"); + return; + } + + bus_range = get_property(pcictrl, "bus-range", &len); + if (bus_range == NULL || len < 2 * sizeof(int)) { + printk(KERN_WARNING EFIKA_PLATFORM_NAME + ": Can't get bus-range for %s\n", pcictrl->full_name); + return; + } + + if (bus_range[1] == bus_range[0]) + printk(KERN_INFO EFIKA_PLATFORM_NAME ": PCI bus %d", + bus_range[0]); + else + printk(KERN_INFO EFIKA_PLATFORM_NAME ": PCI buses %d..%d", + bus_range[0], bus_range[1]); + printk(" controlled by %s\n", pcictrl->full_name); + printk("\n"); + + hose = pcibios_alloc_controller(); + if (!hose) { + printk(KERN_WARNING EFIKA_PLATFORM_NAME + ": Can't allocate PCI controller structure for %s\n", + pcictrl->full_name); + return; + } + + hose->arch_data = of_node_get(pcictrl); + hose->first_busno = bus_range[0]; + hose->last_busno = bus_range[1]; + hose->ops = &rtas_pci_ops; + + pci_process_bridge_OF_ranges(hose, pcictrl, 0); +} + +#else +void __init efika_pcisetup(void) +{} +#endif + + + +/* ------------------------------------------------------------------------ */ +/* Platform setup */ +/* ------------------------------------------------------------------------ */ + +static void efika_show_cpuinfo(struct seq_file *m) +{ + struct device_node *root; + const char *revision = NULL; + const char *codegendescription = NULL; + const char *codegenvendor = NULL; + + root = of_find_node_by_path("/"); + if (!root) + return; + + revision = get_property(root, "revision", NULL); + codegendescription = + get_property(root, "CODEGEN,description", NULL); + codegenvendor = get_property(root, "CODEGEN,vendor", NULL); + + if (codegendescription) + seq_printf(m, "machine\t\t: %s\n", codegendescription); + else + seq_printf(m, "machine\t\t: Efika\n"); + + if (revision) + seq_printf(m, "revision\t: %s\n", revision); + + if (codegenvendor) + seq_printf(m, "vendor\t\t: %s\n", codegenvendor); + + of_node_put(root); +} + +static void __init efika_setup_arch(void) +{ + rtas_initialize(); + +#ifdef CONFIG_BLK_DEV_INITRD + initrd_below_start_ok = 1; + + if (initrd_start) + ROOT_DEV = Root_RAM0; + else +#endif + ROOT_DEV = Root_SDA2; /* sda2 (sda1 is for the kernel) */ + + efika_pcisetup(); + + if (ppc_md.progress) + ppc_md.progress("Linux/PPC " UTS_RELEASE " running on Efika ;-)\n", 0x0); +} + +static int __init efika_probe(void) +{ + char *model = of_get_flat_dt_prop(of_get_flat_dt_root(), + "model", NULL); + + if (model == NULL) + return 0; + if (strcmp(model, "EFIKA5K2")) + return 0; + + ISA_DMA_THRESHOLD = ~0L; + DMA_MODE_READ = 0x44; + DMA_MODE_WRITE = 0x48; + + return 1; +} + +define_machine(efika) +{ + .name = EFIKA_PLATFORM_NAME, + .probe = efika_probe, + .setup_arch = efika_setup_arch, + .init = mpc52xx_declare_of_platform_devices, + .show_cpuinfo = efika_show_cpuinfo, + .init_IRQ = mpc52xx_init_irq, + .get_irq = mpc52xx_get_irq, + .restart = rtas_restart, + .power_off = rtas_power_off, + .halt = rtas_halt, + .set_rtc_time = rtas_set_rtc_time, + .get_rtc_time = rtas_get_rtc_time, + .progress = rtas_progress, + .get_boot_time = rtas_get_boot_time, + .calibrate_decr = generic_calibrate_decr, + .phys_mem_access_prot = pci_phys_mem_access_prot, +}; + diff --git a/arch/powerpc/platforms/52xx/efika.h b/arch/powerpc/platforms/52xx/efika.h deleted file mode 100644 index 2f060fd..0000000 --- a/arch/powerpc/platforms/52xx/efika.h +++ /dev/null @@ -1,19 +0,0 @@ -/* - * Efika 5K2 platform setup - Header file - * - * Copyright (C) 2006 bplan GmbH - * - * This file is licensed under the terms of the GNU General Public License - * version 2. This program is licensed "as is" without any warranty of any - * kind, whether express or implied. - * - */ - -#ifndef __ARCH_POWERPC_EFIKA__ -#define __ARCH_POWERPC_EFIKA__ - -#define EFIKA_PLATFORM_NAME "Efika" - -extern void __init efika_pcisetup(void); - -#endif diff --git a/arch/powerpc/platforms/52xx/lite5200.c b/arch/powerpc/platforms/52xx/lite5200.c index 0f21bab..cc3b40d 100644 --- a/arch/powerpc/platforms/52xx/lite5200.c +++ b/arch/powerpc/platforms/52xx/lite5200.c @@ -51,13 +51,13 @@ #include */ static void __init -lite52xx_setup_cpu(void) +lite5200_setup_cpu(void) { struct mpc52xx_gpio __iomem *gpio; u32 port_config; /* Map zones */ - gpio = mpc52xx_find_and_map("mpc52xx-gpio"); + gpio = mpc52xx_find_and_map("mpc5200-gpio"); if (!gpio) { printk(KERN_ERR __FILE__ ": " "Error while mapping GPIO register for port config. " @@ -85,12 +85,12 @@ error: iounmap(gpio); } -static void __init lite52xx_setup_arch(void) +static void __init lite5200_setup_arch(void) { struct device_node *np; if (ppc_md.progress) - ppc_md.progress("lite52xx_setup_arch()", 0); + ppc_md.progress("lite5200_setup_arch()", 0); np = of_find_node_by_type(NULL, "cpu"); if (np) { @@ -105,7 +105,13 @@ static void __init lite52xx_setup_arch(v /* CPU & Port mux setup */ mpc52xx_setup_cpu(); /* Generic */ - lite52xx_setup_cpu(); /* Platorm specific */ + lite5200_setup_cpu(); /* Platorm specific */ + +#ifdef CONFIG_PCI + np = of_find_node_by_type(np, "pci"); + if (np) + mpc52xx_add_bridge(np); +#endif #ifdef CONFIG_BLK_DEV_INITRD if (initrd_start) @@ -120,7 +126,7 @@ #endif } -void lite52xx_show_cpuinfo(struct seq_file *m) +void lite5200_show_cpuinfo(struct seq_file *m) { struct device_node* np = of_find_all_nodes(NULL); const char *model = NULL; @@ -137,25 +143,26 @@ void lite52xx_show_cpuinfo(struct seq_fi /* * Called very early, MMU is off, device-tree isn't unflattened */ -static int __init lite52xx_probe(void) +static int __init lite5200_probe(void) { unsigned long node = of_get_flat_dt_root(); const char *model = of_get_flat_dt_prop(node, "model", NULL); - if (!of_flat_dt_is_compatible(node, "lite52xx")) + if (!of_flat_dt_is_compatible(node, "fsl,lite5200") && + !of_flat_dt_is_compatible(node, "fsl,lite5200b")) return 0; - pr_debug("%s board w/ mpc52xx found\n", model ? model : "unknown"); + pr_debug("%s board found\n", model ? model : "unknown"); return 1; } -define_machine(lite52xx) { - .name = "lite52xx", - .probe = lite52xx_probe, - .setup_arch = lite52xx_setup_arch, +define_machine(lite5200) { + .name = "lite5200", + .probe = lite5200_probe, + .setup_arch = lite5200_setup_arch, .init = mpc52xx_declare_of_platform_devices, .init_IRQ = mpc52xx_init_irq, .get_irq = mpc52xx_get_irq, - .show_cpuinfo = lite52xx_show_cpuinfo, + .show_cpuinfo = lite5200_show_cpuinfo, .calibrate_decr = generic_calibrate_decr, }; diff --git a/arch/powerpc/platforms/52xx/mpc52xx_common.c b/arch/powerpc/platforms/52xx/mpc52xx_common.c index cc40889..ed0cb69 100644 --- a/arch/powerpc/platforms/52xx/mpc52xx_common.c +++ b/arch/powerpc/platforms/52xx/mpc52xx_common.c @@ -83,8 +83,8 @@ mpc52xx_setup_cpu(void) struct mpc52xx_xlb __iomem *xlb; /* Map zones */ - cdm = mpc52xx_find_and_map("mpc52xx-cdm"); - xlb = mpc52xx_find_and_map("mpc52xx-xlb"); + cdm = mpc52xx_find_and_map("mpc5200-cdm"); + xlb = mpc52xx_find_and_map("mpc5200-xlb"); if (!cdm || !xlb) { printk(KERN_ERR __FILE__ ": " diff --git a/arch/powerpc/platforms/52xx/mpc52xx_pci.c b/arch/powerpc/platforms/52xx/mpc52xx_pci.c new file mode 100644 index 0000000..faf161b --- /dev/null +++ b/arch/powerpc/platforms/52xx/mpc52xx_pci.c @@ -0,0 +1,412 @@ +/* + * PCI code for the Freescale MPC52xx embedded CPU. + * + * Copyright (C) 2006 Secret Lab Technologies Ltd. + * Grant Likely + * Copyright (C) 2004 Sylvain Munaut + * + * This file is licensed under the terms of the GNU General Public License + * version 2. This program is licensed "as is" without any warranty of any + * kind, whether express or implied. + */ + +#undef DEBUG + +#include +#include +#include +#include +#include + + +/* ======================================================================== */ +/* PCI windows config */ +/* ======================================================================== */ + +#define MPC52xx_PCI_TARGET_IO 0xf0000000 +#define MPC52xx_PCI_TARGET_MEM 0x00000000 + + +/* ======================================================================== */ +/* Structures mapping & Defines for PCI Unit */ +/* ======================================================================== */ + +#define MPC52xx_PCI_GSCR_BM 0x40000000 +#define MPC52xx_PCI_GSCR_PE 0x20000000 +#define MPC52xx_PCI_GSCR_SE 0x10000000 +#define MPC52xx_PCI_GSCR_XLB2PCI_MASK 0x07000000 +#define MPC52xx_PCI_GSCR_XLB2PCI_SHIFT 24 +#define MPC52xx_PCI_GSCR_IPG2PCI_MASK 0x00070000 +#define MPC52xx_PCI_GSCR_IPG2PCI_SHIFT 16 +#define MPC52xx_PCI_GSCR_BME 0x00004000 +#define MPC52xx_PCI_GSCR_PEE 0x00002000 +#define MPC52xx_PCI_GSCR_SEE 0x00001000 +#define MPC52xx_PCI_GSCR_PR 0x00000001 + + +#define MPC52xx_PCI_IWBTAR_TRANSLATION(proc_ad,pci_ad,size) \ + ( ( (proc_ad) & 0xff000000 ) | \ + ( (((size) - 1) >> 8) & 0x00ff0000 ) | \ + ( ((pci_ad) >> 16) & 0x0000ff00 ) ) + +#define MPC52xx_PCI_IWCR_PACK(win0,win1,win2) (((win0) << 24) | \ + ((win1) << 16) | \ + ((win2) << 8)) + +#define MPC52xx_PCI_IWCR_DISABLE 0x0 +#define MPC52xx_PCI_IWCR_ENABLE 0x1 +#define MPC52xx_PCI_IWCR_READ 0x0 +#define MPC52xx_PCI_IWCR_READ_LINE 0x2 +#define MPC52xx_PCI_IWCR_READ_MULTI 0x4 +#define MPC52xx_PCI_IWCR_MEM 0x0 +#define MPC52xx_PCI_IWCR_IO 0x8 + +#define MPC52xx_PCI_TCR_P 0x01000000 +#define MPC52xx_PCI_TCR_LD 0x00010000 + +#define MPC52xx_PCI_TBATR_DISABLE 0x0 +#define MPC52xx_PCI_TBATR_ENABLE 0x1 + +struct mpc52xx_pci { + u32 idr; /* PCI + 0x00 */ + u32 scr; /* PCI + 0x04 */ + u32 ccrir; /* PCI + 0x08 */ + u32 cr1; /* PCI + 0x0C */ + u32 bar0; /* PCI + 0x10 */ + u32 bar1; /* PCI + 0x14 */ + u8 reserved1[16]; /* PCI + 0x18 */ + u32 ccpr; /* PCI + 0x28 */ + u32 sid; /* PCI + 0x2C */ + u32 erbar; /* PCI + 0x30 */ + u32 cpr; /* PCI + 0x34 */ + u8 reserved2[4]; /* PCI + 0x38 */ + u32 cr2; /* PCI + 0x3C */ + u8 reserved3[32]; /* PCI + 0x40 */ + u32 gscr; /* PCI + 0x60 */ + u32 tbatr0; /* PCI + 0x64 */ + u32 tbatr1; /* PCI + 0x68 */ + u32 tcr; /* PCI + 0x6C */ + u32 iw0btar; /* PCI + 0x70 */ + u32 iw1btar; /* PCI + 0x74 */ + u32 iw2btar; /* PCI + 0x78 */ + u8 reserved4[4]; /* PCI + 0x7C */ + u32 iwcr; /* PCI + 0x80 */ + u32 icr; /* PCI + 0x84 */ + u32 isr; /* PCI + 0x88 */ + u32 arb; /* PCI + 0x8C */ + u8 reserved5[104]; /* PCI + 0x90 */ + u32 car; /* PCI + 0xF8 */ + u8 reserved6[4]; /* PCI + 0xFC */ +}; + + +/* ======================================================================== */ +/* PCI configuration acess */ +/* ======================================================================== */ + +static int +mpc52xx_pci_read_config(struct pci_bus *bus, unsigned int devfn, + int offset, int len, u32 *val) +{ + struct pci_controller *hose = bus->sysdata; + u32 value; + + if (ppc_md.pci_exclude_device) + if (ppc_md.pci_exclude_device(bus->number, devfn)) + return PCIBIOS_DEVICE_NOT_FOUND; + + out_be32(hose->cfg_addr, + (1 << 31) | + ((bus->number - hose->bus_offset) << 16) | + (devfn << 8) | + (offset & 0xfc)); + mb(); + +#if defined(CONFIG_PPC_MPC5200_BUGFIX) + if (bus->number != hose->bus_offset) { + /* workaround for the bug 435 of the MPC5200 (L25R); + * Don't do 32 bits config access during type-1 cycles */ + switch (len) { + case 1: + value = in_8(((u8 __iomem *)hose->cfg_data) + + (offset & 3)); + break; + case 2: + value = in_le16(((u16 __iomem *)hose->cfg_data) + + ((offset>>1) & 1)); + break; + + default: + value = in_le16((u16 __iomem *)hose->cfg_data) | + (in_le16(((u16 __iomem *)hose->cfg_data) + 1) << 16); + break; + } + } + else +#endif + { + value = in_le32(hose->cfg_data); + + if (len != 4) { + value >>= ((offset & 0x3) << 3); + value &= 0xffffffff >> (32 - (len << 3)); + } + } + + *val = value; + + out_be32(hose->cfg_addr, 0); + mb(); + + return PCIBIOS_SUCCESSFUL; +} + +static int +mpc52xx_pci_write_config(struct pci_bus *bus, unsigned int devfn, + int offset, int len, u32 val) +{ + struct pci_controller *hose = bus->sysdata; + u32 value, mask; + + if (ppc_md.pci_exclude_device) + if (ppc_md.pci_exclude_device(bus->number, devfn)) + return PCIBIOS_DEVICE_NOT_FOUND; + + out_be32(hose->cfg_addr, + (1 << 31) | + ((bus->number - hose->bus_offset) << 16) | + (devfn << 8) | + (offset & 0xfc)); + mb(); + +#if defined(CONFIG_PPC_MPC5200_BUGFIX) + if (bus->number != hose->bus_offset) { + /* workaround for the bug 435 of the MPC5200 (L25R); + * Don't do 32 bits config access during type-1 cycles */ + switch (len) { + case 1: + out_8(((u8 __iomem *)hose->cfg_data) + + (offset & 3), val); + break; + case 2: + out_le16(((u16 __iomem *)hose->cfg_data) + + ((offset>>1) & 1), val); + break; + + default: + out_le16((u16 __iomem *)hose->cfg_data, + (u16)val); + out_le16(((u16 __iomem *)hose->cfg_data) + 1, + (u16)(val>>16)); + break; + } + } + else +#endif + { + if (len != 4) { + value = in_le32(hose->cfg_data); + + offset = (offset & 0x3) << 3; + mask = (0xffffffff >> (32 - (len << 3))); + mask <<= offset; + + value &= ~mask; + val = value | ((val << offset) & mask); + } + + out_le32(hose->cfg_data, val); + } + mb(); + + out_be32(hose->cfg_addr, 0); + mb(); + + return PCIBIOS_SUCCESSFUL; +} + +static struct pci_ops mpc52xx_pci_ops = { + .read = mpc52xx_pci_read_config, + .write = mpc52xx_pci_write_config +}; + + +/* ======================================================================== */ +/* PCI setup */ +/* ======================================================================== */ + +static void __init +mpc52xx_pci_setup(struct pci_controller *hose, + struct mpc52xx_pci __iomem *pci_regs) +{ + struct resource *res; + u32 tmp; + int iwcr0 = 0, iwcr1 = 0, iwcr2 = 0; + + pr_debug("mpc52xx_pci_setup(hose=%p, pci_regs=%p)\n", hose, pci_regs); + + /* pci_process_bridge_OF_ranges() found all our addresses for us; + * now store them in the right places */ + hose->cfg_addr = &pci_regs->car; + hose->cfg_data = hose->io_base_virt; + + /* Control regs */ + tmp = in_be32(&pci_regs->scr); + tmp |= PCI_COMMAND_MASTER | PCI_COMMAND_MEMORY; + out_be32(&pci_regs->scr, tmp); + + /* Memory windows */ + res = &hose->mem_resources[0]; + if (res->flags) { + pr_debug("mem_resource[0] = {.start=%x, .end=%x, .flags=%lx}\n", + res->start, res->end, res->flags); + out_be32(&pci_regs->iw0btar, + MPC52xx_PCI_IWBTAR_TRANSLATION(res->start, res->start, + res->end - res->start + 1)); + iwcr0 = MPC52xx_PCI_IWCR_ENABLE | MPC52xx_PCI_IWCR_MEM; + if (res->flags & IORESOURCE_PREFETCH) + iwcr0 |= MPC52xx_PCI_IWCR_READ_MULTI; + else + iwcr0 |= MPC52xx_PCI_IWCR_READ; + } + + res = &hose->mem_resources[1]; + if (res->flags) { + pr_debug("mem_resource[1] = {.start=%x, .end=%x, .flags=%lx}\n", + res->start, res->end, res->flags); + out_be32(&pci_regs->iw1btar, + MPC52xx_PCI_IWBTAR_TRANSLATION(res->start, res->start, + res->end - res->start + 1)); + iwcr1 = MPC52xx_PCI_IWCR_ENABLE | MPC52xx_PCI_IWCR_MEM; + if (res->flags & IORESOURCE_PREFETCH) + iwcr1 |= MPC52xx_PCI_IWCR_READ_MULTI; + else + iwcr1 |= MPC52xx_PCI_IWCR_READ; + } + + /* IO resources */ + res = &hose->io_resource; + if (!res) { + printk(KERN_ERR "%s: Didn't find IO resources\n", __FILE__); + return; + } + pr_debug(".io_resource={.start=%x,.end=%x,.flags=%lx} " + ".io_base_phys=0x%p\n", + res->start, res->end, res->flags, (void*)hose->io_base_phys); + out_be32(&pci_regs->iw2btar, + MPC52xx_PCI_IWBTAR_TRANSLATION(hose->io_base_phys, + res->start, + res->end - res->start + 1)); + iwcr2 = MPC52xx_PCI_IWCR_ENABLE | MPC52xx_PCI_IWCR_IO; + + /* Set all the IWCR fields at once; they're in the same reg */ + out_be32(&pci_regs->iwcr, MPC52xx_PCI_IWCR_PACK(iwcr0, iwcr1, iwcr2)); + + out_be32(&pci_regs->tbatr0, + MPC52xx_PCI_TBATR_ENABLE | MPC52xx_PCI_TARGET_IO ); + out_be32(&pci_regs->tbatr1, + MPC52xx_PCI_TBATR_ENABLE | MPC52xx_PCI_TARGET_MEM ); + + out_be32(&pci_regs->tcr, MPC52xx_PCI_TCR_LD); + + tmp = in_be32(&pci_regs->gscr); +#if 0 + /* Reset the exteral bus ( internal PCI controller is NOT resetted ) */ + /* Not necessary and can be a bad thing if for example the bootloader + is displaying a splash screen or ... Just left here for + documentation purpose if anyone need it */ + out_be32(&pci_regs->gscr, tmp | MPC52xx_PCI_GSCR_PR); + udelay(50); +#endif + + /* Make sure the PCI bridge is out of reset */ + out_be32(&pci_regs->gscr, tmp & ~MPC52xx_PCI_GSCR_PR); +} + +static void +mpc52xx_pci_fixup_resources(struct pci_dev *dev) +{ + int i; + + pr_debug("mpc52xx_pci_fixup_resources() %.4x:%.4x\n", + dev->vendor, dev->device); + + /* We don't rely on boot loader for PCI and resets all + devices */ + for (i = 0; i < DEVICE_COUNT_RESOURCE; i++) { + struct resource *res = &dev->resource[i]; + if (res->end > res->start) { /* Only valid resources */ + res->end -= res->start; + res->start = 0; + res->flags |= IORESOURCE_UNSET; + } + } + + /* The PCI Host bridge of MPC52xx has a prefetch memory resource + fixed to 1Gb. Doesn't fit in the resource system so we remove it */ + if ( (dev->vendor == PCI_VENDOR_ID_MOTOROLA) && + ( dev->device == PCI_DEVICE_ID_MOTOROLA_MPC5200 + || dev->device == PCI_DEVICE_ID_MOTOROLA_MPC5200B) ) { + struct resource *res = &dev->resource[1]; + res->start = res->end = res->flags = 0; + } +} + +int __init +mpc52xx_add_bridge(struct device_node *node) +{ + int len; + struct mpc52xx_pci __iomem *pci_regs; + struct pci_controller *hose; + const int *bus_range; + struct resource rsrc; + + pr_debug("Adding MPC52xx PCI host bridge %s\n", node->full_name); + + pci_assign_all_buses = 1; + + if (of_address_to_resource(node, 0, &rsrc) != 0) { + printk(KERN_ERR "Can't get %s resources\n", node->full_name); + return -EINVAL; + } + + bus_range = get_property(node, "bus-range", &len); + if (bus_range == NULL || len < 2 * sizeof(int)) { + printk(KERN_WARNING "Can't get %s bus-range, assume bus 0\n", + node->full_name); + bus_range = NULL; + } + + /* There are some PCI quirks on the 52xx, register the hook to + * fix them. */ + ppc_md.pcibios_fixup_resources = mpc52xx_pci_fixup_resources; + + /* Alloc and initialize the pci controller. Values in the device + * tree are needed to configure the 52xx PCI controller. Rather + * than parse the tree here, let pci_process_bridge_OF_ranges() + * do it for us and extract the values after the fact */ + hose = pcibios_alloc_controller(); + if (!hose) + return -ENOMEM; + + hose->arch_data = node; + hose->set_cfg_type = 1; + + hose->first_busno = bus_range ? bus_range[0] : 0; + hose->last_busno = bus_range ? bus_range[1] : 0xff; + + hose->bus_offset = 0; + hose->ops = &mpc52xx_pci_ops; + + pci_regs = ioremap(rsrc.start, rsrc.end - rsrc.start + 1); + if (!pci_regs) + return -ENOMEM; + + pci_process_bridge_OF_ranges(hose, node, 1); + + /* Finish setting up PCI using values obtained by + * pci_proces_bridge_OF_ranges */ + mpc52xx_pci_setup(hose, pci_regs); + + return 0; +} diff --git a/arch/powerpc/platforms/52xx/mpc52xx_pic.c b/arch/powerpc/platforms/52xx/mpc52xx_pic.c index cd91a6c..c751925 100644 --- a/arch/powerpc/platforms/52xx/mpc52xx_pic.c +++ b/arch/powerpc/platforms/52xx/mpc52xx_pic.c @@ -383,16 +383,16 @@ void __init mpc52xx_init_irq(void) struct device_node *picnode; /* Remap the necessary zones */ - picnode = of_find_compatible_node(NULL, NULL, "mpc52xx-pic"); + picnode = of_find_compatible_node(NULL, NULL, "mpc5200-pic"); - intr = mpc52xx_find_and_map("mpc52xx-pic"); + intr = mpc52xx_find_and_map("mpc5200-pic"); if (!intr) - panic(__FILE__ ": find_and_map failed on 'mpc52xx-pic'. " + panic(__FILE__ ": find_and_map failed on 'mpc5200-pic'. " "Check node !"); - sdma = mpc52xx_find_and_map("mpc52xx-bestcomm"); + sdma = mpc52xx_find_and_map("mpc5200-bestcomm"); if (!sdma) - panic(__FILE__ ": find_and_map failed on 'mpc52xx-bestcomm'. " + panic(__FILE__ ": find_and_map failed on 'mpc5200-bestcomm'. " "Check node !"); /* Disable all interrupt sources. */ diff --git a/arch/powerpc/platforms/82xx/mpc82xx.c b/arch/powerpc/platforms/82xx/mpc82xx.c index 0f5b30d..74e7892 100644 --- a/arch/powerpc/platforms/82xx/mpc82xx.c +++ b/arch/powerpc/platforms/82xx/mpc82xx.c @@ -50,7 +50,7 @@ #include #include #include -#include "pq2ads_pd.h" +#include "pq2ads.h" static int __init get_freq(char *name, unsigned long *val) { diff --git a/arch/powerpc/platforms/82xx/mpc82xx_ads.c b/arch/powerpc/platforms/82xx/mpc82xx_ads.c index ea880f1..7334c1a 100644 --- a/arch/powerpc/platforms/82xx/mpc82xx_ads.c +++ b/arch/powerpc/platforms/82xx/mpc82xx_ads.c @@ -51,7 +51,7 @@ #include #include #include <../sysdev/cpm2_pic.h> -#include "pq2ads_pd.h" +#include "pq2ads.h" #ifdef CONFIG_PCI static uint pci_clk_frq; diff --git a/arch/powerpc/platforms/82xx/pq2ads.h b/arch/powerpc/platforms/82xx/pq2ads.h index fb2f92b..5b5cca6 100644 --- a/arch/powerpc/platforms/82xx/pq2ads.h +++ b/arch/powerpc/platforms/82xx/pq2ads.h @@ -22,6 +22,7 @@ #ifdef __KERNEL__ #ifndef __MACH_ADS8260_DEFS #define __MACH_ADS8260_DEFS +#include #include /* For our show_cpuinfo hooks. */ @@ -46,12 +47,12 @@ #define BCSR1_FETH_RST ((uint)0x0400000 #define BCSR1_RS232_EN1 ((uint)0x02000000) /* 0 ==enable */ #define BCSR1_RS232_EN2 ((uint)0x01000000) /* 0 ==enable */ #define BCSR3_FETHIEN2 ((uint)0x10000000) /* 0 == enable*/ -#define BCSR3_FETH2_RS ((uint)0x80000000) /* 0 == reset */ +#define BCSR3_FETH2_RST ((uint)0x80000000) /* 0 == reset */ /* cpm serial driver works with constants below */ #define SIU_INT_SMC1 ((uint)0x04+CPM_IRQ_OFFSET) -#define SIU_INT_SMC2i ((uint)0x05+CPM_IRQ_OFFSET) +#define SIU_INT_SMC2 ((uint)0x05+CPM_IRQ_OFFSET) #define SIU_INT_SCC1 ((uint)0x28+CPM_IRQ_OFFSET) #define SIU_INT_SCC2 ((uint)0x29+CPM_IRQ_OFFSET) #define SIU_INT_SCC3 ((uint)0x2a+CPM_IRQ_OFFSET) diff --git a/arch/powerpc/platforms/83xx/Kconfig b/arch/powerpc/platforms/83xx/Kconfig index edcd5b8..1aea1e6 100644 --- a/arch/powerpc/platforms/83xx/Kconfig +++ b/arch/powerpc/platforms/83xx/Kconfig @@ -3,7 +3,13 @@ menu "Platform support" choice prompt "Machine Type" - default MPC834x_SYS + default MPC834x_MDS + +config MPC8313_RDB + bool "Freescale MPC8313 RDB" + select DEFAULT_UIMAGE + help + This option enables support for the MPC8313 RDB board. config MPC832x_MDS bool "Freescale MPC832x MDS" @@ -12,13 +18,13 @@ config MPC832x_MDS help This option enables support for the MPC832x MDS evaluation board. -config MPC834x_SYS - bool "Freescale MPC834x SYS" +config MPC834x_MDS + bool "Freescale MPC834x MDS" select DEFAULT_UIMAGE help - This option enables support for the MPC 834x SYS evaluation board. + This option enables support for the MPC 834x MDS evaluation board. - Be aware that PCI buses can only function when SYS board is plugged + Be aware that PCI buses can only function when MDS board is plugged into the PIB (Platform IO Board) board from Freescale which provide 3 PCI slots. The PIBs PCI initialization is the bootloader's responsibility. @@ -41,6 +47,12 @@ config MPC8360E_PB endchoice +config PPC_MPC831x + bool + select PPC_UDBG_16550 + select PPC_INDIRECT_PCI + default y if MPC8313_RDB + config PPC_MPC832x bool select PPC_UDBG_16550 @@ -51,7 +63,7 @@ config MPC834x bool select PPC_UDBG_16550 select PPC_INDIRECT_PCI - default y if MPC834x_SYS || MPC834x_ITX + default y if MPC834x_MDS || MPC834x_ITX config PPC_MPC836x bool diff --git a/arch/powerpc/platforms/83xx/Makefile b/arch/powerpc/platforms/83xx/Makefile index f1aa7e2..6c8199c 100644 --- a/arch/powerpc/platforms/83xx/Makefile +++ b/arch/powerpc/platforms/83xx/Makefile @@ -3,7 +3,8 @@ # Makefile for the PowerPC 83xx linux ke # obj-y := misc.o obj-$(CONFIG_PCI) += pci.o -obj-$(CONFIG_MPC834x_SYS) += mpc834x_sys.o +obj-$(CONFIG_MPC8313_RDB) += mpc8313_rdb.o +obj-$(CONFIG_MPC834x_MDS) += mpc834x_mds.o obj-$(CONFIG_MPC834x_ITX) += mpc834x_itx.o obj-$(CONFIG_MPC8360E_PB) += mpc8360e_pb.o obj-$(CONFIG_MPC832x_MDS) += mpc832x_mds.o diff --git a/arch/powerpc/platforms/83xx/misc.c b/arch/powerpc/platforms/83xx/misc.c index f0c6df6..f01806c 100644 --- a/arch/powerpc/platforms/83xx/misc.c +++ b/arch/powerpc/platforms/83xx/misc.c @@ -18,23 +18,36 @@ #include #include "mpc83xx.h" +static __be32 __iomem *restart_reg_base; + +static int __init mpc83xx_restart_init(void) +{ + /* map reset restart_reg_baseister space */ + restart_reg_base = ioremap(get_immrbase() + 0x900, 0xff); + + return 0; +} + +arch_initcall(mpc83xx_restart_init); + void mpc83xx_restart(char *cmd) { #define RST_OFFSET 0x00000900 #define RST_PROT_REG 0x00000018 #define RST_CTRL_REG 0x0000001c - __be32 __iomem *reg; - - /* map reset register space */ - reg = ioremap(get_immrbase() + 0x900, 0xff); local_irq_disable(); - /* enable software reset "RSTE" */ - out_be32(reg + (RST_PROT_REG >> 2), 0x52535445); + if (restart_reg_base) { + /* enable software reset "RSTE" */ + out_be32(restart_reg_base + (RST_PROT_REG >> 2), 0x52535445); + + /* set software hard reset */ + out_be32(restart_reg_base + (RST_CTRL_REG >> 2), 0x2); + } else { + printk (KERN_EMERG "Error: Restart registers not mapped, spinning!\n"); + } - /* set software hard reset */ - out_be32(reg + (RST_CTRL_REG >> 2), 0x2); for (;;) ; } diff --git a/arch/powerpc/platforms/83xx/mpc8313_rdb.c b/arch/powerpc/platforms/83xx/mpc8313_rdb.c new file mode 100644 index 0000000..c3b98c3 --- /dev/null +++ b/arch/powerpc/platforms/83xx/mpc8313_rdb.c @@ -0,0 +1,99 @@ +/* + * arch/powerpc/platforms/83xx/mpc8313_rdb.c + * + * Description: MPC8313x RDB board specific routines. + * This file is based on mpc834x_sys.c + * Author: Lo Wlison + * + * Copyright (C) Freescale Semiconductor, Inc. 2006. All rights reserved. + * + * 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 "mpc83xx.h" + +#undef DEBUG +#ifdef DEBUG +#define DBG(fmt...) udbg_printf(fmt) +#else +#define DBG(fmt...) +#endif + +#ifndef CONFIG_PCI +unsigned long isa_io_base = 0; +unsigned long isa_mem_base = 0; +#endif + +/* ************************************************************************ + * + * Setup the architecture + * + */ +static void __init mpc8313_rdb_setup_arch(void) +{ + struct device_node *np; + + if (ppc_md.progress) + ppc_md.progress("mpc8313_rdb_setup_arch()", 0); + +#ifdef CONFIG_PCI + for (np = NULL; (np = of_find_node_by_type(np, "pci")) != NULL;) + add_bridge(np); + + ppc_md.pci_exclude_device = mpc83xx_exclude_device; +#endif +} + +void __init mpc8313_rdb_init_IRQ(void) +{ + struct device_node *np; + + np = of_find_node_by_type(NULL, "ipic"); + if (!np) + return; + + ipic_init(np, 0); + + /* Initialize the default interrupt mapping priorities, + * in case the boot rom changed something on us. + */ + ipic_set_default_priority(); +} + +/* + * Called very early, MMU is off, device-tree isn't unflattened + */ +static int __init mpc8313_rdb_probe(void) +{ + char *model = of_get_flat_dt_prop(of_get_flat_dt_root(), + "model", NULL); + if (model == NULL) + return 0; + if (strcmp(model, "MPC8313ERDB")) + return 0; + + DBG("MPC8313 RDB found\n"); + + return 1; +} + +define_machine(mpc8313_rdb) { + .name = "MPC8313 RDB", + .probe = mpc8313_rdb_probe, + .setup_arch = mpc8313_rdb_setup_arch, + .init_IRQ = mpc8313_rdb_init_IRQ, + .get_irq = ipic_get_irq, + .restart = mpc83xx_restart, + .time_init = mpc83xx_time_init, + .calibrate_decr = generic_calibrate_decr, + .progress = udbg_progress, +}; diff --git a/arch/powerpc/platforms/83xx/mpc832x_mds.c b/arch/powerpc/platforms/83xx/mpc832x_mds.c index 4d47119..3ecb55f 100644 --- a/arch/powerpc/platforms/83xx/mpc832x_mds.c +++ b/arch/powerpc/platforms/83xx/mpc832x_mds.c @@ -25,6 +25,7 @@ #include #include #include +#include #include #include #include @@ -153,7 +154,7 @@ static int __init mpc832x_declare_of_pla } device_initcall(mpc832x_declare_of_platform_devices); -void __init mpc832x_sys_init_IRQ(void) +static void __init mpc832x_sys_init_IRQ(void) { struct device_node *np; diff --git a/arch/powerpc/platforms/83xx/mpc834x_itx.c b/arch/powerpc/platforms/83xx/mpc834x_itx.c index 314c42a..443a317 100644 --- a/arch/powerpc/platforms/83xx/mpc834x_itx.c +++ b/arch/powerpc/platforms/83xx/mpc834x_itx.c @@ -38,8 +38,6 @@ #include #include "mpc83xx.h" -#include - #ifndef CONFIG_PCI unsigned long isa_io_base = 0; unsigned long isa_mem_base = 0; @@ -81,7 +79,7 @@ #else #endif } -void __init mpc834x_itx_init_IRQ(void) +static void __init mpc834x_itx_init_IRQ(void) { struct device_node *np; diff --git a/arch/powerpc/platforms/83xx/mpc834x_mds.c b/arch/powerpc/platforms/83xx/mpc834x_mds.c new file mode 100644 index 0000000..d2736da --- /dev/null +++ b/arch/powerpc/platforms/83xx/mpc834x_mds.c @@ -0,0 +1,213 @@ +/* + * arch/powerpc/platforms/83xx/mpc834x_mds.c + * + * MPC834x MDS board specific routines + * + * Maintainer: Kumar Gala + * + * 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 +#include +#include +#include +#include +#include +#include +#include + +#include "mpc83xx.h" + +#ifndef CONFIG_PCI +unsigned long isa_io_base = 0; +unsigned long isa_mem_base = 0; +#endif + +#define BCSR5_INT_USB 0x02 +/* Note: This is only for PB, not for PB+PIB + * On PB only port0 is connected using ULPI */ +static int mpc834x_usb_cfg(void) +{ + unsigned long sccr, sicrl; + void __iomem *immap; + void __iomem *bcsr_regs = NULL; + u8 bcsr5; + struct device_node *np = NULL; + int port0_is_dr = 0; + + if ((np = of_find_compatible_node(np, "usb", "fsl-usb2-dr")) != NULL) + port0_is_dr = 1; + if ((np = of_find_compatible_node(np, "usb", "fsl-usb2-mph")) != NULL){ + if (port0_is_dr) { + printk(KERN_WARNING + "There is only one USB port on PB board! \n"); + return -1; + } else if (!port0_is_dr) + /* No usb port enabled */ + return -1; + } + + immap = ioremap(get_immrbase(), 0x1000); + if (!immap) + return -1; + + /* Configure clock */ + sccr = in_be32(immap + MPC83XX_SCCR_OFFS); + if (port0_is_dr) + sccr |= MPC83XX_SCCR_USB_DRCM_11; /* 1:3 */ + else + sccr |= MPC83XX_SCCR_USB_MPHCM_11; /* 1:3 */ + out_be32(immap + MPC83XX_SCCR_OFFS, sccr); + + /* Configure Pin */ + sicrl = in_be32(immap + MPC83XX_SICRL_OFFS); + /* set port0 only */ + if (port0_is_dr) + sicrl |= MPC83XX_SICRL_USB0; + else + sicrl &= ~(MPC83XX_SICRL_USB0); + out_be32(immap + MPC83XX_SICRL_OFFS, sicrl); + + iounmap(immap); + + /* Map BCSR area */ + np = of_find_node_by_name(NULL, "bcsr"); + if (np != 0) { + struct resource res; + + of_address_to_resource(np, 0, &res); + bcsr_regs = ioremap(res.start, res.end - res.start + 1); + of_node_put(np); + } + if (!bcsr_regs) + return -1; + + /* + * if MDS board is plug into PIB board, + * force to use the PHY on MDS board + */ + bcsr5 = in_8(bcsr_regs + 5); + if (!(bcsr5 & BCSR5_INT_USB)) + out_8(bcsr_regs + 5, (bcsr5 | BCSR5_INT_USB)); + iounmap(bcsr_regs); + return 0; +} + +/* ************************************************************************ + * + * Setup the architecture + * + */ +static void __init mpc834x_mds_setup_arch(void) +{ + struct device_node *np; + + if (ppc_md.progress) + ppc_md.progress("mpc834x_mds_setup_arch()", 0); + + np = of_find_node_by_type(NULL, "cpu"); + if (np != 0) { + const unsigned int *fp = + get_property(np, "clock-frequency", NULL); + if (fp != 0) + loops_per_jiffy = *fp / HZ; + else + loops_per_jiffy = 50000000 / HZ; + of_node_put(np); + } + +#ifdef CONFIG_PCI + for (np = NULL; (np = of_find_node_by_type(np, "pci")) != NULL;) + add_bridge(np); + + ppc_md.pci_exclude_device = mpc83xx_exclude_device; +#endif + + mpc834x_usb_cfg(); + +#ifdef CONFIG_ROOT_NFS + ROOT_DEV = Root_NFS; +#else + ROOT_DEV = Root_HDA1; +#endif +} + +static void __init mpc834x_mds_init_IRQ(void) +{ + struct device_node *np; + + np = of_find_node_by_type(NULL, "ipic"); + if (!np) + return; + + ipic_init(np, 0); + + /* Initialize the default interrupt mapping priorities, + * in case the boot rom changed something on us. + */ + ipic_set_default_priority(); +} + +#if defined(CONFIG_I2C_MPC) && defined(CONFIG_SENSORS_DS1374) +extern ulong ds1374_get_rtc_time(void); +extern int ds1374_set_rtc_time(ulong); + +static int __init mpc834x_rtc_hookup(void) +{ + struct timespec tv; + + ppc_md.get_rtc_time = ds1374_get_rtc_time; + ppc_md.set_rtc_time = ds1374_set_rtc_time; + + tv.tv_nsec = 0; + tv.tv_sec = (ppc_md.get_rtc_time) (); + do_settimeofday(&tv); + + return 0; +} + +late_initcall(mpc834x_rtc_hookup); +#endif + +/* + * Called very early, MMU is off, device-tree isn't unflattened + */ +static int __init mpc834x_mds_probe(void) +{ + /* We always match for now, eventually we should look at the flat + dev tree to ensure this is the board we are suppose to run on + */ + return 1; +} + +define_machine(mpc834x_mds) { + .name = "MPC834x MDS", + .probe = mpc834x_mds_probe, + .setup_arch = mpc834x_mds_setup_arch, + .init_IRQ = mpc834x_mds_init_IRQ, + .get_irq = ipic_get_irq, + .restart = mpc83xx_restart, + .time_init = mpc83xx_time_init, + .calibrate_decr = generic_calibrate_decr, + .progress = udbg_progress, +}; diff --git a/arch/powerpc/platforms/83xx/mpc834x_sys.c b/arch/powerpc/platforms/83xx/mpc834x_sys.c deleted file mode 100644 index 80b735a..0000000 --- a/arch/powerpc/platforms/83xx/mpc834x_sys.c +++ /dev/null @@ -1,140 +0,0 @@ -/* - * arch/powerpc/platforms/83xx/mpc834x_sys.c - * - * MPC834x SYS board specific routines - * - * Maintainer: Kumar Gala - * - * 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 -#include -#include -#include -#include -#include -#include -#include - -#include "mpc83xx.h" - -#ifndef CONFIG_PCI -unsigned long isa_io_base = 0; -unsigned long isa_mem_base = 0; -#endif - -/* ************************************************************************ - * - * Setup the architecture - * - */ -static void __init mpc834x_sys_setup_arch(void) -{ - struct device_node *np; - - if (ppc_md.progress) - ppc_md.progress("mpc834x_sys_setup_arch()", 0); - - np = of_find_node_by_type(NULL, "cpu"); - if (np != 0) { - const unsigned int *fp = - get_property(np, "clock-frequency", NULL); - if (fp != 0) - loops_per_jiffy = *fp / HZ; - else - loops_per_jiffy = 50000000 / HZ; - of_node_put(np); - } -#ifdef CONFIG_PCI - for (np = NULL; (np = of_find_node_by_type(np, "pci")) != NULL;) - add_bridge(np); - - ppc_md.pci_exclude_device = mpc83xx_exclude_device; -#endif - -#ifdef CONFIG_ROOT_NFS - ROOT_DEV = Root_NFS; -#else - ROOT_DEV = Root_HDA1; -#endif -} - -void __init mpc834x_sys_init_IRQ(void) -{ - struct device_node *np; - - np = of_find_node_by_type(NULL, "ipic"); - if (!np) - return; - - ipic_init(np, 0); - - /* Initialize the default interrupt mapping priorities, - * in case the boot rom changed something on us. - */ - ipic_set_default_priority(); -} - -#if defined(CONFIG_I2C_MPC) && defined(CONFIG_SENSORS_DS1374) -extern ulong ds1374_get_rtc_time(void); -extern int ds1374_set_rtc_time(ulong); - -static int __init mpc834x_rtc_hookup(void) -{ - struct timespec tv; - - ppc_md.get_rtc_time = ds1374_get_rtc_time; - ppc_md.set_rtc_time = ds1374_set_rtc_time; - - tv.tv_nsec = 0; - tv.tv_sec = (ppc_md.get_rtc_time) (); - do_settimeofday(&tv); - - return 0; -} - -late_initcall(mpc834x_rtc_hookup); -#endif - -/* - * Called very early, MMU is off, device-tree isn't unflattened - */ -static int __init mpc834x_sys_probe(void) -{ - /* We always match for now, eventually we should look at the flat - dev tree to ensure this is the board we are suppose to run on - */ - return 1; -} - -define_machine(mpc834x_sys) { - .name = "MPC834x SYS", - .probe = mpc834x_sys_probe, - .setup_arch = mpc834x_sys_setup_arch, - .init_IRQ = mpc834x_sys_init_IRQ, - .get_irq = ipic_get_irq, - .restart = mpc83xx_restart, - .time_init = mpc83xx_time_init, - .calibrate_decr = generic_calibrate_decr, - .progress = udbg_progress, -}; diff --git a/arch/powerpc/platforms/83xx/mpc834x_sys.h b/arch/powerpc/platforms/83xx/mpc834x_sys.h deleted file mode 100644 index 7d5bbef..0000000 --- a/arch/powerpc/platforms/83xx/mpc834x_sys.h +++ /dev/null @@ -1,23 +0,0 @@ -/* - * arch/powerpc/platforms/83xx/mpc834x_sys.h - * - * MPC834X SYS common board definitions - * - * Maintainer: Kumar Gala - * - * 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 __MACH_MPC83XX_SYS_H__ -#define __MACH_MPC83XX_SYS_H__ - -#define PIRQA MPC83xx_IRQ_EXT4 -#define PIRQB MPC83xx_IRQ_EXT5 -#define PIRQC MPC83xx_IRQ_EXT6 -#define PIRQD MPC83xx_IRQ_EXT7 - -#endif /* __MACH_MPC83XX_SYS_H__ */ diff --git a/arch/powerpc/platforms/83xx/mpc8360e_pb.c b/arch/powerpc/platforms/83xx/mpc8360e_pb.c index 53b92a9..ccce2f9 100644 --- a/arch/powerpc/platforms/83xx/mpc8360e_pb.c +++ b/arch/powerpc/platforms/83xx/mpc8360e_pb.c @@ -31,6 +31,7 @@ #include #include #include +#include #include #include #include @@ -158,7 +159,7 @@ static int __init mpc8360_declare_of_pla } device_initcall(mpc8360_declare_of_platform_devices); -void __init mpc8360_sys_init_IRQ(void) +static void __init mpc8360_sys_init_IRQ(void) { struct device_node *np; diff --git a/arch/powerpc/platforms/83xx/mpc83xx.h b/arch/powerpc/platforms/83xx/mpc83xx.h index 01cae10..9cd03b5 100644 --- a/arch/powerpc/platforms/83xx/mpc83xx.h +++ b/arch/powerpc/platforms/83xx/mpc83xx.h @@ -4,6 +4,24 @@ #define __MPC83XX_H__ #include #include +/* System Clock Control Register */ +#define MPC83XX_SCCR_OFFS 0xA08 +#define MPC83XX_SCCR_USB_MPHCM_11 0x00c00000 +#define MPC83XX_SCCR_USB_MPHCM_01 0x00400000 +#define MPC83XX_SCCR_USB_MPHCM_10 0x00800000 +#define MPC83XX_SCCR_USB_DRCM_11 0x00300000 +#define MPC83XX_SCCR_USB_DRCM_01 0x00100000 +#define MPC83XX_SCCR_USB_DRCM_10 0x00200000 + +/* system i/o configuration register low */ +#define MPC83XX_SICRL_OFFS 0x114 +#define MPC83XX_SICRL_USB0 0x40000000 +#define MPC83XX_SICRL_USB1 0x20000000 + +/* system i/o configuration register high */ +#define MPC83XX_SICRH_OFFS 0x118 +#define MPC83XX_SICRH_USB_UTMI 0x00020000 + /* * Declaration for the various functions exported by the * mpc83xx_* files. Mostly for use by mpc83xx_setup diff --git a/arch/powerpc/platforms/85xx/Kconfig b/arch/powerpc/platforms/85xx/Kconfig index 0584f3c..0efdd2f 100644 --- a/arch/powerpc/platforms/85xx/Kconfig +++ b/arch/powerpc/platforms/85xx/Kconfig @@ -23,6 +23,13 @@ config MPC85xx_CDS help This option enables support for the MPC85xx CDS board +config MPC8568_MDS + bool "Freescale MPC8568 MDS" + select DEFAULT_UIMAGE +# select QUICC_ENGINE + help + This option enables support for the MPC8568 MDS board + endchoice config MPC8540 @@ -36,6 +43,12 @@ config MPC8560 select PPC_INDIRECT_PCI default y if MPC8560_ADS +config MPC85xx + bool + select PPC_UDBG_16550 + select PPC_INDIRECT_PCI + default y if MPC8540_ADS || MPC85xx_CDS || MPC8560_ADS || MPC8568_MDS + config PPC_INDIRECT_PCI_BE bool depends on PPC_85xx diff --git a/arch/powerpc/platforms/85xx/Makefile b/arch/powerpc/platforms/85xx/Makefile index 282f5d0..e40e521 100644 --- a/arch/powerpc/platforms/85xx/Makefile +++ b/arch/powerpc/platforms/85xx/Makefile @@ -5,3 +5,4 @@ obj-$(CONFIG_PPC_85xx) += misc.o pci.o obj-$(CONFIG_MPC8540_ADS) += mpc85xx_ads.o obj-$(CONFIG_MPC8560_ADS) += mpc85xx_ads.o obj-$(CONFIG_MPC85xx_CDS) += mpc85xx_cds.o +obj-$(CONFIG_MPC8568_MDS) += mpc8568_mds.o diff --git a/arch/powerpc/platforms/85xx/mpc8568_mds.c b/arch/powerpc/platforms/85xx/mpc8568_mds.c new file mode 100644 index 0000000..0861d11 --- /dev/null +++ b/arch/powerpc/platforms/85xx/mpc8568_mds.c @@ -0,0 +1,246 @@ +/* + * Copyright (C) Freescale Semicondutor, Inc. 2006-2007. All rights reserved. + * + * Author: Andy Fleming + * + * Based on 83xx/mpc8360e_pb.c by: + * Li Yang + * Yin Olivia + * + * Description: + * MPC8568E MDS PB board specific routines. + * + * 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "mpc85xx.h" + +#undef DEBUG +#ifdef DEBUG +#define DBG(fmt...) udbg_printf(fmt) +#else +#define DBG(fmt...) +#endif + +#ifndef CONFIG_PCI +unsigned long isa_io_base = 0; +unsigned long isa_mem_base = 0; +#endif + +/* ************************************************************************ + * + * Setup the architecture + * + */ +static void __init mpc8568_mds_setup_arch(void) +{ + struct device_node *np; + static u8 *bcsr_regs = NULL; + + + if (ppc_md.progress) + ppc_md.progress("mpc8568_mds_setup_arch()", 0); + + np = of_find_node_by_type(NULL, "cpu"); + if (np != NULL) { + const unsigned int *fp = + get_property(np, "clock-frequency", NULL); + if (fp != NULL) + loops_per_jiffy = *fp / HZ; + else + loops_per_jiffy = 50000000 / HZ; + of_node_put(np); + } + + /* Map BCSR area */ + np = of_find_node_by_name(NULL, "bcsr"); + if (np != NULL) { + struct resource res; + + of_address_to_resource(np, 0, &res); + bcsr_regs = ioremap(res.start, res.end - res.start +1); + of_node_put(np); + } + +#ifdef CONFIG_PCI + for (np = NULL; (np = of_find_node_by_type(np, "pci")) != NULL;) { + add_bridge(np); + } + of_node_put(np); +#endif + +#ifdef CONFIG_QUICC_ENGINE + if ((np = of_find_node_by_name(NULL, "qe")) != NULL) { + qe_reset(); + of_node_put(np); + } + + if ((np = of_find_node_by_name(NULL, "par_io")) != NULL) { + struct device_node *ucc = NULL; + + par_io_init(np); + of_node_put(np); + + for ( ;(ucc = of_find_node_by_name(ucc, "ucc")) != NULL;) + par_io_of_config(ucc); + + of_node_put(ucc); + } + + if (bcsr_regs) { + u8 bcsr_phy; + + /* Reset the Ethernet PHY */ + bcsr_phy = in_be8(&bcsr_regs[9]); + bcsr_phy &= ~0x20; + out_be8(&bcsr_regs[9], bcsr_phy); + + udelay(1000); + + bcsr_phy = in_be8(&bcsr_regs[9]); + bcsr_phy |= 0x20; + out_be8(&bcsr_regs[9], bcsr_phy); + + iounmap(bcsr_regs); + } + +#endif /* CONFIG_QUICC_ENGINE */ +} + +static struct of_device_id mpc8568_ids[] = { + { .type = "soc", }, + { .compatible = "soc", }, + { .type = "qe", }, + {}, +}; + +static int __init mpc8568_publish_devices(void) +{ + if (!machine_is(mpc8568_mds)) + return 0; + + /* Publish the QE devices */ + of_platform_bus_probe(NULL,mpc8568_ids,NULL); + + return 0; +} +device_initcall(mpc8568_publish_devices); + +static void __init mpc8568_mds_pic_init(void) +{ + struct mpic *mpic; + struct resource r; + struct device_node *np = NULL; + + np = of_find_node_by_type(NULL, "open-pic"); + if (!np) + return; + + if (of_address_to_resource(np, 0, &r)) { + printk(KERN_ERR "Failed to map mpic register space\n"); + of_node_put(np); + return; + } + + mpic = mpic_alloc(np, r.start, + MPIC_PRIMARY | MPIC_WANTS_RESET | MPIC_BIG_ENDIAN, + 4, 0, " OpenPIC "); + BUG_ON(mpic == NULL); + of_node_put(np); + + /* Internal Interrupts */ + mpic_assign_isu(mpic, 0, r.start + 0x10200); + mpic_assign_isu(mpic, 1, r.start + 0x10280); + mpic_assign_isu(mpic, 2, r.start + 0x10300); + mpic_assign_isu(mpic, 3, r.start + 0x10380); + mpic_assign_isu(mpic, 4, r.start + 0x10400); + mpic_assign_isu(mpic, 5, r.start + 0x10480); + mpic_assign_isu(mpic, 6, r.start + 0x10500); + mpic_assign_isu(mpic, 7, r.start + 0x10580); + mpic_assign_isu(mpic, 8, r.start + 0x10600); + mpic_assign_isu(mpic, 9, r.start + 0x10680); + mpic_assign_isu(mpic, 10, r.start + 0x10700); + mpic_assign_isu(mpic, 11, r.start + 0x10780); + + /* External Interrupts */ + mpic_assign_isu(mpic, 12, r.start + 0x10000); + mpic_assign_isu(mpic, 13, r.start + 0x10080); + mpic_assign_isu(mpic, 14, r.start + 0x10100); + + mpic_init(mpic); + + +#ifdef CONFIG_QUICC_ENGINE + np = of_find_node_by_type(NULL, "qeic"); + if (!np) + return; + + qe_ic_init(np, 0); + of_node_put(np); +#endif /* CONFIG_QUICC_ENGINE */ +} + + +static int __init mpc8568_mds_probe(void) +{ + char *model = of_get_flat_dt_prop(of_get_flat_dt_root(), + "model", NULL); + if (model == NULL) + return 0; + if (strcmp(model, "MPC8568EMDS")) + return 0; + + DBG("MPC8568EMDS found\n"); + + return 1; +} + + +define_machine(mpc8568_mds) { + .name = "MPC8568E MDS", + .probe = mpc8568_mds_probe, + .setup_arch = mpc8568_mds_setup_arch, + .init_IRQ = mpc8568_mds_pic_init, + .get_irq = mpic_get_irq, + .restart = mpc85xx_restart, + .calibrate_decr = generic_calibrate_decr, + .progress = udbg_progress, +}; diff --git a/arch/powerpc/platforms/85xx/mpc85xx_ads.c b/arch/powerpc/platforms/85xx/mpc85xx_ads.c index bda2e55..c56fce5 100644 --- a/arch/powerpc/platforms/85xx/mpc85xx_ads.c +++ b/arch/powerpc/platforms/85xx/mpc85xx_ads.c @@ -45,8 +45,7 @@ unsigned long isa_mem_base = 0; #endif #ifdef CONFIG_PCI -int -mpc85xx_exclude_device(u_char bus, u_char devfn) +static int mpc85xx_exclude_device(u_char bus, u_char devfn) { if (bus == 0 && PCI_SLOT(devfn) == 0) return PCIBIOS_DEVICE_NOT_FOUND; @@ -69,7 +68,7 @@ static void cpm2_cascade(unsigned int ir #endif /* CONFIG_CPM2 */ -void __init mpc85xx_ads_pic_init(void) +static void __init mpc85xx_ads_pic_init(void) { struct mpic *mpic; struct resource r; @@ -254,7 +253,7 @@ #else #endif } -void mpc85xx_ads_show_cpuinfo(struct seq_file *m) +static void mpc85xx_ads_show_cpuinfo(struct seq_file *m) { uint pvid, svid, phid1; uint memsize = total_memory; diff --git a/arch/powerpc/platforms/85xx/mpc85xx_cds.c b/arch/powerpc/platforms/85xx/mpc85xx_cds.c index 953cd5d..abc0aca 100644 --- a/arch/powerpc/platforms/85xx/mpc85xx_cds.c +++ b/arch/powerpc/platforms/85xx/mpc85xx_cds.c @@ -56,7 +56,6 @@ #endif static int cds_pci_slot = 2; static volatile u8 *cadmus; - #ifdef CONFIG_PCI #define ARCADIA_HOST_BRIDGE_IDSEL 17 @@ -64,8 +63,7 @@ #define ARCADIA_2ND_BRIDGE_IDSEL 3 extern int mpc85xx_pci2_busno; -int -mpc85xx_exclude_device(u_char bus, u_char devfn) +static int mpc85xx_exclude_device(u_char bus, u_char devfn) { if (bus == 0 && PCI_SLOT(devfn) == 0) return PCIBIOS_DEVICE_NOT_FOUND; @@ -81,8 +79,7 @@ mpc85xx_exclude_device(u_char bus, u_cha return PCIBIOS_SUCCESSFUL; } -void __init -mpc85xx_cds_pcibios_fixup(void) +static void __init mpc85xx_cds_pcibios_fixup(void) { struct pci_dev *dev; u_char c; @@ -144,7 +141,7 @@ static void mpc85xx_8259_cascade(unsigne #endif /* PPC_I8259 */ #endif /* CONFIG_PCI */ -void __init mpc85xx_cds_pic_init(void) +static void __init mpc85xx_cds_pic_init(void) { struct mpic *mpic; struct resource r; @@ -224,12 +221,10 @@ #ifdef CONFIG_PPC_I8259 #endif /* CONFIG_PPC_I8259 */ } - /* * Setup the architecture */ -static void __init -mpc85xx_cds_setup_arch(void) +static void __init mpc85xx_cds_setup_arch(void) { struct device_node *cpu; #ifdef CONFIG_PCI @@ -276,9 +271,7 @@ #else #endif } - -void -mpc85xx_cds_show_cpuinfo(struct seq_file *m) +static void mpc85xx_cds_show_cpuinfo(struct seq_file *m) { uint pvid, svid, phid1; uint memsize = total_memory; diff --git a/arch/powerpc/platforms/86xx/Kconfig b/arch/powerpc/platforms/86xx/Kconfig index d1ecc0f..0c70944 100644 --- a/arch/powerpc/platforms/86xx/Kconfig +++ b/arch/powerpc/platforms/86xx/Kconfig @@ -8,6 +8,7 @@ choice config MPC8641_HPCN bool "Freescale MPC8641 HPCN" select PPC_I8259 + select DEFAULT_UIMAGE help This option enables support for the MPC8641 HPCN board. diff --git a/arch/powerpc/platforms/86xx/mpc86xx_smp.c b/arch/powerpc/platforms/86xx/mpc86xx_smp.c index bb7fb41..7ef0c68 100644 --- a/arch/powerpc/platforms/86xx/mpc86xx_smp.c +++ b/arch/powerpc/platforms/86xx/mpc86xx_smp.c @@ -65,7 +65,6 @@ smp_86xx_kick_cpu(int nr) pr_debug("smp_86xx_kick_cpu: kick CPU #%d\n", nr); local_irq_save(flags); - local_irq_disable(); /* Save reset vector */ save_vector = *vector; diff --git a/arch/powerpc/platforms/8xx/Kconfig b/arch/powerpc/platforms/8xx/Kconfig index c8c0ba3..beea683 100644 --- a/arch/powerpc/platforms/8xx/Kconfig +++ b/arch/powerpc/platforms/8xx/Kconfig @@ -1,105 +1,16 @@ +menu "Platform support" + depends on PPC_8xx + config FADS bool +config CPM1 + bool + choice prompt "8xx Machine Type" depends on 8xx - default RPXLITE - -config RPXLITE - bool "RPX-Lite" - ---help--- - Single-board computers based around the PowerPC MPC8xx chips and - intended for embedded applications. The following types are - supported: - - RPX-Lite: - Embedded Planet RPX Lite. PC104 form-factor SBC based on the MPC823. - - RPX-Classic: - Embedded Planet RPX Classic Low-fat. Credit-card-size SBC based on - the MPC 860 - - BSE-IP: - Bright Star Engineering ip-Engine. - - TQM823L: - TQM850L: - TQM855L: - TQM860L: - MPC8xx based family of mini modules, half credit card size, - up to 64 MB of RAM, 8 MB Flash, (Fast) Ethernet, 2 x serial ports, - 2 x CAN bus interface, ... - Manufacturer: TQ Components, www.tq-group.de - Date of Release: October (?) 1999 - End of Life: not yet :-) - URL: - - module: - - starter kit: - - images: - - FPS850L: - FingerPrint Sensor System (based on TQM850L) - Manufacturer: IKENDI AG, - Date of Release: November 1999 - End of life: end 2000 ? - URL: see TQM850L - - IVMS8: - MPC860 based board used in the "Integrated Voice Mail System", - Small Version (8 voice channels) - Manufacturer: Speech Design, - Date of Release: December 2000 (?) - End of life: - - URL: - - IVML24: - MPC860 based board used in the "Integrated Voice Mail System", - Large Version (24 voice channels) - Manufacturer: Speech Design, - Date of Release: March 2001 (?) - End of life: - - URL: - - HERMES: - Hermes-Pro ISDN/LAN router with integrated 8 x hub - Manufacturer: Multidata Gesellschaft fur Datentechnik und Informatik - - Date of Release: 2000 (?) - End of life: - - URL: - - IP860: - VMEBus IP (Industry Pack) carrier board with MPC860 - Manufacturer: MicroSys GmbH, - Date of Release: ? - End of life: - - URL: - - PCU_E: - PCU = Peripheral Controller Unit, Extended - Manufacturer: Siemens AG, ICN (Information and Communication Networks) - - Date of Release: April 2001 - End of life: August 2001 - URL: n. a. - -config RPXCLASSIC - bool "RPX-Classic" - help - The RPX-Classic is a single-board computer based on the Motorola - MPC860. It features 16MB of DRAM and a variable amount of flash, - I2C EEPROM, thermal monitoring, a PCMCIA slot, a DIP switch and two - LEDs. Variants with Ethernet ports exist. Say Y here to support it - directly. - -config BSEIP - bool "BSE-IP" - help - Say Y here to support the Bright Star Engineering ipEngine SBC. - This is a credit-card-sized device featuring a MPC823 processor, - 26MB DRAM, 4MB flash, Ethernet, a 16K-gate FPGA, USB, an LCD/video - controller, and two RS232 ports. + default MPC885ADS config MPC8XXFADS bool "FADS" @@ -107,110 +18,58 @@ config MPC8XXFADS config MPC86XADS bool "MPC86XADS" + select CPM1 help MPC86x Application Development System by Freescale Semiconductor. The MPC86xADS is meant to serve as a platform for s/w and h/w development around the MPC86X processor families. - select FADS config MPC885ADS bool "MPC885ADS" + select CPM1 help Freescale Semiconductor MPC885 Application Development System (ADS). Also known as DUET. The MPC885ADS is meant to serve as a platform for s/w and h/w development around the MPC885 processor family. -config TQM823L - bool "TQM823L" - help - Say Y here to support the TQM823L, one of an MPC8xx-based family of - mini SBCs (half credit-card size) from TQ Components first released - in late 1999. Technical references are at - , and - , and an image at - . - -config TQM850L - bool "TQM850L" - help - Say Y here to support the TQM850L, one of an MPC8xx-based family of - mini SBCs (half credit-card size) from TQ Components first released - in late 1999. Technical references are at - , and - , and an image at - . - -config TQM855L - bool "TQM855L" - help - Say Y here to support the TQM855L, one of an MPC8xx-based family of - mini SBCs (half credit-card size) from TQ Components first released - in late 1999. Technical references are at - , and - , and an image at - . - -config TQM860L - bool "TQM860L" - help - Say Y here to support the TQM860L, one of an MPC8xx-based family of - mini SBCs (half credit-card size) from TQ Components first released - in late 1999. Technical references are at - , and - , and an image at - . - -config FPS850L - bool "FPS850L" - -config IVMS8 - bool "IVMS8" - help - Say Y here to support the Integrated Voice-Mail Small 8-channel SBC - from Speech Design, released March 2001. The manufacturer's website - is at . - -config IVML24 - bool "IVML24" - help - Say Y here to support the Integrated Voice-Mail Large 24-channel SBC - from Speech Design, released March 2001. The manufacturer's website - is at . - -config HERMES_PRO - bool "HERMES" - -config IP860 - bool "IP860" - -config LWMON - bool "LWMON" - -config PCU_E - bool "PCU_E" - -config CCM - bool "CCM" - -config LANTEC - bool "LANTEC" +endchoice -config MBX - bool "MBX" - help - MBX is a line of Motorola single-board computer based around the - MPC821 and MPC860 processors, and intended for embedded-controller - applications. Say Y here to support these boards directly. +menu "Freescale Ethernet driver platform-specific options" + depends on (FS_ENET && MPC885ADS) + + config MPC8xx_SECOND_ETH + bool "Second Ethernet channel" + depends on MPC885ADS + default y + help + This enables support for second Ethernet on MPC885ADS and MPC86xADS boards. + The latter will use SCC1, for 885ADS you can select it below. + + choice + prompt "Second Ethernet channel" + depends on MPC8xx_SECOND_ETH + default MPC8xx_SECOND_ETH_FEC2 + + config MPC8xx_SECOND_ETH_FEC2 + bool "FEC2" + depends on MPC885ADS + help + Enable FEC2 to serve as 2-nd Ethernet channel. Note that SMC2 + (often 2-nd UART) will not work if this is enabled. + + config MPC8xx_SECOND_ETH_SCC3 + bool "SCC3" + depends on MPC885ADS + help + Enable SCC3 to serve as 2-nd Ethernet channel. Note that SMC1 + (often 1-nd UART) will not work if this is enabled. + + endchoice -config WINCEPT - bool "WinCept" - help - The Wincept 100/110 is a Motorola single-board computer based on the - MPC821 PowerPC, introduced in 1998 and designed to be used in - thin-client machines. Say Y to support it directly. +endmenu -endchoice +endmenu # # MPC8xx Communication options @@ -219,79 +78,6 @@ # menu "MPC8xx CPM Options" depends on 8xx -config SCC_ENET - bool "CPM SCC Ethernet" - depends on NET_ETHERNET - help - Enable Ethernet support via the Motorola MPC8xx serial - communications controller. - -choice - prompt "SCC used for Ethernet" - depends on SCC_ENET - default SCC1_ENET - -config SCC1_ENET - bool "SCC1" - help - Use MPC8xx serial communications controller 1 to drive Ethernet - (default). - -config SCC2_ENET - bool "SCC2" - help - Use MPC8xx serial communications controller 2 to drive Ethernet. - -config SCC3_ENET - bool "SCC3" - help - Use MPC8xx serial communications controller 3 to drive Ethernet. - -endchoice - -config FEC_ENET - bool "860T FEC Ethernet" - depends on NET_ETHERNET - help - Enable Ethernet support via the Fast Ethernet Controller (FCC) on - the Motorola MPC8260. - -config USE_MDIO - bool "Use MDIO for PHY configuration" - depends on FEC_ENET - help - On some boards the hardware configuration of the ethernet PHY can be - used without any software interaction over the MDIO interface, so - all MII code can be omitted. Say N here if unsure or if you don't - need link status reports. - -config FEC_AM79C874 - bool "Support AMD79C874 PHY" - depends on USE_MDIO - -config FEC_LXT970 - bool "Support LXT970 PHY" - depends on USE_MDIO - -config FEC_LXT971 - bool "Support LXT971 PHY" - depends on USE_MDIO - -config FEC_QS6612 - bool "Support QS6612 PHY" - depends on USE_MDIO - -config ENET_BIG_BUFFERS - bool "Use Big CPM Ethernet Buffers" - depends on SCC_ENET || FEC_ENET - help - Allocate large buffers for MPC8xx Ethernet. Increases throughput - and decreases the likelihood of dropped packets, but costs memory. - -config HTDMSOUND - bool "Embedded Planet HIOX Audio" - depends on SOUND=y - # This doesn't really belong here, but it is convenient to ask # 8xx specific questions. comment "Generic MPC8xx Options" diff --git a/arch/powerpc/platforms/8xx/Makefile b/arch/powerpc/platforms/8xx/Makefile new file mode 100644 index 0000000..5e2dae3 --- /dev/null +++ b/arch/powerpc/platforms/8xx/Makefile @@ -0,0 +1,6 @@ +# +# Makefile for the PowerPC 8xx linux kernel. +# +obj-$(CONFIG_PPC_8xx) += m8xx_setup.o +obj-$(CONFIG_MPC885ADS) += mpc885ads_setup.o +obj-$(CONFIG_MPC86XADS) += mpc86xads_setup.o diff --git a/arch/powerpc/platforms/8xx/m8xx_setup.c b/arch/powerpc/platforms/8xx/m8xx_setup.c new file mode 100644 index 0000000..9ed7125 --- /dev/null +++ b/arch/powerpc/platforms/8xx/m8xx_setup.c @@ -0,0 +1,303 @@ +/* + * Copyright (C) 1995 Linus Torvalds + * Adapted from 'alpha' version by Gary Thomas + * Modified by Cort Dougan (cort@cs.nmt.edu) + * Modified for MBX using prep/chrp/pmac functions by Dan (dmalek@jlc.net) + * Further modified for generic 8xx by Dan. + */ + +/* + * bootup setup stuff.. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "sysdev/mpc8xx_pic.h" + +void m8xx_calibrate_decr(void); +extern void m8xx_wdt_handler_install(bd_t *bp); +extern int cpm_pic_init(void); +extern int cpm_get_irq(void); + +/* A place holder for time base interrupts, if they are ever enabled. */ +irqreturn_t timebase_interrupt(int irq, void * dev) +{ + printk ("timebase_interrupt()\n"); + + return IRQ_HANDLED; +} + +static struct irqaction tbint_irqaction = { + .handler = timebase_interrupt, + .mask = CPU_MASK_NONE, + .name = "tbint", +}; + +/* per-board overridable init_internal_rtc() function. */ +void __init __attribute__ ((weak)) +init_internal_rtc(void) +{ + sit8xx_t *sys_tmr = (sit8xx_t *) immr_map(im_sit); + + /* Disable the RTC one second and alarm interrupts. */ + clrbits16(&sys_tmr->sit_rtcsc, (RTCSC_SIE | RTCSC_ALE)); + + /* Enable the RTC */ + setbits16(&sys_tmr->sit_rtcsc, (RTCSC_RTF | RTCSC_RTE)); + immr_unmap(sys_tmr); +} + +static int __init get_freq(char *name, unsigned long *val) +{ + struct device_node *cpu; + unsigned int *fp; + int found = 0; + + /* The cpu node should have timebase and clock frequency properties */ + cpu = of_find_node_by_type(NULL, "cpu"); + + if (cpu) { + fp = (unsigned int *)get_property(cpu, name, NULL); + if (fp) { + found = 1; + *val = *fp++; + } + + of_node_put(cpu); + } + + return found; +} + +/* The decrementer counts at the system (internal) clock frequency divided by + * sixteen, or external oscillator divided by four. We force the processor + * to use system clock divided by sixteen. + */ +void __init mpc8xx_calibrate_decr(void) +{ + struct device_node *cpu; + cark8xx_t *clk_r1; + car8xx_t *clk_r2; + sitk8xx_t *sys_tmr1; + sit8xx_t *sys_tmr2; + int irq, virq; + + clk_r1 = (cark8xx_t *) immr_map(im_clkrstk); + + /* Unlock the SCCR. */ + out_be32(&clk_r1->cark_sccrk, ~KAPWR_KEY); + out_be32(&clk_r1->cark_sccrk, KAPWR_KEY); + immr_unmap(clk_r1); + + /* Force all 8xx processors to use divide by 16 processor clock. */ + clk_r2 = (car8xx_t *) immr_map(im_clkrst); + setbits32(&clk_r2->car_sccr, 0x02000000); + immr_unmap(clk_r2); + + /* Processor frequency is MHz. + */ + ppc_tb_freq = 50000000; + if (!get_freq("bus-frequency", &ppc_tb_freq)) { + printk(KERN_ERR "WARNING: Estimating decrementer frequency " + "(not found)\n"); + } + ppc_tb_freq /= 16; + ppc_proc_freq = 50000000; + if (!get_freq("clock-frequency", &ppc_proc_freq)) + printk(KERN_ERR "WARNING: Estimating processor frequency" + "(not found)\n"); + + printk("Decrementer Frequency = 0x%lx\n", ppc_tb_freq); + + /* Perform some more timer/timebase initialization. This used + * to be done elsewhere, but other changes caused it to get + * called more than once....that is a bad thing. + * + * First, unlock all of the registers we are going to modify. + * To protect them from corruption during power down, registers + * that are maintained by keep alive power are "locked". To + * modify these registers we have to write the key value to + * the key location associated with the register. + * Some boards power up with these unlocked, while others + * are locked. Writing anything (including the unlock code?) + * to the unlocked registers will lock them again. So, here + * we guarantee the registers are locked, then we unlock them + * for our use. + */ + sys_tmr1 = (sitk8xx_t *) immr_map(im_sitk); + out_be32(&sys_tmr1->sitk_tbscrk, ~KAPWR_KEY); + out_be32(&sys_tmr1->sitk_rtcsck, ~KAPWR_KEY); + out_be32(&sys_tmr1->sitk_tbk, ~KAPWR_KEY); + out_be32(&sys_tmr1->sitk_tbscrk, KAPWR_KEY); + out_be32(&sys_tmr1->sitk_rtcsck, KAPWR_KEY); + out_be32(&sys_tmr1->sitk_tbk, KAPWR_KEY); + immr_unmap(sys_tmr1); + + init_internal_rtc(); + + /* Enabling the decrementer also enables the timebase interrupts + * (or from the other point of view, to get decrementer interrupts + * we have to enable the timebase). The decrementer interrupt + * is wired into the vector table, nothing to do here for that. + */ + cpu = of_find_node_by_type(NULL, "cpu"); + virq= irq_of_parse_and_map(cpu, 0); + irq = irq_map[virq].hwirq; + + sys_tmr2 = (sit8xx_t *) immr_map(im_sit); + out_be16(&sys_tmr2->sit_tbscr, ((1 << (7 - (irq/2))) << 8) | + (TBSCR_TBF | TBSCR_TBE)); + immr_unmap(sys_tmr2); + + if (setup_irq(virq, &tbint_irqaction)) + panic("Could not allocate timer IRQ!"); + +#ifdef CONFIG_8xx_WDT + /* Install watchdog timer handler early because it might be + * already enabled by the bootloader + */ + m8xx_wdt_handler_install(binfo); +#endif +} + +/* The RTC on the MPC8xx is an internal register. + * We want to protect this during power down, so we need to unlock, + * modify, and re-lock. + */ + +int mpc8xx_set_rtc_time(struct rtc_time *tm) +{ + sitk8xx_t *sys_tmr1; + sit8xx_t *sys_tmr2; + int time; + + sys_tmr1 = (sitk8xx_t *) immr_map(im_sitk); + sys_tmr2 = (sit8xx_t *) immr_map(im_sit); + time = mktime(tm->tm_year+1900, tm->tm_mon+1, tm->tm_mday, + tm->tm_hour, tm->tm_min, tm->tm_sec); + + out_be32(&sys_tmr1->sitk_rtck, KAPWR_KEY); + out_be32(&sys_tmr2->sit_rtc, time); + out_be32(&sys_tmr1->sitk_rtck, ~KAPWR_KEY); + + immr_unmap(sys_tmr2); + immr_unmap(sys_tmr1); + return 0; +} + +void mpc8xx_get_rtc_time(struct rtc_time *tm) +{ + unsigned long data; + sit8xx_t *sys_tmr = (sit8xx_t *) immr_map(im_sit); + + /* Get time from the RTC. */ + data = in_be32(&sys_tmr->sit_rtc); + to_tm(data, tm); + tm->tm_year -= 1900; + tm->tm_mon -= 1; + immr_unmap(sys_tmr); + return; +} + +void mpc8xx_restart(char *cmd) +{ + __volatile__ unsigned char dummy; + car8xx_t * clk_r = (car8xx_t *) immr_map(im_clkrst); + + + local_irq_disable(); + + setbits32(&clk_r->car_plprcr, 0x00000080); + /* Clear the ME bit in MSR to cause checkstop on machine check + */ + mtmsr(mfmsr() & ~0x1000); + + dummy = in_8(&clk_r->res[0]); + printk("Restart failed\n"); + while(1); +} + +void mpc8xx_show_cpuinfo(struct seq_file *m) +{ + struct device_node *root; + uint memsize = total_memory; + const char *model = ""; + + seq_printf(m, "Vendor\t\t: Freescale Semiconductor\n"); + + root = of_find_node_by_path("/"); + if (root) + model = get_property(root, "model", NULL); + seq_printf(m, "Machine\t\t: %s\n", model); + of_node_put(root); + + seq_printf(m, "Memory\t\t: %d MB\n", memsize / (1024 * 1024)); +} + +static void cpm_cascade(unsigned int irq, struct irq_desc *desc) +{ + int cascade_irq; + + if ((cascade_irq = cpm_get_irq()) >= 0) { + struct irq_desc *cdesc = irq_desc + cascade_irq; + + generic_handle_irq(cascade_irq); + cdesc->chip->eoi(cascade_irq); + } + desc->chip->eoi(irq); +} + +/* Initialize the internal interrupt controller. The number of + * interrupts supported can vary with the processor type, and the + * 82xx family can have up to 64. + * External interrupts can be either edge or level triggered, and + * need to be initialized by the appropriate driver. + */ +void __init m8xx_pic_init(void) +{ + int irq; + + if (mpc8xx_pic_init()) { + printk(KERN_ERR "Failed interrupt 8xx controller initialization\n"); + return; + } + + irq = cpm_pic_init(); + if (irq != NO_IRQ) + set_irq_chained_handler(irq, cpm_cascade); +} diff --git a/arch/powerpc/platforms/8xx/mpc86xads.h b/arch/powerpc/platforms/8xx/mpc86xads.h new file mode 100644 index 0000000..b5d19dd --- /dev/null +++ b/arch/powerpc/platforms/8xx/mpc86xads.h @@ -0,0 +1,95 @@ +/* + * A collection of structures, addresses, and values associated with + * the Freescale MPC86xADS board. + * Copied from the FADS stuff. + * + * Author: MontaVista Software, Inc. + * source@mvista.com + * + * 2005 (c) MontaVista Software, Inc. This file is licensed under the + * terms of the GNU General Public License version 2. This program is licensed + * "as is" without any warranty of any kind, whether express or implied. + */ + +#ifdef __KERNEL__ +#ifndef __ASM_MPC86XADS_H__ +#define __ASM_MPC86XADS_H__ + +#include +#include + +/* U-Boot maps BCSR to 0xff080000 */ +#define BCSR_ADDR ((uint)0xff080000) +#define BCSR_SIZE ((uint)32) +#define BCSR0 ((uint)(BCSR_ADDR + 0x00)) +#define BCSR1 ((uint)(BCSR_ADDR + 0x04)) +#define BCSR2 ((uint)(BCSR_ADDR + 0x08)) +#define BCSR3 ((uint)(BCSR_ADDR + 0x0c)) +#define BCSR4 ((uint)(BCSR_ADDR + 0x10)) + +#define CFG_PHYDEV_ADDR ((uint)0xff0a0000) +#define BCSR5 ((uint)(CFG_PHYDEV_ADDR + 0x300)) + +#define IMAP_ADDR (get_immrbase()) +#define IMAP_SIZE ((uint)(64 * 1024)) + +#define MPC8xx_CPM_OFFSET (0x9c0) +#define CPM_MAP_ADDR (get_immrbase() + MPC8xx_CPM_OFFSET) +#define CPM_IRQ_OFFSET 16 // for compability with cpm_uart driver + +#define PCMCIA_MEM_ADDR (uint)0xff020000) +#define PCMCIA_MEM_SIZE ((uint)(64 * 1024)) + +/* Bits of interest in the BCSRs. + */ +#define BCSR1_ETHEN ((uint)0x20000000) +#define BCSR1_IRDAEN ((uint)0x10000000) +#define BCSR1_RS232EN_1 ((uint)0x01000000) +#define BCSR1_PCCEN ((uint)0x00800000) +#define BCSR1_PCCVCC0 ((uint)0x00400000) +#define BCSR1_PCCVPP0 ((uint)0x00200000) +#define BCSR1_PCCVPP1 ((uint)0x00100000) +#define BCSR1_PCCVPP_MASK (BCSR1_PCCVPP0 | BCSR1_PCCVPP1) +#define BCSR1_RS232EN_2 ((uint)0x00040000) +#define BCSR1_PCCVCC1 ((uint)0x00010000) +#define BCSR1_PCCVCC_MASK (BCSR1_PCCVCC0 | BCSR1_PCCVCC1) + +#define BCSR4_ETH10_RST ((uint)0x80000000) /* 10Base-T PHY reset*/ +#define BCSR4_USB_LO_SPD ((uint)0x04000000) +#define BCSR4_USB_VCC ((uint)0x02000000) +#define BCSR4_USB_FULL_SPD ((uint)0x00040000) +#define BCSR4_USB_EN ((uint)0x00020000) + +#define BCSR5_MII2_EN 0x40 +#define BCSR5_MII2_RST 0x20 +#define BCSR5_T1_RST 0x10 +#define BCSR5_ATM155_RST 0x08 +#define BCSR5_ATM25_RST 0x04 +#define BCSR5_MII1_EN 0x02 +#define BCSR5_MII1_RST 0x01 + +/* Interrupt level assignments */ +#define PHY_INTERRUPT SIU_IRQ7 /* PHY link change interrupt */ +#define SIU_INT_FEC1 SIU_LEVEL1 /* FEC1 interrupt */ +#define FEC_INTERRUPT SIU_INT_FEC1 /* FEC interrupt */ + +/* We don't use the 8259 */ +#define NR_8259_INTS 0 + +/* CPM Ethernet through SCC1 */ +#define PA_ENET_RXD ((ushort)0x0001) +#define PA_ENET_TXD ((ushort)0x0002) +#define PA_ENET_TCLK ((ushort)0x0100) +#define PA_ENET_RCLK ((ushort)0x0200) +#define PB_ENET_TENA ((uint)0x00001000) +#define PC_ENET_CLSN ((ushort)0x0010) +#define PC_ENET_RENA ((ushort)0x0020) + +/* Control bits in the SICR to route TCLK (CLK1) and RCLK (CLK2) to + * SCC1. Also, make sure GR1 (bit 24) and SC1 (bit 25) are zero. + */ +#define SICR_ENET_MASK ((uint)0x000000ff) +#define SICR_ENET_CLKRT ((uint)0x0000002c) + +#endif /* __ASM_MPC86XADS_H__ */ +#endif /* __KERNEL__ */ diff --git a/arch/powerpc/platforms/8xx/mpc86xads_setup.c b/arch/powerpc/platforms/8xx/mpc86xads_setup.c new file mode 100644 index 0000000..ef52ce7 --- /dev/null +++ b/arch/powerpc/platforms/8xx/mpc86xads_setup.c @@ -0,0 +1,301 @@ +/*arch/ppc/platforms/mpc86xads-setup.c + * + * Platform setup for the Freescale mpc86xads board + * + * Vitaly Bordug + * + * Copyright 2005 MontaVista Software Inc. + * + * This file is licensed under the terms of the GNU General Public License + * version 2. This program is licensed "as is" without any warranty of any + * kind, whether express or implied. + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +extern void cpm_reset(void); +extern void mpc8xx_show_cpuinfo(struct seq_file*); +extern void mpc8xx_restart(char *cmd); +extern void mpc8xx_calibrate_decr(void); +extern int mpc8xx_set_rtc_time(struct rtc_time *tm); +extern void mpc8xx_get_rtc_time(struct rtc_time *tm); +extern void m8xx_pic_init(void); +extern unsigned int mpc8xx_get_irq(void); + +static void init_smc1_uart_ioports(struct fs_uart_platform_info* fpi); +static void init_smc2_uart_ioports(struct fs_uart_platform_info* fpi); +static void init_scc1_ioports(struct fs_platform_info* ptr); + +void __init mpc86xads_board_setup(void) +{ + cpm8xx_t *cp; + unsigned int *bcsr_io; + u8 tmpval8; + + bcsr_io = ioremap(BCSR1, sizeof(unsigned long)); + cp = (cpm8xx_t *)immr_map(im_cpm); + + if (bcsr_io == NULL) { + printk(KERN_CRIT "Could not remap BCSR\n"); + return; + } +#ifdef CONFIG_SERIAL_CPM_SMC1 + clrbits32(bcsr_io, BCSR1_RS232EN_1); + clrbits32(&cp->cp_simode, 0xe0000000 >> 17); /* brg1 */ + tmpval8 = in_8(&(cp->cp_smc[0].smc_smcm)) | (SMCM_RX | SMCM_TX); + out_8(&(cp->cp_smc[0].smc_smcm), tmpval8); + clrbits16(&cp->cp_smc[0].smc_smcmr, SMCMR_REN | SMCMR_TEN); +#else + setbits32(bcsr_io,BCSR1_RS232EN_1); + out_be16(&cp->cp_smc[0].smc_smcmr, 0); + out_8(&cp->cp_smc[0].smc_smce, 0); +#endif + +#ifdef CONFIG_SERIAL_CPM_SMC2 + clrbits32(bcsr_io,BCSR1_RS232EN_2); + clrbits32(&cp->cp_simode, 0xe0000000 >> 1); + setbits32(&cp->cp_simode, 0x20000000 >> 1); /* brg2 */ + tmpval8 = in_8(&(cp->cp_smc[1].smc_smcm)) | (SMCM_RX | SMCM_TX); + out_8(&(cp->cp_smc[1].smc_smcm), tmpval8); + clrbits16(&cp->cp_smc[1].smc_smcmr, SMCMR_REN | SMCMR_TEN); + + init_smc2_uart_ioports(0); +#else + setbits32(bcsr_io,BCSR1_RS232EN_2); + out_be16(&cp->cp_smc[1].smc_smcmr, 0); + out_8(&cp->cp_smc[1].smc_smce, 0); +#endif + immr_unmap(cp); + iounmap(bcsr_io); +} + + +static void init_fec1_ioports(struct fs_platform_info* ptr) +{ + iop8xx_t *io_port = (iop8xx_t *)immr_map(im_ioport); + + /* configure FEC1 pins */ + + setbits16(&io_port->iop_pdpar, 0x1fff); + setbits16(&io_port->iop_pddir, 0x1fff); + + immr_unmap(io_port); +} + +void init_fec_ioports(struct fs_platform_info *fpi) +{ + int fec_no = fs_get_fec_index(fpi->fs_no); + + switch (fec_no) { + case 0: + init_fec1_ioports(fpi); + break; + default: + printk(KERN_ERR "init_fec_ioports: invalid FEC number\n"); + return; + } +} + +static void init_scc1_ioports(struct fs_platform_info* fpi) +{ + unsigned *bcsr_io; + iop8xx_t *io_port; + cpm8xx_t *cp; + + bcsr_io = ioremap(BCSR_ADDR, BCSR_SIZE); + io_port = (iop8xx_t *)immr_map(im_ioport); + cp = (cpm8xx_t *)immr_map(im_cpm); + + if (bcsr_io == NULL) { + printk(KERN_CRIT "Could not remap BCSR\n"); + return; + } + + /* Configure port A pins for Txd and Rxd. + */ + setbits16(&io_port->iop_papar, PA_ENET_RXD | PA_ENET_TXD); + clrbits16(&io_port->iop_padir, PA_ENET_RXD | PA_ENET_TXD); + clrbits16(&io_port->iop_paodr, PA_ENET_TXD); + + /* Configure port C pins to enable CLSN and RENA. + */ + clrbits16(&io_port->iop_pcpar, PC_ENET_CLSN | PC_ENET_RENA); + clrbits16(&io_port->iop_pcdir, PC_ENET_CLSN | PC_ENET_RENA); + setbits16(&io_port->iop_pcso, PC_ENET_CLSN | PC_ENET_RENA); + + /* Configure port A for TCLK and RCLK. + */ + setbits16(&io_port->iop_papar, PA_ENET_TCLK | PA_ENET_RCLK); + clrbits16(&io_port->iop_padir, PA_ENET_TCLK | PA_ENET_RCLK); + clrbits32(&cp->cp_pbpar, PB_ENET_TENA); + clrbits32(&cp->cp_pbdir, PB_ENET_TENA); + + /* Configure Serial Interface clock routing. + * First, clear all SCC bits to zero, then set the ones we want. + */ + clrbits32(&cp->cp_sicr, SICR_ENET_MASK); + setbits32(&cp->cp_sicr, SICR_ENET_CLKRT); + + /* In the original SCC enet driver the following code is placed at + the end of the initialization */ + setbits32(&cp->cp_pbpar, PB_ENET_TENA); + setbits32(&cp->cp_pbdir, PB_ENET_TENA); + + clrbits32(bcsr_io+1, BCSR1_ETHEN); + iounmap(bcsr_io); + immr_unmap(cp); + immr_unmap(io_port); +} + +void init_scc_ioports(struct fs_platform_info *fpi) +{ + int scc_no = fs_get_scc_index(fpi->fs_no); + + switch (scc_no) { + case 0: + init_scc1_ioports(fpi); + break; + default: + printk(KERN_ERR "init_scc_ioports: invalid SCC number\n"); + return; + } +} + + + +static void init_smc1_uart_ioports(struct fs_uart_platform_info* ptr) +{ + unsigned *bcsr_io; + cpm8xx_t *cp = (cpm8xx_t *)immr_map(im_cpm); + + setbits32(&cp->cp_pbpar, 0x000000c0); + clrbits32(&cp->cp_pbdir, 0x000000c0); + clrbits16(&cp->cp_pbodr, 0x00c0); + immr_unmap(cp); + + bcsr_io = ioremap(BCSR1, sizeof(unsigned long)); + + if (bcsr_io == NULL) { + printk(KERN_CRIT "Could not remap BCSR1\n"); + return; + } + clrbits32(bcsr_io,BCSR1_RS232EN_1); + iounmap(bcsr_io); +} + +static void init_smc2_uart_ioports(struct fs_uart_platform_info* fpi) +{ + unsigned *bcsr_io; + cpm8xx_t *cp = (cpm8xx_t *)immr_map(im_cpm); + + setbits32(&cp->cp_pbpar, 0x00000c00); + clrbits32(&cp->cp_pbdir, 0x00000c00); + clrbits16(&cp->cp_pbodr, 0x0c00); + immr_unmap(cp); + + bcsr_io = ioremap(BCSR1, sizeof(unsigned long)); + + if (bcsr_io == NULL) { + printk(KERN_CRIT "Could not remap BCSR1\n"); + return; + } + clrbits32(bcsr_io,BCSR1_RS232EN_2); + iounmap(bcsr_io); +} + +void init_smc_ioports(struct fs_uart_platform_info *data) +{ + int smc_no = fs_uart_id_fsid2smc(data->fs_no); + + switch (smc_no) { + case 0: + init_smc1_uart_ioports(data); + data->brg = data->clk_rx; + break; + case 1: + init_smc2_uart_ioports(data); + data->brg = data->clk_rx; + break; + default: + printk(KERN_ERR "init_scc_ioports: invalid SCC number\n"); + return; + } +} + +int platform_device_skip(char *model, int id) +{ + return 0; +} + +static void __init mpc86xads_setup_arch(void) +{ + struct device_node *cpu; + + cpu = of_find_node_by_type(NULL, "cpu"); + if (cpu != 0) { + const unsigned int *fp; + + fp = get_property(cpu, "clock-frequency", NULL); + if (fp != 0) + loops_per_jiffy = *fp / HZ; + else + loops_per_jiffy = 50000000 / HZ; + of_node_put(cpu); + } + + cpm_reset(); + + mpc86xads_board_setup(); + + ROOT_DEV = Root_NFS; +} + +static int __init mpc86xads_probe(void) +{ + char *model = of_get_flat_dt_prop(of_get_flat_dt_root(), + "model", NULL); + if (model == NULL) + return 0; + if (strcmp(model, "MPC866ADS")) + return 0; + + return 1; +} + +define_machine(mpc86x_ads) { + .name = "MPC86x ADS", + .probe = mpc86xads_probe, + .setup_arch = mpc86xads_setup_arch, + .init_IRQ = m8xx_pic_init, + .show_cpuinfo = mpc8xx_show_cpuinfo, + .get_irq = mpc8xx_get_irq, + .restart = mpc8xx_restart, + .calibrate_decr = mpc8xx_calibrate_decr, + .set_rtc_time = mpc8xx_set_rtc_time, + .get_rtc_time = mpc8xx_get_rtc_time, +}; diff --git a/arch/powerpc/platforms/8xx/mpc885ads.h b/arch/powerpc/platforms/8xx/mpc885ads.h new file mode 100644 index 0000000..30cbebf --- /dev/null +++ b/arch/powerpc/platforms/8xx/mpc885ads.h @@ -0,0 +1,95 @@ +/* + * A collection of structures, addresses, and values associated with + * the Freescale MPC885ADS board. + * Copied from the FADS stuff. + * + * Author: MontaVista Software, Inc. + * source@mvista.com + * + * 2005 (c) MontaVista Software, Inc. This file is licensed under the + * terms of the GNU General Public License version 2. This program is licensed + * "as is" without any warranty of any kind, whether express or implied. + */ + +#ifdef __KERNEL__ +#ifndef __ASM_MPC885ADS_H__ +#define __ASM_MPC885ADS_H__ + +#include +#include + +/* U-Boot maps BCSR to 0xff080000 */ +#define BCSR_ADDR ((uint)0xff080000) +#define BCSR_SIZE ((uint)32) +#define BCSR0 ((uint)(BCSR_ADDR + 0x00)) +#define BCSR1 ((uint)(BCSR_ADDR + 0x04)) +#define BCSR2 ((uint)(BCSR_ADDR + 0x08)) +#define BCSR3 ((uint)(BCSR_ADDR + 0x0c)) +#define BCSR4 ((uint)(BCSR_ADDR + 0x10)) + +#define CFG_PHYDEV_ADDR ((uint)0xff0a0000) +#define BCSR5 ((uint)(CFG_PHYDEV_ADDR + 0x300)) + +#define IMAP_ADDR (get_immrbase()) +#define IMAP_SIZE ((uint)(64 * 1024)) + +#define MPC8xx_CPM_OFFSET (0x9c0) +#define CPM_MAP_ADDR (get_immrbase() + MPC8xx_CPM_OFFSET) +#define CPM_IRQ_OFFSET 16 // for compability with cpm_uart driver + +#define PCMCIA_MEM_ADDR (uint)0xff020000) +#define PCMCIA_MEM_SIZE ((uint)(64 * 1024)) + +/* Bits of interest in the BCSRs. + */ +#define BCSR1_ETHEN ((uint)0x20000000) +#define BCSR1_IRDAEN ((uint)0x10000000) +#define BCSR1_RS232EN_1 ((uint)0x01000000) +#define BCSR1_PCCEN ((uint)0x00800000) +#define BCSR1_PCCVCC0 ((uint)0x00400000) +#define BCSR1_PCCVPP0 ((uint)0x00200000) +#define BCSR1_PCCVPP1 ((uint)0x00100000) +#define BCSR1_PCCVPP_MASK (BCSR1_PCCVPP0 | BCSR1_PCCVPP1) +#define BCSR1_RS232EN_2 ((uint)0x00040000) +#define BCSR1_PCCVCC1 ((uint)0x00010000) +#define BCSR1_PCCVCC_MASK (BCSR1_PCCVCC0 | BCSR1_PCCVCC1) + +#define BCSR4_ETH10_RST ((uint)0x80000000) /* 10Base-T PHY reset*/ +#define BCSR4_USB_LO_SPD ((uint)0x04000000) +#define BCSR4_USB_VCC ((uint)0x02000000) +#define BCSR4_USB_FULL_SPD ((uint)0x00040000) +#define BCSR4_USB_EN ((uint)0x00020000) + +#define BCSR5_MII2_EN 0x40 +#define BCSR5_MII2_RST 0x20 +#define BCSR5_T1_RST 0x10 +#define BCSR5_ATM155_RST 0x08 +#define BCSR5_ATM25_RST 0x04 +#define BCSR5_MII1_EN 0x02 +#define BCSR5_MII1_RST 0x01 + +/* Interrupt level assignments */ +#define PHY_INTERRUPT SIU_IRQ7 /* PHY link change interrupt */ +#define SIU_INT_FEC1 SIU_LEVEL1 /* FEC1 interrupt */ +#define SIU_INT_FEC2 SIU_LEVEL3 /* FEC2 interrupt */ +#define FEC_INTERRUPT SIU_INT_FEC1 /* FEC interrupt */ + +/* We don't use the 8259 */ +#define NR_8259_INTS 0 + +/* CPM Ethernet through SCC3 */ +#define PA_ENET_RXD ((ushort)0x0040) +#define PA_ENET_TXD ((ushort)0x0080) +#define PE_ENET_TCLK ((uint)0x00004000) +#define PE_ENET_RCLK ((uint)0x00008000) +#define PE_ENET_TENA ((uint)0x00000010) +#define PC_ENET_CLSN ((ushort)0x0400) +#define PC_ENET_RENA ((ushort)0x0800) + +/* Control bits in the SICR to route TCLK (CLK5) and RCLK (CLK6) to + * SCC3. Also, make sure GR3 (bit 8) and SC3 (bit 9) are zero */ +#define SICR_ENET_MASK ((uint)0x00ff0000) +#define SICR_ENET_CLKRT ((uint)0x002c0000) + +#endif /* __ASM_MPC885ADS_H__ */ +#endif /* __KERNEL__ */ diff --git a/arch/powerpc/platforms/8xx/mpc885ads_setup.c b/arch/powerpc/platforms/8xx/mpc885ads_setup.c new file mode 100644 index 0000000..c5fefdf --- /dev/null +++ b/arch/powerpc/platforms/8xx/mpc885ads_setup.c @@ -0,0 +1,387 @@ +/*arch/ppc/platforms/mpc885ads-setup.c + * + * Platform setup for the Freescale mpc885ads board + * + * Vitaly Bordug + * + * Copyright 2005 MontaVista Software Inc. + * + * This file is licensed under the terms of the GNU General Public License + * version 2. This program is licensed "as is" without any warranty of any + * kind, whether express or implied. + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +extern void cpm_reset(void); +extern void mpc8xx_show_cpuinfo(struct seq_file*); +extern void mpc8xx_restart(char *cmd); +extern void mpc8xx_calibrate_decr(void); +extern int mpc8xx_set_rtc_time(struct rtc_time *tm); +extern void mpc8xx_get_rtc_time(struct rtc_time *tm); +extern void m8xx_pic_init(void); +extern unsigned int mpc8xx_get_irq(void); + +static void init_smc1_uart_ioports(struct fs_uart_platform_info* fpi); +static void init_smc2_uart_ioports(struct fs_uart_platform_info* fpi); +static void init_scc3_ioports(struct fs_platform_info* ptr); + +void __init mpc885ads_board_setup(void) +{ + cpm8xx_t *cp; + unsigned int *bcsr_io; + u8 tmpval8; + +#ifdef CONFIG_FS_ENET + iop8xx_t *io_port; +#endif + + bcsr_io = ioremap(BCSR1, sizeof(unsigned long)); + cp = (cpm8xx_t *)immr_map(im_cpm); + + if (bcsr_io == NULL) { + printk(KERN_CRIT "Could not remap BCSR\n"); + return; + } +#ifdef CONFIG_SERIAL_CPM_SMC1 + clrbits32(bcsr_io, BCSR1_RS232EN_1); + clrbits32(&cp->cp_simode, 0xe0000000 >> 17); /* brg1 */ + tmpval8 = in_8(&(cp->cp_smc[0].smc_smcm)) | (SMCM_RX | SMCM_TX); + out_8(&(cp->cp_smc[0].smc_smcm), tmpval8); + clrbits16(&cp->cp_smc[0].smc_smcmr, SMCMR_REN | SMCMR_TEN); /* brg1 */ +#else + setbits32(bcsr_io,BCSR1_RS232EN_1); + out_be16(&cp->cp_smc[0].smc_smcmr, 0); + out_8(&cp->cp_smc[0].smc_smce, 0); +#endif + +#ifdef CONFIG_SERIAL_CPM_SMC2 + clrbits32(bcsr_io,BCSR1_RS232EN_2); + clrbits32(&cp->cp_simode, 0xe0000000 >> 1); + setbits32(&cp->cp_simode, 0x20000000 >> 1); /* brg2 */ + tmpval8 = in_8(&(cp->cp_smc[1].smc_smcm)) | (SMCM_RX | SMCM_TX); + out_8(&(cp->cp_smc[1].smc_smcm), tmpval8); + clrbits16(&cp->cp_smc[1].smc_smcmr, SMCMR_REN | SMCMR_TEN); + + init_smc2_uart_ioports(0); +#else + setbits32(bcsr_io,BCSR1_RS232EN_2); + out_be16(&cp->cp_smc[1].smc_smcmr, 0); + out_8(&cp->cp_smc[1].smc_smce, 0); +#endif + immr_unmap(cp); + iounmap(bcsr_io); + +#ifdef CONFIG_FS_ENET + /* use MDC for MII (common) */ + io_port = (iop8xx_t*)immr_map(im_ioport); + setbits16(&io_port->iop_pdpar, 0x0080); + clrbits16(&io_port->iop_pddir, 0x0080); + + bcsr_io = ioremap(BCSR5, sizeof(unsigned long)); + clrbits32(bcsr_io,BCSR5_MII1_EN); + clrbits32(bcsr_io,BCSR5_MII1_RST); +#ifndef CONFIG_FC_ENET_HAS_SCC + clrbits32(bcsr_io,BCSR5_MII2_EN); + clrbits32(bcsr_io,BCSR5_MII2_RST); + +#endif + iounmap(bcsr_io); + immr_unmap(io_port); + +#endif +} + + +static void init_fec1_ioports(struct fs_platform_info* ptr) +{ + cpm8xx_t *cp = (cpm8xx_t *)immr_map(im_cpm); + iop8xx_t *io_port = (iop8xx_t *)immr_map(im_ioport); + + /* configure FEC1 pins */ + setbits16(&io_port->iop_papar, 0xf830); + setbits16(&io_port->iop_padir, 0x0830); + clrbits16(&io_port->iop_padir, 0xf000); + + setbits32(&cp->cp_pbpar, 0x00001001); + clrbits32(&cp->cp_pbdir, 0x00001001); + + setbits16(&io_port->iop_pcpar, 0x000c); + clrbits16(&io_port->iop_pcdir, 0x000c); + + setbits32(&cp->cp_pepar, 0x00000003); + setbits32(&cp->cp_pedir, 0x00000003); + clrbits32(&cp->cp_peso, 0x00000003); + clrbits32(&cp->cp_cptr, 0x00000100); + + immr_unmap(io_port); + immr_unmap(cp); +} + + +static void init_fec2_ioports(struct fs_platform_info* ptr) +{ + cpm8xx_t *cp = (cpm8xx_t *)immr_map(im_cpm); + iop8xx_t *io_port = (iop8xx_t *)immr_map(im_ioport); + + /* configure FEC2 pins */ + setbits32(&cp->cp_pepar, 0x0003fffc); + setbits32(&cp->cp_pedir, 0x0003fffc); + clrbits32(&cp->cp_peso, 0x000087fc); + setbits32(&cp->cp_peso, 0x00037800); + clrbits32(&cp->cp_cptr, 0x00000080); + + immr_unmap(io_port); + immr_unmap(cp); +} + +void init_fec_ioports(struct fs_platform_info *fpi) +{ + int fec_no = fs_get_fec_index(fpi->fs_no); + + switch (fec_no) { + case 0: + init_fec1_ioports(fpi); + break; + case 1: + init_fec2_ioports(fpi); + break; + default: + printk(KERN_ERR "init_fec_ioports: invalid FEC number\n"); + return; + } +} + +static void init_scc3_ioports(struct fs_platform_info* fpi) +{ + unsigned *bcsr_io; + iop8xx_t *io_port; + cpm8xx_t *cp; + + bcsr_io = ioremap(BCSR_ADDR, BCSR_SIZE); + io_port = (iop8xx_t *)immr_map(im_ioport); + cp = (cpm8xx_t *)immr_map(im_cpm); + + if (bcsr_io == NULL) { + printk(KERN_CRIT "Could not remap BCSR\n"); + return; + } + + /* Enable the PHY. + */ + clrbits32(bcsr_io+4, BCSR4_ETH10_RST); + udelay(1000); + setbits32(bcsr_io+4, BCSR4_ETH10_RST); + /* Configure port A pins for Txd and Rxd. + */ + setbits16(&io_port->iop_papar, PA_ENET_RXD | PA_ENET_TXD); + clrbits16(&io_port->iop_padir, PA_ENET_RXD | PA_ENET_TXD); + + /* Configure port C pins to enable CLSN and RENA. + */ + clrbits16(&io_port->iop_pcpar, PC_ENET_CLSN | PC_ENET_RENA); + clrbits16(&io_port->iop_pcdir, PC_ENET_CLSN | PC_ENET_RENA); + setbits16(&io_port->iop_pcso, PC_ENET_CLSN | PC_ENET_RENA); + + /* Configure port E for TCLK and RCLK. + */ + setbits32(&cp->cp_pepar, PE_ENET_TCLK | PE_ENET_RCLK); + clrbits32(&cp->cp_pepar, PE_ENET_TENA); + clrbits32(&cp->cp_pedir, + PE_ENET_TCLK | PE_ENET_RCLK | PE_ENET_TENA); + clrbits32(&cp->cp_peso, PE_ENET_TCLK | PE_ENET_RCLK); + setbits32(&cp->cp_peso, PE_ENET_TENA); + + /* Configure Serial Interface clock routing. + * First, clear all SCC bits to zero, then set the ones we want. + */ + clrbits32(&cp->cp_sicr, SICR_ENET_MASK); + setbits32(&cp->cp_sicr, SICR_ENET_CLKRT); + + /* Disable Rx and Tx. SMC1 sshould be stopped if SCC3 eternet are used. + */ + clrbits16(&cp->cp_smc[0].smc_smcmr, SMCMR_REN | SMCMR_TEN); + /* On the MPC885ADS SCC ethernet PHY is initialized in the full duplex mode + * by H/W setting after reset. SCC ethernet controller support only half duplex. + * This discrepancy of modes causes a lot of carrier lost errors. + */ + + /* In the original SCC enet driver the following code is placed at + the end of the initialization */ + setbits32(&cp->cp_pepar, PE_ENET_TENA); + clrbits32(&cp->cp_pedir, PE_ENET_TENA); + setbits32(&cp->cp_peso, PE_ENET_TENA); + + setbits32(bcsr_io+4, BCSR1_ETHEN); + iounmap(bcsr_io); + immr_unmap(io_port); + immr_unmap(cp); +} + +void init_scc_ioports(struct fs_platform_info *fpi) +{ + int scc_no = fs_get_scc_index(fpi->fs_no); + + switch (scc_no) { + case 2: + init_scc3_ioports(fpi); + break; + default: + printk(KERN_ERR "init_scc_ioports: invalid SCC number\n"); + return; + } +} + + + +static void init_smc1_uart_ioports(struct fs_uart_platform_info* ptr) +{ + unsigned *bcsr_io; + cpm8xx_t *cp; + + cp = (cpm8xx_t *)immr_map(im_cpm); + setbits32(&cp->cp_pepar, 0x000000c0); + clrbits32(&cp->cp_pedir, 0x000000c0); + clrbits32(&cp->cp_peso, 0x00000040); + setbits32(&cp->cp_peso, 0x00000080); + immr_unmap(cp); + + bcsr_io = ioremap(BCSR1, sizeof(unsigned long)); + + if (bcsr_io == NULL) { + printk(KERN_CRIT "Could not remap BCSR1\n"); + return; + } + clrbits32(bcsr_io,BCSR1_RS232EN_1); + iounmap(bcsr_io); +} + +static void init_smc2_uart_ioports(struct fs_uart_platform_info* fpi) +{ + unsigned *bcsr_io; + cpm8xx_t *cp; + + cp = (cpm8xx_t *)immr_map(im_cpm); + setbits32(&cp->cp_pepar, 0x00000c00); + clrbits32(&cp->cp_pedir, 0x00000c00); + clrbits32(&cp->cp_peso, 0x00000400); + setbits32(&cp->cp_peso, 0x00000800); + immr_unmap(cp); + + bcsr_io = ioremap(BCSR1, sizeof(unsigned long)); + + if (bcsr_io == NULL) { + printk(KERN_CRIT "Could not remap BCSR1\n"); + return; + } + clrbits32(bcsr_io,BCSR1_RS232EN_2); + iounmap(bcsr_io); +} + +void init_smc_ioports(struct fs_uart_platform_info *data) +{ + int smc_no = fs_uart_id_fsid2smc(data->fs_no); + + switch (smc_no) { + case 0: + init_smc1_uart_ioports(data); + data->brg = data->clk_rx; + break; + case 1: + init_smc2_uart_ioports(data); + data->brg = data->clk_rx; + break; + default: + printk(KERN_ERR "init_scc_ioports: invalid SCC number\n"); + return; + } +} + +int platform_device_skip(char *model, int id) +{ +#ifdef CONFIG_MPC8xx_SECOND_ETH_SCC3 + const char *dev = "FEC"; + int n = 2; +#else + const char *dev = "SCC"; + int n = 3; +#endif + + if (!strcmp(model, dev) && n == id) + return 1; + + return 0; +} + +static void __init mpc885ads_setup_arch(void) +{ + struct device_node *cpu; + + cpu = of_find_node_by_type(NULL, "cpu"); + if (cpu != 0) { + const unsigned int *fp; + + fp = get_property(cpu, "clock-frequency", NULL); + if (fp != 0) + loops_per_jiffy = *fp / HZ; + else + loops_per_jiffy = 50000000 / HZ; + of_node_put(cpu); + } + + cpm_reset(); + + mpc885ads_board_setup(); + + ROOT_DEV = Root_NFS; +} + +static int __init mpc885ads_probe(void) +{ + char *model = of_get_flat_dt_prop(of_get_flat_dt_root(), + "model", NULL); + if (model == NULL) + return 0; + if (strcmp(model, "MPC885ADS")) + return 0; + + return 1; +} + +define_machine(mpc885_ads) { + .name = "MPC885 ADS", + .probe = mpc885ads_probe, + .setup_arch = mpc885ads_setup_arch, + .init_IRQ = m8xx_pic_init, + .show_cpuinfo = mpc8xx_show_cpuinfo, + .get_irq = mpc8xx_get_irq, + .restart = mpc8xx_restart, + .calibrate_decr = mpc8xx_calibrate_decr, + .set_rtc_time = mpc8xx_set_rtc_time, + .get_rtc_time = mpc8xx_get_rtc_time, +}; diff --git a/arch/powerpc/platforms/Makefile b/arch/powerpc/platforms/Makefile index 507d1b9..4520042 100644 --- a/arch/powerpc/platforms/Makefile +++ b/arch/powerpc/platforms/Makefile @@ -5,9 +5,11 @@ ifeq ($(CONFIG_PPC64),y) obj-$(CONFIG_PPC_PMAC) += powermac/ endif endif -obj-$(CONFIG_PPC_MPC52xx) += 52xx/ obj-$(CONFIG_PPC_CHRP) += chrp/ obj-$(CONFIG_4xx) += 4xx/ +obj-$(CONFIG_PPC_MPC52xx) += 52xx/ +obj-$(CONFIG_PPC_8xx) += 8xx/ +obj-$(CONFIG_PPC_82xx) += 82xx/ obj-$(CONFIG_PPC_83xx) += 83xx/ obj-$(CONFIG_PPC_85xx) += 85xx/ obj-$(CONFIG_PPC_86xx) += 86xx/ @@ -17,4 +19,5 @@ obj-$(CONFIG_PPC_MAPLE) += maple/ obj-$(CONFIG_PPC_PASEMI) += pasemi/ obj-$(CONFIG_PPC_CELL) += cell/ obj-$(CONFIG_PPC_PS3) += ps3/ +obj-$(CONFIG_PPC_CELLEB) += celleb/ obj-$(CONFIG_EMBEDDED6xx) += embedded6xx/ diff --git a/arch/powerpc/platforms/cell/Makefile b/arch/powerpc/platforms/cell/Makefile index f90e833..869af89 100644 --- a/arch/powerpc/platforms/cell/Makefile +++ b/arch/powerpc/platforms/cell/Makefile @@ -14,7 +14,12 @@ # needed only when building loadable spu spufs-modular-$(CONFIG_SPU_FS) += spu_syscalls.o spu-priv1-$(CONFIG_PPC_CELL_NATIVE) += spu_priv1_mmio.o +spu-manage-$(CONFIG_PPC_CELLEB) += spu_manage.o +spu-manage-$(CONFIG_PPC_CELL_NATIVE) += spu_manage.o + obj-$(CONFIG_SPU_BASE) += spu_callbacks.o spu_base.o \ spu_coredump.o \ $(spufs-modular-m) \ - $(spu-priv1-y) spufs/ + $(spu-priv1-y) \ + $(spu-manage-y) \ + spufs/ diff --git a/arch/powerpc/platforms/cell/iommu.c b/arch/powerpc/platforms/cell/iommu.c index b43466b..67d617b 100644 --- a/arch/powerpc/platforms/cell/iommu.c +++ b/arch/powerpc/platforms/cell/iommu.c @@ -149,7 +149,8 @@ static int cbe_nr_iommus; static void invalidate_tce_cache(struct cbe_iommu *iommu, unsigned long *pte, long n_ptes) { - unsigned long *reg, val; + unsigned long __iomem *reg; + unsigned long val; long n; reg = iommu->xlate_regs + IOC_IOPT_CacheInvd; @@ -592,7 +593,7 @@ static void __init cell_iommu_init_one(s /* Init base fields */ i = cbe_nr_iommus++; iommu = &iommus[i]; - iommu->stab = 0; + iommu->stab = NULL; iommu->nid = nid; snprintf(iommu->name, sizeof(iommu->name), "iommu%d", i); INIT_LIST_HEAD(&iommu->windows); diff --git a/arch/powerpc/platforms/cell/pmu.c b/arch/powerpc/platforms/cell/pmu.c index d04ae16..66ca4b5 100644 --- a/arch/powerpc/platforms/cell/pmu.c +++ b/arch/powerpc/platforms/cell/pmu.c @@ -345,18 +345,12 @@ EXPORT_SYMBOL_GPL(cbe_read_trace_buffer) * Enabling/disabling interrupts for the entire performance monitoring unit. */ -u32 cbe_query_pm_interrupts(u32 cpu) -{ - return cbe_read_pm(cpu, pm_status); -} -EXPORT_SYMBOL_GPL(cbe_query_pm_interrupts); - -u32 cbe_clear_pm_interrupts(u32 cpu) +u32 cbe_get_and_clear_pm_interrupts(u32 cpu) { /* Reading pm_status clears the interrupt bits. */ - return cbe_query_pm_interrupts(cpu); + return cbe_read_pm(cpu, pm_status); } -EXPORT_SYMBOL_GPL(cbe_clear_pm_interrupts); +EXPORT_SYMBOL_GPL(cbe_get_and_clear_pm_interrupts); void cbe_enable_pm_interrupts(u32 cpu, u32 thread, u32 mask) { @@ -371,7 +365,7 @@ EXPORT_SYMBOL_GPL(cbe_enable_pm_interrup void cbe_disable_pm_interrupts(u32 cpu) { - cbe_clear_pm_interrupts(cpu); + cbe_get_and_clear_pm_interrupts(cpu); cbe_write_pm(cpu, pm_status, 0); } EXPORT_SYMBOL_GPL(cbe_disable_pm_interrupts); diff --git a/arch/powerpc/platforms/cell/spu_base.c b/arch/powerpc/platforms/cell/spu_base.c index bd7bffc..c43999a 100644 --- a/arch/powerpc/platforms/cell/spu_base.c +++ b/arch/powerpc/platforms/cell/spu_base.c @@ -170,9 +170,11 @@ int spu_irq_class_0_bottom(struct spu *spu) { unsigned long stat, mask; + unsigned long flags; spu->class_0_pending = 0; + spin_lock_irqsave(&spu->register_lock, flags); mask = spu_int_mask_get(spu, 0); stat = spu_int_stat_get(spu, 0); @@ -188,6 +190,7 @@ spu_irq_class_0_bottom(struct spu *spu) __spu_trap_error(spu); spu_int_stat_clear(spu, 0, stat); + spin_unlock_irqrestore(&spu->register_lock, flags); return (stat & 0x7) ? -EIO : 0; } diff --git a/arch/powerpc/platforms/cell/spu_manage.c b/arch/powerpc/platforms/cell/spu_manage.c new file mode 100644 index 0000000..e34599f --- /dev/null +++ b/arch/powerpc/platforms/cell/spu_manage.c @@ -0,0 +1,366 @@ +/* + * spu management operations for of based platforms + * + * (C) Copyright IBM Deutschland Entwicklung GmbH 2005 + * Copyright 2006 Sony Corp. + * (C) Copyright 2007 TOSHIBA 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. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include "interrupt.h" + +struct device_node *spu_devnode(struct spu *spu) +{ + return spu->devnode; +} + +EXPORT_SYMBOL_GPL(spu_devnode); + +static u64 __init find_spu_unit_number(struct device_node *spe) +{ + const unsigned int *prop; + int proplen; + prop = get_property(spe, "unit-id", &proplen); + if (proplen == 4) + return (u64)*prop; + + prop = get_property(spe, "reg", &proplen); + if (proplen == 4) + return (u64)*prop; + + return 0; +} + +static void spu_unmap(struct spu *spu) +{ + if (!firmware_has_feature(FW_FEATURE_LPAR)) + iounmap(spu->priv1); + iounmap(spu->priv2); + iounmap(spu->problem); + iounmap((__force u8 __iomem *)spu->local_store); +} + +static int __init spu_map_interrupts_old(struct spu *spu, + struct device_node *np) +{ + unsigned int isrc; + const u32 *tmp; + int nid; + + /* Get the interrupt source unit from the device-tree */ + tmp = get_property(np, "isrc", NULL); + if (!tmp) + return -ENODEV; + isrc = tmp[0]; + + tmp = get_property(np->parent->parent, "node-id", NULL); + if (!tmp) { + printk(KERN_WARNING "%s: can't find node-id\n", __FUNCTION__); + nid = spu->node; + } else + nid = tmp[0]; + + /* Add the node number */ + isrc |= nid << IIC_IRQ_NODE_SHIFT; + + /* Now map interrupts of all 3 classes */ + spu->irqs[0] = irq_create_mapping(NULL, IIC_IRQ_CLASS_0 | isrc); + spu->irqs[1] = irq_create_mapping(NULL, IIC_IRQ_CLASS_1 | isrc); + spu->irqs[2] = irq_create_mapping(NULL, IIC_IRQ_CLASS_2 | isrc); + + /* Right now, we only fail if class 2 failed */ + return spu->irqs[2] == NO_IRQ ? -EINVAL : 0; +} + +static void __iomem * __init spu_map_prop_old(struct spu *spu, + struct device_node *n, + const char *name) +{ + const struct address_prop { + unsigned long address; + unsigned int len; + } __attribute__((packed)) *prop; + int proplen; + + prop = get_property(n, name, &proplen); + if (prop == NULL || proplen != sizeof (struct address_prop)) + return NULL; + + return ioremap(prop->address, prop->len); +} + +static int __init spu_map_device_old(struct spu *spu) +{ + struct device_node *node = spu->devnode; + const char *prop; + int ret; + + ret = -ENODEV; + spu->name = get_property(node, "name", NULL); + if (!spu->name) + goto out; + + prop = get_property(node, "local-store", NULL); + if (!prop) + goto out; + spu->local_store_phys = *(unsigned long *)prop; + + /* we use local store as ram, not io memory */ + spu->local_store = (void __force *) + spu_map_prop_old(spu, node, "local-store"); + if (!spu->local_store) + goto out; + + prop = get_property(node, "problem", NULL); + if (!prop) + goto out_unmap; + spu->problem_phys = *(unsigned long *)prop; + + spu->problem = spu_map_prop_old(spu, node, "problem"); + if (!spu->problem) + goto out_unmap; + + spu->priv2 = spu_map_prop_old(spu, node, "priv2"); + if (!spu->priv2) + goto out_unmap; + + if (!firmware_has_feature(FW_FEATURE_LPAR)) { + spu->priv1 = spu_map_prop_old(spu, node, "priv1"); + if (!spu->priv1) + goto out_unmap; + } + + ret = 0; + goto out; + +out_unmap: + spu_unmap(spu); +out: + return ret; +} + +static int __init spu_map_interrupts(struct spu *spu, struct device_node *np) +{ + struct of_irq oirq; + int ret; + int i; + + for (i=0; i < 3; i++) { + ret = of_irq_map_one(np, i, &oirq); + if (ret) { + pr_debug("spu_new: failed to get irq %d\n", i); + goto err; + } + ret = -EINVAL; + pr_debug(" irq %d no 0x%x on %s\n", i, oirq.specifier[0], + oirq.controller->full_name); + spu->irqs[i] = irq_create_of_mapping(oirq.controller, + oirq.specifier, oirq.size); + if (spu->irqs[i] == NO_IRQ) { + pr_debug("spu_new: failed to map it !\n"); + goto err; + } + } + return 0; + +err: + pr_debug("failed to map irq %x for spu %s\n", *oirq.specifier, + spu->name); + for (; i >= 0; i--) { + if (spu->irqs[i] != NO_IRQ) + irq_dispose_mapping(spu->irqs[i]); + } + return ret; +} + +static int spu_map_resource(struct spu *spu, int nr, + void __iomem** virt, unsigned long *phys) +{ + struct device_node *np = spu->devnode; + struct resource resource = { }; + unsigned long len; + int ret; + + ret = of_address_to_resource(np, nr, &resource); + if (ret) + return ret; + if (phys) + *phys = resource.start; + len = resource.end - resource.start + 1; + *virt = ioremap(resource.start, len); + if (!*virt) + return -EINVAL; + return 0; +} + +static int __init spu_map_device(struct spu *spu) +{ + struct device_node *np = spu->devnode; + int ret = -ENODEV; + + spu->name = get_property(np, "name", NULL); + if (!spu->name) + goto out; + + ret = spu_map_resource(spu, 0, (void __iomem**)&spu->local_store, + &spu->local_store_phys); + if (ret) { + pr_debug("spu_new: failed to map %s resource 0\n", + np->full_name); + goto out; + } + ret = spu_map_resource(spu, 1, (void __iomem**)&spu->problem, + &spu->problem_phys); + if (ret) { + pr_debug("spu_new: failed to map %s resource 1\n", + np->full_name); + goto out_unmap; + } + ret = spu_map_resource(spu, 2, (void __iomem**)&spu->priv2, NULL); + if (ret) { + pr_debug("spu_new: failed to map %s resource 2\n", + np->full_name); + goto out_unmap; + } + if (!firmware_has_feature(FW_FEATURE_LPAR)) + ret = spu_map_resource(spu, 3, + (void __iomem**)&spu->priv1, NULL); + if (ret) { + pr_debug("spu_new: failed to map %s resource 3\n", + np->full_name); + goto out_unmap; + } + pr_debug("spu_new: %s maps:\n", np->full_name); + pr_debug(" local store : 0x%016lx -> 0x%p\n", + spu->local_store_phys, spu->local_store); + pr_debug(" problem state : 0x%016lx -> 0x%p\n", + spu->problem_phys, spu->problem); + pr_debug(" priv2 : 0x%p\n", spu->priv2); + pr_debug(" priv1 : 0x%p\n", spu->priv1); + + return 0; + +out_unmap: + spu_unmap(spu); +out: + pr_debug("failed to map spe %s: %d\n", spu->name, ret); + return ret; +} + +static int __init of_enumerate_spus(int (*fn)(void *data)) +{ + int ret; + struct device_node *node; + + ret = -ENODEV; + for (node = of_find_node_by_type(NULL, "spe"); + node; node = of_find_node_by_type(node, "spe")) { + ret = fn(node); + if (ret) { + printk(KERN_WARNING "%s: Error initializing %s\n", + __FUNCTION__, node->name); + break; + } + } + return ret; +} + +static int __init of_create_spu(struct spu *spu, void *data) +{ + int ret; + struct device_node *spe = (struct device_node *)data; + static int legacy_map = 0, legacy_irq = 0; + + spu->devnode = of_node_get(spe); + spu->spe_id = find_spu_unit_number(spe); + + spu->node = of_node_to_nid(spe); + if (spu->node >= MAX_NUMNODES) { + printk(KERN_WARNING "SPE %s on node %d ignored," + " node number too big\n", spe->full_name, spu->node); + printk(KERN_WARNING "Check if CONFIG_NUMA is enabled.\n"); + ret = -ENODEV; + goto out; + } + + ret = spu_map_device(spu); + if (ret) { + if (!legacy_map) { + legacy_map = 1; + printk(KERN_WARNING "%s: Legacy device tree found, " + "trying to map old style\n", __FUNCTION__); + } + ret = spu_map_device_old(spu); + if (ret) { + printk(KERN_ERR "Unable to map %s\n", + spu->name); + goto out; + } + } + + ret = spu_map_interrupts(spu, spe); + if (ret) { + if (!legacy_irq) { + legacy_irq = 1; + printk(KERN_WARNING "%s: Legacy device tree found, " + "trying old style irq\n", __FUNCTION__); + } + ret = spu_map_interrupts_old(spu, spe); + if (ret) { + printk(KERN_ERR "%s: could not map interrupts", + spu->name); + goto out_unmap; + } + } + + pr_debug("Using SPE %s %p %p %p %p %d\n", spu->name, + spu->local_store, spu->problem, spu->priv1, + spu->priv2, spu->number); + goto out; + +out_unmap: + spu_unmap(spu); +out: + return ret; +} + +static int of_destroy_spu(struct spu *spu) +{ + spu_unmap(spu); + of_node_put(spu->devnode); + return 0; +} + +const struct spu_management_ops spu_management_of_ops = { + .enumerate_spus = of_enumerate_spus, + .create_spu = of_create_spu, + .destroy_spu = of_destroy_spu, +}; diff --git a/arch/powerpc/platforms/cell/spu_priv1_mmio.c b/arch/powerpc/platforms/cell/spu_priv1_mmio.c index 910a926..67fa724 100644 --- a/arch/powerpc/platforms/cell/spu_priv1_mmio.c +++ b/arch/powerpc/platforms/cell/spu_priv1_mmio.c @@ -37,490 +37,112 @@ #include #include "interrupt.h" #include "spu_priv1_mmio.h" -static DEFINE_MUTEX(add_spumem_mutex); - -struct spu_pdata { - struct device_node *devnode; - struct spu_priv1 __iomem *priv1; -}; - -static struct spu_pdata *spu_get_pdata(struct spu *spu) -{ - BUG_ON(!spu->pdata); - return spu->pdata; -} - -struct device_node *spu_devnode(struct spu *spu) -{ - return spu_get_pdata(spu)->devnode; -} - -EXPORT_SYMBOL_GPL(spu_devnode); - -static int __init cell_spuprop_present(struct spu *spu, struct device_node *spe, - const char *prop) -{ - const struct address_prop { - unsigned long address; - unsigned int len; - } __attribute__((packed)) *p; - int proplen; - - unsigned long start_pfn, nr_pages; - struct pglist_data *pgdata; - struct zone *zone; - int ret; - - p = get_property(spe, prop, &proplen); - WARN_ON(proplen != sizeof (*p)); - - start_pfn = p->address >> PAGE_SHIFT; - nr_pages = ((unsigned long)p->len + PAGE_SIZE - 1) >> PAGE_SHIFT; - - pgdata = NODE_DATA(spu->node); - zone = pgdata->node_zones; - - /* XXX rethink locking here */ - mutex_lock(&add_spumem_mutex); - ret = __add_pages(zone, start_pfn, nr_pages); - mutex_unlock(&add_spumem_mutex); - - return ret; -} - -static void __iomem * __init map_spe_prop(struct spu *spu, - struct device_node *n, const char *name) -{ - const struct address_prop { - unsigned long address; - unsigned int len; - } __attribute__((packed)) *prop; - - const void *p; - int proplen; - void __iomem *ret = NULL; - int err = 0; - - p = get_property(n, name, &proplen); - if (proplen != sizeof (struct address_prop)) - return NULL; - - prop = p; - - err = cell_spuprop_present(spu, n, name); - if (err && (err != -EEXIST)) - goto out; - - ret = ioremap(prop->address, prop->len); - - out: - return ret; -} - -static void spu_unmap(struct spu *spu) -{ - iounmap(spu->priv2); - iounmap(spu_get_pdata(spu)->priv1); - iounmap(spu->problem); - iounmap((__force u8 __iomem *)spu->local_store); -} - -static int __init spu_map_interrupts_old(struct spu *spu, - struct device_node *np) -{ - unsigned int isrc; - const u32 *tmp; - int nid; - - /* Get the interrupt source unit from the device-tree */ - tmp = get_property(np, "isrc", NULL); - if (!tmp) - return -ENODEV; - isrc = tmp[0]; - - tmp = get_property(np->parent->parent, "node-id", NULL); - if (!tmp) { - printk(KERN_WARNING "%s: can't find node-id\n", __FUNCTION__); - nid = spu->node; - } else - nid = tmp[0]; - - /* Add the node number */ - isrc |= nid << IIC_IRQ_NODE_SHIFT; - - /* Now map interrupts of all 3 classes */ - spu->irqs[0] = irq_create_mapping(NULL, IIC_IRQ_CLASS_0 | isrc); - spu->irqs[1] = irq_create_mapping(NULL, IIC_IRQ_CLASS_1 | isrc); - spu->irqs[2] = irq_create_mapping(NULL, IIC_IRQ_CLASS_2 | isrc); - - /* Right now, we only fail if class 2 failed */ - return spu->irqs[2] == NO_IRQ ? -EINVAL : 0; -} - -static int __init spu_map_device_old(struct spu *spu, struct device_node *node) -{ - const char *prop; - int ret; - - ret = -ENODEV; - spu->name = get_property(node, "name", NULL); - if (!spu->name) - goto out; - - prop = get_property(node, "local-store", NULL); - if (!prop) - goto out; - spu->local_store_phys = *(unsigned long *)prop; - - /* we use local store as ram, not io memory */ - spu->local_store = (void __force *) - map_spe_prop(spu, node, "local-store"); - if (!spu->local_store) - goto out; - - prop = get_property(node, "problem", NULL); - if (!prop) - goto out_unmap; - spu->problem_phys = *(unsigned long *)prop; - - spu->problem= map_spe_prop(spu, node, "problem"); - if (!spu->problem) - goto out_unmap; - - spu_get_pdata(spu)->priv1= map_spe_prop(spu, node, "priv1"); - - spu->priv2= map_spe_prop(spu, node, "priv2"); - if (!spu->priv2) - goto out_unmap; - ret = 0; - goto out; - -out_unmap: - spu_unmap(spu); -out: - return ret; -} - -static int __init spu_map_interrupts(struct spu *spu, struct device_node *np) -{ - struct of_irq oirq; - int ret; - int i; - - for (i=0; i < 3; i++) { - ret = of_irq_map_one(np, i, &oirq); - if (ret) { - pr_debug("spu_new: failed to get irq %d\n", i); - goto err; - } - ret = -EINVAL; - pr_debug(" irq %d no 0x%x on %s\n", i, oirq.specifier[0], - oirq.controller->full_name); - spu->irqs[i] = irq_create_of_mapping(oirq.controller, - oirq.specifier, oirq.size); - if (spu->irqs[i] == NO_IRQ) { - pr_debug("spu_new: failed to map it !\n"); - goto err; - } - } - return 0; - -err: - pr_debug("failed to map irq %x for spu %s\n", *oirq.specifier, - spu->name); - for (; i >= 0; i--) { - if (spu->irqs[i] != NO_IRQ) - irq_dispose_mapping(spu->irqs[i]); - } - return ret; -} - -static int spu_map_resource(struct spu *spu, int nr, - void __iomem** virt, unsigned long *phys) -{ - struct device_node *np = spu_get_pdata(spu)->devnode; - unsigned long start_pfn, nr_pages; - struct pglist_data *pgdata; - struct zone *zone; - struct resource resource = { }; - unsigned long len; - int ret; - - ret = of_address_to_resource(np, nr, &resource); - if (ret) - goto out; - - if (phys) - *phys = resource.start; - len = resource.end - resource.start + 1; - *virt = ioremap(resource.start, len); - if (!*virt) - ret = -EINVAL; - - start_pfn = resource.start >> PAGE_SHIFT; - nr_pages = (len + PAGE_SIZE - 1) >> PAGE_SHIFT; - - pgdata = NODE_DATA(spu->node); - zone = pgdata->node_zones; - - /* XXX rethink locking here */ - mutex_lock(&add_spumem_mutex); - ret = __add_pages(zone, start_pfn, nr_pages); - mutex_unlock(&add_spumem_mutex); - -out: - return ret; -} - -static int __init spu_map_device(struct spu *spu) -{ - struct device_node *np = spu_get_pdata(spu)->devnode; - int ret = -ENODEV; - - spu->name = get_property(np, "name", NULL); - if (!spu->name) - goto out; - - ret = spu_map_resource(spu, 0, (void __iomem**)&spu->local_store, - &spu->local_store_phys); - if (ret) { - pr_debug("spu_new: failed to map %s resource 0\n", - np->full_name); - goto out; - } - ret = spu_map_resource(spu, 1, (void __iomem**)&spu->problem, - &spu->problem_phys); - if (ret) { - pr_debug("spu_new: failed to map %s resource 1\n", - np->full_name); - goto out_unmap; - } - ret = spu_map_resource(spu, 2, (void __iomem**)&spu->priv2, NULL); - if (ret) { - pr_debug("spu_new: failed to map %s resource 2\n", - np->full_name); - goto out_unmap; - } - if (!firmware_has_feature(FW_FEATURE_LPAR)) - ret = spu_map_resource(spu, 3, - (void __iomem**)&spu_get_pdata(spu)->priv1, NULL); - if (ret) { - pr_debug("spu_new: failed to map %s resource 3\n", - np->full_name); - goto out_unmap; - } - pr_debug("spu_new: %s maps:\n", np->full_name); - pr_debug(" local store : 0x%016lx -> 0x%p\n", - spu->local_store_phys, spu->local_store); - pr_debug(" problem state : 0x%016lx -> 0x%p\n", - spu->problem_phys, spu->problem); - pr_debug(" priv2 : 0x%p\n", spu->priv2); - pr_debug(" priv1 : 0x%p\n", - spu_get_pdata(spu)->priv1); - - return 0; - -out_unmap: - spu_unmap(spu); -out: - pr_debug("failed to map spe %s: %d\n", spu->name, ret); - return ret; -} - -static int __init of_enumerate_spus(int (*fn)(void *data)) -{ - int ret; - struct device_node *node; - - ret = -ENODEV; - for (node = of_find_node_by_type(NULL, "spe"); - node; node = of_find_node_by_type(node, "spe")) { - ret = fn(node); - if (ret) { - printk(KERN_WARNING "%s: Error initializing %s\n", - __FUNCTION__, node->name); - break; - } - } - return ret; -} - -static int __init of_create_spu(struct spu *spu, void *data) -{ - int ret; - struct device_node *spe = (struct device_node *)data; - - spu->pdata = kzalloc(sizeof(struct spu_pdata), - GFP_KERNEL); - if (!spu->pdata) { - ret = -ENOMEM; - goto out; - } - spu_get_pdata(spu)->devnode = of_node_get(spe); - - spu->node = of_node_to_nid(spe); - if (spu->node >= MAX_NUMNODES) { - printk(KERN_WARNING "SPE %s on node %d ignored," - " node number too big\n", spe->full_name, spu->node); - printk(KERN_WARNING "Check if CONFIG_NUMA is enabled.\n"); - ret = -ENODEV; - goto out_free; - } - - ret = spu_map_device(spu); - /* try old method */ - if (ret) - ret = spu_map_device_old(spu, spe); - if (ret) - goto out_free; - - ret = spu_map_interrupts(spu, spe); - if (ret) - ret = spu_map_interrupts_old(spu, spe); - if (ret) - goto out_unmap; - - pr_debug(KERN_DEBUG "Using SPE %s %p %p %p %p %d\n", spu->name, - spu->local_store, spu->problem, spu_get_pdata(spu)->priv1, - spu->priv2, spu->number); - goto out; - -out_unmap: - spu_unmap(spu); -out_free: - kfree(spu->pdata); - spu->pdata = NULL; -out: - return ret; -} - -static int of_destroy_spu(struct spu *spu) -{ - spu_unmap(spu); - of_node_put(spu_get_pdata(spu)->devnode); - kfree(spu->pdata); - spu->pdata = NULL; - return 0; -} - -const struct spu_management_ops spu_management_of_ops = { - .enumerate_spus = of_enumerate_spus, - .create_spu = of_create_spu, - .destroy_spu = of_destroy_spu, -}; - static void int_mask_and(struct spu *spu, int class, u64 mask) { u64 old_mask; - old_mask = in_be64(&spu_get_pdata(spu)->priv1->int_mask_RW[class]); - out_be64(&spu_get_pdata(spu)->priv1->int_mask_RW[class], - old_mask & mask); + old_mask = in_be64(&spu->priv1->int_mask_RW[class]); + out_be64(&spu->priv1->int_mask_RW[class], old_mask & mask); } static void int_mask_or(struct spu *spu, int class, u64 mask) { u64 old_mask; - old_mask = in_be64(&spu_get_pdata(spu)->priv1->int_mask_RW[class]); - out_be64(&spu_get_pdata(spu)->priv1->int_mask_RW[class], - old_mask | mask); + old_mask = in_be64(&spu->priv1->int_mask_RW[class]); + out_be64(&spu->priv1->int_mask_RW[class], old_mask | mask); } static void int_mask_set(struct spu *spu, int class, u64 mask) { - out_be64(&spu_get_pdata(spu)->priv1->int_mask_RW[class], mask); + out_be64(&spu->priv1->int_mask_RW[class], mask); } static u64 int_mask_get(struct spu *spu, int class) { - return in_be64(&spu_get_pdata(spu)->priv1->int_mask_RW[class]); + return in_be64(&spu->priv1->int_mask_RW[class]); } static void int_stat_clear(struct spu *spu, int class, u64 stat) { - out_be64(&spu_get_pdata(spu)->priv1->int_stat_RW[class], stat); + out_be64(&spu->priv1->int_stat_RW[class], stat); } static u64 int_stat_get(struct spu *spu, int class) { - return in_be64(&spu_get_pdata(spu)->priv1->int_stat_RW[class]); + return in_be64(&spu->priv1->int_stat_RW[class]); } static void cpu_affinity_set(struct spu *spu, int cpu) { u64 target = iic_get_target_id(cpu); u64 route = target << 48 | target << 32 | target << 16; - out_be64(&spu_get_pdata(spu)->priv1->int_route_RW, route); + out_be64(&spu->priv1->int_route_RW, route); } static u64 mfc_dar_get(struct spu *spu) { - return in_be64(&spu_get_pdata(spu)->priv1->mfc_dar_RW); + return in_be64(&spu->priv1->mfc_dar_RW); } static u64 mfc_dsisr_get(struct spu *spu) { - return in_be64(&spu_get_pdata(spu)->priv1->mfc_dsisr_RW); + return in_be64(&spu->priv1->mfc_dsisr_RW); } static void mfc_dsisr_set(struct spu *spu, u64 dsisr) { - out_be64(&spu_get_pdata(spu)->priv1->mfc_dsisr_RW, dsisr); + out_be64(&spu->priv1->mfc_dsisr_RW, dsisr); } static void mfc_sdr_setup(struct spu *spu) { - out_be64(&spu_get_pdata(spu)->priv1->mfc_sdr_RW, mfspr(SPRN_SDR1)); + out_be64(&spu->priv1->mfc_sdr_RW, mfspr(SPRN_SDR1)); } static void mfc_sr1_set(struct spu *spu, u64 sr1) { - out_be64(&spu_get_pdata(spu)->priv1->mfc_sr1_RW, sr1); + out_be64(&spu->priv1->mfc_sr1_RW, sr1); } static u64 mfc_sr1_get(struct spu *spu) { - return in_be64(&spu_get_pdata(spu)->priv1->mfc_sr1_RW); + return in_be64(&spu->priv1->mfc_sr1_RW); } static void mfc_tclass_id_set(struct spu *spu, u64 tclass_id) { - out_be64(&spu_get_pdata(spu)->priv1->mfc_tclass_id_RW, tclass_id); + out_be64(&spu->priv1->mfc_tclass_id_RW, tclass_id); } static u64 mfc_tclass_id_get(struct spu *spu) { - return in_be64(&spu_get_pdata(spu)->priv1->mfc_tclass_id_RW); + return in_be64(&spu->priv1->mfc_tclass_id_RW); } static void tlb_invalidate(struct spu *spu) { - out_be64(&spu_get_pdata(spu)->priv1->tlb_invalidate_entry_W, 0ul); + out_be64(&spu->priv1->tlb_invalidate_entry_W, 0ul); } static void resource_allocation_groupID_set(struct spu *spu, u64 id) { - out_be64(&spu_get_pdata(spu)->priv1->resource_allocation_groupID_RW, - id); + out_be64(&spu->priv1->resource_allocation_groupID_RW, id); } static u64 resource_allocation_groupID_get(struct spu *spu) { - return in_be64( - &spu_get_pdata(spu)->priv1->resource_allocation_groupID_RW); + return in_be64(&spu->priv1->resource_allocation_groupID_RW); } static void resource_allocation_enable_set(struct spu *spu, u64 enable) { - out_be64(&spu_get_pdata(spu)->priv1->resource_allocation_enable_RW, - enable); + out_be64(&spu->priv1->resource_allocation_enable_RW, enable); } static u64 resource_allocation_enable_get(struct spu *spu) { - return in_be64( - &spu_get_pdata(spu)->priv1->resource_allocation_enable_RW); + return in_be64(&spu->priv1->resource_allocation_enable_RW); } const struct spu_priv1_ops spu_priv1_mmio_ops = diff --git a/arch/powerpc/platforms/cell/spufs/context.c b/arch/powerpc/platforms/cell/spufs/context.c index 0870009..04ad2e3 100644 --- a/arch/powerpc/platforms/cell/spufs/context.c +++ b/arch/powerpc/platforms/cell/spufs/context.c @@ -42,7 +42,7 @@ struct spu_context *alloc_spu_context(st } spin_lock_init(&ctx->mmio_lock); kref_init(&ctx->kref); - init_rwsem(&ctx->state_sema); + mutex_init(&ctx->state_mutex); init_MUTEX(&ctx->run_sema); init_waitqueue_head(&ctx->ibox_wq); init_waitqueue_head(&ctx->wbox_wq); @@ -53,6 +53,10 @@ struct spu_context *alloc_spu_context(st ctx->owner = get_task_mm(current); if (gang) spu_gang_add_ctx(gang, ctx); + ctx->rt_priority = current->rt_priority; + ctx->policy = current->policy; + ctx->prio = current->prio; + INIT_DELAYED_WORK(&ctx->sched_work, spu_sched_tick); goto out; out_free: kfree(ctx); @@ -65,9 +69,9 @@ void destroy_spu_context(struct kref *kr { struct spu_context *ctx; ctx = container_of(kref, struct spu_context, kref); - down_write(&ctx->state_sema); + mutex_lock(&ctx->state_mutex); spu_deactivate(ctx); - up_write(&ctx->state_sema); + mutex_unlock(&ctx->state_mutex); spu_fini_csa(&ctx->csa); if (ctx->gang) spu_gang_remove_ctx(ctx->gang, ctx); @@ -96,107 +100,102 @@ void spu_forget(struct spu_context *ctx) spu_release(ctx); } -void spu_acquire(struct spu_context *ctx) -{ - down_read(&ctx->state_sema); -} - -void spu_release(struct spu_context *ctx) -{ - up_read(&ctx->state_sema); -} - void spu_unmap_mappings(struct spu_context *ctx) { if (ctx->local_store) unmap_mapping_range(ctx->local_store, 0, LS_SIZE, 1); if (ctx->mfc) - unmap_mapping_range(ctx->mfc, 0, 0x4000, 1); + unmap_mapping_range(ctx->mfc, 0, 0x1000, 1); if (ctx->cntl) - unmap_mapping_range(ctx->cntl, 0, 0x4000, 1); + unmap_mapping_range(ctx->cntl, 0, 0x1000, 1); if (ctx->signal1) - unmap_mapping_range(ctx->signal1, 0, 0x4000, 1); + unmap_mapping_range(ctx->signal1, 0, PAGE_SIZE, 1); if (ctx->signal2) - unmap_mapping_range(ctx->signal2, 0, 0x4000, 1); + unmap_mapping_range(ctx->signal2, 0, PAGE_SIZE, 1); + if (ctx->mss) + unmap_mapping_range(ctx->mss, 0, 0x1000, 1); + if (ctx->psmap) + unmap_mapping_range(ctx->psmap, 0, 0x20000, 1); } +/** + * spu_acquire_exclusive - lock spu contex and protect against userspace access + * @ctx: spu contex to lock + * + * Note: + * Returns 0 and with the context locked on success + * Returns negative error and with the context _unlocked_ on failure. + */ int spu_acquire_exclusive(struct spu_context *ctx) { - int ret = 0; + int ret = -EINVAL; - down_write(&ctx->state_sema); - /* ctx is about to be freed, can't acquire any more */ - if (!ctx->owner) { - ret = -EINVAL; - goto out; - } + spu_acquire(ctx); + /* + * Context is about to be freed, so we can't acquire it anymore. + */ + if (!ctx->owner) + goto out_unlock; if (ctx->state == SPU_STATE_SAVED) { ret = spu_activate(ctx, 0); if (ret) - goto out; - ctx->state = SPU_STATE_RUNNABLE; + goto out_unlock; } else { - /* We need to exclude userspace access to the context. */ + /* + * We need to exclude userspace access to the context. + * + * To protect against memory access we invalidate all ptes + * and make sure the pagefault handlers block on the mutex. + */ spu_unmap_mappings(ctx); } -out: - if (ret) - up_write(&ctx->state_sema); + return 0; + + out_unlock: + spu_release(ctx); return ret; } -int spu_acquire_runnable(struct spu_context *ctx) +/** + * spu_acquire_runnable - lock spu contex and make sure it is in runnable state + * @ctx: spu contex to lock + * + * Note: + * Returns 0 and with the context locked on success + * Returns negative error and with the context _unlocked_ on failure. + */ +int spu_acquire_runnable(struct spu_context *ctx, unsigned long flags) { - int ret = 0; - - down_read(&ctx->state_sema); - if (ctx->state == SPU_STATE_RUNNABLE) { - ctx->spu->prio = current->prio; - return 0; - } - up_read(&ctx->state_sema); - - down_write(&ctx->state_sema); - /* ctx is about to be freed, can't acquire any more */ - if (!ctx->owner) { - ret = -EINVAL; - goto out; - } + int ret = -EINVAL; + spu_acquire(ctx); if (ctx->state == SPU_STATE_SAVED) { - ret = spu_activate(ctx, 0); + /* + * Context is about to be freed, so we can't acquire it anymore. + */ + if (!ctx->owner) + goto out_unlock; + ret = spu_activate(ctx, flags); if (ret) - goto out; - ctx->state = SPU_STATE_RUNNABLE; + goto out_unlock; } - downgrade_write(&ctx->state_sema); - /* On success, we return holding the lock */ - - return ret; -out: - /* Release here, to simplify calling code. */ - up_write(&ctx->state_sema); + return 0; + out_unlock: + spu_release(ctx); return ret; } +/** + * spu_acquire_saved - lock spu contex and make sure it is in saved state + * @ctx: spu contex to lock + */ void spu_acquire_saved(struct spu_context *ctx) { - down_read(&ctx->state_sema); - - if (ctx->state == SPU_STATE_SAVED) - return; - - up_read(&ctx->state_sema); - down_write(&ctx->state_sema); - - if (ctx->state == SPU_STATE_RUNNABLE) { + spu_acquire(ctx); + if (ctx->state != SPU_STATE_SAVED) spu_deactivate(ctx); - ctx->state = SPU_STATE_SAVED; - } - - downgrade_write(&ctx->state_sema); } diff --git a/arch/powerpc/platforms/cell/spufs/file.c b/arch/powerpc/platforms/cell/spufs/file.c index 347eff5..b00653d 100644 --- a/arch/powerpc/platforms/cell/spufs/file.c +++ b/arch/powerpc/platforms/cell/spufs/file.c @@ -45,8 +45,8 @@ spufs_mem_open(struct inode *inode, stru struct spufs_inode_info *i = SPUFS_I(inode); struct spu_context *ctx = i->i_ctx; file->private_data = ctx; - file->f_mapping = inode->i_mapping; ctx->local_store = inode->i_mapping; + smp_wmb(); return 0; } @@ -95,39 +95,38 @@ spufs_mem_write(struct file *file, const return ret; } -static struct page * -spufs_mem_mmap_nopage(struct vm_area_struct *vma, - unsigned long address, int *type) +static unsigned long spufs_mem_mmap_nopfn(struct vm_area_struct *vma, + unsigned long address) { - struct page *page = NOPAGE_SIGBUS; - struct spu_context *ctx = vma->vm_file->private_data; - unsigned long offset = address - vma->vm_start; + unsigned long pfn, offset = address - vma->vm_start; + offset += vma->vm_pgoff << PAGE_SHIFT; + if (offset >= LS_SIZE) + return NOPFN_SIGBUS; + spu_acquire(ctx); if (ctx->state == SPU_STATE_SAVED) { vma->vm_page_prot = __pgprot(pgprot_val(vma->vm_page_prot) & ~_PAGE_NO_CACHE); - page = vmalloc_to_page(ctx->csa.lscsa->ls + offset); + pfn = vmalloc_to_pfn(ctx->csa.lscsa->ls + offset); } else { vma->vm_page_prot = __pgprot(pgprot_val(vma->vm_page_prot) - | _PAGE_NO_CACHE); - page = pfn_to_page((ctx->spu->local_store_phys + offset) - >> PAGE_SHIFT); + | _PAGE_NO_CACHE); + pfn = (ctx->spu->local_store_phys + offset) >> PAGE_SHIFT; } - spu_release(ctx); + vm_insert_pfn(vma, address, pfn); - if (type) - *type = VM_FAULT_MINOR; + spu_release(ctx); - page_cache_get(page); - return page; + return NOPFN_REFAULT; } + static struct vm_operations_struct spufs_mem_mmap_vmops = { - .nopage = spufs_mem_mmap_nopage, + .nopfn = spufs_mem_mmap_nopfn, }; static int @@ -136,7 +135,7 @@ spufs_mem_mmap(struct file *file, struct if (!(vma->vm_flags & VM_SHARED)) return -EINVAL; - vma->vm_flags |= VM_IO; + vma->vm_flags |= VM_IO | VM_PFNMAP; vma->vm_page_prot = __pgprot(pgprot_val(vma->vm_page_prot) | _PAGE_NO_CACHE); @@ -144,7 +143,7 @@ spufs_mem_mmap(struct file *file, struct return 0; } -static struct file_operations spufs_mem_fops = { +static const struct file_operations spufs_mem_fops = { .open = spufs_mem_open, .read = spufs_mem_read, .write = spufs_mem_write, @@ -152,49 +151,42 @@ static struct file_operations spufs_mem_ .mmap = spufs_mem_mmap, }; -static struct page *spufs_ps_nopage(struct vm_area_struct *vma, +static unsigned long spufs_ps_nopfn(struct vm_area_struct *vma, unsigned long address, - int *type, unsigned long ps_offs, + unsigned long ps_offs, unsigned long ps_size) { - struct page *page = NOPAGE_SIGBUS; - int fault_type = VM_FAULT_SIGBUS; struct spu_context *ctx = vma->vm_file->private_data; - unsigned long offset = address - vma->vm_start; - unsigned long area; + unsigned long area, offset = address - vma->vm_start; int ret; offset += vma->vm_pgoff << PAGE_SHIFT; if (offset >= ps_size) - goto out; + return NOPFN_SIGBUS; - ret = spu_acquire_runnable(ctx); + /* error here usually means a signal.. we might want to test + * the error code more precisely though + */ + ret = spu_acquire_runnable(ctx, 0); if (ret) - goto out; + return NOPFN_REFAULT; area = ctx->spu->problem_phys + ps_offs; - page = pfn_to_page((area + offset) >> PAGE_SHIFT); - fault_type = VM_FAULT_MINOR; - page_cache_get(page); - + vm_insert_pfn(vma, address, (area + offset) >> PAGE_SHIFT); spu_release(ctx); - out: - if (type) - *type = fault_type; - - return page; + return NOPFN_REFAULT; } #if SPUFS_MMAP_4K -static struct page *spufs_cntl_mmap_nopage(struct vm_area_struct *vma, - unsigned long address, int *type) +static unsigned long spufs_cntl_mmap_nopfn(struct vm_area_struct *vma, + unsigned long address) { - return spufs_ps_nopage(vma, address, type, 0x4000, 0x1000); + return spufs_ps_nopfn(vma, address, 0x4000, 0x1000); } static struct vm_operations_struct spufs_cntl_mmap_vmops = { - .nopage = spufs_cntl_mmap_nopage, + .nopfn = spufs_cntl_mmap_nopfn, }; /* @@ -205,7 +197,7 @@ static int spufs_cntl_mmap(struct file * if (!(vma->vm_flags & VM_SHARED)) return -EINVAL; - vma->vm_flags |= VM_IO; + vma->vm_flags |= VM_IO | VM_PFNMAP; vma->vm_page_prot = __pgprot(pgprot_val(vma->vm_page_prot) | _PAGE_NO_CACHE | _PAGE_GUARDED); @@ -243,13 +235,13 @@ static int spufs_cntl_open(struct inode struct spu_context *ctx = i->i_ctx; file->private_data = ctx; - file->f_mapping = inode->i_mapping; ctx->cntl = inode->i_mapping; + smp_wmb(); return simple_attr_open(inode, file, spufs_cntl_get, spufs_cntl_set, "0x%08lx"); } -static struct file_operations spufs_cntl_fops = { +static const struct file_operations spufs_cntl_fops = { .open = spufs_cntl_open, .release = simple_attr_close, .read = simple_attr_read, @@ -309,7 +301,7 @@ spufs_regs_write(struct file *file, cons return ret; } -static struct file_operations spufs_regs_fops = { +static const struct file_operations spufs_regs_fops = { .open = spufs_regs_open, .read = spufs_regs_read, .write = spufs_regs_write, @@ -360,7 +352,7 @@ spufs_fpcr_write(struct file *file, cons return ret; } -static struct file_operations spufs_fpcr_fops = { +static const struct file_operations spufs_fpcr_fops = { .open = spufs_regs_open, .read = spufs_fpcr_read, .write = spufs_fpcr_write, @@ -426,7 +418,7 @@ static ssize_t spufs_mbox_read(struct fi return count; } -static struct file_operations spufs_mbox_fops = { +static const struct file_operations spufs_mbox_fops = { .open = spufs_pipe_open, .read = spufs_mbox_read, }; @@ -452,7 +444,7 @@ static ssize_t spufs_mbox_stat_read(stru return 4; } -static struct file_operations spufs_mbox_stat_fops = { +static const struct file_operations spufs_mbox_stat_fops = { .open = spufs_pipe_open, .read = spufs_mbox_stat_read, }; @@ -559,7 +551,7 @@ static unsigned int spufs_ibox_poll(stru return mask; } -static struct file_operations spufs_ibox_fops = { +static const struct file_operations spufs_ibox_fops = { .open = spufs_pipe_open, .read = spufs_ibox_read, .poll = spufs_ibox_poll, @@ -585,7 +577,7 @@ static ssize_t spufs_ibox_stat_read(stru return 4; } -static struct file_operations spufs_ibox_stat_fops = { +static const struct file_operations spufs_ibox_stat_fops = { .open = spufs_pipe_open, .read = spufs_ibox_stat_read, }; @@ -692,7 +684,7 @@ static unsigned int spufs_wbox_poll(stru return mask; } -static struct file_operations spufs_wbox_fops = { +static const struct file_operations spufs_wbox_fops = { .open = spufs_pipe_open, .write = spufs_wbox_write, .poll = spufs_wbox_poll, @@ -718,7 +710,7 @@ static ssize_t spufs_wbox_stat_read(stru return 4; } -static struct file_operations spufs_wbox_stat_fops = { +static const struct file_operations spufs_wbox_stat_fops = { .open = spufs_pipe_open, .read = spufs_wbox_stat_read, }; @@ -728,8 +720,8 @@ static int spufs_signal1_open(struct ino struct spufs_inode_info *i = SPUFS_I(inode); struct spu_context *ctx = i->i_ctx; file->private_data = ctx; - file->f_mapping = inode->i_mapping; ctx->signal1 = inode->i_mapping; + smp_wmb(); return nonseekable_open(inode, file); } @@ -791,23 +783,23 @@ static ssize_t spufs_signal1_write(struc return 4; } -static struct page *spufs_signal1_mmap_nopage(struct vm_area_struct *vma, - unsigned long address, int *type) +static unsigned long spufs_signal1_mmap_nopfn(struct vm_area_struct *vma, + unsigned long address) { #if PAGE_SIZE == 0x1000 - return spufs_ps_nopage(vma, address, type, 0x14000, 0x1000); + return spufs_ps_nopfn(vma, address, 0x14000, 0x1000); #elif PAGE_SIZE == 0x10000 /* For 64k pages, both signal1 and signal2 can be used to mmap the whole * signal 1 and 2 area */ - return spufs_ps_nopage(vma, address, type, 0x10000, 0x10000); + return spufs_ps_nopfn(vma, address, 0x10000, 0x10000); #else #error unsupported page size #endif } static struct vm_operations_struct spufs_signal1_mmap_vmops = { - .nopage = spufs_signal1_mmap_nopage, + .nopfn = spufs_signal1_mmap_nopfn, }; static int spufs_signal1_mmap(struct file *file, struct vm_area_struct *vma) @@ -815,7 +807,7 @@ static int spufs_signal1_mmap(struct fil if (!(vma->vm_flags & VM_SHARED)) return -EINVAL; - vma->vm_flags |= VM_IO; + vma->vm_flags |= VM_IO | VM_PFNMAP; vma->vm_page_prot = __pgprot(pgprot_val(vma->vm_page_prot) | _PAGE_NO_CACHE | _PAGE_GUARDED); @@ -823,7 +815,7 @@ static int spufs_signal1_mmap(struct fil return 0; } -static struct file_operations spufs_signal1_fops = { +static const struct file_operations spufs_signal1_fops = { .open = spufs_signal1_open, .read = spufs_signal1_read, .write = spufs_signal1_write, @@ -835,8 +827,8 @@ static int spufs_signal2_open(struct ino struct spufs_inode_info *i = SPUFS_I(inode); struct spu_context *ctx = i->i_ctx; file->private_data = ctx; - file->f_mapping = inode->i_mapping; ctx->signal2 = inode->i_mapping; + smp_wmb(); return nonseekable_open(inode, file); } @@ -899,23 +891,23 @@ static ssize_t spufs_signal2_write(struc } #if SPUFS_MMAP_4K -static struct page *spufs_signal2_mmap_nopage(struct vm_area_struct *vma, - unsigned long address, int *type) +static unsigned long spufs_signal2_mmap_nopfn(struct vm_area_struct *vma, + unsigned long address) { #if PAGE_SIZE == 0x1000 - return spufs_ps_nopage(vma, address, type, 0x1c000, 0x1000); + return spufs_ps_nopfn(vma, address, 0x1c000, 0x1000); #elif PAGE_SIZE == 0x10000 /* For 64k pages, both signal1 and signal2 can be used to mmap the whole * signal 1 and 2 area */ - return spufs_ps_nopage(vma, address, type, 0x10000, 0x10000); + return spufs_ps_nopfn(vma, address, 0x10000, 0x10000); #else #error unsupported page size #endif } static struct vm_operations_struct spufs_signal2_mmap_vmops = { - .nopage = spufs_signal2_mmap_nopage, + .nopfn = spufs_signal2_mmap_nopfn, }; static int spufs_signal2_mmap(struct file *file, struct vm_area_struct *vma) @@ -923,7 +915,7 @@ static int spufs_signal2_mmap(struct fil if (!(vma->vm_flags & VM_SHARED)) return -EINVAL; - vma->vm_flags |= VM_IO; + vma->vm_flags |= VM_IO | VM_PFNMAP; vma->vm_page_prot = __pgprot(pgprot_val(vma->vm_page_prot) | _PAGE_NO_CACHE | _PAGE_GUARDED); @@ -934,7 +926,7 @@ #else /* SPUFS_MMAP_4K */ #define spufs_signal2_mmap NULL #endif /* !SPUFS_MMAP_4K */ -static struct file_operations spufs_signal2_fops = { +static const struct file_operations spufs_signal2_fops = { .open = spufs_signal2_open, .read = spufs_signal2_read, .write = spufs_signal2_write, @@ -1000,14 +992,14 @@ DEFINE_SIMPLE_ATTRIBUTE(spufs_signal2_ty spufs_signal2_type_set, "%llu"); #if SPUFS_MMAP_4K -static struct page *spufs_mss_mmap_nopage(struct vm_area_struct *vma, - unsigned long address, int *type) +static unsigned long spufs_mss_mmap_nopfn(struct vm_area_struct *vma, + unsigned long address) { - return spufs_ps_nopage(vma, address, type, 0x0000, 0x1000); + return spufs_ps_nopfn(vma, address, 0x0000, 0x1000); } static struct vm_operations_struct spufs_mss_mmap_vmops = { - .nopage = spufs_mss_mmap_nopage, + .nopfn = spufs_mss_mmap_nopfn, }; /* @@ -1018,7 +1010,7 @@ static int spufs_mss_mmap(struct file *f if (!(vma->vm_flags & VM_SHARED)) return -EINVAL; - vma->vm_flags |= VM_IO; + vma->vm_flags |= VM_IO | VM_PFNMAP; vma->vm_page_prot = __pgprot(pgprot_val(vma->vm_page_prot) | _PAGE_NO_CACHE | _PAGE_GUARDED); @@ -1032,24 +1024,27 @@ #endif /* !SPUFS_MMAP_4K */ static int spufs_mss_open(struct inode *inode, struct file *file) { struct spufs_inode_info *i = SPUFS_I(inode); + struct spu_context *ctx = i->i_ctx; file->private_data = i->i_ctx; + ctx->mss = inode->i_mapping; + smp_wmb(); return nonseekable_open(inode, file); } -static struct file_operations spufs_mss_fops = { +static const struct file_operations spufs_mss_fops = { .open = spufs_mss_open, .mmap = spufs_mss_mmap, }; -static struct page *spufs_psmap_mmap_nopage(struct vm_area_struct *vma, - unsigned long address, int *type) +static unsigned long spufs_psmap_mmap_nopfn(struct vm_area_struct *vma, + unsigned long address) { - return spufs_ps_nopage(vma, address, type, 0x0000, 0x20000); + return spufs_ps_nopfn(vma, address, 0x0000, 0x20000); } static struct vm_operations_struct spufs_psmap_mmap_vmops = { - .nopage = spufs_psmap_mmap_nopage, + .nopfn = spufs_psmap_mmap_nopfn, }; /* @@ -1060,7 +1055,7 @@ static int spufs_psmap_mmap(struct file if (!(vma->vm_flags & VM_SHARED)) return -EINVAL; - vma->vm_flags |= VM_IO; + vma->vm_flags |= VM_IO | VM_PFNMAP; vma->vm_page_prot = __pgprot(pgprot_val(vma->vm_page_prot) | _PAGE_NO_CACHE | _PAGE_GUARDED); @@ -1071,26 +1066,29 @@ static int spufs_psmap_mmap(struct file static int spufs_psmap_open(struct inode *inode, struct file *file) { struct spufs_inode_info *i = SPUFS_I(inode); + struct spu_context *ctx = i->i_ctx; file->private_data = i->i_ctx; + ctx->psmap = inode->i_mapping; + smp_wmb(); return nonseekable_open(inode, file); } -static struct file_operations spufs_psmap_fops = { +static const struct file_operations spufs_psmap_fops = { .open = spufs_psmap_open, .mmap = spufs_psmap_mmap, }; #if SPUFS_MMAP_4K -static struct page *spufs_mfc_mmap_nopage(struct vm_area_struct *vma, - unsigned long address, int *type) +static unsigned long spufs_mfc_mmap_nopfn(struct vm_area_struct *vma, + unsigned long address) { - return spufs_ps_nopage(vma, address, type, 0x3000, 0x1000); + return spufs_ps_nopfn(vma, address, 0x3000, 0x1000); } static struct vm_operations_struct spufs_mfc_mmap_vmops = { - .nopage = spufs_mfc_mmap_nopage, + .nopfn = spufs_mfc_mmap_nopfn, }; /* @@ -1101,7 +1099,7 @@ static int spufs_mfc_mmap(struct file *f if (!(vma->vm_flags & VM_SHARED)) return -EINVAL; - vma->vm_flags |= VM_IO; + vma->vm_flags |= VM_IO | VM_PFNMAP; vma->vm_page_prot = __pgprot(pgprot_val(vma->vm_page_prot) | _PAGE_NO_CACHE | _PAGE_GUARDED); @@ -1125,6 +1123,8 @@ static int spufs_mfc_open(struct inode * return -EBUSY; file->private_data = ctx; + ctx->mfc = inode->i_mapping; + smp_wmb(); return nonseekable_open(inode, file); } @@ -1309,7 +1309,7 @@ static ssize_t spufs_mfc_write(struct fi if (ret) goto out; - spu_acquire_runnable(ctx); + spu_acquire_runnable(ctx, 0); if (file->f_flags & O_NONBLOCK) { ret = ctx->ops->send_mfc_command(ctx, &cmd); } else { @@ -1393,7 +1393,7 @@ static int spufs_mfc_fasync(int fd, stru return fasync_helper(fd, file, on, &ctx->mfc_fasync); } -static struct file_operations spufs_mfc_fops = { +static const struct file_operations spufs_mfc_fops = { .open = spufs_mfc_open, .read = spufs_mfc_read, .write = spufs_mfc_write, @@ -1650,7 +1650,7 @@ static ssize_t spufs_mbox_info_read(stru return ret; } -static struct file_operations spufs_mbox_info_fops = { +static const struct file_operations spufs_mbox_info_fops = { .open = spufs_info_open, .read = spufs_mbox_info_read, .llseek = generic_file_llseek, @@ -1688,7 +1688,7 @@ static ssize_t spufs_ibox_info_read(stru return ret; } -static struct file_operations spufs_ibox_info_fops = { +static const struct file_operations spufs_ibox_info_fops = { .open = spufs_info_open, .read = spufs_ibox_info_read, .llseek = generic_file_llseek, @@ -1729,7 +1729,7 @@ static ssize_t spufs_wbox_info_read(stru return ret; } -static struct file_operations spufs_wbox_info_fops = { +static const struct file_operations spufs_wbox_info_fops = { .open = spufs_info_open, .read = spufs_wbox_info_read, .llseek = generic_file_llseek, @@ -1779,7 +1779,7 @@ static ssize_t spufs_dma_info_read(struc return ret; } -static struct file_operations spufs_dma_info_fops = { +static const struct file_operations spufs_dma_info_fops = { .open = spufs_info_open, .read = spufs_dma_info_read, }; @@ -1830,7 +1830,7 @@ static ssize_t spufs_proxydma_info_read( return ret; } -static struct file_operations spufs_proxydma_info_fops = { +static const struct file_operations spufs_proxydma_info_fops = { .open = spufs_info_open, .read = spufs_proxydma_info_read, }; diff --git a/arch/powerpc/platforms/cell/spufs/inode.c b/arch/powerpc/platforms/cell/spufs/inode.c index 738b924..8079983 100644 --- a/arch/powerpc/platforms/cell/spufs/inode.c +++ b/arch/powerpc/platforms/cell/spufs/inode.c @@ -220,11 +220,11 @@ static int spufs_dir_close(struct inode return dcache_dir_close(inode, file); } -struct inode_operations spufs_dir_inode_operations = { +const struct inode_operations spufs_dir_inode_operations = { .lookup = simple_lookup, }; -struct file_operations spufs_context_fops = { +const struct file_operations spufs_context_fops = { .open = dcache_dir_open, .release = spufs_dir_close, .llseek = dcache_dir_lseek, @@ -372,7 +372,7 @@ static int spufs_gang_close(struct inode return dcache_dir_close(inode, file); } -struct file_operations spufs_gang_fops = { +const struct file_operations spufs_gang_fops = { .open = dcache_dir_open, .release = spufs_gang_close, .llseek = dcache_dir_lseek, diff --git a/arch/powerpc/platforms/cell/spufs/run.c b/arch/powerpc/platforms/cell/spufs/run.c index 1acc2ff..353a8fa 100644 --- a/arch/powerpc/platforms/cell/spufs/run.c +++ b/arch/powerpc/platforms/cell/spufs/run.c @@ -133,7 +133,7 @@ out_drop_priv: spu_mfc_sr1_set(ctx->spu, sr1); out_unlock: - spu_release_exclusive(ctx); + spu_release(ctx); out: return ret; } @@ -143,7 +143,7 @@ static inline int spu_run_init(struct sp int ret; unsigned long runcntl = SPU_RUNCNTL_RUNNABLE; - ret = spu_acquire_runnable(ctx); + ret = spu_acquire_runnable(ctx, SPU_ACTIVATE_NOWAKE); if (ret) return ret; @@ -155,7 +155,7 @@ static inline int spu_run_init(struct sp spu_release(ctx); ret = spu_setup_isolated(ctx); if (!ret) - ret = spu_acquire_runnable(ctx); + ret = spu_acquire_runnable(ctx, SPU_ACTIVATE_NOWAKE); } /* if userspace has set the runcntrl register (eg, to issue an @@ -164,8 +164,10 @@ static inline int spu_run_init(struct sp (SPU_RUNCNTL_RUNNABLE | SPU_RUNCNTL_ISOLATE); if (runcntl == 0) runcntl = SPU_RUNCNTL_RUNNABLE; - } else + } else { + spu_start_tick(ctx); ctx->ops->npc_write(ctx, *npc); + } ctx->ops->runcntl_write(ctx, runcntl); return ret; @@ -176,6 +178,7 @@ static inline int spu_run_fini(struct sp { int ret = 0; + spu_stop_tick(ctx); *status = ctx->ops->status_read(ctx); *npc = ctx->ops->npc_read(ctx); spu_release(ctx); @@ -329,8 +332,10 @@ long spufs_run_spu(struct file *file, st } if (unlikely(ctx->state != SPU_STATE_RUNNABLE)) { ret = spu_reacquire_runnable(ctx, npc, &status); - if (ret) + if (ret) { + spu_stop_tick(ctx); goto out2; + } continue; } ret = spu_process_events(ctx); @@ -361,4 +366,3 @@ out: up(&ctx->run_sema); return ret; } - diff --git a/arch/powerpc/platforms/cell/spufs/sched.c b/arch/powerpc/platforms/cell/spufs/sched.c index bd6fe4b..2f25e68 100644 --- a/arch/powerpc/platforms/cell/spufs/sched.c +++ b/arch/powerpc/platforms/cell/spufs/sched.c @@ -44,17 +44,18 @@ #include #include #include "spufs.h" -#define SPU_MIN_TIMESLICE (100 * HZ / 1000) +#define SPU_TIMESLICE (HZ) -#define SPU_BITMAP_SIZE (((MAX_PRIO+BITS_PER_LONG)/BITS_PER_LONG)+1) struct spu_prio_array { - unsigned long bitmap[SPU_BITMAP_SIZE]; - wait_queue_head_t waitq[MAX_PRIO]; + DECLARE_BITMAP(bitmap, MAX_PRIO); + struct list_head runq[MAX_PRIO]; + spinlock_t runq_lock; struct list_head active_list[MAX_NUMNODES]; struct mutex active_mutex[MAX_NUMNODES]; }; static struct spu_prio_array *spu_prio; +static struct workqueue_struct *spu_sched_wq; static inline int node_allowed(int node) { @@ -68,6 +69,64 @@ static inline int node_allowed(int node) return 1; } +void spu_start_tick(struct spu_context *ctx) +{ + if (ctx->policy == SCHED_RR) + queue_delayed_work(spu_sched_wq, &ctx->sched_work, SPU_TIMESLICE); +} + +void spu_stop_tick(struct spu_context *ctx) +{ + if (ctx->policy == SCHED_RR) + cancel_delayed_work(&ctx->sched_work); +} + +void spu_sched_tick(struct work_struct *work) +{ + struct spu_context *ctx = + container_of(work, struct spu_context, sched_work.work); + struct spu *spu; + int rearm = 1; + + mutex_lock(&ctx->state_mutex); + spu = ctx->spu; + if (spu) { + int best = sched_find_first_bit(spu_prio->bitmap); + if (best <= ctx->prio) { + spu_deactivate(ctx); + rearm = 0; + } + } + mutex_unlock(&ctx->state_mutex); + + if (rearm) + spu_start_tick(ctx); +} + +/** + * spu_add_to_active_list - add spu to active list + * @spu: spu to add to the active list + */ +static void spu_add_to_active_list(struct spu *spu) +{ + mutex_lock(&spu_prio->active_mutex[spu->node]); + list_add_tail(&spu->list, &spu_prio->active_list[spu->node]); + mutex_unlock(&spu_prio->active_mutex[spu->node]); +} + +/** + * spu_remove_from_active_list - remove spu from active list + * @spu: spu to remove from the active list + */ +static void spu_remove_from_active_list(struct spu *spu) +{ + int node = spu->node; + + mutex_lock(&spu_prio->active_mutex[node]); + list_del_init(&spu->list); + mutex_unlock(&spu_prio->active_mutex[node]); +} + static inline void mm_needs_global_tlbie(struct mm_struct *mm) { int nr = (NR_CPUS > 1) ? NR_CPUS : NR_CPUS + 1; @@ -94,8 +153,12 @@ int spu_switch_event_unregister(struct n return blocking_notifier_chain_unregister(&spu_switch_notifier, n); } - -static inline void bind_context(struct spu *spu, struct spu_context *ctx) +/** + * spu_bind_context - bind spu context to physical spu + * @spu: physical spu to bind to + * @ctx: context to bind + */ +static void spu_bind_context(struct spu *spu, struct spu_context *ctx) { pr_debug("%s: pid=%d SPU=%d NODE=%d\n", __FUNCTION__, current->pid, spu->number, spu->node); @@ -104,7 +167,6 @@ static inline void bind_context(struct s ctx->spu = spu; ctx->ops = &spu_hw_ops; spu->pid = current->pid; - spu->prio = current->prio; spu->mm = ctx->owner; mm_needs_global_tlbie(spu->mm); spu->ibox_callback = spufs_ibox_callback; @@ -118,12 +180,21 @@ static inline void bind_context(struct s spu->timestamp = jiffies; spu_cpu_affinity_set(spu, raw_smp_processor_id()); spu_switch_notify(spu, ctx); + spu_add_to_active_list(spu); + ctx->state = SPU_STATE_RUNNABLE; } -static inline void unbind_context(struct spu *spu, struct spu_context *ctx) +/** + * spu_unbind_context - unbind spu context from physical spu + * @spu: physical spu to unbind from + * @ctx: context to unbind + */ +static void spu_unbind_context(struct spu *spu, struct spu_context *ctx) { pr_debug("%s: unbind pid=%d SPU=%d NODE=%d\n", __FUNCTION__, spu->pid, spu->number, spu->node); + + spu_remove_from_active_list(spu); spu_switch_notify(spu, NULL); spu_unmap_mappings(ctx); spu_save(&ctx->csa, spu); @@ -136,95 +207,98 @@ static inline void unbind_context(struct spu->dma_callback = NULL; spu->mm = NULL; spu->pid = 0; - spu->prio = MAX_PRIO; ctx->ops = &spu_backing_ops; ctx->spu = NULL; spu->flags = 0; spu->ctx = NULL; } -static inline void spu_add_wq(wait_queue_head_t * wq, wait_queue_t * wait, - int prio) +/** + * spu_add_to_rq - add a context to the runqueue + * @ctx: context to add + */ +static void spu_add_to_rq(struct spu_context *ctx) { - prepare_to_wait_exclusive(wq, wait, TASK_INTERRUPTIBLE); - set_bit(prio, spu_prio->bitmap); + spin_lock(&spu_prio->runq_lock); + list_add_tail(&ctx->rq, &spu_prio->runq[ctx->prio]); + set_bit(ctx->prio, spu_prio->bitmap); + spin_unlock(&spu_prio->runq_lock); } -static inline void spu_del_wq(wait_queue_head_t * wq, wait_queue_t * wait, - int prio) +/** + * spu_del_from_rq - remove a context from the runqueue + * @ctx: context to remove + */ +static void spu_del_from_rq(struct spu_context *ctx) { - u64 flags; - - __set_current_state(TASK_RUNNING); - - spin_lock_irqsave(&wq->lock, flags); + spin_lock(&spu_prio->runq_lock); + list_del_init(&ctx->rq); + if (list_empty(&spu_prio->runq[ctx->prio])) + clear_bit(ctx->prio, spu_prio->bitmap); + spin_unlock(&spu_prio->runq_lock); +} - remove_wait_queue_locked(wq, wait); - if (list_empty(&wq->task_list)) - clear_bit(prio, spu_prio->bitmap); +/** + * spu_grab_context - remove one context from the runqueue + * @prio: priority of the context to be removed + * + * This function removes one context from the runqueue for priority @prio. + * If there is more than one context with the given priority the first + * task on the runqueue will be taken. + * + * Returns the spu_context it just removed. + * + * Must be called with spu_prio->runq_lock held. + */ +static struct spu_context *spu_grab_context(int prio) +{ + struct list_head *rq = &spu_prio->runq[prio]; - spin_unlock_irqrestore(&wq->lock, flags); + if (list_empty(rq)) + return NULL; + return list_entry(rq->next, struct spu_context, rq); } -static void spu_prio_wait(struct spu_context *ctx, u64 flags) +static void spu_prio_wait(struct spu_context *ctx) { - int prio = current->prio; - wait_queue_head_t *wq = &spu_prio->waitq[prio]; DEFINE_WAIT(wait); - if (ctx->spu) - return; - - spu_add_wq(wq, &wait, prio); - + set_bit(SPU_SCHED_WAKE, &ctx->sched_flags); + prepare_to_wait_exclusive(&ctx->stop_wq, &wait, TASK_INTERRUPTIBLE); if (!signal_pending(current)) { - up_write(&ctx->state_sema); - pr_debug("%s: pid=%d prio=%d\n", __FUNCTION__, - current->pid, current->prio); + mutex_unlock(&ctx->state_mutex); schedule(); - down_write(&ctx->state_sema); + mutex_lock(&ctx->state_mutex); } - - spu_del_wq(wq, &wait, prio); + __set_current_state(TASK_RUNNING); + remove_wait_queue(&ctx->stop_wq, &wait); + clear_bit(SPU_SCHED_WAKE, &ctx->sched_flags); } -static void spu_prio_wakeup(void) +/** + * spu_reschedule - try to find a runnable context for a spu + * @spu: spu available + * + * This function is called whenever a spu becomes idle. It looks for the + * most suitable runnable spu context and schedules it for execution. + */ +static void spu_reschedule(struct spu *spu) { - int best = sched_find_first_bit(spu_prio->bitmap); - if (best < MAX_PRIO) { - wait_queue_head_t *wq = &spu_prio->waitq[best]; - wake_up_interruptible_nr(wq, 1); - } -} + int best; -static int get_active_spu(struct spu *spu) -{ - int node = spu->node; - struct spu *tmp; - int rc = 0; + spu_free(spu); - mutex_lock(&spu_prio->active_mutex[node]); - list_for_each_entry(tmp, &spu_prio->active_list[node], list) { - if (tmp == spu) { - list_del_init(&spu->list); - rc = 1; - break; - } + spin_lock(&spu_prio->runq_lock); + best = sched_find_first_bit(spu_prio->bitmap); + if (best < MAX_PRIO) { + struct spu_context *ctx = spu_grab_context(best); + if (ctx && test_bit(SPU_SCHED_WAKE, &ctx->sched_flags)) + wake_up(&ctx->stop_wq); } - mutex_unlock(&spu_prio->active_mutex[node]); - return rc; -} - -static void put_active_spu(struct spu *spu) -{ - int node = spu->node; - - mutex_lock(&spu_prio->active_mutex[node]); - list_add_tail(&spu->list, &spu_prio->active_list[node]); - mutex_unlock(&spu_prio->active_mutex[node]); + spin_unlock(&spu_prio->runq_lock); } -static struct spu *spu_get_idle(struct spu_context *ctx, u64 flags) +static struct spu *spu_get_idle(struct spu_context *ctx) { struct spu *spu = NULL; int node = cpu_to_node(raw_smp_processor_id()); @@ -241,87 +315,154 @@ static struct spu *spu_get_idle(struct s return spu; } -static inline struct spu *spu_get(struct spu_context *ctx, u64 flags) +/** + * find_victim - find a lower priority context to preempt + * @ctx: canidate context for running + * + * Returns the freed physical spu to run the new context on. + */ +static struct spu *find_victim(struct spu_context *ctx) { - /* Future: spu_get_idle() if possible, - * otherwise try to preempt an active - * context. + struct spu_context *victim = NULL; + struct spu *spu; + int node, n; + + /* + * Look for a possible preemption candidate on the local node first. + * If there is no candidate look at the other nodes. This isn't + * exactly fair, but so far the whole spu schedule tries to keep + * a strong node affinity. We might want to fine-tune this in + * the future. */ - return spu_get_idle(ctx, flags); + restart: + node = cpu_to_node(raw_smp_processor_id()); + for (n = 0; n < MAX_NUMNODES; n++, node++) { + node = (node < MAX_NUMNODES) ? node : 0; + if (!node_allowed(node)) + continue; + + mutex_lock(&spu_prio->active_mutex[node]); + list_for_each_entry(spu, &spu_prio->active_list[node], list) { + struct spu_context *tmp = spu->ctx; + + if (tmp->rt_priority < ctx->rt_priority && + (!victim || tmp->rt_priority < victim->rt_priority)) + victim = spu->ctx; + } + mutex_unlock(&spu_prio->active_mutex[node]); + + if (victim) { + /* + * This nests ctx->state_mutex, but we always lock + * higher priority contexts before lower priority + * ones, so this is safe until we introduce + * priority inheritance schemes. + */ + if (!mutex_trylock(&victim->state_mutex)) { + victim = NULL; + goto restart; + } + + spu = victim->spu; + if (!spu) { + /* + * This race can happen because we've dropped + * the active list mutex. No a problem, just + * restart the search. + */ + mutex_unlock(&victim->state_mutex); + victim = NULL; + goto restart; + } + spu_unbind_context(spu, victim); + mutex_unlock(&victim->state_mutex); + return spu; + } + } + + return NULL; } -/* The three externally callable interfaces - * for the scheduler begin here. +/** + * spu_activate - find a free spu for a context and execute it + * @ctx: spu context to schedule + * @flags: flags (currently ignored) * - * spu_activate - bind a context to SPU, waiting as needed. - * spu_deactivate - unbind a context from its SPU. - * spu_yield - yield an SPU if others are waiting. + * Tries to find a free spu to run @ctx. If no free spu is availble + * add the context to the runqueue so it gets woken up once an spu + * is available. */ - -int spu_activate(struct spu_context *ctx, u64 flags) +int spu_activate(struct spu_context *ctx, unsigned long flags) { - struct spu *spu; - int ret = 0; - for (;;) { - if (ctx->spu) + if (ctx->spu) + return 0; + + do { + struct spu *spu; + + spu = spu_get_idle(ctx); + /* + * If this is a realtime thread we try to get it running by + * preempting a lower priority thread. + */ + if (!spu && ctx->rt_priority) + spu = find_victim(ctx); + if (spu) { + spu_bind_context(spu, ctx); return 0; - spu = spu_get(ctx, flags); - if (spu != NULL) { - if (ctx->spu != NULL) { - spu_free(spu); - spu_prio_wakeup(); - break; - } - bind_context(spu, ctx); - put_active_spu(spu); - break; } - spu_prio_wait(ctx, flags); - if (signal_pending(current)) { - ret = -ERESTARTSYS; - spu_prio_wakeup(); - break; - } - } - return ret; + + spu_add_to_rq(ctx); + if (!(flags & SPU_ACTIVATE_NOWAKE)) + spu_prio_wait(ctx); + spu_del_from_rq(ctx); + } while (!signal_pending(current)); + + return -ERESTARTSYS; } +/** + * spu_deactivate - unbind a context from it's physical spu + * @ctx: spu context to unbind + * + * Unbind @ctx from the physical spu it is running on and schedule + * the highest priority context to run on the freed physical spu. + */ void spu_deactivate(struct spu_context *ctx) { - struct spu *spu; - int needs_idle; + struct spu *spu = ctx->spu; - spu = ctx->spu; - if (!spu) - return; - needs_idle = get_active_spu(spu); - unbind_context(spu, ctx); - if (needs_idle) { - spu_free(spu); - spu_prio_wakeup(); + if (spu) { + spu_unbind_context(spu, ctx); + spu_reschedule(spu); } } +/** + * spu_yield - yield a physical spu if others are waiting + * @ctx: spu context to yield + * + * Check if there is a higher priority context waiting and if yes + * unbind @ctx from the physical spu and schedule the highest + * priority context to run on the freed physical spu instead. + */ void spu_yield(struct spu_context *ctx) { struct spu *spu; int need_yield = 0; - if (down_write_trylock(&ctx->state_sema)) { + if (mutex_trylock(&ctx->state_mutex)) { if ((spu = ctx->spu) != NULL) { int best = sched_find_first_bit(spu_prio->bitmap); if (best < MAX_PRIO) { pr_debug("%s: yielding SPU %d NODE %d\n", __FUNCTION__, spu->number, spu->node); spu_deactivate(ctx); - ctx->state = SPU_STATE_SAVED; need_yield = 1; - } else { - spu->prio = MAX_PRIO; } } - up_write(&ctx->state_sema); + mutex_unlock(&ctx->state_mutex); } if (unlikely(need_yield)) yield(); @@ -331,14 +472,19 @@ int __init spu_sched_init(void) { int i; + spu_sched_wq = create_singlethread_workqueue("spusched"); + if (!spu_sched_wq) + return 1; + spu_prio = kzalloc(sizeof(struct spu_prio_array), GFP_KERNEL); if (!spu_prio) { printk(KERN_WARNING "%s: Unable to allocate priority queue.\n", __FUNCTION__); + destroy_workqueue(spu_sched_wq); return 1; } for (i = 0; i < MAX_PRIO; i++) { - init_waitqueue_head(&spu_prio->waitq[i]); + INIT_LIST_HEAD(&spu_prio->runq[i]); __clear_bit(i, spu_prio->bitmap); } __set_bit(MAX_PRIO, spu_prio->bitmap); @@ -346,6 +492,7 @@ int __init spu_sched_init(void) mutex_init(&spu_prio->active_mutex[i]); INIT_LIST_HEAD(&spu_prio->active_list[i]); } + spin_lock_init(&spu_prio->runq_lock); return 0; } @@ -364,4 +511,5 @@ void __exit spu_sched_exit(void) mutex_unlock(&spu_prio->active_mutex[node]); } kfree(spu_prio); + destroy_workqueue(spu_sched_wq); } diff --git a/arch/powerpc/platforms/cell/spufs/spufs.h b/arch/powerpc/platforms/cell/spufs/spufs.h index 70fb133..0c43789 100644 --- a/arch/powerpc/platforms/cell/spufs/spufs.h +++ b/arch/powerpc/platforms/cell/spufs/spufs.h @@ -23,7 +23,7 @@ #ifndef SPUFS_H #define SPUFS_H #include -#include +#include #include #include @@ -37,11 +37,13 @@ enum { }; struct spu_context_ops; - -#define SPU_CONTEXT_PREEMPT 0UL - struct spu_gang; +/* ctx->sched_flags */ +enum { + SPU_SCHED_WAKE = 0, +}; + struct spu_context { struct spu *spu; /* pointer to a physical SPU */ struct spu_state csa; /* SPU context save area. */ @@ -51,10 +53,12 @@ struct spu_context { struct address_space *cntl; /* 'control' area mappings. */ struct address_space *signal1; /* 'signal1' area mappings. */ struct address_space *signal2; /* 'signal2' area mappings. */ + struct address_space *mss; /* 'mss' area mappings. */ + struct address_space *psmap; /* 'psmap' area mappings. */ u64 object_id; /* user space pointer for oprofile */ enum { SPU_STATE_RUNNABLE, SPU_STATE_SAVED } state; - struct rw_semaphore state_sema; + struct mutex state_mutex; struct semaphore run_sema; struct mm_struct *owner; @@ -75,6 +79,14 @@ struct spu_context { struct list_head gang_list; struct spu_gang *gang; + + /* scheduler fields */ + struct list_head rq; + struct delayed_work sched_work; + unsigned long sched_flags; + unsigned long rt_priority; + int policy; + int prio; }; struct spu_gang { @@ -149,7 +161,7 @@ long spufs_run_spu(struct file *file, struct spu_context *ctx, u32 *npc, u32 *status); long spufs_create(struct nameidata *nd, unsigned int flags, mode_t mode); -extern struct file_operations spufs_context_fops; +extern const struct file_operations spufs_context_fops; /* gang management */ struct spu_gang *alloc_spu_gang(void); @@ -159,6 +171,16 @@ void spu_gang_remove_ctx(struct spu_gang void spu_gang_add_ctx(struct spu_gang *gang, struct spu_context *ctx); /* context management */ +static inline void spu_acquire(struct spu_context *ctx) +{ + mutex_lock(&ctx->state_mutex); +} + +static inline void spu_release(struct spu_context *ctx) +{ + mutex_unlock(&ctx->state_mutex); +} + struct spu_context * alloc_spu_context(struct spu_gang *gang); void destroy_spu_context(struct kref *kref); struct spu_context * get_spu_context(struct spu_context *ctx); @@ -166,20 +188,18 @@ int put_spu_context(struct spu_context * void spu_unmap_mappings(struct spu_context *ctx); void spu_forget(struct spu_context *ctx); -void spu_acquire(struct spu_context *ctx); -void spu_release(struct spu_context *ctx); -int spu_acquire_runnable(struct spu_context *ctx); +int spu_acquire_runnable(struct spu_context *ctx, unsigned long flags); void spu_acquire_saved(struct spu_context *ctx); int spu_acquire_exclusive(struct spu_context *ctx); - -static inline void spu_release_exclusive(struct spu_context *ctx) -{ - up_write(&ctx->state_sema); -} - -int spu_activate(struct spu_context *ctx, u64 flags); +enum { + SPU_ACTIVATE_NOWAKE = 1, +}; +int spu_activate(struct spu_context *ctx, unsigned long flags); void spu_deactivate(struct spu_context *ctx); void spu_yield(struct spu_context *ctx); +void spu_start_tick(struct spu_context *ctx); +void spu_stop_tick(struct spu_context *ctx); +void spu_sched_tick(struct work_struct *work); int __init spu_sched_init(void); void __exit spu_sched_exit(void); diff --git a/arch/powerpc/platforms/celleb/Makefile b/arch/powerpc/platforms/celleb/Makefile new file mode 100644 index 0000000..3baf658 --- /dev/null +++ b/arch/powerpc/platforms/celleb/Makefile @@ -0,0 +1,9 @@ +obj-y += interrupt.o iommu.o setup.o \ + htab.o beat.o pci.o \ + scc_epci.o hvCall.o + +obj-$(CONFIG_SMP) += smp.o +obj-$(CONFIG_PPC_UDBG_BEAT) += udbg_beat.o +obj-$(CONFIG_USB) += scc_uhc.o +obj-$(CONFIG_HAS_TXX9_SERIAL) += scc_sio.o +obj-$(CONFIG_SPU_BASE) += spu_priv1.o diff --git a/arch/powerpc/platforms/celleb/beat.c b/arch/powerpc/platforms/celleb/beat.c new file mode 100644 index 0000000..99341ce --- /dev/null +++ b/arch/powerpc/platforms/celleb/beat.c @@ -0,0 +1,163 @@ +/* + * Simple routines for Celleb/Beat + * + * (C) Copyright 2006-2007 TOSHIBA CORPORATION + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#include +#include +#include +#include + +#include +#include + +#include "beat_wrapper.h" +#include "beat.h" + +void beat_restart(char *cmd) +{ + beat_shutdown_logical_partition(1); +} + +void beat_power_off(void) +{ + beat_shutdown_logical_partition(0); +} + +u64 beat_halt_code = 0x1000000000000000UL; + +void beat_halt(void) +{ + beat_shutdown_logical_partition(beat_halt_code); +} + +int beat_set_rtc_time(struct rtc_time *rtc_time) +{ + u64 tim; + tim = mktime(rtc_time->tm_year+1900, + rtc_time->tm_mon+1, rtc_time->tm_mday, + rtc_time->tm_hour, rtc_time->tm_min, rtc_time->tm_sec); + if (beat_rtc_write(tim)) + return -1; + return 0; +} + +void beat_get_rtc_time(struct rtc_time *rtc_time) +{ + u64 tim; + + if (beat_rtc_read(&tim)) + tim = 0; + to_tm(tim, rtc_time); + rtc_time->tm_year -= 1900; + rtc_time->tm_mon -= 1; +} + +#define BEAT_NVRAM_SIZE 4096 + +ssize_t beat_nvram_read(char *buf, size_t count, loff_t *index) +{ + unsigned int i; + unsigned long len; + char *p = buf; + + if (*index >= BEAT_NVRAM_SIZE) + return -ENODEV; + i = *index; + if (i + count > BEAT_NVRAM_SIZE) + count = BEAT_NVRAM_SIZE - i; + + for (; count != 0; count -= len) { + len = count; + if (len > BEAT_NVRW_CNT) + len = BEAT_NVRW_CNT; + if (beat_eeprom_read(i, len, p)) { + return -EIO; + } + + p += len; + i += len; + } + *index = i; + return p - buf; +} + +ssize_t beat_nvram_write(char *buf, size_t count, loff_t *index) +{ + unsigned int i; + unsigned long len; + char *p = buf; + + if (*index >= BEAT_NVRAM_SIZE) + return -ENODEV; + i = *index; + if (i + count > BEAT_NVRAM_SIZE) + count = BEAT_NVRAM_SIZE - i; + + for (; count != 0; count -= len) { + len = count; + if (len > BEAT_NVRW_CNT) + len = BEAT_NVRW_CNT; + if (beat_eeprom_write(i, len, p)) { + return -EIO; + } + + p += len; + i += len; + } + *index = i; + return p - buf; +} + +ssize_t beat_nvram_get_size(void) +{ + return BEAT_NVRAM_SIZE; +} + +int beat_set_xdabr(unsigned long dabr) +{ + if (beat_set_dabr(dabr, DABRX_KERNEL | DABRX_USER)) + return -1; + return 0; +} + +int64_t beat_get_term_char(u64 vterm, u64 *len, u64 *t1, u64 *t2) +{ + u64 db[2]; + s64 ret; + + ret = beat_get_characters_from_console(vterm, len, (u8*)db); + if (ret == 0) { + *t1 = db[0]; + *t2 = db[1]; + } + return ret; +} + +int64_t beat_put_term_char(u64 vterm, u64 len, u64 t1, u64 t2) +{ + u64 db[2]; + + db[0] = t1; + db[1] = t2; + return beat_put_characters_to_console(vterm, len, (u8*)db); +} + +EXPORT_SYMBOL(beat_get_term_char); +EXPORT_SYMBOL(beat_put_term_char); +EXPORT_SYMBOL(beat_halt_code); diff --git a/arch/powerpc/platforms/celleb/beat.h b/arch/powerpc/platforms/celleb/beat.h new file mode 100644 index 0000000..2b16bf3 --- /dev/null +++ b/arch/powerpc/platforms/celleb/beat.h @@ -0,0 +1,40 @@ +/* + * Guest OS Interfaces. + * + * (C) Copyright 2006 TOSHIBA CORPORATION + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#ifndef _CELLEB_BEAT_H +#define _CELLEB_BEAT_H + +#define DABRX_KERNEL (1UL<<1) +#define DABRX_USER (1UL<<0) + +int64_t beat_get_term_char(uint64_t,uint64_t*,uint64_t*,uint64_t*); +int64_t beat_put_term_char(uint64_t,uint64_t,uint64_t,uint64_t); +int64_t beat_repository_encode(int, const char *, uint64_t[4]); +void beat_restart(char *); +void beat_power_off(void); +void beat_halt(void); +int beat_set_rtc_time(struct rtc_time *); +void beat_get_rtc_time(struct rtc_time *); +ssize_t beat_nvram_get_size(void); +ssize_t beat_nvram_read(char *, size_t, loff_t *); +ssize_t beat_nvram_write(char *, size_t, loff_t *); +int beat_set_xdabr(unsigned long); + +#endif /* _CELLEB_BEAT_H */ diff --git a/arch/powerpc/platforms/celleb/beat_syscall.h b/arch/powerpc/platforms/celleb/beat_syscall.h new file mode 100644 index 0000000..14e1697 --- /dev/null +++ b/arch/powerpc/platforms/celleb/beat_syscall.h @@ -0,0 +1,160 @@ +/* + * Beat hypervisor call numbers + * + * (C) Copyright 2004-2007 TOSHIBA CORPORATION + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#ifndef BEAT_BEAT_syscall_H +#define BEAT_BEAT_syscall_H + +#ifdef __ASSEMBLY__ +#define __BEAT_ADD_VENDOR_ID(__x, __v) ((__v)<<60|(__x)) +#else +#define __BEAT_ADD_VENDOR_ID(__x, __v) ((u64)(__v)<<60|(__x)) +#endif +#define HV_allocate_memory __BEAT_ADD_VENDOR_ID(0, 0) +#define HV_construct_virtual_address_space __BEAT_ADD_VENDOR_ID(2, 0) +#define HV_destruct_virtual_address_space __BEAT_ADD_VENDOR_ID(10, 0) +#define HV_get_virtual_address_space_id_of_ppe __BEAT_ADD_VENDOR_ID(4, 0) +#define HV_query_logical_partition_address_region_info \ + __BEAT_ADD_VENDOR_ID(6, 0) +#define HV_release_memory __BEAT_ADD_VENDOR_ID(13, 0) +#define HV_select_virtual_address_space __BEAT_ADD_VENDOR_ID(7, 0) +#define HV_load_range_registers __BEAT_ADD_VENDOR_ID(68, 0) +#define HV_set_ppe_l2cache_rmt_entry __BEAT_ADD_VENDOR_ID(70, 0) +#define HV_set_ppe_tlb_rmt_entry __BEAT_ADD_VENDOR_ID(71, 0) +#define HV_set_spe_tlb_rmt_entry __BEAT_ADD_VENDOR_ID(72, 0) +#define HV_get_io_address_translation_fault_info __BEAT_ADD_VENDOR_ID(14, 0) +#define HV_get_iopte __BEAT_ADD_VENDOR_ID(16, 0) +#define HV_preload_iopt_cache __BEAT_ADD_VENDOR_ID(17, 0) +#define HV_put_iopte __BEAT_ADD_VENDOR_ID(15, 0) +#define HV_connect_event_ports __BEAT_ADD_VENDOR_ID(21, 0) +#define HV_construct_event_receive_port __BEAT_ADD_VENDOR_ID(18, 0) +#define HV_destruct_event_receive_port __BEAT_ADD_VENDOR_ID(19, 0) +#define HV_destruct_event_send_port __BEAT_ADD_VENDOR_ID(22, 0) +#define HV_get_state_of_event_send_port __BEAT_ADD_VENDOR_ID(25, 0) +#define HV_request_to_connect_event_ports __BEAT_ADD_VENDOR_ID(20, 0) +#define HV_send_event_externally __BEAT_ADD_VENDOR_ID(23, 0) +#define HV_send_event_locally __BEAT_ADD_VENDOR_ID(24, 0) +#define HV_construct_and_connect_irq_plug __BEAT_ADD_VENDOR_ID(28, 0) +#define HV_destruct_irq_plug __BEAT_ADD_VENDOR_ID(29, 0) +#define HV_detect_pending_interrupts __BEAT_ADD_VENDOR_ID(26, 0) +#define HV_end_of_interrupt __BEAT_ADD_VENDOR_ID(27, 0) +#define HV_assign_control_signal_notification_port __BEAT_ADD_VENDOR_ID(45, 0) +#define HV_end_of_control_signal_processing __BEAT_ADD_VENDOR_ID(48, 0) +#define HV_get_control_signal __BEAT_ADD_VENDOR_ID(46, 0) +#define HV_set_irq_mask_for_spe __BEAT_ADD_VENDOR_ID(61, 0) +#define HV_shutdown_logical_partition __BEAT_ADD_VENDOR_ID(44, 0) +#define HV_connect_message_ports __BEAT_ADD_VENDOR_ID(35, 0) +#define HV_destruct_message_port __BEAT_ADD_VENDOR_ID(36, 0) +#define HV_receive_message __BEAT_ADD_VENDOR_ID(37, 0) +#define HV_get_message_port_info __BEAT_ADD_VENDOR_ID(34, 0) +#define HV_request_to_connect_message_ports __BEAT_ADD_VENDOR_ID(33, 0) +#define HV_send_message __BEAT_ADD_VENDOR_ID(32, 0) +#define HV_get_logical_ppe_id __BEAT_ADD_VENDOR_ID(69, 0) +#define HV_pause __BEAT_ADD_VENDOR_ID(9, 0) +#define HV_destruct_shared_memory_handle __BEAT_ADD_VENDOR_ID(51, 0) +#define HV_get_shared_memory_info __BEAT_ADD_VENDOR_ID(52, 0) +#define HV_permit_sharing_memory __BEAT_ADD_VENDOR_ID(50, 0) +#define HV_request_to_attach_shared_memory __BEAT_ADD_VENDOR_ID(49, 0) +#define HV_enable_logical_spe_execution __BEAT_ADD_VENDOR_ID(55, 0) +#define HV_construct_logical_spe __BEAT_ADD_VENDOR_ID(53, 0) +#define HV_disable_logical_spe_execution __BEAT_ADD_VENDOR_ID(56, 0) +#define HV_destruct_logical_spe __BEAT_ADD_VENDOR_ID(54, 0) +#define HV_sense_spe_execution_status __BEAT_ADD_VENDOR_ID(58, 0) +#define HV_insert_htab_entry __BEAT_ADD_VENDOR_ID(101, 0) +#define HV_read_htab_entries __BEAT_ADD_VENDOR_ID(95, 0) +#define HV_write_htab_entry __BEAT_ADD_VENDOR_ID(94, 0) +#define HV_assign_io_address_translation_fault_port \ + __BEAT_ADD_VENDOR_ID(100, 0) +#define HV_set_interrupt_mask __BEAT_ADD_VENDOR_ID(73, 0) +#define HV_get_logical_partition_id __BEAT_ADD_VENDOR_ID(74, 0) +#define HV_create_repository_node2 __BEAT_ADD_VENDOR_ID(90, 0) +#define HV_create_repository_node __BEAT_ADD_VENDOR_ID(90, 0) /* alias */ +#define HV_get_repository_node_value2 __BEAT_ADD_VENDOR_ID(91, 0) +#define HV_get_repository_node_value __BEAT_ADD_VENDOR_ID(91, 0) /* alias */ +#define HV_modify_repository_node_value2 __BEAT_ADD_VENDOR_ID(92, 0) +#define HV_modify_repository_node_value __BEAT_ADD_VENDOR_ID(92, 0) /* alias */ +#define HV_remove_repository_node2 __BEAT_ADD_VENDOR_ID(93, 0) +#define HV_remove_repository_node __BEAT_ADD_VENDOR_ID(93, 0) /* alias */ +#define HV_cancel_shared_memory __BEAT_ADD_VENDOR_ID(104, 0) +#define HV_clear_interrupt_status_of_spe __BEAT_ADD_VENDOR_ID(206, 0) +#define HV_construct_spe_irq_outlet __BEAT_ADD_VENDOR_ID(80, 0) +#define HV_destruct_spe_irq_outlet __BEAT_ADD_VENDOR_ID(81, 0) +#define HV_disconnect_ipspc_service __BEAT_ADD_VENDOR_ID(88, 0) +#define HV_execute_ipspc_command __BEAT_ADD_VENDOR_ID(86, 0) +#define HV_get_interrupt_status_of_spe __BEAT_ADD_VENDOR_ID(205, 0) +#define HV_get_spe_privileged_state_1_registers __BEAT_ADD_VENDOR_ID(208, 0) +#define HV_permit_use_of_ipspc_service __BEAT_ADD_VENDOR_ID(85, 0) +#define HV_reinitialize_logical_spe __BEAT_ADD_VENDOR_ID(82, 0) +#define HV_request_ipspc_service __BEAT_ADD_VENDOR_ID(84, 0) +#define HV_stop_ipspc_command __BEAT_ADD_VENDOR_ID(87, 0) +#define HV_set_spe_privileged_state_1_registers __BEAT_ADD_VENDOR_ID(204, 0) +#define HV_get_status_of_ipspc_service __BEAT_ADD_VENDOR_ID(203, 0) +#define HV_put_characters_to_console __BEAT_ADD_VENDOR_ID(0x101, 1) +#define HV_get_characters_from_console __BEAT_ADD_VENDOR_ID(0x102, 1) +#define HV_get_base_clock __BEAT_ADD_VENDOR_ID(0x111, 1) +#define HV_set_base_clock __BEAT_ADD_VENDOR_ID(0x112, 1) +#define HV_get_frame_cycle __BEAT_ADD_VENDOR_ID(0x114, 1) +#define HV_disable_console __BEAT_ADD_VENDOR_ID(0x115, 1) +#define HV_disable_all_console __BEAT_ADD_VENDOR_ID(0x116, 1) +#define HV_oneshot_timer __BEAT_ADD_VENDOR_ID(0x117, 1) +#define HV_set_dabr __BEAT_ADD_VENDOR_ID(0x118, 1) +#define HV_get_dabr __BEAT_ADD_VENDOR_ID(0x119, 1) +#define HV_start_hv_stats __BEAT_ADD_VENDOR_ID(0x21c, 1) +#define HV_stop_hv_stats __BEAT_ADD_VENDOR_ID(0x21d, 1) +#define HV_get_hv_stats __BEAT_ADD_VENDOR_ID(0x21e, 1) +#define HV_get_hv_error_stats __BEAT_ADD_VENDOR_ID(0x221, 1) +#define HV_get_stats __BEAT_ADD_VENDOR_ID(0x224, 1) +#define HV_get_heap_stats __BEAT_ADD_VENDOR_ID(0x225, 1) +#define HV_get_memory_stats __BEAT_ADD_VENDOR_ID(0x227, 1) +#define HV_get_memory_detail __BEAT_ADD_VENDOR_ID(0x228, 1) +#define HV_set_priority_of_irq_outlet __BEAT_ADD_VENDOR_ID(0x122, 1) +#define HV_get_physical_spe_by_reservation_id __BEAT_ADD_VENDOR_ID(0x128, 1) +#define HV_get_spe_context __BEAT_ADD_VENDOR_ID(0x129, 1) +#define HV_set_spe_context __BEAT_ADD_VENDOR_ID(0x12a, 1) +#define HV_downcount_of_interrupt __BEAT_ADD_VENDOR_ID(0x12e, 1) +#define HV_peek_spe_context __BEAT_ADD_VENDOR_ID(0x12f, 1) +#define HV_read_bpa_register __BEAT_ADD_VENDOR_ID(0x131, 1) +#define HV_write_bpa_register __BEAT_ADD_VENDOR_ID(0x132, 1) +#define HV_map_context_table_of_spe __BEAT_ADD_VENDOR_ID(0x137, 1) +#define HV_get_slb_for_logical_spe __BEAT_ADD_VENDOR_ID(0x138, 1) +#define HV_set_slb_for_logical_spe __BEAT_ADD_VENDOR_ID(0x139, 1) +#define HV_init_pm __BEAT_ADD_VENDOR_ID(0x150, 1) +#define HV_set_pm_signal __BEAT_ADD_VENDOR_ID(0x151, 1) +#define HV_get_pm_signal __BEAT_ADD_VENDOR_ID(0x152, 1) +#define HV_set_pm_config __BEAT_ADD_VENDOR_ID(0x153, 1) +#define HV_get_pm_config __BEAT_ADD_VENDOR_ID(0x154, 1) +#define HV_get_inner_trace_data __BEAT_ADD_VENDOR_ID(0x155, 1) +#define HV_set_ext_trace_buffer __BEAT_ADD_VENDOR_ID(0x156, 1) +#define HV_get_ext_trace_buffer __BEAT_ADD_VENDOR_ID(0x157, 1) +#define HV_set_pm_interrupt __BEAT_ADD_VENDOR_ID(0x158, 1) +#define HV_get_pm_interrupt __BEAT_ADD_VENDOR_ID(0x159, 1) +#define HV_kick_pm __BEAT_ADD_VENDOR_ID(0x160, 1) +#define HV_construct_pm_context __BEAT_ADD_VENDOR_ID(0x164, 1) +#define HV_destruct_pm_context __BEAT_ADD_VENDOR_ID(0x165, 1) +#define HV_be_slow __BEAT_ADD_VENDOR_ID(0x170, 1) +#define HV_assign_ipspc_server_connection_status_notification_port \ + __BEAT_ADD_VENDOR_ID(0x173, 1) +#define HV_get_raid_of_physical_spe __BEAT_ADD_VENDOR_ID(0x174, 1) +#define HV_set_physical_spe_to_rag __BEAT_ADD_VENDOR_ID(0x175, 1) +#define HV_release_physical_spe_from_rag __BEAT_ADD_VENDOR_ID(0x176, 1) +#define HV_rtc_read __BEAT_ADD_VENDOR_ID(0x190, 1) +#define HV_rtc_write __BEAT_ADD_VENDOR_ID(0x191, 1) +#define HV_eeprom_read __BEAT_ADD_VENDOR_ID(0x192, 1) +#define HV_eeprom_write __BEAT_ADD_VENDOR_ID(0x193, 1) +#endif diff --git a/arch/powerpc/platforms/celleb/beat_wrapper.h b/arch/powerpc/platforms/celleb/beat_wrapper.h new file mode 100644 index 0000000..76ea0a6 --- /dev/null +++ b/arch/powerpc/platforms/celleb/beat_wrapper.h @@ -0,0 +1,220 @@ +/* + * Beat hypervisor call I/F + * + * (C) Copyright 2007 TOSHIBA CORPORATION + * + * This code is based on arch/powerpc/platforms/pseries/plpar_wrapper.h. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +#ifndef BEAT_HCALL +#include "beat_syscall.h" + +/* defined in hvCall.S */ +extern s64 beat_hcall_norets(u64 opcode, ...); +extern s64 beat_hcall_norets8(u64 opcode, u64 arg1, u64 arg2, u64 arg3, + u64 arg4, u64 arg5, u64 arg6, u64 arg7, u64 arg8); +extern s64 beat_hcall1(u64 opcode, u64 retbuf[1], ...); +extern s64 beat_hcall2(u64 opcode, u64 retbuf[2], ...); +extern s64 beat_hcall3(u64 opcode, u64 retbuf[3], ...); +extern s64 beat_hcall4(u64 opcode, u64 retbuf[4], ...); +extern s64 beat_hcall5(u64 opcode, u64 retbuf[5], ...); +extern s64 beat_hcall6(u64 opcode, u64 retbuf[6], ...); + +static inline s64 beat_downcount_of_interrupt(u64 plug_id) +{ + return beat_hcall_norets(HV_downcount_of_interrupt, plug_id); +} + +static inline s64 beat_set_interrupt_mask(u64 index, + u64 val0, u64 val1, u64 val2, u64 val3) +{ + return beat_hcall_norets(HV_set_interrupt_mask, index, + val0, val1, val2, val3); +} + +static inline s64 beat_destruct_irq_plug(u64 plug_id) +{ + return beat_hcall_norets(HV_destruct_irq_plug, plug_id); +} + +static inline s64 beat_construct_and_connect_irq_plug(u64 plug_id, + u64 outlet_id) +{ + return beat_hcall_norets(HV_construct_and_connect_irq_plug, plug_id, + outlet_id); +} + +static inline s64 beat_detect_pending_interrupts(u64 index, u64 *retbuf) +{ + return beat_hcall4(HV_detect_pending_interrupts, retbuf, index); +} + +static inline s64 beat_pause(u64 style) +{ + return beat_hcall_norets(HV_pause, style); +} + +static inline s64 beat_read_htab_entries(u64 htab_id, u64 index, u64 *retbuf) +{ + return beat_hcall5(HV_read_htab_entries, retbuf, htab_id, index); +} + +static inline s64 beat_insert_htab_entry(u64 htab_id, u64 group, + u64 bitmask, u64 hpte_v, u64 hpte_r, u64 *slot) +{ + u64 dummy[3]; + s64 ret; + + ret = beat_hcall3(HV_insert_htab_entry, dummy, htab_id, group, + bitmask, hpte_v, hpte_r); + *slot = dummy[0]; + return ret; +} + +static inline s64 beat_write_htab_entry(u64 htab_id, u64 slot, + u64 hpte_v, u64 hpte_r, u64 mask_v, u64 mask_r, + u64 *ret_v, u64 *ret_r) +{ + u64 dummy[2]; + s64 ret; + + ret = beat_hcall2(HV_write_htab_entry, dummy, htab_id, slot, + hpte_v, hpte_r, mask_v, mask_r); + *ret_v = dummy[0]; + *ret_r = dummy[1]; + return ret; +} + +static inline void beat_shutdown_logical_partition(u64 code) +{ + (void)beat_hcall_norets(HV_shutdown_logical_partition, code); +} + +static inline s64 beat_rtc_write(u64 time_from_epoch) +{ + return beat_hcall_norets(HV_rtc_write, time_from_epoch); +} + +static inline s64 beat_rtc_read(u64 *time_from_epoch) +{ + u64 dummy[1]; + s64 ret; + + ret = beat_hcall1(HV_rtc_read, dummy); + *time_from_epoch = dummy[0]; + return ret; +} + +#define BEAT_NVRW_CNT (sizeof(u64) * 6) + +static inline s64 beat_eeprom_write(u64 index, u64 length, u8 *buffer) +{ + u64 b[6]; + + if (length > BEAT_NVRW_CNT) + return -1; + memcpy(b, buffer, sizeof(b)); + return beat_hcall_norets8(HV_eeprom_write, index, length, + b[0], b[1], b[2], b[3], b[4], b[5]); +} + +static inline s64 beat_eeprom_read(u64 index, u64 length, u8 *buffer) +{ + u64 b[6]; + s64 ret; + + if (length > BEAT_NVRW_CNT) + return -1; + ret = beat_hcall6(HV_eeprom_read, b, index, length); + memcpy(buffer, b, length); + return ret; +} + +static inline s64 beat_set_dabr(u64 value, u64 style) +{ + return beat_hcall_norets(HV_set_dabr, value, style); +} + +static inline s64 beat_get_characters_from_console(u64 termno, u64 *len, + u8 *buffer) +{ + u64 dummy[3]; + s64 ret; + + ret = beat_hcall3(HV_get_characters_from_console, dummy, termno, len); + *len = dummy[0]; + memcpy(buffer, dummy + 1, *len); + return ret; +} + +static inline s64 beat_put_characters_to_console(u64 termno, u64 len, + u8 *buffer) +{ + u64 b[2]; + + memcpy(b, buffer, len); + return beat_hcall_norets(HV_put_characters_to_console, termno, len, b[0], b[1]); +} + +static inline s64 beat_get_spe_privileged_state_1_registers( + u64 id, u64 offsetof, u64 *value) +{ + u64 dummy[1]; + s64 ret; + + ret = beat_hcall1(HV_get_spe_privileged_state_1_registers, dummy, id, + offsetof); + *value = dummy[0]; + return ret; +} + +static inline s64 beat_set_irq_mask_for_spe(u64 id, u64 class, u64 mask) +{ + return beat_hcall_norets(HV_set_irq_mask_for_spe, id, class, mask); +} + +static inline s64 beat_clear_interrupt_status_of_spe(u64 id, u64 class, + u64 mask) +{ + return beat_hcall_norets(HV_clear_interrupt_status_of_spe, + id, class, mask); +} + +static inline s64 beat_set_spe_privileged_state_1_registers( + u64 id, u64 offsetof, u64 value) +{ + return beat_hcall_norets(HV_set_spe_privileged_state_1_registers, + id, offsetof, value); +} + +static inline s64 beat_get_interrupt_status_of_spe(u64 id, u64 class, u64 *val) +{ + u64 dummy[1]; + s64 ret; + + ret = beat_hcall1(HV_get_interrupt_status_of_spe, dummy, id, class); + *val = dummy[0]; + return ret; +} + +static inline s64 beat_put_iopte(u64 ioas_id, u64 io_addr, u64 real_addr, + u64 ioid, u64 flags) +{ + return beat_hcall_norets(HV_put_iopte, ioas_id, io_addr, real_addr, + ioid, flags); +} + +#endif diff --git a/arch/powerpc/platforms/celleb/htab.c b/arch/powerpc/platforms/celleb/htab.c new file mode 100644 index 0000000..279d733 --- /dev/null +++ b/arch/powerpc/platforms/celleb/htab.c @@ -0,0 +1,308 @@ +/* + * "Cell Reference Set" HTAB support. + * + * (C) Copyright 2006-2007 TOSHIBA CORPORATION + * + * This code is based on arch/powerpc/platforms/pseries/lpar.c: + * Copyright (C) 2001 Todd Inglett, IBM Corporation + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#undef DEBUG_LOW + +#include +#include + +#include +#include +#include +#include +#include + +#include "beat_wrapper.h" + +#ifdef DEBUG_LOW +#define DBG_LOW(fmt...) do { udbg_printf(fmt); } while(0) +#else +#define DBG_LOW(fmt...) do { } while(0) +#endif + +static DEFINE_SPINLOCK(beat_htab_lock); + +static inline unsigned int beat_read_mask(unsigned hpte_group) +{ + unsigned long hpte_v[5]; + unsigned long rmask = 0; + + beat_read_htab_entries(0, hpte_group + 0, hpte_v); + if (!(hpte_v[0] & HPTE_V_BOLTED)) + rmask |= 0x8000; + if (!(hpte_v[1] & HPTE_V_BOLTED)) + rmask |= 0x4000; + if (!(hpte_v[2] & HPTE_V_BOLTED)) + rmask |= 0x2000; + if (!(hpte_v[3] & HPTE_V_BOLTED)) + rmask |= 0x1000; + beat_read_htab_entries(0, hpte_group + 4, hpte_v); + if (!(hpte_v[0] & HPTE_V_BOLTED)) + rmask |= 0x0800; + if (!(hpte_v[1] & HPTE_V_BOLTED)) + rmask |= 0x0400; + if (!(hpte_v[2] & HPTE_V_BOLTED)) + rmask |= 0x0200; + if (!(hpte_v[3] & HPTE_V_BOLTED)) + rmask |= 0x0100; + hpte_group = ~hpte_group & (htab_hash_mask * HPTES_PER_GROUP); + beat_read_htab_entries(0, hpte_group + 0, hpte_v); + if (!(hpte_v[0] & HPTE_V_BOLTED)) + rmask |= 0x80; + if (!(hpte_v[1] & HPTE_V_BOLTED)) + rmask |= 0x40; + if (!(hpte_v[2] & HPTE_V_BOLTED)) + rmask |= 0x20; + if (!(hpte_v[3] & HPTE_V_BOLTED)) + rmask |= 0x10; + beat_read_htab_entries(0, hpte_group + 4, hpte_v); + if (!(hpte_v[0] & HPTE_V_BOLTED)) + rmask |= 0x08; + if (!(hpte_v[1] & HPTE_V_BOLTED)) + rmask |= 0x04; + if (!(hpte_v[2] & HPTE_V_BOLTED)) + rmask |= 0x02; + if (!(hpte_v[3] & HPTE_V_BOLTED)) + rmask |= 0x01; + return rmask; +} + +static long beat_lpar_hpte_insert(unsigned long hpte_group, + unsigned long va, unsigned long pa, + unsigned long rflags, unsigned long vflags, + int psize) +{ + unsigned long lpar_rc; + unsigned long slot; + unsigned long hpte_v, hpte_r; + + /* same as iseries */ + if (vflags & HPTE_V_SECONDARY) + return -1; + + if (!(vflags & HPTE_V_BOLTED)) + DBG_LOW("hpte_insert(group=%lx, va=%016lx, pa=%016lx, " + "rflags=%lx, vflags=%lx, psize=%d)\n", + hpte_group, va, pa, rflags, vflags, psize); + + hpte_v = hpte_encode_v(va, psize) | vflags | HPTE_V_VALID; + hpte_r = hpte_encode_r(pa, psize) | rflags; + + if (!(vflags & HPTE_V_BOLTED)) + DBG_LOW(" hpte_v=%016lx, hpte_r=%016lx\n", hpte_v, hpte_r); + + if (rflags & (_PAGE_GUARDED|_PAGE_NO_CACHE)) + hpte_r &= ~_PAGE_COHERENT; + + spin_lock(&beat_htab_lock); + if ((lpar_rc = beat_read_mask(hpte_group)) == 0) { + if (!(vflags & HPTE_V_BOLTED)) + DBG_LOW(" full\n"); + spin_unlock(&beat_htab_lock); + return -1; + } + + lpar_rc = beat_insert_htab_entry(0, hpte_group, lpar_rc << 48, + hpte_v, hpte_r, &slot); + spin_unlock(&beat_htab_lock); + + /* + * Since we try and ioremap PHBs we don't own, the pte insert + * will fail. However we must catch the failure in hash_page + * or we will loop forever, so return -2 in this case. + */ + if (unlikely(lpar_rc != 0)) { + if (!(vflags & HPTE_V_BOLTED)) + DBG_LOW(" lpar err %lx\n", lpar_rc); + return -2; + } + if (!(vflags & HPTE_V_BOLTED)) + DBG_LOW(" -> slot: %lx\n", slot); + + /* We have to pass down the secondary bucket bit here as well */ + return (slot ^ hpte_group) & 15; +} + +static long beat_lpar_hpte_remove(unsigned long hpte_group) +{ + DBG_LOW("hpte_remove(group=%lx)\n", hpte_group); + return -1; +} + +static unsigned long beat_lpar_hpte_getword0(unsigned long slot) +{ + unsigned long dword0, dword[5]; + unsigned long lpar_rc; + + lpar_rc = beat_read_htab_entries(0, slot & ~3UL, dword); + + dword0 = dword[slot&3]; + + BUG_ON(lpar_rc != 0); + + return dword0; +} + +static void beat_lpar_hptab_clear(void) +{ + unsigned long size_bytes = 1UL << ppc64_pft_size; + unsigned long hpte_count = size_bytes >> 4; + int i; + unsigned long dummy0, dummy1; + + /* TODO: Use bulk call */ + for (i = 0; i < hpte_count; i++) + beat_write_htab_entry(0, i, 0, 0, -1UL, -1UL, &dummy0, &dummy1); +} + +/* + * NOTE: for updatepp ops we are fortunate that the linux "newpp" bits and + * the low 3 bits of flags happen to line up. So no transform is needed. + * We can probably optimize here and assume the high bits of newpp are + * already zero. For now I am paranoid. + */ +static long beat_lpar_hpte_updatepp(unsigned long slot, + unsigned long newpp, + unsigned long va, + int psize, int local) +{ + unsigned long lpar_rc; + unsigned long dummy0, dummy1, want_v; + + want_v = hpte_encode_v(va, psize); + + DBG_LOW(" update: " + "avpnv=%016lx, slot=%016lx, psize: %d, newpp %016lx ... ", + want_v & HPTE_V_AVPN, slot, psize, newpp); + + spin_lock(&beat_htab_lock); + dummy0 = beat_lpar_hpte_getword0(slot); + if ((dummy0 & ~0x7FUL) != (want_v & ~0x7FUL)) { + DBG_LOW("not found !\n"); + spin_unlock(&beat_htab_lock); + return -1; + } + + lpar_rc = beat_write_htab_entry(0, slot, 0, newpp, 0, 7, &dummy0, + &dummy1); + spin_unlock(&beat_htab_lock); + if (lpar_rc != 0 || dummy0 == 0) { + DBG_LOW("not found !\n"); + return -1; + } + + DBG_LOW("ok %lx %lx\n", dummy0, dummy1); + + BUG_ON(lpar_rc != 0); + + return 0; +} + +static long beat_lpar_hpte_find(unsigned long va, int psize) +{ + unsigned long hash; + unsigned long i, j; + long slot; + unsigned long want_v, hpte_v; + + hash = hpt_hash(va, mmu_psize_defs[psize].shift); + want_v = hpte_encode_v(va, psize); + + for (j = 0; j < 2; j++) { + slot = (hash & htab_hash_mask) * HPTES_PER_GROUP; + for (i = 0; i < HPTES_PER_GROUP; i++) { + hpte_v = beat_lpar_hpte_getword0(slot); + + if (HPTE_V_COMPARE(hpte_v, want_v) + && (hpte_v & HPTE_V_VALID) + && (!!(hpte_v & HPTE_V_SECONDARY) == j)) { + /* HPTE matches */ + if (j) + slot = -slot; + return slot; + } + ++slot; + } + hash = ~hash; + } + + return -1; +} + +static void beat_lpar_hpte_updateboltedpp(unsigned long newpp, + unsigned long ea, + int psize) +{ + unsigned long lpar_rc, slot, vsid, va, dummy0, dummy1; + + vsid = get_kernel_vsid(ea); + va = (vsid << 28) | (ea & 0x0fffffff); + + spin_lock(&beat_htab_lock); + slot = beat_lpar_hpte_find(va, psize); + BUG_ON(slot == -1); + + lpar_rc = beat_write_htab_entry(0, slot, 0, newpp, 0, 7, + &dummy0, &dummy1); + spin_unlock(&beat_htab_lock); + + BUG_ON(lpar_rc != 0); +} + +static void beat_lpar_hpte_invalidate(unsigned long slot, unsigned long va, + int psize, int local) +{ + unsigned long want_v; + unsigned long lpar_rc; + unsigned long dummy1, dummy2; + unsigned long flags; + + DBG_LOW(" inval : slot=%lx, va=%016lx, psize: %d, local: %d\n", + slot, va, psize, local); + want_v = hpte_encode_v(va, psize); + + spin_lock_irqsave(&beat_htab_lock, flags); + dummy1 = beat_lpar_hpte_getword0(slot); + + if ((dummy1 & ~0x7FUL) != (want_v & ~0x7FUL)) { + DBG_LOW("not found !\n"); + spin_unlock_irqrestore(&beat_htab_lock, flags); + return; + } + + lpar_rc = beat_write_htab_entry(0, slot, 0, 0, HPTE_V_VALID, 0, + &dummy1, &dummy2); + spin_unlock_irqrestore(&beat_htab_lock, flags); + + BUG_ON(lpar_rc != 0); +} + +void __init hpte_init_beat(void) +{ + ppc_md.hpte_invalidate = beat_lpar_hpte_invalidate; + ppc_md.hpte_updatepp = beat_lpar_hpte_updatepp; + ppc_md.hpte_updateboltedpp = beat_lpar_hpte_updateboltedpp; + ppc_md.hpte_insert = beat_lpar_hpte_insert; + ppc_md.hpte_remove = beat_lpar_hpte_remove; + ppc_md.hpte_clear_all = beat_lpar_hptab_clear; +} diff --git a/arch/powerpc/platforms/celleb/hvCall.S b/arch/powerpc/platforms/celleb/hvCall.S new file mode 100644 index 0000000..74c8174 --- /dev/null +++ b/arch/powerpc/platforms/celleb/hvCall.S @@ -0,0 +1,287 @@ +/* + * Beat hypervisor call I/F + * + * (C) Copyright 2007 TOSHIBA CORPORATION + * + * This code is based on arch/powerpc/platforms/pseries/hvCall.S. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#include + +#define STK_PARM(i) (48 + ((i)-3)*8) + +/* Not implemented on Beat, now */ +#define HCALL_INST_PRECALL +#define HCALL_INST_POSTCALL + + .text + +#define HVSC .long 0x44000022 + +/* Note: takes only 7 input parameters at maximum */ +_GLOBAL(beat_hcall_norets) + HMT_MEDIUM + + mfcr r0 + stw r0,8(r1) + + HCALL_INST_PRECALL + + mr r11,r3 + mr r3,r4 + mr r4,r5 + mr r5,r6 + mr r6,r7 + mr r7,r8 + mr r8,r9 + + HVSC /* invoke the hypervisor */ + + HCALL_INST_POSTCALL + + lwz r0,8(r1) + mtcrf 0xff,r0 + + blr /* return r3 = status */ + +/* Note: takes 8 input parameters at maximum */ +_GLOBAL(beat_hcall_norets8) + HMT_MEDIUM + + mfcr r0 + stw r0,8(r1) + + HCALL_INST_PRECALL + + mr r11,r3 + mr r3,r4 + mr r4,r5 + mr r5,r6 + mr r6,r7 + mr r7,r8 + mr r8,r9 + ld r10,STK_PARM(r10)(r1) + + HVSC /* invoke the hypervisor */ + + HCALL_INST_POSTCALL + + lwz r0,8(r1) + mtcrf 0xff,r0 + + blr /* return r3 = status */ + +/* Note: takes only 6 input parameters, 1 output parameters at maximum */ +_GLOBAL(beat_hcall1) + HMT_MEDIUM + + mfcr r0 + stw r0,8(r1) + + HCALL_INST_PRECALL + + std r4,STK_PARM(r4)(r1) /* save ret buffer */ + + mr r11,r3 + mr r3,r5 + mr r4,r6 + mr r5,r7 + mr r6,r8 + mr r7,r9 + mr r8,r10 + + HVSC /* invoke the hypervisor */ + + HCALL_INST_POSTCALL + + ld r12,STK_PARM(r4)(r1) + std r4, 0(r12) + + lwz r0,8(r1) + mtcrf 0xff,r0 + + blr /* return r3 = status */ + +/* Note: takes only 6 input parameters, 2 output parameters at maximum */ +_GLOBAL(beat_hcall2) + HMT_MEDIUM + + mfcr r0 + stw r0,8(r1) + + HCALL_INST_PRECALL + + std r4,STK_PARM(r4)(r1) /* save ret buffer */ + + mr r11,r3 + mr r3,r5 + mr r4,r6 + mr r5,r7 + mr r6,r8 + mr r7,r9 + mr r8,r10 + + HVSC /* invoke the hypervisor */ + + HCALL_INST_POSTCALL + + ld r12,STK_PARM(r4)(r1) + std r4, 0(r12) + std r5, 8(r12) + + lwz r0,8(r1) + mtcrf 0xff,r0 + + blr /* return r3 = status */ + +/* Note: takes only 6 input parameters, 3 output parameters at maximum */ +_GLOBAL(beat_hcall3) + HMT_MEDIUM + + mfcr r0 + stw r0,8(r1) + + HCALL_INST_PRECALL + + std r4,STK_PARM(r4)(r1) /* save ret buffer */ + + mr r11,r3 + mr r3,r5 + mr r4,r6 + mr r5,r7 + mr r6,r8 + mr r7,r9 + mr r8,r10 + + HVSC /* invoke the hypervisor */ + + HCALL_INST_POSTCALL + + ld r12,STK_PARM(r4)(r1) + std r4, 0(r12) + std r5, 8(r12) + std r6, 16(r12) + + lwz r0,8(r1) + mtcrf 0xff,r0 + + blr /* return r3 = status */ + +/* Note: takes only 6 input parameters, 4 output parameters at maximum */ +_GLOBAL(beat_hcall4) + HMT_MEDIUM + + mfcr r0 + stw r0,8(r1) + + HCALL_INST_PRECALL + + std r4,STK_PARM(r4)(r1) /* save ret buffer */ + + mr r11,r3 + mr r3,r5 + mr r4,r6 + mr r5,r7 + mr r6,r8 + mr r7,r9 + mr r8,r10 + + HVSC /* invoke the hypervisor */ + + HCALL_INST_POSTCALL + + ld r12,STK_PARM(r4)(r1) + std r4, 0(r12) + std r5, 8(r12) + std r6, 16(r12) + std r7, 24(r12) + + lwz r0,8(r1) + mtcrf 0xff,r0 + + blr /* return r3 = status */ + +/* Note: takes only 6 input parameters, 5 output parameters at maximum */ +_GLOBAL(beat_hcall5) + HMT_MEDIUM + + mfcr r0 + stw r0,8(r1) + + HCALL_INST_PRECALL + + std r4,STK_PARM(r4)(r1) /* save ret buffer */ + + mr r11,r3 + mr r3,r5 + mr r4,r6 + mr r5,r7 + mr r6,r8 + mr r7,r9 + mr r8,r10 + + HVSC /* invoke the hypervisor */ + + HCALL_INST_POSTCALL + + ld r12,STK_PARM(r4)(r1) + std r4, 0(r12) + std r5, 8(r12) + std r6, 16(r12) + std r7, 24(r12) + std r8, 32(r12) + + lwz r0,8(r1) + mtcrf 0xff,r0 + + blr /* return r3 = status */ + +/* Note: takes only 6 input parameters, 6 output parameters at maximum */ +_GLOBAL(beat_hcall6) + HMT_MEDIUM + + mfcr r0 + stw r0,8(r1) + + HCALL_INST_PRECALL + + std r4,STK_PARM(r4)(r1) /* save ret buffer */ + + mr r11,r3 + mr r3,r5 + mr r4,r6 + mr r5,r7 + mr r6,r8 + mr r7,r9 + mr r8,r10 + + HVSC /* invoke the hypervisor */ + + HCALL_INST_POSTCALL + + ld r12,STK_PARM(r4)(r1) + std r4, 0(r12) + std r5, 8(r12) + std r6, 16(r12) + std r7, 24(r12) + std r8, 32(r12) + std r9, 40(r12) + + lwz r0,8(r1) + mtcrf 0xff,r0 + + blr /* return r3 = status */ diff --git a/arch/powerpc/platforms/celleb/interrupt.c b/arch/powerpc/platforms/celleb/interrupt.c new file mode 100644 index 0000000..98e6665 --- /dev/null +++ b/arch/powerpc/platforms/celleb/interrupt.c @@ -0,0 +1,274 @@ +/* + * Celleb/Beat Interrupt controller + * + * (C) Copyright 2006-2007 TOSHIBA CORPORATION + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#include +#include +#include +#include +#include + +#include + +#include "interrupt.h" +#include "beat_wrapper.h" + +#define MAX_IRQS NR_IRQS +static DEFINE_SPINLOCK(beatic_irq_mask_lock); +static uint64_t beatic_irq_mask_enable[(MAX_IRQS+255)/64]; +static uint64_t beatic_irq_mask_ack[(MAX_IRQS+255)/64]; + +static struct irq_host *beatic_host = NULL; + +/* + * In this implementation, "virq" == "IRQ plug number", + * "(irq_hw_number_t)hwirq" == "IRQ outlet number". + */ + +/* assumption: locked */ +static inline void beatic_update_irq_mask(unsigned int irq_plug) +{ + int off; + unsigned long masks[4]; + + off = (irq_plug / 256) * 4; + masks[0] = beatic_irq_mask_enable[off + 0] + & beatic_irq_mask_ack[off + 0]; + masks[1] = beatic_irq_mask_enable[off + 1] + & beatic_irq_mask_ack[off + 1]; + masks[2] = beatic_irq_mask_enable[off + 2] + & beatic_irq_mask_ack[off + 2]; + masks[3] = beatic_irq_mask_enable[off + 3] + & beatic_irq_mask_ack[off + 3]; + if (beat_set_interrupt_mask(irq_plug&~255UL, + masks[0], masks[1], masks[2], masks[3]) != 0) + panic("Failed to set mask IRQ!"); +} + +static void beatic_mask_irq(unsigned int irq_plug) +{ + unsigned long flags; + + spin_lock_irqsave(&beatic_irq_mask_lock, flags); + beatic_irq_mask_enable[irq_plug/64] &= ~(1UL << (63 - (irq_plug%64))); + beatic_update_irq_mask(irq_plug); + spin_unlock_irqrestore(&beatic_irq_mask_lock, flags); +} + +static void beatic_unmask_irq(unsigned int irq_plug) +{ + unsigned long flags; + + spin_lock_irqsave(&beatic_irq_mask_lock, flags); + beatic_irq_mask_enable[irq_plug/64] |= 1UL << (63 - (irq_plug%64)); + beatic_update_irq_mask(irq_plug); + spin_unlock_irqrestore(&beatic_irq_mask_lock, flags); +} + +static void beatic_ack_irq(unsigned int irq_plug) +{ + unsigned long flags; + + spin_lock_irqsave(&beatic_irq_mask_lock, flags); + beatic_irq_mask_ack[irq_plug/64] &= ~(1UL << (63 - (irq_plug%64))); + beatic_update_irq_mask(irq_plug); + spin_unlock_irqrestore(&beatic_irq_mask_lock, flags); +} + +static void beatic_end_irq(unsigned int irq_plug) +{ + s64 err; + unsigned long flags; + + if ((err = beat_downcount_of_interrupt(irq_plug)) != 0) { + if ((err & 0xFFFFFFFF) != 0xFFFFFFF5) /* -11: wrong state */ + panic("Failed to downcount IRQ! Error = %16lx", err); + + printk(KERN_ERR "IRQ over-downcounted, plug %d\n", irq_plug); + } + spin_lock_irqsave(&beatic_irq_mask_lock, flags); + beatic_irq_mask_ack[irq_plug/64] |= 1UL << (63 - (irq_plug%64)); + beatic_update_irq_mask(irq_plug); + spin_unlock_irqrestore(&beatic_irq_mask_lock, flags); +} + +static struct irq_chip beatic_pic = { + .typename = " CELL-BEAT ", + .unmask = beatic_unmask_irq, + .mask = beatic_mask_irq, + .eoi = beatic_end_irq, +}; + +/* + * Dispose binding hardware IRQ number (hw) and Virtuql IRQ number (virq), + * update flags. + * + * Note that the number (virq) is already assigned at upper layer. + */ +static void beatic_pic_host_unmap(struct irq_host *h, unsigned int virq) +{ + beat_destruct_irq_plug(virq); +} + +/* + * Create or update binding hardware IRQ number (hw) and Virtuql + * IRQ number (virq). This is called only once for a given mapping. + * + * Note that the number (virq) is already assigned at upper layer. + */ +static int beatic_pic_host_map(struct irq_host *h, unsigned int virq, + irq_hw_number_t hw) +{ + struct irq_desc *desc = get_irq_desc(virq); + int64_t err; + + if ((err = beat_construct_and_connect_irq_plug(virq, hw)) < 0) + return -EIO; + + desc->status |= IRQ_LEVEL; + set_irq_chip_and_handler(virq, &beatic_pic, handle_fasteoi_irq); + return 0; +} + +/* + * Update binding hardware IRQ number (hw) and Virtuql + * IRQ number (virq). This is called only once for a given mapping. + */ +static void beatic_pic_host_remap(struct irq_host *h, unsigned int virq, + irq_hw_number_t hw) +{ + beat_construct_and_connect_irq_plug(virq, hw); +} + +/* + * Translate device-tree interrupt spec to irq_hw_number_t style (ulong), + * to pass away to irq_create_mapping(). + * + * Called from irq_create_of_mapping() only. + * Note: We have only 1 entry to translate. + */ +static int beatic_pic_host_xlate(struct irq_host *h, struct device_node *ct, + u32 *intspec, unsigned int intsize, + irq_hw_number_t *out_hwirq, + unsigned int *out_flags) +{ + u64 *intspec2 = (u64 *)intspec; + + *out_hwirq = *intspec2; + *out_flags |= IRQ_TYPE_LEVEL_LOW; + return 0; +} + +static struct irq_host_ops beatic_pic_host_ops = { + .map = beatic_pic_host_map, + .remap = beatic_pic_host_remap, + .unmap = beatic_pic_host_unmap, + .xlate = beatic_pic_host_xlate, +}; + +/* + * Get an IRQ number + * Note: returns VIRQ + */ +static inline unsigned int beatic_get_irq_plug(void) +{ + int i; + uint64_t pending[4], ub; + + for (i = 0; i < MAX_IRQS; i += 256) { + beat_detect_pending_interrupts(i, pending); + __asm__ ("cntlzd %0,%1":"=r"(ub): + "r"(pending[0] & beatic_irq_mask_enable[i/64+0] + & beatic_irq_mask_ack[i/64+0])); + if (ub != 64) + return i + ub + 0; + __asm__ ("cntlzd %0,%1":"=r"(ub): + "r"(pending[1] & beatic_irq_mask_enable[i/64+1] + & beatic_irq_mask_ack[i/64+1])); + if (ub != 64) + return i + ub + 64; + __asm__ ("cntlzd %0,%1":"=r"(ub): + "r"(pending[2] & beatic_irq_mask_enable[i/64+2] + & beatic_irq_mask_ack[i/64+2])); + if (ub != 64) + return i + ub + 128; + __asm__ ("cntlzd %0,%1":"=r"(ub): + "r"(pending[3] & beatic_irq_mask_enable[i/64+3] + & beatic_irq_mask_ack[i/64+3])); + if (ub != 64) + return i + ub + 192; + } + + return NO_IRQ; +} +unsigned int beatic_get_irq(void) +{ + unsigned int ret; + + ret = beatic_get_irq_plug(); + if (ret != NO_IRQ) + beatic_ack_irq(ret); + return ret; +} + +/* + */ +void __init beatic_init_IRQ(void) +{ + int i; + + memset(beatic_irq_mask_enable, 0, sizeof(beatic_irq_mask_enable)); + memset(beatic_irq_mask_ack, 255, sizeof(beatic_irq_mask_ack)); + for (i = 0; i < MAX_IRQS; i += 256) + beat_set_interrupt_mask(i, 0L, 0L, 0L, 0L); + + /* Set out get_irq function */ + ppc_md.get_irq = beatic_get_irq; + + /* Allocate an irq host */ + beatic_host = irq_alloc_host(IRQ_HOST_MAP_NOMAP, 0, + &beatic_pic_host_ops, + 0); + BUG_ON(beatic_host == NULL); + irq_set_default_host(beatic_host); +} + +#ifdef CONFIG_SMP + +/* Nullified to compile with SMP mode */ +void beatic_setup_cpu(int cpu) +{ +} + +void beatic_cause_IPI(int cpu, int mesg) +{ +} + +void beatic_request_IPIs(void) +{ +} +#endif /* CONFIG_SMP */ + +void beatic_deinit_IRQ(void) +{ + int i; + + for (i = 1; i < NR_IRQS; i++) + beat_destruct_irq_plug(i); +} diff --git a/arch/powerpc/platforms/celleb/interrupt.h b/arch/powerpc/platforms/celleb/interrupt.h new file mode 100644 index 0000000..b470fd0 --- /dev/null +++ b/arch/powerpc/platforms/celleb/interrupt.h @@ -0,0 +1,33 @@ +/* + * Celleb/Beat Interrupt controller + * + * (C) Copyright 2006 TOSHIBA CORPORATION + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#ifndef ASM_BEAT_PIC_H +#define ASM_BEAT_PIC_H +#ifdef __KERNEL__ + +extern void beatic_init_IRQ(void); +extern unsigned int beatic_get_irq(void); +extern void beatic_cause_IPI(int cpu, int mesg); +extern void beatic_request_IPIs(void); +extern void beatic_setup_cpu(int); +extern void beatic_deinit_IRQ(void); + +#endif +#endif /* ASM_BEAT_PIC_H */ diff --git a/arch/powerpc/platforms/celleb/iommu.c b/arch/powerpc/platforms/celleb/iommu.c new file mode 100644 index 0000000..f63b94c --- /dev/null +++ b/arch/powerpc/platforms/celleb/iommu.c @@ -0,0 +1,104 @@ +/* + * Support for IOMMU on Celleb platform. + * + * (C) Copyright 2006-2007 TOSHIBA CORPORATION + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#include +#include +#include +#include + +#include + +#include "beat_wrapper.h" + +#define DMA_FLAGS 0xf800000000000000UL /* r/w permitted, coherency required, + strongest order */ + +static int __init find_dma_window(u64 *io_space_id, u64 *ioid, + u64 *base, u64 *size, u64 *io_page_size) +{ + struct device_node *dn; + const unsigned long *dma_window; + + for_each_node_by_type(dn, "ioif") { + dma_window = get_property(dn, "toshiba,dma-window", NULL); + if (dma_window) { + *io_space_id = (dma_window[0] >> 32) & 0xffffffffUL; + *ioid = dma_window[0] & 0x7ffUL; + *base = dma_window[1]; + *size = dma_window[2]; + *io_page_size = 1 << dma_window[3]; + of_node_put(dn); + return 1; + } + } + return 0; +} + +static void __init celleb_init_direct_mapping(void) +{ + u64 lpar_addr, io_addr; + u64 io_space_id, ioid, dma_base, dma_size, io_page_size; + + if (!find_dma_window(&io_space_id, &ioid, &dma_base, &dma_size, + &io_page_size)) { + pr_info("No dma window found !\n"); + return; + } + + for (lpar_addr = 0; lpar_addr < dma_size; lpar_addr += io_page_size) { + io_addr = lpar_addr + dma_base; + (void)beat_put_iopte(io_space_id, io_addr, lpar_addr, + ioid, DMA_FLAGS); + } + + dma_direct_offset = dma_base; +} + +static int celleb_of_bus_notify(struct notifier_block *nb, + unsigned long action, void *data) +{ + struct device *dev = data; + + /* We are only intereted in device addition */ + if (action != BUS_NOTIFY_ADD_DEVICE) + return 0; + + dev->archdata.dma_ops = pci_dma_ops; + + return 0; +} + +static struct notifier_block celleb_of_bus_notifier = { + .notifier_call = celleb_of_bus_notify +}; + +static int __init celleb_init_iommu(void) +{ + if (!machine_is(celleb)) + return -ENODEV; + + celleb_init_direct_mapping(); + pci_dma_ops = &dma_direct_ops; + bus_register_notifier(&of_platform_bus_type, &celleb_of_bus_notifier); + + return 0; +} + +arch_initcall(celleb_init_iommu); diff --git a/arch/powerpc/platforms/celleb/pci.c b/arch/powerpc/platforms/celleb/pci.c new file mode 100644 index 0000000..98de836 --- /dev/null +++ b/arch/powerpc/platforms/celleb/pci.c @@ -0,0 +1,481 @@ +/* + * Support for PCI on Celleb platform. + * + * (C) Copyright 2006-2007 TOSHIBA CORPORATION + * + * This code is based on arch/powerpc/kernel/rtas_pci.c: + * Copyright (C) 2001 Dave Engebretsen, IBM Corporation + * Copyright (C) 2003 Anton Blanchard , IBM + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#undef DEBUG + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include "pci.h" +#include "interrupt.h" + +#define MAX_PCI_DEVICES 32 +#define MAX_PCI_FUNCTIONS 8 +#define MAX_PCI_BASE_ADDRS 3 /* use 64 bit address */ + +/* definition for fake pci configuration area for GbE, .... ,and etc. */ + +struct celleb_pci_resource { + struct resource r[MAX_PCI_BASE_ADDRS]; +}; + +struct celleb_pci_private { + unsigned char *fake_config[MAX_PCI_DEVICES][MAX_PCI_FUNCTIONS]; + struct celleb_pci_resource *res[MAX_PCI_DEVICES][MAX_PCI_FUNCTIONS]; +}; + +static inline u8 celleb_fake_config_readb(void *addr) +{ + u8 *p = addr; + return *p; +} + +static inline u16 celleb_fake_config_readw(void *addr) +{ + __le16 *p = addr; + return le16_to_cpu(*p); +} + +static inline u32 celleb_fake_config_readl(void *addr) +{ + __le32 *p = addr; + return le32_to_cpu(*p); +} + +static inline void celleb_fake_config_writeb(u32 val, void *addr) +{ + u8 *p = addr; + *p = val; +} + +static inline void celleb_fake_config_writew(u32 val, void *addr) +{ + __le16 val16; + __le16 *p = addr; + val16 = cpu_to_le16(val); + *p = val16; +} + +static inline void celleb_fake_config_writel(u32 val, void *addr) +{ + __le32 val32; + __le32 *p = addr; + val32 = cpu_to_le32(val); + *p = val32; +} + +static unsigned char *get_fake_config_start(struct pci_controller *hose, + int devno, int fn) +{ + struct celleb_pci_private *private = hose->private_data; + + if (private == NULL) + return NULL; + + return private->fake_config[devno][fn]; +} + +static struct celleb_pci_resource *get_resource_start( + struct pci_controller *hose, + int devno, int fn) +{ + struct celleb_pci_private *private = hose->private_data; + + if (private == NULL) + return NULL; + + return private->res[devno][fn]; +} + + +static void celleb_config_read_fake(unsigned char *config, int where, + int size, u32 *val) +{ + char *p = config + where; + + switch (size) { + case 1: + *val = celleb_fake_config_readb(p); + break; + case 2: + *val = celleb_fake_config_readw(p); + break; + case 4: + *val = celleb_fake_config_readl(p); + break; + } + + return; +} + +static void celleb_config_write_fake(unsigned char *config, int where, + int size, u32 val) +{ + char *p = config + where; + + switch (size) { + case 1: + celleb_fake_config_writeb(val, p); + break; + case 2: + celleb_fake_config_writew(val, p); + break; + case 4: + celleb_fake_config_writel(val, p); + break; + } + return; +} + +static int celleb_fake_pci_read_config(struct pci_bus *bus, + unsigned int devfn, int where, int size, u32 *val) +{ + char *config; + struct device_node *node; + struct pci_controller *hose; + unsigned int devno = devfn >> 3; + unsigned int fn = devfn & 0x7; + + /* allignment check */ + BUG_ON(where % size); + + pr_debug(" fake read: bus=0x%x, ", bus->number); + node = (struct device_node *)bus->sysdata; + hose = pci_find_hose_for_OF_device(node); + config = get_fake_config_start(hose, devno, fn); + + pr_debug("devno=0x%x, where=0x%x, size=0x%x, ", devno, where, size); + if (!config) { + pr_debug("failed\n"); + return PCIBIOS_DEVICE_NOT_FOUND; + } + + celleb_config_read_fake(config, where, size, val); + pr_debug("val=0x%x\n", *val); + + return PCIBIOS_SUCCESSFUL; +} + + +static int celleb_fake_pci_write_config(struct pci_bus *bus, + unsigned int devfn, int where, int size, u32 val) +{ + char *config; + struct device_node *node; + struct pci_controller *hose; + struct celleb_pci_resource *res; + unsigned int devno = devfn >> 3; + unsigned int fn = devfn & 0x7; + + /* allignment check */ + BUG_ON(where % size); + + node = (struct device_node *)bus->sysdata; + hose = pci_find_hose_for_OF_device(node); + config = get_fake_config_start(hose, devno, fn); + + if (!config) + return PCIBIOS_DEVICE_NOT_FOUND; + + if (val == ~0) { + int i = (where - PCI_BASE_ADDRESS_0) >> 3; + + switch (where) { + case PCI_BASE_ADDRESS_0: + case PCI_BASE_ADDRESS_2: + if (size != 4) + return PCIBIOS_DEVICE_NOT_FOUND; + res = get_resource_start(hose, devno, fn); + if (!res) + return PCIBIOS_DEVICE_NOT_FOUND; + celleb_config_write_fake(config, where, size, + (res->r[i].end - res->r[i].start)); + return PCIBIOS_SUCCESSFUL; + case PCI_BASE_ADDRESS_1: + case PCI_BASE_ADDRESS_3: + case PCI_BASE_ADDRESS_4: + case PCI_BASE_ADDRESS_5: + break; + default: + break; + } + } + + celleb_config_write_fake(config, where, size, val); + pr_debug(" fake write: where=%x, size=%d, val=%x\n", + where, size, val); + + return PCIBIOS_SUCCESSFUL; +} + +static struct pci_ops celleb_fake_pci_ops = { + celleb_fake_pci_read_config, + celleb_fake_pci_write_config +}; + +static inline void celleb_setup_pci_base_addrs(struct pci_controller *hose, + unsigned int devno, unsigned int fn, + unsigned int num_base_addr) +{ + u32 val; + unsigned char *config; + struct celleb_pci_resource *res; + + config = get_fake_config_start(hose, devno, fn); + res = get_resource_start(hose, devno, fn); + + if (!config || !res) + return; + + switch (num_base_addr) { + case 3: + val = (res->r[2].start & 0xfffffff0) + | PCI_BASE_ADDRESS_MEM_TYPE_64; + celleb_config_write_fake(config, PCI_BASE_ADDRESS_4, 4, val); + val = res->r[2].start >> 32; + celleb_config_write_fake(config, PCI_BASE_ADDRESS_5, 4, val); + /* FALLTHROUGH */ + case 2: + val = (res->r[1].start & 0xfffffff0) + | PCI_BASE_ADDRESS_MEM_TYPE_64; + celleb_config_write_fake(config, PCI_BASE_ADDRESS_2, 4, val); + val = res->r[1].start >> 32; + celleb_config_write_fake(config, PCI_BASE_ADDRESS_3, 4, val); + /* FALLTHROUGH */ + case 1: + val = (res->r[0].start & 0xfffffff0) + | PCI_BASE_ADDRESS_MEM_TYPE_64; + celleb_config_write_fake(config, PCI_BASE_ADDRESS_0, 4, val); + val = res->r[0].start >> 32; + celleb_config_write_fake(config, PCI_BASE_ADDRESS_1, 4, val); + break; + } + + val = PCI_COMMAND_IO | PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER; + celleb_config_write_fake(config, PCI_COMMAND, 2, val); +} + +static int __devinit celleb_setup_fake_pci_device(struct device_node *node, + struct pci_controller *hose) +{ + unsigned int rlen; + int num_base_addr = 0; + u32 val; + const u32 *wi0, *wi1, *wi2, *wi3, *wi4; + unsigned int devno, fn; + struct celleb_pci_private *private = hose->private_data; + unsigned char **config = NULL; + struct celleb_pci_resource **res = NULL; + const char *name; + const unsigned long *li; + int size, result; + + if (private == NULL) { + printk(KERN_ERR "PCI: " + "memory space for pci controller is not assigned\n"); + goto error; + } + + name = get_property(node, "model", &rlen); + if (!name) { + printk(KERN_ERR "PCI: model property not found.\n"); + goto error; + } + + wi4 = get_property(node, "reg", &rlen); + if (wi4 == NULL) + goto error; + + devno = ((wi4[0] >> 8) & 0xff) >> 3; + fn = (wi4[0] >> 8) & 0x7; + + pr_debug("PCI: celleb_setup_fake_pci() %s devno=%x fn=%x\n", name, + devno, fn); + + size = 256; + config = &private->fake_config[devno][fn]; + if (mem_init_done) + *config = kzalloc(size, GFP_KERNEL); + else + *config = alloc_bootmem(size); + if (*config == NULL) { + printk(KERN_ERR "PCI: " + "not enough memory for fake configuration space\n"); + goto error; + } + pr_debug("PCI: fake config area assigned 0x%016lx\n", + (unsigned long)*config); + + size = sizeof(struct celleb_pci_resource); + res = &private->res[devno][fn]; + if (mem_init_done) + *res = kzalloc(size, GFP_KERNEL); + else + *res = alloc_bootmem(size); + if (*res == NULL) { + printk(KERN_ERR + "PCI: not enough memory for resource data space\n"); + goto error; + } + pr_debug("PCI: res assigned 0x%016lx\n", (unsigned long)*res); + + wi0 = get_property(node, "device-id", NULL); + wi1 = get_property(node, "vendor-id", NULL); + wi2 = get_property(node, "class-code", NULL); + wi3 = get_property(node, "revision-id", NULL); + + celleb_config_write_fake(*config, PCI_DEVICE_ID, 2, wi0[0] & 0xffff); + celleb_config_write_fake(*config, PCI_VENDOR_ID, 2, wi1[0] & 0xffff); + pr_debug("class-code = 0x%08x\n", wi2[0]); + + celleb_config_write_fake(*config, PCI_CLASS_PROG, 1, wi2[0] & 0xff); + celleb_config_write_fake(*config, PCI_CLASS_DEVICE, 2, + (wi2[0] >> 8) & 0xffff); + celleb_config_write_fake(*config, PCI_REVISION_ID, 1, wi3[0]); + + while (num_base_addr < MAX_PCI_BASE_ADDRS) { + result = of_address_to_resource(node, + num_base_addr, &(*res)->r[num_base_addr]); + if (result) + break; + num_base_addr++; + } + + celleb_setup_pci_base_addrs(hose, devno, fn, num_base_addr); + + li = get_property(node, "interrupts", &rlen); + val = li[0]; + celleb_config_write_fake(*config, PCI_INTERRUPT_PIN, 1, 1); + celleb_config_write_fake(*config, PCI_INTERRUPT_LINE, 1, val); + +#ifdef DEBUG + pr_debug("PCI: %s irq=%ld\n", name, li[0]); + for (i = 0; i < 6; i++) { + celleb_config_read_fake(*config, + PCI_BASE_ADDRESS_0 + 0x4 * i, 4, + &val); + pr_debug("PCI: %s fn=%d base_address_%d=0x%x\n", + name, fn, i, val); + } +#endif + + celleb_config_write_fake(*config, PCI_HEADER_TYPE, 1, + PCI_HEADER_TYPE_NORMAL); + + return 0; + +error: + if (mem_init_done) { + if (config && *config) + kfree(*config); + if (res && *res) + kfree(*res); + + } else { + if (config && *config) { + size = 256; + free_bootmem((unsigned long)(*config), size); + } + if (res && *res) { + size = sizeof(struct celleb_pci_resource); + free_bootmem((unsigned long)(*res), size); + } + } + + return 1; +} + +static int __devinit phb_set_bus_ranges(struct device_node *dev, + struct pci_controller *phb) +{ + const int *bus_range; + unsigned int len; + + bus_range = get_property(dev, "bus-range", &len); + if (bus_range == NULL || len < 2 * sizeof(int)) + return 1; + + phb->first_busno = bus_range[0]; + phb->last_busno = bus_range[1]; + + return 0; +} + +static void __devinit celleb_alloc_private_mem(struct pci_controller *hose) +{ + if (mem_init_done) + hose->private_data = + kzalloc(sizeof(struct celleb_pci_private), GFP_KERNEL); + else + hose->private_data = + alloc_bootmem(sizeof(struct celleb_pci_private)); +} + +int __devinit celleb_setup_phb(struct pci_controller *phb) +{ + const char *name; + struct device_node *dev = phb->arch_data; + struct device_node *node; + unsigned int rlen; + + name = get_property(dev, "name", &rlen); + if (!name) + return 1; + + pr_debug("PCI: celleb_setup_phb() %s\n", name); + phb_set_bus_ranges(dev, phb); + + if (strcmp(name, "epci") == 0) { + phb->ops = &celleb_epci_ops; + return celleb_setup_epci(dev, phb); + + } else if (strcmp(name, "pci-pseudo") == 0) { + phb->ops = &celleb_fake_pci_ops; + celleb_alloc_private_mem(phb); + for (node = of_get_next_child(dev, NULL); + node != NULL; node = of_get_next_child(dev, node)) + celleb_setup_fake_pci_device(node, phb); + + } else + return 1; + + return 0; +} + +int celleb_pci_probe_mode(struct pci_bus *bus) +{ + return PCI_PROBE_DEVTREE; +} diff --git a/arch/powerpc/platforms/celleb/pci.h b/arch/powerpc/platforms/celleb/pci.h new file mode 100644 index 0000000..5340e34 --- /dev/null +++ b/arch/powerpc/platforms/celleb/pci.h @@ -0,0 +1,35 @@ +/* + * pci prototypes for Celleb platform + * + * (C) Copyright 2006-2007 TOSHIBA CORPORATION + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#ifndef _CELLEB_PCI_H +#define _CELLEB_PCI_H + +#include + +#include +#include + +extern int celleb_setup_phb(struct pci_controller *); +extern int celleb_pci_probe_mode(struct pci_bus *); + +extern struct pci_ops celleb_epci_ops; +extern int celleb_setup_epci(struct device_node *, struct pci_controller *); + +#endif /* _CELLEB_PCI_H */ diff --git a/arch/powerpc/platforms/celleb/scc.h b/arch/powerpc/platforms/celleb/scc.h new file mode 100644 index 0000000..e9ce8a7 --- /dev/null +++ b/arch/powerpc/platforms/celleb/scc.h @@ -0,0 +1,145 @@ +/* + * SCC (Super Companion Chip) definitions + * + * (C) Copyright 2004-2006 TOSHIBA CORPORATION + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#ifndef _CELLEB_SCC_H +#define _CELLEB_SCC_H + +#define PCI_VENDOR_ID_TOSHIBA_2 0x102f +#define PCI_DEVICE_ID_TOSHIBA_SCC_PCIEXC_BRIDGE 0x01b0 +#define PCI_DEVICE_ID_TOSHIBA_SCC_EPCI_BRIDGE 0x01b1 +#define PCI_DEVICE_ID_TOSHIBA_SCC_BRIDGE 0x01b2 +#define PCI_DEVICE_ID_TOSHIBA_SCC_GBE 0x01b3 +#define PCI_DEVICE_ID_TOSHIBA_SCC_ATA 0x01b4 +#define PCI_DEVICE_ID_TOSHIBA_SCC_USB2 0x01b5 +#define PCI_DEVICE_ID_TOSHIBA_SCC_USB 0x01b6 +#define PCI_DEVICE_ID_TOSHIBA_SCC_ENCDEC 0x01b7 + +#define SCC_EPCI_REG 0x0000d000 + +/* EPCI registers */ +#define SCC_EPCI_CNF10_REG 0x010 +#define SCC_EPCI_CNF14_REG 0x014 +#define SCC_EPCI_CNF18_REG 0x018 +#define SCC_EPCI_PVBAT 0x100 +#define SCC_EPCI_VPMBAT 0x104 +#define SCC_EPCI_VPIBAT 0x108 +#define SCC_EPCI_VCSR 0x110 +#define SCC_EPCI_VIENAB 0x114 +#define SCC_EPCI_VISTAT 0x118 +#define SCC_EPCI_VRDCOUNT 0x124 +#define SCC_EPCI_BAM0 0x12c +#define SCC_EPCI_BAM1 0x134 +#define SCC_EPCI_BAM2 0x13c +#define SCC_EPCI_IADR 0x164 +#define SCC_EPCI_CLKRST 0x800 +#define SCC_EPCI_INTSET 0x804 +#define SCC_EPCI_STATUS 0x808 +#define SCC_EPCI_ABTSET 0x80c +#define SCC_EPCI_WATRP 0x810 +#define SCC_EPCI_DUMMYRADR 0x814 +#define SCC_EPCI_SWRESP 0x818 +#define SCC_EPCI_CNTOPT 0x81c +#define SCC_EPCI_ECMODE 0xf00 +#define SCC_EPCI_IOM_AC_NUM 5 +#define SCC_EPCI_IOM_ACTE(n) (0xf10 + (n) * 4) +#define SCC_EPCI_IOT_AC_NUM 4 +#define SCC_EPCI_IOT_ACTE(n) (0xf30 + (n) * 4) +#define SCC_EPCI_MAEA 0xf50 +#define SCC_EPCI_MAEC 0xf54 +#define SCC_EPCI_CKCTRL 0xff0 + +/* bits for SCC_EPCI_VCSR */ +#define SCC_EPCI_VCSR_FRE 0x00020000 +#define SCC_EPCI_VCSR_FWE 0x00010000 +#define SCC_EPCI_VCSR_DR 0x00000400 +#define SCC_EPCI_VCSR_SR 0x00000008 +#define SCC_EPCI_VCSR_AT 0x00000004 + +/* bits for SCC_EPCI_VIENAB/SCC_EPCI_VISTAT */ +#define SCC_EPCI_VISTAT_PMPE 0x00000008 +#define SCC_EPCI_VISTAT_PMFE 0x00000004 +#define SCC_EPCI_VISTAT_PRA 0x00000002 +#define SCC_EPCI_VISTAT_PRD 0x00000001 +#define SCC_EPCI_VISTAT_ALL 0x0000000f + +#define SCC_EPCI_VIENAB_PMPEE 0x00000008 +#define SCC_EPCI_VIENAB_PMFEE 0x00000004 +#define SCC_EPCI_VIENAB_PRA 0x00000002 +#define SCC_EPCI_VIENAB_PRD 0x00000001 +#define SCC_EPCI_VIENAB_ALL 0x0000000f + +/* bits for SCC_EPCI_CLKRST */ +#define SCC_EPCI_CLKRST_CKS_MASK 0x00030000 +#define SCC_EPCI_CLKRST_CKS_2 0x00000000 +#define SCC_EPCI_CLKRST_CKS_4 0x00010000 +#define SCC_EPCI_CLKRST_CKS_8 0x00020000 +#define SCC_EPCI_CLKRST_PCICRST 0x00000400 +#define SCC_EPCI_CLKRST_BC 0x00000200 +#define SCC_EPCI_CLKRST_PCIRST 0x00000100 +#define SCC_EPCI_CLKRST_PCKEN 0x00000001 + +/* bits for SCC_EPCI_INTSET/SCC_EPCI_STATUS */ +#define SCC_EPCI_INT_2M 0x01000000 +#define SCC_EPCI_INT_RERR 0x00200000 +#define SCC_EPCI_INT_SERR 0x00100000 +#define SCC_EPCI_INT_PRTER 0x00080000 +#define SCC_EPCI_INT_SER 0x00040000 +#define SCC_EPCI_INT_PER 0x00020000 +#define SCC_EPCI_INT_PAI 0x00010000 +#define SCC_EPCI_INT_1M 0x00000100 +#define SCC_EPCI_INT_PME 0x00000010 +#define SCC_EPCI_INT_INTD 0x00000008 +#define SCC_EPCI_INT_INTC 0x00000004 +#define SCC_EPCI_INT_INTB 0x00000002 +#define SCC_EPCI_INT_INTA 0x00000001 +#define SCC_EPCI_INT_DEVINT 0x0000000f +#define SCC_EPCI_INT_ALL 0x003f001f +#define SCC_EPCI_INT_ALLERR 0x003f0000 + +/* bits for SCC_EPCI_CKCTRL */ +#define SCC_EPCI_CKCTRL_CRST0 0x00010000 +#define SCC_EPCI_CKCTRL_CRST1 0x00020000 +#define SCC_EPCI_CKCTRL_OCLKEN 0x00000100 +#define SCC_EPCI_CKCTRL_LCLKEN 0x00000001 + +#define SCC_EPCI_IDSEL_AD_TO_SLOT(ad) ((ad) - 10) +#define SCC_EPCI_MAX_DEVNU SCC_EPCI_IDSEL_AD_TO_SLOT(32) + +/* bits for SCC_EPCI_CNTOPT */ +#define SCC_EPCI_CNTOPT_O2PMB 0x00000002 + +/* UHC registers */ +#define SCC_UHC_CKRCTRL 0xff0 +#define SCC_UHC_ECMODE 0xf00 + +/* bits for SCC_UHC_CKRCTRL */ +#define SCC_UHC_F48MCKLEN 0x00000001 +#define SCC_UHC_P_SUSPEND 0x00000002 +#define SCC_UHC_PHY_SUSPEND_SEL 0x00000004 +#define SCC_UHC_HCLKEN 0x00000100 +#define SCC_UHC_USBEN 0x00010000 +#define SCC_UHC_USBCEN 0x00020000 +#define SCC_UHC_PHYEN 0x00040000 + +/* bits for SCC_UHC_ECMODE */ +#define SCC_UHC_ECMODE_BY_BYTE 0x00000555 +#define SCC_UHC_ECMODE_BY_WORD 0x00000aaa + +#endif /* _CELLEB_SCC_H */ diff --git a/arch/powerpc/platforms/celleb/scc_epci.c b/arch/powerpc/platforms/celleb/scc_epci.c new file mode 100644 index 0000000..c11b39c --- /dev/null +++ b/arch/powerpc/platforms/celleb/scc_epci.c @@ -0,0 +1,409 @@ +/* + * Support for SCC external PCI + * + * (C) Copyright 2004-2007 TOSHIBA CORPORATION + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#undef DEBUG + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include "scc.h" +#include "pci.h" +#include "interrupt.h" + +#define MAX_PCI_DEVICES 32 +#define MAX_PCI_FUNCTIONS 8 + +#define iob() __asm__ __volatile__("eieio; sync":::"memory") + + +#if 0 /* test code for epci dummy read */ +static void celleb_epci_dummy_read(struct pci_dev *dev) +{ + void __iomem *epci_base; + struct device_node *node; + struct pci_controller *hose; + u32 val; + + node = (struct device_node *)dev->bus->sysdata; + hose = pci_find_hose_for_OF_device(node); + + if (!hose) + return; + + epci_base = hose->cfg_addr; + + val = in_be32(epci_base + SCC_EPCI_WATRP); + iosync(); + + return; +} +#endif + +static inline void clear_and_disable_master_abort_interrupt( + struct pci_controller *hose) +{ + void __iomem *addr; + addr = hose->cfg_addr + PCI_COMMAND; + out_be32(addr, in_be32(addr) | (PCI_STATUS_REC_MASTER_ABORT << 16)); +} + +static int celleb_epci_check_abort(struct pci_controller *hose, + void __iomem *addr) +{ + void __iomem *reg, *epci_base; + u32 val; + + iob(); + epci_base = hose->cfg_addr; + + reg = epci_base + PCI_COMMAND; + val = in_be32(reg); + + if (val & (PCI_STATUS_REC_MASTER_ABORT << 16)) { + out_be32(reg, + (val & 0xffff) | (PCI_STATUS_REC_MASTER_ABORT << 16)); + + /* clear PCI Controller error, FRE, PMFE */ + reg = epci_base + SCC_EPCI_STATUS; + out_be32(reg, SCC_EPCI_INT_PAI); + + reg = epci_base + SCC_EPCI_VCSR; + val = in_be32(reg) & 0xffff; + val |= SCC_EPCI_VCSR_FRE; + out_be32(reg, val); + + reg = epci_base + SCC_EPCI_VISTAT; + out_be32(reg, SCC_EPCI_VISTAT_PMFE); + return PCIBIOS_DEVICE_NOT_FOUND; + } + + return PCIBIOS_SUCCESSFUL; +} + +static void __iomem *celleb_epci_make_config_addr(struct pci_controller *hose, + unsigned int devfn, int where) +{ + void __iomem *addr; + struct pci_bus *bus = hose->bus; + + if (bus->self) + addr = hose->cfg_data + + (((bus->number & 0xff) << 16) + | ((devfn & 0xff) << 8) + | (where & 0xff) + | 0x01000000); + else + addr = hose->cfg_data + + (((devfn & 0xff) << 8) | (where & 0xff)); + + pr_debug("EPCI: config_addr = 0x%p\n", addr); + + return addr; +} + +static int celleb_epci_read_config(struct pci_bus *bus, + unsigned int devfn, int where, int size, u32 * val) +{ + void __iomem *addr; + struct device_node *node; + struct pci_controller *hose; + + /* allignment check */ + BUG_ON(where % size); + + node = (struct device_node *)bus->sysdata; + hose = pci_find_hose_for_OF_device(node); + + if (!hose->cfg_data) + return PCIBIOS_DEVICE_NOT_FOUND; + + if (bus->number == hose->first_busno && devfn == 0) { + /* EPCI controller self */ + + addr = hose->cfg_addr + where; + + switch (size) { + case 1: + *val = in_8(addr); + break; + case 2: + *val = in_be16(addr); + break; + case 4: + *val = in_be32(addr); + break; + default: + return PCIBIOS_DEVICE_NOT_FOUND; + } + + } else { + + clear_and_disable_master_abort_interrupt(hose); + addr = celleb_epci_make_config_addr(hose, devfn, where); + + switch (size) { + case 1: + *val = in_8(addr); + break; + case 2: + *val = in_le16(addr); + break; + case 4: + *val = in_le32(addr); + break; + default: + return PCIBIOS_DEVICE_NOT_FOUND; + } + } + + pr_debug("EPCI: " + "addr=0x%lx, devfn=0x%x, where=0x%x, size=0x%x, val=0x%x\n", + addr, devfn, where, size, *val); + + return celleb_epci_check_abort(hose, NULL); +} + +static int celleb_epci_write_config(struct pci_bus *bus, + unsigned int devfn, int where, int size, u32 val) +{ + void __iomem *addr; + struct device_node *node; + struct pci_controller *hose; + + /* allignment check */ + BUG_ON(where % size); + + node = (struct device_node *)bus->sysdata; + hose = pci_find_hose_for_OF_device(node); + + if (!hose->cfg_data) + return PCIBIOS_DEVICE_NOT_FOUND; + + if (bus->number == hose->first_busno && devfn == 0) { + /* EPCI controller self */ + + addr = hose->cfg_addr + where; + + switch (size) { + case 1: + out_8(addr, val); + break; + case 2: + out_be16(addr, val); + break; + case 4: + out_be32(addr, val); + break; + default: + return PCIBIOS_DEVICE_NOT_FOUND; + } + + } else { + + clear_and_disable_master_abort_interrupt(hose); + addr = celleb_epci_make_config_addr(hose, devfn, where); + + switch (size) { + case 1: + out_8(addr, val); + break; + case 2: + out_le16(addr, val); + break; + case 4: + out_le32(addr, val); + break; + default: + return PCIBIOS_DEVICE_NOT_FOUND; + } + } + + return celleb_epci_check_abort(hose, addr); +} + +struct pci_ops celleb_epci_ops = { + celleb_epci_read_config, + celleb_epci_write_config, +}; + +/* to be moved in FW */ +static int __devinit celleb_epci_init(struct pci_controller *hose) +{ + u32 val; + void __iomem *reg, *epci_base; + int hwres = 0; + + epci_base = hose->cfg_addr; + + /* PCI core reset(Internal bus and PCI clock) */ + reg = epci_base + SCC_EPCI_CKCTRL; + val = in_be32(reg); + if (val == 0x00030101) + hwres = 1; + else { + val &= ~(SCC_EPCI_CKCTRL_CRST0 | SCC_EPCI_CKCTRL_CRST1); + out_be32(reg, val); + + /* set PCI core clock */ + val = in_be32(reg); + val |= (SCC_EPCI_CKCTRL_OCLKEN | SCC_EPCI_CKCTRL_LCLKEN); + out_be32(reg, val); + + /* release PCI core reset (internal bus) */ + val = in_be32(reg); + val |= SCC_EPCI_CKCTRL_CRST0; + out_be32(reg, val); + + /* set PCI clock select */ + reg = epci_base + SCC_EPCI_CLKRST; + val = in_be32(reg); + val &= ~SCC_EPCI_CLKRST_CKS_MASK; + val |= SCC_EPCI_CLKRST_CKS_2; + out_be32(reg, val); + + /* set arbiter */ + reg = epci_base + SCC_EPCI_ABTSET; + out_be32(reg, 0x0f1f001f); /* temporary value */ + + /* buffer on */ + reg = epci_base + SCC_EPCI_CLKRST; + val = in_be32(reg); + val |= SCC_EPCI_CLKRST_BC; + out_be32(reg, val); + + /* PCI clock enable */ + val = in_be32(reg); + val |= SCC_EPCI_CLKRST_PCKEN; + out_be32(reg, val); + + /* release PCI core reset (all) */ + reg = epci_base + SCC_EPCI_CKCTRL; + val = in_be32(reg); + val |= (SCC_EPCI_CKCTRL_CRST0 | SCC_EPCI_CKCTRL_CRST1); + out_be32(reg, val); + + /* set base translation registers. (already set by Beat) */ + + /* set base address masks. (already set by Beat) */ + } + + /* release interrupt masks and clear all interrupts */ + reg = epci_base + SCC_EPCI_INTSET; + out_be32(reg, 0x013f011f); /* all interrupts enable */ + reg = epci_base + SCC_EPCI_VIENAB; + val = SCC_EPCI_VIENAB_PMPEE | SCC_EPCI_VIENAB_PMFEE; + out_be32(reg, val); + reg = epci_base + SCC_EPCI_STATUS; + out_be32(reg, 0xffffffff); + reg = epci_base + SCC_EPCI_VISTAT; + out_be32(reg, 0xffffffff); + + /* disable PCI->IB address translation */ + reg = epci_base + SCC_EPCI_VCSR; + val = in_be32(reg); + val &= ~(SCC_EPCI_VCSR_DR | SCC_EPCI_VCSR_AT); + out_be32(reg, val); + + /* set base addresses. (no need to set?) */ + + /* memory space, bus master enable */ + reg = epci_base + PCI_COMMAND; + val = PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER; + out_be32(reg, val); + + /* endian mode setup */ + reg = epci_base + SCC_EPCI_ECMODE; + val = 0x00550155; + out_be32(reg, val); + + /* set control option */ + reg = epci_base + SCC_EPCI_CNTOPT; + val = in_be32(reg); + val |= SCC_EPCI_CNTOPT_O2PMB; + out_be32(reg, val); + + /* XXX: temporay: set registers for address conversion setup */ + reg = epci_base + SCC_EPCI_CNF10_REG; + out_be32(reg, 0x80000008); + reg = epci_base + SCC_EPCI_CNF14_REG; + out_be32(reg, 0x40000008); + + reg = epci_base + SCC_EPCI_BAM0; + out_be32(reg, 0x80000000); + reg = epci_base + SCC_EPCI_BAM1; + out_be32(reg, 0xe0000000); + + reg = epci_base + SCC_EPCI_PVBAT; + out_be32(reg, 0x80000000); + + if (!hwres) { + /* release external PCI reset */ + reg = epci_base + SCC_EPCI_CLKRST; + val = in_be32(reg); + val |= SCC_EPCI_CLKRST_PCIRST; + out_be32(reg, val); + } + + return 0; +} + +int __devinit celleb_setup_epci(struct device_node *node, + struct pci_controller *hose) +{ + struct resource r; + + pr_debug("PCI: celleb_setup_epci()\n"); + + if (of_address_to_resource(node, 0, &r)) + goto error; + hose->cfg_addr = ioremap(r.start, (r.end - r.start + 1)); + if (!hose->cfg_addr) + goto error; + pr_debug("EPCI: cfg_addr map 0x%016lx->0x%016lx + 0x%016lx\n", + r.start, (unsigned long)hose->cfg_addr, + (r.end - r.start + 1)); + + if (of_address_to_resource(node, 2, &r)) + goto error; + hose->cfg_data = ioremap(r.start, (r.end - r.start + 1)); + if (!hose->cfg_data) + goto error; + pr_debug("EPCI: cfg_data map 0x%016lx->0x%016lx + 0x%016lx\n", + r.start, (unsigned long)hose->cfg_data, + (r.end - r.start + 1)); + + celleb_epci_init(hose); + + return 0; + +error: + return 1; +} diff --git a/arch/powerpc/platforms/celleb/scc_sio.c b/arch/powerpc/platforms/celleb/scc_sio.c new file mode 100644 index 0000000..bcd25f5 --- /dev/null +++ b/arch/powerpc/platforms/celleb/scc_sio.c @@ -0,0 +1,101 @@ +/* + * setup serial port in SCC + * + * (C) Copyright 2006 TOSHIBA CORPORATION + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#include +#include +#include +#include + +#include +#include + +/* sio irq0=0xb00010022 irq0=0xb00010023 irq2=0xb00010024 + mmio=0xfff000-0x1000,0xff2000-0x1000 */ +static int txx9_serial_bitmap = 0; + +static struct { + uint32_t offset; + uint32_t index; +} txx9_scc_tab[3] = { + { 0x300, 0 }, /* 0xFFF300 */ + { 0x400, 0 }, /* 0xFFF400 */ + { 0x800, 1 } /* 0xFF2800 */ +}; + +static int txx9_serial_init(void) +{ + extern int early_serial_txx9_setup(struct uart_port *port); + struct device_node *node; + int i; + struct uart_port req; + struct of_irq irq; + struct resource res; + + node = of_find_node_by_path("/ioif1/sio"); + if (!node) + return 0; + + for(i = 0; i < sizeof(txx9_scc_tab)/sizeof(txx9_scc_tab[0]); i++) { + if (!(txx9_serial_bitmap & (1< UHC_RESET_WAIT_MAX) { + printk(KERN_ERR "Failed to disable UHC reset %x\n", + in_be32(uhc_clkctrl)); + break; + } + } + + /* Endian Conversion Mode for Master ALL area */ + out_be32(uhc_ecmode, SCC_UHC_ECMODE_BY_BYTE); + + iounmap(uhc_base); +} + +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_TOSHIBA_2, + PCI_DEVICE_ID_TOSHIBA_SCC_USB, enable_scc_uhc); diff --git a/arch/powerpc/platforms/celleb/setup.c b/arch/powerpc/platforms/celleb/setup.c new file mode 100644 index 0000000..1de63ac --- /dev/null +++ b/arch/powerpc/platforms/celleb/setup.c @@ -0,0 +1,191 @@ +/* + * Celleb setup code + * + * (C) Copyright 2006-2007 TOSHIBA CORPORATION + * + * This code is based on arch/powerpc/platforms/cell/setup.c: + * Copyright (C) 1995 Linus Torvalds + * Adapted from 'alpha' version by Gary Thomas + * Modified by Cort Dougan (cort@cs.nmt.edu) + * Modified by PPC64 Team, IBM Corp + * Modified by Cell Team, IBM Deutschland Entwicklung GmbH + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#undef DEBUG + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "interrupt.h" +#include "beat_wrapper.h" +#include "beat.h" +#include "pci.h" + +static char celleb_machine_type[128] = "Celleb"; + +static void celleb_show_cpuinfo(struct seq_file *m) +{ + struct device_node *root; + const char *model = ""; + + root = of_find_node_by_path("/"); + if (root) + model = get_property(root, "model", NULL); + /* using "CHRP" is to trick anaconda into installing FCx into Celleb */ + seq_printf(m, "machine\t\t: %s %s\n", celleb_machine_type, model); + of_node_put(root); +} + +static int celleb_machine_type_hack(char *ptr) +{ + strncpy(celleb_machine_type, ptr, sizeof(celleb_machine_type)); + celleb_machine_type[sizeof(celleb_machine_type)-1] = 0; + return 0; +} + +__setup("celleb_machine_type_hack", celleb_machine_type_hack); + +static void celleb_progress(char *s, unsigned short hex) +{ + printk("*** %04x : %s\n", hex, s ? s : ""); +} + +static void __init celleb_setup_arch(void) +{ +#ifdef CONFIG_SPU_BASE + spu_priv1_ops = &spu_priv1_beat_ops; + spu_management_ops = &spu_management_of_ops; +#endif + +#ifdef CONFIG_SMP + smp_init_celleb(); +#endif + + /* init to some ~sane value until calibrate_delay() runs */ + loops_per_jiffy = 50000000; + + if (ROOT_DEV == 0) { + printk("No ramdisk, default root is /dev/hda2\n"); + ROOT_DEV = Root_HDA2; + } + +#ifdef CONFIG_DUMMY_CONSOLE + conswitchp = &dummy_con; +#endif +} + +static void beat_power_save(void) +{ + beat_pause(0); +} + +static int __init celleb_probe(void) +{ + unsigned long root = of_get_flat_dt_root(); + + if (!of_flat_dt_is_compatible(root, "Beat")) + return 0; + + powerpc_firmware_features |= FW_FEATURE_CELLEB_POSSIBLE; + hpte_init_beat(); + return 1; +} + +/* + * Cell has no legacy IO; anything calling this function has to + * fail or bad things will happen + */ +static int celleb_check_legacy_ioport(unsigned int baseport) +{ + return -ENODEV; +} + +static void celleb_kexec_cpu_down(int crash, int secondary) +{ + beatic_deinit_IRQ(); +} + +static struct of_device_id celleb_bus_ids[] = { + { .type = "scc", }, + { .type = "ioif", }, /* old style */ + {}, +}; + +static int __init celleb_publish_devices(void) +{ + if (!machine_is(celleb)) + return 0; + + /* Publish OF platform devices for southbridge IOs */ + of_platform_bus_probe(NULL, celleb_bus_ids, NULL); + + return 0; +} +device_initcall(celleb_publish_devices); + +define_machine(celleb) { + .name = "Cell Reference Set", + .probe = celleb_probe, + .setup_arch = celleb_setup_arch, + .show_cpuinfo = celleb_show_cpuinfo, + .restart = beat_restart, + .power_off = beat_power_off, + .halt = beat_halt, + .get_rtc_time = beat_get_rtc_time, + .set_rtc_time = beat_set_rtc_time, + .calibrate_decr = generic_calibrate_decr, + .check_legacy_ioport = celleb_check_legacy_ioport, + .progress = celleb_progress, + .power_save = beat_power_save, + .nvram_size = beat_nvram_get_size, + .nvram_read = beat_nvram_read, + .nvram_write = beat_nvram_write, + .set_dabr = beat_set_xdabr, + .init_IRQ = beatic_init_IRQ, + .get_irq = beatic_get_irq, + .pci_probe_mode = celleb_pci_probe_mode, + .pci_setup_phb = celleb_setup_phb, +#ifdef CONFIG_KEXEC + .kexec_cpu_down = celleb_kexec_cpu_down, + .machine_kexec = default_machine_kexec, + .machine_kexec_prepare = default_machine_kexec_prepare, + .machine_crash_shutdown = default_machine_crash_shutdown, +#endif +}; diff --git a/arch/powerpc/platforms/celleb/smp.c b/arch/powerpc/platforms/celleb/smp.c new file mode 100644 index 0000000..a763125 --- /dev/null +++ b/arch/powerpc/platforms/celleb/smp.c @@ -0,0 +1,124 @@ +/* + * SMP support for Celleb platform. (Incomplete) + * + * (C) Copyright 2006 TOSHIBA CORPORATION + * + * This code is based on arch/powerpc/platforms/cell/smp.c: + * Dave Engebretsen, Peter Bergner, and + * Mike Corrigan {engebret|bergner|mikec}@us.ibm.com + * Plus various changes from other IBM teams... + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#undef DEBUG + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include "interrupt.h" + +#ifdef DEBUG +#define DBG(fmt...) udbg_printf(fmt) +#else +#define DBG(fmt...) +#endif + +/* + * The primary thread of each non-boot processor is recorded here before + * smp init. + */ +/* static cpumask_t of_spin_map; */ + +/** + * smp_startup_cpu() - start the given cpu + * + * At boot time, there is nothing to do for primary threads which were + * started from Open Firmware. For anything else, call RTAS with the + * appropriate start location. + * + * Returns: + * 0 - failure + * 1 - success + */ +static inline int __devinit smp_startup_cpu(unsigned int lcpu) +{ + return 0; +} + +static void smp_beatic_message_pass(int target, int msg) +{ + unsigned int i; + + if (target < NR_CPUS) { + beatic_cause_IPI(target, msg); + } else { + for_each_online_cpu(i) { + if (target == MSG_ALL_BUT_SELF + && i == smp_processor_id()) + continue; + beatic_cause_IPI(i, msg); + } + } +} + +static int __init smp_beatic_probe(void) +{ + return cpus_weight(cpu_possible_map); +} + +static void __devinit smp_beatic_setup_cpu(int cpu) +{ + beatic_setup_cpu(cpu); +} + +static void __devinit smp_celleb_kick_cpu(int nr) +{ + BUG_ON(nr < 0 || nr >= NR_CPUS); + + if (!smp_startup_cpu(nr)) + return; +} + +static int smp_celleb_cpu_bootable(unsigned int nr) +{ + return 1; +} +static struct smp_ops_t bpa_beatic_smp_ops = { + .message_pass = smp_beatic_message_pass, + .probe = smp_beatic_probe, + .kick_cpu = smp_celleb_kick_cpu, + .setup_cpu = smp_beatic_setup_cpu, + .cpu_bootable = smp_celleb_cpu_bootable, +}; + +/* This is called very early */ +void __init smp_init_celleb(void) +{ + DBG(" -> smp_init_celleb()\n"); + + smp_ops = &bpa_beatic_smp_ops; + + DBG(" <- smp_init_celleb()\n"); +} diff --git a/arch/powerpc/platforms/celleb/spu_priv1.c b/arch/powerpc/platforms/celleb/spu_priv1.c new file mode 100644 index 0000000..2bf6700 --- /dev/null +++ b/arch/powerpc/platforms/celleb/spu_priv1.c @@ -0,0 +1,208 @@ +/* + * spu hypervisor abstraction for Beat + * + * (C) Copyright 2006-2007 TOSHIBA CORPORATION + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#include + +#include +#include +#include + +#include "beat_wrapper.h" + +static inline void _int_mask_set(struct spu *spu, int class, u64 mask) +{ + spu->shadow_int_mask_RW[class] = mask; + beat_set_irq_mask_for_spe(spu->spe_id, class, mask); +} + +static inline u64 _int_mask_get(struct spu *spu, int class) +{ + return spu->shadow_int_mask_RW[class]; +} + +static void int_mask_set(struct spu *spu, int class, u64 mask) +{ + _int_mask_set(spu, class, mask); +} + +static u64 int_mask_get(struct spu *spu, int class) +{ + return _int_mask_get(spu, class); +} + +static void int_mask_and(struct spu *spu, int class, u64 mask) +{ + u64 old_mask; + old_mask = _int_mask_get(spu, class); + _int_mask_set(spu, class, old_mask & mask); +} + +static void int_mask_or(struct spu *spu, int class, u64 mask) +{ + u64 old_mask; + old_mask = _int_mask_get(spu, class); + _int_mask_set(spu, class, old_mask | mask); +} + +static void int_stat_clear(struct spu *spu, int class, u64 stat) +{ + beat_clear_interrupt_status_of_spe(spu->spe_id, class, stat); +} + +static u64 int_stat_get(struct spu *spu, int class) +{ + u64 int_stat; + beat_get_interrupt_status_of_spe(spu->spe_id, class, &int_stat); + return int_stat; +} + +static void cpu_affinity_set(struct spu *spu, int cpu) +{ + return; +} + +static u64 mfc_dar_get(struct spu *spu) +{ + u64 dar; + beat_get_spe_privileged_state_1_registers( + spu->spe_id, + offsetof(struct spu_priv1, mfc_dar_RW), &dar); + return dar; +} + +static u64 mfc_dsisr_get(struct spu *spu) +{ + u64 dsisr; + beat_get_spe_privileged_state_1_registers( + spu->spe_id, + offsetof(struct spu_priv1, mfc_dsisr_RW), &dsisr); + return dsisr; +} + +static void mfc_dsisr_set(struct spu *spu, u64 dsisr) +{ + beat_set_spe_privileged_state_1_registers( + spu->spe_id, + offsetof(struct spu_priv1, mfc_dsisr_RW), dsisr); +} + +static void mfc_sdr_setup(struct spu *spu) +{ + return; +} + +static void mfc_sr1_set(struct spu *spu, u64 sr1) +{ + beat_set_spe_privileged_state_1_registers( + spu->spe_id, + offsetof(struct spu_priv1, mfc_sr1_RW), sr1); +} + +static u64 mfc_sr1_get(struct spu *spu) +{ + u64 sr1; + beat_get_spe_privileged_state_1_registers( + spu->spe_id, + offsetof(struct spu_priv1, mfc_sr1_RW), &sr1); + return sr1; +} + +static void mfc_tclass_id_set(struct spu *spu, u64 tclass_id) +{ + beat_set_spe_privileged_state_1_registers( + spu->spe_id, + offsetof(struct spu_priv1, mfc_tclass_id_RW), tclass_id); +} + +static u64 mfc_tclass_id_get(struct spu *spu) +{ + u64 tclass_id; + beat_get_spe_privileged_state_1_registers( + spu->spe_id, + offsetof(struct spu_priv1, mfc_tclass_id_RW), &tclass_id); + return tclass_id; +} + +static void tlb_invalidate(struct spu *spu) +{ + beat_set_spe_privileged_state_1_registers( + spu->spe_id, + offsetof(struct spu_priv1, tlb_invalidate_entry_W), 0ul); +} + +static void resource_allocation_groupID_set(struct spu *spu, u64 id) +{ + beat_set_spe_privileged_state_1_registers( + spu->spe_id, + offsetof(struct spu_priv1, resource_allocation_groupID_RW), + id); +} + +static u64 resource_allocation_groupID_get(struct spu *spu) +{ + u64 id; + beat_get_spe_privileged_state_1_registers( + spu->spe_id, + offsetof(struct spu_priv1, resource_allocation_groupID_RW), + &id); + return id; +} + +static void resource_allocation_enable_set(struct spu *spu, u64 enable) +{ + beat_set_spe_privileged_state_1_registers( + spu->spe_id, + offsetof(struct spu_priv1, resource_allocation_enable_RW), + enable); +} + +static u64 resource_allocation_enable_get(struct spu *spu) +{ + u64 enable; + beat_get_spe_privileged_state_1_registers( + spu->spe_id, + offsetof(struct spu_priv1, resource_allocation_enable_RW), + &enable); + return enable; +} + +const struct spu_priv1_ops spu_priv1_beat_ops = +{ + .int_mask_and = int_mask_and, + .int_mask_or = int_mask_or, + .int_mask_set = int_mask_set, + .int_mask_get = int_mask_get, + .int_stat_clear = int_stat_clear, + .int_stat_get = int_stat_get, + .cpu_affinity_set = cpu_affinity_set, + .mfc_dar_get = mfc_dar_get, + .mfc_dsisr_get = mfc_dsisr_get, + .mfc_dsisr_set = mfc_dsisr_set, + .mfc_sdr_setup = mfc_sdr_setup, + .mfc_sr1_set = mfc_sr1_set, + .mfc_sr1_get = mfc_sr1_get, + .mfc_tclass_id_set = mfc_tclass_id_set, + .mfc_tclass_id_get = mfc_tclass_id_get, + .tlb_invalidate = tlb_invalidate, + .resource_allocation_groupID_set = resource_allocation_groupID_set, + .resource_allocation_groupID_get = resource_allocation_groupID_get, + .resource_allocation_enable_set = resource_allocation_enable_set, + .resource_allocation_enable_get = resource_allocation_enable_get, +}; diff --git a/arch/powerpc/platforms/celleb/udbg_beat.c b/arch/powerpc/platforms/celleb/udbg_beat.c new file mode 100644 index 0000000..d888c46 --- /dev/null +++ b/arch/powerpc/platforms/celleb/udbg_beat.c @@ -0,0 +1,97 @@ +/* + * udbg function for Beat + * + * (C) Copyright 2006 TOSHIBA CORPORATION + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#include +#include + +#include +#include +#include + +#include "beat.h" + +#define celleb_vtermno 0 + +static void udbg_putc_beat(char c) +{ + unsigned long rc; + + if (c == '\n') + udbg_putc_beat('\r'); + + rc = beat_put_term_char(celleb_vtermno, 1, (uint64_t)c << 56, 0); +} + +/* Buffered chars getc */ +static long inbuflen; +static long inbuf[2]; /* must be 2 longs */ + +static int udbg_getc_poll_beat(void) +{ + /* The interface is tricky because it may return up to 16 chars. + * We save them statically for future calls to udbg_getc(). + */ + char ch, *buf = (char *)inbuf; + int i; + long rc; + if (inbuflen == 0) { + /* get some more chars. */ + inbuflen = 0; + rc = beat_get_term_char(celleb_vtermno, &inbuflen, inbuf+0, inbuf+1); + if (rc != 0) + inbuflen = 0; /* otherwise inbuflen is garbage */ + } + if (inbuflen <= 0 || inbuflen > 16) { + /* Catch error case as well as other oddities (corruption) */ + inbuflen = 0; + return -1; + } + ch = buf[0]; + for (i = 1; i < inbuflen; i++) /* shuffle them down. */ + buf[i-1] = buf[i]; + inbuflen--; + return ch; +} + +static int udbg_getc_beat(void) +{ + int ch; + for (;;) { + ch = udbg_getc_poll_beat(); + if (ch == -1) { + /* This shouldn't be needed...but... */ + volatile unsigned long delay; + for (delay=0; delay < 2000000; delay++) + ; + } else { + return ch; + } + } +} + +/* call this from early_init() for a working debug console on + * vterm capable LPAR machines + */ +void __init udbg_init_debug_beat(void) +{ + udbg_putc = udbg_putc_beat; + udbg_getc = udbg_getc_beat; + udbg_getc_poll = udbg_getc_poll_beat; +} diff --git a/arch/powerpc/platforms/chrp/setup.c b/arch/powerpc/platforms/chrp/setup.c index e1f51d4..117c9a0 100644 --- a/arch/powerpc/platforms/chrp/setup.c +++ b/arch/powerpc/platforms/chrp/setup.c @@ -75,7 +75,7 @@ extern irqreturn_t xmon_irq(int, void *) extern unsigned long loops_per_jiffy; /* To be replaced by RTAS when available */ -static unsigned int *briq_SPOR; +static unsigned int __iomem *briq_SPOR; #ifdef CONFIG_SMP extern struct smp_ops_t chrp_smp_ops; @@ -267,7 +267,7 @@ void __init chrp_setup_arch(void) } else if (machine && strncmp(machine, "TotalImpact,BRIQ-1", 18) == 0) { _chrp_type = _CHRP_briq; /* Map the SPOR register on briq and change the restart hook */ - briq_SPOR = (unsigned int *)ioremap(0xff0000e8, 4); + briq_SPOR = ioremap(0xff0000e8, 4); ppc_md.restart = briq_restart; } else { /* Let's assume it is an IBM chrp if all else fails */ diff --git a/arch/powerpc/platforms/embedded6xx/Kconfig b/arch/powerpc/platforms/embedded6xx/Kconfig index b3c2ce4..886c522 100644 --- a/arch/powerpc/platforms/embedded6xx/Kconfig +++ b/arch/powerpc/platforms/embedded6xx/Kconfig @@ -104,15 +104,6 @@ config RADSTONE_PPC7D config PAL4 bool "SBS-Palomar4" -config GEMINI - bool "Synergy-Gemini" - select PPC_INDIRECT_PCI - depends on BROKEN - help - Select Gemini if configuring for a Synergy Microsystems' Gemini - series Single Board Computer. More information is available at: - . - config EST8260 bool "EST8260" ---help--- diff --git a/arch/powerpc/platforms/embedded6xx/linkstation.c b/arch/powerpc/platforms/embedded6xx/linkstation.c index 61599d9..3f6c411 100644 --- a/arch/powerpc/platforms/embedded6xx/linkstation.c +++ b/arch/powerpc/platforms/embedded6xx/linkstation.c @@ -13,7 +13,6 @@ #include #include #include -#include #include #include @@ -91,17 +90,6 @@ #ifdef CONFIG_MTD_PHYSMAP ARRAY_SIZE(linkstation_physmap_partitions)); #endif -#ifdef CONFIG_BLK_DEV_INITRD - if (initrd_start) - ROOT_DEV = Root_RAM0; - else -#endif -#ifdef CONFIG_ROOT_NFS - ROOT_DEV = Root_NFS; -#else - ROOT_DEV = Root_HDA1; -#endif - /* Lookup PCI host bridges */ for (np = NULL; (np = of_find_node_by_type(np, "pci")) != NULL;) add_bridge(np); diff --git a/arch/powerpc/platforms/iseries/lpevents.c b/arch/powerpc/platforms/iseries/lpevents.c index c1f4502..91df52a 100644 --- a/arch/powerpc/platforms/iseries/lpevents.c +++ b/arch/powerpc/platforms/iseries/lpevents.c @@ -308,7 +308,7 @@ static int proc_lpevents_open(struct ino return single_open(file, proc_lpevents_show, NULL); } -static struct file_operations proc_lpevents_operations = { +static const struct file_operations proc_lpevents_operations = { .open = proc_lpevents_open, .read = seq_read, .llseek = seq_lseek, diff --git a/arch/powerpc/platforms/iseries/mf.c b/arch/powerpc/platforms/iseries/mf.c index 1ad0e4a..b1187d9 100644 --- a/arch/powerpc/platforms/iseries/mf.c +++ b/arch/powerpc/platforms/iseries/mf.c @@ -1224,7 +1224,7 @@ out: return rc; } -static struct file_operations proc_vmlinux_operations = { +static const struct file_operations proc_vmlinux_operations = { .write = proc_mf_change_vmlinux, }; @@ -1253,7 +1253,6 @@ static int __init mf_proc_init(void) ent = create_proc_entry("cmdline", S_IFREG|S_IRUSR|S_IWUSR, mf); if (!ent) return 1; - ent->nlink = 1; ent->data = (void *)(long)i; ent->read_proc = proc_mf_dump_cmdline; ent->write_proc = proc_mf_change_cmdline; @@ -1264,7 +1263,6 @@ static int __init mf_proc_init(void) ent = create_proc_entry("vmlinux", S_IFREG|S_IWUSR, mf); if (!ent) return 1; - ent->nlink = 1; ent->data = (void *)(long)i; ent->proc_fops = &proc_vmlinux_operations; } @@ -1272,7 +1270,6 @@ static int __init mf_proc_init(void) ent = create_proc_entry("side", S_IFREG|S_IRUSR|S_IWUSR, mf_proc_root); if (!ent) return 1; - ent->nlink = 1; ent->data = (void *)0; ent->read_proc = proc_mf_dump_side; ent->write_proc = proc_mf_change_side; @@ -1280,7 +1277,6 @@ static int __init mf_proc_init(void) ent = create_proc_entry("src", S_IFREG|S_IRUSR|S_IWUSR, mf_proc_root); if (!ent) return 1; - ent->nlink = 1; ent->data = (void *)0; ent->read_proc = proc_mf_dump_src; ent->write_proc = proc_mf_change_src; diff --git a/arch/powerpc/platforms/iseries/proc.c b/arch/powerpc/platforms/iseries/proc.c index b54e371..f2cde41 100644 --- a/arch/powerpc/platforms/iseries/proc.c +++ b/arch/powerpc/platforms/iseries/proc.c @@ -101,7 +101,7 @@ static int proc_titantod_open(struct ino return single_open(file, proc_titantod_show, NULL); } -static struct file_operations proc_titantod_operations = { +static const struct file_operations proc_titantod_operations = { .open = proc_titantod_open, .read = seq_read, .llseek = seq_lseek, diff --git a/arch/powerpc/platforms/iseries/viopath.c b/arch/powerpc/platforms/iseries/viopath.c index a6799ed..e2100ec 100644 --- a/arch/powerpc/platforms/iseries/viopath.c +++ b/arch/powerpc/platforms/iseries/viopath.c @@ -173,7 +173,7 @@ static int proc_viopath_open(struct inod return single_open(file, proc_viopath_show, NULL); } -static struct file_operations proc_viopath_operations = { +static const struct file_operations proc_viopath_operations = { .open = proc_viopath_open, .read = seq_read, .llseek = seq_lseek, diff --git a/arch/powerpc/platforms/maple/pci.c b/arch/powerpc/platforms/maple/pci.c index 3f6a69f..73c5990 100644 --- a/arch/powerpc/platforms/maple/pci.c +++ b/arch/powerpc/platforms/maple/pci.c @@ -425,14 +425,6 @@ static void __init setup_u4_pcie(struct hose->cfg_addr = ioremap(0xf0000000 + 0x800000, 0x1000); hose->cfg_data = ioremap(0xf0000000 + 0xc00000, 0x1000); - /* The bus contains a bridge from root -> device, we need to - * make it visible on bus 0 so that we pick the right type - * of config cycles. If we didn't, we would have to force all - * config cycles to be type 1. So we override the "bus-range" - * property here - */ - hose->first_busno = 0x00; - hose->last_busno = 0xff; u4_pcie = hose; } @@ -560,13 +552,16 @@ void __init maple_pci_init(void) return; } for (np = NULL; (np = of_get_next_child(root, np)) != NULL;) { - if (np->name == NULL) + if (!np->type) continue; - if (!strcmp(np->name, "pci") || !strcmp(np->name, "pcie")) { - if (add_bridge(np) == 0) - of_node_get(np); - } - if (strcmp(np->name, "ht") == 0) { + if (strcmp(np->type, "pci") && strcmp(np->type, "ht")) + continue; + if ((device_is_compatible(np, "u4-pcie") || + device_is_compatible(np, "u3-agp")) && + add_bridge(np) == 0) + of_node_get(np); + + if (device_is_compatible(np, "u3-ht")) { of_node_get(np); ht = np; } diff --git a/arch/powerpc/platforms/maple/setup.c b/arch/powerpc/platforms/maple/setup.c index 50855d4..82d3f9e 100644 --- a/arch/powerpc/platforms/maple/setup.c +++ b/arch/powerpc/platforms/maple/setup.c @@ -62,6 +62,7 @@ #include #include #include #include +#include #include "maple.h" @@ -195,6 +196,8 @@ #endif maple_use_rtas_reboot_and_halt_if_present(); printk(KERN_DEBUG "Using native/NAP idle loop\n"); + + mmio_nvram_init(); } /* diff --git a/arch/powerpc/platforms/pasemi/Kconfig b/arch/powerpc/platforms/pasemi/Kconfig new file mode 100644 index 0000000..68dc529 --- /dev/null +++ b/arch/powerpc/platforms/pasemi/Kconfig @@ -0,0 +1,10 @@ +menu "PA Semi PWRficient options" + depends on PPC_PASEMI + +config PPC_PASEMI_IOMMU + bool "PA Semi IOMMU support" + depends on PPC_PASEMI + help + IOMMU support for PA6T-1682M + +endmenu diff --git a/arch/powerpc/platforms/pasemi/Makefile b/arch/powerpc/platforms/pasemi/Makefile index 1be1a99..e657cca 100644 --- a/arch/powerpc/platforms/pasemi/Makefile +++ b/arch/powerpc/platforms/pasemi/Makefile @@ -1 +1,2 @@ -obj-y += setup.o pci.o time.o +obj-y += setup.o pci.o time.o idle.o powersave.o iommu.o + diff --git a/arch/powerpc/platforms/pasemi/idle.c b/arch/powerpc/platforms/pasemi/idle.c new file mode 100644 index 0000000..1ca3ff3 --- /dev/null +++ b/arch/powerpc/platforms/pasemi/idle.c @@ -0,0 +1,88 @@ +/* + * Copyright (C) 2006-2007 PA Semi, Inc + * + * Maintained by: Olof Johansson + * + * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +#undef DEBUG + +#include +#include + +#include +#include + +#include "pasemi.h" + +struct sleep_mode { + char *name; + void (*entry)(void); +}; + +static struct sleep_mode modes[] = { + { .name = "spin", .entry = &idle_spin }, + { .name = "doze", .entry = &idle_doze }, +}; + +static int current_mode = 0; + +static int pasemi_system_reset_exception(struct pt_regs *regs) +{ + /* If we were woken up from power savings, we need to return + * to the calling function, since nip is not saved across + * all modes. + */ + + if (regs->msr & SRR1_WAKEMASK) + regs->nip = regs->link; + + switch (regs->msr & SRR1_WAKEMASK) { + case SRR1_WAKEEE: + do_IRQ(regs); + break; + case SRR1_WAKEDEC: + timer_interrupt(regs); + break; + default: + /* do system reset */ + return 0; + } + /* everything handled */ + regs->msr |= MSR_RI; + return 1; +} + +void __init pasemi_idle_init(void) +{ + ppc_md.system_reset_exception = pasemi_system_reset_exception; + ppc_md.power_save = modes[current_mode].entry; + printk(KERN_INFO "Using PA6T idle loop (%s)\n", modes[current_mode].name); +} + +static int __init idle_param(char *p) +{ + int i; + for (i = 0; i < sizeof(modes)/sizeof(struct sleep_mode); i++) { + if (!strcmp(modes[i].name, p)) { + current_mode = i; + break; + } + } + return 0; +} + +early_param("idle", idle_param); diff --git a/arch/powerpc/platforms/pasemi/iommu.c b/arch/powerpc/platforms/pasemi/iommu.c new file mode 100644 index 0000000..459a53b --- /dev/null +++ b/arch/powerpc/platforms/pasemi/iommu.c @@ -0,0 +1,281 @@ +/* + * Copyright (C) 2005-2007, PA Semi, Inc + * + * Maintained by: Olof Johansson + * + * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#undef DEBUG + +#include +#include +#include +#include +#include +#include + + +#define IOBMAP_PAGE_SHIFT 12 +#define IOBMAP_PAGE_SIZE (1 << IOBMAP_PAGE_SHIFT) +#define IOBMAP_PAGE_MASK (IOBMAP_PAGE_SIZE - 1) + +#define IOBMAP_PAGE_FACTOR (PAGE_SHIFT - IOBMAP_PAGE_SHIFT) + +#define IOB_BASE 0xe0000000 +#define IOB_SIZE 0x3000 +/* Configuration registers */ +#define IOBCAP_REG 0x10 +#define IOBCOM_REG 0x40 +/* Enable IOB address translation */ +#define IOBCOM_ATEN 0x00000100 + +/* Address decode configuration register */ +#define IOB_AD_REG 0x53 +/* IOBCOM_AD_REG fields */ +#define IOB_AD_VGPRT 0x00000e00 +#define IOB_AD_VGAEN 0x00000100 +/* Direct mapping settings */ +#define IOB_AD_MPSEL_MASK 0x00000030 +#define IOB_AD_MPSEL_B38 0x00000000 +#define IOB_AD_MPSEL_B40 0x00000010 +#define IOB_AD_MPSEL_B42 0x00000020 +/* Translation window size / enable */ +#define IOB_AD_TRNG_MASK 0x00000003 +#define IOB_AD_TRNG_256M 0x00000000 +#define IOB_AD_TRNG_2G 0x00000001 +#define IOB_AD_TRNG_128G 0x00000003 + +#define IOB_TABLEBASE_REG 0x55 + +/* Base of the 64 4-byte L1 registers */ +#define IOB_XLT_L1_REGBASE 0xac0 + +/* Register to invalidate TLB entries */ +#define IOB_AT_INVAL_TLB_REG 0xb40 + +/* The top two bits of the level 1 entry contains valid and type flags */ +#define IOBMAP_L1E_V 0x40000000 +#define IOBMAP_L1E_V_B 0x80000000 + +/* For big page entries, the bottom two bits contains flags */ +#define IOBMAP_L1E_BIG_CACHED 0x00000002 +#define IOBMAP_L1E_BIG_PRIORITY 0x00000001 + +/* For regular level 2 entries, top 2 bits contain valid and cache flags */ +#define IOBMAP_L2E_V 0x80000000 +#define IOBMAP_L2E_V_CACHED 0xc0000000 + +static u32 *iob; +static u32 iob_l1_emptyval; +static u32 iob_l2_emptyval; +static u32 *iob_l2_base; + +static struct iommu_table iommu_table_iobmap; +static int iommu_table_iobmap_inited; + +static void iobmap_build(struct iommu_table *tbl, long index, + long npages, unsigned long uaddr, + enum dma_data_direction direction) +{ + u32 *ip; + u32 rpn; + unsigned long bus_addr; + + pr_debug("iobmap: build at: %lx, %lx, addr: %lx\n", index, npages, uaddr); + + bus_addr = (tbl->it_offset + index) << PAGE_SHIFT; + + npages <<= IOBMAP_PAGE_FACTOR; + index <<= IOBMAP_PAGE_FACTOR; + + ip = ((u32 *)tbl->it_base) + index; + + while (npages--) { + rpn = virt_to_abs(uaddr) >> IOBMAP_PAGE_SHIFT; + + *(ip++) = IOBMAP_L2E_V | rpn; + /* invalidate tlb, can be optimized more */ + out_le32(iob+IOB_AT_INVAL_TLB_REG, bus_addr >> 14); + + uaddr += IOBMAP_PAGE_SIZE; + bus_addr += IOBMAP_PAGE_SIZE; + } +} + + +static void iobmap_free(struct iommu_table *tbl, long index, + long npages) +{ + u32 *ip; + unsigned long bus_addr; + + pr_debug("iobmap: free at: %lx, %lx\n", index, npages); + + bus_addr = (tbl->it_offset + index) << PAGE_SHIFT; + + npages <<= IOBMAP_PAGE_FACTOR; + index <<= IOBMAP_PAGE_FACTOR; + + ip = ((u32 *)tbl->it_base) + index; + + while (npages--) { + *(ip++) = iob_l2_emptyval; + /* invalidate tlb, can be optimized more */ + out_le32(iob+IOB_AT_INVAL_TLB_REG, bus_addr >> 14); + bus_addr += IOBMAP_PAGE_SIZE; + } +} + + +static void iommu_table_iobmap_setup(void) +{ + pr_debug(" -> %s\n", __func__); + iommu_table_iobmap.it_busno = 0; + iommu_table_iobmap.it_offset = 0; + /* it_size is in number of entries */ + iommu_table_iobmap.it_size = 0x80000000 >> PAGE_SHIFT; + + /* Initialize the common IOMMU code */ + iommu_table_iobmap.it_base = (unsigned long)iob_l2_base; + iommu_table_iobmap.it_index = 0; + /* XXXOJN tune this to avoid IOB cache invals. + * Should probably be 8 (64 bytes) + */ + iommu_table_iobmap.it_blocksize = 4; + iommu_init_table(&iommu_table_iobmap, 0); + pr_debug(" <- %s\n", __func__); +} + + + +static void pci_dma_bus_setup_pasemi(struct pci_bus *bus) +{ + struct device_node *dn; + + pr_debug("pci_dma_bus_setup, bus %p, bus->self %p\n", bus, bus->self); + + if (!iommu_table_iobmap_inited) { + iommu_table_iobmap_inited = 1; + iommu_table_iobmap_setup(); + } + + dn = pci_bus_to_OF_node(bus); + + if (dn) + PCI_DN(dn)->iommu_table = &iommu_table_iobmap; + +} + + +static void pci_dma_dev_setup_pasemi(struct pci_dev *dev) +{ + pr_debug("pci_dma_dev_setup, dev %p (%s)\n", dev, pci_name(dev)); + + /* DMA device is untranslated, but all other PCI-e goes through + * the IOMMU + */ + if (dev->vendor == 0x1959 && dev->device == 0xa007) + dev->dev.archdata.dma_ops = &dma_direct_ops; + else + dev->dev.archdata.dma_data = &iommu_table_iobmap; +} + +static void pci_dma_bus_setup_null(struct pci_bus *b) { } +static void pci_dma_dev_setup_null(struct pci_dev *d) { } + +int iob_init(struct device_node *dn) +{ + unsigned long tmp; + u32 regword; + int i; + + pr_debug(" -> %s\n", __func__); + + /* Allocate a spare page to map all invalid IOTLB pages. */ + tmp = lmb_alloc(IOBMAP_PAGE_SIZE, IOBMAP_PAGE_SIZE); + if (!tmp) + panic("IOBMAP: Cannot allocate spare page!"); + /* Empty l1 is marked invalid */ + iob_l1_emptyval = 0; + /* Empty l2 is mapped to dummy page */ + iob_l2_emptyval = IOBMAP_L2E_V | (tmp >> IOBMAP_PAGE_SHIFT); + + iob = ioremap(IOB_BASE, IOB_SIZE); + if (!iob) + panic("IOBMAP: Cannot map registers!"); + + /* setup direct mapping of the L1 entries */ + for (i = 0; i < 64; i++) { + /* Each L1 covers 32MB, i.e. 8K entries = 32K of ram */ + regword = IOBMAP_L1E_V | (__pa(iob_l2_base + i*0x2000) >> 12); + out_le32(iob+IOB_XLT_L1_REGBASE+i, regword); + } + + /* set 2GB translation window, based at 0 */ + regword = in_le32(iob+IOB_AD_REG); + regword &= ~IOB_AD_TRNG_MASK; + regword |= IOB_AD_TRNG_2G; + out_le32(iob+IOB_AD_REG, regword); + + /* Enable translation */ + regword = in_le32(iob+IOBCOM_REG); + regword |= IOBCOM_ATEN; + out_le32(iob+IOBCOM_REG, regword); + + pr_debug(" <- %s\n", __func__); + + return 0; +} + + +/* These are called very early. */ +void iommu_init_early_pasemi(void) +{ + int iommu_off; + +#ifndef CONFIG_PPC_PASEMI_IOMMU + iommu_off = 1; +#else + iommu_off = of_chosen && + get_property(of_chosen, "linux,iommu-off", NULL); +#endif + if (iommu_off) { + /* Direct I/O, IOMMU off */ + ppc_md.pci_dma_dev_setup = pci_dma_dev_setup_null; + ppc_md.pci_dma_bus_setup = pci_dma_bus_setup_null; + pci_dma_ops = &dma_direct_ops; + + return; + } + + iob_init(NULL); + + ppc_md.pci_dma_dev_setup = pci_dma_dev_setup_pasemi; + ppc_md.pci_dma_bus_setup = pci_dma_bus_setup_pasemi; + ppc_md.tce_build = iobmap_build; + ppc_md.tce_free = iobmap_free; + pci_dma_ops = &dma_iommu_ops; +} + +void __init alloc_iobmap_l2(void) +{ +#ifndef CONFIG_PPC_PASEMI_IOMMU + return; +#endif + /* For 2G space, 8x64 pages (2^21 bytes) is max total l2 size */ + iob_l2_base = (u32 *)abs_to_virt(lmb_alloc_base(1UL<<21, 1UL<<21, 0x80000000)); + + printk(KERN_INFO "IOBMAP L2 allocated at: %p\n", iob_l2_base); +} diff --git a/arch/powerpc/platforms/pasemi/pasemi.h b/arch/powerpc/platforms/pasemi/pasemi.h index 51c2a23..2d3927e 100644 --- a/arch/powerpc/platforms/pasemi/pasemi.h +++ b/arch/powerpc/platforms/pasemi/pasemi.h @@ -3,5 +3,17 @@ #define _PASEMI_PASEMI_H extern unsigned long pas_get_boot_time(void); extern void pas_pci_init(void); +extern void __devinit pas_pci_irq_fixup(struct pci_dev *dev); +extern void __devinit pas_pci_dma_dev_setup(struct pci_dev *dev); + +extern void __init alloc_iobmap_l2(void); + +extern void __init pasemi_idle_init(void); + +/* Power savings modes, implemented in asm */ +extern void idle_spin(void); +extern void idle_doze(void); + + #endif /* _PASEMI_PASEMI_H */ diff --git a/arch/powerpc/platforms/pasemi/pci.c b/arch/powerpc/platforms/pasemi/pci.c index faa618e..7ecb2ba 100644 --- a/arch/powerpc/platforms/pasemi/pci.c +++ b/arch/powerpc/platforms/pasemi/pci.c @@ -163,6 +163,19 @@ static void __init pas_fixup_phb_resourc } +void __devinit pas_pci_irq_fixup(struct pci_dev *dev) +{ + /* DMA is special, 84 interrupts (128 -> 211), all but 128 + * need to be mapped by hand here. + */ + if (dev->vendor == 0x1959 && dev->device == 0xa007) { + int i; + for (i = 129; i < 212; i++) + irq_create_mapping(NULL, i); + } +} + + void __init pas_pci_init(void) { struct device_node *np, *root; diff --git a/arch/powerpc/platforms/pasemi/powersave.S b/arch/powerpc/platforms/pasemi/powersave.S new file mode 100644 index 0000000..6d0fba6 --- /dev/null +++ b/arch/powerpc/platforms/pasemi/powersave.S @@ -0,0 +1,80 @@ +/* + * Copyright (C) 2006-2007 PA Semi, Inc + * + * Maintained by: Olof Johansson + * + * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +#include +#include +#include +#include +#include +#include +#include + +/* Power savings opcodes since not all binutils have them at this time */ +#define DOZE .long 0x4c000324 +#define NAP .long 0x4c000364 +#define SLEEP .long 0x4c0003a4 +#define RVW .long 0x4c0003e4 + +/* Common sequence to do before going to any of the + * powersavings modes. + */ + +#define PRE_SLEEP_SEQUENCE \ + std r3,8(r1); \ + ptesync ; \ + ld r3,8(r1); \ +1: cmpd r3,r3; \ + bne 1b + +_doze: + PRE_SLEEP_SEQUENCE + DOZE + b . + + +_GLOBAL(idle_spin) + blr + +_GLOBAL(idle_doze) + LOAD_REG_ADDR(r3, _doze) + b sleep_common + +/* Add more modes here later */ + +sleep_common: + mflr r0 + std r0, 16(r1) + stdu r1,-64(r1) + + LOAD_REG_IMMEDIATE(r6,MSR_DR|MSR_IR|MSR_ME|MSR_EE) + mfmsr r4 + andc r5,r4,r6 + mtmsrd r5,0 + + mtctr r3 + bctrl + + mtmsrd r4,0 + + addi r1,r1,64 + ld r0,16(r1) + mtlr r0 + blr + diff --git a/arch/powerpc/platforms/pasemi/setup.c b/arch/powerpc/platforms/pasemi/setup.c index bea7d1b..449cf1a 100644 --- a/arch/powerpc/platforms/pasemi/setup.c +++ b/arch/powerpc/platforms/pasemi/setup.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2006 PA Semi, Inc + * Copyright (C) 2006-2007 PA Semi, Inc * * Authors: Kip Walker, PA Semi * Olof Johansson, PA Semi @@ -38,31 +38,46 @@ #include #include "pasemi.h" +static void __iomem *reset_reg; + static void pas_restart(char *cmd) { - printk("restart unimplemented, looping...\n"); - for (;;) ; + printk("Restarting...\n"); + while (1) + out_le32(reset_reg, 0x6000000); } -static void pas_power_off(void) +#ifdef CONFIG_SMP +static DEFINE_SPINLOCK(timebase_lock); + +static void __devinit pas_give_timebase(void) { - printk("power off unimplemented, looping...\n"); - for (;;) ; + unsigned long tb; + + spin_lock(&timebase_lock); + mtspr(SPRN_TBCTL, TBCTL_FREEZE); + tb = mftb(); + mtspr(SPRN_TBCTL, TBCTL_UPDATE_LOWER | (tb & 0xffffffff)); + mtspr(SPRN_TBCTL, TBCTL_UPDATE_UPPER | (tb >> 32)); + mtspr(SPRN_TBCTL, TBCTL_RESTART); + spin_unlock(&timebase_lock); + pr_debug("pas_give_timebase: cpu %d gave tb %lx\n", + smp_processor_id(), tb); } -static void pas_halt(void) +static void __devinit pas_take_timebase(void) { - pas_power_off(); + pr_debug("pas_take_timebase: cpu %d has tb %lx\n", + smp_processor_id(), mftb()); } -#ifdef CONFIG_SMP struct smp_ops_t pas_smp_ops = { .probe = smp_mpic_probe, .message_pass = smp_mpic_message_pass, .kick_cpu = smp_generic_kick_cpu, .setup_cpu = smp_mpic_setup_cpu, - .give_timebase = smp_generic_give_timebase, - .take_timebase = smp_generic_take_timebase, + .give_timebase = pas_give_timebase, + .take_timebase = pas_take_timebase, }; #endif /* CONFIG_SMP */ @@ -72,9 +87,6 @@ #ifdef CONFIG_SMP /* Setup SMP callback */ smp_ops = &pas_smp_ops; #endif - /* no iommu yet */ - pci_dma_ops = &dma_direct_ops; - /* Lookup PCI hosts */ pas_pci_init(); @@ -82,7 +94,11 @@ #ifdef CONFIG_DUMMY_CONSOLE conswitchp = &dummy_con; #endif - printk(KERN_DEBUG "Using default idle loop\n"); + /* Remap SDC register for doing reset */ + /* XXXOJN This should maybe come out of the device tree */ + reset_reg = ioremap(0xfc101100, 4); + + pasemi_idle_init(); } /* No legacy IO on our parts */ @@ -130,8 +146,9 @@ static __init void pas_init_IRQ(void) openpic_addr = of_read_number(opprop, naddr); printk(KERN_DEBUG "OpenPIC addr: %lx\n", openpic_addr); - mpic = mpic_alloc(mpic_node, openpic_addr, MPIC_PRIMARY, 0, 0, - " PAS-OPIC "); + mpic = mpic_alloc(mpic_node, openpic_addr, + MPIC_PRIMARY|MPIC_LARGE_VECTORS, + 0, 0, " PAS-OPIC "); BUG_ON(!mpic); mpic_assign_isu(mpic, 0, openpic_addr + 0x10000); @@ -146,6 +163,53 @@ static void __init pas_progress(char *s, } +static int pas_machine_check_handler(struct pt_regs *regs) +{ + int cpu = smp_processor_id(); + unsigned long srr0, srr1, dsisr; + + srr0 = regs->nip; + srr1 = regs->msr; + dsisr = mfspr(SPRN_DSISR); + printk(KERN_ERR "Machine Check on CPU %d\n", cpu); + printk(KERN_ERR "SRR0 0x%016lx SRR1 0x%016lx\n", srr0, srr1); + printk(KERN_ERR "DSISR 0x%016lx DAR 0x%016lx\n", dsisr, regs->dar); + printk(KERN_ERR "Cause:\n"); + + if (srr1 & 0x200000) + printk(KERN_ERR "Signalled by SDC\n"); + if (srr1 & 0x100000) { + printk(KERN_ERR "Load/Store detected error:\n"); + if (dsisr & 0x8000) + printk(KERN_ERR "D-cache ECC double-bit error or bus error\n"); + if (dsisr & 0x4000) + printk(KERN_ERR "LSU snoop response error\n"); + if (dsisr & 0x2000) + printk(KERN_ERR "MMU SLB multi-hit or invalid B field\n"); + if (dsisr & 0x1000) + printk(KERN_ERR "Recoverable Duptags\n"); + if (dsisr & 0x800) + printk(KERN_ERR "Recoverable D-cache parity error count overflow\n"); + if (dsisr & 0x400) + printk(KERN_ERR "TLB parity error count overflow\n"); + } + if (srr1 & 0x80000) + printk(KERN_ERR "Bus Error\n"); + if (srr1 & 0x40000) + printk(KERN_ERR "I-side SLB multiple hit\n"); + if (srr1 & 0x20000) + printk(KERN_ERR "I-cache parity error hit\n"); + + /* SRR1[62] is from MSR[62] if recoverable, so pass that back */ + return !!(srr1 & 0x2); +} + +static void __init pas_init_early(void) +{ + iommu_init_early_pasemi(); +} + + /* * Called very early, MMU is off, device-tree isn't unflattened */ @@ -158,6 +222,8 @@ static int __init pas_probe(void) hpte_init_native(); + alloc_iobmap_l2(); + return 1; } @@ -165,13 +231,14 @@ define_machine(pas) { .name = "PA Semi PA6T-1682M", .probe = pas_probe, .setup_arch = pas_setup_arch, + .init_early = pas_init_early, .init_IRQ = pas_init_IRQ, .get_irq = mpic_get_irq, .restart = pas_restart, - .power_off = pas_power_off, - .halt = pas_halt, .get_boot_time = pas_get_boot_time, .calibrate_decr = generic_calibrate_decr, .check_legacy_ioport = pas_check_legacy_ioport, .progress = pas_progress, + .machine_check_exception = pas_machine_check_handler, + .pci_irq_fixup = pas_pci_irq_fixup, }; diff --git a/arch/powerpc/platforms/powermac/pic.c b/arch/powerpc/platforms/powermac/pic.c index 39db128..5e5c0e4 100644 --- a/arch/powerpc/platforms/powermac/pic.c +++ b/arch/powerpc/platforms/powermac/pic.c @@ -305,8 +305,6 @@ static int pmac_pic_host_map(struct irq_ level = !!(level_mask[hw >> 5] & (1UL << (hw & 0x1f))); if (level) desc->status |= IRQ_LEVEL; - else - desc->status |= IRQ_DELAYED_DISABLE; set_irq_chip_and_handler(virq, &pmac_pic, level ? handle_level_irq : handle_edge_irq); return 0; diff --git a/arch/powerpc/platforms/powermac/setup.c b/arch/powerpc/platforms/powermac/setup.c index d949e9d..651fa42 100644 --- a/arch/powerpc/platforms/powermac/setup.c +++ b/arch/powerpc/platforms/powermac/setup.c @@ -506,8 +506,8 @@ void note_bootable_part(dev_t dev, int p if ((goodness <= current_root_goodness) && ROOT_DEV != DEFAULT_ROOT_DEVICE) return; - p = strstr(saved_command_line, "root="); - if (p != NULL && (p == saved_command_line || p[-1] == ' ')) + p = strstr(boot_command_line, "root="); + if (p != NULL && (p == boot_command_line || p[-1] == ' ')) return; if (!found_boot) { diff --git a/arch/powerpc/platforms/powermac/smp.c b/arch/powerpc/platforms/powermac/smp.c index eeb2ae5..d73fb73 100644 --- a/arch/powerpc/platforms/powermac/smp.c +++ b/arch/powerpc/platforms/powermac/smp.c @@ -795,7 +795,6 @@ static void __devinit smp_core99_kick_cp ppc_md.progress("smp_core99_kick_cpu", 0x346); local_irq_save(flags); - local_irq_disable(); /* Save reset vector */ save_vector = *vector; diff --git a/arch/powerpc/platforms/ps3/Kconfig b/arch/powerpc/platforms/ps3/Kconfig index de52ec4..4be3943 100644 --- a/arch/powerpc/platforms/ps3/Kconfig +++ b/arch/powerpc/platforms/ps3/Kconfig @@ -51,4 +51,15 @@ config PS3_VUART including the System Manager and AV Settings. In general, all users will say Y. +config PS3_PS3AV + tristate "PS3 AV settings driver" + depends on PPC_PS3 + select PS3_VUART + default y + help + Include support for the PS3 AV Settings driver. + + This support is required for graphics and sound. In + general, all users will say Y or M. + endmenu diff --git a/arch/powerpc/platforms/ps3/Makefile b/arch/powerpc/platforms/ps3/Makefile index 1994904..a0048fc 100644 --- a/arch/powerpc/platforms/ps3/Makefile +++ b/arch/powerpc/platforms/ps3/Makefile @@ -1,5 +1,6 @@ obj-y += setup.o mm.o time.o hvcall.o htab.o repository.o obj-y += interrupt.o exports.o os-area.o +obj-y += system-bus.o obj-$(CONFIG_SMP) += smp.o obj-$(CONFIG_SPU_BASE) += spu.o diff --git a/arch/powerpc/platforms/ps3/htab.c b/arch/powerpc/platforms/ps3/htab.c index 8fe1769..e12e59f 100644 --- a/arch/powerpc/platforms/ps3/htab.c +++ b/arch/powerpc/platforms/ps3/htab.c @@ -2,7 +2,7 @@ * PS3 pagetable management routines. * * Copyright (C) 2006 Sony Computer Entertainment Inc. - * Copyright 2006 Sony Corp. + * Copyright 2006, 2007 Sony 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 @@ -23,8 +23,8 @@ #include #include #include #include -#include #include +#include #include "platform.h" @@ -234,6 +234,9 @@ static void ps3_hpte_invalidate(unsigned static void ps3_hpte_clear(void) { + /* Make sure to clean up the frame buffer device first */ + ps3fb_cleanup(); + lv1_unmap_htab(htab_addr); } diff --git a/arch/powerpc/platforms/ps3/interrupt.c b/arch/powerpc/platforms/ps3/interrupt.c index 6f5de43..631c300 100644 --- a/arch/powerpc/platforms/ps3/interrupt.c +++ b/arch/powerpc/platforms/ps3/interrupt.c @@ -24,7 +24,6 @@ #include #include #include -#include #include #include "platform.h" @@ -36,15 +35,148 @@ #define DBG(fmt...) do{if(0)printk(fmt); #endif /** + * struct ps3_bmp - a per cpu irq status and mask bitmap structure + * @status: 256 bit status bitmap indexed by plug + * @unused_1: + * @mask: 256 bit mask bitmap indexed by plug + * @unused_2: + * @lock: + * @ipi_debug_brk_mask: + * + * The HV mantains per SMT thread mappings of HV outlet to HV plug on + * behalf of the guest. These mappings are implemented as 256 bit guest + * supplied bitmaps indexed by plug number. The addresses of the bitmaps + * are registered with the HV through lv1_configure_irq_state_bitmap(). + * The HV requires that the 512 bits of status + mask not cross a page + * boundary. PS3_BMP_MINALIGN is used to define this minimal 64 byte + * alignment. + * + * The HV supports 256 plugs per thread, assigned as {0..255}, for a total + * of 512 plugs supported on a processor. To simplify the logic this + * implementation equates HV plug value to Linux virq value, constrains each + * interrupt to have a system wide unique plug number, and limits the range + * of the plug values to map into the first dword of the bitmaps. This + * gives a usable range of plug values of {NUM_ISA_INTERRUPTS..63}. Note + * that there is no constraint on how many in this set an individual thread + * can acquire. + */ + +#define PS3_BMP_MINALIGN 64 + +struct ps3_bmp { + struct { + u64 status; + u64 unused_1[3]; + u64 mask; + u64 unused_2[3]; + }; + u64 ipi_debug_brk_mask; + spinlock_t lock; +}; + +/** + * struct ps3_private - a per cpu data structure + * @bmp: ps3_bmp structure + * @node: HV logical_ppe_id + * @cpu: HV thread_id + */ + +struct ps3_private { + struct ps3_bmp bmp __attribute__ ((aligned (PS3_BMP_MINALIGN))); + u64 node; + unsigned int cpu; +}; + +static DEFINE_PER_CPU(struct ps3_private, ps3_private); + +int ps3_alloc_irq(enum ps3_cpu_binding cpu, unsigned long outlet, + unsigned int *virq) +{ + int result; + struct ps3_private *pd; + + /* This defines the default interrupt distribution policy. */ + + if (cpu == PS3_BINDING_CPU_ANY) + cpu = 0; + + pd = &per_cpu(ps3_private, cpu); + + *virq = irq_create_mapping(NULL, outlet); + + if (*virq == NO_IRQ) { + pr_debug("%s:%d: irq_create_mapping failed: outlet %lu\n", + __func__, __LINE__, outlet); + result = -ENOMEM; + goto fail_create; + } + + /* Binds outlet to cpu + virq. */ + + result = lv1_connect_irq_plug_ext(pd->node, pd->cpu, *virq, outlet, 0); + + if (result) { + pr_info("%s:%d: lv1_connect_irq_plug_ext failed: %s\n", + __func__, __LINE__, ps3_result(result)); + result = -EPERM; + goto fail_connect; + } + + pr_debug("%s:%d: outlet %lu => cpu %u, virq %u\n", __func__, __LINE__, + outlet, cpu, *virq); + + result = set_irq_chip_data(*virq, pd); + + if (result) { + pr_debug("%s:%d: set_irq_chip_data failed\n", + __func__, __LINE__); + goto fail_set; + } + + return result; + +fail_set: + lv1_disconnect_irq_plug_ext(pd->node, pd->cpu, *virq); +fail_connect: + irq_dispose_mapping(*virq); +fail_create: + return result; +} +EXPORT_SYMBOL_GPL(ps3_alloc_irq); + +int ps3_free_irq(unsigned int virq) +{ + int result; + const struct ps3_private *pd = get_irq_chip_data(virq); + + pr_debug("%s:%d: node %lu, cpu %d, virq %u\n", __func__, __LINE__, + pd->node, pd->cpu, virq); + + result = lv1_disconnect_irq_plug_ext(pd->node, pd->cpu, virq); + + if (result) + pr_info("%s:%d: lv1_disconnect_irq_plug_ext failed: %s\n", + __func__, __LINE__, ps3_result(result)); + + set_irq_chip_data(virq, NULL); + irq_dispose_mapping(virq); + return result; +} +EXPORT_SYMBOL_GPL(ps3_free_irq); + +/** * ps3_alloc_io_irq - Assign a virq to a system bus device. - * interrupt_id: The device interrupt id read from the system repository. + * @cpu: enum ps3_cpu_binding indicating the cpu the interrupt should be + * serviced on. + * @interrupt_id: The device interrupt id read from the system repository. * @virq: The assigned Linux virq. * * An io irq represents a non-virtualized device interrupt. interrupt_id * coresponds to the interrupt number of the interrupt controller. */ -int ps3_alloc_io_irq(unsigned int interrupt_id, unsigned int *virq) +int ps3_alloc_io_irq(enum ps3_cpu_binding cpu, unsigned int interrupt_id, + unsigned int *virq) { int result; unsigned long outlet; @@ -57,13 +189,12 @@ int ps3_alloc_io_irq(unsigned int interr return result; } - *virq = irq_create_mapping(NULL, outlet); - - pr_debug("%s:%d: interrupt_id %u => outlet %lu, virq %u\n", - __func__, __LINE__, interrupt_id, outlet, *virq); + result = ps3_alloc_irq(cpu, outlet, virq); + BUG_ON(result); - return 0; + return result; } +EXPORT_SYMBOL_GPL(ps3_alloc_io_irq); int ps3_free_io_irq(unsigned int virq) { @@ -75,13 +206,16 @@ int ps3_free_io_irq(unsigned int virq) pr_debug("%s:%d: lv1_destruct_io_irq_outlet failed: %s\n", __func__, __LINE__, ps3_result(result)); - irq_dispose_mapping(virq); + ps3_free_irq(virq); return result; } +EXPORT_SYMBOL_GPL(ps3_free_io_irq); /** * ps3_alloc_event_irq - Allocate a virq for use with a system event. + * @cpu: enum ps3_cpu_binding indicating the cpu the interrupt should be + * serviced on. * @virq: The assigned Linux virq. * * The virq can be used with lv1_connect_interrupt_event_receive_port() to @@ -89,7 +223,7 @@ int ps3_free_io_irq(unsigned int virq) * events. */ -int ps3_alloc_event_irq(unsigned int *virq) +int ps3_alloc_event_irq(enum ps3_cpu_binding cpu, unsigned int *virq) { int result; unsigned long outlet; @@ -103,12 +237,10 @@ int ps3_alloc_event_irq(unsigned int *vi return result; } - *virq = irq_create_mapping(NULL, outlet); - - pr_debug("%s:%d: outlet %lu, virq %u\n", __func__, __LINE__, outlet, - *virq); + result = ps3_alloc_irq(cpu, outlet, virq); + BUG_ON(result); - return 0; + return result; } int ps3_free_event_irq(unsigned int virq) @@ -123,7 +255,7 @@ int ps3_free_event_irq(unsigned int virq pr_debug("%s:%d: lv1_destruct_event_receive_port failed: %s\n", __func__, __LINE__, ps3_result(result)); - irq_dispose_mapping(virq); + ps3_free_irq(virq); pr_debug(" <- %s:%d\n", __func__, __LINE__); return result; @@ -136,6 +268,8 @@ int ps3_send_event_locally(unsigned int /** * ps3_connect_event_irq - Assign a virq to a system bus device. + * @cpu: enum ps3_cpu_binding indicating the cpu the interrupt should be + * serviced on. * @did: The HV device identifier read from the system repository. * @interrupt_id: The device interrupt id read from the system repository. * @virq: The assigned Linux virq. @@ -144,12 +278,13 @@ int ps3_send_event_locally(unsigned int * coresponds to the software interrupt number. */ -int ps3_connect_event_irq(const struct ps3_device_id *did, - unsigned int interrupt_id, unsigned int *virq) +int ps3_connect_event_irq(enum ps3_cpu_binding cpu, + const struct ps3_device_id *did, unsigned int interrupt_id, + unsigned int *virq) { int result; - result = ps3_alloc_event_irq(virq); + result = ps3_alloc_event_irq(cpu, virq); if (result) return result; @@ -196,6 +331,8 @@ int ps3_disconnect_event_irq(const struc /** * ps3_alloc_vuart_irq - Configure the system virtual uart virq. + * @cpu: enum ps3_cpu_binding indicating the cpu the interrupt should be + * serviced on. * @virt_addr_bmp: The caller supplied virtual uart interrupt bitmap. * @virq: The assigned Linux virq. * @@ -203,13 +340,14 @@ int ps3_disconnect_event_irq(const struc * freeing the interrupt will return a wrong state error. */ -int ps3_alloc_vuart_irq(void* virt_addr_bmp, unsigned int *virq) +int ps3_alloc_vuart_irq(enum ps3_cpu_binding cpu, void* virt_addr_bmp, + unsigned int *virq) { int result; unsigned long outlet; - unsigned long lpar_addr; + u64 lpar_addr; - BUG_ON(!is_kernel_addr((unsigned long)virt_addr_bmp)); + BUG_ON(!is_kernel_addr((u64)virt_addr_bmp)); lpar_addr = ps3_mm_phys_to_lpar(__pa(virt_addr_bmp)); @@ -221,12 +359,10 @@ int ps3_alloc_vuart_irq(void* virt_addr_ return result; } - *virq = irq_create_mapping(NULL, outlet); - - pr_debug("%s:%d: outlet %lu, virq %u\n", __func__, __LINE__, - outlet, *virq); + result = ps3_alloc_irq(cpu, outlet, virq); + BUG_ON(result); - return 0; + return result; } int ps3_free_vuart_irq(unsigned int virq) @@ -241,21 +377,23 @@ int ps3_free_vuart_irq(unsigned int virq return result; } - irq_dispose_mapping(virq); + ps3_free_irq(virq); return result; } /** * ps3_alloc_spe_irq - Configure an spe virq. + * @cpu: enum ps3_cpu_binding indicating the cpu the interrupt should be + * serviced on. * @spe_id: The spe_id returned from lv1_construct_logical_spe(). * @class: The spe interrupt class {0,1,2}. * @virq: The assigned Linux virq. * */ -int ps3_alloc_spe_irq(unsigned long spe_id, unsigned int class, - unsigned int *virq) +int ps3_alloc_spe_irq(enum ps3_cpu_binding cpu, unsigned long spe_id, + unsigned int class, unsigned int *virq) { int result; unsigned long outlet; @@ -270,73 +408,24 @@ int ps3_alloc_spe_irq(unsigned long spe_ return result; } - *virq = irq_create_mapping(NULL, outlet); - - pr_debug("%s:%d: spe_id %lu, class %u, outlet %lu, virq %u\n", - __func__, __LINE__, spe_id, class, outlet, *virq); + result = ps3_alloc_irq(cpu, outlet, virq); + BUG_ON(result); - return 0; + return result; } int ps3_free_spe_irq(unsigned int virq) { - irq_dispose_mapping(virq); + ps3_free_irq(virq); return 0; } + #define PS3_INVALID_OUTLET ((irq_hw_number_t)-1) #define PS3_PLUG_MAX 63 -/** - * struct bmp - a per cpu irq status and mask bitmap structure - * @status: 256 bit status bitmap indexed by plug - * @unused_1: - * @mask: 256 bit mask bitmap indexed by plug - * @unused_2: - * @lock: - * @ipi_debug_brk_mask: - * - * The HV mantains per SMT thread mappings of HV outlet to HV plug on - * behalf of the guest. These mappings are implemented as 256 bit guest - * supplied bitmaps indexed by plug number. The address of the bitmaps are - * registered with the HV through lv1_configure_irq_state_bitmap(). - * - * The HV supports 256 plugs per thread, assigned as {0..255}, for a total - * of 512 plugs supported on a processor. To simplify the logic this - * implementation equates HV plug value to linux virq value, constrains each - * interrupt to have a system wide unique plug number, and limits the range - * of the plug values to map into the first dword of the bitmaps. This - * gives a usable range of plug values of {NUM_ISA_INTERRUPTS..63}. Note - * that there is no constraint on how many in this set an individual thread - * can aquire. - */ - -struct bmp { - struct { - unsigned long status; - unsigned long unused_1[3]; - unsigned long mask; - unsigned long unused_2[3]; - } __attribute__ ((packed)); - spinlock_t lock; - unsigned long ipi_debug_brk_mask; -}; - -/** - * struct private - a per cpu data structure - * @node: HV node id - * @cpu: HV thread id - * @bmp: an HV bmp structure - */ - -struct private { - unsigned long node; - unsigned int cpu; - struct bmp bmp; -}; - #if defined(DEBUG) -static void _dump_64_bmp(const char *header, const unsigned long *p, unsigned cpu, +static void _dump_64_bmp(const char *header, const u64 *p, unsigned cpu, const char* func, int line) { pr_debug("%s:%d: %s %u {%04lx_%04lx_%04lx_%04lx}\n", @@ -346,14 +435,14 @@ static void _dump_64_bmp(const char *hea } static void __attribute__ ((unused)) _dump_256_bmp(const char *header, - const unsigned long *p, unsigned cpu, const char* func, int line) + const u64 *p, unsigned cpu, const char* func, int line) { pr_debug("%s:%d: %s %u {%016lx:%016lx:%016lx:%016lx}\n", func, line, header, cpu, p[0], p[1], p[2], p[3]); } #define dump_bmp(_x) _dump_bmp(_x, __func__, __LINE__) -static void _dump_bmp(struct private* pd, const char* func, int line) +static void _dump_bmp(struct ps3_private* pd, const char* func, int line) { unsigned long flags; @@ -364,7 +453,7 @@ static void _dump_bmp(struct private* pd } #define dump_mask(_x) _dump_mask(_x, __func__, __LINE__) -static void __attribute__ ((unused)) _dump_mask(struct private* pd, +static void __attribute__ ((unused)) _dump_mask(struct ps3_private* pd, const char* func, int line) { unsigned long flags; @@ -374,109 +463,94 @@ static void __attribute__ ((unused)) _du spin_unlock_irqrestore(&pd->bmp.lock, flags); } #else -static void dump_bmp(struct private* pd) {}; +static void dump_bmp(struct ps3_private* pd) {}; #endif /* defined(DEBUG) */ -static void chip_mask(unsigned int virq) +static void ps3_chip_mask(unsigned int virq) { + struct ps3_private *pd = get_irq_chip_data(virq); + u64 bit = 0x8000000000000000UL >> virq; + u64 *p = &pd->bmp.mask; + u64 old; unsigned long flags; - struct private *pd = get_irq_chip_data(virq); pr_debug("%s:%d: cpu %u, virq %d\n", __func__, __LINE__, pd->cpu, virq); - BUG_ON(virq < NUM_ISA_INTERRUPTS); - BUG_ON(virq > PS3_PLUG_MAX); - - spin_lock_irqsave(&pd->bmp.lock, flags); - pd->bmp.mask &= ~(0x8000000000000000UL >> virq); - spin_unlock_irqrestore(&pd->bmp.lock, flags); + local_irq_save(flags); + asm volatile( + "1: ldarx %0,0,%3\n" + "andc %0,%0,%2\n" + "stdcx. %0,0,%3\n" + "bne- 1b" + : "=&r" (old), "+m" (*p) + : "r" (bit), "r" (p) + : "cc" ); lv1_did_update_interrupt_mask(pd->node, pd->cpu); + local_irq_restore(flags); } -static void chip_unmask(unsigned int virq) +static void ps3_chip_unmask(unsigned int virq) { + struct ps3_private *pd = get_irq_chip_data(virq); + u64 bit = 0x8000000000000000UL >> virq; + u64 *p = &pd->bmp.mask; + u64 old; unsigned long flags; - struct private *pd = get_irq_chip_data(virq); pr_debug("%s:%d: cpu %u, virq %d\n", __func__, __LINE__, pd->cpu, virq); - BUG_ON(virq < NUM_ISA_INTERRUPTS); - BUG_ON(virq > PS3_PLUG_MAX); - - spin_lock_irqsave(&pd->bmp.lock, flags); - pd->bmp.mask |= (0x8000000000000000UL >> virq); - spin_unlock_irqrestore(&pd->bmp.lock, flags); + local_irq_save(flags); + asm volatile( + "1: ldarx %0,0,%3\n" + "or %0,%0,%2\n" + "stdcx. %0,0,%3\n" + "bne- 1b" + : "=&r" (old), "+m" (*p) + : "r" (bit), "r" (p) + : "cc" ); lv1_did_update_interrupt_mask(pd->node, pd->cpu); + local_irq_restore(flags); } -static void chip_eoi(unsigned int virq) +static void ps3_chip_eoi(unsigned int virq) { - lv1_end_of_interrupt(virq); + const struct ps3_private *pd = get_irq_chip_data(virq); + lv1_end_of_interrupt_ext(pd->node, pd->cpu, virq); } static struct irq_chip irq_chip = { .typename = "ps3", - .mask = chip_mask, - .unmask = chip_unmask, - .eoi = chip_eoi, + .mask = ps3_chip_mask, + .unmask = ps3_chip_unmask, + .eoi = ps3_chip_eoi, }; -static void host_unmap(struct irq_host *h, unsigned int virq) +static void ps3_host_unmap(struct irq_host *h, unsigned int virq) { - int result; - - pr_debug("%s:%d: virq %d\n", __func__, __LINE__, virq); - - lv1_disconnect_irq_plug(virq); - - result = set_irq_chip_data(virq, NULL); - BUG_ON(result); + set_irq_chip_data(virq, NULL); } -static DEFINE_PER_CPU(struct private, private); - -static int host_map(struct irq_host *h, unsigned int virq, +static int ps3_host_map(struct irq_host *h, unsigned int virq, irq_hw_number_t hwirq) { - int result; - unsigned int cpu; - - pr_debug(" -> %s:%d\n", __func__, __LINE__); - pr_debug("%s:%d: hwirq %lu => virq %u\n", __func__, __LINE__, hwirq, + pr_debug("%s:%d: hwirq %lu, virq %u\n", __func__, __LINE__, hwirq, virq); - /* bind this virq to a cpu */ - - preempt_disable(); - cpu = smp_processor_id(); - result = lv1_connect_irq_plug(virq, hwirq); - preempt_enable(); - - if (result) { - pr_info("%s:%d: lv1_connect_irq_plug failed:" - " %s\n", __func__, __LINE__, ps3_result(result)); - return -EPERM; - } - - result = set_irq_chip_data(virq, &per_cpu(private, cpu)); - BUG_ON(result); - set_irq_chip_and_handler(virq, &irq_chip, handle_fasteoi_irq); - pr_debug(" <- %s:%d\n", __func__, __LINE__); - return result; + return 0; } -static struct irq_host_ops host_ops = { - .map = host_map, - .unmap = host_unmap, +static struct irq_host_ops ps3_host_ops = { + .map = ps3_host_map, + .unmap = ps3_host_unmap, }; void __init ps3_register_ipi_debug_brk(unsigned int cpu, unsigned int virq) { - struct private *pd = &per_cpu(private, cpu); + struct ps3_private *pd = &per_cpu(ps3_private, cpu); pd->bmp.ipi_debug_brk_mask = 0x8000000000000000UL >> virq; @@ -484,57 +558,32 @@ void __init ps3_register_ipi_debug_brk(u cpu, virq, pd->bmp.ipi_debug_brk_mask); } -static int bmp_get_and_clear_status_bit(struct bmp *m) +unsigned int ps3_get_irq(void) { - unsigned long flags; - unsigned int bit; - unsigned long x; - - spin_lock_irqsave(&m->lock, flags); + struct ps3_private *pd = &__get_cpu_var(ps3_private); + u64 x = (pd->bmp.status & pd->bmp.mask); + unsigned int plug; /* check for ipi break first to stop this cpu ASAP */ - if (m->status & m->ipi_debug_brk_mask) { - m->status &= ~m->ipi_debug_brk_mask; - spin_unlock_irqrestore(&m->lock, flags); - return __ilog2(m->ipi_debug_brk_mask); - } - - x = (m->status & m->mask); + if (x & pd->bmp.ipi_debug_brk_mask) + x &= pd->bmp.ipi_debug_brk_mask; - for (bit = NUM_ISA_INTERRUPTS, x <<= bit; x; bit++, x <<= 1) - if (x & 0x8000000000000000UL) { - m->status &= ~(0x8000000000000000UL >> bit); - spin_unlock_irqrestore(&m->lock, flags); - return bit; - } + asm volatile("cntlzd %0,%1" : "=r" (plug) : "r" (x)); + plug &= 0x3f; - spin_unlock_irqrestore(&m->lock, flags); - - pr_debug("%s:%d: not found\n", __func__, __LINE__); - return -1; -} - -unsigned int ps3_get_irq(void) -{ - int plug; - - struct private *pd = &__get_cpu_var(private); - - plug = bmp_get_and_clear_status_bit(&pd->bmp); - - if (plug < 1) { + if (unlikely(plug) == NO_IRQ) { pr_debug("%s:%d: no plug found: cpu %u\n", __func__, __LINE__, pd->cpu); - dump_bmp(&per_cpu(private, 0)); - dump_bmp(&per_cpu(private, 1)); + dump_bmp(&per_cpu(ps3_private, 0)); + dump_bmp(&per_cpu(ps3_private, 1)); return NO_IRQ; } #if defined(DEBUG) - if (plug < NUM_ISA_INTERRUPTS || plug > PS3_PLUG_MAX) { - dump_bmp(&per_cpu(private, 0)); - dump_bmp(&per_cpu(private, 1)); + if (unlikely(plug < NUM_ISA_INTERRUPTS || plug > PS3_PLUG_MAX)) { + dump_bmp(&per_cpu(ps3_private, 0)); + dump_bmp(&per_cpu(ps3_private, 1)); BUG(); } #endif @@ -544,26 +593,27 @@ #endif void __init ps3_init_IRQ(void) { int result; - unsigned long node; unsigned cpu; struct irq_host *host; - lv1_get_logical_ppe_id(&node); - - host = irq_alloc_host(IRQ_HOST_MAP_NOMAP, 0, &host_ops, + host = irq_alloc_host(IRQ_HOST_MAP_NOMAP, 0, &ps3_host_ops, PS3_INVALID_OUTLET); irq_set_default_host(host); irq_set_virq_count(PS3_PLUG_MAX + 1); for_each_possible_cpu(cpu) { - struct private *pd = &per_cpu(private, cpu); + struct ps3_private *pd = &per_cpu(ps3_private, cpu); - pd->node = node; - pd->cpu = cpu; + lv1_get_logical_ppe_id(&pd->node); + pd->cpu = get_hard_smp_processor_id(cpu); spin_lock_init(&pd->bmp.lock); - result = lv1_configure_irq_state_bitmap(node, cpu, - ps3_mm_phys_to_lpar(__pa(&pd->bmp.status))); + pr_debug("%s:%d: node %lu, cpu %d, bmp %lxh\n", __func__, + __LINE__, pd->node, pd->cpu, + ps3_mm_phys_to_lpar(__pa(&pd->bmp))); + + result = lv1_configure_irq_state_bitmap(pd->node, pd->cpu, + ps3_mm_phys_to_lpar(__pa(&pd->bmp))); if (result) pr_debug("%s:%d: lv1_configure_irq_state_bitmap failed:" diff --git a/arch/powerpc/platforms/ps3/mm.c b/arch/powerpc/platforms/ps3/mm.c index 49c0d01..42354de 100644 --- a/arch/powerpc/platforms/ps3/mm.c +++ b/arch/powerpc/platforms/ps3/mm.c @@ -25,7 +25,6 @@ #include #include #include #include -#include #include #include "platform.h" diff --git a/arch/powerpc/platforms/ps3/os-area.c b/arch/powerpc/platforms/ps3/os-area.c index 5835830..5c3da08 100644 --- a/arch/powerpc/platforms/ps3/os-area.c +++ b/arch/powerpc/platforms/ps3/os-area.c @@ -22,7 +22,6 @@ #include #include #include -#include #include "platform.h" @@ -59,7 +58,7 @@ struct os_area_header { u32 ldr_format; u32 ldr_size; u32 _reserved_2[6]; -} __attribute__ ((packed)); +}; enum { PARAM_BOOT_FLAG_GAME_OS = 0, @@ -67,13 +66,6 @@ enum { }; enum { - PARAM_AV_MULTI_OUT_NTSC = 0, - PARAM_AV_MULTI_OUT_PAL_RGB = 1, - PARAM_AV_MULTI_OUT_PAL_YCBCR = 2, - PARAM_AV_MULTI_OUT_SECAM = 3, -}; - -enum { PARAM_CTRL_BUTTON_O_IS_YES = 0, PARAM_CTRL_BUTTON_X_IS_YES = 1, }; @@ -114,7 +106,7 @@ struct os_area_params { u8 dns_primary[4]; u8 dns_secondary[4]; u8 _reserved_5[8]; -} __attribute__ ((packed)); +}; /** * struct saved_params - Static working copies of data from the 'Other OS' area. @@ -257,3 +249,13 @@ u64 ps3_os_area_rtc_diff(void) { return saved_params.rtc_diff ? saved_params.rtc_diff : 946684800UL; } + +/** + * ps3_os_area_get_av_multi_out - Returns the default video mode. + */ + +enum ps3_param_av_multi_out ps3_os_area_get_av_multi_out(void) +{ + return saved_params.av_multi_out; +} +EXPORT_SYMBOL_GPL(ps3_os_area_get_av_multi_out); diff --git a/arch/powerpc/platforms/ps3/platform.h b/arch/powerpc/platforms/ps3/platform.h index 23b111b..ca04f03 100644 --- a/arch/powerpc/platforms/ps3/platform.h +++ b/arch/powerpc/platforms/ps3/platform.h @@ -22,6 +22,9 @@ #if !defined(_PS3_PLATFORM_H) #define _PS3_PLATFORM_H #include +#include + +#include /* htab */ @@ -65,4 +68,152 @@ #else static inline void ps3_spu_set_platform (void) {} #endif +/* repository bus info */ + +enum ps3_bus_type { + PS3_BUS_TYPE_SB = 4, + PS3_BUS_TYPE_STORAGE = 5, +}; + +enum ps3_dev_type { + PS3_DEV_TYPE_STOR_DISK = TYPE_DISK, /* 0 */ + PS3_DEV_TYPE_SB_GELIC = 3, + PS3_DEV_TYPE_SB_USB = 4, + PS3_DEV_TYPE_STOR_ROM = TYPE_ROM, /* 5 */ + PS3_DEV_TYPE_SB_GPIO = 6, + PS3_DEV_TYPE_STOR_FLASH = TYPE_RBC, /* 14 */ +}; + +int ps3_repository_read_bus_str(unsigned int bus_index, const char *bus_str, + u64 *value); +int ps3_repository_read_bus_id(unsigned int bus_index, unsigned int *bus_id); +int ps3_repository_read_bus_type(unsigned int bus_index, + enum ps3_bus_type *bus_type); +int ps3_repository_read_bus_num_dev(unsigned int bus_index, + unsigned int *num_dev); + +/* repository bus device info */ + +enum ps3_interrupt_type { + PS3_INTERRUPT_TYPE_EVENT_PORT = 2, + PS3_INTERRUPT_TYPE_SB_OHCI = 3, + PS3_INTERRUPT_TYPE_SB_EHCI = 4, + PS3_INTERRUPT_TYPE_OTHER = 5, +}; + +enum ps3_reg_type { + PS3_REG_TYPE_SB_OHCI = 3, + PS3_REG_TYPE_SB_EHCI = 4, + PS3_REG_TYPE_SB_GPIO = 5, +}; + +int ps3_repository_read_dev_str(unsigned int bus_index, + unsigned int dev_index, const char *dev_str, u64 *value); +int ps3_repository_read_dev_id(unsigned int bus_index, unsigned int dev_index, + unsigned int *dev_id); +int ps3_repository_read_dev_type(unsigned int bus_index, + unsigned int dev_index, enum ps3_dev_type *dev_type); +int ps3_repository_read_dev_intr(unsigned int bus_index, + unsigned int dev_index, unsigned int intr_index, + enum ps3_interrupt_type *intr_type, unsigned int *interrupt_id); +int ps3_repository_read_dev_reg_type(unsigned int bus_index, + unsigned int dev_index, unsigned int reg_index, + enum ps3_reg_type *reg_type); +int ps3_repository_read_dev_reg_addr(unsigned int bus_index, + unsigned int dev_index, unsigned int reg_index, u64 *bus_addr, + u64 *len); +int ps3_repository_read_dev_reg(unsigned int bus_index, + unsigned int dev_index, unsigned int reg_index, + enum ps3_reg_type *reg_type, u64 *bus_addr, u64 *len); + +/* repository bus enumerators */ + +struct ps3_repository_device { + unsigned int bus_index; + unsigned int dev_index; + struct ps3_device_id did; +}; + +int ps3_repository_find_device(enum ps3_bus_type bus_type, + enum ps3_dev_type dev_type, + const struct ps3_repository_device *start_dev, + struct ps3_repository_device *dev); +static inline int ps3_repository_find_first_device( + enum ps3_bus_type bus_type, enum ps3_dev_type dev_type, + struct ps3_repository_device *dev) +{ + return ps3_repository_find_device(bus_type, dev_type, NULL, dev); +} +int ps3_repository_find_interrupt(const struct ps3_repository_device *dev, + enum ps3_interrupt_type intr_type, unsigned int *interrupt_id); +int ps3_repository_find_reg(const struct ps3_repository_device *dev, + enum ps3_reg_type reg_type, u64 *bus_addr, u64 *len); + +/* repository block device info */ + +int ps3_repository_read_stor_dev_port(unsigned int bus_index, + unsigned int dev_index, u64 *port); +int ps3_repository_read_stor_dev_blk_size(unsigned int bus_index, + unsigned int dev_index, u64 *blk_size); +int ps3_repository_read_stor_dev_num_blocks(unsigned int bus_index, + unsigned int dev_index, u64 *num_blocks); +int ps3_repository_read_stor_dev_num_regions(unsigned int bus_index, + unsigned int dev_index, unsigned int *num_regions); +int ps3_repository_read_stor_dev_region_id(unsigned int bus_index, + unsigned int dev_index, unsigned int region_index, + unsigned int *region_id); +int ps3_repository_read_stor_dev_region_size(unsigned int bus_index, + unsigned int dev_index, unsigned int region_index, u64 *region_size); +int ps3_repository_read_stor_dev_region_start(unsigned int bus_index, + unsigned int dev_index, unsigned int region_index, u64 *region_start); +int ps3_repository_read_stor_dev_info(unsigned int bus_index, + unsigned int dev_index, u64 *port, u64 *blk_size, + u64 *num_blocks, unsigned int *num_regions); +int ps3_repository_read_stor_dev_region(unsigned int bus_index, + unsigned int dev_index, unsigned int region_index, + unsigned int *region_id, u64 *region_start, u64 *region_size); + +/* repository pu and memory info */ + +int ps3_repository_read_num_pu(unsigned int *num_pu); +int ps3_repository_read_ppe_id(unsigned int *pu_index, unsigned int *ppe_id); +int ps3_repository_read_rm_base(unsigned int ppe_id, u64 *rm_base); +int ps3_repository_read_rm_size(unsigned int ppe_id, u64 *rm_size); +int ps3_repository_read_region_total(u64 *region_total); +int ps3_repository_read_mm_info(u64 *rm_base, u64 *rm_size, + u64 *region_total); + +/* repository pme info */ + +int ps3_repository_read_num_be(unsigned int *num_be); +int ps3_repository_read_be_node_id(unsigned int be_index, u64 *node_id); +int ps3_repository_read_tb_freq(u64 node_id, u64 *tb_freq); +int ps3_repository_read_be_tb_freq(unsigned int be_index, u64 *tb_freq); + +/* repository 'Other OS' area */ + +int ps3_repository_read_boot_dat_addr(u64 *lpar_addr); +int ps3_repository_read_boot_dat_size(unsigned int *size); +int ps3_repository_read_boot_dat_info(u64 *lpar_addr, unsigned int *size); + +/* repository spu info */ + +/** + * enum spu_resource_type - Type of spu resource. + * @spu_resource_type_shared: Logical spu is shared with other partions. + * @spu_resource_type_exclusive: Logical spu is not shared with other partions. + * + * Returned by ps3_repository_read_spu_resource_id(). + */ + +enum ps3_spu_resource_type { + PS3_SPU_RESOURCE_TYPE_SHARED = 0, + PS3_SPU_RESOURCE_TYPE_EXCLUSIVE = 0x8000000000000000UL, +}; + +int ps3_repository_read_num_spu_reserved(unsigned int *num_spu_reserved); +int ps3_repository_read_num_spu_resource_id(unsigned int *num_resource_id); +int ps3_repository_read_spu_resource_id(unsigned int res_index, + enum ps3_spu_resource_type* resource_type, unsigned int *resource_id); + #endif diff --git a/arch/powerpc/platforms/ps3/repository.c b/arch/powerpc/platforms/ps3/repository.c index 273a0d6..ae586a0 100644 --- a/arch/powerpc/platforms/ps3/repository.c +++ b/arch/powerpc/platforms/ps3/repository.c @@ -18,9 +18,10 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -#include #include +#include "platform.h" + enum ps3_vendor_id { PS3_VENDOR_ID_NONE = 0, PS3_VENDOR_ID_SONY = 0x8000000000000000UL, @@ -257,7 +258,7 @@ int ps3_repository_read_dev_type(unsigne int ps3_repository_read_dev_intr(unsigned int bus_index, unsigned int dev_index, unsigned int intr_index, - unsigned int *intr_type, unsigned int* interrupt_id) + enum ps3_interrupt_type *intr_type, unsigned int* interrupt_id) { int result; u64 v1; @@ -275,7 +276,8 @@ int ps3_repository_read_dev_intr(unsigne } int ps3_repository_read_dev_reg_type(unsigned int bus_index, - unsigned int dev_index, unsigned int reg_index, unsigned int *reg_type) + unsigned int dev_index, unsigned int reg_index, + enum ps3_reg_type *reg_type) { int result; u64 v1; @@ -302,8 +304,8 @@ int ps3_repository_read_dev_reg_addr(uns } int ps3_repository_read_dev_reg(unsigned int bus_index, - unsigned int dev_index, unsigned int reg_index, unsigned int *reg_type, - u64 *bus_addr, u64 *len) + unsigned int dev_index, unsigned int reg_index, + enum ps3_reg_type *reg_type, u64 *bus_addr, u64 *len) { int result = ps3_repository_read_dev_reg_type(bus_index, dev_index, reg_index, reg_type); @@ -343,7 +345,7 @@ int ps3_repository_dump_resource_info(un } for (res_index = 0; res_index < 10; res_index++) { - enum ps3_region_type reg_type; + enum ps3_reg_type reg_type; u64 bus_addr; u64 len; @@ -367,7 +369,55 @@ int ps3_repository_dump_resource_info(un return result; } -static int dump_device_info(unsigned int bus_index, unsigned int num_dev) +static int dump_stor_dev_info(unsigned int bus_index, unsigned int dev_index) +{ + int result = 0; + unsigned int num_regions, region_index; + u64 port, blk_size, num_blocks; + + pr_debug(" -> %s:%d: (%u:%u)\n", __func__, __LINE__, + bus_index, dev_index); + + result = ps3_repository_read_stor_dev_info(bus_index, dev_index, &port, + &blk_size, &num_blocks, &num_regions); + if (result) { + pr_debug("%s:%d ps3_repository_read_stor_dev_info" + " (%u:%u) failed\n", __func__, __LINE__, + bus_index, dev_index); + goto out; + } + + pr_debug("%s:%d (%u:%u): port %lu, blk_size %lu, num_blocks " + "%lu, num_regions %u\n", + __func__, __LINE__, bus_index, dev_index, port, + blk_size, num_blocks, num_regions); + + for (region_index = 0; region_index < num_regions; region_index++) { + unsigned int region_id; + u64 region_start, region_size; + + result = ps3_repository_read_stor_dev_region(bus_index, + dev_index, region_index, ®ion_id, ®ion_start, + ®ion_size); + if (result) { + pr_debug("%s:%d ps3_repository_read_stor_dev_region" + " (%u:%u) failed\n", __func__, __LINE__, + bus_index, dev_index); + break; + } + + pr_debug("%s:%d (%u:%u) region_id %u, start %lxh, size %lxh\n", + __func__, __LINE__, bus_index, dev_index, region_id, + region_start, region_size); + } + +out: + pr_debug(" <- %s:%d\n", __func__, __LINE__); + return result; +} + +static int dump_device_info(unsigned int bus_index, enum ps3_bus_type bus_type, + unsigned int num_dev) { int result = 0; unsigned int dev_index; @@ -402,6 +452,9 @@ static int dump_device_info(unsigned int __LINE__, bus_index, dev_index, dev_type, dev_id); ps3_repository_dump_resource_info(bus_index, dev_index); + + if (bus_type == PS3_BUS_TYPE_STORAGE) + dump_stor_dev_info(bus_index, dev_index); } pr_debug(" <- %s:%d\n", __func__, __LINE__); @@ -452,7 +505,7 @@ int ps3_repository_dump_bus_info(void) __func__, __LINE__, bus_index, bus_type, bus_id, num_dev); - dump_device_info(bus_index, num_dev); + dump_device_info(bus_index, bus_type, num_dev); } pr_debug(" <- %s:%d\n", __func__, __LINE__); @@ -487,7 +540,8 @@ static int find_device(unsigned int bus_ break; } - BUG_ON(dev_index == num_dev); + if (dev_index == num_dev) + return -1; pr_debug("%s:%d: found dev_type %u at dev_index %u\n", __func__, __LINE__, dev_type, dev_index); @@ -521,7 +575,7 @@ int ps3_repository_find_device (enum ps3 pr_debug("%s:%d: find bus_type %u, dev_type %u\n", __func__, __LINE__, bus_type, dev_type); - dev->bus_index = UINT_MAX; + BUG_ON(start_dev && start_dev->bus_index > 10); for (bus_index = start_dev ? start_dev->bus_index : 0; bus_index < 10; bus_index++) { @@ -532,13 +586,15 @@ int ps3_repository_find_device (enum ps3 if (result) { pr_debug("%s:%d read_bus_type failed\n", __func__, __LINE__); + dev->bus_index = UINT_MAX; return result; } if (x == bus_type) break; } - BUG_ON(bus_index == 10); + if (bus_index >= 10) + return -ENODEV; pr_debug("%s:%d: found bus_type %u at bus_index %u\n", __func__, __LINE__, bus_type, bus_index); @@ -604,7 +660,8 @@ int ps3_repository_find_interrupt(const } } - BUG_ON(res_index == 10); + if (res_index == 10) + return -ENODEV; pr_debug("%s:%d: found intr_type %u at res_index %u\n", __func__, __LINE__, intr_type, res_index); @@ -612,8 +669,8 @@ int ps3_repository_find_interrupt(const return result; } -int ps3_repository_find_region(const struct ps3_repository_device *dev, - enum ps3_region_type reg_type, u64 *bus_addr, u64 *len) +int ps3_repository_find_reg(const struct ps3_repository_device *dev, + enum ps3_reg_type reg_type, u64 *bus_addr, u64 *len) { int result = 0; unsigned int res_index; @@ -623,7 +680,7 @@ int ps3_repository_find_region(const str *bus_addr = *len = 0; for (res_index = 0; res_index < 10; res_index++) { - enum ps3_region_type t; + enum ps3_reg_type t; u64 a; u64 l; @@ -643,7 +700,8 @@ int ps3_repository_find_region(const str } } - BUG_ON(res_index == 10); + if (res_index == 10) + return -ENODEV; pr_debug("%s:%d: found reg_type %u at res_index %u\n", __func__, __LINE__, reg_type, res_index); @@ -651,6 +709,136 @@ int ps3_repository_find_region(const str return result; } +int ps3_repository_read_stor_dev_port(unsigned int bus_index, + unsigned int dev_index, u64 *port) +{ + return read_node(PS3_LPAR_ID_PME, + make_first_field("bus", bus_index), + make_field("dev", dev_index), + make_field("port", 0), + 0, port, 0); +} + +int ps3_repository_read_stor_dev_blk_size(unsigned int bus_index, + unsigned int dev_index, u64 *blk_size) +{ + return read_node(PS3_LPAR_ID_PME, + make_first_field("bus", bus_index), + make_field("dev", dev_index), + make_field("blk_size", 0), + 0, blk_size, 0); +} + +int ps3_repository_read_stor_dev_num_blocks(unsigned int bus_index, + unsigned int dev_index, u64 *num_blocks) +{ + return read_node(PS3_LPAR_ID_PME, + make_first_field("bus", bus_index), + make_field("dev", dev_index), + make_field("n_blocks", 0), + 0, num_blocks, 0); +} + +int ps3_repository_read_stor_dev_num_regions(unsigned int bus_index, + unsigned int dev_index, unsigned int *num_regions) +{ + int result; + u64 v1; + + result = read_node(PS3_LPAR_ID_PME, + make_first_field("bus", bus_index), + make_field("dev", dev_index), + make_field("n_regs", 0), + 0, &v1, 0); + *num_regions = v1; + return result; +} + +int ps3_repository_read_stor_dev_region_id(unsigned int bus_index, + unsigned int dev_index, unsigned int region_index, + unsigned int *region_id) +{ + int result; + u64 v1; + + result = read_node(PS3_LPAR_ID_PME, + make_first_field("bus", bus_index), + make_field("dev", dev_index), + make_field("region", region_index), + make_field("id", 0), + &v1, 0); + *region_id = v1; + return result; +} + +int ps3_repository_read_stor_dev_region_size(unsigned int bus_index, + unsigned int dev_index, unsigned int region_index, u64 *region_size) +{ + return read_node(PS3_LPAR_ID_PME, + make_first_field("bus", bus_index), + make_field("dev", dev_index), + make_field("region", region_index), + make_field("size", 0), + region_size, 0); +} + +int ps3_repository_read_stor_dev_region_start(unsigned int bus_index, + unsigned int dev_index, unsigned int region_index, u64 *region_start) +{ + return read_node(PS3_LPAR_ID_PME, + make_first_field("bus", bus_index), + make_field("dev", dev_index), + make_field("region", region_index), + make_field("start", 0), + region_start, 0); +} + +int ps3_repository_read_stor_dev_info(unsigned int bus_index, + unsigned int dev_index, u64 *port, u64 *blk_size, + u64 *num_blocks, unsigned int *num_regions) +{ + int result; + + result = ps3_repository_read_stor_dev_port(bus_index, dev_index, port); + if (result) + return result; + + result = ps3_repository_read_stor_dev_blk_size(bus_index, dev_index, + blk_size); + if (result) + return result; + + result = ps3_repository_read_stor_dev_num_blocks(bus_index, dev_index, + num_blocks); + if (result) + return result; + + result = ps3_repository_read_stor_dev_num_regions(bus_index, dev_index, + num_regions); + return result; +} + +int ps3_repository_read_stor_dev_region(unsigned int bus_index, + unsigned int dev_index, unsigned int region_index, + unsigned int *region_id, u64 *region_start, u64 *region_size) +{ + int result; + + result = ps3_repository_read_stor_dev_region_id(bus_index, dev_index, + region_index, region_id); + if (result) + return result; + + result = ps3_repository_read_stor_dev_region_start(bus_index, dev_index, + region_index, region_start); + if (result) + return result; + + result = ps3_repository_read_stor_dev_region_size(bus_index, dev_index, + region_index, region_size); + return result; +} + int ps3_repository_read_rm_size(unsigned int ppe_id, u64 *rm_size) { return read_node(PS3_LPAR_ID_CURRENT, diff --git a/arch/powerpc/platforms/ps3/setup.c b/arch/powerpc/platforms/ps3/setup.c index d8b5cad..13d669a 100644 --- a/arch/powerpc/platforms/ps3/setup.c +++ b/arch/powerpc/platforms/ps3/setup.c @@ -24,6 +24,7 @@ #include #include #include #include +#include #include #include @@ -41,10 +42,18 @@ #else #define DBG(fmt...) do{if(0)printk(fmt);}while(0) #endif -static void ps3_show_cpuinfo(struct seq_file *m) +int ps3_get_firmware_version(union ps3_firmware_version *v) { - seq_printf(m, "machine\t\t: %s\n", ppc_md.name); + int result = lv1_get_version_info(&v->raw); + + if (result) { + v->raw = 0; + return -1; + } + + return result; } +EXPORT_SYMBOL_GPL(ps3_get_firmware_version); static void ps3_power_save(void) { @@ -72,10 +81,56 @@ #endif for (;;) ; } + +static void prealloc(struct ps3_prealloc *p) +{ + if (!p->size) + return; + + p->address = __alloc_bootmem(p->size, p->align, __pa(MAX_DMA_ADDRESS)); + if (!p->address) { + printk(KERN_ERR "%s: Cannot allocate %s\n", __FUNCTION__, + p->name); + return; + } + + printk(KERN_INFO "%s: %lu bytes at %p\n", p->name, p->size, + p->address); +} + +#ifdef CONFIG_FB_PS3 +struct ps3_prealloc ps3fb_videomemory = { + .name = "ps3fb videomemory", + .size = CONFIG_FB_PS3_DEFAULT_SIZE_M*1024*1024, + .align = 1024*1024 /* the GPU requires 1 MiB alignment */ +}; +#define prealloc_ps3fb_videomemory() prealloc(&ps3fb_videomemory) + +static int __init early_parse_ps3fb(char *p) +{ + if (!p) + return 1; + + ps3fb_videomemory.size = _ALIGN_UP(memparse(p, &p), + ps3fb_videomemory.align); + return 0; +} +early_param("ps3fb", early_parse_ps3fb); +#else +#define prealloc_ps3fb_videomemory() do { } while (0) +#endif + + static void __init ps3_setup_arch(void) { + union ps3_firmware_version v; + DBG(" -> %s:%d\n", __func__, __LINE__); + ps3_get_firmware_version(&v); + printk(KERN_INFO "PS3 firmware version %u.%u.%u\n", v.major, v.minor, + v.rev); + ps3_spu_set_platform(); ps3_map_htab(); @@ -87,6 +142,7 @@ #ifdef CONFIG_DUMMY_CONSOLE conswitchp = &dummy_con; #endif + prealloc_ps3fb_videomemory(); ppc_md.power_save = ps3_power_save; DBG(" <- %s:%d\n", __func__, __LINE__); @@ -156,7 +212,6 @@ define_machine(ps3) { .name = "PS3", .probe = ps3_probe, .setup_arch = ps3_setup_arch, - .show_cpuinfo = ps3_show_cpuinfo, .init_IRQ = ps3_init_IRQ, .panic = ps3_panic, .get_boot_time = ps3_get_boot_time, diff --git a/arch/powerpc/platforms/ps3/smp.c b/arch/powerpc/platforms/ps3/smp.c index 11d2080..6fb8879 100644 --- a/arch/powerpc/platforms/ps3/smp.c +++ b/arch/powerpc/platforms/ps3/smp.c @@ -23,7 +23,6 @@ #include #include #include -#include #include "platform.h" @@ -111,7 +110,7 @@ static void __init ps3_smp_setup_cpu(int BUILD_BUG_ON(PPC_MSG_DEBUGGER_BREAK != 3); for (i = 0; i < MSG_COUNT; i++) { - result = ps3_alloc_event_irq(&virqs[i]); + result = ps3_alloc_event_irq(cpu, &virqs[i]); if (result) continue; diff --git a/arch/powerpc/platforms/ps3/spu.c b/arch/powerpc/platforms/ps3/spu.c index 644532c..a397e4e 100644 --- a/arch/powerpc/platforms/ps3/spu.c +++ b/arch/powerpc/platforms/ps3/spu.c @@ -26,9 +26,10 @@ #include #include #include -#include #include +#include "platform.h" + /* spu_management_ops */ /** @@ -50,7 +51,7 @@ enum spe_type { */ struct spe_shadow { - u8 padding_0000[0x0140]; + u8 padding_0140[0x0140]; u64 int_status_class0_RW; /* 0x0140 */ u64 int_status_class1_RW; /* 0x0148 */ u64 int_status_class2_RW; /* 0x0150 */ @@ -67,8 +68,7 @@ struct spe_shadow { u8 padding_0c08[0x0f00-0x0c08]; u64 spe_execution_status; /* 0x0f00 */ u8 padding_0f08[0x1000-0x0f08]; -} __attribute__ ((packed)); - +}; /** * enum spe_ex_state - Logical spe execution state. @@ -170,31 +170,6 @@ static int __init construct_spu(struct s return result; } -static int __init add_spu_pages(unsigned long start_addr, unsigned long size) -{ - int result; - unsigned long start_pfn; - unsigned long nr_pages; - struct pglist_data *pgdata; - struct zone *zone; - - BUG_ON(!mem_init_done); - - start_pfn = start_addr >> PAGE_SHIFT; - nr_pages = (size + PAGE_SIZE - 1) >> PAGE_SHIFT; - - pgdata = NODE_DATA(0); - zone = pgdata->node_zones; - - result = __add_pages(zone, start_pfn, nr_pages); - - if (result) - pr_debug("%s:%d: __add_pages failed: (%d)\n", - __func__, __LINE__, result); - - return result; -} - static void spu_unmap(struct spu *spu) { iounmap(spu->priv2); @@ -206,19 +181,6 @@ static void spu_unmap(struct spu *spu) static int __init setup_areas(struct spu *spu) { struct table {char* name; unsigned long addr; unsigned long size;}; - int result; - - /* setup pages */ - - result = add_spu_pages(spu->local_store_phys, LS_SIZE); - if (result) - goto fail_add; - - result = add_spu_pages(spu->problem_phys, sizeof(struct spu_problem)); - if (result) - goto fail_add; - - /* ioremap */ spu_pdata(spu)->shadow = __ioremap( spu_pdata(spu)->shadow_addr, sizeof(struct spe_shadow), @@ -260,28 +222,28 @@ static int __init setup_areas(struct spu fail_ioremap: spu_unmap(spu); -fail_add: - return result; + + return -ENOMEM; } static int __init setup_interrupts(struct spu *spu) { int result; - result = ps3_alloc_spe_irq(spu_pdata(spu)->spe_id, 0, - &spu->irqs[0]); + result = ps3_alloc_spe_irq(PS3_BINDING_CPU_ANY, spu_pdata(spu)->spe_id, + 0, &spu->irqs[0]); if (result) goto fail_alloc_0; - result = ps3_alloc_spe_irq(spu_pdata(spu)->spe_id, 1, - &spu->irqs[1]); + result = ps3_alloc_spe_irq(PS3_BINDING_CPU_ANY, spu_pdata(spu)->spe_id, + 1, &spu->irqs[1]); if (result) goto fail_alloc_1; - result = ps3_alloc_spe_irq(spu_pdata(spu)->spe_id, 2, - &spu->irqs[2]); + result = ps3_alloc_spe_irq(PS3_BINDING_CPU_ANY, spu_pdata(spu)->spe_id, + 2, &spu->irqs[2]); if (result) goto fail_alloc_2; diff --git a/arch/powerpc/platforms/ps3/system-bus.c b/arch/powerpc/platforms/ps3/system-bus.c new file mode 100644 index 0000000..a9f7e4a --- /dev/null +++ b/arch/powerpc/platforms/ps3/system-bus.c @@ -0,0 +1,384 @@ +/* + * PS3 system bus driver. + * + * Copyright (C) 2006 Sony Computer Entertainment Inc. + * Copyright 2006 Sony Corp. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include +#include +#include +#include +#include + +#include +#include +#include + +#include "platform.h" + +#define dump_mmio_region(_a) _dump_mmio_region(_a, __func__, __LINE__) +static void _dump_mmio_region(const struct ps3_mmio_region* r, + const char* func, int line) +{ + pr_debug("%s:%d: dev %u:%u\n", func, line, r->did.bus_id, + r->did.dev_id); + pr_debug("%s:%d: bus_addr %lxh\n", func, line, r->bus_addr); + pr_debug("%s:%d: len %lxh\n", func, line, r->len); + pr_debug("%s:%d: lpar_addr %lxh\n", func, line, r->lpar_addr); +} + +int ps3_mmio_region_create(struct ps3_mmio_region *r) +{ + int result; + + result = lv1_map_device_mmio_region(r->did.bus_id, r->did.dev_id, + r->bus_addr, r->len, r->page_size, &r->lpar_addr); + + if (result) { + pr_debug("%s:%d: lv1_map_device_mmio_region failed: %s\n", + __func__, __LINE__, ps3_result(result)); + r->lpar_addr = 0; + } + + dump_mmio_region(r); + return result; +} +EXPORT_SYMBOL_GPL(ps3_mmio_region_create); + +int ps3_free_mmio_region(struct ps3_mmio_region *r) +{ + int result; + + result = lv1_unmap_device_mmio_region(r->did.bus_id, r->did.dev_id, + r->lpar_addr); + + if (result) + pr_debug("%s:%d: lv1_unmap_device_mmio_region failed: %s\n", + __func__, __LINE__, ps3_result(result)); + + r->lpar_addr = 0; + return result; +} +EXPORT_SYMBOL_GPL(ps3_free_mmio_region); + +static int ps3_system_bus_match(struct device *_dev, + struct device_driver *_drv) +{ + int result; + struct ps3_system_bus_driver *drv = to_ps3_system_bus_driver(_drv); + struct ps3_system_bus_device *dev = to_ps3_system_bus_device(_dev); + + result = dev->match_id == drv->match_id; + + pr_info("%s:%d: dev=%u(%s), drv=%u(%s): %s\n", __func__, __LINE__, + dev->match_id, dev->core.bus_id, drv->match_id, drv->core.name, + (result ? "match" : "miss")); + return result; +} + +static int ps3_system_bus_probe(struct device *_dev) +{ + int result; + struct ps3_system_bus_device *dev = to_ps3_system_bus_device(_dev); + struct ps3_system_bus_driver *drv = + to_ps3_system_bus_driver(_dev->driver); + + result = lv1_open_device(dev->did.bus_id, dev->did.dev_id, 0); + + if (result) { + pr_debug("%s:%d: lv1_open_device failed (%d)\n", + __func__, __LINE__, result); + result = -EACCES; + goto clean_none; + } + + if (dev->d_region->did.bus_id) { + result = ps3_dma_region_create(dev->d_region); + + if (result) { + pr_debug("%s:%d: ps3_dma_region_create failed (%d)\n", + __func__, __LINE__, result); + BUG_ON("check region type"); + result = -EINVAL; + goto clean_device; + } + } + + BUG_ON(!drv); + + if (drv->probe) + result = drv->probe(dev); + else + pr_info("%s:%d: %s no probe method\n", __func__, __LINE__, + dev->core.bus_id); + + if (result) { + pr_debug("%s:%d: drv->probe failed\n", __func__, __LINE__); + goto clean_dma; + } + + return result; + +clean_dma: + ps3_dma_region_free(dev->d_region); +clean_device: + lv1_close_device(dev->did.bus_id, dev->did.dev_id); +clean_none: + return result; +} + +static int ps3_system_bus_remove(struct device *_dev) +{ + struct ps3_system_bus_device *dev = to_ps3_system_bus_device(_dev); + struct ps3_system_bus_driver *drv = + to_ps3_system_bus_driver(_dev->driver); + + if (drv->remove) + drv->remove(dev); + else + pr_info("%s:%d: %s no remove method\n", __func__, __LINE__, + dev->core.bus_id); + + ps3_dma_region_free(dev->d_region); + ps3_free_mmio_region(dev->m_region); + lv1_close_device(dev->did.bus_id, dev->did.dev_id); + + return 0; +} + +struct bus_type ps3_system_bus_type = { + .name = "ps3_system_bus", + .match = ps3_system_bus_match, + .probe = ps3_system_bus_probe, + .remove = ps3_system_bus_remove, +}; + +int __init ps3_system_bus_init(void) +{ + int result; + + if (!firmware_has_feature(FW_FEATURE_PS3_LV1)) + return 0; + + result = bus_register(&ps3_system_bus_type); + BUG_ON(result); + return result; +} + +core_initcall(ps3_system_bus_init); + +/* Allocates a contiguous real buffer and creates mappings over it. + * Returns the virtual address of the buffer and sets dma_handle + * to the dma address (mapping) of the first page. + */ + +static void * ps3_alloc_coherent(struct device *_dev, size_t size, + dma_addr_t *dma_handle, gfp_t flag) +{ + int result; + struct ps3_system_bus_device *dev = to_ps3_system_bus_device(_dev); + unsigned long virt_addr; + + BUG_ON(!dev->d_region->bus_addr); + + flag &= ~(__GFP_DMA | __GFP_HIGHMEM); + flag |= __GFP_ZERO; + + virt_addr = __get_free_pages(flag, get_order(size)); + + if (!virt_addr) { + pr_debug("%s:%d: get_free_pages failed\n", __func__, __LINE__); + goto clean_none; + } + + result = ps3_dma_map(dev->d_region, virt_addr, size, dma_handle); + + if (result) { + pr_debug("%s:%d: ps3_dma_map failed (%d)\n", + __func__, __LINE__, result); + BUG_ON("check region type"); + goto clean_alloc; + } + + return (void*)virt_addr; + +clean_alloc: + free_pages(virt_addr, get_order(size)); +clean_none: + dma_handle = NULL; + return NULL; +} + +static void ps3_free_coherent(struct device *_dev, size_t size, void *vaddr, + dma_addr_t dma_handle) +{ + struct ps3_system_bus_device *dev = to_ps3_system_bus_device(_dev); + + ps3_dma_unmap(dev->d_region, dma_handle, size); + free_pages((unsigned long)vaddr, get_order(size)); +} + +/* Creates TCEs for a user provided buffer. The user buffer must be + * contiguous real kernel storage (not vmalloc). The address of the buffer + * passed here is the kernel (virtual) address of the buffer. The buffer + * need not be page aligned, the dma_addr_t returned will point to the same + * byte within the page as vaddr. + */ + +static dma_addr_t ps3_map_single(struct device *_dev, void *ptr, size_t size, + enum dma_data_direction direction) +{ + struct ps3_system_bus_device *dev = to_ps3_system_bus_device(_dev); + int result; + unsigned long bus_addr; + + result = ps3_dma_map(dev->d_region, (unsigned long)ptr, size, + &bus_addr); + + if (result) { + pr_debug("%s:%d: ps3_dma_map failed (%d)\n", + __func__, __LINE__, result); + } + + return bus_addr; +} + +static void ps3_unmap_single(struct device *_dev, dma_addr_t dma_addr, + size_t size, enum dma_data_direction direction) +{ + struct ps3_system_bus_device *dev = to_ps3_system_bus_device(_dev); + int result; + + result = ps3_dma_unmap(dev->d_region, dma_addr, size); + + if (result) { + pr_debug("%s:%d: ps3_dma_unmap failed (%d)\n", + __func__, __LINE__, result); + } +} + +static int ps3_map_sg(struct device *_dev, struct scatterlist *sg, int nents, + enum dma_data_direction direction) +{ + struct ps3_system_bus_device *dev = to_ps3_system_bus_device(_dev); + int i; + +#if defined(CONFIG_PS3_DYNAMIC_DMA) + BUG_ON("do"); + return -EPERM; +#else + for (i = 0; i < nents; i++, sg++) { + int result = ps3_dma_map(dev->d_region, + page_to_phys(sg->page) + sg->offset, sg->length, + &sg->dma_address); + + if (result) { + pr_debug("%s:%d: ps3_dma_map failed (%d)\n", + __func__, __LINE__, result); + return -EINVAL; + } + + sg->dma_length = sg->length; + } + + return nents; +#endif +} + +static void ps3_unmap_sg(struct device *_dev, struct scatterlist *sg, + int nents, enum dma_data_direction direction) +{ +#if defined(CONFIG_PS3_DYNAMIC_DMA) + BUG_ON("do"); +#endif +} + +static int ps3_dma_supported(struct device *_dev, u64 mask) +{ + return mask >= DMA_32BIT_MASK; +} + +static struct dma_mapping_ops ps3_dma_ops = { + .alloc_coherent = ps3_alloc_coherent, + .free_coherent = ps3_free_coherent, + .map_single = ps3_map_single, + .unmap_single = ps3_unmap_single, + .map_sg = ps3_map_sg, + .unmap_sg = ps3_unmap_sg, + .dma_supported = ps3_dma_supported +}; + +/** + * ps3_system_bus_release_device - remove a device from the system bus + */ + +static void ps3_system_bus_release_device(struct device *_dev) +{ + struct ps3_system_bus_device *dev = to_ps3_system_bus_device(_dev); + kfree(dev); +} + +/** + * ps3_system_bus_device_register - add a device to the system bus + * + * ps3_system_bus_device_register() expects the dev object to be allocated + * dynamically by the caller. The system bus takes ownership of the dev + * object and frees the object in ps3_system_bus_release_device(). + */ + +int ps3_system_bus_device_register(struct ps3_system_bus_device *dev) +{ + int result; + static unsigned int dev_count = 1; + + dev->core.parent = NULL; + dev->core.bus = &ps3_system_bus_type; + dev->core.release = ps3_system_bus_release_device; + + dev->core.archdata.of_node = NULL; + dev->core.archdata.dma_ops = &ps3_dma_ops; + dev->core.archdata.numa_node = 0; + + snprintf(dev->core.bus_id, sizeof(dev->core.bus_id), "sb_%02x", + dev_count++); + + pr_debug("%s:%d add %s\n", __func__, __LINE__, dev->core.bus_id); + + result = device_register(&dev->core); + return result; +} + +EXPORT_SYMBOL_GPL(ps3_system_bus_device_register); + +int ps3_system_bus_driver_register(struct ps3_system_bus_driver *drv) +{ + int result; + + drv->core.bus = &ps3_system_bus_type; + + result = driver_register(&drv->core); + return result; +} + +EXPORT_SYMBOL_GPL(ps3_system_bus_driver_register); + +void ps3_system_bus_driver_unregister(struct ps3_system_bus_driver *drv) +{ + driver_unregister(&drv->core); +} + +EXPORT_SYMBOL_GPL(ps3_system_bus_driver_unregister); diff --git a/arch/powerpc/platforms/pseries/Makefile b/arch/powerpc/platforms/pseries/Makefile index 69590fb..dc0583b 100644 --- a/arch/powerpc/platforms/pseries/Makefile +++ b/arch/powerpc/platforms/pseries/Makefile @@ -9,6 +9,7 @@ obj-$(CONFIG_SMP) += smp.o obj-$(CONFIG_XICS) += xics.o obj-$(CONFIG_SCANLOG) += scanlog.o obj-$(CONFIG_EEH) += eeh.o eeh_cache.o eeh_driver.o eeh_event.o +obj-$(CONFIG_KEXEC) += kexec.o obj-$(CONFIG_HOTPLUG_CPU) += hotplug-cpu.o diff --git a/arch/powerpc/platforms/pseries/eeh.c b/arch/powerpc/platforms/pseries/eeh.c index da6e536..6cedbc0 100644 --- a/arch/powerpc/platforms/pseries/eeh.c +++ b/arch/powerpc/platforms/pseries/eeh.c @@ -747,6 +747,7 @@ struct eeh_early_enable_info { /* Enable eeh for the given device node. */ static void *early_enable_eeh(struct device_node *dn, void *data) { + unsigned int rets[3]; struct eeh_early_enable_info *info = data; int ret; const char *status = get_property(dn, "status", NULL); @@ -803,16 +804,14 @@ #endif regs[0], info->buid_hi, info->buid_lo, EEH_ENABLE); + enable = 0; if (ret == 0) { - eeh_subsystem_enabled = 1; - pdn->eeh_mode |= EEH_MODE_SUPPORTED; pdn->eeh_config_addr = regs[0]; /* If the newer, better, ibm,get-config-addr-info is supported, * then use that instead. */ pdn->eeh_pe_config_addr = 0; if (ibm_get_config_addr_info != RTAS_UNKNOWN_SERVICE) { - unsigned int rets[2]; ret = rtas_call (ibm_get_config_addr_info, 4, 2, rets, pdn->eeh_config_addr, info->buid_hi, info->buid_lo, @@ -820,6 +819,20 @@ #endif if (ret == 0) pdn->eeh_pe_config_addr = rets[0]; } + + /* Some older systems (Power4) allow the + * ibm,set-eeh-option call to succeed even on nodes + * where EEH is not supported. Verify support + * explicitly. */ + ret = read_slot_reset_state(pdn, rets); + if ((ret == 0) && (rets[1] == 1)) + enable = 1; + } + + if (enable) { + eeh_subsystem_enabled = 1; + pdn->eeh_mode |= EEH_MODE_SUPPORTED; + #ifdef DEBUG printk(KERN_DEBUG "EEH: %s: eeh enabled, config=%x pe_config=%x\n", dn->full_name, pdn->eeh_config_addr, pdn->eeh_pe_config_addr); @@ -1065,7 +1078,7 @@ static int proc_eeh_open(struct inode *i return single_open(file, proc_eeh_show, NULL); } -static struct file_operations proc_eeh_operations = { +static const struct file_operations proc_eeh_operations = { .open = proc_eeh_open, .read = seq_read, .llseek = seq_lseek, diff --git a/arch/powerpc/platforms/pseries/eeh_driver.c b/arch/powerpc/platforms/pseries/eeh_driver.c index cbd6b07..a4c0bf8 100644 --- a/arch/powerpc/platforms/pseries/eeh_driver.c +++ b/arch/powerpc/platforms/pseries/eeh_driver.c @@ -446,7 +446,8 @@ excess_failures: */ printk(KERN_ERR "EEH: PCI device at location=%s driver=%s pci addr=%s \n" - "has failed %d times and has been permanently disabled. \n" + "has failed %d times in the last hour " + "and has been permanently disabled. \n" "Please try reseating this device or replacing it.\n", location, drv_str, pci_str, frozen_pdn->eeh_freeze_count); goto perm_error; diff --git a/arch/powerpc/platforms/pseries/firmware.c b/arch/powerpc/platforms/pseries/firmware.c index 1c7b2ba..90522e3 100644 --- a/arch/powerpc/platforms/pseries/firmware.c +++ b/arch/powerpc/platforms/pseries/firmware.c @@ -59,6 +59,7 @@ firmware_features_table[FIRMWARE_MAX_FEA {FW_FEATURE_XDABR, "hcall-xdabr"}, {FW_FEATURE_MULTITCE, "hcall-multi-tce"}, {FW_FEATURE_SPLPAR, "hcall-splpar"}, + {FW_FEATURE_BULK_REMOVE, "hcall-bulk"}, }; /* Build up the firmware features bitmask using the contents of diff --git a/arch/powerpc/platforms/pseries/firmware.h b/arch/powerpc/platforms/pseries/firmware.h deleted file mode 100644 index 714f56f..0000000 --- a/arch/powerpc/platforms/pseries/firmware.h +++ /dev/null @@ -1,17 +0,0 @@ -/* - * Copyright 2006 IBM Corporation. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version - * 2 of the License, or (at your option) any later version. - */ - -#ifndef _PSERIES_FIRMWARE_H -#define _PSERIES_FIRMWARE_H - -#include - -extern void __init fw_feature_init(void); - -#endif /* _PSERIES_FIRMWARE_H */ diff --git a/arch/powerpc/platforms/pseries/hvCall_inst.c b/arch/powerpc/platforms/pseries/hvCall_inst.c index 3ddc049..eae51ef 100644 --- a/arch/powerpc/platforms/pseries/hvCall_inst.c +++ b/arch/powerpc/platforms/pseries/hvCall_inst.c @@ -90,7 +90,7 @@ static int hcall_inst_seq_open(struct in return rc; } -static struct file_operations hcall_inst_seq_fops = { +static const struct file_operations hcall_inst_seq_fops = { .open = hcall_inst_seq_open, .read = seq_read, .llseek = seq_lseek, diff --git a/arch/powerpc/platforms/pseries/kexec.c b/arch/powerpc/platforms/pseries/kexec.c new file mode 100644 index 0000000..af26856 --- /dev/null +++ b/arch/powerpc/platforms/pseries/kexec.c @@ -0,0 +1,72 @@ +/* + * Copyright 2006 Michael Ellerman, IBM Corporation + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + */ + +#include +#include +#include +#include +#include + +#include "pseries.h" +#include "xics.h" +#include "plpar_wrappers.h" + +static void pseries_kexec_cpu_down(int crash_shutdown, int secondary) +{ + /* Don't risk a hypervisor call if we're crashing */ + if (firmware_has_feature(FW_FEATURE_SPLPAR) && !crash_shutdown) { + unsigned long addr; + + addr = __pa(get_slb_shadow()); + if (unregister_slb_shadow(hard_smp_processor_id(), addr)) + printk("SLB shadow buffer deregistration of " + "cpu %u (hw_cpu_id %d) failed\n", + smp_processor_id(), + hard_smp_processor_id()); + + addr = __pa(get_lppaca()); + if (unregister_vpa(hard_smp_processor_id(), addr)) { + printk("VPA deregistration of cpu %u (hw_cpu_id %d) " + "failed\n", smp_processor_id(), + hard_smp_processor_id()); + } + } +} + +static void pseries_kexec_cpu_down_mpic(int crash_shutdown, int secondary) +{ + pseries_kexec_cpu_down(crash_shutdown, secondary); + mpic_teardown_this_cpu(secondary); +} + +void __init setup_kexec_cpu_down_mpic(void) +{ + ppc_md.kexec_cpu_down = pseries_kexec_cpu_down_mpic; +} + +static void pseries_kexec_cpu_down_xics(int crash_shutdown, int secondary) +{ + pseries_kexec_cpu_down(crash_shutdown, secondary); + xics_teardown_cpu(secondary); +} + +void __init setup_kexec_cpu_down_xics(void) +{ + ppc_md.kexec_cpu_down = pseries_kexec_cpu_down_xics; +} + +static int __init pseries_kexec_setup(void) +{ + ppc_md.machine_kexec = default_machine_kexec; + ppc_md.machine_kexec_prepare = default_machine_kexec_prepare; + ppc_md.machine_crash_shutdown = default_machine_crash_shutdown; + + return 0; +} +__initcall(pseries_kexec_setup); diff --git a/arch/powerpc/platforms/pseries/lpar.c b/arch/powerpc/platforms/pseries/lpar.c index 721436d..7496005 100644 --- a/arch/powerpc/platforms/pseries/lpar.c +++ b/arch/powerpc/platforms/pseries/lpar.c @@ -502,23 +502,70 @@ static void pSeries_lpar_hpte_invalidate BUG_ON(lpar_rc != H_SUCCESS); } +/* Flag bits for H_BULK_REMOVE */ +#define HBR_REQUEST 0x4000000000000000UL +#define HBR_RESPONSE 0x8000000000000000UL +#define HBR_END 0xc000000000000000UL +#define HBR_AVPN 0x0200000000000000UL +#define HBR_ANDCOND 0x0100000000000000UL + /* * Take a spinlock around flushes to avoid bouncing the hypervisor tlbie * lock. */ static void pSeries_lpar_flush_hash_range(unsigned long number, int local) { - int i; + unsigned long i, pix, rc; unsigned long flags = 0; struct ppc64_tlb_batch *batch = &__get_cpu_var(ppc64_tlb_batch); int lock_tlbie = !cpu_has_feature(CPU_FTR_LOCKLESS_TLBIE); + unsigned long param[9]; + unsigned long va; + unsigned long hash, index, shift, hidx, slot; + real_pte_t pte; + int psize; if (lock_tlbie) spin_lock_irqsave(&pSeries_lpar_tlbie_lock, flags); - for (i = 0; i < number; i++) - flush_hash_page(batch->vaddr[i], batch->pte[i], - batch->psize, local); + psize = batch->psize; + pix = 0; + for (i = 0; i < number; i++) { + va = batch->vaddr[i]; + pte = batch->pte[i]; + pte_iterate_hashed_subpages(pte, psize, va, index, shift) { + hash = hpt_hash(va, shift); + hidx = __rpte_to_hidx(pte, index); + if (hidx & _PTEIDX_SECONDARY) + hash = ~hash; + slot = (hash & htab_hash_mask) * HPTES_PER_GROUP; + slot += hidx & _PTEIDX_GROUP_IX; + if (!firmware_has_feature(FW_FEATURE_BULK_REMOVE)) { + pSeries_lpar_hpte_invalidate(slot, va, psize, + local); + } else { + param[pix] = HBR_REQUEST | HBR_AVPN | slot; + param[pix+1] = hpte_encode_v(va, psize) & + HPTE_V_AVPN; + pix += 2; + if (pix == 8) { + rc = plpar_hcall9(H_BULK_REMOVE, param, + param[0], param[1], param[2], + param[3], param[4], param[5], + param[6], param[7]); + BUG_ON(rc != H_SUCCESS); + pix = 0; + } + } + } pte_iterate_hashed_end(); + } + if (pix) { + param[pix] = HBR_END; + rc = plpar_hcall9(H_BULK_REMOVE, param, param[0], param[1], + param[2], param[3], param[4], param[5], + param[6], param[7]); + BUG_ON(rc != H_SUCCESS); + } if (lock_tlbie) spin_unlock_irqrestore(&pSeries_lpar_tlbie_lock, flags); diff --git a/arch/powerpc/platforms/pseries/pci.c b/arch/powerpc/platforms/pseries/pci.c index 715db5c..fa59124 100644 --- a/arch/powerpc/platforms/pseries/pci.c +++ b/arch/powerpc/platforms/pseries/pci.c @@ -77,7 +77,7 @@ void __init pSeries_final_fixup(void) /* * Assume the winbond 82c105 is the IDE controller on a - * p610. We should probably be more careful in case + * p610/p615/p630. We should probably be more careful in case * someone tries to plug in a similar adapter. */ static void fixup_winbond_82c105(struct pci_dev* dev) @@ -98,6 +98,10 @@ static void fixup_winbond_82c105(struct if (dev->resource[i].flags & IORESOURCE_IO && dev->bus->number == 0 && dev->devfn == 0x81) dev->resource[i].flags &= ~IORESOURCE_IO; + if (dev->resource[i].start == 0 && dev->resource[i].end) { + dev->resource[i].flags = 0; + dev->resource[i].end = 0; + } } } DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_WINBOND, PCI_DEVICE_ID_WINBOND_82C105, diff --git a/arch/powerpc/platforms/pseries/pseries.h b/arch/powerpc/platforms/pseries/pseries.h new file mode 100644 index 0000000..b43f139 --- /dev/null +++ b/arch/powerpc/platforms/pseries/pseries.h @@ -0,0 +1,36 @@ +/* + * Copyright 2006 IBM Corporation. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + */ + +#ifndef _PSERIES_PSERIES_H +#define _PSERIES_PSERIES_H + +extern void __init fw_feature_init(void); + +struct pt_regs; + +extern int pSeries_system_reset_exception(struct pt_regs *regs); +extern int pSeries_machine_check_exception(struct pt_regs *regs); + +#ifdef CONFIG_SMP +extern void smp_init_pseries_mpic(void); +extern void smp_init_pseries_xics(void); +#else +static inline smp_init_pseries_mpic(void) { }; +static inline smp_init_pseries_xics(void) { }; +#endif + +#ifdef CONFIG_KEXEC +extern void setup_kexec_cpu_down_xics(void); +extern void setup_kexec_cpu_down_mpic(void); +#else +static inline setup_kexec_cpu_down_xics(void) { }; +static inline setup_kexec_cpu_down_mpic(void) { }; +#endif + +#endif /* _PSERIES_PSERIES_H */ diff --git a/arch/powerpc/platforms/pseries/ras.c b/arch/powerpc/platforms/pseries/ras.c index b1d3d16..edc0388 100644 --- a/arch/powerpc/platforms/pseries/ras.c +++ b/arch/powerpc/platforms/pseries/ras.c @@ -51,7 +51,7 @@ #include #include #include -#include "ras.h" +#include "pseries.h" static unsigned char ras_log_buf[RTAS_ERROR_LOG_MAX]; static DEFINE_SPINLOCK(ras_log_buf_lock); diff --git a/arch/powerpc/platforms/pseries/ras.h b/arch/powerpc/platforms/pseries/ras.h deleted file mode 100644 index 0e66b0d..0000000 --- a/arch/powerpc/platforms/pseries/ras.h +++ /dev/null @@ -1,9 +0,0 @@ -#ifndef _PSERIES_RAS_H -#define _PSERIES_RAS_H - -struct pt_regs; - -extern int pSeries_system_reset_exception(struct pt_regs *regs); -extern int pSeries_machine_check_exception(struct pt_regs *regs); - -#endif /* _PSERIES_RAS_H */ diff --git a/arch/powerpc/platforms/pseries/reconfig.c b/arch/powerpc/platforms/pseries/reconfig.c index 4ad33e4..5aa97af 100644 --- a/arch/powerpc/platforms/pseries/reconfig.c +++ b/arch/powerpc/platforms/pseries/reconfig.c @@ -499,7 +499,7 @@ out: return rv ? rv : count; } -static struct file_operations ofdt_fops = { +static const struct file_operations ofdt_fops = { .write = ofdt_write }; @@ -513,7 +513,6 @@ static int proc_ppc64_create_ofdt(void) ent = create_proc_entry("ppc64/ofdt", S_IWUSR, NULL); if (ent) { - ent->nlink = 1; ent->data = NULL; ent->size = 0; ent->proc_fops = &ofdt_fops; diff --git a/arch/powerpc/platforms/pseries/rtasd.c b/arch/powerpc/platforms/pseries/rtasd.c index 8ca2612..77d0937 100644 --- a/arch/powerpc/platforms/pseries/rtasd.c +++ b/arch/powerpc/platforms/pseries/rtasd.c @@ -331,7 +331,7 @@ static unsigned int rtas_log_poll(struct return 0; } -struct file_operations proc_rtas_log_operations = { +const struct file_operations proc_rtas_log_operations = { .read = rtas_log_read, .poll = rtas_log_poll, .open = rtas_log_open, diff --git a/arch/powerpc/platforms/pseries/scanlog.c b/arch/powerpc/platforms/pseries/scanlog.c index 45368a5..8e1ef16 100644 --- a/arch/powerpc/platforms/pseries/scanlog.c +++ b/arch/powerpc/platforms/pseries/scanlog.c @@ -184,7 +184,7 @@ static int scanlog_release(struct inode return 0; } -struct file_operations scanlog_fops = { +const struct file_operations scanlog_fops = { .owner = THIS_MODULE, .read = scanlog_read, .write = scanlog_write, diff --git a/arch/powerpc/platforms/pseries/setup.c b/arch/powerpc/platforms/pseries/setup.c index 042ecae..435a045 100644 --- a/arch/powerpc/platforms/pseries/setup.c +++ b/arch/powerpc/platforms/pseries/setup.c @@ -55,7 +55,6 @@ #include #include #include #include -#include #include #include #include "xics.h" @@ -65,10 +64,10 @@ #include #include #include #include +#include #include "plpar_wrappers.h" -#include "ras.h" -#include "firmware.h" +#include "pseries.h" #ifdef DEBUG #define DBG(fmt...) udbg_printf(fmt) @@ -77,8 +76,6 @@ #define DBG(fmt...) #endif /* move those away to a .h */ -extern void smp_init_pseries_mpic(void); -extern void smp_init_pseries_xics(void); extern void find_udbg_vterm(void); int fwnmi_active; /* TRUE if an FWNMI handler is present */ @@ -221,42 +218,6 @@ static void pseries_lpar_enable_pmcs(voi get_lppaca()->pmcregs_in_use = 1; } -#ifdef CONFIG_KEXEC -static void pseries_kexec_cpu_down(int crash_shutdown, int secondary) -{ - /* Don't risk a hypervisor call if we're crashing */ - if (firmware_has_feature(FW_FEATURE_SPLPAR) && !crash_shutdown) { - unsigned long addr; - - addr = __pa(get_slb_shadow()); - if (unregister_slb_shadow(hard_smp_processor_id(), addr)) - printk("SLB shadow buffer deregistration of " - "cpu %u (hw_cpu_id %d) failed\n", - smp_processor_id(), - hard_smp_processor_id()); - - addr = __pa(get_lppaca()); - if (unregister_vpa(hard_smp_processor_id(), addr)) { - printk("VPA deregistration of cpu %u (hw_cpu_id %d) " - "failed\n", smp_processor_id(), - hard_smp_processor_id()); - } - } -} - -static void pseries_kexec_cpu_down_mpic(int crash_shutdown, int secondary) -{ - pseries_kexec_cpu_down(crash_shutdown, secondary); - mpic_teardown_this_cpu(secondary); -} - -static void pseries_kexec_cpu_down_xics(int crash_shutdown, int secondary) -{ - pseries_kexec_cpu_down(crash_shutdown, secondary); - xics_teardown_cpu(secondary); -} -#endif /* CONFIG_KEXEC */ - static void __init pseries_discover_pic(void) { struct device_node *np; @@ -269,21 +230,13 @@ static void __init pseries_discover_pic( pSeries_mpic_node = of_node_get(np); ppc_md.init_IRQ = pseries_mpic_init_IRQ; ppc_md.get_irq = mpic_get_irq; -#ifdef CONFIG_KEXEC - ppc_md.kexec_cpu_down = pseries_kexec_cpu_down_mpic; -#endif -#ifdef CONFIG_SMP + setup_kexec_cpu_down_mpic(); smp_init_pseries_mpic(); -#endif return; } else if (strstr(typep, "ppc-xicp")) { ppc_md.init_IRQ = xics_init_IRQ; -#ifdef CONFIG_KEXEC - ppc_md.kexec_cpu_down = pseries_kexec_cpu_down_xics; -#endif -#ifdef CONFIG_SMP + setup_kexec_cpu_down_xics(); smp_init_pseries_xics(); -#endif return; } } @@ -554,9 +507,4 @@ define_machine(pseries) { .check_legacy_ioport = pSeries_check_legacy_ioport, .system_reset_exception = pSeries_system_reset_exception, .machine_check_exception = pSeries_machine_check_exception, -#ifdef CONFIG_KEXEC - .machine_kexec = default_machine_kexec, - .machine_kexec_prepare = default_machine_kexec_prepare, - .machine_crash_shutdown = default_machine_crash_shutdown, -#endif }; diff --git a/arch/powerpc/platforms/pseries/smp.c b/arch/powerpc/platforms/pseries/smp.c index 4408518..116305b 100644 --- a/arch/powerpc/platforms/pseries/smp.c +++ b/arch/powerpc/platforms/pseries/smp.c @@ -48,6 +48,7 @@ #include #include #include "plpar_wrappers.h" +#include "pseries.h" #ifdef DEBUG #include diff --git a/arch/powerpc/sysdev/Makefile b/arch/powerpc/sysdev/Makefile index 2621a7e..85dcdf1 100644 --- a/arch/powerpc/sysdev/Makefile +++ b/arch/powerpc/sysdev/Makefile @@ -22,4 +22,6 @@ # Temporary hack until we have migrated ifeq ($(ARCH),powerpc) obj-$(CONFIG_MTD) += rom.o obj-$(CONFIG_CPM2) += cpm2_common.o cpm2_pic.o +obj-$(CONFIG_8xx) += mpc8xx_pic.o commproc.o +obj-$(CONFIG_UCODE_PATCH) += micropatch.o endif diff --git a/arch/powerpc/sysdev/commproc.c b/arch/powerpc/sysdev/commproc.c new file mode 100644 index 0000000..9b4fafd --- /dev/null +++ b/arch/powerpc/sysdev/commproc.c @@ -0,0 +1,398 @@ +/* + * General Purpose functions for the global management of the + * Communication Processor Module. + * Copyright (c) 1997 Dan error_act (dmalek@jlc.net) + * + * In addition to the individual control of the communication + * channels, there are a few functions that globally affect the + * communication processor. + * + * Buffer descriptors must be allocated from the dual ported memory + * space. The allocator for that is here. When the communication + * process is reset, we reclaim the memory available. There is + * currently no deallocator for this memory. + * The amount of space available is platform dependent. On the + * MBX, the EPPC software loads additional microcode into the + * communication processor, and uses some of the DP ram for this + * purpose. Current, the first 512 bytes and the last 256 bytes of + * memory are used. Right now I am conservative and only use the + * memory that can never be used for microcode. If there are + * applications that require more DP ram, we can expand the boundaries + * but then we have to be careful of any downloaded microcode. + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#define CPM_MAP_SIZE (0x4000) + +static void m8xx_cpm_dpinit(void); +static uint host_buffer; /* One page of host buffer */ +static uint host_end; /* end + 1 */ +cpm8xx_t *cpmp; /* Pointer to comm processor space */ +cpic8xx_t *cpic_reg; + +static struct device_node *cpm_pic_node; +static struct irq_host *cpm_pic_host; + +static void cpm_mask_irq(unsigned int irq) +{ + unsigned int cpm_vec = (unsigned int)irq_map[irq].hwirq; + + clrbits32(&cpic_reg->cpic_cimr, (1 << cpm_vec)); +} + +static void cpm_unmask_irq(unsigned int irq) +{ + unsigned int cpm_vec = (unsigned int)irq_map[irq].hwirq; + + setbits32(&cpic_reg->cpic_cimr, (1 << cpm_vec)); +} + +static void cpm_end_irq(unsigned int irq) +{ + unsigned int cpm_vec = (unsigned int)irq_map[irq].hwirq; + + out_be32(&cpic_reg->cpic_cisr, (1 << cpm_vec)); +} + +static struct irq_chip cpm_pic = { + .typename = " CPM PIC ", + .mask = cpm_mask_irq, + .unmask = cpm_unmask_irq, + .eoi = cpm_end_irq, +}; + +int cpm_get_irq(void) +{ + int cpm_vec; + + /* Get the vector by setting the ACK bit and then reading + * the register. + */ + out_be16(&cpic_reg->cpic_civr, 1); + cpm_vec = in_be16(&cpic_reg->cpic_civr); + cpm_vec >>= 11; + + return irq_linear_revmap(cpm_pic_host, cpm_vec); +} + +static int cpm_pic_host_match(struct irq_host *h, struct device_node *node) +{ + return cpm_pic_node == node; +} + +static int cpm_pic_host_map(struct irq_host *h, unsigned int virq, + irq_hw_number_t hw) +{ + pr_debug("cpm_pic_host_map(%d, 0x%lx)\n", virq, hw); + + get_irq_desc(virq)->status |= IRQ_LEVEL; + set_irq_chip_and_handler(virq, &cpm_pic, handle_fasteoi_irq); + return 0; +} + +/* The CPM can generate the error interrupt when there is a race condition + * between generating and masking interrupts. All we have to do is ACK it + * and return. This is a no-op function so we don't need any special + * tests in the interrupt handler. + */ +static irqreturn_t cpm_error_interrupt(int irq, void *dev) +{ + return IRQ_HANDLED; +} + +static struct irqaction cpm_error_irqaction = { + .handler = cpm_error_interrupt, + .mask = CPU_MASK_NONE, + .name = "error", +}; + +static struct irq_host_ops cpm_pic_host_ops = { + .match = cpm_pic_host_match, + .map = cpm_pic_host_map, +}; + +unsigned int cpm_pic_init(void) +{ + struct device_node *np = NULL; + struct resource res; + unsigned int sirq = NO_IRQ, hwirq, eirq; + int ret; + + pr_debug("cpm_pic_init\n"); + + np = of_find_compatible_node(NULL, "cpm-pic", "CPM"); + if (np == NULL) { + printk(KERN_ERR "CPM PIC init: can not find cpm-pic node\n"); + return sirq; + } + ret = of_address_to_resource(np, 0, &res); + if (ret) + goto end; + + cpic_reg = (void *)ioremap(res.start, res.end - res.start + 1); + if (cpic_reg == NULL) + goto end; + + sirq = irq_of_parse_and_map(np, 0); + if (sirq == NO_IRQ) + goto end; + + /* Initialize the CPM interrupt controller. */ + hwirq = (unsigned int)irq_map[sirq].hwirq; + out_be32(&cpic_reg->cpic_cicr, + (CICR_SCD_SCC4 | CICR_SCC_SCC3 | CICR_SCB_SCC2 | CICR_SCA_SCC1) | + ((hwirq/2) << 13) | CICR_HP_MASK); + + out_be32(&cpic_reg->cpic_cimr, 0); + + cpm_pic_node = of_node_get(np); + + cpm_pic_host = irq_alloc_host(IRQ_HOST_MAP_LINEAR, 64, &cpm_pic_host_ops, 64); + if (cpm_pic_host == NULL) { + printk(KERN_ERR "CPM2 PIC: failed to allocate irq host!\n"); + sirq = NO_IRQ; + goto end; + } + of_node_put(np); + + /* Install our own error handler. */ + np = of_find_node_by_type(NULL, "cpm"); + if (np == NULL) { + printk(KERN_ERR "CPM PIC init: can not find cpm node\n"); + goto end; + } + eirq= irq_of_parse_and_map(np, 0); + if (eirq == NO_IRQ) + goto end; + + if (setup_irq(eirq, &cpm_error_irqaction)) + printk(KERN_ERR "Could not allocate CPM error IRQ!"); + + setbits32(&cpic_reg->cpic_cicr, CICR_IEN); + +end: + of_node_put(np); + return sirq; +} + +void cpm_reset(void) +{ + cpm8xx_t *commproc; + sysconf8xx_t *siu_conf; + + commproc = (cpm8xx_t *)ioremap(CPM_MAP_ADDR, CPM_MAP_SIZE); + +#ifdef CONFIG_UCODE_PATCH + /* Perform a reset. + */ + out_be16(&commproc->cp_cpcr, CPM_CR_RST | CPM_CR_FLG); + + /* Wait for it. + */ + while (in_be16(&commproc->cp_cpcr) & CPM_CR_FLG); + + cpm_load_patch(commproc); +#endif + + /* Set SDMA Bus Request priority 5. + * On 860T, this also enables FEC priority 6. I am not sure + * this is what we realy want for some applications, but the + * manual recommends it. + * Bit 25, FAM can also be set to use FEC aggressive mode (860T). + */ + siu_conf = (sysconf8xx_t*)immr_map(im_siu_conf); + out_be32(&siu_conf->sc_sdcr, 1); + immr_unmap(siu_conf); + + /* Reclaim the DP memory for our use. */ + m8xx_cpm_dpinit(); + + /* Tell everyone where the comm processor resides. + */ + cpmp = commproc; +} + +/* We used to do this earlier, but have to postpone as long as possible + * to ensure the kernel VM is now running. + */ +static void +alloc_host_memory(void) +{ + dma_addr_t physaddr; + + /* Set the host page for allocation. + */ + host_buffer = (uint)dma_alloc_coherent(NULL, PAGE_SIZE, &physaddr, + GFP_KERNEL); + host_end = host_buffer + PAGE_SIZE; +} + +/* We also own one page of host buffer space for the allocation of + * UART "fifos" and the like. + */ +uint +m8xx_cpm_hostalloc(uint size) +{ + uint retloc; + + if (host_buffer == 0) + alloc_host_memory(); + + if ((host_buffer + size) >= host_end) + return(0); + + retloc = host_buffer; + host_buffer += size; + + return(retloc); +} + +/* Set a baud rate generator. This needs lots of work. There are + * four BRGs, any of which can be wired to any channel. + * The internal baud rate clock is the system clock divided by 16. + * This assumes the baudrate is 16x oversampled by the uart. + */ +#define BRG_INT_CLK (get_brgfreq()) +#define BRG_UART_CLK (BRG_INT_CLK/16) +#define BRG_UART_CLK_DIV16 (BRG_UART_CLK/16) + +void +cpm_setbrg(uint brg, uint rate) +{ + volatile uint *bp; + + /* This is good enough to get SMCs running..... + */ + bp = (uint *)&cpmp->cp_brgc1; + bp += brg; + /* The BRG has a 12-bit counter. For really slow baud rates (or + * really fast processors), we may have to further divide by 16. + */ + if (((BRG_UART_CLK / rate) - 1) < 4096) + *bp = (((BRG_UART_CLK / rate) - 1) << 1) | CPM_BRG_EN; + else + *bp = (((BRG_UART_CLK_DIV16 / rate) - 1) << 1) | + CPM_BRG_EN | CPM_BRG_DIV16; +} + +/* + * dpalloc / dpfree bits. + */ +static spinlock_t cpm_dpmem_lock; +/* + * 16 blocks should be enough to satisfy all requests + * until the memory subsystem goes up... + */ +static rh_block_t cpm_boot_dpmem_rh_block[16]; +static rh_info_t cpm_dpmem_info; + +#define CPM_DPMEM_ALIGNMENT 8 +static u8* dpram_vbase; +static uint dpram_pbase; + +void m8xx_cpm_dpinit(void) +{ + spin_lock_init(&cpm_dpmem_lock); + + dpram_vbase = immr_map_size(im_cpm.cp_dpmem, CPM_DATAONLY_BASE + CPM_DATAONLY_SIZE); + dpram_pbase = (uint)&((immap_t *)IMAP_ADDR)->im_cpm.cp_dpmem; + + /* Initialize the info header */ + rh_init(&cpm_dpmem_info, CPM_DPMEM_ALIGNMENT, + sizeof(cpm_boot_dpmem_rh_block) / + sizeof(cpm_boot_dpmem_rh_block[0]), + cpm_boot_dpmem_rh_block); + + /* + * Attach the usable dpmem area. + * XXX: This is actually crap. CPM_DATAONLY_BASE and + * CPM_DATAONLY_SIZE are a subset of the available dparm. It varies + * with the processor and the microcode patches applied / activated. + * But the following should be at least safe. + */ + rh_attach_region(&cpm_dpmem_info, (void *)CPM_DATAONLY_BASE, CPM_DATAONLY_SIZE); +} + +/* + * Allocate the requested size worth of DP memory. + * This function returns an offset into the DPRAM area. + * Use cpm_dpram_addr() to get the virtual address of the area. + */ +uint cpm_dpalloc(uint size, uint align) +{ + void *start; + unsigned long flags; + + spin_lock_irqsave(&cpm_dpmem_lock, flags); + cpm_dpmem_info.alignment = align; + start = rh_alloc(&cpm_dpmem_info, size, "commproc"); + spin_unlock_irqrestore(&cpm_dpmem_lock, flags); + + return (uint)start; +} +EXPORT_SYMBOL(cpm_dpalloc); + +int cpm_dpfree(uint offset) +{ + int ret; + unsigned long flags; + + spin_lock_irqsave(&cpm_dpmem_lock, flags); + ret = rh_free(&cpm_dpmem_info, (void *)offset); + spin_unlock_irqrestore(&cpm_dpmem_lock, flags); + + return ret; +} +EXPORT_SYMBOL(cpm_dpfree); + +uint cpm_dpalloc_fixed(uint offset, uint size, uint align) +{ + void *start; + unsigned long flags; + + spin_lock_irqsave(&cpm_dpmem_lock, flags); + cpm_dpmem_info.alignment = align; + start = rh_alloc_fixed(&cpm_dpmem_info, (void *)offset, size, "commproc"); + spin_unlock_irqrestore(&cpm_dpmem_lock, flags); + + return (uint)start; +} +EXPORT_SYMBOL(cpm_dpalloc_fixed); + +void cpm_dpdump(void) +{ + rh_dump(&cpm_dpmem_info); +} +EXPORT_SYMBOL(cpm_dpdump); + +void *cpm_dpram_addr(uint offset) +{ + return (void *)(dpram_vbase + offset); +} +EXPORT_SYMBOL(cpm_dpram_addr); + +uint cpm_dpram_phys(u8* addr) +{ + return (dpram_pbase + (uint)(addr - dpram_vbase)); +} +EXPORT_SYMBOL(cpm_dpram_addr); diff --git a/arch/powerpc/sysdev/cpm2_pic.c b/arch/powerpc/sysdev/cpm2_pic.c index 767ee66..eabfe06 100644 --- a/arch/powerpc/sysdev/cpm2_pic.c +++ b/arch/powerpc/sysdev/cpm2_pic.c @@ -36,9 +36,20 @@ #include #include #include #include +#include #include "cpm2_pic.h" +/* External IRQS */ +#define CPM2_IRQ_EXT1 19 +#define CPM2_IRQ_EXT7 25 + +/* Port C IRQS */ +#define CPM2_IRQ_PORTC15 48 +#define CPM2_IRQ_PORTC0 63 + +static intctl_cpm2_t *cpm2_intctl; + static struct device_node *cpm2_pic_node; static struct irq_host *cpm2_pic_host; #define NR_MASK_WORDS ((NR_IRQS + 31) / 32) @@ -68,68 +79,55 @@ static const u_char irq_to_siubit[] = { 24, 25, 26, 27, 28, 29, 30, 31, }; -static void cpm2_mask_irq(unsigned int irq_nr) +static void cpm2_mask_irq(unsigned int virq) { int bit, word; - volatile uint *simr; - - irq_nr -= CPM_IRQ_OFFSET; + unsigned int irq_nr = virq_to_hw(virq); bit = irq_to_siubit[irq_nr]; word = irq_to_siureg[irq_nr]; - simr = &(cpm2_intctl->ic_simrh); ppc_cached_irq_mask[word] &= ~(1 << bit); - simr[word] = ppc_cached_irq_mask[word]; + out_be32(&cpm2_intctl->ic_simrh + word, ppc_cached_irq_mask[word]); } -static void cpm2_unmask_irq(unsigned int irq_nr) +static void cpm2_unmask_irq(unsigned int virq) { int bit, word; - volatile uint *simr; - - irq_nr -= CPM_IRQ_OFFSET; + unsigned int irq_nr = virq_to_hw(virq); bit = irq_to_siubit[irq_nr]; word = irq_to_siureg[irq_nr]; - simr = &(cpm2_intctl->ic_simrh); ppc_cached_irq_mask[word] |= 1 << bit; - simr[word] = ppc_cached_irq_mask[word]; + out_be32(&cpm2_intctl->ic_simrh + word, ppc_cached_irq_mask[word]); } -static void cpm2_mask_and_ack(unsigned int irq_nr) +static void cpm2_ack(unsigned int virq) { int bit, word; - volatile uint *simr, *sipnr; - - irq_nr -= CPM_IRQ_OFFSET; + unsigned int irq_nr = virq_to_hw(virq); bit = irq_to_siubit[irq_nr]; word = irq_to_siureg[irq_nr]; - simr = &(cpm2_intctl->ic_simrh); - sipnr = &(cpm2_intctl->ic_sipnrh); - ppc_cached_irq_mask[word] &= ~(1 << bit); - simr[word] = ppc_cached_irq_mask[word]; - sipnr[word] = 1 << bit; + out_be32(&cpm2_intctl->ic_sipnrh + word, 1 << bit); } -static void cpm2_end_irq(unsigned int irq_nr) +static void cpm2_end_irq(unsigned int virq) { int bit, word; - volatile uint *simr; + unsigned int irq_nr = virq_to_hw(virq); if (!(irq_desc[irq_nr].status & (IRQ_DISABLED|IRQ_INPROGRESS)) && irq_desc[irq_nr].action) { - irq_nr -= CPM_IRQ_OFFSET; bit = irq_to_siubit[irq_nr]; word = irq_to_siureg[irq_nr]; - simr = &(cpm2_intctl->ic_simrh); ppc_cached_irq_mask[word] |= 1 << bit; - simr[word] = ppc_cached_irq_mask[word]; + out_be32(&cpm2_intctl->ic_simrh + word, ppc_cached_irq_mask[word]); + /* * Work around large numbers of spurious IRQs on PowerPC 82xx * systems. @@ -138,13 +136,59 @@ static void cpm2_end_irq(unsigned int ir } } +static int cpm2_set_irq_type(unsigned int virq, unsigned int flow_type) +{ + unsigned int src = virq_to_hw(virq); + struct irq_desc *desc = get_irq_desc(virq); + unsigned int vold, vnew, edibit; + + if (flow_type == IRQ_TYPE_NONE) + flow_type = IRQ_TYPE_LEVEL_LOW; + + if (flow_type & IRQ_TYPE_EDGE_RISING) { + printk(KERN_ERR "CPM2 PIC: sense type 0x%x not supported\n", + flow_type); + return -EINVAL; + } + + desc->status &= ~(IRQ_TYPE_SENSE_MASK | IRQ_LEVEL); + desc->status |= flow_type & IRQ_TYPE_SENSE_MASK; + if (flow_type & IRQ_TYPE_LEVEL_LOW) { + desc->status |= IRQ_LEVEL; + desc->handle_irq = handle_level_irq; + } else + desc->handle_irq = handle_edge_irq; + + /* internal IRQ senses are LEVEL_LOW + * EXT IRQ and Port C IRQ senses are programmable + */ + if (src >= CPM2_IRQ_EXT1 && src <= CPM2_IRQ_EXT7) + edibit = (14 - (src - CPM2_IRQ_EXT1)); + else + if (src >= CPM2_IRQ_PORTC15 && src <= CPM2_IRQ_PORTC0) + edibit = (31 - (src - CPM2_IRQ_PORTC15)); + else + return (flow_type & IRQ_TYPE_LEVEL_LOW) ? 0 : -EINVAL; + + vold = in_be32(&cpm2_intctl->ic_siexr); + + if ((flow_type & IRQ_TYPE_SENSE_MASK) == IRQ_TYPE_EDGE_FALLING) + vnew = vold | (1 << edibit); + else + vnew = vold & ~(1 << edibit); + + if (vold != vnew) + out_be32(&cpm2_intctl->ic_siexr, vnew); + return 0; +} + static struct irq_chip cpm2_pic = { .typename = " CPM2 SIU ", - .enable = cpm2_unmask_irq, - .disable = cpm2_mask_irq, + .mask = cpm2_mask_irq, .unmask = cpm2_unmask_irq, - .mask_ack = cpm2_mask_and_ack, - .end = cpm2_end_irq, + .ack = cpm2_ack, + .eoi = cpm2_end_irq, + .set_type = cpm2_set_irq_type, }; unsigned int cpm2_get_irq(void) @@ -154,17 +198,17 @@ unsigned int cpm2_get_irq(void) /* For CPM2, read the SIVEC register and shift the bits down * to get the irq number. */ - bits = cpm2_intctl->ic_sivec; + bits = in_be32(&cpm2_intctl->ic_sivec); irq = bits >> 26; if (irq == 0) return(-1); - return irq+CPM_IRQ_OFFSET; + return irq_linear_revmap(cpm2_pic_host, irq); } static int cpm2_pic_host_match(struct irq_host *h, struct device_node *node) { - return cpm2_pic_node == NULL || cpm2_pic_node == node; + return cpm2_pic_node == node; } static int cpm2_pic_host_map(struct irq_host *h, unsigned int virq, @@ -177,39 +221,21 @@ static int cpm2_pic_host_map(struct irq_ return 0; } -static void cpm2_host_unmap(struct irq_host *h, unsigned int virq) -{ - /* Make sure irq is masked in hardware */ - cpm2_mask_irq(virq); - - /* remove chip and handler */ - set_irq_chip_and_handler(virq, NULL, NULL); -} - static int cpm2_pic_host_xlate(struct irq_host *h, struct device_node *ct, u32 *intspec, unsigned int intsize, irq_hw_number_t *out_hwirq, unsigned int *out_flags) { - static const unsigned char map_cpm2_senses[4] = { - IRQ_TYPE_LEVEL_LOW, - IRQ_TYPE_LEVEL_HIGH, - IRQ_TYPE_EDGE_FALLING, - IRQ_TYPE_EDGE_RISING, - }; - *out_hwirq = intspec[0]; - if (intsize > 1 && intspec[1] < 4) - *out_flags = map_cpm2_senses[intspec[1]]; + if (intsize > 1) + *out_flags = intspec[1]; else *out_flags = IRQ_TYPE_NONE; - return 0; } static struct irq_host_ops cpm2_pic_host_ops = { .match = cpm2_pic_host_match, .map = cpm2_pic_host_map, - .unmap = cpm2_host_unmap, .xlate = cpm2_pic_host_xlate, }; @@ -217,37 +243,37 @@ void cpm2_pic_init(struct device_node *n { int i; + cpm2_intctl = cpm2_map(im_intctl); + /* Clear the CPM IRQ controller, in case it has any bits set * from the bootloader */ /* Mask out everything */ - cpm2_intctl->ic_simrh = 0x00000000; - cpm2_intctl->ic_simrl = 0x00000000; + out_be32(&cpm2_intctl->ic_simrh, 0x00000000); + out_be32(&cpm2_intctl->ic_simrl, 0x00000000); wmb(); /* Ack everything */ - cpm2_intctl->ic_sipnrh = 0xffffffff; - cpm2_intctl->ic_sipnrl = 0xffffffff; + out_be32(&cpm2_intctl->ic_sipnrh, 0xffffffff); + out_be32(&cpm2_intctl->ic_sipnrl, 0xffffffff); wmb(); /* Dummy read of the vector */ - i = cpm2_intctl->ic_sivec; + i = in_be32(&cpm2_intctl->ic_sivec); rmb(); /* Initialize the default interrupt mapping priorities, * in case the boot rom changed something on us. */ - cpm2_intctl->ic_sicr = 0; - cpm2_intctl->ic_scprrh = 0x05309770; - cpm2_intctl->ic_scprrl = 0x05309770; + out_be16(&cpm2_intctl->ic_sicr, 0); + out_be32(&cpm2_intctl->ic_scprrh, 0x05309770); + out_be32(&cpm2_intctl->ic_scprrl, 0x05309770); /* create a legacy host */ - if (node) - cpm2_pic_node = of_node_get(node); - + cpm2_pic_node = of_node_get(node); cpm2_pic_host = irq_alloc_host(IRQ_HOST_MAP_LINEAR, 64, &cpm2_pic_host_ops, 64); if (cpm2_pic_host == NULL) { printk(KERN_ERR "CPM2 PIC: failed to allocate irq host!\n"); diff --git a/arch/powerpc/sysdev/cpm2_pic.h b/arch/powerpc/sysdev/cpm2_pic.h index 2840616..30e5828 100644 --- a/arch/powerpc/sysdev/cpm2_pic.h +++ b/arch/powerpc/sysdev/cpm2_pic.h @@ -1,8 +1,6 @@ #ifndef _PPC_KERNEL_CPM2_H #define _PPC_KERNEL_CPM2_H -extern intctl_cpm2_t *cpm2_intctl; - extern unsigned int cpm2_get_irq(void); extern void cpm2_pic_init(struct device_node*); diff --git a/arch/powerpc/sysdev/fsl_soc.c b/arch/powerpc/sysdev/fsl_soc.c index ad31e56..34161bc 100644 --- a/arch/powerpc/sysdev/fsl_soc.c +++ b/arch/powerpc/sysdev/fsl_soc.c @@ -38,7 +38,8 @@ #include #include extern void init_fcc_ioports(struct fs_platform_info*); -extern void init_scc_ioports(struct fs_uart_platform_info*); +extern void init_fec_ioports(struct fs_platform_info*); +extern void init_smc_ioports(struct fs_uart_platform_info*); static phys_addr_t immrbase = -1; phys_addr_t get_immrbase(void) @@ -63,7 +64,7 @@ phys_addr_t get_immrbase(void) EXPORT_SYMBOL(get_immrbase); -#ifdef CONFIG_CPM2 +#if defined(CONFIG_CPM2) || defined(CONFIG_8xx) static u32 brgfreq = -1; @@ -440,7 +441,8 @@ static int __init fsl_usb_of_init(void) { struct device_node *np; unsigned int i; - struct platform_device *usb_dev_mph = NULL, *usb_dev_dr = NULL; + struct platform_device *usb_dev_mph = NULL, *usb_dev_dr_host = NULL, + *usb_dev_dr_client = NULL; int ret; for (np = NULL, i = 0; @@ -506,33 +508,72 @@ static int __init fsl_usb_of_init(void) of_irq_to_resource(np, 0, &r[1]); - usb_dev_dr = - platform_device_register_simple("fsl-ehci", i, r, 2); - if (IS_ERR(usb_dev_dr)) { - ret = PTR_ERR(usb_dev_dr); + prop = get_property(np, "dr_mode", NULL); + + if (!prop || !strcmp(prop, "host")) { + usb_data.operating_mode = FSL_USB2_DR_HOST; + usb_dev_dr_host = platform_device_register_simple( + "fsl-ehci", i, r, 2); + if (IS_ERR(usb_dev_dr_host)) { + ret = PTR_ERR(usb_dev_dr_host); + goto err; + } + } else if (prop && !strcmp(prop, "peripheral")) { + usb_data.operating_mode = FSL_USB2_DR_DEVICE; + usb_dev_dr_client = platform_device_register_simple( + "fsl-usb2-udc", i, r, 2); + if (IS_ERR(usb_dev_dr_client)) { + ret = PTR_ERR(usb_dev_dr_client); + goto err; + } + } else if (prop && !strcmp(prop, "otg")) { + usb_data.operating_mode = FSL_USB2_DR_OTG; + usb_dev_dr_host = platform_device_register_simple( + "fsl-ehci", i, r, 2); + if (IS_ERR(usb_dev_dr_host)) { + ret = PTR_ERR(usb_dev_dr_host); + goto err; + } + usb_dev_dr_client = platform_device_register_simple( + "fsl-usb2-udc", i, r, 2); + if (IS_ERR(usb_dev_dr_client)) { + ret = PTR_ERR(usb_dev_dr_client); + goto err; + } + } else { + ret = -EINVAL; goto err; } - usb_dev_dr->dev.coherent_dma_mask = 0xffffffffUL; - usb_dev_dr->dev.dma_mask = &usb_dev_dr->dev.coherent_dma_mask; - - usb_data.operating_mode = FSL_USB2_DR_HOST; - prop = get_property(np, "phy_type", NULL); usb_data.phy_mode = determine_usb_phy(prop); - ret = - platform_device_add_data(usb_dev_dr, &usb_data, - sizeof(struct - fsl_usb2_platform_data)); - if (ret) - goto unreg_dr; + if (usb_dev_dr_host) { + usb_dev_dr_host->dev.coherent_dma_mask = 0xffffffffUL; + usb_dev_dr_host->dev.dma_mask = &usb_dev_dr_host-> + dev.coherent_dma_mask; + if ((ret = platform_device_add_data(usb_dev_dr_host, + &usb_data, sizeof(struct + fsl_usb2_platform_data)))) + goto unreg_dr; + } + if (usb_dev_dr_client) { + usb_dev_dr_client->dev.coherent_dma_mask = 0xffffffffUL; + usb_dev_dr_client->dev.dma_mask = &usb_dev_dr_client-> + dev.coherent_dma_mask; + if ((ret = platform_device_add_data(usb_dev_dr_client, + &usb_data, sizeof(struct + fsl_usb2_platform_data)))) + goto unreg_dr; + } } return 0; unreg_dr: - if (usb_dev_dr) - platform_device_unregister(usb_dev_dr); + if (usb_dev_dr_host) + platform_device_unregister(usb_dev_dr_host); + if (usb_dev_dr_client) + platform_device_unregister(usb_dev_dr_client); unreg_mph: if (usb_dev_mph) platform_device_unregister(usb_dev_mph); @@ -544,6 +585,8 @@ arch_initcall(fsl_usb_of_init); #ifdef CONFIG_CPM2 +extern void init_scc_ioports(struct fs_uart_platform_info*); + static const char fcc_regs[] = "fcc_regs"; static const char fcc_regs_c[] = "fcc_regs_c"; static const char fcc_pram[] = "fcc_pram"; @@ -696,7 +739,7 @@ static int __init fs_enet_of_init(void) if (ret) goto unreg; } - + of_node_put(phy); of_node_put(mdio); @@ -792,3 +835,270 @@ err: arch_initcall(cpm_uart_of_init); #endif /* CONFIG_CPM2 */ + +#ifdef CONFIG_8xx + +extern void init_scc_ioports(struct fs_platform_info*); +extern int platform_device_skip(char *model, int id); + +static int __init fs_enet_mdio_of_init(void) +{ + struct device_node *np; + unsigned int i; + struct platform_device *mdio_dev; + struct resource res; + int ret; + + for (np = NULL, i = 0; + (np = of_find_compatible_node(np, "mdio", "fs_enet")) != NULL; + i++) { + struct fs_mii_fec_platform_info mdio_data; + + memset(&res, 0, sizeof(res)); + memset(&mdio_data, 0, sizeof(mdio_data)); + + ret = of_address_to_resource(np, 0, &res); + if (ret) + goto err; + + mdio_dev = + platform_device_register_simple("fsl-cpm-fec-mdio", + res.start, &res, 1); + if (IS_ERR(mdio_dev)) { + ret = PTR_ERR(mdio_dev); + goto err; + } + + mdio_data.mii_speed = ((((ppc_proc_freq + 4999999) / 2500000) / 2) & 0x3F) << 1; + + ret = + platform_device_add_data(mdio_dev, &mdio_data, + sizeof(struct fs_mii_fec_platform_info)); + if (ret) + goto unreg; + } + return 0; + +unreg: + platform_device_unregister(mdio_dev); +err: + return ret; +} + +arch_initcall(fs_enet_mdio_of_init); + +static const char *enet_regs = "regs"; +static const char *enet_pram = "pram"; +static const char *enet_irq = "interrupt"; +static char bus_id[9][BUS_ID_SIZE]; + +static int __init fs_enet_of_init(void) +{ + struct device_node *np; + unsigned int i; + struct platform_device *fs_enet_dev = NULL; + struct resource res; + int ret; + + for (np = NULL, i = 0; + (np = of_find_compatible_node(np, "network", "fs_enet")) != NULL; + i++) { + struct resource r[4]; + struct device_node *phy = NULL, *mdio = NULL; + struct fs_platform_info fs_enet_data; + unsigned int *id, *phy_addr; + void *mac_addr; + phandle *ph; + char *model; + + memset(r, 0, sizeof(r)); + memset(&fs_enet_data, 0, sizeof(fs_enet_data)); + + model = (char *)get_property(np, "model", NULL); + if (model == NULL) { + ret = -ENODEV; + goto unreg; + } + + id = (u32 *) get_property(np, "device-id", NULL); + fs_enet_data.fs_no = *id; + + if (platform_device_skip(model, *id)) + continue; + + ret = of_address_to_resource(np, 0, &r[0]); + if (ret) + goto err; + r[0].name = enet_regs; + + mac_addr = (void *)get_property(np, "mac-address", NULL); + memcpy(fs_enet_data.macaddr, mac_addr, 6); + + ph = (phandle *) get_property(np, "phy-handle", NULL); + if (ph != NULL) + phy = of_find_node_by_phandle(*ph); + + if (phy != NULL) { + phy_addr = (u32 *) get_property(phy, "reg", NULL); + fs_enet_data.phy_addr = *phy_addr; + fs_enet_data.has_phy = 1; + + mdio = of_get_parent(phy); + ret = of_address_to_resource(mdio, 0, &res); + if (ret) { + of_node_put(phy); + of_node_put(mdio); + goto unreg; + } + } + + model = (char*)get_property(np, "model", NULL); + strcpy(fs_enet_data.fs_type, model); + + if (strstr(model, "FEC")) { + r[1].start = r[1].end = irq_of_parse_and_map(np, 0); + r[1].flags = IORESOURCE_IRQ; + r[1].name = enet_irq; + + fs_enet_dev = + platform_device_register_simple("fsl-cpm-fec", i, &r[0], 2); + + if (IS_ERR(fs_enet_dev)) { + ret = PTR_ERR(fs_enet_dev); + goto err; + } + + fs_enet_data.rx_ring = 128; + fs_enet_data.tx_ring = 16; + fs_enet_data.rx_copybreak = 240; + fs_enet_data.use_napi = 1; + fs_enet_data.napi_weight = 17; + + snprintf((char*)&bus_id[i], BUS_ID_SIZE, "%x:%02x", + (u32)res.start, fs_enet_data.phy_addr); + fs_enet_data.bus_id = (char*)&bus_id[i]; + fs_enet_data.init_ioports = init_fec_ioports; + } + if (strstr(model, "SCC")) { + ret = of_address_to_resource(np, 1, &r[1]); + if (ret) + goto err; + r[1].name = enet_pram; + + r[2].start = r[2].end = irq_of_parse_and_map(np, 0); + r[2].flags = IORESOURCE_IRQ; + r[2].name = enet_irq; + + fs_enet_dev = + platform_device_register_simple("fsl-cpm-scc", i, &r[0], 3); + + if (IS_ERR(fs_enet_dev)) { + ret = PTR_ERR(fs_enet_dev); + goto err; + } + + fs_enet_data.rx_ring = 64; + fs_enet_data.tx_ring = 8; + fs_enet_data.rx_copybreak = 240; + fs_enet_data.use_napi = 1; + fs_enet_data.napi_weight = 17; + + snprintf((char*)&bus_id[i], BUS_ID_SIZE, "%s", "fixed@10:1"); + fs_enet_data.bus_id = (char*)&bus_id[i]; + fs_enet_data.init_ioports = init_scc_ioports; + } + + of_node_put(phy); + of_node_put(mdio); + + ret = platform_device_add_data(fs_enet_dev, &fs_enet_data, + sizeof(struct + fs_platform_info)); + if (ret) + goto unreg; + } + return 0; + +unreg: + platform_device_unregister(fs_enet_dev); +err: + return ret; +} + +arch_initcall(fs_enet_of_init); + + +static const char *smc_regs = "regs"; +static const char *smc_pram = "pram"; + +static int __init cpm_smc_uart_of_init(void) +{ + struct device_node *np; + unsigned int i; + struct platform_device *cpm_uart_dev; + int ret; + + for (np = NULL, i = 0; + (np = of_find_compatible_node(np, "serial", "cpm_uart")) != NULL; + i++) { + struct resource r[3]; + struct fs_uart_platform_info cpm_uart_data; + int *id; + char *model; + + memset(r, 0, sizeof(r)); + memset(&cpm_uart_data, 0, sizeof(cpm_uart_data)); + + ret = of_address_to_resource(np, 0, &r[0]); + if (ret) + goto err; + + r[0].name = smc_regs; + + ret = of_address_to_resource(np, 1, &r[1]); + if (ret) + goto err; + r[1].name = smc_pram; + + r[2].start = r[2].end = irq_of_parse_and_map(np, 0); + r[2].flags = IORESOURCE_IRQ; + + cpm_uart_dev = + platform_device_register_simple("fsl-cpm-smc:uart", i, &r[0], 3); + + if (IS_ERR(cpm_uart_dev)) { + ret = PTR_ERR(cpm_uart_dev); + goto err; + } + + model = (char*)get_property(np, "model", NULL); + strcpy(cpm_uart_data.fs_type, model); + + id = (int*)get_property(np, "device-id", NULL); + cpm_uart_data.fs_no = *id; + cpm_uart_data.uart_clk = ppc_proc_freq; + + cpm_uart_data.tx_num_fifo = 4; + cpm_uart_data.tx_buf_size = 32; + cpm_uart_data.rx_num_fifo = 4; + cpm_uart_data.rx_buf_size = 32; + + ret = + platform_device_add_data(cpm_uart_dev, &cpm_uart_data, + sizeof(struct + fs_uart_platform_info)); + if (ret) + goto unreg; + } + + return 0; + +unreg: + platform_device_unregister(cpm_uart_dev); +err: + return ret; +} + +arch_initcall(cpm_smc_uart_of_init); + +#endif /* CONFIG_8xx */ diff --git a/arch/powerpc/sysdev/grackle.c b/arch/powerpc/sysdev/grackle.c index b6ec793..4205362 100644 --- a/arch/powerpc/sysdev/grackle.c +++ b/arch/powerpc/sysdev/grackle.c @@ -56,6 +56,8 @@ static inline void grackle_set_loop_snoo void __init setup_grackle(struct pci_controller *hose) { setup_indirect_pci(hose, 0xfec00000, 0xfee00000); + if (machine_is_compatible("PowerMac1,1")) + pci_assign_all_buses = 1; if (machine_is_compatible("AAPL,PowerBook1998")) grackle_set_loop_snoop(hose, 1); #if 0 /* Disabled for now, HW problems ??? */ diff --git a/arch/powerpc/sysdev/ipic.c b/arch/powerpc/sysdev/ipic.c index 746f78c..473c415 100644 --- a/arch/powerpc/sysdev/ipic.c +++ b/arch/powerpc/sysdev/ipic.c @@ -557,8 +557,7 @@ static struct irq_host_ops ipic_host_ops .xlate = ipic_host_xlate, }; -void __init ipic_init(struct device_node *node, - unsigned int flags) +struct ipic * __init ipic_init(struct device_node *node, unsigned int flags) { struct ipic *ipic; struct resource res; @@ -566,22 +565,24 @@ void __init ipic_init(struct device_node ipic = alloc_bootmem(sizeof(struct ipic)); if (ipic == NULL) - return; + return NULL; memset(ipic, 0, sizeof(struct ipic)); - ipic->of_node = node ? of_node_get(node) : NULL; + ipic->of_node = of_node_get(node); ipic->irqhost = irq_alloc_host(IRQ_HOST_MAP_LINEAR, NR_IPIC_INTS, &ipic_host_ops, 0); if (ipic->irqhost == NULL) { of_node_put(node); - return; + return NULL; } ret = of_address_to_resource(node, 0, &res); - if (ret) - return; + if (ret) { + of_node_put(node); + return NULL; + } ipic->regs = ioremap(res.start, res.end - res.start + 1); @@ -625,6 +626,8 @@ void __init ipic_init(struct device_node printk ("IPIC (%d IRQ sources) at %p\n", NR_IPIC_INTS, primary_ipic->regs); + + return ipic; } int ipic_set_priority(unsigned int virq, unsigned int priority) diff --git a/arch/powerpc/sysdev/micropatch.c b/arch/powerpc/sysdev/micropatch.c new file mode 100644 index 0000000..712b10a --- /dev/null +++ b/arch/powerpc/sysdev/micropatch.c @@ -0,0 +1,743 @@ + +/* Microcode patches for the CPM as supplied by Motorola. + * This is the one for IIC/SPI. There is a newer one that + * also relocates SMC2, but this would require additional changes + * to uart.c, so I am holding off on that for a moment. + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* + * I2C/SPI relocation patch arrays. + */ + +#ifdef CONFIG_I2C_SPI_UCODE_PATCH + +uint patch_2000[] = { + 0x7FFFEFD9, + 0x3FFD0000, + 0x7FFB49F7, + 0x7FF90000, + 0x5FEFADF7, + 0x5F89ADF7, + 0x5FEFAFF7, + 0x5F89AFF7, + 0x3A9CFBC8, + 0xE7C0EDF0, + 0x77C1E1BB, + 0xF4DC7F1D, + 0xABAD932F, + 0x4E08FDCF, + 0x6E0FAFF8, + 0x7CCF76CF, + 0xFD1FF9CF, + 0xABF88DC6, + 0xAB5679F7, + 0xB0937383, + 0xDFCE79F7, + 0xB091E6BB, + 0xE5BBE74F, + 0xB3FA6F0F, + 0x6FFB76CE, + 0xEE0DF9CF, + 0x2BFBEFEF, + 0xCFEEF9CF, + 0x76CEAD24, + 0x90B2DF9A, + 0x7FDDD0BF, + 0x4BF847FD, + 0x7CCF76CE, + 0xCFEF7E1F, + 0x7F1D7DFD, + 0xF0B6EF71, + 0x7FC177C1, + 0xFBC86079, + 0xE722FBC8, + 0x5FFFDFFF, + 0x5FB2FFFB, + 0xFBC8F3C8, + 0x94A67F01, + 0x7F1D5F39, + 0xAFE85F5E, + 0xFFDFDF96, + 0xCB9FAF7D, + 0x5FC1AFED, + 0x8C1C5FC1, + 0xAFDD5FC3, + 0xDF9A7EFD, + 0xB0B25FB2, + 0xFFFEABAD, + 0x5FB2FFFE, + 0x5FCE600B, + 0xE6BB600B, + 0x5FCEDFC6, + 0x27FBEFDF, + 0x5FC8CFDE, + 0x3A9CE7C0, + 0xEDF0F3C8, + 0x7F0154CD, + 0x7F1D2D3D, + 0x363A7570, + 0x7E0AF1CE, + 0x37EF2E68, + 0x7FEE10EC, + 0xADF8EFDE, + 0xCFEAE52F, + 0x7D0FE12B, + 0xF1CE5F65, + 0x7E0A4DF8, + 0xCFEA5F72, + 0x7D0BEFEE, + 0xCFEA5F74, + 0xE522EFDE, + 0x5F74CFDA, + 0x0B627385, + 0xDF627E0A, + 0x30D8145B, + 0xBFFFF3C8, + 0x5FFFDFFF, + 0xA7F85F5E, + 0xBFFE7F7D, + 0x10D31450, + 0x5F36BFFF, + 0xAF785F5E, + 0xBFFDA7F8, + 0x5F36BFFE, + 0x77FD30C0, + 0x4E08FDCF, + 0xE5FF6E0F, + 0xAFF87E1F, + 0x7E0FFD1F, + 0xF1CF5F1B, + 0xABF80D5E, + 0x5F5EFFEF, + 0x79F730A2, + 0xAFDD5F34, + 0x47F85F34, + 0xAFED7FDD, + 0x50B24978, + 0x47FD7F1D, + 0x7DFD70AD, + 0xEF717EC1, + 0x6BA47F01, + 0x2D267EFD, + 0x30DE5F5E, + 0xFFFD5F5E, + 0xFFEF5F5E, + 0xFFDF0CA0, + 0xAFED0A9E, + 0xAFDD0C3A, + 0x5F3AAFBD, + 0x7FBDB082, + 0x5F8247F8 +}; + +uint patch_2f00[] = { + 0x3E303430, + 0x34343737, + 0xABF7BF9B, + 0x994B4FBD, + 0xBD599493, + 0x349FFF37, + 0xFB9B177D, + 0xD9936956, + 0xBBFDD697, + 0xBDD2FD11, + 0x31DB9BB3, + 0x63139637, + 0x93733693, + 0x193137F7, + 0x331737AF, + 0x7BB9B999, + 0xBB197957, + 0x7FDFD3D5, + 0x73B773F7, + 0x37933B99, + 0x1D115316, + 0x99315315, + 0x31694BF4, + 0xFBDBD359, + 0x31497353, + 0x76956D69, + 0x7B9D9693, + 0x13131979, + 0x79376935 +}; +#endif + +/* + * I2C/SPI/SMC1 relocation patch arrays. + */ + +#ifdef CONFIG_I2C_SPI_SMC1_UCODE_PATCH + +uint patch_2000[] = { + 0x3fff0000, + 0x3ffd0000, + 0x3ffb0000, + 0x3ff90000, + 0x5f13eff8, + 0x5eb5eff8, + 0x5f88adf7, + 0x5fefadf7, + 0x3a9cfbc8, + 0x77cae1bb, + 0xf4de7fad, + 0xabae9330, + 0x4e08fdcf, + 0x6e0faff8, + 0x7ccf76cf, + 0xfdaff9cf, + 0xabf88dc8, + 0xab5879f7, + 0xb0925d8d, + 0xdfd079f7, + 0xb090e6bb, + 0xe5bbe74f, + 0x9e046f0f, + 0x6ffb76ce, + 0xee0cf9cf, + 0x2bfbefef, + 0xcfeef9cf, + 0x76cead23, + 0x90b3df99, + 0x7fddd0c1, + 0x4bf847fd, + 0x7ccf76ce, + 0xcfef77ca, + 0x7eaf7fad, + 0x7dfdf0b7, + 0xef7a7fca, + 0x77cafbc8, + 0x6079e722, + 0xfbc85fff, + 0xdfff5fb3, + 0xfffbfbc8, + 0xf3c894a5, + 0xe7c9edf9, + 0x7f9a7fad, + 0x5f36afe8, + 0x5f5bffdf, + 0xdf95cb9e, + 0xaf7d5fc3, + 0xafed8c1b, + 0x5fc3afdd, + 0x5fc5df99, + 0x7efdb0b3, + 0x5fb3fffe, + 0xabae5fb3, + 0xfffe5fd0, + 0x600be6bb, + 0x600b5fd0, + 0xdfc827fb, + 0xefdf5fca, + 0xcfde3a9c, + 0xe7c9edf9, + 0xf3c87f9e, + 0x54ca7fed, + 0x2d3a3637, + 0x756f7e9a, + 0xf1ce37ef, + 0x2e677fee, + 0x10ebadf8, + 0xefdecfea, + 0xe52f7d9f, + 0xe12bf1ce, + 0x5f647e9a, + 0x4df8cfea, + 0x5f717d9b, + 0xefeecfea, + 0x5f73e522, + 0xefde5f73, + 0xcfda0b61, + 0x5d8fdf61, + 0xe7c9edf9, + 0x7e9a30d5, + 0x1458bfff, + 0xf3c85fff, + 0xdfffa7f8, + 0x5f5bbffe, + 0x7f7d10d0, + 0x144d5f33, + 0xbfffaf78, + 0x5f5bbffd, + 0xa7f85f33, + 0xbffe77fd, + 0x30bd4e08, + 0xfdcfe5ff, + 0x6e0faff8, + 0x7eef7e9f, + 0xfdeff1cf, + 0x5f17abf8, + 0x0d5b5f5b, + 0xffef79f7, + 0x309eafdd, + 0x5f3147f8, + 0x5f31afed, + 0x7fdd50af, + 0x497847fd, + 0x7f9e7fed, + 0x7dfd70a9, + 0xef7e7ece, + 0x6ba07f9e, + 0x2d227efd, + 0x30db5f5b, + 0xfffd5f5b, + 0xffef5f5b, + 0xffdf0c9c, + 0xafed0a9a, + 0xafdd0c37, + 0x5f37afbd, + 0x7fbdb081, + 0x5f8147f8, + 0x3a11e710, + 0xedf0ccdd, + 0xf3186d0a, + 0x7f0e5f06, + 0x7fedbb38, + 0x3afe7468, + 0x7fedf4fc, + 0x8ffbb951, + 0xb85f77fd, + 0xb0df5ddd, + 0xdefe7fed, + 0x90e1e74d, + 0x6f0dcbf7, + 0xe7decfed, + 0xcb74cfed, + 0xcfeddf6d, + 0x91714f74, + 0x5dd2deef, + 0x9e04e7df, + 0xefbb6ffb, + 0xe7ef7f0e, + 0x9e097fed, + 0xebdbeffa, + 0xeb54affb, + 0x7fea90d7, + 0x7e0cf0c3, + 0xbffff318, + 0x5fffdfff, + 0xac59efea, + 0x7fce1ee5, + 0xe2ff5ee1, + 0xaffbe2ff, + 0x5ee3affb, + 0xf9cc7d0f, + 0xaef8770f, + 0x7d0fb0c6, + 0xeffbbfff, + 0xcfef5ede, + 0x7d0fbfff, + 0x5ede4cf8, + 0x7fddd0bf, + 0x49f847fd, + 0x7efdf0bb, + 0x7fedfffd, + 0x7dfdf0b7, + 0xef7e7e1e, + 0x5ede7f0e, + 0x3a11e710, + 0xedf0ccab, + 0xfb18ad2e, + 0x1ea9bbb8, + 0x74283b7e, + 0x73c2e4bb, + 0x2ada4fb8, + 0xdc21e4bb, + 0xb2a1ffbf, + 0x5e2c43f8, + 0xfc87e1bb, + 0xe74ffd91, + 0x6f0f4fe8, + 0xc7ba32e2, + 0xf396efeb, + 0x600b4f78, + 0xe5bb760b, + 0x53acaef8, + 0x4ef88b0e, + 0xcfef9e09, + 0xabf8751f, + 0xefef5bac, + 0x741f4fe8, + 0x751e760d, + 0x7fdbf081, + 0x741cafce, + 0xefcc7fce, + 0x751e70ac, + 0x741ce7bb, + 0x3372cfed, + 0xafdbefeb, + 0xe5bb760b, + 0x53f2aef8, + 0xafe8e7eb, + 0x4bf8771e, + 0x7e247fed, + 0x4fcbe2cc, + 0x7fbc30a9, + 0x7b0f7a0f, + 0x34d577fd, + 0x308b5db7, + 0xde553e5f, + 0xaf78741f, + 0x741f30f0, + 0xcfef5e2c, + 0x741f3eac, + 0xafb8771e, + 0x5e677fed, + 0x0bd3e2cc, + 0x741ccfec, + 0xe5ca53cd, + 0x6fcb4f74, + 0x5dadde4b, + 0x2ab63d38, + 0x4bb3de30, + 0x751f741c, + 0x6c42effa, + 0xefea7fce, + 0x6ffc30be, + 0xefec3fca, + 0x30b3de2e, + 0xadf85d9e, + 0xaf7daefd, + 0x5d9ede2e, + 0x5d9eafdd, + 0x761f10ac, + 0x1da07efd, + 0x30adfffe, + 0x4908fb18, + 0x5fffdfff, + 0xafbb709b, + 0x4ef85e67, + 0xadf814ad, + 0x7a0f70ad, + 0xcfef50ad, + 0x7a0fde30, + 0x5da0afed, + 0x3c12780f, + 0xefef780f, + 0xefef790f, + 0xa7f85e0f, + 0xffef790f, + 0xefef790f, + 0x14adde2e, + 0x5d9eadfd, + 0x5e2dfffb, + 0xe79addfd, + 0xeff96079, + 0x607ae79a, + 0xddfceff9, + 0x60795dff, + 0x607acfef, + 0xefefefdf, + 0xefbfef7f, + 0xeeffedff, + 0xebffe7ff, + 0xafefafdf, + 0xafbfaf7f, + 0xaeffadff, + 0xabffa7ff, + 0x6fef6fdf, + 0x6fbf6f7f, + 0x6eff6dff, + 0x6bff67ff, + 0x2fef2fdf, + 0x2fbf2f7f, + 0x2eff2dff, + 0x2bff27ff, + 0x4e08fd1f, + 0xe5ff6e0f, + 0xaff87eef, + 0x7e0ffdef, + 0xf11f6079, + 0xabf8f542, + 0x7e0af11c, + 0x37cfae3a, + 0x7fec90be, + 0xadf8efdc, + 0xcfeae52f, + 0x7d0fe12b, + 0xf11c6079, + 0x7e0a4df8, + 0xcfea5dc4, + 0x7d0befec, + 0xcfea5dc6, + 0xe522efdc, + 0x5dc6cfda, + 0x4e08fd1f, + 0x6e0faff8, + 0x7c1f761f, + 0xfdeff91f, + 0x6079abf8, + 0x761cee24, + 0xf91f2bfb, + 0xefefcfec, + 0xf91f6079, + 0x761c27fb, + 0xefdf5da7, + 0xcfdc7fdd, + 0xd09c4bf8, + 0x47fd7c1f, + 0x761ccfcf, + 0x7eef7fed, + 0x7dfdf093, + 0xef7e7f1e, + 0x771efb18, + 0x6079e722, + 0xe6bbe5bb, + 0xae0ae5bb, + 0x600bae85, + 0xe2bbe2bb, + 0xe2bbe2bb, + 0xaf02e2bb, + 0xe2bb2ff9, + 0x6079e2bb +}; + +uint patch_2f00[] = { + 0x30303030, + 0x3e3e3434, + 0xabbf9b99, + 0x4b4fbdbd, + 0x59949334, + 0x9fff37fb, + 0x9b177dd9, + 0x936956bb, + 0xfbdd697b, + 0xdd2fd113, + 0x1db9f7bb, + 0x36313963, + 0x79373369, + 0x3193137f, + 0x7331737a, + 0xf7bb9b99, + 0x9bb19795, + 0x77fdfd3d, + 0x573b773f, + 0x737933f7, + 0xb991d115, + 0x31699315, + 0x31531694, + 0xbf4fbdbd, + 0x35931497, + 0x35376956, + 0xbd697b9d, + 0x96931313, + 0x19797937, + 0x6935af78, + 0xb9b3baa3, + 0xb8788683, + 0x368f78f7, + 0x87778733, + 0x3ffffb3b, + 0x8e8f78b8, + 0x1d118e13, + 0xf3ff3f8b, + 0x6bd8e173, + 0xd1366856, + 0x68d1687b, + 0x3daf78b8, + 0x3a3a3f87, + 0x8f81378f, + 0xf876f887, + 0x77fd8778, + 0x737de8d6, + 0xbbf8bfff, + 0xd8df87f7, + 0xfd876f7b, + 0x8bfff8bd, + 0x8683387d, + 0xb873d87b, + 0x3b8fd7f8, + 0xf7338883, + 0xbb8ee1f8, + 0xef837377, + 0x3337b836, + 0x817d11f8, + 0x7378b878, + 0xd3368b7d, + 0xed731b7d, + 0x833731f3, + 0xf22f3f23 +}; + +uint patch_2e00[] = { + 0x27eeeeee, + 0xeeeeeeee, + 0xeeeeeeee, + 0xeeeeeeee, + 0xee4bf4fb, + 0xdbd259bb, + 0x1979577f, + 0xdfd2d573, + 0xb773f737, + 0x4b4fbdbd, + 0x25b9b177, + 0xd2d17376, + 0x956bbfdd, + 0x697bdd2f, + 0xff9f79ff, + 0xff9ff22f +}; +#endif + +/* + * USB SOF patch arrays. + */ + +#ifdef CONFIG_USB_SOF_UCODE_PATCH + +uint patch_2000[] = { + 0x7fff0000, + 0x7ffd0000, + 0x7ffb0000, + 0x49f7ba5b, + 0xba383ffb, + 0xf9b8b46d, + 0xe5ab4e07, + 0xaf77bffe, + 0x3f7bbf79, + 0xba5bba38, + 0xe7676076, + 0x60750000 +}; + +uint patch_2f00[] = { + 0x3030304c, + 0xcab9e441, + 0xa1aaf220 +}; +#endif + +void +cpm_load_patch(cpm8xx_t *cp) +{ + volatile uint *dp; /* Dual-ported RAM. */ + volatile cpm8xx_t *commproc; + volatile iic_t *iip; + volatile spi_t *spp; + volatile smc_uart_t *smp; + int i; + + commproc = cp; + +#ifdef CONFIG_USB_SOF_UCODE_PATCH + commproc->cp_rccr = 0; + + dp = (uint *)(commproc->cp_dpmem); + for (i=0; i<(sizeof(patch_2000)/4); i++) + *dp++ = patch_2000[i]; + + dp = (uint *)&(commproc->cp_dpmem[0x0f00]); + for (i=0; i<(sizeof(patch_2f00)/4); i++) + *dp++ = patch_2f00[i]; + + commproc->cp_rccr = 0x0009; + + printk("USB SOF microcode patch installed\n"); +#endif /* CONFIG_USB_SOF_UCODE_PATCH */ + +#if defined(CONFIG_I2C_SPI_UCODE_PATCH) || \ + defined(CONFIG_I2C_SPI_SMC1_UCODE_PATCH) + + commproc->cp_rccr = 0; + + dp = (uint *)(commproc->cp_dpmem); + for (i=0; i<(sizeof(patch_2000)/4); i++) + *dp++ = patch_2000[i]; + + dp = (uint *)&(commproc->cp_dpmem[0x0f00]); + for (i=0; i<(sizeof(patch_2f00)/4); i++) + *dp++ = patch_2f00[i]; + + iip = (iic_t *)&commproc->cp_dparam[PROFF_IIC]; +# define RPBASE 0x0500 + iip->iic_rpbase = RPBASE; + + /* Put SPI above the IIC, also 32-byte aligned. + */ + i = (RPBASE + sizeof(iic_t) + 31) & ~31; + spp = (spi_t *)&commproc->cp_dparam[PROFF_SPI]; + spp->spi_rpbase = i; + +# if defined(CONFIG_I2C_SPI_UCODE_PATCH) + commproc->cp_cpmcr1 = 0x802a; + commproc->cp_cpmcr2 = 0x8028; + commproc->cp_cpmcr3 = 0x802e; + commproc->cp_cpmcr4 = 0x802c; + commproc->cp_rccr = 1; + + printk("I2C/SPI microcode patch installed.\n"); +# endif /* CONFIG_I2C_SPI_UCODE_PATCH */ + +# if defined(CONFIG_I2C_SPI_SMC1_UCODE_PATCH) + + dp = (uint *)&(commproc->cp_dpmem[0x0e00]); + for (i=0; i<(sizeof(patch_2e00)/4); i++) + *dp++ = patch_2e00[i]; + + commproc->cp_cpmcr1 = 0x8080; + commproc->cp_cpmcr2 = 0x808a; + commproc->cp_cpmcr3 = 0x8028; + commproc->cp_cpmcr4 = 0x802a; + commproc->cp_rccr = 3; + + smp = (smc_uart_t *)&commproc->cp_dparam[PROFF_SMC1]; + smp->smc_rpbase = 0x1FC0; + + printk("I2C/SPI/SMC1 microcode patch installed.\n"); +# endif /* CONFIG_I2C_SPI_SMC1_UCODE_PATCH) */ + +#endif /* some variation of the I2C/SPI patch was selected */ +} + +/* + * Take this entire routine out, since no one calls it and its + * logic is suspect. + */ + +#if 0 +void +verify_patch(volatile immap_t *immr) +{ + volatile uint *dp; + volatile cpm8xx_t *commproc; + int i; + + commproc = (cpm8xx_t *)&immr->im_cpm; + + printk("cp_rccr %x\n", commproc->cp_rccr); + commproc->cp_rccr = 0; + + dp = (uint *)(commproc->cp_dpmem); + for (i=0; i<(sizeof(patch_2000)/4); i++) + if (*dp++ != patch_2000[i]) { + printk("patch_2000 bad at %d\n", i); + dp--; + printk("found 0x%X, wanted 0x%X\n", *dp, patch_2000[i]); + break; + } + + dp = (uint *)&(commproc->cp_dpmem[0x0f00]); + for (i=0; i<(sizeof(patch_2f00)/4); i++) + if (*dp++ != patch_2f00[i]) { + printk("patch_2f00 bad at %d\n", i); + dp--; + printk("found 0x%X, wanted 0x%X\n", *dp, patch_2f00[i]); + break; + } + + commproc->cp_rccr = 0x0009; +} +#endif diff --git a/arch/powerpc/sysdev/mpc8xx_pic.c b/arch/powerpc/sysdev/mpc8xx_pic.c new file mode 100644 index 0000000..2fc2bcd --- /dev/null +++ b/arch/powerpc/sysdev/mpc8xx_pic.c @@ -0,0 +1,197 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "mpc8xx_pic.h" + + +#define PIC_VEC_SPURRIOUS 15 + +extern int cpm_get_irq(struct pt_regs *regs); + +static struct device_node *mpc8xx_pic_node; +static struct irq_host *mpc8xx_pic_host; +#define NR_MASK_WORDS ((NR_IRQS + 31) / 32) +static unsigned long ppc_cached_irq_mask[NR_MASK_WORDS]; +static sysconf8xx_t *siu_reg; + +int cpm_get_irq(struct pt_regs *regs); + +static void mpc8xx_unmask_irq(unsigned int virq) +{ + int bit, word; + unsigned int irq_nr = (unsigned int)irq_map[virq].hwirq; + + bit = irq_nr & 0x1f; + word = irq_nr >> 5; + + ppc_cached_irq_mask[word] |= (1 << (31-bit)); + out_be32(&siu_reg->sc_simask, ppc_cached_irq_mask[word]); +} + +static void mpc8xx_mask_irq(unsigned int virq) +{ + int bit, word; + unsigned int irq_nr = (unsigned int)irq_map[virq].hwirq; + + bit = irq_nr & 0x1f; + word = irq_nr >> 5; + + ppc_cached_irq_mask[word] &= ~(1 << (31-bit)); + out_be32(&siu_reg->sc_simask, ppc_cached_irq_mask[word]); +} + +static void mpc8xx_ack(unsigned int virq) +{ + int bit; + unsigned int irq_nr = (unsigned int)irq_map[virq].hwirq; + + bit = irq_nr & 0x1f; + out_be32(&siu_reg->sc_sipend, 1 << (31-bit)); +} + +static void mpc8xx_end_irq(unsigned int virq) +{ + int bit, word; + unsigned int irq_nr = (unsigned int)irq_map[virq].hwirq; + + bit = irq_nr & 0x1f; + word = irq_nr >> 5; + + ppc_cached_irq_mask[word] |= (1 << (31-bit)); + out_be32(&siu_reg->sc_simask, ppc_cached_irq_mask[word]); +} + +static int mpc8xx_set_irq_type(unsigned int virq, unsigned int flow_type) +{ + struct irq_desc *desc = get_irq_desc(virq); + + desc->status &= ~(IRQ_TYPE_SENSE_MASK | IRQ_LEVEL); + desc->status |= flow_type & IRQ_TYPE_SENSE_MASK; + if (flow_type & (IRQ_TYPE_LEVEL_HIGH | IRQ_TYPE_LEVEL_LOW)) + desc->status |= IRQ_LEVEL; + + if (flow_type & IRQ_TYPE_EDGE_FALLING) { + irq_hw_number_t hw = (unsigned int)irq_map[virq].hwirq; + unsigned int siel = in_be32(&siu_reg->sc_siel); + + /* only external IRQ senses are programmable */ + if ((hw & 1) == 0) { + siel |= (0x80000000 >> hw); + out_be32(&siu_reg->sc_siel, siel); + desc->handle_irq = handle_edge_irq; + } + } + return 0; +} + +static struct irq_chip mpc8xx_pic = { + .typename = " MPC8XX SIU ", + .unmask = mpc8xx_unmask_irq, + .mask = mpc8xx_mask_irq, + .ack = mpc8xx_ack, + .eoi = mpc8xx_end_irq, + .set_type = mpc8xx_set_irq_type, +}; + +unsigned int mpc8xx_get_irq(void) +{ + int irq; + + /* For MPC8xx, read the SIVEC register and shift the bits down + * to get the irq number. + */ + irq = in_be32(&siu_reg->sc_sivec) >> 26; + + if (irq == PIC_VEC_SPURRIOUS) + irq = NO_IRQ; + + return irq_linear_revmap(mpc8xx_pic_host, irq); + +} + +static int mpc8xx_pic_host_match(struct irq_host *h, struct device_node *node) +{ + return mpc8xx_pic_node == node; +} + +static int mpc8xx_pic_host_map(struct irq_host *h, unsigned int virq, + irq_hw_number_t hw) +{ + pr_debug("mpc8xx_pic_host_map(%d, 0x%lx)\n", virq, hw); + + /* Set default irq handle */ + set_irq_chip_and_handler(virq, &mpc8xx_pic, handle_level_irq); + return 0; +} + + +static int mpc8xx_pic_host_xlate(struct irq_host *h, struct device_node *ct, + u32 *intspec, unsigned int intsize, + irq_hw_number_t *out_hwirq, unsigned int *out_flags) +{ + static unsigned char map_pic_senses[4] = { + IRQ_TYPE_EDGE_RISING, + IRQ_TYPE_LEVEL_LOW, + IRQ_TYPE_LEVEL_HIGH, + IRQ_TYPE_EDGE_FALLING, + }; + + *out_hwirq = intspec[0]; + if (intsize > 1 && intspec[1] < 4) + *out_flags = map_pic_senses[intspec[1]]; + else + *out_flags = IRQ_TYPE_NONE; + + return 0; +} + + +static struct irq_host_ops mpc8xx_pic_host_ops = { + .match = mpc8xx_pic_host_match, + .map = mpc8xx_pic_host_map, + .xlate = mpc8xx_pic_host_xlate, +}; + +int mpc8xx_pic_init(void) +{ + struct resource res; + struct device_node *np = NULL; + int ret; + + np = of_find_node_by_type(np, "mpc8xx-pic"); + + if (np == NULL) { + printk(KERN_ERR "Could not find open-pic node\n"); + return -ENOMEM; + } + + mpc8xx_pic_node = of_node_get(np); + + ret = of_address_to_resource(np, 0, &res); + of_node_put(np); + if (ret) + return ret; + + siu_reg = (void *)ioremap(res.start, res.end - res.start + 1); + if (siu_reg == NULL) + return -EINVAL; + + mpc8xx_pic_host = irq_alloc_host(IRQ_HOST_MAP_LINEAR, 64, &mpc8xx_pic_host_ops, 64); + if (mpc8xx_pic_host == NULL) { + printk(KERN_ERR "MPC8xx PIC: failed to allocate irq host!\n"); + ret = -ENOMEM; + } + + return ret; +} diff --git a/arch/powerpc/sysdev/mpc8xx_pic.h b/arch/powerpc/sysdev/mpc8xx_pic.h new file mode 100644 index 0000000..afa2ee6 --- /dev/null +++ b/arch/powerpc/sysdev/mpc8xx_pic.h @@ -0,0 +1,12 @@ +#ifndef _PPC_KERNEL_MPC8xx_H +#define _PPC_KERNEL_MPC8xx_H + +#include +#include + +extern struct hw_interrupt_type mpc8xx_pic; + +int mpc8xx_pic_init(void); +unsigned int mpc8xx_get_irq(void); + +#endif /* _PPC_KERNEL_PPC8xx_H */ diff --git a/arch/powerpc/sysdev/mpic.c b/arch/powerpc/sysdev/mpic.c index d01ced1..4e54a09 100644 --- a/arch/powerpc/sysdev/mpic.c +++ b/arch/powerpc/sysdev/mpic.c @@ -496,13 +496,18 @@ #define mpic_irq_to_hw(virq) ((unsigned static struct mpic *mpic_find(unsigned int irq, unsigned int *is_ipi) { unsigned int src = mpic_irq_to_hw(irq); + struct mpic *mpic; if (irq < NUM_ISA_INTERRUPTS) return NULL; + + mpic = irq_desc[irq].chip_data; + if (is_ipi) - *is_ipi = (src >= MPIC_VEC_IPI_0 && src <= MPIC_VEC_IPI_3); + *is_ipi = (src >= mpic->ipi_vecs[0] && + src <= mpic->ipi_vecs[3]); - return irq_desc[irq].chip_data; + return mpic; } /* Convert a cpu mask from logical to physical cpu numbers. */ @@ -540,7 +545,11 @@ static inline void mpic_eoi(struct mpic #ifdef CONFIG_SMP static irqreturn_t mpic_ipi_action(int irq, void *dev_id) { - smp_message_recv(mpic_irq_to_hw(irq) - MPIC_VEC_IPI_0); + struct mpic *mpic; + + mpic = mpic_find(irq, NULL); + smp_message_recv(mpic_irq_to_hw(irq) - mpic->ipi_vecs[0]); + return IRQ_HANDLED; } #endif /* CONFIG_SMP */ @@ -663,7 +672,7 @@ #ifdef CONFIG_SMP static void mpic_unmask_ipi(unsigned int irq) { struct mpic *mpic = mpic_from_ipi(irq); - unsigned int src = mpic_irq_to_hw(irq) - MPIC_VEC_IPI_0; + unsigned int src = mpic_irq_to_hw(irq) - mpic->ipi_vecs[0]; DBG("%s: enable_ipi: %d (ipi %d)\n", mpic->name, irq, src); mpic_ipi_write(src, mpic_ipi_read(src) & ~MPIC_VECPRI_MASK); @@ -807,11 +816,11 @@ static int mpic_host_map(struct irq_host DBG("mpic: map virq %d, hwirq 0x%lx\n", virq, hw); - if (hw == MPIC_VEC_SPURRIOUS) + if (hw == mpic->spurious_vec) return -EINVAL; #ifdef CONFIG_SMP - else if (hw >= MPIC_VEC_IPI_0) { + else if (hw >= mpic->ipi_vecs[0]) { WARN_ON(!(mpic->flags & MPIC_PRIMARY)); DBG("mpic: mapping as IPI\n"); @@ -904,6 +913,7 @@ struct mpic * __init mpic_alloc(struct d u32 reg; const char *vers; int i; + int intvec_top; u64 paddr = phys_addr; mpic = alloc_bootmem(sizeof(struct mpic)); @@ -912,11 +922,11 @@ struct mpic * __init mpic_alloc(struct d memset(mpic, 0, sizeof(struct mpic)); mpic->name = name; - mpic->of_node = node ? of_node_get(node) : NULL; + mpic->of_node = of_node_get(node); - mpic->irqhost = irq_alloc_host(IRQ_HOST_MAP_LINEAR, 256, + mpic->irqhost = irq_alloc_host(IRQ_HOST_MAP_LINEAR, isu_size, &mpic_host_ops, - MPIC_VEC_SPURRIOUS); + flags & MPIC_LARGE_VECTORS ? 2048 : 256); if (mpic->irqhost == NULL) { of_node_put(node); return NULL; @@ -944,6 +954,21 @@ #endif /* CONFIG_SMP */ mpic->irq_count = irq_count; mpic->num_sources = 0; /* so far */ + if (flags & MPIC_LARGE_VECTORS) + intvec_top = 2047; + else + intvec_top = 255; + + mpic->timer_vecs[0] = intvec_top - 8; + mpic->timer_vecs[1] = intvec_top - 7; + mpic->timer_vecs[2] = intvec_top - 6; + mpic->timer_vecs[3] = intvec_top - 5; + mpic->ipi_vecs[0] = intvec_top - 4; + mpic->ipi_vecs[1] = intvec_top - 3; + mpic->ipi_vecs[2] = intvec_top - 2; + mpic->ipi_vecs[3] = intvec_top - 1; + mpic->spurious_vec = intvec_top; + /* Check for "big-endian" in device-tree */ if (node && get_property(node, "big-endian", NULL) != NULL) mpic->flags |= MPIC_BIG_ENDIAN; @@ -1084,11 +1109,6 @@ void __init mpic_init(struct mpic *mpic) int i; BUG_ON(mpic->num_sources == 0); - WARN_ON(mpic->num_sources > MPIC_VEC_IPI_0); - - /* Sanitize source count */ - if (mpic->num_sources > MPIC_VEC_IPI_0) - mpic->num_sources = MPIC_VEC_IPI_0; printk(KERN_INFO "mpic: Initializing for %d sources\n", mpic->num_sources); @@ -1104,7 +1124,7 @@ void __init mpic_init(struct mpic *mpic) i * MPIC_INFO(TIMER_STRIDE) + MPIC_INFO(TIMER_VECTOR_PRI), MPIC_VECPRI_MASK | - (MPIC_VEC_TIMER_0 + i)); + (mpic->timer_vecs[0] + i)); } /* Initialize IPIs to our reserved vectors and mark them disabled for now */ @@ -1113,7 +1133,7 @@ void __init mpic_init(struct mpic *mpic) mpic_ipi_write(i, MPIC_VECPRI_MASK | (10 << MPIC_VECPRI_PRIORITY_SHIFT) | - (MPIC_VEC_IPI_0 + i)); + (mpic->ipi_vecs[0] + i)); } /* Initialize interrupt sources */ @@ -1136,8 +1156,8 @@ void __init mpic_init(struct mpic *mpic) 1 << hard_smp_processor_id()); } - /* Init spurrious vector */ - mpic_write(mpic->gregs, MPIC_INFO(GREG_SPURIOUS), MPIC_VEC_SPURRIOUS); + /* Init spurious vector */ + mpic_write(mpic->gregs, MPIC_INFO(GREG_SPURIOUS), mpic->spurious_vec); /* Disable 8259 passthrough, if supported */ if (!(mpic->flags & MPIC_NO_PTHROU_DIS)) @@ -1184,9 +1204,9 @@ void mpic_irq_set_priority(unsigned int spin_lock_irqsave(&mpic_lock, flags); if (is_ipi) { - reg = mpic_ipi_read(src - MPIC_VEC_IPI_0) & + reg = mpic_ipi_read(src - mpic->ipi_vecs[0]) & ~MPIC_VECPRI_PRIORITY_MASK; - mpic_ipi_write(src - MPIC_VEC_IPI_0, + mpic_ipi_write(src - mpic->ipi_vecs[0], reg | (pri << MPIC_VECPRI_PRIORITY_SHIFT)); } else { reg = mpic_irq_read(src, MPIC_INFO(IRQ_VECTOR_PRI)) @@ -1207,7 +1227,7 @@ unsigned int mpic_irq_get_priority(unsig spin_lock_irqsave(&mpic_lock, flags); if (is_ipi) - reg = mpic_ipi_read(src = MPIC_VEC_IPI_0); + reg = mpic_ipi_read(src = mpic->ipi_vecs[0]); else reg = mpic_irq_read(src, MPIC_INFO(IRQ_VECTOR_PRI)); spin_unlock_irqrestore(&mpic_lock, flags); @@ -1313,7 +1333,7 @@ unsigned int mpic_get_one_irq(struct mpi #ifdef DEBUG_LOW DBG("%s: get_one_irq(): %d\n", mpic->name, src); #endif - if (unlikely(src == MPIC_VEC_SPURRIOUS)) + if (unlikely(src == mpic->spurious_vec)) return NO_IRQ; return irq_linear_revmap(mpic->irqhost, src); } @@ -1345,7 +1365,7 @@ void mpic_request_ipis(void) for (i = 0; i < 4; i++) { unsigned int vipi = irq_create_mapping(mpic->irqhost, - MPIC_VEC_IPI_0 + i); + mpic->ipi_vecs[0] + i); if (vipi == NO_IRQ) { printk(KERN_ERR "Failed to map IPI %d\n", i); break; @@ -1375,4 +1395,25 @@ void smp_mpic_message_pass(int target, i break; } } + +int __init smp_mpic_probe(void) +{ + int nr_cpus; + + DBG("smp_mpic_probe()...\n"); + + nr_cpus = cpus_weight(cpu_possible_map); + + DBG("nr_cpus: %d\n", nr_cpus); + + if (nr_cpus > 1) + mpic_request_ipis(); + + return nr_cpus; +} + +void __devinit smp_mpic_setup_cpu(int cpu) +{ + mpic_setup_this_cpu(); +} #endif /* CONFIG_SMP */ diff --git a/arch/powerpc/sysdev/qe_lib/qe_ic.c b/arch/powerpc/sysdev/qe_lib/qe_ic.c index 74e48d9..4d1dcb4 100644 --- a/arch/powerpc/sysdev/qe_lib/qe_ic.c +++ b/arch/powerpc/sysdev/qe_lib/qe_ic.c @@ -323,7 +323,7 @@ unsigned int qe_ic_get_high_irq(struct q return irq_linear_revmap(qe_ic->irqhost, irq); } -void fastcall qe_ic_cascade_low(unsigned int irq, struct irq_desc *desc) +void qe_ic_cascade_low(unsigned int irq, struct irq_desc *desc) { struct qe_ic *qe_ic = desc->handler_data; unsigned int cascade_irq = qe_ic_get_low_irq(qe_ic); @@ -332,7 +332,7 @@ void fastcall qe_ic_cascade_low(unsigned generic_handle_irq(cascade_irq); } -void fastcall qe_ic_cascade_high(unsigned int irq, struct irq_desc *desc) +void qe_ic_cascade_high(unsigned int irq, struct irq_desc *desc) { struct qe_ic *qe_ic = desc->handler_data; unsigned int cascade_irq = qe_ic_get_high_irq(qe_ic); @@ -352,7 +352,7 @@ void __init qe_ic_init(struct device_nod return; memset(qe_ic, 0, sizeof(struct qe_ic)); - qe_ic->of_node = node ? of_node_get(node) : NULL; + qe_ic->of_node = of_node_get(node); qe_ic->irqhost = irq_alloc_host(IRQ_HOST_MAP_LINEAR, NR_QE_IC_INTS, &qe_ic_host_ops, 0); diff --git a/arch/powerpc/sysdev/qe_lib/ucc_slow.c b/arch/powerpc/sysdev/qe_lib/ucc_slow.c index 47b5620..0e97e5c 100644 --- a/arch/powerpc/sysdev/qe_lib/ucc_slow.c +++ b/arch/powerpc/sysdev/qe_lib/ucc_slow.c @@ -179,7 +179,7 @@ int ucc_slow_init(struct ucc_slow_info * uccs->us_info = us_info; uccs->saved_uccm = 0; uccs->p_rx_frame = 0; - uccs->us_regs = us_info->us_regs; + uccs->us_regs = us_info->regs; us_regs = uccs->us_regs; uccs->p_ucce = (u16 *) & (us_regs->ucce); uccs->p_uccm = (u16 *) & (us_regs->uccm); @@ -206,7 +206,7 @@ #endif /* STATISTICS */ uccs->us_pram = qe_muram_addr(uccs->us_pram_offset); /* Init Guemr register */ - if ((ret = ucc_init_guemr((struct ucc_common *) (us_info->us_regs)))) { + if ((ret = ucc_init_guemr((struct ucc_common *) (us_info->regs)))) { uccs_err("ucc_slow_init: Could not init the guemr register."); ucc_slow_free(uccs); return ret; @@ -214,7 +214,7 @@ #endif /* STATISTICS */ /* Set UCC to slow type */ if ((ret = ucc_set_type(us_info->ucc_num, - (struct ucc_common *) (us_info->us_regs), + (struct ucc_common *) (us_info->regs), UCC_SPEED_TYPE_SLOW))) { uccs_err("ucc_slow_init: Could not init the guemr register."); ucc_slow_free(uccs); diff --git a/arch/powerpc/xmon/ppc-opc.c b/arch/powerpc/xmon/ppc-opc.c index 5d841f4..af3780e 100644 --- a/arch/powerpc/xmon/ppc-opc.c +++ b/arch/powerpc/xmon/ppc-opc.c @@ -21,6 +21,7 @@ 02110-1301, USA. */ #include +#include #include "nonstdio.h" #include "ppc.h" @@ -4932,8 +4933,7 @@ const struct powerpc_opcode powerpc_opco }; -const int powerpc_num_opcodes = - sizeof (powerpc_opcodes) / sizeof (powerpc_opcodes[0]); +const int powerpc_num_opcodes = ARRAY_SIZE(powerpc_opcodes); /* The macro table. This is only used by the assembler. */ @@ -4989,5 +4989,4 @@ const struct powerpc_macro powerpc_macro { "clrlslwi.",4, PPCCOM, "rlwinm. %0,%1,%3,(%2)-(%3),31-(%3)" }, }; -const int powerpc_num_macros = - sizeof (powerpc_macros) / sizeof (powerpc_macros[0]); +const int powerpc_num_macros = ARRAY_SIZE(powerpc_macros); diff --git a/arch/powerpc/xmon/spu-dis.c b/arch/powerpc/xmon/spu-dis.c index ee929c6..e5f8983 100644 --- a/arch/powerpc/xmon/spu-dis.c +++ b/arch/powerpc/xmon/spu-dis.c @@ -85,7 +85,7 @@ get_index_for_opcode (unsigned int insn) if ((index = spu_disassemble_table[opcode & 0x7ff]) != 0) return index; - return 0; + return NULL; } /* Print a Spu instruction. */ diff --git a/arch/powerpc/xmon/spu-opc.c b/arch/powerpc/xmon/spu-opc.c index efffde9..530df3d 100644 --- a/arch/powerpc/xmon/spu-opc.c +++ b/arch/powerpc/xmon/spu-opc.c @@ -18,6 +18,7 @@ with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA. */ +#include #include "spu.h" /* This file holds the Spu opcode table */ @@ -40,5 +41,4 @@ #undef APUOP #undef APUOPFB }; -const int spu_num_opcodes = - sizeof (spu_opcodes) / sizeof (spu_opcodes[0]); +const int spu_num_opcodes = ARRAY_SIZE(spu_opcodes); diff --git a/arch/powerpc/xmon/xmon.c b/arch/powerpc/xmon/xmon.c index 77540a2..0183e5f 100644 --- a/arch/powerpc/xmon/xmon.c +++ b/arch/powerpc/xmon/xmon.c @@ -2811,7 +2811,6 @@ static void dump_spu_fields(struct spu * DUMP_FIELD(spu, "0x%lx", irqs[2]); DUMP_FIELD(spu, "0x%x", slb_replace); DUMP_FIELD(spu, "%d", pid); - DUMP_FIELD(spu, "%d", prio); DUMP_FIELD(spu, "0x%p", mm); DUMP_FIELD(spu, "0x%p", ctx); DUMP_FIELD(spu, "0x%p", rq); diff --git a/arch/ppc/8xx_io/cs4218_tdm.c b/arch/ppc/8xx_io/cs4218_tdm.c index b7bb5f0..a956f28 100644 --- a/arch/ppc/8xx_io/cs4218_tdm.c +++ b/arch/ppc/8xx_io/cs4218_tdm.c @@ -1379,7 +1379,6 @@ #endif } static DEFINE_TIMER(beep_timer, cs_nosound, 0, 0); -}; static void cs_mksound(unsigned int hz, unsigned int ticks) { @@ -1712,7 +1711,7 @@ static int mixer_ioctl(struct inode *ino } -static struct file_operations mixer_fops = +static const struct file_operations mixer_fops = { .owner = THIS_MODULE, .llseek = sound_lseek, @@ -2299,7 +2298,7 @@ #endif -static struct file_operations sq_fops = +static const struct file_operations sq_fops = { .owner = THIS_MODULE, .llseek = sound_lseek, @@ -2434,7 +2433,7 @@ static ssize_t state_read(struct file *f } -static struct file_operations state_fops = +static const struct file_operations state_fops = { .owner = THIS_MODULE, .llseek = sound_lseek, diff --git a/arch/ppc/Kconfig b/arch/ppc/Kconfig index 8eb82ef..0df9c33 100644 --- a/arch/ppc/Kconfig +++ b/arch/ppc/Kconfig @@ -670,15 +670,6 @@ config RADSTONE_PPC7D config PAL4 bool "SBS-Palomar4" -config GEMINI - bool "Synergy-Gemini" - depends on BROKEN - select PPC_INDIRECT_PCI - help - Select Gemini if configuring for a Synergy Microsystems' Gemini - series Single Board Computer. More information is available at: - . - config EST8260 bool "EST8260" ---help--- @@ -1186,6 +1177,10 @@ config ISA have an IBM RS/6000 or pSeries machine or a PReP machine, say Y. If you have an embedded board, consult your board documentation. +config ZONE_DMA + bool + default y + config GENERIC_ISA_DMA bool depends on 6xx && !CPM2 diff --git a/arch/ppc/boot/simple/Makefile b/arch/ppc/boot/simple/Makefile index 28be01b..bcfb6cd 100644 --- a/arch/ppc/boot/simple/Makefile +++ b/arch/ppc/boot/simple/Makefile @@ -116,10 +116,6 @@ zimageinitrd-$(CONFIG_WALNUT) := zImage extra.o-$(CONFIG_CHESTNUT) := misc-chestnut.o end-$(CONFIG_CHESTNUT) := chestnut - zimage-$(CONFIG_GEMINI) := zImage-STRIPELF -zimageinitrd-$(CONFIG_GEMINI) := zImage.initrd-STRIPELF - end-$(CONFIG_GEMINI) := gemini - extra.o-$(CONFIG_KATANA) := misc-katana.o end-$(CONFIG_KATANA) := katana cacheflag-$(CONFIG_KATANA) := -include $(clear_L2_L3) diff --git a/arch/ppc/boot/simple/misc.c b/arch/ppc/boot/simple/misc.c index a5df089..c3d3305 100644 --- a/arch/ppc/boot/simple/misc.c +++ b/arch/ppc/boot/simple/misc.c @@ -42,14 +42,11 @@ #define HAS_KEYB 0 #endif /* Will / Can the user give input? - * Val Henson has requested that Gemini doesn't wait for the - * user to edit the cmdline or not. */ #if (defined(CONFIG_SERIAL_8250_CONSOLE) \ || defined(CONFIG_VGA_CONSOLE) \ || defined(CONFIG_SERIAL_MPC52xx_CONSOLE) \ - || defined(CONFIG_SERIAL_MPSC_CONSOLE)) \ - && !defined(CONFIG_GEMINI) + || defined(CONFIG_SERIAL_MPSC_CONSOLE)) #define INTERACTIVE_CONSOLE 1 #endif @@ -178,16 +175,6 @@ #endif if (keyb_present) CRT_tstc(); /* Forces keyboard to be initialized */ -#ifdef CONFIG_GEMINI - /* - * If cmd_line is empty and cmd_preset is not, copy cmd_preset - * to cmd_line. This way we can override cmd_preset with the - * command line from Smon. - */ - - if ( (cmd_line[0] == '\0') && (cmd_preset[0] != '\0')) - memcpy (cmd_line, cmd_preset, sizeof(cmd_preset)); -#endif /* Display standard Linux/PPC boot prompt for kernel args */ puts("\nLinux/PPC load: "); diff --git a/arch/ppc/configs/gemini_defconfig b/arch/ppc/configs/gemini_defconfig deleted file mode 100644 index ebcd17b..0000000 --- a/arch/ppc/configs/gemini_defconfig +++ /dev/null @@ -1,618 +0,0 @@ -# -# Automatically generated make config: don't edit -# -CONFIG_MMU=y -CONFIG_RWSEM_XCHGADD_ALGORITHM=y -CONFIG_HAVE_DEC_LOCK=y - -# -# Code maturity level options -# -CONFIG_EXPERIMENTAL=y - -# -# General setup -# -CONFIG_SWAP=y -CONFIG_SYSVIPC=y -# CONFIG_BSD_PROCESS_ACCT is not set -CONFIG_SYSCTL=y -CONFIG_LOG_BUF_SHIFT=14 -# CONFIG_EMBEDDED is not set -CONFIG_FUTEX=y -CONFIG_EPOLL=y - -# -# Loadable module support -# -CONFIG_MODULES=y -CONFIG_MODULE_UNLOAD=y -# CONFIG_MODULE_FORCE_UNLOAD is not set -CONFIG_OBSOLETE_MODPARM=y -# CONFIG_MODVERSIONS is not set -CONFIG_KMOD=y - -# -# Platform support -# -CONFIG_PPC=y -CONFIG_PPC32=y -CONFIG_6xx=y -# CONFIG_40x is not set -# CONFIG_POWER3 is not set -# CONFIG_8xx is not set - -# -# IBM 4xx options -# -# CONFIG_8260 is not set -CONFIG_GENERIC_ISA_DMA=y -CONFIG_PPC_STD_MMU=y -# CONFIG_PPC_MULTIPLATFORM is not set -# CONFIG_APUS is not set -# CONFIG_WILLOW_2 is not set -# CONFIG_PCORE is not set -# CONFIG_POWERPMC250 is not set -# CONFIG_EV64260 is not set -# CONFIG_SPRUCE is not set -# CONFIG_LOPEC is not set -# CONFIG_MCPN765 is not set -# CONFIG_MVME5100 is not set -# CONFIG_PPLUS is not set -# CONFIG_PRPMC750 is not set -# CONFIG_PRPMC800 is not set -# CONFIG_SANDPOINT is not set -# CONFIG_ADIR is not set -# CONFIG_K2 is not set -# CONFIG_PAL4 is not set -CONFIG_GEMINI=y -# CONFIG_SMP is not set -# CONFIG_PREEMPT is not set -CONFIG_ALTIVEC=y -CONFIG_TAU=y -# CONFIG_TAU_INT is not set -# CONFIG_TAU_AVERAGE is not set -# CONFIG_CPU_FREQ is not set - -# -# General setup -# -# CONFIG_HIGHMEM is not set -CONFIG_PCI=y -CONFIG_PCI_DOMAINS=y -CONFIG_KCORE_ELF=y -CONFIG_BINFMT_ELF=y -CONFIG_KERNEL_ELF=y -# CONFIG_BINFMT_MISC is not set -CONFIG_PCI_LEGACY_PROC=y -CONFIG_PCI_NAMES=y -# CONFIG_HOTPLUG is not set - -# -# Parallel port support -# -# CONFIG_PARPORT is not set -# CONFIG_PPC601_SYNC_FIX is not set -# CONFIG_CMDLINE_BOOL is not set - -# -# Advanced setup -# -# CONFIG_ADVANCED_OPTIONS is not set - -# -# Default settings for advanced configuration options are used -# -CONFIG_HIGHMEM_START=0xfe000000 -CONFIG_LOWMEM_SIZE=0x30000000 -CONFIG_KERNEL_START=0xc0000000 -CONFIG_TASK_SIZE=0x80000000 -CONFIG_BOOT_LOAD=0x00800000 - -# -# Memory Technology Devices (MTD) -# -# CONFIG_MTD is not set - -# -# Plug and Play support -# -# CONFIG_PNP is not set - -# -# Block devices -# -# CONFIG_BLK_DEV_FD is not set -# CONFIG_BLK_CPQ_DA is not set -# CONFIG_BLK_CPQ_CISS_DA is not set -# CONFIG_BLK_DEV_DAC960 is not set -# CONFIG_BLK_DEV_UMEM is not set -# CONFIG_BLK_DEV_LOOP is not set -# CONFIG_BLK_DEV_NBD is not set -CONFIG_BLK_DEV_RAM=y -CONFIG_BLK_DEV_RAM_SIZE=4096 -CONFIG_BLK_DEV_INITRD=y - -# -# Multi-device support (RAID and LVM) -# -# CONFIG_MD is not set - -# -# ATA/IDE/MFM/RLL support -# -# CONFIG_IDE is not set - -# -# SCSI support -# -CONFIG_SCSI=y - -# -# SCSI support type (disk, tape, CD-ROM) -# -CONFIG_BLK_DEV_SD=y -# CONFIG_CHR_DEV_ST is not set -# CONFIG_CHR_DEV_OSST is not set -CONFIG_BLK_DEV_SR=y -CONFIG_BLK_DEV_SR_VENDOR=y -CONFIG_CHR_DEV_SG=y - -# -# Some SCSI devices (e.g. CD jukebox) support multiple LUNs -# -# CONFIG_SCSI_MULTI_LUN is not set -# CONFIG_SCSI_REPORT_LUNS is not set -CONFIG_SCSI_CONSTANTS=y -# CONFIG_SCSI_LOGGING is not set - -# -# SCSI low-level drivers -# -# CONFIG_BLK_DEV_3W_XXXX_RAID is not set -# CONFIG_SCSI_ACARD is not set -# CONFIG_SCSI_AACRAID is not set -# CONFIG_SCSI_AIC7XXX is not set -# CONFIG_SCSI_AIC7XXX_OLD is not set -# CONFIG_SCSI_AIC79XX is not set -# CONFIG_SCSI_DPT_I2O is not set -# CONFIG_SCSI_ADVANSYS is not set -# CONFIG_SCSI_IN2000 is not set -# CONFIG_SCSI_AM53C974 is not set -# CONFIG_SCSI_MEGARAID is not set -# CONFIG_SCSI_BUSLOGIC is not set -# CONFIG_SCSI_CPQFCTS is not set -# CONFIG_SCSI_DMX3191D is not set -# CONFIG_SCSI_EATA is not set -# CONFIG_SCSI_EATA_PIO is not set -# CONFIG_SCSI_FUTURE_DOMAIN is not set -# CONFIG_SCSI_GDTH is not set -# CONFIG_SCSI_GENERIC_NCR5380 is not set -# CONFIG_SCSI_GENERIC_NCR5380_MMIO is not set -# CONFIG_SCSI_INITIO is not set -# CONFIG_SCSI_INIA100 is not set -# CONFIG_SCSI_NCR53C7xx is not set -CONFIG_SCSI_SYM53C8XX_2=y -CONFIG_SCSI_SYM53C8XX_DMA_ADDRESSING_MODE=0 -CONFIG_SCSI_SYM53C8XX_DEFAULT_TAGS=16 -CONFIG_SCSI_SYM53C8XX_MAX_TAGS=64 -# CONFIG_SCSI_SYM53C8XX_IOMAPPED is not set -# CONFIG_SCSI_PCI2000 is not set -# CONFIG_SCSI_PCI2220I is not set -# CONFIG_SCSI_QLOGIC_ISP is not set -# CONFIG_SCSI_QLOGIC_FC is not set -# CONFIG_SCSI_QLOGIC_1280 is not set -# CONFIG_SCSI_DC395x is not set -# CONFIG_SCSI_DC390T is not set -# CONFIG_SCSI_U14_34F is not set -# CONFIG_SCSI_NSP32 is not set -# CONFIG_SCSI_DEBUG is not set - -# -# Fusion MPT device support -# -# CONFIG_FUSION is not set - -# -# IEEE 1394 (FireWire) support (EXPERIMENTAL) -# -# CONFIG_IEEE1394 is not set - -# -# I2O device support -# -# CONFIG_I2O is not set - -# -# Networking support -# -CONFIG_NET=y - -# -# Networking options -# -CONFIG_PACKET=y -# CONFIG_PACKET_MMAP is not set -# CONFIG_NETLINK_DEV is not set -CONFIG_NETFILTER=y -# CONFIG_NETFILTER_DEBUG is not set -CONFIG_UNIX=y -# CONFIG_NET_KEY is not set -CONFIG_INET=y -# CONFIG_IP_MULTICAST is not set -# CONFIG_IP_ADVANCED_ROUTER is not set -# CONFIG_IP_PNP is not set -# CONFIG_NET_IPIP is not set -# CONFIG_NET_IPGRE is not set -# CONFIG_ARPD is not set -# CONFIG_INET_ECN is not set -# CONFIG_SYN_COOKIES is not set -# CONFIG_INET_AH is not set -# CONFIG_INET_ESP is not set -# CONFIG_INET_IPCOMP is not set - -# -# IP: Netfilter Configuration -# -# CONFIG_IP_NF_CONNTRACK is not set -# CONFIG_IP_NF_QUEUE is not set -# CONFIG_IP_NF_IPTABLES is not set -# CONFIG_IP_NF_ARPTABLES is not set -# CONFIG_IP_NF_COMPAT_IPCHAINS is not set -# CONFIG_IP_NF_COMPAT_IPFWADM is not set -# CONFIG_IPV6 is not set -# CONFIG_XFRM_USER is not set - -# -# SCTP Configuration (EXPERIMENTAL) -# -CONFIG_IPV6_SCTP__=y -# CONFIG_IP_SCTP is not set -# CONFIG_ATM is not set -# CONFIG_VLAN_8021Q is not set -# CONFIG_LLC is not set -# CONFIG_DECNET is not set -# CONFIG_BRIDGE is not set -# CONFIG_X25 is not set -# CONFIG_LAPB is not set -# CONFIG_NET_DIVERT is not set -# CONFIG_ECONET is not set -# CONFIG_WAN_ROUTER is not set -# CONFIG_NET_HW_FLOWCONTROL is not set - -# -# QoS and/or fair queueing -# -# CONFIG_NET_SCHED is not set - -# -# Network testing -# -# CONFIG_NET_PKTGEN is not set -CONFIG_NETDEVICES=y - -# -# ARCnet devices -# -# CONFIG_ARCNET is not set -# CONFIG_DUMMY is not set -# CONFIG_BONDING is not set -# CONFIG_EQUALIZER is not set -# CONFIG_TUN is not set -# CONFIG_ETHERTAP is not set - -# -# Ethernet (10 or 100Mbit) -# -CONFIG_NET_ETHERNET=y -# CONFIG_MII is not set -# CONFIG_OAKNET is not set -# CONFIG_HAPPYMEAL is not set -# CONFIG_SUNGEM is not set -# CONFIG_NET_VENDOR_3COM is not set - -# -# Tulip family network device support -# -# CONFIG_NET_TULIP is not set -# CONFIG_HP100 is not set -# CONFIG_NET_PCI is not set - -# -# Ethernet (1000 Mbit) -# -# CONFIG_ACENIC is not set -# CONFIG_DL2K is not set -# CONFIG_E1000 is not set -# CONFIG_NS83820 is not set -# CONFIG_HAMACHI is not set -# CONFIG_YELLOWFIN is not set -# CONFIG_R8169 is not set -# CONFIG_SK98LIN is not set -# CONFIG_TIGON3 is not set - -# -# Ethernet (10000 Mbit) -# -# CONFIG_IXGB is not set -# CONFIG_FDDI is not set -# CONFIG_HIPPI is not set -# CONFIG_PPP is not set -# CONFIG_SLIP is not set - -# -# Wireless LAN (non-hamradio) -# -# CONFIG_NET_RADIO is not set - -# -# Token Ring devices (depends on LLC=y) -# -# CONFIG_NET_FC is not set -# CONFIG_RCPCI is not set -# CONFIG_SHAPER is not set - -# -# Wan interfaces -# -# CONFIG_WAN is not set - -# -# Amateur Radio support -# -# CONFIG_HAMRADIO is not set - -# -# IrDA (infrared) support -# -# CONFIG_IRDA is not set - -# -# ISDN subsystem -# -# CONFIG_ISDN_BOOL is not set - -# -# Graphics support -# -# CONFIG_FB is not set - -# -# Old CD-ROM drivers (not SCSI, not IDE) -# -# CONFIG_CD_NO_IDESCSI is not set - -# -# Input device support -# -# CONFIG_INPUT is not set - -# -# Userland interfaces -# - -# -# Input I/O drivers -# -# CONFIG_GAMEPORT is not set -CONFIG_SOUND_GAMEPORT=y -# CONFIG_SERIO is not set - -# -# Input Device Drivers -# - -# -# Macintosh device drivers -# - -# -# Character devices -# -# CONFIG_SERIAL_NONSTANDARD is not set - -# -# Serial drivers -# -CONFIG_SERIAL_8250=y -CONFIG_SERIAL_8250_CONSOLE=y -# CONFIG_SERIAL_8250_EXTENDED is not set - -# -# Non-8250 serial port support -# -CONFIG_SERIAL_CORE=y -CONFIG_SERIAL_CORE_CONSOLE=y -CONFIG_UNIX98_PTYS=y -CONFIG_UNIX98_PTY_COUNT=256 - -# -# I2C support -# -# CONFIG_I2C is not set - -# -# I2C Hardware Sensors Mainboard support -# - -# -# I2C Hardware Sensors Chip support -# -# CONFIG_I2C_SENSOR is not set - -# -# Mice -# -# CONFIG_BUSMOUSE is not set -# CONFIG_QIC02_TAPE is not set - -# -# IPMI -# -# CONFIG_IPMI_HANDLER is not set - -# -# Watchdog Cards -# -# CONFIG_WATCHDOG is not set -# CONFIG_NVRAM is not set -CONFIG_GEN_RTC=y -# CONFIG_GEN_RTC_X is not set -# CONFIG_DTLK is not set -# CONFIG_R3964 is not set -# CONFIG_APPLICOM is not set - -# -# Ftape, the floppy tape device driver -# -# CONFIG_FTAPE is not set -# CONFIG_AGP is not set -# CONFIG_DRM is not set -# CONFIG_RAW_DRIVER is not set -# CONFIG_HANGCHECK_TIMER is not set - -# -# Multimedia devices -# -# CONFIG_VIDEO_DEV is not set - -# -# Digital Video Broadcasting Devices -# -# CONFIG_DVB is not set - -# -# File systems -# -CONFIG_EXT2_FS=y -# CONFIG_EXT2_FS_XATTR is not set -# CONFIG_EXT3_FS is not set -# CONFIG_JBD is not set -# CONFIG_REISERFS_FS is not set -# CONFIG_JFS_FS is not set -# CONFIG_XFS_FS is not set -# CONFIG_MINIX_FS is not set -# CONFIG_ROMFS_FS is not set -# CONFIG_QUOTA is not set -# CONFIG_AUTOFS_FS is not set -# CONFIG_AUTOFS4_FS is not set - -# -# CD-ROM/DVD Filesystems -# -CONFIG_ISO9660_FS=y -# CONFIG_JOLIET is not set -# CONFIG_ZISOFS is not set -# CONFIG_UDF_FS is not set - -# -# DOS/FAT/NT Filesystems -# -# CONFIG_FAT_FS is not set -# CONFIG_NTFS_FS is not set - -# -# Pseudo filesystems -# -CONFIG_PROC_FS=y -CONFIG_DEVFS_FS=y -# CONFIG_DEVFS_MOUNT is not set -# CONFIG_DEVFS_DEBUG is not set -CONFIG_DEVPTS_FS=y -# CONFIG_DEVPTS_FS_XATTR is not set -CONFIG_TMPFS=y -CONFIG_RAMFS=y - -# -# Miscellaneous filesystems -# -# CONFIG_ADFS_FS is not set -# CONFIG_AFFS_FS is not set -# CONFIG_HFS_FS is not set -# CONFIG_BEFS_FS is not set -# CONFIG_BFS_FS is not set -# CONFIG_EFS_FS is not set -# CONFIG_CRAMFS is not set -# CONFIG_VXFS_FS is not set -# CONFIG_HPFS_FS is not set -# CONFIG_QNX4FS_FS is not set -# CONFIG_SYSV_FS is not set -# CONFIG_UFS_FS is not set - -# -# Network File Systems -# -CONFIG_NFS_FS=y -# CONFIG_NFS_V3 is not set -# CONFIG_NFS_V4 is not set -CONFIG_NFSD=y -# CONFIG_NFSD_V3 is not set -# CONFIG_NFSD_TCP is not set -CONFIG_LOCKD=y -CONFIG_EXPORTFS=y -CONFIG_SUNRPC=y -# CONFIG_SUNRPC_GSS is not set -# CONFIG_SMB_FS is not set -# CONFIG_CIFS is not set -# CONFIG_NCP_FS is not set -# CONFIG_CODA_FS is not set -# CONFIG_INTERMEZZO_FS is not set -# CONFIG_AFS_FS is not set - -# -# Partition Types -# -CONFIG_PARTITION_ADVANCED=y -# CONFIG_ACORN_PARTITION is not set -# CONFIG_OSF_PARTITION is not set -# CONFIG_AMIGA_PARTITION is not set -# CONFIG_ATARI_PARTITION is not set -# CONFIG_MAC_PARTITION is not set -CONFIG_MSDOS_PARTITION=y -# CONFIG_BSD_DISKLABEL is not set -# CONFIG_MINIX_SUBPARTITION is not set -CONFIG_SOLARIS_X86_PARTITION=y -# CONFIG_UNIXWARE_DISKLABEL is not set -# CONFIG_LDM_PARTITION is not set -# CONFIG_NEC98_PARTITION is not set -# CONFIG_SGI_PARTITION is not set -# CONFIG_ULTRIX_PARTITION is not set -# CONFIG_SUN_PARTITION is not set -# CONFIG_EFI_PARTITION is not set - -# -# Sound -# -# CONFIG_SOUND is not set - -# -# USB support -# -# CONFIG_USB is not set -# CONFIG_USB_GADGET is not set - -# -# Bluetooth support -# -# CONFIG_BT is not set - -# -# Library routines -# -# CONFIG_CRC32 is not set - -# -# Kernel hacking -# -# CONFIG_DEBUG_KERNEL is not set -# CONFIG_KALLSYMS is not set - -# -# Security options -# -# CONFIG_SECURITY is not set - -# -# Cryptographic options -# -# CONFIG_CRYPTO is not set diff --git a/arch/ppc/configs/taishan_defconfig b/arch/ppc/configs/taishan_defconfig new file mode 100644 index 0000000..1ca0204 --- /dev/null +++ b/arch/ppc/configs/taishan_defconfig @@ -0,0 +1,1077 @@ +# +# Automatically generated make config: don't edit +# Linux kernel version: 2.6.20 +# Mon Feb 12 11:11:58 2007 +# +CONFIG_MMU=y +CONFIG_GENERIC_HARDIRQS=y +CONFIG_RWSEM_XCHGADD_ALGORITHM=y +CONFIG_ARCH_HAS_ILOG2_U32=y +# CONFIG_ARCH_HAS_ILOG2_U64 is not set +CONFIG_GENERIC_HWEIGHT=y +CONFIG_GENERIC_CALIBRATE_DELAY=y +CONFIG_PPC=y +CONFIG_PPC32=y +CONFIG_GENERIC_NVRAM=y +CONFIG_GENERIC_FIND_NEXT_BIT=y +CONFIG_SCHED_NO_NO_OMIT_FRAME_POINTER=y +CONFIG_ARCH_MAY_HAVE_PC_FDC=y +CONFIG_GENERIC_BUG=y +CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config" + +# +# Code maturity level options +# +CONFIG_EXPERIMENTAL=y +CONFIG_BROKEN_ON_SMP=y +CONFIG_INIT_ENV_ARG_LIMIT=32 + +# +# General setup +# +CONFIG_LOCALVERSION="" +CONFIG_LOCALVERSION_AUTO=y +CONFIG_SWAP=y +CONFIG_SYSVIPC=y +# CONFIG_IPC_NS is not set +# CONFIG_POSIX_MQUEUE is not set +# CONFIG_BSD_PROCESS_ACCT is not set +# CONFIG_TASKSTATS is not set +# CONFIG_UTS_NS is not set +# CONFIG_AUDIT is not set +# CONFIG_IKCONFIG is not set +CONFIG_SYSFS_DEPRECATED=y +# CONFIG_RELAY is not set +CONFIG_INITRAMFS_SOURCE="" +# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set +CONFIG_SYSCTL=y +CONFIG_EMBEDDED=y +CONFIG_SYSCTL_SYSCALL=y +CONFIG_KALLSYMS=y +# CONFIG_KALLSYMS_ALL is not set +# CONFIG_KALLSYMS_EXTRA_PASS is not set +# CONFIG_HOTPLUG is not set +CONFIG_PRINTK=y +CONFIG_BUG=y +CONFIG_ELF_CORE=y +CONFIG_BASE_FULL=y +CONFIG_FUTEX=y +CONFIG_EPOLL=y +CONFIG_SHMEM=y +CONFIG_SLAB=y +CONFIG_VM_EVENT_COUNTERS=y +CONFIG_RT_MUTEXES=y +# CONFIG_TINY_SHMEM is not set +CONFIG_BASE_SMALL=0 +# CONFIG_SLOB is not set + +# +# Loadable module support +# +CONFIG_MODULES=y +CONFIG_MODULE_UNLOAD=y +# CONFIG_MODULE_FORCE_UNLOAD is not set +# CONFIG_MODVERSIONS is not set +# CONFIG_MODULE_SRCVERSION_ALL is not set +CONFIG_KMOD=y + +# +# Block layer +# +CONFIG_BLOCK=y +# CONFIG_LBD is not set +# CONFIG_BLK_DEV_IO_TRACE is not set +# CONFIG_LSF is not set + +# +# IO Schedulers +# +CONFIG_IOSCHED_NOOP=y +CONFIG_IOSCHED_AS=y +CONFIG_IOSCHED_DEADLINE=y +CONFIG_IOSCHED_CFQ=y +CONFIG_DEFAULT_AS=y +# CONFIG_DEFAULT_DEADLINE is not set +# CONFIG_DEFAULT_CFQ is not set +# CONFIG_DEFAULT_NOOP is not set +CONFIG_DEFAULT_IOSCHED="anticipatory" + +# +# Processor +# +# CONFIG_6xx is not set +# CONFIG_40x is not set +CONFIG_44x=y +# CONFIG_8xx is not set +# CONFIG_E200 is not set +# CONFIG_E500 is not set +CONFIG_PPC_DCR_NATIVE=y +CONFIG_PPC_DCR=y +CONFIG_BOOKE=y +CONFIG_PTE_64BIT=y +CONFIG_PHYS_64BIT=y +# CONFIG_MATH_EMULATION is not set +# CONFIG_KEXEC is not set +# CONFIG_CPU_FREQ is not set +CONFIG_4xx=y +CONFIG_WANT_EARLY_SERIAL=y + +# +# IBM 4xx options +# +# CONFIG_BAMBOO is not set +# CONFIG_EBONY is not set +# CONFIG_LUAN is not set +# CONFIG_YUCCA is not set +# CONFIG_OCOTEA is not set +CONFIG_TAISHAN=y +CONFIG_440GX=y +CONFIG_440A=y +CONFIG_IBM_OCP=y +CONFIG_IBM_EMAC4=y +CONFIG_PPC4xx_DMA=y +CONFIG_PPC4xx_EDMA=y +CONFIG_PPC_GEN550=y +CONFIG_NOT_COHERENT_CACHE=y + +# +# Platform options +# +# CONFIG_PC_KEYBOARD is not set +# CONFIG_HIGHMEM is not set +CONFIG_ARCH_POPULATES_NODE_MAP=y +# CONFIG_HZ_100 is not set +CONFIG_HZ_250=y +# CONFIG_HZ_300 is not set +# CONFIG_HZ_1000 is not set +CONFIG_HZ=250 +CONFIG_PREEMPT_NONE=y +# CONFIG_PREEMPT_VOLUNTARY is not set +# CONFIG_PREEMPT is not set +CONFIG_SELECT_MEMORY_MODEL=y +CONFIG_FLATMEM_MANUAL=y +# CONFIG_DISCONTIGMEM_MANUAL is not set +# CONFIG_SPARSEMEM_MANUAL is not set +CONFIG_FLATMEM=y +CONFIG_FLAT_NODE_MEM_MAP=y +# CONFIG_SPARSEMEM_STATIC is not set +CONFIG_SPLIT_PTLOCK_CPUS=4 +CONFIG_RESOURCES_64BIT=y +CONFIG_ZONE_DMA_FLAG=1 +CONFIG_BINFMT_ELF=y +# CONFIG_BINFMT_MISC is not set +CONFIG_CMDLINE_BOOL=y +CONFIG_CMDLINE="ip=on console=ttyS0,115200" +CONFIG_SECCOMP=y +CONFIG_ISA_DMA_API=y + +# +# Bus options +# +CONFIG_ZONE_DMA=y +# CONFIG_PPC_I8259 is not set +CONFIG_PPC_INDIRECT_PCI=y +CONFIG_PCI=y +CONFIG_PCI_DOMAINS=y +# CONFIG_PCI_DEBUG is not set + +# +# PCCARD (PCMCIA/CardBus) support +# + +# +# Advanced setup +# +# CONFIG_ADVANCED_OPTIONS is not set + +# +# Default settings for advanced configuration options are used +# +CONFIG_HIGHMEM_START=0xfe000000 +CONFIG_LOWMEM_SIZE=0x30000000 +CONFIG_KERNEL_START=0xc0000000 +CONFIG_TASK_SIZE=0x80000000 +CONFIG_CONSISTENT_START=0xff100000 +CONFIG_CONSISTENT_SIZE=0x00200000 +CONFIG_BOOT_LOAD=0x01000000 + +# +# Networking +# +CONFIG_NET=y + +# +# Networking options +# +# CONFIG_NETDEBUG is not set +CONFIG_PACKET=y +# CONFIG_PACKET_MMAP is not set +CONFIG_UNIX=y +CONFIG_XFRM=y +# CONFIG_XFRM_USER is not set +# CONFIG_XFRM_SUB_POLICY is not set +# CONFIG_XFRM_MIGRATE is not set +# CONFIG_NET_KEY is not set +CONFIG_INET=y +# CONFIG_IP_MULTICAST is not set +CONFIG_IP_ADVANCED_ROUTER=y +CONFIG_ASK_IP_FIB_HASH=y +# CONFIG_IP_FIB_TRIE is not set +CONFIG_IP_FIB_HASH=y +# CONFIG_IP_MULTIPLE_TABLES is not set +# CONFIG_IP_ROUTE_MULTIPATH is not set +# CONFIG_IP_ROUTE_VERBOSE is not set +CONFIG_IP_PNP=y +# CONFIG_IP_PNP_DHCP is not set +CONFIG_IP_PNP_BOOTP=y +# CONFIG_IP_PNP_RARP is not set +# CONFIG_NET_IPIP is not set +# CONFIG_NET_IPGRE is not set +# CONFIG_ARPD is not set +# CONFIG_SYN_COOKIES is not set +# CONFIG_INET_AH is not set +# CONFIG_INET_ESP is not set +# CONFIG_INET_IPCOMP is not set +# CONFIG_INET_XFRM_TUNNEL is not set +# CONFIG_INET_TUNNEL is not set +CONFIG_INET_XFRM_MODE_TRANSPORT=y +CONFIG_INET_XFRM_MODE_TUNNEL=y +CONFIG_INET_XFRM_MODE_BEET=y +CONFIG_INET_DIAG=y +CONFIG_INET_TCP_DIAG=y +# CONFIG_TCP_CONG_ADVANCED is not set +CONFIG_TCP_CONG_CUBIC=y +CONFIG_DEFAULT_TCP_CONG="cubic" +# CONFIG_TCP_MD5SIG is not set +# CONFIG_IPV6 is not set +# CONFIG_INET6_XFRM_TUNNEL is not set +# CONFIG_INET6_TUNNEL is not set +# CONFIG_NETWORK_SECMARK is not set +# CONFIG_NETFILTER is not set + +# +# DCCP Configuration (EXPERIMENTAL) +# +# CONFIG_IP_DCCP is not set + +# +# SCTP Configuration (EXPERIMENTAL) +# +# CONFIG_IP_SCTP is not set + +# +# TIPC Configuration (EXPERIMENTAL) +# +# CONFIG_TIPC is not set +# CONFIG_ATM is not set +CONFIG_BRIDGE=y +# CONFIG_VLAN_8021Q is not set +# CONFIG_DECNET is not set +CONFIG_LLC=y +# CONFIG_LLC2 is not set +# CONFIG_IPX is not set +# CONFIG_ATALK is not set +# CONFIG_X25 is not set +# CONFIG_LAPB is not set +# CONFIG_ECONET is not set +# CONFIG_WAN_ROUTER is not set + +# +# QoS and/or fair queueing +# +# CONFIG_NET_SCHED is not set + +# +# Network testing +# +# CONFIG_NET_PKTGEN is not set +# CONFIG_HAMRADIO is not set +# CONFIG_IRDA is not set +# CONFIG_BT is not set +# CONFIG_IEEE80211 is not set + +# +# Device Drivers +# + +# +# Generic Driver Options +# +# CONFIG_STANDALONE is not set +CONFIG_PREVENT_FIRMWARE_BUILD=y +# CONFIG_DEBUG_DRIVER is not set +# CONFIG_DEBUG_DEVRES is not set +# CONFIG_SYS_HYPERVISOR is not set + +# +# Connector - unified userspace <-> kernelspace linker +# +# CONFIG_CONNECTOR is not set + +# +# Memory Technology Devices (MTD) +# +CONFIG_MTD=y +# CONFIG_MTD_DEBUG is not set +CONFIG_MTD_CONCAT=y +CONFIG_MTD_PARTITIONS=y +# CONFIG_MTD_REDBOOT_PARTS is not set +CONFIG_MTD_CMDLINE_PARTS=y + +# +# User Modules And Translation Layers +# +CONFIG_MTD_CHAR=y +CONFIG_MTD_BLKDEVS=y +CONFIG_MTD_BLOCK=y +# CONFIG_FTL is not set +# CONFIG_NFTL is not set +# CONFIG_INFTL is not set +# CONFIG_RFD_FTL is not set +# CONFIG_SSFDC is not set + +# +# RAM/ROM/Flash chip drivers +# +CONFIG_MTD_CFI=y +CONFIG_MTD_JEDECPROBE=y +CONFIG_MTD_GEN_PROBE=y +CONFIG_MTD_CFI_ADV_OPTIONS=y +CONFIG_MTD_CFI_NOSWAP=y +# CONFIG_MTD_CFI_BE_BYTE_SWAP is not set +# CONFIG_MTD_CFI_LE_BYTE_SWAP is not set +# CONFIG_MTD_CFI_GEOMETRY is not set +CONFIG_MTD_MAP_BANK_WIDTH_1=y +CONFIG_MTD_MAP_BANK_WIDTH_2=y +CONFIG_MTD_MAP_BANK_WIDTH_4=y +# CONFIG_MTD_MAP_BANK_WIDTH_8 is not set +# CONFIG_MTD_MAP_BANK_WIDTH_16 is not set +# CONFIG_MTD_MAP_BANK_WIDTH_32 is not set +CONFIG_MTD_CFI_I1=y +CONFIG_MTD_CFI_I2=y +# CONFIG_MTD_CFI_I4 is not set +# CONFIG_MTD_CFI_I8 is not set +# CONFIG_MTD_OTP is not set +# CONFIG_MTD_CFI_INTELEXT is not set +CONFIG_MTD_CFI_AMDSTD=y +# CONFIG_MTD_CFI_STAA is not set +CONFIG_MTD_CFI_UTIL=y +# CONFIG_MTD_RAM is not set +# CONFIG_MTD_ROM is not set +# CONFIG_MTD_ABSENT is not set +# CONFIG_MTD_OBSOLETE_CHIPS is not set + +# +# Mapping drivers for chip access +# +CONFIG_MTD_COMPLEX_MAPPINGS=y +CONFIG_MTD_PHYSMAP=y +CONFIG_MTD_PHYSMAP_START=0x8000000 +CONFIG_MTD_PHYSMAP_LEN=0x0 +CONFIG_MTD_PHYSMAP_BANKWIDTH=2 +# CONFIG_MTD_PCI is not set +# CONFIG_MTD_PLATRAM is not set + +# +# Self-contained MTD device drivers +# +# CONFIG_MTD_PMC551 is not set +# CONFIG_MTD_SLRAM is not set +# CONFIG_MTD_PHRAM is not set +# CONFIG_MTD_MTDRAM is not set +# CONFIG_MTD_BLOCK2MTD is not set + +# +# Disk-On-Chip Device Drivers +# +# CONFIG_MTD_DOC2000 is not set +# CONFIG_MTD_DOC2001 is not set +# CONFIG_MTD_DOC2001PLUS is not set + +# +# NAND Flash Device Drivers +# +# CONFIG_MTD_NAND is not set +# CONFIG_MTD_NAND_CAFE is not set + +# +# OneNAND Flash Device Drivers +# +# CONFIG_MTD_ONENAND is not set + +# +# Parallel port support +# +# CONFIG_PARPORT is not set + +# +# Plug and Play support +# + +# +# Block devices +# +# CONFIG_BLK_DEV_FD is not set +# CONFIG_BLK_CPQ_DA is not set +# CONFIG_BLK_CPQ_CISS_DA is not set +# CONFIG_BLK_DEV_DAC960 is not set +# CONFIG_BLK_DEV_UMEM is not set +# CONFIG_BLK_DEV_COW_COMMON is not set +# CONFIG_BLK_DEV_LOOP is not set +# CONFIG_BLK_DEV_NBD is not set +# CONFIG_BLK_DEV_SX8 is not set +CONFIG_BLK_DEV_RAM=y +CONFIG_BLK_DEV_RAM_COUNT=16 +CONFIG_BLK_DEV_RAM_SIZE=65536 +CONFIG_BLK_DEV_RAM_BLOCKSIZE=1024 +CONFIG_BLK_DEV_INITRD=y +# CONFIG_CDROM_PKTCDVD is not set +# CONFIG_ATA_OVER_ETH is not set + +# +# Misc devices +# +# CONFIG_SGI_IOC4 is not set +# CONFIG_TIFM_CORE is not set + +# +# ATA/ATAPI/MFM/RLL support +# +# CONFIG_IDE is not set + +# +# SCSI device support +# +# CONFIG_RAID_ATTRS is not set +# CONFIG_SCSI is not set +# CONFIG_SCSI_NETLINK is not set + +# +# Serial ATA (prod) and Parallel ATA (experimental) drivers +# +# CONFIG_ATA is not set + +# +# Multi-device support (RAID and LVM) +# +# CONFIG_MD is not set + +# +# Fusion MPT device support +# +# CONFIG_FUSION is not set + +# +# IEEE 1394 (FireWire) support +# +# CONFIG_IEEE1394 is not set + +# +# I2O device support +# +# CONFIG_I2O is not set + +# +# Macintosh device drivers +# +# CONFIG_MAC_EMUMOUSEBTN is not set +# CONFIG_WINDFARM is not set + +# +# Network device support +# +CONFIG_NETDEVICES=y +# CONFIG_DUMMY is not set +# CONFIG_BONDING is not set +# CONFIG_EQUALIZER is not set +# CONFIG_TUN is not set + +# +# ARCnet devices +# +# CONFIG_ARCNET is not set + +# +# PHY device support +# +# CONFIG_PHYLIB is not set + +# +# Ethernet (10 or 100Mbit) +# +CONFIG_NET_ETHERNET=y +CONFIG_MII=y +# CONFIG_HAPPYMEAL is not set +# CONFIG_SUNGEM is not set +# CONFIG_CASSINI is not set +# CONFIG_NET_VENDOR_3COM is not set + +# +# Tulip family network device support +# +# CONFIG_NET_TULIP is not set +# CONFIG_HP100 is not set +CONFIG_IBM_EMAC=y +CONFIG_IBM_EMAC_RXB=128 +CONFIG_IBM_EMAC_TXB=128 +CONFIG_IBM_EMAC_POLL_WEIGHT=32 +CONFIG_IBM_EMAC_RX_COPY_THRESHOLD=256 +CONFIG_IBM_EMAC_RX_SKB_HEADROOM=0 +CONFIG_IBM_EMAC_PHY_RX_CLK_FIX=y +# CONFIG_IBM_EMAC_DEBUG is not set +CONFIG_IBM_EMAC_ZMII=y +CONFIG_IBM_EMAC_RGMII=y +CONFIG_IBM_EMAC_TAH=y +CONFIG_NET_PCI=y +# CONFIG_PCNET32 is not set +# CONFIG_AMD8111_ETH is not set +# CONFIG_ADAPTEC_STARFIRE is not set +# CONFIG_B44 is not set +# CONFIG_FORCEDETH is not set +# CONFIG_DGRS is not set +# CONFIG_EEPRO100 is not set +CONFIG_E100=y +# CONFIG_FEALNX is not set +# CONFIG_NATSEMI is not set +# CONFIG_NE2K_PCI is not set +# CONFIG_8139CP is not set +# CONFIG_8139TOO is not set +# CONFIG_SIS900 is not set +# CONFIG_EPIC100 is not set +# CONFIG_SUNDANCE is not set +# CONFIG_TLAN is not set +# CONFIG_VIA_RHINE is not set +# CONFIG_SC92031 is not set + +# +# Ethernet (1000 Mbit) +# +# CONFIG_ACENIC is not set +# CONFIG_DL2K is not set +# CONFIG_E1000 is not set +# CONFIG_NS83820 is not set +# CONFIG_HAMACHI is not set +# CONFIG_YELLOWFIN is not set +# CONFIG_R8169 is not set +# CONFIG_SIS190 is not set +# CONFIG_SKGE is not set +# CONFIG_SKY2 is not set +# CONFIG_SK98LIN is not set +# CONFIG_VIA_VELOCITY is not set +# CONFIG_TIGON3 is not set +# CONFIG_BNX2 is not set +# CONFIG_QLA3XXX is not set +# CONFIG_ATL1 is not set + +# +# Ethernet (10000 Mbit) +# +# CONFIG_CHELSIO_T1 is not set +# CONFIG_CHELSIO_T3 is not set +# CONFIG_IXGB is not set +# CONFIG_S2IO is not set +# CONFIG_MYRI10GE is not set +# CONFIG_NETXEN_NIC is not set + +# +# Token Ring devices +# +# CONFIG_TR is not set + +# +# Wireless LAN (non-hamradio) +# +# CONFIG_NET_RADIO is not set + +# +# Wan interfaces +# +# CONFIG_WAN is not set +# CONFIG_FDDI is not set +# CONFIG_HIPPI is not set +CONFIG_PPP=y +# CONFIG_PPP_MULTILINK is not set +# CONFIG_PPP_FILTER is not set +# CONFIG_PPP_ASYNC is not set +# CONFIG_PPP_SYNC_TTY is not set +# CONFIG_PPP_DEFLATE is not set +# CONFIG_PPP_BSDCOMP is not set +# CONFIG_PPP_MPPE is not set +CONFIG_PPPOE=y +# CONFIG_SLIP is not set +CONFIG_SLHC=y +# CONFIG_SHAPER is not set +# CONFIG_NETCONSOLE is not set +# CONFIG_NETPOLL is not set +# CONFIG_NET_POLL_CONTROLLER is not set + +# +# ISDN subsystem +# +# CONFIG_ISDN is not set + +# +# Telephony Support +# +# CONFIG_PHONE is not set + +# +# Input device support +# +# CONFIG_INPUT is not set + +# +# Hardware I/O ports +# +CONFIG_SERIO=y +# CONFIG_SERIO_I8042 is not set +# CONFIG_SERIO_SERPORT is not set +# CONFIG_SERIO_PCIPS2 is not set +# CONFIG_SERIO_LIBPS2 is not set +# CONFIG_SERIO_RAW is not set +# CONFIG_GAMEPORT is not set + +# +# Character devices +# +# CONFIG_VT is not set +# CONFIG_SERIAL_NONSTANDARD is not set + +# +# Serial drivers +# +CONFIG_SERIAL_8250=y +CONFIG_SERIAL_8250_CONSOLE=y +CONFIG_SERIAL_8250_PCI=y +CONFIG_SERIAL_8250_NR_UARTS=4 +CONFIG_SERIAL_8250_RUNTIME_UARTS=4 +CONFIG_SERIAL_8250_EXTENDED=y +# CONFIG_SERIAL_8250_MANY_PORTS is not set +CONFIG_SERIAL_8250_SHARE_IRQ=y +# CONFIG_SERIAL_8250_DETECT_IRQ is not set +# CONFIG_SERIAL_8250_RSA is not set + +# +# Non-8250 serial port support +# +# CONFIG_SERIAL_UARTLITE is not set +CONFIG_SERIAL_CORE=y +CONFIG_SERIAL_CORE_CONSOLE=y +# CONFIG_SERIAL_JSM is not set +CONFIG_UNIX98_PTYS=y +CONFIG_LEGACY_PTYS=y +CONFIG_LEGACY_PTY_COUNT=256 + +# +# IPMI +# +# CONFIG_IPMI_HANDLER is not set + +# +# Watchdog Cards +# +# CONFIG_WATCHDOG is not set +CONFIG_HW_RANDOM=m +# CONFIG_NVRAM is not set +# CONFIG_GEN_RTC is not set +# CONFIG_DTLK is not set +# CONFIG_R3964 is not set +# CONFIG_APPLICOM is not set +# CONFIG_AGP is not set +# CONFIG_DRM is not set +# CONFIG_RAW_DRIVER is not set + +# +# TPM devices +# +# CONFIG_TCG_TPM is not set + +# +# I2C support +# +CONFIG_I2C=y +CONFIG_I2C_CHARDEV=y + +# +# I2C Algorithms +# +# CONFIG_I2C_ALGOBIT is not set +# CONFIG_I2C_ALGOPCF is not set +# CONFIG_I2C_ALGOPCA is not set + +# +# I2C Hardware Bus support +# +# CONFIG_I2C_ALI1535 is not set +# CONFIG_I2C_ALI1563 is not set +# CONFIG_I2C_ALI15X3 is not set +# CONFIG_I2C_AMD756 is not set +# CONFIG_I2C_AMD8111 is not set +# CONFIG_I2C_I801 is not set +# CONFIG_I2C_I810 is not set +# CONFIG_I2C_PIIX4 is not set +CONFIG_I2C_IBM_IIC=y +# CONFIG_I2C_MPC is not set +# CONFIG_I2C_NFORCE2 is not set +# CONFIG_I2C_OCORES is not set +# CONFIG_I2C_PARPORT_LIGHT is not set +# CONFIG_I2C_PROSAVAGE is not set +# CONFIG_I2C_SAVAGE4 is not set +# CONFIG_I2C_SIS5595 is not set +# CONFIG_I2C_SIS630 is not set +# CONFIG_I2C_SIS96X is not set +# CONFIG_I2C_STUB is not set +# CONFIG_I2C_VIA is not set +# CONFIG_I2C_VIAPRO is not set +# CONFIG_I2C_VOODOO3 is not set +# CONFIG_I2C_PCA_ISA is not set + +# +# Miscellaneous I2C Chip support +# +# CONFIG_SENSORS_DS1337 is not set +# CONFIG_SENSORS_DS1374 is not set +CONFIG_SENSORS_EEPROM=y +# CONFIG_SENSORS_PCF8574 is not set +# CONFIG_SENSORS_PCA9539 is not set +# CONFIG_SENSORS_PCF8591 is not set +# CONFIG_SENSORS_M41T00 is not set +# CONFIG_SENSORS_MAX6875 is not set +# CONFIG_I2C_DEBUG_CORE is not set +# CONFIG_I2C_DEBUG_ALGO is not set +# CONFIG_I2C_DEBUG_BUS is not set +# CONFIG_I2C_DEBUG_CHIP is not set + +# +# SPI support +# +# CONFIG_SPI is not set +# CONFIG_SPI_MASTER is not set + +# +# Dallas's 1-wire bus +# +# CONFIG_W1 is not set + +# +# Hardware Monitoring support +# +CONFIG_HWMON=y +# CONFIG_HWMON_VID is not set +# CONFIG_SENSORS_ABITUGURU is not set +# CONFIG_SENSORS_ADM1021 is not set +# CONFIG_SENSORS_ADM1025 is not set +# CONFIG_SENSORS_ADM1026 is not set +# CONFIG_SENSORS_ADM1031 is not set +# CONFIG_SENSORS_ADM9240 is not set +# CONFIG_SENSORS_ASB100 is not set +# CONFIG_SENSORS_ATXP1 is not set +# CONFIG_SENSORS_DS1621 is not set +# CONFIG_SENSORS_F71805F is not set +# CONFIG_SENSORS_FSCHER is not set +# CONFIG_SENSORS_FSCPOS is not set +# CONFIG_SENSORS_GL518SM is not set +# CONFIG_SENSORS_GL520SM is not set +# CONFIG_SENSORS_IT87 is not set +# CONFIG_SENSORS_LM63 is not set +# CONFIG_SENSORS_LM75 is not set +# CONFIG_SENSORS_LM77 is not set +# CONFIG_SENSORS_LM78 is not set +# CONFIG_SENSORS_LM80 is not set +# CONFIG_SENSORS_LM83 is not set +# CONFIG_SENSORS_LM85 is not set +# CONFIG_SENSORS_LM87 is not set +# CONFIG_SENSORS_LM90 is not set +# CONFIG_SENSORS_LM92 is not set +# CONFIG_SENSORS_MAX1619 is not set +# CONFIG_SENSORS_PC87360 is not set +# CONFIG_SENSORS_PC87427 is not set +# CONFIG_SENSORS_SIS5595 is not set +# CONFIG_SENSORS_SMSC47M1 is not set +# CONFIG_SENSORS_SMSC47M192 is not set +# CONFIG_SENSORS_SMSC47B397 is not set +# CONFIG_SENSORS_VIA686A is not set +# CONFIG_SENSORS_VT1211 is not set +# CONFIG_SENSORS_VT8231 is not set +# CONFIG_SENSORS_W83781D is not set +# CONFIG_SENSORS_W83791D is not set +# CONFIG_SENSORS_W83792D is not set +# CONFIG_SENSORS_W83793 is not set +# CONFIG_SENSORS_W83L785TS is not set +# CONFIG_SENSORS_W83627HF is not set +# CONFIG_SENSORS_W83627EHF is not set +# CONFIG_HWMON_DEBUG_CHIP is not set + +# +# Multimedia devices +# +# CONFIG_VIDEO_DEV is not set + +# +# Digital Video Broadcasting Devices +# +# CONFIG_DVB is not set + +# +# Graphics support +# +CONFIG_FIRMWARE_EDID=y +# CONFIG_FB is not set +# CONFIG_FB_IBM_GXT4500 is not set +# CONFIG_BACKLIGHT_LCD_SUPPORT is not set + +# +# Sound +# +# CONFIG_SOUND is not set + +# +# USB support +# +CONFIG_USB_ARCH_HAS_HCD=y +CONFIG_USB_ARCH_HAS_OHCI=y +CONFIG_USB_ARCH_HAS_EHCI=y +# CONFIG_USB is not set + +# +# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support' +# + +# +# USB Gadget Support +# +# CONFIG_USB_GADGET is not set + +# +# MMC/SD Card support +# +# CONFIG_MMC is not set + +# +# LED devices +# +# CONFIG_NEW_LEDS is not set + +# +# LED drivers +# + +# +# LED Triggers +# + +# +# InfiniBand support +# +# CONFIG_INFINIBAND is not set + +# +# EDAC - error detection and reporting (RAS) (EXPERIMENTAL) +# + +# +# Real Time Clock +# +# CONFIG_RTC_CLASS is not set + +# +# DMA Engine support +# +# CONFIG_DMA_ENGINE is not set + +# +# DMA Clients +# + +# +# DMA Devices +# + +# +# Auxiliary Display support +# + +# +# Virtualization +# + +# +# File systems +# +CONFIG_EXT2_FS=y +CONFIG_EXT2_FS_XATTR=y +CONFIG_EXT2_FS_POSIX_ACL=y +CONFIG_EXT2_FS_SECURITY=y +CONFIG_EXT2_FS_XIP=y +CONFIG_FS_XIP=y +CONFIG_EXT3_FS=y +CONFIG_EXT3_FS_XATTR=y +CONFIG_EXT3_FS_POSIX_ACL=y +CONFIG_EXT3_FS_SECURITY=y +# CONFIG_EXT4DEV_FS is not set +CONFIG_JBD=y +CONFIG_JBD_DEBUG=y +CONFIG_FS_MBCACHE=y +# CONFIG_REISERFS_FS is not set +# CONFIG_JFS_FS is not set +CONFIG_FS_POSIX_ACL=y +# CONFIG_XFS_FS is not set +# CONFIG_GFS2_FS is not set +# CONFIG_OCFS2_FS is not set +# CONFIG_MINIX_FS is not set +# CONFIG_ROMFS_FS is not set +CONFIG_INOTIFY=y +CONFIG_INOTIFY_USER=y +# CONFIG_QUOTA is not set +CONFIG_DNOTIFY=y +# CONFIG_AUTOFS_FS is not set +# CONFIG_AUTOFS4_FS is not set +# CONFIG_FUSE_FS is not set + +# +# CD-ROM/DVD Filesystems +# +# CONFIG_ISO9660_FS is not set +# CONFIG_UDF_FS is not set + +# +# DOS/FAT/NT Filesystems +# +# CONFIG_MSDOS_FS is not set +# CONFIG_VFAT_FS is not set +# CONFIG_NTFS_FS is not set + +# +# Pseudo filesystems +# +CONFIG_PROC_FS=y +CONFIG_PROC_KCORE=y +CONFIG_PROC_SYSCTL=y +CONFIG_SYSFS=y +CONFIG_TMPFS=y +# CONFIG_TMPFS_POSIX_ACL is not set +# CONFIG_HUGETLB_PAGE is not set +CONFIG_RAMFS=y +# CONFIG_CONFIGFS_FS is not set + +# +# Miscellaneous filesystems +# +# CONFIG_ADFS_FS is not set +# CONFIG_AFFS_FS is not set +# CONFIG_HFS_FS is not set +# CONFIG_HFSPLUS_FS is not set +# CONFIG_BEFS_FS is not set +# CONFIG_BFS_FS is not set +# CONFIG_EFS_FS is not set +CONFIG_JFFS2_FS=y +CONFIG_JFFS2_FS_DEBUG=0 +CONFIG_JFFS2_FS_WRITEBUFFER=y +CONFIG_JFFS2_SUMMARY=y +# CONFIG_JFFS2_FS_XATTR is not set +# CONFIG_JFFS2_COMPRESSION_OPTIONS is not set +CONFIG_JFFS2_ZLIB=y +CONFIG_JFFS2_RTIME=y +# CONFIG_JFFS2_RUBIN is not set +# CONFIG_CRAMFS is not set +# CONFIG_VXFS_FS is not set +# CONFIG_HPFS_FS is not set +# CONFIG_QNX4FS_FS is not set +# CONFIG_SYSV_FS is not set +# CONFIG_UFS_FS is not set + +# +# Network File Systems +# +CONFIG_NFS_FS=y +# CONFIG_NFS_V3 is not set +# CONFIG_NFS_V4 is not set +# CONFIG_NFS_DIRECTIO is not set +# CONFIG_NFSD is not set +CONFIG_ROOT_NFS=y +CONFIG_LOCKD=y +CONFIG_NFS_COMMON=y +CONFIG_SUNRPC=y +# CONFIG_RPCSEC_GSS_KRB5 is not set +# CONFIG_RPCSEC_GSS_SPKM3 is not set +# CONFIG_SMB_FS is not set +# CONFIG_CIFS is not set +# CONFIG_NCP_FS is not set +# CONFIG_CODA_FS is not set +# CONFIG_AFS_FS is not set +# CONFIG_9P_FS is not set + +# +# Partition Types +# +# CONFIG_PARTITION_ADVANCED is not set +CONFIG_MSDOS_PARTITION=y + +# +# Native Language Support +# +# CONFIG_NLS is not set + +# +# Distributed Lock Manager +# +# CONFIG_DLM is not set + +# +# Library routines +# +CONFIG_BITREVERSE=y +# CONFIG_CRC_CCITT is not set +# CONFIG_CRC16 is not set +CONFIG_CRC32=y +# CONFIG_LIBCRC32C is not set +CONFIG_ZLIB_INFLATE=y +CONFIG_ZLIB_DEFLATE=y +CONFIG_PLIST=y +CONFIG_HAS_IOMEM=y +CONFIG_HAS_IOPORT=y +# CONFIG_PROFILING is not set + +# +# Kernel hacking +# +# CONFIG_PRINTK_TIME is not set +CONFIG_ENABLE_MUST_CHECK=y +# CONFIG_MAGIC_SYSRQ is not set +# CONFIG_UNUSED_SYMBOLS is not set +CONFIG_DEBUG_FS=y +# CONFIG_HEADERS_CHECK is not set +CONFIG_DEBUG_KERNEL=y +CONFIG_LOG_BUF_SHIFT=14 +CONFIG_DETECT_SOFTLOCKUP=y +# CONFIG_SCHEDSTATS is not set +# CONFIG_DEBUG_SLAB is not set +# CONFIG_DEBUG_RT_MUTEXES is not set +# CONFIG_RT_MUTEX_TESTER is not set +# CONFIG_DEBUG_SPINLOCK is not set +CONFIG_DEBUG_MUTEXES=y +# CONFIG_DEBUG_SPINLOCK_SLEEP is not set +# CONFIG_DEBUG_LOCKING_API_SELFTESTS is not set +# CONFIG_DEBUG_KOBJECT is not set +# CONFIG_DEBUG_BUGVERBOSE is not set +CONFIG_DEBUG_INFO=y +# CONFIG_DEBUG_VM is not set +# CONFIG_DEBUG_LIST is not set +CONFIG_FORCED_INLINING=y +# CONFIG_RCU_TORTURE_TEST is not set +# CONFIG_KGDB is not set +# CONFIG_XMON is not set +CONFIG_BDI_SWITCH=y +# CONFIG_SERIAL_TEXT_DEBUG is not set +CONFIG_PPC_OCP=y + +# +# Security options +# +# CONFIG_KEYS is not set +# CONFIG_SECURITY is not set + +# +# Cryptographic options +# +# CONFIG_CRYPTO is not set diff --git a/arch/ppc/kernel/Makefile b/arch/ppc/kernel/Makefile index 466437f..6b4f022 100644 --- a/arch/ppc/kernel/Makefile +++ b/arch/ppc/kernel/Makefile @@ -12,7 +12,6 @@ obj-y := entry.o traps.o time.o misc. setup.o \ ppc_htab.o obj-$(CONFIG_MODULES) += ppc_ksyms.o -obj-$(CONFIG_NOT_COHERENT_CACHE) += dma-mapping.o obj-$(CONFIG_PCI) += pci.o obj-$(CONFIG_RAPIDIO) += rio.o obj-$(CONFIG_KGDB) += ppc-stub.o diff --git a/arch/ppc/kernel/dma-mapping.c b/arch/ppc/kernel/dma-mapping.c deleted file mode 100644 index 10fec73..0000000 --- a/arch/ppc/kernel/dma-mapping.c +++ /dev/null @@ -1,442 +0,0 @@ -/* - * PowerPC version derived from arch/arm/mm/consistent.c - * Copyright (C) 2001 Dan Malek (dmalek@jlc.net) - * - * Copyright (C) 2000 Russell King - * - * Consistent memory allocators. Used for DMA devices that want to - * share uncached memory with the processor core. The function return - * is the virtual address and 'dma_handle' is the physical address. - * Mostly stolen from the ARM port, with some changes for PowerPC. - * -- Dan - * - * Reorganized to get rid of the arch-specific consistent_* functions - * and provide non-coherent implementations for the DMA API. -Matt - * - * Added in_interrupt() safe dma_alloc_coherent()/dma_free_coherent() - * implementation. This is pulled straight from ARM and barely - * modified. -Matt - * - * 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 - -int map_page(unsigned long va, phys_addr_t pa, int flags); - -#include - -/* - * This address range defaults to a value that is safe for all - * platforms which currently set CONFIG_NOT_COHERENT_CACHE. It - * can be further configured for specific applications under - * the "Advanced Setup" menu. -Matt - */ -#define CONSISTENT_BASE (CONFIG_CONSISTENT_START) -#define CONSISTENT_END (CONFIG_CONSISTENT_START + CONFIG_CONSISTENT_SIZE) -#define CONSISTENT_OFFSET(x) (((unsigned long)(x) - CONSISTENT_BASE) >> PAGE_SHIFT) - -/* - * This is the page table (2MB) covering uncached, DMA consistent allocations - */ -static pte_t *consistent_pte; -static DEFINE_SPINLOCK(consistent_lock); - -/* - * VM region handling support. - * - * This should become something generic, handling VM region allocations for - * vmalloc and similar (ioremap, module space, etc). - * - * I envisage vmalloc()'s supporting vm_struct becoming: - * - * struct vm_struct { - * struct vm_region region; - * unsigned long flags; - * struct page **pages; - * unsigned int nr_pages; - * unsigned long phys_addr; - * }; - * - * get_vm_area() would then call vm_region_alloc with an appropriate - * struct vm_region head (eg): - * - * struct vm_region vmalloc_head = { - * .vm_list = LIST_HEAD_INIT(vmalloc_head.vm_list), - * .vm_start = VMALLOC_START, - * .vm_end = VMALLOC_END, - * }; - * - * However, vmalloc_head.vm_start is variable (typically, it is dependent on - * the amount of RAM found at boot time.) I would imagine that get_vm_area() - * would have to initialise this each time prior to calling vm_region_alloc(). - */ -struct vm_region { - struct list_head vm_list; - unsigned long vm_start; - unsigned long vm_end; -}; - -static struct vm_region consistent_head = { - .vm_list = LIST_HEAD_INIT(consistent_head.vm_list), - .vm_start = CONSISTENT_BASE, - .vm_end = CONSISTENT_END, -}; - -static struct vm_region * -vm_region_alloc(struct vm_region *head, size_t size, gfp_t gfp) -{ - unsigned long addr = head->vm_start, end = head->vm_end - size; - unsigned long flags; - struct vm_region *c, *new; - - new = kmalloc(sizeof(struct vm_region), gfp); - if (!new) - goto out; - - spin_lock_irqsave(&consistent_lock, flags); - - list_for_each_entry(c, &head->vm_list, vm_list) { - if ((addr + size) < addr) - goto nospc; - if ((addr + size) <= c->vm_start) - goto found; - addr = c->vm_end; - if (addr > end) - goto nospc; - } - - found: - /* - * Insert this entry _before_ the one we found. - */ - list_add_tail(&new->vm_list, &c->vm_list); - new->vm_start = addr; - new->vm_end = addr + size; - - spin_unlock_irqrestore(&consistent_lock, flags); - return new; - - nospc: - spin_unlock_irqrestore(&consistent_lock, flags); - kfree(new); - out: - return NULL; -} - -static struct vm_region *vm_region_find(struct vm_region *head, unsigned long addr) -{ - struct vm_region *c; - - list_for_each_entry(c, &head->vm_list, vm_list) { - if (c->vm_start == addr) - goto out; - } - c = NULL; - out: - return c; -} - -/* - * Allocate DMA-coherent memory space and return both the kernel remapped - * virtual and bus address for that space. - */ -void * -__dma_alloc_coherent(size_t size, dma_addr_t *handle, gfp_t gfp) -{ - struct page *page; - struct vm_region *c; - unsigned long order; - u64 mask = 0x00ffffff, limit; /* ISA default */ - - if (!consistent_pte) { - printk(KERN_ERR "%s: not initialised\n", __func__); - dump_stack(); - return NULL; - } - - size = PAGE_ALIGN(size); - limit = (mask + 1) & ~mask; - if ((limit && size >= limit) || size >= (CONSISTENT_END - CONSISTENT_BASE)) { - printk(KERN_WARNING "coherent allocation too big (requested %#x mask %#Lx)\n", - size, mask); - return NULL; - } - - order = get_order(size); - - if (mask != 0xffffffff) - gfp |= GFP_DMA; - - page = alloc_pages(gfp, order); - if (!page) - goto no_page; - - /* - * Invalidate any data that might be lurking in the - * kernel direct-mapped region for device DMA. - */ - { - unsigned long kaddr = (unsigned long)page_address(page); - memset(page_address(page), 0, size); - flush_dcache_range(kaddr, kaddr + size); - } - - /* - * Allocate a virtual address in the consistent mapping region. - */ - c = vm_region_alloc(&consistent_head, size, - gfp & ~(__GFP_DMA | __GFP_HIGHMEM)); - if (c) { - unsigned long vaddr = c->vm_start; - pte_t *pte = consistent_pte + CONSISTENT_OFFSET(vaddr); - struct page *end = page + (1 << order); - - split_page(page, order); - - /* - * Set the "dma handle" - */ - *handle = page_to_bus(page); - - do { - BUG_ON(!pte_none(*pte)); - - SetPageReserved(page); - set_pte_at(&init_mm, vaddr, - pte, mk_pte(page, pgprot_noncached(PAGE_KERNEL))); - page++; - pte++; - vaddr += PAGE_SIZE; - } while (size -= PAGE_SIZE); - - /* - * Free the otherwise unused pages. - */ - while (page < end) { - __free_page(page); - page++; - } - - return (void *)c->vm_start; - } - - if (page) - __free_pages(page, order); - no_page: - return NULL; -} -EXPORT_SYMBOL(__dma_alloc_coherent); - -/* - * free a page as defined by the above mapping. - */ -void __dma_free_coherent(size_t size, void *vaddr) -{ - struct vm_region *c; - unsigned long flags, addr; - pte_t *ptep; - - size = PAGE_ALIGN(size); - - spin_lock_irqsave(&consistent_lock, flags); - - c = vm_region_find(&consistent_head, (unsigned long)vaddr); - if (!c) - goto no_area; - - if ((c->vm_end - c->vm_start) != size) { - printk(KERN_ERR "%s: freeing wrong coherent size (%ld != %d)\n", - __func__, c->vm_end - c->vm_start, size); - dump_stack(); - size = c->vm_end - c->vm_start; - } - - ptep = consistent_pte + CONSISTENT_OFFSET(c->vm_start); - addr = c->vm_start; - do { - pte_t pte = ptep_get_and_clear(&init_mm, addr, ptep); - unsigned long pfn; - - ptep++; - addr += PAGE_SIZE; - - if (!pte_none(pte) && pte_present(pte)) { - pfn = pte_pfn(pte); - - if (pfn_valid(pfn)) { - struct page *page = pfn_to_page(pfn); - ClearPageReserved(page); - - __free_page(page); - continue; - } - } - - printk(KERN_CRIT "%s: bad page in kernel page table\n", - __func__); - } while (size -= PAGE_SIZE); - - flush_tlb_kernel_range(c->vm_start, c->vm_end); - - list_del(&c->vm_list); - - spin_unlock_irqrestore(&consistent_lock, flags); - - kfree(c); - return; - - no_area: - spin_unlock_irqrestore(&consistent_lock, flags); - printk(KERN_ERR "%s: trying to free invalid coherent area: %p\n", - __func__, vaddr); - dump_stack(); -} -EXPORT_SYMBOL(__dma_free_coherent); - -/* - * Initialise the consistent memory allocation. - */ -static int __init dma_alloc_init(void) -{ - pgd_t *pgd; - pmd_t *pmd; - pte_t *pte; - int ret = 0; - - do { - pgd = pgd_offset(&init_mm, CONSISTENT_BASE); - pmd = pmd_alloc(&init_mm, pgd, CONSISTENT_BASE); - if (!pmd) { - printk(KERN_ERR "%s: no pmd tables\n", __func__); - ret = -ENOMEM; - break; - } - WARN_ON(!pmd_none(*pmd)); - - pte = pte_alloc_kernel(pmd, CONSISTENT_BASE); - if (!pte) { - printk(KERN_ERR "%s: no pte tables\n", __func__); - ret = -ENOMEM; - break; - } - - consistent_pte = pte; - } while (0); - - return ret; -} - -core_initcall(dma_alloc_init); - -/* - * make an area consistent. - */ -void __dma_sync(void *vaddr, size_t size, int direction) -{ - unsigned long start = (unsigned long)vaddr; - unsigned long end = start + size; - - switch (direction) { - case DMA_NONE: - BUG(); - case DMA_FROM_DEVICE: /* invalidate only */ - invalidate_dcache_range(start, end); - break; - case DMA_TO_DEVICE: /* writeback only */ - clean_dcache_range(start, end); - break; - case DMA_BIDIRECTIONAL: /* writeback and invalidate */ - flush_dcache_range(start, end); - break; - } -} -EXPORT_SYMBOL(__dma_sync); - -#ifdef CONFIG_HIGHMEM -/* - * __dma_sync_page() implementation for systems using highmem. - * In this case, each page of a buffer must be kmapped/kunmapped - * in order to have a virtual address for __dma_sync(). This must - * not sleep so kmap_atomic()/kunmap_atomic() are used. - * - * Note: yes, it is possible and correct to have a buffer extend - * beyond the first page. - */ -static inline void __dma_sync_page_highmem(struct page *page, - unsigned long offset, size_t size, int direction) -{ - size_t seg_size = min((size_t)(PAGE_SIZE - offset), size); - size_t cur_size = seg_size; - unsigned long flags, start, seg_offset = offset; - int nr_segs = 1 + ((size - seg_size) + PAGE_SIZE - 1)/PAGE_SIZE; - int seg_nr = 0; - - local_irq_save(flags); - - do { - start = (unsigned long)kmap_atomic(page + seg_nr, - KM_PPC_SYNC_PAGE) + seg_offset; - - /* Sync this buffer segment */ - __dma_sync((void *)start, seg_size, direction); - kunmap_atomic((void *)start, KM_PPC_SYNC_PAGE); - seg_nr++; - - /* Calculate next buffer segment size */ - seg_size = min((size_t)PAGE_SIZE, size - cur_size); - - /* Add the segment size to our running total */ - cur_size += seg_size; - seg_offset = 0; - } while (seg_nr < nr_segs); - - local_irq_restore(flags); -} -#endif /* CONFIG_HIGHMEM */ - -/* - * __dma_sync_page makes memory consistent. identical to __dma_sync, but - * takes a struct page instead of a virtual address - */ -void __dma_sync_page(struct page *page, unsigned long offset, - size_t size, int direction) -{ -#ifdef CONFIG_HIGHMEM - __dma_sync_page_highmem(page, offset, size, direction); -#else - unsigned long start = (unsigned long)page_address(page) + offset; - __dma_sync((void *)start, size, direction); -#endif -} -EXPORT_SYMBOL(__dma_sync_page); diff --git a/arch/ppc/kernel/head.S b/arch/ppc/kernel/head.S index 100052a..c7cb9d5 100644 --- a/arch/ppc/kernel/head.S +++ b/arch/ppc/kernel/head.S @@ -310,12 +310,7 @@ #define EXC_XFER_EE_LITE(n, hdlr) \ /* System reset */ /* core99 pmac starts the seconary here by changing the vector, and putting it back to what it was (unknown_exception) when done. */ -#if defined(CONFIG_GEMINI) && defined(CONFIG_SMP) - . = 0x100 - b __secondary_start_gemini -#else EXCEPTION(0x100, Reset, unknown_exception, EXC_XFER_STD) -#endif /* Machine check */ . = 0x200 @@ -897,19 +892,6 @@ #endif #endif /* CONFIG_APUS */ #ifdef CONFIG_SMP -#ifdef CONFIG_GEMINI - .globl __secondary_start_gemini -__secondary_start_gemini: - mfspr r4,SPRN_HID0 - ori r4,r4,HID0_ICFI - li r3,0 - ori r3,r3,HID0_ICE - andc r4,r4,r3 - mtspr SPRN_HID0,r4 - sync - b __secondary_start -#endif /* CONFIG_GEMINI */ - .globl __secondary_start_pmac_0 __secondary_start_pmac_0: /* NB the entries for cpus 0, 1, 2 must each occupy 8 bytes. */ diff --git a/arch/ppc/kernel/head_fsl_booke.S b/arch/ppc/kernel/head_fsl_booke.S index 66877bd..1f155d3 100644 --- a/arch/ppc/kernel/head_fsl_booke.S +++ b/arch/ppc/kernel/head_fsl_booke.S @@ -206,7 +206,8 @@ #endif rlwimi r7,r3,16,4,15 /* Setup MAS0 = TLBSEL | ESEL(r3) */ mtspr SPRN_MAS0,r7 tlbre - li r6,0 + mfspr r6,SPRN_MAS1 + rlwinm r6,r6,0,2,0 /* clear IPROT */ mtspr SPRN_MAS1,r6 tlbwe /* Invalidate TLB1 */ @@ -248,6 +249,8 @@ #endif rlwimi r7,r5,16,4,15 /* Setup MAS0 = TLBSEL | ESEL(r5) */ mtspr SPRN_MAS0,r7 tlbre + mfspr r8,SPRN_MAS1 + rlwinm r8,r8,0,2,0 /* clear IPROT */ mtspr SPRN_MAS1,r8 tlbwe /* Invalidate TLB1 */ @@ -889,7 +892,6 @@ #endif /* CONFIG_SMP */ REST_GPR(9, r11) REST_GPR(12, r11) lwz r11,GPR11(r11) - SYNC rfi /* @@ -953,7 +955,6 @@ #ifdef CONFIG_SPE _GLOBAL(giveup_spe) mfmsr r5 oris r5,r5,MSR_SPE@h - SYNC mtmsr r5 /* enable use of SPE now */ isync cmpi 0,r3,0 diff --git a/arch/ppc/kernel/ppc_htab.c b/arch/ppc/kernel/ppc_htab.c index bd129d3..0a7e42d 100644 --- a/arch/ppc/kernel/ppc_htab.c +++ b/arch/ppc/kernel/ppc_htab.c @@ -442,17 +442,22 @@ static ctl_table htab_ctl_table[]={ .mode = 0644, .proc_handler = &proc_dol2crvec, }, - { 0, }, + {} }; static ctl_table htab_sysctl_root[] = { - { 1, "kernel", NULL, 0, 0755, htab_ctl_table, }, - { 0,}, + { + .ctl_name = CTL_KERN, + .procname = "kernel", + .mode = 0555, + .child = htab_ctl_table, + }, + {} }; static int __init register_ppc_htab_sysctl(void) { - register_sysctl_table(htab_sysctl_root, 0); + register_sysctl_table(htab_sysctl_root); return 0; } diff --git a/arch/ppc/kernel/ppc_ksyms.c b/arch/ppc/kernel/ppc_ksyms.c index c8b65ca..1318b6f 100644 --- a/arch/ppc/kernel/ppc_ksyms.c +++ b/arch/ppc/kernel/ppc_ksyms.c @@ -43,6 +43,7 @@ #include #include #include #include +#include #ifdef CONFIG_8xx #include @@ -270,7 +271,7 @@ #endif /* CONFIG_SMP */ extern long *intercept_table; EXPORT_SYMBOL(intercept_table); #endif /* CONFIG_PPC_STD_MMU */ -#if defined(CONFIG_40x) || defined(CONFIG_BOOKE) +#ifdef CONFIG_PPC_DCR_NATIVE EXPORT_SYMBOL(__mtdcr); EXPORT_SYMBOL(__mfdcr); #endif diff --git a/arch/ppc/kernel/setup.c b/arch/ppc/kernel/setup.c index 3c506af..c79704f 100644 --- a/arch/ppc/kernel/setup.c +++ b/arch/ppc/kernel/setup.c @@ -543,7 +543,7 @@ #endif init_mm.brk = (unsigned long) klimit; /* Save unparsed command line copy for /proc/cmdline */ - strlcpy(saved_command_line, cmd_line, COMMAND_LINE_SIZE); + strlcpy(boot_command_line, cmd_line, COMMAND_LINE_SIZE); *cmdline_p = cmd_line; parse_early_param(); diff --git a/arch/ppc/kernel/vmlinux.lds.S b/arch/ppc/kernel/vmlinux.lds.S index 6192126..a062556 100644 --- a/arch/ppc/kernel/vmlinux.lds.S +++ b/arch/ppc/kernel/vmlinux.lds.S @@ -135,10 +135,12 @@ SECTIONS .data.percpu : { *(.data.percpu) } __per_cpu_end = .; +#ifdef CONFIG_BLK_DEV_INITRD . = ALIGN(4096); __initramfs_start = .; .init.ramfs : { *(.init.ramfs) } __initramfs_end = .; +#endif . = ALIGN(4096); __init_end = .; diff --git a/arch/ppc/lib/rheap.c b/arch/ppc/lib/rheap.c index 31e5118..d407007 100644 --- a/arch/ppc/lib/rheap.c +++ b/arch/ppc/lib/rheap.c @@ -14,6 +14,7 @@ */ #include #include +#include #include #include @@ -654,7 +655,7 @@ void rh_dump(rh_info_t * info) int maxnr; int i, nr; - maxnr = sizeof(st) / sizeof(st[0]); + maxnr = ARRAY_SIZE(st); printk(KERN_INFO "info @0x%p (%d slots empty / %d max)\n", diff --git a/arch/ppc/mm/pgtable.c b/arch/ppc/mm/pgtable.c index 354a940..c023b72 100644 --- a/arch/ppc/mm/pgtable.c +++ b/arch/ppc/mm/pgtable.c @@ -313,11 +313,8 @@ void __init mapin_ram(void) } } -/* is x a power of 2? */ -#define is_power_of_2(x) ((x) != 0 && (((x) & ((x) - 1)) == 0)) - /* is x a power of 4? */ -#define is_power_of_4(x) ((x) != 0 && (((x) & (x-1)) == 0) && (ffs(x) & 1)) +#define is_power_of_4(x) is_power_of_2(x) && (ffs(x) & 1) /* * Set up a mapping for a block of I/O. diff --git a/arch/ppc/platforms/4xx/Kconfig b/arch/ppc/platforms/4xx/Kconfig index 6980de4..705ae56 100644 --- a/arch/ppc/platforms/4xx/Kconfig +++ b/arch/ppc/platforms/4xx/Kconfig @@ -98,6 +98,12 @@ config OCOTEA help This option enables support for the IBM PPC440GX evaluation board. +config TAISHAN + bool "Taishan" + select WANT_EARLY_SERIAL + help + This option enables support for the AMCC PPC440GX evaluation board. + endchoice config EP405PC @@ -126,7 +132,7 @@ config 440GP config 440GX bool - depends on OCOTEA + depends on OCOTEA || TAISHAN default y config 440SP @@ -173,7 +179,7 @@ config BOOKE config IBM_OCP bool - depends on ASH || BAMBOO || BUBINGA || CPCI405 || EBONY || EP405 || LUAN || YUCCA || OCOTEA || REDWOOD_5 || REDWOOD_6 || SYCAMORE || WALNUT + depends on ASH || BAMBOO || BUBINGA || CPCI405 || EBONY || EP405 || LUAN || YUCCA || OCOTEA || REDWOOD_5 || REDWOOD_6 || SYCAMORE || TAISHAN || WALNUT default y config IBM_EMAC4 diff --git a/arch/ppc/platforms/4xx/Makefile b/arch/ppc/platforms/4xx/Makefile index a04a0d0..fa6610b 100644 --- a/arch/ppc/platforms/4xx/Makefile +++ b/arch/ppc/platforms/4xx/Makefile @@ -12,6 +12,7 @@ obj-$(CONFIG_OCOTEA) += ocotea.o obj-$(CONFIG_REDWOOD_5) += redwood5.o obj-$(CONFIG_REDWOOD_6) += redwood6.o obj-$(CONFIG_SYCAMORE) += sycamore.o +obj-$(CONFIG_TAISHAN) += taishan.o obj-$(CONFIG_WALNUT) += walnut.o obj-$(CONFIG_XILINX_ML300) += xilinx_ml300.o obj-$(CONFIG_XILINX_ML403) += xilinx_ml403.o diff --git a/arch/ppc/platforms/4xx/taishan.c b/arch/ppc/platforms/4xx/taishan.c new file mode 100644 index 0000000..bb0253e --- /dev/null +++ b/arch/ppc/platforms/4xx/taishan.c @@ -0,0 +1,395 @@ +/* + * arch/ppc/platforms/4xx/taishan.c + * + * AMCC Taishan board specific routines + * + * Copyright 2007 DENX Software Engineering, Stefan Roese + * + * 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 +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include +#include + +extern bd_t __res; + +static struct ibm44x_clocks clocks __initdata; + +/* + * NOR FLASH configuration (using mtd physmap driver) + */ + +/* start will be added dynamically, end is always fixed */ +static struct resource taishan_nor_resource = { + .start = TAISHAN_FLASH_ADDR, + .end = 0x1ffffffffULL, + .flags = IORESOURCE_MEM, +}; + +#define RW_PART0_OF 0 +#define RW_PART0_SZ 0x180000 +#define RW_PART1_SZ 0x200000 +/* Partition 2 will be autosized dynamically... */ +#define RW_PART3_SZ 0x80000 +#define RW_PART4_SZ 0x40000 + +static struct mtd_partition taishan_nor_parts[] = { + { + .name = "kernel", + .offset = 0, + .size = RW_PART0_SZ + }, + { + .name = "root", + .offset = MTDPART_OFS_APPEND, + .size = RW_PART1_SZ, + }, + { + .name = "user", + .offset = MTDPART_OFS_APPEND, +/* .size = RW_PART2_SZ */ /* will be adjusted dynamically */ + }, + { + .name = "env", + .offset = MTDPART_OFS_APPEND, + .size = RW_PART3_SZ, + }, + { + .name = "u-boot", + .offset = MTDPART_OFS_APPEND, + .size = RW_PART4_SZ, + } +}; + +static struct physmap_flash_data taishan_nor_data = { + .width = 4, + .parts = taishan_nor_parts, + .nr_parts = ARRAY_SIZE(taishan_nor_parts), +}; + +static struct platform_device taishan_nor_device = { + .name = "physmap-flash", + .id = 0, + .dev = { + .platform_data = &taishan_nor_data, + }, + .num_resources = 1, + .resource = &taishan_nor_resource, +}; + +static int taishan_setup_flash(void) +{ + /* + * Adjust partition 2 to flash size + */ + taishan_nor_parts[2].size = __res.bi_flashsize - + RW_PART0_SZ - RW_PART1_SZ - RW_PART3_SZ - RW_PART4_SZ; + + platform_device_register(&taishan_nor_device); + + return 0; +} +arch_initcall(taishan_setup_flash); + +static void __init +taishan_calibrate_decr(void) +{ + unsigned int freq; + + if (mfspr(SPRN_CCR1) & CCR1_TCS) + freq = TAISHAN_TMR_CLK; + else + freq = clocks.cpu; + + ibm44x_calibrate_decr(freq); +} + +static int +taishan_show_cpuinfo(struct seq_file *m) +{ + seq_printf(m, "vendor\t\t: AMCC\n"); + seq_printf(m, "machine\t\t: PPC440GX EVB (Taishan)\n"); + ibm440gx_show_cpuinfo(m); + return 0; +} + +static inline int +taishan_map_irq(struct pci_dev *dev, unsigned char idsel, unsigned char pin) +{ + static char pci_irq_table[][4] = + /* + * PCI IDSEL/INTPIN->INTLINE + * A B C D + */ + { + { 23, 24, 25, 26 }, /* IDSEL 1 - PCI Slot 0 */ + { 24, 25, 26, 23 }, /* IDSEL 2 - PCI Slot 1 */ + }; + + const long min_idsel = 1, max_idsel = 2, irqs_per_slot = 4; + return PCI_IRQ_TABLE_LOOKUP; +} + +static void __init taishan_set_emacdata(void) +{ + struct ocp_def *def; + struct ocp_func_emac_data *emacdata; + int i; + + /* Set phy_map, phy_mode, and mac_addr for each EMAC */ + for (i=2; i<4; i++) { + def = ocp_get_one_device(OCP_VENDOR_IBM, OCP_FUNC_EMAC, i); + emacdata = def->additions; + if (i < 2) { + emacdata->phy_map = 0x00000001; /* Skip 0x00 */ + emacdata->phy_mode = PHY_MODE_SMII; + } else { + emacdata->phy_map = 0x00000001; /* Skip 0x00 */ + emacdata->phy_mode = PHY_MODE_RGMII; + } + if (i == 0) + memcpy(emacdata->mac_addr, "\0\0\0\0\0\0", 6); + else if (i == 1) + memcpy(emacdata->mac_addr, "\0\0\0\0\0\0", 6); + else if (i == 2) + memcpy(emacdata->mac_addr, __res.bi_enetaddr, 6); + else if (i == 3) + memcpy(emacdata->mac_addr, __res.bi_enet1addr, 6); + } +} + +#define PCIX_READW(offset) \ + (readw(pcix_reg_base+offset)) + +#define PCIX_WRITEW(value, offset) \ + (writew(value, pcix_reg_base+offset)) + +#define PCIX_WRITEL(value, offset) \ + (writel(value, pcix_reg_base+offset)) + +/* + * FIXME: This is only here to "make it work". This will move + * to a ibm_pcix.c which will contain a generic IBM PCIX bridge + * configuration library. -Matt + */ +static void __init +taishan_setup_pcix(void) +{ + void *pcix_reg_base; + + pcix_reg_base = ioremap64(PCIX0_REG_BASE, PCIX_REG_SIZE); + + /* Enable PCIX0 I/O, Mem, and Busmaster cycles */ + PCIX_WRITEW(PCIX_READW(PCIX0_COMMAND) | PCI_COMMAND_IO | PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER, PCIX0_COMMAND); + + /* Disable all windows */ + PCIX_WRITEL(0, PCIX0_POM0SA); + PCIX_WRITEL(0, PCIX0_POM1SA); + PCIX_WRITEL(0, PCIX0_POM2SA); + PCIX_WRITEL(0, PCIX0_PIM0SA); + PCIX_WRITEL(0, PCIX0_PIM0SAH); + PCIX_WRITEL(0, PCIX0_PIM1SA); + PCIX_WRITEL(0, PCIX0_PIM2SA); + PCIX_WRITEL(0, PCIX0_PIM2SAH); + + /* Setup 2GB PLB->PCI outbound mem window (3_8000_0000->0_8000_0000) */ + PCIX_WRITEL(0x00000003, PCIX0_POM0LAH); + PCIX_WRITEL(0x80000000, PCIX0_POM0LAL); + PCIX_WRITEL(0x00000000, PCIX0_POM0PCIAH); + PCIX_WRITEL(0x80000000, PCIX0_POM0PCIAL); + PCIX_WRITEL(0x80000001, PCIX0_POM0SA); + + /* Setup 2GB PCI->PLB inbound memory window at 0, enable MSIs */ + PCIX_WRITEL(0x00000000, PCIX0_PIM0LAH); + PCIX_WRITEL(0x00000000, PCIX0_PIM0LAL); + PCIX_WRITEL(0xe0000007, PCIX0_PIM0SA); + PCIX_WRITEL(0xffffffff, PCIX0_PIM0SAH); + + iounmap(pcix_reg_base); + + eieio(); +} + +static void __init +taishan_setup_hose(void) +{ + struct pci_controller *hose; + + /* Configure windows on the PCI-X host bridge */ + taishan_setup_pcix(); + + hose = pcibios_alloc_controller(); + + if (!hose) + return; + + hose->first_busno = 0; + hose->last_busno = 0xff; + + hose->pci_mem_offset = TAISHAN_PCI_MEM_OFFSET; + + pci_init_resource(&hose->io_resource, + TAISHAN_PCI_LOWER_IO, + TAISHAN_PCI_UPPER_IO, + IORESOURCE_IO, + "PCI host bridge"); + + pci_init_resource(&hose->mem_resources[0], + TAISHAN_PCI_LOWER_MEM, + TAISHAN_PCI_UPPER_MEM, + IORESOURCE_MEM, + "PCI host bridge"); + + hose->io_space.start = TAISHAN_PCI_LOWER_IO; + hose->io_space.end = TAISHAN_PCI_UPPER_IO; + hose->mem_space.start = TAISHAN_PCI_LOWER_MEM; + hose->mem_space.end = TAISHAN_PCI_UPPER_MEM; + hose->io_base_virt = ioremap64(TAISHAN_PCI_IO_BASE, TAISHAN_PCI_IO_SIZE); + isa_io_base = (unsigned long) hose->io_base_virt; + + setup_indirect_pci(hose, + TAISHAN_PCI_CFGA_PLB32, + TAISHAN_PCI_CFGD_PLB32); + hose->set_cfg_type = 1; + + hose->last_busno = pciauto_bus_scan(hose, hose->first_busno); + + ppc_md.pci_swizzle = common_swizzle; + ppc_md.pci_map_irq = taishan_map_irq; +} + + +static void __init +taishan_early_serial_map(void) +{ + struct uart_port port; + + /* Setup ioremapped serial port access */ + memset(&port, 0, sizeof(port)); + port.membase = ioremap64(PPC440GX_UART0_ADDR, 8); + port.irq = UART0_INT; + port.uartclk = clocks.uart0; + port.regshift = 0; + port.iotype = UPIO_MEM; + port.flags = UPF_BOOT_AUTOCONF | UPF_SKIP_TEST; + port.line = 0; + + if (early_serial_setup(&port) != 0) + printk("Early serial init of port 0 failed\n"); + +#if defined(CONFIG_SERIAL_TEXT_DEBUG) || defined(CONFIG_KGDB) + /* Configure debug serial access */ + gen550_init(0, &port); + + /* Purge TLB entry added in head_44x.S for early serial access */ + _tlbie(UART0_IO_BASE); +#endif + + port.membase = ioremap64(PPC440GX_UART1_ADDR, 8); + port.irq = UART1_INT; + port.uartclk = clocks.uart1; + port.line = 1; + + if (early_serial_setup(&port) != 0) + printk("Early serial init of port 1 failed\n"); + +#if defined(CONFIG_SERIAL_TEXT_DEBUG) || defined(CONFIG_KGDB) + /* Configure debug serial access */ + gen550_init(1, &port); +#endif +} + +static void __init +taishan_setup_arch(void) +{ + taishan_set_emacdata(); + + ibm440gx_tah_enable(); + + /* + * Determine various clocks. + * To be completely correct we should get SysClk + * from FPGA, because it can be changed by on-board switches + * --ebs + */ + ibm440gx_get_clocks(&clocks, 33333333, 6 * 1843200); + ocp_sys_info.opb_bus_freq = clocks.opb; + + /* init to some ~sane value until calibrate_delay() runs */ + loops_per_jiffy = 50000000/HZ; + + /* Setup PCI host bridge */ + taishan_setup_hose(); + +#ifdef CONFIG_BLK_DEV_INITRD + if (initrd_start) + ROOT_DEV = Root_RAM0; + else +#endif +#ifdef CONFIG_ROOT_NFS + ROOT_DEV = Root_NFS; +#else + ROOT_DEV = Root_HDA1; +#endif + + taishan_early_serial_map(); + + /* Identify the system */ + printk("AMCC PowerPC 440GX Taishan Platform\n"); +} + +static void __init taishan_init(void) +{ + ibm440gx_l2c_setup(&clocks); +} + +void __init platform_init(unsigned long r3, unsigned long r4, + unsigned long r5, unsigned long r6, unsigned long r7) +{ + ibm44x_platform_init(r3, r4, r5, r6, r7); + + ppc_md.setup_arch = taishan_setup_arch; + ppc_md.show_cpuinfo = taishan_show_cpuinfo; + ppc_md.get_irq = NULL; /* Set in ppc4xx_pic_init() */ + + ppc_md.calibrate_decr = taishan_calibrate_decr; + +#ifdef CONFIG_KGDB + ppc_md.early_serial_map = taishan_early_serial_map; +#endif + ppc_md.init = taishan_init; +} + diff --git a/arch/ppc/platforms/4xx/taishan.h b/arch/ppc/platforms/4xx/taishan.h new file mode 100644 index 0000000..ea7561a --- /dev/null +++ b/arch/ppc/platforms/4xx/taishan.h @@ -0,0 +1,67 @@ +/* + * arch/ppc/platforms/4xx/taishan.h + * + * AMCC Taishan board definitions + * + * Copyright 2007 DENX Software Engineering, Stefan Roese + * + * 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. + * + */ + +#ifdef __KERNEL__ +#ifndef __ASM_TAISHAN_H__ +#define __ASM_TAISHAN_H__ + +#include + +/* External timer clock frequency */ +#define TAISHAN_TMR_CLK 25000000 + +/* Flash */ +#define TAISHAN_FPGA_ADDR 0x0000000141000000ULL +#define TAISHAN_LCM_ADDR 0x0000000142000000ULL +#define TAISHAN_FLASH_ADDR 0x00000001fc000000ULL +#define TAISHAN_FLASH_SIZE 0x4000000 + +/* + * Serial port defines + */ +#define RS_TABLE_SIZE 2 + +/* head_44x.S created UART mapping, used before early_serial_setup. + * We cannot use default OpenBIOS UART mappings because they + * don't work for configurations with more than 512M RAM. --ebs + */ +#define UART0_IO_BASE 0xF0000200 +#define UART1_IO_BASE 0xF0000300 + +#define BASE_BAUD 11059200/16 +#define STD_UART_OP(num) \ + { 0, BASE_BAUD, 0, UART##num##_INT, \ + (ASYNC_BOOT_AUTOCONF | ASYNC_SKIP_TEST), \ + iomem_base: (void*)UART##num##_IO_BASE, \ + io_type: SERIAL_IO_MEM}, + +#define SERIAL_PORT_DFNS \ + STD_UART_OP(0) \ + STD_UART_OP(1) + +/* PCI support */ +#define TAISHAN_PCI_LOWER_IO 0x00000000 +#define TAISHAN_PCI_UPPER_IO 0x0000ffff +#define TAISHAN_PCI_LOWER_MEM 0x80000000 +#define TAISHAN_PCI_UPPER_MEM 0xffffefff + +#define TAISHAN_PCI_CFGA_PLB32 0x0ec00000 +#define TAISHAN_PCI_CFGD_PLB32 0x0ec00004 + +#define TAISHAN_PCI_IO_BASE 0x0000000208000000ULL +#define TAISHAN_PCI_IO_SIZE 0x00010000 +#define TAISHAN_PCI_MEM_OFFSET 0x00000000 + +#endif /* __ASM_TAISHAN_H__ */ +#endif /* __KERNEL__ */ diff --git a/arch/ppc/platforms/Makefile b/arch/ppc/platforms/Makefile index 90c6222..e17fad4 100644 --- a/arch/ppc/platforms/Makefile +++ b/arch/ppc/platforms/Makefile @@ -13,7 +13,6 @@ obj-$(CONFIG_TQM8260) += tqm8260_setup. obj-$(CONFIG_CPCI690) += cpci690.o obj-$(CONFIG_EV64260) += ev64260.o obj-$(CONFIG_CHESTNUT) += chestnut.o -obj-$(CONFIG_GEMINI) += gemini_pci.o gemini_setup.o gemini_prom.o obj-$(CONFIG_LOPEC) += lopec.o obj-$(CONFIG_KATANA) += katana.o obj-$(CONFIG_HDPU) += hdpu.o diff --git a/arch/ppc/platforms/gemini.h b/arch/ppc/platforms/gemini.h deleted file mode 100644 index 5528fd0..0000000 --- a/arch/ppc/platforms/gemini.h +++ /dev/null @@ -1,165 +0,0 @@ -/* - * Onboard registers and descriptions for Synergy Microsystems' - * "Gemini" boards. - * - */ -#ifdef __KERNEL__ -#ifndef __PPC_GEMINI_H -#define __PPC_GEMINI_H - -/* Registers */ - -#define GEMINI_SERIAL_B (0xffeffb00) -#define GEMINI_SERIAL_A (0xffeffb08) -#define GEMINI_USWITCH (0xffeffd00) -#define GEMINI_BREV (0xffeffe00) -#define GEMINI_BECO (0xffeffe08) -#define GEMINI_FEAT (0xffeffe10) -#define GEMINI_BSTAT (0xffeffe18) -#define GEMINI_CPUSTAT (0xffeffe20) -#define GEMINI_L2CFG (0xffeffe30) -#define GEMINI_MEMCFG (0xffeffe38) -#define GEMINI_FLROM (0xffeffe40) -#define GEMINI_P0PCI (0xffeffe48) -#define GEMINI_FLWIN (0xffeffe50) -#define GEMINI_P0INTMASK (0xffeffe60) -#define GEMINI_P0INTAP (0xffeffe68) -#define GEMINI_PCIERR (0xffeffe70) -#define GEMINI_LEDBASE (0xffeffe80) -#define GEMINI_RTC (0xffe9fff8) -#define GEMINI_LEDS 8 -#define GEMINI_SWITCHES 8 - - -/* Flash ROM bit definitions */ -#define GEMINI_FLS_WEN (1<<0) -#define GEMINI_FLS_JMP (1<<6) -#define GEMINI_FLS_BOOT (1<<7) - -/* Memory bit definitions */ -#define GEMINI_MEM_TYPE_MASK 0xc0 -#define GEMINI_MEM_SIZE_MASK 0x38 -#define GEMINI_MEM_BANK_MASK 0x07 - -/* L2 cache bit definitions */ -#define GEMINI_L2_SIZE_MASK 0xc0 -#define GEMINI_L2_RATIO_MASK 0x03 - -/* Timebase register bit definitons */ -#define GEMINI_TIMEB0_EN (1<<0) -#define GEMINI_TIMEB1_EN (1<<1) -#define GEMINI_TIMEB2_EN (1<<2) -#define GEMINI_TIMEB3_EN (1<<3) - -/* CPU status bit definitions */ -#define GEMINI_CPU_ID_MASK 0x03 -#define GEMINI_CPU_COUNT_MASK 0x0c -#define GEMINI_CPU0_HALTED (1<<4) -#define GEMINI_CPU1_HALTED (1<<5) -#define GEMINI_CPU2_HALTED (1<<6) -#define GEMINI_CPU3_HALTED (1<<7) - -/* Board status bit definitions */ -#define GEMINI_BRD_FAIL (1<<0) /* FAIL led is lit */ -#define GEMINI_BRD_BUS_MASK 0x0c /* PowerPC bus speed */ - -/* Board family/feature bit descriptions */ -#define GEMINI_FEAT_HAS_FLASH (1<<0) -#define GEMINI_FEAT_HAS_ETH (1<<1) -#define GEMINI_FEAT_HAS_SCSI (1<<2) -#define GEMINI_FEAT_HAS_P0 (1<<3) -#define GEMINI_FEAT_FAM_MASK 0xf0 - -/* Mod/ECO bit definitions */ -#define GEMINI_ECO_LEVEL_MASK 0x0f -#define GEMINI_MOD_MASK 0xf0 - -/* Type/revision bit definitions */ -#define GEMINI_REV_MASK 0x0f -#define GEMINI_TYPE_MASK 0xf0 - -/* User switch definitions */ -#define GEMINI_SWITCH_VERBOSE 1 /* adds "debug" to boot cmd line */ -#define GEMINI_SWITCH_SINGLE_USER 7 /* boots into "single-user" mode */ - -#define SGS_RTC_CONTROL 0 -#define SGS_RTC_SECONDS 1 -#define SGS_RTC_MINUTES 2 -#define SGS_RTC_HOURS 3 -#define SGS_RTC_DAY 4 -#define SGS_RTC_DAY_OF_MONTH 5 -#define SGS_RTC_MONTH 6 -#define SGS_RTC_YEAR 7 - -#define SGS_RTC_SET 0x80 -#define SGS_RTC_IS_STOPPED 0x80 - -#define GRACKLE_CONFIG_ADDR_ADDR (0xfec00000) -#define GRACKLE_CONFIG_DATA_ADDR (0xfee00000) - -#define GEMINI_BOOT_INIT (0xfff00100) - -#ifndef __ASSEMBLY__ - -static inline void grackle_write( unsigned long addr, unsigned long data ) -{ - __asm__ __volatile__( - " stwbrx %1, 0, %0\n \ - sync\n \ - stwbrx %3, 0, %2\n \ - sync " - : /* no output */ - : "r" (GRACKLE_CONFIG_ADDR_ADDR), "r" (addr), - "r" (GRACKLE_CONFIG_DATA_ADDR), "r" (data)); -} - -static inline unsigned long grackle_read( unsigned long addr ) -{ - unsigned long val; - - __asm__ __volatile__( - " stwbrx %1, 0, %2\n \ - sync\n \ - lwbrx %0, 0, %3\n \ - sync " - : "=r" (val) - : "r" (addr), "r" (GRACKLE_CONFIG_ADDR_ADDR), - "r" (GRACKLE_CONFIG_DATA_ADDR)); - - return val; -} - -static inline void gemini_led_on( int led ) -{ - if (led >= 0 && led < GEMINI_LEDS) - *(unsigned char *)(GEMINI_LEDBASE + (led<<3)) = 1; -} - -static inline void gemini_led_off(int led) -{ - if (led >= 0 && led < GEMINI_LEDS) - *(unsigned char *)(GEMINI_LEDBASE + (led<<3)) = 0; -} - -static inline int gemini_led_val(int led) -{ - int val = 0; - if (led >= 0 && led < GEMINI_LEDS) - val = *(unsigned char *)(GEMINI_LEDBASE + (led<<3)); - return (val & 0x1); -} - -/* returns processor id from the board */ -static inline int gemini_processor(void) -{ - unsigned char cpu = *(unsigned char *)(GEMINI_CPUSTAT); - return (int) ((cpu == 0) ? 4 : (cpu & GEMINI_CPU_ID_MASK)); -} - - -extern void _gemini_reboot(void); -extern void gemini_prom_init(void); -extern void gemini_init_l2(void); -#endif /* __ASSEMBLY__ */ -#endif -#endif /* __KERNEL__ */ diff --git a/arch/ppc/platforms/gemini_pci.c b/arch/ppc/platforms/gemini_pci.c deleted file mode 100644 index 9565609..0000000 --- a/arch/ppc/platforms/gemini_pci.c +++ /dev/null @@ -1,41 +0,0 @@ -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include - -void __init gemini_pcibios_fixup(void) -{ - int i; - struct pci_dev *dev = NULL; - - for_each_pci_dev(dev) { - for(i = 0; i < 6; i++) { - if (dev->resource[i].flags & IORESOURCE_IO) { - dev->resource[i].start |= (0xfe << 24); - dev->resource[i].end |= (0xfe << 24); - } - } - } -} - - -/* The "bootloader" for Synergy boards does none of this for us, so we need to - lay it all out ourselves... --Dan */ -void __init gemini_find_bridges(void) -{ - struct pci_controller* hose; - - ppc_md.pcibios_fixup = gemini_pcibios_fixup; - - hose = pcibios_alloc_controller(); - if (!hose) - return; - setup_indirect_pci(hose, 0xfec00000, 0xfee00000); -} diff --git a/arch/ppc/platforms/gemini_prom.S b/arch/ppc/platforms/gemini_prom.S deleted file mode 100644 index e8c84d2..0000000 --- a/arch/ppc/platforms/gemini_prom.S +++ /dev/null @@ -1,90 +0,0 @@ -/* - * Not really prom support code (yet), but sort of anti-prom code. The current - * bootloader does a number of things it shouldn't and doesn't do things that it - * should. The stuff in here is mainly a hodge-podge collection of setup code - * to get the board up and running. - * ---Dan - */ - -#include -#include -#include -#include - -/* - * On 750's the MMU is on when Linux is booted, so we need to clear out the - * bootloader's BAT settings, make sure we're in supervisor state (gotcha!), - * and turn off the MMU. - * - */ - -_GLOBAL(gemini_prom_init) -#ifdef CONFIG_SMP - /* Since the MMU's on, get stuff in rom space that we'll need */ - lis r4,GEMINI_CPUSTAT@h - ori r4,r4,GEMINI_CPUSTAT@l - lbz r5,0(r4) - andi. r5,r5,3 - mr r24,r5 /* cpu # used later on */ -#endif - mfmsr r4 - li r3,MSR_PR /* ensure supervisor! */ - ori r3,r3,MSR_IR|MSR_DR - andc r4,r4,r3 - mtmsr r4 - isync -#if 0 - /* zero out the bats now that the MMU is off */ -prom_no_mmu: - li r3,0 - mtspr SPRN_IBAT0U,r3 - mtspr SPRN_IBAT0L,r3 - mtspr SPRN_IBAT1U,r3 - mtspr SPRN_IBAT1L,r3 - mtspr SPRN_IBAT2U,r3 - mtspr SPRN_IBAT2L,r3 - mtspr SPRN_IBAT3U,r3 - mtspr SPRN_IBAT3L,r3 - - mtspr SPRN_DBAT0U,r3 - mtspr SPRN_DBAT0L,r3 - mtspr SPRN_DBAT1U,r3 - mtspr SPRN_DBAT1L,r3 - mtspr SPRN_DBAT2U,r3 - mtspr SPRN_DBAT2L,r3 - mtspr SPRN_DBAT3U,r3 - mtspr SPRN_DBAT3L,r3 -#endif - - /* the bootloader (as far as I'm currently aware) doesn't mess with page - tables, but since we're already here, might as well zap these, too */ - li r4,0 - mtspr SPRN_SDR1,r4 - - li r4,16 - mtctr r4 - li r3,0 - li r4,0 -3: mtsrin r3,r4 - addi r3,r3,1 - bdnz 3b - -#ifdef CONFIG_SMP - /* The 750 book (and Mot/IBM support) says that this will "assist" snooping - when in SMP. Not sure yet whether this should stay or leave... */ - mfspr r4,SPRN_HID0 - ori r4,r4,HID0_ABE - mtspr SPRN_HID0,r4 - sync -#endif /* CONFIG_SMP */ - blr - -/* apparently, SMon doesn't pay attention to HID0[SRST]. Disable the MMU and - branch to 0xfff00100 */ -_GLOBAL(_gemini_reboot) - lis r5,GEMINI_BOOT_INIT@h - ori r5,r5,GEMINI_BOOT_INIT@l - li r6,MSR_IP - mtspr SPRN_SRR0,r5 - mtspr SPRN_SRR1,r6 - rfi diff --git a/arch/ppc/platforms/gemini_serial.h b/arch/ppc/platforms/gemini_serial.h deleted file mode 100644 index b915eff..0000000 --- a/arch/ppc/platforms/gemini_serial.h +++ /dev/null @@ -1,40 +0,0 @@ -#ifdef __KERNEL__ -#ifndef __ASMPPC_GEMINI_SERIAL_H -#define __ASMPPC_GEMINI_SERIAL_H - -#include - -#ifdef CONFIG_SERIAL_MANY_PORTS -#define RS_TABLE_SIZE 64 -#else -#define RS_TABLE_SIZE 4 -#endif - -/* Rate for the 24.576 Mhz clock for the onboard serial chip */ -#define BASE_BAUD (24576000 / 16) - -#ifdef CONFIG_SERIAL_DETECT_IRQ -#define STD_COM_FLAGS (ASYNC_BOOT_AUTOCONF|ASYNC_SKIP_TEST|ASYNC_AUTO_IRQ) -#define STD_COM4_FLAGS (ASYNC_BOOT_AUTOCONF|ASYNC_AUTO_IRQ) -#else -#define STD_COM_FLAGS (ASYNC_BOOT_AUTOCONF|ASYNC_SKIP_TEST) -#define STD_COM4_FLAGS (ASYNC_BOOT_AUTOCONF) -#endif - -#define STD_SERIAL_PORT_DEFNS \ - { 0, BASE_BAUD, GEMINI_SERIAL_A, 15, STD_COM_FLAGS }, /* ttyS0 */ \ - { 0, BASE_BAUD, GEMINI_SERIAL_B, 14, STD_COM_FLAGS }, /* ttyS1 */ \ - -#ifdef CONFIG_GEMINI_PU32 -#define PU32_SERIAL_PORT_DEFNS \ - { 0, BASE_BAUD, NULL, 0, STD_COM_FLAGS }, -#else -#define PU32_SERIAL_PORT_DEFNS -#endif - -#define SERIAL_PORT_DFNS \ - STD_SERIAL_PORT_DEFNS \ - PU32_SERIAL_PORT_DEFNS - -#endif -#endif /* __KERNEL__ */ diff --git a/arch/ppc/platforms/gemini_setup.c b/arch/ppc/platforms/gemini_setup.c deleted file mode 100644 index f48048f..0000000 --- a/arch/ppc/platforms/gemini_setup.c +++ /dev/null @@ -1,577 +0,0 @@ -/* - * Copyright (C) 1995 Linus Torvalds - * Adapted from 'alpha' version by Gary Thomas - * Modified by Cort Dougan (cort@cs.nmt.edu) - * Synergy Microsystems board support by Dan Cox (dan@synergymicro.com) - * - */ - -#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 - -void gemini_find_bridges(void); -static int gemini_get_clock_speed(void); -extern void gemini_pcibios_fixup(void); - -static char *gemini_board_families[] = { - "VGM", "VSS", "KGM", "VGR", "VCM", "VCS", "KCM", "VCR" -}; -static int gemini_board_count = sizeof(gemini_board_families) / - sizeof(gemini_board_families[0]); - -static unsigned int cpu_7xx[16] = { - 0, 15, 14, 0, 0, 13, 5, 9, 6, 11, 8, 10, 16, 12, 7, 0 -}; -static unsigned int cpu_6xx[16] = { - 0, 0, 14, 0, 0, 13, 5, 9, 6, 11, 8, 10, 0, 12, 7, 0 -}; - -/* - * prom_init is the Gemini version of prom.c:prom_init. We only need - * the BSS clearing code, so I copied that out of prom.c. This is a - * lot simpler than hacking prom.c so it will build with Gemini. -VAL - */ - -#define PTRRELOC(x) ((typeof(x))((unsigned long)(x) + offset)) - -unsigned long -prom_init(void) -{ - unsigned long offset = reloc_offset(); - unsigned long phys; - extern char __bss_start, _end; - - /* First zero the BSS -- use memset, some arches don't have - * caches on yet */ - memset_io(PTRRELOC(&__bss_start),0 , &_end - &__bss_start); - - /* Default */ - phys = offset + KERNELBASE; - - gemini_prom_init(); - - return phys; -} - -int -gemini_show_cpuinfo(struct seq_file *m) -{ - unsigned char reg, rev; - char *family; - unsigned int type; - - reg = readb(GEMINI_FEAT); - family = gemini_board_families[((reg>>4) & 0xf)]; - if (((reg>>4) & 0xf) > gemini_board_count) - printk(KERN_ERR "cpuinfo(): unable to determine board family\n"); - - reg = readb(GEMINI_BREV); - type = (reg>>4) & 0xf; - rev = reg & 0xf; - - reg = readb(GEMINI_BECO); - - seq_printf(m, "machine\t\t: Gemini %s%d, rev %c, eco %d\n", - family, type, (rev + 'A'), (reg & 0xf)); - - seq_printf(m, "board\t\t: Gemini %s", family); - if (type > 9) - seq_printf(m, "%c", (type - 10) + 'A'); - else - seq_printf(m, "%d", type); - - seq_printf(m, ", rev %c, eco %d\n", (rev + 'A'), (reg & 0xf)); - - seq_printf(m, "clock\t\t: %dMhz\n", gemini_get_clock_speed()); - - return 0; -} - -static u_char gemini_openpic_initsenses[] = { - 1, - 1, - 1, - 1, - 0, - 0, - 1, /* remainder are level-triggered */ -}; - -#define GEMINI_MPIC_ADDR (0xfcfc0000) -#define GEMINI_MPIC_PCI_CFG (0x80005800) - -void __init gemini_openpic_init(void) -{ - - OpenPIC_Addr = (volatile struct OpenPIC *) - grackle_read(GEMINI_MPIC_PCI_CFG + 0x10); - OpenPIC_InitSenses = gemini_openpic_initsenses; - OpenPIC_NumInitSenses = sizeof( gemini_openpic_initsenses ); - - ioremap( GEMINI_MPIC_ADDR, OPENPIC_SIZE); -} - - -extern unsigned long loops_per_jiffy; -extern int root_mountflags; -extern char cmd_line[]; - -void -gemini_heartbeat(void) -{ - static unsigned long led = GEMINI_LEDBASE+(4*8); - static char direction = 8; - - - /* We only want to do this on 1 CPU */ - if (smp_processor_id()) - return; - *(char *)led = 0; - if ( (led + direction) > (GEMINI_LEDBASE+(7*8)) || - (led + direction) < (GEMINI_LEDBASE+(4*8)) ) - direction *= -1; - led += direction; - *(char *)led = 0xff; - ppc_md.heartbeat_count = ppc_md.heartbeat_reset; -} - -void __init gemini_setup_arch(void) -{ - extern char cmd_line[]; - - - loops_per_jiffy = 50000000/HZ; - -#ifdef CONFIG_BLK_DEV_INITRD - /* bootable off CDROM */ - if (initrd_start) - ROOT_DEV = Root_SR0; - else -#endif - ROOT_DEV = Root_SDA1; - - /* nothing but serial consoles... */ - sprintf(cmd_line, "%s console=ttyS0", cmd_line); - - printk("Boot arguments: %s\n", cmd_line); - - ppc_md.heartbeat = gemini_heartbeat; - ppc_md.heartbeat_reset = HZ/8; - ppc_md.heartbeat_count = 1; - - /* Lookup PCI hosts */ - gemini_find_bridges(); - /* take special pains to map the MPIC, since it isn't mapped yet */ - gemini_openpic_init(); - /* start the L2 */ - gemini_init_l2(); -} - - -int -gemini_get_clock_speed(void) -{ - unsigned long hid1, pvr; - int clock; - - pvr = mfspr(SPRN_PVR); - hid1 = (mfspr(SPRN_HID1) >> 28) & 0xf; - if (PVR_VER(pvr) == 8 || - PVR_VER(pvr) == 12) - hid1 = cpu_7xx[hid1]; - else - hid1 = cpu_6xx[hid1]; - - switch((readb(GEMINI_BSTAT) & 0xc) >> 2) { - - case 0: - default: - clock = (hid1*100)/3; - break; - - case 1: - clock = (hid1*125)/3; - break; - - case 2: - clock = (hid1*50); - break; - } - - return clock; -} - -void __init gemini_init_l2(void) -{ - unsigned char reg, brev, fam, creg; - unsigned long cache; - unsigned long pvr; - - reg = readb(GEMINI_L2CFG); - brev = readb(GEMINI_BREV); - fam = readb(GEMINI_FEAT); - pvr = mfspr(SPRN_PVR); - - switch(PVR_VER(pvr)) { - - case 8: - if (reg & 0xc0) - cache = (((reg >> 6) & 0x3) << 28); - else - cache = 0x3 << 28; - -#ifdef CONFIG_SMP - /* Pre-3.0 processor revs had snooping errata. Leave - their L2's disabled with SMP. -- Dan */ - if (PVR_CFG(pvr) < 3) { - printk("Pre-3.0 750; L2 left disabled!\n"); - return; - } -#endif /* CONFIG_SMP */ - - /* Special case: VGM5-B's came before L2 ratios were set on - the board. Processor speed shouldn't be too high, so - set L2 ratio to 1:1.5. */ - if ((brev == 0x51) && ((fam & 0xa0) >> 4) == 0) - reg |= 1; - - /* determine best cache ratio based upon what the board - tells us (which sometimes _may_ not be true) and - the processor speed. */ - else { - if (gemini_get_clock_speed() > 250) - reg = 2; - } - break; - case 12: - { - static unsigned long l2_size_val = 0; - - if (!l2_size_val) - l2_size_val = _get_L2CR(); - cache = l2_size_val; - break; - } - case 4: - case 9: - creg = readb(GEMINI_CPUSTAT); - if (((creg & 0xc) >> 2) != 1) - printk("Dual-604 boards don't support the use of L2\n"); - else - writeb(1, GEMINI_L2CFG); - return; - default: - printk("Unknown processor; L2 left disabled\n"); - return; - } - - cache |= ((1<>2)&0x3) { - case 0: - default: - freq = 66667; - break; - case 1: - freq = 83000; - break; - case 2: - freq = 100000; - break; - } - - freq *= 1000; - divisor = 4; - tb_ticks_per_jiffy = freq / HZ / divisor; - tb_to_us = mulhwu_scale_factor(freq/divisor, 1000000); -} - -unsigned long __init gemini_find_end_of_memory(void) -{ - unsigned long total; - unsigned char reg; - - reg = readb(GEMINI_MEMCFG); - total = ((1<<((reg & 0x7) - 1)) * - (8<<((reg >> 3) & 0x7))); - total *= (1024*1024); - return total; -} - -static void __init -gemini_map_io(void) -{ - io_block_mapping(0xf0000000, 0xf0000000, 0x10000000, _PAGE_IO); - io_block_mapping(0x80000000, 0x80000000, 0x10000000, _PAGE_IO); -} - -#ifdef CONFIG_SMP -static int -smp_gemini_probe(void) -{ - int i, nr; - - nr = (readb(GEMINI_CPUSTAT) & GEMINI_CPU_COUNT_MASK) >> 2; - if (nr == 0) - nr = 4; - - if (nr > 1) { - openpic_request_IPIs(); - for (i = 1; i < nr; ++i) - smp_hw_index[i] = i; - } - - return nr; -} - -static void -smp_gemini_kick_cpu(int nr) -{ - openpic_reset_processor_phys(1 << nr); - openpic_reset_processor_phys(0); -} - -static void -smp_gemini_setup_cpu(int cpu_nr) -{ - if (OpenPIC_Addr) - do_openpic_setup_cpu(); - if (cpu_nr > 0) - gemini_init_l2(); -} - -static struct smp_ops_t gemini_smp_ops = { - smp_openpic_message_pass, - smp_gemini_probe, - smp_gemini_kick_cpu, - smp_gemini_setup_cpu, - .give_timebase = smp_generic_give_timebase, - .take_timebase = smp_generic_take_timebase, -}; -#endif /* CONFIG_SMP */ - -void __init platform_init(unsigned long r3, unsigned long r4, unsigned long r5, - unsigned long r6, unsigned long r7) -{ - int i; - - /* Restore BATs for now */ - mtspr(SPRN_DBAT3U, 0xf0001fff); - mtspr(SPRN_DBAT3L, 0xf000002a); - - parse_bootinfo(find_bootinfo()); - - for(i = 0; i < GEMINI_LEDS; i++) - gemini_led_off(i); - - ISA_DMA_THRESHOLD = 0; - DMA_MODE_READ = 0; - DMA_MODE_WRITE = 0; - -#ifdef CONFIG_BLK_DEV_INITRD - if ( r4 ) - { - initrd_start = r4 + KERNELBASE; - initrd_end = r5 + KERNELBASE; - } -#endif - - ppc_md.setup_arch = gemini_setup_arch; - ppc_md.show_cpuinfo = gemini_show_cpuinfo; - ppc_md.init_IRQ = gemini_init_IRQ; - ppc_md.get_irq = openpic_get_irq; - ppc_md.init = NULL; - - ppc_md.restart = gemini_restart; - ppc_md.power_off = gemini_power_off; - ppc_md.halt = gemini_halt; - - ppc_md.time_init = gemini_time_init; - ppc_md.set_rtc_time = gemini_set_rtc_time; - ppc_md.get_rtc_time = gemini_get_rtc_time; - ppc_md.calibrate_decr = gemini_calibrate_decr; - - ppc_md.find_end_of_memory = gemini_find_end_of_memory; - ppc_md.setup_io_mappings = gemini_map_io; - - ppc_md.pcibios_fixup_bus = gemini_pcibios_fixup; - -#ifdef CONFIG_SMP - smp_ops = &gemini_smp_ops; -#endif /* CONFIG_SMP */ -} diff --git a/arch/ppc/platforms/lopec.c b/arch/ppc/platforms/lopec.c index 18dc6e8..b947c77 100644 --- a/arch/ppc/platforms/lopec.c +++ b/arch/ppc/platforms/lopec.c @@ -344,7 +344,7 @@ #ifdef CONFIG_PPCBUG_NVRAM if (bootargs != NULL) { strcpy(cmd_line, bootargs); /* again.. */ - strcpy(saved_command_line, cmd_line); + strcpy(boot_command_line, cmd_line); } } #endif diff --git a/arch/ppc/platforms/mpc866ads_setup.c b/arch/ppc/platforms/mpc866ads_setup.c index 8a0c07e..5b05d4b 100644 --- a/arch/ppc/platforms/mpc866ads_setup.c +++ b/arch/ppc/platforms/mpc866ads_setup.c @@ -369,7 +369,7 @@ #ifdef CONFIG_SERIAL_CPM_SMC1 ppc_sys_device_setfunc(MPC8xx_CPM_SMC1, PPC_SYS_FUNC_UART); #endif -#ifdef CONFIG_SERIAL_CPM_SMC +#ifdef CONFIG_SERIAL_CPM_SMC2 ppc_sys_device_enable(MPC8xx_CPM_SMC2); ppc_sys_device_setfunc(MPC8xx_CPM_SMC2, PPC_SYS_FUNC_UART); #endif diff --git a/arch/ppc/platforms/pplus.c b/arch/ppc/platforms/pplus.c index 9778105..8a1788c 100644 --- a/arch/ppc/platforms/pplus.c +++ b/arch/ppc/platforms/pplus.c @@ -592,7 +592,7 @@ #ifdef CONFIG_PPCBUG_NVRAM if (bootargs != NULL) { strcpy(cmd_line, bootargs); /* again.. */ - strcpy(saved_command_line, cmd_line); + strcpy(boot_command_line, cmd_line); } } #endif diff --git a/arch/ppc/platforms/prep_setup.c b/arch/ppc/platforms/prep_setup.c index 1cb75a1..f166299 100644 --- a/arch/ppc/platforms/prep_setup.c +++ b/arch/ppc/platforms/prep_setup.c @@ -634,7 +634,7 @@ static void __init prep_init_sound(void) /* * Find a way to push these informations to the cs4232 driver * Give it out with printk, when not in cmd_line? - * Append it to cmd_line and saved_command_line? + * Append it to cmd_line and boot_command_line? * Format is cs4232=io,irq,dma,dma2 */ } @@ -897,7 +897,7 @@ #endif if (bootargs != NULL) { strcpy(cmd_line, bootargs); /* again.. */ - strcpy(saved_command_line, cmd_line); + strcpy(boot_command_line, cmd_line); } } diff --git a/arch/ppc/syslib/Makefile b/arch/ppc/syslib/Makefile index dca23f2..0991111 100644 --- a/arch/ppc/syslib/Makefile +++ b/arch/ppc/syslib/Makefile @@ -45,7 +45,6 @@ obj-$(CONFIG_EBONY) += pci_auto.o todc_ obj-$(CONFIG_EV64260) += todc_time.o pci_auto.o obj-$(CONFIG_EV64360) += todc_time.o obj-$(CONFIG_CHESTNUT) += mv64360_pic.o pci_auto.o -obj-$(CONFIG_GEMINI) += open_pic.o obj-$(CONFIG_GT64260) += gt64260_pic.o obj-$(CONFIG_LOPEC) += pci_auto.o todc_time.o obj-$(CONFIG_HDPU) += pci_auto.o @@ -70,6 +69,7 @@ obj-$(CONFIG_SANDPOINT) += pci_auto.o t obj-$(CONFIG_SBC82xx) += todc_time.o obj-$(CONFIG_SPRUCE) += cpc700_pic.o pci_auto.o \ todc_time.o +obj-$(CONFIG_TAISHAN) += pci_auto.o obj-$(CONFIG_8260) += m8260_setup.o pq2_devices.o pq2_sys.o \ ppc_sys.o obj-$(CONFIG_PCI_8260) += m82xx_pci.o pci_auto.o diff --git a/arch/ppc/syslib/i8259.c b/arch/ppc/syslib/i8259.c index a43dda5..1e5a00a 100644 --- a/arch/ppc/syslib/i8259.c +++ b/arch/ppc/syslib/i8259.c @@ -154,7 +154,7 @@ static struct resource pic_edgectrl_iore static struct irqaction i8259_irqaction = { .handler = no_action, - .flags = SA_INTERRUPT, + .flags = IRQF_DISABLED, .mask = CPU_MASK_NONE, .name = "82c59 secondary cascade", }; diff --git a/arch/ppc/syslib/m8260_pci_erratum9.c b/arch/ppc/syslib/m8260_pci_erratum9.c index 5475709..ebb8c8f 100644 --- a/arch/ppc/syslib/m8260_pci_erratum9.c +++ b/arch/ppc/syslib/m8260_pci_erratum9.c @@ -105,7 +105,8 @@ void idma_pci9_init(void) idma_reg[IDMA_CHAN].idmr = 0; /* mask all IDMA interrupts */ idma_reg[IDMA_CHAN].idsr = 0xff; /* clear all event flags */ - printk("<4>Using IDMA%d for MPC8260 device erratum PCI 9 workaround\n", + printk(KERN_WARNING + "Using IDMA%d for MPC8260 device erratum PCI 9 workaround\n", IDMA_CHAN + 1); return; diff --git a/arch/ppc/syslib/m8xx_setup.c b/arch/ppc/syslib/m8xx_setup.c index d8d299b..01e48d8 100644 --- a/arch/ppc/syslib/m8xx_setup.c +++ b/arch/ppc/syslib/m8xx_setup.c @@ -77,7 +77,7 @@ static struct mtd_partition mpc8xxads_pa } }; -#define mpc8xxads_part_num (sizeof (mpc8xxads_partitions) / sizeof (mpc8xxads_partitions[0])) +#define mpc8xxads_part_num ARRAY_SIZE(mpc8xxads_partitions) #endif diff --git a/arch/ppc/syslib/ppc85xx_rio.c b/arch/ppc/syslib/ppc85xx_rio.c index 05b0e94..2b09780 100644 --- a/arch/ppc/syslib/ppc85xx_rio.c +++ b/arch/ppc/syslib/ppc85xx_rio.c @@ -59,8 +59,6 @@ #define DBELL_SID(x) (*(u8 *)(x + DOORB #define DBELL_TID(x) (*(u8 *)(x + DOORBELL_TID_OFFSET)) #define DBELL_INF(x) (*(u16 *)(x + DOORBELL_INFO_OFFSET)) -#define is_power_of_2(x) (((x) & ((x) - 1)) == 0) - struct rio_atmu_regs { u32 rowtar; u32 pad1; diff --git a/arch/ppc/xmon/ppc-opc.c b/arch/ppc/xmon/ppc-opc.c index 533a6c9..034313c 100644 --- a/arch/ppc/xmon/ppc-opc.c +++ b/arch/ppc/xmon/ppc-opc.c @@ -19,6 +19,7 @@ along with this file; see the file COPYI Software Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include +#include #include "ansidecl.h" #include "ppc.h" @@ -2669,8 +2670,7 @@ const struct powerpc_opcode powerpc_opco }; -const int powerpc_num_opcodes = - sizeof (powerpc_opcodes) / sizeof (powerpc_opcodes[0]); +const int powerpc_num_opcodes = ARRAY_SIZE(powerpc_opcodes); /* The macro table. This is only used by the assembler. */ @@ -2717,5 +2717,4 @@ const struct powerpc_macro powerpc_macro }; -const int powerpc_num_macros = - sizeof (powerpc_macros) / sizeof (powerpc_macros[0]); +const int powerpc_num_macros = ARRAY_SIZE(powerpc_macros); diff --git a/arch/ppc/xmon/start.c b/arch/ppc/xmon/start.c index d74a883..8f0b953 100644 --- a/arch/ppc/xmon/start.c +++ b/arch/ppc/xmon/start.c @@ -58,10 +58,7 @@ #endif void xmon_map_scc(void) { -#if defined(CONFIG_GEMINI) - /* should already be mapped by the kernel boot */ - sccd = (volatile unsigned char *) 0xffeffb08; -#elif defined(CONFIG_405GP) +#if defined(CONFIG_405GP) sccd = (volatile unsigned char *)0xef600300; #elif defined(CONFIG_440EP) sccd = (volatile unsigned char *) ioremap(PPC440EP_UART0_ADDR, 8); diff --git a/arch/s390/Kconfig b/arch/s390/Kconfig index 1227236..eaaac37 100644 --- a/arch/s390/Kconfig +++ b/arch/s390/Kconfig @@ -7,6 +7,10 @@ config MMU bool default y +config ZONE_DMA + bool + default y + config LOCKDEP_SUPPORT bool default y @@ -34,13 +38,12 @@ config GENERIC_HWEIGHT bool default y -config GENERIC_CALIBRATE_DELAY - bool - default y - config GENERIC_TIME def_bool y +config NO_IOMEM + def_bool y + mainmenu "Linux Kernel Configuration" config S390 @@ -134,6 +137,31 @@ config AUDIT_ARCH bool default y +config S390_SWITCH_AMODE + bool "Switch kernel/user addressing modes" + help + This option allows to switch the addressing modes of kernel and user + space. The kernel parameter switch_amode=on will enable this feature, + default is disabled. Enabling this (via kernel parameter) on machines + earlier than IBM System z9-109 EC/BC will reduce system performance. + + Note that this option will also be selected by selecting the execute + protection option below. Enabling the execute protection via the + noexec kernel parameter will also switch the addressing modes, + independent of the switch_amode kernel parameter. + + +config S390_EXEC_PROTECT + bool "Data execute protection" + select S390_SWITCH_AMODE + help + This option allows to enable a buffer overflow protection for user + space programs and it also selects the addressing mode option above. + The kernel parameter noexec=on will enable this feature and also + switch the addressing modes, default is disabled. Enabling this (via + kernel parameter) on machines earlier than IBM System z9-109 EC/BC + will reduce system performance. + comment "Code generation options" choice diff --git a/arch/s390/appldata/appldata.h b/arch/s390/appldata/appldata.h index 0429481..4069b81 100644 --- a/arch/s390/appldata/appldata.h +++ b/arch/s390/appldata/appldata.h @@ -21,8 +21,7 @@ #define APPLDATA_RECORD_OS_ID 0x02 /* i #define APPLDATA_RECORD_NET_SUM_ID 0x03 /* must be < 256 ! */ #define APPLDATA_RECORD_PROC_ID 0x04 -#define CTL_APPLDATA 2120 /* sysctl IDs, must be unique */ -#define CTL_APPLDATA_TIMER 2121 +#define CTL_APPLDATA_TIMER 2121 /* sysctl IDs, must be unique */ #define CTL_APPLDATA_INTERVAL 2122 #define CTL_APPLDATA_MEM 2123 #define CTL_APPLDATA_OS 2124 diff --git a/arch/s390/appldata/appldata_base.c b/arch/s390/appldata/appldata_base.c index b8c2372..0c3cf4b 100644 --- a/arch/s390/appldata/appldata_base.c +++ b/arch/s390/appldata/appldata_base.c @@ -81,7 +81,7 @@ static struct ctl_table appldata_dir_tab /* * Timer */ -DEFINE_PER_CPU(struct vtimer_list, appldata_timer); +static DEFINE_PER_CPU(struct vtimer_list, appldata_timer); static atomic_t appldata_expire_count = ATOMIC_INIT(0); static DEFINE_SPINLOCK(appldata_timer_lock); @@ -506,7 +506,7 @@ int appldata_register_ops(struct appldat ops->ctl_table[3].ctl_name = 0; - ops->sysctl_header = register_sysctl_table(ops->ctl_table,1); + ops->sysctl_header = register_sysctl_table(ops->ctl_table); P_INFO("%s-ops registered!\n", ops->name); return 0; @@ -606,7 +606,7 @@ static int __init appldata_init(void) /* Register cpu hotplug notifier */ register_hotcpu_notifier(&appldata_nb); - appldata_sysctl_header = register_sysctl_table(appldata_dir_table, 1); + appldata_sysctl_header = register_sysctl_table(appldata_dir_table); #ifdef MODULE appldata_dir_table[0].de->owner = THIS_MODULE; appldata_table[0].de->owner = THIS_MODULE; diff --git a/arch/s390/appldata/appldata_mem.c b/arch/s390/appldata/appldata_mem.c index 8aea369..4ca6157 100644 --- a/arch/s390/appldata/appldata_mem.c +++ b/arch/s390/appldata/appldata_mem.c @@ -36,7 +36,7 @@ #define P2K(x) ((x) << (PAGE_SHIFT - 10) * book: * http://oss.software.ibm.com/developerworks/opensource/linux390/index.shtml */ -struct appldata_mem_data { +static struct appldata_mem_data { u64 timestamp; u32 sync_count_1; /* after VM collected the record data, */ u32 sync_count_2; /* sync_count_1 and sync_count_2 should be the diff --git a/arch/s390/appldata/appldata_net_sum.c b/arch/s390/appldata/appldata_net_sum.c index 075e619..f64b8c8 100644 --- a/arch/s390/appldata/appldata_net_sum.c +++ b/arch/s390/appldata/appldata_net_sum.c @@ -34,7 +34,7 @@ #define MY_PRINT_NAME "appldata_net_sum" * book: * http://oss.software.ibm.com/developerworks/opensource/linux390/index.shtml */ -struct appldata_net_sum_data { +static struct appldata_net_sum_data { u64 timestamp; u32 sync_count_1; /* after VM collected the record data, */ u32 sync_count_2; /* sync_count_1 and sync_count_2 should be the diff --git a/arch/s390/crypto/Kconfig b/arch/s390/crypto/Kconfig new file mode 100644 index 0000000..99ff9f0 --- /dev/null +++ b/arch/s390/crypto/Kconfig @@ -0,0 +1,60 @@ +config CRYPTO_SHA1_S390 + tristate "SHA1 digest algorithm" + depends on S390 + select CRYPTO_ALGAPI + help + This is the s390 hardware accelerated implementation of the + SHA-1 secure hash standard (FIPS 180-1/DFIPS 180-2). + +config CRYPTO_SHA256_S390 + tristate "SHA256 digest algorithm" + depends on S390 + select CRYPTO_ALGAPI + help + This is the s390 hardware accelerated implementation of the + SHA256 secure hash standard (DFIPS 180-2). + + This version of SHA implements a 256 bit hash with 128 bits of + security against collision attacks. + +config CRYPTO_DES_S390 + tristate "DES and Triple DES cipher algorithms" + depends on S390 + select CRYPTO_ALGAPI + select CRYPTO_BLKCIPHER + help + This us the s390 hardware accelerated implementation of the + DES cipher algorithm (FIPS 46-2), and Triple DES EDE (FIPS 46-3). + +config CRYPTO_AES_S390 + tristate "AES cipher algorithms" + depends on S390 + select CRYPTO_ALGAPI + select CRYPTO_BLKCIPHER + help + This is the s390 hardware accelerated implementation of the + AES cipher algorithms (FIPS-197). AES uses the Rijndael + algorithm. + + Rijndael appears to be consistently a very good performer in + both hardware and software across a wide range of computing + environments regardless of its use in feedback or non-feedback + modes. Its key setup time is excellent, and its key agility is + good. Rijndael's very low memory requirements make it very well + suited for restricted-space environments, in which it also + demonstrates excellent performance. Rijndael's operations are + among the easiest to defend against power and timing attacks. + + On s390 the System z9-109 currently only supports the key size + of 128 bit. + +config S390_PRNG + tristate "Pseudo random number generator device driver" + depends on S390 + default "m" + help + Select this option if you want to use the s390 pseudo random number + generator. The PRNG is part of the cryptograhic processor functions + and uses triple-DES to generate secure random numbers like the + ANSI X9.17 standard. The PRNG is usable via the char device + /dev/prandom. diff --git a/arch/s390/crypto/Makefile b/arch/s390/crypto/Makefile index bfe2541..14e552c 100644 --- a/arch/s390/crypto/Makefile +++ b/arch/s390/crypto/Makefile @@ -6,5 +6,4 @@ obj-$(CONFIG_CRYPTO_SHA1_S390) += sha1_s obj-$(CONFIG_CRYPTO_SHA256_S390) += sha256_s390.o obj-$(CONFIG_CRYPTO_DES_S390) += des_s390.o des_check_key.o obj-$(CONFIG_CRYPTO_AES_S390) += aes_s390.o - -obj-$(CONFIG_CRYPTO_TEST) += crypt_s390_query.o +obj-$(CONFIG_S390_PRNG) += prng.o diff --git a/arch/s390/crypto/aes_s390.c b/arch/s390/crypto/aes_s390.c index 15c9eec..9163635 100644 --- a/arch/s390/crypto/aes_s390.c +++ b/arch/s390/crypto/aes_s390.c @@ -4,7 +4,7 @@ * s390 implementation of the AES Cipher Algorithm. * * s390 Version: - * Copyright (C) 2005 IBM Deutschland GmbH, IBM Corporation + * Copyright IBM Corp. 2005,2007 * Author(s): Jan Glauber (jang@de.ibm.com) * * Derived from "crypto/aes.c" @@ -27,9 +27,11 @@ #define AES_MAX_KEY_SIZE 32 /* data block size for all key lengths */ #define AES_BLOCK_SIZE 16 -int has_aes_128 = 0; -int has_aes_192 = 0; -int has_aes_256 = 0; +#define AES_KEYLEN_128 1 +#define AES_KEYLEN_192 2 +#define AES_KEYLEN_256 4 + +static char keylen_flag = 0; struct s390_aes_ctx { u8 iv[AES_BLOCK_SIZE]; @@ -47,20 +49,19 @@ static int aes_set_key(struct crypto_tfm switch (key_len) { case 16: - if (!has_aes_128) + if (!(keylen_flag & AES_KEYLEN_128)) goto fail; break; case 24: - if (!has_aes_192) + if (!(keylen_flag & AES_KEYLEN_192)) goto fail; break; case 32: - if (!has_aes_256) + if (!(keylen_flag & AES_KEYLEN_256)) goto fail; break; default: - /* invalid key length */ goto fail; break; } @@ -322,34 +323,32 @@ static int __init aes_init(void) int ret; if (crypt_s390_func_available(KM_AES_128_ENCRYPT)) - has_aes_128 = 1; + keylen_flag |= AES_KEYLEN_128; if (crypt_s390_func_available(KM_AES_192_ENCRYPT)) - has_aes_192 = 1; + keylen_flag |= AES_KEYLEN_192; if (crypt_s390_func_available(KM_AES_256_ENCRYPT)) - has_aes_256 = 1; + keylen_flag |= AES_KEYLEN_256; + + if (!keylen_flag) + return -EOPNOTSUPP; - if (!has_aes_128 && !has_aes_192 && !has_aes_256) - return -ENOSYS; + /* z9 109 and z9 BC/EC only support 128 bit key length */ + if (keylen_flag == AES_KEYLEN_128) + printk(KERN_INFO + "aes_s390: hardware acceleration only available for" + "128 bit keys\n"); ret = crypto_register_alg(&aes_alg); - if (ret != 0) { - printk(KERN_INFO "crypt_s390: aes-s390 couldn't be loaded.\n"); + if (ret) goto aes_err; - } ret = crypto_register_alg(&ecb_aes_alg); - if (ret != 0) { - printk(KERN_INFO - "crypt_s390: ecb-aes-s390 couldn't be loaded.\n"); + if (ret) goto ecb_aes_err; - } ret = crypto_register_alg(&cbc_aes_alg); - if (ret != 0) { - printk(KERN_INFO - "crypt_s390: cbc-aes-s390 couldn't be loaded.\n"); + if (ret) goto cbc_aes_err; - } out: return ret; diff --git a/arch/s390/crypto/crypt_s390.h b/arch/s390/crypto/crypt_s390.h index 2b13708..2775d26 100644 --- a/arch/s390/crypto/crypt_s390.h +++ b/arch/s390/crypto/crypt_s390.h @@ -3,8 +3,9 @@ * * Support for s390 cryptographic instructions. * - * Copyright (C) 2003 IBM Deutschland GmbH, IBM Corporation - * Author(s): Thomas Spatzier (tspat@de.ibm.com) + * Copyright IBM Corp. 2003,2007 + * Author(s): Thomas Spatzier + * Jan Glauber (jan.glauber@de.ibm.com) * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the Free @@ -32,7 +33,8 @@ enum crypt_s390_operations { CRYPT_S390_KMAC = 0x0500 }; -/* function codes for KM (CIPHER MESSAGE) instruction +/* + * function codes for KM (CIPHER MESSAGE) instruction * 0x80 is the decipher modifier bit */ enum crypt_s390_km_func { @@ -51,7 +53,8 @@ enum crypt_s390_km_func { KM_AES_256_DECRYPT = CRYPT_S390_KM | 0x14 | 0x80, }; -/* function codes for KMC (CIPHER MESSAGE WITH CHAINING) +/* + * function codes for KMC (CIPHER MESSAGE WITH CHAINING) * instruction */ enum crypt_s390_kmc_func { @@ -68,9 +71,11 @@ enum crypt_s390_kmc_func { KMC_AES_192_DECRYPT = CRYPT_S390_KMC | 0x13 | 0x80, KMC_AES_256_ENCRYPT = CRYPT_S390_KMC | 0x14, KMC_AES_256_DECRYPT = CRYPT_S390_KMC | 0x14 | 0x80, + KMC_PRNG = CRYPT_S390_KMC | 0x43, }; -/* function codes for KIMD (COMPUTE INTERMEDIATE MESSAGE DIGEST) +/* + * function codes for KIMD (COMPUTE INTERMEDIATE MESSAGE DIGEST) * instruction */ enum crypt_s390_kimd_func { @@ -79,7 +84,8 @@ enum crypt_s390_kimd_func { KIMD_SHA_256 = CRYPT_S390_KIMD | 2, }; -/* function codes for KLMD (COMPUTE LAST MESSAGE DIGEST) +/* + * function codes for KLMD (COMPUTE LAST MESSAGE DIGEST) * instruction */ enum crypt_s390_klmd_func { @@ -88,7 +94,8 @@ enum crypt_s390_klmd_func { KLMD_SHA_256 = CRYPT_S390_KLMD | 2, }; -/* function codes for KMAC (COMPUTE MESSAGE AUTHENTICATION CODE) +/* + * function codes for KMAC (COMPUTE MESSAGE AUTHENTICATION CODE) * instruction */ enum crypt_s390_kmac_func { @@ -98,229 +105,219 @@ enum crypt_s390_kmac_func { KMAC_TDEA_192 = CRYPT_S390_KMAC | 3 }; -/* status word for s390 crypto instructions' QUERY functions */ -struct crypt_s390_query_status { - u64 high; - u64 low; -}; - -/* +/** + * crypt_s390_km: + * @func: the function code passed to KM; see crypt_s390_km_func + * @param: address of parameter block; see POP for details on each func + * @dest: address of destination memory area + * @src: address of source memory area + * @src_len: length of src operand in bytes + * * Executes the KM (CIPHER MESSAGE) operation of the CPU. - * @param func: the function code passed to KM; see crypt_s390_km_func - * @param param: address of parameter block; see POP for details on each func - * @param dest: address of destination memory area - * @param src: address of source memory area - * @param src_len: length of src operand in bytes - * @returns < zero for failure, 0 for the query func, number of processed bytes - * for encryption/decryption funcs + * + * Returns -1 for failure, 0 for the query func, number of processed + * bytes for encryption/decryption funcs */ -static inline int -crypt_s390_km(long func, void* param, u8* dest, const u8* src, long src_len) +static inline int crypt_s390_km(long func, void *param, + u8 *dest, const u8 *src, long src_len) { register long __func asm("0") = func & CRYPT_S390_FUNC_MASK; - register void* __param asm("1") = param; - register const u8* __src asm("2") = src; + register void *__param asm("1") = param; + register const u8 *__src asm("2") = src; register long __src_len asm("3") = src_len; - register u8* __dest asm("4") = dest; + register u8 *__dest asm("4") = dest; int ret; asm volatile( "0: .insn rre,0xb92e0000,%3,%1 \n" /* KM opcode */ "1: brc 1,0b \n" /* handle partial completion */ - " ahi %0,%h7\n" - "2: ahi %0,%h8\n" - "3:\n" - EX_TABLE(0b,3b) EX_TABLE(1b,2b) + " la %0,0\n" + "2:\n" + EX_TABLE(0b,2b) EX_TABLE(1b,2b) : "=d" (ret), "+a" (__src), "+d" (__src_len), "+a" (__dest) - : "d" (__func), "a" (__param), "0" (-EFAULT), - "K" (ENOSYS), "K" (-ENOSYS + EFAULT) : "cc", "memory"); + : "d" (__func), "a" (__param), "0" (-1) : "cc", "memory"); if (ret < 0) return ret; return (func & CRYPT_S390_FUNC_MASK) ? src_len - __src_len : __src_len; } -/* +/** + * crypt_s390_kmc: + * @func: the function code passed to KM; see crypt_s390_kmc_func + * @param: address of parameter block; see POP for details on each func + * @dest: address of destination memory area + * @src: address of source memory area + * @src_len: length of src operand in bytes + * * Executes the KMC (CIPHER MESSAGE WITH CHAINING) operation of the CPU. - * @param func: the function code passed to KM; see crypt_s390_kmc_func - * @param param: address of parameter block; see POP for details on each func - * @param dest: address of destination memory area - * @param src: address of source memory area - * @param src_len: length of src operand in bytes - * @returns < zero for failure, 0 for the query func, number of processed bytes - * for encryption/decryption funcs + * + * Returns -1 for failure, 0 for the query func, number of processed + * bytes for encryption/decryption funcs */ -static inline int -crypt_s390_kmc(long func, void* param, u8* dest, const u8* src, long src_len) +static inline int crypt_s390_kmc(long func, void *param, + u8 *dest, const u8 *src, long src_len) { register long __func asm("0") = func & CRYPT_S390_FUNC_MASK; - register void* __param asm("1") = param; - register const u8* __src asm("2") = src; + register void *__param asm("1") = param; + register const u8 *__src asm("2") = src; register long __src_len asm("3") = src_len; - register u8* __dest asm("4") = dest; + register u8 *__dest asm("4") = dest; int ret; asm volatile( "0: .insn rre,0xb92f0000,%3,%1 \n" /* KMC opcode */ "1: brc 1,0b \n" /* handle partial completion */ - " ahi %0,%h7\n" - "2: ahi %0,%h8\n" - "3:\n" - EX_TABLE(0b,3b) EX_TABLE(1b,2b) + " la %0,0\n" + "2:\n" + EX_TABLE(0b,2b) EX_TABLE(1b,2b) : "=d" (ret), "+a" (__src), "+d" (__src_len), "+a" (__dest) - : "d" (__func), "a" (__param), "0" (-EFAULT), - "K" (ENOSYS), "K" (-ENOSYS + EFAULT) : "cc", "memory"); + : "d" (__func), "a" (__param), "0" (-1) : "cc", "memory"); if (ret < 0) return ret; return (func & CRYPT_S390_FUNC_MASK) ? src_len - __src_len : __src_len; } -/* +/** + * crypt_s390_kimd: + * @func: the function code passed to KM; see crypt_s390_kimd_func + * @param: address of parameter block; see POP for details on each func + * @src: address of source memory area + * @src_len: length of src operand in bytes + * * Executes the KIMD (COMPUTE INTERMEDIATE MESSAGE DIGEST) operation * of the CPU. - * @param func: the function code passed to KM; see crypt_s390_kimd_func - * @param param: address of parameter block; see POP for details on each func - * @param src: address of source memory area - * @param src_len: length of src operand in bytes - * @returns < zero for failure, 0 for the query func, number of processed bytes - * for digest funcs + * + * Returns -1 for failure, 0 for the query func, number of processed + * bytes for digest funcs */ -static inline int -crypt_s390_kimd(long func, void* param, const u8* src, long src_len) +static inline int crypt_s390_kimd(long func, void *param, + const u8 *src, long src_len) { register long __func asm("0") = func & CRYPT_S390_FUNC_MASK; - register void* __param asm("1") = param; - register const u8* __src asm("2") = src; + register void *__param asm("1") = param; + register const u8 *__src asm("2") = src; register long __src_len asm("3") = src_len; int ret; asm volatile( "0: .insn rre,0xb93e0000,%1,%1 \n" /* KIMD opcode */ "1: brc 1,0b \n" /* handle partial completion */ - " ahi %0,%h6\n" - "2: ahi %0,%h7\n" - "3:\n" - EX_TABLE(0b,3b) EX_TABLE(1b,2b) + " la %0,0\n" + "2:\n" + EX_TABLE(0b,2b) EX_TABLE(1b,2b) : "=d" (ret), "+a" (__src), "+d" (__src_len) - : "d" (__func), "a" (__param), "0" (-EFAULT), - "K" (ENOSYS), "K" (-ENOSYS + EFAULT) : "cc", "memory"); + : "d" (__func), "a" (__param), "0" (-1) : "cc", "memory"); if (ret < 0) return ret; return (func & CRYPT_S390_FUNC_MASK) ? src_len - __src_len : __src_len; } -/* +/** + * crypt_s390_klmd: + * @func: the function code passed to KM; see crypt_s390_klmd_func + * @param: address of parameter block; see POP for details on each func + * @src: address of source memory area + * @src_len: length of src operand in bytes + * * Executes the KLMD (COMPUTE LAST MESSAGE DIGEST) operation of the CPU. - * @param func: the function code passed to KM; see crypt_s390_klmd_func - * @param param: address of parameter block; see POP for details on each func - * @param src: address of source memory area - * @param src_len: length of src operand in bytes - * @returns < zero for failure, 0 for the query func, number of processed bytes - * for digest funcs + * + * Returns -1 for failure, 0 for the query func, number of processed + * bytes for digest funcs */ -static inline int -crypt_s390_klmd(long func, void* param, const u8* src, long src_len) +static inline int crypt_s390_klmd(long func, void *param, + const u8 *src, long src_len) { register long __func asm("0") = func & CRYPT_S390_FUNC_MASK; - register void* __param asm("1") = param; - register const u8* __src asm("2") = src; + register void *__param asm("1") = param; + register const u8 *__src asm("2") = src; register long __src_len asm("3") = src_len; int ret; asm volatile( "0: .insn rre,0xb93f0000,%1,%1 \n" /* KLMD opcode */ "1: brc 1,0b \n" /* handle partial completion */ - " ahi %0,%h6\n" - "2: ahi %0,%h7\n" - "3:\n" - EX_TABLE(0b,3b) EX_TABLE(1b,2b) + " la %0,0\n" + "2:\n" + EX_TABLE(0b,2b) EX_TABLE(1b,2b) : "=d" (ret), "+a" (__src), "+d" (__src_len) - : "d" (__func), "a" (__param), "0" (-EFAULT), - "K" (ENOSYS), "K" (-ENOSYS + EFAULT) : "cc", "memory"); + : "d" (__func), "a" (__param), "0" (-1) : "cc", "memory"); if (ret < 0) return ret; return (func & CRYPT_S390_FUNC_MASK) ? src_len - __src_len : __src_len; } -/* +/** + * crypt_s390_kmac: + * @func: the function code passed to KM; see crypt_s390_klmd_func + * @param: address of parameter block; see POP for details on each func + * @src: address of source memory area + * @src_len: length of src operand in bytes + * * Executes the KMAC (COMPUTE MESSAGE AUTHENTICATION CODE) operation * of the CPU. - * @param func: the function code passed to KM; see crypt_s390_klmd_func - * @param param: address of parameter block; see POP for details on each func - * @param src: address of source memory area - * @param src_len: length of src operand in bytes - * @returns < zero for failure, 0 for the query func, number of processed bytes - * for digest funcs + * + * Returns -1 for failure, 0 for the query func, number of processed + * bytes for digest funcs */ -static inline int -crypt_s390_kmac(long func, void* param, const u8* src, long src_len) +static inline int crypt_s390_kmac(long func, void *param, + const u8 *src, long src_len) { register long __func asm("0") = func & CRYPT_S390_FUNC_MASK; - register void* __param asm("1") = param; - register const u8* __src asm("2") = src; + register void *__param asm("1") = param; + register const u8 *__src asm("2") = src; register long __src_len asm("3") = src_len; int ret; asm volatile( "0: .insn rre,0xb91e0000,%1,%1 \n" /* KLAC opcode */ "1: brc 1,0b \n" /* handle partial completion */ - " ahi %0,%h6\n" - "2: ahi %0,%h7\n" - "3:\n" - EX_TABLE(0b,3b) EX_TABLE(1b,2b) + " la %0,0\n" + "2:\n" + EX_TABLE(0b,2b) EX_TABLE(1b,2b) : "=d" (ret), "+a" (__src), "+d" (__src_len) - : "d" (__func), "a" (__param), "0" (-EFAULT), - "K" (ENOSYS), "K" (-ENOSYS + EFAULT) : "cc", "memory"); + : "d" (__func), "a" (__param), "0" (-1) : "cc", "memory"); if (ret < 0) return ret; return (func & CRYPT_S390_FUNC_MASK) ? src_len - __src_len : __src_len; } /** + * crypt_s390_func_available: + * @func: the function code of the specific function; 0 if op in general + * * Tests if a specific crypto function is implemented on the machine. - * @param func: the function code of the specific function; 0 if op in general - * @return 1 if func available; 0 if func or op in general not available + * + * Returns 1 if func available; 0 if func or op in general not available */ -static inline int -crypt_s390_func_available(int func) +static inline int crypt_s390_func_available(int func) { + unsigned char status[16]; int ret; - struct crypt_s390_query_status status = { - .high = 0, - .low = 0 - }; - switch (func & CRYPT_S390_OP_MASK){ - case CRYPT_S390_KM: - ret = crypt_s390_km(KM_QUERY, &status, NULL, NULL, 0); - break; - case CRYPT_S390_KMC: - ret = crypt_s390_kmc(KMC_QUERY, &status, NULL, NULL, 0); - break; - case CRYPT_S390_KIMD: - ret = crypt_s390_kimd(KIMD_QUERY, &status, NULL, 0); - break; - case CRYPT_S390_KLMD: - ret = crypt_s390_klmd(KLMD_QUERY, &status, NULL, 0); - break; - case CRYPT_S390_KMAC: - ret = crypt_s390_kmac(KMAC_QUERY, &status, NULL, 0); - break; - default: - ret = 0; - return ret; - } - if (ret >= 0){ - func &= CRYPT_S390_FUNC_MASK; - func &= 0x7f; //mask modifier bit - if (func < 64){ - ret = (status.high >> (64 - func - 1)) & 0x1; - } else { - ret = (status.low >> (128 - func - 1)) & 0x1; - } - } else { - ret = 0; + switch (func & CRYPT_S390_OP_MASK) { + case CRYPT_S390_KM: + ret = crypt_s390_km(KM_QUERY, &status, NULL, NULL, 0); + break; + case CRYPT_S390_KMC: + ret = crypt_s390_kmc(KMC_QUERY, &status, NULL, NULL, 0); + break; + case CRYPT_S390_KIMD: + ret = crypt_s390_kimd(KIMD_QUERY, &status, NULL, 0); + break; + case CRYPT_S390_KLMD: + ret = crypt_s390_klmd(KLMD_QUERY, &status, NULL, 0); + break; + case CRYPT_S390_KMAC: + ret = crypt_s390_kmac(KMAC_QUERY, &status, NULL, 0); + break; + default: + return 0; } - return ret; + if (ret < 0) + return 0; + func &= CRYPT_S390_FUNC_MASK; + func &= 0x7f; /* mask modifier bit */ + return (status[func >> 3] & (0x80 >> (func & 7))) != 0; } -#endif // _CRYPTO_ARCH_S390_CRYPT_S390_H +#endif /* _CRYPTO_ARCH_S390_CRYPT_S390_H */ diff --git a/arch/s390/crypto/crypt_s390_query.c b/arch/s390/crypto/crypt_s390_query.c deleted file mode 100644 index 54fb11d..0000000 --- a/arch/s390/crypto/crypt_s390_query.c +++ /dev/null @@ -1,129 +0,0 @@ -/* - * Cryptographic API. - * - * Support for s390 cryptographic instructions. - * Testing module for querying processor crypto capabilities. - * - * Copyright (c) 2003 IBM Deutschland Entwicklung GmbH, IBM Corporation - * Author(s): Thomas Spatzier (tspat@de.ibm.com) - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the Free - * Software Foundation; either version 2 of the License, or (at your option) - * any later version. - * - */ -#include -#include -#include -#include -#include "crypt_s390.h" - -static void query_available_functions(void) -{ - printk(KERN_INFO "#####################\n"); - - /* query available KM functions */ - printk(KERN_INFO "KM_QUERY: %d\n", - crypt_s390_func_available(KM_QUERY)); - printk(KERN_INFO "KM_DEA: %d\n", - crypt_s390_func_available(KM_DEA_ENCRYPT)); - printk(KERN_INFO "KM_TDEA_128: %d\n", - crypt_s390_func_available(KM_TDEA_128_ENCRYPT)); - printk(KERN_INFO "KM_TDEA_192: %d\n", - crypt_s390_func_available(KM_TDEA_192_ENCRYPT)); - printk(KERN_INFO "KM_AES_128: %d\n", - crypt_s390_func_available(KM_AES_128_ENCRYPT)); - printk(KERN_INFO "KM_AES_192: %d\n", - crypt_s390_func_available(KM_AES_192_ENCRYPT)); - printk(KERN_INFO "KM_AES_256: %d\n", - crypt_s390_func_available(KM_AES_256_ENCRYPT)); - - /* query available KMC functions */ - printk(KERN_INFO "KMC_QUERY: %d\n", - crypt_s390_func_available(KMC_QUERY)); - printk(KERN_INFO "KMC_DEA: %d\n", - crypt_s390_func_available(KMC_DEA_ENCRYPT)); - printk(KERN_INFO "KMC_TDEA_128: %d\n", - crypt_s390_func_available(KMC_TDEA_128_ENCRYPT)); - printk(KERN_INFO "KMC_TDEA_192: %d\n", - crypt_s390_func_available(KMC_TDEA_192_ENCRYPT)); - printk(KERN_INFO "KMC_AES_128: %d\n", - crypt_s390_func_available(KMC_AES_128_ENCRYPT)); - printk(KERN_INFO "KMC_AES_192: %d\n", - crypt_s390_func_available(KMC_AES_192_ENCRYPT)); - printk(KERN_INFO "KMC_AES_256: %d\n", - crypt_s390_func_available(KMC_AES_256_ENCRYPT)); - - /* query available KIMD functions */ - printk(KERN_INFO "KIMD_QUERY: %d\n", - crypt_s390_func_available(KIMD_QUERY)); - printk(KERN_INFO "KIMD_SHA_1: %d\n", - crypt_s390_func_available(KIMD_SHA_1)); - printk(KERN_INFO "KIMD_SHA_256: %d\n", - crypt_s390_func_available(KIMD_SHA_256)); - - /* query available KLMD functions */ - printk(KERN_INFO "KLMD_QUERY: %d\n", - crypt_s390_func_available(KLMD_QUERY)); - printk(KERN_INFO "KLMD_SHA_1: %d\n", - crypt_s390_func_available(KLMD_SHA_1)); - printk(KERN_INFO "KLMD_SHA_256: %d\n", - crypt_s390_func_available(KLMD_SHA_256)); - - /* query available KMAC functions */ - printk(KERN_INFO "KMAC_QUERY: %d\n", - crypt_s390_func_available(KMAC_QUERY)); - printk(KERN_INFO "KMAC_DEA: %d\n", - crypt_s390_func_available(KMAC_DEA)); - printk(KERN_INFO "KMAC_TDEA_128: %d\n", - crypt_s390_func_available(KMAC_TDEA_128)); - printk(KERN_INFO "KMAC_TDEA_192: %d\n", - crypt_s390_func_available(KMAC_TDEA_192)); -} - -static int init(void) -{ - struct crypt_s390_query_status status = { - .high = 0, - .low = 0 - }; - - printk(KERN_INFO "crypt_s390: querying available crypto functions\n"); - crypt_s390_km(KM_QUERY, &status, NULL, NULL, 0); - printk(KERN_INFO "KM:\t%016llx %016llx\n", - (unsigned long long) status.high, - (unsigned long long) status.low); - status.high = status.low = 0; - crypt_s390_kmc(KMC_QUERY, &status, NULL, NULL, 0); - printk(KERN_INFO "KMC:\t%016llx %016llx\n", - (unsigned long long) status.high, - (unsigned long long) status.low); - status.high = status.low = 0; - crypt_s390_kimd(KIMD_QUERY, &status, NULL, 0); - printk(KERN_INFO "KIMD:\t%016llx %016llx\n", - (unsigned long long) status.high, - (unsigned long long) status.low); - status.high = status.low = 0; - crypt_s390_klmd(KLMD_QUERY, &status, NULL, 0); - printk(KERN_INFO "KLMD:\t%016llx %016llx\n", - (unsigned long long) status.high, - (unsigned long long) status.low); - status.high = status.low = 0; - crypt_s390_kmac(KMAC_QUERY, &status, NULL, 0); - printk(KERN_INFO "KMAC:\t%016llx %016llx\n", - (unsigned long long) status.high, - (unsigned long long) status.low); - - query_available_functions(); - return -ECANCELED; -} - -static void __exit cleanup(void) -{ -} - -module_init(init); -module_exit(cleanup); - -MODULE_LICENSE("GPL"); diff --git a/arch/s390/crypto/des_check_key.c b/arch/s390/crypto/des_check_key.c index e3f5c5f..5706af2 100644 --- a/arch/s390/crypto/des_check_key.c +++ b/arch/s390/crypto/des_check_key.c @@ -10,8 +10,9 @@ * scatterlist interface. Changed LGPL to GPL per section 3 of the LGPL. * * s390 Version: - * Copyright (C) 2003 IBM Deutschland GmbH, IBM Corporation - * Author(s): Thomas Spatzier (tspat@de.ibm.com) + * Copyright IBM Corp. 2003 + * Author(s): Thomas Spatzier + * Jan Glauber (jan.glauber@de.ibm.com) * * Derived from "crypto/des.c" * Copyright (c) 1992 Dana L. How. @@ -30,6 +31,7 @@ #include #include #include #include +#include "crypto_des.h" #define ROR(d,c,o) ((d) = (d) >> (c) | (d) << (o)) diff --git a/arch/s390/crypto/des_s390.c b/arch/s390/crypto/des_s390.c index 2aba048..ea22707 100644 --- a/arch/s390/crypto/des_s390.c +++ b/arch/s390/crypto/des_s390.c @@ -3,9 +3,9 @@ * * s390 implementation of the DES Cipher Algorithm. * - * Copyright (c) 2003 IBM Deutschland Entwicklung GmbH, IBM Corporation - * Author(s): Thomas Spatzier (tspat@de.ibm.com) - * + * Copyright IBM Corp. 2003,2007 + * Author(s): Thomas Spatzier + * Jan Glauber (jan.glauber@de.ibm.com) * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -557,7 +557,7 @@ static int init(void) if (!crypt_s390_func_available(KM_DEA_ENCRYPT) || !crypt_s390_func_available(KM_TDEA_128_ENCRYPT) || !crypt_s390_func_available(KM_TDEA_192_ENCRYPT)) - return -ENOSYS; + return -EOPNOTSUPP; ret = crypto_register_alg(&des_alg); if (ret) diff --git a/arch/s390/crypto/prng.c b/arch/s390/crypto/prng.c new file mode 100644 index 0000000..8eb3a1a --- /dev/null +++ b/arch/s390/crypto/prng.c @@ -0,0 +1,213 @@ +/* + * Copyright IBM Corp. 2006,2007 + * Author(s): Jan Glauber + * Driver for the s390 pseudo random number generator + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "crypt_s390.h" + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Jan Glauber "); +MODULE_DESCRIPTION("s390 PRNG interface"); + +static int prng_chunk_size = 256; +module_param(prng_chunk_size, int, S_IRUSR | S_IRGRP | S_IROTH); +MODULE_PARM_DESC(prng_chunk_size, "PRNG read chunk size in bytes"); + +static int prng_entropy_limit = 4096; +module_param(prng_entropy_limit, int, S_IRUSR | S_IRGRP | S_IROTH | S_IWUSR); +MODULE_PARM_DESC(prng_entropy_limit, + "PRNG add entropy after that much bytes were produced"); + +/* + * Any one who considers arithmetical methods of producing random digits is, + * of course, in a state of sin. -- John von Neumann + */ + +struct s390_prng_data { + unsigned long count; /* how many bytes were produced */ + char *buf; +}; + +static struct s390_prng_data *p; + +/* copied from libica, use a non-zero initial parameter block */ +static unsigned char parm_block[32] = { +0x0F,0x2B,0x8E,0x63,0x8C,0x8E,0xD2,0x52,0x64,0xB7,0xA0,0x7B,0x75,0x28,0xB8,0xF4, +0x75,0x5F,0xD2,0xA6,0x8D,0x97,0x11,0xFF,0x49,0xD8,0x23,0xF3,0x7E,0x21,0xEC,0xA0, +}; + +static int prng_open(struct inode *inode, struct file *file) +{ + return nonseekable_open(inode, file); +} + +static void prng_add_entropy(void) +{ + __u64 entropy[4]; + unsigned int i; + int ret; + + for (i = 0; i < 16; i++) { + ret = crypt_s390_kmc(KMC_PRNG, parm_block, (char *)entropy, + (char *)entropy, sizeof(entropy)); + BUG_ON(ret < 0 || ret != sizeof(entropy)); + memcpy(parm_block, entropy, sizeof(entropy)); + } +} + +static void prng_seed(int nbytes) +{ + char buf[16]; + int i = 0; + + BUG_ON(nbytes > 16); + get_random_bytes(buf, nbytes); + + /* Add the entropy */ + while (nbytes >= 8) { + *((__u64 *)parm_block) ^= *((__u64 *)buf+i*8); + prng_add_entropy(); + i += 8; + nbytes -= 8; + } + prng_add_entropy(); +} + +static ssize_t prng_read(struct file *file, char __user *ubuf, size_t nbytes, + loff_t *ppos) +{ + int chunk, n; + int ret = 0; + int tmp; + + /* nbytes can be arbitrary long, we spilt it into chunks */ + while (nbytes) { + /* same as in extract_entropy_user in random.c */ + if (need_resched()) { + if (signal_pending(current)) { + if (ret == 0) + ret = -ERESTARTSYS; + break; + } + schedule(); + } + + /* + * we lose some random bytes if an attacker issues + * reads < 8 bytes, but we don't care + */ + chunk = min_t(int, nbytes, prng_chunk_size); + + /* PRNG only likes multiples of 8 bytes */ + n = (chunk + 7) & -8; + + if (p->count > prng_entropy_limit) + prng_seed(8); + + /* if the CPU supports PRNG stckf is present too */ + asm volatile(".insn s,0xb27c0000,%0" + : "=m" (*((unsigned long long *)p->buf)) : : "cc"); + + /* + * Beside the STCKF the input for the TDES-EDE is the output + * of the last operation. We differ here from X9.17 since we + * only store one timestamp into the buffer. Padding the whole + * buffer with timestamps does not improve security, since + * successive stckf have nearly constant offsets. + * If an attacker knows the first timestamp it would be + * trivial to guess the additional values. One timestamp + * is therefore enough and still guarantees unique input values. + * + * Note: you can still get strict X9.17 conformity by setting + * prng_chunk_size to 8 bytes. + */ + tmp = crypt_s390_kmc(KMC_PRNG, parm_block, p->buf, p->buf, n); + BUG_ON((tmp < 0) || (tmp != n)); + + p->count += n; + + if (copy_to_user(ubuf, p->buf, chunk)) + return -EFAULT; + + nbytes -= chunk; + ret += chunk; + ubuf += chunk; + } + return ret; +} + +static struct file_operations prng_fops = { + .owner = THIS_MODULE, + .open = &prng_open, + .release = NULL, + .read = &prng_read, +}; + +static struct miscdevice prng_dev = { + .name = "prandom", + .minor = MISC_DYNAMIC_MINOR, + .fops = &prng_fops, +}; + +static int __init prng_init(void) +{ + int ret; + + /* check if the CPU has a PRNG */ + if (!crypt_s390_func_available(KMC_PRNG)) + return -EOPNOTSUPP; + + if (prng_chunk_size < 8) + return -EINVAL; + + p = kmalloc(sizeof(struct s390_prng_data), GFP_KERNEL); + if (!p) + return -ENOMEM; + p->count = 0; + + p->buf = kmalloc(prng_chunk_size, GFP_KERNEL); + if (!p->buf) { + ret = -ENOMEM; + goto out_free; + } + + /* initialize the PRNG, add 128 bits of entropy */ + prng_seed(16); + + ret = misc_register(&prng_dev); + if (ret) { + printk(KERN_WARNING + "Could not register misc device for PRNG.\n"); + goto out_buf; + } + return 0; + +out_buf: + kfree(p->buf); +out_free: + kfree(p); + return ret; +} + +static void __exit prng_exit(void) +{ + /* wipe me */ + memset(p->buf, 0, prng_chunk_size); + kfree(p->buf); + kfree(p); + + misc_deregister(&prng_dev); +} + +module_init(prng_init); +module_exit(prng_exit); diff --git a/arch/s390/crypto/sha1_s390.c b/arch/s390/crypto/sha1_s390.c index 49ca869..969639f 100644 --- a/arch/s390/crypto/sha1_s390.c +++ b/arch/s390/crypto/sha1_s390.c @@ -8,8 +8,9 @@ * implementation written by Steve Reid. * * s390 Version: - * Copyright (C) 2003 IBM Deutschland GmbH, IBM Corporation - * Author(s): Thomas Spatzier (tspat@de.ibm.com) + * Copyright IBM Corp. 2003,2007 + * Author(s): Thomas Spatzier + * Jan Glauber (jan.glauber@de.ibm.com) * * Derived from "crypto/sha1.c" * Copyright (c) Alan Smithee. @@ -43,16 +44,14 @@ struct crypt_s390_sha1_ctx { static void sha1_init(struct crypto_tfm *tfm) { struct crypt_s390_sha1_ctx *ctx = crypto_tfm_ctx(tfm); - static const u32 initstate[5] = { - 0x67452301, - 0xEFCDAB89, - 0x98BADCFE, - 0x10325476, - 0xC3D2E1F0 - }; + + ctx->state[0] = 0x67452301; + ctx->state[1] = 0xEFCDAB89; + ctx->state[2] = 0x98BADCFE; + ctx->state[3] = 0x10325476; + ctx->state[4] = 0xC3D2E1F0; ctx->count = 0; - memcpy(ctx->state, &initstate, sizeof(initstate)); ctx->buf_len = 0; } @@ -63,13 +62,13 @@ static void sha1_update(struct crypto_tf long imd_len; sctx = crypto_tfm_ctx(tfm); - sctx->count += len * 8; //message bit length + sctx->count += len * 8; /* message bit length */ - //anything in buffer yet? -> must be completed + /* anything in buffer yet? -> must be completed */ if (sctx->buf_len && (sctx->buf_len + len) >= SHA1_BLOCK_SIZE) { - //complete full block and hash + /* complete full block and hash */ memcpy(sctx->buffer + sctx->buf_len, data, - SHA1_BLOCK_SIZE - sctx->buf_len); + SHA1_BLOCK_SIZE - sctx->buf_len); crypt_s390_kimd(KIMD_SHA_1, sctx->state, sctx->buffer, SHA1_BLOCK_SIZE); data += SHA1_BLOCK_SIZE - sctx->buf_len; @@ -77,37 +76,36 @@ static void sha1_update(struct crypto_tf sctx->buf_len = 0; } - //rest of data contains full blocks? + /* rest of data contains full blocks? */ imd_len = len & ~0x3ful; - if (imd_len){ + if (imd_len) { crypt_s390_kimd(KIMD_SHA_1, sctx->state, data, imd_len); data += imd_len; len -= imd_len; } - //anything left? store in buffer - if (len){ + /* anything left? store in buffer */ + if (len) { memcpy(sctx->buffer + sctx->buf_len , data, len); sctx->buf_len += len; } } -static void -pad_message(struct crypt_s390_sha1_ctx* sctx) +static void pad_message(struct crypt_s390_sha1_ctx* sctx) { int index; index = sctx->buf_len; - sctx->buf_len = (sctx->buf_len < 56)? - SHA1_BLOCK_SIZE:2 * SHA1_BLOCK_SIZE; - //start pad with 1 + sctx->buf_len = (sctx->buf_len < 56) ? + SHA1_BLOCK_SIZE:2 * SHA1_BLOCK_SIZE; + /* start pad with 1 */ sctx->buffer[index] = 0x80; - //pad with zeros + /* pad with zeros */ index++; memset(sctx->buffer + index, 0x00, sctx->buf_len - index); - //append length + /* append length */ memcpy(sctx->buffer + sctx->buf_len - 8, &sctx->count, - sizeof sctx->count); + sizeof sctx->count); } /* Add padding and return the message digest. */ @@ -115,47 +113,40 @@ static void sha1_final(struct crypto_tfm { struct crypt_s390_sha1_ctx *sctx = crypto_tfm_ctx(tfm); - //must perform manual padding + /* must perform manual padding */ pad_message(sctx); crypt_s390_kimd(KIMD_SHA_1, sctx->state, sctx->buffer, sctx->buf_len); - //copy digest to out + /* copy digest to out */ memcpy(out, sctx->state, SHA1_DIGEST_SIZE); - /* Wipe context */ + /* wipe context */ memset(sctx, 0, sizeof *sctx); } static struct crypto_alg alg = { .cra_name = "sha1", - .cra_driver_name = "sha1-s390", + .cra_driver_name= "sha1-s390", .cra_priority = CRYPT_S390_PRIORITY, .cra_flags = CRYPTO_ALG_TYPE_DIGEST, .cra_blocksize = SHA1_BLOCK_SIZE, .cra_ctxsize = sizeof(struct crypt_s390_sha1_ctx), .cra_module = THIS_MODULE, - .cra_list = LIST_HEAD_INIT(alg.cra_list), + .cra_list = LIST_HEAD_INIT(alg.cra_list), .cra_u = { .digest = { .dia_digestsize = SHA1_DIGEST_SIZE, - .dia_init = sha1_init, - .dia_update = sha1_update, - .dia_final = sha1_final } } + .dia_init = sha1_init, + .dia_update = sha1_update, + .dia_final = sha1_final } } }; -static int -init(void) +static int __init init(void) { - int ret = -ENOSYS; + if (!crypt_s390_func_available(KIMD_SHA_1)) + return -EOPNOTSUPP; - if (crypt_s390_func_available(KIMD_SHA_1)){ - ret = crypto_register_alg(&alg); - if (ret == 0){ - printk(KERN_INFO "crypt_s390: sha1_s390 loaded.\n"); - } - } - return ret; + return crypto_register_alg(&alg); } -static void __exit -fini(void) +static void __exit fini(void) { crypto_unregister_alg(&alg); } diff --git a/arch/s390/crypto/sha256_s390.c b/arch/s390/crypto/sha256_s390.c index 8e4e675..78436c6 100644 --- a/arch/s390/crypto/sha256_s390.c +++ b/arch/s390/crypto/sha256_s390.c @@ -4,7 +4,7 @@ * s390 implementation of the SHA256 Secure Hash Algorithm. * * s390 Version: - * Copyright (C) 2005 IBM Deutschland GmbH, IBM Corporation + * Copyright IBM Corp. 2005,2007 * Author(s): Jan Glauber (jang@de.ibm.com) * * Derived from "crypto/sha256.c" @@ -143,15 +143,10 @@ static struct crypto_alg alg = { static int init(void) { - int ret; - if (!crypt_s390_func_available(KIMD_SHA_256)) - return -ENOSYS; + return -EOPNOTSUPP; - ret = crypto_register_alg(&alg); - if (ret != 0) - printk(KERN_INFO "crypt_s390: sha256_s390 couldn't be loaded."); - return ret; + return crypto_register_alg(&alg); } static void __exit fini(void) diff --git a/arch/s390/defconfig b/arch/s390/defconfig index 5368cf4..1406400 100644 --- a/arch/s390/defconfig +++ b/arch/s390/defconfig @@ -108,6 +108,8 @@ CONFIG_DEFAULT_MIGRATION_COST=1000000 CONFIG_COMPAT=y CONFIG_SYSVIPC_COMPAT=y CONFIG_AUDIT_ARCH=y +CONFIG_S390_SWITCH_AMODE=y +CONFIG_S390_EXEC_PROTECT=y # # Code generation options @@ -177,6 +179,8 @@ CONFIG_XFRM=y # CONFIG_XFRM_USER is not set # CONFIG_XFRM_SUB_POLICY is not set CONFIG_NET_KEY=y +CONFIG_IUCV=m +CONFIG_AFIUCV=m CONFIG_INET=y CONFIG_IP_MULTICAST=y # CONFIG_IP_ADVANCED_ROUTER is not set @@ -431,7 +435,6 @@ CONFIG_TN3270_CONSOLE=y CONFIG_TN3215=y CONFIG_TN3215_CONSOLE=y CONFIG_CCW_CONSOLE=y -CONFIG_SCLP=y CONFIG_SCLP_TTY=y CONFIG_SCLP_CONSOLE=y CONFIG_SCLP_VT220_TTY=y @@ -507,7 +510,6 @@ # S/390 network device drivers # CONFIG_LCS=m CONFIG_CTC=m -CONFIG_IUCV=m # CONFIG_NETIUCV is not set # CONFIG_SMSGIUCV is not set # CONFIG_CLAW is not set @@ -724,9 +726,7 @@ # CONFIG_CRYPTO_NULL is not set # CONFIG_CRYPTO_MD4 is not set # CONFIG_CRYPTO_MD5 is not set # CONFIG_CRYPTO_SHA1 is not set -# CONFIG_CRYPTO_SHA1_S390 is not set # CONFIG_CRYPTO_SHA256 is not set -# CONFIG_CRYPTO_SHA256_S390 is not set # CONFIG_CRYPTO_SHA512 is not set # CONFIG_CRYPTO_WP512 is not set # CONFIG_CRYPTO_TGR192 is not set @@ -735,12 +735,10 @@ CONFIG_CRYPTO_ECB=m CONFIG_CRYPTO_CBC=y # CONFIG_CRYPTO_LRW is not set # CONFIG_CRYPTO_DES is not set -# CONFIG_CRYPTO_DES_S390 is not set # CONFIG_CRYPTO_BLOWFISH is not set # CONFIG_CRYPTO_TWOFISH is not set # CONFIG_CRYPTO_SERPENT is not set # CONFIG_CRYPTO_AES is not set -# CONFIG_CRYPTO_AES_S390 is not set # CONFIG_CRYPTO_CAST5 is not set # CONFIG_CRYPTO_CAST6 is not set # CONFIG_CRYPTO_TEA is not set @@ -755,6 +753,11 @@ # CONFIG_CRYPTO_TEST is not set # # Hardware crypto devices # +# CONFIG_CRYPTO_SHA1_S390 is not set +# CONFIG_CRYPTO_SHA256_S390 is not set +# CONFIG_CRYPTO_DES_S390 is not set +# CONFIG_CRYPTO_AES_S390 is not set +CONFIG_S390_PRNG=m # # Library routines diff --git a/arch/s390/hypfs/Makefile b/arch/s390/hypfs/Makefile index f4b00cd..b08d2ab 100644 --- a/arch/s390/hypfs/Makefile +++ b/arch/s390/hypfs/Makefile @@ -4,4 +4,4 @@ # obj-$(CONFIG_S390_HYPFS_FS) += s390_hypfs.o -s390_hypfs-objs := inode.o hypfs_diag.o +s390_hypfs-objs := inode.o hypfs_diag.o hypfs_vm.o diff --git a/arch/s390/hypfs/hypfs.h b/arch/s390/hypfs/hypfs.h index f3dbd91..aea5720 100644 --- a/arch/s390/hypfs/hypfs.h +++ b/arch/s390/hypfs/hypfs.h @@ -27,4 +27,13 @@ extern struct dentry *hypfs_create_str(s struct dentry *dir, const char *name, char *string); +/* LPAR Hypervisor */ +extern int hypfs_diag_init(void); +extern void hypfs_diag_exit(void); +extern int hypfs_diag_create_files(struct super_block *sb, struct dentry *root); + +/* VM Hypervisor */ +extern int hypfs_vm_init(void); +extern int hypfs_vm_create_files(struct super_block *sb, struct dentry *root); + #endif /* _HYPFS_H_ */ diff --git a/arch/s390/hypfs/hypfs_diag.h b/arch/s390/hypfs/hypfs_diag.h deleted file mode 100644 index 256b384..0000000 --- a/arch/s390/hypfs/hypfs_diag.h +++ /dev/null @@ -1,16 +0,0 @@ -/* - * arch/s390/hypfs_diag.h - * Hypervisor filesystem for Linux on s390. - * - * Copyright (C) IBM Corp. 2006 - * Author(s): Michael Holzheu - */ - -#ifndef _HYPFS_DIAG_H_ -#define _HYPFS_DIAG_H_ - -extern int hypfs_diag_init(void); -extern void hypfs_diag_exit(void); -extern int hypfs_diag_create_files(struct super_block *sb, struct dentry *root); - -#endif /* _HYPFS_DIAG_H_ */ diff --git a/arch/s390/hypfs/hypfs_vm.c b/arch/s390/hypfs/hypfs_vm.c new file mode 100644 index 0000000..d01fc8f --- /dev/null +++ b/arch/s390/hypfs/hypfs_vm.c @@ -0,0 +1,231 @@ +/* + * Hypervisor filesystem for Linux on s390. z/VM implementation. + * + * Copyright (C) IBM Corp. 2006 + * Author(s): Michael Holzheu + */ + +#include +#include +#include +#include +#include +#include "hypfs.h" + +#define NAME_LEN 8 + +static char local_guest[] = " "; +static char all_guests[] = "* "; +static char *guest_query; + +struct diag2fc_data { + __u32 version; + __u32 flags; + __u64 used_cpu; + __u64 el_time; + __u64 mem_min_kb; + __u64 mem_max_kb; + __u64 mem_share_kb; + __u64 mem_used_kb; + __u32 pcpus; + __u32 lcpus; + __u32 vcpus; + __u32 cpu_min; + __u32 cpu_max; + __u32 cpu_shares; + __u32 cpu_use_samp; + __u32 cpu_delay_samp; + __u32 page_wait_samp; + __u32 idle_samp; + __u32 other_samp; + __u32 total_samp; + char guest_name[NAME_LEN]; +}; + +struct diag2fc_parm_list { + char userid[NAME_LEN]; + char aci_grp[NAME_LEN]; + __u64 addr; + __u32 size; + __u32 fmt; +}; + +static int diag2fc(int size, char* query, void *addr) +{ + unsigned long residual_cnt; + unsigned long rc; + struct diag2fc_parm_list parm_list; + + memcpy(parm_list.userid, query, NAME_LEN); + ASCEBC(parm_list.userid, NAME_LEN); + parm_list.addr = (unsigned long) addr ; + parm_list.size = size; + parm_list.fmt = 0x02; + memset(parm_list.aci_grp, 0x40, NAME_LEN); + rc = -1; + + asm volatile( + " diag %0,%1,0x2fc\n" + "0:\n" + EX_TABLE(0b,0b) + : "=d" (residual_cnt), "+d" (rc) : "0" (&parm_list) : "memory"); + + if ((rc != 0 ) && (rc != -2)) + return rc; + else + return -residual_cnt; +} + +static struct diag2fc_data *diag2fc_store(char *query, int *count) +{ + int size; + struct diag2fc_data *data; + + do { + size = diag2fc(0, query, NULL); + if (size < 0) + return ERR_PTR(-EACCES); + data = vmalloc(size); + if (!data) + return ERR_PTR(-ENOMEM); + if (diag2fc(size, query, data) == 0) + break; + vfree(data); + } while (1); + *count = (size / sizeof(*data)); + + return data; +} + +static void diag2fc_free(void *data) +{ + vfree(data); +} + +#define ATTRIBUTE(sb, dir, name, member) \ +do { \ + void *rc; \ + rc = hypfs_create_u64(sb, dir, name, member); \ + if (IS_ERR(rc)) \ + return PTR_ERR(rc); \ +} while(0) + +static int hpyfs_vm_create_guest(struct super_block *sb, + struct dentry *systems_dir, + struct diag2fc_data *data) +{ + char guest_name[NAME_LEN + 1] = {}; + struct dentry *guest_dir, *cpus_dir, *samples_dir, *mem_dir; + int dedicated_flag, capped_value; + + capped_value = (data->flags & 0x00000006) >> 1; + dedicated_flag = (data->flags & 0x00000008) >> 3; + + /* guest dir */ + memcpy(guest_name, data->guest_name, NAME_LEN); + EBCASC(guest_name, NAME_LEN); + strstrip(guest_name); + guest_dir = hypfs_mkdir(sb, systems_dir, guest_name); + if (IS_ERR(guest_dir)) + return PTR_ERR(guest_dir); + ATTRIBUTE(sb, guest_dir, "onlinetime_us", data->el_time); + + /* logical cpu information */ + cpus_dir = hypfs_mkdir(sb, guest_dir, "cpus"); + if (IS_ERR(cpus_dir)) + return PTR_ERR(cpus_dir); + ATTRIBUTE(sb, cpus_dir, "cputime_us", data->used_cpu); + ATTRIBUTE(sb, cpus_dir, "capped", capped_value); + ATTRIBUTE(sb, cpus_dir, "dedicated", dedicated_flag); + ATTRIBUTE(sb, cpus_dir, "count", data->vcpus); + ATTRIBUTE(sb, cpus_dir, "weight_min", data->cpu_min); + ATTRIBUTE(sb, cpus_dir, "weight_max", data->cpu_max); + ATTRIBUTE(sb, cpus_dir, "weight_cur", data->cpu_shares); + + /* memory information */ + mem_dir = hypfs_mkdir(sb, guest_dir, "mem"); + if (IS_ERR(mem_dir)) + return PTR_ERR(mem_dir); + ATTRIBUTE(sb, mem_dir, "min_KiB", data->mem_min_kb); + ATTRIBUTE(sb, mem_dir, "max_KiB", data->mem_max_kb); + ATTRIBUTE(sb, mem_dir, "used_KiB", data->mem_used_kb); + ATTRIBUTE(sb, mem_dir, "share_KiB", data->mem_share_kb); + + /* samples */ + samples_dir = hypfs_mkdir(sb, guest_dir, "samples"); + if (IS_ERR(samples_dir)) + return PTR_ERR(samples_dir); + ATTRIBUTE(sb, samples_dir, "cpu_using", data->cpu_use_samp); + ATTRIBUTE(sb, samples_dir, "cpu_delay", data->cpu_delay_samp); + ATTRIBUTE(sb, samples_dir, "mem_delay", data->page_wait_samp); + ATTRIBUTE(sb, samples_dir, "idle", data->idle_samp); + ATTRIBUTE(sb, samples_dir, "other", data->other_samp); + ATTRIBUTE(sb, samples_dir, "total", data->total_samp); + return 0; +} + +int hypfs_vm_create_files(struct super_block *sb, struct dentry *root) +{ + struct dentry *dir, *file; + struct diag2fc_data *data; + int rc, i, count = 0; + + data = diag2fc_store(guest_query, &count); + if (IS_ERR(data)) + return PTR_ERR(data); + + /* Hpervisor Info */ + dir = hypfs_mkdir(sb, root, "hyp"); + if (IS_ERR(dir)) { + rc = PTR_ERR(dir); + goto failed; + } + file = hypfs_create_str(sb, dir, "type", "z/VM Hypervisor"); + if (IS_ERR(file)) { + rc = PTR_ERR(file); + goto failed; + } + + /* physical cpus */ + dir = hypfs_mkdir(sb, root, "cpus"); + if (IS_ERR(dir)) { + rc = PTR_ERR(dir); + goto failed; + } + file = hypfs_create_u64(sb, dir, "count", data->lcpus); + if (IS_ERR(file)) { + rc = PTR_ERR(file); + goto failed; + } + + /* guests */ + dir = hypfs_mkdir(sb, root, "systems"); + if (IS_ERR(dir)) { + rc = PTR_ERR(dir); + goto failed; + } + + for (i = 0; i < count; i++) { + rc = hpyfs_vm_create_guest(sb, dir, &(data[i])); + if (rc) + goto failed; + } + diag2fc_free(data); + return 0; + +failed: + diag2fc_free(data); + return rc; +} + +int hypfs_vm_init(void) +{ + if (diag2fc(0, all_guests, NULL) > 0) + guest_query = all_guests; + else if (diag2fc(0, local_guest, NULL) > 0) + guest_query = local_guest; + else + return -EACCES; + + return 0; +} diff --git a/arch/s390/hypfs/inode.c b/arch/s390/hypfs/inode.c index b6716c4..ba5d316 100644 --- a/arch/s390/hypfs/inode.c +++ b/arch/s390/hypfs/inode.c @@ -19,7 +19,6 @@ #include #include #include #include "hypfs.h" -#include "hypfs_diag.h" #define HYPFS_MAGIC 0x687970 /* ASCII 'hyp' */ #define TMP_SIZE 64 /* size of temporary buffers */ @@ -35,7 +34,7 @@ struct hypfs_sb_info { struct mutex lock; /* lock to protect update process */ }; -static struct file_operations hypfs_file_ops; +static const struct file_operations hypfs_file_ops; static struct file_system_type hypfs_type; static struct super_operations hypfs_s_ops; @@ -192,7 +191,10 @@ static ssize_t hypfs_aio_write(struct ki goto out; } hypfs_delete_tree(sb->s_root); - rc = hypfs_diag_create_files(sb, sb->s_root); + if (MACHINE_IS_VM) + rc = hypfs_vm_create_files(sb, sb->s_root); + else + rc = hypfs_diag_create_files(sb, sb->s_root); if (rc) { printk(KERN_ERR "hypfs: Update failed\n"); hypfs_delete_tree(sb->s_root); @@ -289,7 +291,10 @@ static int hypfs_fill_super(struct super rc = -ENOMEM; goto err_alloc; } - rc = hypfs_diag_create_files(sb, root_dentry); + if (MACHINE_IS_VM) + rc = hypfs_vm_create_files(sb, root_dentry); + else + rc = hypfs_diag_create_files(sb, root_dentry); if (rc) goto err_tree; sbi->update_file = hypfs_create_update_file(sb, root_dentry); @@ -435,7 +440,7 @@ struct dentry *hypfs_create_str(struct s return dentry; } -static struct file_operations hypfs_file_ops = { +static const struct file_operations hypfs_file_ops = { .open = hypfs_open, .release = hypfs_release, .read = do_sync_read, @@ -462,11 +467,15 @@ static int __init hypfs_init(void) { int rc; - if (MACHINE_IS_VM) - return -ENODATA; - if (hypfs_diag_init()) { - rc = -ENODATA; - goto fail_diag; + if (MACHINE_IS_VM) { + if (hypfs_vm_init()) + /* no diag 2fc, just exit */ + return -ENODATA; + } else { + if (hypfs_diag_init()) { + rc = -ENODATA; + goto fail_diag; + } } kset_set_kset_s(&s390_subsys, hypervisor_subsys); rc = subsystem_register(&s390_subsys); @@ -480,7 +489,8 @@ static int __init hypfs_init(void) fail_filesystem: subsystem_unregister(&s390_subsys); fail_sysfs: - hypfs_diag_exit(); + if (!MACHINE_IS_VM) + hypfs_diag_exit(); fail_diag: printk(KERN_ERR "hypfs: Initialization failed with rc = %i.\n", rc); return rc; @@ -488,7 +498,8 @@ fail_diag: static void __exit hypfs_exit(void) { - hypfs_diag_exit(); + if (!MACHINE_IS_VM) + hypfs_diag_exit(); unregister_filesystem(&hypfs_type); subsystem_unregister(&s390_subsys); } diff --git a/arch/s390/kernel/Makefile b/arch/s390/kernel/Makefile index a81881c..5492d25 100644 --- a/arch/s390/kernel/Makefile +++ b/arch/s390/kernel/Makefile @@ -4,9 +4,9 @@ # EXTRA_AFLAGS := -traditional -obj-y := bitmap.o traps.o time.o process.o reset.o \ +obj-y := bitmap.o traps.o time.o process.o base.o early.o \ setup.o sys_s390.o ptrace.o signal.o cpcmd.o ebcdic.o \ - semaphore.o s390_ext.o debug.o profile.o irq.o ipl.o + semaphore.o s390_ext.o debug.o irq.o ipl.o obj-y += $(if $(CONFIG_64BIT),entry64.o,entry.o) obj-y += $(if $(CONFIG_64BIT),reipl64.o,reipl.o) diff --git a/arch/s390/kernel/base.S b/arch/s390/kernel/base.S new file mode 100644 index 0000000..dc7e525 --- /dev/null +++ b/arch/s390/kernel/base.S @@ -0,0 +1,150 @@ +/* + * arch/s390/kernel/base.S + * + * Copyright IBM Corp. 2006,2007 + * Author(s): Heiko Carstens + * Michael Holzheu + */ + +#include +#include + +#ifdef CONFIG_64BIT + + .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 + larl %r1,s390_base_mcck_handler_fn + lg %r1,0(%r1) + ltgr %r1,%r1 + jz 1f + basr %r14,%r1 +1: la %r1,4095 + lmg %r0,%r15,__LC_GPREGS_SAVE_AREA-4095(%r1) + lpswe __LC_MCK_OLD_PSW + + .section .bss + .globl s390_base_mcck_handler_fn +s390_base_mcck_handler_fn: + .quad 0 + .previous + + .globl s390_base_ext_handler +s390_base_ext_handler: + stmg %r0,%r15,__LC_SAVE_AREA + basr %r13,0 +0: aghi %r15,-STACK_FRAME_OVERHEAD + larl %r1,s390_base_ext_handler_fn + lg %r1,0(%r1) + ltgr %r1,%r1 + jz 1f + basr %r14,%r1 +1: lmg %r0,%r15,__LC_SAVE_AREA + ni __LC_EXT_OLD_PSW+1,0xfd # clear wait state bit + lpswe __LC_EXT_OLD_PSW + + .section .bss + .globl s390_base_ext_handler_fn +s390_base_ext_handler_fn: + .quad 0 + .previous + + .globl s390_base_pgm_handler +s390_base_pgm_handler: + stmg %r0,%r15,__LC_SAVE_AREA + basr %r13,0 +0: aghi %r15,-STACK_FRAME_OVERHEAD + larl %r1,s390_base_pgm_handler_fn + lg %r1,0(%r1) + ltgr %r1,%r1 + jz 1f + basr %r14,%r1 + lmg %r0,%r15,__LC_SAVE_AREA + lpswe __LC_PGM_OLD_PSW +1: lpswe disabled_wait_psw-0b(%r13) + + .align 8 +disabled_wait_psw: + .quad 0x0002000180000000,0x0000000000000000 + s390_base_pgm_handler + + .section .bss + .globl s390_base_pgm_handler_fn +s390_base_pgm_handler_fn: + .quad 0 + .previous + +#else /* CONFIG_64BIT */ + + .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 + l %r1,2f-0b(%r13) + l %r1,0(%r1) + ltr %r1,%r1 + jz 1f + basr %r14,%r1 +1: lm %r0,%r15,__LC_GPREGS_SAVE_AREA + lpsw __LC_MCK_OLD_PSW + +2: .long s390_base_mcck_handler_fn + + .section .bss + .globl s390_base_mcck_handler_fn +s390_base_mcck_handler_fn: + .long 0 + .previous + + .globl s390_base_ext_handler +s390_base_ext_handler: + stm %r0,%r15,__LC_SAVE_AREA + basr %r13,0 +0: ahi %r15,-STACK_FRAME_OVERHEAD + l %r1,2f-0b(%r13) + l %r1,0(%r1) + ltr %r1,%r1 + jz 1f + basr %r14,%r1 +1: lm %r0,%r15,__LC_SAVE_AREA + ni __LC_EXT_OLD_PSW+1,0xfd # clear wait state bit + lpsw __LC_EXT_OLD_PSW + +2: .long s390_base_ext_handler_fn + + .section .bss + .globl s390_base_ext_handler_fn +s390_base_ext_handler_fn: + .long 0 + .previous + + .globl s390_base_pgm_handler +s390_base_pgm_handler: + stm %r0,%r15,__LC_SAVE_AREA + basr %r13,0 +0: ahi %r15,-STACK_FRAME_OVERHEAD + l %r1,2f-0b(%r13) + l %r1,0(%r1) + ltr %r1,%r1 + jz 1f + basr %r14,%r1 + lm %r0,%r15,__LC_SAVE_AREA + lpsw __LC_PGM_OLD_PSW + +1: lpsw disabled_wait_psw-0b(%r13) + +2: .long s390_base_pgm_handler_fn + +disabled_wait_psw: + .align 8 + .long 0x000a0000,0x00000000 + s390_base_pgm_handler + + .section .bss + .globl s390_base_pgm_handler_fn +s390_base_pgm_handler_fn: + .long 0 + .previous + +#endif /* CONFIG_64BIT */ diff --git a/arch/s390/kernel/binfmt_elf32.c b/arch/s390/kernel/binfmt_elf32.c index 5c46054..f1e40ca 100644 --- a/arch/s390/kernel/binfmt_elf32.c +++ b/arch/s390/kernel/binfmt_elf32.c @@ -192,7 +192,7 @@ #undef MODULE_AUTHOR #undef cputime_to_timeval #define cputime_to_timeval cputime_to_compat_timeval -static __inline__ void +static inline void cputime_to_compat_timeval(const cputime_t cputime, struct compat_timeval *value) { value->tv_usec = cputime % 1000000; diff --git a/arch/s390/kernel/compat_exec_domain.c b/arch/s390/kernel/compat_exec_domain.c index 71d27c4..914d494 100644 --- a/arch/s390/kernel/compat_exec_domain.c +++ b/arch/s390/kernel/compat_exec_domain.c @@ -12,10 +12,9 @@ #include #include #include -struct exec_domain s390_exec_domain; +static struct exec_domain s390_exec_domain; -static int __init -s390_init (void) +static int __init s390_init (void) { s390_exec_domain.name = "Linux/s390"; s390_exec_domain.handler = NULL; diff --git a/arch/s390/kernel/compat_linux.c b/arch/s390/kernel/compat_linux.c index 5b33f82..664c669 100644 --- a/arch/s390/kernel/compat_linux.c +++ b/arch/s390/kernel/compat_linux.c @@ -69,6 +69,12 @@ #include #include "compat_linux.h" +long psw_user32_bits = (PSW_BASE32_BITS | PSW_MASK_DAT | PSW_ASC_HOME | + PSW_MASK_IO | PSW_MASK_EXT | PSW_MASK_MCHECK | + PSW_MASK_PSTATE | PSW_DEFAULT_KEY); +long psw32_user_bits = (PSW32_BASE_BITS | PSW32_MASK_DAT | PSW32_ASC_HOME | + PSW32_MASK_IO | PSW32_MASK_EXT | PSW32_MASK_MCHECK | + PSW32_MASK_PSTATE); /* For this source file, we want overflow handling. */ @@ -392,51 +398,6 @@ int cp_compat_stat(struct kstat *stat, s return err; } -struct sysinfo32 { - s32 uptime; - u32 loads[3]; - u32 totalram; - u32 freeram; - u32 sharedram; - u32 bufferram; - u32 totalswap; - u32 freeswap; - unsigned short procs; - unsigned short pads; - u32 totalhigh; - u32 freehigh; - unsigned int mem_unit; - char _f[8]; -}; - -asmlinkage long sys32_sysinfo(struct sysinfo32 __user *info) -{ - struct sysinfo s; - int ret, err; - mm_segment_t old_fs = get_fs (); - - set_fs (KERNEL_DS); - ret = sys_sysinfo((struct sysinfo __user *) &s); - set_fs (old_fs); - err = put_user (s.uptime, &info->uptime); - err |= __put_user (s.loads[0], &info->loads[0]); - err |= __put_user (s.loads[1], &info->loads[1]); - err |= __put_user (s.loads[2], &info->loads[2]); - err |= __put_user (s.totalram, &info->totalram); - err |= __put_user (s.freeram, &info->freeram); - err |= __put_user (s.sharedram, &info->sharedram); - err |= __put_user (s.bufferram, &info->bufferram); - err |= __put_user (s.totalswap, &info->totalswap); - err |= __put_user (s.freeswap, &info->freeswap); - err |= __put_user (s.procs, &info->procs); - err |= __put_user (s.totalhigh, &info->totalhigh); - err |= __put_user (s.freehigh, &info->freehigh); - err |= __put_user (s.mem_unit, &info->mem_unit); - if (err) - return -EFAULT; - return ret; -} - asmlinkage long sys32_sched_rr_get_interval(compat_pid_t pid, struct compat_timespec __user *interval) { @@ -445,7 +406,8 @@ asmlinkage long sys32_sched_rr_get_inter mm_segment_t old_fs = get_fs (); set_fs (KERNEL_DS); - ret = sys_sched_rr_get_interval(pid, (struct timespec __user *) &t); + ret = sys_sched_rr_get_interval(pid, + (struct timespec __force __user *) &t); set_fs (old_fs); if (put_compat_timespec(&t, interval)) return -EFAULT; @@ -472,8 +434,8 @@ asmlinkage long sys32_rt_sigprocmask(int } set_fs (KERNEL_DS); ret = sys_rt_sigprocmask(how, - set ? (sigset_t __user *) &s : NULL, - oset ? (sigset_t __user *) &s : NULL, + set ? (sigset_t __force __user *) &s : NULL, + oset ? (sigset_t __force __user *) &s : NULL, sigsetsize); set_fs (old_fs); if (ret) return ret; @@ -499,7 +461,7 @@ asmlinkage long sys32_rt_sigpending(comp mm_segment_t old_fs = get_fs(); set_fs (KERNEL_DS); - ret = sys_rt_sigpending((sigset_t __user *) &s, sigsetsize); + ret = sys_rt_sigpending((sigset_t __force __user *) &s, sigsetsize); set_fs (old_fs); if (!ret) { switch (_NSIG_WORDS) { @@ -524,7 +486,7 @@ sys32_rt_sigqueueinfo(int pid, int sig, if (copy_siginfo_from_user32(&info, uinfo)) return -EFAULT; set_fs (KERNEL_DS); - ret = sys_rt_sigqueueinfo(pid, sig, (siginfo_t __user *) &info); + ret = sys_rt_sigqueueinfo(pid, sig, (siginfo_t __force __user *) &info); set_fs (old_fs); return ret; } @@ -682,7 +644,7 @@ asmlinkage long sys32_sendfile(int out_f set_fs(KERNEL_DS); ret = sys_sendfile(out_fd, in_fd, - offset ? (off_t __user *) &of : NULL, count); + offset ? (off_t __force __user *) &of : NULL, count); set_fs(old_fs); if (offset && put_user(of, offset)) @@ -703,7 +665,8 @@ asmlinkage long sys32_sendfile64(int out set_fs(KERNEL_DS); ret = sys_sendfile64(out_fd, in_fd, - offset ? (loff_t __user *) &lof : NULL, count); + offset ? (loff_t __force __user *) &lof : NULL, + count); set_fs(old_fs); if (offset && put_user(lof, offset)) diff --git a/arch/s390/kernel/compat_linux.h b/arch/s390/kernel/compat_linux.h index 1a18e29..e89f8c0 100644 --- a/arch/s390/kernel/compat_linux.h +++ b/arch/s390/kernel/compat_linux.h @@ -115,37 +115,6 @@ typedef struct __u32 addr; } _psw_t32 __attribute__ ((aligned(8))); -#define PSW32_MASK_PER 0x40000000UL -#define PSW32_MASK_DAT 0x04000000UL -#define PSW32_MASK_IO 0x02000000UL -#define PSW32_MASK_EXT 0x01000000UL -#define PSW32_MASK_KEY 0x00F00000UL -#define PSW32_MASK_MCHECK 0x00040000UL -#define PSW32_MASK_WAIT 0x00020000UL -#define PSW32_MASK_PSTATE 0x00010000UL -#define PSW32_MASK_ASC 0x0000C000UL -#define PSW32_MASK_CC 0x00003000UL -#define PSW32_MASK_PM 0x00000f00UL - -#define PSW32_ADDR_AMODE31 0x80000000UL -#define PSW32_ADDR_INSN 0x7FFFFFFFUL - -#define PSW32_BASE_BITS 0x00080000UL - -#define PSW32_ASC_PRIMARY 0x00000000UL -#define PSW32_ASC_ACCREG 0x00004000UL -#define PSW32_ASC_SECONDARY 0x00008000UL -#define PSW32_ASC_HOME 0x0000C000UL - -#define PSW32_USER_BITS (PSW32_BASE_BITS | PSW32_MASK_DAT | PSW32_ASC_HOME | \ - PSW32_MASK_IO | PSW32_MASK_EXT | PSW32_MASK_MCHECK | \ - PSW32_MASK_PSTATE) - -#define PSW32_MASK_MERGE(CURRENT,NEW) \ - (((CURRENT) & ~(PSW32_MASK_CC|PSW32_MASK_PM)) | \ - ((NEW) & (PSW32_MASK_CC|PSW32_MASK_PM))) - - typedef struct { _psw_t32 psw; diff --git a/arch/s390/kernel/compat_signal.c b/arch/s390/kernel/compat_signal.c index 861888a..887a988 100644 --- a/arch/s390/kernel/compat_signal.c +++ b/arch/s390/kernel/compat_signal.c @@ -275,8 +275,8 @@ sys32_sigaltstack(const stack_t32 __user } set_fs (KERNEL_DS); - ret = do_sigaltstack((stack_t __user *) (uss ? &kss : NULL), - (stack_t __user *) (uoss ? &koss : NULL), + ret = do_sigaltstack((stack_t __force __user *) (uss ? &kss : NULL), + (stack_t __force __user *) (uoss ? &koss : NULL), regs->gprs[15]); set_fs (old_fs); @@ -298,7 +298,7 @@ static int save_sigregs32(struct pt_regs _s390_regs_common32 regs32; int err, i; - regs32.psw.mask = PSW32_MASK_MERGE(PSW32_USER_BITS, + regs32.psw.mask = PSW32_MASK_MERGE(psw32_user_bits, (__u32)(regs->psw.mask >> 32)); regs32.psw.addr = PSW32_ADDR_AMODE31 | (__u32) regs->psw.addr; for (i = 0; i < NUM_GPRS; i++) @@ -401,7 +401,7 @@ asmlinkage long sys32_rt_sigreturn(struc goto badframe; set_fs (KERNEL_DS); - do_sigaltstack((stack_t __user *)&st, NULL, regs->gprs[15]); + do_sigaltstack((stack_t __force __user *)&st, NULL, regs->gprs[15]); set_fs (old_fs); return regs->gprs[2]; diff --git a/arch/s390/kernel/compat_wrapper.S b/arch/s390/kernel/compat_wrapper.S index 71e54ef..9790129 100644 --- a/arch/s390/kernel/compat_wrapper.S +++ b/arch/s390/kernel/compat_wrapper.S @@ -517,10 +517,10 @@ sys32_swapoff_wrapper: llgtr %r2,%r2 # const char * jg sys_swapoff # branch to system call - .globl sys32_sysinfo_wrapper -sys32_sysinfo_wrapper: + .globl compat_sys_sysinfo_wrapper +compat_sys_sysinfo_wrapper: llgtr %r2,%r2 # struct sysinfo_emu31 * - jg sys32_sysinfo # branch to system call + jg compat_sys_sysinfo # branch to system call .globl sys32_ipc_wrapper sys32_ipc_wrapper: diff --git a/arch/s390/kernel/cpcmd.c b/arch/s390/kernel/cpcmd.c index a5972f1..6c89f30 100644 --- a/arch/s390/kernel/cpcmd.c +++ b/arch/s390/kernel/cpcmd.c @@ -16,6 +16,7 @@ #include #include #include #include +#include static DEFINE_SPINLOCK(cpcmd_lock); static char cpcmd_buf[241]; @@ -88,13 +89,8 @@ int cpcmd(const char *cmd, char *respons int len; unsigned long flags; - if ((rlen == 0) || (response == NULL) - || !((unsigned long)response >> 31)) { - spin_lock_irqsave(&cpcmd_lock, flags); - len = __cpcmd(cmd, response, rlen, response_code); - spin_unlock_irqrestore(&cpcmd_lock, flags); - } - else { + if ((virt_to_phys(response) != (unsigned long) response) || + (((unsigned long)response + rlen) >> 31)) { lowbuf = kmalloc(rlen, GFP_KERNEL | GFP_DMA); if (!lowbuf) { printk(KERN_WARNING @@ -106,6 +102,10 @@ int cpcmd(const char *cmd, char *respons spin_unlock_irqrestore(&cpcmd_lock, flags); memcpy(response, lowbuf, rlen); kfree(lowbuf); + } else { + spin_lock_irqsave(&cpcmd_lock, flags); + len = __cpcmd(cmd, response, rlen, response_code); + spin_unlock_irqrestore(&cpcmd_lock, flags); } return len; } diff --git a/arch/s390/kernel/crash.c b/arch/s390/kernel/crash.c index 926ccee..8cc7c9f 100644 --- a/arch/s390/kernel/crash.c +++ b/arch/s390/kernel/crash.c @@ -9,6 +9,7 @@ #include #include +#include void machine_crash_shutdown(struct pt_regs *regs) { diff --git a/arch/s390/kernel/debug.c b/arch/s390/kernel/debug.c index bb57bc0..eca3fe5 100644 --- a/arch/s390/kernel/debug.c +++ b/arch/s390/kernel/debug.c @@ -120,7 +120,7 @@ struct debug_view debug_hex_ascii_view = NULL }; -struct debug_view debug_level_view = { +static struct debug_view debug_level_view = { "level", &debug_prolog_level_fn, NULL, @@ -129,7 +129,7 @@ struct debug_view debug_level_view = { NULL }; -struct debug_view debug_pages_view = { +static struct debug_view debug_pages_view = { "pages", &debug_prolog_pages_fn, NULL, @@ -138,7 +138,7 @@ struct debug_view debug_pages_view = { NULL }; -struct debug_view debug_flush_view = { +static struct debug_view debug_flush_view = { "flush", NULL, NULL, @@ -156,18 +156,18 @@ struct debug_view debug_sprintf_view = { NULL }; - +/* used by dump analysis tools to determine version of debug feature */ unsigned int debug_feature_version = __DEBUG_FEATURE_VERSION; /* static globals */ static debug_info_t *debug_area_first = NULL; static debug_info_t *debug_area_last = NULL; -DECLARE_MUTEX(debug_lock); +static DECLARE_MUTEX(debug_lock); static int initialized; -static struct file_operations debug_file_ops = { +static const struct file_operations debug_file_ops = { .owner = THIS_MODULE, .read = debug_output, .write = debug_input, @@ -852,7 +852,6 @@ debug_finish_entry(debug_info_t * id, de static int debug_stoppable=1; static int debug_active=1; -#define CTL_S390DBF 5677 #define CTL_S390DBF_STOPPABLE 5678 #define CTL_S390DBF_ACTIVE 5679 @@ -905,7 +904,7 @@ static struct ctl_table s390dbf_dir_tabl { .ctl_name = 0 } }; -struct ctl_table_header *s390dbf_sysctl_header; +static struct ctl_table_header *s390dbf_sysctl_header; void debug_stop_all(void) @@ -1054,7 +1053,7 @@ __init debug_init(void) { int rc = 0; - s390dbf_sysctl_header = register_sysctl_table(s390dbf_dir_table, 1); + s390dbf_sysctl_header = register_sysctl_table(s390dbf_dir_table); down(&debug_lock); debug_debugfs_root_entry = debugfs_create_dir(DEBUG_DIR_ROOT,NULL); printk(KERN_INFO "debug: Initialization complete\n"); @@ -1300,8 +1299,7 @@ out: * flushes debug areas */ -void -debug_flush(debug_info_t* id, int area) +static void debug_flush(debug_info_t* id, int area) { unsigned long flags; int i,j; @@ -1511,8 +1509,7 @@ out: /* * clean up module */ -void -__exit debug_exit(void) +static void __exit debug_exit(void) { debugfs_remove(debug_debugfs_root_entry); unregister_sysctl_table(s390dbf_sysctl_header); diff --git a/arch/s390/kernel/early.c b/arch/s390/kernel/early.c new file mode 100644 index 0000000..e518dd5 --- /dev/null +++ b/arch/s390/kernel/early.c @@ -0,0 +1,306 @@ +/* + * arch/s390/kernel/early.c + * + * Copyright IBM Corp. 2007 + * Author(s): Hongjie Yang , + * Heiko Carstens + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* + * Create a Kernel NSS if the SAVESYS= parameter is defined + */ +#define DEFSYS_CMD_SIZE 96 +#define SAVESYS_CMD_SIZE 32 + +char kernel_nss_name[NSS_NAME_SIZE + 1]; + +#ifdef CONFIG_SHARED_KERNEL +static noinline __init void create_kernel_nss(void) +{ + unsigned int i, stext_pfn, eshared_pfn, end_pfn, min_size; +#ifdef CONFIG_BLK_DEV_INITRD + unsigned int sinitrd_pfn, einitrd_pfn; +#endif + int response; + char *savesys_ptr; + char upper_command_line[COMMAND_LINE_SIZE]; + char defsys_cmd[DEFSYS_CMD_SIZE]; + char savesys_cmd[SAVESYS_CMD_SIZE]; + + /* Do nothing if we are not running under VM */ + if (!MACHINE_IS_VM) + return; + + /* Convert COMMAND_LINE to upper case */ + for (i = 0; i < strlen(COMMAND_LINE); i++) + upper_command_line[i] = toupper(COMMAND_LINE[i]); + + savesys_ptr = strstr(upper_command_line, "SAVESYS="); + + if (!savesys_ptr) + return; + + savesys_ptr += 8; /* Point to the beginning of the NSS name */ + for (i = 0; i < NSS_NAME_SIZE; i++) { + if (savesys_ptr[i] == ' ' || savesys_ptr[i] == '\0') + break; + kernel_nss_name[i] = savesys_ptr[i]; + } + + stext_pfn = PFN_DOWN(__pa(&_stext)); + eshared_pfn = PFN_DOWN(__pa(&_eshared)); + end_pfn = PFN_UP(__pa(&_end)); + min_size = end_pfn << 2; + + sprintf(defsys_cmd, "DEFSYS %s 00000-%.5X EW %.5X-%.5X SR %.5X-%.5X", + kernel_nss_name, stext_pfn - 1, stext_pfn, eshared_pfn - 1, + eshared_pfn, end_pfn); + +#ifdef CONFIG_BLK_DEV_INITRD + if (INITRD_START && INITRD_SIZE) { + sinitrd_pfn = PFN_DOWN(__pa(INITRD_START)); + einitrd_pfn = PFN_UP(__pa(INITRD_START + INITRD_SIZE)); + min_size = einitrd_pfn << 2; + sprintf(defsys_cmd, "%s EW %.5X-%.5X", defsys_cmd, + sinitrd_pfn, einitrd_pfn); + } +#endif + + sprintf(defsys_cmd, "%s EW MINSIZE=%.7iK", defsys_cmd, min_size); + sprintf(savesys_cmd, "SAVESYS %s \n IPL %s", + kernel_nss_name, kernel_nss_name); + + __cpcmd(defsys_cmd, NULL, 0, &response); + + if (response != 0) + return; + + __cpcmd(savesys_cmd, NULL, 0, &response); + + if (response != strlen(savesys_cmd)) + return; + + ipl_flags = IPL_NSS_VALID; +} + +#else /* CONFIG_SHARED_KERNEL */ + +static inline void create_kernel_nss(void) { } + +#endif /* CONFIG_SHARED_KERNEL */ + +/* + * Clear bss memory + */ +static noinline __init void clear_bss_section(void) +{ + memset(__bss_start, 0, _end - __bss_start); +} + +/* + * Initialize storage key for kernel pages + */ +static noinline __init void init_kernel_storage_key(void) +{ + unsigned long end_pfn, init_pfn; + + end_pfn = PFN_UP(__pa(&_end)); + + for (init_pfn = 0 ; init_pfn < end_pfn; init_pfn++) + page_set_storage_key(init_pfn << PAGE_SHIFT, PAGE_DEFAULT_KEY); +} + +static noinline __init void detect_machine_type(void) +{ + struct cpuinfo_S390 *cpuinfo = &S390_lowcore.cpu_data; + + asm volatile("stidp %0" : "=m" (S390_lowcore.cpu_data.cpu_id)); + + /* Running under z/VM ? */ + if (cpuinfo->cpu_id.version == 0xff) + machine_flags |= 1; + + /* Running on a P/390 ? */ + if (cpuinfo->cpu_id.machine == 0x7490) + machine_flags |= 4; +} + +static noinline __init int memory_fast_detect(void) +{ + + unsigned long val0 = 0; + unsigned long val1 = 0xc; + int ret = -ENOSYS; + + if (ipl_flags & IPL_NSS_VALID) + return -ENOSYS; + + asm volatile( + " diag %1,%2,0x260\n" + "0: lhi %0,0\n" + "1:\n" + EX_TABLE(0b,1b) + : "+d" (ret), "+d" (val0), "+d" (val1) : : "cc"); + + if (ret || val0 != val1) + return -ENOSYS; + + memory_chunk[0].size = val0; + return 0; +} + +#define ADDR2G (1UL << 31) + +static noinline __init unsigned long sclp_memory_detect(void) +{ + struct sclp_readinfo_sccb *sccb; + unsigned long long memsize; + + sccb = &s390_readinfo_sccb; + + if (sccb->header.response_code != 0x10) + return 0; + + if (sccb->rnsize) + memsize = sccb->rnsize << 20; + else + memsize = sccb->rnsize2 << 20; + if (sccb->rnmax) + memsize *= sccb->rnmax; + else + memsize *= sccb->rnmax2; +#ifndef CONFIG_64BIT + /* + * Can't deal with more than 2G in 31 bit addressing mode, so + * limit the value in order to avoid strange side effects. + */ + if (memsize > ADDR2G) + memsize = ADDR2G; +#endif + return (unsigned long) memsize; +} + +static inline __init unsigned long __tprot(unsigned long addr) +{ + int cc = -1; + + asm volatile( + " tprot 0(%1),0\n" + "0: ipm %0\n" + " srl %0,28\n" + "1:\n" + EX_TABLE(0b,1b) + : "+d" (cc) : "a" (addr) : "cc"); + return (unsigned long)cc; +} + +/* Checking memory in 128KB increments. */ +#define CHUNK_INCR (1UL << 17) + +static noinline __init void find_memory_chunks(unsigned long memsize) +{ + unsigned long addr = 0, old_addr = 0; + unsigned long old_cc = CHUNK_READ_WRITE; + unsigned long cc; + int chunk = 0; + + while (chunk < MEMORY_CHUNKS) { + cc = __tprot(addr); + while (cc == old_cc) { + addr += CHUNK_INCR; + cc = __tprot(addr); +#ifndef CONFIG_64BIT + if (addr == ADDR2G) + break; +#endif + } + + if (old_addr != addr && + (old_cc == CHUNK_READ_WRITE || old_cc == CHUNK_READ_ONLY)) { + memory_chunk[chunk].addr = old_addr; + memory_chunk[chunk].size = addr - old_addr; + memory_chunk[chunk].type = old_cc; + chunk++; + } + + old_addr = addr; + old_cc = cc; + +#ifndef CONFIG_64BIT + if (addr == ADDR2G) + break; +#endif + /* + * Finish memory detection at the first hole, unless + * - we reached the hsa -> skip it. + * - we know there must be more. + */ + if (cc == -1UL && !memsize && old_addr != ADDR2G) + break; + if (memsize && addr >= memsize) + break; + } +} + +static __init void early_pgm_check_handler(void) +{ + unsigned long addr; + const struct exception_table_entry *fixup; + + addr = S390_lowcore.program_old_psw.addr; + fixup = search_exception_tables(addr & PSW_ADDR_INSN); + if (!fixup) + disabled_wait(0); + S390_lowcore.program_old_psw.addr = fixup->fixup | PSW_ADDR_AMODE; +} + +static noinline __init void setup_lowcore_early(void) +{ + psw_t psw; + + psw.mask = PSW_BASE_BITS | PSW_DEFAULT_KEY; + psw.addr = PSW_ADDR_AMODE | (unsigned long) s390_base_ext_handler; + S390_lowcore.external_new_psw = psw; + psw.addr = PSW_ADDR_AMODE | (unsigned long) s390_base_pgm_handler; + S390_lowcore.program_new_psw = psw; + s390_base_pgm_handler_fn = early_pgm_check_handler; +} + +/* + * Save ipl parameters, clear bss memory, initialize storage keys + * and create a kernel NSS at startup if the SAVESYS= parm is defined + */ +void __init startup_init(void) +{ + unsigned long memsize; + + ipl_save_parameters(); + clear_bss_section(); + init_kernel_storage_key(); + lockdep_init(); + lockdep_off(); + detect_machine_type(); + create_kernel_nss(); + sort_main_extable(); + setup_lowcore_early(); + sclp_readinfo_early(); + memsize = sclp_memory_detect(); + if (memory_fast_detect() < 0) + find_memory_chunks(memsize); + lockdep_on(); +} diff --git a/arch/s390/kernel/ebcdic.c b/arch/s390/kernel/ebcdic.c index bb0f973..cc0dc60 100644 --- a/arch/s390/kernel/ebcdic.c +++ b/arch/s390/kernel/ebcdic.c @@ -11,6 +11,7 @@ #include #include +#include /* * ASCII (IBM PC 437) -> EBCDIC 037 diff --git a/arch/s390/kernel/head31.S b/arch/s390/kernel/head31.S index eca5070..453fd3b 100644 --- a/arch/s390/kernel/head31.S +++ b/arch/s390/kernel/head31.S @@ -51,176 +51,15 @@ # st %r15,__LC_KERNEL_STACK # set end of kernel stack ahi %r15,-96 xc __SF_BACKCHAIN(4,%r15),__SF_BACKCHAIN(%r15) # clear backchain - - l %r14,.Lipl_save_parameters-.LPG1(%r13) - basr %r14,%r14 # -# clear bss memory +# Save ipl parameters, clear bss memory, initialize storage key for kernel pages, +# and create a kernel NSS if the SAVESYS= parm is defined # - l %r2,.Lbss_bgn-.LPG1(%r13) # start of bss - l %r3,.Lbss_end-.LPG1(%r13) # end of bss - sr %r3,%r2 # length of bss - sr %r4,%r4 - sr %r5,%r5 # set src,length and pad to zero - sr %r0,%r0 - mvcle %r2,%r4,0 # clear mem - jo .-4 # branch back, if not finish - - l %r2,.Lrcp-.LPG1(%r13) # Read SCP forced command word -.Lservicecall: - stosm .Lpmask-.LPG1(%r13),0x01 # authorize ext interrupts - - stctl %r0, %r0,.Lcr-.LPG1(%r13) # get cr0 - la %r1,0x200 # set bit 22 - o %r1,.Lcr-.LPG1(%r13) # or old cr0 with r1 - st %r1,.Lcr-.LPG1(%r13) - lctl %r0, %r0,.Lcr-.LPG1(%r13) # load modified cr0 - - mvc __LC_EXT_NEW_PSW(8),.Lpcext-.LPG1(%r13) # set postcall psw - la %r1, .Lsclph-.LPG1(%r13) - a %r1,__LC_EXT_NEW_PSW+4 # set handler - st %r1,__LC_EXT_NEW_PSW+4 - - l %r4,.Lsccbaddr-.LPG1(%r13) # %r4 is our index for sccb stuff - lr %r1,%r4 # our sccb - .insn rre,0xb2200000,%r2,%r1 # service call - ipm %r1 - srl %r1,28 # get cc code - xr %r3, %r3 - chi %r1,3 - be .Lfchunk-.LPG1(%r13) # leave - chi %r1,2 - be .Lservicecall-.LPG1(%r13) - lpsw .Lwaitsclp-.LPG1(%r13) -.Lsclph: - lh %r1,.Lsccbr-.Lsccb(%r4) - chi %r1,0x10 # 0x0010 is the sucess code - je .Lprocsccb # let's process the sccb - chi %r1,0x1f0 - bne .Lfchunk-.LPG1(%r13) # unhandled error code - c %r2, .Lrcp-.LPG1(%r13) # Did we try Read SCP forced - bne .Lfchunk-.LPG1(%r13) # if no, give up - l %r2, .Lrcp2-.LPG1(%r13) # try with Read SCP - b .Lservicecall-.LPG1(%r13) -.Lprocsccb: - lhi %r1,0 - icm %r1,3,.Lscpincr1-.Lsccb(%r4) # use this one if != 0 - jnz .Lscnd - lhi %r1,0x800 # otherwise report 2GB -.Lscnd: - lhi %r3,0x800 # limit reported memory size to 2GB - cr %r1,%r3 - jl .Lno2gb - lr %r1,%r3 -.Lno2gb: - xr %r3,%r3 # same logic - ic %r3,.Lscpa1-.Lsccb(%r4) - chi %r3,0x00 - jne .Lcompmem - l %r3,.Lscpa2-.Lsccb(%r4) -.Lcompmem: - mr %r2,%r1 # mem in MB on 128-bit - l %r1,.Lonemb-.LPG1(%r13) - mr %r2,%r1 # mem size in bytes in %r3 - b .Lfchunk-.LPG1(%r13) - - .align 4 -.Lipl_save_parameters: - .long ipl_save_parameters -.Linittu: - .long init_thread_union -.Lpmask: - .byte 0 - .align 8 -.Lpcext:.long 0x00080000,0x80000000 -.Lcr: - .long 0x00 # place holder for cr0 - .align 8 -.Lwaitsclp: - .long 0x010a0000,0x80000000 + .Lsclph -.Lrcp: - .int 0x00120001 # Read SCP forced code -.Lrcp2: - .int 0x00020001 # Read SCP code -.Lonemb: - .int 0x100000 -.Lfchunk: + l %r14,.Lstartup_init-.LPG1(%r13) + basr %r14,%r14 -# -# find memory chunks. -# - lr %r9,%r3 # end of mem - mvc __LC_PGM_NEW_PSW(8),.Lpcmem-.LPG1(%r13) - la %r1,1 # test in increments of 128KB - sll %r1,17 - l %r3,.Lmchunk-.LPG1(%r13) # get pointer to memory_chunk array - slr %r4,%r4 # set start of chunk to zero - slr %r5,%r5 # set end of chunk to zero - slr %r6,%r6 # set access code to zero - la %r10,MEMORY_CHUNKS # number of chunks -.Lloop: - tprot 0(%r5),0 # test protection of first byte - ipm %r7 - srl %r7,28 - clr %r6,%r7 # compare cc with last access code - be .Lsame-.LPG1(%r13) - lhi %r8,0 # no program checks - b .Lsavchk-.LPG1(%r13) -.Lsame: - ar %r5,%r1 # add 128KB to end of chunk - bno .Lloop-.LPG1(%r13) # r1 < 0x80000000 -> loop -.Lchkmem: # > 2GB or tprot got a program check - lhi %r8,1 # set program check flag -.Lsavchk: - clr %r4,%r5 # chunk size > 0? - be .Lchkloop-.LPG1(%r13) - st %r4,0(%r3) # store start address of chunk - lr %r0,%r5 - slr %r0,%r4 - st %r0,4(%r3) # store size of chunk - st %r6,8(%r3) # store type of chunk - la %r3,12(%r3) - ahi %r10,-1 # update chunk number -.Lchkloop: - lr %r6,%r7 # set access code to last cc - # we got an exception or we're starting a new - # chunk , we must check if we should - # still try to find valid memory (if we detected - # the amount of available storage), and if we - # have chunks left - xr %r0,%r0 - clr %r0,%r9 # did we detect memory? - je .Ldonemem # if not, leave - chi %r10,0 # do we have chunks left? - je .Ldonemem - chi %r8,1 # program check ? - je .Lpgmchk - lr %r4,%r5 # potential new chunk - alr %r5,%r1 # add 128KB to end of chunk - j .Llpcnt -.Lpgmchk: - alr %r5,%r1 # add 128KB to end of chunk - lr %r4,%r5 # potential new chunk -.Llpcnt: - clr %r5,%r9 # should we go on? - jl .Lloop -.Ldonemem: l %r12,.Lmflags-.LPG1(%r13) # get address of machine_flags # -# find out if we are running under VM -# - stidp __LC_CPUID # store cpuid - tm __LC_CPUID,0xff # running under VM ? - bno .Lnovm-.LPG1(%r13) - oi 3(%r12),1 # set VM flag -.Lnovm: - lh %r0,__LC_CPUID+4 # get cpu version - chi %r0,0x7490 # running on a P/390 ? - bne .Lnop390-.LPG1(%r13) - oi 3(%r12),4 # set P/390 flag -.Lnop390: - -# # find out if we have an IEEE fpu # mvc __LC_PGM_NEW_PSW(8),.Lpcfpu-.LPG1(%r13) @@ -295,7 +134,6 @@ # .long 0 # cr15: linkage stack operations .Lduct: .long 0,0,0,0,0,0,0,0 .long 0,0,0,0,0,0,0,0 -.Lpcmem:.long 0x00080000,0x80000000 + .Lchkmem .Lpcfpu:.long 0x00080000,0x80000000 + .Lchkfpu .Lpccsp:.long 0x00080000,0x80000000 + .Lchkcsp .Lpcmvpg:.long 0x00080000,0x80000000 + .Lchkmvpg @@ -306,7 +144,9 @@ # .Lbss_bgn: .long __bss_start .Lbss_end: .long _end .Lparmaddr: .long PARMAREA -.Lsccbaddr: .long .Lsccb +.Linittu: .long init_thread_union +.Lstartup_init: + .long startup_init .globl ipl_schib ipl_schib: @@ -322,26 +162,6 @@ ipl_devno: .word 0 .org 0x12000 -.globl s390_readinfo_sccb -s390_readinfo_sccb: -.Lsccb: - .hword 0x1000 # length, one page - .byte 0x00,0x00,0x00 - .byte 0x80 # variable response bit set -.Lsccbr: - .hword 0x00 # response code -.Lscpincr1: - .hword 0x00 -.Lscpa1: - .byte 0x00 - .fill 89,1,0 -.Lscpa2: - .int 0x00 -.Lscpincr2: - .quad 0x00 - .fill 3984,1,0 - .org 0x13000 - #ifdef CONFIG_SHARED_KERNEL .org 0x100000 #endif diff --git a/arch/s390/kernel/head64.S b/arch/s390/kernel/head64.S index 6ba3f45..b8fec4e 100644 --- a/arch/s390/kernel/head64.S +++ b/arch/s390/kernel/head64.S @@ -58,183 +58,15 @@ # stg %r15,__LC_KERNEL_STACK # set end of kernel stack aghi %r15,-160 xc __SF_BACKCHAIN(4,%r15),__SF_BACKCHAIN(%r15) # clear backchain - - brasl %r14,ipl_save_parameters # -# clear bss memory +# Save ipl parameters, clear bss memory, initialize storage key for kernel pages, +# and create a kernel NSS if the SAVESYS= parm is defined # - larl %r2,__bss_start # start of bss segment - larl %r3,_end # end of bss segment - sgr %r3,%r2 # length of bss - sgr %r4,%r4 # - sgr %r5,%r5 # set src,length and pad to zero - mvcle %r2,%r4,0 # clear mem - jo .-4 # branch back, if not finish + brasl %r14,startup_init # set program check new psw mask mvc __LC_PGM_NEW_PSW(8),.Lpcmsk-.LPG1(%r13) - larl %r1,.Lslowmemdetect # set program check address - stg %r1,__LC_PGM_NEW_PSW+8 - lghi %r1,0xc - diag %r0,%r1,0x260 # get memory size of virtual machine - cgr %r0,%r1 # different? -> old detection routine - jne .Lslowmemdetect - aghi %r1,1 # size is one more than end - larl %r2,memory_chunk - stg %r1,8(%r2) # store size of chunk - j .Ldonemem - -.Lslowmemdetect: - l %r2,.Lrcp-.LPG1(%r13) # Read SCP forced command word -.Lservicecall: - stosm .Lpmask-.LPG1(%r13),0x01 # authorize ext interrupts - - stctg %r0,%r0,.Lcr-.LPG1(%r13) # get cr0 - la %r1,0x200 # set bit 22 - og %r1,.Lcr-.LPG1(%r13) # or old cr0 with r1 - stg %r1,.Lcr-.LPG1(%r13) - lctlg %r0,%r0,.Lcr-.LPG1(%r13) # load modified cr0 - - mvc __LC_EXT_NEW_PSW(8),.Lpcmsk-.LPG1(%r13) # set postcall psw - larl %r1,.Lsclph - stg %r1,__LC_EXT_NEW_PSW+8 # set handler - - larl %r4,.Lsccb # %r4 is our index for sccb stuff - lgr %r1,%r4 # our sccb - .insn rre,0xb2200000,%r2,%r1 # service call - ipm %r1 - srl %r1,28 # get cc code - xr %r3,%r3 - chi %r1,3 - be .Lfchunk-.LPG1(%r13) # leave - chi %r1,2 - be .Lservicecall-.LPG1(%r13) - lpswe .Lwaitsclp-.LPG1(%r13) -.Lsclph: - lh %r1,.Lsccbr-.Lsccb(%r4) - chi %r1,0x10 # 0x0010 is the sucess code - je .Lprocsccb # let's process the sccb - chi %r1,0x1f0 - bne .Lfchunk-.LPG1(%r13) # unhandled error code - c %r2,.Lrcp-.LPG1(%r13) # Did we try Read SCP forced - bne .Lfchunk-.LPG1(%r13) # if no, give up - l %r2,.Lrcp2-.LPG1(%r13) # try with Read SCP - b .Lservicecall-.LPG1(%r13) -.Lprocsccb: - lghi %r1,0 - icm %r1,3,.Lscpincr1-.Lsccb(%r4) # use this one if != 0 - jnz .Lscnd - lg %r1,.Lscpincr2-.Lsccb(%r4) # otherwise use this one -.Lscnd: - xr %r3,%r3 # same logic - ic %r3,.Lscpa1-.Lsccb(%r4) - chi %r3,0x00 - jne .Lcompmem - l %r3,.Lscpa2-.Lsccb(%r4) -.Lcompmem: - mlgr %r2,%r1 # mem in MB on 128-bit - l %r1,.Lonemb-.LPG1(%r13) - mlgr %r2,%r1 # mem size in bytes in %r3 - b .Lfchunk-.LPG1(%r13) - - .align 4 -.Lpmask: - .byte 0 - .align 8 -.Lcr: - .quad 0x00 # place holder for cr0 -.Lwaitsclp: - .quad 0x0102000180000000,.Lsclph -.Lrcp: - .int 0x00120001 # Read SCP forced code -.Lrcp2: - .int 0x00020001 # Read SCP code -.Lonemb: - .int 0x100000 - -.Lfchunk: - -# -# find memory chunks. -# - lgr %r9,%r3 # end of mem - larl %r1,.Lchkmem # set program check address - stg %r1,__LC_PGM_NEW_PSW+8 - la %r1,1 # test in increments of 128KB - sllg %r1,%r1,17 - larl %r3,memory_chunk - slgr %r4,%r4 # set start of chunk to zero - slgr %r5,%r5 # set end of chunk to zero - slr %r6,%r6 # set access code to zero - la %r10,MEMORY_CHUNKS # number of chunks -.Lloop: - tprot 0(%r5),0 # test protection of first byte - ipm %r7 - srl %r7,28 - clr %r6,%r7 # compare cc with last access code - je .Lsame - lghi %r8,0 # no program checks - j .Lsavchk -.Lsame: - algr %r5,%r1 # add 128KB to end of chunk - # no need to check here, - brc 12,.Lloop # this is the same chunk -.Lchkmem: # > 16EB or tprot got a program check - lghi %r8,1 # set program check flag -.Lsavchk: - clgr %r4,%r5 # chunk size > 0? - je .Lchkloop - stg %r4,0(%r3) # store start address of chunk - lgr %r0,%r5 - slgr %r0,%r4 - stg %r0,8(%r3) # store size of chunk - st %r6,20(%r3) # store type of chunk - la %r3,24(%r3) - ahi %r10,-1 # update chunk number -.Lchkloop: - lr %r6,%r7 # set access code to last cc - # we got an exception or we're starting a new - # chunk , we must check if we should - # still try to find valid memory (if we detected - # the amount of available storage), and if we - # have chunks left - lghi %r4,1 - sllg %r4,%r4,31 - clgr %r5,%r4 - je .Lhsaskip - xr %r0, %r0 - clgr %r0, %r9 # did we detect memory? - je .Ldonemem # if not, leave - chi %r10, 0 # do we have chunks left? - je .Ldonemem -.Lhsaskip: - chi %r8,1 # program check ? - je .Lpgmchk - lgr %r4,%r5 # potential new chunk - algr %r5,%r1 # add 128KB to end of chunk - j .Llpcnt -.Lpgmchk: - algr %r5,%r1 # add 128KB to end of chunk - lgr %r4,%r5 # potential new chunk -.Llpcnt: - clgr %r5,%r9 # should we go on? - jl .Lloop -.Ldonemem: - larl %r12,machine_flags # -# find out if we are running under VM -# - stidp __LC_CPUID # store cpuid - tm __LC_CPUID,0xff # running under VM ? - bno 0f-.LPG1(%r13) - oi 7(%r12),1 # set VM flag -0: lh %r0,__LC_CPUID+4 # get cpu version - chi %r0,0x7490 # running on a P/390 ? - bne 1f-.LPG1(%r13) - oi 7(%r12),4 # set P/390 flag -1: - -# # find out if we have the MVPG instruction # la %r1,0f-.LPG1(%r13) # set program check address @@ -336,25 +168,6 @@ ipl_devno: .word 0 .org 0x12000 -.globl s390_readinfo_sccb -s390_readinfo_sccb: -.Lsccb: - .hword 0x1000 # length, one page - .byte 0x00,0x00,0x00 - .byte 0x80 # variable response bit set -.Lsccbr: - .hword 0x00 # response code -.Lscpincr1: - .hword 0x00 -.Lscpa1: - .byte 0x00 - .fill 89,1,0 -.Lscpa2: - .int 0x00 -.Lscpincr2: - .quad 0x00 - .fill 3984,1,0 - .org 0x13000 #ifdef CONFIG_SHARED_KERNEL .org 0x100000 diff --git a/arch/s390/kernel/ipl.c b/arch/s390/kernel/ipl.c index 9e9972e..0522595 100644 --- a/arch/s390/kernel/ipl.c +++ b/arch/s390/kernel/ipl.c @@ -20,26 +20,27 @@ #include #include #include #include +#include #define IPL_PARM_BLOCK_VERSION 0 -#define LOADPARM_LEN 8 -extern char s390_readinfo_sccb[]; -#define SCCB_VALID (*((__u16*)&s390_readinfo_sccb[6]) == 0x0010) -#define SCCB_LOADPARM (&s390_readinfo_sccb[24]) -#define SCCB_FLAG (s390_readinfo_sccb[91]) +#define SCCB_VALID (s390_readinfo_sccb.header.response_code == 0x10) +#define SCCB_LOADPARM (&s390_readinfo_sccb.loadparm) +#define SCCB_FLAG (s390_readinfo_sccb.flags) enum ipl_type { IPL_TYPE_NONE = 1, IPL_TYPE_UNKNOWN = 2, IPL_TYPE_CCW = 4, IPL_TYPE_FCP = 8, + IPL_TYPE_NSS = 16, }; #define IPL_NONE_STR "none" #define IPL_UNKNOWN_STR "unknown" #define IPL_CCW_STR "ccw" #define IPL_FCP_STR "fcp" +#define IPL_NSS_STR "nss" static char *ipl_type_str(enum ipl_type type) { @@ -50,6 +51,8 @@ static char *ipl_type_str(enum ipl_type return IPL_CCW_STR; case IPL_TYPE_FCP: return IPL_FCP_STR; + case IPL_TYPE_NSS: + return IPL_NSS_STR; case IPL_TYPE_UNKNOWN: default: return IPL_UNKNOWN_STR; @@ -64,6 +67,7 @@ enum ipl_method { IPL_METHOD_FCP_RO_DIAG, IPL_METHOD_FCP_RW_DIAG, IPL_METHOD_FCP_RO_VM, + IPL_METHOD_NSS, }; enum shutdown_action { @@ -114,11 +118,14 @@ enum diag308_rc { static int diag308_set_works = 0; static int reipl_capabilities = IPL_TYPE_UNKNOWN; + static enum ipl_type reipl_type = IPL_TYPE_UNKNOWN; static enum ipl_method reipl_method = IPL_METHOD_NONE; static struct ipl_parameter_block *reipl_block_fcp; static struct ipl_parameter_block *reipl_block_ccw; +static char reipl_nss_name[NSS_NAME_SIZE + 1]; + static int dump_capabilities = IPL_TYPE_NONE; static enum ipl_type dump_type = IPL_TYPE_NONE; static enum ipl_method dump_method = IPL_METHOD_NONE; @@ -173,6 +180,24 @@ static struct subsys_attribute sys_##_pr sys_##_prefix##_##_name##_show, \ sys_##_prefix##_##_name##_store); +#define DEFINE_IPL_ATTR_STR_RW(_prefix, _name, _fmt_out, _fmt_in, _value)\ +static ssize_t sys_##_prefix##_##_name##_show(struct subsystem *subsys, \ + char *page) \ +{ \ + return sprintf(page, _fmt_out, _value); \ +} \ +static ssize_t sys_##_prefix##_##_name##_store(struct subsystem *subsys,\ + const char *buf, size_t len) \ +{ \ + if (sscanf(buf, _fmt_in, _value) != 1) \ + return -EINVAL; \ + return len; \ +} \ +static struct subsys_attribute sys_##_prefix##_##_name##_attr = \ + __ATTR(_name,(S_IRUGO | S_IWUSR), \ + sys_##_prefix##_##_name##_show, \ + sys_##_prefix##_##_name##_store); + static void make_attrs_ro(struct attribute **attrs) { while (*attrs) { @@ -189,6 +214,8 @@ static enum ipl_type ipl_get_type(void) { struct ipl_parameter_block *ipl = IPL_PARMBLOCK_START; + if (ipl_flags & IPL_NSS_VALID) + return IPL_TYPE_NSS; if (!(ipl_flags & IPL_DEVNO_VALID)) return IPL_TYPE_UNKNOWN; if (!(ipl_flags & IPL_PARMBLOCK_VALID)) @@ -324,6 +351,20 @@ static struct attribute_group ipl_ccw_at .attrs = ipl_ccw_attrs, }; +/* NSS ipl device attributes */ + +DEFINE_IPL_ATTR_RO(ipl_nss, name, "%s\n", kernel_nss_name); + +static struct attribute *ipl_nss_attrs[] = { + &sys_ipl_type_attr.attr, + &sys_ipl_nss_name_attr.attr, + NULL, +}; + +static struct attribute_group ipl_nss_attr_group = { + .attrs = ipl_nss_attrs, +}; + /* UNKNOWN ipl device attributes */ static struct attribute *ipl_unknown_attrs[] = { @@ -432,6 +473,21 @@ static struct attribute_group reipl_ccw_ .attrs = reipl_ccw_attrs, }; + +/* NSS reipl device attributes */ + +DEFINE_IPL_ATTR_STR_RW(reipl_nss, name, "%s\n", "%s\n", reipl_nss_name); + +static struct attribute *reipl_nss_attrs[] = { + &sys_reipl_nss_name_attr.attr, + NULL, +}; + +static struct attribute_group reipl_nss_attr_group = { + .name = IPL_NSS_STR, + .attrs = reipl_nss_attrs, +}; + /* reipl type */ static int reipl_set_type(enum ipl_type type) @@ -454,6 +510,9 @@ static int reipl_set_type(enum ipl_type else reipl_method = IPL_METHOD_FCP_RO_DIAG; break; + case IPL_TYPE_NSS: + reipl_method = IPL_METHOD_NSS; + break; default: reipl_method = IPL_METHOD_NONE; } @@ -475,6 +534,8 @@ static ssize_t reipl_type_store(struct s rc = reipl_set_type(IPL_TYPE_CCW); else if (strncmp(buf, IPL_FCP_STR, strlen(IPL_FCP_STR)) == 0) rc = reipl_set_type(IPL_TYPE_FCP); + else if (strncmp(buf, IPL_NSS_STR, strlen(IPL_NSS_STR)) == 0) + rc = reipl_set_type(IPL_TYPE_NSS); return (rc != 0) ? rc : len; } @@ -647,6 +708,10 @@ void do_reipl(void) case IPL_METHOD_FCP_RO_VM: __cpcmd("IPL", NULL, 0, NULL); break; + case IPL_METHOD_NSS: + sprintf(buf, "IPL %s", reipl_nss_name); + __cpcmd(buf, NULL, 0, NULL); + break; case IPL_METHOD_NONE: default: if (MACHINE_IS_VM) @@ -733,6 +798,10 @@ static int __init ipl_init(void) case IPL_TYPE_FCP: rc = ipl_register_fcp_files(); break; + case IPL_TYPE_NSS: + rc = sysfs_create_group(&ipl_subsys.kset.kobj, + &ipl_nss_attr_group); + break; default: rc = sysfs_create_group(&ipl_subsys.kset.kobj, &ipl_unknown_attr_group); @@ -755,6 +824,20 @@ static void __init reipl_probe(void) free_page((unsigned long)buffer); } +static int __init reipl_nss_init(void) +{ + int rc; + + if (!MACHINE_IS_VM) + return 0; + rc = sysfs_create_group(&reipl_subsys.kset.kobj, &reipl_nss_attr_group); + if (rc) + return rc; + strncpy(reipl_nss_name, kernel_nss_name, NSS_NAME_SIZE + 1); + reipl_capabilities |= IPL_TYPE_NSS; + return 0; +} + static int __init reipl_ccw_init(void) { int rc; @@ -837,6 +920,9 @@ static int __init reipl_init(void) rc = reipl_fcp_init(); if (rc) return rc; + rc = reipl_nss_init(); + if (rc) + return rc; rc = reipl_set_type(ipl_get_type()); if (rc) return rc; @@ -993,8 +1079,6 @@ static void do_reset_calls(void) reset->fn(); } -extern void reset_mcck_handler(void); -extern void reset_pgm_handler(void); extern __u32 dump_prefix_page; void s390_reset_system(void) @@ -1016,14 +1100,14 @@ void s390_reset_system(void) __ctl_clear_bit(0,28); /* Set new machine check handler */ - S390_lowcore.mcck_new_psw.mask = PSW_KERNEL_BITS & ~PSW_MASK_MCHECK; + S390_lowcore.mcck_new_psw.mask = psw_kernel_bits & ~PSW_MASK_MCHECK; S390_lowcore.mcck_new_psw.addr = - PSW_ADDR_AMODE | (unsigned long) &reset_mcck_handler; + PSW_ADDR_AMODE | (unsigned long) s390_base_mcck_handler; /* Set new program check handler */ - S390_lowcore.program_new_psw.mask = PSW_KERNEL_BITS & ~PSW_MASK_MCHECK; + S390_lowcore.program_new_psw.mask = psw_kernel_bits & ~PSW_MASK_MCHECK; S390_lowcore.program_new_psw.addr = - PSW_ADDR_AMODE | (unsigned long) &reset_pgm_handler; + PSW_ADDR_AMODE | (unsigned long) s390_base_pgm_handler; do_reset_calls(); } diff --git a/arch/s390/kernel/irq.c b/arch/s390/kernel/irq.c index 1eef509..8f0cbca 100644 --- a/arch/s390/kernel/irq.c +++ b/arch/s390/kernel/irq.c @@ -1,9 +1,9 @@ /* * arch/s390/kernel/irq.c * - * S390 version - * Copyright (C) 2004 IBM Deutschland Entwicklung GmbH, IBM Corporation + * Copyright IBM Corp. 2004,2007 * Author(s): Martin Schwidefsky (schwidefsky@de.ibm.com), + * Thomas Spatzier (tspat@de.ibm.com) * * This file contains interrupt related functions. */ @@ -14,6 +14,8 @@ #include #include #include #include +#include +#include /* * show_interrupts is needed by /proc/interrupts. @@ -93,5 +95,12 @@ asmlinkage void do_softirq(void) local_irq_restore(flags); } - EXPORT_SYMBOL(do_softirq); + +void init_irq_proc(void) +{ + struct proc_dir_entry *root_irq_dir; + + root_irq_dir = proc_mkdir("irq", NULL); + create_prof_cpu_mask(root_irq_dir); +} diff --git a/arch/s390/kernel/kprobes.c b/arch/s390/kernel/kprobes.c index 576368c..a466bab 100644 --- a/arch/s390/kernel/kprobes.c +++ b/arch/s390/kernel/kprobes.c @@ -155,15 +155,34 @@ void __kprobes get_instruction_type(stru static int __kprobes swap_instruction(void *aref) { struct ins_replace_args *args = aref; + u32 *addr; + u32 instr; int err = -EFAULT; + /* + * Text segment is read-only, hence we use stura to bypass dynamic + * address translation to exchange the instruction. Since stura + * always operates on four bytes, but we only want to exchange two + * bytes do some calculations to get things right. In addition we + * shall not cross any page boundaries (vmalloc area!) when writing + * the new instruction. + */ + addr = (u32 *)ALIGN((unsigned long)args->ptr, 4); + if ((unsigned long)args->ptr & 2) + instr = ((*addr) & 0xffff0000) | args->new; + else + instr = ((*addr) & 0x0000ffff) | args->new << 16; + asm volatile( - "0: mvc 0(2,%2),0(%3)\n" - "1: la %0,0\n" + " lra %1,0(%1)\n" + "0: stura %2,%1\n" + "1: la %0,0\n" "2:\n" EX_TABLE(0b,2b) - : "+d" (err), "=m" (*args->ptr) - : "a" (args->ptr), "a" (&args->new), "m" (args->new)); + : "+d" (err) + : "a" (addr), "d" (instr) + : "memory", "cc"); + return err; } @@ -356,7 +375,7 @@ no_kprobe: * - When the probed function returns, this probe * causes the handlers to fire */ -void __kprobes kretprobe_trampoline_holder(void) +void kretprobe_trampoline_holder(void) { asm volatile(".global kretprobe_trampoline\n" "kretprobe_trampoline: bcr 0,0\n"); @@ -365,7 +384,8 @@ void __kprobes kretprobe_trampoline_hold /* * Called when the probe at kretprobe trampoline is hit */ -int __kprobes trampoline_probe_handler(struct kprobe *p, struct pt_regs *regs) +static int __kprobes trampoline_probe_handler(struct kprobe *p, + struct pt_regs *regs) { struct kretprobe_instance *ri = NULL; struct hlist_head *head, empty_rp; diff --git a/arch/s390/kernel/machine_kexec.c b/arch/s390/kernel/machine_kexec.c index f6d9bcc..52f57af 100644 --- a/arch/s390/kernel/machine_kexec.c +++ b/arch/s390/kernel/machine_kexec.c @@ -11,6 +11,7 @@ #include #include #include #include +#include #include #include #include diff --git a/arch/s390/kernel/module.c b/arch/s390/kernel/module.c index d989ed4..39d1dd7 100644 --- a/arch/s390/kernel/module.c +++ b/arch/s390/kernel/module.c @@ -30,6 +30,7 @@ #include #include #include #include +#include #if 0 #define DEBUGP printk @@ -58,7 +59,7 @@ void module_free(struct module *mod, voi table entries. */ } -static inline void +static void check_rela(Elf_Rela *rela, struct module *me) { struct mod_arch_syminfo *info; @@ -181,7 +182,7 @@ apply_relocate(Elf_Shdr *sechdrs, const return -ENOEXEC; } -static inline int +static int apply_rela(Elf_Rela *rela, Elf_Addr base, Elf_Sym *symtab, struct module *me) { diff --git a/arch/s390/kernel/process.c b/arch/s390/kernel/process.c index 6603fbb..5acfac6 100644 --- a/arch/s390/kernel/process.c +++ b/arch/s390/kernel/process.c @@ -144,7 +144,7 @@ #endif trace_hardirqs_on(); /* Wait for external, I/O or machine check interrupt. */ - __load_psw_mask(PSW_KERNEL_BITS | PSW_MASK_WAIT | + __load_psw_mask(psw_kernel_bits | PSW_MASK_WAIT | PSW_MASK_IO | PSW_MASK_EXT); } @@ -190,7 +190,7 @@ int kernel_thread(int (*fn)(void *), voi struct pt_regs regs; memset(®s, 0, sizeof(regs)); - regs.psw.mask = PSW_KERNEL_BITS | PSW_MASK_IO | PSW_MASK_EXT; + regs.psw.mask = psw_kernel_bits | PSW_MASK_IO | PSW_MASK_EXT; regs.psw.addr = (unsigned long) kernel_thread_starter | PSW_ADDR_AMODE; regs.gprs[9] = (unsigned long) fn; regs.gprs[10] = (unsigned long) arg; diff --git a/arch/s390/kernel/profile.c b/arch/s390/kernel/profile.c deleted file mode 100644 index b81aa1f..0000000 --- a/arch/s390/kernel/profile.c +++ /dev/null @@ -1,20 +0,0 @@ -/* - * arch/s390/kernel/profile.c - * - * Copyright (C) 2003 IBM Deutschland Entwicklung GmbH, IBM Corporation - * Author(s): Thomas Spatzier (tspat@de.ibm.com) - * - */ -#include -#include - -static struct proc_dir_entry * root_irq_dir; - -void init_irq_proc(void) -{ - /* create /proc/irq */ - root_irq_dir = proc_mkdir("irq", NULL); - - /* create /proc/irq/prof_cpu_mask */ - create_prof_cpu_mask(root_irq_dir); -} diff --git a/arch/s390/kernel/ptrace.c b/arch/s390/kernel/ptrace.c index 8f36504..2a8f087 100644 --- a/arch/s390/kernel/ptrace.c +++ b/arch/s390/kernel/ptrace.c @@ -86,15 +86,13 @@ #endif per_info->control_regs.bits.storage_alt_space_ctl = 0; } -void -set_single_step(struct task_struct *task) +static void set_single_step(struct task_struct *task) { task->thread.per_info.single_step = 1; FixPerRegisters(task); } -void -clear_single_step(struct task_struct *task) +static void clear_single_step(struct task_struct *task) { task->thread.per_info.single_step = 0; FixPerRegisters(task); @@ -232,9 +230,9 @@ #endif */ if (addr == (addr_t) &dummy->regs.psw.mask && #ifdef CONFIG_COMPAT - data != PSW_MASK_MERGE(PSW_USER32_BITS, data) && + data != PSW_MASK_MERGE(psw_user32_bits, data) && #endif - data != PSW_MASK_MERGE(PSW_USER_BITS, data)) + data != PSW_MASK_MERGE(psw_user_bits, data)) /* Invalid psw mask. */ return -EINVAL; #ifndef CONFIG_64BIT @@ -309,7 +307,7 @@ do_ptrace_normal(struct task_struct *chi copied = access_process_vm(child, addr, &tmp, sizeof(tmp), 0); if (copied != sizeof(tmp)) return -EIO; - return put_user(tmp, (unsigned long __user *) data); + return put_user(tmp, (unsigned long __force __user *) data); case PTRACE_PEEKUSR: /* read the word at location addr in the USER area. */ @@ -331,7 +329,7 @@ do_ptrace_normal(struct task_struct *chi case PTRACE_PEEKUSR_AREA: case PTRACE_POKEUSR_AREA: - if (copy_from_user(&parea, (void __user *) addr, + if (copy_from_user(&parea, (void __force __user *) addr, sizeof(parea))) return -EFAULT; addr = parea.kernel_addr; @@ -341,10 +339,11 @@ do_ptrace_normal(struct task_struct *chi if (request == PTRACE_PEEKUSR_AREA) ret = peek_user(child, addr, data); else { - addr_t tmp; - if (get_user (tmp, (addr_t __user *) data)) + addr_t utmp; + if (get_user(utmp, + (addr_t __force __user *) data)) return -EFAULT; - ret = poke_user(child, addr, tmp); + ret = poke_user(child, addr, utmp); } if (ret) return ret; @@ -394,7 +393,7 @@ peek_user_emu31(struct task_struct *chil if (addr == (addr_t) &dummy32->regs.psw.mask) { /* Fake a 31 bit psw mask. */ tmp = (__u32)(task_pt_regs(child)->psw.mask >> 32); - tmp = PSW32_MASK_MERGE(PSW32_USER_BITS, tmp); + tmp = PSW32_MASK_MERGE(psw32_user_bits, tmp); } else if (addr == (addr_t) &dummy32->regs.psw.addr) { /* Fake a 31 bit psw address. */ tmp = (__u32) task_pt_regs(child)->psw.addr | @@ -469,11 +468,11 @@ poke_user_emu31(struct task_struct *chil */ if (addr == (addr_t) &dummy32->regs.psw.mask) { /* Build a 64 bit psw mask from 31 bit mask. */ - if (tmp != PSW32_MASK_MERGE(PSW32_USER_BITS, tmp)) + if (tmp != PSW32_MASK_MERGE(psw32_user_bits, tmp)) /* Invalid psw mask. */ return -EINVAL; task_pt_regs(child)->psw.mask = - PSW_MASK_MERGE(PSW_USER32_BITS, (__u64) tmp << 32); + PSW_MASK_MERGE(psw_user32_bits, (__u64) tmp << 32); } else if (addr == (addr_t) &dummy32->regs.psw.addr) { /* Build a 64 bit psw address from 31 bit address. */ task_pt_regs(child)->psw.addr = @@ -550,7 +549,7 @@ do_ptrace_emu31(struct task_struct *chil copied = access_process_vm(child, addr, &tmp, sizeof(tmp), 0); if (copied != sizeof(tmp)) return -EIO; - return put_user(tmp, (unsigned int __user *) data); + return put_user(tmp, (unsigned int __force __user *) data); case PTRACE_PEEKUSR: /* read the word at location addr in the USER area. */ @@ -571,7 +570,7 @@ do_ptrace_emu31(struct task_struct *chil case PTRACE_PEEKUSR_AREA: case PTRACE_POKEUSR_AREA: - if (copy_from_user(&parea, (void __user *) addr, + if (copy_from_user(&parea, (void __force __user *) addr, sizeof(parea))) return -EFAULT; addr = parea.kernel_addr; @@ -581,10 +580,11 @@ do_ptrace_emu31(struct task_struct *chil if (request == PTRACE_PEEKUSR_AREA) ret = peek_user_emu31(child, addr, data); else { - __u32 tmp; - if (get_user (tmp, (__u32 __user *) data)) + __u32 utmp; + if (get_user(utmp, + (__u32 __force __user *) data)) return -EFAULT; - ret = poke_user_emu31(child, addr, tmp); + ret = poke_user_emu31(child, addr, utmp); } if (ret) return ret; @@ -595,17 +595,19 @@ do_ptrace_emu31(struct task_struct *chil return 0; case PTRACE_GETEVENTMSG: return put_user((__u32) child->ptrace_message, - (unsigned int __user *) data); + (unsigned int __force __user *) data); case PTRACE_GETSIGINFO: if (child->last_siginfo == NULL) return -EINVAL; - return copy_siginfo_to_user32((compat_siginfo_t __user *) data, + return copy_siginfo_to_user32((compat_siginfo_t + __force __user *) data, child->last_siginfo); case PTRACE_SETSIGINFO: if (child->last_siginfo == NULL) return -EINVAL; return copy_siginfo_from_user32(child->last_siginfo, - (compat_siginfo_t __user *) data); + (compat_siginfo_t + __force __user *) data); } return ptrace_request(child, request, addr, data); } diff --git a/arch/s390/kernel/reset.S b/arch/s390/kernel/reset.S deleted file mode 100644 index 8a87355..0000000 --- a/arch/s390/kernel/reset.S +++ /dev/null @@ -1,90 +0,0 @@ -/* - * arch/s390/kernel/reset.S - * - * Copyright (C) IBM Corp. 2006 - * Author(s): Heiko Carstens - * Michael Holzheu - */ - -#include -#include - -#ifdef CONFIG_64BIT - - .globl reset_mcck_handler -reset_mcck_handler: - basr %r13,0 -0: lg %r15,__LC_PANIC_STACK # load panic stack - aghi %r15,-STACK_FRAME_OVERHEAD - lg %r1,s390_reset_mcck_handler-0b(%r13) - ltgr %r1,%r1 - jz 1f - basr %r14,%r1 -1: la %r1,4095 - lmg %r0,%r15,__LC_GPREGS_SAVE_AREA-4095(%r1) - lpswe __LC_MCK_OLD_PSW - - .globl s390_reset_mcck_handler -s390_reset_mcck_handler: - .quad 0 - - .globl reset_pgm_handler -reset_pgm_handler: - stmg %r0,%r15,__LC_SAVE_AREA - basr %r13,0 -0: lg %r15,__LC_PANIC_STACK # load panic stack - aghi %r15,-STACK_FRAME_OVERHEAD - lg %r1,s390_reset_pgm_handler-0b(%r13) - ltgr %r1,%r1 - jz 1f - basr %r14,%r1 - lmg %r0,%r15,__LC_SAVE_AREA - lpswe __LC_PGM_OLD_PSW -1: lpswe disabled_wait_psw-0b(%r13) - .globl s390_reset_pgm_handler -s390_reset_pgm_handler: - .quad 0 - .align 8 -disabled_wait_psw: - .quad 0x0002000180000000,0x0000000000000000 + reset_pgm_handler - -#else /* CONFIG_64BIT */ - - .globl reset_mcck_handler -reset_mcck_handler: - basr %r13,0 -0: l %r15,__LC_PANIC_STACK # load panic stack - ahi %r15,-STACK_FRAME_OVERHEAD - l %r1,s390_reset_mcck_handler-0b(%r13) - ltr %r1,%r1 - jz 1f - basr %r14,%r1 -1: lm %r0,%r15,__LC_GPREGS_SAVE_AREA - lpsw __LC_MCK_OLD_PSW - - .globl s390_reset_mcck_handler -s390_reset_mcck_handler: - .long 0 - - .globl reset_pgm_handler -reset_pgm_handler: - stm %r0,%r15,__LC_SAVE_AREA - basr %r13,0 -0: l %r15,__LC_PANIC_STACK # load panic stack - ahi %r15,-STACK_FRAME_OVERHEAD - l %r1,s390_reset_pgm_handler-0b(%r13) - ltr %r1,%r1 - jz 1f - basr %r14,%r1 - lm %r0,%r15,__LC_SAVE_AREA - lpsw __LC_PGM_OLD_PSW - -1: lpsw disabled_wait_psw-0b(%r13) - .globl s390_reset_pgm_handler -s390_reset_pgm_handler: - .long 0 -disabled_wait_psw: - .align 8 - .long 0x000a0000,0x00000000 + reset_pgm_handler - -#endif /* CONFIG_64BIT */ diff --git a/arch/s390/kernel/s390_ext.c b/arch/s390/kernel/s390_ext.c index bc5beaa..acf93db 100644 --- a/arch/s390/kernel/s390_ext.c +++ b/arch/s390/kernel/s390_ext.c @@ -125,14 +125,12 @@ void do_extint(struct pt_regs *regs, uns * Make sure that the i/o interrupt did not "overtake" * the last HZ timer interrupt. */ - account_ticks(); + account_ticks(S390_lowcore.int_clock); kstat_cpu(smp_processor_id()).irqs[EXTERNAL_INTERRUPT]++; index = ext_hash(code); for (p = ext_int_hash[index]; p; p = p->next) { - if (likely(p->code == code)) { - if (likely(p->handler)) - p->handler(code); - } + if (likely(p->code == code)) + p->handler(code); } irq_exit(); set_irq_regs(old_regs); diff --git a/arch/s390/kernel/setup.c b/arch/s390/kernel/setup.c index 5d8ee3b..50c5210 100644 --- a/arch/s390/kernel/setup.c +++ b/arch/s390/kernel/setup.c @@ -38,6 +38,8 @@ #include #include #include #include +#include +#include #include #include @@ -49,6 +51,14 @@ #include #include #include #include +#include +#include + +long psw_kernel_bits = (PSW_BASE_BITS | PSW_MASK_DAT | PSW_ASC_PRIMARY | + PSW_MASK_MCHECK | PSW_DEFAULT_KEY); +long psw_user_bits = (PSW_BASE_BITS | PSW_MASK_DAT | PSW_ASC_HOME | + PSW_MASK_IO | PSW_MASK_EXT | PSW_MASK_MCHECK | + PSW_MASK_PSTATE | PSW_DEFAULT_KEY); /* * User copy operations. @@ -117,9 +127,9 @@ void __devinit cpu_init (void) */ char vmhalt_cmd[128] = ""; char vmpoff_cmd[128] = ""; -char vmpanic_cmd[128] = ""; +static char vmpanic_cmd[128] = ""; -static inline void strncpy_skip_quote(char *dst, char *src, int n) +static void strncpy_skip_quote(char *dst, char *src, int n) { int sx, dx; @@ -275,10 +285,6 @@ #endif } #ifdef CONFIG_SMP -extern void machine_restart_smp(char *); -extern void machine_halt_smp(void); -extern void machine_power_off_smp(void); - void (*_machine_restart)(char *command) = machine_restart_smp; void (*_machine_halt)(void) = machine_halt_smp; void (*_machine_power_off)(void) = machine_power_off_smp; @@ -386,6 +392,84 @@ static int __init early_parse_ipldelay(c } early_param("ipldelay", early_parse_ipldelay); +#ifdef CONFIG_S390_SWITCH_AMODE +unsigned int switch_amode = 0; +EXPORT_SYMBOL_GPL(switch_amode); + +static void set_amode_and_uaccess(unsigned long user_amode, + unsigned long user32_amode) +{ + psw_user_bits = PSW_BASE_BITS | PSW_MASK_DAT | user_amode | + PSW_MASK_IO | PSW_MASK_EXT | PSW_MASK_MCHECK | + PSW_MASK_PSTATE | PSW_DEFAULT_KEY; +#ifdef CONFIG_COMPAT + psw_user32_bits = PSW_BASE32_BITS | PSW_MASK_DAT | user_amode | + PSW_MASK_IO | PSW_MASK_EXT | PSW_MASK_MCHECK | + PSW_MASK_PSTATE | PSW_DEFAULT_KEY; + psw32_user_bits = PSW32_BASE_BITS | PSW32_MASK_DAT | user32_amode | + PSW32_MASK_IO | PSW32_MASK_EXT | PSW32_MASK_MCHECK | + PSW32_MASK_PSTATE; +#endif + psw_kernel_bits = PSW_BASE_BITS | PSW_MASK_DAT | PSW_ASC_HOME | + PSW_MASK_MCHECK | PSW_DEFAULT_KEY; + + if (MACHINE_HAS_MVCOS) { + printk("mvcos available.\n"); + memcpy(&uaccess, &uaccess_mvcos_switch, sizeof(uaccess)); + } else { + printk("mvcos not available.\n"); + memcpy(&uaccess, &uaccess_pt, sizeof(uaccess)); + } +} + +/* + * Switch kernel/user addressing modes? + */ +static int __init early_parse_switch_amode(char *p) +{ + switch_amode = 1; + return 0; +} +early_param("switch_amode", early_parse_switch_amode); + +#else /* CONFIG_S390_SWITCH_AMODE */ +static inline void set_amode_and_uaccess(unsigned long user_amode, + unsigned long user32_amode) +{ +} +#endif /* CONFIG_S390_SWITCH_AMODE */ + +#ifdef CONFIG_S390_EXEC_PROTECT +unsigned int s390_noexec = 0; +EXPORT_SYMBOL_GPL(s390_noexec); + +/* + * Enable execute protection? + */ +static int __init early_parse_noexec(char *p) +{ + if (!strncmp(p, "off", 3)) + return 0; + switch_amode = 1; + s390_noexec = 1; + return 0; +} +early_param("noexec", early_parse_noexec); +#endif /* CONFIG_S390_EXEC_PROTECT */ + +static void setup_addressing_mode(void) +{ + if (s390_noexec) { + printk("S390 execute protection active, "); + set_amode_and_uaccess(PSW_ASC_SECONDARY, PSW32_ASC_SECONDARY); + return; + } + if (switch_amode) { + printk("S390 address spaces switched, "); + set_amode_and_uaccess(PSW_ASC_PRIMARY, PSW32_ASC_PRIMARY); + } +} + static void __init setup_lowcore(void) { @@ -402,19 +486,21 @@ setup_lowcore(void) lc->restart_psw.mask = PSW_BASE_BITS | PSW_DEFAULT_KEY; lc->restart_psw.addr = PSW_ADDR_AMODE | (unsigned long) restart_int_handler; - lc->external_new_psw.mask = PSW_KERNEL_BITS; + if (switch_amode) + lc->restart_psw.mask |= PSW_ASC_HOME; + lc->external_new_psw.mask = psw_kernel_bits; lc->external_new_psw.addr = PSW_ADDR_AMODE | (unsigned long) ext_int_handler; - lc->svc_new_psw.mask = PSW_KERNEL_BITS | PSW_MASK_IO | PSW_MASK_EXT; + lc->svc_new_psw.mask = psw_kernel_bits | PSW_MASK_IO | PSW_MASK_EXT; lc->svc_new_psw.addr = PSW_ADDR_AMODE | (unsigned long) system_call; - lc->program_new_psw.mask = PSW_KERNEL_BITS; + lc->program_new_psw.mask = psw_kernel_bits; lc->program_new_psw.addr = PSW_ADDR_AMODE | (unsigned long)pgm_check_handler; lc->mcck_new_psw.mask = - PSW_KERNEL_BITS & ~PSW_MASK_MCHECK & ~PSW_MASK_DAT; + psw_kernel_bits & ~PSW_MASK_MCHECK & ~PSW_MASK_DAT; lc->mcck_new_psw.addr = PSW_ADDR_AMODE | (unsigned long) mcck_int_handler; - lc->io_new_psw.mask = PSW_KERNEL_BITS; + lc->io_new_psw.mask = psw_kernel_bits; lc->io_new_psw.addr = PSW_ADDR_AMODE | (unsigned long) io_int_handler; lc->ipl_device = S390_lowcore.ipl_device; lc->jiffy_timer = -1LL; @@ -439,7 +525,7 @@ #endif static void __init setup_resources(void) { - struct resource *res; + struct resource *res, *sub_res; int i; code_resource.start = (unsigned long) &_text; @@ -464,8 +550,38 @@ setup_resources(void) res->start = memory_chunk[i].addr; res->end = memory_chunk[i].addr + memory_chunk[i].size - 1; request_resource(&iomem_resource, res); - request_resource(res, &code_resource); - request_resource(res, &data_resource); + + if (code_resource.start >= res->start && + code_resource.start <= res->end && + code_resource.end > res->end) { + sub_res = alloc_bootmem_low(sizeof(struct resource)); + memcpy(sub_res, &code_resource, + sizeof(struct resource)); + sub_res->end = res->end; + code_resource.start = res->end + 1; + request_resource(res, sub_res); + } + + if (code_resource.start >= res->start && + code_resource.start <= res->end && + code_resource.end <= res->end) + request_resource(res, &code_resource); + + if (data_resource.start >= res->start && + data_resource.start <= res->end && + data_resource.end > res->end) { + sub_res = alloc_bootmem_low(sizeof(struct resource)); + memcpy(sub_res, &data_resource, + sizeof(struct resource)); + sub_res->end = res->end; + data_resource.start = res->end + 1; + request_resource(res, sub_res); + } + + if (data_resource.start >= res->start && + data_resource.start <= res->end && + data_resource.end <= res->end) + request_resource(res, &data_resource); } } @@ -495,16 +611,13 @@ static void __init setup_memory_end(void } if (!memory_end) memory_end = memory_size; - if (real_size > memory_end) - printk("More memory detected than supported. Unused: %luk\n", - (real_size - memory_end) >> 10); } static void __init setup_memory(void) { unsigned long bootmap_size; - unsigned long start_pfn, end_pfn, init_pfn; + unsigned long start_pfn, end_pfn; int i; /* @@ -514,10 +627,6 @@ setup_memory(void) start_pfn = PFN_UP(__pa(&_end)); end_pfn = max_pfn = PFN_DOWN(memory_end); - /* Initialize storage key for kernel pages */ - for (init_pfn = 0 ; init_pfn < start_pfn; init_pfn++) - page_set_storage_key(init_pfn << PAGE_SHIFT, PAGE_DEFAULT_KEY); - #ifdef CONFIG_BLK_DEV_INITRD /* * Move the initrd in case the bitmap of the bootmem allocater @@ -631,7 +740,7 @@ #else /* CONFIG_64BIT */ #endif /* CONFIG_64BIT */ /* Save unparsed command line copy for /proc/cmdline */ - strlcpy(saved_command_line, COMMAND_LINE, COMMAND_LINE_SIZE); + strlcpy(boot_command_line, COMMAND_LINE, COMMAND_LINE_SIZE); *cmdline_p = COMMAND_LINE; *(*cmdline_p + COMMAND_LINE_SIZE - 1) = '\0'; @@ -651,6 +760,7 @@ #endif /* CONFIG_64BIT */ parse_early_param(); setup_memory_end(); + setup_addressing_mode(); setup_memory(); setup_resources(); setup_lowcore(); @@ -694,6 +804,7 @@ static int show_cpuinfo(struct seq_file struct cpuinfo_S390 *cpuinfo; unsigned long n = (unsigned long) v - 1; + s390_adjust_jiffies(); preempt_disable(); if (!n) { seq_printf(m, "vendor_id : IBM/S390\n" diff --git a/arch/s390/kernel/signal.c b/arch/s390/kernel/signal.c index 4c8a795..554f9cf 100644 --- a/arch/s390/kernel/signal.c +++ b/arch/s390/kernel/signal.c @@ -119,7 +119,7 @@ static int save_sigregs(struct pt_regs * /* Copy a 'clean' PSW mask to the user to avoid leaking information about whether PER is currently on. */ - user_sregs.regs.psw.mask = PSW_MASK_MERGE(PSW_USER_BITS, regs->psw.mask); + user_sregs.regs.psw.mask = PSW_MASK_MERGE(psw_user_bits, regs->psw.mask); user_sregs.regs.psw.addr = regs->psw.addr; memcpy(&user_sregs.regs.gprs, ®s->gprs, sizeof(sregs->regs.gprs)); memcpy(&user_sregs.regs.acrs, current->thread.acrs, diff --git a/arch/s390/kernel/smp.c b/arch/s390/kernel/smp.c index c0cd255..83a4ea6 100644 --- a/arch/s390/kernel/smp.c +++ b/arch/s390/kernel/smp.c @@ -22,23 +22,23 @@ #include #include - #include #include #include #include - #include #include #include #include - +#include +#include #include #include #include #include #include #include +#include extern volatile int __cpu_logical_map[]; @@ -53,17 +53,11 @@ cpumask_t cpu_possible_map = CPU_MASK_NO static struct task_struct *current_set[NR_CPUS]; -/* - * Reboot, halt and power_off routines for SMP. - */ -extern char vmhalt_cmd[]; -extern char vmpoff_cmd[]; - static void smp_ext_bitcall(int, ec_bit_sig); static void smp_ext_bitcall_others(ec_bit_sig); /* -5B * Structure and data for smp_call_function(). This is designed to minimise + * Structure and data for smp_call_function(). This is designed to minimise * static memory requirements. It also looks cleaner. */ static DEFINE_SPINLOCK(call_lock); @@ -110,7 +104,7 @@ int smp_call_function (void (*func) (voi * remote CPUs are nearly ready to execute <> or are or have executed. * * You must not call this function with disabled interrupts or from a - * hardware interrupt handler or from a bottom half handler. + * hardware interrupt handler. */ { struct call_data_struct data; @@ -119,8 +113,8 @@ int smp_call_function (void (*func) (voi if (cpus <= 0) return 0; - /* Can deadlock when called with interrupts disabled */ - WARN_ON(irqs_disabled()); + /* Can deadlock when interrupts are disabled or if in wrong context */ + WARN_ON(irqs_disabled() || in_irq()); data.func = func; data.info = info; @@ -129,7 +123,7 @@ int smp_call_function (void (*func) (voi if (wait) atomic_set(&data.finished, 0); - spin_lock(&call_lock); + spin_lock_bh(&call_lock); call_data = &data; /* Send a message to all other CPUs and wait for them to respond */ smp_ext_bitcall_others(ec_call_function); @@ -141,7 +135,7 @@ int smp_call_function (void (*func) (voi if (wait) while (atomic_read(&data.finished) != cpus) cpu_relax(); - spin_unlock(&call_lock); + spin_unlock_bh(&call_lock); return 0; } @@ -165,6 +159,9 @@ int smp_call_function_on(void (*func) (v if (!cpu_online(cpu)) return -EINVAL; + /* Can deadlock when interrupts are disabled or if in wrong context */ + WARN_ON(irqs_disabled() || in_irq()); + /* disable preemption for local function call */ curr_cpu = get_cpu(); @@ -200,7 +197,7 @@ int smp_call_function_on(void (*func) (v } EXPORT_SYMBOL(smp_call_function_on); -static inline void do_send_stop(void) +static void do_send_stop(void) { int cpu, rc; @@ -214,7 +211,7 @@ static inline void do_send_stop(void) } } -static inline void do_store_status(void) +static void do_store_status(void) { int cpu, rc; @@ -230,7 +227,7 @@ static inline void do_store_status(void) } } -static inline void do_wait_for_stop(void) +static void do_wait_for_stop(void) { int cpu; @@ -250,7 +247,7 @@ static inline void do_wait_for_stop(void void smp_send_stop(void) { /* Disable all interrupts/machine checks */ - __load_psw_mask(PSW_KERNEL_BITS & ~PSW_MASK_MCHECK); + __load_psw_mask(psw_kernel_bits & ~PSW_MASK_MCHECK); /* write magic number to zero page (absolute 0) */ lowcore_ptr[smp_processor_id()]->panic_magic = __PANIC_MAGIC; @@ -298,7 +295,7 @@ void machine_power_off_smp(void) * cpus are handled. */ -void do_ext_call_interrupt(__u16 code) +static void do_ext_call_interrupt(__u16 code) { unsigned long bits; @@ -385,7 +382,7 @@ struct ec_creg_mask_parms { /* * callback for setting/clearing control bits */ -void smp_ctl_bit_callback(void *info) { +static void smp_ctl_bit_callback(void *info) { struct ec_creg_mask_parms *pp = info; unsigned long cregs[16]; int i; @@ -458,17 +455,15 @@ __init smp_count_cpus(void) /* * Activate a secondary processor. */ -extern void init_cpu_timer(void); -extern void init_cpu_vtimer(void); - int __devinit start_secondary(void *cpuvoid) { /* Setup the cpu */ cpu_init(); preempt_disable(); - /* init per CPU timer */ + /* Enable TOD clock interrupts on the secondary cpu. */ init_cpu_timer(); #ifdef CONFIG_VIRT_TIMER + /* Enable cpu timer interrupts on the secondary cpu. */ init_cpu_vtimer(); #endif /* Enable pfault pseudo page faults on this cpu. */ @@ -542,7 +537,7 @@ smp_put_cpu(int cpu) spin_unlock_irqrestore(&smp_reserve_lock, flags); } -static inline int +static int cpu_stopped(int cpu) { __u32 status; diff --git a/arch/s390/kernel/stacktrace.c b/arch/s390/kernel/stacktrace.c index 0d14a47..2e5c65a 100644 --- a/arch/s390/kernel/stacktrace.c +++ b/arch/s390/kernel/stacktrace.c @@ -11,11 +11,11 @@ #include #include #include -static inline unsigned long save_context_stack(struct stack_trace *trace, - unsigned int *skip, - unsigned long sp, - unsigned long low, - unsigned long high) +static unsigned long save_context_stack(struct stack_trace *trace, + unsigned int *skip, + unsigned long sp, + unsigned long low, + unsigned long high) { struct stack_frame *sf; struct pt_regs *regs; diff --git a/arch/s390/kernel/syscalls.S b/arch/s390/kernel/syscalls.S index a4ceae3..a52c444 100644 --- a/arch/s390/kernel/syscalls.S +++ b/arch/s390/kernel/syscalls.S @@ -124,7 +124,7 @@ NI_SYSCALL /* old "idle" system ca NI_SYSCALL /* vm86old for i386 */ SYSCALL(sys_wait4,sys_wait4,compat_sys_wait4_wrapper) SYSCALL(sys_swapoff,sys_swapoff,sys32_swapoff_wrapper) /* 115 */ -SYSCALL(sys_sysinfo,sys_sysinfo,sys32_sysinfo_wrapper) +SYSCALL(sys_sysinfo,sys_sysinfo,compat_sys_sysinfo_wrapper) SYSCALL(sys_ipc,sys_ipc,sys32_ipc_wrapper) SYSCALL(sys_fsync,sys_fsync,sys32_fsync_wrapper) SYSCALL(sys_sigreturn_glue,sys_sigreturn_glue,sys32_sigreturn_glue) diff --git a/arch/s390/kernel/time.c b/arch/s390/kernel/time.c index 6cceed4..ee9fd7b 100644 --- a/arch/s390/kernel/time.c +++ b/arch/s390/kernel/time.c @@ -37,11 +37,15 @@ #include #include #include #include +#include /* change this if you have some constant time drift */ #define USECS_PER_JIFFY ((unsigned long) 1000000/HZ) #define CLK_TICKS_PER_JIFFY ((unsigned long) USECS_PER_JIFFY << 12) +/* The value of the TOD clock for 1.1.1970. */ +#define TOD_UNIX_EPOCH 0x7d91048bca000000ULL + /* * Create a small time difference between the timer interrupts * on the different cpus to avoid lock contention. @@ -51,6 +55,7 @@ #define CPU_DEVIATION (smp_process #define TICK_SIZE tick static ext_int_info_t ext_int_info_cc; +static ext_int_info_t ext_int_etr_cc; static u64 init_timer_cc; static u64 jiffies_timer_cc; static u64 xtime_cc; @@ -89,29 +94,21 @@ #else #define s390_do_profile() do { ; } while(0) #endif /* CONFIG_PROFILING */ - /* - * timer_interrupt() needs to keep up the real-time clock, - * as well as call the "do_timer()" routine every clocktick + * Advance the per cpu tick counter up to the time given with the + * "time" argument. The per cpu update consists of accounting + * the virtual cpu time, calling update_process_times and calling + * the profiling hook. If xtime is before time it is advanced as well. */ -void account_ticks(void) +void account_ticks(u64 time) { - __u64 tmp; __u32 ticks; + __u64 tmp; /* Calculate how many ticks have passed. */ - if (S390_lowcore.int_clock < S390_lowcore.jiffy_timer) { - /* - * We have to program the clock comparator even if - * no tick has passed. That happens if e.g. an i/o - * interrupt wakes up an idle processor that has - * switched off its hz timer. - */ - tmp = S390_lowcore.jiffy_timer + CPU_DEVIATION; - asm volatile ("SCKC %0" : : "m" (tmp)); + if (time < S390_lowcore.jiffy_timer) return; - } - tmp = S390_lowcore.int_clock - S390_lowcore.jiffy_timer; + tmp = time - S390_lowcore.jiffy_timer; if (tmp >= 2*CLK_TICKS_PER_JIFFY) { /* more than two ticks ? */ ticks = __div(tmp, CLK_TICKS_PER_JIFFY) + 1; S390_lowcore.jiffy_timer += @@ -124,10 +121,6 @@ void account_ticks(void) S390_lowcore.jiffy_timer += CLK_TICKS_PER_JIFFY; } - /* set clock comparator for next tick */ - tmp = S390_lowcore.jiffy_timer + CPU_DEVIATION; - asm volatile ("SCKC %0" : : "m" (tmp)); - #ifdef CONFIG_SMP /* * Do not rely on the boot cpu to do the calls to do_timer. @@ -173,7 +166,7 @@ #endif * Stop the HZ tick on the current CPU. * Only cpu_idle may call this function. */ -static inline void stop_hz_timer(void) +static void stop_hz_timer(void) { unsigned long flags; unsigned long seq, next; @@ -210,20 +203,21 @@ static inline void stop_hz_timer(void) if (timer >= jiffies_timer_cc) todval = timer; } - asm volatile ("SCKC %0" : : "m" (todval)); + set_clock_comparator(todval); } /* * Start the HZ tick on the current CPU. * Only cpu_idle may call this function. */ -static inline void start_hz_timer(void) +static void start_hz_timer(void) { BUG_ON(!in_interrupt()); if (!cpu_isset(smp_processor_id(), nohz_cpu_mask)) return; - account_ticks(); + account_ticks(get_clock()); + set_clock_comparator(S390_lowcore.jiffy_timer + CPU_DEVIATION); cpu_clear(smp_processor_id(), nohz_cpu_mask); } @@ -245,7 +239,7 @@ static struct notifier_block nohz_idle_n .notifier_call = nohz_idle_notify, }; -void __init nohz_init(void) +static void __init nohz_init(void) { if (register_idle_notifier(&nohz_idle_nb)) panic("Couldn't register idle notifier"); @@ -254,24 +248,57 @@ void __init nohz_init(void) #endif /* - * Start the clock comparator on the current CPU. + * Set up per cpu jiffy timer and set the clock comparator. + */ +static void setup_jiffy_timer(void) +{ + /* Set up clock comparator to next jiffy. */ + S390_lowcore.jiffy_timer = + jiffies_timer_cc + (jiffies_64 + 1) * CLK_TICKS_PER_JIFFY; + set_clock_comparator(S390_lowcore.jiffy_timer + CPU_DEVIATION); +} + +/* + * Set up lowcore and control register of the current cpu to + * enable TOD clock and clock comparator interrupts. */ void init_cpu_timer(void) { - unsigned long cr0; - __u64 timer; + setup_jiffy_timer(); - timer = jiffies_timer_cc + jiffies_64 * CLK_TICKS_PER_JIFFY; - S390_lowcore.jiffy_timer = timer + CLK_TICKS_PER_JIFFY; - timer += CLK_TICKS_PER_JIFFY + CPU_DEVIATION; - asm volatile ("SCKC %0" : : "m" (timer)); - /* allow clock comparator timer interrupt */ - __ctl_store(cr0, 0, 0); - cr0 |= 0x800; - __ctl_load(cr0, 0, 0); + /* Enable clock comparator timer interrupt. */ + __ctl_set_bit(0,11); + + /* Always allow ETR external interrupts, even without an ETR. */ + __ctl_set_bit(0, 4); } -extern void vtime_init(void); +static void clock_comparator_interrupt(__u16 code) +{ + /* set clock comparator for next tick */ + set_clock_comparator(S390_lowcore.jiffy_timer + CPU_DEVIATION); +} + +static void etr_reset(void); +static void etr_init(void); +static void etr_ext_handler(__u16); + +/* + * Get the TOD clock running. + */ +static u64 __init reset_tod_clock(void) +{ + u64 time; + + etr_reset(); + if (store_clock(&time) == 0) + return time; + /* TOD clock not running. Set the clock to Unix Epoch. */ + if (set_clock(TOD_UNIX_EPOCH) != 0 || store_clock(&time) != 0) + panic("TOD clock not operational."); + + return TOD_UNIX_EPOCH; +} static cycle_t read_tod_clock(void) { @@ -285,7 +312,7 @@ static struct clocksource clocksource_to .mask = -1ULL, .mult = 1000, .shift = 12, - .is_continuous = 1, + .flags = CLOCK_SOURCE_IS_CONTINUOUS, }; @@ -295,48 +322,31 @@ static struct clocksource clocksource_to */ void __init time_init(void) { - __u64 set_time_cc; - int cc; - - /* kick the TOD clock */ - asm volatile( - " stck 0(%2)\n" - " ipm %0\n" - " srl %0,28" - : "=d" (cc), "=m" (init_timer_cc) - : "a" (&init_timer_cc) : "cc"); - switch (cc) { - case 0: /* clock in set state: all is fine */ - break; - case 1: /* clock in non-set state: FIXME */ - printk("time_init: TOD clock in non-set state\n"); - break; - case 2: /* clock in error state: FIXME */ - printk("time_init: TOD clock in error state\n"); - break; - case 3: /* clock in stopped or not-operational state: FIXME */ - printk("time_init: TOD clock stopped/non-operational\n"); - break; - } + init_timer_cc = reset_tod_clock(); + xtime_cc = init_timer_cc + CLK_TICKS_PER_JIFFY; jiffies_timer_cc = init_timer_cc - jiffies_64 * CLK_TICKS_PER_JIFFY; /* set xtime */ - xtime_cc = init_timer_cc + CLK_TICKS_PER_JIFFY; - set_time_cc = init_timer_cc - 0x8126d60e46000000LL + - (0x3c26700LL*1000000*4096); - tod_to_timeval(set_time_cc, &xtime); + tod_to_timeval(init_timer_cc - TOD_UNIX_EPOCH, &xtime); set_normalized_timespec(&wall_to_monotonic, -xtime.tv_sec, -xtime.tv_nsec); /* request the clock comparator external interrupt */ - if (register_early_external_interrupt(0x1004, NULL, + if (register_early_external_interrupt(0x1004, + clock_comparator_interrupt, &ext_int_info_cc) != 0) panic("Couldn't request external interrupt 0x1004"); if (clocksource_register(&clocksource_tod) != 0) panic("Could not register TOD clock source"); - init_cpu_timer(); + /* request the etr external interrupt */ + if (register_early_external_interrupt(0x1406, etr_ext_handler, + &ext_int_etr_cc) != 0) + panic("Couldn't request external interrupt 0x1406"); + + /* Enable TOD clock interrupts on the boot cpu. */ + init_cpu_timer(); #ifdef CONFIG_NO_IDLE_HZ nohz_init(); @@ -345,5 +355,1048 @@ #endif #ifdef CONFIG_VIRT_TIMER vtime_init(); #endif + etr_init(); +} + +/* + * External Time Reference (ETR) code. + */ +static int etr_port0_online; +static int etr_port1_online; + +static int __init early_parse_etr(char *p) +{ + if (strncmp(p, "off", 3) == 0) + etr_port0_online = etr_port1_online = 0; + else if (strncmp(p, "port0", 5) == 0) + etr_port0_online = 1; + else if (strncmp(p, "port1", 5) == 0) + etr_port1_online = 1; + else if (strncmp(p, "on", 2) == 0) + etr_port0_online = etr_port1_online = 1; + return 0; +} +early_param("etr", early_parse_etr); + +enum etr_event { + ETR_EVENT_PORT0_CHANGE, + ETR_EVENT_PORT1_CHANGE, + ETR_EVENT_PORT_ALERT, + ETR_EVENT_SYNC_CHECK, + ETR_EVENT_SWITCH_LOCAL, + ETR_EVENT_UPDATE, +}; + +enum etr_flags { + ETR_FLAG_ENOSYS, + ETR_FLAG_EACCES, + ETR_FLAG_STEAI, +}; + +/* + * Valid bit combinations of the eacr register are (x = don't care): + * e0 e1 dp p0 p1 ea es sl + * 0 0 x 0 0 0 0 0 initial, disabled state + * 0 0 x 0 1 1 0 0 port 1 online + * 0 0 x 1 0 1 0 0 port 0 online + * 0 0 x 1 1 1 0 0 both ports online + * 0 1 x 0 1 1 0 0 port 1 online and usable, ETR or PPS mode + * 0 1 x 0 1 1 0 1 port 1 online, usable and ETR mode + * 0 1 x 0 1 1 1 0 port 1 online, usable, PPS mode, in-sync + * 0 1 x 0 1 1 1 1 port 1 online, usable, ETR mode, in-sync + * 0 1 x 1 1 1 0 0 both ports online, port 1 usable + * 0 1 x 1 1 1 1 0 both ports online, port 1 usable, PPS mode, in-sync + * 0 1 x 1 1 1 1 1 both ports online, port 1 usable, ETR mode, in-sync + * 1 0 x 1 0 1 0 0 port 0 online and usable, ETR or PPS mode + * 1 0 x 1 0 1 0 1 port 0 online, usable and ETR mode + * 1 0 x 1 0 1 1 0 port 0 online, usable, PPS mode, in-sync + * 1 0 x 1 0 1 1 1 port 0 online, usable, ETR mode, in-sync + * 1 0 x 1 1 1 0 0 both ports online, port 0 usable + * 1 0 x 1 1 1 1 0 both ports online, port 0 usable, PPS mode, in-sync + * 1 0 x 1 1 1 1 1 both ports online, port 0 usable, ETR mode, in-sync + * 1 1 x 1 1 1 1 0 both ports online & usable, ETR, in-sync + * 1 1 x 1 1 1 1 1 both ports online & usable, ETR, in-sync + */ +static struct etr_eacr etr_eacr; +static u64 etr_tolec; /* time of last eacr update */ +static unsigned long etr_flags; +static struct etr_aib etr_port0; +static int etr_port0_uptodate; +static struct etr_aib etr_port1; +static int etr_port1_uptodate; +static unsigned long etr_events; +static struct timer_list etr_timer; +static struct tasklet_struct etr_tasklet; +static DEFINE_PER_CPU(atomic_t, etr_sync_word); + +static void etr_timeout(unsigned long dummy); +static void etr_tasklet_fn(unsigned long dummy); + +/* + * The etr get_clock function. It will write the current clock value + * to the clock pointer and return 0 if the clock is in sync with the + * external time source. If the clock mode is local it will return + * -ENOSYS and -EAGAIN if the clock is not in sync with the external + * reference. This function is what ETR is all about.. + */ +int get_sync_clock(unsigned long long *clock) +{ + atomic_t *sw_ptr; + unsigned int sw0, sw1; + + sw_ptr = &get_cpu_var(etr_sync_word); + sw0 = atomic_read(sw_ptr); + *clock = get_clock(); + sw1 = atomic_read(sw_ptr); + put_cpu_var(etr_sync_sync); + if (sw0 == sw1 && (sw0 & 0x80000000U)) + /* Success: time is in sync. */ + return 0; + if (test_bit(ETR_FLAG_ENOSYS, &etr_flags)) + return -ENOSYS; + if (test_bit(ETR_FLAG_EACCES, &etr_flags)) + return -EACCES; + return -EAGAIN; +} +EXPORT_SYMBOL(get_sync_clock); + +/* + * Make get_sync_clock return -EAGAIN. + */ +static void etr_disable_sync_clock(void *dummy) +{ + atomic_t *sw_ptr = &__get_cpu_var(etr_sync_word); + /* + * Clear the in-sync bit 2^31. All get_sync_clock calls will + * fail until the sync bit is turned back on. In addition + * increase the "sequence" counter to avoid the race of an + * etr event and the complete recovery against get_sync_clock. + */ + atomic_clear_mask(0x80000000, sw_ptr); + atomic_inc(sw_ptr); +} + +/* + * Make get_sync_clock return 0 again. + * Needs to be called from a context disabled for preemption. + */ +static void etr_enable_sync_clock(void) +{ + atomic_t *sw_ptr = &__get_cpu_var(etr_sync_word); + atomic_set_mask(0x80000000, sw_ptr); +} + +/* + * Reset ETR attachment. + */ +static void etr_reset(void) +{ + etr_eacr = (struct etr_eacr) { + .e0 = 0, .e1 = 0, ._pad0 = 4, .dp = 0, + .p0 = 0, .p1 = 0, ._pad1 = 0, .ea = 0, + .es = 0, .sl = 0 }; + if (etr_setr(&etr_eacr) == 0) + etr_tolec = get_clock(); + else { + set_bit(ETR_FLAG_ENOSYS, &etr_flags); + if (etr_port0_online || etr_port1_online) { + printk(KERN_WARNING "Running on non ETR capable " + "machine, only local mode available.\n"); + etr_port0_online = etr_port1_online = 0; + } + } +} + +static void etr_init(void) +{ + struct etr_aib aib; + + if (test_bit(ETR_FLAG_ENOSYS, &etr_flags)) + return; + /* Check if this machine has the steai instruction. */ + if (etr_steai(&aib, ETR_STEAI_STEPPING_PORT) == 0) + set_bit(ETR_FLAG_STEAI, &etr_flags); + setup_timer(&etr_timer, etr_timeout, 0UL); + tasklet_init(&etr_tasklet, etr_tasklet_fn, 0); + if (!etr_port0_online && !etr_port1_online) + set_bit(ETR_FLAG_EACCES, &etr_flags); + if (etr_port0_online) { + set_bit(ETR_EVENT_PORT0_CHANGE, &etr_events); + tasklet_hi_schedule(&etr_tasklet); + } + if (etr_port1_online) { + set_bit(ETR_EVENT_PORT1_CHANGE, &etr_events); + tasklet_hi_schedule(&etr_tasklet); + } +} + +/* + * Two sorts of ETR machine checks. The architecture reads: + * "When a machine-check niterruption occurs and if a switch-to-local or + * ETR-sync-check interrupt request is pending but disabled, this pending + * disabled interruption request is indicated and is cleared". + * Which means that we can get etr_switch_to_local events from the machine + * check handler although the interruption condition is disabled. Lovely.. + */ + +/* + * Switch to local machine check. This is called when the last usable + * ETR port goes inactive. After switch to local the clock is not in sync. + */ +void etr_switch_to_local(void) +{ + if (!etr_eacr.sl) + return; + etr_disable_sync_clock(NULL); + set_bit(ETR_EVENT_SWITCH_LOCAL, &etr_events); + tasklet_hi_schedule(&etr_tasklet); +} + +/* + * ETR sync check machine check. This is called when the ETR OTE and the + * local clock OTE are farther apart than the ETR sync check tolerance. + * After a ETR sync check the clock is not in sync. The machine check + * is broadcasted to all cpus at the same time. + */ +void etr_sync_check(void) +{ + if (!etr_eacr.es) + return; + etr_disable_sync_clock(NULL); + set_bit(ETR_EVENT_SYNC_CHECK, &etr_events); + tasklet_hi_schedule(&etr_tasklet); +} + +/* + * ETR external interrupt. There are two causes: + * 1) port state change, check the usability of the port + * 2) port alert, one of the ETR-data-validity bits (v1-v2 bits of the + * sldr-status word) or ETR-data word 1 (edf1) or ETR-data word 3 (edf3) + * or ETR-data word 4 (edf4) has changed. + */ +static void etr_ext_handler(__u16 code) +{ + struct etr_interruption_parameter *intparm = + (struct etr_interruption_parameter *) &S390_lowcore.ext_params; + + if (intparm->pc0) + /* ETR port 0 state change. */ + set_bit(ETR_EVENT_PORT0_CHANGE, &etr_events); + if (intparm->pc1) + /* ETR port 1 state change. */ + set_bit(ETR_EVENT_PORT1_CHANGE, &etr_events); + if (intparm->eai) + /* + * ETR port alert on either port 0, 1 or both. + * Both ports are not up-to-date now. + */ + set_bit(ETR_EVENT_PORT_ALERT, &etr_events); + tasklet_hi_schedule(&etr_tasklet); +} + +static void etr_timeout(unsigned long dummy) +{ + set_bit(ETR_EVENT_UPDATE, &etr_events); + tasklet_hi_schedule(&etr_tasklet); +} + +/* + * Check if the etr mode is pss. + */ +static inline int etr_mode_is_pps(struct etr_eacr eacr) +{ + return eacr.es && !eacr.sl; +} + +/* + * Check if the etr mode is etr. + */ +static inline int etr_mode_is_etr(struct etr_eacr eacr) +{ + return eacr.es && eacr.sl; +} + +/* + * Check if the port can be used for TOD synchronization. + * For PPS mode the port has to receive OTEs. For ETR mode + * the port has to receive OTEs, the ETR stepping bit has to + * be zero and the validity bits for data frame 1, 2, and 3 + * have to be 1. + */ +static int etr_port_valid(struct etr_aib *aib, int port) +{ + unsigned int psc; + + /* Check that this port is receiving OTEs. */ + if (aib->tsp == 0) + return 0; + + psc = port ? aib->esw.psc1 : aib->esw.psc0; + if (psc == etr_lpsc_pps_mode) + return 1; + if (psc == etr_lpsc_operational_step) + return !aib->esw.y && aib->slsw.v1 && + aib->slsw.v2 && aib->slsw.v3; + return 0; +} + +/* + * Check if two ports are on the same network. + */ +static int etr_compare_network(struct etr_aib *aib1, struct etr_aib *aib2) +{ + // FIXME: any other fields we have to compare? + return aib1->edf1.net_id == aib2->edf1.net_id; +} + +/* + * Wrapper for etr_stei that converts physical port states + * to logical port states to be consistent with the output + * of stetr (see etr_psc vs. etr_lpsc). + */ +static void etr_steai_cv(struct etr_aib *aib, unsigned int func) +{ + BUG_ON(etr_steai(aib, func) != 0); + /* Convert port state to logical port state. */ + if (aib->esw.psc0 == 1) + aib->esw.psc0 = 2; + else if (aib->esw.psc0 == 0 && aib->esw.p == 0) + aib->esw.psc0 = 1; + if (aib->esw.psc1 == 1) + aib->esw.psc1 = 2; + else if (aib->esw.psc1 == 0 && aib->esw.p == 1) + aib->esw.psc1 = 1; +} + +/* + * Check if the aib a2 is still connected to the same attachment as + * aib a1, the etv values differ by one and a2 is valid. + */ +static int etr_aib_follows(struct etr_aib *a1, struct etr_aib *a2, int p) +{ + int state_a1, state_a2; + + /* Paranoia check: e0/e1 should better be the same. */ + if (a1->esw.eacr.e0 != a2->esw.eacr.e0 || + a1->esw.eacr.e1 != a2->esw.eacr.e1) + return 0; + + /* Still connected to the same etr ? */ + state_a1 = p ? a1->esw.psc1 : a1->esw.psc0; + state_a2 = p ? a2->esw.psc1 : a2->esw.psc0; + if (state_a1 == etr_lpsc_operational_step) { + if (state_a2 != etr_lpsc_operational_step || + a1->edf1.net_id != a2->edf1.net_id || + a1->edf1.etr_id != a2->edf1.etr_id || + a1->edf1.etr_pn != a2->edf1.etr_pn) + return 0; + } else if (state_a2 != etr_lpsc_pps_mode) + return 0; + + /* The ETV value of a2 needs to be ETV of a1 + 1. */ + if (a1->edf2.etv + 1 != a2->edf2.etv) + return 0; + + if (!etr_port_valid(a2, p)) + return 0; + + return 1; +} + +/* + * The time is "clock". xtime is what we think the time is. + * Adjust the value by a multiple of jiffies and add the delta to ntp. + * "delay" is an approximation how long the synchronization took. If + * the time correction is positive, then "delay" is subtracted from + * the time difference and only the remaining part is passed to ntp. + */ +static void etr_adjust_time(unsigned long long clock, unsigned long long delay) +{ + unsigned long long delta, ticks; + struct timex adjust; + + /* + * We don't have to take the xtime lock because the cpu + * executing etr_adjust_time is running disabled in + * tasklet context and all other cpus are looping in + * etr_sync_cpu_start. + */ + if (clock > xtime_cc) { + /* It is later than we thought. */ + delta = ticks = clock - xtime_cc; + delta = ticks = (delta < delay) ? 0 : delta - delay; + delta -= do_div(ticks, CLK_TICKS_PER_JIFFY); + init_timer_cc = init_timer_cc + delta; + jiffies_timer_cc = jiffies_timer_cc + delta; + xtime_cc = xtime_cc + delta; + adjust.offset = ticks * (1000000 / HZ); + } else { + /* It is earlier than we thought. */ + delta = ticks = xtime_cc - clock; + delta -= do_div(ticks, CLK_TICKS_PER_JIFFY); + init_timer_cc = init_timer_cc - delta; + jiffies_timer_cc = jiffies_timer_cc - delta; + xtime_cc = xtime_cc - delta; + adjust.offset = -ticks * (1000000 / HZ); + } + if (adjust.offset != 0) { + printk(KERN_NOTICE "etr: time adjusted by %li micro-seconds\n", + adjust.offset); + adjust.modes = ADJ_OFFSET_SINGLESHOT; + do_adjtimex(&adjust); + } +} + +static void etr_sync_cpu_start(void *dummy) +{ + int *in_sync = dummy; + + etr_enable_sync_clock(); + /* + * This looks like a busy wait loop but it isn't. etr_sync_cpus + * is called on all other cpus while the TOD clocks is stopped. + * __udelay will stop the cpu on an enabled wait psw until the + * TOD is running again. + */ + while (*in_sync == 0) + __udelay(1); + if (*in_sync != 1) + /* Didn't work. Clear per-cpu in sync bit again. */ + etr_disable_sync_clock(NULL); + /* + * This round of TOD syncing is done. Set the clock comparator + * to the next tick and let the processor continue. + */ + setup_jiffy_timer(); +} + +static void etr_sync_cpu_end(void *dummy) +{ +} + +/* + * Sync the TOD clock using the port refered to by aibp. This port + * has to be enabled and the other port has to be disabled. The + * last eacr update has to be more than 1.6 seconds in the past. + */ +static int etr_sync_clock(struct etr_aib *aib, int port) +{ + struct etr_aib *sync_port; + unsigned long long clock, delay; + int in_sync, follows; + int rc; + + /* Check if the current aib is adjacent to the sync port aib. */ + sync_port = (port == 0) ? &etr_port0 : &etr_port1; + follows = etr_aib_follows(sync_port, aib, port); + memcpy(sync_port, aib, sizeof(*aib)); + if (!follows) + return -EAGAIN; + + /* + * Catch all other cpus and make them wait until we have + * successfully synced the clock. smp_call_function will + * return after all other cpus are in etr_sync_cpu_start. + */ + in_sync = 0; + preempt_disable(); + smp_call_function(etr_sync_cpu_start,&in_sync,0,0); + local_irq_disable(); + etr_enable_sync_clock(); + + /* Set clock to next OTE. */ + __ctl_set_bit(14, 21); + __ctl_set_bit(0, 29); + clock = ((unsigned long long) (aib->edf2.etv + 1)) << 32; + if (set_clock(clock) == 0) { + __udelay(1); /* Wait for the clock to start. */ + __ctl_clear_bit(0, 29); + __ctl_clear_bit(14, 21); + etr_stetr(aib); + /* Adjust Linux timing variables. */ + delay = (unsigned long long) + (aib->edf2.etv - sync_port->edf2.etv) << 32; + etr_adjust_time(clock, delay); + setup_jiffy_timer(); + /* Verify that the clock is properly set. */ + if (!etr_aib_follows(sync_port, aib, port)) { + /* Didn't work. */ + etr_disable_sync_clock(NULL); + in_sync = -EAGAIN; + rc = -EAGAIN; + } else { + in_sync = 1; + rc = 0; + } + } else { + /* Could not set the clock ?!? */ + __ctl_clear_bit(0, 29); + __ctl_clear_bit(14, 21); + etr_disable_sync_clock(NULL); + in_sync = -EAGAIN; + rc = -EAGAIN; + } + local_irq_enable(); + smp_call_function(etr_sync_cpu_end,NULL,0,0); + preempt_enable(); + return rc; +} + +/* + * Handle the immediate effects of the different events. + * The port change event is used for online/offline changes. + */ +static struct etr_eacr etr_handle_events(struct etr_eacr eacr) +{ + if (test_and_clear_bit(ETR_EVENT_SYNC_CHECK, &etr_events)) + eacr.es = 0; + if (test_and_clear_bit(ETR_EVENT_SWITCH_LOCAL, &etr_events)) + eacr.es = eacr.sl = 0; + if (test_and_clear_bit(ETR_EVENT_PORT_ALERT, &etr_events)) + etr_port0_uptodate = etr_port1_uptodate = 0; + + if (test_and_clear_bit(ETR_EVENT_PORT0_CHANGE, &etr_events)) { + if (eacr.e0) + /* + * Port change of an enabled port. We have to + * assume that this can have caused an stepping + * port switch. + */ + etr_tolec = get_clock(); + eacr.p0 = etr_port0_online; + if (!eacr.p0) + eacr.e0 = 0; + etr_port0_uptodate = 0; + } + if (test_and_clear_bit(ETR_EVENT_PORT1_CHANGE, &etr_events)) { + if (eacr.e1) + /* + * Port change of an enabled port. We have to + * assume that this can have caused an stepping + * port switch. + */ + etr_tolec = get_clock(); + eacr.p1 = etr_port1_online; + if (!eacr.p1) + eacr.e1 = 0; + etr_port1_uptodate = 0; + } + clear_bit(ETR_EVENT_UPDATE, &etr_events); + return eacr; +} + +/* + * Set up a timer that expires after the etr_tolec + 1.6 seconds if + * one of the ports needs an update. + */ +static void etr_set_tolec_timeout(unsigned long long now) +{ + unsigned long micros; + + if ((!etr_eacr.p0 || etr_port0_uptodate) && + (!etr_eacr.p1 || etr_port1_uptodate)) + return; + micros = (now > etr_tolec) ? ((now - etr_tolec) >> 12) : 0; + micros = (micros > 1600000) ? 0 : 1600000 - micros; + mod_timer(&etr_timer, jiffies + (micros * HZ) / 1000000 + 1); +} + +/* + * Set up a time that expires after 1/2 second. + */ +static void etr_set_sync_timeout(void) +{ + mod_timer(&etr_timer, jiffies + HZ/2); +} + +/* + * Update the aib information for one or both ports. + */ +static struct etr_eacr etr_handle_update(struct etr_aib *aib, + struct etr_eacr eacr) +{ + /* With both ports disabled the aib information is useless. */ + if (!eacr.e0 && !eacr.e1) + return eacr; + + /* Update port0 or port1 with aib stored in etr_tasklet_fn. */ + if (aib->esw.q == 0) { + /* Information for port 0 stored. */ + if (eacr.p0 && !etr_port0_uptodate) { + etr_port0 = *aib; + if (etr_port0_online) + etr_port0_uptodate = 1; + } + } else { + /* Information for port 1 stored. */ + if (eacr.p1 && !etr_port1_uptodate) { + etr_port1 = *aib; + if (etr_port0_online) + etr_port1_uptodate = 1; + } + } + + /* + * Do not try to get the alternate port aib if the clock + * is not in sync yet. + */ + if (!eacr.es) + return eacr; + + /* + * If steai is available we can get the information about + * the other port immediately. If only stetr is available the + * data-port bit toggle has to be used. + */ + if (test_bit(ETR_FLAG_STEAI, &etr_flags)) { + if (eacr.p0 && !etr_port0_uptodate) { + etr_steai_cv(&etr_port0, ETR_STEAI_PORT_0); + etr_port0_uptodate = 1; + } + if (eacr.p1 && !etr_port1_uptodate) { + etr_steai_cv(&etr_port1, ETR_STEAI_PORT_1); + etr_port1_uptodate = 1; + } + } else { + /* + * One port was updated above, if the other + * port is not uptodate toggle dp bit. + */ + if ((eacr.p0 && !etr_port0_uptodate) || + (eacr.p1 && !etr_port1_uptodate)) + eacr.dp ^= 1; + else + eacr.dp = 0; + } + return eacr; +} + +/* + * Write new etr control register if it differs from the current one. + * Return 1 if etr_tolec has been updated as well. + */ +static void etr_update_eacr(struct etr_eacr eacr) +{ + int dp_changed; + + if (memcmp(&etr_eacr, &eacr, sizeof(eacr)) == 0) + /* No change, return. */ + return; + /* + * The disable of an active port of the change of the data port + * bit can/will cause a change in the data port. + */ + dp_changed = etr_eacr.e0 > eacr.e0 || etr_eacr.e1 > eacr.e1 || + (etr_eacr.dp ^ eacr.dp) != 0; + etr_eacr = eacr; + etr_setr(&etr_eacr); + if (dp_changed) + etr_tolec = get_clock(); +} + +/* + * ETR tasklet. In this function you'll find the main logic. In + * particular this is the only function that calls etr_update_eacr(), + * it "controls" the etr control register. + */ +static void etr_tasklet_fn(unsigned long dummy) +{ + unsigned long long now; + struct etr_eacr eacr; + struct etr_aib aib; + int sync_port; + + /* Create working copy of etr_eacr. */ + eacr = etr_eacr; + + /* Check for the different events and their immediate effects. */ + eacr = etr_handle_events(eacr); + + /* Check if ETR is supposed to be active. */ + eacr.ea = eacr.p0 || eacr.p1; + if (!eacr.ea) { + /* Both ports offline. Reset everything. */ + eacr.dp = eacr.es = eacr.sl = 0; + on_each_cpu(etr_disable_sync_clock, NULL, 0, 1); + del_timer_sync(&etr_timer); + etr_update_eacr(eacr); + set_bit(ETR_FLAG_EACCES, &etr_flags); + return; + } + + /* Store aib to get the current ETR status word. */ + BUG_ON(etr_stetr(&aib) != 0); + etr_port0.esw = etr_port1.esw = aib.esw; /* Copy status word. */ + now = get_clock(); + + /* + * Update the port information if the last stepping port change + * or data port change is older than 1.6 seconds. + */ + if (now >= etr_tolec + (1600000 << 12)) + eacr = etr_handle_update(&aib, eacr); + + /* + * Select ports to enable. The prefered synchronization mode is PPS. + * If a port can be enabled depends on a number of things: + * 1) The port needs to be online and uptodate. A port is not + * disabled just because it is not uptodate, but it is only + * enabled if it is uptodate. + * 2) The port needs to have the same mode (pps / etr). + * 3) The port needs to be usable -> etr_port_valid() == 1 + * 4) To enable the second port the clock needs to be in sync. + * 5) If both ports are useable and are ETR ports, the network id + * has to be the same. + * The eacr.sl bit is used to indicate etr mode vs. pps mode. + */ + if (eacr.p0 && aib.esw.psc0 == etr_lpsc_pps_mode) { + eacr.sl = 0; + eacr.e0 = 1; + if (!etr_mode_is_pps(etr_eacr)) + eacr.es = 0; + if (!eacr.es || !eacr.p1 || aib.esw.psc1 != etr_lpsc_pps_mode) + eacr.e1 = 0; + // FIXME: uptodate checks ? + else if (etr_port0_uptodate && etr_port1_uptodate) + eacr.e1 = 1; + sync_port = (etr_port0_uptodate && + etr_port_valid(&etr_port0, 0)) ? 0 : -1; + clear_bit(ETR_FLAG_EACCES, &etr_flags); + } else if (eacr.p1 && aib.esw.psc1 == etr_lpsc_pps_mode) { + eacr.sl = 0; + eacr.e0 = 0; + eacr.e1 = 1; + if (!etr_mode_is_pps(etr_eacr)) + eacr.es = 0; + sync_port = (etr_port1_uptodate && + etr_port_valid(&etr_port1, 1)) ? 1 : -1; + clear_bit(ETR_FLAG_EACCES, &etr_flags); + } else if (eacr.p0 && aib.esw.psc0 == etr_lpsc_operational_step) { + eacr.sl = 1; + eacr.e0 = 1; + if (!etr_mode_is_etr(etr_eacr)) + eacr.es = 0; + if (!eacr.es || !eacr.p1 || + aib.esw.psc1 != etr_lpsc_operational_alt) + eacr.e1 = 0; + else if (etr_port0_uptodate && etr_port1_uptodate && + etr_compare_network(&etr_port0, &etr_port1)) + eacr.e1 = 1; + sync_port = (etr_port0_uptodate && + etr_port_valid(&etr_port0, 0)) ? 0 : -1; + clear_bit(ETR_FLAG_EACCES, &etr_flags); + } else if (eacr.p1 && aib.esw.psc1 == etr_lpsc_operational_step) { + eacr.sl = 1; + eacr.e0 = 0; + eacr.e1 = 1; + if (!etr_mode_is_etr(etr_eacr)) + eacr.es = 0; + sync_port = (etr_port1_uptodate && + etr_port_valid(&etr_port1, 1)) ? 1 : -1; + clear_bit(ETR_FLAG_EACCES, &etr_flags); + } else { + /* Both ports not usable. */ + eacr.es = eacr.sl = 0; + sync_port = -1; + set_bit(ETR_FLAG_EACCES, &etr_flags); + } + + /* + * If the clock is in sync just update the eacr and return. + * If there is no valid sync port wait for a port update. + */ + if (eacr.es || sync_port < 0) { + etr_update_eacr(eacr); + etr_set_tolec_timeout(now); + return; + } + + /* + * Prepare control register for clock syncing + * (reset data port bit, set sync check control. + */ + eacr.dp = 0; + eacr.es = 1; + + /* + * Update eacr and try to synchronize the clock. If the update + * of eacr caused a stepping port switch (or if we have to + * assume that a stepping port switch has occured) or the + * clock syncing failed, reset the sync check control bit + * and set up a timer to try again after 0.5 seconds + */ + etr_update_eacr(eacr); + if (now < etr_tolec + (1600000 << 12) || + etr_sync_clock(&aib, sync_port) != 0) { + /* Sync failed. Try again in 1/2 second. */ + eacr.es = 0; + etr_update_eacr(eacr); + etr_set_sync_timeout(); + } else + etr_set_tolec_timeout(now); +} + +/* + * Sysfs interface functions + */ +static struct sysdev_class etr_sysclass = { + set_kset_name("etr") +}; + +static struct sys_device etr_port0_dev = { + .id = 0, + .cls = &etr_sysclass, +}; + +static struct sys_device etr_port1_dev = { + .id = 1, + .cls = &etr_sysclass, +}; + +/* + * ETR class attributes + */ +static ssize_t etr_stepping_port_show(struct sysdev_class *class, char *buf) +{ + return sprintf(buf, "%i\n", etr_port0.esw.p); +} + +static SYSDEV_CLASS_ATTR(stepping_port, 0400, etr_stepping_port_show, NULL); + +static ssize_t etr_stepping_mode_show(struct sysdev_class *class, char *buf) +{ + char *mode_str; + + if (etr_mode_is_pps(etr_eacr)) + mode_str = "pps"; + else if (etr_mode_is_etr(etr_eacr)) + mode_str = "etr"; + else + mode_str = "local"; + return sprintf(buf, "%s\n", mode_str); +} + +static SYSDEV_CLASS_ATTR(stepping_mode, 0400, etr_stepping_mode_show, NULL); + +/* + * ETR port attributes + */ +static inline struct etr_aib *etr_aib_from_dev(struct sys_device *dev) +{ + if (dev == &etr_port0_dev) + return etr_port0_online ? &etr_port0 : NULL; + else + return etr_port1_online ? &etr_port1 : NULL; +} + +static ssize_t etr_online_show(struct sys_device *dev, char *buf) +{ + unsigned int online; + + online = (dev == &etr_port0_dev) ? etr_port0_online : etr_port1_online; + return sprintf(buf, "%i\n", online); +} + +static ssize_t etr_online_store(struct sys_device *dev, + const char *buf, size_t count) +{ + unsigned int value; + + value = simple_strtoul(buf, NULL, 0); + if (value != 0 && value != 1) + return -EINVAL; + if (test_bit(ETR_FLAG_ENOSYS, &etr_flags)) + return -ENOSYS; + if (dev == &etr_port0_dev) { + if (etr_port0_online == value) + return count; /* Nothing to do. */ + etr_port0_online = value; + set_bit(ETR_EVENT_PORT0_CHANGE, &etr_events); + tasklet_hi_schedule(&etr_tasklet); + } else { + if (etr_port1_online == value) + return count; /* Nothing to do. */ + etr_port1_online = value; + set_bit(ETR_EVENT_PORT1_CHANGE, &etr_events); + tasklet_hi_schedule(&etr_tasklet); + } + return count; +} + +static SYSDEV_ATTR(online, 0600, etr_online_show, etr_online_store); + +static ssize_t etr_stepping_control_show(struct sys_device *dev, char *buf) +{ + return sprintf(buf, "%i\n", (dev == &etr_port0_dev) ? + etr_eacr.e0 : etr_eacr.e1); +} + +static SYSDEV_ATTR(stepping_control, 0400, etr_stepping_control_show, NULL); + +static ssize_t etr_mode_code_show(struct sys_device *dev, char *buf) +{ + if (!etr_port0_online && !etr_port1_online) + /* Status word is not uptodate if both ports are offline. */ + return -ENODATA; + return sprintf(buf, "%i\n", (dev == &etr_port0_dev) ? + etr_port0.esw.psc0 : etr_port0.esw.psc1); +} + +static SYSDEV_ATTR(state_code, 0400, etr_mode_code_show, NULL); + +static ssize_t etr_untuned_show(struct sys_device *dev, char *buf) +{ + struct etr_aib *aib = etr_aib_from_dev(dev); + + if (!aib || !aib->slsw.v1) + return -ENODATA; + return sprintf(buf, "%i\n", aib->edf1.u); +} + +static SYSDEV_ATTR(untuned, 0400, etr_untuned_show, NULL); + +static ssize_t etr_network_id_show(struct sys_device *dev, char *buf) +{ + struct etr_aib *aib = etr_aib_from_dev(dev); + + if (!aib || !aib->slsw.v1) + return -ENODATA; + return sprintf(buf, "%i\n", aib->edf1.net_id); +} + +static SYSDEV_ATTR(network, 0400, etr_network_id_show, NULL); + +static ssize_t etr_id_show(struct sys_device *dev, char *buf) +{ + struct etr_aib *aib = etr_aib_from_dev(dev); + + if (!aib || !aib->slsw.v1) + return -ENODATA; + return sprintf(buf, "%i\n", aib->edf1.etr_id); +} + +static SYSDEV_ATTR(id, 0400, etr_id_show, NULL); + +static ssize_t etr_port_number_show(struct sys_device *dev, char *buf) +{ + struct etr_aib *aib = etr_aib_from_dev(dev); + + if (!aib || !aib->slsw.v1) + return -ENODATA; + return sprintf(buf, "%i\n", aib->edf1.etr_pn); +} + +static SYSDEV_ATTR(port, 0400, etr_port_number_show, NULL); + +static ssize_t etr_coupled_show(struct sys_device *dev, char *buf) +{ + struct etr_aib *aib = etr_aib_from_dev(dev); + + if (!aib || !aib->slsw.v3) + return -ENODATA; + return sprintf(buf, "%i\n", aib->edf3.c); +} + +static SYSDEV_ATTR(coupled, 0400, etr_coupled_show, NULL); + +static ssize_t etr_local_time_show(struct sys_device *dev, char *buf) +{ + struct etr_aib *aib = etr_aib_from_dev(dev); + + if (!aib || !aib->slsw.v3) + return -ENODATA; + return sprintf(buf, "%i\n", aib->edf3.blto); +} + +static SYSDEV_ATTR(local_time, 0400, etr_local_time_show, NULL); + +static ssize_t etr_utc_offset_show(struct sys_device *dev, char *buf) +{ + struct etr_aib *aib = etr_aib_from_dev(dev); + + if (!aib || !aib->slsw.v3) + return -ENODATA; + return sprintf(buf, "%i\n", aib->edf3.buo); +} + +static SYSDEV_ATTR(utc_offset, 0400, etr_utc_offset_show, NULL); + +static struct sysdev_attribute *etr_port_attributes[] = { + &attr_online, + &attr_stepping_control, + &attr_state_code, + &attr_untuned, + &attr_network, + &attr_id, + &attr_port, + &attr_coupled, + &attr_local_time, + &attr_utc_offset, + NULL +}; + +static int __init etr_register_port(struct sys_device *dev) +{ + struct sysdev_attribute **attr; + int rc; + + rc = sysdev_register(dev); + if (rc) + goto out; + for (attr = etr_port_attributes; *attr; attr++) { + rc = sysdev_create_file(dev, *attr); + if (rc) + goto out_unreg; + } + return 0; +out_unreg: + for (; attr >= etr_port_attributes; attr--) + sysdev_remove_file(dev, *attr); + sysdev_unregister(dev); +out: + return rc; +} + +static void __init etr_unregister_port(struct sys_device *dev) +{ + struct sysdev_attribute **attr; + + for (attr = etr_port_attributes; *attr; attr++) + sysdev_remove_file(dev, *attr); + sysdev_unregister(dev); +} + +static int __init etr_init_sysfs(void) +{ + int rc; + + rc = sysdev_class_register(&etr_sysclass); + if (rc) + goto out; + rc = sysdev_class_create_file(&etr_sysclass, &attr_stepping_port); + if (rc) + goto out_unreg_class; + rc = sysdev_class_create_file(&etr_sysclass, &attr_stepping_mode); + if (rc) + goto out_remove_stepping_port; + rc = etr_register_port(&etr_port0_dev); + if (rc) + goto out_remove_stepping_mode; + rc = etr_register_port(&etr_port1_dev); + if (rc) + goto out_remove_port0; + return 0; + +out_remove_port0: + etr_unregister_port(&etr_port0_dev); +out_remove_stepping_mode: + sysdev_class_remove_file(&etr_sysclass, &attr_stepping_mode); +out_remove_stepping_port: + sysdev_class_remove_file(&etr_sysclass, &attr_stepping_port); +out_unreg_class: + sysdev_class_unregister(&etr_sysclass); +out: + return rc; } +device_initcall(etr_init_sysfs); diff --git a/arch/s390/kernel/traps.c b/arch/s390/kernel/traps.c index 3cbb0dc..f0e5a32 100644 --- a/arch/s390/kernel/traps.c +++ b/arch/s390/kernel/traps.c @@ -283,7 +283,7 @@ char *task_show_regs(struct task_struct return buffer; } -DEFINE_SPINLOCK(die_lock); +static DEFINE_SPINLOCK(die_lock); void die(const char * str, struct pt_regs * regs, long err) { @@ -364,8 +364,7 @@ void __kprobes do_single_step(struct pt_ force_sig(SIGTRAP, current); } -asmlinkage void -default_trap_handler(struct pt_regs * regs, long interruption_code) +static void default_trap_handler(struct pt_regs * regs, long interruption_code) { if (regs->psw.mask & PSW_MASK_PSTATE) { local_irq_enable(); @@ -376,7 +375,7 @@ default_trap_handler(struct pt_regs * re } #define DO_ERROR_INFO(signr, str, name, sicode, siaddr) \ -asmlinkage void name(struct pt_regs * regs, long interruption_code) \ +static void name(struct pt_regs * regs, long interruption_code) \ { \ siginfo_t info; \ info.si_signo = signr; \ @@ -442,7 +441,7 @@ do_fp_trap(struct pt_regs *regs, void __ "floating point exception", regs, &si); } -asmlinkage void illegal_op(struct pt_regs * regs, long interruption_code) +static void illegal_op(struct pt_regs * regs, long interruption_code) { siginfo_t info; __u8 opcode[6]; @@ -491,8 +490,15 @@ #ifdef CONFIG_MATHEMU #endif } else signal = SIGILL; - } else - signal = SIGILL; + } else { + /* + * If we get an illegal op in kernel mode, send it through the + * kprobes notifier. If kprobes doesn't pick it up, SIGILL + */ + if (notify_die(DIE_BPT, "bpt", regs, interruption_code, + 3, SIGTRAP) != NOTIFY_STOP) + signal = SIGILL; + } #ifdef CONFIG_MATHEMU if (signal == SIGFPE) @@ -585,7 +591,7 @@ DO_ERROR_INFO(SIGILL, "specification exc ILL_ILLOPN, get_check_address(regs)); #endif -asmlinkage void data_exception(struct pt_regs * regs, long interruption_code) +static void data_exception(struct pt_regs * regs, long interruption_code) { __u16 __user *location; int signal = 0; @@ -675,7 +681,7 @@ #endif } } -asmlinkage void space_switch_exception(struct pt_regs * regs, long int_code) +static void space_switch_exception(struct pt_regs * regs, long int_code) { siginfo_t info; diff --git a/arch/s390/kernel/vmlinux.lds.S b/arch/s390/kernel/vmlinux.lds.S index fe0f2e9..c30716a 100644 --- a/arch/s390/kernel/vmlinux.lds.S +++ b/arch/s390/kernel/vmlinux.lds.S @@ -31,18 +31,19 @@ SECTIONS _etext = .; /* End of text section */ - . = ALIGN(16); /* Exception table */ - __start___ex_table = .; - __ex_table : { *(__ex_table) } - __stop___ex_table = .; - RODATA #ifdef CONFIG_SHARED_KERNEL . = ALIGN(1048576); /* VM shared segments are 1MB aligned */ +#endif + . = ALIGN(4096); _eshared = .; /* End of shareable data */ -#endif + + . = ALIGN(16); /* Exception table */ + __start___ex_table = .; + __ex_table : { *(__ex_table) } + __stop___ex_table = .; .data : { /* Data */ *(.data) @@ -90,11 +91,14 @@ #endif .con_initcall.init : { *(.con_initcall.init) } __con_initcall_end = .; SECURITY_INIT + +#ifdef CONFIG_BLK_DEV_INITRD . = ALIGN(256); __initramfs_start = .; .init.ramfs : { *(.init.initramfs) } . = ALIGN(2); __initramfs_end = .; +#endif . = ALIGN(256); __per_cpu_start = .; .data.percpu : { *(.data.percpu) } diff --git a/arch/s390/kernel/vtime.c b/arch/s390/kernel/vtime.c index 21baaf5..9d5b028 100644 --- a/arch/s390/kernel/vtime.c +++ b/arch/s390/kernel/vtime.c @@ -25,7 +25,7 @@ #include #include static ext_int_info_t ext_int_info_timer; -DEFINE_PER_CPU(struct vtimer_queue, virt_cpu_timer); +static DEFINE_PER_CPU(struct vtimer_queue, virt_cpu_timer); #ifdef CONFIG_VIRT_CPU_ACCOUNTING /* @@ -524,16 +524,15 @@ EXPORT_SYMBOL(del_virt_timer); void init_cpu_vtimer(void) { struct vtimer_queue *vt_list; - unsigned long cr0; /* kick the virtual timer */ S390_lowcore.exit_timer = VTIMER_MAX_SLICE; S390_lowcore.last_update_timer = VTIMER_MAX_SLICE; asm volatile ("SPT %0" : : "m" (S390_lowcore.last_update_timer)); asm volatile ("STCK %0" : "=m" (S390_lowcore.last_update_clock)); - __ctl_store(cr0, 0, 0); - cr0 |= 0x400; - __ctl_load(cr0, 0, 0); + + /* enable cpu timer interrupts */ + __ctl_set_bit(0,10); vt_list = &per_cpu(virt_cpu_timer, smp_processor_id()); INIT_LIST_HEAD(&vt_list->list); @@ -572,6 +571,7 @@ void __init vtime_init(void) if (register_idle_notifier(&vtimer_idle_nb)) panic("Couldn't register idle notifier"); + /* Enable cpu timer interrupts on the boot cpu. */ init_cpu_vtimer(); } diff --git a/arch/s390/lib/Makefile b/arch/s390/lib/Makefile index b5f94cf..7a44fed 100644 --- a/arch/s390/lib/Makefile +++ b/arch/s390/lib/Makefile @@ -4,7 +4,7 @@ # EXTRA_AFLAGS := -traditional -lib-y += delay.o string.o uaccess_std.o uaccess_pt.o +lib-y += delay.o string.o uaccess_std.o uaccess_pt.o qrnnd.o lib-$(CONFIG_32BIT) += div64.o lib-$(CONFIG_64BIT) += uaccess_mvcos.o lib-$(CONFIG_SMP) += spinlock.o diff --git a/arch/s390/lib/delay.c b/arch/s390/lib/delay.c index 027c474..0285444 100644 --- a/arch/s390/lib/delay.c +++ b/arch/s390/lib/delay.c @@ -1,5 +1,5 @@ /* - * arch/s390/kernel/delay.c + * arch/s390/lib/delay.c * Precise Delay Loops for S390 * * S390 version @@ -13,10 +13,8 @@ #include #include - -#ifdef CONFIG_SMP -#include -#endif +#include +#include void __delay(unsigned long loops) { @@ -31,17 +29,39 @@ void __delay(unsigned long loops) } /* - * Waits for 'usecs' microseconds using the tod clock, giving up the time slice - * of the virtual PU inbetween to avoid congestion. + * Waits for 'usecs' microseconds using the TOD clock comparator. */ void __udelay(unsigned long usecs) { - uint64_t start_cc; + u64 end, time, jiffy_timer = 0; + unsigned long flags, cr0, mask, dummy; + + local_irq_save(flags); + if (raw_irqs_disabled_flags(flags)) { + jiffy_timer = S390_lowcore.jiffy_timer; + S390_lowcore.jiffy_timer = -1ULL - (4096 << 12); + __ctl_store(cr0, 0, 0); + dummy = (cr0 & 0xffff00e0) | 0x00000800; + __ctl_load(dummy , 0, 0); + mask = psw_kernel_bits | PSW_MASK_WAIT | PSW_MASK_EXT; + } else + mask = psw_kernel_bits | PSW_MASK_WAIT | + PSW_MASK_EXT | PSW_MASK_IO; + + end = get_clock() + ((u64) usecs << 12); + do { + time = end < S390_lowcore.jiffy_timer ? + end : S390_lowcore.jiffy_timer; + set_clock_comparator(time); + trace_hardirqs_on(); + __load_psw_mask(mask); + local_irq_disable(); + } while (get_clock() < end); - if (usecs == 0) - return; - start_cc = get_clock(); - do { - cpu_relax(); - } while (((get_clock() - start_cc)/4096) < usecs); + if (raw_irqs_disabled_flags(flags)) { + __ctl_load(cr0, 0, 0); + S390_lowcore.jiffy_timer = jiffy_timer; + } + set_clock_comparator(S390_lowcore.jiffy_timer); + local_irq_restore(flags); } diff --git a/arch/s390/lib/qrnnd.S b/arch/s390/lib/qrnnd.S new file mode 100644 index 0000000..eb1df63 --- /dev/null +++ b/arch/s390/lib/qrnnd.S @@ -0,0 +1,77 @@ +# S/390 __udiv_qrnnd + +# r2 : &__r +# r3 : upper half of 64 bit word n +# r4 : lower half of 64 bit word n +# r5 : divisor d +# the reminder r of the division is to be stored to &__r and +# the quotient q is to be returned + + .text + .globl __udiv_qrnnd +__udiv_qrnnd: + st %r2,24(%r15) # store pointer to reminder for later + lr %r0,%r3 # reload n + lr %r1,%r4 + ltr %r2,%r5 # reload and test divisor + jp 5f + # divisor >= 0x80000000 + srdl %r0,2 # n/4 + srl %r2,1 # d/2 + slr %r1,%r2 # special case if last bit of d is set + brc 3,0f # (n/4) div (n/2) can overflow by 1 + ahi %r0,-1 # trick: subtract n/2, then divide +0: dr %r0,%r2 # signed division + ahi %r1,1 # trick part 2: add 1 to the quotient + # now (n >> 2) = (d >> 1) * %r1 + %r0 + lhi %r3,1 + nr %r3,%r1 # test last bit of q + jz 1f + alr %r0,%r2 # add (d>>1) to r +1: srl %r1,1 # q >>= 1 + # now (n >> 2) = (d&-2) * %r1 + %r0 + lhi %r3,1 + nr %r3,%r5 # test last bit of d + jz 2f + slr %r0,%r1 # r -= q + brc 3,2f # borrow ? + alr %r0,%r5 # r += d + ahi %r1,-1 +2: # now (n >> 2) = d * %r1 + %r0 + alr %r1,%r1 # q <<= 1 + alr %r0,%r0 # r <<= 1 + brc 12,3f # overflow on r ? + slr %r0,%r5 # r -= d + ahi %r1,1 # q += 1 +3: lhi %r3,2 + nr %r3,%r4 # test next to last bit of n + jz 4f + ahi %r0,1 # r += 1 +4: clr %r0,%r5 # r >= d ? + jl 6f + slr %r0,%r5 # r -= d + ahi %r1,1 # q += 1 + # now (n >> 1) = d * %r1 + %r0 + j 6f +5: # divisor < 0x80000000 + srdl %r0,1 + dr %r0,%r2 # signed division + # now (n >> 1) = d * %r1 + %r0 +6: alr %r1,%r1 # q <<= 1 + alr %r0,%r0 # r <<= 1 + brc 12,7f # overflow on r ? + slr %r0,%r5 # r -= d + ahi %r1,1 # q += 1 +7: lhi %r3,1 + nr %r3,%r4 # isolate last bit of n + alr %r0,%r3 # r += (n & 1) + clr %r0,%r5 # r >= d ? + jl 8f + slr %r0,%r5 # r -= d + ahi %r1,1 # q += 1 +8: # now n = d * %r1 + %r0 + l %r2,24(%r15) + st %r0,0(%r2) + lr %r2,%r1 + br %r14 + .end __udiv_qrnnd diff --git a/arch/s390/lib/uaccess.h b/arch/s390/lib/uaccess.h new file mode 100644 index 0000000..126011d --- /dev/null +++ b/arch/s390/lib/uaccess.h @@ -0,0 +1,23 @@ +/* + * arch/s390/uaccess.h + * + * Copyright IBM Corp. 2007 + * + */ + +#ifndef __ARCH_S390_LIB_UACCESS_H +#define __ARCH_S390_LIB_UACCESS_H + +extern size_t copy_from_user_std(size_t, const void __user *, void *); +extern size_t copy_to_user_std(size_t, void __user *, const void *); +extern size_t strnlen_user_std(size_t, const char __user *); +extern size_t strncpy_from_user_std(size_t, const char __user *, char *); +extern int futex_atomic_cmpxchg_std(int __user *, int, int); +extern int futex_atomic_op_std(int, int __user *, int, int *); + +extern size_t copy_from_user_pt(size_t, const void __user *, void *); +extern size_t copy_to_user_pt(size_t, void __user *, const void *); +extern int futex_atomic_op_pt(int, int __user *, int, int *); +extern int futex_atomic_cmpxchg_pt(int __user *, int, int); + +#endif /* __ARCH_S390_LIB_UACCESS_H */ diff --git a/arch/s390/lib/uaccess_mvcos.c b/arch/s390/lib/uaccess_mvcos.c index f9a23d5..6d87723 100644 --- a/arch/s390/lib/uaccess_mvcos.c +++ b/arch/s390/lib/uaccess_mvcos.c @@ -12,6 +12,7 @@ #include #include #include #include +#include "uaccess.h" #ifndef __s390x__ #define AHI "ahi" @@ -27,10 +28,7 @@ #define LHI "lghi" #define SLR "slgr" #endif -extern size_t copy_from_user_std(size_t, const void __user *, void *); -extern size_t copy_to_user_std(size_t, void __user *, const void *); - -size_t copy_from_user_mvcos(size_t size, const void __user *ptr, void *x) +static size_t copy_from_user_mvcos(size_t size, const void __user *ptr, void *x) { register unsigned long reg0 asm("0") = 0x81UL; unsigned long tmp1, tmp2; @@ -69,14 +67,14 @@ size_t copy_from_user_mvcos(size_t size, return size; } -size_t copy_from_user_mvcos_check(size_t size, const void __user *ptr, void *x) +static size_t copy_from_user_mvcos_check(size_t size, const void __user *ptr, void *x) { if (size <= 256) return copy_from_user_std(size, ptr, x); return copy_from_user_mvcos(size, ptr, x); } -size_t copy_to_user_mvcos(size_t size, void __user *ptr, const void *x) +static size_t copy_to_user_mvcos(size_t size, void __user *ptr, const void *x) { register unsigned long reg0 asm("0") = 0x810000UL; unsigned long tmp1, tmp2; @@ -105,14 +103,16 @@ size_t copy_to_user_mvcos(size_t size, v return size; } -size_t copy_to_user_mvcos_check(size_t size, void __user *ptr, const void *x) +static size_t copy_to_user_mvcos_check(size_t size, void __user *ptr, + const void *x) { if (size <= 256) return copy_to_user_std(size, ptr, x); return copy_to_user_mvcos(size, ptr, x); } -size_t copy_in_user_mvcos(size_t size, void __user *to, const void __user *from) +static size_t copy_in_user_mvcos(size_t size, void __user *to, + const void __user *from) { register unsigned long reg0 asm("0") = 0x810081UL; unsigned long tmp1, tmp2; @@ -134,7 +134,7 @@ size_t copy_in_user_mvcos(size_t size, v return size; } -size_t clear_user_mvcos(size_t size, void __user *to) +static size_t clear_user_mvcos(size_t size, void __user *to) { register unsigned long reg0 asm("0") = 0x810000UL; unsigned long tmp1, tmp2; @@ -162,10 +162,43 @@ size_t clear_user_mvcos(size_t size, voi return size; } -extern size_t strnlen_user_std(size_t, const char __user *); -extern size_t strncpy_from_user_std(size_t, const char __user *, char *); -extern int futex_atomic_op(int, int __user *, int, int *); -extern int futex_atomic_cmpxchg(int __user *, int, int); +static size_t strnlen_user_mvcos(size_t count, const char __user *src) +{ + char buf[256]; + int rc; + size_t done, len, len_str; + + done = 0; + do { + len = min(count - done, (size_t) 256); + rc = uaccess.copy_from_user(len, src + done, buf); + if (unlikely(rc == len)) + return 0; + len -= rc; + len_str = strnlen(buf, len); + done += len_str; + } while ((len_str == len) && (done < count)); + return done + 1; +} + +static size_t strncpy_from_user_mvcos(size_t count, const char __user *src, + char *dst) +{ + int rc; + size_t done, len, len_str; + + done = 0; + do { + len = min(count - done, (size_t) 4096); + rc = uaccess.copy_from_user(len, src + done, dst); + if (unlikely(rc == len)) + return -EFAULT; + len -= rc; + len_str = strnlen(dst, len); + done += len_str; + } while ((len_str == len) && (done < count)); + return done; +} struct uaccess_ops uaccess_mvcos = { .copy_from_user = copy_from_user_mvcos_check, @@ -176,6 +209,21 @@ struct uaccess_ops uaccess_mvcos = { .clear_user = clear_user_mvcos, .strnlen_user = strnlen_user_std, .strncpy_from_user = strncpy_from_user_std, - .futex_atomic_op = futex_atomic_op, - .futex_atomic_cmpxchg = futex_atomic_cmpxchg, + .futex_atomic_op = futex_atomic_op_std, + .futex_atomic_cmpxchg = futex_atomic_cmpxchg_std, +}; + +#ifdef CONFIG_S390_SWITCH_AMODE +struct uaccess_ops uaccess_mvcos_switch = { + .copy_from_user = copy_from_user_mvcos, + .copy_from_user_small = copy_from_user_mvcos, + .copy_to_user = copy_to_user_mvcos, + .copy_to_user_small = copy_to_user_mvcos, + .copy_in_user = copy_in_user_mvcos, + .clear_user = clear_user_mvcos, + .strnlen_user = strnlen_user_mvcos, + .strncpy_from_user = strncpy_from_user_mvcos, + .futex_atomic_op = futex_atomic_op_pt, + .futex_atomic_cmpxchg = futex_atomic_cmpxchg_pt, }; +#endif diff --git a/arch/s390/lib/uaccess_pt.c b/arch/s390/lib/uaccess_pt.c index 49c3e46..6318167 100644 --- a/arch/s390/lib/uaccess_pt.c +++ b/arch/s390/lib/uaccess_pt.c @@ -1,7 +1,8 @@ /* * arch/s390/lib/uaccess_pt.c * - * User access functions based on page table walks. + * User access functions based on page table walks for enhanced + * system layout without hardware support. * * Copyright IBM Corp. 2006 * Author(s): Gerald Schaefer (gerald.schaefer@de.ibm.com) @@ -12,9 +13,10 @@ #include #include #include #include +#include "uaccess.h" -static inline int __handle_fault(struct mm_struct *mm, unsigned long address, - int write_access) +static int __handle_fault(struct mm_struct *mm, unsigned long address, + int write_access) { struct vm_area_struct *vma; int ret = -EFAULT; @@ -79,8 +81,8 @@ out_sigbus: return ret; } -static inline size_t __user_copy_pt(unsigned long uaddr, void *kptr, - size_t n, int write_user) +static size_t __user_copy_pt(unsigned long uaddr, void *kptr, + size_t n, int write_user) { struct mm_struct *mm = current->mm; unsigned long offset, pfn, done, size; @@ -133,6 +135,49 @@ fault: goto retry; } +/* + * Do DAT for user address by page table walk, return kernel address. + * This function needs to be called with current->mm->page_table_lock held. + */ +static unsigned long __dat_user_addr(unsigned long uaddr) +{ + struct mm_struct *mm = current->mm; + unsigned long pfn, ret; + pgd_t *pgd; + pmd_t *pmd; + pte_t *pte; + int rc; + + ret = 0; +retry: + pgd = pgd_offset(mm, uaddr); + if (pgd_none(*pgd) || unlikely(pgd_bad(*pgd))) + goto fault; + + pmd = pmd_offset(pgd, uaddr); + if (pmd_none(*pmd) || unlikely(pmd_bad(*pmd))) + goto fault; + + pte = pte_offset_map(pmd, uaddr); + if (!pte || !pte_present(*pte)) + goto fault; + + pfn = pte_pfn(*pte); + if (!pfn_valid(pfn)) + goto out; + + ret = (pfn << PAGE_SHIFT) + (uaddr & (PAGE_SIZE - 1)); +out: + return ret; +fault: + spin_unlock(&mm->page_table_lock); + rc = __handle_fault(mm, uaddr, 0); + spin_lock(&mm->page_table_lock); + if (rc) + goto out; + goto retry; +} + size_t copy_from_user_pt(size_t n, const void __user *from, void *to) { size_t rc; @@ -155,3 +200,277 @@ size_t copy_to_user_pt(size_t n, void __ } return __user_copy_pt((unsigned long) to, (void *) from, n, 1); } + +static size_t clear_user_pt(size_t n, void __user *to) +{ + long done, size, ret; + + if (segment_eq(get_fs(), KERNEL_DS)) { + memset((void __kernel __force *) to, 0, n); + return 0; + } + done = 0; + do { + if (n - done > PAGE_SIZE) + size = PAGE_SIZE; + else + size = n - done; + ret = __user_copy_pt((unsigned long) to + done, + &empty_zero_page, size, 1); + done += size; + if (ret) + return ret + n - done; + } while (done < n); + return 0; +} + +static size_t strnlen_user_pt(size_t count, const char __user *src) +{ + char *addr; + unsigned long uaddr = (unsigned long) src; + struct mm_struct *mm = current->mm; + unsigned long offset, pfn, done, len; + pgd_t *pgd; + pmd_t *pmd; + pte_t *pte; + size_t len_str; + + if (segment_eq(get_fs(), KERNEL_DS)) + return strnlen((const char __kernel __force *) src, count) + 1; + done = 0; +retry: + spin_lock(&mm->page_table_lock); + do { + pgd = pgd_offset(mm, uaddr); + if (pgd_none(*pgd) || unlikely(pgd_bad(*pgd))) + goto fault; + + pmd = pmd_offset(pgd, uaddr); + if (pmd_none(*pmd) || unlikely(pmd_bad(*pmd))) + goto fault; + + pte = pte_offset_map(pmd, uaddr); + if (!pte || !pte_present(*pte)) + goto fault; + + pfn = pte_pfn(*pte); + if (!pfn_valid(pfn)) { + done = -1; + goto out; + } + + offset = uaddr & (PAGE_SIZE-1); + addr = (char *)(pfn << PAGE_SHIFT) + offset; + len = min(count - done, PAGE_SIZE - offset); + len_str = strnlen(addr, len); + done += len_str; + uaddr += len_str; + } while ((len_str == len) && (done < count)); +out: + spin_unlock(&mm->page_table_lock); + return done + 1; +fault: + spin_unlock(&mm->page_table_lock); + if (__handle_fault(mm, uaddr, 0)) { + return 0; + } + goto retry; +} + +static size_t strncpy_from_user_pt(size_t count, const char __user *src, + char *dst) +{ + size_t n = strnlen_user_pt(count, src); + + if (!n) + return -EFAULT; + if (n > count) + n = count; + if (segment_eq(get_fs(), KERNEL_DS)) { + memcpy(dst, (const char __kernel __force *) src, n); + if (dst[n-1] == '\0') + return n-1; + else + return n; + } + if (__user_copy_pt((unsigned long) src, dst, n, 0)) + return -EFAULT; + if (dst[n-1] == '\0') + return n-1; + else + return n; +} + +static size_t copy_in_user_pt(size_t n, void __user *to, + const void __user *from) +{ + struct mm_struct *mm = current->mm; + unsigned long offset_from, offset_to, offset_max, pfn_from, pfn_to, + uaddr, done, size; + unsigned long uaddr_from = (unsigned long) from; + unsigned long uaddr_to = (unsigned long) to; + pgd_t *pgd_from, *pgd_to; + pmd_t *pmd_from, *pmd_to; + pte_t *pte_from, *pte_to; + int write_user; + + done = 0; +retry: + spin_lock(&mm->page_table_lock); + do { + pgd_from = pgd_offset(mm, uaddr_from); + if (pgd_none(*pgd_from) || unlikely(pgd_bad(*pgd_from))) { + uaddr = uaddr_from; + write_user = 0; + goto fault; + } + pgd_to = pgd_offset(mm, uaddr_to); + if (pgd_none(*pgd_to) || unlikely(pgd_bad(*pgd_to))) { + uaddr = uaddr_to; + write_user = 1; + goto fault; + } + + pmd_from = pmd_offset(pgd_from, uaddr_from); + if (pmd_none(*pmd_from) || unlikely(pmd_bad(*pmd_from))) { + uaddr = uaddr_from; + write_user = 0; + goto fault; + } + pmd_to = pmd_offset(pgd_to, uaddr_to); + if (pmd_none(*pmd_to) || unlikely(pmd_bad(*pmd_to))) { + uaddr = uaddr_to; + write_user = 1; + goto fault; + } + + pte_from = pte_offset_map(pmd_from, uaddr_from); + if (!pte_from || !pte_present(*pte_from)) { + uaddr = uaddr_from; + write_user = 0; + goto fault; + } + pte_to = pte_offset_map(pmd_to, uaddr_to); + if (!pte_to || !pte_present(*pte_to) || !pte_write(*pte_to)) { + uaddr = uaddr_to; + write_user = 1; + goto fault; + } + + pfn_from = pte_pfn(*pte_from); + if (!pfn_valid(pfn_from)) + goto out; + pfn_to = pte_pfn(*pte_to); + if (!pfn_valid(pfn_to)) + goto out; + + offset_from = uaddr_from & (PAGE_SIZE-1); + offset_to = uaddr_from & (PAGE_SIZE-1); + offset_max = max(offset_from, offset_to); + size = min(n - done, PAGE_SIZE - offset_max); + + memcpy((void *)(pfn_to << PAGE_SHIFT) + offset_to, + (void *)(pfn_from << PAGE_SHIFT) + offset_from, size); + done += size; + uaddr_from += size; + uaddr_to += size; + } while (done < n); +out: + spin_unlock(&mm->page_table_lock); + return n - done; +fault: + spin_unlock(&mm->page_table_lock); + if (__handle_fault(mm, uaddr, write_user)) + return n - done; + goto retry; +} + +#define __futex_atomic_op(insn, ret, oldval, newval, uaddr, oparg) \ + asm volatile("0: l %1,0(%6)\n" \ + "1: " insn \ + "2: cs %1,%2,0(%6)\n" \ + "3: jl 1b\n" \ + " lhi %0,0\n" \ + "4:\n" \ + EX_TABLE(0b,4b) EX_TABLE(2b,4b) EX_TABLE(3b,4b) \ + : "=d" (ret), "=&d" (oldval), "=&d" (newval), \ + "=m" (*uaddr) \ + : "0" (-EFAULT), "d" (oparg), "a" (uaddr), \ + "m" (*uaddr) : "cc" ); + +int futex_atomic_op_pt(int op, int __user *uaddr, int oparg, int *old) +{ + int oldval = 0, newval, ret; + + spin_lock(¤t->mm->page_table_lock); + uaddr = (int __user *) __dat_user_addr((unsigned long) uaddr); + if (!uaddr) { + spin_unlock(¤t->mm->page_table_lock); + return -EFAULT; + } + get_page(virt_to_page(uaddr)); + spin_unlock(¤t->mm->page_table_lock); + switch (op) { + case FUTEX_OP_SET: + __futex_atomic_op("lr %2,%5\n", + ret, oldval, newval, uaddr, oparg); + break; + case FUTEX_OP_ADD: + __futex_atomic_op("lr %2,%1\nar %2,%5\n", + ret, oldval, newval, uaddr, oparg); + break; + case FUTEX_OP_OR: + __futex_atomic_op("lr %2,%1\nor %2,%5\n", + ret, oldval, newval, uaddr, oparg); + break; + case FUTEX_OP_ANDN: + __futex_atomic_op("lr %2,%1\nnr %2,%5\n", + ret, oldval, newval, uaddr, oparg); + break; + case FUTEX_OP_XOR: + __futex_atomic_op("lr %2,%1\nxr %2,%5\n", + ret, oldval, newval, uaddr, oparg); + break; + default: + ret = -ENOSYS; + } + put_page(virt_to_page(uaddr)); + *old = oldval; + return ret; +} + +int futex_atomic_cmpxchg_pt(int __user *uaddr, int oldval, int newval) +{ + int ret; + + spin_lock(¤t->mm->page_table_lock); + uaddr = (int __user *) __dat_user_addr((unsigned long) uaddr); + if (!uaddr) { + spin_unlock(¤t->mm->page_table_lock); + return -EFAULT; + } + get_page(virt_to_page(uaddr)); + spin_unlock(¤t->mm->page_table_lock); + asm volatile(" cs %1,%4,0(%5)\n" + "0: lr %0,%1\n" + "1:\n" + EX_TABLE(0b,1b) + : "=d" (ret), "+d" (oldval), "=m" (*uaddr) + : "0" (-EFAULT), "d" (newval), "a" (uaddr), "m" (*uaddr) + : "cc", "memory" ); + put_page(virt_to_page(uaddr)); + return ret; +} + +struct uaccess_ops uaccess_pt = { + .copy_from_user = copy_from_user_pt, + .copy_from_user_small = copy_from_user_pt, + .copy_to_user = copy_to_user_pt, + .copy_to_user_small = copy_to_user_pt, + .copy_in_user = copy_in_user_pt, + .clear_user = clear_user_pt, + .strnlen_user = strnlen_user_pt, + .strncpy_from_user = strncpy_from_user_pt, + .futex_atomic_op = futex_atomic_op_pt, + .futex_atomic_cmpxchg = futex_atomic_cmpxchg_pt, +}; diff --git a/arch/s390/lib/uaccess_std.c b/arch/s390/lib/uaccess_std.c index 56a0214..28c4500 100644 --- a/arch/s390/lib/uaccess_std.c +++ b/arch/s390/lib/uaccess_std.c @@ -13,6 +13,7 @@ #include #include #include #include +#include "uaccess.h" #ifndef __s390x__ #define AHI "ahi" @@ -28,9 +29,6 @@ #define LHI "lghi" #define SLR "slgr" #endif -extern size_t copy_from_user_pt(size_t n, const void __user *from, void *to); -extern size_t copy_to_user_pt(size_t n, void __user *to, const void *from); - size_t copy_from_user_std(size_t size, const void __user *ptr, void *x) { unsigned long tmp1, tmp2; @@ -72,7 +70,8 @@ size_t copy_from_user_std(size_t size, c return size; } -size_t copy_from_user_std_check(size_t size, const void __user *ptr, void *x) +static size_t copy_from_user_std_check(size_t size, const void __user *ptr, + void *x) { if (size <= 1024) return copy_from_user_std(size, ptr, x); @@ -110,14 +109,16 @@ size_t copy_to_user_std(size_t size, voi return size; } -size_t copy_to_user_std_check(size_t size, void __user *ptr, const void *x) +static size_t copy_to_user_std_check(size_t size, void __user *ptr, + const void *x) { if (size <= 1024) return copy_to_user_std(size, ptr, x); return copy_to_user_pt(size, ptr, x); } -size_t copy_in_user_std(size_t size, void __user *to, const void __user *from) +static size_t copy_in_user_std(size_t size, void __user *to, + const void __user *from) { unsigned long tmp1; @@ -148,7 +149,7 @@ size_t copy_in_user_std(size_t size, voi return size; } -size_t clear_user_std(size_t size, void __user *to) +static size_t clear_user_std(size_t size, void __user *to) { unsigned long tmp1, tmp2; @@ -254,7 +255,7 @@ #define __futex_atomic_op(insn, ret, old : "0" (-EFAULT), "d" (oparg), "a" (uaddr), \ "m" (*uaddr) : "cc"); -int futex_atomic_op(int op, int __user *uaddr, int oparg, int *old) +int futex_atomic_op_std(int op, int __user *uaddr, int oparg, int *old) { int oldval = 0, newval, ret; @@ -286,7 +287,7 @@ int futex_atomic_op(int op, int __user * return ret; } -int futex_atomic_cmpxchg(int __user *uaddr, int oldval, int newval) +int futex_atomic_cmpxchg_std(int __user *uaddr, int oldval, int newval) { int ret; @@ -311,6 +312,6 @@ struct uaccess_ops uaccess_std = { .clear_user = clear_user_std, .strnlen_user = strnlen_user_std, .strncpy_from_user = strncpy_from_user_std, - .futex_atomic_op = futex_atomic_op, - .futex_atomic_cmpxchg = futex_atomic_cmpxchg, + .futex_atomic_op = futex_atomic_op_std, + .futex_atomic_cmpxchg = futex_atomic_cmpxchg_std, }; diff --git a/arch/s390/math-emu/Makefile b/arch/s390/math-emu/Makefile index c10df14..73b3e72 100644 --- a/arch/s390/math-emu/Makefile +++ b/arch/s390/math-emu/Makefile @@ -2,7 +2,7 @@ # # Makefile for the FPU instruction emulation. # -obj-$(CONFIG_MATHEMU) := math.o qrnnd.o +obj-$(CONFIG_MATHEMU) := math.o EXTRA_CFLAGS := -I$(src) -Iinclude/math-emu -w EXTRA_AFLAGS := -traditional diff --git a/arch/s390/math-emu/math.c b/arch/s390/math-emu/math.c index 6b9aec5..3ee78cc 100644 --- a/arch/s390/math-emu/math.c +++ b/arch/s390/math-emu/math.c @@ -15,7 +15,7 @@ #include #include #include -#include "sfp-util.h" +#include #include #include #include diff --git a/arch/s390/math-emu/qrnnd.S b/arch/s390/math-emu/qrnnd.S deleted file mode 100644 index b01c2b6..0000000 --- a/arch/s390/math-emu/qrnnd.S +++ /dev/null @@ -1,77 +0,0 @@ -# S/390 __udiv_qrnnd - -# r2 : &__r -# r3 : upper half of 64 bit word n -# r4 : lower half of 64 bit word n -# r5 : divisor d -# the reminder r of the division is to be stored to &__r and -# the quotient q is to be returned - - .text - .globl __udiv_qrnnd -__udiv_qrnnd: - st %r2,24(%r15) # store pointer to reminder for later - lr %r0,%r3 # reload n - lr %r1,%r4 - ltr %r2,%r5 # reload and test divisor - jp 5f - # divisor >= 0x80000000 - srdl %r0,2 # n/4 - srl %r2,1 # d/2 - slr %r1,%r2 # special case if last bit of d is set - brc 3,0f # (n/4) div (n/2) can overflow by 1 - ahi %r0,-1 # trick: subtract n/2, then divide -0: dr %r0,%r2 # signed division - ahi %r1,1 # trick part 2: add 1 to the quotient - # now (n >> 2) = (d >> 1) * %r1 + %r0 - lhi %r3,1 - nr %r3,%r1 # test last bit of q - jz 1f - alr %r0,%r2 # add (d>>1) to r -1: srl %r1,1 # q >>= 1 - # now (n >> 2) = (d&-2) * %r1 + %r0 - lhi %r3,1 - nr %r3,%r5 # test last bit of d - jz 2f - slr %r0,%r1 # r -= q - brc 3,2f # borrow ? - alr %r0,%r5 # r += d - ahi %r1,-1 -2: # now (n >> 2) = d * %r1 + %r0 - alr %r1,%r1 # q <<= 1 - alr %r0,%r0 # r <<= 1 - brc 12,3f # overflow on r ? - slr %r0,%r5 # r -= d - ahi %r1,1 # q += 1 -3: lhi %r3,2 - nr %r3,%r4 # test next to last bit of n - jz 4f - ahi %r0,1 # r += 1 -4: clr %r0,%r5 # r >= d ? - jl 6f - slr %r0,%r5 # r -= d - ahi %r1,1 # q += 1 - # now (n >> 1) = d * %r1 + %r0 - j 6f -5: # divisor < 0x80000000 - srdl %r0,1 - dr %r0,%r2 # signed division - # now (n >> 1) = d * %r1 + %r0 -6: alr %r1,%r1 # q <<= 1 - alr %r0,%r0 # r <<= 1 - brc 12,7f # overflow on r ? - slr %r0,%r5 # r -= d - ahi %r1,1 # q += 1 -7: lhi %r3,1 - nr %r3,%r4 # isolate last bit of n - alr %r0,%r3 # r += (n & 1) - clr %r0,%r5 # r >= d ? - jl 8f - slr %r0,%r5 # r -= d - ahi %r1,1 # q += 1 -8: # now n = d * %r1 + %r0 - l %r2,24(%r15) - st %r0,0(%r2) - lr %r2,%r1 - br %r14 - .end __udiv_qrnnd diff --git a/arch/s390/math-emu/sfp-util.h b/arch/s390/math-emu/sfp-util.h deleted file mode 100644 index 5b6ca45..0000000 --- a/arch/s390/math-emu/sfp-util.h +++ /dev/null @@ -1,66 +0,0 @@ -#include -#include -#include -#include - -#define add_ssaaaa(sh, sl, ah, al, bh, bl) ({ \ - unsigned int __sh = (ah); \ - unsigned int __sl = (al); \ - asm volatile( \ - " alr %1,%3\n" \ - " brc 12,0f\n" \ - " ahi %0,1\n" \ - "0: alr %0,%2" \ - : "+&d" (__sh), "+d" (__sl) \ - : "d" (bh), "d" (bl) : "cc"); \ - (sh) = __sh; \ - (sl) = __sl; \ -}) - -#define sub_ddmmss(sh, sl, ah, al, bh, bl) ({ \ - unsigned int __sh = (ah); \ - unsigned int __sl = (al); \ - asm volatile( \ - " slr %1,%3\n" \ - " brc 3,0f\n" \ - " ahi %0,-1\n" \ - "0: slr %0,%2" \ - : "+&d" (__sh), "+d" (__sl) \ - : "d" (bh), "d" (bl) : "cc"); \ - (sh) = __sh; \ - (sl) = __sl; \ -}) - -/* a umul b = a mul b + (a>=2<<31) ? b<<32:0 + (b>=2<<31) ? a<<32:0 */ -#define umul_ppmm(wh, wl, u, v) ({ \ - unsigned int __wh = u; \ - unsigned int __wl = v; \ - asm volatile( \ - " ltr 1,%0\n" \ - " mr 0,%1\n" \ - " jnm 0f\n" \ - " alr 0,%1\n" \ - "0: ltr %1,%1\n" \ - " jnm 1f\n" \ - " alr 0,%0\n" \ - "1: lr %0,0\n" \ - " lr %1,1\n" \ - : "+d" (__wh), "+d" (__wl) \ - : : "0", "1", "cc"); \ - wh = __wh; \ - wl = __wl; \ -}) - -#define udiv_qrnnd(q, r, n1, n0, d) \ - do { unsigned long __r; \ - (q) = __udiv_qrnnd (&__r, (n1), (n0), (d)); \ - (r) = __r; \ - } while (0) -extern unsigned long __udiv_qrnnd (unsigned long *, unsigned long, - unsigned long , unsigned long); - -#define UDIV_NEEDS_NORMALIZATION 0 - -#define abort() return 0 - -#define __BYTE_ORDER __BIG_ENDIAN diff --git a/arch/s390/mm/Makefile b/arch/s390/mm/Makefile index 8e09db1..f95449b 100644 --- a/arch/s390/mm/Makefile +++ b/arch/s390/mm/Makefile @@ -2,6 +2,6 @@ # # Makefile for the linux s390-specific parts of the memory manager. # -obj-y := init.o fault.o ioremap.o extmem.o mmap.o vmem.o +obj-y := init.o fault.o extmem.o mmap.o vmem.o obj-$(CONFIG_CMM) += cmm.o diff --git a/arch/s390/mm/cmm.c b/arch/s390/mm/cmm.c index 607f50e..c5b2f4f 100644 --- a/arch/s390/mm/cmm.c +++ b/arch/s390/mm/cmm.c @@ -245,7 +245,7 @@ cmm_set_timeout(long nr, long seconds) cmm_set_timer(); } -static inline int +static int cmm_skip_blanks(char *cp, char **endp) { char *str; @@ -256,10 +256,6 @@ cmm_skip_blanks(char *cp, char **endp) } #ifdef CONFIG_CMM_PROC -/* These will someday get removed. */ -#define VM_CMM_PAGES 1111 -#define VM_CMM_TIMED_PAGES 1112 -#define VM_CMM_TIMEOUT 1113 static struct ctl_table cmm_table[]; @@ -414,7 +410,7 @@ cmm_smsg_target(char *from, char *msg) } #endif -struct ctl_table_header *cmm_sysctl_header; +static struct ctl_table_header *cmm_sysctl_header; static int cmm_init (void) @@ -422,7 +418,7 @@ cmm_init (void) int rc = -ENOMEM; #ifdef CONFIG_CMM_PROC - cmm_sysctl_header = register_sysctl_table(cmm_dir_table, 1); + cmm_sysctl_header = register_sysctl_table(cmm_dir_table); if (!cmm_sysctl_header) goto out; #endif diff --git a/arch/s390/mm/extmem.c b/arch/s390/mm/extmem.c index 775bf19..394980b 100644 --- a/arch/s390/mm/extmem.c +++ b/arch/s390/mm/extmem.c @@ -15,6 +15,7 @@ #include #include #include #include +#include #include #include #include @@ -70,6 +71,7 @@ struct qin64 { struct dcss_segment { struct list_head list; char dcss_name[8]; + char res_name[15]; unsigned long start_addr; unsigned long end; atomic_t ref_count; @@ -77,6 +79,7 @@ struct dcss_segment { unsigned int vm_segtype; struct qrange range[6]; int segcnt; + struct resource *res; }; static DEFINE_MUTEX(dcss_lock); @@ -88,7 +91,7 @@ static char *segtype_string[] = { "SW", * Create the 8 bytes, ebcdic VM segment name from * an ascii name. */ -static void inline +static void dcss_mkname(char *name, char *dcss_name) { int i; @@ -303,6 +306,29 @@ __segment_load (char *name, int do_nonsh goto out_free; } + seg->res = kzalloc(sizeof(struct resource), GFP_KERNEL); + if (seg->res == NULL) { + rc = -ENOMEM; + goto out_shared; + } + seg->res->flags = IORESOURCE_BUSY | IORESOURCE_MEM; + seg->res->start = seg->start_addr; + seg->res->end = seg->end; + memcpy(&seg->res_name, seg->dcss_name, 8); + EBCASC(seg->res_name, 8); + seg->res_name[8] = '\0'; + strncat(seg->res_name, " (DCSS)", 7); + seg->res->name = seg->res_name; + rc = seg->vm_segtype; + if (rc == SEG_TYPE_SC || + ((rc == SEG_TYPE_SR || rc == SEG_TYPE_ER) && !do_nonshared)) + seg->res->flags |= IORESOURCE_READONLY; + if (request_resource(&iomem_resource, seg->res)) { + rc = -EBUSY; + kfree(seg->res); + goto out_shared; + } + if (do_nonshared) dcss_command = DCSS_LOADNSR; else @@ -316,12 +342,11 @@ __segment_load (char *name, int do_nonsh rc = dcss_diag_translate_rc (seg->end); dcss_diag(DCSS_PURGESEG, seg->dcss_name, &seg->start_addr, &seg->end); - goto out_shared; + goto out_resource; } seg->do_nonshared = do_nonshared; atomic_set(&seg->ref_count, 1); list_add(&seg->list, &dcss_list); - rc = seg->vm_segtype; *addr = seg->start_addr; *end = seg->end; if (do_nonshared) @@ -329,12 +354,16 @@ __segment_load (char *name, int do_nonsh "type %s in non-shared mode\n", name, (void*)seg->start_addr, (void*)seg->end, segtype_string[seg->vm_segtype]); - else + else { PRINT_INFO ("segment_load: loaded segment %s range %p .. %p " "type %s in shared mode\n", name, (void*)seg->start_addr, (void*)seg->end, segtype_string[seg->vm_segtype]); + } goto out; + out_resource: + release_resource(seg->res); + kfree(seg->res); out_shared: remove_shared_memory(seg->start_addr, seg->end - seg->start_addr + 1); out_free: @@ -401,6 +430,7 @@ segment_load (char *name, int do_nonshar * -ENOENT : no such segment (segment gone!) * -EAGAIN : segment is in use by other exploiters, try later * -EINVAL : no segment with the given name is currently loaded - name invalid + * -EBUSY : segment can temporarily not be used (overlaps with dcss) * 0 : operation succeeded */ int @@ -428,12 +458,24 @@ segment_modify_shared (char *name, int d rc = -EAGAIN; goto out_unlock; } - dcss_diag(DCSS_PURGESEG, seg->dcss_name, - &dummy, &dummy); - if (do_nonshared) + release_resource(seg->res); + if (do_nonshared) { dcss_command = DCSS_LOADNSR; - else - dcss_command = DCSS_LOADNOLY; + seg->res->flags &= ~IORESOURCE_READONLY; + } else { + dcss_command = DCSS_LOADNOLY; + if (seg->vm_segtype == SEG_TYPE_SR || + seg->vm_segtype == SEG_TYPE_ER) + seg->res->flags |= IORESOURCE_READONLY; + } + if (request_resource(&iomem_resource, seg->res)) { + PRINT_WARN("segment_modify_shared: could not reload segment %s" + " - overlapping resources\n", name); + rc = -EBUSY; + kfree(seg->res); + goto out_del; + } + dcss_diag(DCSS_PURGESEG, seg->dcss_name, &dummy, &dummy); diag_cc = dcss_diag(dcss_command, seg->dcss_name, &seg->start_addr, &seg->end); if (diag_cc > 1) { @@ -446,9 +488,9 @@ segment_modify_shared (char *name, int d rc = 0; goto out_unlock; out_del: + remove_shared_memory(seg->start_addr, seg->end - seg->start_addr + 1); list_del(&seg->list); - dcss_diag(DCSS_PURGESEG, seg->dcss_name, - &dummy, &dummy); + dcss_diag(DCSS_PURGESEG, seg->dcss_name, &dummy, &dummy); kfree(seg); out_unlock: mutex_unlock(&dcss_lock); @@ -478,6 +520,8 @@ segment_unload(char *name) } if (atomic_dec_return(&seg->ref_count) != 0) goto out_unlock; + release_resource(seg->res); + kfree(seg->res); remove_shared_memory(seg->start_addr, seg->end - seg->start_addr + 1); list_del(&seg->list); dcss_diag(DCSS_PURGESEG, seg->dcss_name, &dummy, &dummy); diff --git a/arch/s390/mm/fault.c b/arch/s390/mm/fault.c index cd85e34..641aef3 100644 --- a/arch/s390/mm/fault.c +++ b/arch/s390/mm/fault.c @@ -52,7 +52,7 @@ #endif extern void die(const char *,struct pt_regs *,long); #ifdef CONFIG_KPROBES -ATOMIC_NOTIFIER_HEAD(notify_page_fault_chain); +static ATOMIC_NOTIFIER_HEAD(notify_page_fault_chain); int register_page_fault_notifier(struct notifier_block *nb) { return atomic_notifier_chain_register(¬ify_page_fault_chain, nb); @@ -83,12 +83,10 @@ static inline int notify_page_fault(enum } #endif -extern spinlock_t timerlist_lock; /* * Unlock any spinlocks which will prevent us from getting the - * message out (timerlist_lock is acquired through the - * console unblank code) + * message out. */ void bust_spinlocks(int yes) { @@ -137,7 +135,9 @@ static int __check_access_register(struc /* * Check which address space the address belongs to. - * Returns 1 for user space and 0 for kernel space. + * May return 1 or 2 for user space and 0 for kernel space. + * Returns 2 for user space in primary addressing mode with + * CONFIG_S390_EXEC_PROTECT on and kernel parameter noexec=on. */ static inline int check_user_space(struct pt_regs *regs, int error_code) { @@ -154,7 +154,7 @@ static inline int check_user_space(struc return __check_access_register(regs, error_code); if (descriptor == 2) return current->thread.mm_segment.ar4; - return descriptor != 0; + return ((descriptor != 0) ^ (switch_amode)) << s390_noexec; } /* @@ -183,6 +183,77 @@ #endif force_sig_info(SIGSEGV, &si, current); } +#ifdef CONFIG_S390_EXEC_PROTECT +extern long sys_sigreturn(struct pt_regs *regs); +extern long sys_rt_sigreturn(struct pt_regs *regs); +extern long sys32_sigreturn(struct pt_regs *regs); +extern long sys32_rt_sigreturn(struct pt_regs *regs); + +static inline void do_sigreturn(struct mm_struct *mm, struct pt_regs *regs, + int rt) +{ + up_read(&mm->mmap_sem); + clear_tsk_thread_flag(current, TIF_SINGLE_STEP); +#ifdef CONFIG_COMPAT + if (test_tsk_thread_flag(current, TIF_31BIT)) { + if (rt) + sys32_rt_sigreturn(regs); + else + sys32_sigreturn(regs); + return; + } +#endif /* CONFIG_COMPAT */ + if (rt) + sys_rt_sigreturn(regs); + else + sys_sigreturn(regs); + return; +} + +static int signal_return(struct mm_struct *mm, struct pt_regs *regs, + unsigned long address, unsigned long error_code) +{ + pgd_t *pgd; + pmd_t *pmd; + pte_t *pte; + u16 *instruction; + unsigned long pfn, uaddr = regs->psw.addr; + + spin_lock(&mm->page_table_lock); + pgd = pgd_offset(mm, uaddr); + if (pgd_none(*pgd) || unlikely(pgd_bad(*pgd))) + goto out_fault; + pmd = pmd_offset(pgd, uaddr); + if (pmd_none(*pmd) || unlikely(pmd_bad(*pmd))) + goto out_fault; + pte = pte_offset_map(pmd_offset(pgd_offset(mm, uaddr), uaddr), uaddr); + if (!pte || !pte_present(*pte)) + goto out_fault; + pfn = pte_pfn(*pte); + if (!pfn_valid(pfn)) + goto out_fault; + spin_unlock(&mm->page_table_lock); + + instruction = (u16 *) ((pfn << PAGE_SHIFT) + (uaddr & (PAGE_SIZE-1))); + if (*instruction == 0x0a77) + do_sigreturn(mm, regs, 0); + else if (*instruction == 0x0aad) + do_sigreturn(mm, regs, 1); + else { + printk("- XXX - do_exception: task = %s, primary, NO EXEC " + "-> SIGSEGV\n", current->comm); + up_read(&mm->mmap_sem); + current->thread.prot_addr = address; + current->thread.trap_no = error_code; + do_sigsegv(regs, error_code, SEGV_MAPERR, address); + } + return 0; +out_fault: + spin_unlock(&mm->page_table_lock); + return -EFAULT; +} +#endif /* CONFIG_S390_EXEC_PROTECT */ + /* * This routine handles page faults. It determines the address, * and the problem, and then passes it off to one of the appropriate @@ -260,6 +331,17 @@ do_exception(struct pt_regs *regs, unsig vma = find_vma(mm, address); if (!vma) goto bad_area; + +#ifdef CONFIG_S390_EXEC_PROTECT + if (unlikely((user_address == 2) && !(vma->vm_flags & VM_EXEC))) + if (!signal_return(mm, regs, address, error_code)) + /* + * signal_return() has done an up_read(&mm->mmap_sem) + * if it returns 0. + */ + return; +#endif + if (vma->vm_start <= address) goto good_area; if (!(vma->vm_flags & VM_GROWSDOWN)) @@ -452,8 +534,7 @@ void pfault_fini(void) : : "a" (&refbk), "m" (refbk) : "cc"); } -asmlinkage void -pfault_interrupt(__u16 error_code) +static void pfault_interrupt(__u16 error_code) { struct task_struct *tsk; __u16 subcode; diff --git a/arch/s390/mm/init.c b/arch/s390/mm/init.c index 4bb21be..b3e7c45 100644 --- a/arch/s390/mm/init.c +++ b/arch/s390/mm/init.c @@ -25,7 +25,7 @@ #include #include #include #include - +#include #include #include #include @@ -95,20 +95,18 @@ static void __init setup_ro_region(void) pte_t new_pte; unsigned long address, end; - address = ((unsigned long)&__start_rodata) & PAGE_MASK; - end = PFN_ALIGN((unsigned long)&__end_rodata); + address = ((unsigned long)&_stext) & PAGE_MASK; + end = PFN_ALIGN((unsigned long)&_eshared); for (; address < end; address += PAGE_SIZE) { pgd = pgd_offset_k(address); pmd = pmd_offset(pgd, address); pte = pte_offset_kernel(pmd, address); new_pte = mk_pte_phys(address, __pgprot(_PAGE_RO)); - set_pte(pte, new_pte); + *pte = new_pte; } } -extern void vmem_map_init(void); - /* * paging_init() sets up the page tables */ @@ -125,11 +123,11 @@ void __init paging_init(void) #ifdef CONFIG_64BIT pgdir_k = (__pa(swapper_pg_dir) & PAGE_MASK) | _KERN_REGION_TABLE; for (i = 0; i < PTRS_PER_PGD; i++) - pgd_clear(pg_dir + i); + pgd_clear_kernel(pg_dir + i); #else pgdir_k = (__pa(swapper_pg_dir) & PAGE_MASK) | _KERNSEG_TABLE; for (i = 0; i < PTRS_PER_PGD; i++) - pmd_clear((pmd_t *)(pg_dir + i)); + pmd_clear_kernel((pmd_t *)(pg_dir + i)); #endif vmem_map_init(); setup_ro_region(); @@ -174,10 +172,8 @@ void __init mem_init(void) datasize >>10, initsize >> 10); printk("Write protected kernel read-only data: %#lx - %#lx\n", - (unsigned long)&__start_rodata, - PFN_ALIGN((unsigned long)&__end_rodata) - 1); - printk("Virtual memmap size: %ldk\n", - (max_pfn * sizeof(struct page)) >> 10); + (unsigned long)&_stext, + PFN_ALIGN((unsigned long)&_eshared) - 1); } void free_initmem(void) diff --git a/arch/s390/mm/ioremap.c b/arch/s390/mm/ioremap.c deleted file mode 100644 index 3d2100a..0000000 --- a/arch/s390/mm/ioremap.c +++ /dev/null @@ -1,58 +0,0 @@ -/* - * arch/s390/mm/ioremap.c - * - * S390 version - * Copyright (C) 1999 IBM Deutschland Entwicklung GmbH, IBM Corporation - * Author(s): Hartmut Penner (hp@de.ibm.com) - * - * Derived from "arch/i386/mm/extable.c" - * (C) Copyright 1995 1996 Linus Torvalds - * - * Re-map IO memory to kernel address space so that we can access it. - * This is needed for high PCI addresses that aren't mapped in the - * 640k-1MB IO memory area on PC's - */ - -#include -#include -#include -#include - -/* - * Generic mapping function (not visible outside): - */ - -/* - * Remap an arbitrary physical address space into the kernel virtual - * address space. Needed when the kernel wants to access high addresses - * directly. - */ -void * __ioremap(unsigned long phys_addr, unsigned long size, unsigned long flags) -{ - void * addr; - struct vm_struct * area; - - if (phys_addr < virt_to_phys(high_memory)) - return phys_to_virt(phys_addr); - if (phys_addr & ~PAGE_MASK) - return NULL; - size = PAGE_ALIGN(size); - if (!size || size > phys_addr + size) - return NULL; - area = get_vm_area(size, VM_IOREMAP); - if (!area) - return NULL; - addr = area->addr; - if (ioremap_page_range((unsigned long)addr, (unsigned long)addr + size, - phys_addr, __pgprot(flags))) { - vfree(addr); - return NULL; - } - return addr; -} - -void iounmap(void *addr) -{ - if (addr > high_memory) - vfree(addr); -} diff --git a/arch/s390/mm/vmem.c b/arch/s390/mm/vmem.c index cd3d93e..92a5651 100644 --- a/arch/s390/mm/vmem.c +++ b/arch/s390/mm/vmem.c @@ -82,7 +82,7 @@ static inline pmd_t *vmem_pmd_alloc(void if (!pmd) return NULL; for (i = 0; i < PTRS_PER_PMD; i++) - pmd_clear(pmd + i); + pmd_clear_kernel(pmd + i); return pmd; } @@ -97,7 +97,7 @@ static inline pte_t *vmem_pte_alloc(void return NULL; pte_val(empty_pte) = _PAGE_TYPE_EMPTY; for (i = 0; i < PTRS_PER_PTE; i++) - set_pte(pte + i, empty_pte); + pte[i] = empty_pte; return pte; } @@ -119,7 +119,7 @@ static int vmem_add_range(unsigned long pm_dir = vmem_pmd_alloc(); if (!pm_dir) goto out; - pgd_populate(&init_mm, pg_dir, pm_dir); + pgd_populate_kernel(&init_mm, pg_dir, pm_dir); } pm_dir = pmd_offset(pg_dir, address); @@ -132,7 +132,7 @@ static int vmem_add_range(unsigned long pt_dir = pte_offset_kernel(pm_dir, address); pte = pfn_pte(address >> PAGE_SHIFT, PAGE_KERNEL); - set_pte(pt_dir, pte); + *pt_dir = pte; } ret = 0; out: @@ -161,7 +161,7 @@ static void vmem_remove_range(unsigned l if (pmd_none(*pm_dir)) continue; pt_dir = pte_offset_kernel(pm_dir, address); - set_pte(pt_dir, pte); + *pt_dir = pte; } flush_tlb_kernel_range(start, start + size); } @@ -191,7 +191,7 @@ static int vmem_add_mem_map(unsigned lon pm_dir = vmem_pmd_alloc(); if (!pm_dir) goto out; - pgd_populate(&init_mm, pg_dir, pm_dir); + pgd_populate_kernel(&init_mm, pg_dir, pm_dir); } pm_dir = pmd_offset(pg_dir, address); @@ -210,7 +210,7 @@ static int vmem_add_mem_map(unsigned lon if (!new_page) goto out; pte = pfn_pte(new_page >> PAGE_SHIFT, PAGE_KERNEL); - set_pte(pt_dir, pte); + *pt_dir = pte; } } ret = 0; diff --git a/arch/sh/Kconfig b/arch/sh/Kconfig index 3aa3b88..4d16d89 100644 --- a/arch/sh/Kconfig +++ b/arch/sh/Kconfig @@ -48,6 +48,9 @@ config GENERIC_IOMAP config GENERIC_TIME def_bool n +config SYS_SUPPORTS_APM_EMULATION + bool + config ARCH_MAY_HAVE_PC_FDC bool @@ -126,17 +129,12 @@ config SH_7751_SYSTEMH config SH_HP6XX bool "HP6XX" + select SYS_SUPPORTS_APM_EMULATION help Select HP6XX if configuring for a HP jornada HP6xx. More information (hardware only) at . -config SH_EC3104 - bool "EC3104" - help - Select EC3104 if configuring for a system with an Eclipse - International EC3104 chip, e.g. the Harris AD2000. - config SH_SATURN bool "Saturn" select CPU_SUBTYPE_SH7604 @@ -152,9 +150,6 @@ config SH_DREAMCAST . There is a Dreamcast project is at . -config SH_BIGSUR - bool "BigSur" - config SH_MPC1211 bool "Interface MPC1211" help @@ -477,6 +472,7 @@ config SH_PCLK_FREQ config SH_CLK_MD int "CPU Mode Pin Setting" + default 0 depends on CPU_SUBTYPE_SH7619 || CPU_SUBTYPE_SH7206 help MD2 - MD0 pin setting. @@ -506,8 +502,9 @@ source "arch/sh/cchips/Kconfig" config HEARTBEAT bool "Heartbeat LED" depends on SH_MPC1211 || SH_SH03 || \ - SH_BIGSUR || SOLUTION_ENGINE || \ - SH_RTS7751R2D || SH_SH4202_MICRODEV || SH_LANDISK + SOLUTION_ENGINE || \ + SH_RTS7751R2D || SH_SH4202_MICRODEV || SH_LANDISK || \ + SH_R7780RP help Use the power-on LED on your machine as a load meter. The exact behavior is platform-dependent, but normally the flash frequency is @@ -592,6 +589,8 @@ menu "Boot options" config ZERO_PAGE_OFFSET hex "Zero page offset" default "0x00004000" if SH_MPC1211 || SH_SH03 + default "0x00010000" if PAGE_SIZE_64KB + default "0x00002000" if PAGE_SIZE_8KB default "0x00001000" help This sets the default offset of zero page. @@ -694,9 +693,6 @@ depends on EXPERIMENTAL source kernel/power/Kconfig -config APM - bool "Advanced Power Management Emulation" - depends on PM endmenu source "net/Kconfig" diff --git a/arch/sh/Makefile b/arch/sh/Makefile index c1dbef2..bd9b172 100644 --- a/arch/sh/Makefile +++ b/arch/sh/Makefile @@ -35,6 +35,7 @@ endif endif cflags-$(CONFIG_CPU_SH2) := -m2 +cflags-$(CONFIG_CPU_SH2A) := -m2a $(call cc-option,-m2a-nofpu,) cflags-$(CONFIG_CPU_SH3) := -m3 cflags-$(CONFIG_CPU_SH4) := -m4 \ $(call cc-option,-mno-implicit-fp,-m4-nofpu) @@ -93,10 +94,8 @@ machdir-$(CONFIG_SH_7300_SOLUTION_ENGINE machdir-$(CONFIG_SH_7343_SOLUTION_ENGINE) := se/7343 machdir-$(CONFIG_SH_73180_SOLUTION_ENGINE) := se/73180 machdir-$(CONFIG_SH_HP6XX) := hp6xx -machdir-$(CONFIG_SH_EC3104) := ec3104 machdir-$(CONFIG_SH_SATURN) := saturn machdir-$(CONFIG_SH_DREAMCAST) := dreamcast -machdir-$(CONFIG_SH_BIGSUR) := bigsur machdir-$(CONFIG_SH_MPC1211) := mpc1211 machdir-$(CONFIG_SH_SH03) := sh03 machdir-$(CONFIG_SH_SECUREEDGE5410) := snapgear diff --git a/arch/sh/boards/bigsur/Makefile b/arch/sh/boards/bigsur/Makefile deleted file mode 100644 index 0ff9497..0000000 --- a/arch/sh/boards/bigsur/Makefile +++ /dev/null @@ -1,6 +0,0 @@ -# -# Makefile for the BigSur specific parts of the kernel -# - -obj-y := setup.o io.o irq.o led.o - diff --git a/arch/sh/boards/bigsur/io.c b/arch/sh/boards/bigsur/io.c deleted file mode 100644 index 23071f9..0000000 --- a/arch/sh/boards/bigsur/io.c +++ /dev/null @@ -1,120 +0,0 @@ -/* - * arch/sh/boards/bigsur/io.c - * - * By Dustin McIntire (dustin@sensoria.com) (c)2001 - * Derived from io_hd64465.h, which bore the message: - * By Greg Banks - * (c) 2000 PocketPenguins Inc. - * and from io_hd64461.h, which bore the message: - * Copyright 2000 Stuart Menefy (stuart.menefy@st.com) - * - * May be copied or modified under the terms of the GNU General Public - * License. See linux/COPYING for more information. - * - * IO functions for a Hitachi Big Sur Evaluation Board. - */ - -#include -#include -#include -#include -#include - -/* Low iomap maps port 0-1K to addresses in 8byte chunks */ -#define BIGSUR_IOMAP_LO_THRESH 0x400 -#define BIGSUR_IOMAP_LO_SHIFT 3 -#define BIGSUR_IOMAP_LO_MASK ((1<>BIGSUR_IOMAP_LO_SHIFT) -static u32 bigsur_iomap_lo[BIGSUR_IOMAP_LO_NMAP]; -static u8 bigsur_iomap_lo_shift[BIGSUR_IOMAP_LO_NMAP]; - -/* High iomap maps port 1K-64K to addresses in 1K chunks */ -#define BIGSUR_IOMAP_HI_THRESH 0x10000 -#define BIGSUR_IOMAP_HI_SHIFT 10 -#define BIGSUR_IOMAP_HI_MASK ((1<>BIGSUR_IOMAP_HI_SHIFT) -static u32 bigsur_iomap_hi[BIGSUR_IOMAP_HI_NMAP]; -static u8 bigsur_iomap_hi_shift[BIGSUR_IOMAP_HI_NMAP]; - -void bigsur_port_map(u32 baseport, u32 nports, u32 addr, u8 shift) -{ - u32 port, endport = baseport + nports; - - pr_debug("bigsur_port_map(base=0x%0x, n=0x%0x, addr=0x%08x)\n", - baseport, nports, addr); - - for (port = baseport ; - port < endport && port < BIGSUR_IOMAP_LO_THRESH ; - port += (1<>BIGSUR_IOMAP_LO_SHIFT] = addr; - bigsur_iomap_lo_shift[port>>BIGSUR_IOMAP_LO_SHIFT] = shift; - addr += (1<<(BIGSUR_IOMAP_LO_SHIFT)); - } - - for (port = max_t(u32, baseport, BIGSUR_IOMAP_LO_THRESH); - port < endport && port < BIGSUR_IOMAP_HI_THRESH ; - port += (1<>BIGSUR_IOMAP_HI_SHIFT] = addr; - bigsur_iomap_hi_shift[port>>BIGSUR_IOMAP_HI_SHIFT] = shift; - addr += (1<<(BIGSUR_IOMAP_HI_SHIFT)); - } -} -EXPORT_SYMBOL(bigsur_port_map); - -void bigsur_port_unmap(u32 baseport, u32 nports) -{ - u32 port, endport = baseport + nports; - - pr_debug("bigsur_port_unmap(base=0x%0x, n=0x%0x)\n", baseport, nports); - - for (port = baseport ; - port < endport && port < BIGSUR_IOMAP_LO_THRESH ; - port += (1<>BIGSUR_IOMAP_LO_SHIFT] = 0; - } - - for (port = max_t(u32, baseport, BIGSUR_IOMAP_LO_THRESH); - port < endport && port < BIGSUR_IOMAP_HI_THRESH ; - port += (1<>BIGSUR_IOMAP_HI_SHIFT] = 0; - } -} -EXPORT_SYMBOL(bigsur_port_unmap); - -unsigned long bigsur_isa_port2addr(unsigned long port) -{ - unsigned long addr = 0; - unsigned char shift; - - /* Physical address not in P0, do nothing */ - if (PXSEG(port)) { - addr = port; - /* physical address in P0, map to P2 */ - } else if (port >= 0x30000) { - addr = P2SEGADDR(port); - /* Big Sur I/O + HD64465 registers 0x10000-0x30000 */ - } else if (port >= BIGSUR_IOMAP_HI_THRESH) { - addr = BIGSUR_INTERNAL_BASE + (port - BIGSUR_IOMAP_HI_THRESH); - /* Handle remapping of high IO/PCI IO ports */ - } else if (port >= BIGSUR_IOMAP_LO_THRESH) { - addr = bigsur_iomap_hi[port >> BIGSUR_IOMAP_HI_SHIFT]; - shift = bigsur_iomap_hi_shift[port >> BIGSUR_IOMAP_HI_SHIFT]; - - if (addr != 0) - addr += (port & BIGSUR_IOMAP_HI_MASK) << shift; - } else { - /* Handle remapping of low IO ports */ - addr = bigsur_iomap_lo[port >> BIGSUR_IOMAP_LO_SHIFT]; - shift = bigsur_iomap_lo_shift[port >> BIGSUR_IOMAP_LO_SHIFT]; - - if (addr != 0) - addr += (port & BIGSUR_IOMAP_LO_MASK) << shift; - } - - pr_debug("%s(0x%08lx) = 0x%08lx\n", __FUNCTION__, port, addr); - - return addr; -} - diff --git a/arch/sh/boards/bigsur/irq.c b/arch/sh/boards/bigsur/irq.c deleted file mode 100644 index 1ab04da..0000000 --- a/arch/sh/boards/bigsur/irq.c +++ /dev/null @@ -1,334 +0,0 @@ -/* - * - * By Dustin McIntire (dustin@sensoria.com) (c)2001 - * - * Setup and IRQ handling code for the HD64465 companion chip. - * by Greg Banks - * Copyright (c) 2000 PocketPenguins Inc - * - * Derived from setup_hd64465.c which bore the message: - * Greg Banks - * Copyright (c) 2000 PocketPenguins Inc and - * Copyright (C) 2000 YAEGASHI Takeshi - * and setup_cqreek.c which bore message: - * Copyright (C) 2000 Niibe Yutaka - * - * May be copied or modified under the terms of the GNU General Public - * License. See linux/COPYING for more information. - * - * IRQ functions for a Hitachi Big Sur Evaluation Board. - * - */ -#undef DEBUG - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -#include -#include -#include - -//#define BIGSUR_DEBUG 3 -#undef BIGSUR_DEBUG - -#ifdef BIGSUR_DEBUG -#define DIPRINTK(n, args...) if (BIGSUR_DEBUG>(n)) printk(args) -#else -#define DIPRINTK(n, args...) -#endif /* BIGSUR_DEBUG */ - -#ifdef CONFIG_HD64465 -extern int hd64465_irq_demux(int irq); -#endif /* CONFIG_HD64465 */ - - -/*===========================================================*/ -// Big Sur CPLD IRQ Routines -/*===========================================================*/ - -/* Level 1 IRQ routines */ -static void disable_bigsur_l1irq(unsigned int irq) -{ - unsigned char mask; - unsigned int mask_port = ((irq - BIGSUR_IRQ_LOW)/8) ? BIGSUR_IRLMR1 : BIGSUR_IRLMR0; - unsigned char bit = (1 << ((irq - MGATE_IRQ_LOW)%8) ); - - if(irq >= BIGSUR_IRQ_LOW && irq < BIGSUR_IRQ_HIGH) { - pr_debug("Disable L1 IRQ %d\n", irq); - DIPRINTK(2,"disable_bigsur_l1irq: IMR=0x%08x mask=0x%x\n", - mask_port, bit); - - /* Disable IRQ - set mask bit */ - mask = inb(mask_port) | bit; - outb(mask, mask_port); - return; - } - pr_debug("disable_bigsur_l1irq: Invalid IRQ %d\n", irq); -} - -static void enable_bigsur_l1irq(unsigned int irq) -{ - unsigned char mask; - unsigned int mask_port = ((irq - BIGSUR_IRQ_LOW)/8) ? BIGSUR_IRLMR1 : BIGSUR_IRLMR0; - unsigned char bit = (1 << ((irq - MGATE_IRQ_LOW)%8) ); - - if(irq >= BIGSUR_IRQ_LOW && irq < BIGSUR_IRQ_HIGH) { - pr_debug("Enable L1 IRQ %d\n", irq); - DIPRINTK(2,"enable_bigsur_l1irq: IMR=0x%08x mask=0x%x\n", - mask_port, bit); - /* Enable L1 IRQ - clear mask bit */ - mask = inb(mask_port) & ~bit; - outb(mask, mask_port); - return; - } - pr_debug("enable_bigsur_l1irq: Invalid IRQ %d\n", irq); -} - - -/* Level 2 irq masks and registers for L2 decoding */ -/* Level2 bitmasks for each level 1 IRQ */ -const u32 bigsur_l2irq_mask[] = - {0x40,0x80,0x08,0x01,0x01,0x3C,0x3E,0xFF,0x40,0x80,0x06,0x03}; -/* Level2 to ISR[n] map for each level 1 IRQ */ -const u32 bigsur_l2irq_reg[] = - { 2, 2, 3, 3, 1, 2, 1, 0, 1, 1, 3, 2}; -/* Level2 to Level 1 IRQ map */ -const u32 bigsur_l2_l1_map[] = - {7,7,7,7,7,7,7,7, 4,6,6,6,6,6,8,9, 11,11,5,5,5,5,0,1, 3,10,10,2,-1,-1,-1,-1}; -/* IRQ inactive level (high or low) */ -const u32 bigsur_l2_inactv_state[] = {0x00, 0xBE, 0xFC, 0xF7}; - -/* CPLD external status and mask registers base and offsets */ -static const u32 isr_base = BIGSUR_IRQ0; -static const u32 isr_offset = BIGSUR_IRQ0 - BIGSUR_IRQ1; -static const u32 imr_base = BIGSUR_IMR0; -static const u32 imr_offset = BIGSUR_IMR0 - BIGSUR_IMR1; - -#define REG_NUM(irq) ((irq-BIGSUR_2NDLVL_IRQ_LOW)/8 ) - -/* Level 2 IRQ routines */ -static void disable_bigsur_l2irq(unsigned int irq) -{ - unsigned char mask; - unsigned char bit = 1 << ((irq-BIGSUR_2NDLVL_IRQ_LOW)%8); - unsigned int mask_port = imr_base - REG_NUM(irq)*imr_offset; - - if(irq >= BIGSUR_2NDLVL_IRQ_LOW && irq < BIGSUR_2NDLVL_IRQ_HIGH) { - pr_debug("Disable L2 IRQ %d\n", irq); - DIPRINTK(2,"disable_bigsur_l2irq: IMR=0x%08x mask=0x%x\n", - mask_port, bit); - - /* Disable L2 IRQ - set mask bit */ - mask = inb(mask_port) | bit; - outb(mask, mask_port); - return; - } - pr_debug("disable_bigsur_l2irq: Invalid IRQ %d\n", irq); -} - -static void enable_bigsur_l2irq(unsigned int irq) -{ - unsigned char mask; - unsigned char bit = 1 << ((irq-BIGSUR_2NDLVL_IRQ_LOW)%8); - unsigned int mask_port = imr_base - REG_NUM(irq)*imr_offset; - - if(irq >= BIGSUR_2NDLVL_IRQ_LOW && irq < BIGSUR_2NDLVL_IRQ_HIGH) { - pr_debug("Enable L2 IRQ %d\n", irq); - DIPRINTK(2,"enable_bigsur_l2irq: IMR=0x%08x mask=0x%x\n", - mask_port, bit); - - /* Enable L2 IRQ - clear mask bit */ - mask = inb(mask_port) & ~bit; - outb(mask, mask_port); - return; - } - pr_debug("enable_bigsur_l2irq: Invalid IRQ %d\n", irq); -} - -static void mask_and_ack_bigsur(unsigned int irq) -{ - pr_debug("mask_and_ack_bigsur IRQ %d\n", irq); - if(irq >= BIGSUR_IRQ_LOW && irq < BIGSUR_IRQ_HIGH) - disable_bigsur_l1irq(irq); - else - disable_bigsur_l2irq(irq); -} - -static void end_bigsur_irq(unsigned int irq) -{ - pr_debug("end_bigsur_irq IRQ %d\n", irq); - if (!(irq_desc[irq].status & (IRQ_DISABLED|IRQ_INPROGRESS))) { - if(irq >= BIGSUR_IRQ_LOW && irq < BIGSUR_IRQ_HIGH) - enable_bigsur_l1irq(irq); - else - enable_bigsur_l2irq(irq); - } -} - -static unsigned int startup_bigsur_irq(unsigned int irq) -{ - u8 mask; - u32 reg; - - pr_debug("startup_bigsur_irq IRQ %d\n", irq); - - if(irq >= BIGSUR_IRQ_LOW && irq < BIGSUR_IRQ_HIGH) { - /* Enable the L1 IRQ */ - enable_bigsur_l1irq(irq); - /* Enable all L2 IRQs in this L1 IRQ */ - mask = ~(bigsur_l2irq_mask[irq-BIGSUR_IRQ_LOW]); - reg = imr_base - bigsur_l2irq_reg[irq-BIGSUR_IRQ_LOW] * imr_offset; - mask &= inb(reg); - outb(mask,reg); - DIPRINTK(2,"startup_bigsur_irq: IMR=0x%08x mask=0x%x\n",reg,inb(reg)); - } - else { - /* Enable the L2 IRQ - clear mask bit */ - enable_bigsur_l2irq(irq); - /* Enable the L1 bit masking this L2 IRQ */ - enable_bigsur_l1irq(bigsur_l2_l1_map[irq-BIGSUR_2NDLVL_IRQ_LOW]); - DIPRINTK(2,"startup_bigsur_irq: L1=%d L2=%d\n", - bigsur_l2_l1_map[irq-BIGSUR_2NDLVL_IRQ_LOW],irq); - } - return 0; -} - -static void shutdown_bigsur_irq(unsigned int irq) -{ - pr_debug("shutdown_bigsur_irq IRQ %d\n", irq); - if(irq >= BIGSUR_IRQ_LOW && irq < BIGSUR_IRQ_HIGH) - disable_bigsur_l1irq(irq); - else - disable_bigsur_l2irq(irq); -} - -/* Define the IRQ structures for the L1 and L2 IRQ types */ -static struct hw_interrupt_type bigsur_l1irq_type = { - .typename = "BigSur-CPLD-Level1-IRQ", - .startup = startup_bigsur_irq, - .shutdown = shutdown_bigsur_irq, - .enable = enable_bigsur_l1irq, - .disable = disable_bigsur_l1irq, - .ack = mask_and_ack_bigsur, - .end = end_bigsur_irq -}; - -static struct hw_interrupt_type bigsur_l2irq_type = { - .typename = "BigSur-CPLD-Level2-IRQ", - .startup = startup_bigsur_irq, - .shutdown =shutdown_bigsur_irq, - .enable = enable_bigsur_l2irq, - .disable = disable_bigsur_l2irq, - .ack = mask_and_ack_bigsur, - .end = end_bigsur_irq -}; - - -static void make_bigsur_l1isr(unsigned int irq) { - - /* sanity check first */ - if(irq >= BIGSUR_IRQ_LOW && irq < BIGSUR_IRQ_HIGH) { - /* save the handler in the main description table */ - irq_desc[irq].chip = &bigsur_l1irq_type; - irq_desc[irq].status = IRQ_DISABLED; - irq_desc[irq].action = 0; - irq_desc[irq].depth = 1; - - disable_bigsur_l1irq(irq); - return; - } - pr_debug("make_bigsur_l1isr: bad irq, %d\n", irq); - return; -} - -static void make_bigsur_l2isr(unsigned int irq) { - - /* sanity check first */ - if(irq >= BIGSUR_2NDLVL_IRQ_LOW && irq < BIGSUR_2NDLVL_IRQ_HIGH) { - /* save the handler in the main description table */ - irq_desc[irq].chip = &bigsur_l2irq_type; - irq_desc[irq].status = IRQ_DISABLED; - irq_desc[irq].action = 0; - irq_desc[irq].depth = 1; - - disable_bigsur_l2irq(irq); - return; - } - pr_debug("make_bigsur_l2isr: bad irq, %d\n", irq); - return; -} - -/* The IRQ's will be decoded as follows: - * If a level 2 handler exists and there is an unmasked active - * IRQ, the 2nd level handler will be called. - * If a level 2 handler does not exist for the active IRQ - * the 1st level handler will be called. - */ - -int bigsur_irq_demux(int irq) -{ - int dmux_irq = irq; - u8 mask, actv_irqs; - u32 reg_num; - - DIPRINTK(3,"bigsur_irq_demux, irq=%d\n", irq); - /* decode the 1st level IRQ */ - if(irq >= BIGSUR_IRQ_LOW && irq < BIGSUR_IRQ_HIGH) { - /* Get corresponding L2 ISR bitmask and ISR number */ - mask = bigsur_l2irq_mask[irq-BIGSUR_IRQ_LOW]; - reg_num = bigsur_l2irq_reg[irq-BIGSUR_IRQ_LOW]; - /* find the active IRQ's (XOR with inactive level)*/ - actv_irqs = inb(isr_base-reg_num*isr_offset) ^ - bigsur_l2_inactv_state[reg_num]; - /* decode active IRQ's */ - actv_irqs = actv_irqs & mask & ~(inb(imr_base-reg_num*imr_offset)); - /* if NEZ then we have an active L2 IRQ */ - if(actv_irqs) dmux_irq = ffz(~actv_irqs) + reg_num*8+BIGSUR_2NDLVL_IRQ_LOW; - /* if no 2nd level IRQ action, but has 1st level, use 1st level handler */ - if(!irq_desc[dmux_irq].action && irq_desc[irq].action) - dmux_irq = irq; - DIPRINTK(1,"bigsur_irq_demux: irq=%d dmux_irq=%d mask=0x%04x reg=%d\n", - irq, dmux_irq, mask, reg_num); - } -#ifdef CONFIG_HD64465 - dmux_irq = hd64465_irq_demux(dmux_irq); -#endif /* CONFIG_HD64465 */ - DIPRINTK(3,"bigsur_irq_demux, demux_irq=%d\n", dmux_irq); - - return dmux_irq; -} - -/*===========================================================*/ -// Big Sur Init Routines -/*===========================================================*/ -void __init init_bigsur_IRQ(void) -{ - int i; - - if (!MACH_BIGSUR) return; - - /* Create ISR's for Big Sur CPLD IRQ's */ - /*==============================================================*/ - for(i=BIGSUR_IRQ_LOW;i - * - * May be copied or modified under the terms of the GNU General Public - * License. See linux/COPYING for more information. - * - * This file contains Big Sur specific LED code. - */ - -#include -#include - -static void mach_led(int position, int value) -{ - int word; - - word = bigsur_inl(BIGSUR_CSLR); - if (value) { - bigsur_outl(word & ~BIGSUR_LED, BIGSUR_CSLR); - } else { - bigsur_outl(word | BIGSUR_LED, BIGSUR_CSLR); - } -} - -#ifdef CONFIG_HEARTBEAT - -#include - -/* Cycle the LED on/off */ -void heartbeat_bigsur(void) -{ - static unsigned cnt = 0, period = 0, dist = 0; - - if (cnt == 0 || cnt == dist) - mach_led( -1, 1); - else if (cnt == 7 || cnt == dist+7) - mach_led( -1, 0); - - if (++cnt > period) { - cnt = 0; - /* The hyperbolic function below modifies the heartbeat period - * length in dependency of the current (5min) load. It goes - * through the points f(0)=126, f(1)=86, f(5)=51, - * f(inf)->30. */ - period = ((672< - * Copyright (c) 2000 PocketPenguins Inc - * - * Derived from setup_hd64465.c which bore the message: - * Greg Banks - * Copyright (c) 2000 PocketPenguins Inc and - * Copyright (C) 2000 YAEGASHI Takeshi - * and setup_cqreek.c which bore message: - * Copyright (C) 2000 Niibe Yutaka - * - * May be copied or modified under the terms of the GNU General Public - * License. See linux/COPYING for more information. - * - * Setup functions for a Hitachi Big Sur Evaluation Board. - * - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include - -/*===========================================================*/ -// Big Sur Init Routines -/*===========================================================*/ - -static void __init bigsur_setup(char **cmdline_p) -{ - /* Mask all 2nd level IRQ's */ - outb(-1,BIGSUR_IMR0); - outb(-1,BIGSUR_IMR1); - outb(-1,BIGSUR_IMR2); - outb(-1,BIGSUR_IMR3); - - /* Mask 1st level interrupts */ - outb(-1,BIGSUR_IRLMR0); - outb(-1,BIGSUR_IRLMR1); - -#if defined (CONFIG_HD64465) && defined (CONFIG_SERIAL) - /* remap IO ports for first ISA serial port to HD64465 UART */ - bigsur_port_map(0x3f8, 8, CONFIG_HD64465_IOBASE + 0x8000, 1); -#endif /* CONFIG_HD64465 && CONFIG_SERIAL */ - /* TODO: setup IDE registers */ - bigsur_port_map(BIGSUR_IDECTL_IOPORT, 2, BIGSUR_ICTL, 8); - /* Setup the Ethernet port to BIGSUR_ETHER_IOPORT */ - bigsur_port_map(BIGSUR_ETHER_IOPORT, 16, BIGSUR_ETHR+BIGSUR_ETHER_IOPORT, 0); - /* set page to 1 */ - outw(1, BIGSUR_ETHR+0xe); - /* set the IO port to BIGSUR_ETHER_IOPORT */ - outw(BIGSUR_ETHER_IOPORT<<3, BIGSUR_ETHR+0x2); -} - -/* - * The Machine Vector - */ -extern void heartbeat_bigsur(void); -extern void init_bigsur_IRQ(void); - -struct sh_machine_vector mv_bigsur __initmv = { - .mv_name = "Big Sur", - .mv_setup = bigsur_setup, - - .mv_isa_port2addr = bigsur_isa_port2addr, - .mv_irq_demux = bigsur_irq_demux, - - .mv_init_irq = init_bigsur_IRQ, -#ifdef CONFIG_HEARTBEAT - .mv_heartbeat = heartbeat_bigsur, -#endif -}; -ALIAS_MV(bigsur) diff --git a/arch/sh/boards/ec3104/Makefile b/arch/sh/boards/ec3104/Makefile deleted file mode 100644 index 1788915..0000000 --- a/arch/sh/boards/ec3104/Makefile +++ /dev/null @@ -1,6 +0,0 @@ -# -# Makefile for the EC3104 specific parts of the kernel -# - -obj-y := setup.o io.o irq.o - diff --git a/arch/sh/boards/ec3104/io.c b/arch/sh/boards/ec3104/io.c deleted file mode 100644 index 2f86394..0000000 --- a/arch/sh/boards/ec3104/io.c +++ /dev/null @@ -1,81 +0,0 @@ -/* - * linux/arch/sh/boards/ec3104/io.c - * EC3104 companion chip support - * - * Copyright (C) 2000 Philipp Rumpf - * - */ -/* EC3104 note: - * This code was written without any documentation about the EC3104 chip. While - * I hope I got most of the basic functionality right, the register names I use - * are most likely completely different from those in the chip documentation. - * - * If you have any further information about the EC3104, please tell me - * (prumpf@tux.org). - */ - -#include -#include -#include -#include -#include - -/* - * EC3104 has a real ISA bus which we redirect low port accesses to (the - * actual device on mine is a ESS 1868, and I don't want to hack the driver - * more than strictly necessary). I am not going to duplicate the - * hard coding of PC addresses (for the 16550s aso) here though; it's just - * too ugly. - */ - -#define low_port(port) ((port) < 0x10000) - -static inline unsigned long port2addr(unsigned long port) -{ - switch(port >> 16) { - case 0: - return EC3104_ISA_BASE + port * 2; - - /* XXX hack. it's unclear what to do about the serial ports */ - case 1: - return EC3104_BASE + (port&0xffff) * 4; - - default: - /* XXX PCMCIA */ - return 0; - } -} - -unsigned char ec3104_inb(unsigned long port) -{ - u8 ret; - - ret = *(volatile u8 *)port2addr(port); - - return ret; -} - -unsigned short ec3104_inw(unsigned long port) -{ - BUG(); -} - -unsigned long ec3104_inl(unsigned long port) -{ - BUG(); -} - -void ec3104_outb(unsigned char data, unsigned long port) -{ - *(volatile u8 *)port2addr(port) = data; -} - -void ec3104_outw(unsigned short data, unsigned long port) -{ - BUG(); -} - -void ec3104_outl(unsigned long data, unsigned long port) -{ - BUG(); -} diff --git a/arch/sh/boards/ec3104/irq.c b/arch/sh/boards/ec3104/irq.c deleted file mode 100644 index ffa4ff1..0000000 --- a/arch/sh/boards/ec3104/irq.c +++ /dev/null @@ -1,196 +0,0 @@ -/* - * linux/arch/sh/boards/ec3104/irq.c - * EC3104 companion chip support - * - * Copyright (C) 2000 Philipp Rumpf - * - */ - -#include -#include -#include - -/* This is for debugging mostly; here's the table that I intend to keep - * in here: - * - * index function base addr power interrupt bit - * 0 power b0ec0000 --- 00000001 (unused) - * 1 irqs b0ec1000 --- 00000002 (unused) - * 2 ?? b0ec2000 b0ec0008 00000004 - * 3 PS2 (1) b0ec3000 b0ec000c 00000008 - * 4 PS2 (2) b0ec4000 b0ec0010 00000010 - * 5 ?? b0ec5000 b0ec0014 00000020 - * 6 I2C b0ec6000 b0ec0018 00000040 - * 7 serial (1) b0ec7000 b0ec001c 00000080 - * 8 serial (2) b0ec8000 b0ec0020 00000100 - * 9 serial (3) b0ec9000 b0ec0024 00000200 - * 10 serial (4) b0eca000 b0ec0028 00000400 - * 12 GPIO (1) b0ecc000 b0ec0030 - * 13 GPIO (2) b0ecc000 b0ec0030 - * 16 pcmcia (1) b0ed0000 b0ec0040 00010000 - * 17 pcmcia (2) b0ed1000 b0ec0044 00020000 - */ - -/* I used the register names from another interrupt controller I worked with, - * since it seems to be identical to the ec3104 except that all bits are - * inverted: - * - * IRR: Interrupt Request Register (pending and enabled interrupts) - * IMR: Interrupt Mask Register (which interrupts are enabled) - * IPR: Interrupt Pending Register (pending interrupts, even disabled ones) - * - * 0 bits mean pending or enabled, 1 bits mean not pending or disabled. all - * IRQs seem to be level-triggered. - */ - -#define EC3104_IRR (EC3104_BASE + 0x1000) -#define EC3104_IMR (EC3104_BASE + 0x1004) -#define EC3104_IPR (EC3104_BASE + 0x1008) - -#define ctrl_readl(addr) (*(volatile u32 *)(addr)) -#define ctrl_writel(data,addr) (*(volatile u32 *)(addr) = (data)) -#define ctrl_readb(addr) (*(volatile u8 *)(addr)) - -static char *ec3104_name(unsigned index) -{ - switch(index) { - case 0: - return "power management"; - case 1: - return "interrupts"; - case 3: - return "PS2 (1)"; - case 4: - return "PS2 (2)"; - case 5: - return "I2C (1)"; - case 6: - return "I2C (2)"; - case 7: - return "serial (1)"; - case 8: - return "serial (2)"; - case 9: - return "serial (3)"; - case 10: - return "serial (4)"; - case 16: - return "pcmcia (1)"; - case 17: - return "pcmcia (2)"; - default: { - static char buf[32]; - - sprintf(buf, "unknown (%d)", index); - - return buf; - } - } -} - -int get_pending_interrupts(char *buf) -{ - u32 ipr; - u32 bit; - char *p = buf; - - p += sprintf(p, "pending: ("); - - ipr = ctrl_inl(EC3104_IPR); - - for (bit = 1; bit < 32; bit++) - if (!(ipr & (1< - * - */ -/* EC3104 note: - * This code was written without any documentation about the EC3104 chip. While - * I hope I got most of the basic functionality right, the register names I use - * are most likely completely different from those in the chip documentation. - * - * If you have any further information about the EC3104, please tell me - * (prumpf@tux.org). - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -static void __init ec3104_setup(char **cmdline_p) -{ - char str[8]; - int i; - - for (i=0; i<8; i++) - str[i] = ctrl_readb(EC3104_BASE + i); - - for (i = EC3104_IRQBASE; i < EC3104_IRQBASE + 32; i++) - irq_desc[i].handler = &ec3104_int; - - printk("initializing EC3104 \"%.8s\" at %08x, IRQ %d, IRQ base %d\n", - str, EC3104_BASE, EC3104_IRQ, EC3104_IRQBASE); - - /* mask all interrupts. this should have been done by the boot - * loader for us but we want to be sure ... */ - ctrl_writel(0xffffffff, EC3104_IMR); -} - -/* - * The Machine Vector - */ -struct sh_machine_vector mv_ec3104 __initmv = { - .mv_name = "EC3104", - .mv_setup = ec3104_setup, - .mv_nr_irqs = 96, - - .mv_inb = ec3104_inb, - .mv_inw = ec3104_inw, - .mv_inl = ec3104_inl, - .mv_outb = ec3104_outb, - .mv_outw = ec3104_outw, - .mv_outl = ec3104_outl, - - .mv_irq_demux = ec3104_irq_demux, -}; -ALIAS_MV(ec3104) diff --git a/arch/sh/boards/hp6xx/hp6xx_apm.c b/arch/sh/boards/hp6xx/hp6xx_apm.c index d146cda..d1c1460 100644 --- a/arch/sh/boards/hp6xx/hp6xx_apm.c +++ b/arch/sh/boards/hp6xx/hp6xx_apm.c @@ -7,12 +7,11 @@ * modify it under the terms of the GNU General Public License. */ #include -#include #include #include #include -#include -#include +#include +#include #include #include @@ -27,60 +26,41 @@ #define HP680_BATTERY_AC_ON 900 #define MODNAME "hp6x0_apm" -static int hp6x0_apm_get_info(char *buf, char **start, off_t fpos, int length) +static void hp6x0_apm_get_power_status(struct apm_power_info *info) { + int battery, backup, charging, percentage; u8 pgdr; - char *p; - int battery_status; - int battery_flag; - int ac_line_status; - int time_units = APM_BATTERY_LIFE_UNKNOWN; - int battery = adc_single(ADC_CHANNEL_BATTERY); - int backup = adc_single(ADC_CHANNEL_BACKUP); - int charging = adc_single(ADC_CHANNEL_CHARGE); - int percentage; + battery = adc_single(ADC_CHANNEL_BATTERY); + backup = adc_single(ADC_CHANNEL_BACKUP); + charging = adc_single(ADC_CHANNEL_CHARGE); percentage = 100 * (battery - HP680_BATTERY_MIN) / (HP680_BATTERY_MAX - HP680_BATTERY_MIN); - ac_line_status = (battery > HP680_BATTERY_AC_ON) ? + info->ac_line_status = (battery > HP680_BATTERY_AC_ON) ? APM_AC_ONLINE : APM_AC_OFFLINE; - p = buf; - pgdr = ctrl_inb(SH7709_PGDR); if (pgdr & PGDR_MAIN_BATTERY_OUT) { - battery_status = APM_BATTERY_STATUS_NOT_PRESENT; - battery_flag = 0x80; - percentage = -1; - } else if (charging < 8 ) { - battery_status = APM_BATTERY_STATUS_CHARGING; - battery_flag = 0x08; - ac_line_status = 0xff; + info->battery_status = APM_BATTERY_STATUS_NOT_PRESENT; + info->battery_flag = 0x80; + } else if (charging < 8) { + info->battery_status = APM_BATTERY_STATUS_CHARGING; + info->battery_flag = 0x08; + info->ac_line_status = 0xff; } else if (percentage <= APM_CRITICAL) { - battery_status = APM_BATTERY_STATUS_CRITICAL; - battery_flag = 0x04; + info->battery_status = APM_BATTERY_STATUS_CRITICAL; + info->battery_flag = 0x04; } else if (percentage <= APM_LOW) { - battery_status = APM_BATTERY_STATUS_LOW; - battery_flag = 0x02; + info->battery_status = APM_BATTERY_STATUS_LOW; + info->battery_flag = 0x02; } else { - battery_status = APM_BATTERY_STATUS_HIGH; - battery_flag = 0x01; + info->battery_status = APM_BATTERY_STATUS_HIGH; + info->battery_flag = 0x01; } - p += sprintf(p, "1.0 1.2 0x%02x 0x%02x 0x%02x 0x%02x %d%% %d %s\n", - APM_32_BIT_SUPPORT, - ac_line_status, - battery_status, - battery_flag, - percentage, - time_units, - "min"); - p += sprintf(p, "bat=%d backup=%d charge=%d\n", - battery, backup, charging); - - return p - buf; + info->units = 0; } static irqreturn_t hp6x0_apm_interrupt(int irq, void *dev) @@ -96,14 +76,14 @@ static int __init hp6x0_apm_init(void) int ret; ret = request_irq(HP680_BTN_IRQ, hp6x0_apm_interrupt, - IRQF_DISABLED, MODNAME, 0); + IRQF_DISABLED, MODNAME, NULL); if (unlikely(ret < 0)) { printk(KERN_ERR MODNAME ": IRQ %d request failed\n", HP680_BTN_IRQ); return ret; } - apm_get_info = hp6x0_apm_get_info; + apm_get_power_status = hp6x0_apm_get_power_status; return ret; } @@ -111,7 +91,7 @@ static int __init hp6x0_apm_init(void) static void __exit hp6x0_apm_exit(void) { free_irq(HP680_BTN_IRQ, 0); - apm_get_info = 0; + apm_get_info = NULL; } module_init(hp6x0_apm_init); diff --git a/arch/sh/boards/landisk/landisk_pwb.c b/arch/sh/boards/landisk/landisk_pwb.c index e625249..47a63c6 100644 --- a/arch/sh/boards/landisk/landisk_pwb.c +++ b/arch/sh/boards/landisk/landisk_pwb.c @@ -150,7 +150,7 @@ static irqreturn_t sw_interrupt(int irq, return IRQ_HANDLED; } -static struct file_operations swdrv_fops = { +static const struct file_operations swdrv_fops = { .read = swdrv_read, /* read */ .write = swdrv_write, /* write */ .open = swdrv_open, /* open */ diff --git a/arch/sh/boards/mpc1211/Makefile b/arch/sh/boards/mpc1211/Makefile index 1644ebe..8cd31b5 100644 --- a/arch/sh/boards/mpc1211/Makefile +++ b/arch/sh/boards/mpc1211/Makefile @@ -2,7 +2,7 @@ # # Makefile for the Interface (CTP/PCI/MPC-SH02) specific parts of the kernel # -obj-y := setup.o rtc.o led.o +obj-y := setup.o rtc.o obj-$(CONFIG_PCI) += pci.o diff --git a/arch/sh/boards/mpc1211/led.c b/arch/sh/boards/mpc1211/led.c deleted file mode 100644 index 8df1591..0000000 --- a/arch/sh/boards/mpc1211/led.c +++ /dev/null @@ -1,63 +0,0 @@ -/* - * linux/arch/sh/boards/mpc1211/led.c - * - * Copyright (C) 2001 Saito.K & Jeanne - * - * This file contains Interface MPC-1211 specific LED code. - */ - - -static void mach_led(int position, int value) -{ - volatile unsigned char* p = (volatile unsigned char*)0xa2000000; - - if (value) { - *p |= 1; - } else { - *p &= ~1; - } -} - -#ifdef CONFIG_HEARTBEAT - -#include - -/* Cycle the LED's in the clasic Knightrider/Sun pattern */ -void heartbeat_mpc1211(void) -{ - static unsigned int cnt = 0, period = 0; - volatile unsigned char* p = (volatile unsigned char*)0xa2000000; - static unsigned bit = 0, up = 1; - - cnt += 1; - if (cnt < period) { - return; - } - - cnt = 0; - - /* Go through the points (roughly!): - * f(0)=10, f(1)=16, f(2)=20, f(5)=35,f(inf)->110 - */ - period = 110 - ( (300< #include #include #include +#include #include #include #include @@ -281,6 +282,32 @@ static int put_smb_blk(unsigned char *p, return 0; } +static struct resource heartbeat_resources[] = { + [0] = { + .start = 0xa2000000, + .end = 0xa2000000 + 8 - 1, + .flags = IORESOURCE_MEM, + }, +}; + +static struct platform_device heartbeat_device = { + .name = "heartbeat", + .id = -1, + .num_resources = ARRAY_SIZE(heartbeat_resources), + .resource = heartbeat_resources, +}; + +static struct platform_device *mpc1211_devices[] __initdata = { + &heartbeat_device, +}; + +static int __init mpc1211_devices_setup(void) +{ + return platform_add_devices(mpc1211_devices, + ARRAY_SIZE(mpc1211_devices)); +} +__initcall(mpc1211_devices_setup); + /* arch/sh/boards/mpc1211/rtc.c */ void mpc1211_time_init(void); @@ -317,9 +344,5 @@ struct sh_machine_vector mv_mpc1211 __in .mv_nr_irqs = 48, .mv_irq_demux = mpc1211_irq_demux, .mv_init_irq = init_mpc1211_IRQ, - -#ifdef CONFIG_HEARTBEAT - .mv_heartbeat = heartbeat_mpc1211, -#endif }; ALIAS_MV(mpc1211) diff --git a/arch/sh/boards/renesas/r7780rp/Makefile b/arch/sh/boards/renesas/r7780rp/Makefile index 574b031..3c93012 100644 --- a/arch/sh/boards/renesas/r7780rp/Makefile +++ b/arch/sh/boards/renesas/r7780rp/Makefile @@ -4,5 +4,4 @@ # obj-y := setup.o io.o irq.o -obj-$(CONFIG_HEARTBEAT) += led.o obj-$(CONFIG_PUSH_SWITCH) += psw.o diff --git a/arch/sh/boards/renesas/r7780rp/io.c b/arch/sh/boards/renesas/r7780rp/io.c index 311cccc..f74d2ff 100644 --- a/arch/sh/boards/renesas/r7780rp/io.c +++ b/arch/sh/boards/renesas/r7780rp/io.c @@ -11,22 +11,9 @@ #include #include #include +#include #include #include -#include - -static inline unsigned long port2adr(unsigned int port) -{ - if ((0x1f0 <= port && port < 0x1f8) || port == 0x3f6) - if (port == 0x3f6) - return (PA_AREA5_IO + 0x80c); - else - return (PA_AREA5_IO + 0x1000 + ((port-0x1f0) << 1)); - else - maybebadio((unsigned long)port); - - return port; -} static inline unsigned long port88796l(unsigned int port, int flag) { @@ -40,18 +27,6 @@ static inline unsigned long port88796l(u return addr; } -/* The 7780 R7780RP-1 seems to have everything hooked */ -/* up pretty normally (nothing on high-bytes only...) so this */ -/* shouldn't be needed */ -static inline int shifted_port(unsigned long port) -{ - /* For IDE registers, value is not shifted */ - if ((0x1f0 <= port && port < 0x1f8) || port == 0x3f6) - return 0; - else - return 1; -} - #if defined(CONFIG_NE2000) || defined(CONFIG_NE2000_MODULE) #define CHECK_AX88796L_PORT(port) \ ((port >= AX88796L_IO_BASE) && (port < (AX88796L_IO_BASE+0x20))) @@ -70,12 +45,10 @@ u8 r7780rp_inb(unsigned long port) { if (CHECK_AX88796L_PORT(port)) return ctrl_inw(port88796l(port, 0)) & 0xff; - else if (PXSEG(port)) - return ctrl_inb(port); - else if (is_pci_ioaddr(port) || shifted_port(port)) + else if (is_pci_ioaddr(port)) return ctrl_inb(pci_ioaddr(port)); - return ctrl_inw(port2adr(port)) & 0xff; + return ctrl_inw(port) & 0xff; } u8 r7780rp_inb_p(unsigned long port) @@ -84,12 +57,10 @@ u8 r7780rp_inb_p(unsigned long port) if (CHECK_AX88796L_PORT(port)) v = ctrl_inw(port88796l(port, 0)) & 0xff; - else if (PXSEG(port)) - v = ctrl_inb(port); - else if (is_pci_ioaddr(port) || shifted_port(port)) + else if (is_pci_ioaddr(port)) v = ctrl_inb(pci_ioaddr(port)); else - v = ctrl_inw(port2adr(port)) & 0xff; + v = ctrl_inw(port) & 0xff; ctrl_delay(); @@ -98,80 +69,56 @@ u8 r7780rp_inb_p(unsigned long port) u16 r7780rp_inw(unsigned long port) { - if (CHECK_AX88796L_PORT(port)) - maybebadio(port); - else if (PXSEG(port)) - return ctrl_inw(port); - else if (is_pci_ioaddr(port) || shifted_port(port)) + if (is_pci_ioaddr(port)) return ctrl_inw(pci_ioaddr(port)); - else - maybebadio(port); - return 0; + return ctrl_inw(port); } u32 r7780rp_inl(unsigned long port) { - if (CHECK_AX88796L_PORT(port)) - maybebadio(port); - else if (PXSEG(port)) - return ctrl_inl(port); - else if (is_pci_ioaddr(port) || shifted_port(port)) + if (is_pci_ioaddr(port)) return ctrl_inl(pci_ioaddr(port)); - else - maybebadio(port); - return 0; + return ctrl_inl(port); } void r7780rp_outb(u8 value, unsigned long port) { if (CHECK_AX88796L_PORT(port)) ctrl_outw(value, port88796l(port, 0)); - else if (PXSEG(port)) - ctrl_outb(value, port); - else if (is_pci_ioaddr(port) || shifted_port(port)) + else if (is_pci_ioaddr(port)) ctrl_outb(value, pci_ioaddr(port)); else - ctrl_outw(value, port2adr(port)); + ctrl_outb(value, port); } void r7780rp_outb_p(u8 value, unsigned long port) { if (CHECK_AX88796L_PORT(port)) ctrl_outw(value, port88796l(port, 0)); - else if (PXSEG(port)) - ctrl_outb(value, port); - else if (is_pci_ioaddr(port) || shifted_port(port)) + else if (is_pci_ioaddr(port)) ctrl_outb(value, pci_ioaddr(port)); else - ctrl_outw(value, port2adr(port)); + ctrl_outb(value, port); ctrl_delay(); } void r7780rp_outw(u16 value, unsigned long port) { - if (CHECK_AX88796L_PORT(port)) - maybebadio(port); - else if (PXSEG(port)) - ctrl_outw(value, port); - else if (is_pci_ioaddr(port) || shifted_port(port)) + if (is_pci_ioaddr(port)) ctrl_outw(value, pci_ioaddr(port)); else - maybebadio(port); + ctrl_outw(value, port); } void r7780rp_outl(u32 value, unsigned long port) { - if (CHECK_AX88796L_PORT(port)) - maybebadio(port); - else if (PXSEG(port)) - ctrl_outl(value, port); - else if (is_pci_ioaddr(port) || shifted_port(port)) + if (is_pci_ioaddr(port)) ctrl_outl(value, pci_ioaddr(port)); else - maybebadio(port); + ctrl_outl(value, port); } void r7780rp_insb(unsigned long port, void *dst, unsigned long count) @@ -183,16 +130,13 @@ void r7780rp_insb(unsigned long port, vo p = (volatile u16 *)port88796l(port, 0); while (count--) *buf++ = *p & 0xff; - } else if (PXSEG(port)) { - while (count--) - *buf++ = *(volatile u8 *)port; - } else if (is_pci_ioaddr(port) || shifted_port(port)) { + } else if (is_pci_ioaddr(port)) { volatile u8 *bp = (volatile u8 *)pci_ioaddr(port); while (count--) *buf++ = *bp; } else { - p = (volatile u16 *)port2adr(port); + p = (volatile u16 *)port; while (count--) *buf++ = *p & 0xff; } @@ -205,30 +149,26 @@ void r7780rp_insw(unsigned long port, vo if (CHECK_AX88796L_PORT(port)) p = (volatile u16 *)port88796l(port, 1); - else if (PXSEG(port)) - p = (volatile u16 *)port; - else if (is_pci_ioaddr(port) || shifted_port(port)) + else if (is_pci_ioaddr(port)) p = (volatile u16 *)pci_ioaddr(port); else - p = (volatile u16 *)port2adr(port); + p = (volatile u16 *)port; while (count--) *buf++ = *p; + + flush_dcache_all(); } void r7780rp_insl(unsigned long port, void *dst, unsigned long count) { - u32 *buf = dst; - - if (CHECK_AX88796L_PORT(port)) - maybebadio(port); - else if (is_pci_ioaddr(port) || shifted_port(port)) { + if (is_pci_ioaddr(port)) { volatile u32 *p = (volatile u32 *)pci_ioaddr(port); + u32 *buf = dst; while (count--) *buf++ = *p; - } else - maybebadio(port); + } } void r7780rp_outsb(unsigned long port, const void *src, unsigned long count) @@ -240,19 +180,14 @@ void r7780rp_outsb(unsigned long port, c p = (volatile u16 *)port88796l(port, 0); while (count--) *p = *buf++; - } else if (PXSEG(port)) - while (count--) - ctrl_outb(*buf++, port); - else if (is_pci_ioaddr(port) || shifted_port(port)) { + } else if (is_pci_ioaddr(port)) { volatile u8 *bp = (volatile u8 *)pci_ioaddr(port); while (count--) *bp = *buf++; - } else { - p = (volatile u16 *)port2adr(port); + } else while (count--) - *p = *buf++; - } + ctrl_outb(*buf++, port); } void r7780rp_outsw(unsigned long port, const void *src, unsigned long count) @@ -262,40 +197,37 @@ void r7780rp_outsw(unsigned long port, c if (CHECK_AX88796L_PORT(port)) p = (volatile u16 *)port88796l(port, 1); - else if (PXSEG(port)) - p = (volatile u16 *)port; - else if (is_pci_ioaddr(port) || shifted_port(port)) + else if (is_pci_ioaddr(port)) p = (volatile u16 *)pci_ioaddr(port); else - p = (volatile u16 *)port2adr(port); + p = (volatile u16 *)port; while (count--) *p = *buf++; + + flush_dcache_all(); } void r7780rp_outsl(unsigned long port, const void *src, unsigned long count) { const u32 *buf = src; + u32 *p; - if (CHECK_AX88796L_PORT(port)) - maybebadio(port); - else if (is_pci_ioaddr(port) || shifted_port(port)) { - volatile u32 *p = (volatile u32 *)pci_ioaddr(port); + if (is_pci_ioaddr(port)) + p = (u32 *)pci_ioaddr(port); + else + p = (u32 *)port; - while (count--) - *p = *buf++; - } else - maybebadio(port); + while (count--) + ctrl_outl(*buf++, (unsigned long)p); } void __iomem *r7780rp_ioport_map(unsigned long port, unsigned int size) { if (CHECK_AX88796L_PORT(port)) return (void __iomem *)port88796l(port, size > 1); - else if (PXSEG(port)) - return (void __iomem *)port; - else if (is_pci_ioaddr(port) || shifted_port(port)) + else if (is_pci_ioaddr(port)) return (void __iomem *)pci_ioaddr(port); - return (void __iomem *)port2adr(port); + return (void __iomem *)port; } diff --git a/arch/sh/boards/renesas/r7780rp/led.c b/arch/sh/boards/renesas/r7780rp/led.c deleted file mode 100644 index 6a00a25..0000000 --- a/arch/sh/boards/renesas/r7780rp/led.c +++ /dev/null @@ -1,43 +0,0 @@ -/* - * Copyright (C) Atom Create Engineering Co., Ltd. - * - * May be copied or modified under the terms of GNU General Public - * License. See linux/COPYING for more information. - * - * This file contains Renesas Solutions HIGHLANDER R7780RP-1 specific LED code. - */ -#include -#include -#include - -/* Cycle the LED's in the clasic Knightriger/Sun pattern */ -void heartbeat_r7780rp(void) -{ - static unsigned int cnt = 0, period = 0; - volatile unsigned short *p = (volatile unsigned short *)PA_OBLED; - static unsigned bit = 0, up = 1; - unsigned bit_pos[] = {2, 1, 0, 3, 6, 5, 4, 7}; - - cnt += 1; - if (cnt < period) - return; - - cnt = 0; - - /* Go through the points (roughly!): - * f(0)=10, f(1)=16, f(2)=20, f(5)=35, f(int)->110 - */ - period = 110 - ((300 << FSHIFT)/((avenrun[0]/5) + (3< #include +#include #include #include #include #include -extern void heartbeat_r7780rp(void); extern void init_r7780rp_IRQ(void); static struct resource m66596_usb_host_resources[] = { @@ -46,14 +46,14 @@ static struct platform_device m66596_usb static struct resource cf_ide_resources[] = { [0] = { - .start = 0x1f0, - .end = 0x1f0 + 8, - .flags = IORESOURCE_IO, + .start = PA_AREA5_IO + 0x1000, + .end = PA_AREA5_IO + 0x1000 + 0x08 - 1, + .flags = IORESOURCE_MEM, }, [1] = { - .start = 0x1f0 + 0x206, - .end = 0x1f0 + 8 + 0x206 + 8, - .flags = IORESOURCE_IO, + .start = PA_AREA5_IO + 0x80c, + .end = PA_AREA5_IO + 0x80c + 0x16 - 1, + .flags = IORESOURCE_MEM, }, [2] = { #ifdef CONFIG_SH_R7780MP @@ -65,16 +65,44 @@ #endif }, }; +static struct pata_platform_info pata_info = { + .ioport_shift = 1, +}; + static struct platform_device cf_ide_device = { .name = "pata_platform", .id = -1, .num_resources = ARRAY_SIZE(cf_ide_resources), .resource = cf_ide_resources, + .dev = { + .platform_data = &pata_info, + }, +}; + +static unsigned char heartbeat_bit_pos[] = { 2, 1, 0, 3, 6, 5, 4, 7 }; + +static struct resource heartbeat_resources[] = { + [0] = { + .start = PA_OBLED, + .end = PA_OBLED + ARRAY_SIZE(heartbeat_bit_pos) - 1, + .flags = IORESOURCE_MEM, + }, +}; + +static struct platform_device heartbeat_device = { + .name = "heartbeat", + .id = -1, + .dev = { + .platform_data = heartbeat_bit_pos, + }, + .num_resources = ARRAY_SIZE(heartbeat_resources), + .resource = heartbeat_resources, }; static struct platform_device *r7780rp_devices[] __initdata = { &m66596_usb_host_device, &cf_ide_device, + &heartbeat_device, }; static int __init r7780rp_devices_setup(void) @@ -148,7 +176,7 @@ static void __init r7780rp_setup(char ** #ifndef CONFIG_SH_R7780MP ctrl_outw(0x0001, PA_SDPOW); /* SD Power ON */ #endif - ctrl_outw(ctrl_inw(PA_IVDRCTL) | 0x0100, PA_IVDRCTL); /* Si13112 */ + ctrl_outw(ctrl_inw(PA_IVDRCTL) | 0x01, PA_IVDRCTL); /* Si13112 */ pm_power_off = r7780rp_power_off; } @@ -185,8 +213,5 @@ struct sh_machine_vector mv_r7780rp __in .mv_ioport_map = r7780rp_ioport_map, .mv_init_irq = init_r7780rp_IRQ, -#ifdef CONFIG_HEARTBEAT - .mv_heartbeat = heartbeat_r7780rp, -#endif }; ALIAS_MV(r7780rp) diff --git a/arch/sh/boards/renesas/rts7751r2d/Makefile b/arch/sh/boards/renesas/rts7751r2d/Makefile index 686fc9e..0d4c75a 100644 --- a/arch/sh/boards/renesas/rts7751r2d/Makefile +++ b/arch/sh/boards/renesas/rts7751r2d/Makefile @@ -2,5 +2,4 @@ # # Makefile for the RTS7751R2D specific parts of the kernel # -obj-y := setup.o io.o irq.o -obj-$(CONFIG_HEARTBEAT) += led.o +obj-y := setup.o irq.o diff --git a/arch/sh/boards/renesas/rts7751r2d/io.c b/arch/sh/boards/renesas/rts7751r2d/io.c deleted file mode 100644 index f2507a8..0000000 --- a/arch/sh/boards/renesas/rts7751r2d/io.c +++ /dev/null @@ -1,302 +0,0 @@ -/* - * Copyright (C) 2001 Ian da Silva, Jeremy Siegel - * Based largely on io_se.c. - * - * I/O routine for Renesas Technology sales RTS7751R2D. - * - * Initial version only to support LAN access; some - * placeholder code from io_rts7751r2d.c left in with the - * expectation of later SuperIO and PCMCIA access. - */ -#include -#include -#include -#include -#include -#include - -/* - * The 7751R RTS7751R2D uses the built-in PCI controller (PCIC) - * of the 7751R processor, and has a SuperIO accessible via the PCI. - * The board also includes a PCMCIA controller on its memory bus, - * like the other Solution Engine boards. - */ - -static inline unsigned long port2adr(unsigned int port) -{ - if ((0x1f0 <= port && port < 0x1f8) || port == 0x3f6) - if (port == 0x3f6) - return (PA_AREA5_IO + 0x80c); - else - return (PA_AREA5_IO + 0x1000 + ((port-0x1f0) << 1)); - else - maybebadio((unsigned long)port); - - return port; -} - -static inline unsigned long port88796l(unsigned int port, int flag) -{ - unsigned long addr; - - if (flag) - addr = PA_AX88796L + ((port - AX88796L_IO_BASE) << 1); - else - addr = PA_AX88796L + ((port - AX88796L_IO_BASE) << 1) + 0x1000; - - return addr; -} - -/* The 7751R RTS7751R2D seems to have everything hooked */ -/* up pretty normally (nothing on high-bytes only...) so this */ -/* shouldn't be needed */ -static inline int shifted_port(unsigned long port) -{ - /* For IDE registers, value is not shifted */ - if ((0x1f0 <= port && port < 0x1f8) || port == 0x3f6) - return 0; - else - return 1; -} - -#if defined(CONFIG_NE2000) || defined(CONFIG_NE2000_MODULE) -#define CHECK_AX88796L_PORT(port) \ - ((port >= AX88796L_IO_BASE) && (port < (AX88796L_IO_BASE+0x20))) -#else -#define CHECK_AX88796L_PORT(port) (0) -#endif - -/* - * General outline: remap really low stuff [eventually] to SuperIO, - * stuff in PCI IO space (at or above window at pci.h:PCIBIOS_MIN_IO) - * is mapped through the PCI IO window. Stuff with high bits (PXSEG) - * should be way beyond the window, and is used w/o translation for - * compatibility. - */ -unsigned char rts7751r2d_inb(unsigned long port) -{ - if (CHECK_AX88796L_PORT(port)) - return (*(volatile unsigned short *)port88796l(port, 0)) & 0xff; - else if (PXSEG(port)) - return *(volatile unsigned char *)port; - else if (is_pci_ioaddr(port) || shifted_port(port)) - return *(volatile unsigned char *)pci_ioaddr(port); - else - return (*(volatile unsigned short *)port2adr(port) & 0xff); -} - -unsigned char rts7751r2d_inb_p(unsigned long port) -{ - unsigned char v; - - if (CHECK_AX88796L_PORT(port)) - v = (*(volatile unsigned short *)port88796l(port, 0)) & 0xff; - else if (PXSEG(port)) - v = *(volatile unsigned char *)port; - else if (is_pci_ioaddr(port) || shifted_port(port)) - v = *(volatile unsigned char *)pci_ioaddr(port); - else - v = (*(volatile unsigned short *)port2adr(port) & 0xff); - - ctrl_delay(); - - return v; -} - -unsigned short rts7751r2d_inw(unsigned long port) -{ - if (CHECK_AX88796L_PORT(port)) - maybebadio(port); - else if (PXSEG(port)) - return *(volatile unsigned short *)port; - else if (is_pci_ioaddr(port) || shifted_port(port)) - return *(volatile unsigned short *)pci_ioaddr(port); - else - maybebadio(port); - - return 0; -} - -unsigned int rts7751r2d_inl(unsigned long port) -{ - if (CHECK_AX88796L_PORT(port)) - maybebadio(port); - else if (PXSEG(port)) - return *(volatile unsigned long *)port; - else if (is_pci_ioaddr(port) || shifted_port(port)) - return *(volatile unsigned long *)pci_ioaddr(port); - else - maybebadio(port); - - return 0; -} - -void rts7751r2d_outb(unsigned char value, unsigned long port) -{ - if (CHECK_AX88796L_PORT(port)) - *((volatile unsigned short *)port88796l(port, 0)) = value; - else if (PXSEG(port)) - *(volatile unsigned char *)port = value; - else if (is_pci_ioaddr(port) || shifted_port(port)) - *(volatile unsigned char *)pci_ioaddr(port) = value; - else - *(volatile unsigned short *)port2adr(port) = value; -} - -void rts7751r2d_outb_p(unsigned char value, unsigned long port) -{ - if (CHECK_AX88796L_PORT(port)) - *((volatile unsigned short *)port88796l(port, 0)) = value; - else if (PXSEG(port)) - *(volatile unsigned char *)port = value; - else if (is_pci_ioaddr(port) || shifted_port(port)) - *(volatile unsigned char *)pci_ioaddr(port) = value; - else - *(volatile unsigned short *)port2adr(port) = value; - - ctrl_delay(); -} - -void rts7751r2d_outw(unsigned short value, unsigned long port) -{ - if (CHECK_AX88796L_PORT(port)) - maybebadio(port); - else if (PXSEG(port)) - *(volatile unsigned short *)port = value; - else if (is_pci_ioaddr(port) || shifted_port(port)) - *(volatile unsigned short *)pci_ioaddr(port) = value; - else - maybebadio(port); -} - -void rts7751r2d_outl(unsigned int value, unsigned long port) -{ - if (CHECK_AX88796L_PORT(port)) - maybebadio(port); - else if (PXSEG(port)) - *(volatile unsigned long *)port = value; - else if (is_pci_ioaddr(port) || shifted_port(port)) - *(volatile unsigned long *)pci_ioaddr(port) = value; - else - maybebadio(port); -} - -void rts7751r2d_insb(unsigned long port, void *addr, unsigned long count) -{ - unsigned long a = (unsigned long)addr; - volatile __u8 *bp; - volatile __u16 *p; - - if (CHECK_AX88796L_PORT(port)) { - p = (volatile unsigned short *)port88796l(port, 0); - while (count--) - ctrl_outb(*p & 0xff, a++); - } else if (PXSEG(port)) - while (count--) - ctrl_outb(ctrl_inb(port), a++); - else if (is_pci_ioaddr(port) || shifted_port(port)) { - bp = (__u8 *)pci_ioaddr(port); - while (count--) - ctrl_outb(*bp, a++); - } else { - p = (volatile unsigned short *)port2adr(port); - while (count--) - ctrl_outb(*p & 0xff, a++); - } -} - -void rts7751r2d_insw(unsigned long port, void *addr, unsigned long count) -{ - unsigned long a = (unsigned long)addr; - volatile __u16 *p; - - if (CHECK_AX88796L_PORT(port)) - p = (volatile unsigned short *)port88796l(port, 1); - else if (PXSEG(port)) - p = (volatile unsigned short *)port; - else if (is_pci_ioaddr(port) || shifted_port(port)) - p = (volatile unsigned short *)pci_ioaddr(port); - else - p = (volatile unsigned short *)port2adr(port); - while (count--) - ctrl_outw(*p, a++); -} - -void rts7751r2d_insl(unsigned long port, void *addr, unsigned long count) -{ - if (CHECK_AX88796L_PORT(port)) - maybebadio(port); - else if (is_pci_ioaddr(port) || shifted_port(port)) { - unsigned long a = (unsigned long)addr; - - while (count--) { - ctrl_outl(ctrl_inl(pci_ioaddr(port)), a); - a += 4; - } - } else - maybebadio(port); -} - -void rts7751r2d_outsb(unsigned long port, const void *addr, unsigned long count) -{ - unsigned long a = (unsigned long)addr; - volatile __u8 *bp; - volatile __u16 *p; - - if (CHECK_AX88796L_PORT(port)) { - p = (volatile unsigned short *)port88796l(port, 0); - while (count--) - *p = ctrl_inb(a++); - } else if (PXSEG(port)) - while (count--) - ctrl_outb(a++, port); - else if (is_pci_ioaddr(port) || shifted_port(port)) { - bp = (__u8 *)pci_ioaddr(port); - while (count--) - *bp = ctrl_inb(a++); - } else { - p = (volatile unsigned short *)port2adr(port); - while (count--) - *p = ctrl_inb(a++); - } -} - -void rts7751r2d_outsw(unsigned long port, const void *addr, unsigned long count) -{ - unsigned long a = (unsigned long)addr; - volatile __u16 *p; - - if (CHECK_AX88796L_PORT(port)) - p = (volatile unsigned short *)port88796l(port, 1); - else if (PXSEG(port)) - p = (volatile unsigned short *)port; - else if (is_pci_ioaddr(port) || shifted_port(port)) - p = (volatile unsigned short *)pci_ioaddr(port); - else - p = (volatile unsigned short *)port2adr(port); - - while (count--) { - ctrl_outw(*p, a); - a += 2; - } -} - -void rts7751r2d_outsl(unsigned long port, const void *addr, unsigned long count) -{ - if (CHECK_AX88796L_PORT(port)) - maybebadio(port); - else if (is_pci_ioaddr(port) || shifted_port(port)) { - unsigned long a = (unsigned long)addr; - - while (count--) { - ctrl_outl(ctrl_inl(a), pci_ioaddr(port)); - a += 4; - } - } else - maybebadio(port); -} - -unsigned long rts7751r2d_isa_port2addr(unsigned long offset) -{ - return port2adr(offset); -} diff --git a/arch/sh/boards/renesas/rts7751r2d/irq.c b/arch/sh/boards/renesas/rts7751r2d/irq.c index cb0eb20..0bae904 100644 --- a/arch/sh/boards/renesas/rts7751r2d/irq.c +++ b/arch/sh/boards/renesas/rts7751r2d/irq.c @@ -9,7 +9,9 @@ * Atom Create Engineering Co., Ltd. 2002. */ #include +#include #include +#include #include #include @@ -22,79 +24,31 @@ #endif extern int voyagergx_irq_demux(int irq); extern void setup_voyagergx_irq(void); -static void enable_rts7751r2d_irq(unsigned int irq); -static void disable_rts7751r2d_irq(unsigned int irq); - -/* shutdown is same as "disable" */ -#define shutdown_rts7751r2d_irq disable_rts7751r2d_irq - -static void ack_rts7751r2d_irq(unsigned int irq); -static void end_rts7751r2d_irq(unsigned int irq); - -static unsigned int startup_rts7751r2d_irq(unsigned int irq) +static void enable_rts7751r2d_irq(unsigned int irq) { - enable_rts7751r2d_irq(irq); - return 0; /* never anything pending */ + /* Set priority in IPR back to original value */ + ctrl_outw(ctrl_inw(IRLCNTR1) | (1 << mask_pos[irq]), IRLCNTR1); } static void disable_rts7751r2d_irq(unsigned int irq) { - unsigned short val; - unsigned short mask = 0xffff ^ (0x0001 << mask_pos[irq]); - /* Set the priority in IPR to 0 */ - val = ctrl_inw(IRLCNTR1); - val &= mask; - ctrl_outw(val, IRLCNTR1); -} - -static void enable_rts7751r2d_irq(unsigned int irq) -{ - unsigned short val; - unsigned short value = (0x0001 << mask_pos[irq]); - - /* Set priority in IPR back to original value */ - val = ctrl_inw(IRLCNTR1); - val |= value; - ctrl_outw(val, IRLCNTR1); + ctrl_outw(ctrl_inw(IRLCNTR1) & (0xffff ^ (1 << mask_pos[irq])), + IRLCNTR1); } int rts7751r2d_irq_demux(int irq) { - int demux_irq; - - demux_irq = voyagergx_irq_demux(irq); - return demux_irq; -} - -static void ack_rts7751r2d_irq(unsigned int irq) -{ - disable_rts7751r2d_irq(irq); + return voyagergx_irq_demux(irq); } -static void end_rts7751r2d_irq(unsigned int irq) -{ - if (!(irq_desc[irq].status & (IRQ_DISABLED|IRQ_INPROGRESS))) - enable_rts7751r2d_irq(irq); -} - -static struct hw_interrupt_type rts7751r2d_irq_type = { - .typename = "RTS7751R2D IRQ", - .startup = startup_rts7751r2d_irq, - .shutdown = shutdown_rts7751r2d_irq, - .enable = enable_rts7751r2d_irq, - .disable = disable_rts7751r2d_irq, - .ack = ack_rts7751r2d_irq, - .end = end_rts7751r2d_irq, +static struct irq_chip rts7751r2d_irq_chip __read_mostly = { + .name = "rts7751r2d", + .mask = disable_rts7751r2d_irq, + .unmask = enable_rts7751r2d_irq, + .mask_ack = disable_rts7751r2d_irq, }; -static void make_rts7751r2d_irq(unsigned int irq) -{ - disable_irq_nosync(irq); - irq_desc[irq].chip = &rts7751r2d_irq_type; - disable_rts7751r2d_irq(irq); -} - /* * Initialize IRQ setting */ @@ -119,8 +73,12 @@ void __init init_rts7751r2d_IRQ(void) * IRL14=Extention #3 */ - for (i=0; i<15; i++) - make_rts7751r2d_irq(i); + for (i=0; i<15; i++) { + disable_irq_nosync(i); + set_irq_chip_and_handler_name(i, &rts7751r2d_irq_chip, + handle_level_irq, "level"); + enable_rts7751r2d_irq(i); + } setup_voyagergx_irq(); } diff --git a/arch/sh/boards/renesas/rts7751r2d/led.c b/arch/sh/boards/renesas/rts7751r2d/led.c deleted file mode 100644 index 509f548..0000000 --- a/arch/sh/boards/renesas/rts7751r2d/led.c +++ /dev/null @@ -1,44 +0,0 @@ -/* - * linux/arch/sh/boards/renesas/rts7751r2d/led.c - * - * Copyright (C) Atom Create Engineering Co., Ltd. - * - * May be copied or modified under the terms of GNU General Public - * License. See linux/COPYING for more information. - * - * This file contains Renesas Technology Sales RTS7751R2D specific LED code. - */ -#include -#include -#include - -/* Cycle the LED's in the clasic Knightriger/Sun pattern */ -void heartbeat_rts7751r2d(void) -{ - static unsigned int cnt = 0, period = 0; - volatile unsigned short *p = (volatile unsigned short *)PA_OUTPORT; - static unsigned bit = 0, up = 1; - - cnt += 1; - if (cnt < period) - return; - - cnt = 0; - - /* Go through the points (roughly!): - * f(0)=10, f(1)=16, f(2)=20, f(5)=35, f(int)->110 - */ - period = 110 - ((300 << FSHIFT)/((avenrun[0]/5) + (3< #include +#include #include #include #include -#include -#include +#include #include - -extern void heartbeat_rts7751r2d(void); -extern void init_rts7751r2d_IRQ(void); -extern int rts7751r2d_irq_demux(int irq); - -extern void *voyagergx_consistent_alloc(struct device *, size_t, dma_addr_t *, gfp_t); -extern int voyagergx_consistent_free(struct device *, size_t, void *, dma_addr_t); - -static struct plat_serial8250_port uart_platform_data[] = { - { - .membase = (void *)VOYAGER_UART_BASE, - .mapbase = VOYAGER_UART_BASE, - .iotype = UPIO_MEM, - .irq = VOYAGER_UART0_IRQ, - .flags = UPF_BOOT_AUTOCONF, - .regshift = 2, - .uartclk = (9600 * 16), - }, { - .flags = 0, - }, -}; +#include static void __init voyagergx_serial_init(void) { @@ -45,32 +25,96 @@ static void __init voyagergx_serial_init /* * GPIO Control */ - val = inl(GPIO_MUX_HIGH); + val = readl((void __iomem *)GPIO_MUX_HIGH); val |= 0x00001fe0; - outl(val, GPIO_MUX_HIGH); + writel(val, (void __iomem *)GPIO_MUX_HIGH); /* * Power Mode Gate */ - val = inl(POWER_MODE0_GATE); + val = readl((void __iomem *)POWER_MODE0_GATE); val |= (POWER_MODE0_GATE_U0 | POWER_MODE0_GATE_U1); - outl(val, POWER_MODE0_GATE); + writel(val, (void __iomem *)POWER_MODE0_GATE); - val = inl(POWER_MODE1_GATE); + val = readl((void __iomem *)POWER_MODE1_GATE); val |= (POWER_MODE1_GATE_U0 | POWER_MODE1_GATE_U1); - outl(val, POWER_MODE1_GATE); + writel(val, (void __iomem *)POWER_MODE1_GATE); } +static struct resource cf_ide_resources[] = { + [0] = { + .start = PA_AREA5_IO + 0x1000, + .end = PA_AREA5_IO + 0x1000 + 0x08 - 1, + .flags = IORESOURCE_MEM, + }, + [1] = { + .start = PA_AREA5_IO + 0x80c, + .end = PA_AREA5_IO + 0x80c + 0x16 - 1, + .flags = IORESOURCE_MEM, + }, + [2] = { +#ifdef CONFIG_RTS7751R2D_REV11 + .start = 1, +#else + .start = 2, +#endif + .flags = IORESOURCE_IRQ, + }, +}; + +static struct pata_platform_info pata_info = { + .ioport_shift = 1, +}; + +static struct platform_device cf_ide_device = { + .name = "pata_platform", + .id = -1, + .num_resources = ARRAY_SIZE(cf_ide_resources), + .resource = cf_ide_resources, + .dev = { + .platform_data = &pata_info, + }, +}; + +static struct plat_serial8250_port uart_platform_data[] = { + { + .membase = (void __iomem *)VOYAGER_UART_BASE, + .mapbase = VOYAGER_UART_BASE, + .iotype = UPIO_MEM, + .irq = VOYAGER_UART0_IRQ, + .flags = UPF_BOOT_AUTOCONF | UPF_SKIP_TEST, + .regshift = 2, + .uartclk = (9600 * 16), + } +}; + static struct platform_device uart_device = { .name = "serial8250", - .id = -1, + .id = PLAT8250_DEV_PLATFORM, .dev = { .platform_data = uart_platform_data, }, }; +static struct resource heartbeat_resources[] = { + [0] = { + .start = PA_OUTPORT, + .end = PA_OUTPORT + 8 - 1, + .flags = IORESOURCE_MEM, + }, +}; + +static struct platform_device heartbeat_device = { + .name = "heartbeat", + .id = -1, + .num_resources = ARRAY_SIZE(heartbeat_resources), + .resource = heartbeat_resources, +}; + static struct platform_device *rts7751r2d_devices[] __initdata = { &uart_device, + &heartbeat_device, + &cf_ide_device, }; static int __init rts7751r2d_devices_setup(void) @@ -78,6 +122,7 @@ static int __init rts7751r2d_devices_set return platform_add_devices(rts7751r2d_devices, ARRAY_SIZE(rts7751r2d_devices)); } +__initcall(rts7751r2d_devices_setup); static void rts7751r2d_power_off(void) { @@ -89,14 +134,17 @@ static void rts7751r2d_power_off(void) */ static void __init rts7751r2d_setup(char **cmdline_p) { - device_initcall(rts7751r2d_devices_setup); + u16 ver = ctrl_inw(PA_VERREG); + + printk(KERN_INFO "Renesas Technology Sales RTS7751R2D support.\n"); + + printk(KERN_INFO "FPGA version:%d (revision:%d)\n", + (ver >> 4) & 0xf, ver & 0xf); ctrl_outw(0x0000, PA_OUTPORT); pm_power_off = rts7751r2d_power_off; voyagergx_serial_init(); - - printk(KERN_INFO "Renesas Technology Sales RTS7751R2D support.\n"); } /* @@ -107,31 +155,7 @@ struct sh_machine_vector mv_rts7751r2d _ .mv_setup = rts7751r2d_setup, .mv_nr_irqs = 72, - .mv_inb = rts7751r2d_inb, - .mv_inw = rts7751r2d_inw, - .mv_inl = rts7751r2d_inl, - .mv_outb = rts7751r2d_outb, - .mv_outw = rts7751r2d_outw, - .mv_outl = rts7751r2d_outl, - - .mv_inb_p = rts7751r2d_inb_p, - .mv_inw_p = rts7751r2d_inw, - .mv_inl_p = rts7751r2d_inl, - .mv_outb_p = rts7751r2d_outb_p, - .mv_outw_p = rts7751r2d_outw, - .mv_outl_p = rts7751r2d_outl, - - .mv_insb = rts7751r2d_insb, - .mv_insw = rts7751r2d_insw, - .mv_insl = rts7751r2d_insl, - .mv_outsb = rts7751r2d_outsb, - .mv_outsw = rts7751r2d_outsw, - .mv_outsl = rts7751r2d_outsl, - .mv_init_irq = init_rts7751r2d_IRQ, -#ifdef CONFIG_HEARTBEAT - .mv_heartbeat = heartbeat_rts7751r2d, -#endif .mv_irq_demux = rts7751r2d_irq_demux, #ifdef CONFIG_USB_SM501 diff --git a/arch/sh/boards/se/7206/Makefile b/arch/sh/boards/se/7206/Makefile index 63950f4..63e7ed6 100644 --- a/arch/sh/boards/se/7206/Makefile +++ b/arch/sh/boards/se/7206/Makefile @@ -3,5 +3,3 @@ # Makefile for the 7206 SolutionEngine s # obj-y := setup.o io.o irq.o -obj-$(CONFIG_HEARTBEAT) += led.o - diff --git a/arch/sh/boards/se/7206/led.c b/arch/sh/boards/se/7206/led.c deleted file mode 100644 index ef79460..0000000 --- a/arch/sh/boards/se/7206/led.c +++ /dev/null @@ -1,57 +0,0 @@ -/* - * linux/arch/sh/kernel/led_se.c - * - * Copyright (C) 2000 Stuart Menefy - * - * May be copied or modified under the terms of the GNU General Public - * License. See linux/COPYING for more information. - * - * This file contains Solution Engine specific LED code. - */ - -#include -#include - -#ifdef CONFIG_HEARTBEAT - -#include - -/* Cycle the LED's in the clasic Knightrider/Sun pattern */ -void heartbeat_se(void) -{ - static unsigned int cnt = 0, period = 0; - volatile unsigned short* p = (volatile unsigned short*)PA_LED; - static unsigned bit = 0, up = 1; - - cnt += 1; - if (cnt < period) { - return; - } - - cnt = 0; - - /* Go through the points (roughly!): - * f(0)=10, f(1)=16, f(2)=20, f(5)=35,f(inf)->110 - */ - period = 110 - ( (300< - * - * May be copied or modified under the terms of the GNU General Public - * License. See linux/COPYING for more information. - * - * This file contains Solution Engine specific LED code. - */ - -#include -#include - -/* Cycle the LED's in the clasic Knightrider/Sun pattern */ -void heartbeat_7300se(void) -{ - static unsigned int cnt = 0, period = 0; - volatile unsigned short *p = (volatile unsigned short *) PA_LED; - static unsigned bit = 0, up = 1; - - cnt += 1; - if (cnt < period) { - return; - } - - cnt = 0; - - /* Go through the points (roughly!): - * f(0)=10, f(1)=16, f(2)=20, f(5)=35,f(inf)->110 - */ - period = 110 - ((300 << FSHIFT) / ((avenrun[0] / 5) + (3 << FSHIFT))); - - if (up) { - if (bit == 7) { - bit--; - up = 0; - } else { - bit++; - } - } else { - if (bit == 0) { - bit++; - up = 1; - } else { - bit--; - } - } - *p = 1 << (bit + 8); - -} - diff --git a/arch/sh/boards/se/7300/setup.c b/arch/sh/boards/se/7300/setup.c index 6f082a7..f196095 100644 --- a/arch/sh/boards/se/7300/setup.c +++ b/arch/sh/boards/se/7300/setup.c @@ -6,14 +6,43 @@ * SH-Mobile SolutionEngine 7300 Support. * */ - #include +#include #include #include -void heartbeat_7300se(void); void init_7300se_IRQ(void); +static unsigned char heartbeat_bit_pos[] = { 8, 9, 10, 11, 12, 13, 14, 15 }; + +static struct resource heartbeat_resources[] = { + [0] = { + .start = PA_LED, + .end = PA_LED + ARRAY_SIZE(heartbeat_bit_pos) - 1, + .flags = IORESOURCE_MEM, + }, +}; + +static struct platform_device heartbeat_device = { + .name = "heartbeat", + .id = -1, + .dev = { + .platform_data = heartbeat_bit_pos, + }, + .num_resources = ARRAY_SIZE(heartbeat_resources), + .resource = heartbeat_resources, +}; + +static struct platform_device *se7300_devices[] __initdata = { + &heartbeat_device, +}; + +static int __init se7300_devices_setup(void) +{ + return platform_add_devices(se7300_devices, ARRAY_SIZE(se7300_devices)); +} +__initcall(se7300_devices_setup); + /* * The Machine Vector */ @@ -42,8 +71,5 @@ struct sh_machine_vector mv_7300se __ini .mv_outsl = sh7300se_outsl, .mv_init_irq = init_7300se_IRQ, -#ifdef CONFIG_HEARTBEAT - .mv_heartbeat = heartbeat_7300se, -#endif }; ALIAS_MV(7300se) diff --git a/arch/sh/boards/se/73180/Makefile b/arch/sh/boards/se/73180/Makefile index 8f63886..e7c0996 100644 --- a/arch/sh/boards/se/73180/Makefile +++ b/arch/sh/boards/se/73180/Makefile @@ -3,5 +3,3 @@ # Makefile for the 73180 SolutionEngine # obj-y := setup.o io.o irq.o - -obj-$(CONFIG_HEARTBEAT) += led.o diff --git a/arch/sh/boards/se/73180/led.c b/arch/sh/boards/se/73180/led.c deleted file mode 100644 index 4b72e9a..0000000 --- a/arch/sh/boards/se/73180/led.c +++ /dev/null @@ -1,53 +0,0 @@ -/* - * arch/sh/boards/se/73180/led.c - * - * Derived from arch/sh/boards/se/770x/led.c - * - * Copyright (C) 2000 Stuart Menefy - * - * May be copied or modified under the terms of the GNU General Public - * License. See linux/COPYING for more information. - * - * This file contains Solution Engine specific LED code. - */ - -#include -#include - -/* Cycle the LED's in the clasic Knightrider/Sun pattern */ -void heartbeat_73180se(void) -{ - static unsigned int cnt = 0, period = 0; - volatile unsigned short *p = (volatile unsigned short *) PA_LED; - static unsigned bit = 0, up = 1; - - cnt += 1; - if (cnt < period) { - return; - } - - cnt = 0; - - /* Go through the points (roughly!): - * f(0)=10, f(1)=16, f(2)=20, f(5)=35,f(inf)->110 - */ - period = 110 - ((300 << FSHIFT) / ((avenrun[0] / 5) + (3 << FSHIFT))); - - if (up) { - if (bit == 7) { - bit--; - up = 0; - } else { - bit++; - } - } else { - if (bit == 0) { - bit++; - up = 1; - } else { - bit--; - } - } - *p = 1 << (bit + LED_SHIFT); - -} diff --git a/arch/sh/boards/se/73180/setup.c b/arch/sh/boards/se/73180/setup.c index b38ef50..911ce1c 100644 --- a/arch/sh/boards/se/73180/setup.c +++ b/arch/sh/boards/se/73180/setup.c @@ -10,13 +10,39 @@ */ #include +#include #include #include #include -void heartbeat_73180se(void); void init_73180se_IRQ(void); +static struct resource heartbeat_resources[] = { + [0] = { + .start = PA_LED, + .end = PA_LED + 8 - 1, + .flags = IORESOURCE_MEM, + }, +}; + +static struct platform_device heartbeat_device = { + .name = "heartbeat", + .id = -1, + .num_resources = ARRAY_SIZE(heartbeat_resources), + .resource = heartbeat_resources, +}; + +static struct platform_device *se73180_devices[] __initdata = { + &heartbeat_device, +}; + +static int __init se73180_devices_setup(void) +{ + return platform_add_devices(sh7343se_platform_devices, + ARRAY_SIZE(sh7343se_platform_devices)); +} +__initcall(se73180_devices_setup); + /* * The Machine Vector */ @@ -46,8 +72,5 @@ struct sh_machine_vector mv_73180se __in .mv_init_irq = init_73180se_IRQ, .mv_irq_demux = shmse_irq_demux, -#ifdef CONFIG_HEARTBEAT - .mv_heartbeat = heartbeat_73180se, -#endif }; ALIAS_MV(73180se) diff --git a/arch/sh/boards/se/7343/Makefile b/arch/sh/boards/se/7343/Makefile index 4291069..3024796 100644 --- a/arch/sh/boards/se/7343/Makefile +++ b/arch/sh/boards/se/7343/Makefile @@ -3,5 +3,3 @@ # Makefile for the 7343 SolutionEngine s # obj-y := setup.o io.o irq.o - -obj-$(CONFIG_HEARTBEAT) += led.o diff --git a/arch/sh/boards/se/7343/led.c b/arch/sh/boards/se/7343/led.c deleted file mode 100644 index 6b39e19..0000000 --- a/arch/sh/boards/se/7343/led.c +++ /dev/null @@ -1,44 +0,0 @@ -/* - * arch/sh/boards/se/7343/led.c - * - */ -#include -#include - -/* Cycle the LED's in the clasic Knightrider/Sun pattern */ -void heartbeat_7343se(void) -{ - static unsigned int cnt = 0, period = 0; - volatile unsigned short *p = (volatile unsigned short *) PA_LED; - static unsigned bit = 0, up = 1; - - cnt += 1; - if (cnt < period) { - return; - } - - cnt = 0; - - /* Go through the points (roughly!): - * f(0)=10, f(1)=16, f(2)=20, f(5)=35,f(inf)->110 - */ - period = 110 - ((300 << FSHIFT) / ((avenrun[0] / 5) + (3 << FSHIFT))); - - if (up) { - if (bit == 7) { - bit--; - up = 0; - } else { - bit++; - } - } else { - if (bit == 0) { - bit++; - up = 1; - } else { - bit--; - } - } - *p = 1 << (bit + LED_SHIFT); - -} diff --git a/arch/sh/boards/se/7343/setup.c b/arch/sh/boards/se/7343/setup.c index c7d17fe..3fdb16f 100644 --- a/arch/sh/boards/se/7343/setup.c +++ b/arch/sh/boards/se/7343/setup.c @@ -4,7 +4,6 @@ #include #include #include -void heartbeat_7343se(void); void init_7343se_IRQ(void); static struct resource smc91x_resources[] = { @@ -31,14 +30,30 @@ static struct platform_device smc91x_dev .resource = smc91x_resources, }; -static struct platform_device *smc91x_platform_devices[] __initdata = { +static struct resource heartbeat_resources[] = { + [0] = { + .start = PA_LED, + .end = PA_LED + 8 - 1, + .flags = IORESOURCE_MEM, + }, +}; + +static struct platform_device heartbeat_device = { + .name = "heartbeat", + .id = -1, + .num_resources = ARRAY_SIZE(heartbeat_resources), + .resource = heartbeat_resources, +}; + +static struct platform_device *sh7343se_platform_devices[] __initdata = { &smc91x_device, + &heartbeat_device, }; static int __init sh7343se_devices_setup(void) { - return platform_add_devices(smc91x_platform_devices, - ARRAY_SIZE(smc91x_platform_devices)); + return platform_add_devices(sh7343se_platform_devices, + ARRAY_SIZE(sh7343se_platform_devices)); } static void __init sh7343se_setup(char **cmdline_p) @@ -76,8 +91,5 @@ struct sh_machine_vector mv_7343se __ini .mv_init_irq = init_7343se_IRQ, .mv_irq_demux = shmse_irq_demux, -#ifdef CONFIG_HEARTBEAT - .mv_heartbeat = heartbeat_7343se, -#endif }; ALIAS_MV(7343se) diff --git a/arch/sh/boards/se/770x/Makefile b/arch/sh/boards/se/770x/Makefile index 9a5035f..8e624b0 100644 --- a/arch/sh/boards/se/770x/Makefile +++ b/arch/sh/boards/se/770x/Makefile @@ -3,4 +3,3 @@ # Makefile for the 770x SolutionEngine s # obj-y := setup.o io.o irq.o -obj-$(CONFIG_HEARTBEAT) += led.o diff --git a/arch/sh/boards/se/770x/irq.c b/arch/sh/boards/se/770x/irq.c index fcd7cd7..307ca5d 100644 --- a/arch/sh/boards/se/770x/irq.c +++ b/arch/sh/boards/se/770x/irq.c @@ -2,56 +2,96 @@ * linux/arch/sh/boards/se/770x/irq.c * * Copyright (C) 2000 Kazumoto Kojima + * Copyright (C) 2006 Nobuhiro Iwamatsu * * Hitachi SolutionEngine Support. * */ #include +#include #include #include #include #include +/* + * If the problem of make_ipr_irq is solved, + * this code will become unnecessary. :-) + */ +static void se770x_disable_ipr_irq(unsigned int irq) +{ + struct ipr_data *p = get_irq_chip_data(irq); + + ctrl_outw(ctrl_inw(p->addr) & (0xffff ^ (0xf << p->shift)), p->addr); +} + +static void se770x_enable_ipr_irq(unsigned int irq) +{ + struct ipr_data *p = get_irq_chip_data(irq); + + ctrl_outw(ctrl_inw(p->addr) | (p->priority << p->shift), p->addr); +} + +static struct irq_chip se770x_irq_chip = { + .name = "MS770xSE-FPGA", + .mask = se770x_disable_ipr_irq, + .unmask = se770x_enable_ipr_irq, + .mask_ack = se770x_disable_ipr_irq, +}; + +void make_se770x_irq(struct ipr_data *table, unsigned int nr_irqs) +{ + int i; + + for (i = 0; i < nr_irqs; i++) { + unsigned int irq = table[i].irq; + disable_irq_nosync(irq); + set_irq_chip_and_handler_name(irq, &se770x_irq_chip, + handle_level_irq, "level"); + set_irq_chip_data(irq, &table[i]); + se770x_enable_ipr_irq(irq); + } +} + static struct ipr_data se770x_ipr_map[] = { #if defined(CONFIG_CPU_SUBTYPE_SH7705) /* This is default value */ - { 0xf-0x2, BCR_ILCRA, 2, 0x2 }, - { 0xf-0xa, BCR_ILCRA, 1, 0xa }, - { 0xf-0x5, BCR_ILCRB, 0, 0x5 }, - { 0xf-0x8, BCR_ILCRC, 1, 0x8 }, - { 0xf-0xc, BCR_ILCRC, 0, 0xc }, - { 0xf-0xe, BCR_ILCRD, 3, 0xe }, - { 0xf-0x3, BCR_ILCRD, 1, 0x3 }, /* LAN */ - { 0xf-0xd, BCR_ILCRE, 2, 0xd }, - { 0xf-0x9, BCR_ILCRE, 1, 0x9 }, - { 0xf-0x1, BCR_ILCRE, 0, 0x1 }, - { 0xf-0xf, BCR_ILCRF, 3, 0xf }, - { 0xf-0xb, BCR_ILCRF, 1, 0xb }, - { 0xf-0x7, BCR_ILCRG, 3, 0x7 }, - { 0xf-0x6, BCR_ILCRG, 2, 0x6 }, - { 0xf-0x4, BCR_ILCRG, 1, 0x4 }, + { 0xf-0x2, 0, 8, 0x2 , BCR_ILCRA}, + { 0xf-0xa, 0, 4, 0xa , BCR_ILCRA}, + { 0xf-0x5, 0, 0, 0x5 , BCR_ILCRB}, + { 0xf-0x8, 0, 4, 0x8 , BCR_ILCRC}, + { 0xf-0xc, 0, 0, 0xc , BCR_ILCRC}, + { 0xf-0xe, 0, 12, 0xe , BCR_ILCRD}, + { 0xf-0x3, 0, 4, 0x3 , BCR_ILCRD}, /* LAN */ + { 0xf-0xd, 0, 8, 0xd , BCR_ILCRE}, + { 0xf-0x9, 0, 4, 0x9 , BCR_ILCRE}, + { 0xf-0x1, 0, 0, 0x1 , BCR_ILCRE}, + { 0xf-0xf, 0, 12, 0xf , BCR_ILCRF}, + { 0xf-0xb, 0, 4, 0xb , BCR_ILCRF}, + { 0xf-0x7, 0, 12, 0x7 , BCR_ILCRG}, + { 0xf-0x6, 0, 8, 0x6 , BCR_ILCRG}, + { 0xf-0x4, 0, 4, 0x4 , BCR_ILCRG}, #else - { 14, BCR_ILCRA, 2, 0x0f-14 }, - { 12, BCR_ILCRA, 1, 0x0f-12 }, - { 8, BCR_ILCRB, 1, 0x0f- 8 }, - { 6, BCR_ILCRC, 3, 0x0f- 6 }, - { 5, BCR_ILCRC, 2, 0x0f- 5 }, - { 4, BCR_ILCRC, 1, 0x0f- 4 }, - { 3, BCR_ILCRC, 0, 0x0f- 3 }, - { 1, BCR_ILCRD, 3, 0x0f- 1 }, - - { 10, BCR_ILCRD, 1, 0x0f-10 }, /* LAN */ - - { 0, BCR_ILCRE, 3, 0x0f- 0 }, /* PCIRQ3 */ - { 11, BCR_ILCRE, 2, 0x0f-11 }, /* PCIRQ2 */ - { 9, BCR_ILCRE, 1, 0x0f- 9 }, /* PCIRQ1 */ - { 7, BCR_ILCRE, 0, 0x0f- 7 }, /* PCIRQ0 */ - + { 14, 0, 8, 0x0f-14 ,BCR_ILCRA}, + { 12, 0, 4, 0x0f-12 ,BCR_ILCRA}, + { 8, 0, 4, 0x0f- 8 ,BCR_ILCRB}, + { 6, 0, 12, 0x0f- 6 ,BCR_ILCRC}, + { 5, 0, 8, 0x0f- 5 ,BCR_ILCRC}, + { 4, 0, 4, 0x0f- 4 ,BCR_ILCRC}, + { 3, 0, 0, 0x0f- 3 ,BCR_ILCRC}, + { 1, 0, 12, 0x0f- 1 ,BCR_ILCRD}, + /* ST NIC */ + { 10, 0, 4, 0x0f-10 ,BCR_ILCRD}, /* LAN */ + /* MRSHPC IRQs setting */ + { 0, 0, 12, 0x0f- 0 ,BCR_ILCRE}, /* PCIRQ3 */ + { 11, 0, 8, 0x0f-11 ,BCR_ILCRE}, /* PCIRQ2 */ + { 9, 0, 4, 0x0f- 9 ,BCR_ILCRE}, /* PCIRQ1 */ + { 7, 0, 0, 0x0f- 7 ,BCR_ILCRE}, /* PCIRQ0 */ /* #2, #13 are allocated for SLOT IRQ #1 and #2 (for now) */ /* NOTE: #2 and #13 are not used on PC */ - { 13, BCR_ILCRG, 1, 0x0f-13 }, /* SLOTIRQ2 */ - { 2, BCR_ILCRG, 0, 0x0f- 2 }, /* SLOTIRQ1 */ + { 13, 0, 4, 0x0f-13 ,BCR_ILCRG}, /* SLOTIRQ2 */ + { 2, 0, 0, 0x0f- 2 ,BCR_ILCRG}, /* SLOTIRQ1 */ #endif }; @@ -81,5 +121,5 @@ #if defined(CONFIG_CPU_SUBTYPE_SH7705) ctrl_outw(0, BCR_ILCRF); ctrl_outw(0, BCR_ILCRG); #endif - make_ipr_irq(se770x_ipr_map, ARRAY_SIZE(se770x_ipr_map)); + make_se770x_irq(se770x_ipr_map, ARRAY_SIZE(se770x_ipr_map)); } diff --git a/arch/sh/boards/se/770x/led.c b/arch/sh/boards/se/770x/led.c deleted file mode 100644 index d93dd83..0000000 --- a/arch/sh/boards/se/770x/led.c +++ /dev/null @@ -1,52 +0,0 @@ -/* - * linux/arch/sh/boards/se/770x/led.c - * - * Copyright (C) 2000 Stuart Menefy - * - * May be copied or modified under the terms of the GNU General Public - * License. See linux/COPYING for more information. - * - * This file contains Solution Engine specific LED code. - */ - -#include -#include - -/* Cycle the LED's in the clasic Knightrider/Sun pattern */ -void heartbeat_se(void) -{ - static unsigned int cnt = 0, period = 0; - volatile unsigned short* p = (volatile unsigned short*)PA_LED; - static unsigned bit = 0, up = 1; - - cnt += 1; - if (cnt < period) { - return; - } - - cnt = 0; - - /* Go through the points (roughly!): - * f(0)=10, f(1)=16, f(2)=20, f(5)=35,f(inf)->110 - */ - period = 110 - ( (300< +#include #include #include #include #include -void heartbeat_se(void); void init_se_IRQ(void); /* @@ -36,11 +35,6 @@ static void __init smsc_setup(char **cmd smsc_config(ACTIVATE_INDEX, 0x01); smsc_config(IRQ_SELECT_INDEX, 6); /* IRQ6 */ - /* IDE1 */ - smsc_config(CURRENT_LDN_INDEX, LDN_IDE1); - smsc_config(ACTIVATE_INDEX, 0x01); - smsc_config(IRQ_SELECT_INDEX, 14); /* IRQ14 */ - /* AUXIO (GPIO): to use IDE1 */ smsc_config(CURRENT_LDN_INDEX, LDN_AUXIO); smsc_config(GPIO46_INDEX, 0x00); /* nIOROP */ @@ -69,6 +63,36 @@ static void __init smsc_setup(char **cmd outb_p(CONFIG_EXIT, CONFIG_PORT); } +static unsigned char heartbeat_bit_pos[] = { 8, 9, 10, 11, 12, 13, 14, 15 }; + +static struct resource heartbeat_resources[] = { + [0] = { + .start = PA_LED, + .end = PA_LED + ARRAY_SIZE(heartbeat_bit_pos) - 1, + .flags = IORESOURCE_MEM, + }, +}; + +static struct platform_device heartbeat_device = { + .name = "heartbeat", + .id = -1, + .dev = { + .platform_data = heartbeat_bit_pos, + }, + .num_resources = ARRAY_SIZE(heartbeat_resources), + .resource = heartbeat_resources, +}; + +static struct platform_device *se_devices[] __initdata = { + &heartbeat_device, +}; + +static int __init se_devices_setup(void) +{ + return platform_add_devices(se_devices, ARRAY_SIZE(se_devices)); +} +__initcall(se_devices_setup); + /* * The Machine Vector */ @@ -107,8 +131,5 @@ #endif .mv_outsl = se_outsl, .mv_init_irq = init_se_IRQ, -#ifdef CONFIG_HEARTBEAT - .mv_heartbeat = heartbeat_se, -#endif }; ALIAS_MV(se) diff --git a/arch/sh/boards/se/7751/Makefile b/arch/sh/boards/se/7751/Makefile index 188900c..dbc29f3 100644 --- a/arch/sh/boards/se/7751/Makefile +++ b/arch/sh/boards/se/7751/Makefile @@ -5,4 +5,3 @@ # obj-y := setup.o io.o irq.o obj-$(CONFIG_PCI) += pci.o -obj-$(CONFIG_HEARTBEAT) += led.o diff --git a/arch/sh/boards/se/7751/led.c b/arch/sh/boards/se/7751/led.c deleted file mode 100644 index de4194d..0000000 --- a/arch/sh/boards/se/7751/led.c +++ /dev/null @@ -1,51 +0,0 @@ -/* - * linux/arch/sh/boards/se/7751/led.c - * - * Copyright (C) 2000 Stuart Menefy - * - * May be copied or modified under the terms of the GNU General Public - * License. See linux/COPYING for more information. - * - * This file contains Solution Engine specific LED code. - */ -#include -#include - -/* Cycle the LED's in the clasic Knightrider/Sun pattern */ -void heartbeat_7751se(void) -{ - static unsigned int cnt = 0, period = 0; - volatile unsigned short* p = (volatile unsigned short*)PA_LED; - static unsigned bit = 0, up = 1; - - cnt += 1; - if (cnt < period) { - return; - } - - cnt = 0; - - /* Go through the points (roughly!): - * f(0)=10, f(1)=16, f(2)=20, f(5)=35,f(inf)->110 - */ - period = 110 - ( (300< +#include #include #include #include -void heartbeat_7751se(void); void init_7751se_IRQ(void); #ifdef CONFIG_SH_KGDB @@ -161,11 +161,40 @@ static int kgdb_uart_setup(void) } #endif /* CONFIG_SH_KGDB */ +static unsigned char heartbeat_bit_pos[] = { 8, 9, 10, 11, 12, 13, 14, 15 }; + +static struct resource heartbeat_resources[] = { + [0] = { + .start = PA_LED, + .end = PA_LED + ARRAY_SIZE(heartbeat_bit_pos) - 1, + .flags = IORESOURCE_MEM, + }, +}; + +static struct platform_device heartbeat_device = { + .name = "heartbeat", + .id = -1, + .dev = { + .platform_data = heartbeat_bit_pos, + }, + .num_resources = ARRAY_SIZE(heartbeat_resources), + .resource = heartbeat_resources, +}; + +static struct platform_device *se7751_devices[] __initdata = { + &smc91x_device, + &heartbeat_device, +}; + +static int __init se7751_devices_setup(void) +{ + return platform_add_devices(se7751_devices, ARRAY_SIZE(se7751_devices)); +} +__initcall(se7751_devices_setup); /* * The Machine Vector */ - struct sh_machine_vector mv_7751se __initmv = { .mv_name = "7751 SolutionEngine", .mv_setup = sh7751se_setup, @@ -189,8 +218,5 @@ struct sh_machine_vector mv_7751se __ini .mv_outsl = sh7751se_outsl, .mv_init_irq = init_7751se_IRQ, -#ifdef CONFIG_HEARTBEAT - .mv_heartbeat = heartbeat_7751se, -#endif }; ALIAS_MV(7751se) diff --git a/arch/sh/boards/sh03/Makefile b/arch/sh/boards/sh03/Makefile index 321be50..400306a 100644 --- a/arch/sh/boards/sh03/Makefile +++ b/arch/sh/boards/sh03/Makefile @@ -3,4 +3,3 @@ # Makefile for the Interface (CTP/PCI-SH # obj-y := setup.o rtc.o -obj-$(CONFIG_HEARTBEAT) += led.o diff --git a/arch/sh/boards/sh03/led.c b/arch/sh/boards/sh03/led.c deleted file mode 100644 index d38562a..0000000 --- a/arch/sh/boards/sh03/led.c +++ /dev/null @@ -1,48 +0,0 @@ -/* - * linux/arch/sh/boards/sh03/led.c - * - * Copyright (C) 2004 Saito.K Interface Corporation. - * - * This file contains Interface CTP/PCI-SH03 specific LED code. - */ - -#include - -/* Cycle the LED's in the clasic Knightrider/Sun pattern */ -void heartbeat_sh03(void) -{ - static unsigned int cnt = 0, period = 0; - volatile unsigned char* p = (volatile unsigned char*)0xa0800000; - static unsigned bit = 0, up = 1; - - cnt += 1; - if (cnt < period) { - return; - } - - cnt = 0; - - /* Go through the points (roughly!): - * f(0)=10, f(1)=16, f(2)=20, f(5)=35,f(inf)->110 - */ - period = 110 - ( (300< #include #include +#include #include #include #include @@ -48,15 +49,36 @@ static void __init sh03_setup(char **cmd board_time_init = sh03_time_init; } +static struct resource heartbeat_resources[] = { + [0] = { + .start = 0xa0800000, + .end = 0xa0800000 + 8 - 1, + .flags = IORESOURCE_MEM, + }, +}; + +static struct platform_device heartbeat_device = { + .name = "heartbeat", + .id = -1, + .num_resources = ARRAY_SIZE(heartbeat_resources), + .resource = heartbeat_resources, +}; + +static struct platform_device *sh03_devices[] __initdata = { + &heartbeat_device, +}; + +static int __init sh03_devices_setup(void) +{ + return platform_add_devices(sh03_devices, ARRAY_SIZE(sh03_devices)); +} +__initcall(sh03_devices_setup); + struct sh_machine_vector mv_sh03 __initmv = { .mv_name = "Interface (CTP/PCI-SH03)", .mv_setup = sh03_setup, .mv_nr_irqs = 48, .mv_ioport_map = sh03_ioport_map, .mv_init_irq = init_sh03_IRQ, - -#ifdef CONFIG_HEARTBEAT - .mv_heartbeat = heartbeat_sh03, -#endif }; ALIAS_MV(sh03) diff --git a/arch/sh/boards/shmin/setup.c b/arch/sh/boards/shmin/setup.c index a31a1d1..4a9df4a 100644 --- a/arch/sh/boards/shmin/setup.c +++ b/arch/sh/boards/shmin/setup.c @@ -12,12 +12,22 @@ #include #include #include -#define PFC_PHCR 0xa400010e +#define PFC_PHCR 0xa400010eUL +#define INTC_ICR1 0xa4000010UL +#define INTC_IPRC 0xa4000016UL + +static struct ipr_data shmin_ipr_map[] = { + { .irq=32, .addr=INTC_IPRC, .shift= 0, .priority=0 }, + { .irq=33, .addr=INTC_IPRC, .shift= 4, .priority=0 }, + { .irq=34, .addr=INTC_IPRC, .shift= 8, .priority=8 }, + { .irq=35, .addr=INTC_IPRC, .shift=12, .priority=0 }, +}; static void __init init_shmin_irq(void) { ctrl_outw(0x2a00, PFC_PHCR); // IRQ0-3=IRQ ctrl_outw(0x0aaa, INTC_ICR1); // IRQ0-3=IRQ-mode,Low-active. + make_ipr_irq(shmin_ipr_map, ARRAY_SIZE(shmin_ipr_map)); } static void __iomem *shmin_ioport_map(unsigned long port, unsigned int size) diff --git a/arch/sh/cchips/voyagergx/irq.c b/arch/sh/cchips/voyagergx/irq.c index f7ea700..70f1290 100644 --- a/arch/sh/cchips/voyagergx/irq.c +++ b/arch/sh/cchips/voyagergx/irq.c @@ -28,21 +28,21 @@ static void disable_voyagergx_irq(unsign unsigned long val; unsigned long mask = 1 << (irq - VOYAGER_IRQ_BASE); - pr_debug("disable_voyagergx_irq(%d): mask=%lx\n", irq, mask); - val = inl(VOYAGER_INT_MASK); - val &= ~mask; - outl(val, VOYAGER_INT_MASK); + pr_debug("disable_voyagergx_irq(%d): mask=%x\n", irq, mask); + val = readl((void __iomem *)VOYAGER_INT_MASK); + val &= ~mask; + writel(val, (void __iomem *)VOYAGER_INT_MASK); } static void enable_voyagergx_irq(unsigned int irq) { - unsigned long val; - unsigned long mask = 1 << (irq - VOYAGER_IRQ_BASE); + unsigned long val; + unsigned long mask = 1 << (irq - VOYAGER_IRQ_BASE); - pr_debug("disable_voyagergx_irq(%d): mask=%lx\n", irq, mask); - val = inl(VOYAGER_INT_MASK); - val |= mask; - outl(val, VOYAGER_INT_MASK); + pr_debug("disable_voyagergx_irq(%d): mask=%x\n", irq, mask); + val = readl((void __iomem *)VOYAGER_INT_MASK); + val |= mask; + writel(val, (void __iomem *)VOYAGER_INT_MASK); } static void mask_and_ack_voyagergx(unsigned int irq) @@ -68,20 +68,20 @@ static void shutdown_voyagergx_irq(unsig } static struct hw_interrupt_type voyagergx_irq_type = { - .typename = "VOYAGERGX-IRQ", - .startup = startup_voyagergx_irq, - .shutdown = shutdown_voyagergx_irq, - .enable = enable_voyagergx_irq, - .disable = disable_voyagergx_irq, - .ack = mask_and_ack_voyagergx, - .end = end_voyagergx_irq, + .typename = "VOYAGERGX-IRQ", + .startup = startup_voyagergx_irq, + .shutdown = shutdown_voyagergx_irq, + .enable = enable_voyagergx_irq, + .disable = disable_voyagergx_irq, + .ack = mask_and_ack_voyagergx, + .end = end_voyagergx_irq, }; static irqreturn_t voyagergx_interrupt(int irq, void *dev_id) { printk(KERN_INFO "VoyagerGX: spurious interrupt, status: 0x%x\n", - inl(INT_STATUS)); + (unsigned int)readl((void __iomem *)INT_STATUS)); return IRQ_HANDLED; } @@ -93,13 +93,13 @@ static struct { void voyagergx_register_irq_demux(int irq, int (*demux)(int irq, void *dev), void *dev) { - voyagergx_demux[irq - VOYAGER_IRQ_BASE].func = demux; - voyagergx_demux[irq - VOYAGER_IRQ_BASE].dev = dev; + voyagergx_demux[irq - VOYAGER_IRQ_BASE].func = demux; + voyagergx_demux[irq - VOYAGER_IRQ_BASE].dev = dev; } void voyagergx_unregister_irq_demux(int irq) { - voyagergx_demux[irq - VOYAGER_IRQ_BASE].func = 0; + voyagergx_demux[irq - VOYAGER_IRQ_BASE].func = 0; } int voyagergx_irq_demux(int irq) @@ -107,31 +107,25 @@ int voyagergx_irq_demux(int irq) if (irq == IRQ_VOYAGER ) { unsigned long i = 0, bit __attribute__ ((unused)); - unsigned long val = inl(INT_STATUS); -#if 1 - if ( val & ( 1 << 1 )){ + unsigned long val = readl((void __iomem *)INT_STATUS); + + if (val & (1 << 1)) i = 1; - } else if ( val & ( 1 << 2 )){ + else if (val & (1 << 2)) i = 2; - } else if ( val & ( 1 << 6 )){ + else if (val & (1 << 6)) i = 6; - } else if( val & ( 1 << 10 )){ + else if (val & (1 << 10)) i = 10; - } else if( val & ( 1 << 11 )){ + else if (val & (1 << 11)) i = 11; - } else if( val & ( 1 << 12 )){ + else if (val & (1 << 12)) i = 12; - } else if( val & ( 1 << 17 )){ + else if (val & (1 << 17)) i = 17; - } else { + else printk("Unexpected IRQ irq = %d status = 0x%08lx\n", irq, val); - } - pr_debug("voyagergx_irq_demux %ld\n", i); -#else - for (bit = 1, i = 0 ; i < VOYAGER_IRQ_NUM ; bit <<= 1, i++) - if (val & bit) - break; -#endif + pr_debug("voyagergx_irq_demux %d \n", i); if (i < VOYAGER_IRQ_NUM) { irq = VOYAGER_IRQ_BASE + i; if (voyagergx_demux[i].func != 0) diff --git a/arch/sh/cchips/voyagergx/setup.c b/arch/sh/cchips/voyagergx/setup.c index 66b2fed..33f0302 100644 --- a/arch/sh/cchips/voyagergx/setup.c +++ b/arch/sh/cchips/voyagergx/setup.c @@ -19,7 +19,7 @@ static int __init setup_voyagergx(void) { unsigned long val; - val = inl(DRAM_CTRL); + val = readl((void __iomem *)DRAM_CTRL); val |= (DRAM_CTRL_CPU_COLUMN_SIZE_256 | DRAM_CTRL_CPU_ACTIVE_PRECHARGE | DRAM_CTRL_CPU_RESET | @@ -29,7 +29,7 @@ static int __init setup_voyagergx(void) DRAM_CTRL_ACTIVE_PRECHARGE | DRAM_CTRL_RESET | DRAM_CTRL_REMAIN_ACTIVE); - outl(val, DRAM_CTRL); + writel(val, (void __iomem *)DRAM_CTRL); return 0; } diff --git a/arch/sh/configs/rts7751r2d_defconfig b/arch/sh/configs/rts7751r2d_defconfig index 099e98f..db6a02d 100644 --- a/arch/sh/configs/rts7751r2d_defconfig +++ b/arch/sh/configs/rts7751r2d_defconfig @@ -1,15 +1,21 @@ # # Automatically generated make config: don't edit -# Linux kernel version: 2.6.18 -# Tue Oct 3 11:38:36 2006 +# Linux kernel version: 2.6.20 +# Thu Feb 15 17:17:29 2007 # CONFIG_SUPERH=y CONFIG_RWSEM_GENERIC_SPINLOCK=y CONFIG_GENERIC_FIND_NEXT_BIT=y CONFIG_GENERIC_HWEIGHT=y CONFIG_GENERIC_HARDIRQS=y +CONFIG_GENERIC_HARDIRQS_NO__DO_IRQ=y CONFIG_GENERIC_IRQ_PROBE=y CONFIG_GENERIC_CALIBRATE_DELAY=y +# CONFIG_GENERIC_TIME is not set +CONFIG_STACKTRACE_SUPPORT=y +CONFIG_LOCKDEP_SUPPORT=y +# CONFIG_ARCH_HAS_ILOG2_U32 is not set +# CONFIG_ARCH_HAS_ILOG2_U64 is not set CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config" # @@ -33,8 +39,8 @@ # CONFIG_TASKSTATS is not set # CONFIG_UTS_NS is not set # CONFIG_AUDIT is not set # CONFIG_IKCONFIG is not set +CONFIG_SYSFS_DEPRECATED=y # CONFIG_RELAY is not set -CONFIG_INITRAMFS_SOURCE="" # CONFIG_CC_OPTIMIZE_FOR_SIZE is not set CONFIG_SYSCTL=y CONFIG_EMBEDDED=y @@ -97,10 +103,8 @@ # CONFIG_SH_7343_SOLUTION_ENGINE is not # CONFIG_SH_73180_SOLUTION_ENGINE is not set # CONFIG_SH_7751_SYSTEMH is not set # CONFIG_SH_HP6XX is not set -# CONFIG_SH_EC3104 is not set # CONFIG_SH_SATURN is not set # CONFIG_SH_DREAMCAST is not set -# CONFIG_SH_BIGSUR is not set # CONFIG_SH_MPC1211 is not set # CONFIG_SH_SH03 is not set # CONFIG_SH_SECUREEDGE5410 is not set @@ -113,6 +117,9 @@ # CONFIG_SH_SH4202_MICRODEV is not set # CONFIG_SH_LANDISK is not set # CONFIG_SH_TITAN is not set # CONFIG_SH_SHMIN is not set +# CONFIG_SH_7206_SOLUTION_ENGINE is not set +# CONFIG_SH_7619_SOLUTION_ENGINE is not set +# CONFIG_SH_ASDAP310 is not set # CONFIG_SH_UNKNOWN is not set # @@ -124,6 +131,12 @@ # # SH-2 Processor Support # # CONFIG_CPU_SUBTYPE_SH7604 is not set +# CONFIG_CPU_SUBTYPE_SH7619 is not set + +# +# SH-2A Processor Support +# +# CONFIG_CPU_SUBTYPE_SH7206 is not set # # SH-3 Processor Support @@ -159,12 +172,14 @@ # SH-4A Processor Support # # CONFIG_CPU_SUBTYPE_SH7770 is not set # CONFIG_CPU_SUBTYPE_SH7780 is not set +# CONFIG_CPU_SUBTYPE_SH7785 is not set # # SH4AL-DSP Processor Support # # CONFIG_CPU_SUBTYPE_SH73180 is not set # CONFIG_CPU_SUBTYPE_SH7343 is not set +# CONFIG_CPU_SUBTYPE_SH7722 is not set # # Memory management options @@ -174,6 +189,9 @@ CONFIG_PAGE_OFFSET=0x80000000 CONFIG_MEMORY_START=0x0c000000 CONFIG_MEMORY_SIZE=0x04000000 CONFIG_VSYSCALL=y +CONFIG_PAGE_SIZE_4KB=y +# CONFIG_PAGE_SIZE_8KB is not set +# CONFIG_PAGE_SIZE_64KB is not set CONFIG_SELECT_MEMORY_MODEL=y CONFIG_FLATMEM_MANUAL=y # CONFIG_DISCONTIGMEM_MANUAL is not set @@ -183,6 +201,7 @@ CONFIG_FLAT_NODE_MEM_MAP=y # CONFIG_SPARSEMEM_STATIC is not set CONFIG_SPLIT_PTLOCK_CPUS=4 # CONFIG_RESOURCES_64BIT is not set +CONFIG_ZONE_DMA_FLAG=0 # # Cache configuration @@ -195,11 +214,14 @@ # # Processor features # CONFIG_CPU_LITTLE_ENDIAN=y +# CONFIG_CPU_BIG_ENDIAN is not set CONFIG_SH_FPU=y # CONFIG_SH_DSP is not set # CONFIG_SH_STORE_QUEUES is not set CONFIG_CPU_HAS_INTEVT=y +CONFIG_CPU_HAS_IPR_IRQ=y CONFIG_CPU_HAS_SR_RB=y +CONFIG_CPU_HAS_PTEA=y # # Timer support @@ -210,6 +232,8 @@ # # RTS7751R2D options # CONFIG_RTS7751R2D_REV11=y +CONFIG_SH_TIMER_IRQ=16 +# CONFIG_NO_IDLE_HZ is not set CONFIG_SH_PCLK_FREQ=60000000 # @@ -232,10 +256,16 @@ # CONFIG_HD6446X_SERIES is not set CONFIG_HEARTBEAT=y # +# Additional SuperH Device Drivers +# +# CONFIG_PUSH_SWITCH is not set + +# # Kernel features # # CONFIG_HZ_100 is not set CONFIG_HZ_250=y +# CONFIG_HZ_300 is not set # CONFIG_HZ_1000 is not set CONFIG_HZ=250 # CONFIG_KEXEC is not set @@ -251,7 +281,7 @@ CONFIG_ZERO_PAGE_OFFSET=0x00010000 CONFIG_BOOT_LINK_OFFSET=0x00800000 # CONFIG_UBC_WAKEUP is not set CONFIG_CMDLINE_BOOL=y -CONFIG_CMDLINE="mem=64M console=ttySC0,115200 root=/dev/hda1" +CONFIG_CMDLINE="console=ttySC0,115200 root=/dev/sda1" # # Bus options @@ -260,7 +290,6 @@ CONFIG_PCI=y CONFIG_SH_PCIDMA_NONCOHERENT=y CONFIG_PCI_AUTO=y CONFIG_PCI_AUTO_UPDATE_RESOURCES=y -# CONFIG_PCI_MULTITHREAD_PROBE is not set # # PCCARD (PCMCIA/CardBus) support @@ -302,6 +331,7 @@ CONFIG_UNIX=y CONFIG_XFRM=y # CONFIG_XFRM_USER is not set # CONFIG_XFRM_SUB_POLICY is not set +# CONFIG_XFRM_MIGRATE is not set # CONFIG_NET_KEY is not set CONFIG_INET=y # CONFIG_IP_MULTICAST is not set @@ -319,11 +349,13 @@ # CONFIG_INET_XFRM_TUNNEL is not set # CONFIG_INET_TUNNEL is not set CONFIG_INET_XFRM_MODE_TRANSPORT=y CONFIG_INET_XFRM_MODE_TUNNEL=y +CONFIG_INET_XFRM_MODE_BEET=y CONFIG_INET_DIAG=y CONFIG_INET_TCP_DIAG=y # CONFIG_TCP_CONG_ADVANCED is not set CONFIG_TCP_CONG_CUBIC=y CONFIG_DEFAULT_TCP_CONG="cubic" +# CONFIG_TCP_MD5SIG is not set # CONFIG_IPV6 is not set # CONFIG_INET6_XFRM_TUNNEL is not set # CONFIG_INET6_TUNNEL is not set @@ -380,7 +412,7 @@ # Generic Driver Options # CONFIG_STANDALONE=y CONFIG_PREVENT_FIRMWARE_BUILD=y -# CONFIG_FW_LOADER is not set +CONFIG_FW_LOADER=m # CONFIG_SYS_HYPERVISOR is not set # @@ -422,44 +454,145 @@ # CONFIG_CDROM_PKTCDVD is not set # CONFIG_ATA_OVER_ETH is not set # -# ATA/ATAPI/MFM/RLL support -# -CONFIG_IDE=y -CONFIG_IDE_MAX_HWIFS=4 -CONFIG_BLK_DEV_IDE=y - -# -# Please see Documentation/ide.txt for help/info on IDE drives +# Misc devices # -# CONFIG_BLK_DEV_IDE_SATA is not set -CONFIG_BLK_DEV_IDEDISK=y -# CONFIG_IDEDISK_MULTI_MODE is not set -# CONFIG_BLK_DEV_IDECD is not set -# CONFIG_BLK_DEV_IDETAPE is not set -# CONFIG_BLK_DEV_IDEFLOPPY is not set -# CONFIG_IDE_TASK_IOCTL is not set +# CONFIG_SGI_IOC4 is not set +# CONFIG_TIFM_CORE is not set # -# IDE chipset support/bugfixes +# ATA/ATAPI/MFM/RLL support # -CONFIG_IDE_GENERIC=y -# CONFIG_BLK_DEV_IDEPCI is not set -# CONFIG_IDE_ARM is not set -# CONFIG_BLK_DEV_IDEDMA is not set -# CONFIG_IDEDMA_AUTO is not set -# CONFIG_BLK_DEV_HD is not set +# CONFIG_IDE is not set # # SCSI device support # # CONFIG_RAID_ATTRS is not set -# CONFIG_SCSI is not set +CONFIG_SCSI=y +# CONFIG_SCSI_TGT is not set # CONFIG_SCSI_NETLINK is not set +CONFIG_SCSI_PROC_FS=y + +# +# SCSI support type (disk, tape, CD-ROM) +# +CONFIG_BLK_DEV_SD=y +# CONFIG_CHR_DEV_ST is not set +# CONFIG_CHR_DEV_OSST is not set +# CONFIG_BLK_DEV_SR is not set +# CONFIG_CHR_DEV_SG is not set +# CONFIG_CHR_DEV_SCH is not set + +# +# Some SCSI devices (e.g. CD jukebox) support multiple LUNs +# +# CONFIG_SCSI_MULTI_LUN is not set +# CONFIG_SCSI_CONSTANTS is not set +# CONFIG_SCSI_LOGGING is not set +# CONFIG_SCSI_SCAN_ASYNC is not set + +# +# SCSI Transports +# +# CONFIG_SCSI_SPI_ATTRS is not set +# CONFIG_SCSI_FC_ATTRS is not set +# CONFIG_SCSI_ISCSI_ATTRS is not set +# CONFIG_SCSI_SAS_ATTRS is not set +# CONFIG_SCSI_SAS_LIBSAS is not set + +# +# SCSI low-level drivers +# +# CONFIG_ISCSI_TCP is not set +# CONFIG_BLK_DEV_3W_XXXX_RAID is not set +# CONFIG_SCSI_3W_9XXX is not set +# CONFIG_SCSI_ACARD is not set +# CONFIG_SCSI_AACRAID is not set +# CONFIG_SCSI_AIC7XXX is not set +# CONFIG_SCSI_AIC7XXX_OLD is not set +# CONFIG_SCSI_AIC79XX is not set +# CONFIG_SCSI_AIC94XX is not set +# CONFIG_SCSI_DPT_I2O is not set +# CONFIG_SCSI_ARCMSR is not set +# CONFIG_MEGARAID_NEWGEN is not set +# CONFIG_MEGARAID_LEGACY is not set +# CONFIG_MEGARAID_SAS is not set +# CONFIG_SCSI_HPTIOP is not set +# CONFIG_SCSI_DMX3191D is not set +# CONFIG_SCSI_FUTURE_DOMAIN is not set +# CONFIG_SCSI_IPS is not set +# CONFIG_SCSI_INITIO is not set +# CONFIG_SCSI_INIA100 is not set +# CONFIG_SCSI_STEX is not set +# CONFIG_SCSI_SYM53C8XX_2 is not set +# CONFIG_SCSI_IPR is not set +# CONFIG_SCSI_QLOGIC_1280 is not set +# CONFIG_SCSI_QLA_FC is not set +# CONFIG_SCSI_QLA_ISCSI is not set +# CONFIG_SCSI_LPFC is not set +# CONFIG_SCSI_DC395x is not set +# CONFIG_SCSI_DC390T is not set +# CONFIG_SCSI_NSP32 is not set +# CONFIG_SCSI_DEBUG is not set +# CONFIG_SCSI_SRP is not set # # Serial ATA (prod) and Parallel ATA (experimental) drivers # -# CONFIG_ATA is not set +CONFIG_ATA=y +# CONFIG_ATA_NONSTANDARD is not set +# CONFIG_SATA_AHCI is not set +# CONFIG_SATA_SVW is not set +# CONFIG_ATA_PIIX is not set +# CONFIG_SATA_MV is not set +# CONFIG_SATA_NV is not set +# CONFIG_PDC_ADMA is not set +# CONFIG_SATA_QSTOR is not set +# CONFIG_SATA_PROMISE is not set +# CONFIG_SATA_SX4 is not set +# CONFIG_SATA_SIL is not set +# CONFIG_SATA_SIL24 is not set +# CONFIG_SATA_SIS is not set +# CONFIG_SATA_ULI is not set +# CONFIG_SATA_VIA is not set +# CONFIG_SATA_VITESSE is not set +# CONFIG_SATA_INIC162X is not set +# CONFIG_PATA_ALI is not set +# CONFIG_PATA_AMD is not set +# CONFIG_PATA_ARTOP is not set +# CONFIG_PATA_ATIIXP is not set +# CONFIG_PATA_CMD64X is not set +# CONFIG_PATA_CS5520 is not set +# CONFIG_PATA_CS5530 is not set +# CONFIG_PATA_CYPRESS is not set +# CONFIG_PATA_EFAR is not set +# CONFIG_ATA_GENERIC is not set +# CONFIG_PATA_HPT366 is not set +# CONFIG_PATA_HPT37X is not set +# CONFIG_PATA_HPT3X2N is not set +# CONFIG_PATA_HPT3X3 is not set +# CONFIG_PATA_IT821X is not set +# CONFIG_PATA_IT8213 is not set +# CONFIG_PATA_JMICRON is not set +# CONFIG_PATA_TRIFLEX is not set +# CONFIG_PATA_MARVELL is not set +# CONFIG_PATA_MPIIX is not set +# CONFIG_PATA_OLDPIIX is not set +# CONFIG_PATA_NETCELL is not set +# CONFIG_PATA_NS87410 is not set +# CONFIG_PATA_OPTI is not set +# CONFIG_PATA_OPTIDMA is not set +# CONFIG_PATA_PDC_OLD is not set +# CONFIG_PATA_RADISYS is not set +# CONFIG_PATA_RZ1000 is not set +# CONFIG_PATA_SC1200 is not set +# CONFIG_PATA_SERVERWORKS is not set +# CONFIG_PATA_PDC2027X is not set +# CONFIG_PATA_SIL680 is not set +# CONFIG_PATA_SIS is not set +# CONFIG_PATA_VIA is not set +# CONFIG_PATA_WINBOND is not set +CONFIG_PATA_PLATFORM=y # # Multi-device support (RAID and LVM) @@ -470,6 +603,9 @@ # # Fusion MPT device support # # CONFIG_FUSION is not set +# CONFIG_FUSION_SPI is not set +# CONFIG_FUSION_FC is not set +# CONFIG_FUSION_SAS is not set # # IEEE 1394 (FireWire) support @@ -540,6 +676,7 @@ # CONFIG_EPIC100 is not set # CONFIG_SUNDANCE is not set # CONFIG_TLAN is not set # CONFIG_VIA_RHINE is not set +# CONFIG_SC92031 is not set # # Ethernet (1000 Mbit) @@ -559,14 +696,17 @@ # CONFIG_VIA_VELOCITY is not set # CONFIG_TIGON3 is not set # CONFIG_BNX2 is not set # CONFIG_QLA3XXX is not set +# CONFIG_ATL1 is not set # # Ethernet (10000 Mbit) # # CONFIG_CHELSIO_T1 is not set +# CONFIG_CHELSIO_T3 is not set # CONFIG_IXGB is not set # CONFIG_S2IO is not set # CONFIG_MYRI10GE is not set +# CONFIG_NETXEN_NIC is not set # # Token Ring devices @@ -611,6 +751,7 @@ # CONFIG_FDDI is not set # CONFIG_HIPPI is not set # CONFIG_PPP is not set # CONFIG_SLIP is not set +# CONFIG_NET_FC is not set # CONFIG_SHAPER is not set # CONFIG_NETCONSOLE is not set # CONFIG_NETPOLL is not set @@ -646,14 +787,23 @@ # CONFIG_SERIAL_NONSTANDARD is not set # # Serial drivers # -# CONFIG_SERIAL_8250 is not set +CONFIG_SERIAL_8250=y +# CONFIG_SERIAL_8250_CONSOLE is not set +CONFIG_SERIAL_8250_PCI=y +CONFIG_SERIAL_8250_NR_UARTS=4 +CONFIG_SERIAL_8250_RUNTIME_UARTS=4 +# CONFIG_SERIAL_8250_EXTENDED is not set # # Non-8250 serial port support # -# CONFIG_SERIAL_SH_SCI is not set +CONFIG_SERIAL_SH_SCI=y +CONFIG_SERIAL_SH_SCI_NR_UARTS=1 +CONFIG_SERIAL_SH_SCI_CONSOLE=y +CONFIG_SERIAL_CORE=y +CONFIG_SERIAL_CORE_CONSOLE=y # CONFIG_SERIAL_JSM is not set -# CONFIG_UNIX98_PTYS is not set +CONFIG_UNIX98_PTYS=y CONFIG_LEGACY_PTYS=y CONFIG_LEGACY_PTY_COUNT=256 @@ -671,10 +821,6 @@ # CONFIG_GEN_RTC is not set # CONFIG_DTLK is not set # CONFIG_R3964 is not set # CONFIG_APPLICOM is not set - -# -# Ftape, the floppy tape device driver -# # CONFIG_DRM is not set # CONFIG_RAW_DRIVER is not set @@ -682,7 +828,6 @@ # # TPM devices # # CONFIG_TCG_TPM is not set -# CONFIG_TELCLOCK is not set # # I2C support @@ -698,6 +843,7 @@ # CONFIG_SPI_MASTER is not set # # Dallas's 1-wire bus # +# CONFIG_W1 is not set # # Hardware Monitoring support @@ -706,18 +852,14 @@ CONFIG_HWMON=y # CONFIG_HWMON_VID is not set # CONFIG_SENSORS_ABITUGURU is not set # CONFIG_SENSORS_F71805F is not set +# CONFIG_SENSORS_PC87427 is not set # CONFIG_SENSORS_VT1211 is not set # CONFIG_HWMON_DEBUG_CHIP is not set # -# Misc devices -# - -# # Multimedia devices # # CONFIG_VIDEO_DEV is not set -CONFIG_VIDEO_V4L2=y # # Digital Video Broadcasting Devices @@ -759,7 +901,6 @@ # CONFIG_SND_MPU401_UART=m CONFIG_SND_OPL3_LIB=m CONFIG_SND_AC97_CODEC=m -CONFIG_SND_AC97_BUS=m # CONFIG_SND_DUMMY is not set # CONFIG_SND_MTPAV is not set # CONFIG_SND_SERIAL_U16550 is not set @@ -782,6 +923,18 @@ # CONFIG_SND_CA0106 is not set # CONFIG_SND_CMIPCI is not set # CONFIG_SND_CS4281 is not set # CONFIG_SND_CS46XX is not set +# CONFIG_SND_DARLA20 is not set +# CONFIG_SND_GINA20 is not set +# CONFIG_SND_LAYLA20 is not set +# CONFIG_SND_DARLA24 is not set +# CONFIG_SND_GINA24 is not set +# CONFIG_SND_LAYLA24 is not set +# CONFIG_SND_MONA is not set +# CONFIG_SND_MIA is not set +# CONFIG_SND_ECHO3G is not set +# CONFIG_SND_INDIGO is not set +# CONFIG_SND_INDIGOIO is not set +# CONFIG_SND_INDIGODJ is not set # CONFIG_SND_EMU10K1 is not set # CONFIG_SND_EMU10K1X is not set # CONFIG_SND_ENS1370 is not set @@ -801,6 +954,7 @@ # CONFIG_SND_MAESTRO3 is not set # CONFIG_SND_MIXART is not set # CONFIG_SND_NM256 is not set # CONFIG_SND_PCXHR is not set +# CONFIG_SND_RIPTIDE is not set # CONFIG_SND_RME32 is not set # CONFIG_SND_RME96 is not set # CONFIG_SND_RME9652 is not set @@ -813,17 +967,22 @@ CONFIG_SND_YMFPCI=m # CONFIG_SND_AC97_POWER_SAVE is not set # +# SoC audio support +# +# CONFIG_SND_SOC is not set + +# # Open Sound System # CONFIG_SOUND_PRIME=m -# CONFIG_OSS_OBSOLETE_DRIVER is not set +# CONFIG_OBSOLETE_OSS is not set # CONFIG_SOUND_BT878 is not set -# CONFIG_SOUND_ES1371 is not set # CONFIG_SOUND_ICH is not set # CONFIG_SOUND_TRIDENT is not set # CONFIG_SOUND_MSNDCLAS is not set # CONFIG_SOUND_MSNDPIN is not set # CONFIG_SOUND_VIA82CXXX is not set +CONFIG_AC97_BUS=m # # USB support @@ -872,7 +1031,29 @@ # # # Real Time Clock # -# CONFIG_RTC_CLASS is not set +CONFIG_RTC_LIB=y +CONFIG_RTC_CLASS=y +CONFIG_RTC_HCTOSYS=y +CONFIG_RTC_HCTOSYS_DEVICE="rtc0" +# CONFIG_RTC_DEBUG is not set + +# +# RTC interfaces +# +CONFIG_RTC_INTF_SYSFS=y +CONFIG_RTC_INTF_PROC=y +CONFIG_RTC_INTF_DEV=y +# CONFIG_RTC_INTF_DEV_UIE_EMUL is not set + +# +# RTC drivers +# +# CONFIG_RTC_DRV_DS1553 is not set +# CONFIG_RTC_DRV_DS1742 is not set +# CONFIG_RTC_DRV_M48T86 is not set +CONFIG_RTC_DRV_SH=y +# CONFIG_RTC_DRV_TEST is not set +# CONFIG_RTC_DRV_V3020 is not set # # DMA Engine support @@ -888,16 +1069,26 @@ # DMA Devices # # +# Auxiliary Display support +# + +# +# Virtualization +# + +# # File systems # CONFIG_EXT2_FS=y # CONFIG_EXT2_FS_XATTR is not set # CONFIG_EXT2_FS_XIP is not set # CONFIG_EXT3_FS is not set +# CONFIG_EXT4DEV_FS is not set # CONFIG_REISERFS_FS is not set # CONFIG_JFS_FS is not set # CONFIG_FS_POSIX_ACL is not set # CONFIG_XFS_FS is not set +# CONFIG_GFS2_FS is not set # CONFIG_OCFS2_FS is not set CONFIG_MINIX_FS=y # CONFIG_ROMFS_FS is not set @@ -932,7 +1123,8 @@ CONFIG_PROC_FS=y CONFIG_PROC_KCORE=y CONFIG_PROC_SYSCTL=y CONFIG_SYSFS=y -# CONFIG_TMPFS is not set +CONFIG_TMPFS=y +# CONFIG_TMPFS_POSIX_ACL is not set # CONFIG_HUGETLBFS is not set # CONFIG_HUGETLB_PAGE is not set CONFIG_RAMFS=y @@ -1018,6 +1210,11 @@ # CONFIG_NLS_KOI8_U is not set # CONFIG_NLS_UTF8 is not set # +# Distributed Lock Manager +# +# CONFIG_DLM is not set + +# # Profiling support # CONFIG_PROFILING=y @@ -1026,16 +1223,20 @@ CONFIG_OPROFILE=y # # Kernel hacking # +CONFIG_TRACE_IRQFLAGS_SUPPORT=y # CONFIG_PRINTK_TIME is not set CONFIG_ENABLE_MUST_CHECK=y # CONFIG_MAGIC_SYSRQ is not set # CONFIG_UNUSED_SYMBOLS is not set +# CONFIG_DEBUG_FS is not set +# CONFIG_HEADERS_CHECK is not set # CONFIG_DEBUG_KERNEL is not set CONFIG_LOG_BUF_SHIFT=14 # CONFIG_DEBUG_BUGVERBOSE is not set -# CONFIG_DEBUG_FS is not set # CONFIG_SH_STANDARD_BIOS is not set -# CONFIG_EARLY_SCIF_CONSOLE is not set +CONFIG_EARLY_SCIF_CONSOLE=y +CONFIG_EARLY_SCIF_CONSOLE_PORT=0xffe80000 +CONFIG_EARLY_PRINTK=y # CONFIG_KGDB is not set # @@ -1052,8 +1253,11 @@ # CONFIG_CRYPTO is not set # # Library routines # +CONFIG_BITREVERSE=y # CONFIG_CRC_CCITT is not set # CONFIG_CRC16 is not set CONFIG_CRC32=y # CONFIG_LIBCRC32C is not set CONFIG_PLIST=y +CONFIG_HAS_IOMEM=y +CONFIG_HAS_IOPORT=y diff --git a/arch/sh/configs/se7750_defconfig b/arch/sh/configs/se7750_defconfig index 5d357d6..4e6e77f 100644 --- a/arch/sh/configs/se7750_defconfig +++ b/arch/sh/configs/se7750_defconfig @@ -1,7 +1,7 @@ # # Automatically generated make config: don't edit -# Linux kernel version: 2.6.18 -# Tue Oct 3 11:49:01 2006 +# Linux kernel version: 2.6.20-rc2 +# Thu Dec 28 23:15:49 2006 # CONFIG_SUPERH=y CONFIG_RWSEM_GENERIC_SPINLOCK=y @@ -10,6 +10,11 @@ CONFIG_GENERIC_HWEIGHT=y CONFIG_GENERIC_HARDIRQS=y CONFIG_GENERIC_IRQ_PROBE=y CONFIG_GENERIC_CALIBRATE_DELAY=y +# CONFIG_GENERIC_TIME is not set +CONFIG_STACKTRACE_SUPPORT=y +CONFIG_LOCKDEP_SUPPORT=y +# CONFIG_ARCH_HAS_ILOG2_U32 is not set +# CONFIG_ARCH_HAS_ILOG2_U64 is not set CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config" # @@ -35,6 +40,7 @@ # CONFIG_UTS_NS is not set # CONFIG_AUDIT is not set CONFIG_IKCONFIG=y CONFIG_IKCONFIG_PROC=y +CONFIG_SYSFS_DEPRECATED=y # CONFIG_RELAY is not set CONFIG_INITRAMFS_SOURCE="" # CONFIG_CC_OPTIMIZE_FOR_SIZE is not set @@ -116,6 +122,8 @@ # CONFIG_SH_SH4202_MICRODEV is not set # CONFIG_SH_LANDISK is not set # CONFIG_SH_TITAN is not set # CONFIG_SH_SHMIN is not set +# CONFIG_SH_7206_SOLUTION_ENGINE is not set +# CONFIG_SH_7619_SOLUTION_ENGINE is not set # CONFIG_SH_UNKNOWN is not set # @@ -127,6 +135,12 @@ # # SH-2 Processor Support # # CONFIG_CPU_SUBTYPE_SH7604 is not set +# CONFIG_CPU_SUBTYPE_SH7619 is not set + +# +# SH-2A Processor Support +# +# CONFIG_CPU_SUBTYPE_SH7206 is not set # # SH-3 Processor Support @@ -162,12 +176,14 @@ # SH-4A Processor Support # # CONFIG_CPU_SUBTYPE_SH7770 is not set # CONFIG_CPU_SUBTYPE_SH7780 is not set +# CONFIG_CPU_SUBTYPE_SH7785 is not set # # SH4AL-DSP Processor Support # # CONFIG_CPU_SUBTYPE_SH73180 is not set # CONFIG_CPU_SUBTYPE_SH7343 is not set +# CONFIG_CPU_SUBTYPE_SH7722 is not set # # Memory management options @@ -177,6 +193,9 @@ CONFIG_PAGE_OFFSET=0x80000000 CONFIG_MEMORY_START=0x0c000000 CONFIG_MEMORY_SIZE=0x02000000 CONFIG_VSYSCALL=y +CONFIG_PAGE_SIZE_4KB=y +# CONFIG_PAGE_SIZE_8KB is not set +# CONFIG_PAGE_SIZE_64KB is not set CONFIG_SELECT_MEMORY_MODEL=y CONFIG_FLATMEM_MANUAL=y # CONFIG_DISCONTIGMEM_MANUAL is not set @@ -202,17 +221,22 @@ # # Processor features # CONFIG_CPU_LITTLE_ENDIAN=y +# CONFIG_CPU_BIG_ENDIAN is not set CONFIG_SH_FPU=y # CONFIG_SH_DSP is not set # CONFIG_SH_STORE_QUEUES is not set CONFIG_CPU_HAS_INTEVT=y +CONFIG_CPU_HAS_IPR_IRQ=y CONFIG_CPU_HAS_SR_RB=y +CONFIG_CPU_HAS_PTEA=y # # Timer support # CONFIG_SH_TMU=y -CONFIG_SH_PCLK_FREQ=50000000 +CONFIG_SH_TIMER_IRQ=16 +# CONFIG_NO_IDLE_HZ is not set +CONFIG_SH_PCLK_FREQ=33333333 # # CPU Frequency scaling @@ -231,10 +255,16 @@ # CONFIG_HD6446X_SERIES is not set CONFIG_HEARTBEAT=y # +# Additional SuperH Device Drivers +# +# CONFIG_PUSH_SWITCH is not set + +# # Kernel features # # CONFIG_HZ_100 is not set CONFIG_HZ_250=y +# CONFIG_HZ_300 is not set # CONFIG_HZ_1000 is not set CONFIG_HZ=250 # CONFIG_KEXEC is not set @@ -249,8 +279,7 @@ # CONFIG_ZERO_PAGE_OFFSET=0x00001000 CONFIG_BOOT_LINK_OFFSET=0x00800000 # CONFIG_UBC_WAKEUP is not set -CONFIG_CMDLINE_BOOL=y -CONFIG_CMDLINE="console=ttySC1,38400 root=/dev/nfs ip=bootp" +# CONFIG_CMDLINE_BOOL is not set # # Bus options @@ -313,11 +342,13 @@ # CONFIG_INET_XFRM_TUNNEL is not set # CONFIG_INET_TUNNEL is not set CONFIG_INET_XFRM_MODE_TRANSPORT=y CONFIG_INET_XFRM_MODE_TUNNEL=y +CONFIG_INET_XFRM_MODE_BEET=y CONFIG_INET_DIAG=y CONFIG_INET_TCP_DIAG=y # CONFIG_TCP_CONG_ADVANCED is not set CONFIG_TCP_CONG_CUBIC=y CONFIG_DEFAULT_TCP_CONG="cubic" +# CONFIG_TCP_MD5SIG is not set # CONFIG_IPV6 is not set # CONFIG_INET6_XFRM_TUNNEL is not set # CONFIG_INET6_TUNNEL is not set @@ -480,16 +511,79 @@ # CONFIG_CDROM_PKTCDVD is not set # CONFIG_ATA_OVER_ETH is not set # +# Misc devices +# +# CONFIG_TIFM_CORE is not set + +# # ATA/ATAPI/MFM/RLL support # -# CONFIG_IDE is not set +CONFIG_IDE=y +CONFIG_IDE_MAX_HWIFS=4 +CONFIG_BLK_DEV_IDE=y + +# +# Please see Documentation/ide.txt for help/info on IDE drives +# +# CONFIG_BLK_DEV_IDE_SATA is not set +CONFIG_BLK_DEV_IDEDISK=y +# CONFIG_IDEDISK_MULTI_MODE is not set +# CONFIG_BLK_DEV_IDECD is not set +# CONFIG_BLK_DEV_IDETAPE is not set +# CONFIG_BLK_DEV_IDEFLOPPY is not set +# CONFIG_BLK_DEV_IDESCSI is not set +# CONFIG_IDE_TASK_IOCTL is not set + +# +# IDE chipset support/bugfixes +# +# CONFIG_IDE_GENERIC is not set +# CONFIG_IDE_ARM is not set +# CONFIG_BLK_DEV_IDEDMA is not set +# CONFIG_IDEDMA_AUTO is not set +# CONFIG_BLK_DEV_HD is not set # # SCSI device support # # CONFIG_RAID_ATTRS is not set -# CONFIG_SCSI is not set +CONFIG_SCSI=y +# CONFIG_SCSI_TGT is not set # CONFIG_SCSI_NETLINK is not set +CONFIG_SCSI_PROC_FS=y + +# +# SCSI support type (disk, tape, CD-ROM) +# +# CONFIG_BLK_DEV_SD is not set +# CONFIG_CHR_DEV_ST is not set +# CONFIG_CHR_DEV_OSST is not set +# CONFIG_BLK_DEV_SR is not set +# CONFIG_CHR_DEV_SG is not set +# CONFIG_CHR_DEV_SCH is not set + +# +# Some SCSI devices (e.g. CD jukebox) support multiple LUNs +# +# CONFIG_SCSI_MULTI_LUN is not set +# CONFIG_SCSI_CONSTANTS is not set +# CONFIG_SCSI_LOGGING is not set +# CONFIG_SCSI_SCAN_ASYNC is not set + +# +# SCSI Transports +# +# CONFIG_SCSI_SPI_ATTRS is not set +# CONFIG_SCSI_FC_ATTRS is not set +# CONFIG_SCSI_ISCSI_ATTRS is not set +# CONFIG_SCSI_SAS_ATTRS is not set +# CONFIG_SCSI_SAS_LIBSAS is not set + +# +# SCSI low-level drivers +# +# CONFIG_ISCSI_TCP is not set +# CONFIG_SCSI_DEBUG is not set # # Serial ATA (prod) and Parallel ATA (experimental) drivers @@ -633,17 +727,12 @@ CONFIG_HW_RANDOM=y # CONFIG_GEN_RTC is not set # CONFIG_DTLK is not set # CONFIG_R3964 is not set - -# -# Ftape, the floppy tape device driver -# # CONFIG_RAW_DRIVER is not set # # TPM devices # # CONFIG_TCG_TPM is not set -# CONFIG_TELCLOCK is not set # # I2C support @@ -659,6 +748,7 @@ # CONFIG_SPI_MASTER is not set # # Dallas's 1-wire bus # +# CONFIG_W1 is not set # # Hardware Monitoring support @@ -667,18 +757,14 @@ CONFIG_HWMON=y # CONFIG_HWMON_VID is not set # CONFIG_SENSORS_ABITUGURU is not set # CONFIG_SENSORS_F71805F is not set +# CONFIG_SENSORS_PC87427 is not set # CONFIG_SENSORS_VT1211 is not set # CONFIG_HWMON_DEBUG_CHIP is not set # -# Misc devices -# - -# # Multimedia devices # # CONFIG_VIDEO_DEV is not set -CONFIG_VIDEO_V4L2=y # # Digital Video Broadcasting Devices @@ -758,14 +844,20 @@ # DMA Devices # # +# Virtualization +# + +# # File systems # # CONFIG_EXT2_FS is not set # CONFIG_EXT3_FS is not set +# CONFIG_EXT4DEV_FS is not set # CONFIG_REISERFS_FS is not set # CONFIG_JFS_FS is not set # CONFIG_FS_POSIX_ACL is not set # CONFIG_XFS_FS is not set +# CONFIG_GFS2_FS is not set # CONFIG_OCFS2_FS is not set # CONFIG_MINIX_FS is not set # CONFIG_ROMFS_FS is not set @@ -814,7 +906,6 @@ # CONFIG_HFSPLUS_FS is not set # CONFIG_BEFS_FS is not set # CONFIG_BFS_FS is not set # CONFIG_EFS_FS is not set -# CONFIG_JFFS_FS is not set CONFIG_JFFS2_FS=y CONFIG_JFFS2_FS_DEBUG=0 CONFIG_JFFS2_FS_WRITEBUFFER=y @@ -875,6 +966,11 @@ # # CONFIG_NLS is not set # +# Distributed Lock Manager +# +# CONFIG_DLM is not set + +# # Profiling support # # CONFIG_PROFILING is not set @@ -882,14 +978,16 @@ # CONFIG_PROFILING is not set # # Kernel hacking # +CONFIG_TRACE_IRQFLAGS_SUPPORT=y # CONFIG_PRINTK_TIME is not set -CONFIG_ENABLE_MUST_CHECK=y +# CONFIG_ENABLE_MUST_CHECK is not set # CONFIG_MAGIC_SYSRQ is not set # CONFIG_UNUSED_SYMBOLS is not set +# CONFIG_DEBUG_FS is not set +# CONFIG_HEADERS_CHECK is not set # CONFIG_DEBUG_KERNEL is not set CONFIG_LOG_BUF_SHIFT=14 # CONFIG_DEBUG_BUGVERBOSE is not set -# CONFIG_DEBUG_FS is not set # CONFIG_SH_STANDARD_BIOS is not set # CONFIG_EARLY_SCIF_CONSOLE is not set # CONFIG_KGDB is not set @@ -908,6 +1006,7 @@ # CONFIG_CRYPTO is not set # # Library routines # +CONFIG_BITREVERSE=y # CONFIG_CRC_CCITT is not set # CONFIG_CRC16 is not set CONFIG_CRC32=y @@ -915,3 +1014,4 @@ # CONFIG_LIBCRC32C is not set CONFIG_ZLIB_INFLATE=y CONFIG_ZLIB_DEFLATE=y CONFIG_PLIST=y +CONFIG_IOMAP_COPY=y diff --git a/arch/sh/drivers/Makefile b/arch/sh/drivers/Makefile index bf18dbf..6cb9267 100644 --- a/arch/sh/drivers/Makefile +++ b/arch/sh/drivers/Makefile @@ -6,3 +6,4 @@ obj-$(CONFIG_PCI) += pci/ obj-$(CONFIG_SH_DMA) += dma/ obj-$(CONFIG_SUPERHYWAY) += superhyway/ obj-$(CONFIG_PUSH_SWITCH) += push-switch.o +obj-$(CONFIG_HEARTBEAT) += heartbeat.o diff --git a/arch/sh/drivers/dma/dma-sh.c b/arch/sh/drivers/dma/dma-sh.c index f63721e..06ed060 100644 --- a/arch/sh/drivers/dma/dma-sh.c +++ b/arch/sh/drivers/dma/dma-sh.c @@ -19,34 +19,26 @@ #include #include #include "dma-sh.h" - - -#ifdef CONFIG_CPU_SH4 -static struct ipr_data dmae_ipr_map[] = { - { DMAE_IRQ, DMA_IPR_ADDR, DMA_IPR_POS, DMA_PRIORITY }, -}; +static int dmte_irq_map[] = { + DMTE0_IRQ, + DMTE1_IRQ, + DMTE2_IRQ, + DMTE3_IRQ, +#if defined(CONFIG_CPU_SUBTYPE_SH7751R) || \ + defined(CONFIG_CPU_SUBTYPE_SH7760) || \ + defined(CONFIG_CPU_SUBTYPE_SH7780) + DMTE4_IRQ, + DMTE5_IRQ, + DMTE6_IRQ, + DMTE7_IRQ, #endif -static struct ipr_data dmte_ipr_map[] = { - /* - * Normally we could just do DMTE0_IRQ + chan outright, though in the - * case of the 7751R, the DMTE IRQs for channels > 4 start right above - * the SCIF - */ - { DMTE0_IRQ + 0, DMA_IPR_ADDR, DMA_IPR_POS, DMA_PRIORITY }, - { DMTE0_IRQ + 1, DMA_IPR_ADDR, DMA_IPR_POS, DMA_PRIORITY }, - { DMTE0_IRQ + 2, DMA_IPR_ADDR, DMA_IPR_POS, DMA_PRIORITY }, - { DMTE0_IRQ + 3, DMA_IPR_ADDR, DMA_IPR_POS, DMA_PRIORITY }, - { DMTE4_IRQ + 0, DMA_IPR_ADDR, DMA_IPR_POS, DMA_PRIORITY }, - { DMTE4_IRQ + 1, DMA_IPR_ADDR, DMA_IPR_POS, DMA_PRIORITY }, - { DMTE4_IRQ + 2, DMA_IPR_ADDR, DMA_IPR_POS, DMA_PRIORITY }, - { DMTE4_IRQ + 3, DMA_IPR_ADDR, DMA_IPR_POS, DMA_PRIORITY }, }; static inline unsigned int get_dmte_irq(unsigned int chan) { unsigned int irq = 0; - if (chan < ARRAY_SIZE(dmte_ipr_map)) - irq = dmte_ipr_map[chan].irq; + if (chan < ARRAY_SIZE(dmte_irq_map)) + irq = dmte_irq_map[chan]; return irq; } @@ -103,7 +95,7 @@ static void sh_dmac_free_dma(struct dma_ free_irq(get_dmte_irq(chan->chan), chan); } -static void +static int sh_dmac_configure_channel(struct dma_channel *chan, unsigned long chcr) { if (!chcr) @@ -119,6 +111,7 @@ sh_dmac_configure_channel(struct dma_cha ctrl_outl(chcr, CHCR[chan->chan]); chan->flags |= DMA_CONFIGURED; + return 0; } static void sh_dmac_enable_dma(struct dma_channel *chan) @@ -262,17 +255,11 @@ static int __init sh_dmac_init(void) int i; #ifdef CONFIG_CPU_SH4 - make_ipr_irq(dmae_ipr_map, ARRAY_SIZE(dmae_ipr_map)); i = request_irq(DMAE_IRQ, dma_err, IRQF_DISABLED, "DMAC Address Error", 0); if (unlikely(i < 0)) return i; #endif - i = info->nr_channels; - if (i > ARRAY_SIZE(dmte_ipr_map)) - i = ARRAY_SIZE(dmte_ipr_map); - make_ipr_irq(dmte_ipr_map, i); - /* * Initialize DMAOR, and clean up any error flags that may have * been set. diff --git a/arch/sh/drivers/heartbeat.c b/arch/sh/drivers/heartbeat.c new file mode 100644 index 0000000..bc59cb6 --- /dev/null +++ b/arch/sh/drivers/heartbeat.c @@ -0,0 +1,132 @@ +/* + * Generic heartbeat driver for regular LED banks + * + * Copyright (C) 2007 Paul Mundt + * + * Most SH reference boards include a number of individual LEDs that can + * be independently controlled (either via a pre-defined hardware + * function or via the LED class, if desired -- the hardware tends to + * encapsulate some of the same "triggers" that the LED class supports, + * so there's not too much value in it). + * + * Additionally, most of these boards also have a LED bank that we've + * traditionally used for strobing the load average. This use case is + * handled by this driver, rather than giving each LED bit position its + * own struct device. + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + */ +#include +#include +#include +#include +#include +#include + +#define DRV_NAME "heartbeat" +#define DRV_VERSION "0.1.0" + +struct heartbeat_data { + void __iomem *base; + unsigned char bit_pos[8]; + struct timer_list timer; +}; + +static void heartbeat_timer(unsigned long data) +{ + struct heartbeat_data *hd = (struct heartbeat_data *)data; + static unsigned bit = 0, up = 1; + + ctrl_outw(1 << hd->bit_pos[bit], (unsigned long)hd->base); + if (up) + if (bit == (ARRAY_SIZE(hd->bit_pos) - 1)) { + bit--; + up = 0; + } else + bit++; + else if (bit == 0) + up = 1; + else + bit--; + + mod_timer(&hd->timer, jiffies + (110 - ((300 << FSHIFT) / + ((avenrun[0] / 5) + (3 << FSHIFT))))); +} + +static int heartbeat_drv_probe(struct platform_device *pdev) +{ + struct resource *res; + struct heartbeat_data *hd; + + if (unlikely(pdev->num_resources != 1)) { + dev_err(&pdev->dev, "invalid number of resources\n"); + return -EINVAL; + } + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (unlikely(res == NULL)) { + dev_err(&pdev->dev, "invalid resource\n"); + return -EINVAL; + } + + hd = kmalloc(sizeof(struct heartbeat_data), GFP_KERNEL); + if (unlikely(!hd)) + return -ENOMEM; + + if (pdev->dev.platform_data) { + memcpy(hd->bit_pos, pdev->dev.platform_data, + ARRAY_SIZE(hd->bit_pos)); + } else { + int i; + + for (i = 0; i < ARRAY_SIZE(hd->bit_pos); i++) + hd->bit_pos[i] = i; + } + + hd->base = (void __iomem *)res->start; + + setup_timer(&hd->timer, heartbeat_timer, (unsigned long)hd); + platform_set_drvdata(pdev, hd); + + return mod_timer(&hd->timer, jiffies + 1); +} + +static int heartbeat_drv_remove(struct platform_device *pdev) +{ + struct heartbeat_data *hd = platform_get_drvdata(pdev); + + del_timer_sync(&hd->timer); + + platform_set_drvdata(pdev, NULL); + + kfree(hd); + + return 0; +} + +static struct platform_driver heartbeat_driver = { + .probe = heartbeat_drv_probe, + .remove = heartbeat_drv_remove, + .driver = { + .name = DRV_NAME, + }, +}; + +static int __init heartbeat_init(void) +{ + printk(KERN_NOTICE DRV_NAME ": version %s loaded\n", DRV_VERSION); + return platform_driver_register(&heartbeat_driver); +} + +static void __exit heartbeat_exit(void) +{ + platform_driver_unregister(&heartbeat_driver); +} +module_init(heartbeat_init); +module_exit(heartbeat_exit); + +MODULE_VERSION(DRV_VERSION); +MODULE_AUTHOR("Paul Mundt"); +MODULE_LICENSE("GPLv2"); diff --git a/arch/sh/drivers/pci/Makefile b/arch/sh/drivers/pci/Makefile index 9e00cb8..cc8d0d0 100644 --- a/arch/sh/drivers/pci/Makefile +++ b/arch/sh/drivers/pci/Makefile @@ -12,7 +12,6 @@ obj-$(CONFIG_CPU_SUBTYPE_SH7780) += pci- obj-$(CONFIG_SH_DREAMCAST) += ops-dreamcast.o fixups-dreamcast.o \ dma-dreamcast.o obj-$(CONFIG_SH_SECUREEDGE5410) += ops-snapgear.o -obj-$(CONFIG_SH_BIGSUR) += ops-bigsur.o obj-$(CONFIG_SH_RTS7751R2D) += ops-rts7751r2d.o fixups-rts7751r2d.o obj-$(CONFIG_SH_SH03) += ops-sh03.o fixups-sh03.o obj-$(CONFIG_SH_R7780RP) += ops-r7780rp.o fixups-r7780rp.o diff --git a/arch/sh/drivers/pci/ops-bigsur.c b/arch/sh/drivers/pci/ops-bigsur.c deleted file mode 100644 index eb31be7..0000000 --- a/arch/sh/drivers/pci/ops-bigsur.c +++ /dev/null @@ -1,83 +0,0 @@ -/* - * linux/arch/sh/drivers/pci/ops-bigsur.c - * - * By Dustin McIntire (dustin@sensoria.com) (c)2001 - * - * Ported to new API by Paul Mundt . - * - * May be copied or modified under the terms of the GNU General Public - * License. See linux/COPYING for more information. - * - * PCI initialization for the Hitachi Big Sur Evaluation Board - */ -#include -#include -#include -#include -#include -#include "pci-sh4.h" -#include - -#define BIGSUR_PCI_IO 0x4000 -#define BIGSUR_PCI_MEM 0xfd000000 - -static struct resource sh7751_io_resource = { - .name = "SH7751 IO", - .start = BIGSUR_PCI_IO, - .end = BIGSUR_PCI_IO + (64*1024) - 1, - .flags = IORESOURCE_IO, -}; - -static struct resource sh7751_mem_resource = { - .name = "SH7751 mem", - .start = BIGSUR_PCI_MEM, - .end = BIGSUR_PCI_MEM + (64*1024*1024) - 1, - .flags = IORESOURCE_MEM, -}; - -extern struct pci_ops sh7751_pci_ops; - -struct pci_channel board_pci_channels[] = { - { &sh4_pci_ops, &sh7751_io_resource, &sh7751_mem_resource, 0, 0xff }, - { 0, } -}; - -static struct sh4_pci_address_map sh7751_pci_map = { - .window0 = { - .base = SH7751_CS3_BASE_ADDR, - .size = BIGSUR_LSR0_SIZE, - }, - - .window1 = { - .base = SH7751_CS3_BASE_ADDR, - .size = BIGSUR_LSR1_SIZE, - }, -}; - -/* - * Initialize the Big Sur PCI interface - * Setup hardware to be Central Funtion - * Copy the BSR regs to the PCI interface - * Setup PCI windows into local RAM - */ -int __init pcibios_init_platform(void) -{ - return sh7751_pcic_init(&sh7751_pci_map); -} - -int __init pcibios_map_platform_irq(struct pci_dev *pdev, u8 slot, u8 pin) -{ - /* - * The Big Sur can be used in a CPCI chassis, but the SH7751 PCI - * interface is on the wrong end of the board so that it can also - * support a V320 CPI interface chip... Therefor the IRQ mapping is - * somewhat use dependent... I'l assume a linear map for now, i.e. - * INTA=slot0,pin0... INTD=slot3,pin0... - */ - int irq = (slot + pin-1) % 4 + BIGSUR_SH7751_PCI_IRQ_BASE; - - PCIDBG(2, "PCI: Mapping Big Sur IRQ for slot %d, pin %c to irq %d\n", - slot, pin-1+'A', irq); - - return irq; -} diff --git a/arch/sh/drivers/pci/pci-sh7751.c b/arch/sh/drivers/pci/pci-sh7751.c index 85e1ee2..9ddff76 100644 --- a/arch/sh/drivers/pci/pci-sh7751.c +++ b/arch/sh/drivers/pci/pci-sh7751.c @@ -157,15 +157,6 @@ int __init sh7751_pcic_init(struct sh4_p PCIBIOS_MIN_IO, (64 << 10), SH7751_PCI_IO_BASE + PCIBIOS_MIN_IO); - /* - * XXX: For now, leave this board-specific. In the event we have other - * boards that need to do similar work, this can be wrapped. - */ -#ifdef CONFIG_SH_BIGSUR - bigsur_port_map(PCIBIOS_MIN_IO, (64 << 10), - SH7751_PCI_IO_BASE + PCIBIOS_MIN_IO, 0); -#endif - /* Make sure the MSB's of IO window are set to access PCI space * correctly */ word = PCIBIOS_MIN_IO & SH4_PCIIOBR_MASK; diff --git a/arch/sh/kernel/Makefile b/arch/sh/kernel/Makefile index 99c7e52..ff30d7f 100644 --- a/arch/sh/kernel/Makefile +++ b/arch/sh/kernel/Makefile @@ -6,7 +6,8 @@ extra-y := head.o init_task.o vmlinux.ld obj-y := process.o signal.o traps.o irq.o \ ptrace.o setup.o time.o sys_sh.o semaphore.o \ - io.o io_generic.o sh_ksyms.o syscalls.o + io.o io_generic.o sh_ksyms.o syscalls.o \ + debugtraps.o obj-y += cpu/ timers/ obj-$(CONFIG_VSYSCALL) += vsyscall/ @@ -19,6 +20,5 @@ obj-$(CONFIG_SH_CPU_FREQ) += cpufreq.o obj-$(CONFIG_MODULES) += module.o obj-$(CONFIG_EARLY_PRINTK) += early_printk.o obj-$(CONFIG_KEXEC) += machine_kexec.o relocate_kernel.o -obj-$(CONFIG_APM) += apm.o obj-$(CONFIG_PM) += pm.o obj-$(CONFIG_STACKTRACE) += stacktrace.o diff --git a/arch/sh/kernel/apm.c b/arch/sh/kernel/apm.c deleted file mode 100644 index 4f66f91..0000000 --- a/arch/sh/kernel/apm.c +++ /dev/null @@ -1,538 +0,0 @@ -/* - * bios-less APM driver for hp680 - * - * Copyright 2005 (c) Andriy Skulysh - * - * based on ARM APM driver by - * Jamey Hicks - * - * adapted from the APM BIOS driver for Linux by - * Stephen Rothwell (sfr@linuxcare.com) - * - * APM 1.2 Reference: - * Intel Corporation, Microsoft Corporation. Advanced Power Management - * (APM) BIOS Interface Specification, Revision 1.2, February 1996. - * - * [This document is available from Microsoft at: - * http://www.microsoft.com/hwdev/busbios/amp_12.htm] - */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#define MODNAME "apm" - -/* - * The apm_bios device is one of the misc char devices. - * This is its minor number. - */ -#define APM_MINOR_DEV 134 - -/* - * Maximum number of events stored - */ -#define APM_MAX_EVENTS 16 - -struct apm_queue { - unsigned int event_head; - unsigned int event_tail; - apm_event_t events[APM_MAX_EVENTS]; -}; - -/* - * The per-file APM data - */ -struct apm_user { - struct list_head list; - - unsigned int suser: 1; - unsigned int writer: 1; - unsigned int reader: 1; - - int suspend_result; - unsigned int suspend_state; -#define SUSPEND_NONE 0 /* no suspend pending */ -#define SUSPEND_PENDING 1 /* suspend pending read */ -#define SUSPEND_READ 2 /* suspend read, pending ack */ -#define SUSPEND_ACKED 3 /* suspend acked */ -#define SUSPEND_DONE 4 /* suspend completed */ - - struct apm_queue queue; -}; - -/* - * Local variables - */ -static int suspends_pending; - -static DECLARE_WAIT_QUEUE_HEAD(apm_waitqueue); -static DECLARE_WAIT_QUEUE_HEAD(apm_suspend_waitqueue); - -/* - * This is a list of everyone who has opened /dev/apm_bios - */ -static DECLARE_RWSEM(user_list_lock); -static LIST_HEAD(apm_user_list); - -/* - * kapmd info. kapmd provides us a process context to handle - * "APM" events within - specifically necessary if we're going - * to be suspending the system. - */ -static DECLARE_WAIT_QUEUE_HEAD(kapmd_wait); -static DECLARE_COMPLETION(kapmd_exit); -static DEFINE_SPINLOCK(kapmd_queue_lock); -static struct apm_queue kapmd_queue; - -int apm_suspended; -EXPORT_SYMBOL(apm_suspended); - -/* Platform-specific apm_read_proc(). */ -int (*apm_get_info)(char *buf, char **start, off_t fpos, int length); -EXPORT_SYMBOL(apm_get_info); - -/* - * APM event queue management. - */ -static inline int queue_empty(struct apm_queue *q) -{ - return q->event_head == q->event_tail; -} - -static inline apm_event_t queue_get_event(struct apm_queue *q) -{ - q->event_tail = (q->event_tail + 1) % APM_MAX_EVENTS; - return q->events[q->event_tail]; -} - -static void queue_add_event(struct apm_queue *q, apm_event_t event) -{ - q->event_head = (q->event_head + 1) % APM_MAX_EVENTS; - if (q->event_head == q->event_tail) { - static int notified; - - if (notified++ == 0) - printk(KERN_ERR "apm: an event queue overflowed\n"); - - q->event_tail = (q->event_tail + 1) % APM_MAX_EVENTS; - } - q->events[q->event_head] = event; -} - -static void queue_event_one_user(struct apm_user *as, apm_event_t event) -{ - if (as->suser && as->writer) { - switch (event) { - case APM_SYS_SUSPEND: - case APM_USER_SUSPEND: - /* - * If this user already has a suspend pending, - * don't queue another one. - */ - if (as->suspend_state != SUSPEND_NONE) - return; - - as->suspend_state = SUSPEND_PENDING; - suspends_pending++; - break; - } - } - queue_add_event(&as->queue, event); -} - -static void queue_event(apm_event_t event, struct apm_user *sender) -{ - struct apm_user *as; - - down_read(&user_list_lock); - - list_for_each_entry(as, &apm_user_list, list) - if (as != sender && as->reader) - queue_event_one_user(as, event); - - up_read(&user_list_lock); - wake_up_interruptible(&apm_waitqueue); -} - -/** - * apm_queue_event - queue an APM event for kapmd - * @event: APM event - * - * Queue an APM event for kapmd to process and ultimately take the - * appropriate action. Only a subset of events are handled: - * %APM_LOW_BATTERY - * %APM_POWER_STATUS_CHANGE - * %APM_USER_SUSPEND - * %APM_SYS_SUSPEND - * %APM_CRITICAL_SUSPEND - */ -void apm_queue_event(apm_event_t event) -{ - spin_lock_irq(&kapmd_queue_lock); - queue_add_event(&kapmd_queue, event); - spin_unlock_irq(&kapmd_queue_lock); - - wake_up_interruptible(&kapmd_wait); -} -EXPORT_SYMBOL(apm_queue_event); - -static void apm_suspend(void) -{ - struct apm_user *as; - int err; - - apm_suspended = 1; - err = pm_suspend(PM_SUSPEND_MEM); - - /* - * Anyone on the APM queues will think we're still suspended. - * Send a message so everyone knows we're now awake again. - */ - queue_event(APM_NORMAL_RESUME, NULL); - - /* - * Finally, wake up anyone who is sleeping on the suspend. - */ - down_read(&user_list_lock); - list_for_each_entry(as, &apm_user_list, list) { - as->suspend_result = err; - as->suspend_state = SUSPEND_DONE; - } - up_read(&user_list_lock); - - wake_up(&apm_suspend_waitqueue); - apm_suspended = 0; -} - -static ssize_t apm_read(struct file *fp, char __user *buf, - size_t count, loff_t *ppos) -{ - struct apm_user *as = fp->private_data; - apm_event_t event; - int i = count, ret = 0; - - if (count < sizeof(apm_event_t)) - return -EINVAL; - - if (queue_empty(&as->queue) && fp->f_flags & O_NONBLOCK) - return -EAGAIN; - - wait_event_interruptible(apm_waitqueue, !queue_empty(&as->queue)); - - while ((i >= sizeof(event)) && !queue_empty(&as->queue)) { - event = queue_get_event(&as->queue); - - ret = -EFAULT; - if (copy_to_user(buf, &event, sizeof(event))) - break; - - if (event == APM_SYS_SUSPEND || event == APM_USER_SUSPEND) - as->suspend_state = SUSPEND_READ; - - buf += sizeof(event); - i -= sizeof(event); - } - - if (i < count) - ret = count - i; - - return ret; -} - -static unsigned int apm_poll(struct file *fp, poll_table * wait) -{ - struct apm_user *as = fp->private_data; - - poll_wait(fp, &apm_waitqueue, wait); - return queue_empty(&as->queue) ? 0 : POLLIN | POLLRDNORM; -} - -/* - * apm_ioctl - handle APM ioctl - * - * APM_IOC_SUSPEND - * This IOCTL is overloaded, and performs two functions. It is used to: - * - initiate a suspend - * - acknowledge a suspend read from /dev/apm_bios. - * Only when everyone who has opened /dev/apm_bios with write permission - * has acknowledge does the actual suspend happen. - */ -static int -apm_ioctl(struct inode * inode, struct file *filp, u_int cmd, u_long arg) -{ - struct apm_user *as = filp->private_data; - unsigned long flags; - int err = -EINVAL; - - if (!as->suser || !as->writer) - return -EPERM; - - switch (cmd) { - case APM_IOC_SUSPEND: - as->suspend_result = -EINTR; - - if (as->suspend_state == SUSPEND_READ) { - /* - * If we read a suspend command from /dev/apm_bios, - * then the corresponding APM_IOC_SUSPEND ioctl is - * interpreted as an acknowledge. - */ - as->suspend_state = SUSPEND_ACKED; - suspends_pending--; - } else { - /* - * Otherwise it is a request to suspend the system. - * Queue an event for all readers, and expect an - * acknowledge from all writers who haven't already - * acknowledged. - */ - queue_event(APM_USER_SUSPEND, as); - } - - /* - * If there are no further acknowledges required, suspend - * the system. - */ - if (suspends_pending == 0) - apm_suspend(); - - /* - * Wait for the suspend/resume to complete. If there are - * pending acknowledges, we wait here for them. - * - * Note that we need to ensure that the PM subsystem does - * not kick us out of the wait when it suspends the threads. - */ - flags = current->flags; - current->flags |= PF_NOFREEZE; - - /* - * Note: do not allow a thread which is acking the suspend - * to escape until the resume is complete. - */ - if (as->suspend_state == SUSPEND_ACKED) - wait_event(apm_suspend_waitqueue, - as->suspend_state == SUSPEND_DONE); - else - wait_event_interruptible(apm_suspend_waitqueue, - as->suspend_state == SUSPEND_DONE); - - current->flags = flags; - err = as->suspend_result; - as->suspend_state = SUSPEND_NONE; - break; - } - - return err; -} - -static int apm_release(struct inode * inode, struct file * filp) -{ - struct apm_user *as = filp->private_data; - filp->private_data = NULL; - - down_write(&user_list_lock); - list_del(&as->list); - up_write(&user_list_lock); - - /* - * We are now unhooked from the chain. As far as new - * events are concerned, we no longer exist. However, we - * need to balance suspends_pending, which means the - * possibility of sleeping. - */ - if (as->suspend_state != SUSPEND_NONE) { - suspends_pending -= 1; - if (suspends_pending == 0) - apm_suspend(); - } - - kfree(as); - return 0; -} - -static int apm_open(struct inode * inode, struct file * filp) -{ - struct apm_user *as; - - as = kzalloc(sizeof(*as), GFP_KERNEL); - if (as) { - /* - * XXX - this is a tiny bit broken, when we consider BSD - * process accounting. If the device is opened by root, we - * instantly flag that we used superuser privs. Who knows, - * we might close the device immediately without doing a - * privileged operation -- cevans - */ - as->suser = capable(CAP_SYS_ADMIN); - as->writer = (filp->f_mode & FMODE_WRITE) == FMODE_WRITE; - as->reader = (filp->f_mode & FMODE_READ) == FMODE_READ; - - down_write(&user_list_lock); - list_add(&as->list, &apm_user_list); - up_write(&user_list_lock); - - filp->private_data = as; - } - - return as ? 0 : -ENOMEM; -} - -static struct file_operations apm_bios_fops = { - .owner = THIS_MODULE, - .read = apm_read, - .poll = apm_poll, - .ioctl = apm_ioctl, - .open = apm_open, - .release = apm_release, -}; - -static struct miscdevice apm_device = { - .minor = APM_MINOR_DEV, - .name = "apm_bios", - .fops = &apm_bios_fops -}; - - -#ifdef CONFIG_PROC_FS -/* - * Arguments, with symbols from linux/apm_bios.h. - * - * 0) Linux driver version (this will change if format changes) - * 1) APM BIOS Version. Usually 1.0, 1.1 or 1.2. - * 2) APM flags from APM Installation Check (0x00): - * bit 0: APM_16_BIT_SUPPORT - * bit 1: APM_32_BIT_SUPPORT - * bit 2: APM_IDLE_SLOWS_CLOCK - * bit 3: APM_BIOS_DISABLED - * bit 4: APM_BIOS_DISENGAGED - * 3) AC line status - * 0x00: Off-line - * 0x01: On-line - * 0x02: On backup power (BIOS >= 1.1 only) - * 0xff: Unknown - * 4) Battery status - * 0x00: High - * 0x01: Low - * 0x02: Critical - * 0x03: Charging - * 0x04: Selected battery not present (BIOS >= 1.2 only) - * 0xff: Unknown - * 5) Battery flag - * bit 0: High - * bit 1: Low - * bit 2: Critical - * bit 3: Charging - * bit 7: No system battery - * 0xff: Unknown - * 6) Remaining battery life (percentage of charge): - * 0-100: valid - * -1: Unknown - * 7) Remaining battery life (time units): - * Number of remaining minutes or seconds - * -1: Unknown - * 8) min = minutes; sec = seconds - */ -static int apm_read_proc(char *buf, char **start, off_t fpos, int length) -{ - if (likely(apm_get_info)) - return apm_get_info(buf, start, fpos, length); - - return -EINVAL; -} -#endif - -static int kapmd(void *arg) -{ - daemonize("kapmd"); - current->flags |= PF_NOFREEZE; - - do { - apm_event_t event; - - wait_event_interruptible(kapmd_wait, - !queue_empty(&kapmd_queue) || !pm_active); - - if (!pm_active) - break; - - spin_lock_irq(&kapmd_queue_lock); - event = 0; - if (!queue_empty(&kapmd_queue)) - event = queue_get_event(&kapmd_queue); - spin_unlock_irq(&kapmd_queue_lock); - - switch (event) { - case 0: - break; - - case APM_LOW_BATTERY: - case APM_POWER_STATUS_CHANGE: - queue_event(event, NULL); - break; - - case APM_USER_SUSPEND: - case APM_SYS_SUSPEND: - queue_event(event, NULL); - if (suspends_pending == 0) - apm_suspend(); - break; - - case APM_CRITICAL_SUSPEND: - apm_suspend(); - break; - } - } while (1); - - complete_and_exit(&kapmd_exit, 0); -} - -static int __init apm_init(void) -{ - int ret; - - pm_active = 1; - - ret = kernel_thread(kapmd, NULL, CLONE_KERNEL); - if (unlikely(ret < 0)) { - pm_active = 0; - return ret; - } - - create_proc_info_entry("apm", 0, NULL, apm_read_proc); - - ret = misc_register(&apm_device); - if (unlikely(ret != 0)) { - remove_proc_entry("apm", NULL); - - pm_active = 0; - wake_up(&kapmd_wait); - wait_for_completion(&kapmd_exit); - } - - return ret; -} - -static void __exit apm_exit(void) -{ - misc_deregister(&apm_device); - remove_proc_entry("apm", NULL); - - pm_active = 0; - wake_up(&kapmd_wait); - wait_for_completion(&kapmd_exit); -} - -module_init(apm_init); -module_exit(apm_exit); - -MODULE_AUTHOR("Stephen Rothwell, Andriy Skulysh"); -MODULE_DESCRIPTION("Advanced Power Management"); -MODULE_LICENSE("GPL"); diff --git a/arch/sh/kernel/cpu/init.c b/arch/sh/kernel/cpu/init.c index 4812176..4b339a6 100644 --- a/arch/sh/kernel/cpu/init.c +++ b/arch/sh/kernel/cpu/init.c @@ -3,7 +3,7 @@ * * CPU init code * - * Copyright (C) 2002, 2003 Paul Mundt + * Copyright (C) 2002 - 2006 Paul Mundt * Copyright (C) 2003 Richard Curnow * * This file is subject to the terms and conditions of the GNU General Public @@ -12,6 +12,8 @@ */ #include #include +#include +#include #include #include #include @@ -46,7 +48,7 @@ static void __init cache_init(void) { unsigned long ccr, flags; - if (cpu_data->type == CPU_SH_NONE) + if (current_cpu_data.type == CPU_SH_NONE) panic("Unknown CPU"); jump_to_P2(); @@ -66,7 +68,7 @@ static void __init cache_init(void) if (ccr & CCR_CACHE_ENABLE) { unsigned long ways, waysize, addrstart; - waysize = cpu_data->dcache.sets; + waysize = current_cpu_data.dcache.sets; #ifdef CCR_CACHE_ORA /* @@ -77,7 +79,7 @@ #ifdef CCR_CACHE_ORA waysize >>= 1; #endif - waysize <<= cpu_data->dcache.entry_shift; + waysize <<= current_cpu_data.dcache.entry_shift; #ifdef CCR_CACHE_EMODE /* If EMODE is not set, we only have 1 way to flush. */ @@ -85,7 +87,7 @@ #ifdef CCR_CACHE_EMODE ways = 1; else #endif - ways = cpu_data->dcache.ways; + ways = current_cpu_data.dcache.ways; addrstart = CACHE_OC_ADDRESS_ARRAY; do { @@ -93,10 +95,10 @@ #endif for (addr = addrstart; addr < addrstart + waysize; - addr += cpu_data->dcache.linesz) + addr += current_cpu_data.dcache.linesz) ctrl_outl(0, addr); - addrstart += cpu_data->dcache.way_incr; + addrstart += current_cpu_data.dcache.way_incr; } while (--ways); } @@ -108,7 +110,7 @@ #endif #ifdef CCR_CACHE_EMODE /* Force EMODE if possible */ - if (cpu_data->dcache.ways > 1) + if (current_cpu_data.dcache.ways > 1) flags |= CCR_CACHE_EMODE; else flags &= ~CCR_CACHE_EMODE; @@ -125,10 +127,10 @@ #endif #ifdef CONFIG_SH_OCRAM /* Turn on OCRAM -- halve the OC */ flags |= CCR_CACHE_ORA; - cpu_data->dcache.sets >>= 1; + current_cpu_data.dcache.sets >>= 1; - cpu_data->dcache.way_size = cpu_data->dcache.sets * - cpu_data->dcache.linesz; + current_cpu_data.dcache.way_size = current_cpu_data.dcache.sets * + current_cpu_data.dcache.linesz; #endif ctrl_outl(flags, CCR); @@ -170,7 +172,7 @@ static void __init dsp_init(void) /* If the DSP bit is still set, this CPU has a DSP */ if (sr & SR_DSP) - cpu_data->flags |= CPU_HAS_DSP; + current_cpu_data.flags |= CPU_HAS_DSP; /* Now that we've determined the DSP status, clear the DSP bit. */ release_dsp(); @@ -202,22 +204,28 @@ asmlinkage void __init sh_cpu_init(void) cache_init(); shm_align_mask = max_t(unsigned long, - cpu_data->dcache.way_size - 1, + current_cpu_data.dcache.way_size - 1, PAGE_SIZE - 1); /* Disable the FPU */ if (fpu_disabled) { printk("FPU Disabled\n"); - cpu_data->flags &= ~CPU_HAS_FPU; + current_cpu_data.flags &= ~CPU_HAS_FPU; disable_fpu(); } /* FPU initialization */ - if ((cpu_data->flags & CPU_HAS_FPU)) { + if ((current_cpu_data.flags & CPU_HAS_FPU)) { clear_thread_flag(TIF_USEDFPU); clear_used_math(); } + /* + * Initialize the per-CPU ASID cache very early, since the + * TLB flushing routines depend on this being setup. + */ + current_cpu_data.asid_cache = NO_CONTEXT; + #ifdef CONFIG_SH_DSP /* Probe for DSP */ dsp_init(); @@ -225,7 +233,7 @@ #ifdef CONFIG_SH_DSP /* Disable the DSP */ if (dsp_disabled) { printk("DSP Disabled\n"); - cpu_data->flags &= ~CPU_HAS_DSP; + current_cpu_data.flags &= ~CPU_HAS_DSP; release_dsp(); } #endif @@ -240,4 +248,3 @@ #ifdef CONFIG_UBC_WAKEUP ubc_wakeup(); #endif } - diff --git a/arch/sh/kernel/cpu/irq/ipr.c b/arch/sh/kernel/cpu/irq/ipr.c index 35eb575..210280b 100644 --- a/arch/sh/kernel/cpu/irq/ipr.c +++ b/arch/sh/kernel/cpu/irq/ipr.c @@ -43,16 +43,29 @@ static struct irq_chip ipr_irq_chip = { .mask_ack = disable_ipr_irq, }; +unsigned int map_ipridx_to_addr(int idx) __attribute__ ((weak)); +unsigned int map_ipridx_to_addr(int idx) +{ + return 0; +} + void make_ipr_irq(struct ipr_data *table, unsigned int nr_irqs) { int i; for (i = 0; i < nr_irqs; i++) { unsigned int irq = table[i].irq; - table[i].addr = map_ipridx_to_addr(table[i].ipr_idx); + + if (!irq) + irq = table[i].irq = i; + /* could the IPR index be mapped, if not we ignore this */ - if (table[i].addr == 0) - continue; + if (!table[i].addr) { + table[i].addr = map_ipridx_to_addr(table[i].ipr_idx); + if (!table[i].addr) + continue; + } + disable_irq_nosync(irq); set_irq_chip_and_handler_name(irq, &ipr_irq_chip, handle_level_irq, "level"); diff --git a/arch/sh/kernel/cpu/sh2/entry.S b/arch/sh/kernel/cpu/sh2/entry.S index d51fa5e..7f7d292 100644 --- a/arch/sh/kernel/cpu/sh2/entry.S +++ b/arch/sh/kernel/cpu/sh2/entry.S @@ -178,12 +178,10 @@ interrupt_entry: 8: .long do_exception_error trap_entry: - /* verbose BUG trapa entry check */ - mov #0x3e,r8 - cmp/ge r8,r9 - bf/s 1f - add #-0x10,r9 - add #0x10,r9 + mov #0x30,r8 + cmp/ge r8,r9 ! vector 0x20-0x2f is systemcall + bt 1f + add #-0x10,r9 ! convert SH2 to SH3/4 ABI 1: shll2 r9 ! TRA mov #OFF_TRA,r8 @@ -206,7 +204,7 @@ #endif #if defined(CONFIG_SH_STANDARD_BIOS) /* Unwind the stack and jmp to the debug entry */ -debug_kernel_fw: +ENTRY(sh_bios_handler) mov r15,r0 add #(22-4)*4-4,r0 ldc.l @r0+,gbr diff --git a/arch/sh/kernel/cpu/sh2/probe.c b/arch/sh/kernel/cpu/sh2/probe.c index ba527d9..108e81b 100644 --- a/arch/sh/kernel/cpu/sh2/probe.c +++ b/arch/sh/kernel/cpu/sh2/probe.c @@ -18,27 +18,27 @@ #include int __init detect_cpu_and_cache_system(void) { #if defined(CONFIG_CPU_SUBTYPE_SH7604) - cpu_data->type = CPU_SH7604; - cpu_data->dcache.ways = 4; - cpu_data->dcache.way_incr = (1<<10); - cpu_data->dcache.sets = 64; - cpu_data->dcache.entry_shift = 4; - cpu_data->dcache.linesz = L1_CACHE_BYTES; - cpu_data->dcache.flags = 0; + current_cpu_data.type = CPU_SH7604; + current_cpu_data.dcache.ways = 4; + current_cpu_data.dcache.way_incr = (1<<10); + current_cpu_data.dcache.sets = 64; + current_cpu_data.dcache.entry_shift = 4; + current_cpu_data.dcache.linesz = L1_CACHE_BYTES; + current_cpu_data.dcache.flags = 0; #elif defined(CONFIG_CPU_SUBTYPE_SH7619) - cpu_data->type = CPU_SH7619; - cpu_data->dcache.ways = 4; - cpu_data->dcache.way_incr = (1<<12); - cpu_data->dcache.sets = 256; - cpu_data->dcache.entry_shift = 4; - cpu_data->dcache.linesz = L1_CACHE_BYTES; - cpu_data->dcache.flags = 0; + current_cpu_data.type = CPU_SH7619; + current_cpu_data.dcache.ways = 4; + current_cpu_data.dcache.way_incr = (1<<12); + current_cpu_data.dcache.sets = 256; + current_cpu_data.dcache.entry_shift = 4; + current_cpu_data.dcache.linesz = L1_CACHE_BYTES; + current_cpu_data.dcache.flags = 0; #endif /* * SH-2 doesn't have separate caches */ - cpu_data->dcache.flags |= SH_CACHE_COMBINED; - cpu_data->icache = cpu_data->dcache; + current_cpu_data.dcache.flags |= SH_CACHE_COMBINED; + current_cpu_data.icache = current_cpu_data.dcache; return 0; } diff --git a/arch/sh/kernel/cpu/sh2/setup-sh7619.c b/arch/sh/kernel/cpu/sh2/setup-sh7619.c index 79283e6..f83ff8a 100644 --- a/arch/sh/kernel/cpu/sh2/setup-sh7619.c +++ b/arch/sh/kernel/cpu/sh2/setup-sh7619.c @@ -52,42 +52,38 @@ static int __init sh7619_devices_setup(v } __initcall(sh7619_devices_setup); -#define INTC_IPRC 0xf8080000UL -#define INTC_IPRD 0xf8080002UL - -#define CMI0_IRQ 86 - -#define SCIF0_ERI_IRQ 88 -#define SCIF0_RXI_IRQ 89 -#define SCIF0_BRI_IRQ 90 -#define SCIF0_TXI_IRQ 91 - -#define SCIF1_ERI_IRQ 92 -#define SCIF1_RXI_IRQ 93 -#define SCIF1_BRI_IRQ 94 -#define SCIF1_TXI_IRQ 95 - -#define SCIF2_BRI_IRQ 96 -#define SCIF2_ERI_IRQ 97 -#define SCIF2_RXI_IRQ 98 -#define SCIF2_TXI_IRQ 99 - static struct ipr_data sh7619_ipr_map[] = { - { CMI0_IRQ, INTC_IPRC, 1, 2 }, - { SCIF0_ERI_IRQ, INTC_IPRD, 3, 3 }, - { SCIF0_RXI_IRQ, INTC_IPRD, 3, 3 }, - { SCIF0_BRI_IRQ, INTC_IPRD, 3, 3 }, - { SCIF0_TXI_IRQ, INTC_IPRD, 3, 3 }, - { SCIF1_ERI_IRQ, INTC_IPRD, 2, 3 }, - { SCIF1_RXI_IRQ, INTC_IPRD, 2, 3 }, - { SCIF1_BRI_IRQ, INTC_IPRD, 2, 3 }, - { SCIF1_TXI_IRQ, INTC_IPRD, 2, 3 }, - { SCIF2_ERI_IRQ, INTC_IPRD, 1, 3 }, - { SCIF2_RXI_IRQ, INTC_IPRD, 1, 3 }, - { SCIF2_BRI_IRQ, INTC_IPRD, 1, 3 }, - { SCIF2_TXI_IRQ, INTC_IPRD, 1, 3 }, + { 86, 0, 4, 2 }, /* CMI0 */ + { 88, 1, 12, 3 }, /* SCIF0_ERI */ + { 89, 1, 12, 3 }, /* SCIF0_RXI */ + { 90, 1, 12, 3 }, /* SCIF0_BRI */ + { 91, 1, 12, 3 }, /* SCIF0_TXI */ + { 92, 1, 8, 3 }, /* SCIF1_ERI */ + { 93, 1, 8, 3 }, /* SCIF1_RXI */ + { 94, 1, 8, 3 }, /* SCIF1_BRI */ + { 95, 1, 8, 3 }, /* SCIF1_TXI */ + { 96, 1, 4, 3 }, /* SCIF2_ERI */ + { 97, 1, 4, 3 }, /* SCIF2_RXI */ + { 98, 1, 4, 3 }, /* SCIF2_BRI */ + { 99, 1, 4, 3 }, /* SCIF2_TXI */ }; +static unsigned int ipr_offsets[] = { + 0xf8080000, /* IPRC */ + 0xf8080002, /* IPRD */ + 0xf8080004, /* IPRE */ + 0xf8080006, /* IPRF */ + 0xf8080008, /* IPRG */ +}; + +/* given the IPR index return the address of the IPR register */ +unsigned int map_ipridx_to_addr(int idx) +{ + if (unlikely(idx >= ARRAY_SIZE(ipr_offsets))) + return 0; + return ipr_offsets[idx]; +} + void __init init_IRQ_ipr(void) { make_ipr_irq(sh7619_ipr_map, ARRAY_SIZE(sh7619_ipr_map)); diff --git a/arch/sh/kernel/cpu/sh2a/probe.c b/arch/sh/kernel/cpu/sh2a/probe.c index 87c6c05..426f6db 100644 --- a/arch/sh/kernel/cpu/sh2a/probe.c +++ b/arch/sh/kernel/cpu/sh2a/probe.c @@ -17,14 +17,14 @@ #include int __init detect_cpu_and_cache_system(void) { /* Just SH7206 for now .. */ - cpu_data->type = CPU_SH7206; + current_cpu_data.type = CPU_SH7206; - cpu_data->dcache.ways = 4; - cpu_data->dcache.way_incr = (1 << 11); - cpu_data->dcache.sets = 128; - cpu_data->dcache.entry_shift = 4; - cpu_data->dcache.linesz = L1_CACHE_BYTES; - cpu_data->dcache.flags = 0; + current_cpu_data.dcache.ways = 4; + current_cpu_data.dcache.way_incr = (1 << 11); + current_cpu_data.dcache.sets = 128; + current_cpu_data.dcache.entry_shift = 4; + current_cpu_data.dcache.linesz = L1_CACHE_BYTES; + current_cpu_data.dcache.flags = 0; /* * The icache is the same as the dcache as far as this setup is @@ -32,7 +32,7 @@ int __init detect_cpu_and_cache_system(v * lacks the U bit that the dcache has, none of this has any bearing * on the cache info. */ - cpu_data->icache = cpu_data->dcache; + current_cpu_data.icache = current_cpu_data.dcache; return 0; } diff --git a/arch/sh/kernel/cpu/sh2a/setup-sh7206.c b/arch/sh/kernel/cpu/sh2a/setup-sh7206.c index 4b60fcc..4ed9110 100644 --- a/arch/sh/kernel/cpu/sh2a/setup-sh7206.c +++ b/arch/sh/kernel/cpu/sh2a/setup-sh7206.c @@ -57,55 +57,52 @@ static int __init sh7206_devices_setup(v } __initcall(sh7206_devices_setup); -#define INTC_IPR08 0xfffe0c04UL -#define INTC_IPR09 0xfffe0c06UL -#define INTC_IPR14 0xfffe0c10UL - -#define CMI0_IRQ 140 - -#define MTU1_TGI1A 164 - -#define SCIF0_BRI_IRQ 240 -#define SCIF0_ERI_IRQ 241 -#define SCIF0_RXI_IRQ 242 -#define SCIF0_TXI_IRQ 243 - -#define SCIF1_BRI_IRQ 244 -#define SCIF1_ERI_IRQ 245 -#define SCIF1_RXI_IRQ 246 -#define SCIF1_TXI_IRQ 247 - -#define SCIF2_BRI_IRQ 248 -#define SCIF2_ERI_IRQ 249 -#define SCIF2_RXI_IRQ 250 -#define SCIF2_TXI_IRQ 251 - -#define SCIF3_BRI_IRQ 252 -#define SCIF3_ERI_IRQ 253 -#define SCIF3_RXI_IRQ 254 -#define SCIF3_TXI_IRQ 255 - static struct ipr_data sh7206_ipr_map[] = { - { CMI0_IRQ, INTC_IPR08, 3, 2 }, - { MTU2_TGI1A, INTC_IPR09, 1, 2 }, - { SCIF0_ERI_IRQ, INTC_IPR14, 3, 3 }, - { SCIF0_RXI_IRQ, INTC_IPR14, 3, 3 }, - { SCIF0_BRI_IRQ, INTC_IPR14, 3, 3 }, - { SCIF0_TXI_IRQ, INTC_IPR14, 3, 3 }, - { SCIF1_ERI_IRQ, INTC_IPR14, 2, 3 }, - { SCIF1_RXI_IRQ, INTC_IPR14, 2, 3 }, - { SCIF1_BRI_IRQ, INTC_IPR14, 2, 3 }, - { SCIF1_TXI_IRQ, INTC_IPR14, 2, 3 }, - { SCIF2_ERI_IRQ, INTC_IPR14, 1, 3 }, - { SCIF2_RXI_IRQ, INTC_IPR14, 1, 3 }, - { SCIF2_BRI_IRQ, INTC_IPR14, 1, 3 }, - { SCIF2_TXI_IRQ, INTC_IPR14, 1, 3 }, - { SCIF3_ERI_IRQ, INTC_IPR14, 0, 3 }, - { SCIF3_RXI_IRQ, INTC_IPR14, 0, 3 }, - { SCIF3_BRI_IRQ, INTC_IPR14, 0, 3 }, - { SCIF3_TXI_IRQ, INTC_IPR14, 0, 3 }, + { 140, 7, 12, 2 }, /* CMI0 */ + { 164, 8, 4, 2 }, /* MTU2_TGI1A */ + { 240, 13, 12, 3 }, /* SCIF0_BRI */ + { 241, 13, 12, 3 }, /* SCIF0_ERI */ + { 242, 13, 12, 3 }, /* SCIF0_RXI */ + { 243, 13, 12, 3 }, /* SCIF0_TXI */ + { 244, 13, 8, 3 }, /* SCIF1_BRI */ + { 245, 13, 8, 3 }, /* SCIF1_ERI */ + { 246, 13, 8, 3 }, /* SCIF1_RXI */ + { 247, 13, 8, 3 }, /* SCIF1_TXI */ + { 248, 13, 4, 3 }, /* SCIF2_BRI */ + { 249, 13, 4, 3 }, /* SCIF2_ERI */ + { 250, 13, 4, 3 }, /* SCIF2_RXI */ + { 251, 13, 4, 3 }, /* SCIF2_TXI */ + { 252, 13, 0, 3 }, /* SCIF3_BRI */ + { 253, 13, 0, 3 }, /* SCIF3_ERI */ + { 254, 13, 0, 3 }, /* SCIF3_RXI */ + { 255, 13, 0, 3 }, /* SCIF3_TXI */ +}; + +static unsigned int ipr_offsets[] = { + 0xfffe0818, /* IPR01 */ + 0xfffe081a, /* IPR02 */ + 0, /* unused */ + 0, /* unused */ + 0xfffe0820, /* IPR05 */ + 0xfffe0c00, /* IPR06 */ + 0xfffe0c02, /* IPR07 */ + 0xfffe0c04, /* IPR08 */ + 0xfffe0c06, /* IPR09 */ + 0xfffe0c08, /* IPR10 */ + 0xfffe0c0a, /* IPR11 */ + 0xfffe0c0c, /* IPR12 */ + 0xfffe0c0e, /* IPR13 */ + 0xfffe0c10, /* IPR14 */ }; +/* given the IPR index return the address of the IPR register */ +unsigned int map_ipridx_to_addr(int idx) +{ + if (unlikely(idx >= ARRAY_SIZE(ipr_offsets))) + return 0; + return ipr_offsets[idx]; +} + void __init init_IRQ_ipr(void) { make_ipr_irq(sh7206_ipr_map, ARRAY_SIZE(sh7206_ipr_map)); diff --git a/arch/sh/kernel/cpu/sh3/entry.S b/arch/sh/kernel/cpu/sh3/entry.S index 8c0dc27..c19205b 100644 --- a/arch/sh/kernel/cpu/sh3/entry.S +++ b/arch/sh/kernel/cpu/sh3/entry.S @@ -13,10 +13,8 @@ #include #include #include #include -#include #include -#include -#include +#include ! NOTE: ! GNU as (as of 2.9.1) changes bf/s into bt/s and bra, when the address @@ -138,14 +136,29 @@ ENTRY(tlb_protection_violation_store) call_dpf: mov.l 1f, r0 - mov.l @r0, r6 ! address + mov r5, r8 + mov.l @r0, r6 + mov r6, r9 + mov.l 2f, r0 + sts pr, r10 + jsr @r0 + mov r15, r4 + ! + tst r0, r0 + bf/s 0f + lds r10, pr + rts + nop +0: sti mov.l 3f, r0 - + mov r9, r6 + mov r8, r5 jmp @r0 - mov r15, r4 ! regs + mov r15, r4 .align 2 1: .long MMU_TEA +2: .long __do_page_fault 3: .long do_page_fault .align 2 @@ -173,7 +186,7 @@ #endif /* CONFIG_MMU */ #if defined(CONFIG_SH_STANDARD_BIOS) /* Unwind the stack and jmp to the debug entry */ -debug_kernel_fw: +ENTRY(sh_bios_handler) mov.l @r15+, r0 mov.l @r15+, r1 mov.l @r15+, r2 @@ -332,175 +345,9 @@ general_exception: ! ! -/* This code makes some assumptions to improve performance. - * Make sure they are stil true. */ -#if PTRS_PER_PGD != PTRS_PER_PTE -#error PGD and PTE sizes don't match -#endif - -/* gas doesn't flag impossible values for mov #immediate as an error */ -#if (_PAGE_PRESENT >> 2) > 0x7f -#error cannot load PAGE_PRESENT as an immediate -#endif -#if _PAGE_DIRTY > 0x7f -#error cannot load PAGE_DIRTY as an immediate -#endif -#if (_PAGE_PRESENT << 2) != _PAGE_ACCESSED -#error cannot derive PAGE_ACCESSED from PAGE_PRESENT -#endif - -#if defined(CONFIG_CPU_SH4) -#define ldmmupteh(r) mov.l 8f, r -#else -#define ldmmupteh(r) mov #MMU_PTEH, r -#endif - .balign 1024,0,1024 tlb_miss: -#ifdef COUNT_EXCEPTIONS - ! Increment the counts - mov.l 9f, k1 - mov.l @k1, k2 - add #1, k2 - mov.l k2, @k1 -#endif - - ! k0 scratch - ! k1 pgd and pte pointers - ! k2 faulting address - ! k3 pgd and pte index masks - ! k4 shift - - ! Load up the pgd entry (k1) - - ldmmupteh(k0) ! 9 LS (latency=2) MMU_PTEH - - mov.w 4f, k3 ! 8 LS (latency=2) (PTRS_PER_PGD-1) << 2 - mov #-(PGDIR_SHIFT-2), k4 ! 6 EX - - mov.l @(MMU_TEA-MMU_PTEH,k0), k2 ! 18 LS (latency=2) - - mov.l @(MMU_TTB-MMU_PTEH,k0), k1 ! 18 LS (latency=2) - - mov k2, k0 ! 5 MT (latency=0) - shld k4, k0 ! 99 EX - - and k3, k0 ! 78 EX - - mov.l @(k0, k1), k1 ! 21 LS (latency=2) - mov #-(PAGE_SHIFT-2), k4 ! 6 EX - - ! Load up the pte entry (k2) - - mov k2, k0 ! 5 MT (latency=0) - shld k4, k0 ! 99 EX - - tst k1, k1 ! 86 MT - - bt 20f ! 110 BR - - and k3, k0 ! 78 EX - mov.w 5f, k4 ! 8 LS (latency=2) _PAGE_PRESENT - - mov.l @(k0, k1), k2 ! 21 LS (latency=2) - add k0, k1 ! 49 EX - -#ifdef CONFIG_CPU_HAS_PTEA - ! Test the entry for present and _PAGE_ACCESSED - - mov #-28, k3 ! 6 EX - mov k2, k0 ! 5 MT (latency=0) - - tst k4, k2 ! 68 MT - shld k3, k0 ! 99 EX - - bt 20f ! 110 BR - - ! Set PTEA register - ! MMU_PTEA = ((pteval >> 28) & 0xe) | (pteval & 0x1) - ! - ! k0=pte>>28, k1=pte*, k2=pte, k3=, k4=_PAGE_PRESENT - - and #0xe, k0 ! 79 EX - - mov k0, k3 ! 5 MT (latency=0) - mov k2, k0 ! 5 MT (latency=0) - - and #1, k0 ! 79 EX - - or k0, k3 ! 82 EX - - ldmmupteh(k0) ! 9 LS (latency=2) - shll2 k4 ! 101 EX _PAGE_ACCESSED - - tst k4, k2 ! 68 MT - - mov.l k3, @(MMU_PTEA-MMU_PTEH,k0) ! 27 LS - - mov.l 7f, k3 ! 9 LS (latency=2) _PAGE_FLAGS_HARDWARE_MASK - - ! k0=MMU_PTEH, k1=pte*, k2=pte, k3=_PAGE_FLAGS_HARDWARE, k4=_PAGE_ACCESSED -#else - - ! Test the entry for present and _PAGE_ACCESSED - - mov.l 7f, k3 ! 9 LS (latency=2) _PAGE_FLAGS_HARDWARE_MASK - tst k4, k2 ! 68 MT - - shll2 k4 ! 101 EX _PAGE_ACCESSED - ldmmupteh(k0) ! 9 LS (latency=2) - - bt 20f ! 110 BR - tst k4, k2 ! 68 MT - - ! k0=MMU_PTEH, k1=pte*, k2=pte, k3=_PAGE_FLAGS_HARDWARE, k4=_PAGE_ACCESSED - -#endif - - ! Set up the entry - - and k2, k3 ! 78 EX - bt/s 10f ! 108 BR - - mov.l k3, @(MMU_PTEL-MMU_PTEH,k0) ! 27 LS - - ldtlb ! 128 CO - - ! At least one instruction between ldtlb and rte - nop ! 119 NOP - - rte ! 126 CO - - nop ! 119 NOP - - -10: or k4, k2 ! 82 EX - - ldtlb ! 128 CO - - ! At least one instruction between ldtlb and rte - mov.l k2, @k1 ! 27 LS - - rte ! 126 CO - - ! Note we cannot execute mov here, because it is executed after - ! restoring SSR, so would be executed in user space. - nop ! 119 NOP - - - .align 5 - ! Once cache line if possible... -1: .long swapper_pg_dir -4: .short (PTRS_PER_PGD-1) << 2 -5: .short _PAGE_PRESENT -7: .long _PAGE_FLAGS_HARDWARE_MASK -8: .long MMU_PTEH -#ifdef COUNT_EXCEPTIONS -9: .long exception_count_miss -#endif - - ! Either pgd or pte not present -20: mov.l 1f, k2 + mov.l 1f, k2 mov.l 4f, k3 bra handle_exception mov.l @k2, k2 @@ -651,15 +498,6 @@ #endif bf interrupt_exception shlr2 r8 shlr r8 - -#ifdef COUNT_EXCEPTIONS - mov.l 5f, r9 - add r8, r9 - mov.l @r9, r10 - add #1, r10 - mov.l r10, @r9 -#endif - mov.l 4f, r9 add r8, r9 mov.l @r9, r9 @@ -673,9 +511,6 @@ #endif 2: .long 0x000080f0 ! FD=1, IMASK=15 3: .long 0xcfffffff ! RB=0, BL=0 4: .long exception_handling_table -#ifdef COUNT_EXCEPTIONS -5: .long exception_count_table -#endif interrupt_exception: mov.l 1f, r9 diff --git a/arch/sh/kernel/cpu/sh3/probe.c b/arch/sh/kernel/cpu/sh3/probe.c index e670988..821b0ab 100644 --- a/arch/sh/kernel/cpu/sh3/probe.c +++ b/arch/sh/kernel/cpu/sh3/probe.c @@ -50,41 +50,41 @@ int __init detect_cpu_and_cache_system(v back_to_P1(); - cpu_data->dcache.ways = 4; - cpu_data->dcache.entry_shift = 4; - cpu_data->dcache.linesz = L1_CACHE_BYTES; - cpu_data->dcache.flags = 0; + current_cpu_data.dcache.ways = 4; + current_cpu_data.dcache.entry_shift = 4; + current_cpu_data.dcache.linesz = L1_CACHE_BYTES; + current_cpu_data.dcache.flags = 0; /* * 7709A/7729 has 16K cache (256-entry), while 7702 has only * 2K(direct) 7702 is not supported (yet) */ if (data0 == data1 && data2 == data3) { /* Shadow */ - cpu_data->dcache.way_incr = (1 << 11); - cpu_data->dcache.entry_mask = 0x7f0; - cpu_data->dcache.sets = 128; - cpu_data->type = CPU_SH7708; + current_cpu_data.dcache.way_incr = (1 << 11); + current_cpu_data.dcache.entry_mask = 0x7f0; + current_cpu_data.dcache.sets = 128; + current_cpu_data.type = CPU_SH7708; - cpu_data->flags |= CPU_HAS_MMU_PAGE_ASSOC; + current_cpu_data.flags |= CPU_HAS_MMU_PAGE_ASSOC; } else { /* 7709A or 7729 */ - cpu_data->dcache.way_incr = (1 << 12); - cpu_data->dcache.entry_mask = 0xff0; - cpu_data->dcache.sets = 256; - cpu_data->type = CPU_SH7729; + current_cpu_data.dcache.way_incr = (1 << 12); + current_cpu_data.dcache.entry_mask = 0xff0; + current_cpu_data.dcache.sets = 256; + current_cpu_data.type = CPU_SH7729; #if defined(CONFIG_CPU_SUBTYPE_SH7706) - cpu_data->type = CPU_SH7706; + current_cpu_data.type = CPU_SH7706; #endif #if defined(CONFIG_CPU_SUBTYPE_SH7710) - cpu_data->type = CPU_SH7710; + current_cpu_data.type = CPU_SH7710; #endif #if defined(CONFIG_CPU_SUBTYPE_SH7705) - cpu_data->type = CPU_SH7705; + current_cpu_data.type = CPU_SH7705; #if defined(CONFIG_SH7705_CACHE_32KB) - cpu_data->dcache.way_incr = (1 << 13); - cpu_data->dcache.entry_mask = 0x1ff0; - cpu_data->dcache.sets = 512; + current_cpu_data.dcache.way_incr = (1 << 13); + current_cpu_data.dcache.entry_mask = 0x1ff0; + current_cpu_data.dcache.sets = 512; ctrl_outl(CCR_CACHE_32KB, CCR3); #else ctrl_outl(CCR_CACHE_16KB, CCR3); @@ -95,8 +95,8 @@ #endif /* * SH-3 doesn't have separate caches */ - cpu_data->dcache.flags |= SH_CACHE_COMBINED; - cpu_data->icache = cpu_data->dcache; + current_cpu_data.dcache.flags |= SH_CACHE_COMBINED; + current_cpu_data.icache = current_cpu_data.dcache; return 0; } diff --git a/arch/sh/kernel/cpu/sh3/setup-sh7709.c b/arch/sh/kernel/cpu/sh3/setup-sh7709.c index ff43ef2..dc9b211 100644 --- a/arch/sh/kernel/cpu/sh3/setup-sh7709.c +++ b/arch/sh/kernel/cpu/sh3/setup-sh7709.c @@ -51,3 +51,24 @@ static int __init sh7709_devices_setup(v ARRAY_SIZE(sh7709_devices)); } __initcall(sh7709_devices_setup); + +#define IPRx(A,N) .addr=A, .shift=0*N*-1 +#define IPRA(N) IPRx(0xfffffee2UL,N) +#define IPRB(N) IPRx(0xfffffee4UL,N) +#define IPRE(N) IPRx(0xa400001aUL,N) + +static struct ipr_data sh7709_ipr_map[] = { + [16] = { IPRA(15-12), 2 }, /* TMU TUNI0 */ + [17] = { IPRA(11-8), 4 }, /* TMU TUNI1 */ + [22] = { IPRA(3-0), 2 }, /* RTC CUI */ + [23 ... 26] = { IPRB(7-4), 3 }, /* SCI */ + [27] = { IPRB(15-12), 2 }, /* WDT ITI */ + [48 ... 51] = { IPRE(15-12), 7 }, /* DMA */ + [52 ... 55] = { IPRE(11-8), 3 }, /* IRDA */ + [56 ... 59] = { IPRE(7-4), 3 }, /* SCIF */ +}; + +void __init init_IRQ_ipr() +{ + make_ipr_irq(sh7709_ipr_map, ARRAY_SIZE(sh7709_ipr_map)); +} diff --git a/arch/sh/kernel/cpu/sh4/probe.c b/arch/sh/kernel/cpu/sh4/probe.c index 9031a22..9d28c88 100644 --- a/arch/sh/kernel/cpu/sh4/probe.c +++ b/arch/sh/kernel/cpu/sh4/probe.c @@ -10,11 +10,10 @@ * License. See the file "COPYING" in the main directory of this archive * for more details. */ - #include +#include #include #include -#include int __init detect_cpu_and_cache_system(void) { @@ -36,20 +35,20 @@ int __init detect_cpu_and_cache_system(v /* * Setup some sane SH-4 defaults for the icache */ - cpu_data->icache.way_incr = (1 << 13); - cpu_data->icache.entry_shift = 5; - cpu_data->icache.sets = 256; - cpu_data->icache.ways = 1; - cpu_data->icache.linesz = L1_CACHE_BYTES; + current_cpu_data.icache.way_incr = (1 << 13); + current_cpu_data.icache.entry_shift = 5; + current_cpu_data.icache.sets = 256; + current_cpu_data.icache.ways = 1; + current_cpu_data.icache.linesz = L1_CACHE_BYTES; /* * And again for the dcache .. */ - cpu_data->dcache.way_incr = (1 << 14); - cpu_data->dcache.entry_shift = 5; - cpu_data->dcache.sets = 512; - cpu_data->dcache.ways = 1; - cpu_data->dcache.linesz = L1_CACHE_BYTES; + current_cpu_data.dcache.way_incr = (1 << 14); + current_cpu_data.dcache.entry_shift = 5; + current_cpu_data.dcache.sets = 512; + current_cpu_data.dcache.ways = 1; + current_cpu_data.dcache.linesz = L1_CACHE_BYTES; /* * Setup some generic flags we can probe @@ -57,16 +56,16 @@ int __init detect_cpu_and_cache_system(v */ if (((pvr >> 16) & 0xff) == 0x10) { if ((cvr & 0x02000000) == 0) - cpu_data->flags |= CPU_HAS_L2_CACHE; + current_cpu_data.flags |= CPU_HAS_L2_CACHE; if ((cvr & 0x10000000) == 0) - cpu_data->flags |= CPU_HAS_DSP; + current_cpu_data.flags |= CPU_HAS_DSP; - cpu_data->flags |= CPU_HAS_LLSC; + current_cpu_data.flags |= CPU_HAS_LLSC; } /* FPU detection works for everyone */ if ((cvr & 0x20000000) == 1) - cpu_data->flags |= CPU_HAS_FPU; + current_cpu_data.flags |= CPU_HAS_FPU; /* Mask off the upper chip ID */ pvr &= 0xffff; @@ -77,151 +76,151 @@ int __init detect_cpu_and_cache_system(v */ switch (pvr) { case 0x205: - cpu_data->type = CPU_SH7750; - cpu_data->flags |= CPU_HAS_P2_FLUSH_BUG | CPU_HAS_FPU | + current_cpu_data.type = CPU_SH7750; + current_cpu_data.flags |= CPU_HAS_P2_FLUSH_BUG | CPU_HAS_FPU | CPU_HAS_PERF_COUNTER; break; case 0x206: - cpu_data->type = CPU_SH7750S; - cpu_data->flags |= CPU_HAS_P2_FLUSH_BUG | CPU_HAS_FPU | + current_cpu_data.type = CPU_SH7750S; + current_cpu_data.flags |= CPU_HAS_P2_FLUSH_BUG | CPU_HAS_FPU | CPU_HAS_PERF_COUNTER; break; case 0x1100: - cpu_data->type = CPU_SH7751; - cpu_data->flags |= CPU_HAS_FPU; + current_cpu_data.type = CPU_SH7751; + current_cpu_data.flags |= CPU_HAS_FPU; break; case 0x2000: - cpu_data->type = CPU_SH73180; - cpu_data->icache.ways = 4; - cpu_data->dcache.ways = 4; - cpu_data->flags |= CPU_HAS_LLSC; + current_cpu_data.type = CPU_SH73180; + current_cpu_data.icache.ways = 4; + current_cpu_data.dcache.ways = 4; + current_cpu_data.flags |= CPU_HAS_LLSC; break; case 0x2001: case 0x2004: - cpu_data->type = CPU_SH7770; - cpu_data->icache.ways = 4; - cpu_data->dcache.ways = 4; + current_cpu_data.type = CPU_SH7770; + current_cpu_data.icache.ways = 4; + current_cpu_data.dcache.ways = 4; - cpu_data->flags |= CPU_HAS_FPU | CPU_HAS_LLSC; + current_cpu_data.flags |= CPU_HAS_FPU | CPU_HAS_LLSC; break; case 0x2006: case 0x200A: if (prr == 0x61) - cpu_data->type = CPU_SH7781; + current_cpu_data.type = CPU_SH7781; else - cpu_data->type = CPU_SH7780; + current_cpu_data.type = CPU_SH7780; - cpu_data->icache.ways = 4; - cpu_data->dcache.ways = 4; + current_cpu_data.icache.ways = 4; + current_cpu_data.dcache.ways = 4; - cpu_data->flags |= CPU_HAS_FPU | CPU_HAS_PERF_COUNTER | + current_cpu_data.flags |= CPU_HAS_FPU | CPU_HAS_PERF_COUNTER | CPU_HAS_LLSC; break; case 0x3000: case 0x3003: case 0x3009: - cpu_data->type = CPU_SH7343; - cpu_data->icache.ways = 4; - cpu_data->dcache.ways = 4; - cpu_data->flags |= CPU_HAS_LLSC; + current_cpu_data.type = CPU_SH7343; + current_cpu_data.icache.ways = 4; + current_cpu_data.dcache.ways = 4; + current_cpu_data.flags |= CPU_HAS_LLSC; break; case 0x3008: if (prr == 0xa0) { - cpu_data->type = CPU_SH7722; - cpu_data->icache.ways = 4; - cpu_data->dcache.ways = 4; - cpu_data->flags |= CPU_HAS_LLSC; + current_cpu_data.type = CPU_SH7722; + current_cpu_data.icache.ways = 4; + current_cpu_data.dcache.ways = 4; + current_cpu_data.flags |= CPU_HAS_LLSC; } break; case 0x8000: - cpu_data->type = CPU_ST40RA; - cpu_data->flags |= CPU_HAS_FPU; + current_cpu_data.type = CPU_ST40RA; + current_cpu_data.flags |= CPU_HAS_FPU; break; case 0x8100: - cpu_data->type = CPU_ST40GX1; - cpu_data->flags |= CPU_HAS_FPU; + current_cpu_data.type = CPU_ST40GX1; + current_cpu_data.flags |= CPU_HAS_FPU; break; case 0x700: - cpu_data->type = CPU_SH4_501; - cpu_data->icache.ways = 2; - cpu_data->dcache.ways = 2; + current_cpu_data.type = CPU_SH4_501; + current_cpu_data.icache.ways = 2; + current_cpu_data.dcache.ways = 2; break; case 0x600: - cpu_data->type = CPU_SH4_202; - cpu_data->icache.ways = 2; - cpu_data->dcache.ways = 2; - cpu_data->flags |= CPU_HAS_FPU; + current_cpu_data.type = CPU_SH4_202; + current_cpu_data.icache.ways = 2; + current_cpu_data.dcache.ways = 2; + current_cpu_data.flags |= CPU_HAS_FPU; break; case 0x500 ... 0x501: switch (prr) { case 0x10: - cpu_data->type = CPU_SH7750R; + current_cpu_data.type = CPU_SH7750R; break; case 0x11: - cpu_data->type = CPU_SH7751R; + current_cpu_data.type = CPU_SH7751R; break; case 0x50 ... 0x5f: - cpu_data->type = CPU_SH7760; + current_cpu_data.type = CPU_SH7760; break; } - cpu_data->icache.ways = 2; - cpu_data->dcache.ways = 2; + current_cpu_data.icache.ways = 2; + current_cpu_data.dcache.ways = 2; - cpu_data->flags |= CPU_HAS_FPU; + current_cpu_data.flags |= CPU_HAS_FPU; break; default: - cpu_data->type = CPU_SH_NONE; + current_cpu_data.type = CPU_SH_NONE; break; } #ifdef CONFIG_SH_DIRECT_MAPPED - cpu_data->icache.ways = 1; - cpu_data->dcache.ways = 1; + current_cpu_data.icache.ways = 1; + current_cpu_data.dcache.ways = 1; #endif #ifdef CONFIG_CPU_HAS_PTEA - cpu_data->flags |= CPU_HAS_PTEA; + current_cpu_data.flags |= CPU_HAS_PTEA; #endif /* * On anything that's not a direct-mapped cache, look to the CVR * for I/D-cache specifics. */ - if (cpu_data->icache.ways > 1) { + if (current_cpu_data.icache.ways > 1) { size = sizes[(cvr >> 20) & 0xf]; - cpu_data->icache.way_incr = (size >> 1); - cpu_data->icache.sets = (size >> 6); + current_cpu_data.icache.way_incr = (size >> 1); + current_cpu_data.icache.sets = (size >> 6); } /* Setup the rest of the I-cache info */ - cpu_data->icache.entry_mask = cpu_data->icache.way_incr - - cpu_data->icache.linesz; + current_cpu_data.icache.entry_mask = current_cpu_data.icache.way_incr - + current_cpu_data.icache.linesz; - cpu_data->icache.way_size = cpu_data->icache.sets * - cpu_data->icache.linesz; + current_cpu_data.icache.way_size = current_cpu_data.icache.sets * + current_cpu_data.icache.linesz; /* And the rest of the D-cache */ - if (cpu_data->dcache.ways > 1) { + if (current_cpu_data.dcache.ways > 1) { size = sizes[(cvr >> 16) & 0xf]; - cpu_data->dcache.way_incr = (size >> 1); - cpu_data->dcache.sets = (size >> 6); + current_cpu_data.dcache.way_incr = (size >> 1); + current_cpu_data.dcache.sets = (size >> 6); } - cpu_data->dcache.entry_mask = cpu_data->dcache.way_incr - - cpu_data->dcache.linesz; + current_cpu_data.dcache.entry_mask = current_cpu_data.dcache.way_incr - + current_cpu_data.dcache.linesz; - cpu_data->dcache.way_size = cpu_data->dcache.sets * - cpu_data->dcache.linesz; + current_cpu_data.dcache.way_size = current_cpu_data.dcache.sets * + current_cpu_data.dcache.linesz; /* * Setup the L2 cache desc * * SH-4A's have an optional PIPT L2. */ - if (cpu_data->flags & CPU_HAS_L2_CACHE) { + if (current_cpu_data.flags & CPU_HAS_L2_CACHE) { /* * Size calculation is much more sensible * than it is for the L1. @@ -232,16 +231,22 @@ #endif BUG_ON(!size); - cpu_data->scache.way_incr = (1 << 16); - cpu_data->scache.entry_shift = 5; - cpu_data->scache.ways = 4; - cpu_data->scache.linesz = L1_CACHE_BYTES; - cpu_data->scache.entry_mask = - (cpu_data->scache.way_incr - cpu_data->scache.linesz); - cpu_data->scache.sets = size / - (cpu_data->scache.linesz * cpu_data->scache.ways); - cpu_data->scache.way_size = - (cpu_data->scache.sets * cpu_data->scache.linesz); + current_cpu_data.scache.way_incr = (1 << 16); + current_cpu_data.scache.entry_shift = 5; + current_cpu_data.scache.ways = 4; + current_cpu_data.scache.linesz = L1_CACHE_BYTES; + + current_cpu_data.scache.entry_mask = + (current_cpu_data.scache.way_incr - + current_cpu_data.scache.linesz); + + current_cpu_data.scache.sets = size / + (current_cpu_data.scache.linesz * + current_cpu_data.scache.ways); + + current_cpu_data.scache.way_size = + (current_cpu_data.scache.sets * + current_cpu_data.scache.linesz); } return 0; diff --git a/arch/sh/kernel/cpu/sh4/setup-sh7750.c b/arch/sh/kernel/cpu/sh4/setup-sh7750.c index cbac276..6f8f458 100644 --- a/arch/sh/kernel/cpu/sh4/setup-sh7750.c +++ b/arch/sh/kernel/cpu/sh4/setup-sh7750.c @@ -46,11 +46,13 @@ static struct platform_device rtc_device static struct plat_sci_port sci_platform_data[] = { { +#ifndef CONFIG_SH_RTS7751R2D .mapbase = 0xffe00000, .flags = UPF_BOOT_AUTOCONF, .type = PORT_SCI, .irqs = { 23, 24, 25, 0 }, }, { +#endif .mapbase = 0xffe80000, .flags = UPF_BOOT_AUTOCONF, .type = PORT_SCIF, @@ -101,7 +103,7 @@ static struct ipr_data sh7750_ipr_map[] { 35, 2, 8, 7 }, /* DMAC DMTE1 */ { 36, 2, 8, 7 }, /* DMAC DMTE2 */ { 37, 2, 8, 7 }, /* DMAC DMTE3 */ - { 28, 2, 8, 7 }, /* DMAC DMAE */ + { 38, 2, 8, 7 }, /* DMAC DMAE */ }; static struct ipr_data sh7751_ipr_map[] = { diff --git a/arch/sh/kernel/cpu/sh4/setup-sh7760.c b/arch/sh/kernel/cpu/sh4/setup-sh7760.c index 07e5377..b7c7028 100644 --- a/arch/sh/kernel/cpu/sh4/setup-sh7760.c +++ b/arch/sh/kernel/cpu/sh4/setup-sh7760.c @@ -52,17 +52,11 @@ static int __init sh7760_devices_setup(v } __initcall(sh7760_devices_setup); -/* - * SH7760 INTC2-Style interrupts, vectors IRQ48-111 INTEVT 0x800-0xFE0 - */ static struct intc2_data intc2_irq_table[] = { - /* INTPRIO0 | INTMSK0 */ {48, 0, 28, 0, 31, 3}, /* IRQ 4 */ {49, 0, 24, 0, 30, 3}, /* IRQ 3 */ {50, 0, 20, 0, 29, 3}, /* IRQ 2 */ {51, 0, 16, 0, 28, 3}, /* IRQ 1 */ - /* 52-55 (INTEVT 0x880-0x8E0) unused/reserved */ - /* INTPRIO4 | INTMSK0 */ {56, 4, 28, 0, 25, 3}, /* HCAN2_CHAN0 */ {57, 4, 24, 0, 24, 3}, /* HCAN2_CHAN1 */ {58, 4, 20, 0, 23, 3}, /* I2S_CHAN0 */ @@ -71,18 +65,15 @@ static struct intc2_data intc2_irq_table {61, 4, 8, 0, 20, 3}, /* AC97_CHAN1 */ {62, 4, 4, 0, 19, 3}, /* I2C_CHAN0 */ {63, 4, 0, 0, 18, 3}, /* I2C_CHAN1 */ - /* INTPRIO8 | INTMSK0 */ {52, 8, 16, 0, 11, 3}, /* SCIF0_ERI_IRQ */ {53, 8, 16, 0, 10, 3}, /* SCIF0_RXI_IRQ */ {54, 8, 16, 0, 9, 3}, /* SCIF0_BRI_IRQ */ {55, 8, 16, 0, 8, 3}, /* SCIF0_TXI_IRQ */ {64, 8, 28, 0, 17, 3}, /* USBHI_IRQ */ {65, 8, 24, 0, 16, 3}, /* LCDC */ - /* 66, 67 unused */ {68, 8, 20, 0, 14, 13}, /* DMABRGI0_IRQ */ {69, 8, 20, 0, 13, 13}, /* DMABRGI1_IRQ */ {70, 8, 20, 0, 12, 13}, /* DMABRGI2_IRQ */ - /* 71 unused */ {72, 8, 12, 0, 7, 3}, /* SCIF1_ERI_IRQ */ {73, 8, 12, 0, 6, 3}, /* SCIF1_RXI_IRQ */ {74, 8, 12, 0, 5, 3}, /* SCIF1_BRI_IRQ */ @@ -91,26 +82,71 @@ static struct intc2_data intc2_irq_table {77, 8, 8, 0, 2, 3}, /* SCIF2_RXI_IRQ */ {78, 8, 8, 0, 1, 3}, /* SCIF2_BRI_IRQ */ {79, 8, 8, 0, 0, 3}, /* SCIF2_TXI_IRQ */ - /* | INTMSK4 */ {80, 8, 4, 4, 23, 3}, /* SIM_ERI */ {81, 8, 4, 4, 22, 3}, /* SIM_RXI */ {82, 8, 4, 4, 21, 3}, /* SIM_TXI */ {83, 8, 4, 4, 20, 3}, /* SIM_TEI */ {84, 8, 0, 4, 19, 3}, /* HSPII */ - /* INTPRIOC | INTMSK4 */ - /* 85-87 unused/reserved */ {88, 12, 20, 4, 18, 3}, /* MMCI0 */ {89, 12, 20, 4, 17, 3}, /* MMCI1 */ {90, 12, 20, 4, 16, 3}, /* MMCI2 */ {91, 12, 20, 4, 15, 3}, /* MMCI3 */ - {92, 12, 12, 4, 6, 3}, /* MFI (unsure, bug? in my 7760 manual*/ - /* 93-107 reserved/undocumented */ + {92, 12, 12, 4, 6, 3}, /* MFI */ {108,12, 4, 4, 1, 3}, /* ADC */ {109,12, 0, 4, 0, 3}, /* CMTI */ - /* 110-111 reserved/unused */ }; +static struct ipr_data sh7760_ipr_map[] = { + /* IRQ, IPR-idx, shift, priority */ + { 16, 0, 12, 2 }, /* TMU0 TUNI*/ + { 17, 0, 8, 2 }, /* TMU1 TUNI */ + { 18, 0, 4, 2 }, /* TMU2 TUNI */ + { 19, 0, 4, 2 }, /* TMU2 TIPCI */ + { 27, 1, 12, 2 }, /* WDT ITI */ + { 28, 1, 8, 2 }, /* REF RCMI */ + { 29, 1, 8, 2 }, /* REF ROVI */ + { 32, 2, 0, 7 }, /* HUDI */ + { 33, 2, 12, 7 }, /* GPIOI */ + { 34, 2, 8, 7 }, /* DMAC DMTE0 */ + { 35, 2, 8, 7 }, /* DMAC DMTE1 */ + { 36, 2, 8, 7 }, /* DMAC DMTE2 */ + { 37, 2, 8, 7 }, /* DMAC DMTE3 */ + { 38, 2, 8, 7 }, /* DMAC DMAE */ + { 44, 2, 8, 7 }, /* DMAC DMTE4 */ + { 45, 2, 8, 7 }, /* DMAC DMTE5 */ + { 46, 2, 8, 7 }, /* DMAC DMTE6 */ + { 47, 2, 8, 7 }, /* DMAC DMTE7 */ +/* these here are only valid if INTC_ICR bit 7 is set to 1! + * XXX: maybe CONFIG_SH_IRLMODE symbol? SH7751 could use it too */ +#if 0 + { 2, 3, 12, 3 }, /* IRL0 */ + { 5, 3, 8, 3 }, /* IRL1 */ + { 8, 3, 4, 3 }, /* IRL2 */ + { 11, 3, 0, 3 }, /* IRL3 */ +#endif +}; + +static unsigned long ipr_offsets[] = { + 0xffd00004UL, /* 0: IPRA */ + 0xffd00008UL, /* 1: IPRB */ + 0xffd0000cUL, /* 2: IPRC */ + 0xffd00010UL, /* 3: IPRD */ +}; + +/* given the IPR index return the address of the IPR register */ +unsigned int map_ipridx_to_addr(int idx) +{ + if (idx >= ARRAY_SIZE(ipr_offsets)) + return 0; + return ipr_offsets[idx]; +} + void __init init_IRQ_intc2(void) { make_intc2_irq(intc2_irq_table, ARRAY_SIZE(intc2_irq_table)); } + +void __init init_IRQ_ipr(void) +{ + make_ipr_irq(sh7760_ipr_map, ARRAY_SIZE(sh7760_ipr_map)); +} diff --git a/arch/sh/kernel/debugtraps.S b/arch/sh/kernel/debugtraps.S new file mode 100644 index 0000000..13b6674 --- /dev/null +++ b/arch/sh/kernel/debugtraps.S @@ -0,0 +1,41 @@ +/* + * arch/sh/kernel/debugtraps.S + * + * Debug trap jump tables for SuperH + * + * Copyright (C) 2006 Paul Mundt + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + */ +#include +#include + +#if !defined(CONFIG_SH_KGDB) +#define kgdb_handle_exception debug_trap_handler +#endif + +#if !defined(CONFIG_SH_STANDARD_BIOS) +#define sh_bios_handler debug_trap_handler +#endif + + .data + +ENTRY(debug_trap_table) + .long debug_trap_handler /* 0x30 */ + .long debug_trap_handler /* 0x31 */ + .long debug_trap_handler /* 0x32 */ + .long debug_trap_handler /* 0x33 */ + .long debug_trap_handler /* 0x34 */ + .long debug_trap_handler /* 0x35 */ + .long debug_trap_handler /* 0x36 */ + .long debug_trap_handler /* 0x37 */ + .long debug_trap_handler /* 0x38 */ + .long debug_trap_handler /* 0x39 */ + .long debug_trap_handler /* 0x3a */ + .long debug_trap_handler /* 0x3b */ + .long kgdb_handle_exception /* 0x3c */ + .long debug_trap_handler /* 0x3d */ + .long bug_trap_handler /* 0x3e */ + .long sh_bios_handler /* 0x3f */ diff --git a/arch/sh/kernel/early_printk.c b/arch/sh/kernel/early_printk.c index 560b91c..9048c03 100644 --- a/arch/sh/kernel/early_printk.c +++ b/arch/sh/kernel/early_printk.c @@ -106,12 +106,32 @@ static struct console scif_console = { }; #if defined(CONFIG_CPU_SH4) && !defined(CONFIG_SH_STANDARD_BIOS) +#define DEFAULT_BAUD 115200 /* * Simple SCIF init, primarily aimed at SH7750 and other similar SH-4 * devices that aren't using sh-ipl+g. */ -static void scif_sercon_init(int baud) +static void scif_sercon_init(char *s) { + unsigned baud = DEFAULT_BAUD; + char *e; + + if (*s == ',') + ++s; + + if (*s) { + /* ignore ioport/device name */ + s += strcspn(s, ","); + if (*s == ',') + s++; + } + + if (*s) { + baud = simple_strtoul(s, &e, 0); + if (baud == 0 || s == e) + baud = DEFAULT_BAUD; + } + ctrl_outw(0, scif_port.mapbase + 8); ctrl_outw(0, scif_port.mapbase); @@ -167,7 +187,7 @@ #if defined(CONFIG_EARLY_SCIF_CONSOLE) early_console = &scif_console; #if defined(CONFIG_CPU_SH4) && !defined(CONFIG_SH_STANDARD_BIOS) - scif_sercon_init(115200); + scif_sercon_init(buf + 6); #endif } #endif diff --git a/arch/sh/kernel/entry-common.S b/arch/sh/kernel/entry-common.S index fc279ae..ab4ebb8 100644 --- a/arch/sh/kernel/entry-common.S +++ b/arch/sh/kernel/entry-common.S @@ -54,79 +54,24 @@ # define preempt_stop() # define resume_kernel __restore_all #endif -#if defined(CONFIG_SH_STANDARD_BIOS) || defined(CONFIG_SH_KGDB) -! Handle kernel debug if either kgdb (SW) or gdb-stub (FW) is present. -! If both are configured, handle the debug traps (breakpoints) in SW, -! but still allow BIOS traps to FW. - - .align 2 -debug_kernel: -#if defined(CONFIG_SH_STANDARD_BIOS) && defined(CONFIG_SH_KGDB) - /* Force BIOS call to FW (debug_trap put TRA in r8) */ - mov r8,r0 - shlr2 r0 - cmp/eq #0x3f,r0 - bt debug_kernel_fw -#endif /* CONFIG_SH_STANDARD_BIOS && CONFIG_SH_KGDB */ - -debug_enter: -#if defined(CONFIG_SH_KGDB) - /* Jump to kgdb, pass stacked regs as arg */ -debug_kernel_sw: - mov.l 3f, r0 - jmp @r0 - mov r15, r4 - .align 2 -3: .long kgdb_handle_exception -#endif /* CONFIG_SH_KGDB */ -#ifdef CONFIG_SH_STANDARD_BIOS - bra debug_kernel_fw - nop -#endif -#endif /* CONFIG_SH_STANDARD_BIOS || CONFIG_SH_KGDB */ - - .align 2 -debug_trap: -#if defined(CONFIG_SH_STANDARD_BIOS) || defined(CONFIG_SH_KGDB) - mov r8, r0 - shlr2 r0 - cmp/eq #0x3f, r0 ! sh_bios() trap - bf 1f -#ifdef CONFIG_SH_KGDB - cmp/eq #0xff, r0 ! XXX: KGDB trap, fix for SH-2. - bf 1f -#endif - mov #OFF_SR, r0 - mov.l @(r0,r15), r0 ! get status register - shll r0 - shll r0 ! kernel space? - bt/s debug_kernel -1: -#endif - mov.l @r15, r0 ! Restore R0 value - mov.l 1f, r8 - jmp @r8 - nop .align 2 ENTRY(exception_error) ! #ifdef CONFIG_TRACE_IRQFLAGS - mov.l 3f, r0 + mov.l 2f, r0 jsr @r0 nop #endif sti - mov.l 2f, r0 + mov.l 1f, r0 jmp @r0 nop -! .align 2 -1: .long break_point_trap_software -2: .long do_exception_error +1: .long do_exception_error #ifdef CONFIG_TRACE_IRQFLAGS -3: .long trace_hardirqs_on +2: .long trace_hardirqs_on #endif .align 2 @@ -331,16 +276,31 @@ __restore_all: 1: .long restore_all .align 2 -not_syscall_tra: - bra debug_trap - nop - - .align 2 syscall_badsys: ! Bad syscall number mov #-ENOSYS, r0 bra resume_userspace mov.l r0, @(OFF_R0,r15) ! Return value - + +/* + * The main debug trap handler. + * + * r8=TRA (not the trap number!) + * + * Note: This assumes that the trapa value is left in its original + * form (without the shlr2 shift) so the calculation for the jump + * call table offset remains a simple in place mask. + */ +debug_trap: + mov r8, r0 + and #(0xf << 2), r0 + mov.l 1f, r8 + add r0, r8 + mov.l @r8, r8 + jmp @r8 + nop + + .align 2 +1: .long debug_trap_table /* * Syscall interface: @@ -348,17 +308,19 @@ syscall_badsys: ! Bad syscall number * Syscall #: R3 * Arguments #0 to #3: R4--R7 * Arguments #4 to #6: R0, R1, R2 - * TRA: (number of arguments + 0x10) x 4 + * TRA: (number of arguments + ABI revision) x 4 * * This code also handles delegating other traps to the BIOS/gdb stub * according to: * * Trap number - * (TRA>>2) Purpose - * -------- ------- - * 0x0-0xf old syscall ABI - * 0x10-0x1f new syscall ABI - * 0x20-0xff delegated through debug_trap to BIOS/gdb stub. + * (TRA>>2) Purpose + * -------- ------- + * 0x00-0x0f original SH-3/4 syscall ABI (not in general use). + * 0x10-0x1f general SH-3/4 syscall ABI. + * 0x20-0x2f syscall ABI for SH-2 parts. + * 0x30-0x3f debug traps used by the kernel. + * 0x40-0xff Not supported by all parts, so left unhandled. * * Note: When we're first called, the TRA value must be shifted * right 2 bits in order to get the value that was used as the "trapa" @@ -375,17 +337,22 @@ ret_from_fork: nop .align 2 1: .long schedule_tail - ! + +/* + * The poorly named main trapa decode and dispatch routine, for + * system calls and debug traps through their respective jump tables. + */ ENTRY(system_call) #if !defined(CONFIG_CPU_SH2) mov.l 1f, r9 mov.l @r9, r8 ! Read from TRA (Trap Address) Register #endif - ! - ! Is the trap argument >= 0x20? (TRA will be >= 0x80) - mov #0x7f, r9 + /* + * Check the trap type + */ + mov #((0x20 << 2) - 1), r9 cmp/hi r9, r8 - bt/s not_syscall_tra + bt/s debug_trap ! it's a debug trap.. mov #OFF_TRA, r9 add r15, r9 mov.l r8, @r9 ! set TRA value to tra diff --git a/arch/sh/kernel/io_generic.c b/arch/sh/kernel/io_generic.c index 28ec748..66626c0 100644 --- a/arch/sh/kernel/io_generic.c +++ b/arch/sh/kernel/io_generic.c @@ -1,9 +1,8 @@ -/* $Id: io_generic.c,v 1.2 2003/05/04 19:29:53 lethal Exp $ - * - * linux/arch/sh/kernel/io_generic.c +/* + * arch/sh/kernel/io_generic.c * * Copyright (C) 2000 Niibe Yutaka - * Copyright (C) 2005 Paul Mundt + * Copyright (C) 2005 - 2007 Paul Mundt * * Generic I/O routine. These can be used where a machine specific version * is not required. @@ -13,8 +12,9 @@ * for more details. */ #include -#include +#include #include +#include #ifdef CONFIG_CPU_SH3 /* SH3 has a PCMCIA bug that needs a dummy read from area 6 for a @@ -96,6 +96,7 @@ void generic_insw(unsigned long port, vo while (count--) *buf++ = *port_addr; + flush_dcache_all(); dummy_read(); } @@ -170,6 +171,7 @@ void generic_outsw(unsigned long port, c while (count--) *port_addr = *buf++; + flush_dcache_all(); dummy_read(); } diff --git a/arch/sh/kernel/kgdb_stub.c b/arch/sh/kernel/kgdb_stub.c index 9c6315f..d8927d8 100644 --- a/arch/sh/kernel/kgdb_stub.c +++ b/arch/sh/kernel/kgdb_stub.c @@ -1323,8 +1323,11 @@ #endif } /* There has been an exception, most likely a breakpoint. */ -void kgdb_handle_exception(struct pt_regs *regs) +asmlinkage void kgdb_handle_exception(unsigned long r4, unsigned long r5, + unsigned long r6, unsigned long r7, + struct pt_regs __regs) { + struct pt_regs *regs = RELOC_HIDE(&__regs, 0); int excep_code, vbr_val; int count; int trapa_value = ctrl_inl(TRA); @@ -1368,8 +1371,6 @@ void kgdb_handle_exception(struct pt_reg vbr_val = trap_registers.vbr; asm("ldc %0, vbr": :"r"(vbr_val)); - - return; } /* Trigger a breakpoint by function */ diff --git a/arch/sh/kernel/process.c b/arch/sh/kernel/process.c index 486c06e..9d6a438 100644 --- a/arch/sh/kernel/process.c +++ b/arch/sh/kernel/process.c @@ -1,42 +1,30 @@ -/* $Id: process.c,v 1.28 2004/05/05 16:54:23 lethal Exp $ +/* + * arch/sh/kernel/process.c * - * linux/arch/sh/kernel/process.c + * This file handles the architecture-dependent parts of process handling.. * * Copyright (C) 1995 Linus Torvalds * * SuperH version: Copyright (C) 1999, 2000 Niibe Yutaka & Kaz Kojima * Copyright (C) 2006 Lineo Solutions Inc. support SH4A UBC + * Copyright (C) 2002 - 2006 Paul Mundt */ - -/* - * This file handles the architecture-dependent parts of process handling.. - */ - #include -#include #include #include -#include -#include #include -#include #include #include - -#include #include #include -#include #include -static int hlt_counter=0; - +static int hlt_counter; int ubc_usercnt = 0; #define HARD_IDLE_TIMEOUT (HZ / 3) void (*pm_idle)(void); - void (*pm_power_off)(void); EXPORT_SYMBOL(pm_power_off); @@ -44,14 +32,12 @@ void disable_hlt(void) { hlt_counter++; } - EXPORT_SYMBOL(disable_hlt); void enable_hlt(void) { hlt_counter--; } - EXPORT_SYMBOL(enable_hlt); void default_idle(void) @@ -152,19 +138,21 @@ __asm__(".align 5\n" ".align 2\n\t" "1:.long do_exit"); +/* Don't use this in BL=1(cli). Or else, CPU resets! */ int kernel_thread(int (*fn)(void *), void * arg, unsigned long flags) -{ /* Don't use this in BL=1(cli). Or else, CPU resets! */ +{ struct pt_regs regs; memset(®s, 0, sizeof(regs)); - regs.regs[4] = (unsigned long) arg; - regs.regs[5] = (unsigned long) fn; + regs.regs[4] = (unsigned long)arg; + regs.regs[5] = (unsigned long)fn; - regs.pc = (unsigned long) kernel_thread_helper; + regs.pc = (unsigned long)kernel_thread_helper; regs.sr = (1 << 30); /* Ok, create the new process.. */ - return do_fork(flags | CLONE_VM | CLONE_UNTRACED, 0, ®s, 0, NULL, NULL); + return do_fork(flags | CLONE_VM | CLONE_UNTRACED, 0, + ®s, 0, NULL, NULL); } /* @@ -211,21 +199,20 @@ #endif return fpvalid; } -/* +/* * Capture the user space registers if the task is not running (in user space) */ int dump_task_regs(struct task_struct *tsk, elf_gregset_t *regs) { struct pt_regs ptregs; - + ptregs = *task_pt_regs(tsk); elf_core_copy_regs(regs, &ptregs); return 1; } -int -dump_task_fpu (struct task_struct *tsk, elf_fpregset_t *fpu) +int dump_task_fpu(struct task_struct *tsk, elf_fpregset_t *fpu) { int fpvalid = 0; @@ -263,12 +250,14 @@ #endif childregs->regs[15] = usp; ti->addr_limit = USER_DS; } else { - childregs->regs[15] = (unsigned long)task_stack_page(p) + THREAD_SIZE; + childregs->regs[15] = (unsigned long)task_stack_page(p) + + THREAD_SIZE; ti->addr_limit = KERNEL_DS; } - if (clone_flags & CLONE_SETTLS) { + + if (clone_flags & CLONE_SETTLS) childregs->gbr = childregs->regs[0]; - } + childregs->regs[0] = 0; /* Set return value for child */ p->thread.sp = (unsigned long) childregs; @@ -280,8 +269,7 @@ #endif } /* Tracing by user break controller. */ -static void -ubc_set_tracing(int asid, unsigned long pc) +static void ubc_set_tracing(int asid, unsigned long pc) { #if defined(CONFIG_CPU_SH4A) unsigned long val; @@ -297,7 +285,7 @@ #if defined(CONFIG_CPU_SH4A) val = (UBC_CRR_RES | UBC_CRR_PCB | UBC_CRR_BIE); ctrl_outl(val, UBC_CRR0); - /* Read UBC register that we writed last. For chekking UBC Register changed */ + /* Read UBC register that we wrote last, for checking update */ val = ctrl_inl(UBC_CRR0); #else /* CONFIG_CPU_SH4A */ @@ -305,13 +293,14 @@ #else /* CONFIG_CPU_SH4A */ #ifdef CONFIG_MMU /* We don't have any ASID settings for the SH-2! */ - if (cpu_data->type != CPU_SH7604) + if (current_cpu_data.type != CPU_SH7604) ctrl_outb(asid, UBC_BASRA); #endif ctrl_outl(0, UBC_BAMRA); - if (cpu_data->type == CPU_SH7729 || cpu_data->type == CPU_SH7710) { + if (current_cpu_data.type == CPU_SH7729 || + current_cpu_data.type == CPU_SH7710) { ctrl_outw(BBR_INST | BBR_READ | BBR_CPU, UBC_BBRA); ctrl_outl(BRCR_PCBA | BRCR_PCTE, UBC_BRCR); } else { @@ -325,7 +314,8 @@ #endif /* CONFIG_CPU_SH4A */ * switch_to(x,y) should switch tasks from x to y. * */ -struct task_struct *__switch_to(struct task_struct *prev, struct task_struct *next) +struct task_struct *__switch_to(struct task_struct *prev, + struct task_struct *next) { #if defined(CONFIG_SH_FPU) unlazy_fpu(prev, task_pt_regs(prev)); @@ -354,7 +344,7 @@ #endif #ifdef CONFIG_MMU /* * Restore the kernel mode register - * k7 (r7_bank1) + * k7 (r7_bank1) */ asm volatile("ldc %0, r7_bank" : /* no output */ @@ -367,7 +357,7 @@ #endif else if (next->thread.ubc_pc && next->mm) { int asid = 0; #ifdef CONFIG_MMU - asid |= next->mm->context.id & MMU_CONTEXT_ASID_MASK; + asid |= cpu_asid(smp_processor_id(), next->mm); #endif ubc_set_tracing(asid, next->thread.ubc_pc); } else { @@ -405,7 +395,8 @@ asmlinkage int sys_clone(unsigned long c if (!newsp) newsp = regs->regs[15]; return do_fork(clone_flags, newsp, regs, 0, - (int __user *)parent_tidptr, (int __user *)child_tidptr); + (int __user *)parent_tidptr, + (int __user *)child_tidptr); } /* @@ -493,9 +484,27 @@ #endif force_sig(SIGTRAP, current); } -asmlinkage void break_point_trap_software(unsigned long r4, unsigned long r5, - unsigned long r6, unsigned long r7, - struct pt_regs __regs) +/* + * Generic trap handler. + */ +asmlinkage void debug_trap_handler(unsigned long r4, unsigned long r5, + unsigned long r6, unsigned long r7, + struct pt_regs __regs) +{ + struct pt_regs *regs = RELOC_HIDE(&__regs, 0); + + /* Rewind */ + regs->pc -= 2; + + force_sig(SIGTRAP, current); +} + +/* + * Special handler for BUG() traps. + */ +asmlinkage void bug_trap_handler(unsigned long r4, unsigned long r5, + unsigned long r6, unsigned long r7, + struct pt_regs __regs) { struct pt_regs *regs = RELOC_HIDE(&__regs, 0); diff --git a/arch/sh/kernel/setup.c b/arch/sh/kernel/setup.c index 225f9ea..98802ab 100644 --- a/arch/sh/kernel/setup.c +++ b/arch/sh/kernel/setup.c @@ -1,14 +1,11 @@ /* - * linux/arch/sh/kernel/setup.c + * arch/sh/kernel/setup.c * - * Copyright (C) 1999 Niibe Yutaka - * Copyright (C) 2002, 2003 Paul Mundt - */ - -/* * This file handles the architecture-dependent parts of initialization + * + * Copyright (C) 1999 Niibe Yutaka + * Copyright (C) 2002 - 2006 Paul Mundt */ - #include #include #include @@ -75,7 +72,7 @@ #define RAMDISK_IMAGE_START_MASK 0x07FF #define RAMDISK_PROMPT_FLAG 0x8000 #define RAMDISK_LOAD_FLAG 0x4000 -static char command_line[COMMAND_LINE_SIZE] = { 0, }; +static char __initdata command_line[COMMAND_LINE_SIZE] = { 0, }; static struct resource code_resource = { .name = "Kernel code", }; static struct resource data_resource = { .name = "Kernel data", }; @@ -90,8 +87,8 @@ static inline void parse_cmdline (char * int len = 0; /* Save unparsed command line copy for /proc/cmdline */ - memcpy(saved_command_line, COMMAND_LINE, COMMAND_LINE_SIZE); - saved_command_line[COMMAND_LINE_SIZE-1] = '\0'; + memcpy(boot_command_line, COMMAND_LINE, COMMAND_LINE_SIZE); + boot_command_line[COMMAND_LINE_SIZE-1] = '\0'; memory_start = (unsigned long)PAGE_OFFSET+__MEMORY_START; memory_end = memory_start + __MEMORY_SIZE; @@ -395,9 +392,9 @@ static const char *cpu_name[] = { [CPU_SH_NONE] = "Unknown" }; -const char *get_cpu_subtype(void) +const char *get_cpu_subtype(struct sh_cpuinfo *c) { - return cpu_name[boot_cpu_data.type]; + return cpu_name[c->type]; } #ifdef CONFIG_PROC_FS @@ -407,19 +404,19 @@ static const char *cpu_flags[] = { "ptea", "llsc", "l2", NULL }; -static void show_cpuflags(struct seq_file *m) +static void show_cpuflags(struct seq_file *m, struct sh_cpuinfo *c) { unsigned long i; seq_printf(m, "cpu flags\t:"); - if (!cpu_data->flags) { + if (!c->flags) { seq_printf(m, " %s\n", cpu_flags[0]); return; } for (i = 0; cpu_flags[i]; i++) - if ((cpu_data->flags & (1 << i))) + if ((c->flags & (1 << i))) seq_printf(m, " %s", cpu_flags[i+1]); seq_printf(m, "\n"); @@ -441,16 +438,20 @@ static void show_cacheinfo(struct seq_fi */ static int show_cpuinfo(struct seq_file *m, void *v) { - unsigned int cpu = smp_processor_id(); + struct sh_cpuinfo *c = v; + unsigned int cpu = c - cpu_data; + + if (!cpu_online(cpu)) + return 0; - if (!cpu && cpu_online(cpu)) + if (cpu == 0) seq_printf(m, "machine\t\t: %s\n", get_system_type()); seq_printf(m, "processor\t: %d\n", cpu); seq_printf(m, "cpu family\t: %s\n", init_utsname()->machine); - seq_printf(m, "cpu type\t: %s\n", get_cpu_subtype()); + seq_printf(m, "cpu type\t: %s\n", get_cpu_subtype(c)); - show_cpuflags(m); + show_cpuflags(m, c); seq_printf(m, "cache type\t: "); @@ -459,22 +460,22 @@ static int show_cpuinfo(struct seq_file * unified cache on the SH-2 and SH-3, as well as the harvard * style cache on the SH-4. */ - if (boot_cpu_data.icache.flags & SH_CACHE_COMBINED) { + if (c->icache.flags & SH_CACHE_COMBINED) { seq_printf(m, "unified\n"); - show_cacheinfo(m, "cache", boot_cpu_data.icache); + show_cacheinfo(m, "cache", c->icache); } else { seq_printf(m, "split (harvard)\n"); - show_cacheinfo(m, "icache", boot_cpu_data.icache); - show_cacheinfo(m, "dcache", boot_cpu_data.dcache); + show_cacheinfo(m, "icache", c->icache); + show_cacheinfo(m, "dcache", c->dcache); } /* Optional secondary cache */ - if (boot_cpu_data.flags & CPU_HAS_L2_CACHE) - show_cacheinfo(m, "scache", boot_cpu_data.scache); + if (c->flags & CPU_HAS_L2_CACHE) + show_cacheinfo(m, "scache", c->scache); seq_printf(m, "bogomips\t: %lu.%02lu\n", - boot_cpu_data.loops_per_jiffy/(500000/HZ), - (boot_cpu_data.loops_per_jiffy/(5000/HZ)) % 100); + c->loops_per_jiffy/(500000/HZ), + (c->loops_per_jiffy/(5000/HZ)) % 100); return show_clocks(m); } diff --git a/arch/sh/kernel/sh_ksyms.c b/arch/sh/kernel/sh_ksyms.c index e610623..fe1b276 100644 --- a/arch/sh/kernel/sh_ksyms.c +++ b/arch/sh/kernel/sh_ksyms.c @@ -105,7 +105,6 @@ #if defined(CONFIG_MMU) && (defined(CONF EXPORT_SYMBOL(clear_user_page); #endif -EXPORT_SYMBOL(flush_tlb_page); EXPORT_SYMBOL(__down_trylock); #ifdef CONFIG_SMP diff --git a/arch/sh/kernel/signal.c b/arch/sh/kernel/signal.c index 379c88b..32f10a0 100644 --- a/arch/sh/kernel/signal.c +++ b/arch/sh/kernel/signal.c @@ -127,7 +127,7 @@ static inline int restore_sigcontext_fpu { struct task_struct *tsk = current; - if (!(cpu_data->flags & CPU_HAS_FPU)) + if (!(current_cpu_data.flags & CPU_HAS_FPU)) return 0; set_used_math(); @@ -140,7 +140,7 @@ static inline int save_sigcontext_fpu(st { struct task_struct *tsk = current; - if (!(cpu_data->flags & CPU_HAS_FPU)) + if (!(current_cpu_data.flags & CPU_HAS_FPU)) return 0; if (!used_math()) { @@ -181,7 +181,7 @@ #define COPY(x) err |= __get_user(regs- #undef COPY #ifdef CONFIG_SH_FPU - if (cpu_data->flags & CPU_HAS_FPU) { + if (current_cpu_data.flags & CPU_HAS_FPU) { int owned_fp; struct task_struct *tsk = current; diff --git a/arch/sh/kernel/syscalls.S b/arch/sh/kernel/syscalls.S index ca81976..38fc8cd 100644 --- a/arch/sh/kernel/syscalls.S +++ b/arch/sh/kernel/syscalls.S @@ -319,15 +319,15 @@ ENTRY(sys_call_table) .long sys_mq_getsetattr .long sys_kexec_load .long sys_waitid - .long sys_ni_syscall /* 285 */ - .long sys_add_key + .long sys_add_key /* 285 */ .long sys_request_key .long sys_keyctl .long sys_ioprio_set - .long sys_ioprio_get /* 290 */ - .long sys_inotify_init + .long sys_ioprio_get + .long sys_inotify_init /* 290 */ .long sys_inotify_add_watch .long sys_inotify_rm_watch + .long sys_ni_syscall .long sys_migrate_pages .long sys_openat /* 295 */ .long sys_mkdirat diff --git a/arch/sh/kernel/time.c b/arch/sh/kernel/time.c index c206c95..d47e775 100644 --- a/arch/sh/kernel/time.c +++ b/arch/sh/kernel/time.c @@ -41,14 +41,6 @@ static int null_rtc_set_time(const time_ void (*rtc_sh_get_time)(struct timespec *) = null_rtc_get_time; int (*rtc_sh_set_time)(const time_t) = null_rtc_set_time; -/* - * Scheduler clock - returns current time in nanosec units. - */ -unsigned long long __attribute__ ((weak)) sched_clock(void) -{ - return (unsigned long long)jiffies * (1000000000 / HZ); -} - #ifndef CONFIG_GENERIC_TIME void do_gettimeofday(struct timeval *tv) { diff --git a/arch/sh/kernel/traps.c b/arch/sh/kernel/traps.c index ec11015..e9f168f 100644 --- a/arch/sh/kernel/traps.c +++ b/arch/sh/kernel/traps.c @@ -156,13 +156,13 @@ static inline void do_bug_verbose(struct { } #endif /* CONFIG_DEBUG_BUGVERBOSE */ -#endif /* CONFIG_BUG */ void handle_BUG(struct pt_regs *regs) { do_bug_verbose(regs); die("Kernel BUG", regs, TRAPA_BUG_OPCODE & 0xff); } +#endif /* CONFIG_BUG */ /* * handle an instruction that does an unaligned memory access by emulating the @@ -641,7 +641,7 @@ int is_dsp_inst(struct pt_regs *regs) * Safe guard if DSP mode is already enabled or we're lacking * the DSP altogether. */ - if (!(cpu_data->flags & CPU_HAS_DSP) || (regs->sr & SR_DSP)) + if (!(current_cpu_data.flags & CPU_HAS_DSP) || (regs->sr & SR_DSP)) return 0; get_user(inst, ((unsigned short *) regs->pc)); diff --git a/arch/sh/kernel/vmlinux.lds.S b/arch/sh/kernel/vmlinux.lds.S index f34bdcc..75de165 100644 --- a/arch/sh/kernel/vmlinux.lds.S +++ b/arch/sh/kernel/vmlinux.lds.S @@ -83,9 +83,13 @@ SECTIONS .con_initcall.init : { *(.con_initcall.init) } __con_initcall_end = .; SECURITY_INIT + +#ifdef CONFIG_BLK_DEV_INITRD __initramfs_start = .; .init.ramfs : { *(.init.ramfs) } __initramfs_end = .; +#endif + __machvec_start = .; .init.machvec : { *(.init.machvec) } __machvec_end = .; diff --git a/arch/sh/kernel/vsyscall/vsyscall.c b/arch/sh/kernel/vsyscall/vsyscall.c index deb4694..7b0f66f 100644 --- a/arch/sh/kernel/vsyscall/vsyscall.c +++ b/arch/sh/kernel/vsyscall/vsyscall.c @@ -37,11 +37,12 @@ __setup("vdso=", vdso_setup); * of the ELF DSO images included therein. */ extern const char vsyscall_trapa_start, vsyscall_trapa_end; -static void *syscall_page; +static struct page *syscall_pages[1]; int __init vsyscall_init(void) { - syscall_page = (void *)get_zeroed_page(GFP_ATOMIC); + void *syscall_page = (void *)get_zeroed_page(GFP_ATOMIC); + syscall_pages[0] = virt_to_page(syscall_page); /* * XXX: Map this page to a fixmap entry if we get around @@ -55,37 +56,10 @@ int __init vsyscall_init(void) return 0; } -static struct page *syscall_vma_nopage(struct vm_area_struct *vma, - unsigned long address, int *type) -{ - unsigned long offset = address - vma->vm_start; - struct page *page; - - if (address < vma->vm_start || address > vma->vm_end) - return NOPAGE_SIGBUS; - - page = virt_to_page(syscall_page + offset); - - get_page(page); - - return page; -} - -/* Prevent VMA merging */ -static void syscall_vma_close(struct vm_area_struct *vma) -{ -} - -static struct vm_operations_struct syscall_vm_ops = { - .nopage = syscall_vma_nopage, - .close = syscall_vma_close, -}; - /* Setup a VMA at program startup for the vsyscall page */ int arch_setup_additional_pages(struct linux_binprm *bprm, int executable_stack) { - struct vm_area_struct *vma; struct mm_struct *mm = current->mm; unsigned long addr; int ret; @@ -97,30 +71,16 @@ int arch_setup_additional_pages(struct l goto up_fail; } - vma = kmem_cache_zalloc(vm_area_cachep, GFP_KERNEL); - if (!vma) { - ret = -ENOMEM; + ret = install_special_mapping(mm, addr, PAGE_SIZE, + VM_READ | VM_EXEC | + VM_MAYREAD | VM_MAYWRITE | VM_MAYEXEC | + VM_ALWAYSDUMP, + syscall_pages); + if (unlikely(ret)) goto up_fail; - } - - vma->vm_start = addr; - vma->vm_end = addr + PAGE_SIZE; - /* MAYWRITE to allow gdb to COW and set breakpoints */ - vma->vm_flags = VM_READ|VM_EXEC|VM_MAYREAD|VM_MAYEXEC|VM_MAYWRITE; - vma->vm_flags |= mm->def_flags; - vma->vm_page_prot = protection_map[vma->vm_flags & 7]; - vma->vm_ops = &syscall_vm_ops; - vma->vm_mm = mm; - - ret = insert_vm_struct(mm, vma); - if (unlikely(ret)) { - kmem_cache_free(vm_area_cachep, vma); - goto up_fail; - } current->mm->context.vdso = (void *)addr; - mm->total_vm++; up_fail: up_write(&mm->mmap_sem); return ret; diff --git a/arch/sh/mm/Kconfig b/arch/sh/mm/Kconfig index 29f4ee3..6b0d28a 100644 --- a/arch/sh/mm/Kconfig +++ b/arch/sh/mm/Kconfig @@ -20,7 +20,7 @@ config CPU_SH4 bool select CPU_HAS_INTEVT select CPU_HAS_SR_RB - select CPU_HAS_PTEA if !CPU_SUBTYPE_ST40 + select CPU_HAS_PTEA if (!CPU_SUBTYPE_ST40 && !CPU_SH4A) || CPU_SHX2 config CPU_SH4A bool @@ -72,6 +72,7 @@ config CPU_SUBTYPE_SH7705 config CPU_SUBTYPE_SH7706 bool "Support SH7706 processor" select CPU_SH3 + select CPU_HAS_IPR_IRQ help Select SH7706 if you have a 133 Mhz SH-3 HD6417706 CPU. @@ -92,6 +93,7 @@ config CPU_SUBTYPE_SH7708 config CPU_SUBTYPE_SH7709 bool "Support SH7709 processor" select CPU_SH3 + select CPU_HAS_IPR_IRQ select CPU_HAS_PINT_IRQ help Select SH7709 if you have a 80 Mhz SH-3 HD6417709 CPU. @@ -149,6 +151,7 @@ config CPU_SUBTYPE_SH7760 bool "Support SH7760 processor" select CPU_SH4 select CPU_HAS_INTC2_IRQ + select CPU_HAS_IPR_IRQ config CPU_SUBTYPE_SH4_202 bool "Support SH4-202 processor" diff --git a/arch/sh/mm/cache-debugfs.c b/arch/sh/mm/cache-debugfs.c index e0122bd..de6d2c9 100644 --- a/arch/sh/mm/cache-debugfs.c +++ b/arch/sh/mm/cache-debugfs.c @@ -46,10 +46,10 @@ static int cache_seq_show(struct seq_fil if (cache_type == CACHE_TYPE_DCACHE) { base = CACHE_OC_ADDRESS_ARRAY; - cache = &cpu_data->dcache; + cache = ¤t_cpu_data.dcache; } else { base = CACHE_IC_ADDRESS_ARRAY; - cache = &cpu_data->icache; + cache = ¤t_cpu_data.icache; } /* @@ -114,7 +114,7 @@ static int cache_debugfs_open(struct ino return single_open(file, cache_seq_show, inode->i_private); } -static struct file_operations cache_debugfs_fops = { +static const struct file_operations cache_debugfs_fops = { .owner = THIS_MODULE, .open = cache_debugfs_open, .read = seq_read, diff --git a/arch/sh/mm/cache-sh3.c b/arch/sh/mm/cache-sh3.c index 838731f..6d1dbec 100644 --- a/arch/sh/mm/cache-sh3.c +++ b/arch/sh/mm/cache-sh3.c @@ -44,11 +44,11 @@ void __flush_wback_region(void *start, i for (v = begin; v < end; v+=L1_CACHE_BYTES) { unsigned long addrstart = CACHE_OC_ADDRESS_ARRAY; - for (j = 0; j < cpu_data->dcache.ways; j++) { + for (j = 0; j < current_cpu_data.dcache.ways; j++) { unsigned long data, addr, p; p = __pa(v); - addr = addrstart | (v & cpu_data->dcache.entry_mask); + addr = addrstart | (v & current_cpu_data.dcache.entry_mask); local_irq_save(flags); data = ctrl_inl(addr); @@ -60,7 +60,7 @@ void __flush_wback_region(void *start, i break; } local_irq_restore(flags); - addrstart += cpu_data->dcache.way_incr; + addrstart += current_cpu_data.dcache.way_incr; } } } @@ -85,7 +85,7 @@ void __flush_purge_region(void *start, i data = (v & 0xfffffc00); /* _Virtual_ address, ~U, ~V */ addr = CACHE_OC_ADDRESS_ARRAY | - (v & cpu_data->dcache.entry_mask) | SH_CACHE_ASSOC; + (v & current_cpu_data.dcache.entry_mask) | SH_CACHE_ASSOC; ctrl_outl(data, addr); } } diff --git a/arch/sh/mm/cache-sh4.c b/arch/sh/mm/cache-sh4.c index c695515..e0cd4b7 100644 --- a/arch/sh/mm/cache-sh4.c +++ b/arch/sh/mm/cache-sh4.c @@ -54,21 +54,21 @@ static void __init emit_cache_params(voi ctrl_inl(CCN_CVR), ctrl_inl(CCN_PRR)); printk("I-cache : n_ways=%d n_sets=%d way_incr=%d\n", - cpu_data->icache.ways, - cpu_data->icache.sets, - cpu_data->icache.way_incr); + current_cpu_data.icache.ways, + current_cpu_data.icache.sets, + current_cpu_data.icache.way_incr); printk("I-cache : entry_mask=0x%08x alias_mask=0x%08x n_aliases=%d\n", - cpu_data->icache.entry_mask, - cpu_data->icache.alias_mask, - cpu_data->icache.n_aliases); + current_cpu_data.icache.entry_mask, + current_cpu_data.icache.alias_mask, + current_cpu_data.icache.n_aliases); printk("D-cache : n_ways=%d n_sets=%d way_incr=%d\n", - cpu_data->dcache.ways, - cpu_data->dcache.sets, - cpu_data->dcache.way_incr); + current_cpu_data.dcache.ways, + current_cpu_data.dcache.sets, + current_cpu_data.dcache.way_incr); printk("D-cache : entry_mask=0x%08x alias_mask=0x%08x n_aliases=%d\n", - cpu_data->dcache.entry_mask, - cpu_data->dcache.alias_mask, - cpu_data->dcache.n_aliases); + current_cpu_data.dcache.entry_mask, + current_cpu_data.dcache.alias_mask, + current_cpu_data.dcache.n_aliases); if (!__flush_dcache_segment_fn) panic("unknown number of cache ways\n"); @@ -87,10 +87,10 @@ void __init p3_cache_init(void) { int i; - compute_alias(&cpu_data->icache); - compute_alias(&cpu_data->dcache); + compute_alias(¤t_cpu_data.icache); + compute_alias(¤t_cpu_data.dcache); - switch (cpu_data->dcache.ways) { + switch (current_cpu_data.dcache.ways) { case 1: __flush_dcache_segment_fn = __flush_dcache_segment_1way; break; @@ -110,7 +110,7 @@ void __init p3_cache_init(void) if (ioremap_page_range(P3SEG, P3SEG + (PAGE_SIZE * 4), 0, PAGE_KERNEL)) panic("%s failed.", __FUNCTION__); - for (i = 0; i < cpu_data->dcache.n_aliases; i++) + for (i = 0; i < current_cpu_data.dcache.n_aliases; i++) mutex_init(&p3map_mutex[i]); } @@ -200,13 +200,14 @@ void flush_cache_sigtramp(unsigned long : /* no output */ : "m" (__m(v))); - index = CACHE_IC_ADDRESS_ARRAY | (v & cpu_data->icache.entry_mask); + index = CACHE_IC_ADDRESS_ARRAY | + (v & current_cpu_data.icache.entry_mask); local_irq_save(flags); jump_to_P2(); - for (i = 0; i < cpu_data->icache.ways; - i++, index += cpu_data->icache.way_incr) + for (i = 0; i < current_cpu_data.icache.ways; + i++, index += current_cpu_data.icache.way_incr) ctrl_outl(0, index); /* Clear out Valid-bit */ back_to_P1(); @@ -223,7 +224,7 @@ static inline void flush_cache_4096(unsi * All types of SH-4 require PC to be in P2 to operate on the I-cache. * Some types of SH-4 require PC to be in P2 to operate on the D-cache. */ - if ((cpu_data->flags & CPU_HAS_P2_FLUSH_BUG) || + if ((current_cpu_data.flags & CPU_HAS_P2_FLUSH_BUG) || (start < CACHE_OC_ADDRESS_ARRAY)) exec_offset = 0x20000000; @@ -236,16 +237,26 @@ static inline void flush_cache_4096(unsi /* * Write back & invalidate the D-cache of the page. * (To avoid "alias" issues) + * + * This uses a lazy write-back on UP, which is explicitly + * disabled on SMP. */ void flush_dcache_page(struct page *page) { - if (test_bit(PG_mapped, &page->flags)) { +#ifndef CONFIG_SMP + struct address_space *mapping = page_mapping(page); + + if (mapping && !mapping_mapped(mapping)) + set_bit(PG_dcache_dirty, &page->flags); + else +#endif + { unsigned long phys = PHYSADDR(page_address(page)); unsigned long addr = CACHE_OC_ADDRESS_ARRAY; int i, n; /* Loop all the D-cache */ - n = cpu_data->dcache.n_aliases; + n = current_cpu_data.dcache.n_aliases; for (i = 0; i < n; i++, addr += 4096) flush_cache_4096(addr, phys); } @@ -277,7 +288,7 @@ static inline void flush_icache_all(void void flush_dcache_all(void) { - (*__flush_dcache_segment_fn)(0UL, cpu_data->dcache.way_size); + (*__flush_dcache_segment_fn)(0UL, current_cpu_data.dcache.way_size); wmb(); } @@ -291,8 +302,8 @@ static void __flush_cache_mm(struct mm_s unsigned long end) { unsigned long d = 0, p = start & PAGE_MASK; - unsigned long alias_mask = cpu_data->dcache.alias_mask; - unsigned long n_aliases = cpu_data->dcache.n_aliases; + unsigned long alias_mask = current_cpu_data.dcache.alias_mask; + unsigned long n_aliases = current_cpu_data.dcache.n_aliases; unsigned long select_bit; unsigned long all_aliases_mask; unsigned long addr_offset; @@ -379,7 +390,7 @@ void flush_cache_mm(struct mm_struct *mm * If cache is only 4k-per-way, there are never any 'aliases'. Since * the cache is physically tagged, the data can just be left in there. */ - if (cpu_data->dcache.n_aliases == 0) + if (current_cpu_data.dcache.n_aliases == 0) return; /* @@ -416,7 +427,7 @@ void flush_cache_page(struct vm_area_str unsigned long phys = pfn << PAGE_SHIFT; unsigned int alias_mask; - alias_mask = cpu_data->dcache.alias_mask; + alias_mask = current_cpu_data.dcache.alias_mask; /* We only need to flush D-cache when we have alias */ if ((address^phys) & alias_mask) { @@ -430,7 +441,7 @@ void flush_cache_page(struct vm_area_str phys); } - alias_mask = cpu_data->icache.alias_mask; + alias_mask = current_cpu_data.icache.alias_mask; if (vma->vm_flags & VM_EXEC) { /* * Evict entries from the portion of the cache from which code @@ -462,7 +473,7 @@ void flush_cache_range(struct vm_area_st * If cache is only 4k-per-way, there are never any 'aliases'. Since * the cache is physically tagged, the data can just be left in there. */ - if (cpu_data->dcache.n_aliases == 0) + if (current_cpu_data.dcache.n_aliases == 0) return; /* @@ -523,7 +534,7 @@ static void __flush_cache_4096(unsigned unsigned long a, ea, p; unsigned long temp_pc; - dcache = &cpu_data->dcache; + dcache = ¤t_cpu_data.dcache; /* Write this way for better assembly. */ way_count = dcache->ways; way_incr = dcache->way_incr; @@ -598,7 +609,7 @@ static void __flush_dcache_segment_1way( base_addr = ((base_addr >> 16) << 16); base_addr |= start; - dcache = &cpu_data->dcache; + dcache = ¤t_cpu_data.dcache; linesz = dcache->linesz; way_incr = dcache->way_incr; way_size = dcache->way_size; @@ -640,7 +651,7 @@ static void __flush_dcache_segment_2way( base_addr = ((base_addr >> 16) << 16); base_addr |= start; - dcache = &cpu_data->dcache; + dcache = ¤t_cpu_data.dcache; linesz = dcache->linesz; way_incr = dcache->way_incr; way_size = dcache->way_size; @@ -699,7 +710,7 @@ static void __flush_dcache_segment_4way( base_addr = ((base_addr >> 16) << 16); base_addr |= start; - dcache = &cpu_data->dcache; + dcache = ¤t_cpu_data.dcache; linesz = dcache->linesz; way_incr = dcache->way_incr; way_size = dcache->way_size; diff --git a/arch/sh/mm/cache-sh7705.c b/arch/sh/mm/cache-sh7705.c index 045abdf..31f8deb 100644 --- a/arch/sh/mm/cache-sh7705.c +++ b/arch/sh/mm/cache-sh7705.c @@ -3,11 +3,11 @@ * * Copyright (C) 1999, 2000 Niibe Yutaka * Copyright (C) 2004 Alex Song + * Copyright (C) 2006 Paul Mundt * * This file is subject to the terms and conditions of the GNU General Public * License. See the file "COPYING" in the main directory of this archive * for more details. - * */ #include #include @@ -32,9 +32,9 @@ static inline void cache_wback_all(void) { unsigned long ways, waysize, addrstart; - ways = cpu_data->dcache.ways; - waysize = cpu_data->dcache.sets; - waysize <<= cpu_data->dcache.entry_shift; + ways = current_cpu_data.dcache.ways; + waysize = current_cpu_data.dcache.sets; + waysize <<= current_cpu_data.dcache.entry_shift; addrstart = CACHE_OC_ADDRESS_ARRAY; @@ -43,7 +43,7 @@ static inline void cache_wback_all(void) for (addr = addrstart; addr < addrstart + waysize; - addr += cpu_data->dcache.linesz) { + addr += current_cpu_data.dcache.linesz) { unsigned long data; int v = SH_CACHE_UPDATED | SH_CACHE_VALID; @@ -51,10 +51,9 @@ static inline void cache_wback_all(void) if ((data & v) == v) ctrl_outl(data & ~v, addr); - } - addrstart += cpu_data->dcache.way_incr; + addrstart += current_cpu_data.dcache.way_incr; } while (--ways); } @@ -94,9 +93,9 @@ static void __flush_dcache_page(unsigned local_irq_save(flags); jump_to_P2(); - ways = cpu_data->dcache.ways; - waysize = cpu_data->dcache.sets; - waysize <<= cpu_data->dcache.entry_shift; + ways = current_cpu_data.dcache.ways; + waysize = current_cpu_data.dcache.sets; + waysize <<= current_cpu_data.dcache.entry_shift; addrstart = CACHE_OC_ADDRESS_ARRAY; @@ -105,7 +104,7 @@ static void __flush_dcache_page(unsigned for (addr = addrstart; addr < addrstart + waysize; - addr += cpu_data->dcache.linesz) { + addr += current_cpu_data.dcache.linesz) { unsigned long data; data = ctrl_inl(addr) & (0x1ffffC00 | SH_CACHE_VALID); @@ -115,7 +114,7 @@ static void __flush_dcache_page(unsigned } } - addrstart += cpu_data->dcache.way_incr; + addrstart += current_cpu_data.dcache.way_incr; } while (--ways); back_to_P1(); @@ -128,7 +127,11 @@ static void __flush_dcache_page(unsigned */ void flush_dcache_page(struct page *page) { - if (test_bit(PG_mapped, &page->flags)) + struct address_space *mapping = page_mapping(page); + + if (mapping && !mapping_mapped(mapping)) + set_bit(PG_dcache_dirty, &page->flags); + else __flush_dcache_page(PHYSADDR(page_address(page))); } diff --git a/arch/sh/mm/fault.c b/arch/sh/mm/fault.c index 716ebf5..fa5d7f0 100644 --- a/arch/sh/mm/fault.c +++ b/arch/sh/mm/fault.c @@ -17,6 +17,7 @@ #include #include #include #include +#include #include extern void die(const char *,struct pt_regs *,long); @@ -224,3 +225,89 @@ do_sigbus: if (!user_mode(regs)) goto no_context; } + +#ifdef CONFIG_SH_STORE_QUEUES +/* + * This is a special case for the SH-4 store queues, as pages for this + * space still need to be faulted in before it's possible to flush the + * store queue cache for writeout to the remapped region. + */ +#define P3_ADDR_MAX (P4SEG_STORE_QUE + 0x04000000) +#else +#define P3_ADDR_MAX P4SEG +#endif + +/* + * Called with interrupts disabled. + */ +asmlinkage int __kprobes __do_page_fault(struct pt_regs *regs, + unsigned long writeaccess, + unsigned long address) +{ + pgd_t *pgd; + pud_t *pud; + pmd_t *pmd; + pte_t *pte; + pte_t entry; + struct mm_struct *mm = current->mm; + spinlock_t *ptl; + int ret = 1; + +#ifdef CONFIG_SH_KGDB + if (kgdb_nofault && kgdb_bus_err_hook) + kgdb_bus_err_hook(); +#endif + + /* + * We don't take page faults for P1, P2, and parts of P4, these + * are always mapped, whether it be due to legacy behaviour in + * 29-bit mode, or due to PMB configuration in 32-bit mode. + */ + if (address >= P3SEG && address < P3_ADDR_MAX) { + pgd = pgd_offset_k(address); + mm = NULL; + } else { + if (unlikely(address >= TASK_SIZE || !mm)) + return 1; + + pgd = pgd_offset(mm, address); + } + + pud = pud_offset(pgd, address); + if (pud_none_or_clear_bad(pud)) + return 1; + pmd = pmd_offset(pud, address); + if (pmd_none_or_clear_bad(pmd)) + return 1; + + if (mm) + pte = pte_offset_map_lock(mm, pmd, address, &ptl); + else + pte = pte_offset_kernel(pmd, address); + + entry = *pte; + if (unlikely(pte_none(entry) || pte_not_present(entry))) + goto unlock; + if (unlikely(writeaccess && !pte_write(entry))) + goto unlock; + + if (writeaccess) + entry = pte_mkdirty(entry); + entry = pte_mkyoung(entry); + +#ifdef CONFIG_CPU_SH4 + /* + * ITLB is not affected by "ldtlb" instruction. + * So, we need to flush the entry by ourselves. + */ + local_flush_tlb_one(get_asid(), address & PAGE_MASK); +#endif + + set_pte(pte, entry); + update_mmu_cache(NULL, address, entry); + ret = 0; +unlock: + if (mm) + pte_unmap_unlock(pte, ptl); + return ret; +} diff --git a/arch/sh/mm/init.c b/arch/sh/mm/init.c index 29bd37b..ae957a9 100644 --- a/arch/sh/mm/init.c +++ b/arch/sh/mm/init.c @@ -39,11 +39,6 @@ #include DEFINE_PER_CPU(struct mmu_gather, mmu_gathers); pgd_t swapper_pg_dir[PTRS_PER_PGD]; -/* - * Cache of MMU context last used. - */ -unsigned long mmu_context_cache = NO_CONTEXT; - #ifdef CONFIG_MMU /* It'd be good if these lines were in the standard header file. */ #define START_PFN (NODE_DATA(0)->bdata->node_boot_start >> PAGE_SHIFT) @@ -111,7 +106,7 @@ static void set_pte_phys(unsigned long a set_pte(pte, pfn_pte(phys >> PAGE_SHIFT, prot)); - __flush_tlb_page(get_asid(), addr); + flush_tlb_one(get_asid(), addr); } /* @@ -158,7 +153,6 @@ void __init paging_init(void) * Setup some defaults for the zone sizes.. these should be safe * regardless of distcontiguous memory or MMU settings. */ - zones_size[ZONE_DMA] = 0 >> PAGE_SHIFT; zones_size[ZONE_NORMAL] = __MEMORY_SIZE >> PAGE_SHIFT; #ifdef CONFIG_HIGHMEM zones_size[ZONE_HIGHMEM] = 0 >> PAGE_SHIFT; @@ -170,8 +164,6 @@ #ifdef CONFIG_MMU * the zone sizes accordingly, in addition to turning it on. */ { - unsigned long max_dma, low, start_pfn; - /* We don't need to map the kernel through the TLB, as * it is permanatly mapped using P1. So clear the * entire pgd. */ @@ -179,19 +171,7 @@ #ifdef CONFIG_MMU /* Turn on the MMU */ enable_mmu(); - - /* Fixup the zone sizes */ - start_pfn = START_PFN; - max_dma = virt_to_phys((char *)MAX_DMA_ADDRESS) >> PAGE_SHIFT; - low = MAX_LOW_PFN; - - if (low < max_dma) { - zones_size[ZONE_DMA] = low - start_pfn; - zones_size[ZONE_NORMAL] = 0; - } else { - zones_size[ZONE_DMA] = max_dma - start_pfn; - zones_size[ZONE_NORMAL] = low - max_dma; - } + zones_size[ZONE_NORMAL] = MAX_LOW_PFN - START_PFN; } /* Set an initial value for the MMU.TTB so we don't have to diff --git a/arch/sh/mm/ioremap.c b/arch/sh/mm/ioremap.c index 90b494a..be03d74 100644 --- a/arch/sh/mm/ioremap.c +++ b/arch/sh/mm/ioremap.c @@ -45,12 +45,6 @@ void __iomem *__ioremap(unsigned long ph return NULL; /* - * Don't remap the low PCI/ISA area, it's always mapped.. - */ - if (phys_addr >= 0xA0000 && last_addr < 0x100000) - return (void __iomem *)phys_to_virt(phys_addr); - - /* * If we're on an SH7751 or SH7780 PCI controller, PCI memory is * mapped at the end of the address space (typically 0xfd000000) * in a non-translatable area, so mapping through page tables for diff --git a/arch/sh/mm/pg-sh4.c b/arch/sh/mm/pg-sh4.c index 3f98d2a..969efec 100644 --- a/arch/sh/mm/pg-sh4.c +++ b/arch/sh/mm/pg-sh4.c @@ -13,7 +13,7 @@ #include extern struct mutex p3map_mutex[]; -#define CACHE_ALIAS (cpu_data->dcache.alias_mask) +#define CACHE_ALIAS (current_cpu_data.dcache.alias_mask) /* * clear_user_page @@ -23,7 +23,6 @@ #define CACHE_ALIAS (cpu_data->dcache.al */ void clear_user_page(void *to, unsigned long address, struct page *page) { - __set_bit(PG_mapped, &page->flags); if (((address ^ (unsigned long)to) & CACHE_ALIAS) == 0) clear_page(to); else { @@ -40,7 +39,7 @@ void clear_user_page(void *to, unsigned mutex_lock(&p3map_mutex[(address & CACHE_ALIAS)>>12]); set_pte(pte, entry); local_irq_save(flags); - __flush_tlb_page(get_asid(), p3_addr); + flush_tlb_one(get_asid(), p3_addr); local_irq_restore(flags); update_mmu_cache(NULL, p3_addr, entry); __clear_user_page((void *)p3_addr, to); @@ -59,7 +58,6 @@ void clear_user_page(void *to, unsigned void copy_user_page(void *to, void *from, unsigned long address, struct page *page) { - __set_bit(PG_mapped, &page->flags); if (((address ^ (unsigned long)to) & CACHE_ALIAS) == 0) copy_page(to, from); else { @@ -76,7 +74,7 @@ void copy_user_page(void *to, void *from mutex_lock(&p3map_mutex[(address & CACHE_ALIAS)>>12]); set_pte(pte, entry); local_irq_save(flags); - __flush_tlb_page(get_asid(), p3_addr); + flush_tlb_one(get_asid(), p3_addr); local_irq_restore(flags); update_mmu_cache(NULL, p3_addr, entry); __copy_user_page((void *)p3_addr, from, to); @@ -84,23 +82,3 @@ void copy_user_page(void *to, void *from mutex_unlock(&p3map_mutex[(address & CACHE_ALIAS)>>12]); } } - -/* - * For SH-4, we have our own implementation for ptep_get_and_clear - */ -inline pte_t ptep_get_and_clear(struct mm_struct *mm, unsigned long addr, pte_t *ptep) -{ - pte_t pte = *ptep; - - pte_clear(mm, addr, ptep); - if (!pte_not_present(pte)) { - unsigned long pfn = pte_pfn(pte); - if (pfn_valid(pfn)) { - struct page *page = pfn_to_page(pfn); - struct address_space *mapping = page_mapping(page); - if (!mapping || !mapping_writably_mapped(mapping)) - __clear_bit(PG_mapped, &page->flags); - } - } - return pte; -} diff --git a/arch/sh/mm/pg-sh7705.c b/arch/sh/mm/pg-sh7705.c index ff9ece9..887ab9d 100644 --- a/arch/sh/mm/pg-sh7705.c +++ b/arch/sh/mm/pg-sh7705.c @@ -7,9 +7,7 @@ * This file is subject to the terms and conditions of the GNU General Public * License. See the file "COPYING" in the main directory of this archive * for more details. - * */ - #include #include #include @@ -45,13 +43,13 @@ static inline void __flush_purge_virtual p = __pa(p1_begin); - ways = cpu_data->dcache.ways; + ways = current_cpu_data.dcache.ways; addr = CACHE_OC_ADDRESS_ARRAY; do { unsigned long data; - addr |= (v & cpu_data->dcache.entry_mask); + addr |= (v & current_cpu_data.dcache.entry_mask); data = ctrl_inl(addr); if ((data & CACHE_PHYSADDR_MASK) == @@ -60,7 +58,7 @@ static inline void __flush_purge_virtual ctrl_outl(data, addr); } - addr += cpu_data->dcache.way_incr; + addr += current_cpu_data.dcache.way_incr; } while (--ways); p1_begin += L1_CACHE_BYTES; @@ -76,7 +74,6 @@ void clear_user_page(void *to, unsigned { struct page *page = virt_to_page(to); - __set_bit(PG_mapped, &page->flags); if (((address ^ (unsigned long)to) & CACHE_ALIAS) == 0) { clear_page(to); __flush_wback_region(to, PAGE_SIZE); @@ -95,12 +92,11 @@ void clear_user_page(void *to, unsigned * @from: P1 address * @address: U0 address to be mapped */ -void copy_user_page(void *to, void *from, unsigned long address, struct page *pg) +void copy_user_page(void *to, void *from, unsigned long address, + struct page *pg) { struct page *page = virt_to_page(to); - - __set_bit(PG_mapped, &page->flags); if (((address ^ (unsigned long)to) & CACHE_ALIAS) == 0) { copy_page(to, from); __flush_wback_region(to, PAGE_SIZE); @@ -112,26 +108,3 @@ void copy_user_page(void *to, void *from __flush_wback_region(to, PAGE_SIZE); } } - -/* - * For SH7705, we have our own implementation for ptep_get_and_clear - * Copied from pg-sh4.c - */ -inline pte_t ptep_get_and_clear(struct mm_struct *mm, unsigned long addr, pte_t *ptep) -{ - pte_t pte = *ptep; - - pte_clear(mm, addr, ptep); - if (!pte_not_present(pte)) { - unsigned long pfn = pte_pfn(pte); - if (pfn_valid(pfn)) { - struct page *page = pfn_to_page(pfn); - struct address_space *mapping = page_mapping(page); - if (!mapping || !mapping_writably_mapped(mapping)) - __clear_bit(PG_mapped, &page->flags); - } - } - - return pte; -} - diff --git a/arch/sh/mm/pmb.c b/arch/sh/mm/pmb.c index b60ad83..d0d45e2 100644 --- a/arch/sh/mm/pmb.c +++ b/arch/sh/mm/pmb.c @@ -378,7 +378,7 @@ static int pmb_debugfs_open(struct inode return single_open(file, pmb_seq_show, NULL); } -static struct file_operations pmb_debugfs_fops = { +static const struct file_operations pmb_debugfs_fops = { .owner = THIS_MODULE, .open = pmb_debugfs_open, .read = seq_read, diff --git a/arch/sh/mm/tlb-flush.c b/arch/sh/mm/tlb-flush.c index 73ec7f6..d2f7b4a 100644 --- a/arch/sh/mm/tlb-flush.c +++ b/arch/sh/mm/tlb-flush.c @@ -2,24 +2,28 @@ * TLB flushing operations for SH with an MMU. * * Copyright (C) 1999 Niibe Yutaka - * Copyright (C) 2003 Paul Mundt + * Copyright (C) 2003 - 2006 Paul Mundt * * This file is subject to the terms and conditions of the GNU General Public * License. See the file "COPYING" in the main directory of this archive * for more details. */ #include +#include #include #include +#include -void flush_tlb_page(struct vm_area_struct *vma, unsigned long page) +void local_flush_tlb_page(struct vm_area_struct *vma, unsigned long page) { - if (vma->vm_mm && vma->vm_mm->context.id != NO_CONTEXT) { + unsigned int cpu = smp_processor_id(); + + if (vma->vm_mm && cpu_context(cpu, vma->vm_mm) != NO_CONTEXT) { unsigned long flags; unsigned long asid; unsigned long saved_asid = MMU_NO_ASID; - asid = vma->vm_mm->context.id & MMU_CONTEXT_ASID_MASK; + asid = cpu_asid(cpu, vma->vm_mm); page &= PAGE_MASK; local_irq_save(flags); @@ -27,33 +31,34 @@ void flush_tlb_page(struct vm_area_struc saved_asid = get_asid(); set_asid(asid); } - __flush_tlb_page(asid, page); + local_flush_tlb_one(asid, page); if (saved_asid != MMU_NO_ASID) set_asid(saved_asid); local_irq_restore(flags); } } -void flush_tlb_range(struct vm_area_struct *vma, unsigned long start, - unsigned long end) +void local_flush_tlb_range(struct vm_area_struct *vma, unsigned long start, + unsigned long end) { struct mm_struct *mm = vma->vm_mm; + unsigned int cpu = smp_processor_id(); - if (mm->context.id != NO_CONTEXT) { + if (cpu_context(cpu, mm) != NO_CONTEXT) { unsigned long flags; int size; local_irq_save(flags); size = (end - start + (PAGE_SIZE - 1)) >> PAGE_SHIFT; if (size > (MMU_NTLB_ENTRIES/4)) { /* Too many TLB to flush */ - mm->context.id = NO_CONTEXT; + cpu_context(cpu, mm) = NO_CONTEXT; if (mm == current->mm) - activate_context(mm); + activate_context(mm, cpu); } else { unsigned long asid; unsigned long saved_asid = MMU_NO_ASID; - asid = mm->context.id & MMU_CONTEXT_ASID_MASK; + asid = cpu_asid(cpu, mm); start &= PAGE_MASK; end += (PAGE_SIZE - 1); end &= PAGE_MASK; @@ -62,7 +67,7 @@ void flush_tlb_range(struct vm_area_stru set_asid(asid); } while (start < end) { - __flush_tlb_page(asid, start); + local_flush_tlb_one(asid, start); start += PAGE_SIZE; } if (saved_asid != MMU_NO_ASID) @@ -72,26 +77,27 @@ void flush_tlb_range(struct vm_area_stru } } -void flush_tlb_kernel_range(unsigned long start, unsigned long end) +void local_flush_tlb_kernel_range(unsigned long start, unsigned long end) { + unsigned int cpu = smp_processor_id(); unsigned long flags; int size; local_irq_save(flags); size = (end - start + (PAGE_SIZE - 1)) >> PAGE_SHIFT; if (size > (MMU_NTLB_ENTRIES/4)) { /* Too many TLB to flush */ - flush_tlb_all(); + local_flush_tlb_all(); } else { unsigned long asid; unsigned long saved_asid = get_asid(); - asid = init_mm.context.id & MMU_CONTEXT_ASID_MASK; + asid = cpu_asid(cpu, &init_mm); start &= PAGE_MASK; end += (PAGE_SIZE - 1); end &= PAGE_MASK; set_asid(asid); while (start < end) { - __flush_tlb_page(asid, start); + local_flush_tlb_one(asid, start); start += PAGE_SIZE; } set_asid(saved_asid); @@ -99,22 +105,24 @@ void flush_tlb_kernel_range(unsigned lon local_irq_restore(flags); } -void flush_tlb_mm(struct mm_struct *mm) +void local_flush_tlb_mm(struct mm_struct *mm) { + unsigned int cpu = smp_processor_id(); + /* Invalidate all TLB of this process. */ /* Instead of invalidating each TLB, we get new MMU context. */ - if (mm->context.id != NO_CONTEXT) { + if (cpu_context(cpu, mm) != NO_CONTEXT) { unsigned long flags; local_irq_save(flags); - mm->context.id = NO_CONTEXT; + cpu_context(cpu, mm) = NO_CONTEXT; if (mm == current->mm) - activate_context(mm); + activate_context(mm, cpu); local_irq_restore(flags); } } -void flush_tlb_all(void) +void local_flush_tlb_all(void) { unsigned long flags, status; @@ -132,3 +140,54 @@ void flush_tlb_all(void) ctrl_barrier(); local_irq_restore(flags); } + +void update_mmu_cache(struct vm_area_struct *vma, + unsigned long address, pte_t pte) +{ + unsigned long flags; + unsigned long pteval; + unsigned long vpn; + struct page *page; + unsigned long pfn = pte_pfn(pte); + struct address_space *mapping; + + if (!pfn_valid(pfn)) + return; + + page = pfn_to_page(pfn); + mapping = page_mapping(page); + if (mapping) { + unsigned long phys = pte_val(pte) & PTE_PHYS_MASK; + int dirty = test_and_clear_bit(PG_dcache_dirty, &page->flags); + + if (dirty) + __flush_wback_region((void *)P1SEGADDR(phys), + PAGE_SIZE); + } + + local_irq_save(flags); + + /* Set PTEH register */ + vpn = (address & MMU_VPN_MASK) | get_asid(); + ctrl_outl(vpn, MMU_PTEH); + + pteval = pte_val(pte); + +#ifdef CONFIG_CPU_HAS_PTEA + /* Set PTEA register */ + /* TODO: make this look less hacky */ + ctrl_outl(((pteval >> 28) & 0xe) | (pteval & 0x1), MMU_PTEA); +#endif + + /* Set PTEL register */ + pteval &= _PAGE_FLAGS_HARDWARE_MASK; /* drop software flags */ +#if defined(CONFIG_SH_WRITETHROUGH) && defined(CONFIG_CPU_SH4) + pteval |= _PAGE_WT; +#endif + /* conveniently, we want all the software flags to be 0 anyway */ + ctrl_outl(pteval, MMU_PTEL); + + /* Load the TLB */ + asm volatile("ldtlb": /* no output */ : /* no input */ : "memory"); + local_irq_restore(flags); +} diff --git a/arch/sh/mm/tlb-nommu.c b/arch/sh/mm/tlb-nommu.c index e55cfea..1ccca7c 100644 --- a/arch/sh/mm/tlb-nommu.c +++ b/arch/sh/mm/tlb-nommu.c @@ -13,39 +13,33 @@ #include /* * Nothing too terribly exciting here .. */ - -void flush_tlb(void) -{ - BUG(); -} - -void flush_tlb_all(void) +void local_flush_tlb_all(void) { BUG(); } -void flush_tlb_mm(struct mm_struct *mm) +void local_flush_tlb_mm(struct mm_struct *mm) { BUG(); } -void flush_tlb_range(struct vm_area_struct *vma, unsigned long start, +void local_flush_tlb_range(struct vm_area_struct *vma, unsigned long start, unsigned long end) { BUG(); } -void flush_tlb_page(struct vm_area_struct *vma, unsigned long page) +void local_flush_tlb_page(struct vm_area_struct *vma, unsigned long page) { BUG(); } -void __flush_tlb_page(unsigned long asid, unsigned long page) +void local_flush_tlb_one(unsigned long asid, unsigned long page) { BUG(); } -void flush_tlb_kernel_range(unsigned long start, unsigned long end) +void local_flush_tlb_kernel_range(unsigned long start, unsigned long end) { BUG(); } @@ -55,4 +49,3 @@ void update_mmu_cache(struct vm_area_str { BUG(); } - diff --git a/arch/sh/mm/tlb-sh3.c b/arch/sh/mm/tlb-sh3.c index 46b09e2..e5e76eb 100644 --- a/arch/sh/mm/tlb-sh3.c +++ b/arch/sh/mm/tlb-sh3.c @@ -8,71 +8,11 @@ * * Released under the terms of the GNU GPL v2.0. */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - +#include #include -#include -#include -#include #include -#include -void update_mmu_cache(struct vm_area_struct * vma, - unsigned long address, pte_t pte) -{ - unsigned long flags; - unsigned long pteval; - unsigned long vpn; - - /* Ptrace may call this routine. */ - if (vma && current->active_mm != vma->vm_mm) - return; - -#if defined(CONFIG_SH7705_CACHE_32KB) - { - struct page *page = pte_page(pte); - unsigned long pfn = pte_pfn(pte); - - if (pfn_valid(pfn) && !test_bit(PG_mapped, &page->flags)) { - unsigned long phys = pte_val(pte) & PTE_PHYS_MASK; - - __flush_wback_region((void *)P1SEGADDR(phys), - PAGE_SIZE); - __set_bit(PG_mapped, &page->flags); - } - } -#endif - - local_irq_save(flags); - - /* Set PTEH register */ - vpn = (address & MMU_VPN_MASK) | get_asid(); - ctrl_outl(vpn, MMU_PTEH); - - pteval = pte_val(pte); - - /* Set PTEL register */ - pteval &= _PAGE_FLAGS_HARDWARE_MASK; /* drop software flags */ - /* conveniently, we want all the software flags to be 0 anyway */ - ctrl_outl(pteval, MMU_PTEL); - - /* Load the TLB */ - asm volatile("ldtlb": /* no output */ : /* no input */ : "memory"); - local_irq_restore(flags); -} - -void __flush_tlb_page(unsigned long asid, unsigned long page) +void local_flush_tlb_one(unsigned long asid, unsigned long page) { unsigned long addr, data; int i, ways = MMU_NTLB_WAYS; @@ -86,7 +26,7 @@ void __flush_tlb_page(unsigned long asid addr = MMU_TLB_ADDRESS_ARRAY | (page & 0x1F000); data = (page & 0xfffe0000) | asid; /* VALID bit is off */ - if ((cpu_data->flags & CPU_HAS_MMU_PAGE_ASSOC)) { + if ((current_cpu_data.flags & CPU_HAS_MMU_PAGE_ASSOC)) { addr |= MMU_PAGE_ASSOC_BIT; ways = 1; /* we already know the way .. */ } @@ -94,4 +34,3 @@ void __flush_tlb_page(unsigned long asid for (i = 0; i < ways; i++) ctrl_outl(data, addr + (i << 8)); } - diff --git a/arch/sh/mm/tlb-sh4.c b/arch/sh/mm/tlb-sh4.c index 812b2d5..221e709 100644 --- a/arch/sh/mm/tlb-sh4.c +++ b/arch/sh/mm/tlb-sh4.c @@ -8,76 +8,11 @@ * * Released under the terms of the GNU GPL v2.0. */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - +#include #include -#include -#include -#include #include -#include -void update_mmu_cache(struct vm_area_struct * vma, - unsigned long address, pte_t pte) -{ - unsigned long flags; - unsigned long pteval; - unsigned long vpn; - struct page *page; - unsigned long pfn; - - /* Ptrace may call this routine. */ - if (vma && current->active_mm != vma->vm_mm) - return; - - pfn = pte_pfn(pte); - if (pfn_valid(pfn)) { - page = pfn_to_page(pfn); - if (!test_bit(PG_mapped, &page->flags)) { - unsigned long phys = pte_val(pte) & PTE_PHYS_MASK; - __flush_wback_region((void *)P1SEGADDR(phys), PAGE_SIZE); - __set_bit(PG_mapped, &page->flags); - } - } - - local_irq_save(flags); - - /* Set PTEH register */ - vpn = (address & MMU_VPN_MASK) | get_asid(); - ctrl_outl(vpn, MMU_PTEH); - - pteval = pte_val(pte); - - /* Set PTEA register */ - if (cpu_data->flags & CPU_HAS_PTEA) - /* TODO: make this look less hacky */ - ctrl_outl(((pteval >> 28) & 0xe) | (pteval & 0x1), MMU_PTEA); - - /* Set PTEL register */ - pteval &= _PAGE_FLAGS_HARDWARE_MASK; /* drop software flags */ -#ifdef CONFIG_SH_WRITETHROUGH - pteval |= _PAGE_WT; -#endif - /* conveniently, we want all the software flags to be 0 anyway */ - ctrl_outl(pteval, MMU_PTEL); - - /* Load the TLB */ - asm volatile("ldtlb": /* no output */ : /* no input */ : "memory"); - local_irq_restore(flags); -} - -void __flush_tlb_page(unsigned long asid, unsigned long page) +void local_flush_tlb_one(unsigned long asid, unsigned long page) { unsigned long addr, data; @@ -93,4 +28,3 @@ void __flush_tlb_page(unsigned long asid ctrl_outl(data, addr); back_to_P1(); } - diff --git a/arch/sh/oprofile/op_model_sh7750.c b/arch/sh/oprofile/op_model_sh7750.c index 60402ee..ebee7e2 100644 --- a/arch/sh/oprofile/op_model_sh7750.c +++ b/arch/sh/oprofile/op_model_sh7750.c @@ -187,7 +187,7 @@ static ssize_t sh7750_write_count(struct return count; } -static struct file_operations count_fops = { +static const struct file_operations count_fops = { .read = sh7750_read_count, .write = sh7750_write_count, }; @@ -259,7 +259,7 @@ static struct oprofile_operations sh7750 int __init oprofile_arch_init(struct oprofile_operations **ops) { - if (!(cpu_data->flags & CPU_HAS_PERF_COUNTER)) + if (!(current_cpu_data.flags & CPU_HAS_PERF_COUNTER)) return -ENODEV; sh7750_perf_counter_ops.cpu_type = (char *)get_cpu_subtype(); diff --git a/arch/sh/tools/mach-types b/arch/sh/tools/mach-types index 0571755..4fe0f94 100644 --- a/arch/sh/tools/mach-types +++ b/arch/sh/tools/mach-types @@ -16,7 +16,6 @@ HD64461 HD64461 HD64465 HD64465 SATURN SH_SATURN DREAMCAST SH_DREAMCAST -BIGSUR SH_BIGSUR MPC1211 SH_MPC1211 SNAPGEAR SH_SECUREEDGE5410 HS7751RVOIP SH_HS7751RVOIP diff --git a/arch/sh64/Kconfig b/arch/sh64/Kconfig index 7bc0744..e14b533 100644 --- a/arch/sh64/Kconfig +++ b/arch/sh64/Kconfig @@ -36,9 +36,6 @@ config GENERIC_CALIBRATE_DELAY config RWSEM_XCHGADD_ALGORITHM bool -config GENERIC_ISA_DMA - bool - config ARCH_HAS_ILOG2_U32 bool default n diff --git a/arch/sh64/kernel/setup.c b/arch/sh64/kernel/setup.c index b9e7d54..53e9d20 100644 --- a/arch/sh64/kernel/setup.c +++ b/arch/sh64/kernel/setup.c @@ -83,7 +83,7 @@ #define RAMDISK_IMAGE_START_MASK 0x07FF #define RAMDISK_PROMPT_FLAG 0x8000 #define RAMDISK_LOAD_FLAG 0x4000 -static char command_line[COMMAND_LINE_SIZE] = { 0, }; +static char __initdata command_line[COMMAND_LINE_SIZE] = { 0, }; unsigned long long memory_start = CONFIG_MEMORY_START; unsigned long long memory_end = CONFIG_MEMORY_START + (CONFIG_MEMORY_SIZE_IN_MB * 1024 * 1024); @@ -95,8 +95,8 @@ static inline void parse_mem_cmdline (ch int len = 0; /* Save unparsed command line copy for /proc/cmdline */ - memcpy(saved_command_line, COMMAND_LINE, COMMAND_LINE_SIZE); - saved_command_line[COMMAND_LINE_SIZE-1] = '\0'; + memcpy(boot_command_line, COMMAND_LINE, COMMAND_LINE_SIZE); + boot_command_line[COMMAND_LINE_SIZE-1] = '\0'; for (;;) { /* diff --git a/arch/sh64/kernel/time.c b/arch/sh64/kernel/time.c index 9c4a38a..390b40d 100644 --- a/arch/sh64/kernel/time.c +++ b/arch/sh64/kernel/time.c @@ -579,12 +579,3 @@ #endif asm __volatile__ ("nop"); panic("Unexpected wakeup!\n"); } - -/* - * Scheduler clock - returns current time in nanosec units. - */ -unsigned long long sched_clock(void) -{ - return (unsigned long long)jiffies * (1000000000 / HZ); -} - diff --git a/arch/sh64/kernel/traps.c b/arch/sh64/kernel/traps.c index 224b7f5..c346d7e 100644 --- a/arch/sh64/kernel/traps.c +++ b/arch/sh64/kernel/traps.c @@ -910,30 +910,57 @@ #endif } static ctl_table unaligned_table[] = { - {1, "kernel_reports", &kernel_mode_unaligned_fixup_count, - sizeof(int), 0644, NULL, &proc_dointvec}, + { + .ctl_name = CTL_UNNUMBERED, + .procname = "kernel_reports", + .data = &kernel_mode_unaligned_fixup_count, + .maxlen = sizeof(int), + .mode = 0644, + .proc_handler = &proc_dointvec + }, #if defined(CONFIG_SH64_USER_MISALIGNED_FIXUP) - {2, "user_reports", &user_mode_unaligned_fixup_count, - sizeof(int), 0644, NULL, &proc_dointvec}, - {3, "user_enable", &user_mode_unaligned_fixup_enable, - sizeof(int), 0644, NULL, &proc_dointvec}, + { + .ctl_name = CTL_UNNUMBERED, + .procname = "user_reports", + .data = &user_mode_unaligned_fixup_count, + .maxlen = sizeof(int), + .mode = 0644, + .proc_handler = &proc_dointvec + }, + { + .ctl_name = CTL_UNNUMBERED, + .procname = "user_enable", + .data = &user_mode_unaligned_fixup_enable, + .maxlen = sizeof(int), + .mode = 0644, + .proc_handler = &proc_dointvec}, #endif - {0} + {} }; static ctl_table unaligned_root[] = { - {1, "unaligned_fixup", NULL, 0, 0555, unaligned_table}, - {0} + { + .ctl_name = CTL_UNNUMBERED, + .procname = "unaligned_fixup", + .mode = 0555, + unaligned_table + }, + {} }; static ctl_table sh64_root[] = { - {1, "sh64", NULL, 0, 0555, unaligned_root}, - {0} + { + .ctl_name = CTL_UNNUMBERED, + .procname = "sh64", + .mode = 0555, + .child = unaligned_root + }, + {} }; static struct ctl_table_header *sysctl_header; static int __init init_sysctl(void) { - sysctl_header = register_sysctl_table(sh64_root, 0); + sysctl_header = register_sysctl_table(sh64_root); return 0; } diff --git a/arch/sh64/kernel/vmlinux.lds.S b/arch/sh64/kernel/vmlinux.lds.S index 95c4d75..a59c5e9 100644 --- a/arch/sh64/kernel/vmlinux.lds.S +++ b/arch/sh64/kernel/vmlinux.lds.S @@ -115,9 +115,13 @@ #endif .con_initcall.init : C_PHYS(.con_initcall.init) { *(.con_initcall.init) } __con_initcall_end = .; SECURITY_INIT + +#ifdef CONFIG_BLK_DEV_INITRD __initramfs_start = .; .init.ramfs : C_PHYS(.init.ramfs) { *(.init.ramfs) } __initramfs_end = .; +#endif + . = ALIGN(PAGE_SIZE); __init_end = .; diff --git a/arch/sh64/mm/init.c b/arch/sh64/mm/init.c index 83295bd..5dc0878 100644 --- a/arch/sh64/mm/init.c +++ b/arch/sh64/mm/init.c @@ -118,10 +118,7 @@ void __init paging_init(void) mmu_context_cache = MMU_CONTEXT_FIRST_VERSION; - /* - * All memory is good as ZONE_NORMAL (fall-through) and ZONE_DMA. - */ - zones_size[ZONE_DMA] = MAX_LOW_PFN - START_PFN; + zones_size[ZONE_NORMAL] = MAX_LOW_PFN - START_PFN; NODE_DATA(0)->node_mem_map = NULL; free_area_init_node(0, NODE_DATA(0), zones_size, __MEMORY_START >> PAGE_SHIFT, 0); } diff --git a/arch/sparc/Kconfig b/arch/sparc/Kconfig index d0dec1e..bd992c0 100644 --- a/arch/sparc/Kconfig +++ b/arch/sparc/Kconfig @@ -13,6 +13,10 @@ config HIGHMEM bool default y +config ZONE_DMA + bool + default y + config GENERIC_ISA_DMA bool default y diff --git a/arch/sparc/kernel/Makefile b/arch/sparc/kernel/Makefile index 6616ee0..e795f28 100644 --- a/arch/sparc/kernel/Makefile +++ b/arch/sparc/kernel/Makefile @@ -12,7 +12,9 @@ obj-y := entry.o wof.o wuf.o etrap.o sys_sparc.o sunos_asm.o systbls.o \ time.o windows.o cpu.o devices.o sclow.o \ tadpole.o tick14.o ptrace.o sys_solaris.o \ - unaligned.o muldiv.o semaphore.o prom.o of_device.o + unaligned.o muldiv.o semaphore.o prom.o of_device.o devres.o + +devres-y = ../../../kernel/irq/devres.o obj-$(CONFIG_PCI) += pcic.o obj-$(CONFIG_SUN4) += sun4setup.o diff --git a/arch/sparc/kernel/apc.c b/arch/sparc/kernel/apc.c index 406dd94..d06a405 100644 --- a/arch/sparc/kernel/apc.c +++ b/arch/sparc/kernel/apc.c @@ -127,7 +127,7 @@ static int apc_ioctl(struct inode *inode return 0; } -static struct file_operations apc_fops = { +static const struct file_operations apc_fops = { .ioctl = apc_ioctl, .open = apc_open, .release = apc_release, diff --git a/arch/sparc/kernel/setup.c b/arch/sparc/kernel/setup.c index 383526a..eccd8e8 100644 --- a/arch/sparc/kernel/setup.c +++ b/arch/sparc/kernel/setup.c @@ -246,7 +246,7 @@ void __init setup_arch(char **cmdline_p) /* Initialize PROM console and command line. */ *cmdline_p = prom_getbootargs(); - strcpy(saved_command_line, *cmdline_p); + strcpy(boot_command_line, *cmdline_p); /* Set sparc_cpu_model */ sparc_cpu_model = sun_unknown; diff --git a/arch/sparc/kernel/sunos_ioctl.c b/arch/sparc/kernel/sunos_ioctl.c index a6ba3d2..32e8274 100644 --- a/arch/sparc/kernel/sunos_ioctl.c +++ b/arch/sparc/kernel/sunos_ioctl.c @@ -11,6 +11,7 @@ #include #include #include #include +#include #include #include #include diff --git a/arch/sparc/kernel/sys_sunos.c b/arch/sparc/kernel/sys_sunos.c index 0bf8c16..da6606f 100644 --- a/arch/sparc/kernel/sys_sunos.c +++ b/arch/sparc/kernel/sys_sunos.c @@ -859,14 +859,16 @@ asmlinkage int sunos_wait4(pid_t pid, un return ret; } -extern int kill_pg(int, int, int); asmlinkage int sunos_killpg(int pgrp, int sig) { int ret; - lock_kernel(); - ret = kill_pg(pgrp, sig, 0); - unlock_kernel(); + rcu_read_lock(); + ret = -EINVAL; + if (pgrp > 0) + ret = kill_pgrp(find_pid(pgrp), sig, 0); + rcu_read_unlock(); + return ret; } diff --git a/arch/sparc/kernel/time.c b/arch/sparc/kernel/time.c index 2fcce00..9bb1240 100644 --- a/arch/sparc/kernel/time.c +++ b/arch/sparc/kernel/time.c @@ -436,15 +436,6 @@ static inline unsigned long do_gettimeof return (*master_l10_counter >> 10) & 0x1fffff; } -/* - * Returns nanoseconds - * XXX This is a suboptimal implementation. - */ -unsigned long long sched_clock(void) -{ - return (unsigned long long)jiffies * (1000000000 / HZ); -} - /* Ok, my cute asm atomicity trick doesn't work anymore. * There are just too many variables that need to be protected * now (both members of xtime, et al.) diff --git a/arch/sparc/kernel/vmlinux.lds.S b/arch/sparc/kernel/vmlinux.lds.S index b73e6b9..e5c24e0 100644 --- a/arch/sparc/kernel/vmlinux.lds.S +++ b/arch/sparc/kernel/vmlinux.lds.S @@ -57,10 +57,14 @@ SECTIONS .con_initcall.init : { *(.con_initcall.init) } __con_initcall_end = .; SECURITY_INIT + +#ifdef CONFIG_BLK_DEV_INITRD . = ALIGN(4096); __initramfs_start = .; .init.ramfs : { *(.init.ramfs) } __initramfs_end = .; +#endif + . = ALIGN(32); __per_cpu_start = .; .data.percpu : { *(.data.percpu) } diff --git a/arch/sparc64/Kconfig b/arch/sparc64/Kconfig index d41f66a..f75a686 100644 --- a/arch/sparc64/Kconfig +++ b/arch/sparc64/Kconfig @@ -232,10 +232,6 @@ config LARGE_ALLOCS source "mm/Kconfig" -config GENERIC_ISA_DMA - bool - default y - config ISA bool help diff --git a/arch/sparc64/defconfig b/arch/sparc64/defconfig index 5a9e68b..0f44a6a 100644 --- a/arch/sparc64/defconfig +++ b/arch/sparc64/defconfig @@ -1,7 +1,7 @@ # # Automatically generated make config: don't edit -# Linux kernel version: 2.6.20-rc2 -# Thu Dec 28 15:09:49 2006 +# Linux kernel version: 2.6.20 +# Sun Feb 11 23:47:40 2007 # CONFIG_SPARC=y CONFIG_SPARC64=y @@ -49,7 +49,6 @@ # CONFIG_AUDIT is not set # CONFIG_IKCONFIG is not set CONFIG_SYSFS_DEPRECATED=y CONFIG_RELAY=y -CONFIG_INITRAMFS_SOURCE="" CONFIG_CC_OPTIMIZE_FOR_SIZE=y CONFIG_SYSCTL=y # CONFIG_EMBEDDED is not set @@ -144,14 +143,14 @@ # CONFIG_SPARSEMEM_STATIC is not set CONFIG_SPARSEMEM_EXTREME=y CONFIG_SPLIT_PTLOCK_CPUS=4 CONFIG_RESOURCES_64BIT=y -CONFIG_GENERIC_ISA_DMA=y +CONFIG_ZONE_DMA_FLAG=0 CONFIG_SBUS=y CONFIG_SBUSCHAR=y CONFIG_SUN_AUXIO=y CONFIG_SUN_IO=y CONFIG_PCI=y CONFIG_PCI_DOMAINS=y -# CONFIG_PCI_MULTITHREAD_PROBE is not set +CONFIG_PCI_MSI=y # CONFIG_PCI_DEBUG is not set CONFIG_SUN_OPENPROMFS=m CONFIG_SPARC32_COMPAT=y @@ -182,7 +181,9 @@ CONFIG_UNIX=y CONFIG_XFRM=y CONFIG_XFRM_USER=m # CONFIG_XFRM_SUB_POLICY is not set +CONFIG_XFRM_MIGRATE=y CONFIG_NET_KEY=m +CONFIG_NET_KEY_MIGRATE=y CONFIG_INET=y CONFIG_IP_MULTICAST=y # CONFIG_IP_ADVANCED_ROUTER is not set @@ -300,6 +301,7 @@ CONFIG_STANDALONE=y # CONFIG_PREVENT_FIRMWARE_BUILD is not set CONFIG_FW_LOADER=y # CONFIG_DEBUG_DRIVER is not set +# CONFIG_DEBUG_DEVRES is not set # CONFIG_SYS_HYPERVISOR is not set # @@ -393,6 +395,7 @@ # CONFIG_BLK_DEV_HPT366 is not set # CONFIG_BLK_DEV_JMICRON is not set # CONFIG_BLK_DEV_SC1200 is not set # CONFIG_BLK_DEV_PIIX is not set +# CONFIG_BLK_DEV_IT8213 is not set # CONFIG_BLK_DEV_IT821X is not set # CONFIG_BLK_DEV_NS87415 is not set # CONFIG_BLK_DEV_PDC202XX_OLD is not set @@ -402,6 +405,7 @@ # CONFIG_BLK_DEV_SIIMAGE is not set # CONFIG_BLK_DEV_SLC90E66 is not set # CONFIG_BLK_DEV_TRM290 is not set # CONFIG_BLK_DEV_VIA82CXXX is not set +# CONFIG_BLK_DEV_TC86C001 is not set # CONFIG_IDE_ARM is not set CONFIG_BLK_DEV_IDEDMA=y # CONFIG_IDEDMA_IVB is not set @@ -579,6 +583,7 @@ # CONFIG_SIS900 is not set # CONFIG_EPIC100 is not set # CONFIG_SUNDANCE is not set # CONFIG_VIA_RHINE is not set +# CONFIG_SC92031 is not set # # Ethernet (1000 Mbit) @@ -601,11 +606,13 @@ # CONFIG_VIA_VELOCITY is not set CONFIG_TIGON3=m CONFIG_BNX2=m # CONFIG_QLA3XXX is not set +# CONFIG_ATL1 is not set # # Ethernet (10000 Mbit) # # CONFIG_CHELSIO_T1 is not set +# CONFIG_CHELSIO_T3 is not set # CONFIG_IXGB is not set # CONFIG_S2IO is not set # CONFIG_MYRI10GE is not set @@ -627,8 +634,17 @@ # # CONFIG_WAN is not set # CONFIG_FDDI is not set # CONFIG_HIPPI is not set -# CONFIG_PPP is not set +CONFIG_PPP=m +CONFIG_PPP_MULTILINK=y +CONFIG_PPP_FILTER=y +CONFIG_PPP_ASYNC=m +CONFIG_PPP_SYNC_TTY=m +CONFIG_PPP_DEFLATE=m +CONFIG_PPP_BSDCOMP=m +CONFIG_PPP_MPPE=m +CONFIG_PPPOE=m # CONFIG_SLIP is not set +CONFIG_SLHC=m # CONFIG_NET_FC is not set # CONFIG_SHAPER is not set # CONFIG_NETCONSOLE is not set @@ -1043,6 +1059,11 @@ CONFIG_SND_SUN_CS4231=m # CONFIG_SND_SUN_DBRI is not set # +# SoC audio support +# +# CONFIG_SND_SOC is not set + +# # Open Sound System # # CONFIG_SOUND_PRIME is not set @@ -1052,6 +1073,7 @@ # # HID Devices # CONFIG_HID=y +# CONFIG_HID_DEBUG is not set # # USB support @@ -1066,9 +1088,7 @@ # # Miscellaneous USB options # CONFIG_USB_DEVICEFS=y -# CONFIG_USB_BANDWIDTH is not set # CONFIG_USB_DYNAMIC_MINORS is not set -# CONFIG_USB_MULTITHREAD_PROBE is not set # CONFIG_USB_OTG is not set # @@ -1078,9 +1098,11 @@ CONFIG_USB_EHCI_HCD=m # CONFIG_USB_EHCI_SPLIT_ISO is not set # CONFIG_USB_EHCI_ROOT_HUB_TT is not set # CONFIG_USB_EHCI_TT_NEWSCHED is not set +# CONFIG_USB_EHCI_BIG_ENDIAN_MMIO is not set # CONFIG_USB_ISP116X_HCD is not set CONFIG_USB_OHCI_HCD=y -# CONFIG_USB_OHCI_BIG_ENDIAN is not set +# CONFIG_USB_OHCI_BIG_ENDIAN_DESC is not set +# CONFIG_USB_OHCI_BIG_ENDIAN_MMIO is not set CONFIG_USB_OHCI_LITTLE_ENDIAN=y CONFIG_USB_UHCI_HCD=m # CONFIG_USB_SL811_HCD is not set @@ -1132,6 +1154,7 @@ # CONFIG_USB_ATI_REMOTE is not set # CONFIG_USB_ATI_REMOTE2 is not set # CONFIG_USB_KEYSPAN_REMOTE is not set # CONFIG_USB_APPLETOUCH is not set +# CONFIG_USB_GTCO is not set # # USB Imaging devices @@ -1236,6 +1259,10 @@ # DMA Devices # # +# Auxiliary Display support +# + +# # Virtualization # @@ -1426,7 +1453,6 @@ # CONFIG_DEBUG_RT_MUTEXES is not set # CONFIG_RT_MUTEX_TESTER is not set # CONFIG_DEBUG_SPINLOCK is not set # CONFIG_DEBUG_MUTEXES is not set -# CONFIG_DEBUG_RWSEMS is not set # CONFIG_DEBUG_LOCK_ALLOC is not set # CONFIG_PROVE_LOCKING is not set # CONFIG_DEBUG_SPINLOCK_SLEEP is not set @@ -1473,8 +1499,10 @@ CONFIG_CRYPTO_TGR192=m CONFIG_CRYPTO_GF128MUL=m CONFIG_CRYPTO_ECB=m CONFIG_CRYPTO_CBC=y +CONFIG_CRYPTO_PCBC=m CONFIG_CRYPTO_LRW=m CONFIG_CRYPTO_DES=y +CONFIG_CRYPTO_FCRYPT=m CONFIG_CRYPTO_BLOWFISH=m CONFIG_CRYPTO_TWOFISH=m CONFIG_CRYPTO_TWOFISH_COMMON=m @@ -1489,6 +1517,7 @@ CONFIG_CRYPTO_ANUBIS=m CONFIG_CRYPTO_DEFLATE=y CONFIG_CRYPTO_MICHAEL_MIC=m CONFIG_CRYPTO_CRC32C=m +CONFIG_CRYPTO_CAMELLIA=m CONFIG_CRYPTO_TEST=m # @@ -1506,4 +1535,5 @@ CONFIG_LIBCRC32C=m CONFIG_ZLIB_INFLATE=y CONFIG_ZLIB_DEFLATE=y CONFIG_PLIST=y -CONFIG_IOMAP_COPY=y +CONFIG_HAS_IOMEM=y +CONFIG_HAS_IOPORT=y diff --git a/arch/sparc64/kernel/irq.c b/arch/sparc64/kernel/irq.c index c3d068c..b5ff3ee 100644 --- a/arch/sparc64/kernel/irq.c +++ b/arch/sparc64/kernel/irq.c @@ -22,6 +22,7 @@ #include #include #include #include +#include #include #include @@ -87,7 +88,6 @@ #define __irq(bucket) ((unsigned int)(un #define irq_work(__cpu) &(trap_block[(__cpu)].irq_worklist) static unsigned int virt_to_real_irq_table[NR_IRQS]; -static unsigned char virt_irq_cur = 1; static unsigned char virt_irq_alloc(unsigned int real_irq) { @@ -95,26 +95,32 @@ static unsigned char virt_irq_alloc(unsi BUILD_BUG_ON(NR_IRQS >= 256); - ent = virt_irq_cur; + for (ent = 1; ent < NR_IRQS; ent++) { + if (!virt_to_real_irq_table[ent]) + break; + } if (ent >= NR_IRQS) { printk(KERN_ERR "IRQ: Out of virtual IRQs.\n"); return 0; } - virt_irq_cur = ent + 1; virt_to_real_irq_table[ent] = real_irq; return ent; } -#if 0 /* Currently unused. */ -static unsigned char real_to_virt_irq(unsigned int real_irq) +static void virt_irq_free(unsigned int virt_irq) { - struct ino_bucket *bucket = __bucket(real_irq); + unsigned int real_irq; - return bucket->virt_irq; + if (virt_irq >= NR_IRQS) + return; + + real_irq = virt_to_real_irq_table[virt_irq]; + virt_to_real_irq_table[virt_irq] = 0; + + __bucket(real_irq)->virt_irq = 0; } -#endif static unsigned int virt_to_real_irq(unsigned char virt_irq) { @@ -268,8 +274,7 @@ #endif static void sun4u_irq_enable(unsigned int virt_irq) { - irq_desc_t *desc = irq_desc + virt_irq; - struct irq_handler_data *data = desc->handler_data; + struct irq_handler_data *data = get_irq_chip_data(virt_irq); if (likely(data)) { unsigned long cpuid, imap; @@ -286,8 +291,7 @@ static void sun4u_irq_enable(unsigned in static void sun4u_irq_disable(unsigned int virt_irq) { - irq_desc_t *desc = irq_desc + virt_irq; - struct irq_handler_data *data = desc->handler_data; + struct irq_handler_data *data = get_irq_chip_data(virt_irq); if (likely(data)) { unsigned long imap = data->imap; @@ -300,8 +304,7 @@ static void sun4u_irq_disable(unsigned i static void sun4u_irq_end(unsigned int virt_irq) { - irq_desc_t *desc = irq_desc + virt_irq; - struct irq_handler_data *data = desc->handler_data; + struct irq_handler_data *data = get_irq_chip_data(virt_irq); if (likely(data)) upa_writel(ICLR_IDLE, data->iclr); @@ -344,6 +347,20 @@ static void sun4v_irq_disable(unsigned i } } +#ifdef CONFIG_PCI_MSI +static void sun4v_msi_enable(unsigned int virt_irq) +{ + sun4v_irq_enable(virt_irq); + unmask_msi_irq(virt_irq); +} + +static void sun4v_msi_disable(unsigned int virt_irq) +{ + mask_msi_irq(virt_irq); + sun4v_irq_disable(virt_irq); +} +#endif + static void sun4v_irq_end(unsigned int virt_irq) { struct ino_bucket *bucket = virt_irq_to_bucket(virt_irq); @@ -362,8 +379,7 @@ static void sun4v_irq_end(unsigned int v static void run_pre_handler(unsigned int virt_irq) { struct ino_bucket *bucket = virt_irq_to_bucket(virt_irq); - irq_desc_t *desc = irq_desc + virt_irq; - struct irq_handler_data *data = desc->handler_data; + struct irq_handler_data *data = get_irq_chip_data(virt_irq); if (likely(data->pre_handler)) { data->pre_handler(__irq_ino(__irq(bucket)), @@ -402,30 +418,47 @@ static struct irq_chip sun4v_irq_ack = { .end = sun4v_irq_end, }; +#ifdef CONFIG_PCI_MSI +static struct irq_chip sun4v_msi = { + .typename = "sun4v+msi", + .mask = mask_msi_irq, + .unmask = unmask_msi_irq, + .enable = sun4v_msi_enable, + .disable = sun4v_msi_disable, + .ack = run_pre_handler, + .end = sun4v_irq_end, +}; +#endif + void irq_install_pre_handler(int virt_irq, void (*func)(unsigned int, void *, void *), void *arg1, void *arg2) { - irq_desc_t *desc = irq_desc + virt_irq; - struct irq_handler_data *data = desc->handler_data; + struct irq_handler_data *data = get_irq_chip_data(virt_irq); + struct irq_chip *chip; data->pre_handler = func; data->pre_handler_arg1 = arg1; data->pre_handler_arg2 = arg2; - if (desc->chip == &sun4u_irq_ack || - desc->chip == &sun4v_irq_ack) + chip = get_irq_chip(virt_irq); + if (chip == &sun4u_irq_ack || + chip == &sun4v_irq_ack +#ifdef CONFIG_PCI_MSI + || chip == &sun4v_msi +#endif + ) return; - desc->chip = (desc->chip == &sun4u_irq ? - &sun4u_irq_ack : &sun4v_irq_ack); + chip = (chip == &sun4u_irq ? + &sun4u_irq_ack : &sun4v_irq_ack); + set_irq_chip(virt_irq, chip); } unsigned int build_irq(int inofixup, unsigned long iclr, unsigned long imap) { struct ino_bucket *bucket; struct irq_handler_data *data; - irq_desc_t *desc; int ino; BUG_ON(tlb_type == hypervisor); @@ -434,11 +467,11 @@ unsigned int build_irq(int inofixup, uns bucket = &ivector_table[ino]; if (!bucket->virt_irq) { bucket->virt_irq = virt_irq_alloc(__irq(bucket)); - irq_desc[bucket->virt_irq].chip = &sun4u_irq; + set_irq_chip(bucket->virt_irq, &sun4u_irq); } - desc = irq_desc + bucket->virt_irq; - if (unlikely(desc->handler_data)) + data = get_irq_chip_data(bucket->virt_irq); + if (unlikely(data)) goto out; data = kzalloc(sizeof(struct irq_handler_data), GFP_ATOMIC); @@ -446,7 +479,7 @@ unsigned int build_irq(int inofixup, uns prom_printf("IRQ: kzalloc(irq_handler_data) failed.\n"); prom_halt(); } - desc->handler_data = data; + set_irq_chip_data(bucket->virt_irq, data); data->imap = imap; data->iclr = iclr; @@ -460,7 +493,6 @@ unsigned int sun4v_build_irq(u32 devhand struct ino_bucket *bucket; struct irq_handler_data *data; unsigned long sysino; - irq_desc_t *desc; BUG_ON(tlb_type != hypervisor); @@ -468,11 +500,11 @@ unsigned int sun4v_build_irq(u32 devhand bucket = &ivector_table[sysino]; if (!bucket->virt_irq) { bucket->virt_irq = virt_irq_alloc(__irq(bucket)); - irq_desc[bucket->virt_irq].chip = &sun4v_irq; + set_irq_chip(bucket->virt_irq, &sun4v_irq); } - desc = irq_desc + bucket->virt_irq; - if (unlikely(desc->handler_data)) + data = get_irq_chip_data(bucket->virt_irq); + if (unlikely(data)) goto out; data = kzalloc(sizeof(struct irq_handler_data), GFP_ATOMIC); @@ -480,7 +512,7 @@ unsigned int sun4v_build_irq(u32 devhand prom_printf("IRQ: kzalloc(irq_handler_data) failed.\n"); prom_halt(); } - desc->handler_data = data; + set_irq_chip_data(bucket->virt_irq, data); /* Catch accidental accesses to these things. IMAP/ICLR handling * is done by hypervisor calls on sun4v platforms, not by direct @@ -493,6 +525,56 @@ out: return bucket->virt_irq; } +#ifdef CONFIG_PCI_MSI +unsigned int sun4v_build_msi(u32 devhandle, unsigned int *virt_irq_p, + unsigned int msi_start, unsigned int msi_end) +{ + struct ino_bucket *bucket; + struct irq_handler_data *data; + unsigned long sysino; + unsigned int devino; + + BUG_ON(tlb_type != hypervisor); + + /* Find a free devino in the given range. */ + for (devino = msi_start; devino < msi_end; devino++) { + sysino = sun4v_devino_to_sysino(devhandle, devino); + bucket = &ivector_table[sysino]; + if (!bucket->virt_irq) + break; + } + if (devino >= msi_end) + return 0; + + sysino = sun4v_devino_to_sysino(devhandle, devino); + bucket = &ivector_table[sysino]; + bucket->virt_irq = virt_irq_alloc(__irq(bucket)); + *virt_irq_p = bucket->virt_irq; + set_irq_chip(bucket->virt_irq, &sun4v_msi); + + data = get_irq_chip_data(bucket->virt_irq); + if (unlikely(data)) + return devino; + + data = kzalloc(sizeof(struct irq_handler_data), GFP_ATOMIC); + if (unlikely(!data)) { + prom_printf("IRQ: kzalloc(irq_handler_data) failed.\n"); + prom_halt(); + } + set_irq_chip_data(bucket->virt_irq, data); + + data->imap = ~0UL; + data->iclr = ~0UL; + + return devino; +} + +void sun4v_destroy_msi(unsigned int virt_irq) +{ + virt_irq_free(virt_irq); +} +#endif + void ack_bad_irq(unsigned int virt_irq) { struct ino_bucket *bucket = virt_irq_to_bucket(virt_irq); diff --git a/arch/sparc64/kernel/pci.c b/arch/sparc64/kernel/pci.c index dfc41cd..6b740eb 100644 --- a/arch/sparc64/kernel/pci.c +++ b/arch/sparc64/kernel/pci.c @@ -13,6 +13,8 @@ #include #include #include #include +#include +#include #include #include @@ -646,4 +648,37 @@ int pci_domain_nr(struct pci_bus *pbus) } EXPORT_SYMBOL(pci_domain_nr); +#ifdef CONFIG_PCI_MSI +int arch_setup_msi_irq(struct pci_dev *pdev, struct msi_desc *desc) +{ + struct pcidev_cookie *pcp = pdev->sysdata; + struct pci_pbm_info *pbm = pcp->pbm; + struct pci_controller_info *p = pbm->parent; + int virt_irq, err; + + if (!pbm->msi_num || !p->setup_msi_irq) + return -EINVAL; + + err = p->setup_msi_irq(&virt_irq, pdev, desc); + if (err < 0) + return err; + + return virt_irq; +} + +void arch_teardown_msi_irq(unsigned int virt_irq) +{ + struct msi_desc *entry = get_irq_data(virt_irq); + struct pci_dev *pdev = entry->dev; + struct pcidev_cookie *pcp = pdev->sysdata; + struct pci_pbm_info *pbm = pcp->pbm; + struct pci_controller_info *p = pbm->parent; + + if (!pbm->msi_num || !p->setup_msi_irq) + return; + + return p->teardown_msi_irq(virt_irq, pdev); +} +#endif /* !(CONFIG_PCI_MSI) */ + #endif /* !(CONFIG_PCI) */ diff --git a/arch/sparc64/kernel/pci_common.c b/arch/sparc64/kernel/pci_common.c index 827ae30..5a92cb9 100644 --- a/arch/sparc64/kernel/pci_common.c +++ b/arch/sparc64/kernel/pci_common.c @@ -7,6 +7,8 @@ #include #include #include +#include +#include #include #include @@ -129,6 +131,20 @@ static void __init fixup_obp_assignments } } +static ssize_t +show_pciobppath_attr(struct device * dev, struct device_attribute * attr, char * buf) +{ + struct pci_dev *pdev; + struct pcidev_cookie *sysdata; + + pdev = to_pci_dev(dev); + sysdata = pdev->sysdata; + + return snprintf (buf, PAGE_SIZE, "%s\n", sysdata->prom_node->full_name); +} + +static DEVICE_ATTR(obppath, S_IRUSR | S_IRGRP | S_IROTH, show_pciobppath_attr, NULL); + /* Fill in the PCI device cookie sysdata for the given * PCI device. This cookie is the means by which one * can get to OBP and PCI controller specific information @@ -142,7 +158,7 @@ static void __init pdev_cookie_fillin(st struct pcidev_cookie *pcp; struct device_node *dp; struct property *prop; - int nregs, len; + int nregs, len, err; dp = find_device_prom_node(pbm, pdev, bus_node, &pregs, &nregs); @@ -215,6 +231,13 @@ static void __init pdev_cookie_fillin(st fixup_obp_assignments(pdev, pcp); pdev->sysdata = pcp; + + /* we don't really care if we can create this file or not, + * but we need to assign the result of the call or the world will fall + * under alien invasion and everybody will be frozen on a spaceship + * ready to be eaten on alpha centauri by some green and jelly humanoid. + */ + err = sysfs_create_file(&pdev->dev.kobj, &dev_attr_obppath.attr); } void __init pci_fill_in_pbm_cookies(struct pci_bus *pbus, diff --git a/arch/sparc64/kernel/pci_sun4v.c b/arch/sparc64/kernel/pci_sun4v.c index 6b04794..ec22cd6 100644 --- a/arch/sparc64/kernel/pci_sun4v.c +++ b/arch/sparc64/kernel/pci_sun4v.c @@ -10,6 +10,8 @@ #include #include #include #include +#include +#include #include #include @@ -1074,6 +1076,443 @@ static void pci_sun4v_get_bus_range(stru } +#ifdef CONFIG_PCI_MSI +struct pci_sun4v_msiq_entry { + u64 version_type; +#define MSIQ_VERSION_MASK 0xffffffff00000000UL +#define MSIQ_VERSION_SHIFT 32 +#define MSIQ_TYPE_MASK 0x00000000000000ffUL +#define MSIQ_TYPE_SHIFT 0 +#define MSIQ_TYPE_NONE 0x00 +#define MSIQ_TYPE_MSG 0x01 +#define MSIQ_TYPE_MSI32 0x02 +#define MSIQ_TYPE_MSI64 0x03 +#define MSIQ_TYPE_INTX 0x08 +#define MSIQ_TYPE_NONE2 0xff + + u64 intx_sysino; + u64 reserved1; + u64 stick; + u64 req_id; /* bus/device/func */ +#define MSIQ_REQID_BUS_MASK 0xff00UL +#define MSIQ_REQID_BUS_SHIFT 8 +#define MSIQ_REQID_DEVICE_MASK 0x00f8UL +#define MSIQ_REQID_DEVICE_SHIFT 3 +#define MSIQ_REQID_FUNC_MASK 0x0007UL +#define MSIQ_REQID_FUNC_SHIFT 0 + + u64 msi_address; + + /* The format of this value is message type dependant. + * For MSI bits 15:0 are the data from the MSI packet. + * For MSI-X bits 31:0 are the data from the MSI packet. + * For MSG, the message code and message routing code where: + * bits 39:32 is the bus/device/fn of the msg target-id + * bits 18:16 is the message routing code + * bits 7:0 is the message code + * For INTx the low order 2-bits are: + * 00 - INTA + * 01 - INTB + * 10 - INTC + * 11 - INTD + */ + u64 msi_data; + + u64 reserved2; +}; + +/* For now this just runs as a pre-handler for the real interrupt handler. + * So we just walk through the queue and ACK all the entries, update the + * head pointer, and return. + * + * In the longer term it would be nice to do something more integrated + * wherein we can pass in some of this MSI info to the drivers. This + * would be most useful for PCIe fabric error messages, although we could + * invoke those directly from the loop here in order to pass the info around. + */ +static void pci_sun4v_msi_prehandler(unsigned int ino, void *data1, void *data2) +{ + struct pci_pbm_info *pbm = data1; + struct pci_sun4v_msiq_entry *base, *ep; + unsigned long msiqid, orig_head, head, type, err; + + msiqid = (unsigned long) data2; + + head = 0xdeadbeef; + err = pci_sun4v_msiq_gethead(pbm->devhandle, msiqid, &head); + if (unlikely(err)) + goto hv_error_get; + + if (unlikely(head >= (pbm->msiq_ent_count * sizeof(struct pci_sun4v_msiq_entry)))) + goto bad_offset; + + head /= sizeof(struct pci_sun4v_msiq_entry); + orig_head = head; + base = (pbm->msi_queues + ((msiqid - pbm->msiq_first) * + (pbm->msiq_ent_count * + sizeof(struct pci_sun4v_msiq_entry)))); + ep = &base[head]; + while ((ep->version_type & MSIQ_TYPE_MASK) != 0) { + type = (ep->version_type & MSIQ_TYPE_MASK) >> MSIQ_TYPE_SHIFT; + if (unlikely(type != MSIQ_TYPE_MSI32 && + type != MSIQ_TYPE_MSI64)) + goto bad_type; + + pci_sun4v_msi_setstate(pbm->devhandle, + ep->msi_data /* msi_num */, + HV_MSISTATE_IDLE); + + /* Clear the entry. */ + ep->version_type &= ~MSIQ_TYPE_MASK; + + /* Go to next entry in ring. */ + head++; + if (head >= pbm->msiq_ent_count) + head = 0; + ep = &base[head]; + } + + if (likely(head != orig_head)) { + /* ACK entries by updating head pointer. */ + head *= sizeof(struct pci_sun4v_msiq_entry); + err = pci_sun4v_msiq_sethead(pbm->devhandle, msiqid, head); + if (unlikely(err)) + goto hv_error_set; + } + return; + +hv_error_set: + printk(KERN_EMERG "MSI: Hypervisor set head gives error %lu\n", err); + goto hv_error_cont; + +hv_error_get: + printk(KERN_EMERG "MSI: Hypervisor get head gives error %lu\n", err); + +hv_error_cont: + printk(KERN_EMERG "MSI: devhandle[%x] msiqid[%lx] head[%lu]\n", + pbm->devhandle, msiqid, head); + return; + +bad_offset: + printk(KERN_EMERG "MSI: Hypervisor gives bad offset %lx max(%lx)\n", + head, pbm->msiq_ent_count * sizeof(struct pci_sun4v_msiq_entry)); + return; + +bad_type: + printk(KERN_EMERG "MSI: Entry has bad type %lx\n", type); + return; +} + +static int msi_bitmap_alloc(struct pci_pbm_info *pbm) +{ + unsigned long size, bits_per_ulong; + + bits_per_ulong = sizeof(unsigned long) * 8; + size = (pbm->msi_num + (bits_per_ulong - 1)) & ~(bits_per_ulong - 1); + size /= 8; + BUG_ON(size % sizeof(unsigned long)); + + pbm->msi_bitmap = kzalloc(size, GFP_KERNEL); + if (!pbm->msi_bitmap) + return -ENOMEM; + + return 0; +} + +static void msi_bitmap_free(struct pci_pbm_info *pbm) +{ + kfree(pbm->msi_bitmap); + pbm->msi_bitmap = NULL; +} + +static int msi_queue_alloc(struct pci_pbm_info *pbm) +{ + unsigned long q_size, alloc_size, pages, order; + int i; + + q_size = pbm->msiq_ent_count * sizeof(struct pci_sun4v_msiq_entry); + alloc_size = (pbm->msiq_num * q_size); + order = get_order(alloc_size); + pages = __get_free_pages(GFP_KERNEL | __GFP_COMP, order); + if (pages == 0UL) { + printk(KERN_ERR "MSI: Cannot allocate MSI queues (o=%lu).\n", + order); + return -ENOMEM; + } + memset((char *)pages, 0, PAGE_SIZE << order); + pbm->msi_queues = (void *) pages; + + for (i = 0; i < pbm->msiq_num; i++) { + unsigned long err, base = __pa(pages + (i * q_size)); + unsigned long ret1, ret2; + + err = pci_sun4v_msiq_conf(pbm->devhandle, + pbm->msiq_first + i, + base, pbm->msiq_ent_count); + if (err) { + printk(KERN_ERR "MSI: msiq register fails (err=%lu)\n", + err); + goto h_error; + } + + err = pci_sun4v_msiq_info(pbm->devhandle, + pbm->msiq_first + i, + &ret1, &ret2); + if (err) { + printk(KERN_ERR "MSI: Cannot read msiq (err=%lu)\n", + err); + goto h_error; + } + if (ret1 != base || ret2 != pbm->msiq_ent_count) { + printk(KERN_ERR "MSI: Bogus qconf " + "expected[%lx:%x] got[%lx:%lx]\n", + base, pbm->msiq_ent_count, + ret1, ret2); + goto h_error; + } + } + + return 0; + +h_error: + free_pages(pages, order); + return -EINVAL; +} + +static void pci_sun4v_msi_init(struct pci_pbm_info *pbm) +{ + u32 *val; + int len; + + val = of_get_property(pbm->prom_node, "#msi-eqs", &len); + if (!val || len != 4) + goto no_msi; + pbm->msiq_num = *val; + if (pbm->msiq_num) { + struct msiq_prop { + u32 first_msiq; + u32 num_msiq; + u32 first_devino; + } *mqp; + struct msi_range_prop { + u32 first_msi; + u32 num_msi; + } *mrng; + struct addr_range_prop { + u32 msi32_high; + u32 msi32_low; + u32 msi32_len; + u32 msi64_high; + u32 msi64_low; + u32 msi64_len; + } *arng; + + val = of_get_property(pbm->prom_node, "msi-eq-size", &len); + if (!val || len != 4) + goto no_msi; + + pbm->msiq_ent_count = *val; + + mqp = of_get_property(pbm->prom_node, + "msi-eq-to-devino", &len); + if (!mqp || len != sizeof(struct msiq_prop)) + goto no_msi; + + pbm->msiq_first = mqp->first_msiq; + pbm->msiq_first_devino = mqp->first_devino; + + val = of_get_property(pbm->prom_node, "#msi", &len); + if (!val || len != 4) + goto no_msi; + pbm->msi_num = *val; + + mrng = of_get_property(pbm->prom_node, "msi-ranges", &len); + if (!mrng || len != sizeof(struct msi_range_prop)) + goto no_msi; + pbm->msi_first = mrng->first_msi; + + val = of_get_property(pbm->prom_node, "msi-data-mask", &len); + if (!val || len != 4) + goto no_msi; + pbm->msi_data_mask = *val; + + val = of_get_property(pbm->prom_node, "msix-data-width", &len); + if (!val || len != 4) + goto no_msi; + pbm->msix_data_width = *val; + + arng = of_get_property(pbm->prom_node, "msi-address-ranges", + &len); + if (!arng || len != sizeof(struct addr_range_prop)) + goto no_msi; + pbm->msi32_start = ((u64)arng->msi32_high << 32) | + (u64) arng->msi32_low; + pbm->msi64_start = ((u64)arng->msi64_high << 32) | + (u64) arng->msi64_low; + pbm->msi32_len = arng->msi32_len; + pbm->msi64_len = arng->msi64_len; + + if (msi_bitmap_alloc(pbm)) + goto no_msi; + + if (msi_queue_alloc(pbm)) { + msi_bitmap_free(pbm); + goto no_msi; + } + + printk(KERN_INFO "%s: MSI Queue first[%u] num[%u] count[%u] " + "devino[0x%x]\n", + pbm->name, + pbm->msiq_first, pbm->msiq_num, + pbm->msiq_ent_count, + pbm->msiq_first_devino); + printk(KERN_INFO "%s: MSI first[%u] num[%u] mask[0x%x] " + "width[%u]\n", + pbm->name, + pbm->msi_first, pbm->msi_num, pbm->msi_data_mask, + pbm->msix_data_width); + printk(KERN_INFO "%s: MSI addr32[0x%lx:0x%x] " + "addr64[0x%lx:0x%x]\n", + pbm->name, + pbm->msi32_start, pbm->msi32_len, + pbm->msi64_start, pbm->msi64_len); + printk(KERN_INFO "%s: MSI queues at RA [%p]\n", + pbm->name, + pbm->msi_queues); + } + + return; + +no_msi: + pbm->msiq_num = 0; + printk(KERN_INFO "%s: No MSI support.\n", pbm->name); +} + +static int alloc_msi(struct pci_pbm_info *pbm) +{ + int i; + + for (i = 0; i < pbm->msi_num; i++) { + if (!test_and_set_bit(i, pbm->msi_bitmap)) + return i + pbm->msi_first; + } + + return -ENOENT; +} + +static void free_msi(struct pci_pbm_info *pbm, int msi_num) +{ + msi_num -= pbm->msi_first; + clear_bit(msi_num, pbm->msi_bitmap); +} + +static int pci_sun4v_setup_msi_irq(unsigned int *virt_irq_p, + struct pci_dev *pdev, + struct msi_desc *entry) +{ + struct pcidev_cookie *pcp = pdev->sysdata; + struct pci_pbm_info *pbm = pcp->pbm; + unsigned long devino, msiqid; + struct msi_msg msg; + int msi_num, err; + + *virt_irq_p = 0; + + msi_num = alloc_msi(pbm); + if (msi_num < 0) + return msi_num; + + devino = sun4v_build_msi(pbm->devhandle, virt_irq_p, + pbm->msiq_first_devino, + (pbm->msiq_first_devino + + pbm->msiq_num)); + err = -ENOMEM; + if (!devino) + goto out_err; + + set_irq_msi(*virt_irq_p, entry); + + msiqid = ((devino - pbm->msiq_first_devino) + + pbm->msiq_first); + + err = -EINVAL; + if (pci_sun4v_msiq_setstate(pbm->devhandle, msiqid, HV_MSIQSTATE_IDLE)) + if (err) + goto out_err; + + if (pci_sun4v_msiq_setvalid(pbm->devhandle, msiqid, HV_MSIQ_VALID)) + goto out_err; + + if (pci_sun4v_msi_setmsiq(pbm->devhandle, + msi_num, msiqid, + (entry->msi_attrib.is_64 ? + HV_MSITYPE_MSI64 : HV_MSITYPE_MSI32))) + goto out_err; + + if (pci_sun4v_msi_setstate(pbm->devhandle, msi_num, HV_MSISTATE_IDLE)) + goto out_err; + + if (pci_sun4v_msi_setvalid(pbm->devhandle, msi_num, HV_MSIVALID_VALID)) + goto out_err; + + pcp->msi_num = msi_num; + + if (entry->msi_attrib.is_64) { + msg.address_hi = pbm->msi64_start >> 32; + msg.address_lo = pbm->msi64_start & 0xffffffff; + } else { + msg.address_hi = 0; + msg.address_lo = pbm->msi32_start; + } + msg.data = msi_num; + write_msi_msg(*virt_irq_p, &msg); + + irq_install_pre_handler(*virt_irq_p, + pci_sun4v_msi_prehandler, + pbm, (void *) msiqid); + + return 0; + +out_err: + free_msi(pbm, msi_num); + sun4v_destroy_msi(*virt_irq_p); + *virt_irq_p = 0; + return err; + +} + +static void pci_sun4v_teardown_msi_irq(unsigned int virt_irq, + struct pci_dev *pdev) +{ + struct pcidev_cookie *pcp = pdev->sysdata; + struct pci_pbm_info *pbm = pcp->pbm; + unsigned long msiqid, err; + unsigned int msi_num; + + msi_num = pcp->msi_num; + err = pci_sun4v_msi_getmsiq(pbm->devhandle, msi_num, &msiqid); + if (err) { + printk(KERN_ERR "%s: getmsiq gives error %lu\n", + pbm->name, err); + return; + } + + pci_sun4v_msi_setvalid(pbm->devhandle, msi_num, HV_MSIVALID_INVALID); + pci_sun4v_msiq_setvalid(pbm->devhandle, msiqid, HV_MSIQ_INVALID); + + free_msi(pbm, msi_num); + + /* The sun4v_destroy_msi() will liberate the devino and thus the MSIQ + * allocation. + */ + sun4v_destroy_msi(virt_irq); +} +#else /* CONFIG_PCI_MSI */ +static void pci_sun4v_msi_init(struct pci_pbm_info *pbm) +{ +} +#endif /* !(CONFIG_PCI_MSI) */ + static void pci_sun4v_pbm_init(struct pci_controller_info *p, struct device_node *dp, u32 devhandle) { struct pci_pbm_info *pbm; @@ -1119,6 +1558,7 @@ static void pci_sun4v_pbm_init(struct pc pci_sun4v_get_bus_range(pbm); pci_sun4v_iommu_init(pbm); + pci_sun4v_msi_init(pbm); pdev_htab_populate(pbm); } @@ -1187,6 +1627,10 @@ void sun4v_pci_init(struct device_node * p->scan_bus = pci_sun4v_scan_bus; p->base_address_update = pci_sun4v_base_address_update; p->resource_adjust = pci_sun4v_resource_adjust; +#ifdef CONFIG_PCI_MSI + p->setup_msi_irq = pci_sun4v_setup_msi_irq; + p->teardown_msi_irq = pci_sun4v_teardown_msi_irq; +#endif p->pci_ops = &pci_sun4v_ops; /* Like PSYCHO and SCHIZO we have a 2GB aligned area diff --git a/arch/sparc64/kernel/pci_sun4v.h b/arch/sparc64/kernel/pci_sun4v.h index 884d25f..8e9fc3a 100644 --- a/arch/sparc64/kernel/pci_sun4v.h +++ b/arch/sparc64/kernel/pci_sun4v.h @@ -28,4 +28,65 @@ extern int pci_sun4v_config_put(unsigned unsigned long size, unsigned long data); +extern unsigned long pci_sun4v_msiq_conf(unsigned long devhandle, + unsigned long msiqid, + unsigned long msiq_paddr, + unsigned long num_entries); +extern unsigned long pci_sun4v_msiq_info(unsigned long devhandle, + unsigned long msiqid, + unsigned long *msiq_paddr, + unsigned long *num_entries); +extern unsigned long pci_sun4v_msiq_getvalid(unsigned long devhandle, + unsigned long msiqid, + unsigned long *valid); +extern unsigned long pci_sun4v_msiq_setvalid(unsigned long devhandle, + unsigned long msiqid, + unsigned long valid); +extern unsigned long pci_sun4v_msiq_getstate(unsigned long devhandle, + unsigned long msiqid, + unsigned long *state); +extern unsigned long pci_sun4v_msiq_setstate(unsigned long devhandle, + unsigned long msiqid, + unsigned long state); +extern unsigned long pci_sun4v_msiq_gethead(unsigned long devhandle, + unsigned long msiqid, + unsigned long *head); +extern unsigned long pci_sun4v_msiq_sethead(unsigned long devhandle, + unsigned long msiqid, + unsigned long head); +extern unsigned long pci_sun4v_msiq_gettail(unsigned long devhandle, + unsigned long msiqid, + unsigned long *head); +extern unsigned long pci_sun4v_msi_getvalid(unsigned long devhandle, + unsigned long msinum, + unsigned long *valid); +extern unsigned long pci_sun4v_msi_setvalid(unsigned long devhandle, + unsigned long msinum, + unsigned long valid); +extern unsigned long pci_sun4v_msi_getmsiq(unsigned long devhandle, + unsigned long msinum, + unsigned long *msiq); +extern unsigned long pci_sun4v_msi_setmsiq(unsigned long devhandle, + unsigned long msinum, + unsigned long msiq, + unsigned long msitype); +extern unsigned long pci_sun4v_msi_getstate(unsigned long devhandle, + unsigned long msinum, + unsigned long *state); +extern unsigned long pci_sun4v_msi_setstate(unsigned long devhandle, + unsigned long msinum, + unsigned long state); +extern unsigned long pci_sun4v_msg_getmsiq(unsigned long devhandle, + unsigned long msinum, + unsigned long *msiq); +extern unsigned long pci_sun4v_msg_setmsiq(unsigned long devhandle, + unsigned long msinum, + unsigned long msiq); +extern unsigned long pci_sun4v_msg_getvalid(unsigned long devhandle, + unsigned long msinum, + unsigned long *valid); +extern unsigned long pci_sun4v_msg_setvalid(unsigned long devhandle, + unsigned long msinum, + unsigned long valid); + #endif /* !(_PCI_SUN4V_H) */ diff --git a/arch/sparc64/kernel/pci_sun4v_asm.S b/arch/sparc64/kernel/pci_sun4v_asm.S index 6604fdb..ecb81f3 100644 --- a/arch/sparc64/kernel/pci_sun4v_asm.S +++ b/arch/sparc64/kernel/pci_sun4v_asm.S @@ -93,3 +93,269 @@ pci_sun4v_config_put: mov -1, %o1 1: retl mov %o1, %o0 + + /* %o0: devhandle + * %o1: msiqid + * %o2: msiq phys address + * %o3: num entries + * + * returns %o0: status + * + * status will be zero if the operation completed + * successfully, else -1 if not + */ + .globl pci_sun4v_msiq_conf +pci_sun4v_msiq_conf: + mov HV_FAST_PCI_MSIQ_CONF, %o5 + ta HV_FAST_TRAP + retl + mov %o0, %o0 + + /* %o0: devhandle + * %o1: msiqid + * %o2: &msiq_phys_addr + * %o3: &msiq_num_entries + * + * returns %o0: status + */ + .globl pci_sun4v_msiq_info +pci_sun4v_msiq_info: + mov %o2, %o4 + mov HV_FAST_PCI_MSIQ_INFO, %o5 + ta HV_FAST_TRAP + stx %o1, [%o4] + stx %o2, [%o3] + retl + mov %o0, %o0 + + /* %o0: devhandle + * %o1: msiqid + * %o2: &valid + * + * returns %o0: status + */ + .globl pci_sun4v_msiq_getvalid +pci_sun4v_msiq_getvalid: + mov HV_FAST_PCI_MSIQ_GETVALID, %o5 + ta HV_FAST_TRAP + stx %o1, [%o2] + retl + mov %o0, %o0 + + /* %o0: devhandle + * %o1: msiqid + * %o2: valid + * + * returns %o0: status + */ + .globl pci_sun4v_msiq_setvalid +pci_sun4v_msiq_setvalid: + mov HV_FAST_PCI_MSIQ_SETVALID, %o5 + ta HV_FAST_TRAP + retl + mov %o0, %o0 + + /* %o0: devhandle + * %o1: msiqid + * %o2: &state + * + * returns %o0: status + */ + .globl pci_sun4v_msiq_getstate +pci_sun4v_msiq_getstate: + mov HV_FAST_PCI_MSIQ_GETSTATE, %o5 + ta HV_FAST_TRAP + stx %o1, [%o2] + retl + mov %o0, %o0 + + /* %o0: devhandle + * %o1: msiqid + * %o2: state + * + * returns %o0: status + */ + .globl pci_sun4v_msiq_setstate +pci_sun4v_msiq_setstate: + mov HV_FAST_PCI_MSIQ_SETSTATE, %o5 + ta HV_FAST_TRAP + retl + mov %o0, %o0 + + /* %o0: devhandle + * %o1: msiqid + * %o2: &head + * + * returns %o0: status + */ + .globl pci_sun4v_msiq_gethead +pci_sun4v_msiq_gethead: + mov HV_FAST_PCI_MSIQ_GETHEAD, %o5 + ta HV_FAST_TRAP + stx %o1, [%o2] + retl + mov %o0, %o0 + + /* %o0: devhandle + * %o1: msiqid + * %o2: head + * + * returns %o0: status + */ + .globl pci_sun4v_msiq_sethead +pci_sun4v_msiq_sethead: + mov HV_FAST_PCI_MSIQ_SETHEAD, %o5 + ta HV_FAST_TRAP + retl + mov %o0, %o0 + + /* %o0: devhandle + * %o1: msiqid + * %o2: &tail + * + * returns %o0: status + */ + .globl pci_sun4v_msiq_gettail +pci_sun4v_msiq_gettail: + mov HV_FAST_PCI_MSIQ_GETTAIL, %o5 + ta HV_FAST_TRAP + stx %o1, [%o2] + retl + mov %o0, %o0 + + /* %o0: devhandle + * %o1: msinum + * %o2: &valid + * + * returns %o0: status + */ + .globl pci_sun4v_msi_getvalid +pci_sun4v_msi_getvalid: + mov HV_FAST_PCI_MSI_GETVALID, %o5 + ta HV_FAST_TRAP + stx %o1, [%o2] + retl + mov %o0, %o0 + + /* %o0: devhandle + * %o1: msinum + * %o2: valid + * + * returns %o0: status + */ + .globl pci_sun4v_msi_setvalid +pci_sun4v_msi_setvalid: + mov HV_FAST_PCI_MSI_SETVALID, %o5 + ta HV_FAST_TRAP + retl + mov %o0, %o0 + + /* %o0: devhandle + * %o1: msinum + * %o2: &msiq + * + * returns %o0: status + */ + .globl pci_sun4v_msi_getmsiq +pci_sun4v_msi_getmsiq: + mov HV_FAST_PCI_MSI_GETMSIQ, %o5 + ta HV_FAST_TRAP + stx %o1, [%o2] + retl + mov %o0, %o0 + + /* %o0: devhandle + * %o1: msinum + * %o2: msitype + * %o3: msiq + * + * returns %o0: status + */ + .globl pci_sun4v_msi_setmsiq +pci_sun4v_msi_setmsiq: + mov HV_FAST_PCI_MSI_SETMSIQ, %o5 + ta HV_FAST_TRAP + retl + mov %o0, %o0 + + /* %o0: devhandle + * %o1: msinum + * %o2: &state + * + * returns %o0: status + */ + .globl pci_sun4v_msi_getstate +pci_sun4v_msi_getstate: + mov HV_FAST_PCI_MSI_GETSTATE, %o5 + ta HV_FAST_TRAP + stx %o1, [%o2] + retl + mov %o0, %o0 + + /* %o0: devhandle + * %o1: msinum + * %o2: state + * + * returns %o0: status + */ + .globl pci_sun4v_msi_setstate +pci_sun4v_msi_setstate: + mov HV_FAST_PCI_MSI_SETSTATE, %o5 + ta HV_FAST_TRAP + retl + mov %o0, %o0 + + /* %o0: devhandle + * %o1: msinum + * %o2: &msiq + * + * returns %o0: status + */ + .globl pci_sun4v_msg_getmsiq +pci_sun4v_msg_getmsiq: + mov HV_FAST_PCI_MSG_GETMSIQ, %o5 + ta HV_FAST_TRAP + stx %o1, [%o2] + retl + mov %o0, %o0 + + /* %o0: devhandle + * %o1: msinum + * %o2: msiq + * + * returns %o0: status + */ + .globl pci_sun4v_msg_setmsiq +pci_sun4v_msg_setmsiq: + mov HV_FAST_PCI_MSG_SETMSIQ, %o5 + ta HV_FAST_TRAP + retl + mov %o0, %o0 + + /* %o0: devhandle + * %o1: msinum + * %o2: &valid + * + * returns %o0: status + */ + .globl pci_sun4v_msg_getvalid +pci_sun4v_msg_getvalid: + mov HV_FAST_PCI_MSG_GETVALID, %o5 + ta HV_FAST_TRAP + stx %o1, [%o2] + retl + mov %o0, %o0 + + /* %o0: devhandle + * %o1: msinum + * %o2: valid + * + * returns %o0: status + */ + .globl pci_sun4v_msg_setvalid +pci_sun4v_msg_setvalid: + mov HV_FAST_PCI_MSG_SETVALID, %o5 + ta HV_FAST_TRAP + retl + mov %o0, %o0 + diff --git a/arch/sparc64/kernel/setup.c b/arch/sparc64/kernel/setup.c index bf033b3..4510283 100644 --- a/arch/sparc64/kernel/setup.c +++ b/arch/sparc64/kernel/setup.c @@ -315,7 +315,7 @@ void __init setup_arch(char **cmdline_p) { /* Initialize PROM console and command line. */ *cmdline_p = prom_getbootargs(); - strcpy(saved_command_line, *cmdline_p); + strcpy(boot_command_line, *cmdline_p); if (tlb_type == hypervisor) printk("ARCH: SUN4V\n"); diff --git a/arch/sparc64/kernel/sunos_ioctl32.c b/arch/sparc64/kernel/sunos_ioctl32.c index 3f619ea..a05e43d 100644 --- a/arch/sparc64/kernel/sunos_ioctl32.c +++ b/arch/sparc64/kernel/sunos_ioctl32.c @@ -11,6 +11,7 @@ #include #include #include #include +#include #include #include #include diff --git a/arch/sparc64/kernel/sys_sparc32.c b/arch/sparc64/kernel/sys_sparc32.c index e27cb71..7876a02 100644 --- a/arch/sparc64/kernel/sys_sparc32.c +++ b/arch/sparc64/kernel/sys_sparc32.c @@ -459,70 +459,6 @@ asmlinkage long compat_sys_sysfs(int opt return sys_sysfs(option, arg1, arg2); } -struct sysinfo32 { - s32 uptime; - u32 loads[3]; - u32 totalram; - u32 freeram; - u32 sharedram; - u32 bufferram; - u32 totalswap; - u32 freeswap; - unsigned short procs; - unsigned short pad; - u32 totalhigh; - u32 freehigh; - u32 mem_unit; - char _f[20-2*sizeof(int)-sizeof(int)]; -}; - -asmlinkage long sys32_sysinfo(struct sysinfo32 __user *info) -{ - struct sysinfo s; - int ret, err; - int bitcount = 0; - mm_segment_t old_fs = get_fs (); - - set_fs(KERNEL_DS); - ret = sys_sysinfo((struct sysinfo __user *) &s); - set_fs(old_fs); - /* Check to see if any memory value is too large for 32-bit and - * scale down if needed. - */ - if ((s.totalram >> 32) || (s.totalswap >> 32)) { - while (s.mem_unit < PAGE_SIZE) { - s.mem_unit <<= 1; - bitcount++; - } - s.totalram >>= bitcount; - s.freeram >>= bitcount; - s.sharedram >>= bitcount; - s.bufferram >>= bitcount; - s.totalswap >>= bitcount; - s.freeswap >>= bitcount; - s.totalhigh >>= bitcount; - s.freehigh >>= bitcount; - } - - err = put_user (s.uptime, &info->uptime); - err |= __put_user (s.loads[0], &info->loads[0]); - err |= __put_user (s.loads[1], &info->loads[1]); - err |= __put_user (s.loads[2], &info->loads[2]); - err |= __put_user (s.totalram, &info->totalram); - err |= __put_user (s.freeram, &info->freeram); - err |= __put_user (s.sharedram, &info->sharedram); - err |= __put_user (s.bufferram, &info->bufferram); - err |= __put_user (s.totalswap, &info->totalswap); - err |= __put_user (s.freeswap, &info->freeswap); - err |= __put_user (s.procs, &info->procs); - err |= __put_user (s.totalhigh, &info->totalhigh); - err |= __put_user (s.freehigh, &info->freehigh); - err |= __put_user (s.mem_unit, &info->mem_unit); - if (err) - return -EFAULT; - return ret; -} - asmlinkage long compat_sys_sched_rr_get_interval(compat_pid_t pid, struct compat_timespec __user *interval) { struct timespec t; diff --git a/arch/sparc64/kernel/sys_sunos32.c b/arch/sparc64/kernel/sys_sunos32.c index 2ebc2c0..4cff95b 100644 --- a/arch/sparc64/kernel/sys_sunos32.c +++ b/arch/sparc64/kernel/sys_sunos32.c @@ -824,10 +824,17 @@ asmlinkage int sunos_wait4(compat_pid_t return ret; } -extern int kill_pg(int, int, int); asmlinkage int sunos_killpg(int pgrp, int sig) { - return kill_pg(pgrp, sig, 0); + int ret; + + rcu_read_lock(); + ret = -EINVAL; + if (pgrp > 0) + ret = kill_pgrp(find_pid(pgrp), sig, 0); + rcu_read_unlock(); + + return ret; } asmlinkage int sunos_audit(void) diff --git a/arch/sparc64/kernel/systbls.S b/arch/sparc64/kernel/systbls.S index 9a80267..948b7d2 100644 --- a/arch/sparc64/kernel/systbls.S +++ b/arch/sparc64/kernel/systbls.S @@ -61,7 +61,7 @@ sys_call_table32: .word sys32_epoll_wait, sys32_ioprio_set, sys_getppid, sys32_sigaction, sys_sgetmask /*200*/ .word sys32_ssetmask, sys_sigsuspend, compat_sys_newlstat, sys_uselib, compat_sys_old_readdir .word sys32_readahead, sys32_socketcall, sys32_syslog, sys32_lookup_dcookie, sys32_fadvise64 -/*210*/ .word sys32_fadvise64_64, sys32_tgkill, sys32_waitpid, sys_swapoff, sys32_sysinfo +/*210*/ .word sys32_fadvise64_64, sys32_tgkill, sys32_waitpid, sys_swapoff, compat_sys_sysinfo .word sys32_ipc, sys32_sigreturn, sys_clone, sys32_ioprio_get, compat_sys_adjtimex /*220*/ .word sys32_sigprocmask, sys_ni_syscall, sys32_delete_module, sys_ni_syscall, sys32_getpgid .word sys32_bdflush, sys32_sysfs, sys_nis_syscall, sys32_setfsuid16, sys32_setfsgid16 diff --git a/arch/sparc64/kernel/time.c b/arch/sparc64/kernel/time.c index 061e1b1..f84da4f 100644 --- a/arch/sparc64/kernel/time.c +++ b/arch/sparc64/kernel/time.c @@ -1327,7 +1327,7 @@ static int mini_rtc_release(struct inode } -static struct file_operations mini_rtc_fops = { +static const struct file_operations mini_rtc_fops = { .owner = THIS_MODULE, .ioctl = mini_rtc_ioctl, .open = mini_rtc_open, diff --git a/arch/sparc64/kernel/vmlinux.lds.S b/arch/sparc64/kernel/vmlinux.lds.S index 4a6063f..13fa2a2 100644 --- a/arch/sparc64/kernel/vmlinux.lds.S +++ b/arch/sparc64/kernel/vmlinux.lds.S @@ -81,10 +81,14 @@ SECTIONS __sun4v_2insn_patch = .; .sun4v_2insn_patch : { *(.sun4v_2insn_patch) } __sun4v_2insn_patch_end = .; + +#ifdef CONFIG_BLK_DEV_INITRD . = ALIGN(8192); __initramfs_start = .; .init.ramfs : { *(.init.ramfs) } __initramfs_end = .; +#endif + . = ALIGN(8192); __per_cpu_start = .; .data.percpu : { *(.data.percpu) } diff --git a/arch/sparc64/mm/init.c b/arch/sparc64/mm/init.c index 054822a..b1a1ee0 100644 --- a/arch/sparc64/mm/init.c +++ b/arch/sparc64/mm/init.c @@ -416,7 +416,7 @@ void show_mem(void) printk("Free swap: %6ldkB\n", nr_swap_pages << (PAGE_SHIFT-10)); printk("%ld pages of RAM\n", num_physpages); - printk("%d free pages\n", nr_free_pages()); + printk("%lu free pages\n", nr_free_pages()); } void mmu_info(struct seq_file *m) @@ -1467,8 +1467,8 @@ void __init paging_init(void) for (znum = 0; znum < MAX_NR_ZONES; znum++) zones_size[znum] = zholes_size[znum] = 0; - zones_size[ZONE_DMA] = end_pfn; - zholes_size[ZONE_DMA] = end_pfn - pages_avail; + zones_size[ZONE_NORMAL] = end_pfn; + zholes_size[ZONE_NORMAL] = end_pfn - pages_avail; free_area_init_node(0, &contig_page_data, zones_size, __pa(PAGE_OFFSET) >> PAGE_SHIFT, @@ -1593,7 +1593,7 @@ #endif initpages = (((unsigned long) __init_end) - ((unsigned long) __init_begin)); initpages = PAGE_ALIGN(initpages) >> PAGE_SHIFT; - printk("Memory: %uk available (%ldk kernel code, %ldk data, %ldk init) [%016lx,%016lx]\n", + printk("Memory: %luk available (%ldk kernel code, %ldk data, %ldk init) [%016lx,%016lx]\n", nr_free_pages() << (PAGE_SHIFT-10), codepages << (PAGE_SHIFT-10), datapages << (PAGE_SHIFT-10), diff --git a/arch/sparc64/solaris/socksys.c b/arch/sparc64/solaris/socksys.c index 89a4757..c286444 100644 --- a/arch/sparc64/solaris/socksys.c +++ b/arch/sparc64/solaris/socksys.c @@ -163,7 +163,7 @@ static unsigned int socksys_poll(struct return mask; } -static struct file_operations socksys_fops = { +static const struct file_operations socksys_fops = { .open = socksys_open, .release = socksys_release, }; diff --git a/arch/um/Kconfig b/arch/um/Kconfig index d32a80e..b3a21ba 100644 --- a/arch/um/Kconfig +++ b/arch/um/Kconfig @@ -16,6 +16,9 @@ config MMU bool default y +config NO_IOMEM + def_bool y + mainmenu "Linux/Usermode Kernel Configuration" config ISA diff --git a/arch/um/drivers/chan_kern.c b/arch/um/drivers/chan_kern.c index 7d4190e..7b8baf1 100644 --- a/arch/um/drivers/chan_kern.c +++ b/arch/um/drivers/chan_kern.c @@ -19,44 +19,11 @@ #include "sigio.h" #include "line.h" #include "os.h" -/* XXX: could well be moved to somewhere else, if needed. */ -static int my_printf(const char * fmt, ...) - __attribute__ ((format (printf, 1, 2))); - -static int my_printf(const char * fmt, ...) -{ - /* Yes, can be called on atomic context.*/ - char *buf = kmalloc(4096, GFP_ATOMIC); - va_list args; - int r; - - if (!buf) { - /* We print directly fmt. - * Yes, yes, yes, feel free to complain. */ - r = strlen(fmt); - } else { - va_start(args, fmt); - r = vsprintf(buf, fmt, args); - va_end(args); - fmt = buf; - } - - if (r) - r = os_write_file(1, fmt, r); - return r; - -} - #ifdef CONFIG_NOCONFIG_CHAN -/* Despite its name, there's no added trailing newline. */ -static int my_puts(const char * buf) -{ - return os_write_file(1, buf, strlen(buf)); -} - -static void *not_configged_init(char *str, int device, struct chan_opts *opts) +static void *not_configged_init(char *str, int device, + const struct chan_opts *opts) { - my_puts("Using a channel type which is configured out of " + printk("Using a channel type which is configured out of " "UML\n"); return NULL; } @@ -64,34 +31,34 @@ static void *not_configged_init(char *st static int not_configged_open(int input, int output, int primary, void *data, char **dev_out) { - my_puts("Using a channel type which is configured out of " + printk("Using a channel type which is configured out of " "UML\n"); return -ENODEV; } static void not_configged_close(int fd, void *data) { - my_puts("Using a channel type which is configured out of " + printk("Using a channel type which is configured out of " "UML\n"); } static int not_configged_read(int fd, char *c_out, void *data) { - my_puts("Using a channel type which is configured out of " + printk("Using a channel type which is configured out of " "UML\n"); return -EIO; } static int not_configged_write(int fd, const char *buf, int len, void *data) { - my_puts("Using a channel type which is configured out of " + printk("Using a channel type which is configured out of " "UML\n"); return -EIO; } static int not_configged_console_write(int fd, const char *buf, int len) { - my_puts("Using a channel type which is configured out of " + printk("Using a channel type which is configured out of " "UML\n"); return -EIO; } @@ -99,14 +66,14 @@ static int not_configged_console_write(i static int not_configged_window_size(int fd, void *data, unsigned short *rows, unsigned short *cols) { - my_puts("Using a channel type which is configured out of " + printk("Using a channel type which is configured out of " "UML\n"); return -ENODEV; } static void not_configged_free(void *data) { - my_puts("Using a channel type which is configured out of " + printk("Using a channel type which is configured out of " "UML\n"); } @@ -255,15 +222,28 @@ void enable_chan(struct line *line) } } +/* Items are added in IRQ context, when free_irq can't be called, and + * removed in process context, when it can. + * This handles interrupt sources which disappear, and which need to + * be permanently disabled. This is discovered in IRQ context, but + * the freeing of the IRQ must be done later. + */ +static DEFINE_SPINLOCK(irqs_to_free_lock); static LIST_HEAD(irqs_to_free); void free_irqs(void) { struct chan *chan; + LIST_HEAD(list); + struct list_head *ele; - while(!list_empty(&irqs_to_free)){ - chan = list_entry(irqs_to_free.next, struct chan, free_list); - list_del(&chan->free_list); + spin_lock_irq(&irqs_to_free_lock); + list_splice_init(&irqs_to_free, &list); + INIT_LIST_HEAD(&irqs_to_free); + spin_unlock_irq(&irqs_to_free_lock); + + list_for_each(ele, &list){ + chan = list_entry(ele, struct chan, free_list); if(chan->input) free_irq(chan->line->driver->read_irq, chan); @@ -279,7 +259,9 @@ static void close_one_chan(struct chan * return; if(delay_free_irq){ + spin_lock_irq(&irqs_to_free_lock); list_add(&chan->free_list, &irqs_to_free); + spin_unlock_irq(&irqs_to_free_lock); } else { if(chan->input) @@ -372,8 +354,7 @@ int console_write_chan(struct list_head return ret; } -int console_open_chan(struct line *line, struct console *co, - const struct chan_opts *opts) +int console_open_chan(struct line *line, struct console *co) { int err; @@ -381,7 +362,7 @@ int console_open_chan(struct line *line, if(err) return err; - printk("Console initialized on /dev/%s%d\n",co->name,co->index); + printk("Console initialized on /dev/%s%d\n", co->name, co->index); return 0; } @@ -534,7 +515,7 @@ #endif }; static struct chan *parse_chan(struct line *line, char *str, int device, - const struct chan_opts *opts) + const struct chan_opts *opts, char **error_out) { const struct chan_type *entry; const struct chan_ops *ops; @@ -553,19 +534,21 @@ static struct chan *parse_chan(struct li } } if(ops == NULL){ - my_printf("parse_chan couldn't parse \"%s\"\n", - str); + *error_out = "No match for configured backends"; return NULL; } - if(ops->init == NULL) - return NULL; + data = (*ops->init)(str, device, opts); - if(data == NULL) + if(data == NULL){ + *error_out = "Configuration failed"; return NULL; + } chan = kmalloc(sizeof(*chan), GFP_ATOMIC); - if(chan == NULL) + if(chan == NULL){ + *error_out = "Memory allocation failed"; return NULL; + } *chan = ((struct chan) { .list = LIST_HEAD_INIT(chan->list), .free_list = LIST_HEAD_INIT(chan->free_list), @@ -582,7 +565,7 @@ static struct chan *parse_chan(struct li } int parse_chan_pair(char *str, struct line *line, int device, - const struct chan_opts *opts) + const struct chan_opts *opts, char **error_out) { struct list_head *chans = &line->chan_list; struct chan *new, *chan; @@ -599,14 +582,14 @@ int parse_chan_pair(char *str, struct li in = str; *out = '\0'; out++; - new = parse_chan(line, in, device, opts); + new = parse_chan(line, in, device, opts, error_out); if(new == NULL) return -1; new->input = 1; list_add(&new->list, chans); - new = parse_chan(line, out, device, opts); + new = parse_chan(line, out, device, opts, error_out); if(new == NULL) return -1; @@ -614,7 +597,7 @@ int parse_chan_pair(char *str, struct li new->output = 1; } else { - new = parse_chan(line, str, device, opts); + new = parse_chan(line, str, device, opts, error_out); if(new == NULL) return -1; diff --git a/arch/um/drivers/harddog_kern.c b/arch/um/drivers/harddog_kern.c index 64ff22a..5560168 100644 --- a/arch/um/drivers/harddog_kern.c +++ b/arch/um/drivers/harddog_kern.c @@ -9,10 +9,10 @@ * 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. - * - * Neither Alan Cox nor CymruNet Ltd. admit liability nor provide - * warranty for any of this software. This material is provided - * "AS-IS" and at no charge. + * + * Neither Alan Cox nor CymruNet Ltd. admit liability nor provide + * warranty for any of this software. This material is provided + * "AS-IS" and at no charge. * * (c) Copyright 1995 Alan Cox * @@ -29,11 +29,11 @@ * Made SMP safe for 2.3.x * * 20011127 Joel Becker (jlbec@evilplan.org> - * Added soft_noboot; Allows testing the softdog trigger without + * Added soft_noboot; Allows testing the softdog trigger without * requiring a recompile. * Added WDIOC_GETTIMEOUT and WDIOC_SETTIMOUT. */ - + #include #include #include @@ -44,12 +44,13 @@ #include #include #include #include +#include #include #include "mconsole.h" MODULE_LICENSE("GPL"); -/* Locked by the BKL in harddog_open and harddog_release */ +static DEFINE_SPINLOCK(lock); static int timer_alive; static int harddog_in_fd = -1; static int harddog_out_fd = -1; @@ -57,18 +58,18 @@ static int harddog_out_fd = -1; /* * Allow only one person to hold it open */ - + extern int start_watchdog(int *in_fd_ret, int *out_fd_ret, char *sock); static int harddog_open(struct inode *inode, struct file *file) { - int err; + int err = -EBUSY; char *sock = NULL; - lock_kernel(); + spin_lock(&lock); if(timer_alive) - return -EBUSY; -#ifdef CONFIG_HARDDOG_NOWAYOUT + goto err; +#ifdef CONFIG_HARDDOG_NOWAYOUT __module_get(THIS_MODULE); #endif @@ -76,11 +77,15 @@ #ifdef CONFIG_MCONSOLE sock = mconsole_notify_socket(); #endif err = start_watchdog(&harddog_in_fd, &harddog_out_fd, sock); - if(err) return(err); + if(err) + goto err; timer_alive = 1; - unlock_kernel(); + spin_unlock(&lock); return nonseekable_open(inode, file); +err: + spin_unlock(&lock); + return err; } extern void stop_watchdog(int in_fd, int out_fd); @@ -90,14 +95,16 @@ static int harddog_release(struct inode /* * Shut off the timer. */ - lock_kernel(); + + spin_lock(&lock); stop_watchdog(harddog_in_fd, harddog_out_fd); harddog_in_fd = -1; harddog_out_fd = -1; timer_alive=0; - unlock_kernel(); + spin_unlock(&lock); + return 0; } @@ -110,7 +117,7 @@ static ssize_t harddog_write(struct file * Refresh the timer. */ if(len) - return(ping_watchdog(harddog_out_fd)); + return ping_watchdog(harddog_out_fd); return 0; } @@ -134,11 +141,11 @@ static int harddog_ioctl(struct inode *i case WDIOC_GETBOOTSTATUS: return put_user(0,(int __user *)argp); case WDIOC_KEEPALIVE: - return(ping_watchdog(harddog_out_fd)); + return ping_watchdog(harddog_out_fd); } } -static struct file_operations harddog_fops = { +static const struct file_operations harddog_fops = { .owner = THIS_MODULE, .write = harddog_write, .ioctl = harddog_ioctl, @@ -165,7 +172,7 @@ static int __init harddog_init(void) printk(banner); - return(0); + return 0; } static void __exit harddog_exit(void) @@ -175,14 +182,3 @@ static void __exit harddog_exit(void) module_init(harddog_init); module_exit(harddog_exit); - -/* - * Overrides for Emacs so that we follow Linus's tabbing style. - * Emacs will notice this stuff at the end of the file and automatically - * adjust the settings for this buffer only. This must remain at the end - * of the file. - * --------------------------------------------------------------------------- - * Local variables: - * c-file-style: "linux" - * End: - */ diff --git a/arch/um/drivers/harddog_user.c b/arch/um/drivers/harddog_user.c index def013b..c495ecf 100644 --- a/arch/um/drivers/harddog_user.c +++ b/arch/um/drivers/harddog_user.c @@ -1,4 +1,4 @@ -/* +/* * Copyright (C) 2002 Jeff Dike (jdike@karaya.com) * Licensed under the GPL */ @@ -38,7 +38,7 @@ int start_watchdog(int *in_fd_ret, int * int in_fds[2], out_fds[2], pid, n, err; char pid_buf[sizeof("nnnnn\0")], c; char *pid_args[] = { "/usr/bin/uml_watchdog", "-pid", pid_buf, NULL }; - char *mconsole_args[] = { "/usr/bin/uml_watchdog", "-mconsole", NULL, + char *mconsole_args[] = { "/usr/bin/uml_watchdog", "-mconsole", NULL, NULL }; char **args = NULL; @@ -96,7 +96,7 @@ int start_watchdog(int *in_fd_ret, int * } *in_fd_ret = in_fds[0]; *out_fd_ret = out_fds[1]; - return(0); + return 0; out_close_in: os_close_file(in_fds[0]); @@ -105,7 +105,7 @@ int start_watchdog(int *in_fd_ret, int * os_close_file(out_fds[0]); os_close_file(out_fds[1]); out: - return(err); + return err; } void stop_watchdog(int in_fd, int out_fd) @@ -123,20 +123,9 @@ int ping_watchdog(int fd) if(n != sizeof(c)){ printk("ping_watchdog - write failed, err = %d\n", -n); if(n < 0) - return(n); - return(-EIO); + return n; + return -EIO; } return 1; } - -/* - * Overrides for Emacs so that we follow Linus's tabbing style. - * Emacs will notice this stuff at the end of the file and automatically - * adjust the settings for this buffer only. This must remain at the end - * of the file. - * --------------------------------------------------------------------------- - * Local variables: - * c-file-style: "linux" - * End: - */ diff --git a/arch/um/drivers/hostaudio_kern.c b/arch/um/drivers/hostaudio_kern.c index a0d148e..10e08a8 100644 --- a/arch/um/drivers/hostaudio_kern.c +++ b/arch/um/drivers/hostaudio_kern.c @@ -15,19 +15,22 @@ #include "init.h" #include "os.h" struct hostaudio_state { - int fd; + int fd; }; struct hostmixer_state { - int fd; + int fd; }; #define HOSTAUDIO_DEV_DSP "/dev/sound/dsp" #define HOSTAUDIO_DEV_MIXER "/dev/sound/mixer" -/* Only changed from linux_main at boot time */ -char *dsp = HOSTAUDIO_DEV_DSP; -char *mixer = HOSTAUDIO_DEV_MIXER; +/* Changed either at boot time or module load time. At boot, this is + * single-threaded; at module load, multiple modules would each have + * their own copy of these variables. + */ +static char *dsp = HOSTAUDIO_DEV_DSP; +static char *mixer = HOSTAUDIO_DEV_MIXER; #define DSP_HELP \ " This is used to specify the host dsp device to the hostaudio driver.\n" \ @@ -69,12 +72,12 @@ #endif static ssize_t hostaudio_read(struct file *file, char __user *buffer, size_t count, loff_t *ppos) { - struct hostaudio_state *state = file->private_data; + struct hostaudio_state *state = file->private_data; void *kbuf; int err; #ifdef DEBUG - printk("hostaudio: read called, count = %d\n", count); + printk("hostaudio: read called, count = %d\n", count); #endif kbuf = kmalloc(count, GFP_KERNEL); @@ -88,7 +91,7 @@ #endif if(copy_to_user(buffer, kbuf, err)) err = -EFAULT; - out: +out: kfree(kbuf); return(err); } @@ -96,12 +99,12 @@ #endif static ssize_t hostaudio_write(struct file *file, const char __user *buffer, size_t count, loff_t *ppos) { - struct hostaudio_state *state = file->private_data; + struct hostaudio_state *state = file->private_data; void *kbuf; int err; #ifdef DEBUG - printk("hostaudio: write called, count = %d\n", count); + printk("hostaudio: write called, count = %d\n", count); #endif kbuf = kmalloc(count, GFP_KERNEL); @@ -125,24 +128,24 @@ #endif static unsigned int hostaudio_poll(struct file *file, struct poll_table_struct *wait) { - unsigned int mask = 0; + unsigned int mask = 0; #ifdef DEBUG - printk("hostaudio: poll called (unimplemented)\n"); + printk("hostaudio: poll called (unimplemented)\n"); #endif - return(mask); + return(mask); } static int hostaudio_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) { - struct hostaudio_state *state = file->private_data; + struct hostaudio_state *state = file->private_data; unsigned long data = 0; int err; #ifdef DEBUG - printk("hostaudio: ioctl called, cmd = %u\n", cmd); + printk("hostaudio: ioctl called, cmd = %u\n", cmd); #endif switch(cmd){ case SNDCTL_DSP_SPEED: @@ -179,42 +182,40 @@ #endif static int hostaudio_open(struct inode *inode, struct file *file) { - struct hostaudio_state *state; - int r = 0, w = 0; - int ret; + struct hostaudio_state *state; + int r = 0, w = 0; + int ret; #ifdef DEBUG - printk("hostaudio: open called (host: %s)\n", dsp); + printk("hostaudio: open called (host: %s)\n", dsp); #endif - state = kmalloc(sizeof(struct hostaudio_state), GFP_KERNEL); - if(state == NULL) + state = kmalloc(sizeof(struct hostaudio_state), GFP_KERNEL); + if(state == NULL) return(-ENOMEM); - if(file->f_mode & FMODE_READ) r = 1; - if(file->f_mode & FMODE_WRITE) w = 1; + if(file->f_mode & FMODE_READ) r = 1; + if(file->f_mode & FMODE_WRITE) w = 1; ret = os_open_file(dsp, of_set_rw(OPENFLAGS(), r, w), 0); - if(ret < 0){ + if(ret < 0){ kfree(state); return(ret); - } - + } state->fd = ret; - file->private_data = state; - return(0); + file->private_data = state; + return(0); } static int hostaudio_release(struct inode *inode, struct file *file) { - struct hostaudio_state *state = file->private_data; + struct hostaudio_state *state = file->private_data; #ifdef DEBUG - printk("hostaudio: release called\n"); + printk("hostaudio: release called\n"); #endif - - os_close_file(state->fd); - kfree(state); + os_close_file(state->fd); + kfree(state); return(0); } @@ -224,10 +225,10 @@ #endif static int hostmixer_ioctl_mixdev(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) { - struct hostmixer_state *state = file->private_data; + struct hostmixer_state *state = file->private_data; #ifdef DEBUG - printk("hostmixer: ioctl called\n"); + printk("hostmixer: ioctl called\n"); #endif return(os_ioctl_generic(state->fd, cmd, arg)); @@ -235,68 +236,67 @@ #endif static int hostmixer_open_mixdev(struct inode *inode, struct file *file) { - struct hostmixer_state *state; - int r = 0, w = 0; - int ret; + struct hostmixer_state *state; + int r = 0, w = 0; + int ret; #ifdef DEBUG - printk("hostmixer: open called (host: %s)\n", mixer); + printk("hostmixer: open called (host: %s)\n", mixer); #endif - state = kmalloc(sizeof(struct hostmixer_state), GFP_KERNEL); - if(state == NULL) return(-ENOMEM); + state = kmalloc(sizeof(struct hostmixer_state), GFP_KERNEL); + if(state == NULL) return(-ENOMEM); - if(file->f_mode & FMODE_READ) r = 1; - if(file->f_mode & FMODE_WRITE) w = 1; + if(file->f_mode & FMODE_READ) r = 1; + if(file->f_mode & FMODE_WRITE) w = 1; ret = os_open_file(mixer, of_set_rw(OPENFLAGS(), r, w), 0); - if(ret < 0){ + if(ret < 0){ printk("hostaudio_open_mixdev failed to open '%s', err = %d\n", dsp, -ret); kfree(state); return(ret); - } + } - file->private_data = state; - return(0); + file->private_data = state; + return(0); } static int hostmixer_release(struct inode *inode, struct file *file) { - struct hostmixer_state *state = file->private_data; + struct hostmixer_state *state = file->private_data; #ifdef DEBUG - printk("hostmixer: release called\n"); + printk("hostmixer: release called\n"); #endif - os_close_file(state->fd); - kfree(state); + os_close_file(state->fd); + kfree(state); return(0); } - /* kernel module operations */ static const struct file_operations hostaudio_fops = { - .owner = THIS_MODULE, - .llseek = no_llseek, - .read = hostaudio_read, - .write = hostaudio_write, - .poll = hostaudio_poll, - .ioctl = hostaudio_ioctl, - .mmap = NULL, - .open = hostaudio_open, - .release = hostaudio_release, + .owner = THIS_MODULE, + .llseek = no_llseek, + .read = hostaudio_read, + .write = hostaudio_write, + .poll = hostaudio_poll, + .ioctl = hostaudio_ioctl, + .mmap = NULL, + .open = hostaudio_open, + .release = hostaudio_release, }; static const struct file_operations hostmixer_fops = { - .owner = THIS_MODULE, - .llseek = no_llseek, - .ioctl = hostmixer_ioctl_mixdev, - .open = hostmixer_open_mixdev, - .release = hostmixer_release, + .owner = THIS_MODULE, + .llseek = no_llseek, + .ioctl = hostmixer_ioctl_mixdev, + .open = hostmixer_open_mixdev, + .release = hostmixer_release, }; struct { @@ -310,42 +310,31 @@ MODULE_LICENSE("GPL"); static int __init hostaudio_init_module(void) { - printk(KERN_INFO "UML Audio Relay (host dsp = %s, host mixer = %s)\n", + printk(KERN_INFO "UML Audio Relay (host dsp = %s, host mixer = %s)\n", dsp, mixer); module_data.dev_audio = register_sound_dsp(&hostaudio_fops, -1); - if(module_data.dev_audio < 0){ - printk(KERN_ERR "hostaudio: couldn't register DSP device!\n"); - return -ENODEV; - } + if(module_data.dev_audio < 0){ + printk(KERN_ERR "hostaudio: couldn't register DSP device!\n"); + return -ENODEV; + } module_data.dev_mixer = register_sound_mixer(&hostmixer_fops, -1); - if(module_data.dev_mixer < 0){ - printk(KERN_ERR "hostmixer: couldn't register mixer " + if(module_data.dev_mixer < 0){ + printk(KERN_ERR "hostmixer: couldn't register mixer " "device!\n"); - unregister_sound_dsp(module_data.dev_audio); - return -ENODEV; - } + unregister_sound_dsp(module_data.dev_audio); + return -ENODEV; + } - return 0; + return 0; } static void __exit hostaudio_cleanup_module (void) { - unregister_sound_mixer(module_data.dev_mixer); - unregister_sound_dsp(module_data.dev_audio); + unregister_sound_mixer(module_data.dev_mixer); + unregister_sound_dsp(module_data.dev_audio); } module_init(hostaudio_init_module); module_exit(hostaudio_cleanup_module); - -/* - * Overrides for Emacs so that we follow Linus's tabbing style. - * Emacs will notice this stuff at the end of the file and automatically - * adjust the settings for this buffer only. This must remain at the end - * of the file. - * --------------------------------------------------------------------------- - * Local variables: - * c-file-style: "linux" - * End: - */ diff --git a/arch/um/drivers/line.c b/arch/um/drivers/line.c index 83301e1..01d4ab6 100644 --- a/arch/um/drivers/line.c +++ b/arch/um/drivers/line.c @@ -191,7 +191,6 @@ void line_flush_buffer(struct tty_struct /*XXX: copied from line_write, verify if it is correct!*/ if(tty->stopped) return; - //return 0; spin_lock_irqsave(&line->lock, flags); err = flush_buffer(line); @@ -421,42 +420,55 @@ int line_setup_irq(int fd, int input, in return err; } +/* Normally, a driver like this can rely mostly on the tty layer + * locking, particularly when it comes to the driver structure. + * However, in this case, mconsole requests can come in "from the + * side", and race with opens and closes. + * + * mconsole config requests will want to be sure the device isn't in + * use, and get_config, open, and close will want a stable + * configuration. The checking and modification of the configuration + * is done under a spinlock. Checking whether the device is in use is + * line->tty->count > 1, also under the spinlock. + * + * tty->count serves to decide whether the device should be enabled or + * disabled on the host. If it's equal to 1, then we are doing the + * first open or last close. Otherwise, open and close just return. + */ + int line_open(struct line *lines, struct tty_struct *tty) { - struct line *line; + struct line *line = &lines[tty->index]; int err = -ENODEV; - line = &lines[tty->index]; - tty->driver_data = line; + spin_lock(&line->count_lock); + if(!line->valid) + goto out_unlock; - /* The IRQ which takes this lock is not yet enabled and won't be run - * before the end, so we don't need to use spin_lock_irq.*/ - spin_lock(&line->lock); + err = 0; + if(tty->count > 1) + goto out_unlock; + + spin_unlock(&line->count_lock); tty->driver_data = line; line->tty = tty; - if(!line->valid) - goto out; - if(tty->count == 1){ - /* Here the device is opened, if necessary, and interrupt - * is registered. - */ - enable_chan(line); - INIT_DELAYED_WORK(&line->task, line_timer_cb); + enable_chan(line); + INIT_DELAYED_WORK(&line->task, line_timer_cb); - if(!line->sigio){ - chan_enable_winch(&line->chan_list, tty); - line->sigio = 1; - } - - chan_window_size(&line->chan_list, &tty->winsize.ws_row, - &tty->winsize.ws_col); + if(!line->sigio){ + chan_enable_winch(&line->chan_list, tty); + line->sigio = 1; } - err = 0; -out: - spin_unlock(&line->lock); + chan_window_size(&line->chan_list, &tty->winsize.ws_row, + &tty->winsize.ws_col); + + return err; + +out_unlock: + spin_unlock(&line->count_lock); return err; } @@ -466,25 +478,36 @@ void line_close(struct tty_struct *tty, { struct line *line = tty->driver_data; - /* XXX: I assume this should be called in process context, not with - * interrupts disabled! - */ - spin_lock_irq(&line->lock); + /* If line_open fails (and tty->driver_data is never set), + * tty_open will call line_close. So just return in this case. + */ + if(line == NULL) + return; /* We ignore the error anyway! */ flush_buffer(line); - if(tty->count == 1){ - line->tty = NULL; - tty->driver_data = NULL; + spin_lock(&line->count_lock); + if(!line->valid) + goto out_unlock; - if(line->sigio){ - unregister_winch(tty); - line->sigio = 0; - } + if(tty->count > 1) + goto out_unlock; + + spin_unlock(&line->count_lock); + + line->tty = NULL; + tty->driver_data = NULL; + + if(line->sigio){ + unregister_winch(tty); + line->sigio = 0; } - spin_unlock_irq(&line->lock); + return; + +out_unlock: + spin_unlock(&line->count_lock); } void close_lines(struct line *lines, int nlines) @@ -495,14 +518,44 @@ void close_lines(struct line *lines, int close_chan(&lines[i].chan_list, 0); } +static int setup_one_line(struct line *lines, int n, char *init, int init_prio, + char **error_out) +{ + struct line *line = &lines[n]; + int err = -EINVAL; + + spin_lock(&line->count_lock); + + if(line->tty != NULL){ + *error_out = "Device is already open"; + goto out; + } + + if (line->init_pri <= init_prio){ + line->init_pri = init_prio; + if (!strcmp(init, "none")) + line->valid = 0; + else { + line->init_str = init; + line->valid = 1; + } + } + err = 0; +out: + spin_unlock(&line->count_lock); + return err; +} + /* Common setup code for both startup command line and mconsole initialization. * @lines contains the array (of size @num) to modify; * @init is the setup string; + * @error_out is an error string in the case of failure; */ -int line_setup(struct line *lines, unsigned int num, char *init) +int line_setup(struct line *lines, unsigned int num, char *init, + char **error_out) { - int i, n; + int i, n, err; char *end; if(*init == '=') { @@ -513,73 +566,56 @@ int line_setup(struct line *lines, unsig else { n = simple_strtoul(init, &end, 0); if(*end != '='){ - printk(KERN_ERR "line_setup failed to parse \"%s\"\n", - init); - return 0; + *error_out = "Couldn't parse device number"; + return -EINVAL; } init = end; } init++; if (n >= (signed int) num) { - printk("line_setup - %d out of range ((0 ... %d) allowed)\n", - n, num - 1); - return 0; + *error_out = "Device number out of range"; + return -EINVAL; } else if (n >= 0){ - if (lines[n].tty != NULL) { - printk("line_setup - device %d is open\n", n); - return 0; - } - if (lines[n].init_pri <= INIT_ONE){ - lines[n].init_pri = INIT_ONE; - if (!strcmp(init, "none")) - lines[n].valid = 0; - else { - lines[n].init_str = init; - lines[n].valid = 1; - } - } + err = setup_one_line(lines, n, init, INIT_ONE, error_out); + if(err) + return err; } else { for(i = 0; i < num; i++){ - if(lines[i].init_pri <= INIT_ALL){ - lines[i].init_pri = INIT_ALL; - if(!strcmp(init, "none")) lines[i].valid = 0; - else { - lines[i].init_str = init; - lines[i].valid = 1; - } - } + err = setup_one_line(lines, i, init, INIT_ALL, + error_out); + if(err) + return err; } } return n == -1 ? num : n; } int line_config(struct line *lines, unsigned int num, char *str, - const struct chan_opts *opts) + const struct chan_opts *opts, char **error_out) { struct line *line; char *new; int n; if(*str == '='){ - printk("line_config - can't configure all devices from " - "mconsole\n"); - return 1; + *error_out = "Can't configure all devices from mconsole"; + return -EINVAL; } new = kstrdup(str, GFP_KERNEL); if(new == NULL){ - printk("line_config - kstrdup failed\n"); - return 1; + *error_out = "Failed to allocate memory"; + return -ENOMEM; } - n = line_setup(lines, num, new); + n = line_setup(lines, num, new, error_out); if(n < 0) - return 1; + return n; line = &lines[n]; - return parse_chan_pair(line->init_str, line, n, opts); + return parse_chan_pair(line->init_str, line, n, opts, error_out); } int line_get_config(char *name, struct line *lines, unsigned int num, char *str, @@ -602,13 +638,13 @@ int line_get_config(char *name, struct l line = &lines[dev]; - spin_lock(&line->lock); + spin_lock(&line->count_lock); if(!line->valid) CONFIG_CHUNK(str, size, n, "none", 1); else if(line->tty == NULL) CONFIG_CHUNK(str, size, n, line->init_str, 1); else n = chan_config_string(&line->chan_list, str, size, error_out); - spin_unlock(&line->lock); + spin_unlock(&line->count_lock); return n; } @@ -628,22 +664,21 @@ int line_id(char **str, int *start_out, return n; } -int line_remove(struct line *lines, unsigned int num, int n) +int line_remove(struct line *lines, unsigned int num, int n, char **error_out) { int err; char config[sizeof("conxxxx=none\0")]; sprintf(config, "%d=none", n); - err = line_setup(lines, num, config); + err = line_setup(lines, num, config, error_out); if(err >= 0) err = 0; return err; } -struct tty_driver *line_register_devfs(struct lines *set, - struct line_driver *line_driver, - const struct tty_operations *ops, - struct line *lines, int nlines) +struct tty_driver *register_lines(struct line_driver *line_driver, + const struct tty_operations *ops, + struct line *lines, int nlines) { int i; struct tty_driver *driver = alloc_tty_driver(nlines); @@ -683,6 +718,7 @@ static LIST_HEAD(winch_handlers); void lines_init(struct line *lines, int nlines, struct chan_opts *opts) { struct line *line; + char *error; int i; for(i = 0; i < nlines; i++){ @@ -696,8 +732,9 @@ void lines_init(struct line *lines, int if(line->init_str == NULL) printk("lines_init - kstrdup returned NULL\n"); - if(parse_chan_pair(line->init_str, line, i, opts)){ - printk("parse_chan_pair failed for device %d\n", i); + if(parse_chan_pair(line->init_str, line, i, opts, &error)){ + printk("parse_chan_pair failed for device %d : %s\n", + i, error); line->valid = 0; } } @@ -737,7 +774,7 @@ static irqreturn_t winch_interrupt(int i line = tty->driver_data; chan_window_size(&line->chan_list, &tty->winsize.ws_row, &tty->winsize.ws_col); - kill_pg(tty->pgrp, SIGWINCH, 1); + kill_pgrp(tty->pgrp, SIGWINCH, 1); } out: if(winch->fd != -1) diff --git a/arch/um/drivers/mconsole_kern.c b/arch/um/drivers/mconsole_kern.c index 96f0189..178b2ef 100644 --- a/arch/um/drivers/mconsole_kern.c +++ b/arch/um/drivers/mconsole_kern.c @@ -33,7 +33,6 @@ #include "mconsole_kern.h" #include "irq_user.h" #include "init.h" #include "os.h" -#include "umid.h" #include "irq_kern.h" #include "choose-mode.h" @@ -337,13 +336,15 @@ void mconsole_stop(struct mc_request *re mconsole_reply(req, "", 0, 0); } -/* This list is populated by __initcall routines. */ - +static DEFINE_SPINLOCK(mc_devices_lock); static LIST_HEAD(mconsole_devices); void mconsole_register_dev(struct mc_device *new) { + spin_lock(&mc_devices_lock); + BUG_ON(!list_empty(&new->list)); list_add(&new->list, &mconsole_devices); + spin_unlock(&mc_devices_lock); } static struct mc_device *mconsole_find_dev(char *name) @@ -367,18 +368,21 @@ struct unplugged_pages { void *pages[UNPLUGGED_PER_PAGE]; }; +static DECLARE_MUTEX(plug_mem_mutex); static unsigned long long unplugged_pages_count = 0; -static struct list_head unplugged_pages = LIST_HEAD_INIT(unplugged_pages); +static LIST_HEAD(unplugged_pages); static int unplug_index = UNPLUGGED_PER_PAGE; -static int mem_config(char *str) +static int mem_config(char *str, char **error_out) { unsigned long long diff; int err = -EINVAL, i, add; char *ret; - if(str[0] != '=') + if(str[0] != '='){ + *error_out = "Expected '=' after 'mem'"; goto out; + } str++; if(str[0] == '-') @@ -386,15 +390,21 @@ static int mem_config(char *str) else if(str[0] == '+'){ add = 1; } - else goto out; + else { + *error_out = "Expected increment to start with '-' or '+'"; + goto out; + } str++; diff = memparse(str, &ret); - if(*ret != '\0') + if(*ret != '\0'){ + *error_out = "Failed to parse memory increment"; goto out; + } diff /= PAGE_SIZE; + down(&plug_mem_mutex); for(i = 0; i < diff; i++){ struct unplugged_pages *unplugged; void *addr; @@ -435,11 +445,14 @@ static int mem_config(char *str) unplugged = list_entry(entry, struct unplugged_pages, list); - unplugged->pages[unplug_index++] = addr; err = os_drop_memory(addr, PAGE_SIZE); - if(err) + if(err){ printk("Failed to release memory - " "errno = %d\n", err); + *error_out = "Failed to release memory"; + goto out_unlock; + } + unplugged->pages[unplug_index++] = addr; } unplugged_pages_count++; @@ -447,6 +460,8 @@ static int mem_config(char *str) } err = 0; +out_unlock: + up(&plug_mem_mutex); out: return err; } @@ -470,12 +485,14 @@ static int mem_id(char **str, int *start return 0; } -static int mem_remove(int n) +static int mem_remove(int n, char **error_out) { + *error_out = "Memory doesn't support the remove operation"; return -EBUSY; } static struct mc_device mem_mc = { + .list = LIST_HEAD_INIT(mem_mc.list), .name = "mem", .config = mem_config, .get_config = mem_get_config, @@ -542,7 +559,7 @@ static void mconsole_get_config(int (*ge void mconsole_config(struct mc_request *req) { struct mc_device *dev; - char *ptr = req->request.data, *name; + char *ptr = req->request.data, *name, *error_string = ""; int err; ptr += strlen("config"); @@ -559,8 +576,8 @@ void mconsole_config(struct mc_request * ptr++; if(*ptr == '='){ - err = (*dev->config)(name); - mconsole_reply(req, "", err, 0); + err = (*dev->config)(name, &error_string); + mconsole_reply(req, error_string, err, 0); } else mconsole_get_config(dev->get_config, req, name); } @@ -595,13 +612,16 @@ void mconsole_remove(struct mc_request * goto out; } - err = (*dev->remove)(n); + err_msg = NULL; + err = (*dev->remove)(n, &err_msg); switch(err){ case -ENODEV: - err_msg = "Device doesn't exist"; + if(err_msg == NULL) + err_msg = "Device doesn't exist"; break; case -EBUSY: - err_msg = "Device is currently open"; + if(err_msg == NULL) + err_msg = "Device is currently open"; break; default: break; @@ -615,7 +635,7 @@ struct mconsole_output { struct mc_request *req; }; -static DEFINE_SPINLOCK(console_lock); +static DEFINE_SPINLOCK(client_lock); static LIST_HEAD(clients); static char console_buf[MCONSOLE_MAX_DATA]; static int console_index = 0; @@ -670,16 +690,18 @@ static void with_console(struct mc_reque unsigned long flags; entry.req = req; + spin_lock_irqsave(&client_lock, flags); list_add(&entry.list, &clients); - spin_lock_irqsave(&console_lock, flags); + spin_unlock_irqrestore(&client_lock, flags); (*proc)(arg); mconsole_reply_len(req, console_buf, console_index, 0, 0); console_index = 0; - spin_unlock_irqrestore(&console_lock, flags); + spin_lock_irqsave(&client_lock, flags); list_del(&entry.list); + spin_unlock_irqrestore(&client_lock, flags); } #ifdef CONFIG_MAGIC_SYSRQ diff --git a/arch/um/drivers/mconsole_user.c b/arch/um/drivers/mconsole_user.c index 75aef6f..f02634f 100644 --- a/arch/um/drivers/mconsole_user.c +++ b/arch/um/drivers/mconsole_user.c @@ -16,7 +16,7 @@ #include #include "user.h" #include "sysdep/ptrace.h" #include "mconsole.h" -#include "umid.h" +#include "os.h" #include "user_util.h" static struct mconsole_command commands[] = { diff --git a/arch/um/drivers/net_kern.c b/arch/um/drivers/net_kern.c index afe3d42..04e31f8 100644 --- a/arch/um/drivers/net_kern.c +++ b/arch/um/drivers/net_kern.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2001 Lennert Buytenhek (buytenh@gnu.org) and + * Copyright (C) 2001 Lennert Buytenhek (buytenh@gnu.org) and * James Leu (jleu@mindspring.net). * Copyright (C) 2001 by various other people who didn't put their name here. * Licensed under the GPL. @@ -91,8 +91,8 @@ irqreturn_t uml_net_interrupt(int irq, v spin_lock(&lp->lock); while((err = uml_net_rx(dev)) > 0) ; if(err < 0) { - printk(KERN_ERR - "Device '%s' read returned %d, shutting it down\n", + printk(KERN_ERR + "Device '%s' read returned %d, shutting it down\n", dev->name, err); /* dev_close can't be called in interrupt context, and takes * again lp->lock. @@ -108,7 +108,7 @@ irqreturn_t uml_net_interrupt(int irq, v out: spin_unlock(&lp->lock); - return(IRQ_HANDLED); + return IRQ_HANDLED; } static int uml_net_open(struct net_device *dev) @@ -159,7 +159,7 @@ out: static int uml_net_close(struct net_device *dev) { struct uml_net_private *lp = dev->priv; - + netif_stop_queue(dev); free_irq(dev->irq, dev); @@ -194,7 +194,7 @@ static int uml_net_start_xmit(struct sk_ /* this is normally done in the interrupt when tx finishes */ netif_wake_queue(dev); - } + } else if(len == 0){ netif_start_queue(dev); lp->stats.tx_dropped++; @@ -239,7 +239,7 @@ static int uml_net_set_mac(struct net_de set_ether_mac(dev, hwaddr->sa_data); spin_unlock_irq(&lp->lock); - return(0); + return 0; } static int uml_net_change_mtu(struct net_device *dev, int new_mtu) @@ -333,7 +333,7 @@ static int eth_configure(int n, void *in struct uml_net_private *lp; int save, err, size; - size = transport->private_size + sizeof(struct uml_net_private) + + size = transport->private_size + sizeof(struct uml_net_private) + sizeof(((struct uml_net_private *) 0)->user); device = kzalloc(sizeof(*device), GFP_KERNEL); @@ -438,7 +438,7 @@ static int eth_configure(int n, void *in lp->tl.function = uml_net_user_timer_expire; memcpy(lp->mac, device->mac, sizeof(lp->mac)); - if (transport->user->init) + if (transport->user->init) (*transport->user->init)(&lp->user, dev); set_ether_mac(dev, device->mac); @@ -460,38 +460,36 @@ static struct uml_net *find_device(int n device = NULL; out: spin_unlock(&devices_lock); - return(device); + return device; } -static int eth_parse(char *str, int *index_out, char **str_out) +static int eth_parse(char *str, int *index_out, char **str_out, + char **error_out) { char *end; - int n; + int n, err = -EINVAL;; n = simple_strtoul(str, &end, 0); if(end == str){ - printk(KERN_ERR "eth_setup: Failed to parse '%s'\n", str); - return(1); - } - if(n < 0){ - printk(KERN_ERR "eth_setup: device %d is negative\n", n); - return(1); + *error_out = "Bad device number"; + return err; } + str = end; if(*str != '='){ - printk(KERN_ERR - "eth_setup: expected '=' after device number\n"); - return(1); + *error_out = "Expected '=' after device number"; + return err; } + str++; if(find_device(n)){ - printk(KERN_ERR "eth_setup: Device %d already configured\n", - n); - return(1); + *error_out = "Device already configured"; + return err; } - if(index_out) *index_out = n; + + *index_out = n; *str_out = str; - return(0); + return 0; } struct eth_init { @@ -500,13 +498,11 @@ struct eth_init { int index; }; -/* Filled in at boot time. Will need locking if the transports become - * modular. - */ -struct list_head transports = LIST_HEAD_INIT(transports); +static DEFINE_SPINLOCK(transports_lock); +static LIST_HEAD(transports); /* Filled in during early boot */ -struct list_head eth_cmd_line = LIST_HEAD_INIT(eth_cmd_line); +static LIST_HEAD(eth_cmd_line); static int check_transport(struct transport *transport, char *eth, int n, void **init_out, char **mac_out) @@ -515,23 +511,23 @@ static int check_transport(struct transp len = strlen(transport->name); if(strncmp(eth, transport->name, len)) - return(0); + return 0; eth += len; if(*eth == ',') eth++; else if(*eth != '\0') - return(0); + return 0; *init_out = kmalloc(transport->setup_size, GFP_KERNEL); if(*init_out == NULL) - return(1); + return 1; if(!transport->setup(eth, mac_out, *init_out)){ kfree(*init_out); *init_out = NULL; } - return(1); + return 1; } void register_transport(struct transport *new) @@ -542,7 +538,10 @@ void register_transport(struct transport char *mac = NULL; int match; + spin_lock(&transports_lock); + BUG_ON(!list_empty(&new->list)); list_add(&new->list, &transports); + spin_unlock(&transports_lock); list_for_each_safe(ele, next, ð_cmd_line){ eth = list_entry(ele, struct eth_init, list); @@ -564,7 +563,9 @@ static int eth_setup_common(char *str, i struct transport *transport; void *init; char *mac = NULL; + int found = 0; + spin_lock(&transports_lock); list_for_each(ele, &transports){ transport = list_entry(ele, struct transport, list); if(!check_transport(transport, str, index, &init, &mac)) @@ -573,19 +574,26 @@ static int eth_setup_common(char *str, i eth_configure(index, init, mac, transport); kfree(init); } - return(1); + found = 1; + break; } - return(0); + + spin_unlock(&transports_lock); + return found; } static int eth_setup(char *str) { struct eth_init *new; + char *error; int n, err; - err = eth_parse(str, &n, &str); - if(err) + err = eth_parse(str, &n, &str, &error); + if(err){ + printk(KERN_ERR "eth_setup - Couldn't parse '%s' : %s\n", + str, error); return 1; + } new = alloc_bootmem(sizeof(*new)); if (new == NULL){ @@ -607,38 +615,24 @@ __uml_help(eth_setup, " Configure a network device.\n\n" ); -#if 0 -static int eth_init(void) -{ - struct list_head *ele, *next; - struct eth_init *eth; - - list_for_each_safe(ele, next, ð_cmd_line){ - eth = list_entry(ele, struct eth_init, list); - - if(eth_setup_common(eth->init, eth->index)) - list_del(ð->list); - } - - return(1); -} -__initcall(eth_init); -#endif - -static int net_config(char *str) +static int net_config(char *str, char **error_out) { int n, err; - err = eth_parse(str, &n, &str); - if(err) return(err); + err = eth_parse(str, &n, &str, error_out); + if(err) + return err; + /* This string is broken up and the pieces used by the underlying + * driver. So, it is freed only if eth_setup_common fails. + */ str = kstrdup(str, GFP_KERNEL); if(str == NULL){ - printk(KERN_ERR "net_config failed to strdup string\n"); - return(-1); + *error_out = "net_config failed to strdup string"; + return -ENOMEM; } err = !eth_setup_common(str, n); - if(err) + if(err) kfree(str); return(err); } @@ -658,7 +652,7 @@ static int net_id(char **str, int *start return n; } -static int net_remove(int n) +static int net_remove(int n, char **error_out) { struct uml_net *device; struct net_device *dev; @@ -671,7 +665,7 @@ static int net_remove(int n) dev = device->dev; lp = dev->priv; if(lp->fd > 0) - return -EBUSY; + return -EBUSY; if(lp->remove != NULL) (*lp->remove)(&lp->user); unregister_netdev(dev); platform_device_unregister(&device->pdev); @@ -683,10 +677,11 @@ static int net_remove(int n) } static struct mc_device net_mc = { + .list = LIST_HEAD_INIT(net_mc.list), .name = "eth", .config = net_config, .get_config = NULL, - .id = net_id, + .id = net_id, .remove = net_remove, }; @@ -699,7 +694,8 @@ static int uml_inetaddr_event(struct not void (*proc)(unsigned char *, unsigned char *, void *); unsigned char addr_buf[4], netmask_buf[4]; - if(dev->open != uml_net_open) return(NOTIFY_DONE); + if(dev->open != uml_net_open) + return NOTIFY_DONE; lp = dev->priv; @@ -717,9 +713,10 @@ static int uml_inetaddr_event(struct not memcpy(netmask_buf, &ifa->ifa_mask, sizeof(netmask_buf)); (*proc)(addr_buf, netmask_buf, &lp->user); } - return(NOTIFY_DONE); + return NOTIFY_DONE; } +/* uml_net_init shouldn't be called twice on two CPUs at the same time */ struct notifier_block uml_inetaddr_notifier = { .notifier_call = uml_inetaddr_event, }; @@ -727,7 +724,7 @@ struct notifier_block uml_inetaddr_notif static int uml_net_init(void) { struct list_head *ele; - struct uml_net_private *lp; + struct uml_net_private *lp; struct in_device *ip; struct in_ifaddr *in; @@ -738,18 +735,21 @@ static int uml_net_init(void) * didn't get a chance to run for them. This fakes it so that * addresses which have already been set up get handled properly. */ + spin_lock(&opened_lock); list_for_each(ele, &opened){ lp = list_entry(ele, struct uml_net_private, list); ip = lp->dev->ip_ptr; - if(ip == NULL) continue; + if(ip == NULL) + continue; in = ip->ifa_list; while(in != NULL){ uml_inetaddr_event(NULL, NETDEV_UP, in); in = in->ifa_next; } - } + } + spin_unlock(&opened_lock); - return(0); + return 0; } __initcall(uml_net_init); @@ -759,13 +759,16 @@ static void close_devices(void) struct list_head *ele; struct uml_net_private *lp; + spin_lock(&opened_lock); list_for_each(ele, &opened){ lp = list_entry(ele, struct uml_net_private, list); free_irq(lp->dev->irq, lp->dev); if((lp->close != NULL) && (lp->fd >= 0)) (*lp->close)(lp->fd, &lp->user); - if(lp->remove != NULL) (*lp->remove)(&lp->user); + if(lp->remove != NULL) + (*lp->remove)(&lp->user); } + spin_unlock(&opened_lock); } __uml_exitcall(close_devices); @@ -783,8 +786,8 @@ struct sk_buff *ether_adjust_skb(struct return(skb); } -void iter_addresses(void *d, void (*cb)(unsigned char *, unsigned char *, - void *), +void iter_addresses(void *d, void (*cb)(unsigned char *, unsigned char *, + void *), void *arg) { struct net_device *dev = d; @@ -809,11 +812,11 @@ int dev_netmask(void *d, void *m) struct in_ifaddr *in; __be32 *mask_out = m; - if(ip == NULL) + if(ip == NULL) return(1); in = ip->ifa_list; - if(in == NULL) + if(in == NULL) return(1); *mask_out = in->ifa_mask; @@ -827,7 +830,7 @@ void *get_output_buffer(int *len_out) ret = (void *) __get_free_pages(GFP_KERNEL, 0); if(ret) *len_out = PAGE_SIZE; else *len_out = 0; - return(ret); + return ret; } void free_output_buffer(void *buffer) @@ -835,7 +838,7 @@ void free_output_buffer(void *buffer) free_pages((unsigned long) buffer, 0); } -int tap_setup_common(char *str, char *type, char **dev_name, char **mac_out, +int tap_setup_common(char *str, char *type, char **dev_name, char **mac_out, char **gate_addr) { char *remain; @@ -854,14 +857,3 @@ unsigned short eth_protocol(struct sk_bu { return(eth_type_trans(skb, skb->dev)); } - -/* - * Overrides for Emacs so that we follow Linus's tabbing style. - * Emacs will notice this stuff at the end of the file and automatically - * adjust the settings for this buffer only. This must remain at the end - * of the file. - * --------------------------------------------------------------------------- - * Local variables: - * c-file-style: "linux" - * End: - */ diff --git a/arch/um/drivers/port_kern.c b/arch/um/drivers/port_kern.c index 6dfe632..1c8efd9 100644 --- a/arch/um/drivers/port_kern.c +++ b/arch/um/drivers/port_kern.c @@ -1,4 +1,4 @@ -/* +/* * Copyright (C) 2001, 2002 Jeff Dike (jdike@karaya.com) * Licensed under the GPL */ @@ -55,9 +55,9 @@ static irqreturn_t pipe_interrupt(int ir fd = os_rcv_fd(conn->socket[0], &conn->helper_pid); if(fd < 0){ if(fd == -EAGAIN) - return(IRQ_NONE); + return IRQ_NONE; - printk(KERN_ERR "pipe_interrupt : os_rcv_fd returned %d\n", + printk(KERN_ERR "pipe_interrupt : os_rcv_fd returned %d\n", -fd); os_close_file(conn->fd); } @@ -68,7 +68,7 @@ static irqreturn_t pipe_interrupt(int ir list_add(&conn->list, &conn->port->connections); complete(&conn->port->done); - return(IRQ_HANDLED); + return IRQ_HANDLED; } #define NO_WAITER_MSG \ @@ -97,14 +97,14 @@ static int port_accept(struct port_list "connection\n"); goto out_close; } - *conn = ((struct connection) + *conn = ((struct connection) { .list = LIST_HEAD_INIT(conn->list), .fd = fd, .socket = { socket[0], socket[1] }, .telnetd_pid = pid, .port = port }); - if(um_request_irq(TELNETD_IRQ, socket[0], IRQ_READ, pipe_interrupt, + if(um_request_irq(TELNETD_IRQ, socket[0], IRQ_READ, pipe_interrupt, IRQF_DISABLED | IRQF_SHARED | IRQF_SAMPLE_RANDOM, "telnetd", conn)){ printk(KERN_ERR "port_accept : failed to get IRQ for " @@ -117,20 +117,20 @@ static int port_accept(struct port_list printk("No one waiting for port\n"); } list_add(&conn->list, &port->pending); - return(1); + return 1; out_free: kfree(conn); out_close: os_close_file(fd); - if(pid != -1) + if(pid != -1) os_kill_process(pid, 1); out: - return(ret); -} + return ret; +} -DECLARE_MUTEX(ports_sem); -struct list_head ports = LIST_HEAD_INIT(ports); +static DECLARE_MUTEX(ports_sem); +static LIST_HEAD(ports); void port_work_proc(struct work_struct *unused) { @@ -158,8 +158,8 @@ static irqreturn_t port_interrupt(int ir port->has_connection = 1; schedule_work(&port_work); - return(IRQ_HANDLED); -} + return IRQ_HANDLED; +} void *port_data(int port_num) { @@ -185,14 +185,14 @@ void *port_data(int port_num) port_num, -fd); goto out_free; } - if(um_request_irq(ACCEPT_IRQ, fd, IRQ_READ, port_interrupt, - IRQF_DISABLED | IRQF_SHARED | IRQF_SAMPLE_RANDOM, "port", - port)){ + if(um_request_irq(ACCEPT_IRQ, fd, IRQ_READ, port_interrupt, + IRQF_DISABLED | IRQF_SHARED | IRQF_SAMPLE_RANDOM, + "port", port)){ printk(KERN_ERR "Failed to get IRQ for port %d\n", port_num); goto out_close; } - *port = ((struct port_list) + *port = ((struct port_list) { .list = LIST_HEAD_INIT(port->list), .wait_count = ATOMIC_INIT(0), .has_connection = 0, @@ -222,7 +222,7 @@ void *port_data(int port_num) os_close_file(fd); out: up(&ports_sem); - return(dev); + return dev; } int port_wait(void *data) @@ -232,15 +232,15 @@ int port_wait(void *data) struct port_list *port = dev->port; int fd; - atomic_inc(&port->wait_count); + atomic_inc(&port->wait_count); while(1){ fd = -ERESTARTSYS; - if(wait_for_completion_interruptible(&port->done)) - goto out; + if(wait_for_completion_interruptible(&port->done)) + goto out; spin_lock(&port->lock); - conn = list_entry(port->connections.next, struct connection, + conn = list_entry(port->connections.next, struct connection, list); list_del(&conn->list); spin_unlock(&port->lock); @@ -248,12 +248,12 @@ int port_wait(void *data) os_shutdown_socket(conn->socket[0], 1, 1); os_close_file(conn->socket[0]); os_shutdown_socket(conn->socket[1], 1, 1); - os_close_file(conn->socket[1]); + os_close_file(conn->socket[1]); /* This is done here because freeing an IRQ can't be done * within the IRQ handler. So, pipe_interrupt always ups * the semaphore regardless of whether it got a successful - * connection. Then we loop here throwing out failed + * connection. Then we loop here throwing out failed * connections until a good one is found. */ free_irq(TELNETD_IRQ, conn); diff --git a/arch/um/drivers/port_user.c b/arch/um/drivers/port_user.c index bc6afaf..8050802 100644 --- a/arch/um/drivers/port_user.c +++ b/arch/um/drivers/port_user.c @@ -1,4 +1,4 @@ -/* +/* * Copyright (C) 2001 Jeff Dike (jdike@karaya.com) * Licensed under the GPL */ @@ -38,18 +38,18 @@ static void *port_init(char *str, int de if(*str != ':'){ printk("port_init : channel type 'port' must specify a " "port number\n"); - return(NULL); + return NULL; } str++; port = strtoul(str, &end, 0); if((*end != '\0') || (end == str)){ printk("port_init : couldn't parse port '%s'\n", str); - return(NULL); + return NULL; } kern_data = port_data(port); if(kern_data == NULL) - return(NULL); + return NULL; data = um_kmalloc(sizeof(*data)); if(data == NULL) @@ -59,10 +59,10 @@ static void *port_init(char *str, int de .kernel_data = kern_data }); sprintf(data->dev, "%d", port); - return(data); + return data; err: port_kern_free(kern_data); - return(NULL); + return NULL; } static void port_free(void *d) @@ -83,14 +83,14 @@ static int port_open(int input, int outp if((fd >= 0) && data->raw){ CATCH_EINTR(err = tcgetattr(fd, &data->tt)); if(err) - return(err); + return err; err = raw(fd); if(err) - return(err); + return err; } *dev_out = data->dev; - return(fd); + return fd; } static void port_close(int fd, void *d) @@ -120,8 +120,8 @@ int port_listen_fd(int port) int fd, err, arg; fd = socket(PF_INET, SOCK_STREAM, 0); - if(fd == -1) - return(-errno); + if(fd == -1) + return -errno; arg = 1; if(setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &arg, sizeof(arg)) < 0){ @@ -136,7 +136,7 @@ int port_listen_fd(int port) err = -errno; goto out; } - + if(listen(fd, 1) < 0){ err = -errno; goto out; @@ -146,10 +146,10 @@ int port_listen_fd(int port) if(err < 0) goto out; - return(fd); + return fd; out: os_close_file(fd); - return(err); + return err; } struct port_pre_exec_data { @@ -173,13 +173,13 @@ void port_pre_exec(void *arg) int port_connection(int fd, int *socket, int *pid_out) { int new, err; - char *argv[] = { "/usr/sbin/in.telnetd", "-L", + char *argv[] = { "/usr/sbin/in.telnetd", "-L", "/usr/lib/uml/port-helper", NULL }; struct port_pre_exec_data data; new = os_accept_connection(fd); if(new < 0) - return(new); + return new; err = os_pipe(socket, 0, 0); if(err < 0) @@ -190,29 +190,18 @@ int port_connection(int fd, int *socket, .pipe_fd = socket[1] }); err = run_helper(port_pre_exec, &data, argv, NULL); - if(err < 0) + if(err < 0) goto out_shutdown; *pid_out = err; - return(new); + return new; out_shutdown: os_shutdown_socket(socket[0], 1, 1); os_close_file(socket[0]); - os_shutdown_socket(socket[1], 1, 1); + os_shutdown_socket(socket[1], 1, 1); os_close_file(socket[1]); out_close: os_close_file(new); - return(err); + return err; } - -/* - * Overrides for Emacs so that we follow Linus's tabbing style. - * Emacs will notice this stuff at the end of the file and automatically - * adjust the settings for this buffer only. This must remain at the end - * of the file. - * --------------------------------------------------------------------------- - * Local variables: - * c-file-style: "linux" - * End: - */ diff --git a/arch/um/drivers/random.c b/arch/um/drivers/random.c index 73b2bdd..e942e83 100644 --- a/arch/um/drivers/random.c +++ b/arch/um/drivers/random.c @@ -78,6 +78,7 @@ static const struct file_operations rng_ .read = rng_dev_read, }; +/* rng_init shouldn't be called more than once at boot time */ static struct miscdevice rng_miscdev = { RNG_MISCDEV_MINOR, RNG_MODULE_NAME, diff --git a/arch/um/drivers/ssl.c b/arch/um/drivers/ssl.c index ed9c590..fc22b9b 100644 --- a/arch/um/drivers/ssl.c +++ b/arch/um/drivers/ssl.c @@ -38,6 +38,7 @@ static void ssl_announce(char *dev_name, dev_name); } +/* Almost const, except that xterm_title may be changed in an initcall */ static struct chan_opts opts = { .announce = ssl_announce, .xterm_title = "Serial Line #%d", @@ -46,10 +47,12 @@ static struct chan_opts opts = { .in_kernel = 1, }; -static int ssl_config(char *str); +static int ssl_config(char *str, char **error_out); static int ssl_get_config(char *dev, char *str, int size, char **error_out); -static int ssl_remove(int n); +static int ssl_remove(int n, char **error_out); + +/* Const, except for .mc.list */ static struct line_driver driver = { .name = "UML serial line", .device_name = "ttyS", @@ -61,9 +64,8 @@ static struct line_driver driver = { .read_irq_name = "ssl", .write_irq = SSL_WRITE_IRQ, .write_irq_name = "ssl-write", - .symlink_from = "serial", - .symlink_to = "tts", .mc = { + .list = LIST_HEAD_INIT(driver.mc.list), .name = "ssl", .config = ssl_config, .get_config = ssl_get_config, @@ -72,17 +74,16 @@ static struct line_driver driver = { }, }; -/* The array is initialized by line_init, which is an initcall. The - * individual elements are protected by individual semaphores. +/* The array is initialized by line_init, at initcall time. The + * elements are locked individually as needed. */ static struct line serial_lines[NR_PORTS] = { [0 ... NR_PORTS - 1] = LINE_INIT(CONFIG_SSL_CHAN, &driver) }; -static struct lines lines = LINES_INIT(NR_PORTS); - -static int ssl_config(char *str) +static int ssl_config(char *str, char **error_out) { - return line_config(serial_lines, ARRAY_SIZE(serial_lines), str, &opts); + return line_config(serial_lines, ARRAY_SIZE(serial_lines), str, &opts, + error_out); } static int ssl_get_config(char *dev, char *str, int size, char **error_out) @@ -91,9 +92,10 @@ static int ssl_get_config(char *dev, cha size, error_out); } -static int ssl_remove(int n) +static int ssl_remove(int n, char **error_out) { - return line_remove(serial_lines, ARRAY_SIZE(serial_lines), n); + return line_remove(serial_lines, ARRAY_SIZE(serial_lines), n, + error_out); } static int ssl_open(struct tty_struct *tty, struct file *filp) @@ -168,9 +170,10 @@ static int ssl_console_setup(struct cons { struct line *line = &serial_lines[co->index]; - return console_open_chan(line, co, &opts); + return console_open_chan(line, co); } +/* No locking for register_console call - relies on single-threaded initcalls */ static struct console ssl_cons = { .name = "ttyS", .write = ssl_console_write, @@ -186,9 +189,8 @@ static int ssl_init(void) printk(KERN_INFO "Initializing software serial port version %d\n", ssl_version); - ssl_driver = line_register_devfs(&lines, &driver, &ssl_ops, - serial_lines, - ARRAY_SIZE(serial_lines)); + ssl_driver = register_lines(&driver, &ssl_ops, serial_lines, + ARRAY_SIZE(serial_lines)); lines_init(serial_lines, ARRAY_SIZE(serial_lines), &opts); @@ -212,7 +214,15 @@ __uml_exitcall(ssl_exit); static int ssl_chan_setup(char *str) { - return line_setup(serial_lines, ARRAY_SIZE(serial_lines), str); + char *error; + int ret; + + ret = line_setup(serial_lines, ARRAY_SIZE(serial_lines), str, &error); + if(ret < 0) + printk(KERN_ERR "Failed to set up serial line with " + "configuration string \"%s\" : %s\n", str, error); + + return 1; } __setup("ssl", ssl_chan_setup); diff --git a/arch/um/drivers/stdio_console.c b/arch/um/drivers/stdio_console.c index 7a4897e..7ff0b0f 100644 --- a/arch/um/drivers/stdio_console.c +++ b/arch/um/drivers/stdio_console.c @@ -30,8 +30,6 @@ #include "init.h" #define MAX_TTYS (16) -/* ----------------------------------------------------------------------------- */ - /* Referenced only by tty_driver below - presumably it's locked correctly * by the tty driver. */ @@ -44,6 +42,7 @@ void stdio_announce(char *dev_name, int dev_name); } +/* Almost const, except that xterm_title may be changed in an initcall */ static struct chan_opts opts = { .announce = stdio_announce, .xterm_title = "Virtual Console #%d", @@ -52,10 +51,12 @@ static struct chan_opts opts = { .in_kernel = 1, }; -static int con_config(char *str); +static int con_config(char *str, char **error_out); static int con_get_config(char *dev, char *str, int size, char **error_out); -static int con_remove(int n); +static int con_remove(int n, char **con_remove); + +/* Const, except for .mc.list */ static struct line_driver driver = { .name = "UML console", .device_name = "tty", @@ -67,9 +68,8 @@ static struct line_driver driver = { .read_irq_name = "console", .write_irq = CONSOLE_WRITE_IRQ, .write_irq_name = "console-write", - .symlink_from = "ttys", - .symlink_to = "vc", .mc = { + .list = LIST_HEAD_INIT(driver.mc.list), .name = "con", .config = con_config, .get_config = con_get_config, @@ -78,18 +78,16 @@ static struct line_driver driver = { }, }; -static struct lines console_lines = LINES_INIT(MAX_TTYS); - -/* The array is initialized by line_init, which is an initcall. The - * individual elements are protected by individual semaphores. +/* The array is initialized by line_init, at initcall time. The + * elements are locked individually as needed. */ -struct line vts[MAX_TTYS] = { LINE_INIT(CONFIG_CON_ZERO_CHAN, &driver), - [ 1 ... MAX_TTYS - 1 ] = - LINE_INIT(CONFIG_CON_CHAN, &driver) }; +static struct line vts[MAX_TTYS] = { LINE_INIT(CONFIG_CON_ZERO_CHAN, &driver), + [ 1 ... MAX_TTYS - 1 ] = + LINE_INIT(CONFIG_CON_CHAN, &driver) }; -static int con_config(char *str) +static int con_config(char *str, char **error_out) { - return line_config(vts, ARRAY_SIZE(vts), str, &opts); + return line_config(vts, ARRAY_SIZE(vts), str, &opts, error_out); } static int con_get_config(char *dev, char *str, int size, char **error_out) @@ -97,9 +95,9 @@ static int con_get_config(char *dev, cha return line_get_config(dev, vts, ARRAY_SIZE(vts), str, size, error_out); } -static int con_remove(int n) +static int con_remove(int n, char **error_out) { - return line_remove(vts, ARRAY_SIZE(vts), n); + return line_remove(vts, ARRAY_SIZE(vts), n, error_out); } static int con_open(struct tty_struct *tty, struct file *filp) @@ -146,9 +144,10 @@ static int uml_console_setup(struct cons { struct line *line = &vts[co->index]; - return console_open_chan(line, co, &opts); + return console_open_chan(line, co); } +/* No locking for register_console call - relies on single-threaded initcalls */ static struct console stdiocons = { .name = "tty", .write = uml_console_write, @@ -156,16 +155,14 @@ static struct console stdiocons = { .setup = uml_console_setup, .flags = CON_PRINTBUFFER, .index = -1, - .data = &vts, }; int stdio_init(void) { char *new_title; - console_driver = line_register_devfs(&console_lines, &driver, - &console_ops, vts, - ARRAY_SIZE(vts)); + console_driver = register_lines(&driver, &console_ops, vts, + ARRAY_SIZE(vts)); if (console_driver == NULL) return -1; printk(KERN_INFO "Initialized stdio console driver\n"); @@ -192,7 +189,15 @@ __uml_exitcall(console_exit); static int console_chan_setup(char *str) { - return line_setup(vts, ARRAY_SIZE(vts), str); + char *error; + int ret; + + ret = line_setup(vts, ARRAY_SIZE(vts), str, &error); + if(ret < 0) + printk(KERN_ERR "Failed to set up console with " + "configuration string \"%s\" : %s\n", str, error); + + return 1; } __setup("con", console_chan_setup); __channel_help(console_chan_setup, "con"); diff --git a/arch/um/drivers/ubd_kern.c b/arch/um/drivers/ubd_kern.c index 49c047b..f98d26e 100644 --- a/arch/um/drivers/ubd_kern.c +++ b/arch/um/drivers/ubd_kern.c @@ -56,6 +56,7 @@ #include "cow.h" enum ubd_req { UBD_READ, UBD_WRITE }; struct io_thread_req { + struct request *req; enum ubd_req op; int fds[2]; unsigned long offsets[2]; @@ -106,10 +107,6 @@ static inline void ubd_set_bit(__u64 bit #define DRIVER_NAME "uml-blkdev" -/* Can be taken in interrupt context, and is passed to the block layer to lock - * the request queue. Kernel side code knows that. */ -static DEFINE_SPINLOCK(ubd_io_lock); - static DEFINE_MUTEX(ubd_lock); /* XXX - this made sense in 2.4 days, now it's only used as a boolean, and @@ -132,12 +129,8 @@ static struct block_device_operations ub .getgeo = ubd_getgeo, }; -/* Protected by the queue_lock */ -static request_queue_t *ubd_queue; - /* Protected by ubd_lock */ static int fake_major = MAJOR_NR; - static struct gendisk *ubd_gendisk[MAX_DEV]; static struct gendisk *fake_gendisk[MAX_DEV]; @@ -148,10 +141,6 @@ #else #define OPEN_FLAGS ((struct openflags) { .r = 1, .w = 1, .s = 0, .c = 0, \ .cl = 1 }) #endif - -/* Not protected - changed only in ubd_setup_common and then only to - * to enable O_SYNC. - */ static struct openflags global_openflags = OPEN_FLAGS; struct cow { @@ -178,6 +167,8 @@ struct ubd { unsigned no_cow:1; struct cow cow; struct platform_device pdev; + struct request_queue *queue; + spinlock_t lock; }; #define DEFAULT_COW { \ @@ -198,8 +189,10 @@ #define DEFAULT_UBD { \ .no_cow = 0, \ .shared = 0, \ .cow = DEFAULT_COW, \ + .lock = SPIN_LOCK_UNLOCKED, \ } +/* Protected by ubd_lock */ struct ubd ubd_devs[MAX_DEV] = { [ 0 ... MAX_DEV - 1 ] = DEFAULT_UBD }; /* Only changed by fake_ide_setup which is a setup */ @@ -242,7 +235,6 @@ static void make_ide_entries(char *dev_n ent = create_proc_entry("media", S_IFREG|S_IRUGO, dir); if(!ent) return; - ent->nlink = 1; ent->data = NULL; ent->read_proc = proc_ide_read_media; ent->write_proc = NULL; @@ -286,12 +278,12 @@ static int parse_unit(char **ptr) * otherwise, the str pointer is used (and owned) inside ubd_devs array, so it * should not be freed on exit. */ -static int ubd_setup_common(char *str, int *index_out) +static int ubd_setup_common(char *str, int *index_out, char **error_out) { struct ubd *ubd_dev; struct openflags flags = global_openflags; char *backing_file; - int n, err, i; + int n, err = 0, i; if(index_out) *index_out = -1; n = *str; @@ -302,56 +294,55 @@ static int ubd_setup_common(char *str, i str++; if(!strcmp(str, "sync")){ global_openflags = of_sync(global_openflags); - return(0); + goto out1; } + + err = -EINVAL; major = simple_strtoul(str, &end, 0); if((*end != '\0') || (end == str)){ - printk(KERN_ERR - "ubd_setup : didn't parse major number\n"); - return(1); + *error_out = "Didn't parse major number"; + goto out1; } - err = 1; - mutex_lock(&ubd_lock); - if(fake_major != MAJOR_NR){ - printk(KERN_ERR "Can't assign a fake major twice\n"); - goto out1; - } + mutex_lock(&ubd_lock); + if(fake_major != MAJOR_NR){ + *error_out = "Can't assign a fake major twice"; + goto out1; + } - fake_major = major; + fake_major = major; printk(KERN_INFO "Setting extra ubd major number to %d\n", major); - err = 0; - out1: - mutex_unlock(&ubd_lock); - return(err); + err = 0; + out1: + mutex_unlock(&ubd_lock); + return err; } n = parse_unit(&str); if(n < 0){ - printk(KERN_ERR "ubd_setup : couldn't parse unit number " - "'%s'\n", str); - return(1); + *error_out = "Couldn't parse device number"; + return -EINVAL; } if(n >= MAX_DEV){ - printk(KERN_ERR "ubd_setup : index %d out of range " - "(%d devices, from 0 to %d)\n", n, MAX_DEV, MAX_DEV - 1); - return(1); + *error_out = "Device number out of range"; + return 1; } - err = 1; + err = -EBUSY; mutex_lock(&ubd_lock); ubd_dev = &ubd_devs[n]; if(ubd_dev->file != NULL){ - printk(KERN_ERR "ubd_setup : device already configured\n"); + *error_out = "Device is already configured"; goto out; } if (index_out) *index_out = n; + err = -EINVAL; for (i = 0; i < sizeof("rscd="); i++) { switch (*str) { case 'r': @@ -370,47 +361,54 @@ static int ubd_setup_common(char *str, i str++; goto break_loop; default: - printk(KERN_ERR "ubd_setup : Expected '=' or flag letter (r, s, c, or d)\n"); + *error_out = "Expected '=' or flag letter " + "(r, s, c, or d)"; goto out; } str++; } - if (*str == '=') - printk(KERN_ERR "ubd_setup : Too many flags specified\n"); - else - printk(KERN_ERR "ubd_setup : Expected '='\n"); + if (*str == '=') + *error_out = "Too many flags specified"; + else + *error_out = "Missing '='"; goto out; break_loop: - err = 0; backing_file = strchr(str, ','); - if (!backing_file) { + if (backing_file == NULL) backing_file = strchr(str, ':'); - } - if(backing_file){ - if(ubd_dev->no_cow) - printk(KERN_ERR "Can't specify both 'd' and a " - "cow file\n"); + if(backing_file != NULL){ + if(ubd_dev->no_cow){ + *error_out = "Can't specify both 'd' and a cow file"; + goto out; + } else { *backing_file = '\0'; backing_file++; } } + err = 0; ubd_dev->file = str; ubd_dev->cow.file = backing_file; ubd_dev->boot_openflags = flags; out: mutex_unlock(&ubd_lock); - return(err); + return err; } static int ubd_setup(char *str) { - ubd_setup_common(str, NULL); - return(1); + char *error; + int err; + + err = ubd_setup_common(str, NULL, &error); + if(err) + printk(KERN_ERR "Failed to initialize device with \"%s\" : " + "%s\n", str, error); + return 1; } __setup("ubd", ubd_setup); @@ -422,7 +420,7 @@ __uml_help(ubd_setup, " use either a ':' or a ',': the first one allows writing things like;\n" " ubd0=~/Uml/root_cow:~/Uml/root_backing_file\n" " while with a ',' the shell would not expand the 2nd '~'.\n" -" When using only one filename, UML will detect whether to thread it like\n" +" When using only one filename, UML will detect whether to treat it like\n" " a COW file or a backing file. To override this detection, add the 'd'\n" " flag:\n" " ubd0d=BackingFile\n" @@ -471,12 +469,6 @@ static void do_ubd_request(request_queue /* Only changed by ubd_init, which is an initcall. */ int thread_fd = -1; -/* Changed by ubd_handler, which is serialized because interrupts only - * happen on CPU 0. - * XXX: currently unused. - */ -static int intr_count = 0; - /* call ubd_finish if you need to serialize */ static void __ubd_finish(struct request *req, int error) { @@ -499,36 +491,38 @@ static void __ubd_finish(struct request * spin_lock_irq()/spin_lock_irqsave() */ static inline void ubd_finish(struct request *req, int error) { - spin_lock(&ubd_io_lock); + struct ubd *dev = req->rq_disk->private_data; + + spin_lock(&dev->lock); __ubd_finish(req, error); - spin_unlock(&ubd_io_lock); + spin_unlock(&dev->lock); } /* XXX - move this inside ubd_intr. */ -/* Called without ubd_io_lock held, and only in interrupt context. */ +/* Called without dev->lock held, and only in interrupt context. */ static void ubd_handler(void) { struct io_thread_req req; - struct request *rq = elv_next_request(ubd_queue); + struct request *rq; + struct ubd *dev; int n; do_ubd = 0; - intr_count++; n = os_read_file(thread_fd, &req, sizeof(req)); if(n != sizeof(req)){ printk(KERN_ERR "Pid %d - spurious interrupt in ubd_handler, " "err = %d\n", os_getpid(), -n); - spin_lock(&ubd_io_lock); - end_request(rq, 0); - spin_unlock(&ubd_io_lock); return; } + rq = req.req; + dev = rq->rq_disk->private_data; + ubd_finish(rq, req.error); - reactivate_fd(thread_fd, UBD_IRQ); - spin_lock(&ubd_io_lock); - do_ubd_request(ubd_queue); - spin_unlock(&ubd_io_lock); + reactivate_fd(thread_fd, UBD_IRQ); + spin_lock(&dev->lock); + do_ubd_request(dev->queue); + spin_unlock(&dev->lock); } static irqreturn_t ubd_intr(int irq, void *dev) @@ -632,8 +626,7 @@ static int ubd_open_dev(struct ubd *ubd_ } static int ubd_disk_register(int major, u64 size, int unit, - struct gendisk **disk_out) - + struct gendisk **disk_out) { struct gendisk *disk; @@ -659,7 +652,7 @@ static int ubd_disk_register(int major, } disk->private_data = &ubd_devs[unit]; - disk->queue = ubd_queue; + disk->queue = ubd_devs[unit].queue; add_disk(disk); *disk_out = disk; @@ -668,28 +661,39 @@ static int ubd_disk_register(int major, #define ROUND_BLOCK(n) ((n + ((1 << 9) - 1)) & (-1 << 9)) -static int ubd_add(int n) +static int ubd_add(int n, char **error_out) { struct ubd *ubd_dev = &ubd_devs[n]; - int err; + int err = 0; - err = -ENODEV; if(ubd_dev->file == NULL) goto out; err = ubd_file_size(ubd_dev, &ubd_dev->size); - if(err < 0) + if(err < 0){ + *error_out = "Couldn't determine size of device's file"; goto out; + } ubd_dev->size = ROUND_BLOCK(ubd_dev->size); - err = ubd_disk_register(MAJOR_NR, ubd_dev->size, n, &ubd_gendisk[n]); - if(err) + err = -ENOMEM; + ubd_dev->queue = blk_init_queue(do_ubd_request, &ubd_dev->lock); + if (ubd_dev->queue == NULL) { + *error_out = "Failed to initialize device queue"; goto out; + } + ubd_dev->queue->queuedata = ubd_dev; + + err = ubd_disk_register(MAJOR_NR, ubd_dev->size, n, &ubd_gendisk[n]); + if(err){ + *error_out = "Failed to register device"; + goto out_cleanup; + } if(fake_major != MAJOR_NR) ubd_disk_register(fake_major, ubd_dev->size, n, - &fake_gendisk[n]); + &fake_gendisk[n]); /* perhaps this should also be under the "if (fake_major)" above */ /* using the fake_disk->disk_name and also the fakehd_set name */ @@ -699,30 +703,37 @@ static int ubd_add(int n) err = 0; out: return err; + +out_cleanup: + blk_cleanup_queue(ubd_dev->queue); + goto out; } -static int ubd_config(char *str) +static int ubd_config(char *str, char **error_out) { int n, ret; + /* This string is possibly broken up and stored, so it's only + * freed if ubd_setup_common fails, or if only general options + * were set. + */ str = kstrdup(str, GFP_KERNEL); if (str == NULL) { - printk(KERN_ERR "ubd_config failed to strdup string\n"); - ret = 1; - goto out; + *error_out = "Failed to allocate memory"; + return -ENOMEM; } - ret = ubd_setup_common(str, &n); - if (ret) { - ret = -1; + + ret = ubd_setup_common(str, &n, error_out); + if (ret) goto err_free; - } + if (n == -1) { ret = 0; goto err_free; } mutex_lock(&ubd_lock); - ret = ubd_add(n); + ret = ubd_add(n, error_out); if (ret) ubd_devs[n].file = NULL; mutex_unlock(&ubd_lock); @@ -777,7 +788,7 @@ static int ubd_id(char **str, int *start return n; } -static int ubd_remove(int n) +static int ubd_remove(int n, char **error_out) { struct ubd *ubd_dev; int err = -ENODEV; @@ -807,6 +818,7 @@ static int ubd_remove(int n) fake_gendisk[n] = NULL; } + blk_cleanup_queue(ubd_dev->queue); platform_device_unregister(&ubd_dev->pdev); *ubd_dev = ((struct ubd) DEFAULT_UBD); err = 0; @@ -815,8 +827,11 @@ out: return err; } -/* All these are called by mconsole in process context and without ubd-specific locks. */ +/* All these are called by mconsole in process context and without + * ubd-specific locks. The structure itself is const except for .list. + */ static struct mc_device ubd_mc = { + .list = LIST_HEAD_INIT(ubd_mc.list), .name = "ubd", .config = ubd_config, .get_config = ubd_get_config, @@ -836,13 +851,17 @@ static int __init ubd0_init(void) { struct ubd *ubd_dev = &ubd_devs[0]; + mutex_lock(&ubd_lock); if(ubd_dev->file == NULL) ubd_dev->file = "root_fs"; + mutex_unlock(&ubd_lock); + return(0); } __initcall(ubd0_init); +/* Used in ubd_init, which is an initcall */ static struct platform_driver ubd_driver = { .driver = { .name = DRIVER_NAME, @@ -851,17 +870,12 @@ static struct platform_driver ubd_driver static int __init ubd_init(void) { - int i; + char *error; + int i, err; if (register_blkdev(MAJOR_NR, "ubd")) return -1; - ubd_queue = blk_init_queue(do_ubd_request, &ubd_io_lock); - if (!ubd_queue) { - unregister_blkdev(MAJOR_NR, "ubd"); - return -1; - } - if (fake_major != MAJOR_NR) { char name[sizeof("ubd_nnn\0")]; @@ -870,8 +884,14 @@ static int __init ubd_init(void) return -1; } platform_driver_register(&ubd_driver); - for (i = 0; i < MAX_DEV; i++) - ubd_add(i); + mutex_lock(&ubd_lock); + for (i = 0; i < MAX_DEV; i++){ + err = ubd_add(i, &error); + if(err) + printk(KERN_ERR "Failed to initialize ubd device %d :" + "%s\n", i, error); + } + mutex_unlock(&ubd_lock); return 0; } @@ -1003,7 +1023,7 @@ static void cowify_req(struct io_thread_ req->bitmap_words, bitmap_len); } -/* Called with ubd_io_lock held */ +/* Called with dev->lock held */ static int prepare_request(struct request *req, struct io_thread_req *io_req) { struct gendisk *disk = req->rq_disk; @@ -1022,6 +1042,7 @@ static int prepare_request(struct reques offset = ((__u64) req->sector) << 9; len = req->current_nr_sectors << 9; + io_req->req = req; io_req->fds[0] = (ubd_dev->cow.file != NULL) ? ubd_dev->cow.fd : ubd_dev->fd; io_req->fds[1] = ubd_dev->fd; io_req->cow_offset = -1; @@ -1043,7 +1064,7 @@ static int prepare_request(struct reques return(0); } -/* Called with ubd_io_lock held */ +/* Called with dev->lock held */ static void do_ubd_request(request_queue_t *q) { struct io_thread_req io_req; @@ -1102,7 +1123,7 @@ static int ubd_ioctl(struct inode * inod sizeof(ubd_id))) return(-EFAULT); return(0); - + case CDROMVOLREAD: if(copy_from_user(&volume, (char __user *) arg, sizeof(volume))) return(-EFAULT); diff --git a/arch/um/include/chan_kern.h b/arch/um/include/chan_kern.h index 9003a34..c4b41bb 100644 --- a/arch/um/include/chan_kern.h +++ b/arch/um/include/chan_kern.h @@ -30,14 +30,13 @@ struct chan { extern void chan_interrupt(struct list_head *chans, struct delayed_work *task, struct tty_struct *tty, int irq); extern int parse_chan_pair(char *str, struct line *line, int device, - const struct chan_opts *opts); + const struct chan_opts *opts, char **error_out); extern int open_chan(struct list_head *chans); extern int write_chan(struct list_head *chans, const char *buf, int len, int write_irq); extern int console_write_chan(struct list_head *chans, const char *buf, int len); -extern int console_open_chan(struct line *line, struct console *co, - const struct chan_opts *opts); +extern int console_open_chan(struct line *line, struct console *co); extern void deactivate_chan(struct list_head *chans, int irq); extern void reactivate_chan(struct list_head *chans, int irq); extern void chan_enable_winch(struct list_head *chans, struct tty_struct *tty); diff --git a/arch/um/include/chan_user.h b/arch/um/include/chan_user.h index a795547..38f16d8 100644 --- a/arch/um/include/chan_user.h +++ b/arch/um/include/chan_user.h @@ -1,4 +1,4 @@ -/* +/* * Copyright (C) 2000, 2001 Jeff Dike (jdike@karaya.com) * Licensed under the GPL */ @@ -9,11 +9,11 @@ #define __CHAN_USER_H__ #include "init.h" struct chan_opts { - void (*announce)(char *dev_name, int dev); + void (*const announce)(char *dev_name, int dev); char *xterm_title; - int raw; - unsigned long tramp_stack; - int in_kernel; + const int raw; + const unsigned long tramp_stack; + const int in_kernel; }; enum chan_init_pri { INIT_STATIC, INIT_ALL, INIT_ONE }; @@ -54,14 +54,3 @@ __uml_help(fn, prefix "[0-9]*=> PAGE_SHIFT; - /* clear the zero-page */ - memset((void *) empty_zero_page, 0, PAGE_SIZE); + /* clear the zero-page */ + memset((void *) empty_zero_page, 0, PAGE_SIZE); /* Map in the area just after the brk now that kmalloc is about * to be turned on. @@ -253,8 +254,10 @@ struct page *arch_validate(struct page * int i; again: - if(page == NULL) return(page); - if(PageHighMem(page)) return(page); + if(page == NULL) + return page; + if(PageHighMem(page)) + return page; addr = (unsigned long) page_address(page); for(i = 0; i < (1 << order); i++){ @@ -263,13 +266,15 @@ struct page *arch_validate(struct page * sizeof(zero), ¤t->thread.fault_addr, ¤t->thread.fault_catcher)){ - if(!(mask & __GFP_WAIT)) return(NULL); + if(!(mask & __GFP_WAIT)) + return NULL; else break; } addr += PAGE_SIZE; } - if(i == (1 << order)) return(page); + if(i == (1 << order)) + return page; page = alloc_pages(mask, order); goto again; } @@ -283,7 +288,6 @@ void free_initmem(void) } #ifdef CONFIG_BLK_DEV_INITRD - void free_initrd_mem(unsigned long start, unsigned long end) { if (start < end) @@ -296,37 +300,36 @@ void free_initrd_mem(unsigned long start totalram_pages++; } } - #endif void show_mem(void) { - int pfn, total = 0, reserved = 0; - int shared = 0, cached = 0; - int highmem = 0; + int pfn, total = 0, reserved = 0; + int shared = 0, cached = 0; + int highmem = 0; struct page *page; - printk("Mem-info:\n"); - show_free_areas(); - printk("Free swap: %6ldkB\n", nr_swap_pages<<(PAGE_SHIFT-10)); - pfn = max_mapnr; - while(pfn-- > 0) { + printk("Mem-info:\n"); + show_free_areas(); + printk("Free swap: %6ldkB\n", nr_swap_pages<<(PAGE_SHIFT-10)); + pfn = max_mapnr; + while(pfn-- > 0) { page = pfn_to_page(pfn); - total++; - if(PageHighMem(page)) - highmem++; - if(PageReserved(page)) - reserved++; - else if(PageSwapCache(page)) - cached++; - else if(page_count(page)) - shared += page_count(page) - 1; - } - printk("%d pages of RAM\n", total); - printk("%d pages of HIGHMEM\n", highmem); - printk("%d reserved pages\n", reserved); - printk("%d pages shared\n", shared); - printk("%d pages swap cached\n", cached); + total++; + if(PageHighMem(page)) + highmem++; + if(PageReserved(page)) + reserved++; + else if(PageSwapCache(page)) + cached++; + else if(page_count(page)) + shared += page_count(page) - 1; + } + printk("%d pages of RAM\n", total); + printk("%d pages of HIGHMEM\n", highmem); + printk("%d reserved pages\n", reserved); + printk("%d pages shared\n", shared); + printk("%d pages swap cached\n", cached); } /* @@ -362,28 +365,7 @@ pte_t *pte_alloc_one_kernel(struct mm_st struct page *pte_alloc_one(struct mm_struct *mm, unsigned long address) { struct page *pte; - + pte = alloc_page(GFP_KERNEL|__GFP_REPEAT|__GFP_ZERO); return pte; } - -struct iomem_region *iomem_regions = NULL; -int iomem_size = 0; - -extern int parse_iomem(char *str, int *add) __init; - -__uml_setup("iomem=", parse_iomem, -"iomem=,\n" -" Configure as an IO memory region named .\n\n" -); - -/* - * Overrides for Emacs so that we follow Linus's tabbing style. - * Emacs will notice this stuff at the end of the file and automatically - * adjust the settings for this buffer only. This must remain at the end - * of the file. - * --------------------------------------------------------------------------- - * Local variables: - * c-file-style: "linux" - * End: - */ diff --git a/arch/um/kernel/physmem.c b/arch/um/kernel/physmem.c index abafa64..638f3b5 100644 --- a/arch/um/kernel/physmem.c +++ b/arch/um/kernel/physmem.c @@ -40,7 +40,7 @@ static struct rb_node **find_rb(void *vi while(*n != NULL){ d = rb_entry(*n, struct phys_desc, rb); if(d->virt == virt) - return(n); + return n; if(d->virt > virt) n = &(*n)->rb_left; @@ -48,7 +48,7 @@ static struct rb_node **find_rb(void *vi n = &(*n)->rb_right; } - return(n); + return n; } static struct phys_desc *find_phys_mapping(void *virt) @@ -56,9 +56,9 @@ static struct phys_desc *find_phys_mappi struct rb_node **n = find_rb(virt); if(*n == NULL) - return(NULL); + return NULL; - return(rb_entry(*n, struct phys_desc, rb)); + return rb_entry(*n, struct phys_desc, rb); } static void insert_phys_mapping(struct phys_desc *desc) @@ -89,10 +89,10 @@ static struct desc_mapping *find_mapping list_for_each(ele, &descriptor_mappings){ desc = list_entry(ele, struct desc_mapping, list); if(desc->fd == fd) - return(desc); + return desc; } - return(NULL); + return NULL; } static struct desc_mapping *descriptor_mapping(int fd) @@ -101,11 +101,11 @@ static struct desc_mapping *descriptor_m desc = find_mapping(fd); if(desc != NULL) - return(desc); + return desc; desc = kmalloc(sizeof(*desc), GFP_ATOMIC); if(desc == NULL) - return(NULL); + return NULL; *desc = ((struct desc_mapping) { .fd = fd, @@ -113,7 +113,7 @@ static struct desc_mapping *descriptor_m .pages = LIST_HEAD_INIT(desc->pages) }); list_add(&desc->list, &descriptor_mappings); - return(desc); + return desc; } int physmem_subst_mapping(void *virt, int fd, __u64 offset, int w) @@ -125,11 +125,11 @@ int physmem_subst_mapping(void *virt, in fd_maps = descriptor_mapping(fd); if(fd_maps == NULL) - return(-ENOMEM); + return -ENOMEM; phys = __pa(virt); desc = find_phys_mapping(virt); - if(desc != NULL) + if(desc != NULL) panic("Address 0x%p is already substituted\n", virt); err = -ENOMEM; @@ -155,7 +155,7 @@ int physmem_subst_mapping(void *virt, in rb_erase(&desc->rb, &phys_mappings); kfree(desc); out: - return(err); + return err; } static int physmem_fd = -1; @@ -182,10 +182,10 @@ int physmem_remove_mapping(void *virt) virt = (void *) ((unsigned long) virt & PAGE_MASK); desc = find_phys_mapping(virt); if(desc == NULL) - return(0); + return 0; remove_mapping(desc); - return(1); + return 1; } void physmem_forget_descriptor(int fd) @@ -239,9 +239,9 @@ void arch_free_page(struct page *page, i int is_remapped(void *virt) { - struct phys_desc *desc = find_phys_mapping(virt); + struct phys_desc *desc = find_phys_mapping(virt); - return(desc != NULL); + return desc != NULL; } /* Changed during early boot */ @@ -276,7 +276,7 @@ int init_maps(unsigned long physmem, uns else map = alloc_bootmem_low_pages(total_len); if(map == NULL) - return(-ENOMEM); + return -ENOMEM; for(i = 0; i < total_pages; i++){ p = &map[i]; @@ -286,7 +286,7 @@ int init_maps(unsigned long physmem, uns } max_mapnr = total_pages; - return(0); + return 0; } /* Changed during early boot */ @@ -296,7 +296,7 @@ unsigned long get_kmem_end(void) { if(kmem_top == 0) kmem_top = CHOOSE_MODE(kmem_end_tt, kmem_end_skas); - return(kmem_top); + return kmem_top; } void map_memory(unsigned long virt, unsigned long phys, unsigned long len, @@ -379,7 +379,7 @@ int phys_mapping(unsigned long phys, __u *offset_out = phys - iomem_size; } - return(fd); + return fd; } static int __init uml_mem_setup(char *line, int *add) @@ -398,6 +398,23 @@ __uml_setup("mem=", uml_mem_setup, " Example: mem=64M\n\n" ); +extern int __init parse_iomem(char *str, int *add); + +__uml_setup("iomem=", parse_iomem, +"iomem=,\n" +" Configure as an IO memory region named .\n\n" +); + +/* + * This list is constructed in parse_iomem and addresses filled in in + * setup_iomem, both of which run during early boot. Afterwards, it's + * unchanged. + */ +struct iomem_region *iomem_regions = NULL; + +/* Initialized in parse_iomem */ +int iomem_size = 0; + unsigned long find_iomem(char *driver, unsigned long *len_out) { struct iomem_region *region = iomem_regions; @@ -405,13 +422,13 @@ unsigned long find_iomem(char *driver, u while(region != NULL){ if(!strcmp(region->driver, driver)){ *len_out = region->size; - return(region->virt); + return region->virt; } region = region->next; } - return(0); + return 0; } int setup_iomem(void) @@ -435,18 +452,7 @@ int setup_iomem(void) region = region->next; } - return(0); + return 0; } __initcall(setup_iomem); - -/* - * Overrides for Emacs so that we follow Linus's tabbing style. - * Emacs will notice this stuff at the end of the file and automatically - * adjust the settings for this buffer only. This must remain at the end - * of the file. - * --------------------------------------------------------------------------- - * Local variables: - * c-file-style: "linux" - * End: - */ diff --git a/arch/um/kernel/ptrace.c b/arch/um/kernel/ptrace.c index 9a77fb3..627742d 100644 --- a/arch/um/kernel/ptrace.c +++ b/arch/um/kernel/ptrace.c @@ -18,6 +18,7 @@ #include "asm/uaccess.h" #include "kern_util.h" #include "skas_ptrace.h" #include "sysdep/ptrace.h" +#include "os.h" static inline void set_singlestepping(struct task_struct *child, int on) { @@ -241,6 +242,12 @@ #ifdef CONFIG_PROC_MM break; } #endif +#ifdef PTRACE_ARCH_PRCTL + case PTRACE_ARCH_PRCTL: + /* XXX Calls ptrace on the host - needs some SMP thinking */ + ret = arch_prctl_skas(child, data, (void *) addr); + break; +#endif default: ret = ptrace_request(child, request, addr, data); break; diff --git a/arch/um/kernel/resource.c b/arch/um/kernel/resource.c deleted file mode 100644 index 32188e1..0000000 --- a/arch/um/kernel/resource.c +++ /dev/null @@ -1,23 +0,0 @@ -/* - * Copyright (C) 2000 Jeff Dike (jdike@karaya.com) - * Licensed under the GPL - */ - -#include "linux/pci.h" - -unsigned long resource_fixup(struct pci_dev * dev, struct resource * res, - unsigned long start, unsigned long size) -{ - return start; -} - -/* - * Overrides for Emacs so that we follow Linus's tabbing style. - * Emacs will notice this stuff at the end of the file and automatically - * adjust the settings for this buffer only. This must remain at the end - * of the file. - * --------------------------------------------------------------------------- - * Local variables: - * c-file-style: "linux" - * End: - */ diff --git a/arch/um/kernel/sigio.c b/arch/um/kernel/sigio.c index 2b0ab43..89f9866 100644 --- a/arch/um/kernel/sigio.c +++ b/arch/um/kernel/sigio.c @@ -23,7 +23,7 @@ static irqreturn_t sigio_interrupt(int i os_read_file(sigio_irq_fd, &c, sizeof(c)); reactivate_fd(sigio_irq_fd, SIGIO_WRITE_IRQ); - return(IRQ_HANDLED); + return IRQ_HANDLED; } int write_sigio_irq(int fd) @@ -36,12 +36,13 @@ int write_sigio_irq(int fd) if(err){ printk("write_sigio_irq : um_request_irq failed, err = %d\n", err); - return(-1); + return -1; } sigio_irq_fd = fd; - return(0); + return 0; } +/* These are called from os-Linux/sigio.c to protect its pollfds arrays. */ static DEFINE_SPINLOCK(sigio_spinlock); void sigio_lock(void) diff --git a/arch/um/kernel/skas/mem.c b/arch/um/kernel/skas/mem.c index 0d2cce6..7c18dfc 100644 --- a/arch/um/kernel/skas/mem.c +++ b/arch/um/kernel/skas/mem.c @@ -14,13 +14,9 @@ unsigned long set_task_sizes_skas(unsign unsigned long host_task_size = ROUND_4M((unsigned long) &host_task_size); -#ifdef CONFIG_HOST_TASK_SIZE - *host_size_out = ROUND_4M(CONFIG_HOST_TASK_SIZE); - *task_size_out = CONFIG_HOST_TASK_SIZE; -#else if (!skas_needs_stub) *task_size_out = host_task_size; else *task_size_out = CONFIG_STUB_START & PGDIR_MASK; -#endif + return host_task_size; } diff --git a/arch/um/kernel/syscall.c b/arch/um/kernel/syscall.c index f5ed862..2828c52 100644 --- a/arch/um/kernel/syscall.c +++ b/arch/um/kernel/syscall.c @@ -149,22 +149,6 @@ long sys_olduname(struct oldold_utsname return error; } -DEFINE_SPINLOCK(syscall_lock); - -static int syscall_index = 0; - -int next_syscall_index(int limit) -{ - int ret; - - spin_lock(&syscall_lock); - ret = syscall_index; - if(++syscall_index == limit) - syscall_index = 0; - spin_unlock(&syscall_lock); - return(ret); -} - int kernel_execve(const char *filename, char *const argv[], char *const envp[]) { mm_segment_t fs; diff --git a/arch/um/kernel/sysrq.c b/arch/um/kernel/sysrq.c index 239c980..f9e02b3 100644 --- a/arch/um/kernel/sysrq.c +++ b/arch/um/kernel/sysrq.c @@ -50,7 +50,7 @@ void dump_stack(void) EXPORT_SYMBOL(dump_stack); /*Stolen from arch/i386/kernel/traps.c */ -static int kstack_depth_to_print = 24; +static const int kstack_depth_to_print = 24; /* This recently started being used in arch-independent code too, as in * kernel/sched.c.*/ diff --git a/arch/um/kernel/time.c b/arch/um/kernel/time.c index 2e354b3..b1f8b07 100644 --- a/arch/um/kernel/time.c +++ b/arch/um/kernel/time.c @@ -35,31 +35,31 @@ unsigned long long sched_clock(void) return (unsigned long long)jiffies_64 * (1000000000 / HZ); } -static unsigned long long prev_nsecs; +static unsigned long long prev_nsecs[NR_CPUS]; #ifdef CONFIG_UML_REAL_TIME_CLOCK -static long long delta; /* Deviation per interval */ +static long long delta[NR_CPUS]; /* Deviation per interval */ #endif void timer_irq(union uml_pt_regs *regs) { unsigned long long ticks = 0; - #ifdef CONFIG_UML_REAL_TIME_CLOCK - if(prev_nsecs){ + int c = cpu(); + if(prev_nsecs[c]){ /* We've had 1 tick */ unsigned long long nsecs = os_nsecs(); - delta += nsecs - prev_nsecs; - prev_nsecs = nsecs; + delta[c] += nsecs - prev_nsecs[c]; + prev_nsecs[c] = nsecs; /* Protect against the host clock being set backwards */ - if(delta < 0) - delta = 0; + if(delta[c] < 0) + delta[c] = 0; - ticks += (delta * HZ) / BILLION; - delta -= (ticks * BILLION) / HZ; + ticks += (delta[c] * HZ) / BILLION; + delta[c] -= (ticks * BILLION) / HZ; } - else prev_nsecs = os_nsecs(); + else prev_nsecs[c] = os_nsecs(); #else ticks = 1; #endif @@ -69,8 +69,8 @@ #endif } } +/* Protects local_offset */ static DEFINE_SPINLOCK(timer_spinlock); - static unsigned long long local_offset = 0; static inline unsigned long long get_time(void) diff --git a/arch/um/kernel/trap.c b/arch/um/kernel/trap.c index b5f124a..26f15c4 100644 --- a/arch/um/kernel/trap.c +++ b/arch/um/kernel/trap.c @@ -128,7 +128,18 @@ out_of_memory: goto out; } -void segv_handler(int sig, union uml_pt_regs *regs) +static void bad_segv(struct faultinfo fi, unsigned long ip) +{ + struct siginfo si; + + si.si_signo = SIGSEGV; + si.si_code = SEGV_ACCERR; + si.si_addr = (void __user *) FAULT_ADDRESS(fi); + current->thread.arch.faultinfo = fi; + force_sig_info(SIGSEGV, &si, current); +} + +static void segv_handler(int sig, union uml_pt_regs *regs) { struct faultinfo * fi = UPT_FAULTINFO(regs); @@ -205,17 +216,6 @@ unsigned long segv(struct faultinfo fi, return(0); } -void bad_segv(struct faultinfo fi, unsigned long ip) -{ - struct siginfo si; - - si.si_signo = SIGSEGV; - si.si_code = SEGV_ACCERR; - si.si_addr = (void __user *) FAULT_ADDRESS(fi); - current->thread.arch.faultinfo = fi; - force_sig_info(SIGSEGV, &si, current); -} - void relay_signal(int sig, union uml_pt_regs *regs) { if(arch_handle_signal(sig, regs)) @@ -232,14 +232,14 @@ void relay_signal(int sig, union uml_pt_ force_sig(sig, current); } -void bus_handler(int sig, union uml_pt_regs *regs) +static void bus_handler(int sig, union uml_pt_regs *regs) { if(current->thread.fault_catcher != NULL) do_longjmp(current->thread.fault_catcher, 1); else relay_signal(sig, regs); } -void winch(int sig, union uml_pt_regs *regs) +static void winch(int sig, union uml_pt_regs *regs) { do_IRQ(WINCH_IRQ, regs); } diff --git a/arch/um/kernel/tt/gdb.c b/arch/um/kernel/tt/gdb.c index 786e4ed..8eba8f7 100644 --- a/arch/um/kernel/tt/gdb.c +++ b/arch/um/kernel/tt/gdb.c @@ -139,7 +139,7 @@ static void config_gdb_cb(void *arg) init_proxy(debugger_pid, 0, 0); } -int gdb_config(char *str) +int gdb_config(char *str, char **error_out) { struct gdb_data data; @@ -154,7 +154,7 @@ void remove_gdb_cb(void *unused) exit_debugger_cb(NULL); } -int gdb_remove(int unused) +int gdb_remove(int unused, char **error_out) { initial_thread_cb(remove_gdb_cb, NULL); return 0; diff --git a/arch/um/kernel/tt/gdb_kern.c b/arch/um/kernel/tt/gdb_kern.c index 68e1bf6..03b06bc 100644 --- a/arch/um/kernel/tt/gdb_kern.c +++ b/arch/um/kernel/tt/gdb_kern.c @@ -8,10 +8,11 @@ #include "mconsole_kern.h" #ifdef CONFIG_MCONSOLE -extern int gdb_config(char *str); -extern int gdb_remove(int n); +extern int gdb_config(char *str, char **error_out); +extern int gdb_remove(int n, char **error_out); static struct mc_device gdb_mc = { + .list = INIT_LIST_HEAD(gdb_mc.list), .name = "gdb", .config = gdb_config, .remove = gdb_remove, diff --git a/arch/um/kernel/um_arch.c b/arch/um/kernel/um_arch.c index 66f43c9..89c6dba 100644 --- a/arch/um/kernel/um_arch.c +++ b/arch/um/kernel/um_arch.c @@ -30,7 +30,6 @@ #include "kern_util.h" #include "kern.h" #include "mem_user.h" #include "mem.h" -#include "umid.h" #include "initrd.h" #include "init.h" #include "os.h" @@ -44,9 +43,9 @@ #endif #define DEFAULT_COMMAND_LINE "root=98:0" /* Changed in linux_main and setup_arch, which run before SMP is started */ -static char command_line[COMMAND_LINE_SIZE] = { 0 }; +static char __initdata command_line[COMMAND_LINE_SIZE] = { 0 }; -static void add_arg(char *arg) +static void __init add_arg(char *arg) { if (strlen(command_line) + strlen(arg) + 1 > COMMAND_LINE_SIZE) { printf("add_arg: Too many command line arguments!\n"); @@ -331,7 +330,7 @@ #define MIN_VMALLOC (32 * 1024 * 1024) extern char __binary_start; -int linux_main(int argc, char **argv) +int __init linux_main(int argc, char **argv) { unsigned long avail, diff; unsigned long virtmem_size, max_physmem; @@ -482,7 +481,7 @@ void __init setup_arch(char **cmdline_p) atomic_notifier_chain_register(&panic_notifier_list, &panic_exit_notifier); paging_init(); - strlcpy(saved_command_line, command_line, COMMAND_LINE_SIZE); + strlcpy(boot_command_line, command_line, COMMAND_LINE_SIZE); *cmdline_p = command_line; setup_hostinfo(); } diff --git a/arch/um/kernel/umid.c b/arch/um/kernel/umid.c index 4eaee82..039e16e 100644 --- a/arch/um/kernel/umid.c +++ b/arch/um/kernel/umid.c @@ -16,8 +16,10 @@ static int __init set_umid_arg(char *nam { int err; - if(umid_inited) + if(umid_inited){ + printf("umid already set\n"); return 0; + } *add = 0; err = set_umid(name); diff --git a/arch/um/os-Linux/aio.c b/arch/um/os-Linux/aio.c index f897140..6ff1274 100644 --- a/arch/um/os-Linux/aio.c +++ b/arch/um/os-Linux/aio.c @@ -24,9 +24,6 @@ struct aio_thread_req { struct aio_context *aio; }; -static int aio_req_fd_r = -1; -static int aio_req_fd_w = -1; - #if defined(HAVE_AIO_ABI) #include @@ -111,6 +108,7 @@ static int do_aio(aio_context_t ctx, enu return err; } +/* Initialized in an initcall and unchanged thereafter */ static aio_context_t ctx = 0; static int aio_thread(void *arg) @@ -137,7 +135,7 @@ static int aio_thread(void *arg) err = os_write_file(reply_fd, &reply, sizeof(reply)); if(err != sizeof(reply)) printk("aio_thread - write failed, fd = %d, " - "err = %d\n", aio_req_fd_r, -err); + "err = %d\n", reply_fd, -err); } } return 0; @@ -182,6 +180,11 @@ out: return err; } +/* These are initialized in initcalls and not changed */ +static int aio_req_fd_r = -1; +static int aio_req_fd_w = -1; +static int aio_pid = -1; + static int not_aio_thread(void *arg) { struct aio_thread_req req; @@ -208,14 +211,12 @@ static int not_aio_thread(void *arg) err = os_write_file(req.aio->reply_fd, &reply, sizeof(reply)); if(err != sizeof(reply)) printk("not_aio_thread - write failed, fd = %d, " - "err = %d\n", aio_req_fd_r, -err); + "err = %d\n", req.aio->reply_fd, -err); } return 0; } -static int aio_pid = -1; - static int init_aio_24(void) { unsigned long stack; @@ -308,6 +309,7 @@ static int submit_aio_26(enum aio_type t } #endif +/* Initialized in an initcall and unchanged thereafter */ static int aio_24 = DEFAULT_24_AIO; static int __init set_aio_24(char *name, int *add) diff --git a/arch/um/os-Linux/elf_aux.c b/arch/um/os-Linux/elf_aux.c index 5a99dd3..3a8d7e3 100644 --- a/arch/um/os-Linux/elf_aux.c +++ b/arch/um/os-Linux/elf_aux.c @@ -21,12 +21,11 @@ #else typedef Elf64_auxv_t elf_auxv_t; #endif +/* These are initialized very early in boot and never changed */ char * elf_aux_platform; long elf_aux_hwcap; - unsigned long vsyscall_ehdr; unsigned long vsyscall_end; - unsigned long __kernel_vsyscall; __init void scan_elf_aux( char **envp) diff --git a/arch/um/os-Linux/file.c b/arch/um/os-Linux/file.c index 189fa67..371b433 100644 --- a/arch/um/os-Linux/file.c +++ b/arch/um/os-Linux/file.c @@ -162,25 +162,6 @@ int os_set_owner(int fd, int pid) return 0; } -/* FIXME? moved wholesale from sigio_user.c to get fcntls out of that file */ -int os_sigio_async(int master, int slave) -{ - int flags; - - flags = fcntl(master, F_GETFL); - if(flags < 0) - return -errno; - - if((fcntl(master, F_SETFL, flags | O_NONBLOCK | O_ASYNC) < 0) || - (fcntl(master, F_SETOWN, os_getpid()) < 0)) - return -errno; - - if((fcntl(slave, F_SETFL, flags | O_NONBLOCK) < 0)) - return -errno; - - return(0); -} - int os_mode_fd(int fd, int mode) { int err; diff --git a/arch/um/os-Linux/irq.c b/arch/um/os-Linux/irq.c index d46b818..d1b61d4 100644 --- a/arch/um/os-Linux/irq.c +++ b/arch/um/os-Linux/irq.c @@ -20,6 +20,10 @@ #include "irq_user.h" #include "os.h" #include "um_malloc.h" +/* + * Locked by irq_lock in arch/um/kernel/irq.c. Changed by os_create_pollfd + * and os_free_irq_by_cb, which are called under irq_lock. + */ static struct pollfd *pollfds = NULL; static int pollfds_num = 0; static int pollfds_size = 0; @@ -58,7 +62,7 @@ int os_create_pollfd(int fd, int events, if (pollfds_num == pollfds_size) { if (size_tmpfds <= pollfds_size * sizeof(pollfds[0])) { /* return min size needed for new pollfds area */ - return((pollfds_size + 1) * sizeof(pollfds[0])); + return (pollfds_size + 1) * sizeof(pollfds[0]); } if (pollfds != NULL) { diff --git a/arch/um/os-Linux/mem.c b/arch/um/os-Linux/mem.c index 4203681..f1ea169 100644 --- a/arch/um/os-Linux/mem.c +++ b/arch/um/os-Linux/mem.c @@ -20,7 +20,13 @@ #include "kern_constants.h" #include +/* Modified by which_tmpdir, which is called during early boot */ static char *default_tmpdir = "/tmp"; + +/* + * Modified when creating the physical memory file and when checking + * the tmp filesystem for usability, both happening during early boot. + */ static char *tempdir = NULL; static void __init find_tempdir(void) @@ -29,7 +35,8 @@ static void __init find_tempdir(void) int i; char *dir = NULL; - if(tempdir != NULL) return; /* We've already been called */ + if(tempdir != NULL) /* We've already been called */ + return; for(i = 0; dirs[i]; i++){ dir = getenv(dirs[i]); if((dir != NULL) && (*dir != '\0')) @@ -83,6 +90,7 @@ static int next(int fd, char *buf, int s return 1; } +/* which_tmpdir is called only during early boot */ static int checked_tmpdir = 0; /* Look for a tmpfs mounted at /dev/shm. I couldn't find a cleaner @@ -186,7 +194,7 @@ int make_tempfile(const char *template, } else { free(tempname); } - return(fd); + return fd; out: free(tempname); return -1; @@ -231,7 +239,7 @@ int create_tmp_file(unsigned long long l exit(1); } - return(fd); + return fd; } int create_mem_file(unsigned long long len) @@ -245,7 +253,7 @@ int create_mem_file(unsigned long long l errno = -err; perror("exec_close"); } - return(fd); + return fd; } diff --git a/arch/um/os-Linux/sigio.c b/arch/um/os-Linux/sigio.c index 925a652..b2e1fd8 100644 --- a/arch/um/os-Linux/sigio.c +++ b/arch/um/os-Linux/sigio.c @@ -97,20 +97,22 @@ static int write_sigio_thread(void *unus static int need_poll(struct pollfds *polls, int n) { - if(n <= polls->size){ - polls->used = n; + struct pollfd *new; + + if(n <= polls->size) return 0; - } - kfree(polls->poll); - polls->poll = um_kmalloc_atomic(n * sizeof(struct pollfd)); - if(polls->poll == NULL){ + + new = um_kmalloc_atomic(n * sizeof(struct pollfd)); + if(new == NULL){ printk("need_poll : failed to allocate new pollfds\n"); - polls->size = 0; - polls->used = 0; return -ENOMEM; } + + memcpy(new, polls->poll, polls->used * sizeof(struct pollfd)); + kfree(polls->poll); + + polls->poll = new; polls->size = n; - polls->used = n; return 0; } @@ -171,15 +173,15 @@ int add_sigio_fd(int fd) goto out; } - n = current_poll.used + 1; - err = need_poll(&next_poll, n); + n = current_poll.used; + err = need_poll(&next_poll, n + 1); if(err) goto out; - for(i = 0; i < current_poll.used; i++) - next_poll.poll[i] = current_poll.poll[i]; - - next_poll.poll[n - 1] = *p; + memcpy(next_poll.poll, current_poll.poll, + current_poll.used * sizeof(struct pollfd)); + next_poll.poll[n] = *p; + next_poll.used = n + 1; update_thread(); out: sigio_unlock(); @@ -214,6 +216,7 @@ int ignore_sigio_fd(int fd) if(p->fd != fd) next_poll.poll[n++] = *p; } + next_poll.used = current_poll.used - 1; update_thread(); out: @@ -331,10 +334,9 @@ void maybe_sigio_broken(int fd, int read sigio_lock(); err = need_poll(&all_sigio_fds, all_sigio_fds.used + 1); - if(err){ - printk("maybe_sigio_broken - failed to add pollfd\n"); + if(err) goto out; - } + all_sigio_fds.poll[all_sigio_fds.used++] = ((struct pollfd) { .fd = fd, .events = read ? POLLIN : POLLOUT, diff --git a/arch/um/os-Linux/start_up.c b/arch/um/os-Linux/start_up.c index 7fe9268..5178eba 100644 --- a/arch/um/os-Linux/start_up.c +++ b/arch/um/os-Linux/start_up.c @@ -54,7 +54,7 @@ static int ptrace_child(void *arg) perror("ptrace"); os_kill_process(pid, 0); } - os_stop_process(pid); + kill(pid, SIGSTOP); /*This syscall will be intercepted by the parent. Don't call more than * once, please.*/ @@ -73,6 +73,34 @@ static int ptrace_child(void *arg) _exit(ret); } +static void fatal_perror(char *str) +{ + perror(str); + exit(1); +} + +static void fatal(char *fmt, ...) +{ + va_list list; + + va_start(list, fmt); + vprintf(fmt, list); + va_end(list); + fflush(stdout); + + exit(1); +} + +static void non_fatal(char *fmt, ...) +{ + va_list list; + + va_start(list, fmt); + vprintf(fmt, list); + va_end(list); + fflush(stdout); +} + static int start_ptraced_child(void **stack_out) { void *stack; @@ -82,20 +110,20 @@ static int start_ptraced_child(void **st stack = mmap(NULL, PAGE_SIZE, PROT_READ | PROT_WRITE | PROT_EXEC, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); if(stack == MAP_FAILED) - panic("check_ptrace : mmap failed, errno = %d", errno); + fatal_perror("check_ptrace : mmap failed"); sp = (unsigned long) stack + PAGE_SIZE - sizeof(void *); pid = clone(ptrace_child, (void *) sp, SIGCHLD, NULL); if(pid < 0) - panic("start_ptraced_child : clone failed, errno = %d", errno); + fatal_perror("start_ptraced_child : clone failed"); CATCH_EINTR(n = waitpid(pid, &status, WUNTRACED)); if(n < 0) - panic("check_ptrace : clone failed, errno = %d", errno); + fatal_perror("check_ptrace : clone failed"); if(!WIFSTOPPED(status) || (WSTOPSIG(status) != SIGSTOP)) - panic("check_ptrace : expected SIGSTOP, got status = %d", + fatal("check_ptrace : expected SIGSTOP, got status = %d", status); *stack_out = stack; - return(pid); + return pid; } /* When testing for SYSEMU support, if it is one of the broken versions, we @@ -105,34 +133,34 @@ static int start_ptraced_child(void **st * must work anyway! */ static int stop_ptraced_child(int pid, void *stack, int exitcode, - int mustpanic) + int mustexit) { int status, n, ret = 0; if(ptrace(PTRACE_CONT, pid, 0, 0) < 0) - panic("check_ptrace : ptrace failed, errno = %d", errno); + fatal_perror("stop_ptraced_child : ptrace failed"); CATCH_EINTR(n = waitpid(pid, &status, 0)); if(!WIFEXITED(status) || (WEXITSTATUS(status) != exitcode)) { int exit_with = WEXITSTATUS(status); if (exit_with == 2) - printf("check_ptrace : child exited with status 2. " - "Serious trouble happening! Try updating your " - "host skas patch!\nDisabling SYSEMU support."); - printf("check_ptrace : child exited with exitcode %d, while " - "expecting %d; status 0x%x", exit_with, - exitcode, status); - if (mustpanic) - panic("\n"); - else - printf("\n"); + non_fatal("check_ptrace : child exited with status 2. " + "Serious trouble happening! Try updating " + "your host skas patch!\nDisabling SYSEMU " + "support."); + non_fatal("check_ptrace : child exited with exitcode %d, while " + "expecting %d; status 0x%x\n", exit_with, + exitcode, status); + if (mustexit) + exit(1); ret = -1; } if(munmap(stack, PAGE_SIZE) < 0) - panic("check_ptrace : munmap failed, errno = %d", errno); + fatal_perror("check_ptrace : munmap failed"); return ret; } +/* Changed only during early boot */ int ptrace_faultinfo = 1; int ptrace_ldt = 1; int proc_mm = 1; @@ -160,6 +188,7 @@ __uml_setup("mode=skas0", mode_skas0_cmd " specify mode=tt. Note that this was recently added - on \n" " older kernels you must use simply \"skas0\".\n\n"); +/* Changed only during early boot */ static int force_sysemu_disabled = 0; static int __init nosysemu_cmd_param(char *str, int* add) @@ -180,9 +209,9 @@ __uml_setup("nosysemu", nosysemu_cmd_par static void __init check_sysemu(void) { void *stack; - int pid, n, status, count=0; + int pid, n, status, count=0; - printf("Checking syscall emulation patch for ptrace..."); + non_fatal("Checking syscall emulation patch for ptrace..."); sysemu_supported = 0; pid = start_ptraced_child(&stack); @@ -191,31 +220,30 @@ static void __init check_sysemu(void) CATCH_EINTR(n = waitpid(pid, &status, WUNTRACED)); if (n < 0) - panic("check_sysemu : wait failed, errno = %d", errno); + fatal_perror("check_sysemu : wait failed"); if(!WIFSTOPPED(status) || (WSTOPSIG(status) != SIGTRAP)) - panic("check_sysemu : expected SIGTRAP, " - "got status = %d", status); + fatal("check_sysemu : expected SIGTRAP, got status = %d", + status); n = ptrace(PTRACE_POKEUSR, pid, PT_SYSCALL_RET_OFFSET, os_getpid()); if(n < 0) - panic("check_sysemu : failed to modify system " - "call return, errno = %d", errno); + fatal_perror("check_sysemu : failed to modify system call " + "return"); if (stop_ptraced_child(pid, stack, 0, 0) < 0) goto fail_stopped; sysemu_supported = 1; - printf("OK\n"); + non_fatal("OK\n"); set_using_sysemu(!force_sysemu_disabled); - printf("Checking advanced syscall emulation patch for ptrace..."); + non_fatal("Checking advanced syscall emulation patch for ptrace..."); pid = start_ptraced_child(&stack); - if(ptrace(PTRACE_OLDSETOPTIONS, pid, 0, - (void *) PTRACE_O_TRACESYSGOOD) < 0) - panic("check_ptrace: PTRACE_OLDSETOPTIONS failed, errno = %d", - errno); + if((ptrace(PTRACE_OLDSETOPTIONS, pid, 0, + (void *) PTRACE_O_TRACESYSGOOD) < 0)) + fatal_perror("check_ptrace: PTRACE_OLDSETOPTIONS failed"); while(1){ count++; @@ -223,29 +251,30 @@ static void __init check_sysemu(void) goto fail; CATCH_EINTR(n = waitpid(pid, &status, WUNTRACED)); if(n < 0) - panic("check_ptrace : wait failed, errno = %d", errno); + fatal_perror("check_ptrace : wait failed"); + if(WIFSTOPPED(status) && (WSTOPSIG(status) == (SIGTRAP|0x80))){ if (!count) - panic("check_ptrace : SYSEMU_SINGLESTEP " + fatal("check_ptrace : SYSEMU_SINGLESTEP " "doesn't singlestep"); n = ptrace(PTRACE_POKEUSR, pid, PT_SYSCALL_RET_OFFSET, os_getpid()); if(n < 0) - panic("check_sysemu : failed to modify system " - "call return, errno = %d", errno); + fatal_perror("check_sysemu : failed to modify " + "system call return"); break; } else if(WIFSTOPPED(status) && (WSTOPSIG(status) == SIGTRAP)) count++; else - panic("check_ptrace : expected SIGTRAP or " - "(SIGTRAP|0x80), got status = %d", status); + fatal("check_ptrace : expected SIGTRAP or " + "(SIGTRAP | 0x80), got status = %d", status); } if (stop_ptraced_child(pid, stack, 0, 0) < 0) goto fail_stopped; sysemu_supported = 2; - printf("OK\n"); + non_fatal("OK\n"); if ( !force_sysemu_disabled ) set_using_sysemu(sysemu_supported); @@ -254,7 +283,7 @@ static void __init check_sysemu(void) fail: stop_ptraced_child(pid, stack, 1, 0); fail_stopped: - printf("missing\n"); + non_fatal("missing\n"); } static void __init check_ptrace(void) @@ -262,22 +291,25 @@ static void __init check_ptrace(void) void *stack; int pid, syscall, n, status; - printf("Checking that ptrace can change system call numbers..."); + non_fatal("Checking that ptrace can change system call numbers..."); pid = start_ptraced_child(&stack); - if(ptrace(PTRACE_OLDSETOPTIONS, pid, 0, (void *)PTRACE_O_TRACESYSGOOD) < 0) - panic("check_ptrace: PTRACE_OLDSETOPTIONS failed, errno = %d", errno); + if((ptrace(PTRACE_OLDSETOPTIONS, pid, 0, + (void *) PTRACE_O_TRACESYSGOOD) < 0)) + fatal_perror("check_ptrace: PTRACE_OLDSETOPTIONS failed"); while(1){ if(ptrace(PTRACE_SYSCALL, pid, 0, 0) < 0) - panic("check_ptrace : ptrace failed, errno = %d", - errno); + fatal_perror("check_ptrace : ptrace failed"); + CATCH_EINTR(n = waitpid(pid, &status, WUNTRACED)); if(n < 0) - panic("check_ptrace : wait failed, errno = %d", errno); - if(!WIFSTOPPED(status) || (WSTOPSIG(status) != (SIGTRAP|0x80))) - panic("check_ptrace : expected (SIGTRAP|0x80), " - "got status = %d", status); + fatal_perror("check_ptrace : wait failed"); + + if(!WIFSTOPPED(status) || + (WSTOPSIG(status) != (SIGTRAP | 0x80))) + fatal("check_ptrace : expected (SIGTRAP|0x80), " + "got status = %d", status); syscall = ptrace(PTRACE_PEEKUSR, pid, PT_SYSCALL_NR_OFFSET, 0); @@ -285,13 +317,13 @@ static void __init check_ptrace(void) n = ptrace(PTRACE_POKEUSR, pid, PT_SYSCALL_NR_OFFSET, __NR_getppid); if(n < 0) - panic("check_ptrace : failed to modify system " - "call, errno = %d", errno); + fatal_perror("check_ptrace : failed to modify " + "system call"); break; } } stop_ptraced_child(pid, stack, 0, 1); - printf("OK\n"); + non_fatal("OK\n"); check_sysemu(); } @@ -350,22 +382,22 @@ static inline void check_skas3_ptrace_fa void *stack; int pid, n; - printf(" - PTRACE_FAULTINFO..."); + non_fatal(" - PTRACE_FAULTINFO..."); pid = start_ptraced_child(&stack); n = ptrace(PTRACE_FAULTINFO, pid, 0, &fi); if (n < 0) { ptrace_faultinfo = 0; if(errno == EIO) - printf("not found\n"); + non_fatal("not found\n"); else perror("not found"); } else { if (!ptrace_faultinfo) - printf("found but disabled on command line\n"); + non_fatal("found but disabled on command line\n"); else - printf("found\n"); + non_fatal("found\n"); } init_registers(pid); @@ -383,13 +415,13 @@ #ifdef PTRACE_LDT .ptr = ldtbuf, .bytecount = sizeof(ldtbuf)}; - printf(" - PTRACE_LDT..."); + non_fatal(" - PTRACE_LDT..."); pid = start_ptraced_child(&stack); n = ptrace(PTRACE_LDT, pid, 0, (unsigned long) &ldt_op); if (n < 0) { if(errno == EIO) - printf("not found\n"); + non_fatal("not found\n"); else { perror("not found"); } @@ -397,9 +429,9 @@ #ifdef PTRACE_LDT } else { if(ptrace_ldt) - printf("found\n"); + non_fatal("found\n"); else - printf("found, but use is disabled\n"); + non_fatal("found, but use is disabled\n"); } stop_ptraced_child(pid, stack, 1, 1); @@ -414,22 +446,22 @@ #endif static inline void check_skas3_proc_mm(void) { - printf(" - /proc/mm..."); - if (os_access("/proc/mm", OS_ACC_W_OK) < 0) { - proc_mm = 0; - printf("not found\n"); + non_fatal(" - /proc/mm..."); + if (access("/proc/mm", W_OK) < 0) { + proc_mm = 0; + perror("not found"); } else { if (!proc_mm) - printf("found but disabled on command line\n"); + non_fatal("found but disabled on command line\n"); else - printf("found\n"); + non_fatal("found\n"); } } int can_do_skas(void) { - printf("Checking for the skas3 patch in the host:\n"); + non_fatal("Checking for the skas3 patch in the host:\n"); check_skas3_proc_mm(); check_skas3_ptrace_faultinfo(); @@ -443,16 +475,16 @@ int can_do_skas(void) #else int can_do_skas(void) { - return(0); + return 0; } #endif int __init parse_iomem(char *str, int *add) { struct iomem_region *new; - struct uml_stat buf; + struct stat64 buf; char *file, *driver; - int fd, err, size; + int fd, size; driver = str; file = strchr(str,','); @@ -462,15 +494,14 @@ int __init parse_iomem(char *str, int *a } *file = '\0'; file++; - fd = os_open_file(file, of_rdwr(OPENFLAGS()), 0); + fd = open(file, O_RDWR, 0); if(fd < 0){ os_print_error(fd, "parse_iomem - Couldn't open io file"); goto out; } - err = os_stat_fd(fd, &buf); - if(err < 0){ - os_print_error(err, "parse_iomem - cannot stat_fd file"); + if(fstat64(fd, &buf) < 0){ + perror("parse_iomem - cannot stat_fd file"); goto out_close; } @@ -480,7 +511,7 @@ int __init parse_iomem(char *str, int *a goto out_close; } - size = (buf.ust_size + UM_KERN_PAGE_SIZE) & ~(UM_KERN_PAGE_SIZE - 1); + size = (buf.st_size + UM_KERN_PAGE_SIZE) & ~(UM_KERN_PAGE_SIZE - 1); *new = ((struct iomem_region) { .next = iomem_regions, .driver = driver, @@ -491,11 +522,11 @@ int __init parse_iomem(char *str, int *a iomem_regions = new; iomem_size += new->size + UM_KERN_PAGE_SIZE; - return(0); + return 0; out_close: - os_close_file(fd); + close(fd); out: - return(1); + return 1; } @@ -526,6 +557,24 @@ static void openpty_cb(void *arg) info->err = -errno; } +static int async_pty(int master, int slave) +{ + int flags; + + flags = fcntl(master, F_GETFL); + if(flags < 0) + return -errno; + + if((fcntl(master, F_SETFL, flags | O_NONBLOCK | O_ASYNC) < 0) || + (fcntl(master, F_SETOWN, os_getpid()) < 0)) + return -errno; + + if((fcntl(slave, F_SETFL, flags | O_NONBLOCK) < 0)) + return -errno; + + return(0); +} + static void __init check_one_sigio(void (*proc)(int, int)) { struct sigaction old, new; @@ -551,7 +600,7 @@ static void __init check_one_sigio(void if (err < 0) panic("check_sigio : __raw failed, errno = %d\n", -err); - err = os_sigio_async(master, slave); + err = async_pty(master, slave); if(err < 0) panic("tty_fds : sigio_async failed, err = %d\n", -err); diff --git a/arch/um/os-Linux/sys-i386/registers.c b/arch/um/os-Linux/sys-i386/registers.c index 7cd0369..79cd93c 100644 --- a/arch/um/os-Linux/sys-i386/registers.c +++ b/arch/um/os-Linux/sys-i386/registers.c @@ -34,27 +34,27 @@ void init_thread_registers(union uml_pt_ int save_fp_registers(int pid, unsigned long *fp_regs) { if(ptrace(PTRACE_GETFPREGS, pid, 0, fp_regs) < 0) - return(-errno); - return(0); + return -errno; + return 0; } int restore_fp_registers(int pid, unsigned long *fp_regs) { if(ptrace(PTRACE_SETFPREGS, pid, 0, fp_regs) < 0) - return(-errno); - return(0); + return -errno; + return 0; } static int move_registers(int pid, int int_op, union uml_pt_regs *regs, int fp_op, unsigned long *fp_regs) { if(ptrace(int_op, pid, 0, regs->skas.regs) < 0) - return(-errno); + return -errno; if(ptrace(fp_op, pid, 0, fp_regs) < 0) - return(-errno); + return -errno; - return(0); + return 0; } void save_registers(int pid, union uml_pt_regs *regs) diff --git a/arch/um/os-Linux/sys-x86_64/Makefile b/arch/um/os-Linux/sys-x86_64/Makefile index f67842a..7955e06 100644 --- a/arch/um/os-Linux/sys-x86_64/Makefile +++ b/arch/um/os-Linux/sys-x86_64/Makefile @@ -3,7 +3,7 @@ # Copyright (C) 2000 Jeff Dike (jdike@ka # Licensed under the GPL # -obj-$(CONFIG_MODE_SKAS) = registers.o signal.o +obj-$(CONFIG_MODE_SKAS) = registers.o prctl.o signal.o USER_OBJS := $(obj-y) diff --git a/arch/um/os-Linux/sys-x86_64/prctl.c b/arch/um/os-Linux/sys-x86_64/prctl.c new file mode 100644 index 0000000..9d34edd --- /dev/null +++ b/arch/um/os-Linux/sys-x86_64/prctl.c @@ -0,0 +1,12 @@ +/* + * Copyright (C) 2007 Jeff Dike (jdike@{addtoit.com,linux.intel.com}) + * Licensed under the GPL + */ + +#include +#include + +int os_arch_prctl(int pid, int code, unsigned long *addr) +{ + return ptrace(PTRACE_ARCH_PRCTL, pid, (unsigned long) addr, code); +} diff --git a/arch/um/os-Linux/sys-x86_64/registers.c b/arch/um/os-Linux/sys-x86_64/registers.c index cb8e8a2..a2d7e0c 100644 --- a/arch/um/os-Linux/sys-x86_64/registers.c +++ b/arch/um/os-Linux/sys-x86_64/registers.c @@ -27,12 +27,12 @@ static int move_registers(int pid, int i union uml_pt_regs *regs) { if(ptrace(int_op, pid, 0, regs->skas.regs) < 0) - return(-errno); + return -errno; if(ptrace(fp_op, pid, 0, regs->skas.fp) < 0) - return(-errno); + return -errno; - return(0); + return 0; } void save_registers(int pid, union uml_pt_regs *regs) diff --git a/arch/um/os-Linux/umid.c b/arch/um/os-Linux/umid.c index 48092b9..b462863 100644 --- a/arch/um/os-Linux/umid.c +++ b/arch/um/os-Linux/umid.c @@ -18,7 +18,7 @@ #define UML_DIR "~/.uml/" #define UMID_LEN 64 /* Changed by set_umid, which is run early in boot */ -char umid[UMID_LEN] = { 0 }; +static char umid[UMID_LEN] = { 0 }; /* Changed by set_uml_dir and make_uml_dir, which are run early in boot */ static char *uml_dir = UML_DIR; @@ -235,6 +235,7 @@ int __init set_umid(char *name) return 0; } +/* Changed in make_umid, which is called during early boot */ static int umid_setup = 0; int __init make_umid(void) diff --git a/arch/um/sys-x86_64/ptrace.c b/arch/um/sys-x86_64/ptrace.c index 147bbf0..55b66e0 100644 --- a/arch/um/sys-x86_64/ptrace.c +++ b/arch/um/sys-x86_64/ptrace.c @@ -71,8 +71,6 @@ int poke_user(struct task_struct *child, if (addr < MAX_REG_OFFSET) return putreg(child, addr, data); - -#if 0 /* Need x86_64 debugregs handling */ else if((addr >= offsetof(struct user, u_debugreg[0])) && (addr <= offsetof(struct user, u_debugreg[7]))){ addr -= offsetof(struct user, u_debugreg[0]); @@ -81,7 +79,6 @@ #if 0 /* Need x86_64 debugregs handling child->thread.arch.debugregs[addr] = data; return 0; } -#endif return -EIO; } @@ -119,14 +116,12 @@ int peek_user(struct task_struct *child, if(addr < MAX_REG_OFFSET){ tmp = getreg(child, addr); } -#if 0 /* Need x86_64 debugregs handling */ else if((addr >= offsetof(struct user, u_debugreg[0])) && (addr <= offsetof(struct user, u_debugreg[7]))){ addr -= offsetof(struct user, u_debugreg[0]); addr = addr >> 2; tmp = child->thread.arch.debugregs[addr]; } -#endif return put_user(tmp, (unsigned long *) data); } diff --git a/arch/um/sys-x86_64/syscalls.c b/arch/um/sys-x86_64/syscalls.c index 73ce446..01b91f9 100644 --- a/arch/um/sys-x86_64/syscalls.c +++ b/arch/um/sys-x86_64/syscalls.c @@ -16,6 +16,7 @@ #include "asm/unistd.h" #include "asm/prctl.h" /* XXX This should get the constants from libc */ #include "choose-mode.h" #include "kern.h" +#include "os.h" asmlinkage long sys_uname64(struct new_utsname __user * name) { @@ -58,40 +59,69 @@ #endif #ifdef CONFIG_MODE_SKAS -/* XXX: Must also call arch_prctl in the host, beside saving the segment bases! */ -static long arch_prctl_skas(int code, unsigned long addr) +long arch_prctl_skas(struct task_struct *task, int code, + unsigned long __user *addr) { - long ret = 0; + unsigned long *ptr = addr, tmp; + long ret; + int pid = task->mm->context.skas.id.u.pid; + /* + * With ARCH_SET_FS (and ARCH_SET_GS is treated similarly to + * be safe), we need to call arch_prctl on the host because + * setting %fs may result in something else happening (like a + * GDT or thread.fs being set instead). So, we let the host + * fiddle the registers and thread struct and restore the + * registers afterwards. + * + * So, the saved registers are stored to the process (this + * needed because a stub may have been the last thing to run), + * arch_prctl is run on the host, then the registers are read + * back. + */ switch(code){ case ARCH_SET_FS: - current->thread.regs.regs.skas.regs[FS_BASE / sizeof(unsigned long)] = addr; - break; case ARCH_SET_GS: - current->thread.regs.regs.skas.regs[GS_BASE / sizeof(unsigned long)] = addr; + restore_registers(pid, ¤t->thread.regs.regs); + break; + case ARCH_GET_FS: + case ARCH_GET_GS: + /* + * With these two, we read to a local pointer and + * put_user it to the userspace pointer that we were + * given. If addr isn't valid (because it hasn't been + * faulted in or is just bogus), we want put_user to + * fault it in (or return -EFAULT) instead of having + * the host return -EFAULT. + */ + ptr = &tmp; + } + + ret = os_arch_prctl(pid, code, ptr); + if(ret) + return ret; + + switch(code){ + case ARCH_SET_FS: + case ARCH_SET_GS: + save_registers(pid, ¤t->thread.regs.regs); break; case ARCH_GET_FS: - ret = put_user(current->thread.regs.regs.skas. - regs[FS_BASE / sizeof(unsigned long)], - (unsigned long __user *)addr); + ret = put_user(tmp, addr); break; case ARCH_GET_GS: - ret = put_user(current->thread.regs.regs.skas. - regs[GS_BASE / sizeof(unsigned long)], - (unsigned long __user *)addr); + ret = put_user(tmp, addr); break; - default: - ret = -EINVAL; - break; } - return(ret); + return ret; } #endif long sys_arch_prctl(int code, unsigned long addr) { - return(CHOOSE_MODE_PROC(arch_prctl_tt, arch_prctl_skas, code, addr)); + return CHOOSE_MODE_PROC(arch_prctl_tt, arch_prctl_skas, current, code, + (unsigned long __user *) addr); } long sys_clone(unsigned long clone_flags, unsigned long newsp, @@ -105,5 +135,14 @@ long sys_clone(unsigned long clone_flags ret = do_fork(clone_flags, newsp, ¤t->thread.regs, 0, parent_tid, child_tid); current->thread.forking = 0; - return(ret); + return ret; +} + +void arch_switch_to_skas(struct task_struct *from, struct task_struct *to) +{ + if(to->thread.arch.fs == 0) + return; + + arch_prctl_skas(to, ARCH_SET_FS, (void __user *) to->thread.arch.fs); } + diff --git a/arch/um/sys-x86_64/tls.c b/arch/um/sys-x86_64/tls.c index ce1bf1b..febbc94 100644 --- a/arch/um/sys-x86_64/tls.c +++ b/arch/um/sys-x86_64/tls.c @@ -1,14 +1,17 @@ #include "linux/sched.h" -void debug_arch_force_load_TLS(void) -{ -} - void clear_flushed_tls(struct task_struct *task) { } int arch_copy_tls(struct task_struct *t) { + /* + * If CLONE_SETTLS is set, we need to save the thread id + * (which is argument 5, child_tid, of clone) so it can be set + * during context switches. + */ + t->thread.arch.fs = t->thread.regs.regs.skas.regs[R8 / sizeof(long)]; + return 0; } diff --git a/arch/v850/Kconfig b/arch/v850/Kconfig index f0d4d72..dbfab8f 100644 --- a/arch/v850/Kconfig +++ b/arch/v850/Kconfig @@ -10,6 +10,9 @@ mainmenu "uClinux/v850 (w/o MMU) Kernel config MMU bool default n +config ZONE_DMA + bool + default y config RWSEM_GENERIC_SPINLOCK bool default y diff --git a/arch/v850/kernel/anna.c b/arch/v850/kernel/anna.c index 40892d3..0e42904 100644 --- a/arch/v850/kernel/anna.c +++ b/arch/v850/kernel/anna.c @@ -114,7 +114,7 @@ static struct v850e_intc_irq_init irq_in { "ST", IRQ_INTST(0), IRQ_INTST_NUM, 3, 5 }, { 0 } }; -#define NUM_IRQ_INITS ((sizeof irq_inits / sizeof irq_inits[0]) - 1) +#define NUM_IRQ_INITS (ARRAY_SIZE(irq_inits) - 1) static struct hw_interrupt_type hw_itypes[NUM_IRQ_INITS]; diff --git a/arch/v850/kernel/as85ep1.c b/arch/v850/kernel/as85ep1.c index 5352f8a..18437bc 100644 --- a/arch/v850/kernel/as85ep1.c +++ b/arch/v850/kernel/as85ep1.c @@ -142,7 +142,7 @@ static struct v850e_intc_irq_init irq_in { "ST", IRQ_INTST(0), IRQ_INTST_NUM, 3, 5 }, { 0 } }; -#define NUM_IRQ_INITS ((sizeof irq_inits / sizeof irq_inits[0]) - 1) +#define NUM_IRQ_INITS (ARRAY_SIZE(irq_inits) - 1) static struct hw_interrupt_type hw_itypes[NUM_IRQ_INITS]; diff --git a/arch/v850/kernel/fpga85e2c.c b/arch/v850/kernel/fpga85e2c.c index cb04a69..5c49235 100644 --- a/arch/v850/kernel/fpga85e2c.c +++ b/arch/v850/kernel/fpga85e2c.c @@ -138,7 +138,7 @@ struct v850e_intc_irq_init irq_inits[] = { "RPU", IRQ_RPU(0), IRQ_RPU_NUM, 1, 6 }, { 0 } }; -#define NUM_IRQ_INITS ((sizeof irq_inits / sizeof irq_inits[0]) - 1) +#define NUM_IRQ_INITS (ARRAY_SIZE(irq_inits) - 1) struct hw_interrupt_type hw_itypes[NUM_IRQ_INITS]; diff --git a/arch/v850/kernel/gbus_int.c b/arch/v850/kernel/gbus_int.c index 25d636e..b2bcc25 100644 --- a/arch/v850/kernel/gbus_int.c +++ b/arch/v850/kernel/gbus_int.c @@ -16,6 +16,7 @@ #include #include #include #include +#include #include @@ -36,7 +37,7 @@ struct used_gint { { 1, GBUS_INT_PRIORITY_HIGH }, { 3, GBUS_INT_PRIORITY_LOW } }; -#define NUM_USED_GINTS (sizeof used_gint / sizeof used_gint[0]) +#define NUM_USED_GINTS ARRAY_SIZE(used_gint) /* A table of which GINT is used by each GBUS interrupts (they are assigned based on priority). */ @@ -231,8 +232,7 @@ struct gbus_int_irq_init gbus_irq_inits[ { "GBUS_INT", IRQ_GBUS_INT(0), IRQ_GBUS_INT_NUM, 1, 6}, { 0 } }; -#define NUM_GBUS_IRQ_INITS \ - ((sizeof gbus_irq_inits / sizeof gbus_irq_inits[0]) - 1) +#define NUM_GBUS_IRQ_INITS (ARRAY_SIZE(gbus_irq_inits) - 1) static struct hw_interrupt_type gbus_hw_itypes[NUM_GBUS_IRQ_INITS]; diff --git a/arch/v850/kernel/ma.c b/arch/v850/kernel/ma.c index 2aa8ab0..143774d 100644 --- a/arch/v850/kernel/ma.c +++ b/arch/v850/kernel/ma.c @@ -43,7 +43,7 @@ static struct v850e_intc_irq_init irq_in { "ST", IRQ_INTST(0), IRQ_INTST_NUM, 4, 5 }, { 0 } }; -#define NUM_IRQ_INITS ((sizeof irq_inits / sizeof irq_inits[0]) - 1) +#define NUM_IRQ_INITS (ARRAY_SIZE(irq_inits) - 1) static struct hw_interrupt_type hw_itypes[NUM_IRQ_INITS]; diff --git a/arch/v850/kernel/me2.c b/arch/v850/kernel/me2.c index 14b0c88..38be5c1 100644 --- a/arch/v850/kernel/me2.c +++ b/arch/v850/kernel/me2.c @@ -44,7 +44,7 @@ static struct v850e_intc_irq_init irq_in { "UBTITO", IRQ_INTUBTITO(0), IRQ_INTUBTITO_NUM, 5, 4 }, { 0 } }; -#define NUM_IRQ_INITS ((sizeof irq_inits / sizeof irq_inits[0]) - 1) +#define NUM_IRQ_INITS (ARRAY_SIZE(irq_inits) - 1) static struct hw_interrupt_type hw_itypes[NUM_IRQ_INITS]; diff --git a/arch/v850/kernel/rte_cb.c b/arch/v850/kernel/rte_cb.c index 0f7f6cd..43018e1 100644 --- a/arch/v850/kernel/rte_cb.c +++ b/arch/v850/kernel/rte_cb.c @@ -15,6 +15,7 @@ #include #include #include #include +#include #include #include @@ -176,8 +177,7 @@ #ifdef CONFIG_RTE_MB_A_PCI #endif { 0 } }; -#define NUM_GBUS_IRQ_INITS \ - ((sizeof gbus_irq_inits / sizeof gbus_irq_inits[0]) - 1) +#define NUM_GBUS_IRQ_INITS (ARRAY_SIZE(gbus_irq_inits) - 1) static struct hw_interrupt_type gbus_hw_itypes[NUM_GBUS_IRQ_INITS]; diff --git a/arch/v850/kernel/rte_cb_leds.c b/arch/v850/kernel/rte_cb_leds.c index 996bd4f..aa47ab1 100644 --- a/arch/v850/kernel/rte_cb_leds.c +++ b/arch/v850/kernel/rte_cb_leds.c @@ -117,7 +117,7 @@ static loff_t leds_dev_lseek (struct fil return 0; } -static struct file_operations leds_fops = { +static const struct file_operations leds_fops = { .read = leds_dev_read, .write = leds_dev_write, .llseek = leds_dev_lseek diff --git a/arch/v850/kernel/rte_mb_a_pci.c b/arch/v850/kernel/rte_mb_a_pci.c index 35213fa..35a4bd5 100644 --- a/arch/v850/kernel/rte_mb_a_pci.c +++ b/arch/v850/kernel/rte_mb_a_pci.c @@ -70,8 +70,7 @@ static struct mb_pci_dev_irq mb_pci_dev_ /* PCI slot 2 */ { 9, IRQ_MB_A_PCI2(0), 1 } }; -#define NUM_MB_PCI_DEV_IRQS \ - (sizeof mb_pci_dev_irqs / sizeof mb_pci_dev_irqs[0]) +#define NUM_MB_PCI_DEV_IRQS ARRAY_SIZE(mb_pci_dev_irqs) /* PCI configuration primitives. */ diff --git a/arch/v850/kernel/rte_me2_cb.c b/arch/v850/kernel/rte_me2_cb.c index 3be355a..46803d4 100644 --- a/arch/v850/kernel/rte_me2_cb.c +++ b/arch/v850/kernel/rte_me2_cb.c @@ -170,8 +170,7 @@ static struct cb_pic_irq_init cb_pic_irq { "CB_EXTTM2", IRQ_CB_EXTTM2, 1, 1, 6 }, { 0 } }; -#define NUM_CB_PIC_IRQ_INITS \ - ((sizeof cb_pic_irq_inits / sizeof cb_pic_irq_inits[0]) - 1) +#define NUM_CB_PIC_IRQ_INITS (ARRAY_SIZE(cb_pic_irq_inits) - 1) static struct hw_interrupt_type cb_pic_hw_itypes[NUM_CB_PIC_IRQ_INITS]; static unsigned char cb_pic_active_irqs = 0; diff --git a/arch/v850/kernel/setup.c b/arch/v850/kernel/setup.c index 1bf672a..a914f24 100644 --- a/arch/v850/kernel/setup.c +++ b/arch/v850/kernel/setup.c @@ -42,7 +42,7 @@ extern char _root_fs_image_start __attri extern char _root_fs_image_end __attribute__ ((__weak__)); -char command_line[COMMAND_LINE_SIZE]; +char __initdata command_line[COMMAND_LINE_SIZE]; /* Memory not used by the kernel. */ static unsigned long total_ram_pages; @@ -64,8 +64,8 @@ void __init setup_arch (char **cmdline) { /* Keep a copy of command line */ *cmdline = command_line; - memcpy (saved_command_line, command_line, COMMAND_LINE_SIZE); - saved_command_line[COMMAND_LINE_SIZE - 1] = '\0'; + memcpy (boot_command_line, command_line, COMMAND_LINE_SIZE); + boot_command_line[COMMAND_LINE_SIZE - 1] = '\0'; console_verbose (); diff --git a/arch/v850/kernel/teg.c b/arch/v850/kernel/teg.c index 290d506..699248f 100644 --- a/arch/v850/kernel/teg.c +++ b/arch/v850/kernel/teg.c @@ -43,7 +43,7 @@ static struct v850e_intc_irq_init irq_in { "ST", IRQ_INTST(0), IRQ_INTST_NUM, 1, 5 }, { 0 } }; -#define NUM_IRQ_INITS ((sizeof irq_inits / sizeof irq_inits[0]) - 1) +#define NUM_IRQ_INITS (ARRAY_SIZE(irq_inits) - 1) static struct hw_interrupt_type hw_itypes[NUM_IRQ_INITS]; diff --git a/arch/v850/kernel/time.c b/arch/v850/kernel/time.c index cd06f47..486e3a4 100644 --- a/arch/v850/kernel/time.c +++ b/arch/v850/kernel/time.c @@ -28,14 +28,6 @@ #include "mach.h" #define TICK_SIZE (tick_nsec / 1000) /* - * Scheduler clock - returns current time in nanosec units. - */ -unsigned long long sched_clock(void) -{ - return (unsigned long long)jiffies * (1000000000 / HZ); -} - -/* * timer_interrupt() needs to keep up the real-time clock, * as well as call the "do_timer()" routine every clocktick */ diff --git a/arch/v850/kernel/vmlinux.lds.S b/arch/v850/kernel/vmlinux.lds.S index 3a5fd07..3563082 100644 --- a/arch/v850/kernel/vmlinux.lds.S +++ b/arch/v850/kernel/vmlinux.lds.S @@ -190,12 +190,16 @@ #define ROOT_FS_CONTENTS \ __root_fs_image_start = . ; \ *(.root) \ __root_fs_image_end = . ; + +#ifdef CONFIG_BLK_DEV_INITRD /* The initramfs archive. */ #define INITRAMFS_CONTENTS \ . = ALIGN (4) ; \ ___initramfs_start = . ; \ *(.init.ramfs) \ ___initramfs_end = . ; +#endif + /* Where the initial bootmap (bitmap for the boot-time memory allocator) should be place. */ #define BOOTMAP_CONTENTS \ diff --git a/arch/x86_64/Kconfig b/arch/x86_64/Kconfig index d427553..56eb14c 100644 --- a/arch/x86_64/Kconfig +++ b/arch/x86_64/Kconfig @@ -24,6 +24,14 @@ config X86 bool default y +config GENERIC_TIME + bool + default y + +config GENERIC_TIME_VSYSCALL + bool + default y + config ZONE_DMA32 bool default y @@ -44,6 +52,10 @@ config MMU bool default y +config ZONE_DMA + bool + default y + config ISA bool @@ -148,18 +160,18 @@ config MPSC Optimize for Intel Pentium 4 and older Nocona/Dempsey Xeon CPUs with Intel Extended Memory 64 Technology(EM64T). For details see . - Note the the latest Xeons (Xeon 51xx and 53xx) are not based on the - Netburst core and shouldn't use this option. You can distingush them + Note that the latest Xeons (Xeon 51xx and 53xx) are not based on the + Netburst core and shouldn't use this option. You can distinguish them using the cpu family field - in /proc/cpuinfo. Family 15 is a older Xeon, Family 6 a newer one - (this rule only applies to system that support EM64T) + in /proc/cpuinfo. Family 15 is an older Xeon, Family 6 a newer one + (this rule only applies to systems that support EM64T) config MCORE2 bool "Intel Core2 / newer Xeon" help Optimize for Intel Core2 and newer Xeons (51xx) - You can distingush the newer Xeons from the older ones using - the cpu family field in /proc/cpuinfo. 15 is a older Xeon + You can distinguish the newer Xeons from the older ones using + the cpu family field in /proc/cpuinfo. 15 is an older Xeon (use CONFIG_MPSC then), 6 is a newer one. This rule only applies to CPUs that support EM64T. @@ -454,8 +466,8 @@ config IOMMU on systems with more than 3GB. This is usually needed for USB, sound, many IDE/SATA chipsets and some other devices. Provides a driver for the AMD Athlon64/Opteron/Turion/Sempron GART - based IOMMU and a software bounce buffer based IOMMU used on Intel - systems and as fallback. + based hardware IOMMU and a software bounce buffer based IOMMU used + on Intel systems and as fallback. The code is only active when needed (enough memory and limited device) unless CONFIG_IOMMU_DEBUG or iommu=force is specified too. @@ -492,6 +504,12 @@ config CALGARY_IOMMU_ENABLED_BY_DEFAULT # need this always selected by IOMMU for the VIA workaround config SWIOTLB bool + help + Support for software bounce buffers used on x86-64 systems + which don't have a hardware IOMMU (e.g. the current generation + of Intel's x86-64 CPUs). Using this PCI devices which can only + access 32-bits of memory can be used on systems with more than + 3 GB of memory. If unsure, say Y. config X86_MCE bool "Machine check support" if EMBEDDED diff --git a/arch/x86_64/defconfig b/arch/x86_64/defconfig index 69584c2..293a4a4 100644 --- a/arch/x86_64/defconfig +++ b/arch/x86_64/defconfig @@ -1,7 +1,7 @@ # # Automatically generated make config: don't edit -# Linux kernel version: 2.6.20-rc3 -# Fri Jan 5 11:54:41 2007 +# Linux kernel version: 2.6.20-git8 +# Tue Feb 13 11:25:16 2007 # CONFIG_X86_64=y CONFIG_64BIT=y @@ -11,6 +11,7 @@ CONFIG_LOCKDEP_SUPPORT=y CONFIG_STACKTRACE_SUPPORT=y CONFIG_SEMAPHORE_SLEEPERS=y CONFIG_MMU=y +CONFIG_ZONE_DMA=y CONFIG_RWSEM_GENERIC_SPINLOCK=y CONFIG_GENERIC_HWEIGHT=y CONFIG_GENERIC_CALIBRATE_DELAY=y @@ -153,6 +154,7 @@ # CONFIG_SPARSEMEM_STATIC is not set CONFIG_SPLIT_PTLOCK_CPUS=4 CONFIG_MIGRATION=y CONFIG_RESOURCES_64BIT=y +CONFIG_ZONE_DMA_FLAG=1 CONFIG_HAVE_ARCH_EARLY_PFN_TO_NID=y CONFIG_OUT_OF_LINE_PFN_TO_PAGE=y CONFIG_NR_CPUS=32 @@ -201,13 +203,14 @@ CONFIG_ACPI=y CONFIG_ACPI_SLEEP=y CONFIG_ACPI_SLEEP_PROC_FS=y CONFIG_ACPI_SLEEP_PROC_SLEEP=y +CONFIG_ACPI_PROCFS=y CONFIG_ACPI_AC=y CONFIG_ACPI_BATTERY=y CONFIG_ACPI_BUTTON=y -# CONFIG_ACPI_VIDEO is not set # CONFIG_ACPI_HOTKEY is not set CONFIG_ACPI_FAN=y # CONFIG_ACPI_DOCK is not set +# CONFIG_ACPI_BAY is not set CONFIG_ACPI_PROCESSOR=y CONFIG_ACPI_HOTPLUG_CPU=y CONFIG_ACPI_THERMAL=y @@ -263,7 +266,6 @@ CONFIG_PCI_MMCONFIG=y CONFIG_PCIEPORTBUS=y CONFIG_PCIEAER=y CONFIG_PCI_MSI=y -# CONFIG_PCI_MULTITHREAD_PROBE is not set # CONFIG_PCI_DEBUG is not set # CONFIG_HT_IRQ is not set @@ -398,6 +400,7 @@ CONFIG_STANDALONE=y CONFIG_PREVENT_FIRMWARE_BUILD=y CONFIG_FW_LOADER=y # CONFIG_DEBUG_DRIVER is not set +# CONFIG_DEBUG_DEVRES is not set # CONFIG_SYS_HYPERVISOR is not set # @@ -466,6 +469,7 @@ CONFIG_BLK_DEV_IDECD=y # CONFIG_BLK_DEV_IDETAPE is not set # CONFIG_BLK_DEV_IDEFLOPPY is not set # CONFIG_BLK_DEV_IDESCSI is not set +CONFIG_BLK_DEV_IDEACPI=y # CONFIG_IDE_TASK_IOCTL is not set # @@ -497,6 +501,7 @@ # CONFIG_BLK_DEV_HPT366 is not set # CONFIG_BLK_DEV_JMICRON is not set # CONFIG_BLK_DEV_SC1200 is not set CONFIG_BLK_DEV_PIIX=y +# CONFIG_BLK_DEV_IT8213 is not set # CONFIG_BLK_DEV_IT821X is not set # CONFIG_BLK_DEV_NS87415 is not set # CONFIG_BLK_DEV_PDC202XX_OLD is not set @@ -507,6 +512,7 @@ # CONFIG_BLK_DEV_SIS5513 is not set # CONFIG_BLK_DEV_SLC90E66 is not set # CONFIG_BLK_DEV_TRM290 is not set # CONFIG_BLK_DEV_VIA82CXXX is not set +# CONFIG_BLK_DEV_TC86C001 is not set # CONFIG_IDE_ARM is not set CONFIG_BLK_DEV_IDEDMA=y # CONFIG_IDEDMA_IVB is not set @@ -599,6 +605,7 @@ # # Serial ATA (prod) and Parallel ATA (experimental) drivers # CONFIG_ATA=y +# CONFIG_ATA_NONSTANDARD is not set CONFIG_SATA_AHCI=y CONFIG_SATA_SVW=y CONFIG_ATA_PIIX=y @@ -614,6 +621,7 @@ # CONFIG_SATA_SIS is not set # CONFIG_SATA_ULI is not set CONFIG_SATA_VIA=y # CONFIG_SATA_VITESSE is not set +# CONFIG_SATA_INIC162X is not set CONFIG_SATA_INTEL_COMBINED=y # CONFIG_PATA_ALI is not set # CONFIG_PATA_AMD is not set @@ -630,6 +638,7 @@ # CONFIG_PATA_HPT37X is not set # CONFIG_PATA_HPT3X2N is not set # CONFIG_PATA_HPT3X3 is not set # CONFIG_PATA_IT821X is not set +# CONFIG_PATA_IT8213 is not set # CONFIG_PATA_JMICRON is not set # CONFIG_PATA_TRIFLEX is not set # CONFIG_PATA_MARVELL is not set @@ -682,9 +691,7 @@ # # Subsystem Options # # CONFIG_IEEE1394_VERBOSEDEBUG is not set -# CONFIG_IEEE1394_OUI_DB is not set # CONFIG_IEEE1394_EXTRA_CONFIG_ROMS is not set -# CONFIG_IEEE1394_EXPORT_FULL_API is not set # # Device Drivers @@ -707,6 +714,11 @@ # # CONFIG_I2O is not set # +# Macintosh device drivers +# +# CONFIG_MAC_EMUMOUSEBTN is not set + +# # Network device support # CONFIG_NETDEVICES=y @@ -774,6 +786,7 @@ # CONFIG_SIS900 is not set # CONFIG_EPIC100 is not set # CONFIG_SUNDANCE is not set # CONFIG_VIA_RHINE is not set +# CONFIG_SC92031 is not set # # Ethernet (1000 Mbit) @@ -795,11 +808,13 @@ # CONFIG_VIA_VELOCITY is not set CONFIG_TIGON3=y CONFIG_BNX2=y # CONFIG_QLA3XXX is not set +# CONFIG_ATL1 is not set # # Ethernet (10000 Mbit) # # CONFIG_CHELSIO_T1 is not set +# CONFIG_CHELSIO_T3 is not set # CONFIG_IXGB is not set CONFIG_S2IO=m # CONFIG_S2IO_NAPI is not set @@ -1115,6 +1130,7 @@ # # Open Sound System # CONFIG_SOUND_PRIME=y +CONFIG_OBSOLETE_OSS=y # CONFIG_SOUND_BT878 is not set # CONFIG_SOUND_ES1371 is not set CONFIG_SOUND_ICH=y @@ -1128,6 +1144,7 @@ # # HID Devices # CONFIG_HID=y +# CONFIG_HID_DEBUG is not set # # USB support @@ -1142,10 +1159,8 @@ # # Miscellaneous USB options # CONFIG_USB_DEVICEFS=y -# CONFIG_USB_BANDWIDTH is not set # CONFIG_USB_DYNAMIC_MINORS is not set # CONFIG_USB_SUSPEND is not set -# CONFIG_USB_MULTITHREAD_PROBE is not set # CONFIG_USB_OTG is not set # @@ -1155,9 +1170,11 @@ CONFIG_USB_EHCI_HCD=y # CONFIG_USB_EHCI_SPLIT_ISO is not set # CONFIG_USB_EHCI_ROOT_HUB_TT is not set # CONFIG_USB_EHCI_TT_NEWSCHED is not set +# CONFIG_USB_EHCI_BIG_ENDIAN_MMIO is not set # CONFIG_USB_ISP116X_HCD is not set CONFIG_USB_OHCI_HCD=y -# CONFIG_USB_OHCI_BIG_ENDIAN is not set +# CONFIG_USB_OHCI_BIG_ENDIAN_DESC is not set +# CONFIG_USB_OHCI_BIG_ENDIAN_MMIO is not set CONFIG_USB_OHCI_LITTLE_ENDIAN=y CONFIG_USB_UHCI_HCD=y # CONFIG_USB_SL811_HCD is not set @@ -1208,6 +1225,7 @@ # CONFIG_USB_ATI_REMOTE is not set # CONFIG_USB_ATI_REMOTE2 is not set # CONFIG_USB_KEYSPAN_REMOTE is not set # CONFIG_USB_APPLETOUCH is not set +# CONFIG_USB_GTCO is not set # # USB Imaging devices @@ -1313,6 +1331,10 @@ # DMA Devices # # +# Auxiliary Display support +# + +# # Virtualization # # CONFIG_KVM is not set @@ -1512,6 +1534,7 @@ CONFIG_UNUSED_SYMBOLS=y CONFIG_DEBUG_FS=y # CONFIG_HEADERS_CHECK is not set CONFIG_DEBUG_KERNEL=y +# CONFIG_DEBUG_SHIRQ is not set CONFIG_LOG_BUF_SHIFT=18 CONFIG_DETECT_SOFTLOCKUP=y # CONFIG_SCHEDSTATS is not set @@ -1520,7 +1543,6 @@ # CONFIG_DEBUG_RT_MUTEXES is not set # CONFIG_RT_MUTEX_TESTER is not set # CONFIG_DEBUG_SPINLOCK is not set # CONFIG_DEBUG_MUTEXES is not set -# CONFIG_DEBUG_RWSEMS is not set # CONFIG_DEBUG_LOCK_ALLOC is not set # CONFIG_PROVE_LOCKING is not set # CONFIG_DEBUG_SPINLOCK_SLEEP is not set @@ -1560,4 +1582,5 @@ CONFIG_CRC32=y # CONFIG_LIBCRC32C is not set CONFIG_ZLIB_INFLATE=y CONFIG_PLIST=y -CONFIG_IOMAP_COPY=y +CONFIG_HAS_IOMEM=y +CONFIG_HAS_IOPORT=y diff --git a/arch/x86_64/ia32/ia32_binfmt.c b/arch/x86_64/ia32/ia32_binfmt.c index 5ce0bd4..071100e 100644 --- a/arch/x86_64/ia32/ia32_binfmt.c +++ b/arch/x86_64/ia32/ia32_binfmt.c @@ -300,12 +300,10 @@ int ia32_setup_arg_pages(struct linux_bi bprm->loader += stack_base; bprm->exec += stack_base; - mpnt = kmem_cache_alloc(vm_area_cachep, GFP_KERNEL); + mpnt = kmem_cache_zalloc(vm_area_cachep, GFP_KERNEL); if (!mpnt) return -ENOMEM; - memset(mpnt, 0, sizeof(*mpnt)); - down_write(&mm->mmap_sem); { mpnt->vm_mm = mm; @@ -346,20 +344,30 @@ #ifdef CONFIG_SYSCTL #include static ctl_table abi_table2[] = { - { 99, "vsyscall32", &sysctl_vsyscall32, sizeof(int), 0644, NULL, - proc_dointvec }, - { 0, } -}; + { + .ctl_name = 99, + .procname = "vsyscall32", + .data = &sysctl_vsyscall32, + .maxlen = sizeof(int), + .mode = 0644, + .proc_handler = proc_dointvec + }, + {} +}; -static ctl_table abi_root_table2[] = { - { .ctl_name = CTL_ABI, .procname = "abi", .mode = 0555, - .child = abi_table2 }, - { 0 }, -}; +static ctl_table abi_root_table2[] = { + { + .ctl_name = CTL_ABI, + .procname = "abi", + .mode = 0555, + .child = abi_table2 + }, + {} +}; static __init int ia32_binfmt_init(void) { - register_sysctl_table(abi_root_table2, 1); + register_sysctl_table(abi_root_table2); return 0; } __initcall(ia32_binfmt_init); diff --git a/arch/x86_64/ia32/ia32_signal.c b/arch/x86_64/ia32/ia32_signal.c index ff499ef..359eacc 100644 --- a/arch/x86_64/ia32/ia32_signal.c +++ b/arch/x86_64/ia32/ia32_signal.c @@ -21,6 +21,7 @@ #include #include #include #include +#include #include #include #include @@ -449,7 +450,11 @@ int ia32_setup_frame(int sig, struct k_s /* Return stub is in 32bit vsyscall page */ { - void __user *restorer = VSYSCALL32_SIGRETURN; + void __user *restorer; + if (current->binfmt->hasvdso) + restorer = VSYSCALL32_SIGRETURN; + else + restorer = (void *)&frame->retcode; if (ka->sa.sa_flags & SA_RESTORER) restorer = ka->sa.sa_restorer; err |= __put_user(ptr_to_compat(restorer), &frame->pretcode); @@ -495,7 +500,7 @@ int ia32_setup_frame(int sig, struct k_s ptrace_notify(SIGTRAP); #if DEBUG_SIG - printk("SIG deliver (%s:%d): sp=%p pc=%p ra=%p\n", + printk("SIG deliver (%s:%d): sp=%p pc=%lx ra=%u\n", current->comm, current->pid, frame, regs->rip, frame->pretcode); #endif @@ -601,7 +606,7 @@ int ia32_setup_rt_frame(int sig, struct ptrace_notify(SIGTRAP); #if DEBUG_SIG - printk("SIG deliver (%s:%d): sp=%p pc=%p ra=%p\n", + printk("SIG deliver (%s:%d): sp=%p pc=%lx ra=%u\n", current->comm, current->pid, frame, regs->rip, frame->pretcode); #endif diff --git a/arch/x86_64/ia32/ia32entry.S b/arch/x86_64/ia32/ia32entry.S index b4aa875..eda7a0d 100644 --- a/arch/x86_64/ia32/ia32entry.S +++ b/arch/x86_64/ia32/ia32entry.S @@ -515,7 +515,7 @@ #endif .quad sys32_vm86_warning /* vm86old */ .quad compat_sys_wait4 .quad sys_swapoff /* 115 */ - .quad sys32_sysinfo + .quad compat_sys_sysinfo .quad sys32_ipc .quad sys_fsync .quad stub32_sigreturn @@ -718,4 +718,5 @@ #endif .quad compat_sys_vmsplice .quad compat_sys_move_pages .quad sys_getcpu + .quad sys_epoll_pwait ia32_syscall_end: diff --git a/arch/x86_64/ia32/sys_ia32.c b/arch/x86_64/ia32/sys_ia32.c index c9bac3a..200fdde 100644 --- a/arch/x86_64/ia32/sys_ia32.c +++ b/arch/x86_64/ia32/sys_ia32.c @@ -523,72 +523,6 @@ sys32_sysfs(int option, u32 arg1, u32 ar return sys_sysfs(option, arg1, arg2); } -struct sysinfo32 { - s32 uptime; - u32 loads[3]; - u32 totalram; - u32 freeram; - u32 sharedram; - u32 bufferram; - u32 totalswap; - u32 freeswap; - unsigned short procs; - unsigned short pad; - u32 totalhigh; - u32 freehigh; - u32 mem_unit; - char _f[20-2*sizeof(u32)-sizeof(int)]; -}; - -asmlinkage long -sys32_sysinfo(struct sysinfo32 __user *info) -{ - struct sysinfo s; - int ret; - mm_segment_t old_fs = get_fs (); - int bitcount = 0; - - set_fs (KERNEL_DS); - ret = sys_sysinfo((struct sysinfo __user *)&s); - set_fs (old_fs); - - /* Check to see if any memory value is too large for 32-bit and scale - * down if needed - */ - if ((s.totalram >> 32) || (s.totalswap >> 32)) { - while (s.mem_unit < PAGE_SIZE) { - s.mem_unit <<= 1; - bitcount++; - } - s.totalram >>= bitcount; - s.freeram >>= bitcount; - s.sharedram >>= bitcount; - s.bufferram >>= bitcount; - s.totalswap >>= bitcount; - s.freeswap >>= bitcount; - s.totalhigh >>= bitcount; - s.freehigh >>= bitcount; - } - - if (!access_ok(VERIFY_WRITE, info, sizeof(struct sysinfo32)) || - __put_user (s.uptime, &info->uptime) || - __put_user (s.loads[0], &info->loads[0]) || - __put_user (s.loads[1], &info->loads[1]) || - __put_user (s.loads[2], &info->loads[2]) || - __put_user (s.totalram, &info->totalram) || - __put_user (s.freeram, &info->freeram) || - __put_user (s.sharedram, &info->sharedram) || - __put_user (s.bufferram, &info->bufferram) || - __put_user (s.totalswap, &info->totalswap) || - __put_user (s.freeswap, &info->freeswap) || - __put_user (s.procs, &info->procs) || - __put_user (s.totalhigh, &info->totalhigh) || - __put_user (s.freehigh, &info->freehigh) || - __put_user (s.mem_unit, &info->mem_unit)) - return -EFAULT; - return 0; -} - asmlinkage long sys32_sched_rr_get_interval(compat_pid_t pid, struct compat_timespec __user *interval) { diff --git a/arch/x86_64/ia32/syscall32.c b/arch/x86_64/ia32/syscall32.c index 59f1fa1..568ff0d 100644 --- a/arch/x86_64/ia32/syscall32.c +++ b/arch/x86_64/ia32/syscall32.c @@ -18,68 +18,34 @@ extern unsigned char syscall32_syscall[] extern unsigned char syscall32_sysenter[], syscall32_sysenter_end[]; extern int sysctl_vsyscall32; -char *syscall32_page; +static struct page *syscall32_pages[1]; static int use_sysenter = -1; -static struct page * -syscall32_nopage(struct vm_area_struct *vma, unsigned long adr, int *type) -{ - struct page *p = virt_to_page(adr - vma->vm_start + syscall32_page); - get_page(p); - return p; -} - -/* Prevent VMA merging */ -static void syscall32_vma_close(struct vm_area_struct *vma) -{ -} - -static struct vm_operations_struct syscall32_vm_ops = { - .close = syscall32_vma_close, - .nopage = syscall32_nopage, -}; - struct linux_binprm; /* Setup a VMA at program startup for the vsyscall page */ int syscall32_setup_pages(struct linux_binprm *bprm, int exstack) { - int npages = (VSYSCALL32_END - VSYSCALL32_BASE) >> PAGE_SHIFT; - struct vm_area_struct *vma; struct mm_struct *mm = current->mm; int ret; - vma = kmem_cache_alloc(vm_area_cachep, GFP_KERNEL); - if (!vma) - return -ENOMEM; - - memset(vma, 0, sizeof(struct vm_area_struct)); - /* Could randomize here */ - vma->vm_start = VSYSCALL32_BASE; - vma->vm_end = VSYSCALL32_END; - /* MAYWRITE to allow gdb to COW and set breakpoints */ - vma->vm_flags = VM_READ|VM_EXEC|VM_MAYREAD|VM_MAYEXEC|VM_MAYWRITE; + down_write(&mm->mmap_sem); /* + * MAYWRITE to allow gdb to COW and set breakpoints + * * Make sure the vDSO gets into every core dump. * Dumping its contents makes post-mortem fully interpretable later * without matching up the same kernel and hardware config to see * what PC values meant. */ - vma->vm_flags |= VM_ALWAYSDUMP; - vma->vm_flags |= mm->def_flags; - vma->vm_page_prot = protection_map[vma->vm_flags & 7]; - vma->vm_ops = &syscall32_vm_ops; - vma->vm_mm = mm; - - down_write(&mm->mmap_sem); - if ((ret = insert_vm_struct(mm, vma))) { - up_write(&mm->mmap_sem); - kmem_cache_free(vm_area_cachep, vma); - return ret; - } - mm->total_vm += npages; + /* Could randomize here */ + ret = install_special_mapping(mm, VSYSCALL32_BASE, PAGE_SIZE, + VM_READ|VM_EXEC| + VM_MAYREAD|VM_MAYWRITE|VM_MAYEXEC| + VM_ALWAYSDUMP, + syscall32_pages); up_write(&mm->mmap_sem); - return 0; + return ret; } const char *arch_vma_name(struct vm_area_struct *vma) @@ -92,9 +58,10 @@ const char *arch_vma_name(struct vm_area static int __init init_syscall32(void) { - syscall32_page = (void *)get_zeroed_page(GFP_KERNEL); + char *syscall32_page = (void *)get_zeroed_page(GFP_KERNEL); if (!syscall32_page) panic("Cannot allocate syscall32 page"); + syscall32_pages[0] = virt_to_page(syscall32_page); if (use_sysenter > 0) { memcpy(syscall32_page, syscall32_sysenter, syscall32_sysenter_end - syscall32_sysenter); diff --git a/arch/x86_64/kernel/Makefile b/arch/x86_64/kernel/Makefile index 3c7cbff..bb47e86 100644 --- a/arch/x86_64/kernel/Makefile +++ b/arch/x86_64/kernel/Makefile @@ -8,7 +8,7 @@ obj-y := process.o signal.o entry.o trap ptrace.o time.o ioport.o ldt.o setup.o i8259.o sys_x86_64.o \ x8664_ksyms.o i387.o syscall.o vsyscall.o \ setup64.o bootflag.o e820.o reboot.o quirks.o i8237.o \ - pci-dma.o pci-nommu.o alternative.o + pci-dma.o pci-nommu.o alternative.o hpet.o tsc.o obj-$(CONFIG_STACKTRACE) += stacktrace.o obj-$(CONFIG_X86_MCE) += mce.o therm_throt.o @@ -19,7 +19,7 @@ obj-$(CONFIG_ACPI) += acpi/ obj-$(CONFIG_X86_MSR) += msr.o obj-$(CONFIG_MICROCODE) += microcode.o obj-$(CONFIG_X86_CPUID) += cpuid.o -obj-$(CONFIG_SMP) += smp.o smpboot.o trampoline.o +obj-$(CONFIG_SMP) += smp.o smpboot.o trampoline.o tsc_sync.o obj-y += apic.o nmi.o obj-y += io_apic.o mpparse.o \ genapic.o genapic_cluster.o genapic_flat.o @@ -43,6 +43,7 @@ obj-$(CONFIG_PCI) += early-quirks.o obj-y += topology.o obj-y += intel_cacheinfo.o +obj-y += pcspeaker.o CFLAGS_vsyscall.o := $(PROFILING) -g0 @@ -56,3 +57,4 @@ quirks-y += ../../i386/kernel/quirks.o i8237-y += ../../i386/kernel/i8237.o msr-$(subst m,y,$(CONFIG_X86_MSR)) += ../../i386/kernel/msr.o alternative-y += ../../i386/kernel/alternative.o +pcspeaker-y += ../../i386/kernel/pcspeaker.o diff --git a/arch/x86_64/kernel/acpi/sleep.c b/arch/x86_64/kernel/acpi/sleep.c index 5ebf62c..23178ce 100644 --- a/arch/x86_64/kernel/acpi/sleep.c +++ b/arch/x86_64/kernel/acpi/sleep.c @@ -58,7 +58,7 @@ unsigned long acpi_wakeup_address = 0; unsigned long acpi_video_flags; extern char wakeup_start, wakeup_end; -extern unsigned long FASTCALL(acpi_copy_wakeup_routine(unsigned long)); +extern unsigned long acpi_copy_wakeup_routine(unsigned long); static pgd_t low_ptr; diff --git a/arch/x86_64/kernel/apic.c b/arch/x86_64/kernel/apic.c index 124b2d2..723417d 100644 --- a/arch/x86_64/kernel/apic.c +++ b/arch/x86_64/kernel/apic.c @@ -37,6 +37,7 @@ #include #include #include #include +#include #include int apic_mapped; @@ -763,7 +764,7 @@ static void setup_APIC_timer(unsigned in local_irq_save(flags); /* wait for irq slice */ - if (vxtime.hpet_address && hpet_use_timer) { + if (hpet_address && hpet_use_timer) { int trigger = hpet_readl(HPET_T0_CMP); while (hpet_readl(HPET_COUNTER) >= trigger) /* do nothing */ ; @@ -785,7 +786,7 @@ static void setup_APIC_timer(unsigned in /* Turn off PIT interrupt if we use APIC timer as main timer. Only works with the PM timer right now TBD fix it for HPET too. */ - if (vxtime.mode == VXTIME_PMTMR && + if ((pmtmr_ioport != 0) && smp_processor_id() == boot_cpu_id && apic_runs_main_timer == 1 && !cpu_isset(boot_cpu_id, timer_interrupt_broadcast_ipi_mask)) { diff --git a/arch/x86_64/kernel/e820.c b/arch/x86_64/kernel/e820.c index 6fe191c..4651fd2 100644 --- a/arch/x86_64/kernel/e820.c +++ b/arch/x86_64/kernel/e820.c @@ -83,6 +83,13 @@ #endif return 1; } +#ifdef CONFIG_NUMA + /* NUMA memory to node map */ + if (last >= nodemap_addr && addr < nodemap_addr + nodemap_size) { + *addrp = nodemap_addr + nodemap_size; + return 1; + } +#endif /* XXX ramdisk image here? */ return 0; } @@ -184,6 +191,37 @@ unsigned long __init e820_end_of_ram(voi } /* + * Find the hole size in the range. + */ +unsigned long __init e820_hole_size(unsigned long start, unsigned long end) +{ + unsigned long ram = 0; + int i; + + for (i = 0; i < e820.nr_map; i++) { + struct e820entry *ei = &e820.map[i]; + unsigned long last, addr; + + if (ei->type != E820_RAM || + ei->addr+ei->size <= start || + ei->addr >= end) + continue; + + addr = round_up(ei->addr, PAGE_SIZE); + if (addr < start) + addr = start; + + last = round_down(ei->addr + ei->size, PAGE_SIZE); + if (last >= end) + last = end; + + if (last > addr) + ram += last - addr; + } + return ((end - start) - ram); +} + +/* * Mark e820 reserved areas as busy for the resource manager. */ void __init e820_reserve_resources(void) diff --git a/arch/x86_64/kernel/early-quirks.c b/arch/x86_64/kernel/early-quirks.c index 49802f1..bd30d13 100644 --- a/arch/x86_64/kernel/early-quirks.c +++ b/arch/x86_64/kernel/early-quirks.c @@ -32,7 +32,7 @@ #ifdef CONFIG_ACPI static int nvidia_hpet_detected __initdata; -static int __init nvidia_hpet_check(unsigned long phys, unsigned long size) +static int __init nvidia_hpet_check(struct acpi_table_header *header) { nvidia_hpet_detected = 1; return 0; @@ -53,7 +53,7 @@ #ifdef CONFIG_ACPI return; nvidia_hpet_detected = 0; - acpi_table_parse(ACPI_HPET, nvidia_hpet_check); + acpi_table_parse(ACPI_SIG_HPET, nvidia_hpet_check); if (nvidia_hpet_detected == 0) { acpi_skip_timer_override = 1; printk(KERN_INFO "Nvidia board " diff --git a/arch/x86_64/kernel/genapic.c b/arch/x86_64/kernel/genapic.c index b007433..0b3603a 100644 --- a/arch/x86_64/kernel/genapic.c +++ b/arch/x86_64/kernel/genapic.c @@ -58,8 +58,8 @@ #if defined(CONFIG_ACPI) * Some x86_64 machines use physical APIC mode regardless of how many * procs/clusters are present (x86_64 ES7000 is an example). */ - if (acpi_fadt.revision > FADT2_REVISION_ID) - if (acpi_fadt.force_apic_physical_destination_mode) { + if (acpi_gbl_FADT.header.revision > FADT2_REVISION_ID) + if (acpi_gbl_FADT.flags & ACPI_FADT_APIC_PHYSICAL) { genapic = &apic_cluster; goto print; } diff --git a/arch/x86_64/kernel/head.S b/arch/x86_64/kernel/head.S index 1e6f808..598a4d0 100644 --- a/arch/x86_64/kernel/head.S +++ b/arch/x86_64/kernel/head.S @@ -163,6 +163,20 @@ #define CR0_PAGING (1<<31) */ lgdt cpu_gdt_descr + /* set up data segments. actually 0 would do too */ + movl $__KERNEL_DS,%eax + movl %eax,%ds + movl %eax,%ss + movl %eax,%es + + /* + * We don't really need to load %fs or %gs, but load them anyway + * to kill any stale realmode selectors. This allows execution + * under VT hardware. + */ + movl %eax,%fs + movl %eax,%gs + /* * Setup up a dummy PDA. this is just for some early bootup code * that does in_interrupt() @@ -173,12 +187,6 @@ #define CR0_PAGING (1<<31) shrq $32,%rdx wrmsr - /* set up data segments. actually 0 would do too */ - movl $__KERNEL_DS,%eax - movl %eax,%ds - movl %eax,%ss - movl %eax,%es - /* esi is pointer to real mode structure with interesting info. pass it to C */ movl %esi, %edi diff --git a/arch/x86_64/kernel/head64.c b/arch/x86_64/kernel/head64.c index cc230b9..5f197b0 100644 --- a/arch/x86_64/kernel/head64.c +++ b/arch/x86_64/kernel/head64.c @@ -34,8 +34,6 @@ #define OLD_CL_MAGIC 0xA33F #define OLD_CL_BASE_ADDR 0x90000 #define OLD_CL_OFFSET 0x90022 -extern char saved_command_line[]; - static void __init copy_bootdata(char *real_mode_data) { int new_data; @@ -50,7 +48,7 @@ static void __init copy_bootdata(char *r new_data = OLD_CL_BASE_ADDR + * (u16 *) OLD_CL_OFFSET; } command_line = (char *) ((u64)(new_data)); - memcpy(saved_command_line, command_line, COMMAND_LINE_SIZE); + memcpy(boot_command_line, command_line, COMMAND_LINE_SIZE); } void __init x86_64_start_kernel(char * real_mode_data) diff --git a/arch/x86_64/kernel/hpet.c b/arch/x86_64/kernel/hpet.c new file mode 100644 index 0000000..65a0edd --- /dev/null +++ b/arch/x86_64/kernel/hpet.c @@ -0,0 +1,511 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +int nohpet __initdata; + +unsigned long hpet_address; +unsigned long hpet_period; /* fsecs / HPET clock */ +unsigned long hpet_tick; /* HPET clocks / interrupt */ + +int hpet_use_timer; /* Use counter of hpet for time keeping, + * otherwise PIT + */ + +#ifdef CONFIG_HPET +static __init int late_hpet_init(void) +{ + struct hpet_data hd; + unsigned int ntimer; + + if (!hpet_address) + return 0; + + memset(&hd, 0, sizeof(hd)); + + ntimer = hpet_readl(HPET_ID); + ntimer = (ntimer & HPET_ID_NUMBER) >> HPET_ID_NUMBER_SHIFT; + ntimer++; + + /* + * Register with driver. + * Timer0 and Timer1 is used by platform. + */ + hd.hd_phys_address = hpet_address; + hd.hd_address = (void __iomem *)fix_to_virt(FIX_HPET_BASE); + hd.hd_nirqs = ntimer; + hd.hd_flags = HPET_DATA_PLATFORM; + hpet_reserve_timer(&hd, 0); +#ifdef CONFIG_HPET_EMULATE_RTC + hpet_reserve_timer(&hd, 1); +#endif + hd.hd_irq[0] = HPET_LEGACY_8254; + hd.hd_irq[1] = HPET_LEGACY_RTC; + if (ntimer > 2) { + struct hpet *hpet; + struct hpet_timer *timer; + int i; + + hpet = (struct hpet *) fix_to_virt(FIX_HPET_BASE); + timer = &hpet->hpet_timers[2]; + for (i = 2; i < ntimer; timer++, i++) + hd.hd_irq[i] = (timer->hpet_config & + Tn_INT_ROUTE_CNF_MASK) >> + Tn_INT_ROUTE_CNF_SHIFT; + + } + + hpet_alloc(&hd); + return 0; +} +fs_initcall(late_hpet_init); +#endif + +int hpet_timer_stop_set_go(unsigned long tick) +{ + unsigned int cfg; + +/* + * Stop the timers and reset the main counter. + */ + + cfg = hpet_readl(HPET_CFG); + cfg &= ~(HPET_CFG_ENABLE | HPET_CFG_LEGACY); + hpet_writel(cfg, HPET_CFG); + hpet_writel(0, HPET_COUNTER); + hpet_writel(0, HPET_COUNTER + 4); + +/* + * Set up timer 0, as periodic with first interrupt to happen at hpet_tick, + * and period also hpet_tick. + */ + if (hpet_use_timer) { + hpet_writel(HPET_TN_ENABLE | HPET_TN_PERIODIC | HPET_TN_SETVAL | + HPET_TN_32BIT, HPET_T0_CFG); + hpet_writel(hpet_tick, HPET_T0_CMP); /* next interrupt */ + hpet_writel(hpet_tick, HPET_T0_CMP); /* period */ + cfg |= HPET_CFG_LEGACY; + } +/* + * Go! + */ + + cfg |= HPET_CFG_ENABLE; + hpet_writel(cfg, HPET_CFG); + + return 0; +} + +int hpet_arch_init(void) +{ + unsigned int id; + + if (!hpet_address) + return -1; + set_fixmap_nocache(FIX_HPET_BASE, hpet_address); + __set_fixmap(VSYSCALL_HPET, hpet_address, PAGE_KERNEL_VSYSCALL_NOCACHE); + +/* + * Read the period, compute tick and quotient. + */ + + id = hpet_readl(HPET_ID); + + if (!(id & HPET_ID_VENDOR) || !(id & HPET_ID_NUMBER)) + return -1; + + hpet_period = hpet_readl(HPET_PERIOD); + if (hpet_period < 100000 || hpet_period > 100000000) + return -1; + + hpet_tick = (FSEC_PER_TICK + hpet_period / 2) / hpet_period; + + hpet_use_timer = (id & HPET_ID_LEGSUP); + + return hpet_timer_stop_set_go(hpet_tick); +} + +int hpet_reenable(void) +{ + return hpet_timer_stop_set_go(hpet_tick); +} + +/* + * calibrate_tsc() calibrates the processor TSC in a very simple way, comparing + * it to the HPET timer of known frequency. + */ + +#define TICK_COUNT 100000000 +#define TICK_MIN 5000 + +/* + * Some platforms take periodic SMI interrupts with 5ms duration. Make sure none + * occurs between the reads of the hpet & TSC. + */ +static void __init read_hpet_tsc(int *hpet, int *tsc) +{ + int tsc1, tsc2, hpet1; + + do { + tsc1 = get_cycles_sync(); + hpet1 = hpet_readl(HPET_COUNTER); + tsc2 = get_cycles_sync(); + } while (tsc2 - tsc1 > TICK_MIN); + *hpet = hpet1; + *tsc = tsc2; +} + +unsigned int __init hpet_calibrate_tsc(void) +{ + int tsc_start, hpet_start; + int tsc_now, hpet_now; + unsigned long flags; + + local_irq_save(flags); + + read_hpet_tsc(&hpet_start, &tsc_start); + + do { + local_irq_disable(); + read_hpet_tsc(&hpet_now, &tsc_now); + local_irq_restore(flags); + } while ((tsc_now - tsc_start) < TICK_COUNT && + (hpet_now - hpet_start) < TICK_COUNT); + + return (tsc_now - tsc_start) * 1000000000L + / ((hpet_now - hpet_start) * hpet_period / 1000); +} + +#ifdef CONFIG_HPET_EMULATE_RTC +/* HPET in LegacyReplacement Mode eats up RTC interrupt line. When, HPET + * is enabled, we support RTC interrupt functionality in software. + * RTC has 3 kinds of interrupts: + * 1) Update Interrupt - generate an interrupt, every sec, when RTC clock + * is updated + * 2) Alarm Interrupt - generate an interrupt at a specific time of day + * 3) Periodic Interrupt - generate periodic interrupt, with frequencies + * 2Hz-8192Hz (2Hz-64Hz for non-root user) (all freqs in powers of 2) + * (1) and (2) above are implemented using polling at a frequency of + * 64 Hz. The exact frequency is a tradeoff between accuracy and interrupt + * overhead. (DEFAULT_RTC_INT_FREQ) + * For (3), we use interrupts at 64Hz or user specified periodic + * frequency, whichever is higher. + */ +#include + +#define DEFAULT_RTC_INT_FREQ 64 +#define RTC_NUM_INTS 1 + +static unsigned long UIE_on; +static unsigned long prev_update_sec; + +static unsigned long AIE_on; +static struct rtc_time alarm_time; + +static unsigned long PIE_on; +static unsigned long PIE_freq = DEFAULT_RTC_INT_FREQ; +static unsigned long PIE_count; + +static unsigned long hpet_rtc_int_freq; /* RTC interrupt frequency */ +static unsigned int hpet_t1_cmp; /* cached comparator register */ + +int is_hpet_enabled(void) +{ + return hpet_address != 0; +} + +/* + * Timer 1 for RTC, we do not use periodic interrupt feature, + * even if HPET supports periodic interrupts on Timer 1. + * The reason being, to set up a periodic interrupt in HPET, we need to + * stop the main counter. And if we do that everytime someone diables/enables + * RTC, we will have adverse effect on main kernel timer running on Timer 0. + * So, for the time being, simulate the periodic interrupt in software. + * + * hpet_rtc_timer_init() is called for the first time and during subsequent + * interuppts reinit happens through hpet_rtc_timer_reinit(). + */ +int hpet_rtc_timer_init(void) +{ + unsigned int cfg, cnt; + unsigned long flags; + + if (!is_hpet_enabled()) + return 0; + /* + * Set the counter 1 and enable the interrupts. + */ + if (PIE_on && (PIE_freq > DEFAULT_RTC_INT_FREQ)) + hpet_rtc_int_freq = PIE_freq; + else + hpet_rtc_int_freq = DEFAULT_RTC_INT_FREQ; + + local_irq_save(flags); + + cnt = hpet_readl(HPET_COUNTER); + cnt += ((hpet_tick*HZ)/hpet_rtc_int_freq); + hpet_writel(cnt, HPET_T1_CMP); + hpet_t1_cmp = cnt; + + cfg = hpet_readl(HPET_T1_CFG); + cfg &= ~HPET_TN_PERIODIC; + cfg |= HPET_TN_ENABLE | HPET_TN_32BIT; + hpet_writel(cfg, HPET_T1_CFG); + + local_irq_restore(flags); + + return 1; +} + +static void hpet_rtc_timer_reinit(void) +{ + unsigned int cfg, cnt, ticks_per_int, lost_ints; + + if (unlikely(!(PIE_on | AIE_on | UIE_on))) { + cfg = hpet_readl(HPET_T1_CFG); + cfg &= ~HPET_TN_ENABLE; + hpet_writel(cfg, HPET_T1_CFG); + return; + } + + if (PIE_on && (PIE_freq > DEFAULT_RTC_INT_FREQ)) + hpet_rtc_int_freq = PIE_freq; + else + hpet_rtc_int_freq = DEFAULT_RTC_INT_FREQ; + + /* It is more accurate to use the comparator value than current count.*/ + ticks_per_int = hpet_tick * HZ / hpet_rtc_int_freq; + hpet_t1_cmp += ticks_per_int; + hpet_writel(hpet_t1_cmp, HPET_T1_CMP); + + /* + * If the interrupt handler was delayed too long, the write above tries + * to schedule the next interrupt in the past and the hardware would + * not interrupt until the counter had wrapped around. + * So we have to check that the comparator wasn't set to a past time. + */ + cnt = hpet_readl(HPET_COUNTER); + if (unlikely((int)(cnt - hpet_t1_cmp) > 0)) { + lost_ints = (cnt - hpet_t1_cmp) / ticks_per_int + 1; + /* Make sure that, even with the time needed to execute + * this code, the next scheduled interrupt has been moved + * back to the future: */ + lost_ints++; + + hpet_t1_cmp += lost_ints * ticks_per_int; + hpet_writel(hpet_t1_cmp, HPET_T1_CMP); + + if (PIE_on) + PIE_count += lost_ints; + + if (printk_ratelimit()) + printk(KERN_WARNING "rtc: lost some interrupts at %ldHz.\n", + hpet_rtc_int_freq); + } +} + +/* + * The functions below are called from rtc driver. + * Return 0 if HPET is not being used. + * Otherwise do the necessary changes and return 1. + */ +int hpet_mask_rtc_irq_bit(unsigned long bit_mask) +{ + if (!is_hpet_enabled()) + return 0; + + if (bit_mask & RTC_UIE) + UIE_on = 0; + if (bit_mask & RTC_PIE) + PIE_on = 0; + if (bit_mask & RTC_AIE) + AIE_on = 0; + + return 1; +} + +int hpet_set_rtc_irq_bit(unsigned long bit_mask) +{ + int timer_init_reqd = 0; + + if (!is_hpet_enabled()) + return 0; + + if (!(PIE_on | AIE_on | UIE_on)) + timer_init_reqd = 1; + + if (bit_mask & RTC_UIE) { + UIE_on = 1; + } + if (bit_mask & RTC_PIE) { + PIE_on = 1; + PIE_count = 0; + } + if (bit_mask & RTC_AIE) { + AIE_on = 1; + } + + if (timer_init_reqd) + hpet_rtc_timer_init(); + + return 1; +} + +int hpet_set_alarm_time(unsigned char hrs, unsigned char min, unsigned char sec) +{ + if (!is_hpet_enabled()) + return 0; + + alarm_time.tm_hour = hrs; + alarm_time.tm_min = min; + alarm_time.tm_sec = sec; + + return 1; +} + +int hpet_set_periodic_freq(unsigned long freq) +{ + if (!is_hpet_enabled()) + return 0; + + PIE_freq = freq; + PIE_count = 0; + + return 1; +} + +int hpet_rtc_dropped_irq(void) +{ + if (!is_hpet_enabled()) + return 0; + + return 1; +} + +irqreturn_t hpet_rtc_interrupt(int irq, void *dev_id, struct pt_regs *regs) +{ + struct rtc_time curr_time; + unsigned long rtc_int_flag = 0; + int call_rtc_interrupt = 0; + + hpet_rtc_timer_reinit(); + + if (UIE_on | AIE_on) { + rtc_get_rtc_time(&curr_time); + } + if (UIE_on) { + if (curr_time.tm_sec != prev_update_sec) { + /* Set update int info, call real rtc int routine */ + call_rtc_interrupt = 1; + rtc_int_flag = RTC_UF; + prev_update_sec = curr_time.tm_sec; + } + } + if (PIE_on) { + PIE_count++; + if (PIE_count >= hpet_rtc_int_freq/PIE_freq) { + /* Set periodic int info, call real rtc int routine */ + call_rtc_interrupt = 1; + rtc_int_flag |= RTC_PF; + PIE_count = 0; + } + } + if (AIE_on) { + if ((curr_time.tm_sec == alarm_time.tm_sec) && + (curr_time.tm_min == alarm_time.tm_min) && + (curr_time.tm_hour == alarm_time.tm_hour)) { + /* Set alarm int info, call real rtc int routine */ + call_rtc_interrupt = 1; + rtc_int_flag |= RTC_AF; + } + } + if (call_rtc_interrupt) { + rtc_int_flag |= (RTC_IRQF | (RTC_NUM_INTS << 8)); + rtc_interrupt(rtc_int_flag, dev_id); + } + return IRQ_HANDLED; +} +#endif + +static int __init nohpet_setup(char *s) +{ + nohpet = 1; + return 1; +} + +__setup("nohpet", nohpet_setup); + +#define HPET_MASK 0xFFFFFFFF +#define HPET_SHIFT 22 + +/* FSEC = 10^-15 NSEC = 10^-9 */ +#define FSEC_PER_NSEC 1000000 + +static void *hpet_ptr; + +static cycle_t read_hpet(void) +{ + return (cycle_t)readl(hpet_ptr); +} + +static cycle_t __vsyscall_fn vread_hpet(void) +{ + return readl((void __iomem *)fix_to_virt(VSYSCALL_HPET) + 0xf0); +} + +struct clocksource clocksource_hpet = { + .name = "hpet", + .rating = 250, + .read = read_hpet, + .mask = (cycle_t)HPET_MASK, + .mult = 0, /* set below */ + .shift = HPET_SHIFT, + .flags = CLOCK_SOURCE_IS_CONTINUOUS, + .vread = vread_hpet, +}; + +static int __init init_hpet_clocksource(void) +{ + unsigned long hpet_period; + void __iomem *hpet_base; + u64 tmp; + + if (!hpet_address) + return -ENODEV; + + /* calculate the hpet address: */ + hpet_base = ioremap_nocache(hpet_address, HPET_MMAP_SIZE); + hpet_ptr = hpet_base + HPET_COUNTER; + + /* calculate the frequency: */ + hpet_period = readl(hpet_base + HPET_PERIOD); + + /* + * hpet period is in femto seconds per cycle + * so we need to convert this to ns/cyc units + * aproximated by mult/2^shift + * + * fsec/cyc * 1nsec/1000000fsec = nsec/cyc = mult/2^shift + * fsec/cyc * 1ns/1000000fsec * 2^shift = mult + * fsec/cyc * 2^shift * 1nsec/1000000fsec = mult + * (fsec/cyc << shift)/1000000 = mult + * (hpet_period << shift)/FSEC_PER_NSEC = mult + */ + tmp = (u64)hpet_period << HPET_SHIFT; + do_div(tmp, FSEC_PER_NSEC); + clocksource_hpet.mult = (u32)tmp; + + return clocksource_register(&clocksource_hpet); +} + +module_init(init_hpet_clocksource); diff --git a/arch/x86_64/kernel/i8259.c b/arch/x86_64/kernel/i8259.c index d73c79e..01e2cf0 100644 --- a/arch/x86_64/kernel/i8259.c +++ b/arch/x86_64/kernel/i8259.c @@ -103,6 +103,7 @@ static void mask_and_ack_8259A(unsigned static struct irq_chip i8259A_chip = { .name = "XT-PIC", .mask = disable_8259A_irq, + .disable = disable_8259A_irq, .unmask = enable_8259A_irq, .mask_ack = mask_and_ack_8259A, }; diff --git a/arch/x86_64/kernel/io_apic.c b/arch/x86_64/kernel/io_apic.c index d7bad90..950682f 100644 --- a/arch/x86_64/kernel/io_apic.c +++ b/arch/x86_64/kernel/io_apic.c @@ -810,11 +810,9 @@ static void ioapic_register_intr(int irq trigger == IOAPIC_LEVEL) set_irq_chip_and_handler_name(irq, &ioapic_chip, handle_fasteoi_irq, "fasteoi"); - else { - irq_desc[irq].status |= IRQ_DELAYED_DISABLE; + else set_irq_chip_and_handler_name(irq, &ioapic_chip, handle_edge_irq, "edge"); - } } static void __init setup_IO_APIC_irq(int apic, int pin, int idx, int irq) { @@ -831,7 +829,7 @@ static void __init setup_IO_APIC_irq(int entry.delivery_mode = INT_DELIVERY_MODE; entry.dest_mode = INT_DEST_MODE; entry.mask = 0; /* enable IRQ */ - entry.dest.logical.logical_dest = cpu_mask_to_apicid(TARGET_CPUS); + entry.dest = cpu_mask_to_apicid(TARGET_CPUS); entry.trigger = irq_trigger(idx); entry.polarity = irq_polarity(idx); @@ -839,7 +837,7 @@ static void __init setup_IO_APIC_irq(int if (irq_trigger(idx)) { entry.trigger = 1; entry.mask = 1; - entry.dest.logical.logical_dest = cpu_mask_to_apicid(TARGET_CPUS); + entry.dest = cpu_mask_to_apicid(TARGET_CPUS); } if (!apic && !IO_APIC_IRQ(irq)) @@ -851,7 +849,7 @@ static void __init setup_IO_APIC_irq(int if (vector < 0) return; - entry.dest.logical.logical_dest = cpu_mask_to_apicid(mask); + entry.dest = cpu_mask_to_apicid(mask); entry.vector = vector; ioapic_register_intr(irq, vector, IOAPIC_AUTO); @@ -920,7 +918,7 @@ static void __init setup_ExtINT_IRQ0_pin */ entry.dest_mode = INT_DEST_MODE; entry.mask = 0; /* unmask IRQ now */ - entry.dest.logical.logical_dest = cpu_mask_to_apicid(TARGET_CPUS); + entry.dest = cpu_mask_to_apicid(TARGET_CPUS); entry.delivery_mode = INT_DELIVERY_MODE; entry.polarity = 0; entry.trigger = 0; @@ -1020,18 +1018,17 @@ void __apicdebuginit print_IO_APIC(void) printk(KERN_DEBUG ".... IRQ redirection table:\n"); - printk(KERN_DEBUG " NR Log Phy Mask Trig IRR Pol" - " Stat Dest 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++) { struct IO_APIC_route_entry entry; entry = ioapic_read_entry(apic, i); - printk(KERN_DEBUG " %02x %03X %02X ", + printk(KERN_DEBUG " %02x %03X ", i, - entry.dest.logical.logical_dest, - entry.dest.physical.physical_dest + entry.dest ); printk("%1d %1d %1d %1d %1d %1d %1d %02X\n", @@ -1293,8 +1290,7 @@ void disable_IO_APIC(void) entry.dest_mode = 0; /* Physical */ entry.delivery_mode = dest_ExtINT; /* ExtInt */ entry.vector = 0; - entry.dest.physical.physical_dest = - GET_APIC_ID(apic_read(APIC_ID)); + entry.dest = GET_APIC_ID(apic_read(APIC_ID)); /* * Add it to the IO-APIC irq-routing table: @@ -1556,7 +1552,7 @@ static inline void unlock_ExtINT_logic(v entry1.dest_mode = 0; /* physical delivery */ entry1.mask = 0; /* unmask IRQ now */ - entry1.dest.physical.physical_dest = hard_smp_processor_id(); + entry1.dest = hard_smp_processor_id(); entry1.delivery_mode = dest_ExtINT; entry1.polarity = entry0.polarity; entry1.trigger = 0; @@ -1956,24 +1952,31 @@ #endif .retrigger = ioapic_retrigger_irq, }; -int arch_setup_msi_irq(unsigned int irq, struct pci_dev *dev) +int arch_setup_msi_irq(struct pci_dev *dev, struct msi_desc *desc) { struct msi_msg msg; - int ret; + int irq, ret; + irq = create_irq(); + if (irq < 0) + return irq; + + set_irq_msi(irq, desc); ret = msi_compose_msg(dev, irq, &msg); - if (ret < 0) + if (ret < 0) { + destroy_irq(irq); return ret; + } write_msi_msg(irq, &msg); set_irq_chip_and_handler_name(irq, &msi_chip, handle_edge_irq, "edge"); - return 0; + return irq; } void arch_teardown_msi_irq(unsigned int irq) { - return; + destroy_irq(irq); } #endif /* CONFIG_PCI_MSI */ @@ -2124,7 +2127,7 @@ int io_apic_set_pci_routing (int ioapic, entry.delivery_mode = INT_DELIVERY_MODE; entry.dest_mode = INT_DEST_MODE; - entry.dest.logical.logical_dest = cpu_mask_to_apicid(mask); + entry.dest = cpu_mask_to_apicid(mask); entry.trigger = triggering; entry.polarity = polarity; entry.mask = 1; /* Disabled (masked) */ diff --git a/arch/x86_64/kernel/ioport.c b/arch/x86_64/kernel/ioport.c index fe063d3..745b1f0 100644 --- a/arch/x86_64/kernel/ioport.c +++ b/arch/x86_64/kernel/ioport.c @@ -114,6 +114,6 @@ asmlinkage long sys_iopl(unsigned int le if (!capable(CAP_SYS_RAWIO)) return -EPERM; } - regs->eflags = (regs->eflags &~ 0x3000UL) | (level << 12); + regs->eflags = (regs->eflags &~ X86_EFLAGS_IOPL) | (level << 12); return 0; } diff --git a/arch/x86_64/kernel/irq.c b/arch/x86_64/kernel/irq.c index 0c06af6..3bc30d2 100644 --- a/arch/x86_64/kernel/irq.c +++ b/arch/x86_64/kernel/irq.c @@ -18,6 +18,7 @@ #include #include #include #include +#include atomic_t irq_err_count; @@ -120,9 +121,14 @@ #endif if (likely(irq < NR_IRQS)) generic_handle_irq(irq); - else if (printk_ratelimit()) - printk(KERN_EMERG "%s: %d.%d No irq handler for vector\n", - __func__, smp_processor_id(), vector); + else { + if (!disable_apic) + ack_APIC_irq(); + + if (printk_ratelimit()) + printk(KERN_EMERG "%s: %d.%d No irq handler for vector\n", + __func__, smp_processor_id(), vector); + } irq_exit(); diff --git a/arch/x86_64/kernel/mce.c b/arch/x86_64/kernel/mce.c index ac08503..8011a8e 100644 --- a/arch/x86_64/kernel/mce.c +++ b/arch/x86_64/kernel/mce.c @@ -19,6 +19,7 @@ #include #include #include #include +#include #include #include #include @@ -42,6 +43,10 @@ static unsigned long console_logged; static int notify_user; static int rip_msr; static int mce_bootlog = 1; +static atomic_t mce_events; + +static char trigger[128]; +static char *trigger_argv[2] = { trigger, NULL }; /* * Lockless MCE logging infrastructure. @@ -57,6 +62,7 @@ struct mce_log mcelog = { void mce_log(struct mce *mce) { unsigned next, entry; + atomic_inc(&mce_events); mce->finished = 0; wmb(); for (;;) { @@ -161,6 +167,17 @@ static inline void mce_get_rip(struct mc } } +static void do_mce_trigger(void) +{ + static atomic_t mce_logged; + int events = atomic_read(&mce_events); + if (events != atomic_read(&mce_logged) && trigger[0]) { + /* Small race window, but should be harmless. */ + atomic_set(&mce_logged, events); + call_usermodehelper(trigger, trigger_argv, NULL, -1); + } +} + /* * The actual machine check handler */ @@ -234,8 +251,12 @@ void do_machine_check(struct pt_regs * r } /* Never do anything final in the polling timer */ - if (!regs) + if (!regs) { + /* Normal interrupt context here. Call trigger for any new + events. */ + do_mce_trigger(); goto out; + } /* If we didn't find an uncorrectable error, pick the last one (shouldn't happen, just being safe). */ @@ -516,7 +537,7 @@ static int mce_ioctl(struct inode *i, st } } -static struct file_operations mce_chrdev_ops = { +static const struct file_operations mce_chrdev_ops = { .read = mce_read, .ioctl = mce_ioctl, }; @@ -606,17 +627,42 @@ #define ACCESSOR(name, var, start) \ } \ static SYSDEV_ATTR(name, 0644, show_ ## name, set_ ## name); +/* TBD should generate these dynamically based on number of available banks */ ACCESSOR(bank0ctl,bank[0],mce_restart()) ACCESSOR(bank1ctl,bank[1],mce_restart()) ACCESSOR(bank2ctl,bank[2],mce_restart()) ACCESSOR(bank3ctl,bank[3],mce_restart()) ACCESSOR(bank4ctl,bank[4],mce_restart()) ACCESSOR(bank5ctl,bank[5],mce_restart()) -static struct sysdev_attribute * bank_attributes[NR_BANKS] = { - &attr_bank0ctl, &attr_bank1ctl, &attr_bank2ctl, - &attr_bank3ctl, &attr_bank4ctl, &attr_bank5ctl}; + +static ssize_t show_trigger(struct sys_device *s, char *buf) +{ + strcpy(buf, trigger); + strcat(buf, "\n"); + return strlen(trigger) + 1; +} + +static ssize_t set_trigger(struct sys_device *s,const char *buf,size_t siz) +{ + char *p; + int len; + strncpy(trigger, buf, sizeof(trigger)); + trigger[sizeof(trigger)-1] = 0; + len = strlen(trigger); + p = strchr(trigger, '\n'); + if (*p) *p = 0; + return len; +} + +static SYSDEV_ATTR(trigger, 0644, show_trigger, set_trigger); ACCESSOR(tolerant,tolerant,) ACCESSOR(check_interval,check_interval,mce_restart()) +static struct sysdev_attribute *mce_attributes[] = { + &attr_bank0ctl, &attr_bank1ctl, &attr_bank2ctl, + &attr_bank3ctl, &attr_bank4ctl, &attr_bank5ctl, + &attr_tolerant, &attr_check_interval, &attr_trigger, + NULL +}; /* Per cpu sysdev init. All of the cpus still share the same ctl bank */ static __cpuinit int mce_create_device(unsigned int cpu) @@ -632,11 +678,9 @@ static __cpuinit int mce_create_device(u err = sysdev_register(&per_cpu(device_mce,cpu)); if (!err) { - for (i = 0; i < banks; i++) + for (i = 0; mce_attributes[i]; i++) sysdev_create_file(&per_cpu(device_mce,cpu), - bank_attributes[i]); - sysdev_create_file(&per_cpu(device_mce,cpu), &attr_tolerant); - sysdev_create_file(&per_cpu(device_mce,cpu), &attr_check_interval); + mce_attributes[i]); } return err; } @@ -645,11 +689,9 @@ static void mce_remove_device(unsigned i { int i; - for (i = 0; i < banks; i++) + for (i = 0; mce_attributes[i]; i++) sysdev_remove_file(&per_cpu(device_mce,cpu), - bank_attributes[i]); - sysdev_remove_file(&per_cpu(device_mce,cpu), &attr_tolerant); - sysdev_remove_file(&per_cpu(device_mce,cpu), &attr_check_interval); + mce_attributes[i]); sysdev_unregister(&per_cpu(device_mce,cpu)); memset(&per_cpu(device_mce, cpu).kobj, 0, sizeof(struct kobject)); } diff --git a/arch/x86_64/kernel/mce_amd.c b/arch/x86_64/kernel/mce_amd.c index fa09deb..d0bd5d6 100644 --- a/arch/x86_64/kernel/mce_amd.c +++ b/arch/x86_64/kernel/mce_amd.c @@ -37,6 +37,8 @@ #define NR_BLOCKS 9 #define THRESHOLD_MAX 0xFFF #define INT_TYPE_APIC 0x00020000 #define MASK_VALID_HI 0x80000000 +#define MASK_CNTP_HI 0x40000000 +#define MASK_LOCKED_HI 0x20000000 #define MASK_LVTOFF_HI 0x00F00000 #define MASK_COUNT_EN_HI 0x00080000 #define MASK_INT_TYPE_HI 0x00060000 @@ -122,14 +124,17 @@ void __cpuinit mce_amd_feature_init(stru for (block = 0; block < NR_BLOCKS; ++block) { if (block == 0) address = MSR_IA32_MC0_MISC + bank * 4; - else if (block == 1) - address = MCG_XBLK_ADDR - + ((low & MASK_BLKPTR_LO) >> 21); + else if (block == 1) { + address = (low & MASK_BLKPTR_LO) >> 21; + if (!address) + break; + address += MCG_XBLK_ADDR; + } else ++address; if (rdmsr_safe(address, &low, &high)) - continue; + break; if (!(high & MASK_VALID_HI)) { if (block) @@ -138,8 +143,8 @@ void __cpuinit mce_amd_feature_init(stru break; } - if (!(high & MASK_VALID_HI >> 1) || - (high & MASK_VALID_HI >> 2)) + if (!(high & MASK_CNTP_HI) || + (high & MASK_LOCKED_HI)) continue; if (!block) @@ -187,17 +192,22 @@ asmlinkage void mce_threshold_interrupt( /* assume first bank caused it */ for (bank = 0; bank < NR_BANKS; ++bank) { + if (!(per_cpu(bank_map, m.cpu) & (1 << bank))) + continue; for (block = 0; block < NR_BLOCKS; ++block) { if (block == 0) address = MSR_IA32_MC0_MISC + bank * 4; - else if (block == 1) - address = MCG_XBLK_ADDR - + ((low & MASK_BLKPTR_LO) >> 21); + else if (block == 1) { + address = (low & MASK_BLKPTR_LO) >> 21; + if (!address) + break; + address += MCG_XBLK_ADDR; + } else ++address; if (rdmsr_safe(address, &low, &high)) - continue; + break; if (!(high & MASK_VALID_HI)) { if (block) @@ -206,10 +216,14 @@ asmlinkage void mce_threshold_interrupt( break; } - if (!(high & MASK_VALID_HI >> 1) || - (high & MASK_VALID_HI >> 2)) + if (!(high & MASK_CNTP_HI) || + (high & MASK_LOCKED_HI)) continue; + /* Log the machine check that caused the threshold + event. */ + do_machine_check(NULL, 0); + if (high & MASK_OVERFLOW_HI) { rdmsrl(address, m.misc); rdmsrl(MSR_IA32_MC0_STATUS + bank * 4, @@ -385,7 +399,7 @@ static __cpuinit int allocate_threshold_ return 0; if (rdmsr_safe(address, &low, &high)) - goto recurse; + return 0; if (!(high & MASK_VALID_HI)) { if (block) @@ -394,14 +408,13 @@ static __cpuinit int allocate_threshold_ return 0; } - if (!(high & MASK_VALID_HI >> 1) || - (high & MASK_VALID_HI >> 2)) + if (!(high & MASK_CNTP_HI) || + (high & MASK_LOCKED_HI)) goto recurse; b = kzalloc(sizeof(struct threshold_block), GFP_KERNEL); if (!b) return -ENOMEM; - memset(b, 0, sizeof(struct threshold_block)); b->block = block; b->bank = bank; @@ -490,7 +503,6 @@ #endif err = -ENOMEM; goto out; } - memset(b, 0, sizeof(struct threshold_bank)); kobject_set_name(&b->kobj, "threshold_bank%i", bank); b->kobj.parent = &per_cpu(device_mce, cpu).kobj; diff --git a/arch/x86_64/kernel/mpparse.c b/arch/x86_64/kernel/mpparse.c index 0807256..50dd8be 100644 --- a/arch/x86_64/kernel/mpparse.c +++ b/arch/x86_64/kernel/mpparse.c @@ -798,7 +798,7 @@ int mp_register_gsi(u32 gsi, int trigger return gsi; /* Don't set up the ACPI SCI because it's already set up */ - if (acpi_fadt.sci_int == gsi) + if (acpi_gbl_FADT.sci_interrupt == gsi) return gsi; ioapic = mp_find_ioapic(gsi); diff --git a/arch/x86_64/kernel/nmi.c b/arch/x86_64/kernel/nmi.c index 9cb42ec..486f4c6 100644 --- a/arch/x86_64/kernel/nmi.c +++ b/arch/x86_64/kernel/nmi.c @@ -172,7 +172,7 @@ static __cpuinit inline int nmi_known_cp { switch (boot_cpu_data.x86_vendor) { case X86_VENDOR_AMD: - return boot_cpu_data.x86 == 15; + return boot_cpu_data.x86 == 15 || boot_cpu_data.x86 == 16; case X86_VENDOR_INTEL: if (cpu_has(&boot_cpu_data, X86_FEATURE_ARCH_PERFMON)) return 1; @@ -214,6 +214,23 @@ static __init void nmi_cpu_busy(void *da } #endif +static unsigned int adjust_for_32bit_ctr(unsigned int hz) +{ + unsigned int retval = hz; + + /* + * On Intel CPUs with ARCH_PERFMON only 32 bits in the counter + * are writable, with higher bits sign extending from bit 31. + * So, we can only program the counter with 31 bit values and + * 32nd bit should be 1, for 33.. to be 1. + * Find the appropriate nmi_hz + */ + if ((((u64)cpu_khz * 1000) / retval) > 0x7fffffffULL) { + retval = ((u64)cpu_khz * 1000) / 0x7fffffffUL + 1; + } + return retval; +} + int __init check_nmi_watchdog (void) { int *counts; @@ -268,17 +285,8 @@ #endif struct nmi_watchdog_ctlblk *wd = &__get_cpu_var(nmi_watchdog_ctlblk); nmi_hz = 1; - /* - * On Intel CPUs with ARCH_PERFMON only 32 bits in the counter - * are writable, with higher bits sign extending from bit 31. - * So, we can only program the counter with 31 bit values and - * 32nd bit should be 1, for 33.. to be 1. - * Find the appropriate nmi_hz - */ - if (wd->perfctr_msr == MSR_ARCH_PERFMON_PERFCTR0 && - ((u64)cpu_khz * 1000) > 0x7fffffffULL) { - nmi_hz = ((u64)cpu_khz * 1000) / 0x7fffffffUL + 1; - } + if (wd->perfctr_msr == MSR_ARCH_PERFMON_PERFCTR0) + nmi_hz = adjust_for_32bit_ctr(nmi_hz); } kfree(counts); @@ -360,6 +368,33 @@ void enable_timer_nmi_watchdog(void) } } +static void __acpi_nmi_disable(void *__unused) +{ + apic_write(APIC_LVT0, APIC_DM_NMI | APIC_LVT_MASKED); +} + +/* + * Disable timer based NMIs on all CPUs: + */ +void acpi_nmi_disable(void) +{ + if (atomic_read(&nmi_active) && nmi_watchdog == NMI_IO_APIC) + on_each_cpu(__acpi_nmi_disable, NULL, 0, 1); +} + +static void __acpi_nmi_enable(void *__unused) +{ + apic_write(APIC_LVT0, APIC_DM_NMI); +} + +/* + * Enable timer based NMIs on all CPUs: + */ +void acpi_nmi_enable(void) +{ + if (atomic_read(&nmi_active) && nmi_watchdog == NMI_IO_APIC) + on_each_cpu(__acpi_nmi_enable, NULL, 0, 1); +} #ifdef CONFIG_PM static int nmi_pm_active; /* nmi_active before suspend */ @@ -634,7 +669,9 @@ static int setup_intel_arch_watchdog(voi /* setup the timer */ wrmsr(evntsel_msr, evntsel, 0); - wrmsrl(perfctr_msr, -((u64)cpu_khz * 1000 / nmi_hz)); + + nmi_hz = adjust_for_32bit_ctr(nmi_hz); + wrmsr(perfctr_msr, (u32)(-((u64)cpu_khz * 1000 / nmi_hz)), 0); apic_write(APIC_LVTPC, APIC_DM_NMI); evntsel |= ARCH_PERFMON_EVENTSEL0_ENABLE; @@ -855,15 +892,23 @@ #endif dummy &= ~P4_CCCR_OVF; wrmsrl(wd->cccr_msr, dummy); apic_write(APIC_LVTPC, APIC_DM_NMI); + /* start the cycle over again */ + wrmsrl(wd->perfctr_msr, + -((u64)cpu_khz * 1000 / nmi_hz)); } else if (wd->perfctr_msr == MSR_ARCH_PERFMON_PERFCTR0) { /* * ArchPerfom/Core Duo needs to re-unmask * the apic vector */ apic_write(APIC_LVTPC, APIC_DM_NMI); + /* ARCH_PERFMON has 32 bit counter writes */ + wrmsr(wd->perfctr_msr, + (u32)(-((u64)cpu_khz * 1000 / nmi_hz)), 0); + } else { + /* start the cycle over again */ + wrmsrl(wd->perfctr_msr, + -((u64)cpu_khz * 1000 / nmi_hz)); } - /* start the cycle over again */ - wrmsrl(wd->perfctr_msr, -((u64)cpu_khz * 1000 / nmi_hz)); rc = 1; } else if (nmi_watchdog == NMI_IO_APIC) { /* don't know how to accurately check for this. diff --git a/arch/x86_64/kernel/pci-calgary.c b/arch/x86_64/kernel/pci-calgary.c index 3d65b1d..04480c3 100644 --- a/arch/x86_64/kernel/pci-calgary.c +++ b/arch/x86_64/kernel/pci-calgary.c @@ -138,6 +138,8 @@ static const unsigned long phb_debug_off #define PHB_DEBUG_STUFF_OFFSET 0x0020 +#define EMERGENCY_PAGES 32 /* = 128KB */ + unsigned int specified_table_size = TCE_TABLE_SIZE_UNSPECIFIED; static int translate_empty_slots __read_mostly = 0; static int calgary_detected __read_mostly = 0; @@ -296,6 +298,16 @@ static void __iommu_free(struct iommu_ta { unsigned long entry; unsigned long badbit; + unsigned long badend; + + /* were we called with bad_dma_address? */ + badend = bad_dma_address + (EMERGENCY_PAGES * PAGE_SIZE); + if (unlikely((dma_addr >= bad_dma_address) && (dma_addr < badend))) { + printk(KERN_ERR "Calgary: driver tried unmapping bad DMA " + "address 0x%Lx\n", dma_addr); + WARN_ON(1); + return; + } entry = dma_addr >> PAGE_SHIFT; @@ -656,8 +668,8 @@ static void __init calgary_reserve_regio u64 start; struct iommu_table *tbl = dev->sysdata; - /* reserve bad_dma_address in case it's a legal address */ - iommu_range_reserve(tbl, bad_dma_address, 1); + /* reserve EMERGENCY_PAGES from bad_dma_address and up */ + iommu_range_reserve(tbl, bad_dma_address, EMERGENCY_PAGES); /* avoid the BIOS/VGA first 640KB-1MB region */ start = (640 * 1024); @@ -1176,6 +1188,7 @@ int __init calgary_iommu_init(void) } force_iommu = 1; + bad_dma_address = 0x0; dma_ops = &calgary_dma_ops; return 0; diff --git a/arch/x86_64/kernel/pci-dma.c b/arch/x86_64/kernel/pci-dma.c index 683b7a5..651ccfb 100644 --- a/arch/x86_64/kernel/pci-dma.c +++ b/arch/x86_64/kernel/pci-dma.c @@ -223,30 +223,10 @@ int dma_set_mask(struct device *dev, u64 } EXPORT_SYMBOL(dma_set_mask); -/* iommu=[size][,noagp][,off][,force][,noforce][,leak][,memaper[=order]][,merge] - [,forcesac][,fullflush][,nomerge][,biomerge] - size set size of iommu (in bytes) - noagp don't initialize the AGP driver and use full aperture. - off don't use the IOMMU - leak turn on simple iommu leak tracing (only when CONFIG_IOMMU_LEAK is on) - memaper[=order] allocate an own aperture over RAM with size 32MB^order. - noforce don't force IOMMU usage. Default. - force Force IOMMU. - merge Do lazy merging. This may improve performance on some block devices. - Implies force (experimental) - biomerge Do merging at the BIO layer. This is more efficient than merge, - but should be only done with very big IOMMUs. Implies merge,force. - nomerge Don't do SG merging. - forcesac For SAC mode for masks <40bits (experimental) - fullflush Flush IOMMU on each allocation (default) - nofullflush Don't use IOMMU fullflush - allowed overwrite iommu off workarounds for specific chipsets. - soft Use software bounce buffering (default for Intel machines) - noaperture Don't touch the aperture for AGP. - allowdac Allow DMA >4GB - nodac Forbid DMA >4GB - panic Force panic when IOMMU overflows -*/ +/* + * See for the iommu kernel parameter + * documentation. + */ __init int iommu_setup(char *p) { iommu_merge = 1; diff --git a/arch/x86_64/kernel/pci-gart.c b/arch/x86_64/kernel/pci-gart.c index fc1960f..030eb37 100644 --- a/arch/x86_64/kernel/pci-gart.c +++ b/arch/x86_64/kernel/pci-gart.c @@ -185,7 +185,7 @@ #endif static inline int need_iommu(struct device *dev, unsigned long addr, size_t size) { u64 mask = *dev->dma_mask; - int high = addr + size >= mask; + int high = addr + size > mask; int mmu = high; if (force_iommu) mmu = 1; @@ -195,7 +195,7 @@ static inline int need_iommu(struct devi static inline int nonforced_iommu(struct device *dev, unsigned long addr, size_t size) { u64 mask = *dev->dma_mask; - int high = addr + size >= mask; + int high = addr + size > mask; int mmu = high; return mmu; } diff --git a/arch/x86_64/kernel/pci-swiotlb.c b/arch/x86_64/kernel/pci-swiotlb.c index 697f0aa..eb18be5 100644 --- a/arch/x86_64/kernel/pci-swiotlb.c +++ b/arch/x86_64/kernel/pci-swiotlb.c @@ -29,7 +29,7 @@ struct dma_mapping_ops swiotlb_dma_ops = .dma_supported = NULL, }; -void pci_swiotlb_init(void) +void __init pci_swiotlb_init(void) { /* don't initialize swiotlb if iommu=off (no_iommu=1) */ if (!iommu_detected && !no_iommu && end_pfn > MAX_DMA32_PFN) diff --git a/arch/x86_64/kernel/pmtimer.c b/arch/x86_64/kernel/pmtimer.c index 7554458..ae8f912 100644 --- a/arch/x86_64/kernel/pmtimer.c +++ b/arch/x86_64/kernel/pmtimer.c @@ -24,15 +24,6 @@ #include #include #include -/* The I/O port the PMTMR resides at. - * The location is detected during setup_arch(), - * in arch/i386/kernel/acpi/boot.c */ -u32 pmtmr_ioport __read_mostly; - -/* value of the Power timer at last timer interrupt */ -static u32 offset_delay; -static u32 last_pmtmr_tick; - #define ACPI_PM_MASK 0xFFFFFF /* limit it to 24 bits */ static inline u32 cyc2us(u32 cycles) @@ -48,38 +39,6 @@ static inline u32 cyc2us(u32 cycles) return (cycles >> 10); } -int pmtimer_mark_offset(void) -{ - static int first_run = 1; - unsigned long tsc; - u32 lost; - - u32 tick = inl(pmtmr_ioport); - u32 delta; - - delta = cyc2us((tick - last_pmtmr_tick) & ACPI_PM_MASK); - - last_pmtmr_tick = tick; - monotonic_base += delta * NSEC_PER_USEC; - - delta += offset_delay; - - lost = delta / (USEC_PER_SEC / HZ); - offset_delay = delta % (USEC_PER_SEC / HZ); - - rdtscll(tsc); - vxtime.last_tsc = tsc - offset_delay * (u64)cpu_khz / 1000; - - /* don't calculate delay for first run, - or if we've got less then a tick */ - if (first_run || (lost < 1)) { - first_run = 0; - offset_delay = 0; - } - - return lost - 1; -} - static unsigned pmtimer_wait_tick(void) { u32 a, b; @@ -101,23 +60,6 @@ void pmtimer_wait(unsigned us) } while (cyc2us(b - a) < us); } -void pmtimer_resume(void) -{ - last_pmtmr_tick = inl(pmtmr_ioport); -} - -unsigned int do_gettimeoffset_pm(void) -{ - u32 now, offset, delta = 0; - - offset = last_pmtmr_tick; - now = inl(pmtmr_ioport); - delta = (now - offset) & ACPI_PM_MASK; - - return offset_delay + cyc2us(delta); -} - - static int __init nopmtimer_setup(char *s) { pmtmr_ioport = 0; diff --git a/arch/x86_64/kernel/ptrace.c b/arch/x86_64/kernel/ptrace.c index addc14a..4326a69 100644 --- a/arch/x86_64/kernel/ptrace.c +++ b/arch/x86_64/kernel/ptrace.c @@ -536,8 +536,12 @@ #endif } ret = 0; for (ui = 0; ui < sizeof(struct user_regs_struct); ui += sizeof(long)) { - ret |= __get_user(tmp, (unsigned long __user *) data); - putreg(child, ui, tmp); + ret = __get_user(tmp, (unsigned long __user *) data); + if (ret) + break; + ret = putreg(child, ui, tmp); + if (ret) + break; data += sizeof(long); } break; diff --git a/arch/x86_64/kernel/setup.c b/arch/x86_64/kernel/setup.c index af425a8..3d98b69 100644 --- a/arch/x86_64/kernel/setup.c +++ b/arch/x86_64/kernel/setup.c @@ -100,7 +100,7 @@ EXPORT_SYMBOL_GPL(edid_info); extern int root_mountflags; -char command_line[COMMAND_LINE_SIZE]; +char __initdata command_line[COMMAND_LINE_SIZE]; struct resource standard_io_resources[] = { { .name = "dma1", .start = 0x00, .end = 0x1f, @@ -138,128 +138,6 @@ struct resource code_resource = { .flags = IORESOURCE_RAM, }; -#define IORESOURCE_ROM (IORESOURCE_BUSY | IORESOURCE_READONLY | IORESOURCE_MEM) - -static struct resource system_rom_resource = { - .name = "System ROM", - .start = 0xf0000, - .end = 0xfffff, - .flags = IORESOURCE_ROM, -}; - -static struct resource extension_rom_resource = { - .name = "Extension ROM", - .start = 0xe0000, - .end = 0xeffff, - .flags = IORESOURCE_ROM, -}; - -static struct resource adapter_rom_resources[] = { - { .name = "Adapter ROM", .start = 0xc8000, .end = 0, - .flags = IORESOURCE_ROM }, - { .name = "Adapter ROM", .start = 0, .end = 0, - .flags = IORESOURCE_ROM }, - { .name = "Adapter ROM", .start = 0, .end = 0, - .flags = IORESOURCE_ROM }, - { .name = "Adapter ROM", .start = 0, .end = 0, - .flags = IORESOURCE_ROM }, - { .name = "Adapter ROM", .start = 0, .end = 0, - .flags = IORESOURCE_ROM }, - { .name = "Adapter ROM", .start = 0, .end = 0, - .flags = IORESOURCE_ROM } -}; - -static struct resource video_rom_resource = { - .name = "Video ROM", - .start = 0xc0000, - .end = 0xc7fff, - .flags = IORESOURCE_ROM, -}; - -static struct resource video_ram_resource = { - .name = "Video RAM area", - .start = 0xa0000, - .end = 0xbffff, - .flags = IORESOURCE_RAM, -}; - -#define romsignature(x) (*(unsigned short *)(x) == 0xaa55) - -static int __init romchecksum(unsigned char *rom, unsigned long length) -{ - unsigned char *p, sum = 0; - - for (p = rom; p < rom + length; p++) - sum += *p; - return sum == 0; -} - -static void __init probe_roms(void) -{ - unsigned long start, length, upper; - unsigned char *rom; - int i; - - /* video rom */ - upper = adapter_rom_resources[0].start; - for (start = video_rom_resource.start; start < upper; start += 2048) { - rom = isa_bus_to_virt(start); - if (!romsignature(rom)) - continue; - - video_rom_resource.start = start; - - /* 0 < length <= 0x7f * 512, historically */ - length = rom[2] * 512; - - /* if checksum okay, trust length byte */ - if (length && romchecksum(rom, length)) - video_rom_resource.end = start + length - 1; - - request_resource(&iomem_resource, &video_rom_resource); - break; - } - - start = (video_rom_resource.end + 1 + 2047) & ~2047UL; - if (start < upper) - start = upper; - - /* system rom */ - request_resource(&iomem_resource, &system_rom_resource); - upper = system_rom_resource.start; - - /* check for extension rom (ignore length byte!) */ - rom = isa_bus_to_virt(extension_rom_resource.start); - if (romsignature(rom)) { - length = extension_rom_resource.end - extension_rom_resource.start + 1; - if (romchecksum(rom, length)) { - request_resource(&iomem_resource, &extension_rom_resource); - upper = extension_rom_resource.start; - } - } - - /* check for adapter roms on 2k boundaries */ - for (i = 0; i < ARRAY_SIZE(adapter_rom_resources) && start < upper; - start += 2048) { - rom = isa_bus_to_virt(start); - if (!romsignature(rom)) - continue; - - /* 0 < length <= 0x7f * 512, historically */ - length = rom[2] * 512; - - /* but accept any length that fits if checksum okay */ - if (!length || start + length > upper || !romchecksum(rom, length)) - continue; - - adapter_rom_resources[i].start = start; - adapter_rom_resources[i].end = start + length - 1; - request_resource(&iomem_resource, &adapter_rom_resources[i]); - - start = adapter_rom_resources[i++].end & ~2047UL; - } -} - #ifdef CONFIG_PROC_VMCORE /* elfcorehdr= specifies the location of elf core header * stored by the crashed kernel. This option will be passed @@ -343,7 +221,7 @@ static void discover_ebda(void) void __init setup_arch(char **cmdline_p) { - printk(KERN_INFO "Command line: %s\n", saved_command_line); + printk(KERN_INFO "Command line: %s\n", boot_command_line); ROOT_DEV = old_decode_dev(ORIG_ROOT_DEV); screen_info = SCREEN_INFO; @@ -373,7 +251,7 @@ #endif early_identify_cpu(&boot_cpu_data); - strlcpy(command_line, saved_command_line, COMMAND_LINE_SIZE); + strlcpy(command_line, boot_command_line, COMMAND_LINE_SIZE); *cmdline_p = command_line; parse_early_param(); @@ -444,6 +322,11 @@ #endif /* reserve ebda region */ if (ebda_addr) reserve_bootmem_generic(ebda_addr, ebda_size); +#ifdef CONFIG_NUMA + /* reserve nodemap region */ + if (nodemap_addr) + reserve_bootmem_generic(nodemap_addr, nodemap_size); +#endif #ifdef CONFIG_SMP /* @@ -519,15 +402,11 @@ #endif init_apic_mappings(); /* - * Request address space for all standard RAM and ROM resources - * and also for regions reported as reserved by the e820. - */ - probe_roms(); + * We trust e820 completely. No explicit ROM probing in memory. + */ e820_reserve_resources(); e820_mark_nosave_regions(); - request_resource(&iomem_resource, &video_ram_resource); - { unsigned i; /* request I/O space for devices used on all i[345]86 PCs */ @@ -1063,7 +942,8 @@ static int show_cpuinfo(struct seq_file NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, "syscall", NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, "nx", NULL, "mmxext", NULL, - NULL, "fxsr_opt", NULL, "rdtscp", NULL, "lm", "3dnowext", "3dnow", + NULL, "fxsr_opt", "pdpe1gb", "rdtscp", NULL, "lm", + "3dnowext", "3dnow", /* Transmeta-defined */ "recovery", "longrun", NULL, "lrti", NULL, NULL, NULL, NULL, @@ -1081,7 +961,7 @@ static int show_cpuinfo(struct seq_file /* Intel-defined (#2) */ "pni", NULL, NULL, "monitor", "ds_cpl", "vmx", "smx", "est", "tm2", "ssse3", "cid", NULL, NULL, "cx16", "xtpr", NULL, - NULL, NULL, "dca", NULL, NULL, NULL, NULL, NULL, + NULL, NULL, "dca", NULL, NULL, NULL, NULL, "popcnt", NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, /* VIA/Cyrix/Centaur-defined */ @@ -1091,8 +971,10 @@ static int show_cpuinfo(struct seq_file NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, /* AMD-defined (#2) */ - "lahf_lm", "cmp_legacy", "svm", NULL, "cr8_legacy", NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + "lahf_lm", "cmp_legacy", "svm", "extapic", "cr8_legacy", + "altmovcr8", "abm", "sse4a", + "misalignsse", "3dnowprefetch", + "osvw", "ibs", NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, }; @@ -1103,6 +985,9 @@ static int show_cpuinfo(struct seq_file "ttp", /* thermal trip */ "tm", "stc", + "100mhzsteps", + "hwpstate", + NULL, /* tsc invariant mapped to constant_tsc */ NULL, /* nothing */ /* constant_tsc - moved to flags */ }; @@ -1219,23 +1104,3 @@ struct seq_operations cpuinfo_op = { .stop = c_stop, .show = show_cpuinfo, }; - -#if defined(CONFIG_INPUT_PCSPKR) || defined(CONFIG_INPUT_PCSPKR_MODULE) -#include -static __init int add_pcspkr(void) -{ - struct platform_device *pd; - int ret; - - pd = platform_device_alloc("pcspkr", -1); - if (!pd) - return -ENOMEM; - - ret = platform_device_add(pd); - if (ret) - platform_device_put(pd); - - return ret; -} -device_initcall(add_pcspkr); -#endif diff --git a/arch/x86_64/kernel/setup64.c b/arch/x86_64/kernel/setup64.c index 8c4b80f..6a70b55 100644 --- a/arch/x86_64/kernel/setup64.c +++ b/arch/x86_64/kernel/setup64.c @@ -37,7 +37,6 @@ struct desc_ptr idt_descr = { 256 * 16 - char boot_cpu_stack[IRQSTACKSIZE] __attribute__((section(".bss.page_aligned"))); unsigned long __supported_pte_mask __read_mostly = ~0UL; -EXPORT_SYMBOL(__supported_pte_mask); static int do_not_nx __cpuinitdata = 0; /* noexec=on|off diff --git a/arch/x86_64/kernel/smpboot.c b/arch/x86_64/kernel/smpboot.c index daf1933..3544372 100644 --- a/arch/x86_64/kernel/smpboot.c +++ b/arch/x86_64/kernel/smpboot.c @@ -148,217 +148,6 @@ static void __cpuinit smp_store_cpu_info print_cpu_info(c); } -/* - * New Funky TSC sync algorithm borrowed from IA64. - * Main advantage is that it doesn't reset the TSCs fully and - * in general looks more robust and it works better than my earlier - * attempts. I believe it was written by David Mosberger. Some minor - * adjustments for x86-64 by me -AK - * - * Original comment reproduced below. - * - * Synchronize TSC of the current (slave) CPU with the TSC of the - * MASTER CPU (normally the time-keeper CPU). We use a closed loop to - * eliminate the possibility of unaccounted-for errors (such as - * getting a machine check in the middle of a calibration step). The - * basic idea is for the slave to ask the master what itc value it has - * and to read its own itc before and after the master responds. Each - * iteration gives us three timestamps: - * - * slave master - * - * t0 ---\ - * ---\ - * ---> - * tm - * /--- - * /--- - * t1 <--- - * - * - * The goal is to adjust the slave's TSC such that tm falls exactly - * half-way between t0 and t1. If we achieve this, the clocks are - * synchronized provided the interconnect between the slave and the - * master is symmetric. Even if the interconnect were asymmetric, we - * would still know that the synchronization error is smaller than the - * roundtrip latency (t0 - t1). - * - * When the interconnect is quiet and symmetric, this lets us - * synchronize the TSC to within one or two cycles. However, we can - * only *guarantee* that the synchronization is accurate to within a - * round-trip time, which is typically in the range of several hundred - * cycles (e.g., ~500 cycles). In practice, this means that the TSCs - * are usually almost perfectly synchronized, but we shouldn't assume - * that the accuracy is much better than half a micro second or so. - * - * [there are other errors like the latency of RDTSC and of the - * WRMSR. These can also account to hundreds of cycles. So it's - * probably worse. It claims 153 cycles error on a dual Opteron, - * but I suspect the numbers are actually somewhat worse -AK] - */ - -#define MASTER 0 -#define SLAVE (SMP_CACHE_BYTES/8) - -/* Intentionally don't use cpu_relax() while TSC synchronization - because we don't want to go into funky power save modi or cause - hypervisors to schedule us away. Going to sleep would likely affect - latency and low latency is the primary objective here. -AK */ -#define no_cpu_relax() barrier() - -static __cpuinitdata DEFINE_SPINLOCK(tsc_sync_lock); -static volatile __cpuinitdata unsigned long go[SLAVE + 1]; -static int notscsync __cpuinitdata; - -#undef DEBUG_TSC_SYNC - -#define NUM_ROUNDS 64 /* magic value */ -#define NUM_ITERS 5 /* likewise */ - -/* Callback on boot CPU */ -static __cpuinit void sync_master(void *arg) -{ - unsigned long flags, i; - - go[MASTER] = 0; - - local_irq_save(flags); - { - for (i = 0; i < NUM_ROUNDS*NUM_ITERS; ++i) { - while (!go[MASTER]) - no_cpu_relax(); - go[MASTER] = 0; - rdtscll(go[SLAVE]); - } - } - local_irq_restore(flags); -} - -/* - * Return the number of cycles by which our tsc differs from the tsc - * on the master (time-keeper) CPU. A positive number indicates our - * tsc is ahead of the master, negative that it is behind. - */ -static inline long -get_delta(long *rt, long *master) -{ - unsigned long best_t0 = 0, best_t1 = ~0UL, best_tm = 0; - unsigned long tcenter, t0, t1, tm; - int i; - - for (i = 0; i < NUM_ITERS; ++i) { - rdtscll(t0); - go[MASTER] = 1; - while (!(tm = go[SLAVE])) - no_cpu_relax(); - go[SLAVE] = 0; - rdtscll(t1); - - if (t1 - t0 < best_t1 - best_t0) - best_t0 = t0, best_t1 = t1, best_tm = tm; - } - - *rt = best_t1 - best_t0; - *master = best_tm - best_t0; - - /* average best_t0 and best_t1 without overflow: */ - tcenter = (best_t0/2 + best_t1/2); - if (best_t0 % 2 + best_t1 % 2 == 2) - ++tcenter; - return tcenter - best_tm; -} - -static __cpuinit void sync_tsc(unsigned int master) -{ - int i, done = 0; - long delta, adj, adjust_latency = 0; - unsigned long flags, rt, master_time_stamp, bound; -#ifdef DEBUG_TSC_SYNC - static struct syncdebug { - long rt; /* roundtrip time */ - long master; /* master's timestamp */ - long diff; /* difference between midpoint and master's timestamp */ - long lat; /* estimate of tsc adjustment latency */ - } t[NUM_ROUNDS] __cpuinitdata; -#endif - - printk(KERN_INFO "CPU %d: Syncing TSC to CPU %u.\n", - smp_processor_id(), master); - - go[MASTER] = 1; - - /* It is dangerous to broadcast IPI as cpus are coming up, - * as they may not be ready to accept them. So since - * we only need to send the ipi to the boot cpu direct - * the message, and avoid the race. - */ - smp_call_function_single(master, sync_master, NULL, 1, 0); - - while (go[MASTER]) /* wait for master to be ready */ - no_cpu_relax(); - - spin_lock_irqsave(&tsc_sync_lock, flags); - { - for (i = 0; i < NUM_ROUNDS; ++i) { - delta = get_delta(&rt, &master_time_stamp); - if (delta == 0) { - done = 1; /* let's lock on to this... */ - bound = rt; - } - - if (!done) { - unsigned long t; - if (i > 0) { - adjust_latency += -delta; - adj = -delta + adjust_latency/4; - } else - adj = -delta; - - rdtscll(t); - wrmsrl(MSR_IA32_TSC, t + adj); - } -#ifdef DEBUG_TSC_SYNC - t[i].rt = rt; - t[i].master = master_time_stamp; - t[i].diff = delta; - t[i].lat = adjust_latency/4; -#endif - } - } - spin_unlock_irqrestore(&tsc_sync_lock, flags); - -#ifdef DEBUG_TSC_SYNC - for (i = 0; i < NUM_ROUNDS; ++i) - printk("rt=%5ld master=%5ld diff=%5ld adjlat=%5ld\n", - t[i].rt, t[i].master, t[i].diff, t[i].lat); -#endif - - printk(KERN_INFO - "CPU %d: synchronized TSC with CPU %u (last diff %ld cycles, " - "maxerr %lu cycles)\n", - smp_processor_id(), master, delta, rt); -} - -static void __cpuinit tsc_sync_wait(void) -{ - /* - * When the CPU has synchronized TSCs assume the BIOS - * or the hardware already synced. Otherwise we could - * mess up a possible perfect synchronization with a - * not-quite-perfect algorithm. - */ - if (notscsync || !cpu_has_tsc || !unsynchronized_tsc()) - return; - sync_tsc(0); -} - -static __init int notscsync_setup(char *s) -{ - notscsync = 1; - return 1; -} -__setup("notscsync", notscsync_setup); - static atomic_t init_deasserted __cpuinitdata; /* @@ -546,6 +335,11 @@ void __cpuinit start_secondary(void) /* otherwise gcc will move up the smp_processor_id before the cpu_init */ barrier(); + /* + * Check TSC sync first: + */ + check_tsc_sync_target(); + Dprintk("cpu %d: setting up apic clock\n", smp_processor_id()); setup_secondary_APIC_clock(); @@ -565,14 +359,6 @@ void __cpuinit start_secondary(void) */ set_cpu_sibling_map(smp_processor_id()); - /* - * Wait for TSC sync to not schedule things before. - * We still process interrupts, which could see an inconsistent - * time in that window unfortunately. - * Do this here because TSC sync has global unprotected state. - */ - tsc_sync_wait(); - /* * We need to hold call_lock, so there is no inconsistency * between the time smp_call_function() determines number of @@ -592,6 +378,7 @@ void __cpuinit start_secondary(void) cpu_set(smp_processor_id(), cpu_online_map); per_cpu(cpu_state, smp_processor_id()) = CPU_ONLINE; spin_unlock(&vector_lock); + unlock_ipi_call_lock(); cpu_idle(); @@ -1168,6 +955,11 @@ int __cpuinit __cpu_up(unsigned int cpu) /* Unleash the CPU! */ Dprintk("waiting for cpu %d\n", cpu); + /* + * Make sure and check TSC sync: + */ + check_tsc_sync_source(cpu); + while (!cpu_isset(cpu, cpu_online_map)) cpu_relax(); @@ -1190,7 +982,6 @@ void __init smp_cpus_done(unsigned int m smp_cleanup_boot(); setup_ioapic_dest(); check_nmi_watchdog(); - time_init_gtod(); } #ifdef CONFIG_HOTPLUG_CPU diff --git a/arch/x86_64/kernel/stacktrace.c b/arch/x86_64/kernel/stacktrace.c index 6026b31..65ac2c6 100644 --- a/arch/x86_64/kernel/stacktrace.c +++ b/arch/x86_64/kernel/stacktrace.c @@ -32,7 +32,7 @@ static void save_stack_address(void *dat trace->skip--; return; } - if (trace->nr_entries < trace->max_entries - 1) + if (trace->nr_entries < trace->max_entries) trace->entries[trace->nr_entries++] = addr; } @@ -49,7 +49,8 @@ static struct stacktrace_ops save_stack_ void save_stack_trace(struct stack_trace *trace, struct task_struct *task) { dump_trace(task, NULL, NULL, &save_stack_ops, trace); - trace->entries[trace->nr_entries++] = ULONG_MAX; + if (trace->nr_entries < trace->max_entries) + trace->entries[trace->nr_entries++] = ULONG_MAX; } EXPORT_SYMBOL(save_stack_trace); diff --git a/arch/x86_64/kernel/time.c b/arch/x86_64/kernel/time.c index 5cc76d0..a87c517 100644 --- a/arch/x86_64/kernel/time.c +++ b/arch/x86_64/kernel/time.c @@ -42,10 +42,8 @@ #include #include #include #include +#include -#ifdef CONFIG_CPU_FREQ -static void cpufreq_delayed_get(void); -#endif extern void i8254_timer_resume(void); extern int using_apic_timer; @@ -55,128 +53,7 @@ DEFINE_SPINLOCK(rtc_lock); EXPORT_SYMBOL(rtc_lock); DEFINE_SPINLOCK(i8253_lock); -int nohpet __initdata = 0; -static int notsc __initdata = 0; - -#define USEC_PER_TICK (USEC_PER_SEC / HZ) -#define NSEC_PER_TICK (NSEC_PER_SEC / HZ) -#define FSEC_PER_TICK (FSEC_PER_SEC / HZ) - -#define NS_SCALE 10 /* 2^10, carefully chosen */ -#define US_SCALE 32 /* 2^32, arbitralrily chosen */ - -unsigned int cpu_khz; /* TSC clocks / usec, not used here */ -EXPORT_SYMBOL(cpu_khz); -static unsigned long hpet_period; /* fsecs / HPET clock */ -unsigned long hpet_tick; /* HPET clocks / interrupt */ -int hpet_use_timer; /* Use counter of hpet for time keeping, otherwise PIT */ -unsigned long vxtime_hz = PIT_TICK_RATE; -int report_lost_ticks; /* command line option */ -unsigned long long monotonic_base; - -struct vxtime_data __vxtime __section_vxtime; /* for vsyscalls */ - volatile unsigned long __jiffies __section_jiffies = INITIAL_JIFFIES; -struct timespec __xtime __section_xtime; -struct timezone __sys_tz __section_sys_tz; - -/* - * do_gettimeoffset() returns microseconds since last timer interrupt was - * triggered by hardware. A memory read of HPET is slower than a register read - * of TSC, but much more reliable. It's also synchronized to the timer - * interrupt. Note that do_gettimeoffset() may return more than hpet_tick, if a - * timer interrupt has happened already, but vxtime.trigger wasn't updated yet. - * This is not a problem, because jiffies hasn't updated either. They are bound - * together by xtime_lock. - */ - -static inline unsigned int do_gettimeoffset_tsc(void) -{ - unsigned long t; - unsigned long x; - t = get_cycles_sync(); - if (t < vxtime.last_tsc) - t = vxtime.last_tsc; /* hack */ - x = ((t - vxtime.last_tsc) * vxtime.tsc_quot) >> US_SCALE; - return x; -} - -static inline unsigned int do_gettimeoffset_hpet(void) -{ - /* cap counter read to one tick to avoid inconsistencies */ - unsigned long counter = hpet_readl(HPET_COUNTER) - vxtime.last; - return (min(counter,hpet_tick) * vxtime.quot) >> US_SCALE; -} - -unsigned int (*do_gettimeoffset)(void) = do_gettimeoffset_tsc; - -/* - * This version of gettimeofday() has microsecond resolution and better than - * microsecond precision, as we're using at least a 10 MHz (usually 14.31818 - * MHz) HPET timer. - */ - -void do_gettimeofday(struct timeval *tv) -{ - unsigned long seq; - unsigned int sec, usec; - - do { - seq = read_seqbegin(&xtime_lock); - - sec = xtime.tv_sec; - usec = xtime.tv_nsec / NSEC_PER_USEC; - - /* i386 does some correction here to keep the clock - monotonous even when ntpd is fixing drift. - But they didn't work for me, there is a non monotonic - clock anyways with ntp. - I dropped all corrections now until a real solution can - be found. Note when you fix it here you need to do the same - in arch/x86_64/kernel/vsyscall.c and export all needed - variables in vmlinux.lds. -AK */ - usec += do_gettimeoffset(); - - } while (read_seqretry(&xtime_lock, seq)); - - tv->tv_sec = sec + usec / USEC_PER_SEC; - tv->tv_usec = usec % USEC_PER_SEC; -} - -EXPORT_SYMBOL(do_gettimeofday); - -/* - * settimeofday() first undoes the correction that gettimeofday would do - * on the time, and then saves it. This is ugly, but has been like this for - * ages already. - */ - -int do_settimeofday(struct timespec *tv) -{ - time_t wtm_sec, sec = tv->tv_sec; - long wtm_nsec, nsec = tv->tv_nsec; - - if ((unsigned long)tv->tv_nsec >= NSEC_PER_SEC) - return -EINVAL; - - write_seqlock_irq(&xtime_lock); - - nsec -= do_gettimeoffset() * NSEC_PER_USEC; - - wtm_sec = wall_to_monotonic.tv_sec + (xtime.tv_sec - sec); - wtm_nsec = wall_to_monotonic.tv_nsec + (xtime.tv_nsec - nsec); - - set_normalized_timespec(&xtime, sec, nsec); - set_normalized_timespec(&wall_to_monotonic, wtm_sec, wtm_nsec); - - ntp_clear(); - - write_sequnlock_irq(&xtime_lock); - clock_was_set(); - return 0; -} - -EXPORT_SYMBOL(do_settimeofday); unsigned long profile_pc(struct pt_regs *regs) { @@ -267,84 +144,9 @@ static void set_rtc_mmss(unsigned long n } -/* monotonic_clock(): returns # of nanoseconds passed since time_init() - * Note: This function is required to return accurate - * time even in the absence of multiple timer ticks. - */ -static inline unsigned long long cycles_2_ns(unsigned long long cyc); -unsigned long long monotonic_clock(void) -{ - unsigned long seq; - u32 last_offset, this_offset, offset; - unsigned long long base; - - if (vxtime.mode == VXTIME_HPET) { - do { - seq = read_seqbegin(&xtime_lock); - - last_offset = vxtime.last; - base = monotonic_base; - this_offset = hpet_readl(HPET_COUNTER); - } while (read_seqretry(&xtime_lock, seq)); - offset = (this_offset - last_offset); - offset *= NSEC_PER_TICK / hpet_tick; - } else { - do { - seq = read_seqbegin(&xtime_lock); - - last_offset = vxtime.last_tsc; - base = monotonic_base; - } while (read_seqretry(&xtime_lock, seq)); - this_offset = get_cycles_sync(); - offset = cycles_2_ns(this_offset - last_offset); - } - return base + offset; -} -EXPORT_SYMBOL(monotonic_clock); - -static noinline void handle_lost_ticks(int lost) -{ - static long lost_count; - static int warned; - if (report_lost_ticks) { - printk(KERN_WARNING "time.c: Lost %d timer tick(s)! ", lost); - print_symbol("rip %s)\n", get_irq_regs()->rip); - } - - if (lost_count == 1000 && !warned) { - printk(KERN_WARNING "warning: many lost ticks.\n" - KERN_WARNING "Your time source seems to be instable or " - "some driver is hogging interupts\n"); - print_symbol("rip %s\n", get_irq_regs()->rip); - if (vxtime.mode == VXTIME_TSC && vxtime.hpet_address) { - printk(KERN_WARNING "Falling back to HPET\n"); - if (hpet_use_timer) - vxtime.last = hpet_readl(HPET_T0_CMP) - - hpet_tick; - else - vxtime.last = hpet_readl(HPET_COUNTER); - vxtime.mode = VXTIME_HPET; - do_gettimeoffset = do_gettimeoffset_hpet; - } - /* else should fall back to PIT, but code missing. */ - warned = 1; - } else - lost_count++; - -#ifdef CONFIG_CPU_FREQ - /* In some cases the CPU can change frequency without us noticing - Give cpufreq a change to catch up. */ - if ((lost_count+1) % 25 == 0) - cpufreq_delayed_get(); -#endif -} - void main_timer_handler(void) { static unsigned long rtc_update = 0; - unsigned long tsc; - int delay = 0, offset = 0, lost = 0; - /* * Here we are in the timer irq handler. We have irqs locally disabled (so we * don't need spin_lock_irqsave()) but we don't know if the timer_bh is running @@ -354,72 +156,11 @@ void main_timer_handler(void) write_seqlock(&xtime_lock); - if (vxtime.hpet_address) - offset = hpet_readl(HPET_COUNTER); - - if (hpet_use_timer) { - /* if we're using the hpet timer functionality, - * we can more accurately know the counter value - * when the timer interrupt occured. - */ - offset = hpet_readl(HPET_T0_CMP) - hpet_tick; - delay = hpet_readl(HPET_COUNTER) - offset; - } else if (!pmtmr_ioport) { - spin_lock(&i8253_lock); - outb_p(0x00, 0x43); - delay = inb_p(0x40); - delay |= inb(0x40) << 8; - spin_unlock(&i8253_lock); - delay = LATCH - 1 - delay; - } - - tsc = get_cycles_sync(); - - if (vxtime.mode == VXTIME_HPET) { - if (offset - vxtime.last > hpet_tick) { - lost = (offset - vxtime.last) / hpet_tick - 1; - } - - monotonic_base += - (offset - vxtime.last) * NSEC_PER_TICK / hpet_tick; - - vxtime.last = offset; -#ifdef CONFIG_X86_PM_TIMER - } else if (vxtime.mode == VXTIME_PMTMR) { - lost = pmtimer_mark_offset(); -#endif - } else { - offset = (((tsc - vxtime.last_tsc) * - vxtime.tsc_quot) >> US_SCALE) - USEC_PER_TICK; - - if (offset < 0) - offset = 0; - - if (offset > USEC_PER_TICK) { - lost = offset / USEC_PER_TICK; - offset %= USEC_PER_TICK; - } - - monotonic_base += cycles_2_ns(tsc - vxtime.last_tsc); - - vxtime.last_tsc = tsc - vxtime.quot * delay / vxtime.tsc_quot; - - if ((((tsc - vxtime.last_tsc) * - vxtime.tsc_quot) >> US_SCALE) < offset) - vxtime.last_tsc = tsc - - (((long) offset << US_SCALE) / vxtime.tsc_quot) - 1; - } - - if (lost > 0) - handle_lost_ticks(lost); - else - lost = 0; - /* * Do the timer stuff. */ - do_timer(lost + 1); + do_timer(1); #ifndef CONFIG_SMP update_process_times(user_mode(get_irq_regs())); #endif @@ -460,45 +201,11 @@ static irqreturn_t timer_interrupt(int i return IRQ_HANDLED; } -static unsigned int cyc2ns_scale __read_mostly; - -static inline void set_cyc2ns_scale(unsigned long cpu_khz) -{ - cyc2ns_scale = (NSEC_PER_MSEC << NS_SCALE) / cpu_khz; -} - -static inline unsigned long long cycles_2_ns(unsigned long long cyc) -{ - return (cyc * cyc2ns_scale) >> NS_SCALE; -} - -unsigned long long sched_clock(void) -{ - unsigned long a = 0; - -#if 0 - /* Don't do a HPET read here. Using TSC always is much faster - and HPET may not be mapped yet when the scheduler first runs. - Disadvantage is a small drift between CPUs in some configurations, - but that should be tolerable. */ - if (__vxtime.mode == VXTIME_HPET) - return (hpet_readl(HPET_COUNTER) * vxtime.quot) >> US_SCALE; -#endif - - /* Could do CPU core sync here. Opteron can execute rdtsc speculatively, - which means it is not completely exact and may not be monotonous between - CPUs. But the errors should be too small to matter for scheduling - purposes. */ - - rdtscll(a); - return cycles_2_ns(a); -} - static unsigned long get_cmos_time(void) { unsigned int year, mon, day, hour, min, sec; unsigned long flags; - unsigned extyear = 0; + unsigned century = 0; spin_lock_irqsave(&rtc_lock, flags); @@ -510,9 +217,9 @@ static unsigned long get_cmos_time(void) mon = CMOS_READ(RTC_MONTH); year = CMOS_READ(RTC_YEAR); #ifdef CONFIG_ACPI - if (acpi_fadt.revision >= FADT2_REVISION_ID && - acpi_fadt.century) - extyear = CMOS_READ(acpi_fadt.century); + if (acpi_gbl_FADT.header.revision >= FADT2_REVISION_ID && + acpi_gbl_FADT.century) + century = CMOS_READ(acpi_gbl_FADT.century); #endif } while (sec != CMOS_READ(RTC_SECONDS)); @@ -530,10 +237,10 @@ #endif BCD_TO_BIN(mon); BCD_TO_BIN(year); - if (extyear) { - BCD_TO_BIN(extyear); - year += extyear; - printk(KERN_INFO "Extended CMOS year: %d\n", extyear); + if (century) { + BCD_TO_BIN(century); + year += century * 100; + printk(KERN_INFO "Extended CMOS year: %d\n", century * 100); } else { /* * x86-64 systems only exists since 2002. @@ -545,159 +252,6 @@ #endif return mktime(year, mon, day, hour, min, sec); } -#ifdef CONFIG_CPU_FREQ - -/* Frequency scaling support. Adjust the TSC based timer when the cpu frequency - changes. - - RED-PEN: On SMP we assume all CPUs run with the same frequency. It's - not that important because current Opteron setups do not support - scaling on SMP anyroads. - - Should fix up last_tsc too. Currently gettimeofday in the - first tick after the change will be slightly wrong. */ - -#include - -static unsigned int cpufreq_delayed_issched = 0; -static unsigned int cpufreq_init = 0; -static struct work_struct cpufreq_delayed_get_work; - -static void handle_cpufreq_delayed_get(struct work_struct *v) -{ - unsigned int cpu; - for_each_online_cpu(cpu) { - cpufreq_get(cpu); - } - cpufreq_delayed_issched = 0; -} - -/* if we notice lost ticks, schedule a call to cpufreq_get() as it tries - * to verify the CPU frequency the timing core thinks the CPU is running - * at is still correct. - */ -static void cpufreq_delayed_get(void) -{ - static int warned; - if (cpufreq_init && !cpufreq_delayed_issched) { - cpufreq_delayed_issched = 1; - if (!warned) { - warned = 1; - printk(KERN_DEBUG - "Losing some ticks... checking if CPU frequency changed.\n"); - } - schedule_work(&cpufreq_delayed_get_work); - } -} - -static unsigned int ref_freq = 0; -static unsigned long loops_per_jiffy_ref = 0; - -static unsigned long cpu_khz_ref = 0; - -static int time_cpufreq_notifier(struct notifier_block *nb, unsigned long val, - void *data) -{ - struct cpufreq_freqs *freq = data; - unsigned long *lpj, dummy; - - if (cpu_has(&cpu_data[freq->cpu], X86_FEATURE_CONSTANT_TSC)) - return 0; - - lpj = &dummy; - if (!(freq->flags & CPUFREQ_CONST_LOOPS)) -#ifdef CONFIG_SMP - lpj = &cpu_data[freq->cpu].loops_per_jiffy; -#else - lpj = &boot_cpu_data.loops_per_jiffy; -#endif - - if (!ref_freq) { - ref_freq = freq->old; - loops_per_jiffy_ref = *lpj; - cpu_khz_ref = cpu_khz; - } - if ((val == CPUFREQ_PRECHANGE && freq->old < freq->new) || - (val == CPUFREQ_POSTCHANGE && freq->old > freq->new) || - (val == CPUFREQ_RESUMECHANGE)) { - *lpj = - cpufreq_scale(loops_per_jiffy_ref, ref_freq, freq->new); - - cpu_khz = cpufreq_scale(cpu_khz_ref, ref_freq, freq->new); - if (!(freq->flags & CPUFREQ_CONST_LOOPS)) - vxtime.tsc_quot = (USEC_PER_MSEC << US_SCALE) / cpu_khz; - } - - set_cyc2ns_scale(cpu_khz_ref); - - return 0; -} - -static struct notifier_block time_cpufreq_notifier_block = { - .notifier_call = time_cpufreq_notifier -}; - -static int __init cpufreq_tsc(void) -{ - INIT_WORK(&cpufreq_delayed_get_work, handle_cpufreq_delayed_get); - if (!cpufreq_register_notifier(&time_cpufreq_notifier_block, - CPUFREQ_TRANSITION_NOTIFIER)) - cpufreq_init = 1; - return 0; -} - -core_initcall(cpufreq_tsc); - -#endif - -/* - * calibrate_tsc() calibrates the processor TSC in a very simple way, comparing - * it to the HPET timer of known frequency. - */ - -#define TICK_COUNT 100000000 -#define TICK_MIN 5000 - -/* - * Some platforms take periodic SMI interrupts with 5ms duration. Make sure none - * occurs between the reads of the hpet & TSC. - */ -static void __init read_hpet_tsc(int *hpet, int *tsc) -{ - int tsc1, tsc2, hpet1; - - do { - tsc1 = get_cycles_sync(); - hpet1 = hpet_readl(HPET_COUNTER); - tsc2 = get_cycles_sync(); - } while (tsc2 - tsc1 > TICK_MIN); - *hpet = hpet1; - *tsc = tsc2; -} - - -static unsigned int __init hpet_calibrate_tsc(void) -{ - int tsc_start, hpet_start; - int tsc_now, hpet_now; - unsigned long flags; - - local_irq_save(flags); - local_irq_disable(); - - read_hpet_tsc(&hpet_start, &tsc_start); - - do { - local_irq_disable(); - read_hpet_tsc(&hpet_now, &tsc_now); - local_irq_restore(flags); - } while ((tsc_now - tsc_start) < TICK_COUNT && - (hpet_now - hpet_start) < TICK_COUNT); - - return (tsc_now - tsc_start) * 1000000000L - / ((hpet_now - hpet_start) * hpet_period / 1000); -} - /* * pit_calibrate_tsc() uses the speaker output (channel 2) of @@ -728,124 +282,6 @@ static unsigned int __init pit_calibrate return (end - start) / 50; } -#ifdef CONFIG_HPET -static __init int late_hpet_init(void) -{ - struct hpet_data hd; - unsigned int ntimer; - - if (!vxtime.hpet_address) - return 0; - - memset(&hd, 0, sizeof (hd)); - - ntimer = hpet_readl(HPET_ID); - ntimer = (ntimer & HPET_ID_NUMBER) >> HPET_ID_NUMBER_SHIFT; - ntimer++; - - /* - * Register with driver. - * Timer0 and Timer1 is used by platform. - */ - hd.hd_phys_address = vxtime.hpet_address; - hd.hd_address = (void __iomem *)fix_to_virt(FIX_HPET_BASE); - hd.hd_nirqs = ntimer; - hd.hd_flags = HPET_DATA_PLATFORM; - hpet_reserve_timer(&hd, 0); -#ifdef CONFIG_HPET_EMULATE_RTC - hpet_reserve_timer(&hd, 1); -#endif - hd.hd_irq[0] = HPET_LEGACY_8254; - hd.hd_irq[1] = HPET_LEGACY_RTC; - if (ntimer > 2) { - struct hpet *hpet; - struct hpet_timer *timer; - int i; - - hpet = (struct hpet *) fix_to_virt(FIX_HPET_BASE); - timer = &hpet->hpet_timers[2]; - for (i = 2; i < ntimer; timer++, i++) - hd.hd_irq[i] = (timer->hpet_config & - Tn_INT_ROUTE_CNF_MASK) >> - Tn_INT_ROUTE_CNF_SHIFT; - - } - - hpet_alloc(&hd); - return 0; -} -fs_initcall(late_hpet_init); -#endif - -static int hpet_timer_stop_set_go(unsigned long tick) -{ - unsigned int cfg; - -/* - * Stop the timers and reset the main counter. - */ - - cfg = hpet_readl(HPET_CFG); - cfg &= ~(HPET_CFG_ENABLE | HPET_CFG_LEGACY); - hpet_writel(cfg, HPET_CFG); - hpet_writel(0, HPET_COUNTER); - hpet_writel(0, HPET_COUNTER + 4); - -/* - * Set up timer 0, as periodic with first interrupt to happen at hpet_tick, - * and period also hpet_tick. - */ - if (hpet_use_timer) { - hpet_writel(HPET_TN_ENABLE | HPET_TN_PERIODIC | HPET_TN_SETVAL | - HPET_TN_32BIT, HPET_T0_CFG); - hpet_writel(hpet_tick, HPET_T0_CMP); /* next interrupt */ - hpet_writel(hpet_tick, HPET_T0_CMP); /* period */ - cfg |= HPET_CFG_LEGACY; - } -/* - * Go! - */ - - cfg |= HPET_CFG_ENABLE; - hpet_writel(cfg, HPET_CFG); - - return 0; -} - -static int hpet_init(void) -{ - unsigned int id; - - if (!vxtime.hpet_address) - return -1; - set_fixmap_nocache(FIX_HPET_BASE, vxtime.hpet_address); - __set_fixmap(VSYSCALL_HPET, vxtime.hpet_address, PAGE_KERNEL_VSYSCALL_NOCACHE); - -/* - * Read the period, compute tick and quotient. - */ - - id = hpet_readl(HPET_ID); - - if (!(id & HPET_ID_VENDOR) || !(id & HPET_ID_NUMBER)) - return -1; - - hpet_period = hpet_readl(HPET_PERIOD); - if (hpet_period < 100000 || hpet_period > 100000000) - return -1; - - hpet_tick = (FSEC_PER_TICK + hpet_period / 2) / hpet_period; - - hpet_use_timer = (id & HPET_ID_LEGSUP); - - return hpet_timer_stop_set_go(hpet_tick); -} - -static int hpet_reenable(void) -{ - return hpet_timer_stop_set_go(hpet_tick); -} - #define PIT_MODE 0x43 #define PIT_CH0 0x40 @@ -873,7 +309,7 @@ void __init pit_stop_interrupt(void) void __init stop_timer_interrupt(void) { char *name; - if (vxtime.hpet_address) { + if (hpet_address) { name = "HPET"; hpet_timer_stop_set_go(0); } else { @@ -883,12 +319,6 @@ void __init stop_timer_interrupt(void) printk(KERN_INFO "timer: %s interrupt stopped.\n", name); } -int __init time_setup(char *str) -{ - report_lost_ticks = 1; - return 1; -} - static struct irqaction irq0 = { timer_interrupt, IRQF_DISABLED, CPU_MASK_NONE, "timer", NULL, NULL }; @@ -896,124 +326,41 @@ static struct irqaction irq0 = { void __init time_init(void) { if (nohpet) - vxtime.hpet_address = 0; - + hpet_address = 0; xtime.tv_sec = get_cmos_time(); xtime.tv_nsec = 0; set_normalized_timespec(&wall_to_monotonic, -xtime.tv_sec, -xtime.tv_nsec); - if (!hpet_init()) - vxtime_hz = (FSEC_PER_SEC + hpet_period / 2) / hpet_period; - else - vxtime.hpet_address = 0; + if (hpet_arch_init()) + hpet_address = 0; if (hpet_use_timer) { /* set tick_nsec to use the proper rate for HPET */ tick_nsec = TICK_NSEC_HPET; cpu_khz = hpet_calibrate_tsc(); timename = "HPET"; -#ifdef CONFIG_X86_PM_TIMER - } else if (pmtmr_ioport && !vxtime.hpet_address) { - vxtime_hz = PM_TIMER_FREQUENCY; - timename = "PM"; - pit_init(); - cpu_khz = pit_calibrate_tsc(); -#endif } else { pit_init(); cpu_khz = pit_calibrate_tsc(); timename = "PIT"; } - vxtime.mode = VXTIME_TSC; - vxtime.quot = (USEC_PER_SEC << US_SCALE) / vxtime_hz; - vxtime.tsc_quot = (USEC_PER_MSEC << US_SCALE) / cpu_khz; - vxtime.last_tsc = get_cycles_sync(); - set_cyc2ns_scale(cpu_khz); - setup_irq(0, &irq0); - -#ifndef CONFIG_SMP - time_init_gtod(); -#endif -} - -/* - * Make an educated guess if the TSC is trustworthy and synchronized - * over all CPUs. - */ -__cpuinit int unsynchronized_tsc(void) -{ -#ifdef CONFIG_SMP - if (apic_is_clustered_box()) - return 1; -#endif - /* Most intel systems have synchronized TSCs except for - multi node systems */ - if (boot_cpu_data.x86_vendor == X86_VENDOR_INTEL) { -#ifdef CONFIG_ACPI - /* But TSC doesn't tick in C3 so don't use it there */ - if (acpi_fadt.length > 0 && acpi_fadt.plvl3_lat < 1000) - return 1; -#endif - return 0; - } - - /* Assume multi socket systems are not synchronized */ - return num_present_cpus() > 1; -} - -/* - * Decide what mode gettimeofday should use. - */ -void time_init_gtod(void) -{ - char *timetype; - if (unsynchronized_tsc()) - notsc = 1; + mark_tsc_unstable(); - if (cpu_has(&boot_cpu_data, X86_FEATURE_RDTSCP)) + if (cpu_has(&boot_cpu_data, X86_FEATURE_RDTSCP)) vgetcpu_mode = VGETCPU_RDTSCP; else vgetcpu_mode = VGETCPU_LSL; - if (vxtime.hpet_address && notsc) { - timetype = hpet_use_timer ? "HPET" : "PIT/HPET"; - if (hpet_use_timer) - vxtime.last = hpet_readl(HPET_T0_CMP) - hpet_tick; - else - vxtime.last = hpet_readl(HPET_COUNTER); - vxtime.mode = VXTIME_HPET; - do_gettimeoffset = do_gettimeoffset_hpet; -#ifdef CONFIG_X86_PM_TIMER - /* Using PM for gettimeofday is quite slow, but we have no other - choice because the TSC is too unreliable on some systems. */ - } else if (pmtmr_ioport && !vxtime.hpet_address && notsc) { - timetype = "PM"; - do_gettimeoffset = do_gettimeoffset_pm; - vxtime.mode = VXTIME_PMTMR; - sysctl_vsyscall = 0; - printk(KERN_INFO "Disabling vsyscall due to use of PM timer\n"); -#endif - } else { - timetype = hpet_use_timer ? "HPET/TSC" : "PIT/TSC"; - vxtime.mode = VXTIME_TSC; - } - - printk(KERN_INFO "time.c: Using %ld.%06ld MHz WALL %s GTOD %s timer.\n", - vxtime_hz / 1000000, vxtime_hz % 1000000, timename, timetype); + set_cyc2ns_scale(cpu_khz); printk(KERN_INFO "time.c: Detected %d.%03d MHz processor.\n", cpu_khz / 1000, cpu_khz % 1000); - vxtime.quot = (USEC_PER_SEC << US_SCALE) / vxtime_hz; - vxtime.tsc_quot = (USEC_PER_MSEC << US_SCALE) / cpu_khz; - vxtime.last_tsc = get_cycles_sync(); - - set_cyc2ns_scale(cpu_khz); + setup_irq(0, &irq0); } -__setup("report_lost_ticks", time_setup); static long clock_cmos_diff; static unsigned long sleep_start; @@ -1050,7 +397,7 @@ static int timer_resume(struct sys_devic sleep_length = 0; ctime = sleep_start; } - if (vxtime.hpet_address) + if (hpet_address) hpet_reenable(); else i8254_timer_resume(); @@ -1059,20 +406,8 @@ static int timer_resume(struct sys_devic write_seqlock_irqsave(&xtime_lock,flags); xtime.tv_sec = sec; xtime.tv_nsec = 0; - if (vxtime.mode == VXTIME_HPET) { - if (hpet_use_timer) - vxtime.last = hpet_readl(HPET_T0_CMP) - hpet_tick; - else - vxtime.last = hpet_readl(HPET_COUNTER); -#ifdef CONFIG_X86_PM_TIMER - } else if (vxtime.mode == VXTIME_PMTMR) { - pmtimer_resume(); -#endif - } else - vxtime.last_tsc = get_cycles_sync(); - write_sequnlock_irqrestore(&xtime_lock,flags); jiffies += sleep_length; - monotonic_base += sleep_length * (NSEC_PER_SEC/HZ); + write_sequnlock_irqrestore(&xtime_lock,flags); touch_softlockup_watchdog(); return 0; } @@ -1098,269 +433,3 @@ static int time_init_device(void) } device_initcall(time_init_device); - -#ifdef CONFIG_HPET_EMULATE_RTC -/* HPET in LegacyReplacement Mode eats up RTC interrupt line. When, HPET - * is enabled, we support RTC interrupt functionality in software. - * RTC has 3 kinds of interrupts: - * 1) Update Interrupt - generate an interrupt, every sec, when RTC clock - * is updated - * 2) Alarm Interrupt - generate an interrupt at a specific time of day - * 3) Periodic Interrupt - generate periodic interrupt, with frequencies - * 2Hz-8192Hz (2Hz-64Hz for non-root user) (all freqs in powers of 2) - * (1) and (2) above are implemented using polling at a frequency of - * 64 Hz. The exact frequency is a tradeoff between accuracy and interrupt - * overhead. (DEFAULT_RTC_INT_FREQ) - * For (3), we use interrupts at 64Hz or user specified periodic - * frequency, whichever is higher. - */ -#include - -#define DEFAULT_RTC_INT_FREQ 64 -#define RTC_NUM_INTS 1 - -static unsigned long UIE_on; -static unsigned long prev_update_sec; - -static unsigned long AIE_on; -static struct rtc_time alarm_time; - -static unsigned long PIE_on; -static unsigned long PIE_freq = DEFAULT_RTC_INT_FREQ; -static unsigned long PIE_count; - -static unsigned long hpet_rtc_int_freq; /* RTC interrupt frequency */ -static unsigned int hpet_t1_cmp; /* cached comparator register */ - -int is_hpet_enabled(void) -{ - return vxtime.hpet_address != 0; -} - -/* - * Timer 1 for RTC, we do not use periodic interrupt feature, - * even if HPET supports periodic interrupts on Timer 1. - * The reason being, to set up a periodic interrupt in HPET, we need to - * stop the main counter. And if we do that everytime someone diables/enables - * RTC, we will have adverse effect on main kernel timer running on Timer 0. - * So, for the time being, simulate the periodic interrupt in software. - * - * hpet_rtc_timer_init() is called for the first time and during subsequent - * interuppts reinit happens through hpet_rtc_timer_reinit(). - */ -int hpet_rtc_timer_init(void) -{ - unsigned int cfg, cnt; - unsigned long flags; - - if (!is_hpet_enabled()) - return 0; - /* - * Set the counter 1 and enable the interrupts. - */ - if (PIE_on && (PIE_freq > DEFAULT_RTC_INT_FREQ)) - hpet_rtc_int_freq = PIE_freq; - else - hpet_rtc_int_freq = DEFAULT_RTC_INT_FREQ; - - local_irq_save(flags); - - cnt = hpet_readl(HPET_COUNTER); - cnt += ((hpet_tick*HZ)/hpet_rtc_int_freq); - hpet_writel(cnt, HPET_T1_CMP); - hpet_t1_cmp = cnt; - - cfg = hpet_readl(HPET_T1_CFG); - cfg &= ~HPET_TN_PERIODIC; - cfg |= HPET_TN_ENABLE | HPET_TN_32BIT; - hpet_writel(cfg, HPET_T1_CFG); - - local_irq_restore(flags); - - return 1; -} - -static void hpet_rtc_timer_reinit(void) -{ - unsigned int cfg, cnt, ticks_per_int, lost_ints; - - if (unlikely(!(PIE_on | AIE_on | UIE_on))) { - cfg = hpet_readl(HPET_T1_CFG); - cfg &= ~HPET_TN_ENABLE; - hpet_writel(cfg, HPET_T1_CFG); - return; - } - - if (PIE_on && (PIE_freq > DEFAULT_RTC_INT_FREQ)) - hpet_rtc_int_freq = PIE_freq; - else - hpet_rtc_int_freq = DEFAULT_RTC_INT_FREQ; - - /* It is more accurate to use the comparator value than current count.*/ - ticks_per_int = hpet_tick * HZ / hpet_rtc_int_freq; - hpet_t1_cmp += ticks_per_int; - hpet_writel(hpet_t1_cmp, HPET_T1_CMP); - - /* - * If the interrupt handler was delayed too long, the write above tries - * to schedule the next interrupt in the past and the hardware would - * not interrupt until the counter had wrapped around. - * So we have to check that the comparator wasn't set to a past time. - */ - cnt = hpet_readl(HPET_COUNTER); - if (unlikely((int)(cnt - hpet_t1_cmp) > 0)) { - lost_ints = (cnt - hpet_t1_cmp) / ticks_per_int + 1; - /* Make sure that, even with the time needed to execute - * this code, the next scheduled interrupt has been moved - * back to the future: */ - lost_ints++; - - hpet_t1_cmp += lost_ints * ticks_per_int; - hpet_writel(hpet_t1_cmp, HPET_T1_CMP); - - if (PIE_on) - PIE_count += lost_ints; - - printk(KERN_WARNING "rtc: lost some interrupts at %ldHz.\n", - hpet_rtc_int_freq); - } -} - -/* - * The functions below are called from rtc driver. - * Return 0 if HPET is not being used. - * Otherwise do the necessary changes and return 1. - */ -int hpet_mask_rtc_irq_bit(unsigned long bit_mask) -{ - if (!is_hpet_enabled()) - return 0; - - if (bit_mask & RTC_UIE) - UIE_on = 0; - if (bit_mask & RTC_PIE) - PIE_on = 0; - if (bit_mask & RTC_AIE) - AIE_on = 0; - - return 1; -} - -int hpet_set_rtc_irq_bit(unsigned long bit_mask) -{ - int timer_init_reqd = 0; - - if (!is_hpet_enabled()) - return 0; - - if (!(PIE_on | AIE_on | UIE_on)) - timer_init_reqd = 1; - - if (bit_mask & RTC_UIE) { - UIE_on = 1; - } - if (bit_mask & RTC_PIE) { - PIE_on = 1; - PIE_count = 0; - } - if (bit_mask & RTC_AIE) { - AIE_on = 1; - } - - if (timer_init_reqd) - hpet_rtc_timer_init(); - - return 1; -} - -int hpet_set_alarm_time(unsigned char hrs, unsigned char min, unsigned char sec) -{ - if (!is_hpet_enabled()) - return 0; - - alarm_time.tm_hour = hrs; - alarm_time.tm_min = min; - alarm_time.tm_sec = sec; - - return 1; -} - -int hpet_set_periodic_freq(unsigned long freq) -{ - if (!is_hpet_enabled()) - return 0; - - PIE_freq = freq; - PIE_count = 0; - - return 1; -} - -int hpet_rtc_dropped_irq(void) -{ - if (!is_hpet_enabled()) - return 0; - - return 1; -} - -irqreturn_t hpet_rtc_interrupt(int irq, void *dev_id, struct pt_regs *regs) -{ - struct rtc_time curr_time; - unsigned long rtc_int_flag = 0; - int call_rtc_interrupt = 0; - - hpet_rtc_timer_reinit(); - - if (UIE_on | AIE_on) { - rtc_get_rtc_time(&curr_time); - } - if (UIE_on) { - if (curr_time.tm_sec != prev_update_sec) { - /* Set update int info, call real rtc int routine */ - call_rtc_interrupt = 1; - rtc_int_flag = RTC_UF; - prev_update_sec = curr_time.tm_sec; - } - } - if (PIE_on) { - PIE_count++; - if (PIE_count >= hpet_rtc_int_freq/PIE_freq) { - /* Set periodic int info, call real rtc int routine */ - call_rtc_interrupt = 1; - rtc_int_flag |= RTC_PF; - PIE_count = 0; - } - } - if (AIE_on) { - if ((curr_time.tm_sec == alarm_time.tm_sec) && - (curr_time.tm_min == alarm_time.tm_min) && - (curr_time.tm_hour == alarm_time.tm_hour)) { - /* Set alarm int info, call real rtc int routine */ - call_rtc_interrupt = 1; - rtc_int_flag |= RTC_AF; - } - } - if (call_rtc_interrupt) { - rtc_int_flag |= (RTC_IRQF | (RTC_NUM_INTS << 8)); - rtc_interrupt(rtc_int_flag, dev_id); - } - return IRQ_HANDLED; -} -#endif - -static int __init nohpet_setup(char *s) -{ - nohpet = 1; - return 1; -} - -__setup("nohpet", nohpet_setup); - -int __init notsc_setup(char *s) -{ - notsc = 1; - return 1; -} - -__setup("notsc", notsc_setup); diff --git a/arch/x86_64/kernel/tsc.c b/arch/x86_64/kernel/tsc.c new file mode 100644 index 0000000..8958318 --- /dev/null +++ b/arch/x86_64/kernel/tsc.c @@ -0,0 +1,226 @@ +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +static int notsc __initdata = 0; + +unsigned int cpu_khz; /* TSC clocks / usec, not used here */ +EXPORT_SYMBOL(cpu_khz); + +static unsigned int cyc2ns_scale __read_mostly; + +void set_cyc2ns_scale(unsigned long khz) +{ + cyc2ns_scale = (NSEC_PER_MSEC << NS_SCALE) / khz; +} + +static unsigned long long cycles_2_ns(unsigned long long cyc) +{ + return (cyc * cyc2ns_scale) >> NS_SCALE; +} + +unsigned long long sched_clock(void) +{ + unsigned long a = 0; + + /* Could do CPU core sync here. Opteron can execute rdtsc speculatively, + * which means it is not completely exact and may not be monotonous + * between CPUs. But the errors should be too small to matter for + * scheduling purposes. + */ + + rdtscll(a); + return cycles_2_ns(a); +} + +static int tsc_unstable; + +static inline int check_tsc_unstable(void) +{ + return tsc_unstable; +} +#ifdef CONFIG_CPU_FREQ + +/* Frequency scaling support. Adjust the TSC based timer when the cpu frequency + * changes. + * + * RED-PEN: On SMP we assume all CPUs run with the same frequency. It's + * not that important because current Opteron setups do not support + * scaling on SMP anyroads. + * + * Should fix up last_tsc too. Currently gettimeofday in the + * first tick after the change will be slightly wrong. + */ + +#include + +static unsigned int cpufreq_delayed_issched = 0; +static unsigned int cpufreq_init = 0; +static struct work_struct cpufreq_delayed_get_work; + +static void handle_cpufreq_delayed_get(struct work_struct *v) +{ + unsigned int cpu; + for_each_online_cpu(cpu) { + cpufreq_get(cpu); + } + cpufreq_delayed_issched = 0; +} + +static unsigned int ref_freq = 0; +static unsigned long loops_per_jiffy_ref = 0; + +static unsigned long cpu_khz_ref = 0; + +static int time_cpufreq_notifier(struct notifier_block *nb, unsigned long val, + void *data) +{ + struct cpufreq_freqs *freq = data; + unsigned long *lpj, dummy; + + if (cpu_has(&cpu_data[freq->cpu], X86_FEATURE_CONSTANT_TSC)) + return 0; + + lpj = &dummy; + if (!(freq->flags & CPUFREQ_CONST_LOOPS)) +#ifdef CONFIG_SMP + lpj = &cpu_data[freq->cpu].loops_per_jiffy; +#else + lpj = &boot_cpu_data.loops_per_jiffy; +#endif + + if (!ref_freq) { + ref_freq = freq->old; + loops_per_jiffy_ref = *lpj; + cpu_khz_ref = cpu_khz; + } + if ((val == CPUFREQ_PRECHANGE && freq->old < freq->new) || + (val == CPUFREQ_POSTCHANGE && freq->old > freq->new) || + (val == CPUFREQ_RESUMECHANGE)) { + *lpj = + cpufreq_scale(loops_per_jiffy_ref, ref_freq, freq->new); + + cpu_khz = cpufreq_scale(cpu_khz_ref, ref_freq, freq->new); + if (!(freq->flags & CPUFREQ_CONST_LOOPS)) + mark_tsc_unstable(); + } + + set_cyc2ns_scale(cpu_khz_ref); + + return 0; +} + +static struct notifier_block time_cpufreq_notifier_block = { + .notifier_call = time_cpufreq_notifier +}; + +static int __init cpufreq_tsc(void) +{ + INIT_WORK(&cpufreq_delayed_get_work, handle_cpufreq_delayed_get); + if (!cpufreq_register_notifier(&time_cpufreq_notifier_block, + CPUFREQ_TRANSITION_NOTIFIER)) + cpufreq_init = 1; + return 0; +} + +core_initcall(cpufreq_tsc); + +#endif + +static int tsc_unstable = 0; + +/* + * Make an educated guess if the TSC is trustworthy and synchronized + * over all CPUs. + */ +__cpuinit int unsynchronized_tsc(void) +{ + if (tsc_unstable) + return 1; + +#ifdef CONFIG_SMP + if (apic_is_clustered_box()) + return 1; +#endif + /* Most intel systems have synchronized TSCs except for + multi node systems */ + if (boot_cpu_data.x86_vendor == X86_VENDOR_INTEL) { +#ifdef CONFIG_ACPI + /* But TSC doesn't tick in C3 so don't use it there */ + if (acpi_gbl_FADT.header.length > 0 && acpi_gbl_FADT.C3latency < 1000) + return 1; +#endif + return 0; + } + + /* Assume multi socket systems are not synchronized */ + return num_present_cpus() > 1; +} + +int __init notsc_setup(char *s) +{ + notsc = 1; + return 1; +} + +__setup("notsc", notsc_setup); + + +/* clock source code: */ +static cycle_t read_tsc(void) +{ + cycle_t ret = (cycle_t)get_cycles_sync(); + return ret; +} + +static cycle_t __vsyscall_fn vread_tsc(void) +{ + cycle_t ret = (cycle_t)get_cycles_sync(); + return ret; +} + +static struct clocksource clocksource_tsc = { + .name = "tsc", + .rating = 300, + .read = read_tsc, + .mask = CLOCKSOURCE_MASK(64), + .shift = 22, + .flags = CLOCK_SOURCE_IS_CONTINUOUS | + CLOCK_SOURCE_MUST_VERIFY, + .vread = vread_tsc, +}; + +void mark_tsc_unstable(void) +{ + if (!tsc_unstable) { + tsc_unstable = 1; + /* Change only the rating, when not registered */ + if (clocksource_tsc.mult) + clocksource_change_rating(&clocksource_tsc, 0); + else + clocksource_tsc.rating = 0; + } +} +EXPORT_SYMBOL_GPL(mark_tsc_unstable); + +static int __init init_tsc_clocksource(void) +{ + if (!notsc) { + clocksource_tsc.mult = clocksource_khz2mult(cpu_khz, + clocksource_tsc.shift); + if (check_tsc_unstable()) + clocksource_tsc.rating = 0; + + return clocksource_register(&clocksource_tsc); + } + return 0; +} + +module_init(init_tsc_clocksource); diff --git a/arch/x86_64/kernel/tsc_sync.c b/arch/x86_64/kernel/tsc_sync.c new file mode 100644 index 0000000..014f0db --- /dev/null +++ b/arch/x86_64/kernel/tsc_sync.c @@ -0,0 +1,187 @@ +/* + * arch/x86_64/kernel/tsc_sync.c: check TSC synchronization. + * + * Copyright (C) 2006, Red Hat, Inc., Ingo Molnar + * + * We check whether all boot CPUs have their TSC's synchronized, + * print a warning if not and turn off the TSC clock-source. + * + * The warp-check is point-to-point between two CPUs, the CPU + * initiating the bootup is the 'source CPU', the freshly booting + * CPU is the 'target CPU'. + * + * Only two CPUs may participate - they can enter in any order. + * ( The serial nature of the boot logic and the CPU hotplug lock + * protects against more than 2 CPUs entering this code. ) + */ +#include +#include +#include +#include +#include +#include + +/* + * Entry/exit counters that make sure that both CPUs + * run the measurement code at once: + */ +static __cpuinitdata atomic_t start_count; +static __cpuinitdata atomic_t stop_count; + +/* + * We use a raw spinlock in this exceptional case, because + * we want to have the fastest, inlined, non-debug version + * of a critical section, to be able to prove TSC time-warps: + */ +static __cpuinitdata raw_spinlock_t sync_lock = __RAW_SPIN_LOCK_UNLOCKED; +static __cpuinitdata cycles_t last_tsc; +static __cpuinitdata cycles_t max_warp; +static __cpuinitdata int nr_warps; + +/* + * TSC-warp measurement loop running on both CPUs: + */ +static __cpuinit void check_tsc_warp(void) +{ + cycles_t start, now, prev, end; + int i; + + start = get_cycles_sync(); + /* + * The measurement runs for 20 msecs: + */ + end = start + cpu_khz * 20ULL; + now = start; + + for (i = 0; ; i++) { + /* + * We take the global lock, measure TSC, save the + * previous TSC that was measured (possibly on + * another CPU) and update the previous TSC timestamp. + */ + __raw_spin_lock(&sync_lock); + prev = last_tsc; + now = get_cycles_sync(); + last_tsc = now; + __raw_spin_unlock(&sync_lock); + + /* + * Be nice every now and then (and also check whether + * measurement is done [we also insert a 100 million + * loops safety exit, so we dont lock up in case the + * TSC readout is totally broken]): + */ + if (unlikely(!(i & 7))) { + if (now > end || i > 100000000) + break; + cpu_relax(); + touch_nmi_watchdog(); + } + /* + * Outside the critical section we can now see whether + * we saw a time-warp of the TSC going backwards: + */ + if (unlikely(prev > now)) { + __raw_spin_lock(&sync_lock); + max_warp = max(max_warp, prev - now); + nr_warps++; + __raw_spin_unlock(&sync_lock); + } + + } +} + +/* + * Source CPU calls into this - it waits for the freshly booted + * target CPU to arrive and then starts the measurement: + */ +void __cpuinit check_tsc_sync_source(int cpu) +{ + int cpus = 2; + + /* + * No need to check if we already know that the TSC is not + * synchronized: + */ + if (unsynchronized_tsc()) + return; + + printk(KERN_INFO "checking TSC synchronization [CPU#%d -> CPU#%d]:", + smp_processor_id(), cpu); + + /* + * Reset it - in case this is a second bootup: + */ + atomic_set(&stop_count, 0); + + /* + * Wait for the target to arrive: + */ + while (atomic_read(&start_count) != cpus-1) + cpu_relax(); + /* + * Trigger the target to continue into the measurement too: + */ + atomic_inc(&start_count); + + check_tsc_warp(); + + while (atomic_read(&stop_count) != cpus-1) + cpu_relax(); + + /* + * Reset it - just in case we boot another CPU later: + */ + atomic_set(&start_count, 0); + + if (nr_warps) { + printk("\n"); + printk(KERN_WARNING "Measured %Ld cycles TSC warp between CPUs," + " turning off TSC clock.\n", max_warp); + mark_tsc_unstable(); + nr_warps = 0; + max_warp = 0; + last_tsc = 0; + } else { + printk(" passed.\n"); + } + + /* + * Let the target continue with the bootup: + */ + atomic_inc(&stop_count); +} + +/* + * Freshly booted CPUs call into this: + */ +void __cpuinit check_tsc_sync_target(void) +{ + int cpus = 2; + + if (unsynchronized_tsc()) + return; + + /* + * Register this CPU's participation and wait for the + * source CPU to start the measurement: + */ + atomic_inc(&start_count); + while (atomic_read(&start_count) != cpus) + cpu_relax(); + + check_tsc_warp(); + + /* + * Ok, we are done: + */ + atomic_inc(&stop_count); + + /* + * Wait for the source CPU to print stuff: + */ + while (atomic_read(&stop_count) != cpus) + cpu_relax(); +} +#undef NR_LOOPS + diff --git a/arch/x86_64/kernel/vmlinux.lds.S b/arch/x86_64/kernel/vmlinux.lds.S index 1e54ddf..b73212c 100644 --- a/arch/x86_64/kernel/vmlinux.lds.S +++ b/arch/x86_64/kernel/vmlinux.lds.S @@ -88,31 +88,25 @@ #define VVIRT(x) (ADDR(x) - VVIRT_OFFSET __vsyscall_0 = VSYSCALL_VIRT_ADDR; . = ALIGN(CONFIG_X86_L1_CACHE_BYTES); - .xtime_lock : AT(VLOAD(.xtime_lock)) { *(.xtime_lock) } - xtime_lock = VVIRT(.xtime_lock); - - .vxtime : AT(VLOAD(.vxtime)) { *(.vxtime) } - vxtime = VVIRT(.vxtime); + .vsyscall_fn : AT(VLOAD(.vsyscall_fn)) { *(.vsyscall_fn) } + . = ALIGN(CONFIG_X86_L1_CACHE_BYTES); + .vsyscall_gtod_data : AT(VLOAD(.vsyscall_gtod_data)) + { *(.vsyscall_gtod_data) } + vsyscall_gtod_data = VVIRT(.vsyscall_gtod_data); .vgetcpu_mode : AT(VLOAD(.vgetcpu_mode)) { *(.vgetcpu_mode) } vgetcpu_mode = VVIRT(.vgetcpu_mode); - .sys_tz : AT(VLOAD(.sys_tz)) { *(.sys_tz) } - sys_tz = VVIRT(.sys_tz); - - .sysctl_vsyscall : AT(VLOAD(.sysctl_vsyscall)) { *(.sysctl_vsyscall) } - sysctl_vsyscall = VVIRT(.sysctl_vsyscall); - - .xtime : AT(VLOAD(.xtime)) { *(.xtime) } - xtime = VVIRT(.xtime); - . = ALIGN(CONFIG_X86_L1_CACHE_BYTES); .jiffies : AT(VLOAD(.jiffies)) { *(.jiffies) } jiffies = VVIRT(.jiffies); - .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) } + .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) } . = VSYSCALL_VIRT_ADDR + 4096; @@ -192,10 +186,14 @@ #undef VVIRT from .altinstructions and .eh_frame */ .exit.text : AT(ADDR(.exit.text) - LOAD_OFFSET) { *(.exit.text) } .exit.data : AT(ADDR(.exit.data) - LOAD_OFFSET) { *(.exit.data) } + +#ifdef CONFIG_BLK_DEV_INITRD . = ALIGN(4096); __initramfs_start = .; .init.ramfs : AT(ADDR(.init.ramfs) - LOAD_OFFSET) { *(.init.ramfs) } __initramfs_end = .; +#endif + . = ALIGN(CONFIG_X86_L1_CACHE_BYTES); __per_cpu_start = .; .data.percpu : AT(ADDR(.data.percpu) - LOAD_OFFSET) { *(.data.percpu) } diff --git a/arch/x86_64/kernel/vsyscall.c b/arch/x86_64/kernel/vsyscall.c index 2433d6f..180ff91 100644 --- a/arch/x86_64/kernel/vsyscall.c +++ b/arch/x86_64/kernel/vsyscall.c @@ -26,6 +26,7 @@ #include #include #include #include +#include #include #include #include @@ -34,6 +35,7 @@ #include #include #include #include +#include #include #include #include @@ -44,56 +46,41 @@ #include #define __vsyscall(nr) __attribute__ ((unused,__section__(".vsyscall_" #nr))) #define __syscall_clobber "r11","rcx","memory" -int __sysctl_vsyscall __section_sysctl_vsyscall = 1; -seqlock_t __xtime_lock __section_xtime_lock = SEQLOCK_UNLOCKED; +struct vsyscall_gtod_data_t { + seqlock_t lock; + int sysctl_enabled; + struct timeval wall_time_tv; + struct timezone sys_tz; + cycle_t offset_base; + struct clocksource clock; +}; int __vgetcpu_mode __section_vgetcpu_mode; -#include - -static __always_inline void timeval_normalize(struct timeval * tv) +struct vsyscall_gtod_data_t __vsyscall_gtod_data __section_vsyscall_gtod_data = { - time_t __sec; - - __sec = tv->tv_usec / 1000000; - if (__sec) { - tv->tv_usec %= 1000000; - tv->tv_sec += __sec; - } -} + .lock = SEQLOCK_UNLOCKED, + .sysctl_enabled = 1, +}; -static __always_inline void do_vgettimeofday(struct timeval * tv) +void update_vsyscall(struct timespec *wall_time, struct clocksource *clock) { - long sequence, t; - unsigned long sec, usec; - - do { - sequence = read_seqbegin(&__xtime_lock); - - sec = __xtime.tv_sec; - usec = __xtime.tv_nsec / 1000; - - if (__vxtime.mode != VXTIME_HPET) { - t = get_cycles_sync(); - if (t < __vxtime.last_tsc) - t = __vxtime.last_tsc; - usec += ((t - __vxtime.last_tsc) * - __vxtime.tsc_quot) >> 32; - /* See comment in x86_64 do_gettimeofday. */ - } else { - usec += ((readl((void __iomem *) - fix_to_virt(VSYSCALL_HPET) + 0xf0) - - __vxtime.last) * __vxtime.quot) >> 32; - } - } while (read_seqretry(&__xtime_lock, sequence)); - - tv->tv_sec = sec + usec / 1000000; - tv->tv_usec = usec % 1000000; + unsigned long flags; + + write_seqlock_irqsave(&vsyscall_gtod_data.lock, flags); + /* copy vsyscall data */ + vsyscall_gtod_data.clock = *clock; + vsyscall_gtod_data.wall_time_tv.tv_sec = wall_time->tv_sec; + vsyscall_gtod_data.wall_time_tv.tv_usec = wall_time->tv_nsec/1000; + vsyscall_gtod_data.sys_tz = sys_tz; + write_sequnlock_irqrestore(&vsyscall_gtod_data.lock, flags); } -/* RED-PEN may want to readd seq locking, but then the variable should be write-once. */ +/* 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) { - *tz = __sys_tz; + *tz = __vsyscall_gtod_data.sys_tz; } static __always_inline int gettimeofday(struct timeval *tv, struct timezone *tz) @@ -101,7 +88,8 @@ static __always_inline int gettimeofday( int ret; asm volatile("vsysc2: syscall" : "=a" (ret) - : "0" (__NR_gettimeofday),"D" (tv),"S" (tz) : __syscall_clobber ); + : "0" (__NR_gettimeofday),"D" (tv),"S" (tz) + : __syscall_clobber ); return ret; } @@ -114,10 +102,44 @@ static __always_inline long time_syscall return secs; } +static __always_inline void do_vgettimeofday(struct timeval * tv) +{ + cycle_t now, base, mask, cycle_delta; + unsigned long seq, mult, shift, nsec_delta; + cycle_t (*vread)(void); + do { + seq = read_seqbegin(&__vsyscall_gtod_data.lock); + + vread = __vsyscall_gtod_data.clock.vread; + if (unlikely(!__vsyscall_gtod_data.sysctl_enabled || !vread)) { + gettimeofday(tv,0); + return; + } + now = vread(); + base = __vsyscall_gtod_data.clock.cycle_last; + mask = __vsyscall_gtod_data.clock.mask; + mult = __vsyscall_gtod_data.clock.mult; + shift = __vsyscall_gtod_data.clock.shift; + + *tv = __vsyscall_gtod_data.wall_time_tv; + + } while (read_seqretry(&__vsyscall_gtod_data.lock, seq)); + + /* calculate interval: */ + cycle_delta = (now - base) & mask; + /* convert to nsecs: */ + nsec_delta = (cycle_delta * mult) >> shift; + + /* convert to usecs and add to timespec: */ + tv->tv_usec += nsec_delta / NSEC_PER_USEC; + while (tv->tv_usec > USEC_PER_SEC) { + tv->tv_sec += 1; + tv->tv_usec -= USEC_PER_SEC; + } +} + int __vsyscall(0) vgettimeofday(struct timeval * tv, struct timezone * tz) { - if (!__sysctl_vsyscall) - return gettimeofday(tv,tz); if (tv) do_vgettimeofday(tv); if (tz) @@ -129,11 +151,11 @@ int __vsyscall(0) vgettimeofday(struct t * unlikely */ time_t __vsyscall(1) vtime(time_t *t) { - if (!__sysctl_vsyscall) + if (unlikely(!__vsyscall_gtod_data.sysctl_enabled)) return time_syscall(t); else if (t) - *t = __xtime.tv_sec; - return __xtime.tv_sec; + *t = __vsyscall_gtod_data.wall_time_tv.tv_sec; + return __vsyscall_gtod_data.wall_time_tv.tv_sec; } /* Fast way to get current CPU and node. @@ -210,7 +232,7 @@ static int vsyscall_sysctl_change(ctl_ta ret = -ENOMEM; goto out; } - if (!sysctl_vsyscall) { + if (!vsyscall_gtod_data.sysctl_enabled) { writew(SYSCALL, map1); writew(SYSCALL, map2); } else { @@ -232,16 +254,17 @@ static int vsyscall_sysctl_nostrat(ctl_t static ctl_table kernel_table2[] = { { .ctl_name = 99, .procname = "vsyscall64", - .data = &sysctl_vsyscall, .maxlen = sizeof(int), .mode = 0644, + .data = &vsyscall_gtod_data.sysctl_enabled, .maxlen = sizeof(int), + .mode = 0644, .strategy = vsyscall_sysctl_nostrat, .proc_handler = vsyscall_sysctl_change }, - { 0, } + {} }; static ctl_table kernel_root_table2[] = { { .ctl_name = CTL_KERN, .procname = "kernel", .mode = 0555, .child = kernel_table2 }, - { 0 }, + {} }; #endif @@ -301,7 +324,7 @@ static int __init vsyscall_init(void) BUG_ON((unsigned long) &vgetcpu != VSYSCALL_ADDR(__NR_vgetcpu)); map_vsyscall(); #ifdef CONFIG_SYSCTL - register_sysctl_table(kernel_root_table2, 0); + register_sysctl_table(kernel_root_table2); #endif on_each_cpu(cpu_vsyscall_init, NULL, 0, 1); hotcpu_notifier(cpu_vsyscall_notifier, 0); diff --git a/arch/x86_64/kernel/x8664_ksyms.c b/arch/x86_64/kernel/x8664_ksyms.c index 6d77e47..0dffae6 100644 --- a/arch/x86_64/kernel/x8664_ksyms.c +++ b/arch/x86_64/kernel/x8664_ksyms.c @@ -26,6 +26,7 @@ EXPORT_SYMBOL(__put_user_4); EXPORT_SYMBOL(__put_user_8); EXPORT_SYMBOL(copy_user_generic); +EXPORT_SYMBOL(__copy_user_nocache); EXPORT_SYMBOL(copy_from_user); EXPORT_SYMBOL(copy_to_user); EXPORT_SYMBOL(__copy_from_user_inatomic); @@ -34,8 +35,8 @@ EXPORT_SYMBOL(copy_page); EXPORT_SYMBOL(clear_page); #ifdef CONFIG_SMP -extern void FASTCALL( __write_lock_failed(rwlock_t *rw)); -extern void FASTCALL( __read_lock_failed(rwlock_t *rw)); +extern void __write_lock_failed(rwlock_t *rw); +extern void __read_lock_failed(rwlock_t *rw); EXPORT_SYMBOL(__write_lock_failed); EXPORT_SYMBOL(__read_lock_failed); #endif diff --git a/arch/x86_64/lib/Makefile b/arch/x86_64/lib/Makefile index b78d417..8d5f835 100644 --- a/arch/x86_64/lib/Makefile +++ b/arch/x86_64/lib/Makefile @@ -9,4 +9,4 @@ obj-y := io.o iomap_copy.o lib-y := csum-partial.o csum-copy.o csum-wrappers.o delay.o \ usercopy.o getuser.o putuser.o \ thunk.o clear_page.o copy_page.o bitstr.o bitops.o -lib-y += memcpy.o memmove.o memset.o copy_user.o rwlock.o +lib-y += memcpy.o memmove.o memset.o copy_user.o rwlock.o copy_user_nocache.o diff --git a/arch/x86_64/lib/copy_user_nocache.S b/arch/x86_64/lib/copy_user_nocache.S new file mode 100644 index 0000000..4620efb --- /dev/null +++ b/arch/x86_64/lib/copy_user_nocache.S @@ -0,0 +1,217 @@ +/* Copyright 2002 Andi Kleen, SuSE Labs. + * Subject to the GNU Public License v2. + * + * Functions to copy from and to user space. + */ + +#include +#include + +#define FIX_ALIGNMENT 1 + +#include +#include +#include +#include + +/* + * copy_user_nocache - Uncached memory copy with exception handling + * This will force destination/source out of cache for more performance. + * + * Input: + * rdi destination + * rsi source + * rdx count + * rcx zero flag when 1 zero on exception + * + * Output: + * eax uncopied bytes or 0 if successful. + */ +ENTRY(__copy_user_nocache) + CFI_STARTPROC + pushq %rbx + CFI_ADJUST_CFA_OFFSET 8 + CFI_REL_OFFSET rbx, 0 + pushq %rcx /* save zero flag */ + CFI_ADJUST_CFA_OFFSET 8 + CFI_REL_OFFSET rcx, 0 + + xorl %eax,%eax /* zero for the exception handler */ + +#ifdef FIX_ALIGNMENT + /* check for bad alignment of destination */ + movl %edi,%ecx + andl $7,%ecx + jnz .Lbad_alignment +.Lafter_bad_alignment: +#endif + + movq %rdx,%rcx + + movl $64,%ebx + shrq $6,%rdx + decq %rdx + js .Lhandle_tail + + .p2align 4 +.Lloop: +.Ls1: movq (%rsi),%r11 +.Ls2: movq 1*8(%rsi),%r8 +.Ls3: movq 2*8(%rsi),%r9 +.Ls4: movq 3*8(%rsi),%r10 +.Ld1: movnti %r11,(%rdi) +.Ld2: movnti %r8,1*8(%rdi) +.Ld3: movnti %r9,2*8(%rdi) +.Ld4: movnti %r10,3*8(%rdi) + +.Ls5: movq 4*8(%rsi),%r11 +.Ls6: movq 5*8(%rsi),%r8 +.Ls7: movq 6*8(%rsi),%r9 +.Ls8: movq 7*8(%rsi),%r10 +.Ld5: movnti %r11,4*8(%rdi) +.Ld6: movnti %r8,5*8(%rdi) +.Ld7: movnti %r9,6*8(%rdi) +.Ld8: movnti %r10,7*8(%rdi) + + dec %rdx + + leaq 64(%rsi),%rsi + leaq 64(%rdi),%rdi + + jns .Lloop + + .p2align 4 +.Lhandle_tail: + movl %ecx,%edx + andl $63,%ecx + shrl $3,%ecx + jz .Lhandle_7 + movl $8,%ebx + .p2align 4 +.Lloop_8: +.Ls9: movq (%rsi),%r8 +.Ld9: movnti %r8,(%rdi) + decl %ecx + leaq 8(%rdi),%rdi + leaq 8(%rsi),%rsi + jnz .Lloop_8 + +.Lhandle_7: + movl %edx,%ecx + andl $7,%ecx + jz .Lende + .p2align 4 +.Lloop_1: +.Ls10: movb (%rsi),%bl +.Ld10: movb %bl,(%rdi) + incq %rdi + incq %rsi + decl %ecx + jnz .Lloop_1 + + CFI_REMEMBER_STATE +.Lende: + popq %rcx + CFI_ADJUST_CFA_OFFSET -8 + CFI_RESTORE %rcx + popq %rbx + CFI_ADJUST_CFA_OFFSET -8 + CFI_RESTORE rbx + ret + CFI_RESTORE_STATE + +#ifdef FIX_ALIGNMENT + /* align destination */ + .p2align 4 +.Lbad_alignment: + movl $8,%r9d + subl %ecx,%r9d + movl %r9d,%ecx + cmpq %r9,%rdx + jz .Lhandle_7 + js .Lhandle_7 +.Lalign_1: +.Ls11: movb (%rsi),%bl +.Ld11: movb %bl,(%rdi) + incq %rsi + incq %rdi + decl %ecx + jnz .Lalign_1 + subq %r9,%rdx + jmp .Lafter_bad_alignment +#endif + + /* table sorted by exception address */ + .section __ex_table,"a" + .align 8 + .quad .Ls1,.Ls1e + .quad .Ls2,.Ls2e + .quad .Ls3,.Ls3e + .quad .Ls4,.Ls4e + .quad .Ld1,.Ls1e + .quad .Ld2,.Ls2e + .quad .Ld3,.Ls3e + .quad .Ld4,.Ls4e + .quad .Ls5,.Ls5e + .quad .Ls6,.Ls6e + .quad .Ls7,.Ls7e + .quad .Ls8,.Ls8e + .quad .Ld5,.Ls5e + .quad .Ld6,.Ls6e + .quad .Ld7,.Ls7e + .quad .Ld8,.Ls8e + .quad .Ls9,.Le_quad + .quad .Ld9,.Le_quad + .quad .Ls10,.Le_byte + .quad .Ld10,.Le_byte +#ifdef FIX_ALIGNMENT + .quad .Ls11,.Lzero_rest + .quad .Ld11,.Lzero_rest +#endif + .quad .Le5,.Le_zero + .previous + + /* compute 64-offset for main loop. 8 bytes accuracy with error on the + pessimistic side. this is gross. it would be better to fix the + interface. */ + /* eax: zero, ebx: 64 */ +.Ls1e: addl $8,%eax +.Ls2e: addl $8,%eax +.Ls3e: addl $8,%eax +.Ls4e: addl $8,%eax +.Ls5e: addl $8,%eax +.Ls6e: addl $8,%eax +.Ls7e: addl $8,%eax +.Ls8e: addl $8,%eax + addq %rbx,%rdi /* +64 */ + subq %rax,%rdi /* correct destination with computed offset */ + + shlq $6,%rdx /* loop counter * 64 (stride length) */ + addq %rax,%rdx /* add offset to loopcnt */ + andl $63,%ecx /* remaining bytes */ + addq %rcx,%rdx /* add them */ + jmp .Lzero_rest + + /* exception on quad word loop in tail handling */ + /* ecx: loopcnt/8, %edx: length, rdi: correct */ +.Le_quad: + shll $3,%ecx + andl $7,%edx + addl %ecx,%edx + /* edx: bytes to zero, rdi: dest, eax:zero */ +.Lzero_rest: + cmpl $0,(%rsp) /* zero flag set? */ + jz .Le_zero + movq %rdx,%rcx +.Le_byte: + xorl %eax,%eax +.Le5: rep + stosb + /* when there is another exception while zeroing the rest just return */ +.Le_zero: + movq %rdx,%rax + jmp .Lende + CFI_ENDPROC +ENDPROC(__copy_user_nocache) + + diff --git a/arch/x86_64/mm/fault.c b/arch/x86_64/mm/fault.c index a65fc6f..6ada723 100644 --- a/arch/x86_64/mm/fault.c +++ b/arch/x86_64/mm/fault.c @@ -56,38 +56,17 @@ int unregister_page_fault_notifier(struc } EXPORT_SYMBOL_GPL(unregister_page_fault_notifier); -static inline int notify_page_fault(enum die_val val, const char *str, - struct pt_regs *regs, long err, int trap, int sig) +static inline int notify_page_fault(struct pt_regs *regs, long err) { struct die_args args = { .regs = regs, - .str = str, + .str = "page fault", .err = err, - .trapnr = trap, - .signr = sig + .trapnr = 14, + .signr = SIGSEGV }; - return atomic_notifier_call_chain(¬ify_page_fault_chain, val, &args); -} - -void bust_spinlocks(int yes) -{ - int loglevel_save = console_loglevel; - if (yes) { - oops_in_progress = 1; - } else { -#ifdef CONFIG_VT - unblank_screen(); -#endif - oops_in_progress = 0; - /* - * OK, the message is on the console. Now we call printk() - * without oops_in_progress set so that printk will give klogd - * a poke. Hold onto your hats... - */ - console_loglevel = 15; /* NMI oopser may have shut the console up */ - printk(" "); - console_loglevel = loglevel_save; - } + return atomic_notifier_call_chain(¬ify_page_fault_chain, + DIE_PAGE_FAULT, &args); } /* Sometimes the CPU reports invalid exceptions on prefetch. @@ -376,8 +355,7 @@ asmlinkage void __kprobes do_page_fault( if (vmalloc_fault(address) >= 0) return; } - if (notify_page_fault(DIE_PAGE_FAULT, "page fault", regs, error_code, 14, - SIGSEGV) == NOTIFY_STOP) + if (notify_page_fault(regs, error_code) == NOTIFY_STOP) return; /* * Don't take the mm semaphore here. If we fixup a prefetch @@ -386,8 +364,7 @@ asmlinkage void __kprobes do_page_fault( goto bad_area_nosemaphore; } - if (notify_page_fault(DIE_PAGE_FAULT, "page fault", regs, error_code, 14, - SIGSEGV) == NOTIFY_STOP) + if (notify_page_fault(regs, error_code) == NOTIFY_STOP) return; if (likely(regs->eflags & X86_EFLAGS_IF)) diff --git a/arch/x86_64/mm/init.c b/arch/x86_64/mm/init.c index 2968b90..ec31534 100644 --- a/arch/x86_64/mm/init.c +++ b/arch/x86_64/mm/init.c @@ -711,20 +711,30 @@ #include extern int exception_trace, page_fault_trace; static ctl_table debug_table2[] = { - { 99, "exception-trace", &exception_trace, sizeof(int), 0644, NULL, - proc_dointvec }, - { 0, } + { + .ctl_name = 99, + .procname = "exception-trace", + .data = &exception_trace, + .maxlen = sizeof(int), + .mode = 0644, + .proc_handler = proc_dointvec + }, + {} }; static ctl_table debug_root_table2[] = { - { .ctl_name = CTL_DEBUG, .procname = "debug", .mode = 0555, - .child = debug_table2 }, - { 0 }, + { + .ctl_name = CTL_DEBUG, + .procname = "debug", + .mode = 0555, + .child = debug_table2 + }, + {} }; static __init int x8664_sysctl_init(void) { - register_sysctl_table(debug_root_table2, 1); + register_sysctl_table(debug_root_table2); return 0; } __initcall(x8664_sysctl_init); diff --git a/arch/x86_64/mm/numa.c b/arch/x86_64/mm/numa.c index 2ee2e00..41b8fb0 100644 --- a/arch/x86_64/mm/numa.c +++ b/arch/x86_64/mm/numa.c @@ -36,6 +36,8 @@ unsigned char apicid_to_node[MAX_LOCAL_A cpumask_t node_to_cpumask[MAX_NUMNODES] __read_mostly; int numa_off __initdata; +unsigned long __initdata nodemap_addr; +unsigned long __initdata nodemap_size; /* @@ -52,34 +54,88 @@ populate_memnodemap(const struct bootnod int res = -1; unsigned long addr, end; - if (shift >= 64) - return -1; - memset(memnodemap, 0xff, sizeof(memnodemap)); + memset(memnodemap, 0xff, memnodemapsize); for (i = 0; i < numnodes; i++) { addr = nodes[i].start; end = nodes[i].end; if (addr >= end) continue; - if ((end >> shift) >= NODEMAPSIZE) + if ((end >> shift) >= memnodemapsize) return 0; do { if (memnodemap[addr >> shift] != 0xff) return -1; memnodemap[addr >> shift] = i; - addr += (1UL << shift); + addr += (1UL << shift); } while (addr < end); res = 1; } return res; } -int __init compute_hash_shift(struct bootnode *nodes, int numnodes) +static int __init allocate_cachealigned_memnodemap(void) { - int shift = 20; + unsigned long pad, pad_addr; + + memnodemap = memnode.embedded_map; + if (memnodemapsize <= 48) + return 0; + + pad = L1_CACHE_BYTES - 1; + pad_addr = 0x8000; + nodemap_size = pad + memnodemapsize; + nodemap_addr = find_e820_area(pad_addr, end_pfn<= 0) - shift++; +/* + * The LSB of all start and end addresses in the node map is the value of the + * maximum possible shift. + */ +static int __init +extract_lsb_from_nodes (const struct bootnode *nodes, int numnodes) +{ + int i, nodes_used = 0; + unsigned long start, end; + unsigned long bitfield = 0, memtop = 0; + + for (i = 0; i < numnodes; i++) { + start = nodes[i].start; + end = nodes[i].end; + if (start >= end) + continue; + bitfield |= start; + nodes_used++; + if (end > memtop) + memtop = end; + } + if (nodes_used <= 1) + i = 63; + else + i = find_first_bit(&bitfield, sizeof(unsigned long)*8); + memnodemapsize = (memtop >> i)+1; + return i; +} + +int __init compute_hash_shift(struct bootnode *nodes, int numnodes) +{ + int shift; + shift = extract_lsb_from_nodes(nodes, numnodes); + if (allocate_cachealigned_memnodemap()) + return -1; printk(KERN_DEBUG "NUMA: Using %d for the hash shift.\n", shift); @@ -216,31 +272,113 @@ void __init numa_init_array(void) } #ifdef CONFIG_NUMA_EMU +/* Numa emulation */ int numa_fake __initdata = 0; -/* Numa emulation */ +/* + * This function is used to find out if the start and end correspond to + * different zones. + */ +int zone_cross_over(unsigned long start, unsigned long end) +{ + if ((start < (MAX_DMA32_PFN << PAGE_SHIFT)) && + (end >= (MAX_DMA32_PFN << PAGE_SHIFT))) + return 1; + return 0; +} + static int __init numa_emulation(unsigned long start_pfn, unsigned long end_pfn) { - int i; + int i, big; struct bootnode nodes[MAX_NUMNODES]; - unsigned long sz = ((end_pfn - start_pfn)< 1) { - unsigned long x = 1; - while ((x << 1) < sz) - x <<= 1; - if (x < sz/2) - printk(KERN_ERR "Numa emulation unbalanced. Complain to maintainer\n"); - sz = x; - } + old_sz = sz; + /* + * Round down to the nearest FAKE_NODE_MIN_SIZE. + */ + sz &= FAKE_NODE_MIN_HASH_MASK; + + /* + * We ensure that each node is at least 64MB big. Smaller than this + * size can cause VM hiccups. + */ + if (sz == 0) { + printk(KERN_INFO "Not enough memory for %d nodes. Reducing " + "the number of nodes\n", numa_fake); + numa_fake = (max_addr - start - hole_size) / FAKE_NODE_MIN_SIZE; + printk(KERN_INFO "Number of fake nodes will be = %d\n", + numa_fake); + sz = FAKE_NODE_MIN_SIZE; + } + /* + * Find out how many nodes can get an extra NODE_MIN_SIZE granule. + * This logic ensures the extra memory gets distributed among as many + * nodes as possible (as compared to one single node getting all that + * extra memory. + */ + big = ((old_sz - sz) * numa_fake) / FAKE_NODE_MIN_SIZE; + printk(KERN_INFO "Fake node Size: %luMB hole_size: %luMB big nodes: " + "%d\n", + (sz >> 20), (hole_size >> 20), big); memset(&nodes,0,sizeof(nodes)); + end = start; for (i = 0; i < numa_fake; i++) { - nodes[i].start = (start_pfn<= max_addr) { + numa_fake = i - 1; + break; + } + start = nodes[i].start = end; + /* + * Final node can have all the remaining memory. + */ if (i == numa_fake-1) - sz = (end_pfn<= max_addr) + break; + } + /* + * Look at the next node to make sure there is some real memory + * to map. Bad things happen when the only memory present + * in a zone on a fake node is IO hole. + */ + while (e820_hole_size(end, end + FAKE_NODE_MIN_SIZE) > 0) { + if (zone_cross_over(start, end + sz)) { + end = (MAX_DMA32_PFN << PAGE_SHIFT); + break; + } + if (end >= max_addr) + break; + end += FAKE_NODE_MIN_SIZE; + } + if (end > max_addr) + end = max_addr; + nodes[i].end = end; printk(KERN_INFO "Faking node %d at %016Lx-%016Lx (%LuMB)\n", i, nodes[i].start, nodes[i].end, @@ -290,6 +428,7 @@ #endif end_pfn << PAGE_SHIFT); /* setup dummy node covering all memory */ memnode_shift = 63; + memnodemap = memnode.embedded_map; memnodemap[0] = 0; nodes_clear(node_online_map); node_set_online(0); @@ -321,20 +460,6 @@ unsigned long __init numa_free_all_bootm return pages; } -#ifdef CONFIG_SPARSEMEM -static void __init arch_sparse_init(void) -{ - int i; - - for_each_online_node(i) - memory_present(i, node_start_pfn(i), node_end_pfn(i)); - - sparse_init(); -} -#else -#define arch_sparse_init() do {} while (0) -#endif - void __init paging_init(void) { int i; @@ -344,7 +469,8 @@ void __init paging_init(void) max_zone_pfns[ZONE_DMA32] = MAX_DMA32_PFN; max_zone_pfns[ZONE_NORMAL] = end_pfn; - arch_sparse_init(); + sparse_memory_present_with_active_regions(MAX_NUMNODES); + sparse_init(); for_each_online_node(i) { setup_node_zones(i); diff --git a/arch/x86_64/mm/pageattr.c b/arch/x86_64/mm/pageattr.c index ccb91dd..65c5eaa 100644 --- a/arch/x86_64/mm/pageattr.c +++ b/arch/x86_64/mm/pageattr.c @@ -107,6 +107,7 @@ static void revert_page(unsigned long ad pud_t *pud; pmd_t *pmd; pte_t large_pte; + unsigned long pfn; pgd = pgd_offset_k(address); BUG_ON(pgd_none(*pgd)); @@ -114,7 +115,8 @@ static void revert_page(unsigned long ad BUG_ON(pud_none(*pud)); pmd = pmd_offset(pud, address); BUG_ON(pmd_val(*pmd) & _PAGE_PSE); - large_pte = mk_pte_phys(__pa(address) & LARGE_PAGE_MASK, ref_prot); + pfn = (__pa(address) & LARGE_PAGE_MASK) >> PAGE_SHIFT; + large_pte = pfn_pte(pfn, ref_prot); large_pte = pte_mkhuge(large_pte); set_pte((pte_t *)pmd, large_pte); } diff --git a/arch/x86_64/mm/srat.c b/arch/x86_64/mm/srat.c index 1087e15..2efe215 100644 --- a/arch/x86_64/mm/srat.c +++ b/arch/x86_64/mm/srat.c @@ -101,7 +101,7 @@ static __init inline int srat_disabled(v static __init int slit_valid(struct acpi_table_slit *slit) { int i, j; - int d = slit->localities; + int d = slit->locality_count; for (i = 0; i < d; i++) { for (j = 0; j < d; j++) { u8 val = slit->entry[d*i + j]; @@ -127,18 +127,18 @@ void __init acpi_numa_slit_init(struct a /* Callback for Proximity Domain -> LAPIC mapping */ void __init -acpi_numa_processor_affinity_init(struct acpi_table_processor_affinity *pa) +acpi_numa_processor_affinity_init(struct acpi_srat_cpu_affinity *pa) { int pxm, node; if (srat_disabled()) return; - if (pa->header.length != sizeof(struct acpi_table_processor_affinity)) { + if (pa->header.length != sizeof(struct acpi_srat_cpu_affinity)) { bad_srat(); return; } - if (pa->flags.enabled == 0) + if ((pa->flags & ACPI_SRAT_CPU_ENABLED) == 0) return; - pxm = pa->proximity_domain; + pxm = pa->proximity_domain_lo; node = setup_node(pxm); if (node < 0) { printk(KERN_ERR "SRAT: Too many proximity domains %x\n", pxm); @@ -254,21 +254,21 @@ static int reserve_hotadd(int node, unsi /* Looks good */ if (nd->start == nd->end) { - nd->start = start; - nd->end = end; + nd->start = start; + nd->end = end; changed = 1; - } else { - if (nd->start == end) { - nd->start = start; + } else { + if (nd->start == end) { + nd->start = start; changed = 1; } - if (nd->end == start) { - nd->end = end; + if (nd->end == start) { + nd->end = end; changed = 1; } if (!changed) printk(KERN_ERR "SRAT: Hotplug zone not continuous. Partly ignored\n"); - } + } ret = update_end_of_memory(nd->end); @@ -279,7 +279,7 @@ static int reserve_hotadd(int node, unsi /* Callback for parsing of the Proximity Domain <-> Memory Area mappings */ void __init -acpi_numa_memory_affinity_init(struct acpi_table_memory_affinity *ma) +acpi_numa_memory_affinity_init(struct acpi_srat_mem_affinity *ma) { struct bootnode *nd, oldnode; unsigned long start, end; @@ -288,16 +288,17 @@ acpi_numa_memory_affinity_init(struct ac if (srat_disabled()) return; - if (ma->header.length != sizeof(struct acpi_table_memory_affinity)) { + if (ma->header.length != sizeof(struct acpi_srat_mem_affinity)) { bad_srat(); return; } - if (ma->flags.enabled == 0) + if ((ma->flags & ACPI_SRAT_MEM_ENABLED) == 0) return; - if (ma->flags.hot_pluggable && !save_add_info()) + + if ((ma->flags & ACPI_SRAT_MEM_HOT_PLUGGABLE) && !save_add_info()) return; - start = ma->base_addr_lo | ((u64)ma->base_addr_hi << 32); - end = start + (ma->length_lo | ((u64)ma->length_hi << 32)); + start = ma->base_address; + end = start + ma->length; pxm = ma->proximity_domain; node = setup_node(pxm); if (node < 0) { @@ -337,7 +338,8 @@ acpi_numa_memory_affinity_init(struct ac push_node_boundaries(node, nd->start >> PAGE_SHIFT, nd->end >> PAGE_SHIFT); - if (ma->flags.hot_pluggable && (reserve_hotadd(node, start, end) < 0)) { + if ((ma->flags & ACPI_SRAT_MEM_HOT_PLUGGABLE) && + (reserve_hotadd(node, start, end) < 0)) { /* Ignore hotadd region. Undo damage */ printk(KERN_NOTICE "SRAT: Hotplug region ignored\n"); *nd = oldnode; @@ -394,7 +396,7 @@ int __init acpi_scan_nodes(unsigned long /* First clean up the node list */ for (i = 0; i < MAX_NUMNODES; i++) { - cutoff_node(i, start, end); + cutoff_node(i, start, end); if ((nodes[i].end - nodes[i].start) < NODE_MIN_SIZE) { unparse_node(i); node_set_offline(i); @@ -426,7 +428,7 @@ int __init acpi_scan_nodes(unsigned long if (!node_online(i)) setup_node_bootmem(i, nodes[i].start, nodes[i].end); - for (i = 0; i < NR_CPUS; i++) { + for (i = 0; i < NR_CPUS; i++) { if (cpu_to_node[i] == NUMA_NO_NODE) continue; if (!node_isset(cpu_to_node[i], nodes_parsed)) @@ -461,7 +463,7 @@ int __node_distance(int a, int b) if (!acpi_slit) return a == b ? 10 : 20; - index = acpi_slit->localities * node_to_pxm(a); + index = acpi_slit->locality_count * node_to_pxm(a); return acpi_slit->entry[index + node_to_pxm(b)]; } diff --git a/arch/x86_64/pci/Makefile b/arch/x86_64/pci/Makefile index 149aba0..c9eddc8 100644 --- a/arch/x86_64/pci/Makefile +++ b/arch/x86_64/pci/Makefile @@ -11,7 +11,7 @@ obj-y += fixup.o init.o obj-$(CONFIG_ACPI) += acpi.o obj-y += legacy.o irq.o common.o early.o # mmconfig has a 64bit special -obj-$(CONFIG_PCI_MMCONFIG) += mmconfig.o direct.o +obj-$(CONFIG_PCI_MMCONFIG) += mmconfig.o direct.o mmconfig-shared.o obj-$(CONFIG_NUMA) += k8-bus.o @@ -24,3 +24,4 @@ fixup-y += ../../i386/pci/fixup.o i386-y += ../../i386/pci/i386.o init-y += ../../i386/pci/init.o early-y += ../../i386/pci/early.o +mmconfig-shared-y += ../../i386/pci/mmconfig-shared.o diff --git a/arch/x86_64/pci/mmconfig.c b/arch/x86_64/pci/mmconfig.c index f8b6b28..65d8273 100644 --- a/arch/x86_64/pci/mmconfig.c +++ b/arch/x86_64/pci/mmconfig.c @@ -1,6 +1,6 @@ /* * mmconfig.c - Low-level direct PCI config space access via MMCONFIG - * + * * This is an 64bit optimized version that always keeps the full mmconfig * space mapped. This allows lockless config space operation. */ @@ -13,49 +13,26 @@ #include #include "pci.h" -/* aperture is up to 256MB but BIOS may reserve less */ -#define MMCONFIG_APER_MIN (2 * 1024*1024) -#define MMCONFIG_APER_MAX (256 * 1024*1024) - -/* Verify the first 16 busses. We assume that systems with more busses - get MCFG right. */ -#define MAX_CHECK_BUS 16 - -static DECLARE_BITMAP(fallback_slots, 32*MAX_CHECK_BUS); - /* Static virtual mapping of the MMCONFIG aperture */ struct mmcfg_virt { - struct acpi_table_mcfg_config *cfg; + struct acpi_mcfg_allocation *cfg; char __iomem *virt; }; static struct mmcfg_virt *pci_mmcfg_virt; static char __iomem *get_virt(unsigned int seg, unsigned bus) { - int cfg_num = -1; - struct acpi_table_mcfg_config *cfg; + struct acpi_mcfg_allocation *cfg; + int cfg_num; - while (1) { - ++cfg_num; - if (cfg_num >= pci_mmcfg_config_num) - break; + for (cfg_num = 0; cfg_num < pci_mmcfg_config_num; cfg_num++) { cfg = pci_mmcfg_virt[cfg_num].cfg; - if (cfg->pci_segment_group_number != seg) - continue; - if ((cfg->start_bus_number <= bus) && + if (cfg->pci_segment == seg && + (cfg->start_bus_number <= bus) && (cfg->end_bus_number >= bus)) return pci_mmcfg_virt[cfg_num].virt; } - /* Handle more broken MCFG tables on Asus etc. - They only contain a single entry for bus 0-0. Assume - this applies to all busses. */ - cfg = &pci_mmcfg_config[0]; - if (pci_mmcfg_config_num == 1 && - cfg->pci_segment_group_number == 0 && - (cfg->start_bus_number | cfg->end_bus_number) == 0) - return pci_mmcfg_virt[0].virt; - /* Fall back to type 0 */ return NULL; } @@ -63,8 +40,8 @@ static char __iomem *get_virt(unsigned i static char __iomem *pci_dev_base(unsigned int seg, unsigned int bus, unsigned int devfn) { char __iomem *addr; - if (seg == 0 && bus < MAX_CHECK_BUS && - test_bit(32*bus + PCI_SLOT(devfn), fallback_slots)) + if (seg == 0 && bus < PCI_MMCFG_MAX_CHECK_BUS && + test_bit(32*bus + PCI_SLOT(devfn), pci_mmcfg_fallback_slots)) return NULL; addr = get_virt(seg, bus); if (!addr) @@ -135,78 +112,46 @@ static struct pci_raw_ops pci_mmcfg = { .write = pci_mmcfg_write, }; -/* K8 systems have some devices (typically in the builtin northbridge) - that are only accessible using type1 - Normally this can be expressed in the MCFG by not listing them - and assigning suitable _SEGs, but this isn't implemented in some BIOS. - Instead try to discover all devices on bus 0 that are unreachable using MM - and fallback for them. */ -static __init void unreachable_devices(void) +static void __iomem * __init mcfg_ioremap(struct acpi_mcfg_allocation *cfg) { - int i, k; - /* Use the max bus number from ACPI here? */ - for (k = 0; k < MAX_CHECK_BUS; k++) { - for (i = 0; i < 32; i++) { - u32 val1; - char __iomem *addr; - - pci_conf1_read(0, k, PCI_DEVFN(i,0), 0, 4, &val1); - if (val1 == 0xffffffff) - continue; - addr = pci_dev_base(0, k, PCI_DEVFN(i, 0)); - if (addr == NULL|| readl(addr) != val1) { - set_bit(i + 32*k, fallback_slots); - printk(KERN_NOTICE "PCI: No mmconfig possible" - " on device %02x:%02x\n", k, i); - } - } + void __iomem *addr; + u32 size; + + size = (cfg->end_bus_number + 1) << 20; + addr = ioremap_nocache(cfg->address, size); + if (addr) { + printk(KERN_INFO "PCI: Using MMCONFIG at %Lx - %Lx\n", + cfg->address, cfg->address + size - 1); } + return addr; } -void __init pci_mmcfg_init(int type) +int __init pci_mmcfg_arch_reachable(unsigned int seg, unsigned int bus, + unsigned int devfn) { - int i; - - if ((pci_probe & PCI_PROBE_MMCONF) == 0) - return; - - acpi_table_parse(ACPI_MCFG, acpi_parse_mcfg); - if ((pci_mmcfg_config_num == 0) || - (pci_mmcfg_config == NULL) || - (pci_mmcfg_config[0].base_address == 0)) - return; - - /* Only do this check when type 1 works. If it doesn't work - assume we run on a Mac and always use MCFG */ - if (type == 1 && !e820_all_mapped(pci_mmcfg_config[0].base_address, - pci_mmcfg_config[0].base_address + MMCONFIG_APER_MIN, - E820_RESERVED)) { - printk(KERN_ERR "PCI: BIOS Bug: MCFG area at %x is not E820-reserved\n", - pci_mmcfg_config[0].base_address); - printk(KERN_ERR "PCI: Not using MMCONFIG.\n"); - return; - } + return pci_dev_base(seg, bus, devfn) != NULL; +} - pci_mmcfg_virt = kmalloc(sizeof(*pci_mmcfg_virt) * pci_mmcfg_config_num, GFP_KERNEL); +int __init pci_mmcfg_arch_init(void) +{ + int i; + pci_mmcfg_virt = kmalloc(sizeof(*pci_mmcfg_virt) * + pci_mmcfg_config_num, GFP_KERNEL); if (pci_mmcfg_virt == NULL) { printk(KERN_ERR "PCI: Can not allocate memory for mmconfig structures\n"); - return; + return 0; } + for (i = 0; i < pci_mmcfg_config_num; ++i) { pci_mmcfg_virt[i].cfg = &pci_mmcfg_config[i]; - pci_mmcfg_virt[i].virt = ioremap_nocache(pci_mmcfg_config[i].base_address, - MMCONFIG_APER_MAX); + pci_mmcfg_virt[i].virt = mcfg_ioremap(&pci_mmcfg_config[i]); if (!pci_mmcfg_virt[i].virt) { printk(KERN_ERR "PCI: Cannot map mmconfig aperture for " "segment %d\n", - pci_mmcfg_config[i].pci_segment_group_number); - return; + pci_mmcfg_config[i].pci_segment); + return 0; } - printk(KERN_INFO "PCI: Using MMCONFIG at %x\n", pci_mmcfg_config[i].base_address); } - - unreachable_devices(); - raw_pci_ops = &pci_mmcfg; - pci_probe = (pci_probe & ~PCI_PROBE_MASK) | PCI_PROBE_MMCONF; + return 1; } diff --git a/arch/xtensa/Kconfig b/arch/xtensa/Kconfig index 2e74cb0..7fbb44b 100644 --- a/arch/xtensa/Kconfig +++ b/arch/xtensa/Kconfig @@ -7,6 +7,10 @@ config FRAME_POINTER bool default n +config ZONE_DMA + bool + default y + config XTENSA bool default y @@ -42,6 +46,9 @@ config ARCH_HAS_ILOG2_U64 bool default n +config NO_IOPORT + def_bool y + source "init/Kconfig" menu "Processor type and features" diff --git a/arch/xtensa/kernel/setup.c b/arch/xtensa/kernel/setup.c index b6374c0..1ecf671 100644 --- a/arch/xtensa/kernel/setup.c +++ b/arch/xtensa/kernel/setup.c @@ -78,7 +78,7 @@ extern unsigned long loops_per_jiffy; /* Command line specified as configuration option. */ -static char command_line[COMMAND_LINE_SIZE]; +static char __initdata command_line[COMMAND_LINE_SIZE]; #ifdef CONFIG_CMDLINE_BOOL static char default_command_line[COMMAND_LINE_SIZE] __initdata = CONFIG_CMDLINE; @@ -253,8 +253,8 @@ void __init setup_arch(char **cmdline_p) extern int mem_reserve(unsigned long, unsigned long, int); extern void bootmem_init(void); - memcpy(saved_command_line, command_line, COMMAND_LINE_SIZE); - saved_command_line[COMMAND_LINE_SIZE-1] = '\0'; + memcpy(boot_command_line, command_line, COMMAND_LINE_SIZE); + boot_command_line[COMMAND_LINE_SIZE-1] = '\0'; *cmdline_p = command_line; /* Reserve some memory regions */ diff --git a/arch/xtensa/kernel/time.c b/arch/xtensa/kernel/time.c index a350431..22949be 100644 --- a/arch/xtensa/kernel/time.c +++ b/arch/xtensa/kernel/time.c @@ -38,15 +38,6 @@ #endif unsigned int last_ccount_stamp; static long last_rtc_update = 0; -/* - * Scheduler clock - returns current tim in nanosec units. - */ - -unsigned long long sched_clock(void) -{ - return (unsigned long long)jiffies * (1000000000 / HZ); -} - static irqreturn_t timer_interrupt(int irq, void *dev_id); static struct irqaction timer_irqaction = { .handler = timer_interrupt, diff --git a/arch/xtensa/kernel/vmlinux.lds.S b/arch/xtensa/kernel/vmlinux.lds.S index a36c104..ab63700 100644 --- a/arch/xtensa/kernel/vmlinux.lds.S +++ b/arch/xtensa/kernel/vmlinux.lds.S @@ -203,10 +203,12 @@ #endif .data.percpu : { *(.data.percpu) } __per_cpu_end = .; +#ifdef CONFIG_BLK_DEV_INITRD . = ALIGN(4096); __initramfs_start =.; .init.ramfs : { *(.init.ramfs) } __initramfs_end = .; +#endif /* We need this dummy segment here */ diff --git a/block/blktrace.c b/block/blktrace.c index d3679dd..3f0e7c3 100644 --- a/block/blktrace.c +++ b/block/blktrace.c @@ -264,7 +264,7 @@ static ssize_t blk_dropped_read(struct f return simple_read_from_buffer(buffer, count, ppos, buf, strlen(buf)); } -static struct file_operations blk_dropped_fops = { +static const struct file_operations blk_dropped_fops = { .owner = THIS_MODULE, .open = blk_dropped_open, .read = blk_dropped_read, @@ -363,10 +363,9 @@ static int blk_trace_setup(request_queue if (!bt->dropped_file) goto err; - bt->rchan = relay_open("trace", dir, buts.buf_size, buts.buf_nr, &blk_relay_callbacks); + bt->rchan = relay_open("trace", dir, buts.buf_size, buts.buf_nr, &blk_relay_callbacks, bt); if (!bt->rchan) goto err; - bt->rchan->private_data = bt; bt->act_mask = buts.act_mask; if (!bt->act_mask) diff --git a/block/cfq-iosched.c b/block/cfq-iosched.c index 07b7062..b6491c0 100644 --- a/block/cfq-iosched.c +++ b/block/cfq-iosched.c @@ -146,9 +146,9 @@ struct cfq_queue { /* fifo list of requests in sort_list */ struct list_head fifo; - unsigned long slice_start; unsigned long slice_end; - unsigned long slice_left; + unsigned long service_last; + long slice_resid; /* number of requests that are on the dispatch list */ int on_dispatch[2]; @@ -162,15 +162,16 @@ struct cfq_queue { }; enum cfqq_state_flags { - CFQ_CFQQ_FLAG_on_rr = 0, - CFQ_CFQQ_FLAG_wait_request, - CFQ_CFQQ_FLAG_must_alloc, - CFQ_CFQQ_FLAG_must_alloc_slice, - CFQ_CFQQ_FLAG_must_dispatch, - CFQ_CFQQ_FLAG_fifo_expire, - CFQ_CFQQ_FLAG_idle_window, - CFQ_CFQQ_FLAG_prio_changed, - CFQ_CFQQ_FLAG_queue_new, + CFQ_CFQQ_FLAG_on_rr = 0, /* on round-robin busy list */ + CFQ_CFQQ_FLAG_wait_request, /* waiting for a request */ + CFQ_CFQQ_FLAG_must_alloc, /* must be allowed rq alloc */ + CFQ_CFQQ_FLAG_must_alloc_slice, /* per-slice must_alloc flag */ + CFQ_CFQQ_FLAG_must_dispatch, /* must dispatch, even if expired */ + CFQ_CFQQ_FLAG_fifo_expire, /* FIFO checked in this slice */ + CFQ_CFQQ_FLAG_idle_window, /* slice idling enabled */ + CFQ_CFQQ_FLAG_prio_changed, /* task priority has changed */ + CFQ_CFQQ_FLAG_queue_new, /* queue never been serviced */ + CFQ_CFQQ_FLAG_slice_new, /* no requests dispatched in slice */ }; #define CFQ_CFQQ_FNS(name) \ @@ -196,6 +197,7 @@ CFQ_CFQQ_FNS(fifo_expire); CFQ_CFQQ_FNS(idle_window); CFQ_CFQQ_FNS(prio_changed); CFQ_CFQQ_FNS(queue_new); +CFQ_CFQQ_FNS(slice_new); #undef CFQ_CFQQ_FNS static struct cfq_queue *cfq_find_cfq_hash(struct cfq_data *, unsigned int, unsigned short); @@ -231,6 +233,50 @@ static inline pid_t cfq_queue_pid(struct } /* + * Scale schedule slice based on io priority. Use the sync time slice only + * if a queue is marked sync and has sync io queued. A sync queue with async + * io only, should not get full sync slice length. + */ +static inline int +cfq_prio_to_slice(struct cfq_data *cfqd, struct cfq_queue *cfqq) +{ + const int base_slice = cfqd->cfq_slice[cfq_cfqq_sync(cfqq)]; + + WARN_ON(cfqq->ioprio >= IOPRIO_BE_NR); + + return base_slice + (base_slice/CFQ_SLICE_SCALE * (4 - cfqq->ioprio)); +} + +static inline void +cfq_set_prio_slice(struct cfq_data *cfqd, struct cfq_queue *cfqq) +{ + cfqq->slice_end = cfq_prio_to_slice(cfqd, cfqq) + jiffies; + cfqq->slice_end += cfqq->slice_resid; + + /* + * Don't carry over residual for more than one slice, we only want + * to slightly correct the fairness. Carrying over forever would + * easily introduce oscillations. + */ + cfqq->slice_resid = 0; +} + +/* + * We need to wrap this check in cfq_cfqq_slice_new(), since ->slice_end + * isn't valid until the first request from the dispatch is activated + * and the slice time set. + */ +static inline int cfq_slice_used(struct cfq_queue *cfqq) +{ + if (cfq_cfqq_slice_new(cfqq)) + return 0; + if (time_before(jiffies, cfqq->slice_end)) + return 0; + + return 1; +} + +/* * Lifted from AS - choose which of rq1 and rq2 that is best served now. * We choose the request that is closest to the head right now. Distance * behind the head is penalized and only allowed to a certain extent. @@ -355,9 +401,14 @@ cfq_find_next_rq(struct cfq_data *cfqd, static void cfq_resort_rr_list(struct cfq_queue *cfqq, int preempted) { struct cfq_data *cfqd = cfqq->cfqd; - struct list_head *list; + struct list_head *list, *n; + struct cfq_queue *__cfqq; - BUG_ON(!cfq_cfqq_on_rr(cfqq)); + /* + * Resorting requires the cfqq to be on the RR list already. + */ + if (!cfq_cfqq_on_rr(cfqq)) + return; list_del(&cfqq->cfq_list); @@ -379,15 +430,13 @@ static void cfq_resort_rr_list(struct cf list = &cfqd->rr_list[cfqq->ioprio]; } - /* - * If this queue was preempted or is new (never been serviced), let - * it be added first for fairness but beind other new queues. - * Otherwise, just add to the back of the list. - */ if (preempted || cfq_cfqq_queue_new(cfqq)) { - struct list_head *n = list; - struct cfq_queue *__cfqq; - + /* + * If this queue was preempted or is new (never been serviced), + * let it be added first for fairness but beind other new + * queues. + */ + n = list; while (n->next != list) { __cfqq = list_entry_cfqq(n->next); if (!cfq_cfqq_queue_new(__cfqq)) @@ -395,11 +444,32 @@ static void cfq_resort_rr_list(struct cf n = n->next; } + list_add_tail(&cfqq->cfq_list, n); + } else if (!cfq_cfqq_class_sync(cfqq)) { + /* + * async queue always goes to the end. this wont be overly + * unfair to writes, as the sort of the sync queue wont be + * allowed to pass the async queue again. + */ + list_add_tail(&cfqq->cfq_list, list); + } else { + /* + * sort by last service, but don't cross a new or async + * queue. we don't cross a new queue because it hasn't been + * service before, and we don't cross an async queue because + * it gets added to the end on expire. + */ + n = list; + while ((n = n->prev) != list) { + struct cfq_queue *__cfqq = list_entry_cfqq(n); - list = n; + if (!cfq_cfqq_class_sync(cfqq) || !__cfqq->service_last) + break; + if (time_before(__cfqq->service_last, cfqq->service_last)) + break; + } + list_add(&cfqq->cfq_list, n); } - - list_add_tail(&cfqq->cfq_list, list); } /* @@ -604,11 +674,10 @@ __cfq_set_active_queue(struct cfq_data * */ del_timer(&cfqd->idle_class_timer); - cfqq->slice_start = jiffies; cfqq->slice_end = 0; - cfqq->slice_left = 0; cfq_clear_cfqq_must_alloc_slice(cfqq); cfq_clear_cfqq_fifo_expire(cfqq); + cfq_mark_cfqq_slice_new(cfqq); } cfqd->active_queue = cfqq; @@ -619,16 +688,11 @@ __cfq_set_active_queue(struct cfq_data * */ static void __cfq_slice_expired(struct cfq_data *cfqd, struct cfq_queue *cfqq, - int preempted) + int preempted, int timed_out) { - unsigned long now = jiffies; - if (cfq_cfqq_wait_request(cfqq)) del_timer(&cfqd->idle_slice_timer); - if (!preempted && !cfq_cfqq_dispatched(cfqq)) - cfq_schedule_dispatch(cfqd); - cfq_clear_cfqq_must_dispatch(cfqq); cfq_clear_cfqq_wait_request(cfqq); cfq_clear_cfqq_queue_new(cfqq); @@ -637,13 +701,10 @@ __cfq_slice_expired(struct cfq_data *cfq * store what was left of this slice, if the queue idled out * or was preempted */ - if (time_after(cfqq->slice_end, now)) - cfqq->slice_left = cfqq->slice_end - now; - else - cfqq->slice_left = 0; + if (timed_out && !cfq_cfqq_slice_new(cfqq)) + cfqq->slice_resid = cfqq->slice_end - jiffies; - if (cfq_cfqq_on_rr(cfqq)) - cfq_resort_rr_list(cfqq, preempted); + cfq_resort_rr_list(cfqq, preempted); if (cfqq == cfqd->active_queue) cfqd->active_queue = NULL; @@ -656,12 +717,13 @@ __cfq_slice_expired(struct cfq_data *cfq cfqd->dispatch_slice = 0; } -static inline void cfq_slice_expired(struct cfq_data *cfqd, int preempted) +static inline void cfq_slice_expired(struct cfq_data *cfqd, int preempted, + int timed_out) { struct cfq_queue *cfqq = cfqd->active_queue; if (cfqq) - __cfq_slice_expired(cfqd, cfqq, preempted); + __cfq_slice_expired(cfqd, cfqq, preempted, timed_out); } /* @@ -758,14 +820,13 @@ static struct cfq_queue *cfq_set_active_ #define CIC_SEEKY(cic) ((cic)->seek_mean > (128 * 1024)) -static int cfq_arm_slice_timer(struct cfq_data *cfqd, struct cfq_queue *cfqq) - +static int cfq_arm_slice_timer(struct cfq_data *cfqd) { + struct cfq_queue *cfqq = cfqd->active_queue; struct cfq_io_context *cic; unsigned long sl; WARN_ON(!RB_EMPTY_ROOT(&cfqq->sort_list)); - WARN_ON(cfqq != cfqd->active_queue); /* * idle is disabled, either manually or by past process history @@ -822,41 +883,21 @@ static inline struct request *cfq_check_ if (cfq_cfqq_fifo_expire(cfqq)) return NULL; + + cfq_mark_cfqq_fifo_expire(cfqq); + if (list_empty(&cfqq->fifo)) return NULL; fifo = cfq_cfqq_class_sync(cfqq); rq = rq_entry_fifo(cfqq->fifo.next); - if (time_after(jiffies, rq->start_time + cfqd->cfq_fifo_expire[fifo])) { - cfq_mark_cfqq_fifo_expire(cfqq); + if (time_after(jiffies, rq->start_time + cfqd->cfq_fifo_expire[fifo])) return rq; - } return NULL; } -/* - * Scale schedule slice based on io priority. Use the sync time slice only - * if a queue is marked sync and has sync io queued. A sync queue with async - * io only, should not get full sync slice length. - */ -static inline int -cfq_prio_to_slice(struct cfq_data *cfqd, struct cfq_queue *cfqq) -{ - const int base_slice = cfqd->cfq_slice[cfq_cfqq_sync(cfqq)]; - - WARN_ON(cfqq->ioprio >= IOPRIO_BE_NR); - - return base_slice + (base_slice/CFQ_SLICE_SCALE * (4 - cfqq->ioprio)); -} - -static inline void -cfq_set_prio_slice(struct cfq_data *cfqd, struct cfq_queue *cfqq) -{ - cfqq->slice_end = cfq_prio_to_slice(cfqd, cfqq) + jiffies; -} - static inline int cfq_prio_to_maxrq(struct cfq_data *cfqd, struct cfq_queue *cfqq) { @@ -872,7 +913,6 @@ cfq_prio_to_maxrq(struct cfq_data *cfqd, */ static struct cfq_queue *cfq_select_queue(struct cfq_data *cfqd) { - unsigned long now = jiffies; struct cfq_queue *cfqq; cfqq = cfqd->active_queue; @@ -882,7 +922,7 @@ static struct cfq_queue *cfq_select_queu /* * slice has expired */ - if (!cfq_cfqq_must_dispatch(cfqq) && time_after(now, cfqq->slice_end)) + if (!cfq_cfqq_must_dispatch(cfqq) && cfq_slice_used(cfqq)) goto expire; /* @@ -891,16 +931,16 @@ static struct cfq_queue *cfq_select_queu */ if (!RB_EMPTY_ROOT(&cfqq->sort_list)) goto keep_queue; - else if (cfq_cfqq_dispatched(cfqq)) { + else if (cfq_cfqq_slice_new(cfqq) || cfq_cfqq_dispatched(cfqq)) { cfqq = NULL; goto keep_queue; } else if (cfq_cfqq_class_sync(cfqq)) { - if (cfq_arm_slice_timer(cfqd, cfqq)) + if (cfq_arm_slice_timer(cfqd)) return NULL; } expire: - cfq_slice_expired(cfqd, 0); + cfq_slice_expired(cfqd, 0, 0); new_queue: cfqq = cfq_set_active_queue(cfqd); keep_queue: @@ -943,20 +983,15 @@ __cfq_dispatch_requests(struct cfq_data } while (dispatched < max_dispatch); /* - * if slice end isn't set yet, set it. - */ - if (!cfqq->slice_end) - cfq_set_prio_slice(cfqd, cfqq); - - /* * expire an async queue immediately if it has used up its slice. idle * queue always expire after 1 dispatch round. */ if ((!cfq_cfqq_sync(cfqq) && cfqd->dispatch_slice >= cfq_prio_to_maxrq(cfqd, cfqq)) || - cfq_class_idle(cfqq) || - !cfq_cfqq_idle_window(cfqq)) - cfq_slice_expired(cfqd, 0); + cfq_class_idle(cfqq)) { + cfqq->slice_end = jiffies + 1; + cfq_slice_expired(cfqd, 0, 0); + } return dispatched; } @@ -991,7 +1026,7 @@ cfq_forced_dispatch(struct cfq_data *cfq dispatched += cfq_forced_dispatch_cfqqs(&cfqd->cur_rr); dispatched += cfq_forced_dispatch_cfqqs(&cfqd->idle_rr); - cfq_slice_expired(cfqd, 0); + cfq_slice_expired(cfqd, 0, 0); BUG_ON(cfqd->busy_queues); @@ -1022,6 +1057,14 @@ cfq_dispatch_requests(request_queue_t *q if (prev_cfqq == cfqq) break; + /* + * So we have dispatched before in this round, if the + * next queue has idling enabled (must be sync), don't + * allow it service until the previous have continued. + */ + if (cfqd->rq_in_driver && cfq_cfqq_idle_window(cfqq)) + break; + cfq_clear_cfqq_must_dispatch(cfqq); cfq_clear_cfqq_wait_request(cfqq); del_timer(&cfqd->idle_slice_timer); @@ -1031,14 +1074,6 @@ cfq_dispatch_requests(request_queue_t *q max_dispatch = 1; dispatched += __cfq_dispatch_requests(cfqd, cfqq, max_dispatch); - - /* - * If the dispatch cfqq has idling enabled and is still - * the active queue, break out. - */ - if (cfq_cfqq_idle_window(cfqq) && cfqd->active_queue) - break; - prev_cfqq = cfqq; } @@ -1064,8 +1099,10 @@ static void cfq_put_queue(struct cfq_que BUG_ON(cfqq->allocated[READ] + cfqq->allocated[WRITE]); BUG_ON(cfq_cfqq_on_rr(cfqq)); - if (unlikely(cfqd->active_queue == cfqq)) - __cfq_slice_expired(cfqd, cfqq, 0); + if (unlikely(cfqd->active_queue == cfqq)) { + __cfq_slice_expired(cfqd, cfqq, 0, 0); + cfq_schedule_dispatch(cfqd); + } /* * it's on the empty list and still hashed @@ -1120,8 +1157,10 @@ static void cfq_free_io_context(struct i static void cfq_exit_cfqq(struct cfq_data *cfqd, struct cfq_queue *cfqq) { - if (unlikely(cfqq == cfqd->active_queue)) - __cfq_slice_expired(cfqd, cfqq, 0); + if (unlikely(cfqq == cfqd->active_queue)) { + __cfq_slice_expired(cfqd, cfqq, 0, 0); + cfq_schedule_dispatch(cfqd); + } cfq_put_queue(cfqq); } @@ -1238,9 +1277,7 @@ static void cfq_init_prio_data(struct cf cfqq->org_ioprio = cfqq->ioprio; cfqq->org_ioprio_class = cfqq->ioprio_class; - if (cfq_cfqq_on_rr(cfqq)) - cfq_resort_rr_list(cfqq, 0); - + cfq_resort_rr_list(cfqq, 0); cfq_clear_cfqq_prio_changed(cfqq); } @@ -1332,10 +1369,7 @@ retry: hlist_add_head(&cfqq->cfq_hash, &cfqd->cfq_hash[hashval]); atomic_set(&cfqq->ref, 0); cfqq->cfqd = cfqd; - /* - * set ->slice_left to allow preemption for a new process - */ - cfqq->slice_left = 2 * cfqd->cfq_slice_idle; + cfq_mark_cfqq_idle_window(cfqq); cfq_mark_cfqq_prio_changed(cfqq); cfq_mark_cfqq_queue_new(cfqq); @@ -1471,22 +1505,8 @@ err: static void cfq_update_io_thinktime(struct cfq_data *cfqd, struct cfq_io_context *cic) { - unsigned long elapsed, ttime; - - /* - * if this context already has stuff queued, thinktime is from - * last queue not last end - */ -#if 0 - if (time_after(cic->last_end_request, cic->last_queue)) - elapsed = jiffies - cic->last_end_request; - else - elapsed = jiffies - cic->last_queue; -#else - elapsed = jiffies - cic->last_end_request; -#endif - - ttime = min(elapsed, 2UL * cfqd->cfq_slice_idle); + unsigned long elapsed = jiffies - cic->last_end_request; + unsigned long ttime = min(elapsed, 2UL * cfqd->cfq_slice_idle); cic->ttime_samples = (7*cic->ttime_samples + 256) / 8; cic->ttime_total = (7*cic->ttime_total + 256*ttime) / 8; @@ -1546,7 +1566,6 @@ cfq_update_idle_window(struct cfq_data * cfq_clear_cfqq_idle_window(cfqq); } - /* * Check if new_cfqq should preempt the currently active queue. Return 0 for * no or if we aren't sure, a 1 will cause a preempt. @@ -1568,11 +1587,6 @@ cfq_should_preempt(struct cfq_data *cfqd if (!cfq_cfqq_wait_request(new_cfqq)) return 0; /* - * if it doesn't have slice left, forget it - */ - if (new_cfqq->slice_left < cfqd->cfq_slice_idle) - return 0; - /* * if the new request is sync, but the currently running queue is * not, let the sync request have priority. */ @@ -1594,10 +1608,7 @@ cfq_should_preempt(struct cfq_data *cfqd */ static void cfq_preempt_queue(struct cfq_data *cfqd, struct cfq_queue *cfqq) { - cfq_slice_expired(cfqd, 1); - - if (!cfqq->slice_left) - cfqq->slice_left = cfq_prio_to_slice(cfqd, cfqq) / 2; + cfq_slice_expired(cfqd, 1, 1); /* * Put the new queue at the front of the of the current list, @@ -1606,7 +1617,8 @@ static void cfq_preempt_queue(struct cfq BUG_ON(!cfq_cfqq_on_rr(cfqq)); list_move(&cfqq->cfq_list, &cfqd->cur_rr); - cfqq->slice_end = cfqq->slice_left + jiffies; + cfqq->slice_end = 0; + cfq_mark_cfqq_slice_new(cfqq); } /* @@ -1639,7 +1651,7 @@ cfq_rq_enqueued(struct cfq_data *cfqd, s */ if (cic == cfqd->active_cic && del_timer(&cfqd->idle_slice_timer)) { - cfq_slice_expired(cfqd, 0); + cfq_slice_expired(cfqd, 0, 0); blk_start_queueing(cfqd->queue); } return; @@ -1649,7 +1661,6 @@ cfq_rq_enqueued(struct cfq_data *cfqd, s cfq_update_io_seektime(cic, rq); cfq_update_idle_window(cfqd, cfqq, cic); - cic->last_queue = jiffies; cic->last_request_pos = rq->sector + rq->nr_sectors; if (cfqq == cfqd->active_queue) { @@ -1702,12 +1713,12 @@ static void cfq_completed_request(reques WARN_ON(!cfqq->on_dispatch[sync]); cfqd->rq_in_driver--; cfqq->on_dispatch[sync]--; + cfqq->service_last = now; if (!cfq_class_idle(cfqq)) cfqd->last_end_request = now; - if (!cfq_cfqq_dispatched(cfqq) && cfq_cfqq_on_rr(cfqq)) - cfq_resort_rr_list(cfqq, 0); + cfq_resort_rr_list(cfqq, 0); if (sync) RQ_CIC(rq)->last_end_request = now; @@ -1717,10 +1728,14 @@ static void cfq_completed_request(reques * or if we want to idle in case it has no pending requests. */ if (cfqd->active_queue == cfqq) { - if (time_after(now, cfqq->slice_end)) - cfq_slice_expired(cfqd, 0); + if (cfq_cfqq_slice_new(cfqq)) { + cfq_set_prio_slice(cfqd, cfqq); + cfq_clear_cfqq_slice_new(cfqq); + } + if (cfq_slice_used(cfqq)) + cfq_slice_expired(cfqd, 0, 1); else if (sync && RB_EMPTY_ROOT(&cfqq->sort_list)) { - if (!cfq_arm_slice_timer(cfqd, cfqq)) + if (!cfq_arm_slice_timer(cfqd)) cfq_schedule_dispatch(cfqd); } } @@ -1757,8 +1772,7 @@ static void cfq_prio_boost(struct cfq_qu /* * refile between round-robin lists if we moved the priority class */ - if ((ioprio_class != cfqq->ioprio_class || ioprio != cfqq->ioprio) && - cfq_cfqq_on_rr(cfqq)) + if ((ioprio_class != cfqq->ioprio_class || ioprio != cfqq->ioprio)) cfq_resort_rr_list(cfqq, 0); } @@ -1893,16 +1907,17 @@ static void cfq_idle_slice_timer(unsigne struct cfq_data *cfqd = (struct cfq_data *) data; struct cfq_queue *cfqq; unsigned long flags; + int timed_out = 1; spin_lock_irqsave(cfqd->queue->queue_lock, flags); if ((cfqq = cfqd->active_queue) != NULL) { - unsigned long now = jiffies; + timed_out = 0; /* * expired */ - if (time_after(now, cfqq->slice_end)) + if (cfq_slice_used(cfqq)) goto expire; /* @@ -1921,7 +1936,7 @@ static void cfq_idle_slice_timer(unsigne } } expire: - cfq_slice_expired(cfqd, 0); + cfq_slice_expired(cfqd, 0, timed_out); out_kick: cfq_schedule_dispatch(cfqd); out_cont: @@ -1967,7 +1982,7 @@ static void cfq_exit_queue(elevator_t *e spin_lock_irq(q->queue_lock); if (cfqd->active_queue) - __cfq_slice_expired(cfqd, cfqd->active_queue, 0); + __cfq_slice_expired(cfqd, cfqd->active_queue, 0, 0); while (!list_empty(&cfqd->cic_list)) { struct cfq_io_context *cic = list_entry(cfqd->cic_list.next, diff --git a/block/elevator.c b/block/elevator.c index f6dafa8..25f6ef2 100644 --- a/block/elevator.c +++ b/block/elevator.c @@ -269,6 +269,22 @@ void elevator_exit(elevator_t *e) EXPORT_SYMBOL(elevator_exit); +static void elv_activate_rq(request_queue_t *q, struct request *rq) +{ + elevator_t *e = q->elevator; + + if (e->ops->elevator_activate_req_fn) + e->ops->elevator_activate_req_fn(q, rq); +} + +static void elv_deactivate_rq(request_queue_t *q, struct request *rq) +{ + elevator_t *e = q->elevator; + + if (e->ops->elevator_deactivate_req_fn) + e->ops->elevator_deactivate_req_fn(q, rq); +} + static inline void __elv_rqhash_del(struct request *rq) { hlist_del_init(&rq->hash); @@ -397,6 +413,8 @@ void elv_dispatch_sort(request_queue_t * list_for_each_prev(entry, &q->queue_head) { struct request *pos = list_entry_rq(entry); + if (rq_data_dir(rq) != rq_data_dir(pos)) + break; if (pos->cmd_flags & (REQ_SOFTBARRIER|REQ_HARDBARRIER|REQ_STARTED)) break; if (rq->sector >= boundary) { @@ -498,16 +516,14 @@ void elv_merge_requests(request_queue_t void elv_requeue_request(request_queue_t *q, struct request *rq) { - elevator_t *e = q->elevator; - /* * it already went through dequeue, we need to decrement the * in_flight count again */ if (blk_account_rq(rq)) { q->in_flight--; - if (blk_sorted_rq(rq) && e->ops->elevator_deactivate_req_fn) - e->ops->elevator_deactivate_req_fn(q, rq); + if (blk_sorted_rq(rq)) + elv_deactivate_rq(q, rq); } rq->cmd_flags &= ~REQ_STARTED; @@ -700,16 +716,13 @@ struct request *elv_next_request(request while ((rq = __elv_next_request(q)) != NULL) { if (!(rq->cmd_flags & REQ_STARTED)) { - elevator_t *e = q->elevator; - /* * This is the first time the device driver * sees this request (possibly after * requeueing). Notify IO scheduler. */ - if (blk_sorted_rq(rq) && - e->ops->elevator_activate_req_fn) - e->ops->elevator_activate_req_fn(q, rq); + if (blk_sorted_rq(rq)) + elv_activate_rq(q, rq); /* * just mark as started even if we don't start diff --git a/block/genhd.c b/block/genhd.c index 457fdac..36bd3e1 100644 --- a/block/genhd.c +++ b/block/genhd.c @@ -61,6 +61,14 @@ int register_blkdev(unsigned int major, /* temporary */ if (major == 0) { for (index = ARRAY_SIZE(major_names)-1; index > 0; index--) { + /* + * Disallow the LANANA-assigned LOCAL/EXPERIMENTAL + * majors + */ + if ((60 <= index && index <= 63) || + (120 <= index && index <= 127) || + (240 <= index && index <= 254)) + continue; if (major_names[index] == NULL) break; } diff --git a/block/ioctl.c b/block/ioctl.c index f6962b6..e3f5eb9 100644 --- a/block/ioctl.c +++ b/block/ioctl.c @@ -61,7 +61,7 @@ static int blkpg_ioctl(struct block_devi } } /* all seems OK */ - add_partition(disk, part, start, length); + add_partition(disk, part, start, length, ADDPART_FLAG_NONE); mutex_unlock(&bdev->bd_mutex); return 0; case BLKPG_DEL_PARTITION: diff --git a/block/ll_rw_blk.c b/block/ll_rw_blk.c index fb67897..38c293b 100644 --- a/block/ll_rw_blk.c +++ b/block/ll_rw_blk.c @@ -1264,7 +1264,7 @@ new_hw_segment: bio->bi_hw_segments = nr_hw_segs; bio->bi_flags |= (1 << BIO_SEG_VALID); } - +EXPORT_SYMBOL(blk_recount_segments); static int blk_phys_contig_segment(request_queue_t *q, struct bio *bio, struct bio *nxt) diff --git a/crypto/Kconfig b/crypto/Kconfig index 92ba249..086fcec 100644 --- a/crypto/Kconfig +++ b/crypto/Kconfig @@ -74,14 +74,6 @@ config CRYPTO_SHA1 help SHA-1 secure hash standard (FIPS 180-1/DFIPS 180-2). -config CRYPTO_SHA1_S390 - tristate "SHA1 digest algorithm (s390)" - depends on S390 - select CRYPTO_ALGAPI - help - This is the s390 hardware accelerated implementation of the - SHA-1 secure hash standard (FIPS 180-1/DFIPS 180-2). - config CRYPTO_SHA256 tristate "SHA256 digest algorithm" select CRYPTO_ALGAPI @@ -91,17 +83,6 @@ config CRYPTO_SHA256 This version of SHA implements a 256 bit hash with 128 bits of security against collision attacks. -config CRYPTO_SHA256_S390 - tristate "SHA256 digest algorithm (s390)" - depends on S390 - select CRYPTO_ALGAPI - help - This is the s390 hardware accelerated implementation of the - SHA256 secure hash standard (DFIPS 180-2). - - This version of SHA implements a 256 bit hash with 128 bits of - security against collision attacks. - config CRYPTO_SHA512 tristate "SHA384 and SHA512 digest algorithms" select CRYPTO_ALGAPI @@ -168,6 +149,15 @@ config CRYPTO_CBC CBC: Cipher Block Chaining mode This block cipher algorithm is required for IPSec. +config CRYPTO_PCBC + tristate "PCBC support" + select CRYPTO_BLKCIPHER + select CRYPTO_MANAGER + default m + help + PCBC: Propagating Cipher Block Chaining mode + This block cipher algorithm is required for RxRPC. + config CRYPTO_LRW tristate "LRW support (EXPERIMENTAL)" depends on EXPERIMENTAL @@ -187,13 +177,12 @@ config CRYPTO_DES help DES cipher algorithm (FIPS 46-2), and Triple DES EDE (FIPS 46-3). -config CRYPTO_DES_S390 - tristate "DES and Triple DES cipher algorithms (s390)" - depends on S390 +config CRYPTO_FCRYPT + tristate "FCrypt cipher algorithm" select CRYPTO_ALGAPI select CRYPTO_BLKCIPHER help - DES cipher algorithm (FIPS 46-2), and Triple DES EDE (FIPS 46-3). + FCrypt algorithm used by RxRPC. config CRYPTO_BLOWFISH tristate "Blowfish cipher algorithm" @@ -336,28 +325,6 @@ config CRYPTO_AES_X86_64 See for more information. -config CRYPTO_AES_S390 - tristate "AES cipher algorithms (s390)" - depends on S390 - select CRYPTO_ALGAPI - select CRYPTO_BLKCIPHER - help - This is the s390 hardware accelerated implementation of the - AES cipher algorithms (FIPS-197). AES uses the Rijndael - algorithm. - - Rijndael appears to be consistently a very good performer in - both hardware and software across a wide range of computing - environments regardless of its use in feedback or non-feedback - modes. Its key setup time is excellent, and its key agility is - good. Rijndael's very low memory requirements make it very well - suited for restricted-space environments, in which it also - demonstrates excellent performance. Rijndael's operations are - among the easiest to defend against power and timing attacks. - - On s390 the System z9-109 currently only supports the key size - of 128 bit. - config CRYPTO_CAST5 tristate "CAST5 (CAST-128) cipher algorithm" select CRYPTO_ALGAPI @@ -458,6 +425,21 @@ config CRYPTO_CRC32C See Castagnoli93. This implementation uses lib/libcrc32c. Module will be crc32c. +config CRYPTO_CAMELLIA + tristate "Camellia cipher algorithms" + depends on CRYPTO + select CRYPTO_ALGAPI + help + Camellia cipher algorithms module. + + Camellia is a symmetric key block cipher developed jointly + at NTT and Mitsubishi Electric Corporation. + + The Camellia specifies three key sizes: 128, 192 and 256 bits. + + See also: + + config CRYPTO_TEST tristate "Testing module" depends on m diff --git a/crypto/Makefile b/crypto/Makefile index 60e3d24..12f93f5 100644 --- a/crypto/Makefile +++ b/crypto/Makefile @@ -27,13 +27,16 @@ obj-$(CONFIG_CRYPTO_TGR192) += tgr192.o obj-$(CONFIG_CRYPTO_GF128MUL) += gf128mul.o obj-$(CONFIG_CRYPTO_ECB) += ecb.o obj-$(CONFIG_CRYPTO_CBC) += cbc.o +obj-$(CONFIG_CRYPTO_PCBC) += pcbc.o obj-$(CONFIG_CRYPTO_LRW) += lrw.o obj-$(CONFIG_CRYPTO_DES) += des.o +obj-$(CONFIG_CRYPTO_FCRYPT) += fcrypt.o obj-$(CONFIG_CRYPTO_BLOWFISH) += blowfish.o obj-$(CONFIG_CRYPTO_TWOFISH) += twofish.o obj-$(CONFIG_CRYPTO_TWOFISH_COMMON) += twofish_common.o obj-$(CONFIG_CRYPTO_SERPENT) += serpent.o obj-$(CONFIG_CRYPTO_AES) += aes.o +obj-$(CONFIG_CRYPTO_CAMELLIA) += camellia.o obj-$(CONFIG_CRYPTO_CAST5) += cast5.o obj-$(CONFIG_CRYPTO_CAST6) += cast6.o obj-$(CONFIG_CRYPTO_ARC4) += arc4.o diff --git a/crypto/algapi.c b/crypto/algapi.c index c915300..f7d2185 100644 --- a/crypto/algapi.c +++ b/crypto/algapi.c @@ -377,7 +377,8 @@ void crypto_drop_spawn(struct crypto_spa } EXPORT_SYMBOL_GPL(crypto_drop_spawn); -struct crypto_tfm *crypto_spawn_tfm(struct crypto_spawn *spawn) +struct crypto_tfm *crypto_spawn_tfm(struct crypto_spawn *spawn, u32 type, + u32 mask) { struct crypto_alg *alg; struct crypto_alg *alg2; @@ -396,10 +397,18 @@ struct crypto_tfm *crypto_spawn_tfm(stru return ERR_PTR(-EAGAIN); } - tfm = __crypto_alloc_tfm(alg, 0); + tfm = ERR_PTR(-EINVAL); + if (unlikely((alg->cra_flags ^ type) & mask)) + goto out_put_alg; + + tfm = __crypto_alloc_tfm(alg, type, mask); if (IS_ERR(tfm)) - crypto_mod_put(alg); + goto out_put_alg; + + return tfm; +out_put_alg: + crypto_mod_put(alg); return tfm; } EXPORT_SYMBOL_GPL(crypto_spawn_tfm); diff --git a/crypto/api.c b/crypto/api.c index 8c44687..55af8bb 100644 --- a/crypto/api.c +++ b/crypto/api.c @@ -212,31 +212,12 @@ struct crypto_alg *crypto_alg_mod_lookup } EXPORT_SYMBOL_GPL(crypto_alg_mod_lookup); -static int crypto_init_flags(struct crypto_tfm *tfm, u32 flags) +static int crypto_init_ops(struct crypto_tfm *tfm, u32 type, u32 mask) { - tfm->crt_flags = flags & CRYPTO_TFM_REQ_MASK; - flags &= ~CRYPTO_TFM_REQ_MASK; - - switch (crypto_tfm_alg_type(tfm)) { - case CRYPTO_ALG_TYPE_CIPHER: - return crypto_init_cipher_flags(tfm, flags); - - case CRYPTO_ALG_TYPE_DIGEST: - return crypto_init_digest_flags(tfm, flags); - - case CRYPTO_ALG_TYPE_COMPRESS: - return crypto_init_compress_flags(tfm, flags); - } - - return 0; -} + const struct crypto_type *type_obj = tfm->__crt_alg->cra_type; -static int crypto_init_ops(struct crypto_tfm *tfm) -{ - const struct crypto_type *type = tfm->__crt_alg->cra_type; - - if (type) - return type->init(tfm); + if (type_obj) + return type_obj->init(tfm, type, mask); switch (crypto_tfm_alg_type(tfm)) { case CRYPTO_ALG_TYPE_CIPHER: @@ -285,29 +266,29 @@ static void crypto_exit_ops(struct crypt } } -static unsigned int crypto_ctxsize(struct crypto_alg *alg, int flags) +static unsigned int crypto_ctxsize(struct crypto_alg *alg, u32 type, u32 mask) { - const struct crypto_type *type = alg->cra_type; + const struct crypto_type *type_obj = alg->cra_type; unsigned int len; len = alg->cra_alignmask & ~(crypto_tfm_ctx_alignment() - 1); - if (type) - return len + type->ctxsize(alg); + if (type_obj) + return len + type_obj->ctxsize(alg, type, mask); switch (alg->cra_flags & CRYPTO_ALG_TYPE_MASK) { default: BUG(); case CRYPTO_ALG_TYPE_CIPHER: - len += crypto_cipher_ctxsize(alg, flags); + len += crypto_cipher_ctxsize(alg); break; case CRYPTO_ALG_TYPE_DIGEST: - len += crypto_digest_ctxsize(alg, flags); + len += crypto_digest_ctxsize(alg); break; case CRYPTO_ALG_TYPE_COMPRESS: - len += crypto_compress_ctxsize(alg, flags); + len += crypto_compress_ctxsize(alg); break; } @@ -322,24 +303,21 @@ void crypto_shoot_alg(struct crypto_alg } EXPORT_SYMBOL_GPL(crypto_shoot_alg); -struct crypto_tfm *__crypto_alloc_tfm(struct crypto_alg *alg, u32 flags) +struct crypto_tfm *__crypto_alloc_tfm(struct crypto_alg *alg, u32 type, + u32 mask) { struct crypto_tfm *tfm = NULL; unsigned int tfm_size; int err = -ENOMEM; - tfm_size = sizeof(*tfm) + crypto_ctxsize(alg, flags); + tfm_size = sizeof(*tfm) + crypto_ctxsize(alg, type, mask); tfm = kzalloc(tfm_size, GFP_KERNEL); if (tfm == NULL) goto out_err; tfm->__crt_alg = alg; - err = crypto_init_flags(tfm, flags); - if (err) - goto out_free_tfm; - - err = crypto_init_ops(tfm); + err = crypto_init_ops(tfm, type, mask); if (err) goto out_free_tfm; @@ -362,31 +340,6 @@ out: } EXPORT_SYMBOL_GPL(__crypto_alloc_tfm); -struct crypto_tfm *crypto_alloc_tfm(const char *name, u32 flags) -{ - struct crypto_tfm *tfm = NULL; - int err; - - do { - struct crypto_alg *alg; - - alg = crypto_alg_mod_lookup(name, 0, CRYPTO_ALG_ASYNC); - err = PTR_ERR(alg); - if (IS_ERR(alg)) - continue; - - tfm = __crypto_alloc_tfm(alg, flags); - err = 0; - if (IS_ERR(tfm)) { - crypto_mod_put(alg); - err = PTR_ERR(tfm); - tfm = NULL; - } - } while (err == -EAGAIN && !signal_pending(current)); - - return tfm; -} - /* * crypto_alloc_base - Locate algorithm and allocate transform * @alg_name: Name of algorithm @@ -420,7 +373,7 @@ struct crypto_tfm *crypto_alloc_base(con goto err; } - tfm = __crypto_alloc_tfm(alg, 0); + tfm = __crypto_alloc_tfm(alg, type, mask); if (!IS_ERR(tfm)) return tfm; @@ -466,7 +419,6 @@ void crypto_free_tfm(struct crypto_tfm * kfree(tfm); } -EXPORT_SYMBOL_GPL(crypto_alloc_tfm); EXPORT_SYMBOL_GPL(crypto_free_tfm); int crypto_has_alg(const char *name, u32 type, u32 mask) diff --git a/crypto/blkcipher.c b/crypto/blkcipher.c index 6e93004..b5befe8 100644 --- a/crypto/blkcipher.c +++ b/crypto/blkcipher.c @@ -16,6 +16,7 @@ #include #include +#include #include #include #include @@ -313,6 +314,9 @@ static int blkcipher_walk_first(struct b struct crypto_blkcipher *tfm = desc->tfm; unsigned int alignmask = crypto_blkcipher_alignmask(tfm); + if (WARN_ON_ONCE(in_irq())) + return -EDEADLK; + walk->nbytes = walk->total; if (unlikely(!walk->total)) return 0; @@ -345,7 +349,8 @@ static int setkey(struct crypto_tfm *tfm return cipher->setkey(tfm, key, keylen); } -static unsigned int crypto_blkcipher_ctxsize(struct crypto_alg *alg) +static unsigned int crypto_blkcipher_ctxsize(struct crypto_alg *alg, u32 type, + u32 mask) { struct blkcipher_alg *cipher = &alg->cra_blkcipher; unsigned int len = alg->cra_ctxsize; @@ -358,7 +363,7 @@ static unsigned int crypto_blkcipher_ctx return len; } -static int crypto_init_blkcipher_ops(struct crypto_tfm *tfm) +static int crypto_init_blkcipher_ops(struct crypto_tfm *tfm, u32 type, u32 mask) { struct blkcipher_tfm *crt = &tfm->crt_blkcipher; struct blkcipher_alg *alg = &tfm->__crt_alg->cra_blkcipher; diff --git a/crypto/camellia.c b/crypto/camellia.c new file mode 100644 index 0000000..6877ecf --- /dev/null +++ b/crypto/camellia.c @@ -0,0 +1,1801 @@ +/* + * Copyright (C) 2006 + * NTT (Nippon Telegraph and Telephone Corporation). + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +/* + * Algorithm Specification + * http://info.isl.ntt.co.jp/crypt/eng/camellia/specifications.html + */ + +/* + * + * NOTE --- NOTE --- NOTE --- NOTE + * This implementation assumes that all memory addresses passed + * as parameters are four-byte aligned. + * + */ + +#include +#include +#include +#include +#include + + +#define CAMELLIA_MIN_KEY_SIZE 16 +#define CAMELLIA_MAX_KEY_SIZE 32 +#define CAMELLIA_BLOCK_SIZE 16 +#define CAMELLIA_TABLE_BYTE_LEN 272 +#define CAMELLIA_TABLE_WORD_LEN (CAMELLIA_TABLE_BYTE_LEN / 4) + +typedef u32 KEY_TABLE_TYPE[CAMELLIA_TABLE_WORD_LEN]; + + +/* key constants */ + +#define CAMELLIA_SIGMA1L (0xA09E667FL) +#define CAMELLIA_SIGMA1R (0x3BCC908BL) +#define CAMELLIA_SIGMA2L (0xB67AE858L) +#define CAMELLIA_SIGMA2R (0x4CAA73B2L) +#define CAMELLIA_SIGMA3L (0xC6EF372FL) +#define CAMELLIA_SIGMA3R (0xE94F82BEL) +#define CAMELLIA_SIGMA4L (0x54FF53A5L) +#define CAMELLIA_SIGMA4R (0xF1D36F1CL) +#define CAMELLIA_SIGMA5L (0x10E527FAL) +#define CAMELLIA_SIGMA5R (0xDE682D1DL) +#define CAMELLIA_SIGMA6L (0xB05688C2L) +#define CAMELLIA_SIGMA6R (0xB3E6C1FDL) + +struct camellia_ctx { + int key_length; + KEY_TABLE_TYPE key_table; +}; + + +/* + * macros + */ + + +# define GETU32(pt) (((u32)(pt)[0] << 24) \ + ^ ((u32)(pt)[1] << 16) \ + ^ ((u32)(pt)[2] << 8) \ + ^ ((u32)(pt)[3])) + +#define COPY4WORD(dst, src) \ + do { \ + (dst)[0]=(src)[0]; \ + (dst)[1]=(src)[1]; \ + (dst)[2]=(src)[2]; \ + (dst)[3]=(src)[3]; \ + }while(0) + +#define SWAP4WORD(word) \ + do { \ + CAMELLIA_SWAP4((word)[0]); \ + CAMELLIA_SWAP4((word)[1]); \ + CAMELLIA_SWAP4((word)[2]); \ + CAMELLIA_SWAP4((word)[3]); \ + }while(0) + +#define XOR4WORD(a, b)/* a = a ^ b */ \ + do { \ + (a)[0]^=(b)[0]; \ + (a)[1]^=(b)[1]; \ + (a)[2]^=(b)[2]; \ + (a)[3]^=(b)[3]; \ + }while(0) + +#define XOR4WORD2(a, b, c)/* a = b ^ c */ \ + do { \ + (a)[0]=(b)[0]^(c)[0]; \ + (a)[1]=(b)[1]^(c)[1]; \ + (a)[2]=(b)[2]^(c)[2]; \ + (a)[3]=(b)[3]^(c)[3]; \ + }while(0) + +#define CAMELLIA_SUBKEY_L(INDEX) (subkey[(INDEX)*2]) +#define CAMELLIA_SUBKEY_R(INDEX) (subkey[(INDEX)*2 + 1]) + +/* rotation right shift 1byte */ +#define CAMELLIA_RR8(x) (((x) >> 8) + ((x) << 24)) +/* rotation left shift 1bit */ +#define CAMELLIA_RL1(x) (((x) << 1) + ((x) >> 31)) +/* rotation left shift 1byte */ +#define CAMELLIA_RL8(x) (((x) << 8) + ((x) >> 24)) + +#define CAMELLIA_ROLDQ(ll, lr, rl, rr, w0, w1, bits) \ + do { \ + w0 = ll; \ + ll = (ll << bits) + (lr >> (32 - bits)); \ + lr = (lr << bits) + (rl >> (32 - bits)); \ + rl = (rl << bits) + (rr >> (32 - bits)); \ + rr = (rr << bits) + (w0 >> (32 - bits)); \ + } while(0) + +#define CAMELLIA_ROLDQo32(ll, lr, rl, rr, w0, w1, bits) \ + do { \ + w0 = ll; \ + w1 = lr; \ + ll = (lr << (bits - 32)) + (rl >> (64 - bits)); \ + lr = (rl << (bits - 32)) + (rr >> (64 - bits)); \ + rl = (rr << (bits - 32)) + (w0 >> (64 - bits)); \ + rr = (w0 << (bits - 32)) + (w1 >> (64 - bits)); \ + } while(0) + +#define CAMELLIA_SP1110(INDEX) (camellia_sp1110[(INDEX)]) +#define CAMELLIA_SP0222(INDEX) (camellia_sp0222[(INDEX)]) +#define CAMELLIA_SP3033(INDEX) (camellia_sp3033[(INDEX)]) +#define CAMELLIA_SP4404(INDEX) (camellia_sp4404[(INDEX)]) + +#define CAMELLIA_F(xl, xr, kl, kr, yl, yr, il, ir, t0, t1) \ + do { \ + il = xl ^ kl; \ + ir = xr ^ kr; \ + t0 = il >> 16; \ + t1 = ir >> 16; \ + yl = CAMELLIA_SP1110(ir & 0xff) \ + ^ CAMELLIA_SP0222((t1 >> 8) & 0xff) \ + ^ CAMELLIA_SP3033(t1 & 0xff) \ + ^ CAMELLIA_SP4404((ir >> 8) & 0xff); \ + yr = CAMELLIA_SP1110((t0 >> 8) & 0xff) \ + ^ CAMELLIA_SP0222(t0 & 0xff) \ + ^ CAMELLIA_SP3033((il >> 8) & 0xff) \ + ^ CAMELLIA_SP4404(il & 0xff); \ + yl ^= yr; \ + yr = CAMELLIA_RR8(yr); \ + yr ^= yl; \ + } while(0) + + +/* + * for speed up + * + */ +#define CAMELLIA_FLS(ll, lr, rl, rr, kll, klr, krl, krr, t0, t1, t2, t3) \ + do { \ + t0 = kll; \ + t2 = krr; \ + t0 &= ll; \ + t2 |= rr; \ + rl ^= t2; \ + lr ^= CAMELLIA_RL1(t0); \ + t3 = krl; \ + t1 = klr; \ + t3 &= rl; \ + t1 |= lr; \ + ll ^= t1; \ + rr ^= CAMELLIA_RL1(t3); \ + } while(0) + +#define CAMELLIA_ROUNDSM(xl, xr, kl, kr, yl, yr, il, ir, t0, t1) \ + do { \ + ir = CAMELLIA_SP1110(xr & 0xff); \ + il = CAMELLIA_SP1110((xl>>24) & 0xff); \ + ir ^= CAMELLIA_SP0222((xr>>24) & 0xff); \ + il ^= CAMELLIA_SP0222((xl>>16) & 0xff); \ + ir ^= CAMELLIA_SP3033((xr>>16) & 0xff); \ + il ^= CAMELLIA_SP3033((xl>>8) & 0xff); \ + ir ^= CAMELLIA_SP4404((xr>>8) & 0xff); \ + il ^= CAMELLIA_SP4404(xl & 0xff); \ + il ^= kl; \ + ir ^= il ^ kr; \ + yl ^= ir; \ + yr ^= CAMELLIA_RR8(il) ^ ir; \ + } while(0) + +/** + * Stuff related to the Camellia key schedule + */ +#define SUBL(x) subL[(x)] +#define SUBR(x) subR[(x)] + + +static const u32 camellia_sp1110[256] = { + 0x70707000,0x82828200,0x2c2c2c00,0xececec00, + 0xb3b3b300,0x27272700,0xc0c0c000,0xe5e5e500, + 0xe4e4e400,0x85858500,0x57575700,0x35353500, + 0xeaeaea00,0x0c0c0c00,0xaeaeae00,0x41414100, + 0x23232300,0xefefef00,0x6b6b6b00,0x93939300, + 0x45454500,0x19191900,0xa5a5a500,0x21212100, + 0xededed00,0x0e0e0e00,0x4f4f4f00,0x4e4e4e00, + 0x1d1d1d00,0x65656500,0x92929200,0xbdbdbd00, + 0x86868600,0xb8b8b800,0xafafaf00,0x8f8f8f00, + 0x7c7c7c00,0xebebeb00,0x1f1f1f00,0xcecece00, + 0x3e3e3e00,0x30303000,0xdcdcdc00,0x5f5f5f00, + 0x5e5e5e00,0xc5c5c500,0x0b0b0b00,0x1a1a1a00, + 0xa6a6a600,0xe1e1e100,0x39393900,0xcacaca00, + 0xd5d5d500,0x47474700,0x5d5d5d00,0x3d3d3d00, + 0xd9d9d900,0x01010100,0x5a5a5a00,0xd6d6d600, + 0x51515100,0x56565600,0x6c6c6c00,0x4d4d4d00, + 0x8b8b8b00,0x0d0d0d00,0x9a9a9a00,0x66666600, + 0xfbfbfb00,0xcccccc00,0xb0b0b000,0x2d2d2d00, + 0x74747400,0x12121200,0x2b2b2b00,0x20202000, + 0xf0f0f000,0xb1b1b100,0x84848400,0x99999900, + 0xdfdfdf00,0x4c4c4c00,0xcbcbcb00,0xc2c2c200, + 0x34343400,0x7e7e7e00,0x76767600,0x05050500, + 0x6d6d6d00,0xb7b7b700,0xa9a9a900,0x31313100, + 0xd1d1d100,0x17171700,0x04040400,0xd7d7d700, + 0x14141400,0x58585800,0x3a3a3a00,0x61616100, + 0xdedede00,0x1b1b1b00,0x11111100,0x1c1c1c00, + 0x32323200,0x0f0f0f00,0x9c9c9c00,0x16161600, + 0x53535300,0x18181800,0xf2f2f200,0x22222200, + 0xfefefe00,0x44444400,0xcfcfcf00,0xb2b2b200, + 0xc3c3c300,0xb5b5b500,0x7a7a7a00,0x91919100, + 0x24242400,0x08080800,0xe8e8e800,0xa8a8a800, + 0x60606000,0xfcfcfc00,0x69696900,0x50505000, + 0xaaaaaa00,0xd0d0d000,0xa0a0a000,0x7d7d7d00, + 0xa1a1a100,0x89898900,0x62626200,0x97979700, + 0x54545400,0x5b5b5b00,0x1e1e1e00,0x95959500, + 0xe0e0e000,0xffffff00,0x64646400,0xd2d2d200, + 0x10101000,0xc4c4c400,0x00000000,0x48484800, + 0xa3a3a300,0xf7f7f700,0x75757500,0xdbdbdb00, + 0x8a8a8a00,0x03030300,0xe6e6e600,0xdadada00, + 0x09090900,0x3f3f3f00,0xdddddd00,0x94949400, + 0x87878700,0x5c5c5c00,0x83838300,0x02020200, + 0xcdcdcd00,0x4a4a4a00,0x90909000,0x33333300, + 0x73737300,0x67676700,0xf6f6f600,0xf3f3f300, + 0x9d9d9d00,0x7f7f7f00,0xbfbfbf00,0xe2e2e200, + 0x52525200,0x9b9b9b00,0xd8d8d800,0x26262600, + 0xc8c8c800,0x37373700,0xc6c6c600,0x3b3b3b00, + 0x81818100,0x96969600,0x6f6f6f00,0x4b4b4b00, + 0x13131300,0xbebebe00,0x63636300,0x2e2e2e00, + 0xe9e9e900,0x79797900,0xa7a7a700,0x8c8c8c00, + 0x9f9f9f00,0x6e6e6e00,0xbcbcbc00,0x8e8e8e00, + 0x29292900,0xf5f5f500,0xf9f9f900,0xb6b6b600, + 0x2f2f2f00,0xfdfdfd00,0xb4b4b400,0x59595900, + 0x78787800,0x98989800,0x06060600,0x6a6a6a00, + 0xe7e7e700,0x46464600,0x71717100,0xbababa00, + 0xd4d4d400,0x25252500,0xababab00,0x42424200, + 0x88888800,0xa2a2a200,0x8d8d8d00,0xfafafa00, + 0x72727200,0x07070700,0xb9b9b900,0x55555500, + 0xf8f8f800,0xeeeeee00,0xacacac00,0x0a0a0a00, + 0x36363600,0x49494900,0x2a2a2a00,0x68686800, + 0x3c3c3c00,0x38383800,0xf1f1f100,0xa4a4a400, + 0x40404000,0x28282800,0xd3d3d300,0x7b7b7b00, + 0xbbbbbb00,0xc9c9c900,0x43434300,0xc1c1c100, + 0x15151500,0xe3e3e300,0xadadad00,0xf4f4f400, + 0x77777700,0xc7c7c700,0x80808000,0x9e9e9e00, +}; + +static const u32 camellia_sp0222[256] = { + 0x00e0e0e0,0x00050505,0x00585858,0x00d9d9d9, + 0x00676767,0x004e4e4e,0x00818181,0x00cbcbcb, + 0x00c9c9c9,0x000b0b0b,0x00aeaeae,0x006a6a6a, + 0x00d5d5d5,0x00181818,0x005d5d5d,0x00828282, + 0x00464646,0x00dfdfdf,0x00d6d6d6,0x00272727, + 0x008a8a8a,0x00323232,0x004b4b4b,0x00424242, + 0x00dbdbdb,0x001c1c1c,0x009e9e9e,0x009c9c9c, + 0x003a3a3a,0x00cacaca,0x00252525,0x007b7b7b, + 0x000d0d0d,0x00717171,0x005f5f5f,0x001f1f1f, + 0x00f8f8f8,0x00d7d7d7,0x003e3e3e,0x009d9d9d, + 0x007c7c7c,0x00606060,0x00b9b9b9,0x00bebebe, + 0x00bcbcbc,0x008b8b8b,0x00161616,0x00343434, + 0x004d4d4d,0x00c3c3c3,0x00727272,0x00959595, + 0x00ababab,0x008e8e8e,0x00bababa,0x007a7a7a, + 0x00b3b3b3,0x00020202,0x00b4b4b4,0x00adadad, + 0x00a2a2a2,0x00acacac,0x00d8d8d8,0x009a9a9a, + 0x00171717,0x001a1a1a,0x00353535,0x00cccccc, + 0x00f7f7f7,0x00999999,0x00616161,0x005a5a5a, + 0x00e8e8e8,0x00242424,0x00565656,0x00404040, + 0x00e1e1e1,0x00636363,0x00090909,0x00333333, + 0x00bfbfbf,0x00989898,0x00979797,0x00858585, + 0x00686868,0x00fcfcfc,0x00ececec,0x000a0a0a, + 0x00dadada,0x006f6f6f,0x00535353,0x00626262, + 0x00a3a3a3,0x002e2e2e,0x00080808,0x00afafaf, + 0x00282828,0x00b0b0b0,0x00747474,0x00c2c2c2, + 0x00bdbdbd,0x00363636,0x00222222,0x00383838, + 0x00646464,0x001e1e1e,0x00393939,0x002c2c2c, + 0x00a6a6a6,0x00303030,0x00e5e5e5,0x00444444, + 0x00fdfdfd,0x00888888,0x009f9f9f,0x00656565, + 0x00878787,0x006b6b6b,0x00f4f4f4,0x00232323, + 0x00484848,0x00101010,0x00d1d1d1,0x00515151, + 0x00c0c0c0,0x00f9f9f9,0x00d2d2d2,0x00a0a0a0, + 0x00555555,0x00a1a1a1,0x00414141,0x00fafafa, + 0x00434343,0x00131313,0x00c4c4c4,0x002f2f2f, + 0x00a8a8a8,0x00b6b6b6,0x003c3c3c,0x002b2b2b, + 0x00c1c1c1,0x00ffffff,0x00c8c8c8,0x00a5a5a5, + 0x00202020,0x00898989,0x00000000,0x00909090, + 0x00474747,0x00efefef,0x00eaeaea,0x00b7b7b7, + 0x00151515,0x00060606,0x00cdcdcd,0x00b5b5b5, + 0x00121212,0x007e7e7e,0x00bbbbbb,0x00292929, + 0x000f0f0f,0x00b8b8b8,0x00070707,0x00040404, + 0x009b9b9b,0x00949494,0x00212121,0x00666666, + 0x00e6e6e6,0x00cecece,0x00ededed,0x00e7e7e7, + 0x003b3b3b,0x00fefefe,0x007f7f7f,0x00c5c5c5, + 0x00a4a4a4,0x00373737,0x00b1b1b1,0x004c4c4c, + 0x00919191,0x006e6e6e,0x008d8d8d,0x00767676, + 0x00030303,0x002d2d2d,0x00dedede,0x00969696, + 0x00262626,0x007d7d7d,0x00c6c6c6,0x005c5c5c, + 0x00d3d3d3,0x00f2f2f2,0x004f4f4f,0x00191919, + 0x003f3f3f,0x00dcdcdc,0x00797979,0x001d1d1d, + 0x00525252,0x00ebebeb,0x00f3f3f3,0x006d6d6d, + 0x005e5e5e,0x00fbfbfb,0x00696969,0x00b2b2b2, + 0x00f0f0f0,0x00313131,0x000c0c0c,0x00d4d4d4, + 0x00cfcfcf,0x008c8c8c,0x00e2e2e2,0x00757575, + 0x00a9a9a9,0x004a4a4a,0x00575757,0x00848484, + 0x00111111,0x00454545,0x001b1b1b,0x00f5f5f5, + 0x00e4e4e4,0x000e0e0e,0x00737373,0x00aaaaaa, + 0x00f1f1f1,0x00dddddd,0x00595959,0x00141414, + 0x006c6c6c,0x00929292,0x00545454,0x00d0d0d0, + 0x00787878,0x00707070,0x00e3e3e3,0x00494949, + 0x00808080,0x00505050,0x00a7a7a7,0x00f6f6f6, + 0x00777777,0x00939393,0x00868686,0x00838383, + 0x002a2a2a,0x00c7c7c7,0x005b5b5b,0x00e9e9e9, + 0x00eeeeee,0x008f8f8f,0x00010101,0x003d3d3d, +}; + +static const u32 camellia_sp3033[256] = { + 0x38003838,0x41004141,0x16001616,0x76007676, + 0xd900d9d9,0x93009393,0x60006060,0xf200f2f2, + 0x72007272,0xc200c2c2,0xab00abab,0x9a009a9a, + 0x75007575,0x06000606,0x57005757,0xa000a0a0, + 0x91009191,0xf700f7f7,0xb500b5b5,0xc900c9c9, + 0xa200a2a2,0x8c008c8c,0xd200d2d2,0x90009090, + 0xf600f6f6,0x07000707,0xa700a7a7,0x27002727, + 0x8e008e8e,0xb200b2b2,0x49004949,0xde00dede, + 0x43004343,0x5c005c5c,0xd700d7d7,0xc700c7c7, + 0x3e003e3e,0xf500f5f5,0x8f008f8f,0x67006767, + 0x1f001f1f,0x18001818,0x6e006e6e,0xaf00afaf, + 0x2f002f2f,0xe200e2e2,0x85008585,0x0d000d0d, + 0x53005353,0xf000f0f0,0x9c009c9c,0x65006565, + 0xea00eaea,0xa300a3a3,0xae00aeae,0x9e009e9e, + 0xec00ecec,0x80008080,0x2d002d2d,0x6b006b6b, + 0xa800a8a8,0x2b002b2b,0x36003636,0xa600a6a6, + 0xc500c5c5,0x86008686,0x4d004d4d,0x33003333, + 0xfd00fdfd,0x66006666,0x58005858,0x96009696, + 0x3a003a3a,0x09000909,0x95009595,0x10001010, + 0x78007878,0xd800d8d8,0x42004242,0xcc00cccc, + 0xef00efef,0x26002626,0xe500e5e5,0x61006161, + 0x1a001a1a,0x3f003f3f,0x3b003b3b,0x82008282, + 0xb600b6b6,0xdb00dbdb,0xd400d4d4,0x98009898, + 0xe800e8e8,0x8b008b8b,0x02000202,0xeb00ebeb, + 0x0a000a0a,0x2c002c2c,0x1d001d1d,0xb000b0b0, + 0x6f006f6f,0x8d008d8d,0x88008888,0x0e000e0e, + 0x19001919,0x87008787,0x4e004e4e,0x0b000b0b, + 0xa900a9a9,0x0c000c0c,0x79007979,0x11001111, + 0x7f007f7f,0x22002222,0xe700e7e7,0x59005959, + 0xe100e1e1,0xda00dada,0x3d003d3d,0xc800c8c8, + 0x12001212,0x04000404,0x74007474,0x54005454, + 0x30003030,0x7e007e7e,0xb400b4b4,0x28002828, + 0x55005555,0x68006868,0x50005050,0xbe00bebe, + 0xd000d0d0,0xc400c4c4,0x31003131,0xcb00cbcb, + 0x2a002a2a,0xad00adad,0x0f000f0f,0xca00caca, + 0x70007070,0xff00ffff,0x32003232,0x69006969, + 0x08000808,0x62006262,0x00000000,0x24002424, + 0xd100d1d1,0xfb00fbfb,0xba00baba,0xed00eded, + 0x45004545,0x81008181,0x73007373,0x6d006d6d, + 0x84008484,0x9f009f9f,0xee00eeee,0x4a004a4a, + 0xc300c3c3,0x2e002e2e,0xc100c1c1,0x01000101, + 0xe600e6e6,0x25002525,0x48004848,0x99009999, + 0xb900b9b9,0xb300b3b3,0x7b007b7b,0xf900f9f9, + 0xce00cece,0xbf00bfbf,0xdf00dfdf,0x71007171, + 0x29002929,0xcd00cdcd,0x6c006c6c,0x13001313, + 0x64006464,0x9b009b9b,0x63006363,0x9d009d9d, + 0xc000c0c0,0x4b004b4b,0xb700b7b7,0xa500a5a5, + 0x89008989,0x5f005f5f,0xb100b1b1,0x17001717, + 0xf400f4f4,0xbc00bcbc,0xd300d3d3,0x46004646, + 0xcf00cfcf,0x37003737,0x5e005e5e,0x47004747, + 0x94009494,0xfa00fafa,0xfc00fcfc,0x5b005b5b, + 0x97009797,0xfe00fefe,0x5a005a5a,0xac00acac, + 0x3c003c3c,0x4c004c4c,0x03000303,0x35003535, + 0xf300f3f3,0x23002323,0xb800b8b8,0x5d005d5d, + 0x6a006a6a,0x92009292,0xd500d5d5,0x21002121, + 0x44004444,0x51005151,0xc600c6c6,0x7d007d7d, + 0x39003939,0x83008383,0xdc00dcdc,0xaa00aaaa, + 0x7c007c7c,0x77007777,0x56005656,0x05000505, + 0x1b001b1b,0xa400a4a4,0x15001515,0x34003434, + 0x1e001e1e,0x1c001c1c,0xf800f8f8,0x52005252, + 0x20002020,0x14001414,0xe900e9e9,0xbd00bdbd, + 0xdd00dddd,0xe400e4e4,0xa100a1a1,0xe000e0e0, + 0x8a008a8a,0xf100f1f1,0xd600d6d6,0x7a007a7a, + 0xbb00bbbb,0xe300e3e3,0x40004040,0x4f004f4f, +}; + +static const u32 camellia_sp4404[256] = { + 0x70700070,0x2c2c002c,0xb3b300b3,0xc0c000c0, + 0xe4e400e4,0x57570057,0xeaea00ea,0xaeae00ae, + 0x23230023,0x6b6b006b,0x45450045,0xa5a500a5, + 0xeded00ed,0x4f4f004f,0x1d1d001d,0x92920092, + 0x86860086,0xafaf00af,0x7c7c007c,0x1f1f001f, + 0x3e3e003e,0xdcdc00dc,0x5e5e005e,0x0b0b000b, + 0xa6a600a6,0x39390039,0xd5d500d5,0x5d5d005d, + 0xd9d900d9,0x5a5a005a,0x51510051,0x6c6c006c, + 0x8b8b008b,0x9a9a009a,0xfbfb00fb,0xb0b000b0, + 0x74740074,0x2b2b002b,0xf0f000f0,0x84840084, + 0xdfdf00df,0xcbcb00cb,0x34340034,0x76760076, + 0x6d6d006d,0xa9a900a9,0xd1d100d1,0x04040004, + 0x14140014,0x3a3a003a,0xdede00de,0x11110011, + 0x32320032,0x9c9c009c,0x53530053,0xf2f200f2, + 0xfefe00fe,0xcfcf00cf,0xc3c300c3,0x7a7a007a, + 0x24240024,0xe8e800e8,0x60600060,0x69690069, + 0xaaaa00aa,0xa0a000a0,0xa1a100a1,0x62620062, + 0x54540054,0x1e1e001e,0xe0e000e0,0x64640064, + 0x10100010,0x00000000,0xa3a300a3,0x75750075, + 0x8a8a008a,0xe6e600e6,0x09090009,0xdddd00dd, + 0x87870087,0x83830083,0xcdcd00cd,0x90900090, + 0x73730073,0xf6f600f6,0x9d9d009d,0xbfbf00bf, + 0x52520052,0xd8d800d8,0xc8c800c8,0xc6c600c6, + 0x81810081,0x6f6f006f,0x13130013,0x63630063, + 0xe9e900e9,0xa7a700a7,0x9f9f009f,0xbcbc00bc, + 0x29290029,0xf9f900f9,0x2f2f002f,0xb4b400b4, + 0x78780078,0x06060006,0xe7e700e7,0x71710071, + 0xd4d400d4,0xabab00ab,0x88880088,0x8d8d008d, + 0x72720072,0xb9b900b9,0xf8f800f8,0xacac00ac, + 0x36360036,0x2a2a002a,0x3c3c003c,0xf1f100f1, + 0x40400040,0xd3d300d3,0xbbbb00bb,0x43430043, + 0x15150015,0xadad00ad,0x77770077,0x80800080, + 0x82820082,0xecec00ec,0x27270027,0xe5e500e5, + 0x85850085,0x35350035,0x0c0c000c,0x41410041, + 0xefef00ef,0x93930093,0x19190019,0x21210021, + 0x0e0e000e,0x4e4e004e,0x65650065,0xbdbd00bd, + 0xb8b800b8,0x8f8f008f,0xebeb00eb,0xcece00ce, + 0x30300030,0x5f5f005f,0xc5c500c5,0x1a1a001a, + 0xe1e100e1,0xcaca00ca,0x47470047,0x3d3d003d, + 0x01010001,0xd6d600d6,0x56560056,0x4d4d004d, + 0x0d0d000d,0x66660066,0xcccc00cc,0x2d2d002d, + 0x12120012,0x20200020,0xb1b100b1,0x99990099, + 0x4c4c004c,0xc2c200c2,0x7e7e007e,0x05050005, + 0xb7b700b7,0x31310031,0x17170017,0xd7d700d7, + 0x58580058,0x61610061,0x1b1b001b,0x1c1c001c, + 0x0f0f000f,0x16160016,0x18180018,0x22220022, + 0x44440044,0xb2b200b2,0xb5b500b5,0x91910091, + 0x08080008,0xa8a800a8,0xfcfc00fc,0x50500050, + 0xd0d000d0,0x7d7d007d,0x89890089,0x97970097, + 0x5b5b005b,0x95950095,0xffff00ff,0xd2d200d2, + 0xc4c400c4,0x48480048,0xf7f700f7,0xdbdb00db, + 0x03030003,0xdada00da,0x3f3f003f,0x94940094, + 0x5c5c005c,0x02020002,0x4a4a004a,0x33330033, + 0x67670067,0xf3f300f3,0x7f7f007f,0xe2e200e2, + 0x9b9b009b,0x26260026,0x37370037,0x3b3b003b, + 0x96960096,0x4b4b004b,0xbebe00be,0x2e2e002e, + 0x79790079,0x8c8c008c,0x6e6e006e,0x8e8e008e, + 0xf5f500f5,0xb6b600b6,0xfdfd00fd,0x59590059, + 0x98980098,0x6a6a006a,0x46460046,0xbaba00ba, + 0x25250025,0x42420042,0xa2a200a2,0xfafa00fa, + 0x07070007,0x55550055,0xeeee00ee,0x0a0a000a, + 0x49490049,0x68680068,0x38380038,0xa4a400a4, + 0x28280028,0x7b7b007b,0xc9c900c9,0xc1c100c1, + 0xe3e300e3,0xf4f400f4,0xc7c700c7,0x9e9e009e, +}; + + + +static void camellia_setup128(const unsigned char *key, u32 *subkey) +{ + u32 kll, klr, krl, krr; + u32 il, ir, t0, t1, w0, w1; + u32 kw4l, kw4r, dw, tl, tr; + u32 subL[26]; + u32 subR[26]; + + /** + * k == kll || klr || krl || krr (|| is concatination) + */ + kll = GETU32(key ); + klr = GETU32(key + 4); + krl = GETU32(key + 8); + krr = GETU32(key + 12); + /** + * generate KL dependent subkeys + */ + /* kw1 */ + SUBL(0) = kll; SUBR(0) = klr; + /* kw2 */ + SUBL(1) = krl; SUBR(1) = krr; + /* rotation left shift 15bit */ + CAMELLIA_ROLDQ(kll, klr, krl, krr, w0, w1, 15); + /* k3 */ + SUBL(4) = kll; SUBR(4) = klr; + /* k4 */ + SUBL(5) = krl; SUBR(5) = krr; + /* rotation left shift 15+30bit */ + CAMELLIA_ROLDQ(kll, klr, krl, krr, w0, w1, 30); + /* k7 */ + SUBL(10) = kll; SUBR(10) = klr; + /* k8 */ + SUBL(11) = krl; SUBR(11) = krr; + /* rotation left shift 15+30+15bit */ + CAMELLIA_ROLDQ(kll, klr, krl, krr, w0, w1, 15); + /* k10 */ + SUBL(13) = krl; SUBR(13) = krr; + /* rotation left shift 15+30+15+17 bit */ + CAMELLIA_ROLDQ(kll, klr, krl, krr, w0, w1, 17); + /* kl3 */ + SUBL(16) = kll; SUBR(16) = klr; + /* kl4 */ + SUBL(17) = krl; SUBR(17) = krr; + /* rotation left shift 15+30+15+17+17 bit */ + CAMELLIA_ROLDQ(kll, klr, krl, krr, w0, w1, 17); + /* k13 */ + SUBL(18) = kll; SUBR(18) = klr; + /* k14 */ + SUBL(19) = krl; SUBR(19) = krr; + /* rotation left shift 15+30+15+17+17+17 bit */ + CAMELLIA_ROLDQ(kll, klr, krl, krr, w0, w1, 17); + /* k17 */ + SUBL(22) = kll; SUBR(22) = klr; + /* k18 */ + SUBL(23) = krl; SUBR(23) = krr; + + /* generate KA */ + kll = SUBL(0); klr = SUBR(0); + krl = SUBL(1); krr = SUBR(1); + CAMELLIA_F(kll, klr, + CAMELLIA_SIGMA1L, CAMELLIA_SIGMA1R, + w0, w1, il, ir, t0, t1); + krl ^= w0; krr ^= w1; + CAMELLIA_F(krl, krr, + CAMELLIA_SIGMA2L, CAMELLIA_SIGMA2R, + kll, klr, il, ir, t0, t1); + /* current status == (kll, klr, w0, w1) */ + CAMELLIA_F(kll, klr, + CAMELLIA_SIGMA3L, CAMELLIA_SIGMA3R, + krl, krr, il, ir, t0, t1); + krl ^= w0; krr ^= w1; + CAMELLIA_F(krl, krr, + CAMELLIA_SIGMA4L, CAMELLIA_SIGMA4R, + w0, w1, il, ir, t0, t1); + kll ^= w0; klr ^= w1; + + /* generate KA dependent subkeys */ + /* k1, k2 */ + SUBL(2) = kll; SUBR(2) = klr; + SUBL(3) = krl; SUBR(3) = krr; + CAMELLIA_ROLDQ(kll, klr, krl, krr, w0, w1, 15); + /* k5,k6 */ + SUBL(6) = kll; SUBR(6) = klr; + SUBL(7) = krl; SUBR(7) = krr; + CAMELLIA_ROLDQ(kll, klr, krl, krr, w0, w1, 15); + /* kl1, kl2 */ + SUBL(8) = kll; SUBR(8) = klr; + SUBL(9) = krl; SUBR(9) = krr; + CAMELLIA_ROLDQ(kll, klr, krl, krr, w0, w1, 15); + /* k9 */ + SUBL(12) = kll; SUBR(12) = klr; + CAMELLIA_ROLDQ(kll, klr, krl, krr, w0, w1, 15); + /* k11, k12 */ + SUBL(14) = kll; SUBR(14) = klr; + SUBL(15) = krl; SUBR(15) = krr; + CAMELLIA_ROLDQo32(kll, klr, krl, krr, w0, w1, 34); + /* k15, k16 */ + SUBL(20) = kll; SUBR(20) = klr; + SUBL(21) = krl; SUBR(21) = krr; + CAMELLIA_ROLDQ(kll, klr, krl, krr, w0, w1, 17); + /* kw3, kw4 */ + SUBL(24) = kll; SUBR(24) = klr; + SUBL(25) = krl; SUBR(25) = krr; + + + /* absorb kw2 to other subkeys */ + /* round 2 */ + SUBL(3) ^= SUBL(1); SUBR(3) ^= SUBR(1); + /* round 4 */ + SUBL(5) ^= SUBL(1); SUBR(5) ^= SUBR(1); + /* round 6 */ + SUBL(7) ^= SUBL(1); SUBR(7) ^= SUBR(1); + SUBL(1) ^= SUBR(1) & ~SUBR(9); + dw = SUBL(1) & SUBL(9), + SUBR(1) ^= CAMELLIA_RL1(dw); /* modified for FLinv(kl2) */ + /* round 8 */ + SUBL(11) ^= SUBL(1); SUBR(11) ^= SUBR(1); + /* round 10 */ + SUBL(13) ^= SUBL(1); SUBR(13) ^= SUBR(1); + /* round 12 */ + SUBL(15) ^= SUBL(1); SUBR(15) ^= SUBR(1); + SUBL(1) ^= SUBR(1) & ~SUBR(17); + dw = SUBL(1) & SUBL(17), + SUBR(1) ^= CAMELLIA_RL1(dw); /* modified for FLinv(kl4) */ + /* round 14 */ + SUBL(19) ^= SUBL(1); SUBR(19) ^= SUBR(1); + /* round 16 */ + SUBL(21) ^= SUBL(1); SUBR(21) ^= SUBR(1); + /* round 18 */ + SUBL(23) ^= SUBL(1); SUBR(23) ^= SUBR(1); + /* kw3 */ + SUBL(24) ^= SUBL(1); SUBR(24) ^= SUBR(1); + + /* absorb kw4 to other subkeys */ + kw4l = SUBL(25); kw4r = SUBR(25); + /* round 17 */ + SUBL(22) ^= kw4l; SUBR(22) ^= kw4r; + /* round 15 */ + SUBL(20) ^= kw4l; SUBR(20) ^= kw4r; + /* round 13 */ + SUBL(18) ^= kw4l; SUBR(18) ^= kw4r; + kw4l ^= kw4r & ~SUBR(16); + dw = kw4l & SUBL(16), + kw4r ^= CAMELLIA_RL1(dw); /* modified for FL(kl3) */ + /* round 11 */ + SUBL(14) ^= kw4l; SUBR(14) ^= kw4r; + /* round 9 */ + SUBL(12) ^= kw4l; SUBR(12) ^= kw4r; + /* round 7 */ + SUBL(10) ^= kw4l; SUBR(10) ^= kw4r; + kw4l ^= kw4r & ~SUBR(8); + dw = kw4l & SUBL(8), + kw4r ^= CAMELLIA_RL1(dw); /* modified for FL(kl1) */ + /* round 5 */ + SUBL(6) ^= kw4l; SUBR(6) ^= kw4r; + /* round 3 */ + SUBL(4) ^= kw4l; SUBR(4) ^= kw4r; + /* round 1 */ + SUBL(2) ^= kw4l; SUBR(2) ^= kw4r; + /* kw1 */ + SUBL(0) ^= kw4l; SUBR(0) ^= kw4r; + + + /* key XOR is end of F-function */ + CAMELLIA_SUBKEY_L(0) = SUBL(0) ^ SUBL(2);/* kw1 */ + CAMELLIA_SUBKEY_R(0) = SUBR(0) ^ SUBR(2); + CAMELLIA_SUBKEY_L(2) = SUBL(3); /* round 1 */ + CAMELLIA_SUBKEY_R(2) = SUBR(3); + CAMELLIA_SUBKEY_L(3) = SUBL(2) ^ SUBL(4); /* round 2 */ + CAMELLIA_SUBKEY_R(3) = SUBR(2) ^ SUBR(4); + CAMELLIA_SUBKEY_L(4) = SUBL(3) ^ SUBL(5); /* round 3 */ + CAMELLIA_SUBKEY_R(4) = SUBR(3) ^ SUBR(5); + CAMELLIA_SUBKEY_L(5) = SUBL(4) ^ SUBL(6); /* round 4 */ + CAMELLIA_SUBKEY_R(5) = SUBR(4) ^ SUBR(6); + CAMELLIA_SUBKEY_L(6) = SUBL(5) ^ SUBL(7); /* round 5 */ + CAMELLIA_SUBKEY_R(6) = SUBR(5) ^ SUBR(7); + tl = SUBL(10) ^ (SUBR(10) & ~SUBR(8)); + dw = tl & SUBL(8), /* FL(kl1) */ + tr = SUBR(10) ^ CAMELLIA_RL1(dw); + CAMELLIA_SUBKEY_L(7) = SUBL(6) ^ tl; /* round 6 */ + CAMELLIA_SUBKEY_R(7) = SUBR(6) ^ tr; + CAMELLIA_SUBKEY_L(8) = SUBL(8); /* FL(kl1) */ + CAMELLIA_SUBKEY_R(8) = SUBR(8); + CAMELLIA_SUBKEY_L(9) = SUBL(9); /* FLinv(kl2) */ + CAMELLIA_SUBKEY_R(9) = SUBR(9); + tl = SUBL(7) ^ (SUBR(7) & ~SUBR(9)); + dw = tl & SUBL(9), /* FLinv(kl2) */ + tr = SUBR(7) ^ CAMELLIA_RL1(dw); + CAMELLIA_SUBKEY_L(10) = tl ^ SUBL(11); /* round 7 */ + CAMELLIA_SUBKEY_R(10) = tr ^ SUBR(11); + CAMELLIA_SUBKEY_L(11) = SUBL(10) ^ SUBL(12); /* round 8 */ + CAMELLIA_SUBKEY_R(11) = SUBR(10) ^ SUBR(12); + CAMELLIA_SUBKEY_L(12) = SUBL(11) ^ SUBL(13); /* round 9 */ + CAMELLIA_SUBKEY_R(12) = SUBR(11) ^ SUBR(13); + CAMELLIA_SUBKEY_L(13) = SUBL(12) ^ SUBL(14); /* round 10 */ + CAMELLIA_SUBKEY_R(13) = SUBR(12) ^ SUBR(14); + CAMELLIA_SUBKEY_L(14) = SUBL(13) ^ SUBL(15); /* round 11 */ + CAMELLIA_SUBKEY_R(14) = SUBR(13) ^ SUBR(15); + tl = SUBL(18) ^ (SUBR(18) & ~SUBR(16)); + dw = tl & SUBL(16), /* FL(kl3) */ + tr = SUBR(18) ^ CAMELLIA_RL1(dw); + CAMELLIA_SUBKEY_L(15) = SUBL(14) ^ tl; /* round 12 */ + CAMELLIA_SUBKEY_R(15) = SUBR(14) ^ tr; + CAMELLIA_SUBKEY_L(16) = SUBL(16); /* FL(kl3) */ + CAMELLIA_SUBKEY_R(16) = SUBR(16); + CAMELLIA_SUBKEY_L(17) = SUBL(17); /* FLinv(kl4) */ + CAMELLIA_SUBKEY_R(17) = SUBR(17); + tl = SUBL(15) ^ (SUBR(15) & ~SUBR(17)); + dw = tl & SUBL(17), /* FLinv(kl4) */ + tr = SUBR(15) ^ CAMELLIA_RL1(dw); + CAMELLIA_SUBKEY_L(18) = tl ^ SUBL(19); /* round 13 */ + CAMELLIA_SUBKEY_R(18) = tr ^ SUBR(19); + CAMELLIA_SUBKEY_L(19) = SUBL(18) ^ SUBL(20); /* round 14 */ + CAMELLIA_SUBKEY_R(19) = SUBR(18) ^ SUBR(20); + CAMELLIA_SUBKEY_L(20) = SUBL(19) ^ SUBL(21); /* round 15 */ + CAMELLIA_SUBKEY_R(20) = SUBR(19) ^ SUBR(21); + CAMELLIA_SUBKEY_L(21) = SUBL(20) ^ SUBL(22); /* round 16 */ + CAMELLIA_SUBKEY_R(21) = SUBR(20) ^ SUBR(22); + CAMELLIA_SUBKEY_L(22) = SUBL(21) ^ SUBL(23); /* round 17 */ + CAMELLIA_SUBKEY_R(22) = SUBR(21) ^ SUBR(23); + CAMELLIA_SUBKEY_L(23) = SUBL(22); /* round 18 */ + CAMELLIA_SUBKEY_R(23) = SUBR(22); + CAMELLIA_SUBKEY_L(24) = SUBL(24) ^ SUBL(23); /* kw3 */ + CAMELLIA_SUBKEY_R(24) = SUBR(24) ^ SUBR(23); + + /* apply the inverse of the last half of P-function */ + dw = CAMELLIA_SUBKEY_L(2) ^ CAMELLIA_SUBKEY_R(2), + dw = CAMELLIA_RL8(dw);/* round 1 */ + CAMELLIA_SUBKEY_R(2) = CAMELLIA_SUBKEY_L(2) ^ dw, + CAMELLIA_SUBKEY_L(2) = dw; + dw = CAMELLIA_SUBKEY_L(3) ^ CAMELLIA_SUBKEY_R(3), + dw = CAMELLIA_RL8(dw);/* round 2 */ + CAMELLIA_SUBKEY_R(3) = CAMELLIA_SUBKEY_L(3) ^ dw, + CAMELLIA_SUBKEY_L(3) = dw; + dw = CAMELLIA_SUBKEY_L(4) ^ CAMELLIA_SUBKEY_R(4), + dw = CAMELLIA_RL8(dw);/* round 3 */ + CAMELLIA_SUBKEY_R(4) = CAMELLIA_SUBKEY_L(4) ^ dw, + CAMELLIA_SUBKEY_L(4) = dw; + dw = CAMELLIA_SUBKEY_L(5) ^ CAMELLIA_SUBKEY_R(5), + dw = CAMELLIA_RL8(dw);/* round 4 */ + CAMELLIA_SUBKEY_R(5) = CAMELLIA_SUBKEY_L(5) ^ dw, + CAMELLIA_SUBKEY_L(5) = dw; + dw = CAMELLIA_SUBKEY_L(6) ^ CAMELLIA_SUBKEY_R(6), + dw = CAMELLIA_RL8(dw);/* round 5 */ + CAMELLIA_SUBKEY_R(6) = CAMELLIA_SUBKEY_L(6) ^ dw, + CAMELLIA_SUBKEY_L(6) = dw; + dw = CAMELLIA_SUBKEY_L(7) ^ CAMELLIA_SUBKEY_R(7), + dw = CAMELLIA_RL8(dw);/* round 6 */ + CAMELLIA_SUBKEY_R(7) = CAMELLIA_SUBKEY_L(7) ^ dw, + CAMELLIA_SUBKEY_L(7) = dw; + dw = CAMELLIA_SUBKEY_L(10) ^ CAMELLIA_SUBKEY_R(10), + dw = CAMELLIA_RL8(dw);/* round 7 */ + CAMELLIA_SUBKEY_R(10) = CAMELLIA_SUBKEY_L(10) ^ dw, + CAMELLIA_SUBKEY_L(10) = dw; + dw = CAMELLIA_SUBKEY_L(11) ^ CAMELLIA_SUBKEY_R(11), + dw = CAMELLIA_RL8(dw);/* round 8 */ + CAMELLIA_SUBKEY_R(11) = CAMELLIA_SUBKEY_L(11) ^ dw, + CAMELLIA_SUBKEY_L(11) = dw; + dw = CAMELLIA_SUBKEY_L(12) ^ CAMELLIA_SUBKEY_R(12), + dw = CAMELLIA_RL8(dw);/* round 9 */ + CAMELLIA_SUBKEY_R(12) = CAMELLIA_SUBKEY_L(12) ^ dw, + CAMELLIA_SUBKEY_L(12) = dw; + dw = CAMELLIA_SUBKEY_L(13) ^ CAMELLIA_SUBKEY_R(13), + dw = CAMELLIA_RL8(dw);/* round 10 */ + CAMELLIA_SUBKEY_R(13) = CAMELLIA_SUBKEY_L(13) ^ dw, + CAMELLIA_SUBKEY_L(13) = dw; + dw = CAMELLIA_SUBKEY_L(14) ^ CAMELLIA_SUBKEY_R(14), + dw = CAMELLIA_RL8(dw);/* round 11 */ + CAMELLIA_SUBKEY_R(14) = CAMELLIA_SUBKEY_L(14) ^ dw, + CAMELLIA_SUBKEY_L(14) = dw; + dw = CAMELLIA_SUBKEY_L(15) ^ CAMELLIA_SUBKEY_R(15), + dw = CAMELLIA_RL8(dw);/* round 12 */ + CAMELLIA_SUBKEY_R(15) = CAMELLIA_SUBKEY_L(15) ^ dw, + CAMELLIA_SUBKEY_L(15) = dw; + dw = CAMELLIA_SUBKEY_L(18) ^ CAMELLIA_SUBKEY_R(18), + dw = CAMELLIA_RL8(dw);/* round 13 */ + CAMELLIA_SUBKEY_R(18) = CAMELLIA_SUBKEY_L(18) ^ dw, + CAMELLIA_SUBKEY_L(18) = dw; + dw = CAMELLIA_SUBKEY_L(19) ^ CAMELLIA_SUBKEY_R(19), + dw = CAMELLIA_RL8(dw);/* round 14 */ + CAMELLIA_SUBKEY_R(19) = CAMELLIA_SUBKEY_L(19) ^ dw, + CAMELLIA_SUBKEY_L(19) = dw; + dw = CAMELLIA_SUBKEY_L(20) ^ CAMELLIA_SUBKEY_R(20), + dw = CAMELLIA_RL8(dw);/* round 15 */ + CAMELLIA_SUBKEY_R(20) = CAMELLIA_SUBKEY_L(20) ^ dw, + CAMELLIA_SUBKEY_L(20) = dw; + dw = CAMELLIA_SUBKEY_L(21) ^ CAMELLIA_SUBKEY_R(21), + dw = CAMELLIA_RL8(dw);/* round 16 */ + CAMELLIA_SUBKEY_R(21) = CAMELLIA_SUBKEY_L(21) ^ dw, + CAMELLIA_SUBKEY_L(21) = dw; + dw = CAMELLIA_SUBKEY_L(22) ^ CAMELLIA_SUBKEY_R(22), + dw = CAMELLIA_RL8(dw);/* round 17 */ + CAMELLIA_SUBKEY_R(22) = CAMELLIA_SUBKEY_L(22) ^ dw, + CAMELLIA_SUBKEY_L(22) = dw; + dw = CAMELLIA_SUBKEY_L(23) ^ CAMELLIA_SUBKEY_R(23), + dw = CAMELLIA_RL8(dw);/* round 18 */ + CAMELLIA_SUBKEY_R(23) = CAMELLIA_SUBKEY_L(23) ^ dw, + CAMELLIA_SUBKEY_L(23) = dw; + + return; +} + + +static void camellia_setup256(const unsigned char *key, u32 *subkey) +{ + u32 kll,klr,krl,krr; /* left half of key */ + u32 krll,krlr,krrl,krrr; /* right half of key */ + u32 il, ir, t0, t1, w0, w1; /* temporary variables */ + u32 kw4l, kw4r, dw, tl, tr; + u32 subL[34]; + u32 subR[34]; + + /** + * key = (kll || klr || krl || krr || krll || krlr || krrl || krrr) + * (|| is concatination) + */ + + kll = GETU32(key ); + klr = GETU32(key + 4); + krl = GETU32(key + 8); + krr = GETU32(key + 12); + krll = GETU32(key + 16); + krlr = GETU32(key + 20); + krrl = GETU32(key + 24); + krrr = GETU32(key + 28); + + /* generate KL dependent subkeys */ + /* kw1 */ + SUBL(0) = kll; SUBR(0) = klr; + /* kw2 */ + SUBL(1) = krl; SUBR(1) = krr; + CAMELLIA_ROLDQo32(kll, klr, krl, krr, w0, w1, 45); + /* k9 */ + SUBL(12) = kll; SUBR(12) = klr; + /* k10 */ + SUBL(13) = krl; SUBR(13) = krr; + CAMELLIA_ROLDQ(kll, klr, krl, krr, w0, w1, 15); + /* kl3 */ + SUBL(16) = kll; SUBR(16) = klr; + /* kl4 */ + SUBL(17) = krl; SUBR(17) = krr; + CAMELLIA_ROLDQ(kll, klr, krl, krr, w0, w1, 17); + /* k17 */ + SUBL(22) = kll; SUBR(22) = klr; + /* k18 */ + SUBL(23) = krl; SUBR(23) = krr; + CAMELLIA_ROLDQo32(kll, klr, krl, krr, w0, w1, 34); + /* k23 */ + SUBL(30) = kll; SUBR(30) = klr; + /* k24 */ + SUBL(31) = krl; SUBR(31) = krr; + + /* generate KR dependent subkeys */ + CAMELLIA_ROLDQ(krll, krlr, krrl, krrr, w0, w1, 15); + /* k3 */ + SUBL(4) = krll; SUBR(4) = krlr; + /* k4 */ + SUBL(5) = krrl; SUBR(5) = krrr; + CAMELLIA_ROLDQ(krll, krlr, krrl, krrr, w0, w1, 15); + /* kl1 */ + SUBL(8) = krll; SUBR(8) = krlr; + /* kl2 */ + SUBL(9) = krrl; SUBR(9) = krrr; + CAMELLIA_ROLDQ(krll, krlr, krrl, krrr, w0, w1, 30); + /* k13 */ + SUBL(18) = krll; SUBR(18) = krlr; + /* k14 */ + SUBL(19) = krrl; SUBR(19) = krrr; + CAMELLIA_ROLDQo32(krll, krlr, krrl, krrr, w0, w1, 34); + /* k19 */ + SUBL(26) = krll; SUBR(26) = krlr; + /* k20 */ + SUBL(27) = krrl; SUBR(27) = krrr; + CAMELLIA_ROLDQo32(krll, krlr, krrl, krrr, w0, w1, 34); + + /* generate KA */ + kll = SUBL(0) ^ krll; klr = SUBR(0) ^ krlr; + krl = SUBL(1) ^ krrl; krr = SUBR(1) ^ krrr; + CAMELLIA_F(kll, klr, + CAMELLIA_SIGMA1L, CAMELLIA_SIGMA1R, + w0, w1, il, ir, t0, t1); + krl ^= w0; krr ^= w1; + CAMELLIA_F(krl, krr, + CAMELLIA_SIGMA2L, CAMELLIA_SIGMA2R, + kll, klr, il, ir, t0, t1); + kll ^= krll; klr ^= krlr; + CAMELLIA_F(kll, klr, + CAMELLIA_SIGMA3L, CAMELLIA_SIGMA3R, + krl, krr, il, ir, t0, t1); + krl ^= w0 ^ krrl; krr ^= w1 ^ krrr; + CAMELLIA_F(krl, krr, + CAMELLIA_SIGMA4L, CAMELLIA_SIGMA4R, + w0, w1, il, ir, t0, t1); + kll ^= w0; klr ^= w1; + + /* generate KB */ + krll ^= kll; krlr ^= klr; + krrl ^= krl; krrr ^= krr; + CAMELLIA_F(krll, krlr, + CAMELLIA_SIGMA5L, CAMELLIA_SIGMA5R, + w0, w1, il, ir, t0, t1); + krrl ^= w0; krrr ^= w1; + CAMELLIA_F(krrl, krrr, + CAMELLIA_SIGMA6L, CAMELLIA_SIGMA6R, + w0, w1, il, ir, t0, t1); + krll ^= w0; krlr ^= w1; + + /* generate KA dependent subkeys */ + CAMELLIA_ROLDQ(kll, klr, krl, krr, w0, w1, 15); + /* k5 */ + SUBL(6) = kll; SUBR(6) = klr; + /* k6 */ + SUBL(7) = krl; SUBR(7) = krr; + CAMELLIA_ROLDQ(kll, klr, krl, krr, w0, w1, 30); + /* k11 */ + SUBL(14) = kll; SUBR(14) = klr; + /* k12 */ + SUBL(15) = krl; SUBR(15) = krr; + /* rotation left shift 32bit */ + /* kl5 */ + SUBL(24) = klr; SUBR(24) = krl; + /* kl6 */ + SUBL(25) = krr; SUBR(25) = kll; + /* rotation left shift 49 from k11,k12 -> k21,k22 */ + CAMELLIA_ROLDQo32(kll, klr, krl, krr, w0, w1, 49); + /* k21 */ + SUBL(28) = kll; SUBR(28) = klr; + /* k22 */ + SUBL(29) = krl; SUBR(29) = krr; + + /* generate KB dependent subkeys */ + /* k1 */ + SUBL(2) = krll; SUBR(2) = krlr; + /* k2 */ + SUBL(3) = krrl; SUBR(3) = krrr; + CAMELLIA_ROLDQ(krll, krlr, krrl, krrr, w0, w1, 30); + /* k7 */ + SUBL(10) = krll; SUBR(10) = krlr; + /* k8 */ + SUBL(11) = krrl; SUBR(11) = krrr; + CAMELLIA_ROLDQ(krll, krlr, krrl, krrr, w0, w1, 30); + /* k15 */ + SUBL(20) = krll; SUBR(20) = krlr; + /* k16 */ + SUBL(21) = krrl; SUBR(21) = krrr; + CAMELLIA_ROLDQo32(krll, krlr, krrl, krrr, w0, w1, 51); + /* kw3 */ + SUBL(32) = krll; SUBR(32) = krlr; + /* kw4 */ + SUBL(33) = krrl; SUBR(33) = krrr; + + /* absorb kw2 to other subkeys */ + /* round 2 */ + SUBL(3) ^= SUBL(1); SUBR(3) ^= SUBR(1); + /* round 4 */ + SUBL(5) ^= SUBL(1); SUBR(5) ^= SUBR(1); + /* round 6 */ + SUBL(7) ^= SUBL(1); SUBR(7) ^= SUBR(1); + SUBL(1) ^= SUBR(1) & ~SUBR(9); + dw = SUBL(1) & SUBL(9), + SUBR(1) ^= CAMELLIA_RL1(dw); /* modified for FLinv(kl2) */ + /* round 8 */ + SUBL(11) ^= SUBL(1); SUBR(11) ^= SUBR(1); + /* round 10 */ + SUBL(13) ^= SUBL(1); SUBR(13) ^= SUBR(1); + /* round 12 */ + SUBL(15) ^= SUBL(1); SUBR(15) ^= SUBR(1); + SUBL(1) ^= SUBR(1) & ~SUBR(17); + dw = SUBL(1) & SUBL(17), + SUBR(1) ^= CAMELLIA_RL1(dw); /* modified for FLinv(kl4) */ + /* round 14 */ + SUBL(19) ^= SUBL(1); SUBR(19) ^= SUBR(1); + /* round 16 */ + SUBL(21) ^= SUBL(1); SUBR(21) ^= SUBR(1); + /* round 18 */ + SUBL(23) ^= SUBL(1); SUBR(23) ^= SUBR(1); + SUBL(1) ^= SUBR(1) & ~SUBR(25); + dw = SUBL(1) & SUBL(25), + SUBR(1) ^= CAMELLIA_RL1(dw); /* modified for FLinv(kl6) */ + /* round 20 */ + SUBL(27) ^= SUBL(1); SUBR(27) ^= SUBR(1); + /* round 22 */ + SUBL(29) ^= SUBL(1); SUBR(29) ^= SUBR(1); + /* round 24 */ + SUBL(31) ^= SUBL(1); SUBR(31) ^= SUBR(1); + /* kw3 */ + SUBL(32) ^= SUBL(1); SUBR(32) ^= SUBR(1); + + + /* absorb kw4 to other subkeys */ + kw4l = SUBL(33); kw4r = SUBR(33); + /* round 23 */ + SUBL(30) ^= kw4l; SUBR(30) ^= kw4r; + /* round 21 */ + SUBL(28) ^= kw4l; SUBR(28) ^= kw4r; + /* round 19 */ + SUBL(26) ^= kw4l; SUBR(26) ^= kw4r; + kw4l ^= kw4r & ~SUBR(24); + dw = kw4l & SUBL(24), + kw4r ^= CAMELLIA_RL1(dw); /* modified for FL(kl5) */ + /* round 17 */ + SUBL(22) ^= kw4l; SUBR(22) ^= kw4r; + /* round 15 */ + SUBL(20) ^= kw4l; SUBR(20) ^= kw4r; + /* round 13 */ + SUBL(18) ^= kw4l; SUBR(18) ^= kw4r; + kw4l ^= kw4r & ~SUBR(16); + dw = kw4l & SUBL(16), + kw4r ^= CAMELLIA_RL1(dw); /* modified for FL(kl3) */ + /* round 11 */ + SUBL(14) ^= kw4l; SUBR(14) ^= kw4r; + /* round 9 */ + SUBL(12) ^= kw4l; SUBR(12) ^= kw4r; + /* round 7 */ + SUBL(10) ^= kw4l; SUBR(10) ^= kw4r; + kw4l ^= kw4r & ~SUBR(8); + dw = kw4l & SUBL(8), + kw4r ^= CAMELLIA_RL1(dw); /* modified for FL(kl1) */ + /* round 5 */ + SUBL(6) ^= kw4l; SUBR(6) ^= kw4r; + /* round 3 */ + SUBL(4) ^= kw4l; SUBR(4) ^= kw4r; + /* round 1 */ + SUBL(2) ^= kw4l; SUBR(2) ^= kw4r; + /* kw1 */ + SUBL(0) ^= kw4l; SUBR(0) ^= kw4r; + + /* key XOR is end of F-function */ + CAMELLIA_SUBKEY_L(0) = SUBL(0) ^ SUBL(2);/* kw1 */ + CAMELLIA_SUBKEY_R(0) = SUBR(0) ^ SUBR(2); + CAMELLIA_SUBKEY_L(2) = SUBL(3); /* round 1 */ + CAMELLIA_SUBKEY_R(2) = SUBR(3); + CAMELLIA_SUBKEY_L(3) = SUBL(2) ^ SUBL(4); /* round 2 */ + CAMELLIA_SUBKEY_R(3) = SUBR(2) ^ SUBR(4); + CAMELLIA_SUBKEY_L(4) = SUBL(3) ^ SUBL(5); /* round 3 */ + CAMELLIA_SUBKEY_R(4) = SUBR(3) ^ SUBR(5); + CAMELLIA_SUBKEY_L(5) = SUBL(4) ^ SUBL(6); /* round 4 */ + CAMELLIA_SUBKEY_R(5) = SUBR(4) ^ SUBR(6); + CAMELLIA_SUBKEY_L(6) = SUBL(5) ^ SUBL(7); /* round 5 */ + CAMELLIA_SUBKEY_R(6) = SUBR(5) ^ SUBR(7); + tl = SUBL(10) ^ (SUBR(10) & ~SUBR(8)); + dw = tl & SUBL(8), /* FL(kl1) */ + tr = SUBR(10) ^ CAMELLIA_RL1(dw); + CAMELLIA_SUBKEY_L(7) = SUBL(6) ^ tl; /* round 6 */ + CAMELLIA_SUBKEY_R(7) = SUBR(6) ^ tr; + CAMELLIA_SUBKEY_L(8) = SUBL(8); /* FL(kl1) */ + CAMELLIA_SUBKEY_R(8) = SUBR(8); + CAMELLIA_SUBKEY_L(9) = SUBL(9); /* FLinv(kl2) */ + CAMELLIA_SUBKEY_R(9) = SUBR(9); + tl = SUBL(7) ^ (SUBR(7) & ~SUBR(9)); + dw = tl & SUBL(9), /* FLinv(kl2) */ + tr = SUBR(7) ^ CAMELLIA_RL1(dw); + CAMELLIA_SUBKEY_L(10) = tl ^ SUBL(11); /* round 7 */ + CAMELLIA_SUBKEY_R(10) = tr ^ SUBR(11); + CAMELLIA_SUBKEY_L(11) = SUBL(10) ^ SUBL(12); /* round 8 */ + CAMELLIA_SUBKEY_R(11) = SUBR(10) ^ SUBR(12); + CAMELLIA_SUBKEY_L(12) = SUBL(11) ^ SUBL(13); /* round 9 */ + CAMELLIA_SUBKEY_R(12) = SUBR(11) ^ SUBR(13); + CAMELLIA_SUBKEY_L(13) = SUBL(12) ^ SUBL(14); /* round 10 */ + CAMELLIA_SUBKEY_R(13) = SUBR(12) ^ SUBR(14); + CAMELLIA_SUBKEY_L(14) = SUBL(13) ^ SUBL(15); /* round 11 */ + CAMELLIA_SUBKEY_R(14) = SUBR(13) ^ SUBR(15); + tl = SUBL(18) ^ (SUBR(18) & ~SUBR(16)); + dw = tl & SUBL(16), /* FL(kl3) */ + tr = SUBR(18) ^ CAMELLIA_RL1(dw); + CAMELLIA_SUBKEY_L(15) = SUBL(14) ^ tl; /* round 12 */ + CAMELLIA_SUBKEY_R(15) = SUBR(14) ^ tr; + CAMELLIA_SUBKEY_L(16) = SUBL(16); /* FL(kl3) */ + CAMELLIA_SUBKEY_R(16) = SUBR(16); + CAMELLIA_SUBKEY_L(17) = SUBL(17); /* FLinv(kl4) */ + CAMELLIA_SUBKEY_R(17) = SUBR(17); + tl = SUBL(15) ^ (SUBR(15) & ~SUBR(17)); + dw = tl & SUBL(17), /* FLinv(kl4) */ + tr = SUBR(15) ^ CAMELLIA_RL1(dw); + CAMELLIA_SUBKEY_L(18) = tl ^ SUBL(19); /* round 13 */ + CAMELLIA_SUBKEY_R(18) = tr ^ SUBR(19); + CAMELLIA_SUBKEY_L(19) = SUBL(18) ^ SUBL(20); /* round 14 */ + CAMELLIA_SUBKEY_R(19) = SUBR(18) ^ SUBR(20); + CAMELLIA_SUBKEY_L(20) = SUBL(19) ^ SUBL(21); /* round 15 */ + CAMELLIA_SUBKEY_R(20) = SUBR(19) ^ SUBR(21); + CAMELLIA_SUBKEY_L(21) = SUBL(20) ^ SUBL(22); /* round 16 */ + CAMELLIA_SUBKEY_R(21) = SUBR(20) ^ SUBR(22); + CAMELLIA_SUBKEY_L(22) = SUBL(21) ^ SUBL(23); /* round 17 */ + CAMELLIA_SUBKEY_R(22) = SUBR(21) ^ SUBR(23); + tl = SUBL(26) ^ (SUBR(26) + & ~SUBR(24)); + dw = tl & SUBL(24), /* FL(kl5) */ + tr = SUBR(26) ^ CAMELLIA_RL1(dw); + CAMELLIA_SUBKEY_L(23) = SUBL(22) ^ tl; /* round 18 */ + CAMELLIA_SUBKEY_R(23) = SUBR(22) ^ tr; + CAMELLIA_SUBKEY_L(24) = SUBL(24); /* FL(kl5) */ + CAMELLIA_SUBKEY_R(24) = SUBR(24); + CAMELLIA_SUBKEY_L(25) = SUBL(25); /* FLinv(kl6) */ + CAMELLIA_SUBKEY_R(25) = SUBR(25); + tl = SUBL(23) ^ (SUBR(23) & + ~SUBR(25)); + dw = tl & SUBL(25), /* FLinv(kl6) */ + tr = SUBR(23) ^ CAMELLIA_RL1(dw); + CAMELLIA_SUBKEY_L(26) = tl ^ SUBL(27); /* round 19 */ + CAMELLIA_SUBKEY_R(26) = tr ^ SUBR(27); + CAMELLIA_SUBKEY_L(27) = SUBL(26) ^ SUBL(28); /* round 20 */ + CAMELLIA_SUBKEY_R(27) = SUBR(26) ^ SUBR(28); + CAMELLIA_SUBKEY_L(28) = SUBL(27) ^ SUBL(29); /* round 21 */ + CAMELLIA_SUBKEY_R(28) = SUBR(27) ^ SUBR(29); + CAMELLIA_SUBKEY_L(29) = SUBL(28) ^ SUBL(30); /* round 22 */ + CAMELLIA_SUBKEY_R(29) = SUBR(28) ^ SUBR(30); + CAMELLIA_SUBKEY_L(30) = SUBL(29) ^ SUBL(31); /* round 23 */ + CAMELLIA_SUBKEY_R(30) = SUBR(29) ^ SUBR(31); + CAMELLIA_SUBKEY_L(31) = SUBL(30); /* round 24 */ + CAMELLIA_SUBKEY_R(31) = SUBR(30); + CAMELLIA_SUBKEY_L(32) = SUBL(32) ^ SUBL(31); /* kw3 */ + CAMELLIA_SUBKEY_R(32) = SUBR(32) ^ SUBR(31); + + /* apply the inverse of the last half of P-function */ + dw = CAMELLIA_SUBKEY_L(2) ^ CAMELLIA_SUBKEY_R(2), + dw = CAMELLIA_RL8(dw);/* round 1 */ + CAMELLIA_SUBKEY_R(2) = CAMELLIA_SUBKEY_L(2) ^ dw, + CAMELLIA_SUBKEY_L(2) = dw; + dw = CAMELLIA_SUBKEY_L(3) ^ CAMELLIA_SUBKEY_R(3), + dw = CAMELLIA_RL8(dw);/* round 2 */ + CAMELLIA_SUBKEY_R(3) = CAMELLIA_SUBKEY_L(3) ^ dw, + CAMELLIA_SUBKEY_L(3) = dw; + dw = CAMELLIA_SUBKEY_L(4) ^ CAMELLIA_SUBKEY_R(4), + dw = CAMELLIA_RL8(dw);/* round 3 */ + CAMELLIA_SUBKEY_R(4) = CAMELLIA_SUBKEY_L(4) ^ dw, + CAMELLIA_SUBKEY_L(4) = dw; + dw = CAMELLIA_SUBKEY_L(5) ^ CAMELLIA_SUBKEY_R(5), + dw = CAMELLIA_RL8(dw);/* round 4 */ + CAMELLIA_SUBKEY_R(5) = CAMELLIA_SUBKEY_L(5) ^ dw, + CAMELLIA_SUBKEY_L(5) = dw; + dw = CAMELLIA_SUBKEY_L(6) ^ CAMELLIA_SUBKEY_R(6), + dw = CAMELLIA_RL8(dw);/* round 5 */ + CAMELLIA_SUBKEY_R(6) = CAMELLIA_SUBKEY_L(6) ^ dw, + CAMELLIA_SUBKEY_L(6) = dw; + dw = CAMELLIA_SUBKEY_L(7) ^ CAMELLIA_SUBKEY_R(7), + dw = CAMELLIA_RL8(dw);/* round 6 */ + CAMELLIA_SUBKEY_R(7) = CAMELLIA_SUBKEY_L(7) ^ dw, + CAMELLIA_SUBKEY_L(7) = dw; + dw = CAMELLIA_SUBKEY_L(10) ^ CAMELLIA_SUBKEY_R(10), + dw = CAMELLIA_RL8(dw);/* round 7 */ + CAMELLIA_SUBKEY_R(10) = CAMELLIA_SUBKEY_L(10) ^ dw, + CAMELLIA_SUBKEY_L(10) = dw; + dw = CAMELLIA_SUBKEY_L(11) ^ CAMELLIA_SUBKEY_R(11), + dw = CAMELLIA_RL8(dw);/* round 8 */ + CAMELLIA_SUBKEY_R(11) = CAMELLIA_SUBKEY_L(11) ^ dw, + CAMELLIA_SUBKEY_L(11) = dw; + dw = CAMELLIA_SUBKEY_L(12) ^ CAMELLIA_SUBKEY_R(12), + dw = CAMELLIA_RL8(dw);/* round 9 */ + CAMELLIA_SUBKEY_R(12) = CAMELLIA_SUBKEY_L(12) ^ dw, + CAMELLIA_SUBKEY_L(12) = dw; + dw = CAMELLIA_SUBKEY_L(13) ^ CAMELLIA_SUBKEY_R(13), + dw = CAMELLIA_RL8(dw);/* round 10 */ + CAMELLIA_SUBKEY_R(13) = CAMELLIA_SUBKEY_L(13) ^ dw, + CAMELLIA_SUBKEY_L(13) = dw; + dw = CAMELLIA_SUBKEY_L(14) ^ CAMELLIA_SUBKEY_R(14), + dw = CAMELLIA_RL8(dw);/* round 11 */ + CAMELLIA_SUBKEY_R(14) = CAMELLIA_SUBKEY_L(14) ^ dw, + CAMELLIA_SUBKEY_L(14) = dw; + dw = CAMELLIA_SUBKEY_L(15) ^ CAMELLIA_SUBKEY_R(15), + dw = CAMELLIA_RL8(dw);/* round 12 */ + CAMELLIA_SUBKEY_R(15) = CAMELLIA_SUBKEY_L(15) ^ dw, + CAMELLIA_SUBKEY_L(15) = dw; + dw = CAMELLIA_SUBKEY_L(18) ^ CAMELLIA_SUBKEY_R(18), + dw = CAMELLIA_RL8(dw);/* round 13 */ + CAMELLIA_SUBKEY_R(18) = CAMELLIA_SUBKEY_L(18) ^ dw, + CAMELLIA_SUBKEY_L(18) = dw; + dw = CAMELLIA_SUBKEY_L(19) ^ CAMELLIA_SUBKEY_R(19), + dw = CAMELLIA_RL8(dw);/* round 14 */ + CAMELLIA_SUBKEY_R(19) = CAMELLIA_SUBKEY_L(19) ^ dw, + CAMELLIA_SUBKEY_L(19) = dw; + dw = CAMELLIA_SUBKEY_L(20) ^ CAMELLIA_SUBKEY_R(20), + dw = CAMELLIA_RL8(dw);/* round 15 */ + CAMELLIA_SUBKEY_R(20) = CAMELLIA_SUBKEY_L(20) ^ dw, + CAMELLIA_SUBKEY_L(20) = dw; + dw = CAMELLIA_SUBKEY_L(21) ^ CAMELLIA_SUBKEY_R(21), + dw = CAMELLIA_RL8(dw);/* round 16 */ + CAMELLIA_SUBKEY_R(21) = CAMELLIA_SUBKEY_L(21) ^ dw, + CAMELLIA_SUBKEY_L(21) = dw; + dw = CAMELLIA_SUBKEY_L(22) ^ CAMELLIA_SUBKEY_R(22), + dw = CAMELLIA_RL8(dw);/* round 17 */ + CAMELLIA_SUBKEY_R(22) = CAMELLIA_SUBKEY_L(22) ^ dw, + CAMELLIA_SUBKEY_L(22) = dw; + dw = CAMELLIA_SUBKEY_L(23) ^ CAMELLIA_SUBKEY_R(23), + dw = CAMELLIA_RL8(dw);/* round 18 */ + CAMELLIA_SUBKEY_R(23) = CAMELLIA_SUBKEY_L(23) ^ dw, + CAMELLIA_SUBKEY_L(23) = dw; + dw = CAMELLIA_SUBKEY_L(26) ^ CAMELLIA_SUBKEY_R(26), + dw = CAMELLIA_RL8(dw);/* round 19 */ + CAMELLIA_SUBKEY_R(26) = CAMELLIA_SUBKEY_L(26) ^ dw, + CAMELLIA_SUBKEY_L(26) = dw; + dw = CAMELLIA_SUBKEY_L(27) ^ CAMELLIA_SUBKEY_R(27), + dw = CAMELLIA_RL8(dw);/* round 20 */ + CAMELLIA_SUBKEY_R(27) = CAMELLIA_SUBKEY_L(27) ^ dw, + CAMELLIA_SUBKEY_L(27) = dw; + dw = CAMELLIA_SUBKEY_L(28) ^ CAMELLIA_SUBKEY_R(28), + dw = CAMELLIA_RL8(dw);/* round 21 */ + CAMELLIA_SUBKEY_R(28) = CAMELLIA_SUBKEY_L(28) ^ dw, + CAMELLIA_SUBKEY_L(28) = dw; + dw = CAMELLIA_SUBKEY_L(29) ^ CAMELLIA_SUBKEY_R(29), + dw = CAMELLIA_RL8(dw);/* round 22 */ + CAMELLIA_SUBKEY_R(29) = CAMELLIA_SUBKEY_L(29) ^ dw, + CAMELLIA_SUBKEY_L(29) = dw; + dw = CAMELLIA_SUBKEY_L(30) ^ CAMELLIA_SUBKEY_R(30), + dw = CAMELLIA_RL8(dw);/* round 23 */ + CAMELLIA_SUBKEY_R(30) = CAMELLIA_SUBKEY_L(30) ^ dw, + CAMELLIA_SUBKEY_L(30) = dw; + dw = CAMELLIA_SUBKEY_L(31) ^ CAMELLIA_SUBKEY_R(31), + dw = CAMELLIA_RL8(dw);/* round 24 */ + CAMELLIA_SUBKEY_R(31) = CAMELLIA_SUBKEY_L(31) ^ dw, + CAMELLIA_SUBKEY_L(31) = dw; + + return; +} + +static void camellia_setup192(const unsigned char *key, u32 *subkey) +{ + unsigned char kk[32]; + u32 krll, krlr, krrl,krrr; + + memcpy(kk, key, 24); + memcpy((unsigned char *)&krll, key+16,4); + memcpy((unsigned char *)&krlr, key+20,4); + krrl = ~krll; + krrr = ~krlr; + memcpy(kk+24, (unsigned char *)&krrl, 4); + memcpy(kk+28, (unsigned char *)&krrr, 4); + camellia_setup256(kk, subkey); + return; +} + + +/** + * Stuff related to camellia encryption/decryption + */ +static void camellia_encrypt128(const u32 *subkey, __be32 *io_text) +{ + u32 il,ir,t0,t1; /* temporary valiables */ + + u32 io[4]; + + io[0] = be32_to_cpu(io_text[0]); + io[1] = be32_to_cpu(io_text[1]); + io[2] = be32_to_cpu(io_text[2]); + io[3] = be32_to_cpu(io_text[3]); + + /* pre whitening but absorb kw2*/ + io[0] ^= CAMELLIA_SUBKEY_L(0); + io[1] ^= CAMELLIA_SUBKEY_R(0); + /* main iteration */ + + CAMELLIA_ROUNDSM(io[0],io[1], + CAMELLIA_SUBKEY_L(2),CAMELLIA_SUBKEY_R(2), + io[2],io[3],il,ir,t0,t1); + CAMELLIA_ROUNDSM(io[2],io[3], + CAMELLIA_SUBKEY_L(3),CAMELLIA_SUBKEY_R(3), + io[0],io[1],il,ir,t0,t1); + CAMELLIA_ROUNDSM(io[0],io[1], + CAMELLIA_SUBKEY_L(4),CAMELLIA_SUBKEY_R(4), + io[2],io[3],il,ir,t0,t1); + CAMELLIA_ROUNDSM(io[2],io[3], + CAMELLIA_SUBKEY_L(5),CAMELLIA_SUBKEY_R(5), + io[0],io[1],il,ir,t0,t1); + CAMELLIA_ROUNDSM(io[0],io[1], + CAMELLIA_SUBKEY_L(6),CAMELLIA_SUBKEY_R(6), + io[2],io[3],il,ir,t0,t1); + CAMELLIA_ROUNDSM(io[2],io[3], + CAMELLIA_SUBKEY_L(7),CAMELLIA_SUBKEY_R(7), + io[0],io[1],il,ir,t0,t1); + + CAMELLIA_FLS(io[0],io[1],io[2],io[3], + CAMELLIA_SUBKEY_L(8),CAMELLIA_SUBKEY_R(8), + CAMELLIA_SUBKEY_L(9),CAMELLIA_SUBKEY_R(9), + t0,t1,il,ir); + + CAMELLIA_ROUNDSM(io[0],io[1], + CAMELLIA_SUBKEY_L(10),CAMELLIA_SUBKEY_R(10), + io[2],io[3],il,ir,t0,t1); + CAMELLIA_ROUNDSM(io[2],io[3], + CAMELLIA_SUBKEY_L(11),CAMELLIA_SUBKEY_R(11), + io[0],io[1],il,ir,t0,t1); + CAMELLIA_ROUNDSM(io[0],io[1], + CAMELLIA_SUBKEY_L(12),CAMELLIA_SUBKEY_R(12), + io[2],io[3],il,ir,t0,t1); + CAMELLIA_ROUNDSM(io[2],io[3], + CAMELLIA_SUBKEY_L(13),CAMELLIA_SUBKEY_R(13), + io[0],io[1],il,ir,t0,t1); + CAMELLIA_ROUNDSM(io[0],io[1], + CAMELLIA_SUBKEY_L(14),CAMELLIA_SUBKEY_R(14), + io[2],io[3],il,ir,t0,t1); + CAMELLIA_ROUNDSM(io[2],io[3], + CAMELLIA_SUBKEY_L(15),CAMELLIA_SUBKEY_R(15), + io[0],io[1],il,ir,t0,t1); + + CAMELLIA_FLS(io[0],io[1],io[2],io[3], + CAMELLIA_SUBKEY_L(16),CAMELLIA_SUBKEY_R(16), + CAMELLIA_SUBKEY_L(17),CAMELLIA_SUBKEY_R(17), + t0,t1,il,ir); + + CAMELLIA_ROUNDSM(io[0],io[1], + CAMELLIA_SUBKEY_L(18),CAMELLIA_SUBKEY_R(18), + io[2],io[3],il,ir,t0,t1); + CAMELLIA_ROUNDSM(io[2],io[3], + CAMELLIA_SUBKEY_L(19),CAMELLIA_SUBKEY_R(19), + io[0],io[1],il,ir,t0,t1); + CAMELLIA_ROUNDSM(io[0],io[1], + CAMELLIA_SUBKEY_L(20),CAMELLIA_SUBKEY_R(20), + io[2],io[3],il,ir,t0,t1); + CAMELLIA_ROUNDSM(io[2],io[3], + CAMELLIA_SUBKEY_L(21),CAMELLIA_SUBKEY_R(21), + io[0],io[1],il,ir,t0,t1); + CAMELLIA_ROUNDSM(io[0],io[1], + CAMELLIA_SUBKEY_L(22),CAMELLIA_SUBKEY_R(22), + io[2],io[3],il,ir,t0,t1); + CAMELLIA_ROUNDSM(io[2],io[3], + CAMELLIA_SUBKEY_L(23),CAMELLIA_SUBKEY_R(23), + io[0],io[1],il,ir,t0,t1); + + /* post whitening but kw4 */ + io[2] ^= CAMELLIA_SUBKEY_L(24); + io[3] ^= CAMELLIA_SUBKEY_R(24); + + t0 = io[0]; + t1 = io[1]; + io[0] = io[2]; + io[1] = io[3]; + io[2] = t0; + io[3] = t1; + + io_text[0] = cpu_to_be32(io[0]); + io_text[1] = cpu_to_be32(io[1]); + io_text[2] = cpu_to_be32(io[2]); + io_text[3] = cpu_to_be32(io[3]); + + return; +} + +static void camellia_decrypt128(const u32 *subkey, __be32 *io_text) +{ + u32 il,ir,t0,t1; /* temporary valiables */ + + u32 io[4]; + + io[0] = be32_to_cpu(io_text[0]); + io[1] = be32_to_cpu(io_text[1]); + io[2] = be32_to_cpu(io_text[2]); + io[3] = be32_to_cpu(io_text[3]); + + /* pre whitening but absorb kw2*/ + io[0] ^= CAMELLIA_SUBKEY_L(24); + io[1] ^= CAMELLIA_SUBKEY_R(24); + + /* main iteration */ + CAMELLIA_ROUNDSM(io[0],io[1], + CAMELLIA_SUBKEY_L(23),CAMELLIA_SUBKEY_R(23), + io[2],io[3],il,ir,t0,t1); + CAMELLIA_ROUNDSM(io[2],io[3], + CAMELLIA_SUBKEY_L(22),CAMELLIA_SUBKEY_R(22), + io[0],io[1],il,ir,t0,t1); + CAMELLIA_ROUNDSM(io[0],io[1], + CAMELLIA_SUBKEY_L(21),CAMELLIA_SUBKEY_R(21), + io[2],io[3],il,ir,t0,t1); + CAMELLIA_ROUNDSM(io[2],io[3], + CAMELLIA_SUBKEY_L(20),CAMELLIA_SUBKEY_R(20), + io[0],io[1],il,ir,t0,t1); + CAMELLIA_ROUNDSM(io[0],io[1], + CAMELLIA_SUBKEY_L(19),CAMELLIA_SUBKEY_R(19), + io[2],io[3],il,ir,t0,t1); + CAMELLIA_ROUNDSM(io[2],io[3], + CAMELLIA_SUBKEY_L(18),CAMELLIA_SUBKEY_R(18), + io[0],io[1],il,ir,t0,t1); + + CAMELLIA_FLS(io[0],io[1],io[2],io[3], + CAMELLIA_SUBKEY_L(17),CAMELLIA_SUBKEY_R(17), + CAMELLIA_SUBKEY_L(16),CAMELLIA_SUBKEY_R(16), + t0,t1,il,ir); + + CAMELLIA_ROUNDSM(io[0],io[1], + CAMELLIA_SUBKEY_L(15),CAMELLIA_SUBKEY_R(15), + io[2],io[3],il,ir,t0,t1); + CAMELLIA_ROUNDSM(io[2],io[3], + CAMELLIA_SUBKEY_L(14),CAMELLIA_SUBKEY_R(14), + io[0],io[1],il,ir,t0,t1); + CAMELLIA_ROUNDSM(io[0],io[1], + CAMELLIA_SUBKEY_L(13),CAMELLIA_SUBKEY_R(13), + io[2],io[3],il,ir,t0,t1); + CAMELLIA_ROUNDSM(io[2],io[3], + CAMELLIA_SUBKEY_L(12),CAMELLIA_SUBKEY_R(12), + io[0],io[1],il,ir,t0,t1); + CAMELLIA_ROUNDSM(io[0],io[1], + CAMELLIA_SUBKEY_L(11),CAMELLIA_SUBKEY_R(11), + io[2],io[3],il,ir,t0,t1); + CAMELLIA_ROUNDSM(io[2],io[3], + CAMELLIA_SUBKEY_L(10),CAMELLIA_SUBKEY_R(10), + io[0],io[1],il,ir,t0,t1); + + CAMELLIA_FLS(io[0],io[1],io[2],io[3], + CAMELLIA_SUBKEY_L(9),CAMELLIA_SUBKEY_R(9), + CAMELLIA_SUBKEY_L(8),CAMELLIA_SUBKEY_R(8), + t0,t1,il,ir); + + CAMELLIA_ROUNDSM(io[0],io[1], + CAMELLIA_SUBKEY_L(7),CAMELLIA_SUBKEY_R(7), + io[2],io[3],il,ir,t0,t1); + CAMELLIA_ROUNDSM(io[2],io[3], + CAMELLIA_SUBKEY_L(6),CAMELLIA_SUBKEY_R(6), + io[0],io[1],il,ir,t0,t1); + CAMELLIA_ROUNDSM(io[0],io[1], + CAMELLIA_SUBKEY_L(5),CAMELLIA_SUBKEY_R(5), + io[2],io[3],il,ir,t0,t1); + CAMELLIA_ROUNDSM(io[2],io[3], + CAMELLIA_SUBKEY_L(4),CAMELLIA_SUBKEY_R(4), + io[0],io[1],il,ir,t0,t1); + CAMELLIA_ROUNDSM(io[0],io[1], + CAMELLIA_SUBKEY_L(3),CAMELLIA_SUBKEY_R(3), + io[2],io[3],il,ir,t0,t1); + CAMELLIA_ROUNDSM(io[2],io[3], + CAMELLIA_SUBKEY_L(2),CAMELLIA_SUBKEY_R(2), + io[0],io[1],il,ir,t0,t1); + + /* post whitening but kw4 */ + io[2] ^= CAMELLIA_SUBKEY_L(0); + io[3] ^= CAMELLIA_SUBKEY_R(0); + + t0 = io[0]; + t1 = io[1]; + io[0] = io[2]; + io[1] = io[3]; + io[2] = t0; + io[3] = t1; + + io_text[0] = cpu_to_be32(io[0]); + io_text[1] = cpu_to_be32(io[1]); + io_text[2] = cpu_to_be32(io[2]); + io_text[3] = cpu_to_be32(io[3]); + + return; +} + + +/** + * stuff for 192 and 256bit encryption/decryption + */ +static void camellia_encrypt256(const u32 *subkey, __be32 *io_text) +{ + u32 il,ir,t0,t1; /* temporary valiables */ + + u32 io[4]; + + io[0] = be32_to_cpu(io_text[0]); + io[1] = be32_to_cpu(io_text[1]); + io[2] = be32_to_cpu(io_text[2]); + io[3] = be32_to_cpu(io_text[3]); + + /* pre whitening but absorb kw2*/ + io[0] ^= CAMELLIA_SUBKEY_L(0); + io[1] ^= CAMELLIA_SUBKEY_R(0); + + /* main iteration */ + CAMELLIA_ROUNDSM(io[0],io[1], + CAMELLIA_SUBKEY_L(2),CAMELLIA_SUBKEY_R(2), + io[2],io[3],il,ir,t0,t1); + CAMELLIA_ROUNDSM(io[2],io[3], + CAMELLIA_SUBKEY_L(3),CAMELLIA_SUBKEY_R(3), + io[0],io[1],il,ir,t0,t1); + CAMELLIA_ROUNDSM(io[0],io[1], + CAMELLIA_SUBKEY_L(4),CAMELLIA_SUBKEY_R(4), + io[2],io[3],il,ir,t0,t1); + CAMELLIA_ROUNDSM(io[2],io[3], + CAMELLIA_SUBKEY_L(5),CAMELLIA_SUBKEY_R(5), + io[0],io[1],il,ir,t0,t1); + CAMELLIA_ROUNDSM(io[0],io[1], + CAMELLIA_SUBKEY_L(6),CAMELLIA_SUBKEY_R(6), + io[2],io[3],il,ir,t0,t1); + CAMELLIA_ROUNDSM(io[2],io[3], + CAMELLIA_SUBKEY_L(7),CAMELLIA_SUBKEY_R(7), + io[0],io[1],il,ir,t0,t1); + + CAMELLIA_FLS(io[0],io[1],io[2],io[3], + CAMELLIA_SUBKEY_L(8),CAMELLIA_SUBKEY_R(8), + CAMELLIA_SUBKEY_L(9),CAMELLIA_SUBKEY_R(9), + t0,t1,il,ir); + + CAMELLIA_ROUNDSM(io[0],io[1], + CAMELLIA_SUBKEY_L(10),CAMELLIA_SUBKEY_R(10), + io[2],io[3],il,ir,t0,t1); + CAMELLIA_ROUNDSM(io[2],io[3], + CAMELLIA_SUBKEY_L(11),CAMELLIA_SUBKEY_R(11), + io[0],io[1],il,ir,t0,t1); + CAMELLIA_ROUNDSM(io[0],io[1], + CAMELLIA_SUBKEY_L(12),CAMELLIA_SUBKEY_R(12), + io[2],io[3],il,ir,t0,t1); + CAMELLIA_ROUNDSM(io[2],io[3], + CAMELLIA_SUBKEY_L(13),CAMELLIA_SUBKEY_R(13), + io[0],io[1],il,ir,t0,t1); + CAMELLIA_ROUNDSM(io[0],io[1], + CAMELLIA_SUBKEY_L(14),CAMELLIA_SUBKEY_R(14), + io[2],io[3],il,ir,t0,t1); + CAMELLIA_ROUNDSM(io[2],io[3], + CAMELLIA_SUBKEY_L(15),CAMELLIA_SUBKEY_R(15), + io[0],io[1],il,ir,t0,t1); + + CAMELLIA_FLS(io[0],io[1],io[2],io[3], + CAMELLIA_SUBKEY_L(16),CAMELLIA_SUBKEY_R(16), + CAMELLIA_SUBKEY_L(17),CAMELLIA_SUBKEY_R(17), + t0,t1,il,ir); + + CAMELLIA_ROUNDSM(io[0],io[1], + CAMELLIA_SUBKEY_L(18),CAMELLIA_SUBKEY_R(18), + io[2],io[3],il,ir,t0,t1); + CAMELLIA_ROUNDSM(io[2],io[3], + CAMELLIA_SUBKEY_L(19),CAMELLIA_SUBKEY_R(19), + io[0],io[1],il,ir,t0,t1); + CAMELLIA_ROUNDSM(io[0],io[1], + CAMELLIA_SUBKEY_L(20),CAMELLIA_SUBKEY_R(20), + io[2],io[3],il,ir,t0,t1); + CAMELLIA_ROUNDSM(io[2],io[3], + CAMELLIA_SUBKEY_L(21),CAMELLIA_SUBKEY_R(21), + io[0],io[1],il,ir,t0,t1); + CAMELLIA_ROUNDSM(io[0],io[1], + CAMELLIA_SUBKEY_L(22),CAMELLIA_SUBKEY_R(22), + io[2],io[3],il,ir,t0,t1); + CAMELLIA_ROUNDSM(io[2],io[3], + CAMELLIA_SUBKEY_L(23),CAMELLIA_SUBKEY_R(23), + io[0],io[1],il,ir,t0,t1); + + CAMELLIA_FLS(io[0],io[1],io[2],io[3], + CAMELLIA_SUBKEY_L(24),CAMELLIA_SUBKEY_R(24), + CAMELLIA_SUBKEY_L(25),CAMELLIA_SUBKEY_R(25), + t0,t1,il,ir); + + CAMELLIA_ROUNDSM(io[0],io[1], + CAMELLIA_SUBKEY_L(26),CAMELLIA_SUBKEY_R(26), + io[2],io[3],il,ir,t0,t1); + CAMELLIA_ROUNDSM(io[2],io[3], + CAMELLIA_SUBKEY_L(27),CAMELLIA_SUBKEY_R(27), + io[0],io[1],il,ir,t0,t1); + CAMELLIA_ROUNDSM(io[0],io[1], + CAMELLIA_SUBKEY_L(28),CAMELLIA_SUBKEY_R(28), + io[2],io[3],il,ir,t0,t1); + CAMELLIA_ROUNDSM(io[2],io[3], + CAMELLIA_SUBKEY_L(29),CAMELLIA_SUBKEY_R(29), + io[0],io[1],il,ir,t0,t1); + CAMELLIA_ROUNDSM(io[0],io[1], + CAMELLIA_SUBKEY_L(30),CAMELLIA_SUBKEY_R(30), + io[2],io[3],il,ir,t0,t1); + CAMELLIA_ROUNDSM(io[2],io[3], + CAMELLIA_SUBKEY_L(31),CAMELLIA_SUBKEY_R(31), + io[0],io[1],il,ir,t0,t1); + + /* post whitening but kw4 */ + io[2] ^= CAMELLIA_SUBKEY_L(32); + io[3] ^= CAMELLIA_SUBKEY_R(32); + + t0 = io[0]; + t1 = io[1]; + io[0] = io[2]; + io[1] = io[3]; + io[2] = t0; + io[3] = t1; + + io_text[0] = cpu_to_be32(io[0]); + io_text[1] = cpu_to_be32(io[1]); + io_text[2] = cpu_to_be32(io[2]); + io_text[3] = cpu_to_be32(io[3]); + + return; +} + + +static void camellia_decrypt256(const u32 *subkey, __be32 *io_text) +{ + u32 il,ir,t0,t1; /* temporary valiables */ + + u32 io[4]; + + io[0] = be32_to_cpu(io_text[0]); + io[1] = be32_to_cpu(io_text[1]); + io[2] = be32_to_cpu(io_text[2]); + io[3] = be32_to_cpu(io_text[3]); + + /* pre whitening but absorb kw2*/ + io[0] ^= CAMELLIA_SUBKEY_L(32); + io[1] ^= CAMELLIA_SUBKEY_R(32); + + /* main iteration */ + CAMELLIA_ROUNDSM(io[0],io[1], + CAMELLIA_SUBKEY_L(31),CAMELLIA_SUBKEY_R(31), + io[2],io[3],il,ir,t0,t1); + CAMELLIA_ROUNDSM(io[2],io[3], + CAMELLIA_SUBKEY_L(30),CAMELLIA_SUBKEY_R(30), + io[0],io[1],il,ir,t0,t1); + CAMELLIA_ROUNDSM(io[0],io[1], + CAMELLIA_SUBKEY_L(29),CAMELLIA_SUBKEY_R(29), + io[2],io[3],il,ir,t0,t1); + CAMELLIA_ROUNDSM(io[2],io[3], + CAMELLIA_SUBKEY_L(28),CAMELLIA_SUBKEY_R(28), + io[0],io[1],il,ir,t0,t1); + CAMELLIA_ROUNDSM(io[0],io[1], + CAMELLIA_SUBKEY_L(27),CAMELLIA_SUBKEY_R(27), + io[2],io[3],il,ir,t0,t1); + CAMELLIA_ROUNDSM(io[2],io[3], + CAMELLIA_SUBKEY_L(26),CAMELLIA_SUBKEY_R(26), + io[0],io[1],il,ir,t0,t1); + + CAMELLIA_FLS(io[0],io[1],io[2],io[3], + CAMELLIA_SUBKEY_L(25),CAMELLIA_SUBKEY_R(25), + CAMELLIA_SUBKEY_L(24),CAMELLIA_SUBKEY_R(24), + t0,t1,il,ir); + + CAMELLIA_ROUNDSM(io[0],io[1], + CAMELLIA_SUBKEY_L(23),CAMELLIA_SUBKEY_R(23), + io[2],io[3],il,ir,t0,t1); + CAMELLIA_ROUNDSM(io[2],io[3], + CAMELLIA_SUBKEY_L(22),CAMELLIA_SUBKEY_R(22), + io[0],io[1],il,ir,t0,t1); + CAMELLIA_ROUNDSM(io[0],io[1], + CAMELLIA_SUBKEY_L(21),CAMELLIA_SUBKEY_R(21), + io[2],io[3],il,ir,t0,t1); + CAMELLIA_ROUNDSM(io[2],io[3], + CAMELLIA_SUBKEY_L(20),CAMELLIA_SUBKEY_R(20), + io[0],io[1],il,ir,t0,t1); + CAMELLIA_ROUNDSM(io[0],io[1], + CAMELLIA_SUBKEY_L(19),CAMELLIA_SUBKEY_R(19), + io[2],io[3],il,ir,t0,t1); + CAMELLIA_ROUNDSM(io[2],io[3], + CAMELLIA_SUBKEY_L(18),CAMELLIA_SUBKEY_R(18), + io[0],io[1],il,ir,t0,t1); + + CAMELLIA_FLS(io[0],io[1],io[2],io[3], + CAMELLIA_SUBKEY_L(17),CAMELLIA_SUBKEY_R(17), + CAMELLIA_SUBKEY_L(16),CAMELLIA_SUBKEY_R(16), + t0,t1,il,ir); + + CAMELLIA_ROUNDSM(io[0],io[1], + CAMELLIA_SUBKEY_L(15),CAMELLIA_SUBKEY_R(15), + io[2],io[3],il,ir,t0,t1); + CAMELLIA_ROUNDSM(io[2],io[3], + CAMELLIA_SUBKEY_L(14),CAMELLIA_SUBKEY_R(14), + io[0],io[1],il,ir,t0,t1); + CAMELLIA_ROUNDSM(io[0],io[1], + CAMELLIA_SUBKEY_L(13),CAMELLIA_SUBKEY_R(13), + io[2],io[3],il,ir,t0,t1); + CAMELLIA_ROUNDSM(io[2],io[3], + CAMELLIA_SUBKEY_L(12),CAMELLIA_SUBKEY_R(12), + io[0],io[1],il,ir,t0,t1); + CAMELLIA_ROUNDSM(io[0],io[1], + CAMELLIA_SUBKEY_L(11),CAMELLIA_SUBKEY_R(11), + io[2],io[3],il,ir,t0,t1); + CAMELLIA_ROUNDSM(io[2],io[3], + CAMELLIA_SUBKEY_L(10),CAMELLIA_SUBKEY_R(10), + io[0],io[1],il,ir,t0,t1); + + CAMELLIA_FLS(io[0],io[1],io[2],io[3], + CAMELLIA_SUBKEY_L(9),CAMELLIA_SUBKEY_R(9), + CAMELLIA_SUBKEY_L(8),CAMELLIA_SUBKEY_R(8), + t0,t1,il,ir); + + CAMELLIA_ROUNDSM(io[0],io[1], + CAMELLIA_SUBKEY_L(7),CAMELLIA_SUBKEY_R(7), + io[2],io[3],il,ir,t0,t1); + CAMELLIA_ROUNDSM(io[2],io[3], + CAMELLIA_SUBKEY_L(6),CAMELLIA_SUBKEY_R(6), + io[0],io[1],il,ir,t0,t1); + CAMELLIA_ROUNDSM(io[0],io[1], + CAMELLIA_SUBKEY_L(5),CAMELLIA_SUBKEY_R(5), + io[2],io[3],il,ir,t0,t1); + CAMELLIA_ROUNDSM(io[2],io[3], + CAMELLIA_SUBKEY_L(4),CAMELLIA_SUBKEY_R(4), + io[0],io[1],il,ir,t0,t1); + CAMELLIA_ROUNDSM(io[0],io[1], + CAMELLIA_SUBKEY_L(3),CAMELLIA_SUBKEY_R(3), + io[2],io[3],il,ir,t0,t1); + CAMELLIA_ROUNDSM(io[2],io[3], + CAMELLIA_SUBKEY_L(2),CAMELLIA_SUBKEY_R(2), + io[0],io[1],il,ir,t0,t1); + + /* post whitening but kw4 */ + io[2] ^= CAMELLIA_SUBKEY_L(0); + io[3] ^= CAMELLIA_SUBKEY_R(0); + + t0 = io[0]; + t1 = io[1]; + io[0] = io[2]; + io[1] = io[3]; + io[2] = t0; + io[3] = t1; + + io_text[0] = cpu_to_be32(io[0]); + io_text[1] = cpu_to_be32(io[1]); + io_text[2] = cpu_to_be32(io[2]); + io_text[3] = cpu_to_be32(io[3]); + + return; +} + + +static int +camellia_set_key(struct crypto_tfm *tfm, const u8 *in_key, + unsigned int key_len) +{ + struct camellia_ctx *cctx = crypto_tfm_ctx(tfm); + const unsigned char *key = (const unsigned char *)in_key; + u32 *flags = &tfm->crt_flags; + + if (key_len != 16 && key_len != 24 && key_len != 32) { + *flags |= CRYPTO_TFM_RES_BAD_KEY_LEN; + return -EINVAL; + } + + cctx->key_length = key_len; + + switch(key_len) { + case 16: + camellia_setup128(key, cctx->key_table); + break; + case 24: + camellia_setup192(key, cctx->key_table); + break; + case 32: + camellia_setup256(key, cctx->key_table); + break; + default: + break; + } + + return 0; +} + + +static void camellia_encrypt(struct crypto_tfm *tfm, u8 *out, const u8 *in) +{ + const struct camellia_ctx *cctx = crypto_tfm_ctx(tfm); + const __be32 *src = (const __be32 *)in; + __be32 *dst = (__be32 *)out; + + __be32 tmp[4]; + + memcpy(tmp, src, CAMELLIA_BLOCK_SIZE); + + switch (cctx->key_length) { + case 16: + camellia_encrypt128(cctx->key_table, tmp); + break; + case 24: + /* fall through */ + case 32: + camellia_encrypt256(cctx->key_table, tmp); + break; + default: + break; + } + + memcpy(dst, tmp, CAMELLIA_BLOCK_SIZE); +} + + +static void camellia_decrypt(struct crypto_tfm *tfm, u8 *out, const u8 *in) +{ + const struct camellia_ctx *cctx = crypto_tfm_ctx(tfm); + const __be32 *src = (const __be32 *)in; + __be32 *dst = (__be32 *)out; + + __be32 tmp[4]; + + memcpy(tmp, src, CAMELLIA_BLOCK_SIZE); + + switch (cctx->key_length) { + case 16: + camellia_decrypt128(cctx->key_table, tmp); + break; + case 24: + /* fall through */ + case 32: + camellia_decrypt256(cctx->key_table, tmp); + break; + default: + break; + } + + memcpy(dst, tmp, CAMELLIA_BLOCK_SIZE); +} + + +static struct crypto_alg camellia_alg = { + .cra_name = "camellia", + .cra_driver_name = "camellia-generic", + .cra_priority = 100, + .cra_flags = CRYPTO_ALG_TYPE_CIPHER, + .cra_blocksize = CAMELLIA_BLOCK_SIZE, + .cra_ctxsize = sizeof(struct camellia_ctx), + .cra_alignmask = 3, + .cra_module = THIS_MODULE, + .cra_list = LIST_HEAD_INIT(camellia_alg.cra_list), + .cra_u = { + .cipher = { + .cia_min_keysize = CAMELLIA_MIN_KEY_SIZE, + .cia_max_keysize = CAMELLIA_MAX_KEY_SIZE, + .cia_setkey = camellia_set_key, + .cia_encrypt = camellia_encrypt, + .cia_decrypt = camellia_decrypt + } + } +}; + +static int __init camellia_init(void) +{ + return crypto_register_alg(&camellia_alg); +} + + +static void __exit camellia_fini(void) +{ + crypto_unregister_alg(&camellia_alg); +} + + +module_init(camellia_init); +module_exit(camellia_fini); + + +MODULE_DESCRIPTION("Camellia Cipher Algorithm"); +MODULE_LICENSE("GPL"); diff --git a/crypto/cbc.c b/crypto/cbc.c index f5542b4..136fea7 100644 --- a/crypto/cbc.c +++ b/crypto/cbc.c @@ -243,6 +243,7 @@ static int crypto_cbc_init_tfm(struct cr struct crypto_instance *inst = (void *)tfm->__crt_alg; struct crypto_spawn *spawn = crypto_instance_ctx(inst); struct crypto_cbc_ctx *ctx = crypto_tfm_ctx(tfm); + struct crypto_cipher *cipher; switch (crypto_tfm_alg_blocksize(tfm)) { case 8: @@ -260,11 +261,11 @@ static int crypto_cbc_init_tfm(struct cr ctx->xor = xor_quad; } - tfm = crypto_spawn_tfm(spawn); - if (IS_ERR(tfm)) - return PTR_ERR(tfm); + cipher = crypto_spawn_cipher(spawn); + if (IS_ERR(cipher)) + return PTR_ERR(cipher); - ctx->child = crypto_cipher_cast(tfm); + ctx->child = cipher; return 0; } diff --git a/crypto/cipher.c b/crypto/cipher.c index 9e03701..333aab2 100644 --- a/crypto/cipher.c +++ b/crypto/cipher.c @@ -12,274 +12,13 @@ * any later version. * */ -#include + #include #include #include -#include -#include +#include #include -#include #include "internal.h" -#include "scatterwalk.h" - -struct cipher_alg_compat { - unsigned int cia_min_keysize; - unsigned int cia_max_keysize; - int (*cia_setkey)(struct crypto_tfm *tfm, const u8 *key, - unsigned int keylen); - void (*cia_encrypt)(struct crypto_tfm *tfm, u8 *dst, const u8 *src); - void (*cia_decrypt)(struct crypto_tfm *tfm, u8 *dst, const u8 *src); - - unsigned int (*cia_encrypt_ecb)(const struct cipher_desc *desc, - u8 *dst, const u8 *src, - unsigned int nbytes); - unsigned int (*cia_decrypt_ecb)(const struct cipher_desc *desc, - u8 *dst, const u8 *src, - unsigned int nbytes); - unsigned int (*cia_encrypt_cbc)(const struct cipher_desc *desc, - u8 *dst, const u8 *src, - unsigned int nbytes); - unsigned int (*cia_decrypt_cbc)(const struct cipher_desc *desc, - u8 *dst, const u8 *src, - unsigned int nbytes); -}; - -static inline void xor_64(u8 *a, const u8 *b) -{ - ((u32 *)a)[0] ^= ((u32 *)b)[0]; - ((u32 *)a)[1] ^= ((u32 *)b)[1]; -} - -static inline void xor_128(u8 *a, const u8 *b) -{ - ((u32 *)a)[0] ^= ((u32 *)b)[0]; - ((u32 *)a)[1] ^= ((u32 *)b)[1]; - ((u32 *)a)[2] ^= ((u32 *)b)[2]; - ((u32 *)a)[3] ^= ((u32 *)b)[3]; -} - -static unsigned int crypt_slow(const struct cipher_desc *desc, - struct scatter_walk *in, - struct scatter_walk *out, unsigned int bsize) -{ - unsigned long alignmask = crypto_tfm_alg_alignmask(desc->tfm); - u8 buffer[bsize * 2 + alignmask]; - u8 *src = (u8 *)ALIGN((unsigned long)buffer, alignmask + 1); - u8 *dst = src + bsize; - - scatterwalk_copychunks(src, in, bsize, 0); - desc->prfn(desc, dst, src, bsize); - scatterwalk_copychunks(dst, out, bsize, 1); - - return bsize; -} - -static inline unsigned int crypt_fast(const struct cipher_desc *desc, - struct scatter_walk *in, - struct scatter_walk *out, - unsigned int nbytes, u8 *tmp) -{ - u8 *src, *dst; - u8 *real_src, *real_dst; - - real_src = scatterwalk_map(in, 0); - real_dst = scatterwalk_map(out, 1); - - src = real_src; - dst = scatterwalk_samebuf(in, out) ? src : real_dst; - - if (tmp) { - memcpy(tmp, src, nbytes); - src = tmp; - dst = tmp; - } - - nbytes = desc->prfn(desc, dst, src, nbytes); - - if (tmp) - memcpy(real_dst, tmp, nbytes); - - scatterwalk_unmap(real_src, 0); - scatterwalk_unmap(real_dst, 1); - - scatterwalk_advance(in, nbytes); - scatterwalk_advance(out, nbytes); - - return nbytes; -} - -/* - * Generic encrypt/decrypt wrapper for ciphers, handles operations across - * multiple page boundaries by using temporary blocks. In user context, - * the kernel is given a chance to schedule us once per page. - */ -static int crypt(const struct cipher_desc *desc, - struct scatterlist *dst, - struct scatterlist *src, - unsigned int nbytes) -{ - struct scatter_walk walk_in, walk_out; - struct crypto_tfm *tfm = desc->tfm; - const unsigned int bsize = crypto_tfm_alg_blocksize(tfm); - unsigned int alignmask = crypto_tfm_alg_alignmask(tfm); - unsigned long buffer = 0; - - if (!nbytes) - return 0; - - if (nbytes % bsize) { - tfm->crt_flags |= CRYPTO_TFM_RES_BAD_BLOCK_LEN; - return -EINVAL; - } - - scatterwalk_start(&walk_in, src); - scatterwalk_start(&walk_out, dst); - - for(;;) { - unsigned int n = nbytes; - u8 *tmp = NULL; - - if (!scatterwalk_aligned(&walk_in, alignmask) || - !scatterwalk_aligned(&walk_out, alignmask)) { - if (!buffer) { - buffer = __get_free_page(GFP_ATOMIC); - if (!buffer) - n = 0; - } - tmp = (u8 *)buffer; - } - - n = scatterwalk_clamp(&walk_in, n); - n = scatterwalk_clamp(&walk_out, n); - - if (likely(n >= bsize)) - n = crypt_fast(desc, &walk_in, &walk_out, n, tmp); - else - n = crypt_slow(desc, &walk_in, &walk_out, bsize); - - nbytes -= n; - - scatterwalk_done(&walk_in, 0, nbytes); - scatterwalk_done(&walk_out, 1, nbytes); - - if (!nbytes) - break; - - crypto_yield(tfm->crt_flags); - } - - if (buffer) - free_page(buffer); - - return 0; -} - -static int crypt_iv_unaligned(struct cipher_desc *desc, - struct scatterlist *dst, - struct scatterlist *src, - unsigned int nbytes) -{ - struct crypto_tfm *tfm = desc->tfm; - unsigned long alignmask = crypto_tfm_alg_alignmask(tfm); - u8 *iv = desc->info; - - if (unlikely(((unsigned long)iv & alignmask))) { - unsigned int ivsize = tfm->crt_cipher.cit_ivsize; - u8 buffer[ivsize + alignmask]; - u8 *tmp = (u8 *)ALIGN((unsigned long)buffer, alignmask + 1); - int err; - - desc->info = memcpy(tmp, iv, ivsize); - err = crypt(desc, dst, src, nbytes); - memcpy(iv, tmp, ivsize); - - return err; - } - - return crypt(desc, dst, src, nbytes); -} - -static unsigned int cbc_process_encrypt(const struct cipher_desc *desc, - u8 *dst, const u8 *src, - unsigned int nbytes) -{ - struct crypto_tfm *tfm = desc->tfm; - void (*xor)(u8 *, const u8 *) = tfm->crt_u.cipher.cit_xor_block; - int bsize = crypto_tfm_alg_blocksize(tfm); - - void (*fn)(struct crypto_tfm *, u8 *, const u8 *) = desc->crfn; - u8 *iv = desc->info; - unsigned int done = 0; - - nbytes -= bsize; - - do { - xor(iv, src); - fn(tfm, dst, iv); - memcpy(iv, dst, bsize); - - src += bsize; - dst += bsize; - } while ((done += bsize) <= nbytes); - - return done; -} - -static unsigned int cbc_process_decrypt(const struct cipher_desc *desc, - u8 *dst, const u8 *src, - unsigned int nbytes) -{ - struct crypto_tfm *tfm = desc->tfm; - void (*xor)(u8 *, const u8 *) = tfm->crt_u.cipher.cit_xor_block; - int bsize = crypto_tfm_alg_blocksize(tfm); - unsigned long alignmask = crypto_tfm_alg_alignmask(desc->tfm); - - u8 stack[src == dst ? bsize + alignmask : 0]; - u8 *buf = (u8 *)ALIGN((unsigned long)stack, alignmask + 1); - u8 **dst_p = src == dst ? &buf : &dst; - - void (*fn)(struct crypto_tfm *, u8 *, const u8 *) = desc->crfn; - u8 *iv = desc->info; - unsigned int done = 0; - - nbytes -= bsize; - - do { - u8 *tmp_dst = *dst_p; - - fn(tfm, tmp_dst, src); - xor(tmp_dst, iv); - memcpy(iv, src, bsize); - if (tmp_dst != dst) - memcpy(dst, tmp_dst, bsize); - - src += bsize; - dst += bsize; - } while ((done += bsize) <= nbytes); - - return done; -} - -static unsigned int ecb_process(const struct cipher_desc *desc, u8 *dst, - const u8 *src, unsigned int nbytes) -{ - struct crypto_tfm *tfm = desc->tfm; - int bsize = crypto_tfm_alg_blocksize(tfm); - void (*fn)(struct crypto_tfm *, u8 *, const u8 *) = desc->crfn; - unsigned int done = 0; - - nbytes -= bsize; - - do { - fn(tfm, dst, src); - - src += bsize; - dst += bsize; - } while ((done += bsize) <= nbytes); - - return done; -} static int setkey(struct crypto_tfm *tfm, const u8 *key, unsigned int keylen) { @@ -293,122 +32,6 @@ static int setkey(struct crypto_tfm *tfm return cia->cia_setkey(tfm, key, keylen); } -static int ecb_encrypt(struct crypto_tfm *tfm, - struct scatterlist *dst, - struct scatterlist *src, unsigned int nbytes) -{ - struct cipher_desc desc; - struct cipher_alg_compat *cipher = (void *)&tfm->__crt_alg->cra_cipher; - - desc.tfm = tfm; - desc.crfn = cipher->cia_encrypt; - desc.prfn = cipher->cia_encrypt_ecb ?: ecb_process; - - return crypt(&desc, dst, src, nbytes); -} - -static int ecb_decrypt(struct crypto_tfm *tfm, - struct scatterlist *dst, - struct scatterlist *src, - unsigned int nbytes) -{ - struct cipher_desc desc; - struct cipher_alg_compat *cipher = (void *)&tfm->__crt_alg->cra_cipher; - - desc.tfm = tfm; - desc.crfn = cipher->cia_decrypt; - desc.prfn = cipher->cia_decrypt_ecb ?: ecb_process; - - return crypt(&desc, dst, src, nbytes); -} - -static int cbc_encrypt(struct crypto_tfm *tfm, - struct scatterlist *dst, - struct scatterlist *src, - unsigned int nbytes) -{ - struct cipher_desc desc; - struct cipher_alg_compat *cipher = (void *)&tfm->__crt_alg->cra_cipher; - - desc.tfm = tfm; - desc.crfn = cipher->cia_encrypt; - desc.prfn = cipher->cia_encrypt_cbc ?: cbc_process_encrypt; - desc.info = tfm->crt_cipher.cit_iv; - - return crypt(&desc, dst, src, nbytes); -} - -static int cbc_encrypt_iv(struct crypto_tfm *tfm, - struct scatterlist *dst, - struct scatterlist *src, - unsigned int nbytes, u8 *iv) -{ - struct cipher_desc desc; - struct cipher_alg_compat *cipher = (void *)&tfm->__crt_alg->cra_cipher; - - desc.tfm = tfm; - desc.crfn = cipher->cia_encrypt; - desc.prfn = cipher->cia_encrypt_cbc ?: cbc_process_encrypt; - desc.info = iv; - - return crypt_iv_unaligned(&desc, dst, src, nbytes); -} - -static int cbc_decrypt(struct crypto_tfm *tfm, - struct scatterlist *dst, - struct scatterlist *src, - unsigned int nbytes) -{ - struct cipher_desc desc; - struct cipher_alg_compat *cipher = (void *)&tfm->__crt_alg->cra_cipher; - - desc.tfm = tfm; - desc.crfn = cipher->cia_decrypt; - desc.prfn = cipher->cia_decrypt_cbc ?: cbc_process_decrypt; - desc.info = tfm->crt_cipher.cit_iv; - - return crypt(&desc, dst, src, nbytes); -} - -static int cbc_decrypt_iv(struct crypto_tfm *tfm, - struct scatterlist *dst, - struct scatterlist *src, - unsigned int nbytes, u8 *iv) -{ - struct cipher_desc desc; - struct cipher_alg_compat *cipher = (void *)&tfm->__crt_alg->cra_cipher; - - desc.tfm = tfm; - desc.crfn = cipher->cia_decrypt; - desc.prfn = cipher->cia_decrypt_cbc ?: cbc_process_decrypt; - desc.info = iv; - - return crypt_iv_unaligned(&desc, dst, src, nbytes); -} - -static int nocrypt(struct crypto_tfm *tfm, - struct scatterlist *dst, - struct scatterlist *src, - unsigned int nbytes) -{ - return -ENOSYS; -} - -static int nocrypt_iv(struct crypto_tfm *tfm, - struct scatterlist *dst, - struct scatterlist *src, - unsigned int nbytes, u8 *iv) -{ - return -ENOSYS; -} - -int crypto_init_cipher_flags(struct crypto_tfm *tfm, u32 flags) -{ - u32 mode = flags & CRYPTO_TFM_MODE_MASK; - tfm->crt_cipher.cit_mode = mode ? mode : CRYPTO_TFM_MODE_ECB; - return 0; -} - static void cipher_crypt_unaligned(void (*fn)(struct crypto_tfm *, u8 *, const u8 *), struct crypto_tfm *tfm, @@ -454,7 +77,6 @@ static void cipher_decrypt_unaligned(str int crypto_init_cipher_ops(struct crypto_tfm *tfm) { - int ret = 0; struct cipher_tfm *ops = &tfm->crt_cipher; struct cipher_alg *cipher = &tfm->__crt_alg->cra_cipher; @@ -464,70 +86,7 @@ int crypto_init_cipher_ops(struct crypto ops->cit_decrypt_one = crypto_tfm_alg_alignmask(tfm) ? cipher_decrypt_unaligned : cipher->cia_decrypt; - switch (tfm->crt_cipher.cit_mode) { - case CRYPTO_TFM_MODE_ECB: - ops->cit_encrypt = ecb_encrypt; - ops->cit_decrypt = ecb_decrypt; - ops->cit_encrypt_iv = nocrypt_iv; - ops->cit_decrypt_iv = nocrypt_iv; - break; - - case CRYPTO_TFM_MODE_CBC: - ops->cit_encrypt = cbc_encrypt; - ops->cit_decrypt = cbc_decrypt; - ops->cit_encrypt_iv = cbc_encrypt_iv; - ops->cit_decrypt_iv = cbc_decrypt_iv; - break; - - case CRYPTO_TFM_MODE_CFB: - ops->cit_encrypt = nocrypt; - ops->cit_decrypt = nocrypt; - ops->cit_encrypt_iv = nocrypt_iv; - ops->cit_decrypt_iv = nocrypt_iv; - break; - - case CRYPTO_TFM_MODE_CTR: - ops->cit_encrypt = nocrypt; - ops->cit_decrypt = nocrypt; - ops->cit_encrypt_iv = nocrypt_iv; - ops->cit_decrypt_iv = nocrypt_iv; - break; - - default: - BUG(); - } - - if (ops->cit_mode == CRYPTO_TFM_MODE_CBC) { - unsigned long align; - unsigned long addr; - - switch (crypto_tfm_alg_blocksize(tfm)) { - case 8: - ops->cit_xor_block = xor_64; - break; - - case 16: - ops->cit_xor_block = xor_128; - break; - - default: - printk(KERN_WARNING "%s: block size %u not supported\n", - crypto_tfm_alg_name(tfm), - crypto_tfm_alg_blocksize(tfm)); - ret = -EINVAL; - goto out; - } - - ops->cit_ivsize = crypto_tfm_alg_blocksize(tfm); - align = crypto_tfm_alg_alignmask(tfm) + 1; - addr = (unsigned long)crypto_tfm_ctx(tfm); - addr = ALIGN(addr, align); - addr += ALIGN(tfm->__crt_alg->cra_ctxsize, align); - ops->cit_iv = (void *)addr; - } - -out: - return ret; + return 0; } void crypto_exit_cipher_ops(struct crypto_tfm *tfm) diff --git a/crypto/compress.c b/crypto/compress.c index eca182a..0a65700 100644 --- a/crypto/compress.c +++ b/crypto/compress.c @@ -34,11 +34,6 @@ static int crypto_decompress(struct cryp dlen); } -int crypto_init_compress_flags(struct crypto_tfm *tfm, u32 flags) -{ - return flags ? -EINVAL : 0; -} - int crypto_init_compress_ops(struct crypto_tfm *tfm) { struct compress_tfm *ops = &tfm->crt_compress; diff --git a/crypto/digest.c b/crypto/digest.c index 8f45932..1bf7414 100644 --- a/crypto/digest.c +++ b/crypto/digest.c @@ -14,7 +14,9 @@ #include #include +#include #include +#include #include #include @@ -29,8 +31,8 @@ static int init(struct hash_desc *desc) return 0; } -static int update(struct hash_desc *desc, - struct scatterlist *sg, unsigned int nbytes) +static int update2(struct hash_desc *desc, + struct scatterlist *sg, unsigned int nbytes) { struct crypto_tfm *tfm = crypto_hash_tfm(desc->tfm); unsigned int alignmask = crypto_tfm_alg_alignmask(tfm); @@ -81,6 +83,14 @@ static int update(struct hash_desc *desc return 0; } +static int update(struct hash_desc *desc, + struct scatterlist *sg, unsigned int nbytes) +{ + if (WARN_ON_ONCE(in_irq())) + return -EDEADLK; + return update2(desc, sg, nbytes); +} + static int final(struct hash_desc *desc, u8 *out) { struct crypto_tfm *tfm = crypto_hash_tfm(desc->tfm); @@ -118,16 +128,14 @@ static int setkey(struct crypto_hash *ha static int digest(struct hash_desc *desc, struct scatterlist *sg, unsigned int nbytes, u8 *out) { + if (WARN_ON_ONCE(in_irq())) + return -EDEADLK; + init(desc); - update(desc, sg, nbytes); + update2(desc, sg, nbytes); return final(desc, out); } -int crypto_init_digest_flags(struct crypto_tfm *tfm, u32 flags) -{ - return flags ? -EINVAL : 0; -} - int crypto_init_digest_ops(struct crypto_tfm *tfm) { struct hash_tfm *ops = &tfm->crt_hash; diff --git a/crypto/ecb.c b/crypto/ecb.c index f239aa9..839a0ae 100644 --- a/crypto/ecb.c +++ b/crypto/ecb.c @@ -99,12 +99,13 @@ static int crypto_ecb_init_tfm(struct cr struct crypto_instance *inst = (void *)tfm->__crt_alg; struct crypto_spawn *spawn = crypto_instance_ctx(inst); struct crypto_ecb_ctx *ctx = crypto_tfm_ctx(tfm); + struct crypto_cipher *cipher; - tfm = crypto_spawn_tfm(spawn); - if (IS_ERR(tfm)) - return PTR_ERR(tfm); + cipher = crypto_spawn_cipher(spawn); + if (IS_ERR(cipher)) + return PTR_ERR(cipher); - ctx->child = crypto_cipher_cast(tfm); + ctx->child = cipher; return 0; } diff --git a/crypto/fcrypt.c b/crypto/fcrypt.c new file mode 100644 index 0000000..9c2bb53 --- /dev/null +++ b/crypto/fcrypt.c @@ -0,0 +1,423 @@ +/* FCrypt encryption algorithm + * + * Copyright (C) 2006 Red Hat, Inc. All Rights Reserved. + * Written by David Howells (dhowells@redhat.com) + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + * + * Based on code: + * + * Copyright (c) 1995 - 2000 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +#include +#include +#include +#include + +#define ROUNDS 16 + +struct fcrypt_ctx { + u32 sched[ROUNDS]; +}; + +/* Rotate right two 32 bit numbers as a 56 bit number */ +#define ror56(hi, lo, n) \ +do { \ + u32 t = lo & ((1 << n) - 1); \ + lo = (lo >> n) | ((hi & ((1 << n) - 1)) << (32 - n)); \ + hi = (hi >> n) | (t << (24-n)); \ +} while(0) + +/* Rotate right one 64 bit number as a 56 bit number */ +#define ror56_64(k, n) \ +do { \ + k = (k >> n) | ((k & ((1 << n) - 1)) << (56 - n)); \ +} while(0) + +/* + * Sboxes for Feistel network derived from + * /afs/transarc.com/public/afsps/afs.rel31b.export-src/rxkad/sboxes.h + */ +#undef Z +#define Z(x) __constant_be32_to_cpu(x << 3) +static const u32 sbox0[256] = { + Z(0xea), Z(0x7f), Z(0xb2), Z(0x64), Z(0x9d), Z(0xb0), Z(0xd9), Z(0x11), + Z(0xcd), Z(0x86), Z(0x86), Z(0x91), Z(0x0a), Z(0xb2), Z(0x93), Z(0x06), + Z(0x0e), Z(0x06), Z(0xd2), Z(0x65), Z(0x73), Z(0xc5), Z(0x28), Z(0x60), + Z(0xf2), Z(0x20), Z(0xb5), Z(0x38), Z(0x7e), Z(0xda), Z(0x9f), Z(0xe3), + Z(0xd2), Z(0xcf), Z(0xc4), Z(0x3c), Z(0x61), Z(0xff), Z(0x4a), Z(0x4a), + Z(0x35), Z(0xac), Z(0xaa), Z(0x5f), Z(0x2b), Z(0xbb), Z(0xbc), Z(0x53), + Z(0x4e), Z(0x9d), Z(0x78), Z(0xa3), Z(0xdc), Z(0x09), Z(0x32), Z(0x10), + Z(0xc6), Z(0x6f), Z(0x66), Z(0xd6), Z(0xab), Z(0xa9), Z(0xaf), Z(0xfd), + Z(0x3b), Z(0x95), Z(0xe8), Z(0x34), Z(0x9a), Z(0x81), Z(0x72), Z(0x80), + Z(0x9c), Z(0xf3), Z(0xec), Z(0xda), Z(0x9f), Z(0x26), Z(0x76), Z(0x15), + Z(0x3e), Z(0x55), Z(0x4d), Z(0xde), Z(0x84), Z(0xee), Z(0xad), Z(0xc7), + Z(0xf1), Z(0x6b), Z(0x3d), Z(0xd3), Z(0x04), Z(0x49), Z(0xaa), Z(0x24), + Z(0x0b), Z(0x8a), Z(0x83), Z(0xba), Z(0xfa), Z(0x85), Z(0xa0), Z(0xa8), + Z(0xb1), Z(0xd4), Z(0x01), Z(0xd8), Z(0x70), Z(0x64), Z(0xf0), Z(0x51), + Z(0xd2), Z(0xc3), Z(0xa7), Z(0x75), Z(0x8c), Z(0xa5), Z(0x64), Z(0xef), + Z(0x10), Z(0x4e), Z(0xb7), Z(0xc6), Z(0x61), Z(0x03), Z(0xeb), Z(0x44), + Z(0x3d), Z(0xe5), Z(0xb3), Z(0x5b), Z(0xae), Z(0xd5), Z(0xad), Z(0x1d), + Z(0xfa), Z(0x5a), Z(0x1e), Z(0x33), Z(0xab), Z(0x93), Z(0xa2), Z(0xb7), + Z(0xe7), Z(0xa8), Z(0x45), Z(0xa4), Z(0xcd), Z(0x29), Z(0x63), Z(0x44), + Z(0xb6), Z(0x69), Z(0x7e), Z(0x2e), Z(0x62), Z(0x03), Z(0xc8), Z(0xe0), + Z(0x17), Z(0xbb), Z(0xc7), Z(0xf3), Z(0x3f), Z(0x36), Z(0xba), Z(0x71), + Z(0x8e), Z(0x97), Z(0x65), Z(0x60), Z(0x69), Z(0xb6), Z(0xf6), Z(0xe6), + Z(0x6e), Z(0xe0), Z(0x81), Z(0x59), Z(0xe8), Z(0xaf), Z(0xdd), Z(0x95), + Z(0x22), Z(0x99), Z(0xfd), Z(0x63), Z(0x19), Z(0x74), Z(0x61), Z(0xb1), + Z(0xb6), Z(0x5b), Z(0xae), Z(0x54), Z(0xb3), Z(0x70), Z(0xff), Z(0xc6), + Z(0x3b), Z(0x3e), Z(0xc1), Z(0xd7), Z(0xe1), Z(0x0e), Z(0x76), Z(0xe5), + Z(0x36), Z(0x4f), Z(0x59), Z(0xc7), Z(0x08), Z(0x6e), Z(0x82), Z(0xa6), + Z(0x93), Z(0xc4), Z(0xaa), Z(0x26), Z(0x49), Z(0xe0), Z(0x21), Z(0x64), + Z(0x07), Z(0x9f), Z(0x64), Z(0x81), Z(0x9c), Z(0xbf), Z(0xf9), Z(0xd1), + Z(0x43), Z(0xf8), Z(0xb6), Z(0xb9), Z(0xf1), Z(0x24), Z(0x75), Z(0x03), + Z(0xe4), Z(0xb0), Z(0x99), Z(0x46), Z(0x3d), Z(0xf5), Z(0xd1), Z(0x39), + Z(0x72), Z(0x12), Z(0xf6), Z(0xba), Z(0x0c), Z(0x0d), Z(0x42), Z(0x2e) +}; + +#undef Z +#define Z(x) __constant_be32_to_cpu((x << 27) | (x >> 5)) +static const u32 sbox1[256] = { + Z(0x77), Z(0x14), Z(0xa6), Z(0xfe), Z(0xb2), Z(0x5e), Z(0x8c), Z(0x3e), + Z(0x67), Z(0x6c), Z(0xa1), Z(0x0d), Z(0xc2), Z(0xa2), Z(0xc1), Z(0x85), + Z(0x6c), Z(0x7b), Z(0x67), Z(0xc6), Z(0x23), Z(0xe3), Z(0xf2), Z(0x89), + Z(0x50), Z(0x9c), Z(0x03), Z(0xb7), Z(0x73), Z(0xe6), Z(0xe1), Z(0x39), + Z(0x31), Z(0x2c), Z(0x27), Z(0x9f), Z(0xa5), Z(0x69), Z(0x44), Z(0xd6), + Z(0x23), Z(0x83), Z(0x98), Z(0x7d), Z(0x3c), Z(0xb4), Z(0x2d), Z(0x99), + Z(0x1c), Z(0x1f), Z(0x8c), Z(0x20), Z(0x03), Z(0x7c), Z(0x5f), Z(0xad), + Z(0xf4), Z(0xfa), Z(0x95), Z(0xca), Z(0x76), Z(0x44), Z(0xcd), Z(0xb6), + Z(0xb8), Z(0xa1), Z(0xa1), Z(0xbe), Z(0x9e), Z(0x54), Z(0x8f), Z(0x0b), + Z(0x16), Z(0x74), Z(0x31), Z(0x8a), Z(0x23), Z(0x17), Z(0x04), Z(0xfa), + Z(0x79), Z(0x84), Z(0xb1), Z(0xf5), Z(0x13), Z(0xab), Z(0xb5), Z(0x2e), + Z(0xaa), Z(0x0c), Z(0x60), Z(0x6b), Z(0x5b), Z(0xc4), Z(0x4b), Z(0xbc), + Z(0xe2), Z(0xaf), Z(0x45), Z(0x73), Z(0xfa), Z(0xc9), Z(0x49), Z(0xcd), + Z(0x00), Z(0x92), Z(0x7d), Z(0x97), Z(0x7a), Z(0x18), Z(0x60), Z(0x3d), + Z(0xcf), Z(0x5b), Z(0xde), Z(0xc6), Z(0xe2), Z(0xe6), Z(0xbb), Z(0x8b), + Z(0x06), Z(0xda), Z(0x08), Z(0x15), Z(0x1b), Z(0x88), Z(0x6a), Z(0x17), + Z(0x89), Z(0xd0), Z(0xa9), Z(0xc1), Z(0xc9), Z(0x70), Z(0x6b), Z(0xe5), + Z(0x43), Z(0xf4), Z(0x68), Z(0xc8), Z(0xd3), Z(0x84), Z(0x28), Z(0x0a), + Z(0x52), Z(0x66), Z(0xa3), Z(0xca), Z(0xf2), Z(0xe3), Z(0x7f), Z(0x7a), + Z(0x31), Z(0xf7), Z(0x88), Z(0x94), Z(0x5e), Z(0x9c), Z(0x63), Z(0xd5), + Z(0x24), Z(0x66), Z(0xfc), Z(0xb3), Z(0x57), Z(0x25), Z(0xbe), Z(0x89), + Z(0x44), Z(0xc4), Z(0xe0), Z(0x8f), Z(0x23), Z(0x3c), Z(0x12), Z(0x52), + Z(0xf5), Z(0x1e), Z(0xf4), Z(0xcb), Z(0x18), Z(0x33), Z(0x1f), Z(0xf8), + Z(0x69), Z(0x10), Z(0x9d), Z(0xd3), Z(0xf7), Z(0x28), Z(0xf8), Z(0x30), + Z(0x05), Z(0x5e), Z(0x32), Z(0xc0), Z(0xd5), Z(0x19), Z(0xbd), Z(0x45), + Z(0x8b), Z(0x5b), Z(0xfd), Z(0xbc), Z(0xe2), Z(0x5c), Z(0xa9), Z(0x96), + Z(0xef), Z(0x70), Z(0xcf), Z(0xc2), Z(0x2a), Z(0xb3), Z(0x61), Z(0xad), + Z(0x80), Z(0x48), Z(0x81), Z(0xb7), Z(0x1d), Z(0x43), Z(0xd9), Z(0xd7), + Z(0x45), Z(0xf0), Z(0xd8), Z(0x8a), Z(0x59), Z(0x7c), Z(0x57), Z(0xc1), + Z(0x79), Z(0xc7), Z(0x34), Z(0xd6), Z(0x43), Z(0xdf), Z(0xe4), Z(0x78), + Z(0x16), Z(0x06), Z(0xda), Z(0x92), Z(0x76), Z(0x51), Z(0xe1), Z(0xd4), + Z(0x70), Z(0x03), Z(0xe0), Z(0x2f), Z(0x96), Z(0x91), Z(0x82), Z(0x80) +}; + +#undef Z +#define Z(x) __constant_be32_to_cpu(x << 11) +static const u32 sbox2[256] = { + Z(0xf0), Z(0x37), Z(0x24), Z(0x53), Z(0x2a), Z(0x03), Z(0x83), Z(0x86), + Z(0xd1), Z(0xec), Z(0x50), Z(0xf0), Z(0x42), Z(0x78), Z(0x2f), Z(0x6d), + Z(0xbf), Z(0x80), Z(0x87), Z(0x27), Z(0x95), Z(0xe2), Z(0xc5), Z(0x5d), + Z(0xf9), Z(0x6f), Z(0xdb), Z(0xb4), Z(0x65), Z(0x6e), Z(0xe7), Z(0x24), + Z(0xc8), Z(0x1a), Z(0xbb), Z(0x49), Z(0xb5), Z(0x0a), Z(0x7d), Z(0xb9), + Z(0xe8), Z(0xdc), Z(0xb7), Z(0xd9), Z(0x45), Z(0x20), Z(0x1b), Z(0xce), + Z(0x59), Z(0x9d), Z(0x6b), Z(0xbd), Z(0x0e), Z(0x8f), Z(0xa3), Z(0xa9), + Z(0xbc), Z(0x74), Z(0xa6), Z(0xf6), Z(0x7f), Z(0x5f), Z(0xb1), Z(0x68), + Z(0x84), Z(0xbc), Z(0xa9), Z(0xfd), Z(0x55), Z(0x50), Z(0xe9), Z(0xb6), + Z(0x13), Z(0x5e), Z(0x07), Z(0xb8), Z(0x95), Z(0x02), Z(0xc0), Z(0xd0), + Z(0x6a), Z(0x1a), Z(0x85), Z(0xbd), Z(0xb6), Z(0xfd), Z(0xfe), Z(0x17), + Z(0x3f), Z(0x09), Z(0xa3), Z(0x8d), Z(0xfb), Z(0xed), Z(0xda), Z(0x1d), + Z(0x6d), Z(0x1c), Z(0x6c), Z(0x01), Z(0x5a), Z(0xe5), Z(0x71), Z(0x3e), + Z(0x8b), Z(0x6b), Z(0xbe), Z(0x29), Z(0xeb), Z(0x12), Z(0x19), Z(0x34), + Z(0xcd), Z(0xb3), Z(0xbd), Z(0x35), Z(0xea), Z(0x4b), Z(0xd5), Z(0xae), + Z(0x2a), Z(0x79), Z(0x5a), Z(0xa5), Z(0x32), Z(0x12), Z(0x7b), Z(0xdc), + Z(0x2c), Z(0xd0), Z(0x22), Z(0x4b), Z(0xb1), Z(0x85), Z(0x59), Z(0x80), + Z(0xc0), Z(0x30), Z(0x9f), Z(0x73), Z(0xd3), Z(0x14), Z(0x48), Z(0x40), + Z(0x07), Z(0x2d), Z(0x8f), Z(0x80), Z(0x0f), Z(0xce), Z(0x0b), Z(0x5e), + Z(0xb7), Z(0x5e), Z(0xac), Z(0x24), Z(0x94), Z(0x4a), Z(0x18), Z(0x15), + Z(0x05), Z(0xe8), Z(0x02), Z(0x77), Z(0xa9), Z(0xc7), Z(0x40), Z(0x45), + Z(0x89), Z(0xd1), Z(0xea), Z(0xde), Z(0x0c), Z(0x79), Z(0x2a), Z(0x99), + Z(0x6c), Z(0x3e), Z(0x95), Z(0xdd), Z(0x8c), Z(0x7d), Z(0xad), Z(0x6f), + Z(0xdc), Z(0xff), Z(0xfd), Z(0x62), Z(0x47), Z(0xb3), Z(0x21), Z(0x8a), + Z(0xec), Z(0x8e), Z(0x19), Z(0x18), Z(0xb4), Z(0x6e), Z(0x3d), Z(0xfd), + Z(0x74), Z(0x54), Z(0x1e), Z(0x04), Z(0x85), Z(0xd8), Z(0xbc), Z(0x1f), + Z(0x56), Z(0xe7), Z(0x3a), Z(0x56), Z(0x67), Z(0xd6), Z(0xc8), Z(0xa5), + Z(0xf3), Z(0x8e), Z(0xde), Z(0xae), Z(0x37), Z(0x49), Z(0xb7), Z(0xfa), + Z(0xc8), Z(0xf4), Z(0x1f), Z(0xe0), Z(0x2a), Z(0x9b), Z(0x15), Z(0xd1), + Z(0x34), Z(0x0e), Z(0xb5), Z(0xe0), Z(0x44), Z(0x78), Z(0x84), Z(0x59), + Z(0x56), Z(0x68), Z(0x77), Z(0xa5), Z(0x14), Z(0x06), Z(0xf5), Z(0x2f), + Z(0x8c), Z(0x8a), Z(0x73), Z(0x80), Z(0x76), Z(0xb4), Z(0x10), Z(0x86) +}; + +#undef Z +#define Z(x) __constant_be32_to_cpu(x << 19) +static const u32 sbox3[256] = { + Z(0xa9), Z(0x2a), Z(0x48), Z(0x51), Z(0x84), Z(0x7e), Z(0x49), Z(0xe2), + Z(0xb5), Z(0xb7), Z(0x42), Z(0x33), Z(0x7d), Z(0x5d), Z(0xa6), Z(0x12), + Z(0x44), Z(0x48), Z(0x6d), Z(0x28), Z(0xaa), Z(0x20), Z(0x6d), Z(0x57), + Z(0xd6), Z(0x6b), Z(0x5d), Z(0x72), Z(0xf0), Z(0x92), Z(0x5a), Z(0x1b), + Z(0x53), Z(0x80), Z(0x24), Z(0x70), Z(0x9a), Z(0xcc), Z(0xa7), Z(0x66), + Z(0xa1), Z(0x01), Z(0xa5), Z(0x41), Z(0x97), Z(0x41), Z(0x31), Z(0x82), + Z(0xf1), Z(0x14), Z(0xcf), Z(0x53), Z(0x0d), Z(0xa0), Z(0x10), Z(0xcc), + Z(0x2a), Z(0x7d), Z(0xd2), Z(0xbf), Z(0x4b), Z(0x1a), Z(0xdb), Z(0x16), + Z(0x47), Z(0xf6), Z(0x51), Z(0x36), Z(0xed), Z(0xf3), Z(0xb9), Z(0x1a), + Z(0xa7), Z(0xdf), Z(0x29), Z(0x43), Z(0x01), Z(0x54), Z(0x70), Z(0xa4), + Z(0xbf), Z(0xd4), Z(0x0b), Z(0x53), Z(0x44), Z(0x60), Z(0x9e), Z(0x23), + Z(0xa1), Z(0x18), Z(0x68), Z(0x4f), Z(0xf0), Z(0x2f), Z(0x82), Z(0xc2), + Z(0x2a), Z(0x41), Z(0xb2), Z(0x42), Z(0x0c), Z(0xed), Z(0x0c), Z(0x1d), + Z(0x13), Z(0x3a), Z(0x3c), Z(0x6e), Z(0x35), Z(0xdc), Z(0x60), Z(0x65), + Z(0x85), Z(0xe9), Z(0x64), Z(0x02), Z(0x9a), Z(0x3f), Z(0x9f), Z(0x87), + Z(0x96), Z(0xdf), Z(0xbe), Z(0xf2), Z(0xcb), Z(0xe5), Z(0x6c), Z(0xd4), + Z(0x5a), Z(0x83), Z(0xbf), Z(0x92), Z(0x1b), Z(0x94), Z(0x00), Z(0x42), + Z(0xcf), Z(0x4b), Z(0x00), Z(0x75), Z(0xba), Z(0x8f), Z(0x76), Z(0x5f), + Z(0x5d), Z(0x3a), Z(0x4d), Z(0x09), Z(0x12), Z(0x08), Z(0x38), Z(0x95), + Z(0x17), Z(0xe4), Z(0x01), Z(0x1d), Z(0x4c), Z(0xa9), Z(0xcc), Z(0x85), + Z(0x82), Z(0x4c), Z(0x9d), Z(0x2f), Z(0x3b), Z(0x66), Z(0xa1), Z(0x34), + Z(0x10), Z(0xcd), Z(0x59), Z(0x89), Z(0xa5), Z(0x31), Z(0xcf), Z(0x05), + Z(0xc8), Z(0x84), Z(0xfa), Z(0xc7), Z(0xba), Z(0x4e), Z(0x8b), Z(0x1a), + Z(0x19), Z(0xf1), Z(0xa1), Z(0x3b), Z(0x18), Z(0x12), Z(0x17), Z(0xb0), + Z(0x98), Z(0x8d), Z(0x0b), Z(0x23), Z(0xc3), Z(0x3a), Z(0x2d), Z(0x20), + Z(0xdf), Z(0x13), Z(0xa0), Z(0xa8), Z(0x4c), Z(0x0d), Z(0x6c), Z(0x2f), + Z(0x47), Z(0x13), Z(0x13), Z(0x52), Z(0x1f), Z(0x2d), Z(0xf5), Z(0x79), + Z(0x3d), Z(0xa2), Z(0x54), Z(0xbd), Z(0x69), Z(0xc8), Z(0x6b), Z(0xf3), + Z(0x05), Z(0x28), Z(0xf1), Z(0x16), Z(0x46), Z(0x40), Z(0xb0), Z(0x11), + Z(0xd3), Z(0xb7), Z(0x95), Z(0x49), Z(0xcf), Z(0xc3), Z(0x1d), Z(0x8f), + Z(0xd8), Z(0xe1), Z(0x73), Z(0xdb), Z(0xad), Z(0xc8), Z(0xc9), Z(0xa9), + Z(0xa1), Z(0xc2), Z(0xc5), Z(0xe3), Z(0xba), Z(0xfc), Z(0x0e), Z(0x25) +}; + +/* + * This is a 16 round Feistel network with permutation F_ENCRYPT + */ +#define F_ENCRYPT(R, L, sched) \ +do { \ + union lc4 { u32 l; u8 c[4]; } u; \ + u.l = sched ^ R; \ + L ^= sbox0[u.c[0]] ^ sbox1[u.c[1]] ^ sbox2[u.c[2]] ^ sbox3[u.c[3]]; \ +} while(0) + +/* + * encryptor + */ +static void fcrypt_encrypt(struct crypto_tfm *tfm, u8 *dst, const u8 *src) +{ + const struct fcrypt_ctx *ctx = crypto_tfm_ctx(tfm); + struct { + u32 l, r; + } X; + + memcpy(&X, src, sizeof(X)); + + F_ENCRYPT(X.r, X.l, ctx->sched[0x0]); + F_ENCRYPT(X.l, X.r, ctx->sched[0x1]); + F_ENCRYPT(X.r, X.l, ctx->sched[0x2]); + F_ENCRYPT(X.l, X.r, ctx->sched[0x3]); + F_ENCRYPT(X.r, X.l, ctx->sched[0x4]); + F_ENCRYPT(X.l, X.r, ctx->sched[0x5]); + F_ENCRYPT(X.r, X.l, ctx->sched[0x6]); + F_ENCRYPT(X.l, X.r, ctx->sched[0x7]); + F_ENCRYPT(X.r, X.l, ctx->sched[0x8]); + F_ENCRYPT(X.l, X.r, ctx->sched[0x9]); + F_ENCRYPT(X.r, X.l, ctx->sched[0xa]); + F_ENCRYPT(X.l, X.r, ctx->sched[0xb]); + F_ENCRYPT(X.r, X.l, ctx->sched[0xc]); + F_ENCRYPT(X.l, X.r, ctx->sched[0xd]); + F_ENCRYPT(X.r, X.l, ctx->sched[0xe]); + F_ENCRYPT(X.l, X.r, ctx->sched[0xf]); + + memcpy(dst, &X, sizeof(X)); +} + +/* + * decryptor + */ +static void fcrypt_decrypt(struct crypto_tfm *tfm, u8 *dst, const u8 *src) +{ + const struct fcrypt_ctx *ctx = crypto_tfm_ctx(tfm); + struct { + u32 l, r; + } X; + + memcpy(&X, src, sizeof(X)); + + F_ENCRYPT(X.l, X.r, ctx->sched[0xf]); + F_ENCRYPT(X.r, X.l, ctx->sched[0xe]); + F_ENCRYPT(X.l, X.r, ctx->sched[0xd]); + F_ENCRYPT(X.r, X.l, ctx->sched[0xc]); + F_ENCRYPT(X.l, X.r, ctx->sched[0xb]); + F_ENCRYPT(X.r, X.l, ctx->sched[0xa]); + F_ENCRYPT(X.l, X.r, ctx->sched[0x9]); + F_ENCRYPT(X.r, X.l, ctx->sched[0x8]); + F_ENCRYPT(X.l, X.r, ctx->sched[0x7]); + F_ENCRYPT(X.r, X.l, ctx->sched[0x6]); + F_ENCRYPT(X.l, X.r, ctx->sched[0x5]); + F_ENCRYPT(X.r, X.l, ctx->sched[0x4]); + F_ENCRYPT(X.l, X.r, ctx->sched[0x3]); + F_ENCRYPT(X.r, X.l, ctx->sched[0x2]); + F_ENCRYPT(X.l, X.r, ctx->sched[0x1]); + F_ENCRYPT(X.r, X.l, ctx->sched[0x0]); + + memcpy(dst, &X, sizeof(X)); +} + +/* + * Generate a key schedule from key, the least significant bit in each key byte + * is parity and shall be ignored. This leaves 56 significant bits in the key + * to scatter over the 16 key schedules. For each schedule extract the low + * order 32 bits and use as schedule, then rotate right by 11 bits. + */ +static int fcrypt_setkey(struct crypto_tfm *tfm, const u8 *key, unsigned int keylen) +{ + struct fcrypt_ctx *ctx = crypto_tfm_ctx(tfm); + +#if BITS_PER_LONG == 64 /* the 64-bit version can also be used for 32-bit + * kernels - it seems to be faster but the code is + * larger */ + + u64 k; /* k holds all 56 non-parity bits */ + + /* discard the parity bits */ + k = (*key++) >> 1; + k <<= 7; + k |= (*key++) >> 1; + k <<= 7; + k |= (*key++) >> 1; + k <<= 7; + k |= (*key++) >> 1; + k <<= 7; + k |= (*key++) >> 1; + k <<= 7; + k |= (*key++) >> 1; + k <<= 7; + k |= (*key++) >> 1; + k <<= 7; + k |= (*key) >> 1; + + /* Use lower 32 bits for schedule, rotate by 11 each round (16 times) */ + ctx->sched[0x0] = be32_to_cpu(k); ror56_64(k, 11); + ctx->sched[0x1] = be32_to_cpu(k); ror56_64(k, 11); + ctx->sched[0x2] = be32_to_cpu(k); ror56_64(k, 11); + ctx->sched[0x3] = be32_to_cpu(k); ror56_64(k, 11); + ctx->sched[0x4] = be32_to_cpu(k); ror56_64(k, 11); + ctx->sched[0x5] = be32_to_cpu(k); ror56_64(k, 11); + ctx->sched[0x6] = be32_to_cpu(k); ror56_64(k, 11); + ctx->sched[0x7] = be32_to_cpu(k); ror56_64(k, 11); + ctx->sched[0x8] = be32_to_cpu(k); ror56_64(k, 11); + ctx->sched[0x9] = be32_to_cpu(k); ror56_64(k, 11); + ctx->sched[0xa] = be32_to_cpu(k); ror56_64(k, 11); + ctx->sched[0xb] = be32_to_cpu(k); ror56_64(k, 11); + ctx->sched[0xc] = be32_to_cpu(k); ror56_64(k, 11); + ctx->sched[0xd] = be32_to_cpu(k); ror56_64(k, 11); + ctx->sched[0xe] = be32_to_cpu(k); ror56_64(k, 11); + ctx->sched[0xf] = be32_to_cpu(k); + + return 0; +#else + u32 hi, lo; /* hi is upper 24 bits and lo lower 32, total 56 */ + + /* discard the parity bits */ + lo = (*key++) >> 1; + lo <<= 7; + lo |= (*key++) >> 1; + lo <<= 7; + lo |= (*key++) >> 1; + lo <<= 7; + lo |= (*key++) >> 1; + hi = lo >> 4; + lo &= 0xf; + lo <<= 7; + lo |= (*key++) >> 1; + lo <<= 7; + lo |= (*key++) >> 1; + lo <<= 7; + lo |= (*key++) >> 1; + lo <<= 7; + lo |= (*key) >> 1; + + /* Use lower 32 bits for schedule, rotate by 11 each round (16 times) */ + ctx->sched[0x0] = be32_to_cpu(lo); ror56(hi, lo, 11); + ctx->sched[0x1] = be32_to_cpu(lo); ror56(hi, lo, 11); + ctx->sched[0x2] = be32_to_cpu(lo); ror56(hi, lo, 11); + ctx->sched[0x3] = be32_to_cpu(lo); ror56(hi, lo, 11); + ctx->sched[0x4] = be32_to_cpu(lo); ror56(hi, lo, 11); + ctx->sched[0x5] = be32_to_cpu(lo); ror56(hi, lo, 11); + ctx->sched[0x6] = be32_to_cpu(lo); ror56(hi, lo, 11); + ctx->sched[0x7] = be32_to_cpu(lo); ror56(hi, lo, 11); + ctx->sched[0x8] = be32_to_cpu(lo); ror56(hi, lo, 11); + ctx->sched[0x9] = be32_to_cpu(lo); ror56(hi, lo, 11); + ctx->sched[0xa] = be32_to_cpu(lo); ror56(hi, lo, 11); + ctx->sched[0xb] = be32_to_cpu(lo); ror56(hi, lo, 11); + ctx->sched[0xc] = be32_to_cpu(lo); ror56(hi, lo, 11); + ctx->sched[0xd] = be32_to_cpu(lo); ror56(hi, lo, 11); + ctx->sched[0xe] = be32_to_cpu(lo); ror56(hi, lo, 11); + ctx->sched[0xf] = be32_to_cpu(lo); + return 0; +#endif +} + +static struct crypto_alg fcrypt_alg = { + .cra_name = "fcrypt", + .cra_flags = CRYPTO_ALG_TYPE_CIPHER, + .cra_blocksize = 8, + .cra_ctxsize = sizeof(struct fcrypt_ctx), + .cra_module = THIS_MODULE, + .cra_alignmask = 3, + .cra_list = LIST_HEAD_INIT(fcrypt_alg.cra_list), + .cra_u = { .cipher = { + .cia_min_keysize = 8, + .cia_max_keysize = 8, + .cia_setkey = fcrypt_setkey, + .cia_encrypt = fcrypt_encrypt, + .cia_decrypt = fcrypt_decrypt } } +}; + +static int __init init(void) +{ + return crypto_register_alg(&fcrypt_alg); +} + +static void __exit fini(void) +{ + crypto_unregister_alg(&fcrypt_alg); +} + +module_init(init); +module_exit(fini); + +MODULE_LICENSE("Dual BSD/GPL"); +MODULE_DESCRIPTION("FCrypt Cipher Algorithm"); +MODULE_AUTHOR("David Howells "); diff --git a/crypto/hash.c b/crypto/hash.c index cdec23d..12c4514 100644 --- a/crypto/hash.c +++ b/crypto/hash.c @@ -16,12 +16,13 @@ #include #include "internal.h" -static unsigned int crypto_hash_ctxsize(struct crypto_alg *alg) +static unsigned int crypto_hash_ctxsize(struct crypto_alg *alg, u32 type, + u32 mask) { return alg->cra_ctxsize; } -static int crypto_init_hash_ops(struct crypto_tfm *tfm) +static int crypto_init_hash_ops(struct crypto_tfm *tfm, u32 type, u32 mask) { struct hash_tfm *crt = &tfm->crt_hash; struct hash_alg *alg = &tfm->__crt_alg->cra_hash; diff --git a/crypto/hmac.c b/crypto/hmac.c index b521bcd..44187c5 100644 --- a/crypto/hmac.c +++ b/crypto/hmac.c @@ -172,15 +172,16 @@ static int hmac_digest(struct hash_desc static int hmac_init_tfm(struct crypto_tfm *tfm) { + struct crypto_hash *hash; struct crypto_instance *inst = (void *)tfm->__crt_alg; struct crypto_spawn *spawn = crypto_instance_ctx(inst); struct hmac_ctx *ctx = hmac_ctx(__crypto_hash_cast(tfm)); - tfm = crypto_spawn_tfm(spawn); - if (IS_ERR(tfm)) - return PTR_ERR(tfm); + hash = crypto_spawn_hash(spawn); + if (IS_ERR(hash)) + return PTR_ERR(hash); - ctx->child = crypto_hash_cast(tfm); + ctx->child = hash; return 0; } diff --git a/crypto/internal.h b/crypto/internal.h index 2da6ad4..60acad9 100644 --- a/crypto/internal.h +++ b/crypto/internal.h @@ -83,8 +83,7 @@ static inline void crypto_exit_proc(void { } #endif -static inline unsigned int crypto_digest_ctxsize(struct crypto_alg *alg, - int flags) +static inline unsigned int crypto_digest_ctxsize(struct crypto_alg *alg) { unsigned int len = alg->cra_ctxsize; @@ -96,23 +95,12 @@ static inline unsigned int crypto_digest return len; } -static inline unsigned int crypto_cipher_ctxsize(struct crypto_alg *alg, - int flags) +static inline unsigned int crypto_cipher_ctxsize(struct crypto_alg *alg) { - unsigned int len = alg->cra_ctxsize; - - switch (flags & CRYPTO_TFM_MODE_MASK) { - case CRYPTO_TFM_MODE_CBC: - len = ALIGN(len, (unsigned long)alg->cra_alignmask + 1); - len += alg->cra_blocksize; - break; - } - - return len; + return alg->cra_ctxsize; } -static inline unsigned int crypto_compress_ctxsize(struct crypto_alg *alg, - int flags) +static inline unsigned int crypto_compress_ctxsize(struct crypto_alg *alg) { return alg->cra_ctxsize; } @@ -121,10 +109,6 @@ struct crypto_alg *crypto_mod_get(struct struct crypto_alg *__crypto_alg_lookup(const char *name, u32 type, u32 mask); struct crypto_alg *crypto_alg_mod_lookup(const char *name, u32 type, u32 mask); -int crypto_init_digest_flags(struct crypto_tfm *tfm, u32 flags); -int crypto_init_cipher_flags(struct crypto_tfm *tfm, u32 flags); -int crypto_init_compress_flags(struct crypto_tfm *tfm, u32 flags); - int crypto_init_digest_ops(struct crypto_tfm *tfm); int crypto_init_cipher_ops(struct crypto_tfm *tfm); int crypto_init_compress_ops(struct crypto_tfm *tfm); @@ -136,7 +120,8 @@ void crypto_exit_compress_ops(struct cry void crypto_larval_error(const char *name, u32 type, u32 mask); void crypto_shoot_alg(struct crypto_alg *alg); -struct crypto_tfm *__crypto_alloc_tfm(struct crypto_alg *alg, u32 flags); +struct crypto_tfm *__crypto_alloc_tfm(struct crypto_alg *alg, u32 type, + u32 mask); int crypto_register_instance(struct crypto_template *tmpl, struct crypto_instance *inst); diff --git a/crypto/lrw.c b/crypto/lrw.c index 5664258..b410508 100644 --- a/crypto/lrw.c +++ b/crypto/lrw.c @@ -201,21 +201,22 @@ static int decrypt(struct blkcipher_desc static int init_tfm(struct crypto_tfm *tfm) { + struct crypto_cipher *cipher; struct crypto_instance *inst = (void *)tfm->__crt_alg; struct crypto_spawn *spawn = crypto_instance_ctx(inst); struct priv *ctx = crypto_tfm_ctx(tfm); u32 *flags = &tfm->crt_flags; - tfm = crypto_spawn_tfm(spawn); - if (IS_ERR(tfm)) - return PTR_ERR(tfm); + cipher = crypto_spawn_cipher(spawn); + if (IS_ERR(cipher)) + return PTR_ERR(cipher); - if (crypto_tfm_alg_blocksize(tfm) != 16) { + if (crypto_cipher_blocksize(cipher) != 16) { *flags |= CRYPTO_TFM_RES_BAD_BLOCK_LEN; return -EINVAL; } - ctx->child = crypto_cipher_cast(tfm); + ctx->child = cipher; return 0; } diff --git a/crypto/pcbc.c b/crypto/pcbc.c new file mode 100644 index 0000000..5174d7f --- /dev/null +++ b/crypto/pcbc.c @@ -0,0 +1,349 @@ +/* + * PCBC: Propagating Cipher Block Chaining mode + * + * Copyright (C) 2006 Red Hat, Inc. All Rights Reserved. + * Written by David Howells (dhowells@redhat.com) + * + * Derived from cbc.c + * - Copyright (c) 2006 Herbert Xu + * + * 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 + +struct crypto_pcbc_ctx { + struct crypto_cipher *child; + void (*xor)(u8 *dst, const u8 *src, unsigned int bs); +}; + +static int crypto_pcbc_setkey(struct crypto_tfm *parent, const u8 *key, + unsigned int keylen) +{ + struct crypto_pcbc_ctx *ctx = crypto_tfm_ctx(parent); + struct crypto_cipher *child = ctx->child; + int err; + + crypto_cipher_clear_flags(child, CRYPTO_TFM_REQ_MASK); + crypto_cipher_set_flags(child, crypto_tfm_get_flags(parent) & + CRYPTO_TFM_REQ_MASK); + err = crypto_cipher_setkey(child, key, keylen); + crypto_tfm_set_flags(parent, crypto_cipher_get_flags(child) & + CRYPTO_TFM_RES_MASK); + return err; +} + +static int crypto_pcbc_encrypt_segment(struct blkcipher_desc *desc, + struct blkcipher_walk *walk, + struct crypto_cipher *tfm, + void (*xor)(u8 *, const u8 *, + unsigned int)) +{ + void (*fn)(struct crypto_tfm *, u8 *, const u8 *) = + crypto_cipher_alg(tfm)->cia_encrypt; + int bsize = crypto_cipher_blocksize(tfm); + unsigned int nbytes = walk->nbytes; + u8 *src = walk->src.virt.addr; + u8 *dst = walk->dst.virt.addr; + u8 *iv = walk->iv; + + do { + xor(iv, src, bsize); + fn(crypto_cipher_tfm(tfm), dst, iv); + memcpy(iv, dst, bsize); + xor(iv, src, bsize); + + src += bsize; + dst += bsize; + } while ((nbytes -= bsize) >= bsize); + + return nbytes; +} + +static int crypto_pcbc_encrypt_inplace(struct blkcipher_desc *desc, + struct blkcipher_walk *walk, + struct crypto_cipher *tfm, + void (*xor)(u8 *, const u8 *, + unsigned int)) +{ + void (*fn)(struct crypto_tfm *, u8 *, const u8 *) = + crypto_cipher_alg(tfm)->cia_encrypt; + int bsize = crypto_cipher_blocksize(tfm); + unsigned int nbytes = walk->nbytes; + u8 *src = walk->src.virt.addr; + u8 *iv = walk->iv; + u8 tmpbuf[bsize]; + + do { + memcpy(tmpbuf, src, bsize); + xor(iv, tmpbuf, bsize); + fn(crypto_cipher_tfm(tfm), src, iv); + memcpy(iv, src, bsize); + xor(iv, tmpbuf, bsize); + + src += bsize; + } while ((nbytes -= bsize) >= bsize); + + memcpy(walk->iv, iv, bsize); + + return nbytes; +} + +static int crypto_pcbc_encrypt(struct blkcipher_desc *desc, + struct scatterlist *dst, struct scatterlist *src, + unsigned int nbytes) +{ + struct blkcipher_walk walk; + struct crypto_blkcipher *tfm = desc->tfm; + struct crypto_pcbc_ctx *ctx = crypto_blkcipher_ctx(tfm); + struct crypto_cipher *child = ctx->child; + void (*xor)(u8 *, const u8 *, unsigned int bs) = ctx->xor; + int err; + + blkcipher_walk_init(&walk, dst, src, nbytes); + err = blkcipher_walk_virt(desc, &walk); + + while ((nbytes = walk.nbytes)) { + if (walk.src.virt.addr == walk.dst.virt.addr) + nbytes = crypto_pcbc_encrypt_inplace(desc, &walk, child, + xor); + else + nbytes = crypto_pcbc_encrypt_segment(desc, &walk, child, + xor); + err = blkcipher_walk_done(desc, &walk, nbytes); + } + + return err; +} + +static int crypto_pcbc_decrypt_segment(struct blkcipher_desc *desc, + struct blkcipher_walk *walk, + struct crypto_cipher *tfm, + void (*xor)(u8 *, const u8 *, + unsigned int)) +{ + void (*fn)(struct crypto_tfm *, u8 *, const u8 *) = + crypto_cipher_alg(tfm)->cia_decrypt; + int bsize = crypto_cipher_blocksize(tfm); + unsigned int nbytes = walk->nbytes; + u8 *src = walk->src.virt.addr; + u8 *dst = walk->dst.virt.addr; + u8 *iv = walk->iv; + + do { + fn(crypto_cipher_tfm(tfm), dst, src); + xor(dst, iv, bsize); + memcpy(iv, src, bsize); + xor(iv, dst, bsize); + + src += bsize; + dst += bsize; + } while ((nbytes -= bsize) >= bsize); + + memcpy(walk->iv, iv, bsize); + + return nbytes; +} + +static int crypto_pcbc_decrypt_inplace(struct blkcipher_desc *desc, + struct blkcipher_walk *walk, + struct crypto_cipher *tfm, + void (*xor)(u8 *, const u8 *, + unsigned int)) +{ + void (*fn)(struct crypto_tfm *, u8 *, const u8 *) = + crypto_cipher_alg(tfm)->cia_decrypt; + int bsize = crypto_cipher_blocksize(tfm); + unsigned int nbytes = walk->nbytes; + u8 *src = walk->src.virt.addr; + u8 *iv = walk->iv; + u8 tmpbuf[bsize]; + + do { + memcpy(tmpbuf, src, bsize); + fn(crypto_cipher_tfm(tfm), src, src); + xor(src, iv, bsize); + memcpy(iv, tmpbuf, bsize); + xor(iv, src, bsize); + + src += bsize; + } while ((nbytes -= bsize) >= bsize); + + memcpy(walk->iv, iv, bsize); + + return nbytes; +} + +static int crypto_pcbc_decrypt(struct blkcipher_desc *desc, + struct scatterlist *dst, struct scatterlist *src, + unsigned int nbytes) +{ + struct blkcipher_walk walk; + struct crypto_blkcipher *tfm = desc->tfm; + struct crypto_pcbc_ctx *ctx = crypto_blkcipher_ctx(tfm); + struct crypto_cipher *child = ctx->child; + void (*xor)(u8 *, const u8 *, unsigned int bs) = ctx->xor; + int err; + + blkcipher_walk_init(&walk, dst, src, nbytes); + err = blkcipher_walk_virt(desc, &walk); + + while ((nbytes = walk.nbytes)) { + if (walk.src.virt.addr == walk.dst.virt.addr) + nbytes = crypto_pcbc_decrypt_inplace(desc, &walk, child, + xor); + else + nbytes = crypto_pcbc_decrypt_segment(desc, &walk, child, + xor); + err = blkcipher_walk_done(desc, &walk, nbytes); + } + + return err; +} + +static void xor_byte(u8 *a, const u8 *b, unsigned int bs) +{ + do { + *a++ ^= *b++; + } while (--bs); +} + +static void xor_quad(u8 *dst, const u8 *src, unsigned int bs) +{ + u32 *a = (u32 *)dst; + u32 *b = (u32 *)src; + + do { + *a++ ^= *b++; + } while ((bs -= 4)); +} + +static void xor_64(u8 *a, const u8 *b, unsigned int bs) +{ + ((u32 *)a)[0] ^= ((u32 *)b)[0]; + ((u32 *)a)[1] ^= ((u32 *)b)[1]; +} + +static void xor_128(u8 *a, const u8 *b, unsigned int bs) +{ + ((u32 *)a)[0] ^= ((u32 *)b)[0]; + ((u32 *)a)[1] ^= ((u32 *)b)[1]; + ((u32 *)a)[2] ^= ((u32 *)b)[2]; + ((u32 *)a)[3] ^= ((u32 *)b)[3]; +} + +static int crypto_pcbc_init_tfm(struct crypto_tfm *tfm) +{ + struct crypto_instance *inst = (void *)tfm->__crt_alg; + struct crypto_spawn *spawn = crypto_instance_ctx(inst); + struct crypto_pcbc_ctx *ctx = crypto_tfm_ctx(tfm); + struct crypto_cipher *cipher; + + switch (crypto_tfm_alg_blocksize(tfm)) { + case 8: + ctx->xor = xor_64; + break; + + case 16: + ctx->xor = xor_128; + break; + + default: + if (crypto_tfm_alg_blocksize(tfm) % 4) + ctx->xor = xor_byte; + else + ctx->xor = xor_quad; + } + + cipher = crypto_spawn_cipher(spawn); + if (IS_ERR(cipher)) + return PTR_ERR(cipher); + + ctx->child = cipher; + return 0; +} + +static void crypto_pcbc_exit_tfm(struct crypto_tfm *tfm) +{ + struct crypto_pcbc_ctx *ctx = crypto_tfm_ctx(tfm); + crypto_free_cipher(ctx->child); +} + +static struct crypto_instance *crypto_pcbc_alloc(void *param, unsigned int len) +{ + struct crypto_instance *inst; + struct crypto_alg *alg; + + alg = crypto_get_attr_alg(param, len, CRYPTO_ALG_TYPE_CIPHER, + CRYPTO_ALG_TYPE_MASK | CRYPTO_ALG_ASYNC); + if (IS_ERR(alg)) + return ERR_PTR(PTR_ERR(alg)); + + inst = crypto_alloc_instance("pcbc", alg); + if (IS_ERR(inst)) + goto out_put_alg; + + inst->alg.cra_flags = CRYPTO_ALG_TYPE_BLKCIPHER; + inst->alg.cra_priority = alg->cra_priority; + inst->alg.cra_blocksize = alg->cra_blocksize; + inst->alg.cra_alignmask = alg->cra_alignmask; + inst->alg.cra_type = &crypto_blkcipher_type; + + if (!(alg->cra_blocksize % 4)) + inst->alg.cra_alignmask |= 3; + inst->alg.cra_blkcipher.ivsize = alg->cra_blocksize; + inst->alg.cra_blkcipher.min_keysize = alg->cra_cipher.cia_min_keysize; + inst->alg.cra_blkcipher.max_keysize = alg->cra_cipher.cia_max_keysize; + + inst->alg.cra_ctxsize = sizeof(struct crypto_pcbc_ctx); + + inst->alg.cra_init = crypto_pcbc_init_tfm; + inst->alg.cra_exit = crypto_pcbc_exit_tfm; + + inst->alg.cra_blkcipher.setkey = crypto_pcbc_setkey; + inst->alg.cra_blkcipher.encrypt = crypto_pcbc_encrypt; + inst->alg.cra_blkcipher.decrypt = crypto_pcbc_decrypt; + +out_put_alg: + crypto_mod_put(alg); + return inst; +} + +static void crypto_pcbc_free(struct crypto_instance *inst) +{ + crypto_drop_spawn(crypto_instance_ctx(inst)); + kfree(inst); +} + +static struct crypto_template crypto_pcbc_tmpl = { + .name = "pcbc", + .alloc = crypto_pcbc_alloc, + .free = crypto_pcbc_free, + .module = THIS_MODULE, +}; + +static int __init crypto_pcbc_module_init(void) +{ + return crypto_register_template(&crypto_pcbc_tmpl); +} + +static void __exit crypto_pcbc_module_exit(void) +{ + crypto_unregister_template(&crypto_pcbc_tmpl); +} + +module_init(crypto_pcbc_module_init); +module_exit(crypto_pcbc_module_exit); + +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("PCBC block cipher algorithm"); diff --git a/crypto/proc.c b/crypto/proc.c index dabce06..102c751 100644 --- a/crypto/proc.c +++ b/crypto/proc.c @@ -101,7 +101,7 @@ static int crypto_info_open(struct inode return seq_open(file, &crypto_seq_ops); } -static struct file_operations proc_crypto_ops = { +static const struct file_operations proc_crypto_ops = { .open = crypto_info_open, .read = seq_read, .llseek = seq_lseek, diff --git a/crypto/tcrypt.c b/crypto/tcrypt.c index d671e89..f5e9da3 100644 --- a/crypto/tcrypt.c +++ b/crypto/tcrypt.c @@ -12,6 +12,7 @@ * Software Foundation; either version 2 of the License, or (at your option) * any later version. * + * 2006-12-07 Added SHA384 HMAC and SHA512 HMAC tests * 2004-08-09 Added cipher speed tests (Reyk Floeter ) * 2003-09-14 Rewritten by Kartikey Mahendra Bhatt * @@ -71,7 +72,8 @@ static char *check[] = { "des", "md5", "des3_ede", "rot13", "sha1", "sha256", "blowfish", "twofish", "serpent", "sha384", "sha512", "md4", "aes", "cast6", "arc4", "michael_mic", "deflate", "crc32c", "tea", "xtea", - "khazad", "wp512", "wp384", "wp256", "tnepres", "xeta", NULL + "khazad", "wp512", "wp384", "wp256", "tnepres", "xeta", "fcrypt", + "camellia", NULL }; static void hexdump(unsigned char *buf, unsigned int len) @@ -765,7 +767,7 @@ static void test_deflate(void) memcpy(tvmem, deflate_comp_tv_template, tsize); tv = (void *)tvmem; - tfm = crypto_alloc_tfm("deflate", 0); + tfm = crypto_alloc_comp("deflate", 0, CRYPTO_ALG_ASYNC); if (tfm == NULL) { printk("failed to load transform for deflate\n"); return; @@ -964,6 +966,26 @@ static void do_test(void) test_cipher("ecb(xeta)", DECRYPT, xeta_dec_tv_template, XETA_DEC_TEST_VECTORS); + //FCrypt + test_cipher("pcbc(fcrypt)", ENCRYPT, fcrypt_pcbc_enc_tv_template, + FCRYPT_ENC_TEST_VECTORS); + test_cipher("pcbc(fcrypt)", DECRYPT, fcrypt_pcbc_dec_tv_template, + FCRYPT_DEC_TEST_VECTORS); + + //CAMELLIA + test_cipher("ecb(camellia)", ENCRYPT, + camellia_enc_tv_template, + CAMELLIA_ENC_TEST_VECTORS); + test_cipher("ecb(camellia)", DECRYPT, + camellia_dec_tv_template, + CAMELLIA_DEC_TEST_VECTORS); + test_cipher("cbc(camellia)", ENCRYPT, + camellia_cbc_enc_tv_template, + CAMELLIA_CBC_ENC_TEST_VECTORS); + test_cipher("cbc(camellia)", DECRYPT, + camellia_cbc_dec_tv_template, + CAMELLIA_CBC_DEC_TEST_VECTORS); + test_hash("sha384", sha384_tv_template, SHA384_TEST_VECTORS); test_hash("sha512", sha512_tv_template, SHA512_TEST_VECTORS); test_hash("wp512", wp512_tv_template, WP512_TEST_VECTORS); @@ -980,6 +1002,10 @@ static void do_test(void) HMAC_SHA1_TEST_VECTORS); test_hash("hmac(sha256)", hmac_sha256_tv_template, HMAC_SHA256_TEST_VECTORS); + test_hash("hmac(sha384)", hmac_sha384_tv_template, + HMAC_SHA384_TEST_VECTORS); + test_hash("hmac(sha512)", hmac_sha512_tv_template, + HMAC_SHA512_TEST_VECTORS); test_hash("xcbc(aes)", aes_xcbc128_tv_template, XCBC_AES_TEST_VECTORS); @@ -1177,6 +1203,28 @@ static void do_test(void) XETA_DEC_TEST_VECTORS); break; + case 31: + test_cipher("pcbc(fcrypt)", ENCRYPT, fcrypt_pcbc_enc_tv_template, + FCRYPT_ENC_TEST_VECTORS); + test_cipher("pcbc(fcrypt)", DECRYPT, fcrypt_pcbc_dec_tv_template, + FCRYPT_DEC_TEST_VECTORS); + break; + + case 32: + test_cipher("ecb(camellia)", ENCRYPT, + camellia_enc_tv_template, + CAMELLIA_ENC_TEST_VECTORS); + test_cipher("ecb(camellia)", DECRYPT, + camellia_dec_tv_template, + CAMELLIA_DEC_TEST_VECTORS); + test_cipher("cbc(camellia)", ENCRYPT, + camellia_cbc_enc_tv_template, + CAMELLIA_CBC_ENC_TEST_VECTORS); + test_cipher("cbc(camellia)", DECRYPT, + camellia_cbc_dec_tv_template, + CAMELLIA_CBC_DEC_TEST_VECTORS); + break; + case 100: test_hash("hmac(md5)", hmac_md5_tv_template, HMAC_MD5_TEST_VECTORS); @@ -1192,6 +1240,16 @@ static void do_test(void) HMAC_SHA256_TEST_VECTORS); break; + case 103: + test_hash("hmac(sha384)", hmac_sha384_tv_template, + HMAC_SHA384_TEST_VECTORS); + break; + + case 104: + test_hash("hmac(sha512)", hmac_sha512_tv_template, + HMAC_SHA512_TEST_VECTORS); + break; + case 200: test_cipher_speed("ecb(aes)", ENCRYPT, sec, NULL, 0, @@ -1260,6 +1318,17 @@ static void do_test(void) des_speed_template); break; + case 205: + test_cipher_speed("ecb(camellia)", ENCRYPT, sec, NULL, 0, + camellia_speed_template); + test_cipher_speed("ecb(camellia)", DECRYPT, sec, NULL, 0, + camellia_speed_template); + test_cipher_speed("cbc(camellia)", ENCRYPT, sec, NULL, 0, + camellia_speed_template); + test_cipher_speed("cbc(camellia)", DECRYPT, sec, NULL, 0, + camellia_speed_template); + break; + case 300: /* fall through */ diff --git a/crypto/tcrypt.h b/crypto/tcrypt.h index 48a8136..887527b 100644 --- a/crypto/tcrypt.h +++ b/crypto/tcrypt.h @@ -12,6 +12,7 @@ * Software Foundation; either version 2 of the License, or (at your option) * any later version. * + * 2006-12-07 Added SHA384 HMAC and SHA512 HMAC tests * 2004-08-09 Cipher speed tests by Reyk Floeter * 2003-09-14 Changes by Kartikey Mahendra Bhatt * @@ -27,7 +28,7 @@ #define MAX_IVLEN 32 struct hash_testvec { /* only used with keyed hash algorithms */ - char key[128] __attribute__ ((__aligned__(4))); + char key[132] __attribute__ ((__aligned__(4))); char plaintext[240]; char digest[MAX_DIGEST_SIZE]; unsigned char tap[MAX_TAP]; @@ -1002,6 +1003,248 @@ static struct hash_testvec aes_xcbc128_t }; /* + * SHA384 HMAC test vectors from RFC4231 + */ + +#define HMAC_SHA384_TEST_VECTORS 4 + +static struct hash_testvec hmac_sha384_tv_template[] = { + { + .key = { 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, + 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, + 0x0b, 0x0b, 0x0b, 0x0b }, // (20 bytes) + .ksize = 20, + .plaintext = { 0x48, 0x69, 0x20, 0x54, 0x68, 0x65, 0x72, 0x65 }, // ("Hi There") + .psize = 8, + .digest = { 0xaf, 0xd0, 0x39, 0x44, 0xd8, 0x48, 0x95, 0x62, + 0x6b, 0x08, 0x25, 0xf4, 0xab, 0x46, 0x90, 0x7f, + 0x15, 0xf9, 0xda, 0xdb, 0xe4, 0x10, 0x1e, 0xc6, + 0x82, 0xaa, 0x03, 0x4c, 0x7c, 0xeb, 0xc5, 0x9c, + 0xfa, 0xea, 0x9e, 0xa9, 0x07, 0x6e, 0xde, 0x7f, + 0x4a, 0xf1, 0x52, 0xe8, 0xb2, 0xfa, 0x9c, 0xb6 }, + }, { + .key = { 0x4a, 0x65, 0x66, 0x65 }, // ("Jefe") + .ksize = 4, + .plaintext = { 0x77, 0x68, 0x61, 0x74, 0x20, 0x64, 0x6f, 0x20, + 0x79, 0x61, 0x20, 0x77, 0x61, 0x6e, 0x74, 0x20, // ("what do ya want ") + 0x66, 0x6f, 0x72, 0x20, 0x6e, 0x6f, 0x74, 0x68, + 0x69, 0x6e, 0x67, 0x3f }, // ("for nothing?") + .psize = 28, + .digest = { 0xaf, 0x45, 0xd2, 0xe3, 0x76, 0x48, 0x40, 0x31, + 0x61, 0x7f, 0x78, 0xd2, 0xb5, 0x8a, 0x6b, 0x1b, + 0x9c, 0x7e, 0xf4, 0x64, 0xf5, 0xa0, 0x1b, 0x47, + 0xe4, 0x2e, 0xc3, 0x73, 0x63, 0x22, 0x44, 0x5e, + 0x8e, 0x22, 0x40, 0xca, 0x5e, 0x69, 0xe2, 0xc7, + 0x8b, 0x32, 0x39, 0xec, 0xfa, 0xb2, 0x16, 0x49 }, + .np = 4, + .tap = { 7, 7, 7, 7 } + }, { + .key = { 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa }, // (131 bytes) + .ksize = 131, + .plaintext = { 0x54, 0x65, 0x73, 0x74, 0x20, 0x55, 0x73, 0x69, + 0x6e, 0x67, 0x20, 0x4c, 0x61, 0x72, 0x67, 0x65, // ("Test Using Large") + 0x72, 0x20, 0x54, 0x68, 0x61, 0x6e, 0x20, 0x42, + 0x6c, 0x6f, 0x63, 0x6b, 0x2d, 0x53, 0x69, 0x7a, // ("r Than Block-Siz") + 0x65, 0x20, 0x4b, 0x65, 0x79, 0x20, 0x2d, 0x20, + 0x48, 0x61, 0x73, 0x68, 0x20, 0x4b, 0x65, 0x79, // ("e Key - Hash Key") + 0x20, 0x46, 0x69, 0x72, 0x73, 0x74 }, // (" First") + .psize = 54, + .digest = { 0x4e, 0xce, 0x08, 0x44, 0x85, 0x81, 0x3e, 0x90, + 0x88, 0xd2, 0xc6, 0x3a, 0x04, 0x1b, 0xc5, 0xb4, + 0x4f, 0x9e, 0xf1, 0x01, 0x2a, 0x2b, 0x58, 0x8f, + 0x3c, 0xd1, 0x1f, 0x05, 0x03, 0x3a, 0xc4, 0xc6, + 0x0c, 0x2e, 0xf6, 0xab, 0x40, 0x30, 0xfe, 0x82, + 0x96, 0x24, 0x8d, 0xf1, 0x63, 0xf4, 0x49, 0x52 }, + }, { + .key = { 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa }, // (131 bytes) + .ksize = 131, + .plaintext = { 0x54, 0x68, 0x69, 0x73, 0x20, 0x69, 0x73, 0x20, + 0x61, 0x20, 0x74, 0x65, 0x73, 0x74, 0x20, 0x75, // ("This is a test u") + 0x73, 0x69, 0x6e, 0x67, 0x20, 0x61, 0x20, 0x6c, + 0x61, 0x72, 0x67, 0x65, 0x72, 0x20, 0x74, 0x68, // ("sing a larger th") + 0x61, 0x6e, 0x20, 0x62, 0x6c, 0x6f, 0x63, 0x6b, + 0x2d, 0x73, 0x69, 0x7a, 0x65, 0x20, 0x6b, 0x65, // ("an block-size ke") + 0x79, 0x20, 0x61, 0x6e, 0x64, 0x20, 0x61, 0x20, + 0x6c, 0x61, 0x72, 0x67, 0x65, 0x72, 0x20, 0x74, // ("y and a larger t") + 0x68, 0x61, 0x6e, 0x20, 0x62, 0x6c, 0x6f, 0x63, + 0x6b, 0x2d, 0x73, 0x69, 0x7a, 0x65, 0x20, 0x64, // ("han block-size d") + 0x61, 0x74, 0x61, 0x2e, 0x20, 0x54, 0x68, 0x65, + 0x20, 0x6b, 0x65, 0x79, 0x20, 0x6e, 0x65, 0x65, // ("ata. The key nee") + 0x64, 0x73, 0x20, 0x74, 0x6f, 0x20, 0x62, 0x65, + 0x20, 0x68, 0x61, 0x73, 0x68, 0x65, 0x64, 0x20, // ("ds to be hashed ") + 0x62, 0x65, 0x66, 0x6f, 0x72, 0x65, 0x20, 0x62, + 0x65, 0x69, 0x6e, 0x67, 0x20, 0x75, 0x73, 0x65, // ("before being use") + 0x64, 0x20, 0x62, 0x79, 0x20, 0x74, 0x68, 0x65, + 0x20, 0x48, 0x4d, 0x41, 0x43, 0x20, 0x61, 0x6c, // ("d by the HMAC al") + 0x67, 0x6f, 0x72, 0x69, 0x74, 0x68, 0x6d, 0x2e }, // ("gorithm.") + .psize = 152, + .digest = { 0x66, 0x17, 0x17, 0x8e, 0x94, 0x1f, 0x02, 0x0d, + 0x35, 0x1e, 0x2f, 0x25, 0x4e, 0x8f, 0xd3, 0x2c, + 0x60, 0x24, 0x20, 0xfe, 0xb0, 0xb8, 0xfb, 0x9a, + 0xdc, 0xce, 0xbb, 0x82, 0x46, 0x1e, 0x99, 0xc5, + 0xa6, 0x78, 0xcc, 0x31, 0xe7, 0x99, 0x17, 0x6d, + 0x38, 0x60, 0xe6, 0x11, 0x0c, 0x46, 0x52, 0x3e }, + }, +}; + +/* + * SHA512 HMAC test vectors from RFC4231 + */ + +#define HMAC_SHA512_TEST_VECTORS 4 + +static struct hash_testvec hmac_sha512_tv_template[] = { + { + .key = { 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, + 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, + 0x0b, 0x0b, 0x0b, 0x0b }, // (20 bytes) + .ksize = 20, + .plaintext = { 0x48, 0x69, 0x20, 0x54, 0x68, 0x65, 0x72, 0x65 }, // ("Hi There") + .psize = 8, + .digest = { 0x87, 0xaa, 0x7c, 0xde, 0xa5, 0xef, 0x61, 0x9d, + 0x4f, 0xf0, 0xb4, 0x24, 0x1a, 0x1d, 0x6c, 0xb0, + 0x23, 0x79, 0xf4, 0xe2, 0xce, 0x4e, 0xc2, 0x78, + 0x7a, 0xd0, 0xb3, 0x05, 0x45, 0xe1, 0x7c, 0xde, + 0xda, 0xa8, 0x33, 0xb7, 0xd6, 0xb8, 0xa7, 0x02, + 0x03, 0x8b, 0x27, 0x4e, 0xae, 0xa3, 0xf4, 0xe4, + 0xbe, 0x9d, 0x91, 0x4e, 0xeb, 0x61, 0xf1, 0x70, + 0x2e, 0x69, 0x6c, 0x20, 0x3a, 0x12, 0x68, 0x54 }, + }, { + .key = { 0x4a, 0x65, 0x66, 0x65 }, // ("Jefe") + .ksize = 4, + .plaintext = { 0x77, 0x68, 0x61, 0x74, 0x20, 0x64, 0x6f, 0x20, + 0x79, 0x61, 0x20, 0x77, 0x61, 0x6e, 0x74, 0x20, // ("what do ya want ") + 0x66, 0x6f, 0x72, 0x20, 0x6e, 0x6f, 0x74, 0x68, + 0x69, 0x6e, 0x67, 0x3f }, // ("for nothing?") + .psize = 28, + .digest = { 0x16, 0x4b, 0x7a, 0x7b, 0xfc, 0xf8, 0x19, 0xe2, + 0xe3, 0x95, 0xfb, 0xe7, 0x3b, 0x56, 0xe0, 0xa3, + 0x87, 0xbd, 0x64, 0x22, 0x2e, 0x83, 0x1f, 0xd6, + 0x10, 0x27, 0x0c, 0xd7, 0xea, 0x25, 0x05, 0x54, + 0x97, 0x58, 0xbf, 0x75, 0xc0, 0x5a, 0x99, 0x4a, + 0x6d, 0x03, 0x4f, 0x65, 0xf8, 0xf0, 0xe6, 0xfd, + 0xca, 0xea, 0xb1, 0xa3, 0x4d, 0x4a, 0x6b, 0x4b, + 0x63, 0x6e, 0x07, 0x0a, 0x38, 0xbc, 0xe7, 0x37 }, + .np = 4, + .tap = { 7, 7, 7, 7 } + }, { + .key = { 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa }, // (131 bytes) + .ksize = 131, + .plaintext = { 0x54, 0x65, 0x73, 0x74, 0x20, 0x55, 0x73, 0x69, + 0x6e, 0x67, 0x20, 0x4c, 0x61, 0x72, 0x67, 0x65, // ("Test Using Large") + 0x72, 0x20, 0x54, 0x68, 0x61, 0x6e, 0x20, 0x42, + 0x6c, 0x6f, 0x63, 0x6b, 0x2d, 0x53, 0x69, 0x7a, // ("r Than Block-Siz") + 0x65, 0x20, 0x4b, 0x65, 0x79, 0x20, 0x2d, 0x20, + 0x48, 0x61, 0x73, 0x68, 0x20, 0x4b, 0x65, 0x79, // ("e Key - Hash Key") + 0x20, 0x46, 0x69, 0x72, 0x73, 0x74 }, // (" First") + .psize = 54, + .digest = { 0x80, 0xb2, 0x42, 0x63, 0xc7, 0xc1, 0xa3, 0xeb, + 0xb7, 0x14, 0x93, 0xc1, 0xdd, 0x7b, 0xe8, 0xb4, + 0x9b, 0x46, 0xd1, 0xf4, 0x1b, 0x4a, 0xee, 0xc1, + 0x12, 0x1b, 0x01, 0x37, 0x83, 0xf8, 0xf3, 0x52, + 0x6b, 0x56, 0xd0, 0x37, 0xe0, 0x5f, 0x25, 0x98, + 0xbd, 0x0f, 0xd2, 0x21, 0x5d, 0x6a, 0x1e, 0x52, + 0x95, 0xe6, 0x4f, 0x73, 0xf6, 0x3f, 0x0a, 0xec, + 0x8b, 0x91, 0x5a, 0x98, 0x5d, 0x78, 0x65, 0x98 }, + }, { + .key = { 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa }, // (131 bytes) + .ksize = 131, + .plaintext = { 0x54, 0x68, 0x69, 0x73, 0x20, 0x69, 0x73, 0x20, + 0x61, 0x20, 0x74, 0x65, 0x73, 0x74, 0x20, 0x75, // ("This is a test u") + 0x73, 0x69, 0x6e, 0x67, 0x20, 0x61, 0x20, 0x6c, + 0x61, 0x72, 0x67, 0x65, 0x72, 0x20, 0x74, 0x68, // ("sing a larger th") + 0x61, 0x6e, 0x20, 0x62, 0x6c, 0x6f, 0x63, 0x6b, + 0x2d, 0x73, 0x69, 0x7a, 0x65, 0x20, 0x6b, 0x65, // ("an block-size ke") + 0x79, 0x20, 0x61, 0x6e, 0x64, 0x20, 0x61, 0x20, + 0x6c, 0x61, 0x72, 0x67, 0x65, 0x72, 0x20, 0x74, // ("y and a larger t") + 0x68, 0x61, 0x6e, 0x20, 0x62, 0x6c, 0x6f, 0x63, + 0x6b, 0x2d, 0x73, 0x69, 0x7a, 0x65, 0x20, 0x64, // ("han block-size d") + 0x61, 0x74, 0x61, 0x2e, 0x20, 0x54, 0x68, 0x65, + 0x20, 0x6b, 0x65, 0x79, 0x20, 0x6e, 0x65, 0x65, // ("ata. The key nee") + 0x64, 0x73, 0x20, 0x74, 0x6f, 0x20, 0x62, 0x65, + 0x20, 0x68, 0x61, 0x73, 0x68, 0x65, 0x64, 0x20, // ("ds to be hashed ") + 0x62, 0x65, 0x66, 0x6f, 0x72, 0x65, 0x20, 0x62, + 0x65, 0x69, 0x6e, 0x67, 0x20, 0x75, 0x73, 0x65, // ("before being use") + 0x64, 0x20, 0x62, 0x79, 0x20, 0x74, 0x68, 0x65, + 0x20, 0x48, 0x4d, 0x41, 0x43, 0x20, 0x61, 0x6c, // ("d by the HMAC al") + 0x67, 0x6f, 0x72, 0x69, 0x74, 0x68, 0x6d, 0x2e }, // ("gorithm.") + .psize = 152, + .digest = { 0xe3, 0x7b, 0x6a, 0x77, 0x5d, 0xc8, 0x7d, 0xba, + 0xa4, 0xdf, 0xa9, 0xf9, 0x6e, 0x5e, 0x3f, 0xfd, + 0xde, 0xbd, 0x71, 0xf8, 0x86, 0x72, 0x89, 0x86, + 0x5d, 0xf5, 0xa3, 0x2d, 0x20, 0xcd, 0xc9, 0x44, + 0xb6, 0x02, 0x2c, 0xac, 0x3c, 0x49, 0x82, 0xb1, + 0x0d, 0x5e, 0xeb, 0x55, 0xc3, 0xe4, 0xde, 0x15, + 0x13, 0x46, 0x76, 0xfb, 0x6d, 0xe0, 0x44, 0x60, + 0x65, 0xc9, 0x74, 0x40, 0xfa, 0x8c, 0x6a, 0x58 }, + }, +}; + +/* * DES test vectors. */ #define DES_ENC_TEST_VECTORS 10 @@ -3316,6 +3559,278 @@ static struct cipher_testvec xeta_dec_tv } }; +/* + * FCrypt test vectors + */ +#define FCRYPT_ENC_TEST_VECTORS ARRAY_SIZE(fcrypt_pcbc_enc_tv_template) +#define FCRYPT_DEC_TEST_VECTORS ARRAY_SIZE(fcrypt_pcbc_dec_tv_template) + +static struct cipher_testvec fcrypt_pcbc_enc_tv_template[] = { + { /* http://www.openafs.org/pipermail/openafs-devel/2000-December/005320.html */ + .key = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, + .klen = 8, + .iv = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, + .input = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, + .ilen = 8, + .result = { 0x0E, 0x09, 0x00, 0xC7, 0x3E, 0xF7, 0xED, 0x41 }, + .rlen = 8, + }, { + .key = { 0x11, 0x44, 0x77, 0xAA, 0xDD, 0x00, 0x33, 0x66 }, + .klen = 8, + .iv = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, + .input = { 0x12, 0x34, 0x56, 0x78, 0x9A, 0xBC, 0xDE, 0xF0 }, + .ilen = 8, + .result = { 0xD8, 0xED, 0x78, 0x74, 0x77, 0xEC, 0x06, 0x80 }, + .rlen = 8, + }, { /* From Arla */ + .key = { 0xf0, 0xe1, 0xd2, 0xc3, 0xb4, 0xa5, 0x96, 0x87 }, + .klen = 8, + .iv = { 0xfe, 0xdc, 0xba, 0x98, 0x76, 0x54, 0x32, 0x10 }, + .input = "The quick brown fox jumps over the lazy dogs.\0\0", + .ilen = 48, + .result = { 0x00, 0xf0, 0xe, 0x11, 0x75, 0xe6, 0x23, 0x82, + 0xee, 0xac, 0x98, 0x62, 0x44, 0x51, 0xe4, 0x84, + 0xc3, 0x59, 0xd8, 0xaa, 0x64, 0x60, 0xae, 0xf7, + 0xd2, 0xd9, 0x13, 0x79, 0x72, 0xa3, 0x45, 0x03, + 0x23, 0xb5, 0x62, 0xd7, 0x0c, 0xf5, 0x27, 0xd1, + 0xf8, 0x91, 0x3c, 0xac, 0x44, 0x22, 0x92, 0xef }, + .rlen = 48, + }, { + .key = { 0xfe, 0xdc, 0xba, 0x98, 0x76, 0x54, 0x32, 0x10 }, + .klen = 8, + .iv = { 0xf0, 0xe1, 0xd2, 0xc3, 0xb4, 0xa5, 0x96, 0x87 }, + .input = "The quick brown fox jumps over the lazy dogs.\0\0", + .ilen = 48, + .result = { 0xca, 0x90, 0xf5, 0x9d, 0xcb, 0xd4, 0xd2, 0x3c, + 0x01, 0x88, 0x7f, 0x3e, 0x31, 0x6e, 0x62, 0x9d, + 0xd8, 0xe0, 0x57, 0xa3, 0x06, 0x3a, 0x42, 0x58, + 0x2a, 0x28, 0xfe, 0x72, 0x52, 0x2f, 0xdd, 0xe0, + 0x19, 0x89, 0x09, 0x1c, 0x2a, 0x8e, 0x8c, 0x94, + 0xfc, 0xc7, 0x68, 0xe4, 0x88, 0xaa, 0xde, 0x0f }, + .rlen = 48, + }, { /* split-page version */ + .key = { 0xfe, 0xdc, 0xba, 0x98, 0x76, 0x54, 0x32, 0x10 }, + .klen = 8, + .iv = { 0xf0, 0xe1, 0xd2, 0xc3, 0xb4, 0xa5, 0x96, 0x87 }, + .input = "The quick brown fox jumps over the lazy dogs.\0\0", + .ilen = 48, + .result = { 0xca, 0x90, 0xf5, 0x9d, 0xcb, 0xd4, 0xd2, 0x3c, + 0x01, 0x88, 0x7f, 0x3e, 0x31, 0x6e, 0x62, 0x9d, + 0xd8, 0xe0, 0x57, 0xa3, 0x06, 0x3a, 0x42, 0x58, + 0x2a, 0x28, 0xfe, 0x72, 0x52, 0x2f, 0xdd, 0xe0, + 0x19, 0x89, 0x09, 0x1c, 0x2a, 0x8e, 0x8c, 0x94, + 0xfc, 0xc7, 0x68, 0xe4, 0x88, 0xaa, 0xde, 0x0f }, + .rlen = 48, + .np = 2, + .tap = { 20, 28 }, + } +}; + +static struct cipher_testvec fcrypt_pcbc_dec_tv_template[] = { + { /* http://www.openafs.org/pipermail/openafs-devel/2000-December/005320.html */ + .key = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, + .klen = 8, + .iv = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, + .input = { 0x0E, 0x09, 0x00, 0xC7, 0x3E, 0xF7, 0xED, 0x41 }, + .ilen = 8, + .result = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, + .rlen = 8, + }, { + .key = { 0x11, 0x44, 0x77, 0xAA, 0xDD, 0x00, 0x33, 0x66 }, + .klen = 8, + .iv = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, + .input = { 0xD8, 0xED, 0x78, 0x74, 0x77, 0xEC, 0x06, 0x80 }, + .ilen = 8, + .result = { 0x12, 0x34, 0x56, 0x78, 0x9A, 0xBC, 0xDE, 0xF0 }, + .rlen = 8, + }, { /* From Arla */ + .key = { 0xf0, 0xe1, 0xd2, 0xc3, 0xb4, 0xa5, 0x96, 0x87 }, + .klen = 8, + .iv = { 0xfe, 0xdc, 0xba, 0x98, 0x76, 0x54, 0x32, 0x10 }, + .input = { 0x00, 0xf0, 0xe, 0x11, 0x75, 0xe6, 0x23, 0x82, + 0xee, 0xac, 0x98, 0x62, 0x44, 0x51, 0xe4, 0x84, + 0xc3, 0x59, 0xd8, 0xaa, 0x64, 0x60, 0xae, 0xf7, + 0xd2, 0xd9, 0x13, 0x79, 0x72, 0xa3, 0x45, 0x03, + 0x23, 0xb5, 0x62, 0xd7, 0x0c, 0xf5, 0x27, 0xd1, + 0xf8, 0x91, 0x3c, 0xac, 0x44, 0x22, 0x92, 0xef }, + .ilen = 48, + .result = "The quick brown fox jumps over the lazy dogs.\0\0", + .rlen = 48, + }, { + .key = { 0xfe, 0xdc, 0xba, 0x98, 0x76, 0x54, 0x32, 0x10 }, + .klen = 8, + .iv = { 0xf0, 0xe1, 0xd2, 0xc3, 0xb4, 0xa5, 0x96, 0x87 }, + .input = { 0xca, 0x90, 0xf5, 0x9d, 0xcb, 0xd4, 0xd2, 0x3c, + 0x01, 0x88, 0x7f, 0x3e, 0x31, 0x6e, 0x62, 0x9d, + 0xd8, 0xe0, 0x57, 0xa3, 0x06, 0x3a, 0x42, 0x58, + 0x2a, 0x28, 0xfe, 0x72, 0x52, 0x2f, 0xdd, 0xe0, + 0x19, 0x89, 0x09, 0x1c, 0x2a, 0x8e, 0x8c, 0x94, + 0xfc, 0xc7, 0x68, 0xe4, 0x88, 0xaa, 0xde, 0x0f }, + .ilen = 48, + .result = "The quick brown fox jumps over the lazy dogs.\0\0", + .rlen = 48, + }, { /* split-page version */ + .key = { 0xfe, 0xdc, 0xba, 0x98, 0x76, 0x54, 0x32, 0x10 }, + .klen = 8, + .iv = { 0xf0, 0xe1, 0xd2, 0xc3, 0xb4, 0xa5, 0x96, 0x87 }, + .input = { 0xca, 0x90, 0xf5, 0x9d, 0xcb, 0xd4, 0xd2, 0x3c, + 0x01, 0x88, 0x7f, 0x3e, 0x31, 0x6e, 0x62, 0x9d, + 0xd8, 0xe0, 0x57, 0xa3, 0x06, 0x3a, 0x42, 0x58, + 0x2a, 0x28, 0xfe, 0x72, 0x52, 0x2f, 0xdd, 0xe0, + 0x19, 0x89, 0x09, 0x1c, 0x2a, 0x8e, 0x8c, 0x94, + 0xfc, 0xc7, 0x68, 0xe4, 0x88, 0xaa, 0xde, 0x0f }, + .ilen = 48, + .result = "The quick brown fox jumps over the lazy dogs.\0\0", + .rlen = 48, + .np = 2, + .tap = { 20, 28 }, + } +}; + +/* + * CAMELLIA test vectors. + */ +#define CAMELLIA_ENC_TEST_VECTORS 3 +#define CAMELLIA_DEC_TEST_VECTORS 3 +#define CAMELLIA_CBC_ENC_TEST_VECTORS 2 +#define CAMELLIA_CBC_DEC_TEST_VECTORS 2 + +static struct cipher_testvec camellia_enc_tv_template[] = { + { + .key = { 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef, + 0xfe, 0xdc, 0xba, 0x98, 0x76, 0x54, 0x32, 0x10 }, + .klen = 16, + .input = { 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef, + 0xfe, 0xdc, 0xba, 0x98, 0x76, 0x54, 0x32, 0x10 }, + .ilen = 16, + .result = { 0x67, 0x67, 0x31, 0x38, 0x54, 0x96, 0x69, 0x73, + 0x08, 0x57, 0x06, 0x56, 0x48, 0xea, 0xbe, 0x43 }, + .rlen = 16, + }, { + .key = { 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef, + 0xfe, 0xdc, 0xba, 0x98, 0x76, 0x54, 0x32, 0x10, + 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77 }, + .klen = 24, + .input = { 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef, + 0xfe, 0xdc, 0xba, 0x98, 0x76, 0x54, 0x32, 0x10 }, + .ilen = 16, + .result = { 0xb4, 0x99, 0x34, 0x01, 0xb3, 0xe9, 0x96, 0xf8, + 0x4e, 0xe5, 0xce, 0xe7, 0xd7, 0x9b, 0x09, 0xb9 }, + .rlen = 16, + }, { + .key = { 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef, + 0xfe, 0xdc, 0xba, 0x98, 0x76, 0x54, 0x32, 0x10, + 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, + 0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff }, + .klen = 32, + .input = { 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef, + 0xfe, 0xdc, 0xba, 0x98, 0x76, 0x54, 0x32, 0x10 }, + .ilen = 16, + .result = { 0x9a, 0xcc, 0x23, 0x7d, 0xff, 0x16, 0xd7, 0x6c, + 0x20, 0xef, 0x7c, 0x91, 0x9e, 0x3a, 0x75, 0x09 }, + .rlen = 16, + }, +}; + +static struct cipher_testvec camellia_dec_tv_template[] = { + { + .key = { 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef, + 0xfe, 0xdc, 0xba, 0x98, 0x76, 0x54, 0x32, 0x10 }, + .klen = 16, + .input = { 0x67, 0x67, 0x31, 0x38, 0x54, 0x96, 0x69, 0x73, + 0x08, 0x57, 0x06, 0x56, 0x48, 0xea, 0xbe, 0x43 }, + .ilen = 16, + .result = { 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef, + 0xfe, 0xdc, 0xba, 0x98, 0x76, 0x54, 0x32, 0x10 }, + .rlen = 16, + }, { + .key = { 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef, + 0xfe, 0xdc, 0xba, 0x98, 0x76, 0x54, 0x32, 0x10, + 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77 }, + .klen = 24, + .input = { 0xb4, 0x99, 0x34, 0x01, 0xb3, 0xe9, 0x96, 0xf8, + 0x4e, 0xe5, 0xce, 0xe7, 0xd7, 0x9b, 0x09, 0xb9 }, + .ilen = 16, + .result = { 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef, + 0xfe, 0xdc, 0xba, 0x98, 0x76, 0x54, 0x32, 0x10 }, + .rlen = 16, + }, { + .key = { 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef, + 0xfe, 0xdc, 0xba, 0x98, 0x76, 0x54, 0x32, 0x10, + 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, + 0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff }, + .klen = 32, + .input = { 0x9a, 0xcc, 0x23, 0x7d, 0xff, 0x16, 0xd7, 0x6c, + 0x20, 0xef, 0x7c, 0x91, 0x9e, 0x3a, 0x75, 0x09 }, + .ilen = 16, + .result = { 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef, + 0xfe, 0xdc, 0xba, 0x98, 0x76, 0x54, 0x32, 0x10 }, + .rlen = 16, + }, +}; + +static struct cipher_testvec camellia_cbc_enc_tv_template[] = { + { + .key = { 0x06, 0xa9, 0x21, 0x40, 0x36, 0xb8, 0xa1, 0x5b, + 0x51, 0x2e, 0x03, 0xd5, 0x34, 0x12, 0x00, 0x06 }, + .klen = 16, + .iv = { 0x3d, 0xaf, 0xba, 0x42, 0x9d, 0x9e, 0xb4, 0x30, + 0xb4, 0x22, 0xda, 0x80, 0x2c, 0x9f, 0xac, 0x41 }, + .input = { "Single block msg" }, + .ilen = 16, + .result = { 0xea, 0x32, 0x12, 0x76, 0x3b, 0x50, 0x10, 0xe7, + 0x18, 0xf6, 0xfd, 0x5d, 0xf6, 0x8f, 0x13, 0x51 }, + .rlen = 16, + }, { + .key = { 0xc2, 0x86, 0x69, 0x6d, 0x88, 0x7c, 0x9a, 0xa0, + 0x61, 0x1b, 0xbb, 0x3e, 0x20, 0x25, 0xa4, 0x5a }, + .klen = 16, + .iv = { 0x56, 0x2e, 0x17, 0x99, 0x6d, 0x09, 0x3d, 0x28, + 0xdd, 0xb3, 0xba, 0x69, 0x5a, 0x2e, 0x6f, 0x58 }, + .input = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, + 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f }, + .ilen = 32, + .result = { 0xa5, 0xdf, 0x6e, 0x50, 0xda, 0x70, 0x6c, 0x01, + 0x4a, 0xab, 0xf3, 0xf2, 0xd6, 0xfc, 0x6c, 0xfd, + 0x19, 0xb4, 0x3e, 0x57, 0x1c, 0x02, 0x5e, 0xa0, + 0x15, 0x78, 0xe0, 0x5e, 0xf2, 0xcb, 0x87, 0x16 }, + .rlen = 32, + }, +}; + +static struct cipher_testvec camellia_cbc_dec_tv_template[] = { + { + .key = { 0x06, 0xa9, 0x21, 0x40, 0x36, 0xb8, 0xa1, 0x5b, + 0x51, 0x2e, 0x03, 0xd5, 0x34, 0x12, 0x00, 0x06 }, + .klen = 16, + .iv = { 0x3d, 0xaf, 0xba, 0x42, 0x9d, 0x9e, 0xb4, 0x30, + 0xb4, 0x22, 0xda, 0x80, 0x2c, 0x9f, 0xac, 0x41 }, + .input = { 0xea, 0x32, 0x12, 0x76, 0x3b, 0x50, 0x10, 0xe7, + 0x18, 0xf6, 0xfd, 0x5d, 0xf6, 0x8f, 0x13, 0x51 }, + .ilen = 16, + .result = { "Single block msg" }, + .rlen = 16, + }, { + .key = { 0xc2, 0x86, 0x69, 0x6d, 0x88, 0x7c, 0x9a, 0xa0, + 0x61, 0x1b, 0xbb, 0x3e, 0x20, 0x25, 0xa4, 0x5a }, + .klen = 16, + .iv = { 0x56, 0x2e, 0x17, 0x99, 0x6d, 0x09, 0x3d, 0x28, + 0xdd, 0xb3, 0xba, 0x69, 0x5a, 0x2e, 0x6f, 0x58 }, + .input = { 0xa5, 0xdf, 0x6e, 0x50, 0xda, 0x70, 0x6c, 0x01, + 0x4a, 0xab, 0xf3, 0xf2, 0xd6, 0xfc, 0x6c, 0xfd, + 0x19, 0xb4, 0x3e, 0x57, 0x1c, 0x02, 0x5e, 0xa0, + 0x15, 0x78, 0xe0, 0x5e, 0xf2, 0xcb, 0x87, 0x16 }, + .ilen = 32, + .result = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, + 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f }, + .rlen = 32, + }, +}; + /* * Compression stuff. */ @@ -3769,4 +4284,25 @@ static struct hash_speed generic_hash_sp { .blen = 0, .plen = 0, } }; +static struct cipher_speed camellia_speed_template[] = { + { .klen = 16, .blen = 16, }, + { .klen = 16, .blen = 64, }, + { .klen = 16, .blen = 256, }, + { .klen = 16, .blen = 1024, }, + { .klen = 16, .blen = 8192, }, + { .klen = 24, .blen = 16, }, + { .klen = 24, .blen = 64, }, + { .klen = 24, .blen = 256, }, + { .klen = 24, .blen = 1024, }, + { .klen = 24, .blen = 8192, }, + { .klen = 32, .blen = 16, }, + { .klen = 32, .blen = 64, }, + { .klen = 32, .blen = 256, }, + { .klen = 32, .blen = 1024, }, + { .klen = 32, .blen = 8192, }, + + /* End marker */ + { .klen = 0, .blen = 0, } +}; + #endif /* _CRYPTO_TCRYPT_H */ diff --git a/crypto/xcbc.c b/crypto/xcbc.c index 9347eb6..53e8ccb 100644 --- a/crypto/xcbc.c +++ b/crypto/xcbc.c @@ -21,6 +21,7 @@ #include #include +#include #include #include #include @@ -47,7 +48,7 @@ static u_int32_t ks[12] = {0x01010101, 0 * +------------------------ */ struct crypto_xcbc_ctx { - struct crypto_tfm *child; + struct crypto_cipher *child; u8 *odds; u8 *prev; u8 *key; @@ -75,8 +76,7 @@ static int _crypto_xcbc_digest_setkey(st if ((err = crypto_cipher_setkey(ctx->child, ctx->key, ctx->keylen))) return err; - ctx->child->__crt_alg->cra_cipher.cia_encrypt(ctx->child, key1, - ctx->consts); + crypto_cipher_encrypt_one(ctx->child, key1, ctx->consts); return crypto_cipher_setkey(ctx->child, key1, bs); } @@ -86,7 +86,7 @@ static int crypto_xcbc_digest_setkey(str { struct crypto_xcbc_ctx *ctx = crypto_hash_ctx_aligned(parent); - if (keylen != crypto_tfm_alg_blocksize(ctx->child)) + if (keylen != crypto_cipher_blocksize(ctx->child)) return -EINVAL; ctx->keylen = keylen; @@ -108,13 +108,13 @@ static int crypto_xcbc_digest_init(struc return 0; } -static int crypto_xcbc_digest_update(struct hash_desc *pdesc, - struct scatterlist *sg, - unsigned int nbytes) +static int crypto_xcbc_digest_update2(struct hash_desc *pdesc, + struct scatterlist *sg, + unsigned int nbytes) { struct crypto_hash *parent = pdesc->tfm; struct crypto_xcbc_ctx *ctx = crypto_hash_ctx_aligned(parent); - struct crypto_tfm *tfm = ctx->child; + struct crypto_cipher *tfm = ctx->child; int bs = crypto_hash_blocksize(parent); unsigned int i = 0; @@ -142,7 +142,7 @@ static int crypto_xcbc_digest_update(str offset += len; crypto_kunmap(p, 0); - crypto_yield(tfm->crt_flags); + crypto_yield(pdesc->flags); continue; } @@ -152,7 +152,7 @@ static int crypto_xcbc_digest_update(str p += bs - ctx->len; ctx->xor(ctx->prev, ctx->odds, bs); - tfm->__crt_alg->cra_cipher.cia_encrypt(tfm, ctx->prev, ctx->prev); + crypto_cipher_encrypt_one(tfm, ctx->prev, ctx->prev); /* clearing the length */ ctx->len = 0; @@ -160,7 +160,8 @@ static int crypto_xcbc_digest_update(str /* encrypting the rest of data */ while (len > bs) { ctx->xor(ctx->prev, p, bs); - tfm->__crt_alg->cra_cipher.cia_encrypt(tfm, ctx->prev, ctx->prev); + crypto_cipher_encrypt_one(tfm, ctx->prev, + ctx->prev); p += bs; len -= bs; } @@ -171,7 +172,7 @@ static int crypto_xcbc_digest_update(str ctx->len = len; } crypto_kunmap(p, 0); - crypto_yield(tfm->crt_flags); + crypto_yield(pdesc->flags); slen -= min(slen, ((unsigned int)(PAGE_SIZE)) - offset); offset = 0; pg++; @@ -183,11 +184,20 @@ static int crypto_xcbc_digest_update(str return 0; } +static int crypto_xcbc_digest_update(struct hash_desc *pdesc, + struct scatterlist *sg, + unsigned int nbytes) +{ + if (WARN_ON_ONCE(in_irq())) + return -EDEADLK; + return crypto_xcbc_digest_update2(pdesc, sg, nbytes); +} + static int crypto_xcbc_digest_final(struct hash_desc *pdesc, u8 *out) { struct crypto_hash *parent = pdesc->tfm; struct crypto_xcbc_ctx *ctx = crypto_hash_ctx_aligned(parent); - struct crypto_tfm *tfm = ctx->child; + struct crypto_cipher *tfm = ctx->child; int bs = crypto_hash_blocksize(parent); int err = 0; @@ -197,13 +207,14 @@ static int crypto_xcbc_digest_final(stru if ((err = crypto_cipher_setkey(tfm, ctx->key, ctx->keylen)) != 0) return err; - tfm->__crt_alg->cra_cipher.cia_encrypt(tfm, key2, (const u8*)(ctx->consts+bs)); + crypto_cipher_encrypt_one(tfm, key2, + (u8 *)(ctx->consts + bs)); ctx->xor(ctx->prev, ctx->odds, bs); ctx->xor(ctx->prev, key2, bs); _crypto_xcbc_digest_setkey(parent, ctx); - tfm->__crt_alg->cra_cipher.cia_encrypt(tfm, out, ctx->prev); + crypto_cipher_encrypt_one(tfm, out, ctx->prev); } else { u8 key3[bs]; unsigned int rlen; @@ -218,14 +229,15 @@ static int crypto_xcbc_digest_final(stru if ((err = crypto_cipher_setkey(tfm, ctx->key, ctx->keylen)) != 0) return err; - tfm->__crt_alg->cra_cipher.cia_encrypt(tfm, key3, (const u8*)(ctx->consts+bs*2)); + crypto_cipher_encrypt_one(tfm, key3, + (u8 *)(ctx->consts + bs * 2)); ctx->xor(ctx->prev, ctx->odds, bs); ctx->xor(ctx->prev, key3, bs); _crypto_xcbc_digest_setkey(parent, ctx); - tfm->__crt_alg->cra_cipher.cia_encrypt(tfm, out, ctx->prev); + crypto_cipher_encrypt_one(tfm, out, ctx->prev); } return 0; @@ -234,21 +246,25 @@ static int crypto_xcbc_digest_final(stru static int crypto_xcbc_digest(struct hash_desc *pdesc, struct scatterlist *sg, unsigned int nbytes, u8 *out) { + if (WARN_ON_ONCE(in_irq())) + return -EDEADLK; + crypto_xcbc_digest_init(pdesc); - crypto_xcbc_digest_update(pdesc, sg, nbytes); + crypto_xcbc_digest_update2(pdesc, sg, nbytes); return crypto_xcbc_digest_final(pdesc, out); } static int xcbc_init_tfm(struct crypto_tfm *tfm) { + struct crypto_cipher *cipher; struct crypto_instance *inst = (void *)tfm->__crt_alg; struct crypto_spawn *spawn = crypto_instance_ctx(inst); struct crypto_xcbc_ctx *ctx = crypto_hash_ctx_aligned(__crypto_hash_cast(tfm)); int bs = crypto_hash_blocksize(__crypto_hash_cast(tfm)); - tfm = crypto_spawn_tfm(spawn); - if (IS_ERR(tfm)) - return PTR_ERR(tfm); + cipher = crypto_spawn_cipher(spawn); + if (IS_ERR(cipher)) + return PTR_ERR(cipher); switch(bs) { case 16: @@ -258,7 +274,7 @@ static int xcbc_init_tfm(struct crypto_t return -EINVAL; } - ctx->child = crypto_cipher_cast(tfm); + ctx->child = cipher; ctx->odds = (u8*)(ctx+1); ctx->prev = ctx->odds + bs; ctx->key = ctx->prev + bs; diff --git a/drivers/Kconfig b/drivers/Kconfig index e7da9fa..050323f 100644 --- a/drivers/Kconfig +++ b/drivers/Kconfig @@ -80,6 +80,8 @@ source "drivers/rtc/Kconfig" source "drivers/dma/Kconfig" +source "drivers/auxdisplay/Kconfig" + source "drivers/kvm/Kconfig" endmenu diff --git a/drivers/Makefile b/drivers/Makefile index 0dd96d1..3a718f5 100644 --- a/drivers/Makefile +++ b/drivers/Makefile @@ -30,7 +30,7 @@ obj-$(CONFIG_PARPORT) += parport/ obj-y += base/ block/ misc/ mfd/ net/ media/ obj-$(CONFIG_NUBUS) += nubus/ obj-$(CONFIG_ATM) += atm/ -obj-$(CONFIG_PPC_PMAC) += macintosh/ +obj-y += macintosh/ obj-$(CONFIG_IDE) += ide/ obj-$(CONFIG_FC4) += fc4/ obj-$(CONFIG_SCSI) += scsi/ @@ -38,6 +38,7 @@ obj-$(CONFIG_ATA) += ata/ obj-$(CONFIG_FUSION) += message/ obj-$(CONFIG_IEEE1394) += ieee1394/ obj-y += cdrom/ +obj-y += auxdisplay/ obj-$(CONFIG_MTD) += mtd/ obj-$(CONFIG_SPI) += spi/ obj-$(CONFIG_PCCARD) += pcmcia/ diff --git a/drivers/acorn/block/mfmhd.c b/drivers/acorn/block/mfmhd.c index 7fde8f4..689a4c3 100644 --- a/drivers/acorn/block/mfmhd.c +++ b/drivers/acorn/block/mfmhd.c @@ -99,7 +99,6 @@ */ #include -#include #include #include #include diff --git a/drivers/acorn/char/i2c.c b/drivers/acorn/char/i2c.c index 9e584a7..d276fd1 100644 --- a/drivers/acorn/char/i2c.c +++ b/drivers/acorn/char/i2c.c @@ -14,7 +14,6 @@ */ #include #include -#include #include #include #include @@ -238,7 +237,7 @@ static int rtc_ioctl(struct inode *inode return -EINVAL; } -static struct file_operations rtc_fops = { +static const struct file_operations rtc_fops = { .ioctl = rtc_ioctl, }; diff --git a/drivers/acpi/Kconfig b/drivers/acpi/Kconfig index f4f000a..20eacc2 100644 --- a/drivers/acpi/Kconfig +++ b/drivers/acpi/Kconfig @@ -3,6 +3,7 @@ # ACPI Configuration # menu "ACPI (Advanced Configuration and Power Interface) Support" + depends on !X86_NUMAQ depends on !X86_VISWS depends on !IA64_HP_SIM depends on IA64 || X86 @@ -77,6 +78,20 @@ config ACPI_SLEEP_PROC_SLEEP Create /proc/acpi/sleep Deprecated by /sys/power/state +config ACPI_PROCFS + bool "Procfs interface (deprecated)" + depends on ACPI + default y + ---help--- + Procfs interface for ACPI is made optional for back-compatible. + As the same functions are duplicated in sysfs interface + and this proc interface will be removed some time later, + it's marked as deprecated. + ( /proc/acpi/debug_layer && debug_level are deprecated by + /sys/module/acpi/parameters/debug_layer && debug_level. + /proc/acpi/info is deprecated by + /sys/module/acpi/parameters/acpica_version ) + config ACPI_AC tristate "AC Adapter" depends on X86 @@ -107,7 +122,7 @@ config ACPI_BUTTON config ACPI_VIDEO tristate "Video" - depends on X86 + depends on X86 && BACKLIGHT_CLASS_DEVICE help This driver implement the ACPI Extensions For Display Adapters for integrated graphics devices on motherboard, as specified in @@ -139,6 +154,13 @@ config ACPI_DOCK help This driver adds support for ACPI controlled docking stations +config ACPI_BAY + tristate "Removable Drive Bay (EXPERIMENTAL)" + depends on EXPERIMENTAL + help + This driver adds support for ACPI controlled removable drive + bays such as the IBM ultrabay or the Dell Module Bay. + config ACPI_PROCESSOR tristate "Processor" default y @@ -186,19 +208,22 @@ config ACPI_ASUS Note: display switching code is currently considered EXPERIMENTAL, toying with these values may even lock your machine. - + All settings are changed via /proc/acpi/asus directory entries. Owner and group for these entries can be set with asus_uid and asus_gid parameters. - + More information and a userspace daemon for handling the extra buttons at . - + If you have an ACPI-compatible ASUS laptop, say Y or M here. This driver is still under development, so if your laptop is unsupported or something works not quite as expected, please use the mailing list - available on the above page (acpi4asus-user@lists.sourceforge.net) - + available on the above page (acpi4asus-user@lists.sourceforge.net). + + NOTE: This driver is deprecated and will probably be removed soon, + use asus-laptop instead. + config ACPI_IBM tristate "IBM ThinkPad Laptop Extras" depends on X86 diff --git a/drivers/acpi/Makefile b/drivers/acpi/Makefile index bce7ca2..856c32b 100644 --- a/drivers/acpi/Makefile +++ b/drivers/acpi/Makefile @@ -37,13 +37,15 @@ endif obj-y += sleep/ obj-y += bus.o glue.o +obj-y += scan.o obj-$(CONFIG_ACPI_AC) += ac.o obj-$(CONFIG_ACPI_BATTERY) += battery.o obj-$(CONFIG_ACPI_BUTTON) += button.o obj-$(CONFIG_ACPI_EC) += ec.o obj-$(CONFIG_ACPI_FAN) += fan.o obj-$(CONFIG_ACPI_DOCK) += dock.o -obj-$(CONFIG_ACPI_VIDEO) += video.o +obj-$(CONFIG_ACPI_BAY) += bay.o +obj-$(CONFIG_ACPI_VIDEO) += video.o obj-$(CONFIG_ACPI_HOTKEY) += hotkey.o obj-y += pci_root.o pci_link.o pci_irq.o pci_bind.o obj-$(CONFIG_ACPI_POWER) += power.o @@ -56,7 +58,6 @@ obj-$(CONFIG_ACPI_NUMA) += numa.o obj-$(CONFIG_ACPI_ASUS) += asus_acpi.o obj-$(CONFIG_ACPI_IBM) += ibm_acpi.o obj-$(CONFIG_ACPI_TOSHIBA) += toshiba_acpi.o -obj-y += scan.o motherboard.o obj-$(CONFIG_ACPI_HOTPLUG_MEMORY) += acpi_memhotplug.o obj-y += cm_sbs.o obj-$(CONFIG_ACPI_SBS) += i2c_ec.o sbs.o diff --git a/drivers/acpi/asus_acpi.c b/drivers/acpi/asus_acpi.c index 396140b..31ad70a 100644 --- a/drivers/acpi/asus_acpi.c +++ b/drivers/acpi/asus_acpi.c @@ -26,7 +26,7 @@ * Pontus Fuchs - Helper functions, cleanup * Johann Wiesner - Small compile fixes * John Belmonte - ACPI code for Toshiba laptop was a good starting point. - * Éric Burghard - LED display support for W1N + * �ic Burghard - LED display support for W1N * */ @@ -1128,7 +1128,6 @@ static int asus_model_match(char *model) static int asus_hotk_get_info(void) { struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL }; - struct acpi_buffer dsdt = { ACPI_ALLOCATE_BUFFER, NULL }; union acpi_object *model = NULL; int bsts_result; char *string = NULL; @@ -1142,11 +1141,9 @@ static int asus_hotk_get_info(void) * HID), this bit will be moved. A global variable asus_info contains * the DSDT header. */ - status = acpi_get_table(ACPI_TABLE_ID_DSDT, 1, &dsdt); + status = acpi_get_table(ACPI_SIG_DSDT, 1, &asus_info); if (ACPI_FAILURE(status)) printk(KERN_WARNING " Couldn't get the DSDT table header\n"); - else - asus_info = dsdt.pointer; /* We have to write 0 on init this far for all ASUS models */ if (!write_acpi_int(hotk->handle, "INIT", 0, &buffer)) { @@ -1358,8 +1355,6 @@ static void __exit asus_acpi_exit(void) acpi_bus_unregister_driver(&asus_hotk_driver); remove_proc_entry(PROC_ASUS, acpi_root_dir); - kfree(asus_info); - return; } diff --git a/drivers/acpi/battery.c b/drivers/acpi/battery.c index 5f43e0d..2f4521a 100644 --- a/drivers/acpi/battery.c +++ b/drivers/acpi/battery.c @@ -64,7 +64,7 @@ extern void *acpi_unlock_battery_dir(str static int acpi_battery_add(struct acpi_device *device); static int acpi_battery_remove(struct acpi_device *device, int type); -static int acpi_battery_resume(struct acpi_device *device, int status); +static int acpi_battery_resume(struct acpi_device *device); static struct acpi_driver acpi_battery_driver = { .name = ACPI_BATTERY_DRIVER_NAME, @@ -753,7 +753,7 @@ static int acpi_battery_remove(struct ac } /* this is needed to learn about changes made in suspended state */ -static int acpi_battery_resume(struct acpi_device *device, int state) +static int acpi_battery_resume(struct acpi_device *device) { struct acpi_battery *battery; diff --git a/drivers/acpi/bay.c b/drivers/acpi/bay.c new file mode 100644 index 0000000..91082ce --- /dev/null +++ b/drivers/acpi/bay.c @@ -0,0 +1,490 @@ +/* + * bay.c - ACPI removable drive bay driver + * + * Copyright (C) 2006 Kristen Carlson Accardi + * + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or (at + * your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + * + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define ACPI_BAY_DRIVER_NAME "ACPI Removable Drive Bay Driver" + +ACPI_MODULE_NAME("bay") +MODULE_AUTHOR("Kristen Carlson Accardi"); +MODULE_DESCRIPTION(ACPI_BAY_DRIVER_NAME); +MODULE_LICENSE("GPL"); +#define ACPI_BAY_CLASS "bay" +#define ACPI_BAY_COMPONENT 0x10000000 +#define _COMPONENT ACPI_BAY_COMPONENT +#define bay_dprintk(h,s) {\ + char prefix[80] = {'\0'};\ + struct acpi_buffer buffer = {sizeof(prefix), prefix};\ + acpi_get_name(h, ACPI_FULL_PATHNAME, &buffer);\ + printk(KERN_DEBUG PREFIX "%s: %s\n", prefix, s); } +static void bay_notify(acpi_handle handle, u32 event, void *data); +static int acpi_bay_add(struct acpi_device *device); +static int acpi_bay_remove(struct acpi_device *device, int type); + +static struct acpi_driver acpi_bay_driver = { + .name = ACPI_BAY_DRIVER_NAME, + .class = ACPI_BAY_CLASS, + .ids = ACPI_BAY_HID, + .ops = { + .add = acpi_bay_add, + .remove = acpi_bay_remove, + }, +}; + +struct bay { + acpi_handle handle; + char *name; + struct list_head list; + struct platform_device *pdev; +}; + +static LIST_HEAD(drive_bays); + + +/***************************************************************************** + * Drive Bay functions * + *****************************************************************************/ +/** + * is_ejectable - see if a device is ejectable + * @handle: acpi handle of the device + * + * If an acpi object has a _EJ0 method, then it is ejectable + */ +static int is_ejectable(acpi_handle handle) +{ + acpi_status status; + acpi_handle tmp; + + status = acpi_get_handle(handle, "_EJ0", &tmp); + if (ACPI_FAILURE(status)) + return 0; + return 1; +} + +/** + * bay_present - see if the bay device is present + * @bay: the drive bay + * + * execute the _STA method. + */ +static int bay_present(struct bay *bay) +{ + unsigned long sta; + acpi_status status; + + if (bay) { + status = acpi_evaluate_integer(bay->handle, "_STA", NULL, &sta); + if (ACPI_SUCCESS(status) && sta) + return 1; + } + return 0; +} + +/** + * eject_device - respond to an eject request + * @handle - the device to eject + * + * Call this devices _EJ0 method. + */ +static void eject_device(acpi_handle handle) +{ + struct acpi_object_list arg_list; + union acpi_object arg; + + bay_dprintk(handle, "Ejecting device"); + + arg_list.count = 1; + arg_list.pointer = &arg; + arg.type = ACPI_TYPE_INTEGER; + arg.integer.value = 1; + + if (ACPI_FAILURE(acpi_evaluate_object(handle, "_EJ0", + &arg_list, NULL))) + pr_debug("Failed to evaluate _EJ0!\n"); +} + +/* + * show_present - read method for "present" file in sysfs + */ +static ssize_t show_present(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct bay *bay = dev_get_drvdata(dev); + return snprintf(buf, PAGE_SIZE, "%d\n", bay_present(bay)); + +} +DEVICE_ATTR(present, S_IRUGO, show_present, NULL); + +/* + * write_eject - write method for "eject" file in sysfs + */ +static ssize_t write_eject(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) +{ + struct bay *bay = dev_get_drvdata(dev); + + if (!count) + return -EINVAL; + + eject_device(bay->handle); + return count; +} +DEVICE_ATTR(eject, S_IWUSR, NULL, write_eject); + +/** + * is_ata - see if a device is an ata device + * @handle: acpi handle of the device + * + * If an acpi object has one of 4 ATA ACPI methods defined, + * then it is an ATA device + */ +static int is_ata(acpi_handle handle) +{ + acpi_handle tmp; + + if ((ACPI_SUCCESS(acpi_get_handle(handle, "_GTF", &tmp))) || + (ACPI_SUCCESS(acpi_get_handle(handle, "_GTM", &tmp))) || + (ACPI_SUCCESS(acpi_get_handle(handle, "_STM", &tmp))) || + (ACPI_SUCCESS(acpi_get_handle(handle, "_SDD", &tmp)))) + return 1; + + return 0; +} + +/** + * parent_is_ata(acpi_handle handle) + * + */ +static int parent_is_ata(acpi_handle handle) +{ + acpi_handle phandle; + + if (acpi_get_parent(handle, &phandle)) + return 0; + + return is_ata(phandle); +} + +/** + * is_ejectable_bay - see if a device is an ejectable drive bay + * @handle: acpi handle of the device + * + * If an acpi object is ejectable and has one of the ACPI ATA + * methods defined, then we can safely call it an ejectable + * drive bay + */ +static int is_ejectable_bay(acpi_handle handle) +{ + if ((is_ata(handle) || parent_is_ata(handle)) && is_ejectable(handle)) + return 1; + return 0; +} + +/** + * eject_removable_drive - try to eject this drive + * @dev : the device structure of the drive + * + * If a device is a removable drive that requires an _EJ0 method + * to be executed in order to safely remove from the system, do + * it. ATM - always returns success + */ +int eject_removable_drive(struct device *dev) +{ + acpi_handle handle = DEVICE_ACPI_HANDLE(dev); + + if (handle) { + bay_dprintk(handle, "Got device handle"); + if (is_ejectable_bay(handle)) + eject_device(handle); + } else { + printk("No acpi handle for device\n"); + } + + /* should I return an error code? */ + return 0; +} +EXPORT_SYMBOL_GPL(eject_removable_drive); + +static int acpi_bay_add(struct acpi_device *device) +{ + bay_dprintk(device->handle, "adding bay device"); + strcpy(acpi_device_name(device), "Dockable Bay"); + strcpy(acpi_device_class(device), "bay"); + return 0; +} + +static int acpi_bay_add_fs(struct bay *bay) +{ + int ret; + struct device *dev = &bay->pdev->dev; + + ret = device_create_file(dev, &dev_attr_present); + if (ret) + goto add_fs_err; + ret = device_create_file(dev, &dev_attr_eject); + if (ret) { + device_remove_file(dev, &dev_attr_present); + goto add_fs_err; + } + return 0; + + add_fs_err: + bay_dprintk(bay->handle, "Error adding sysfs files\n"); + return ret; +} + +static void acpi_bay_remove_fs(struct bay *bay) +{ + struct device *dev = &bay->pdev->dev; + + /* cleanup sysfs */ + device_remove_file(dev, &dev_attr_present); + device_remove_file(dev, &dev_attr_eject); +} + +static int bay_is_dock_device(acpi_handle handle) +{ + acpi_handle parent; + + acpi_get_parent(handle, &parent); + + /* if the device or it's parent is dependent on the + * dock, then we are a dock device + */ + return (is_dock_device(handle) || is_dock_device(parent)); +} + +static int bay_add(acpi_handle handle, int id) +{ + acpi_status status; + struct bay *new_bay; + struct platform_device *pdev; + struct acpi_buffer nbuffer = {ACPI_ALLOCATE_BUFFER, NULL}; + acpi_get_name(handle, ACPI_FULL_PATHNAME, &nbuffer); + + bay_dprintk(handle, "Adding notify handler"); + + /* + * Initialize bay device structure + */ + new_bay = kzalloc(sizeof(*new_bay), GFP_ATOMIC); + INIT_LIST_HEAD(&new_bay->list); + new_bay->handle = handle; + new_bay->name = (char *)nbuffer.pointer; + + /* initialize platform device stuff */ + pdev = platform_device_register_simple(ACPI_BAY_CLASS, id, NULL, 0); + if (pdev == NULL) { + printk(KERN_ERR PREFIX "Error registering bay device\n"); + goto bay_add_err; + } + new_bay->pdev = pdev; + platform_set_drvdata(pdev, new_bay); + + if (acpi_bay_add_fs(new_bay)) { + platform_device_unregister(new_bay->pdev); + goto bay_add_err; + } + + /* register for events on this device */ + status = acpi_install_notify_handler(handle, ACPI_SYSTEM_NOTIFY, + bay_notify, new_bay); + if (ACPI_FAILURE(status)) { + printk(KERN_ERR PREFIX "Error installing bay notify handler\n"); + } + + /* if we are on a dock station, we should register for dock + * notifications. + */ + if (bay_is_dock_device(handle)) { + bay_dprintk(handle, "Is dependent on dock\n"); + register_hotplug_dock_device(handle, bay_notify, new_bay); + } + list_add(&new_bay->list, &drive_bays); + printk(KERN_INFO PREFIX "Bay [%s] Added\n", new_bay->name); + return 0; + +bay_add_err: + kfree(new_bay->name); + kfree(new_bay); + return -ENODEV; +} + +static int acpi_bay_remove(struct acpi_device *device, int type) +{ + /*** FIXME: do something here */ + return 0; +} + +/** + * bay_create_acpi_device - add new devices to acpi + * @handle - handle of the device to add + * + * This function will create a new acpi_device for the given + * handle if one does not exist already. This should cause + * acpi to scan for drivers for the given devices, and call + * matching driver's add routine. + * + * Returns a pointer to the acpi_device corresponding to the handle. + */ +static struct acpi_device * bay_create_acpi_device(acpi_handle handle) +{ + struct acpi_device *device = NULL; + struct acpi_device *parent_device; + acpi_handle parent; + int ret; + + bay_dprintk(handle, "Trying to get device"); + if (acpi_bus_get_device(handle, &device)) { + /* + * no device created for this object, + * so we should create one. + */ + bay_dprintk(handle, "No device for handle"); + acpi_get_parent(handle, &parent); + if (acpi_bus_get_device(parent, &parent_device)) + parent_device = NULL; + + ret = acpi_bus_add(&device, parent_device, handle, + ACPI_BUS_TYPE_DEVICE); + if (ret) { + pr_debug("error adding bus, %x\n", + -ret); + return NULL; + } + } + return device; +} + +/** + * bay_notify - act upon an acpi bay notification + * @handle: the bay handle + * @event: the acpi event + * @data: our driver data struct + * + */ +static void bay_notify(acpi_handle handle, u32 event, void *data) +{ + struct acpi_device *dev; + + bay_dprintk(handle, "Bay event"); + + switch(event) { + case ACPI_NOTIFY_BUS_CHECK: + printk("Bus Check\n"); + case ACPI_NOTIFY_DEVICE_CHECK: + printk("Device Check\n"); + dev = bay_create_acpi_device(handle); + if (dev) + acpi_bus_generate_event(dev, event, 0); + else + printk("No device for generating event\n"); + /* wouldn't it be a good idea to just rescan SATA + * right here? + */ + break; + case ACPI_NOTIFY_EJECT_REQUEST: + printk("Eject request\n"); + dev = bay_create_acpi_device(handle); + if (dev) + acpi_bus_generate_event(dev, event, 0); + else + printk("No device for generating eventn"); + + /* wouldn't it be a good idea to just call the + * eject_device here if we were a SATA device? + */ + break; + default: + printk("unknown event %d\n", event); + } +} + +static acpi_status +find_bay(acpi_handle handle, u32 lvl, void *context, void **rv) +{ + int *count = (int *)context; + + /* + * there could be more than one ejectable bay. + * so, just return AE_OK always so that every object + * will be checked. + */ + if (is_ejectable_bay(handle)) { + bay_dprintk(handle, "found ejectable bay"); + if (!bay_add(handle, *count)) + (*count)++; + } + return AE_OK; +} + +static int __init bay_init(void) +{ + int bays = 0; + + INIT_LIST_HEAD(&drive_bays); + + /* look for dockable drive bays */ + acpi_walk_namespace(ACPI_TYPE_DEVICE, ACPI_ROOT_OBJECT, + ACPI_UINT32_MAX, find_bay, &bays, NULL); + + if (bays) + if ((acpi_bus_register_driver(&acpi_bay_driver) < 0)) + printk(KERN_ERR "Unable to register bay driver\n"); + + if (!bays) + return -ENODEV; + + return 0; +} + +static void __exit bay_exit(void) +{ + struct bay *bay, *tmp; + + list_for_each_entry_safe(bay, tmp, &drive_bays, list) { + if (is_dock_device(bay->handle)) + unregister_hotplug_dock_device(bay->handle); + acpi_bay_remove_fs(bay); + acpi_remove_notify_handler(bay->handle, ACPI_SYSTEM_NOTIFY, + bay_notify); + platform_device_unregister(bay->pdev); + kfree(bay->name); + kfree(bay); + } + + acpi_bus_unregister_driver(&acpi_bay_driver); +} + +postcore_initcall(bay_init); +module_exit(bay_exit); + diff --git a/drivers/acpi/blacklist.c b/drivers/acpi/blacklist.c index f9c972b..f289fd4 100644 --- a/drivers/acpi/blacklist.c +++ b/drivers/acpi/blacklist.c @@ -44,7 +44,7 @@ struct acpi_blacklist_item { char oem_id[7]; char oem_table_id[9]; u32 oem_revision; - acpi_table_type table; + char *table; enum acpi_blacklist_predicates oem_revision_predicate; char *reason; u32 is_critical_error; @@ -56,18 +56,18 @@ struct acpi_blacklist_item { */ static struct acpi_blacklist_item acpi_blacklist[] __initdata = { /* Compaq Presario 1700 */ - {"PTLTD ", " DSDT ", 0x06040000, ACPI_DSDT, less_than_or_equal, + {"PTLTD ", " DSDT ", 0x06040000, ACPI_SIG_DSDT, less_than_or_equal, "Multiple problems", 1}, /* Sony FX120, FX140, FX150? */ - {"SONY ", "U0 ", 0x20010313, ACPI_DSDT, less_than_or_equal, + {"SONY ", "U0 ", 0x20010313, ACPI_SIG_DSDT, less_than_or_equal, "ACPI driver problem", 1}, /* Compaq Presario 800, Insyde BIOS */ - {"INT440", "SYSFexxx", 0x00001001, ACPI_DSDT, less_than_or_equal, + {"INT440", "SYSFexxx", 0x00001001, ACPI_SIG_DSDT, less_than_or_equal, "Does not use _REG to protect EC OpRegions", 1}, /* IBM 600E - _ADR should return 7, but it returns 1 */ - {"IBM ", "TP600E ", 0x00000105, ACPI_DSDT, less_than_or_equal, + {"IBM ", "TP600E ", 0x00000105, ACPI_SIG_DSDT, less_than_or_equal, "Incorrect _ADR", 1}, - {"ASUS\0\0", "P2B-S ", 0, ACPI_DSDT, all_versions, + {"ASUS\0\0", "P2B-S ", 0, ACPI_SIG_DSDT, all_versions, "Bogus PCI routing", 1}, {""} @@ -79,7 +79,7 @@ static int __init blacklist_by_year(void { int year = dmi_get_year(DMI_BIOS_DATE); /* Doesn't exist? Likely an old system */ - if (year == -1) + if (year == -1) return 1; /* 0? Likely a buggy new BIOS */ if (year == 0) @@ -103,22 +103,21 @@ int __init acpi_blacklisted(void) { int i = 0; int blacklisted = 0; - struct acpi_table_header *table_header; + struct acpi_table_header table_header; while (acpi_blacklist[i].oem_id[0] != '\0') { - if (acpi_get_table_header_early - (acpi_blacklist[i].table, &table_header)) { + if (acpi_get_table_header(acpi_blacklist[i].table, 0, &table_header)) { i++; continue; } - if (strncmp(acpi_blacklist[i].oem_id, table_header->oem_id, 6)) { + if (strncmp(acpi_blacklist[i].oem_id, table_header.oem_id, 6)) { i++; continue; } if (strncmp - (acpi_blacklist[i].oem_table_id, table_header->oem_table_id, + (acpi_blacklist[i].oem_table_id, table_header.oem_table_id, 8)) { i++; continue; @@ -127,14 +126,14 @@ int __init acpi_blacklisted(void) if ((acpi_blacklist[i].oem_revision_predicate == all_versions) || (acpi_blacklist[i].oem_revision_predicate == less_than_or_equal - && table_header->oem_revision <= + && table_header.oem_revision <= acpi_blacklist[i].oem_revision) || (acpi_blacklist[i].oem_revision_predicate == greater_than_or_equal - && table_header->oem_revision >= + && table_header.oem_revision >= acpi_blacklist[i].oem_revision) || (acpi_blacklist[i].oem_revision_predicate == equal - && table_header->oem_revision == + && table_header.oem_revision == acpi_blacklist[i].oem_revision)) { printk(KERN_ERR PREFIX diff --git a/drivers/acpi/bus.c b/drivers/acpi/bus.c index 766332e..c26468d 100644 --- a/drivers/acpi/bus.c +++ b/drivers/acpi/bus.c @@ -44,9 +44,6 @@ #ifdef CONFIG_X86 extern void __init acpi_pic_sci_set_trigger(unsigned int irq, u16 trigger); #endif -struct fadt_descriptor acpi_fadt; -EXPORT_SYMBOL(acpi_fadt); - struct acpi_device *acpi_root; struct proc_dir_entry *acpi_root_dir; EXPORT_SYMBOL(acpi_root_dir); @@ -195,7 +192,7 @@ int acpi_bus_set_power(acpi_handle handl if (!device->flags.power_manageable) { ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Device `[%s]' is not power manageable\n", - device->kobj.name)); + device->dev.kobj.name)); return -ENODEV; } /* @@ -582,11 +579,12 @@ static int __init acpi_bus_init_irq(void return 0; } +acpi_native_uint acpi_gbl_permanent_mmap; + + void __init acpi_early_init(void) { acpi_status status = AE_OK; - struct acpi_buffer buffer = { sizeof(acpi_fadt), &acpi_fadt }; - if (acpi_disabled) return; @@ -597,6 +595,15 @@ void __init acpi_early_init(void) if (!acpi_strict) acpi_gbl_enable_interpreter_slack = TRUE; + acpi_gbl_permanent_mmap = 1; + + status = acpi_reallocate_root_table(); + if (ACPI_FAILURE(status)) { + printk(KERN_ERR PREFIX + "Unable to reallocate ACPI tables\n"); + goto error0; + } + status = acpi_initialize_subsystem(); if (ACPI_FAILURE(status)) { printk(KERN_ERR PREFIX @@ -611,32 +618,25 @@ void __init acpi_early_init(void) goto error0; } - /* - * Get a separate copy of the FADT for use by other drivers. - */ - status = acpi_get_table(ACPI_TABLE_ID_FADT, 1, &buffer); - if (ACPI_FAILURE(status)) { - printk(KERN_ERR PREFIX "Unable to get the FADT\n"); - goto error0; - } #ifdef CONFIG_X86 if (!acpi_ioapic) { - extern acpi_interrupt_flags acpi_sci_flags; + extern u8 acpi_sci_flags; /* compatible (0) means level (3) */ - if (acpi_sci_flags.trigger == 0) - acpi_sci_flags.trigger = 3; - + if (!(acpi_sci_flags & ACPI_MADT_TRIGGER_MASK)) { + acpi_sci_flags &= ~ACPI_MADT_TRIGGER_MASK; + acpi_sci_flags |= ACPI_MADT_TRIGGER_LEVEL; + } /* Set PIC-mode SCI trigger type */ - acpi_pic_sci_set_trigger(acpi_fadt.sci_int, - acpi_sci_flags.trigger); + acpi_pic_sci_set_trigger(acpi_gbl_FADT.sci_interrupt, + (acpi_sci_flags & ACPI_MADT_TRIGGER_MASK) >> 2); } else { extern int acpi_sci_override_gsi; /* - * now that acpi_fadt is initialized, + * now that acpi_gbl_FADT is initialized, * update it with result from INT_SRC_OVR parsing */ - acpi_fadt.sci_int = acpi_sci_override_gsi; + acpi_gbl_FADT.sci_interrupt = acpi_sci_override_gsi; } #endif diff --git a/drivers/acpi/button.c b/drivers/acpi/button.c index ac86058..c726612 100644 --- a/drivers/acpi/button.c +++ b/drivers/acpi/button.c @@ -75,7 +75,7 @@ static int acpi_button_state_open_fs(str static struct acpi_driver acpi_button_driver = { .name = ACPI_BUTTON_DRIVER_NAME, .class = ACPI_BUTTON_CLASS, - .ids = "ACPI_FPB,ACPI_FSB,PNP0C0D,PNP0C0C,PNP0C0E", + .ids = "button_power,button_sleep,PNP0C0D,PNP0C0C,PNP0C0E", .ops = { .add = acpi_button_add, .remove = acpi_button_remove, diff --git a/drivers/acpi/container.c b/drivers/acpi/container.c index 0a1863e..69a68fd 100644 --- a/drivers/acpi/container.c +++ b/drivers/acpi/container.c @@ -167,7 +167,7 @@ static void container_notify_cb(acpi_han if (ACPI_FAILURE(status) || !device) { result = container_device_add(&device, handle); if (!result) - kobject_uevent(&device->kobj, + kobject_uevent(&device->dev.kobj, KOBJ_ONLINE); else printk("Failed to add container\n"); @@ -175,13 +175,13 @@ static void container_notify_cb(acpi_han } else { if (ACPI_SUCCESS(status)) { /* device exist and this is a remove request */ - kobject_uevent(&device->kobj, KOBJ_OFFLINE); + kobject_uevent(&device->dev.kobj, KOBJ_OFFLINE); } } break; case ACPI_NOTIFY_EJECT_REQUEST: if (!acpi_bus_get_device(handle, &device) && device) { - kobject_uevent(&device->kobj, KOBJ_OFFLINE); + kobject_uevent(&device->dev.kobj, KOBJ_OFFLINE); } break; default: diff --git a/drivers/acpi/debug.c b/drivers/acpi/debug.c index 35c6af8..d48f65a 100644 --- a/drivers/acpi/debug.c +++ b/drivers/acpi/debug.c @@ -13,14 +13,11 @@ #include #define _COMPONENT ACPI_SYSTEM_COMPONENT ACPI_MODULE_NAME("debug") -#define ACPI_SYSTEM_FILE_DEBUG_LAYER "debug_layer" -#define ACPI_SYSTEM_FILE_DEBUG_LEVEL "debug_level" + #ifdef MODULE_PARAM_PREFIX #undef MODULE_PARAM_PREFIX #endif -#define MODULE_PARAM_PREFIX - module_param(acpi_dbg_layer, uint, 0400); -module_param(acpi_dbg_level, uint, 0400); +#define MODULE_PARAM_PREFIX "acpi." struct acpi_dlayer { const char *name; @@ -86,6 +83,60 @@ static const struct acpi_dlevel acpi_deb ACPI_DEBUG_INIT(ACPI_LV_EVENTS), }; +/* -------------------------------------------------------------------------- + FS Interface (/sys) + -------------------------------------------------------------------------- */ +static int param_get_debug_layer(char *buffer, struct kernel_param *kp) { + int result = 0; + int i; + + result = sprintf(buffer, "%-25s\tHex SET\n", "Description"); + + for(i = 0; i common.next; - info.bank_value = (u32) arg->common.value.integer; + + /* Currently, only the following constants are supported */ + + switch (arg->common.aml_opcode) { + case AML_ZERO_OP: + info.bank_value = 0; + break; + + case AML_ONE_OP: + info.bank_value = 1; + break; + + case AML_BYTE_OP: + case AML_WORD_OP: + case AML_DWORD_OP: + case AML_QWORD_OP: + info.bank_value = (u32) arg->common.value.integer; + break; + + default: + info.bank_value = 0; + ACPI_ERROR((AE_INFO, + "Non-constant BankValue for BankField is not implemented")); + } /* Fourth arg is the field flags */ diff --git a/drivers/acpi/dispatcher/dsinit.c b/drivers/acpi/dispatcher/dsinit.c index 1888c05..af923c3 100644 --- a/drivers/acpi/dispatcher/dsinit.c +++ b/drivers/acpi/dispatcher/dsinit.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2006, R. Byron Moore + * Copyright (C) 2000 - 2007, R. Byron Moore * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -44,6 +44,7 @@ #include #include #include +#include #define _COMPONENT ACPI_DISPATCHER ACPI_MODULE_NAME("dsinit") @@ -90,7 +91,7 @@ acpi_ds_init_one_object(acpi_handle obj_ * We are only interested in NS nodes owned by the table that * was just loaded */ - if (node->owner_id != info->table_desc->owner_id) { + if (node->owner_id != info->owner_id) { return (AE_OK); } @@ -150,14 +151,21 @@ acpi_ds_init_one_object(acpi_handle obj_ ******************************************************************************/ acpi_status -acpi_ds_initialize_objects(struct acpi_table_desc * table_desc, +acpi_ds_initialize_objects(acpi_native_uint table_index, struct acpi_namespace_node * start_node) { acpi_status status; struct acpi_init_walk_info info; + struct acpi_table_header *table; + acpi_owner_id owner_id; ACPI_FUNCTION_TRACE(ds_initialize_objects); + status = acpi_tb_get_owner_id(table_index, &owner_id); + if (ACPI_FAILURE(status)) { + return_ACPI_STATUS(status); + } + ACPI_DEBUG_PRINT((ACPI_DB_DISPATCH, "**** Starting initialization of namespace objects ****\n")); ACPI_DEBUG_PRINT_RAW((ACPI_DB_INIT, "Parsing all Control Methods:")); @@ -166,7 +174,8 @@ acpi_ds_initialize_objects(struct acpi_t info.op_region_count = 0; info.object_count = 0; info.device_count = 0; - info.table_desc = table_desc; + info.table_index = table_index; + info.owner_id = owner_id; /* Walk entire namespace from the supplied root */ @@ -176,10 +185,14 @@ acpi_ds_initialize_objects(struct acpi_t ACPI_EXCEPTION((AE_INFO, status, "During WalkNamespace")); } + status = acpi_get_table_by_index(table_index, &table); + if (ACPI_FAILURE(status)) { + return_ACPI_STATUS(status); + } + ACPI_DEBUG_PRINT_RAW((ACPI_DB_INIT, "\nTable [%4.4s](id %4.4X) - %hd Objects with %hd Devices %hd Methods %hd Regions\n", - table_desc->pointer->signature, - table_desc->owner_id, info.object_count, + table->signature, owner_id, info.object_count, info.device_count, info.method_count, info.op_region_count)); diff --git a/drivers/acpi/dispatcher/dsmethod.c b/drivers/acpi/dispatcher/dsmethod.c index cf888ad..1cbe619 100644 --- a/drivers/acpi/dispatcher/dsmethod.c +++ b/drivers/acpi/dispatcher/dsmethod.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2006, R. Byron Moore + * Copyright (C) 2000 - 2007, R. Byron Moore * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -327,7 +327,7 @@ acpi_ds_call_control_method(struct acpi_ ACPI_FUNCTION_TRACE_PTR(ds_call_control_method, this_walk_state); ACPI_DEBUG_PRINT((ACPI_DB_DISPATCH, - "Execute method %p, currentstate=%p\n", + "Calling method %p, currentstate=%p\n", this_walk_state->prev_op, this_walk_state)); /* @@ -351,49 +351,7 @@ acpi_ds_call_control_method(struct acpi_ return_ACPI_STATUS(status); } - /* - * 1) Parse the method. All "normal" methods are parsed for each execution. - * Internal methods (_OSI, etc.) do not require parsing. - */ - if (!(obj_desc->method.method_flags & AML_METHOD_INTERNAL_ONLY)) { - - /* Create a new walk state for the parse */ - - next_walk_state = - acpi_ds_create_walk_state(obj_desc->method.owner_id, op, - obj_desc, NULL); - if (!next_walk_state) { - status = AE_NO_MEMORY; - goto cleanup; - } - - /* Create and init a parse tree root */ - - op = acpi_ps_create_scope_op(); - if (!op) { - status = AE_NO_MEMORY; - goto cleanup; - } - - status = acpi_ds_init_aml_walk(next_walk_state, op, method_node, - obj_desc->method.aml_start, - obj_desc->method.aml_length, - NULL, 1); - if (ACPI_FAILURE(status)) { - acpi_ps_delete_parse_tree(op); - goto cleanup; - } - - /* Begin AML parse (deletes next_walk_state) */ - - status = acpi_ps_parse_aml(next_walk_state); - acpi_ps_delete_parse_tree(op); - if (ACPI_FAILURE(status)) { - goto cleanup; - } - } - - /* 2) Begin method execution. Create a new walk state */ + /* Begin method parse/execution. Create a new walk state */ next_walk_state = acpi_ds_create_walk_state(obj_desc->method.owner_id, NULL, obj_desc, thread); @@ -424,7 +382,8 @@ acpi_ds_call_control_method(struct acpi_ status = acpi_ds_init_aml_walk(next_walk_state, NULL, method_node, obj_desc->method.aml_start, - obj_desc->method.aml_length, info, 3); + obj_desc->method.aml_length, info, + ACPI_IMODE_EXECUTE); ACPI_FREE(info); if (ACPI_FAILURE(status)) { @@ -445,8 +404,8 @@ acpi_ds_call_control_method(struct acpi_ this_walk_state->num_operands = 0; ACPI_DEBUG_PRINT((ACPI_DB_DISPATCH, - "Starting nested execution, newstate=%p\n", - next_walk_state)); + "**** Begin nested execution of [%4.4s] **** WalkState=%p\n", + method_node->name.ascii, next_walk_state)); /* Invoke an internal method if necessary */ diff --git a/drivers/acpi/dispatcher/dsmthdat.c b/drivers/acpi/dispatcher/dsmthdat.c index 459160f..ba4626e 100644 --- a/drivers/acpi/dispatcher/dsmthdat.c +++ b/drivers/acpi/dispatcher/dsmthdat.c @@ -5,7 +5,7 @@ ******************************************************************************/ /* - * Copyright (C) 2000 - 2006, R. Byron Moore + * Copyright (C) 2000 - 2007, R. Byron Moore * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/dispatcher/dsobject.c b/drivers/acpi/dispatcher/dsobject.c index 72190ab..a474ca2 100644 --- a/drivers/acpi/dispatcher/dsobject.c +++ b/drivers/acpi/dispatcher/dsobject.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2006, R. Byron Moore + * Copyright (C) 2000 - 2007, R. Byron Moore * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -260,7 +260,7 @@ acpi_ds_build_internal_buffer_obj(struct } obj_desc->buffer.flags |= AOPOBJ_DATA_VALID; - op->common.node = (struct acpi_namespace_node *)obj_desc; + op->common.node = ACPI_CAST_PTR(struct acpi_namespace_node, obj_desc); return_ACPI_STATUS(AE_OK); } @@ -270,7 +270,8 @@ acpi_ds_build_internal_buffer_obj(struct * * PARAMETERS: walk_state - Current walk state * Op - Parser object to be translated - * package_length - Number of elements in the package + * element_count - Number of elements in the package - this is + * the num_elements argument to Package() * obj_desc_ptr - Where the ACPI internal object is returned * * RETURN: Status @@ -278,18 +279,29 @@ acpi_ds_build_internal_buffer_obj(struct * DESCRIPTION: Translate a parser Op package object to the equivalent * namespace object * + * NOTE: The number of elements in the package will be always be the num_elements + * count, regardless of the number of elements in the package list. If + * num_elements is smaller, only that many package list elements are used. + * if num_elements is larger, the Package object is padded out with + * objects of type Uninitialized (as per ACPI spec.) + * + * Even though the ASL compilers do not allow num_elements to be smaller + * than the Package list length (for the fixed length package opcode), some + * BIOS code modifies the AML on the fly to adjust the num_elements, and + * this code compensates for that. This also provides compatibility with + * other AML interpreters. + * ******************************************************************************/ acpi_status acpi_ds_build_internal_package_obj(struct acpi_walk_state *walk_state, union acpi_parse_object *op, - u32 package_length, + u32 element_count, union acpi_operand_object **obj_desc_ptr) { union acpi_parse_object *arg; union acpi_parse_object *parent; union acpi_operand_object *obj_desc = NULL; - u32 package_list_length; acpi_status status = AE_OK; acpi_native_uint i; @@ -318,32 +330,13 @@ acpi_ds_build_internal_package_obj(struc obj_desc->package.node = parent->common.node; } - obj_desc->package.count = package_length; - - /* Count the number of items in the package list */ - - arg = op->common.value.arg; - arg = arg->common.next; - for (package_list_length = 0; arg; package_list_length++) { - arg = arg->common.next; - } - - /* - * The package length (number of elements) will be the greater - * of the specified length and the length of the initializer list - */ - if (package_list_length > package_length) { - obj_desc->package.count = package_list_length; - } - /* - * Allocate the pointer array (array of pointers to the - * individual objects). Add an extra pointer slot so - * that the list is always null terminated. + * Allocate the element array (array of pointers to the individual + * objects) based on the num_elements parameter. Add an extra pointer slot + * so that the list is always null terminated. */ obj_desc->package.elements = ACPI_ALLOCATE_ZEROED(((acpi_size) - obj_desc->package. - count + + element_count + 1) * sizeof(void *)); if (!obj_desc->package.elements) { @@ -351,15 +344,20 @@ acpi_ds_build_internal_package_obj(struc return_ACPI_STATUS(AE_NO_MEMORY); } + obj_desc->package.count = element_count; + /* - * Initialize all elements of the package + * Initialize the elements of the package, up to the num_elements count. + * Package is automatically padded with uninitialized (NULL) elements + * if num_elements is greater than the package list length. Likewise, + * Package is truncated if num_elements is less than the list length. */ arg = op->common.value.arg; arg = arg->common.next; - for (i = 0; arg; i++) { + for (i = 0; arg && (i < element_count); i++) { if (arg->common.aml_opcode == AML_INT_RETURN_VALUE_OP) { - /* Object (package or buffer) is already built */ + /* This package element is already built, just get it */ obj_desc->package.elements[i] = ACPI_CAST_PTR(union acpi_operand_object, @@ -373,8 +371,14 @@ acpi_ds_build_internal_package_obj(struc arg = arg->common.next; } + if (!arg) { + ACPI_DEBUG_PRINT((ACPI_DB_INFO, + "Package List length larger than NumElements count (%X), truncated\n", + element_count)); + } + obj_desc->package.flags |= AOPOBJ_DATA_VALID; - op->common.node = (struct acpi_namespace_node *)obj_desc; + op->common.node = ACPI_CAST_PTR(struct acpi_namespace_node, obj_desc); return_ACPI_STATUS(status); } @@ -488,8 +492,9 @@ acpi_ds_init_object_from_op(struct acpi_ /* * Defer evaluation of Buffer term_arg operand */ - obj_desc->buffer.node = (struct acpi_namespace_node *) - walk_state->operands[0]; + obj_desc->buffer.node = + ACPI_CAST_PTR(struct acpi_namespace_node, + walk_state->operands[0]); obj_desc->buffer.aml_start = op->named.data; obj_desc->buffer.aml_length = op->named.length; break; @@ -499,8 +504,9 @@ acpi_ds_init_object_from_op(struct acpi_ /* * Defer evaluation of Package term_arg operand */ - obj_desc->package.node = (struct acpi_namespace_node *) - walk_state->operands[0]; + obj_desc->package.node = + ACPI_CAST_PTR(struct acpi_namespace_node, + walk_state->operands[0]); obj_desc->package.aml_start = op->named.data; obj_desc->package.aml_length = op->named.length; break; diff --git a/drivers/acpi/dispatcher/dsopcode.c b/drivers/acpi/dispatcher/dsopcode.c index 5b974a8..6c6104a 100644 --- a/drivers/acpi/dispatcher/dsopcode.c +++ b/drivers/acpi/dispatcher/dsopcode.c @@ -6,7 +6,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2006, R. Byron Moore + * Copyright (C) 2000 - 2007, R. Byron Moore * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -114,7 +114,7 @@ acpi_ds_execute_arguments(struct acpi_na } status = acpi_ds_init_aml_walk(walk_state, op, NULL, aml_start, - aml_length, NULL, 1); + aml_length, NULL, ACPI_IMODE_LOAD_PASS1); if (ACPI_FAILURE(status)) { acpi_ds_delete_walk_state(walk_state); goto cleanup; @@ -157,7 +157,7 @@ acpi_ds_execute_arguments(struct acpi_na /* Execute the opcode and arguments */ status = acpi_ds_init_aml_walk(walk_state, op, NULL, aml_start, - aml_length, NULL, 3); + aml_length, NULL, ACPI_IMODE_EXECUTE); if (ACPI_FAILURE(status)) { acpi_ds_delete_walk_state(walk_state); goto cleanup; diff --git a/drivers/acpi/dispatcher/dsutils.c b/drivers/acpi/dispatcher/dsutils.c index 05230ba..e4073e0 100644 --- a/drivers/acpi/dispatcher/dsutils.c +++ b/drivers/acpi/dispatcher/dsutils.c @@ -5,7 +5,7 @@ ******************************************************************************/ /* - * Copyright (C) 2000 - 2006, R. Byron Moore + * Copyright (C) 2000 - 2007, R. Byron Moore * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/dispatcher/dswexec.c b/drivers/acpi/dispatcher/dswexec.c index d7a616c..69693fa 100644 --- a/drivers/acpi/dispatcher/dswexec.c +++ b/drivers/acpi/dispatcher/dswexec.c @@ -6,7 +6,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2006, R. Byron Moore + * Copyright (C) 2000 - 2007, R. Byron Moore * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -219,7 +219,7 @@ acpi_ds_exec_begin_op(struct acpi_walk_s if (!op) { status = acpi_ds_load2_begin_op(walk_state, out_op); if (ACPI_FAILURE(status)) { - return_ACPI_STATUS(status); + goto error_exit; } op = *out_op; @@ -238,7 +238,7 @@ acpi_ds_exec_begin_op(struct acpi_walk_s status = acpi_ds_scope_stack_pop(walk_state); if (ACPI_FAILURE(status)) { - return_ACPI_STATUS(status); + goto error_exit; } } } @@ -287,7 +287,7 @@ acpi_ds_exec_begin_op(struct acpi_walk_s status = acpi_ds_result_stack_push(walk_state); if (ACPI_FAILURE(status)) { - return_ACPI_STATUS(status); + goto error_exit; } status = acpi_ds_exec_begin_control_op(walk_state, op); @@ -328,6 +328,10 @@ acpi_ds_exec_begin_op(struct acpi_walk_s /* Nothing to do here during method execution */ return_ACPI_STATUS(status); + + error_exit: + status = acpi_ds_method_error(status, walk_state); + return_ACPI_STATUS(status); } /***************************************************************************** diff --git a/drivers/acpi/dispatcher/dswload.c b/drivers/acpi/dispatcher/dswload.c index e3ca7f6..8ab9d1b 100644 --- a/drivers/acpi/dispatcher/dswload.c +++ b/drivers/acpi/dispatcher/dswload.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2006, R. Byron Moore + * Copyright (C) 2000 - 2007, R. Byron Moore * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -196,6 +196,7 @@ #endif * one of the opcodes that actually opens a scope */ switch (node->type) { + case ACPI_TYPE_ANY: case ACPI_TYPE_LOCAL_SCOPE: /* Scope */ case ACPI_TYPE_DEVICE: case ACPI_TYPE_POWER: @@ -546,6 +547,7 @@ acpi_ds_load2_begin_op(struct acpi_walk_ acpi_status status; acpi_object_type object_type; char *buffer_ptr; + u32 flags; ACPI_FUNCTION_TRACE(ds_load2_begin_op); @@ -669,6 +671,7 @@ #endif * one of the opcodes that actually opens a scope */ switch (node->type) { + case ACPI_TYPE_ANY: case ACPI_TYPE_LOCAL_SCOPE: /* Scope */ case ACPI_TYPE_DEVICE: case ACPI_TYPE_POWER: @@ -750,12 +753,20 @@ #endif break; } - /* Add new entry into namespace */ + flags = ACPI_NS_NO_UPSEARCH; + if (walk_state->pass_number == ACPI_IMODE_EXECUTE) { + + /* Execution mode, node cannot already exist, node is temporary */ + + flags |= (ACPI_NS_ERROR_IF_FOUND | ACPI_NS_TEMPORARY); + } + + /* Add new entry or lookup existing entry */ status = acpi_ns_lookup(walk_state->scope_info, buffer_ptr, - object_type, ACPI_IMODE_LOAD_PASS2, - ACPI_NS_NO_UPSEARCH, walk_state, &(node)); + object_type, ACPI_IMODE_LOAD_PASS2, flags, + walk_state, &node); break; } diff --git a/drivers/acpi/dispatcher/dswscope.c b/drivers/acpi/dispatcher/dswscope.c index c922897..3927c49 100644 --- a/drivers/acpi/dispatcher/dswscope.c +++ b/drivers/acpi/dispatcher/dswscope.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2006, R. Byron Moore + * Copyright (C) 2000 - 2007, R. Byron Moore * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/dispatcher/dswstate.c b/drivers/acpi/dispatcher/dswstate.c index 7817e55..16c8e38 100644 --- a/drivers/acpi/dispatcher/dswstate.c +++ b/drivers/acpi/dispatcher/dswstate.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2006, R. Byron Moore + * Copyright (C) 2000 - 2007, R. Byron Moore * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/dock.c b/drivers/acpi/dock.c index 90990a4..688e83a 100644 --- a/drivers/acpi/dock.c +++ b/drivers/acpi/dock.c @@ -615,20 +615,28 @@ static acpi_status find_dock_devices(acpi_handle handle, u32 lvl, void *context, void **rv) { acpi_status status; - acpi_handle tmp; + acpi_handle tmp, parent; struct dock_station *ds = context; struct dock_dependent_device *dd; status = acpi_bus_get_ejd(handle, &tmp); - if (ACPI_FAILURE(status)) - return AE_OK; + if (ACPI_FAILURE(status)) { + /* try the parent device as well */ + status = acpi_get_parent(handle, &parent); + if (ACPI_FAILURE(status)) + goto fdd_out; + /* see if parent is dependent on dock */ + status = acpi_bus_get_ejd(parent, &tmp); + if (ACPI_FAILURE(status)) + goto fdd_out; + } if (tmp == ds->handle) { dd = alloc_dock_dependent_device(handle); if (dd) add_dock_dependent_device(ds, dd); } - +fdd_out: return AE_OK; } diff --git a/drivers/acpi/ec.c b/drivers/acpi/ec.c index cbdf031..743ce27 100644 --- a/drivers/acpi/ec.c +++ b/drivers/acpi/ec.c @@ -872,9 +872,8 @@ static int __init acpi_ec_get_real_ecdt( acpi_status status; struct acpi_table_ecdt *ecdt_ptr; - status = acpi_get_firmware_table("ECDT", 1, ACPI_LOGICAL_ADDRESSING, - (struct acpi_table_header **) - &ecdt_ptr); + status = acpi_get_table(ACPI_SIG_ECDT, 1, + (struct acpi_table_header **)&ecdt_ptr); if (ACPI_FAILURE(status)) return -ENODEV; @@ -891,14 +890,14 @@ static int __init acpi_ec_get_real_ecdt( if (acpi_ec_mode == EC_INTR) { init_waitqueue_head(&ec_ecdt->wait); } - ec_ecdt->command_addr = ecdt_ptr->ec_control.address; - ec_ecdt->data_addr = ecdt_ptr->ec_data.address; - ec_ecdt->gpe = ecdt_ptr->gpe_bit; + ec_ecdt->command_addr = ecdt_ptr->control.address; + ec_ecdt->data_addr = ecdt_ptr->data.address; + ec_ecdt->gpe = ecdt_ptr->gpe; /* use the GL just to be safe */ ec_ecdt->global_lock = TRUE; ec_ecdt->uid = ecdt_ptr->uid; - status = acpi_get_handle(NULL, ecdt_ptr->ec_id, &ec_ecdt->handle); + status = acpi_get_handle(NULL, ecdt_ptr->id, &ec_ecdt->handle); if (ACPI_FAILURE(status)) { goto error; } diff --git a/drivers/acpi/events/evevent.c b/drivers/acpi/events/evevent.c index 919037d..a1f87b5 100644 --- a/drivers/acpi/events/evevent.c +++ b/drivers/acpi/events/evevent.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2006, R. Byron Moore + * Copyright (C) 2000 - 2007, R. Byron Moore * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -70,13 +70,6 @@ acpi_status acpi_ev_initialize_events(vo ACPI_FUNCTION_TRACE(ev_initialize_events); - /* Make sure we have ACPI tables */ - - if (!acpi_gbl_DSDT) { - ACPI_WARNING((AE_INFO, "No ACPI tables present!")); - return_ACPI_STATUS(AE_NO_ACPI_TABLES); - } - /* * Initialize the Fixed and General Purpose Events. This is done prior to * enabling SCIs to prevent interrupts from occurring before the handlers are @@ -211,8 +204,7 @@ static acpi_status acpi_ev_fixed_event_i if (acpi_gbl_fixed_event_info[i].enable_register_id != 0xFF) { status = acpi_set_register(acpi_gbl_fixed_event_info[i]. - enable_register_id, 0, - ACPI_MTX_LOCK); + enable_register_id, 0); if (ACPI_FAILURE(status)) { return (status); } @@ -298,7 +290,7 @@ static u32 acpi_ev_fixed_event_dispatch( /* Clear the status bit */ (void)acpi_set_register(acpi_gbl_fixed_event_info[event]. - status_register_id, 1, ACPI_MTX_DO_NOT_LOCK); + status_register_id, 1); /* * Make sure we've got a handler. If not, report an error. @@ -306,8 +298,7 @@ static u32 acpi_ev_fixed_event_dispatch( */ if (NULL == acpi_gbl_fixed_event_handlers[event].handler) { (void)acpi_set_register(acpi_gbl_fixed_event_info[event]. - enable_register_id, 0, - ACPI_MTX_DO_NOT_LOCK); + enable_register_id, 0); ACPI_ERROR((AE_INFO, "No installed handler for fixed event [%08X]", diff --git a/drivers/acpi/events/evgpe.c b/drivers/acpi/events/evgpe.c index c76c058..dfac3ec 100644 --- a/drivers/acpi/events/evgpe.c +++ b/drivers/acpi/events/evgpe.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2006, R. Byron Moore + * Copyright (C) 2000 - 2007, R. Byron Moore * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -121,7 +121,9 @@ acpi_ev_update_gpe_enable_masks(struct a if (!gpe_register_info) { return_ACPI_STATUS(AE_NOT_EXIST); } - register_bit = gpe_event_info->register_bit; + register_bit = (u8) + (1 << + (gpe_event_info->gpe_number - gpe_register_info->base_gpe_number)); /* 1) Disable case. Simply clear all enable bits */ @@ -458,8 +460,7 @@ u32 acpi_ev_gpe_detect(struct acpi_gpe_x /* Examine one GPE bit */ - if (enabled_status_byte & - acpi_gbl_decode_to8bit[j]) { + if (enabled_status_byte & (1 << j)) { /* * Found an active GPE. Dispatch the event to a handler * or method. @@ -570,7 +571,7 @@ static void ACPI_SYSTEM_XFACE acpi_ev_as if (ACPI_FAILURE(status)) { ACPI_EXCEPTION((AE_INFO, status, - "While evaluating GPE method [%4.4s]", + "while evaluating GPE method [%4.4s]", acpi_ut_get_node_name (local_gpe_event_info.dispatch. method_node))); @@ -618,6 +619,8 @@ acpi_ev_gpe_dispatch(struct acpi_gpe_eve ACPI_FUNCTION_TRACE(ev_gpe_dispatch); + acpi_gpe_count++; + /* * If edge-triggered, clear the GPE status bit now. Note that * level-triggered events are cleared after the GPE is serviced. @@ -633,20 +636,23 @@ acpi_ev_gpe_dispatch(struct acpi_gpe_eve } } - /* Save current system state */ - - if (acpi_gbl_system_awake_and_running) { - ACPI_SET_BIT(gpe_event_info->flags, ACPI_GPE_SYSTEM_RUNNING); - } else { - ACPI_CLEAR_BIT(gpe_event_info->flags, ACPI_GPE_SYSTEM_RUNNING); + if (!acpi_gbl_system_awake_and_running) { + /* + * We just woke up because of a wake GPE. Disable any further GPEs + * until we are fully up and running (Only wake GPEs should be enabled + * at this time, but we just brute-force disable them all.) + * 1) We must disable this particular wake GPE so it won't fire again + * 2) We want to disable all wake GPEs, since we are now awake + */ + (void)acpi_hw_disable_all_gpes(); } /* - * Dispatch the GPE to either an installed handler, or the control - * method associated with this GPE (_Lxx or _Exx). - * If a handler exists, we invoke it and do not attempt to run the method. - * If there is neither a handler nor a method, we disable the level to - * prevent further events from coming in here. + * Dispatch the GPE to either an installed handler, or the control method + * associated with this GPE (_Lxx or _Exx). If a handler exists, we invoke + * it and do not attempt to run the method. If there is neither a handler + * nor a method, we disable this GPE to prevent further such pointless + * events from firing. */ switch (gpe_event_info->flags & ACPI_GPE_DISPATCH_MASK) { case ACPI_GPE_DISPATCH_HANDLER: @@ -677,8 +683,8 @@ acpi_ev_gpe_dispatch(struct acpi_gpe_eve case ACPI_GPE_DISPATCH_METHOD: /* - * Disable GPE, so it doesn't keep firing before the method has a - * chance to run. + * Disable the GPE, so it doesn't keep firing before the method has a + * chance to run (it runs asynchronously with interrupts enabled). */ status = acpi_ev_disable_gpe(gpe_event_info); if (ACPI_FAILURE(status)) { @@ -711,7 +717,7 @@ acpi_ev_gpe_dispatch(struct acpi_gpe_eve gpe_number)); /* - * Disable the GPE. The GPE will remain disabled until the ACPI + * Disable the GPE. The GPE will remain disabled until the ACPI * Core Subsystem is restarted, or a handler is installed. */ status = acpi_ev_disable_gpe(gpe_event_info); @@ -726,50 +732,3 @@ acpi_ev_gpe_dispatch(struct acpi_gpe_eve return_UINT32(ACPI_INTERRUPT_HANDLED); } - -#ifdef ACPI_GPE_NOTIFY_CHECK -/******************************************************************************* - * TBD: NOT USED, PROTOTYPE ONLY AND WILL PROBABLY BE REMOVED - * - * FUNCTION: acpi_ev_check_for_wake_only_gpe - * - * PARAMETERS: gpe_event_info - info for this GPE - * - * RETURN: Status - * - * DESCRIPTION: Determine if a a GPE is "wake-only". - * - * Called from Notify() code in interpreter when a "DeviceWake" - * Notify comes in. - * - ******************************************************************************/ - -acpi_status -acpi_ev_check_for_wake_only_gpe(struct acpi_gpe_event_info *gpe_event_info) -{ - acpi_status status; - - ACPI_FUNCTION_TRACE(ev_check_for_wake_only_gpe); - - if ((gpe_event_info) && /* Only >0 for _Lxx/_Exx */ - ((gpe_event_info->flags & ACPI_GPE_SYSTEM_MASK) == ACPI_GPE_SYSTEM_RUNNING)) { /* System state at GPE time */ - /* This must be a wake-only GPE, disable it */ - - status = acpi_ev_disable_gpe(gpe_event_info); - - /* Set GPE to wake-only. Do not change wake disabled/enabled status */ - - acpi_ev_set_gpe_type(gpe_event_info, ACPI_GPE_TYPE_WAKE); - - ACPI_INFO((AE_INFO, - "GPE %p was updated from wake/run to wake-only", - gpe_event_info)); - - /* This was a wake-only GPE */ - - return_ACPI_STATUS(AE_WAKE_ONLY_GPE); - } - - return_ACPI_STATUS(AE_OK); -} -#endif diff --git a/drivers/acpi/events/evgpeblk.c b/drivers/acpi/events/evgpeblk.c index 95ddeb4..ad5bc76 100644 --- a/drivers/acpi/events/evgpeblk.c +++ b/drivers/acpi/events/evgpeblk.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2006, R. Byron Moore + * Copyright (C) 2000 - 2007, R. Byron Moore * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -529,7 +529,7 @@ static struct acpi_gpe_xrupt_info *acpi_ /* Install new interrupt handler if not SCI_INT */ - if (interrupt_number != acpi_gbl_FADT->sci_int) { + if (interrupt_number != acpi_gbl_FADT.sci_interrupt) { status = acpi_os_install_interrupt_handler(interrupt_number, acpi_ev_gpe_xrupt_handler, gpe_xrupt); @@ -567,7 +567,7 @@ acpi_ev_delete_gpe_xrupt(struct acpi_gpe /* We never want to remove the SCI interrupt handler */ - if (gpe_xrupt->interrupt_number == acpi_gbl_FADT->sci_int) { + if (gpe_xrupt->interrupt_number == acpi_gbl_FADT.sci_interrupt) { gpe_xrupt->gpe_block_list_head = NULL; return_ACPI_STATUS(AE_OK); } @@ -796,30 +796,31 @@ acpi_ev_create_gpe_info_blocks(struct ac (u8) (gpe_block->block_base_number + (i * ACPI_GPE_REGISTER_WIDTH)); - ACPI_STORE_ADDRESS(this_register->status_address.address, - (gpe_block->block_address.address + i)); + this_register->status_address.address = + gpe_block->block_address.address + i; - ACPI_STORE_ADDRESS(this_register->enable_address.address, - (gpe_block->block_address.address - + i + gpe_block->register_count)); + this_register->enable_address.address = + gpe_block->block_address.address + i + + gpe_block->register_count; - this_register->status_address.address_space_id = - gpe_block->block_address.address_space_id; - this_register->enable_address.address_space_id = - gpe_block->block_address.address_space_id; - this_register->status_address.register_bit_width = + this_register->status_address.space_id = + gpe_block->block_address.space_id; + this_register->enable_address.space_id = + gpe_block->block_address.space_id; + this_register->status_address.bit_width = ACPI_GPE_REGISTER_WIDTH; - this_register->enable_address.register_bit_width = + this_register->enable_address.bit_width = ACPI_GPE_REGISTER_WIDTH; - this_register->status_address.register_bit_offset = + this_register->status_address.bit_offset = ACPI_GPE_REGISTER_WIDTH; - this_register->enable_address.register_bit_offset = + this_register->enable_address.bit_offset = ACPI_GPE_REGISTER_WIDTH; /* Init the event_info for each GPE within this register */ for (j = 0; j < ACPI_GPE_REGISTER_WIDTH; j++) { - this_event->register_bit = acpi_gbl_decode_to8bit[j]; + this_event->gpe_number = + (u8) (this_register->base_gpe_number + j); this_event->register_info = this_register; this_event++; } @@ -1109,11 +1110,12 @@ acpi_status acpi_ev_gpe_initialize(void) * If EITHER the register length OR the block address are zero, then that * particular block is not supported. */ - if (acpi_gbl_FADT->gpe0_blk_len && acpi_gbl_FADT->xgpe0_blk.address) { + if (acpi_gbl_FADT.gpe0_block_length && + acpi_gbl_FADT.xgpe0_block.address) { /* GPE block 0 exists (has both length and address > 0) */ - register_count0 = (u16) (acpi_gbl_FADT->gpe0_blk_len / 2); + register_count0 = (u16) (acpi_gbl_FADT.gpe0_block_length / 2); gpe_number_max = (register_count0 * ACPI_GPE_REGISTER_WIDTH) - 1; @@ -1121,9 +1123,9 @@ acpi_status acpi_ev_gpe_initialize(void) /* Install GPE Block 0 */ status = acpi_ev_create_gpe_block(acpi_gbl_fadt_gpe_device, - &acpi_gbl_FADT->xgpe0_blk, + &acpi_gbl_FADT.xgpe0_block, register_count0, 0, - acpi_gbl_FADT->sci_int, + acpi_gbl_FADT.sci_interrupt, &acpi_gbl_gpe_fadt_blocks[0]); if (ACPI_FAILURE(status)) { @@ -1132,20 +1134,21 @@ acpi_status acpi_ev_gpe_initialize(void) } } - if (acpi_gbl_FADT->gpe1_blk_len && acpi_gbl_FADT->xgpe1_blk.address) { + if (acpi_gbl_FADT.gpe1_block_length && + acpi_gbl_FADT.xgpe1_block.address) { /* GPE block 1 exists (has both length and address > 0) */ - register_count1 = (u16) (acpi_gbl_FADT->gpe1_blk_len / 2); + register_count1 = (u16) (acpi_gbl_FADT.gpe1_block_length / 2); /* Check for GPE0/GPE1 overlap (if both banks exist) */ if ((register_count0) && - (gpe_number_max >= acpi_gbl_FADT->gpe1_base)) { + (gpe_number_max >= acpi_gbl_FADT.gpe1_base)) { ACPI_ERROR((AE_INFO, "GPE0 block (GPE 0 to %d) overlaps the GPE1 block (GPE %d to %d) - Ignoring GPE1", - gpe_number_max, acpi_gbl_FADT->gpe1_base, - acpi_gbl_FADT->gpe1_base + + gpe_number_max, acpi_gbl_FADT.gpe1_base, + acpi_gbl_FADT.gpe1_base + ((register_count1 * ACPI_GPE_REGISTER_WIDTH) - 1))); @@ -1157,10 +1160,11 @@ acpi_status acpi_ev_gpe_initialize(void) status = acpi_ev_create_gpe_block(acpi_gbl_fadt_gpe_device, - &acpi_gbl_FADT->xgpe1_blk, + &acpi_gbl_FADT.xgpe1_block, register_count1, - acpi_gbl_FADT->gpe1_base, - acpi_gbl_FADT->sci_int, + acpi_gbl_FADT.gpe1_base, + acpi_gbl_FADT. + sci_interrupt, &acpi_gbl_gpe_fadt_blocks [1]); @@ -1173,7 +1177,7 @@ acpi_status acpi_ev_gpe_initialize(void) * GPE0 and GPE1 do not have to be contiguous in the GPE number * space. However, GPE0 always starts at GPE number zero. */ - gpe_number_max = acpi_gbl_FADT->gpe1_base + + gpe_number_max = acpi_gbl_FADT.gpe1_base + ((register_count1 * ACPI_GPE_REGISTER_WIDTH) - 1); } } diff --git a/drivers/acpi/events/evmisc.c b/drivers/acpi/events/evmisc.c index bf63edc..1b784ff 100644 --- a/drivers/acpi/events/evmisc.c +++ b/drivers/acpi/events/evmisc.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2006, R. Byron Moore + * Copyright (C) 2000 - 2007, R. Byron Moore * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -63,14 +63,18 @@ static const char *acpi_notify_value_nam }; #endif +/* Pointer to FACS needed for the Global Lock */ + +static struct acpi_table_facs *facs = NULL; + /* Local prototypes */ static void ACPI_SYSTEM_XFACE acpi_ev_notify_dispatch(void *context); -static void ACPI_SYSTEM_XFACE acpi_ev_global_lock_thread(void *context); - static u32 acpi_ev_global_lock_handler(void *context); +static acpi_status acpi_ev_remove_global_lock_handler(void); + /******************************************************************************* * * FUNCTION: acpi_ev_is_notify_object @@ -282,49 +286,19 @@ static void ACPI_SYSTEM_XFACE acpi_ev_no /******************************************************************************* * - * FUNCTION: acpi_ev_global_lock_thread - * - * PARAMETERS: Context - From thread interface, not used - * - * RETURN: None - * - * DESCRIPTION: Invoked by SCI interrupt handler upon acquisition of the - * Global Lock. Simply signal all threads that are waiting - * for the lock. - * - ******************************************************************************/ - -static void ACPI_SYSTEM_XFACE acpi_ev_global_lock_thread(void *context) -{ - acpi_status status; - - /* Signal threads that are waiting for the lock */ - - if (acpi_gbl_global_lock_thread_count) { - - /* Send sufficient units to the semaphore */ - - status = - acpi_os_signal_semaphore(acpi_gbl_global_lock_semaphore, - acpi_gbl_global_lock_thread_count); - if (ACPI_FAILURE(status)) { - ACPI_ERROR((AE_INFO, - "Could not signal Global Lock semaphore")); - } - } -} - -/******************************************************************************* - * * FUNCTION: acpi_ev_global_lock_handler * * PARAMETERS: Context - From thread interface, not used * - * RETURN: ACPI_INTERRUPT_HANDLED or ACPI_INTERRUPT_NOT_HANDLED + * RETURN: ACPI_INTERRUPT_HANDLED * * DESCRIPTION: Invoked directly from the SCI handler when a global lock - * release interrupt occurs. Grab the global lock and queue - * the global lock thread for execution + * release interrupt occurs. Attempt to acquire the global lock, + * if successful, signal the thread waiting for the lock. + * + * NOTE: Assumes that the semaphore can be signaled from interrupt level. If + * this is not possible for some reason, a separate thread will have to be + * scheduled to do this. * ******************************************************************************/ @@ -333,16 +307,24 @@ static u32 acpi_ev_global_lock_handler(v u8 acquired = FALSE; /* - * Attempt to get the lock + * Attempt to get the lock. + * * If we don't get it now, it will be marked pending and we will * take another interrupt when it becomes free. */ - ACPI_ACQUIRE_GLOBAL_LOCK(acpi_gbl_common_fACS.global_lock, acquired); + ACPI_ACQUIRE_GLOBAL_LOCK(facs, acquired); if (acquired) { /* Got the lock, now wake all threads waiting for it */ + acpi_gbl_global_lock_acquired = TRUE; - acpi_ev_global_lock_thread(context); + /* Send a unit to the semaphore */ + + if (ACPI_FAILURE(acpi_os_signal_semaphore( + acpi_gbl_global_lock_semaphore, 1))) { + ACPI_ERROR((AE_INFO, + "Could not signal Global Lock semaphore")); + } } return (ACPI_INTERRUPT_HANDLED); @@ -366,6 +348,13 @@ acpi_status acpi_ev_init_global_lock_han ACPI_FUNCTION_TRACE(ev_init_global_lock_handler); + status = + acpi_get_table_by_index(ACPI_TABLE_INDEX_FACS, + (struct acpi_table_header **)&facs); + if (ACPI_FAILURE(status)) { + return_ACPI_STATUS(status); + } + acpi_gbl_global_lock_present = TRUE; status = acpi_install_fixed_event_handler(ACPI_EVENT_GLOBAL, acpi_ev_global_lock_handler, @@ -389,6 +378,31 @@ acpi_status acpi_ev_init_global_lock_han return_ACPI_STATUS(status); } +/******************************************************************************* + * + * FUNCTION: acpi_ev_remove_global_lock_handler + * + * PARAMETERS: None + * + * RETURN: Status + * + * DESCRIPTION: Remove the handler for the Global Lock + * + ******************************************************************************/ + +static acpi_status acpi_ev_remove_global_lock_handler(void) +{ + acpi_status status; + + ACPI_FUNCTION_TRACE(ev_remove_global_lock_handler); + + acpi_gbl_global_lock_present = FALSE; + status = acpi_remove_fixed_event_handler(ACPI_EVENT_GLOBAL, + acpi_ev_global_lock_handler); + + return_ACPI_STATUS(status); +} + /****************************************************************************** * * FUNCTION: acpi_ev_acquire_global_lock @@ -399,6 +413,16 @@ acpi_status acpi_ev_init_global_lock_han * * DESCRIPTION: Attempt to gain ownership of the Global Lock. * + * MUTEX: Interpreter must be locked + * + * Note: The original implementation allowed multiple threads to "acquire" the + * Global Lock, and the OS would hold the lock until the last thread had + * released it. However, this could potentially starve the BIOS out of the + * lock, especially in the case where there is a tight handshake between the + * Embedded Controller driver and the BIOS. Therefore, this implementation + * allows only one thread to acquire the HW Global Lock at a time, and makes + * the global lock appear as a standard mutex on the OS side. + * *****************************************************************************/ acpi_status acpi_ev_acquire_global_lock(u16 timeout) @@ -408,53 +432,51 @@ acpi_status acpi_ev_acquire_global_lock( ACPI_FUNCTION_TRACE(ev_acquire_global_lock); -#ifndef ACPI_APPLICATION - /* Make sure that we actually have a global lock */ - - if (!acpi_gbl_global_lock_present) { - return_ACPI_STATUS(AE_NO_GLOBAL_LOCK); + /* + * Only one thread can acquire the GL at a time, the global_lock_mutex + * enforces this. This interface releases the interpreter if we must wait. + */ + status = acpi_ex_system_wait_mutex(acpi_gbl_global_lock_mutex, timeout); + if (ACPI_FAILURE(status)) { + return_ACPI_STATUS(status); } -#endif - - /* One more thread wants the global lock */ - - acpi_gbl_global_lock_thread_count++; /* - * If we (OS side vs. BIOS side) have the hardware lock already, - * we are done + * Make sure that a global lock actually exists. If not, just treat + * the lock as a standard mutex. */ - if (acpi_gbl_global_lock_acquired) { + if (!acpi_gbl_global_lock_present) { + acpi_gbl_global_lock_acquired = TRUE; return_ACPI_STATUS(AE_OK); } - /* We must acquire the actual hardware lock */ + /* Attempt to acquire the actual hardware lock */ - ACPI_ACQUIRE_GLOBAL_LOCK(acpi_gbl_common_fACS.global_lock, acquired); + ACPI_ACQUIRE_GLOBAL_LOCK(facs, acquired); if (acquired) { /* We got the lock */ ACPI_DEBUG_PRINT((ACPI_DB_EXEC, - "Acquired the HW Global Lock\n")); + "Acquired hardware Global Lock\n")); acpi_gbl_global_lock_acquired = TRUE; return_ACPI_STATUS(AE_OK); } /* - * Did not get the lock. The pending bit was set above, and we must now + * Did not get the lock. The pending bit was set above, and we must now * wait until we get the global lock released interrupt. */ - ACPI_DEBUG_PRINT((ACPI_DB_EXEC, "Waiting for the HW Global Lock\n")); + ACPI_DEBUG_PRINT((ACPI_DB_EXEC, "Waiting for hardware Global Lock\n")); /* - * Acquire the global lock semaphore first. - * Since this wait will block, we must release the interpreter + * Wait for handshake with the global lock interrupt handler. + * This interface releases the interpreter if we must wait. */ - status = - acpi_ex_system_wait_semaphore(acpi_gbl_global_lock_semaphore, - timeout); + status = acpi_ex_system_wait_semaphore(acpi_gbl_global_lock_semaphore, + ACPI_WAIT_FOREVER); + return_ACPI_STATUS(status); } @@ -477,38 +499,39 @@ acpi_status acpi_ev_release_global_lock( ACPI_FUNCTION_TRACE(ev_release_global_lock); - if (!acpi_gbl_global_lock_thread_count) { + /* Lock must be already acquired */ + + if (!acpi_gbl_global_lock_acquired) { ACPI_WARNING((AE_INFO, - "Cannot release HW Global Lock, it has not been acquired")); + "Cannot release the ACPI Global Lock, it has not been acquired")); return_ACPI_STATUS(AE_NOT_ACQUIRED); } - /* One fewer thread has the global lock */ + if (acpi_gbl_global_lock_present) { - acpi_gbl_global_lock_thread_count--; - if (acpi_gbl_global_lock_thread_count) { + /* Allow any thread to release the lock */ - /* There are still some threads holding the lock, cannot release */ + ACPI_RELEASE_GLOBAL_LOCK(facs, pending); - return_ACPI_STATUS(AE_OK); + /* + * If the pending bit was set, we must write GBL_RLS to the control + * register + */ + if (pending) { + status = + acpi_set_register(ACPI_BITREG_GLOBAL_LOCK_RELEASE, + 1); + } + + ACPI_DEBUG_PRINT((ACPI_DB_EXEC, + "Released hardware Global Lock\n")); } - /* - * No more threads holding lock, we can do the actual hardware - * release - */ - ACPI_RELEASE_GLOBAL_LOCK(acpi_gbl_common_fACS.global_lock, pending); acpi_gbl_global_lock_acquired = FALSE; - /* - * If the pending bit was set, we must write GBL_RLS to the control - * register - */ - if (pending) { - status = acpi_set_register(ACPI_BITREG_GLOBAL_LOCK_RELEASE, - 1, ACPI_MTX_LOCK); - } + /* Release the local GL mutex */ + acpi_os_release_mutex(acpi_gbl_global_lock_mutex); return_ACPI_STATUS(status); } @@ -558,6 +581,12 @@ void acpi_ev_terminate(void) if (ACPI_FAILURE(status)) { ACPI_ERROR((AE_INFO, "Could not remove SCI handler")); } + + status = acpi_ev_remove_global_lock_handler(); + if (ACPI_FAILURE(status)) { + ACPI_ERROR((AE_INFO, + "Could not remove Global Lock handler")); + } } /* Deallocate all handler objects installed within GPE info structs */ diff --git a/drivers/acpi/events/evregion.c b/drivers/acpi/events/evregion.c index 21caae0..e99f0c4 100644 --- a/drivers/acpi/events/evregion.c +++ b/drivers/acpi/events/evregion.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2006, R. Byron Moore + * Copyright (C) 2000 - 2007, R. Byron Moore * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -291,7 +291,6 @@ acpi_ev_address_space_dispatch(union acp u32 bit_width, acpi_integer * value) { acpi_status status; - acpi_status status2; acpi_adr_space_handler handler; acpi_adr_space_setup region_setup; union acpi_operand_object *handler_desc; @@ -345,7 +344,7 @@ acpi_ev_address_space_dispatch(union acp * setup will potentially execute control methods * (e.g., _REG method for this region) */ - acpi_ex_exit_interpreter(); + acpi_ex_relinquish_interpreter(); status = region_setup(region_obj, ACPI_REGION_ACTIVATE, handler_desc->address_space.context, @@ -353,10 +352,7 @@ acpi_ev_address_space_dispatch(union acp /* Re-enter the interpreter */ - status2 = acpi_ex_enter_interpreter(); - if (ACPI_FAILURE(status2)) { - return_ACPI_STATUS(status2); - } + acpi_ex_reacquire_interpreter(); /* Check for failure of the Region Setup */ @@ -409,7 +405,7 @@ acpi_ev_address_space_dispatch(union acp * exit the interpreter because the handler *might* block -- we don't * know what it will do, so we can't hold the lock on the intepreter. */ - acpi_ex_exit_interpreter(); + acpi_ex_relinquish_interpreter(); } /* Call the handler */ @@ -430,10 +426,7 @@ acpi_ev_address_space_dispatch(union acp * We just returned from a non-default handler, we must re-enter the * interpreter */ - status2 = acpi_ex_enter_interpreter(); - if (ACPI_FAILURE(status2)) { - return_ACPI_STATUS(status2); - } + acpi_ex_reacquire_interpreter(); } return_ACPI_STATUS(status); diff --git a/drivers/acpi/events/evrgnini.c b/drivers/acpi/events/evrgnini.c index 203d135..a4fa7e6 100644 --- a/drivers/acpi/events/evrgnini.c +++ b/drivers/acpi/events/evrgnini.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2006, R. Byron Moore + * Copyright (C) 2000 - 2007, R. Byron Moore * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -48,6 +48,11 @@ #include #define _COMPONENT ACPI_EVENTS ACPI_MODULE_NAME("evrgnini") +/* Local prototypes */ +static u8 acpi_ev_match_pci_root_bridge(char *id); + +static u8 acpi_ev_is_pci_root_bridge(struct acpi_namespace_node *node); + /******************************************************************************* * * FUNCTION: acpi_ev_system_memory_region_setup @@ -62,6 +67,7 @@ ACPI_MODULE_NAME("evrgnini") * DESCRIPTION: Setup a system_memory operation region * ******************************************************************************/ + acpi_status acpi_ev_system_memory_region_setup(acpi_handle handle, u32 function, @@ -168,9 +174,9 @@ acpi_ev_pci_config_region_setup(acpi_han union acpi_operand_object *handler_obj; struct acpi_namespace_node *parent_node; struct acpi_namespace_node *pci_root_node; + struct acpi_namespace_node *pci_device_node; union acpi_operand_object *region_obj = (union acpi_operand_object *)handle; - struct acpi_device_id object_hID; ACPI_FUNCTION_TRACE(ev_pci_config_region_setup); @@ -215,45 +221,30 @@ acpi_ev_pci_config_region_setup(acpi_han pci_root_node = parent_node; while (pci_root_node != acpi_gbl_root_node) { - status = - acpi_ut_execute_HID(pci_root_node, &object_hID); - if (ACPI_SUCCESS(status)) { - /* - * Got a valid _HID string, check if this is a PCI root. - * New for ACPI 3.0: check for a PCI Express root also. - */ - if (! - (ACPI_STRNCMP - (object_hID.value, PCI_ROOT_HID_STRING, - sizeof(PCI_ROOT_HID_STRING))) - || - !(ACPI_STRNCMP - (object_hID.value, - PCI_EXPRESS_ROOT_HID_STRING, - sizeof(PCI_EXPRESS_ROOT_HID_STRING)))) { - - /* Install a handler for this PCI root bridge */ - status = - acpi_install_address_space_handler((acpi_handle) pci_root_node, ACPI_ADR_SPACE_PCI_CONFIG, ACPI_DEFAULT_HANDLER, NULL, NULL); - if (ACPI_FAILURE(status)) { - if (status == AE_SAME_HANDLER) { - /* - * It is OK if the handler is already installed on the root - * bridge. Still need to return a context object for the - * new PCI_Config operation region, however. - */ - status = AE_OK; - } else { - ACPI_EXCEPTION((AE_INFO, - status, - "Could not install PciConfig handler for Root Bridge %4.4s", - acpi_ut_get_node_name - (pci_root_node))); - } + /* Get the _HID/_CID in order to detect a root_bridge */ + + if (acpi_ev_is_pci_root_bridge(pci_root_node)) { + + /* Install a handler for this PCI root bridge */ + + status = acpi_install_address_space_handler((acpi_handle) pci_root_node, ACPI_ADR_SPACE_PCI_CONFIG, ACPI_DEFAULT_HANDLER, NULL, NULL); + if (ACPI_FAILURE(status)) { + if (status == AE_SAME_HANDLER) { + /* + * It is OK if the handler is already installed on the root + * bridge. Still need to return a context object for the + * new PCI_Config operation region, however. + */ + status = AE_OK; + } else { + ACPI_EXCEPTION((AE_INFO, status, + "Could not install PciConfig handler for Root Bridge %4.4s", + acpi_ut_get_node_name + (pci_root_node))); } - break; } + break; } pci_root_node = acpi_ns_get_parent_node(pci_root_node); @@ -282,14 +273,25 @@ acpi_ev_pci_config_region_setup(acpi_han /* * For PCI_Config space access, we need the segment, bus, * device and function numbers. Acquire them here. + * + * Find the parent device object. (This allows the operation region to be + * within a subscope under the device, such as a control method.) */ + pci_device_node = region_obj->region.node; + while (pci_device_node && (pci_device_node->type != ACPI_TYPE_DEVICE)) { + pci_device_node = acpi_ns_get_parent_node(pci_device_node); + } + + if (!pci_device_node) { + return_ACPI_STATUS(AE_AML_OPERAND_TYPE); + } /* * Get the PCI device and function numbers from the _ADR object * contained in the parent's scope. */ status = - acpi_ut_evaluate_numeric_object(METHOD_NAME__ADR, parent_node, + acpi_ut_evaluate_numeric_object(METHOD_NAME__ADR, pci_device_node, &pci_value); /* @@ -329,6 +331,91 @@ acpi_ev_pci_config_region_setup(acpi_han /******************************************************************************* * + * FUNCTION: acpi_ev_match_pci_root_bridge + * + * PARAMETERS: Id - The HID/CID in string format + * + * RETURN: TRUE if the Id is a match for a PCI/PCI-Express Root Bridge + * + * DESCRIPTION: Determine if the input ID is a PCI Root Bridge ID. + * + ******************************************************************************/ + +static u8 acpi_ev_match_pci_root_bridge(char *id) +{ + + /* + * Check if this is a PCI root. + * ACPI 3.0+: check for a PCI Express root also. + */ + if (!(ACPI_STRNCMP(id, + PCI_ROOT_HID_STRING, + sizeof(PCI_ROOT_HID_STRING))) || + !(ACPI_STRNCMP(id, + PCI_EXPRESS_ROOT_HID_STRING, + sizeof(PCI_EXPRESS_ROOT_HID_STRING)))) { + return (TRUE); + } + + return (FALSE); +} + +/******************************************************************************* + * + * FUNCTION: acpi_ev_is_pci_root_bridge + * + * PARAMETERS: Node - Device node being examined + * + * RETURN: TRUE if device is a PCI/PCI-Express Root Bridge + * + * DESCRIPTION: Determine if the input device represents a PCI Root Bridge by + * examining the _HID and _CID for the device. + * + ******************************************************************************/ + +static u8 acpi_ev_is_pci_root_bridge(struct acpi_namespace_node *node) +{ + acpi_status status; + struct acpi_device_id hid; + struct acpi_compatible_id_list *cid; + acpi_native_uint i; + + /* + * Get the _HID and check for a PCI Root Bridge + */ + status = acpi_ut_execute_HID(node, &hid); + if (ACPI_FAILURE(status)) { + return (FALSE); + } + + if (acpi_ev_match_pci_root_bridge(hid.value)) { + return (TRUE); + } + + /* + * The _HID did not match. + * Get the _CID and check for a PCI Root Bridge + */ + status = acpi_ut_execute_CID(node, &cid); + if (ACPI_FAILURE(status)) { + return (FALSE); + } + + /* Check all _CIDs in the returned list */ + + for (i = 0; i < cid->count; i++) { + if (acpi_ev_match_pci_root_bridge(cid->id[i].value)) { + ACPI_FREE(cid); + return (TRUE); + } + } + + ACPI_FREE(cid); + return (FALSE); +} + +/******************************************************************************* + * * FUNCTION: acpi_ev_pci_bar_region_setup * * PARAMETERS: Handle - Region we are interested in @@ -432,6 +519,9 @@ acpi_ev_default_region_setup(acpi_handle * a PCI address in the scope of the definition. This address is * required to perform an access to PCI config space. * + * MUTEX: Interpreter should be unlocked, because we may run the _REG + * method for this region. + * ******************************************************************************/ acpi_status diff --git a/drivers/acpi/events/evsci.c b/drivers/acpi/events/evsci.c index 8106215..7e5d15c 100644 --- a/drivers/acpi/events/evsci.c +++ b/drivers/acpi/events/evsci.c @@ -6,7 +6,7 @@ ******************************************************************************/ /* - * Copyright (C) 2000 - 2006, R. Byron Moore + * Copyright (C) 2000 - 2007, R. Byron Moore * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -142,9 +142,10 @@ u32 acpi_ev_install_sci_handler(void) ACPI_FUNCTION_TRACE(ev_install_sci_handler); - status = acpi_os_install_interrupt_handler((u32) acpi_gbl_FADT->sci_int, - acpi_ev_sci_xrupt_handler, - acpi_gbl_gpe_xrupt_list_head); + status = + acpi_os_install_interrupt_handler((u32) acpi_gbl_FADT.sci_interrupt, + acpi_ev_sci_xrupt_handler, + acpi_gbl_gpe_xrupt_list_head); return_ACPI_STATUS(status); } @@ -175,8 +176,9 @@ acpi_status acpi_ev_remove_sci_handler(v /* Just let the OS remove the handler and disable the level */ - status = acpi_os_remove_interrupt_handler((u32) acpi_gbl_FADT->sci_int, - acpi_ev_sci_xrupt_handler); + status = + acpi_os_remove_interrupt_handler((u32) acpi_gbl_FADT.sci_interrupt, + acpi_ev_sci_xrupt_handler); return_ACPI_STATUS(status); } diff --git a/drivers/acpi/events/evxface.c b/drivers/acpi/events/evxface.c index 923fd2b..685a103 100644 --- a/drivers/acpi/events/evxface.c +++ b/drivers/acpi/events/evxface.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2006, R. Byron Moore + * Copyright (C) 2000 - 2007, R. Byron Moore * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -768,11 +768,9 @@ acpi_status acpi_acquire_global_lock(u16 return (AE_BAD_PARAMETER); } - status = acpi_ex_enter_interpreter(); - if (ACPI_FAILURE(status)) { - return (status); - } + /* Must lock interpreter to prevent race conditions */ + acpi_ex_enter_interpreter(); status = acpi_ev_acquire_global_lock(timeout); acpi_ex_exit_interpreter(); diff --git a/drivers/acpi/events/evxfevnt.c b/drivers/acpi/events/evxfevnt.c index 7ebc2ef..17065e9 100644 --- a/drivers/acpi/events/evxfevnt.c +++ b/drivers/acpi/events/evxfevnt.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2006, R. Byron Moore + * Copyright (C) 2000 - 2007, R. Byron Moore * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -44,6 +44,7 @@ #include #include #include +#include #define _COMPONENT ACPI_EVENTS ACPI_MODULE_NAME("evxfevnt") @@ -65,13 +66,14 @@ acpi_status acpi_enable(void) ACPI_FUNCTION_TRACE(acpi_enable); - /* Make sure we have the FADT */ + /* ACPI tables must be present */ - if (!acpi_gbl_FADT) { - ACPI_WARNING((AE_INFO, "No FADT information present!")); + if (!acpi_tb_tables_loaded()) { return_ACPI_STATUS(AE_NO_ACPI_TABLES); } + /* Check current mode */ + if (acpi_hw_get_mode() == ACPI_SYS_MODE_ACPI) { ACPI_DEBUG_PRINT((ACPI_DB_INIT, "System is already in ACPI mode\n")); @@ -111,11 +113,6 @@ acpi_status acpi_disable(void) ACPI_FUNCTION_TRACE(acpi_disable); - if (!acpi_gbl_FADT) { - ACPI_WARNING((AE_INFO, "No FADT information present!")); - return_ACPI_STATUS(AE_NO_ACPI_TABLES); - } - if (acpi_hw_get_mode() == ACPI_SYS_MODE_LEGACY) { ACPI_DEBUG_PRINT((ACPI_DB_INIT, "System is already in legacy (non-ACPI) mode\n")); @@ -169,7 +166,7 @@ acpi_status acpi_enable_event(u32 event, */ status = acpi_set_register(acpi_gbl_fixed_event_info[event]. - enable_register_id, 1, ACPI_MTX_LOCK); + enable_register_id, 1); if (ACPI_FAILURE(status)) { return_ACPI_STATUS(status); } @@ -178,7 +175,7 @@ acpi_status acpi_enable_event(u32 event, status = acpi_get_register(acpi_gbl_fixed_event_info[event]. - enable_register_id, &value, ACPI_MTX_LOCK); + enable_register_id, &value); if (ACPI_FAILURE(status)) { return_ACPI_STATUS(status); } @@ -368,14 +365,14 @@ acpi_status acpi_disable_event(u32 event */ status = acpi_set_register(acpi_gbl_fixed_event_info[event]. - enable_register_id, 0, ACPI_MTX_LOCK); + enable_register_id, 0); if (ACPI_FAILURE(status)) { return_ACPI_STATUS(status); } status = acpi_get_register(acpi_gbl_fixed_event_info[event]. - enable_register_id, &value, ACPI_MTX_LOCK); + enable_register_id, &value); if (ACPI_FAILURE(status)) { return_ACPI_STATUS(status); } @@ -421,7 +418,7 @@ acpi_status acpi_clear_event(u32 event) */ status = acpi_set_register(acpi_gbl_fixed_event_info[event]. - status_register_id, 1, ACPI_MTX_LOCK); + status_register_id, 1); return_ACPI_STATUS(status); } @@ -510,7 +507,7 @@ acpi_status acpi_get_event_status(u32 ev status = acpi_get_register(acpi_gbl_fixed_event_info[event]. - status_register_id, event_status, ACPI_MTX_LOCK); + status_register_id, event_status); return_ACPI_STATUS(status); } diff --git a/drivers/acpi/events/evxfregn.c b/drivers/acpi/events/evxfregn.c index 83b12a9..7bf09c5 100644 --- a/drivers/acpi/events/evxfregn.c +++ b/drivers/acpi/events/evxfregn.c @@ -6,7 +6,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2006, R. Byron Moore + * Copyright (C) 2000 - 2007, R. Byron Moore * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/executer/exconfig.c b/drivers/acpi/executer/exconfig.c index c8341fa..25802f3 100644 --- a/drivers/acpi/executer/exconfig.c +++ b/drivers/acpi/executer/exconfig.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2006, R. Byron Moore + * Copyright (C) 2000 - 2007, R. Byron Moore * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -54,7 +54,7 @@ ACPI_MODULE_NAME("exconfig") /* Local prototypes */ static acpi_status -acpi_ex_add_table(struct acpi_table_header *table, +acpi_ex_add_table(acpi_native_uint table_index, struct acpi_namespace_node *parent_node, union acpi_operand_object **ddb_handle); @@ -74,12 +74,11 @@ acpi_ex_add_table(struct acpi_table_head ******************************************************************************/ static acpi_status -acpi_ex_add_table(struct acpi_table_header *table, +acpi_ex_add_table(acpi_native_uint table_index, struct acpi_namespace_node *parent_node, union acpi_operand_object **ddb_handle) { acpi_status status; - struct acpi_table_desc table_info; union acpi_operand_object *obj_desc; ACPI_FUNCTION_TRACE(ex_add_table); @@ -98,42 +97,16 @@ acpi_ex_add_table(struct acpi_table_head /* Install the new table into the local data structures */ - ACPI_MEMSET(&table_info, 0, sizeof(struct acpi_table_desc)); - - table_info.type = ACPI_TABLE_ID_SSDT; - table_info.pointer = table; - table_info.length = (acpi_size) table->length; - table_info.allocation = ACPI_MEM_ALLOCATED; - - status = acpi_tb_install_table(&table_info); - obj_desc->reference.object = table_info.installed_desc; - - if (ACPI_FAILURE(status)) { - if (status == AE_ALREADY_EXISTS) { - - /* Table already exists, just return the handle */ - - return_ACPI_STATUS(AE_OK); - } - goto cleanup; - } + obj_desc->reference.object = ACPI_CAST_PTR(void, table_index); /* Add the table to the namespace */ - status = acpi_ns_load_table(table_info.installed_desc, parent_node); + status = acpi_ns_load_table(table_index, parent_node); if (ACPI_FAILURE(status)) { - - /* Uninstall table on error */ - - (void)acpi_tb_uninstall_table(table_info.installed_desc); - goto cleanup; + acpi_ut_remove_reference(obj_desc); + *ddb_handle = NULL; } - return_ACPI_STATUS(AE_OK); - - cleanup: - acpi_ut_remove_reference(obj_desc); - *ddb_handle = NULL; return_ACPI_STATUS(status); } @@ -146,7 +119,7 @@ acpi_ex_add_table(struct acpi_table_head * * RETURN: Status * - * DESCRIPTION: Load an ACPI table + * DESCRIPTION: Load an ACPI table from the RSDT/XSDT * ******************************************************************************/ @@ -156,33 +129,20 @@ acpi_ex_load_table_op(struct acpi_walk_s { acpi_status status; union acpi_operand_object **operand = &walk_state->operands[0]; - struct acpi_table_header *table; + acpi_native_uint table_index; struct acpi_namespace_node *parent_node; struct acpi_namespace_node *start_node; struct acpi_namespace_node *parameter_node = NULL; union acpi_operand_object *ddb_handle; + struct acpi_table_header *table; ACPI_FUNCTION_TRACE(ex_load_table_op); -#if 0 - /* - * Make sure that the signature does not match one of the tables that - * is already loaded. - */ - status = acpi_tb_match_signature(operand[0]->string.pointer, NULL); - if (status == AE_OK) { - - /* Signature matched -- don't allow override */ - - return_ACPI_STATUS(AE_ALREADY_EXISTS); - } -#endif - - /* Find the ACPI table */ + /* Find the ACPI table in the RSDT/XSDT */ status = acpi_tb_find_table(operand[0]->string.pointer, operand[1]->string.pointer, - operand[2]->string.pointer, &table); + operand[2]->string.pointer, &table_index); if (ACPI_FAILURE(status)) { if (status != AE_NOT_FOUND) { return_ACPI_STATUS(status); @@ -245,7 +205,7 @@ #endif /* Load the table into the namespace */ - status = acpi_ex_add_table(table, parent_node, &ddb_handle); + status = acpi_ex_add_table(table_index, parent_node, &ddb_handle); if (ACPI_FAILURE(status)) { return_ACPI_STATUS(status); } @@ -266,9 +226,13 @@ #endif } } - ACPI_INFO((AE_INFO, - "Dynamic OEM Table Load - [%4.4s] OemId [%6.6s] OemTableId [%8.8s]", - table->signature, table->oem_id, table->oem_table_id)); + status = acpi_get_table_by_index(table_index, &table); + if (ACPI_SUCCESS(status)) { + ACPI_INFO((AE_INFO, + "Dynamic OEM Table Load - [%4.4s] OemId [%6.6s] OemTableId [%8.8s]", + table->signature, table->oem_id, + table->oem_table_id)); + } *return_desc = ddb_handle; return_ACPI_STATUS(status); @@ -278,7 +242,7 @@ #endif * * FUNCTION: acpi_ex_load_op * - * PARAMETERS: obj_desc - Region or Field where the table will be + * PARAMETERS: obj_desc - Region or Buffer/Field where the table will be * obtained * Target - Where a handle to the table will be stored * walk_state - Current state @@ -287,6 +251,12 @@ #endif * * DESCRIPTION: Load an ACPI table from a field or operation region * + * NOTE: Region Fields (Field, bank_field, index_fields) are resolved to buffer + * objects before this code is reached. + * + * If source is an operation region, it must refer to system_memory, as + * per the ACPI specification. + * ******************************************************************************/ acpi_status @@ -294,22 +264,26 @@ acpi_ex_load_op(union acpi_operand_objec union acpi_operand_object *target, struct acpi_walk_state *walk_state) { - acpi_status status; union acpi_operand_object *ddb_handle; - union acpi_operand_object *buffer_desc = NULL; - struct acpi_table_header *table_ptr = NULL; - acpi_physical_address address; - struct acpi_table_header table_header; - acpi_integer temp; - u32 i; + struct acpi_table_desc table_desc; + acpi_native_uint table_index; + acpi_status status; ACPI_FUNCTION_TRACE(ex_load_op); - /* Object can be either an op_region or a Field */ + ACPI_MEMSET(&table_desc, 0, sizeof(struct acpi_table_desc)); + + /* Source Object can be either an op_region or a Buffer/Field */ switch (ACPI_GET_OBJECT_TYPE(obj_desc)) { case ACPI_TYPE_REGION: + /* Region must be system_memory (from ACPI spec) */ + + if (obj_desc->region.space_id != ACPI_ADR_SPACE_SYSTEM_MEMORY) { + return_ACPI_STATUS(AE_AML_OPERAND_TYPE); + } + ACPI_DEBUG_PRINT((ACPI_DB_EXEC, "Load from Region %p %s\n", obj_desc, acpi_ut_get_object_type_name(obj_desc))); @@ -325,113 +299,41 @@ acpi_ex_load_op(union acpi_operand_objec } } - /* Get the base physical address of the region */ - - address = obj_desc->region.address; - - /* Get part of the table header to get the table length */ - - table_header.length = 0; - for (i = 0; i < 8; i++) { - status = - acpi_ev_address_space_dispatch(obj_desc, ACPI_READ, - (acpi_physical_address) - (i + address), 8, - &temp); - if (ACPI_FAILURE(status)) { - return_ACPI_STATUS(status); - } - - /* Get the one valid byte of the returned 64-bit value */ - - ACPI_CAST_PTR(u8, &table_header)[i] = (u8) temp; - } - - /* Sanity check the table length */ - - if (table_header.length < sizeof(struct acpi_table_header)) { - return_ACPI_STATUS(AE_BAD_HEADER); - } - - /* Allocate a buffer for the entire table */ - - table_ptr = ACPI_ALLOCATE(table_header.length); - if (!table_ptr) { - return_ACPI_STATUS(AE_NO_MEMORY); - } - - /* Get the entire table from the op region */ - - for (i = 0; i < table_header.length; i++) { - status = - acpi_ev_address_space_dispatch(obj_desc, ACPI_READ, - (acpi_physical_address) - (i + address), 8, - &temp); - if (ACPI_FAILURE(status)) { - goto cleanup; - } - - /* Get the one valid byte of the returned 64-bit value */ - - ACPI_CAST_PTR(u8, table_ptr)[i] = (u8) temp; - } + table_desc.address = obj_desc->region.address; + table_desc.length = obj_desc->region.length; + table_desc.flags = ACPI_TABLE_ORIGIN_MAPPED; break; - case ACPI_TYPE_LOCAL_REGION_FIELD: - case ACPI_TYPE_LOCAL_BANK_FIELD: - case ACPI_TYPE_LOCAL_INDEX_FIELD: + case ACPI_TYPE_BUFFER: /* Buffer or resolved region_field */ - ACPI_DEBUG_PRINT((ACPI_DB_EXEC, "Load from Field %p %s\n", - obj_desc, - acpi_ut_get_object_type_name(obj_desc))); + /* Simply extract the buffer from the buffer object */ - /* - * The length of the field must be at least as large as the table. - * Read the entire field and thus the entire table. Buffer is - * allocated during the read. - */ - status = - acpi_ex_read_data_from_field(walk_state, obj_desc, - &buffer_desc); - if (ACPI_FAILURE(status)) { - return_ACPI_STATUS(status); - } - - table_ptr = ACPI_CAST_PTR(struct acpi_table_header, - buffer_desc->buffer.pointer); - - /* All done with the buffer_desc, delete it */ - - buffer_desc->buffer.pointer = NULL; - acpi_ut_remove_reference(buffer_desc); + ACPI_DEBUG_PRINT((ACPI_DB_EXEC, + "Load from Buffer or Field %p %s\n", obj_desc, + acpi_ut_get_object_type_name(obj_desc))); - /* Sanity check the table length */ + table_desc.pointer = ACPI_CAST_PTR(struct acpi_table_header, + obj_desc->buffer.pointer); + table_desc.length = table_desc.pointer->length; + table_desc.flags = ACPI_TABLE_ORIGIN_ALLOCATED; - if (table_ptr->length < sizeof(struct acpi_table_header)) { - status = AE_BAD_HEADER; - goto cleanup; - } + obj_desc->buffer.pointer = NULL; break; default: return_ACPI_STATUS(AE_AML_OPERAND_TYPE); } - /* The table must be either an SSDT or a PSDT */ - - if ((!ACPI_COMPARE_NAME(table_ptr->signature, PSDT_SIG)) && - (!ACPI_COMPARE_NAME(table_ptr->signature, SSDT_SIG))) { - ACPI_ERROR((AE_INFO, - "Table has invalid signature [%4.4s], must be SSDT or PSDT", - table_ptr->signature)); - status = AE_BAD_SIGNATURE; + /* + * Install the new table into the local data structures + */ + status = acpi_tb_add_table(&table_desc, &table_index); + if (ACPI_FAILURE(status)) { goto cleanup; } - /* Install the new table into the local data structures */ - - status = acpi_ex_add_table(table_ptr, acpi_gbl_root_node, &ddb_handle); + status = + acpi_ex_add_table(table_index, acpi_gbl_root_node, &ddb_handle); if (ACPI_FAILURE(status)) { /* On error, table_ptr was deallocated above */ @@ -450,13 +352,9 @@ acpi_ex_load_op(union acpi_operand_objec return_ACPI_STATUS(status); } - ACPI_INFO((AE_INFO, - "Dynamic SSDT Load - OemId [%6.6s] OemTableId [%8.8s]", - table_ptr->oem_id, table_ptr->oem_table_id)); - cleanup: if (ACPI_FAILURE(status)) { - ACPI_FREE(table_ptr); + acpi_tb_delete_table(&table_desc); } return_ACPI_STATUS(status); } @@ -477,7 +375,7 @@ acpi_status acpi_ex_unload_table(union a { acpi_status status = AE_OK; union acpi_operand_object *table_desc = ddb_handle; - struct acpi_table_desc *table_info; + acpi_native_uint table_index; ACPI_FUNCTION_TRACE(ex_unload_table); @@ -493,19 +391,18 @@ acpi_status acpi_ex_unload_table(union a return_ACPI_STATUS(AE_BAD_PARAMETER); } - /* Get the actual table descriptor from the ddb_handle */ + /* Get the table index from the ddb_handle */ - table_info = (struct acpi_table_desc *)table_desc->reference.object; + table_index = (acpi_native_uint) table_desc->reference.object; /* * Delete the entire namespace under this table Node * (Offset contains the table_id) */ - acpi_ns_delete_namespace_by_owner(table_info->owner_id); - - /* Delete the table itself */ + acpi_tb_delete_namespace_by_owner(table_index); + acpi_tb_release_owner_id(table_index); - (void)acpi_tb_uninstall_table(table_info->installed_desc); + acpi_tb_set_table_loaded_flag(table_index, FALSE); /* Delete the table descriptor (ddb_handle) */ diff --git a/drivers/acpi/executer/exconvrt.c b/drivers/acpi/executer/exconvrt.c index 544e81a..d470e8b 100644 --- a/drivers/acpi/executer/exconvrt.c +++ b/drivers/acpi/executer/exconvrt.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2006, R. Byron Moore + * Copyright (C) 2000 - 2007, R. Byron Moore * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/executer/excreate.c b/drivers/acpi/executer/excreate.c index 34eec82..7c38528 100644 --- a/drivers/acpi/executer/excreate.c +++ b/drivers/acpi/executer/excreate.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2006, R. Byron Moore + * Copyright (C) 2000 - 2007, R. Byron Moore * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -359,8 +359,9 @@ acpi_status acpi_ex_create_table_region( union acpi_operand_object **operand = &walk_state->operands[0]; union acpi_operand_object *obj_desc; struct acpi_namespace_node *node; - struct acpi_table_header *table; union acpi_operand_object *region_obj2; + acpi_native_uint table_index; + struct acpi_table_header *table; ACPI_FUNCTION_TRACE(ex_create_table_region); @@ -380,7 +381,7 @@ acpi_status acpi_ex_create_table_region( status = acpi_tb_find_table(operand[1]->string.pointer, operand[2]->string.pointer, - operand[3]->string.pointer, &table); + operand[3]->string.pointer, &table_index); if (ACPI_FAILURE(status)) { return_ACPI_STATUS(status); } @@ -395,6 +396,11 @@ acpi_status acpi_ex_create_table_region( region_obj2 = obj_desc->common.next_object; region_obj2->extra.region_context = NULL; + status = acpi_get_table_by_index(table_index, &table); + if (ACPI_FAILURE(status)) { + return_ACPI_STATUS(status); + } + /* Init the region from the operands */ obj_desc->region.space_id = REGION_DATA_TABLE; @@ -553,7 +559,8 @@ acpi_ex_create_method(u8 * aml_start, obj_desc = acpi_ut_create_internal_object(ACPI_TYPE_METHOD); if (!obj_desc) { - return_ACPI_STATUS(AE_NO_MEMORY); + status = AE_NO_MEMORY; + goto exit; } /* Save the method's AML pointer and length */ @@ -576,10 +583,7 @@ acpi_ex_create_method(u8 * aml_start, * Get the sync_level. If method is serialized, a mutex will be * created for this method when it is parsed. */ - if (acpi_gbl_all_methods_serialized) { - obj_desc->method.sync_level = 0; - obj_desc->method.method_flags |= AML_METHOD_SERIALIZED; - } else if (method_flags & AML_METHOD_SERIALIZED) { + if (method_flags & AML_METHOD_SERIALIZED) { /* * ACPI 1.0: sync_level = 0 * ACPI 2.0: sync_level = sync_level in method declaration @@ -597,6 +601,7 @@ acpi_ex_create_method(u8 * aml_start, acpi_ut_remove_reference(obj_desc); + exit: /* Remove a reference to the operand */ acpi_ut_remove_reference(operand[1]); diff --git a/drivers/acpi/executer/exdump.c b/drivers/acpi/executer/exdump.c index 2450943..68d283f 100644 --- a/drivers/acpi/executer/exdump.c +++ b/drivers/acpi/executer/exdump.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2006, R. Byron Moore + * Copyright (C) 2000 - 2007, R. Byron Moore * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -59,8 +59,6 @@ static void acpi_ex_out_string(char *tit static void acpi_ex_out_pointer(char *title, void *value); -static void acpi_ex_out_address(char *title, acpi_physical_address value); - static void acpi_ex_dump_object(union acpi_operand_object *obj_desc, struct acpi_exdump_info *info); @@ -92,10 +90,11 @@ static struct acpi_exdump_info acpi_ex_d {ACPI_EXD_STRING, 0, NULL} }; -static struct acpi_exdump_info acpi_ex_dump_buffer[4] = { +static struct acpi_exdump_info acpi_ex_dump_buffer[5] = { {ACPI_EXD_INIT, ACPI_EXD_TABLE_SIZE(acpi_ex_dump_buffer), NULL}, {ACPI_EXD_UINT32, ACPI_EXD_OFFSET(buffer.length), "Length"}, {ACPI_EXD_POINTER, ACPI_EXD_OFFSET(buffer.pointer), "Pointer"}, + {ACPI_EXD_POINTER, ACPI_EXD_OFFSET(buffer.node), "Parent Node"}, {ACPI_EXD_BUFFER, 0, NULL} }; @@ -165,8 +164,8 @@ static struct acpi_exdump_info acpi_ex_d static struct acpi_exdump_info acpi_ex_dump_processor[7] = { {ACPI_EXD_INIT, ACPI_EXD_TABLE_SIZE(acpi_ex_dump_processor), NULL}, - {ACPI_EXD_UINT32, ACPI_EXD_OFFSET(processor.proc_id), "Processor ID"}, - {ACPI_EXD_UINT32, ACPI_EXD_OFFSET(processor.length), "Length"}, + {ACPI_EXD_UINT8, ACPI_EXD_OFFSET(processor.proc_id), "Processor ID"}, + {ACPI_EXD_UINT8, ACPI_EXD_OFFSET(processor.length), "Length"}, {ACPI_EXD_ADDRESS, ACPI_EXD_OFFSET(processor.address), "Address"}, {ACPI_EXD_POINTER, ACPI_EXD_OFFSET(processor.system_notify), "System Notify"}, @@ -379,18 +378,12 @@ acpi_ex_dump_object(union acpi_operand_o break; case ACPI_EXD_POINTER: + case ACPI_EXD_ADDRESS: acpi_ex_out_pointer(name, *ACPI_CAST_PTR(void *, target)); break; - case ACPI_EXD_ADDRESS: - - acpi_ex_out_address(name, - *ACPI_CAST_PTR - (acpi_physical_address, target)); - break; - case ACPI_EXD_STRING: acpi_ut_print_string(obj_desc->string.pointer, @@ -834,16 +827,6 @@ static void acpi_ex_out_pointer(char *ti acpi_os_printf("%20s : %p\n", title, value); } -static void acpi_ex_out_address(char *title, acpi_physical_address value) -{ - -#if ACPI_MACHINE_WIDTH == 16 - acpi_os_printf("%20s : %p\n", title, value); -#else - acpi_os_printf("%20s : %8.8X%8.8X\n", title, ACPI_FORMAT_UINT64(value)); -#endif -} - /******************************************************************************* * * FUNCTION: acpi_ex_dump_namespace_node diff --git a/drivers/acpi/executer/exfield.c b/drivers/acpi/executer/exfield.c index 9ea9c3a..2d88a3d 100644 --- a/drivers/acpi/executer/exfield.c +++ b/drivers/acpi/executer/exfield.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2006, R. Byron Moore + * Copyright (C) 2000 - 2007, R. Byron Moore * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/executer/exfldio.c b/drivers/acpi/executer/exfldio.c index 40f0bee..65a48b6 100644 --- a/drivers/acpi/executer/exfldio.c +++ b/drivers/acpi/executer/exfldio.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2006, R. Byron Moore + * Copyright (C) 2000 - 2007, R. Byron Moore * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -257,14 +257,13 @@ acpi_ex_access_region(union acpi_operand } ACPI_DEBUG_PRINT_RAW((ACPI_DB_BFIELD, - " Region [%s:%X], Width %X, ByteBase %X, Offset %X at %8.8X%8.8X\n", + " Region [%s:%X], Width %X, ByteBase %X, Offset %X at %p\n", acpi_ut_get_region_name(rgn_desc->region. space_id), rgn_desc->region.space_id, obj_desc->common_field.access_byte_width, obj_desc->common_field.base_byte_offset, - field_datum_byte_offset, - ACPI_FORMAT_UINT64(address))); + field_datum_byte_offset, (void *)address)); /* Invoke the appropriate address_space/op_region handler */ diff --git a/drivers/acpi/executer/exmisc.c b/drivers/acpi/executer/exmisc.c index bd98aab..f13d1ce 100644 --- a/drivers/acpi/executer/exmisc.c +++ b/drivers/acpi/executer/exmisc.c @@ -6,7 +6,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2006, R. Byron Moore + * Copyright (C) 2000 - 2007, R. Byron Moore * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/executer/exmutex.c b/drivers/acpi/executer/exmutex.c index bf90f04..5101bad 100644 --- a/drivers/acpi/executer/exmutex.c +++ b/drivers/acpi/executer/exmutex.c @@ -6,7 +6,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2006, R. Byron Moore + * Copyright (C) 2000 - 2007, R. Byron Moore * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -44,6 +44,7 @@ #include #include +#include #define _COMPONENT ACPI_EXECUTER ACPI_MODULE_NAME("exmutex") @@ -150,7 +151,7 @@ acpi_ex_acquire_mutex(union acpi_operand return_ACPI_STATUS(AE_BAD_PARAMETER); } - /* Sanity check -- we must have a valid thread ID */ + /* Sanity check: we must have a valid thread ID */ if (!walk_state->thread) { ACPI_ERROR((AE_INFO, @@ -174,24 +175,28 @@ acpi_ex_acquire_mutex(union acpi_operand /* Support for multiple acquires by the owning thread */ if (obj_desc->mutex.owner_thread) { - - /* Special case for Global Lock, allow all threads */ - - if ((obj_desc->mutex.owner_thread->thread_id == - walk_state->thread->thread_id) || - (obj_desc->mutex.os_mutex == ACPI_GLOBAL_LOCK)) { + if (obj_desc->mutex.owner_thread->thread_id == + walk_state->thread->thread_id) { /* - * The mutex is already owned by this thread, - * just increment the acquisition depth + * The mutex is already owned by this thread, just increment the + * acquisition depth */ obj_desc->mutex.acquisition_depth++; return_ACPI_STATUS(AE_OK); } } - /* Acquire the mutex, wait if necessary */ + /* Acquire the mutex, wait if necessary. Special case for Global Lock */ + + if (obj_desc->mutex.os_mutex == acpi_gbl_global_lock_mutex) { + status = + acpi_ev_acquire_global_lock((u16) time_desc->integer.value); + } else { + status = acpi_ex_system_wait_mutex(obj_desc->mutex.os_mutex, + (u16) time_desc->integer. + value); + } - status = acpi_ex_system_acquire_mutex(time_desc, obj_desc); if (ACPI_FAILURE(status)) { /* Includes failure from a timeout on time_desc */ @@ -211,7 +216,6 @@ acpi_ex_acquire_mutex(union acpi_operand /* Link the mutex to the current thread for force-unlock at method exit */ acpi_ex_link_mutex(obj_desc, walk_state->thread); - return_ACPI_STATUS(AE_OK); } @@ -232,7 +236,7 @@ acpi_status acpi_ex_release_mutex(union acpi_operand_object *obj_desc, struct acpi_walk_state *walk_state) { - acpi_status status; + acpi_status status = AE_OK; ACPI_FUNCTION_TRACE(ex_release_mutex); @@ -249,7 +253,7 @@ acpi_ex_release_mutex(union acpi_operand return_ACPI_STATUS(AE_AML_MUTEX_NOT_ACQUIRED); } - /* Sanity check -- we must have a valid thread ID */ + /* Sanity check: we must have a valid thread ID */ if (!walk_state->thread) { ACPI_ERROR((AE_INFO, @@ -264,7 +268,7 @@ acpi_ex_release_mutex(union acpi_operand */ if ((obj_desc->mutex.owner_thread->thread_id != walk_state->thread->thread_id) - && (obj_desc->mutex.os_mutex != ACPI_GLOBAL_LOCK)) { + && (obj_desc->mutex.os_mutex != acpi_gbl_global_lock_mutex)) { ACPI_ERROR((AE_INFO, "Thread %lX cannot release Mutex [%4.4s] acquired by thread %lX", (unsigned long)walk_state->thread->thread_id, @@ -274,8 +278,8 @@ acpi_ex_release_mutex(union acpi_operand } /* - * The sync level of the mutex must be less than or - * equal to the current sync level + * The sync level of the mutex must be less than or equal to the current + * sync level */ if (obj_desc->mutex.sync_level > walk_state->thread->current_sync_level) { ACPI_ERROR((AE_INFO, @@ -298,11 +302,15 @@ acpi_ex_release_mutex(union acpi_operand acpi_ex_unlink_mutex(obj_desc); - /* Release the mutex */ + /* Release the mutex, special case for Global Lock */ - status = acpi_ex_system_release_mutex(obj_desc); + if (obj_desc->mutex.os_mutex == acpi_gbl_global_lock_mutex) { + status = acpi_ev_release_global_lock(); + } else { + acpi_os_release_mutex(obj_desc->mutex.os_mutex); + } - /* Update the mutex and walk state, restore sync_level before acquire */ + /* Update the mutex and restore sync_level */ obj_desc->mutex.owner_thread = NULL; walk_state->thread->current_sync_level = @@ -321,39 +329,49 @@ acpi_ex_release_mutex(union acpi_operand * * DESCRIPTION: Release all mutexes held by this thread * + * NOTE: This function is called as the thread is exiting the interpreter. + * Mutexes are not released when an individual control method is exited, but + * only when the parent thread actually exits the interpreter. This allows one + * method to acquire a mutex, and a different method to release it, as long as + * this is performed underneath a single parent control method. + * ******************************************************************************/ void acpi_ex_release_all_mutexes(struct acpi_thread_state *thread) { union acpi_operand_object *next = thread->acquired_mutex_list; - union acpi_operand_object *this; - acpi_status status; + union acpi_operand_object *obj_desc; ACPI_FUNCTION_ENTRY(); /* Traverse the list of owned mutexes, releasing each one */ while (next) { - this = next; - next = this->mutex.next; + obj_desc = next; + next = obj_desc->mutex.next; + + obj_desc->mutex.prev = NULL; + obj_desc->mutex.next = NULL; + obj_desc->mutex.acquisition_depth = 0; + + /* Release the mutex, special case for Global Lock */ - this->mutex.acquisition_depth = 1; - this->mutex.prev = NULL; - this->mutex.next = NULL; + if (obj_desc->mutex.os_mutex == acpi_gbl_global_lock_mutex) { - /* Release the mutex */ + /* Ignore errors */ - status = acpi_ex_system_release_mutex(this); - if (ACPI_FAILURE(status)) { - continue; + (void)acpi_ev_release_global_lock(); + } else { + acpi_os_release_mutex(obj_desc->mutex.os_mutex); } /* Mark mutex unowned */ - this->mutex.owner_thread = NULL; + obj_desc->mutex.owner_thread = NULL; /* Update Thread sync_level (Last mutex is the important one) */ - thread->current_sync_level = this->mutex.original_sync_level; + thread->current_sync_level = + obj_desc->mutex.original_sync_level; } } diff --git a/drivers/acpi/executer/exnames.c b/drivers/acpi/executer/exnames.c index d3d7036..1ee4fb1 100644 --- a/drivers/acpi/executer/exnames.c +++ b/drivers/acpi/executer/exnames.c @@ -6,7 +6,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2006, R. Byron Moore + * Copyright (C) 2000 - 2007, R. Byron Moore * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/executer/exoparg1.c b/drivers/acpi/executer/exoparg1.c index 6374d8b..252f10a 100644 --- a/drivers/acpi/executer/exoparg1.c +++ b/drivers/acpi/executer/exoparg1.c @@ -6,7 +6,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2006, R. Byron Moore + * Copyright (C) 2000 - 2007, R. Byron Moore * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -104,9 +104,7 @@ acpi_status acpi_ex_opcode_0A_0T_1R(stru status = AE_NO_MEMORY; goto cleanup; } -#if ACPI_MACHINE_WIDTH != 16 return_desc->integer.value = acpi_os_get_timer(); -#endif break; default: /* Unknown opcode */ diff --git a/drivers/acpi/executer/exoparg2.c b/drivers/acpi/executer/exoparg2.c index 7d2cbc1..17e652e 100644 --- a/drivers/acpi/executer/exoparg2.c +++ b/drivers/acpi/executer/exoparg2.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2006, R. Byron Moore + * Copyright (C) 2000 - 2007, R. Byron Moore * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/executer/exoparg3.c b/drivers/acpi/executer/exoparg3.c index e2d945d..7fe67cf 100644 --- a/drivers/acpi/executer/exoparg3.c +++ b/drivers/acpi/executer/exoparg3.c @@ -6,7 +6,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2006, R. Byron Moore + * Copyright (C) 2000 - 2007, R. Byron Moore * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/executer/exoparg6.c b/drivers/acpi/executer/exoparg6.c index f0c0ba6..bd80a9c 100644 --- a/drivers/acpi/executer/exoparg6.c +++ b/drivers/acpi/executer/exoparg6.c @@ -6,7 +6,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2006, R. Byron Moore + * Copyright (C) 2000 - 2007, R. Byron Moore * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/executer/exprep.c b/drivers/acpi/executer/exprep.c index 44d064f..a669662 100644 --- a/drivers/acpi/executer/exprep.c +++ b/drivers/acpi/executer/exprep.c @@ -6,7 +6,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2006, R. Byron Moore + * Copyright (C) 2000 - 2007, R. Byron Moore * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/executer/exregion.c b/drivers/acpi/executer/exregion.c index 3cc97ba..2e9ce94 100644 --- a/drivers/acpi/executer/exregion.c +++ b/drivers/acpi/executer/exregion.c @@ -6,7 +6,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2006, R. Byron Moore + * Copyright (C) 2000 - 2007, R. Byron Moore * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -155,16 +155,15 @@ #endif /* Create a new mapping starting at the address given */ - status = acpi_os_map_memory(address, window_size, - (void **)&mem_info-> - mapped_logical_address); - if (ACPI_FAILURE(status)) { + mem_info->mapped_logical_address = + acpi_os_map_memory((acpi_native_uint) address, window_size); + if (!mem_info->mapped_logical_address) { ACPI_ERROR((AE_INFO, "Could not map memory at %8.8X%8.8X, size %X", ACPI_FORMAT_UINT64(address), (u32) window_size)); mem_info->mapped_length = 0; - return_ACPI_STATUS(status); + return_ACPI_STATUS(AE_NO_MEMORY); } /* Save the physical address and mapping size */ @@ -210,11 +209,10 @@ #endif *value = (acpi_integer) ACPI_GET32(logical_addr_ptr); break; -#if ACPI_MACHINE_WIDTH != 16 case 64: *value = (acpi_integer) ACPI_GET64(logical_addr_ptr); break; -#endif + default: /* bit_width was already validated */ break; @@ -236,11 +234,9 @@ #endif ACPI_SET32(logical_addr_ptr) = (u32) * value; break; -#if ACPI_MACHINE_WIDTH != 16 case 64: ACPI_SET64(logical_addr_ptr) = (u64) * value; break; -#endif default: /* bit_width was already validated */ diff --git a/drivers/acpi/executer/exresnte.c b/drivers/acpi/executer/exresnte.c index 3089b05..2b3a01c 100644 --- a/drivers/acpi/executer/exresnte.c +++ b/drivers/acpi/executer/exresnte.c @@ -6,7 +6,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2006, R. Byron Moore + * Copyright (C) 2000 - 2007, R. Byron Moore * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/executer/exresolv.c b/drivers/acpi/executer/exresolv.c index 6499de8..6c64e55 100644 --- a/drivers/acpi/executer/exresolv.c +++ b/drivers/acpi/executer/exresolv.c @@ -6,7 +6,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2006, R. Byron Moore + * Copyright (C) 2000 - 2007, R. Byron Moore * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -141,7 +141,7 @@ acpi_ex_resolve_object_to_value(union ac acpi_status status = AE_OK; union acpi_operand_object *stack_desc; void *temp_node; - union acpi_operand_object *obj_desc; + union acpi_operand_object *obj_desc = NULL; u16 opcode; ACPI_FUNCTION_TRACE(ex_resolve_object_to_value); @@ -299,8 +299,6 @@ acpi_ex_resolve_object_to_value(union ac status = acpi_ds_get_package_arguments(stack_desc); break; - /* These cases may never happen here, but just in case.. */ - case ACPI_TYPE_BUFFER_FIELD: case ACPI_TYPE_LOCAL_REGION_FIELD: case ACPI_TYPE_LOCAL_BANK_FIELD: @@ -314,6 +312,10 @@ acpi_ex_resolve_object_to_value(union ac status = acpi_ex_read_data_from_field(walk_state, stack_desc, &obj_desc); + + /* Remove a reference to the original operand, then override */ + + acpi_ut_remove_reference(*stack_ptr); *stack_ptr = (void *)obj_desc; break; diff --git a/drivers/acpi/executer/exresop.c b/drivers/acpi/executer/exresop.c index 4c93d09..ba76186 100644 --- a/drivers/acpi/executer/exresop.c +++ b/drivers/acpi/executer/exresop.c @@ -6,7 +6,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2006, R. Byron Moore + * Copyright (C) 2000 - 2007, R. Byron Moore * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -611,22 +611,20 @@ acpi_ex_resolve_operands(u16 opcode, } goto next_operand; - case ARGI_REGION_OR_FIELD: + case ARGI_REGION_OR_BUFFER: /* Used by Load() only */ - /* Need an operand of type REGION or a FIELD in a region */ + /* Need an operand of type REGION or a BUFFER (which could be a resolved region field) */ switch (ACPI_GET_OBJECT_TYPE(obj_desc)) { + case ACPI_TYPE_BUFFER: case ACPI_TYPE_REGION: - case ACPI_TYPE_LOCAL_REGION_FIELD: - case ACPI_TYPE_LOCAL_BANK_FIELD: - case ACPI_TYPE_LOCAL_INDEX_FIELD: /* Valid operand */ break; default: ACPI_ERROR((AE_INFO, - "Needed [Region/RegionField], found [%s] %p", + "Needed [Region/Buffer], found [%s] %p", acpi_ut_get_object_type_name (obj_desc), obj_desc)); diff --git a/drivers/acpi/executer/exstore.c b/drivers/acpi/executer/exstore.c index 0456405..f4b69a6 100644 --- a/drivers/acpi/executer/exstore.c +++ b/drivers/acpi/executer/exstore.c @@ -6,7 +6,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2006, R. Byron Moore + * Copyright (C) 2000 - 2007, R. Byron Moore * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/executer/exstoren.c b/drivers/acpi/executer/exstoren.c index 591aaf0..1d622c6 100644 --- a/drivers/acpi/executer/exstoren.c +++ b/drivers/acpi/executer/exstoren.c @@ -7,7 +7,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2006, R. Byron Moore + * Copyright (C) 2000 - 2007, R. Byron Moore * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/executer/exstorob.c b/drivers/acpi/executer/exstorob.c index 99ebe5a..8233d40 100644 --- a/drivers/acpi/executer/exstorob.c +++ b/drivers/acpi/executer/exstorob.c @@ -6,7 +6,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2006, R. Byron Moore + * Copyright (C) 2000 - 2007, R. Byron Moore * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/executer/exsystem.c b/drivers/acpi/executer/exsystem.c index 28aef3e..9460baf 100644 --- a/drivers/acpi/executer/exsystem.c +++ b/drivers/acpi/executer/exsystem.c @@ -6,7 +6,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2006, R. Byron Moore + * Copyright (C) 2000 - 2007, R. Byron Moore * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -66,7 +66,6 @@ ACPI_MODULE_NAME("exsystem") acpi_status acpi_ex_system_wait_semaphore(acpi_semaphore semaphore, u16 timeout) { acpi_status status; - acpi_status status2; ACPI_FUNCTION_TRACE(ex_system_wait_semaphore); @@ -79,7 +78,7 @@ acpi_status acpi_ex_system_wait_semaphor /* We must wait, so unlock the interpreter */ - acpi_ex_exit_interpreter(); + acpi_ex_relinquish_interpreter(); status = acpi_os_wait_semaphore(semaphore, 1, timeout); @@ -89,13 +88,7 @@ acpi_status acpi_ex_system_wait_semaphor /* Reacquire the interpreter */ - status2 = acpi_ex_enter_interpreter(); - if (ACPI_FAILURE(status2)) { - - /* Report fatal error, could not acquire interpreter */ - - return_ACPI_STATUS(status2); - } + acpi_ex_reacquire_interpreter(); } return_ACPI_STATUS(status); @@ -119,7 +112,6 @@ acpi_status acpi_ex_system_wait_semaphor acpi_status acpi_ex_system_wait_mutex(acpi_mutex mutex, u16 timeout) { acpi_status status; - acpi_status status2; ACPI_FUNCTION_TRACE(ex_system_wait_mutex); @@ -132,7 +124,7 @@ acpi_status acpi_ex_system_wait_mutex(ac /* We must wait, so unlock the interpreter */ - acpi_ex_exit_interpreter(); + acpi_ex_relinquish_interpreter(); status = acpi_os_acquire_mutex(mutex, timeout); @@ -142,13 +134,7 @@ acpi_status acpi_ex_system_wait_mutex(ac /* Reacquire the interpreter */ - status2 = acpi_ex_enter_interpreter(); - if (ACPI_FAILURE(status2)) { - - /* Report fatal error, could not acquire interpreter */ - - return_ACPI_STATUS(status2); - } + acpi_ex_reacquire_interpreter(); } return_ACPI_STATUS(status); @@ -209,96 +195,18 @@ acpi_status acpi_ex_system_do_stall(u32 acpi_status acpi_ex_system_do_suspend(acpi_integer how_long) { - acpi_status status; - ACPI_FUNCTION_ENTRY(); /* Since this thread will sleep, we must release the interpreter */ - acpi_ex_exit_interpreter(); + acpi_ex_relinquish_interpreter(); acpi_os_sleep(how_long); /* And now we must get the interpreter again */ - status = acpi_ex_enter_interpreter(); - return (status); -} - -/******************************************************************************* - * - * FUNCTION: acpi_ex_system_acquire_mutex - * - * PARAMETERS: time_desc - Maximum time to wait for the mutex - * obj_desc - The object descriptor for this op - * - * RETURN: Status - * - * DESCRIPTION: Provides an access point to perform synchronization operations - * within the AML. This function will cause a lock to be generated - * for the Mutex pointed to by obj_desc. - * - ******************************************************************************/ - -acpi_status -acpi_ex_system_acquire_mutex(union acpi_operand_object * time_desc, - union acpi_operand_object * obj_desc) -{ - acpi_status status = AE_OK; - - ACPI_FUNCTION_TRACE_PTR(ex_system_acquire_mutex, obj_desc); - - if (!obj_desc) { - return_ACPI_STATUS(AE_BAD_PARAMETER); - } - - /* Support for the _GL_ Mutex object -- go get the global lock */ - - if (obj_desc->mutex.os_mutex == ACPI_GLOBAL_LOCK) { - status = - acpi_ev_acquire_global_lock((u16) time_desc->integer.value); - return_ACPI_STATUS(status); - } - - status = acpi_ex_system_wait_mutex(obj_desc->mutex.os_mutex, - (u16) time_desc->integer.value); - return_ACPI_STATUS(status); -} - -/******************************************************************************* - * - * FUNCTION: acpi_ex_system_release_mutex - * - * PARAMETERS: obj_desc - The object descriptor for this op - * - * RETURN: Status - * - * DESCRIPTION: Provides an access point to perform synchronization operations - * within the AML. This operation is a request to release a - * previously acquired Mutex. If the Mutex variable is set then - * it will be decremented. - * - ******************************************************************************/ - -acpi_status acpi_ex_system_release_mutex(union acpi_operand_object *obj_desc) -{ - acpi_status status = AE_OK; - - ACPI_FUNCTION_TRACE(ex_system_release_mutex); - - if (!obj_desc) { - return_ACPI_STATUS(AE_BAD_PARAMETER); - } - - /* Support for the _GL_ Mutex object -- release the global lock */ - - if (obj_desc->mutex.os_mutex == ACPI_GLOBAL_LOCK) { - status = acpi_ev_release_global_lock(); - return_ACPI_STATUS(status); - } - - acpi_os_release_mutex(obj_desc->mutex.os_mutex); - return_ACPI_STATUS(AE_OK); + acpi_ex_reacquire_interpreter(); + return (AE_OK); } /******************************************************************************* @@ -314,7 +222,7 @@ acpi_status acpi_ex_system_release_mutex * ******************************************************************************/ -acpi_status acpi_ex_system_signal_event(union acpi_operand_object *obj_desc) +acpi_status acpi_ex_system_signal_event(union acpi_operand_object * obj_desc) { acpi_status status = AE_OK; diff --git a/drivers/acpi/executer/exutils.c b/drivers/acpi/executer/exutils.c index 982c8b6..6b0aecc 100644 --- a/drivers/acpi/executer/exutils.c +++ b/drivers/acpi/executer/exutils.c @@ -6,7 +6,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2006, R. Byron Moore + * Copyright (C) 2000 - 2007, R. Byron Moore * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -76,14 +76,15 @@ #ifndef ACPI_NO_METHOD_EXECUTION * * PARAMETERS: None * - * RETURN: Status + * RETURN: None * - * DESCRIPTION: Enter the interpreter execution region. Failure to enter - * the interpreter region is a fatal system error + * DESCRIPTION: Enter the interpreter execution region. Failure to enter + * the interpreter region is a fatal system error. Used in + * conjunction with exit_interpreter. * ******************************************************************************/ -acpi_status acpi_ex_enter_interpreter(void) +void acpi_ex_enter_interpreter(void) { acpi_status status; @@ -91,31 +92,55 @@ acpi_status acpi_ex_enter_interpreter(vo status = acpi_ut_acquire_mutex(ACPI_MTX_INTERPRETER); if (ACPI_FAILURE(status)) { - ACPI_ERROR((AE_INFO, "Could not acquire interpreter mutex")); + ACPI_ERROR((AE_INFO, + "Could not acquire AML Interpreter mutex")); } - return_ACPI_STATUS(status); + return_VOID; } /******************************************************************************* * - * FUNCTION: acpi_ex_exit_interpreter + * FUNCTION: acpi_ex_reacquire_interpreter * * PARAMETERS: None * * RETURN: None * - * DESCRIPTION: Exit the interpreter execution region + * DESCRIPTION: Reacquire the interpreter execution region from within the + * interpreter code. Failure to enter the interpreter region is a + * fatal system error. Used in conjuction with + * relinquish_interpreter + * + ******************************************************************************/ + +void acpi_ex_reacquire_interpreter(void) +{ + ACPI_FUNCTION_TRACE(ex_reacquire_interpreter); + + /* + * If the global serialized flag is set, do not release the interpreter, + * since it was not actually released by acpi_ex_relinquish_interpreter. + * This forces the interpreter to be single threaded. + */ + if (!acpi_gbl_all_methods_serialized) { + acpi_ex_enter_interpreter(); + } + + return_VOID; +} + +/******************************************************************************* + * + * FUNCTION: acpi_ex_exit_interpreter + * + * PARAMETERS: None + * + * RETURN: None * - * Cases where the interpreter is unlocked: - * 1) Completion of the execution of a control method - * 2) Method blocked on a Sleep() AML opcode - * 3) Method blocked on an Acquire() AML opcode - * 4) Method blocked on a Wait() AML opcode - * 5) Method blocked to acquire the global lock - * 6) Method blocked to execute a serialized control method that is - * already executing - * 7) About to invoke a user-installed opregion handler + * DESCRIPTION: Exit the interpreter execution region. This is the top level + * routine used to exit the interpreter when all processing has + * been completed. * ******************************************************************************/ @@ -127,7 +152,46 @@ void acpi_ex_exit_interpreter(void) status = acpi_ut_release_mutex(ACPI_MTX_INTERPRETER); if (ACPI_FAILURE(status)) { - ACPI_ERROR((AE_INFO, "Could not release interpreter mutex")); + ACPI_ERROR((AE_INFO, + "Could not release AML Interpreter mutex")); + } + + return_VOID; +} + +/******************************************************************************* + * + * FUNCTION: acpi_ex_relinquish_interpreter + * + * PARAMETERS: None + * + * RETURN: None + * + * DESCRIPTION: Exit the interpreter execution region, from within the + * interpreter - before attempting an operation that will possibly + * block the running thread. + * + * Cases where the interpreter is unlocked internally + * 1) Method to be blocked on a Sleep() AML opcode + * 2) Method to be blocked on an Acquire() AML opcode + * 3) Method to be blocked on a Wait() AML opcode + * 4) Method to be blocked to acquire the global lock + * 5) Method to be blocked waiting to execute a serialized control method + * that is currently executing + * 6) About to invoke a user-installed opregion handler + * + ******************************************************************************/ + +void acpi_ex_relinquish_interpreter(void) +{ + ACPI_FUNCTION_TRACE(ex_relinquish_interpreter); + + /* + * If the global serialized flag is set, do not release the interpreter. + * This forces the interpreter to be single threaded. + */ + if (!acpi_gbl_all_methods_serialized) { + acpi_ex_exit_interpreter(); } return_VOID; @@ -141,8 +205,8 @@ void acpi_ex_exit_interpreter(void) * * RETURN: none * - * DESCRIPTION: Truncate a number to 32-bits if the currently executing method - * belongs to a 32-bit ACPI table. + * DESCRIPTION: Truncate an ACPI Integer to 32 bits if the execution mode is + * 32-bit, as determined by the revision of the DSDT. * ******************************************************************************/ diff --git a/drivers/acpi/fan.c b/drivers/acpi/fan.c index f305a82..af22fdf 100644 --- a/drivers/acpi/fan.c +++ b/drivers/acpi/fan.c @@ -48,8 +48,8 @@ MODULE_LICENSE("GPL"); static int acpi_fan_add(struct acpi_device *device); static int acpi_fan_remove(struct acpi_device *device, int type); -static int acpi_fan_suspend(struct acpi_device *device, int state); -static int acpi_fan_resume(struct acpi_device *device, int state); +static int acpi_fan_suspend(struct acpi_device *device, pm_message_t state); +static int acpi_fan_resume(struct acpi_device *device); static struct acpi_driver acpi_fan_driver = { .name = ACPI_FAN_DRIVER_NAME, @@ -237,7 +237,7 @@ static int acpi_fan_remove(struct acpi_d return 0; } -static int acpi_fan_suspend(struct acpi_device *device, int state) +static int acpi_fan_suspend(struct acpi_device *device, pm_message_t state) { if (!device) return -EINVAL; @@ -247,7 +247,7 @@ static int acpi_fan_suspend(struct acpi_ return AE_OK; } -static int acpi_fan_resume(struct acpi_device *device, int state) +static int acpi_fan_resume(struct acpi_device *device) { int result = 0; int power_state = 0; diff --git a/drivers/acpi/glue.c b/drivers/acpi/glue.c index 8a0324b..7b6c9ff 100644 --- a/drivers/acpi/glue.c +++ b/drivers/acpi/glue.c @@ -86,129 +86,6 @@ static int acpi_find_bridge_device(struc return ret; } -/* Get PCI root bridge's handle from its segment and bus number */ -struct acpi_find_pci_root { - unsigned int seg; - unsigned int bus; - acpi_handle handle; -}; - -static acpi_status -do_root_bridge_busnr_callback(struct acpi_resource *resource, void *data) -{ - unsigned long *busnr = data; - struct acpi_resource_address64 address; - - if (resource->type != ACPI_RESOURCE_TYPE_ADDRESS16 && - resource->type != ACPI_RESOURCE_TYPE_ADDRESS32 && - resource->type != ACPI_RESOURCE_TYPE_ADDRESS64) - return AE_OK; - - acpi_resource_to_address64(resource, &address); - if ((address.address_length > 0) && - (address.resource_type == ACPI_BUS_NUMBER_RANGE)) - *busnr = address.minimum; - - return AE_OK; -} - -static int get_root_bridge_busnr(acpi_handle handle) -{ - acpi_status status; - unsigned long bus, bbn; - struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL }; - - acpi_get_name(handle, ACPI_FULL_PATHNAME, &buffer); - - status = acpi_evaluate_integer(handle, METHOD_NAME__BBN, NULL, - &bbn); - if (status == AE_NOT_FOUND) { - /* Assume bus = 0 */ - printk(KERN_INFO PREFIX - "Assume root bridge [%s] bus is 0\n", - (char *)buffer.pointer); - status = AE_OK; - bbn = 0; - } - if (ACPI_FAILURE(status)) { - bbn = -ENODEV; - goto exit; - } - if (bbn > 0) - goto exit; - - /* _BBN in some systems return 0 for all root bridges */ - bus = -1; - status = acpi_walk_resources(handle, METHOD_NAME__CRS, - do_root_bridge_busnr_callback, &bus); - /* If _CRS failed, we just use _BBN */ - if (ACPI_FAILURE(status) || (bus == -1)) - goto exit; - /* We select _CRS */ - if (bbn != bus) { - printk(KERN_INFO PREFIX - "_BBN and _CRS returns different value for %s. Select _CRS\n", - (char *)buffer.pointer); - bbn = bus; - } - exit: - kfree(buffer.pointer); - return (int)bbn; -} - -static acpi_status -find_pci_rootbridge(acpi_handle handle, u32 lvl, void *context, void **rv) -{ - struct acpi_find_pci_root *find = (struct acpi_find_pci_root *)context; - unsigned long seg, bus; - acpi_status status; - int tmp; - struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL }; - - acpi_get_name(handle, ACPI_FULL_PATHNAME, &buffer); - - status = acpi_evaluate_integer(handle, METHOD_NAME__SEG, NULL, &seg); - if (status == AE_NOT_FOUND) { - /* Assume seg = 0 */ - status = AE_OK; - seg = 0; - } - if (ACPI_FAILURE(status)) { - status = AE_CTRL_DEPTH; - goto exit; - } - - tmp = get_root_bridge_busnr(handle); - if (tmp < 0) { - printk(KERN_ERR PREFIX - "Find root bridge failed for %s\n", - (char *)buffer.pointer); - status = AE_CTRL_DEPTH; - goto exit; - } - bus = tmp; - - if (seg == find->seg && bus == find->bus) - { - find->handle = handle; - status = AE_CTRL_TERMINATE; - } - else - status = AE_OK; - exit: - kfree(buffer.pointer); - return status; -} - -acpi_handle acpi_get_pci_rootbridge_handle(unsigned int seg, unsigned int bus) -{ - struct acpi_find_pci_root find = { seg, bus, NULL }; - - acpi_get_devices(PCI_ROOT_HID_STRING, find_pci_rootbridge, &find, NULL); - return find.handle; -} -EXPORT_SYMBOL_GPL(acpi_get_pci_rootbridge_handle); - /* Get device's handler per its address under its parent */ struct acpi_find_child { acpi_handle handle; diff --git a/drivers/acpi/hardware/hwacpi.c b/drivers/acpi/hardware/hwacpi.c index de50fab..6031ca1 100644 --- a/drivers/acpi/hardware/hwacpi.c +++ b/drivers/acpi/hardware/hwacpi.c @@ -6,7 +6,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2006, R. Byron Moore + * Copyright (C) 2000 - 2007, R. Byron Moore * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -49,41 +49,6 @@ ACPI_MODULE_NAME("hwacpi") /****************************************************************************** * - * FUNCTION: acpi_hw_initialize - * - * PARAMETERS: None - * - * RETURN: Status - * - * DESCRIPTION: Initialize and validate the various ACPI registers defined in - * the FADT. - * - ******************************************************************************/ -acpi_status acpi_hw_initialize(void) -{ - acpi_status status; - - ACPI_FUNCTION_TRACE(hw_initialize); - - /* We must have the ACPI tables by the time we get here */ - - if (!acpi_gbl_FADT) { - ACPI_ERROR((AE_INFO, "No FADT is present")); - return_ACPI_STATUS(AE_NO_ACPI_TABLES); - } - - /* Sanity check the FADT for valid values */ - - status = acpi_ut_validate_fadt(); - if (ACPI_FAILURE(status)) { - return_ACPI_STATUS(status); - } - - return_ACPI_STATUS(AE_OK); -} - -/****************************************************************************** - * * FUNCTION: acpi_hw_set_mode * * PARAMETERS: Mode - SYS_MODE_ACPI or SYS_MODE_LEGACY @@ -93,7 +58,6 @@ acpi_status acpi_hw_initialize(void) * DESCRIPTION: Transitions the system into the requested mode. * ******************************************************************************/ - acpi_status acpi_hw_set_mode(u32 mode) { @@ -106,7 +70,7 @@ acpi_status acpi_hw_set_mode(u32 mode) * ACPI 2.0 clarified that if SMI_CMD in FADT is zero, * system does not support mode transition. */ - if (!acpi_gbl_FADT->smi_cmd) { + if (!acpi_gbl_FADT.smi_command) { ACPI_ERROR((AE_INFO, "No SMI_CMD in FADT, mode transition failed")); return_ACPI_STATUS(AE_NO_HARDWARE_RESPONSE); @@ -119,7 +83,7 @@ acpi_status acpi_hw_set_mode(u32 mode) * we make sure both the numbers are zero to determine these * transitions are not supported. */ - if (!acpi_gbl_FADT->acpi_enable && !acpi_gbl_FADT->acpi_disable) { + if (!acpi_gbl_FADT.acpi_enable && !acpi_gbl_FADT.acpi_disable) { ACPI_ERROR((AE_INFO, "No ACPI mode transition supported in this system (enable/disable both zero)")); return_ACPI_STATUS(AE_OK); @@ -130,9 +94,8 @@ acpi_status acpi_hw_set_mode(u32 mode) /* BIOS should have disabled ALL fixed and GP events */ - status = acpi_os_write_port(acpi_gbl_FADT->smi_cmd, - (u32) acpi_gbl_FADT->acpi_enable, - 8); + status = acpi_os_write_port(acpi_gbl_FADT.smi_command, + (u32) acpi_gbl_FADT.acpi_enable, 8); ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Attempting to enable ACPI mode\n")); break; @@ -143,8 +106,8 @@ acpi_status acpi_hw_set_mode(u32 mode) * BIOS should clear all fixed status bits and restore fixed event * enable bits to default */ - status = acpi_os_write_port(acpi_gbl_FADT->smi_cmd, - (u32) acpi_gbl_FADT->acpi_disable, + status = acpi_os_write_port(acpi_gbl_FADT.smi_command, + (u32) acpi_gbl_FADT.acpi_disable, 8); ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Attempting to enable Legacy (non-ACPI) mode\n")); @@ -204,12 +167,11 @@ u32 acpi_hw_get_mode(void) * ACPI 2.0 clarified that if SMI_CMD in FADT is zero, * system does not support mode transition. */ - if (!acpi_gbl_FADT->smi_cmd) { + if (!acpi_gbl_FADT.smi_command) { return_UINT32(ACPI_SYS_MODE_ACPI); } - status = - acpi_get_register(ACPI_BITREG_SCI_ENABLE, &value, ACPI_MTX_LOCK); + status = acpi_get_register(ACPI_BITREG_SCI_ENABLE, &value); if (ACPI_FAILURE(status)) { return_UINT32(ACPI_SYS_MODE_LEGACY); } diff --git a/drivers/acpi/hardware/hwgpe.c b/drivers/acpi/hardware/hwgpe.c index 608a3a6..117a05c 100644 --- a/drivers/acpi/hardware/hwgpe.c +++ b/drivers/acpi/hardware/hwgpe.c @@ -6,7 +6,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2006, R. Byron Moore + * Copyright (C) 2000 - 2007, R. Byron Moore * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -105,14 +105,20 @@ acpi_hw_write_gpe_enable_reg(struct acpi acpi_status acpi_hw_clear_gpe(struct acpi_gpe_event_info * gpe_event_info) { acpi_status status; + u8 register_bit; ACPI_FUNCTION_ENTRY(); + register_bit = (u8) + (1 << + (gpe_event_info->gpe_number - + gpe_event_info->register_info->base_gpe_number)); + /* * Write a one to the appropriate bit in the status register to * clear this GPE. */ - status = acpi_hw_low_level_write(8, gpe_event_info->register_bit, + status = acpi_hw_low_level_write(8, register_bit, &gpe_event_info->register_info-> status_address); @@ -155,7 +161,10 @@ acpi_hw_get_gpe_status(struct acpi_gpe_e /* Get the register bitmask for this GPE */ - register_bit = gpe_event_info->register_bit; + register_bit = (u8) + (1 << + (gpe_event_info->gpe_number - + gpe_event_info->register_info->base_gpe_number)); /* GPE currently enabled? (enabled for runtime?) */ diff --git a/drivers/acpi/hardware/hwregs.c b/drivers/acpi/hardware/hwregs.c index fa58c1e..1d371fa 100644 --- a/drivers/acpi/hardware/hwregs.c +++ b/drivers/acpi/hardware/hwregs.c @@ -7,7 +7,7 @@ ******************************************************************************/ /* - * Copyright (C) 2000 - 2006, R. Byron Moore + * Copyright (C) 2000 - 2007, R. Byron Moore * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -54,17 +54,15 @@ ACPI_MODULE_NAME("hwregs") * * FUNCTION: acpi_hw_clear_acpi_status * - * PARAMETERS: Flags - Lock the hardware or not + * PARAMETERS: None * - * RETURN: none + * RETURN: None * * DESCRIPTION: Clears all fixed and general purpose status bits * THIS FUNCTION MUST BE CALLED WITH INTERRUPTS DISABLED * - * NOTE: TBD: Flags parameter is obsolete, to be removed - * ******************************************************************************/ -acpi_status acpi_hw_clear_acpi_status(u32 flags) +acpi_status acpi_hw_clear_acpi_status(void) { acpi_status status; acpi_cpu_flags lock_flags = 0; @@ -73,7 +71,7 @@ acpi_status acpi_hw_clear_acpi_status(u3 ACPI_DEBUG_PRINT((ACPI_DB_IO, "About to write %04X to %04X\n", ACPI_BITMASK_ALL_FIXED_STATUS, - (u16) acpi_gbl_FADT->xpm1a_evt_blk.address)); + (u16) acpi_gbl_FADT.xpm1a_event_block.address)); lock_flags = acpi_os_acquire_lock(acpi_gbl_hardware_lock); @@ -86,10 +84,10 @@ acpi_status acpi_hw_clear_acpi_status(u3 /* Clear the fixed events */ - if (acpi_gbl_FADT->xpm1b_evt_blk.address) { + if (acpi_gbl_FADT.xpm1b_event_block.address) { status = acpi_hw_low_level_write(16, ACPI_BITMASK_ALL_FIXED_STATUS, - &acpi_gbl_FADT->xpm1b_evt_blk); + &acpi_gbl_FADT.xpm1b_event_block); if (ACPI_FAILURE(status)) { goto unlock_and_exit; } @@ -253,18 +251,15 @@ struct acpi_bit_register_info *acpi_hw_g * * PARAMETERS: register_id - ID of ACPI bit_register to access * return_value - Value that was read from the register - * Flags - Lock the hardware or not * * RETURN: Status and the value read from specified Register. Value * returned is normalized to bit0 (is shifted all the way right) * * DESCRIPTION: ACPI bit_register read function. * - * NOTE: TBD: Flags parameter is obsolete, to be removed - * ******************************************************************************/ -acpi_status acpi_get_register(u32 register_id, u32 * return_value, u32 flags) +acpi_status acpi_get_register(u32 register_id, u32 * return_value) { u32 register_value = 0; struct acpi_bit_register_info *bit_reg_info; @@ -312,16 +307,13 @@ ACPI_EXPORT_SYMBOL(acpi_get_register) * PARAMETERS: register_id - ID of ACPI bit_register to access * Value - (only used on write) value to write to the * Register, NOT pre-normalized to the bit pos - * Flags - Lock the hardware or not * * RETURN: Status * * DESCRIPTION: ACPI Bit Register write function. * - * NOTE: TBD: Flags parameter is obsolete, to be removed - * ******************************************************************************/ -acpi_status acpi_set_register(u32 register_id, u32 value, u32 flags) +acpi_status acpi_set_register(u32 register_id, u32 value) { u32 register_value = 0; struct acpi_bit_register_info *bit_reg_info; @@ -422,8 +414,9 @@ acpi_status acpi_set_register(u32 regist ACPI_DEBUG_PRINT((ACPI_DB_IO, "PM2 control: Read %X from %8.8X%8.8X\n", register_value, - ACPI_FORMAT_UINT64(acpi_gbl_FADT-> - xpm2_cnt_blk.address))); + ACPI_FORMAT_UINT64(acpi_gbl_FADT. + xpm2_control_block. + address))); ACPI_REGISTER_INSERT_VALUE(register_value, bit_reg_info->bit_position, @@ -433,8 +426,9 @@ acpi_status acpi_set_register(u32 regist ACPI_DEBUG_PRINT((ACPI_DB_IO, "About to write %4.4X to %8.8X%8.8X\n", register_value, - ACPI_FORMAT_UINT64(acpi_gbl_FADT-> - xpm2_cnt_blk.address))); + ACPI_FORMAT_UINT64(acpi_gbl_FADT. + xpm2_control_block. + address))); status = acpi_hw_register_write(ACPI_MTX_DO_NOT_LOCK, ACPI_REGISTER_PM2_CONTROL, @@ -495,7 +489,7 @@ acpi_hw_register_read(u8 use_lock, u32 r status = acpi_hw_low_level_read(16, &value1, - &acpi_gbl_FADT->xpm1a_evt_blk); + &acpi_gbl_FADT.xpm1a_event_block); if (ACPI_FAILURE(status)) { goto unlock_and_exit; } @@ -504,7 +498,7 @@ acpi_hw_register_read(u8 use_lock, u32 r status = acpi_hw_low_level_read(16, &value2, - &acpi_gbl_FADT->xpm1b_evt_blk); + &acpi_gbl_FADT.xpm1b_event_block); value1 |= value2; break; @@ -527,14 +521,14 @@ acpi_hw_register_read(u8 use_lock, u32 r status = acpi_hw_low_level_read(16, &value1, - &acpi_gbl_FADT->xpm1a_cnt_blk); + &acpi_gbl_FADT.xpm1a_control_block); if (ACPI_FAILURE(status)) { goto unlock_and_exit; } status = acpi_hw_low_level_read(16, &value2, - &acpi_gbl_FADT->xpm1b_cnt_blk); + &acpi_gbl_FADT.xpm1b_control_block); value1 |= value2; break; @@ -542,19 +536,20 @@ acpi_hw_register_read(u8 use_lock, u32 r status = acpi_hw_low_level_read(8, &value1, - &acpi_gbl_FADT->xpm2_cnt_blk); + &acpi_gbl_FADT.xpm2_control_block); break; case ACPI_REGISTER_PM_TIMER: /* 32-bit access */ status = acpi_hw_low_level_read(32, &value1, - &acpi_gbl_FADT->xpm_tmr_blk); + &acpi_gbl_FADT.xpm_timer_block); break; case ACPI_REGISTER_SMI_COMMAND_BLOCK: /* 8-bit access */ - status = acpi_os_read_port(acpi_gbl_FADT->smi_cmd, &value1, 8); + status = + acpi_os_read_port(acpi_gbl_FADT.smi_command, &value1, 8); break; default: @@ -635,7 +630,7 @@ acpi_status acpi_hw_register_write(u8 us status = acpi_hw_low_level_write(16, value, - &acpi_gbl_FADT->xpm1a_evt_blk); + &acpi_gbl_FADT.xpm1a_event_block); if (ACPI_FAILURE(status)) { goto unlock_and_exit; } @@ -644,7 +639,7 @@ acpi_status acpi_hw_register_write(u8 us status = acpi_hw_low_level_write(16, value, - &acpi_gbl_FADT->xpm1b_evt_blk); + &acpi_gbl_FADT.xpm1b_event_block); break; case ACPI_REGISTER_PM1_ENABLE: /* 16-bit access */ @@ -682,49 +677,50 @@ acpi_status acpi_hw_register_write(u8 us status = acpi_hw_low_level_write(16, value, - &acpi_gbl_FADT->xpm1a_cnt_blk); + &acpi_gbl_FADT.xpm1a_control_block); if (ACPI_FAILURE(status)) { goto unlock_and_exit; } status = acpi_hw_low_level_write(16, value, - &acpi_gbl_FADT->xpm1b_cnt_blk); + &acpi_gbl_FADT.xpm1b_control_block); break; case ACPI_REGISTER_PM1A_CONTROL: /* 16-bit access */ status = acpi_hw_low_level_write(16, value, - &acpi_gbl_FADT->xpm1a_cnt_blk); + &acpi_gbl_FADT.xpm1a_control_block); break; case ACPI_REGISTER_PM1B_CONTROL: /* 16-bit access */ status = acpi_hw_low_level_write(16, value, - &acpi_gbl_FADT->xpm1b_cnt_blk); + &acpi_gbl_FADT.xpm1b_control_block); break; case ACPI_REGISTER_PM2_CONTROL: /* 8-bit access */ status = acpi_hw_low_level_write(8, value, - &acpi_gbl_FADT->xpm2_cnt_blk); + &acpi_gbl_FADT.xpm2_control_block); break; case ACPI_REGISTER_PM_TIMER: /* 32-bit access */ status = acpi_hw_low_level_write(32, value, - &acpi_gbl_FADT->xpm_tmr_blk); + &acpi_gbl_FADT.xpm_timer_block); break; case ACPI_REGISTER_SMI_COMMAND_BLOCK: /* 8-bit access */ /* SMI_CMD is currently always in IO space */ - status = acpi_os_write_port(acpi_gbl_FADT->smi_cmd, value, 8); + status = + acpi_os_write_port(acpi_gbl_FADT.smi_command, value, 8); break; default: @@ -783,7 +779,7 @@ acpi_hw_low_level_read(u32 width, u32 * * Two address spaces supported: Memory or IO. * PCI_Config is not supported here because the GAS struct is insufficient */ - switch (reg->address_space_id) { + switch (reg->space_id) { case ACPI_ADR_SPACE_SYSTEM_MEMORY: status = acpi_os_read_memory((acpi_physical_address) address, @@ -792,22 +788,20 @@ acpi_hw_low_level_read(u32 width, u32 * case ACPI_ADR_SPACE_SYSTEM_IO: - status = acpi_os_read_port((acpi_io_address) address, - value, width); + status = + acpi_os_read_port((acpi_io_address) address, value, width); break; default: ACPI_ERROR((AE_INFO, - "Unsupported address space: %X", - reg->address_space_id)); + "Unsupported address space: %X", reg->space_id)); return (AE_BAD_PARAMETER); } ACPI_DEBUG_PRINT((ACPI_DB_IO, "Read: %8.8X width %2d from %8.8X%8.8X (%s)\n", - *value, width, - ACPI_FORMAT_UINT64(address), - acpi_ut_get_region_name(reg->address_space_id))); + *value, width, ACPI_FORMAT_UINT64(address), + acpi_ut_get_region_name(reg->space_id))); return (status); } @@ -854,7 +848,7 @@ acpi_hw_low_level_write(u32 width, u32 v * Two address spaces supported: Memory or IO. * PCI_Config is not supported here because the GAS struct is insufficient */ - switch (reg->address_space_id) { + switch (reg->space_id) { case ACPI_ADR_SPACE_SYSTEM_MEMORY: status = acpi_os_write_memory((acpi_physical_address) address, @@ -863,22 +857,20 @@ acpi_hw_low_level_write(u32 width, u32 v case ACPI_ADR_SPACE_SYSTEM_IO: - status = acpi_os_write_port((acpi_io_address) address, - value, width); + status = acpi_os_write_port((acpi_io_address) address, value, + width); break; default: ACPI_ERROR((AE_INFO, - "Unsupported address space: %X", - reg->address_space_id)); + "Unsupported address space: %X", reg->space_id)); return (AE_BAD_PARAMETER); } ACPI_DEBUG_PRINT((ACPI_DB_IO, "Wrote: %8.8X width %2d to %8.8X%8.8X (%s)\n", - value, width, - ACPI_FORMAT_UINT64(address), - acpi_ut_get_region_name(reg->address_space_id))); + value, width, ACPI_FORMAT_UINT64(address), + acpi_ut_get_region_name(reg->space_id))); return (status); } diff --git a/drivers/acpi/hardware/hwsleep.c b/drivers/acpi/hardware/hwsleep.c index 8bb43ca..57901ca 100644 --- a/drivers/acpi/hardware/hwsleep.c +++ b/drivers/acpi/hardware/hwsleep.c @@ -6,7 +6,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2006, R. Byron Moore + * Copyright (C) 2000 - 2007, R. Byron Moore * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -43,6 +43,7 @@ */ #include +#include #define _COMPONENT ACPI_HARDWARE ACPI_MODULE_NAME("hwsleep") @@ -62,17 +63,32 @@ ACPI_MODULE_NAME("hwsleep") acpi_status acpi_set_firmware_waking_vector(acpi_physical_address physical_address) { + struct acpi_table_facs *facs; + acpi_status status; ACPI_FUNCTION_TRACE(acpi_set_firmware_waking_vector); + /* Get the FACS */ + + status = + acpi_get_table_by_index(ACPI_TABLE_INDEX_FACS, + (struct acpi_table_header **)&facs); + if (ACPI_FAILURE(status)) { + return_ACPI_STATUS(status); + } + /* Set the vector */ - if (acpi_gbl_common_fACS.vector_width == 32) { - *(ACPI_CAST_PTR - (u32, acpi_gbl_common_fACS.firmware_waking_vector)) - = (u32) physical_address; + if ((facs->length < 32) || (!(facs->xfirmware_waking_vector))) { + /* + * ACPI 1.0 FACS or short table or optional X_ field is zero + */ + facs->firmware_waking_vector = (u32) physical_address; } else { - *acpi_gbl_common_fACS.firmware_waking_vector = physical_address; + /* + * ACPI 2.0 FACS with valid X_ field + */ + facs->xfirmware_waking_vector = physical_address; } return_ACPI_STATUS(AE_OK); @@ -97,6 +113,8 @@ #ifdef ACPI_FUTURE_USAGE acpi_status acpi_get_firmware_waking_vector(acpi_physical_address * physical_address) { + struct acpi_table_facs *facs; + acpi_status status; ACPI_FUNCTION_TRACE(acpi_get_firmware_waking_vector); @@ -104,16 +122,29 @@ acpi_get_firmware_waking_vector(acpi_phy return_ACPI_STATUS(AE_BAD_PARAMETER); } + /* Get the FACS */ + + status = + acpi_get_table_by_index(ACPI_TABLE_INDEX_FACS, + (struct acpi_table_header **)&facs); + if (ACPI_FAILURE(status)) { + return_ACPI_STATUS(status); + } + /* Get the vector */ - if (acpi_gbl_common_fACS.vector_width == 32) { - *physical_address = (acpi_physical_address) - * - (ACPI_CAST_PTR - (u32, acpi_gbl_common_fACS.firmware_waking_vector)); + if ((facs->length < 32) || (!(facs->xfirmware_waking_vector))) { + /* + * ACPI 1.0 FACS or short table or optional X_ field is zero + */ + *physical_address = + (acpi_physical_address) facs->firmware_waking_vector; } else { + /* + * ACPI 2.0 FACS with valid X_ field + */ *physical_address = - *acpi_gbl_common_fACS.firmware_waking_vector; + (acpi_physical_address) facs->xfirmware_waking_vector; } return_ACPI_STATUS(AE_OK); @@ -246,15 +277,14 @@ acpi_status asmlinkage acpi_enter_sleep_ /* Clear wake status */ - status = - acpi_set_register(ACPI_BITREG_WAKE_STATUS, 1, ACPI_MTX_DO_NOT_LOCK); + status = acpi_set_register(ACPI_BITREG_WAKE_STATUS, 1); if (ACPI_FAILURE(status)) { return_ACPI_STATUS(status); } /* Clear all fixed and general purpose status bits */ - status = acpi_hw_clear_acpi_status(ACPI_MTX_DO_NOT_LOCK); + status = acpi_hw_clear_acpi_status(); if (ACPI_FAILURE(status)) { return_ACPI_STATUS(status); } @@ -367,8 +397,7 @@ acpi_status asmlinkage acpi_enter_sleep_ /* Wait until we enter sleep state */ do { - status = acpi_get_register(ACPI_BITREG_WAKE_STATUS, &in_value, - ACPI_MTX_DO_NOT_LOCK); + status = acpi_get_register(ACPI_BITREG_WAKE_STATUS, &in_value); if (ACPI_FAILURE(status)) { return_ACPI_STATUS(status); } @@ -401,13 +430,12 @@ acpi_status asmlinkage acpi_enter_sleep_ ACPI_FUNCTION_TRACE(acpi_enter_sleep_state_s4bios); - status = - acpi_set_register(ACPI_BITREG_WAKE_STATUS, 1, ACPI_MTX_DO_NOT_LOCK); + status = acpi_set_register(ACPI_BITREG_WAKE_STATUS, 1); if (ACPI_FAILURE(status)) { return_ACPI_STATUS(status); } - status = acpi_hw_clear_acpi_status(ACPI_MTX_DO_NOT_LOCK); + status = acpi_hw_clear_acpi_status(); if (ACPI_FAILURE(status)) { return_ACPI_STATUS(status); } @@ -429,13 +457,12 @@ acpi_status asmlinkage acpi_enter_sleep_ ACPI_FLUSH_CPU_CACHE(); - status = acpi_os_write_port(acpi_gbl_FADT->smi_cmd, - (u32) acpi_gbl_FADT->S4bios_req, 8); + status = acpi_os_write_port(acpi_gbl_FADT.smi_command, + (u32) acpi_gbl_FADT.S4bios_request, 8); do { acpi_os_stall(1000); - status = acpi_get_register(ACPI_BITREG_WAKE_STATUS, &in_value, - ACPI_MTX_DO_NOT_LOCK); + status = acpi_get_register(ACPI_BITREG_WAKE_STATUS, &in_value); if (ACPI_FAILURE(status)) { return_ACPI_STATUS(status); } @@ -568,13 +595,11 @@ acpi_status acpi_leave_sleep_state(u8 sl (void) acpi_set_register(acpi_gbl_fixed_event_info - [ACPI_EVENT_POWER_BUTTON].enable_register_id, 1, - ACPI_MTX_DO_NOT_LOCK); + [ACPI_EVENT_POWER_BUTTON].enable_register_id, 1); (void) acpi_set_register(acpi_gbl_fixed_event_info - [ACPI_EVENT_POWER_BUTTON].status_register_id, 1, - ACPI_MTX_DO_NOT_LOCK); + [ACPI_EVENT_POWER_BUTTON].status_register_id, 1); arg.integer.value = ACPI_SST_WORKING; status = acpi_evaluate_object(NULL, METHOD_NAME__SST, &arg_list, NULL); diff --git a/drivers/acpi/hardware/hwtimer.c b/drivers/acpi/hardware/hwtimer.c index c4ec47c..c32eab6 100644 --- a/drivers/acpi/hardware/hwtimer.c +++ b/drivers/acpi/hardware/hwtimer.c @@ -6,7 +6,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2006, R. Byron Moore + * Copyright (C) 2000 - 2007, R. Byron Moore * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -66,7 +66,7 @@ acpi_status acpi_get_timer_resolution(u3 return_ACPI_STATUS(AE_BAD_PARAMETER); } - if (acpi_gbl_FADT->tmr_val_ext == 0) { + if ((acpi_gbl_FADT.flags & ACPI_FADT_32BIT_TIMER) == 0) { *resolution = 24; } else { *resolution = 32; @@ -98,7 +98,8 @@ acpi_status acpi_get_timer(u32 * ticks) return_ACPI_STATUS(AE_BAD_PARAMETER); } - status = acpi_hw_low_level_read(32, ticks, &acpi_gbl_FADT->xpm_tmr_blk); + status = + acpi_hw_low_level_read(32, ticks, &acpi_gbl_FADT.xpm_timer_block); return_ACPI_STATUS(status); } @@ -153,7 +154,7 @@ acpi_get_timer_duration(u32 start_ticks, if (start_ticks < end_ticks) { delta_ticks = end_ticks - start_ticks; } else if (start_ticks > end_ticks) { - if (acpi_gbl_FADT->tmr_val_ext == 0) { + if ((acpi_gbl_FADT.flags & ACPI_FADT_32BIT_TIMER) == 0) { /* 24-bit Timer */ diff --git a/drivers/acpi/i2c_ec.c b/drivers/acpi/i2c_ec.c index 8338be0..76ec8b6 100644 --- a/drivers/acpi/i2c_ec.c +++ b/drivers/acpi/i2c_ec.c @@ -14,7 +14,6 @@ #include #include #include #include -#include #include #include #include @@ -340,6 +339,7 @@ static int acpi_ec_hc_add(struct acpi_de smbus->adapter.owner = THIS_MODULE; smbus->adapter.algo = &acpi_ec_smbus_algorithm; smbus->adapter.algo_data = smbus; + smbus->adapter.dev.parent = &device->dev; if (i2c_add_adapter(&smbus->adapter)) { ACPI_DEBUG_PRINT((ACPI_DB_WARN, diff --git a/drivers/acpi/motherboard.c b/drivers/acpi/motherboard.c deleted file mode 100644 index 2e17ec7..0000000 --- a/drivers/acpi/motherboard.c +++ /dev/null @@ -1,191 +0,0 @@ -/* - * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or (at - * your option) any later version. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. - * - * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - */ - -/* Purpose: Prevent PCMCIA cards from using motherboard resources. */ - -#include -#include -#include -#include -#include -#include - -#include -#include - -#define _COMPONENT ACPI_SYSTEM_COMPONENT -ACPI_MODULE_NAME("acpi_motherboard") - -/* Dell use PNP0C01 instead of PNP0C02 */ -#define ACPI_MB_HID1 "PNP0C01" -#define ACPI_MB_HID2 "PNP0C02" -/** - * Doesn't care about legacy IO ports, only IO ports beyond 0x1000 are reserved - * Doesn't care about the failure of 'request_region', since other may reserve - * the io ports as well - */ -#define IS_RESERVED_ADDR(base, len) \ - (((len) > 0) && ((base) > 0) && ((base) + (len) < IO_SPACE_LIMIT) \ - && ((base) + (len) > PCIBIOS_MIN_IO)) -/* - * Clearing the flag (IORESOURCE_BUSY) allows drivers to use - * the io ports if they really know they can use it, while - * still preventing hotplug PCI devices from using it. - */ - -/* - * When CONFIG_PNP is enabled, pnp/system.c binds to PNP0C01 - * and PNP0C02, redundant with acpi_reserve_io_ranges(). - * But acpi_reserve_io_ranges() is necessary for !CONFIG_PNP. - */ -static acpi_status acpi_reserve_io_ranges(struct acpi_resource *res, void *data) -{ - struct resource *requested_res = NULL; - - - if (res->type == ACPI_RESOURCE_TYPE_IO) { - struct acpi_resource_io *io_res = &res->data.io; - - if (io_res->minimum != io_res->maximum) - return AE_OK; - if (IS_RESERVED_ADDR - (io_res->minimum, io_res->address_length)) { - ACPI_DEBUG_PRINT((ACPI_DB_INFO, - "Motherboard resources 0x%08x - 0x%08x\n", - io_res->minimum, - io_res->minimum + - io_res->address_length)); - requested_res = - request_region(io_res->minimum, - io_res->address_length, "motherboard"); - } - } else if (res->type == ACPI_RESOURCE_TYPE_FIXED_IO) { - struct acpi_resource_fixed_io *fixed_io_res = - &res->data.fixed_io; - - if (IS_RESERVED_ADDR - (fixed_io_res->address, fixed_io_res->address_length)) { - ACPI_DEBUG_PRINT((ACPI_DB_INFO, - "Motherboard resources 0x%08x - 0x%08x\n", - fixed_io_res->address, - fixed_io_res->address + - fixed_io_res->address_length)); - requested_res = - request_region(fixed_io_res->address, - fixed_io_res->address_length, - "motherboard"); - } - } else { - /* Memory mapped IO? */ - } - - if (requested_res) - requested_res->flags &= ~IORESOURCE_BUSY; - return AE_OK; -} - -static int acpi_motherboard_add(struct acpi_device *device) -{ - if (!device) - return -EINVAL; - acpi_walk_resources(device->handle, METHOD_NAME__CRS, - acpi_reserve_io_ranges, NULL); - - return 0; -} - -static struct acpi_driver acpi_motherboard_driver1 = { - .name = "motherboard", - .class = "", - .ids = ACPI_MB_HID1, - .ops = { - .add = acpi_motherboard_add, - }, -}; - -static struct acpi_driver acpi_motherboard_driver2 = { - .name = "motherboard", - .class = "", - .ids = ACPI_MB_HID2, - .ops = { - .add = acpi_motherboard_add, - }, -}; - -static void __init acpi_request_region (struct acpi_generic_address *addr, - unsigned int length, char *desc) -{ - if (!addr->address || !length) - return; - - if (addr->address_space_id == ACPI_ADR_SPACE_SYSTEM_IO) - request_region(addr->address, length, desc); - else if (addr->address_space_id == ACPI_ADR_SPACE_SYSTEM_MEMORY) - request_mem_region(addr->address, length, desc); -} - -static void __init acpi_reserve_resources(void) -{ - acpi_request_region(&acpi_gbl_FADT->xpm1a_evt_blk, - acpi_gbl_FADT->pm1_evt_len, "ACPI PM1a_EVT_BLK"); - - acpi_request_region(&acpi_gbl_FADT->xpm1b_evt_blk, - acpi_gbl_FADT->pm1_evt_len, "ACPI PM1b_EVT_BLK"); - - acpi_request_region(&acpi_gbl_FADT->xpm1a_cnt_blk, - acpi_gbl_FADT->pm1_cnt_len, "ACPI PM1a_CNT_BLK"); - - acpi_request_region(&acpi_gbl_FADT->xpm1b_cnt_blk, - acpi_gbl_FADT->pm1_cnt_len, "ACPI PM1b_CNT_BLK"); - - if (acpi_gbl_FADT->pm_tm_len == 4) - acpi_request_region(&acpi_gbl_FADT->xpm_tmr_blk, 4, "ACPI PM_TMR"); - - acpi_request_region(&acpi_gbl_FADT->xpm2_cnt_blk, - acpi_gbl_FADT->pm2_cnt_len, "ACPI PM2_CNT_BLK"); - - /* Length of GPE blocks must be a non-negative multiple of 2 */ - - if (!(acpi_gbl_FADT->gpe0_blk_len & 0x1)) - acpi_request_region(&acpi_gbl_FADT->xgpe0_blk, - acpi_gbl_FADT->gpe0_blk_len, "ACPI GPE0_BLK"); - - if (!(acpi_gbl_FADT->gpe1_blk_len & 0x1)) - acpi_request_region(&acpi_gbl_FADT->xgpe1_blk, - acpi_gbl_FADT->gpe1_blk_len, "ACPI GPE1_BLK"); -} - -static int __init acpi_motherboard_init(void) -{ - acpi_bus_register_driver(&acpi_motherboard_driver1); - acpi_bus_register_driver(&acpi_motherboard_driver2); - /* - * Guarantee motherboard IO reservation first - * This module must run after scan.c - */ - if (!acpi_disabled) - acpi_reserve_resources(); - return 0; -} - -/** - * Reserve motherboard resources after PCI claim BARs, - * but before PCI assign resources for uninitialized PCI devices - */ -fs_initcall(acpi_motherboard_init); diff --git a/drivers/acpi/namespace/nsaccess.c b/drivers/acpi/namespace/nsaccess.c index c1c6c23..57faf59 100644 --- a/drivers/acpi/namespace/nsaccess.c +++ b/drivers/acpi/namespace/nsaccess.c @@ -5,7 +5,7 @@ ******************************************************************************/ /* - * Copyright (C) 2000 - 2006, R. Byron Moore + * Copyright (C) 2000 - 2007, R. Byron Moore * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -195,31 +195,27 @@ #endif obj_desc->mutex.sync_level = (u8) (ACPI_TO_INTEGER(val) - 1); - if (ACPI_STRCMP(init_val->name, "_GL_") == 0) { + /* Create a mutex */ - /* Create a counting semaphore for the global lock */ + status = + acpi_os_create_mutex(&obj_desc->mutex. + os_mutex); + if (ACPI_FAILURE(status)) { + acpi_ut_remove_reference(obj_desc); + goto unlock_and_exit; + } - status = - acpi_os_create_semaphore - (ACPI_NO_UNIT_LIMIT, 1, - &acpi_gbl_global_lock_semaphore); - if (ACPI_FAILURE(status)) { - acpi_ut_remove_reference - (obj_desc); - goto unlock_and_exit; - } + /* Special case for ACPI Global Lock */ - /* Mark this mutex as very special */ + if (ACPI_STRCMP(init_val->name, "_GL_") == 0) { + acpi_gbl_global_lock_mutex = + obj_desc->mutex.os_mutex; - obj_desc->mutex.os_mutex = - ACPI_GLOBAL_LOCK; - } else { - /* Create a mutex */ + /* Create additional counting semaphore for global lock */ status = - acpi_os_create_mutex(&obj_desc-> - mutex. - os_mutex); + acpi_os_create_semaphore(1, 0, + &acpi_gbl_global_lock_semaphore); if (ACPI_FAILURE(status)) { acpi_ut_remove_reference (obj_desc); diff --git a/drivers/acpi/namespace/nsalloc.c b/drivers/acpi/namespace/nsalloc.c index 55b407a..1d693d8 100644 --- a/drivers/acpi/namespace/nsalloc.c +++ b/drivers/acpi/namespace/nsalloc.c @@ -5,7 +5,7 @@ ******************************************************************************/ /* - * Copyright (C) 2000 - 2006, R. Byron Moore + * Copyright (C) 2000 - 2007, R. Byron Moore * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -61,6 +61,9 @@ ACPI_MODULE_NAME("nsalloc") struct acpi_namespace_node *acpi_ns_create_node(u32 name) { struct acpi_namespace_node *node; +#ifdef ACPI_DBG_TRACK_ALLOCATIONS + u32 temp; +#endif ACPI_FUNCTION_TRACE(ns_create_node); @@ -71,6 +74,15 @@ struct acpi_namespace_node *acpi_ns_crea ACPI_MEM_TRACKING(acpi_gbl_ns_node_list->total_allocated++); +#ifdef ACPI_DBG_TRACK_ALLOCATIONS + temp = + acpi_gbl_ns_node_list->total_allocated - + acpi_gbl_ns_node_list->total_freed; + if (temp > acpi_gbl_ns_node_list->max_occupied) { + acpi_gbl_ns_node_list->max_occupied = temp; + } +#endif + node->name.integer = name; ACPI_SET_DESCRIPTOR_TYPE(node, ACPI_DESC_TYPE_NAMED); return_PTR(node); diff --git a/drivers/acpi/namespace/nsdump.c b/drivers/acpi/namespace/nsdump.c index d72df66..1fc4f86 100644 --- a/drivers/acpi/namespace/nsdump.c +++ b/drivers/acpi/namespace/nsdump.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2006, R. Byron Moore + * Copyright (C) 2000 - 2007, R. Byron Moore * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -205,7 +205,7 @@ acpi_ns_dump_one_object(acpi_handle obj_ if (!acpi_ut_valid_acpi_name(this_node->name.integer)) { this_node->name.integer = - acpi_ut_repair_name(this_node->name.integer); + acpi_ut_repair_name(this_node->name.ascii); ACPI_WARNING((AE_INFO, "Invalid ACPI Name %08X", this_node->name.integer)); @@ -226,6 +226,12 @@ acpi_ns_dump_one_object(acpi_handle obj_ obj_desc = acpi_ns_get_attached_object(this_node); acpi_dbg_level = dbg_level; + /* Temp nodes are those nodes created by a control method */ + + if (this_node->flags & ANOBJ_TEMPORARY) { + acpi_os_printf("(T) "); + } + switch (info->display_type & ACPI_DISPLAY_MASK) { case ACPI_DISPLAY_SUMMARY: @@ -623,7 +629,8 @@ acpi_ns_dump_objects(acpi_object_type ty info.display_type = display_type; (void)acpi_ns_walk_namespace(type, start_handle, max_depth, - ACPI_NS_WALK_NO_UNLOCK, + ACPI_NS_WALK_NO_UNLOCK | + ACPI_NS_WALK_TEMP_NODES, acpi_ns_dump_one_object, (void *)&info, NULL); } diff --git a/drivers/acpi/namespace/nsdumpdv.c b/drivers/acpi/namespace/nsdumpdv.c index c6bf5d3..5097e16 100644 --- a/drivers/acpi/namespace/nsdumpdv.c +++ b/drivers/acpi/namespace/nsdumpdv.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2006, R. Byron Moore + * Copyright (C) 2000 - 2007, R. Byron Moore * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/namespace/nseval.c b/drivers/acpi/namespace/nseval.c index 4b0a4a8..aa6370c 100644 --- a/drivers/acpi/namespace/nseval.c +++ b/drivers/acpi/namespace/nseval.c @@ -5,7 +5,7 @@ ******************************************************************************/ /* - * Copyright (C) 2000 - 2006, R. Byron Moore + * Copyright (C) 2000 - 2007, R. Byron Moore * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -154,11 +154,7 @@ acpi_status acpi_ns_evaluate(struct acpi * Execute the method via the interpreter. The interpreter is locked * here before calling into the AML parser */ - status = acpi_ex_enter_interpreter(); - if (ACPI_FAILURE(status)) { - return_ACPI_STATUS(status); - } - + acpi_ex_enter_interpreter(); status = acpi_ps_execute_method(info); acpi_ex_exit_interpreter(); } else { @@ -182,10 +178,7 @@ acpi_status acpi_ns_evaluate(struct acpi * resolution, we must lock it because we could access an opregion. * The opregion access code assumes that the interpreter is locked. */ - status = acpi_ex_enter_interpreter(); - if (ACPI_FAILURE(status)) { - return_ACPI_STATUS(status); - } + acpi_ex_enter_interpreter(); /* Function has a strange interface */ diff --git a/drivers/acpi/namespace/nsinit.c b/drivers/acpi/namespace/nsinit.c index aec8488..33db224 100644 --- a/drivers/acpi/namespace/nsinit.c +++ b/drivers/acpi/namespace/nsinit.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2006, R. Byron Moore + * Copyright (C) 2000 - 2007, R. Byron Moore * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -45,6 +45,7 @@ #include #include #include #include +#include #define _COMPONENT ACPI_NAMESPACE ACPI_MODULE_NAME("nsinit") @@ -213,7 +214,7 @@ acpi_ns_init_one_object(acpi_handle obj_ u32 level, void *context, void **return_value) { acpi_object_type type; - acpi_status status; + acpi_status status = AE_OK; struct acpi_init_walk_info *info = (struct acpi_init_walk_info *)context; struct acpi_namespace_node *node = @@ -267,10 +268,7 @@ acpi_ns_init_one_object(acpi_handle obj_ /* * Must lock the interpreter before executing AML code */ - status = acpi_ex_enter_interpreter(); - if (ACPI_FAILURE(status)) { - return (status); - } + acpi_ex_enter_interpreter(); /* * Each of these types can contain executable AML code within the @@ -537,7 +535,15 @@ acpi_ns_init_one_device(acpi_handle obj_ info->parameter_type = ACPI_PARAM_ARGS; info->flags = ACPI_IGNORE_RETURN_VALUE; + /* + * Some hardware relies on this being executed as atomically + * as possible (without an NMI being received in the middle of + * this) - so disable NMIs and initialize the device: + */ + acpi_nmi_disable(); status = acpi_ns_evaluate(info); + acpi_nmi_enable(); + if (ACPI_SUCCESS(status)) { walk_info->num_INI++; diff --git a/drivers/acpi/namespace/nsload.c b/drivers/acpi/namespace/nsload.c index fe75d88..d4f9654 100644 --- a/drivers/acpi/namespace/nsload.c +++ b/drivers/acpi/namespace/nsload.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2006, R. Byron Moore + * Copyright (C) 2000 - 2007, R. Byron Moore * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -44,13 +44,12 @@ #include #include #include +#include #define _COMPONENT ACPI_NAMESPACE ACPI_MODULE_NAME("nsload") /* Local prototypes */ -static acpi_status acpi_ns_load_table_by_type(acpi_table_type table_type); - #ifdef ACPI_FUTURE_IMPLEMENTATION acpi_status acpi_ns_unload_namespace(acpi_handle handle); @@ -62,7 +61,7 @@ #ifndef ACPI_NO_METHOD_EXECUTION * * FUNCTION: acpi_ns_load_table * - * PARAMETERS: table_desc - Descriptor for table to be loaded + * PARAMETERS: table_index - Index for table to be loaded * Node - Owning NS node * * RETURN: Status @@ -72,42 +71,13 @@ #ifndef ACPI_NO_METHOD_EXECUTION ******************************************************************************/ acpi_status -acpi_ns_load_table(struct acpi_table_desc *table_desc, +acpi_ns_load_table(acpi_native_uint table_index, struct acpi_namespace_node *node) { acpi_status status; ACPI_FUNCTION_TRACE(ns_load_table); - /* Check if table contains valid AML (must be DSDT, PSDT, SSDT, etc.) */ - - if (! - (acpi_gbl_table_data[table_desc->type]. - flags & ACPI_TABLE_EXECUTABLE)) { - - /* Just ignore this table */ - - return_ACPI_STATUS(AE_OK); - } - - /* Check validity of the AML start and length */ - - if (!table_desc->aml_start) { - ACPI_ERROR((AE_INFO, "Null AML pointer")); - return_ACPI_STATUS(AE_BAD_PARAMETER); - } - - ACPI_DEBUG_PRINT((ACPI_DB_INFO, "AML block at %p\n", - table_desc->aml_start)); - - /* Ignore table if there is no AML contained within */ - - if (!table_desc->aml_length) { - ACPI_WARNING((AE_INFO, "Zero-length AML block in table [%4.4s]", - table_desc->pointer->signature)); - return_ACPI_STATUS(AE_OK); - } - /* * Parse the table and load the namespace with all named * objects found within. Control methods are NOT parsed @@ -117,15 +87,34 @@ acpi_ns_load_table(struct acpi_table_des * to another control method, we can't continue parsing * because we don't know how many arguments to parse next! */ + status = acpi_ut_acquire_mutex(ACPI_MTX_NAMESPACE); + if (ACPI_FAILURE(status)) { + return_ACPI_STATUS(status); + } + + /* If table already loaded into namespace, just return */ + + if (acpi_tb_is_table_loaded(table_index)) { + status = AE_ALREADY_EXISTS; + goto unlock; + } + ACPI_DEBUG_PRINT((ACPI_DB_INFO, "**** Loading table into namespace ****\n")); - status = acpi_ut_acquire_mutex(ACPI_MTX_NAMESPACE); + status = acpi_tb_allocate_owner_id(table_index); if (ACPI_FAILURE(status)) { - return_ACPI_STATUS(status); + goto unlock; + } + + status = acpi_ns_parse_table(table_index, node->child); + if (ACPI_SUCCESS(status)) { + acpi_tb_set_table_loaded_flag(table_index, TRUE); + } else { + acpi_tb_release_owner_id(table_index); } - status = acpi_ns_parse_table(table_desc, node->child); + unlock: (void)acpi_ut_release_mutex(ACPI_MTX_NAMESPACE); if (ACPI_FAILURE(status)) { @@ -141,7 +130,7 @@ acpi_ns_load_table(struct acpi_table_des ACPI_DEBUG_PRINT((ACPI_DB_INFO, "**** Begin Table Method Parsing and Object Initialization ****\n")); - status = acpi_ds_initialize_objects(table_desc, node); + status = acpi_ds_initialize_objects(table_index, node); ACPI_DEBUG_PRINT((ACPI_DB_INFO, "**** Completed Table Method Parsing and Object Initialization ****\n")); @@ -149,99 +138,7 @@ acpi_ns_load_table(struct acpi_table_des return_ACPI_STATUS(status); } -/******************************************************************************* - * - * FUNCTION: acpi_ns_load_table_by_type - * - * PARAMETERS: table_type - Id of the table type to load - * - * RETURN: Status - * - * DESCRIPTION: Load an ACPI table or tables into the namespace. All tables - * of the given type are loaded. The mechanism allows this - * routine to be called repeatedly. - * - ******************************************************************************/ - -static acpi_status acpi_ns_load_table_by_type(acpi_table_type table_type) -{ - u32 i; - acpi_status status; - struct acpi_table_desc *table_desc; - - ACPI_FUNCTION_TRACE(ns_load_table_by_type); - - status = acpi_ut_acquire_mutex(ACPI_MTX_TABLES); - if (ACPI_FAILURE(status)) { - return_ACPI_STATUS(status); - } - - /* - * Table types supported are: - * DSDT (one), SSDT/PSDT (multiple) - */ - switch (table_type) { - case ACPI_TABLE_ID_DSDT: - - ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Namespace load: DSDT\n")); - - table_desc = acpi_gbl_table_lists[ACPI_TABLE_ID_DSDT].next; - - /* If table already loaded into namespace, just return */ - - if (table_desc->loaded_into_namespace) { - goto unlock_and_exit; - } - - /* Now load the single DSDT */ - - status = acpi_ns_load_table(table_desc, acpi_gbl_root_node); - if (ACPI_SUCCESS(status)) { - table_desc->loaded_into_namespace = TRUE; - } - break; - - case ACPI_TABLE_ID_SSDT: - case ACPI_TABLE_ID_PSDT: - - ACPI_DEBUG_PRINT((ACPI_DB_INFO, - "Namespace load: %d SSDT or PSDTs\n", - acpi_gbl_table_lists[table_type].count)); - - /* - * Traverse list of SSDT or PSDT tables - */ - table_desc = acpi_gbl_table_lists[table_type].next; - for (i = 0; i < acpi_gbl_table_lists[table_type].count; i++) { - /* - * Only attempt to load table into namespace if it is not - * already loaded! - */ - if (!table_desc->loaded_into_namespace) { - status = - acpi_ns_load_table(table_desc, - acpi_gbl_root_node); - if (ACPI_FAILURE(status)) { - break; - } - - table_desc->loaded_into_namespace = TRUE; - } - - table_desc = table_desc->next; - } - break; - - default: - status = AE_SUPPORT; - break; - } - - unlock_and_exit: - (void)acpi_ut_release_mutex(ACPI_MTX_TABLES); - return_ACPI_STATUS(status); -} - +#ifdef ACPI_OBSOLETE_FUNCTIONS /******************************************************************************* * * FUNCTION: acpi_load_namespace @@ -288,6 +185,7 @@ acpi_status acpi_ns_load_namespace(void) return_ACPI_STATUS(status); } +#endif #ifdef ACPI_FUTURE_IMPLEMENTATION /******************************************************************************* diff --git a/drivers/acpi/namespace/nsnames.c b/drivers/acpi/namespace/nsnames.c index 97b8332..cbd94af 100644 --- a/drivers/acpi/namespace/nsnames.c +++ b/drivers/acpi/namespace/nsnames.c @@ -5,7 +5,7 @@ ******************************************************************************/ /* - * Copyright (C) 2000 - 2006, R. Byron Moore + * Copyright (C) 2000 - 2007, R. Byron Moore * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/namespace/nsobject.c b/drivers/acpi/namespace/nsobject.c index aabe879..d9d7377 100644 --- a/drivers/acpi/namespace/nsobject.c +++ b/drivers/acpi/namespace/nsobject.c @@ -6,7 +6,7 @@ ******************************************************************************/ /* - * Copyright (C) 2000 - 2006, R. Byron Moore + * Copyright (C) 2000 - 2007, R. Byron Moore * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/namespace/nsparse.c b/drivers/acpi/namespace/nsparse.c index 155505a..e696aa8 100644 --- a/drivers/acpi/namespace/nsparse.c +++ b/drivers/acpi/namespace/nsparse.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2006, R. Byron Moore + * Copyright (C) 2000 - 2007, R. Byron Moore * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -45,6 +45,7 @@ #include #include #include #include +#include #define _COMPONENT ACPI_NAMESPACE ACPI_MODULE_NAME("nsparse") @@ -62,14 +63,24 @@ ACPI_MODULE_NAME("nsparse") * ******************************************************************************/ acpi_status -acpi_ns_one_complete_parse(u8 pass_number, struct acpi_table_desc *table_desc) +acpi_ns_one_complete_parse(acpi_native_uint pass_number, + acpi_native_uint table_index) { union acpi_parse_object *parse_root; acpi_status status; + acpi_native_uint aml_length; + u8 *aml_start; struct acpi_walk_state *walk_state; + struct acpi_table_header *table; + acpi_owner_id owner_id; ACPI_FUNCTION_TRACE(ns_one_complete_parse); + status = acpi_tb_get_owner_id(table_index, &owner_id); + if (ACPI_FAILURE(status)) { + return_ACPI_STATUS(status); + } + /* Create and init a Root Node */ parse_root = acpi_ps_create_scope_op(); @@ -79,26 +90,41 @@ acpi_ns_one_complete_parse(u8 pass_numbe /* Create and initialize a new walk state */ - walk_state = acpi_ds_create_walk_state(table_desc->owner_id, - NULL, NULL, NULL); + walk_state = acpi_ds_create_walk_state(owner_id, NULL, NULL, NULL); if (!walk_state) { acpi_ps_free_op(parse_root); return_ACPI_STATUS(AE_NO_MEMORY); } - status = acpi_ds_init_aml_walk(walk_state, parse_root, NULL, - table_desc->aml_start, - table_desc->aml_length, NULL, - pass_number); + status = acpi_get_table_by_index(table_index, &table); + if (ACPI_FAILURE(status)) { + acpi_ds_delete_walk_state(walk_state); + acpi_ps_free_op(parse_root); + return_ACPI_STATUS(status); + } + + /* Table must consist of at least a complete header */ + + if (table->length < sizeof(struct acpi_table_header)) { + status = AE_BAD_HEADER; + } else { + aml_start = (u8 *) table + sizeof(struct acpi_table_header); + aml_length = table->length - sizeof(struct acpi_table_header); + status = acpi_ds_init_aml_walk(walk_state, parse_root, NULL, + aml_start, aml_length, NULL, + (u8) pass_number); + } + if (ACPI_FAILURE(status)) { acpi_ds_delete_walk_state(walk_state); + acpi_ps_delete_parse_tree(parse_root); return_ACPI_STATUS(status); } /* Parse the AML */ ACPI_DEBUG_PRINT((ACPI_DB_PARSE, "*PARSE* pass %d parse\n", - pass_number)); + (unsigned)pass_number)); status = acpi_ps_parse_aml(walk_state); acpi_ps_delete_parse_tree(parse_root); @@ -119,7 +145,7 @@ acpi_ns_one_complete_parse(u8 pass_numbe ******************************************************************************/ acpi_status -acpi_ns_parse_table(struct acpi_table_desc *table_desc, +acpi_ns_parse_table(acpi_native_uint table_index, struct acpi_namespace_node *start_node) { acpi_status status; @@ -134,10 +160,10 @@ acpi_ns_parse_table(struct acpi_table_de * each Parser Op subtree is deleted when it is finished. This saves * a great deal of memory, and allows a small cache of parse objects * to service the entire parse. The second pass of the parse then - * performs another complete parse of the AML.. + * performs another complete parse of the AML. */ ACPI_DEBUG_PRINT((ACPI_DB_PARSE, "**** Start pass 1\n")); - status = acpi_ns_one_complete_parse(1, table_desc); + status = acpi_ns_one_complete_parse(ACPI_IMODE_LOAD_PASS1, table_index); if (ACPI_FAILURE(status)) { return_ACPI_STATUS(status); } @@ -152,7 +178,7 @@ acpi_ns_parse_table(struct acpi_table_de * parse objects are all cached. */ ACPI_DEBUG_PRINT((ACPI_DB_PARSE, "**** Start pass 2\n")); - status = acpi_ns_one_complete_parse(2, table_desc); + status = acpi_ns_one_complete_parse(ACPI_IMODE_LOAD_PASS2, table_index); if (ACPI_FAILURE(status)) { return_ACPI_STATUS(status); } diff --git a/drivers/acpi/namespace/nssearch.c b/drivers/acpi/namespace/nssearch.c index 500e2bb..e863be6 100644 --- a/drivers/acpi/namespace/nssearch.c +++ b/drivers/acpi/namespace/nssearch.c @@ -5,7 +5,7 @@ ******************************************************************************/ /* - * Copyright (C) 2000 - 2006, R. Byron Moore + * Copyright (C) 2000 - 2007, R. Byron Moore * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -321,7 +321,8 @@ acpi_ns_search_and_enter(u32 target_name * even though there are a few bad names. */ if (!acpi_ut_valid_acpi_name(target_name)) { - target_name = acpi_ut_repair_name(target_name); + target_name = + acpi_ut_repair_name(ACPI_CAST_PTR(char, &target_name)); /* Report warning only if in strict mode or debug mode */ @@ -401,6 +402,10 @@ #ifdef ACPI_ASL_COMPILER } #endif + if (flags & ACPI_NS_TEMPORARY) { + new_node->flags |= ANOBJ_TEMPORARY; + } + /* Install the new object into the parent's list of children */ acpi_ns_install_node(walk_state, node, new_node, type); diff --git a/drivers/acpi/namespace/nsutils.c b/drivers/acpi/namespace/nsutils.c index aa4e799..90fd059 100644 --- a/drivers/acpi/namespace/nsutils.c +++ b/drivers/acpi/namespace/nsutils.c @@ -6,7 +6,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2006, R. Byron Moore + * Copyright (C) 2000 - 2007, R. Byron Moore * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -770,13 +770,6 @@ void acpi_ns_terminate(void) } ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Namespace freed\n")); - - /* - * 2) Now we can delete the ACPI tables - */ - acpi_tb_delete_all_tables(); - ACPI_DEBUG_PRINT((ACPI_DB_INFO, "ACPI Tables freed\n")); - return_VOID; } diff --git a/drivers/acpi/namespace/nswalk.c b/drivers/acpi/namespace/nswalk.c index c8f6bef..94eb8f3 100644 --- a/drivers/acpi/namespace/nswalk.c +++ b/drivers/acpi/namespace/nswalk.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2006, R. Byron Moore + * Copyright (C) 2000 - 2007, R. Byron Moore * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -126,7 +126,7 @@ struct acpi_namespace_node *acpi_ns_get_ * PARAMETERS: Type - acpi_object_type to search for * start_node - Handle in namespace where search begins * max_depth - Depth to which search is to reach - * unlock_before_callback- Whether to unlock the NS before invoking + * Flags - Whether to unlock the NS before invoking * the callback routine * user_function - Called when an object of "Type" is found * Context - Passed to user function @@ -153,7 +153,7 @@ acpi_status acpi_ns_walk_namespace(acpi_object_type type, acpi_handle start_node, u32 max_depth, - u8 unlock_before_callback, + u32 flags, acpi_walk_callback user_function, void *context, void **return_value) { @@ -193,20 +193,34 @@ acpi_ns_walk_namespace(acpi_object_type acpi_ns_get_next_node(ACPI_TYPE_ANY, parent_node, child_node); if (child_node) { - /* - * Found node, Get the type if we are not - * searching for ANY - */ + + /* Found next child, get the type if we are not searching for ANY */ + if (type != ACPI_TYPE_ANY) { child_type = child_node->type; } - if (child_type == type) { + /* + * Ignore all temporary namespace nodes (created during control + * method execution) unless told otherwise. These temporary nodes + * can cause a race condition because they can be deleted during the + * execution of the user function (if the namespace is unlocked before + * invocation of the user function.) Only the debugger namespace dump + * will examine the temporary nodes. + */ + if ((child_node->flags & ANOBJ_TEMPORARY) && + !(flags & ACPI_NS_WALK_TEMP_NODES)) { + status = AE_CTRL_DEPTH; + } + + /* Type must match requested type */ + + else if (child_type == type) { /* - * Found a matching node, invoke the user - * callback function + * Found a matching node, invoke the user callback function. + * Unlock the namespace if flag is set. */ - if (unlock_before_callback) { + if (flags & ACPI_NS_WALK_UNLOCK) { mutex_status = acpi_ut_release_mutex (ACPI_MTX_NAMESPACE); @@ -216,10 +230,11 @@ acpi_ns_walk_namespace(acpi_object_type } } - status = user_function(child_node, level, - context, return_value); + status = + user_function(child_node, level, context, + return_value); - if (unlock_before_callback) { + if (flags & ACPI_NS_WALK_UNLOCK) { mutex_status = acpi_ut_acquire_mutex (ACPI_MTX_NAMESPACE); @@ -251,20 +266,17 @@ acpi_ns_walk_namespace(acpi_object_type } /* - * Depth first search: - * Attempt to go down another level in the namespace - * if we are allowed to. Don't go any further if we - * have reached the caller specified maximum depth - * or if the user function has specified that the - * maximum depth has been reached. + * Depth first search: Attempt to go down another level in the + * namespace if we are allowed to. Don't go any further if we have + * reached the caller specified maximum depth or if the user + * function has specified that the maximum depth has been reached. */ if ((level < max_depth) && (status != AE_CTRL_DEPTH)) { if (acpi_ns_get_next_node (ACPI_TYPE_ANY, child_node, NULL)) { - /* - * There is at least one child of this - * node, visit the onde - */ + + /* There is at least one child of this node, visit it */ + level++; parent_node = child_node; child_node = NULL; @@ -272,9 +284,8 @@ acpi_ns_walk_namespace(acpi_object_type } } else { /* - * No more children of this node (acpi_ns_get_next_node - * failed), go back upwards in the namespace tree to - * the node's parent. + * No more children of this node (acpi_ns_get_next_node failed), go + * back upwards in the namespace tree to the node's parent. */ level--; child_node = parent_node; diff --git a/drivers/acpi/namespace/nsxfeval.c b/drivers/acpi/namespace/nsxfeval.c index dca6799..7ac6ace 100644 --- a/drivers/acpi/namespace/nsxfeval.c +++ b/drivers/acpi/namespace/nsxfeval.c @@ -6,7 +6,7 @@ ******************************************************************************/ /* - * Copyright (C) 2000 - 2006, R. Byron Moore + * Copyright (C) 2000 - 2007, R. Byron Moore * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -170,7 +170,6 @@ acpi_evaluate_object(acpi_handle handle, struct acpi_buffer *return_buffer) { acpi_status status; - acpi_status status2; struct acpi_evaluate_info *info; acpi_size buffer_space_needed; u32 i; @@ -329,14 +328,12 @@ acpi_evaluate_object(acpi_handle handle, * Delete the internal return object. NOTE: Interpreter must be * locked to avoid race condition. */ - status2 = acpi_ex_enter_interpreter(); - if (ACPI_SUCCESS(status2)) { + acpi_ex_enter_interpreter(); - /* Remove one reference on the return object (should delete it) */ + /* Remove one reference on the return object (should delete it) */ - acpi_ut_remove_reference(info->return_object); - acpi_ex_exit_interpreter(); - } + acpi_ut_remove_reference(info->return_object); + acpi_ex_exit_interpreter(); } cleanup: diff --git a/drivers/acpi/namespace/nsxfname.c b/drivers/acpi/namespace/nsxfname.c index 978213a..b489781 100644 --- a/drivers/acpi/namespace/nsxfname.c +++ b/drivers/acpi/namespace/nsxfname.c @@ -6,7 +6,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2006, R. Byron Moore + * Copyright (C) 2000 - 2007, R. Byron Moore * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -84,38 +84,41 @@ acpi_get_handle(acpi_handle parent, /* Convert a parent handle to a prefix node */ if (parent) { - status = acpi_ut_acquire_mutex(ACPI_MTX_NAMESPACE); - if (ACPI_FAILURE(status)) { - return (status); - } - prefix_node = acpi_ns_map_handle_to_node(parent); if (!prefix_node) { - (void)acpi_ut_release_mutex(ACPI_MTX_NAMESPACE); return (AE_BAD_PARAMETER); } + } + + /* + * Valid cases are: + * 1) Fully qualified pathname + * 2) Parent + Relative pathname + * + * Error for + */ + if (acpi_ns_valid_root_prefix(pathname[0])) { - status = acpi_ut_release_mutex(ACPI_MTX_NAMESPACE); - if (ACPI_FAILURE(status)) { - return (status); + /* Pathname is fully qualified (starts with '\') */ + + /* Special case for root-only, since we can't search for it */ + + if (!ACPI_STRCMP(pathname, ACPI_NS_ROOT_PATH)) { + *ret_handle = + acpi_ns_convert_entry_to_handle(acpi_gbl_root_node); + return (AE_OK); } - } + } else if (!prefix_node) { - /* Special case for root, since we can't search for it */ + /* Relative path with null prefix is disallowed */ - if (ACPI_STRCMP(pathname, ACPI_NS_ROOT_PATH) == 0) { - *ret_handle = - acpi_ns_convert_entry_to_handle(acpi_gbl_root_node); - return (AE_OK); + return (AE_BAD_PARAMETER); } - /* - * Find the Node and convert to a handle - */ - status = acpi_ns_get_node(prefix_node, pathname, ACPI_NS_NO_UPSEARCH, - &node); + /* Find the Node and convert to a handle */ - *ret_handle = NULL; + status = + acpi_ns_get_node(prefix_node, pathname, ACPI_NS_NO_UPSEARCH, &node); if (ACPI_SUCCESS(status)) { *ret_handle = acpi_ns_convert_entry_to_handle(node); } diff --git a/drivers/acpi/namespace/nsxfobj.c b/drivers/acpi/namespace/nsxfobj.c index a18b1c2..faa3758 100644 --- a/drivers/acpi/namespace/nsxfobj.c +++ b/drivers/acpi/namespace/nsxfobj.c @@ -6,7 +6,7 @@ ******************************************************************************/ /* - * Copyright (C) 2000 - 2006, R. Byron Moore + * Copyright (C) 2000 - 2007, R. Byron Moore * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/numa.c b/drivers/acpi/numa.c index bd96a70..4a9faff 100644 --- a/drivers/acpi/numa.c +++ b/drivers/acpi/numa.c @@ -45,7 +45,7 @@ int __cpuinitdata pxm_to_node_map[MAX_PX int __cpuinitdata node_to_pxm_map[MAX_NUMNODES] = { [0 ... MAX_NUMNODES - 1] = PXM_INVAL }; -extern int __init acpi_table_parse_madt_family(enum acpi_table_id id, +extern int __init acpi_table_parse_madt_family(char *id, unsigned long madt_size, int entry_id, acpi_madt_entry_handler handler, @@ -89,7 +89,7 @@ void __cpuinit acpi_unmap_pxm_to_node(in node_clear(node, nodes_found_map); } -void __init acpi_table_print_srat_entry(acpi_table_entry_header * header) +void __init acpi_table_print_srat_entry(struct acpi_subtable_header * header) { ACPI_FUNCTION_NAME("acpi_table_print_srat_entry"); @@ -99,36 +99,35 @@ void __init acpi_table_print_srat_entry( switch (header->type) { - case ACPI_SRAT_PROCESSOR_AFFINITY: + case ACPI_SRAT_TYPE_CPU_AFFINITY: #ifdef ACPI_DEBUG_OUTPUT { - struct acpi_table_processor_affinity *p = - (struct acpi_table_processor_affinity *)header; + struct acpi_srat_cpu_affinity *p = + (struct acpi_srat_cpu_affinity *)header; ACPI_DEBUG_PRINT((ACPI_DB_INFO, "SRAT Processor (id[0x%02x] eid[0x%02x]) in proximity domain %d %s\n", - p->apic_id, p->lsapic_eid, - p->proximity_domain, - p->flags. - enabled ? "enabled" : "disabled")); + p->apic_id, p->local_sapic_eid, + p->proximity_domain_lo, + (p->flags & ACPI_SRAT_CPU_ENABLED)? + "enabled" : "disabled")); } #endif /* ACPI_DEBUG_OUTPUT */ break; - case ACPI_SRAT_MEMORY_AFFINITY: + case ACPI_SRAT_TYPE_MEMORY_AFFINITY: #ifdef ACPI_DEBUG_OUTPUT { - struct acpi_table_memory_affinity *p = - (struct acpi_table_memory_affinity *)header; + struct acpi_srat_mem_affinity *p = + (struct acpi_srat_mem_affinity *)header; ACPI_DEBUG_PRINT((ACPI_DB_INFO, - "SRAT Memory (0x%08x%08x length 0x%08x%08x type 0x%x) in proximity domain %d %s%s\n", - p->base_addr_hi, p->base_addr_lo, - p->length_hi, p->length_lo, + "SRAT Memory (0x%lx length 0x%lx type 0x%x) in proximity domain %d %s%s\n", + (unsigned long)p->base_address, + (unsigned long)p->length, p->memory_type, p->proximity_domain, - p->flags. - enabled ? "enabled" : "disabled", - p->flags. - hot_pluggable ? " hot-pluggable" : - "")); + (p->flags & ACPI_SRAT_MEM_ENABLED)? + "enabled" : "disabled", + (p->flags & ACPI_SRAT_MEM_HOT_PLUGGABLE)? + " hot-pluggable" : "")); } #endif /* ACPI_DEBUG_OUTPUT */ break; @@ -141,18 +140,18 @@ #endif /* ACPI_DEBUG_OUTPUT */ } } -static int __init acpi_parse_slit(unsigned long phys_addr, unsigned long size) +static int __init acpi_parse_slit(struct acpi_table_header *table) { struct acpi_table_slit *slit; u32 localities; - if (!phys_addr || !size) + if (!table) return -EINVAL; - slit = (struct acpi_table_slit *)__va(phys_addr); + slit = (struct acpi_table_slit *)table; /* downcast just for %llu vs %lu for i386/ia64 */ - localities = (u32) slit->localities; + localities = (u32) slit->locality_count; acpi_numa_slit_init(slit); @@ -160,12 +159,12 @@ static int __init acpi_parse_slit(unsign } static int __init -acpi_parse_processor_affinity(acpi_table_entry_header * header, +acpi_parse_processor_affinity(struct acpi_subtable_header * header, const unsigned long end) { - struct acpi_table_processor_affinity *processor_affinity; + struct acpi_srat_cpu_affinity *processor_affinity; - processor_affinity = (struct acpi_table_processor_affinity *)header; + processor_affinity = (struct acpi_srat_cpu_affinity *)header; if (!processor_affinity) return -EINVAL; @@ -178,12 +177,12 @@ acpi_parse_processor_affinity(acpi_table } static int __init -acpi_parse_memory_affinity(acpi_table_entry_header * header, +acpi_parse_memory_affinity(struct acpi_subtable_header * header, const unsigned long end) { - struct acpi_table_memory_affinity *memory_affinity; + struct acpi_srat_mem_affinity *memory_affinity; - memory_affinity = (struct acpi_table_memory_affinity *)header; + memory_affinity = (struct acpi_srat_mem_affinity *)header; if (!memory_affinity) return -EINVAL; @@ -195,23 +194,23 @@ acpi_parse_memory_affinity(acpi_table_en return 0; } -static int __init acpi_parse_srat(unsigned long phys_addr, unsigned long size) +static int __init acpi_parse_srat(struct acpi_table_header *table) { struct acpi_table_srat *srat; - if (!phys_addr || !size) + if (!table) return -EINVAL; - srat = (struct acpi_table_srat *)__va(phys_addr); + srat = (struct acpi_table_srat *)table; return 0; } int __init -acpi_table_parse_srat(enum acpi_srat_entry_id id, +acpi_table_parse_srat(enum acpi_srat_type id, acpi_madt_entry_handler handler, unsigned int max_entries) { - return acpi_table_parse_madt_family(ACPI_SRAT, + return acpi_table_parse_madt_family(ACPI_SIG_SRAT, sizeof(struct acpi_table_srat), id, handler, max_entries); } @@ -221,17 +220,17 @@ int __init acpi_numa_init(void) int result; /* SRAT: Static Resource Affinity Table */ - result = acpi_table_parse(ACPI_SRAT, acpi_parse_srat); + result = acpi_table_parse(ACPI_SIG_SRAT, acpi_parse_srat); if (result > 0) { - result = acpi_table_parse_srat(ACPI_SRAT_PROCESSOR_AFFINITY, + result = acpi_table_parse_srat(ACPI_SRAT_TYPE_CPU_AFFINITY, acpi_parse_processor_affinity, NR_CPUS); - result = acpi_table_parse_srat(ACPI_SRAT_MEMORY_AFFINITY, acpi_parse_memory_affinity, NR_NODE_MEMBLKS); // IA64 specific + result = acpi_table_parse_srat(ACPI_SRAT_TYPE_MEMORY_AFFINITY, acpi_parse_memory_affinity, NR_NODE_MEMBLKS); // IA64 specific } /* SLIT: System Locality Information Table */ - result = acpi_table_parse(ACPI_SLIT, acpi_parse_slit); + result = acpi_table_parse(ACPI_SIG_SLIT, acpi_parse_slit); acpi_numa_arch_fixup(); return 0; diff --git a/drivers/acpi/osl.c b/drivers/acpi/osl.c index 57ae1e5..0f6f3bc 100644 --- a/drivers/acpi/osl.c +++ b/drivers/acpi/osl.c @@ -36,6 +36,7 @@ #include #include #include #include +#include #include #include #include @@ -75,6 +76,54 @@ static acpi_osd_handler acpi_irq_handler static void *acpi_irq_context; static struct workqueue_struct *kacpid_wq; +static void __init acpi_request_region (struct acpi_generic_address *addr, + unsigned int length, char *desc) +{ + struct resource *res; + + if (!addr->address || !length) + return; + + if (addr->space_id == ACPI_ADR_SPACE_SYSTEM_IO) + res = request_region(addr->address, length, desc); + else if (addr->space_id == ACPI_ADR_SPACE_SYSTEM_MEMORY) + res = request_mem_region(addr->address, length, desc); +} + +static int __init acpi_reserve_resources(void) +{ + acpi_request_region(&acpi_gbl_FADT.xpm1a_event_block, acpi_gbl_FADT.pm1_event_length, + "ACPI PM1a_EVT_BLK"); + + acpi_request_region(&acpi_gbl_FADT.xpm1b_event_block, acpi_gbl_FADT.pm1_event_length, + "ACPI PM1b_EVT_BLK"); + + acpi_request_region(&acpi_gbl_FADT.xpm1a_control_block, acpi_gbl_FADT.pm1_control_length, + "ACPI PM1a_CNT_BLK"); + + acpi_request_region(&acpi_gbl_FADT.xpm1b_control_block, acpi_gbl_FADT.pm1_control_length, + "ACPI PM1b_CNT_BLK"); + + if (acpi_gbl_FADT.pm_timer_length == 4) + acpi_request_region(&acpi_gbl_FADT.xpm_timer_block, 4, "ACPI PM_TMR"); + + acpi_request_region(&acpi_gbl_FADT.xpm2_control_block, acpi_gbl_FADT.pm2_control_length, + "ACPI PM2_CNT_BLK"); + + /* Length of GPE blocks must be a non-negative multiple of 2 */ + + if (!(acpi_gbl_FADT.gpe0_block_length & 0x1)) + acpi_request_region(&acpi_gbl_FADT.xgpe0_block, + acpi_gbl_FADT.gpe0_block_length, "ACPI GPE0_BLK"); + + if (!(acpi_gbl_FADT.gpe1_block_length & 0x1)) + acpi_request_region(&acpi_gbl_FADT.xgpe1_block, + acpi_gbl_FADT.gpe1_block_length, "ACPI GPE1_BLK"); + + return 0; +} +device_initcall(acpi_reserve_resources); + acpi_status acpi_os_initialize(void) { return AE_OK; @@ -136,53 +185,43 @@ #else #endif } -acpi_status acpi_os_get_root_pointer(u32 flags, struct acpi_pointer *addr) +acpi_physical_address __init acpi_os_get_root_pointer(void) { if (efi_enabled) { - addr->pointer_type = ACPI_PHYSICAL_POINTER; if (efi.acpi20 != EFI_INVALID_TABLE_ADDR) - addr->pointer.physical = efi.acpi20; + return efi.acpi20; else if (efi.acpi != EFI_INVALID_TABLE_ADDR) - addr->pointer.physical = efi.acpi; + return efi.acpi; else { printk(KERN_ERR PREFIX "System description tables not found\n"); - return AE_NOT_FOUND; + return 0; } - } else { - if (ACPI_FAILURE(acpi_find_root_pointer(flags, addr))) { - printk(KERN_ERR PREFIX - "System description tables not found\n"); - return AE_NOT_FOUND; - } - } - - return AE_OK; + } else + return acpi_find_rsdp(); } -acpi_status -acpi_os_map_memory(acpi_physical_address phys, acpi_size size, - void __iomem ** virt) +void __iomem *acpi_os_map_memory(acpi_physical_address phys, acpi_size size) { if (phys > ULONG_MAX) { printk(KERN_ERR PREFIX "Cannot map memory that high\n"); - return AE_BAD_PARAMETER; + return 0; } - /* - * ioremap checks to ensure this is in reserved space - */ - *virt = ioremap((unsigned long)phys, size); - - if (!*virt) - return AE_NO_MEMORY; - - return AE_OK; + if (acpi_gbl_permanent_mmap) + /* + * ioremap checks to ensure this is in reserved space + */ + return ioremap((unsigned long)phys, size); + else + return __acpi_map_table((unsigned long)phys, size); } EXPORT_SYMBOL_GPL(acpi_os_map_memory); void acpi_os_unmap_memory(void __iomem * virt, acpi_size size) { - iounmap(virt); + if (acpi_gbl_permanent_mmap) { + iounmap(virt); + } } EXPORT_SYMBOL_GPL(acpi_os_unmap_memory); @@ -254,7 +293,7 @@ acpi_os_install_interrupt_handler(u32 gs * FADT. It may not be the same if an interrupt source override exists * for the SCI. */ - gsi = acpi_fadt.sci_int; + gsi = acpi_gbl_FADT.sci_interrupt; if (acpi_gsi_to_irq(gsi, &irq) < 0) { printk(KERN_ERR PREFIX "SCI (ACPI GSI %d) not registered\n", gsi); diff --git a/drivers/acpi/parser/psargs.c b/drivers/acpi/parser/psargs.c index bf88e07..c2b9835 100644 --- a/drivers/acpi/parser/psargs.c +++ b/drivers/acpi/parser/psargs.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2006, R. Byron Moore + * Copyright (C) 2000 - 2007, R. Byron Moore * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/parser/psloop.c b/drivers/acpi/parser/psloop.c index e1541db..773aee8 100644 --- a/drivers/acpi/parser/psloop.c +++ b/drivers/acpi/parser/psloop.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2006, R. Byron Moore + * Copyright (C) 2000 - 2007, R. Byron Moore * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -42,12 +42,11 @@ */ /* - * Parse the AML and build an operation tree as most interpreters, - * like Perl, do. Parsing is done by hand rather than with a YACC - * generated parser to tightly constrain stack and dynamic memory - * usage. At the same time, parsing is kept flexible and the code - * fairly compact by parsing based on a list of AML opcode - * templates in aml_op_info[] + * Parse the AML and build an operation tree as most interpreters, (such as + * Perl) do. Parsing is done by hand rather than with a YACC generated parser + * to tightly constrain stack and dynamic memory usage. Parsing is kept + * flexible and the code fairly compact by parsing based on a list of AML + * opcode templates in aml_op_info[]. */ #include @@ -60,766 +59,679 @@ ACPI_MODULE_NAME("psloop") static u32 acpi_gbl_depth = 0; +/* Local prototypes */ + +static acpi_status acpi_ps_get_aml_opcode(struct acpi_walk_state *walk_state); + +static acpi_status +acpi_ps_build_named_op(struct acpi_walk_state *walk_state, + u8 * aml_op_start, + union acpi_parse_object *unnamed_op, + union acpi_parse_object **op); + +static acpi_status +acpi_ps_create_op(struct acpi_walk_state *walk_state, + u8 * aml_op_start, union acpi_parse_object **new_op); + +static acpi_status +acpi_ps_get_arguments(struct acpi_walk_state *walk_state, + u8 * aml_op_start, union acpi_parse_object *op); + +static acpi_status +acpi_ps_complete_op(struct acpi_walk_state *walk_state, + union acpi_parse_object **op, acpi_status status); + +static acpi_status +acpi_ps_complete_final_op(struct acpi_walk_state *walk_state, + union acpi_parse_object *op, acpi_status status); + /******************************************************************************* * - * FUNCTION: acpi_ps_parse_loop + * FUNCTION: acpi_ps_get_aml_opcode * * PARAMETERS: walk_state - Current state * * RETURN: Status * - * DESCRIPTION: Parse AML (pointed to by the current parser state) and return - * a tree of ops. + * DESCRIPTION: Extract the next AML opcode from the input stream. * ******************************************************************************/ -acpi_status acpi_ps_parse_loop(struct acpi_walk_state *walk_state) +static acpi_status acpi_ps_get_aml_opcode(struct acpi_walk_state *walk_state) { - acpi_status status = AE_OK; - acpi_status status2; - union acpi_parse_object *op = NULL; /* current op */ - union acpi_parse_object *arg = NULL; - union acpi_parse_object *pre_op = NULL; - struct acpi_parse_state *parser_state; - u8 *aml_op_start = NULL; - ACPI_FUNCTION_TRACE_PTR(ps_parse_loop, walk_state); + ACPI_FUNCTION_TRACE_PTR(ps_get_aml_opcode, walk_state); - if (walk_state->descending_callback == NULL) { - return_ACPI_STATUS(AE_BAD_PARAMETER); - } + walk_state->aml_offset = + (u32) ACPI_PTR_DIFF(walk_state->parser_state.aml, + walk_state->parser_state.aml_start); + walk_state->opcode = acpi_ps_peek_opcode(&(walk_state->parser_state)); - parser_state = &walk_state->parser_state; - walk_state->arg_types = 0; + /* + * First cut to determine what we have found: + * 1) A valid AML opcode + * 2) A name string + * 3) An unknown/invalid opcode + */ + walk_state->op_info = acpi_ps_get_opcode_info(walk_state->opcode); -#if (!defined (ACPI_NO_METHOD_EXECUTION) && !defined (ACPI_CONSTANT_EVAL_ONLY)) + switch (walk_state->op_info->class) { + case AML_CLASS_ASCII: + case AML_CLASS_PREFIX: + /* + * Starts with a valid prefix or ASCII char, this is a name + * string. Convert the bare name string to a namepath. + */ + walk_state->opcode = AML_INT_NAMEPATH_OP; + walk_state->arg_types = ARGP_NAMESTRING; + break; - if (walk_state->walk_type & ACPI_WALK_METHOD_RESTART) { + case AML_CLASS_UNKNOWN: - /* We are restarting a preempted control method */ + /* The opcode is unrecognized. Just skip unknown opcodes */ - if (acpi_ps_has_completed_scope(parser_state)) { - /* - * We must check if a predicate to an IF or WHILE statement - * was just completed - */ - if ((parser_state->scope->parse_scope.op) && - ((parser_state->scope->parse_scope.op->common. - aml_opcode == AML_IF_OP) - || (parser_state->scope->parse_scope.op->common. - aml_opcode == AML_WHILE_OP)) - && (walk_state->control_state) - && (walk_state->control_state->common.state == - ACPI_CONTROL_PREDICATE_EXECUTING)) { - /* - * A predicate was just completed, get the value of the - * predicate and branch based on that value - */ - walk_state->op = NULL; - status = - acpi_ds_get_predicate_value(walk_state, - ACPI_TO_POINTER - (TRUE)); - if (ACPI_FAILURE(status) - && ((status & AE_CODE_MASK) != - AE_CODE_CONTROL)) { - if (status == AE_AML_NO_RETURN_VALUE) { - ACPI_EXCEPTION((AE_INFO, status, - "Invoked method did not return a value")); + ACPI_ERROR((AE_INFO, + "Found unknown opcode %X at AML address %p offset %X, ignoring", + walk_state->opcode, walk_state->parser_state.aml, + walk_state->aml_offset)); - } - ACPI_EXCEPTION((AE_INFO, status, - "GetPredicate Failed")); - return_ACPI_STATUS(status); - } + ACPI_DUMP_BUFFER(walk_state->parser_state.aml, 128); - status = - acpi_ps_next_parse_state(walk_state, op, - status); - } + /* Assume one-byte bad opcode */ - acpi_ps_pop_scope(parser_state, &op, - &walk_state->arg_types, - &walk_state->arg_count); - ACPI_DEBUG_PRINT((ACPI_DB_PARSE, - "Popped scope, Op=%p\n", op)); - } else if (walk_state->prev_op) { + walk_state->parser_state.aml++; + return_ACPI_STATUS(AE_CTRL_PARSE_CONTINUE); - /* We were in the middle of an op */ + default: - op = walk_state->prev_op; - walk_state->arg_types = walk_state->prev_arg_types; - } + /* Found opcode info, this is a normal opcode */ + + walk_state->parser_state.aml += + acpi_ps_get_opcode_size(walk_state->opcode); + walk_state->arg_types = walk_state->op_info->parse_args; + break; } -#endif - /* Iterative parsing loop, while there is more AML to process: */ + return_ACPI_STATUS(AE_OK); +} - while ((parser_state->aml < parser_state->aml_end) || (op)) { - aml_op_start = parser_state->aml; - if (!op) { +/******************************************************************************* + * + * FUNCTION: acpi_ps_build_named_op + * + * PARAMETERS: walk_state - Current state + * aml_op_start - Begin of named Op in AML + * unnamed_op - Early Op (not a named Op) + * Op - Returned Op + * + * RETURN: Status + * + * DESCRIPTION: Parse a named Op + * + ******************************************************************************/ - /* Get the next opcode from the AML stream */ +static acpi_status +acpi_ps_build_named_op(struct acpi_walk_state *walk_state, + u8 * aml_op_start, + union acpi_parse_object *unnamed_op, + union acpi_parse_object **op) +{ + acpi_status status = AE_OK; + union acpi_parse_object *arg = NULL; - walk_state->aml_offset = - (u32) ACPI_PTR_DIFF(parser_state->aml, - parser_state->aml_start); - walk_state->opcode = acpi_ps_peek_opcode(parser_state); + ACPI_FUNCTION_TRACE_PTR(ps_build_named_op, walk_state); - /* - * First cut to determine what we have found: - * 1) A valid AML opcode - * 2) A name string - * 3) An unknown/invalid opcode - */ - walk_state->op_info = - acpi_ps_get_opcode_info(walk_state->opcode); - switch (walk_state->op_info->class) { - case AML_CLASS_ASCII: - case AML_CLASS_PREFIX: - /* - * Starts with a valid prefix or ASCII char, this is a name - * string. Convert the bare name string to a namepath. - */ - walk_state->opcode = AML_INT_NAMEPATH_OP; - walk_state->arg_types = ARGP_NAMESTRING; - break; + unnamed_op->common.value.arg = NULL; + unnamed_op->common.aml_opcode = walk_state->opcode; - case AML_CLASS_UNKNOWN: + /* + * Get and append arguments until we find the node that contains + * the name (the type ARGP_NAME). + */ + while (GET_CURRENT_ARG_TYPE(walk_state->arg_types) && + (GET_CURRENT_ARG_TYPE(walk_state->arg_types) != ARGP_NAME)) { + status = + acpi_ps_get_next_arg(walk_state, + &(walk_state->parser_state), + GET_CURRENT_ARG_TYPE(walk_state-> + arg_types), &arg); + if (ACPI_FAILURE(status)) { + return_ACPI_STATUS(status); + } - /* The opcode is unrecognized. Just skip unknown opcodes */ + acpi_ps_append_arg(unnamed_op, arg); + INCREMENT_ARG_LIST(walk_state->arg_types); + } - ACPI_ERROR((AE_INFO, - "Found unknown opcode %X at AML address %p offset %X, ignoring", - walk_state->opcode, - parser_state->aml, - walk_state->aml_offset)); + /* + * Make sure that we found a NAME and didn't run out of arguments + */ + if (!GET_CURRENT_ARG_TYPE(walk_state->arg_types)) { + return_ACPI_STATUS(AE_AML_NO_OPERAND); + } - ACPI_DUMP_BUFFER(parser_state->aml, 128); + /* We know that this arg is a name, move to next arg */ - /* Assume one-byte bad opcode */ + INCREMENT_ARG_LIST(walk_state->arg_types); - parser_state->aml++; - continue; + /* + * Find the object. This will either insert the object into + * the namespace or simply look it up + */ + walk_state->op = NULL; - default: + status = walk_state->descending_callback(walk_state, op); + if (ACPI_FAILURE(status)) { + ACPI_EXCEPTION((AE_INFO, status, "During name lookup/catalog")); + return_ACPI_STATUS(status); + } - /* Found opcode info, this is a normal opcode */ + if (!*op) { + return_ACPI_STATUS(AE_CTRL_PARSE_CONTINUE); + } - parser_state->aml += - acpi_ps_get_opcode_size(walk_state->opcode); - walk_state->arg_types = - walk_state->op_info->parse_args; - break; - } + status = acpi_ps_next_parse_state(walk_state, *op, status); + if (ACPI_FAILURE(status)) { + if (status == AE_CTRL_PENDING) { + return_ACPI_STATUS(AE_CTRL_PARSE_PENDING); + } + return_ACPI_STATUS(status); + } - /* Create Op structure and append to parent's argument list */ + acpi_ps_append_arg(*op, unnamed_op->common.value.arg); + acpi_gbl_depth++; - if (walk_state->op_info->flags & AML_NAMED) { + if ((*op)->common.aml_opcode == AML_REGION_OP) { + /* + * Defer final parsing of an operation_region body, because we don't + * have enough info in the first pass to parse it correctly (i.e., + * there may be method calls within the term_arg elements of the body.) + * + * However, we must continue parsing because the opregion is not a + * standalone package -- we don't know where the end is at this point. + * + * (Length is unknown until parse of the body complete) + */ + (*op)->named.data = aml_op_start; + (*op)->named.length = 0; + } - /* Allocate a new pre_op if necessary */ + return_ACPI_STATUS(AE_OK); +} - if (!pre_op) { - pre_op = - acpi_ps_alloc_op(walk_state-> - opcode); - if (!pre_op) { - status = AE_NO_MEMORY; - goto close_this_op; - } - } +/******************************************************************************* + * + * FUNCTION: acpi_ps_create_op + * + * PARAMETERS: walk_state - Current state + * aml_op_start - Op start in AML + * new_op - Returned Op + * + * RETURN: Status + * + * DESCRIPTION: Get Op from AML + * + ******************************************************************************/ - pre_op->common.value.arg = NULL; - pre_op->common.aml_opcode = walk_state->opcode; +static acpi_status +acpi_ps_create_op(struct acpi_walk_state *walk_state, + u8 * aml_op_start, union acpi_parse_object **new_op) +{ + acpi_status status = AE_OK; + union acpi_parse_object *op; + union acpi_parse_object *named_op = NULL; - /* - * Get and append arguments until we find the node that contains - * the name (the type ARGP_NAME). - */ - while (GET_CURRENT_ARG_TYPE - (walk_state->arg_types) - && - (GET_CURRENT_ARG_TYPE - (walk_state->arg_types) != ARGP_NAME)) { - status = - acpi_ps_get_next_arg(walk_state, - parser_state, - GET_CURRENT_ARG_TYPE - (walk_state-> - arg_types), - &arg); - if (ACPI_FAILURE(status)) { - goto close_this_op; - } + ACPI_FUNCTION_TRACE_PTR(ps_create_op, walk_state); - acpi_ps_append_arg(pre_op, arg); - INCREMENT_ARG_LIST(walk_state-> - arg_types); - } + status = acpi_ps_get_aml_opcode(walk_state); + if (status == AE_CTRL_PARSE_CONTINUE) { + return_ACPI_STATUS(AE_CTRL_PARSE_CONTINUE); + } - /* - * Make sure that we found a NAME and didn't run out of - * arguments - */ - if (!GET_CURRENT_ARG_TYPE - (walk_state->arg_types)) { - status = AE_AML_NO_OPERAND; - goto close_this_op; - } + /* Create Op structure and append to parent's argument list */ - /* We know that this arg is a name, move to next arg */ + walk_state->op_info = acpi_ps_get_opcode_info(walk_state->opcode); + op = acpi_ps_alloc_op(walk_state->opcode); + if (!op) { + return_ACPI_STATUS(AE_NO_MEMORY); + } - INCREMENT_ARG_LIST(walk_state->arg_types); + if (walk_state->op_info->flags & AML_NAMED) { + status = + acpi_ps_build_named_op(walk_state, aml_op_start, op, + &named_op); + acpi_ps_free_op(op); + if (ACPI_FAILURE(status)) { + return_ACPI_STATUS(status); + } - /* - * Find the object. This will either insert the object into - * the namespace or simply look it up - */ - walk_state->op = NULL; + *new_op = named_op; + return_ACPI_STATUS(AE_OK); + } - status = - walk_state->descending_callback(walk_state, - &op); - if (ACPI_FAILURE(status)) { - ACPI_EXCEPTION((AE_INFO, status, - "During name lookup/catalog")); - goto close_this_op; - } + /* Not a named opcode, just allocate Op and append to parent */ - if (!op) { - continue; - } + if (walk_state->op_info->flags & AML_CREATE) { + /* + * Backup to beginning of create_xXXfield declaration + * body_length is unknown until we parse the body + */ + op->named.data = aml_op_start; + op->named.length = 0; + } - status = - acpi_ps_next_parse_state(walk_state, op, - status); - if (status == AE_CTRL_PENDING) { - status = AE_OK; - goto close_this_op; - } + acpi_ps_append_arg(acpi_ps_get_parent_scope + (&(walk_state->parser_state)), op); - if (ACPI_FAILURE(status)) { - goto close_this_op; - } + if (walk_state->descending_callback != NULL) { + /* + * Find the object. This will either insert the object into + * the namespace or simply look it up + */ + walk_state->op = *new_op = op; - acpi_ps_append_arg(op, - pre_op->common.value.arg); - acpi_gbl_depth++; - - if (op->common.aml_opcode == AML_REGION_OP) { - /* - * Defer final parsing of an operation_region body, - * because we don't have enough info in the first pass - * to parse it correctly (i.e., there may be method - * calls within the term_arg elements of the body.) - * - * However, we must continue parsing because - * the opregion is not a standalone package -- - * we don't know where the end is at this point. - * - * (Length is unknown until parse of the body complete) - */ - op->named.data = aml_op_start; - op->named.length = 0; - } - } else { - /* Not a named opcode, just allocate Op and append to parent */ + status = walk_state->descending_callback(walk_state, &op); + status = acpi_ps_next_parse_state(walk_state, op, status); + if (status == AE_CTRL_PENDING) { + status = AE_CTRL_PARSE_PENDING; + } + } - walk_state->op_info = - acpi_ps_get_opcode_info(walk_state->opcode); - op = acpi_ps_alloc_op(walk_state->opcode); - if (!op) { - status = AE_NO_MEMORY; - goto close_this_op; - } + return_ACPI_STATUS(status); +} - if (walk_state->op_info->flags & AML_CREATE) { - /* - * Backup to beginning of create_xXXfield declaration - * body_length is unknown until we parse the body - */ - op->named.data = aml_op_start; - op->named.length = 0; - } +/******************************************************************************* + * + * FUNCTION: acpi_ps_get_arguments + * + * PARAMETERS: walk_state - Current state + * aml_op_start - Op start in AML + * Op - Current Op + * + * RETURN: Status + * + * DESCRIPTION: Get arguments for passed Op. + * + ******************************************************************************/ - acpi_ps_append_arg(acpi_ps_get_parent_scope - (parser_state), op); +static acpi_status +acpi_ps_get_arguments(struct acpi_walk_state *walk_state, + u8 * aml_op_start, union acpi_parse_object *op) +{ + acpi_status status = AE_OK; + union acpi_parse_object *arg = NULL; - if ((walk_state->descending_callback != NULL)) { - /* - * Find the object. This will either insert the object into - * the namespace or simply look it up - */ - walk_state->op = op; + ACPI_FUNCTION_TRACE_PTR(ps_get_arguments, walk_state); - status = - walk_state-> - descending_callback(walk_state, - &op); - status = - acpi_ps_next_parse_state(walk_state, - op, - status); - if (status == AE_CTRL_PENDING) { - status = AE_OK; - goto close_this_op; - } + switch (op->common.aml_opcode) { + case AML_BYTE_OP: /* AML_BYTEDATA_ARG */ + case AML_WORD_OP: /* AML_WORDDATA_ARG */ + case AML_DWORD_OP: /* AML_DWORDATA_ARG */ + case AML_QWORD_OP: /* AML_QWORDATA_ARG */ + case AML_STRING_OP: /* AML_ASCIICHARLIST_ARG */ - if (ACPI_FAILURE(status)) { - goto close_this_op; - } - } - } + /* Fill in constant or string argument directly */ - op->common.aml_offset = walk_state->aml_offset; + acpi_ps_get_next_simple_arg(&(walk_state->parser_state), + GET_CURRENT_ARG_TYPE(walk_state-> + arg_types), + op); + break; - if (walk_state->op_info) { - ACPI_DEBUG_PRINT((ACPI_DB_PARSE, - "Opcode %4.4X [%s] Op %p Aml %p AmlOffset %5.5X\n", - (u32) op->common.aml_opcode, - walk_state->op_info->name, op, - parser_state->aml, - op->common.aml_offset)); - } + case AML_INT_NAMEPATH_OP: /* AML_NAMESTRING_ARG */ + + status = + acpi_ps_get_next_namepath(walk_state, + &(walk_state->parser_state), op, + 1); + if (ACPI_FAILURE(status)) { + return_ACPI_STATUS(status); } + walk_state->arg_types = 0; + break; + + default: /* - * Start arg_count at zero because we don't know if there are - * any args yet + * Op is not a constant or string, append each argument to the Op */ - walk_state->arg_count = 0; - - /* Are there any arguments that must be processed? */ - - if (walk_state->arg_types) { - - /* Get arguments */ - - switch (op->common.aml_opcode) { - case AML_BYTE_OP: /* AML_BYTEDATA_ARG */ - case AML_WORD_OP: /* AML_WORDDATA_ARG */ - case AML_DWORD_OP: /* AML_DWORDATA_ARG */ - case AML_QWORD_OP: /* AML_QWORDATA_ARG */ - case AML_STRING_OP: /* AML_ASCIICHARLIST_ARG */ - - /* Fill in constant or string argument directly */ - - acpi_ps_get_next_simple_arg(parser_state, - GET_CURRENT_ARG_TYPE - (walk_state-> - arg_types), op); - break; - - case AML_INT_NAMEPATH_OP: /* AML_NAMESTRING_ARG */ - - status = - acpi_ps_get_next_namepath(walk_state, - parser_state, op, - 1); - if (ACPI_FAILURE(status)) { - goto close_this_op; - } - - walk_state->arg_types = 0; - break; + while (GET_CURRENT_ARG_TYPE(walk_state->arg_types) + && !walk_state->arg_count) { + walk_state->aml_offset = + (u32) ACPI_PTR_DIFF(walk_state->parser_state.aml, + walk_state->parser_state. + aml_start); - default: - /* - * Op is not a constant or string, append each argument - * to the Op - */ - while (GET_CURRENT_ARG_TYPE - (walk_state->arg_types) - && !walk_state->arg_count) { - walk_state->aml_offset = (u32) - ACPI_PTR_DIFF(parser_state->aml, - parser_state-> - aml_start); + status = + acpi_ps_get_next_arg(walk_state, + &(walk_state->parser_state), + GET_CURRENT_ARG_TYPE + (walk_state->arg_types), &arg); + if (ACPI_FAILURE(status)) { + return_ACPI_STATUS(status); + } - status = - acpi_ps_get_next_arg(walk_state, - parser_state, - GET_CURRENT_ARG_TYPE - (walk_state-> - arg_types), - &arg); - if (ACPI_FAILURE(status)) { - goto close_this_op; - } + if (arg) { + arg->common.aml_offset = walk_state->aml_offset; + acpi_ps_append_arg(op, arg); + } - if (arg) { - arg->common.aml_offset = - walk_state->aml_offset; - acpi_ps_append_arg(op, arg); - } - INCREMENT_ARG_LIST(walk_state-> - arg_types); - } + INCREMENT_ARG_LIST(walk_state->arg_types); + } - /* Special processing for certain opcodes */ + /* Special processing for certain opcodes */ - /* TBD (remove): Temporary mechanism to disable this code if needed */ + /* TBD (remove): Temporary mechanism to disable this code if needed */ #ifdef ACPI_ENABLE_MODULE_LEVEL_CODE - if ((walk_state->pass_number <= - ACPI_IMODE_LOAD_PASS1) - && - ((walk_state-> - parse_flags & ACPI_PARSE_DISASSEMBLE) == - 0)) { - /* - * We want to skip If/Else/While constructs during Pass1 - * because we want to actually conditionally execute the - * code during Pass2. - * - * Except for disassembly, where we always want to - * walk the If/Else/While packages - */ - switch (op->common.aml_opcode) { - case AML_IF_OP: - case AML_ELSE_OP: - case AML_WHILE_OP: - - ACPI_DEBUG_PRINT((ACPI_DB_PARSE, - "Pass1: Skipping an If/Else/While body\n")); - - /* Skip body of if/else/while in pass 1 */ - - parser_state->aml = - parser_state->pkg_end; - walk_state->arg_count = 0; - break; - - default: - break; - } - } -#endif - switch (op->common.aml_opcode) { - case AML_METHOD_OP: - - /* - * Skip parsing of control method - * because we don't have enough info in the first pass - * to parse it correctly. - * - * Save the length and address of the body - */ - op->named.data = parser_state->aml; - op->named.length = - (u32) (parser_state->pkg_end - - parser_state->aml); - - /* Skip body of method */ - - parser_state->aml = - parser_state->pkg_end; - walk_state->arg_count = 0; - break; - - case AML_BUFFER_OP: - case AML_PACKAGE_OP: - case AML_VAR_PACKAGE_OP: - - if ((op->common.parent) && - (op->common.parent->common. - aml_opcode == AML_NAME_OP) - && (walk_state->pass_number <= - ACPI_IMODE_LOAD_PASS2)) { - /* - * Skip parsing of Buffers and Packages - * because we don't have enough info in the first pass - * to parse them correctly. - */ - op->named.data = aml_op_start; - op->named.length = - (u32) (parser_state-> - pkg_end - - aml_op_start); - - /* Skip body */ - - parser_state->aml = - parser_state->pkg_end; - walk_state->arg_count = 0; - } - break; + if ((walk_state->pass_number <= ACPI_IMODE_LOAD_PASS1) && + ((walk_state->parse_flags & ACPI_PARSE_DISASSEMBLE) == 0)) { + /* + * We want to skip If/Else/While constructs during Pass1 because we + * want to actually conditionally execute the code during Pass2. + * + * Except for disassembly, where we always want to walk the + * If/Else/While packages + */ + switch (op->common.aml_opcode) { + case AML_IF_OP: + case AML_ELSE_OP: + case AML_WHILE_OP: - case AML_WHILE_OP: + ACPI_DEBUG_PRINT((ACPI_DB_PARSE, + "Pass1: Skipping an If/Else/While body\n")); - if (walk_state->control_state) { - walk_state->control_state-> - control.package_end = - parser_state->pkg_end; - } - break; + /* Skip body of if/else/while in pass 1 */ - default: + walk_state->parser_state.aml = + walk_state->parser_state.pkg_end; + walk_state->arg_count = 0; + break; - /* No action for all other opcodes */ - break; - } + default: break; } } +#endif - /* Check for arguments that need to be processed */ - - if (walk_state->arg_count) { + switch (op->common.aml_opcode) { + case AML_METHOD_OP: /* - * There are arguments (complex ones), push Op and - * prepare for argument + * Skip parsing of control method because we don't have enough + * info in the first pass to parse it correctly. + * + * Save the length and address of the body */ - status = acpi_ps_push_scope(parser_state, op, - walk_state->arg_types, - walk_state->arg_count); - if (ACPI_FAILURE(status)) { - goto close_this_op; - } - op = NULL; - continue; - } + op->named.data = walk_state->parser_state.aml; + op->named.length = (u32) + (walk_state->parser_state.pkg_end - + walk_state->parser_state.aml); - /* - * All arguments have been processed -- Op is complete, - * prepare for next - */ - walk_state->op_info = - acpi_ps_get_opcode_info(op->common.aml_opcode); - if (walk_state->op_info->flags & AML_NAMED) { - if (acpi_gbl_depth) { - acpi_gbl_depth--; - } + /* Skip body of method */ - if (op->common.aml_opcode == AML_REGION_OP) { + walk_state->parser_state.aml = + walk_state->parser_state.pkg_end; + walk_state->arg_count = 0; + break; + + case AML_BUFFER_OP: + case AML_PACKAGE_OP: + case AML_VAR_PACKAGE_OP: + + if ((op->common.parent) && + (op->common.parent->common.aml_opcode == + AML_NAME_OP) + && (walk_state->pass_number <= + ACPI_IMODE_LOAD_PASS2)) { /* - * Skip parsing of control method or opregion body, - * because we don't have enough info in the first pass - * to parse them correctly. - * - * Completed parsing an op_region declaration, we now - * know the length. + * Skip parsing of Buffers and Packages because we don't have + * enough info in the first pass to parse them correctly. */ - op->named.length = - (u32) (parser_state->aml - op->named.data); - } - } + op->named.data = aml_op_start; + op->named.length = (u32) + (walk_state->parser_state.pkg_end - + aml_op_start); - if (walk_state->op_info->flags & AML_CREATE) { - /* - * Backup to beginning of create_xXXfield declaration (1 for - * Opcode) - * - * body_length is unknown until we parse the body - */ - op->named.length = - (u32) (parser_state->aml - op->named.data); - } + /* Skip body */ - /* This op complete, notify the dispatcher */ + walk_state->parser_state.aml = + walk_state->parser_state.pkg_end; + walk_state->arg_count = 0; + } + break; - if (walk_state->ascending_callback != NULL) { - walk_state->op = op; - walk_state->opcode = op->common.aml_opcode; + case AML_WHILE_OP: - status = walk_state->ascending_callback(walk_state); - status = - acpi_ps_next_parse_state(walk_state, op, status); - if (status == AE_CTRL_PENDING) { - status = AE_OK; - goto close_this_op; + if (walk_state->control_state) { + walk_state->control_state->control.package_end = + walk_state->parser_state.pkg_end; } - } - - close_this_op: - /* - * Finished one argument of the containing scope - */ - parser_state->scope->parse_scope.arg_count--; + break; - /* Finished with pre_op */ + default: - if (pre_op) { - acpi_ps_free_op(pre_op); - pre_op = NULL; + /* No action for all other opcodes */ + break; } - /* Close this Op (will result in parse subtree deletion) */ + break; + } - status2 = acpi_ps_complete_this_op(walk_state, op); - if (ACPI_FAILURE(status2)) { - return_ACPI_STATUS(status2); - } - op = NULL; + return_ACPI_STATUS(AE_OK); +} - switch (status) { - case AE_OK: - break; +/******************************************************************************* + * + * FUNCTION: acpi_ps_complete_op + * + * PARAMETERS: walk_state - Current state + * Op - Returned Op + * Status - Parse status before complete Op + * + * RETURN: Status + * + * DESCRIPTION: Complete Op + * + ******************************************************************************/ - case AE_CTRL_TRANSFER: +static acpi_status +acpi_ps_complete_op(struct acpi_walk_state *walk_state, + union acpi_parse_object **op, acpi_status status) +{ + acpi_status status2; - /* We are about to transfer to a called method. */ + ACPI_FUNCTION_TRACE_PTR(ps_complete_op, walk_state); - walk_state->prev_op = op; - walk_state->prev_arg_types = walk_state->arg_types; - return_ACPI_STATUS(status); + /* + * Finished one argument of the containing scope + */ + walk_state->parser_state.scope->parse_scope.arg_count--; - case AE_CTRL_END: + /* Close this Op (will result in parse subtree deletion) */ - acpi_ps_pop_scope(parser_state, &op, - &walk_state->arg_types, - &walk_state->arg_count); + status2 = acpi_ps_complete_this_op(walk_state, *op); + if (ACPI_FAILURE(status2)) { + return_ACPI_STATUS(status2); + } - if (op) { - walk_state->op = op; - walk_state->op_info = - acpi_ps_get_opcode_info(op->common. - aml_opcode); - walk_state->opcode = op->common.aml_opcode; + *op = NULL; - status = - walk_state->ascending_callback(walk_state); - status = - acpi_ps_next_parse_state(walk_state, op, - status); + switch (status) { + case AE_OK: + break; - status2 = - acpi_ps_complete_this_op(walk_state, op); - if (ACPI_FAILURE(status2)) { - return_ACPI_STATUS(status2); - } - op = NULL; - } - status = AE_OK; - break; + case AE_CTRL_TRANSFER: - case AE_CTRL_BREAK: - case AE_CTRL_CONTINUE: + /* We are about to transfer to a called method */ - /* Pop off scopes until we find the While */ + walk_state->prev_op = NULL; + walk_state->prev_arg_types = walk_state->arg_types; + return_ACPI_STATUS(status); - while (!op || (op->common.aml_opcode != AML_WHILE_OP)) { - acpi_ps_pop_scope(parser_state, &op, - &walk_state->arg_types, - &walk_state->arg_count); + case AE_CTRL_END: - if (op->common.aml_opcode != AML_WHILE_OP) { - status2 = - acpi_ds_result_stack_pop - (walk_state); - if (ACPI_FAILURE(status2)) { - return_ACPI_STATUS(status2); - } - } - } - - /* Close this iteration of the While loop */ + acpi_ps_pop_scope(&(walk_state->parser_state), op, + &walk_state->arg_types, + &walk_state->arg_count); - walk_state->op = op; + if (*op) { + walk_state->op = *op; walk_state->op_info = - acpi_ps_get_opcode_info(op->common.aml_opcode); - walk_state->opcode = op->common.aml_opcode; + acpi_ps_get_opcode_info((*op)->common.aml_opcode); + walk_state->opcode = (*op)->common.aml_opcode; status = walk_state->ascending_callback(walk_state); status = - acpi_ps_next_parse_state(walk_state, op, status); + acpi_ps_next_parse_state(walk_state, *op, status); - status2 = acpi_ps_complete_this_op(walk_state, op); + status2 = acpi_ps_complete_this_op(walk_state, *op); if (ACPI_FAILURE(status2)) { return_ACPI_STATUS(status2); } - op = NULL; - - status = AE_OK; - break; + } - case AE_CTRL_TERMINATE: + status = AE_OK; + break; - status = AE_OK; + case AE_CTRL_BREAK: + case AE_CTRL_CONTINUE: - /* Clean up */ - do { - if (op) { - status2 = - acpi_ps_complete_this_op(walk_state, - op); - if (ACPI_FAILURE(status2)) { - return_ACPI_STATUS(status2); - } + /* Pop off scopes until we find the While */ - status2 = - acpi_ds_result_stack_pop - (walk_state); - if (ACPI_FAILURE(status2)) { - return_ACPI_STATUS(status2); - } + while (!(*op) || ((*op)->common.aml_opcode != AML_WHILE_OP)) { + acpi_ps_pop_scope(&(walk_state->parser_state), op, + &walk_state->arg_types, + &walk_state->arg_count); - acpi_ut_delete_generic_state - (acpi_ut_pop_generic_state - (&walk_state->control_state)); + if ((*op)->common.aml_opcode != AML_WHILE_OP) { + status2 = acpi_ds_result_stack_pop(walk_state); + if (ACPI_FAILURE(status2)) { + return_ACPI_STATUS(status2); } + } + } - acpi_ps_pop_scope(parser_state, &op, - &walk_state->arg_types, - &walk_state->arg_count); + /* Close this iteration of the While loop */ - } while (op); + walk_state->op = *op; + walk_state->op_info = + acpi_ps_get_opcode_info((*op)->common.aml_opcode); + walk_state->opcode = (*op)->common.aml_opcode; - return_ACPI_STATUS(status); + status = walk_state->ascending_callback(walk_state); + status = acpi_ps_next_parse_state(walk_state, *op, status); - default: /* All other non-AE_OK status */ + status2 = acpi_ps_complete_this_op(walk_state, *op); + if (ACPI_FAILURE(status2)) { + return_ACPI_STATUS(status2); + } - do { - if (op) { - status2 = - acpi_ps_complete_this_op(walk_state, - op); - if (ACPI_FAILURE(status2)) { - return_ACPI_STATUS(status2); - } + status = AE_OK; + break; + + case AE_CTRL_TERMINATE: + + /* Clean up */ + do { + if (*op) { + status2 = + acpi_ps_complete_this_op(walk_state, *op); + if (ACPI_FAILURE(status2)) { + return_ACPI_STATUS(status2); + } + status2 = acpi_ds_result_stack_pop(walk_state); + if (ACPI_FAILURE(status2)) { + return_ACPI_STATUS(status2); } - acpi_ps_pop_scope(parser_state, &op, - &walk_state->arg_types, - &walk_state->arg_count); + acpi_ut_delete_generic_state + (acpi_ut_pop_generic_state + (&walk_state->control_state)); + } - } while (op); + acpi_ps_pop_scope(&(walk_state->parser_state), op, + &walk_state->arg_types, + &walk_state->arg_count); - /* - * TBD: Cleanup parse ops on error - */ -#if 0 - if (op == NULL) { - acpi_ps_pop_scope(parser_state, &op, - &walk_state->arg_types, - &walk_state->arg_count); + } while (*op); + + return_ACPI_STATUS(AE_OK); + + default: /* All other non-AE_OK status */ + + do { + if (*op) { + status2 = + acpi_ps_complete_this_op(walk_state, *op); + if (ACPI_FAILURE(status2)) { + return_ACPI_STATUS(status2); + } } -#endif - walk_state->prev_op = op; - walk_state->prev_arg_types = walk_state->arg_types; - return_ACPI_STATUS(status); - } - /* This scope complete? */ + acpi_ps_pop_scope(&(walk_state->parser_state), op, + &walk_state->arg_types, + &walk_state->arg_count); - if (acpi_ps_has_completed_scope(parser_state)) { - acpi_ps_pop_scope(parser_state, &op, + } while (*op); + +#if 0 + /* + * TBD: Cleanup parse ops on error + */ + if (*op == NULL) { + acpi_ps_pop_scope(parser_state, op, &walk_state->arg_types, &walk_state->arg_count); - ACPI_DEBUG_PRINT((ACPI_DB_PARSE, - "Popped scope, Op=%p\n", op)); - } else { - op = NULL; } +#endif + walk_state->prev_op = NULL; + walk_state->prev_arg_types = walk_state->arg_types; + return_ACPI_STATUS(status); + } - } /* while parser_state->Aml */ + /* This scope complete? */ + + if (acpi_ps_has_completed_scope(&(walk_state->parser_state))) { + acpi_ps_pop_scope(&(walk_state->parser_state), op, + &walk_state->arg_types, + &walk_state->arg_count); + ACPI_DEBUG_PRINT((ACPI_DB_PARSE, "Popped scope, Op=%p\n", *op)); + } else { + *op = NULL; + } + + return_ACPI_STATUS(AE_OK); +} + +/******************************************************************************* + * + * FUNCTION: acpi_ps_complete_final_op + * + * PARAMETERS: walk_state - Current state + * Op - Current Op + * Status - Current parse status before complete last + * Op + * + * RETURN: Status + * + * DESCRIPTION: Complete last Op. + * + ******************************************************************************/ + +static acpi_status +acpi_ps_complete_final_op(struct acpi_walk_state *walk_state, + union acpi_parse_object *op, acpi_status status) +{ + acpi_status status2; + + ACPI_FUNCTION_TRACE_PTR(ps_complete_final_op, walk_state); /* * Complete the last Op (if not completed), and clear the scope stack. * It is easily possible to end an AML "package" with an unbounded number * of open scopes (such as when several ASL blocks are closed with - * sequential closing braces). We want to terminate each one cleanly. + * sequential closing braces). We want to terminate each one cleanly. */ ACPI_DEBUG_PRINT((ACPI_DB_PARSE, "AML package complete at Op %p\n", op)); @@ -838,8 +750,12 @@ #endif acpi_ps_next_parse_state(walk_state, op, status); if (status == AE_CTRL_PENDING) { - status = AE_OK; - goto close_this_op; + status = + acpi_ps_complete_op(walk_state, &op, + AE_OK); + if (ACPI_FAILURE(status)) { + return_ACPI_STATUS(status); + } } if (status == AE_CTRL_TERMINATE) { @@ -858,7 +774,9 @@ #endif } } - acpi_ps_pop_scope(parser_state, + acpi_ps_pop_scope(& + (walk_state-> + parser_state), &op, &walk_state-> arg_types, @@ -887,10 +805,252 @@ #endif } } - acpi_ps_pop_scope(parser_state, &op, &walk_state->arg_types, + acpi_ps_pop_scope(&(walk_state->parser_state), &op, + &walk_state->arg_types, &walk_state->arg_count); } while (op); return_ACPI_STATUS(status); } + +/******************************************************************************* + * + * FUNCTION: acpi_ps_parse_loop + * + * PARAMETERS: walk_state - Current state + * + * RETURN: Status + * + * DESCRIPTION: Parse AML (pointed to by the current parser state) and return + * a tree of ops. + * + ******************************************************************************/ + +acpi_status acpi_ps_parse_loop(struct acpi_walk_state *walk_state) +{ + acpi_status status = AE_OK; + union acpi_parse_object *op = NULL; /* current op */ + struct acpi_parse_state *parser_state; + u8 *aml_op_start = NULL; + + ACPI_FUNCTION_TRACE_PTR(ps_parse_loop, walk_state); + + if (walk_state->descending_callback == NULL) { + return_ACPI_STATUS(AE_BAD_PARAMETER); + } + + parser_state = &walk_state->parser_state; + walk_state->arg_types = 0; + +#if (!defined (ACPI_NO_METHOD_EXECUTION) && !defined (ACPI_CONSTANT_EVAL_ONLY)) + + if (walk_state->walk_type & ACPI_WALK_METHOD_RESTART) { + + /* We are restarting a preempted control method */ + + if (acpi_ps_has_completed_scope(parser_state)) { + /* + * We must check if a predicate to an IF or WHILE statement + * was just completed + */ + if ((parser_state->scope->parse_scope.op) && + ((parser_state->scope->parse_scope.op->common. + aml_opcode == AML_IF_OP) + || (parser_state->scope->parse_scope.op->common. + aml_opcode == AML_WHILE_OP)) + && (walk_state->control_state) + && (walk_state->control_state->common.state == + ACPI_CONTROL_PREDICATE_EXECUTING)) { + /* + * A predicate was just completed, get the value of the + * predicate and branch based on that value + */ + walk_state->op = NULL; + status = + acpi_ds_get_predicate_value(walk_state, + ACPI_TO_POINTER + (TRUE)); + if (ACPI_FAILURE(status) + && ((status & AE_CODE_MASK) != + AE_CODE_CONTROL)) { + if (status == AE_AML_NO_RETURN_VALUE) { + ACPI_EXCEPTION((AE_INFO, status, + "Invoked method did not return a value")); + + } + + ACPI_EXCEPTION((AE_INFO, status, + "GetPredicate Failed")); + return_ACPI_STATUS(status); + } + + status = + acpi_ps_next_parse_state(walk_state, op, + status); + } + + acpi_ps_pop_scope(parser_state, &op, + &walk_state->arg_types, + &walk_state->arg_count); + ACPI_DEBUG_PRINT((ACPI_DB_PARSE, + "Popped scope, Op=%p\n", op)); + } else if (walk_state->prev_op) { + + /* We were in the middle of an op */ + + op = walk_state->prev_op; + walk_state->arg_types = walk_state->prev_arg_types; + } + } +#endif + + /* Iterative parsing loop, while there is more AML to process: */ + + while ((parser_state->aml < parser_state->aml_end) || (op)) { + aml_op_start = parser_state->aml; + if (!op) { + status = + acpi_ps_create_op(walk_state, aml_op_start, &op); + if (ACPI_FAILURE(status)) { + if (status == AE_CTRL_PARSE_CONTINUE) { + continue; + } + + if (status == AE_CTRL_PARSE_PENDING) { + status = AE_OK; + } + + status = + acpi_ps_complete_op(walk_state, &op, + status); + if (ACPI_FAILURE(status)) { + return_ACPI_STATUS(status); + } + + continue; + } + + op->common.aml_offset = walk_state->aml_offset; + + if (walk_state->op_info) { + ACPI_DEBUG_PRINT((ACPI_DB_PARSE, + "Opcode %4.4X [%s] Op %p Aml %p AmlOffset %5.5X\n", + (u32) op->common.aml_opcode, + walk_state->op_info->name, op, + parser_state->aml, + op->common.aml_offset)); + } + } + + /* + * Start arg_count at zero because we don't know if there are + * any args yet + */ + walk_state->arg_count = 0; + + /* Are there any arguments that must be processed? */ + + if (walk_state->arg_types) { + + /* Get arguments */ + + status = + acpi_ps_get_arguments(walk_state, aml_op_start, op); + if (ACPI_FAILURE(status)) { + status = + acpi_ps_complete_op(walk_state, &op, + status); + if (ACPI_FAILURE(status)) { + return_ACPI_STATUS(status); + } + + continue; + } + } + + /* Check for arguments that need to be processed */ + + if (walk_state->arg_count) { + /* + * There are arguments (complex ones), push Op and + * prepare for argument + */ + status = acpi_ps_push_scope(parser_state, op, + walk_state->arg_types, + walk_state->arg_count); + if (ACPI_FAILURE(status)) { + status = + acpi_ps_complete_op(walk_state, &op, + status); + if (ACPI_FAILURE(status)) { + return_ACPI_STATUS(status); + } + + continue; + } + + op = NULL; + continue; + } + + /* + * All arguments have been processed -- Op is complete, + * prepare for next + */ + walk_state->op_info = + acpi_ps_get_opcode_info(op->common.aml_opcode); + if (walk_state->op_info->flags & AML_NAMED) { + if (acpi_gbl_depth) { + acpi_gbl_depth--; + } + + if (op->common.aml_opcode == AML_REGION_OP) { + /* + * Skip parsing of control method or opregion body, + * because we don't have enough info in the first pass + * to parse them correctly. + * + * Completed parsing an op_region declaration, we now + * know the length. + */ + op->named.length = + (u32) (parser_state->aml - op->named.data); + } + } + + if (walk_state->op_info->flags & AML_CREATE) { + /* + * Backup to beginning of create_xXXfield declaration (1 for + * Opcode) + * + * body_length is unknown until we parse the body + */ + op->named.length = + (u32) (parser_state->aml - op->named.data); + } + + /* This op complete, notify the dispatcher */ + + if (walk_state->ascending_callback != NULL) { + walk_state->op = op; + walk_state->opcode = op->common.aml_opcode; + + status = walk_state->ascending_callback(walk_state); + status = + acpi_ps_next_parse_state(walk_state, op, status); + if (status == AE_CTRL_PENDING) { + status = AE_OK; + } + } + + status = acpi_ps_complete_op(walk_state, &op, status); + if (ACPI_FAILURE(status)) { + return_ACPI_STATUS(status); + } + + } /* while parser_state->Aml */ + + status = acpi_ps_complete_final_op(walk_state, op, status); + return_ACPI_STATUS(status); +} diff --git a/drivers/acpi/parser/psopcode.c b/drivers/acpi/parser/psopcode.c index 4bd25e3..16d8b6c 100644 --- a/drivers/acpi/parser/psopcode.c +++ b/drivers/acpi/parser/psopcode.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2006, R. Byron Moore + * Copyright (C) 2000 - 2007, R. Byron Moore * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/parser/psparse.c b/drivers/acpi/parser/psparse.c index a02aa62..5d63f48 100644 --- a/drivers/acpi/parser/psparse.c +++ b/drivers/acpi/parser/psparse.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2006, R. Byron Moore + * Copyright (C) 2000 - 2007, R. Byron Moore * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -540,6 +540,11 @@ acpi_status acpi_ps_parse_aml(struct acp if ((status == AE_ALREADY_EXISTS) && (!walk_state->method_desc->method.mutex)) { + ACPI_INFO((AE_INFO, + "Marking method %4.4s as Serialized", + walk_state->method_node->name. + ascii)); + /* * Method tried to create an object twice. The probable cause is * that the method cannot handle reentrancy. diff --git a/drivers/acpi/parser/psscope.c b/drivers/acpi/parser/psscope.c index a3e0314..77cfa4e 100644 --- a/drivers/acpi/parser/psscope.c +++ b/drivers/acpi/parser/psscope.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2006, R. Byron Moore + * Copyright (C) 2000 - 2007, R. Byron Moore * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/parser/pstree.c b/drivers/acpi/parser/pstree.c index 0015717..966e7ea 100644 --- a/drivers/acpi/parser/pstree.c +++ b/drivers/acpi/parser/pstree.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2006, R. Byron Moore + * Copyright (C) 2000 - 2007, R. Byron Moore * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/parser/psutils.c b/drivers/acpi/parser/psutils.c index d405387..8ca5200 100644 --- a/drivers/acpi/parser/psutils.c +++ b/drivers/acpi/parser/psutils.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2006, R. Byron Moore + * Copyright (C) 2000 - 2007, R. Byron Moore * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/parser/pswalk.c b/drivers/acpi/parser/pswalk.c index a84a547..49f9757 100644 --- a/drivers/acpi/parser/pswalk.c +++ b/drivers/acpi/parser/pswalk.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2006, R. Byron Moore + * Copyright (C) 2000 - 2007, R. Byron Moore * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/parser/psxface.c b/drivers/acpi/parser/psxface.c index 5d996c1..94103bc 100644 --- a/drivers/acpi/parser/psxface.c +++ b/drivers/acpi/parser/psxface.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2006, R. Byron Moore + * Copyright (C) 2000 - 2007, R. Byron Moore * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -54,8 +54,6 @@ static void acpi_ps_start_trace(struct a static void acpi_ps_stop_trace(struct acpi_evaluate_info *info); -static acpi_status acpi_ps_execute_pass(struct acpi_evaluate_info *info); - static void acpi_ps_update_parameter_list(struct acpi_evaluate_info *info, u16 action); @@ -215,6 +213,8 @@ static void acpi_ps_stop_trace(struct ac acpi_status acpi_ps_execute_method(struct acpi_evaluate_info *info) { acpi_status status; + union acpi_parse_object *op; + struct acpi_walk_state *walk_state; ACPI_FUNCTION_TRACE(ps_execute_method); @@ -234,8 +234,7 @@ acpi_status acpi_ps_execute_method(struc } /* - * The caller "owns" the parameters, so give each one an extra - * reference + * The caller "owns" the parameters, so give each one an extra reference */ acpi_ps_update_parameter_list(info, REF_INCREMENT); @@ -244,30 +243,50 @@ acpi_status acpi_ps_execute_method(struc acpi_ps_start_trace(info); /* - * 1) Perform the first pass parse of the method to enter any - * named objects that it creates into the namespace + * Execute the method. Performs parse simultaneously */ ACPI_DEBUG_PRINT((ACPI_DB_PARSE, - "**** Begin Method Parse **** Entry=%p obj=%p\n", - info->resolved_node, info->obj_desc)); + "**** Begin Method Parse/Execute [%4.4s] **** Node=%p Obj=%p\n", + info->resolved_node->name.ascii, info->resolved_node, + info->obj_desc)); + + /* Create and init a Root Node */ + + op = acpi_ps_create_scope_op(); + if (!op) { + status = AE_NO_MEMORY; + goto cleanup; + } + + /* Create and initialize a new walk state */ + + info->pass_number = ACPI_IMODE_EXECUTE; + walk_state = + acpi_ds_create_walk_state(info->obj_desc->method.owner_id, NULL, + NULL, NULL); + if (!walk_state) { + status = AE_NO_MEMORY; + goto cleanup; + } - info->pass_number = 1; - status = acpi_ps_execute_pass(info); + status = acpi_ds_init_aml_walk(walk_state, op, info->resolved_node, + info->obj_desc->method.aml_start, + info->obj_desc->method.aml_length, info, + info->pass_number); if (ACPI_FAILURE(status)) { + acpi_ds_delete_walk_state(walk_state); goto cleanup; } - /* - * 2) Execute the method. Performs second pass parse simultaneously - */ - ACPI_DEBUG_PRINT((ACPI_DB_PARSE, - "**** Begin Method Execution **** Entry=%p obj=%p\n", - info->resolved_node, info->obj_desc)); + /* Parse the AML */ - info->pass_number = 3; - status = acpi_ps_execute_pass(info); + status = acpi_ps_parse_aml(walk_state); + + /* walk_state was deleted by parse_aml */ cleanup: + acpi_ps_delete_parse_tree(op); + /* End optional tracing */ acpi_ps_stop_trace(info); @@ -330,62 +349,3 @@ acpi_ps_update_parameter_list(struct acp } } } - -/******************************************************************************* - * - * FUNCTION: acpi_ps_execute_pass - * - * PARAMETERS: Info - See struct acpi_evaluate_info - * (Used: pass_number, Node, and obj_desc) - * - * RETURN: Status - * - * DESCRIPTION: Single AML pass: Parse or Execute a control method - * - ******************************************************************************/ - -static acpi_status acpi_ps_execute_pass(struct acpi_evaluate_info *info) -{ - acpi_status status; - union acpi_parse_object *op; - struct acpi_walk_state *walk_state; - - ACPI_FUNCTION_TRACE(ps_execute_pass); - - /* Create and init a Root Node */ - - op = acpi_ps_create_scope_op(); - if (!op) { - return_ACPI_STATUS(AE_NO_MEMORY); - } - - /* Create and initialize a new walk state */ - - walk_state = - acpi_ds_create_walk_state(info->obj_desc->method.owner_id, NULL, - NULL, NULL); - if (!walk_state) { - status = AE_NO_MEMORY; - goto cleanup; - } - - status = acpi_ds_init_aml_walk(walk_state, op, info->resolved_node, - info->obj_desc->method.aml_start, - info->obj_desc->method.aml_length, - info->pass_number == 1 ? NULL : info, - info->pass_number); - if (ACPI_FAILURE(status)) { - acpi_ds_delete_walk_state(walk_state); - goto cleanup; - } - - /* Parse the AML */ - - status = acpi_ps_parse_aml(walk_state); - - /* Walk state was deleted by parse_aml */ - - cleanup: - acpi_ps_delete_parse_tree(op); - return_ACPI_STATUS(status); -} diff --git a/drivers/acpi/pci_link.c b/drivers/acpi/pci_link.c index 481e633..0f683c8 100644 --- a/drivers/acpi/pci_link.c +++ b/drivers/acpi/pci_link.c @@ -513,7 +513,7 @@ int __init acpi_irq_penalty_init(void) } } /* Add a penalty for the SCI */ - acpi_irq_penalty[acpi_fadt.sci_int] += PIRQ_PENALTY_PCI_USING; + acpi_irq_penalty[acpi_gbl_FADT.sci_interrupt] += PIRQ_PENALTY_PCI_USING; return 0; } @@ -785,7 +785,7 @@ static int irqrouter_resume(struct sys_d /* Make sure SCI is enabled again (Apple firmware bug?) */ - acpi_set_register(ACPI_BITREG_SCI_ENABLE, 1, ACPI_MTX_DO_NOT_LOCK); + acpi_set_register(ACPI_BITREG_SCI_ENABLE, 1); list_for_each(node, &acpi_link.entries) { link = list_entry(node, struct acpi_pci_link, node); diff --git a/drivers/acpi/pci_root.c b/drivers/acpi/pci_root.c index a860efa..4ecf701 100644 --- a/drivers/acpi/pci_root.c +++ b/drivers/acpi/pci_root.c @@ -117,6 +117,19 @@ void acpi_pci_unregister_driver(struct a EXPORT_SYMBOL(acpi_pci_unregister_driver); +acpi_handle acpi_get_pci_rootbridge_handle(unsigned int seg, unsigned int bus) +{ + struct acpi_pci_root *tmp; + + list_for_each_entry(tmp, &acpi_pci_roots, node) { + if ((tmp->id.segment == (u16) seg) && (tmp->id.bus == (u16) bus)) + return tmp->device->handle; + } + return NULL; +} + +EXPORT_SYMBOL_GPL(acpi_get_pci_rootbridge_handle); + static acpi_status get_root_bridge_busnr_callback(struct acpi_resource *resource, void *data) { @@ -152,6 +165,21 @@ static acpi_status try_get_root_bridge_b return AE_OK; } +static void acpi_pci_bridge_scan(struct acpi_device *device) +{ + int status; + struct acpi_device *child = NULL; + + if (device->flags.bus_address) + if (device->parent && device->parent->ops.bind) { + status = device->parent->ops.bind(device); + if (!status) { + list_for_each_entry(child, &device->children, node) + acpi_pci_bridge_scan(child); + } + } +} + static int acpi_pci_root_add(struct acpi_device *device) { int result = 0; @@ -160,6 +188,7 @@ static int acpi_pci_root_add(struct acpi acpi_status status = AE_OK; unsigned long value = 0; acpi_handle handle = NULL; + struct acpi_device *child; if (!device) @@ -175,9 +204,6 @@ static int acpi_pci_root_add(struct acpi strcpy(acpi_device_class(device), ACPI_PCI_ROOT_CLASS); acpi_driver_data(device) = root; - /* - * TBD: Doesn't the bus driver automatically set this? - */ device->ops.bind = acpi_pci_bind; /* @@ -299,6 +325,12 @@ static int acpi_pci_root_add(struct acpi result = acpi_pci_irq_add_prt(device->handle, root->id.segment, root->id.bus); + /* + * Scan and bind all _ADR-Based Devices + */ + list_for_each_entry(child, &device->children, node) + acpi_pci_bridge_scan(child); + end: if (result) { if (!list_empty(&root->node)) diff --git a/drivers/acpi/processor_core.c b/drivers/acpi/processor_core.c index 5f9496d..0079bc5 100644 --- a/drivers/acpi/processor_core.c +++ b/drivers/acpi/processor_core.c @@ -375,30 +375,126 @@ static int acpi_processor_remove_fs(stru } /* Use the acpiid in MADT to map cpus in case of SMP */ + #ifndef CONFIG_SMP -#define convert_acpiid_to_cpu(acpi_id) (-1) +static int get_cpu_id(acpi_handle handle, u32 acpi_id) {return -1;} #else +static struct acpi_table_madt *madt; + +static int map_lapic_id(struct acpi_subtable_header *entry, + u32 acpi_id, int *apic_id) +{ + struct acpi_madt_local_apic *lapic = + (struct acpi_madt_local_apic *)entry; + if ((lapic->lapic_flags & ACPI_MADT_ENABLED) && + lapic->processor_id == acpi_id) { + *apic_id = lapic->id; + return 1; + } + return 0; +} + +static int map_lsapic_id(struct acpi_subtable_header *entry, + u32 acpi_id, int *apic_id) +{ + struct acpi_madt_local_sapic *lsapic = + (struct acpi_madt_local_sapic *)entry; + /* Only check enabled APICs*/ + if (lsapic->lapic_flags & ACPI_MADT_ENABLED) { + /* First check against id */ + if (lsapic->processor_id == acpi_id) { + *apic_id = lsapic->id; + return 1; + /* Check against optional uid */ + } else if (entry->length >= 16 && + lsapic->uid == acpi_id) { + *apic_id = lsapic->uid; + return 1; + } + } + return 0; +} + #ifdef CONFIG_IA64 -#define arch_acpiid_to_apicid ia64_acpiid_to_sapicid #define arch_cpu_to_apicid ia64_cpu_to_sapicid -#define ARCH_BAD_APICID (0xffff) #else -#define arch_acpiid_to_apicid x86_acpiid_to_apicid #define arch_cpu_to_apicid x86_cpu_to_apicid -#define ARCH_BAD_APICID (0xff) #endif -static int convert_acpiid_to_cpu(u8 acpi_id) +static int map_madt_entry(u32 acpi_id) +{ + unsigned long madt_end, entry; + int apic_id = -1; + + if (!madt) + return apic_id; + + entry = (unsigned long)madt; + madt_end = entry + madt->header.length; + + /* Parse all entries looking for a match. */ + + entry += sizeof(struct acpi_table_madt); + while (entry + sizeof(struct acpi_subtable_header) < madt_end) { + struct acpi_subtable_header *header = + (struct acpi_subtable_header *)entry; + if (header->type == ACPI_MADT_TYPE_LOCAL_APIC) { + if (map_lapic_id(header, acpi_id, &apic_id)) + break; + } else if (header->type == ACPI_MADT_TYPE_LOCAL_SAPIC) { + if (map_lsapic_id(header, acpi_id, &apic_id)) + break; + } + entry += header->length; + } + return apic_id; +} + +static int map_mat_entry(acpi_handle handle, u32 acpi_id) +{ + struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL }; + union acpi_object *obj; + struct acpi_subtable_header *header; + int apic_id = -1; + + if (ACPI_FAILURE(acpi_evaluate_object(handle, "_MAT", NULL, &buffer))) + goto exit; + + if (!buffer.length || !buffer.pointer) + goto exit; + + obj = buffer.pointer; + if (obj->type != ACPI_TYPE_BUFFER || + obj->buffer.length < sizeof(struct acpi_subtable_header)) { + goto exit; + } + + header = (struct acpi_subtable_header *)obj->buffer.pointer; + if (header->type == ACPI_MADT_TYPE_LOCAL_APIC) { + map_lapic_id(header, acpi_id, &apic_id); + } else if (header->type == ACPI_MADT_TYPE_LOCAL_SAPIC) { + map_lsapic_id(header, acpi_id, &apic_id); + } + +exit: + if (buffer.pointer) + kfree(buffer.pointer); + return apic_id; +} + +static int get_cpu_id(acpi_handle handle, u32 acpi_id) { - u16 apic_id; int i; + int apic_id = -1; - apic_id = arch_acpiid_to_apicid[acpi_id]; - if (apic_id == ARCH_BAD_APICID) - return -1; + apic_id = map_mat_entry(handle, acpi_id); + if (apic_id == -1) + apic_id = map_madt_entry(acpi_id); + if (apic_id == -1) + return apic_id; - for (i = 0; i < NR_CPUS; i++) { + for (i = 0; i < NR_CPUS; ++i) { if (arch_cpu_to_apicid[i] == apic_id) return i; } @@ -410,7 +506,7 @@ #endif Driver Interface -------------------------------------------------------------------------- */ -static int acpi_processor_get_info(struct acpi_processor *pr) +static int acpi_processor_get_info(struct acpi_processor *pr, unsigned has_uid) { acpi_status status = 0; union acpi_object object = { 0 }; @@ -431,7 +527,7 @@ static int acpi_processor_get_info(struc * Check to see if we have bus mastering arbitration control. This * is required for proper C3 usage (to maintain cache coherency). */ - if (acpi_fadt.V1_pm2_cnt_blk && acpi_fadt.pm2_cnt_len) { + if (acpi_gbl_FADT.pm2_control_block && acpi_gbl_FADT.pm2_control_length) { pr->flags.bm_control = 1; ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Bus mastering arbitration control present\n")); @@ -439,24 +535,35 @@ static int acpi_processor_get_info(struc ACPI_DEBUG_PRINT((ACPI_DB_INFO, "No bus mastering arbitration control\n")); - /* - * Evalute the processor object. Note that it is common on SMP to - * have the first (boot) processor with a valid PBLK address while - * all others have a NULL address. - */ - status = acpi_evaluate_object(pr->handle, NULL, NULL, &buffer); - if (ACPI_FAILURE(status)) { - printk(KERN_ERR PREFIX "Evaluating processor object\n"); - return -ENODEV; - } - - /* - * TBD: Synch processor ID (via LAPIC/LSAPIC structures) on SMP. - * >>> 'acpi_get_processor_id(acpi_id, &id)' in arch/xxx/acpi.c - */ - pr->acpi_id = object.processor.proc_id; + /* Check if it is a Device with HID and UID */ + if (has_uid) { + unsigned long value; + status = acpi_evaluate_integer(pr->handle, METHOD_NAME__UID, + NULL, &value); + if (ACPI_FAILURE(status)) { + printk(KERN_ERR PREFIX "Evaluating processor _UID\n"); + return -ENODEV; + } + pr->acpi_id = value; + } else { + /* + * Evalute the processor object. Note that it is common on SMP to + * have the first (boot) processor with a valid PBLK address while + * all others have a NULL address. + */ + status = acpi_evaluate_object(pr->handle, NULL, NULL, &buffer); + if (ACPI_FAILURE(status)) { + printk(KERN_ERR PREFIX "Evaluating processor object\n"); + return -ENODEV; + } - cpu_index = convert_acpiid_to_cpu(pr->acpi_id); + /* + * TBD: Synch processor ID (via LAPIC/LSAPIC structures) on SMP. + * >>> 'acpi_get_processor_id(acpi_id, &id)' in arch/xxx/acpi.c + */ + pr->acpi_id = object.processor.proc_id; + } + cpu_index = get_cpu_id(pr->handle, pr->acpi_id); /* Handle UP system running SMP kernel, with no LAPIC in MADT */ if (!cpu0_initialized && (cpu_index == -1) && @@ -473,7 +580,7 @@ static int acpi_processor_get_info(struc * less than the max # of CPUs. They should be ignored _iff * they are physically not present. */ - if (cpu_index == -1) { + if (pr->id == -1) { if (ACPI_FAILURE (acpi_processor_hotadd_init(pr->handle, &pr->id))) { return -ENODEV; @@ -490,8 +597,8 @@ static int acpi_processor_get_info(struc object.processor.pblk_length); else { pr->throttling.address = object.processor.pblk_address; - pr->throttling.duty_offset = acpi_fadt.duty_offset; - pr->throttling.duty_width = acpi_fadt.duty_width; + pr->throttling.duty_offset = acpi_gbl_FADT.duty_offset; + pr->throttling.duty_width = acpi_gbl_FADT.duty_width; pr->pblk = object.processor.pblk_address; @@ -525,7 +632,7 @@ static int __cpuinit acpi_processor_star pr = acpi_driver_data(device); - result = acpi_processor_get_info(pr); + result = acpi_processor_get_info(pr, device->flags.unique_id); if (result) { /* Processor is physically not present */ return 0; @@ -707,7 +814,7 @@ int acpi_processor_device_add(acpi_handl return -ENODEV; if ((pr->id >= 0) && (pr->id < NR_CPUS)) { - kobject_uevent(&(*device)->kobj, KOBJ_ONLINE); + kobject_uevent(&(*device)->dev.kobj, KOBJ_ONLINE); } return 0; } @@ -745,13 +852,13 @@ acpi_processor_hotplug_notify(acpi_handl } if (pr->id >= 0 && (pr->id < NR_CPUS)) { - kobject_uevent(&device->kobj, KOBJ_OFFLINE); + kobject_uevent(&device->dev.kobj, KOBJ_OFFLINE); break; } result = acpi_processor_start(device); if ((!result) && ((pr->id >= 0) && (pr->id < NR_CPUS))) { - kobject_uevent(&device->kobj, KOBJ_ONLINE); + kobject_uevent(&device->dev.kobj, KOBJ_ONLINE); } else { printk(KERN_ERR PREFIX "Device [%s] failed to start\n", acpi_device_bid(device)); @@ -774,7 +881,7 @@ acpi_processor_hotplug_notify(acpi_handl } if ((pr->id < NR_CPUS) && (cpu_present(pr->id))) - kobject_uevent(&device->kobj, KOBJ_OFFLINE); + kobject_uevent(&device->dev.kobj, KOBJ_OFFLINE); break; default: ACPI_DEBUG_PRINT((ACPI_DB_INFO, @@ -895,6 +1002,12 @@ static int __init acpi_processor_init(vo memset(&processors, 0, sizeof(processors)); memset(&errata, 0, sizeof(errata)); +#ifdef CONFIG_SMP + if (ACPI_FAILURE(acpi_get_table(ACPI_SIG_MADT, 0, + (struct acpi_table_header **)&madt))) + madt = 0; +#endif + acpi_processor_dir = proc_mkdir(ACPI_PROCESSOR_CLASS, acpi_root_dir); if (!acpi_processor_dir) return -ENOMEM; diff --git a/drivers/acpi/processor_idle.c b/drivers/acpi/processor_idle.c index 3f30af2..8206fc1 100644 --- a/drivers/acpi/processor_idle.c +++ b/drivers/acpi/processor_idle.c @@ -39,6 +39,17 @@ #include #include #include /* need_resched() */ #include +#include + +/* + * Include the apic definitions for x86 to have the APIC timer related defines + * available also for UP (on SMP it gets magically included via linux/smp.h). + * asm/acpi.h is not an option, as it would require more include magic. Also + * creating an empty asm-ia64/apic.h would just trade pest vs. cholera. + */ +#ifdef CONFIG_X86 +#include +#endif #include #include @@ -160,7 +171,7 @@ static inline u32 ticks_elapsed(u32 t1, { if (t2 >= t1) return (t2 - t1); - else if (!acpi_fadt.tmr_val_ext) + else if (!(acpi_gbl_FADT.flags & ACPI_FADT_32BIT_TIMER)) return (((0x00FFFFFF - t1) + t2) & 0x00FFFFFF); else return ((0xFFFFFFFF - t1) + t2); @@ -187,8 +198,7 @@ acpi_processor_power_activate(struct acp case ACPI_STATE_C3: /* Disable bus master reload */ if (new->type != ACPI_STATE_C3 && pr->flags.bm_check) - acpi_set_register(ACPI_BITREG_BUS_MASTER_RLD, 0, - ACPI_MTX_DO_NOT_LOCK); + acpi_set_register(ACPI_BITREG_BUS_MASTER_RLD, 0); break; } } @@ -198,8 +208,7 @@ acpi_processor_power_activate(struct acp case ACPI_STATE_C3: /* Enable bus master reload */ if (old->type != ACPI_STATE_C3 && pr->flags.bm_check) - acpi_set_register(ACPI_BITREG_BUS_MASTER_RLD, 1, - ACPI_MTX_DO_NOT_LOCK); + acpi_set_register(ACPI_BITREG_BUS_MASTER_RLD, 1); break; } @@ -236,10 +245,85 @@ static void acpi_cstate_enter(struct acp /* Dummy wait op - must do something useless after P_LVL2 read because chipsets cannot guarantee that STPCLK# signal gets asserted in time to freeze execution properly. */ - unused = inl(acpi_fadt.xpm_tmr_blk.address); + unused = inl(acpi_gbl_FADT.xpm_timer_block.address); } } +#ifdef ARCH_APICTIMER_STOPS_ON_C3 + +/* + * Some BIOS implementations switch to C3 in the published C2 state. + * This seems to be a common problem on AMD boxen, but other vendors + * are affected too. We pick the most conservative approach: we assume + * that the local APIC stops in both C2 and C3. + */ +static void acpi_timer_check_state(int state, struct acpi_processor *pr, + struct acpi_processor_cx *cx) +{ + struct acpi_processor_power *pwr = &pr->power; + + /* + * Check, if one of the previous states already marked the lapic + * unstable + */ + if (pwr->timer_broadcast_on_state < state) + return; + + if (cx->type >= ACPI_STATE_C2) + pr->power.timer_broadcast_on_state = state; +} + +static void acpi_propagate_timer_broadcast(struct acpi_processor *pr) +{ +#ifdef CONFIG_GENERIC_CLOCKEVENTS + unsigned long reason; + + reason = pr->power.timer_broadcast_on_state < INT_MAX ? + CLOCK_EVT_NOTIFY_BROADCAST_ON : CLOCK_EVT_NOTIFY_BROADCAST_OFF; + + clockevents_notify(reason, &pr->id); +#else + cpumask_t mask = cpumask_of_cpu(pr->id); + + if (pr->power.timer_broadcast_on_state < INT_MAX) + on_each_cpu(switch_APIC_timer_to_ipi, &mask, 1, 1); + else + on_each_cpu(switch_ipi_to_APIC_timer, &mask, 1, 1); +#endif +} + +/* Power(C) State timer broadcast control */ +static void acpi_state_timer_broadcast(struct acpi_processor *pr, + struct acpi_processor_cx *cx, + int broadcast) +{ +#ifdef CONFIG_GENERIC_CLOCKEVENTS + + int state = cx - pr->power.states; + + if (state >= pr->power.timer_broadcast_on_state) { + unsigned long reason; + + reason = broadcast ? CLOCK_EVT_NOTIFY_BROADCAST_ENTER : + CLOCK_EVT_NOTIFY_BROADCAST_EXIT; + clockevents_notify(reason, &pr->id); + } +#endif +} + +#else + +static void acpi_timer_check_state(int state, struct acpi_processor *pr, + struct acpi_processor_cx *cstate) { } +static void acpi_propagate_timer_broadcast(struct acpi_processor *pr) { } +static void acpi_state_timer_broadcast(struct acpi_processor *pr, + struct acpi_processor_cx *cx, + int broadcast) +{ +} + +#endif + static void acpi_processor_idle(void) { struct acpi_processor *pr = NULL; @@ -291,12 +375,10 @@ static void acpi_processor_idle(void) pr->power.bm_activity <<= diff; - acpi_get_register(ACPI_BITREG_BUS_MASTER_STATUS, - &bm_status, ACPI_MTX_DO_NOT_LOCK); + acpi_get_register(ACPI_BITREG_BUS_MASTER_STATUS, &bm_status); if (bm_status) { pr->power.bm_activity |= 0x1; - acpi_set_register(ACPI_BITREG_BUS_MASTER_STATUS, - 1, ACPI_MTX_DO_NOT_LOCK); + acpi_set_register(ACPI_BITREG_BUS_MASTER_STATUS, 1); } /* * PIIX4 Erratum #18: Note that BM_STS doesn't always reflect @@ -338,7 +420,7 @@ #ifdef CONFIG_HOTPLUG_CPU * detection phase, to work cleanly with logical CPU hotplug. */ if ((cx->type != ACPI_STATE_C1) && (num_online_cpus() > 1) && - !pr->flags.has_cst && !acpi_fadt.plvl2_up) + !pr->flags.has_cst && !(acpi_gbl_FADT.flags & ACPI_FADT_C2_MP_SUPPORTED)) cx = &pr->power.states[ACPI_STATE_C1]; #endif @@ -384,11 +466,12 @@ #endif case ACPI_STATE_C2: /* Get start time (ticks) */ - t1 = inl(acpi_fadt.xpm_tmr_blk.address); + t1 = inl(acpi_gbl_FADT.xpm_timer_block.address); /* Invoke C2 */ + acpi_state_timer_broadcast(pr, cx, 1); acpi_cstate_enter(cx); /* Get end time (ticks) */ - t2 = inl(acpi_fadt.xpm_tmr_blk.address); + t2 = inl(acpi_gbl_FADT.xpm_timer_block.address); #ifdef CONFIG_GENERIC_TIME /* TSC halts in C2, so notify users */ @@ -400,6 +483,7 @@ #endif /* Compute time (ticks) that we were actually asleep */ sleep_ticks = ticks_elapsed(t1, t2) - cx->latency_ticks - C2_OVERHEAD; + acpi_state_timer_broadcast(pr, cx, 0); break; case ACPI_STATE_C3: @@ -411,8 +495,7 @@ #endif * All CPUs are trying to go to C3 * Disable bus master arbitration */ - acpi_set_register(ACPI_BITREG_ARB_DISABLE, 1, - ACPI_MTX_DO_NOT_LOCK); + acpi_set_register(ACPI_BITREG_ARB_DISABLE, 1); } } else { /* SMP with no shared cache... Invalidate cache */ @@ -420,16 +503,16 @@ #endif } /* Get start time (ticks) */ - t1 = inl(acpi_fadt.xpm_tmr_blk.address); + t1 = inl(acpi_gbl_FADT.xpm_timer_block.address); /* Invoke C3 */ + acpi_state_timer_broadcast(pr, cx, 1); acpi_cstate_enter(cx); /* Get end time (ticks) */ - t2 = inl(acpi_fadt.xpm_tmr_blk.address); + t2 = inl(acpi_gbl_FADT.xpm_timer_block.address); if (pr->flags.bm_check) { /* Enable bus master arbitration */ atomic_dec(&c3_cpu_count); - acpi_set_register(ACPI_BITREG_ARB_DISABLE, 0, - ACPI_MTX_DO_NOT_LOCK); + acpi_set_register(ACPI_BITREG_ARB_DISABLE, 0); } #ifdef CONFIG_GENERIC_TIME @@ -442,6 +525,7 @@ #endif /* Compute time (ticks) that we were actually asleep */ sleep_ticks = ticks_elapsed(t1, t2) - cx->latency_ticks - C3_OVERHEAD; + acpi_state_timer_broadcast(pr, cx, 0); break; default: @@ -457,7 +541,7 @@ #endif #ifdef CONFIG_HOTPLUG_CPU /* Don't do promotion/demotion */ if ((cx->type == ACPI_STATE_C1) && (num_online_cpus() > 1) && - !pr->flags.has_cst && !acpi_fadt.plvl2_up) { + !pr->flags.has_cst && !(acpi_gbl_FADT.flags & ACPI_FADT_C2_MP_SUPPORTED)) { next_state = cx; goto end; } @@ -627,7 +711,8 @@ #ifndef CONFIG_HOTPLUG_CPU * Check for P_LVL2_UP flag before entering C2 and above on * an SMP system. */ - if ((num_online_cpus() > 1) && !acpi_fadt.plvl2_up) + if ((num_online_cpus() > 1) && + !(acpi_gbl_FADT.flags & ACPI_FADT_C2_MP_SUPPORTED)) return -ENODEV; #endif @@ -636,8 +721,8 @@ #endif pr->power.states[ACPI_STATE_C3].address = pr->pblk + 5; /* determine latencies from FADT */ - pr->power.states[ACPI_STATE_C2].latency = acpi_fadt.plvl2_lat; - pr->power.states[ACPI_STATE_C3].latency = acpi_fadt.plvl3_lat; + pr->power.states[ACPI_STATE_C2].latency = acpi_gbl_FADT.C2latency; + pr->power.states[ACPI_STATE_C3].latency = acpi_gbl_FADT.C3latency; ACPI_DEBUG_PRINT((ACPI_DB_INFO, "lvl2[0x%08x] lvl3[0x%08x]\n", @@ -883,14 +968,13 @@ static void acpi_processor_power_verify_ * WBINVD should be set in fadt, for C3 state to be * supported on when bm_check is not required. */ - if (acpi_fadt.wb_invd != 1) { + if (!(acpi_gbl_FADT.flags & ACPI_FADT_WBINVD)) { ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Cache invalidation should work properly" " for C3 to be enabled on SMP systems\n")); return; } - acpi_set_register(ACPI_BITREG_BUS_MASTER_RLD, - 0, ACPI_MTX_DO_NOT_LOCK); + acpi_set_register(ACPI_BITREG_BUS_MASTER_RLD, 0); } /* @@ -910,11 +994,7 @@ static int acpi_processor_power_verify(s unsigned int i; unsigned int working = 0; -#ifdef ARCH_APICTIMER_STOPS_ON_C3 - int timer_broadcast = 0; - cpumask_t mask = cpumask_of_cpu(pr->id); - on_each_cpu(switch_ipi_to_APIC_timer, &mask, 1, 1); -#endif + pr->power.timer_broadcast_on_state = INT_MAX; for (i = 1; i < ACPI_PROCESSOR_MAX_POWER; i++) { struct acpi_processor_cx *cx = &pr->power.states[i]; @@ -926,21 +1006,14 @@ #endif case ACPI_STATE_C2: acpi_processor_power_verify_c2(cx); -#ifdef ARCH_APICTIMER_STOPS_ON_C3 - /* Some AMD systems fake C3 as C2, but still - have timer troubles */ - if (cx->valid && - boot_cpu_data.x86_vendor == X86_VENDOR_AMD) - timer_broadcast++; -#endif + if (cx->valid) + acpi_timer_check_state(i, pr, cx); break; case ACPI_STATE_C3: acpi_processor_power_verify_c3(pr, cx); -#ifdef ARCH_APICTIMER_STOPS_ON_C3 if (cx->valid) - timer_broadcast++; -#endif + acpi_timer_check_state(i, pr, cx); break; } @@ -948,10 +1021,7 @@ #endif working++; } -#ifdef ARCH_APICTIMER_STOPS_ON_C3 - if (timer_broadcast) - on_each_cpu(switch_APIC_timer_to_ipi, &mask, 1, 1); -#endif + acpi_propagate_timer_broadcast(pr); return (working); } @@ -1096,7 +1166,7 @@ static int acpi_processor_power_seq_show seq_printf(seq, "latency[%03d] usage[%08d] duration[%020llu]\n", pr->power.states[i].latency, pr->power.states[i].usage, - pr->power.states[i].time); + (unsigned long long)pr->power.states[i].time); } end: @@ -1164,9 +1234,9 @@ #endif if (!pr) return -EINVAL; - if (acpi_fadt.cst_cnt && !nocst) { + if (acpi_gbl_FADT.cst_control && !nocst) { status = - acpi_os_write_port(acpi_fadt.smi_cmd, acpi_fadt.cst_cnt, 8); + acpi_os_write_port(acpi_gbl_FADT.smi_command, acpi_gbl_FADT.cst_control, 8); if (ACPI_FAILURE(status)) { ACPI_EXCEPTION((AE_INFO, status, "Notifying BIOS of _CST ability failed")); diff --git a/drivers/acpi/processor_perflib.c b/drivers/acpi/processor_perflib.c index cbb6f08..058f13c 100644 --- a/drivers/acpi/processor_perflib.c +++ b/drivers/acpi/processor_perflib.c @@ -352,31 +352,24 @@ int acpi_processor_notify_smm(struct mod is_done = -EIO; - /* Can't write pstate_cnt to smi_cmd if either value is zero */ - if ((!acpi_fadt.smi_cmd) || (!acpi_fadt.pstate_cnt)) { - ACPI_DEBUG_PRINT((ACPI_DB_INFO, "No SMI port or pstate_cnt\n")); + /* Can't write pstate_control to smi_command if either value is zero */ + if ((!acpi_gbl_FADT.smi_command) || (!acpi_gbl_FADT.pstate_control)) { + ACPI_DEBUG_PRINT((ACPI_DB_INFO, "No SMI port or pstate_control\n")); module_put(calling_module); return 0; } ACPI_DEBUG_PRINT((ACPI_DB_INFO, - "Writing pstate_cnt [0x%x] to smi_cmd [0x%x]\n", - acpi_fadt.pstate_cnt, acpi_fadt.smi_cmd)); + "Writing pstate_control [0x%x] to smi_command [0x%x]\n", + acpi_gbl_FADT.pstate_control, acpi_gbl_FADT.smi_command)); - /* FADT v1 doesn't support pstate_cnt, many BIOS vendors use - * it anyway, so we need to support it... */ - if (acpi_fadt_is_v1) { - ACPI_DEBUG_PRINT((ACPI_DB_INFO, - "Using v1.0 FADT reserved value for pstate_cnt\n")); - } - - status = acpi_os_write_port(acpi_fadt.smi_cmd, - (u32) acpi_fadt.pstate_cnt, 8); + status = acpi_os_write_port(acpi_gbl_FADT.smi_command, + (u32) acpi_gbl_FADT.pstate_control, 8); if (ACPI_FAILURE(status)) { ACPI_EXCEPTION((AE_INFO, status, - "Failed to write pstate_cnt [0x%x] to " - "smi_cmd [0x%x]", acpi_fadt.pstate_cnt, - acpi_fadt.smi_cmd)); + "Failed to write pstate_control [0x%x] to " + "smi_command [0x%x]", acpi_gbl_FADT.pstate_control, + acpi_gbl_FADT.smi_command)); module_put(calling_module); return status; } diff --git a/drivers/acpi/processor_throttling.c b/drivers/acpi/processor_throttling.c index 0ec7dcd..89dff36 100644 --- a/drivers/acpi/processor_throttling.c +++ b/drivers/acpi/processor_throttling.c @@ -125,7 +125,7 @@ int acpi_processor_set_throttling(struct /* Used to clear all duty_value bits */ duty_mask = pr->throttling.state_count - 1; - duty_mask <<= acpi_fadt.duty_offset; + duty_mask <<= acpi_gbl_FADT.duty_offset; duty_mask = ~duty_mask; } @@ -208,7 +208,7 @@ int acpi_processor_get_throttling_info(s return 0; } - pr->throttling.state_count = 1 << acpi_fadt.duty_width; + pr->throttling.state_count = 1 << acpi_gbl_FADT.duty_width; /* * Compute state values. Note that throttling displays a linear power/ diff --git a/drivers/acpi/resources/rsaddr.c b/drivers/acpi/resources/rsaddr.c index 8fa3213..271e615 100644 --- a/drivers/acpi/resources/rsaddr.c +++ b/drivers/acpi/resources/rsaddr.c @@ -5,7 +5,7 @@ ******************************************************************************/ /* - * Copyright (C) 2000 - 2006, R. Byron Moore + * Copyright (C) 2000 - 2007, R. Byron Moore * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/resources/rscalc.c b/drivers/acpi/resources/rscalc.c index cf87b02..8c6d3fd 100644 --- a/drivers/acpi/resources/rscalc.c +++ b/drivers/acpi/resources/rscalc.c @@ -5,7 +5,7 @@ ******************************************************************************/ /* - * Copyright (C) 2000 - 2006, R. Byron Moore + * Copyright (C) 2000 - 2007, R. Byron Moore * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/resources/rscreate.c b/drivers/acpi/resources/rscreate.c index 008058a..1358c06 100644 --- a/drivers/acpi/resources/rscreate.c +++ b/drivers/acpi/resources/rscreate.c @@ -5,7 +5,7 @@ ******************************************************************************/ /* - * Copyright (C) 2000 - 2006, R. Byron Moore + * Copyright (C) 2000 - 2007, R. Byron Moore * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/resources/rsdump.c b/drivers/acpi/resources/rsdump.c index 9c99a72..de20a5d 100644 --- a/drivers/acpi/resources/rsdump.c +++ b/drivers/acpi/resources/rsdump.c @@ -5,7 +5,7 @@ ******************************************************************************/ /* - * Copyright (C) 2000 - 2006, R. Byron Moore + * Copyright (C) 2000 - 2007, R. Byron Moore * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/resources/rsinfo.c b/drivers/acpi/resources/rsinfo.c index 9e7ae2f..7e3c335 100644 --- a/drivers/acpi/resources/rsinfo.c +++ b/drivers/acpi/resources/rsinfo.c @@ -5,7 +5,7 @@ ******************************************************************************/ /* - * Copyright (C) 2000 - 2006, R. Byron Moore + * Copyright (C) 2000 - 2007, R. Byron Moore * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/resources/rsio.c b/drivers/acpi/resources/rsio.c index ea56716..b297bc3 100644 --- a/drivers/acpi/resources/rsio.c +++ b/drivers/acpi/resources/rsio.c @@ -5,7 +5,7 @@ ******************************************************************************/ /* - * Copyright (C) 2000 - 2006, R. Byron Moore + * Copyright (C) 2000 - 2007, R. Byron Moore * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/resources/rsirq.c b/drivers/acpi/resources/rsirq.c index 1fa63bc..5657f7b 100644 --- a/drivers/acpi/resources/rsirq.c +++ b/drivers/acpi/resources/rsirq.c @@ -5,7 +5,7 @@ ******************************************************************************/ /* - * Copyright (C) 2000 - 2006, R. Byron Moore + * Copyright (C) 2000 - 2007, R. Byron Moore * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/resources/rslist.c b/drivers/acpi/resources/rslist.c index 29423ce..a92755c 100644 --- a/drivers/acpi/resources/rslist.c +++ b/drivers/acpi/resources/rslist.c @@ -5,7 +5,7 @@ ******************************************************************************/ /* - * Copyright (C) 2000 - 2006, R. Byron Moore + * Copyright (C) 2000 - 2007, R. Byron Moore * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/resources/rsmemory.c b/drivers/acpi/resources/rsmemory.c index a513193..521eab7 100644 --- a/drivers/acpi/resources/rsmemory.c +++ b/drivers/acpi/resources/rsmemory.c @@ -5,7 +5,7 @@ ******************************************************************************/ /* - * Copyright (C) 2000 - 2006, R. Byron Moore + * Copyright (C) 2000 - 2007, R. Byron Moore * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/resources/rsmisc.c b/drivers/acpi/resources/rsmisc.c index faf6e10..3b63b56 100644 --- a/drivers/acpi/resources/rsmisc.c +++ b/drivers/acpi/resources/rsmisc.c @@ -5,7 +5,7 @@ ******************************************************************************/ /* - * Copyright (C) 2000 - 2006, R. Byron Moore + * Copyright (C) 2000 - 2007, R. Byron Moore * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/resources/rsutils.c b/drivers/acpi/resources/rsutils.c index a9cbee8..2442a8f 100644 --- a/drivers/acpi/resources/rsutils.c +++ b/drivers/acpi/resources/rsutils.c @@ -5,7 +5,7 @@ ******************************************************************************/ /* - * Copyright (C) 2000 - 2006, R. Byron Moore + * Copyright (C) 2000 - 2007, R. Byron Moore * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/resources/rsxface.c b/drivers/acpi/resources/rsxface.c index 1999e2a..991f890 100644 --- a/drivers/acpi/resources/rsxface.c +++ b/drivers/acpi/resources/rsxface.c @@ -5,7 +5,7 @@ ******************************************************************************/ /* - * Copyright (C) 2000 - 2006, R. Byron Moore + * Copyright (C) 2000 - 2007, R. Byron Moore * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c index 283d875..64f26db 100644 --- a/drivers/acpi/scan.c +++ b/drivers/acpi/scan.c @@ -21,101 +21,305 @@ #define ACPI_BUS_DRIVER_NAME "ACPI Bus #define ACPI_BUS_DEVICE_NAME "System Bus" static LIST_HEAD(acpi_device_list); +static LIST_HEAD(acpi_bus_id_list); DEFINE_SPINLOCK(acpi_device_lock); LIST_HEAD(acpi_wakeup_device_list); +struct acpi_device_bus_id{ + char bus_id[15]; + unsigned int instance_no; + struct list_head node; +}; +static int acpi_eject_operation(acpi_handle handle, int lockable) +{ + struct acpi_object_list arg_list; + union acpi_object arg; + acpi_status status = AE_OK; + + /* + * TBD: evaluate _PS3? + */ + + if (lockable) { + arg_list.count = 1; + arg_list.pointer = &arg; + arg.type = ACPI_TYPE_INTEGER; + arg.integer.value = 0; + acpi_evaluate_object(handle, "_LCK", &arg_list, NULL); + } + + arg_list.count = 1; + arg_list.pointer = &arg; + arg.type = ACPI_TYPE_INTEGER; + arg.integer.value = 1; + + /* + * TBD: _EJD support. + */ + + status = acpi_evaluate_object(handle, "_EJ0", &arg_list, NULL); + if (ACPI_FAILURE(status)) { + return (-ENODEV); + } + + return (0); +} -static void acpi_device_release(struct kobject *kobj) +static ssize_t +acpi_eject_store(struct device *d, struct device_attribute *attr, + const char *buf, size_t count) { - struct acpi_device *dev = container_of(kobj, struct acpi_device, kobj); - kfree(dev->pnp.cid_list); - kfree(dev); + int result; + int ret = count; + int islockable; + acpi_status status; + acpi_handle handle; + acpi_object_type type = 0; + struct acpi_device *acpi_device = to_acpi_device(d); + + if ((!count) || (buf[0] != '1')) { + return -EINVAL; + } +#ifndef FORCE_EJECT + if (acpi_device->driver == NULL) { + ret = -ENODEV; + goto err; + } +#endif + status = acpi_get_type(acpi_device->handle, &type); + if (ACPI_FAILURE(status) || (!acpi_device->flags.ejectable)) { + ret = -ENODEV; + goto err; + } + + islockable = acpi_device->flags.lockable; + handle = acpi_device->handle; + + result = acpi_bus_trim(acpi_device, 1); + + if (!result) + result = acpi_eject_operation(handle, islockable); + + if (result) { + ret = -EBUSY; + } + err: + return ret; } -struct acpi_device_attribute { - struct attribute attr; - ssize_t(*show) (struct acpi_device *, char *); - ssize_t(*store) (struct acpi_device *, const char *, size_t); -}; +static DEVICE_ATTR(eject, 0200, NULL, acpi_eject_store); + +static ssize_t +acpi_device_hid_show(struct device *dev, struct device_attribute *attr, char *buf) { + struct acpi_device *acpi_dev = to_acpi_device(dev); + + return sprintf(buf, "%s\n", acpi_dev->pnp.hardware_id); +} +static DEVICE_ATTR(hid, 0444, acpi_device_hid_show, NULL); + +static ssize_t +acpi_device_path_show(struct device *dev, struct device_attribute *attr, char *buf) { + struct acpi_device *acpi_dev = to_acpi_device(dev); + struct acpi_buffer path = {ACPI_ALLOCATE_BUFFER, NULL}; + int result; + + result = acpi_get_name(acpi_dev->handle, ACPI_FULL_PATHNAME, &path); + if(result) + goto end; + + result = sprintf(buf, "%s\n", (char*)path.pointer); + kfree(path.pointer); + end: + return result; +} +static DEVICE_ATTR(path, 0444, acpi_device_path_show, NULL); + +static int acpi_device_setup_files(struct acpi_device *dev) +{ + acpi_status status; + acpi_handle temp; + int result = 0; + + /* + * Devices gotten from FADT don't have a "path" attribute + */ + if(dev->handle) { + result = device_create_file(&dev->dev, &dev_attr_path); + if(result) + goto end; + } -typedef void acpi_device_sysfs_files(struct kobject *, - const struct attribute *); + if(dev->flags.hardware_id) { + result = device_create_file(&dev->dev, &dev_attr_hid); + if(result) + goto end; + } -static void setup_sys_fs_device_files(struct acpi_device *dev, - acpi_device_sysfs_files * func); + /* + * If device has _EJ0, 'eject' file is created that is used to trigger + * hot-removal function from userland. + */ + status = acpi_get_handle(dev->handle, "_EJ0", &temp); + if (ACPI_SUCCESS(status)) + result = device_create_file(&dev->dev, &dev_attr_eject); + end: + return result; +} -#define create_sysfs_device_files(dev) \ - setup_sys_fs_device_files(dev, (acpi_device_sysfs_files *)&sysfs_create_file) -#define remove_sysfs_device_files(dev) \ - setup_sys_fs_device_files(dev, (acpi_device_sysfs_files *)&sysfs_remove_file) +static void acpi_device_remove_files(struct acpi_device *dev) +{ + acpi_status status; + acpi_handle temp; -#define to_acpi_device(n) container_of(n, struct acpi_device, kobj) -#define to_handle_attr(n) container_of(n, struct acpi_device_attribute, attr); + /* + * If device has _EJ0, 'eject' file is created that is used to trigger + * hot-removal function from userland. + */ + status = acpi_get_handle(dev->handle, "_EJ0", &temp); + if (ACPI_SUCCESS(status)) + device_remove_file(&dev->dev, &dev_attr_eject); -static ssize_t acpi_device_attr_show(struct kobject *kobj, - struct attribute *attr, char *buf) + if(dev->flags.hardware_id) + device_remove_file(&dev->dev, &dev_attr_hid); + if(dev->handle) + device_remove_file(&dev->dev, &dev_attr_path); +} +/* -------------------------------------------------------------------------- + ACPI Bus operations + -------------------------------------------------------------------------- */ +static void acpi_device_release(struct device *dev) { - struct acpi_device *device = to_acpi_device(kobj); - struct acpi_device_attribute *attribute = to_handle_attr(attr); - return attribute->show ? attribute->show(device, buf) : -EIO; + struct acpi_device *acpi_dev = to_acpi_device(dev); + + kfree(acpi_dev->pnp.cid_list); + kfree(acpi_dev); } -static ssize_t acpi_device_attr_store(struct kobject *kobj, - struct attribute *attr, const char *buf, - size_t len) + +static int acpi_device_suspend(struct device *dev, pm_message_t state) { - struct acpi_device *device = to_acpi_device(kobj); - struct acpi_device_attribute *attribute = to_handle_attr(attr); - return attribute->store ? attribute->store(device, buf, len) : -EIO; + struct acpi_device *acpi_dev = to_acpi_device(dev); + struct acpi_driver *acpi_drv = acpi_dev->driver; + + if (acpi_drv && acpi_drv->ops.suspend) + return acpi_drv->ops.suspend(acpi_dev, state); + return 0; } -static struct sysfs_ops acpi_device_sysfs_ops = { - .show = acpi_device_attr_show, - .store = acpi_device_attr_store, -}; +static int acpi_device_resume(struct device *dev) +{ + struct acpi_device *acpi_dev = to_acpi_device(dev); + struct acpi_driver *acpi_drv = acpi_dev->driver; -static struct kobj_type ktype_acpi_ns = { - .sysfs_ops = &acpi_device_sysfs_ops, - .release = acpi_device_release, -}; + if (acpi_drv && acpi_drv->ops.resume) + return acpi_drv->ops.resume(acpi_dev); + return 0; +} -static int namespace_uevent(struct kset *kset, struct kobject *kobj, - char **envp, int num_envp, char *buffer, - int buffer_size) +static int acpi_bus_match(struct device *dev, struct device_driver *drv) { - struct acpi_device *dev = to_acpi_device(kobj); - int i = 0; - int len = 0; + struct acpi_device *acpi_dev = to_acpi_device(dev); + struct acpi_driver *acpi_drv = to_acpi_driver(drv); - if (!dev->driver) - return 0; + return !acpi_match_ids(acpi_dev, acpi_drv->ids); +} - if (add_uevent_var(envp, num_envp, &i, buffer, buffer_size, &len, - "PHYSDEVDRIVER=%s", dev->driver->name)) +static int acpi_device_uevent(struct device *dev, char **envp, int num_envp, + char *buffer, int buffer_size) +{ + struct acpi_device *acpi_dev = to_acpi_device(dev); + int i = 0, length = 0, ret = 0; + + if (acpi_dev->flags.hardware_id) + ret = add_uevent_var(envp, num_envp, &i, + buffer, buffer_size, &length, + "HWID=%s", acpi_dev->pnp.hardware_id); + if (ret) return -ENOMEM; + if (acpi_dev->flags.compatible_ids) { + int j; + struct acpi_compatible_id_list *cid_list; + + cid_list = acpi_dev->pnp.cid_list; + + for (j = 0; j < cid_list->count; j++) { + ret = add_uevent_var(envp, num_envp, &i, buffer, + buffer_size, &length, "COMPTID=%s", + cid_list->id[j].value); + if (ret) + return -ENOMEM; + } + } envp[i] = NULL; + return 0; +} + +static int acpi_bus_driver_init(struct acpi_device *, struct acpi_driver *); +static int acpi_start_single_object(struct acpi_device *); +static int acpi_device_probe(struct device * dev) +{ + struct acpi_device *acpi_dev = to_acpi_device(dev); + struct acpi_driver *acpi_drv = to_acpi_driver(dev->driver); + int ret; + + ret = acpi_bus_driver_init(acpi_dev, acpi_drv); + if (!ret) { + if (acpi_dev->bus_ops.acpi_op_start) + acpi_start_single_object(acpi_dev); + ACPI_DEBUG_PRINT((ACPI_DB_INFO, + "Found driver [%s] for device [%s]\n", + acpi_drv->name, acpi_dev->pnp.bus_id)); + get_device(dev); + } + return ret; +} +static int acpi_device_remove(struct device * dev) +{ + struct acpi_device *acpi_dev = to_acpi_device(dev); + struct acpi_driver *acpi_drv = acpi_dev->driver; + + if (acpi_drv) { + if (acpi_drv->ops.stop) + acpi_drv->ops.stop(acpi_dev, acpi_dev->removal_type); + if (acpi_drv->ops.remove) + acpi_drv->ops.remove(acpi_dev, acpi_dev->removal_type); + } + acpi_dev->driver = NULL; + acpi_driver_data(dev) = NULL; + + put_device(dev); return 0; } -static struct kset_uevent_ops namespace_uevent_ops = { - .uevent = &namespace_uevent, -}; +static void acpi_device_shutdown(struct device *dev) +{ + struct acpi_device *acpi_dev = to_acpi_device(dev); + struct acpi_driver *acpi_drv = acpi_dev->driver; + + if (acpi_drv && acpi_drv->ops.shutdown) + acpi_drv->ops.shutdown(acpi_dev); -static struct kset acpi_namespace_kset = { - .kobj = { - .name = "namespace", - }, - .subsys = &acpi_subsys, - .ktype = &ktype_acpi_ns, - .uevent_ops = &namespace_uevent_ops, + return ; +} + +static struct bus_type acpi_bus_type = { + .name = "acpi", + .suspend = acpi_device_suspend, + .resume = acpi_device_resume, + .shutdown = acpi_device_shutdown, + .match = acpi_bus_match, + .probe = acpi_device_probe, + .remove = acpi_device_remove, + .uevent = acpi_device_uevent, }; -static void acpi_device_register(struct acpi_device *device, +static int acpi_device_register(struct acpi_device *device, struct acpi_device *parent) { - int err; - + int result; + struct acpi_device_bus_id *acpi_device_bus_id, *new_bus_id; + int found = 0; /* * Linkage * ------- @@ -126,7 +330,33 @@ static void acpi_device_register(struct INIT_LIST_HEAD(&device->g_list); INIT_LIST_HEAD(&device->wakeup_list); + new_bus_id = kzalloc(sizeof(struct acpi_device_bus_id), GFP_KERNEL); + if (!new_bus_id) { + printk(KERN_ERR PREFIX "Memory allocation error\n"); + return -ENOMEM; + } + spin_lock(&acpi_device_lock); + /* + * Find suitable bus_id and instance number in acpi_bus_id_list + * If failed, create one and link it into acpi_bus_id_list + */ + list_for_each_entry(acpi_device_bus_id, &acpi_bus_id_list, node) { + if(!strcmp(acpi_device_bus_id->bus_id, device->flags.hardware_id? device->pnp.hardware_id : "device")) { + acpi_device_bus_id->instance_no ++; + found = 1; + kfree(new_bus_id); + break; + } + } + if(!found) { + acpi_device_bus_id = new_bus_id; + strcpy(acpi_device_bus_id->bus_id, device->flags.hardware_id ? device->pnp.hardware_id : "device"); + acpi_device_bus_id->instance_no = 0; + list_add_tail(&acpi_device_bus_id->node, &acpi_bus_id_list); + } + sprintf(device->dev.bus_id, "%s:%02x", acpi_device_bus_id->bus_id, acpi_device_bus_id->instance_no); + if (device->parent) { list_add_tail(&device->node, &device->parent->children); list_add_tail(&device->g_list, &device->parent->g_list); @@ -136,16 +366,33 @@ static void acpi_device_register(struct list_add_tail(&device->wakeup_list, &acpi_wakeup_device_list); spin_unlock(&acpi_device_lock); - strlcpy(device->kobj.name, device->pnp.bus_id, KOBJ_NAME_LEN); - if (parent) - device->kobj.parent = &parent->kobj; - device->kobj.ktype = &ktype_acpi_ns; - device->kobj.kset = &acpi_namespace_kset; - err = kobject_register(&device->kobj); - if (err < 0) - printk(KERN_WARNING "%s: kobject_register error: %d\n", - __FUNCTION__, err); - create_sysfs_device_files(device); + if (device->parent) + device->dev.parent = &parent->dev; + device->dev.bus = &acpi_bus_type; + device_initialize(&device->dev); + device->dev.release = &acpi_device_release; + result = device_add(&device->dev); + if(result) { + printk("Error adding device %s", device->dev.bus_id); + goto end; + } + + result = acpi_device_setup_files(device); + if(result) + ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Error creating sysfs interface for device %s\n", device->dev.bus_id)); + + device->removal_type = ACPI_BUS_REMOVAL_NORMAL; + return 0; + end: + spin_lock(&acpi_device_lock); + if (device->parent) { + list_del(&device->node); + list_del(&device->g_list); + } else + list_del(&device->g_list); + list_del(&device->wakeup_list); + spin_unlock(&acpi_device_lock); + return result; } static void acpi_device_unregister(struct acpi_device *device, int type) @@ -158,81 +405,143 @@ static void acpi_device_unregister(struc list_del(&device->g_list); list_del(&device->wakeup_list); - spin_unlock(&acpi_device_lock); acpi_detach_data(device->handle, acpi_bus_data_handler); - remove_sysfs_device_files(device); - kobject_unregister(&device->kobj); + + acpi_device_remove_files(device); + device_unregister(&device->dev); } -void acpi_bus_data_handler(acpi_handle handle, u32 function, void *context) +/* -------------------------------------------------------------------------- + Driver Management + -------------------------------------------------------------------------- */ +/** + * acpi_bus_driver_init - add a device to a driver + * @device: the device to add and initialize + * @driver: driver for the device + * + * Used to initialize a device via its device driver. Called whenever a + * driver is bound to a device. Invokes the driver's add() ops. + */ +static int +acpi_bus_driver_init(struct acpi_device *device, struct acpi_driver *driver) { + int result = 0; - /* TBD */ - return; -} + if (!device || !driver) + return -EINVAL; -static int acpi_bus_get_power_flags(struct acpi_device *device) -{ - acpi_status status = 0; - acpi_handle handle = NULL; - u32 i = 0; + if (!driver->ops.add) + return -ENOSYS; + result = driver->ops.add(device); + if (result) { + device->driver = NULL; + acpi_driver_data(device) = NULL; + return result; + } - /* - * Power Management Flags - */ - status = acpi_get_handle(device->handle, "_PSC", &handle); - if (ACPI_SUCCESS(status)) - device->power.flags.explicit_get = 1; - status = acpi_get_handle(device->handle, "_IRC", &handle); - if (ACPI_SUCCESS(status)) - device->power.flags.inrush_current = 1; + device->driver = driver; /* - * Enumerate supported power management states + * TBD - Configuration Management: Assign resources to device based + * upon possible configuration and currently allocated resources. */ - for (i = ACPI_STATE_D0; i <= ACPI_STATE_D3; i++) { - struct acpi_device_power_state *ps = &device->power.states[i]; - char object_name[5] = { '_', 'P', 'R', '0' + i, '\0' }; - /* Evaluate "_PRx" to se if power resources are referenced */ - acpi_evaluate_reference(device->handle, object_name, NULL, - &ps->resources); - if (ps->resources.count) { - device->power.flags.power_resources = 1; - ps->flags.valid = 1; - } + ACPI_DEBUG_PRINT((ACPI_DB_INFO, + "Driver successfully bound to device\n")); + return 0; +} - /* Evaluate "_PSx" to see if we can do explicit sets */ - object_name[2] = 'S'; - status = acpi_get_handle(device->handle, object_name, &handle); - if (ACPI_SUCCESS(status)) { - ps->flags.explicit_set = 1; - ps->flags.valid = 1; - } +static int acpi_start_single_object(struct acpi_device *device) +{ + int result = 0; + struct acpi_driver *driver; - /* State is valid if we have some power control */ - if (ps->resources.count || ps->flags.explicit_set) - ps->flags.valid = 1; - ps->power = -1; /* Unknown - driver assigned */ - ps->latency = -1; /* Unknown - driver assigned */ + if (!(driver = device->driver)) + return 0; + + if (driver->ops.start) { + result = driver->ops.start(device); + if (result && driver->ops.remove) + driver->ops.remove(device, ACPI_BUS_REMOVAL_NORMAL); } - /* Set defaults for D0 and D3 states (always valid) */ - device->power.states[ACPI_STATE_D0].flags.valid = 1; - device->power.states[ACPI_STATE_D0].power = 100; - device->power.states[ACPI_STATE_D3].flags.valid = 1; - device->power.states[ACPI_STATE_D3].power = 0; + return result; +} - /* TBD: System wake support and resource requirements. */ +/** + * acpi_bus_register_driver - register a driver with the ACPI bus + * @driver: driver being registered + * + * Registers a driver with the ACPI bus. Searches the namespace for all + * devices that match the driver's criteria and binds. Returns zero for + * success or a negative error status for failure. + */ +int acpi_bus_register_driver(struct acpi_driver *driver) +{ + int ret; - device->power.state = ACPI_STATE_UNKNOWN; + if (acpi_disabled) + return -ENODEV; + driver->drv.name = driver->name; + driver->drv.bus = &acpi_bus_type; + driver->drv.owner = driver->owner; - return 0; + ret = driver_register(&driver->drv); + return ret; +} + +EXPORT_SYMBOL(acpi_bus_register_driver); + +/** + * acpi_bus_unregister_driver - unregisters a driver with the APIC bus + * @driver: driver to unregister + * + * Unregisters a driver with the ACPI bus. Searches the namespace for all + * devices that match the driver's criteria and unbinds. + */ +void acpi_bus_unregister_driver(struct acpi_driver *driver) +{ + driver_unregister(&driver->drv); +} + +EXPORT_SYMBOL(acpi_bus_unregister_driver); + +/* -------------------------------------------------------------------------- + Device Enumeration + -------------------------------------------------------------------------- */ +acpi_status +acpi_bus_get_ejd(acpi_handle handle, acpi_handle *ejd) +{ + acpi_status status; + acpi_handle tmp; + struct acpi_buffer buffer = {ACPI_ALLOCATE_BUFFER, NULL}; + union acpi_object *obj; + + status = acpi_get_handle(handle, "_EJD", &tmp); + if (ACPI_FAILURE(status)) + return status; + + status = acpi_evaluate_object(handle, "_EJD", NULL, &buffer); + if (ACPI_SUCCESS(status)) { + obj = buffer.pointer; + status = acpi_get_handle(NULL, obj->string.pointer, ejd); + kfree(buffer.pointer); + } + return status; +} +EXPORT_SYMBOL_GPL(acpi_bus_get_ejd); + +void acpi_bus_data_handler(acpi_handle handle, u32 function, void *context) +{ + + /* TBD */ + + return; } int acpi_match_ids(struct acpi_device *device, char *ids) @@ -254,6 +563,12 @@ int acpi_match_ids(struct acpi_device *d return -ENOENT; } +static int acpi_bus_get_perf_flags(struct acpi_device *device) +{ + device->performance.state = ACPI_STATE_UNKNOWN; + return 0; +} + static acpi_status acpi_bus_extract_wakeup_device_power_package(struct acpi_device *device, union acpi_object *package) @@ -338,359 +653,66 @@ static int acpi_bus_get_wakeup_device_fl return 0; } -/* -------------------------------------------------------------------------- - ACPI sysfs device file support - -------------------------------------------------------------------------- */ -static ssize_t acpi_eject_store(struct acpi_device *device, - const char *buf, size_t count); - -#define ACPI_DEVICE_ATTR(_name,_mode,_show,_store) \ -static struct acpi_device_attribute acpi_device_attr_##_name = \ - __ATTR(_name, _mode, _show, _store) - -ACPI_DEVICE_ATTR(eject, 0200, NULL, acpi_eject_store); - -/** - * setup_sys_fs_device_files - sets up the device files under device namespace - * @dev: acpi_device object - * @func: function pointer to create or destroy the device file - */ -static void -setup_sys_fs_device_files(struct acpi_device *dev, - acpi_device_sysfs_files * func) -{ - acpi_status status; - acpi_handle temp = NULL; - - /* - * If device has _EJ0, 'eject' file is created that is used to trigger - * hot-removal function from userland. - */ - status = acpi_get_handle(dev->handle, "_EJ0", &temp); - if (ACPI_SUCCESS(status)) - (*(func)) (&dev->kobj, &acpi_device_attr_eject.attr); -} - -static int acpi_eject_operation(acpi_handle handle, int lockable) +static int acpi_bus_get_power_flags(struct acpi_device *device) { - struct acpi_object_list arg_list; - union acpi_object arg; - acpi_status status = AE_OK; - - /* - * TBD: evaluate _PS3? - */ - - if (lockable) { - arg_list.count = 1; - arg_list.pointer = &arg; - arg.type = ACPI_TYPE_INTEGER; - arg.integer.value = 0; - acpi_evaluate_object(handle, "_LCK", &arg_list, NULL); - } + acpi_status status = 0; + acpi_handle handle = NULL; + u32 i = 0; - arg_list.count = 1; - arg_list.pointer = &arg; - arg.type = ACPI_TYPE_INTEGER; - arg.integer.value = 1; /* - * TBD: _EJD support. + * Power Management Flags */ - - status = acpi_evaluate_object(handle, "_EJ0", &arg_list, NULL); - if (ACPI_FAILURE(status)) { - return (-ENODEV); - } - - return (0); -} - -static ssize_t -acpi_eject_store(struct acpi_device *device, const char *buf, size_t count) -{ - int result; - int ret = count; - int islockable; - acpi_status status; - acpi_handle handle; - acpi_object_type type = 0; - - if ((!count) || (buf[0] != '1')) { - return -EINVAL; - } -#ifndef FORCE_EJECT - if (device->driver == NULL) { - ret = -ENODEV; - goto err; - } -#endif - status = acpi_get_type(device->handle, &type); - if (ACPI_FAILURE(status) || (!device->flags.ejectable)) { - ret = -ENODEV; - goto err; - } - - islockable = device->flags.lockable; - handle = device->handle; - - result = acpi_bus_trim(device, 1); - - if (!result) - result = acpi_eject_operation(handle, islockable); - - if (result) { - ret = -EBUSY; - } - err: - return ret; -} - -/* -------------------------------------------------------------------------- - Performance Management - -------------------------------------------------------------------------- */ - -static int acpi_bus_get_perf_flags(struct acpi_device *device) -{ - device->performance.state = ACPI_STATE_UNKNOWN; - return 0; -} - -/* -------------------------------------------------------------------------- - Driver Management - -------------------------------------------------------------------------- */ - -static LIST_HEAD(acpi_bus_drivers); - -/** - * acpi_bus_match - match device IDs to driver's supported IDs - * @device: the device that we are trying to match to a driver - * @driver: driver whose device id table is being checked - * - * Checks the device's hardware (_HID) or compatible (_CID) ids to see if it - * matches the specified driver's criteria. - */ -static int -acpi_bus_match(struct acpi_device *device, struct acpi_driver *driver) -{ - if (driver && driver->ops.match) - return driver->ops.match(device, driver); - return acpi_match_ids(device, driver->ids); -} - -/** - * acpi_bus_driver_init - add a device to a driver - * @device: the device to add and initialize - * @driver: driver for the device - * - * Used to initialize a device via its device driver. Called whenever a - * driver is bound to a device. Invokes the driver's add() and start() ops. - */ -static int -acpi_bus_driver_init(struct acpi_device *device, struct acpi_driver *driver) -{ - int result = 0; - - - if (!device || !driver) - return -EINVAL; - - if (!driver->ops.add) - return -ENOSYS; - - result = driver->ops.add(device); - if (result) { - device->driver = NULL; - acpi_driver_data(device) = NULL; - return result; - } - - device->driver = driver; + status = acpi_get_handle(device->handle, "_PSC", &handle); + if (ACPI_SUCCESS(status)) + device->power.flags.explicit_get = 1; + status = acpi_get_handle(device->handle, "_IRC", &handle); + if (ACPI_SUCCESS(status)) + device->power.flags.inrush_current = 1; /* - * TBD - Configuration Management: Assign resources to device based - * upon possible configuration and currently allocated resources. + * Enumerate supported power management states */ + for (i = ACPI_STATE_D0; i <= ACPI_STATE_D3; i++) { + struct acpi_device_power_state *ps = &device->power.states[i]; + char object_name[5] = { '_', 'P', 'R', '0' + i, '\0' }; - ACPI_DEBUG_PRINT((ACPI_DB_INFO, - "Driver successfully bound to device\n")); - return 0; -} - -static int acpi_start_single_object(struct acpi_device *device) -{ - int result = 0; - struct acpi_driver *driver; - - - if (!(driver = device->driver)) - return 0; - - if (driver->ops.start) { - result = driver->ops.start(device); - if (result && driver->ops.remove) - driver->ops.remove(device, ACPI_BUS_REMOVAL_NORMAL); - } - - return result; -} - -static void acpi_driver_attach(struct acpi_driver *drv) -{ - struct list_head *node, *next; - - - spin_lock(&acpi_device_lock); - list_for_each_safe(node, next, &acpi_device_list) { - struct acpi_device *dev = - container_of(node, struct acpi_device, g_list); - - if (dev->driver || !dev->status.present) - continue; - spin_unlock(&acpi_device_lock); - - if (!acpi_bus_match(dev, drv)) { - if (!acpi_bus_driver_init(dev, drv)) { - acpi_start_single_object(dev); - atomic_inc(&drv->references); - ACPI_DEBUG_PRINT((ACPI_DB_INFO, - "Found driver [%s] for device [%s]\n", - drv->name, dev->pnp.bus_id)); - } + /* Evaluate "_PRx" to se if power resources are referenced */ + acpi_evaluate_reference(device->handle, object_name, NULL, + &ps->resources); + if (ps->resources.count) { + device->power.flags.power_resources = 1; + ps->flags.valid = 1; } - spin_lock(&acpi_device_lock); - } - spin_unlock(&acpi_device_lock); -} - -static void acpi_driver_detach(struct acpi_driver *drv) -{ - struct list_head *node, *next; - - spin_lock(&acpi_device_lock); - list_for_each_safe(node, next, &acpi_device_list) { - struct acpi_device *dev = - container_of(node, struct acpi_device, g_list); - - if (dev->driver == drv) { - spin_unlock(&acpi_device_lock); - if (drv->ops.remove) - drv->ops.remove(dev, ACPI_BUS_REMOVAL_NORMAL); - spin_lock(&acpi_device_lock); - dev->driver = NULL; - dev->driver_data = NULL; - atomic_dec(&drv->references); + /* Evaluate "_PSx" to see if we can do explicit sets */ + object_name[2] = 'S'; + status = acpi_get_handle(device->handle, object_name, &handle); + if (ACPI_SUCCESS(status)) { + ps->flags.explicit_set = 1; + ps->flags.valid = 1; } - } - spin_unlock(&acpi_device_lock); -} - -/** - * acpi_bus_register_driver - register a driver with the ACPI bus - * @driver: driver being registered - * - * Registers a driver with the ACPI bus. Searches the namespace for all - * devices that match the driver's criteria and binds. Returns zero for - * success or a negative error status for failure. - */ -int acpi_bus_register_driver(struct acpi_driver *driver) -{ - - if (acpi_disabled) - return -ENODEV; - - spin_lock(&acpi_device_lock); - list_add_tail(&driver->node, &acpi_bus_drivers); - spin_unlock(&acpi_device_lock); - acpi_driver_attach(driver); - - return 0; -} - -EXPORT_SYMBOL(acpi_bus_register_driver); - -/** - * acpi_bus_unregister_driver - unregisters a driver with the APIC bus - * @driver: driver to unregister - * - * Unregisters a driver with the ACPI bus. Searches the namespace for all - * devices that match the driver's criteria and unbinds. - */ -void acpi_bus_unregister_driver(struct acpi_driver *driver) -{ - acpi_driver_detach(driver); - - if (!atomic_read(&driver->references)) { - spin_lock(&acpi_device_lock); - list_del_init(&driver->node); - spin_unlock(&acpi_device_lock); - } - return; -} - -EXPORT_SYMBOL(acpi_bus_unregister_driver); - -/** - * acpi_bus_find_driver - check if there is a driver installed for the device - * @device: device that we are trying to find a supporting driver for - * - * Parses the list of registered drivers looking for a driver applicable for - * the specified device. - */ -static int acpi_bus_find_driver(struct acpi_device *device) -{ - int result = 0; - struct list_head *node, *next; + /* State is valid if we have some power control */ + if (ps->resources.count || ps->flags.explicit_set) + ps->flags.valid = 1; - spin_lock(&acpi_device_lock); - list_for_each_safe(node, next, &acpi_bus_drivers) { - struct acpi_driver *driver = - container_of(node, struct acpi_driver, node); - - atomic_inc(&driver->references); - spin_unlock(&acpi_device_lock); - if (!acpi_bus_match(device, driver)) { - result = acpi_bus_driver_init(device, driver); - if (!result) - goto Done; - } - atomic_dec(&driver->references); - spin_lock(&acpi_device_lock); + ps->power = -1; /* Unknown - driver assigned */ + ps->latency = -1; /* Unknown - driver assigned */ } - spin_unlock(&acpi_device_lock); - - Done: - return result; -} -/* -------------------------------------------------------------------------- - Device Enumeration - -------------------------------------------------------------------------- */ + /* Set defaults for D0 and D3 states (always valid) */ + device->power.states[ACPI_STATE_D0].flags.valid = 1; + device->power.states[ACPI_STATE_D0].power = 100; + device->power.states[ACPI_STATE_D3].flags.valid = 1; + device->power.states[ACPI_STATE_D3].power = 0; -acpi_status -acpi_bus_get_ejd(acpi_handle handle, acpi_handle *ejd) -{ - acpi_status status; - acpi_handle tmp; - struct acpi_buffer buffer = {ACPI_ALLOCATE_BUFFER, NULL}; - union acpi_object *obj; + /* TBD: System wake support and resource requirements. */ - status = acpi_get_handle(handle, "_EJD", &tmp); - if (ACPI_FAILURE(status)) - return status; + device->power.state = ACPI_STATE_UNKNOWN; - status = acpi_evaluate_object(handle, "_EJD", NULL, &buffer); - if (ACPI_SUCCESS(status)) { - obj = buffer.pointer; - status = acpi_get_handle(NULL, obj->string.pointer, ejd); - kfree(buffer.pointer); - } - return status; + return 0; } -EXPORT_SYMBOL_GPL(acpi_bus_get_ejd); - static int acpi_bus_get_flags(struct acpi_device *device) { @@ -782,6 +804,75 @@ static void acpi_device_get_busid(struct } } +static int +acpi_video_bus_match(struct acpi_device *device) +{ + acpi_handle h_dummy1; + acpi_handle h_dummy2; + acpi_handle h_dummy3; + + + if (!device) + return -EINVAL; + + /* Since there is no HID, CID for ACPI Video drivers, we have + * to check well known required nodes for each feature we support. + */ + + /* Does this device able to support video switching ? */ + if (ACPI_SUCCESS(acpi_get_handle(device->handle, "_DOD", &h_dummy1)) && + ACPI_SUCCESS(acpi_get_handle(device->handle, "_DOS", &h_dummy2))) + return 0; + + /* Does this device able to retrieve a video ROM ? */ + if (ACPI_SUCCESS(acpi_get_handle(device->handle, "_ROM", &h_dummy1))) + return 0; + + /* Does this device able to configure which video head to be POSTed ? */ + if (ACPI_SUCCESS(acpi_get_handle(device->handle, "_VPO", &h_dummy1)) && + ACPI_SUCCESS(acpi_get_handle(device->handle, "_GPD", &h_dummy2)) && + ACPI_SUCCESS(acpi_get_handle(device->handle, "_SPD", &h_dummy3))) + return 0; + + return -ENODEV; +} + +/* + * acpi_bay_match - see if a device is an ejectable driver bay + * + * If an acpi object is ejectable and has one of the ACPI ATA methods defined, + * then we can safely call it an ejectable drive bay + */ +static int acpi_bay_match(struct acpi_device *device){ + acpi_status status; + acpi_handle handle; + acpi_handle tmp; + acpi_handle phandle; + + handle = device->handle; + + status = acpi_get_handle(handle, "_EJ0", &tmp); + if (ACPI_FAILURE(status)) + return -ENODEV; + + if ((ACPI_SUCCESS(acpi_get_handle(handle, "_GTF", &tmp))) || + (ACPI_SUCCESS(acpi_get_handle(handle, "_GTM", &tmp))) || + (ACPI_SUCCESS(acpi_get_handle(handle, "_STM", &tmp))) || + (ACPI_SUCCESS(acpi_get_handle(handle, "_SDD", &tmp)))) + return 0; + + if (acpi_get_parent(handle, &phandle)) + return -ENODEV; + + if ((ACPI_SUCCESS(acpi_get_handle(phandle, "_GTF", &tmp))) || + (ACPI_SUCCESS(acpi_get_handle(phandle, "_GTM", &tmp))) || + (ACPI_SUCCESS(acpi_get_handle(phandle, "_STM", &tmp))) || + (ACPI_SUCCESS(acpi_get_handle(phandle, "_SDD", &tmp)))) + return 0; + + return -ENODEV; +} + static void acpi_device_set_id(struct acpi_device *device, struct acpi_device *parent, acpi_handle handle, int type) @@ -812,6 +903,16 @@ static void acpi_device_set_id(struct ac device->pnp.bus_address = info->address; device->flags.bus_address = 1; } + + if(!(info->valid & (ACPI_VALID_HID | ACPI_VALID_CID))){ + status = acpi_video_bus_match(device); + if(ACPI_SUCCESS(status)) + hid = ACPI_VIDEO_HID; + + status = acpi_bay_match(device); + if (ACPI_SUCCESS(status)) + hid = ACPI_BAY_HID; + } break; case ACPI_BUS_TYPE_POWER: hid = ACPI_POWER_HID; @@ -888,86 +989,24 @@ static int acpi_device_set_context(struc return result; } -static void acpi_device_get_debug_info(struct acpi_device *device, - acpi_handle handle, int type) -{ -#ifdef CONFIG_ACPI_DEBUG_OUTPUT - char *type_string = NULL; - char name[80] = { '?', '\0' }; - struct acpi_buffer buffer = { sizeof(name), name }; - - switch (type) { - case ACPI_BUS_TYPE_DEVICE: - type_string = "Device"; - acpi_get_name(handle, ACPI_FULL_PATHNAME, &buffer); - break; - case ACPI_BUS_TYPE_POWER: - type_string = "Power Resource"; - acpi_get_name(handle, ACPI_FULL_PATHNAME, &buffer); - break; - case ACPI_BUS_TYPE_PROCESSOR: - type_string = "Processor"; - acpi_get_name(handle, ACPI_FULL_PATHNAME, &buffer); - break; - case ACPI_BUS_TYPE_SYSTEM: - type_string = "System"; - acpi_get_name(handle, ACPI_FULL_PATHNAME, &buffer); - break; - case ACPI_BUS_TYPE_THERMAL: - type_string = "Thermal Zone"; - acpi_get_name(handle, ACPI_FULL_PATHNAME, &buffer); - break; - case ACPI_BUS_TYPE_POWER_BUTTON: - type_string = "Power Button"; - sprintf(name, "PWRB"); - break; - case ACPI_BUS_TYPE_SLEEP_BUTTON: - type_string = "Sleep Button"; - sprintf(name, "SLPB"); - break; - } - - printk(KERN_DEBUG "Found %s %s [%p]\n", type_string, name, handle); -#endif /*CONFIG_ACPI_DEBUG_OUTPUT */ -} - static int acpi_bus_remove(struct acpi_device *dev, int rmdevice) { - int result = 0; - struct acpi_driver *driver; - - if (!dev) return -EINVAL; - driver = dev->driver; - - if ((driver) && (driver->ops.remove)) { - - if (driver->ops.stop) { - result = driver->ops.stop(dev, ACPI_BUS_REMOVAL_EJECT); - if (result) - return result; - } - - result = dev->driver->ops.remove(dev, ACPI_BUS_REMOVAL_EJECT); - if (result) { - return result; - } - - atomic_dec(&dev->driver->references); - dev->driver = NULL; - acpi_driver_data(dev) = NULL; - } + dev->removal_type = ACPI_BUS_REMOVAL_EJECT; + device_release_driver(&dev->dev); if (!rmdevice) return 0; + /* + * unbind _ADR-Based Devices when hot removal + */ if (dev->flags.bus_address) { if ((dev->parent) && (dev->parent->ops.unbind)) dev->parent->ops.unbind(dev); } - acpi_device_unregister(dev, ACPI_BUS_REMOVAL_EJECT); return 0; @@ -975,7 +1014,8 @@ static int acpi_bus_remove(struct acpi_d static int acpi_add_single_object(struct acpi_device **child, - struct acpi_device *parent, acpi_handle handle, int type) + struct acpi_device *parent, acpi_handle handle, int type, + struct acpi_bus_ops *ops) { int result = 0; struct acpi_device *device = NULL; @@ -992,6 +1032,8 @@ acpi_add_single_object(struct acpi_devic device->handle = handle; device->parent = parent; + device->bus_ops = *ops; /* workround for not call .start */ + acpi_device_get_busid(device, handle, type); @@ -1076,33 +1118,16 @@ acpi_add_single_object(struct acpi_devic if ((result = acpi_device_set_context(device, type))) goto end; - acpi_device_get_debug_info(device, handle, type); - - acpi_device_register(device, parent); + result = acpi_device_register(device, parent); /* - * Bind _ADR-Based Devices - * ----------------------- - * If there's a a bus address (_ADR) then we utilize the parent's - * 'bind' function (if exists) to bind the ACPI- and natively- - * enumerated device representations. + * Bind _ADR-Based Devices when hot add */ if (device->flags.bus_address) { if (device->parent && device->parent->ops.bind) device->parent->ops.bind(device); } - /* - * Locate & Attach Driver - * ---------------------- - * If there's a hardware id (_HID) or compatible ids (_CID) we check - * to see if there's a driver installed for this kind of device. Note - * that drivers can install before or after a device is enumerated. - * - * TBD: Assumes LDM provides driver hot-plug capability. - */ - acpi_bus_find_driver(device); - end: if (!result) *child = device; @@ -1188,14 +1213,14 @@ static int acpi_bus_scan(struct acpi_dev if (ops->acpi_op_add) status = acpi_add_single_object(&child, parent, - chandle, type); + chandle, type, ops); else status = acpi_bus_get_device(chandle, &child); if (ACPI_FAILURE(status)) continue; - if (ops->acpi_op_start) { + if (ops->acpi_op_start && !(ops->acpi_op_add)) { status = acpi_start_single_object(child); if (ACPI_FAILURE(status)) continue; @@ -1233,13 +1258,13 @@ acpi_bus_add(struct acpi_device **child, int result; struct acpi_bus_ops ops; + memset(&ops, 0, sizeof(ops)); + ops.acpi_op_add = 1; - result = acpi_add_single_object(child, parent, handle, type); - if (!result) { - memset(&ops, 0, sizeof(ops)); - ops.acpi_op_add = 1; + result = acpi_add_single_object(child, parent, handle, type, &ops); + if (!result) result = acpi_bus_scan(*child, &ops); - } + return result; } @@ -1325,127 +1350,35 @@ static int acpi_bus_scan_fixed(struct ac { int result = 0; struct acpi_device *device = NULL; - + struct acpi_bus_ops ops; if (!root) return -ENODEV; + memset(&ops, 0, sizeof(ops)); + ops.acpi_op_add = 1; + ops.acpi_op_start = 1; + /* * Enumerate all fixed-feature devices. */ - if (acpi_fadt.pwr_button == 0) { + if ((acpi_gbl_FADT.flags & ACPI_FADT_POWER_BUTTON) == 0) { result = acpi_add_single_object(&device, acpi_root, NULL, - ACPI_BUS_TYPE_POWER_BUTTON); - if (!result) - result = acpi_start_single_object(device); + ACPI_BUS_TYPE_POWER_BUTTON, + &ops); } - if (acpi_fadt.sleep_button == 0) { + if ((acpi_gbl_FADT.flags & ACPI_FADT_SLEEP_BUTTON) == 0) { result = acpi_add_single_object(&device, acpi_root, NULL, - ACPI_BUS_TYPE_SLEEP_BUTTON); - if (!result) - result = acpi_start_single_object(device); + ACPI_BUS_TYPE_SLEEP_BUTTON, + &ops); } return result; } - -static inline struct acpi_device * to_acpi_dev(struct device * dev) -{ - return container_of(dev, struct acpi_device, dev); -} - - -static int root_suspend(struct acpi_device * acpi_dev, pm_message_t state) -{ - struct acpi_device * dev, * next; - int result; - - spin_lock(&acpi_device_lock); - list_for_each_entry_safe_reverse(dev, next, &acpi_device_list, g_list) { - if (dev->driver && dev->driver->ops.suspend) { - spin_unlock(&acpi_device_lock); - result = dev->driver->ops.suspend(dev, 0); - if (result) { - printk(KERN_ERR PREFIX "[%s - %s] Suspend failed: %d\n", - acpi_device_name(dev), - acpi_device_bid(dev), result); - } - spin_lock(&acpi_device_lock); - } - } - spin_unlock(&acpi_device_lock); - return 0; -} - - -static int acpi_device_suspend(struct device * dev, pm_message_t state) -{ - struct acpi_device * acpi_dev = to_acpi_dev(dev); - - /* - * For now, we should only register 1 generic device - - * the ACPI root device - and from there, we walk the - * tree of ACPI devices to suspend each one using the - * ACPI driver methods. - */ - if (acpi_dev->handle == ACPI_ROOT_OBJECT) - root_suspend(acpi_dev, state); - return 0; -} - - - -static int root_resume(struct acpi_device * acpi_dev) -{ - struct acpi_device * dev, * next; - int result; - - spin_lock(&acpi_device_lock); - list_for_each_entry_safe(dev, next, &acpi_device_list, g_list) { - if (dev->driver && dev->driver->ops.resume) { - spin_unlock(&acpi_device_lock); - result = dev->driver->ops.resume(dev, 0); - if (result) { - printk(KERN_ERR PREFIX "[%s - %s] resume failed: %d\n", - acpi_device_name(dev), - acpi_device_bid(dev), result); - } - spin_lock(&acpi_device_lock); - } - } - spin_unlock(&acpi_device_lock); - return 0; -} - - -static int acpi_device_resume(struct device * dev) -{ - struct acpi_device * acpi_dev = to_acpi_dev(dev); - - /* - * For now, we should only register 1 generic device - - * the ACPI root device - and from there, we walk the - * tree of ACPI devices to resume each one using the - * ACPI driver methods. - */ - if (acpi_dev->handle == ACPI_ROOT_OBJECT) - root_resume(acpi_dev); - return 0; -} - - -static struct bus_type acpi_bus_type = { - .name = "acpi", - .suspend = acpi_device_suspend, - .resume = acpi_device_resume, -}; - - - static int __init acpi_scan_init(void) { int result; @@ -1455,9 +1388,9 @@ static int __init acpi_scan_init(void) if (acpi_disabled) return 0; - result = kset_register(&acpi_namespace_kset); - if (result < 0) - printk(KERN_ERR PREFIX "kset_register error: %d\n", result); + memset(&ops, 0, sizeof(ops)); + ops.acpi_op_add = 1; + ops.acpi_op_start = 1; result = bus_register(&acpi_bus_type); if (result) { @@ -1469,32 +1402,16 @@ static int __init acpi_scan_init(void) * Create the root device in the bus's device tree */ result = acpi_add_single_object(&acpi_root, NULL, ACPI_ROOT_OBJECT, - ACPI_BUS_TYPE_SYSTEM); + ACPI_BUS_TYPE_SYSTEM, &ops); if (result) goto Done; - result = acpi_start_single_object(acpi_root); - if (result) - goto Done; - - acpi_root->dev.bus = &acpi_bus_type; - snprintf(acpi_root->dev.bus_id, BUS_ID_SIZE, "%s", acpi_bus_type.name); - result = device_register(&acpi_root->dev); - if (result) { - /* We don't want to quit even if we failed to add suspend/resume */ - printk(KERN_ERR PREFIX "Could not register device\n"); - } - /* * Enumerate devices in the ACPI namespace. */ result = acpi_bus_scan_fixed(acpi_root); - if (!result) { - memset(&ops, 0, sizeof(ops)); - ops.acpi_op_add = 1; - ops.acpi_op_start = 1; + if (!result) result = acpi_bus_scan(acpi_root, &ops); - } if (result) acpi_device_unregister(acpi_root, ACPI_BUS_REMOVAL_NORMAL); diff --git a/drivers/acpi/sleep/poweroff.c b/drivers/acpi/sleep/poweroff.c index 47fb4b3..d9801ef 100644 --- a/drivers/acpi/sleep/poweroff.c +++ b/drivers/acpi/sleep/poweroff.c @@ -12,7 +12,6 @@ #include #include #include -#include #include #include #include "sleep.h" diff --git a/drivers/acpi/sleep/proc.c b/drivers/acpi/sleep/proc.c index 3496257..ccc11b3 100644 --- a/drivers/acpi/sleep/proc.c +++ b/drivers/acpi/sleep/proc.c @@ -73,7 +73,7 @@ #endif /* CONFIG_ACPI_SLEEP_PROC_SLEE static int acpi_system_alarm_seq_show(struct seq_file *seq, void *offset) { u32 sec, min, hr; - u32 day, mo, yr; + u32 day, mo, yr, cent = 0; unsigned char rtc_control = 0; unsigned long flags; @@ -87,20 +87,19 @@ static int acpi_system_alarm_seq_show(st rtc_control = CMOS_READ(RTC_CONTROL); /* If we ever get an FACP with proper values... */ - if (acpi_gbl_FADT->day_alrm) + if (acpi_gbl_FADT.day_alarm) /* ACPI spec: only low 6 its should be cared */ - day = CMOS_READ(acpi_gbl_FADT->day_alrm) & 0x3F; + day = CMOS_READ(acpi_gbl_FADT.day_alarm) & 0x3F; else day = CMOS_READ(RTC_DAY_OF_MONTH); - if (acpi_gbl_FADT->mon_alrm) - mo = CMOS_READ(acpi_gbl_FADT->mon_alrm); + if (acpi_gbl_FADT.month_alarm) + mo = CMOS_READ(acpi_gbl_FADT.month_alarm); else mo = CMOS_READ(RTC_MONTH); - if (acpi_gbl_FADT->century) - yr = CMOS_READ(acpi_gbl_FADT->century) * 100 + - CMOS_READ(RTC_YEAR); - else - yr = CMOS_READ(RTC_YEAR); + if (acpi_gbl_FADT.century) + cent = CMOS_READ(acpi_gbl_FADT.century); + + yr = CMOS_READ(RTC_YEAR); spin_unlock_irqrestore(&rtc_lock, flags); @@ -111,10 +110,11 @@ static int acpi_system_alarm_seq_show(st BCD_TO_BIN(day); BCD_TO_BIN(mo); BCD_TO_BIN(yr); + BCD_TO_BIN(cent); } /* we're trusting the FADT (see above) */ - if (!acpi_gbl_FADT->century) + if (!acpi_gbl_FADT.century) /* If we're not trusting the FADT, we should at least make it * right for _this_ century... ehm, what is _this_ century? * @@ -134,6 +134,8 @@ static int acpi_system_alarm_seq_show(st * */ yr += 2000; + else + yr += cent * 100; seq_printf(seq, "%4.4u-", yr); (mo > 12) ? seq_puts(seq, "**-") : seq_printf(seq, "%2.2u-", mo); @@ -317,12 +319,12 @@ acpi_system_write_alarm(struct file *fil * offsets into the CMOS RAM here -- which for some reason are pointing * to the RTC area of memory. */ - if (acpi_gbl_FADT->day_alrm) - CMOS_WRITE(day, acpi_gbl_FADT->day_alrm); - if (acpi_gbl_FADT->mon_alrm) - CMOS_WRITE(mo, acpi_gbl_FADT->mon_alrm); - if (acpi_gbl_FADT->century) - CMOS_WRITE(yr / 100, acpi_gbl_FADT->century); + if (acpi_gbl_FADT.day_alarm) + CMOS_WRITE(day, acpi_gbl_FADT.day_alarm); + if (acpi_gbl_FADT.month_alarm) + CMOS_WRITE(mo, acpi_gbl_FADT.month_alarm); + if (acpi_gbl_FADT.century) + CMOS_WRITE(yr / 100, acpi_gbl_FADT.century); /* enable the rtc alarm interrupt */ rtc_control |= RTC_AIE; CMOS_WRITE(rtc_control, RTC_CONTROL); diff --git a/drivers/acpi/system.c b/drivers/acpi/system.c index d86dcb3..7147b0b 100644 --- a/drivers/acpi/system.c +++ b/drivers/acpi/system.c @@ -32,6 +32,11 @@ #include #define _COMPONENT ACPI_SYSTEM_COMPONENT ACPI_MODULE_NAME("acpi_system") +#ifdef MODULE_PARAM_PREFIX +#undef MODULE_PARAM_PREFIX +#endif +#define MODULE_PARAM_PREFIX "acpi." + #define ACPI_SYSTEM_CLASS "system" #define ACPI_SYSTEM_DRIVER_NAME "ACPI System Driver" #define ACPI_SYSTEM_DEVICE_NAME "System" @@ -39,11 +44,24 @@ #define ACPI_SYSTEM_FILE_INFO "info" #define ACPI_SYSTEM_FILE_EVENT "event" #define ACPI_SYSTEM_FILE_DSDT "dsdt" #define ACPI_SYSTEM_FILE_FADT "fadt" -extern struct fadt_descriptor acpi_fadt; + +/* + * Make ACPICA version work as module param + */ +static int param_get_acpica_version(char *buffer, struct kernel_param *kp) { + int result; + + result = sprintf(buffer, "%x", ACPI_CA_VERSION); + + return result; +} + +module_param_call(acpica_version, NULL, param_get_acpica_version, NULL, 0444); /* -------------------------------------------------------------------------- FS Interface (/proc) -------------------------------------------------------------------------- */ +#ifdef CONFIG_ACPI_PROCFS static int acpi_system_read_info(struct seq_file *seq, void *offset) { @@ -63,6 +81,7 @@ static const struct file_operations acpi .llseek = seq_lseek, .release = single_release, }; +#endif static ssize_t acpi_system_read_dsdt(struct file *, char __user *, size_t, loff_t *); @@ -76,17 +95,16 @@ acpi_system_read_dsdt(struct file *file, char __user * buffer, size_t count, loff_t * ppos) { acpi_status status = AE_OK; - struct acpi_buffer dsdt = { ACPI_ALLOCATE_BUFFER, NULL }; + struct acpi_table_header *dsdt = NULL; ssize_t res; - status = acpi_get_table(ACPI_TABLE_ID_DSDT, 1, &dsdt); + status = acpi_get_table(ACPI_SIG_DSDT, 1, &dsdt); if (ACPI_FAILURE(status)) return -ENODEV; res = simple_read_from_buffer(buffer, count, ppos, - dsdt.pointer, dsdt.length); - kfree(dsdt.pointer); + dsdt, dsdt->length); return res; } @@ -103,17 +121,16 @@ acpi_system_read_fadt(struct file *file, char __user * buffer, size_t count, loff_t * ppos) { acpi_status status = AE_OK; - struct acpi_buffer fadt = { ACPI_ALLOCATE_BUFFER, NULL }; + struct acpi_table_header *fadt = NULL; ssize_t res; - status = acpi_get_table(ACPI_TABLE_ID_FADT, 1, &fadt); + status = acpi_get_table(ACPI_SIG_FADT, 1, &fadt); if (ACPI_FAILURE(status)) return -ENODEV; res = simple_read_from_buffer(buffer, count, ppos, - fadt.pointer, fadt.length); - kfree(fadt.pointer); + fadt, fadt->length); return res; } @@ -128,6 +145,7 @@ static int __init acpi_system_init(void) if (acpi_disabled) return 0; +#ifdef CONFIG_ACPI_PROCFS /* 'info' [R] */ name = ACPI_SYSTEM_FILE_INFO; entry = create_proc_entry(name, S_IRUGO, acpi_root_dir); @@ -136,6 +154,7 @@ static int __init acpi_system_init(void) else { entry->proc_fops = &acpi_system_info_ops; } +#endif /* 'dsdt' [R] */ name = ACPI_SYSTEM_FILE_DSDT; @@ -159,7 +178,9 @@ static int __init acpi_system_init(void) Error: remove_proc_entry(ACPI_SYSTEM_FILE_FADT, acpi_root_dir); remove_proc_entry(ACPI_SYSTEM_FILE_DSDT, acpi_root_dir); +#ifdef CONFIG_ACPI_PROCFS remove_proc_entry(ACPI_SYSTEM_FILE_INFO, acpi_root_dir); +#endif error = -EFAULT; goto Done; diff --git a/drivers/acpi/tables.c b/drivers/acpi/tables.c index ffa30c9..45bd173 100644 --- a/drivers/acpi/tables.c +++ b/drivers/acpi/tables.c @@ -25,7 +25,6 @@ #include #include -#include #include #include #include @@ -38,154 +37,97 @@ #define PREFIX "ACPI: " #define ACPI_MAX_TABLES 128 -static char *acpi_table_signatures[ACPI_TABLE_COUNT] = { - [ACPI_TABLE_UNKNOWN] = "????", - [ACPI_APIC] = "APIC", - [ACPI_BOOT] = "BOOT", - [ACPI_DBGP] = "DBGP", - [ACPI_DSDT] = "DSDT", - [ACPI_ECDT] = "ECDT", - [ACPI_ETDT] = "ETDT", - [ACPI_FADT] = "FACP", - [ACPI_FACS] = "FACS", - [ACPI_OEMX] = "OEM", - [ACPI_PSDT] = "PSDT", - [ACPI_SBST] = "SBST", - [ACPI_SLIT] = "SLIT", - [ACPI_SPCR] = "SPCR", - [ACPI_SRAT] = "SRAT", - [ACPI_SSDT] = "SSDT", - [ACPI_SPMI] = "SPMI", - [ACPI_HPET] = "HPET", - [ACPI_MCFG] = "MCFG", -}; - static char *mps_inti_flags_polarity[] = { "dfl", "high", "res", "low" }; static char *mps_inti_flags_trigger[] = { "dfl", "edge", "res", "level" }; -/* System Description Table (RSDT/XSDT) */ -struct acpi_table_sdt { - unsigned long pa; - enum acpi_table_id id; - unsigned long size; -} __attribute__ ((packed)); - -static unsigned long sdt_pa; /* Physical Address */ -static unsigned long sdt_count; /* Table count */ +static struct acpi_table_desc initial_tables[ACPI_MAX_TABLES] __initdata; -static struct acpi_table_sdt sdt_entry[ACPI_MAX_TABLES] __initdata; - -void acpi_table_print(struct acpi_table_header *header, unsigned long phys_addr) -{ - char *name = NULL; - - if (!header) - return; - - /* Some table signatures aren't good table names */ - - if (!strncmp((char *)&header->signature, - acpi_table_signatures[ACPI_APIC], - sizeof(header->signature))) { - name = "MADT"; - } else if (!strncmp((char *)&header->signature, - acpi_table_signatures[ACPI_FADT], - sizeof(header->signature))) { - name = "FADT"; - } else - name = header->signature; - - printk(KERN_DEBUG PREFIX - "%.4s (v%3.3d %6.6s %8.8s 0x%08x %.4s 0x%08x) @ 0x%p\n", name, - header->revision, header->oem_id, header->oem_table_id, - header->oem_revision, header->asl_compiler_id, - header->asl_compiler_revision, (void *)phys_addr); -} - -void acpi_table_print_madt_entry(acpi_table_entry_header * header) +void acpi_table_print_madt_entry(struct acpi_subtable_header * header) { if (!header) return; switch (header->type) { - case ACPI_MADT_LAPIC: + case ACPI_MADT_TYPE_LOCAL_APIC: { - struct acpi_table_lapic *p = - (struct acpi_table_lapic *)header; + struct acpi_madt_local_apic *p = + (struct acpi_madt_local_apic *)header; printk(KERN_INFO PREFIX "LAPIC (acpi_id[0x%02x] lapic_id[0x%02x] %s)\n", - p->acpi_id, p->id, - p->flags.enabled ? "enabled" : "disabled"); + p->processor_id, p->id, + (p->lapic_flags & ACPI_MADT_ENABLED) ? "enabled" : "disabled"); } break; - case ACPI_MADT_IOAPIC: + case ACPI_MADT_TYPE_IO_APIC: { - struct acpi_table_ioapic *p = - (struct acpi_table_ioapic *)header; + struct acpi_madt_io_apic *p = + (struct acpi_madt_io_apic *)header; printk(KERN_INFO PREFIX "IOAPIC (id[0x%02x] address[0x%08x] gsi_base[%d])\n", p->id, p->address, p->global_irq_base); } break; - case ACPI_MADT_INT_SRC_OVR: + case ACPI_MADT_TYPE_INTERRUPT_OVERRIDE: { - struct acpi_table_int_src_ovr *p = - (struct acpi_table_int_src_ovr *)header; + struct acpi_madt_interrupt_override *p = + (struct acpi_madt_interrupt_override *)header; printk(KERN_INFO PREFIX "INT_SRC_OVR (bus %d bus_irq %d global_irq %d %s %s)\n", - p->bus, p->bus_irq, p->global_irq, - mps_inti_flags_polarity[p->flags.polarity], - mps_inti_flags_trigger[p->flags.trigger]); - if (p->flags.reserved) + p->bus, p->source_irq, p->global_irq, + mps_inti_flags_polarity[p->inti_flags & ACPI_MADT_POLARITY_MASK], + mps_inti_flags_trigger[(p->inti_flags & ACPI_MADT_TRIGGER_MASK) >> 2]); + if (p->inti_flags & + ~(ACPI_MADT_POLARITY_MASK | ACPI_MADT_TRIGGER_MASK)) printk(KERN_INFO PREFIX "INT_SRC_OVR unexpected reserved flags: 0x%x\n", - p->flags.reserved); + p->inti_flags & + ~(ACPI_MADT_POLARITY_MASK | ACPI_MADT_TRIGGER_MASK)); } break; - case ACPI_MADT_NMI_SRC: + case ACPI_MADT_TYPE_NMI_SOURCE: { - struct acpi_table_nmi_src *p = - (struct acpi_table_nmi_src *)header; + struct acpi_madt_nmi_source *p = + (struct acpi_madt_nmi_source *)header; printk(KERN_INFO PREFIX "NMI_SRC (%s %s global_irq %d)\n", - mps_inti_flags_polarity[p->flags.polarity], - mps_inti_flags_trigger[p->flags.trigger], + mps_inti_flags_polarity[p->inti_flags & ACPI_MADT_POLARITY_MASK], + mps_inti_flags_trigger[(p->inti_flags & ACPI_MADT_TRIGGER_MASK) >> 2], p->global_irq); } break; - case ACPI_MADT_LAPIC_NMI: + case ACPI_MADT_TYPE_LOCAL_APIC_NMI: { - struct acpi_table_lapic_nmi *p = - (struct acpi_table_lapic_nmi *)header; + struct acpi_madt_local_apic_nmi *p = + (struct acpi_madt_local_apic_nmi *)header; printk(KERN_INFO PREFIX "LAPIC_NMI (acpi_id[0x%02x] %s %s lint[0x%x])\n", - p->acpi_id, - mps_inti_flags_polarity[p->flags.polarity], - mps_inti_flags_trigger[p->flags.trigger], + p->processor_id, + mps_inti_flags_polarity[p->inti_flags & ACPI_MADT_POLARITY_MASK ], + mps_inti_flags_trigger[(p->inti_flags & ACPI_MADT_TRIGGER_MASK) >> 2], p->lint); } break; - case ACPI_MADT_LAPIC_ADDR_OVR: + case ACPI_MADT_TYPE_LOCAL_APIC_OVERRIDE: { - struct acpi_table_lapic_addr_ovr *p = - (struct acpi_table_lapic_addr_ovr *)header; + struct acpi_madt_local_apic_override *p = + (struct acpi_madt_local_apic_override *)header; printk(KERN_INFO PREFIX "LAPIC_ADDR_OVR (address[%p])\n", (void *)(unsigned long)p->address); } break; - case ACPI_MADT_IOSAPIC: + case ACPI_MADT_TYPE_IO_SAPIC: { - struct acpi_table_iosapic *p = - (struct acpi_table_iosapic *)header; + struct acpi_madt_io_sapic *p = + (struct acpi_madt_io_sapic *)header; printk(KERN_INFO PREFIX "IOSAPIC (id[0x%x] address[%p] gsi_base[%d])\n", p->id, (void *)(unsigned long)p->address, @@ -193,26 +135,26 @@ void acpi_table_print_madt_entry(acpi_ta } break; - case ACPI_MADT_LSAPIC: + case ACPI_MADT_TYPE_LOCAL_SAPIC: { - struct acpi_table_lsapic *p = - (struct acpi_table_lsapic *)header; + struct acpi_madt_local_sapic *p = + (struct acpi_madt_local_sapic *)header; printk(KERN_INFO PREFIX "LSAPIC (acpi_id[0x%02x] lsapic_id[0x%02x] lsapic_eid[0x%02x] %s)\n", - p->acpi_id, p->id, p->eid, - p->flags.enabled ? "enabled" : "disabled"); + p->processor_id, p->id, p->eid, + (p->lapic_flags & ACPI_MADT_ENABLED) ? "enabled" : "disabled"); } break; - case ACPI_MADT_PLAT_INT_SRC: + case ACPI_MADT_TYPE_INTERRUPT_SOURCE: { - struct acpi_table_plat_int_src *p = - (struct acpi_table_plat_int_src *)header; + struct acpi_madt_interrupt_source *p = + (struct acpi_madt_interrupt_source *)header; printk(KERN_INFO PREFIX "PLAT_INT_SRC (%s %s type[0x%x] id[0x%04x] eid[0x%x] iosapic_vector[0x%x] global_irq[0x%x]\n", - mps_inti_flags_polarity[p->flags.polarity], - mps_inti_flags_trigger[p->flags.trigger], - p->type, p->id, p->eid, p->iosapic_vector, + mps_inti_flags_polarity[p->inti_flags & ACPI_MADT_POLARITY_MASK], + mps_inti_flags_trigger[(p->inti_flags & ACPI_MADT_TRIGGER_MASK) >> 2], + p->type, p->id, p->eid, p->io_sapic_vector, p->global_irq); } break; @@ -225,342 +167,76 @@ void acpi_table_print_madt_entry(acpi_ta } } -static int -acpi_table_compute_checksum(void *table_pointer, unsigned long length) -{ - u8 *p = table_pointer; - unsigned long remains = length; - unsigned long sum = 0; - - if (!p || !length) - return -EINVAL; - - while (remains--) - sum += *p++; - - return (sum & 0xFF); -} -/* - * acpi_get_table_header_early() - * for acpi_blacklisted(), acpi_table_get_sdt() - */ int __init -acpi_get_table_header_early(enum acpi_table_id id, - struct acpi_table_header **header) -{ - unsigned int i; - enum acpi_table_id temp_id; - - /* DSDT is different from the rest */ - if (id == ACPI_DSDT) - temp_id = ACPI_FADT; - else - temp_id = id; - - /* Locate the table. */ - - for (i = 0; i < sdt_count; i++) { - if (sdt_entry[i].id != temp_id) - continue; - *header = (void *) - __acpi_map_table(sdt_entry[i].pa, sdt_entry[i].size); - if (!*header) { - printk(KERN_WARNING PREFIX "Unable to map %s\n", - acpi_table_signatures[temp_id]); - return -ENODEV; - } - break; - } - - if (!*header) { - printk(KERN_WARNING PREFIX "%s not present\n", - acpi_table_signatures[id]); - return -ENODEV; - } - - /* Map the DSDT header via the pointer in the FADT */ - if (id == ACPI_DSDT) { - struct fadt_descriptor *fadt = - (struct fadt_descriptor *)*header; - - if (fadt->revision == 3 && fadt->Xdsdt) { - *header = (void *)__acpi_map_table(fadt->Xdsdt, - sizeof(struct - acpi_table_header)); - } else if (fadt->V1_dsdt) { - *header = (void *)__acpi_map_table(fadt->V1_dsdt, - sizeof(struct - acpi_table_header)); - } else - *header = NULL; - - if (!*header) { - printk(KERN_WARNING PREFIX "Unable to map DSDT\n"); - return -ENODEV; - } - } - - return 0; -} - -int __init -acpi_table_parse_madt_family(enum acpi_table_id id, +acpi_table_parse_madt_family(char *id, unsigned long madt_size, int entry_id, acpi_madt_entry_handler handler, unsigned int max_entries) { - void *madt = NULL; - acpi_table_entry_header *entry; + struct acpi_table_header *madt = NULL; + struct acpi_subtable_header *entry; unsigned int count = 0; unsigned long madt_end; - unsigned int i; if (!handler) return -EINVAL; /* Locate the MADT (if exists). There should only be one. */ - - for (i = 0; i < sdt_count; i++) { - if (sdt_entry[i].id != id) - continue; - madt = (void *) - __acpi_map_table(sdt_entry[i].pa, sdt_entry[i].size); - if (!madt) { - printk(KERN_WARNING PREFIX "Unable to map %s\n", - acpi_table_signatures[id]); - return -ENODEV; - } - break; - } + acpi_get_table(id, 0, &madt); if (!madt) { - printk(KERN_WARNING PREFIX "%s not present\n", - acpi_table_signatures[id]); + printk(KERN_WARNING PREFIX "%4.4s not present\n", id); return -ENODEV; } - madt_end = (unsigned long)madt + sdt_entry[i].size; + madt_end = (unsigned long)madt + madt->length; /* Parse all entries looking for a match. */ - entry = (acpi_table_entry_header *) + entry = (struct acpi_subtable_header *) ((unsigned long)madt + madt_size); - while (((unsigned long)entry) + sizeof(acpi_table_entry_header) < + while (((unsigned long)entry) + sizeof(struct acpi_subtable_header) < madt_end) { if (entry->type == entry_id && (!max_entries || count++ < max_entries)) if (handler(entry, madt_end)) return -EINVAL; - entry = (acpi_table_entry_header *) + entry = (struct acpi_subtable_header *) ((unsigned long)entry + entry->length); } if (max_entries && count > max_entries) { - printk(KERN_WARNING PREFIX "[%s:0x%02x] ignored %i entries of " - "%i found\n", acpi_table_signatures[id], entry_id, - count - max_entries, count); + printk(KERN_WARNING PREFIX "[%4.4s:0x%02x] ignored %i entries of " + "%i found\n", id, entry_id, count - max_entries, count); } return count; } int __init -acpi_table_parse_madt(enum acpi_madt_entry_id id, +acpi_table_parse_madt(enum acpi_madt_type id, acpi_madt_entry_handler handler, unsigned int max_entries) { - return acpi_table_parse_madt_family(ACPI_APIC, + return acpi_table_parse_madt_family(ACPI_SIG_MADT, sizeof(struct acpi_table_madt), id, handler, max_entries); } -int __init acpi_table_parse(enum acpi_table_id id, acpi_table_handler handler) +int __init acpi_table_parse(char *id, acpi_table_handler handler) { - int count = 0; - unsigned int i = 0; - + struct acpi_table_header *table = NULL; if (!handler) return -EINVAL; - for (i = 0; i < sdt_count; i++) { - if (sdt_entry[i].id != id) - continue; - count++; - if (count == 1) - handler(sdt_entry[i].pa, sdt_entry[i].size); - - else - printk(KERN_WARNING PREFIX - "%d duplicate %s table ignored.\n", count, - acpi_table_signatures[id]); - } - - return count; -} - -static int __init acpi_table_get_sdt(struct acpi_table_rsdp *rsdp) -{ - struct acpi_table_header *header = NULL; - unsigned int i, id = 0; - - if (!rsdp) - return -EINVAL; - - /* First check XSDT (but only on ACPI 2.0-compatible systems) */ - - if ((rsdp->revision >= 2) && - (((struct acpi20_table_rsdp *)rsdp)->xsdt_address)) { - - struct acpi_table_xsdt *mapped_xsdt = NULL; - - sdt_pa = ((struct acpi20_table_rsdp *)rsdp)->xsdt_address; - - /* map in just the header */ - header = (struct acpi_table_header *) - __acpi_map_table(sdt_pa, sizeof(struct acpi_table_header)); - - if (!header) { - printk(KERN_WARNING PREFIX - "Unable to map XSDT header\n"); - return -ENODEV; - } - - /* remap in the entire table before processing */ - mapped_xsdt = (struct acpi_table_xsdt *) - __acpi_map_table(sdt_pa, header->length); - if (!mapped_xsdt) { - printk(KERN_WARNING PREFIX "Unable to map XSDT\n"); - return -ENODEV; - } - header = &mapped_xsdt->header; - - if (strncmp(header->signature, "XSDT", 4)) { - printk(KERN_WARNING PREFIX - "XSDT signature incorrect\n"); - return -ENODEV; - } - - if (acpi_table_compute_checksum(header, header->length)) { - printk(KERN_WARNING PREFIX "Invalid XSDT checksum\n"); - return -ENODEV; - } - - sdt_count = - (header->length - sizeof(struct acpi_table_header)) >> 3; - if (sdt_count > ACPI_MAX_TABLES) { - printk(KERN_WARNING PREFIX - "Truncated %lu XSDT entries\n", - (sdt_count - ACPI_MAX_TABLES)); - sdt_count = ACPI_MAX_TABLES; - } - - for (i = 0; i < sdt_count; i++) - sdt_entry[i].pa = (unsigned long)mapped_xsdt->entry[i]; - } - - /* Then check RSDT */ - - else if (rsdp->rsdt_address) { - - struct acpi_table_rsdt *mapped_rsdt = NULL; - - sdt_pa = rsdp->rsdt_address; - - /* map in just the header */ - header = (struct acpi_table_header *) - __acpi_map_table(sdt_pa, sizeof(struct acpi_table_header)); - if (!header) { - printk(KERN_WARNING PREFIX - "Unable to map RSDT header\n"); - return -ENODEV; - } - - /* remap in the entire table before processing */ - mapped_rsdt = (struct acpi_table_rsdt *) - __acpi_map_table(sdt_pa, header->length); - if (!mapped_rsdt) { - printk(KERN_WARNING PREFIX "Unable to map RSDT\n"); - return -ENODEV; - } - header = &mapped_rsdt->header; - - if (strncmp(header->signature, "RSDT", 4)) { - printk(KERN_WARNING PREFIX - "RSDT signature incorrect\n"); - return -ENODEV; - } - - if (acpi_table_compute_checksum(header, header->length)) { - printk(KERN_WARNING PREFIX "Invalid RSDT checksum\n"); - return -ENODEV; - } - - sdt_count = - (header->length - sizeof(struct acpi_table_header)) >> 2; - if (sdt_count > ACPI_MAX_TABLES) { - printk(KERN_WARNING PREFIX - "Truncated %lu RSDT entries\n", - (sdt_count - ACPI_MAX_TABLES)); - sdt_count = ACPI_MAX_TABLES; - } - - for (i = 0; i < sdt_count; i++) - sdt_entry[i].pa = (unsigned long)mapped_rsdt->entry[i]; - } - - else { - printk(KERN_WARNING PREFIX - "No System Description Table (RSDT/XSDT) specified in RSDP\n"); - return -ENODEV; - } - - acpi_table_print(header, sdt_pa); - - for (i = 0; i < sdt_count; i++) { - - /* map in just the header */ - header = (struct acpi_table_header *) - __acpi_map_table(sdt_entry[i].pa, - sizeof(struct acpi_table_header)); - if (!header) - continue; - - /* remap in the entire table before processing */ - header = (struct acpi_table_header *) - __acpi_map_table(sdt_entry[i].pa, header->length); - if (!header) - continue; - - acpi_table_print(header, sdt_entry[i].pa); - - if (acpi_table_compute_checksum(header, header->length)) { - printk(KERN_WARNING " >>> ERROR: Invalid checksum\n"); - continue; - } - - sdt_entry[i].size = header->length; - - for (id = 0; id < ACPI_TABLE_COUNT; id++) { - if (!strncmp((char *)&header->signature, - acpi_table_signatures[id], - sizeof(header->signature))) { - sdt_entry[i].id = id; - } - } - } - - /* - * The DSDT is *not* in the RSDT (why not? no idea.) but we want - * to print its info, because this is what people usually blacklist - * against. Unfortunately, we don't know the phys_addr, so just - * print 0. Maybe no one will notice. - */ - if (!acpi_get_table_header_early(ACPI_DSDT, &header)) - acpi_table_print(header, 0); - - return 0; + acpi_get_table(id, 0, &table); + if (table) { + handler(table); + return 1; + } else + return 0; } /* @@ -568,54 +244,13 @@ static int __init acpi_table_get_sdt(str * * find RSDP, find and checksum SDT/XSDT. * checksum all tables, print SDT/XSDT - * + * * result: sdt_entry[] is initialized */ + int __init acpi_table_init(void) { - struct acpi_table_rsdp *rsdp = NULL; - unsigned long rsdp_phys = 0; - int result = 0; - - /* Locate and map the Root System Description Table (RSDP) */ - - rsdp_phys = acpi_find_rsdp(); - if (!rsdp_phys) { - printk(KERN_ERR PREFIX "Unable to locate RSDP\n"); - return -ENODEV; - } - - rsdp = (struct acpi_table_rsdp *)__acpi_map_table(rsdp_phys, - sizeof(struct acpi_table_rsdp)); - if (!rsdp) { - printk(KERN_WARNING PREFIX "Unable to map RSDP\n"); - return -ENODEV; - } - - printk(KERN_DEBUG PREFIX - "RSDP (v%3.3d %6.6s ) @ 0x%p\n", - rsdp->revision, rsdp->oem_id, (void *)rsdp_phys); - - if (rsdp->revision < 2) - result = - acpi_table_compute_checksum(rsdp, - sizeof(struct acpi_table_rsdp)); - else - result = - acpi_table_compute_checksum(rsdp, - ((struct acpi20_table_rsdp *) - rsdp)->length); - - if (result) { - printk(KERN_WARNING " >>> ERROR: Invalid checksum\n"); - return -ENODEV; - } - - /* Locate and map the System Description table (RSDT/XSDT) */ - - if (acpi_table_get_sdt(rsdp)) - return -ENODEV; - + acpi_initialize_tables(initial_tables, ACPI_MAX_TABLES, 0); return 0; } diff --git a/drivers/acpi/tables/Makefile b/drivers/acpi/tables/Makefile index aa4c695..0a7d7af 100644 --- a/drivers/acpi/tables/Makefile +++ b/drivers/acpi/tables/Makefile @@ -2,7 +2,6 @@ # # Makefile for all Linux ACPI interpreter subdirectories # -obj-y := tbconvrt.o tbget.o tbrsdt.o tbxface.o \ - tbgetall.o tbinstal.o tbutils.o tbxfroot.o +obj-y := tbxface.o tbinstal.o tbutils.o tbfind.o tbfadt.o EXTRA_CFLAGS += $(ACPI_CFLAGS) diff --git a/drivers/acpi/tables/tbconvrt.c b/drivers/acpi/tables/tbconvrt.c deleted file mode 100644 index d697fcb..0000000 --- a/drivers/acpi/tables/tbconvrt.c +++ /dev/null @@ -1,622 +0,0 @@ -/****************************************************************************** - * - * Module Name: tbconvrt - ACPI Table conversion utilities - * - *****************************************************************************/ - -/* - * Copyright (C) 2000 - 2006, R. Byron Moore - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions, and the following disclaimer, - * without modification. - * 2. Redistributions in binary form must reproduce at minimum a disclaimer - * substantially similar to the "NO WARRANTY" disclaimer below - * ("Disclaimer") and any redistribution must be conditioned upon - * including a substantially similar Disclaimer requirement for further - * binary redistribution. - * 3. Neither the names of the above-listed copyright holders nor the names - * of any contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * Alternatively, this software may be distributed under the terms of the - * GNU General Public License ("GPL") version 2 as published by the Free - * Software Foundation. - * - * NO WARRANTY - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, - * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING - * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGES. - */ - -#include -#include - -#define _COMPONENT ACPI_TABLES -ACPI_MODULE_NAME("tbconvrt") - -/* Local prototypes */ -static void -acpi_tb_init_generic_address(struct acpi_generic_address *new_gas_struct, - u8 register_bit_width, - acpi_physical_address address); - -static void -acpi_tb_convert_fadt1(struct fadt_descriptor *local_fadt, - struct fadt_descriptor_rev1 *original_fadt); - -static void -acpi_tb_convert_fadt2(struct fadt_descriptor *local_fadt, - struct fadt_descriptor *original_fadt); - -u8 acpi_fadt_is_v1; -ACPI_EXPORT_SYMBOL(acpi_fadt_is_v1) - -/******************************************************************************* - * - * FUNCTION: acpi_tb_get_table_count - * - * PARAMETERS: RSDP - Pointer to the RSDP - * RSDT - Pointer to the RSDT/XSDT - * - * RETURN: The number of tables pointed to by the RSDT or XSDT. - * - * DESCRIPTION: Calculate the number of tables. Automatically handles either - * an RSDT or XSDT. - * - ******************************************************************************/ - -u32 -acpi_tb_get_table_count(struct rsdp_descriptor *RSDP, - struct acpi_table_header *RSDT) -{ - u32 pointer_size; - - ACPI_FUNCTION_ENTRY(); - - /* RSDT pointers are 32 bits, XSDT pointers are 64 bits */ - - if (acpi_gbl_root_table_type == ACPI_TABLE_TYPE_RSDT) { - pointer_size = sizeof(u32); - } else { - pointer_size = sizeof(u64); - } - - /* - * Determine the number of tables pointed to by the RSDT/XSDT. - * This is defined by the ACPI Specification to be the number of - * pointers contained within the RSDT/XSDT. The size of the pointers - * is architecture-dependent. - */ - return ((RSDT->length - - sizeof(struct acpi_table_header)) / pointer_size); -} - -/******************************************************************************* - * - * FUNCTION: acpi_tb_convert_to_xsdt - * - * PARAMETERS: table_info - Info about the RSDT - * - * RETURN: Status - * - * DESCRIPTION: Convert an RSDT to an XSDT (internal common format) - * - ******************************************************************************/ - -acpi_status acpi_tb_convert_to_xsdt(struct acpi_table_desc *table_info) -{ - acpi_size table_size; - u32 i; - struct xsdt_descriptor *new_table; - - ACPI_FUNCTION_ENTRY(); - - /* Compute size of the converted XSDT */ - - table_size = ((acpi_size) acpi_gbl_rsdt_table_count * sizeof(u64)) + - sizeof(struct acpi_table_header); - - /* Allocate an XSDT */ - - new_table = ACPI_ALLOCATE_ZEROED(table_size); - if (!new_table) { - return (AE_NO_MEMORY); - } - - /* Copy the header and set the length */ - - ACPI_MEMCPY(new_table, table_info->pointer, - sizeof(struct acpi_table_header)); - new_table->length = (u32) table_size; - - /* Copy the table pointers */ - - for (i = 0; i < acpi_gbl_rsdt_table_count; i++) { - - /* RSDT pointers are 32 bits, XSDT pointers are 64 bits */ - - if (acpi_gbl_root_table_type == ACPI_TABLE_TYPE_RSDT) { - ACPI_STORE_ADDRESS(new_table->table_offset_entry[i], - (ACPI_CAST_PTR - (struct rsdt_descriptor, - table_info->pointer))-> - table_offset_entry[i]); - } else { - new_table->table_offset_entry[i] = - (ACPI_CAST_PTR(struct xsdt_descriptor, - table_info->pointer))-> - table_offset_entry[i]; - } - } - - /* Delete the original table (either mapped or in a buffer) */ - - acpi_tb_delete_single_table(table_info); - - /* Point the table descriptor to the new table */ - - table_info->pointer = - ACPI_CAST_PTR(struct acpi_table_header, new_table); - table_info->length = table_size; - table_info->allocation = ACPI_MEM_ALLOCATED; - - return (AE_OK); -} - -/******************************************************************************* - * - * FUNCTION: acpi_tb_init_generic_address - * - * PARAMETERS: new_gas_struct - GAS struct to be initialized - * register_bit_width - Width of this register - * Address - Address of the register - * - * RETURN: None - * - * DESCRIPTION: Initialize a GAS structure. - * - ******************************************************************************/ - -static void -acpi_tb_init_generic_address(struct acpi_generic_address *new_gas_struct, - u8 register_bit_width, - acpi_physical_address address) -{ - - ACPI_STORE_ADDRESS(new_gas_struct->address, address); - - new_gas_struct->address_space_id = ACPI_ADR_SPACE_SYSTEM_IO; - new_gas_struct->register_bit_width = register_bit_width; - new_gas_struct->register_bit_offset = 0; - new_gas_struct->access_width = 0; -} - -/******************************************************************************* - * - * FUNCTION: acpi_tb_convert_fadt1 - * - * PARAMETERS: local_fadt - Pointer to new FADT - * original_fadt - Pointer to old FADT - * - * RETURN: None, populates local_fadt - * - * DESCRIPTION: Convert an ACPI 1.0 FADT to common internal format - * - ******************************************************************************/ - -static void -acpi_tb_convert_fadt1(struct fadt_descriptor *local_fadt, - struct fadt_descriptor_rev1 *original_fadt) -{ - - /* ACPI 1.0 FACS */ - /* The BIOS stored FADT should agree with Revision 1.0 */ - acpi_fadt_is_v1 = 1; - - /* - * Copy the table header and the common part of the tables. - * - * The 2.0 table is an extension of the 1.0 table, so the entire 1.0 - * table can be copied first, then expand some fields to 64 bits. - */ - ACPI_MEMCPY(local_fadt, original_fadt, - sizeof(struct fadt_descriptor_rev1)); - - /* Convert table pointers to 64-bit fields */ - - ACPI_STORE_ADDRESS(local_fadt->xfirmware_ctrl, - local_fadt->V1_firmware_ctrl); - ACPI_STORE_ADDRESS(local_fadt->Xdsdt, local_fadt->V1_dsdt); - - /* - * System Interrupt Model isn't used in ACPI 2.0 - * (local_fadt->Reserved1 = 0;) - */ - - /* - * This field is set by the OEM to convey the preferred power management - * profile to OSPM. It doesn't have any 1.0 equivalence. Since we don't - * know what kind of 32-bit system this is, we will use "unspecified". - */ - local_fadt->prefer_PM_profile = PM_UNSPECIFIED; - - /* - * Processor Performance State Control. This is the value OSPM writes to - * the SMI_CMD register to assume processor performance state control - * responsibility. There isn't any equivalence in 1.0, but as many 1.x - * ACPI tables contain _PCT and _PSS we also keep this value, unless - * acpi_strict is set. - */ - if (acpi_strict) - local_fadt->pstate_cnt = 0; - - /* - * Support for the _CST object and C States change notification. - * This data item hasn't any 1.0 equivalence so leave it zero. - */ - local_fadt->cst_cnt = 0; - - /* - * FADT Rev 2 was an interim FADT released between ACPI 1.0 and ACPI 2.0. - * It primarily adds the FADT reset mechanism. - */ - if ((original_fadt->revision == 2) && - (original_fadt->length == - sizeof(struct fadt_descriptor_rev2_minus))) { - /* - * Grab the entire generic address struct, plus the 1-byte reset value - * that immediately follows. - */ - ACPI_MEMCPY(&local_fadt->reset_register, - &(ACPI_CAST_PTR(struct fadt_descriptor_rev2_minus, - original_fadt))->reset_register, - sizeof(struct acpi_generic_address) + 1); - } else { - /* - * Since there isn't any equivalence in 1.0 and since it is highly - * likely that a 1.0 system has legacy support. - */ - local_fadt->iapc_boot_arch = BAF_LEGACY_DEVICES; - } - - /* - * Convert the V1.0 block addresses to V2.0 GAS structures - */ - acpi_tb_init_generic_address(&local_fadt->xpm1a_evt_blk, - local_fadt->pm1_evt_len, - (acpi_physical_address) local_fadt-> - V1_pm1a_evt_blk); - acpi_tb_init_generic_address(&local_fadt->xpm1b_evt_blk, - local_fadt->pm1_evt_len, - (acpi_physical_address) local_fadt-> - V1_pm1b_evt_blk); - acpi_tb_init_generic_address(&local_fadt->xpm1a_cnt_blk, - local_fadt->pm1_cnt_len, - (acpi_physical_address) local_fadt-> - V1_pm1a_cnt_blk); - acpi_tb_init_generic_address(&local_fadt->xpm1b_cnt_blk, - local_fadt->pm1_cnt_len, - (acpi_physical_address) local_fadt-> - V1_pm1b_cnt_blk); - acpi_tb_init_generic_address(&local_fadt->xpm2_cnt_blk, - local_fadt->pm2_cnt_len, - (acpi_physical_address) local_fadt-> - V1_pm2_cnt_blk); - acpi_tb_init_generic_address(&local_fadt->xpm_tmr_blk, - local_fadt->pm_tm_len, - (acpi_physical_address) local_fadt-> - V1_pm_tmr_blk); - acpi_tb_init_generic_address(&local_fadt->xgpe0_blk, 0, - (acpi_physical_address) local_fadt-> - V1_gpe0_blk); - acpi_tb_init_generic_address(&local_fadt->xgpe1_blk, 0, - (acpi_physical_address) local_fadt-> - V1_gpe1_blk); - - /* Create separate GAS structs for the PM1 Enable registers */ - - acpi_tb_init_generic_address(&acpi_gbl_xpm1a_enable, - (u8) ACPI_DIV_2(acpi_gbl_FADT-> - pm1_evt_len), - (acpi_physical_address) - (local_fadt->xpm1a_evt_blk.address + - ACPI_DIV_2(acpi_gbl_FADT->pm1_evt_len))); - - /* PM1B is optional; leave null if not present */ - - if (local_fadt->xpm1b_evt_blk.address) { - acpi_tb_init_generic_address(&acpi_gbl_xpm1b_enable, - (u8) ACPI_DIV_2(acpi_gbl_FADT-> - pm1_evt_len), - (acpi_physical_address) - (local_fadt->xpm1b_evt_blk. - address + - ACPI_DIV_2(acpi_gbl_FADT-> - pm1_evt_len))); - } -} - -/******************************************************************************* - * - * FUNCTION: acpi_tb_convert_fadt2 - * - * PARAMETERS: local_fadt - Pointer to new FADT - * original_fadt - Pointer to old FADT - * - * RETURN: None, populates local_fadt - * - * DESCRIPTION: Convert an ACPI 2.0 FADT to common internal format. - * Handles optional "X" fields. - * - ******************************************************************************/ - -static void -acpi_tb_convert_fadt2(struct fadt_descriptor *local_fadt, - struct fadt_descriptor *original_fadt) -{ - - /* We have an ACPI 2.0 FADT but we must copy it to our local buffer */ - - ACPI_MEMCPY(local_fadt, original_fadt, sizeof(struct fadt_descriptor)); - - /* - * "X" fields are optional extensions to the original V1.0 fields, so - * we must selectively expand V1.0 fields if the corresponding X field - * is zero. - */ - if (!(local_fadt->xfirmware_ctrl)) { - ACPI_STORE_ADDRESS(local_fadt->xfirmware_ctrl, - local_fadt->V1_firmware_ctrl); - } - - if (!(local_fadt->Xdsdt)) { - ACPI_STORE_ADDRESS(local_fadt->Xdsdt, local_fadt->V1_dsdt); - } - - if (!(local_fadt->xpm1a_evt_blk.address)) { - acpi_tb_init_generic_address(&local_fadt->xpm1a_evt_blk, - local_fadt->pm1_evt_len, - (acpi_physical_address) - local_fadt->V1_pm1a_evt_blk); - } - - if (!(local_fadt->xpm1b_evt_blk.address)) { - acpi_tb_init_generic_address(&local_fadt->xpm1b_evt_blk, - local_fadt->pm1_evt_len, - (acpi_physical_address) - local_fadt->V1_pm1b_evt_blk); - } - - if (!(local_fadt->xpm1a_cnt_blk.address)) { - acpi_tb_init_generic_address(&local_fadt->xpm1a_cnt_blk, - local_fadt->pm1_cnt_len, - (acpi_physical_address) - local_fadt->V1_pm1a_cnt_blk); - } - - if (!(local_fadt->xpm1b_cnt_blk.address)) { - acpi_tb_init_generic_address(&local_fadt->xpm1b_cnt_blk, - local_fadt->pm1_cnt_len, - (acpi_physical_address) - local_fadt->V1_pm1b_cnt_blk); - } - - if (!(local_fadt->xpm2_cnt_blk.address)) { - acpi_tb_init_generic_address(&local_fadt->xpm2_cnt_blk, - local_fadt->pm2_cnt_len, - (acpi_physical_address) - local_fadt->V1_pm2_cnt_blk); - } - - if (!(local_fadt->xpm_tmr_blk.address)) { - acpi_tb_init_generic_address(&local_fadt->xpm_tmr_blk, - local_fadt->pm_tm_len, - (acpi_physical_address) - local_fadt->V1_pm_tmr_blk); - } - - if (!(local_fadt->xgpe0_blk.address)) { - acpi_tb_init_generic_address(&local_fadt->xgpe0_blk, - 0, - (acpi_physical_address) - local_fadt->V1_gpe0_blk); - } - - if (!(local_fadt->xgpe1_blk.address)) { - acpi_tb_init_generic_address(&local_fadt->xgpe1_blk, - 0, - (acpi_physical_address) - local_fadt->V1_gpe1_blk); - } - - /* Create separate GAS structs for the PM1 Enable registers */ - - acpi_tb_init_generic_address(&acpi_gbl_xpm1a_enable, - (u8) ACPI_DIV_2(acpi_gbl_FADT-> - pm1_evt_len), - (acpi_physical_address) - (local_fadt->xpm1a_evt_blk.address + - ACPI_DIV_2(acpi_gbl_FADT->pm1_evt_len))); - - acpi_gbl_xpm1a_enable.address_space_id = - local_fadt->xpm1a_evt_blk.address_space_id; - - /* PM1B is optional; leave null if not present */ - - if (local_fadt->xpm1b_evt_blk.address) { - acpi_tb_init_generic_address(&acpi_gbl_xpm1b_enable, - (u8) ACPI_DIV_2(acpi_gbl_FADT-> - pm1_evt_len), - (acpi_physical_address) - (local_fadt->xpm1b_evt_blk. - address + - ACPI_DIV_2(acpi_gbl_FADT-> - pm1_evt_len))); - - acpi_gbl_xpm1b_enable.address_space_id = - local_fadt->xpm1b_evt_blk.address_space_id; - } -} - -/******************************************************************************* - * - * FUNCTION: acpi_tb_convert_table_fadt - * - * PARAMETERS: None - * - * RETURN: Status - * - * DESCRIPTION: Converts a BIOS supplied ACPI 1.0 FADT to a local - * ACPI 2.0 FADT. If the BIOS supplied a 2.0 FADT then it is simply - * copied to the local FADT. The ACPI CA software uses this - * local FADT. Thus a significant amount of special #ifdef - * type codeing is saved. - * - ******************************************************************************/ - -acpi_status acpi_tb_convert_table_fadt(void) -{ - struct fadt_descriptor *local_fadt; - struct acpi_table_desc *table_desc; - - ACPI_FUNCTION_TRACE(tb_convert_table_fadt); - - /* - * acpi_gbl_FADT is valid. Validate the FADT length. The table must be - * at least as long as the version 1.0 FADT - */ - if (acpi_gbl_FADT->length < sizeof(struct fadt_descriptor_rev1)) { - ACPI_ERROR((AE_INFO, "FADT is invalid, too short: 0x%X", - acpi_gbl_FADT->length)); - return_ACPI_STATUS(AE_INVALID_TABLE_LENGTH); - } - - /* Allocate buffer for the ACPI 2.0(+) FADT */ - - local_fadt = ACPI_ALLOCATE_ZEROED(sizeof(struct fadt_descriptor)); - if (!local_fadt) { - return_ACPI_STATUS(AE_NO_MEMORY); - } - - if (acpi_gbl_FADT->revision >= FADT2_REVISION_ID) { - if (acpi_gbl_FADT->length < sizeof(struct fadt_descriptor)) { - - /* Length is too short to be a V2.0 table */ - - ACPI_WARNING((AE_INFO, - "Inconsistent FADT length (0x%X) and revision (0x%X), using FADT V1.0 portion of table", - acpi_gbl_FADT->length, - acpi_gbl_FADT->revision)); - - acpi_tb_convert_fadt1(local_fadt, - (void *)acpi_gbl_FADT); - } else { - /* Valid V2.0 table */ - - acpi_tb_convert_fadt2(local_fadt, acpi_gbl_FADT); - } - } else { - /* Valid V1.0 table */ - - acpi_tb_convert_fadt1(local_fadt, (void *)acpi_gbl_FADT); - } - - /* Global FADT pointer will point to the new common V2.0 FADT */ - - acpi_gbl_FADT = local_fadt; - acpi_gbl_FADT->length = sizeof(struct fadt_descriptor); - - /* Free the original table */ - - table_desc = acpi_gbl_table_lists[ACPI_TABLE_ID_FADT].next; - acpi_tb_delete_single_table(table_desc); - - /* Install the new table */ - - table_desc->pointer = - ACPI_CAST_PTR(struct acpi_table_header, acpi_gbl_FADT); - table_desc->allocation = ACPI_MEM_ALLOCATED; - table_desc->length = sizeof(struct fadt_descriptor); - - /* Dump the entire FADT */ - - ACPI_DEBUG_PRINT((ACPI_DB_TABLES, - "Hex dump of common internal FADT, size %d (%X)\n", - acpi_gbl_FADT->length, acpi_gbl_FADT->length)); - - ACPI_DUMP_BUFFER(ACPI_CAST_PTR(u8, acpi_gbl_FADT), - acpi_gbl_FADT->length); - - return_ACPI_STATUS(AE_OK); -} - -/******************************************************************************* - * - * FUNCTION: acpi_tb_build_common_facs - * - * PARAMETERS: table_info - Info for currently installed FACS - * - * RETURN: Status - * - * DESCRIPTION: Convert ACPI 1.0 and ACPI 2.0 FACS to a common internal - * table format. - * - ******************************************************************************/ - -acpi_status acpi_tb_build_common_facs(struct acpi_table_desc *table_info) -{ - - ACPI_FUNCTION_TRACE(tb_build_common_facs); - - /* Absolute minimum length is 24, but the ACPI spec says 64 */ - - if (acpi_gbl_FACS->length < 24) { - ACPI_ERROR((AE_INFO, "Invalid FACS table length: 0x%X", - acpi_gbl_FACS->length)); - return_ACPI_STATUS(AE_INVALID_TABLE_LENGTH); - } - - if (acpi_gbl_FACS->length < 64) { - ACPI_WARNING((AE_INFO, - "FACS is shorter than the ACPI specification allows: 0x%X, using anyway", - acpi_gbl_FACS->length)); - } - - /* Copy fields to the new FACS */ - - acpi_gbl_common_fACS.global_lock = &(acpi_gbl_FACS->global_lock); - - if ((acpi_gbl_RSDP->revision < 2) || - (acpi_gbl_FACS->length < 32) || - (!(acpi_gbl_FACS->xfirmware_waking_vector))) { - - /* ACPI 1.0 FACS or short table or optional X_ field is zero */ - - acpi_gbl_common_fACS.firmware_waking_vector = ACPI_CAST_PTR(u64, - & - (acpi_gbl_FACS-> - firmware_waking_vector)); - acpi_gbl_common_fACS.vector_width = 32; - } else { - /* ACPI 2.0 FACS with valid X_ field */ - - acpi_gbl_common_fACS.firmware_waking_vector = - &acpi_gbl_FACS->xfirmware_waking_vector; - acpi_gbl_common_fACS.vector_width = 64; - } - - return_ACPI_STATUS(AE_OK); -} diff --git a/drivers/acpi/tables/tbfadt.c b/drivers/acpi/tables/tbfadt.c new file mode 100644 index 0000000..807c711 --- /dev/null +++ b/drivers/acpi/tables/tbfadt.c @@ -0,0 +1,434 @@ +/****************************************************************************** + * + * Module Name: tbfadt - FADT table utilities + * + *****************************************************************************/ + +/* + * Copyright (C) 2000 - 2007, R. Byron Moore + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + */ + +#include +#include + +#define _COMPONENT ACPI_TABLES +ACPI_MODULE_NAME("tbfadt") + +/* Local prototypes */ +static void inline +acpi_tb_init_generic_address(struct acpi_generic_address *generic_address, + u8 bit_width, u64 address); + +static void acpi_tb_convert_fadt(void); + +static void acpi_tb_validate_fadt(void); + +/* Table for conversion of FADT to common internal format and FADT validation */ + +typedef struct acpi_fadt_info { + char *name; + u8 target; + u8 source; + u8 length; + u8 type; + +} acpi_fadt_info; + +#define ACPI_FADT_REQUIRED 1 +#define ACPI_FADT_SEPARATE_LENGTH 2 + +static struct acpi_fadt_info fadt_info_table[] = { + {"Pm1aEventBlock", ACPI_FADT_OFFSET(xpm1a_event_block), + ACPI_FADT_OFFSET(pm1a_event_block), + ACPI_FADT_OFFSET(pm1_event_length), ACPI_FADT_REQUIRED}, + + {"Pm1bEventBlock", ACPI_FADT_OFFSET(xpm1b_event_block), + ACPI_FADT_OFFSET(pm1b_event_block), + ACPI_FADT_OFFSET(pm1_event_length), 0}, + + {"Pm1aControlBlock", ACPI_FADT_OFFSET(xpm1a_control_block), + ACPI_FADT_OFFSET(pm1a_control_block), + ACPI_FADT_OFFSET(pm1_control_length), ACPI_FADT_REQUIRED}, + + {"Pm1bControlBlock", ACPI_FADT_OFFSET(xpm1b_control_block), + ACPI_FADT_OFFSET(pm1b_control_block), + ACPI_FADT_OFFSET(pm1_control_length), 0}, + + {"Pm2ControlBlock", ACPI_FADT_OFFSET(xpm2_control_block), + ACPI_FADT_OFFSET(pm2_control_block), + ACPI_FADT_OFFSET(pm2_control_length), ACPI_FADT_SEPARATE_LENGTH}, + + {"PmTimerBlock", ACPI_FADT_OFFSET(xpm_timer_block), + ACPI_FADT_OFFSET(pm_timer_block), + ACPI_FADT_OFFSET(pm_timer_length), ACPI_FADT_REQUIRED}, + + {"Gpe0Block", ACPI_FADT_OFFSET(xgpe0_block), + ACPI_FADT_OFFSET(gpe0_block), + ACPI_FADT_OFFSET(gpe0_block_length), ACPI_FADT_SEPARATE_LENGTH}, + + {"Gpe1Block", ACPI_FADT_OFFSET(xgpe1_block), + ACPI_FADT_OFFSET(gpe1_block), + ACPI_FADT_OFFSET(gpe1_block_length), ACPI_FADT_SEPARATE_LENGTH} +}; + +#define ACPI_FADT_INFO_ENTRIES (sizeof (fadt_info_table) / sizeof (struct acpi_fadt_info)) + +/******************************************************************************* + * + * FUNCTION: acpi_tb_init_generic_address + * + * PARAMETERS: generic_address - GAS struct to be initialized + * bit_width - Width of this register + * Address - Address of the register + * + * RETURN: None + * + * DESCRIPTION: Initialize a Generic Address Structure (GAS) + * See the ACPI specification for a full description and + * definition of this structure. + * + ******************************************************************************/ + +static void inline +acpi_tb_init_generic_address(struct acpi_generic_address *generic_address, + u8 bit_width, u64 address) +{ + + /* + * The 64-bit Address field is non-aligned in the byte packed + * GAS struct. + */ + ACPI_MOVE_64_TO_64(&generic_address->address, &address); + + /* All other fields are byte-wide */ + + generic_address->space_id = ACPI_ADR_SPACE_SYSTEM_IO; + generic_address->bit_width = bit_width; + generic_address->bit_offset = 0; + generic_address->access_width = 0; +} + +/******************************************************************************* + * + * FUNCTION: acpi_tb_parse_fadt + * + * PARAMETERS: table_index - Index for the FADT + * Flags - Flags + * + * RETURN: None + * + * DESCRIPTION: Initialize the FADT, DSDT and FACS tables + * (FADT contains the addresses of the DSDT and FACS) + * + ******************************************************************************/ + +void acpi_tb_parse_fadt(acpi_native_uint table_index, u8 flags) +{ + u32 length; + struct acpi_table_header *table; + + /* + * The FADT has multiple versions with different lengths, + * and it contains pointers to both the DSDT and FACS tables. + * + * Get a local copy of the FADT and convert it to a common format + * Map entire FADT, assumed to be smaller than one page. + */ + length = acpi_gbl_root_table_list.tables[table_index].length; + + table = + acpi_os_map_memory(acpi_gbl_root_table_list.tables[table_index]. + address, length); + if (!table) { + return; + } + + /* + * Validate the FADT checksum before we copy the table. Ignore + * checksum error as we want to try to get the DSDT and FACS. + */ + (void)acpi_tb_verify_checksum(table, length); + + /* Obtain a local copy of the FADT in common ACPI 2.0+ format */ + + acpi_tb_create_local_fadt(table, length); + + /* All done with the real FADT, unmap it */ + + acpi_os_unmap_memory(table, length); + + /* Obtain the DSDT and FACS tables via their addresses within the FADT */ + + acpi_tb_install_table((acpi_physical_address) acpi_gbl_FADT.Xdsdt, + flags, ACPI_SIG_DSDT, ACPI_TABLE_INDEX_DSDT); + + acpi_tb_install_table((acpi_physical_address) acpi_gbl_FADT.Xfacs, + flags, ACPI_SIG_FACS, ACPI_TABLE_INDEX_FACS); +} + +/******************************************************************************* + * + * FUNCTION: acpi_tb_create_local_fadt + * + * PARAMETERS: Table - Pointer to BIOS FADT + * Length - Length of the table + * + * RETURN: None + * + * DESCRIPTION: Get a local copy of the FADT and convert it to a common format. + * Performs validation on some important FADT fields. + * + ******************************************************************************/ + +void acpi_tb_create_local_fadt(struct acpi_table_header *table, u32 length) +{ + + /* + * Check if the FADT is larger than what we know about (ACPI 2.0 version). + * Truncate the table, but make some noise. + */ + if (length > sizeof(struct acpi_table_fadt)) { + ACPI_WARNING((AE_INFO, + "FADT (revision %u) is longer than ACPI 2.0 version, truncating length 0x%X to 0x%zX", + table->revision, (unsigned)length, + sizeof(struct acpi_table_fadt))); + } + + /* Copy the entire FADT locally. Zero first for tb_convert_fadt */ + + ACPI_MEMSET(&acpi_gbl_FADT, 0, sizeof(struct acpi_table_fadt)); + + ACPI_MEMCPY(&acpi_gbl_FADT, table, + ACPI_MIN(length, sizeof(struct acpi_table_fadt))); + + /* + * 1) Convert the local copy of the FADT to the common internal format + * 2) Validate some of the important values within the FADT + */ + acpi_tb_convert_fadt(); + acpi_tb_validate_fadt(); +} + +/******************************************************************************* + * + * FUNCTION: acpi_tb_convert_fadt + * + * PARAMETERS: None, uses acpi_gbl_FADT + * + * RETURN: None + * + * DESCRIPTION: Converts all versions of the FADT to a common internal format. + * -> Expand all 32-bit addresses to 64-bit. + * + * NOTE: acpi_gbl_FADT must be of size (struct acpi_table_fadt), + * and must contain a copy of the actual FADT. + * + * ACPICA will use the "X" fields of the FADT for all addresses. + * + * "X" fields are optional extensions to the original V1.0 fields. Even if + * they are present in the structure, they can be optionally not used by + * setting them to zero. Therefore, we must selectively expand V1.0 fields + * if the corresponding X field is zero. + * + * For ACPI 1.0 FADTs, all address fields are expanded to the corresponding + * "X" fields. + * + * For ACPI 2.0 FADTs, any "X" fields that are NULL are filled in by + * expanding the corresponding ACPI 1.0 field. + * + ******************************************************************************/ + +static void acpi_tb_convert_fadt(void) +{ + u8 pm1_register_length; + struct acpi_generic_address *target; + acpi_native_uint i; + + /* Update the local FADT table header length */ + + acpi_gbl_FADT.header.length = sizeof(struct acpi_table_fadt); + + /* Expand the 32-bit FACS and DSDT addresses to 64-bit as necessary */ + + if (!acpi_gbl_FADT.Xfacs) { + acpi_gbl_FADT.Xfacs = (u64) acpi_gbl_FADT.facs; + } + + if (!acpi_gbl_FADT.Xdsdt) { + acpi_gbl_FADT.Xdsdt = (u64) acpi_gbl_FADT.dsdt; + } + + /* + * Expand the 32-bit V1.0 addresses to the 64-bit "X" generic address + * structures as necessary. + */ + for (i = 0; i < ACPI_FADT_INFO_ENTRIES; i++) { + target = + ACPI_ADD_PTR(struct acpi_generic_address, &acpi_gbl_FADT, + fadt_info_table[i].target); + + /* Expand only if the X target is null */ + + if (!target->address) { + acpi_tb_init_generic_address(target, + *ACPI_ADD_PTR(u8, + &acpi_gbl_FADT, + fadt_info_table + [i].length), + (u64) * ACPI_ADD_PTR(u32, + &acpi_gbl_FADT, + fadt_info_table + [i]. + source)); + } + } + + /* + * Calculate separate GAS structs for the PM1 Enable registers. + * These addresses do not appear (directly) in the FADT, so it is + * useful to calculate them once, here. + * + * The PM event blocks are split into two register blocks, first is the + * PM Status Register block, followed immediately by the PM Enable Register + * block. Each is of length (pm1_event_length/2) + */ + pm1_register_length = (u8) ACPI_DIV_2(acpi_gbl_FADT.pm1_event_length); + + /* The PM1A register block is required */ + + acpi_tb_init_generic_address(&acpi_gbl_xpm1a_enable, + pm1_register_length, + (acpi_gbl_FADT.xpm1a_event_block.address + + pm1_register_length)); + /* Don't forget to copy space_id of the GAS */ + acpi_gbl_xpm1a_enable.space_id = acpi_gbl_FADT.xpm1a_event_block.space_id; + + /* The PM1B register block is optional, ignore if not present */ + + if (acpi_gbl_FADT.xpm1b_event_block.address) { + acpi_tb_init_generic_address(&acpi_gbl_xpm1b_enable, + pm1_register_length, + (acpi_gbl_FADT.xpm1b_event_block. + address + pm1_register_length)); + /* Don't forget to copy space_id of the GAS */ + acpi_gbl_xpm1b_enable.space_id = acpi_gbl_FADT.xpm1a_event_block.space_id; + + } +} + +/****************************************************************************** + * + * FUNCTION: acpi_tb_validate_fadt + * + * PARAMETERS: Table - Pointer to the FADT to be validated + * + * RETURN: None + * + * DESCRIPTION: Validate various important fields within the FADT. If a problem + * is found, issue a message, but no status is returned. + * Used by both the table manager and the disassembler. + * + * Possible additional checks: + * (acpi_gbl_FADT.pm1_event_length >= 4) + * (acpi_gbl_FADT.pm1_control_length >= 2) + * (acpi_gbl_FADT.pm_timer_length >= 4) + * Gpe block lengths must be multiple of 2 + * + ******************************************************************************/ + +static void acpi_tb_validate_fadt(void) +{ + u32 *address32; + struct acpi_generic_address *address64; + u8 length; + acpi_native_uint i; + + /* Examine all of the 64-bit extended address fields (X fields) */ + + for (i = 0; i < ACPI_FADT_INFO_ENTRIES; i++) { + + /* Generate pointers to the 32-bit and 64-bit addresses and get the length */ + + address64 = + ACPI_ADD_PTR(struct acpi_generic_address, &acpi_gbl_FADT, + fadt_info_table[i].target); + address32 = + ACPI_ADD_PTR(u32, &acpi_gbl_FADT, + fadt_info_table[i].source); + length = + *ACPI_ADD_PTR(u8, &acpi_gbl_FADT, + fadt_info_table[i].length); + + if (fadt_info_table[i].type & ACPI_FADT_REQUIRED) { + /* + * Field is required (Pm1a_event, Pm1a_control, pm_timer). + * Both the address and length must be non-zero. + */ + if (!address64->address || !length) { + ACPI_ERROR((AE_INFO, + "Required field \"%s\" has zero address and/or length: %8.8X%8.8X/%X", + fadt_info_table[i].name, + ACPI_FORMAT_UINT64(address64-> + address), + length)); + } + } else if (fadt_info_table[i].type & ACPI_FADT_SEPARATE_LENGTH) { + /* + * Field is optional (PM2Control, GPE0, GPE1) AND has its own + * length field. If present, both the address and length must be valid. + */ + if ((address64->address && !length) + || (!address64->address && length)) { + ACPI_WARNING((AE_INFO, + "Optional field \"%s\" has zero address or length: %8.8X%8.8X/%X", + fadt_info_table[i].name, + ACPI_FORMAT_UINT64(address64-> + address), + length)); + } + } + + /* If both 32- and 64-bit addresses are valid (non-zero), they must match */ + + if (address64->address && *address32 && + (address64->address != (u64) * address32)) { + ACPI_ERROR((AE_INFO, + "32/64X address mismatch in \"%s\": [%8.8X] [%8.8X%8.8X], using 64X", + fadt_info_table[i].name, *address32, + ACPI_FORMAT_UINT64(address64->address))); + } + } +} diff --git a/drivers/acpi/tables/tbfind.c b/drivers/acpi/tables/tbfind.c new file mode 100644 index 0000000..058c064 --- /dev/null +++ b/drivers/acpi/tables/tbfind.c @@ -0,0 +1,126 @@ +/****************************************************************************** + * + * Module Name: tbfind - find table + * + *****************************************************************************/ + +/* + * Copyright (C) 2000 - 2007, R. Byron Moore + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + */ + +#include +#include + +#define _COMPONENT ACPI_TABLES +ACPI_MODULE_NAME("tbfind") + +/******************************************************************************* + * + * FUNCTION: acpi_tb_find_table + * + * PARAMETERS: Signature - String with ACPI table signature + * oem_id - String with the table OEM ID + * oem_table_id - String with the OEM Table ID + * table_index - Where the table index is returned + * + * RETURN: Status and table index + * + * DESCRIPTION: Find an ACPI table (in the RSDT/XSDT) that matches the + * Signature, OEM ID and OEM Table ID. Returns an index that can + * be used to get the table header or entire table. + * + ******************************************************************************/ +acpi_status +acpi_tb_find_table(char *signature, + char *oem_id, + char *oem_table_id, acpi_native_uint * table_index) +{ + acpi_native_uint i; + acpi_status status; + + ACPI_FUNCTION_TRACE(tb_find_table); + + for (i = 0; i < acpi_gbl_root_table_list.count; ++i) { + if (ACPI_MEMCMP(&(acpi_gbl_root_table_list.tables[i].signature), + signature, ACPI_NAME_SIZE)) { + + /* Not the requested table */ + + continue; + } + + /* Table with matching signature has been found */ + + if (!acpi_gbl_root_table_list.tables[i].pointer) { + + /* Table is not currently mapped, map it */ + + status = + acpi_tb_verify_table(&acpi_gbl_root_table_list. + tables[i]); + if (ACPI_FAILURE(status)) { + return_ACPI_STATUS(status); + } + + if (!acpi_gbl_root_table_list.tables[i].pointer) { + continue; + } + } + + /* Check for table match on all IDs */ + + if (!ACPI_MEMCMP + (acpi_gbl_root_table_list.tables[i].pointer->signature, + signature, ACPI_NAME_SIZE) && (!oem_id[0] + || + !ACPI_MEMCMP + (acpi_gbl_root_table_list. + tables[i].pointer->oem_id, + oem_id, ACPI_OEM_ID_SIZE)) + && (!oem_table_id[0] + || !ACPI_MEMCMP(acpi_gbl_root_table_list.tables[i]. + pointer->oem_table_id, oem_table_id, + ACPI_OEM_TABLE_ID_SIZE))) { + *table_index = i; + + ACPI_DEBUG_PRINT((ACPI_DB_TABLES, + "Found table [%4.4s]\n", signature)); + return_ACPI_STATUS(AE_OK); + } + } + + return_ACPI_STATUS(AE_NOT_FOUND); +} diff --git a/drivers/acpi/tables/tbget.c b/drivers/acpi/tables/tbget.c deleted file mode 100644 index 11e2d44..0000000 --- a/drivers/acpi/tables/tbget.c +++ /dev/null @@ -1,471 +0,0 @@ -/****************************************************************************** - * - * Module Name: tbget - ACPI Table get* routines - * - *****************************************************************************/ - -/* - * Copyright (C) 2000 - 2006, R. Byron Moore - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions, and the following disclaimer, - * without modification. - * 2. Redistributions in binary form must reproduce at minimum a disclaimer - * substantially similar to the "NO WARRANTY" disclaimer below - * ("Disclaimer") and any redistribution must be conditioned upon - * including a substantially similar Disclaimer requirement for further - * binary redistribution. - * 3. Neither the names of the above-listed copyright holders nor the names - * of any contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * Alternatively, this software may be distributed under the terms of the - * GNU General Public License ("GPL") version 2 as published by the Free - * Software Foundation. - * - * NO WARRANTY - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, - * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING - * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGES. - */ - -#include -#include - -#define _COMPONENT ACPI_TABLES -ACPI_MODULE_NAME("tbget") - -/* Local prototypes */ -static acpi_status -acpi_tb_get_this_table(struct acpi_pointer *address, - struct acpi_table_header *header, - struct acpi_table_desc *table_info); - -static acpi_status -acpi_tb_table_override(struct acpi_table_header *header, - struct acpi_table_desc *table_info); - -/******************************************************************************* - * - * FUNCTION: acpi_tb_get_table - * - * PARAMETERS: Address - Address of table to retrieve. Can be - * Logical or Physical - * table_info - Where table info is returned - * - * RETURN: None - * - * DESCRIPTION: Get entire table of unknown size. - * - ******************************************************************************/ - -acpi_status -acpi_tb_get_table(struct acpi_pointer *address, - struct acpi_table_desc *table_info) -{ - acpi_status status; - struct acpi_table_header header; - - ACPI_FUNCTION_TRACE(tb_get_table); - - /* Get the header in order to get signature and table size */ - - status = acpi_tb_get_table_header(address, &header); - if (ACPI_FAILURE(status)) { - return_ACPI_STATUS(status); - } - - /* Get the entire table */ - - status = acpi_tb_get_table_body(address, &header, table_info); - if (ACPI_FAILURE(status)) { - ACPI_EXCEPTION((AE_INFO, status, - "Could not get ACPI table (size %X)", - header.length)); - return_ACPI_STATUS(status); - } - - return_ACPI_STATUS(AE_OK); -} - -/******************************************************************************* - * - * FUNCTION: acpi_tb_get_table_header - * - * PARAMETERS: Address - Address of table to retrieve. Can be - * Logical or Physical - * return_header - Where the table header is returned - * - * RETURN: Status - * - * DESCRIPTION: Get an ACPI table header. Works in both physical or virtual - * addressing mode. Works with both physical or logical pointers. - * Table is either copied or mapped, depending on the pointer - * type and mode of the processor. - * - ******************************************************************************/ - -acpi_status -acpi_tb_get_table_header(struct acpi_pointer *address, - struct acpi_table_header *return_header) -{ - acpi_status status = AE_OK; - struct acpi_table_header *header = NULL; - - ACPI_FUNCTION_TRACE(tb_get_table_header); - - /* - * Flags contains the current processor mode (Virtual or Physical - * addressing) The pointer_type is either Logical or Physical - */ - switch (address->pointer_type) { - case ACPI_PHYSMODE_PHYSPTR: - case ACPI_LOGMODE_LOGPTR: - - /* Pointer matches processor mode, copy the header */ - - ACPI_MEMCPY(return_header, address->pointer.logical, - sizeof(struct acpi_table_header)); - break; - - case ACPI_LOGMODE_PHYSPTR: - - /* Create a logical address for the physical pointer */ - - status = acpi_os_map_memory(address->pointer.physical, - sizeof(struct acpi_table_header), - (void *)&header); - if (ACPI_FAILURE(status)) { - ACPI_ERROR((AE_INFO, - "Could not map memory at %8.8X%8.8X for table header", - ACPI_FORMAT_UINT64(address->pointer. - physical))); - return_ACPI_STATUS(status); - } - - /* Copy header and delete mapping */ - - ACPI_MEMCPY(return_header, header, - sizeof(struct acpi_table_header)); - acpi_os_unmap_memory(header, sizeof(struct acpi_table_header)); - break; - - default: - - ACPI_ERROR((AE_INFO, "Invalid address flags %X", - address->pointer_type)); - return_ACPI_STATUS(AE_BAD_PARAMETER); - } - - ACPI_DEBUG_PRINT((ACPI_DB_TABLES, "Table Signature: [%4.4s]\n", - return_header->signature)); - - return_ACPI_STATUS(AE_OK); -} - -/******************************************************************************* - * - * FUNCTION: acpi_tb_get_table_body - * - * PARAMETERS: Address - Address of table to retrieve. Can be - * Logical or Physical - * Header - Header of the table to retrieve - * table_info - Where the table info is returned - * - * RETURN: Status - * - * DESCRIPTION: Get an entire ACPI table with support to allow the host OS to - * replace the table with a newer version (table override.) - * Works in both physical or virtual - * addressing mode. Works with both physical or logical pointers. - * Table is either copied or mapped, depending on the pointer - * type and mode of the processor. - * - ******************************************************************************/ - -acpi_status -acpi_tb_get_table_body(struct acpi_pointer *address, - struct acpi_table_header *header, - struct acpi_table_desc *table_info) -{ - acpi_status status; - - ACPI_FUNCTION_TRACE(tb_get_table_body); - - if (!table_info || !address) { - return_ACPI_STATUS(AE_BAD_PARAMETER); - } - - /* Attempt table override. */ - - status = acpi_tb_table_override(header, table_info); - if (ACPI_SUCCESS(status)) { - - /* Table was overridden by the host OS */ - - return_ACPI_STATUS(status); - } - - /* No override, get the original table */ - - status = acpi_tb_get_this_table(address, header, table_info); - return_ACPI_STATUS(status); -} - -/******************************************************************************* - * - * FUNCTION: acpi_tb_table_override - * - * PARAMETERS: Header - Pointer to table header - * table_info - Return info if table is overridden - * - * RETURN: None - * - * DESCRIPTION: Attempts override of current table with a new one if provided - * by the host OS. - * - ******************************************************************************/ - -static acpi_status -acpi_tb_table_override(struct acpi_table_header *header, - struct acpi_table_desc *table_info) -{ - struct acpi_table_header *new_table; - acpi_status status; - struct acpi_pointer address; - - ACPI_FUNCTION_TRACE(tb_table_override); - - /* - * The OSL will examine the header and decide whether to override this - * table. If it decides to override, a table will be returned in new_table, - * which we will then copy. - */ - status = acpi_os_table_override(header, &new_table); - if (ACPI_FAILURE(status)) { - - /* Some severe error from the OSL, but we basically ignore it */ - - ACPI_EXCEPTION((AE_INFO, status, - "Could not override ACPI table")); - return_ACPI_STATUS(status); - } - - if (!new_table) { - - /* No table override */ - - return_ACPI_STATUS(AE_NO_ACPI_TABLES); - } - - /* - * We have a new table to override the old one. Get a copy of - * the new one. We know that the new table has a logical pointer. - */ - address.pointer_type = ACPI_LOGICAL_POINTER | ACPI_LOGICAL_ADDRESSING; - address.pointer.logical = new_table; - - status = acpi_tb_get_this_table(&address, new_table, table_info); - if (ACPI_FAILURE(status)) { - ACPI_EXCEPTION((AE_INFO, status, "Could not copy ACPI table")); - return_ACPI_STATUS(status); - } - - /* Copy the table info */ - - ACPI_INFO((AE_INFO, "Table [%4.4s] replaced by host OS", - table_info->pointer->signature)); - - return_ACPI_STATUS(AE_OK); -} - -/******************************************************************************* - * - * FUNCTION: acpi_tb_get_this_table - * - * PARAMETERS: Address - Address of table to retrieve. Can be - * Logical or Physical - * Header - Header of the table to retrieve - * table_info - Where the table info is returned - * - * RETURN: Status - * - * DESCRIPTION: Get an entire ACPI table. Works in both physical or virtual - * addressing mode. Works with both physical or logical pointers. - * Table is either copied or mapped, depending on the pointer - * type and mode of the processor. - * - ******************************************************************************/ - -static acpi_status -acpi_tb_get_this_table(struct acpi_pointer *address, - struct acpi_table_header *header, - struct acpi_table_desc *table_info) -{ - struct acpi_table_header *full_table = NULL; - u8 allocation; - acpi_status status = AE_OK; - - ACPI_FUNCTION_TRACE(tb_get_this_table); - - /* Validate minimum length */ - - if (header->length < sizeof(struct acpi_table_header)) { - ACPI_ERROR((AE_INFO, - "Table length (%X) is smaller than minimum (%zX)", - header->length, sizeof(struct acpi_table_header))); - - return_ACPI_STATUS(AE_INVALID_TABLE_LENGTH); - } - - /* - * Flags contains the current processor mode (Virtual or Physical - * addressing) The pointer_type is either Logical or Physical - */ - switch (address->pointer_type) { - case ACPI_PHYSMODE_PHYSPTR: - case ACPI_LOGMODE_LOGPTR: - - /* Pointer matches processor mode, copy the table to a new buffer */ - - full_table = ACPI_ALLOCATE(header->length); - if (!full_table) { - ACPI_ERROR((AE_INFO, - "Could not allocate table memory for [%4.4s] length %X", - header->signature, header->length)); - return_ACPI_STATUS(AE_NO_MEMORY); - } - - /* Copy the entire table (including header) to the local buffer */ - - ACPI_MEMCPY(full_table, address->pointer.logical, - header->length); - - /* Save allocation type */ - - allocation = ACPI_MEM_ALLOCATED; - break; - - case ACPI_LOGMODE_PHYSPTR: - - /* - * Just map the table's physical memory - * into our address space. - */ - status = acpi_os_map_memory(address->pointer.physical, - (acpi_size) header->length, - ACPI_CAST_PTR(void, &full_table)); - if (ACPI_FAILURE(status)) { - ACPI_ERROR((AE_INFO, - "Could not map memory for table [%4.4s] at %8.8X%8.8X for length %X", - header->signature, - ACPI_FORMAT_UINT64(address->pointer. - physical), - header->length)); - return (status); - } - - /* Save allocation type */ - - allocation = ACPI_MEM_MAPPED; - break; - - default: - - ACPI_ERROR((AE_INFO, "Invalid address flags %X", - address->pointer_type)); - return_ACPI_STATUS(AE_BAD_PARAMETER); - } - - /* - * Validate checksum for _most_ tables, - * even the ones whose signature we don't recognize - */ - if (table_info->type != ACPI_TABLE_ID_FACS) { - status = acpi_tb_verify_table_checksum(full_table); - -#if (!ACPI_CHECKSUM_ABORT) - if (ACPI_FAILURE(status)) { - - /* Ignore the error if configuration says so */ - - status = AE_OK; - } -#endif - } - - /* Return values */ - - table_info->pointer = full_table; - table_info->length = (acpi_size) header->length; - table_info->allocation = allocation; - - ACPI_DEBUG_PRINT((ACPI_DB_INFO, - "Found table [%4.4s] at %8.8X%8.8X, mapped/copied to %p\n", - full_table->signature, - ACPI_FORMAT_UINT64(address->pointer.physical), - full_table)); - - return_ACPI_STATUS(status); -} - -/******************************************************************************* - * - * FUNCTION: acpi_tb_get_table_ptr - * - * PARAMETERS: table_type - one of the defined table types - * Instance - Which table of this type - * return_table - pointer to location to place the pointer for - * return - * - * RETURN: Status - * - * DESCRIPTION: This function is called to get the pointer to an ACPI table. - * - ******************************************************************************/ - -acpi_status -acpi_tb_get_table_ptr(acpi_table_type table_type, - u32 instance, struct acpi_table_header **return_table) -{ - struct acpi_table_desc *table_desc; - u32 i; - - ACPI_FUNCTION_TRACE(tb_get_table_ptr); - - if (table_type > ACPI_TABLE_ID_MAX) { - return_ACPI_STATUS(AE_BAD_PARAMETER); - } - - /* Check for instance out of range of the current table count */ - - if (instance > acpi_gbl_table_lists[table_type].count) { - return_ACPI_STATUS(AE_NOT_EXIST); - } - - /* - * Walk the list to get the desired table - * Note: Instance is one-based - */ - table_desc = acpi_gbl_table_lists[table_type].next; - for (i = 1; i < instance; i++) { - table_desc = table_desc->next; - } - - /* We are now pointing to the requested table's descriptor */ - - *return_table = table_desc->pointer; - return_ACPI_STATUS(AE_OK); -} diff --git a/drivers/acpi/tables/tbgetall.c b/drivers/acpi/tables/tbgetall.c deleted file mode 100644 index ad98211..0000000 --- a/drivers/acpi/tables/tbgetall.c +++ /dev/null @@ -1,311 +0,0 @@ -/****************************************************************************** - * - * Module Name: tbgetall - Get all required ACPI tables - * - *****************************************************************************/ - -/* - * Copyright (C) 2000 - 2006, R. Byron Moore - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions, and the following disclaimer, - * without modification. - * 2. Redistributions in binary form must reproduce at minimum a disclaimer - * substantially similar to the "NO WARRANTY" disclaimer below - * ("Disclaimer") and any redistribution must be conditioned upon - * including a substantially similar Disclaimer requirement for further - * binary redistribution. - * 3. Neither the names of the above-listed copyright holders nor the names - * of any contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * Alternatively, this software may be distributed under the terms of the - * GNU General Public License ("GPL") version 2 as published by the Free - * Software Foundation. - * - * NO WARRANTY - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, - * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING - * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGES. - */ - -#include -#include - -#define _COMPONENT ACPI_TABLES -ACPI_MODULE_NAME("tbgetall") - -/* Local prototypes */ -static acpi_status -acpi_tb_get_primary_table(struct acpi_pointer *address, - struct acpi_table_desc *table_info); - -static acpi_status -acpi_tb_get_secondary_table(struct acpi_pointer *address, - acpi_string signature, - struct acpi_table_desc *table_info); - -/******************************************************************************* - * - * FUNCTION: acpi_tb_get_primary_table - * - * PARAMETERS: Address - Physical address of table to retrieve - * *table_info - Where the table info is returned - * - * RETURN: Status - * - * DESCRIPTION: Maps the physical address of table into a logical address - * - ******************************************************************************/ - -static acpi_status -acpi_tb_get_primary_table(struct acpi_pointer *address, - struct acpi_table_desc *table_info) -{ - acpi_status status; - struct acpi_table_header header; - - ACPI_FUNCTION_TRACE(tb_get_primary_table); - - /* Ignore a NULL address in the RSDT */ - - if (!address->pointer.value) { - return_ACPI_STATUS(AE_OK); - } - - /* Get the header in order to get signature and table size */ - - status = acpi_tb_get_table_header(address, &header); - if (ACPI_FAILURE(status)) { - return_ACPI_STATUS(status); - } - - /* Clear the table_info */ - - ACPI_MEMSET(table_info, 0, sizeof(struct acpi_table_desc)); - - /* - * Check the table signature and make sure it is recognized. - * Also checks the header checksum - */ - table_info->pointer = &header; - status = acpi_tb_recognize_table(table_info, ACPI_TABLE_PRIMARY); - if (ACPI_FAILURE(status)) { - return_ACPI_STATUS(status); - } - - /* Get the entire table */ - - status = acpi_tb_get_table_body(address, &header, table_info); - if (ACPI_FAILURE(status)) { - return_ACPI_STATUS(status); - } - - /* Install the table */ - - status = acpi_tb_install_table(table_info); - return_ACPI_STATUS(status); -} - -/******************************************************************************* - * - * FUNCTION: acpi_tb_get_secondary_table - * - * PARAMETERS: Address - Physical address of table to retrieve - * *table_info - Where the table info is returned - * - * RETURN: Status - * - * DESCRIPTION: Maps the physical address of table into a logical address - * - ******************************************************************************/ - -static acpi_status -acpi_tb_get_secondary_table(struct acpi_pointer *address, - acpi_string signature, - struct acpi_table_desc *table_info) -{ - acpi_status status; - struct acpi_table_header header; - - ACPI_FUNCTION_TRACE_STR(tb_get_secondary_table, signature); - - /* Get the header in order to match the signature */ - - status = acpi_tb_get_table_header(address, &header); - if (ACPI_FAILURE(status)) { - return_ACPI_STATUS(status); - } - - /* Signature must match request */ - - if (!ACPI_COMPARE_NAME(header.signature, signature)) { - ACPI_ERROR((AE_INFO, - "Incorrect table signature - wanted [%s] found [%4.4s]", - signature, header.signature)); - return_ACPI_STATUS(AE_BAD_SIGNATURE); - } - - /* - * Check the table signature and make sure it is recognized. - * Also checks the header checksum - */ - table_info->pointer = &header; - status = acpi_tb_recognize_table(table_info, ACPI_TABLE_SECONDARY); - if (ACPI_FAILURE(status)) { - return_ACPI_STATUS(status); - } - - /* Get the entire table */ - - status = acpi_tb_get_table_body(address, &header, table_info); - if (ACPI_FAILURE(status)) { - return_ACPI_STATUS(status); - } - - /* Install the table */ - - status = acpi_tb_install_table(table_info); - return_ACPI_STATUS(status); -} - -/******************************************************************************* - * - * FUNCTION: acpi_tb_get_required_tables - * - * PARAMETERS: None - * - * RETURN: Status - * - * DESCRIPTION: Load and validate tables other than the RSDT. The RSDT must - * already be loaded and validated. - * - * Get the minimum set of ACPI tables, namely: - * - * 1) FADT (via RSDT in loop below) - * 2) FACS (via FADT) - * 3) DSDT (via FADT) - * - ******************************************************************************/ - -acpi_status acpi_tb_get_required_tables(void) -{ - acpi_status status = AE_OK; - u32 i; - struct acpi_table_desc table_info; - struct acpi_pointer address; - - ACPI_FUNCTION_TRACE(tb_get_required_tables); - - ACPI_DEBUG_PRINT((ACPI_DB_INFO, "%d ACPI tables in RSDT\n", - acpi_gbl_rsdt_table_count)); - - address.pointer_type = acpi_gbl_table_flags | ACPI_LOGICAL_ADDRESSING; - - /* - * Loop through all table pointers found in RSDT. - * This will NOT include the FACS and DSDT - we must get - * them after the loop. - * - * The only tables we are interested in getting here is the FADT and - * any SSDTs. - */ - for (i = 0; i < acpi_gbl_rsdt_table_count; i++) { - - /* Get the table address from the common internal XSDT */ - - address.pointer.value = acpi_gbl_XSDT->table_offset_entry[i]; - - /* - * Get the tables needed by this subsystem (FADT and any SSDTs). - * NOTE: All other tables are completely ignored at this time. - */ - status = acpi_tb_get_primary_table(&address, &table_info); - if ((status != AE_OK) && (status != AE_TABLE_NOT_SUPPORTED)) { - ACPI_WARNING((AE_INFO, - "%s, while getting table at %8.8X%8.8X", - acpi_format_exception(status), - ACPI_FORMAT_UINT64(address.pointer. - value))); - } - } - - /* We must have a FADT to continue */ - - if (!acpi_gbl_FADT) { - ACPI_ERROR((AE_INFO, "No FADT present in RSDT/XSDT")); - return_ACPI_STATUS(AE_NO_ACPI_TABLES); - } - - /* - * Convert the FADT to a common format. This allows earlier revisions of - * the table to coexist with newer versions, using common access code. - */ - status = acpi_tb_convert_table_fadt(); - if (ACPI_FAILURE(status)) { - ACPI_ERROR((AE_INFO, - "Could not convert FADT to internal common format")); - return_ACPI_STATUS(status); - } - - /* Get the FACS (Pointed to by the FADT) */ - - address.pointer.value = acpi_gbl_FADT->xfirmware_ctrl; - - status = acpi_tb_get_secondary_table(&address, FACS_SIG, &table_info); - if (ACPI_FAILURE(status)) { - ACPI_EXCEPTION((AE_INFO, status, - "Could not get/install the FACS")); - return_ACPI_STATUS(status); - } - - /* - * Create the common FACS pointer table - * (Contains pointers to the original table) - */ - status = acpi_tb_build_common_facs(&table_info); - if (ACPI_FAILURE(status)) { - return_ACPI_STATUS(status); - } - - /* Get/install the DSDT (Pointed to by the FADT) */ - - address.pointer.value = acpi_gbl_FADT->Xdsdt; - - status = acpi_tb_get_secondary_table(&address, DSDT_SIG, &table_info); - if (ACPI_FAILURE(status)) { - ACPI_ERROR((AE_INFO, "Could not get/install the DSDT")); - return_ACPI_STATUS(status); - } - - /* Set Integer Width (32/64) based upon DSDT revision */ - - acpi_ut_set_integer_width(acpi_gbl_DSDT->revision); - - /* Dump the entire DSDT */ - - ACPI_DEBUG_PRINT((ACPI_DB_TABLES, - "Hex dump of entire DSDT, size %d (0x%X), Integer width = %d\n", - acpi_gbl_DSDT->length, acpi_gbl_DSDT->length, - acpi_gbl_integer_bit_width)); - - ACPI_DUMP_BUFFER(ACPI_CAST_PTR(u8, acpi_gbl_DSDT), - acpi_gbl_DSDT->length); - - /* Always delete the RSDP mapping, we are done with it */ - - acpi_tb_delete_tables_by_type(ACPI_TABLE_ID_RSDP); - return_ACPI_STATUS(status); -} diff --git a/drivers/acpi/tables/tbinstal.c b/drivers/acpi/tables/tbinstal.c index 1668a23..0e7b121 100644 --- a/drivers/acpi/tables/tbinstal.c +++ b/drivers/acpi/tables/tbinstal.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2006, R. Byron Moore + * Copyright (C) 2000 - 2007, R. Byron Moore * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -42,510 +42,498 @@ */ #include +#include #include #define _COMPONENT ACPI_TABLES ACPI_MODULE_NAME("tbinstal") -/* Local prototypes */ -static acpi_status -acpi_tb_match_signature(char *signature, - struct acpi_table_desc *table_info, u8 search_type); - -/******************************************************************************* +/****************************************************************************** * - * FUNCTION: acpi_tb_match_signature + * FUNCTION: acpi_tb_verify_table * - * PARAMETERS: Signature - Table signature to match - * table_info - Return data - * search_type - Table type to match (primary/secondary) + * PARAMETERS: table_desc - table * * RETURN: Status * - * DESCRIPTION: Compare signature against the list of "ACPI-subsystem-owned" - * tables (DSDT/FADT/SSDT, etc.) Returns the table_type_iD on match. + * DESCRIPTION: this function is called to verify and map table * - ******************************************************************************/ - -static acpi_status -acpi_tb_match_signature(char *signature, - struct acpi_table_desc *table_info, u8 search_type) + *****************************************************************************/ +acpi_status acpi_tb_verify_table(struct acpi_table_desc *table_desc) { - acpi_native_uint i; + acpi_status status = AE_OK; - ACPI_FUNCTION_TRACE(tb_match_signature); + ACPI_FUNCTION_TRACE(tb_verify_table); - /* Search for a signature match among the known table types */ + /* Map the table if necessary */ - for (i = 0; i < (ACPI_TABLE_ID_MAX + 1); i++) { - if (!(acpi_gbl_table_data[i].flags & search_type)) { - continue; + if (!table_desc->pointer) { + if ((table_desc->flags & ACPI_TABLE_ORIGIN_MASK) == + ACPI_TABLE_ORIGIN_MAPPED) { + table_desc->pointer = + acpi_os_map_memory(table_desc->address, + table_desc->length); } + if (!table_desc->pointer) { + return_ACPI_STATUS(AE_NO_MEMORY); + } + } - if (!ACPI_STRNCMP(signature, acpi_gbl_table_data[i].signature, - acpi_gbl_table_data[i].sig_length)) { - - /* Found a signature match, return index if requested */ + /* FACS is the odd table, has no standard ACPI header and no checksum */ - if (table_info) { - table_info->type = (u8) i; - } + if (!ACPI_COMPARE_NAME(&table_desc->signature, ACPI_SIG_FACS)) { - ACPI_DEBUG_PRINT((ACPI_DB_INFO, - "Table [%4.4s] is an ACPI table consumed by the core subsystem\n", - (char *)acpi_gbl_table_data[i]. - signature)); + /* Always calculate checksum, ignore bad checksum if requested */ - return_ACPI_STATUS(AE_OK); - } + status = + acpi_tb_verify_checksum(table_desc->pointer, + table_desc->length); } - ACPI_DEBUG_PRINT((ACPI_DB_INFO, - "Table [%4.4s] is not an ACPI table consumed by the core subsystem - ignored\n", - (char *)signature)); - - return_ACPI_STATUS(AE_TABLE_NOT_SUPPORTED); + return_ACPI_STATUS(status); } /******************************************************************************* * - * FUNCTION: acpi_tb_install_table + * FUNCTION: acpi_tb_add_table * - * PARAMETERS: table_info - Return value from acpi_tb_get_table_body + * PARAMETERS: table_desc - Table descriptor + * table_index - Where the table index is returned * * RETURN: Status * - * DESCRIPTION: Install the table into the global data structures. + * DESCRIPTION: This function is called to add the ACPI table * ******************************************************************************/ -acpi_status acpi_tb_install_table(struct acpi_table_desc *table_info) +acpi_status +acpi_tb_add_table(struct acpi_table_desc *table_desc, + acpi_native_uint * table_index) { - acpi_status status; - - ACPI_FUNCTION_TRACE(tb_install_table); + acpi_native_uint i; + acpi_native_uint length; + acpi_status status = AE_OK; - /* Lock tables while installing */ + ACPI_FUNCTION_TRACE(tb_add_table); - status = acpi_ut_acquire_mutex(ACPI_MTX_TABLES); - if (ACPI_FAILURE(status)) { - ACPI_EXCEPTION((AE_INFO, status, - "Could not acquire table mutex")); - return_ACPI_STATUS(status); + if (!table_desc->pointer) { + status = acpi_tb_verify_table(table_desc); + if (ACPI_FAILURE(status) || !table_desc->pointer) { + return_ACPI_STATUS(status); + } } - /* - * Ignore a table that is already installed. For example, some BIOS - * ASL code will repeatedly attempt to load the same SSDT. - */ - status = acpi_tb_is_table_installed(table_info); - if (ACPI_FAILURE(status)) { - goto unlock_and_exit; + /* The table must be either an SSDT or a PSDT */ + + if ((!ACPI_COMPARE_NAME(table_desc->pointer->signature, ACPI_SIG_PSDT)) + && + (!ACPI_COMPARE_NAME(table_desc->pointer->signature, ACPI_SIG_SSDT))) + { + ACPI_ERROR((AE_INFO, + "Table has invalid signature [%4.4s], must be SSDT or PSDT", + table_desc->pointer->signature)); + return_ACPI_STATUS(AE_BAD_SIGNATURE); } - /* Install the table into the global data structure */ + (void)acpi_ut_acquire_mutex(ACPI_MTX_TABLES); + + /* Check if table is already registered */ + + for (i = 0; i < acpi_gbl_root_table_list.count; ++i) { + if (!acpi_gbl_root_table_list.tables[i].pointer) { + status = + acpi_tb_verify_table(&acpi_gbl_root_table_list. + tables[i]); + if (ACPI_FAILURE(status) + || !acpi_gbl_root_table_list.tables[i].pointer) { + continue; + } + } + + length = ACPI_MIN(table_desc->length, + acpi_gbl_root_table_list.tables[i].length); + if (ACPI_MEMCMP(table_desc->pointer, + acpi_gbl_root_table_list.tables[i].pointer, + length)) { + continue; + } + + /* Table is already registered */ + + acpi_tb_delete_table(table_desc); + *table_index = i; + goto release; + } - status = acpi_tb_init_table_descriptor(table_info->type, table_info); + /* + * Add the table to the global table list + */ + status = acpi_tb_store_table(table_desc->address, table_desc->pointer, + table_desc->length, table_desc->flags, + table_index); if (ACPI_FAILURE(status)) { - ACPI_EXCEPTION((AE_INFO, status, - "Could not install table [%4.4s]", - table_info->pointer->signature)); + goto release; } - ACPI_DEBUG_PRINT((ACPI_DB_INFO, "%s located at %p\n", - acpi_gbl_table_data[table_info->type].name, - table_info->pointer)); + acpi_tb_print_table_header(table_desc->address, table_desc->pointer); - unlock_and_exit: + release: (void)acpi_ut_release_mutex(ACPI_MTX_TABLES); return_ACPI_STATUS(status); } /******************************************************************************* * - * FUNCTION: acpi_tb_recognize_table + * FUNCTION: acpi_tb_resize_root_table_list * - * PARAMETERS: table_info - Return value from acpi_tb_get_table_body - * search_type - Table type to match (primary/secondary) + * PARAMETERS: None * * RETURN: Status * - * DESCRIPTION: Check a table signature for a match against known table types - * - * NOTE: All table pointers are validated as follows: - * 1) Table pointer must point to valid physical memory - * 2) Signature must be 4 ASCII chars, even if we don't recognize the - * name - * 3) Table must be readable for length specified in the header - * 4) Table checksum must be valid (with the exception of the FACS - * which has no checksum for some odd reason) + * DESCRIPTION: Expand the size of global table array * ******************************************************************************/ -acpi_status -acpi_tb_recognize_table(struct acpi_table_desc *table_info, u8 search_type) +acpi_status acpi_tb_resize_root_table_list(void) { - struct acpi_table_header *table_header; - acpi_status status; + struct acpi_table_desc *tables; - ACPI_FUNCTION_TRACE(tb_recognize_table); + ACPI_FUNCTION_TRACE(tb_resize_root_table_list); - /* Ensure that we have a valid table pointer */ + /* allow_resize flag is a parameter to acpi_initialize_tables */ - table_header = (struct acpi_table_header *)table_info->pointer; - if (!table_header) { - return_ACPI_STATUS(AE_BAD_PARAMETER); + if (!(acpi_gbl_root_table_list.flags & ACPI_ROOT_ALLOW_RESIZE)) { + ACPI_ERROR((AE_INFO, + "Resize of Root Table Array is not allowed")); + return_ACPI_STATUS(AE_SUPPORT); } - /* - * We only "recognize" a limited number of ACPI tables -- namely, the - * ones that are used by the subsystem (DSDT, FADT, etc.) - * - * An AE_TABLE_NOT_SUPPORTED means that the table was not recognized. - * This can be any one of many valid ACPI tables, it just isn't one of - * the tables that is consumed by the core subsystem - */ - status = acpi_tb_match_signature(table_header->signature, - table_info, search_type); - if (ACPI_FAILURE(status)) { - return_ACPI_STATUS(status); + /* Increase the Table Array size */ + + tables = ACPI_ALLOCATE_ZEROED((acpi_gbl_root_table_list.size + + ACPI_ROOT_TABLE_SIZE_INCREMENT) + * sizeof(struct acpi_table_desc)); + if (!tables) { + ACPI_ERROR((AE_INFO, + "Could not allocate new root table array")); + return_ACPI_STATUS(AE_NO_MEMORY); } - status = acpi_tb_validate_table_header(table_header); - if (ACPI_FAILURE(status)) { - return_ACPI_STATUS(status); + /* Copy and free the previous table array */ + + if (acpi_gbl_root_table_list.tables) { + ACPI_MEMCPY(tables, acpi_gbl_root_table_list.tables, + acpi_gbl_root_table_list.size * + sizeof(struct acpi_table_desc)); + + if (acpi_gbl_root_table_list.flags & ACPI_ROOT_ORIGIN_ALLOCATED) { + ACPI_FREE(acpi_gbl_root_table_list.tables); + } } - /* Return the table type and length via the info struct */ + acpi_gbl_root_table_list.tables = tables; + acpi_gbl_root_table_list.size += ACPI_ROOT_TABLE_SIZE_INCREMENT; + acpi_gbl_root_table_list.flags |= (u8) ACPI_ROOT_ORIGIN_ALLOCATED; - table_info->length = (acpi_size) table_header->length; - return_ACPI_STATUS(status); + return_ACPI_STATUS(AE_OK); } /******************************************************************************* * - * FUNCTION: acpi_tb_init_table_descriptor + * FUNCTION: acpi_tb_store_table * - * PARAMETERS: table_type - The type of the table - * table_info - A table info struct + * PARAMETERS: Address - Table address + * Table - Table header + * Length - Table length + * Flags - flags * - * RETURN: None. + * RETURN: Status and table index. * - * DESCRIPTION: Install a table into the global data structs. + * DESCRIPTION: Add an ACPI table to the global table list * ******************************************************************************/ acpi_status -acpi_tb_init_table_descriptor(acpi_table_type table_type, - struct acpi_table_desc *table_info) +acpi_tb_store_table(acpi_physical_address address, + struct acpi_table_header *table, + u32 length, u8 flags, acpi_native_uint * table_index) { - struct acpi_table_list *list_head; - struct acpi_table_desc *table_desc; - acpi_status status; - - ACPI_FUNCTION_TRACE_U32(tb_init_table_descriptor, table_type); + acpi_status status = AE_OK; - /* Allocate a descriptor for this table */ + /* Ensure that there is room for the table in the Root Table List */ - table_desc = ACPI_ALLOCATE_ZEROED(sizeof(struct acpi_table_desc)); - if (!table_desc) { - return_ACPI_STATUS(AE_NO_MEMORY); + if (acpi_gbl_root_table_list.count >= acpi_gbl_root_table_list.size) { + status = acpi_tb_resize_root_table_list(); + if (ACPI_FAILURE(status)) { + return (status); + } } - /* Get a new owner ID for the table */ + /* Initialize added table */ + + acpi_gbl_root_table_list.tables[acpi_gbl_root_table_list.count]. + address = address; + acpi_gbl_root_table_list.tables[acpi_gbl_root_table_list.count]. + pointer = table; + acpi_gbl_root_table_list.tables[acpi_gbl_root_table_list.count].length = + length; + acpi_gbl_root_table_list.tables[acpi_gbl_root_table_list.count]. + owner_id = 0; + acpi_gbl_root_table_list.tables[acpi_gbl_root_table_list.count].flags = + flags; + + ACPI_MOVE_32_TO_32(& + (acpi_gbl_root_table_list. + tables[acpi_gbl_root_table_list.count].signature), + table->signature); + + *table_index = acpi_gbl_root_table_list.count; + acpi_gbl_root_table_list.count++; + return (status); +} - status = acpi_ut_allocate_owner_id(&table_desc->owner_id); - if (ACPI_FAILURE(status)) { - goto error_exit1; - } +/******************************************************************************* + * + * FUNCTION: acpi_tb_delete_table + * + * PARAMETERS: table_index - Table index + * + * RETURN: None + * + * DESCRIPTION: Delete one internal ACPI table + * + ******************************************************************************/ - /* Install the table into the global data structure */ +void acpi_tb_delete_table(struct acpi_table_desc *table_desc) +{ + /* Table must be mapped or allocated */ + if (!table_desc->pointer) { + return; + } + switch (table_desc->flags & ACPI_TABLE_ORIGIN_MASK) { + case ACPI_TABLE_ORIGIN_MAPPED: + acpi_os_unmap_memory(table_desc->pointer, table_desc->length); + break; + case ACPI_TABLE_ORIGIN_ALLOCATED: + ACPI_FREE(table_desc->pointer); + break; + default:; + } - list_head = &acpi_gbl_table_lists[table_type]; + table_desc->pointer = NULL; +} - /* - * Two major types of tables: 1) Only one instance is allowed. This - * includes most ACPI tables such as the DSDT. 2) Multiple instances of - * the table are allowed. This includes SSDT and PSDTs. - */ - if (ACPI_IS_SINGLE_TABLE(acpi_gbl_table_data[table_type].flags)) { - /* - * Only one table allowed, and a table has alread been installed - * at this location, so return an error. - */ - if (list_head->next) { - status = AE_ALREADY_EXISTS; - goto error_exit2; - } +/******************************************************************************* + * + * FUNCTION: acpi_tb_terminate + * + * PARAMETERS: None + * + * RETURN: None + * + * DESCRIPTION: Delete all internal ACPI tables + * + ******************************************************************************/ - table_desc->next = list_head->next; - list_head->next = table_desc; +void acpi_tb_terminate(void) +{ + acpi_native_uint i; - if (table_desc->next) { - table_desc->next->prev = table_desc; - } + ACPI_FUNCTION_TRACE(tb_terminate); - list_head->count++; - } else { - /* - * Link the new table in to the list of tables of this type. - * Insert at the end of the list, order IS IMPORTANT. - * - * table_desc->Prev & Next are already NULL from calloc() - */ - list_head->count++; - - if (!list_head->next) { - list_head->next = table_desc; - } else { - table_desc->next = list_head->next; + (void)acpi_ut_acquire_mutex(ACPI_MTX_TABLES); - while (table_desc->next->next) { - table_desc->next = table_desc->next->next; - } + /* Delete the individual tables */ - table_desc->next->next = table_desc; - table_desc->prev = table_desc->next; - table_desc->next = NULL; - } + for (i = 0; i < acpi_gbl_root_table_list.count; ++i) { + acpi_tb_delete_table(&acpi_gbl_root_table_list.tables[i]); } - /* Finish initialization of the table descriptor */ - - table_desc->loaded_into_namespace = FALSE; - table_desc->type = (u8) table_type; - table_desc->pointer = table_info->pointer; - table_desc->length = table_info->length; - table_desc->allocation = table_info->allocation; - table_desc->aml_start = (u8 *) (table_desc->pointer + 1), - table_desc->aml_length = (u32) - (table_desc->length - (u32) sizeof(struct acpi_table_header)); - /* - * Set the appropriate global pointer (if there is one) to point to the - * newly installed table + * Delete the root table array if allocated locally. Array cannot be + * mapped, so we don't need to check for that flag. */ - if (acpi_gbl_table_data[table_type].global_ptr) { - *(acpi_gbl_table_data[table_type].global_ptr) = - table_info->pointer; + if (acpi_gbl_root_table_list.flags & ACPI_ROOT_ORIGIN_ALLOCATED) { + ACPI_FREE(acpi_gbl_root_table_list.tables); } - /* Return Data */ - - table_info->owner_id = table_desc->owner_id; - table_info->installed_desc = table_desc; - return_ACPI_STATUS(AE_OK); - - /* Error exit with cleanup */ - - error_exit2: - - acpi_ut_release_owner_id(&table_desc->owner_id); + acpi_gbl_root_table_list.tables = NULL; + acpi_gbl_root_table_list.flags = 0; + acpi_gbl_root_table_list.count = 0; - error_exit1: - - ACPI_FREE(table_desc); - return_ACPI_STATUS(status); + ACPI_DEBUG_PRINT((ACPI_DB_INFO, "ACPI Tables freed\n")); + (void)acpi_ut_release_mutex(ACPI_MTX_TABLES); } /******************************************************************************* * - * FUNCTION: acpi_tb_delete_all_tables + * FUNCTION: acpi_tb_delete_namespace_by_owner * - * PARAMETERS: None. + * PARAMETERS: table_index - Table index * - * RETURN: None. + * RETURN: None * - * DESCRIPTION: Delete all internal ACPI tables + * DESCRIPTION: Delete all namespace objects created when this table was loaded. * ******************************************************************************/ -void acpi_tb_delete_all_tables(void) +void acpi_tb_delete_namespace_by_owner(acpi_native_uint table_index) { - acpi_table_type type; + acpi_owner_id owner_id; - /* - * Free memory allocated for ACPI tables - * Memory can either be mapped or allocated - */ - for (type = 0; type < (ACPI_TABLE_ID_MAX + 1); type++) { - acpi_tb_delete_tables_by_type(type); + (void)acpi_ut_acquire_mutex(ACPI_MTX_TABLES); + if (table_index < acpi_gbl_root_table_list.count) { + owner_id = + acpi_gbl_root_table_list.tables[table_index].owner_id; + } else { + (void)acpi_ut_release_mutex(ACPI_MTX_TABLES); + return; } + + (void)acpi_ut_release_mutex(ACPI_MTX_TABLES); + acpi_ns_delete_namespace_by_owner(owner_id); } /******************************************************************************* * - * FUNCTION: acpi_tb_delete_tables_by_type + * FUNCTION: acpi_tb_allocate_owner_id * - * PARAMETERS: Type - The table type to be deleted + * PARAMETERS: table_index - Table index * - * RETURN: None. + * RETURN: Status * - * DESCRIPTION: Delete an internal ACPI table - * Locks the ACPI table mutex + * DESCRIPTION: Allocates owner_id in table_desc * ******************************************************************************/ -void acpi_tb_delete_tables_by_type(acpi_table_type type) +acpi_status acpi_tb_allocate_owner_id(acpi_native_uint table_index) { - struct acpi_table_desc *table_desc; - u32 count; - u32 i; + acpi_status status = AE_BAD_PARAMETER; - ACPI_FUNCTION_TRACE_U32(tb_delete_tables_by_type, type); + ACPI_FUNCTION_TRACE(tb_allocate_owner_id); - if (type > ACPI_TABLE_ID_MAX) { - return_VOID; - } - - if (ACPI_FAILURE(acpi_ut_acquire_mutex(ACPI_MTX_TABLES))) { - return; - } - - /* Clear the appropriate "typed" global table pointer */ - - switch (type) { - case ACPI_TABLE_ID_RSDP: - acpi_gbl_RSDP = NULL; - break; - - case ACPI_TABLE_ID_DSDT: - acpi_gbl_DSDT = NULL; - break; - - case ACPI_TABLE_ID_FADT: - acpi_gbl_FADT = NULL; - break; - - case ACPI_TABLE_ID_FACS: - acpi_gbl_FACS = NULL; - break; - - case ACPI_TABLE_ID_XSDT: - acpi_gbl_XSDT = NULL; - break; - - case ACPI_TABLE_ID_SSDT: - case ACPI_TABLE_ID_PSDT: - default: - break; - } - - /* - * Free the table - * 1) Get the head of the list - */ - table_desc = acpi_gbl_table_lists[type].next; - count = acpi_gbl_table_lists[type].count; - - /* - * 2) Walk the entire list, deleting both the allocated tables - * and the table descriptors - */ - for (i = 0; i < count; i++) { - table_desc = acpi_tb_uninstall_table(table_desc); + (void)acpi_ut_acquire_mutex(ACPI_MTX_TABLES); + if (table_index < acpi_gbl_root_table_list.count) { + status = acpi_ut_allocate_owner_id + (&(acpi_gbl_root_table_list.tables[table_index].owner_id)); } (void)acpi_ut_release_mutex(ACPI_MTX_TABLES); - return_VOID; + return_ACPI_STATUS(status); } /******************************************************************************* * - * FUNCTION: acpi_tb_delete_single_table + * FUNCTION: acpi_tb_release_owner_id * - * PARAMETERS: table_info - A table info struct + * PARAMETERS: table_index - Table index * - * RETURN: None. + * RETURN: Status * - * DESCRIPTION: Low-level free for a single ACPI table. Handles cases where - * the table was allocated a buffer or was mapped. + * DESCRIPTION: Releases owner_id in table_desc * ******************************************************************************/ -void acpi_tb_delete_single_table(struct acpi_table_desc *table_desc) +acpi_status acpi_tb_release_owner_id(acpi_native_uint table_index) { + acpi_status status = AE_BAD_PARAMETER; - /* Must have a valid table descriptor and pointer */ + ACPI_FUNCTION_TRACE(tb_release_owner_id); - if ((!table_desc) || (!table_desc->pointer)) { - return; + (void)acpi_ut_acquire_mutex(ACPI_MTX_TABLES); + if (table_index < acpi_gbl_root_table_list.count) { + acpi_ut_release_owner_id(& + (acpi_gbl_root_table_list. + tables[table_index].owner_id)); + status = AE_OK; } - /* Valid table, determine type of memory allocation */ - - switch (table_desc->allocation) { - case ACPI_MEM_NOT_ALLOCATED: - break; - - case ACPI_MEM_ALLOCATED: - - ACPI_FREE(table_desc->pointer); - break; - - case ACPI_MEM_MAPPED: - - acpi_os_unmap_memory(table_desc->pointer, table_desc->length); - break; - - default: - break; - } + (void)acpi_ut_release_mutex(ACPI_MTX_TABLES); + return_ACPI_STATUS(status); } /******************************************************************************* * - * FUNCTION: acpi_tb_uninstall_table + * FUNCTION: acpi_tb_get_owner_id * - * PARAMETERS: table_info - A table info struct + * PARAMETERS: table_index - Table index + * owner_id - Where the table owner_id is returned * - * RETURN: Pointer to the next table in the list (of same type) + * RETURN: Status * - * DESCRIPTION: Free the memory associated with an internal ACPI table that - * is either installed or has never been installed. - * Table mutex should be locked. + * DESCRIPTION: returns owner_id for the ACPI table * ******************************************************************************/ -struct acpi_table_desc *acpi_tb_uninstall_table(struct acpi_table_desc - *table_desc) +acpi_status +acpi_tb_get_owner_id(acpi_native_uint table_index, acpi_owner_id * owner_id) { - struct acpi_table_desc *next_desc; + acpi_status status = AE_BAD_PARAMETER; - ACPI_FUNCTION_TRACE_PTR(tb_uninstall_table, table_desc); + ACPI_FUNCTION_TRACE(tb_get_owner_id); - if (!table_desc) { - return_PTR(NULL); + (void)acpi_ut_acquire_mutex(ACPI_MTX_TABLES); + if (table_index < acpi_gbl_root_table_list.count) { + *owner_id = + acpi_gbl_root_table_list.tables[table_index].owner_id; + status = AE_OK; } - /* Unlink the descriptor from the doubly linked list */ + (void)acpi_ut_release_mutex(ACPI_MTX_TABLES); + return_ACPI_STATUS(status); +} - if (table_desc->prev) { - table_desc->prev->next = table_desc->next; - } else { - /* Is first on list, update list head */ +/******************************************************************************* + * + * FUNCTION: acpi_tb_is_table_loaded + * + * PARAMETERS: table_index - Table index + * + * RETURN: Table Loaded Flag + * + ******************************************************************************/ - acpi_gbl_table_lists[table_desc->type].next = table_desc->next; - } +u8 acpi_tb_is_table_loaded(acpi_native_uint table_index) +{ + u8 is_loaded = FALSE; - if (table_desc->next) { - table_desc->next->prev = table_desc->prev; + (void)acpi_ut_acquire_mutex(ACPI_MTX_TABLES); + if (table_index < acpi_gbl_root_table_list.count) { + is_loaded = (u8) + (acpi_gbl_root_table_list.tables[table_index]. + flags & ACPI_TABLE_IS_LOADED); } - /* Free the memory allocated for the table itself */ - - acpi_tb_delete_single_table(table_desc); - - /* Free the owner ID associated with this table */ - - acpi_ut_release_owner_id(&table_desc->owner_id); + (void)acpi_ut_release_mutex(ACPI_MTX_TABLES); + return (is_loaded); +} - /* Free the table descriptor */ +/******************************************************************************* + * + * FUNCTION: acpi_tb_set_table_loaded_flag + * + * PARAMETERS: table_index - Table index + * is_loaded - TRUE if table is loaded, FALSE otherwise + * + * RETURN: None + * + * DESCRIPTION: Sets the table loaded flag to either TRUE or FALSE. + * + ******************************************************************************/ - next_desc = table_desc->next; - ACPI_FREE(table_desc); +void acpi_tb_set_table_loaded_flag(acpi_native_uint table_index, u8 is_loaded) +{ - /* Return pointer to the next descriptor */ + (void)acpi_ut_acquire_mutex(ACPI_MTX_TABLES); + if (table_index < acpi_gbl_root_table_list.count) { + if (is_loaded) { + acpi_gbl_root_table_list.tables[table_index].flags |= + ACPI_TABLE_IS_LOADED; + } else { + acpi_gbl_root_table_list.tables[table_index].flags &= + ~ACPI_TABLE_IS_LOADED; + } + } - return_PTR(next_desc); + (void)acpi_ut_release_mutex(ACPI_MTX_TABLES); } diff --git a/drivers/acpi/tables/tbrsdt.c b/drivers/acpi/tables/tbrsdt.c deleted file mode 100644 index 86a5fca..0000000 --- a/drivers/acpi/tables/tbrsdt.c +++ /dev/null @@ -1,307 +0,0 @@ -/****************************************************************************** - * - * Module Name: tbrsdt - ACPI RSDT table utilities - * - *****************************************************************************/ - -/* - * Copyright (C) 2000 - 2006, R. Byron Moore - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions, and the following disclaimer, - * without modification. - * 2. Redistributions in binary form must reproduce at minimum a disclaimer - * substantially similar to the "NO WARRANTY" disclaimer below - * ("Disclaimer") and any redistribution must be conditioned upon - * including a substantially similar Disclaimer requirement for further - * binary redistribution. - * 3. Neither the names of the above-listed copyright holders nor the names - * of any contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * Alternatively, this software may be distributed under the terms of the - * GNU General Public License ("GPL") version 2 as published by the Free - * Software Foundation. - * - * NO WARRANTY - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, - * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING - * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGES. - */ - -#include -#include - -#define _COMPONENT ACPI_TABLES -ACPI_MODULE_NAME("tbrsdt") - -/******************************************************************************* - * - * FUNCTION: acpi_tb_verify_rsdp - * - * PARAMETERS: Address - RSDP (Pointer to RSDT) - * - * RETURN: Status - * - * DESCRIPTION: Load and validate the RSDP (ptr) and RSDT (table) - * - ******************************************************************************/ -acpi_status acpi_tb_verify_rsdp(struct acpi_pointer *address) -{ - struct acpi_table_desc table_info; - acpi_status status; - struct rsdp_descriptor *rsdp; - - ACPI_FUNCTION_TRACE(tb_verify_rsdp); - - switch (address->pointer_type) { - case ACPI_LOGICAL_POINTER: - - rsdp = address->pointer.logical; - break; - - case ACPI_PHYSICAL_POINTER: - /* - * Obtain access to the RSDP structure - */ - status = acpi_os_map_memory(address->pointer.physical, - sizeof(struct rsdp_descriptor), - ACPI_CAST_PTR(void, &rsdp)); - if (ACPI_FAILURE(status)) { - return_ACPI_STATUS(status); - } - break; - - default: - return_ACPI_STATUS(AE_BAD_PARAMETER); - } - - /* Verify RSDP signature and checksum */ - - status = acpi_tb_validate_rsdp(rsdp); - if (ACPI_FAILURE(status)) { - goto cleanup; - } - - /* RSDP is ok. Init the table info */ - - table_info.pointer = ACPI_CAST_PTR(struct acpi_table_header, rsdp); - table_info.length = sizeof(struct rsdp_descriptor); - - if (address->pointer_type == ACPI_PHYSICAL_POINTER) { - table_info.allocation = ACPI_MEM_MAPPED; - } else { - table_info.allocation = ACPI_MEM_NOT_ALLOCATED; - } - - /* Save the table pointers and allocation info */ - - status = acpi_tb_init_table_descriptor(ACPI_TABLE_ID_RSDP, &table_info); - if (ACPI_FAILURE(status)) { - goto cleanup; - } - - /* Save the RSDP in a global for easy access */ - - acpi_gbl_RSDP = - ACPI_CAST_PTR(struct rsdp_descriptor, table_info.pointer); - return_ACPI_STATUS(status); - - /* Error exit */ - cleanup: - - if (acpi_gbl_table_flags & ACPI_PHYSICAL_POINTER) { - acpi_os_unmap_memory(rsdp, sizeof(struct rsdp_descriptor)); - } - return_ACPI_STATUS(status); -} - -/******************************************************************************* - * - * FUNCTION: acpi_tb_get_rsdt_address - * - * PARAMETERS: out_address - Where the address is returned - * - * RETURN: None, Address - * - * DESCRIPTION: Extract the address of either the RSDT or XSDT, depending on the - * version of the RSDP and whether the XSDT pointer is valid - * - ******************************************************************************/ - -void acpi_tb_get_rsdt_address(struct acpi_pointer *out_address) -{ - - ACPI_FUNCTION_ENTRY(); - - out_address->pointer_type = - acpi_gbl_table_flags | ACPI_LOGICAL_ADDRESSING; - - /* Use XSDT if it is present */ - - if ((acpi_gbl_RSDP->revision >= 2) && - acpi_gbl_RSDP->xsdt_physical_address) { - out_address->pointer.value = - acpi_gbl_RSDP->xsdt_physical_address; - acpi_gbl_root_table_type = ACPI_TABLE_TYPE_XSDT; - } else { - /* No XSDT, use the RSDT */ - - out_address->pointer.value = - acpi_gbl_RSDP->rsdt_physical_address; - acpi_gbl_root_table_type = ACPI_TABLE_TYPE_RSDT; - } -} - -/******************************************************************************* - * - * FUNCTION: acpi_tb_validate_rsdt - * - * PARAMETERS: table_ptr - Addressable pointer to the RSDT. - * - * RETURN: Status - * - * DESCRIPTION: Validate signature for the RSDT or XSDT - * - ******************************************************************************/ - -acpi_status acpi_tb_validate_rsdt(struct acpi_table_header *table_ptr) -{ - char *signature; - - ACPI_FUNCTION_ENTRY(); - - /* Validate minimum length */ - - if (table_ptr->length < sizeof(struct acpi_table_header)) { - ACPI_ERROR((AE_INFO, - "RSDT/XSDT length (%X) is smaller than minimum (%zX)", - table_ptr->length, - sizeof(struct acpi_table_header))); - - return (AE_INVALID_TABLE_LENGTH); - } - - /* Search for appropriate signature, RSDT or XSDT */ - - if (acpi_gbl_root_table_type == ACPI_TABLE_TYPE_RSDT) { - signature = RSDT_SIG; - } else { - signature = XSDT_SIG; - } - - if (!ACPI_COMPARE_NAME(table_ptr->signature, signature)) { - - /* Invalid RSDT or XSDT signature */ - - ACPI_ERROR((AE_INFO, - "Invalid signature where RSDP indicates RSDT/XSDT should be located. RSDP:")); - - ACPI_DUMP_BUFFER(acpi_gbl_RSDP, 20); - - ACPI_ERROR((AE_INFO, - "RSDT/XSDT signature at %X is invalid", - acpi_gbl_RSDP->rsdt_physical_address)); - - if (acpi_gbl_root_table_type == ACPI_TABLE_TYPE_RSDT) { - ACPI_ERROR((AE_INFO, "Looking for RSDT")); - } else { - ACPI_ERROR((AE_INFO, "Looking for XSDT")); - } - - ACPI_DUMP_BUFFER(ACPI_CAST_PTR(char, table_ptr), 48); - return (AE_BAD_SIGNATURE); - } - - return (AE_OK); -} - -/******************************************************************************* - * - * FUNCTION: acpi_tb_get_table_rsdt - * - * PARAMETERS: None - * - * RETURN: Status - * - * DESCRIPTION: Load and validate the RSDP (ptr) and RSDT (table) - * - ******************************************************************************/ - -acpi_status acpi_tb_get_table_rsdt(void) -{ - struct acpi_table_desc table_info; - acpi_status status; - struct acpi_pointer address; - - ACPI_FUNCTION_TRACE(tb_get_table_rsdt); - - /* Get the RSDT/XSDT via the RSDP */ - - acpi_tb_get_rsdt_address(&address); - - table_info.type = ACPI_TABLE_ID_XSDT; - status = acpi_tb_get_table(&address, &table_info); - if (ACPI_FAILURE(status)) { - ACPI_EXCEPTION((AE_INFO, status, - "Could not get the RSDT/XSDT")); - return_ACPI_STATUS(status); - } - - ACPI_DEBUG_PRINT((ACPI_DB_INFO, - "RSDP located at %p, points to RSDT physical=%8.8X%8.8X\n", - acpi_gbl_RSDP, - ACPI_FORMAT_UINT64(address.pointer.value))); - - /* Check the RSDT or XSDT signature */ - - status = acpi_tb_validate_rsdt(table_info.pointer); - if (ACPI_FAILURE(status)) { - goto error_cleanup; - } - - /* Get the number of tables defined in the RSDT or XSDT */ - - acpi_gbl_rsdt_table_count = acpi_tb_get_table_count(acpi_gbl_RSDP, - table_info.pointer); - - /* Convert and/or copy to an XSDT structure */ - - status = acpi_tb_convert_to_xsdt(&table_info); - if (ACPI_FAILURE(status)) { - goto error_cleanup; - } - - /* Save the table pointers and allocation info */ - - status = acpi_tb_init_table_descriptor(ACPI_TABLE_ID_XSDT, &table_info); - if (ACPI_FAILURE(status)) { - goto error_cleanup; - } - - acpi_gbl_XSDT = - ACPI_CAST_PTR(struct xsdt_descriptor, table_info.pointer); - - ACPI_DEBUG_PRINT((ACPI_DB_INFO, "XSDT located at %p\n", acpi_gbl_XSDT)); - return_ACPI_STATUS(status); - - error_cleanup: - - /* Free table allocated by acpi_tb_get_table */ - - acpi_tb_delete_single_table(&table_info); - - return_ACPI_STATUS(status); -} diff --git a/drivers/acpi/tables/tbutils.c b/drivers/acpi/tables/tbutils.c index 209a401..1da64b4 100644 --- a/drivers/acpi/tables/tbutils.c +++ b/drivers/acpi/tables/tbutils.c @@ -1,11 +1,11 @@ /****************************************************************************** * - * Module Name: tbutils - Table manipulation utilities + * Module Name: tbutils - table utilities * *****************************************************************************/ /* - * Copyright (C) 2000 - 2006, R. Byron Moore + * Copyright (C) 2000 - 2007, R. Byron Moore * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -48,137 +48,119 @@ #define _COMPONENT ACPI_TABLES ACPI_MODULE_NAME("tbutils") /* Local prototypes */ -#ifdef ACPI_OBSOLETE_FUNCTIONS -acpi_status -acpi_tb_handle_to_object(u16 table_id, struct acpi_table_desc **table_desc); -#endif +static acpi_physical_address +acpi_tb_get_root_table_entry(u8 * table_entry, + acpi_native_uint table_entry_size); /******************************************************************************* * - * FUNCTION: acpi_tb_is_table_installed - * - * PARAMETERS: new_table_desc - Descriptor for new table being installed + * FUNCTION: acpi_tb_tables_loaded * - * RETURN: Status - AE_ALREADY_EXISTS if the table is already installed + * PARAMETERS: None * - * DESCRIPTION: Determine if an ACPI table is already installed + * RETURN: TRUE if required ACPI tables are loaded * - * MUTEX: Table data structures should be locked + * DESCRIPTION: Determine if the minimum required ACPI tables are present + * (FADT, FACS, DSDT) * ******************************************************************************/ -acpi_status acpi_tb_is_table_installed(struct acpi_table_desc *new_table_desc) +u8 acpi_tb_tables_loaded(void) { - struct acpi_table_desc *table_desc; - - ACPI_FUNCTION_TRACE(tb_is_table_installed); - /* Get the list descriptor and first table descriptor */ - - table_desc = acpi_gbl_table_lists[new_table_desc->type].next; + if (acpi_gbl_root_table_list.count >= 3) { + return (TRUE); + } - /* Examine all installed tables of this type */ + return (FALSE); +} - while (table_desc) { - /* - * If the table lengths match, perform a full bytewise compare. This - * means that we will allow tables with duplicate oem_table_id(s), as - * long as the tables are different in some way. - * - * Checking if the table has been loaded into the namespace means that - * we don't check for duplicate tables during the initial installation - * of tables within the RSDT/XSDT. - */ - if ((table_desc->loaded_into_namespace) && - (table_desc->pointer->length == - new_table_desc->pointer->length) - && - (!ACPI_MEMCMP - (table_desc->pointer, new_table_desc->pointer, - new_table_desc->pointer->length))) { - - /* Match: this table is already installed */ - - ACPI_DEBUG_PRINT((ACPI_DB_TABLES, - "Table [%4.4s] already installed: Rev %X OemTableId [%8.8s]\n", - new_table_desc->pointer->signature, - new_table_desc->pointer->revision, - new_table_desc->pointer-> - oem_table_id)); - - new_table_desc->owner_id = table_desc->owner_id; - new_table_desc->installed_desc = table_desc; - - return_ACPI_STATUS(AE_ALREADY_EXISTS); - } +/******************************************************************************* + * + * FUNCTION: acpi_tb_print_table_header + * + * PARAMETERS: Address - Table physical address + * Header - Table header + * + * RETURN: None + * + * DESCRIPTION: Print an ACPI table header. Special cases for FACS and RSDP. + * + ******************************************************************************/ - /* Get next table on the list */ +void +acpi_tb_print_table_header(acpi_physical_address address, + struct acpi_table_header *header) +{ - table_desc = table_desc->next; + if (ACPI_COMPARE_NAME(header->signature, ACPI_SIG_FACS)) { + + /* FACS only has signature and length fields of common table header */ + + ACPI_INFO((AE_INFO, "%4.4s %08lX, %04X", + header->signature, (unsigned long)address, + header->length)); + } else if (ACPI_COMPARE_NAME(header->signature, ACPI_SIG_RSDP)) { + + /* RSDP has no common fields */ + + ACPI_INFO((AE_INFO, "RSDP %08lX, %04X (r%d %6.6s)", + (unsigned long)address, + (ACPI_CAST_PTR(struct acpi_table_rsdp, header)-> + revision > + 0) ? ACPI_CAST_PTR(struct acpi_table_rsdp, + header)->length : 20, + ACPI_CAST_PTR(struct acpi_table_rsdp, + header)->revision, + ACPI_CAST_PTR(struct acpi_table_rsdp, + header)->oem_id)); + } else { + /* Standard ACPI table with full common header */ + + ACPI_INFO((AE_INFO, + "%4.4s %08lX, %04X (r%d %6.6s %8.8s %8X %4.4s %8X)", + header->signature, (unsigned long)address, + header->length, header->revision, header->oem_id, + header->oem_table_id, header->oem_revision, + header->asl_compiler_id, + header->asl_compiler_revision)); } - - return_ACPI_STATUS(AE_OK); } /******************************************************************************* * - * FUNCTION: acpi_tb_validate_table_header + * FUNCTION: acpi_tb_validate_checksum * - * PARAMETERS: table_header - Logical pointer to the table + * PARAMETERS: Table - ACPI table to verify + * Length - Length of entire table * * RETURN: Status * - * DESCRIPTION: Check an ACPI table header for validity - * - * NOTE: Table pointers are validated as follows: - * 1) Table pointer must point to valid physical memory - * 2) Signature must be 4 ASCII chars, even if we don't recognize the - * name - * 3) Table must be readable for length specified in the header - * 4) Table checksum must be valid (with the exception of the FACS - * which has no checksum because it contains variable fields) + * DESCRIPTION: Verifies that the table checksums to zero. Optionally returns + * exception on bad checksum. * ******************************************************************************/ -acpi_status -acpi_tb_validate_table_header(struct acpi_table_header *table_header) +acpi_status acpi_tb_verify_checksum(struct acpi_table_header *table, u32 length) { - acpi_name signature; - - ACPI_FUNCTION_ENTRY(); - - /* Verify that this is a valid address */ - - if (!acpi_os_readable(table_header, sizeof(struct acpi_table_header))) { - ACPI_ERROR((AE_INFO, - "Cannot read table header at %p", table_header)); - - return (AE_BAD_ADDRESS); - } + u8 checksum; - /* Ensure that the signature is 4 ASCII characters */ + /* Compute the checksum on the table */ - ACPI_MOVE_32_TO_32(&signature, table_header->signature); - if (!acpi_ut_valid_acpi_name(signature)) { - ACPI_ERROR((AE_INFO, "Invalid table signature 0x%8.8X", - signature)); + checksum = acpi_tb_checksum(ACPI_CAST_PTR(u8, table), length); - ACPI_DUMP_BUFFER(table_header, - sizeof(struct acpi_table_header)); - return (AE_BAD_SIGNATURE); - } + /* Checksum ok? (should be zero) */ - /* Validate the table length */ + if (checksum) { + ACPI_WARNING((AE_INFO, + "Incorrect checksum in table [%4.4s] - %2.2X, should be %2.2X", + table->signature, table->checksum, + (u8) (table->checksum - checksum))); - if (table_header->length < sizeof(struct acpi_table_header)) { - ACPI_ERROR((AE_INFO, - "Invalid length 0x%X in table with signature %4.4s", - (u32) table_header->length, - ACPI_CAST_PTR(char, &signature))); +#if (ACPI_CHECKSUM_ABORT) - ACPI_DUMP_BUFFER(table_header, - sizeof(struct acpi_table_header)); - return (AE_BAD_HEADER); + return (AE_BAD_CHECKSUM); +#endif } return (AE_OK); @@ -186,157 +168,320 @@ acpi_tb_validate_table_header(struct acp /******************************************************************************* * - * FUNCTION: acpi_tb_sum_table + * FUNCTION: acpi_tb_checksum * - * PARAMETERS: Buffer - Buffer to sum - * Length - Size of the buffer + * PARAMETERS: Buffer - Pointer to memory region to be checked + * Length - Length of this memory region * - * RETURN: 8 bit sum of buffer + * RETURN: Checksum (u8) * - * DESCRIPTION: Computes an 8 bit sum of the buffer(length) and returns it. + * DESCRIPTION: Calculates circular checksum of memory region. * ******************************************************************************/ -u8 acpi_tb_sum_table(void *buffer, u32 length) +u8 acpi_tb_checksum(u8 * buffer, acpi_native_uint length) { - acpi_native_uint i; u8 sum = 0; + u8 *end = buffer + length; - if (!buffer || !length) { - return (0); + while (buffer < end) { + sum = (u8) (sum + *(buffer++)); } - for (i = 0; i < length; i++) { - sum = (u8) (sum + ((u8 *) buffer)[i]); - } - return (sum); + return sum; } /******************************************************************************* * - * FUNCTION: acpi_tb_generate_checksum + * FUNCTION: acpi_tb_install_table * - * PARAMETERS: Table - Pointer to a valid ACPI table (with a - * standard ACPI header) + * PARAMETERS: Address - Physical address of DSDT or FACS + * Flags - Flags + * Signature - Table signature, NULL if no need to + * match + * table_index - Index into root table array * - * RETURN: 8 bit checksum of buffer + * RETURN: None * - * DESCRIPTION: Computes an 8 bit checksum of the table. + * DESCRIPTION: Install an ACPI table into the global data structure. * ******************************************************************************/ -u8 acpi_tb_generate_checksum(struct acpi_table_header * table) +void +acpi_tb_install_table(acpi_physical_address address, + u8 flags, char *signature, acpi_native_uint table_index) { - u8 checksum; + struct acpi_table_header *table; + + if (!address) { + ACPI_ERROR((AE_INFO, + "Null physical address for ACPI table [%s]", + signature)); + return; + } + + /* Map just the table header */ + + table = acpi_os_map_memory(address, sizeof(struct acpi_table_header)); + if (!table) { + return; + } + + /* If a particular signature is expected, signature must match */ + + if (signature && !ACPI_COMPARE_NAME(table->signature, signature)) { + ACPI_ERROR((AE_INFO, + "Invalid signature 0x%X for ACPI table [%s]", + *ACPI_CAST_PTR(u32, table->signature), signature)); + goto unmap_and_exit; + } - /* Sum the entire table as-is */ + /* Initialize the table entry */ - checksum = acpi_tb_sum_table(table, table->length); + acpi_gbl_root_table_list.tables[table_index].address = address; + acpi_gbl_root_table_list.tables[table_index].length = table->length; + acpi_gbl_root_table_list.tables[table_index].flags = flags; - /* Subtract off the existing checksum value in the table */ + ACPI_MOVE_32_TO_32(& + (acpi_gbl_root_table_list.tables[table_index]. + signature), table->signature); - checksum = (u8) (checksum - table->checksum); + acpi_tb_print_table_header(address, table); - /* Compute the final checksum */ + if (table_index == ACPI_TABLE_INDEX_DSDT) { - checksum = (u8) (0 - checksum); - return (checksum); + /* Global integer width is based upon revision of the DSDT */ + + acpi_ut_set_integer_width(table->revision); + } + + unmap_and_exit: + acpi_os_unmap_memory(table, sizeof(struct acpi_table_header)); } /******************************************************************************* * - * FUNCTION: acpi_tb_set_checksum + * FUNCTION: acpi_tb_get_root_table_entry * - * PARAMETERS: Table - Pointer to a valid ACPI table (with a - * standard ACPI header) + * PARAMETERS: table_entry - Pointer to the RSDT/XSDT table entry + * table_entry_size - sizeof 32 or 64 (RSDT or XSDT) * - * RETURN: None. Sets the table checksum field + * RETURN: Physical address extracted from the root table * - * DESCRIPTION: Computes an 8 bit checksum of the table and inserts the - * checksum into the table header. + * DESCRIPTION: Get one root table entry. Handles 32-bit and 64-bit cases on + * both 32-bit and 64-bit platforms + * + * NOTE: acpi_physical_address is 32-bit on 32-bit platforms, 64-bit on + * 64-bit platforms. * ******************************************************************************/ -void acpi_tb_set_checksum(struct acpi_table_header *table) +static acpi_physical_address +acpi_tb_get_root_table_entry(u8 * table_entry, + acpi_native_uint table_entry_size) { + u64 address64; + + /* + * Get the table physical address (32-bit for RSDT, 64-bit for XSDT): + * Note: Addresses are 32-bit aligned (not 64) in both RSDT and XSDT + */ + if (table_entry_size == sizeof(u32)) { + /* + * 32-bit platform, RSDT: Return 32-bit table entry + * 64-bit platform, RSDT: Expand 32-bit to 64-bit and return + */ + return ((acpi_physical_address) + (*ACPI_CAST_PTR(u32, table_entry))); + } else { + /* + * 32-bit platform, XSDT: Truncate 64-bit to 32-bit and return + * 64-bit platform, XSDT: Move (unaligned) 64-bit to local, return 64-bit + */ + ACPI_MOVE_64_TO_64(&address64, table_entry); - table->checksum = acpi_tb_generate_checksum(table); +#if ACPI_MACHINE_WIDTH == 32 + if (address64 > ACPI_UINT32_MAX) { + + /* Will truncate 64-bit address to 32 bits, issue warning */ + + ACPI_WARNING((AE_INFO, + "64-bit Physical Address in XSDT is too large (%8.8X%8.8X), truncating", + ACPI_FORMAT_UINT64(address64))); + } +#endif + return ((acpi_physical_address) (address64)); + } } /******************************************************************************* * - * FUNCTION: acpi_tb_verify_table_checksum + * FUNCTION: acpi_tb_parse_root_table + * + * PARAMETERS: Rsdp - Pointer to the RSDP + * Flags - Flags * - * PARAMETERS: *table_header - ACPI table to verify + * RETURN: Status * - * RETURN: 8 bit checksum of table + * DESCRIPTION: This function is called to parse the Root System Description + * Table (RSDT or XSDT) * - * DESCRIPTION: Generates an 8 bit checksum of table and returns and compares - * it to the existing checksum value. + * NOTE: Tables are mapped (not copied) for efficiency. The FACS must + * be mapped and cannot be copied because it contains the actual + * memory location of the ACPI Global Lock. * ******************************************************************************/ -acpi_status -acpi_tb_verify_table_checksum(struct acpi_table_header *table_header) +acpi_status __init +acpi_tb_parse_root_table(acpi_physical_address rsdp_address, u8 flags) { - u8 checksum; + struct acpi_table_rsdp *rsdp; + acpi_native_uint table_entry_size; + acpi_native_uint i; + u32 table_count; + struct acpi_table_header *table; + acpi_physical_address address; + u32 length; + u8 *table_entry; + acpi_status status; + + ACPI_FUNCTION_TRACE(tb_parse_root_table); + + /* + * Map the entire RSDP and extract the address of the RSDT or XSDT + */ + rsdp = acpi_os_map_memory(rsdp_address, sizeof(struct acpi_table_rsdp)); + if (!rsdp) { + return_ACPI_STATUS(AE_NO_MEMORY); + } - ACPI_FUNCTION_TRACE(tb_verify_table_checksum); + acpi_tb_print_table_header(rsdp_address, + ACPI_CAST_PTR(struct acpi_table_header, + rsdp)); - /* Compute the checksum on the table */ + /* Differentiate between RSDT and XSDT root tables */ - checksum = acpi_tb_generate_checksum(table_header); + if (rsdp->revision > 1 && rsdp->xsdt_physical_address) { + /* + * Root table is an XSDT (64-bit physical addresses). We must use the + * XSDT if the revision is > 1 and the XSDT pointer is present, as per + * the ACPI specification. + */ + address = (acpi_physical_address) rsdp->xsdt_physical_address; + table_entry_size = sizeof(u64); + } else { + /* Root table is an RSDT (32-bit physical addresses) */ - /* Checksum ok? */ + address = (acpi_physical_address) rsdp->rsdt_physical_address; + table_entry_size = sizeof(u32); + } - if (checksum == table_header->checksum) { - return_ACPI_STATUS(AE_OK); + /* + * It is not possible to map more than one entry in some environments, + * so unmap the RSDP here before mapping other tables + */ + acpi_os_unmap_memory(rsdp, sizeof(struct acpi_table_rsdp)); + + /* Map the RSDT/XSDT table header to get the full table length */ + + table = acpi_os_map_memory(address, sizeof(struct acpi_table_header)); + if (!table) { + return_ACPI_STATUS(AE_NO_MEMORY); } - ACPI_WARNING((AE_INFO, - "Incorrect checksum in table [%4.4s] - is %2.2X, should be %2.2X", - table_header->signature, table_header->checksum, - checksum)); + acpi_tb_print_table_header(address, table); - return_ACPI_STATUS(AE_BAD_CHECKSUM); -} + /* Get the length of the full table, verify length and map entire table */ -#ifdef ACPI_OBSOLETE_FUNCTIONS -/******************************************************************************* - * - * FUNCTION: acpi_tb_handle_to_object - * - * PARAMETERS: table_id - Id for which the function is searching - * table_desc - Pointer to return the matching table - * descriptor. - * - * RETURN: Search the tables to find one with a matching table_id and - * return a pointer to that table descriptor. - * - ******************************************************************************/ + length = table->length; + acpi_os_unmap_memory(table, sizeof(struct acpi_table_header)); -acpi_status -acpi_tb_handle_to_object(u16 table_id, - struct acpi_table_desc **return_table_desc) -{ - u32 i; - struct acpi_table_desc *table_desc; + if (length < sizeof(struct acpi_table_header)) { + ACPI_ERROR((AE_INFO, "Invalid length 0x%X in RSDT/XSDT", + length)); + return_ACPI_STATUS(AE_INVALID_TABLE_LENGTH); + } - ACPI_FUNCTION_NAME(tb_handle_to_object); + table = acpi_os_map_memory(address, length); + if (!table) { + return_ACPI_STATUS(AE_NO_MEMORY); + } + + /* Validate the root table checksum */ + + status = acpi_tb_verify_checksum(table, length); + if (ACPI_FAILURE(status)) { + acpi_os_unmap_memory(table, length); + return_ACPI_STATUS(status); + } - for (i = 0; i < ACPI_TABLE_MAX; i++) { - table_desc = acpi_gbl_table_lists[i].next; - while (table_desc) { - if (table_desc->table_id == table_id) { - *return_table_desc = table_desc; - return (AE_OK); + /* Calculate the number of tables described in the root table */ + + table_count = + (u32) ((table->length - + sizeof(struct acpi_table_header)) / table_entry_size); + + /* + * First two entries in the table array are reserved for the DSDT and FACS, + * which are not actually present in the RSDT/XSDT - they come from the FADT + */ + table_entry = + ACPI_CAST_PTR(u8, table) + sizeof(struct acpi_table_header); + acpi_gbl_root_table_list.count = 2; + + /* + * Initialize the root table array from the RSDT/XSDT + */ + for (i = 0; i < table_count; i++) { + if (acpi_gbl_root_table_list.count >= + acpi_gbl_root_table_list.size) { + + /* There is no more room in the root table array, attempt resize */ + + status = acpi_tb_resize_root_table_list(); + if (ACPI_FAILURE(status)) { + ACPI_WARNING((AE_INFO, + "Truncating %u table entries!", + (unsigned) + (acpi_gbl_root_table_list.size - + acpi_gbl_root_table_list. + count))); + break; } + } + + /* Get the table physical address (32-bit for RSDT, 64-bit for XSDT) */ - table_desc = table_desc->next; + acpi_gbl_root_table_list.tables[acpi_gbl_root_table_list.count]. + address = + acpi_tb_get_root_table_entry(table_entry, table_entry_size); + + table_entry += table_entry_size; + acpi_gbl_root_table_list.count++; + } + + /* + * It is not possible to map more than one entry in some environments, + * so unmap the root table here before mapping other tables + */ + acpi_os_unmap_memory(table, length); + + /* + * Complete the initialization of the root table array by examining + * the header of each table + */ + for (i = 2; i < acpi_gbl_root_table_list.count; i++) { + acpi_tb_install_table(acpi_gbl_root_table_list.tables[i]. + address, flags, NULL, i); + + /* Special case for FADT - get the DSDT and FACS */ + + if (ACPI_COMPARE_NAME + (&acpi_gbl_root_table_list.tables[i].signature, + ACPI_SIG_FADT)) { + acpi_tb_parse_fadt(i, flags); } } - ACPI_ERROR((AE_INFO, "TableId=%X does not exist", table_id)); - return (AE_BAD_PARAMETER); + return_ACPI_STATUS(AE_OK); } -#endif diff --git a/drivers/acpi/tables/tbxface.c b/drivers/acpi/tables/tbxface.c index 5ba9303..807978d 100644 --- a/drivers/acpi/tables/tbxface.c +++ b/drivers/acpi/tables/tbxface.c @@ -6,7 +6,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2006, R. Byron Moore + * Copyright (C) 2000 - 2007, R. Byron Moore * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -49,80 +49,158 @@ #include #define _COMPONENT ACPI_TABLES ACPI_MODULE_NAME("tbxface") +/* Local prototypes */ +static acpi_status acpi_tb_load_namespace(void); + /******************************************************************************* * - * FUNCTION: acpi_load_tables + * FUNCTION: acpi_allocate_root_table * - * PARAMETERS: None + * PARAMETERS: initial_table_count - Size of initial_table_array, in number of + * struct acpi_table_desc structures * * RETURN: Status * - * DESCRIPTION: This function is called to load the ACPI tables from the - * provided RSDT + * DESCRIPTION: Allocate a root table array. Used by i_aSL compiler and + * acpi_initialize_tables. * ******************************************************************************/ -acpi_status acpi_load_tables(void) + +acpi_status acpi_allocate_root_table(u32 initial_table_count) { - struct acpi_pointer rsdp_address; - acpi_status status; - ACPI_FUNCTION_TRACE(acpi_load_tables); + acpi_gbl_root_table_list.size = initial_table_count; + acpi_gbl_root_table_list.flags = ACPI_ROOT_ALLOW_RESIZE; - /* Get the RSDP */ + return (acpi_tb_resize_root_table_list()); +} - status = acpi_os_get_root_pointer(ACPI_LOGICAL_ADDRESSING, - &rsdp_address); - if (ACPI_FAILURE(status)) { - ACPI_EXCEPTION((AE_INFO, status, "Could not get the RSDP")); - goto error_exit; - } +/******************************************************************************* + * + * FUNCTION: acpi_initialize_tables + * + * PARAMETERS: initial_table_array - Pointer to an array of pre-allocated + * struct acpi_table_desc structures. If NULL, the + * array is dynamically allocated. + * initial_table_count - Size of initial_table_array, in number of + * struct acpi_table_desc structures + * allow_realloc - Flag to tell Table Manager if resize of + * pre-allocated array is allowed. Ignored + * if initial_table_array is NULL. + * + * RETURN: Status + * + * DESCRIPTION: Initialize the table manager, get the RSDP and RSDT/XSDT. + * + * NOTE: Allows static allocation of the initial table array in order + * to avoid the use of dynamic memory in confined environments + * such as the kernel boot sequence where it may not be available. + * + * If the host OS memory managers are initialized, use NULL for + * initial_table_array, and the table will be dynamically allocated. + * + ******************************************************************************/ - /* Map and validate the RSDP */ +acpi_status __init +acpi_initialize_tables(struct acpi_table_desc * initial_table_array, + u32 initial_table_count, u8 allow_resize) +{ + acpi_physical_address rsdp_address; + acpi_status status; - acpi_gbl_table_flags = rsdp_address.pointer_type; + ACPI_FUNCTION_TRACE(acpi_initialize_tables); - status = acpi_tb_verify_rsdp(&rsdp_address); - if (ACPI_FAILURE(status)) { - ACPI_EXCEPTION((AE_INFO, status, "During RSDP validation")); - goto error_exit; + /* + * Set up the Root Table Array + * Allocate the table array if requested + */ + if (!initial_table_array) { + status = acpi_allocate_root_table(initial_table_count); + if (ACPI_FAILURE(status)) { + return_ACPI_STATUS(status); + } + } else { + /* Root Table Array has been statically allocated by the host */ + + ACPI_MEMSET(initial_table_array, 0, + initial_table_count * + sizeof(struct acpi_table_desc)); + + acpi_gbl_root_table_list.tables = initial_table_array; + acpi_gbl_root_table_list.size = initial_table_count; + acpi_gbl_root_table_list.flags = ACPI_ROOT_ORIGIN_UNKNOWN; + if (allow_resize) { + acpi_gbl_root_table_list.flags |= + ACPI_ROOT_ALLOW_RESIZE; + } } - /* Get the RSDT via the RSDP */ + /* Get the address of the RSDP */ - status = acpi_tb_get_table_rsdt(); - if (ACPI_FAILURE(status)) { - ACPI_EXCEPTION((AE_INFO, status, "Could not load RSDT")); - goto error_exit; + rsdp_address = acpi_os_get_root_pointer(); + if (!rsdp_address) { + return_ACPI_STATUS(AE_NOT_FOUND); } - /* Now get the tables needed by this subsystem (FADT, DSDT, etc.) */ + /* + * Get the root table (RSDT or XSDT) and extract all entries to the local + * Root Table Array. This array contains the information of the RSDT/XSDT + * in a common, more useable format. + */ + status = + acpi_tb_parse_root_table(rsdp_address, ACPI_TABLE_ORIGIN_MAPPED); + return_ACPI_STATUS(status); +} - status = acpi_tb_get_required_tables(); - if (ACPI_FAILURE(status)) { - ACPI_EXCEPTION((AE_INFO, status, - "Could not get all required tables (DSDT/FADT/FACS)")); - goto error_exit; +/******************************************************************************* + * + * FUNCTION: acpi_reallocate_root_table + * + * PARAMETERS: None + * + * RETURN: Status + * + * DESCRIPTION: Reallocate Root Table List into dynamic memory. Copies the + * root list from the previously provided scratch area. Should + * be called once dynamic memory allocation is available in the + * kernel + * + ******************************************************************************/ +acpi_status acpi_reallocate_root_table(void) +{ + struct acpi_table_desc *tables; + acpi_size new_size; + + ACPI_FUNCTION_TRACE(acpi_reallocate_root_table); + + /* + * Only reallocate the root table if the host provided a static buffer + * for the table array in the call to acpi_initialize_tables. + */ + if (acpi_gbl_root_table_list.flags & ACPI_ROOT_ORIGIN_ALLOCATED) { + return_ACPI_STATUS(AE_SUPPORT); } - ACPI_DEBUG_PRINT((ACPI_DB_INIT, "ACPI Tables successfully acquired\n")); + new_size = + (acpi_gbl_root_table_list.count + + ACPI_ROOT_TABLE_SIZE_INCREMENT) * sizeof(struct acpi_table_desc); - /* Load the namespace from the tables */ + /* Create new array and copy the old array */ - status = acpi_ns_load_namespace(); - if (ACPI_FAILURE(status)) { - ACPI_EXCEPTION((AE_INFO, status, "Could not load namespace")); - goto error_exit; + tables = ACPI_ALLOCATE_ZEROED(new_size); + if (!tables) { + return_ACPI_STATUS(AE_NO_MEMORY); } - return_ACPI_STATUS(AE_OK); + ACPI_MEMCPY(tables, acpi_gbl_root_table_list.tables, new_size); - error_exit: - ACPI_EXCEPTION((AE_INFO, status, "Could not load tables")); - return_ACPI_STATUS(status); -} - -ACPI_EXPORT_SYMBOL(acpi_load_tables) + acpi_gbl_root_table_list.size = acpi_gbl_root_table_list.count; + acpi_gbl_root_table_list.tables = tables; + acpi_gbl_root_table_list.flags = + ACPI_ROOT_ORIGIN_ALLOCATED | ACPI_ROOT_ALLOW_RESIZE; + return_ACPI_STATUS(AE_OK); +} /******************************************************************************* * * FUNCTION: acpi_load_table @@ -141,342 +219,405 @@ ACPI_EXPORT_SYMBOL(acpi_load_tables) acpi_status acpi_load_table(struct acpi_table_header *table_ptr) { acpi_status status; - struct acpi_table_desc table_info; - struct acpi_pointer address; - - ACPI_FUNCTION_TRACE(acpi_load_table); - - if (!table_ptr) { - return_ACPI_STATUS(AE_BAD_PARAMETER); - } - - /* Copy the table to a local buffer */ + acpi_native_uint table_index; + struct acpi_table_desc table_desc; - address.pointer_type = ACPI_LOGICAL_POINTER | ACPI_LOGICAL_ADDRESSING; - address.pointer.logical = table_ptr; - - status = acpi_tb_get_table_body(&address, table_ptr, &table_info); - if (ACPI_FAILURE(status)) { - return_ACPI_STATUS(status); - } - - /* Check signature for a valid table type */ - - status = acpi_tb_recognize_table(&table_info, ACPI_TABLE_ALL); - if (ACPI_FAILURE(status)) { - return_ACPI_STATUS(status); - } + if (!table_ptr) + return AE_BAD_PARAMETER; - /* Install the new table into the local data structures */ + ACPI_MEMSET(&table_desc, 0, sizeof(struct acpi_table_desc)); + table_desc.pointer = table_ptr; + table_desc.length = table_ptr->length; + table_desc.flags = ACPI_TABLE_ORIGIN_UNKNOWN; - status = acpi_tb_install_table(&table_info); + /* + * Install the new table into the local data structures + */ + status = acpi_tb_add_table(&table_desc, &table_index); if (ACPI_FAILURE(status)) { - if (status == AE_ALREADY_EXISTS) { - - /* Table already exists, no error */ - - status = AE_OK; - } - - /* Free table allocated by acpi_tb_get_table_body */ - - acpi_tb_delete_single_table(&table_info); - return_ACPI_STATUS(status); + return status; } + status = acpi_ns_load_table(table_index, acpi_gbl_root_node); + return status; +} - /* Convert the table to common format if necessary */ - - switch (table_info.type) { - case ACPI_TABLE_ID_FADT: - - status = acpi_tb_convert_table_fadt(); - break; - - case ACPI_TABLE_ID_FACS: +ACPI_EXPORT_SYMBOL(acpi_load_table) - status = acpi_tb_build_common_facs(&table_info); - break; +/****************************************************************************** + * + * FUNCTION: acpi_get_table_header + * + * PARAMETERS: Signature - ACPI signature of needed table + * Instance - Which instance (for SSDTs) + * out_table_header - The pointer to the table header to fill + * + * RETURN: Status and pointer to mapped table header + * + * DESCRIPTION: Finds an ACPI table header. + * + * NOTE: Caller is responsible in unmapping the header with + * acpi_os_unmap_memory + * + *****************************************************************************/ +acpi_status +acpi_get_table_header(char *signature, + acpi_native_uint instance, + struct acpi_table_header *out_table_header) +{ + acpi_native_uint i; + acpi_native_uint j; + struct acpi_table_header *header; - default: - /* Load table into namespace if it contains executable AML */ + /* Parameter validation */ - status = - acpi_ns_load_table(table_info.installed_desc, - acpi_gbl_root_node); - break; + if (!signature || !out_table_header) { + return (AE_BAD_PARAMETER); } - if (ACPI_FAILURE(status)) { + /* + * Walk the root table list + */ + for (i = 0, j = 0; i < acpi_gbl_root_table_list.count; i++) { + if (!ACPI_COMPARE_NAME + (&(acpi_gbl_root_table_list.tables[i].signature), + signature)) { + continue; + } - /* Uninstall table and free the buffer */ + if (++j < instance) { + continue; + } - (void)acpi_tb_uninstall_table(table_info.installed_desc); + if (!acpi_gbl_root_table_list.tables[i].pointer) { + if ((acpi_gbl_root_table_list.tables[i]. + flags & ACPI_TABLE_ORIGIN_MASK) == + ACPI_TABLE_ORIGIN_MAPPED) { + header = + acpi_os_map_memory(acpi_gbl_root_table_list. + tables[i].address, + sizeof(struct + acpi_table_header)); + if (!header) { + return AE_NO_MEMORY; + } + ACPI_MEMCPY(out_table_header, header, + sizeof(struct acpi_table_header)); + acpi_os_unmap_memory(header, + sizeof(struct + acpi_table_header)); + } else { + return AE_NOT_FOUND; + } + } else { + ACPI_MEMCPY(out_table_header, + acpi_gbl_root_table_list.tables[i].pointer, + sizeof(struct acpi_table_header)); + } + return (AE_OK); } - return_ACPI_STATUS(status); + return (AE_NOT_FOUND); } -ACPI_EXPORT_SYMBOL(acpi_load_table) +ACPI_EXPORT_SYMBOL(acpi_get_table_header) -/******************************************************************************* + +/****************************************************************************** * * FUNCTION: acpi_unload_table_id * - * PARAMETERS: table_type - Type of table to be unloaded - * id - Owner ID of the table to be removed. + * PARAMETERS: id - Owner ID of the table to be removed. * * RETURN: Status * * DESCRIPTION: This routine is used to force the unload of a table (by id) * ******************************************************************************/ -acpi_status acpi_unload_table_id(acpi_table_type table_type, acpi_owner_id id) +acpi_status acpi_unload_table_id(acpi_owner_id id) { - struct acpi_table_desc *table_desc; - acpi_status status; + int i; + acpi_status status = AE_NOT_EXIST; ACPI_FUNCTION_TRACE(acpi_unload_table); - /* Parameter validation */ - if (table_type > ACPI_TABLE_ID_MAX) - return_ACPI_STATUS(AE_BAD_PARAMETER); - /* Find table from the requested type list */ - table_desc = acpi_gbl_table_lists[table_type].next; - while (table_desc && table_desc->owner_id != id) - table_desc = table_desc->next; - - if (!table_desc) - return_ACPI_STATUS(AE_NOT_EXIST); - - /* - * Delete all namespace objects owned by this table. Note that these - * objects can appear anywhere in the namespace by virtue of the AML - * "Scope" operator. Thus, we need to track ownership by an ID, not - * simply a position within the hierarchy - */ - acpi_ns_delete_namespace_by_owner(table_desc->owner_id); - - status = acpi_ut_acquire_mutex(ACPI_MTX_TABLES); - if (ACPI_FAILURE(status)) - return_ACPI_STATUS(status); - - (void)acpi_tb_uninstall_table(table_desc); - - (void)acpi_ut_release_mutex(ACPI_MTX_TABLES); - - return_ACPI_STATUS(AE_OK); + for (i = 0; i < acpi_gbl_root_table_list.count; ++i) { + if (id != acpi_gbl_root_table_list.tables[i].owner_id) { + continue; + } + /* + * Delete all namespace objects owned by this table. Note that these + * objects can appear anywhere in the namespace by virtue of the AML + * "Scope" operator. Thus, we need to track ownership by an ID, not + * simply a position within the hierarchy + */ + acpi_tb_delete_namespace_by_owner(i); + acpi_tb_release_owner_id(i); + acpi_tb_set_table_loaded_flag(i, FALSE); + } + return_ACPI_STATUS(status); } ACPI_EXPORT_SYMBOL(acpi_unload_table_id) -#ifdef ACPI_FUTURE_USAGE /******************************************************************************* * - * FUNCTION: acpi_unload_table + * FUNCTION: acpi_get_table * - * PARAMETERS: table_type - Type of table to be unloaded + * PARAMETERS: Signature - ACPI signature of needed table + * Instance - Which instance (for SSDTs) + * out_table - Where the pointer to the table is returned * - * RETURN: Status + * RETURN: Status and pointer to table * - * DESCRIPTION: This routine is used to force the unload of a table + * DESCRIPTION: Finds and verifies an ACPI table. * - ******************************************************************************/ -acpi_status acpi_unload_table(acpi_table_type table_type) + *****************************************************************************/ +acpi_status +acpi_get_table(char *signature, + acpi_native_uint instance, struct acpi_table_header ** out_table) { - struct acpi_table_desc *table_desc; - - ACPI_FUNCTION_TRACE(acpi_unload_table); + acpi_native_uint i; + acpi_native_uint j; + acpi_status status; /* Parameter validation */ - if (table_type > ACPI_TABLE_ID_MAX) { - return_ACPI_STATUS(AE_BAD_PARAMETER); + if (!signature || !out_table) { + return (AE_BAD_PARAMETER); } - /* Find all tables of the requested type */ + /* + * Walk the root table list + */ + for (i = 0, j = 0; i < acpi_gbl_root_table_list.count; i++) { + if (!ACPI_COMPARE_NAME + (&(acpi_gbl_root_table_list.tables[i].signature), + signature)) { + continue; + } - table_desc = acpi_gbl_table_lists[table_type].next; - if (!table_desc) { - return_ACPI_STATUS(AE_NOT_EXIST); - } + if (++j < instance) { + continue; + } - while (table_desc) { - /* - * Delete all namespace objects owned by this table. Note that these - * objects can appear anywhere in the namespace by virtue of the AML - * "Scope" operator. Thus, we need to track ownership by an ID, not - * simply a position within the hierarchy - */ - acpi_ns_delete_namespace_by_owner(table_desc->owner_id); - table_desc = table_desc->next; - } + status = + acpi_tb_verify_table(&acpi_gbl_root_table_list.tables[i]); + if (ACPI_SUCCESS(status)) { + *out_table = acpi_gbl_root_table_list.tables[i].pointer; + } - /* Delete (or unmap) all tables of this type */ + if (!acpi_gbl_permanent_mmap) { + acpi_gbl_root_table_list.tables[i].pointer = 0; + } - acpi_tb_delete_tables_by_type(table_type); - return_ACPI_STATUS(AE_OK); + return (status); + } + + return (AE_NOT_FOUND); } -ACPI_EXPORT_SYMBOL(acpi_unload_table) +ACPI_EXPORT_SYMBOL(acpi_get_table) /******************************************************************************* * - * FUNCTION: acpi_get_table_header + * FUNCTION: acpi_get_table_by_index * - * PARAMETERS: table_type - one of the defined table types - * Instance - the non zero instance of the table, allows - * support for multiple tables of the same type - * see acpi_gbl_acpi_table_flag - * out_table_header - pointer to the struct acpi_table_header if successful + * PARAMETERS: table_index - Table index + * Table - Where the pointer to the table is returned * - * DESCRIPTION: This function is called to get an ACPI table header. The caller - * supplies an pointer to a data area sufficient to contain an ACPI - * struct acpi_table_header structure. + * RETURN: Status and pointer to the table * - * The header contains a length field that can be used to determine - * the size of the buffer needed to contain the entire table. This - * function is not valid for the RSD PTR table since it does not - * have a standard header and is fixed length. + * DESCRIPTION: Obtain a table by an index into the global table list. * ******************************************************************************/ acpi_status -acpi_get_table_header(acpi_table_type table_type, - u32 instance, struct acpi_table_header *out_table_header) +acpi_get_table_by_index(acpi_native_uint table_index, + struct acpi_table_header ** table) { - struct acpi_table_header *tbl_ptr; acpi_status status; - ACPI_FUNCTION_TRACE(acpi_get_table_header); + ACPI_FUNCTION_TRACE(acpi_get_table_by_index); + + /* Parameter validation */ - if ((instance == 0) || - (table_type == ACPI_TABLE_ID_RSDP) || (!out_table_header)) { + if (!table) { return_ACPI_STATUS(AE_BAD_PARAMETER); } - /* Check the table type and instance */ + (void)acpi_ut_acquire_mutex(ACPI_MTX_TABLES); + + /* Validate index */ - if ((table_type > ACPI_TABLE_ID_MAX) || - (ACPI_IS_SINGLE_TABLE(acpi_gbl_table_data[table_type].flags) && - instance > 1)) { + if (table_index >= acpi_gbl_root_table_list.count) { + (void)acpi_ut_release_mutex(ACPI_MTX_TABLES); return_ACPI_STATUS(AE_BAD_PARAMETER); } - /* Get a pointer to the entire table */ + if (!acpi_gbl_root_table_list.tables[table_index].pointer) { - status = acpi_tb_get_table_ptr(table_type, instance, &tbl_ptr); - if (ACPI_FAILURE(status)) { - return_ACPI_STATUS(status); - } + /* Table is not mapped, map it */ - /* The function will return a NULL pointer if the table is not loaded */ - - if (tbl_ptr == NULL) { - return_ACPI_STATUS(AE_NOT_EXIST); + status = + acpi_tb_verify_table(&acpi_gbl_root_table_list. + tables[table_index]); + if (ACPI_FAILURE(status)) { + (void)acpi_ut_release_mutex(ACPI_MTX_TABLES); + return_ACPI_STATUS(status); + } } - /* Copy the header to the caller's buffer */ - - ACPI_MEMCPY(ACPI_CAST_PTR(void, out_table_header), - ACPI_CAST_PTR(void, tbl_ptr), - sizeof(struct acpi_table_header)); - - return_ACPI_STATUS(status); + *table = acpi_gbl_root_table_list.tables[table_index].pointer; + (void)acpi_ut_release_mutex(ACPI_MTX_TABLES); + return_ACPI_STATUS(AE_OK); } -ACPI_EXPORT_SYMBOL(acpi_get_table_header) -#endif /* ACPI_FUTURE_USAGE */ +ACPI_EXPORT_SYMBOL(acpi_get_table_by_index) /******************************************************************************* * - * FUNCTION: acpi_get_table + * FUNCTION: acpi_tb_load_namespace * - * PARAMETERS: table_type - one of the defined table types - * Instance - the non zero instance of the table, allows - * support for multiple tables of the same type - * see acpi_gbl_acpi_table_flag - * ret_buffer - pointer to a structure containing a buffer to - * receive the table + * PARAMETERS: None * * RETURN: Status * - * DESCRIPTION: This function is called to get an ACPI table. The caller - * supplies an out_buffer large enough to contain the entire ACPI - * table. The caller should call the acpi_get_table_header function - * first to determine the buffer size needed. Upon completion - * the out_buffer->Length field will indicate the number of bytes - * copied into the out_buffer->buf_ptr buffer. This table will be - * a complete table including the header. + * DESCRIPTION: Load the namespace from the DSDT and all SSDTs/PSDTs found in + * the RSDT/XSDT. * ******************************************************************************/ -acpi_status -acpi_get_table(acpi_table_type table_type, - u32 instance, struct acpi_buffer *ret_buffer) +static acpi_status acpi_tb_load_namespace(void) { - struct acpi_table_header *tbl_ptr; acpi_status status; - acpi_size table_length; + struct acpi_table_header *table; + acpi_native_uint i; - ACPI_FUNCTION_TRACE(acpi_get_table); + ACPI_FUNCTION_TRACE(tb_load_namespace); - /* Parameter validation */ + (void)acpi_ut_acquire_mutex(ACPI_MTX_TABLES); - if (instance == 0) { - return_ACPI_STATUS(AE_BAD_PARAMETER); + /* + * Load the namespace. The DSDT is required, but any SSDT and PSDT tables + * are optional. + */ + if (!acpi_gbl_root_table_list.count || + !ACPI_COMPARE_NAME(& + (acpi_gbl_root_table_list. + tables[ACPI_TABLE_INDEX_DSDT].signature), + ACPI_SIG_DSDT) + || + ACPI_FAILURE(acpi_tb_verify_table + (&acpi_gbl_root_table_list. + tables[ACPI_TABLE_INDEX_DSDT]))) { + status = AE_NO_ACPI_TABLES; + goto unlock_and_exit; } - status = acpi_ut_validate_buffer(ret_buffer); - if (ACPI_FAILURE(status)) { - return_ACPI_STATUS(status); + /* + * Find DSDT table + */ + status = + acpi_os_table_override(acpi_gbl_root_table_list. + tables[ACPI_TABLE_INDEX_DSDT].pointer, + &table); + if (ACPI_SUCCESS(status) && table) { + /* + * DSDT table has been found + */ + acpi_tb_delete_table(&acpi_gbl_root_table_list. + tables[ACPI_TABLE_INDEX_DSDT]); + acpi_gbl_root_table_list.tables[ACPI_TABLE_INDEX_DSDT].pointer = + table; + acpi_gbl_root_table_list.tables[ACPI_TABLE_INDEX_DSDT].length = + table->length; + acpi_gbl_root_table_list.tables[ACPI_TABLE_INDEX_DSDT].flags = + ACPI_TABLE_ORIGIN_UNKNOWN; + + ACPI_INFO((AE_INFO, "Table DSDT replaced by host OS")); + acpi_tb_print_table_header(0, table); } - /* Check the table type and instance */ + status = + acpi_tb_verify_table(&acpi_gbl_root_table_list. + tables[ACPI_TABLE_INDEX_DSDT]); + if (ACPI_FAILURE(status)) { - if ((table_type > ACPI_TABLE_ID_MAX) || - (ACPI_IS_SINGLE_TABLE(acpi_gbl_table_data[table_type].flags) && - instance > 1)) { - return_ACPI_STATUS(AE_BAD_PARAMETER); + /* A valid DSDT is required */ + + status = AE_NO_ACPI_TABLES; + goto unlock_and_exit; } - /* Get a pointer to the entire table */ + (void)acpi_ut_release_mutex(ACPI_MTX_TABLES); - status = acpi_tb_get_table_ptr(table_type, instance, &tbl_ptr); + /* + * Load and parse tables. + */ + status = acpi_ns_load_table(ACPI_TABLE_INDEX_DSDT, acpi_gbl_root_node); if (ACPI_FAILURE(status)) { return_ACPI_STATUS(status); } /* - * acpi_tb_get_table_ptr will return a NULL pointer if the - * table is not loaded. + * Load any SSDT or PSDT tables. Note: Loop leaves tables locked */ - if (tbl_ptr == NULL) { - return_ACPI_STATUS(AE_NOT_EXIST); + (void)acpi_ut_acquire_mutex(ACPI_MTX_TABLES); + for (i = 0; i < acpi_gbl_root_table_list.count; ++i) { + if ((!ACPI_COMPARE_NAME + (&(acpi_gbl_root_table_list.tables[i].signature), + ACPI_SIG_SSDT) + && + !ACPI_COMPARE_NAME(& + (acpi_gbl_root_table_list.tables[i]. + signature), ACPI_SIG_PSDT)) + || + ACPI_FAILURE(acpi_tb_verify_table + (&acpi_gbl_root_table_list.tables[i]))) { + continue; + } + + /* Ignore errors while loading tables, get as many as possible */ + + (void)acpi_ut_release_mutex(ACPI_MTX_TABLES); + (void)acpi_ns_load_table(i, acpi_gbl_root_node); + (void)acpi_ut_acquire_mutex(ACPI_MTX_TABLES); } - /* Get the table length */ + ACPI_DEBUG_PRINT((ACPI_DB_INIT, "ACPI Tables successfully acquired\n")); - if (table_type == ACPI_TABLE_ID_RSDP) { + unlock_and_exit: + (void)acpi_ut_release_mutex(ACPI_MTX_TABLES); + return_ACPI_STATUS(status); +} - /* RSD PTR is the only "table" without a header */ +/******************************************************************************* + * + * FUNCTION: acpi_load_tables + * + * PARAMETERS: None + * + * RETURN: Status + * + * DESCRIPTION: Load the ACPI tables from the RSDT/XSDT + * + ******************************************************************************/ - table_length = sizeof(struct rsdp_descriptor); - } else { - table_length = (acpi_size) tbl_ptr->length; - } +acpi_status acpi_load_tables(void) +{ + acpi_status status; - /* Validate/Allocate/Clear caller buffer */ + ACPI_FUNCTION_TRACE(acpi_load_tables); - status = acpi_ut_initialize_buffer(ret_buffer, table_length); + /* + * Load the namespace from the tables + */ + status = acpi_tb_load_namespace(); if (ACPI_FAILURE(status)) { - return_ACPI_STATUS(status); + ACPI_EXCEPTION((AE_INFO, status, + "While loading namespace from ACPI tables")); } - /* Copy the table to the buffer */ - - ACPI_MEMCPY(ACPI_CAST_PTR(void, ret_buffer->pointer), - ACPI_CAST_PTR(void, tbl_ptr), table_length); - - return_ACPI_STATUS(AE_OK); + return_ACPI_STATUS(status); } -ACPI_EXPORT_SYMBOL(acpi_get_table) +ACPI_EXPORT_SYMBOL(acpi_load_tables) diff --git a/drivers/acpi/tables/tbxfroot.c b/drivers/acpi/tables/tbxfroot.c index da2648b..cf8fa51 100644 --- a/drivers/acpi/tables/tbxfroot.c +++ b/drivers/acpi/tables/tbxfroot.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2006, R. Byron Moore + * Copyright (C) 2000 - 2007, R. Byron Moore * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -48,16 +48,15 @@ #define _COMPONENT ACPI_TABLES ACPI_MODULE_NAME("tbxfroot") /* Local prototypes */ -static acpi_status -acpi_tb_find_rsdp(struct acpi_table_desc *table_info, u32 flags); - static u8 *acpi_tb_scan_memory_for_rsdp(u8 * start_address, u32 length); +static acpi_status acpi_tb_validate_rsdp(struct acpi_table_rsdp *rsdp); + /******************************************************************************* * * FUNCTION: acpi_tb_validate_rsdp * - * PARAMETERS: Rsdp - Pointer to unvalidated RSDP + * PARAMETERS: Rsdp - Pointer to unvalidated RSDP * * RETURN: Status * @@ -65,14 +64,18 @@ static u8 *acpi_tb_scan_memory_for_rsdp( * ******************************************************************************/ -acpi_status acpi_tb_validate_rsdp(struct rsdp_descriptor *rsdp) +static acpi_status acpi_tb_validate_rsdp(struct acpi_table_rsdp *rsdp) { ACPI_FUNCTION_ENTRY(); /* - * The signature and checksum must both be correct + * The signature and checksum must both be correct + * + * Note: Sometimes there exists more than one RSDP in memory; the valid + * RSDP has a valid checksum, all others have an invalid checksum. */ - if (ACPI_STRNCMP((char *)rsdp, RSDP_SIG, sizeof(RSDP_SIG) - 1) != 0) { + if (ACPI_STRNCMP((char *)rsdp, ACPI_SIG_RSDP, sizeof(ACPI_SIG_RSDP) - 1) + != 0) { /* Nope, BAD Signature */ @@ -81,14 +84,14 @@ acpi_status acpi_tb_validate_rsdp(struct /* Check the standard checksum */ - if (acpi_tb_sum_table(rsdp, ACPI_RSDP_CHECKSUM_LENGTH) != 0) { + if (acpi_tb_checksum((u8 *) rsdp, ACPI_RSDP_CHECKSUM_LENGTH) != 0) { return (AE_BAD_CHECKSUM); } /* Check extended checksum if table version >= 2 */ if ((rsdp->revision >= 2) && - (acpi_tb_sum_table(rsdp, ACPI_RSDP_XCHECKSUM_LENGTH) != 0)) { + (acpi_tb_checksum((u8 *) rsdp, ACPI_RSDP_XCHECKSUM_LENGTH) != 0)) { return (AE_BAD_CHECKSUM); } @@ -97,314 +100,123 @@ acpi_status acpi_tb_validate_rsdp(struct /******************************************************************************* * - * FUNCTION: acpi_tb_find_table - * - * PARAMETERS: Signature - String with ACPI table signature - * oem_id - String with the table OEM ID - * oem_table_id - String with the OEM Table ID - * table_ptr - Where the table pointer is returned - * - * RETURN: Status + * FUNCTION: acpi_tb_find_rsdp * - * DESCRIPTION: Find an ACPI table (in the RSDT/XSDT) that matches the - * Signature, OEM ID and OEM Table ID. + * PARAMETERS: table_address - Where the table pointer is returned * - ******************************************************************************/ - -acpi_status -acpi_tb_find_table(char *signature, - char *oem_id, - char *oem_table_id, struct acpi_table_header ** table_ptr) -{ - acpi_status status; - struct acpi_table_header *table; - - ACPI_FUNCTION_TRACE(tb_find_table); - - /* Validate string lengths */ - - if ((ACPI_STRLEN(signature) > ACPI_NAME_SIZE) || - (ACPI_STRLEN(oem_id) > sizeof(table->oem_id)) || - (ACPI_STRLEN(oem_table_id) > sizeof(table->oem_table_id))) { - return_ACPI_STATUS(AE_AML_STRING_LIMIT); - } - - if (ACPI_COMPARE_NAME(signature, DSDT_SIG)) { - /* - * The DSDT pointer is contained in the FADT, not the RSDT. - * This code should suffice, because the only code that would perform - * a "find" on the DSDT is the data_table_region() AML opcode -- in - * which case, the DSDT is guaranteed to be already loaded. - * If this becomes insufficient, the FADT will have to be found first. - */ - if (!acpi_gbl_DSDT) { - return_ACPI_STATUS(AE_NO_ACPI_TABLES); - } - table = acpi_gbl_DSDT; - } else { - /* Find the table */ - - status = acpi_get_firmware_table(signature, 1, - ACPI_LOGICAL_ADDRESSING, - &table); - if (ACPI_FAILURE(status)) { - return_ACPI_STATUS(status); - } - } - - /* Check oem_id and oem_table_id */ - - if ((oem_id[0] && - ACPI_STRNCMP(oem_id, table->oem_id, - sizeof(table->oem_id))) || - (oem_table_id[0] && - ACPI_STRNCMP(oem_table_id, table->oem_table_id, - sizeof(table->oem_table_id)))) { - return_ACPI_STATUS(AE_AML_NAME_NOT_FOUND); - } - - ACPI_DEBUG_PRINT((ACPI_DB_TABLES, "Found table [%4.4s]\n", - table->signature)); - - *table_ptr = table; - return_ACPI_STATUS(AE_OK); -} - -/******************************************************************************* - * - * FUNCTION: acpi_get_firmware_table + * RETURN: Status, RSDP physical address * - * PARAMETERS: Signature - Any ACPI table signature - * Instance - the non zero instance of the table, allows - * support for multiple tables of the same type - * Flags - Physical/Virtual support - * table_pointer - Where a buffer containing the table is - * returned + * DESCRIPTION: Search lower 1_mbyte of memory for the root system descriptor + * pointer structure. If it is found, set *RSDP to point to it. * - * RETURN: Status + * NOTE1: The RSDP must be either in the first 1_k of the Extended + * BIOS Data Area or between E0000 and FFFFF (From ACPI Spec.) + * Only a 32-bit physical address is necessary. * - * DESCRIPTION: This function is called to get an ACPI table. A buffer is - * allocated for the table and returned in table_pointer. - * This table will be a complete table including the header. + * NOTE2: This function is always available, regardless of the + * initialization state of the rest of ACPI. * ******************************************************************************/ -acpi_status -acpi_get_firmware_table(acpi_string signature, - u32 instance, - u32 flags, struct acpi_table_header **table_pointer) +acpi_status acpi_find_root_pointer(acpi_native_uint * table_address) { - acpi_status status; - struct acpi_pointer address; - struct acpi_table_header *header = NULL; - struct acpi_table_desc *table_info = NULL; - struct acpi_table_desc *rsdt_info; - u32 table_count; - u32 i; - u32 j; - - ACPI_FUNCTION_TRACE(acpi_get_firmware_table); - - /* - * Ensure that at least the table manager is initialized. We don't - * require that the entire ACPI subsystem is up for this interface. - * If we have a buffer, we must have a length too - */ - if ((instance == 0) || (!signature) || (!table_pointer)) { - return_ACPI_STATUS(AE_BAD_PARAMETER); - } - - /* Ensure that we have a RSDP */ - - if (!acpi_gbl_RSDP) { - - /* Get the RSDP */ - - status = acpi_os_get_root_pointer(flags, &address); - if (ACPI_FAILURE(status)) { - ACPI_DEBUG_PRINT((ACPI_DB_INFO, "RSDP not found\n")); - return_ACPI_STATUS(AE_NO_ACPI_TABLES); - } - - /* Map and validate the RSDP */ - - if ((flags & ACPI_MEMORY_MODE) == ACPI_LOGICAL_ADDRESSING) { - status = acpi_os_map_memory(address.pointer.physical, - sizeof(struct - rsdp_descriptor), - (void *)&acpi_gbl_RSDP); - if (ACPI_FAILURE(status)) { - return_ACPI_STATUS(status); - } - } else { - acpi_gbl_RSDP = address.pointer.logical; - } - - /* The RDSP signature and checksum must both be correct */ - - status = acpi_tb_validate_rsdp(acpi_gbl_RSDP); - if (ACPI_FAILURE(status)) { - return_ACPI_STATUS(status); - } - } - - /* Get the RSDT address via the RSDP */ - - acpi_tb_get_rsdt_address(&address); - ACPI_DEBUG_PRINT((ACPI_DB_INFO, - "RSDP located at %p, RSDT physical=%8.8X%8.8X\n", - acpi_gbl_RSDP, - ACPI_FORMAT_UINT64(address.pointer.value))); + u8 *table_ptr; + u8 *mem_rover; + u32 physical_address; - /* Insert processor_mode flags */ + ACPI_FUNCTION_TRACE(acpi_find_root_pointer); - address.pointer_type |= flags; + /* 1a) Get the location of the Extended BIOS Data Area (EBDA) */ - /* Get and validate the RSDT */ + table_ptr = acpi_os_map_memory((acpi_physical_address) + ACPI_EBDA_PTR_LOCATION, + ACPI_EBDA_PTR_LENGTH); + if (!table_ptr) { + ACPI_ERROR((AE_INFO, + "Could not map memory at %8.8X for length %X", + ACPI_EBDA_PTR_LOCATION, ACPI_EBDA_PTR_LENGTH)); - rsdt_info = ACPI_ALLOCATE_ZEROED(sizeof(struct acpi_table_desc)); - if (!rsdt_info) { return_ACPI_STATUS(AE_NO_MEMORY); } - status = acpi_tb_get_table(&address, rsdt_info); - if (ACPI_FAILURE(status)) { - goto cleanup; - } - - status = acpi_tb_validate_rsdt(rsdt_info->pointer); - if (ACPI_FAILURE(status)) { - goto cleanup; - } + ACPI_MOVE_16_TO_32(&physical_address, table_ptr); - /* Allocate a scratch table header and table descriptor */ + /* Convert segment part to physical address */ - header = ACPI_ALLOCATE(sizeof(struct acpi_table_header)); - if (!header) { - status = AE_NO_MEMORY; - goto cleanup; - } + physical_address <<= 4; + acpi_os_unmap_memory(table_ptr, ACPI_EBDA_PTR_LENGTH); - table_info = ACPI_ALLOCATE(sizeof(struct acpi_table_desc)); - if (!table_info) { - status = AE_NO_MEMORY; - goto cleanup; - } + /* EBDA present? */ - /* Get the number of table pointers within the RSDT */ - - table_count = - acpi_tb_get_table_count(acpi_gbl_RSDP, rsdt_info->pointer); - address.pointer_type = acpi_gbl_table_flags | flags; - - /* - * Search the RSDT/XSDT for the correct instance of the - * requested table - */ - for (i = 0, j = 0; i < table_count; i++) { + if (physical_address > 0x400) { /* - * Get the next table pointer, handle RSDT vs. XSDT - * RSDT pointers are 32 bits, XSDT pointers are 64 bits + * 1b) Search EBDA paragraphs (EBDA is required to be a + * minimum of 1_k length) */ - if (acpi_gbl_root_table_type == ACPI_TABLE_TYPE_RSDT) { - address.pointer.value = - (ACPI_CAST_PTR - (struct rsdt_descriptor, - rsdt_info->pointer))->table_offset_entry[i]; - } else { - address.pointer.value = - (ACPI_CAST_PTR - (struct xsdt_descriptor, - rsdt_info->pointer))->table_offset_entry[i]; - } - - /* Get the table header */ + table_ptr = acpi_os_map_memory((acpi_native_uint) + physical_address, + ACPI_EBDA_WINDOW_SIZE); + if (!table_ptr) { + ACPI_ERROR((AE_INFO, + "Could not map memory at %8.8X for length %X", + physical_address, ACPI_EBDA_WINDOW_SIZE)); - status = acpi_tb_get_table_header(&address, header); - if (ACPI_FAILURE(status)) { - goto cleanup; + return_ACPI_STATUS(AE_NO_MEMORY); } - /* Compare table signatures and table instance */ - - if (ACPI_COMPARE_NAME(header->signature, signature)) { - - /* An instance of the table was found */ + mem_rover = + acpi_tb_scan_memory_for_rsdp(table_ptr, + ACPI_EBDA_WINDOW_SIZE); + acpi_os_unmap_memory(table_ptr, ACPI_EBDA_WINDOW_SIZE); - j++; - if (j >= instance) { + if (mem_rover) { - /* Found the correct instance, get the entire table */ + /* Return the physical address */ - status = - acpi_tb_get_table_body(&address, header, - table_info); - if (ACPI_FAILURE(status)) { - goto cleanup; - } + physical_address += + (u32) ACPI_PTR_DIFF(mem_rover, table_ptr); - *table_pointer = table_info->pointer; - goto cleanup; - } + *table_address = physical_address; + return_ACPI_STATUS(AE_OK); } } - /* Did not find the table */ + /* + * 2) Search upper memory: 16-byte boundaries in E0000h-FFFFFh + */ + table_ptr = acpi_os_map_memory((acpi_physical_address) + ACPI_HI_RSDP_WINDOW_BASE, + ACPI_HI_RSDP_WINDOW_SIZE); - status = AE_NOT_EXIST; + if (!table_ptr) { + ACPI_ERROR((AE_INFO, + "Could not map memory at %8.8X for length %X", + ACPI_HI_RSDP_WINDOW_BASE, + ACPI_HI_RSDP_WINDOW_SIZE)); - cleanup: - if (rsdt_info->pointer) { - acpi_os_unmap_memory(rsdt_info->pointer, - (acpi_size) rsdt_info->pointer->length); + return_ACPI_STATUS(AE_NO_MEMORY); } - ACPI_FREE(rsdt_info); - if (header) { - ACPI_FREE(header); - } - if (table_info) { - ACPI_FREE(table_info); - } - return_ACPI_STATUS(status); -} + mem_rover = + acpi_tb_scan_memory_for_rsdp(table_ptr, ACPI_HI_RSDP_WINDOW_SIZE); + acpi_os_unmap_memory(table_ptr, ACPI_HI_RSDP_WINDOW_SIZE); -ACPI_EXPORT_SYMBOL(acpi_get_firmware_table) + if (mem_rover) { -/* TBD: Move to a new file */ -#if ACPI_MACHINE_WIDTH != 16 -/******************************************************************************* - * - * FUNCTION: acpi_find_root_pointer - * - * PARAMETERS: Flags - Logical/Physical addressing - * rsdp_address - Where to place the RSDP address - * - * RETURN: Status, Physical address of the RSDP - * - * DESCRIPTION: Find the RSDP - * - ******************************************************************************/ -acpi_status acpi_find_root_pointer(u32 flags, struct acpi_pointer *rsdp_address) -{ - struct acpi_table_desc table_info; - acpi_status status; - - ACPI_FUNCTION_TRACE(acpi_find_root_pointer); - - /* Get the RSDP */ + /* Return the physical address */ - status = acpi_tb_find_rsdp(&table_info, flags); - if (ACPI_FAILURE(status)) { - ACPI_EXCEPTION((AE_INFO, status, - "RSDP structure not found - Flags=%X", flags)); + physical_address = (u32) + (ACPI_HI_RSDP_WINDOW_BASE + + ACPI_PTR_DIFF(mem_rover, table_ptr)); - return_ACPI_STATUS(AE_NO_ACPI_TABLES); + *table_address = physical_address; + return_ACPI_STATUS(AE_OK); } - rsdp_address->pointer_type = ACPI_PHYSICAL_POINTER; - rsdp_address->pointer.physical = table_info.physical_address; - return_ACPI_STATUS(AE_OK); + /* A valid RSDP was not found */ + + ACPI_ERROR((AE_INFO, "A valid RSDP was not found")); + return_ACPI_STATUS(AE_NOT_FOUND); } ACPI_EXPORT_SYMBOL(acpi_find_root_pointer) @@ -440,7 +252,7 @@ static u8 *acpi_tb_scan_memory_for_rsdp( status = acpi_tb_validate_rsdp(ACPI_CAST_PTR - (struct rsdp_descriptor, mem_rover)); + (struct acpi_table_rsdp, mem_rover)); if (ACPI_SUCCESS(status)) { /* Sig and checksum valid, we have found a real RSDP */ @@ -461,189 +273,3 @@ static u8 *acpi_tb_scan_memory_for_rsdp( start_address)); return_PTR(NULL); } - -/******************************************************************************* - * - * FUNCTION: acpi_tb_find_rsdp - * - * PARAMETERS: table_info - Where the table info is returned - * Flags - Current memory mode (logical vs. - * physical addressing) - * - * RETURN: Status, RSDP physical address - * - * DESCRIPTION: Search lower 1_mbyte of memory for the root system descriptor - * pointer structure. If it is found, set *RSDP to point to it. - * - * NOTE1: The RSDP must be either in the first 1_k of the Extended - * BIOS Data Area or between E0000 and FFFFF (From ACPI Spec.) - * Only a 32-bit physical address is necessary. - * - * NOTE2: This function is always available, regardless of the - * initialization state of the rest of ACPI. - * - ******************************************************************************/ - -static acpi_status -acpi_tb_find_rsdp(struct acpi_table_desc *table_info, u32 flags) -{ - u8 *table_ptr; - u8 *mem_rover; - u32 physical_address; - acpi_status status; - - ACPI_FUNCTION_TRACE(tb_find_rsdp); - - /* - * Scan supports either logical addressing or physical addressing - */ - if ((flags & ACPI_MEMORY_MODE) == ACPI_LOGICAL_ADDRESSING) { - - /* 1a) Get the location of the Extended BIOS Data Area (EBDA) */ - - status = acpi_os_map_memory((acpi_physical_address) - ACPI_EBDA_PTR_LOCATION, - ACPI_EBDA_PTR_LENGTH, - (void *)&table_ptr); - if (ACPI_FAILURE(status)) { - ACPI_ERROR((AE_INFO, - "Could not map memory at %8.8X for length %X", - ACPI_EBDA_PTR_LOCATION, - ACPI_EBDA_PTR_LENGTH)); - - return_ACPI_STATUS(status); - } - - ACPI_MOVE_16_TO_32(&physical_address, table_ptr); - - /* Convert segment part to physical address */ - - physical_address <<= 4; - acpi_os_unmap_memory(table_ptr, ACPI_EBDA_PTR_LENGTH); - - /* EBDA present? */ - - if (physical_address > 0x400) { - /* - * 1b) Search EBDA paragraphs (EBDA is required to be a - * minimum of 1_k length) - */ - status = acpi_os_map_memory((acpi_physical_address) - physical_address, - ACPI_EBDA_WINDOW_SIZE, - (void *)&table_ptr); - if (ACPI_FAILURE(status)) { - ACPI_ERROR((AE_INFO, - "Could not map memory at %8.8X for length %X", - physical_address, - ACPI_EBDA_WINDOW_SIZE)); - - return_ACPI_STATUS(status); - } - - mem_rover = acpi_tb_scan_memory_for_rsdp(table_ptr, - ACPI_EBDA_WINDOW_SIZE); - acpi_os_unmap_memory(table_ptr, ACPI_EBDA_WINDOW_SIZE); - - if (mem_rover) { - - /* Return the physical address */ - - physical_address += - (u32) ACPI_PTR_DIFF(mem_rover, table_ptr); - - table_info->physical_address = - (acpi_physical_address) physical_address; - return_ACPI_STATUS(AE_OK); - } - } - - /* - * 2) Search upper memory: 16-byte boundaries in E0000h-FFFFFh - */ - status = acpi_os_map_memory((acpi_physical_address) - ACPI_HI_RSDP_WINDOW_BASE, - ACPI_HI_RSDP_WINDOW_SIZE, - (void *)&table_ptr); - - if (ACPI_FAILURE(status)) { - ACPI_ERROR((AE_INFO, - "Could not map memory at %8.8X for length %X", - ACPI_HI_RSDP_WINDOW_BASE, - ACPI_HI_RSDP_WINDOW_SIZE)); - - return_ACPI_STATUS(status); - } - - mem_rover = - acpi_tb_scan_memory_for_rsdp(table_ptr, - ACPI_HI_RSDP_WINDOW_SIZE); - acpi_os_unmap_memory(table_ptr, ACPI_HI_RSDP_WINDOW_SIZE); - - if (mem_rover) { - - /* Return the physical address */ - - physical_address = (u32) - (ACPI_HI_RSDP_WINDOW_BASE + - ACPI_PTR_DIFF(mem_rover, table_ptr)); - - table_info->physical_address = - (acpi_physical_address) physical_address; - return_ACPI_STATUS(AE_OK); - } - } - - /* - * Physical addressing - */ - else { - /* 1a) Get the location of the EBDA */ - - ACPI_MOVE_16_TO_32(&physical_address, ACPI_EBDA_PTR_LOCATION); - physical_address <<= 4; /* Convert segment to physical address */ - - /* EBDA present? */ - - if (physical_address > 0x400) { - /* - * 1b) Search EBDA paragraphs (EBDA is required to be a minimum of - * 1_k length) - */ - mem_rover = - acpi_tb_scan_memory_for_rsdp(ACPI_PHYSADDR_TO_PTR - (physical_address), - ACPI_EBDA_WINDOW_SIZE); - if (mem_rover) { - - /* Return the physical address */ - - table_info->physical_address = - ACPI_TO_INTEGER(mem_rover); - return_ACPI_STATUS(AE_OK); - } - } - - /* 2) Search upper memory: 16-byte boundaries in E0000h-FFFFFh */ - - mem_rover = - acpi_tb_scan_memory_for_rsdp(ACPI_PHYSADDR_TO_PTR - (ACPI_HI_RSDP_WINDOW_BASE), - ACPI_HI_RSDP_WINDOW_SIZE); - if (mem_rover) { - - /* Found it, return the physical address */ - - table_info->physical_address = - ACPI_TO_INTEGER(mem_rover); - return_ACPI_STATUS(AE_OK); - } - } - - /* A valid RSDP was not found */ - - ACPI_ERROR((AE_INFO, "No valid RSDP was found")); - return_ACPI_STATUS(AE_NOT_FOUND); -} - -#endif diff --git a/drivers/acpi/thermal.c b/drivers/acpi/thermal.c index 40ddb4d..986afd4 100644 --- a/drivers/acpi/thermal.c +++ b/drivers/acpi/thermal.c @@ -36,7 +36,8 @@ #include #include #include #include -#include +#include +#include #include #include #include @@ -82,7 +83,7 @@ MODULE_PARM_DESC(tzp, "Thermal zone poll static int acpi_thermal_add(struct acpi_device *device); static int acpi_thermal_remove(struct acpi_device *device, int type); -static int acpi_thermal_resume(struct acpi_device *device, int state); +static int acpi_thermal_resume(struct acpi_device *device); static int acpi_thermal_state_open_fs(struct inode *inode, struct file *file); static int acpi_thermal_temp_open_fs(struct inode *inode, struct file *file); static int acpi_thermal_trip_open_fs(struct inode *inode, struct file *file); @@ -1353,7 +1354,7 @@ static int acpi_thermal_remove(struct ac return 0; } -static int acpi_thermal_resume(struct acpi_device *device, int state) +static int acpi_thermal_resume(struct acpi_device *device) { struct acpi_thermal *tz = NULL; int i; diff --git a/drivers/acpi/utilities/utalloc.c b/drivers/acpi/utilities/utalloc.c index f6cbc0b..55a7648 100644 --- a/drivers/acpi/utilities/utalloc.c +++ b/drivers/acpi/utilities/utalloc.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2006, R. Byron Moore + * Copyright (C) 2000 - 2007, R. Byron Moore * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -42,6 +42,7 @@ */ #include +#include #define _COMPONENT ACPI_UTILITIES ACPI_MODULE_NAME("utalloc") @@ -142,6 +143,14 @@ #endif acpi_status acpi_ut_delete_caches(void) { +#ifdef ACPI_DBG_TRACK_ALLOCATIONS + char buffer[7]; + + if (acpi_gbl_display_final_mem_stats) { + ACPI_STRCPY(buffer, "MEMORY"); + acpi_db_display_statistics(buffer); + } +#endif (void)acpi_os_delete_cache(acpi_gbl_namespace_cache); acpi_gbl_namespace_cache = NULL; diff --git a/drivers/acpi/utilities/utcache.c b/drivers/acpi/utilities/utcache.c index 1a1f810..870f6ed 100644 --- a/drivers/acpi/utilities/utcache.c +++ b/drivers/acpi/utilities/utcache.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2006, R. Byron Moore + * Copyright (C) 2000 - 2007, R. Byron Moore * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -289,6 +289,14 @@ void *acpi_os_acquire_object(struct acpi ACPI_MEM_TRACKING(cache->total_allocated++); +#ifdef ACPI_DBG_TRACK_ALLOCATIONS + if ((cache->total_allocated - cache->total_freed) > + cache->max_occupied) { + cache->max_occupied = + cache->total_allocated - cache->total_freed; + } +#endif + /* Avoid deadlock with ACPI_ALLOCATE_ZEROED */ status = acpi_ut_release_mutex(ACPI_MTX_CACHES); diff --git a/drivers/acpi/utilities/utcopy.c b/drivers/acpi/utilities/utcopy.c index 5e1a80d..84d529d 100644 --- a/drivers/acpi/utilities/utcopy.c +++ b/drivers/acpi/utilities/utcopy.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2006, R. Byron Moore + * Copyright (C) 2000 - 2007, R. Byron Moore * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -719,6 +719,15 @@ acpi_ut_copy_simple_object(union acpi_op acpi_ut_add_reference(source_desc->reference.object); break; + case ACPI_TYPE_REGION: + /* + * We copied the Region Handler, so we now must add a reference + */ + if (dest_desc->region.handler) { + acpi_ut_add_reference(dest_desc->region.handler); + } + break; + default: /* Nothing to do for other simple objects */ break; diff --git a/drivers/acpi/utilities/utdebug.c b/drivers/acpi/utilities/utdebug.c index 9e9054e..61ad4f2 100644 --- a/drivers/acpi/utilities/utdebug.c +++ b/drivers/acpi/utilities/utdebug.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2006, R. Byron Moore + * Copyright (C) 2000 - 2007, R. Byron Moore * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -181,8 +181,7 @@ acpi_ut_debug_print(u32 requested_debug_ if (ACPI_LV_THREADS & acpi_dbg_level) { acpi_os_printf ("\n**** Context Switch from TID %lX to TID %lX ****\n\n", - (unsigned long) acpi_gbl_prev_thread_id, - (unsigned long) thread_id); + (unsigned long)acpi_gbl_prev_thread_id, (unsigned long)thread_id); } acpi_gbl_prev_thread_id = thread_id; @@ -195,7 +194,7 @@ acpi_ut_debug_print(u32 requested_debug_ acpi_os_printf("%8s-%04ld ", module_name, line_number); if (ACPI_LV_THREADS & acpi_dbg_level) { - acpi_os_printf("[%04lX] ", thread_id); + acpi_os_printf("[%04lX] ", (unsigned long)thread_id); } acpi_os_printf("[%02ld] %-22.22s: ", diff --git a/drivers/acpi/utilities/utdelete.c b/drivers/acpi/utilities/utdelete.c index 9d3f114..f777ceb 100644 --- a/drivers/acpi/utilities/utdelete.c +++ b/drivers/acpi/utilities/utdelete.c @@ -5,7 +5,7 @@ ******************************************************************************/ /* - * Copyright (C) 2000 - 2006, R. Byron Moore + * Copyright (C) 2000 - 2007, R. Byron Moore * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -158,16 +158,20 @@ static void acpi_ut_delete_internal_obj( "***** Mutex %p, OS Mutex %p\n", object, object->mutex.os_mutex)); - if (object->mutex.os_mutex != ACPI_GLOBAL_LOCK) { - acpi_ex_unlink_mutex(object); - acpi_os_delete_mutex(object->mutex.os_mutex); - } else { - /* Global Lock "mutex" is actually a counting semaphore */ + if (object->mutex.os_mutex == acpi_gbl_global_lock_mutex) { + + /* Global Lock has extra semaphore */ (void) acpi_os_delete_semaphore (acpi_gbl_global_lock_semaphore); acpi_gbl_global_lock_semaphore = NULL; + + acpi_os_delete_mutex(object->mutex.os_mutex); + acpi_gbl_global_lock_mutex = NULL; + } else { + acpi_ex_unlink_mutex(object); + acpi_os_delete_mutex(object->mutex.os_mutex); } break; diff --git a/drivers/acpi/utilities/uteval.c b/drivers/acpi/utilities/uteval.c index d6d7121..13d5879 100644 --- a/drivers/acpi/utilities/uteval.c +++ b/drivers/acpi/utilities/uteval.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2006, R. Byron Moore + * Copyright (C) 2000 - 2007, R. Byron Moore * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/utilities/utglobal.c b/drivers/acpi/utilities/utglobal.c index 014030a..af33358 100644 --- a/drivers/acpi/utilities/utglobal.c +++ b/drivers/acpi/utilities/utglobal.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2006, R. Byron Moore + * Copyright (C) 2000 - 2007, R. Byron Moore * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -46,89 +46,9 @@ #define DEFINE_ACPI_GLOBALS #include #include +ACPI_EXPORT_SYMBOL(acpi_gbl_FADT) #define _COMPONENT ACPI_UTILITIES -ACPI_MODULE_NAME("utglobal") - -/******************************************************************************* - * - * FUNCTION: acpi_format_exception - * - * PARAMETERS: Status - The acpi_status code to be formatted - * - * RETURN: A string containing the exception text. A valid pointer is - * always returned. - * - * DESCRIPTION: This function translates an ACPI exception into an ASCII string. - * - ******************************************************************************/ -const char *acpi_format_exception(acpi_status status) -{ - acpi_status sub_status; - const char *exception = NULL; - - ACPI_FUNCTION_ENTRY(); - - /* - * Status is composed of two parts, a "type" and an actual code - */ - sub_status = (status & ~AE_CODE_MASK); - - switch (status & AE_CODE_MASK) { - case AE_CODE_ENVIRONMENTAL: - - if (sub_status <= AE_CODE_ENV_MAX) { - exception = acpi_gbl_exception_names_env[sub_status]; - } - break; - - case AE_CODE_PROGRAMMER: - - if (sub_status <= AE_CODE_PGM_MAX) { - exception = - acpi_gbl_exception_names_pgm[sub_status - 1]; - } - break; - - case AE_CODE_ACPI_TABLES: - - if (sub_status <= AE_CODE_TBL_MAX) { - exception = - acpi_gbl_exception_names_tbl[sub_status - 1]; - } - break; - - case AE_CODE_AML: - - if (sub_status <= AE_CODE_AML_MAX) { - exception = - acpi_gbl_exception_names_aml[sub_status - 1]; - } - break; - - case AE_CODE_CONTROL: - - if (sub_status <= AE_CODE_CTRL_MAX) { - exception = - acpi_gbl_exception_names_ctrl[sub_status - 1]; - } - break; - - default: - break; - } - - if (!exception) { - - /* Exception code was not recognized */ - - ACPI_ERROR((AE_INFO, - "Unknown exception code: 0x%8.8X", status)); - - exception = "UNKNOWN_STATUS_CODE"; - } - - return (ACPI_CAST_PTR(const char, exception)); -} + ACPI_MODULE_NAME("utglobal") /******************************************************************************* * @@ -163,8 +83,6 @@ u32 acpi_gbl_startup_flags = 0; u8 acpi_gbl_shutdown = TRUE; -const u8 acpi_gbl_decode_to8bit[8] = { 1, 2, 4, 8, 16, 32, 64, 128 }; - const char *acpi_gbl_sleep_state_names[ACPI_S_STATE_COUNT] = { "\\_S0_", "\\_S1_", @@ -183,10 +101,45 @@ const char *acpi_gbl_highest_dstate_name /******************************************************************************* * - * Namespace globals + * FUNCTION: acpi_format_exception + * + * PARAMETERS: Status - The acpi_status code to be formatted + * + * RETURN: A string containing the exception text. A valid pointer is + * always returned. + * + * DESCRIPTION: This function translates an ACPI exception into an ASCII string + * It is here instead of utxface.c so it is always present. * ******************************************************************************/ +const char *acpi_format_exception(acpi_status status) +{ + const char *exception = NULL; + + ACPI_FUNCTION_ENTRY(); + + exception = acpi_ut_validate_exception(status); + if (!exception) { + + /* Exception code was not recognized */ + + ACPI_ERROR((AE_INFO, + "Unknown exception code: 0x%8.8X", status)); + + exception = "UNKNOWN_STATUS_CODE"; + } + + return (ACPI_CAST_PTR(const char, exception)); +} + +ACPI_EXPORT_SYMBOL(acpi_format_exception) + +/******************************************************************************* + * + * Namespace globals + * + ******************************************************************************/ /* * Predefined ACPI Names (Built-in to the Interpreter) * @@ -280,53 +233,6 @@ char acpi_ut_hex_to_ascii_char(acpi_inte return (acpi_gbl_hex_to_ascii[(integer >> position) & 0xF]); } -/******************************************************************************* - * - * Table name globals - * - * NOTE: This table includes ONLY the ACPI tables that the subsystem consumes. - * it is NOT an exhaustive list of all possible ACPI tables. All ACPI tables - * that are not used by the subsystem are simply ignored. - * - * Do NOT add any table to this list that is not consumed directly by this - * subsystem (No MADT, ECDT, SBST, etc.) - * - ******************************************************************************/ - -struct acpi_table_list acpi_gbl_table_lists[ACPI_TABLE_ID_MAX + 1]; - -struct acpi_table_support acpi_gbl_table_data[ACPI_TABLE_ID_MAX + 1] = { - /*********** Name, Signature, Global typed pointer Signature size, Type How many allowed?, Contains valid AML? */ - - /* RSDP 0 */ {RSDP_NAME, RSDP_SIG, NULL, sizeof(RSDP_SIG) - 1, - ACPI_TABLE_ROOT | ACPI_TABLE_SINGLE} - , - /* DSDT 1 */ {DSDT_SIG, DSDT_SIG, (void *)&acpi_gbl_DSDT, - sizeof(DSDT_SIG) - 1, - ACPI_TABLE_SECONDARY | ACPI_TABLE_SINGLE | - ACPI_TABLE_EXECUTABLE} - , - /* FADT 2 */ {FADT_SIG, FADT_SIG, (void *)&acpi_gbl_FADT, - sizeof(FADT_SIG) - 1, - ACPI_TABLE_PRIMARY | ACPI_TABLE_SINGLE} - , - /* FACS 3 */ {FACS_SIG, FACS_SIG, (void *)&acpi_gbl_FACS, - sizeof(FACS_SIG) - 1, - ACPI_TABLE_SECONDARY | ACPI_TABLE_SINGLE} - , - /* PSDT 4 */ {PSDT_SIG, PSDT_SIG, NULL, sizeof(PSDT_SIG) - 1, - ACPI_TABLE_PRIMARY | ACPI_TABLE_MULTIPLE | - ACPI_TABLE_EXECUTABLE} - , - /* SSDT 5 */ {SSDT_SIG, SSDT_SIG, NULL, sizeof(SSDT_SIG) - 1, - ACPI_TABLE_PRIMARY | ACPI_TABLE_MULTIPLE | - ACPI_TABLE_EXECUTABLE} - , - /* XSDT 6 */ {XSDT_SIG, XSDT_SIG, NULL, sizeof(RSDT_SIG) - 1, - ACPI_TABLE_ROOT | ACPI_TABLE_SINGLE} - , -}; - /****************************************************************************** * * Event and Hardware globals @@ -612,7 +518,7 @@ char *acpi_ut_get_node_name(void *object /* Name must be a valid ACPI name */ if (!acpi_ut_valid_acpi_name(node->name.integer)) { - node->name.integer = acpi_ut_repair_name(node->name.integer); + node->name.integer = acpi_ut_repair_name(node->name.ascii); } /* Return the name */ @@ -751,13 +657,6 @@ void acpi_ut_init_globals(void) return; } - /* ACPI table structure */ - - for (i = 0; i < (ACPI_TABLE_ID_MAX + 1); i++) { - acpi_gbl_table_lists[i].next = NULL; - acpi_gbl_table_lists[i].count = 0; - } - /* Mutex locked flags */ for (i = 0; i < ACPI_NUM_MUTEX; i++) { @@ -773,6 +672,7 @@ void acpi_ut_init_globals(void) /* GPE support */ + acpi_gpe_count = 0; acpi_gbl_gpe_xrupt_list_head = NULL; acpi_gbl_gpe_fadt_blocks[0] = NULL; acpi_gbl_gpe_fadt_blocks[1] = NULL; @@ -784,25 +684,15 @@ void acpi_ut_init_globals(void) acpi_gbl_exception_handler = NULL; acpi_gbl_init_handler = NULL; - /* Global "typed" ACPI table pointers */ - - acpi_gbl_RSDP = NULL; - acpi_gbl_XSDT = NULL; - acpi_gbl_FACS = NULL; - acpi_gbl_FADT = NULL; - acpi_gbl_DSDT = NULL; - /* Global Lock support */ acpi_gbl_global_lock_semaphore = NULL; + acpi_gbl_global_lock_mutex = NULL; acpi_gbl_global_lock_acquired = FALSE; - acpi_gbl_global_lock_thread_count = 0; acpi_gbl_global_lock_handle = 0; /* Miscellaneous variables */ - acpi_gbl_table_flags = ACPI_PHYSICAL_POINTER; - acpi_gbl_rsdp_original_location = 0; acpi_gbl_cm_single_step = FALSE; acpi_gbl_db_terminate_threads = FALSE; acpi_gbl_shutdown = FALSE; @@ -837,8 +727,13 @@ #ifdef ACPI_DEBUG_OUTPUT acpi_gbl_lowest_stack_pointer = ACPI_SIZE_MAX; #endif +#ifdef ACPI_DBG_TRACK_ALLOCATIONS + acpi_gbl_display_final_mem_stats = FALSE; +#endif + return_VOID; } ACPI_EXPORT_SYMBOL(acpi_dbg_level) ACPI_EXPORT_SYMBOL(acpi_dbg_layer) +ACPI_EXPORT_SYMBOL(acpi_gpe_count) diff --git a/drivers/acpi/utilities/utinit.c b/drivers/acpi/utilities/utinit.c index ff76055..ad3c0d0 100644 --- a/drivers/acpi/utilities/utinit.c +++ b/drivers/acpi/utilities/utinit.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2006, R. Byron Moore + * Copyright (C) 2000 - 2007, R. Byron Moore * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -44,119 +44,14 @@ #include #include #include +#include #define _COMPONENT ACPI_UTILITIES ACPI_MODULE_NAME("utinit") /* Local prototypes */ -static void -acpi_ut_fadt_register_error(char *register_name, u32 value, u8 offset); - static void acpi_ut_terminate(void); -/******************************************************************************* - * - * FUNCTION: acpi_ut_fadt_register_error - * - * PARAMETERS: register_name - Pointer to string identifying register - * Value - Actual register contents value - * Offset - Byte offset in the FADT - * - * RETURN: AE_BAD_VALUE - * - * DESCRIPTION: Display failure message - * - ******************************************************************************/ - -static void -acpi_ut_fadt_register_error(char *register_name, u32 value, u8 offset) -{ - - ACPI_WARNING((AE_INFO, - "Invalid FADT value %s=%X at offset %X FADT=%p", - register_name, value, offset, acpi_gbl_FADT)); -} - -/****************************************************************************** - * - * FUNCTION: acpi_ut_validate_fadt - * - * PARAMETERS: None - * - * RETURN: Status - * - * DESCRIPTION: Validate various ACPI registers in the FADT - * - ******************************************************************************/ - -acpi_status acpi_ut_validate_fadt(void) -{ - - /* - * Verify Fixed ACPI Description Table fields, - * but don't abort on any problems, just display error - */ - if (acpi_gbl_FADT->pm1_evt_len < 4) { - acpi_ut_fadt_register_error("PM1_EVT_LEN", - (u32) acpi_gbl_FADT->pm1_evt_len, - ACPI_FADT_OFFSET(pm1_evt_len)); - } - - if (!acpi_gbl_FADT->pm1_cnt_len) { - acpi_ut_fadt_register_error("PM1_CNT_LEN", 0, - ACPI_FADT_OFFSET(pm1_cnt_len)); - } - - if (!acpi_gbl_FADT->xpm1a_evt_blk.address) { - acpi_ut_fadt_register_error("X_PM1a_EVT_BLK", 0, - ACPI_FADT_OFFSET(xpm1a_evt_blk. - address)); - } - - if (!acpi_gbl_FADT->xpm1a_cnt_blk.address) { - acpi_ut_fadt_register_error("X_PM1a_CNT_BLK", 0, - ACPI_FADT_OFFSET(xpm1a_cnt_blk. - address)); - } - - if (!acpi_gbl_FADT->xpm_tmr_blk.address) { - acpi_ut_fadt_register_error("X_PM_TMR_BLK", 0, - ACPI_FADT_OFFSET(xpm_tmr_blk. - address)); - } - - if ((acpi_gbl_FADT->xpm2_cnt_blk.address && - !acpi_gbl_FADT->pm2_cnt_len)) { - acpi_ut_fadt_register_error("PM2_CNT_LEN", - (u32) acpi_gbl_FADT->pm2_cnt_len, - ACPI_FADT_OFFSET(pm2_cnt_len)); - } - - if (acpi_gbl_FADT->pm_tm_len < 4) { - acpi_ut_fadt_register_error("PM_TM_LEN", - (u32) acpi_gbl_FADT->pm_tm_len, - ACPI_FADT_OFFSET(pm_tm_len)); - } - - /* Length of GPE blocks must be a multiple of 2 */ - - if (acpi_gbl_FADT->xgpe0_blk.address && - (acpi_gbl_FADT->gpe0_blk_len & 1)) { - acpi_ut_fadt_register_error("(x)GPE0_BLK_LEN", - (u32) acpi_gbl_FADT->gpe0_blk_len, - ACPI_FADT_OFFSET(gpe0_blk_len)); - } - - if (acpi_gbl_FADT->xgpe1_blk.address && - (acpi_gbl_FADT->gpe1_blk_len & 1)) { - acpi_ut_fadt_register_error("(x)GPE1_BLK_LEN", - (u32) acpi_gbl_FADT->gpe1_blk_len, - ACPI_FADT_OFFSET(gpe1_blk_len)); - } - - return (AE_OK); -} - /****************************************************************************** * * FUNCTION: acpi_ut_terminate @@ -178,7 +73,6 @@ static void acpi_ut_terminate(void) ACPI_FUNCTION_TRACE(ut_terminate); - /* Free global tables, etc. */ /* Free global GPE blocks and related info structures */ gpe_xrupt_info = acpi_gbl_gpe_xrupt_list_head; @@ -239,6 +133,10 @@ void acpi_ut_subsystem_shutdown(void) acpi_ns_terminate(); + /* Delete the ACPI tables */ + + acpi_tb_terminate(); + /* Close the globals */ acpi_ut_terminate(); diff --git a/drivers/acpi/utilities/utmath.c b/drivers/acpi/utilities/utmath.c index 19d74be..0c56a0d 100644 --- a/drivers/acpi/utilities/utmath.c +++ b/drivers/acpi/utilities/utmath.c @@ -5,7 +5,7 @@ ******************************************************************************/ /* - * Copyright (C) 2000 - 2006, R. Byron Moore + * Copyright (C) 2000 - 2007, R. Byron Moore * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/utilities/utmisc.c b/drivers/acpi/utilities/utmisc.c index 6d8a821..50133ff 100644 --- a/drivers/acpi/utilities/utmisc.c +++ b/drivers/acpi/utilities/utmisc.c @@ -5,7 +5,7 @@ ******************************************************************************/ /* - * Copyright (C) 2000 - 2006, R. Byron Moore + * Copyright (C) 2000 - 2007, R. Byron Moore * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -51,6 +51,78 @@ ACPI_MODULE_NAME("utmisc") /******************************************************************************* * + * FUNCTION: acpi_ut_validate_exception + * + * PARAMETERS: Status - The acpi_status code to be formatted + * + * RETURN: A string containing the exception text. NULL if exception is + * not valid. + * + * DESCRIPTION: This function validates and translates an ACPI exception into + * an ASCII string. + * + ******************************************************************************/ +const char *acpi_ut_validate_exception(acpi_status status) +{ + acpi_status sub_status; + const char *exception = NULL; + + ACPI_FUNCTION_ENTRY(); + + /* + * Status is composed of two parts, a "type" and an actual code + */ + sub_status = (status & ~AE_CODE_MASK); + + switch (status & AE_CODE_MASK) { + case AE_CODE_ENVIRONMENTAL: + + if (sub_status <= AE_CODE_ENV_MAX) { + exception = acpi_gbl_exception_names_env[sub_status]; + } + break; + + case AE_CODE_PROGRAMMER: + + if (sub_status <= AE_CODE_PGM_MAX) { + exception = + acpi_gbl_exception_names_pgm[sub_status - 1]; + } + break; + + case AE_CODE_ACPI_TABLES: + + if (sub_status <= AE_CODE_TBL_MAX) { + exception = + acpi_gbl_exception_names_tbl[sub_status - 1]; + } + break; + + case AE_CODE_AML: + + if (sub_status <= AE_CODE_AML_MAX) { + exception = + acpi_gbl_exception_names_aml[sub_status - 1]; + } + break; + + case AE_CODE_CONTROL: + + if (sub_status <= AE_CODE_CTRL_MAX) { + exception = + acpi_gbl_exception_names_ctrl[sub_status - 1]; + } + break; + + default: + break; + } + + return (ACPI_CAST_PTR(const char, exception)); +} + +/******************************************************************************* + * * FUNCTION: acpi_ut_is_aml_table * * PARAMETERS: Table - An ACPI table @@ -62,14 +134,15 @@ ACPI_MODULE_NAME("utmisc") * data tables that do not contain AML code. * ******************************************************************************/ + u8 acpi_ut_is_aml_table(struct acpi_table_header *table) { /* These are the only tables that contain executable AML */ - if (ACPI_COMPARE_NAME(table->signature, DSDT_SIG) || - ACPI_COMPARE_NAME(table->signature, PSDT_SIG) || - ACPI_COMPARE_NAME(table->signature, SSDT_SIG)) { + if (ACPI_COMPARE_NAME(table->signature, ACPI_SIG_DSDT) || + ACPI_COMPARE_NAME(table->signature, ACPI_SIG_PSDT) || + ACPI_COMPARE_NAME(table->signature, ACPI_SIG_SSDT)) { return (TRUE); } @@ -418,7 +491,7 @@ u32 acpi_ut_dword_byte_swap(u32 value) void acpi_ut_set_integer_width(u8 revision) { - if (revision <= 1) { + if (revision < 2) { /* 32-bit case */ @@ -582,26 +655,25 @@ u8 acpi_ut_valid_acpi_name(u32 name) * ******************************************************************************/ -acpi_name acpi_ut_repair_name(acpi_name name) +acpi_name acpi_ut_repair_name(char *name) { - char *name_ptr = ACPI_CAST_PTR(char, &name); - char new_name[ACPI_NAME_SIZE]; acpi_native_uint i; + char new_name[ACPI_NAME_SIZE]; for (i = 0; i < ACPI_NAME_SIZE; i++) { - new_name[i] = name_ptr[i]; + new_name[i] = name[i]; /* * Replace a bad character with something printable, yet technically * still invalid. This prevents any collisions with existing "good" * names in the namespace. */ - if (!acpi_ut_valid_acpi_char(name_ptr[i], i)) { + if (!acpi_ut_valid_acpi_char(name[i], i)) { new_name[i] = '*'; } } - return (*ACPI_CAST_PTR(u32, new_name)); + return (*(u32 *) new_name); } /******************************************************************************* @@ -996,9 +1068,13 @@ acpi_ut_info(char *module_name, u32 line { va_list args; - acpi_os_printf("ACPI (%s-%04d): ", module_name, line_number); + /* + * Removed module_name, line_number, and acpica version, not needed + * for info output + */ + acpi_os_printf("ACPI: "); va_start(args, format); acpi_os_vprintf(format, args); - acpi_os_printf(" [%X]\n", ACPI_CA_VERSION); + acpi_os_printf("\n"); } diff --git a/drivers/acpi/utilities/utmutex.c b/drivers/acpi/utilities/utmutex.c index 180e73c..cbad2ef 100644 --- a/drivers/acpi/utilities/utmutex.c +++ b/drivers/acpi/utilities/utmutex.c @@ -5,7 +5,7 @@ ******************************************************************************/ /* - * Copyright (C) 2000 - 2006, R. Byron Moore + * Copyright (C) 2000 - 2007, R. Byron Moore * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/utilities/utobject.c b/drivers/acpi/utilities/utobject.c index ba7d8ac..4696124 100644 --- a/drivers/acpi/utilities/utobject.c +++ b/drivers/acpi/utilities/utobject.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2006, R. Byron Moore + * Copyright (C) 2000 - 2007, R. Byron Moore * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/utilities/utresrc.c b/drivers/acpi/utilities/utresrc.c index 5a2de92..e8fe1ba 100644 --- a/drivers/acpi/utilities/utresrc.c +++ b/drivers/acpi/utilities/utresrc.c @@ -5,7 +5,7 @@ ******************************************************************************/ /* - * Copyright (C) 2000 - 2006, R. Byron Moore + * Copyright (C) 2000 - 2007, R. Byron Moore * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/utilities/utstate.c b/drivers/acpi/utilities/utstate.c index eaa13d0..edcaafa 100644 --- a/drivers/acpi/utilities/utstate.c +++ b/drivers/acpi/utilities/utstate.c @@ -5,7 +5,7 @@ ******************************************************************************/ /* - * Copyright (C) 2000 - 2006, R. Byron Moore + * Copyright (C) 2000 - 2007, R. Byron Moore * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/utilities/utxface.c b/drivers/acpi/utilities/utxface.c index 3538f69..de3276f 100644 --- a/drivers/acpi/utilities/utxface.c +++ b/drivers/acpi/utilities/utxface.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2006, R. Byron Moore + * Copyright (C) 2000 - 2007, R. Byron Moore * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -67,6 +67,7 @@ acpi_status acpi_initialize_subsystem(vo ACPI_FUNCTION_TRACE(acpi_initialize_subsystem); + acpi_gbl_startup_flags = ACPI_SUBSYSTEM_INITIALIZE; ACPI_DEBUG_EXEC(acpi_ut_init_stack_ptr_trace()); /* Initialize the OS-Dependent layer */ @@ -127,20 +128,6 @@ acpi_status acpi_enable_subsystem(u32 fl ACPI_FUNCTION_TRACE(acpi_enable_subsystem); - /* - * We must initialize the hardware before we can enable ACPI. - * The values from the FADT are validated here. - */ - if (!(flags & ACPI_NO_HARDWARE_INIT)) { - ACPI_DEBUG_PRINT((ACPI_DB_EXEC, - "[Init] Initializing ACPI hardware\n")); - - status = acpi_hw_initialize(); - if (ACPI_FAILURE(status)) { - return_ACPI_STATUS(status); - } - } - /* Enable ACPI mode */ if (!(flags & ACPI_NO_ACPI_ENABLE)) { @@ -398,7 +385,6 @@ acpi_status acpi_get_system_info(struct { struct acpi_system_info *info_ptr; acpi_status status; - u32 i; ACPI_FUNCTION_TRACE(acpi_get_system_info); @@ -431,9 +417,7 @@ acpi_status acpi_get_system_info(struct /* Timer resolution - 24 or 32 bits */ - if (!acpi_gbl_FADT) { - info_ptr->timer_resolution = 0; - } else if (acpi_gbl_FADT->tmr_val_ext == 0) { + if (acpi_gbl_FADT.flags & ACPI_FADT_32BIT_TIMER) { info_ptr->timer_resolution = 24; } else { info_ptr->timer_resolution = 32; @@ -449,13 +433,6 @@ acpi_status acpi_get_system_info(struct info_ptr->debug_layer = acpi_dbg_layer; info_ptr->debug_level = acpi_dbg_level; - /* Current status of the ACPI tables, per table type */ - - info_ptr->num_table_types = ACPI_TABLE_ID_MAX + 1; - for (i = 0; i < (ACPI_TABLE_ID_MAX + 1); i++) { - info_ptr->table_info[i].count = acpi_gbl_table_lists[i].count; - } - return_ACPI_STATUS(AE_OK); } diff --git a/drivers/acpi/video.c b/drivers/acpi/video.c index 3d54680..e0b97ad 100644 --- a/drivers/acpi/video.c +++ b/drivers/acpi/video.c @@ -32,6 +32,7 @@ #include #include #include +#include #include #include @@ -56,6 +57,12 @@ #define ACPI_VIDEO_NOTIFY_DISPLAY_OFF 0 #define ACPI_VIDEO_HEAD_INVALID (~0u - 1) #define ACPI_VIDEO_HEAD_END (~0u) +#define MAX_NAME_LEN 20 + +#define ACPI_VIDEO_DISPLAY_CRT 1 +#define ACPI_VIDEO_DISPLAY_TV 2 +#define ACPI_VIDEO_DISPLAY_DVI 3 +#define ACPI_VIDEO_DISPLAY_LCD 4 #define _COMPONENT ACPI_VIDEO_COMPONENT ACPI_MODULE_NAME("acpi_video") @@ -66,16 +73,14 @@ MODULE_LICENSE("GPL"); static int acpi_video_bus_add(struct acpi_device *device); static int acpi_video_bus_remove(struct acpi_device *device, int type); -static int acpi_video_bus_match(struct acpi_device *device, - struct acpi_driver *driver); static struct acpi_driver acpi_video_bus = { .name = ACPI_VIDEO_DRIVER_NAME, .class = ACPI_VIDEO_CLASS, + .ids = ACPI_VIDEO_HID, .ops = { .add = acpi_video_bus_add, .remove = acpi_video_bus_remove, - .match = acpi_video_bus_match, }, }; @@ -133,20 +138,21 @@ struct acpi_video_device_flags { u8 crt:1; u8 lcd:1; u8 tvout:1; + u8 dvi:1; u8 bios:1; u8 unknown:1; - u8 reserved:3; + u8 reserved:2; }; struct acpi_video_device_cap { u8 _ADR:1; /*Return the unique ID */ u8 _BCL:1; /*Query list of brightness control levels supported */ u8 _BCM:1; /*Set the brightness level */ + u8 _BQC:1; /* Get current brightness level */ u8 _DDC:1; /*Return the EDID for this device */ u8 _DCS:1; /*Return status of output device */ u8 _DGS:1; /*Query graphics state */ u8 _DSS:1; /*Device state set */ - u8 _reserved:1; }; struct acpi_video_device_brightness { @@ -163,6 +169,8 @@ struct acpi_video_device { struct acpi_video_bus *video; struct acpi_device *dev; struct acpi_video_device_brightness *brightness; + struct backlight_device *backlight; + struct backlight_properties *data; }; /* bus */ @@ -257,11 +265,35 @@ static void acpi_video_device_bind(struc struct acpi_video_device *device); static int acpi_video_device_enumerate(struct acpi_video_bus *video); static int acpi_video_switch_output(struct acpi_video_bus *video, int event); +static int acpi_video_device_lcd_set_level(struct acpi_video_device *device, + int level); +static int acpi_video_device_lcd_get_level_current( + struct acpi_video_device *device, + unsigned long *level); static int acpi_video_get_next_level(struct acpi_video_device *device, u32 level_current, u32 event); static void acpi_video_switch_brightness(struct acpi_video_device *device, int event); +/*backlight device sysfs support*/ +static int acpi_video_get_brightness(struct backlight_device *bd) +{ + unsigned long cur_level; + struct acpi_video_device *vd = + (struct acpi_video_device *)class_get_devdata(&bd->class_dev); + acpi_video_device_lcd_get_level_current(vd, &cur_level); + return (int) cur_level; +} + +static int acpi_video_set_brightness(struct backlight_device *bd) +{ + int request_level = bd->props->brightness; + struct acpi_video_device *vd = + (struct acpi_video_device *)class_get_devdata(&bd->class_dev); + acpi_video_device_lcd_set_level(vd, request_level); + return 0; +} + /* -------------------------------------------------------------------------- Video Management -------------------------------------------------------------------------- */ @@ -499,6 +531,7 @@ static void acpi_video_device_find_cap(s acpi_integer status; acpi_handle h_dummy1; int i; + u32 max_level = 0; union acpi_object *obj = NULL; struct acpi_video_device_brightness *br = NULL; @@ -514,6 +547,8 @@ static void acpi_video_device_find_cap(s if (ACPI_SUCCESS(acpi_get_handle(device->dev->handle, "_BCM", &h_dummy1))) { device->cap._BCM = 1; } + if (ACPI_SUCCESS(acpi_get_handle(device->dev->handle,"_BQC",&h_dummy1))) + device->cap._BQC = 1; if (ACPI_SUCCESS(acpi_get_handle(device->dev->handle, "_DDC", &h_dummy1))) { device->cap._DDC = 1; } @@ -550,6 +585,8 @@ static void acpi_video_device_find_cap(s continue; } br->levels[count] = (u32) o->integer.value; + if (br->levels[count] > max_level) + max_level = br->levels[count]; count++; } out: @@ -568,6 +605,37 @@ static void acpi_video_device_find_cap(s kfree(obj); + if (device->cap._BCL && device->cap._BCM && device->cap._BQC){ + unsigned long tmp; + static int count = 0; + char *name; + struct backlight_properties *acpi_video_data; + + name = kzalloc(MAX_NAME_LEN, GFP_KERNEL); + if (!name) + return; + + acpi_video_data = kzalloc( + sizeof(struct backlight_properties), + GFP_KERNEL); + if (!acpi_video_data){ + kfree(name); + return; + } + acpi_video_data->owner = THIS_MODULE; + acpi_video_data->get_brightness = + acpi_video_get_brightness; + acpi_video_data->update_status = + acpi_video_set_brightness; + sprintf(name, "acpi_video%d", count++); + device->data = acpi_video_data; + acpi_video_data->max_brightness = max_level; + acpi_video_device_lcd_get_level_current(device, &tmp); + acpi_video_data->brightness = (int)tmp; + device->backlight = backlight_device_register(name, + NULL, device, acpi_video_data); + kfree(name); + } return; } @@ -668,6 +736,8 @@ static int acpi_video_device_info_seq_sh seq_printf(seq, "LCD\n"); else if (dev->flags.tvout) seq_printf(seq, "TVOUT\n"); + else if (dev->flags.dvi) + seq_printf(seq, "DVI\n"); else seq_printf(seq, "UNKNOWN\n"); @@ -1242,6 +1312,16 @@ static int acpi_video_bus_remove_fs(stru -------------------------------------------------------------------------- */ /* device interface */ +static struct acpi_video_device_attrib* +acpi_video_get_device_attr(struct acpi_video_bus *video, unsigned long device_id) +{ + int count; + + for(count = 0; count < video->attached_count; count++) + if((video->attached_array[count].value.int_val & 0xffff) == device_id) + return &(video->attached_array[count].value.attrib); + return NULL; +} static int acpi_video_bus_get_one_device(struct acpi_device *device, @@ -1250,7 +1330,7 @@ acpi_video_bus_get_one_device(struct acp unsigned long device_id; int status; struct acpi_video_device *data; - + struct acpi_video_device_attrib* attribute; if (!device || !video) return -EINVAL; @@ -1271,20 +1351,30 @@ acpi_video_bus_get_one_device(struct acp data->video = video; data->dev = device; - switch (device_id & 0xffff) { - case 0x0100: - data->flags.crt = 1; - break; - case 0x0400: - data->flags.lcd = 1; - break; - case 0x0200: - data->flags.tvout = 1; - break; - default: + attribute = acpi_video_get_device_attr(video, device_id); + + if((attribute != NULL) && attribute->device_id_scheme) { + switch (attribute->display_type) { + case ACPI_VIDEO_DISPLAY_CRT: + data->flags.crt = 1; + break; + case ACPI_VIDEO_DISPLAY_TV: + data->flags.tvout = 1; + break; + case ACPI_VIDEO_DISPLAY_DVI: + data->flags.dvi = 1; + break; + case ACPI_VIDEO_DISPLAY_LCD: + data->flags.lcd = 1; + break; + default: + data->flags.unknown = 1; + break; + } + if(attribute->bios_can_detect) + data->flags.bios = 1; + } else data->flags.unknown = 1; - break; - } acpi_video_device_bind(video, data); acpi_video_device_find_cap(data); @@ -1588,7 +1678,10 @@ static int acpi_video_bus_put_one_device status = acpi_remove_notify_handler(device->dev->handle, ACPI_DEVICE_NOTIFY, acpi_video_device_notify); - + if (device->backlight){ + backlight_device_unregister(device->backlight); + kfree(device->data); + } return 0; } @@ -1790,39 +1883,6 @@ static int acpi_video_bus_remove(struct return 0; } -static int -acpi_video_bus_match(struct acpi_device *device, struct acpi_driver *driver) -{ - acpi_handle h_dummy1; - acpi_handle h_dummy2; - acpi_handle h_dummy3; - - - if (!device || !driver) - return -EINVAL; - - /* Since there is no HID, CID for ACPI Video drivers, we have - * to check well known required nodes for each feature we support. - */ - - /* Does this device able to support video switching ? */ - if (ACPI_SUCCESS(acpi_get_handle(device->handle, "_DOD", &h_dummy1)) && - ACPI_SUCCESS(acpi_get_handle(device->handle, "_DOS", &h_dummy2))) - return 0; - - /* Does this device able to retrieve a video ROM ? */ - if (ACPI_SUCCESS(acpi_get_handle(device->handle, "_ROM", &h_dummy1))) - return 0; - - /* Does this device able to configure which video head to be POSTed ? */ - if (ACPI_SUCCESS(acpi_get_handle(device->handle, "_VPO", &h_dummy1)) && - ACPI_SUCCESS(acpi_get_handle(device->handle, "_GPD", &h_dummy2)) && - ACPI_SUCCESS(acpi_get_handle(device->handle, "_SPD", &h_dummy3))) - return 0; - - return -ENODEV; -} - static int __init acpi_video_init(void) { int result = 0; diff --git a/drivers/ata/Kconfig b/drivers/ata/Kconfig index 1c94b43..3747457 100644 --- a/drivers/ata/Kconfig +++ b/drivers/ata/Kconfig @@ -41,12 +41,12 @@ config SATA_SVW If unsure, say N. config ATA_PIIX - tristate "Intel PIIX/ICH SATA support" + tristate "Intel ESB, ICH, PIIX3, PIIX4 PATA/SATA support" depends on PCI help This option enables support for ICH5/6/7/8 Serial ATA - and support for PATA on the Intel PIIX3/PIIX4/ICH series - PATA host controllers. + and support for PATA on the Intel ESB/ICH/PIIX3/PIIX4 series + host controllers. If unsure, say N. @@ -116,11 +116,14 @@ config SATA_SIL24 If unsure, say N. config SATA_SIS - tristate "SiS 964/180 SATA support" + tristate "SiS 964/965/966/180 SATA support" depends on PCI + select PATA_SIS help - This option enables support for SiS Serial ATA 964/180. - + This option enables support for SiS Serial ATA on + SiS 964/965/966/180 and Parallel ATA on SiS 180. + The PATA support for SiS 180 requires additionally to + enable the PATA_SIS driver in the config. If unsure, say N. config SATA_ULI @@ -147,6 +150,12 @@ config SATA_VITESSE If unsure, say N. +config SATA_INIC162X + tristate "Initio 162x SATA support (HIGHLY EXPERIMENTAL)" + depends on PCI && EXPERIMENTAL + help + This option enables support for Initio 162x Serial ATA. + config SATA_INTEL_COMBINED bool depends on IDE=y && !BLK_DEV_IDE_SATA && (SATA_AHCI || ATA_PIIX) @@ -296,7 +305,7 @@ config PATA_ISAPNP If unsure, say N. config PATA_IT821X - tristate "IT821x PATA support (Experimental)" + tristate "IT8211/2 PATA support (Experimental)" depends on PCI && EXPERIMENTAL help This option enables support for the ITE 8211 and 8212 @@ -305,6 +314,15 @@ config PATA_IT821X If unsure, say N. +config PATA_IT8213 + tristate "IT8213 PATA support (Experimental)" + depends on PCI && EXPERIMENTAL + help + This option enables support for the ITE 821 PATA + controllers via the new ATA layer. + + If unsure, say N. + config PATA_JMICRON tristate "JMicron PATA support" depends on PCI @@ -341,6 +359,15 @@ config PATA_MARVELL If unsure, say N. +config PATA_MPC52xx + tristate "Freescale MPC52xx SoC internal IDE" + depends on PPC_MPC52xx + help + This option enables support for integrated IDE controller + of the Freescale MPC52xx SoC. + + If unsure, say N. + config PATA_MPIIX tristate "Intel PATA MPIIX support" depends on PCI diff --git a/drivers/ata/Makefile b/drivers/ata/Makefile index bc3d81a..cd096f0 100644 --- a/drivers/ata/Makefile +++ b/drivers/ata/Makefile @@ -15,6 +15,7 @@ obj-$(CONFIG_SATA_SX4) += sata_sx4.o obj-$(CONFIG_SATA_NV) += sata_nv.o obj-$(CONFIG_SATA_ULI) += sata_uli.o obj-$(CONFIG_SATA_MV) += sata_mv.o +obj-$(CONFIG_SATA_INIC162X) += sata_inic162x.o obj-$(CONFIG_PDC_ADMA) += pdc_adma.o obj-$(CONFIG_PATA_ALI) += pata_ali.o @@ -33,11 +34,13 @@ obj-$(CONFIG_PATA_HPT3X2N) += pata_hpt3x obj-$(CONFIG_PATA_HPT3X3) += pata_hpt3x3.o obj-$(CONFIG_PATA_ISAPNP) += pata_isapnp.o obj-$(CONFIG_PATA_IT821X) += pata_it821x.o +obj-$(CONFIG_PATA_IT8213) += pata_it8213.o obj-$(CONFIG_PATA_JMICRON) += pata_jmicron.o obj-$(CONFIG_PATA_NETCELL) += pata_netcell.o obj-$(CONFIG_PATA_NS87410) += pata_ns87410.o obj-$(CONFIG_PATA_OPTI) += pata_opti.o obj-$(CONFIG_PATA_OPTIDMA) += pata_optidma.o +obj-$(CONFIG_PATA_MPC52xx) += pata_mpc52xx.o obj-$(CONFIG_PATA_MARVELL) += pata_marvell.o obj-$(CONFIG_PATA_MPIIX) += pata_mpiix.o obj-$(CONFIG_PATA_OLDPIIX) += pata_oldpiix.o diff --git a/drivers/ata/ahci.c b/drivers/ata/ahci.c index 48616c6..6a3543e 100644 --- a/drivers/ata/ahci.c +++ b/drivers/ata/ahci.c @@ -39,13 +39,11 @@ #include #include #include #include -#include #include #include #include #include #include -#include #define DRV_NAME "ahci" #define DRV_VERSION "2.0" @@ -166,9 +164,6 @@ enum { PORT_CMD_ICC_PARTIAL = (0x2 << 28), /* Put i/f in partial state */ PORT_CMD_ICC_SLUMBER = (0x6 << 28), /* Put i/f in slumber state */ - /* hpriv->flags bits */ - AHCI_FLAG_MSI = (1 << 0), - /* ap->flags bits */ AHCI_FLAG_NO_NCQ = (1 << 24), AHCI_FLAG_IGN_IRQ_IF_ERR = (1 << 25), /* ignore IRQ_IF_ERR */ @@ -191,7 +186,6 @@ struct ahci_sg { }; struct ahci_host_priv { - unsigned long flags; u32 cap; /* cache of HOST_CAP register */ u32 port_map; /* cache of HOST_PORTS_IMPL reg */ }; @@ -229,7 +223,6 @@ static int ahci_port_suspend(struct ata_ static int ahci_port_resume(struct ata_port *ap); static int ahci_pci_device_suspend(struct pci_dev *pdev, pm_message_t mesg); static int ahci_pci_device_resume(struct pci_dev *pdev); -static void ahci_remove_one (struct pci_dev *pdev); static struct scsi_host_template ahci_sht = { .module = THIS_MODULE, @@ -266,6 +259,8 @@ static const struct ata_port_operations .irq_handler = ahci_interrupt, .irq_clear = ahci_irq_clear, + .irq_on = ata_dummy_irq_on, + .irq_ack = ata_dummy_irq_ack, .scr_read = ahci_scr_read, .scr_write = ahci_scr_write, @@ -297,6 +292,8 @@ static const struct ata_port_operations .irq_handler = ahci_interrupt, .irq_clear = ahci_irq_clear, + .irq_on = ata_dummy_irq_on, + .irq_ack = ata_dummy_irq_ack, .scr_read = ahci_scr_read, .scr_write = ahci_scr_write, @@ -431,7 +428,7 @@ static const struct pci_device_id ahci_p /* Generic, PCI class code for AHCI */ { PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID, - 0x010601, 0xffffff, board_ahci }, + PCI_CLASS_STORAGE_SATA_AHCI, 0xffffff, board_ahci }, { } /* terminate list */ }; @@ -441,9 +438,9 @@ static struct pci_driver ahci_pci_driver .name = DRV_NAME, .id_table = ahci_pci_tbl, .probe = ahci_init_one, + .remove = ata_pci_remove_one, .suspend = ahci_pci_device_suspend, .resume = ahci_pci_device_resume, - .remove = ahci_remove_one, }; @@ -452,16 +449,12 @@ static inline int ahci_nr_ports(u32 cap) return (cap & 0x1f) + 1; } -static inline unsigned long ahci_port_base_ul (unsigned long base, unsigned int port) +static inline void __iomem *ahci_port_base(void __iomem *base, + unsigned int port) { return base + 0x100 + (port * 0x80); } -static inline void __iomem *ahci_port_base (void __iomem *base, unsigned int port) -{ - return (void __iomem *) ahci_port_base_ul((unsigned long)base, port); -} - static u32 ahci_scr_read (struct ata_port *ap, unsigned int sc_reg_in) { unsigned int sc_reg; @@ -475,7 +468,7 @@ static u32 ahci_scr_read (struct ata_por return 0xffffffffU; } - return readl((void __iomem *) ap->ioaddr.scr_addr + (sc_reg * 4)); + return readl(ap->ioaddr.scr_addr + (sc_reg * 4)); } @@ -493,7 +486,7 @@ static void ahci_scr_write (struct ata_p return; } - writel(val, (void __iomem *) ap->ioaddr.scr_addr + (sc_reg * 4)); + writel(val, ap->ioaddr.scr_addr + (sc_reg * 4)); } static void ahci_start_engine(void __iomem *port_mmio) @@ -735,7 +728,7 @@ static void ahci_init_controller(void __ static unsigned int ahci_dev_classify(struct ata_port *ap) { - void __iomem *port_mmio = (void __iomem *) ap->ioaddr.cmd_addr; + void __iomem *port_mmio = ap->ioaddr.cmd_addr; struct ata_taskfile tf; u32 tmp; @@ -763,7 +756,7 @@ static void ahci_fill_cmd_slot(struct ah static int ahci_clo(struct ata_port *ap) { - void __iomem *port_mmio = (void __iomem *) ap->ioaddr.cmd_addr; + void __iomem *port_mmio = ap->ioaddr.cmd_addr; struct ahci_host_priv *hpriv = ap->host->private_data; u32 tmp; @@ -785,7 +778,7 @@ static int ahci_clo(struct ata_port *ap) static int ahci_softreset(struct ata_port *ap, unsigned int *class) { struct ahci_port_priv *pp = ap->private_data; - void __iomem *mmio = ap->host->mmio_base; + void __iomem *mmio = ap->host->iomap[AHCI_PCI_BAR]; void __iomem *port_mmio = ahci_port_base(mmio, ap->port_no); const u32 cmd_fis_len = 5; /* five dwords */ const char *reason = NULL; @@ -893,7 +886,7 @@ static int ahci_hardreset(struct ata_por struct ahci_port_priv *pp = ap->private_data; u8 *d2h_fis = pp->rx_fis + RX_FIS_D2H_REG; struct ata_taskfile tf; - void __iomem *mmio = ap->host->mmio_base; + void __iomem *mmio = ap->host->iomap[AHCI_PCI_BAR]; void __iomem *port_mmio = ahci_port_base(mmio, ap->port_no); int rc; @@ -921,7 +914,7 @@ static int ahci_hardreset(struct ata_por static int ahci_vt8251_hardreset(struct ata_port *ap, unsigned int *class) { - void __iomem *mmio = ap->host->mmio_base; + void __iomem *mmio = ap->host->iomap[AHCI_PCI_BAR]; void __iomem *port_mmio = ahci_port_base(mmio, ap->port_no); int rc; @@ -946,7 +939,7 @@ static int ahci_vt8251_hardreset(struct static void ahci_postreset(struct ata_port *ap, unsigned int *class) { - void __iomem *port_mmio = (void __iomem *) ap->ioaddr.cmd_addr; + void __iomem *port_mmio = ap->ioaddr.cmd_addr; u32 new_tmp, tmp; ata_std_postreset(ap, class); @@ -965,7 +958,7 @@ static void ahci_postreset(struct ata_po static u8 ahci_check_status(struct ata_port *ap) { - void __iomem *mmio = (void __iomem *) ap->ioaddr.cmd_addr; + void __iomem *mmio = ap->ioaddr.cmd_addr; return readl(mmio + PORT_TFDATA) & 0xFF; } @@ -1111,7 +1104,7 @@ static void ahci_error_intr(struct ata_p static void ahci_host_intr(struct ata_port *ap) { - void __iomem *mmio = ap->host->mmio_base; + void __iomem *mmio = ap->host->iomap[AHCI_PCI_BAR]; void __iomem *port_mmio = ahci_port_base(mmio, ap->port_no); struct ata_eh_info *ehi = &ap->eh_info; struct ahci_port_priv *pp = ap->private_data; @@ -1173,7 +1166,7 @@ static void ahci_host_intr(struct ata_po * dangerous, we need to know more about them. Print * more of it. */ - const u32 *f = pp->rx_fis + RX_FIS_SDB; + const __le32 *f = pp->rx_fis + RX_FIS_SDB; ata_port_printk(ap, KERN_INFO, "Spurious SDB FIS during NCQ " "issue=0x%x SAct=0x%x FIS=%08x:%08x%s\n", @@ -1209,7 +1202,7 @@ static irqreturn_t ahci_interrupt(int ir VPRINTK("ENTER\n"); hpriv = host->private_data; - mmio = host->mmio_base; + mmio = host->iomap[AHCI_PCI_BAR]; /* sigh. 0xffffffff is a valid return from h/w */ irq_stat = readl(mmio + HOST_IRQ_STAT); @@ -1254,7 +1247,7 @@ static irqreturn_t ahci_interrupt(int ir static unsigned int ahci_qc_issue(struct ata_queued_cmd *qc) { struct ata_port *ap = qc->ap; - void __iomem *port_mmio = (void __iomem *) ap->ioaddr.cmd_addr; + void __iomem *port_mmio = ap->ioaddr.cmd_addr; if (qc->tf.protocol == ATA_PROT_NCQ) writel(1 << qc->tag, port_mmio + PORT_SCR_ACT); @@ -1266,7 +1259,7 @@ static unsigned int ahci_qc_issue(struct static void ahci_freeze(struct ata_port *ap) { - void __iomem *mmio = ap->host->mmio_base; + void __iomem *mmio = ap->host->iomap[AHCI_PCI_BAR]; void __iomem *port_mmio = ahci_port_base(mmio, ap->port_no); /* turn IRQ off */ @@ -1275,7 +1268,7 @@ static void ahci_freeze(struct ata_port static void ahci_thaw(struct ata_port *ap) { - void __iomem *mmio = ap->host->mmio_base; + void __iomem *mmio = ap->host->iomap[AHCI_PCI_BAR]; void __iomem *port_mmio = ahci_port_base(mmio, ap->port_no); u32 tmp; @@ -1290,7 +1283,7 @@ static void ahci_thaw(struct ata_port *a static void ahci_error_handler(struct ata_port *ap) { - void __iomem *mmio = ap->host->mmio_base; + void __iomem *mmio = ap->host->iomap[AHCI_PCI_BAR]; void __iomem *port_mmio = ahci_port_base(mmio, ap->port_no); if (!(ap->pflags & ATA_PFLAG_FROZEN)) { @@ -1306,7 +1299,7 @@ static void ahci_error_handler(struct at static void ahci_vt8251_error_handler(struct ata_port *ap) { - void __iomem *mmio = ap->host->mmio_base; + void __iomem *mmio = ap->host->iomap[AHCI_PCI_BAR]; void __iomem *port_mmio = ahci_port_base(mmio, ap->port_no); if (!(ap->pflags & ATA_PFLAG_FROZEN)) { @@ -1323,7 +1316,7 @@ static void ahci_vt8251_error_handler(st static void ahci_post_internal_cmd(struct ata_queued_cmd *qc) { struct ata_port *ap = qc->ap; - void __iomem *mmio = ap->host->mmio_base; + void __iomem *mmio = ap->host->iomap[AHCI_PCI_BAR]; void __iomem *port_mmio = ahci_port_base(mmio, ap->port_no); if (qc->flags & ATA_QCFLAG_FAILED) @@ -1340,7 +1333,7 @@ static int ahci_port_suspend(struct ata_ { struct ahci_host_priv *hpriv = ap->host->private_data; struct ahci_port_priv *pp = ap->private_data; - void __iomem *mmio = ap->host->mmio_base; + void __iomem *mmio = ap->host->iomap[AHCI_PCI_BAR]; void __iomem *port_mmio = ahci_port_base(mmio, ap->port_no); const char *emsg = NULL; int rc; @@ -1361,7 +1354,7 @@ static int ahci_port_resume(struct ata_p { struct ahci_port_priv *pp = ap->private_data; struct ahci_host_priv *hpriv = ap->host->private_data; - void __iomem *mmio = ap->host->mmio_base; + void __iomem *mmio = ap->host->iomap[AHCI_PCI_BAR]; void __iomem *port_mmio = ahci_port_base(mmio, ap->port_no); ahci_power_up(port_mmio, hpriv->cap); @@ -1373,7 +1366,7 @@ static int ahci_port_resume(struct ata_p static int ahci_pci_device_suspend(struct pci_dev *pdev, pm_message_t mesg) { struct ata_host *host = dev_get_drvdata(&pdev->dev); - void __iomem *mmio = host->mmio_base; + void __iomem *mmio = host->iomap[AHCI_PCI_BAR]; u32 ctl; if (mesg.event == PM_EVENT_SUSPEND) { @@ -1394,10 +1387,12 @@ static int ahci_pci_device_resume(struct { struct ata_host *host = dev_get_drvdata(&pdev->dev); struct ahci_host_priv *hpriv = host->private_data; - void __iomem *mmio = host->mmio_base; + void __iomem *mmio = host->iomap[AHCI_PCI_BAR]; int rc; - ata_pci_device_do_resume(pdev); + rc = ata_pci_device_do_resume(pdev); + if (rc) + return rc; if (pdev->dev.power.power_state.event == PM_EVENT_SUSPEND) { rc = ahci_reset_controller(mmio, pdev); @@ -1418,29 +1413,24 @@ static int ahci_port_start(struct ata_po struct device *dev = ap->host->dev; struct ahci_host_priv *hpriv = ap->host->private_data; struct ahci_port_priv *pp; - void __iomem *mmio = ap->host->mmio_base; + void __iomem *mmio = ap->host->iomap[AHCI_PCI_BAR]; void __iomem *port_mmio = ahci_port_base(mmio, ap->port_no); void *mem; dma_addr_t mem_dma; int rc; - pp = kmalloc(sizeof(*pp), GFP_KERNEL); + pp = devm_kzalloc(dev, sizeof(*pp), GFP_KERNEL); if (!pp) return -ENOMEM; - memset(pp, 0, sizeof(*pp)); rc = ata_pad_alloc(ap, dev); - if (rc) { - kfree(pp); + if (rc) return rc; - } - mem = dma_alloc_coherent(dev, AHCI_PORT_PRIV_DMA_SZ, &mem_dma, GFP_KERNEL); - if (!mem) { - ata_pad_free(ap, dev); - kfree(pp); + mem = dmam_alloc_coherent(dev, AHCI_PORT_PRIV_DMA_SZ, &mem_dma, + GFP_KERNEL); + if (!mem) return -ENOMEM; - } memset(mem, 0, AHCI_PORT_PRIV_DMA_SZ); /* @@ -1482,10 +1472,8 @@ static int ahci_port_start(struct ata_po static void ahci_port_stop(struct ata_port *ap) { - struct device *dev = ap->host->dev; struct ahci_host_priv *hpriv = ap->host->private_data; - struct ahci_port_priv *pp = ap->private_data; - void __iomem *mmio = ap->host->mmio_base; + void __iomem *mmio = ap->host->iomap[AHCI_PCI_BAR]; void __iomem *port_mmio = ahci_port_base(mmio, ap->port_no); const char *emsg = NULL; int rc; @@ -1494,19 +1482,13 @@ static void ahci_port_stop(struct ata_po rc = ahci_deinit_port(port_mmio, hpriv->cap, &emsg); if (rc) ata_port_printk(ap, KERN_WARNING, "%s (%d)\n", emsg, rc); - - ap->private_data = NULL; - dma_free_coherent(dev, AHCI_PORT_PRIV_DMA_SZ, - pp->cmd_slot, pp->cmd_slot_dma); - ata_pad_free(ap, dev); - kfree(pp); } -static void ahci_setup_port(struct ata_ioports *port, unsigned long base, +static void ahci_setup_port(struct ata_ioports *port, void __iomem *base, unsigned int port_idx) { VPRINTK("ENTER, base==0x%lx, port_idx %u\n", base, port_idx); - base = ahci_port_base_ul(base, port_idx); + base = ahci_port_base(base, port_idx); VPRINTK("base now==0x%lx\n", base); port->cmd_addr = base; @@ -1519,7 +1501,7 @@ static int ahci_host_init(struct ata_pro { struct ahci_host_priv *hpriv = probe_ent->private_data; struct pci_dev *pdev = to_pci_dev(probe_ent->dev); - void __iomem *mmio = probe_ent->mmio_base; + void __iomem *mmio = probe_ent->iomap[AHCI_PCI_BAR]; unsigned int i, cap_n_ports, using_dac; int rc; @@ -1586,7 +1568,7 @@ static int ahci_host_init(struct ata_pro } for (i = 0; i < probe_ent->n_ports; i++) - ahci_setup_port(&probe_ent->port[i], (unsigned long) mmio, i); + ahci_setup_port(&probe_ent->port[i], mmio, i); ahci_init_controller(mmio, pdev, probe_ent->n_ports, probe_ent->port_flags, hpriv); @@ -1600,7 +1582,7 @@ static void ahci_print_info(struct ata_p { struct ahci_host_priv *hpriv = probe_ent->private_data; struct pci_dev *pdev = to_pci_dev(probe_ent->dev); - void __iomem *mmio = probe_ent->mmio_base; + void __iomem *mmio = probe_ent->iomap[AHCI_PCI_BAR]; u32 vers, cap, impl, speed; const char *speed_s; u16 cc; @@ -1619,11 +1601,11 @@ static void ahci_print_info(struct ata_p speed_s = "?"; pci_read_config_word(pdev, 0x0a, &cc); - if (cc == 0x0101) + if (cc == PCI_CLASS_STORAGE_IDE) scc_s = "IDE"; - else if (cc == 0x0106) + else if (cc == PCI_CLASS_STORAGE_SATA) scc_s = "SATA"; - else if (cc == 0x0104) + else if (cc == PCI_CLASS_STORAGE_RAID) scc_s = "RAID"; else scc_s = "unknown"; @@ -1667,15 +1649,13 @@ static void ahci_print_info(struct ata_p ); } -static int ahci_init_one (struct pci_dev *pdev, const struct pci_device_id *ent) +static int ahci_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) { static int printed_version; - struct ata_probe_ent *probe_ent = NULL; - struct ahci_host_priv *hpriv; - unsigned long base; - void __iomem *mmio_base; unsigned int board_idx = (unsigned int) ent->driver_data; - int have_msi, pci_dev_busy = 0; + struct device *dev = &pdev->dev; + struct ata_probe_ent *probe_ent; + struct ahci_host_priv *hpriv; int rc; VPRINTK("ENTER\n"); @@ -1685,57 +1665,36 @@ static int ahci_init_one (struct pci_dev if (!printed_version++) dev_printk(KERN_DEBUG, &pdev->dev, "version " DRV_VERSION "\n"); - /* JMicron-specific fixup: make sure we're in AHCI mode */ - /* This is protected from races with ata_jmicron by the pci probe - locking */ if (pdev->vendor == PCI_VENDOR_ID_JMICRON) { - /* AHCI enable, AHCI on function 0 */ - pci_write_config_byte(pdev, 0x41, 0xa1); - /* Function 1 is the PATA controller */ + /* Function 1 is the PATA controller except on the 368, where + we are not AHCI anyway */ if (PCI_FUNC(pdev->devfn)) return -ENODEV; } - rc = pci_enable_device(pdev); + rc = pcim_enable_device(pdev); if (rc) return rc; - rc = pci_request_regions(pdev, DRV_NAME); - if (rc) { - pci_dev_busy = 1; - goto err_out; - } + rc = pcim_iomap_regions(pdev, 1 << AHCI_PCI_BAR, DRV_NAME); + if (rc == -EBUSY) + pcim_pin_device(pdev); + if (rc) + return rc; - if (pci_enable_msi(pdev) == 0) - have_msi = 1; - else { + if (pci_enable_msi(pdev)) pci_intx(pdev, 1); - have_msi = 0; - } - probe_ent = kmalloc(sizeof(*probe_ent), GFP_KERNEL); - if (probe_ent == NULL) { - rc = -ENOMEM; - goto err_out_msi; - } + probe_ent = devm_kzalloc(dev, sizeof(*probe_ent), GFP_KERNEL); + if (probe_ent == NULL) + return -ENOMEM; - memset(probe_ent, 0, sizeof(*probe_ent)); probe_ent->dev = pci_dev_to_dev(pdev); INIT_LIST_HEAD(&probe_ent->node); - mmio_base = pci_iomap(pdev, AHCI_PCI_BAR, 0); - if (mmio_base == NULL) { - rc = -ENOMEM; - goto err_out_free_ent; - } - base = (unsigned long) mmio_base; - - hpriv = kmalloc(sizeof(*hpriv), GFP_KERNEL); - if (!hpriv) { - rc = -ENOMEM; - goto err_out_iounmap; - } - memset(hpriv, 0, sizeof(*hpriv)); + hpriv = devm_kzalloc(dev, sizeof(*hpriv), GFP_KERNEL); + if (!hpriv) + return -ENOMEM; probe_ent->sht = ahci_port_info[board_idx].sht; probe_ent->port_flags = ahci_port_info[board_idx].flags; @@ -1745,16 +1704,13 @@ static int ahci_init_one (struct pci_dev probe_ent->irq = pdev->irq; probe_ent->irq_flags = IRQF_SHARED; - probe_ent->mmio_base = mmio_base; + probe_ent->iomap = pcim_iomap_table(pdev); probe_ent->private_data = hpriv; - if (have_msi) - hpriv->flags |= AHCI_FLAG_MSI; - /* initialize adapter */ rc = ahci_host_init(probe_ent); if (rc) - goto err_out_hpriv; + return rc; if (!(probe_ent->port_flags & AHCI_FLAG_NO_NCQ) && (hpriv->cap & HOST_CAP_NCQ)) @@ -1762,62 +1718,11 @@ static int ahci_init_one (struct pci_dev ahci_print_info(probe_ent); - /* FIXME: check ata_device_add return value */ - ata_device_add(probe_ent); - kfree(probe_ent); + if (!ata_device_add(probe_ent)) + return -ENODEV; + devm_kfree(dev, probe_ent); return 0; - -err_out_hpriv: - kfree(hpriv); -err_out_iounmap: - pci_iounmap(pdev, mmio_base); -err_out_free_ent: - kfree(probe_ent); -err_out_msi: - if (have_msi) - pci_disable_msi(pdev); - else - pci_intx(pdev, 0); - pci_release_regions(pdev); -err_out: - if (!pci_dev_busy) - pci_disable_device(pdev); - return rc; -} - -static void ahci_remove_one (struct pci_dev *pdev) -{ - struct device *dev = pci_dev_to_dev(pdev); - struct ata_host *host = dev_get_drvdata(dev); - struct ahci_host_priv *hpriv = host->private_data; - unsigned int i; - int have_msi; - - for (i = 0; i < host->n_ports; i++) - ata_port_detach(host->ports[i]); - - have_msi = hpriv->flags & AHCI_FLAG_MSI; - free_irq(host->irq, host); - - for (i = 0; i < host->n_ports; i++) { - struct ata_port *ap = host->ports[i]; - - ata_scsi_release(ap->scsi_host); - scsi_host_put(ap->scsi_host); - } - - kfree(hpriv); - pci_iounmap(pdev, host->mmio_base); - kfree(host); - - if (have_msi) - pci_disable_msi(pdev); - else - pci_intx(pdev, 0); - pci_release_regions(pdev); - pci_disable_device(pdev); - dev_set_drvdata(dev, NULL); } static int __init ahci_init(void) diff --git a/drivers/ata/ata_generic.c b/drivers/ata/ata_generic.c index 24af560..be66ea0 100644 --- a/drivers/ata/ata_generic.c +++ b/drivers/ata/ata_generic.c @@ -79,7 +79,7 @@ static int generic_set_mode(struct ata_p /* Bits 5 and 6 indicate if DMA is active on master/slave */ if (ap->ioaddr.bmdma_addr) - dma_enabled = inb(ap->ioaddr.bmdma_addr + ATA_DMA_CMD); + dma_enabled = ioread8(ap->ioaddr.bmdma_addr + ATA_DMA_CMD); for (i = 0; i < ATA_MAX_DEVICES; i++) { struct ata_device *dev = &ap->device[i]; @@ -138,7 +138,7 @@ static struct ata_port_operations generi .bmdma_stop = ata_bmdma_stop, .bmdma_status = ata_bmdma_status, - .data_xfer = ata_pio_data_xfer, + .data_xfer = ata_data_xfer, .freeze = ata_bmdma_freeze, .thaw = ata_bmdma_thaw, @@ -150,10 +150,10 @@ static struct ata_port_operations generi .irq_handler = ata_interrupt, .irq_clear = ata_bmdma_irq_clear, + .irq_on = ata_irq_on, + .irq_ack = ata_irq_ack, .port_start = ata_port_start, - .port_stop = ata_port_stop, - .host_stop = ata_host_stop }; static int all_generic_ide; /* Set to claim all devices */ diff --git a/drivers/ata/ata_piix.c b/drivers/ata/ata_piix.c index 47701b2..4d716c7 100644 --- a/drivers/ata/ata_piix.c +++ b/drivers/ata/ata_piix.c @@ -118,7 +118,7 @@ enum { PIIX_80C_SEC = (1 << 7) | (1 << 6), /* controller IDs */ - piix_pata_33 = 0, /* PIIX3 or 4 at 33Mhz */ + piix_pata_33 = 0, /* PIIX4 at 33Mhz */ ich_pata_33 = 1, /* ICH up to UDMA 33 only */ ich_pata_66 = 2, /* ICH up to 66 Mhz */ ich_pata_100 = 3, /* ICH up to UDMA 100 */ @@ -128,6 +128,7 @@ enum { ich6_sata_ahci = 7, ich6m_sata_ahci = 8, ich8_sata_ahci = 9, + piix_pata_mwdma = 10, /* PIIX3 MWDMA only */ /* constants for mapping table */ P0 = 0, /* port 0 */ @@ -153,7 +154,6 @@ struct piix_host_priv { static int piix_init_one (struct pci_dev *pdev, const struct pci_device_id *ent); -static void piix_host_stop(struct ata_host *host); static void piix_pata_error_handler(struct ata_port *ap); static void ich_pata_error_handler(struct ata_port *ap); static void piix_sata_error_handler(struct ata_port *ap); @@ -164,7 +164,8 @@ static void ich_set_dmamode (struct ata_ static unsigned int in_module_init = 1; static const struct pci_device_id piix_pci_tbl[] = { -#ifdef ATA_ENABLE_PATA + /* Intel PIIX3 for the 430HX etc */ + { 0x8086, 0x7010, PCI_ANY_ID, PCI_ANY_ID, 0, 0, piix_pata_mwdma }, /* Intel PIIX4 for the 430TX/440BX/MX chipset: UDMA 33 */ /* Also PIIX4E (fn3 rev 2) and PIIX4M (fn3 rev 3) */ { 0x8086, 0x7111, PCI_ANY_ID, PCI_ANY_ID, 0, 0, piix_pata_33 }, @@ -202,7 +203,6 @@ #ifdef ATA_ENABLE_PATA /* ICH7/7-R (i945, i975) UDMA 100*/ { 0x8086, 0x27DF, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich_pata_133 }, { 0x8086, 0x269E, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich_pata_100 }, -#endif /* NOTE: The following PCI ids must be kept in sync with the * list in drivers/pci/quirks.c. @@ -297,7 +297,7 @@ static const struct ata_port_operations .bmdma_status = ata_bmdma_status, .qc_prep = ata_qc_prep, .qc_issue = ata_qc_issue_prot, - .data_xfer = ata_pio_data_xfer, + .data_xfer = ata_data_xfer, .freeze = ata_bmdma_freeze, .thaw = ata_bmdma_thaw, @@ -306,10 +306,10 @@ static const struct ata_port_operations .irq_handler = ata_interrupt, .irq_clear = ata_bmdma_irq_clear, + .irq_on = ata_irq_on, + .irq_ack = ata_irq_ack, .port_start = ata_port_start, - .port_stop = ata_port_stop, - .host_stop = piix_host_stop, }; static const struct ata_port_operations ich_pata_ops = { @@ -330,7 +330,7 @@ static const struct ata_port_operations .bmdma_status = ata_bmdma_status, .qc_prep = ata_qc_prep, .qc_issue = ata_qc_issue_prot, - .data_xfer = ata_pio_data_xfer, + .data_xfer = ata_data_xfer, .freeze = ata_bmdma_freeze, .thaw = ata_bmdma_thaw, @@ -339,10 +339,10 @@ static const struct ata_port_operations .irq_handler = ata_interrupt, .irq_clear = ata_bmdma_irq_clear, + .irq_on = ata_irq_on, + .irq_ack = ata_irq_ack, .port_start = ata_port_start, - .port_stop = ata_port_stop, - .host_stop = piix_host_stop, }; static const struct ata_port_operations piix_sata_ops = { @@ -360,7 +360,7 @@ static const struct ata_port_operations .bmdma_status = ata_bmdma_status, .qc_prep = ata_qc_prep, .qc_issue = ata_qc_issue_prot, - .data_xfer = ata_pio_data_xfer, + .data_xfer = ata_data_xfer, .freeze = ata_bmdma_freeze, .thaw = ata_bmdma_thaw, @@ -369,10 +369,10 @@ static const struct ata_port_operations .irq_handler = ata_interrupt, .irq_clear = ata_bmdma_irq_clear, + .irq_on = ata_irq_on, + .irq_ack = ata_irq_ack, .port_start = ata_port_start, - .port_stop = ata_port_stop, - .host_stop = piix_host_stop, }; static const struct piix_map_db ich5_map_db = { @@ -441,7 +441,7 @@ static const struct piix_map_db *piix_ma }; static struct ata_port_info piix_port_info[] = { - /* piix_pata_33: 0: PIIX3 or 4 at 33MHz */ + /* piix_pata_33: 0: PIIX4 at 33MHz */ { .sht = &piix_sht, .flags = PIIX_PATA_FLAGS, @@ -543,6 +543,14 @@ static struct ata_port_info piix_port_in .port_ops = &piix_sata_ops, }, + /* piix_pata_mwdma: 10: PIIX3 MWDMA only */ + { + .sht = &piix_sht, + .flags = PIIX_PATA_FLAGS, + .pio_mask = 0x1f, /* pio0-4 */ + .mwdma_mask = 0x06, /* mwdma1-2 ?? CHECK 0 should be ok but slow */ + .port_ops = &piix_pata_ops, + }, }; static struct pci_bits piix_enable_bits[] = { @@ -569,6 +577,7 @@ struct ich_laptop { static const struct ich_laptop ich_laptop[] = { /* devid, subvendor, subdev */ { 0x27DF, 0x0005, 0x0280 }, /* ICH7 on Acer 5602WLMi */ + { 0x27DF, 0x1025, 0x0110 }, /* ICH7 on Acer 3682WLMi */ /* end marker */ { 0, } }; @@ -632,7 +641,7 @@ static int piix_pata_prereset(struct ata if (!pci_test_config_bits(pdev, &piix_enable_bits[ap->port_no])) return -ENOENT; - + ap->cbl = ATA_CBL_PATA40; return ata_std_prereset(ap); } @@ -776,7 +785,7 @@ static void do_pata_set_dmamode (struct u16 master_data; u8 speed = adev->dma_mode; int devid = adev->devno + 2 * ap->port_no; - u8 udma_enable; + u8 udma_enable = 0; static const /* ISP RTC */ u8 timings[][2] = { { 0, 0 }, @@ -786,7 +795,8 @@ static void do_pata_set_dmamode (struct { 2, 3 }, }; pci_read_config_word(dev, master_port, &master_data); - pci_read_config_byte(dev, 0x48, &udma_enable); + if (ap->udma_mask) + pci_read_config_byte(dev, 0x48, &udma_enable); if (speed >= XFER_UDMA_0) { unsigned int udma = adev->dma_mode - XFER_UDMA_0; @@ -1059,6 +1069,7 @@ static void __devinit piix_init_sata_map static int 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]; struct ata_port_info *ppinfo[2] = { &port_info[0], &port_info[1] }; struct piix_host_priv *hpriv; @@ -1072,7 +1083,7 @@ static int piix_init_one (struct pci_dev if (!in_module_init) return -ENODEV; - hpriv = kzalloc(sizeof(*hpriv), GFP_KERNEL); + hpriv = devm_kzalloc(dev, sizeof(*hpriv), GFP_KERNEL); if (!hpriv) return -ENOMEM; @@ -1122,15 +1133,6 @@ static int piix_init_one (struct pci_dev return ata_pci_init_one(pdev, ppinfo, 2); } -static void piix_host_stop(struct ata_host *host) -{ - struct piix_host_priv *hpriv = host->private_data; - - ata_host_stop(host); - - kfree(hpriv); -} - static int __init piix_init(void) { int rc; diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c index 667acd2..2cf8251 100644 --- a/drivers/ata/libata-core.c +++ b/drivers/ata/libata-core.c @@ -59,6 +59,9 @@ #include #include "libata.h" +#define DRV_VERSION "2.10" /* must be exactly four chars */ + + /* debounce timing parameters in msecs { interval, duration, timeout } */ const unsigned long sata_deb_timing_normal[] = { 5, 100, 2000 }; const unsigned long sata_deb_timing_hotplug[] = { 25, 500, 2000 }; @@ -598,51 +601,7 @@ void ata_dev_disable(struct ata_device * } /** - * ata_pio_devchk - PATA device presence detection - * @ap: ATA channel to examine - * @device: Device to examine (starting at zero) - * - * This technique was originally described in - * Hale Landis's ATADRVR (www.ata-atapi.com), and - * later found its way into the ATA/ATAPI spec. - * - * Write a pattern to the ATA shadow registers, - * and if a device is present, it will respond by - * correctly storing and echoing back the - * ATA shadow register contents. - * - * LOCKING: - * caller. - */ - -static unsigned int ata_pio_devchk(struct ata_port *ap, - unsigned int device) -{ - struct ata_ioports *ioaddr = &ap->ioaddr; - u8 nsect, lbal; - - ap->ops->dev_select(ap, device); - - outb(0x55, ioaddr->nsect_addr); - outb(0xaa, ioaddr->lbal_addr); - - outb(0xaa, ioaddr->nsect_addr); - outb(0x55, ioaddr->lbal_addr); - - outb(0x55, ioaddr->nsect_addr); - outb(0xaa, ioaddr->lbal_addr); - - nsect = inb(ioaddr->nsect_addr); - lbal = inb(ioaddr->lbal_addr); - - if ((nsect == 0x55) && (lbal == 0xaa)) - return 1; /* we found a device */ - - return 0; /* nothing found */ -} - -/** - * ata_mmio_devchk - PATA device presence detection + * ata_devchk - PATA device presence detection * @ap: ATA channel to examine * @device: Device to examine (starting at zero) * @@ -659,25 +618,24 @@ static unsigned int ata_pio_devchk(struc * caller. */ -static unsigned int ata_mmio_devchk(struct ata_port *ap, - unsigned int device) +static unsigned int ata_devchk(struct ata_port *ap, unsigned int device) { struct ata_ioports *ioaddr = &ap->ioaddr; u8 nsect, lbal; ap->ops->dev_select(ap, device); - writeb(0x55, (void __iomem *) ioaddr->nsect_addr); - writeb(0xaa, (void __iomem *) ioaddr->lbal_addr); + iowrite8(0x55, ioaddr->nsect_addr); + iowrite8(0xaa, ioaddr->lbal_addr); - writeb(0xaa, (void __iomem *) ioaddr->nsect_addr); - writeb(0x55, (void __iomem *) ioaddr->lbal_addr); + iowrite8(0xaa, ioaddr->nsect_addr); + iowrite8(0x55, ioaddr->lbal_addr); - writeb(0x55, (void __iomem *) ioaddr->nsect_addr); - writeb(0xaa, (void __iomem *) ioaddr->lbal_addr); + iowrite8(0x55, ioaddr->nsect_addr); + iowrite8(0xaa, ioaddr->lbal_addr); - nsect = readb((void __iomem *) ioaddr->nsect_addr); - lbal = readb((void __iomem *) ioaddr->lbal_addr); + nsect = ioread8(ioaddr->nsect_addr); + lbal = ioread8(ioaddr->lbal_addr); if ((nsect == 0x55) && (lbal == 0xaa)) return 1; /* we found a device */ @@ -686,27 +644,6 @@ static unsigned int ata_mmio_devchk(stru } /** - * ata_devchk - PATA device presence detection - * @ap: ATA channel to examine - * @device: Device to examine (starting at zero) - * - * Dispatch ATA device presence detection, depending - * on whether we are using PIO or MMIO to talk to the - * ATA shadow registers. - * - * LOCKING: - * caller. - */ - -static unsigned int ata_devchk(struct ata_port *ap, - unsigned int device) -{ - if (ap->flags & ATA_FLAG_MMIO) - return ata_mmio_devchk(ap, device); - return ata_pio_devchk(ap, device); -} - -/** * ata_dev_classify - determine device type based on ATA-spec signature * @tf: ATA taskfile register set for device to be identified * @@ -923,11 +860,7 @@ void ata_std_dev_select (struct ata_port else tmp = ATA_DEVICE_OBS | ATA_DEV1; - if (ap->flags & ATA_FLAG_MMIO) { - writeb(tmp, (void __iomem *) ap->ioaddr.device_addr); - } else { - outb(tmp, ap->ioaddr.device_addr); - } + iowrite8(tmp, ap->ioaddr.device_addr); ata_pause(ap); /* needed; also flushes, for mmio */ } @@ -1156,7 +1089,7 @@ void ata_port_flush_task(struct ata_port ata_port_printk(ap, KERN_DEBUG, "%s: EXIT\n", __FUNCTION__); } -void ata_qc_complete_internal(struct ata_queued_cmd *qc) +static void ata_qc_complete_internal(struct ata_queued_cmd *qc) { struct completion *waiting = qc->private_data; @@ -1249,7 +1182,6 @@ unsigned ata_exec_internal_sg(struct ata buflen += sg[i].length; ata_sg_init(qc, sg, n_elem); - qc->nsect = buflen / ATA_SECT_SIZE; qc->nbytes = buflen; } @@ -1292,7 +1224,7 @@ unsigned ata_exec_internal_sg(struct ata if (ap->ops->post_internal_cmd) ap->ops->post_internal_cmd(qc); - if (qc->flags & ATA_QCFLAG_FAILED && !qc->err_mask) { + if ((qc->flags & ATA_QCFLAG_FAILED) && !qc->err_mask) { if (ata_msg_warn(ap)) ata_dev_printk(dev, KERN_WARNING, "zero err_mask for failed " @@ -1478,7 +1410,16 @@ int ata_dev_read_id(struct ata_device *d } tf.protocol = ATA_PROT_PIO; - tf.flags |= ATA_TFLAG_POLLING; /* for polling presence detection */ + + /* Some devices choke if TF registers contain garbage. Make + * sure those are properly initialized. + */ + tf.flags |= ATA_TFLAG_ISADDR | ATA_TFLAG_DEVICE; + + /* Device presence detection is unreliable on some + * controllers. Always poll IDENTIFY if available. + */ + tf.flags |= ATA_TFLAG_POLLING; err_mask = ata_exec_internal(dev, &tf, NULL, DMA_FROM_DEVICE, id, sizeof(id[0]) * ATA_ID_WORDS); @@ -1608,6 +1549,8 @@ int ata_dev_configure(struct ata_device const u16 *id = dev->id; unsigned int xfer_mask; char revbuf[7]; /* XYZ-99\0 */ + char fwrevbuf[ATA_ID_FW_REV_LEN+1]; + char modelbuf[ATA_ID_PROD_LEN+1]; int rc; if (!ata_dev_enabled(dev) && ata_msg_info(ap)) { @@ -1662,6 +1605,16 @@ int ata_dev_configure(struct ata_device dev->n_sectors = ata_id_n_sectors(id); + /* SCSI only uses 4-char revisions, dump full 8 chars from ATA */ + ata_id_c_string(dev->id, fwrevbuf, ATA_ID_FW_REV, + sizeof(fwrevbuf)); + + ata_id_c_string(dev->id, modelbuf, ATA_ID_PROD, + sizeof(modelbuf)); + + if (dev->id[59] & 0x100) + dev->multi_count = dev->id[59] & 0xff; + if (ata_id_has_lba(id)) { const char *lba_desc; char ncq_desc[20]; @@ -1681,13 +1634,16 @@ int ata_dev_configure(struct ata_device ata_dev_config_ncq(dev, ncq_desc, sizeof(ncq_desc)); /* print device info to dmesg */ - if (ata_msg_drv(ap) && print_info) - ata_dev_printk(dev, KERN_INFO, "%s, " - "max %s, %Lu sectors: %s %s\n", - revbuf, - ata_mode_string(xfer_mask), + if (ata_msg_drv(ap) && print_info) { + 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, - lba_desc, ncq_desc); + dev->multi_count, lba_desc, ncq_desc); + } } else { /* CHS */ @@ -1704,22 +1660,17 @@ int ata_dev_configure(struct ata_device } /* print device info to dmesg */ - if (ata_msg_drv(ap) && print_info) - ata_dev_printk(dev, KERN_INFO, "%s, " - "max %s, %Lu sectors: CHS %u/%u/%u\n", - revbuf, - ata_mode_string(xfer_mask), - (unsigned long long)dev->n_sectors, - dev->cylinders, dev->heads, - dev->sectors); - } - - if (dev->id[59] & 0x100) { - dev->multi_count = dev->id[59] & 0xff; - if (ata_msg_drv(ap) && print_info) + if (ata_msg_drv(ap) && print_info) { ata_dev_printk(dev, KERN_INFO, - "ata%u: dev %u multi count %u\n", - ap->id, dev->devno, dev->multi_count); + "%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); + } } dev->cdb_len = 16; @@ -2391,6 +2342,10 @@ static int ata_dev_set_mode(struct ata_d dev->flags |= ATA_DFLAG_PIO; err_mask = ata_dev_set_xfermode(dev); + /* Old CFA may refuse this command, which is just fine */ + if (dev->xfer_shift == ATA_SHIFT_PIO && ata_id_is_cfa(dev->id)) + err_mask &= ~AC_ERR_DEV; + if (err_mask) { ata_dev_printk(dev, KERN_ERR, "failed to set xfermode " "(err_mask=0x%x)\n", err_mask); @@ -2493,7 +2448,7 @@ int ata_set_mode(struct ata_port *ap, st for (i = 0; i < ATA_MAX_DEVICES; i++) { dev = &ap->device[i]; - /* don't udpate suspended devices' xfer mode */ + /* don't update suspended devices' xfer mode */ if (!ata_dev_ready(dev)) continue; @@ -2614,13 +2569,8 @@ static void ata_bus_post_reset(struct at u8 nsect, lbal; ap->ops->dev_select(ap, 1); - if (ap->flags & ATA_FLAG_MMIO) { - nsect = readb((void __iomem *) ioaddr->nsect_addr); - lbal = readb((void __iomem *) ioaddr->lbal_addr); - } else { - nsect = inb(ioaddr->nsect_addr); - lbal = inb(ioaddr->lbal_addr); - } + nsect = ioread8(ioaddr->nsect_addr); + lbal = ioread8(ioaddr->lbal_addr); if ((nsect == 1) && (lbal == 1)) break; if (time_after(jiffies, timeout)) { @@ -2648,19 +2598,11 @@ static unsigned int ata_bus_softreset(st DPRINTK("ata%u: bus reset via SRST\n", ap->id); /* software reset. causes dev0 to be selected */ - if (ap->flags & ATA_FLAG_MMIO) { - writeb(ap->ctl, (void __iomem *) ioaddr->ctl_addr); - udelay(20); /* FIXME: flush */ - writeb(ap->ctl | ATA_SRST, (void __iomem *) ioaddr->ctl_addr); - udelay(20); /* FIXME: flush */ - writeb(ap->ctl, (void __iomem *) ioaddr->ctl_addr); - } else { - outb(ap->ctl, ioaddr->ctl_addr); - udelay(10); - outb(ap->ctl | ATA_SRST, ioaddr->ctl_addr); - udelay(10); - outb(ap->ctl, ioaddr->ctl_addr); - } + iowrite8(ap->ctl, ioaddr->ctl_addr); + udelay(20); /* FIXME: flush */ + iowrite8(ap->ctl | ATA_SRST, ioaddr->ctl_addr); + udelay(20); /* FIXME: flush */ + iowrite8(ap->ctl, ioaddr->ctl_addr); /* spec mandates ">= 2ms" before checking status. * We wait 150ms, because that was the magic delay used for @@ -2745,8 +2687,7 @@ void ata_bus_reset(struct ata_port *ap) ap->device[1].class = ata_dev_try_classify(ap, 1, &err); /* re-enable interrupts */ - if (ap->ioaddr.ctl_addr) /* FIXME: hack. create a hook instead */ - ata_irq_on(ap); + ap->ops->irq_on(ap); /* is double-select really necessary? */ if (ap->device[1].class != ATA_DEV_NONE) @@ -2761,10 +2702,7 @@ void ata_bus_reset(struct ata_port *ap) if (ap->flags & (ATA_FLAG_SATA_RESET | ATA_FLAG_SRST)) { /* set up device control for ATA_FLAG_SATA_RESET */ - if (ap->flags & ATA_FLAG_MMIO) - writeb(ap->ctl, (void __iomem *) ioaddr->ctl_addr); - else - outb(ap->ctl, ioaddr->ctl_addr); + iowrite8(ap->ctl, ioaddr->ctl_addr); } DPRINTK("EXIT\n"); @@ -3098,6 +3036,9 @@ int sata_std_hardreset(struct ata_port * return 0; } + /* wait a while before checking status, see SRST for more info */ + msleep(150); + if (ata_busy_sleep(ap, ATA_TMOUT_BOOT_QUICK, ATA_TMOUT_BOOT)) { ata_port_printk(ap, KERN_ERR, "COMRESET failed (device not ready)\n"); @@ -3138,11 +3079,8 @@ void ata_std_postreset(struct ata_port * sata_scr_write(ap, SCR_ERROR, serror); /* re-enable interrupts */ - if (!ap->ops->error_handler) { - /* FIXME: hack. create a hook instead */ - if (ap->ioaddr.ctl_addr) - ata_irq_on(ap); - } + if (!ap->ops->error_handler) + ap->ops->irq_on(ap); /* is double-select really necessary? */ if (classes[0] != ATA_DEV_NONE) @@ -3157,12 +3095,8 @@ void ata_std_postreset(struct ata_port * } /* set up device control */ - if (ap->ioaddr.ctl_addr) { - if (ap->flags & ATA_FLAG_MMIO) - writeb(ap->ctl, (void __iomem *) ap->ioaddr.ctl_addr); - else - outb(ap->ctl, ap->ioaddr.ctl_addr); - } + if (ap->ioaddr.ctl_addr) + iowrite8(ap->ctl, ap->ioaddr.ctl_addr); DPRINTK("EXIT\n"); } @@ -3187,7 +3121,8 @@ static int ata_dev_same_device(struct at const u16 *new_id) { const u16 *old_id = dev->id; - unsigned char model[2][41], serial[2][21]; + unsigned char model[2][ATA_ID_PROD_LEN + 1]; + unsigned char serial[2][ATA_ID_SERNO_LEN + 1]; u64 new_n_sectors; if (dev->class != new_class) { @@ -3196,10 +3131,10 @@ static int ata_dev_same_device(struct at return 0; } - ata_id_c_string(old_id, model[0], ATA_ID_PROD_OFS, sizeof(model[0])); - ata_id_c_string(new_id, model[1], ATA_ID_PROD_OFS, sizeof(model[1])); - ata_id_c_string(old_id, serial[0], ATA_ID_SERNO_OFS, sizeof(serial[0])); - ata_id_c_string(new_id, serial[1], ATA_ID_SERNO_OFS, sizeof(serial[1])); + ata_id_c_string(old_id, model[0], ATA_ID_PROD, sizeof(model[0])); + ata_id_c_string(new_id, model[1], ATA_ID_PROD, sizeof(model[1])); + ata_id_c_string(old_id, serial[0], ATA_ID_SERNO, sizeof(serial[0])); + ata_id_c_string(new_id, serial[1], ATA_ID_SERNO, sizeof(serial[1])); new_n_sectors = ata_id_n_sectors(new_id); if (strcmp(model[0], model[1])) { @@ -3324,37 +3259,20 @@ static const struct ata_blacklist_entry { } }; -static int ata_strim(char *s, size_t len) -{ - len = strnlen(s, len); - - /* ATAPI specifies that empty space is blank-filled; remove blanks */ - while ((len > 0) && (s[len - 1] == ' ')) { - len--; - s[len] = 0; - } - return len; -} - unsigned long ata_device_blacklisted(const struct ata_device *dev) { - unsigned char model_num[40]; - unsigned char model_rev[16]; - unsigned int nlen, rlen; + unsigned char model_num[ATA_ID_PROD_LEN + 1]; + unsigned char model_rev[ATA_ID_FW_REV_LEN + 1]; const struct ata_blacklist_entry *ad = ata_device_blacklist; - ata_id_string(dev->id, model_num, ATA_ID_PROD_OFS, - sizeof(model_num)); - ata_id_string(dev->id, model_rev, ATA_ID_FW_REV_OFS, - sizeof(model_rev)); - nlen = ata_strim(model_num, sizeof(model_num)); - rlen = ata_strim(model_rev, sizeof(model_rev)); + ata_id_c_string(dev->id, model_num, ATA_ID_PROD, sizeof(model_num)); + ata_id_c_string(dev->id, model_rev, ATA_ID_FW_REV, sizeof(model_rev)); while (ad->model_num) { - if (!strncmp(ad->model_num, model_num, nlen)) { + if (!strcmp(ad->model_num, model_num)) { if (ad->model_rev == NULL) return ad->horkage; - if (!strncmp(ad->model_rev, model_rev, rlen)) + if (!strcmp(ad->model_rev, model_rev)) return ad->horkage; } ad++; @@ -3894,53 +3812,7 @@ #endif /* __BIG_ENDIAN */ } /** - * ata_mmio_data_xfer - Transfer data by MMIO - * @adev: device for this I/O - * @buf: data buffer - * @buflen: buffer length - * @write_data: read/write - * - * Transfer data from/to the device data register by MMIO. - * - * LOCKING: - * Inherited from caller. - */ - -void ata_mmio_data_xfer(struct ata_device *adev, unsigned char *buf, - unsigned int buflen, int write_data) -{ - struct ata_port *ap = adev->ap; - unsigned int i; - unsigned int words = buflen >> 1; - u16 *buf16 = (u16 *) buf; - void __iomem *mmio = (void __iomem *)ap->ioaddr.data_addr; - - /* Transfer multiple of 2 bytes */ - if (write_data) { - for (i = 0; i < words; i++) - writew(le16_to_cpu(buf16[i]), mmio); - } else { - for (i = 0; i < words; i++) - buf16[i] = cpu_to_le16(readw(mmio)); - } - - /* Transfer trailing 1 byte, if any. */ - if (unlikely(buflen & 0x01)) { - u16 align_buf[1] = { 0 }; - unsigned char *trailing_buf = buf + buflen - 1; - - if (write_data) { - memcpy(align_buf, trailing_buf, 1); - writew(le16_to_cpu(align_buf[0]), mmio); - } else { - align_buf[0] = cpu_to_le16(readw(mmio)); - memcpy(trailing_buf, align_buf, 1); - } - } -} - -/** - * ata_pio_data_xfer - Transfer data by PIO + * ata_data_xfer - Transfer data by PIO * @adev: device to target * @buf: data buffer * @buflen: buffer length @@ -3951,18 +3823,17 @@ void ata_mmio_data_xfer(struct ata_devic * LOCKING: * Inherited from caller. */ - -void ata_pio_data_xfer(struct ata_device *adev, unsigned char *buf, - unsigned int buflen, int write_data) +void ata_data_xfer(struct ata_device *adev, unsigned char *buf, + unsigned int buflen, int write_data) { struct ata_port *ap = adev->ap; unsigned int words = buflen >> 1; /* Transfer multiple of 2 bytes */ if (write_data) - outsw(ap->ioaddr.data_addr, buf, words); + iowrite16_rep(ap->ioaddr.data_addr, buf, words); else - insw(ap->ioaddr.data_addr, buf, words); + ioread16_rep(ap->ioaddr.data_addr, buf, words); /* Transfer trailing 1 byte, if any. */ if (unlikely(buflen & 0x01)) { @@ -3971,16 +3842,16 @@ void ata_pio_data_xfer(struct ata_device if (write_data) { memcpy(align_buf, trailing_buf, 1); - outw(le16_to_cpu(align_buf[0]), ap->ioaddr.data_addr); + iowrite16(le16_to_cpu(align_buf[0]), ap->ioaddr.data_addr); } else { - align_buf[0] = cpu_to_le16(inw(ap->ioaddr.data_addr)); + align_buf[0] = cpu_to_le16(ioread16(ap->ioaddr.data_addr)); memcpy(trailing_buf, align_buf, 1); } } } /** - * ata_pio_data_xfer_noirq - Transfer data by PIO + * ata_data_xfer_noirq - Transfer data by PIO * @adev: device to target * @buf: data buffer * @buflen: buffer length @@ -3992,13 +3863,12 @@ void ata_pio_data_xfer(struct ata_device * LOCKING: * Inherited from caller. */ - -void ata_pio_data_xfer_noirq(struct ata_device *adev, unsigned char *buf, - unsigned int buflen, int write_data) +void ata_data_xfer_noirq(struct ata_device *adev, unsigned char *buf, + unsigned int buflen, int write_data) { unsigned long flags; local_irq_save(flags); - ata_pio_data_xfer(adev, buf, buflen, write_data); + ata_data_xfer(adev, buf, buflen, write_data); local_irq_restore(flags); } @@ -4022,11 +3892,11 @@ static void ata_pio_sector(struct ata_qu unsigned int offset; unsigned char *buf; - if (qc->cursect == (qc->nsect - 1)) + if (qc->curbytes == qc->nbytes - ATA_SECT_SIZE) ap->hsm_task_state = HSM_ST_LAST; page = sg[qc->cursg].page; - offset = sg[qc->cursg].offset + qc->cursg_ofs * ATA_SECT_SIZE; + offset = sg[qc->cursg].offset + qc->cursg_ofs; /* get the current page and offset */ page = nth_page(page, (offset >> PAGE_SHIFT)); @@ -4051,10 +3921,10 @@ static void ata_pio_sector(struct ata_qu ap->ops->data_xfer(qc->dev, buf + offset, ATA_SECT_SIZE, do_write); } - qc->cursect++; - qc->cursg_ofs++; + qc->curbytes += ATA_SECT_SIZE; + qc->cursg_ofs += ATA_SECT_SIZE; - if ((qc->cursg_ofs * ATA_SECT_SIZE) == (&sg[qc->cursg])->length) { + if (qc->cursg_ofs == (&sg[qc->cursg])->length) { qc->cursg++; qc->cursg_ofs = 0; } @@ -4079,7 +3949,8 @@ static void ata_pio_sectors(struct ata_q WARN_ON(qc->dev->multi_count == 0); - nsect = min(qc->nsect - qc->cursect, qc->dev->multi_count); + nsect = min((qc->nbytes - qc->curbytes) / ATA_SECT_SIZE, + qc->dev->multi_count); while (nsect--) ata_pio_sector(qc); } else @@ -4320,7 +4191,7 @@ static void ata_hsm_qc_complete(struct a qc = ata_qc_from_tag(ap, qc->tag); if (qc) { if (likely(!(qc->err_mask & AC_ERR_HSM))) { - ata_irq_on(ap); + ap->ops->irq_on(ap); ata_qc_complete(qc); } else ata_port_freeze(ap); @@ -4336,7 +4207,7 @@ static void ata_hsm_qc_complete(struct a } else { if (in_wq) { spin_lock_irqsave(ap->lock, flags); - ata_irq_on(ap); + ap->ops->irq_on(ap); ata_qc_complete(qc); spin_unlock_irqrestore(ap->lock, flags); } else @@ -5161,7 +5032,7 @@ idle_irq: #ifdef ATA_IRQ_TRAP if ((ap->stats.idle_irq % 1000) == 0) { - ata_irq_ack(ap, 0); /* debug trap */ + ap->ops->irq_ack(ap, 0); /* debug trap */ ata_port_printk(ap, KERN_WARNING, "irq trap\n"); return 1; } @@ -5502,54 +5373,25 @@ void ata_host_resume(struct ata_host *ho * LOCKING: * Inherited from caller. */ - -int ata_port_start (struct ata_port *ap) +int ata_port_start(struct ata_port *ap) { struct device *dev = ap->dev; int rc; - ap->prd = dma_alloc_coherent(dev, ATA_PRD_TBL_SZ, &ap->prd_dma, GFP_KERNEL); + ap->prd = dmam_alloc_coherent(dev, ATA_PRD_TBL_SZ, &ap->prd_dma, + GFP_KERNEL); if (!ap->prd) return -ENOMEM; rc = ata_pad_alloc(ap, dev); - if (rc) { - dma_free_coherent(dev, ATA_PRD_TBL_SZ, ap->prd, ap->prd_dma); + if (rc) return rc; - } - - DPRINTK("prd alloc, virt %p, dma %llx\n", ap->prd, (unsigned long long) ap->prd_dma); + DPRINTK("prd alloc, virt %p, dma %llx\n", ap->prd, + (unsigned long long)ap->prd_dma); return 0; } - -/** - * ata_port_stop - Undo ata_port_start() - * @ap: Port to shut down - * - * Frees the PRD table. - * - * May be used as the port_stop() entry in ata_port_operations. - * - * LOCKING: - * Inherited from caller. - */ - -void ata_port_stop (struct ata_port *ap) -{ - struct device *dev = ap->dev; - - dma_free_coherent(dev, ATA_PRD_TBL_SZ, ap->prd, ap->prd_dma); - ata_pad_free(ap, dev); -} - -void ata_host_stop (struct ata_host *host) -{ - if (host->mmio_base) - iounmap(host->mmio_base); -} - /** * ata_dev_init - Initialize an ata_device structure * @dev: Device structure to initialize @@ -5723,6 +5565,27 @@ static struct ata_port * ata_port_add(co return ap; } +static void ata_host_release(struct device *gendev, void *res) +{ + struct ata_host *host = dev_get_drvdata(gendev); + int i; + + for (i = 0; i < host->n_ports; i++) { + struct ata_port *ap = host->ports[i]; + + if (!ap) + continue; + + if (ap->ops->port_stop) + ap->ops->port_stop(ap); + + scsi_host_put(ap->scsi_host); + } + + if (host->ops->host_stop) + host->ops->host_stop(host); +} + /** * ata_sas_host_init - Initialize a host struct * @host: host to initialize @@ -5770,22 +5633,28 @@ int ata_device_add(const struct ata_prob int rc; DPRINTK("ENTER\n"); - + if (ent->irq == 0) { dev_printk(KERN_ERR, dev, "is not available: No interrupt assigned.\n"); return 0; } + + if (!devres_open_group(dev, ata_device_add, GFP_KERNEL)) + return 0; + /* alloc a container for our list of ATA ports (buses) */ - host = kzalloc(sizeof(struct ata_host) + - (ent->n_ports * sizeof(void *)), GFP_KERNEL); + host = devres_alloc(ata_host_release, sizeof(struct ata_host) + + (ent->n_ports * sizeof(void *)), GFP_KERNEL); if (!host) - return 0; + goto err_out; + devres_add(dev, host); + dev_set_drvdata(dev, host); ata_host_init(host, dev, ent->_host_flags, ent->port_ops); host->n_ports = ent->n_ports; host->irq = ent->irq; host->irq2 = ent->irq2; - host->mmio_base = ent->mmio_base; + host->iomap = ent->iomap; host->private_data = ent->private_data; /* register each port bound to this device */ @@ -5823,8 +5692,8 @@ int ata_device_add(const struct ata_prob (ap->pio_mask << ATA_SHIFT_PIO); /* print per-port info to dmesg */ - ata_port_printk(ap, KERN_INFO, "%cATA max %s cmd 0x%lX " - "ctl 0x%lX bmdma 0x%lX irq %d\n", + ata_port_printk(ap, KERN_INFO, "%cATA max %s cmd 0x%p " + "ctl 0x%p bmdma 0x%p irq %d\n", ap->flags & ATA_FLAG_SATA ? 'S' : 'P', ata_mode_string(xfer_mode_mask), ap->ioaddr.cmd_addr, @@ -5837,8 +5706,8 @@ int ata_device_add(const struct ata_prob } /* obtain irq, that may be shared between channels */ - rc = request_irq(ent->irq, ent->port_ops->irq_handler, ent->irq_flags, - DRV_NAME, host); + rc = devm_request_irq(dev, ent->irq, ent->port_ops->irq_handler, + ent->irq_flags, DRV_NAME, host); if (rc) { dev_printk(KERN_ERR, dev, "irq %lu request failed: %d\n", ent->irq, rc); @@ -5851,15 +5720,19 @@ int ata_device_add(const struct ata_prob so trap it now */ BUG_ON(ent->irq == ent->irq2); - rc = request_irq(ent->irq2, ent->port_ops->irq_handler, ent->irq_flags, - DRV_NAME, host); + rc = devm_request_irq(dev, ent->irq2, + ent->port_ops->irq_handler, ent->irq_flags, + DRV_NAME, host); if (rc) { dev_printk(KERN_ERR, dev, "irq %lu request failed: %d\n", ent->irq2, rc); - goto err_out_free_irq; + goto err_out; } } + /* resource acquisition complete */ + devres_remove_group(dev, ata_device_add); + /* perform each probe synchronously */ DPRINTK("probe begin\n"); for (i = 0; i < host->n_ports; i++) { @@ -5928,24 +5801,13 @@ int ata_device_add(const struct ata_prob ata_scsi_scan_host(ap); } - dev_set_drvdata(dev, host); - VPRINTK("EXIT, returning %u\n", ent->n_ports); return ent->n_ports; /* success */ -err_out_free_irq: - free_irq(ent->irq, host); -err_out: - for (i = 0; i < host->n_ports; i++) { - struct ata_port *ap = host->ports[i]; - if (ap) { - ap->ops->port_stop(ap); - scsi_host_put(ap->scsi_host); - } - } - - kfree(host); - VPRINTK("EXIT, returning 0\n"); + err_out: + devres_release_group(dev, ata_device_add); + dev_set_drvdata(dev, NULL); + VPRINTK("EXIT, returning %d\n", rc); return 0; } @@ -6008,76 +5870,20 @@ void ata_port_detach(struct ata_port *ap } /** - * ata_host_remove - PCI layer callback for device removal - * @host: ATA host set that was removed + * ata_host_detach - Detach all ports of an ATA host + * @host: Host to detach * - * Unregister all objects associated with this host set. Free those - * objects. + * Detach all ports of @host. * * LOCKING: - * Inherited from calling layer (may sleep). + * Kernel thread context (may sleep). */ - -void ata_host_remove(struct ata_host *host) +void ata_host_detach(struct ata_host *host) { - unsigned int i; + int i; for (i = 0; i < host->n_ports; i++) ata_port_detach(host->ports[i]); - - free_irq(host->irq, host); - if (host->irq2) - free_irq(host->irq2, host); - - for (i = 0; i < host->n_ports; i++) { - struct ata_port *ap = host->ports[i]; - - ata_scsi_release(ap->scsi_host); - - if ((ap->flags & ATA_FLAG_NO_LEGACY) == 0) { - struct ata_ioports *ioaddr = &ap->ioaddr; - - /* FIXME: Add -ac IDE pci mods to remove these special cases */ - if (ioaddr->cmd_addr == ATA_PRIMARY_CMD) - release_region(ATA_PRIMARY_CMD, 8); - else if (ioaddr->cmd_addr == ATA_SECONDARY_CMD) - release_region(ATA_SECONDARY_CMD, 8); - } - - scsi_host_put(ap->scsi_host); - } - - if (host->ops->host_stop) - host->ops->host_stop(host); - - kfree(host); -} - -/** - * ata_scsi_release - SCSI layer callback hook for host unload - * @shost: libata host to be unloaded - * - * Performs all duties necessary to shut down a libata port... - * Kill port kthread, disable port, and release resources. - * - * LOCKING: - * Inherited from SCSI layer. - * - * RETURNS: - * One. - */ - -int ata_scsi_release(struct Scsi_Host *shost) -{ - struct ata_port *ap = ata_shost_to_port(shost); - - DPRINTK("ENTER\n"); - - ap->ops->port_disable(ap); - ap->ops->port_stop(ap); - - DPRINTK("EXIT\n"); - return 1; } struct ata_probe_ent * @@ -6085,7 +5891,11 @@ ata_probe_ent_alloc(struct device *dev, { struct ata_probe_ent *probe_ent; - probe_ent = kzalloc(sizeof(*probe_ent), GFP_KERNEL); + /* XXX - the following if can go away once all LLDs are managed */ + if (!list_empty(&dev->devres_head)) + probe_ent = devm_kzalloc(dev, sizeof(*probe_ent), GFP_KERNEL); + else + probe_ent = kzalloc(sizeof(*probe_ent), GFP_KERNEL); if (!probe_ent) { printk(KERN_ERR DRV_NAME "(%s): out of memory\n", kobject_name(&(dev->kobj))); @@ -6135,37 +5945,23 @@ void ata_std_ports(struct ata_ioports *i #ifdef CONFIG_PCI -void ata_pci_host_stop (struct ata_host *host) -{ - struct pci_dev *pdev = to_pci_dev(host->dev); - - pci_iounmap(pdev, host->mmio_base); -} - /** * ata_pci_remove_one - PCI layer callback for device removal * @pdev: PCI device that was removed * - * PCI layer indicates to libata via this hook that - * hot-unplug or module unload event has occurred. - * Handle this by unregistering all objects associated - * with this PCI device. Free those objects. Then finally - * release PCI resources and disable device. + * PCI layer indicates to libata via this hook that hot-unplug or + * module unload event has occurred. Detach all ports. Resource + * release is handled via devres. * * LOCKING: * Inherited from PCI layer (may sleep). */ - -void ata_pci_remove_one (struct pci_dev *pdev) +void ata_pci_remove_one(struct pci_dev *pdev) { struct device *dev = pci_dev_to_dev(pdev); struct ata_host *host = dev_get_drvdata(dev); - ata_host_remove(host); - - pci_release_regions(pdev); - pci_disable_device(pdev); - dev_set_drvdata(dev, NULL); + ata_host_detach(host); } /* move to PCI subsystem */ @@ -6212,12 +6008,22 @@ void ata_pci_device_do_suspend(struct pc } } -void ata_pci_device_do_resume(struct pci_dev *pdev) +int ata_pci_device_do_resume(struct pci_dev *pdev) { + int rc; + pci_set_power_state(pdev, PCI_D0); pci_restore_state(pdev); - pci_enable_device(pdev); + + rc = pcim_enable_device(pdev); + if (rc) { + dev_printk(KERN_ERR, &pdev->dev, + "failed to enable device after resume (%d)\n", rc); + return rc; + } + pci_set_master(pdev); + return 0; } int ata_pci_device_suspend(struct pci_dev *pdev, pm_message_t mesg) @@ -6237,10 +6043,12 @@ int ata_pci_device_suspend(struct pci_de int ata_pci_device_resume(struct pci_dev *pdev) { struct ata_host *host = dev_get_drvdata(&pdev->dev); + int rc; - ata_pci_device_do_resume(pdev); - ata_host_resume(host); - return 0; + rc = ata_pci_device_do_resume(pdev); + if (rc == 0) + ata_host_resume(host); + return rc; } #endif /* CONFIG_PCI */ @@ -6386,8 +6194,7 @@ EXPORT_SYMBOL_GPL(ata_std_bios_param); EXPORT_SYMBOL_GPL(ata_std_ports); EXPORT_SYMBOL_GPL(ata_host_init); EXPORT_SYMBOL_GPL(ata_device_add); -EXPORT_SYMBOL_GPL(ata_port_detach); -EXPORT_SYMBOL_GPL(ata_host_remove); +EXPORT_SYMBOL_GPL(ata_host_detach); EXPORT_SYMBOL_GPL(ata_sg_init); EXPORT_SYMBOL_GPL(ata_sg_init_one); EXPORT_SYMBOL_GPL(ata_hsm_move); @@ -6404,12 +6211,9 @@ EXPORT_SYMBOL_GPL(ata_check_status); EXPORT_SYMBOL_GPL(ata_altstatus); EXPORT_SYMBOL_GPL(ata_exec_command); EXPORT_SYMBOL_GPL(ata_port_start); -EXPORT_SYMBOL_GPL(ata_port_stop); -EXPORT_SYMBOL_GPL(ata_host_stop); EXPORT_SYMBOL_GPL(ata_interrupt); -EXPORT_SYMBOL_GPL(ata_mmio_data_xfer); -EXPORT_SYMBOL_GPL(ata_pio_data_xfer); -EXPORT_SYMBOL_GPL(ata_pio_data_xfer_noirq); +EXPORT_SYMBOL_GPL(ata_data_xfer); +EXPORT_SYMBOL_GPL(ata_data_xfer_noirq); EXPORT_SYMBOL_GPL(ata_qc_prep); EXPORT_SYMBOL_GPL(ata_noop_qc_prep); EXPORT_SYMBOL_GPL(ata_bmdma_setup); @@ -6446,7 +6250,6 @@ EXPORT_SYMBOL_GPL(ata_scsi_queuecmd); EXPORT_SYMBOL_GPL(ata_scsi_slave_config); EXPORT_SYMBOL_GPL(ata_scsi_slave_destroy); EXPORT_SYMBOL_GPL(ata_scsi_change_queue_depth); -EXPORT_SYMBOL_GPL(ata_scsi_release); EXPORT_SYMBOL_GPL(ata_host_intr); EXPORT_SYMBOL_GPL(sata_scr_valid); EXPORT_SYMBOL_GPL(sata_scr_read); @@ -6467,7 +6270,6 @@ EXPORT_SYMBOL_GPL(ata_timing_merge); #ifdef CONFIG_PCI EXPORT_SYMBOL_GPL(pci_test_config_bits); -EXPORT_SYMBOL_GPL(ata_pci_host_stop); EXPORT_SYMBOL_GPL(ata_pci_init_native_mode); EXPORT_SYMBOL_GPL(ata_pci_init_one); EXPORT_SYMBOL_GPL(ata_pci_remove_one); @@ -6491,3 +6293,7 @@ EXPORT_SYMBOL_GPL(ata_eh_thaw_port); EXPORT_SYMBOL_GPL(ata_eh_qc_complete); EXPORT_SYMBOL_GPL(ata_eh_qc_retry); EXPORT_SYMBOL_GPL(ata_do_eh); +EXPORT_SYMBOL_GPL(ata_irq_on); +EXPORT_SYMBOL_GPL(ata_dummy_irq_on); +EXPORT_SYMBOL_GPL(ata_irq_ack); +EXPORT_SYMBOL_GPL(ata_dummy_irq_ack); diff --git a/drivers/ata/libata-eh.c b/drivers/ata/libata-eh.c index 7484358..52c85af 100644 --- a/drivers/ata/libata-eh.c +++ b/drivers/ata/libata-eh.c @@ -1443,15 +1443,10 @@ static void ata_eh_report(struct ata_por }; struct ata_queued_cmd *qc = __ata_qc_from_tag(ap, tag); struct ata_taskfile *cmd = &qc->tf, *res = &qc->result_tf; - unsigned int nbytes; if (!(qc->flags & ATA_QCFLAG_FAILED) || !qc->err_mask) continue; - nbytes = qc->nbytes; - if (!nbytes) - nbytes = qc->nsect << 9; - ata_dev_printk(qc->dev, KERN_ERR, "cmd %02x/%02x:%02x:%02x:%02x:%02x/%02x:%02x:%02x:%02x:%02x/%02x " "tag %d cdb 0x%x data %u %s\n " @@ -1461,7 +1456,7 @@ static void ata_eh_report(struct ata_por cmd->lbal, cmd->lbam, cmd->lbah, cmd->hob_feature, cmd->hob_nsect, cmd->hob_lbal, cmd->hob_lbam, cmd->hob_lbah, - cmd->device, qc->tag, qc->cdb[0], nbytes, + cmd->device, qc->tag, qc->cdb[0], qc->nbytes, dma_str[qc->dma_dir], res->command, res->feature, res->nsect, res->lbal, res->lbam, res->lbah, diff --git a/drivers/ata/libata-scsi.c b/drivers/ata/libata-scsi.c index 73902d3..0009818 100644 --- a/drivers/ata/libata-scsi.c +++ b/drivers/ata/libata-scsi.c @@ -149,6 +149,45 @@ int ata_std_bios_param(struct scsi_devic } /** + * ata_get_identity - Handler for HDIO_GET_IDENTITY ioctl + * @sdev: SCSI device to get identify data for + * @arg: User buffer area for identify data + * + * LOCKING: + * Defined by the SCSI layer. We don't really care. + * + * RETURNS: + * Zero on success, negative errno on error. + */ +static int ata_get_identity(struct scsi_device *sdev, void __user *arg) +{ + struct ata_port *ap = ata_shost_to_port(sdev->host); + struct ata_device *dev = ata_scsi_find_dev(ap, sdev); + u16 __user *dst = arg; + char buf[40]; + + if (!dev) + return -ENOMSG; + + if (copy_to_user(dst, dev->id, ATA_ID_WORDS * sizeof(u16))) + return -EFAULT; + + ata_id_string(dev->id, buf, ATA_ID_PROD, ATA_ID_PROD_LEN); + if (copy_to_user(dst + ATA_ID_PROD, buf, ATA_ID_PROD_LEN)) + return -EFAULT; + + ata_id_string(dev->id, buf, ATA_ID_FW_REV, ATA_ID_FW_REV_LEN); + if (copy_to_user(dst + ATA_ID_FW_REV, buf, ATA_ID_FW_REV_LEN)) + return -EFAULT; + + ata_id_string(dev->id, buf, ATA_ID_SERNO, ATA_ID_SERNO_LEN); + if (copy_to_user(dst + ATA_ID_SERNO, buf, ATA_ID_SERNO_LEN)) + return -EFAULT; + + return 0; +} + +/** * ata_cmd_ioctl - Handler for HDIO_DRIVE_CMD ioctl * @scsidev: Device to which we are issuing command * @arg: User provided data for issuing command @@ -159,7 +198,6 @@ int ata_std_bios_param(struct scsi_devic * RETURNS: * Zero on success, negative errno on error. */ - int ata_cmd_ioctl(struct scsi_device *scsidev, void __user *arg) { int rc = 0; @@ -359,6 +397,9 @@ int ata_scsi_ioctl(struct scsi_device *s return -EINVAL; return 0; + case HDIO_GET_IDENTITY: + return ata_get_identity(scsidev, arg); + case HDIO_DRIVE_CMD: if (!capable(CAP_SYS_ADMIN) || !capable(CAP_SYS_RAWIO)) return -EACCES; @@ -397,9 +438,9 @@ int ata_scsi_ioctl(struct scsi_device *s * RETURNS: * Command allocated, or %NULL if none available. */ -struct ata_queued_cmd *ata_scsi_qc_new(struct ata_device *dev, - struct scsi_cmnd *cmd, - void (*done)(struct scsi_cmnd *)) +static struct ata_queued_cmd *ata_scsi_qc_new(struct ata_device *dev, + struct scsi_cmnd *cmd, + void (*done)(struct scsi_cmnd *)) { struct ata_queued_cmd *qc; @@ -435,7 +476,7 @@ struct ata_queued_cmd *ata_scsi_qc_new(s * LOCKING: * inherited from caller */ -void ata_dump_status(unsigned id, struct ata_taskfile *tf) +static void ata_dump_status(unsigned id, struct ata_taskfile *tf) { u8 stat = tf->command, err = tf->feature; @@ -610,8 +651,8 @@ int ata_scsi_device_resume(struct scsi_d * LOCKING: * spin_lock_irqsave(host lock) */ -void ata_to_sense_error(unsigned id, u8 drv_stat, u8 drv_err, u8 *sk, u8 *asc, - u8 *ascq, int verbose) +static void ata_to_sense_error(unsigned id, u8 drv_stat, u8 drv_err, u8 *sk, + u8 *asc, u8 *ascq, int verbose) { int i; @@ -1359,7 +1400,7 @@ static unsigned int ata_scsi_rw_xlat(str goto nothing_to_do; qc->flags |= ATA_QCFLAG_IO; - qc->nsect = n_block; + qc->nbytes = n_block * ATA_SECT_SIZE; rc = ata_build_rw_tf(&qc->tf, qc->dev, block, n_block, tf_flags, qc->tag); @@ -1698,8 +1739,8 @@ unsigned int ata_scsiop_inq_std(struct a if (buflen > 35) { memcpy(&rbuf[8], "ATA ", 8); - ata_id_string(args->id, &rbuf[16], ATA_ID_PROD_OFS, 16); - ata_id_string(args->id, &rbuf[32], ATA_ID_FW_REV_OFS, 4); + ata_id_string(args->id, &rbuf[16], ATA_ID_PROD, 16); + ata_id_string(args->id, &rbuf[32], ATA_ID_FW_REV, 4); if (rbuf[32] == 0 || rbuf[32] == ' ') memcpy(&rbuf[32], "n/a ", 4); } @@ -1768,13 +1809,13 @@ unsigned int ata_scsiop_inq_80(struct at 0, 0x80, /* this page code */ 0, - ATA_SERNO_LEN, /* page len */ + ATA_ID_SERNO_LEN, /* page len */ }; memcpy(rbuf, hdr, sizeof(hdr)); - if (buflen > (ATA_SERNO_LEN + 4 - 1)) + if (buflen > (ATA_ID_SERNO_LEN + 4 - 1)) ata_id_string(args->id, (unsigned char *) &rbuf[4], - ATA_ID_SERNO_OFS, ATA_SERNO_LEN); + ATA_ID_SERNO, ATA_ID_SERNO_LEN); return 0; } @@ -1799,19 +1840,18 @@ unsigned int ata_scsiop_inq_83(struct at { int num; const int sat_model_serial_desc_len = 68; - const int ata_model_byte_len = 40; rbuf[1] = 0x83; /* this page code */ num = 4; - if (buflen > (ATA_SERNO_LEN + num + 3)) { + if (buflen > (ATA_ID_SERNO_LEN + num + 3)) { /* piv=0, assoc=lu, code_set=ACSII, designator=vendor */ rbuf[num + 0] = 2; - rbuf[num + 3] = ATA_SERNO_LEN; + rbuf[num + 3] = ATA_ID_SERNO_LEN; num += 4; ata_id_string(args->id, (unsigned char *) rbuf + num, - ATA_ID_SERNO_OFS, ATA_SERNO_LEN); - num += ATA_SERNO_LEN; + ATA_ID_SERNO, ATA_ID_SERNO_LEN); + num += ATA_ID_SERNO_LEN; } if (buflen > (sat_model_serial_desc_len + num + 3)) { /* SAT defined lu model and serial numbers descriptor */ @@ -1823,11 +1863,11 @@ unsigned int ata_scsiop_inq_83(struct at memcpy(rbuf + num, "ATA ", 8); num += 8; ata_id_string(args->id, (unsigned char *) rbuf + num, - ATA_ID_PROD_OFS, ata_model_byte_len); - num += ata_model_byte_len; + ATA_ID_PROD, ATA_ID_PROD_LEN); + num += ATA_ID_PROD_LEN; ata_id_string(args->id, (unsigned char *) rbuf + num, - ATA_ID_SERNO_OFS, ATA_SERNO_LEN); - num += ATA_SERNO_LEN; + ATA_ID_SERNO, ATA_ID_SERNO_LEN); + num += ATA_ID_SERNO_LEN; } rbuf[3] = num - 4; /* page len (assume less than 256 bytes) */ return 0; @@ -1955,15 +1995,15 @@ static unsigned int ata_msense_rw_recove */ static int ata_dev_supports_fua(u16 *id) { - unsigned char model[41], fw[9]; + unsigned char model[ATA_ID_PROD_LEN + 1], fw[ATA_ID_FW_REV_LEN + 1]; if (!libata_fua) return 0; if (!ata_id_has_fua(id)) return 0; - ata_id_c_string(id, model, ATA_ID_PROD_OFS, sizeof(model)); - ata_id_c_string(id, fw, ATA_ID_FW_REV_OFS, sizeof(fw)); + ata_id_c_string(id, model, ATA_ID_PROD, sizeof(model)); + ata_id_c_string(id, fw, ATA_ID_FW_REV, sizeof(fw)); if (strcmp(model, "Maxtor")) return 1; @@ -2661,7 +2701,7 @@ static unsigned int ata_scsi_pass_thru(s * TODO: find out if we need to do more here to * cover scatter/gather case. */ - qc->nsect = scmd->request_bufflen / ATA_SECT_SIZE; + qc->nbytes = scmd->request_bufflen; /* request result TF */ qc->flags |= ATA_QCFLAG_RESULT_TF; @@ -3059,7 +3099,8 @@ void ata_scsi_hotplug(struct work_struct for (i = 0; i < ATA_MAX_DEVICES; i++) { struct ata_device *dev = &ap->device[i]; if (ata_dev_enabled(dev) && !dev->sdev) { - queue_delayed_work(ata_aux_wq, &ap->hotplug_task, HZ); + queue_delayed_work(ata_aux_wq, &ap->hotplug_task, + round_jiffies_relative(HZ)); break; } } @@ -3264,7 +3305,8 @@ EXPORT_SYMBOL_GPL(ata_sas_port_init); void ata_sas_port_destroy(struct ata_port *ap) { - ap->ops->port_stop(ap); + if (ap->ops->port_stop) + ap->ops->port_stop(ap); kfree(ap); } EXPORT_SYMBOL_GPL(ata_sas_port_destroy); diff --git a/drivers/ata/libata-sff.c b/drivers/ata/libata-sff.c index 12c88c5..16bc3e3 100644 --- a/drivers/ata/libata-sff.c +++ b/drivers/ata/libata-sff.c @@ -56,10 +56,7 @@ u8 ata_irq_on(struct ata_port *ap) ap->ctl &= ~ATA_NIEN; ap->last_ctl = ap->ctl; - if (ap->flags & ATA_FLAG_MMIO) - writeb(ap->ctl, (void __iomem *) ioaddr->ctl_addr); - else - outb(ap->ctl, ioaddr->ctl_addr); + iowrite8(ap->ctl, ioaddr->ctl_addr); tmp = ata_wait_idle(ap); ap->ops->irq_clear(ap); @@ -67,92 +64,74 @@ u8 ata_irq_on(struct ata_port *ap) return tmp; } +u8 ata_dummy_irq_on (struct ata_port *ap) { return 0; } + /** - * ata_tf_load_pio - send taskfile registers to host controller - * @ap: Port to which output is sent - * @tf: ATA taskfile register set + * ata_irq_ack - Acknowledge a device interrupt. + * @ap: Port on which interrupts are enabled. * - * Outputs ATA taskfile to standard ATA host controller. + * Wait up to 10 ms for legacy IDE device to become idle (BUSY + * or BUSY+DRQ clear). Obtain dma status and port status from + * device. Clear the interrupt. Return port status. * * LOCKING: - * Inherited from caller. */ -static void ata_tf_load_pio(struct ata_port *ap, const struct ata_taskfile *tf) +u8 ata_irq_ack(struct ata_port *ap, unsigned int chk_drq) { - struct ata_ioports *ioaddr = &ap->ioaddr; - unsigned int is_addr = tf->flags & ATA_TFLAG_ISADDR; + unsigned int bits = chk_drq ? ATA_BUSY | ATA_DRQ : ATA_BUSY; + u8 host_stat, post_stat, status; - if (tf->ctl != ap->last_ctl) { - outb(tf->ctl, ioaddr->ctl_addr); - ap->last_ctl = tf->ctl; - ata_wait_idle(ap); - } + status = ata_busy_wait(ap, bits, 1000); + if (status & bits) + if (ata_msg_err(ap)) + printk(KERN_ERR "abnormal status 0x%X\n", status); - if (is_addr && (tf->flags & ATA_TFLAG_LBA48)) { - outb(tf->hob_feature, ioaddr->feature_addr); - outb(tf->hob_nsect, ioaddr->nsect_addr); - outb(tf->hob_lbal, ioaddr->lbal_addr); - outb(tf->hob_lbam, ioaddr->lbam_addr); - outb(tf->hob_lbah, ioaddr->lbah_addr); - VPRINTK("hob: feat 0x%X nsect 0x%X, lba 0x%X 0x%X 0x%X\n", - tf->hob_feature, - tf->hob_nsect, - tf->hob_lbal, - tf->hob_lbam, - tf->hob_lbah); - } + /* get controller status; clear intr, err bits */ + host_stat = ioread8(ap->ioaddr.bmdma_addr + ATA_DMA_STATUS); + iowrite8(host_stat | ATA_DMA_INTR | ATA_DMA_ERR, + ap->ioaddr.bmdma_addr + ATA_DMA_STATUS); - if (is_addr) { - outb(tf->feature, ioaddr->feature_addr); - outb(tf->nsect, ioaddr->nsect_addr); - outb(tf->lbal, ioaddr->lbal_addr); - outb(tf->lbam, ioaddr->lbam_addr); - outb(tf->lbah, ioaddr->lbah_addr); - VPRINTK("feat 0x%X nsect 0x%X lba 0x%X 0x%X 0x%X\n", - tf->feature, - tf->nsect, - tf->lbal, - tf->lbam, - tf->lbah); - } + post_stat = ioread8(ap->ioaddr.bmdma_addr + ATA_DMA_STATUS); - if (tf->flags & ATA_TFLAG_DEVICE) { - outb(tf->device, ioaddr->device_addr); - VPRINTK("device 0x%X\n", tf->device); - } + if (ata_msg_intr(ap)) + printk(KERN_INFO "%s: irq ack: host_stat 0x%X, new host_stat 0x%X, drv_stat 0x%X\n", + __FUNCTION__, + host_stat, post_stat, status); - ata_wait_idle(ap); + return status; } +u8 ata_dummy_irq_ack(struct ata_port *ap, unsigned int chk_drq) { return 0; } + /** - * ata_tf_load_mmio - send taskfile registers to host controller + * ata_tf_load - send taskfile registers to host controller * @ap: Port to which output is sent * @tf: ATA taskfile register set * - * Outputs ATA taskfile to standard ATA host controller using MMIO. + * Outputs ATA taskfile to standard ATA host controller. * * LOCKING: * Inherited from caller. */ -static void ata_tf_load_mmio(struct ata_port *ap, const struct ata_taskfile *tf) +void ata_tf_load(struct ata_port *ap, const struct ata_taskfile *tf) { struct ata_ioports *ioaddr = &ap->ioaddr; unsigned int is_addr = tf->flags & ATA_TFLAG_ISADDR; if (tf->ctl != ap->last_ctl) { - writeb(tf->ctl, (void __iomem *) ap->ioaddr.ctl_addr); + iowrite8(tf->ctl, ioaddr->ctl_addr); ap->last_ctl = tf->ctl; ata_wait_idle(ap); } if (is_addr && (tf->flags & ATA_TFLAG_LBA48)) { - writeb(tf->hob_feature, (void __iomem *) ioaddr->feature_addr); - writeb(tf->hob_nsect, (void __iomem *) ioaddr->nsect_addr); - writeb(tf->hob_lbal, (void __iomem *) ioaddr->lbal_addr); - writeb(tf->hob_lbam, (void __iomem *) ioaddr->lbam_addr); - writeb(tf->hob_lbah, (void __iomem *) ioaddr->lbah_addr); + iowrite8(tf->hob_feature, ioaddr->feature_addr); + iowrite8(tf->hob_nsect, ioaddr->nsect_addr); + iowrite8(tf->hob_lbal, ioaddr->lbal_addr); + iowrite8(tf->hob_lbam, ioaddr->lbam_addr); + iowrite8(tf->hob_lbah, ioaddr->lbah_addr); VPRINTK("hob: feat 0x%X nsect 0x%X, lba 0x%X 0x%X 0x%X\n", tf->hob_feature, tf->hob_nsect, @@ -162,11 +141,11 @@ static void ata_tf_load_mmio(struct ata_ } if (is_addr) { - writeb(tf->feature, (void __iomem *) ioaddr->feature_addr); - writeb(tf->nsect, (void __iomem *) ioaddr->nsect_addr); - writeb(tf->lbal, (void __iomem *) ioaddr->lbal_addr); - writeb(tf->lbam, (void __iomem *) ioaddr->lbam_addr); - writeb(tf->lbah, (void __iomem *) ioaddr->lbah_addr); + iowrite8(tf->feature, ioaddr->feature_addr); + iowrite8(tf->nsect, ioaddr->nsect_addr); + iowrite8(tf->lbal, ioaddr->lbal_addr); + iowrite8(tf->lbam, ioaddr->lbam_addr); + iowrite8(tf->lbah, ioaddr->lbah_addr); VPRINTK("feat 0x%X nsect 0x%X lba 0x%X 0x%X 0x%X\n", tf->feature, tf->nsect, @@ -176,108 +155,34 @@ static void ata_tf_load_mmio(struct ata_ } if (tf->flags & ATA_TFLAG_DEVICE) { - writeb(tf->device, (void __iomem *) ioaddr->device_addr); + iowrite8(tf->device, ioaddr->device_addr); VPRINTK("device 0x%X\n", tf->device); } ata_wait_idle(ap); } - -/** - * ata_tf_load - send taskfile registers to host controller - * @ap: Port to which output is sent - * @tf: ATA taskfile register set - * - * Outputs ATA taskfile to standard ATA host controller using MMIO - * or PIO as indicated by the ATA_FLAG_MMIO flag. - * Writes the control, feature, nsect, lbal, lbam, and lbah registers. - * Optionally (ATA_TFLAG_LBA48) writes hob_feature, hob_nsect, - * hob_lbal, hob_lbam, and hob_lbah. - * - * This function waits for idle (!BUSY and !DRQ) after writing - * registers. If the control register has a new value, this - * function also waits for idle after writing control and before - * writing the remaining registers. - * - * May be used as the tf_load() entry in ata_port_operations. - * - * LOCKING: - * Inherited from caller. - */ -void ata_tf_load(struct ata_port *ap, const struct ata_taskfile *tf) -{ - if (ap->flags & ATA_FLAG_MMIO) - ata_tf_load_mmio(ap, tf); - else - ata_tf_load_pio(ap, tf); -} - /** - * ata_exec_command_pio - issue ATA command to host controller - * @ap: port to which command is being issued - * @tf: ATA taskfile register set - * - * Issues PIO write to ATA command register, with proper - * synchronization with interrupt handler / other threads. - * - * LOCKING: - * spin_lock_irqsave(host lock) - */ - -static void ata_exec_command_pio(struct ata_port *ap, const struct ata_taskfile *tf) -{ - DPRINTK("ata%u: cmd 0x%X\n", ap->id, tf->command); - - outb(tf->command, ap->ioaddr.command_addr); - ata_pause(ap); -} - - -/** - * ata_exec_command_mmio - issue ATA command to host controller + * ata_exec_command - issue ATA command to host controller * @ap: port to which command is being issued * @tf: ATA taskfile register set * - * Issues MMIO write to ATA command register, with proper - * synchronization with interrupt handler / other threads. - * - * FIXME: missing write posting for 400nS delay enforcement + * Issues ATA command, with proper synchronization with interrupt + * handler / other threads. * * LOCKING: * spin_lock_irqsave(host lock) */ - -static void ata_exec_command_mmio(struct ata_port *ap, const struct ata_taskfile *tf) +void ata_exec_command(struct ata_port *ap, const struct ata_taskfile *tf) { DPRINTK("ata%u: cmd 0x%X\n", ap->id, tf->command); - writeb(tf->command, (void __iomem *) ap->ioaddr.command_addr); + iowrite8(tf->command, ap->ioaddr.command_addr); ata_pause(ap); } - -/** - * ata_exec_command - issue ATA command to host controller - * @ap: port to which command is being issued - * @tf: ATA taskfile register set - * - * Issues PIO/MMIO write to ATA command register, with proper - * synchronization with interrupt handler / other threads. - * - * LOCKING: - * spin_lock_irqsave(host lock) - */ -void ata_exec_command(struct ata_port *ap, const struct ata_taskfile *tf) -{ - if (ap->flags & ATA_FLAG_MMIO) - ata_exec_command_mmio(ap, tf); - else - ata_exec_command_pio(ap, tf); -} - /** - * ata_tf_read_pio - input device's ATA taskfile shadow registers + * ata_tf_read - input device's ATA taskfile shadow registers * @ap: Port from which input is read * @tf: ATA taskfile register set for storing input * @@ -287,121 +192,28 @@ void ata_exec_command(struct ata_port *a * LOCKING: * Inherited from caller. */ - -static void ata_tf_read_pio(struct ata_port *ap, struct ata_taskfile *tf) -{ - struct ata_ioports *ioaddr = &ap->ioaddr; - - tf->command = ata_check_status(ap); - tf->feature = inb(ioaddr->error_addr); - tf->nsect = inb(ioaddr->nsect_addr); - tf->lbal = inb(ioaddr->lbal_addr); - tf->lbam = inb(ioaddr->lbam_addr); - tf->lbah = inb(ioaddr->lbah_addr); - tf->device = inb(ioaddr->device_addr); - - if (tf->flags & ATA_TFLAG_LBA48) { - outb(tf->ctl | ATA_HOB, ioaddr->ctl_addr); - tf->hob_feature = inb(ioaddr->error_addr); - tf->hob_nsect = inb(ioaddr->nsect_addr); - tf->hob_lbal = inb(ioaddr->lbal_addr); - tf->hob_lbam = inb(ioaddr->lbam_addr); - tf->hob_lbah = inb(ioaddr->lbah_addr); - } -} - -/** - * ata_tf_read_mmio - input device's ATA taskfile shadow registers - * @ap: Port from which input is read - * @tf: ATA taskfile register set for storing input - * - * Reads ATA taskfile registers for currently-selected device - * into @tf via MMIO. - * - * LOCKING: - * Inherited from caller. - */ - -static void ata_tf_read_mmio(struct ata_port *ap, struct ata_taskfile *tf) +void ata_tf_read(struct ata_port *ap, struct ata_taskfile *tf) { struct ata_ioports *ioaddr = &ap->ioaddr; tf->command = ata_check_status(ap); - tf->feature = readb((void __iomem *)ioaddr->error_addr); - tf->nsect = readb((void __iomem *)ioaddr->nsect_addr); - tf->lbal = readb((void __iomem *)ioaddr->lbal_addr); - tf->lbam = readb((void __iomem *)ioaddr->lbam_addr); - tf->lbah = readb((void __iomem *)ioaddr->lbah_addr); - tf->device = readb((void __iomem *)ioaddr->device_addr); + tf->feature = ioread8(ioaddr->error_addr); + tf->nsect = ioread8(ioaddr->nsect_addr); + tf->lbal = ioread8(ioaddr->lbal_addr); + tf->lbam = ioread8(ioaddr->lbam_addr); + tf->lbah = ioread8(ioaddr->lbah_addr); + tf->device = ioread8(ioaddr->device_addr); if (tf->flags & ATA_TFLAG_LBA48) { - writeb(tf->ctl | ATA_HOB, (void __iomem *) ap->ioaddr.ctl_addr); - tf->hob_feature = readb((void __iomem *)ioaddr->error_addr); - tf->hob_nsect = readb((void __iomem *)ioaddr->nsect_addr); - tf->hob_lbal = readb((void __iomem *)ioaddr->lbal_addr); - tf->hob_lbam = readb((void __iomem *)ioaddr->lbam_addr); - tf->hob_lbah = readb((void __iomem *)ioaddr->lbah_addr); + iowrite8(tf->ctl | ATA_HOB, ioaddr->ctl_addr); + tf->hob_feature = ioread8(ioaddr->error_addr); + tf->hob_nsect = ioread8(ioaddr->nsect_addr); + tf->hob_lbal = ioread8(ioaddr->lbal_addr); + tf->hob_lbam = ioread8(ioaddr->lbam_addr); + tf->hob_lbah = ioread8(ioaddr->lbah_addr); } } - -/** - * ata_tf_read - input device's ATA taskfile shadow registers - * @ap: Port from which input is read - * @tf: ATA taskfile register set for storing input - * - * Reads ATA taskfile registers for currently-selected device - * into @tf. - * - * Reads nsect, lbal, lbam, lbah, and device. If ATA_TFLAG_LBA48 - * is set, also reads the hob registers. - * - * May be used as the tf_read() entry in ata_port_operations. - * - * LOCKING: - * Inherited from caller. - */ -void ata_tf_read(struct ata_port *ap, struct ata_taskfile *tf) -{ - if (ap->flags & ATA_FLAG_MMIO) - ata_tf_read_mmio(ap, tf); - else - ata_tf_read_pio(ap, tf); -} - -/** - * ata_check_status_pio - Read device status reg & clear interrupt - * @ap: port where the device is - * - * Reads ATA taskfile status register for currently-selected device - * and return its value. This also clears pending interrupts - * from this device - * - * LOCKING: - * Inherited from caller. - */ -static u8 ata_check_status_pio(struct ata_port *ap) -{ - return inb(ap->ioaddr.status_addr); -} - -/** - * ata_check_status_mmio - Read device status reg & clear interrupt - * @ap: port where the device is - * - * Reads ATA taskfile status register for currently-selected device - * via MMIO and return its value. This also clears pending interrupts - * from this device - * - * LOCKING: - * Inherited from caller. - */ -static u8 ata_check_status_mmio(struct ata_port *ap) -{ - return readb((void __iomem *) ap->ioaddr.status_addr); -} - - /** * ata_check_status - Read device status reg & clear interrupt * @ap: port where the device is @@ -410,19 +222,14 @@ static u8 ata_check_status_mmio(struct a * and return its value. This also clears pending interrupts * from this device * - * May be used as the check_status() entry in ata_port_operations. - * * LOCKING: * Inherited from caller. */ u8 ata_check_status(struct ata_port *ap) { - if (ap->flags & ATA_FLAG_MMIO) - return ata_check_status_mmio(ap); - return ata_check_status_pio(ap); + return ioread8(ap->ioaddr.status_addr); } - /** * ata_altstatus - Read device alternate status reg * @ap: port where the device is @@ -441,58 +248,52 @@ u8 ata_altstatus(struct ata_port *ap) if (ap->ops->check_altstatus) return ap->ops->check_altstatus(ap); - if (ap->flags & ATA_FLAG_MMIO) - return readb((void __iomem *)ap->ioaddr.altstatus_addr); - return inb(ap->ioaddr.altstatus_addr); + return ioread8(ap->ioaddr.altstatus_addr); } /** - * ata_bmdma_setup_mmio - Set up PCI IDE BMDMA transaction + * ata_bmdma_setup - Set up PCI IDE BMDMA transaction * @qc: Info associated with this ATA transaction. * * LOCKING: * spin_lock_irqsave(host lock) */ - -static void ata_bmdma_setup_mmio (struct ata_queued_cmd *qc) +void ata_bmdma_setup(struct ata_queued_cmd *qc) { struct ata_port *ap = qc->ap; unsigned int rw = (qc->tf.flags & ATA_TFLAG_WRITE); u8 dmactl; - void __iomem *mmio = (void __iomem *) ap->ioaddr.bmdma_addr; /* load PRD table addr. */ mb(); /* make sure PRD table writes are visible to controller */ - writel(ap->prd_dma, mmio + ATA_DMA_TABLE_OFS); + iowrite32(ap->prd_dma, ap->ioaddr.bmdma_addr + ATA_DMA_TABLE_OFS); /* specify data direction, triple-check start bit is clear */ - dmactl = readb(mmio + ATA_DMA_CMD); + dmactl = ioread8(ap->ioaddr.bmdma_addr + ATA_DMA_CMD); dmactl &= ~(ATA_DMA_WR | ATA_DMA_START); if (!rw) dmactl |= ATA_DMA_WR; - writeb(dmactl, mmio + ATA_DMA_CMD); + iowrite8(dmactl, ap->ioaddr.bmdma_addr + ATA_DMA_CMD); /* issue r/w command */ ap->ops->exec_command(ap, &qc->tf); } /** - * ata_bmdma_start_mmio - Start a PCI IDE BMDMA transaction + * ata_bmdma_start - Start a PCI IDE BMDMA transaction * @qc: Info associated with this ATA transaction. * * LOCKING: * spin_lock_irqsave(host lock) */ - -static void ata_bmdma_start_mmio (struct ata_queued_cmd *qc) +void ata_bmdma_start (struct ata_queued_cmd *qc) { struct ata_port *ap = qc->ap; - void __iomem *mmio = (void __iomem *) ap->ioaddr.bmdma_addr; u8 dmactl; /* start host DMA transaction */ - dmactl = readb(mmio + ATA_DMA_CMD); - writeb(dmactl | ATA_DMA_START, mmio + ATA_DMA_CMD); + dmactl = ioread8(ap->ioaddr.bmdma_addr + ATA_DMA_CMD); + iowrite8(dmactl | ATA_DMA_START, ap->ioaddr.bmdma_addr + ATA_DMA_CMD); /* Strictly, one may wish to issue a readb() here, to * flush the mmio write. However, control also passes @@ -508,96 +309,6 @@ static void ata_bmdma_start_mmio (struct } /** - * ata_bmdma_setup_pio - Set up PCI IDE BMDMA transaction (PIO) - * @qc: Info associated with this ATA transaction. - * - * LOCKING: - * spin_lock_irqsave(host lock) - */ - -static void ata_bmdma_setup_pio (struct ata_queued_cmd *qc) -{ - struct ata_port *ap = qc->ap; - unsigned int rw = (qc->tf.flags & ATA_TFLAG_WRITE); - u8 dmactl; - - /* load PRD table addr. */ - outl(ap->prd_dma, ap->ioaddr.bmdma_addr + ATA_DMA_TABLE_OFS); - - /* specify data direction, triple-check start bit is clear */ - dmactl = inb(ap->ioaddr.bmdma_addr + ATA_DMA_CMD); - dmactl &= ~(ATA_DMA_WR | ATA_DMA_START); - if (!rw) - dmactl |= ATA_DMA_WR; - outb(dmactl, ap->ioaddr.bmdma_addr + ATA_DMA_CMD); - - /* issue r/w command */ - ap->ops->exec_command(ap, &qc->tf); -} - -/** - * ata_bmdma_start_pio - Start a PCI IDE BMDMA transaction (PIO) - * @qc: Info associated with this ATA transaction. - * - * LOCKING: - * spin_lock_irqsave(host lock) - */ - -static void ata_bmdma_start_pio (struct ata_queued_cmd *qc) -{ - struct ata_port *ap = qc->ap; - u8 dmactl; - - /* start host DMA transaction */ - dmactl = inb(ap->ioaddr.bmdma_addr + ATA_DMA_CMD); - outb(dmactl | ATA_DMA_START, - ap->ioaddr.bmdma_addr + ATA_DMA_CMD); -} - - -/** - * ata_bmdma_start - Start a PCI IDE BMDMA transaction - * @qc: Info associated with this ATA transaction. - * - * Writes the ATA_DMA_START flag to the DMA command register. - * - * May be used as the bmdma_start() entry in ata_port_operations. - * - * LOCKING: - * spin_lock_irqsave(host lock) - */ -void ata_bmdma_start(struct ata_queued_cmd *qc) -{ - if (qc->ap->flags & ATA_FLAG_MMIO) - ata_bmdma_start_mmio(qc); - else - ata_bmdma_start_pio(qc); -} - - -/** - * ata_bmdma_setup - Set up PCI IDE BMDMA transaction - * @qc: Info associated with this ATA transaction. - * - * Writes address of PRD table to device's PRD Table Address - * register, sets the DMA control register, and calls - * ops->exec_command() to start the transfer. - * - * May be used as the bmdma_setup() entry in ata_port_operations. - * - * LOCKING: - * spin_lock_irqsave(host lock) - */ -void ata_bmdma_setup(struct ata_queued_cmd *qc) -{ - if (qc->ap->flags & ATA_FLAG_MMIO) - ata_bmdma_setup_mmio(qc); - else - ata_bmdma_setup_pio(qc); -} - - -/** * ata_bmdma_irq_clear - Clear PCI IDE BMDMA interrupt. * @ap: Port associated with this ATA transaction. * @@ -608,23 +319,16 @@ void ata_bmdma_setup(struct ata_queued_c * LOCKING: * spin_lock_irqsave(host lock) */ - void ata_bmdma_irq_clear(struct ata_port *ap) { - if (!ap->ioaddr.bmdma_addr) + void __iomem *mmio = ap->ioaddr.bmdma_addr; + + if (!mmio) return; - if (ap->flags & ATA_FLAG_MMIO) { - void __iomem *mmio = - ((void __iomem *) ap->ioaddr.bmdma_addr) + ATA_DMA_STATUS; - writeb(readb(mmio), mmio); - } else { - unsigned long addr = ap->ioaddr.bmdma_addr + ATA_DMA_STATUS; - outb(inb(addr), addr); - } + iowrite8(ioread8(mmio + ATA_DMA_STATUS), mmio + ATA_DMA_STATUS); } - /** * ata_bmdma_status - Read PCI IDE BMDMA status * @ap: Port associated with this ATA transaction. @@ -636,19 +340,11 @@ void ata_bmdma_irq_clear(struct ata_port * LOCKING: * spin_lock_irqsave(host lock) */ - u8 ata_bmdma_status(struct ata_port *ap) { - u8 host_stat; - if (ap->flags & ATA_FLAG_MMIO) { - void __iomem *mmio = (void __iomem *) ap->ioaddr.bmdma_addr; - host_stat = readb(mmio + ATA_DMA_STATUS); - } else - host_stat = inb(ap->ioaddr.bmdma_addr + ATA_DMA_STATUS); - return host_stat; + return ioread8(ap->ioaddr.bmdma_addr + ATA_DMA_STATUS); } - /** * ata_bmdma_stop - Stop PCI IDE BMDMA transfer * @qc: Command we are ending DMA for @@ -660,21 +356,14 @@ u8 ata_bmdma_status(struct ata_port *ap) * LOCKING: * spin_lock_irqsave(host lock) */ - void ata_bmdma_stop(struct ata_queued_cmd *qc) { struct ata_port *ap = qc->ap; - if (ap->flags & ATA_FLAG_MMIO) { - void __iomem *mmio = (void __iomem *) ap->ioaddr.bmdma_addr; + void __iomem *mmio = ap->ioaddr.bmdma_addr; - /* clear start/stop bit */ - writeb(readb(mmio + ATA_DMA_CMD) & ~ATA_DMA_START, - mmio + ATA_DMA_CMD); - } else { - /* clear start/stop bit */ - outb(inb(ap->ioaddr.bmdma_addr + ATA_DMA_CMD) & ~ATA_DMA_START, - ap->ioaddr.bmdma_addr + ATA_DMA_CMD); - } + /* clear start/stop bit */ + iowrite8(ioread8(mmio + ATA_DMA_CMD) & ~ATA_DMA_START, + mmio + ATA_DMA_CMD); /* one-PIO-cycle guaranteed wait, per spec, for HDMA1:0 transition */ ata_altstatus(ap); /* dummy read */ @@ -696,10 +385,7 @@ void ata_bmdma_freeze(struct ata_port *a ap->ctl |= ATA_NIEN; ap->last_ctl = ap->ctl; - if (ap->flags & ATA_FLAG_MMIO) - writeb(ap->ctl, (void __iomem *)ioaddr->ctl_addr); - else - outb(ap->ctl, ioaddr->ctl_addr); + iowrite8(ap->ctl, ioaddr->ctl_addr); /* Under certain circumstances, some controllers raise IRQ on * ATA_NIEN manipulation. Also, many controllers fail to mask @@ -724,8 +410,7 @@ void ata_bmdma_thaw(struct ata_port *ap) /* clear & re-enable interrupts */ ata_chk_status(ap); ap->ops->irq_clear(ap); - if (ap->ioaddr.ctl_addr) /* FIXME: hack. create a hook instead */ - ata_irq_on(ap); + ap->ops->irq_on(ap); } /** @@ -775,7 +460,7 @@ void ata_bmdma_drive_eh(struct ata_port * really a timeout event, adjust error mask and * cancel frozen state. */ - if (qc->err_mask == AC_ERR_TIMEOUT && host_stat & ATA_DMA_ERR) { + if (qc->err_mask == AC_ERR_TIMEOUT && (host_stat & ATA_DMA_ERR)) { qc->err_mask = AC_ERR_HOST_BUS; thaw = 1; } @@ -832,6 +517,21 @@ void ata_bmdma_post_internal_cmd(struct } #ifdef CONFIG_PCI + +static int ata_resources_present(struct pci_dev *pdev, int port) +{ + int i; + + /* Check the PCI resources for this channel are enabled */ + port = port * 2; + for (i = 0; i < 2; i ++) { + if (pci_resource_start(pdev, port + i) == 0 || + pci_resource_len(pdev, port + i) == 0) + return 0; + } + return 1; +} + /** * ata_pci_init_native_mode - Initialize native-mode driver * @pdev: pci device to be initialized @@ -853,45 +553,62 @@ #ifdef CONFIG_PCI struct ata_probe_ent * ata_pci_init_native_mode(struct pci_dev *pdev, struct ata_port_info **port, int ports) { - struct ata_probe_ent *probe_ent = - ata_probe_ent_alloc(pci_dev_to_dev(pdev), port[0]); - int p = 0; - unsigned long bmdma; + struct ata_probe_ent *probe_ent; + int i, p = 0; + void __iomem * const *iomap; + + /* iomap BARs */ + for (i = 0; i < 4; i++) { + if (pcim_iomap(pdev, i, 0) == NULL) { + dev_printk(KERN_ERR, &pdev->dev, + "failed to iomap PCI BAR %d\n", i); + return NULL; + } + } + pcim_iomap(pdev, 4, 0); /* may fail */ + iomap = pcim_iomap_table(pdev); + + /* alloc and init probe_ent */ + probe_ent = ata_probe_ent_alloc(pci_dev_to_dev(pdev), port[0]); if (!probe_ent) return NULL; probe_ent->irq = pdev->irq; probe_ent->irq_flags = IRQF_SHARED; + + /* Discard disabled ports. Some controllers show their + unused channels this way */ + if (ata_resources_present(pdev, 0) == 0) + ports &= ~ATA_PORT_PRIMARY; + if (ata_resources_present(pdev, 1) == 0) + ports &= ~ATA_PORT_SECONDARY; if (ports & ATA_PORT_PRIMARY) { - probe_ent->port[p].cmd_addr = pci_resource_start(pdev, 0); + probe_ent->port[p].cmd_addr = iomap[0]; probe_ent->port[p].altstatus_addr = - probe_ent->port[p].ctl_addr = - pci_resource_start(pdev, 1) | ATA_PCI_CTL_OFS; - bmdma = pci_resource_start(pdev, 4); - if (bmdma) { + probe_ent->port[p].ctl_addr = (void __iomem *) + ((unsigned long)iomap[1] | ATA_PCI_CTL_OFS); + if (iomap[4]) { if ((!(port[p]->flags & ATA_FLAG_IGN_SIMPLEX)) && - (inb(bmdma + 2) & 0x80)) + (ioread8(iomap[4] + 2) & 0x80)) probe_ent->_host_flags |= ATA_HOST_SIMPLEX; - probe_ent->port[p].bmdma_addr = bmdma; + probe_ent->port[p].bmdma_addr = iomap[4]; } ata_std_ports(&probe_ent->port[p]); p++; } if (ports & ATA_PORT_SECONDARY) { - probe_ent->port[p].cmd_addr = pci_resource_start(pdev, 2); + probe_ent->port[p].cmd_addr = iomap[2]; probe_ent->port[p].altstatus_addr = - probe_ent->port[p].ctl_addr = - pci_resource_start(pdev, 3) | ATA_PCI_CTL_OFS; - bmdma = pci_resource_start(pdev, 4); - if (bmdma) { - bmdma += 8; + probe_ent->port[p].ctl_addr = (void __iomem *) + ((unsigned long)iomap[3] | ATA_PCI_CTL_OFS); + if (iomap[4]) { if ((!(port[p]->flags & ATA_FLAG_IGN_SIMPLEX)) && - (inb(bmdma + 2) & 0x80)) + (ioread8(iomap[4] + 10) & 0x80)) probe_ent->_host_flags |= ATA_HOST_SIMPLEX; - probe_ent->port[p].bmdma_addr = bmdma; + probe_ent->port[p].bmdma_addr = iomap[4] + 8; } ata_std_ports(&probe_ent->port[p]); probe_ent->pinfo2 = port[1]; @@ -902,13 +619,29 @@ ata_pci_init_native_mode(struct pci_dev return probe_ent; } - static struct ata_probe_ent *ata_pci_init_legacy_port(struct pci_dev *pdev, struct ata_port_info **port, int port_mask) { struct ata_probe_ent *probe_ent; - unsigned long bmdma = pci_resource_start(pdev, 4); + void __iomem *iomap[5] = { }, *bmdma; + + if (port_mask & ATA_PORT_PRIMARY) { + iomap[0] = devm_ioport_map(&pdev->dev, ATA_PRIMARY_CMD, 8); + iomap[1] = devm_ioport_map(&pdev->dev, ATA_PRIMARY_CTL, 1); + if (!iomap[0] || !iomap[1]) + return NULL; + } + + if (port_mask & ATA_PORT_SECONDARY) { + iomap[2] = devm_ioport_map(&pdev->dev, ATA_SECONDARY_CMD, 8); + iomap[3] = devm_ioport_map(&pdev->dev, ATA_SECONDARY_CTL, 1); + if (!iomap[2] || !iomap[3]) + return NULL; + } + bmdma = pcim_iomap(pdev, 4, 16); /* may fail */ + + /* alloc and init probe_ent */ probe_ent = ata_probe_ent_alloc(pci_dev_to_dev(pdev), port[0]); if (!probe_ent) return NULL; @@ -918,13 +651,13 @@ static struct ata_probe_ent *ata_pci_ini if (port_mask & ATA_PORT_PRIMARY) { probe_ent->irq = ATA_PRIMARY_IRQ(pdev); - probe_ent->port[0].cmd_addr = ATA_PRIMARY_CMD; + probe_ent->port[0].cmd_addr = iomap[0]; probe_ent->port[0].altstatus_addr = - probe_ent->port[0].ctl_addr = ATA_PRIMARY_CTL; + probe_ent->port[0].ctl_addr = iomap[1]; if (bmdma) { probe_ent->port[0].bmdma_addr = bmdma; if ((!(port[0]->flags & ATA_FLAG_IGN_SIMPLEX)) && - (inb(bmdma + 2) & 0x80)) + (ioread8(bmdma + 2) & 0x80)) probe_ent->_host_flags |= ATA_HOST_SIMPLEX; } ata_std_ports(&probe_ent->port[0]); @@ -936,13 +669,13 @@ static struct ata_probe_ent *ata_pci_ini probe_ent->irq2 = ATA_SECONDARY_IRQ(pdev); else probe_ent->irq = ATA_SECONDARY_IRQ(pdev); - probe_ent->port[1].cmd_addr = ATA_SECONDARY_CMD; + probe_ent->port[1].cmd_addr = iomap[2]; probe_ent->port[1].altstatus_addr = - probe_ent->port[1].ctl_addr = ATA_SECONDARY_CTL; + probe_ent->port[1].ctl_addr = iomap[3]; if (bmdma) { probe_ent->port[1].bmdma_addr = bmdma + 8; if ((!(port[1]->flags & ATA_FLAG_IGN_SIMPLEX)) && - (inb(bmdma + 10) & 0x80)) + (ioread8(bmdma + 10) & 0x80)) probe_ent->_host_flags |= ATA_HOST_SIMPLEX; } ata_std_ports(&probe_ent->port[1]); @@ -984,15 +717,18 @@ static struct ata_probe_ent *ata_pci_ini int ata_pci_init_one (struct pci_dev *pdev, struct ata_port_info **port_info, unsigned int n_ports) { + struct device *dev = &pdev->dev; struct ata_probe_ent *probe_ent = NULL; struct ata_port_info *port[2]; u8 mask; unsigned int legacy_mode = 0; - int disable_dev_on_err = 1; int rc; DPRINTK("ENTER\n"); + if (!devres_open_group(dev, NULL, GFP_KERNEL)) + return -ENOMEM; + BUG_ON(n_ports < 1 || n_ports > 2); port[0] = port_info[0]; @@ -1009,9 +745,9 @@ int ata_pci_init_one (struct pci_dev *pd boot for the primary video which is BIOS enabled */ - rc = pci_enable_device(pdev); + rc = pcim_enable_device(pdev); if (rc) - return rc; + goto err_out; if ((pdev->class >> 8) == PCI_CLASS_STORAGE_IDE) { u8 tmp8; @@ -1027,7 +763,8 @@ #if defined(CONFIG_NO_ATA_LEGACY) left a device in compatibility mode */ if (legacy_mode) { printk(KERN_ERR "ata: Compatibility mode ATA is not supported on this platform, skipping.\n"); - return -EOPNOTSUPP; + rc = -EOPNOTSUPP; + goto err_out; } #endif } @@ -1035,13 +772,13 @@ #endif if (!legacy_mode) { rc = pci_request_regions(pdev, DRV_NAME); if (rc) { - disable_dev_on_err = 0; + pcim_pin_device(pdev); goto err_out; } } else { /* Deal with combined mode hack. This side of the logic all goes away once the combined mode hack is killed in 2.6.21 */ - if (!request_region(ATA_PRIMARY_CMD, 8, "libata")) { + if (!devm_request_region(dev, ATA_PRIMARY_CMD, 8, "libata")) { struct resource *conflict, res; res.start = ATA_PRIMARY_CMD; res.end = ATA_PRIMARY_CMD + 8 - 1; @@ -1051,7 +788,7 @@ #endif if (!strcmp(conflict->name, "libata")) legacy_mode |= ATA_PORT_PRIMARY; else { - disable_dev_on_err = 0; + pcim_pin_device(pdev); printk(KERN_WARNING "ata: 0x%0X IDE port busy\n" \ "ata: conflict with %s\n", ATA_PRIMARY_CMD, @@ -1060,7 +797,7 @@ #endif } else legacy_mode |= ATA_PORT_PRIMARY; - if (!request_region(ATA_SECONDARY_CMD, 8, "libata")) { + if (!devm_request_region(dev, ATA_SECONDARY_CMD, 8, "libata")) { struct resource *conflict, res; res.start = ATA_SECONDARY_CMD; res.end = ATA_SECONDARY_CMD + 8 - 1; @@ -1070,7 +807,7 @@ #endif if (!strcmp(conflict->name, "libata")) legacy_mode |= ATA_PORT_SECONDARY; else { - disable_dev_on_err = 0; + pcim_pin_device(pdev); printk(KERN_WARNING "ata: 0x%X IDE port busy\n" \ "ata: conflict with %s\n", ATA_SECONDARY_CMD, @@ -1090,16 +827,16 @@ #endif /* we have legacy mode, but all ports are unavailable */ if (legacy_mode == (1 << 3)) { rc = -EBUSY; - goto err_out_regions; + goto err_out; } /* TODO: If we get no DMA mask we should fall back to PIO */ rc = pci_set_dma_mask(pdev, ATA_DMA_MASK); if (rc) - goto err_out_regions; + goto err_out; rc = pci_set_consistent_dma_mask(pdev, ATA_DMA_MASK); if (rc) - goto err_out_regions; + goto err_out; if (legacy_mode) { probe_ent = ata_pci_init_legacy_port(pdev, port, legacy_mode); @@ -1111,40 +848,22 @@ #endif } if (!probe_ent) { rc = -ENOMEM; - goto err_out_regions; + goto err_out; } pci_set_master(pdev); if (!ata_device_add(probe_ent)) { rc = -ENODEV; - goto err_out_ent; + goto err_out; } - kfree(probe_ent); - + devm_kfree(dev, probe_ent); + devres_remove_group(dev, NULL); return 0; -err_out_ent: - kfree(probe_ent); -err_out_regions: - /* All this conditional stuff is needed for the combined mode hack - until 2.6.21 when it can go */ - if (legacy_mode) { - pci_release_region(pdev, 4); - if (legacy_mode & ATA_PORT_PRIMARY) { - release_region(ATA_PRIMARY_CMD, 8); - pci_release_region(pdev, 1); - } - if (legacy_mode & ATA_PORT_SECONDARY) { - release_region(ATA_SECONDARY_CMD, 8); - pci_release_region(pdev, 3); - } - } else - pci_release_regions(pdev); err_out: - if (disable_dev_on_err) - pci_disable_device(pdev); + devres_release_group(dev, NULL); return rc; } diff --git a/drivers/ata/libata.h b/drivers/ata/libata.h index 81ae41d..06ccf23 100644 --- a/drivers/ata/libata.h +++ b/drivers/ata/libata.h @@ -29,7 +29,6 @@ #ifndef __LIBATA_H__ #define __LIBATA_H__ #define DRV_NAME "libata" -#define DRV_VERSION "2.00" /* must be exactly four chars */ struct ata_scsi_args { struct ata_device *dev; @@ -136,4 +135,7 @@ extern void ata_qc_schedule_eh(struct at /* libata-sff.c */ extern u8 ata_irq_on(struct ata_port *ap); +/* pata_sis.c */ +extern struct ata_port_info sis_info133; + #endif /* __LIBATA_H__ */ diff --git a/drivers/ata/pata_ali.c b/drivers/ata/pata_ali.c index c5d61d1..ab44d18 100644 --- a/drivers/ata/pata_ali.c +++ b/drivers/ata/pata_ali.c @@ -153,11 +153,11 @@ static void ali_early_error_handler(stru static unsigned long ali_20_filter(const struct ata_port *ap, struct ata_device *adev, unsigned long mask) { - char model_num[40]; + char model_num[ATA_ID_PROD_LEN + 1]; /* No DMA on anything but a disk for now */ if (adev->class != ATA_DEV_ATA) mask &= ~(ATA_MASK_MWDMA | ATA_MASK_UDMA); - ata_id_string(adev->id, model_num, ATA_ID_PROD_OFS, sizeof(model_num)); + ata_id_c_string(adev->id, model_num, ATA_ID_PROD, sizeof(model_num)); if (strstr(model_num, "WDC")) return mask &= ~ATA_MASK_UDMA; return ata_pci_default_filter(ap, adev, mask); @@ -370,14 +370,14 @@ static struct ata_port_operations ali_ea .qc_prep = ata_qc_prep, .qc_issue = ata_qc_issue_prot, - .data_xfer = ata_pio_data_xfer, + .data_xfer = ata_data_xfer, .irq_handler = ata_interrupt, .irq_clear = ata_bmdma_irq_clear, + .irq_on = ata_irq_on, + .irq_ack = ata_irq_ack, .port_start = ata_port_start, - .port_stop = ata_port_stop, - .host_stop = ata_host_stop }; /* @@ -411,14 +411,14 @@ static struct ata_port_operations ali_20 .qc_prep = ata_qc_prep, .qc_issue = ata_qc_issue_prot, - .data_xfer = ata_pio_data_xfer, + .data_xfer = ata_data_xfer, .irq_handler = ata_interrupt, .irq_clear = ata_bmdma_irq_clear, + .irq_on = ata_irq_on, + .irq_ack = ata_irq_ack, .port_start = ata_port_start, - .port_stop = ata_port_stop, - .host_stop = ata_host_stop }; /* @@ -449,14 +449,14 @@ static struct ata_port_operations ali_c2 .qc_prep = ata_qc_prep, .qc_issue = ata_qc_issue_prot, - .data_xfer = ata_pio_data_xfer, + .data_xfer = ata_data_xfer, .irq_handler = ata_interrupt, .irq_clear = ata_bmdma_irq_clear, + .irq_on = ata_irq_on, + .irq_ack = ata_irq_ack, .port_start = ata_port_start, - .port_stop = ata_port_stop, - .host_stop = ata_host_stop }; /* @@ -486,14 +486,14 @@ static struct ata_port_operations ali_c5 .qc_prep = ata_qc_prep, .qc_issue = ata_qc_issue_prot, - .data_xfer = ata_pio_data_xfer, + .data_xfer = ata_data_xfer, .irq_handler = ata_interrupt, .irq_clear = ata_bmdma_irq_clear, + .irq_on = ata_irq_on, + .irq_ack = ata_irq_ack, .port_start = ata_port_start, - .port_stop = ata_port_stop, - .host_stop = ata_host_stop }; @@ -504,7 +504,7 @@ static struct ata_port_operations ali_c5 * Perform the setup on the device that must be done both at boot * and at resume time. */ - + static void ali_init_chipset(struct pci_dev *pdev) { u8 rev, tmp; @@ -655,7 +655,7 @@ static int ali_init_one(struct pci_dev * port_info[0] = port_info[1] = &info_c5; ali_init_chipset(pdev); - + isa_bridge = pci_get_device(PCI_VENDOR_ID_AL, PCI_DEVICE_ID_AL_M1533, NULL); if (isa_bridge && rev >= 0x20 && rev < 0xC2) { /* Are we paired with a UDMA capable chip */ diff --git a/drivers/ata/pata_amd.c b/drivers/ata/pata_amd.c index a6b3300..619e44b 100644 --- a/drivers/ata/pata_amd.c +++ b/drivers/ata/pata_amd.c @@ -362,14 +362,14 @@ static struct ata_port_operations amd33_ .qc_prep = ata_qc_prep, .qc_issue = ata_qc_issue_prot, - .data_xfer = ata_pio_data_xfer, + .data_xfer = ata_data_xfer, .irq_handler = ata_interrupt, .irq_clear = ata_bmdma_irq_clear, + .irq_on = ata_irq_on, + .irq_ack = ata_irq_ack, .port_start = ata_port_start, - .port_stop = ata_port_stop, - .host_stop = ata_host_stop }; static struct ata_port_operations amd66_port_ops = { @@ -396,14 +396,14 @@ static struct ata_port_operations amd66_ .qc_prep = ata_qc_prep, .qc_issue = ata_qc_issue_prot, - .data_xfer = ata_pio_data_xfer, + .data_xfer = ata_data_xfer, .irq_handler = ata_interrupt, .irq_clear = ata_bmdma_irq_clear, + .irq_on = ata_irq_on, + .irq_ack = ata_irq_ack, .port_start = ata_port_start, - .port_stop = ata_port_stop, - .host_stop = ata_host_stop }; static struct ata_port_operations amd100_port_ops = { @@ -430,14 +430,14 @@ static struct ata_port_operations amd100 .qc_prep = ata_qc_prep, .qc_issue = ata_qc_issue_prot, - .data_xfer = ata_pio_data_xfer, + .data_xfer = ata_data_xfer, .irq_handler = ata_interrupt, .irq_clear = ata_bmdma_irq_clear, + .irq_on = ata_irq_on, + .irq_ack = ata_irq_ack, .port_start = ata_port_start, - .port_stop = ata_port_stop, - .host_stop = ata_host_stop }; static struct ata_port_operations amd133_port_ops = { @@ -464,14 +464,14 @@ static struct ata_port_operations amd133 .qc_prep = ata_qc_prep, .qc_issue = ata_qc_issue_prot, - .data_xfer = ata_pio_data_xfer, + .data_xfer = ata_data_xfer, .irq_handler = ata_interrupt, .irq_clear = ata_bmdma_irq_clear, + .irq_on = ata_irq_on, + .irq_ack = ata_irq_ack, .port_start = ata_port_start, - .port_stop = ata_port_stop, - .host_stop = ata_host_stop }; static struct ata_port_operations nv100_port_ops = { @@ -498,14 +498,14 @@ static struct ata_port_operations nv100_ .qc_prep = ata_qc_prep, .qc_issue = ata_qc_issue_prot, - .data_xfer = ata_pio_data_xfer, + .data_xfer = ata_data_xfer, .irq_handler = ata_interrupt, .irq_clear = ata_bmdma_irq_clear, + .irq_on = ata_irq_on, + .irq_ack = ata_irq_ack, .port_start = ata_port_start, - .port_stop = ata_port_stop, - .host_stop = ata_host_stop }; static struct ata_port_operations nv133_port_ops = { @@ -532,14 +532,14 @@ static struct ata_port_operations nv133_ .qc_prep = ata_qc_prep, .qc_issue = ata_qc_issue_prot, - .data_xfer = ata_pio_data_xfer, + .data_xfer = ata_data_xfer, .irq_handler = ata_interrupt, .irq_clear = ata_bmdma_irq_clear, + .irq_on = ata_irq_on, + .irq_ack = ata_irq_ack, .port_start = ata_port_start, - .port_stop = ata_port_stop, - .host_stop = ata_host_stop }; static int amd_init_one(struct pci_dev *pdev, const struct pci_device_id *id) diff --git a/drivers/ata/pata_artop.c b/drivers/ata/pata_artop.c index 37bc132..21c3028 100644 --- a/drivers/ata/pata_artop.c +++ b/drivers/ata/pata_artop.c @@ -341,14 +341,14 @@ static const struct ata_port_operations .qc_prep = ata_qc_prep, .qc_issue = ata_qc_issue_prot, - .data_xfer = ata_pio_data_xfer, + .data_xfer = ata_data_xfer, .irq_handler = ata_interrupt, .irq_clear = ata_bmdma_irq_clear, + .irq_on = ata_irq_on, + .irq_ack = ata_irq_ack, .port_start = ata_port_start, - .port_stop = ata_port_stop, - .host_stop = ata_host_stop, }; static const struct ata_port_operations artop6260_ops = { @@ -373,14 +373,14 @@ static const struct ata_port_operations .bmdma_status = ata_bmdma_status, .qc_prep = ata_qc_prep, .qc_issue = ata_qc_issue_prot, - .data_xfer = ata_pio_data_xfer, + .data_xfer = ata_data_xfer, .irq_handler = ata_interrupt, .irq_clear = ata_bmdma_irq_clear, + .irq_on = ata_irq_on, + .irq_ack = ata_irq_ack, .port_start = ata_port_start, - .port_stop = ata_port_stop, - .host_stop = ata_host_stop, }; diff --git a/drivers/ata/pata_atiixp.c b/drivers/ata/pata_atiixp.c index 504e1db..c3eb40c 100644 --- a/drivers/ata/pata_atiixp.c +++ b/drivers/ata/pata_atiixp.c @@ -252,14 +252,14 @@ static struct ata_port_operations atiixp .qc_prep = ata_qc_prep, .qc_issue = ata_qc_issue_prot, - .data_xfer = ata_pio_data_xfer, + .data_xfer = ata_data_xfer, .irq_handler = ata_interrupt, .irq_clear = ata_bmdma_irq_clear, + .irq_on = ata_irq_on, + .irq_ack = ata_irq_ack, .port_start = ata_port_start, - .port_stop = ata_port_stop, - .host_stop = ata_host_stop }; static int atiixp_init_one(struct pci_dev *dev, const struct pci_device_id *id) diff --git a/drivers/ata/pata_cmd64x.c b/drivers/ata/pata_cmd64x.c index 449162c..da09828 100644 --- a/drivers/ata/pata_cmd64x.c +++ b/drivers/ata/pata_cmd64x.c @@ -313,14 +313,14 @@ static struct ata_port_operations cmd64x .qc_prep = ata_qc_prep, .qc_issue = ata_qc_issue_prot, - .data_xfer = ata_pio_data_xfer, + .data_xfer = ata_data_xfer, .irq_handler = ata_interrupt, .irq_clear = ata_bmdma_irq_clear, + .irq_on = ata_irq_on, + .irq_ack = ata_irq_ack, .port_start = ata_port_start, - .port_stop = ata_port_stop, - .host_stop = ata_host_stop }; static struct ata_port_operations cmd646r1_port_ops = { @@ -347,14 +347,14 @@ static struct ata_port_operations cmd646 .qc_prep = ata_qc_prep, .qc_issue = ata_qc_issue_prot, - .data_xfer = ata_pio_data_xfer, + .data_xfer = ata_data_xfer, .irq_handler = ata_interrupt, .irq_clear = ata_bmdma_irq_clear, + .irq_on = ata_irq_on, + .irq_ack = ata_irq_ack, .port_start = ata_port_start, - .port_stop = ata_port_stop, - .host_stop = ata_host_stop }; static struct ata_port_operations cmd648_port_ops = { @@ -381,14 +381,14 @@ static struct ata_port_operations cmd648 .qc_prep = ata_qc_prep, .qc_issue = ata_qc_issue_prot, - .data_xfer = ata_pio_data_xfer, + .data_xfer = ata_data_xfer, .irq_handler = ata_interrupt, .irq_clear = ata_bmdma_irq_clear, + .irq_on = ata_irq_on, + .irq_ack = ata_irq_ack, .port_start = ata_port_start, - .port_stop = ata_port_stop, - .host_stop = ata_host_stop }; static int cmd64x_init_one(struct pci_dev *pdev, const struct pci_device_id *id) diff --git a/drivers/ata/pata_cs5520.c b/drivers/ata/pata_cs5520.c index 9f165a8..1ce8fcf 100644 --- a/drivers/ata/pata_cs5520.c +++ b/drivers/ata/pata_cs5520.c @@ -99,9 +99,9 @@ static void cs5520_set_timings(struct at static void cs5520_enable_dma(struct ata_port *ap, struct ata_device *adev) { /* Set the DMA enable/disable flag */ - u8 reg = inb(ap->ioaddr.bmdma_addr + 0x02); + u8 reg = ioread8(ap->ioaddr.bmdma_addr + 0x02); reg |= 1<<(adev->devno + 5); - outb(reg, ap->ioaddr.bmdma_addr + 0x02); + iowrite8(reg, ap->ioaddr.bmdma_addr + 0x02); } /** @@ -193,19 +193,20 @@ static struct ata_port_operations cs5520 .bmdma_status = ata_bmdma_status, .qc_prep = ata_qc_prep, .qc_issue = ata_qc_issue_prot, - .data_xfer = ata_pio_data_xfer, + .data_xfer = ata_data_xfer, .irq_handler = ata_interrupt, .irq_clear = ata_bmdma_irq_clear, + .irq_on = ata_irq_on, + .irq_ack = ata_irq_ack, .port_start = ata_port_start, - .port_stop = ata_port_stop, - .host_stop = ata_host_stop, }; static int __devinit cs5520_init_one(struct pci_dev *dev, const struct pci_device_id *id) { u8 pcicfg; + void *iomap[5]; static struct ata_probe_ent probe[2]; int ports = 0; @@ -236,6 +237,16 @@ static int __devinit cs5520_init_one(str return -ENODEV; } + /* Map IO ports */ + iomap[0] = devm_ioport_map(&dev->dev, 0x1F0, 8); + iomap[1] = devm_ioport_map(&dev->dev, 0x3F6, 1); + iomap[2] = devm_ioport_map(&dev->dev, 0x170, 8); + iomap[3] = devm_ioport_map(&dev->dev, 0x376, 1); + iomap[4] = pcim_iomap(dev, 2, 0); + + if (!iomap[0] || !iomap[1] || !iomap[2] || !iomap[3] || !iomap[4]) + return -ENOMEM; + /* We have to do our own plumbing as the PCI setup for this chipset is non-standard so we can't punt to the libata code */ @@ -249,10 +260,10 @@ static int __devinit cs5520_init_one(str probe[0].irq_flags = 0; probe[0].port_flags = ATA_FLAG_SLAVE_POSS|ATA_FLAG_SRST; probe[0].n_ports = 1; - probe[0].port[0].cmd_addr = 0x1F0; - probe[0].port[0].ctl_addr = 0x3F6; - probe[0].port[0].altstatus_addr = 0x3F6; - probe[0].port[0].bmdma_addr = pci_resource_start(dev, 2); + probe[0].port[0].cmd_addr = iomap[0]; + probe[0].port[0].ctl_addr = iomap[1]; + probe[0].port[0].altstatus_addr = iomap[1]; + probe[0].port[0].bmdma_addr = iomap[4]; /* The secondary lurks at different addresses but is otherwise the same beastie */ @@ -260,10 +271,10 @@ static int __devinit cs5520_init_one(str probe[1] = probe[0]; INIT_LIST_HEAD(&probe[1].node); probe[1].irq = 15; - probe[1].port[0].cmd_addr = 0x170; - probe[1].port[0].ctl_addr = 0x376; - probe[1].port[0].altstatus_addr = 0x376; - probe[1].port[0].bmdma_addr = pci_resource_start(dev, 2) + 8; + probe[1].port[0].cmd_addr = iomap[2]; + probe[1].port[0].ctl_addr = iomap[3]; + probe[1].port[0].altstatus_addr = iomap[3]; + probe[1].port[0].bmdma_addr = iomap[4] + 8; /* Let libata fill in the port details */ ata_std_ports(&probe[0].port[0]); @@ -294,7 +305,7 @@ static void __devexit cs5520_remove_one( struct device *dev = pci_dev_to_dev(pdev); struct ata_host *host = dev_get_drvdata(dev); - ata_host_remove(host); + ata_host_detach(host); dev_set_drvdata(dev, NULL); } @@ -305,7 +316,7 @@ static void __devexit cs5520_remove_one( * Do any reconfiguration work needed by a resume from RAM. We need * to restore DMA mode support on BIOSen which disabled it */ - + static int cs5520_reinit_one(struct pci_dev *pdev) { u8 pcicfg; diff --git a/drivers/ata/pata_cs5530.c b/drivers/ata/pata_cs5530.c index b1ca207..3d7b7d8 100644 --- a/drivers/ata/pata_cs5530.c +++ b/drivers/ata/pata_cs5530.c @@ -37,6 +37,13 @@ #include #define DRV_NAME "pata_cs5530" #define DRV_VERSION "0.7.1" +static void __iomem *cs5530_port_base(struct ata_port *ap) +{ + unsigned long bmdma = (unsigned long)ap->ioaddr.bmdma_addr; + + return (void __iomem *)((bmdma & ~0x0F) + 0x20 + 0x10 * ap->port_no); +} + /** * cs5530_set_piomode - PIO setup * @ap: ATA interface @@ -52,19 +59,19 @@ static void cs5530_set_piomode(struct at {0x00009172, 0x00012171, 0x00020080, 0x00032010, 0x00040010}, {0xd1329172, 0x71212171, 0x30200080, 0x20102010, 0x00100010} }; - unsigned long base = ( ap->ioaddr.bmdma_addr & ~0x0F) + 0x20 + 0x10 * ap->port_no; + void __iomem *base = cs5530_port_base(ap); u32 tuning; int format; /* Find out which table to use */ - tuning = inl(base + 0x04); + tuning = ioread32(base + 0x04); format = (tuning & 0x80000000UL) ? 1 : 0; /* Now load the right timing register */ if (adev->devno) base += 0x08; - outl(cs5530_pio_timings[format][adev->pio_mode - XFER_PIO_0], base); + iowrite32(cs5530_pio_timings[format][adev->pio_mode - XFER_PIO_0], base); } /** @@ -79,12 +86,12 @@ static void cs5530_set_piomode(struct at static void cs5530_set_dmamode(struct ata_port *ap, struct ata_device *adev) { - unsigned long base = ( ap->ioaddr.bmdma_addr & ~0x0F) + 0x20 + 0x10 * ap->port_no; + void __iomem *base = cs5530_port_base(ap); u32 tuning, timing = 0; u8 reg; /* Find out which table to use */ - tuning = inl(base + 0x04); + tuning = ioread32(base + 0x04); switch(adev->dma_mode) { case XFER_UDMA_0: @@ -105,20 +112,20 @@ static void cs5530_set_dmamode(struct at /* Merge in the PIO format bit */ timing |= (tuning & 0x80000000UL); if (adev->devno == 0) /* Master */ - outl(timing, base + 0x04); + iowrite32(timing, base + 0x04); else { if (timing & 0x00100000) tuning |= 0x00100000; /* UDMA for both */ else tuning &= ~0x00100000; /* MWDMA for both */ - outl(tuning, base + 0x04); - outl(timing, base + 0x0C); + iowrite32(tuning, base + 0x04); + iowrite32(timing, base + 0x0C); } /* Set the DMA capable bit in the BMDMA area */ - reg = inb(ap->ioaddr.bmdma_addr + ATA_DMA_STATUS); + reg = ioread8(ap->ioaddr.bmdma_addr + ATA_DMA_STATUS); reg |= (1 << (5 + adev->devno)); - outb(reg, ap->ioaddr.bmdma_addr + ATA_DMA_STATUS); + iowrite8(reg, ap->ioaddr.bmdma_addr + ATA_DMA_STATUS); /* Remember the last DMA setup we did */ @@ -210,14 +217,14 @@ static struct ata_port_operations cs5530 .qc_prep = ata_qc_prep, .qc_issue = cs5530_qc_issue_prot, - .data_xfer = ata_pio_data_xfer, + .data_xfer = ata_data_xfer, .irq_handler = ata_interrupt, .irq_clear = ata_bmdma_irq_clear, + .irq_on = ata_irq_on, + .irq_ack = ata_irq_ack, .port_start = ata_port_start, - .port_stop = ata_port_stop, - .host_stop = ata_host_stop }; static struct dmi_system_id palmax_dmi_table[] = { @@ -247,7 +254,7 @@ static int cs5530_is_palmax(void) * Perform the chip initialisation work that is shared between both * setup and resume paths */ - + static int cs5530_init_chip(void) { struct pci_dev *master_0 = NULL, *cs5530_0 = NULL, *dev = NULL; @@ -357,11 +364,11 @@ static int cs5530_init_one(struct pci_de .port_ops = &cs5530_port_ops }; static struct ata_port_info *port_info[2] = { &info, &info }; - + /* Chip initialisation */ if (cs5530_init_chip()) return -ENODEV; - + if (cs5530_is_palmax()) port_info[1] = &info_palmax_secondary; @@ -376,7 +383,7 @@ static int cs5530_reinit_one(struct pci_ BUG(); return ata_pci_device_resume(pdev); } - + static const struct pci_device_id cs5530[] = { { PCI_VDEVICE(CYRIX, PCI_DEVICE_ID_CYRIX_5530_IDE), }, diff --git a/drivers/ata/pata_cs5535.c b/drivers/ata/pata_cs5535.c index e3efec4..17bc693 100644 --- a/drivers/ata/pata_cs5535.c +++ b/drivers/ata/pata_cs5535.c @@ -214,14 +214,14 @@ static struct ata_port_operations cs5535 .qc_prep = ata_qc_prep, .qc_issue = ata_qc_issue_prot, - .data_xfer = ata_pio_data_xfer, + .data_xfer = ata_data_xfer, .irq_handler = ata_interrupt, .irq_clear = ata_bmdma_irq_clear, + .irq_on = ata_irq_on, + .irq_ack = ata_irq_ack, .port_start = ata_port_start, - .port_stop = ata_port_stop, - .host_stop = ata_host_stop }; /** diff --git a/drivers/ata/pata_cypress.c b/drivers/ata/pata_cypress.c index e2a9569..63f48f0 100644 --- a/drivers/ata/pata_cypress.c +++ b/drivers/ata/pata_cypress.c @@ -165,14 +165,14 @@ static struct ata_port_operations cy82c6 .qc_prep = ata_qc_prep, .qc_issue = ata_qc_issue_prot, - .data_xfer = ata_pio_data_xfer, + .data_xfer = ata_data_xfer, .irq_handler = ata_interrupt, .irq_clear = ata_bmdma_irq_clear, + .irq_on = ata_irq_on, + .irq_ack = ata_irq_ack, .port_start = ata_port_start, - .port_stop = ata_port_stop, - .host_stop = ata_host_stop }; static int cy82c693_init_one(struct pci_dev *pdev, const struct pci_device_id *id) diff --git a/drivers/ata/pata_efar.c b/drivers/ata/pata_efar.c index edf8a63..c19b6a8 100644 --- a/drivers/ata/pata_efar.c +++ b/drivers/ata/pata_efar.c @@ -261,14 +261,14 @@ static const struct ata_port_operations .bmdma_status = ata_bmdma_status, .qc_prep = ata_qc_prep, .qc_issue = ata_qc_issue_prot, - .data_xfer = ata_pio_data_xfer, + .data_xfer = ata_data_xfer, .irq_handler = ata_interrupt, .irq_clear = ata_bmdma_irq_clear, + .irq_on = ata_irq_on, + .irq_ack = ata_irq_ack, .port_start = ata_port_start, - .port_stop = ata_port_stop, - .host_stop = ata_host_stop, }; diff --git a/drivers/ata/pata_hpt366.c b/drivers/ata/pata_hpt366.c index 2663599..27d724b 100644 --- a/drivers/ata/pata_hpt366.c +++ b/drivers/ata/pata_hpt366.c @@ -151,23 +151,13 @@ static const char *bad_ata66_3[] = { static int hpt_dma_blacklisted(const struct ata_device *dev, char *modestr, const char *list[]) { - unsigned char model_num[40]; - char *s; - unsigned int len; + unsigned char model_num[ATA_ID_PROD_LEN + 1]; int i = 0; - ata_id_string(dev->id, model_num, ATA_ID_PROD_OFS, sizeof(model_num)); - s = &model_num[0]; - len = strnlen(s, sizeof(model_num)); + ata_id_c_string(dev->id, model_num, ATA_ID_PROD, sizeof(model_num)); - /* ATAPI specifies that empty space is blank-filled; remove blanks */ - while ((len > 0) && (s[len - 1] == ' ')) { - len--; - s[len] = 0; - } - - while(list[i] != NULL) { - if (!strncmp(list[i], s, len)) { + while (list[i] != NULL) { + if (!strcmp(list[i], model_num)) { printk(KERN_WARNING DRV_NAME ": %s is not supported for %s.\n", modestr, list[i]); return 1; @@ -232,7 +222,7 @@ static int hpt36x_pre_reset(struct ata_p if (!pci_test_config_bits(pdev, &hpt36x_enable_bits[ap->port_no])) return -ENOENT; - + pci_read_config_byte(pdev, 0x5A, &ata66); if (ata66 & (1 << ap->port_no)) ap->cbl = ATA_CBL_PATA40; @@ -371,14 +361,14 @@ static struct ata_port_operations hpt366 .qc_prep = ata_qc_prep, .qc_issue = ata_qc_issue_prot, - .data_xfer = ata_pio_data_xfer, + .data_xfer = ata_data_xfer, .irq_handler = ata_interrupt, .irq_clear = ata_bmdma_irq_clear, + .irq_on = ata_irq_on, + .irq_ack = ata_irq_ack, .port_start = ata_port_start, - .port_stop = ata_port_stop, - .host_stop = ata_host_stop }; /** diff --git a/drivers/ata/pata_hpt37x.c b/drivers/ata/pata_hpt37x.c index dfb3060..4ffc392 100644 --- a/drivers/ata/pata_hpt37x.c +++ b/drivers/ata/pata_hpt37x.c @@ -349,24 +349,13 @@ static u32 hpt37x_find_mode(struct ata_p static int hpt_dma_blacklisted(const struct ata_device *dev, char *modestr, const char *list[]) { - unsigned char model_num[40]; - char *s; - unsigned int len; + unsigned char model_num[ATA_ID_PROD_LEN + 1]; int i = 0; - ata_id_string(dev->id, model_num, ATA_ID_PROD_OFS, - sizeof(model_num)); - s = &model_num[0]; - len = strnlen(s, sizeof(model_num)); + ata_id_c_string(dev->id, model_num, ATA_ID_PROD, sizeof(model_num)); - /* ATAPI specifies that empty space is blank-filled; remove blanks */ - while ((len > 0) && (s[len - 1] == ' ')) { - len--; - s[len] = 0; - } - - while(list[i] != NULL) { - if (!strncmp(list[i], s, len)) { + while (list[i] != NULL) { + if (!strcmp(list[i], model_num)) { printk(KERN_WARNING DRV_NAME ": %s is not supported for %s.\n", modestr, list[i]); return 1; @@ -459,7 +448,7 @@ static int hpt37x_pre_reset(struct ata_p }; if (!pci_test_config_bits(pdev, &hpt37x_enable_bits[ap->port_no])) return -ENOENT; - + pci_read_config_byte(pdev, 0x5B, &scr2); pci_write_config_byte(pdev, 0x5B, scr2 & ~0x01); /* Cable register now active */ @@ -504,7 +493,7 @@ static int hpt374_pre_reset(struct ata_p if (!pci_test_config_bits(pdev, &hpt37x_enable_bits[ap->port_no])) return -ENOENT; - + /* Do the extra channel work */ pci_read_config_word(pdev, 0x52, &mcr3); pci_read_config_word(pdev, 0x56, &mcr6); @@ -645,24 +634,24 @@ static void hpt370_bmdma_stop(struct ata { struct ata_port *ap = qc->ap; struct pci_dev *pdev = to_pci_dev(ap->host->dev); - u8 dma_stat = inb(ap->ioaddr.bmdma_addr + 2); + u8 dma_stat = ioread8(ap->ioaddr.bmdma_addr + 2); u8 dma_cmd; - unsigned long bmdma = ap->ioaddr.bmdma_addr; + void __iomem *bmdma = ap->ioaddr.bmdma_addr; if (dma_stat & 0x01) { udelay(20); - dma_stat = inb(bmdma + 2); + dma_stat = ioread8(bmdma + 2); } if (dma_stat & 0x01) { /* Clear the engine */ pci_write_config_byte(pdev, 0x50 + 4 * ap->port_no, 0x37); udelay(10); /* Stop DMA */ - dma_cmd = inb(bmdma ); - outb(dma_cmd & 0xFE, bmdma); + dma_cmd = ioread8(bmdma ); + iowrite8(dma_cmd & 0xFE, bmdma); /* Clear Error */ - dma_stat = inb(bmdma + 2); - outb(dma_stat | 0x06 , bmdma + 2); + dma_stat = ioread8(bmdma + 2); + iowrite8(dma_stat | 0x06 , bmdma + 2); /* Clear the engine */ pci_write_config_byte(pdev, 0x50 + 4 * ap->port_no, 0x37); udelay(10); @@ -807,14 +796,14 @@ static struct ata_port_operations hpt370 .qc_prep = ata_qc_prep, .qc_issue = ata_qc_issue_prot, - .data_xfer = ata_pio_data_xfer, + .data_xfer = ata_data_xfer, .irq_handler = ata_interrupt, .irq_clear = ata_bmdma_irq_clear, + .irq_on = ata_irq_on, + .irq_ack = ata_irq_ack, .port_start = ata_port_start, - .port_stop = ata_port_stop, - .host_stop = ata_host_stop }; /* @@ -846,14 +835,14 @@ static struct ata_port_operations hpt370 .qc_prep = ata_qc_prep, .qc_issue = ata_qc_issue_prot, - .data_xfer = ata_pio_data_xfer, + .data_xfer = ata_data_xfer, .irq_handler = ata_interrupt, .irq_clear = ata_bmdma_irq_clear, + .irq_on = ata_irq_on, + .irq_ack = ata_irq_ack, .port_start = ata_port_start, - .port_stop = ata_port_stop, - .host_stop = ata_host_stop }; /* @@ -886,14 +875,14 @@ static struct ata_port_operations hpt372 .qc_prep = ata_qc_prep, .qc_issue = ata_qc_issue_prot, - .data_xfer = ata_pio_data_xfer, + .data_xfer = ata_data_xfer, .irq_handler = ata_interrupt, .irq_clear = ata_bmdma_irq_clear, + .irq_on = ata_irq_on, + .irq_ack = ata_irq_ack, .port_start = ata_port_start, - .port_stop = ata_port_stop, - .host_stop = ata_host_stop }; /* @@ -926,14 +915,14 @@ static struct ata_port_operations hpt374 .qc_prep = ata_qc_prep, .qc_issue = ata_qc_issue_prot, - .data_xfer = ata_pio_data_xfer, + .data_xfer = ata_data_xfer, .irq_handler = ata_interrupt, .irq_clear = ata_bmdma_irq_clear, + .irq_on = ata_irq_on, + .irq_ack = ata_irq_ack, .port_start = ata_port_start, - .port_stop = ata_port_stop, - .host_stop = ata_host_stop }; /** diff --git a/drivers/ata/pata_hpt3x2n.c b/drivers/ata/pata_hpt3x2n.c index 886fab9..65f2e18 100644 --- a/drivers/ata/pata_hpt3x2n.c +++ b/drivers/ata/pata_hpt3x2n.c @@ -263,26 +263,26 @@ static void hpt3x2n_bmdma_stop(struct at static void hpt3x2n_set_clock(struct ata_port *ap, int source) { - unsigned long bmdma = ap->ioaddr.bmdma_addr; + void __iomem *bmdma = ap->ioaddr.bmdma_addr; /* Tristate the bus */ - outb(0x80, bmdma+0x73); - outb(0x80, bmdma+0x77); + iowrite8(0x80, bmdma+0x73); + iowrite8(0x80, bmdma+0x77); /* Switch clock and reset channels */ - outb(source, bmdma+0x7B); - outb(0xC0, bmdma+0x79); + iowrite8(source, bmdma+0x7B); + iowrite8(0xC0, bmdma+0x79); /* Reset state machines */ - outb(0x37, bmdma+0x70); - outb(0x37, bmdma+0x74); + iowrite8(0x37, bmdma+0x70); + iowrite8(0x37, bmdma+0x74); /* Complete reset */ - outb(0x00, bmdma+0x79); + iowrite8(0x00, bmdma+0x79); /* Reconnect channels to bus */ - outb(0x00, bmdma+0x73); - outb(0x00, bmdma+0x77); + iowrite8(0x00, bmdma+0x73); + iowrite8(0x00, bmdma+0x77); } /* Check if our partner interface is busy */ @@ -373,14 +373,14 @@ static struct ata_port_operations hpt3x2 .qc_prep = ata_qc_prep, .qc_issue = hpt3x2n_qc_issue_prot, - .data_xfer = ata_pio_data_xfer, + .data_xfer = ata_data_xfer, .irq_handler = ata_interrupt, .irq_clear = ata_bmdma_irq_clear, + .irq_on = ata_irq_on, + .irq_ack = ata_irq_ack, .port_start = ata_port_start, - .port_stop = ata_port_stop, - .host_stop = ata_host_stop }; /** diff --git a/drivers/ata/pata_hpt3x3.c b/drivers/ata/pata_hpt3x3.c index 5f1d385..483ce7c 100644 --- a/drivers/ata/pata_hpt3x3.c +++ b/drivers/ata/pata_hpt3x3.c @@ -148,14 +148,14 @@ static struct ata_port_operations hpt3x3 .qc_prep = ata_qc_prep, .qc_issue = ata_qc_issue_prot, - .data_xfer = ata_pio_data_xfer, + .data_xfer = ata_data_xfer, .irq_handler = ata_interrupt, .irq_clear = ata_bmdma_irq_clear, + .irq_on = ata_irq_on, + .irq_ack = ata_irq_ack, .port_start = ata_port_start, - .port_stop = ata_port_stop, - .host_stop = ata_host_stop }; /** @@ -164,7 +164,7 @@ static struct ata_port_operations hpt3x3 * * Perform the setup required at boot and on resume. */ - + static void hpt3x3_init_chipset(struct pci_dev *dev) { u16 cmd; diff --git a/drivers/ata/pata_isapnp.c b/drivers/ata/pata_isapnp.c index a97d55a..1bf5ec1 100644 --- a/drivers/ata/pata_isapnp.c +++ b/drivers/ata/pata_isapnp.c @@ -53,14 +53,14 @@ static struct ata_port_operations isapnp .qc_prep = ata_qc_prep, .qc_issue = ata_qc_issue_prot, - .data_xfer = ata_pio_data_xfer, + .data_xfer = ata_data_xfer, .irq_handler = ata_interrupt, .irq_clear = ata_bmdma_irq_clear, + .irq_on = ata_irq_on, + .irq_ack = ata_irq_ack, .port_start = ata_port_start, - .port_stop = ata_port_stop, - .host_stop = ata_host_stop }; /** @@ -75,6 +75,7 @@ static struct ata_port_operations isapnp static int isapnp_init_one(struct pnp_dev *idev, const struct pnp_device_id *dev_id) { struct ata_probe_ent ae; + void __iomem *cmd_addr, *ctl_addr; if (pnp_port_valid(idev, 0) == 0) return -ENODEV; @@ -83,6 +84,10 @@ static int isapnp_init_one(struct pnp_de if (pnp_irq_valid(idev, 0) == 0) return -ENODEV; + cmd_addr = devm_ioport_map(&idev->dev, pnp_port_start(idev, 0), 8); + if (!cmd_addr) + return -ENOMEM; + memset(&ae, 0, sizeof(struct ata_probe_ent)); INIT_LIST_HEAD(&ae.node); ae.dev = &idev->dev; @@ -93,11 +98,13 @@ static int isapnp_init_one(struct pnp_de ae.irq = pnp_irq(idev, 0); ae.irq_flags = 0; ae.port_flags = ATA_FLAG_SLAVE_POSS; - ae.port[0].cmd_addr = pnp_port_start(idev, 0); + ae.port[0].cmd_addr = cmd_addr; if (pnp_port_valid(idev, 1) == 0) { - ae.port[0].altstatus_addr = pnp_port_start(idev, 1); - ae.port[0].ctl_addr = pnp_port_start(idev, 1); + ctl_addr = devm_ioport_map(&idev->dev, + pnp_port_start(idev, 1), 1); + ae.port[0].altstatus_addr = ctl_addr; + ae.port[0].ctl_addr = ctl_addr; ae.port_flags |= ATA_FLAG_SRST; } ata_std_ports(&ae.port[0]); @@ -120,7 +127,7 @@ static void isapnp_remove_one(struct pnp struct device *dev = &idev->dev; struct ata_host *host = dev_get_drvdata(dev); - ata_host_remove(host); + ata_host_detach(host); dev_set_drvdata(dev, NULL); } diff --git a/drivers/ata/pata_it8213.c b/drivers/ata/pata_it8213.c new file mode 100644 index 0000000..7eac869 --- /dev/null +++ b/drivers/ata/pata_it8213.c @@ -0,0 +1,354 @@ +/* + * pata_it8213.c - iTE Tech. Inc. IT8213 PATA driver + * + * The IT8213 is a very Intel ICH like device for timing purposes, having + * a similar register layout and the same split clock arrangement. Cable + * detection is different, and it does not have slave channels or all the + * clutter of later ICH/SATA setups. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define DRV_NAME "pata_it8213" +#define DRV_VERSION "0.0.2" + +/** + * it8213_pre_reset - check for 40/80 pin + * @ap: Port + * + * Perform cable detection for the 8213 ATA interface. This is + * different to the PIIX arrangement + */ + +static int it8213_pre_reset(struct ata_port *ap) +{ + static const struct pci_bits it8213_enable_bits[] = { + { 0x41U, 1U, 0x80UL, 0x80UL }, /* port 0 */ + }; + + struct pci_dev *pdev = to_pci_dev(ap->host->dev); + u8 tmp; + + if (!pci_test_config_bits(pdev, &it8213_enable_bits[ap->port_no])) + return -ENOENT; + + pci_read_config_byte(pdev, 0x42, &tmp); + if (tmp & 2) /* The initial docs are incorrect */ + ap->cbl = ATA_CBL_PATA40; + else + ap->cbl = ATA_CBL_PATA80; + return ata_std_prereset(ap); +} + +/** + * it8213_probe_reset - Probe specified port on PATA host controller + * @ap: Port to probe + * + * LOCKING: + * None (inherited from caller). + */ + +static void it8213_error_handler(struct ata_port *ap) +{ + ata_bmdma_drive_eh(ap, it8213_pre_reset, ata_std_softreset, NULL, ata_std_postreset); +} + +/** + * it8213_set_piomode - Initialize host controller PATA PIO timings + * @ap: Port whose timings we are configuring + * @adev: um + * + * Set PIO mode for device, in host controller PCI config space. + * + * LOCKING: + * None (inherited from caller). + */ + +static void it8213_set_piomode (struct ata_port *ap, struct ata_device *adev) +{ + unsigned int pio = adev->pio_mode - XFER_PIO_0; + struct pci_dev *dev = to_pci_dev(ap->host->dev); + unsigned int idetm_port= ap->port_no ? 0x42 : 0x40; + u16 idetm_data; + int control = 0; + + /* + * See Intel Document 298600-004 for the timing programing rules + * for PIIX/ICH. The 8213 is a clone so very similar + */ + + static const /* ISP RTC */ + u8 timings[][2] = { { 0, 0 }, + { 0, 0 }, + { 1, 0 }, + { 2, 1 }, + { 2, 3 }, }; + + if (pio > 2) + control |= 1; /* TIME1 enable */ + if (ata_pio_need_iordy(adev)) /* PIO 3/4 require IORDY */ + control |= 2; /* IORDY enable */ + /* Bit 2 is set for ATAPI on the IT8213 - reverse of ICH/PIIX */ + if (adev->class != ATA_DEV_ATA) + control |= 4; + + pci_read_config_word(dev, idetm_port, &idetm_data); + + /* Enable PPE, IE and TIME as appropriate */ + + if (adev->devno == 0) { + idetm_data &= 0xCCF0; + idetm_data |= control; + idetm_data |= (timings[pio][0] << 12) | + (timings[pio][1] << 8); + } else { + u8 slave_data; + + idetm_data &= 0xCC0F; + idetm_data |= (control << 4); + + /* Slave timing in seperate register */ + pci_read_config_byte(dev, 0x44, &slave_data); + slave_data &= 0xF0; + slave_data |= ((timings[pio][0] << 2) | timings[pio][1]) << 4; + pci_write_config_byte(dev, 0x44, slave_data); + } + + idetm_data |= 0x4000; /* Ensure SITRE is enabled */ + pci_write_config_word(dev, idetm_port, idetm_data); +} + +/** + * it8213_set_dmamode - Initialize host controller PATA DMA timings + * @ap: Port whose timings we are configuring + * @adev: Device to program + * + * Set UDMA/MWDMA mode for device, in host controller PCI config space. + * This device is basically an ICH alike. + * + * LOCKING: + * None (inherited from caller). + */ + +static void it8213_set_dmamode (struct ata_port *ap, struct ata_device *adev) +{ + struct pci_dev *dev = to_pci_dev(ap->host->dev); + u16 master_data; + u8 speed = adev->dma_mode; + int devid = adev->devno; + u8 udma_enable; + + static const /* ISP RTC */ + u8 timings[][2] = { { 0, 0 }, + { 0, 0 }, + { 1, 0 }, + { 2, 1 }, + { 2, 3 }, }; + + pci_read_config_word(dev, 0x40, &master_data); + pci_read_config_byte(dev, 0x48, &udma_enable); + + if (speed >= XFER_UDMA_0) { + unsigned int udma = adev->dma_mode - XFER_UDMA_0; + u16 udma_timing; + u16 ideconf; + int u_clock, u_speed; + + /* Clocks follow the PIIX style */ + u_speed = min(2 - (udma & 1), udma); + if (udma == 5) + u_clock = 0x1000; /* 100Mhz */ + else if (udma > 2) + u_clock = 1; /* 66Mhz */ + else + u_clock = 0; /* 33Mhz */ + + udma_enable |= (1 << devid); + + /* Load the UDMA mode number */ + pci_read_config_word(dev, 0x4A, &udma_timing); + udma_timing &= ~(3 << (4 * devid)); + udma_timing |= (udma & 3) << (4 * devid); + pci_write_config_word(dev, 0x4A, udma_timing); + + /* Load the clock selection */ + pci_read_config_word(dev, 0x54, &ideconf); + ideconf &= ~(0x1001 << devid); + ideconf |= u_clock << devid; + pci_write_config_word(dev, 0x54, ideconf); + } else { + /* + * MWDMA is driven by the PIO timings. We must also enable + * IORDY unconditionally along with TIME1. PPE has already + * been set when the PIO timing was set. + */ + unsigned int mwdma = adev->dma_mode - XFER_MW_DMA_0; + unsigned int control; + u8 slave_data; + static const unsigned int needed_pio[3] = { + XFER_PIO_0, XFER_PIO_3, XFER_PIO_4 + }; + int pio = needed_pio[mwdma] - XFER_PIO_0; + + control = 3; /* IORDY|TIME1 */ + + /* If the drive MWDMA is faster than it can do PIO then + we must force PIO into PIO0 */ + + if (adev->pio_mode < needed_pio[mwdma]) + /* Enable DMA timing only */ + control |= 8; /* PIO cycles in PIO0 */ + + if (devid) { /* Slave */ + master_data &= 0xFF4F; /* Mask out IORDY|TIME1|DMAONLY */ + master_data |= control << 4; + pci_read_config_byte(dev, 0x44, &slave_data); + slave_data &= (0x0F + 0xE1 * ap->port_no); + /* Load the matching timing */ + slave_data |= ((timings[pio][0] << 2) | timings[pio][1]) << (ap->port_no ? 4 : 0); + pci_write_config_byte(dev, 0x44, slave_data); + } else { /* Master */ + master_data &= 0xCCF4; /* Mask out IORDY|TIME1|DMAONLY + and master timing bits */ + master_data |= control; + master_data |= + (timings[pio][0] << 12) | + (timings[pio][1] << 8); + } + udma_enable &= ~(1 << devid); + pci_write_config_word(dev, 0x40, master_data); + } + pci_write_config_byte(dev, 0x48, udma_enable); +} + +static struct scsi_host_template it8213_sht = { + .module = THIS_MODULE, + .name = DRV_NAME, + .ioctl = ata_scsi_ioctl, + .queuecommand = ata_scsi_queuecmd, + .can_queue = ATA_DEF_QUEUE, + .this_id = ATA_SHT_THIS_ID, + .sg_tablesize = LIBATA_MAX_PRD, + .max_sectors = ATA_MAX_SECTORS, + .cmd_per_lun = ATA_SHT_CMD_PER_LUN, + .emulated = ATA_SHT_EMULATED, + .use_clustering = ATA_SHT_USE_CLUSTERING, + .proc_name = DRV_NAME, + .dma_boundary = ATA_DMA_BOUNDARY, + .slave_configure = ata_scsi_slave_config, + .bios_param = ata_std_bios_param, + .resume = ata_scsi_device_resume, + .suspend = ata_scsi_device_suspend, +}; + +static const struct ata_port_operations it8213_ops = { + .port_disable = ata_port_disable, + .set_piomode = it8213_set_piomode, + .set_dmamode = it8213_set_dmamode, + .mode_filter = ata_pci_default_filter, + + .tf_load = ata_tf_load, + .tf_read = ata_tf_read, + .check_status = ata_check_status, + .exec_command = ata_exec_command, + .dev_select = ata_std_dev_select, + + .freeze = ata_bmdma_freeze, + .thaw = ata_bmdma_thaw, + .error_handler = it8213_error_handler, + .post_internal_cmd = ata_bmdma_post_internal_cmd, + + .bmdma_setup = ata_bmdma_setup, + .bmdma_start = ata_bmdma_start, + .bmdma_stop = ata_bmdma_stop, + .bmdma_status = ata_bmdma_status, + .qc_prep = ata_qc_prep, + .qc_issue = ata_qc_issue_prot, + .data_xfer = ata_data_xfer, + + .irq_handler = ata_interrupt, + .irq_clear = ata_bmdma_irq_clear, + .irq_on = ata_irq_on, + .irq_ack = ata_irq_ack, + + .port_start = ata_port_start, +}; + + +/** + * it8213_init_one - Register 8213 ATA PCI device with kernel services + * @pdev: PCI device to register + * @ent: Entry in it8213_pci_tbl matching with @pdev + * + * Called from kernel PCI layer. + * + * LOCKING: + * Inherited from PCI layer (may sleep). + * + * RETURNS: + * Zero on success, or -ERRNO value. + */ + +static int it8213_init_one (struct pci_dev *pdev, const struct pci_device_id *ent) +{ + static int printed_version; + static struct ata_port_info info = { + .sht = &it8213_sht, + .flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST, + .pio_mask = 0x1f, /* pio0-4 */ + .mwdma_mask = 0x07, /* mwdma0-2 */ + .udma_mask = 0x1f, /* UDMA 100 */ + .port_ops = &it8213_ops, + }; + static struct ata_port_info *port_info[2] = { &info, &info }; + + if (!printed_version++) + dev_printk(KERN_DEBUG, &pdev->dev, + "version " DRV_VERSION "\n"); + + /* Current IT8213 stuff is single port */ + return ata_pci_init_one(pdev, port_info, 1); +} + +static const struct pci_device_id it8213_pci_tbl[] = { + { PCI_VDEVICE(ITE, PCI_DEVICE_ID_ITE_8213), }, + + { } /* terminate list */ +}; + +static struct pci_driver it8213_pci_driver = { + .name = DRV_NAME, + .id_table = it8213_pci_tbl, + .probe = it8213_init_one, + .remove = ata_pci_remove_one, + .suspend = ata_pci_device_suspend, + .resume = ata_pci_device_resume, +}; + +static int __init it8213_init(void) +{ + return pci_register_driver(&it8213_pci_driver); +} + +static void __exit it8213_exit(void) +{ + pci_unregister_driver(&it8213_pci_driver); +} + +module_init(it8213_init); +module_exit(it8213_exit); + +MODULE_AUTHOR("Alan Cox"); +MODULE_DESCRIPTION("SCSI low-level driver for the ITE 8213"); +MODULE_LICENSE("GPL"); +MODULE_DEVICE_TABLE(pci, it8213_pci_tbl); +MODULE_VERSION(DRV_VERSION); diff --git a/drivers/ata/pata_it821x.c b/drivers/ata/pata_it821x.c index e8afd48..73394c7 100644 --- a/drivers/ata/pata_it821x.c +++ b/drivers/ata/pata_it821x.c @@ -492,7 +492,7 @@ static int it821x_smart_set_mode(struct /* Bits 5 and 6 indicate if DMA is active on master/slave */ /* It is possible that BMDMA isn't allocated */ if (ap->ioaddr.bmdma_addr) - dma_enabled = inb(ap->ioaddr.bmdma_addr + ATA_DMA_CMD); + dma_enabled = ioread8(ap->ioaddr.bmdma_addr + ATA_DMA_CMD); for (i = 0; i < ATA_MAX_DEVICES; i++) { struct ata_device *dev = &ap->device[i]; @@ -531,23 +531,9 @@ static int it821x_smart_set_mode(struct static void it821x_dev_config(struct ata_port *ap, struct ata_device *adev) { - unsigned char model_num[40]; - char *s; - unsigned int len; - - /* This block ought to be a library routine as it is in several - drivers now */ - - ata_id_string(adev->id, model_num, ATA_ID_PROD_OFS, - sizeof(model_num)); - s = &model_num[0]; - len = strnlen(s, sizeof(model_num)); - - /* ATAPI specifies that empty space is blank-filled; remove blanks */ - while ((len > 0) && (s[len - 1] == ' ')) { - len--; - s[len] = 0; - } + unsigned char model_num[ATA_ID_PROD_LEN + 1]; + + ata_id_c_string(adev->id, model_num, ATA_ID_PROD, sizeof(model_num)); if (adev->max_sectors > 255) adev->max_sectors = 255; @@ -608,14 +594,10 @@ static int it821x_port_start(struct ata_ if (ret < 0) return ret; - ap->private_data = kmalloc(sizeof(struct it821x_dev), GFP_KERNEL); - if (ap->private_data == NULL) { - ata_port_stop(ap); + itdev = devm_kzalloc(&pdev->dev, sizeof(struct it821x_dev), GFP_KERNEL); + if (itdev == NULL) return -ENOMEM; - } - - itdev = ap->private_data; - memset(itdev, 0, sizeof(struct it821x_dev)); + ap->private_data = itdev; pci_read_config_byte(pdev, 0x50, &conf); @@ -646,20 +628,6 @@ static int it821x_port_start(struct ata_ return 0; } -/** - * it821x_port_stop - port shutdown - * @ap: ATA port being removed - * - * Release the private objects we added in it821x_port_start - */ - -static void it821x_port_stop(struct ata_port *ap) { - kfree(ap->private_data); - ap->private_data = NULL; /* We want an OOPS if we reuse this - too late! */ - ata_port_stop(ap); -} - static struct scsi_host_template it821x_sht = { .module = THIS_MODULE, .name = DRV_NAME, @@ -706,14 +674,14 @@ static struct ata_port_operations it821x .qc_prep = ata_qc_prep, .qc_issue = it821x_smart_qc_issue_prot, - .data_xfer = ata_pio_data_xfer, + .data_xfer = ata_data_xfer, .irq_handler = ata_interrupt, .irq_clear = ata_bmdma_irq_clear, + .irq_on = ata_irq_on, + .irq_ack = ata_irq_ack, .port_start = it821x_port_start, - .port_stop = it821x_port_stop, - .host_stop = ata_host_stop }; static struct ata_port_operations it821x_passthru_port_ops = { @@ -742,14 +710,14 @@ static struct ata_port_operations it821x .qc_prep = ata_qc_prep, .qc_issue = it821x_passthru_qc_issue_prot, - .data_xfer = ata_pio_data_xfer, + .data_xfer = ata_data_xfer, .irq_clear = ata_bmdma_irq_clear, .irq_handler = ata_interrupt, + .irq_on = ata_irq_on, + .irq_ack = ata_irq_ack, .port_start = it821x_port_start, - .port_stop = it821x_port_stop, - .host_stop = ata_host_stop }; static void __devinit it821x_disable_raid(struct pci_dev *pdev) diff --git a/drivers/ata/pata_ixp4xx_cf.c b/drivers/ata/pata_ixp4xx_cf.c index 23b8aab..3222ac7 100644 --- a/drivers/ata/pata_ixp4xx_cf.c +++ b/drivers/ata/pata_ixp4xx_cf.c @@ -95,14 +95,6 @@ static void ixp4xx_irq_clear(struct ata_ { } -static void ixp4xx_host_stop (struct ata_host *host) -{ - struct ixp4xx_pata_data *data = host->dev->platform_data; - - iounmap(data->cs0); - iounmap(data->cs1); -} - static struct scsi_host_template ixp4xx_sht = { .module = THIS_MODULE, .name = DRV_NAME, @@ -139,10 +131,10 @@ static struct ata_port_operations ixp4xx .irq_handler = ata_interrupt, .irq_clear = ixp4xx_irq_clear, + .irq_on = ata_irq_on, + .irq_ack = ata_irq_ack, .port_start = ata_port_start, - .port_stop = ata_port_stop, - .host_stop = ixp4xx_host_stop, .phy_reset = ixp4xx_phy_reset, }; @@ -150,9 +142,9 @@ static struct ata_port_operations ixp4xx static void ixp4xx_setup_port(struct ata_ioports *ioaddr, struct ixp4xx_pata_data *data) { - ioaddr->cmd_addr = (unsigned long) data->cs0; - ioaddr->altstatus_addr = (unsigned long) data->cs1 + 0x06; - ioaddr->ctl_addr = (unsigned long) data->cs1 + 0x06; + ioaddr->cmd_addr = data->cs0; + ioaddr->altstatus_addr = data->cs1 + 0x06; + ioaddr->ctl_addr = data->cs1 + 0x06; ata_std_ports(ioaddr); @@ -162,19 +154,19 @@ #ifndef __ARMEB__ * ixp4xx in little endian mode. */ - ioaddr->data_addr ^= 0x02; - ioaddr->cmd_addr ^= 0x03; - ioaddr->altstatus_addr ^= 0x03; - ioaddr->ctl_addr ^= 0x03; - ioaddr->error_addr ^= 0x03; - ioaddr->feature_addr ^= 0x03; - ioaddr->nsect_addr ^= 0x03; - ioaddr->lbal_addr ^= 0x03; - ioaddr->lbam_addr ^= 0x03; - ioaddr->lbah_addr ^= 0x03; - ioaddr->device_addr ^= 0x03; - ioaddr->status_addr ^= 0x03; - ioaddr->command_addr ^= 0x03; + *(unsigned long *)&ioaddr->data_addr ^= 0x02; + *(unsigned long *)&ioaddr->cmd_addr ^= 0x03; + *(unsigned long *)&ioaddr->altstatus_addr ^= 0x03; + *(unsigned long *)&ioaddr->ctl_addr ^= 0x03; + *(unsigned long *)&ioaddr->error_addr ^= 0x03; + *(unsigned long *)&ioaddr->feature_addr ^= 0x03; + *(unsigned long *)&ioaddr->nsect_addr ^= 0x03; + *(unsigned long *)&ioaddr->lbal_addr ^= 0x03; + *(unsigned long *)&ioaddr->lbam_addr ^= 0x03; + *(unsigned long *)&ioaddr->lbah_addr ^= 0x03; + *(unsigned long *)&ioaddr->device_addr ^= 0x03; + *(unsigned long *)&ioaddr->status_addr ^= 0x03; + *(unsigned long *)&ioaddr->command_addr ^= 0x03; #endif } @@ -195,8 +187,8 @@ static __devinit int ixp4xx_pata_probe(s pdev->dev.coherent_dma_mask = DMA_32BIT_MASK; - data->cs0 = ioremap(cs0->start, 0x1000); - data->cs1 = ioremap(cs1->start, 0x1000); + data->cs0 = devm_ioremap(&pdev->dev, cs0->start, 0x1000); + data->cs1 = devm_ioremap(&pdev->dev, cs1->start, 0x1000); irq = platform_get_irq(pdev, 0); if (irq) @@ -238,7 +230,7 @@ static __devexit int ixp4xx_pata_remove( { struct ata_host *host = platform_get_drvdata(dev); - ata_host_remove(host); + ata_host_detach(host); platform_set_drvdata(dev, NULL); return 0; diff --git a/drivers/ata/pata_jmicron.c b/drivers/ata/pata_jmicron.c index d50264a..7a635dd 100644 --- a/drivers/ata/pata_jmicron.c +++ b/drivers/ata/pata_jmicron.c @@ -161,16 +161,16 @@ static const struct ata_port_operations .bmdma_status = ata_bmdma_status, .qc_prep = ata_qc_prep, .qc_issue = ata_qc_issue_prot, - .data_xfer = ata_pio_data_xfer, + .data_xfer = ata_data_xfer, /* IRQ-related hooks */ .irq_handler = ata_interrupt, .irq_clear = ata_bmdma_irq_clear, + .irq_on = ata_irq_on, + .irq_ack = ata_irq_ack, /* Generic PATA PCI ATA helpers */ .port_start = ata_port_start, - .port_stop = ata_port_stop, - .host_stop = ata_host_stop, }; @@ -221,7 +221,7 @@ static int jmicron_init_one (struct pci_ static int jmicron_reinit_one(struct pci_dev *pdev) { u32 reg; - + switch(pdev->device) { case PCI_DEVICE_ID_JMICRON_JMB368: break; diff --git a/drivers/ata/pata_legacy.c b/drivers/ata/pata_legacy.c index 581cb33..98c1fee 100644 --- a/drivers/ata/pata_legacy.c +++ b/drivers/ata/pata_legacy.c @@ -89,9 +89,10 @@ static int probe_all; /* Set to check static int ht6560a; /* HT 6560A on primary 1, secondary 2, both 3 */ static int ht6560b; /* HT 6560A on primary 1, secondary 2, both 3 */ static int opti82c611a; /* Opti82c611A on primary 1, secondary 2, both 3 */ -static int opti82c46x; /* Opti 82c465MV present (pri/sec autodetect) */ +static int opti82c46x; /* Opti 82c465MV present (pri/sec autodetect) */ static int autospeed; /* Chip present which snoops speed changes */ static int pio_mask = 0x1F; /* PIO range for autospeed devices */ +static int iordy_mask = 0xFFFFFFFF; /* Use iordy if available */ /** * legacy_set_mode - mode setting @@ -113,6 +114,7 @@ static int legacy_set_mode(struct ata_po for (i = 0; i < ATA_MAX_DEVICES; i++) { struct ata_device *dev = &ap->device[i]; if (ata_dev_enabled(dev)) { + 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; @@ -164,14 +166,14 @@ static struct ata_port_operations simple .qc_prep = ata_qc_prep, .qc_issue = ata_qc_issue_prot, - .data_xfer = ata_pio_data_xfer_noirq, + .data_xfer = ata_data_xfer_noirq, .irq_handler = ata_interrupt, .irq_clear = ata_bmdma_irq_clear, + .irq_on = ata_irq_on, + .irq_ack = ata_irq_ack, .port_start = ata_port_start, - .port_stop = ata_port_stop, - .host_stop = ata_host_stop }; static struct ata_port_operations legacy_port_ops = { @@ -189,14 +191,14 @@ static struct ata_port_operations legacy .qc_prep = ata_qc_prep, .qc_issue = ata_qc_issue_prot, - .data_xfer = ata_pio_data_xfer_noirq, + .data_xfer = ata_data_xfer_noirq, .irq_handler = ata_interrupt, .irq_clear = ata_bmdma_irq_clear, + .irq_on = ata_irq_on, + .irq_ack = ata_irq_ack, .port_start = ata_port_start, - .port_stop = ata_port_stop, - .host_stop = ata_host_stop }; /* @@ -257,31 +259,33 @@ static void pdc_data_xfer_vlb(struct ata local_irq_save(flags); /* Perform the 32bit I/O synchronization sequence */ - inb(ap->ioaddr.nsect_addr); - inb(ap->ioaddr.nsect_addr); - inb(ap->ioaddr.nsect_addr); + ioread8(ap->ioaddr.nsect_addr); + ioread8(ap->ioaddr.nsect_addr); + ioread8(ap->ioaddr.nsect_addr); /* Now the data */ if (write_data) - outsl(ap->ioaddr.data_addr, buf, buflen >> 2); + iowrite32_rep(ap->ioaddr.data_addr, buf, buflen >> 2); else - insl(ap->ioaddr.data_addr, buf, buflen >> 2); + ioread32_rep(ap->ioaddr.data_addr, buf, buflen >> 2); if (unlikely(slop)) { u32 pad; if (write_data) { memcpy(&pad, buf + buflen - slop, slop); - outl(le32_to_cpu(pad), ap->ioaddr.data_addr); + pad = le32_to_cpu(pad); + iowrite32(pad, ap->ioaddr.data_addr); } else { - pad = cpu_to_le16(inl(ap->ioaddr.data_addr)); + pad = ioread32(ap->ioaddr.data_addr); + pad = cpu_to_le16(pad); memcpy(buf + buflen - slop, &pad, slop); } } local_irq_restore(flags); } else - ata_pio_data_xfer_noirq(adev, buf, buflen, write_data); + ata_data_xfer_noirq(adev, buf, buflen, write_data); } static struct ata_port_operations pdc20230_port_ops = { @@ -303,10 +307,10 @@ static struct ata_port_operations pdc202 .irq_handler = ata_interrupt, .irq_clear = ata_bmdma_irq_clear, + .irq_on = ata_irq_on, + .irq_ack = ata_irq_ack, .port_start = ata_port_start, - .port_stop = ata_port_stop, - .host_stop = ata_host_stop }; /* @@ -332,8 +336,8 @@ static void ht6560a_set_piomode(struct a inb(0x3E6); inb(0x3E6); - outb(recover << 4 | active, ap->ioaddr.device_addr); - inb(ap->ioaddr.status_addr); + iowrite8(recover << 4 | active, ap->ioaddr.device_addr); + ioread8(ap->ioaddr.status_addr); } static struct ata_port_operations ht6560a_port_ops = { @@ -351,14 +355,14 @@ static struct ata_port_operations ht6560 .qc_prep = ata_qc_prep, .qc_issue = ata_qc_issue_prot, - .data_xfer = ata_pio_data_xfer, /* Check vlb/noirq */ + .data_xfer = ata_data_xfer, /* Check vlb/noirq */ .irq_handler = ata_interrupt, .irq_clear = ata_bmdma_irq_clear, + .irq_on = ata_irq_on, + .irq_ack = ata_irq_ack, .port_start = ata_port_start, - .port_stop = ata_port_stop, - .host_stop = ata_host_stop }; /* @@ -387,7 +391,7 @@ static void ht6560b_set_piomode(struct a inb(0x3E6); inb(0x3E6); - outb(recover << 4 | active, ap->ioaddr.device_addr); + iowrite8(recover << 4 | active, ap->ioaddr.device_addr); if (adev->class != ATA_DEV_ATA) { u8 rconf = inb(0x3E6); @@ -396,7 +400,7 @@ static void ht6560b_set_piomode(struct a outb(rconf, 0x3E6); } } - inb(ap->ioaddr.status_addr); + ioread8(ap->ioaddr.status_addr); } static struct ata_port_operations ht6560b_port_ops = { @@ -414,14 +418,14 @@ static struct ata_port_operations ht6560 .qc_prep = ata_qc_prep, .qc_issue = ata_qc_issue_prot, - .data_xfer = ata_pio_data_xfer, /* FIXME: Check 32bit and noirq */ + .data_xfer = ata_data_xfer, /* FIXME: Check 32bit and noirq */ .irq_handler = ata_interrupt, .irq_clear = ata_bmdma_irq_clear, + .irq_on = ata_irq_on, + .irq_ack = ata_irq_ack, .port_start = ata_port_start, - .port_stop = ata_port_stop, - .host_stop = ata_host_stop }; /* @@ -464,12 +468,12 @@ static void opti82c611a_set_piomode(stru u8 rc; /* Enter configuration mode */ - inw(ap->ioaddr.error_addr); - inw(ap->ioaddr.error_addr); - outb(3, ap->ioaddr.nsect_addr); + ioread16(ap->ioaddr.error_addr); + ioread16(ap->ioaddr.error_addr); + iowrite8(3, ap->ioaddr.nsect_addr); /* Read VLB clock strapping */ - clock = 1000000000 / khz[inb(ap->ioaddr.lbah_addr) & 0x03]; + clock = 1000000000 / khz[ioread8(ap->ioaddr.lbah_addr) & 0x03]; /* Get the timing data in cycles */ ata_timing_compute(adev, adev->pio_mode, &t, clock, 1000); @@ -487,33 +491,33 @@ static void opti82c611a_set_piomode(stru setup = FIT(t.setup, 1, 4) - 1; /* Select the right timing bank for write timing */ - rc = inb(ap->ioaddr.lbal_addr); + rc = ioread8(ap->ioaddr.lbal_addr); rc &= 0x7F; rc |= (adev->devno << 7); - outb(rc, ap->ioaddr.lbal_addr); + iowrite8(rc, ap->ioaddr.lbal_addr); /* Write the timings */ - outb(active << 4 | recover, ap->ioaddr.error_addr); + iowrite8(active << 4 | recover, ap->ioaddr.error_addr); /* Select the right bank for read timings, also load the shared timings for address */ - rc = inb(ap->ioaddr.device_addr); + rc = ioread8(ap->ioaddr.device_addr); rc &= 0xC0; rc |= adev->devno; /* Index select */ rc |= (setup << 4) | 0x04; - outb(rc, ap->ioaddr.device_addr); + iowrite8(rc, ap->ioaddr.device_addr); /* Load the read timings */ - outb(active << 4 | recover, ap->ioaddr.data_addr); + iowrite8(active << 4 | recover, ap->ioaddr.data_addr); /* Ensure the timing register mode is right */ - rc = inb (ap->ioaddr.lbal_addr); + rc = ioread8(ap->ioaddr.lbal_addr); rc &= 0x73; rc |= 0x84; - outb(rc, ap->ioaddr.lbal_addr); + iowrite8(rc, ap->ioaddr.lbal_addr); /* Exit command mode */ - outb(0x83, ap->ioaddr.nsect_addr); + iowrite8(0x83, ap->ioaddr.nsect_addr); } @@ -532,14 +536,14 @@ static struct ata_port_operations opti82 .qc_prep = ata_qc_prep, .qc_issue = ata_qc_issue_prot, - .data_xfer = ata_pio_data_xfer, + .data_xfer = ata_data_xfer, .irq_handler = ata_interrupt, .irq_clear = ata_bmdma_irq_clear, + .irq_on = ata_irq_on, + .irq_ack = ata_irq_ack, .port_start = ata_port_start, - .port_stop = ata_port_stop, - .host_stop = ata_host_stop }; /* @@ -563,9 +567,9 @@ static void opti82c46x_set_piomode(struc sysclk = opti_syscfg(0xAC) & 0xC0; /* BIOS set */ /* Enter configuration mode */ - inw(ap->ioaddr.error_addr); - inw(ap->ioaddr.error_addr); - outb(3, ap->ioaddr.nsect_addr); + ioread16(ap->ioaddr.error_addr); + ioread16(ap->ioaddr.error_addr); + iowrite8(3, ap->ioaddr.nsect_addr); /* Read VLB clock strapping */ clock = 1000000000 / khz[sysclk]; @@ -586,33 +590,33 @@ static void opti82c46x_set_piomode(struc setup = FIT(t.setup, 1, 4) - 1; /* Select the right timing bank for write timing */ - rc = inb(ap->ioaddr.lbal_addr); + rc = ioread8(ap->ioaddr.lbal_addr); rc &= 0x7F; rc |= (adev->devno << 7); - outb(rc, ap->ioaddr.lbal_addr); + iowrite8(rc, ap->ioaddr.lbal_addr); /* Write the timings */ - outb(active << 4 | recover, ap->ioaddr.error_addr); + iowrite8(active << 4 | recover, ap->ioaddr.error_addr); /* Select the right bank for read timings, also load the shared timings for address */ - rc = inb(ap->ioaddr.device_addr); + rc = ioread8(ap->ioaddr.device_addr); rc &= 0xC0; rc |= adev->devno; /* Index select */ rc |= (setup << 4) | 0x04; - outb(rc, ap->ioaddr.device_addr); + iowrite8(rc, ap->ioaddr.device_addr); /* Load the read timings */ - outb(active << 4 | recover, ap->ioaddr.data_addr); + iowrite8(active << 4 | recover, ap->ioaddr.data_addr); /* Ensure the timing register mode is right */ - rc = inb (ap->ioaddr.lbal_addr); + rc = ioread8(ap->ioaddr.lbal_addr); rc &= 0x73; rc |= 0x84; - outb(rc, ap->ioaddr.lbal_addr); + iowrite8(rc, ap->ioaddr.lbal_addr); /* Exit command mode */ - outb(0x83, ap->ioaddr.nsect_addr); + iowrite8(0x83, ap->ioaddr.nsect_addr); /* We need to know this for quad device on the MVB */ ap->host->private_data = ap; @@ -662,14 +666,14 @@ static struct ata_port_operations opti82 .qc_prep = ata_qc_prep, .qc_issue = opti82c46x_qc_issue_prot, - .data_xfer = ata_pio_data_xfer, + .data_xfer = ata_data_xfer, .irq_handler = ata_interrupt, .irq_clear = ata_bmdma_irq_clear, + .irq_on = ata_irq_on, + .irq_ack = ata_irq_ack, .port_start = ata_port_start, - .port_stop = ata_port_stop, - .host_stop = ata_host_stop }; @@ -689,25 +693,32 @@ static __init int legacy_init_one(int po struct legacy_data *ld = &legacy_data[nr_legacy_host]; struct ata_probe_ent ae; struct platform_device *pdev; - int ret = -EBUSY; struct ata_port_operations *ops = &legacy_port_ops; + void __iomem *io_addr, *ctrl_addr; int pio_modes = pio_mask; u32 mask = (1 << port); - - if (request_region(io, 8, "pata_legacy") == NULL) - return -EBUSY; - if (request_region(ctrl, 1, "pata_legacy") == NULL) - goto fail_io; + u32 iordy = (iordy_mask & mask) ? 0: ATA_FLAG_NO_IORDY; + int ret; pdev = platform_device_register_simple(DRV_NAME, nr_legacy_host, NULL, 0); - if (IS_ERR(pdev)) { - ret = PTR_ERR(pdev); - goto fail_dev; - } + if (IS_ERR(pdev)) + return PTR_ERR(pdev); + + ret = -EBUSY; + if (devm_request_region(&pdev->dev, io, 8, "pata_legacy") == NULL || + devm_request_region(&pdev->dev, ctrl, 1, "pata_legacy") == NULL) + goto fail; + + ret = -ENOMEM; + io_addr = devm_ioport_map(&pdev->dev, io, 8); + ctrl_addr = devm_ioport_map(&pdev->dev, ctrl, 1); + if (!io_addr || !ctrl_addr) + goto fail; if (ht6560a & mask) { ops = &ht6560a_port_ops; pio_modes = 0x07; + iordy = ATA_FLAG_NO_IORDY; } if (ht6560b & mask) { ops = &ht6560b_port_ops; @@ -743,6 +754,7 @@ static __init int legacy_init_one(int po printk(KERN_INFO "PDC20230-C/20630 VLB ATA controller detected.\n"); pio_modes = 0x07; ops = &pdc20230_port_ops; + iordy = ATA_FLAG_NO_IORDY; udelay(100); inb(0x1F5); } else { @@ -760,6 +772,7 @@ static __init int legacy_init_one(int po /* Chip does mode setting by command snooping */ if (ops == &legacy_port_ops && (autospeed & mask)) ops = &simple_port_ops; + memset(&ae, 0, sizeof(struct ata_probe_ent)); INIT_LIST_HEAD(&ae.node); ae.dev = &pdev->dev; @@ -769,28 +782,23 @@ static __init int legacy_init_one(int po ae.pio_mask = pio_modes; ae.irq = irq; ae.irq_flags = 0; - ae.port_flags = ATA_FLAG_SLAVE_POSS|ATA_FLAG_SRST; - ae.port[0].cmd_addr = io; - ae.port[0].altstatus_addr = ctrl; - ae.port[0].ctl_addr = ctrl; + ae.port_flags = ATA_FLAG_SLAVE_POSS|ATA_FLAG_SRST|iordy; + ae.port[0].cmd_addr = io_addr; + ae.port[0].altstatus_addr = ctrl_addr; + ae.port[0].ctl_addr = ctrl_addr; ata_std_ports(&ae.port[0]); ae.private_data = ld; - ret = ata_device_add(&ae); - if (ret == 0) { - ret = -ENODEV; + ret = -ENODEV; + if (!ata_device_add(&ae)) goto fail; - } + legacy_host[nr_legacy_host++] = dev_get_drvdata(&pdev->dev); ld->platform_dev = pdev; return 0; fail: platform_device_unregister(pdev); -fail_dev: - release_region(ctrl, 1); -fail_io: - release_region(io, 8); return ret; } @@ -923,15 +931,11 @@ static __exit void legacy_exit(void) for (i = 0; i < nr_legacy_host; i++) { struct legacy_data *ld = &legacy_data[i]; - struct ata_port *ap =legacy_host[i]->ports[0]; - unsigned long io = ap->ioaddr.cmd_addr; - unsigned long ctrl = ap->ioaddr.ctl_addr; - ata_host_remove(legacy_host[i]); + + ata_host_detach(legacy_host[i]); platform_device_unregister(ld->platform_dev); if (ld->timing) release_region(ld->timing, 2); - release_region(io, 8); - release_region(ctrl, 1); } } @@ -947,6 +951,7 @@ module_param(ht6560b, int, 0); module_param(opti82c611a, int, 0); module_param(opti82c46x, int, 0); module_param(pio_mask, int, 0); +module_param(iordy_mask, int, 0); module_init(legacy_init); module_exit(legacy_exit); diff --git a/drivers/ata/pata_marvell.c b/drivers/ata/pata_marvell.c index 1c810ea..13a70ac 100644 --- a/drivers/ata/pata_marvell.c +++ b/drivers/ata/pata_marvell.c @@ -45,10 +45,10 @@ static int marvell_pre_reset(struct ata_ for(i = 0; i <= 0x0F; i++) printk("%02X:%02X ", i, readb(barp + i)); printk("\n"); - + devices = readl(barp + 0x0C); pci_iounmap(pdev, barp); - + if ((pdev->device == 0x6145) && (ap->port_no == 0) && (!(devices & 0x10))) /* PATA enable ? */ return -ENOENT; @@ -57,7 +57,7 @@ static int marvell_pre_reset(struct ata_ switch(ap->port_no) { case 0: - if (inb(ap->ioaddr.bmdma_addr + 1) & 1) + if (ioread8(ap->ioaddr.bmdma_addr + 1) & 1) ap->cbl = ATA_CBL_PATA40; else ap->cbl = ATA_CBL_PATA80; @@ -129,16 +129,16 @@ static const struct ata_port_operations .bmdma_status = ata_bmdma_status, .qc_prep = ata_qc_prep, .qc_issue = ata_qc_issue_prot, - .data_xfer = ata_pio_data_xfer, + .data_xfer = ata_data_xfer, /* Timeout handling */ .irq_handler = ata_interrupt, .irq_clear = ata_bmdma_irq_clear, + .irq_on = ata_irq_on, + .irq_ack = ata_irq_ack, /* Generic PATA PCI ATA helpers */ .port_start = ata_port_start, - .port_stop = ata_port_stop, - .host_stop = ata_host_stop, }; diff --git a/drivers/ata/pata_mpc52xx.c b/drivers/ata/pata_mpc52xx.c new file mode 100644 index 0000000..29e1809 --- /dev/null +++ b/drivers/ata/pata_mpc52xx.c @@ -0,0 +1,536 @@ +/* + * drivers/ata/pata_mpc52xx.c + * + * libata driver for the Freescale MPC52xx on-chip IDE interface + * + * Copyright (C) 2006 Sylvain Munaut + * Copyright (C) 2003 Mipsys - Benjamin Herrenschmidt + * + * This file is licensed under the terms of the GNU General Public License + * version 2. This program is licensed "as is" without any warranty of any + * kind, whether express or implied. + */ + +#include +#include +#include +#include +#include + +#include +#include +#include +#include + + +#define DRV_NAME "mpc52xx_ata" +#define DRV_VERSION "0.1.0" + + +/* Private structures used by the driver */ +struct mpc52xx_ata_timings { + u32 pio1; + u32 pio2; +}; + +struct mpc52xx_ata_priv { + unsigned int ipb_period; + struct mpc52xx_ata __iomem * ata_regs; + int ata_irq; + struct mpc52xx_ata_timings timings[2]; + int csel; +}; + + +/* ATAPI-4 PIO specs (in ns) */ +static const int ataspec_t0[5] = {600, 383, 240, 180, 120}; +static const int ataspec_t1[5] = { 70, 50, 30, 30, 25}; +static const int ataspec_t2_8[5] = {290, 290, 290, 80, 70}; +static const int ataspec_t2_16[5] = {165, 125, 100, 80, 70}; +static const int ataspec_t2i[5] = { 0, 0, 0, 70, 25}; +static const int ataspec_t4[5] = { 30, 20, 15, 10, 10}; +static const int ataspec_ta[5] = { 35, 35, 35, 35, 35}; + +#define CALC_CLKCYC(c,v) ((((v)+(c)-1)/(c))) + + +/* Bit definitions inside the registers */ +#define MPC52xx_ATA_HOSTCONF_SMR 0x80000000UL /* State machine reset */ +#define MPC52xx_ATA_HOSTCONF_FR 0x40000000UL /* FIFO Reset */ +#define MPC52xx_ATA_HOSTCONF_IE 0x02000000UL /* Enable interrupt in PIO */ +#define MPC52xx_ATA_HOSTCONF_IORDY 0x01000000UL /* Drive supports IORDY protocol */ + +#define MPC52xx_ATA_HOSTSTAT_TIP 0x80000000UL /* Transaction in progress */ +#define MPC52xx_ATA_HOSTSTAT_UREP 0x40000000UL /* UDMA Read Extended Pause */ +#define MPC52xx_ATA_HOSTSTAT_RERR 0x02000000UL /* Read Error */ +#define MPC52xx_ATA_HOSTSTAT_WERR 0x01000000UL /* Write Error */ + +#define MPC52xx_ATA_FIFOSTAT_EMPTY 0x01 /* FIFO Empty */ + +#define MPC52xx_ATA_DMAMODE_WRITE 0x01 /* Write DMA */ +#define MPC52xx_ATA_DMAMODE_READ 0x02 /* Read DMA */ +#define MPC52xx_ATA_DMAMODE_UDMA 0x04 /* UDMA enabled */ +#define MPC52xx_ATA_DMAMODE_IE 0x08 /* Enable drive interrupt to CPU in DMA mode */ +#define MPC52xx_ATA_DMAMODE_FE 0x10 /* FIFO Flush enable in Rx mode */ +#define MPC52xx_ATA_DMAMODE_FR 0x20 /* FIFO Reset */ +#define MPC52xx_ATA_DMAMODE_HUT 0x40 /* Host UDMA burst terminate */ + + +/* Structure of the hardware registers */ +struct mpc52xx_ata { + + /* Host interface registers */ + u32 config; /* ATA + 0x00 Host configuration */ + u32 host_status; /* ATA + 0x04 Host controller status */ + u32 pio1; /* ATA + 0x08 PIO Timing 1 */ + u32 pio2; /* ATA + 0x0c PIO Timing 2 */ + u32 mdma1; /* ATA + 0x10 MDMA Timing 1 */ + u32 mdma2; /* ATA + 0x14 MDMA Timing 2 */ + u32 udma1; /* ATA + 0x18 UDMA Timing 1 */ + u32 udma2; /* ATA + 0x1c UDMA Timing 2 */ + u32 udma3; /* ATA + 0x20 UDMA Timing 3 */ + u32 udma4; /* ATA + 0x24 UDMA Timing 4 */ + u32 udma5; /* ATA + 0x28 UDMA Timing 5 */ + u32 share_cnt; /* ATA + 0x2c ATA share counter */ + u32 reserved0[3]; + + /* FIFO registers */ + u32 fifo_data; /* ATA + 0x3c */ + u8 fifo_status_frame; /* ATA + 0x40 */ + u8 fifo_status; /* ATA + 0x41 */ + u16 reserved7[1]; + u8 fifo_control; /* ATA + 0x44 */ + u8 reserved8[5]; + u16 fifo_alarm; /* ATA + 0x4a */ + u16 reserved9; + u16 fifo_rdp; /* ATA + 0x4e */ + u16 reserved10; + u16 fifo_wrp; /* ATA + 0x52 */ + u16 reserved11; + u16 fifo_lfrdp; /* ATA + 0x56 */ + u16 reserved12; + u16 fifo_lfwrp; /* ATA + 0x5a */ + + /* Drive TaskFile registers */ + u8 tf_control; /* ATA + 0x5c TASKFILE Control/Alt Status */ + u8 reserved13[3]; + u16 tf_data; /* ATA + 0x60 TASKFILE Data */ + u16 reserved14; + u8 tf_features; /* ATA + 0x64 TASKFILE Features/Error */ + u8 reserved15[3]; + u8 tf_sec_count; /* ATA + 0x68 TASKFILE Sector Count */ + u8 reserved16[3]; + u8 tf_sec_num; /* ATA + 0x6c TASKFILE Sector Number */ + u8 reserved17[3]; + u8 tf_cyl_low; /* ATA + 0x70 TASKFILE Cylinder Low */ + u8 reserved18[3]; + u8 tf_cyl_high; /* ATA + 0x74 TASKFILE Cylinder High */ + u8 reserved19[3]; + u8 tf_dev_head; /* ATA + 0x78 TASKFILE Device/Head */ + u8 reserved20[3]; + u8 tf_command; /* ATA + 0x7c TASKFILE Command/Status */ + u8 dma_mode; /* ATA + 0x7d ATA Host DMA Mode configuration */ + u8 reserved21[2]; +}; + + +/* ======================================================================== */ +/* Aux fns */ +/* ======================================================================== */ + + +/* MPC52xx low level hw control */ + +static int +mpc52xx_ata_compute_pio_timings(struct mpc52xx_ata_priv *priv, int dev, int pio) +{ + struct mpc52xx_ata_timings *timing = &priv->timings[dev]; + unsigned int ipb_period = priv->ipb_period; + unsigned int t0, t1, t2_8, t2_16, t2i, t4, ta; + + if ((pio<0) || (pio>4)) + return -EINVAL; + + t0 = CALC_CLKCYC(ipb_period, 1000 * ataspec_t0[pio]); + t1 = CALC_CLKCYC(ipb_period, 1000 * ataspec_t1[pio]); + t2_8 = CALC_CLKCYC(ipb_period, 1000 * ataspec_t2_8[pio]); + t2_16 = CALC_CLKCYC(ipb_period, 1000 * ataspec_t2_16[pio]); + t2i = CALC_CLKCYC(ipb_period, 1000 * ataspec_t2i[pio]); + t4 = CALC_CLKCYC(ipb_period, 1000 * ataspec_t4[pio]); + ta = CALC_CLKCYC(ipb_period, 1000 * ataspec_ta[pio]); + + timing->pio1 = (t0 << 24) | (t2_8 << 16) | (t2_16 << 8) | (t2i); + timing->pio2 = (t4 << 24) | (t1 << 16) | (ta << 8); + + return 0; +} + +static void +mpc52xx_ata_apply_timings(struct mpc52xx_ata_priv *priv, int device) +{ + struct mpc52xx_ata __iomem *regs = priv->ata_regs; + struct mpc52xx_ata_timings *timing = &priv->timings[device]; + + out_be32(®s->pio1, timing->pio1); + out_be32(®s->pio2, timing->pio2); + out_be32(®s->mdma1, 0); + out_be32(®s->mdma2, 0); + out_be32(®s->udma1, 0); + out_be32(®s->udma2, 0); + out_be32(®s->udma3, 0); + out_be32(®s->udma4, 0); + out_be32(®s->udma5, 0); + + priv->csel = device; +} + +static int +mpc52xx_ata_hw_init(struct mpc52xx_ata_priv *priv) +{ + struct mpc52xx_ata __iomem *regs = priv->ata_regs; + int tslot; + + /* Clear share_cnt (all sample code do this ...) */ + out_be32(®s->share_cnt, 0); + + /* Configure and reset host */ + out_be32(®s->config, + MPC52xx_ATA_HOSTCONF_IE | + MPC52xx_ATA_HOSTCONF_IORDY | + MPC52xx_ATA_HOSTCONF_SMR | + MPC52xx_ATA_HOSTCONF_FR); + + udelay(10); + + out_be32(®s->config, + MPC52xx_ATA_HOSTCONF_IE | + MPC52xx_ATA_HOSTCONF_IORDY); + + /* Set the time slot to 1us */ + tslot = CALC_CLKCYC(priv->ipb_period, 1000000); + out_be32(®s->share_cnt, tslot << 16 ); + + /* Init timings to PIO0 */ + memset(priv->timings, 0x00, 2*sizeof(struct mpc52xx_ata_timings)); + + mpc52xx_ata_compute_pio_timings(priv, 0, 0); + mpc52xx_ata_compute_pio_timings(priv, 1, 0); + + mpc52xx_ata_apply_timings(priv, 0); + + return 0; +} + + +/* ======================================================================== */ +/* libata driver */ +/* ======================================================================== */ + +static void +mpc52xx_ata_set_piomode(struct ata_port *ap, struct ata_device *adev) +{ + struct mpc52xx_ata_priv *priv = ap->host->private_data; + int pio, rv; + + pio = adev->pio_mode - XFER_PIO_0; + + rv = mpc52xx_ata_compute_pio_timings(priv, adev->devno, pio); + + if (rv) { + printk(KERN_ERR DRV_NAME + ": Trying to select invalid PIO mode %d\n", pio); + return; + } + + mpc52xx_ata_apply_timings(priv, adev->devno); +} +static void +mpc52xx_ata_dev_select(struct ata_port *ap, unsigned int device) +{ + struct mpc52xx_ata_priv *priv = ap->host->private_data; + + if (device != priv->csel) + mpc52xx_ata_apply_timings(priv, device); + + ata_std_dev_select(ap,device); +} + +static void +mpc52xx_ata_error_handler(struct ata_port *ap) +{ + ata_bmdma_drive_eh(ap, ata_std_prereset, ata_std_softreset, NULL, + ata_std_postreset); +} + + + +static struct scsi_host_template mpc52xx_ata_sht = { + .module = THIS_MODULE, + .name = DRV_NAME, + .ioctl = ata_scsi_ioctl, + .queuecommand = ata_scsi_queuecmd, + .can_queue = ATA_DEF_QUEUE, + .this_id = ATA_SHT_THIS_ID, + .sg_tablesize = LIBATA_MAX_PRD, + .max_sectors = ATA_MAX_SECTORS, + .cmd_per_lun = ATA_SHT_CMD_PER_LUN, + .emulated = ATA_SHT_EMULATED, + .use_clustering = ATA_SHT_USE_CLUSTERING, + .proc_name = DRV_NAME, + .dma_boundary = ATA_DMA_BOUNDARY, + .slave_configure = ata_scsi_slave_config, + .bios_param = ata_std_bios_param, +}; + +static struct ata_port_operations mpc52xx_ata_port_ops = { + .port_disable = ata_port_disable, + .set_piomode = mpc52xx_ata_set_piomode, + .dev_select = mpc52xx_ata_dev_select, + .tf_load = ata_tf_load, + .tf_read = ata_tf_read, + .check_status = ata_check_status, + .exec_command = ata_exec_command, + .freeze = ata_bmdma_freeze, + .thaw = ata_bmdma_thaw, + .error_handler = mpc52xx_ata_error_handler, + .qc_prep = ata_qc_prep, + .qc_issue = ata_qc_issue_prot, + .data_xfer = ata_data_xfer, + .irq_handler = ata_interrupt, + .irq_clear = ata_bmdma_irq_clear, + .irq_on = ata_irq_on, + .irq_ack = ata_irq_ack, + .port_start = ata_port_start, +}; + +static struct ata_probe_ent mpc52xx_ata_probe_ent = { + .port_ops = &mpc52xx_ata_port_ops, + .sht = &mpc52xx_ata_sht, + .n_ports = 1, + .pio_mask = 0x1f, /* Up to PIO4 */ + .mwdma_mask = 0x00, /* No MWDMA */ + .udma_mask = 0x00, /* No UDMA */ + .port_flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST, + .irq_flags = 0, +}; + +static int __devinit +mpc52xx_ata_init_one(struct device *dev, struct mpc52xx_ata_priv *priv) +{ + struct ata_probe_ent *ae = &mpc52xx_ata_probe_ent; + struct ata_ioports *aio = &ae->port[0]; + int rv; + + INIT_LIST_HEAD(&ae->node); + ae->dev = dev; + ae->irq = priv->ata_irq; + + aio->cmd_addr = 0; /* Don't have a classic reg block */ + aio->altstatus_addr = &priv->ata_regs->tf_control; + aio->ctl_addr = &priv->ata_regs->tf_control; + aio->data_addr = &priv->ata_regs->tf_data; + aio->error_addr = &priv->ata_regs->tf_features; + aio->feature_addr = &priv->ata_regs->tf_features; + aio->nsect_addr = &priv->ata_regs->tf_sec_count; + aio->lbal_addr = &priv->ata_regs->tf_sec_num; + aio->lbam_addr = &priv->ata_regs->tf_cyl_low; + aio->lbah_addr = &priv->ata_regs->tf_cyl_high; + aio->device_addr = &priv->ata_regs->tf_dev_head; + aio->status_addr = &priv->ata_regs->tf_command; + aio->command_addr = &priv->ata_regs->tf_command; + + ae->private_data = priv; + + rv = ata_device_add(ae); + + return rv ? 0 : -EINVAL; +} + +static struct mpc52xx_ata_priv * +mpc52xx_ata_remove_one(struct device *dev) +{ + struct ata_host *host = dev_get_drvdata(dev); + struct mpc52xx_ata_priv *priv = host->private_data; + + ata_host_detach(host); + + return priv; +} + + +/* ======================================================================== */ +/* OF Platform driver */ +/* ======================================================================== */ + +static int __devinit +mpc52xx_ata_probe(struct of_device *op, const struct of_device_id *match) +{ + unsigned int ipb_freq; + struct resource res_mem; + int ata_irq = NO_IRQ; + struct mpc52xx_ata __iomem *ata_regs; + struct mpc52xx_ata_priv *priv; + int rv; + + /* Get ipb frequency */ + ipb_freq = mpc52xx_find_ipb_freq(op->node); + if (!ipb_freq) { + printk(KERN_ERR DRV_NAME ": " + "Unable to find IPB Bus frequency\n" ); + return -ENODEV; + } + + /* Get IRQ and register */ + rv = of_address_to_resource(op->node, 0, &res_mem); + if (rv) { + printk(KERN_ERR DRV_NAME ": " + "Error while parsing device node resource\n" ); + return rv; + } + + ata_irq = irq_of_parse_and_map(op->node, 0); + if (ata_irq == NO_IRQ) { + printk(KERN_ERR DRV_NAME ": " + "Error while mapping the irq\n"); + return -EINVAL; + } + + /* Request mem region */ + if (!devm_request_mem_region(&op->dev, res_mem.start, + sizeof(struct mpc52xx_ata), DRV_NAME)) { + printk(KERN_ERR DRV_NAME ": " + "Error while requesting mem region\n"); + rv = -EBUSY; + goto err; + } + + /* Remap registers */ + ata_regs = devm_ioremap(&op->dev, res_mem.start, + sizeof(struct mpc52xx_ata)); + if (!ata_regs) { + printk(KERN_ERR DRV_NAME ": " + "Error while mapping register set\n"); + rv = -ENOMEM; + goto err; + } + + /* Prepare our private structure */ + priv = devm_kzalloc(&op->dev, sizeof(struct mpc52xx_ata_priv), + GFP_ATOMIC); + if (!priv) { + printk(KERN_ERR DRV_NAME ": " + "Error while allocating private structure\n"); + rv = -ENOMEM; + goto err; + } + + priv->ipb_period = 1000000000 / (ipb_freq / 1000); + priv->ata_regs = ata_regs; + priv->ata_irq = ata_irq; + priv->csel = -1; + + /* Init the hw */ + rv = mpc52xx_ata_hw_init(priv); + if (rv) { + printk(KERN_ERR DRV_NAME ": Error during HW init\n"); + goto err; + } + + /* Register ourselves to libata */ + rv = mpc52xx_ata_init_one(&op->dev, priv); + if (rv) { + printk(KERN_ERR DRV_NAME ": " + "Error while registering to ATA layer\n"); + return rv; + } + + /* Done */ + return 0; + + /* Error path */ +err: + irq_dispose_mapping(ata_irq); + return rv; +} + +static int +mpc52xx_ata_remove(struct of_device *op) +{ + struct mpc52xx_ata_priv *priv; + + priv = mpc52xx_ata_remove_one(&op->dev); + irq_dispose_mapping(priv->ata_irq); + + return 0; +} + + +#ifdef CONFIG_PM + +static int +mpc52xx_ata_suspend(struct of_device *op, pm_message_t state) +{ + return 0; /* FIXME : What to do here ? */ +} + +static int +mpc52xx_ata_resume(struct of_device *op) +{ + return 0; /* FIXME : What to do here ? */ +} + +#endif + + +static struct of_device_id mpc52xx_ata_of_match[] = { + { + .type = "ata", + .compatible = "mpc5200-ata", + }, + {}, +}; + + +static struct of_platform_driver mpc52xx_ata_of_platform_driver = { + .owner = THIS_MODULE, + .name = DRV_NAME, + .match_table = mpc52xx_ata_of_match, + .probe = mpc52xx_ata_probe, + .remove = mpc52xx_ata_remove, +#ifdef CONFIG_PM + .suspend = mpc52xx_ata_suspend, + .resume = mpc52xx_ata_resume, +#endif + .driver = { + .name = DRV_NAME, + .owner = THIS_MODULE, + }, +}; + + +/* ======================================================================== */ +/* Module */ +/* ======================================================================== */ + +static int __init +mpc52xx_ata_init(void) +{ + printk(KERN_INFO "ata: MPC52xx IDE/ATA libata driver\n"); + return of_register_platform_driver(&mpc52xx_ata_of_platform_driver); +} + +static void __exit +mpc52xx_ata_exit(void) +{ + of_unregister_platform_driver(&mpc52xx_ata_of_platform_driver); +} + +module_init(mpc52xx_ata_init); +module_exit(mpc52xx_ata_exit); + +MODULE_AUTHOR("Sylvain Munaut "); +MODULE_DESCRIPTION("Freescale MPC52xx IDE/ATA libata driver"); +MODULE_LICENSE("GPL"); +MODULE_DEVICE_TABLE(of, mpc52xx_ata_of_match); +MODULE_VERSION(DRV_VERSION); + diff --git a/drivers/ata/pata_mpiix.c b/drivers/ata/pata_mpiix.c index 4ccca93..f2e7115 100644 --- a/drivers/ata/pata_mpiix.c +++ b/drivers/ata/pata_mpiix.c @@ -35,7 +35,7 @@ #include #include #define DRV_NAME "pata_mpiix" -#define DRV_VERSION "0.7.3" +#define DRV_VERSION "0.7.5" enum { IDETIM = 0x6C, /* IDE control register */ @@ -49,12 +49,9 @@ enum { static int mpiix_pre_reset(struct ata_port *ap) { struct pci_dev *pdev = to_pci_dev(ap->host->dev); - static const struct pci_bits mpiix_enable_bits[] = { - { 0x6D, 1, 0x80, 0x80 }, - { 0x6F, 1, 0x80, 0x80 } - }; + static const struct pci_bits mpiix_enable_bits = { 0x6D, 1, 0x80, 0x80 }; - if (!pci_test_config_bits(pdev, &mpiix_enable_bits[ap->port_no])) + if (!pci_test_config_bits(pdev, &mpiix_enable_bits)) return -ENOENT; ap->cbl = ATA_CBL_PATA40; return ata_std_prereset(ap); @@ -80,8 +77,8 @@ static void mpiix_error_handler(struct a * @adev: ATA device * * Called to do the PIO mode setup. The MPIIX allows us to program the - * IORDY sample point (2-5 clocks), recovery 1-4 clocks and whether - * prefetching or iordy are used. + * IORDY sample point (2-5 clocks), recovery (1-4 clocks) and whether + * prefetching or IORDY are used. * * This would get very ugly because we can only program timing for one * device at a time, the other gets PIO0. Fortunately libata calls @@ -103,18 +100,19 @@ static void mpiix_set_piomode(struct ata { 2, 3 }, }; pci_read_config_word(pdev, IDETIM, &idetim); - /* Mask the IORDY/TIME/PPE0 bank for this device */ + + /* Mask the IORDY/TIME/PPE for this device */ if (adev->class == ATA_DEV_ATA) - control |= PPE; /* PPE enable for disk */ + control |= PPE; /* Enable prefetch/posting for disk */ if (ata_pio_need_iordy(adev)) - control |= IORDY; /* IORDY */ - if (pio > 0) + control |= IORDY; + if (pio > 1) control |= FTIM; /* This drive is on the fast timing bank */ /* Mask out timing and clear both TIME bank selects */ idetim &= 0xCCEE; - idetim &= ~(0x07 << (2 * adev->devno)); - idetim |= (control << (2 * adev->devno)); + idetim &= ~(0x07 << (4 * adev->devno)); + idetim |= control << (4 * adev->devno); idetim |= (timings[pio][0] << 12) | (timings[pio][1] << 8); pci_write_config_word(pdev, IDETIM, idetim); @@ -188,23 +186,24 @@ static struct ata_port_operations mpiix_ .qc_prep = ata_qc_prep, .qc_issue = mpiix_qc_issue_prot, - .data_xfer = ata_pio_data_xfer, + .data_xfer = ata_data_xfer, .irq_handler = ata_interrupt, .irq_clear = ata_bmdma_irq_clear, + .irq_on = ata_irq_on, + .irq_ack = ata_irq_ack, .port_start = ata_port_start, - .port_stop = ata_port_stop, - .host_stop = ata_host_stop }; static int mpiix_init_one(struct pci_dev *dev, const struct pci_device_id *id) { /* Single threaded by the PCI probe logic */ - static struct ata_probe_ent probe[2]; + static struct ata_probe_ent probe; static int printed_version; + void __iomem *cmd_addr, *ctl_addr; u16 idetim; - int enabled; + int irq; if (!printed_version++) dev_printk(KERN_DEBUG, &dev->dev, "version " DRV_VERSION "\n"); @@ -217,65 +216,49 @@ static int mpiix_init_one(struct pci_dev if (!(idetim & ENABLED)) return -ENODEV; + /* See if it's primary or secondary channel... */ + if (!(idetim & SECONDARY)) { + irq = 14; + cmd_addr = devm_ioport_map(&dev->dev, 0x1F0, 8); + ctl_addr = devm_ioport_map(&dev->dev, 0x3F6, 1); + } else { + irq = 15; + cmd_addr = devm_ioport_map(&dev->dev, 0x170, 8); + ctl_addr = devm_ioport_map(&dev->dev, 0x376, 1); + } + + if (!cmd_addr || !ctl_addr) + return -ENOMEM; + /* We do our own plumbing to avoid leaking special cases for whacko ancient hardware into the core code. There are two issues to worry about. #1 The chip is a bridge so if in legacy mode and without BARs set fools the setup. #2 If you pci_disable_device the MPIIX your box goes castors up */ - INIT_LIST_HEAD(&probe[0].node); - probe[0].dev = pci_dev_to_dev(dev); - probe[0].port_ops = &mpiix_port_ops; - probe[0].sht = &mpiix_sht; - probe[0].pio_mask = 0x1F; - probe[0].irq = 14; - probe[0].irq_flags = SA_SHIRQ; - probe[0].port_flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST; - probe[0].n_ports = 1; - probe[0].port[0].cmd_addr = 0x1F0; - probe[0].port[0].ctl_addr = 0x3F6; - probe[0].port[0].altstatus_addr = 0x3F6; - - /* The secondary lurks at different addresses but is otherwise - the same beastie */ - - INIT_LIST_HEAD(&probe[1].node); - probe[1] = probe[0]; - probe[1].irq = 15; - probe[1].port[0].cmd_addr = 0x170; - probe[1].port[0].ctl_addr = 0x376; - probe[1].port[0].altstatus_addr = 0x376; + INIT_LIST_HEAD(&probe.node); + probe.dev = pci_dev_to_dev(dev); + probe.port_ops = &mpiix_port_ops; + probe.sht = &mpiix_sht; + probe.pio_mask = 0x1F; + probe.irq_flags = IRQF_SHARED; + probe.port_flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST; + probe.n_ports = 1; + + probe.irq = irq; + probe.port[0].cmd_addr = cmd_addr; + probe.port[0].ctl_addr = ctl_addr; + probe.port[0].altstatus_addr = ctl_addr; /* Let libata fill in the port details */ - ata_std_ports(&probe[0].port[0]); - ata_std_ports(&probe[1].port[0]); + ata_std_ports(&probe.port[0]); /* Now add the port that is active */ - enabled = (idetim & SECONDARY) ? 1 : 0; - - if (ata_device_add(&probe[enabled])) + if (ata_device_add(&probe)) return 0; return -ENODEV; } -/** - * mpiix_remove_one - device unload - * @pdev: PCI device being removed - * - * Handle an unplug/unload event for a PCI device. Unload the - * PCI driver but do not use the default handler as we *MUST NOT* - * disable the device as it has other functions. - */ - -static void __devexit mpiix_remove_one(struct pci_dev *pdev) -{ - struct device *dev = pci_dev_to_dev(pdev); - struct ata_host *host = dev_get_drvdata(dev); - - ata_host_remove(host); - dev_set_drvdata(dev, NULL); -} - static const struct pci_device_id mpiix[] = { { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_82371MX), }, @@ -286,7 +269,7 @@ static struct pci_driver mpiix_pci_drive .name = DRV_NAME, .id_table = mpiix, .probe = mpiix_init_one, - .remove = mpiix_remove_one, + .remove = ata_pci_remove_one, .suspend = ata_pci_device_suspend, .resume = ata_pci_device_resume, }; diff --git a/drivers/ata/pata_netcell.c b/drivers/ata/pata_netcell.c index cf7fe03..e8393e1 100644 --- a/drivers/ata/pata_netcell.c +++ b/drivers/ata/pata_netcell.c @@ -89,16 +89,16 @@ static const struct ata_port_operations .bmdma_status = ata_bmdma_status, .qc_prep = ata_qc_prep, .qc_issue = ata_qc_issue_prot, - .data_xfer = ata_pio_data_xfer, + .data_xfer = ata_data_xfer, /* IRQ-related hooks */ .irq_handler = ata_interrupt, .irq_clear = ata_bmdma_irq_clear, + .irq_on = ata_irq_on, + .irq_ack = ata_irq_ack, /* Generic PATA PCI ATA helpers */ .port_start = ata_port_start, - .port_stop = ata_port_stop, - .host_stop = ata_host_stop, }; diff --git a/drivers/ata/pata_ns87410.c b/drivers/ata/pata_ns87410.c index c3032eb..3d1fa48 100644 --- a/drivers/ata/pata_ns87410.c +++ b/drivers/ata/pata_ns87410.c @@ -179,14 +179,14 @@ static struct ata_port_operations ns8741 .qc_prep = ata_qc_prep, .qc_issue = ns87410_qc_issue_prot, - .data_xfer = ata_pio_data_xfer, + .data_xfer = ata_data_xfer, .irq_handler = ata_interrupt, .irq_clear = ata_bmdma_irq_clear, + .irq_on = ata_irq_on, + .irq_ack = ata_irq_ack, .port_start = ata_port_start, - .port_stop = ata_port_stop, - .host_stop = ata_host_stop }; static int ns87410_init_one(struct pci_dev *dev, const struct pci_device_id *id) diff --git a/drivers/ata/pata_oldpiix.c b/drivers/ata/pata_oldpiix.c index 10ac3cc..45215aa 100644 --- a/drivers/ata/pata_oldpiix.c +++ b/drivers/ata/pata_oldpiix.c @@ -25,7 +25,7 @@ #include #include #define DRV_NAME "pata_oldpiix" -#define DRV_VERSION "0.5.2" +#define DRV_VERSION "0.5.3" /** * oldpiix_pre_reset - probe begin @@ -94,19 +94,21 @@ static void oldpiix_set_piomode (struct { 2, 1 }, { 2, 3 }, }; - if (pio > 2) - control |= 1; /* TIME1 enable */ + if (pio > 1) + control |= 1; /* TIME */ if (ata_pio_need_iordy(adev)) - control |= 2; /* IE IORDY */ + control |= 2; /* IE */ - /* Intel specifies that the PPE functionality is for disk only */ + /* Intel specifies that the prefetch/posting is for disk only */ if (adev->class == ATA_DEV_ATA) - control |= 4; /* PPE enable */ + control |= 4; /* PPE */ pci_read_config_word(dev, idetm_port, &idetm_data); - /* Enable PPE, IE and TIME as appropriate. Clear the other - drive timing bits */ + /* + * Set PPE, IE and TIME as appropriate. + * Clear the other drive's timing bits. + */ if (adev->devno == 0) { idetm_data &= 0xCCE0; idetm_data |= control; @@ -259,14 +261,14 @@ static const struct ata_port_operations .bmdma_status = ata_bmdma_status, .qc_prep = ata_qc_prep, .qc_issue = oldpiix_qc_issue_prot, - .data_xfer = ata_pio_data_xfer, + .data_xfer = ata_data_xfer, .irq_handler = ata_interrupt, .irq_clear = ata_bmdma_irq_clear, + .irq_on = ata_irq_on, + .irq_ack = ata_irq_ack, .port_start = ata_port_start, - .port_stop = ata_port_stop, - .host_stop = ata_host_stop, }; diff --git a/drivers/ata/pata_opti.c b/drivers/ata/pata_opti.c index c2988b0..da1aa14 100644 --- a/drivers/ata/pata_opti.c +++ b/drivers/ata/pata_opti.c @@ -95,18 +95,18 @@ static void opti_error_handler(struct at static void opti_write_reg(struct ata_port *ap, u8 val, int reg) { - unsigned long regio = ap->ioaddr.cmd_addr; + void __iomem *regio = ap->ioaddr.cmd_addr; /* These 3 unlock the control register access */ - inw(regio + 1); - inw(regio + 1); - outb(3, regio + 2); + ioread16(regio + 1); + ioread16(regio + 1); + iowrite8(3, regio + 2); /* Do the I/O */ - outb(val, regio + reg); + iowrite8(val, regio + reg); /* Relock */ - outb(0x83, regio + 2); + iowrite8(0x83, regio + 2); } /** @@ -124,7 +124,7 @@ static void opti_set_piomode(struct ata_ struct ata_device *pair = ata_dev_pair(adev); int clock; int pio = adev->pio_mode - XFER_PIO_0; - unsigned long regio = ap->ioaddr.cmd_addr; + void __iomem *regio = ap->ioaddr.cmd_addr; u8 addr; /* Address table precomputed with prefetch off and a DCLK of 2 */ @@ -137,8 +137,8 @@ static void opti_set_piomode(struct ata_ { 0x58, 0x44, 0x32, 0x22, 0x21 } }; - outb(0xff, regio + 5); - clock = inw(regio + 5) & 1; + iowrite8(0xff, regio + 5); + clock = ioread16(regio + 5) & 1; /* * As with many controllers the address setup time is shared @@ -205,14 +205,14 @@ static struct ata_port_operations opti_p .qc_prep = ata_qc_prep, .qc_issue = ata_qc_issue_prot, - .data_xfer = ata_pio_data_xfer, + .data_xfer = ata_data_xfer, .irq_handler = ata_interrupt, .irq_clear = ata_bmdma_irq_clear, + .irq_on = ata_irq_on, + .irq_ack = ata_irq_ack, .port_start = ata_port_start, - .port_stop = ata_port_stop, - .host_stop = ata_host_stop }; static int opti_init_one(struct pci_dev *dev, const struct pci_device_id *id) diff --git a/drivers/ata/pata_optidma.c b/drivers/ata/pata_optidma.c index 80d111c..d80b36e 100644 --- a/drivers/ata/pata_optidma.c +++ b/drivers/ata/pata_optidma.c @@ -91,12 +91,12 @@ static void optidma_error_handler(struct static void optidma_unlock(struct ata_port *ap) { - unsigned long regio = ap->ioaddr.cmd_addr; + void __iomem *regio = ap->ioaddr.cmd_addr; /* These 3 unlock the control register access */ - inw(regio + 1); - inw(regio + 1); - outb(3, regio + 2); + ioread16(regio + 1); + ioread16(regio + 1); + iowrite8(3, regio + 2); } /** @@ -108,10 +108,10 @@ static void optidma_unlock(struct ata_po static void optidma_lock(struct ata_port *ap) { - unsigned long regio = ap->ioaddr.cmd_addr; + void __iomem *regio = ap->ioaddr.cmd_addr; /* Relock */ - outb(0x83, regio + 2); + iowrite8(0x83, regio + 2); } /** @@ -133,7 +133,7 @@ static void optidma_set_mode(struct ata_ struct ata_device *pair = ata_dev_pair(adev); int pio = adev->pio_mode - XFER_PIO_0; int dma = adev->dma_mode - XFER_MW_DMA_0; - unsigned long regio = ap->ioaddr.cmd_addr; + void __iomem *regio = ap->ioaddr.cmd_addr; u8 addr; /* Address table precomputed with a DCLK of 2 */ @@ -178,20 +178,20 @@ static void optidma_set_mode(struct ata_ /* Commence primary programming sequence */ /* First we load the device number into the timing select */ - outb(adev->devno, regio + MISC_REG); + iowrite8(adev->devno, regio + MISC_REG); /* Now we load the data timings into read data/write data */ if (mode < XFER_MW_DMA_0) { - outb(data_rec_timing[pci_clock][pio], regio + READ_REG); - outb(data_rec_timing[pci_clock][pio], regio + WRITE_REG); + iowrite8(data_rec_timing[pci_clock][pio], regio + READ_REG); + iowrite8(data_rec_timing[pci_clock][pio], regio + WRITE_REG); } else if (mode < XFER_UDMA_0) { - outb(dma_data_rec_timing[pci_clock][dma], regio + READ_REG); - outb(dma_data_rec_timing[pci_clock][dma], regio + WRITE_REG); + iowrite8(dma_data_rec_timing[pci_clock][dma], regio + READ_REG); + iowrite8(dma_data_rec_timing[pci_clock][dma], regio + WRITE_REG); } /* Finally we load the address setup into the misc register */ - outb(addr | adev->devno, regio + MISC_REG); + iowrite8(addr | adev->devno, regio + MISC_REG); /* Programming sequence complete, timing 0 dev 0, timing 1 dev 1 */ - outb(0x85, regio + CNTRL_REG); + iowrite8(0x85, regio + CNTRL_REG); /* Switch back to IDE mode */ optidma_lock(ap); @@ -389,14 +389,14 @@ static struct ata_port_operations optidm .qc_prep = ata_qc_prep, .qc_issue = ata_qc_issue_prot, - .data_xfer = ata_pio_data_xfer, + .data_xfer = ata_data_xfer, .irq_handler = ata_interrupt, .irq_clear = ata_bmdma_irq_clear, + .irq_on = ata_irq_on, + .irq_ack = ata_irq_ack, .port_start = ata_port_start, - .port_stop = ata_port_stop, - .host_stop = ata_host_stop }; static struct ata_port_operations optiplus_port_ops = { @@ -424,14 +424,14 @@ static struct ata_port_operations optipl .qc_prep = ata_qc_prep, .qc_issue = ata_qc_issue_prot, - .data_xfer = ata_pio_data_xfer, + .data_xfer = ata_data_xfer, .irq_handler = ata_interrupt, .irq_clear = ata_bmdma_irq_clear, + .irq_on = ata_irq_on, + .irq_ack = ata_irq_ack, .port_start = ata_port_start, - .port_stop = ata_port_stop, - .host_stop = ata_host_stop }; /** diff --git a/drivers/ata/pata_pcmcia.c b/drivers/ata/pata_pcmcia.c index 9ed7f58..36468ec 100644 --- a/drivers/ata/pata_pcmcia.c +++ b/drivers/ata/pata_pcmcia.c @@ -88,14 +88,14 @@ static struct ata_port_operations pcmcia .qc_prep = ata_qc_prep, .qc_issue = ata_qc_issue_prot, - .data_xfer = ata_pio_data_xfer_noirq, + .data_xfer = ata_data_xfer_noirq, .irq_handler = ata_interrupt, .irq_clear = ata_bmdma_irq_clear, + .irq_on = ata_irq_on, + .irq_ack = ata_irq_ack, .port_start = ata_port_start, - .port_stop = ata_port_stop, - .host_stop = ata_host_stop }; #define CS_CHECK(fn, ret) \ @@ -123,6 +123,7 @@ static int pcmcia_init_one(struct pcmcia cistpl_cftable_entry_t *cfg; int pass, last_ret = 0, last_fn = 0, is_kme = 0, ret = -ENOMEM; unsigned long io_base, ctl_base; + void __iomem *io_addr, *ctl_addr; info = kzalloc(sizeof(*info), GFP_KERNEL); if (info == NULL) @@ -233,10 +234,17 @@ next_entry: CS_CHECK(RequestIRQ, pcmcia_request_irq(pdev, &pdev->irq)); CS_CHECK(RequestConfiguration, pcmcia_request_configuration(pdev, &pdev->conf)); + /* iomap */ + ret = -ENOMEM; + io_addr = devm_ioport_map(&pdev->dev, io_base, 8); + ctl_addr = devm_ioport_map(&pdev->dev, ctl_base, 1); + if (!io_addr || !ctl_addr) + goto failed; + /* Success. Disable the IRQ nIEN line, do quirks */ - outb(0x02, ctl_base); + iowrite8(0x02, ctl_addr); if (is_kme) - outb(0x81, ctl_base + 0x01); + iowrite8(0x81, ctl_addr + 0x01); /* FIXME: Could be more ports at base + 0x10 but we only deal with one right now */ @@ -256,13 +264,14 @@ next_entry: ae.n_ports = 1; ae.pio_mask = 1; /* ISA so PIO 0 cycles */ ae.irq = pdev->irq.AssignedIRQ; - ae.irq_flags = SA_SHIRQ; + ae.irq_flags = IRQF_SHARED; ae.port_flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST; - ae.port[0].cmd_addr = io_base; - ae.port[0].altstatus_addr = ctl_base; - ae.port[0].ctl_addr = ctl_base; + ae.port[0].cmd_addr = io_addr; + ae.port[0].altstatus_addr = ctl_addr; + ae.port[0].ctl_addr = ctl_addr; ata_std_ports(&ae.port[0]); + ret = -ENODEV; if (ata_device_add(&ae) == 0) goto failed; @@ -298,7 +307,7 @@ static void pcmcia_remove_one(struct pcm /* If we have attached the device to the ATA layer, detach it */ if (info->ndev) { struct ata_host *host = dev_get_drvdata(dev); - ata_host_remove(host); + ata_host_detach(host); dev_set_drvdata(dev, NULL); } info->ndev = 0; diff --git a/drivers/ata/pata_pdc2027x.c b/drivers/ata/pata_pdc2027x.c index 76dd1c9..6153787 100644 --- a/drivers/ata/pata_pdc2027x.c +++ b/drivers/ata/pata_pdc2027x.c @@ -33,7 +33,6 @@ #include #include #include #include -#include #define DRV_NAME "pata_pdc2027x" #define DRV_VERSION "0.74-ac5" @@ -46,6 +45,8 @@ #define PDPRINTK(fmt, args...) #endif enum { + PDC_MMIO_BAR = 5, + PDC_UDMA_100 = 0, PDC_UDMA_133 = 1, @@ -62,7 +63,6 @@ enum { }; static int pdc2027x_init_one(struct pci_dev *pdev, const struct pci_device_id *ent); -static void pdc2027x_remove_one(struct pci_dev *pdev); static void pdc2027x_error_handler(struct ata_port *ap); static void pdc2027x_set_piomode(struct ata_port *ap, struct ata_device *adev); static void pdc2027x_set_dmamode(struct ata_port *ap, struct ata_device *adev); @@ -123,7 +123,7 @@ static struct pci_driver pdc2027x_pci_dr .name = DRV_NAME, .id_table = pdc2027x_pci_tbl, .probe = pdc2027x_init_one, - .remove = __devexit_p(pdc2027x_remove_one), + .remove = ata_pci_remove_one, }; static struct scsi_host_template pdc2027x_sht = { @@ -160,7 +160,7 @@ static struct ata_port_operations pdc202 .bmdma_status = ata_bmdma_status, .qc_prep = ata_qc_prep, .qc_issue = ata_qc_issue_prot, - .data_xfer = ata_mmio_data_xfer, + .data_xfer = ata_data_xfer, .freeze = ata_bmdma_freeze, .thaw = ata_bmdma_thaw, @@ -169,10 +169,10 @@ static struct ata_port_operations pdc202 .irq_handler = ata_interrupt, .irq_clear = ata_bmdma_irq_clear, + .irq_on = ata_irq_on, + .irq_ack = ata_irq_ack, .port_start = ata_port_start, - .port_stop = ata_port_stop, - .host_stop = ata_pci_host_stop, }; static struct ata_port_operations pdc2027x_pata133_ops = { @@ -194,7 +194,7 @@ static struct ata_port_operations pdc202 .bmdma_status = ata_bmdma_status, .qc_prep = ata_qc_prep, .qc_issue = ata_qc_issue_prot, - .data_xfer = ata_mmio_data_xfer, + .data_xfer = ata_data_xfer, .freeze = ata_bmdma_freeze, .thaw = ata_bmdma_thaw, @@ -203,10 +203,10 @@ static struct ata_port_operations pdc202 .irq_handler = ata_interrupt, .irq_clear = ata_bmdma_irq_clear, + .irq_on = ata_irq_on, + .irq_ack = ata_irq_ack, .port_start = ata_port_start, - .port_stop = ata_port_stop, - .host_stop = ata_pci_host_stop, }; static struct ata_port_info pdc2027x_port_info[] = { @@ -245,7 +245,7 @@ MODULE_DEVICE_TABLE(pci, pdc2027x_pci_tb */ static inline void __iomem *port_mmio(struct ata_port *ap, unsigned int offset) { - return ap->host->mmio_base + ap->port_no * 0x100 + offset; + return ap->host->iomap[PDC_MMIO_BAR] + ap->port_no * 0x100 + offset; } /** @@ -526,18 +526,19 @@ static int pdc2027x_check_atapi_dma(stru static long pdc_read_counter(struct ata_probe_ent *probe_ent) { + void __iomem *mmio_base = probe_ent->iomap[PDC_MMIO_BAR]; long counter; int retry = 1; u32 bccrl, bccrh, bccrlv, bccrhv; retry: - bccrl = readl(probe_ent->mmio_base + PDC_BYTE_COUNT) & 0xffff; - bccrh = readl(probe_ent->mmio_base + PDC_BYTE_COUNT + 0x100) & 0xffff; + bccrl = readl(mmio_base + PDC_BYTE_COUNT) & 0xffff; + bccrh = readl(mmio_base + PDC_BYTE_COUNT + 0x100) & 0xffff; rmb(); /* Read the counter values again for verification */ - bccrlv = readl(probe_ent->mmio_base + PDC_BYTE_COUNT) & 0xffff; - bccrhv = readl(probe_ent->mmio_base + PDC_BYTE_COUNT + 0x100) & 0xffff; + bccrlv = readl(mmio_base + PDC_BYTE_COUNT) & 0xffff; + bccrhv = readl(mmio_base + PDC_BYTE_COUNT + 0x100) & 0xffff; rmb(); counter = (bccrh << 15) | bccrl; @@ -568,7 +569,7 @@ retry: */ static void pdc_adjust_pll(struct ata_probe_ent *probe_ent, long pll_clock, unsigned int board_idx) { - + void __iomem *mmio_base = probe_ent->iomap[PDC_MMIO_BAR]; u16 pll_ctl; long pll_clock_khz = pll_clock / 1000; long pout_required = board_idx? PDC_133_MHZ:PDC_100_MHZ; @@ -587,7 +588,7 @@ #ifdef PDC_DEBUG /* Show the current clock value of PLL control register * (maybe already configured by the firmware) */ - pll_ctl = readw(probe_ent->mmio_base + PDC_PLL_CTL); + pll_ctl = readw(mmio_base + PDC_PLL_CTL); PDPRINTK("pll_ctl[%X]\n", pll_ctl); #endif @@ -627,8 +628,8 @@ #endif PDPRINTK("Writing pll_ctl[%X]\n", pll_ctl); - writew(pll_ctl, probe_ent->mmio_base + PDC_PLL_CTL); - readw(probe_ent->mmio_base + PDC_PLL_CTL); /* flush */ + writew(pll_ctl, mmio_base + PDC_PLL_CTL); + readw(mmio_base + PDC_PLL_CTL); /* flush */ /* Wait the PLL circuit to be stable */ mdelay(30); @@ -638,7 +639,7 @@ #ifdef PDC_DEBUG * Show the current clock value of PLL control register * (maybe configured by the firmware) */ - pll_ctl = readw(probe_ent->mmio_base + PDC_PLL_CTL); + pll_ctl = readw(mmio_base + PDC_PLL_CTL); PDPRINTK("pll_ctl[%X]\n", pll_ctl); #endif @@ -654,6 +655,7 @@ #endif */ static long pdc_detect_pll_input_clock(struct ata_probe_ent *probe_ent) { + void __iomem *mmio_base = probe_ent->iomap[PDC_MMIO_BAR]; u32 scr; long start_count, end_count; long pll_clock; @@ -662,10 +664,10 @@ static long pdc_detect_pll_input_clock(s start_count = pdc_read_counter(probe_ent); /* Start the test mode */ - scr = readl(probe_ent->mmio_base + PDC_SYS_CTL); + scr = readl(mmio_base + PDC_SYS_CTL); PDPRINTK("scr[%X]\n", scr); - writel(scr | (0x01 << 14), probe_ent->mmio_base + PDC_SYS_CTL); - readl(probe_ent->mmio_base + PDC_SYS_CTL); /* flush */ + writel(scr | (0x01 << 14), mmio_base + PDC_SYS_CTL); + readl(mmio_base + PDC_SYS_CTL); /* flush */ /* Let the counter run for 100 ms. */ mdelay(100); @@ -674,10 +676,10 @@ static long pdc_detect_pll_input_clock(s end_count = pdc_read_counter(probe_ent); /* Stop the test mode */ - scr = readl(probe_ent->mmio_base + PDC_SYS_CTL); + scr = readl(mmio_base + PDC_SYS_CTL); PDPRINTK("scr[%X]\n", scr); - writel(scr & ~(0x01 << 14), probe_ent->mmio_base + PDC_SYS_CTL); - readl(probe_ent->mmio_base + PDC_SYS_CTL); /* flush */ + writel(scr & ~(0x01 << 14), mmio_base + PDC_SYS_CTL); + readl(mmio_base + PDC_SYS_CTL); /* flush */ /* calculate the input clock in Hz */ pll_clock = (start_count - end_count) * 10; @@ -722,7 +724,7 @@ static int pdc_hardware_init(struct pci_ * @port: ata ioports to setup * @base: base address */ -static void pdc_ata_setup_port(struct ata_ioports *port, unsigned long base) +static void pdc_ata_setup_port(struct ata_ioports *port, void __iomem *base) { port->cmd_addr = port->data_addr = base; @@ -755,48 +757,37 @@ static int __devinit pdc2027x_init_one(s static int printed_version; unsigned int board_idx = (unsigned int) ent->driver_data; - struct ata_probe_ent *probe_ent = NULL; - unsigned long base; + struct ata_probe_ent *probe_ent; void __iomem *mmio_base; int rc; if (!printed_version++) dev_printk(KERN_DEBUG, &pdev->dev, "version " DRV_VERSION "\n"); - rc = pci_enable_device(pdev); + rc = pcim_enable_device(pdev); if (rc) return rc; - rc = pci_request_regions(pdev, DRV_NAME); + rc = pcim_iomap_regions(pdev, 1 << PDC_MMIO_BAR, DRV_NAME); if (rc) - goto err_out; + return rc; rc = pci_set_dma_mask(pdev, ATA_DMA_MASK); if (rc) - goto err_out_regions; + return rc; rc = pci_set_consistent_dma_mask(pdev, ATA_DMA_MASK); if (rc) - goto err_out_regions; + return rc; /* Prepare the probe entry */ - probe_ent = kzalloc(sizeof(*probe_ent), GFP_KERNEL); - if (probe_ent == NULL) { - rc = -ENOMEM; - goto err_out_regions; - } + probe_ent = devm_kzalloc(&pdev->dev, sizeof(*probe_ent), GFP_KERNEL); + if (probe_ent == NULL) + return -ENOMEM; probe_ent->dev = pci_dev_to_dev(pdev); INIT_LIST_HEAD(&probe_ent->node); - mmio_base = pci_iomap(pdev, 5, 0); - if (!mmio_base) { - rc = -ENOMEM; - goto err_out_free_ent; - } - - base = (unsigned long) mmio_base; - probe_ent->sht = pdc2027x_port_info[board_idx].sht; probe_ent->port_flags = pdc2027x_port_info[board_idx].flags; probe_ent->pio_mask = pdc2027x_port_info[board_idx].pio_mask; @@ -805,13 +796,15 @@ static int __devinit pdc2027x_init_one(s probe_ent->port_ops = pdc2027x_port_info[board_idx].port_ops; probe_ent->irq = pdev->irq; - probe_ent->irq_flags = SA_SHIRQ; - probe_ent->mmio_base = mmio_base; + probe_ent->irq_flags = IRQF_SHARED; + probe_ent->iomap = pcim_iomap_table(pdev); - pdc_ata_setup_port(&probe_ent->port[0], base + 0x17c0); - probe_ent->port[0].bmdma_addr = base + 0x1000; - pdc_ata_setup_port(&probe_ent->port[1], base + 0x15c0); - probe_ent->port[1].bmdma_addr = base + 0x1008; + mmio_base = probe_ent->iomap[PDC_MMIO_BAR]; + + pdc_ata_setup_port(&probe_ent->port[0], mmio_base + 0x17c0); + probe_ent->port[0].bmdma_addr = mmio_base + 0x1000; + pdc_ata_setup_port(&probe_ent->port[1], mmio_base + 0x15c0); + probe_ent->port[1].bmdma_addr = mmio_base + 0x1008; probe_ent->n_ports = 2; @@ -820,32 +813,13 @@ static int __devinit pdc2027x_init_one(s /* initialize adapter */ if (pdc_hardware_init(pdev, probe_ent, board_idx) != 0) - goto err_out_free_ent; + return -EIO; - ata_device_add(probe_ent); - kfree(probe_ent); + if (!ata_device_add(probe_ent)) + return -ENODEV; + devm_kfree(&pdev->dev, probe_ent); return 0; - -err_out_free_ent: - kfree(probe_ent); -err_out_regions: - pci_release_regions(pdev); -err_out: - pci_disable_device(pdev); - return rc; -} - -/** - * pdc2027x_remove_one - Called to remove a single instance of the - * adapter. - * - * @dev: The PCI device to remove. - * FIXME: module load/unload not working yet - */ -static void __devexit pdc2027x_remove_one(struct pci_dev *pdev) -{ - ata_pci_remove_one(pdev); } /** diff --git a/drivers/ata/pata_pdc202xx_old.c b/drivers/ata/pata_pdc202xx_old.c index ad691b9..6dd6341 100644 --- a/drivers/ata/pata_pdc202xx_old.c +++ b/drivers/ata/pata_pdc202xx_old.c @@ -170,17 +170,17 @@ static void pdc2026x_bmdma_start(struct struct ata_taskfile *tf = &qc->tf; int sel66 = ap->port_no ? 0x08: 0x02; - unsigned long master = ap->host->ports[0]->ioaddr.bmdma_addr; - unsigned long clock = master + 0x11; - unsigned long atapi_reg = master + 0x20 + (4 * ap->port_no); + void __iomem *master = ap->host->ports[0]->ioaddr.bmdma_addr; + void __iomem *clock = master + 0x11; + void __iomem *atapi_reg = master + 0x20 + (4 * ap->port_no); u32 len; /* Check we keep host level locking here */ if (adev->dma_mode >= XFER_UDMA_2) - outb(inb(clock) | sel66, clock); + iowrite8(ioread8(clock) | sel66, clock); else - outb(inb(clock) & ~sel66, clock); + iowrite8(ioread8(clock) & ~sel66, clock); /* The DMA clocks may have been trashed by a reset. FIXME: make conditional and move to qc_issue ? */ @@ -189,17 +189,14 @@ static void pdc2026x_bmdma_start(struct /* Cases the state machine will not complete correctly without help */ if ((tf->flags & ATA_TFLAG_LBA48) || tf->protocol == ATA_PROT_ATAPI_DMA) { - if (tf->flags & ATA_TFLAG_LBA48) - len = qc->nsect * 512; - else - len = qc->nbytes; + len = qc->nbytes; if (tf->flags & ATA_TFLAG_WRITE) len |= 0x06000000; else len |= 0x05000000; - outl(len, atapi_reg); + iowrite32(len, atapi_reg); } /* Activate DMA */ @@ -222,19 +219,19 @@ static void pdc2026x_bmdma_stop(struct a int sel66 = ap->port_no ? 0x08: 0x02; /* The clock bits are in the same register for both channels */ - unsigned long master = ap->host->ports[0]->ioaddr.bmdma_addr; - unsigned long clock = master + 0x11; - unsigned long atapi_reg = master + 0x20 + (4 * ap->port_no); + void __iomem *master = ap->host->ports[0]->ioaddr.bmdma_addr; + void __iomem *clock = master + 0x11; + void __iomem *atapi_reg = master + 0x20 + (4 * ap->port_no); /* Cases the state machine will not complete correctly */ if (tf->protocol == ATA_PROT_ATAPI_DMA || ( tf->flags & ATA_TFLAG_LBA48)) { - outl(0, atapi_reg); - outb(inb(clock) & ~sel66, clock); + iowrite32(0, atapi_reg); + iowrite8(ioread8(clock) & ~sel66, clock); } /* Check we keep host level locking here */ /* Flip back to 33Mhz for PIO */ if (adev->dma_mode >= XFER_UDMA_2) - outb(inb(clock) & ~sel66, clock); + iowrite8(ioread8(clock) & ~sel66, clock); ata_bmdma_stop(qc); } @@ -297,14 +294,14 @@ static struct ata_port_operations pdc202 .qc_prep = ata_qc_prep, .qc_issue = ata_qc_issue_prot, - .data_xfer = ata_pio_data_xfer, + .data_xfer = ata_data_xfer, .irq_handler = ata_interrupt, .irq_clear = ata_bmdma_irq_clear, + .irq_on = ata_irq_on, + .irq_ack = ata_irq_ack, .port_start = ata_port_start, - .port_stop = ata_port_stop, - .host_stop = ata_host_stop }; static struct ata_port_operations pdc2026x_port_ops = { @@ -331,14 +328,14 @@ static struct ata_port_operations pdc202 .qc_prep = ata_qc_prep, .qc_issue = ata_qc_issue_prot, - .data_xfer = ata_pio_data_xfer, + .data_xfer = ata_data_xfer, .irq_handler = ata_interrupt, .irq_clear = ata_bmdma_irq_clear, + .irq_on = ata_irq_on, + .irq_ack = ata_irq_ack, .port_start = ata_port_start, - .port_stop = ata_port_stop, - .host_stop = ata_host_stop }; static int pdc202xx_init_one(struct pci_dev *dev, const struct pci_device_id *id) diff --git a/drivers/ata/pata_platform.c b/drivers/ata/pata_platform.c index 40ae11c..479a326 100644 --- a/drivers/ata/pata_platform.c +++ b/drivers/ata/pata_platform.c @@ -47,23 +47,6 @@ static int pata_platform_set_mode(struct return 0; } -static void pata_platform_host_stop(struct ata_host *host) -{ - int i; - - /* - * Unmap the bases for MMIO - */ - for (i = 0; i < host->n_ports; i++) { - struct ata_port *ap = host->ports[i]; - - if (ap->flags & ATA_FLAG_MMIO) { - iounmap((void __iomem *)ap->ioaddr.ctl_addr); - iounmap((void __iomem *)ap->ioaddr.cmd_addr); - } - } -} - static struct scsi_host_template pata_platform_sht = { .module = THIS_MODULE, .name = DRV_NAME, @@ -100,14 +83,14 @@ static struct ata_port_operations pata_p .qc_prep = ata_qc_prep, .qc_issue = ata_qc_issue_prot, - .data_xfer = ata_pio_data_xfer_noirq, + .data_xfer = ata_data_xfer_noirq, .irq_handler = ata_interrupt, .irq_clear = ata_bmdma_irq_clear, + .irq_on = ata_irq_on, + .irq_ack = ata_irq_ack, .port_start = ata_port_start, - .port_stop = ata_port_stop, - .host_stop = pata_platform_host_stop }; static void pata_platform_setup_port(struct ata_ioports *ioaddr, @@ -153,7 +136,6 @@ static int __devinit pata_platform_probe struct resource *io_res, *ctl_res; struct ata_probe_ent ae; unsigned int mmio; - int ret; /* * Simple resource validation .. @@ -207,46 +189,29 @@ static int __devinit pata_platform_probe * Handle the MMIO case */ if (mmio) { - ae.port_flags |= ATA_FLAG_MMIO; - - ae.port[0].cmd_addr = (unsigned long)ioremap(io_res->start, + ae.port[0].cmd_addr = devm_ioremap(&pdev->dev, io_res->start, io_res->end - io_res->start + 1); - if (unlikely(!ae.port[0].cmd_addr)) { - dev_err(&pdev->dev, "failed to remap IO base\n"); - return -ENXIO; - } - - ae.port[0].ctl_addr = (unsigned long)ioremap(ctl_res->start, + ae.port[0].ctl_addr = devm_ioremap(&pdev->dev, ctl_res->start, ctl_res->end - ctl_res->start + 1); - if (unlikely(!ae.port[0].ctl_addr)) { - dev_err(&pdev->dev, "failed to remap CTL base\n"); - ret = -ENXIO; - goto bad_remap; - } } else { - ae.port[0].cmd_addr = io_res->start; - ae.port[0].ctl_addr = ctl_res->start; + ae.port[0].cmd_addr = devm_ioport_map(&pdev->dev, io_res->start, + io_res->end - io_res->start + 1); + ae.port[0].ctl_addr = devm_ioport_map(&pdev->dev, ctl_res->start, + ctl_res->end - ctl_res->start + 1); + } + if (!ae.port[0].cmd_addr || !ae.port[0].ctl_addr) { + dev_err(&pdev->dev, "failed to map IO/CTL base\n"); + return -ENOMEM; } ae.port[0].altstatus_addr = ae.port[0].ctl_addr; pata_platform_setup_port(&ae.port[0], pdev->dev.platform_data); - if (unlikely(ata_device_add(&ae) == 0)) { - ret = -ENODEV; - goto add_failed; - } + if (unlikely(ata_device_add(&ae) == 0)) + return -ENODEV; return 0; - -add_failed: - if (ae.port[0].ctl_addr && mmio) - iounmap((void __iomem *)ae.port[0].ctl_addr); -bad_remap: - if (ae.port[0].cmd_addr && mmio) - iounmap((void __iomem *)ae.port[0].cmd_addr); - - return ret; } /** @@ -261,7 +226,7 @@ static int __devexit pata_platform_remov struct device *dev = &pdev->dev; struct ata_host *host = dev_get_drvdata(dev); - ata_host_remove(host); + ata_host_detach(host); dev_set_drvdata(dev, NULL); return 0; diff --git a/drivers/ata/pata_qdi.c b/drivers/ata/pata_qdi.c index afc0d99..4362141 100644 --- a/drivers/ata/pata_qdi.c +++ b/drivers/ata/pata_qdi.c @@ -131,22 +131,24 @@ static void qdi_data_xfer(struct ata_dev if (ata_id_has_dword_io(adev->id)) { if (write_data) - outsl(ap->ioaddr.data_addr, buf, buflen >> 2); + iowrite32_rep(ap->ioaddr.data_addr, buf, buflen >> 2); else - insl(ap->ioaddr.data_addr, buf, buflen >> 2); + ioread32_rep(ap->ioaddr.data_addr, buf, buflen >> 2); if (unlikely(slop)) { u32 pad; if (write_data) { memcpy(&pad, buf + buflen - slop, slop); - outl(le32_to_cpu(pad), ap->ioaddr.data_addr); + pad = le32_to_cpu(pad); + iowrite32(pad, ap->ioaddr.data_addr); } else { - pad = cpu_to_le32(inl(ap->ioaddr.data_addr)); + pad = ioread32(ap->ioaddr.data_addr); + pad = cpu_to_le32(pad); memcpy(buf + buflen - slop, &pad, slop); } } } else - ata_pio_data_xfer(adev, buf, buflen, write_data); + ata_data_xfer(adev, buf, buflen, write_data); } static struct scsi_host_template qdi_sht = { @@ -189,10 +191,10 @@ static struct ata_port_operations qdi650 .irq_handler = ata_interrupt, .irq_clear = ata_bmdma_irq_clear, + .irq_on = ata_irq_on, + .irq_ack = ata_irq_ack, .port_start = ata_port_start, - .port_stop = ata_port_stop, - .host_stop = ata_host_stop }; static struct ata_port_operations qdi6580_port_ops = { @@ -217,10 +219,10 @@ static struct ata_port_operations qdi658 .irq_handler = ata_interrupt, .irq_clear = ata_bmdma_irq_clear, + .irq_on = ata_irq_on, + .irq_ack = ata_irq_ack, .port_start = ata_port_start, - .port_stop = ata_port_stop, - .host_stop = ata_host_stop }; /** @@ -238,10 +240,9 @@ static __init int qdi_init_one(unsigned { struct ata_probe_ent ae; struct platform_device *pdev; + void __iomem *io_addr, *ctl_addr; int ret; - unsigned long ctrl = io + 0x206; - /* * Fill in a probe structure first of all */ @@ -250,6 +251,12 @@ static __init int qdi_init_one(unsigned if (IS_ERR(pdev)) return PTR_ERR(pdev); + ret = -ENOMEM; + io_addr = devm_ioport_map(&pdev->dev, io, 8); + ctl_addr = devm_ioport_map(&pdev->dev, io + 0x206, 1); + if (!io_addr || !ctl_addr) + goto fail; + memset(&ae, 0, sizeof(struct ata_probe_ent)); INIT_LIST_HEAD(&ae.node); ae.dev = &pdev->dev; @@ -257,19 +264,21 @@ static __init int qdi_init_one(unsigned if (type == 6580) { ae.port_ops = &qdi6580_port_ops; ae.pio_mask = 0x1F; + ae.port_flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST; } else { ae.port_ops = &qdi6500_port_ops; ae.pio_mask = 0x07; /* Actually PIO3 !IORDY is possible */ + ae.port_flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST | + ATA_FLAG_NO_IORDY; } ae.sht = &qdi_sht; ae.n_ports = 1; ae.irq = irq; ae.irq_flags = 0; - ae.port_flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST; - ae.port[0].cmd_addr = io; - ae.port[0].altstatus_addr = ctrl; - ae.port[0].ctl_addr = ctrl; + ae.port[0].cmd_addr = io_addr; + ae.port[0].altstatus_addr = ctl_addr; + ae.port[0].ctl_addr = ctl_addr; ata_std_ports(&ae.port[0]); /* @@ -282,14 +291,17 @@ static __init int qdi_init_one(unsigned qdi_data[nr_qdi_host].platform_dev = pdev; printk(KERN_INFO DRV_NAME": qd%d at 0x%lx.\n", type, io); - ret = ata_device_add(&ae); - if (ret == 0) { - platform_device_unregister(pdev); - return -ENODEV; - } + + ret = -ENODEV; + if (!ata_device_add(&ae)) + goto fail; qdi_host[nr_qdi_host++] = dev_get_drvdata(&pdev->dev); return 0; + + fail: + platform_device_unregister(pdev); + return ret; } /** @@ -382,7 +394,7 @@ static __exit void qdi_exit(void) int i; for (i = 0; i < nr_qdi_host; i++) { - ata_host_remove(qdi_host[i]); + ata_host_detach(qdi_host[i]); /* Free the control resource. The 6580 dual channel has the resources * claimed as a pair of 2 byte resources so we need no special cases... */ diff --git a/drivers/ata/pata_radisys.c b/drivers/ata/pata_radisys.c index 065541d..0d1e571 100644 --- a/drivers/ata/pata_radisys.c +++ b/drivers/ata/pata_radisys.c @@ -255,14 +255,14 @@ static const struct ata_port_operations .bmdma_status = ata_bmdma_status, .qc_prep = ata_qc_prep, .qc_issue = radisys_qc_issue_prot, - .data_xfer = ata_pio_data_xfer, + .data_xfer = ata_data_xfer, .irq_handler = ata_interrupt, .irq_clear = ata_bmdma_irq_clear, + .irq_on = ata_irq_on, + .irq_ack = ata_irq_ack, .port_start = ata_port_start, - .port_stop = ata_port_stop, - .host_stop = ata_host_stop, }; diff --git a/drivers/ata/pata_rz1000.c b/drivers/ata/pata_rz1000.c index cec0729..71a2bac 100644 --- a/drivers/ata/pata_rz1000.c +++ b/drivers/ata/pata_rz1000.c @@ -115,7 +115,7 @@ static struct ata_port_operations rz1000 .qc_prep = ata_qc_prep, .qc_issue = ata_qc_issue_prot, - .data_xfer = ata_pio_data_xfer, + .data_xfer = ata_data_xfer, .freeze = ata_bmdma_freeze, .thaw = ata_bmdma_thaw, @@ -124,10 +124,10 @@ static struct ata_port_operations rz1000 .irq_handler = ata_interrupt, .irq_clear = ata_bmdma_irq_clear, + .irq_on = ata_irq_on, + .irq_ack = ata_irq_ack, .port_start = ata_port_start, - .port_stop = ata_port_stop, - .host_stop = ata_host_stop }; static int rz1000_fifo_disable(struct pci_dev *pdev) diff --git a/drivers/ata/pata_sc1200.c b/drivers/ata/pata_sc1200.c index a3b35bc..58e42fb 100644 --- a/drivers/ata/pata_sc1200.c +++ b/drivers/ata/pata_sc1200.c @@ -220,14 +220,14 @@ static struct ata_port_operations sc1200 .qc_prep = ata_qc_prep, .qc_issue = sc1200_qc_issue_prot, - .data_xfer = ata_pio_data_xfer, + .data_xfer = ata_data_xfer, .irq_handler = ata_interrupt, .irq_clear = ata_bmdma_irq_clear, + .irq_on = ata_irq_on, + .irq_ack = ata_irq_ack, .port_start = ata_port_start, - .port_stop = ata_port_stop, - .host_stop = ata_host_stop }; /** diff --git a/drivers/ata/pata_serverworks.c b/drivers/ata/pata_serverworks.c index f02b6a3..ad5b43f 100644 --- a/drivers/ata/pata_serverworks.c +++ b/drivers/ata/pata_serverworks.c @@ -218,25 +218,18 @@ static unsigned long serverworks_osb4_fi static unsigned long serverworks_csb_filter(const struct ata_port *ap, struct ata_device *adev, unsigned long mask) { const char *p; - char model_num[40]; - int len, i; + char model_num[ATA_ID_PROD_LEN + 1]; + int i; /* Disk, UDMA */ if (adev->class != ATA_DEV_ATA) return ata_pci_default_filter(ap, adev, mask); /* Actually do need to check */ - ata_id_string(adev->id, model_num, ATA_ID_PROD_OFS, sizeof(model_num)); - /* Precuationary - why not do this in the libata core ?? */ + ata_id_c_string(adev->id, model_num, ATA_ID_PROD, sizeof(model_num)); - len = strlen(model_num); - while ((len > 0) && (model_num[len - 1] == ' ')) { - len--; - model_num[len] = 0; - } - - for(i = 0; (p = csb_bad_ata100[i]) != NULL; i++) { - if (!strncmp(p, model_num, len)) + for (i = 0; (p = csb_bad_ata100[i]) != NULL; i++) { + if (!strcmp(p, model_num)) mask &= ~(0x1F << ATA_SHIFT_UDMA); } return ata_pci_default_filter(ap, adev, mask); @@ -355,14 +348,14 @@ static struct ata_port_operations server .qc_prep = ata_qc_prep, .qc_issue = ata_qc_issue_prot, - .data_xfer = ata_pio_data_xfer, + .data_xfer = ata_data_xfer, .irq_handler = ata_interrupt, .irq_clear = ata_bmdma_irq_clear, + .irq_on = ata_irq_on, + .irq_ack = ata_irq_ack, .port_start = ata_port_start, - .port_stop = ata_port_stop, - .host_stop = ata_host_stop }; static struct ata_port_operations serverworks_csb_port_ops = { @@ -390,14 +383,14 @@ static struct ata_port_operations server .qc_prep = ata_qc_prep, .qc_issue = ata_qc_issue_prot, - .data_xfer = ata_pio_data_xfer, + .data_xfer = ata_data_xfer, .irq_handler = ata_interrupt, .irq_clear = ata_bmdma_irq_clear, + .irq_on = ata_irq_on, + .irq_ack = ata_irq_ack, .port_start = ata_port_start, - .port_stop = ata_port_stop, - .host_stop = ata_host_stop }; static int serverworks_fixup_osb4(struct pci_dev *pdev) @@ -559,7 +552,7 @@ static int serverworks_reinit_one(struct { /* Force master latency timer to 64 PCI clocks */ pci_write_config_byte(pdev, PCI_LATENCY_TIMER, 0x40); - + switch (pdev->device) { case PCI_DEVICE_ID_SERVERWORKS_OSB4IDE: diff --git a/drivers/ata/pata_sil680.c b/drivers/ata/pata_sil680.c index e8dfd8f..ed79fab 100644 --- a/drivers/ata/pata_sil680.c +++ b/drivers/ata/pata_sil680.c @@ -252,14 +252,14 @@ static struct ata_port_operations sil680 .qc_prep = ata_qc_prep, .qc_issue = ata_qc_issue_prot, - .data_xfer = ata_pio_data_xfer, + .data_xfer = ata_data_xfer, .irq_handler = ata_interrupt, .irq_clear = ata_bmdma_irq_clear, + .irq_on = ata_irq_on, + .irq_ack = ata_irq_ack, .port_start = ata_port_start, - .port_stop = ata_port_stop, - .host_stop = ata_host_stop }; /** @@ -270,7 +270,7 @@ static struct ata_port_operations sil680 * is powered up on boot and when we resume in case we resumed from RAM. * Returns the final clock settings. */ - + static u8 sil680_init_chip(struct pci_dev *pdev) { u32 class_rev = 0; diff --git a/drivers/ata/pata_sis.c b/drivers/ata/pata_sis.c index 916cedb..560103d 100644 --- a/drivers/ata/pata_sis.c +++ b/drivers/ata/pata_sis.c @@ -32,7 +32,9 @@ #include #include #include #include +#include "libata.h" +#undef DRV_NAME /* already defined in libata.h, for libata-core */ #define DRV_NAME "pata_sis" #define DRV_VERSION "0.4.5" @@ -43,6 +45,34 @@ struct sis_chipset { up code later */ }; +struct sis_laptop { + u16 device; + u16 subvendor; + u16 subdevice; +}; + +static const struct sis_laptop sis_laptop[] = { + /* devid, subvendor, subdev */ + { 0x5513, 0x1043, 0x1107 }, /* ASUS A6K */ + /* end marker */ + { 0, } +}; + +static int sis_short_ata40(struct pci_dev *dev) +{ + const struct sis_laptop *lap = &sis_laptop[0]; + + while (lap->device) { + if (lap->device == dev->device && + lap->subvendor == dev->subsystem_vendor && + lap->subdevice == dev->subsystem_device) + return 1; + lap++; + } + + return 0; +} + /** * sis_port_base - return PCI configuration base for dev * @adev: device @@ -79,7 +109,7 @@ static int sis_133_pre_reset(struct ata_ /* The top bit of this register is the cable detect bit */ pci_read_config_word(pdev, 0x50 + 2 * ap->port_no, &tmp); - if (tmp & 0x8000) + if ((tmp & 0x8000) && !sis_short_ata40(pdev)) ap->cbl = ATA_CBL_PATA40; else ap->cbl = ATA_CBL_PATA80; @@ -127,7 +157,7 @@ static int sis_66_pre_reset(struct ata_p /* Older chips keep cable detect in bits 4/5 of reg 0x48 */ pci_read_config_byte(pdev, 0x48, &tmp); tmp >>= ap->port_no; - if (tmp & 0x10) + if ((tmp & 0x10) && !sis_short_ata40(pdev)) ap->cbl = ATA_CBL_PATA40; else ap->cbl = ATA_CBL_PATA80; @@ -573,14 +603,14 @@ static const struct ata_port_operations .bmdma_status = ata_bmdma_status, .qc_prep = ata_qc_prep, .qc_issue = ata_qc_issue_prot, - .data_xfer = ata_pio_data_xfer, + .data_xfer = ata_data_xfer, .irq_handler = ata_interrupt, .irq_clear = ata_bmdma_irq_clear, + .irq_on = ata_irq_on, + .irq_ack = ata_irq_ack, .port_start = ata_port_start, - .port_stop = ata_port_stop, - .host_stop = ata_host_stop, }; static const struct ata_port_operations sis_133_early_ops = { @@ -606,14 +636,14 @@ static const struct ata_port_operations .bmdma_status = ata_bmdma_status, .qc_prep = ata_qc_prep, .qc_issue = ata_qc_issue_prot, - .data_xfer = ata_pio_data_xfer, + .data_xfer = ata_data_xfer, .irq_handler = ata_interrupt, .irq_clear = ata_bmdma_irq_clear, + .irq_on = ata_irq_on, + .irq_ack = ata_irq_ack, .port_start = ata_port_start, - .port_stop = ata_port_stop, - .host_stop = ata_host_stop, }; static const struct ata_port_operations sis_100_ops = { @@ -640,14 +670,14 @@ static const struct ata_port_operations .bmdma_status = ata_bmdma_status, .qc_prep = ata_qc_prep, .qc_issue = ata_qc_issue_prot, - .data_xfer = ata_pio_data_xfer, + .data_xfer = ata_data_xfer, .irq_handler = ata_interrupt, .irq_clear = ata_bmdma_irq_clear, + .irq_on = ata_irq_on, + .irq_ack = ata_irq_ack, .port_start = ata_port_start, - .port_stop = ata_port_stop, - .host_stop = ata_host_stop, }; static const struct ata_port_operations sis_66_ops = { @@ -673,14 +703,14 @@ static const struct ata_port_operations .bmdma_status = ata_bmdma_status, .qc_prep = ata_qc_prep, .qc_issue = ata_qc_issue_prot, - .data_xfer = ata_pio_data_xfer, + .data_xfer = ata_data_xfer, .irq_handler = ata_interrupt, .irq_clear = ata_bmdma_irq_clear, + .irq_on = ata_irq_on, + .irq_ack = ata_irq_ack, .port_start = ata_port_start, - .port_stop = ata_port_stop, - .host_stop = ata_host_stop, }; static const struct ata_port_operations sis_old_ops = { @@ -706,14 +736,14 @@ static const struct ata_port_operations .bmdma_status = ata_bmdma_status, .qc_prep = ata_qc_prep, .qc_issue = ata_qc_issue_prot, - .data_xfer = ata_pio_data_xfer, + .data_xfer = ata_data_xfer, .irq_handler = ata_interrupt, .irq_clear = ata_bmdma_irq_clear, + .irq_on = ata_irq_on, + .irq_ack = ata_irq_ack, .port_start = ata_port_start, - .port_stop = ata_port_stop, - .host_stop = ata_host_stop, }; static struct ata_port_info sis_info = { @@ -753,7 +783,7 @@ static struct ata_port_info sis_info100_ .pio_mask = 0x1f, /* pio0-4 */ .port_ops = &sis_66_ops, }; -static struct ata_port_info sis_info133 = { +struct ata_port_info sis_info133 = { .sht = &sis_sht, .flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST, .pio_mask = 0x1f, /* pio0-4 */ @@ -768,6 +798,8 @@ static struct ata_port_info sis_info133_ .port_ops = &sis_133_early_ops, }; +/* Privately shared with the SiS180 SATA driver, not for use elsewhere */ +EXPORT_SYMBOL_GPL(sis_info133); static void sis_fixup(struct pci_dev *pdev, struct sis_chipset *sis) { @@ -847,7 +879,7 @@ static int sis_init_one (struct pci_dev struct sis_chipset *chipset = NULL; static struct sis_chipset sis_chipsets[] = { - + { 0x0968, &sis_info133 }, { 0x0966, &sis_info133 }, { 0x0965, &sis_info133 }, diff --git a/drivers/ata/pata_sl82c105.c b/drivers/ata/pata_sl82c105.c index e94f515..96e890f 100644 --- a/drivers/ata/pata_sl82c105.c +++ b/drivers/ata/pata_sl82c105.c @@ -139,13 +139,13 @@ static void sl82c105_set_dmamode(struct { switch(adev->dma_mode) { case XFER_MW_DMA_0: - sl82c105_configure_piomode(ap, adev, 1); + sl82c105_configure_piomode(ap, adev, 0); break; case XFER_MW_DMA_1: sl82c105_configure_piomode(ap, adev, 3); break; case XFER_MW_DMA_2: - sl82c105_configure_piomode(ap, adev, 3); + sl82c105_configure_piomode(ap, adev, 4); break; default: BUG(); @@ -187,7 +187,9 @@ static void sl82c105_bmdma_start(struct { struct ata_port *ap = qc->ap; + udelay(100); sl82c105_reset_engine(ap); + udelay(100); /* Set the clocks for DMA */ sl82c105_configure_dmamode(ap, qc->dev); @@ -216,6 +218,7 @@ static void sl82c105_bmdma_stop(struct a ata_bmdma_stop(qc); sl82c105_reset_engine(ap); + udelay(100); /* This will redo the initial setup of the DMA device to matching PIO timings */ @@ -262,14 +265,14 @@ static struct ata_port_operations sl82c1 .qc_prep = ata_qc_prep, .qc_issue = ata_qc_issue_prot, - .data_xfer = ata_pio_data_xfer, + .data_xfer = ata_data_xfer, .irq_handler = ata_interrupt, .irq_clear = ata_bmdma_irq_clear, + .irq_on = ata_irq_on, + .irq_ack = ata_irq_ack, .port_start = ata_port_start, - .port_stop = ata_port_stop, - .host_stop = ata_host_stop }; /** diff --git a/drivers/ata/pata_triflex.c b/drivers/ata/pata_triflex.c index a142971..453ab90 100644 --- a/drivers/ata/pata_triflex.c +++ b/drivers/ata/pata_triflex.c @@ -221,14 +221,14 @@ static struct ata_port_operations trifle .qc_prep = ata_qc_prep, .qc_issue = ata_qc_issue_prot, - .data_xfer = ata_pio_data_xfer, + .data_xfer = ata_data_xfer, .irq_handler = ata_interrupt, .irq_clear = ata_bmdma_irq_clear, + .irq_on = ata_irq_on, + .irq_ack = ata_irq_ack, .port_start = ata_port_start, - .port_stop = ata_port_stop, - .host_stop = ata_host_stop }; static int triflex_init_one(struct pci_dev *dev, const struct pci_device_id *id) diff --git a/drivers/ata/pata_via.c b/drivers/ata/pata_via.c index f0b6c3b..220fcd6 100644 --- a/drivers/ata/pata_via.c +++ b/drivers/ata/pata_via.c @@ -334,14 +334,14 @@ static struct ata_port_operations via_po .qc_prep = ata_qc_prep, .qc_issue = ata_qc_issue_prot, - .data_xfer = ata_pio_data_xfer, + .data_xfer = ata_data_xfer, .irq_handler = ata_interrupt, .irq_clear = ata_bmdma_irq_clear, + .irq_on = ata_irq_on, + .irq_ack = ata_irq_ack, .port_start = ata_port_start, - .port_stop = ata_port_stop, - .host_stop = ata_host_stop }; static struct ata_port_operations via_port_ops_noirq = { @@ -369,14 +369,14 @@ static struct ata_port_operations via_po .qc_prep = ata_qc_prep, .qc_issue = ata_qc_issue_prot, - .data_xfer = ata_pio_data_xfer_noirq, + .data_xfer = ata_data_xfer_noirq, .irq_handler = ata_interrupt, .irq_clear = ata_bmdma_irq_clear, + .irq_on = ata_irq_on, + .irq_ack = ata_irq_ack, .port_start = ata_port_start, - .port_stop = ata_port_stop, - .host_stop = ata_host_stop }; /** @@ -391,11 +391,11 @@ static struct ata_port_operations via_po static void via_config_fifo(struct pci_dev *pdev, unsigned int flags) { u8 enable; - + /* 0x40 low bits indicate enabled channels */ pci_read_config_byte(pdev, 0x40 , &enable); enable &= 3; - + if (flags & VIA_SET_FIFO) { static const u8 fifo_setting[4] = {0x00, 0x60, 0x00, 0x20}; u8 fifo; @@ -516,7 +516,7 @@ static int via_init_one(struct pci_dev * /* Initialise the FIFO for the enabled channels. */ via_config_fifo(pdev, config->flags); - + /* Clock set up */ switch(config->flags & VIA_UDMA) { case VIA_UDMA_NONE: @@ -575,7 +575,7 @@ static int via_reinit_one(struct pci_dev u32 timing; struct ata_host *host = dev_get_drvdata(&pdev->dev); const struct via_isa_bridge *config = host->private_data; - + via_config_fifo(pdev, config->flags); if ((config->flags & VIA_UDMA) == VIA_UDMA_66) { @@ -590,7 +590,7 @@ static int via_reinit_one(struct pci_dev timing &= ~0x80008; pci_write_config_dword(pdev, 0x50, timing); } - return ata_pci_device_resume(pdev); + return ata_pci_device_resume(pdev); } static const struct pci_device_id via[] = { diff --git a/drivers/ata/pata_winbond.c b/drivers/ata/pata_winbond.c index 5d1f518..0888b4f 100644 --- a/drivers/ata/pata_winbond.c +++ b/drivers/ata/pata_winbond.c @@ -5,7 +5,7 @@ * Support for the Winbond 83759A when operating in advanced mode. * Multichip mode is not currently supported. */ - + #include #include #include @@ -69,7 +69,7 @@ static void winbond_set_piomode(struct a int timing = 0x88 + (ap->port_no * 4) + (adev->devno * 2); reg = winbond_readcfg(winbond->config, 0x81); - + /* Get the timing data in cycles */ if (reg & 0x40) /* Fast VLB bus, assume 50MHz */ ata_timing_compute(adev, adev->pio_mode, &t, 20000, 1000); @@ -80,9 +80,9 @@ static void winbond_set_piomode(struct a recovery = (FIT(t.recover, 1, 15) + 1) & 0x0F; timing = (active << 4) | recovery; winbond_writecfg(winbond->config, timing, reg); - + /* Load the setup timing */ - + reg = 0x35; if (adev->class != ATA_DEV_ATA) reg |= 0x08; /* FIFO off */ @@ -100,22 +100,24 @@ static void winbond_data_xfer(struct ata if (ata_id_has_dword_io(adev->id)) { if (write_data) - outsl(ap->ioaddr.data_addr, buf, buflen >> 2); + iowrite32_rep(ap->ioaddr.data_addr, buf, buflen >> 2); else - insl(ap->ioaddr.data_addr, buf, buflen >> 2); + ioread32_rep(ap->ioaddr.data_addr, buf, buflen >> 2); if (unlikely(slop)) { u32 pad; if (write_data) { memcpy(&pad, buf + buflen - slop, slop); - outl(le32_to_cpu(pad), ap->ioaddr.data_addr); + pad = le32_to_cpu(pad); + iowrite32(pad, ap->ioaddr.data_addr); } else { - pad = cpu_to_le16(inl(ap->ioaddr.data_addr)); + pad = ioread32(ap->ioaddr.data_addr); + pad = cpu_to_le16(pad); memcpy(buf + buflen - slop, &pad, slop); } } } else - ata_pio_data_xfer(adev, buf, buflen, write_data); + ata_data_xfer(adev, buf, buflen, write_data); } static struct scsi_host_template winbond_sht = { @@ -158,10 +160,10 @@ static struct ata_port_operations winbon .irq_handler = ata_interrupt, .irq_clear = ata_bmdma_irq_clear, + .irq_on = ata_irq_on, + .irq_ack = ata_irq_ack, .port_start = ata_port_start, - .port_stop = ata_port_stop, - .host_stop = ata_host_stop }; /** @@ -194,13 +196,15 @@ static __init int winbond_init_one(unsig winbond_writecfg(port, 0x85, reg); reg = winbond_readcfg(port, 0x81); - + if (!(reg & 0x03)) /* Disabled */ return 0; for (i = 0; i < 2 ; i ++) { + unsigned long cmd_port = 0x1F0 - (0x80 * i); + void __iomem *cmd_addr, *ctl_addr; - if (reg & (1 << i)) { + if (reg & (1 << i)) { /* * Fill in a probe structure first of all */ @@ -209,6 +213,13 @@ static __init int winbond_init_one(unsig if (IS_ERR(pdev)) return PTR_ERR(pdev); + cmd_addr = devm_ioport_map(&pdev->dev, cmd_port, 8); + ctl_addr = devm_ioport_map(&pdev->dev, cmd_port + 0x0206, 1); + if (!cmd_addr || !ctl_addr) { + platform_device_unregister(pdev); + return -ENOMEM; + } + memset(&ae, 0, sizeof(struct ata_probe_ent)); INIT_LIST_HEAD(&ae.node); ae.dev = &pdev->dev; @@ -217,14 +228,14 @@ static __init int winbond_init_one(unsig ae.pio_mask = 0x1F; ae.sht = &winbond_sht; - + ae.n_ports = 1; ae.irq = 14 + i; ae.irq_flags = 0; ae.port_flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST; - ae.port[0].cmd_addr = 0x1F0 - (0x80 * i); - ae.port[0].altstatus_addr = ae.port[0].cmd_addr + 0x0206; - ae.port[0].ctl_addr = ae.port[0].altstatus_addr; + ae.port[0].cmd_addr = cmd_addr; + ae.port[0].altstatus_addr = ctl_addr; + ae.port[0].ctl_addr = ctl_addr; ata_std_ports(&ae.port[0]); /* * Hook in a private data structure per channel @@ -257,7 +268,7 @@ static __init int winbond_init(void) int ct = 0; int i; - + if (probe_winbond == 0) return -ENODEV; @@ -288,7 +299,7 @@ static __exit void winbond_exit(void) int i; for (i = 0; i < nr_winbond_host; i++) { - ata_host_remove(winbond_host[i]); + ata_host_detach(winbond_host[i]); release_region(winbond_data[i].config, 2); platform_device_unregister(winbond_data[i].platform_dev); } diff --git a/drivers/ata/pdc_adma.c b/drivers/ata/pdc_adma.c index 90786d7..857ac23 100644 --- a/drivers/ata/pdc_adma.c +++ b/drivers/ata/pdc_adma.c @@ -39,10 +39,8 @@ #include #include #include #include -#include #include #include -#include #include #define DRV_NAME "pdc_adma" @@ -52,9 +50,15 @@ #define DRV_VERSION "0.04" #define ADMA_ATA_REGS(base,port_no) ((base) + ((port_no) * 0x40)) /* macro to calculate base address for ADMA regs */ -#define ADMA_REGS(base,port_no) ((base) + 0x80 + ((port_no) * 0x20)) +#define ADMA_REGS(base,port_no) ((base) + 0x80 + ((port_no) * 0x20)) + +/* macro to obtain addresses from ata_host */ +#define ADMA_HOST_REGS(host,port_no) \ + ADMA_REGS((host)->iomap[ADMA_MMIO_BAR], port_no) enum { + ADMA_MMIO_BAR = 4, + ADMA_PORTS = 2, ADMA_CPB_BYTES = 40, ADMA_PRD_BYTES = LIBATA_MAX_PRD * 16, @@ -167,9 +171,11 @@ static const struct ata_port_operations .qc_prep = adma_qc_prep, .qc_issue = adma_qc_issue, .eng_timeout = adma_eng_timeout, - .data_xfer = ata_mmio_data_xfer, + .data_xfer = ata_data_xfer, .irq_handler = adma_intr, .irq_clear = adma_irq_clear, + .irq_on = ata_irq_on, + .irq_ack = ata_irq_ack, .port_start = adma_port_start, .port_stop = adma_port_stop, .host_stop = adma_host_stop, @@ -235,11 +241,10 @@ static void adma_reset_engine(void __iom static void adma_reinit_engine(struct ata_port *ap) { struct adma_port_priv *pp = ap->private_data; - void __iomem *mmio_base = ap->host->mmio_base; - void __iomem *chan = ADMA_REGS(mmio_base, ap->port_no); + void __iomem *chan = ADMA_HOST_REGS(ap->host, ap->port_no); /* mask/clear ATA interrupts */ - writeb(ATA_NIEN, (void __iomem *)ap->ioaddr.ctl_addr); + writeb(ATA_NIEN, ap->ioaddr.ctl_addr); ata_check_status(ap); /* reset the ADMA engine */ @@ -263,7 +268,7 @@ static void adma_reinit_engine(struct at static inline void adma_enter_reg_mode(struct ata_port *ap) { - void __iomem *chan = ADMA_REGS(ap->host->mmio_base, ap->port_no); + void __iomem *chan = ADMA_HOST_REGS(ap->host, ap->port_no); writew(aPIOMD4, chan + ADMA_CONTROL); readb(chan + ADMA_STATUS); /* flush */ @@ -410,7 +415,7 @@ #endif static inline void adma_packet_start(struct ata_queued_cmd *qc) { struct ata_port *ap = qc->ap; - void __iomem *chan = ADMA_REGS(ap->host->mmio_base, ap->port_no); + void __iomem *chan = ADMA_HOST_REGS(ap->host, ap->port_no); VPRINTK("ENTER, ap %p\n", ap); @@ -443,13 +448,12 @@ static unsigned int adma_qc_issue(struct static inline unsigned int adma_intr_pkt(struct ata_host *host) { unsigned int handled = 0, port_no; - u8 __iomem *mmio_base = host->mmio_base; for (port_no = 0; port_no < host->n_ports; ++port_no) { struct ata_port *ap = host->ports[port_no]; struct adma_port_priv *pp; struct ata_queued_cmd *qc; - void __iomem *chan = ADMA_REGS(mmio_base, port_no); + void __iomem *chan = ADMA_HOST_REGS(host, port_no); u8 status = readb(chan + ADMA_STATUS); if (status == 0) @@ -523,7 +527,7 @@ static irqreturn_t adma_intr(int irq, vo return IRQ_RETVAL(handled); } -static void adma_ata_setup_port(struct ata_ioports *port, unsigned long base) +static void adma_ata_setup_port(struct ata_ioports *port, void __iomem *base) { port->cmd_addr = port->data_addr = base + 0x000; @@ -550,48 +554,28 @@ static int adma_port_start(struct ata_po if (rc) return rc; adma_enter_reg_mode(ap); - rc = -ENOMEM; - pp = kzalloc(sizeof(*pp), GFP_KERNEL); + pp = devm_kzalloc(dev, sizeof(*pp), GFP_KERNEL); if (!pp) - goto err_out; - pp->pkt = dma_alloc_coherent(dev, ADMA_PKT_BYTES, &pp->pkt_dma, - GFP_KERNEL); + return -ENOMEM; + pp->pkt = dmam_alloc_coherent(dev, ADMA_PKT_BYTES, &pp->pkt_dma, + GFP_KERNEL); if (!pp->pkt) - goto err_out_kfree; + return -ENOMEM; /* paranoia? */ if ((pp->pkt_dma & 7) != 0) { printk("bad alignment for pp->pkt_dma: %08x\n", (u32)pp->pkt_dma); - dma_free_coherent(dev, ADMA_PKT_BYTES, - pp->pkt, pp->pkt_dma); - goto err_out_kfree; + return -ENOMEM; } memset(pp->pkt, 0, ADMA_PKT_BYTES); ap->private_data = pp; adma_reinit_engine(ap); return 0; - -err_out_kfree: - kfree(pp); -err_out: - ata_port_stop(ap); - return rc; } static void adma_port_stop(struct ata_port *ap) { - struct device *dev = ap->host->dev; - struct adma_port_priv *pp = ap->private_data; - - adma_reset_engine(ADMA_REGS(ap->host->mmio_base, ap->port_no)); - if (pp != NULL) { - ap->private_data = NULL; - if (pp->pkt != NULL) - dma_free_coherent(dev, ADMA_PKT_BYTES, - pp->pkt, pp->pkt_dma); - kfree(pp); - } - ata_port_stop(ap); + adma_reset_engine(ADMA_HOST_REGS(ap->host, ap->port_no)); } static void adma_host_stop(struct ata_host *host) @@ -599,16 +583,14 @@ static void adma_host_stop(struct ata_ho unsigned int port_no; for (port_no = 0; port_no < ADMA_PORTS; ++port_no) - adma_reset_engine(ADMA_REGS(host->mmio_base, port_no)); - - ata_pci_host_stop(host); + adma_reset_engine(ADMA_HOST_REGS(host, port_no)); } static void adma_host_init(unsigned int chip_id, struct ata_probe_ent *probe_ent) { unsigned int port_no; - void __iomem *mmio_base = probe_ent->mmio_base; + void __iomem *mmio_base = probe_ent->iomap[ADMA_MMIO_BAR]; /* enable/lock aGO operation */ writeb(7, mmio_base + ADMA_MODE_LOCK); @@ -638,7 +620,7 @@ static int adma_set_dma_masks(struct pci } static int adma_ata_init_one(struct pci_dev *pdev, - const struct pci_device_id *ent) + const struct pci_device_id *ent) { static int printed_version; struct ata_probe_ent *probe_ent = NULL; @@ -649,34 +631,25 @@ static int adma_ata_init_one(struct pci_ if (!printed_version++) dev_printk(KERN_DEBUG, &pdev->dev, "version " DRV_VERSION "\n"); - rc = pci_enable_device(pdev); + rc = pcim_enable_device(pdev); if (rc) return rc; - rc = pci_request_regions(pdev, DRV_NAME); - if (rc) - goto err_out; - - if ((pci_resource_flags(pdev, 4) & IORESOURCE_MEM) == 0) { - rc = -ENODEV; - goto err_out_regions; - } + if ((pci_resource_flags(pdev, 4) & IORESOURCE_MEM) == 0) + return -ENODEV; - mmio_base = pci_iomap(pdev, 4, 0); - if (mmio_base == NULL) { - rc = -ENOMEM; - goto err_out_regions; - } + rc = pcim_iomap_regions(pdev, 1 << ADMA_MMIO_BAR, DRV_NAME); + if (rc) + return rc; + mmio_base = pcim_iomap_table(pdev)[ADMA_MMIO_BAR]; rc = adma_set_dma_masks(pdev, mmio_base); if (rc) - goto err_out_iounmap; + return rc; - probe_ent = kzalloc(sizeof(*probe_ent), GFP_KERNEL); - if (probe_ent == NULL) { - rc = -ENOMEM; - goto err_out_iounmap; - } + probe_ent = devm_kzalloc(&pdev->dev, sizeof(*probe_ent), GFP_KERNEL); + if (probe_ent == NULL) + return -ENOMEM; probe_ent->dev = pci_dev_to_dev(pdev); INIT_LIST_HEAD(&probe_ent->node); @@ -690,12 +663,12 @@ static int adma_ata_init_one(struct pci_ probe_ent->irq = pdev->irq; probe_ent->irq_flags = IRQF_SHARED; - probe_ent->mmio_base = mmio_base; probe_ent->n_ports = ADMA_PORTS; + probe_ent->iomap = pcim_iomap_table(pdev); for (port_no = 0; port_no < probe_ent->n_ports; ++port_no) { adma_ata_setup_port(&probe_ent->port[port_no], - ADMA_ATA_REGS((unsigned long)mmio_base, port_no)); + ADMA_ATA_REGS(mmio_base, port_no)); } pci_set_master(pdev); @@ -703,19 +676,11 @@ static int adma_ata_init_one(struct pci_ /* initialize adapter */ adma_host_init(board_idx, probe_ent); - rc = ata_device_add(probe_ent); - kfree(probe_ent); - if (rc != ADMA_PORTS) - goto err_out_iounmap; - return 0; + if (!ata_device_add(probe_ent)) + return -ENODEV; -err_out_iounmap: - pci_iounmap(pdev, mmio_base); -err_out_regions: - pci_release_regions(pdev); -err_out: - pci_disable_device(pdev); - return rc; + devm_kfree(&pdev->dev, probe_ent); + return 0; } static int __init adma_ata_init(void) diff --git a/drivers/ata/sata_inic162x.c b/drivers/ata/sata_inic162x.c new file mode 100644 index 0000000..31b636f --- /dev/null +++ b/drivers/ata/sata_inic162x.c @@ -0,0 +1,781 @@ +/* + * sata_inic162x.c - Driver for Initio 162x SATA controllers + * + * Copyright 2006 SUSE Linux Products GmbH + * Copyright 2006 Tejun Heo + * + * This file is released under GPL v2. + * + * This controller is eccentric and easily locks up if something isn't + * right. Documentation is available at initio's website but it only + * documents registers (not programming model). + * + * - ATA disks work. + * - Hotplug works. + * - ATAPI read works but burning doesn't. This thing is really + * peculiar about ATAPI and I couldn't figure out how ATAPI PIO and + * ATAPI DMA WRITE should be programmed. If you've got a clue, be + * my guest. + * - Both STR and STD work. + */ + +#include +#include +#include +#include +#include +#include +#include + +#define DRV_NAME "sata_inic162x" +#define DRV_VERSION "0.1" + +enum { + MMIO_BAR = 5, + + NR_PORTS = 2, + + HOST_CTL = 0x7c, + HOST_STAT = 0x7e, + HOST_IRQ_STAT = 0xbc, + HOST_IRQ_MASK = 0xbe, + + PORT_SIZE = 0x40, + + /* registers for ATA TF operation */ + PORT_TF = 0x00, + PORT_ALT_STAT = 0x08, + PORT_IRQ_STAT = 0x09, + PORT_IRQ_MASK = 0x0a, + PORT_PRD_CTL = 0x0b, + PORT_PRD_ADDR = 0x0c, + PORT_PRD_XFERLEN = 0x10, + + /* IDMA register */ + PORT_IDMA_CTL = 0x14, + + PORT_SCR = 0x20, + + /* HOST_CTL bits */ + HCTL_IRQOFF = (1 << 8), /* global IRQ off */ + HCTL_PWRDWN = (1 << 13), /* power down PHYs */ + HCTL_SOFTRST = (1 << 13), /* global reset (no phy reset) */ + HCTL_RPGSEL = (1 << 15), /* register page select */ + + HCTL_KNOWN_BITS = HCTL_IRQOFF | HCTL_PWRDWN | HCTL_SOFTRST | + HCTL_RPGSEL, + + /* HOST_IRQ_(STAT|MASK) bits */ + HIRQ_PORT0 = (1 << 0), + HIRQ_PORT1 = (1 << 1), + HIRQ_SOFT = (1 << 14), + HIRQ_GLOBAL = (1 << 15), /* STAT only */ + + /* PORT_IRQ_(STAT|MASK) bits */ + PIRQ_OFFLINE = (1 << 0), /* device unplugged */ + PIRQ_ONLINE = (1 << 1), /* device plugged */ + PIRQ_COMPLETE = (1 << 2), /* completion interrupt */ + PIRQ_FATAL = (1 << 3), /* fatal error */ + PIRQ_ATA = (1 << 4), /* ATA interrupt */ + PIRQ_REPLY = (1 << 5), /* reply FIFO not empty */ + PIRQ_PENDING = (1 << 7), /* port IRQ pending (STAT only) */ + + PIRQ_ERR = PIRQ_OFFLINE | PIRQ_ONLINE | PIRQ_FATAL, + + PIRQ_MASK_DMA_READ = PIRQ_REPLY | PIRQ_ATA, + PIRQ_MASK_OTHER = PIRQ_REPLY | PIRQ_COMPLETE, + PIRQ_MASK_FREEZE = 0xff, + + /* PORT_PRD_CTL bits */ + PRD_CTL_START = (1 << 0), + PRD_CTL_WR = (1 << 3), + PRD_CTL_DMAEN = (1 << 7), /* DMA enable */ + + /* PORT_IDMA_CTL bits */ + IDMA_CTL_RST_ATA = (1 << 2), /* hardreset ATA bus */ + IDMA_CTL_RST_IDMA = (1 << 5), /* reset IDMA machinary */ + IDMA_CTL_GO = (1 << 7), /* IDMA mode go */ + IDMA_CTL_ATA_NIEN = (1 << 8), /* ATA IRQ disable */ +}; + +struct inic_host_priv { + u16 cached_hctl; +}; + +struct inic_port_priv { + u8 dfl_prdctl; + u8 cached_prdctl; + u8 cached_pirq_mask; +}; + +static int inic_slave_config(struct scsi_device *sdev) +{ + /* This controller is braindamaged. dma_boundary is 0xffff + * like others but it will lock up the whole machine HARD if + * 65536 byte PRD entry is fed. Reduce maximum segment size. + */ + blk_queue_max_segment_size(sdev->request_queue, 65536 - 512); + + return ata_scsi_slave_config(sdev); +} + +static struct scsi_host_template inic_sht = { + .module = THIS_MODULE, + .name = DRV_NAME, + .ioctl = ata_scsi_ioctl, + .queuecommand = ata_scsi_queuecmd, + .can_queue = ATA_DEF_QUEUE, + .this_id = ATA_SHT_THIS_ID, + .sg_tablesize = LIBATA_MAX_PRD, + .cmd_per_lun = ATA_SHT_CMD_PER_LUN, + .emulated = ATA_SHT_EMULATED, + .use_clustering = ATA_SHT_USE_CLUSTERING, + .proc_name = DRV_NAME, + .dma_boundary = ATA_DMA_BOUNDARY, + .slave_configure = inic_slave_config, + .slave_destroy = ata_scsi_slave_destroy, + .bios_param = ata_std_bios_param, + .suspend = ata_scsi_device_suspend, + .resume = ata_scsi_device_resume, +}; + +static const int scr_map[] = { + [SCR_STATUS] = 0, + [SCR_ERROR] = 1, + [SCR_CONTROL] = 2, +}; + +static void __iomem * inic_port_base(struct ata_port *ap) +{ + return ap->host->iomap[MMIO_BAR] + ap->port_no * PORT_SIZE; +} + +static void __inic_set_pirq_mask(struct ata_port *ap, u8 mask) +{ + void __iomem *port_base = inic_port_base(ap); + struct inic_port_priv *pp = ap->private_data; + + writeb(mask, port_base + PORT_IRQ_MASK); + pp->cached_pirq_mask = mask; +} + +static void inic_set_pirq_mask(struct ata_port *ap, u8 mask) +{ + struct inic_port_priv *pp = ap->private_data; + + if (pp->cached_pirq_mask != mask) + __inic_set_pirq_mask(ap, mask); +} + +static void inic_reset_port(void __iomem *port_base) +{ + void __iomem *idma_ctl = port_base + PORT_IDMA_CTL; + u16 ctl; + + ctl = readw(idma_ctl); + ctl &= ~(IDMA_CTL_RST_IDMA | IDMA_CTL_ATA_NIEN | IDMA_CTL_GO); + + /* mask IRQ and assert reset */ + writew(ctl | IDMA_CTL_RST_IDMA | IDMA_CTL_ATA_NIEN, idma_ctl); + readw(idma_ctl); /* flush */ + + /* give it some time */ + msleep(1); + + /* release reset */ + writew(ctl | IDMA_CTL_ATA_NIEN, idma_ctl); + + /* clear irq */ + writeb(0xff, port_base + PORT_IRQ_STAT); + + /* reenable ATA IRQ, turn off IDMA mode */ + writew(ctl, idma_ctl); +} + +static u32 inic_scr_read(struct ata_port *ap, unsigned sc_reg) +{ + void __iomem *scr_addr = (void __iomem *)ap->ioaddr.scr_addr; + void __iomem *addr; + u32 val; + + if (unlikely(sc_reg >= ARRAY_SIZE(scr_map))) + return 0xffffffffU; + + addr = scr_addr + scr_map[sc_reg] * 4; + val = readl(scr_addr + scr_map[sc_reg] * 4); + + /* this controller has stuck DIAG.N, ignore it */ + if (sc_reg == SCR_ERROR) + val &= ~SERR_PHYRDY_CHG; + return val; +} + +static void inic_scr_write(struct ata_port *ap, unsigned sc_reg, u32 val) +{ + void __iomem *scr_addr = (void __iomem *)ap->ioaddr.scr_addr; + void __iomem *addr; + + if (unlikely(sc_reg >= ARRAY_SIZE(scr_map))) + return; + + addr = scr_addr + scr_map[sc_reg] * 4; + writel(val, scr_addr + scr_map[sc_reg] * 4); +} + +/* + * In TF mode, inic162x is very similar to SFF device. TF registers + * function the same. DMA engine behaves similary using the same PRD + * format as BMDMA but different command register, interrupt and event + * notification methods are used. The following inic_bmdma_*() + * functions do the impedance matching. + */ +static void inic_bmdma_setup(struct ata_queued_cmd *qc) +{ + struct ata_port *ap = qc->ap; + struct inic_port_priv *pp = ap->private_data; + void __iomem *port_base = inic_port_base(ap); + int rw = qc->tf.flags & ATA_TFLAG_WRITE; + + /* make sure device sees PRD table writes */ + wmb(); + + /* load transfer length */ + writel(qc->nbytes, port_base + PORT_PRD_XFERLEN); + + /* turn on DMA and specify data direction */ + pp->cached_prdctl = pp->dfl_prdctl | PRD_CTL_DMAEN; + if (!rw) + pp->cached_prdctl |= PRD_CTL_WR; + writeb(pp->cached_prdctl, port_base + PORT_PRD_CTL); + + /* issue r/w command */ + ap->ops->exec_command(ap, &qc->tf); +} + +static void inic_bmdma_start(struct ata_queued_cmd *qc) +{ + struct ata_port *ap = qc->ap; + struct inic_port_priv *pp = ap->private_data; + void __iomem *port_base = inic_port_base(ap); + + /* start host DMA transaction */ + pp->cached_prdctl |= PRD_CTL_START; + writeb(pp->cached_prdctl, port_base + PORT_PRD_CTL); +} + +static void inic_bmdma_stop(struct ata_queued_cmd *qc) +{ + struct ata_port *ap = qc->ap; + struct inic_port_priv *pp = ap->private_data; + void __iomem *port_base = inic_port_base(ap); + + /* stop DMA engine */ + writeb(pp->dfl_prdctl, port_base + PORT_PRD_CTL); +} + +static u8 inic_bmdma_status(struct ata_port *ap) +{ + /* event is already verified by the interrupt handler */ + return ATA_DMA_INTR; +} + +static void inic_irq_clear(struct ata_port *ap) +{ + /* noop */ +} + +static void inic_host_intr(struct ata_port *ap) +{ + void __iomem *port_base = inic_port_base(ap); + struct ata_eh_info *ehi = &ap->eh_info; + u8 irq_stat; + + /* fetch and clear irq */ + irq_stat = readb(port_base + PORT_IRQ_STAT); + writeb(irq_stat, port_base + PORT_IRQ_STAT); + + if (likely(!(irq_stat & PIRQ_ERR))) { + struct ata_queued_cmd *qc = ata_qc_from_tag(ap, ap->active_tag); + + if (unlikely(!qc || (qc->tf.flags & ATA_TFLAG_POLLING))) { + ata_chk_status(ap); /* clear ATA interrupt */ + return; + } + + if (likely(ata_host_intr(ap, qc))) + return; + + ata_chk_status(ap); /* clear ATA interrupt */ + ata_port_printk(ap, KERN_WARNING, "unhandled " + "interrupt, irq_stat=%x\n", irq_stat); + return; + } + + /* error */ + ata_ehi_push_desc(ehi, "irq_stat=0x%x", irq_stat); + + if (irq_stat & (PIRQ_OFFLINE | PIRQ_ONLINE)) { + ata_ehi_hotplugged(ehi); + ata_port_freeze(ap); + } else + ata_port_abort(ap); +} + +static irqreturn_t inic_interrupt(int irq, void *dev_instance) +{ + struct ata_host *host = dev_instance; + void __iomem *mmio_base = host->iomap[MMIO_BAR]; + u16 host_irq_stat; + int i, handled = 0;; + + host_irq_stat = readw(mmio_base + HOST_IRQ_STAT); + + if (unlikely(!(host_irq_stat & HIRQ_GLOBAL))) + goto out; + + spin_lock(&host->lock); + + for (i = 0; i < NR_PORTS; i++) { + struct ata_port *ap = host->ports[i]; + + if (!(host_irq_stat & (HIRQ_PORT0 << i))) + continue; + + if (likely(ap && !(ap->flags & ATA_FLAG_DISABLED))) { + inic_host_intr(ap); + handled++; + } else { + if (ata_ratelimit()) + dev_printk(KERN_ERR, host->dev, "interrupt " + "from disabled port %d (0x%x)\n", + i, host_irq_stat); + } + } + + spin_unlock(&host->lock); + + out: + return IRQ_RETVAL(handled); +} + +static unsigned int inic_qc_issue(struct ata_queued_cmd *qc) +{ + struct ata_port *ap = qc->ap; + + /* ATA IRQ doesn't wait for DMA transfer completion and vice + * versa. Mask IRQ selectively to detect command completion. + * Without it, ATA DMA read command can cause data corruption. + * + * Something similar might be needed for ATAPI writes. I + * tried a lot of combinations but couldn't find the solution. + */ + if (qc->tf.protocol == ATA_PROT_DMA && + !(qc->tf.flags & ATA_TFLAG_WRITE)) + inic_set_pirq_mask(ap, PIRQ_MASK_DMA_READ); + else + inic_set_pirq_mask(ap, PIRQ_MASK_OTHER); + + /* Issuing a command to yet uninitialized port locks up the + * controller. Most of the time, this happens for the first + * command after reset which are ATA and ATAPI IDENTIFYs. + * Fast fail if stat is 0x7f or 0xff for those commands. + */ + if (unlikely(qc->tf.command == ATA_CMD_ID_ATA || + qc->tf.command == ATA_CMD_ID_ATAPI)) { + u8 stat = ata_chk_status(ap); + if (stat == 0x7f || stat == 0xff) + return AC_ERR_HSM; + } + + return ata_qc_issue_prot(qc); +} + +static void inic_freeze(struct ata_port *ap) +{ + void __iomem *port_base = inic_port_base(ap); + + __inic_set_pirq_mask(ap, PIRQ_MASK_FREEZE); + + ata_chk_status(ap); + writeb(0xff, port_base + PORT_IRQ_STAT); + + readb(port_base + PORT_IRQ_STAT); /* flush */ +} + +static void inic_thaw(struct ata_port *ap) +{ + void __iomem *port_base = inic_port_base(ap); + + ata_chk_status(ap); + writeb(0xff, port_base + PORT_IRQ_STAT); + + __inic_set_pirq_mask(ap, PIRQ_MASK_OTHER); + + readb(port_base + PORT_IRQ_STAT); /* flush */ +} + +/* + * SRST and SControl hardreset don't give valid signature on this + * controller. Only controller specific hardreset mechanism works. + */ +static int inic_hardreset(struct ata_port *ap, unsigned int *class) +{ + void __iomem *port_base = inic_port_base(ap); + void __iomem *idma_ctl = port_base + PORT_IDMA_CTL; + const unsigned long *timing = sata_ehc_deb_timing(&ap->eh_context); + u16 val; + int rc; + + /* hammer it into sane state */ + inic_reset_port(port_base); + + val = readw(idma_ctl); + writew(val | IDMA_CTL_RST_ATA, idma_ctl); + readw(idma_ctl); /* flush */ + msleep(1); + writew(val & ~IDMA_CTL_RST_ATA, idma_ctl); + + rc = sata_phy_resume(ap, timing); + if (rc) { + ata_port_printk(ap, KERN_WARNING, "failed to resume " + "link after reset (errno=%d)\n", rc); + return rc; + } + + *class = ATA_DEV_NONE; + if (ata_port_online(ap)) { + struct ata_taskfile tf; + + /* wait a while before checking status */ + msleep(150); + + if (ata_busy_sleep(ap, ATA_TMOUT_BOOT_QUICK, ATA_TMOUT_BOOT)) { + ata_port_printk(ap, KERN_WARNING, + "device busy after hardreset\n"); + return -EIO; + } + + ata_tf_read(ap, &tf); + *class = ata_dev_classify(&tf); + if (*class == ATA_DEV_UNKNOWN) + *class = ATA_DEV_NONE; + } + + return 0; +} + +static void inic_error_handler(struct ata_port *ap) +{ + void __iomem *port_base = inic_port_base(ap); + struct inic_port_priv *pp = ap->private_data; + unsigned long flags; + + /* reset PIO HSM and stop DMA engine */ + inic_reset_port(port_base); + + spin_lock_irqsave(ap->lock, flags); + ap->hsm_task_state = HSM_ST_IDLE; + writeb(pp->dfl_prdctl, port_base + PORT_PRD_CTL); + spin_unlock_irqrestore(ap->lock, flags); + + /* PIO and DMA engines have been stopped, perform recovery */ + ata_do_eh(ap, ata_std_prereset, NULL, inic_hardreset, + ata_std_postreset); +} + +static void inic_post_internal_cmd(struct ata_queued_cmd *qc) +{ + /* make DMA engine forget about the failed command */ + if (qc->err_mask) + inic_reset_port(inic_port_base(qc->ap)); +} + +static void inic_dev_config(struct ata_port *ap, struct ata_device *dev) +{ + /* inic can only handle upto LBA28 max sectors */ + if (dev->max_sectors > ATA_MAX_SECTORS) + dev->max_sectors = ATA_MAX_SECTORS; +} + +static void init_port(struct ata_port *ap) +{ + void __iomem *port_base = inic_port_base(ap); + + /* Setup PRD address */ + writel(ap->prd_dma, port_base + PORT_PRD_ADDR); +} + +static int inic_port_resume(struct ata_port *ap) +{ + init_port(ap); + return 0; +} + +static int inic_port_start(struct ata_port *ap) +{ + void __iomem *port_base = inic_port_base(ap); + struct inic_port_priv *pp; + u8 tmp; + int rc; + + /* alloc and initialize private data */ + pp = devm_kzalloc(ap->host->dev, sizeof(*pp), GFP_KERNEL); + if (!pp) + return -ENOMEM; + ap->private_data = pp; + + /* default PRD_CTL value, DMAEN, WR and START off */ + tmp = readb(port_base + PORT_PRD_CTL); + tmp &= ~(PRD_CTL_DMAEN | PRD_CTL_WR | PRD_CTL_START); + pp->dfl_prdctl = tmp; + + /* Alloc resources */ + rc = ata_port_start(ap); + if (rc) { + kfree(pp); + return rc; + } + + init_port(ap); + + return 0; +} + +static struct ata_port_operations inic_port_ops = { + .port_disable = ata_port_disable, + .tf_load = ata_tf_load, + .tf_read = ata_tf_read, + .check_status = ata_check_status, + .exec_command = ata_exec_command, + .dev_select = ata_std_dev_select, + + .scr_read = inic_scr_read, + .scr_write = inic_scr_write, + + .bmdma_setup = inic_bmdma_setup, + .bmdma_start = inic_bmdma_start, + .bmdma_stop = inic_bmdma_stop, + .bmdma_status = inic_bmdma_status, + + .irq_handler = inic_interrupt, + .irq_clear = inic_irq_clear, + .irq_on = ata_irq_on, + .irq_ack = ata_irq_ack, + + .qc_prep = ata_qc_prep, + .qc_issue = inic_qc_issue, + .data_xfer = ata_data_xfer, + + .freeze = inic_freeze, + .thaw = inic_thaw, + .error_handler = inic_error_handler, + .post_internal_cmd = inic_post_internal_cmd, + .dev_config = inic_dev_config, + + .port_resume = inic_port_resume, + + .port_start = inic_port_start, +}; + +static struct ata_port_info inic_port_info = { + .sht = &inic_sht, + /* For some reason, ATA_PROT_ATAPI is broken on this + * controller, and no, PIO_POLLING does't fix it. It somehow + * manages to report the wrong ireason and ignoring ireason + * results in machine lock up. Tell libata to always prefer + * DMA. + */ + .flags = ATA_FLAG_SATA | ATA_FLAG_PIO_DMA, + .pio_mask = 0x1f, /* pio0-4 */ + .mwdma_mask = 0x07, /* mwdma0-2 */ + .udma_mask = 0x7f, /* udma0-6 */ + .port_ops = &inic_port_ops +}; + +static int init_controller(void __iomem *mmio_base, u16 hctl) +{ + int i; + u16 val; + + hctl &= ~HCTL_KNOWN_BITS; + + /* Soft reset whole controller. Spec says reset duration is 3 + * PCI clocks, be generous and give it 10ms. + */ + writew(hctl | HCTL_SOFTRST, mmio_base + HOST_CTL); + readw(mmio_base + HOST_CTL); /* flush */ + + for (i = 0; i < 10; i++) { + msleep(1); + val = readw(mmio_base + HOST_CTL); + if (!(val & HCTL_SOFTRST)) + break; + } + + if (val & HCTL_SOFTRST) + return -EIO; + + /* mask all interrupts and reset ports */ + for (i = 0; i < NR_PORTS; i++) { + void __iomem *port_base = mmio_base + i * PORT_SIZE; + + writeb(0xff, port_base + PORT_IRQ_MASK); + inic_reset_port(port_base); + } + + /* port IRQ is masked now, unmask global IRQ */ + writew(hctl & ~HCTL_IRQOFF, mmio_base + HOST_CTL); + val = readw(mmio_base + HOST_IRQ_MASK); + val &= ~(HIRQ_PORT0 | HIRQ_PORT1); + writew(val, mmio_base + HOST_IRQ_MASK); + + return 0; +} + +static int inic_pci_device_resume(struct pci_dev *pdev) +{ + struct ata_host *host = dev_get_drvdata(&pdev->dev); + struct inic_host_priv *hpriv = host->private_data; + void __iomem *mmio_base = host->iomap[MMIO_BAR]; + int rc; + + ata_pci_device_do_resume(pdev); + + if (pdev->dev.power.power_state.event == PM_EVENT_SUSPEND) { + printk("XXX\n"); + rc = init_controller(mmio_base, hpriv->cached_hctl); + if (rc) + return rc; + } + + ata_host_resume(host); + + return 0; +} + +static int inic_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) +{ + static int printed_version; + struct ata_port_info *pinfo = &inic_port_info; + struct ata_probe_ent *probe_ent; + struct inic_host_priv *hpriv; + void __iomem * const *iomap; + int i, rc; + + if (!printed_version++) + dev_printk(KERN_DEBUG, &pdev->dev, "version " DRV_VERSION "\n"); + + rc = pcim_enable_device(pdev); + if (rc) + return rc; + + rc = pci_request_regions(pdev, DRV_NAME); + if (rc) + return rc; + + rc = pcim_iomap_regions(pdev, 0x3f, DRV_NAME); + if (rc) + return rc; + iomap = pcim_iomap_table(pdev); + + /* Set dma_mask. This devices doesn't support 64bit addressing. */ + rc = pci_set_dma_mask(pdev, DMA_32BIT_MASK); + if (rc) { + dev_printk(KERN_ERR, &pdev->dev, + "32-bit DMA enable failed\n"); + return rc; + } + + rc = pci_set_consistent_dma_mask(pdev, DMA_32BIT_MASK); + if (rc) { + dev_printk(KERN_ERR, &pdev->dev, + "32-bit consistent DMA enable failed\n"); + return rc; + } + + probe_ent = devm_kzalloc(&pdev->dev, sizeof(*probe_ent), GFP_KERNEL); + hpriv = devm_kzalloc(&pdev->dev, sizeof(*hpriv), GFP_KERNEL); + if (!probe_ent || !hpriv) + return -ENOMEM; + + probe_ent->dev = &pdev->dev; + INIT_LIST_HEAD(&probe_ent->node); + + probe_ent->sht = pinfo->sht; + probe_ent->port_flags = pinfo->flags; + probe_ent->pio_mask = pinfo->pio_mask; + probe_ent->mwdma_mask = pinfo->mwdma_mask; + probe_ent->udma_mask = pinfo->udma_mask; + probe_ent->port_ops = pinfo->port_ops; + probe_ent->n_ports = NR_PORTS; + + probe_ent->irq = pdev->irq; + probe_ent->irq_flags = IRQF_SHARED; + + probe_ent->iomap = iomap; + + for (i = 0; i < NR_PORTS; i++) { + struct ata_ioports *port = &probe_ent->port[i]; + void __iomem *port_base = iomap[MMIO_BAR] + i * PORT_SIZE; + + port->cmd_addr = iomap[2 * i]; + port->altstatus_addr = + port->ctl_addr = (void __iomem *) + ((unsigned long)iomap[2 * i + 1] | ATA_PCI_CTL_OFS); + port->scr_addr = port_base + PORT_SCR; + + ata_std_ports(port); + } + + probe_ent->private_data = hpriv; + hpriv->cached_hctl = readw(iomap[MMIO_BAR] + HOST_CTL); + + rc = init_controller(iomap[MMIO_BAR], hpriv->cached_hctl); + if (rc) { + dev_printk(KERN_ERR, &pdev->dev, + "failed to initialize controller\n"); + return rc; + } + + pci_set_master(pdev); + + if (!ata_device_add(probe_ent)) + return -ENODEV; + + devm_kfree(&pdev->dev, probe_ent); + + return 0; +} + +static const struct pci_device_id inic_pci_tbl[] = { + { PCI_VDEVICE(INIT, 0x1622), }, + { }, +}; + +static struct pci_driver inic_pci_driver = { + .name = DRV_NAME, + .id_table = inic_pci_tbl, + .suspend = ata_pci_device_suspend, + .resume = inic_pci_device_resume, + .probe = inic_init_one, + .remove = ata_pci_remove_one, +}; + +static int __init inic_init(void) +{ + return pci_register_driver(&inic_pci_driver); +} + +static void __exit inic_exit(void) +{ + pci_unregister_driver(&inic_pci_driver); +} + +MODULE_AUTHOR("Tejun Heo"); +MODULE_DESCRIPTION("low-level driver for Initio 162x SATA"); +MODULE_LICENSE("GPL v2"); +MODULE_DEVICE_TABLE(pci, inic_pci_tbl); +MODULE_VERSION(DRV_VERSION); + +module_init(inic_init); +module_exit(inic_exit); diff --git a/drivers/ata/sata_mv.c b/drivers/ata/sata_mv.c index aae0b52..d689df5 100644 --- a/drivers/ata/sata_mv.c +++ b/drivers/ata/sata_mv.c @@ -28,13 +28,11 @@ #include #include #include #include -#include #include #include #include #include #include -#include #define DRV_NAME "sata_mv" #define DRV_VERSION "0.7" @@ -342,7 +340,6 @@ static u32 mv5_scr_read(struct ata_port static void mv5_scr_write(struct ata_port *ap, unsigned int sc_reg_in, u32 val); static void mv_phy_reset(struct ata_port *ap); static void __mv_phy_reset(struct ata_port *ap, int can_sleep); -static void mv_host_stop(struct ata_host *host); static int mv_port_start(struct ata_port *ap); static void mv_port_stop(struct ata_port *ap); static void mv_qc_prep(struct ata_queued_cmd *qc); @@ -406,19 +403,20 @@ static const struct ata_port_operations .qc_prep = mv_qc_prep, .qc_issue = mv_qc_issue, - .data_xfer = ata_mmio_data_xfer, + .data_xfer = ata_data_xfer, .eng_timeout = mv_eng_timeout, .irq_handler = mv_interrupt, .irq_clear = mv_irq_clear, + .irq_on = ata_irq_on, + .irq_ack = ata_irq_ack, .scr_read = mv5_scr_read, .scr_write = mv5_scr_write, .port_start = mv_port_start, .port_stop = mv_port_stop, - .host_stop = mv_host_stop, }; static const struct ata_port_operations mv6_ops = { @@ -434,19 +432,20 @@ static const struct ata_port_operations .qc_prep = mv_qc_prep, .qc_issue = mv_qc_issue, - .data_xfer = ata_mmio_data_xfer, + .data_xfer = ata_data_xfer, .eng_timeout = mv_eng_timeout, .irq_handler = mv_interrupt, .irq_clear = mv_irq_clear, + .irq_on = ata_irq_on, + .irq_ack = ata_irq_ack, .scr_read = mv_scr_read, .scr_write = mv_scr_write, .port_start = mv_port_start, .port_stop = mv_port_stop, - .host_stop = mv_host_stop, }; static const struct ata_port_operations mv_iie_ops = { @@ -462,19 +461,20 @@ static const struct ata_port_operations .qc_prep = mv_qc_prep_iie, .qc_issue = mv_qc_issue, - .data_xfer = ata_mmio_data_xfer, + .data_xfer = ata_data_xfer, .eng_timeout = mv_eng_timeout, .irq_handler = mv_interrupt, .irq_clear = mv_irq_clear, + .irq_on = ata_irq_on, + .irq_ack = ata_irq_ack, .scr_read = mv_scr_read, .scr_write = mv_scr_write, .port_start = mv_port_start, .port_stop = mv_port_stop, - .host_stop = mv_host_stop, }; static const struct ata_port_info mv_port_info[] = { @@ -620,7 +620,7 @@ static inline void __iomem *mv_port_base static inline void __iomem *mv_ap_base(struct ata_port *ap) { - return mv_port_base(ap->host->mmio_base, ap->port_no); + return mv_port_base(ap->host->iomap[MV_PRIMARY_BAR], ap->port_no); } static inline int mv_get_hc_count(unsigned long port_flags) @@ -809,35 +809,6 @@ static void mv_scr_write(struct ata_port } } -/** - * mv_host_stop - Host specific cleanup/stop routine. - * @host: host data structure - * - * Disable ints, cleanup host memory, call general purpose - * host_stop. - * - * LOCKING: - * Inherited from caller. - */ -static void mv_host_stop(struct ata_host *host) -{ - struct mv_host_priv *hpriv = host->private_data; - struct pci_dev *pdev = to_pci_dev(host->dev); - - if (hpriv->hp_flags & MV_HP_FLAG_MSI) { - pci_disable_msi(pdev); - } else { - pci_intx(pdev, 0); - } - kfree(hpriv); - ata_host_stop(host); -} - -static inline void mv_priv_free(struct mv_port_priv *pp, struct device *dev) -{ - dma_free_coherent(dev, MV_PORT_PRIV_DMA_SZ, pp->crpb, pp->crpb_dma); -} - static void mv_edma_cfg(struct mv_host_priv *hpriv, void __iomem *port_mmio) { u32 cfg = readl(port_mmio + EDMA_CFG_OFS); @@ -883,22 +854,21 @@ static int mv_port_start(struct ata_port void __iomem *port_mmio = mv_ap_base(ap); void *mem; dma_addr_t mem_dma; - int rc = -ENOMEM; + int rc; - pp = kmalloc(sizeof(*pp), GFP_KERNEL); + pp = devm_kzalloc(dev, sizeof(*pp), GFP_KERNEL); if (!pp) - goto err_out; - memset(pp, 0, sizeof(*pp)); + return -ENOMEM; - mem = dma_alloc_coherent(dev, MV_PORT_PRIV_DMA_SZ, &mem_dma, - GFP_KERNEL); + mem = dmam_alloc_coherent(dev, MV_PORT_PRIV_DMA_SZ, &mem_dma, + GFP_KERNEL); if (!mem) - goto err_out_pp; + return -ENOMEM; memset(mem, 0, MV_PORT_PRIV_DMA_SZ); rc = ata_pad_alloc(ap, dev); if (rc) - goto err_out_priv; + return rc; /* First item in chunk of DMA memory: * 32-slot command request table (CRQB), 32 bytes each in size @@ -951,13 +921,6 @@ static int mv_port_start(struct ata_port */ ap->private_data = pp; return 0; - -err_out_priv: - mv_priv_free(pp, dev); -err_out_pp: - kfree(pp); -err_out: - return rc; } /** @@ -971,18 +934,11 @@ err_out: */ static void mv_port_stop(struct ata_port *ap) { - struct device *dev = ap->host->dev; - struct mv_port_priv *pp = ap->private_data; unsigned long flags; spin_lock_irqsave(&ap->host->lock, flags); mv_stop_dma(ap); spin_unlock_irqrestore(&ap->host->lock, flags); - - ap->private_data = NULL; - ata_pad_free(ap, dev); - mv_priv_free(pp, dev); - kfree(pp); } /** @@ -1348,7 +1304,7 @@ static void mv_err_intr(struct ata_port */ static void mv_host_intr(struct ata_host *host, u32 relevant, unsigned int hc) { - void __iomem *mmio = host->mmio_base; + void __iomem *mmio = host->iomap[MV_PRIMARY_BAR]; void __iomem *hc_mmio = mv_hc_base(mmio, hc); struct ata_queued_cmd *qc; u32 hc_irq_cause; @@ -1391,8 +1347,7 @@ static void mv_host_intr(struct ata_host } else { /* PIO: check for device (drive) interrupt */ if ((DEV_IRQ << hard_port) & hc_irq_cause) { - ata_status = readb((void __iomem *) - ap->ioaddr.status_addr); + ata_status = readb(ap->ioaddr.status_addr); handled = 1; /* ignore spurious intr if drive still BUSY */ if (ata_status & ATA_BUSY) { @@ -1452,7 +1407,7 @@ static irqreturn_t mv_interrupt(int irq, { struct ata_host *host = dev_instance; unsigned int hc, handled = 0, n_hcs; - void __iomem *mmio = host->mmio_base; + void __iomem *mmio = host->iomap[MV_PRIMARY_BAR]; struct mv_host_priv *hpriv; u32 irq_stat; @@ -1528,22 +1483,24 @@ static unsigned int mv5_scr_offset(unsig static u32 mv5_scr_read(struct ata_port *ap, unsigned int sc_reg_in) { - void __iomem *mmio = mv5_phy_base(ap->host->mmio_base, ap->port_no); + void __iomem *mmio = ap->host->iomap[MV_PRIMARY_BAR]; + void __iomem *addr = mv5_phy_base(mmio, ap->port_no); unsigned int ofs = mv5_scr_offset(sc_reg_in); if (ofs != 0xffffffffU) - return readl(mmio + ofs); + return readl(addr + ofs); else return (u32) ofs; } static void mv5_scr_write(struct ata_port *ap, unsigned int sc_reg_in, u32 val) { - void __iomem *mmio = mv5_phy_base(ap->host->mmio_base, ap->port_no); + void __iomem *mmio = ap->host->iomap[MV_PRIMARY_BAR]; + void __iomem *addr = mv5_phy_base(mmio, ap->port_no); unsigned int ofs = mv5_scr_offset(sc_reg_in); if (ofs != 0xffffffffU) - writelfl(val, mmio + ofs); + writelfl(val, addr + ofs); } static void mv5_reset_bus(struct pci_dev *pdev, void __iomem *mmio) @@ -1905,7 +1862,7 @@ static void mv_channel_reset(struct mv_h static void mv_stop_and_reset(struct ata_port *ap) { struct mv_host_priv *hpriv = ap->host->private_data; - void __iomem *mmio = ap->host->mmio_base; + void __iomem *mmio = ap->host->iomap[MV_PRIMARY_BAR]; mv_stop_dma(ap); @@ -2003,10 +1960,10 @@ comreset_retry: break; } - tf.lbah = readb((void __iomem *) ap->ioaddr.lbah_addr); - tf.lbam = readb((void __iomem *) ap->ioaddr.lbam_addr); - tf.lbal = readb((void __iomem *) ap->ioaddr.lbal_addr); - tf.nsect = readb((void __iomem *) ap->ioaddr.nsect_addr); + tf.lbah = readb(ap->ioaddr.lbah_addr); + tf.lbam = readb(ap->ioaddr.lbam_addr); + tf.lbal = readb(ap->ioaddr.lbal_addr); + tf.nsect = readb(ap->ioaddr.nsect_addr); dev->class = ata_dev_classify(&tf); if (!ata_dev_enabled(dev)) { @@ -2038,17 +1995,17 @@ static void mv_phy_reset(struct ata_port */ static void mv_eng_timeout(struct ata_port *ap) { + void __iomem *mmio = ap->host->iomap[MV_PRIMARY_BAR]; struct ata_queued_cmd *qc; unsigned long flags; ata_port_printk(ap, KERN_ERR, "Entering mv_eng_timeout\n"); DPRINTK("All regs @ start of eng_timeout\n"); - mv_dump_all_regs(ap->host->mmio_base, ap->port_no, - to_pci_dev(ap->host->dev)); + mv_dump_all_regs(mmio, ap->port_no, to_pci_dev(ap->host->dev)); qc = ata_qc_from_tag(ap, ap->active_tag); printk(KERN_ERR "mmio_base %p ap %p qc %p scsi_cmnd %p &cmnd %p\n", - ap->host->mmio_base, ap, qc, qc->scsicmd, &qc->scsicmd->cmnd); + mmio, ap, qc, qc->scsicmd, &qc->scsicmd->cmnd); spin_lock_irqsave(&ap->host->lock, flags); mv_err_intr(ap, 0); @@ -2076,7 +2033,7 @@ static void mv_eng_timeout(struct ata_po */ static void mv_port_init(struct ata_ioports *port, void __iomem *port_mmio) { - unsigned long shd_base = (unsigned long) port_mmio + SHD_BLK_OFS; + void __iomem *shd_base = port_mmio + SHD_BLK_OFS; unsigned serr_ofs; /* PIO related setup @@ -2224,7 +2181,7 @@ static int mv_init_host(struct pci_dev * unsigned int board_idx) { int rc = 0, n_hc, port, hc; - void __iomem *mmio = probe_ent->mmio_base; + void __iomem *mmio = probe_ent->iomap[MV_PRIMARY_BAR]; struct mv_host_priv *hpriv = probe_ent->private_data; /* global interrupt mask */ @@ -2342,49 +2299,36 @@ static void mv_print_info(struct ata_pro static int mv_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) { static int printed_version = 0; - struct ata_probe_ent *probe_ent = NULL; + struct device *dev = &pdev->dev; + struct ata_probe_ent *probe_ent; struct mv_host_priv *hpriv; unsigned int board_idx = (unsigned int)ent->driver_data; - void __iomem *mmio_base; - int pci_dev_busy = 0, rc; + int rc; if (!printed_version++) dev_printk(KERN_INFO, &pdev->dev, "version " DRV_VERSION "\n"); - rc = pci_enable_device(pdev); - if (rc) { + rc = pcim_enable_device(pdev); + if (rc) return rc; - } pci_set_master(pdev); - rc = pci_request_regions(pdev, DRV_NAME); - if (rc) { - pci_dev_busy = 1; - goto err_out; - } + rc = pcim_iomap_regions(pdev, 1 << MV_PRIMARY_BAR, DRV_NAME); + if (rc == -EBUSY) + pcim_pin_device(pdev); + if (rc) + return rc; - probe_ent = kmalloc(sizeof(*probe_ent), GFP_KERNEL); - if (probe_ent == NULL) { - rc = -ENOMEM; - goto err_out_regions; - } + probe_ent = devm_kzalloc(dev, sizeof(*probe_ent), GFP_KERNEL); + if (probe_ent == NULL) + return -ENOMEM; - memset(probe_ent, 0, sizeof(*probe_ent)); probe_ent->dev = pci_dev_to_dev(pdev); INIT_LIST_HEAD(&probe_ent->node); - mmio_base = pci_iomap(pdev, MV_PRIMARY_BAR, 0); - if (mmio_base == NULL) { - rc = -ENOMEM; - goto err_out_free_ent; - } - - hpriv = kmalloc(sizeof(*hpriv), GFP_KERNEL); - if (!hpriv) { - rc = -ENOMEM; - goto err_out_iounmap; - } - memset(hpriv, 0, sizeof(*hpriv)); + hpriv = devm_kzalloc(dev, sizeof(*hpriv), GFP_KERNEL); + if (!hpriv) + return -ENOMEM; probe_ent->sht = mv_port_info[board_idx].sht; probe_ent->port_flags = mv_port_info[board_idx].flags; @@ -2394,53 +2338,26 @@ static int mv_init_one(struct pci_dev *p probe_ent->irq = pdev->irq; probe_ent->irq_flags = IRQF_SHARED; - probe_ent->mmio_base = mmio_base; + probe_ent->iomap = pcim_iomap_table(pdev); probe_ent->private_data = hpriv; /* initialize adapter */ rc = mv_init_host(pdev, probe_ent, board_idx); - if (rc) { - goto err_out_hpriv; - } + if (rc) + return rc; /* Enable interrupts */ - if (msi && pci_enable_msi(pdev) == 0) { - hpriv->hp_flags |= MV_HP_FLAG_MSI; - } else { + if (msi && !pci_enable_msi(pdev)) pci_intx(pdev, 1); - } mv_dump_pci_cfg(pdev, 0x68); mv_print_info(probe_ent); - if (ata_device_add(probe_ent) == 0) { - rc = -ENODEV; /* No devices discovered */ - goto err_out_dev_add; - } + if (ata_device_add(probe_ent) == 0) + return -ENODEV; - kfree(probe_ent); + devm_kfree(dev, probe_ent); return 0; - -err_out_dev_add: - if (MV_HP_FLAG_MSI & hpriv->hp_flags) { - pci_disable_msi(pdev); - } else { - pci_intx(pdev, 0); - } -err_out_hpriv: - kfree(hpriv); -err_out_iounmap: - pci_iounmap(pdev, mmio_base); -err_out_free_ent: - kfree(probe_ent); -err_out_regions: - pci_release_regions(pdev); -err_out: - if (!pci_dev_busy) { - pci_disable_device(pdev); - } - - return rc; } static int __init mv_init(void) diff --git a/drivers/ata/sata_nv.c b/drivers/ata/sata_nv.c index f7a963e..ab92f20 100644 --- a/drivers/ata/sata_nv.c +++ b/drivers/ata/sata_nv.c @@ -49,11 +49,13 @@ #include #include #define DRV_NAME "sata_nv" -#define DRV_VERSION "3.2" +#define DRV_VERSION "3.3" #define NV_ADMA_DMA_BOUNDARY 0xffffffffUL enum { + NV_MMIO_BAR = 5, + NV_PORTS = 2, NV_PIO_MASK = 0x1f, NV_MWDMA_MASK = 0x07, @@ -213,12 +215,21 @@ struct nv_adma_port_priv { dma_addr_t cpb_dma; struct nv_adma_prd *aprd; dma_addr_t aprd_dma; + void __iomem * ctl_block; + void __iomem * gen_block; + void __iomem * notifier_clear_block; u8 flags; }; +struct nv_host_priv { + unsigned long type; +}; + #define NV_ADMA_CHECK_INTR(GCTL, PORT) ((GCTL) & ( 1 << (19 + (12 * (PORT))))) static int nv_init_one (struct pci_dev *pdev, const struct pci_device_id *ent); +static void nv_remove_one (struct pci_dev *pdev); +static int nv_pci_device_resume(struct pci_dev *pdev); static void nv_ck804_host_stop(struct ata_host *host); static irqreturn_t nv_generic_interrupt(int irq, void *dev_instance); static irqreturn_t nv_nf2_interrupt(int irq, void *dev_instance); @@ -239,6 +250,8 @@ static irqreturn_t nv_adma_interrupt(int static void nv_adma_irq_clear(struct ata_port *ap); static int nv_adma_port_start(struct ata_port *ap); static void nv_adma_port_stop(struct ata_port *ap); +static int nv_adma_port_suspend(struct ata_port *ap, pm_message_t mesg); +static int nv_adma_port_resume(struct ata_port *ap); static void nv_adma_error_handler(struct ata_port *ap); static void nv_adma_host_stop(struct ata_host *host); static void nv_adma_bmdma_setup(struct ata_queued_cmd *qc); @@ -284,7 +297,9 @@ static struct pci_driver nv_pci_driver = .name = DRV_NAME, .id_table = nv_pci_tbl, .probe = nv_init_one, - .remove = ata_pci_remove_one, + .suspend = ata_pci_device_suspend, + .resume = nv_pci_device_resume, + .remove = nv_remove_one, }; static struct scsi_host_template nv_sht = { @@ -303,6 +318,8 @@ static struct scsi_host_template nv_sht .slave_configure = ata_scsi_slave_config, .slave_destroy = ata_scsi_slave_destroy, .bios_param = ata_std_bios_param, + .suspend = ata_scsi_device_suspend, + .resume = ata_scsi_device_resume, }; static struct scsi_host_template nv_adma_sht = { @@ -321,6 +338,8 @@ static struct scsi_host_template nv_adma .slave_configure = nv_adma_slave_config, .slave_destroy = ata_scsi_slave_destroy, .bios_param = ata_std_bios_param, + .suspend = ata_scsi_device_suspend, + .resume = ata_scsi_device_resume, }; static const struct ata_port_operations nv_generic_ops = { @@ -340,14 +359,14 @@ static const struct ata_port_operations .thaw = ata_bmdma_thaw, .error_handler = nv_error_handler, .post_internal_cmd = ata_bmdma_post_internal_cmd, - .data_xfer = ata_pio_data_xfer, + .data_xfer = ata_data_xfer, .irq_handler = nv_generic_interrupt, .irq_clear = ata_bmdma_irq_clear, + .irq_on = ata_irq_on, + .irq_ack = ata_irq_ack, .scr_read = nv_scr_read, .scr_write = nv_scr_write, .port_start = ata_port_start, - .port_stop = ata_port_stop, - .host_stop = ata_pci_host_stop, }; static const struct ata_port_operations nv_nf2_ops = { @@ -367,14 +386,14 @@ static const struct ata_port_operations .thaw = nv_nf2_thaw, .error_handler = nv_error_handler, .post_internal_cmd = ata_bmdma_post_internal_cmd, - .data_xfer = ata_pio_data_xfer, + .data_xfer = ata_data_xfer, .irq_handler = nv_nf2_interrupt, .irq_clear = ata_bmdma_irq_clear, + .irq_on = ata_irq_on, + .irq_ack = ata_irq_ack, .scr_read = nv_scr_read, .scr_write = nv_scr_write, .port_start = ata_port_start, - .port_stop = ata_port_stop, - .host_stop = ata_pci_host_stop, }; static const struct ata_port_operations nv_ck804_ops = { @@ -394,13 +413,14 @@ static const struct ata_port_operations .thaw = nv_ck804_thaw, .error_handler = nv_error_handler, .post_internal_cmd = ata_bmdma_post_internal_cmd, - .data_xfer = ata_pio_data_xfer, + .data_xfer = ata_data_xfer, .irq_handler = nv_ck804_interrupt, .irq_clear = ata_bmdma_irq_clear, + .irq_on = ata_irq_on, + .irq_ack = ata_irq_ack, .scr_read = nv_scr_read, .scr_write = nv_scr_write, .port_start = ata_port_start, - .port_stop = ata_port_stop, .host_stop = nv_ck804_host_stop, }; @@ -422,13 +442,17 @@ static const struct ata_port_operations .thaw = nv_ck804_thaw, .error_handler = nv_adma_error_handler, .post_internal_cmd = nv_adma_bmdma_stop, - .data_xfer = ata_mmio_data_xfer, + .data_xfer = ata_data_xfer, .irq_handler = nv_adma_interrupt, .irq_clear = nv_adma_irq_clear, + .irq_on = ata_irq_on, + .irq_ack = ata_irq_ack, .scr_read = nv_scr_read, .scr_write = nv_scr_write, .port_start = nv_adma_port_start, .port_stop = nv_adma_port_stop, + .port_suspend = nv_adma_port_suspend, + .port_resume = nv_adma_port_resume, .host_stop = nv_adma_host_stop, }; @@ -467,6 +491,7 @@ static struct ata_port_info nv_port_info { .sht = &nv_adma_sht, .flags = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY | + ATA_FLAG_HRST_TO_RESUME | ATA_FLAG_MMIO | ATA_FLAG_NCQ, .pio_mask = NV_PIO_MASK, .mwdma_mask = NV_MWDMA_MASK, @@ -483,57 +508,72 @@ MODULE_VERSION(DRV_VERSION); static int adma_enabled = 1; -static inline void __iomem *__nv_adma_ctl_block(void __iomem *mmio, - unsigned int port_no) -{ - mmio += NV_ADMA_PORT + port_no * NV_ADMA_PORT_SIZE; - return mmio; -} - -static inline void __iomem *nv_adma_ctl_block(struct ata_port *ap) -{ - return __nv_adma_ctl_block(ap->host->mmio_base, ap->port_no); -} - -static inline void __iomem *nv_adma_gen_block(struct ata_port *ap) -{ - return (ap->host->mmio_base + NV_ADMA_GEN); -} - -static inline void __iomem *nv_adma_notifier_clear_block(struct ata_port *ap) -{ - return (nv_adma_gen_block(ap) + NV_ADMA_NOTIFIER_CLEAR + (4 * ap->port_no)); -} - static void nv_adma_register_mode(struct ata_port *ap) { - void __iomem *mmio = nv_adma_ctl_block(ap); struct nv_adma_port_priv *pp = ap->private_data; - u16 tmp; + void __iomem *mmio = pp->ctl_block; + u16 tmp, status; + int count = 0; if (pp->flags & NV_ADMA_PORT_REGISTER_MODE) return; + status = readw(mmio + NV_ADMA_STAT); + while(!(status & NV_ADMA_STAT_IDLE) && count < 20) { + ndelay(50); + status = readw(mmio + NV_ADMA_STAT); + count++; + } + if(count == 20) + 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); + count = 0; + status = readw(mmio + NV_ADMA_STAT); + while(!(status & NV_ADMA_STAT_LEGACY) && count < 20) { + ndelay(50); + status = readw(mmio + NV_ADMA_STAT); + count++; + } + if(count == 20) + ata_port_printk(ap, KERN_WARNING, + "timeout waiting for ADMA LEGACY, stat=0x%hx\n", + status); + pp->flags |= NV_ADMA_PORT_REGISTER_MODE; } static void nv_adma_mode(struct ata_port *ap) { - void __iomem *mmio = nv_adma_ctl_block(ap); struct nv_adma_port_priv *pp = ap->private_data; - u16 tmp; + void __iomem *mmio = pp->ctl_block; + u16 tmp, status; + int count = 0; if (!(pp->flags & NV_ADMA_PORT_REGISTER_MODE)) return; - + WARN_ON(pp->flags & NV_ADMA_ATAPI_SETUP_COMPLETE); tmp = readw(mmio + NV_ADMA_CTL); writew(tmp | NV_ADMA_CTL_GO, mmio + NV_ADMA_CTL); + status = readw(mmio + NV_ADMA_STAT); + while(((status & NV_ADMA_STAT_LEGACY) || + !(status & NV_ADMA_STAT_IDLE)) && count < 20) { + ndelay(50); + status = readw(mmio + NV_ADMA_STAT); + count++; + } + if(count == 20) + ata_port_printk(ap, KERN_WARNING, + "timeout waiting for ADMA LEGACY clear and IDLE, stat=0x%hx\n", + status); + pp->flags &= ~NV_ADMA_PORT_REGISTER_MODE; } @@ -568,7 +608,7 @@ static int nv_adma_slave_config(struct s /* Subtract 1 since an extra entry may be needed for padding, see libata-scsi.c */ sg_tablesize = LIBATA_MAX_PRD - 1; - + /* Since the legacy DMA engine is in use, we need to disable ADMA on the port. */ adma_enable = 0; @@ -580,7 +620,7 @@ static int nv_adma_slave_config(struct s sg_tablesize = NV_ADMA_SGTBL_TOTAL_LEN; adma_enable = 1; } - + pci_read_config_dword(pdev, NV_MCP_SATA_CFG_20, ¤t_reg); if(ap->port_no == 1) @@ -589,7 +629,7 @@ static int nv_adma_slave_config(struct s else config_mask = NV_MCP_SATA_CFG_20_PORT0_EN | NV_MCP_SATA_CFG_20_PORT0_PWB_EN; - + if(adma_enable) { new_reg = current_reg | config_mask; pp->flags &= ~NV_ADMA_ATAPI_SETUP_COMPLETE; @@ -598,10 +638,10 @@ static int nv_adma_slave_config(struct s new_reg = current_reg & ~config_mask; pp->flags |= NV_ADMA_ATAPI_SETUP_COMPLETE; } - + if(current_reg != new_reg) pci_write_config_dword(pdev, NV_MCP_SATA_CFG_20, new_reg); - + blk_queue_bounce_limit(sdev->request_queue, bounce_limit); blk_queue_segment_boundary(sdev->request_queue, segment_boundary); blk_queue_max_hw_segments(sdev->request_queue, sg_tablesize); @@ -648,53 +688,62 @@ static unsigned int nv_adma_tf_to_cpb(st return idx; } -static void nv_adma_check_cpb(struct ata_port *ap, int cpb_num, int force_err) +static int nv_adma_check_cpb(struct ata_port *ap, int cpb_num, int force_err) { struct nv_adma_port_priv *pp = ap->private_data; - int complete = 0, have_err = 0; u8 flags = pp->cpb[cpb_num].resp_flags; VPRINTK("CPB %d, flags=0x%x\n", cpb_num, flags); - if (flags & NV_CPB_RESP_DONE) { - VPRINTK("CPB flags done, flags=0x%x\n", flags); - complete = 1; - } - if (flags & NV_CPB_RESP_ATA_ERR) { - ata_port_printk(ap, KERN_ERR, "CPB flags ATA err, flags=0x%x\n", flags); - have_err = 1; - complete = 1; - } - if (flags & NV_CPB_RESP_CMD_ERR) { - ata_port_printk(ap, KERN_ERR, "CPB flags CMD err, flags=0x%x\n", flags); - have_err = 1; - complete = 1; - } - if (flags & NV_CPB_RESP_CPB_ERR) { - ata_port_printk(ap, KERN_ERR, "CPB flags CPB err, flags=0x%x\n", flags); - have_err = 1; - complete = 1; + if (unlikely((force_err || + flags & (NV_CPB_RESP_ATA_ERR | + NV_CPB_RESP_CMD_ERR | + NV_CPB_RESP_CPB_ERR)))) { + struct ata_eh_info *ehi = &ap->eh_info; + int freeze = 0; + + ata_ehi_clear_desc(ehi); + ata_ehi_push_desc(ehi, "CPB resp_flags 0x%x", flags ); + if (flags & NV_CPB_RESP_ATA_ERR) { + ata_ehi_push_desc(ehi, ": ATA error"); + ehi->err_mask |= AC_ERR_DEV; + } else if (flags & NV_CPB_RESP_CMD_ERR) { + ata_ehi_push_desc(ehi, ": CMD error"); + ehi->err_mask |= AC_ERR_DEV; + } else if (flags & NV_CPB_RESP_CPB_ERR) { + ata_ehi_push_desc(ehi, ": CPB error"); + ehi->err_mask |= AC_ERR_SYSTEM; + freeze = 1; + } else { + /* notifier error, but no error in CPB flags? */ + ehi->err_mask |= AC_ERR_OTHER; + freeze = 1; + } + /* Kill all commands. EH will determine what actually failed. */ + if (freeze) + ata_port_freeze(ap); + else + ata_port_abort(ap); + return 1; } - if(complete || force_err) - { + + if (flags & NV_CPB_RESP_DONE) { struct ata_queued_cmd *qc = ata_qc_from_tag(ap, cpb_num); - if(likely(qc)) { - u8 ata_status = 0; - /* Only use the ATA port status for non-NCQ commands. + VPRINTK("CPB flags done, flags=0x%x\n", flags); + if (likely(qc)) { + /* Grab the ATA port status for non-NCQ commands. For NCQ commands the current status may have nothing to do with the command just completed. */ - if(qc->tf.protocol != ATA_PROT_NCQ) - ata_status = readb(nv_adma_ctl_block(ap) + (ATA_REG_STATUS * 4)); - - if(have_err || force_err) - ata_status |= ATA_ERR; - - qc->err_mask |= ac_err_mask(ata_status); + if (qc->tf.protocol != ATA_PROT_NCQ) { + u8 ata_status = readb(pp->ctl_block + (ATA_REG_STATUS * 4)); + qc->err_mask |= ac_err_mask(ata_status); + } DPRINTK("Completing qc from tag %d with err_mask %u\n",cpb_num, qc->err_mask); ata_qc_complete(qc); } } + return 0; } static int nv_host_intr(struct ata_port *ap, u8 irq_stat) @@ -735,15 +784,14 @@ static irqreturn_t nv_adma_interrupt(int if (ap && !(ap->flags & ATA_FLAG_DISABLED)) { struct nv_adma_port_priv *pp = ap->private_data; - void __iomem *mmio = nv_adma_ctl_block(ap); + void __iomem *mmio = pp->ctl_block; u16 status; u32 gen_ctl; - int have_global_err = 0; u32 notifier, notifier_error; /* if in ATA register mode, use standard ata interrupt handler */ if (pp->flags & NV_ADMA_PORT_REGISTER_MODE) { - u8 irq_stat = readb(host->mmio_base + NV_INT_STATUS_CK804) + u8 irq_stat = readb(host->iomap[NV_MMIO_BAR] + NV_INT_STATUS_CK804) >> (NV_INT_PORT_SHIFT * i); if(ata_tag_valid(ap->active_tag)) /** NV_INT_DEV indication seems unreliable at times @@ -758,7 +806,7 @@ static irqreturn_t nv_adma_interrupt(int notifier_error = readl(mmio + NV_ADMA_NOTIFIER_ERROR); notifier_clears[i] = notifier | notifier_error; - gen_ctl = readl(nv_adma_gen_block(ap) + NV_ADMA_GEN_CTL); + gen_ctl = readl(pp->gen_block + NV_ADMA_GEN_CTL); if( !NV_ADMA_CHECK_INTR(gen_ctl, ap->port_no) && !notifier && !notifier_error) @@ -774,52 +822,64 @@ static irqreturn_t nv_adma_interrupt(int readw(mmio + NV_ADMA_STAT); /* flush posted write */ rmb(); - /* freeze if hotplugged */ - if (unlikely(status & (NV_ADMA_STAT_HOTPLUG | NV_ADMA_STAT_HOTUNPLUG))) { - ata_port_printk(ap, KERN_NOTICE, "Hotplug event, freezing\n"); + handled++; /* irq handled if we got here */ + + /* freeze if hotplugged or controller error */ + if (unlikely(status & (NV_ADMA_STAT_HOTPLUG | + NV_ADMA_STAT_HOTUNPLUG | + NV_ADMA_STAT_TIMEOUT | + NV_ADMA_STAT_SERROR))) { + struct ata_eh_info *ehi = &ap->eh_info; + + ata_ehi_clear_desc(ehi); + ata_ehi_push_desc(ehi, "ADMA status 0x%08x", status ); + if (status & NV_ADMA_STAT_TIMEOUT) { + ehi->err_mask |= AC_ERR_SYSTEM; + ata_ehi_push_desc(ehi, ": timeout"); + } else if (status & NV_ADMA_STAT_HOTPLUG) { + ata_ehi_hotplugged(ehi); + ata_ehi_push_desc(ehi, ": hotplug"); + } else if (status & NV_ADMA_STAT_HOTUNPLUG) { + ata_ehi_hotplugged(ehi); + ata_ehi_push_desc(ehi, ": hot unplug"); + } else if (status & NV_ADMA_STAT_SERROR) { + /* let libata analyze SError and figure out the cause */ + ata_ehi_push_desc(ehi, ": SError"); + } ata_port_freeze(ap); - handled++; continue; } - if (status & NV_ADMA_STAT_TIMEOUT) { - ata_port_printk(ap, KERN_ERR, "timeout, stat=0x%x\n", status); - have_global_err = 1; - } - if (status & NV_ADMA_STAT_CPBERR) { - ata_port_printk(ap, KERN_ERR, "CPB error, stat=0x%x\n", status); - have_global_err = 1; - } - if ((status & NV_ADMA_STAT_DONE) || have_global_err) { + if (status & (NV_ADMA_STAT_DONE | + NV_ADMA_STAT_CPBERR)) { /** Check CPBs for completed commands */ - if(ata_tag_valid(ap->active_tag)) + if (ata_tag_valid(ap->active_tag)) { /* Non-NCQ command */ - nv_adma_check_cpb(ap, ap->active_tag, have_global_err || - (notifier_error & (1 << ap->active_tag))); - else { - int pos; + nv_adma_check_cpb(ap, ap->active_tag, + notifier_error & (1 << ap->active_tag)); + } else { + int pos, error = 0; u32 active = ap->sactive; - while( (pos = ffs(active)) ) { + + while ((pos = ffs(active)) && !error) { pos--; - nv_adma_check_cpb(ap, pos, have_global_err || - (notifier_error & (1 << pos)) ); + error = nv_adma_check_cpb(ap, pos, + notifier_error & (1 << pos) ); active &= ~(1 << pos ); } } } - - handled++; /* irq handled if we got here */ } } - + if(notifier_clears[0] || notifier_clears[1]) { /* Note: Both notifier clear registers must be written if either is set, even if one is zero, according to NVIDIA. */ - writel(notifier_clears[0], - nv_adma_notifier_clear_block(host->ports[0])); - writel(notifier_clears[1], - nv_adma_notifier_clear_block(host->ports[1])); + struct nv_adma_port_priv *pp = host->ports[0]->private_data; + writel(notifier_clears[0], pp->notifier_clear_block); + pp = host->ports[1]->private_data; + writel(notifier_clears[1], pp->notifier_clear_block); } spin_unlock(&host->lock); @@ -829,19 +889,20 @@ static irqreturn_t nv_adma_interrupt(int static void nv_adma_irq_clear(struct ata_port *ap) { - void __iomem *mmio = nv_adma_ctl_block(ap); + struct nv_adma_port_priv *pp = ap->private_data; + void __iomem *mmio = pp->ctl_block; u16 status = readw(mmio + NV_ADMA_STAT); u32 notifier = readl(mmio + NV_ADMA_NOTIFIER); u32 notifier_error = readl(mmio + NV_ADMA_NOTIFIER_ERROR); - unsigned long dma_stat_addr = ap->ioaddr.bmdma_addr + ATA_DMA_STATUS; + void __iomem *dma_stat_addr = ap->ioaddr.bmdma_addr + ATA_DMA_STATUS; /* clear ADMA status */ writew(status, mmio + NV_ADMA_STAT); writel(notifier | notifier_error, - nv_adma_notifier_clear_block(ap)); + pp->notifier_clear_block); /** clear legacy status */ - outb(inb(dma_stat_addr), dma_stat_addr); + iowrite8(ioread8(dma_stat_addr), dma_stat_addr); } static void nv_adma_bmdma_setup(struct ata_queued_cmd *qc) @@ -857,15 +918,15 @@ static void nv_adma_bmdma_setup(struct a } /* load PRD table addr. */ - outl(ap->prd_dma, ap->ioaddr.bmdma_addr + ATA_DMA_TABLE_OFS); + iowrite32(ap->prd_dma, ap->ioaddr.bmdma_addr + ATA_DMA_TABLE_OFS); /* specify data direction, triple-check start bit is clear */ - dmactl = inb(ap->ioaddr.bmdma_addr + ATA_DMA_CMD); + dmactl = ioread8(ap->ioaddr.bmdma_addr + ATA_DMA_CMD); dmactl &= ~(ATA_DMA_WR | ATA_DMA_START); if (!rw) dmactl |= ATA_DMA_WR; - outb(dmactl, ap->ioaddr.bmdma_addr + ATA_DMA_CMD); + iowrite8(dmactl, ap->ioaddr.bmdma_addr + ATA_DMA_CMD); /* issue r/w command */ ata_exec_command(ap, &qc->tf); @@ -883,9 +944,9 @@ static void nv_adma_bmdma_start(struct a } /* start host DMA transaction */ - dmactl = inb(ap->ioaddr.bmdma_addr + ATA_DMA_CMD); - outb(dmactl | ATA_DMA_START, - ap->ioaddr.bmdma_addr + ATA_DMA_CMD); + dmactl = ioread8(ap->ioaddr.bmdma_addr + ATA_DMA_CMD); + iowrite8(dmactl | ATA_DMA_START, + ap->ioaddr.bmdma_addr + ATA_DMA_CMD); } static void nv_adma_bmdma_stop(struct ata_queued_cmd *qc) @@ -897,8 +958,8 @@ static void nv_adma_bmdma_stop(struct at return; /* clear start/stop bit */ - outb(inb(ap->ioaddr.bmdma_addr + ATA_DMA_CMD) & ~ATA_DMA_START, - ap->ioaddr.bmdma_addr + ATA_DMA_CMD); + iowrite8(ioread8(ap->ioaddr.bmdma_addr + ATA_DMA_CMD) & ~ATA_DMA_START, + ap->ioaddr.bmdma_addr + ATA_DMA_CMD); /* one-PIO-cycle guaranteed wait, per spec, for HDMA1:0 transition */ ata_altstatus(ap); /* dummy read */ @@ -910,7 +971,7 @@ static u8 nv_adma_bmdma_status(struct at WARN_ON(!(pp->flags & NV_ADMA_PORT_REGISTER_MODE)); - return inb(ap->ioaddr.bmdma_addr + ATA_DMA_STATUS); + return ioread8(ap->ioaddr.bmdma_addr + ATA_DMA_STATUS); } static int nv_adma_port_start(struct ata_port *ap) @@ -920,7 +981,7 @@ static int nv_adma_port_start(struct ata int rc; void *mem; dma_addr_t mem_dma; - void __iomem *mmio = nv_adma_ctl_block(ap); + void __iomem *mmio; u16 tmp; VPRINTK("ENTER\n"); @@ -929,19 +990,21 @@ static int nv_adma_port_start(struct ata if (rc) return rc; - pp = kzalloc(sizeof(*pp), GFP_KERNEL); - if (!pp) { - rc = -ENOMEM; - goto err_out; - } - - mem = dma_alloc_coherent(dev, NV_ADMA_PORT_PRIV_DMA_SZ, - &mem_dma, GFP_KERNEL); - - if (!mem) { - rc = -ENOMEM; - goto err_out_kfree; - } + pp = devm_kzalloc(dev, sizeof(*pp), GFP_KERNEL); + if (!pp) + return -ENOMEM; + + mmio = ap->host->iomap[NV_MMIO_BAR] + NV_ADMA_PORT + + ap->port_no * NV_ADMA_PORT_SIZE; + pp->ctl_block = mmio; + pp->gen_block = ap->host->iomap[NV_MMIO_BAR] + NV_ADMA_GEN; + pp->notifier_clear_block = pp->gen_block + + NV_ADMA_NOTIFIER_CLEAR + (4 * ap->port_no); + + mem = dmam_alloc_coherent(dev, NV_ADMA_PORT_PRIV_DMA_SZ, + &mem_dma, GFP_KERNEL); + if (!mem) + return -ENOMEM; memset(mem, 0, NV_ADMA_PORT_PRIV_DMA_SZ); /* @@ -975,9 +1038,9 @@ static int nv_adma_port_start(struct ata /* clear CPB fetch count */ writew(0, mmio + NV_ADMA_CPB_COUNT); - /* clear GO for register mode */ + /* clear GO for register mode, enable interrupt */ tmp = readw(mmio + NV_ADMA_CTL); - writew(tmp & ~NV_ADMA_CTL_GO, mmio + NV_ADMA_CTL); + writew( (tmp & ~NV_ADMA_CTL_GO) | NV_ADMA_CTL_AIEN, mmio + NV_ADMA_CTL); tmp = readw(mmio + NV_ADMA_CTL); writew(tmp | NV_ADMA_CTL_CHANNEL_RESET, mmio + NV_ADMA_CTL); @@ -987,53 +1050,89 @@ static int nv_adma_port_start(struct ata readl( mmio + NV_ADMA_CTL ); /* flush posted write */ return 0; - -err_out_kfree: - kfree(pp); -err_out: - ata_port_stop(ap); - return rc; } static void nv_adma_port_stop(struct ata_port *ap) { - struct device *dev = ap->host->dev; struct nv_adma_port_priv *pp = ap->private_data; - void __iomem *mmio = nv_adma_ctl_block(ap); + void __iomem *mmio = pp->ctl_block; VPRINTK("ENTER\n"); + writew(0, mmio + NV_ADMA_CTL); +} + +static int nv_adma_port_suspend(struct ata_port *ap, pm_message_t mesg) +{ + struct nv_adma_port_priv *pp = ap->private_data; + void __iomem *mmio = pp->ctl_block; + /* Go to register mode - clears GO */ + nv_adma_register_mode(ap); + + /* clear CPB fetch count */ + writew(0, mmio + NV_ADMA_CPB_COUNT); + + /* disable interrupt, shut down port */ writew(0, mmio + NV_ADMA_CTL); - ap->private_data = NULL; - dma_free_coherent(dev, NV_ADMA_PORT_PRIV_DMA_SZ, pp->cpb, pp->cpb_dma); - kfree(pp); - ata_port_stop(ap); + return 0; } +static int nv_adma_port_resume(struct ata_port *ap) +{ + struct nv_adma_port_priv *pp = ap->private_data; + void __iomem *mmio = pp->ctl_block; + u16 tmp; + + /* set CPB block location */ + writel(pp->cpb_dma & 0xFFFFFFFF, mmio + NV_ADMA_CPB_BASE_LOW); + writel((pp->cpb_dma >> 16 ) >> 16, mmio + NV_ADMA_CPB_BASE_HIGH); + + /* clear any outstanding interrupt conditions */ + writew(0xffff, mmio + NV_ADMA_STAT); + + /* initialize port variables */ + pp->flags |= NV_ADMA_PORT_REGISTER_MODE; + + /* clear CPB fetch count */ + writew(0, mmio + NV_ADMA_CPB_COUNT); + + /* clear GO for register mode, enable interrupt */ + tmp = readw(mmio + NV_ADMA_CTL); + writew((tmp & ~NV_ADMA_CTL_GO) | NV_ADMA_CTL_AIEN, mmio + NV_ADMA_CTL); + + tmp = readw(mmio + NV_ADMA_CTL); + writew(tmp | NV_ADMA_CTL_CHANNEL_RESET, mmio + NV_ADMA_CTL); + readl( mmio + NV_ADMA_CTL ); /* flush posted write */ + udelay(1); + writew(tmp & ~NV_ADMA_CTL_CHANNEL_RESET, mmio + NV_ADMA_CTL); + readl( mmio + NV_ADMA_CTL ); /* flush posted write */ + + return 0; +} static void nv_adma_setup_port(struct ata_probe_ent *probe_ent, unsigned int port) { - void __iomem *mmio = probe_ent->mmio_base; + void __iomem *mmio = probe_ent->iomap[NV_MMIO_BAR]; struct ata_ioports *ioport = &probe_ent->port[port]; VPRINTK("ENTER\n"); mmio += NV_ADMA_PORT + port * NV_ADMA_PORT_SIZE; - ioport->cmd_addr = (unsigned long) mmio; - ioport->data_addr = (unsigned long) mmio + (ATA_REG_DATA * 4); + ioport->cmd_addr = mmio; + ioport->data_addr = mmio + (ATA_REG_DATA * 4); ioport->error_addr = - ioport->feature_addr = (unsigned long) mmio + (ATA_REG_ERR * 4); - ioport->nsect_addr = (unsigned long) mmio + (ATA_REG_NSECT * 4); - ioport->lbal_addr = (unsigned long) mmio + (ATA_REG_LBAL * 4); - ioport->lbam_addr = (unsigned long) mmio + (ATA_REG_LBAM * 4); - ioport->lbah_addr = (unsigned long) mmio + (ATA_REG_LBAH * 4); - ioport->device_addr = (unsigned long) mmio + (ATA_REG_DEVICE * 4); + ioport->feature_addr = mmio + (ATA_REG_ERR * 4); + ioport->nsect_addr = mmio + (ATA_REG_NSECT * 4); + ioport->lbal_addr = mmio + (ATA_REG_LBAL * 4); + ioport->lbam_addr = mmio + (ATA_REG_LBAM * 4); + ioport->lbah_addr = mmio + (ATA_REG_LBAH * 4); + ioport->device_addr = mmio + (ATA_REG_DEVICE * 4); ioport->status_addr = - ioport->command_addr = (unsigned long) mmio + (ATA_REG_STATUS * 4); + ioport->command_addr = mmio + (ATA_REG_STATUS * 4); ioport->altstatus_addr = - ioport->ctl_addr = (unsigned long) mmio + 0x20; + ioport->ctl_addr = mmio + 0x20; } static int nv_adma_host_init(struct ata_probe_ent *probe_ent) @@ -1056,15 +1155,6 @@ static int nv_adma_host_init(struct ata_ for (i = 0; i < probe_ent->n_ports; i++) nv_adma_setup_port(probe_ent, i); - for (i = 0; i < probe_ent->n_ports; i++) { - void __iomem *mmio = __nv_adma_ctl_block(probe_ent->mmio_base, i); - u16 tmp; - - /* enable interrupt, clear reset if not already clear */ - tmp = readw(mmio + NV_ADMA_CTL); - writew(tmp | NV_ADMA_CTL_AIEN, mmio + NV_ADMA_CTL); - } - return 0; } @@ -1110,18 +1200,31 @@ static void nv_adma_fill_sg(struct ata_q cpb->next_aprd = cpu_to_le64(((u64)(pp->aprd_dma + NV_ADMA_SGTBL_SZ * qc->tag))); } +static int nv_adma_use_reg_mode(struct ata_queued_cmd *qc) +{ + struct nv_adma_port_priv *pp = qc->ap->private_data; + + /* ADMA engine can only be used for non-ATAPI DMA commands, + or interrupt-driven no-data commands. */ + if((pp->flags & NV_ADMA_ATAPI_SETUP_COMPLETE) || + (qc->tf.flags & ATA_TFLAG_POLLING)) + return 1; + + if((qc->flags & ATA_QCFLAG_DMAMAP) || + (qc->tf.protocol == ATA_PROT_NODATA)) + return 0; + + return 1; +} + static void nv_adma_qc_prep(struct ata_queued_cmd *qc) { struct nv_adma_port_priv *pp = qc->ap->private_data; struct nv_adma_cpb *cpb = &pp->cpb[qc->tag]; u8 ctl_flags = NV_CPB_CTL_CPB_VALID | - NV_CPB_CTL_APRD_VALID | NV_CPB_CTL_IEN; - VPRINTK("qc->flags = 0x%lx\n", qc->flags); - - if (!(qc->flags & ATA_QCFLAG_DMAMAP) || - (pp->flags & NV_ADMA_ATAPI_SETUP_COMPLETE)) { + if (nv_adma_use_reg_mode(qc)) { nv_adma_register_mode(qc->ap); ata_qc_prep(qc); return; @@ -1137,9 +1240,15 @@ static void nv_adma_qc_prep(struct ata_q if (qc->tf.protocol == ATA_PROT_NCQ) ctl_flags |= NV_CPB_CTL_QUEUE | NV_CPB_CTL_FPDMA; + VPRINTK("qc->flags = 0x%lx\n", qc->flags); + nv_adma_tf_to_cpb(&qc->tf, cpb->tf); - nv_adma_fill_sg(qc, cpb); + if(qc->flags & ATA_QCFLAG_DMAMAP) { + nv_adma_fill_sg(qc, cpb); + ctl_flags |= NV_CPB_CTL_APRD_VALID; + } else + memset(&cpb->aprd[0], 0, sizeof(struct nv_adma_prd) * 5); /* Be paranoid and don't let the device see NV_CPB_CTL_CPB_VALID until we are finished filling in all of the contents */ @@ -1150,14 +1259,13 @@ static void nv_adma_qc_prep(struct ata_q static unsigned int nv_adma_qc_issue(struct ata_queued_cmd *qc) { struct nv_adma_port_priv *pp = qc->ap->private_data; - void __iomem *mmio = nv_adma_ctl_block(qc->ap); + void __iomem *mmio = pp->ctl_block; VPRINTK("ENTER\n"); - if (!(qc->flags & ATA_QCFLAG_DMAMAP) || - (pp->flags & NV_ADMA_ATAPI_SETUP_COMPLETE)) { + if (nv_adma_use_reg_mode(qc)) { /* use ATA register mode */ - VPRINTK("no dmamap or ATAPI, using ATA register mode: 0x%lx\n", qc->flags); + VPRINTK("using ATA register mode: 0x%lx\n", qc->flags); nv_adma_register_mode(qc->ap); return ata_qc_issue_prot(qc); } else @@ -1229,7 +1337,7 @@ static irqreturn_t nv_nf2_interrupt(int irqreturn_t ret; spin_lock(&host->lock); - irq_stat = inb(host->ports[0]->ioaddr.scr_addr + NV_INT_STATUS); + irq_stat = ioread8(host->ports[0]->ioaddr.scr_addr + NV_INT_STATUS); ret = nv_do_interrupt(host, irq_stat); spin_unlock(&host->lock); @@ -1243,7 +1351,7 @@ static irqreturn_t nv_ck804_interrupt(in irqreturn_t ret; spin_lock(&host->lock); - irq_stat = readb(host->mmio_base + NV_INT_STATUS_CK804); + irq_stat = readb(host->iomap[NV_MMIO_BAR] + NV_INT_STATUS_CK804); ret = nv_do_interrupt(host, irq_stat); spin_unlock(&host->lock); @@ -1255,7 +1363,7 @@ static u32 nv_scr_read (struct ata_port if (sc_reg > SCR_CONTROL) return 0xffffffffU; - return ioread32((void __iomem *)ap->ioaddr.scr_addr + (sc_reg * 4)); + return ioread32(ap->ioaddr.scr_addr + (sc_reg * 4)); } static void nv_scr_write (struct ata_port *ap, unsigned int sc_reg, u32 val) @@ -1263,36 +1371,36 @@ static void nv_scr_write (struct ata_por if (sc_reg > SCR_CONTROL) return; - iowrite32(val, (void __iomem *)ap->ioaddr.scr_addr + (sc_reg * 4)); + iowrite32(val, ap->ioaddr.scr_addr + (sc_reg * 4)); } static void nv_nf2_freeze(struct ata_port *ap) { - unsigned long scr_addr = ap->host->ports[0]->ioaddr.scr_addr; + void __iomem *scr_addr = ap->host->ports[0]->ioaddr.scr_addr; int shift = ap->port_no * NV_INT_PORT_SHIFT; u8 mask; - mask = inb(scr_addr + NV_INT_ENABLE); + mask = ioread8(scr_addr + NV_INT_ENABLE); mask &= ~(NV_INT_ALL << shift); - outb(mask, scr_addr + NV_INT_ENABLE); + iowrite8(mask, scr_addr + NV_INT_ENABLE); } static void nv_nf2_thaw(struct ata_port *ap) { - unsigned long scr_addr = ap->host->ports[0]->ioaddr.scr_addr; + void __iomem *scr_addr = ap->host->ports[0]->ioaddr.scr_addr; int shift = ap->port_no * NV_INT_PORT_SHIFT; u8 mask; - outb(NV_INT_ALL << shift, scr_addr + NV_INT_STATUS); + iowrite8(NV_INT_ALL << shift, scr_addr + NV_INT_STATUS); - mask = inb(scr_addr + NV_INT_ENABLE); + mask = ioread8(scr_addr + NV_INT_ENABLE); mask |= (NV_INT_MASK << shift); - outb(mask, scr_addr + NV_INT_ENABLE); + iowrite8(mask, scr_addr + NV_INT_ENABLE); } static void nv_ck804_freeze(struct ata_port *ap) { - void __iomem *mmio_base = ap->host->mmio_base; + void __iomem *mmio_base = ap->host->iomap[NV_MMIO_BAR]; int shift = ap->port_no * NV_INT_PORT_SHIFT; u8 mask; @@ -1303,7 +1411,7 @@ static void nv_ck804_freeze(struct ata_p static void nv_ck804_thaw(struct ata_port *ap) { - void __iomem *mmio_base = ap->host->mmio_base; + void __iomem *mmio_base = ap->host->iomap[NV_MMIO_BAR]; int shift = ap->port_no * NV_INT_PORT_SHIFT; u8 mask; @@ -1335,32 +1443,13 @@ static void nv_adma_error_handler(struct { struct nv_adma_port_priv *pp = ap->private_data; if(!(pp->flags & NV_ADMA_PORT_REGISTER_MODE)) { - void __iomem *mmio = nv_adma_ctl_block(ap); + void __iomem *mmio = pp->ctl_block; int i; u16 tmp; - u32 notifier = readl(mmio + NV_ADMA_NOTIFIER); - u32 notifier_error = readl(mmio + NV_ADMA_NOTIFIER_ERROR); - u32 gen_ctl = readl(nv_adma_gen_block(ap) + NV_ADMA_GEN_CTL); - u32 status = readw(mmio + NV_ADMA_STAT); - - ata_port_printk(ap, KERN_ERR, "EH in ADMA mode, notifier 0x%X " - "notifier_error 0x%X gen_ctl 0x%X status 0x%X\n", - notifier, notifier_error, gen_ctl, status); - - for( i=0;icpb[i]; - if( cpb->ctl_flags || cpb->resp_flags ) - ata_port_printk(ap, KERN_ERR, - "CPB %d: ctl_flags 0x%x, resp_flags 0x%x\n", - i, cpb->ctl_flags, cpb->resp_flags); - } - /* Push us back into port register mode for error handling. */ nv_adma_register_mode(ap); - ata_port_printk(ap, KERN_ERR, "Resetting port\n"); - /* Mark all of the CPBs as invalid to prevent them from being executed */ for( i=0;icpb[i].ctl_flags &= ~NV_CPB_CTL_CPB_VALID; @@ -1386,10 +1475,10 @@ static int nv_init_one (struct pci_dev * static int printed_version = 0; struct ata_port_info *ppi[2]; struct ata_probe_ent *probe_ent; - int pci_dev_busy = 0; + struct nv_host_priv *hpriv; int rc; u32 bar; - unsigned long base; + void __iomem *base; unsigned long type = ent->driver_data; int mask_set = 0; @@ -1400,17 +1489,17 @@ static int nv_init_one (struct pci_dev * if (pci_resource_start(pdev, bar) == 0) return -ENODEV; - if ( !printed_version++) + if (!printed_version++) dev_printk(KERN_DEBUG, &pdev->dev, "version " DRV_VERSION "\n"); - rc = pci_enable_device(pdev); + rc = pcim_enable_device(pdev); if (rc) - goto err_out; + return rc; rc = pci_request_regions(pdev, DRV_NAME); if (rc) { - pci_dev_busy = 1; - goto err_out_disable; + pcim_pin_device(pdev); + return rc; } if(type >= CK804 && adma_enabled) { @@ -1424,27 +1513,31 @@ static int nv_init_one (struct pci_dev * if(!mask_set) { rc = pci_set_dma_mask(pdev, ATA_DMA_MASK); if (rc) - goto err_out_regions; + return rc; rc = pci_set_consistent_dma_mask(pdev, ATA_DMA_MASK); if (rc) - goto err_out_regions; + return rc; } rc = -ENOMEM; + hpriv = devm_kzalloc(&pdev->dev, sizeof(*hpriv), GFP_KERNEL); + if (!hpriv) + return -ENOMEM; + ppi[0] = ppi[1] = &nv_port_info[type]; probe_ent = ata_pci_init_native_mode(pdev, ppi, ATA_PORT_PRIMARY | ATA_PORT_SECONDARY); if (!probe_ent) - goto err_out_regions; + return -ENOMEM; - probe_ent->mmio_base = pci_iomap(pdev, 5, 0); - if (!probe_ent->mmio_base) { - rc = -EIO; - goto err_out_free_ent; - } + if (!pcim_iomap(pdev, NV_MMIO_BAR, 0)) + return -EIO; + probe_ent->iomap = pcim_iomap_table(pdev); - base = (unsigned long)probe_ent->mmio_base; + probe_ent->private_data = hpriv; + hpriv->type = type; + base = probe_ent->iomap[NV_MMIO_BAR]; probe_ent->port[0].scr_addr = base + NV_PORT0_SCR_REG_OFFSET; probe_ent->port[1].scr_addr = base + NV_PORT1_SCR_REG_OFFSET; @@ -1462,28 +1555,72 @@ static int nv_init_one (struct pci_dev * if (type == ADMA) { rc = nv_adma_host_init(probe_ent); if (rc) - goto err_out_iounmap; + return rc; } rc = ata_device_add(probe_ent); if (rc != NV_PORTS) - goto err_out_iounmap; - - kfree(probe_ent); + return -ENODEV; + devm_kfree(&pdev->dev, probe_ent); return 0; +} -err_out_iounmap: - pci_iounmap(pdev, probe_ent->mmio_base); -err_out_free_ent: - kfree(probe_ent); -err_out_regions: - pci_release_regions(pdev); -err_out_disable: - if (!pci_dev_busy) - pci_disable_device(pdev); -err_out: - return rc; +static void nv_remove_one (struct pci_dev *pdev) +{ + struct ata_host *host = dev_get_drvdata(&pdev->dev); + struct nv_host_priv *hpriv = host->private_data; + + ata_pci_remove_one(pdev); + kfree(hpriv); +} + +static int nv_pci_device_resume(struct pci_dev *pdev) +{ + struct ata_host *host = dev_get_drvdata(&pdev->dev); + struct nv_host_priv *hpriv = host->private_data; + int rc; + + rc = ata_pci_device_do_resume(pdev); + if(rc) + return rc; + + if (pdev->dev.power.power_state.event == PM_EVENT_SUSPEND) { + if(hpriv->type >= CK804) { + u8 regval; + + pci_read_config_byte(pdev, NV_MCP_SATA_CFG_20, ®val); + regval |= NV_MCP_SATA_CFG_20_SATA_SPACE_EN; + pci_write_config_byte(pdev, NV_MCP_SATA_CFG_20, regval); + } + if(hpriv->type == ADMA) { + u32 tmp32; + struct nv_adma_port_priv *pp; + /* enable/disable ADMA on the ports appropriately */ + pci_read_config_dword(pdev, NV_MCP_SATA_CFG_20, &tmp32); + + pp = host->ports[0]->private_data; + if(pp->flags & NV_ADMA_ATAPI_SETUP_COMPLETE) + tmp32 &= ~(NV_MCP_SATA_CFG_20_PORT0_EN | + NV_MCP_SATA_CFG_20_PORT0_PWB_EN); + else + tmp32 |= (NV_MCP_SATA_CFG_20_PORT0_EN | + NV_MCP_SATA_CFG_20_PORT0_PWB_EN); + pp = host->ports[1]->private_data; + if(pp->flags & NV_ADMA_ATAPI_SETUP_COMPLETE) + tmp32 &= ~(NV_MCP_SATA_CFG_20_PORT1_EN | + NV_MCP_SATA_CFG_20_PORT1_PWB_EN); + else + tmp32 |= (NV_MCP_SATA_CFG_20_PORT1_EN | + NV_MCP_SATA_CFG_20_PORT1_PWB_EN); + + pci_write_config_dword(pdev, NV_MCP_SATA_CFG_20, tmp32); + } + } + + ata_host_resume(host); + + return 0; } static void nv_ck804_host_stop(struct ata_host *host) @@ -1495,25 +1632,13 @@ static void nv_ck804_host_stop(struct at pci_read_config_byte(pdev, NV_MCP_SATA_CFG_20, ®val); regval &= ~NV_MCP_SATA_CFG_20_SATA_SPACE_EN; pci_write_config_byte(pdev, NV_MCP_SATA_CFG_20, regval); - - ata_pci_host_stop(host); } static void nv_adma_host_stop(struct ata_host *host) { struct pci_dev *pdev = to_pci_dev(host->dev); - int i; u32 tmp32; - for (i = 0; i < host->n_ports; i++) { - void __iomem *mmio = __nv_adma_ctl_block(host->mmio_base, i); - u16 tmp; - - /* disable interrupt */ - tmp = readw(mmio + NV_ADMA_CTL); - writew(tmp & ~NV_ADMA_CTL_AIEN, mmio + NV_ADMA_CTL); - } - /* disable ADMA on the ports */ pci_read_config_dword(pdev, NV_MCP_SATA_CFG_20, &tmp32); tmp32 &= ~(NV_MCP_SATA_CFG_20_PORT0_EN | diff --git a/drivers/ata/sata_promise.c b/drivers/ata/sata_promise.c index f055874..cf9ed8c 100644 --- a/drivers/ata/sata_promise.c +++ b/drivers/ata/sata_promise.c @@ -37,12 +37,11 @@ #include #include #include #include -#include #include +#include #include #include #include -#include #include "sata_promise.h" #define DRV_NAME "sata_promise" @@ -50,6 +49,17 @@ #define DRV_VERSION "1.05" enum { + PDC_MMIO_BAR = 3, + + /* register offsets */ + PDC_FEATURE = 0x04, /* Feature/Error reg (per port) */ + PDC_SECTOR_COUNT = 0x08, /* Sector count reg (per port) */ + PDC_SECTOR_NUMBER = 0x0C, /* Sector number reg (per port) */ + PDC_CYLINDER_LOW = 0x10, /* Cylinder low reg (per port) */ + PDC_CYLINDER_HIGH = 0x14, /* Cylinder high reg (per port) */ + PDC_DEVICE = 0x18, /* Device/Head reg (per port) */ + PDC_COMMAND = 0x1C, /* Command/status reg (per port) */ + PDC_ALTSTATUS = 0x38, /* Alternate-status/device-control reg (per port) */ PDC_PKT_SUBMIT = 0x40, /* Command packet pointer addr */ PDC_INT_SEQMASK = 0x40, /* Mask of asserted SEQ INTs */ PDC_FLASH_CTL = 0x44, /* Flash control register */ @@ -71,13 +81,23 @@ enum { PDC_HAS_PATA = (1 << 1), /* PDC20375/20575 has PATA */ + /* Sequence counter control registers bit definitions */ + PDC_SEQCNTRL_INT_MASK = (1 << 5), /* Sequence Interrupt Mask */ + + /* Feature register values */ + PDC_FEATURE_ATAPI_PIO = 0x00, /* ATAPI data xfer by PIO */ + PDC_FEATURE_ATAPI_DMA = 0x01, /* ATAPI data xfer by DMA */ + + /* Device/Head register values */ + PDC_DEVICE_SATA = 0xE0, /* Device/Head value for SATA devices */ + /* PDC_CTLSTAT bit definitions */ PDC_DMA_ENABLE = (1 << 7), PDC_IRQ_DISABLE = (1 << 10), PDC_RESET = (1 << 11), /* HDMA reset */ PDC_COMMON_FLAGS = ATA_FLAG_NO_LEGACY | - ATA_FLAG_MMIO | ATA_FLAG_NO_ATAPI | + ATA_FLAG_MMIO | ATA_FLAG_PIO_POLLING, /* hp->flags bits */ @@ -92,22 +112,21 @@ struct pdc_port_priv { struct pdc_host_priv { unsigned long flags; + unsigned long port_flags[ATA_MAX_PORTS]; }; static u32 pdc_sata_scr_read (struct ata_port *ap, unsigned int sc_reg); static void pdc_sata_scr_write (struct ata_port *ap, unsigned int sc_reg, u32 val); static int pdc_ata_init_one (struct pci_dev *pdev, const struct pci_device_id *ent); static irqreturn_t pdc_interrupt (int irq, void *dev_instance); -static void pdc_eng_timeout(struct ata_port *ap); static int pdc_port_start(struct ata_port *ap); -static void pdc_port_stop(struct ata_port *ap); -static void pdc_pata_phy_reset(struct ata_port *ap); static void pdc_qc_prep(struct ata_queued_cmd *qc); static void pdc_tf_load_mmio(struct ata_port *ap, const struct ata_taskfile *tf); static void pdc_exec_command_mmio(struct ata_port *ap, const struct ata_taskfile *tf); +static int pdc_check_atapi_dma(struct ata_queued_cmd *qc); +static int pdc_old_check_atapi_dma(struct ata_queued_cmd *qc); static void pdc_irq_clear(struct ata_port *ap); static unsigned int pdc_qc_issue_prot(struct ata_queued_cmd *qc); -static void pdc_host_stop(struct ata_host *host); static void pdc_freeze(struct ata_port *ap); static void pdc_thaw(struct ata_port *ap); static void pdc_error_handler(struct ata_port *ap); @@ -139,6 +158,7 @@ static const struct ata_port_operations .check_status = ata_check_status, .exec_command = pdc_exec_command_mmio, .dev_select = ata_std_dev_select, + .check_atapi_dma = pdc_check_atapi_dma, .qc_prep = pdc_qc_prep, .qc_issue = pdc_qc_issue_prot, @@ -146,48 +166,76 @@ static const struct ata_port_operations .thaw = pdc_thaw, .error_handler = pdc_error_handler, .post_internal_cmd = pdc_post_internal_cmd, - .data_xfer = ata_mmio_data_xfer, + .data_xfer = ata_data_xfer, .irq_handler = pdc_interrupt, .irq_clear = pdc_irq_clear, + .irq_on = ata_irq_on, + .irq_ack = ata_irq_ack, .scr_read = pdc_sata_scr_read, .scr_write = pdc_sata_scr_write, .port_start = pdc_port_start, - .port_stop = pdc_port_stop, - .host_stop = pdc_host_stop, }; -static const struct ata_port_operations pdc_pata_ops = { +/* First-generation chips need a more restrictive ->check_atapi_dma op */ +static const struct ata_port_operations pdc_old_sata_ops = { .port_disable = ata_port_disable, .tf_load = pdc_tf_load_mmio, .tf_read = ata_tf_read, .check_status = ata_check_status, .exec_command = pdc_exec_command_mmio, .dev_select = ata_std_dev_select, + .check_atapi_dma = pdc_old_check_atapi_dma, - .phy_reset = pdc_pata_phy_reset, + .qc_prep = pdc_qc_prep, + .qc_issue = pdc_qc_issue_prot, + .freeze = pdc_freeze, + .thaw = pdc_thaw, + .error_handler = pdc_error_handler, + .post_internal_cmd = pdc_post_internal_cmd, + .data_xfer = ata_data_xfer, + .irq_handler = pdc_interrupt, + .irq_clear = pdc_irq_clear, + .irq_on = ata_irq_on, + .irq_ack = ata_irq_ack, + + .scr_read = pdc_sata_scr_read, + .scr_write = pdc_sata_scr_write, + .port_start = pdc_port_start, +}; + +static const struct ata_port_operations pdc_pata_ops = { + .port_disable = ata_port_disable, + .tf_load = pdc_tf_load_mmio, + .tf_read = ata_tf_read, + .check_status = ata_check_status, + .exec_command = pdc_exec_command_mmio, + .dev_select = ata_std_dev_select, + .check_atapi_dma = pdc_check_atapi_dma, .qc_prep = pdc_qc_prep, .qc_issue = pdc_qc_issue_prot, - .data_xfer = ata_mmio_data_xfer, - .eng_timeout = pdc_eng_timeout, + .freeze = pdc_freeze, + .thaw = pdc_thaw, + .error_handler = pdc_error_handler, + .data_xfer = ata_data_xfer, .irq_handler = pdc_interrupt, .irq_clear = pdc_irq_clear, + .irq_on = ata_irq_on, + .irq_ack = ata_irq_ack, .port_start = pdc_port_start, - .port_stop = pdc_port_stop, - .host_stop = pdc_host_stop, }; static const struct ata_port_info pdc_port_info[] = { /* board_2037x */ { .sht = &pdc_ata_sht, - .flags = PDC_COMMON_FLAGS | ATA_FLAG_SATA, + .flags = PDC_COMMON_FLAGS, .pio_mask = 0x1f, /* pio0-4 */ .mwdma_mask = 0x07, /* mwdma0-2 */ .udma_mask = 0x7f, /* udma0-6 ; FIXME */ - .port_ops = &pdc_sata_ops, + .port_ops = &pdc_old_sata_ops, }, /* board_20319 */ @@ -197,13 +245,13 @@ static const struct ata_port_info pdc_po .pio_mask = 0x1f, /* pio0-4 */ .mwdma_mask = 0x07, /* mwdma0-2 */ .udma_mask = 0x7f, /* udma0-6 ; FIXME */ - .port_ops = &pdc_sata_ops, + .port_ops = &pdc_old_sata_ops, }, /* board_20619 */ { .sht = &pdc_ata_sht, - .flags = PDC_COMMON_FLAGS | ATA_FLAG_SRST | ATA_FLAG_SLAVE_POSS, + .flags = PDC_COMMON_FLAGS | ATA_FLAG_SLAVE_POSS, .pio_mask = 0x1f, /* pio0-4 */ .mwdma_mask = 0x07, /* mwdma0-2 */ .udma_mask = 0x7f, /* udma0-6 ; FIXME */ @@ -213,7 +261,7 @@ static const struct ata_port_info pdc_po /* board_2057x */ { .sht = &pdc_ata_sht, - .flags = PDC_COMMON_FLAGS | ATA_FLAG_SATA, + .flags = PDC_COMMON_FLAGS, .pio_mask = 0x1f, /* pio0-4 */ .mwdma_mask = 0x07, /* mwdma0-2 */ .udma_mask = 0x7f, /* udma0-6 ; FIXME */ @@ -271,21 +319,22 @@ static int pdc_port_start(struct ata_por struct pdc_port_priv *pp; int rc; + /* fix up port flags and cable type for SATA+PATA chips */ + ap->flags |= hp->port_flags[ap->port_no]; + if (ap->flags & ATA_FLAG_SATA) + ap->cbl = ATA_CBL_SATA; + rc = ata_port_start(ap); if (rc) return rc; - pp = kzalloc(sizeof(*pp), GFP_KERNEL); - if (!pp) { - rc = -ENOMEM; - goto err_out; - } + pp = devm_kzalloc(dev, sizeof(*pp), GFP_KERNEL); + if (!pp) + return -ENOMEM; - pp->pkt = dma_alloc_coherent(dev, 128, &pp->pkt_dma, GFP_KERNEL); - if (!pp->pkt) { - rc = -ENOMEM; - goto err_out_kfree; - } + pp->pkt = dmam_alloc_coherent(dev, 128, &pp->pkt_dma, GFP_KERNEL); + if (!pp->pkt) + return -ENOMEM; ap->private_data = pp; @@ -300,40 +349,11 @@ static int pdc_port_start(struct ata_por } return 0; - -err_out_kfree: - kfree(pp); -err_out: - ata_port_stop(ap); - return rc; } - -static void pdc_port_stop(struct ata_port *ap) -{ - struct device *dev = ap->host->dev; - struct pdc_port_priv *pp = ap->private_data; - - ap->private_data = NULL; - dma_free_coherent(dev, 128, pp->pkt, pp->pkt_dma); - kfree(pp); - ata_port_stop(ap); -} - - -static void pdc_host_stop(struct ata_host *host) -{ - struct pdc_host_priv *hp = host->private_data; - - ata_pci_host_stop(host); - - kfree(hp); -} - - static void pdc_reset_port(struct ata_port *ap) { - void __iomem *mmio = (void __iomem *) ap->ioaddr.cmd_addr + PDC_CTLSTAT; + void __iomem *mmio = ap->ioaddr.cmd_addr + PDC_CTLSTAT; unsigned int i; u32 tmp; @@ -367,28 +387,104 @@ static void pdc_pata_cbl_detect(struct a ap->cbl = ATA_CBL_PATA80; } -static void pdc_pata_phy_reset(struct ata_port *ap) -{ - pdc_pata_cbl_detect(ap); - pdc_reset_port(ap); - ata_port_probe(ap); - ata_bus_reset(ap); -} - static u32 pdc_sata_scr_read (struct ata_port *ap, unsigned int sc_reg) { - if (sc_reg > SCR_CONTROL) + if (sc_reg > SCR_CONTROL || ap->cbl != ATA_CBL_SATA) return 0xffffffffU; - return readl((void __iomem *) ap->ioaddr.scr_addr + (sc_reg * 4)); + return readl(ap->ioaddr.scr_addr + (sc_reg * 4)); } static void pdc_sata_scr_write (struct ata_port *ap, unsigned int sc_reg, u32 val) { - if (sc_reg > SCR_CONTROL) + if (sc_reg > SCR_CONTROL || ap->cbl != ATA_CBL_SATA) return; - writel(val, (void __iomem *) ap->ioaddr.scr_addr + (sc_reg * 4)); + writel(val, ap->ioaddr.scr_addr + (sc_reg * 4)); +} + +static void pdc_atapi_pkt(struct ata_queued_cmd *qc) +{ + struct ata_port *ap = qc->ap; + dma_addr_t sg_table = ap->prd_dma; + unsigned int cdb_len = qc->dev->cdb_len; + u8 *cdb = qc->cdb; + struct pdc_port_priv *pp = ap->private_data; + u8 *buf = pp->pkt; + u32 *buf32 = (u32 *) buf; + unsigned int dev_sel, feature, nbytes; + + /* set control bits (byte 0), zero delay seq id (byte 3), + * and seq id (byte 2) + */ + switch (qc->tf.protocol) { + case ATA_PROT_ATAPI_DMA: + if (!(qc->tf.flags & ATA_TFLAG_WRITE)) + buf32[0] = cpu_to_le32(PDC_PKT_READ); + else + buf32[0] = 0; + break; + case ATA_PROT_ATAPI_NODATA: + buf32[0] = cpu_to_le32(PDC_PKT_NODATA); + break; + default: + BUG(); + break; + } + buf32[1] = cpu_to_le32(sg_table); /* S/G table addr */ + buf32[2] = 0; /* no next-packet */ + + /* select drive */ + if (sata_scr_valid(ap)) { + dev_sel = PDC_DEVICE_SATA; + } else { + dev_sel = ATA_DEVICE_OBS; + if (qc->dev->devno != 0) + dev_sel |= ATA_DEV1; + } + buf[12] = (1 << 5) | ATA_REG_DEVICE; + buf[13] = dev_sel; + buf[14] = (1 << 5) | ATA_REG_DEVICE | PDC_PKT_CLEAR_BSY; + buf[15] = dev_sel; /* once more, waiting for BSY to clear */ + + buf[16] = (1 << 5) | ATA_REG_NSECT; + buf[17] = 0x00; + buf[18] = (1 << 5) | ATA_REG_LBAL; + buf[19] = 0x00; + + /* set feature and byte counter registers */ + if (qc->tf.protocol != ATA_PROT_ATAPI_DMA) { + feature = PDC_FEATURE_ATAPI_PIO; + /* set byte counter register to real transfer byte count */ + nbytes = qc->nbytes; + if (nbytes > 0xffff) + nbytes = 0xffff; + } else { + feature = PDC_FEATURE_ATAPI_DMA; + /* set byte counter register to 0 */ + nbytes = 0; + } + buf[20] = (1 << 5) | ATA_REG_FEATURE; + buf[21] = feature; + buf[22] = (1 << 5) | ATA_REG_BYTEL; + buf[23] = nbytes & 0xFF; + buf[24] = (1 << 5) | ATA_REG_BYTEH; + buf[25] = (nbytes >> 8) & 0xFF; + + /* send ATAPI packet command 0xA0 */ + buf[26] = (1 << 5) | ATA_REG_CMD; + buf[27] = ATA_CMD_PACKET; + + /* select drive and check DRQ */ + buf[28] = (1 << 5) | ATA_REG_DEVICE | PDC_PKT_WAIT_DRDY; + buf[29] = dev_sel; + + /* we can represent cdb lengths 2/4/6/8/10/12/14/16 */ + BUG_ON(cdb_len & ~0x1E); + + /* append the CDB as the final part */ + buf[30] = (((cdb_len >> 1) & 7) << 5) | ATA_REG_DATA | PDC_LAST_REG; + memcpy(buf+31, cdb, cdb_len); } static void pdc_qc_prep(struct ata_queued_cmd *qc) @@ -415,6 +511,17 @@ static void pdc_qc_prep(struct ata_queue pdc_pkt_footer(&qc->tf, pp->pkt, i); break; + case ATA_PROT_ATAPI: + ata_qc_prep(qc); + break; + + case ATA_PROT_ATAPI_DMA: + ata_qc_prep(qc); + /*FALLTHROUGH*/ + case ATA_PROT_ATAPI_NODATA: + pdc_atapi_pkt(qc); + break; + default: break; } @@ -447,6 +554,13 @@ static void pdc_thaw(struct ata_port *ap readl(mmio + PDC_CTLSTAT); /* flush */ } +static int pdc_pre_reset(struct ata_port *ap) +{ + if (!sata_scr_valid(ap)) + pdc_pata_cbl_detect(ap); + return ata_std_prereset(ap); +} + static void pdc_error_handler(struct ata_port *ap) { ata_reset_fn_t hardreset; @@ -459,7 +573,7 @@ static void pdc_error_handler(struct ata hardreset = sata_std_hardreset; /* perform recovery */ - ata_do_eh(ap, ata_std_prereset, ata_std_softreset, hardreset, + ata_do_eh(ap, pdc_pre_reset, ata_std_softreset, hardreset, ata_std_postreset); } @@ -475,49 +589,12 @@ static void pdc_post_internal_cmd(struct pdc_reset_port(ap); } -static void pdc_eng_timeout(struct ata_port *ap) -{ - struct ata_host *host = ap->host; - u8 drv_stat; - struct ata_queued_cmd *qc; - unsigned long flags; - - DPRINTK("ENTER\n"); - - spin_lock_irqsave(&host->lock, flags); - - qc = ata_qc_from_tag(ap, ap->active_tag); - - switch (qc->tf.protocol) { - case ATA_PROT_DMA: - case ATA_PROT_NODATA: - ata_port_printk(ap, KERN_ERR, "command timeout\n"); - drv_stat = ata_wait_idle(ap); - qc->err_mask |= __ac_err_mask(drv_stat); - break; - - default: - drv_stat = ata_busy_wait(ap, ATA_BUSY | ATA_DRQ, 1000); - - ata_port_printk(ap, KERN_ERR, - "unknown timeout, cmd 0x%x stat 0x%x\n", - qc->tf.command, drv_stat); - - qc->err_mask |= ac_err_mask(drv_stat); - break; - } - - spin_unlock_irqrestore(&host->lock, flags); - ata_eh_qc_complete(qc); - DPRINTK("EXIT\n"); -} - static inline unsigned int pdc_host_intr( struct ata_port *ap, struct ata_queued_cmd *qc) { unsigned int handled = 0; u32 tmp; - void __iomem *mmio = (void __iomem *) ap->ioaddr.cmd_addr + PDC_GLOBAL_CTL; + void __iomem *mmio = ap->ioaddr.cmd_addr + PDC_GLOBAL_CTL; tmp = readl(mmio); if (tmp & PDC_ERR_MASK) { @@ -528,6 +605,8 @@ static inline unsigned int pdc_host_intr switch (qc->tf.protocol) { case ATA_PROT_DMA: case ATA_PROT_NODATA: + case ATA_PROT_ATAPI_DMA: + case ATA_PROT_ATAPI_NODATA: qc->err_mask |= ac_err_mask(ata_wait_idle(ap)); ata_qc_complete(qc); handled = 1; @@ -544,7 +623,7 @@ static inline unsigned int pdc_host_intr static void pdc_irq_clear(struct ata_port *ap) { struct ata_host *host = ap->host; - void __iomem *mmio = host->mmio_base; + void __iomem *mmio = host->iomap[PDC_MMIO_BAR]; readl(mmio + PDC_INT_SEQMASK); } @@ -560,12 +639,12 @@ static irqreturn_t pdc_interrupt (int ir VPRINTK("ENTER\n"); - if (!host || !host->mmio_base) { + if (!host || !host->iomap[PDC_MMIO_BAR]) { VPRINTK("QUICK EXIT\n"); return IRQ_NONE; } - mmio_base = host->mmio_base; + mmio_base = host->iomap[PDC_MMIO_BAR]; /* reading should also clear interrupts */ mask = readl(mmio_base + PDC_INT_SEQMASK); @@ -610,32 +689,34 @@ static inline void pdc_packet_start(stru { struct ata_port *ap = qc->ap; struct pdc_port_priv *pp = ap->private_data; + void __iomem *mmio = ap->host->iomap[PDC_MMIO_BAR]; unsigned int port_no = ap->port_no; u8 seq = (u8) (port_no + 1); VPRINTK("ENTER, ap %p\n", ap); - writel(0x00000001, ap->host->mmio_base + (seq * 4)); - readl(ap->host->mmio_base + (seq * 4)); /* flush */ + writel(0x00000001, mmio + (seq * 4)); + readl(mmio + (seq * 4)); /* flush */ pp->pkt[2] = seq; wmb(); /* flush PRD, pkt writes */ - writel(pp->pkt_dma, (void __iomem *) ap->ioaddr.cmd_addr + PDC_PKT_SUBMIT); - readl((void __iomem *) ap->ioaddr.cmd_addr + PDC_PKT_SUBMIT); /* flush */ + writel(pp->pkt_dma, ap->ioaddr.cmd_addr + PDC_PKT_SUBMIT); + readl(ap->ioaddr.cmd_addr + PDC_PKT_SUBMIT); /* flush */ } static unsigned int pdc_qc_issue_prot(struct ata_queued_cmd *qc) { switch (qc->tf.protocol) { + case ATA_PROT_ATAPI_NODATA: + if (qc->dev->flags & ATA_DFLAG_CDB_INTR) + break; + /*FALLTHROUGH*/ + case ATA_PROT_ATAPI_DMA: case ATA_PROT_DMA: case ATA_PROT_NODATA: pdc_packet_start(qc); return 0; - case ATA_PROT_ATAPI_DMA: - BUG(); - break; - default: break; } @@ -658,8 +739,44 @@ static void pdc_exec_command_mmio(struct ata_exec_command(ap, tf); } +static int pdc_check_atapi_dma(struct ata_queued_cmd *qc) +{ + u8 *scsicmd = qc->scsicmd->cmnd; + int pio = 1; /* atapi dma off by default */ + + /* Whitelist commands that may use DMA. */ + switch (scsicmd[0]) { + case WRITE_12: + case WRITE_10: + case WRITE_6: + case READ_12: + case READ_10: + case READ_6: + case 0xad: /* READ_DVD_STRUCTURE */ + case 0xbe: /* READ_CD */ + pio = 0; + } + /* -45150 (FFFF4FA2) to -1 (FFFFFFFF) shall use PIO mode */ + if (scsicmd[0] == WRITE_10) { + unsigned int lba; + lba = (scsicmd[2] << 24) | (scsicmd[3] << 16) | (scsicmd[4] << 8) | scsicmd[5]; + if (lba >= 0xFFFF4FA2) + pio = 1; + } + return pio; +} + +static int pdc_old_check_atapi_dma(struct ata_queued_cmd *qc) +{ + struct ata_port *ap = qc->ap; + + /* First generation chips cannot use ATAPI DMA on SATA ports */ + if (sata_scr_valid(ap)) + return 1; + return pdc_check_atapi_dma(qc); +} -static void pdc_ata_setup_port(struct ata_ioports *port, unsigned long base) +static void pdc_ata_setup_port(struct ata_ioports *port, void __iomem *base) { port->cmd_addr = base; port->data_addr = base; @@ -679,7 +796,7 @@ static void pdc_ata_setup_port(struct at static void pdc_host_init(unsigned int chip_id, struct ata_probe_ent *pe) { - void __iomem *mmio = pe->mmio_base; + void __iomem *mmio = pe->iomap[PDC_MMIO_BAR]; struct pdc_host_priv *hp = pe->private_data; int hotplug_offset; u32 tmp; @@ -733,55 +850,43 @@ static void pdc_host_init(unsigned int c static int pdc_ata_init_one (struct pci_dev *pdev, const struct pci_device_id *ent) { static int printed_version; - struct ata_probe_ent *probe_ent = NULL; + struct ata_probe_ent *probe_ent; struct pdc_host_priv *hp; - unsigned long base; - void __iomem *mmio_base; + void __iomem *base; unsigned int board_idx = (unsigned int) ent->driver_data; - int pci_dev_busy = 0; int rc; + u8 tmp; if (!printed_version++) dev_printk(KERN_DEBUG, &pdev->dev, "version " DRV_VERSION "\n"); - rc = pci_enable_device(pdev); + rc = pcim_enable_device(pdev); if (rc) return rc; - rc = pci_request_regions(pdev, DRV_NAME); - if (rc) { - pci_dev_busy = 1; - goto err_out; - } + rc = pcim_iomap_regions(pdev, 1 << PDC_MMIO_BAR, DRV_NAME); + if (rc == -EBUSY) + pcim_pin_device(pdev); + if (rc) + return rc; rc = pci_set_dma_mask(pdev, ATA_DMA_MASK); if (rc) - goto err_out_regions; + return rc; rc = pci_set_consistent_dma_mask(pdev, ATA_DMA_MASK); if (rc) - goto err_out_regions; + return rc; - probe_ent = kzalloc(sizeof(*probe_ent), GFP_KERNEL); - if (probe_ent == NULL) { - rc = -ENOMEM; - goto err_out_regions; - } + probe_ent = devm_kzalloc(&pdev->dev, sizeof(*probe_ent), GFP_KERNEL); + if (probe_ent == NULL) + return -ENOMEM; probe_ent->dev = pci_dev_to_dev(pdev); INIT_LIST_HEAD(&probe_ent->node); - mmio_base = pci_iomap(pdev, 3, 0); - if (mmio_base == NULL) { - rc = -ENOMEM; - goto err_out_free_ent; - } - base = (unsigned long) mmio_base; - - hp = kzalloc(sizeof(*hp), GFP_KERNEL); - if (hp == NULL) { - rc = -ENOMEM; - goto err_out_free_ent; - } + hp = devm_kzalloc(&pdev->dev, sizeof(*hp), GFP_KERNEL); + if (hp == NULL) + return -ENOMEM; probe_ent->private_data = hp; @@ -794,7 +899,9 @@ static int pdc_ata_init_one (struct pci_ probe_ent->irq = pdev->irq; probe_ent->irq_flags = IRQF_SHARED; - probe_ent->mmio_base = mmio_base; + probe_ent->iomap = pcim_iomap_table(pdev); + + base = probe_ent->iomap[PDC_MMIO_BAR]; pdc_ata_setup_port(&probe_ent->port[0], base + 0x200); pdc_ata_setup_port(&probe_ent->port[1], base + 0x280); @@ -820,7 +927,17 @@ static int pdc_ata_init_one (struct pci_ hp->flags |= PDC_FLAG_GEN_II; /* Fall through */ case board_2037x: - probe_ent->n_ports = 2; + /* TX2plus boards also have a PATA port */ + tmp = readb(base + PDC_FLASH_CTL+1); + if (!(tmp & 0x80)) { + probe_ent->n_ports = 3; + pdc_ata_setup_port(&probe_ent->port[2], base + 0x300); + hp->port_flags[2] = ATA_FLAG_SLAVE_POSS; + printk(KERN_INFO DRV_NAME " PATA port found\n"); + } else + probe_ent->n_ports = 2; + hp->port_flags[0] = ATA_FLAG_SATA; + hp->port_flags[1] = ATA_FLAG_SATA; break; case board_20619: probe_ent->n_ports = 4; @@ -841,22 +958,11 @@ static int pdc_ata_init_one (struct pci_ /* initialize adapter */ pdc_host_init(board_idx, probe_ent); - /* FIXME: Need any other frees than hp? */ if (!ata_device_add(probe_ent)) - kfree(hp); - - kfree(probe_ent); + return -ENODEV; + devm_kfree(&pdev->dev, probe_ent); return 0; - -err_out_free_ent: - kfree(probe_ent); -err_out_regions: - pci_release_regions(pdev); -err_out: - if (!pci_dev_busy) - pci_disable_device(pdev); - return rc; } diff --git a/drivers/ata/sata_qstor.c b/drivers/ata/sata_qstor.c index 710909d..6097d8f 100644 --- a/drivers/ata/sata_qstor.c +++ b/drivers/ata/sata_qstor.c @@ -34,16 +34,16 @@ #include #include #include #include -#include #include #include -#include #include #define DRV_NAME "sata_qstor" #define DRV_VERSION "0.06" enum { + QS_MMIO_BAR = 4, + QS_PORTS = 4, QS_MAX_PRD = LIBATA_MAX_PRD, QS_CPB_ORDER = 6, @@ -117,7 +117,6 @@ static int qs_ata_init_one (struct pci_d static irqreturn_t qs_intr (int irq, void *dev_instance); static int qs_port_start(struct ata_port *ap); static void qs_host_stop(struct ata_host *host); -static void qs_port_stop(struct ata_port *ap); static void qs_phy_reset(struct ata_port *ap); static void qs_qc_prep(struct ata_queued_cmd *qc); static unsigned int qs_qc_issue(struct ata_queued_cmd *qc); @@ -157,14 +156,15 @@ static const struct ata_port_operations .phy_reset = qs_phy_reset, .qc_prep = qs_qc_prep, .qc_issue = qs_qc_issue, - .data_xfer = ata_mmio_data_xfer, + .data_xfer = ata_data_xfer, .eng_timeout = qs_eng_timeout, .irq_handler = qs_intr, .irq_clear = qs_irq_clear, + .irq_on = ata_irq_on, + .irq_ack = ata_irq_ack, .scr_read = qs_scr_read, .scr_write = qs_scr_write, .port_start = qs_port_start, - .port_stop = qs_port_stop, .host_stop = qs_host_stop, .bmdma_stop = qs_bmdma_stop, .bmdma_status = qs_bmdma_status, @@ -197,6 +197,11 @@ static struct pci_driver qs_ata_pci_driv .remove = ata_pci_remove_one, }; +static void __iomem *qs_mmio_base(struct ata_host *host) +{ + return host->iomap[QS_MMIO_BAR]; +} + static int qs_check_atapi_dma(struct ata_queued_cmd *qc) { return 1; /* ATAPI DMA not supported */ @@ -219,7 +224,7 @@ static void qs_irq_clear(struct ata_port static inline void qs_enter_reg_mode(struct ata_port *ap) { - u8 __iomem *chan = ap->host->mmio_base + (ap->port_no * 0x4000); + u8 __iomem *chan = qs_mmio_base(ap->host) + (ap->port_no * 0x4000); writeb(QS_CTR0_REG, chan + QS_CCT_CTR0); readb(chan + QS_CCT_CTR0); /* flush */ @@ -227,7 +232,7 @@ static inline void qs_enter_reg_mode(str static inline void qs_reset_channel_logic(struct ata_port *ap) { - u8 __iomem *chan = ap->host->mmio_base + (ap->port_no * 0x4000); + u8 __iomem *chan = qs_mmio_base(ap->host) + (ap->port_no * 0x4000); writeb(QS_CTR1_RCHN, chan + QS_CCT_CTR1); readb(chan + QS_CCT_CTR0); /* flush */ @@ -257,14 +262,14 @@ static u32 qs_scr_read (struct ata_port { if (sc_reg > SCR_CONTROL) return ~0U; - return readl((void __iomem *)(ap->ioaddr.scr_addr + (sc_reg * 8))); + return readl(ap->ioaddr.scr_addr + (sc_reg * 8)); } static void qs_scr_write (struct ata_port *ap, unsigned int sc_reg, u32 val) { if (sc_reg > SCR_CONTROL) return; - writel(val, (void __iomem *)(ap->ioaddr.scr_addr + (sc_reg * 8))); + writel(val, ap->ioaddr.scr_addr + (sc_reg * 8)); } static unsigned int qs_fill_sg(struct ata_queued_cmd *qc) @@ -325,7 +330,7 @@ static void qs_qc_prep(struct ata_queued /* host control block (HCB) */ buf[ 0] = QS_HCB_HDR; buf[ 1] = hflags; - *(__le32 *)(&buf[ 4]) = cpu_to_le32(qc->nsect * ATA_SECT_SIZE); + *(__le32 *)(&buf[ 4]) = cpu_to_le32(qc->nbytes); *(__le32 *)(&buf[ 8]) = cpu_to_le32(nelem); addr = ((u64)pp->pkt_dma) + QS_CPB_BYTES; *(__le64 *)(&buf[16]) = cpu_to_le64(addr); @@ -341,7 +346,7 @@ static void qs_qc_prep(struct ata_queued static inline void qs_packet_start(struct ata_queued_cmd *qc) { struct ata_port *ap = qc->ap; - u8 __iomem *chan = ap->host->mmio_base + (ap->port_no * 0x4000); + u8 __iomem *chan = qs_mmio_base(ap->host) + (ap->port_no * 0x4000); VPRINTK("ENTER, ap %p\n", ap); @@ -378,7 +383,7 @@ static inline unsigned int qs_intr_pkt(s { unsigned int handled = 0; u8 sFFE; - u8 __iomem *mmio_base = host->mmio_base; + u8 __iomem *mmio_base = qs_mmio_base(host); do { u32 sff0 = readl(mmio_base + QS_HST_SFF); @@ -470,7 +475,7 @@ static irqreturn_t qs_intr(int irq, void return IRQ_RETVAL(handled); } -static void qs_ata_setup_port(struct ata_ioports *port, unsigned long base) +static void qs_ata_setup_port(struct ata_ioports *port, void __iomem *base) { port->cmd_addr = port->data_addr = base + 0x400; @@ -492,7 +497,7 @@ static int qs_port_start(struct ata_port { struct device *dev = ap->host->dev; struct qs_port_priv *pp; - void __iomem *mmio_base = ap->host->mmio_base; + void __iomem *mmio_base = qs_mmio_base(ap->host); void __iomem *chan = mmio_base + (ap->port_no * 0x4000); u64 addr; int rc; @@ -501,17 +506,13 @@ static int qs_port_start(struct ata_port if (rc) return rc; qs_enter_reg_mode(ap); - pp = kzalloc(sizeof(*pp), GFP_KERNEL); - if (!pp) { - rc = -ENOMEM; - goto err_out; - } - pp->pkt = dma_alloc_coherent(dev, QS_PKT_BYTES, &pp->pkt_dma, - GFP_KERNEL); - if (!pp->pkt) { - rc = -ENOMEM; - goto err_out_kfree; - } + pp = devm_kzalloc(dev, sizeof(*pp), GFP_KERNEL); + if (!pp) + return -ENOMEM; + pp->pkt = dmam_alloc_coherent(dev, QS_PKT_BYTES, &pp->pkt_dma, + GFP_KERNEL); + if (!pp->pkt) + return -ENOMEM; memset(pp->pkt, 0, QS_PKT_BYTES); ap->private_data = pp; @@ -519,43 +520,19 @@ static int qs_port_start(struct ata_port writel((u32) addr, chan + QS_CCF_CPBA); writel((u32)(addr >> 32), chan + QS_CCF_CPBA + 4); return 0; - -err_out_kfree: - kfree(pp); -err_out: - ata_port_stop(ap); - return rc; -} - -static void qs_port_stop(struct ata_port *ap) -{ - struct device *dev = ap->host->dev; - struct qs_port_priv *pp = ap->private_data; - - if (pp != NULL) { - ap->private_data = NULL; - if (pp->pkt != NULL) - dma_free_coherent(dev, QS_PKT_BYTES, pp->pkt, - pp->pkt_dma); - kfree(pp); - } - ata_port_stop(ap); } static void qs_host_stop(struct ata_host *host) { - void __iomem *mmio_base = host->mmio_base; - struct pci_dev *pdev = to_pci_dev(host->dev); + void __iomem *mmio_base = qs_mmio_base(host); writeb(0, mmio_base + QS_HCT_CTRL); /* disable host interrupts */ writeb(QS_CNFG3_GSRST, mmio_base + QS_HCF_CNFG3); /* global reset */ - - pci_iounmap(pdev, mmio_base); } static void qs_host_init(unsigned int chip_id, struct ata_probe_ent *pe) { - void __iomem *mmio_base = pe->mmio_base; + void __iomem *mmio_base = pe->iomap[QS_MMIO_BAR]; unsigned int port_no; writeb(0, mmio_base + QS_HCT_CTRL); /* disable host interrupts */ @@ -630,44 +607,34 @@ static int qs_ata_init_one(struct pci_de const struct pci_device_id *ent) { static int printed_version; - struct ata_probe_ent *probe_ent = NULL; - void __iomem *mmio_base; + struct ata_probe_ent *probe_ent; + void __iomem * const *iomap; unsigned int board_idx = (unsigned int) ent->driver_data; int rc, port_no; if (!printed_version++) dev_printk(KERN_DEBUG, &pdev->dev, "version " DRV_VERSION "\n"); - rc = pci_enable_device(pdev); + rc = pcim_enable_device(pdev); if (rc) return rc; - rc = pci_request_regions(pdev, DRV_NAME); - if (rc) - goto err_out; - - if ((pci_resource_flags(pdev, 4) & IORESOURCE_MEM) == 0) { - rc = -ENODEV; - goto err_out_regions; - } + if ((pci_resource_flags(pdev, QS_MMIO_BAR) & IORESOURCE_MEM) == 0) + return -ENODEV; - mmio_base = pci_iomap(pdev, 4, 0); - if (mmio_base == NULL) { - rc = -ENOMEM; - goto err_out_regions; - } + rc = pcim_iomap_regions(pdev, 1 << QS_MMIO_BAR, DRV_NAME); + if (rc) + return rc; + iomap = pcim_iomap_table(pdev); - rc = qs_set_dma_masks(pdev, mmio_base); + rc = qs_set_dma_masks(pdev, iomap[QS_MMIO_BAR]); if (rc) - goto err_out_iounmap; + return rc; - probe_ent = kmalloc(sizeof(*probe_ent), GFP_KERNEL); - if (probe_ent == NULL) { - rc = -ENOMEM; - goto err_out_iounmap; - } + probe_ent = devm_kzalloc(&pdev->dev, sizeof(*probe_ent), GFP_KERNEL); + if (probe_ent == NULL) + return -ENOMEM; - memset(probe_ent, 0, sizeof(*probe_ent)); probe_ent->dev = pci_dev_to_dev(pdev); INIT_LIST_HEAD(&probe_ent->node); @@ -680,12 +647,12 @@ static int qs_ata_init_one(struct pci_de probe_ent->irq = pdev->irq; probe_ent->irq_flags = IRQF_SHARED; - probe_ent->mmio_base = mmio_base; + probe_ent->iomap = iomap; probe_ent->n_ports = QS_PORTS; for (port_no = 0; port_no < probe_ent->n_ports; ++port_no) { - unsigned long chan = (unsigned long)mmio_base + - (port_no * 0x4000); + void __iomem *chan = + probe_ent->iomap[QS_MMIO_BAR] + (port_no * 0x4000); qs_ata_setup_port(&probe_ent->port[port_no], chan); } @@ -694,19 +661,11 @@ static int qs_ata_init_one(struct pci_de /* initialize adapter */ qs_host_init(board_idx, probe_ent); - rc = ata_device_add(probe_ent); - kfree(probe_ent); - if (rc != QS_PORTS) - goto err_out_iounmap; - return 0; + if (ata_device_add(probe_ent) != QS_PORTS) + return -EIO; -err_out_iounmap: - pci_iounmap(pdev, mmio_base); -err_out_regions: - pci_release_regions(pdev); -err_out: - pci_disable_device(pdev); - return rc; + devm_kfree(&pdev->dev, probe_ent); + return 0; } static int __init qs_ata_init(void) diff --git a/drivers/ata/sata_sil.c b/drivers/ata/sata_sil.c index 7808d03..dca3d37 100644 --- a/drivers/ata/sata_sil.c +++ b/drivers/ata/sata_sil.c @@ -49,6 +49,8 @@ #define DRV_NAME "sata_sil" #define DRV_VERSION "2.0" enum { + SIL_MMIO_BAR = 5, + /* * host flags */ @@ -200,18 +202,18 @@ static const struct ata_port_operations .bmdma_status = ata_bmdma_status, .qc_prep = ata_qc_prep, .qc_issue = ata_qc_issue_prot, - .data_xfer = ata_mmio_data_xfer, + .data_xfer = ata_data_xfer, .freeze = sil_freeze, .thaw = sil_thaw, .error_handler = ata_bmdma_error_handler, .post_internal_cmd = ata_bmdma_post_internal_cmd, .irq_handler = sil_interrupt, .irq_clear = ata_bmdma_irq_clear, + .irq_on = ata_irq_on, + .irq_ack = ata_irq_ack, .scr_read = sil_scr_read, .scr_write = sil_scr_write, .port_start = ata_port_start, - .port_stop = ata_port_stop, - .host_stop = ata_pci_host_stop, }; static const struct ata_port_info sil_port_info[] = { @@ -297,7 +299,8 @@ static void sil_post_set_mode (struct at { struct ata_host *host = ap->host; struct ata_device *dev; - void __iomem *addr = host->mmio_base + sil_port[ap->port_no].xfer_mode; + void __iomem *mmio_base = host->iomap[SIL_MMIO_BAR]; + void __iomem *addr = mmio_base + sil_port[ap->port_no].xfer_mode; u32 tmp, dev_mode[2]; unsigned int i; @@ -320,9 +323,9 @@ static void sil_post_set_mode (struct at readl(addr); /* flush */ } -static inline unsigned long sil_scr_addr(struct ata_port *ap, unsigned int sc_reg) +static inline void __iomem *sil_scr_addr(struct ata_port *ap, unsigned int sc_reg) { - unsigned long offset = ap->ioaddr.scr_addr; + void __iomem *offset = ap->ioaddr.scr_addr; switch (sc_reg) { case SCR_STATUS: @@ -341,7 +344,7 @@ static inline unsigned long sil_scr_addr static u32 sil_scr_read (struct ata_port *ap, unsigned int sc_reg) { - void __iomem *mmio = (void __iomem *) sil_scr_addr(ap, sc_reg); + void __iomem *mmio = sil_scr_addr(ap, sc_reg); if (mmio) return readl(mmio); return 0xffffffffU; @@ -349,7 +352,7 @@ static u32 sil_scr_read (struct ata_port static void sil_scr_write (struct ata_port *ap, unsigned int sc_reg, u32 val) { - void __iomem *mmio = (void __iomem *) sil_scr_addr(ap, sc_reg); + void __iomem *mmio = sil_scr_addr(ap, sc_reg); if (mmio) writel(val, mmio); } @@ -444,7 +447,7 @@ static void sil_host_intr(struct ata_por static irqreturn_t sil_interrupt(int irq, void *dev_instance) { struct ata_host *host = dev_instance; - void __iomem *mmio_base = host->mmio_base; + void __iomem *mmio_base = host->iomap[SIL_MMIO_BAR]; int handled = 0; int i; @@ -476,7 +479,7 @@ static irqreturn_t sil_interrupt(int irq static void sil_freeze(struct ata_port *ap) { - void __iomem *mmio_base = ap->host->mmio_base; + void __iomem *mmio_base = ap->host->iomap[SIL_MMIO_BAR]; u32 tmp; /* global IRQ mask doesn't block SATA IRQ, turn off explicitly */ @@ -491,7 +494,7 @@ static void sil_freeze(struct ata_port * static void sil_thaw(struct ata_port *ap) { - void __iomem *mmio_base = ap->host->mmio_base; + void __iomem *mmio_base = ap->host->iomap[SIL_MMIO_BAR]; u32 tmp; /* clear IRQ */ @@ -541,9 +544,9 @@ static void sil_dev_config(struct ata_po { int print_info = ap->eh_context.i.flags & ATA_EHI_PRINTINFO; unsigned int n, quirks = 0; - unsigned char model_num[41]; + unsigned char model_num[ATA_ID_PROD_LEN + 1]; - ata_id_c_string(dev->id, model_num, ATA_ID_PROD_OFS, sizeof(model_num)); + ata_id_c_string(dev->id, model_num, ATA_ID_PROD, sizeof(model_num)); for (n = 0; sil_blacklist[n].product; n++) if (!strcmp(sil_blacklist[n].product, model_num)) { @@ -621,38 +624,35 @@ static void sil_init_controller(struct p static int sil_init_one (struct pci_dev *pdev, const struct pci_device_id *ent) { static int printed_version; - struct ata_probe_ent *probe_ent = NULL; - unsigned long base; + struct device *dev = &pdev->dev; + struct ata_probe_ent *probe_ent; void __iomem *mmio_base; int rc; unsigned int i; - int pci_dev_busy = 0; if (!printed_version++) dev_printk(KERN_DEBUG, &pdev->dev, "version " DRV_VERSION "\n"); - rc = pci_enable_device(pdev); + rc = pcim_enable_device(pdev); if (rc) return rc; - rc = pci_request_regions(pdev, DRV_NAME); - if (rc) { - pci_dev_busy = 1; - goto err_out; - } + rc = pcim_iomap_regions(pdev, 1 << SIL_MMIO_BAR, DRV_NAME); + if (rc == -EBUSY) + pcim_pin_device(pdev); + if (rc) + return rc; rc = pci_set_dma_mask(pdev, ATA_DMA_MASK); if (rc) - goto err_out_regions; + return rc; rc = pci_set_consistent_dma_mask(pdev, ATA_DMA_MASK); if (rc) - goto err_out_regions; + return rc; - probe_ent = kzalloc(sizeof(*probe_ent), GFP_KERNEL); - if (probe_ent == NULL) { - rc = -ENOMEM; - goto err_out_regions; - } + probe_ent = devm_kzalloc(dev, sizeof(*probe_ent), GFP_KERNEL); + if (probe_ent == NULL) + return -ENOMEM; INIT_LIST_HEAD(&probe_ent->node); probe_ent->dev = pci_dev_to_dev(pdev); @@ -666,22 +666,16 @@ static int sil_init_one (struct pci_dev probe_ent->irq_flags = IRQF_SHARED; probe_ent->port_flags = sil_port_info[ent->driver_data].flags; - mmio_base = pci_iomap(pdev, 5, 0); - if (mmio_base == NULL) { - rc = -ENOMEM; - goto err_out_free_ent; - } - - probe_ent->mmio_base = mmio_base; + probe_ent->iomap = pcim_iomap_table(pdev); - base = (unsigned long) mmio_base; + mmio_base = probe_ent->iomap[SIL_MMIO_BAR]; for (i = 0; i < probe_ent->n_ports; i++) { - probe_ent->port[i].cmd_addr = base + sil_port[i].tf; + probe_ent->port[i].cmd_addr = mmio_base + sil_port[i].tf; probe_ent->port[i].altstatus_addr = - probe_ent->port[i].ctl_addr = base + sil_port[i].ctl; - probe_ent->port[i].bmdma_addr = base + sil_port[i].bmdma; - probe_ent->port[i].scr_addr = base + sil_port[i].scr; + probe_ent->port[i].ctl_addr = mmio_base + sil_port[i].ctl; + probe_ent->port[i].bmdma_addr = mmio_base + sil_port[i].bmdma; + probe_ent->port[i].scr_addr = mmio_base + sil_port[i].scr; ata_std_ports(&probe_ent->port[i]); } @@ -690,30 +684,25 @@ static int sil_init_one (struct pci_dev pci_set_master(pdev); - /* FIXME: check ata_device_add return value */ - ata_device_add(probe_ent); - kfree(probe_ent); + if (!ata_device_add(probe_ent)) + return -ENODEV; + devm_kfree(dev, probe_ent); return 0; - -err_out_free_ent: - kfree(probe_ent); -err_out_regions: - pci_release_regions(pdev); -err_out: - if (!pci_dev_busy) - pci_disable_device(pdev); - return rc; } #ifdef CONFIG_PM static int sil_pci_device_resume(struct pci_dev *pdev) { struct ata_host *host = dev_get_drvdata(&pdev->dev); + int rc; + + rc = ata_pci_device_do_resume(pdev); + if (rc) + return rc; - ata_pci_device_do_resume(pdev); sil_init_controller(pdev, host->n_ports, host->ports[0]->flags, - host->mmio_base); + host->iomap[SIL_MMIO_BAR]); ata_host_resume(host); return 0; diff --git a/drivers/ata/sata_sil24.c b/drivers/ata/sata_sil24.c index 5aa288d..e65e8d5 100644 --- a/drivers/ata/sata_sil24.c +++ b/drivers/ata/sata_sil24.c @@ -28,7 +28,6 @@ #include #include #include #include -#include #define DRV_NAME "sata_sil24" #define DRV_VERSION "0.3" @@ -61,6 +60,9 @@ struct sil24_port_multiplier { }; enum { + SIL24_HOST_BAR = 0, + SIL24_PORT_BAR = 2, + /* * Global controller registers (128 bytes @ BAR0) */ @@ -321,12 +323,6 @@ struct sil24_port_priv { struct ata_taskfile tf; /* Cached taskfile registers */ }; -/* ap->host->private_data */ -struct sil24_host_priv { - void __iomem *host_base; /* global controller control (128 bytes @BAR0) */ - void __iomem *port_base; /* port registers (4 * 8192 bytes @BAR2) */ -}; - static void sil24_dev_config(struct ata_port *ap, struct ata_device *dev); static u8 sil24_check_status(struct ata_port *ap); static u32 sil24_scr_read(struct ata_port *ap, unsigned sc_reg); @@ -341,8 +337,6 @@ static void sil24_thaw(struct ata_port * static void sil24_error_handler(struct ata_port *ap); static void sil24_post_internal_cmd(struct ata_queued_cmd *qc); static int sil24_port_start(struct ata_port *ap); -static void sil24_port_stop(struct ata_port *ap); -static void sil24_host_stop(struct ata_host *host); static int sil24_init_one(struct pci_dev *pdev, const struct pci_device_id *ent); #ifdef CONFIG_PM static int sil24_pci_device_resume(struct pci_dev *pdev); @@ -362,7 +356,7 @@ static struct pci_driver sil24_pci_drive .name = DRV_NAME, .id_table = sil24_pci_tbl, .probe = sil24_init_one, - .remove = ata_pci_remove_one, /* safe? */ + .remove = ata_pci_remove_one, #ifdef CONFIG_PM .suspend = ata_pci_device_suspend, .resume = sil24_pci_device_resume, @@ -406,6 +400,8 @@ static const struct ata_port_operations .irq_handler = sil24_interrupt, .irq_clear = sil24_irq_clear, + .irq_on = ata_dummy_irq_on, + .irq_ack = ata_dummy_irq_ack, .scr_read = sil24_scr_read, .scr_write = sil24_scr_write, @@ -416,8 +412,6 @@ static const struct ata_port_operations .post_internal_cmd = sil24_post_internal_cmd, .port_start = sil24_port_start, - .port_stop = sil24_port_stop, - .host_stop = sil24_host_stop, }; /* @@ -467,7 +461,7 @@ static int sil24_tag(int tag) static void sil24_dev_config(struct ata_port *ap, struct ata_device *dev) { - void __iomem *port = (void __iomem *)ap->ioaddr.cmd_addr; + void __iomem *port = ap->ioaddr.cmd_addr; if (dev->cdb_len == 16) writel(PORT_CS_CDB16, port + PORT_CTRL_STAT); @@ -478,7 +472,7 @@ static void sil24_dev_config(struct ata_ static inline void sil24_update_tf(struct ata_port *ap) { struct sil24_port_priv *pp = ap->private_data; - void __iomem *port = (void __iomem *)ap->ioaddr.cmd_addr; + void __iomem *port = ap->ioaddr.cmd_addr; struct sil24_prb __iomem *prb = port; u8 fis[6 * 4]; @@ -501,7 +495,7 @@ static int sil24_scr_map[] = { static u32 sil24_scr_read(struct ata_port *ap, unsigned sc_reg) { - void __iomem *scr_addr = (void __iomem *)ap->ioaddr.scr_addr; + void __iomem *scr_addr = ap->ioaddr.scr_addr; if (sc_reg < ARRAY_SIZE(sil24_scr_map)) { void __iomem *addr; addr = scr_addr + sil24_scr_map[sc_reg] * 4; @@ -512,7 +506,7 @@ static u32 sil24_scr_read(struct ata_por static void sil24_scr_write(struct ata_port *ap, unsigned sc_reg, u32 val) { - void __iomem *scr_addr = (void __iomem *)ap->ioaddr.scr_addr; + void __iomem *scr_addr = ap->ioaddr.scr_addr; if (sc_reg < ARRAY_SIZE(sil24_scr_map)) { void __iomem *addr; addr = scr_addr + sil24_scr_map[sc_reg] * 4; @@ -528,7 +522,7 @@ static void sil24_tf_read(struct ata_por static int sil24_init_port(struct ata_port *ap) { - void __iomem *port = (void __iomem *)ap->ioaddr.cmd_addr; + void __iomem *port = ap->ioaddr.cmd_addr; u32 tmp; writel(PORT_CS_INIT, port + PORT_CTRL_STAT); @@ -544,7 +538,7 @@ static int sil24_init_port(struct ata_po static int sil24_softreset(struct ata_port *ap, unsigned int *class) { - void __iomem *port = (void __iomem *)ap->ioaddr.cmd_addr; + void __iomem *port = ap->ioaddr.cmd_addr; struct sil24_port_priv *pp = ap->private_data; struct sil24_prb *prb = &pp->cmd_block[0].ata.prb; dma_addr_t paddr = pp->cmd_block_dma; @@ -604,7 +598,7 @@ static int sil24_softreset(struct ata_po static int sil24_hardreset(struct ata_port *ap, unsigned int *class) { - void __iomem *port = (void __iomem *)ap->ioaddr.cmd_addr; + void __iomem *port = ap->ioaddr.cmd_addr; const char *reason; int tout_msec, rc; u32 tmp; @@ -721,7 +715,7 @@ static unsigned int sil24_qc_issue(struc { struct ata_port *ap = qc->ap; struct sil24_port_priv *pp = ap->private_data; - void __iomem *port = (void __iomem *)ap->ioaddr.cmd_addr; + void __iomem *port = ap->ioaddr.cmd_addr; unsigned int tag = sil24_tag(qc->tag); dma_addr_t paddr; void __iomem *activate; @@ -742,7 +736,7 @@ static void sil24_irq_clear(struct ata_p static void sil24_freeze(struct ata_port *ap) { - void __iomem *port = (void __iomem *)ap->ioaddr.cmd_addr; + void __iomem *port = ap->ioaddr.cmd_addr; /* Port-wide IRQ mask in HOST_CTRL doesn't really work, clear * PORT_IRQ_ENABLE instead. @@ -752,7 +746,7 @@ static void sil24_freeze(struct ata_port static void sil24_thaw(struct ata_port *ap) { - void __iomem *port = (void __iomem *)ap->ioaddr.cmd_addr; + void __iomem *port = ap->ioaddr.cmd_addr; u32 tmp; /* clear IRQ */ @@ -765,7 +759,7 @@ static void sil24_thaw(struct ata_port * static void sil24_error_intr(struct ata_port *ap) { - void __iomem *port = (void __iomem *)ap->ioaddr.cmd_addr; + void __iomem *port = ap->ioaddr.cmd_addr; struct ata_eh_info *ehi = &ap->eh_info; int freeze = 0; u32 irq_stat; @@ -843,7 +837,7 @@ static void sil24_finish_qc(struct ata_q static inline void sil24_host_intr(struct ata_port *ap) { - void __iomem *port = (void __iomem *)ap->ioaddr.cmd_addr; + void __iomem *port = ap->ioaddr.cmd_addr; u32 slot_stat, qc_active; int rc; @@ -878,12 +872,12 @@ static inline void sil24_host_intr(struc static irqreturn_t sil24_interrupt(int irq, void *dev_instance) { struct ata_host *host = dev_instance; - struct sil24_host_priv *hpriv = host->private_data; + void __iomem *host_base = host->iomap[SIL24_HOST_BAR]; unsigned handled = 0; u32 status; int i; - status = readl(hpriv->host_base + HOST_IRQ_STAT); + status = readl(host_base + HOST_IRQ_STAT); if (status == 0xffffffff) { printk(KERN_ERR DRV_NAME ": IRQ status == 0xffffffff, " @@ -938,13 +932,6 @@ static void sil24_post_internal_cmd(stru sil24_init_port(ap); } -static inline void sil24_cblk_free(struct sil24_port_priv *pp, struct device *dev) -{ - const size_t cb_size = sizeof(*pp->cmd_block) * SIL24_MAX_CMDS; - - dma_free_coherent(dev, cb_size, pp->cmd_block, pp->cmd_block_dma); -} - static int sil24_port_start(struct ata_port *ap) { struct device *dev = ap->host->dev; @@ -952,22 +939,22 @@ static int sil24_port_start(struct ata_p union sil24_cmd_block *cb; size_t cb_size = sizeof(*cb) * SIL24_MAX_CMDS; dma_addr_t cb_dma; - int rc = -ENOMEM; + int rc; - pp = kzalloc(sizeof(*pp), GFP_KERNEL); + pp = devm_kzalloc(dev, sizeof(*pp), GFP_KERNEL); if (!pp) - goto err_out; + return -ENOMEM; pp->tf.command = ATA_DRDY; - cb = dma_alloc_coherent(dev, cb_size, &cb_dma, GFP_KERNEL); + cb = dmam_alloc_coherent(dev, cb_size, &cb_dma, GFP_KERNEL); if (!cb) - goto err_out_pp; + return -ENOMEM; memset(cb, 0, cb_size); rc = ata_pad_alloc(ap, dev); if (rc) - goto err_out_pad; + return rc; pp->cmd_block = cb; pp->cmd_block_dma = cb_dma; @@ -975,33 +962,6 @@ static int sil24_port_start(struct ata_p ap->private_data = pp; return 0; - -err_out_pad: - sil24_cblk_free(pp, dev); -err_out_pp: - kfree(pp); -err_out: - return rc; -} - -static void sil24_port_stop(struct ata_port *ap) -{ - struct device *dev = ap->host->dev; - struct sil24_port_priv *pp = ap->private_data; - - sil24_cblk_free(pp, dev); - ata_pad_free(ap, dev); - kfree(pp); -} - -static void sil24_host_stop(struct ata_host *host) -{ - struct sil24_host_priv *hpriv = host->private_data; - struct pci_dev *pdev = to_pci_dev(host->dev); - - pci_iounmap(pdev, hpriv->host_base); - pci_iounmap(pdev, hpriv->port_base); - kfree(hpriv); } static void sil24_init_controller(struct pci_dev *pdev, int n_ports, @@ -1066,43 +1026,32 @@ static void sil24_init_controller(struct static int sil24_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) { static int printed_version = 0; + struct device *dev = &pdev->dev; unsigned int board_id = (unsigned int)ent->driver_data; struct ata_port_info *pinfo = &sil24_port_info[board_id]; - struct ata_probe_ent *probe_ent = NULL; - struct sil24_host_priv *hpriv = NULL; - void __iomem *host_base = NULL; - void __iomem *port_base = NULL; + struct ata_probe_ent *probe_ent; + void __iomem *host_base; + void __iomem *port_base; int i, rc; u32 tmp; if (!printed_version++) dev_printk(KERN_DEBUG, &pdev->dev, "version " DRV_VERSION "\n"); - rc = pci_enable_device(pdev); + rc = pcim_enable_device(pdev); if (rc) return rc; - rc = pci_request_regions(pdev, DRV_NAME); + rc = pcim_iomap_regions(pdev, + (1 << SIL24_HOST_BAR) | (1 << SIL24_PORT_BAR), + DRV_NAME); if (rc) - goto out_disable; - - rc = -ENOMEM; - /* map mmio registers */ - host_base = pci_iomap(pdev, 0, 0); - if (!host_base) - goto out_free; - port_base = pci_iomap(pdev, 2, 0); - if (!port_base) - goto out_free; - - /* allocate & init probe_ent and hpriv */ - probe_ent = kzalloc(sizeof(*probe_ent), GFP_KERNEL); - if (!probe_ent) - goto out_free; + return rc; - hpriv = kzalloc(sizeof(*hpriv), GFP_KERNEL); - if (!hpriv) - goto out_free; + /* allocate & init probe_ent */ + probe_ent = devm_kzalloc(dev, sizeof(*probe_ent), GFP_KERNEL); + if (!probe_ent) + return -ENOMEM; probe_ent->dev = pci_dev_to_dev(pdev); INIT_LIST_HEAD(&probe_ent->node); @@ -1117,10 +1066,10 @@ static int sil24_init_one(struct pci_dev probe_ent->irq = pdev->irq; probe_ent->irq_flags = IRQF_SHARED; - probe_ent->private_data = hpriv; + probe_ent->iomap = pcim_iomap_table(pdev); - hpriv->host_base = host_base; - hpriv->port_base = port_base; + host_base = probe_ent->iomap[SIL24_HOST_BAR]; + port_base = probe_ent->iomap[SIL24_PORT_BAR]; /* * Configure the device @@ -1132,7 +1081,7 @@ static int sil24_init_one(struct pci_dev if (rc) { dev_printk(KERN_ERR, &pdev->dev, "64-bit DMA enable failed\n"); - goto out_free; + return rc; } } } else { @@ -1140,13 +1089,13 @@ static int sil24_init_one(struct pci_dev if (rc) { dev_printk(KERN_ERR, &pdev->dev, "32-bit DMA enable failed\n"); - goto out_free; + return rc; } rc = pci_set_consistent_dma_mask(pdev, DMA_32BIT_MASK); if (rc) { dev_printk(KERN_ERR, &pdev->dev, "32-bit consistent DMA enable failed\n"); - goto out_free; + return rc; } } @@ -1162,11 +1111,10 @@ static int sil24_init_one(struct pci_dev } for (i = 0; i < probe_ent->n_ports; i++) { - unsigned long portu = - (unsigned long)port_base + i * PORT_REGS_SIZE; + void __iomem *port = port_base + i * PORT_REGS_SIZE; - probe_ent->port[i].cmd_addr = portu; - probe_ent->port[i].scr_addr = portu + PORT_SCONTROL; + probe_ent->port[i].cmd_addr = port; + probe_ent->port[i].scr_addr = port + PORT_SCONTROL; ata_std_ports(&probe_ent->port[i]); } @@ -1176,38 +1124,30 @@ static int sil24_init_one(struct pci_dev pci_set_master(pdev); - /* FIXME: check ata_device_add return value */ - ata_device_add(probe_ent); + if (!ata_device_add(probe_ent)) + return -ENODEV; - kfree(probe_ent); + devm_kfree(dev, probe_ent); return 0; - - out_free: - if (host_base) - pci_iounmap(pdev, host_base); - if (port_base) - pci_iounmap(pdev, port_base); - kfree(probe_ent); - kfree(hpriv); - pci_release_regions(pdev); - out_disable: - pci_disable_device(pdev); - return rc; } #ifdef CONFIG_PM static int sil24_pci_device_resume(struct pci_dev *pdev) { struct ata_host *host = dev_get_drvdata(&pdev->dev); - struct sil24_host_priv *hpriv = host->private_data; + void __iomem *host_base = host->iomap[SIL24_HOST_BAR]; + void __iomem *port_base = host->iomap[SIL24_PORT_BAR]; + int rc; - ata_pci_device_do_resume(pdev); + rc = ata_pci_device_do_resume(pdev); + if (rc) + return rc; if (pdev->dev.power.power_state.event == PM_EVENT_SUSPEND) - writel(HOST_CTRL_GLOBAL_RST, hpriv->host_base + HOST_CTRL); + writel(HOST_CTRL_GLOBAL_RST, host_base + HOST_CTRL); sil24_init_controller(pdev, host->n_ports, host->ports[0]->flags, - hpriv->host_base, hpriv->port_base); + host_base, port_base); ata_host_resume(host); diff --git a/drivers/ata/sata_sis.c b/drivers/ata/sata_sis.c index 9c25a1e..49c9e2b 100644 --- a/drivers/ata/sata_sis.c +++ b/drivers/ata/sata_sis.c @@ -40,9 +40,11 @@ #include #include #include #include +#include "libata.h" +#undef DRV_NAME /* already defined in libata.h, for libata-core */ #define DRV_NAME "sata_sis" -#define DRV_VERSION "0.6" +#define DRV_VERSION "0.7" enum { sis_180 = 0, @@ -67,9 +69,12 @@ static u32 sis_scr_read (struct ata_port static void sis_scr_write (struct ata_port *ap, unsigned int sc_reg, u32 val); static const struct pci_device_id sis_pci_tbl[] = { - { PCI_VDEVICE(SI, 0x180), sis_180 }, - { PCI_VDEVICE(SI, 0x181), sis_180 }, - { PCI_VDEVICE(SI, 0x182), sis_180 }, + { PCI_VDEVICE(SI, 0x0180), sis_180 }, /* SiS 964/180 */ + { PCI_VDEVICE(SI, 0x0181), sis_180 }, /* SiS 964/180 */ + { PCI_VDEVICE(SI, 0x0182), sis_180 }, /* SiS 965/965L */ + { PCI_VDEVICE(SI, 0x0183), sis_180 }, /* SiS 965/965L */ + { PCI_VDEVICE(SI, 0x1182), sis_180 }, /* SiS 966/966L */ + { PCI_VDEVICE(SI, 0x1183), sis_180 }, /* SiS 966/966L */ { } /* terminate list */ }; @@ -112,18 +117,18 @@ static const struct ata_port_operations .bmdma_status = ata_bmdma_status, .qc_prep = ata_qc_prep, .qc_issue = ata_qc_issue_prot, - .data_xfer = ata_pio_data_xfer, + .data_xfer = ata_data_xfer, .freeze = ata_bmdma_freeze, .thaw = ata_bmdma_thaw, .error_handler = ata_bmdma_error_handler, .post_internal_cmd = ata_bmdma_post_internal_cmd, .irq_handler = ata_interrupt, .irq_clear = ata_bmdma_irq_clear, + .irq_on = ata_irq_on, + .irq_ack = ata_irq_ack, .scr_read = sis_scr_read, .scr_write = sis_scr_write, .port_start = ata_port_start, - .port_stop = ata_port_stop, - .host_stop = ata_host_stop, }; static struct ata_port_info sis_port_info = { @@ -135,31 +140,42 @@ static struct ata_port_info sis_port_inf .port_ops = &sis_ops, }; - MODULE_AUTHOR("Uwe Koziolek"); MODULE_DESCRIPTION("low-level driver for Silicon Integratad Systems SATA controller"); MODULE_LICENSE("GPL"); MODULE_DEVICE_TABLE(pci, sis_pci_tbl); MODULE_VERSION(DRV_VERSION); -static unsigned int get_scr_cfg_addr(unsigned int port_no, unsigned int sc_reg, int device) +static unsigned int get_scr_cfg_addr(struct ata_port *ap, unsigned int sc_reg) { + struct pci_dev *pdev = to_pci_dev(ap->host->dev); unsigned int addr = SIS_SCR_BASE + (4 * sc_reg); + u8 pmr; - if (port_no) { - if (device == 0x182) - addr += SIS182_SATA1_OFS; - else - addr += SIS180_SATA1_OFS; + if (ap->port_no) { + switch (pdev->device) { + case 0x0180: + case 0x0181: + pci_read_config_byte(pdev, SIS_PMR, &pmr); + if ((pmr & SIS_PMR_COMBINED) == 0) + addr += SIS180_SATA1_OFS; + break; + + case 0x0182: + case 0x0183: + case 0x1182: + case 0x1183: + addr += SIS182_SATA1_OFS; + break; + } } - return addr; } static u32 sis_scr_cfg_read (struct ata_port *ap, unsigned int sc_reg) { struct pci_dev *pdev = to_pci_dev(ap->host->dev); - unsigned int cfg_addr = get_scr_cfg_addr(ap->port_no, sc_reg, pdev->device); + unsigned int cfg_addr = get_scr_cfg_addr(ap, sc_reg); u32 val, val2 = 0; u8 pmr; @@ -170,26 +186,28 @@ static u32 sis_scr_cfg_read (struct ata_ pci_read_config_dword(pdev, cfg_addr, &val); - if ((pdev->device == 0x182) || (pmr & SIS_PMR_COMBINED)) + if ((pdev->device == 0x0182) || (pdev->device == 0x0183) || (pdev->device == 0x1182) || + (pdev->device == 0x1183) || (pmr & SIS_PMR_COMBINED)) pci_read_config_dword(pdev, cfg_addr+0x10, &val2); return (val|val2) & 0xfffffffb; /* avoid problems with powerdowned ports */ } -static void sis_scr_cfg_write (struct ata_port *ap, unsigned int scr, u32 val) +static void sis_scr_cfg_write (struct ata_port *ap, unsigned int sc_reg, u32 val) { struct pci_dev *pdev = to_pci_dev(ap->host->dev); - unsigned int cfg_addr = get_scr_cfg_addr(ap->port_no, scr, pdev->device); + unsigned int cfg_addr = get_scr_cfg_addr(ap, sc_reg); u8 pmr; - if (scr == SCR_ERROR) /* doesn't exist in PCI cfg space */ + if (sc_reg == SCR_ERROR) /* doesn't exist in PCI cfg space */ return; pci_read_config_byte(pdev, SIS_PMR, &pmr); pci_write_config_dword(pdev, cfg_addr, val); - if ((pdev->device == 0x182) || (pmr & SIS_PMR_COMBINED)) + if ((pdev->device == 0x0182) || (pdev->device == 0x0183) || (pdev->device == 0x1182) || + (pdev->device == 0x1183) || (pmr & SIS_PMR_COMBINED)) pci_write_config_dword(pdev, cfg_addr+0x10, val); } @@ -207,10 +225,11 @@ static u32 sis_scr_read (struct ata_port pci_read_config_byte(pdev, SIS_PMR, &pmr); - val = inl(ap->ioaddr.scr_addr + (sc_reg * 4)); + val = ioread32(ap->ioaddr.scr_addr + (sc_reg * 4)); - if ((pdev->device == 0x182) || (pmr & SIS_PMR_COMBINED)) - val2 = inl(ap->ioaddr.scr_addr + (sc_reg * 4) + 0x10); + if ((pdev->device == 0x0182) || (pdev->device == 0x0183) || (pdev->device == 0x1182) || + (pdev->device == 0x1183) || (pmr & SIS_PMR_COMBINED)) + val2 = ioread32(ap->ioaddr.scr_addr + (sc_reg * 4) + 0x10); return (val | val2) & 0xfffffffb; } @@ -228,9 +247,10 @@ static void sis_scr_write (struct ata_po if (ap->flags & SIS_FLAG_CFGSCR) sis_scr_cfg_write(ap, sc_reg, val); else { - outl(val, ap->ioaddr.scr_addr + (sc_reg * 4)); - if ((pdev->device == 0x182) || (pmr & SIS_PMR_COMBINED)) - outl(val, ap->ioaddr.scr_addr + (sc_reg * 4)+0x10); + iowrite32(val, ap->ioaddr.scr_addr + (sc_reg * 4)); + if ((pdev->device == 0x0182) || (pdev->device == 0x0183) || (pdev->device == 0x1182) || + (pdev->device == 0x1183) || (pmr & SIS_PMR_COMBINED)) + iowrite32(val, ap->ioaddr.scr_addr + (sc_reg * 4)+0x10); } } @@ -241,29 +261,28 @@ static int sis_init_one (struct pci_dev int rc; u32 genctl, val; struct ata_port_info pi = sis_port_info, *ppi[2] = { &pi, &pi }; - int pci_dev_busy = 0; u8 pmr; - u8 port2_start; + u8 port2_start = 0x20; if (!printed_version++) dev_printk(KERN_INFO, &pdev->dev, "version " DRV_VERSION "\n"); - rc = pci_enable_device(pdev); + rc = pcim_enable_device(pdev); if (rc) return rc; rc = pci_request_regions(pdev, DRV_NAME); if (rc) { - pci_dev_busy = 1; - goto err_out; + pcim_pin_device(pdev); + return rc; } rc = pci_set_dma_mask(pdev, ATA_DMA_MASK); if (rc) - goto err_out_regions; + return rc; rc = pci_set_consistent_dma_mask(pdev, ATA_DMA_MASK); if (rc) - goto err_out_regions; + return rc; /* check and see if the SCRs are in IO space or PCI cfg space */ pci_read_config_dword(pdev, SIS_GENCTL, &genctl); @@ -282,60 +301,79 @@ static int sis_init_one (struct pci_dev } pci_read_config_byte(pdev, SIS_PMR, &pmr); - if (ent->device != 0x182) { + switch (ent->device) { + case 0x0180: + case 0x0181: + + /* The PATA-handling is provided by pata_sis */ + switch (pmr & 0x30) { + case 0x10: + ppi[1] = &sis_info133; + break; + + case 0x30: + ppi[0] = &sis_info133; + break; + } if ((pmr & SIS_PMR_COMBINED) == 0) { dev_printk(KERN_INFO, &pdev->dev, "Detected SiS 180/181/964 chipset in SATA mode\n"); port2_start = 64; - } - else { + } else { dev_printk(KERN_INFO, &pdev->dev, "Detected SiS 180/181 chipset in combined mode\n"); port2_start=0; pi.flags |= ATA_FLAG_SLAVE_POSS; } - } - else { + break; + + case 0x0182: + case 0x0183: pci_read_config_dword ( pdev, 0x6C, &val); if (val & (1L << 31)) { dev_printk(KERN_INFO, &pdev->dev, "Detected SiS 182/965 chipset\n"); pi.flags |= ATA_FLAG_SLAVE_POSS; - } - else + } else { dev_printk(KERN_INFO, &pdev->dev, "Detected SiS 182/965L chipset\n"); - port2_start = 0x20; + } + break; + + case 0x1182: + case 0x1183: + pci_read_config_dword(pdev, 0x64, &val); + if (val & 0x10000000) { + dev_printk(KERN_INFO, &pdev->dev, "Detected SiS 1182/1183/966L SATA controller\n"); + } else { + dev_printk(KERN_INFO, &pdev->dev, "Detected SiS 1182/1183/966 SATA controller\n"); + pi.flags |= ATA_FLAG_SLAVE_POSS; + } + break; } probe_ent = ata_pci_init_native_mode(pdev, ppi, ATA_PORT_PRIMARY | ATA_PORT_SECONDARY); - if (!probe_ent) { - rc = -ENOMEM; - goto err_out_regions; - } + if (!probe_ent) + return -ENOMEM; if (!(probe_ent->port_flags & SIS_FLAG_CFGSCR)) { - probe_ent->port[0].scr_addr = - pci_resource_start(pdev, SIS_SCR_PCI_BAR); - probe_ent->port[1].scr_addr = - pci_resource_start(pdev, SIS_SCR_PCI_BAR) + port2_start; + void *mmio; + + mmio = pcim_iomap(pdev, SIS_SCR_PCI_BAR, 0); + if (!mmio) + return -ENOMEM; + + probe_ent->port[0].scr_addr = mmio; + probe_ent->port[1].scr_addr = mmio + port2_start; } pci_set_master(pdev); pci_intx(pdev, 1); - /* FIXME: check ata_device_add return value */ - ata_device_add(probe_ent); - kfree(probe_ent); + if (!ata_device_add(probe_ent)) + return -EIO; + devm_kfree(&pdev->dev, probe_ent); return 0; -err_out_regions: - pci_release_regions(pdev); - -err_out: - if (!pci_dev_busy) - pci_disable_device(pdev); - return rc; - } static int __init sis_init(void) @@ -350,4 +388,3 @@ static void __exit sis_exit(void) module_init(sis_init); module_exit(sis_exit); - diff --git a/drivers/ata/sata_svw.c b/drivers/ata/sata_svw.c index 46d8a94..4e42899 100644 --- a/drivers/ata/sata_svw.c +++ b/drivers/ata/sata_svw.c @@ -116,7 +116,7 @@ static u32 k2_sata_scr_read (struct ata_ { if (sc_reg > SCR_CONTROL) return 0xffffffffU; - return readl((void *) ap->ioaddr.scr_addr + (sc_reg * 4)); + return readl((void __iomem *) ap->ioaddr.scr_addr + (sc_reg * 4)); } @@ -125,7 +125,7 @@ static void k2_sata_scr_write (struct at { if (sc_reg > SCR_CONTROL) return; - writel(val, (void *) ap->ioaddr.scr_addr + (sc_reg * 4)); + writel(val, (void __iomem *) ap->ioaddr.scr_addr + (sc_reg * 4)); } @@ -135,31 +135,31 @@ static void k2_sata_tf_load(struct ata_p unsigned int is_addr = tf->flags & ATA_TFLAG_ISADDR; if (tf->ctl != ap->last_ctl) { - writeb(tf->ctl, (void __iomem *) ioaddr->ctl_addr); + writeb(tf->ctl, ioaddr->ctl_addr); ap->last_ctl = tf->ctl; ata_wait_idle(ap); } if (is_addr && (tf->flags & ATA_TFLAG_LBA48)) { writew(tf->feature | (((u16)tf->hob_feature) << 8), - (void __iomem *) ioaddr->feature_addr); + ioaddr->feature_addr); writew(tf->nsect | (((u16)tf->hob_nsect) << 8), - (void __iomem *) ioaddr->nsect_addr); + ioaddr->nsect_addr); writew(tf->lbal | (((u16)tf->hob_lbal) << 8), - (void __iomem *) ioaddr->lbal_addr); + ioaddr->lbal_addr); writew(tf->lbam | (((u16)tf->hob_lbam) << 8), - (void __iomem *) ioaddr->lbam_addr); + ioaddr->lbam_addr); writew(tf->lbah | (((u16)tf->hob_lbah) << 8), - (void __iomem *) ioaddr->lbah_addr); + ioaddr->lbah_addr); } else if (is_addr) { - writew(tf->feature, (void __iomem *) ioaddr->feature_addr); - writew(tf->nsect, (void __iomem *) ioaddr->nsect_addr); - writew(tf->lbal, (void __iomem *) ioaddr->lbal_addr); - writew(tf->lbam, (void __iomem *) ioaddr->lbam_addr); - writew(tf->lbah, (void __iomem *) ioaddr->lbah_addr); + writew(tf->feature, ioaddr->feature_addr); + writew(tf->nsect, ioaddr->nsect_addr); + writew(tf->lbal, ioaddr->lbal_addr); + writew(tf->lbam, ioaddr->lbam_addr); + writew(tf->lbah, ioaddr->lbah_addr); } if (tf->flags & ATA_TFLAG_DEVICE) - writeb(tf->device, (void __iomem *) ioaddr->device_addr); + writeb(tf->device, ioaddr->device_addr); ata_wait_idle(ap); } @@ -171,12 +171,12 @@ static void k2_sata_tf_read(struct ata_p u16 nsect, lbal, lbam, lbah, feature; tf->command = k2_stat_check_status(ap); - tf->device = readw((void __iomem *)ioaddr->device_addr); - feature = readw((void __iomem *)ioaddr->error_addr); - nsect = readw((void __iomem *)ioaddr->nsect_addr); - lbal = readw((void __iomem *)ioaddr->lbal_addr); - lbam = readw((void __iomem *)ioaddr->lbam_addr); - lbah = readw((void __iomem *)ioaddr->lbah_addr); + tf->device = readw(ioaddr->device_addr); + feature = readw(ioaddr->error_addr); + nsect = readw(ioaddr->nsect_addr); + lbal = readw(ioaddr->lbal_addr); + lbam = readw(ioaddr->lbam_addr); + lbah = readw(ioaddr->lbah_addr); tf->feature = feature; tf->nsect = nsect; @@ -262,7 +262,7 @@ static void k2_bmdma_start_mmio (struct static u8 k2_stat_check_status(struct ata_port *ap) { - return readl((void *) ap->ioaddr.status_addr); + return readl((void __iomem *) ap->ioaddr.status_addr); } #ifdef CONFIG_PPC_OF @@ -349,21 +349,21 @@ static const struct ata_port_operations .bmdma_status = ata_bmdma_status, .qc_prep = ata_qc_prep, .qc_issue = ata_qc_issue_prot, - .data_xfer = ata_mmio_data_xfer, + .data_xfer = ata_data_xfer, .freeze = ata_bmdma_freeze, .thaw = ata_bmdma_thaw, .error_handler = ata_bmdma_error_handler, .post_internal_cmd = ata_bmdma_post_internal_cmd, .irq_handler = ata_interrupt, .irq_clear = ata_bmdma_irq_clear, + .irq_on = ata_irq_on, + .irq_ack = ata_irq_ack, .scr_read = k2_sata_scr_read, .scr_write = k2_sata_scr_write, .port_start = ata_port_start, - .port_stop = ata_port_stop, - .host_stop = ata_pci_host_stop, }; -static void k2_sata_setup_port(struct ata_ioports *port, unsigned long base) +static void k2_sata_setup_port(struct ata_ioports *port, void __iomem *base) { port->cmd_addr = base + K2_SATA_TF_CMD_OFFSET; port->data_addr = base + K2_SATA_TF_DATA_OFFSET; @@ -386,12 +386,11 @@ static void k2_sata_setup_port(struct at static int k2_sata_init_one (struct pci_dev *pdev, const struct pci_device_id *ent) { static int printed_version; - struct ata_probe_ent *probe_ent = NULL; - unsigned long base; + struct device *dev = &pdev->dev; + struct ata_probe_ent *probe_ent; void __iomem *mmio_base; const struct k2_board_info *board_info = &k2_board_info[ent->driver_data]; - int pci_dev_busy = 0; int rc; int i; @@ -402,7 +401,7 @@ static int k2_sata_init_one (struct pci_ * If this driver happens to only be useful on Apple's K2, then * we should check that here as it has a normal Serverworks ID */ - rc = pci_enable_device(pdev); + rc = pcim_enable_device(pdev); if (rc) return rc; /* @@ -412,48 +411,27 @@ static int k2_sata_init_one (struct pci_ if (pci_resource_len(pdev, 5) == 0) return -ENODEV; - /* Request PCI regions */ - rc = pci_request_regions(pdev, DRV_NAME); - if (rc) { - pci_dev_busy = 1; - goto err_out; - } + /* Request and iomap PCI regions */ + rc = pcim_iomap_regions(pdev, 1 << 5, DRV_NAME); + if (rc == -EBUSY) + pcim_pin_device(pdev); + if (rc) + return rc; rc = pci_set_dma_mask(pdev, ATA_DMA_MASK); if (rc) - goto err_out_regions; + return rc; rc = pci_set_consistent_dma_mask(pdev, ATA_DMA_MASK); if (rc) - goto err_out_regions; + return rc; - probe_ent = kmalloc(sizeof(*probe_ent), GFP_KERNEL); - if (probe_ent == NULL) { - rc = -ENOMEM; - goto err_out_regions; - } + probe_ent = devm_kzalloc(dev, sizeof(*probe_ent), GFP_KERNEL); + if (probe_ent == NULL) + return -ENOMEM; - memset(probe_ent, 0, sizeof(*probe_ent)); probe_ent->dev = pci_dev_to_dev(pdev); INIT_LIST_HEAD(&probe_ent->node); - mmio_base = pci_iomap(pdev, 5, 0); - if (mmio_base == NULL) { - rc = -ENOMEM; - goto err_out_free_ent; - } - base = (unsigned long) mmio_base; - - /* Clear a magic bit in SCR1 according to Darwin, those help - * some funky seagate drives (though so far, those were already - * set by the firmware on the machines I had access to) - */ - writel(readl(mmio_base + K2_SATA_SICR1_OFFSET) & ~0x00040000, - mmio_base + K2_SATA_SICR1_OFFSET); - - /* Clear SATA error & interrupts we don't use */ - writel(0xffffffff, mmio_base + K2_SATA_SCR_ERROR_OFFSET); - writel(0x0, mmio_base + K2_SATA_SIM_OFFSET); - probe_ent->sht = &k2_sata_sht; probe_ent->port_flags = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY | ATA_FLAG_MMIO | board_info->port_flags; @@ -461,7 +439,7 @@ static int k2_sata_init_one (struct pci_ probe_ent->n_ports = 4; probe_ent->irq = pdev->irq; probe_ent->irq_flags = IRQF_SHARED; - probe_ent->mmio_base = mmio_base; + probe_ent->iomap = pcim_iomap_table(pdev); /* We don't care much about the PIO/UDMA masks, but the core won't like us * if we don't fill these @@ -470,28 +448,33 @@ static int k2_sata_init_one (struct pci_ probe_ent->mwdma_mask = 0x7; probe_ent->udma_mask = 0x7f; + mmio_base = probe_ent->iomap[5]; + /* different controllers have different number of ports - currently 4 or 8 */ /* All ports are on the same function. Multi-function device is no * longer available. This should not be seen in any system. */ for (i = 0; i < board_info->n_ports; i++) - k2_sata_setup_port(&probe_ent->port[i], base + i * K2_SATA_PORT_OFFSET); + k2_sata_setup_port(&probe_ent->port[i], + mmio_base + i * K2_SATA_PORT_OFFSET); + + /* Clear a magic bit in SCR1 according to Darwin, those help + * some funky seagate drives (though so far, those were already + * set by the firmware on the machines I had access to) + */ + writel(readl(mmio_base + K2_SATA_SICR1_OFFSET) & ~0x00040000, + mmio_base + K2_SATA_SICR1_OFFSET); + + /* Clear SATA error & interrupts we don't use */ + writel(0xffffffff, mmio_base + K2_SATA_SCR_ERROR_OFFSET); + writel(0x0, mmio_base + K2_SATA_SIM_OFFSET); pci_set_master(pdev); - /* FIXME: check ata_device_add return value */ - ata_device_add(probe_ent); - kfree(probe_ent); + if (!ata_device_add(probe_ent)) + return -ENODEV; + devm_kfree(dev, probe_ent); return 0; - -err_out_free_ent: - kfree(probe_ent); -err_out_regions: - pci_release_regions(pdev); -err_out: - if (!pci_dev_busy) - pci_disable_device(pdev); - return rc; } /* 0x240 is device ID for Apple K2 device diff --git a/drivers/ata/sata_sx4.c b/drivers/ata/sata_sx4.c index ae7992d..0ebd77b 100644 --- a/drivers/ata/sata_sx4.c +++ b/drivers/ata/sata_sx4.c @@ -37,12 +37,10 @@ #include #include #include #include -#include #include #include #include #include -#include #include "sata_promise.h" #define DRV_NAME "sata_sx4" @@ -50,6 +48,9 @@ #define DRV_VERSION "0.9" enum { + PDC_MMIO_BAR = 3, + PDC_DIMM_BAR = 4, + PDC_PRD_TBL = 0x44, /* Direct command DMA table addr */ PDC_PKT_SUBMIT = 0x40, /* Command packet pointer addr */ @@ -138,8 +139,6 @@ struct pdc_port_priv { }; struct pdc_host_priv { - void __iomem *dimm_mmio; - unsigned int doing_hdma; unsigned int hdma_prod; unsigned int hdma_cons; @@ -156,11 +155,9 @@ static irqreturn_t pdc20621_interrupt (i static void pdc_eng_timeout(struct ata_port *ap); static void pdc_20621_phy_reset (struct ata_port *ap); static int pdc_port_start(struct ata_port *ap); -static void pdc_port_stop(struct ata_port *ap); static void pdc20621_qc_prep(struct ata_queued_cmd *qc); static void pdc_tf_load_mmio(struct ata_port *ap, const struct ata_taskfile *tf); static void pdc_exec_command_mmio(struct ata_port *ap, const struct ata_taskfile *tf); -static void pdc20621_host_stop(struct ata_host *host); static unsigned int pdc20621_dimm_init(struct ata_probe_ent *pe); static int pdc20621_detect_dimm(struct ata_probe_ent *pe); static unsigned int pdc20621_i2c_read(struct ata_probe_ent *pe, @@ -205,13 +202,13 @@ static const struct ata_port_operations .phy_reset = pdc_20621_phy_reset, .qc_prep = pdc20621_qc_prep, .qc_issue = pdc20621_qc_issue_prot, - .data_xfer = ata_mmio_data_xfer, + .data_xfer = ata_data_xfer, .eng_timeout = pdc_eng_timeout, .irq_handler = pdc20621_interrupt, .irq_clear = pdc20621_irq_clear, + .irq_on = ata_irq_on, + .irq_ack = ata_irq_ack, .port_start = pdc_port_start, - .port_stop = pdc_port_stop, - .host_stop = pdc20621_host_stop, }; static const struct ata_port_info pdc_port_info[] = { @@ -243,18 +240,6 @@ static struct pci_driver pdc_sata_pci_dr }; -static void pdc20621_host_stop(struct ata_host *host) -{ - struct pci_dev *pdev = to_pci_dev(host->dev); - struct pdc_host_priv *hpriv = host->private_data; - void __iomem *dimm_mmio = hpriv->dimm_mmio; - - pci_iounmap(pdev, dimm_mmio); - kfree(hpriv); - - pci_iounmap(pdev, host->mmio_base); -} - static int pdc_port_start(struct ata_port *ap) { struct device *dev = ap->host->dev; @@ -265,43 +250,19 @@ static int pdc_port_start(struct ata_por if (rc) return rc; - pp = kmalloc(sizeof(*pp), GFP_KERNEL); - if (!pp) { - rc = -ENOMEM; - goto err_out; - } - memset(pp, 0, sizeof(*pp)); + pp = devm_kzalloc(dev, sizeof(*pp), GFP_KERNEL); + if (!pp) + return -ENOMEM; - pp->pkt = dma_alloc_coherent(dev, 128, &pp->pkt_dma, GFP_KERNEL); - if (!pp->pkt) { - rc = -ENOMEM; - goto err_out_kfree; - } + pp->pkt = dmam_alloc_coherent(dev, 128, &pp->pkt_dma, GFP_KERNEL); + if (!pp->pkt) + return -ENOMEM; ap->private_data = pp; return 0; - -err_out_kfree: - kfree(pp); -err_out: - ata_port_stop(ap); - return rc; -} - - -static void pdc_port_stop(struct ata_port *ap) -{ - struct device *dev = ap->host->dev; - struct pdc_port_priv *pp = ap->private_data; - - ap->private_data = NULL; - dma_free_coherent(dev, 128, pp->pkt, pp->pkt_dma); - kfree(pp); - ata_port_stop(ap); } - static void pdc_20621_phy_reset (struct ata_port *ap) { VPRINTK("ENTER\n"); @@ -452,9 +413,8 @@ static void pdc20621_dma_prep(struct ata struct scatterlist *sg; struct ata_port *ap = qc->ap; struct pdc_port_priv *pp = ap->private_data; - void __iomem *mmio = ap->host->mmio_base; - struct pdc_host_priv *hpriv = ap->host->private_data; - void __iomem *dimm_mmio = hpriv->dimm_mmio; + void __iomem *mmio = ap->host->iomap[PDC_MMIO_BAR]; + void __iomem *dimm_mmio = ap->host->iomap[PDC_DIMM_BAR]; unsigned int portno = ap->port_no; unsigned int i, idx, total_len = 0, sgt_len; u32 *buf = (u32 *) &pp->dimm_buf[PDC_DIMM_HEADER_SZ]; @@ -513,9 +473,8 @@ static void pdc20621_nodata_prep(struct { struct ata_port *ap = qc->ap; struct pdc_port_priv *pp = ap->private_data; - void __iomem *mmio = ap->host->mmio_base; - struct pdc_host_priv *hpriv = ap->host->private_data; - void __iomem *dimm_mmio = hpriv->dimm_mmio; + void __iomem *mmio = ap->host->iomap[PDC_MMIO_BAR]; + void __iomem *dimm_mmio = ap->host->iomap[PDC_DIMM_BAR]; unsigned int portno = ap->port_no; unsigned int i; @@ -565,7 +524,7 @@ static void __pdc20621_push_hdma(struct { struct ata_port *ap = qc->ap; struct ata_host *host = ap->host; - void __iomem *mmio = host->mmio_base; + void __iomem *mmio = host->iomap[PDC_MMIO_BAR]; /* hard-code chip #0 */ mmio += PDC_CHIP0_OFS; @@ -619,8 +578,7 @@ static void pdc20621_dump_hdma(struct at { struct ata_port *ap = qc->ap; unsigned int port_no = ap->port_no; - struct pdc_host_priv *hpriv = ap->host->private_data; - void *dimm_mmio = hpriv->dimm_mmio; + void __iomem *dimm_mmio = ap->host->iomap[PDC_DIMM_BAR]; dimm_mmio += (port_no * PDC_DIMM_WINDOW_STEP); dimm_mmio += PDC_DIMM_HOST_PKT; @@ -639,7 +597,7 @@ static void pdc20621_packet_start(struct struct ata_port *ap = qc->ap; struct ata_host *host = ap->host; unsigned int port_no = ap->port_no; - void __iomem *mmio = host->mmio_base; + void __iomem *mmio = host->iomap[PDC_MMIO_BAR]; unsigned int rw = (qc->tf.flags & ATA_TFLAG_WRITE); u8 seq = (u8) (port_no + 1); unsigned int port_ofs; @@ -668,8 +626,8 @@ static void pdc20621_packet_start(struct readl(mmio + PDC_20621_SEQCTL + (seq * 4)); /* flush */ writel(port_ofs + PDC_DIMM_ATA_PKT, - (void __iomem *) ap->ioaddr.cmd_addr + PDC_PKT_SUBMIT); - readl((void __iomem *) ap->ioaddr.cmd_addr + PDC_PKT_SUBMIT); + ap->ioaddr.cmd_addr + PDC_PKT_SUBMIT); + readl(ap->ioaddr.cmd_addr + PDC_PKT_SUBMIT); VPRINTK("submitted ofs 0x%x (%u), seq %u\n", port_ofs + PDC_DIMM_ATA_PKT, port_ofs + PDC_DIMM_ATA_PKT, @@ -747,8 +705,8 @@ static inline unsigned int pdc20621_host writel(0x00000001, mmio + PDC_20621_SEQCTL + (seq * 4)); readl(mmio + PDC_20621_SEQCTL + (seq * 4)); writel(port_ofs + PDC_DIMM_ATA_PKT, - (void __iomem *) ap->ioaddr.cmd_addr + PDC_PKT_SUBMIT); - readl((void __iomem *) ap->ioaddr.cmd_addr + PDC_PKT_SUBMIT); + ap->ioaddr.cmd_addr + PDC_PKT_SUBMIT); + readl(ap->ioaddr.cmd_addr + PDC_PKT_SUBMIT); } /* step two - execute ATA command */ @@ -781,7 +739,7 @@ static inline unsigned int pdc20621_host static void pdc20621_irq_clear(struct ata_port *ap) { struct ata_host *host = ap->host; - void __iomem *mmio = host->mmio_base; + void __iomem *mmio = host->iomap[PDC_MMIO_BAR]; mmio += PDC_CHIP0_OFS; @@ -799,12 +757,12 @@ static irqreturn_t pdc20621_interrupt (i VPRINTK("ENTER\n"); - if (!host || !host->mmio_base) { + if (!host || !host->iomap[PDC_MMIO_BAR]) { VPRINTK("QUICK EXIT\n"); return IRQ_NONE; } - mmio_base = host->mmio_base; + mmio_base = host->iomap[PDC_MMIO_BAR]; /* reading should also clear interrupts */ mmio_base += PDC_CHIP0_OFS; @@ -905,7 +863,7 @@ static void pdc_exec_command_mmio(struct } -static void pdc_sata_setup_port(struct ata_ioports *port, unsigned long base) +static void pdc_sata_setup_port(struct ata_ioports *port, void __iomem *base) { port->cmd_addr = base; port->data_addr = base; @@ -931,9 +889,8 @@ static void pdc20621_get_from_dimm(struc u16 idx; u8 page_mask; long dist; - void __iomem *mmio = pe->mmio_base; - struct pdc_host_priv *hpriv = pe->private_data; - void __iomem *dimm_mmio = hpriv->dimm_mmio; + void __iomem *mmio = pe->iomap[PDC_MMIO_BAR]; + void __iomem *dimm_mmio = pe->iomap[PDC_DIMM_BAR]; /* hard-code chip #0 */ mmio += PDC_CHIP0_OFS; @@ -987,9 +944,8 @@ static void pdc20621_put_to_dimm(struct u16 idx; u8 page_mask; long dist; - void __iomem *mmio = pe->mmio_base; - struct pdc_host_priv *hpriv = pe->private_data; - void __iomem *dimm_mmio = hpriv->dimm_mmio; + void __iomem *mmio = pe->iomap[PDC_MMIO_BAR]; + void __iomem *dimm_mmio = pe->iomap[PDC_DIMM_BAR]; /* hard-code chip #0 */ mmio += PDC_CHIP0_OFS; @@ -1034,7 +990,7 @@ static void pdc20621_put_to_dimm(struct static unsigned int pdc20621_i2c_read(struct ata_probe_ent *pe, u32 device, u32 subaddr, u32 *pdata) { - void __iomem *mmio = pe->mmio_base; + void __iomem *mmio = pe->iomap[PDC_MMIO_BAR]; u32 i2creg = 0; u32 status; u32 count =0; @@ -1093,7 +1049,7 @@ static int pdc20621_prog_dimm0(struct at u32 data = 0; int size, i; u8 bdimmsize; - void __iomem *mmio = pe->mmio_base; + void __iomem *mmio = pe->iomap[PDC_MMIO_BAR]; static const struct { unsigned int reg; unsigned int ofs; @@ -1155,8 +1111,8 @@ static int pdc20621_prog_dimm0(struct at static unsigned int pdc20621_prog_dimm_global(struct ata_probe_ent *pe) { u32 data, spd0; - int error, i; - void __iomem *mmio = pe->mmio_base; + int error, i; + void __iomem *mmio = pe->iomap[PDC_MMIO_BAR]; /* hard-code chip #0 */ mmio += PDC_CHIP0_OFS; @@ -1210,7 +1166,7 @@ static unsigned int pdc20621_dimm_init(s u32 ticks=0; u32 clock=0; u32 fparam=0; - void __iomem *mmio = pe->mmio_base; + void __iomem *mmio = pe->iomap[PDC_MMIO_BAR]; /* hard-code chip #0 */ mmio += PDC_CHIP0_OFS; @@ -1334,7 +1290,7 @@ #endif static void pdc_20621_init(struct ata_probe_ent *pe) { u32 tmp; - void __iomem *mmio = pe->mmio_base; + void __iomem *mmio = pe->iomap[PDC_MMIO_BAR]; /* hard-code chip #0 */ mmio += PDC_CHIP0_OFS; @@ -1365,67 +1321,43 @@ static void pdc_20621_init(struct ata_pr static int pdc_sata_init_one (struct pci_dev *pdev, const struct pci_device_id *ent) { static int printed_version; - struct ata_probe_ent *probe_ent = NULL; - unsigned long base; - void __iomem *mmio_base; - void __iomem *dimm_mmio = NULL; - struct pdc_host_priv *hpriv = NULL; + struct ata_probe_ent *probe_ent; + void __iomem *base; + struct pdc_host_priv *hpriv; unsigned int board_idx = (unsigned int) ent->driver_data; - int pci_dev_busy = 0; int rc; if (!printed_version++) dev_printk(KERN_DEBUG, &pdev->dev, "version " DRV_VERSION "\n"); - rc = pci_enable_device(pdev); + rc = pcim_enable_device(pdev); if (rc) return rc; - rc = pci_request_regions(pdev, DRV_NAME); - if (rc) { - pci_dev_busy = 1; - goto err_out; - } + rc = pcim_iomap_regions(pdev, (1 << PDC_MMIO_BAR) | (1 << PDC_DIMM_BAR), + DRV_NAME); + if (rc == -EBUSY) + pcim_pin_device(pdev); + if (rc) + return rc; rc = pci_set_dma_mask(pdev, ATA_DMA_MASK); if (rc) - goto err_out_regions; + return rc; rc = pci_set_consistent_dma_mask(pdev, ATA_DMA_MASK); if (rc) - goto err_out_regions; + return rc; - probe_ent = kmalloc(sizeof(*probe_ent), GFP_KERNEL); - if (probe_ent == NULL) { - rc = -ENOMEM; - goto err_out_regions; - } + probe_ent = devm_kzalloc(&pdev->dev, sizeof(*probe_ent), GFP_KERNEL); + if (probe_ent == NULL) + return -ENOMEM; - memset(probe_ent, 0, sizeof(*probe_ent)); probe_ent->dev = pci_dev_to_dev(pdev); INIT_LIST_HEAD(&probe_ent->node); - mmio_base = pci_iomap(pdev, 3, 0); - if (mmio_base == NULL) { - rc = -ENOMEM; - goto err_out_free_ent; - } - base = (unsigned long) mmio_base; - - hpriv = kmalloc(sizeof(*hpriv), GFP_KERNEL); - if (!hpriv) { - rc = -ENOMEM; - goto err_out_iounmap; - } - memset(hpriv, 0, sizeof(*hpriv)); - - dimm_mmio = pci_iomap(pdev, 4, 0); - if (!dimm_mmio) { - kfree(hpriv); - rc = -ENOMEM; - goto err_out_iounmap; - } - - hpriv->dimm_mmio = dimm_mmio; + hpriv = devm_kzalloc(&pdev->dev, sizeof(*hpriv), GFP_KERNEL); + if (!hpriv) + return -ENOMEM; probe_ent->sht = pdc_port_info[board_idx].sht; probe_ent->port_flags = pdc_port_info[board_idx].flags; @@ -1436,10 +1368,10 @@ static int pdc_sata_init_one (struct pci probe_ent->irq = pdev->irq; probe_ent->irq_flags = IRQF_SHARED; - probe_ent->mmio_base = mmio_base; + probe_ent->iomap = pcim_iomap_table(pdev); probe_ent->private_data = hpriv; - base += PDC_CHIP0_OFS; + base = probe_ent->iomap[PDC_MMIO_BAR] + PDC_CHIP0_OFS; probe_ent->n_ports = 4; pdc_sata_setup_port(&probe_ent->port[0], base + 0x200); @@ -1451,31 +1383,15 @@ static int pdc_sata_init_one (struct pci /* initialize adapter */ /* initialize local dimm */ - if (pdc20621_dimm_init(probe_ent)) { - rc = -ENOMEM; - goto err_out_iounmap_dimm; - } + if (pdc20621_dimm_init(probe_ent)) + return -ENOMEM; pdc_20621_init(probe_ent); - /* FIXME: check ata_device_add return value */ - ata_device_add(probe_ent); - kfree(probe_ent); + if (!ata_device_add(probe_ent)) + return -ENODEV; + devm_kfree(&pdev->dev, probe_ent); return 0; - -err_out_iounmap_dimm: /* only get to this label if 20621 */ - kfree(hpriv); - pci_iounmap(pdev, dimm_mmio); -err_out_iounmap: - pci_iounmap(pdev, mmio_base); -err_out_free_ent: - kfree(probe_ent); -err_out_regions: - pci_release_regions(pdev); -err_out: - if (!pci_dev_busy) - pci_disable_device(pdev); - return rc; } diff --git a/drivers/ata/sata_uli.c b/drivers/ata/sata_uli.c index a43aec6..80131ee 100644 --- a/drivers/ata/sata_uli.c +++ b/drivers/ata/sata_uli.c @@ -108,7 +108,7 @@ static const struct ata_port_operations .bmdma_status = ata_bmdma_status, .qc_prep = ata_qc_prep, .qc_issue = ata_qc_issue_prot, - .data_xfer = ata_pio_data_xfer, + .data_xfer = ata_data_xfer, .freeze = ata_bmdma_freeze, .thaw = ata_bmdma_thaw, @@ -117,13 +117,13 @@ static const struct ata_port_operations .irq_handler = ata_interrupt, .irq_clear = ata_bmdma_irq_clear, + .irq_on = ata_irq_on, + .irq_ack = ata_irq_ack, .scr_read = uli_scr_read, .scr_write = uli_scr_write, .port_start = ata_port_start, - .port_stop = ata_port_stop, - .host_stop = ata_host_stop, }; static struct ata_port_info uli_port_info = { @@ -189,62 +189,60 @@ static int uli_init_one (struct pci_dev struct ata_port_info *ppi[2]; int rc; unsigned int board_idx = (unsigned int) ent->driver_data; - int pci_dev_busy = 0; struct uli_priv *hpriv; + void __iomem * const *iomap; if (!printed_version++) dev_printk(KERN_INFO, &pdev->dev, "version " DRV_VERSION "\n"); - rc = pci_enable_device(pdev); + rc = pcim_enable_device(pdev); if (rc) return rc; rc = pci_request_regions(pdev, DRV_NAME); if (rc) { - pci_dev_busy = 1; - goto err_out; + pcim_pin_device(pdev); + return rc; } rc = pci_set_dma_mask(pdev, ATA_DMA_MASK); if (rc) - goto err_out_regions; + return rc; rc = pci_set_consistent_dma_mask(pdev, ATA_DMA_MASK); if (rc) - goto err_out_regions; + return rc; ppi[0] = ppi[1] = &uli_port_info; probe_ent = ata_pci_init_native_mode(pdev, ppi, ATA_PORT_PRIMARY | ATA_PORT_SECONDARY); - if (!probe_ent) { - rc = -ENOMEM; - goto err_out_regions; - } + if (!probe_ent) + return -ENOMEM; - hpriv = kzalloc(sizeof(*hpriv), GFP_KERNEL); - if (!hpriv) { - rc = -ENOMEM; - goto err_out_probe_ent; - } + hpriv = devm_kzalloc(&pdev->dev, sizeof(*hpriv), GFP_KERNEL); + if (!hpriv) + return -ENOMEM; probe_ent->private_data = hpriv; + iomap = pcim_iomap_table(pdev); + switch (board_idx) { case uli_5287: hpriv->scr_cfg_addr[0] = ULI5287_BASE; hpriv->scr_cfg_addr[1] = ULI5287_BASE + ULI5287_OFFS; probe_ent->n_ports = 4; - probe_ent->port[2].cmd_addr = pci_resource_start(pdev, 0) + 8; + probe_ent->port[2].cmd_addr = iomap[0] + 8; probe_ent->port[2].altstatus_addr = - probe_ent->port[2].ctl_addr = - (pci_resource_start(pdev, 1) | ATA_PCI_CTL_OFS) + 4; - probe_ent->port[2].bmdma_addr = pci_resource_start(pdev, 4) + 16; + probe_ent->port[2].ctl_addr = (void __iomem *) + ((unsigned long)iomap[1] | ATA_PCI_CTL_OFS) + 4; + probe_ent->port[2].bmdma_addr = iomap[4] + 16; hpriv->scr_cfg_addr[2] = ULI5287_BASE + ULI5287_OFFS*4; - probe_ent->port[3].cmd_addr = pci_resource_start(pdev, 2) + 8; + probe_ent->port[3].cmd_addr = iomap[2] + 8; probe_ent->port[3].altstatus_addr = - probe_ent->port[3].ctl_addr = - (pci_resource_start(pdev, 3) | ATA_PCI_CTL_OFS) + 4; - probe_ent->port[3].bmdma_addr = pci_resource_start(pdev, 4) + 24; + probe_ent->port[3].ctl_addr = (void __iomem *) + ((unsigned long)iomap[3] | ATA_PCI_CTL_OFS) + 4; + probe_ent->port[3].bmdma_addr = iomap[4] + 24; hpriv->scr_cfg_addr[3] = ULI5287_BASE + ULI5287_OFFS*5; ata_std_ports(&probe_ent->port[2]); @@ -269,21 +267,11 @@ static int uli_init_one (struct pci_dev pci_set_master(pdev); pci_intx(pdev, 1); - /* FIXME: check ata_device_add return value */ - ata_device_add(probe_ent); - kfree(probe_ent); + if (!ata_device_add(probe_ent)) + return -ENODEV; + devm_kfree(&pdev->dev, probe_ent); return 0; - -err_out_probe_ent: - kfree(probe_ent); -err_out_regions: - pci_release_regions(pdev); -err_out: - if (!pci_dev_busy) - pci_disable_device(pdev); - return rc; - } static int __init uli_init(void) diff --git a/drivers/ata/sata_via.c b/drivers/ata/sata_via.c index d3d5c0d..baca6d7 100644 --- a/drivers/ata/sata_via.c +++ b/drivers/ata/sata_via.c @@ -44,7 +44,6 @@ #include #include #include #include -#include #define DRV_NAME "sata_via" #define DRV_VERSION "2.0" @@ -59,11 +58,14 @@ enum { SATA_INT_GATE = 0x41, /* SATA interrupt gating */ SATA_NATIVE_MODE = 0x42, /* Native mode enable */ SATA_PATA_SHARING = 0x49, /* PATA/SATA sharing func ctrl */ - + PATA_UDMA_TIMING = 0xB3, /* PATA timing for DMA/ cable detect */ + PATA_PIO_TIMING = 0xAB, /* PATA timing register */ + PORT0 = (1 << 1), PORT1 = (1 << 0), ALL_PORTS = PORT0 | PORT1, - N_PORTS = 2, + PATA_PORT = 2, /* PATA is port 2 */ + N_PORTS = 3, NATIVE_MODE_ALL = (1 << 7) | (1 << 6) | (1 << 5) | (1 << 4), @@ -76,6 +78,11 @@ static u32 svia_scr_read (struct ata_por static void svia_scr_write (struct ata_port *ap, unsigned int sc_reg, u32 val); static void svia_noop_freeze(struct ata_port *ap); static void vt6420_error_handler(struct ata_port *ap); +static void vt6421_sata_error_handler(struct ata_port *ap); +static void vt6421_pata_error_handler(struct ata_port *ap); +static void vt6421_set_pio_mode(struct ata_port *ap, struct ata_device *adev); +static void vt6421_set_dma_mode(struct ata_port *ap, struct ata_device *adev); +static int vt6421_port_start(struct ata_port *ap); static const struct pci_device_id svia_pci_tbl[] = { { PCI_VDEVICE(VIA, 0x5337), vt6420 }, @@ -127,7 +134,7 @@ static const struct ata_port_operations .qc_prep = ata_qc_prep, .qc_issue = ata_qc_issue_prot, - .data_xfer = ata_pio_data_xfer, + .data_xfer = ata_data_xfer, .freeze = svia_noop_freeze, .thaw = ata_bmdma_thaw, @@ -136,15 +143,49 @@ static const struct ata_port_operations .irq_handler = ata_interrupt, .irq_clear = ata_bmdma_irq_clear, + .irq_on = ata_irq_on, + .irq_ack = ata_irq_ack, .port_start = ata_port_start, - .port_stop = ata_port_stop, - .host_stop = ata_host_stop, }; -static const struct ata_port_operations vt6421_sata_ops = { +static const struct ata_port_operations vt6421_pata_ops = { .port_disable = ata_port_disable, + + .set_piomode = vt6421_set_pio_mode, + .set_dmamode = vt6421_set_dma_mode, + + .tf_load = ata_tf_load, + .tf_read = ata_tf_read, + .check_status = ata_check_status, + .exec_command = ata_exec_command, + .dev_select = ata_std_dev_select, + + .bmdma_setup = ata_bmdma_setup, + .bmdma_start = ata_bmdma_start, + .bmdma_stop = ata_bmdma_stop, + .bmdma_status = ata_bmdma_status, + + .qc_prep = ata_qc_prep, + .qc_issue = ata_qc_issue_prot, + .data_xfer = ata_data_xfer, + + .freeze = ata_bmdma_freeze, + .thaw = ata_bmdma_thaw, + .error_handler = vt6421_pata_error_handler, + .post_internal_cmd = ata_bmdma_post_internal_cmd, + .irq_handler = ata_interrupt, + .irq_clear = ata_bmdma_irq_clear, + .irq_on = ata_irq_on, + .irq_ack = ata_irq_ack, + + .port_start = vt6421_port_start, +}; + +static const struct ata_port_operations vt6421_sata_ops = { + .port_disable = ata_port_disable, + .tf_load = ata_tf_load, .tf_read = ata_tf_read, .check_status = ata_check_status, @@ -158,22 +199,22 @@ static const struct ata_port_operations .qc_prep = ata_qc_prep, .qc_issue = ata_qc_issue_prot, - .data_xfer = ata_pio_data_xfer, + .data_xfer = ata_data_xfer, .freeze = ata_bmdma_freeze, .thaw = ata_bmdma_thaw, - .error_handler = ata_bmdma_error_handler, + .error_handler = vt6421_sata_error_handler, .post_internal_cmd = ata_bmdma_post_internal_cmd, .irq_handler = ata_interrupt, .irq_clear = ata_bmdma_irq_clear, + .irq_on = ata_irq_on, + .irq_ack = ata_irq_ack, .scr_read = svia_scr_read, .scr_write = svia_scr_write, - .port_start = ata_port_start, - .port_stop = ata_port_stop, - .host_stop = ata_host_stop, + .port_start = vt6421_port_start, }; static struct ata_port_info vt6420_port_info = { @@ -195,14 +236,14 @@ static u32 svia_scr_read (struct ata_por { if (sc_reg > SCR_CONTROL) return 0xffffffffU; - return inl(ap->ioaddr.scr_addr + (4 * sc_reg)); + return ioread32(ap->ioaddr.scr_addr + (4 * sc_reg)); } static void svia_scr_write (struct ata_port *ap, unsigned int sc_reg, u32 val) { if (sc_reg > SCR_CONTROL) return; - outl(val, ap->ioaddr.scr_addr + (4 * sc_reg)); + iowrite32(val, ap->ioaddr.scr_addr + (4 * sc_reg)); } static void svia_noop_freeze(struct ata_port *ap) @@ -289,6 +330,61 @@ static void vt6420_error_handler(struct NULL, ata_std_postreset); } +static int vt6421_pata_prereset(struct ata_port *ap) +{ + struct pci_dev *pdev = to_pci_dev(ap->host->dev); + u8 tmp; + + pci_read_config_byte(pdev, PATA_UDMA_TIMING, &tmp); + if (tmp & 0x10) + ap->cbl = ATA_CBL_PATA40; + else + ap->cbl = ATA_CBL_PATA80; + return 0; +} + +static void vt6421_pata_error_handler(struct ata_port *ap) +{ + return ata_bmdma_drive_eh(ap, vt6421_pata_prereset, ata_std_softreset, + NULL, ata_std_postreset); +} + +static int vt6421_sata_prereset(struct ata_port *ap) +{ + ap->cbl = ATA_CBL_SATA; + return 0; +} + +static void vt6421_sata_error_handler(struct ata_port *ap) +{ + return ata_bmdma_drive_eh(ap, vt6421_sata_prereset, ata_std_softreset, + NULL, ata_std_postreset); +} + +static void vt6421_set_pio_mode(struct ata_port *ap, struct ata_device *adev) +{ + struct pci_dev *pdev = to_pci_dev(ap->host->dev); + static const u8 pio_bits[] = { 0xA8, 0x65, 0x65, 0x31, 0x20 }; + pci_write_config_byte(pdev, PATA_PIO_TIMING, pio_bits[adev->pio_mode - XFER_PIO_0]); +} + +static void vt6421_set_dma_mode(struct ata_port *ap, struct ata_device *adev) +{ + struct pci_dev *pdev = to_pci_dev(ap->host->dev); + static const u8 udma_bits[] = { 0xEE, 0xE8, 0xE6, 0xE4, 0xE2, 0xE1, 0xE0, 0xE0 }; + pci_write_config_byte(pdev, PATA_UDMA_TIMING, udma_bits[adev->pio_mode - XFER_UDMA_0]); +} + +static int vt6421_port_start(struct ata_port *ap) +{ + if (ap->port_no == PATA_PORT) { + ap->ops = &vt6421_pata_ops; + ap->mwdma_mask = 0; + ap->flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_NO_LEGACY | ATA_FLAG_SRST; + } + return ata_port_start(ap); +} + static const unsigned int svia_bar_sizes[] = { 8, 4, 8, 4, 16, 256 }; @@ -297,31 +393,28 @@ static const unsigned int vt6421_bar_siz 16, 16, 16, 16, 32, 128 }; -static unsigned long svia_scr_addr(unsigned long addr, unsigned int port) +static void __iomem * svia_scr_addr(void __iomem *addr, unsigned int port) { return addr + (port * 128); } -static unsigned long vt6421_scr_addr(unsigned long addr, unsigned int port) +static void __iomem * vt6421_scr_addr(void __iomem *addr, unsigned int port) { return addr + (port * 64); } static void vt6421_init_addrs(struct ata_probe_ent *probe_ent, - struct pci_dev *pdev, - unsigned int port) + void __iomem * const *iomap, unsigned int port) { - unsigned long reg_addr = pci_resource_start(pdev, port); - unsigned long bmdma_addr = pci_resource_start(pdev, 4) + (port * 8); - unsigned long scr_addr; + void __iomem *reg_addr = iomap[port]; + void __iomem *bmdma_addr = iomap[4] + (port * 8); probe_ent->port[port].cmd_addr = reg_addr; probe_ent->port[port].altstatus_addr = - probe_ent->port[port].ctl_addr = (reg_addr + 8) | ATA_PCI_CTL_OFS; + probe_ent->port[port].ctl_addr = (void __iomem *) + ((unsigned long)(reg_addr + 8) | ATA_PCI_CTL_OFS); probe_ent->port[port].bmdma_addr = bmdma_addr; - - scr_addr = vt6421_scr_addr(pci_resource_start(pdev, 5), port); - probe_ent->port[port].scr_addr = scr_addr; + probe_ent->port[port].scr_addr = vt6421_scr_addr(iomap[5], port); ata_std_ports(&probe_ent->port[port]); } @@ -330,16 +423,16 @@ static struct ata_probe_ent *vt6420_init { struct ata_probe_ent *probe_ent; struct ata_port_info *ppi[2]; - + void __iomem * const *iomap; + ppi[0] = ppi[1] = &vt6420_port_info; probe_ent = ata_pci_init_native_mode(pdev, ppi, ATA_PORT_PRIMARY | ATA_PORT_SECONDARY); if (!probe_ent) return NULL; - probe_ent->port[0].scr_addr = - svia_scr_addr(pci_resource_start(pdev, 5), 0); - probe_ent->port[1].scr_addr = - svia_scr_addr(pci_resource_start(pdev, 5), 1); + iomap = pcim_iomap_table(pdev); + probe_ent->port[0].scr_addr = svia_scr_addr(iomap[5], 0); + probe_ent->port[1].scr_addr = svia_scr_addr(iomap[5], 1); return probe_ent; } @@ -349,7 +442,7 @@ static struct ata_probe_ent *vt6421_init struct ata_probe_ent *probe_ent; unsigned int i; - probe_ent = kmalloc(sizeof(*probe_ent), GFP_KERNEL); + probe_ent = devm_kzalloc(&pdev->dev, sizeof(*probe_ent), GFP_KERNEL); if (!probe_ent) return NULL; @@ -368,7 +461,7 @@ static struct ata_probe_ent *vt6421_init probe_ent->udma_mask = 0x7f; for (i = 0; i < N_PORTS; i++) - vt6421_init_addrs(probe_ent, pdev, i); + vt6421_init_addrs(probe_ent, pcim_iomap_table(pdev), i); return probe_ent; } @@ -420,20 +513,19 @@ static int svia_init_one (struct pci_dev struct ata_probe_ent *probe_ent; int board_id = (int) ent->driver_data; const int *bar_sizes; - int pci_dev_busy = 0; u8 tmp8; if (!printed_version++) dev_printk(KERN_DEBUG, &pdev->dev, "version " DRV_VERSION "\n"); - rc = pci_enable_device(pdev); + rc = pcim_enable_device(pdev); if (rc) return rc; - rc = pci_request_regions(pdev, DRV_NAME); + rc = pcim_iomap_regions(pdev, 0x1f, DRV_NAME); if (rc) { - pci_dev_busy = 1; - goto err_out; + pcim_pin_device(pdev); + return rc; } if (board_id == vt6420) { @@ -442,8 +534,7 @@ static int svia_init_one (struct pci_dev dev_printk(KERN_ERR, &pdev->dev, "SATA master/slave not supported (0x%x)\n", (int) tmp8); - rc = -EIO; - goto err_out_regions; + return -EIO; } bar_sizes = &svia_bar_sizes[0]; @@ -459,16 +550,15 @@ static int svia_init_one (struct pci_dev i, (unsigned long long)pci_resource_start(pdev, i), (unsigned long long)pci_resource_len(pdev, i)); - rc = -ENODEV; - goto err_out_regions; + return -ENODEV; } rc = pci_set_dma_mask(pdev, ATA_DMA_MASK); if (rc) - goto err_out_regions; + return rc; rc = pci_set_consistent_dma_mask(pdev, ATA_DMA_MASK); if (rc) - goto err_out_regions; + return rc; if (board_id == vt6420) probe_ent = vt6420_init_probe_ent(pdev); @@ -477,26 +567,18 @@ static int svia_init_one (struct pci_dev if (!probe_ent) { dev_printk(KERN_ERR, &pdev->dev, "out of memory\n"); - rc = -ENOMEM; - goto err_out_regions; + return -ENOMEM; } svia_configure(pdev); pci_set_master(pdev); - /* FIXME: check ata_device_add return value */ - ata_device_add(probe_ent); - kfree(probe_ent); + if (!ata_device_add(probe_ent)) + return -ENODEV; + devm_kfree(&pdev->dev, probe_ent); return 0; - -err_out_regions: - pci_release_regions(pdev); -err_out: - if (!pci_dev_busy) - pci_disable_device(pdev); - return rc; } static int __init svia_init(void) @@ -511,4 +593,3 @@ static void __exit svia_exit(void) module_init(svia_init); module_exit(svia_exit); - diff --git a/drivers/ata/sata_vsc.c b/drivers/ata/sata_vsc.c index 0fa1b89..2fd037b 100644 --- a/drivers/ata/sata_vsc.c +++ b/drivers/ata/sata_vsc.c @@ -50,6 +50,8 @@ #define DRV_NAME "sata_vsc" #define DRV_VERSION "2.0" enum { + VSC_MMIO_BAR = 0, + /* Interrupt register offsets (from chip base address) */ VSC_SATA_INT_STAT_OFFSET = 0x00, VSC_SATA_INT_MASK_OFFSET = 0x04, @@ -96,7 +98,6 @@ enum { VSC_SATA_INT_PHY_CHANGE), }; - #define is_vsc_sata_int_err(port_idx, int_status) \ (int_status & (VSC_SATA_INT_ERROR << (8 * port_idx))) @@ -105,7 +106,7 @@ static u32 vsc_sata_scr_read (struct ata { if (sc_reg > SCR_CONTROL) return 0xffffffffU; - return readl((void __iomem *) ap->ioaddr.scr_addr + (sc_reg * 4)); + return readl(ap->ioaddr.scr_addr + (sc_reg * 4)); } @@ -114,7 +115,7 @@ static void vsc_sata_scr_write (struct a { if (sc_reg > SCR_CONTROL) return; - writel(val, (void __iomem *) ap->ioaddr.scr_addr + (sc_reg * 4)); + writel(val, ap->ioaddr.scr_addr + (sc_reg * 4)); } @@ -123,7 +124,7 @@ static void vsc_intr_mask_update(struct void __iomem *mask_addr; u8 mask; - mask_addr = ap->host->mmio_base + + mask_addr = ap->host->iomap[VSC_MMIO_BAR] + VSC_SATA_INT_MASK_OFFSET + ap->port_no; mask = readb(mask_addr); if (ctl & ATA_NIEN) @@ -150,25 +151,25 @@ static void vsc_sata_tf_load(struct ata_ } if (is_addr && (tf->flags & ATA_TFLAG_LBA48)) { writew(tf->feature | (((u16)tf->hob_feature) << 8), - (void __iomem *) ioaddr->feature_addr); + ioaddr->feature_addr); writew(tf->nsect | (((u16)tf->hob_nsect) << 8), - (void __iomem *) ioaddr->nsect_addr); + ioaddr->nsect_addr); writew(tf->lbal | (((u16)tf->hob_lbal) << 8), - (void __iomem *) ioaddr->lbal_addr); + ioaddr->lbal_addr); writew(tf->lbam | (((u16)tf->hob_lbam) << 8), - (void __iomem *) ioaddr->lbam_addr); + ioaddr->lbam_addr); writew(tf->lbah | (((u16)tf->hob_lbah) << 8), - (void __iomem *) ioaddr->lbah_addr); + ioaddr->lbah_addr); } else if (is_addr) { - writew(tf->feature, (void __iomem *) ioaddr->feature_addr); - writew(tf->nsect, (void __iomem *) ioaddr->nsect_addr); - writew(tf->lbal, (void __iomem *) ioaddr->lbal_addr); - writew(tf->lbam, (void __iomem *) ioaddr->lbam_addr); - writew(tf->lbah, (void __iomem *) ioaddr->lbah_addr); + writew(tf->feature, ioaddr->feature_addr); + writew(tf->nsect, ioaddr->nsect_addr); + writew(tf->lbal, ioaddr->lbal_addr); + writew(tf->lbam, ioaddr->lbam_addr); + writew(tf->lbah, ioaddr->lbah_addr); } if (tf->flags & ATA_TFLAG_DEVICE) - writeb(tf->device, (void __iomem *) ioaddr->device_addr); + writeb(tf->device, ioaddr->device_addr); ata_wait_idle(ap); } @@ -180,12 +181,12 @@ static void vsc_sata_tf_read(struct ata_ u16 nsect, lbal, lbam, lbah, feature; tf->command = ata_check_status(ap); - tf->device = readw((void __iomem *) ioaddr->device_addr); - feature = readw((void __iomem *) ioaddr->error_addr); - nsect = readw((void __iomem *) ioaddr->nsect_addr); - lbal = readw((void __iomem *) ioaddr->lbal_addr); - lbam = readw((void __iomem *) ioaddr->lbam_addr); - lbah = readw((void __iomem *) ioaddr->lbah_addr); + tf->device = readw(ioaddr->device_addr); + feature = readw(ioaddr->error_addr); + nsect = readw(ioaddr->nsect_addr); + lbal = readw(ioaddr->lbal_addr); + lbam = readw(ioaddr->lbam_addr); + lbah = readw(ioaddr->lbah_addr); tf->feature = feature; tf->nsect = nsect; @@ -217,7 +218,8 @@ static irqreturn_t vsc_sata_interrupt (i spin_lock(&host->lock); - int_status = readl(host->mmio_base + VSC_SATA_INT_STAT_OFFSET); + int_status = readl(host->iomap[VSC_MMIO_BAR] + + VSC_SATA_INT_STAT_OFFSET); for (i = 0; i < host->n_ports; i++) { if (int_status & ((u32) 0xFF << (8 * i))) { @@ -301,21 +303,22 @@ static const struct ata_port_operations .bmdma_status = ata_bmdma_status, .qc_prep = ata_qc_prep, .qc_issue = ata_qc_issue_prot, - .data_xfer = ata_mmio_data_xfer, + .data_xfer = ata_data_xfer, .freeze = ata_bmdma_freeze, .thaw = ata_bmdma_thaw, .error_handler = ata_bmdma_error_handler, .post_internal_cmd = ata_bmdma_post_internal_cmd, .irq_handler = vsc_sata_interrupt, .irq_clear = ata_bmdma_irq_clear, + .irq_on = ata_irq_on, + .irq_ack = ata_irq_ack, .scr_read = vsc_sata_scr_read, .scr_write = vsc_sata_scr_write, .port_start = ata_port_start, - .port_stop = ata_port_stop, - .host_stop = ata_pci_host_stop, }; -static void __devinit vsc_sata_setup_port(struct ata_ioports *port, unsigned long base) +static void __devinit vsc_sata_setup_port(struct ata_ioports *port, + void __iomem *base) { port->cmd_addr = base + VSC_SATA_TF_CMD_OFFSET; port->data_addr = base + VSC_SATA_TF_DATA_OFFSET; @@ -332,71 +335,66 @@ static void __devinit vsc_sata_setup_por port->ctl_addr = base + VSC_SATA_TF_CTL_OFFSET; port->bmdma_addr = base + VSC_SATA_DMA_CMD_OFFSET; port->scr_addr = base + VSC_SATA_SCR_STATUS_OFFSET; - writel(0, (void __iomem *) base + VSC_SATA_UP_DESCRIPTOR_OFFSET); - writel(0, (void __iomem *) base + VSC_SATA_UP_DATA_BUFFER_OFFSET); + writel(0, base + VSC_SATA_UP_DESCRIPTOR_OFFSET); + writel(0, base + VSC_SATA_UP_DATA_BUFFER_OFFSET); } static int __devinit vsc_sata_init_one (struct pci_dev *pdev, const struct pci_device_id *ent) { static int printed_version; - struct ata_probe_ent *probe_ent = NULL; - unsigned long base; - int pci_dev_busy = 0; + struct ata_probe_ent *probe_ent; void __iomem *mmio_base; int rc; + u8 cls; if (!printed_version++) dev_printk(KERN_DEBUG, &pdev->dev, "version " DRV_VERSION "\n"); - rc = pci_enable_device(pdev); + rc = pcim_enable_device(pdev); if (rc) return rc; /* * Check if we have needed resource mapped. */ - if (pci_resource_len(pdev, 0) == 0) { - rc = -ENODEV; - goto err_out; - } + if (pci_resource_len(pdev, 0) == 0) + return -ENODEV; - rc = pci_request_regions(pdev, DRV_NAME); - if (rc) { - pci_dev_busy = 1; - goto err_out; - } + rc = pcim_iomap_regions(pdev, 1 << VSC_MMIO_BAR, DRV_NAME); + if (rc == -EBUSY) + pcim_pin_device(pdev); + if (rc) + return rc; /* * Use 32 bit DMA mask, because 64 bit address support is poor. */ rc = pci_set_dma_mask(pdev, DMA_32BIT_MASK); if (rc) - goto err_out_regions; + return rc; rc = pci_set_consistent_dma_mask(pdev, DMA_32BIT_MASK); if (rc) - goto err_out_regions; + return rc; - probe_ent = kmalloc(sizeof(*probe_ent), GFP_KERNEL); - if (probe_ent == NULL) { - rc = -ENOMEM; - goto err_out_regions; - } - memset(probe_ent, 0, sizeof(*probe_ent)); + probe_ent = devm_kzalloc(&pdev->dev, sizeof(*probe_ent), GFP_KERNEL); + if (probe_ent == NULL) + return -ENOMEM; probe_ent->dev = pci_dev_to_dev(pdev); INIT_LIST_HEAD(&probe_ent->node); - mmio_base = pci_iomap(pdev, 0, 0); - if (mmio_base == NULL) { - rc = -ENOMEM; - goto err_out_free_ent; - } - base = (unsigned long) mmio_base; - /* - * Due to a bug in the chip, the default cache line size can't be used + * Due to a bug in the chip, the default cache line size can't be + * used (unless the default is non-zero). */ - pci_write_config_byte(pdev, PCI_CACHE_LINE_SIZE, 0x80); + pci_read_config_byte(pdev, PCI_CACHE_LINE_SIZE, &cls); + if (cls == 0x00) + pci_write_config_byte(pdev, PCI_CACHE_LINE_SIZE, 0x80); + + if (pci_enable_msi(pdev) == 0) + pci_intx(pdev, 0); + else + probe_ent->irq_flags = IRQF_SHARED; probe_ent->sht = &vsc_sata_sht; probe_ent->port_flags = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY | @@ -404,8 +402,7 @@ static int __devinit vsc_sata_init_one ( probe_ent->port_ops = &vsc_sata_ops; probe_ent->n_ports = 4; probe_ent->irq = pdev->irq; - probe_ent->irq_flags = IRQF_SHARED; - probe_ent->mmio_base = mmio_base; + probe_ent->iomap = pcim_iomap_table(pdev); /* We don't care much about the PIO/UDMA masks, but the core won't like us * if we don't fill these @@ -414,11 +411,13 @@ static int __devinit vsc_sata_init_one ( probe_ent->mwdma_mask = 0x07; probe_ent->udma_mask = 0x7f; + mmio_base = probe_ent->iomap[VSC_MMIO_BAR]; + /* We have 4 ports per PCI function */ - vsc_sata_setup_port(&probe_ent->port[0], base + 1 * VSC_SATA_PORT_OFFSET); - vsc_sata_setup_port(&probe_ent->port[1], base + 2 * VSC_SATA_PORT_OFFSET); - vsc_sata_setup_port(&probe_ent->port[2], base + 3 * VSC_SATA_PORT_OFFSET); - vsc_sata_setup_port(&probe_ent->port[3], base + 4 * VSC_SATA_PORT_OFFSET); + vsc_sata_setup_port(&probe_ent->port[0], mmio_base + 1 * VSC_SATA_PORT_OFFSET); + vsc_sata_setup_port(&probe_ent->port[1], mmio_base + 2 * VSC_SATA_PORT_OFFSET); + vsc_sata_setup_port(&probe_ent->port[2], mmio_base + 3 * VSC_SATA_PORT_OFFSET); + vsc_sata_setup_port(&probe_ent->port[3], mmio_base + 4 * VSC_SATA_PORT_OFFSET); pci_set_master(pdev); @@ -430,20 +429,11 @@ static int __devinit vsc_sata_init_one ( */ pci_write_config_dword(pdev, 0x98, 0); - /* FIXME: check ata_device_add return value */ - ata_device_add(probe_ent); - kfree(probe_ent); + if (!ata_device_add(probe_ent)) + return -ENODEV; + devm_kfree(&pdev->dev, probe_ent); return 0; - -err_out_free_ent: - kfree(probe_ent); -err_out_regions: - pci_release_regions(pdev); -err_out: - if (!pci_dev_busy) - pci_disable_device(pdev); - return rc; } static const struct pci_device_id vsc_sata_pci_tbl[] = { diff --git a/drivers/atm/adummy.c b/drivers/atm/adummy.c index ac2c108..8d60c4e 100644 --- a/drivers/atm/adummy.c +++ b/drivers/atm/adummy.c @@ -13,7 +13,6 @@ #include #include #include #include -#include #include #include #include diff --git a/drivers/atm/eni.c b/drivers/atm/eni.c index 5aab7bd..8fccf01 100644 --- a/drivers/atm/eni.c +++ b/drivers/atm/eni.c @@ -912,7 +912,6 @@ static int start_rx(struct atm_dev *dev) free_page((unsigned long) eni_dev->free_list); return -ENOMEM; } - memset(eni_dev->rx_map,0,PAGE_SIZE); eni_dev->rx_mult = DEFAULT_RX_MULT; eni_dev->fast = eni_dev->last_fast = NULL; eni_dev->slow = eni_dev->last_slow = NULL; diff --git a/drivers/atm/fore200e.c b/drivers/atm/fore200e.c index 4aeb3d0..a7c0ed3 100644 --- a/drivers/atm/fore200e.c +++ b/drivers/atm/fore200e.c @@ -29,7 +29,6 @@ #include #include #include #include -#include #include #include #include diff --git a/drivers/atm/idt77105.c b/drivers/atm/idt77105.c index 325325a..0bd657f 100644 --- a/drivers/atm/idt77105.c +++ b/drivers/atm/idt77105.c @@ -4,7 +4,6 @@ #include -#include #include #include #include diff --git a/drivers/atm/uPD98402.c b/drivers/atm/uPD98402.c index 9504cce..fc8cb07 100644 --- a/drivers/atm/uPD98402.c +++ b/drivers/atm/uPD98402.c @@ -4,7 +4,6 @@ #include -#include /* for jiffies */ #include #include #include diff --git a/drivers/atm/zatm.c b/drivers/atm/zatm.c index 756d4f7..0d7091e 100644 --- a/drivers/atm/zatm.c +++ b/drivers/atm/zatm.c @@ -4,7 +4,6 @@ #include -#include #include #include #include diff --git a/drivers/auxdisplay/Kconfig b/drivers/auxdisplay/Kconfig new file mode 100644 index 0000000..0300e7f --- /dev/null +++ b/drivers/auxdisplay/Kconfig @@ -0,0 +1,109 @@ +# +# For a description of the syntax of this configuration file, +# see Documentation/kbuild/kconfig-language.txt. +# +# Auxiliary display drivers configuration. +# + +menu "Auxiliary Display support" + +config KS0108 + tristate "KS0108 LCD Controller" + depends on PARPORT_PC + default n + ---help--- + If you have a LCD controlled by one or more KS0108 + controllers, say Y. You will need also another more specific + driver for your LCD. + + Depends on Parallel Port support. If you say Y at + parport, you will be able to compile this as a module (M) + and built-in as well (Y). + + To compile this as a module, choose M here: + the module will be called ks0108. + + If unsure, say N. + +config KS0108_PORT + hex "Parallel port where the LCD is connected" + depends on KS0108 + default 0x378 + ---help--- + The address of the parallel port where the LCD is connected. + + The first standard parallel port address is 0x378. + The second standard parallel port address is 0x278. + The third standard parallel port address is 0x3BC. + + You can specify a different address if you need. + + If you don't know what I'm talking about, load the parport module, + and execute "dmesg" or "cat /proc/ioports". You can see there how + many parallel ports are present and which address each one has. + + Usually you only need to use 0x378. + + If you compile this as a module, you can still override this + using the module parameters. + +config KS0108_DELAY + int "Delay between each control writing (microseconds)" + depends on KS0108 + default "2" + ---help--- + Amount of time the ks0108 should wait between each control write + to the parallel port. + + If your driver seems to miss random writings, increment this. + + If you don't know what I'm talking about, ignore it. + + If you compile this as a module, you can still override this + value using the module parameters. + +config CFAG12864B + tristate "CFAG12864B LCD" + depends on X86 + depends on FB + depends on KS0108 + default n + ---help--- + If you have a Crystalfontz 128x64 2-color LCD, cfag12864b Series, + say Y. You also need the ks0108 LCD Controller driver. + + For help about how to wire your LCD to the parallel port, + check Documentation/auxdisplay/cfag12864b + + Depends on the x86 arch and the framebuffer support. + + The LCD framebuffer driver can be attached to a console. + It will work fine. However, you can't attach it to the fbdev driver + of the xorg server. + + To compile this as a module, choose M here: + the modules will be called cfag12864b and cfag12864bfb. + + If unsure, say N. + +config CFAG12864B_RATE + int "Refresh rate (hertz)" + depends on CFAG12864B + default "20" + ---help--- + Refresh rate of the LCD. + + As the LCD is not memory mapped, the driver has to make the work by + software. This means you should be careful setting this value higher. + If your CPUs are really slow or you feel the system is slowed down, + decrease the value. + + Be careful modifying this value to a very high value: + You can freeze the computer, or the LCD maybe can't draw as fast as you + are requesting. + + If you don't know what I'm talking about, ignore it. + + If you compile this as a module, you can still override this + value using the module parameters. +endmenu diff --git a/drivers/auxdisplay/Makefile b/drivers/auxdisplay/Makefile new file mode 100644 index 0000000..8a8936a --- /dev/null +++ b/drivers/auxdisplay/Makefile @@ -0,0 +1,6 @@ +# +# Makefile for the kernel auxiliary displays device drivers. +# + +obj-$(CONFIG_KS0108) += ks0108.o +obj-$(CONFIG_CFAG12864B) += cfag12864b.o cfag12864bfb.o diff --git a/drivers/auxdisplay/cfag12864b.c b/drivers/auxdisplay/cfag12864b.c new file mode 100644 index 0000000..889583d --- /dev/null +++ b/drivers/auxdisplay/cfag12864b.c @@ -0,0 +1,383 @@ +/* + * Filename: cfag12864b.c + * Version: 0.1.0 + * Description: cfag12864b LCD driver + * License: GPLv2 + * Depends: ks0108 + * + * Author: Copyright (C) Miguel Ojeda Sandonis + * Date: 2006-10-31 + * + * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +#define CFAG12864B_NAME "cfag12864b" + +/* + * Module Parameters + */ + +static unsigned int cfag12864b_rate = CONFIG_CFAG12864B_RATE; +module_param(cfag12864b_rate, uint, S_IRUGO); +MODULE_PARM_DESC(cfag12864b_rate, + "Refresh rate (hertzs)"); + +unsigned int cfag12864b_getrate(void) +{ + return cfag12864b_rate; +} + +/* + * cfag12864b Commands + * + * E = Enable signal + * Everytime E switch from low to high, + * cfag12864b/ks0108 reads the command/data. + * + * CS1 = First ks0108controller. + * If high, the first ks0108 controller receives commands/data. + * + * CS2 = Second ks0108 controller + * If high, the second ks0108 controller receives commands/data. + * + * DI = Data/Instruction + * If low, cfag12864b will expect commands. + * If high, cfag12864b will expect data. + * + */ + +#define bit(n) (((unsigned char)1)<<(n)) + +#define CFAG12864B_BIT_E (0) +#define CFAG12864B_BIT_CS1 (2) +#define CFAG12864B_BIT_CS2 (1) +#define CFAG12864B_BIT_DI (3) + +static unsigned char cfag12864b_state; + +static void cfag12864b_set(void) +{ + ks0108_writecontrol(cfag12864b_state); +} + +static void cfag12864b_setbit(unsigned char state, unsigned char n) +{ + if (state) + cfag12864b_state |= bit(n); + else + cfag12864b_state &= ~bit(n); +} + +static void cfag12864b_e(unsigned char state) +{ + cfag12864b_setbit(state, CFAG12864B_BIT_E); + cfag12864b_set(); +} + +static void cfag12864b_cs1(unsigned char state) +{ + cfag12864b_setbit(state, CFAG12864B_BIT_CS1); +} + +static void cfag12864b_cs2(unsigned char state) +{ + cfag12864b_setbit(state, CFAG12864B_BIT_CS2); +} + +static void cfag12864b_di(unsigned char state) +{ + cfag12864b_setbit(state, CFAG12864B_BIT_DI); +} + +static void cfag12864b_setcontrollers(unsigned char first, + unsigned char second) +{ + if (first) + cfag12864b_cs1(0); + else + cfag12864b_cs1(1); + + if (second) + cfag12864b_cs2(0); + else + cfag12864b_cs2(1); +} + +static void cfag12864b_controller(unsigned char which) +{ + if (which == 0) + cfag12864b_setcontrollers(1, 0); + else if (which == 1) + cfag12864b_setcontrollers(0, 1); +} + +static void cfag12864b_displaystate(unsigned char state) +{ + cfag12864b_di(0); + cfag12864b_e(1); + ks0108_displaystate(state); + cfag12864b_e(0); +} + +static void cfag12864b_address(unsigned char address) +{ + cfag12864b_di(0); + cfag12864b_e(1); + ks0108_address(address); + cfag12864b_e(0); +} + +static void cfag12864b_page(unsigned char page) +{ + cfag12864b_di(0); + cfag12864b_e(1); + ks0108_page(page); + cfag12864b_e(0); +} + +static void cfag12864b_startline(unsigned char startline) +{ + cfag12864b_di(0); + cfag12864b_e(1); + ks0108_startline(startline); + cfag12864b_e(0); +} + +static void cfag12864b_writebyte(unsigned char byte) +{ + cfag12864b_di(1); + cfag12864b_e(1); + ks0108_writedata(byte); + cfag12864b_e(0); +} + +static void cfag12864b_nop(void) +{ + cfag12864b_startline(0); +} + +/* + * cfag12864b Internal Commands + */ + +static void cfag12864b_on(void) +{ + cfag12864b_setcontrollers(1, 1); + cfag12864b_displaystate(1); +} + +static void cfag12864b_off(void) +{ + cfag12864b_setcontrollers(1, 1); + cfag12864b_displaystate(0); +} + +static void cfag12864b_clear(void) +{ + unsigned char i, j; + + cfag12864b_setcontrollers(1, 1); + for (i = 0; i < CFAG12864B_PAGES; i++) { + cfag12864b_page(i); + cfag12864b_address(0); + for (j = 0; j < CFAG12864B_ADDRESSES; j++) + cfag12864b_writebyte(0); + } +} + +/* + * Update work + */ + +unsigned char *cfag12864b_buffer; +static unsigned char *cfag12864b_cache; +static DEFINE_MUTEX(cfag12864b_mutex); +static unsigned char cfag12864b_updating; +static void cfag12864b_update(struct work_struct *delayed_work); +static struct workqueue_struct *cfag12864b_workqueue; +static DECLARE_DELAYED_WORK(cfag12864b_work, cfag12864b_update); + +static void cfag12864b_queue(void) +{ + queue_delayed_work(cfag12864b_workqueue, &cfag12864b_work, + HZ / cfag12864b_rate); +} + +unsigned char cfag12864b_enable(void) +{ + unsigned char ret; + + mutex_lock(&cfag12864b_mutex); + + if (!cfag12864b_updating) { + cfag12864b_updating = 1; + cfag12864b_queue(); + ret = 0; + } else + ret = 1; + + mutex_unlock(&cfag12864b_mutex); + + return ret; +} + +void cfag12864b_disable(void) +{ + mutex_lock(&cfag12864b_mutex); + + if (cfag12864b_updating) { + cfag12864b_updating = 0; + cancel_delayed_work(&cfag12864b_work); + flush_workqueue(cfag12864b_workqueue); + } + + mutex_unlock(&cfag12864b_mutex); +} + +unsigned char cfag12864b_isenabled(void) +{ + return cfag12864b_updating; +} + +static void cfag12864b_update(struct work_struct *work) +{ + unsigned char c; + unsigned short i, j, k, b; + + if (memcmp(cfag12864b_cache, cfag12864b_buffer, CFAG12864B_SIZE)) { + for (i = 0; i < CFAG12864B_CONTROLLERS; i++) { + cfag12864b_controller(i); + cfag12864b_nop(); + for (j = 0; j < CFAG12864B_PAGES; j++) { + cfag12864b_page(j); + cfag12864b_nop(); + cfag12864b_address(0); + cfag12864b_nop(); + for (k = 0; k < CFAG12864B_ADDRESSES; k++) { + for (c = 0, b = 0; b < 8; b++) + if (cfag12864b_buffer + [i * CFAG12864B_ADDRESSES / 8 + + k / 8 + (j * 8 + b) * + CFAG12864B_WIDTH / 8] + & bit(k % 8)) + c |= bit(b); + cfag12864b_writebyte(c); + } + } + } + + memcpy(cfag12864b_cache, cfag12864b_buffer, CFAG12864B_SIZE); + } + + if (cfag12864b_updating) + cfag12864b_queue(); +} + +/* + * cfag12864b Exported Symbols + */ + +EXPORT_SYMBOL_GPL(cfag12864b_buffer); +EXPORT_SYMBOL_GPL(cfag12864b_getrate); +EXPORT_SYMBOL_GPL(cfag12864b_enable); +EXPORT_SYMBOL_GPL(cfag12864b_disable); +EXPORT_SYMBOL_GPL(cfag12864b_isenabled); + +/* + * Module Init & Exit + */ + +static int __init cfag12864b_init(void) +{ + int ret = -EINVAL; + + if (PAGE_SIZE < CFAG12864B_SIZE) { + printk(KERN_ERR CFAG12864B_NAME ": ERROR: " + "page size (%i) < cfag12864b size (%i)\n", + (unsigned int)PAGE_SIZE, CFAG12864B_SIZE); + ret = -ENOMEM; + goto none; + } + + cfag12864b_buffer = (unsigned char *) __get_free_page(GFP_KERNEL); + if (cfag12864b_buffer == NULL) { + printk(KERN_ERR CFAG12864B_NAME ": ERROR: " + "can't get a free page\n"); + ret = -ENOMEM; + goto none; + } + + cfag12864b_cache = kmalloc(sizeof(unsigned char) * + CFAG12864B_SIZE, GFP_KERNEL); + if (cfag12864b_buffer == NULL) { + printk(KERN_ERR CFAG12864B_NAME ": ERROR: " + "can't alloc cache buffer (%i bytes)\n", + CFAG12864B_SIZE); + ret = -ENOMEM; + goto bufferalloced; + } + + cfag12864b_workqueue = create_singlethread_workqueue(CFAG12864B_NAME); + if (cfag12864b_workqueue == NULL) + goto cachealloced; + + memset(cfag12864b_buffer, 0, CFAG12864B_SIZE); + + cfag12864b_clear(); + cfag12864b_on(); + + return 0; + +cachealloced: + kfree(cfag12864b_cache); + +bufferalloced: + free_page((unsigned long) cfag12864b_buffer); + +none: + return ret; +} + +static void __exit cfag12864b_exit(void) +{ + cfag12864b_disable(); + cfag12864b_off(); + destroy_workqueue(cfag12864b_workqueue); + kfree(cfag12864b_cache); + free_page((unsigned long) cfag12864b_buffer); +} + +module_init(cfag12864b_init); +module_exit(cfag12864b_exit); + +MODULE_LICENSE("GPL v2"); +MODULE_AUTHOR("Miguel Ojeda Sandonis "); +MODULE_DESCRIPTION("cfag12864b LCD driver"); diff --git a/drivers/auxdisplay/cfag12864bfb.c b/drivers/auxdisplay/cfag12864bfb.c new file mode 100644 index 0000000..94765e7 --- /dev/null +++ b/drivers/auxdisplay/cfag12864bfb.c @@ -0,0 +1,180 @@ +/* + * Filename: cfag12864bfb.c + * Version: 0.1.0 + * Description: cfag12864b LCD framebuffer driver + * License: GPLv2 + * Depends: cfag12864b + * + * Author: Copyright (C) Miguel Ojeda Sandonis + * Date: 2006-10-31 + * + * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define CFAG12864BFB_NAME "cfag12864bfb" + +static struct fb_fix_screeninfo cfag12864bfb_fix __initdata = { + .id = "cfag12864b", + .type = FB_TYPE_PACKED_PIXELS, + .visual = FB_VISUAL_MONO10, + .xpanstep = 0, + .ypanstep = 0, + .ywrapstep = 0, + .line_length = CFAG12864B_WIDTH / 8, + .accel = FB_ACCEL_NONE, +}; + +static struct fb_var_screeninfo cfag12864bfb_var __initdata = { + .xres = CFAG12864B_WIDTH, + .yres = CFAG12864B_HEIGHT, + .xres_virtual = CFAG12864B_WIDTH, + .yres_virtual = CFAG12864B_HEIGHT, + .bits_per_pixel = 1, + .red = { 0, 1, 0 }, + .green = { 0, 1, 0 }, + .blue = { 0, 1, 0 }, + .left_margin = 0, + .right_margin = 0, + .upper_margin = 0, + .lower_margin = 0, + .vmode = FB_VMODE_NONINTERLACED, +}; + +static int cfag12864bfb_mmap(struct fb_info *info, struct vm_area_struct *vma) +{ + return vm_insert_page(vma, vma->vm_start, + virt_to_page(cfag12864b_buffer)); +} + +static struct fb_ops cfag12864bfb_ops = { + .owner = THIS_MODULE, + .fb_fillrect = cfb_fillrect, + .fb_copyarea = cfb_copyarea, + .fb_imageblit = cfb_imageblit, + .fb_mmap = cfag12864bfb_mmap, +}; + +static int __init cfag12864bfb_probe(struct platform_device *device) +{ + int ret = -EINVAL; + struct fb_info *info = framebuffer_alloc(0, &device->dev); + + if (!info) + goto none; + + info->screen_base = (char __iomem *) cfag12864b_buffer; + info->screen_size = CFAG12864B_SIZE; + info->fbops = &cfag12864bfb_ops; + info->fix = cfag12864bfb_fix; + info->var = cfag12864bfb_var; + info->pseudo_palette = NULL; + info->par = NULL; + info->flags = FBINFO_FLAG_DEFAULT; + + if (register_framebuffer(info) < 0) + goto fballoced; + + platform_set_drvdata(device, info); + + printk(KERN_INFO "fb%d: %s frame buffer device\n", info->node, + info->fix.id); + + return 0; + +fballoced: + framebuffer_release(info); + +none: + return ret; +} + +static int cfag12864bfb_remove(struct platform_device *device) +{ + struct fb_info *info = platform_get_drvdata(device); + + if (info) { + unregister_framebuffer(info); + framebuffer_release(info); + } + + return 0; +} + +static struct platform_driver cfag12864bfb_driver = { + .probe = cfag12864bfb_probe, + .remove = cfag12864bfb_remove, + .driver = { + .name = CFAG12864BFB_NAME, + }, +}; + +static struct platform_device *cfag12864bfb_device; + +static int __init cfag12864bfb_init(void) +{ + int ret; + + if (cfag12864b_enable()) { + printk(KERN_ERR CFAG12864BFB_NAME ": ERROR: " + "can't enable cfag12864b refreshing (being used)\n"); + return -ENODEV; + } + + ret = platform_driver_register(&cfag12864bfb_driver); + + if (!ret) { + cfag12864bfb_device = + platform_device_alloc(CFAG12864BFB_NAME, 0); + + if (cfag12864bfb_device) + ret = platform_device_add(cfag12864bfb_device); + else + ret = -ENOMEM; + + if (ret) { + platform_device_put(cfag12864bfb_device); + platform_driver_unregister(&cfag12864bfb_driver); + } + } + + return ret; +} + +static void __exit cfag12864bfb_exit(void) +{ + platform_device_unregister(cfag12864bfb_device); + platform_driver_unregister(&cfag12864bfb_driver); + cfag12864b_disable(); +} + +module_init(cfag12864bfb_init); +module_exit(cfag12864bfb_exit); + +MODULE_LICENSE("GPL v2"); +MODULE_AUTHOR("Miguel Ojeda Sandonis "); +MODULE_DESCRIPTION("cfag12864b LCD framebuffer driver"); diff --git a/drivers/auxdisplay/ks0108.c b/drivers/auxdisplay/ks0108.c new file mode 100644 index 0000000..a637575 --- /dev/null +++ b/drivers/auxdisplay/ks0108.c @@ -0,0 +1,166 @@ +/* + * Filename: ks0108.c + * Version: 0.1.0 + * Description: ks0108 LCD Controller driver + * License: GPLv2 + * Depends: parport + * + * Author: Copyright (C) Miguel Ojeda Sandonis + * Date: 2006-10-31 + * + * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define KS0108_NAME "ks0108" + +/* + * Module Parameters + */ + +static unsigned int ks0108_port = CONFIG_KS0108_PORT; +module_param(ks0108_port, uint, S_IRUGO); +MODULE_PARM_DESC(ks0108_port, "Parallel port where the LCD is connected"); + +static unsigned int ks0108_delay = CONFIG_KS0108_DELAY; +module_param(ks0108_delay, uint, S_IRUGO); +MODULE_PARM_DESC(ks0108_delay, "Delay between each control writing (microseconds)"); + +/* + * Device + */ + +static struct parport *ks0108_parport; +static struct pardevice *ks0108_pardevice; + +/* + * ks0108 Exported Commands (don't lock) + * + * You _should_ lock in the top driver: This functions _should not_ + * get race conditions in any way. Locking for each byte here would be + * so slow and useless. + * + * There are not bit definitions because they are not flags, + * just arbitrary combinations defined by the documentation for each + * function in the ks0108 LCD controller. If you want to know what means + * a specific combination, look at the function's name. + * + * The ks0108_writecontrol bits need to be reverted ^(0,1,3) because + * the parallel port also revert them using a "not" logic gate. + */ + +#define bit(n) (((unsigned char)1)<<(n)) + +void ks0108_writedata(unsigned char byte) +{ + parport_write_data(ks0108_parport, byte); +} + +void ks0108_writecontrol(unsigned char byte) +{ + udelay(ks0108_delay); + parport_write_control(ks0108_parport, byte ^ (bit(0) | bit(1) | bit(3))); +} + +void ks0108_displaystate(unsigned char state) +{ + ks0108_writedata((state ? bit(0) : 0) | bit(1) | bit(2) | bit(3) | bit(4) | bit(5)); +} + +void ks0108_startline(unsigned char startline) +{ + ks0108_writedata(min(startline,(unsigned char)63) | bit(6) | bit(7)); +} + +void ks0108_address(unsigned char address) +{ + ks0108_writedata(min(address,(unsigned char)63) | bit(6)); +} + +void ks0108_page(unsigned char page) +{ + ks0108_writedata(min(page,(unsigned char)7) | bit(3) | bit(4) | bit(5) | bit(7)); +} + +EXPORT_SYMBOL_GPL(ks0108_writedata); +EXPORT_SYMBOL_GPL(ks0108_writecontrol); +EXPORT_SYMBOL_GPL(ks0108_displaystate); +EXPORT_SYMBOL_GPL(ks0108_startline); +EXPORT_SYMBOL_GPL(ks0108_address); +EXPORT_SYMBOL_GPL(ks0108_page); + +/* + * Module Init & Exit + */ + +static int __init ks0108_init(void) +{ + int result; + int ret = -EINVAL; + + ks0108_parport = parport_find_base(ks0108_port); + if (ks0108_parport == NULL) { + printk(KERN_ERR KS0108_NAME ": ERROR: " + "parport didn't find %i port\n", ks0108_port); + goto none; + } + + ks0108_pardevice = parport_register_device(ks0108_parport, KS0108_NAME, + NULL, NULL, NULL, PARPORT_DEV_EXCL, NULL); + if (ks0108_pardevice == NULL) { + printk(KERN_ERR KS0108_NAME ": ERROR: " + "parport didn't register new device\n"); + goto none; + } + + result = parport_claim(ks0108_pardevice); + if (result != 0) { + printk(KERN_ERR KS0108_NAME ": ERROR: " + "can't claim %i parport, maybe in use\n", ks0108_port); + ret = result; + goto registered; + } + + return 0; + +registered: + parport_unregister_device(ks0108_pardevice); + +none: + return ret; +} + +static void __exit ks0108_exit(void) +{ + parport_release(ks0108_pardevice); + parport_unregister_device(ks0108_pardevice); +} + +module_init(ks0108_init); +module_exit(ks0108_exit); + +MODULE_LICENSE("GPL v2"); +MODULE_AUTHOR("Miguel Ojeda Sandonis "); +MODULE_DESCRIPTION("ks0108 LCD Controller driver"); + diff --git a/drivers/base/Kconfig b/drivers/base/Kconfig index 1429f3a..5d6312e 100644 --- a/drivers/base/Kconfig +++ b/drivers/base/Kconfig @@ -37,6 +37,18 @@ config DEBUG_DRIVER If you are unsure about this, say N here. +config DEBUG_DEVRES + bool "Managed device resources verbose debug messages" + depends on DEBUG_KERNEL + help + This option enables kernel parameter devres.log. If set to + non-zero, devres debug messages are printed. Select this if + you are having a problem with devres or want to debug + resource management for a managed device. devres.log can be + switched on and off from sysfs node. + + If you are unsure about this, Say N here. + config SYS_HYPERVISOR bool default n diff --git a/drivers/base/Makefile b/drivers/base/Makefile index 7bbb9ee..e9eb738 100644 --- a/drivers/base/Makefile +++ b/drivers/base/Makefile @@ -3,6 +3,7 @@ # Makefile for the Linux device tree obj-y := core.o sys.o bus.o dd.o \ driver.o class.o platform.o \ cpu.o firmware.o init.o map.o dmapool.o \ + dma-mapping.o devres.o \ attribute_container.o transport_class.o obj-y += power/ obj-$(CONFIG_ISA) += isa.o diff --git a/drivers/base/base.h b/drivers/base/base.h index d26644a..de7e144 100644 --- a/drivers/base/base.h +++ b/drivers/base/base.h @@ -44,3 +44,4 @@ struct class_device_attribute *to_class_ extern char *make_class_name(const char *name, struct kobject *kobj); +extern void devres_release_all(struct device *dev); diff --git a/drivers/base/class.c b/drivers/base/class.c index 8bf2ca2..96def1d 100644 --- a/drivers/base/class.c +++ b/drivers/base/class.c @@ -364,7 +364,7 @@ char *make_class_name(const char *name, class_name = kmalloc(size, GFP_KERNEL); if (!class_name) - return ERR_PTR(-ENOMEM); + return NULL; strcpy(class_name, name); strcat(class_name, ":"); @@ -411,8 +411,11 @@ static int make_deprecated_class_device_ return 0; class_name = make_class_name(class_dev->class->name, &class_dev->kobj); - error = sysfs_create_link(&class_dev->dev->kobj, &class_dev->kobj, - class_name); + if (class_name) + error = sysfs_create_link(&class_dev->dev->kobj, + &class_dev->kobj, class_name); + else + error = -ENOMEM; kfree(class_name); return error; } @@ -425,7 +428,8 @@ static void remove_deprecated_class_devi return; class_name = make_class_name(class_dev->class->name, &class_dev->kobj); - sysfs_remove_link(&class_dev->dev->kobj, class_name); + if (class_name) + sysfs_remove_link(&class_dev->dev->kobj, class_name); kfree(class_name); } #else @@ -863,9 +867,12 @@ #ifdef CONFIG_SYSFS_DEPRECATED if (class_dev->dev) { new_class_name = make_class_name(class_dev->class->name, &class_dev->kobj); - sysfs_create_link(&class_dev->dev->kobj, &class_dev->kobj, - new_class_name); - sysfs_remove_link(&class_dev->dev->kobj, old_class_name); + if (new_class_name) + sysfs_create_link(&class_dev->dev->kobj, + &class_dev->kobj, new_class_name); + if (old_class_name) + sysfs_remove_link(&class_dev->dev->kobj, + old_class_name); } #endif class_device_put(class_dev); diff --git a/drivers/base/core.c b/drivers/base/core.c index 67b79a7..a8ac34b 100644 --- a/drivers/base/core.c +++ b/drivers/base/core.c @@ -95,6 +95,8 @@ static void device_release(struct kobjec if (dev->release) dev->release(dev); + else if (dev->type && dev->type->release) + dev->type->release(dev); else if (dev->class && dev->class->dev_release) dev->class->dev_release(dev); else { @@ -154,25 +156,47 @@ static int dev_uevent(struct kset *kset, "MINOR=%u", MINOR(dev->devt)); } -#ifdef CONFIG_SYSFS_DEPRECATED - /* add bus name (same as SUBSYSTEM, deprecated) */ - if (dev->bus) - add_uevent_var(envp, num_envp, &i, - buffer, buffer_size, &length, - "PHYSDEVBUS=%s", dev->bus->name); -#endif - - /* add driver name (PHYSDEV* values are deprecated)*/ - if (dev->driver) { + if (dev->driver) add_uevent_var(envp, num_envp, &i, buffer, buffer_size, &length, "DRIVER=%s", dev->driver->name); + #ifdef CONFIG_SYSFS_DEPRECATED + if (dev->class) { + struct device *parent = dev->parent; + + /* find first bus device in parent chain */ + while (parent && !parent->bus) + parent = parent->parent; + if (parent && parent->bus) { + const char *path; + + path = kobject_get_path(&parent->kobj, GFP_KERNEL); + add_uevent_var(envp, num_envp, &i, + buffer, buffer_size, &length, + "PHYSDEVPATH=%s", path); + kfree(path); + + add_uevent_var(envp, num_envp, &i, + buffer, buffer_size, &length, + "PHYSDEVBUS=%s", parent->bus->name); + + if (parent->driver) + add_uevent_var(envp, num_envp, &i, + buffer, buffer_size, &length, + "PHYSDEVDRIVER=%s", parent->driver->name); + } + } else if (dev->bus) { add_uevent_var(envp, num_envp, &i, buffer, buffer_size, &length, - "PHYSDEVDRIVER=%s", dev->driver->name); -#endif + "PHYSDEVBUS=%s", dev->bus->name); + + if (dev->driver) + add_uevent_var(envp, num_envp, &i, + buffer, buffer_size, &length, + "PHYSDEVDRIVER=%s", dev->driver->name); } +#endif /* terminate, set to next free slot, shrink available space */ envp[i] = NULL; @@ -184,19 +208,25 @@ #endif if (dev->bus && dev->bus->uevent) { /* have the bus specific function add its stuff */ retval = dev->bus->uevent(dev, envp, num_envp, buffer, buffer_size); - if (retval) { - pr_debug ("%s - uevent() returned %d\n", + if (retval) + pr_debug ("%s: bus uevent() returned %d\n", __FUNCTION__, retval); - } } if (dev->class && dev->class->dev_uevent) { /* have the class specific function add its stuff */ retval = dev->class->dev_uevent(dev, envp, num_envp, buffer, buffer_size); - if (retval) { - pr_debug("%s - dev_uevent() returned %d\n", - __FUNCTION__, retval); - } + if (retval) + pr_debug("%s: class uevent() returned %d\n", + __FUNCTION__, retval); + } + + if (dev->type && dev->type->uevent) { + /* have the device type specific fuction add its stuff */ + retval = dev->type->uevent(dev, envp, num_envp, buffer, buffer_size); + if (retval) + pr_debug("%s: dev_type uevent() returned %d\n", + __FUNCTION__, retval); } return retval; @@ -247,37 +277,50 @@ static void device_remove_groups(struct static int device_add_attrs(struct device *dev) { struct class *class = dev->class; + struct device_type *type = dev->type; int error = 0; int i; - if (!class) - return 0; - - if (class->dev_attrs) { + if (class && class->dev_attrs) { for (i = 0; attr_name(class->dev_attrs[i]); i++) { error = device_create_file(dev, &class->dev_attrs[i]); if (error) break; } + if (error) + while (--i >= 0) + device_remove_file(dev, &class->dev_attrs[i]); } - if (error) - while (--i >= 0) - device_remove_file(dev, &class->dev_attrs[i]); + + if (type && type->attrs) { + for (i = 0; attr_name(type->attrs[i]); i++) { + error = device_create_file(dev, &type->attrs[i]); + if (error) + break; + } + if (error) + while (--i >= 0) + device_remove_file(dev, &type->attrs[i]); + } + return error; } static void device_remove_attrs(struct device *dev) { struct class *class = dev->class; + struct device_type *type = dev->type; int i; - if (!class) - return; - - if (class->dev_attrs) { + if (class && class->dev_attrs) { for (i = 0; attr_name(class->dev_attrs[i]); i++) device_remove_file(dev, &class->dev_attrs[i]); } + + if (type && type->attrs) { + for (i = 0; attr_name(type->attrs[i]); i++) + device_remove_file(dev, &type->attrs[i]); + } } @@ -385,27 +428,30 @@ void device_initialize(struct device *de INIT_LIST_HEAD(&dev->dma_pools); INIT_LIST_HEAD(&dev->node); init_MUTEX(&dev->sem); + spin_lock_init(&dev->devres_lock); + INIT_LIST_HEAD(&dev->devres_head); device_init_wakeup(dev, 0); set_dev_node(dev, -1); } #ifdef CONFIG_SYSFS_DEPRECATED -static int setup_parent(struct device *dev, struct device *parent) +static struct kobject * get_device_parent(struct device *dev, + struct device *parent) { /* Set the parent to the class, not the parent device */ /* this keeps sysfs from having a symlink to make old udevs happy */ if (dev->class) - dev->kobj.parent = &dev->class->subsys.kset.kobj; + return &dev->class->subsys.kset.kobj; else if (parent) - dev->kobj.parent = &parent->kobj; + return &parent->kobj; - return 0; + return NULL; } #else -static int virtual_device_parent(struct device *dev) +static struct kobject * virtual_device_parent(struct device *dev) { if (!dev->class) - return -ENODEV; + return ERR_PTR(-ENODEV); if (!dev->class->virtual_dir) { static struct kobject *virtual_dir = NULL; @@ -415,25 +461,31 @@ static int virtual_device_parent(struct dev->class->virtual_dir = kobject_add_dir(virtual_dir, dev->class->name); } - dev->kobj.parent = dev->class->virtual_dir; - return 0; + return dev->class->virtual_dir; } -static int setup_parent(struct device *dev, struct device *parent) +static struct kobject * get_device_parent(struct device *dev, + struct device *parent) { - int error; - /* if this is a class device, and has no parent, create one */ if ((dev->class) && (parent == NULL)) { - error = virtual_device_parent(dev); - if (error) - return error; + return virtual_device_parent(dev); } else if (parent) - dev->kobj.parent = &parent->kobj; + return &parent->kobj; + return NULL; +} +#endif +static int setup_parent(struct device *dev, struct device *parent) +{ + struct kobject *kobj; + kobj = get_device_parent(dev, parent); + if (IS_ERR(kobj)) + return PTR_ERR(kobj); + if (kobj) + dev->kobj.parent = kobj; return 0; } -#endif /** * device_add - add device to device hierarchy. @@ -520,9 +572,13 @@ int device_add(struct device *dev) &dev->kobj, dev->bus_id); #ifdef CONFIG_SYSFS_DEPRECATED if (parent) { - sysfs_create_link(&dev->kobj, &dev->parent->kobj, "device"); - class_name = make_class_name(dev->class->name, &dev->kobj); - sysfs_create_link(&dev->parent->kobj, &dev->kobj, class_name); + sysfs_create_link(&dev->kobj, &dev->parent->kobj, + "device"); + class_name = make_class_name(dev->class->name, + &dev->kobj); + if (class_name) + sysfs_create_link(&dev->parent->kobj, + &dev->kobj, class_name); } #endif } @@ -535,7 +591,8 @@ #endif goto PMError; if ((error = bus_add_device(dev))) goto BusError; - kobject_uevent(&dev->kobj, KOBJ_ADD); + if (!dev->uevent_suppress) + kobject_uevent(&dev->kobj, KOBJ_ADD); if ((error = bus_attach_device(dev))) goto AttachError; if (parent) @@ -665,7 +722,9 @@ #ifdef CONFIG_SYSFS_DEPRECATED if (parent) { char *class_name = make_class_name(dev->class->name, &dev->kobj); - sysfs_remove_link(&dev->parent->kobj, class_name); + if (class_name) + sysfs_remove_link(&dev->parent->kobj, + class_name); kfree(class_name); sysfs_remove_link(&dev->kobj, "device"); } @@ -968,20 +1027,25 @@ #ifdef CONFIG_SYSFS_DEPRECATED class_name = make_class_name(dev->class->name, &dev->kobj); if (!class_name) { - error = PTR_ERR(class_name); - class_name = NULL; + error = -ENOMEM; goto out; } if (old_parent) { sysfs_remove_link(&dev->kobj, "device"); sysfs_remove_link(&old_parent->kobj, class_name); } - error = sysfs_create_link(&dev->kobj, &new_parent->kobj, "device"); - if (error) - goto out; - error = sysfs_create_link(&new_parent->kobj, &dev->kobj, class_name); - if (error) - sysfs_remove_link(&dev->kobj, "device"); + if (new_parent) { + error = sysfs_create_link(&dev->kobj, &new_parent->kobj, + "device"); + if (error) + goto out; + error = sysfs_create_link(&new_parent->kobj, &dev->kobj, + class_name); + if (error) + sysfs_remove_link(&dev->kobj, "device"); + } + else + error = 0; out: kfree(class_name); return error; @@ -993,29 +1057,28 @@ #endif /** * device_move - moves a device to a new parent * @dev: the pointer to the struct device to be moved - * @new_parent: the new parent of the device + * @new_parent: the new parent of the device (can by NULL) */ int device_move(struct device *dev, struct device *new_parent) { int error; struct device *old_parent; + struct kobject *new_parent_kobj; dev = get_device(dev); if (!dev) return -EINVAL; - if (!device_is_registered(dev)) { - error = -EINVAL; - goto out; - } new_parent = get_device(new_parent); - if (!new_parent) { - error = -EINVAL; + new_parent_kobj = get_device_parent (dev, new_parent); + if (IS_ERR(new_parent_kobj)) { + error = PTR_ERR(new_parent_kobj); + put_device(new_parent); goto out; } pr_debug("DEVICE: moving '%s' to '%s'\n", dev->bus_id, - new_parent->bus_id); - error = kobject_move(&dev->kobj, &new_parent->kobj); + new_parent ? new_parent->bus_id : ""); + error = kobject_move(&dev->kobj, new_parent_kobj); if (error) { put_device(new_parent); goto out; @@ -1024,7 +1087,8 @@ int device_move(struct device *dev, stru dev->parent = new_parent; if (old_parent) klist_remove(&dev->knode_parent); - klist_add_tail(&dev->knode_parent, &new_parent->klist_children); + if (new_parent) + klist_add_tail(&dev->knode_parent, &new_parent->klist_children); if (!dev->class) goto out_put; error = device_move_class_links(dev, old_parent, new_parent); @@ -1032,7 +1096,8 @@ int device_move(struct device *dev, stru /* We ignore errors on cleanup since we're hosed anyway... */ device_move_class_links(dev, new_parent, old_parent); if (!kobject_move(&dev->kobj, &old_parent->kobj)) { - klist_remove(&dev->knode_parent); + if (new_parent) + klist_remove(&dev->knode_parent); if (old_parent) klist_add_tail(&dev->knode_parent, &old_parent->klist_children); diff --git a/drivers/base/dd.c b/drivers/base/dd.c index 510e788..6a48824 100644 --- a/drivers/base/dd.c +++ b/drivers/base/dd.c @@ -86,8 +86,12 @@ static void driver_sysfs_remove(struct d */ int device_bind_driver(struct device *dev) { - driver_bound(dev); - return driver_sysfs_add(dev); + int ret; + + ret = driver_sysfs_add(dev); + if (!ret) + driver_bound(dev); + return ret; } struct stupid_thread_structure { @@ -108,6 +112,7 @@ static int really_probe(void *void_data) atomic_inc(&probe_count); pr_debug("%s: Probing driver %s with device %s\n", drv->bus->name, drv->name, dev->bus_id); + WARN_ON(!list_empty(&dev->devres_head)); dev->driver = drv; if (driver_sysfs_add(dev)) { @@ -133,21 +138,21 @@ static int really_probe(void *void_data) goto done; probe_failed: + devres_release_all(dev); driver_sysfs_remove(dev); dev->driver = NULL; - if (ret == -ENODEV || ret == -ENXIO) { - /* Driver matched, but didn't support device - * or device not found. - * Not an error; keep going. - */ - ret = 0; - } else { + if (ret != -ENODEV && ret != -ENXIO) { /* driver matched but the probe failed */ printk(KERN_WARNING "%s: probe of %s failed with error %d\n", drv->name, dev->bus_id, ret); } + /* + * Ignore errors returned by ->probe so that the next driver can try + * its luck. + */ + ret = 0; done: kfree(data); atomic_dec(&probe_count); @@ -324,6 +329,7 @@ static void __device_release_driver(stru dev->bus->remove(dev); else if (drv->remove) drv->remove(dev); + devres_release_all(dev); dev->driver = NULL; put_driver(drv); } diff --git a/drivers/base/devres.c b/drivers/base/devres.c new file mode 100644 index 0000000..e177c95 --- /dev/null +++ b/drivers/base/devres.c @@ -0,0 +1,644 @@ +/* + * drivers/base/devres.c - device resource management + * + * Copyright (c) 2006 SUSE Linux Products GmbH + * Copyright (c) 2006 Tejun Heo + * + * This file is released under the GPLv2. + */ + +#include +#include + +struct devres_node { + struct list_head entry; + dr_release_t release; +#ifdef CONFIG_DEBUG_DEVRES + const char *name; + size_t size; +#endif +}; + +struct devres { + struct devres_node node; + /* -- 3 pointers */ + unsigned long long data[]; /* guarantee ull alignment */ +}; + +struct devres_group { + struct devres_node node[2]; + void *id; + int color; + /* -- 8 pointers */ +}; + +#ifdef CONFIG_DEBUG_DEVRES +static int log_devres = 0; +module_param_named(log, log_devres, int, S_IRUGO | S_IWUSR); + +static void set_node_dbginfo(struct devres_node *node, const char *name, + size_t size) +{ + node->name = name; + node->size = size; +} + +static void devres_log(struct device *dev, struct devres_node *node, + const char *op) +{ + if (unlikely(log_devres)) + dev_printk(KERN_ERR, dev, "DEVRES %3s %p %s (%lu bytes)\n", + op, node, node->name, (unsigned long)node->size); +} +#else /* CONFIG_DEBUG_DEVRES */ +#define set_node_dbginfo(node, n, s) do {} while (0) +#define devres_log(dev, node, op) do {} while (0) +#endif /* CONFIG_DEBUG_DEVRES */ + +/* + * Release functions for devres group. These callbacks are used only + * for identification. + */ +static void group_open_release(struct device *dev, void *res) +{ + /* noop */ +} + +static void group_close_release(struct device *dev, void *res) +{ + /* noop */ +} + +static struct devres_group * node_to_group(struct devres_node *node) +{ + if (node->release == &group_open_release) + return container_of(node, struct devres_group, node[0]); + if (node->release == &group_close_release) + return container_of(node, struct devres_group, node[1]); + return NULL; +} + +static __always_inline struct devres * alloc_dr(dr_release_t release, + size_t size, gfp_t gfp) +{ + size_t tot_size = sizeof(struct devres) + size; + struct devres *dr; + + dr = kmalloc_track_caller(tot_size, gfp); + if (unlikely(!dr)) + return NULL; + + memset(dr, 0, tot_size); + INIT_LIST_HEAD(&dr->node.entry); + dr->node.release = release; + return dr; +} + +static void add_dr(struct device *dev, struct devres_node *node) +{ + devres_log(dev, node, "ADD"); + BUG_ON(!list_empty(&node->entry)); + list_add_tail(&node->entry, &dev->devres_head); +} + +/** + * devres_alloc - Allocate device resource data + * @release: Release function devres will be associated with + * @size: Allocation size + * @gfp: Allocation flags + * + * allocate devres of @size bytes. The allocated area is zeroed, then + * associated with @release. The returned pointer can be passed to + * other devres_*() functions. + * + * RETURNS: + * Pointer to allocated devres on success, NULL on failure. + */ +#ifdef CONFIG_DEBUG_DEVRES +void * __devres_alloc(dr_release_t release, size_t size, gfp_t gfp, + const char *name) +{ + struct devres *dr; + + dr = alloc_dr(release, size, gfp); + if (unlikely(!dr)) + return NULL; + set_node_dbginfo(&dr->node, name, size); + return dr->data; +} +EXPORT_SYMBOL_GPL(__devres_alloc); +#else +void * devres_alloc(dr_release_t release, size_t size, gfp_t gfp) +{ + struct devres *dr; + + dr = alloc_dr(release, size, gfp); + if (unlikely(!dr)) + return NULL; + return dr->data; +} +EXPORT_SYMBOL_GPL(devres_alloc); +#endif + +/** + * devres_free - Free device resource data + * @res: Pointer to devres data to free + * + * Free devres created with devres_alloc(). + */ +void devres_free(void *res) +{ + if (res) { + struct devres *dr = container_of(res, struct devres, data); + + BUG_ON(!list_empty(&dr->node.entry)); + kfree(dr); + } +} +EXPORT_SYMBOL_GPL(devres_free); + +/** + * devres_add - Register device resource + * @dev: Device to add resource to + * @res: Resource to register + * + * Register devres @res to @dev. @res should have been allocated + * using devres_alloc(). On driver detach, the associated release + * function will be invoked and devres will be freed automatically. + */ +void devres_add(struct device *dev, void *res) +{ + struct devres *dr = container_of(res, struct devres, data); + unsigned long flags; + + spin_lock_irqsave(&dev->devres_lock, flags); + add_dr(dev, &dr->node); + spin_unlock_irqrestore(&dev->devres_lock, flags); +} +EXPORT_SYMBOL_GPL(devres_add); + +static struct devres *find_dr(struct device *dev, dr_release_t release, + dr_match_t match, void *match_data) +{ + struct devres_node *node; + + list_for_each_entry_reverse(node, &dev->devres_head, entry) { + struct devres *dr = container_of(node, struct devres, node); + + if (node->release != release) + continue; + if (match && !match(dev, dr->data, match_data)) + continue; + return dr; + } + + return NULL; +} + +/** + * devres_find - Find device resource + * @dev: Device to lookup resource from + * @release: Look for resources associated with this release function + * @match: Match function (optional) + * @match_data: Data for the match function + * + * Find the latest devres of @dev which is associated with @release + * and for which @match returns 1. If @match is NULL, it's considered + * to match all. + * + * RETURNS: + * Pointer to found devres, NULL if not found. + */ +void * devres_find(struct device *dev, dr_release_t release, + dr_match_t match, void *match_data) +{ + struct devres *dr; + unsigned long flags; + + spin_lock_irqsave(&dev->devres_lock, flags); + dr = find_dr(dev, release, match, match_data); + spin_unlock_irqrestore(&dev->devres_lock, flags); + + if (dr) + return dr->data; + return NULL; +} +EXPORT_SYMBOL_GPL(devres_find); + +/** + * devres_get - Find devres, if non-existent, add one atomically + * @dev: Device to lookup or add devres for + * @new_res: Pointer to new initialized devres to add if not found + * @match: Match function (optional) + * @match_data: Data for the match function + * + * Find the latest devres of @dev which has the same release function + * as @new_res and for which @match return 1. If found, @new_res is + * freed; otherwise, @new_res is added atomically. + * + * RETURNS: + * Pointer to found or added devres. + */ +void * devres_get(struct device *dev, void *new_res, + dr_match_t match, void *match_data) +{ + struct devres *new_dr = container_of(new_res, struct devres, data); + struct devres *dr; + unsigned long flags; + + spin_lock_irqsave(&dev->devres_lock, flags); + dr = find_dr(dev, new_dr->node.release, match, match_data); + if (!dr) { + add_dr(dev, &new_dr->node); + dr = new_dr; + new_dr = NULL; + } + spin_unlock_irqrestore(&dev->devres_lock, flags); + devres_free(new_dr); + + return dr->data; +} +EXPORT_SYMBOL_GPL(devres_get); + +/** + * devres_remove - Find a device resource and remove it + * @dev: Device to find resource from + * @release: Look for resources associated with this release function + * @match: Match function (optional) + * @match_data: Data for the match function + * + * Find the latest devres of @dev associated with @release and for + * which @match returns 1. If @match is NULL, it's considered to + * match all. If found, the resource is removed atomically and + * returned. + * + * RETURNS: + * Pointer to removed devres on success, NULL if not found. + */ +void * devres_remove(struct device *dev, dr_release_t release, + dr_match_t match, void *match_data) +{ + struct devres *dr; + unsigned long flags; + + spin_lock_irqsave(&dev->devres_lock, flags); + dr = find_dr(dev, release, match, match_data); + if (dr) { + list_del_init(&dr->node.entry); + devres_log(dev, &dr->node, "REM"); + } + spin_unlock_irqrestore(&dev->devres_lock, flags); + + if (dr) + return dr->data; + return NULL; +} +EXPORT_SYMBOL_GPL(devres_remove); + +/** + * devres_destroy - Find a device resource and destroy it + * @dev: Device to find resource from + * @release: Look for resources associated with this release function + * @match: Match function (optional) + * @match_data: Data for the match function + * + * Find the latest devres of @dev associated with @release and for + * which @match returns 1. If @match is NULL, it's considered to + * match all. If found, the resource is removed atomically and freed. + * + * RETURNS: + * 0 if devres is found and freed, -ENOENT if not found. + */ +int devres_destroy(struct device *dev, dr_release_t release, + dr_match_t match, void *match_data) +{ + void *res; + + res = devres_remove(dev, release, match, match_data); + if (unlikely(!res)) + return -ENOENT; + + devres_free(res); + return 0; +} +EXPORT_SYMBOL_GPL(devres_destroy); + +static int remove_nodes(struct device *dev, + struct list_head *first, struct list_head *end, + struct list_head *todo) +{ + int cnt = 0, nr_groups = 0; + struct list_head *cur; + + /* First pass - move normal devres entries to @todo and clear + * devres_group colors. + */ + cur = first; + while (cur != end) { + struct devres_node *node; + struct devres_group *grp; + + node = list_entry(cur, struct devres_node, entry); + cur = cur->next; + + grp = node_to_group(node); + if (grp) { + /* clear color of group markers in the first pass */ + grp->color = 0; + nr_groups++; + } else { + /* regular devres entry */ + if (&node->entry == first) + first = first->next; + list_move_tail(&node->entry, todo); + cnt++; + } + } + + if (!nr_groups) + return cnt; + + /* Second pass - Scan groups and color them. A group gets + * color value of two iff the group is wholly contained in + * [cur, end). That is, for a closed group, both opening and + * closing markers should be in the range, while just the + * opening marker is enough for an open group. + */ + cur = first; + while (cur != end) { + struct devres_node *node; + struct devres_group *grp; + + node = list_entry(cur, struct devres_node, entry); + cur = cur->next; + + grp = node_to_group(node); + BUG_ON(!grp || list_empty(&grp->node[0].entry)); + + grp->color++; + if (list_empty(&grp->node[1].entry)) + grp->color++; + + BUG_ON(grp->color <= 0 || grp->color > 2); + if (grp->color == 2) { + /* No need to update cur or end. The removed + * nodes are always before both. + */ + list_move_tail(&grp->node[0].entry, todo); + list_del_init(&grp->node[1].entry); + } + } + + return cnt; +} + +static int release_nodes(struct device *dev, struct list_head *first, + struct list_head *end, unsigned long flags) +{ + LIST_HEAD(todo); + int cnt; + struct devres *dr, *tmp; + + cnt = remove_nodes(dev, first, end, &todo); + + spin_unlock_irqrestore(&dev->devres_lock, flags); + + /* Release. Note that both devres and devres_group are + * handled as devres in the following loop. This is safe. + */ + list_for_each_entry_safe_reverse(dr, tmp, &todo, node.entry) { + devres_log(dev, &dr->node, "REL"); + dr->node.release(dev, dr->data); + kfree(dr); + } + + return cnt; +} + +/** + * devres_release_all - Release all resources + * @dev: Device to release resources for + * + * Release all resources associated with @dev. This function is + * called on driver detach. + */ +int devres_release_all(struct device *dev) +{ + unsigned long flags; + + spin_lock_irqsave(&dev->devres_lock, flags); + return release_nodes(dev, dev->devres_head.next, &dev->devres_head, + flags); +} + +/** + * devres_open_group - Open a new devres group + * @dev: Device to open devres group for + * @id: Separator ID + * @gfp: Allocation flags + * + * Open a new devres group for @dev with @id. For @id, using a + * pointer to an object which won't be used for another group is + * recommended. If @id is NULL, address-wise unique ID is created. + * + * RETURNS: + * ID of the new group, NULL on failure. + */ +void * devres_open_group(struct device *dev, void *id, gfp_t gfp) +{ + struct devres_group *grp; + unsigned long flags; + + grp = kmalloc(sizeof(*grp), gfp); + if (unlikely(!grp)) + return NULL; + + grp->node[0].release = &group_open_release; + grp->node[1].release = &group_close_release; + INIT_LIST_HEAD(&grp->node[0].entry); + INIT_LIST_HEAD(&grp->node[1].entry); + set_node_dbginfo(&grp->node[0], "grp<", 0); + set_node_dbginfo(&grp->node[1], "grp>", 0); + grp->id = grp; + if (id) + grp->id = id; + + spin_lock_irqsave(&dev->devres_lock, flags); + add_dr(dev, &grp->node[0]); + spin_unlock_irqrestore(&dev->devres_lock, flags); + return grp->id; +} +EXPORT_SYMBOL_GPL(devres_open_group); + +/* Find devres group with ID @id. If @id is NULL, look for the latest. */ +static struct devres_group * find_group(struct device *dev, void *id) +{ + struct devres_node *node; + + list_for_each_entry_reverse(node, &dev->devres_head, entry) { + struct devres_group *grp; + + if (node->release != &group_open_release) + continue; + + grp = container_of(node, struct devres_group, node[0]); + + if (id) { + if (grp->id == id) + return grp; + } else if (list_empty(&grp->node[1].entry)) + return grp; + } + + return NULL; +} + +/** + * devres_close_group - Close a devres group + * @dev: Device to close devres group for + * @id: ID of target group, can be NULL + * + * Close the group identified by @id. If @id is NULL, the latest open + * group is selected. + */ +void devres_close_group(struct device *dev, void *id) +{ + struct devres_group *grp; + unsigned long flags; + + spin_lock_irqsave(&dev->devres_lock, flags); + + grp = find_group(dev, id); + if (grp) + add_dr(dev, &grp->node[1]); + else + WARN_ON(1); + + spin_unlock_irqrestore(&dev->devres_lock, flags); +} +EXPORT_SYMBOL_GPL(devres_close_group); + +/** + * devres_remove_group - Remove a devres group + * @dev: Device to remove group for + * @id: ID of target group, can be NULL + * + * Remove the group identified by @id. If @id is NULL, the latest + * open group is selected. Note that removing a group doesn't affect + * any other resources. + */ +void devres_remove_group(struct device *dev, void *id) +{ + struct devres_group *grp; + unsigned long flags; + + spin_lock_irqsave(&dev->devres_lock, flags); + + grp = find_group(dev, id); + if (grp) { + list_del_init(&grp->node[0].entry); + list_del_init(&grp->node[1].entry); + devres_log(dev, &grp->node[0], "REM"); + } else + WARN_ON(1); + + spin_unlock_irqrestore(&dev->devres_lock, flags); + + kfree(grp); +} +EXPORT_SYMBOL_GPL(devres_remove_group); + +/** + * devres_release_group - Release resources in a devres group + * @dev: Device to release group for + * @id: ID of target group, can be NULL + * + * Release all resources in the group identified by @id. If @id is + * NULL, the latest open group is selected. The selected group and + * groups properly nested inside the selected group are removed. + * + * RETURNS: + * The number of released non-group resources. + */ +int devres_release_group(struct device *dev, void *id) +{ + struct devres_group *grp; + unsigned long flags; + int cnt = 0; + + spin_lock_irqsave(&dev->devres_lock, flags); + + grp = find_group(dev, id); + if (grp) { + struct list_head *first = &grp->node[0].entry; + struct list_head *end = &dev->devres_head; + + if (!list_empty(&grp->node[1].entry)) + end = grp->node[1].entry.next; + + cnt = release_nodes(dev, first, end, flags); + } else { + WARN_ON(1); + spin_unlock_irqrestore(&dev->devres_lock, flags); + } + + return cnt; +} +EXPORT_SYMBOL_GPL(devres_release_group); + +/* + * Managed kzalloc/kfree + */ +static void devm_kzalloc_release(struct device *dev, void *res) +{ + /* noop */ +} + +static int devm_kzalloc_match(struct device *dev, void *res, void *data) +{ + return res == data; +} + +/** + * devm_kzalloc - Managed kzalloc + * @dev: Device to allocate memory for + * @size: Allocation size + * @gfp: Allocation gfp flags + * + * Managed kzalloc. Memory allocated with this function is + * automatically freed on driver detach. Like all other devres + * resources, guaranteed alignment is unsigned long long. + * + * RETURNS: + * Pointer to allocated memory on success, NULL on failure. + */ +void * devm_kzalloc(struct device *dev, size_t size, gfp_t gfp) +{ + struct devres *dr; + + /* use raw alloc_dr for kmalloc caller tracing */ + dr = alloc_dr(devm_kzalloc_release, size, gfp); + if (unlikely(!dr)) + return NULL; + + set_node_dbginfo(&dr->node, "devm_kzalloc_release", size); + devres_add(dev, dr->data); + return dr->data; +} +EXPORT_SYMBOL_GPL(devm_kzalloc); + +/** + * devm_kfree - Managed kfree + * @dev: Device this memory belongs to + * @p: Memory to free + * + * Free memory allocated with dev_kzalloc(). + */ +void devm_kfree(struct device *dev, void *p) +{ + int rc; + + rc = devres_destroy(dev, devm_kzalloc_release, devm_kzalloc_match, p); + WARN_ON(rc); +} +EXPORT_SYMBOL_GPL(devm_kfree); diff --git a/drivers/base/dma-mapping.c b/drivers/base/dma-mapping.c new file mode 100644 index 0000000..ca9186f --- /dev/null +++ b/drivers/base/dma-mapping.c @@ -0,0 +1,218 @@ +/* + * drivers/base/dma-mapping.c - arch-independent dma-mapping routines + * + * Copyright (c) 2006 SUSE Linux Products GmbH + * Copyright (c) 2006 Tejun Heo + * + * This file is released under the GPLv2. + */ + +#include + +/* + * Managed DMA API + */ +struct dma_devres { + size_t size; + void *vaddr; + dma_addr_t dma_handle; +}; + +static void dmam_coherent_release(struct device *dev, void *res) +{ + struct dma_devres *this = res; + + dma_free_coherent(dev, this->size, this->vaddr, this->dma_handle); +} + +static void dmam_noncoherent_release(struct device *dev, void *res) +{ + struct dma_devres *this = res; + + dma_free_noncoherent(dev, this->size, this->vaddr, this->dma_handle); +} + +static int dmam_match(struct device *dev, void *res, void *match_data) +{ + struct dma_devres *this = res, *match = match_data; + + if (this->vaddr == match->vaddr) { + WARN_ON(this->size != match->size || + this->dma_handle != match->dma_handle); + return 1; + } + return 0; +} + +/** + * dmam_alloc_coherent - Managed dma_alloc_coherent() + * @dev: Device to allocate coherent memory for + * @size: Size of allocation + * @dma_handle: Out argument for allocated DMA handle + * @gfp: Allocation flags + * + * Managed dma_alloc_coherent(). Memory allocated using this function + * will be automatically released on driver detach. + * + * RETURNS: + * Pointer to allocated memory on success, NULL on failure. + */ +void * dmam_alloc_coherent(struct device *dev, size_t size, + dma_addr_t *dma_handle, gfp_t gfp) +{ + struct dma_devres *dr; + void *vaddr; + + dr = devres_alloc(dmam_coherent_release, sizeof(*dr), gfp); + if (!dr) + return NULL; + + vaddr = dma_alloc_coherent(dev, size, dma_handle, gfp); + if (!vaddr) { + devres_free(dr); + return NULL; + } + + dr->vaddr = vaddr; + dr->dma_handle = *dma_handle; + dr->size = size; + + devres_add(dev, dr); + + return vaddr; +} +EXPORT_SYMBOL(dmam_alloc_coherent); + +/** + * dmam_free_coherent - Managed dma_free_coherent() + * @dev: Device to free coherent memory for + * @size: Size of allocation + * @vaddr: Virtual address of the memory to free + * @dma_handle: DMA handle of the memory to free + * + * Managed dma_free_coherent(). + */ +void dmam_free_coherent(struct device *dev, size_t size, void *vaddr, + dma_addr_t dma_handle) +{ + struct dma_devres match_data = { size, vaddr, dma_handle }; + + dma_free_coherent(dev, size, vaddr, dma_handle); + WARN_ON(devres_destroy(dev, dmam_coherent_release, dmam_match, + &match_data)); +} +EXPORT_SYMBOL(dmam_free_coherent); + +/** + * dmam_alloc_non_coherent - Managed dma_alloc_non_coherent() + * @dev: Device to allocate non_coherent memory for + * @size: Size of allocation + * @dma_handle: Out argument for allocated DMA handle + * @gfp: Allocation flags + * + * Managed dma_alloc_non_coherent(). Memory allocated using this + * function will be automatically released on driver detach. + * + * RETURNS: + * Pointer to allocated memory on success, NULL on failure. + */ +void *dmam_alloc_noncoherent(struct device *dev, size_t size, + dma_addr_t *dma_handle, gfp_t gfp) +{ + struct dma_devres *dr; + void *vaddr; + + dr = devres_alloc(dmam_noncoherent_release, sizeof(*dr), gfp); + if (!dr) + return NULL; + + vaddr = dma_alloc_noncoherent(dev, size, dma_handle, gfp); + if (!vaddr) { + devres_free(dr); + return NULL; + } + + dr->vaddr = vaddr; + dr->dma_handle = *dma_handle; + dr->size = size; + + devres_add(dev, dr); + + return vaddr; +} +EXPORT_SYMBOL(dmam_alloc_noncoherent); + +/** + * dmam_free_coherent - Managed dma_free_noncoherent() + * @dev: Device to free noncoherent memory for + * @size: Size of allocation + * @vaddr: Virtual address of the memory to free + * @dma_handle: DMA handle of the memory to free + * + * Managed dma_free_noncoherent(). + */ +void dmam_free_noncoherent(struct device *dev, size_t size, void *vaddr, + dma_addr_t dma_handle) +{ + struct dma_devres match_data = { size, vaddr, dma_handle }; + + dma_free_noncoherent(dev, size, vaddr, dma_handle); + WARN_ON(!devres_destroy(dev, dmam_noncoherent_release, dmam_match, + &match_data)); +} +EXPORT_SYMBOL(dmam_free_noncoherent); + +#ifdef ARCH_HAS_DMA_DECLARE_COHERENT_MEMORY + +static void dmam_coherent_decl_release(struct device *dev, void *res) +{ + dma_release_declared_memory(dev); +} + +/** + * dmam_declare_coherent_memory - Managed dma_declare_coherent_memory() + * @dev: Device to declare coherent memory for + * @bus_addr: Bus address of coherent memory to be declared + * @device_addr: Device address of coherent memory to be declared + * @size: Size of coherent memory to be declared + * @flags: Flags + * + * Managed dma_declare_coherent_memory(). + * + * RETURNS: + * 0 on success, -errno on failure. + */ +int dmam_declare_coherent_memory(struct device *dev, dma_addr_t bus_addr, + dma_addr_t device_addr, size_t size, int flags) +{ + void *res; + int rc; + + res = devres_alloc(dmam_coherent_decl_release, 0, GFP_KERNEL); + if (!res) + return -ENOMEM; + + rc = dma_declare_coherent_memory(dev, bus_addr, device_addr, size, + flags); + if (rc == 0) + devres_add(dev, res); + else + devres_free(res); + + return rc; +} +EXPORT_SYMBOL(dmam_declare_coherent_memory); + +/** + * dmam_release_declared_memory - Managed dma_release_declared_memory(). + * @dev: Device to release declared coherent memory for + * + * Managed dmam_release_declared_memory(). + */ +void dmam_release_declared_memory(struct device *dev) +{ + WARN_ON(devres_destroy(dev, dmam_coherent_decl_release, NULL, NULL)); +} +EXPORT_SYMBOL(dmam_release_declared_memory); + +#endif diff --git a/drivers/base/dmapool.c b/drivers/base/dmapool.c index f95d502..cd467c9 100644 --- a/drivers/base/dmapool.c +++ b/drivers/base/dmapool.c @@ -415,8 +415,67 @@ #endif spin_unlock_irqrestore (&pool->lock, flags); } +/* + * Managed DMA pool + */ +static void dmam_pool_release(struct device *dev, void *res) +{ + struct dma_pool *pool = *(struct dma_pool **)res; + + dma_pool_destroy(pool); +} + +static int dmam_pool_match(struct device *dev, void *res, void *match_data) +{ + return *(struct dma_pool **)res == match_data; +} + +/** + * dmam_pool_create - Managed dma_pool_create() + * @name: name of pool, for diagnostics + * @dev: device that will be doing the DMA + * @size: size of the blocks in this pool. + * @align: alignment requirement for blocks; must be a power of two + * @allocation: returned blocks won't cross this boundary (or zero) + * + * Managed dma_pool_create(). DMA pool created with this function is + * automatically destroyed on driver detach. + */ +struct dma_pool *dmam_pool_create(const char *name, struct device *dev, + size_t size, size_t align, size_t allocation) +{ + struct dma_pool **ptr, *pool; + + ptr = devres_alloc(dmam_pool_release, sizeof(*ptr), GFP_KERNEL); + if (!ptr) + return NULL; + + pool = *ptr = dma_pool_create(name, dev, size, align, allocation); + if (pool) + devres_add(dev, ptr); + else + devres_free(ptr); + + return pool; +} + +/** + * dmam_pool_destroy - Managed dma_pool_destroy() + * @pool: dma pool that will be destroyed + * + * Managed dma_pool_destroy(). + */ +void dmam_pool_destroy(struct dma_pool *pool) +{ + struct device *dev = pool->dev; + + dma_pool_destroy(pool); + WARN_ON(devres_destroy(dev, dmam_pool_release, dmam_pool_match, pool)); +} EXPORT_SYMBOL (dma_pool_create); EXPORT_SYMBOL (dma_pool_destroy); EXPORT_SYMBOL (dma_pool_alloc); EXPORT_SYMBOL (dma_pool_free); +EXPORT_SYMBOL (dmam_pool_create); +EXPORT_SYMBOL (dmam_pool_destroy); diff --git a/drivers/base/firmware_class.c b/drivers/base/firmware_class.c index 64558f4..c0a979a 100644 --- a/drivers/base/firmware_class.c +++ b/drivers/base/firmware_class.c @@ -35,7 +35,7 @@ enum { FW_STATUS_READY_NOHOTPLUG, }; -static int loading_timeout = 10; /* In seconds */ +static int loading_timeout = 60; /* In seconds */ /* fw_lock could be moved to 'struct firmware_priv' but since it is just * guarding for corner cases a global lock should be OK */ diff --git a/drivers/base/node.c b/drivers/base/node.c index 001e6f6..475e33f 100644 --- a/drivers/base/node.c +++ b/drivers/base/node.c @@ -40,13 +40,8 @@ static ssize_t node_read_meminfo(struct int n; int nid = dev->id; struct sysinfo i; - unsigned long inactive; - unsigned long active; - unsigned long free; si_meminfo_node(&i, nid); - __get_zone_counts(&active, &inactive, &free, NODE_DATA(nid)); - n = sprintf(buf, "\n" "Node %d MemTotal: %8lu kB\n" @@ -74,8 +69,8 @@ #endif nid, K(i.totalram), nid, K(i.freeram), nid, K(i.totalram - i.freeram), - nid, K(active), - nid, K(inactive), + nid, node_page_state(nid, NR_ACTIVE), + nid, node_page_state(nid, NR_INACTIVE), #ifdef CONFIG_HIGHMEM nid, K(i.totalhigh), nid, K(i.freehigh), diff --git a/drivers/base/platform.c b/drivers/base/platform.c index f9c903b..30480f6 100644 --- a/drivers/base/platform.c +++ b/drivers/base/platform.c @@ -611,8 +611,15 @@ EXPORT_SYMBOL_GPL(platform_bus_type); int __init platform_bus_init(void) { - device_register(&platform_bus); - return bus_register(&platform_bus_type); + int error; + + error = device_register(&platform_bus); + if (error) + return error; + error = bus_register(&platform_bus_type); + if (error) + device_unregister(&platform_bus); + return error; } #ifndef ARCH_HAS_DMA_GET_REQUIRED_MASK diff --git a/drivers/block/DAC960.c b/drivers/block/DAC960.c index 8d81a3a..92bf868 100644 --- a/drivers/block/DAC960.c +++ b/drivers/block/DAC960.c @@ -177,7 +177,7 @@ static void DAC960_AnnounceDriver(DAC960 DAC960_Failure prints a standardized error message, and then returns false. */ -static boolean DAC960_Failure(DAC960_Controller_T *Controller, +static bool DAC960_Failure(DAC960_Controller_T *Controller, unsigned char *ErrorMessage) { DAC960_Error("While configuring DAC960 PCI RAID Controller at\n", @@ -206,7 +206,7 @@ static boolean DAC960_Failure(DAC960_Con that are passed in. */ -static boolean init_dma_loaf(struct pci_dev *dev, struct dma_loaf *loaf, +static bool init_dma_loaf(struct pci_dev *dev, struct dma_loaf *loaf, size_t len) { void *cpu_addr; @@ -250,7 +250,7 @@ static void free_dma_loaf(struct pci_dev failure. */ -static boolean DAC960_CreateAuxiliaryStructures(DAC960_Controller_T *Controller) +static bool DAC960_CreateAuxiliaryStructures(DAC960_Controller_T *Controller) { int CommandAllocationLength, CommandAllocationGroupSize; int CommandsRemaining = 0, CommandIdentifier, CommandGroupByteCount; @@ -790,7 +790,7 @@ static void DAC960_ExecuteCommand(DAC960 on failure. */ -static boolean DAC960_V1_ExecuteType3(DAC960_Controller_T *Controller, +static bool DAC960_V1_ExecuteType3(DAC960_Controller_T *Controller, DAC960_V1_CommandOpcode_T CommandOpcode, dma_addr_t DataDMA) { @@ -814,7 +814,7 @@ static boolean DAC960_V1_ExecuteType3(DA on failure. */ -static boolean DAC960_V1_ExecuteType3B(DAC960_Controller_T *Controller, +static bool DAC960_V1_ExecuteType3B(DAC960_Controller_T *Controller, DAC960_V1_CommandOpcode_T CommandOpcode, unsigned char CommandOpcode2, dma_addr_t DataDMA) @@ -840,7 +840,7 @@ static boolean DAC960_V1_ExecuteType3B(D on failure. */ -static boolean DAC960_V1_ExecuteType3D(DAC960_Controller_T *Controller, +static bool DAC960_V1_ExecuteType3D(DAC960_Controller_T *Controller, DAC960_V1_CommandOpcode_T CommandOpcode, unsigned char Channel, unsigned char TargetID, @@ -870,7 +870,7 @@ static boolean DAC960_V1_ExecuteType3D(D Return data in The controller's HealthStatusBuffer, which is dma-able memory */ -static boolean DAC960_V2_GeneralInfo(DAC960_Controller_T *Controller) +static bool DAC960_V2_GeneralInfo(DAC960_Controller_T *Controller) { DAC960_Command_T *Command = DAC960_AllocateCommand(Controller); DAC960_V2_CommandMailbox_T *CommandMailbox = &Command->V2.CommandMailbox; @@ -908,7 +908,7 @@ static boolean DAC960_V2_GeneralInfo(DAC memory buffer. */ -static boolean DAC960_V2_NewControllerInfo(DAC960_Controller_T *Controller) +static bool DAC960_V2_NewControllerInfo(DAC960_Controller_T *Controller) { DAC960_Command_T *Command = DAC960_AllocateCommand(Controller); DAC960_V2_CommandMailbox_T *CommandMailbox = &Command->V2.CommandMailbox; @@ -946,7 +946,7 @@ static boolean DAC960_V2_NewControllerIn Data is returned in the controller's V2.NewLogicalDeviceInformation */ -static boolean DAC960_V2_NewLogicalDeviceInfo(DAC960_Controller_T *Controller, +static bool DAC960_V2_NewLogicalDeviceInfo(DAC960_Controller_T *Controller, unsigned short LogicalDeviceNumber) { DAC960_Command_T *Command = DAC960_AllocateCommand(Controller); @@ -997,7 +997,7 @@ static boolean DAC960_V2_NewLogicalDevic */ -static boolean DAC960_V2_NewPhysicalDeviceInfo(DAC960_Controller_T *Controller, +static bool DAC960_V2_NewPhysicalDeviceInfo(DAC960_Controller_T *Controller, unsigned char Channel, unsigned char TargetID, unsigned char LogicalUnit) @@ -1082,7 +1082,7 @@ static void DAC960_V2_ConstructNewUnitSe memory buffer. */ -static boolean DAC960_V2_NewInquiryUnitSerialNumber(DAC960_Controller_T *Controller, +static bool DAC960_V2_NewInquiryUnitSerialNumber(DAC960_Controller_T *Controller, int Channel, int TargetID, int LogicalUnit) { DAC960_Command_T *Command; @@ -1110,7 +1110,7 @@ static boolean DAC960_V2_NewInquiryUnitS success and false on failure. */ -static boolean DAC960_V2_DeviceOperation(DAC960_Controller_T *Controller, +static bool DAC960_V2_DeviceOperation(DAC960_Controller_T *Controller, DAC960_V2_IOCTL_Opcode_T IOCTL_Opcode, DAC960_V2_OperationDevice_T OperationDevice) @@ -1142,7 +1142,7 @@ static boolean DAC960_V2_DeviceOperation other dma mapped memory. */ -static boolean DAC960_V1_EnableMemoryMailboxInterface(DAC960_Controller_T +static bool DAC960_V1_EnableMemoryMailboxInterface(DAC960_Controller_T *Controller) { void __iomem *ControllerBaseAddress = Controller->BaseAddress; @@ -1348,7 +1348,7 @@ #define TIMEOUT_COUNT 1000000 the structures that are contained in that region. */ -static boolean DAC960_V2_EnableMemoryMailboxInterface(DAC960_Controller_T +static bool DAC960_V2_EnableMemoryMailboxInterface(DAC960_Controller_T *Controller) { void __iomem *ControllerBaseAddress = Controller->BaseAddress; @@ -1373,8 +1373,7 @@ static boolean DAC960_V2_EnableMemoryMai Controller->BounceBufferLimit = DAC690_V2_PciDmaMask; /* This is a temporary dma mapping, used only in the scope of this function */ - CommandMailbox = - (DAC960_V2_CommandMailbox_T *)pci_alloc_consistent( PCI_Device, + CommandMailbox = pci_alloc_consistent(PCI_Device, sizeof(DAC960_V2_CommandMailbox_T), &CommandMailboxDMA); if (CommandMailbox == NULL) return false; @@ -1526,7 +1525,7 @@ static boolean DAC960_V2_EnableMemoryMai from DAC960 V1 Firmware Controllers and initializes the Controller structure. */ -static boolean DAC960_V1_ReadControllerConfiguration(DAC960_Controller_T +static bool DAC960_V1_ReadControllerConfiguration(DAC960_Controller_T *Controller) { DAC960_V1_Enquiry2_T *Enquiry2; @@ -1767,7 +1766,7 @@ #endif from DAC960 V2 Firmware Controllers and initializes the Controller structure. */ -static boolean DAC960_V2_ReadControllerConfiguration(DAC960_Controller_T +static bool DAC960_V2_ReadControllerConfiguration(DAC960_Controller_T *Controller) { DAC960_V2_ControllerInfo_T *ControllerInfo = @@ -1879,8 +1878,8 @@ static boolean DAC960_V2_ReadControllerC if (NewLogicalDeviceInfo->LogicalDeviceState != DAC960_V2_LogicalDevice_Offline) Controller->LogicalDriveInitiallyAccessible[LogicalDeviceNumber] = true; - LogicalDeviceInfo = (DAC960_V2_LogicalDeviceInfo_T *) - kmalloc(sizeof(DAC960_V2_LogicalDeviceInfo_T), GFP_ATOMIC); + LogicalDeviceInfo = kmalloc(sizeof(DAC960_V2_LogicalDeviceInfo_T), + GFP_ATOMIC); if (LogicalDeviceInfo == NULL) return DAC960_Failure(Controller, "LOGICAL DEVICE ALLOCATION"); Controller->V2.LogicalDeviceInformation[LogicalDeviceNumber] = @@ -1898,7 +1897,7 @@ static boolean DAC960_V2_ReadControllerC for Controller. */ -static boolean DAC960_ReportControllerConfiguration(DAC960_Controller_T +static bool DAC960_ReportControllerConfiguration(DAC960_Controller_T *Controller) { DAC960_Info("Configuring Mylex %s PCI RAID Controller\n", @@ -1947,7 +1946,7 @@ static boolean DAC960_ReportControllerCo Controller. */ -static boolean DAC960_V1_ReadDeviceConfiguration(DAC960_Controller_T +static bool DAC960_V1_ReadDeviceConfiguration(DAC960_Controller_T *Controller) { struct dma_loaf local_dma; @@ -2095,7 +2094,7 @@ static boolean DAC960_V1_ReadDeviceConfi device connected to Controller. */ -static boolean DAC960_V2_ReadDeviceConfiguration(DAC960_Controller_T +static bool DAC960_V2_ReadDeviceConfiguration(DAC960_Controller_T *Controller) { unsigned char Channel = 0, TargetID = 0, LogicalUnit = 0; @@ -2113,8 +2112,8 @@ static boolean DAC960_V2_ReadDeviceConfi if (!DAC960_V2_NewPhysicalDeviceInfo(Controller, Channel, TargetID, LogicalUnit)) break; - PhysicalDeviceInfo = (DAC960_V2_PhysicalDeviceInfo_T *) - kmalloc(sizeof(DAC960_V2_PhysicalDeviceInfo_T), GFP_ATOMIC); + PhysicalDeviceInfo = kmalloc(sizeof(DAC960_V2_PhysicalDeviceInfo_T), + GFP_ATOMIC); if (PhysicalDeviceInfo == NULL) return DAC960_Failure(Controller, "PHYSICAL DEVICE ALLOCATION"); Controller->V2.PhysicalDeviceInformation[PhysicalDeviceIndex] = @@ -2122,8 +2121,8 @@ static boolean DAC960_V2_ReadDeviceConfi memcpy(PhysicalDeviceInfo, NewPhysicalDeviceInfo, sizeof(DAC960_V2_PhysicalDeviceInfo_T)); - InquiryUnitSerialNumber = (DAC960_SCSI_Inquiry_UnitSerialNumber_T *) - kmalloc(sizeof(DAC960_SCSI_Inquiry_UnitSerialNumber_T), GFP_ATOMIC); + InquiryUnitSerialNumber = kmalloc( + sizeof(DAC960_SCSI_Inquiry_UnitSerialNumber_T), GFP_ATOMIC); if (InquiryUnitSerialNumber == NULL) { kfree(PhysicalDeviceInfo); return DAC960_Failure(Controller, "SERIAL NUMBER ALLOCATION"); @@ -2219,7 +2218,7 @@ static void DAC960_SanitizeInquiryData(D Information for DAC960 V1 Firmware Controllers. */ -static boolean DAC960_V1_ReportDeviceConfiguration(DAC960_Controller_T +static bool DAC960_V1_ReportDeviceConfiguration(DAC960_Controller_T *Controller) { int LogicalDriveNumber, Channel, TargetID; @@ -2316,7 +2315,7 @@ static boolean DAC960_V1_ReportDeviceCon Information for DAC960 V2 Firmware Controllers. */ -static boolean DAC960_V2_ReportDeviceConfiguration(DAC960_Controller_T +static bool DAC960_V2_ReportDeviceConfiguration(DAC960_Controller_T *Controller) { int PhysicalDeviceIndex, LogicalDriveNumber; @@ -2501,7 +2500,7 @@ static boolean DAC960_V2_ReportDeviceCon associated with Controller. */ -static boolean DAC960_RegisterBlockDevice(DAC960_Controller_T *Controller) +static bool DAC960_RegisterBlockDevice(DAC960_Controller_T *Controller) { int MajorNumber = DAC960_MAJOR + Controller->ControllerNumber; int n; @@ -2582,7 +2581,7 @@ static void DAC960_ComputeGenericDiskInf It returns true for fatal errors and false otherwise. */ -static boolean DAC960_ReportErrorStatus(DAC960_Controller_T *Controller, +static bool DAC960_ReportErrorStatus(DAC960_Controller_T *Controller, unsigned char ErrorStatus, unsigned char Parameter0, unsigned char Parameter1) @@ -3048,7 +3047,7 @@ Failure: DAC960_InitializeController initializes Controller. */ -static boolean +static bool DAC960_InitializeController(DAC960_Controller_T *Controller) { if (DAC960_ReadControllerConfiguration(Controller) && @@ -3445,8 +3444,8 @@ static void DAC960_RequestFunction(struc individual Buffer. */ -static inline boolean DAC960_ProcessCompletedRequest(DAC960_Command_T *Command, - boolean SuccessfulIO) +static inline bool DAC960_ProcessCompletedRequest(DAC960_Command_T *Command, + bool SuccessfulIO) { struct request *Request = Command->Request; int UpToDate; @@ -3572,7 +3571,7 @@ #endif else if (CommandType == DAC960_ReadRetryCommand || CommandType == DAC960_WriteRetryCommand) { - boolean normal_completion; + bool normal_completion; #ifdef FORCE_RETRY_FAILURE_DEBUG static int retry_count = 1; #endif @@ -4659,7 +4658,7 @@ #endif else if (CommandType == DAC960_ReadRetryCommand || CommandType == DAC960_WriteRetryCommand) { - boolean normal_completion; + bool normal_completion; #ifdef FORCE_RETRY_FAILURE_DEBUG static int retry_count = 1; @@ -4949,8 +4948,8 @@ #endif PhysicalDevice.LogicalUnit = NewLogicalDeviceInfo->LogicalUnit; Controller->V2.LogicalDriveToVirtualDevice[LogicalDeviceNumber] = PhysicalDevice; - LogicalDeviceInfo = (DAC960_V2_LogicalDeviceInfo_T *) - kmalloc(sizeof(DAC960_V2_LogicalDeviceInfo_T), GFP_ATOMIC); + LogicalDeviceInfo = kmalloc(sizeof(DAC960_V2_LogicalDeviceInfo_T), + GFP_ATOMIC); Controller->V2.LogicalDeviceInformation[LogicalDeviceNumber] = LogicalDeviceInfo; DAC960_Critical("Logical Drive %d (/dev/rd/c%dd%d) " @@ -5632,7 +5631,7 @@ static void DAC960_MonitoringTimerFuncti &Controller->V2.ControllerInformation; unsigned int StatusChangeCounter = Controller->V2.HealthStatusBuffer->StatusChangeCounter; - boolean ForceMonitoringCommand = false; + bool ForceMonitoringCommand = false; if (time_after(jiffies, Controller->SecondaryMonitoringTime + DAC960_SecondaryMonitoringInterval)) { @@ -5696,7 +5695,7 @@ static void DAC960_MonitoringTimerFuncti necessary. It returns true if there is enough room and false otherwise. */ -static boolean DAC960_CheckStatusBuffer(DAC960_Controller_T *Controller, +static bool DAC960_CheckStatusBuffer(DAC960_Controller_T *Controller, unsigned int ByteCount) { unsigned char *NewStatusBuffer; @@ -5709,14 +5708,14 @@ static boolean DAC960_CheckStatusBuffer( unsigned int NewStatusBufferLength = DAC960_InitialStatusBufferSize; while (NewStatusBufferLength < ByteCount) NewStatusBufferLength *= 2; - Controller->CombinedStatusBuffer = - (unsigned char *) kmalloc(NewStatusBufferLength, GFP_ATOMIC); + Controller->CombinedStatusBuffer = kmalloc(NewStatusBufferLength, + GFP_ATOMIC); if (Controller->CombinedStatusBuffer == NULL) return false; Controller->CombinedStatusBufferLength = NewStatusBufferLength; return true; } - NewStatusBuffer = (unsigned char *) - kmalloc(2 * Controller->CombinedStatusBufferLength, GFP_ATOMIC); + NewStatusBuffer = kmalloc(2 * Controller->CombinedStatusBufferLength, + GFP_ATOMIC); if (NewStatusBuffer == NULL) { DAC960_Warning("Unable to expand Combined Status Buffer - Truncating\n", @@ -5744,7 +5743,7 @@ static void DAC960_Message(DAC960_Messag ...) { static unsigned char Buffer[DAC960_LineBufferSize]; - static boolean BeginningOfLine = true; + static bool BeginningOfLine = true; va_list Arguments; int Length = 0; va_start(Arguments, Controller); @@ -5837,7 +5836,7 @@ static void DAC960_Message(DAC960_Messag Channel and TargetID and returns true on success and false on failure. */ -static boolean DAC960_ParsePhysicalDevice(DAC960_Controller_T *Controller, +static bool DAC960_ParsePhysicalDevice(DAC960_Controller_T *Controller, char *UserCommandString, unsigned char *Channel, unsigned char *TargetID) @@ -5870,7 +5869,7 @@ static boolean DAC960_ParsePhysicalDevic returns true on success and false on failure. */ -static boolean DAC960_ParseLogicalDrive(DAC960_Controller_T *Controller, +static bool DAC960_ParseLogicalDrive(DAC960_Controller_T *Controller, char *UserCommandString, unsigned char *LogicalDriveNumber) { @@ -5951,7 +5950,7 @@ static void DAC960_V1_SetDeviceState(DAC Controllers. */ -static boolean DAC960_V1_ExecuteUserCommand(DAC960_Controller_T *Controller, +static bool DAC960_V1_ExecuteUserCommand(DAC960_Controller_T *Controller, unsigned char *UserCommand) { DAC960_Command_T *Command; @@ -6166,7 +6165,7 @@ failure: on failure. */ -static boolean DAC960_V2_TranslatePhysicalDevice(DAC960_Command_T *Command, +static bool DAC960_V2_TranslatePhysicalDevice(DAC960_Command_T *Command, unsigned char Channel, unsigned char TargetID, unsigned short @@ -6213,7 +6212,7 @@ static boolean DAC960_V2_TranslatePhysic Controllers. */ -static boolean DAC960_V2_ExecuteUserCommand(DAC960_Controller_T *Controller, +static bool DAC960_V2_ExecuteUserCommand(DAC960_Controller_T *Controller, unsigned char *UserCommand) { DAC960_Command_T *Command; @@ -7025,7 +7024,7 @@ static int DAC960_gam_ioctl(struct inode return -EINVAL; } -static struct file_operations DAC960_gam_fops = { +static const struct file_operations DAC960_gam_fops = { .owner = THIS_MODULE, .ioctl = DAC960_gam_ioctl }; diff --git a/drivers/block/DAC960.h b/drivers/block/DAC960.h index 6148073..f5e2436 100644 --- a/drivers/block/DAC960.h +++ b/drivers/block/DAC960.h @@ -68,13 +68,6 @@ #define DAC690_V1_PciDmaMask 0xffffffff #define DAC690_V2_PciDmaMask 0xffffffffffffffffULL /* - Define a Boolean data type. -*/ - -typedef bool boolean; - - -/* Define a 32/64 bit I/O Address data type. */ @@ -139,25 +132,25 @@ typedef struct DAC960_SCSI_Inquiry unsigned char PeripheralDeviceType:5; /* Byte 0 Bits 0-4 */ unsigned char PeripheralQualifier:3; /* Byte 0 Bits 5-7 */ unsigned char DeviceTypeModifier:7; /* Byte 1 Bits 0-6 */ - boolean RMB:1; /* Byte 1 Bit 7 */ + bool RMB:1; /* Byte 1 Bit 7 */ unsigned char ANSI_ApprovedVersion:3; /* Byte 2 Bits 0-2 */ unsigned char ECMA_Version:3; /* Byte 2 Bits 3-5 */ unsigned char ISO_Version:2; /* Byte 2 Bits 6-7 */ unsigned char ResponseDataFormat:4; /* Byte 3 Bits 0-3 */ unsigned char :2; /* Byte 3 Bits 4-5 */ - boolean TrmIOP:1; /* Byte 3 Bit 6 */ - boolean AENC:1; /* Byte 3 Bit 7 */ + bool TrmIOP:1; /* Byte 3 Bit 6 */ + bool AENC:1; /* Byte 3 Bit 7 */ unsigned char AdditionalLength; /* Byte 4 */ unsigned char :8; /* Byte 5 */ unsigned char :8; /* Byte 6 */ - boolean SftRe:1; /* Byte 7 Bit 0 */ - boolean CmdQue:1; /* Byte 7 Bit 1 */ - boolean :1; /* Byte 7 Bit 2 */ - boolean Linked:1; /* Byte 7 Bit 3 */ - boolean Sync:1; /* Byte 7 Bit 4 */ - boolean WBus16:1; /* Byte 7 Bit 5 */ - boolean WBus32:1; /* Byte 7 Bit 6 */ - boolean RelAdr:1; /* Byte 7 Bit 7 */ + bool SftRe:1; /* Byte 7 Bit 0 */ + bool CmdQue:1; /* Byte 7 Bit 1 */ + bool :1; /* Byte 7 Bit 2 */ + bool Linked:1; /* Byte 7 Bit 3 */ + bool Sync:1; /* Byte 7 Bit 4 */ + bool WBus16:1; /* Byte 7 Bit 5 */ + bool WBus32:1; /* Byte 7 Bit 6 */ + bool RelAdr:1; /* Byte 7 Bit 7 */ unsigned char VendorIdentification[8]; /* Bytes 8-15 */ unsigned char ProductIdentification[16]; /* Bytes 16-31 */ unsigned char ProductRevisionLevel[4]; /* Bytes 32-35 */ @@ -215,13 +208,13 @@ DAC960_SCSI_RequestSenseKey_T; typedef struct DAC960_SCSI_RequestSense { unsigned char ErrorCode:7; /* Byte 0 Bits 0-6 */ - boolean Valid:1; /* Byte 0 Bit 7 */ + bool Valid:1; /* Byte 0 Bit 7 */ unsigned char SegmentNumber; /* Byte 1 */ DAC960_SCSI_RequestSenseKey_T SenseKey:4; /* Byte 2 Bits 0-3 */ unsigned char :1; /* Byte 2 Bit 4 */ - boolean ILI:1; /* Byte 2 Bit 5 */ - boolean EOM:1; /* Byte 2 Bit 6 */ - boolean Filemark:1; /* Byte 2 Bit 7 */ + bool ILI:1; /* Byte 2 Bit 5 */ + bool EOM:1; /* Byte 2 Bit 6 */ + bool Filemark:1; /* Byte 2 Bit 7 */ unsigned char Information[4]; /* Bytes 3-6 */ unsigned char AdditionalSenseLength; /* Byte 7 */ unsigned char CommandSpecificInformation[4]; /* Bytes 8-11 */ @@ -381,8 +374,8 @@ typedef struct DAC960_V1_Enquiry unsigned int LogicalDriveSizes[32]; /* Bytes 4-131 */ unsigned short FlashAge; /* Bytes 132-133 */ struct { - boolean DeferredWriteError:1; /* Byte 134 Bit 0 */ - boolean BatteryLow:1; /* Byte 134 Bit 1 */ + bool DeferredWriteError:1; /* Byte 134 Bit 0 */ + bool BatteryLow:1; /* Byte 134 Bit 1 */ unsigned char :6; /* Byte 134 Bits 2-7 */ } StatusFlags; unsigned char :8; /* Byte 135 */ @@ -410,7 +403,7 @@ typedef struct DAC960_V1_Enquiry unsigned char RebuildCount; /* Byte 150 */ struct { unsigned char :3; /* Byte 151 Bits 0-2 */ - boolean BatteryBackupUnitPresent:1; /* Byte 151 Bit 3 */ + bool BatteryBackupUnitPresent:1; /* Byte 151 Bit 3 */ unsigned char :3; /* Byte 151 Bits 4-6 */ unsigned char :1; /* Byte 151 Bit 7 */ } MiscFlags; @@ -492,8 +485,8 @@ typedef struct DAC960_V1_Enquiry2 DAC960_V1_ErrorCorrection_ECC = 0x2, DAC960_V1_ErrorCorrection_Last = 0x7 } __attribute__ ((packed)) ErrorCorrection:3; /* Byte 40 Bits 3-5 */ - boolean FastPageMode:1; /* Byte 40 Bit 6 */ - boolean LowPowerMemory:1; /* Byte 40 Bit 7 */ + bool FastPageMode:1; /* Byte 40 Bit 6 */ + bool LowPowerMemory:1; /* Byte 40 Bit 7 */ unsigned char :8; /* Bytes 41 */ } MemoryType; unsigned short ClockSpeed; /* Bytes 42-43 */ @@ -538,7 +531,7 @@ typedef struct DAC960_V1_Enquiry2 DAC960_V1_Ultra = 0x1, DAC960_V1_Ultra2 = 0x2 } __attribute__ ((packed)) BusSpeed:2; /* Byte 106 Bits 2-3 */ - boolean Differential:1; /* Byte 106 Bit 4 */ + bool Differential:1; /* Byte 106 Bit 4 */ unsigned char :3; /* Byte 106 Bits 5-7 */ } SCSICapability; unsigned char :8; /* Byte 107 */ @@ -554,10 +547,10 @@ typedef struct DAC960_V1_Enquiry2 } __attribute__ ((packed)) FaultManagementType; /* Byte 114 */ unsigned char :8; /* Byte 115 */ struct { - boolean Clustering:1; /* Byte 116 Bit 0 */ - boolean MylexOnlineRAIDExpansion:1; /* Byte 116 Bit 1 */ - boolean ReadAhead:1; /* Byte 116 Bit 2 */ - boolean BackgroundInitialization:1; /* Byte 116 Bit 3 */ + bool Clustering:1; /* Byte 116 Bit 0 */ + bool MylexOnlineRAIDExpansion:1; /* Byte 116 Bit 1 */ + bool ReadAhead:1; /* Byte 116 Bit 2 */ + bool BackgroundInitialization:1; /* Byte 116 Bit 3 */ unsigned int :28; /* Bytes 116-119 */ } FirmwareFeatures; unsigned int :32; /* Bytes 120-123 */ @@ -589,7 +582,7 @@ typedef struct DAC960_V1_LogicalDriveInf unsigned int LogicalDriveSize; /* Bytes 0-3 */ DAC960_V1_LogicalDriveState_T LogicalDriveState; /* Byte 4 */ unsigned char RAIDLevel:7; /* Byte 5 Bits 0-6 */ - boolean WriteBack:1; /* Byte 5 Bit 7 */ + bool WriteBack:1; /* Byte 5 Bit 7 */ unsigned short :16; /* Bytes 6-7 */ } DAC960_V1_LogicalDriveInformation_T; @@ -630,13 +623,13 @@ typedef struct DAC960_V1_EventLogEntry unsigned char :2; /* Byte 3 Bits 6-7 */ unsigned short SequenceNumber; /* Bytes 4-5 */ unsigned char ErrorCode:7; /* Byte 6 Bits 0-6 */ - boolean Valid:1; /* Byte 6 Bit 7 */ + bool Valid:1; /* Byte 6 Bit 7 */ unsigned char SegmentNumber; /* Byte 7 */ DAC960_SCSI_RequestSenseKey_T SenseKey:4; /* Byte 8 Bits 0-3 */ unsigned char :1; /* Byte 8 Bit 4 */ - boolean ILI:1; /* Byte 8 Bit 5 */ - boolean EOM:1; /* Byte 8 Bit 6 */ - boolean Filemark:1; /* Byte 8 Bit 7 */ + bool ILI:1; /* Byte 8 Bit 5 */ + bool EOM:1; /* Byte 8 Bit 6 */ + bool Filemark:1; /* Byte 8 Bit 7 */ unsigned char Information[4]; /* Bytes 9-12 */ unsigned char AdditionalSenseLength; /* Byte 13 */ unsigned char CommandSpecificInformation[4]; /* Bytes 14-17 */ @@ -670,7 +663,7 @@ DAC960_V1_PhysicalDeviceState_T; typedef struct DAC960_V1_DeviceState { - boolean Present:1; /* Byte 0 Bit 0 */ + bool Present:1; /* Byte 0 Bit 0 */ unsigned char :7; /* Byte 0 Bits 1-7 */ enum { DAC960_V1_OtherType = 0x0, @@ -678,12 +671,12 @@ typedef struct DAC960_V1_DeviceState DAC960_V1_SequentialType = 0x2, DAC960_V1_CDROM_or_WORM_Type = 0x3 } __attribute__ ((packed)) DeviceType:2; /* Byte 1 Bits 0-1 */ - boolean :1; /* Byte 1 Bit 2 */ - boolean Fast20:1; /* Byte 1 Bit 3 */ - boolean Sync:1; /* Byte 1 Bit 4 */ - boolean Fast:1; /* Byte 1 Bit 5 */ - boolean Wide:1; /* Byte 1 Bit 6 */ - boolean TaggedQueuingSupported:1; /* Byte 1 Bit 7 */ + bool :1; /* Byte 1 Bit 2 */ + bool Fast20:1; /* Byte 1 Bit 3 */ + bool Sync:1; /* Byte 1 Bit 4 */ + bool Fast:1; /* Byte 1 Bit 5 */ + bool Wide:1; /* Byte 1 Bit 6 */ + bool TaggedQueuingSupported:1; /* Byte 1 Bit 7 */ DAC960_V1_PhysicalDeviceState_T DeviceState; /* Byte 2 */ unsigned char :8; /* Byte 3 */ unsigned char SynchronousMultiplier; /* Byte 4 */ @@ -765,15 +758,15 @@ DAC960_V1_ErrorTable_T; typedef struct DAC960_V1_Config2 { unsigned char :1; /* Byte 0 Bit 0 */ - boolean ActiveNegationEnabled:1; /* Byte 0 Bit 1 */ + bool ActiveNegationEnabled:1; /* Byte 0 Bit 1 */ unsigned char :5; /* Byte 0 Bits 2-6 */ - boolean NoRescanIfResetReceivedDuringScan:1; /* Byte 0 Bit 7 */ - boolean StorageWorksSupportEnabled:1; /* Byte 1 Bit 0 */ - boolean HewlettPackardSupportEnabled:1; /* Byte 1 Bit 1 */ - boolean NoDisconnectOnFirstCommand:1; /* Byte 1 Bit 2 */ + bool NoRescanIfResetReceivedDuringScan:1; /* Byte 0 Bit 7 */ + bool StorageWorksSupportEnabled:1; /* Byte 1 Bit 0 */ + bool HewlettPackardSupportEnabled:1; /* Byte 1 Bit 1 */ + bool NoDisconnectOnFirstCommand:1; /* Byte 1 Bit 2 */ unsigned char :2; /* Byte 1 Bits 3-4 */ - boolean AEMI_ARM:1; /* Byte 1 Bit 5 */ - boolean AEMI_OFM:1; /* Byte 1 Bit 6 */ + bool AEMI_ARM:1; /* Byte 1 Bit 5 */ + bool AEMI_OFM:1; /* Byte 1 Bit 6 */ unsigned char :1; /* Byte 1 Bit 7 */ enum { DAC960_V1_OEMID_Mylex = 0x00, @@ -787,13 +780,13 @@ typedef struct DAC960_V1_Config2 unsigned char PhysicalSector; /* Byte 4 */ unsigned char LogicalSector; /* Byte 5 */ unsigned char BlockFactor; /* Byte 6 */ - boolean ReadAheadEnabled:1; /* Byte 7 Bit 0 */ - boolean LowBIOSDelay:1; /* Byte 7 Bit 1 */ + bool ReadAheadEnabled:1; /* Byte 7 Bit 0 */ + bool LowBIOSDelay:1; /* Byte 7 Bit 1 */ unsigned char :2; /* Byte 7 Bits 2-3 */ - boolean ReassignRestrictedToOneSector:1; /* Byte 7 Bit 4 */ + bool ReassignRestrictedToOneSector:1; /* Byte 7 Bit 4 */ unsigned char :1; /* Byte 7 Bit 5 */ - boolean ForceUnitAccessDuringWriteRecovery:1; /* Byte 7 Bit 6 */ - boolean EnableLeftSymmetricRAID5Algorithm:1; /* Byte 7 Bit 7 */ + bool ForceUnitAccessDuringWriteRecovery:1; /* Byte 7 Bit 6 */ + bool EnableLeftSymmetricRAID5Algorithm:1; /* Byte 7 Bit 7 */ unsigned char DefaultRebuildRate; /* Byte 8 */ unsigned char :8; /* Byte 9 */ unsigned char BlocksPerCacheLine; /* Byte 10 */ @@ -805,10 +798,10 @@ typedef struct DAC960_V1_Config2 DAC960_V1_Sync_5MHz = 0x2, DAC960_V1_Sync_10or20MHz = 0x3 /* Byte 11 Bits 0-1 */ } __attribute__ ((packed)) Speed:2; - boolean Force8Bit:1; /* Byte 11 Bit 2 */ - boolean DisableFast20:1; /* Byte 11 Bit 3 */ + bool Force8Bit:1; /* Byte 11 Bit 2 */ + bool DisableFast20:1; /* Byte 11 Bit 3 */ unsigned char :3; /* Byte 11 Bits 4-6 */ - boolean EnableTaggedQueuing:1; /* Byte 11 Bit 7 */ + bool EnableTaggedQueuing:1; /* Byte 11 Bit 7 */ } __attribute__ ((packed)) ChannelParameters[6]; /* Bytes 12-17 */ unsigned char SCSIInitiatorID; /* Byte 18 */ unsigned char :8; /* Byte 19 */ @@ -819,8 +812,8 @@ typedef struct DAC960_V1_Config2 unsigned char SimultaneousDeviceSpinUpCount; /* Byte 21 */ unsigned char SecondsDelayBetweenSpinUps; /* Byte 22 */ unsigned char Reserved1[29]; /* Bytes 23-51 */ - boolean BIOSDisabled:1; /* Byte 52 Bit 0 */ - boolean CDROMBootEnabled:1; /* Byte 52 Bit 1 */ + bool BIOSDisabled:1; /* Byte 52 Bit 0 */ + bool CDROMBootEnabled:1; /* Byte 52 Bit 1 */ unsigned char :3; /* Byte 52 Bits 2-4 */ enum { DAC960_V1_Geometry_128_32 = 0x0, @@ -849,7 +842,7 @@ typedef struct DAC960_V1_DCDB DAC960_V1_DCDB_DataTransferSystemToDevice = 2, DAC960_V1_DCDB_IllegalDataTransfer = 3 } __attribute__ ((packed)) Direction:2; /* Byte 1 Bits 0-1 */ - boolean EarlyStatus:1; /* Byte 1 Bit 2 */ + bool EarlyStatus:1; /* Byte 1 Bit 2 */ unsigned char :1; /* Byte 1 Bit 3 */ enum { DAC960_V1_DCDB_Timeout_24_hours = 0, @@ -857,8 +850,8 @@ typedef struct DAC960_V1_DCDB DAC960_V1_DCDB_Timeout_60_seconds = 2, DAC960_V1_DCDB_Timeout_10_minutes = 3 } __attribute__ ((packed)) Timeout:2; /* Byte 1 Bits 4-5 */ - boolean NoAutomaticRequestSense:1; /* Byte 1 Bit 6 */ - boolean DisconnectPermitted:1; /* Byte 1 Bit 7 */ + bool NoAutomaticRequestSense:1; /* Byte 1 Bit 6 */ + bool DisconnectPermitted:1; /* Byte 1 Bit 7 */ unsigned short TransferLength; /* Bytes 2-3 */ DAC960_BusAddress32_T BusAddress; /* Bytes 4-7 */ unsigned char CDBLength:4; /* Byte 8 Bits 0-3 */ @@ -920,7 +913,7 @@ typedef union DAC960_V1_CommandMailbox DAC960_V1_CommandIdentifier_T CommandIdentifier; /* Byte 1 */ unsigned char Dummy1[5]; /* Bytes 2-6 */ unsigned char LogicalDriveNumber:6; /* Byte 7 Bits 0-6 */ - boolean AutoRestore:1; /* Byte 7 Bit 7 */ + bool AutoRestore:1; /* Byte 7 Bit 7 */ unsigned char Dummy2[8]; /* Bytes 8-15 */ } __attribute__ ((packed)) Type3C; struct { @@ -1070,9 +1063,9 @@ typedef struct DAC960_V2_MemoryType DAC960_V2_MemoryType_SDRAM = 0x04, DAC960_V2_MemoryType_Last = 0x1F } __attribute__ ((packed)) MemoryType:5; /* Byte 0 Bits 0-4 */ - boolean :1; /* Byte 0 Bit 5 */ - boolean MemoryParity:1; /* Byte 0 Bit 6 */ - boolean MemoryECC:1; /* Byte 0 Bit 7 */ + bool :1; /* Byte 0 Bit 5 */ + bool MemoryParity:1; /* Byte 0 Bit 6 */ + bool MemoryECC:1; /* Byte 0 Bit 7 */ } DAC960_V2_MemoryType_T; @@ -1187,13 +1180,13 @@ typedef struct DAC960_V2_ControllerInfo unsigned char OEM_Code; /* Byte 131 */ unsigned char VendorName[16]; /* Bytes 132-147 */ /* Other Physical/Controller/Operation Information */ - boolean BBU_Present:1; /* Byte 148 Bit 0 */ - boolean ActiveActiveClusteringMode:1; /* Byte 148 Bit 1 */ + bool BBU_Present:1; /* Byte 148 Bit 0 */ + bool ActiveActiveClusteringMode:1; /* Byte 148 Bit 1 */ unsigned char :6; /* Byte 148 Bits 2-7 */ unsigned char :8; /* Byte 149 */ unsigned short :16; /* Bytes 150-151 */ /* Physical Device Scan Information */ - boolean PhysicalScanActive:1; /* Byte 152 Bit 0 */ + bool PhysicalScanActive:1; /* Byte 152 Bit 0 */ unsigned char :7; /* Byte 152 Bits 1-7 */ unsigned char PhysicalDeviceChannelNumber; /* Byte 153 */ unsigned char PhysicalDeviceTargetID; /* Byte 154 */ @@ -1305,8 +1298,8 @@ typedef struct DAC960_V2_ControllerInfo unsigned int FreeIOP; /* Bytes 468-471 */ unsigned short MaximumCombLengthInBlocks; /* Bytes 472-473 */ unsigned short NumberOfConfigurationGroups; /* Bytes 474-475 */ - boolean InstallationAbortStatus:1; /* Byte 476 Bit 0 */ - boolean MaintenanceModeStatus:1; /* Byte 476 Bit 1 */ + bool InstallationAbortStatus:1; /* Byte 476 Bit 0 */ + bool MaintenanceModeStatus:1; /* Byte 476 Bit 1 */ unsigned int :24; /* Bytes 476-479 */ unsigned char Reserved10[32]; /* Bytes 480-511 */ unsigned char Reserved11[512]; /* Bytes 512-1023 */ @@ -1357,33 +1350,33 @@ typedef struct DAC960_V2_LogicalDeviceIn DAC960_V2_IntelligentWriteCacheEnabled = 0x3, DAC960_V2_WriteCache_Last = 0x7 } __attribute__ ((packed)) WriteCache:3; /* Byte 8 Bits 3-5 */ - boolean :1; /* Byte 8 Bit 6 */ - boolean LogicalDeviceInitialized:1; /* Byte 8 Bit 7 */ + bool :1; /* Byte 8 Bit 6 */ + bool LogicalDeviceInitialized:1; /* Byte 8 Bit 7 */ } LogicalDeviceControl; /* Byte 8 */ /* Logical Device Operations Status */ - boolean ConsistencyCheckInProgress:1; /* Byte 9 Bit 0 */ - boolean RebuildInProgress:1; /* Byte 9 Bit 1 */ - boolean BackgroundInitializationInProgress:1; /* Byte 9 Bit 2 */ - boolean ForegroundInitializationInProgress:1; /* Byte 9 Bit 3 */ - boolean DataMigrationInProgress:1; /* Byte 9 Bit 4 */ - boolean PatrolOperationInProgress:1; /* Byte 9 Bit 5 */ + bool ConsistencyCheckInProgress:1; /* Byte 9 Bit 0 */ + bool RebuildInProgress:1; /* Byte 9 Bit 1 */ + bool BackgroundInitializationInProgress:1; /* Byte 9 Bit 2 */ + bool ForegroundInitializationInProgress:1; /* Byte 9 Bit 3 */ + bool DataMigrationInProgress:1; /* Byte 9 Bit 4 */ + bool PatrolOperationInProgress:1; /* Byte 9 Bit 5 */ unsigned char :2; /* Byte 9 Bits 6-7 */ unsigned char RAID5WriteUpdate; /* Byte 10 */ unsigned char RAID5Algorithm; /* Byte 11 */ unsigned short LogicalDeviceNumber; /* Bytes 12-13 */ /* BIOS Info */ - boolean BIOSDisabled:1; /* Byte 14 Bit 0 */ - boolean CDROMBootEnabled:1; /* Byte 14 Bit 1 */ - boolean DriveCoercionEnabled:1; /* Byte 14 Bit 2 */ - boolean WriteSameDisabled:1; /* Byte 14 Bit 3 */ - boolean HBA_ModeEnabled:1; /* Byte 14 Bit 4 */ + bool BIOSDisabled:1; /* Byte 14 Bit 0 */ + bool CDROMBootEnabled:1; /* Byte 14 Bit 1 */ + bool DriveCoercionEnabled:1; /* Byte 14 Bit 2 */ + bool WriteSameDisabled:1; /* Byte 14 Bit 3 */ + bool HBA_ModeEnabled:1; /* Byte 14 Bit 4 */ enum { DAC960_V2_Geometry_128_32 = 0x0, DAC960_V2_Geometry_255_63 = 0x1, DAC960_V2_Geometry_Reserved1 = 0x2, DAC960_V2_Geometry_Reserved2 = 0x3 } __attribute__ ((packed)) DriveGeometry:2; /* Byte 14 Bits 5-6 */ - boolean SuperReadAheadEnabled:1; /* Byte 14 Bit 7 */ + bool SuperReadAheadEnabled:1; /* Byte 14 Bit 7 */ unsigned char :8; /* Byte 15 */ /* Error Counters */ unsigned short SoftErrors; /* Bytes 16-17 */ @@ -1446,13 +1439,13 @@ typedef struct DAC960_V2_PhysicalDeviceI unsigned char TargetID; /* Byte 2 */ unsigned char LogicalUnit; /* Byte 3 */ /* Configuration Status Bits */ - boolean PhysicalDeviceFaultTolerant:1; /* Byte 4 Bit 0 */ - boolean PhysicalDeviceConnected:1; /* Byte 4 Bit 1 */ - boolean PhysicalDeviceLocalToController:1; /* Byte 4 Bit 2 */ + bool PhysicalDeviceFaultTolerant:1; /* Byte 4 Bit 0 */ + bool PhysicalDeviceConnected:1; /* Byte 4 Bit 1 */ + bool PhysicalDeviceLocalToController:1; /* Byte 4 Bit 2 */ unsigned char :5; /* Byte 4 Bits 3-7 */ /* Multiple Host/Controller Status Bits */ - boolean RemoteHostSystemDead:1; /* Byte 5 Bit 0 */ - boolean RemoteControllerDead:1; /* Byte 5 Bit 1 */ + bool RemoteHostSystemDead:1; /* Byte 5 Bit 0 */ + bool RemoteControllerDead:1; /* Byte 5 Bit 1 */ unsigned char :6; /* Byte 5 Bits 2-7 */ DAC960_V2_PhysicalDeviceState_T PhysicalDeviceState; /* Byte 6 */ unsigned char NegotiatedDataWidthBits; /* Byte 7 */ @@ -1464,12 +1457,12 @@ typedef struct DAC960_V2_PhysicalDeviceI unsigned char NetworkAddress[16]; /* Bytes 16-31 */ unsigned short MaximumTags; /* Bytes 32-33 */ /* Physical Device Operations Status */ - boolean ConsistencyCheckInProgress:1; /* Byte 34 Bit 0 */ - boolean RebuildInProgress:1; /* Byte 34 Bit 1 */ - boolean MakingDataConsistentInProgress:1; /* Byte 34 Bit 2 */ - boolean PhysicalDeviceInitializationInProgress:1; /* Byte 34 Bit 3 */ - boolean DataMigrationInProgress:1; /* Byte 34 Bit 4 */ - boolean PatrolOperationInProgress:1; /* Byte 34 Bit 5 */ + bool ConsistencyCheckInProgress:1; /* Byte 34 Bit 0 */ + bool RebuildInProgress:1; /* Byte 34 Bit 1 */ + bool MakingDataConsistentInProgress:1; /* Byte 34 Bit 2 */ + bool PhysicalDeviceInitializationInProgress:1; /* Byte 34 Bit 3 */ + bool DataMigrationInProgress:1; /* Byte 34 Bit 4 */ + bool PatrolOperationInProgress:1; /* Byte 34 Bit 5 */ unsigned char :2; /* Byte 34 Bits 6-7 */ unsigned char LongOperationStatus; /* Byte 35 */ unsigned char ParityErrors; /* Byte 36 */ @@ -1555,14 +1548,14 @@ DAC960_V2_Event_T; typedef struct DAC960_V2_CommandControlBits { - boolean ForceUnitAccess:1; /* Byte 0 Bit 0 */ - boolean DisablePageOut:1; /* Byte 0 Bit 1 */ - boolean :1; /* Byte 0 Bit 2 */ - boolean AdditionalScatterGatherListMemory:1; /* Byte 0 Bit 3 */ - boolean DataTransferControllerToHost:1; /* Byte 0 Bit 4 */ - boolean :1; /* Byte 0 Bit 5 */ - boolean NoAutoRequestSense:1; /* Byte 0 Bit 6 */ - boolean DisconnectProhibited:1; /* Byte 0 Bit 7 */ + bool ForceUnitAccess:1; /* Byte 0 Bit 0 */ + bool DisablePageOut:1; /* Byte 0 Bit 1 */ + bool :1; /* Byte 0 Bit 2 */ + bool AdditionalScatterGatherListMemory:1; /* Byte 0 Bit 3 */ + bool DataTransferControllerToHost:1; /* Byte 0 Bit 4 */ + bool :1; /* Byte 0 Bit 5 */ + bool NoAutoRequestSense:1; /* Byte 0 Bit 6 */ + bool DisconnectProhibited:1; /* Byte 0 Bit 7 */ } DAC960_V2_CommandControlBits_T; @@ -1825,8 +1818,8 @@ typedef union DAC960_V2_CommandMailbox DAC960_V2_CommandTimeout_T CommandTimeout; /* Byte 19 */ unsigned char RequestSenseSize; /* Byte 20 */ unsigned char IOCTL_Opcode; /* Byte 21 */ - boolean RestoreConsistency:1; /* Byte 22 Bit 0 */ - boolean InitializedAreaOnly:1; /* Byte 22 Bit 1 */ + bool RestoreConsistency:1; /* Byte 22 Bit 0 */ + bool InitializedAreaOnly:1; /* Byte 22 Bit 1 */ unsigned char :6; /* Byte 22 Bits 2-7 */ unsigned char Reserved[9]; /* Bytes 23-31 */ DAC960_V2_DataTransferMemoryAddress_T @@ -2190,7 +2183,7 @@ typedef union DAC960_V1_StatusMailbox struct { DAC960_V1_CommandIdentifier_T CommandIdentifier; /* Byte 0 */ unsigned char :7; /* Byte 1 Bits 0-6 */ - boolean Valid:1; /* Byte 1 Bit 7 */ + bool Valid:1; /* Byte 1 Bit 7 */ DAC960_V1_CommandStatus_T CommandStatus; /* Bytes 2-3 */ } Fields; } @@ -2322,12 +2315,12 @@ typedef struct DAC960_Controller unsigned long ShutdownMonitoringTimer; unsigned long LastProgressReportTime; unsigned long LastCurrentStatusTime; - boolean ControllerInitialized; - boolean MonitoringCommandDeferred; - boolean EphemeralProgressMessage; - boolean DriveSpinUpMessageDisplayed; - boolean MonitoringAlertMode; - boolean SuppressEnclosureMessages; + bool ControllerInitialized; + bool MonitoringCommandDeferred; + bool EphemeralProgressMessage; + bool DriveSpinUpMessageDisplayed; + bool MonitoringAlertMode; + bool SuppressEnclosureMessages; struct timer_list MonitoringTimer; struct gendisk *disks[DAC960_MaxLogicalDrives]; struct pci_pool *ScatterGatherPool; @@ -2342,11 +2335,11 @@ typedef struct DAC960_Controller DAC960_Command_T InitialCommand; DAC960_Command_T *Commands[DAC960_MaxDriverQueueDepth]; struct proc_dir_entry *ControllerProcEntry; - boolean LogicalDriveInitiallyAccessible[DAC960_MaxLogicalDrives]; + bool LogicalDriveInitiallyAccessible[DAC960_MaxLogicalDrives]; void (*QueueCommand)(DAC960_Command_T *Command); - boolean (*ReadControllerConfiguration)(struct DAC960_Controller *); - boolean (*ReadDeviceConfiguration)(struct DAC960_Controller *); - boolean (*ReportDeviceConfiguration)(struct DAC960_Controller *); + bool (*ReadControllerConfiguration)(struct DAC960_Controller *); + bool (*ReadDeviceConfiguration)(struct DAC960_Controller *); + bool (*ReportDeviceConfiguration)(struct DAC960_Controller *); void (*QueueReadWriteCommand)(DAC960_Command_T *Command); union { struct { @@ -2359,21 +2352,21 @@ typedef struct DAC960_Controller unsigned short OldEventLogSequenceNumber; unsigned short DeviceStateChannel; unsigned short DeviceStateTargetID; - boolean DualModeMemoryMailboxInterface; - boolean BackgroundInitializationStatusSupported; - boolean SAFTE_EnclosureManagementEnabled; - boolean NeedLogicalDriveInformation; - boolean NeedErrorTableInformation; - boolean NeedDeviceStateInformation; - boolean NeedDeviceInquiryInformation; - boolean NeedDeviceSerialNumberInformation; - boolean NeedRebuildProgress; - boolean NeedConsistencyCheckProgress; - boolean NeedBackgroundInitializationStatus; - boolean StartDeviceStateScan; - boolean RebuildProgressFirst; - boolean RebuildFlagPending; - boolean RebuildStatusPending; + bool DualModeMemoryMailboxInterface; + bool BackgroundInitializationStatusSupported; + bool SAFTE_EnclosureManagementEnabled; + bool NeedLogicalDriveInformation; + bool NeedErrorTableInformation; + bool NeedDeviceStateInformation; + bool NeedDeviceInquiryInformation; + bool NeedDeviceSerialNumberInformation; + bool NeedRebuildProgress; + bool NeedConsistencyCheckProgress; + bool NeedBackgroundInitializationStatus; + bool StartDeviceStateScan; + bool RebuildProgressFirst; + bool RebuildFlagPending; + bool RebuildStatusPending; dma_addr_t FirstCommandMailboxDMA; DAC960_V1_CommandMailbox_T *FirstCommandMailbox; @@ -2432,17 +2425,17 @@ typedef struct DAC960_Controller dma_addr_t NewInquiryUnitSerialNumberDMA; int DeviceResetCount[DAC960_V1_MaxChannels][DAC960_V1_MaxTargets]; - boolean DirectCommandActive[DAC960_V1_MaxChannels][DAC960_V1_MaxTargets]; + bool DirectCommandActive[DAC960_V1_MaxChannels][DAC960_V1_MaxTargets]; } V1; struct { unsigned int StatusChangeCounter; unsigned int NextEventSequenceNumber; unsigned int PhysicalDeviceIndex; - boolean NeedLogicalDeviceInformation; - boolean NeedPhysicalDeviceInformation; - boolean NeedDeviceSerialNumberInformation; - boolean StartLogicalDeviceInformationScan; - boolean StartPhysicalDeviceInformationScan; + bool NeedLogicalDeviceInformation; + bool NeedPhysicalDeviceInformation; + bool NeedDeviceSerialNumberInformation; + bool StartLogicalDeviceInformationScan; + bool StartPhysicalDeviceInformationScan; struct pci_pool *RequestSensePool; dma_addr_t FirstCommandMailboxDMA; @@ -2487,7 +2480,7 @@ typedef struct DAC960_Controller DAC960_V2_PhysicalDevice_T LogicalDriveToVirtualDevice[DAC960_MaxLogicalDrives]; - boolean LogicalDriveFoundDuringScan[DAC960_MaxLogicalDrives]; + bool LogicalDriveFoundDuringScan[DAC960_MaxLogicalDrives]; } V2; } FW; unsigned char ProgressBuffer[DAC960_ProgressBufferSize]; @@ -2572,17 +2565,17 @@ typedef union DAC960_GEM_InboundDoorBell unsigned int All; struct { unsigned int :24; - boolean HardwareMailboxNewCommand:1; - boolean AcknowledgeHardwareMailboxStatus:1; - boolean GenerateInterrupt:1; - boolean ControllerReset:1; - boolean MemoryMailboxNewCommand:1; + bool HardwareMailboxNewCommand:1; + bool AcknowledgeHardwareMailboxStatus:1; + bool GenerateInterrupt:1; + bool ControllerReset:1; + bool MemoryMailboxNewCommand:1; unsigned int :3; } Write; struct { unsigned int :24; - boolean HardwareMailboxFull:1; - boolean InitializationInProgress:1; + bool HardwareMailboxFull:1; + bool InitializationInProgress:1; unsigned int :6; } Read; } @@ -2596,14 +2589,14 @@ typedef union DAC960_GEM_OutboundDoorBel unsigned int All; struct { unsigned int :24; - boolean AcknowledgeHardwareMailboxInterrupt:1; - boolean AcknowledgeMemoryMailboxInterrupt:1; + bool AcknowledgeHardwareMailboxInterrupt:1; + bool AcknowledgeMemoryMailboxInterrupt:1; unsigned int :6; } Write; struct { unsigned int :24; - boolean HardwareMailboxStatusAvailable:1; - boolean MemoryMailboxStatusAvailable:1; + bool HardwareMailboxStatusAvailable:1; + bool MemoryMailboxStatusAvailable:1; unsigned int :6; } Read; } @@ -2635,7 +2628,7 @@ typedef union DAC960_GEM_ErrorStatusRegi struct { unsigned int :24; unsigned int :5; - boolean ErrorStatusPending:1; + bool ErrorStatusPending:1; unsigned int :2; } Bits; } @@ -2697,7 +2690,7 @@ void DAC960_GEM_MemoryMailboxNewCommand( } static inline -boolean DAC960_GEM_HardwareMailboxFullP(void __iomem *ControllerBaseAddress) +bool DAC960_GEM_HardwareMailboxFullP(void __iomem *ControllerBaseAddress) { DAC960_GEM_InboundDoorBellRegister_T InboundDoorBellRegister; InboundDoorBellRegister.All = @@ -2707,7 +2700,7 @@ boolean DAC960_GEM_HardwareMailboxFullP( } static inline -boolean DAC960_GEM_InitializationInProgressP(void __iomem *ControllerBaseAddress) +bool DAC960_GEM_InitializationInProgressP(void __iomem *ControllerBaseAddress) { DAC960_GEM_InboundDoorBellRegister_T InboundDoorBellRegister; InboundDoorBellRegister.All = @@ -2748,7 +2741,7 @@ void DAC960_GEM_AcknowledgeInterrupt(voi } static inline -boolean DAC960_GEM_HardwareMailboxStatusAvailableP(void __iomem *ControllerBaseAddress) +bool DAC960_GEM_HardwareMailboxStatusAvailableP(void __iomem *ControllerBaseAddress) { DAC960_GEM_OutboundDoorBellRegister_T OutboundDoorBellRegister; OutboundDoorBellRegister.All = @@ -2758,7 +2751,7 @@ boolean DAC960_GEM_HardwareMailboxStatus } static inline -boolean DAC960_GEM_MemoryMailboxStatusAvailableP(void __iomem *ControllerBaseAddress) +bool DAC960_GEM_MemoryMailboxStatusAvailableP(void __iomem *ControllerBaseAddress) { DAC960_GEM_OutboundDoorBellRegister_T OutboundDoorBellRegister; OutboundDoorBellRegister.All = @@ -2790,7 +2783,7 @@ void DAC960_GEM_DisableInterrupts(void _ } static inline -boolean DAC960_GEM_InterruptsEnabledP(void __iomem *ControllerBaseAddress) +bool DAC960_GEM_InterruptsEnabledP(void __iomem *ControllerBaseAddress) { DAC960_GEM_InterruptMaskRegister_T InterruptMaskRegister; InterruptMaskRegister.All = @@ -2834,7 +2827,7 @@ DAC960_GEM_ReadCommandStatus(void __iome return readw(ControllerBaseAddress + DAC960_GEM_CommandStatusOffset + 2); } -static inline boolean +static inline bool DAC960_GEM_ReadErrorStatus(void __iomem *ControllerBaseAddress, unsigned char *ErrorStatus, unsigned char *Parameter0, @@ -2882,16 +2875,16 @@ typedef union DAC960_BA_InboundDoorBellR { unsigned char All; struct { - boolean HardwareMailboxNewCommand:1; /* Bit 0 */ - boolean AcknowledgeHardwareMailboxStatus:1; /* Bit 1 */ - boolean GenerateInterrupt:1; /* Bit 2 */ - boolean ControllerReset:1; /* Bit 3 */ - boolean MemoryMailboxNewCommand:1; /* Bit 4 */ + bool HardwareMailboxNewCommand:1; /* Bit 0 */ + bool AcknowledgeHardwareMailboxStatus:1; /* Bit 1 */ + bool GenerateInterrupt:1; /* Bit 2 */ + bool ControllerReset:1; /* Bit 3 */ + bool MemoryMailboxNewCommand:1; /* Bit 4 */ unsigned char :3; /* Bits 5-7 */ } Write; struct { - boolean HardwareMailboxEmpty:1; /* Bit 0 */ - boolean InitializationNotInProgress:1; /* Bit 1 */ + bool HardwareMailboxEmpty:1; /* Bit 0 */ + bool InitializationNotInProgress:1; /* Bit 1 */ unsigned char :6; /* Bits 2-7 */ } Read; } @@ -2906,13 +2899,13 @@ typedef union DAC960_BA_OutboundDoorBell { unsigned char All; struct { - boolean AcknowledgeHardwareMailboxInterrupt:1; /* Bit 0 */ - boolean AcknowledgeMemoryMailboxInterrupt:1; /* Bit 1 */ + bool AcknowledgeHardwareMailboxInterrupt:1; /* Bit 0 */ + bool AcknowledgeMemoryMailboxInterrupt:1; /* Bit 1 */ unsigned char :6; /* Bits 2-7 */ } Write; struct { - boolean HardwareMailboxStatusAvailable:1; /* Bit 0 */ - boolean MemoryMailboxStatusAvailable:1; /* Bit 1 */ + bool HardwareMailboxStatusAvailable:1; /* Bit 0 */ + bool MemoryMailboxStatusAvailable:1; /* Bit 1 */ unsigned char :6; /* Bits 2-7 */ } Read; } @@ -2928,8 +2921,8 @@ typedef union DAC960_BA_InterruptMaskReg unsigned char All; struct { unsigned int :2; /* Bits 0-1 */ - boolean DisableInterrupts:1; /* Bit 2 */ - boolean DisableInterruptsI2O:1; /* Bit 3 */ + bool DisableInterrupts:1; /* Bit 2 */ + bool DisableInterruptsI2O:1; /* Bit 3 */ unsigned int :4; /* Bits 4-7 */ } Bits; } @@ -2945,7 +2938,7 @@ typedef union DAC960_BA_ErrorStatusRegis unsigned char All; struct { unsigned int :2; /* Bits 0-1 */ - boolean ErrorStatusPending:1; /* Bit 2 */ + bool ErrorStatusPending:1; /* Bit 2 */ unsigned int :5; /* Bits 3-7 */ } Bits; } @@ -3008,7 +3001,7 @@ void DAC960_BA_MemoryMailboxNewCommand(v } static inline -boolean DAC960_BA_HardwareMailboxFullP(void __iomem *ControllerBaseAddress) +bool DAC960_BA_HardwareMailboxFullP(void __iomem *ControllerBaseAddress) { DAC960_BA_InboundDoorBellRegister_T InboundDoorBellRegister; InboundDoorBellRegister.All = @@ -3017,7 +3010,7 @@ boolean DAC960_BA_HardwareMailboxFullP(v } static inline -boolean DAC960_BA_InitializationInProgressP(void __iomem *ControllerBaseAddress) +bool DAC960_BA_InitializationInProgressP(void __iomem *ControllerBaseAddress) { DAC960_BA_InboundDoorBellRegister_T InboundDoorBellRegister; InboundDoorBellRegister.All = @@ -3057,7 +3050,7 @@ void DAC960_BA_AcknowledgeInterrupt(void } static inline -boolean DAC960_BA_HardwareMailboxStatusAvailableP(void __iomem *ControllerBaseAddress) +bool DAC960_BA_HardwareMailboxStatusAvailableP(void __iomem *ControllerBaseAddress) { DAC960_BA_OutboundDoorBellRegister_T OutboundDoorBellRegister; OutboundDoorBellRegister.All = @@ -3066,7 +3059,7 @@ boolean DAC960_BA_HardwareMailboxStatusA } static inline -boolean DAC960_BA_MemoryMailboxStatusAvailableP(void __iomem *ControllerBaseAddress) +bool DAC960_BA_MemoryMailboxStatusAvailableP(void __iomem *ControllerBaseAddress) { DAC960_BA_OutboundDoorBellRegister_T OutboundDoorBellRegister; OutboundDoorBellRegister.All = @@ -3097,7 +3090,7 @@ void DAC960_BA_DisableInterrupts(void __ } static inline -boolean DAC960_BA_InterruptsEnabledP(void __iomem *ControllerBaseAddress) +bool DAC960_BA_InterruptsEnabledP(void __iomem *ControllerBaseAddress) { DAC960_BA_InterruptMaskRegister_T InterruptMaskRegister; InterruptMaskRegister.All = @@ -3140,7 +3133,7 @@ DAC960_BA_ReadCommandStatus(void __iomem return readw(ControllerBaseAddress + DAC960_BA_CommandStatusOffset + 2); } -static inline boolean +static inline bool DAC960_BA_ReadErrorStatus(void __iomem *ControllerBaseAddress, unsigned char *ErrorStatus, unsigned char *Parameter0, @@ -3188,16 +3181,16 @@ typedef union DAC960_LP_InboundDoorBellR { unsigned char All; struct { - boolean HardwareMailboxNewCommand:1; /* Bit 0 */ - boolean AcknowledgeHardwareMailboxStatus:1; /* Bit 1 */ - boolean GenerateInterrupt:1; /* Bit 2 */ - boolean ControllerReset:1; /* Bit 3 */ - boolean MemoryMailboxNewCommand:1; /* Bit 4 */ + bool HardwareMailboxNewCommand:1; /* Bit 0 */ + bool AcknowledgeHardwareMailboxStatus:1; /* Bit 1 */ + bool GenerateInterrupt:1; /* Bit 2 */ + bool ControllerReset:1; /* Bit 3 */ + bool MemoryMailboxNewCommand:1; /* Bit 4 */ unsigned char :3; /* Bits 5-7 */ } Write; struct { - boolean HardwareMailboxFull:1; /* Bit 0 */ - boolean InitializationInProgress:1; /* Bit 1 */ + bool HardwareMailboxFull:1; /* Bit 0 */ + bool InitializationInProgress:1; /* Bit 1 */ unsigned char :6; /* Bits 2-7 */ } Read; } @@ -3212,13 +3205,13 @@ typedef union DAC960_LP_OutboundDoorBell { unsigned char All; struct { - boolean AcknowledgeHardwareMailboxInterrupt:1; /* Bit 0 */ - boolean AcknowledgeMemoryMailboxInterrupt:1; /* Bit 1 */ + bool AcknowledgeHardwareMailboxInterrupt:1; /* Bit 0 */ + bool AcknowledgeMemoryMailboxInterrupt:1; /* Bit 1 */ unsigned char :6; /* Bits 2-7 */ } Write; struct { - boolean HardwareMailboxStatusAvailable:1; /* Bit 0 */ - boolean MemoryMailboxStatusAvailable:1; /* Bit 1 */ + bool HardwareMailboxStatusAvailable:1; /* Bit 0 */ + bool MemoryMailboxStatusAvailable:1; /* Bit 1 */ unsigned char :6; /* Bits 2-7 */ } Read; } @@ -3234,7 +3227,7 @@ typedef union DAC960_LP_InterruptMaskReg unsigned char All; struct { unsigned int :2; /* Bits 0-1 */ - boolean DisableInterrupts:1; /* Bit 2 */ + bool DisableInterrupts:1; /* Bit 2 */ unsigned int :5; /* Bits 3-7 */ } Bits; } @@ -3250,7 +3243,7 @@ typedef union DAC960_LP_ErrorStatusRegis unsigned char All; struct { unsigned int :2; /* Bits 0-1 */ - boolean ErrorStatusPending:1; /* Bit 2 */ + bool ErrorStatusPending:1; /* Bit 2 */ unsigned int :5; /* Bits 3-7 */ } Bits; } @@ -3313,7 +3306,7 @@ void DAC960_LP_MemoryMailboxNewCommand(v } static inline -boolean DAC960_LP_HardwareMailboxFullP(void __iomem *ControllerBaseAddress) +bool DAC960_LP_HardwareMailboxFullP(void __iomem *ControllerBaseAddress) { DAC960_LP_InboundDoorBellRegister_T InboundDoorBellRegister; InboundDoorBellRegister.All = @@ -3322,7 +3315,7 @@ boolean DAC960_LP_HardwareMailboxFullP(v } static inline -boolean DAC960_LP_InitializationInProgressP(void __iomem *ControllerBaseAddress) +bool DAC960_LP_InitializationInProgressP(void __iomem *ControllerBaseAddress) { DAC960_LP_InboundDoorBellRegister_T InboundDoorBellRegister; InboundDoorBellRegister.All = @@ -3362,7 +3355,7 @@ void DAC960_LP_AcknowledgeInterrupt(void } static inline -boolean DAC960_LP_HardwareMailboxStatusAvailableP(void __iomem *ControllerBaseAddress) +bool DAC960_LP_HardwareMailboxStatusAvailableP(void __iomem *ControllerBaseAddress) { DAC960_LP_OutboundDoorBellRegister_T OutboundDoorBellRegister; OutboundDoorBellRegister.All = @@ -3371,7 +3364,7 @@ boolean DAC960_LP_HardwareMailboxStatusA } static inline -boolean DAC960_LP_MemoryMailboxStatusAvailableP(void __iomem *ControllerBaseAddress) +bool DAC960_LP_MemoryMailboxStatusAvailableP(void __iomem *ControllerBaseAddress) { DAC960_LP_OutboundDoorBellRegister_T OutboundDoorBellRegister; OutboundDoorBellRegister.All = @@ -3400,7 +3393,7 @@ void DAC960_LP_DisableInterrupts(void __ } static inline -boolean DAC960_LP_InterruptsEnabledP(void __iomem *ControllerBaseAddress) +bool DAC960_LP_InterruptsEnabledP(void __iomem *ControllerBaseAddress) { DAC960_LP_InterruptMaskRegister_T InterruptMaskRegister; InterruptMaskRegister.All = @@ -3442,7 +3435,7 @@ DAC960_LP_ReadCommandStatus(void __iomem return readw(ControllerBaseAddress + DAC960_LP_CommandStatusOffset + 2); } -static inline boolean +static inline bool DAC960_LP_ReadErrorStatus(void __iomem *ControllerBaseAddress, unsigned char *ErrorStatus, unsigned char *Parameter0, @@ -3502,16 +3495,16 @@ typedef union DAC960_LA_InboundDoorBellR { unsigned char All; struct { - boolean HardwareMailboxNewCommand:1; /* Bit 0 */ - boolean AcknowledgeHardwareMailboxStatus:1; /* Bit 1 */ - boolean GenerateInterrupt:1; /* Bit 2 */ - boolean ControllerReset:1; /* Bit 3 */ - boolean MemoryMailboxNewCommand:1; /* Bit 4 */ + bool HardwareMailboxNewCommand:1; /* Bit 0 */ + bool AcknowledgeHardwareMailboxStatus:1; /* Bit 1 */ + bool GenerateInterrupt:1; /* Bit 2 */ + bool ControllerReset:1; /* Bit 3 */ + bool MemoryMailboxNewCommand:1; /* Bit 4 */ unsigned char :3; /* Bits 5-7 */ } Write; struct { - boolean HardwareMailboxEmpty:1; /* Bit 0 */ - boolean InitializationNotInProgress:1; /* Bit 1 */ + bool HardwareMailboxEmpty:1; /* Bit 0 */ + bool InitializationNotInProgress:1; /* Bit 1 */ unsigned char :6; /* Bits 2-7 */ } Read; } @@ -3526,13 +3519,13 @@ typedef union DAC960_LA_OutboundDoorBell { unsigned char All; struct { - boolean AcknowledgeHardwareMailboxInterrupt:1; /* Bit 0 */ - boolean AcknowledgeMemoryMailboxInterrupt:1; /* Bit 1 */ + bool AcknowledgeHardwareMailboxInterrupt:1; /* Bit 0 */ + bool AcknowledgeMemoryMailboxInterrupt:1; /* Bit 1 */ unsigned char :6; /* Bits 2-7 */ } Write; struct { - boolean HardwareMailboxStatusAvailable:1; /* Bit 0 */ - boolean MemoryMailboxStatusAvailable:1; /* Bit 1 */ + bool HardwareMailboxStatusAvailable:1; /* Bit 0 */ + bool MemoryMailboxStatusAvailable:1; /* Bit 1 */ unsigned char :6; /* Bits 2-7 */ } Read; } @@ -3548,7 +3541,7 @@ typedef union DAC960_LA_InterruptMaskReg unsigned char All; struct { unsigned char :2; /* Bits 0-1 */ - boolean DisableInterrupts:1; /* Bit 2 */ + bool DisableInterrupts:1; /* Bit 2 */ unsigned char :5; /* Bits 3-7 */ } Bits; } @@ -3564,7 +3557,7 @@ typedef union DAC960_LA_ErrorStatusRegis unsigned char All; struct { unsigned int :2; /* Bits 0-1 */ - boolean ErrorStatusPending:1; /* Bit 2 */ + bool ErrorStatusPending:1; /* Bit 2 */ unsigned int :5; /* Bits 3-7 */ } Bits; } @@ -3627,7 +3620,7 @@ void DAC960_LA_MemoryMailboxNewCommand(v } static inline -boolean DAC960_LA_HardwareMailboxFullP(void __iomem *ControllerBaseAddress) +bool DAC960_LA_HardwareMailboxFullP(void __iomem *ControllerBaseAddress) { DAC960_LA_InboundDoorBellRegister_T InboundDoorBellRegister; InboundDoorBellRegister.All = @@ -3636,7 +3629,7 @@ boolean DAC960_LA_HardwareMailboxFullP(v } static inline -boolean DAC960_LA_InitializationInProgressP(void __iomem *ControllerBaseAddress) +bool DAC960_LA_InitializationInProgressP(void __iomem *ControllerBaseAddress) { DAC960_LA_InboundDoorBellRegister_T InboundDoorBellRegister; InboundDoorBellRegister.All = @@ -3676,7 +3669,7 @@ void DAC960_LA_AcknowledgeInterrupt(void } static inline -boolean DAC960_LA_HardwareMailboxStatusAvailableP(void __iomem *ControllerBaseAddress) +bool DAC960_LA_HardwareMailboxStatusAvailableP(void __iomem *ControllerBaseAddress) { DAC960_LA_OutboundDoorBellRegister_T OutboundDoorBellRegister; OutboundDoorBellRegister.All = @@ -3685,7 +3678,7 @@ boolean DAC960_LA_HardwareMailboxStatusA } static inline -boolean DAC960_LA_MemoryMailboxStatusAvailableP(void __iomem *ControllerBaseAddress) +bool DAC960_LA_MemoryMailboxStatusAvailableP(void __iomem *ControllerBaseAddress) { DAC960_LA_OutboundDoorBellRegister_T OutboundDoorBellRegister; OutboundDoorBellRegister.All = @@ -3714,7 +3707,7 @@ void DAC960_LA_DisableInterrupts(void __ } static inline -boolean DAC960_LA_InterruptsEnabledP(void __iomem *ControllerBaseAddress) +bool DAC960_LA_InterruptsEnabledP(void __iomem *ControllerBaseAddress) { DAC960_LA_InterruptMaskRegister_T InterruptMaskRegister; InterruptMaskRegister.All = @@ -3763,7 +3756,7 @@ DAC960_LA_ReadStatusRegister(void __iome return readw(ControllerBaseAddress + DAC960_LA_StatusRegisterOffset); } -static inline boolean +static inline bool DAC960_LA_ReadErrorStatus(void __iomem *ControllerBaseAddress, unsigned char *ErrorStatus, unsigned char *Parameter0, @@ -3822,16 +3815,16 @@ typedef union DAC960_PG_InboundDoorBellR { unsigned int All; struct { - boolean HardwareMailboxNewCommand:1; /* Bit 0 */ - boolean AcknowledgeHardwareMailboxStatus:1; /* Bit 1 */ - boolean GenerateInterrupt:1; /* Bit 2 */ - boolean ControllerReset:1; /* Bit 3 */ - boolean MemoryMailboxNewCommand:1; /* Bit 4 */ + bool HardwareMailboxNewCommand:1; /* Bit 0 */ + bool AcknowledgeHardwareMailboxStatus:1; /* Bit 1 */ + bool GenerateInterrupt:1; /* Bit 2 */ + bool ControllerReset:1; /* Bit 3 */ + bool MemoryMailboxNewCommand:1; /* Bit 4 */ unsigned int :27; /* Bits 5-31 */ } Write; struct { - boolean HardwareMailboxFull:1; /* Bit 0 */ - boolean InitializationInProgress:1; /* Bit 1 */ + bool HardwareMailboxFull:1; /* Bit 0 */ + bool InitializationInProgress:1; /* Bit 1 */ unsigned int :30; /* Bits 2-31 */ } Read; } @@ -3846,13 +3839,13 @@ typedef union DAC960_PG_OutboundDoorBell { unsigned int All; struct { - boolean AcknowledgeHardwareMailboxInterrupt:1; /* Bit 0 */ - boolean AcknowledgeMemoryMailboxInterrupt:1; /* Bit 1 */ + bool AcknowledgeHardwareMailboxInterrupt:1; /* Bit 0 */ + bool AcknowledgeMemoryMailboxInterrupt:1; /* Bit 1 */ unsigned int :30; /* Bits 2-31 */ } Write; struct { - boolean HardwareMailboxStatusAvailable:1; /* Bit 0 */ - boolean MemoryMailboxStatusAvailable:1; /* Bit 1 */ + bool HardwareMailboxStatusAvailable:1; /* Bit 0 */ + bool MemoryMailboxStatusAvailable:1; /* Bit 1 */ unsigned int :30; /* Bits 2-31 */ } Read; } @@ -3868,7 +3861,7 @@ typedef union DAC960_PG_InterruptMaskReg unsigned int All; struct { unsigned int MessageUnitInterruptMask1:2; /* Bits 0-1 */ - boolean DisableInterrupts:1; /* Bit 2 */ + bool DisableInterrupts:1; /* Bit 2 */ unsigned int MessageUnitInterruptMask2:5; /* Bits 3-7 */ unsigned int Reserved0:24; /* Bits 8-31 */ } Bits; @@ -3885,7 +3878,7 @@ typedef union DAC960_PG_ErrorStatusRegis unsigned char All; struct { unsigned int :2; /* Bits 0-1 */ - boolean ErrorStatusPending:1; /* Bit 2 */ + bool ErrorStatusPending:1; /* Bit 2 */ unsigned int :5; /* Bits 3-7 */ } Bits; } @@ -3948,7 +3941,7 @@ void DAC960_PG_MemoryMailboxNewCommand(v } static inline -boolean DAC960_PG_HardwareMailboxFullP(void __iomem *ControllerBaseAddress) +bool DAC960_PG_HardwareMailboxFullP(void __iomem *ControllerBaseAddress) { DAC960_PG_InboundDoorBellRegister_T InboundDoorBellRegister; InboundDoorBellRegister.All = @@ -3957,7 +3950,7 @@ boolean DAC960_PG_HardwareMailboxFullP(v } static inline -boolean DAC960_PG_InitializationInProgressP(void __iomem *ControllerBaseAddress) +bool DAC960_PG_InitializationInProgressP(void __iomem *ControllerBaseAddress) { DAC960_PG_InboundDoorBellRegister_T InboundDoorBellRegister; InboundDoorBellRegister.All = @@ -3997,7 +3990,7 @@ void DAC960_PG_AcknowledgeInterrupt(void } static inline -boolean DAC960_PG_HardwareMailboxStatusAvailableP(void __iomem *ControllerBaseAddress) +bool DAC960_PG_HardwareMailboxStatusAvailableP(void __iomem *ControllerBaseAddress) { DAC960_PG_OutboundDoorBellRegister_T OutboundDoorBellRegister; OutboundDoorBellRegister.All = @@ -4006,7 +3999,7 @@ boolean DAC960_PG_HardwareMailboxStatusA } static inline -boolean DAC960_PG_MemoryMailboxStatusAvailableP(void __iomem *ControllerBaseAddress) +bool DAC960_PG_MemoryMailboxStatusAvailableP(void __iomem *ControllerBaseAddress) { DAC960_PG_OutboundDoorBellRegister_T OutboundDoorBellRegister; OutboundDoorBellRegister.All = @@ -4039,7 +4032,7 @@ void DAC960_PG_DisableInterrupts(void __ } static inline -boolean DAC960_PG_InterruptsEnabledP(void __iomem *ControllerBaseAddress) +bool DAC960_PG_InterruptsEnabledP(void __iomem *ControllerBaseAddress) { DAC960_PG_InterruptMaskRegister_T InterruptMaskRegister; InterruptMaskRegister.All = @@ -4088,7 +4081,7 @@ DAC960_PG_ReadStatusRegister(void __iome return readw(ControllerBaseAddress + DAC960_PG_StatusRegisterOffset); } -static inline boolean +static inline bool DAC960_PG_ReadErrorStatus(void __iomem *ControllerBaseAddress, unsigned char *ErrorStatus, unsigned char *Parameter0, @@ -4147,15 +4140,15 @@ typedef union DAC960_PD_InboundDoorBellR { unsigned char All; struct { - boolean NewCommand:1; /* Bit 0 */ - boolean AcknowledgeStatus:1; /* Bit 1 */ - boolean GenerateInterrupt:1; /* Bit 2 */ - boolean ControllerReset:1; /* Bit 3 */ + bool NewCommand:1; /* Bit 0 */ + bool AcknowledgeStatus:1; /* Bit 1 */ + bool GenerateInterrupt:1; /* Bit 2 */ + bool ControllerReset:1; /* Bit 3 */ unsigned char :4; /* Bits 4-7 */ } Write; struct { - boolean MailboxFull:1; /* Bit 0 */ - boolean InitializationInProgress:1; /* Bit 1 */ + bool MailboxFull:1; /* Bit 0 */ + bool InitializationInProgress:1; /* Bit 1 */ unsigned char :6; /* Bits 2-7 */ } Read; } @@ -4170,11 +4163,11 @@ typedef union DAC960_PD_OutboundDoorBell { unsigned char All; struct { - boolean AcknowledgeInterrupt:1; /* Bit 0 */ + bool AcknowledgeInterrupt:1; /* Bit 0 */ unsigned char :7; /* Bits 1-7 */ } Write; struct { - boolean StatusAvailable:1; /* Bit 0 */ + bool StatusAvailable:1; /* Bit 0 */ unsigned char :7; /* Bits 1-7 */ } Read; } @@ -4189,7 +4182,7 @@ typedef union DAC960_PD_InterruptEnableR { unsigned char All; struct { - boolean EnableInterrupts:1; /* Bit 0 */ + bool EnableInterrupts:1; /* Bit 0 */ unsigned char :7; /* Bits 1-7 */ } Bits; } @@ -4205,7 +4198,7 @@ typedef union DAC960_PD_ErrorStatusRegis unsigned char All; struct { unsigned int :2; /* Bits 0-1 */ - boolean ErrorStatusPending:1; /* Bit 2 */ + bool ErrorStatusPending:1; /* Bit 2 */ unsigned int :5; /* Bits 3-7 */ } Bits; } @@ -4258,7 +4251,7 @@ void DAC960_PD_ControllerReset(void __io } static inline -boolean DAC960_PD_MailboxFullP(void __iomem *ControllerBaseAddress) +bool DAC960_PD_MailboxFullP(void __iomem *ControllerBaseAddress) { DAC960_PD_InboundDoorBellRegister_T InboundDoorBellRegister; InboundDoorBellRegister.All = @@ -4267,7 +4260,7 @@ boolean DAC960_PD_MailboxFullP(void __io } static inline -boolean DAC960_PD_InitializationInProgressP(void __iomem *ControllerBaseAddress) +bool DAC960_PD_InitializationInProgressP(void __iomem *ControllerBaseAddress) { DAC960_PD_InboundDoorBellRegister_T InboundDoorBellRegister; InboundDoorBellRegister.All = @@ -4286,7 +4279,7 @@ void DAC960_PD_AcknowledgeInterrupt(void } static inline -boolean DAC960_PD_StatusAvailableP(void __iomem *ControllerBaseAddress) +bool DAC960_PD_StatusAvailableP(void __iomem *ControllerBaseAddress) { DAC960_PD_OutboundDoorBellRegister_T OutboundDoorBellRegister; OutboundDoorBellRegister.All = @@ -4315,7 +4308,7 @@ void DAC960_PD_DisableInterrupts(void __ } static inline -boolean DAC960_PD_InterruptsEnabledP(void __iomem *ControllerBaseAddress) +bool DAC960_PD_InterruptsEnabledP(void __iomem *ControllerBaseAddress) { DAC960_PD_InterruptEnableRegister_T InterruptEnableRegister; InterruptEnableRegister.All = @@ -4350,7 +4343,7 @@ DAC960_PD_ReadStatusRegister(void __iome return readw(ControllerBaseAddress + DAC960_PD_StatusRegisterOffset); } -static inline boolean +static inline bool DAC960_PD_ReadErrorStatus(void __iomem *ControllerBaseAddress, unsigned char *ErrorStatus, unsigned char *Parameter0, diff --git a/drivers/block/Kconfig b/drivers/block/Kconfig index 58c1deb..cacb1c8 100644 --- a/drivers/block/Kconfig +++ b/drivers/block/Kconfig @@ -417,8 +417,10 @@ config BLK_DEV_INITRD etc. See for details. If RAM disk support (BLK_DEV_RAM) is also included, this - also enables initial RAM disk (initrd) support. + also enables initial RAM disk (initrd) support and adds + 15 Kbytes (more on some other architectures) to the kernel size. + If unsure say Y. config CDROM_PKTCDVD tristate "Packet writing on CD/DVD media" diff --git a/drivers/block/acsi.c b/drivers/block/acsi.c index 706cdc6..e3d9152 100644 --- a/drivers/block/acsi.c +++ b/drivers/block/acsi.c @@ -46,7 +46,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/block/acsi_slm.c b/drivers/block/acsi_slm.c index e04be94..e2e0432 100644 --- a/drivers/block/acsi_slm.c +++ b/drivers/block/acsi_slm.c @@ -269,7 +269,7 @@ static int slm_get_pagesize( int device, static DEFINE_TIMER(slm_timer, slm_test_ready, 0, 0); -static struct file_operations slm_fops = { +static const struct file_operations slm_fops = { .owner = THIS_MODULE, .read = slm_read, .write = slm_write, diff --git a/drivers/block/aoe/aoechr.c b/drivers/block/aoe/aoechr.c index e22b4c9..39e563e 100644 --- a/drivers/block/aoe/aoechr.c +++ b/drivers/block/aoe/aoechr.c @@ -233,7 +233,7 @@ loop: } } -static struct file_operations aoe_fops = { +static const struct file_operations aoe_fops = { .write = aoechr_write, .read = aoechr_read, .open = aoechr_open, diff --git a/drivers/block/paride/Kconfig b/drivers/block/paride/Kconfig index c0d2854..28cf308 100644 --- a/drivers/block/paride/Kconfig +++ b/drivers/block/paride/Kconfig @@ -2,14 +2,8 @@ # # PARIDE configuration # # PARIDE doesn't need PARPORT, but if PARPORT is configured as a module, -# PARIDE must also be a module. The bogus CONFIG_PARIDE_PARPORT option -# controls the choices given to the user ... +# PARIDE must also be a module. # PARIDE only supports PC style parports. Tough for USB or other parports... -config PARIDE_PARPORT - tristate - depends on PARIDE!=n - default m if PARPORT_PC=m - default y if PARPORT_PC!=m comment "Parallel IDE high-level drivers" depends on PARIDE diff --git a/drivers/block/paride/pd.c b/drivers/block/paride/pd.c index 9d9bff2..99e2c8c 100644 --- a/drivers/block/paride/pd.c +++ b/drivers/block/paride/pd.c @@ -153,7 +153,6 @@ #include #include #include #include -#include #include static DEFINE_SPINLOCK(pd_lock); diff --git a/drivers/block/paride/pg.c b/drivers/block/paride/pg.c index 9970aed..d89e7d3 100644 --- a/drivers/block/paride/pg.c +++ b/drivers/block/paride/pg.c @@ -227,7 +227,7 @@ static struct class *pg_class; /* kernel glue structures */ -static struct file_operations pg_fops = { +static const struct file_operations pg_fops = { .owner = THIS_MODULE, .read = pg_read, .write = pg_write, diff --git a/drivers/block/paride/pt.c b/drivers/block/paride/pt.c index c902b25..9f4e67e 100644 --- a/drivers/block/paride/pt.c +++ b/drivers/block/paride/pt.c @@ -232,7 +232,7 @@ static char pt_scratch[512]; /* scratch /* kernel glue structures */ -static struct file_operations pt_fops = { +static const struct file_operations pt_fops = { .owner = THIS_MODULE, .read = pt_read, .write = pt_write, diff --git a/drivers/block/pktcdvd.c b/drivers/block/pktcdvd.c index 6246219..93fb6ed 100644 --- a/drivers/block/pktcdvd.c +++ b/drivers/block/pktcdvd.c @@ -190,15 +190,6 @@ static struct attribute *kobj_pkt_attrs_ NULL }; -/* declares a char buffer[64] _dbuf, copies data from - * _b with length _l into it and ensures that _dbuf ends - * with a \0 character. - */ -#define DECLARE_BUF_AS_STRING(_dbuf, _b, _l) \ - char _dbuf[64]; int dlen = (_l) < 0 ? 0 : (_l); \ - if (dlen >= sizeof(_dbuf)) dlen = sizeof(_dbuf)-1; \ - memcpy(_dbuf, _b, dlen); _dbuf[dlen] = 0 - static ssize_t kobj_pkt_show(struct kobject *kobj, struct attribute *attr, char *data) { @@ -264,9 +255,8 @@ static ssize_t kobj_pkt_store(struct kob { struct pktcdvd_device *pd = to_pktcdvdkobj(kobj)->pd; int val; - DECLARE_BUF_AS_STRING(dbuf, data, len); /* ensure sscanf scans a string */ - if (strcmp(attr->name, "reset") == 0 && dlen > 0) { + if (strcmp(attr->name, "reset") == 0 && len > 0) { pd->stats.pkt_started = 0; pd->stats.pkt_ended = 0; pd->stats.secs_w = 0; @@ -274,7 +264,7 @@ static ssize_t kobj_pkt_store(struct kob pd->stats.secs_r = 0; } else if (strcmp(attr->name, "congestion_off") == 0 - && sscanf(dbuf, "%d", &val) == 1) { + && sscanf(data, "%d", &val) == 1) { spin_lock(&pd->lock); pd->write_congestion_off = val; init_write_congestion_marks(&pd->write_congestion_off, @@ -282,7 +272,7 @@ static ssize_t kobj_pkt_store(struct kob spin_unlock(&pd->lock); } else if (strcmp(attr->name, "congestion_on") == 0 - && sscanf(dbuf, "%d", &val) == 1) { + && sscanf(data, "%d", &val) == 1) { spin_lock(&pd->lock); pd->write_congestion_on = val; init_write_congestion_marks(&pd->write_congestion_off, @@ -369,8 +359,7 @@ static ssize_t class_pktcdvd_store_add(s size_t count) { unsigned int major, minor; - DECLARE_BUF_AS_STRING(dbuf, buf, count); - if (sscanf(dbuf, "%u:%u", &major, &minor) == 2) { + if (sscanf(buf, "%u:%u", &major, &minor) == 2) { pkt_setup_dev(MKDEV(major, minor), NULL); return count; } @@ -381,8 +370,7 @@ static ssize_t class_pktcdvd_store_remov size_t count) { unsigned int major, minor; - DECLARE_BUF_AS_STRING(dbuf, buf, count); - if (sscanf(dbuf, "%u:%u", &major, &minor) == 2) { + if (sscanf(buf, "%u:%u", &major, &minor) == 2) { pkt_remove_dev(MKDEV(major, minor)); return count; } @@ -447,7 +435,7 @@ static int pkt_debugfs_fops_open(struct return single_open(file, pkt_debugfs_seq_show, inode->i_private); } -static struct file_operations debug_fops = { +static const struct file_operations debug_fops = { .open = pkt_debugfs_fops_open, .read = seq_read, .llseek = seq_lseek, @@ -1377,7 +1365,7 @@ try_next_bio: && pd->bio_queue_size <= pd->write_congestion_off); spin_unlock(&pd->lock); if (wakeup) - blk_clear_queue_congested(pd->disk->queue, WRITE); + clear_bdi_congested(&pd->disk->queue->backing_dev_info, WRITE); pkt->sleep_time = max(PACKET_WAIT_TIME, 1); pkt_set_state(pkt, PACKET_WAITING_STATE); @@ -2598,7 +2586,7 @@ static int pkt_make_request(request_queu spin_lock(&pd->lock); if (pd->write_congestion_on > 0 && pd->bio_queue_size >= pd->write_congestion_on) { - blk_set_queue_congested(q, WRITE); + set_bdi_congested(&q->backing_dev_info, WRITE); do { spin_unlock(&pd->lock); congestion_wait(WRITE, HZ); @@ -2737,7 +2725,7 @@ static int pkt_seq_open(struct inode *in return single_open(file, pkt_seq_show, PDE(inode)->data); } -static struct file_operations pkt_proc_fops = { +static const struct file_operations pkt_proc_fops = { .open = pkt_seq_open, .read = seq_read, .llseek = seq_lseek, @@ -3064,7 +3052,7 @@ static int pkt_ctl_ioctl(struct inode *i } -static struct file_operations pkt_ctl_fops = { +static const struct file_operations pkt_ctl_fops = { .ioctl = pkt_ctl_ioctl, .owner = THIS_MODULE, }; diff --git a/drivers/block/umem.c b/drivers/block/umem.c index 30f16bd..dff3766 100644 --- a/drivers/block/umem.c +++ b/drivers/block/umem.c @@ -35,7 +35,6 @@ */ //#define DEBUG /* uncomment if you want debugging info (pr_debug) */ -#include #include #include #include diff --git a/drivers/bluetooth/bfusb.c b/drivers/bluetooth/bfusb.c index 31ade99..27cceb6 100644 --- a/drivers/bluetooth/bfusb.c +++ b/drivers/bluetooth/bfusb.c @@ -27,7 +27,6 @@ #include #include #include #include -#include #include #include diff --git a/drivers/bluetooth/bt3c_cs.c b/drivers/bluetooth/bt3c_cs.c index aae3aba..34e5555 100644 --- a/drivers/bluetooth/bt3c_cs.c +++ b/drivers/bluetooth/bt3c_cs.c @@ -27,7 +27,6 @@ #include #include #include #include -#include #include #include #include diff --git a/drivers/bluetooth/btuart_cs.c b/drivers/bluetooth/btuart_cs.c index 92648ef..c1bce75 100644 --- a/drivers/bluetooth/btuart_cs.c +++ b/drivers/bluetooth/btuart_cs.c @@ -26,7 +26,6 @@ #include #include #include #include -#include #include #include #include diff --git a/drivers/bluetooth/dtl1_cs.c b/drivers/bluetooth/dtl1_cs.c index 77b99ee..459aa97 100644 --- a/drivers/bluetooth/dtl1_cs.c +++ b/drivers/bluetooth/dtl1_cs.c @@ -26,7 +26,6 @@ #include #include #include #include -#include #include #include #include diff --git a/drivers/bluetooth/hci_bcsp.c b/drivers/bluetooth/hci_bcsp.c index 5e2c318..d66064c 100644 --- a/drivers/bluetooth/hci_bcsp.c +++ b/drivers/bluetooth/hci_bcsp.c @@ -26,7 +26,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/bluetooth/hci_h4.c b/drivers/bluetooth/hci_h4.c index ad62abb..34f0afc 100644 --- a/drivers/bluetooth/hci_h4.c +++ b/drivers/bluetooth/hci_h4.c @@ -27,7 +27,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/bluetooth/hci_ldisc.c b/drivers/bluetooth/hci_ldisc.c index 420b645..0f4203b 100644 --- a/drivers/bluetooth/hci_ldisc.c +++ b/drivers/bluetooth/hci_ldisc.c @@ -27,7 +27,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/bluetooth/hci_usb.c b/drivers/bluetooth/hci_usb.c index 6bdf593..406af57 100644 --- a/drivers/bluetooth/hci_usb.c +++ b/drivers/bluetooth/hci_usb.c @@ -35,7 +35,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/bluetooth/hci_vhci.c b/drivers/bluetooth/hci_vhci.c index a278d98..b71a5cc 100644 --- a/drivers/bluetooth/hci_vhci.c +++ b/drivers/bluetooth/hci_vhci.c @@ -332,7 +332,7 @@ static int vhci_fasync(int fd, struct fi return 0; } -static struct file_operations vhci_fops = { +static const struct file_operations vhci_fops = { .owner = THIS_MODULE, .llseek = vhci_llseek, .read = vhci_read, diff --git a/drivers/cdrom/aztcd.c b/drivers/cdrom/aztcd.c index ec46949..1f9fb7a 100644 --- a/drivers/cdrom/aztcd.c +++ b/drivers/cdrom/aztcd.c @@ -170,7 +170,6 @@ #include "aztcd.h" #include #include -#include #include #include #include diff --git a/drivers/cdrom/cdrom.c b/drivers/cdrom/cdrom.c index 3105ddd..b36f44d 100644 --- a/drivers/cdrom/cdrom.c +++ b/drivers/cdrom/cdrom.c @@ -3553,9 +3553,7 @@ static void cdrom_sysctl_register(void) if (initialized == 1) return; - cdrom_sysctl_header = register_sysctl_table(cdrom_root_table, 1); - if (cdrom_root_table->ctl_name && cdrom_root_table->child->de) - cdrom_root_table->child->de->owner = THIS_MODULE; + cdrom_sysctl_header = register_sysctl_table(cdrom_root_table); /* set the defaults */ cdrom_sysctl_settings.autoclose = autoclose; diff --git a/drivers/cdrom/cm206.c b/drivers/cdrom/cm206.c index b6c61bb..2301311 100644 --- a/drivers/cdrom/cm206.c +++ b/drivers/cdrom/cm206.c @@ -183,7 +183,6 @@ #include #include /* These include what we really need */ #include #include -#include #include #include #include diff --git a/drivers/cdrom/gscd.c b/drivers/cdrom/gscd.c index fa70824..b3ab6e9 100644 --- a/drivers/cdrom/gscd.c +++ b/drivers/cdrom/gscd.c @@ -53,7 +53,6 @@ #include #include #include #include -#include #include #include #include diff --git a/drivers/cdrom/sjcd.c b/drivers/cdrom/sjcd.c index bf5aef4..5409fca 100644 --- a/drivers/cdrom/sjcd.c +++ b/drivers/cdrom/sjcd.c @@ -60,7 +60,6 @@ #define SJCD_VERSION_MINOR 7 #include #include -#include #include #include #include diff --git a/drivers/cdrom/viocd.c b/drivers/cdrom/viocd.c index 93fbf84..dc13eba 100644 --- a/drivers/cdrom/viocd.c +++ b/drivers/cdrom/viocd.c @@ -176,7 +176,7 @@ static int proc_viocd_open(struct inode return single_open(file, proc_viocd_show, NULL); } -static struct file_operations proc_viocd_operations = { +static const struct file_operations proc_viocd_operations = { .open = proc_viocd_open, .read = seq_read, .llseek = seq_lseek, diff --git a/drivers/char/Kconfig b/drivers/char/Kconfig index 9e43e39..d0a6dc5 100644 --- a/drivers/char/Kconfig +++ b/drivers/char/Kconfig @@ -191,7 +191,7 @@ config MOXA_INTELLIO module will be called moxa. config MOXA_SMARTIO - tristate "Moxa SmartIO support" + tristate "Moxa SmartIO support (OBSOLETE)" depends on SERIAL_NONSTANDARD help Say Y here if you have a Moxa SmartIO multiport serial card. @@ -202,7 +202,7 @@ config MOXA_SMARTIO here. config MOXA_SMARTIO_NEW - tristate "Moxa SmartIO support v. 2.0 (EXPERIMENTAL)" + tristate "Moxa SmartIO support v. 2.0" depends on SERIAL_NONSTANDARD && (PCI || EISA || ISA) help Say Y here if you have a Moxa SmartIO multiport serial card and/or @@ -610,6 +610,13 @@ config HVC_RTAS help IBM Console device driver which makes use of RTAS +config HVC_BEAT + bool "Toshiba's Beat Hypervisor Console support" + depends on PPC_CELLEB + select HVC_DRIVER + help + Toshiba's Cell Reference Set Beat Console device driver + config HVCS tristate "IBM Hypervisor Virtual Console Server support" depends on PPC_PSERIES diff --git a/drivers/char/Makefile b/drivers/char/Makefile index fc11063..ae8567c 100644 --- a/drivers/char/Makefile +++ b/drivers/char/Makefile @@ -45,6 +45,7 @@ obj-$(CONFIG_RIO) += rio/ generic_seria obj-$(CONFIG_HVC_CONSOLE) += hvc_vio.o hvsi.o obj-$(CONFIG_HVC_ISERIES) += hvc_iseries.o obj-$(CONFIG_HVC_RTAS) += hvc_rtas.o +obj-$(CONFIG_HVC_BEAT) += hvc_beat.o obj-$(CONFIG_HVC_DRIVER) += hvc_console.o obj-$(CONFIG_RAW_DRIVER) += raw.o obj-$(CONFIG_SGI_SNSC) += snsc.o snsc_event.o @@ -59,6 +60,8 @@ obj-$(CONFIG_BRIQ_PANEL) += briq_panel.o obj-$(CONFIG_PRINTER) += lp.o obj-$(CONFIG_TIPAR) += tipar.o +obj-$(CONFIG_APM_EMULATION) += apm-emulation.o + obj-$(CONFIG_DTLK) += dtlk.o obj-$(CONFIG_R3964) += n_r3964.o obj-$(CONFIG_APPLICOM) += applicom.o diff --git a/drivers/char/agp/Makefile b/drivers/char/agp/Makefile index 3e58160..a0d04a2 100644 --- a/drivers/char/agp/Makefile +++ b/drivers/char/agp/Makefile @@ -1,6 +1,7 @@ agpgart-y := backend.o frontend.o generic.o isoch.o obj-$(CONFIG_AGP) += agpgart.o +obj-$(CONFIG_COMPAT) += compat_ioctl.o obj-$(CONFIG_AGP_ALI) += ali-agp.o obj-$(CONFIG_AGP_ATI) += ati-agp.o obj-$(CONFIG_AGP_AMD) += amd-k7-agp.o diff --git a/drivers/char/agp/agp.h b/drivers/char/agp/agp.h index 1d59e2a..9bd68d9 100644 --- a/drivers/char/agp/agp.h +++ b/drivers/char/agp/agp.h @@ -114,6 +114,7 @@ struct agp_bridge_driver { void (*free_by_type)(struct agp_memory *); void *(*agp_alloc_page)(struct agp_bridge_data *); void (*agp_destroy_page)(void *); + int (*agp_type_to_mask_type) (struct agp_bridge_data *, int); }; struct agp_bridge_data { @@ -218,6 +219,7 @@ #define I810_PTE_BASE 0x10000 #define I810_PTE_MAIN_UNCACHED 0x00000000 #define I810_PTE_LOCAL 0x00000002 #define I810_PTE_VALID 0x00000001 +#define I830_PTE_SYSTEM_CACHED 0x00000006 #define I810_SMRAM_MISCC 0x70 #define I810_GFX_MEM_WIN_SIZE 0x00010000 #define I810_GFX_MEM_WIN_32M 0x00010000 @@ -270,8 +272,16 @@ void global_cache_flush(void); void get_agp_version(struct agp_bridge_data *bridge); unsigned long agp_generic_mask_memory(struct agp_bridge_data *bridge, unsigned long addr, int type); +int agp_generic_type_to_mask_type(struct agp_bridge_data *bridge, + int type); struct agp_bridge_data *agp_generic_find_bridge(struct pci_dev *pdev); +/* generic functions for user-populated AGP memory types */ +struct agp_memory *agp_generic_alloc_user(size_t page_count, int type); +void agp_alloc_page_array(size_t size, struct agp_memory *mem); +void agp_free_page_array(struct agp_memory *mem); + + /* generic routines for agp>=3 */ int agp3_generic_fetch_size(void); void agp3_generic_tlbflush(struct agp_memory *mem); @@ -288,6 +298,8 @@ #define gart_to_virt(x) (phys_to_virt(ga extern int agp_off; extern int agp_try_unsupported_boot; +long compat_agp_ioctl(struct file *file, unsigned int cmd, unsigned long arg); + /* Chipset independant registers (from AGP Spec) */ #define AGP_APBASE 0x10 diff --git a/drivers/char/agp/ali-agp.c b/drivers/char/agp/ali-agp.c index 5a31ec7..98177a9 100644 --- a/drivers/char/agp/ali-agp.c +++ b/drivers/char/agp/ali-agp.c @@ -214,6 +214,7 @@ static struct agp_bridge_driver ali_gene .free_by_type = agp_generic_free_by_type, .agp_alloc_page = agp_generic_alloc_page, .agp_destroy_page = ali_destroy_page, + .agp_type_to_mask_type = agp_generic_type_to_mask_type, }; static struct agp_bridge_driver ali_m1541_bridge = { @@ -237,6 +238,7 @@ static struct agp_bridge_driver ali_m154 .free_by_type = agp_generic_free_by_type, .agp_alloc_page = m1541_alloc_page, .agp_destroy_page = m1541_destroy_page, + .agp_type_to_mask_type = agp_generic_type_to_mask_type, }; diff --git a/drivers/char/agp/alpha-agp.c b/drivers/char/agp/alpha-agp.c index b4e00a3..b0acf41 100644 --- a/drivers/char/agp/alpha-agp.c +++ b/drivers/char/agp/alpha-agp.c @@ -91,6 +91,9 @@ static int alpha_core_agp_insert_memory( int num_entries, status; void *temp; + if (type >= AGP_USER_TYPES || mem->type >= AGP_USER_TYPES) + return -EINVAL; + temp = agp_bridge->current_size; num_entries = A_SIZE_FIX(temp)->num_entries; if ((pg_start + mem->page_count) > num_entries) @@ -142,6 +145,7 @@ struct agp_bridge_driver alpha_core_agp_ .free_by_type = agp_generic_free_by_type, .agp_alloc_page = agp_generic_alloc_page, .agp_destroy_page = agp_generic_destroy_page, + .agp_type_to_mask_type = agp_generic_type_to_mask_type, }; struct agp_bridge_data *alpha_bridge; diff --git a/drivers/char/agp/amd-k7-agp.c b/drivers/char/agp/amd-k7-agp.c index c85c8ca..3d8d448 100644 --- a/drivers/char/agp/amd-k7-agp.c +++ b/drivers/char/agp/amd-k7-agp.c @@ -381,6 +381,7 @@ static struct agp_bridge_driver amd_iron .free_by_type = agp_generic_free_by_type, .agp_alloc_page = agp_generic_alloc_page, .agp_destroy_page = agp_generic_destroy_page, + .agp_type_to_mask_type = agp_generic_type_to_mask_type, }; static struct agp_device_ids amd_agp_device_ids[] __devinitdata = diff --git a/drivers/char/agp/amd64-agp.c b/drivers/char/agp/amd64-agp.c index 93d2209..636d984 100644 --- a/drivers/char/agp/amd64-agp.c +++ b/drivers/char/agp/amd64-agp.c @@ -62,12 +62,18 @@ static int amd64_insert_memory(struct ag { int i, j, num_entries; long long tmp; + int mask_type; + struct agp_bridge_data *bridge = mem->bridge; u32 pte; num_entries = agp_num_entries(); - if (type != 0 || mem->type != 0) + if (type != mem->type) return -EINVAL; + mask_type = bridge->driver->agp_type_to_mask_type(bridge, type); + if (mask_type != 0) + return -EINVAL; + /* Make sure we can fit the range in the gatt table. */ /* FIXME: could wrap */ @@ -90,7 +96,7 @@ static int amd64_insert_memory(struct ag for (i = 0, j = pg_start; i < mem->page_count; i++, j++) { tmp = agp_bridge->driver->mask_memory(agp_bridge, - mem->memory[i], mem->type); + mem->memory[i], mask_type); BUG_ON(tmp & 0xffffff0000000ffcULL); pte = (tmp & 0x000000ff00000000ULL) >> 28; @@ -247,6 +253,7 @@ static struct agp_bridge_driver amd_8151 .free_by_type = agp_generic_free_by_type, .agp_alloc_page = agp_generic_alloc_page, .agp_destroy_page = agp_generic_destroy_page, + .agp_type_to_mask_type = agp_generic_type_to_mask_type, }; /* Some basic sanity checks for the aperture. */ diff --git a/drivers/char/agp/ati-agp.c b/drivers/char/agp/ati-agp.c index 9987dc2..77c9ad6 100644 --- a/drivers/char/agp/ati-agp.c +++ b/drivers/char/agp/ati-agp.c @@ -431,6 +431,7 @@ static struct agp_bridge_driver ati_gene .free_by_type = agp_generic_free_by_type, .agp_alloc_page = agp_generic_alloc_page, .agp_destroy_page = agp_generic_destroy_page, + .agp_type_to_mask_type = agp_generic_type_to_mask_type, }; diff --git a/drivers/char/agp/backend.c b/drivers/char/agp/backend.c index d59e037..ebdd6dd 100644 --- a/drivers/char/agp/backend.c +++ b/drivers/char/agp/backend.c @@ -43,7 +43,7 @@ #include "agp.h" * fix some real stupidity. It's only by chance we can bump * past 0.99 at all due to some boolean logic error. */ #define AGPGART_VERSION_MAJOR 0 -#define AGPGART_VERSION_MINOR 101 +#define AGPGART_VERSION_MINOR 102 static const struct agp_version agp_current_version = { .major = AGPGART_VERSION_MAJOR, diff --git a/drivers/char/agp/compat_ioctl.c b/drivers/char/agp/compat_ioctl.c new file mode 100644 index 0000000..fcb4b1b --- /dev/null +++ b/drivers/char/agp/compat_ioctl.c @@ -0,0 +1,282 @@ +/* + * AGPGART driver frontend compatibility ioctls + * Copyright (C) 2004 Silicon Graphics, Inc. + * Copyright (C) 2002-2003 Dave Jones + * Copyright (C) 1999 Jeff Hartmann + * Copyright (C) 1999 Precision Insight, Inc. + * Copyright (C) 1999 Xi Graphics, Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * JEFF HARTMANN, OR ANY OTHER CONTRIBUTORS BE LIABLE FOR ANY CLAIM, + * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR + * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE + * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + */ + +#include +#include +#include +#include +#include "agp.h" +#include "compat_ioctl.h" + +static int compat_agpioc_info_wrap(struct agp_file_private *priv, void __user *arg) +{ + struct agp_info32 userinfo; + struct agp_kern_info kerninfo; + + agp_copy_info(agp_bridge, &kerninfo); + + userinfo.version.major = kerninfo.version.major; + userinfo.version.minor = kerninfo.version.minor; + userinfo.bridge_id = kerninfo.device->vendor | + (kerninfo.device->device << 16); + userinfo.agp_mode = kerninfo.mode; + userinfo.aper_base = (compat_long_t)kerninfo.aper_base; + userinfo.aper_size = kerninfo.aper_size; + userinfo.pg_total = userinfo.pg_system = kerninfo.max_memory; + userinfo.pg_used = kerninfo.current_memory; + + if (copy_to_user(arg, &userinfo, sizeof(userinfo))) + return -EFAULT; + + return 0; +} + +static int compat_agpioc_reserve_wrap(struct agp_file_private *priv, void __user *arg) +{ + struct agp_region32 ureserve; + struct agp_region kreserve; + struct agp_client *client; + struct agp_file_private *client_priv; + + DBG(""); + if (copy_from_user(&ureserve, arg, sizeof(ureserve))) + return -EFAULT; + + if ((unsigned) ureserve.seg_count >= ~0U/sizeof(struct agp_segment32)) + return -EFAULT; + + kreserve.pid = ureserve.pid; + kreserve.seg_count = ureserve.seg_count; + + client = agp_find_client_by_pid(kreserve.pid); + + if (kreserve.seg_count == 0) { + /* remove a client */ + client_priv = agp_find_private(kreserve.pid); + + if (client_priv != NULL) { + set_bit(AGP_FF_IS_CLIENT, &client_priv->access_flags); + set_bit(AGP_FF_IS_VALID, &client_priv->access_flags); + } + if (client == NULL) { + /* client is already removed */ + return 0; + } + return agp_remove_client(kreserve.pid); + } else { + struct agp_segment32 *usegment; + struct agp_segment *ksegment; + int seg; + + if (ureserve.seg_count >= 16384) + return -EINVAL; + + usegment = kmalloc(sizeof(*usegment) * ureserve.seg_count, GFP_KERNEL); + if (!usegment) + return -ENOMEM; + + ksegment = kmalloc(sizeof(*ksegment) * kreserve.seg_count, GFP_KERNEL); + if (!ksegment) { + kfree(usegment); + return -ENOMEM; + } + + if (copy_from_user(usegment, (void __user *) ureserve.seg_list, + sizeof(*usegment) * ureserve.seg_count)) { + kfree(usegment); + kfree(ksegment); + return -EFAULT; + } + + for (seg = 0; seg < ureserve.seg_count; seg++) { + ksegment[seg].pg_start = usegment[seg].pg_start; + ksegment[seg].pg_count = usegment[seg].pg_count; + ksegment[seg].prot = usegment[seg].prot; + } + + kfree(usegment); + kreserve.seg_list = ksegment; + + if (client == NULL) { + /* Create the client and add the segment */ + client = agp_create_client(kreserve.pid); + + if (client == NULL) { + kfree(ksegment); + return -ENOMEM; + } + client_priv = agp_find_private(kreserve.pid); + + if (client_priv != NULL) { + set_bit(AGP_FF_IS_CLIENT, &client_priv->access_flags); + set_bit(AGP_FF_IS_VALID, &client_priv->access_flags); + } + } + return agp_create_segment(client, &kreserve); + } + /* Will never really happen */ + return -EINVAL; +} + +static int compat_agpioc_allocate_wrap(struct agp_file_private *priv, void __user *arg) +{ + struct agp_memory *memory; + struct agp_allocate32 alloc; + + DBG(""); + if (copy_from_user(&alloc, arg, sizeof(alloc))) + return -EFAULT; + + memory = agp_allocate_memory_wrap(alloc.pg_count, alloc.type); + + if (memory == NULL) + return -ENOMEM; + + alloc.key = memory->key; + alloc.physical = memory->physical; + + if (copy_to_user(arg, &alloc, sizeof(alloc))) { + agp_free_memory_wrap(memory); + return -EFAULT; + } + return 0; +} + +static int compat_agpioc_bind_wrap(struct agp_file_private *priv, void __user *arg) +{ + struct agp_bind32 bind_info; + struct agp_memory *memory; + + DBG(""); + if (copy_from_user(&bind_info, arg, sizeof(bind_info))) + return -EFAULT; + + memory = agp_find_mem_by_key(bind_info.key); + + if (memory == NULL) + return -EINVAL; + + return agp_bind_memory(memory, bind_info.pg_start); +} + +static int compat_agpioc_unbind_wrap(struct agp_file_private *priv, void __user *arg) +{ + struct agp_memory *memory; + struct agp_unbind32 unbind; + + DBG(""); + if (copy_from_user(&unbind, arg, sizeof(unbind))) + return -EFAULT; + + memory = agp_find_mem_by_key(unbind.key); + + if (memory == NULL) + return -EINVAL; + + return agp_unbind_memory(memory); +} + +long compat_agp_ioctl(struct file *file, unsigned int cmd, unsigned long arg) +{ + struct agp_file_private *curr_priv = file->private_data; + int ret_val = -ENOTTY; + + mutex_lock(&(agp_fe.agp_mutex)); + + if ((agp_fe.current_controller == NULL) && + (cmd != AGPIOC_ACQUIRE32)) { + ret_val = -EINVAL; + goto ioctl_out; + } + if ((agp_fe.backend_acquired != TRUE) && + (cmd != AGPIOC_ACQUIRE32)) { + ret_val = -EBUSY; + goto ioctl_out; + } + if (cmd != AGPIOC_ACQUIRE32) { + if (!(test_bit(AGP_FF_IS_CONTROLLER, &curr_priv->access_flags))) { + ret_val = -EPERM; + goto ioctl_out; + } + /* Use the original pid of the controller, + * in case it's threaded */ + + if (agp_fe.current_controller->pid != curr_priv->my_pid) { + ret_val = -EBUSY; + goto ioctl_out; + } + } + + switch (cmd) { + case AGPIOC_INFO32: + ret_val = compat_agpioc_info_wrap(curr_priv, (void __user *) arg); + break; + + case AGPIOC_ACQUIRE32: + ret_val = agpioc_acquire_wrap(curr_priv); + break; + + case AGPIOC_RELEASE32: + ret_val = agpioc_release_wrap(curr_priv); + break; + + case AGPIOC_SETUP32: + ret_val = agpioc_setup_wrap(curr_priv, (void __user *) arg); + break; + + case AGPIOC_RESERVE32: + ret_val = compat_agpioc_reserve_wrap(curr_priv, (void __user *) arg); + break; + + case AGPIOC_PROTECT32: + ret_val = agpioc_protect_wrap(curr_priv); + break; + + case AGPIOC_ALLOCATE32: + ret_val = compat_agpioc_allocate_wrap(curr_priv, (void __user *) arg); + break; + + case AGPIOC_DEALLOCATE32: + ret_val = agpioc_deallocate_wrap(curr_priv, (int) arg); + break; + + case AGPIOC_BIND32: + ret_val = compat_agpioc_bind_wrap(curr_priv, (void __user *) arg); + break; + + case AGPIOC_UNBIND32: + ret_val = compat_agpioc_unbind_wrap(curr_priv, (void __user *) arg); + break; + } + +ioctl_out: + DBG("ioctl returns %d\n", ret_val); + mutex_unlock(&(agp_fe.agp_mutex)); + return ret_val; +} + diff --git a/drivers/char/agp/compat_ioctl.h b/drivers/char/agp/compat_ioctl.h new file mode 100644 index 0000000..71939d6 --- /dev/null +++ b/drivers/char/agp/compat_ioctl.h @@ -0,0 +1,105 @@ +/* + * Copyright (C) 1999 Jeff Hartmann + * Copyright (C) 1999 Precision Insight, Inc. + * Copyright (C) 1999 Xi Graphics, Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * JEFF HARTMANN, OR ANY OTHER CONTRIBUTORS BE LIABLE FOR ANY CLAIM, + * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR + * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE + * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + */ + +#ifndef _AGP_COMPAT_IOCTL_H +#define _AGP_COMPAT_IOCTL_H + +#include +#include + +#define AGPIOC_INFO32 _IOR (AGPIOC_BASE, 0, compat_uptr_t) +#define AGPIOC_ACQUIRE32 _IO (AGPIOC_BASE, 1) +#define AGPIOC_RELEASE32 _IO (AGPIOC_BASE, 2) +#define AGPIOC_SETUP32 _IOW (AGPIOC_BASE, 3, compat_uptr_t) +#define AGPIOC_RESERVE32 _IOW (AGPIOC_BASE, 4, compat_uptr_t) +#define AGPIOC_PROTECT32 _IOW (AGPIOC_BASE, 5, compat_uptr_t) +#define AGPIOC_ALLOCATE32 _IOWR(AGPIOC_BASE, 6, compat_uptr_t) +#define AGPIOC_DEALLOCATE32 _IOW (AGPIOC_BASE, 7, compat_int_t) +#define AGPIOC_BIND32 _IOW (AGPIOC_BASE, 8, compat_uptr_t) +#define AGPIOC_UNBIND32 _IOW (AGPIOC_BASE, 9, compat_uptr_t) + +struct agp_info32 { + struct agp_version version; /* version of the driver */ + u32 bridge_id; /* bridge vendor/device */ + u32 agp_mode; /* mode info of bridge */ + compat_long_t aper_base; /* base of aperture */ + compat_size_t aper_size; /* size of aperture */ + compat_size_t pg_total; /* max pages (swap + system) */ + compat_size_t pg_system; /* max pages (system) */ + compat_size_t pg_used; /* current pages used */ +}; + +/* + * The "prot" down below needs still a "sleep" flag somehow ... + */ +struct agp_segment32 { + compat_off_t pg_start; /* starting page to populate */ + compat_size_t pg_count; /* number of pages */ + compat_int_t prot; /* prot flags for mmap */ +}; + +struct agp_region32 { + compat_pid_t pid; /* pid of process */ + compat_size_t seg_count; /* number of segments */ + struct agp_segment32 *seg_list; +}; + +struct agp_allocate32 { + compat_int_t key; /* tag of allocation */ + compat_size_t pg_count; /* number of pages */ + u32 type; /* 0 == normal, other devspec */ + u32 physical; /* device specific (some devices + * need a phys address of the + * actual page behind the gatt + * table) */ +}; + +struct agp_bind32 { + compat_int_t key; /* tag of allocation */ + compat_off_t pg_start; /* starting page to populate */ +}; + +struct agp_unbind32 { + compat_int_t key; /* tag of allocation */ + u32 priority; /* priority for paging out */ +}; + +extern struct agp_front_data agp_fe; + +int agpioc_acquire_wrap(struct agp_file_private *priv); +int agpioc_release_wrap(struct agp_file_private *priv); +int agpioc_protect_wrap(struct agp_file_private *priv); +int agpioc_setup_wrap(struct agp_file_private *priv, void __user *arg); +int agpioc_deallocate_wrap(struct agp_file_private *priv, int arg); +struct agp_file_private *agp_find_private(pid_t pid); +struct agp_client *agp_create_client(pid_t id); +int agp_remove_client(pid_t id); +int agp_create_segment(struct agp_client *client, struct agp_region *region); +void agp_free_memory_wrap(struct agp_memory *memory); +struct agp_memory *agp_allocate_memory_wrap(size_t pg_count, u32 type); +struct agp_memory *agp_find_mem_by_key(int key); +struct agp_client *agp_find_client_by_pid(pid_t id); + +#endif /* _AGP_COMPAT_H */ diff --git a/drivers/char/agp/efficeon-agp.c b/drivers/char/agp/efficeon-agp.c index 30f730f..658cb1a 100644 --- a/drivers/char/agp/efficeon-agp.c +++ b/drivers/char/agp/efficeon-agp.c @@ -335,6 +335,7 @@ static struct agp_bridge_driver efficeon .free_by_type = agp_generic_free_by_type, .agp_alloc_page = agp_generic_alloc_page, .agp_destroy_page = agp_generic_destroy_page, + .agp_type_to_mask_type = agp_generic_type_to_mask_type, }; static int __devinit agp_efficeon_probe(struct pci_dev *pdev, diff --git a/drivers/char/agp/frontend.c b/drivers/char/agp/frontend.c index 0f2ed2a..679d7f9 100644 --- a/drivers/char/agp/frontend.c +++ b/drivers/char/agp/frontend.c @@ -41,9 +41,9 @@ #include #include #include "agp.h" -static struct agp_front_data agp_fe; +struct agp_front_data agp_fe; -static struct agp_memory *agp_find_mem_by_key(int key) +struct agp_memory *agp_find_mem_by_key(int key) { struct agp_memory *curr; @@ -159,7 +159,7 @@ static pgprot_t agp_convert_mmap_flags(i return vm_get_page_prot(prot_bits); } -static int agp_create_segment(struct agp_client *client, struct agp_region *region) +int agp_create_segment(struct agp_client *client, struct agp_region *region) { struct agp_segment_priv **ret_seg; struct agp_segment_priv *seg; @@ -211,7 +211,7 @@ static void agp_insert_into_pool(struct /* File private list routines */ -static struct agp_file_private *agp_find_private(pid_t pid) +struct agp_file_private *agp_find_private(pid_t pid) { struct agp_file_private *curr; @@ -266,13 +266,13 @@ static void agp_remove_file_private(stru * Wrappers for agp_free_memory & agp_allocate_memory * These make sure that internal lists are kept updated. */ -static void agp_free_memory_wrap(struct agp_memory *memory) +void agp_free_memory_wrap(struct agp_memory *memory) { agp_remove_from_pool(memory); agp_free_memory(memory); } -static struct agp_memory *agp_allocate_memory_wrap(size_t pg_count, u32 type) +struct agp_memory *agp_allocate_memory_wrap(size_t pg_count, u32 type) { struct agp_memory *memory; @@ -484,7 +484,7 @@ static struct agp_controller *agp_find_c return NULL; } -static struct agp_client *agp_find_client_by_pid(pid_t id) +struct agp_client *agp_find_client_by_pid(pid_t id) { struct agp_client *temp; @@ -509,7 +509,7 @@ static void agp_insert_client(struct agp agp_fe.current_controller->num_clients++; } -static struct agp_client *agp_create_client(pid_t id) +struct agp_client *agp_create_client(pid_t id) { struct agp_client *new_client; @@ -522,7 +522,7 @@ static struct agp_client *agp_create_cli return new_client; } -static int agp_remove_client(pid_t id) +int agp_remove_client(pid_t id) { struct agp_client *client; struct agp_client *prev_client; @@ -746,7 +746,7 @@ static int agpioc_info_wrap(struct agp_f return 0; } -static int agpioc_acquire_wrap(struct agp_file_private *priv) +int agpioc_acquire_wrap(struct agp_file_private *priv) { struct agp_controller *controller; @@ -789,14 +789,14 @@ static int agpioc_acquire_wrap(struct ag return 0; } -static int agpioc_release_wrap(struct agp_file_private *priv) +int agpioc_release_wrap(struct agp_file_private *priv) { DBG(""); agp_controller_release_current(agp_fe.current_controller, priv); return 0; } -static int agpioc_setup_wrap(struct agp_file_private *priv, void __user *arg) +int agpioc_setup_wrap(struct agp_file_private *priv, void __user *arg) { struct agp_setup mode; @@ -876,7 +876,7 @@ static int agpioc_reserve_wrap(struct ag return -EINVAL; } -static int agpioc_protect_wrap(struct agp_file_private *priv) +int agpioc_protect_wrap(struct agp_file_private *priv) { DBG(""); /* This function is not currently implemented */ @@ -892,6 +892,9 @@ static int agpioc_allocate_wrap(struct a if (copy_from_user(&alloc, arg, sizeof(struct agp_allocate))) return -EFAULT; + if (alloc.type >= AGP_USER_TYPES) + return -EINVAL; + memory = agp_allocate_memory_wrap(alloc.pg_count, alloc.type); if (memory == NULL) @@ -907,7 +910,7 @@ static int agpioc_allocate_wrap(struct a return 0; } -static int agpioc_deallocate_wrap(struct agp_file_private *priv, int arg) +int agpioc_deallocate_wrap(struct agp_file_private *priv, int arg) { struct agp_memory *memory; @@ -1043,6 +1046,9 @@ static const struct file_operations agp_ .read = agp_read, .write = agp_write, .ioctl = agp_ioctl, +#ifdef CONFIG_COMPAT + .compat_ioctl = compat_agp_ioctl, +#endif .mmap = agp_mmap, .open = agp_open, .release = agp_release, diff --git a/drivers/char/agp/generic.c b/drivers/char/agp/generic.c index 3491d6f..7923337 100644 --- a/drivers/char/agp/generic.c +++ b/drivers/char/agp/generic.c @@ -101,6 +101,63 @@ static int agp_get_key(void) return -1; } +/* + * Use kmalloc if possible for the page list. Otherwise fall back to + * vmalloc. This speeds things up and also saves memory for small AGP + * regions. + */ + +void agp_alloc_page_array(size_t size, struct agp_memory *mem) +{ + mem->memory = NULL; + mem->vmalloc_flag = 0; + + if (size <= 2*PAGE_SIZE) + mem->memory = kmalloc(size, GFP_KERNEL | __GFP_NORETRY); + if (mem->memory == NULL) { + mem->memory = vmalloc(size); + mem->vmalloc_flag = 1; + } +} +EXPORT_SYMBOL(agp_alloc_page_array); + +void agp_free_page_array(struct agp_memory *mem) +{ + if (mem->vmalloc_flag) { + vfree(mem->memory); + } else { + kfree(mem->memory); + } +} +EXPORT_SYMBOL(agp_free_page_array); + + +static struct agp_memory *agp_create_user_memory(unsigned long num_agp_pages) +{ + struct agp_memory *new; + unsigned long alloc_size = num_agp_pages*sizeof(struct page *); + + new = kzalloc(sizeof(struct agp_memory), GFP_KERNEL); + if (new == NULL) + return NULL; + + new->key = agp_get_key(); + + if (new->key < 0) { + kfree(new); + return NULL; + } + + agp_alloc_page_array(alloc_size, new); + + if (new->memory == NULL) { + agp_free_key(new->key); + kfree(new); + return NULL; + } + new->num_scratch_pages = 0; + return new; +} struct agp_memory *agp_create_memory(int scratch_pages) { @@ -116,7 +173,8 @@ struct agp_memory *agp_create_memory(int kfree(new); return NULL; } - new->memory = vmalloc(PAGE_SIZE * scratch_pages); + + agp_alloc_page_array(PAGE_SIZE * scratch_pages, new); if (new->memory == NULL) { agp_free_key(new->key); @@ -124,6 +182,7 @@ struct agp_memory *agp_create_memory(int return NULL; } new->num_scratch_pages = scratch_pages; + new->type = AGP_NORMAL_MEMORY; return new; } EXPORT_SYMBOL(agp_create_memory); @@ -146,6 +205,11 @@ void agp_free_memory(struct agp_memory * if (curr->is_bound == TRUE) agp_unbind_memory(curr); + if (curr->type >= AGP_USER_TYPES) { + agp_generic_free_by_type(curr); + return; + } + if (curr->type != 0) { curr->bridge->driver->free_by_type(curr); return; @@ -157,7 +221,7 @@ void agp_free_memory(struct agp_memory * flush_agp_mappings(); } agp_free_key(curr->key); - vfree(curr->memory); + agp_free_page_array(curr); kfree(curr); } EXPORT_SYMBOL(agp_free_memory); @@ -188,6 +252,13 @@ struct agp_memory *agp_allocate_memory(s if ((atomic_read(&bridge->current_memory_agp) + page_count) > bridge->max_memory_agp) return NULL; + if (type >= AGP_USER_TYPES) { + new = agp_generic_alloc_user(page_count, type); + if (new) + new->bridge = bridge; + return new; + } + if (type != 0) { new = bridge->driver->alloc_by_type(page_count, type); if (new) @@ -960,6 +1031,7 @@ int agp_generic_insert_memory(struct agp off_t j; void *temp; struct agp_bridge_data *bridge; + int mask_type; bridge = mem->bridge; if (!bridge) @@ -995,7 +1067,11 @@ int agp_generic_insert_memory(struct agp num_entries -= agp_memory_reserved/PAGE_SIZE; if (num_entries < 0) num_entries = 0; - if (type != 0 || mem->type != 0) { + if (type != mem->type) + return -EINVAL; + + mask_type = bridge->driver->agp_type_to_mask_type(bridge, type); + if (mask_type != 0) { /* The generic routines know nothing of memory types */ return -EINVAL; } @@ -1018,7 +1094,8 @@ int agp_generic_insert_memory(struct agp } for (i = 0, j = pg_start; i < mem->page_count; i++, j++) { - writel(bridge->driver->mask_memory(bridge, mem->memory[i], mem->type), bridge->gatt_table+j); + writel(bridge->driver->mask_memory(bridge, mem->memory[i], mask_type), + bridge->gatt_table+j); } readl(bridge->gatt_table+j-1); /* PCI Posting. */ @@ -1032,6 +1109,7 @@ int agp_generic_remove_memory(struct agp { size_t i; struct agp_bridge_data *bridge; + int mask_type; bridge = mem->bridge; if (!bridge) @@ -1040,7 +1118,11 @@ int agp_generic_remove_memory(struct agp if (mem->page_count == 0) return 0; - if (type != 0 || mem->type != 0) { + if (type != mem->type) + return -EINVAL; + + mask_type = bridge->driver->agp_type_to_mask_type(bridge, type); + if (mask_type != 0) { /* The generic routines know nothing of memory types */ return -EINVAL; } @@ -1056,22 +1138,40 @@ int agp_generic_remove_memory(struct agp } EXPORT_SYMBOL(agp_generic_remove_memory); - struct agp_memory *agp_generic_alloc_by_type(size_t page_count, int type) { return NULL; } EXPORT_SYMBOL(agp_generic_alloc_by_type); - void agp_generic_free_by_type(struct agp_memory *curr) { - vfree(curr->memory); + agp_free_page_array(curr); agp_free_key(curr->key); kfree(curr); } EXPORT_SYMBOL(agp_generic_free_by_type); +struct agp_memory *agp_generic_alloc_user(size_t page_count, int type) +{ + struct agp_memory *new; + int i; + int pages; + + pages = (page_count + ENTRIES_PER_PAGE - 1) / ENTRIES_PER_PAGE; + new = agp_create_user_memory(page_count); + if (new == NULL) + return NULL; + + for (i = 0; i < page_count; i++) + new->memory[i] = 0; + new->page_count = 0; + new->type = type; + new->num_scratch_pages = pages; + + return new; +} +EXPORT_SYMBOL(agp_generic_alloc_user); /* * Basic Page Allocation Routines - @@ -1165,6 +1265,15 @@ unsigned long agp_generic_mask_memory(st } EXPORT_SYMBOL(agp_generic_mask_memory); +int agp_generic_type_to_mask_type(struct agp_bridge_data *bridge, + int type) +{ + if (type >= AGP_USER_TYPES) + return 0; + return type; +} +EXPORT_SYMBOL(agp_generic_type_to_mask_type); + /* * These functions are implemented according to the AGPv3 spec, * which covers implementation details that had previously been diff --git a/drivers/char/agp/hp-agp.c b/drivers/char/agp/hp-agp.c index 907fb66..847deab 100644 --- a/drivers/char/agp/hp-agp.c +++ b/drivers/char/agp/hp-agp.c @@ -438,6 +438,7 @@ struct agp_bridge_driver hp_zx1_driver = .free_by_type = agp_generic_free_by_type, .agp_alloc_page = agp_generic_alloc_page, .agp_destroy_page = agp_generic_destroy_page, + .agp_type_to_mask_type = agp_generic_type_to_mask_type, .cant_use_aperture = 1, }; diff --git a/drivers/char/agp/i460-agp.c b/drivers/char/agp/i460-agp.c index 9176944..3e76186 100644 --- a/drivers/char/agp/i460-agp.c +++ b/drivers/char/agp/i460-agp.c @@ -293,6 +293,9 @@ static int i460_insert_memory_small_io_p pr_debug("i460_insert_memory_small_io_page(mem=%p, pg_start=%ld, type=%d, paddr0=0x%lx)\n", mem, pg_start, type, mem->memory[0]); + if (type >= AGP_USER_TYPES || mem->type >= AGP_USER_TYPES) + return -EINVAL; + io_pg_start = I460_IOPAGES_PER_KPAGE * pg_start; temp = agp_bridge->current_size; @@ -396,6 +399,9 @@ static int i460_insert_memory_large_io_p struct lp_desc *start, *end, *lp; void *temp; + if (type >= AGP_USER_TYPES || mem->type >= AGP_USER_TYPES) + return -EINVAL; + temp = agp_bridge->current_size; num_entries = A_SIZE_8(temp)->num_entries; @@ -572,6 +578,7 @@ #else #endif .alloc_by_type = agp_generic_alloc_by_type, .free_by_type = agp_generic_free_by_type, + .agp_type_to_mask_type = agp_generic_type_to_mask_type, .cant_use_aperture = 1, }; diff --git a/drivers/char/agp/intel-agp.c b/drivers/char/agp/intel-agp.c index a3011de..06b0bb6 100644 --- a/drivers/char/agp/intel-agp.c +++ b/drivers/char/agp/intel-agp.c @@ -5,6 +5,7 @@ #include #include #include +#include #include #include #include "agp.h" @@ -24,6 +25,9 @@ #define IS_I965 (agp_bridge->dev->device agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_82965G_HB) +extern int agp_memory_reserved; + + /* Intel 815 register */ #define INTEL_815_APCONT 0x51 #define INTEL_815_ATTBASE_MASK ~0x1FFFFFFF @@ -68,12 +72,15 @@ static struct aper_size_info_fixed intel #define AGP_DCACHE_MEMORY 1 #define AGP_PHYS_MEMORY 2 +#define INTEL_AGP_CACHED_MEMORY 3 static struct gatt_mask intel_i810_masks[] = { {.mask = I810_PTE_VALID, .type = 0}, {.mask = (I810_PTE_VALID | I810_PTE_LOCAL), .type = AGP_DCACHE_MEMORY}, - {.mask = I810_PTE_VALID, .type = 0} + {.mask = I810_PTE_VALID, .type = 0}, + {.mask = I810_PTE_VALID | I830_PTE_SYSTEM_CACHED, + .type = INTEL_AGP_CACHED_MEMORY} }; static struct _intel_i810_private { @@ -117,13 +124,15 @@ static int intel_i810_configure(void) current_size = A_SIZE_FIX(agp_bridge->current_size); - pci_read_config_dword(intel_i810_private.i810_dev, I810_MMADDR, &temp); - temp &= 0xfff80000; - - intel_i810_private.registers = ioremap(temp, 128 * 4096); if (!intel_i810_private.registers) { - printk(KERN_ERR PFX "Unable to remap memory.\n"); - return -ENOMEM; + pci_read_config_dword(intel_i810_private.i810_dev, I810_MMADDR, &temp); + temp &= 0xfff80000; + + intel_i810_private.registers = ioremap(temp, 128 * 4096); + if (!intel_i810_private.registers) { + printk(KERN_ERR PFX "Unable to remap memory.\n"); + return -ENOMEM; + } } if ((readl(intel_i810_private.registers+I810_DRAM_CTL) @@ -201,62 +210,79 @@ static void i8xx_destroy_pages(void *add atomic_dec(&agp_bridge->current_memory_agp); } +static int intel_i830_type_to_mask_type(struct agp_bridge_data *bridge, + int type) +{ + if (type < AGP_USER_TYPES) + return type; + else if (type == AGP_USER_CACHED_MEMORY) + return INTEL_AGP_CACHED_MEMORY; + else + return 0; +} + static int intel_i810_insert_entries(struct agp_memory *mem, off_t pg_start, int type) { int i, j, num_entries; void *temp; + int ret = -EINVAL; + int mask_type; if (mem->page_count == 0) - return 0; + goto out; temp = agp_bridge->current_size; num_entries = A_SIZE_FIX(temp)->num_entries; if ((pg_start + mem->page_count) > num_entries) - return -EINVAL; + goto out_err; - for (j = pg_start; j < (pg_start + mem->page_count); j++) { - if (!PGE_EMPTY(agp_bridge, readl(agp_bridge->gatt_table+j))) - return -EBUSY; - } - if (type != 0 || mem->type != 0) { - if ((type == AGP_DCACHE_MEMORY) && (mem->type == AGP_DCACHE_MEMORY)) { - /* special insert */ - if (!mem->is_flushed) { - global_cache_flush(); - mem->is_flushed = TRUE; - } - - for (i = pg_start; i < (pg_start + mem->page_count); i++) { - writel((i*4096)|I810_PTE_LOCAL|I810_PTE_VALID, intel_i810_private.registers+I810_PTE_BASE+(i*4)); - } - readl(intel_i810_private.registers+I810_PTE_BASE+((i-1)*4)); /* PCI Posting. */ - - agp_bridge->driver->tlb_flush(mem); - return 0; + for (j = pg_start; j < (pg_start + mem->page_count); j++) { + if (!PGE_EMPTY(agp_bridge, readl(agp_bridge->gatt_table+j))) { + ret = -EBUSY; + goto out_err; } - if ((type == AGP_PHYS_MEMORY) && (mem->type == AGP_PHYS_MEMORY)) - goto insert; - return -EINVAL; } -insert: - if (!mem->is_flushed) { - global_cache_flush(); - mem->is_flushed = TRUE; - } + if (type != mem->type) + goto out_err; - for (i = 0, j = pg_start; i < mem->page_count; i++, j++) { - writel(agp_bridge->driver->mask_memory(agp_bridge, - mem->memory[i], mem->type), - intel_i810_private.registers+I810_PTE_BASE+(j*4)); + mask_type = agp_bridge->driver->agp_type_to_mask_type(agp_bridge, type); + + switch (mask_type) { + case AGP_DCACHE_MEMORY: + if (!mem->is_flushed) + global_cache_flush(); + for (i = pg_start; i < (pg_start + mem->page_count); i++) { + writel((i*4096)|I810_PTE_LOCAL|I810_PTE_VALID, + intel_i810_private.registers+I810_PTE_BASE+(i*4)); + } + readl(intel_i810_private.registers+I810_PTE_BASE+((i-1)*4)); + break; + case AGP_PHYS_MEMORY: + case AGP_NORMAL_MEMORY: + if (!mem->is_flushed) + global_cache_flush(); + for (i = 0, j = pg_start; i < mem->page_count; i++, j++) { + writel(agp_bridge->driver->mask_memory(agp_bridge, + mem->memory[i], + mask_type), + intel_i810_private.registers+I810_PTE_BASE+(j*4)); + } + readl(intel_i810_private.registers+I810_PTE_BASE+((j-1)*4)); + break; + default: + goto out_err; } - readl(intel_i810_private.registers+I810_PTE_BASE+((j-1)*4)); /* PCI Posting. */ agp_bridge->driver->tlb_flush(mem); - return 0; +out: + ret = 0; +out_err: + mem->is_flushed = 1; + return ret; } static int intel_i810_remove_entries(struct agp_memory *mem, off_t pg_start, @@ -337,12 +363,11 @@ static struct agp_memory *intel_i810_all new->type = AGP_DCACHE_MEMORY; new->page_count = pg_count; new->num_scratch_pages = 0; - vfree(new->memory); + agp_free_page_array(new); return new; } if (type == AGP_PHYS_MEMORY) return alloc_agpphysmem_i8xx(pg_count, type); - return NULL; } @@ -357,7 +382,7 @@ static void intel_i810_free_by_type(stru gart_to_virt(curr->memory[0])); global_flush_tlb(); } - vfree(curr->memory); + agp_free_page_array(curr); } kfree(curr); } @@ -619,9 +644,11 @@ static int intel_i830_insert_entries(str { int i,j,num_entries; void *temp; + int ret = -EINVAL; + int mask_type; if (mem->page_count == 0) - return 0; + goto out; temp = agp_bridge->current_size; num_entries = A_SIZE_FIX(temp)->num_entries; @@ -631,34 +658,41 @@ static int intel_i830_insert_entries(str pg_start,intel_i830_private.gtt_entries); printk (KERN_INFO PFX "Trying to insert into local/stolen memory\n"); - return -EINVAL; + goto out_err; } if ((pg_start + mem->page_count) > num_entries) - return -EINVAL; + goto out_err; /* The i830 can't check the GTT for entries since its read only, * depend on the caller to make the correct offset decisions. */ - if ((type != 0 && type != AGP_PHYS_MEMORY) || - (mem->type != 0 && mem->type != AGP_PHYS_MEMORY)) - return -EINVAL; + if (type != mem->type) + goto out_err; + + mask_type = agp_bridge->driver->agp_type_to_mask_type(agp_bridge, type); - if (!mem->is_flushed) { + if (mask_type != 0 && mask_type != AGP_PHYS_MEMORY && + mask_type != INTEL_AGP_CACHED_MEMORY) + goto out_err; + + if (!mem->is_flushed) global_cache_flush(); - mem->is_flushed = TRUE; - } for (i = 0, j = pg_start; i < mem->page_count; i++, j++) { writel(agp_bridge->driver->mask_memory(agp_bridge, - mem->memory[i], mem->type), - intel_i830_private.registers+I810_PTE_BASE+(j*4)); + mem->memory[i], mask_type), + intel_i830_private.registers+I810_PTE_BASE+(j*4)); } readl(intel_i830_private.registers+I810_PTE_BASE+((j-1)*4)); - agp_bridge->driver->tlb_flush(mem); - return 0; + +out: + ret = 0; +out_err: + mem->is_flushed = 1; + return ret; } static int intel_i830_remove_entries(struct agp_memory *mem,off_t pg_start, @@ -687,7 +721,6 @@ static struct agp_memory *intel_i830_all { if (type == AGP_PHYS_MEMORY) return alloc_agpphysmem_i8xx(pg_count, type); - /* always return NULL for other allocation types for now */ return NULL; } @@ -734,9 +767,11 @@ static int intel_i915_insert_entries(str { int i,j,num_entries; void *temp; + int ret = -EINVAL; + int mask_type; if (mem->page_count == 0) - return 0; + goto out; temp = agp_bridge->current_size; num_entries = A_SIZE_FIX(temp)->num_entries; @@ -746,33 +781,41 @@ static int intel_i915_insert_entries(str pg_start,intel_i830_private.gtt_entries); printk (KERN_INFO PFX "Trying to insert into local/stolen memory\n"); - return -EINVAL; + goto out_err; } if ((pg_start + mem->page_count) > num_entries) - return -EINVAL; + goto out_err; - /* The i830 can't check the GTT for entries since its read only, + /* The i915 can't check the GTT for entries since its read only, * depend on the caller to make the correct offset decisions. */ - if ((type != 0 && type != AGP_PHYS_MEMORY) || - (mem->type != 0 && mem->type != AGP_PHYS_MEMORY)) - return -EINVAL; + if (type != mem->type) + goto out_err; + + mask_type = agp_bridge->driver->agp_type_to_mask_type(agp_bridge, type); - if (!mem->is_flushed) { + if (mask_type != 0 && mask_type != AGP_PHYS_MEMORY && + mask_type != INTEL_AGP_CACHED_MEMORY) + goto out_err; + + if (!mem->is_flushed) global_cache_flush(); - mem->is_flushed = TRUE; - } for (i = 0, j = pg_start; i < mem->page_count; i++, j++) { writel(agp_bridge->driver->mask_memory(agp_bridge, - mem->memory[i], mem->type), intel_i830_private.gtt+j); + mem->memory[i], mask_type), intel_i830_private.gtt+j); } - readl(intel_i830_private.gtt+j-1); + readl(intel_i830_private.gtt+j-1); agp_bridge->driver->tlb_flush(mem); - return 0; + + out: + ret = 0; + out_err: + mem->is_flushed = 1; + return ret; } static int intel_i915_remove_entries(struct agp_memory *mem,off_t pg_start, @@ -803,7 +846,7 @@ static int intel_i915_remove_entries(str */ static int intel_i9xx_fetch_size(void) { - int num_sizes = sizeof(intel_i830_sizes) / sizeof(*intel_i830_sizes); + int num_sizes = ARRAY_SIZE(intel_i830_sizes); int aper_size; /* size in megabytes */ int i; @@ -1384,6 +1427,7 @@ static struct agp_bridge_driver intel_ge .free_by_type = agp_generic_free_by_type, .agp_alloc_page = agp_generic_alloc_page, .agp_destroy_page = agp_generic_destroy_page, + .agp_type_to_mask_type = agp_generic_type_to_mask_type, }; static struct agp_bridge_driver intel_810_driver = { @@ -1408,6 +1452,7 @@ static struct agp_bridge_driver intel_81 .free_by_type = intel_i810_free_by_type, .agp_alloc_page = agp_generic_alloc_page, .agp_destroy_page = agp_generic_destroy_page, + .agp_type_to_mask_type = agp_generic_type_to_mask_type, }; static struct agp_bridge_driver intel_815_driver = { @@ -1431,6 +1476,7 @@ static struct agp_bridge_driver intel_81 .free_by_type = agp_generic_free_by_type, .agp_alloc_page = agp_generic_alloc_page, .agp_destroy_page = agp_generic_destroy_page, + .agp_type_to_mask_type = agp_generic_type_to_mask_type, }; static struct agp_bridge_driver intel_830_driver = { @@ -1455,6 +1501,7 @@ static struct agp_bridge_driver intel_83 .free_by_type = intel_i810_free_by_type, .agp_alloc_page = agp_generic_alloc_page, .agp_destroy_page = agp_generic_destroy_page, + .agp_type_to_mask_type = intel_i830_type_to_mask_type, }; static struct agp_bridge_driver intel_820_driver = { @@ -1478,6 +1525,7 @@ static struct agp_bridge_driver intel_82 .free_by_type = agp_generic_free_by_type, .agp_alloc_page = agp_generic_alloc_page, .agp_destroy_page = agp_generic_destroy_page, + .agp_type_to_mask_type = agp_generic_type_to_mask_type, }; static struct agp_bridge_driver intel_830mp_driver = { @@ -1501,6 +1549,7 @@ static struct agp_bridge_driver intel_83 .free_by_type = agp_generic_free_by_type, .agp_alloc_page = agp_generic_alloc_page, .agp_destroy_page = agp_generic_destroy_page, + .agp_type_to_mask_type = agp_generic_type_to_mask_type, }; static struct agp_bridge_driver intel_840_driver = { @@ -1524,6 +1573,7 @@ static struct agp_bridge_driver intel_84 .free_by_type = agp_generic_free_by_type, .agp_alloc_page = agp_generic_alloc_page, .agp_destroy_page = agp_generic_destroy_page, + .agp_type_to_mask_type = agp_generic_type_to_mask_type, }; static struct agp_bridge_driver intel_845_driver = { @@ -1547,6 +1597,7 @@ static struct agp_bridge_driver intel_84 .free_by_type = agp_generic_free_by_type, .agp_alloc_page = agp_generic_alloc_page, .agp_destroy_page = agp_generic_destroy_page, + .agp_type_to_mask_type = agp_generic_type_to_mask_type, }; static struct agp_bridge_driver intel_850_driver = { @@ -1570,6 +1621,7 @@ static struct agp_bridge_driver intel_85 .free_by_type = agp_generic_free_by_type, .agp_alloc_page = agp_generic_alloc_page, .agp_destroy_page = agp_generic_destroy_page, + .agp_type_to_mask_type = agp_generic_type_to_mask_type, }; static struct agp_bridge_driver intel_860_driver = { @@ -1593,6 +1645,7 @@ static struct agp_bridge_driver intel_86 .free_by_type = agp_generic_free_by_type, .agp_alloc_page = agp_generic_alloc_page, .agp_destroy_page = agp_generic_destroy_page, + .agp_type_to_mask_type = agp_generic_type_to_mask_type, }; static struct agp_bridge_driver intel_915_driver = { @@ -1617,6 +1670,7 @@ static struct agp_bridge_driver intel_91 .free_by_type = intel_i810_free_by_type, .agp_alloc_page = agp_generic_alloc_page, .agp_destroy_page = agp_generic_destroy_page, + .agp_type_to_mask_type = intel_i830_type_to_mask_type, }; static struct agp_bridge_driver intel_i965_driver = { @@ -1641,6 +1695,7 @@ static struct agp_bridge_driver intel_i9 .free_by_type = intel_i810_free_by_type, .agp_alloc_page = agp_generic_alloc_page, .agp_destroy_page = agp_generic_destroy_page, + .agp_type_to_mask_type = intel_i830_type_to_mask_type, }; static struct agp_bridge_driver intel_7505_driver = { @@ -1664,6 +1719,7 @@ static struct agp_bridge_driver intel_75 .free_by_type = agp_generic_free_by_type, .agp_alloc_page = agp_generic_alloc_page, .agp_destroy_page = agp_generic_destroy_page, + .agp_type_to_mask_type = agp_generic_type_to_mask_type, }; static int find_i810(u16 device) diff --git a/drivers/char/agp/nvidia-agp.c b/drivers/char/agp/nvidia-agp.c index df7f37b..2563286 100644 --- a/drivers/char/agp/nvidia-agp.c +++ b/drivers/char/agp/nvidia-agp.c @@ -310,6 +310,7 @@ static struct agp_bridge_driver nvidia_d .free_by_type = agp_generic_free_by_type, .agp_alloc_page = agp_generic_alloc_page, .agp_destroy_page = agp_generic_destroy_page, + .agp_type_to_mask_type = agp_generic_type_to_mask_type, }; static int __devinit agp_nvidia_probe(struct pci_dev *pdev, diff --git a/drivers/char/agp/parisc-agp.c b/drivers/char/agp/parisc-agp.c index 17c50b0..b7b4590 100644 --- a/drivers/char/agp/parisc-agp.c +++ b/drivers/char/agp/parisc-agp.c @@ -228,6 +228,7 @@ struct agp_bridge_driver parisc_agp_driv .free_by_type = agp_generic_free_by_type, .agp_alloc_page = agp_generic_alloc_page, .agp_destroy_page = agp_generic_destroy_page, + .agp_type_to_mask_type = agp_generic_type_to_mask_type, .cant_use_aperture = 1, }; diff --git a/drivers/char/agp/sgi-agp.c b/drivers/char/agp/sgi-agp.c index 902648d..92d1dc4 100644 --- a/drivers/char/agp/sgi-agp.c +++ b/drivers/char/agp/sgi-agp.c @@ -265,6 +265,7 @@ struct agp_bridge_driver sgi_tioca_drive .free_by_type = agp_generic_free_by_type, .agp_alloc_page = sgi_tioca_alloc_page, .agp_destroy_page = agp_generic_destroy_page, + .agp_type_to_mask_type = agp_generic_type_to_mask_type, .cant_use_aperture = 1, .needs_scratch_page = 0, .num_aperture_sizes = 1, diff --git a/drivers/char/agp/sis-agp.c b/drivers/char/agp/sis-agp.c index a00fd48..60342b7 100644 --- a/drivers/char/agp/sis-agp.c +++ b/drivers/char/agp/sis-agp.c @@ -140,6 +140,7 @@ static struct agp_bridge_driver sis_driv .free_by_type = agp_generic_free_by_type, .agp_alloc_page = agp_generic_alloc_page, .agp_destroy_page = agp_generic_destroy_page, + .agp_type_to_mask_type = agp_generic_type_to_mask_type, }; static struct agp_device_ids sis_agp_device_ids[] __devinitdata = diff --git a/drivers/char/agp/sworks-agp.c b/drivers/char/agp/sworks-agp.c index 4f2d7d9..9f5ae77 100644 --- a/drivers/char/agp/sworks-agp.c +++ b/drivers/char/agp/sworks-agp.c @@ -444,6 +444,7 @@ static struct agp_bridge_driver sworks_d .free_by_type = agp_generic_free_by_type, .agp_alloc_page = agp_generic_alloc_page, .agp_destroy_page = agp_generic_destroy_page, + .agp_type_to_mask_type = agp_generic_type_to_mask_type, }; static int __devinit agp_serverworks_probe(struct pci_dev *pdev, diff --git a/drivers/char/agp/uninorth-agp.c b/drivers/char/agp/uninorth-agp.c index dffc193..6c45702 100644 --- a/drivers/char/agp/uninorth-agp.c +++ b/drivers/char/agp/uninorth-agp.c @@ -510,6 +510,7 @@ struct agp_bridge_driver uninorth_agp_dr .free_by_type = agp_generic_free_by_type, .agp_alloc_page = agp_generic_alloc_page, .agp_destroy_page = agp_generic_destroy_page, + .agp_type_to_mask_type = agp_generic_type_to_mask_type, .cant_use_aperture = 1, }; @@ -534,6 +535,7 @@ struct agp_bridge_driver u3_agp_driver = .free_by_type = agp_generic_free_by_type, .agp_alloc_page = agp_generic_alloc_page, .agp_destroy_page = agp_generic_destroy_page, + .agp_type_to_mask_type = agp_generic_type_to_mask_type, .cant_use_aperture = 1, .needs_scratch_page = 1, }; diff --git a/drivers/char/agp/via-agp.c b/drivers/char/agp/via-agp.c index 2ded7a2..2e7c043 100644 --- a/drivers/char/agp/via-agp.c +++ b/drivers/char/agp/via-agp.c @@ -191,6 +191,7 @@ static struct agp_bridge_driver via_agp3 .free_by_type = agp_generic_free_by_type, .agp_alloc_page = agp_generic_alloc_page, .agp_destroy_page = agp_generic_destroy_page, + .agp_type_to_mask_type = agp_generic_type_to_mask_type, }; static struct agp_bridge_driver via_driver = { @@ -214,6 +215,7 @@ static struct agp_bridge_driver via_driv .free_by_type = agp_generic_free_by_type, .agp_alloc_page = agp_generic_alloc_page, .agp_destroy_page = agp_generic_destroy_page, + .agp_type_to_mask_type = agp_generic_type_to_mask_type, }; static struct agp_device_ids via_agp_device_ids[] __devinitdata = diff --git a/drivers/char/amiserial.c b/drivers/char/amiserial.c index feb4ac8..0e2b72f 100644 --- a/drivers/char/amiserial.c +++ b/drivers/char/amiserial.c @@ -527,10 +527,8 @@ static void do_softint(unsigned long pri if (!tty) return; - if (test_and_clear_bit(RS_EVENT_WRITE_WAKEUP, &info->event)) { + if (test_and_clear_bit(RS_EVENT_WRITE_WAKEUP, &info->event)) tty_wakeup(tty); - wake_up_interruptible(&tty->write_wait); - } } /* @@ -904,8 +902,7 @@ static int rs_write(struct tty_struct * if (!info->xmit.buf) return 0; - local_save_flags(flags); - local_irq_disable(); + local_irq_save(flags); while (1) { c = CIRC_SPACE_TO_END(info->xmit.head, info->xmit.tail, @@ -968,7 +965,6 @@ static void rs_flush_buffer(struct tty_s local_irq_save(flags); info->xmit.head = info->xmit.tail = 0; local_irq_restore(flags); - wake_up_interruptible(&tty->write_wait); tty_wakeup(tty); } diff --git a/drivers/char/apm-emulation.c b/drivers/char/apm-emulation.c new file mode 100644 index 0000000..179c7a3 --- /dev/null +++ b/drivers/char/apm-emulation.c @@ -0,0 +1,672 @@ +/* + * bios-less APM driver for ARM Linux + * Jamey Hicks + * adapted from the APM BIOS driver for Linux by Stephen Rothwell (sfr@linuxcare.com) + * + * APM 1.2 Reference: + * Intel Corporation, Microsoft Corporation. Advanced Power Management + * (APM) BIOS Interface Specification, Revision 1.2, February 1996. + * + * [This document is available from Microsoft at: + * http://www.microsoft.com/hwdev/busbios/amp_12.htm] + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +/* + * The apm_bios device is one of the misc char devices. + * This is its minor number. + */ +#define APM_MINOR_DEV 134 + +/* + * See Documentation/Config.help for the configuration options. + * + * Various options can be changed at boot time as follows: + * (We allow underscores for compatibility with the modules code) + * apm=on/off enable/disable APM + */ + +/* + * Maximum number of events stored + */ +#define APM_MAX_EVENTS 16 + +struct apm_queue { + unsigned int event_head; + unsigned int event_tail; + apm_event_t events[APM_MAX_EVENTS]; +}; + +/* + * The per-file APM data + */ +struct apm_user { + struct list_head list; + + unsigned int suser: 1; + unsigned int writer: 1; + unsigned int reader: 1; + + int suspend_result; + unsigned int suspend_state; +#define SUSPEND_NONE 0 /* no suspend pending */ +#define SUSPEND_PENDING 1 /* suspend pending read */ +#define SUSPEND_READ 2 /* suspend read, pending ack */ +#define SUSPEND_ACKED 3 /* suspend acked */ +#define SUSPEND_WAIT 4 /* waiting for suspend */ +#define SUSPEND_DONE 5 /* suspend completed */ + + struct apm_queue queue; +}; + +/* + * Local variables + */ +static int suspends_pending; +static int apm_disabled; +static struct task_struct *kapmd_tsk; + +static DECLARE_WAIT_QUEUE_HEAD(apm_waitqueue); +static DECLARE_WAIT_QUEUE_HEAD(apm_suspend_waitqueue); + +/* + * This is a list of everyone who has opened /dev/apm_bios + */ +static DECLARE_RWSEM(user_list_lock); +static LIST_HEAD(apm_user_list); + +/* + * kapmd info. kapmd provides us a process context to handle + * "APM" events within - specifically necessary if we're going + * to be suspending the system. + */ +static DECLARE_WAIT_QUEUE_HEAD(kapmd_wait); +static DEFINE_SPINLOCK(kapmd_queue_lock); +static struct apm_queue kapmd_queue; + +static DEFINE_MUTEX(state_lock); + +static const char driver_version[] = "1.13"; /* no spaces */ + + + +/* + * Compatibility cruft until the IPAQ people move over to the new + * interface. + */ +static void __apm_get_power_status(struct apm_power_info *info) +{ +} + +/* + * This allows machines to provide their own "apm get power status" function. + */ +void (*apm_get_power_status)(struct apm_power_info *) = __apm_get_power_status; +EXPORT_SYMBOL(apm_get_power_status); + + +/* + * APM event queue management. + */ +static inline int queue_empty(struct apm_queue *q) +{ + return q->event_head == q->event_tail; +} + +static inline apm_event_t queue_get_event(struct apm_queue *q) +{ + q->event_tail = (q->event_tail + 1) % APM_MAX_EVENTS; + return q->events[q->event_tail]; +} + +static void queue_add_event(struct apm_queue *q, apm_event_t event) +{ + q->event_head = (q->event_head + 1) % APM_MAX_EVENTS; + if (q->event_head == q->event_tail) { + static int notified; + + if (notified++ == 0) + printk(KERN_ERR "apm: an event queue overflowed\n"); + q->event_tail = (q->event_tail + 1) % APM_MAX_EVENTS; + } + q->events[q->event_head] = event; +} + +static void queue_event(apm_event_t event) +{ + struct apm_user *as; + + down_read(&user_list_lock); + list_for_each_entry(as, &apm_user_list, list) { + if (as->reader) + queue_add_event(&as->queue, event); + } + up_read(&user_list_lock); + wake_up_interruptible(&apm_waitqueue); +} + +/* + * queue_suspend_event - queue an APM suspend event. + * + * Check that we're in a state where we can suspend. If not, + * return -EBUSY. Otherwise, queue an event to all "writer" + * users. If there are no "writer" users, return '1' to + * indicate that we can immediately suspend. + */ +static int queue_suspend_event(apm_event_t event, struct apm_user *sender) +{ + struct apm_user *as; + int ret = 1; + + mutex_lock(&state_lock); + down_read(&user_list_lock); + + /* + * If a thread is still processing, we can't suspend, so reject + * the request. + */ + list_for_each_entry(as, &apm_user_list, list) { + if (as != sender && as->reader && as->writer && as->suser && + as->suspend_state != SUSPEND_NONE) { + ret = -EBUSY; + goto out; + } + } + + list_for_each_entry(as, &apm_user_list, list) { + if (as != sender && as->reader && as->writer && as->suser) { + as->suspend_state = SUSPEND_PENDING; + suspends_pending++; + queue_add_event(&as->queue, event); + ret = 0; + } + } + out: + up_read(&user_list_lock); + mutex_unlock(&state_lock); + wake_up_interruptible(&apm_waitqueue); + return ret; +} + +static void apm_suspend(void) +{ + struct apm_user *as; + int err = pm_suspend(PM_SUSPEND_MEM); + + /* + * Anyone on the APM queues will think we're still suspended. + * Send a message so everyone knows we're now awake again. + */ + queue_event(APM_NORMAL_RESUME); + + /* + * Finally, wake up anyone who is sleeping on the suspend. + */ + mutex_lock(&state_lock); + down_read(&user_list_lock); + list_for_each_entry(as, &apm_user_list, list) { + if (as->suspend_state == SUSPEND_WAIT || + as->suspend_state == SUSPEND_ACKED) { + as->suspend_result = err; + as->suspend_state = SUSPEND_DONE; + } + } + up_read(&user_list_lock); + mutex_unlock(&state_lock); + + wake_up(&apm_suspend_waitqueue); +} + +static ssize_t apm_read(struct file *fp, char __user *buf, size_t count, loff_t *ppos) +{ + struct apm_user *as = fp->private_data; + apm_event_t event; + int i = count, ret = 0; + + if (count < sizeof(apm_event_t)) + return -EINVAL; + + if (queue_empty(&as->queue) && fp->f_flags & O_NONBLOCK) + return -EAGAIN; + + wait_event_interruptible(apm_waitqueue, !queue_empty(&as->queue)); + + while ((i >= sizeof(event)) && !queue_empty(&as->queue)) { + event = queue_get_event(&as->queue); + + ret = -EFAULT; + if (copy_to_user(buf, &event, sizeof(event))) + break; + + mutex_lock(&state_lock); + if (as->suspend_state == SUSPEND_PENDING && + (event == APM_SYS_SUSPEND || event == APM_USER_SUSPEND)) + as->suspend_state = SUSPEND_READ; + mutex_unlock(&state_lock); + + buf += sizeof(event); + i -= sizeof(event); + } + + if (i < count) + ret = count - i; + + return ret; +} + +static unsigned int apm_poll(struct file *fp, poll_table * wait) +{ + struct apm_user *as = fp->private_data; + + poll_wait(fp, &apm_waitqueue, wait); + return queue_empty(&as->queue) ? 0 : POLLIN | POLLRDNORM; +} + +/* + * apm_ioctl - handle APM ioctl + * + * APM_IOC_SUSPEND + * This IOCTL is overloaded, and performs two functions. It is used to: + * - initiate a suspend + * - acknowledge a suspend read from /dev/apm_bios. + * Only when everyone who has opened /dev/apm_bios with write permission + * has acknowledge does the actual suspend happen. + */ +static int +apm_ioctl(struct inode * inode, struct file *filp, u_int cmd, u_long arg) +{ + struct apm_user *as = filp->private_data; + unsigned long flags; + int err = -EINVAL; + + if (!as->suser || !as->writer) + return -EPERM; + + switch (cmd) { + case APM_IOC_SUSPEND: + mutex_lock(&state_lock); + + as->suspend_result = -EINTR; + + if (as->suspend_state == SUSPEND_READ) { + int pending; + + /* + * If we read a suspend command from /dev/apm_bios, + * then the corresponding APM_IOC_SUSPEND ioctl is + * interpreted as an acknowledge. + */ + as->suspend_state = SUSPEND_ACKED; + suspends_pending--; + pending = suspends_pending == 0; + mutex_unlock(&state_lock); + + /* + * If there are no further acknowledges required, + * suspend the system. + */ + if (pending) + apm_suspend(); + + /* + * Wait for the suspend/resume to complete. If there + * are pending acknowledges, we wait here for them. + * + * Note: we need to ensure that the PM subsystem does + * not kick us out of the wait when it suspends the + * threads. + */ + flags = current->flags; + current->flags |= PF_NOFREEZE; + + wait_event(apm_suspend_waitqueue, + as->suspend_state == SUSPEND_DONE); + } else { + as->suspend_state = SUSPEND_WAIT; + mutex_unlock(&state_lock); + + /* + * Otherwise it is a request to suspend the system. + * Queue an event for all readers, and expect an + * acknowledge from all writers who haven't already + * acknowledged. + */ + err = queue_suspend_event(APM_USER_SUSPEND, as); + if (err < 0) { + /* + * Avoid taking the lock here - this + * should be fine. + */ + as->suspend_state = SUSPEND_NONE; + break; + } + + if (err > 0) + apm_suspend(); + + /* + * Wait for the suspend/resume to complete. If there + * are pending acknowledges, we wait here for them. + * + * Note: we need to ensure that the PM subsystem does + * not kick us out of the wait when it suspends the + * threads. + */ + flags = current->flags; + current->flags |= PF_NOFREEZE; + + wait_event_interruptible(apm_suspend_waitqueue, + as->suspend_state == SUSPEND_DONE); + } + + current->flags = flags; + + mutex_lock(&state_lock); + err = as->suspend_result; + as->suspend_state = SUSPEND_NONE; + mutex_unlock(&state_lock); + break; + } + + return err; +} + +static int apm_release(struct inode * inode, struct file * filp) +{ + struct apm_user *as = filp->private_data; + int pending = 0; + + filp->private_data = NULL; + + down_write(&user_list_lock); + list_del(&as->list); + up_write(&user_list_lock); + + /* + * We are now unhooked from the chain. As far as new + * events are concerned, we no longer exist. However, we + * need to balance suspends_pending, which means the + * possibility of sleeping. + */ + mutex_lock(&state_lock); + if (as->suspend_state != SUSPEND_NONE) { + suspends_pending -= 1; + pending = suspends_pending == 0; + } + mutex_unlock(&state_lock); + if (pending) + apm_suspend(); + + kfree(as); + return 0; +} + +static int apm_open(struct inode * inode, struct file * filp) +{ + struct apm_user *as; + + as = kzalloc(sizeof(*as), GFP_KERNEL); + if (as) { + /* + * XXX - this is a tiny bit broken, when we consider BSD + * process accounting. If the device is opened by root, we + * instantly flag that we used superuser privs. Who knows, + * we might close the device immediately without doing a + * privileged operation -- cevans + */ + as->suser = capable(CAP_SYS_ADMIN); + as->writer = (filp->f_mode & FMODE_WRITE) == FMODE_WRITE; + as->reader = (filp->f_mode & FMODE_READ) == FMODE_READ; + + down_write(&user_list_lock); + list_add(&as->list, &apm_user_list); + up_write(&user_list_lock); + + filp->private_data = as; + } + + return as ? 0 : -ENOMEM; +} + +static struct file_operations apm_bios_fops = { + .owner = THIS_MODULE, + .read = apm_read, + .poll = apm_poll, + .ioctl = apm_ioctl, + .open = apm_open, + .release = apm_release, +}; + +static struct miscdevice apm_device = { + .minor = APM_MINOR_DEV, + .name = "apm_bios", + .fops = &apm_bios_fops +}; + + +#ifdef CONFIG_PROC_FS +/* + * Arguments, with symbols from linux/apm_bios.h. + * + * 0) Linux driver version (this will change if format changes) + * 1) APM BIOS Version. Usually 1.0, 1.1 or 1.2. + * 2) APM flags from APM Installation Check (0x00): + * bit 0: APM_16_BIT_SUPPORT + * bit 1: APM_32_BIT_SUPPORT + * bit 2: APM_IDLE_SLOWS_CLOCK + * bit 3: APM_BIOS_DISABLED + * bit 4: APM_BIOS_DISENGAGED + * 3) AC line status + * 0x00: Off-line + * 0x01: On-line + * 0x02: On backup power (BIOS >= 1.1 only) + * 0xff: Unknown + * 4) Battery status + * 0x00: High + * 0x01: Low + * 0x02: Critical + * 0x03: Charging + * 0x04: Selected battery not present (BIOS >= 1.2 only) + * 0xff: Unknown + * 5) Battery flag + * bit 0: High + * bit 1: Low + * bit 2: Critical + * bit 3: Charging + * bit 7: No system battery + * 0xff: Unknown + * 6) Remaining battery life (percentage of charge): + * 0-100: valid + * -1: Unknown + * 7) Remaining battery life (time units): + * Number of remaining minutes or seconds + * -1: Unknown + * 8) min = minutes; sec = seconds + */ +static int apm_get_info(char *buf, char **start, off_t fpos, int length) +{ + struct apm_power_info info; + char *units; + int ret; + + info.ac_line_status = 0xff; + info.battery_status = 0xff; + info.battery_flag = 0xff; + info.battery_life = -1; + info.time = -1; + info.units = -1; + + if (apm_get_power_status) + apm_get_power_status(&info); + + switch (info.units) { + default: units = "?"; break; + case 0: units = "min"; break; + case 1: units = "sec"; break; + } + + ret = sprintf(buf, "%s 1.2 0x%02x 0x%02x 0x%02x 0x%02x %d%% %d %s\n", + driver_version, APM_32_BIT_SUPPORT, + info.ac_line_status, info.battery_status, + info.battery_flag, info.battery_life, + info.time, units); + + return ret; +} +#endif + +static int kapmd(void *arg) +{ + do { + apm_event_t event; + int ret; + + wait_event_interruptible(kapmd_wait, + !queue_empty(&kapmd_queue) || kthread_should_stop()); + + if (kthread_should_stop()) + break; + + spin_lock_irq(&kapmd_queue_lock); + event = 0; + if (!queue_empty(&kapmd_queue)) + event = queue_get_event(&kapmd_queue); + spin_unlock_irq(&kapmd_queue_lock); + + switch (event) { + case 0: + break; + + case APM_LOW_BATTERY: + case APM_POWER_STATUS_CHANGE: + queue_event(event); + break; + + case APM_USER_SUSPEND: + case APM_SYS_SUSPEND: + ret = queue_suspend_event(event, NULL); + if (ret < 0) { + /* + * We were busy. Try again in 50ms. + */ + queue_add_event(&kapmd_queue, event); + msleep(50); + } + if (ret > 0) + apm_suspend(); + break; + + case APM_CRITICAL_SUSPEND: + apm_suspend(); + break; + } + } while (1); + + return 0; +} + +static int __init apm_init(void) +{ + int ret; + + if (apm_disabled) { + printk(KERN_NOTICE "apm: disabled on user request.\n"); + return -ENODEV; + } + + kapmd_tsk = kthread_create(kapmd, NULL, "kapmd"); + if (IS_ERR(kapmd_tsk)) { + ret = PTR_ERR(kapmd_tsk); + kapmd_tsk = NULL; + return ret; + } + kapmd_tsk->flags |= PF_NOFREEZE; + wake_up_process(kapmd_tsk); + +#ifdef CONFIG_PROC_FS + create_proc_info_entry("apm", 0, NULL, apm_get_info); +#endif + + ret = misc_register(&apm_device); + if (ret != 0) { + remove_proc_entry("apm", NULL); + kthread_stop(kapmd_tsk); + } + + return ret; +} + +static void __exit apm_exit(void) +{ + misc_deregister(&apm_device); + remove_proc_entry("apm", NULL); + + kthread_stop(kapmd_tsk); +} + +module_init(apm_init); +module_exit(apm_exit); + +MODULE_AUTHOR("Stephen Rothwell"); +MODULE_DESCRIPTION("Advanced Power Management"); +MODULE_LICENSE("GPL"); + +#ifndef MODULE +static int __init apm_setup(char *str) +{ + while ((str != NULL) && (*str != '\0')) { + if (strncmp(str, "off", 3) == 0) + apm_disabled = 1; + if (strncmp(str, "on", 2) == 0) + apm_disabled = 0; + str = strchr(str, ','); + if (str != NULL) + str += strspn(str, ", \t"); + } + return 1; +} + +__setup("apm=", apm_setup); +#endif + +/** + * apm_queue_event - queue an APM event for kapmd + * @event: APM event + * + * Queue an APM event for kapmd to process and ultimately take the + * appropriate action. Only a subset of events are handled: + * %APM_LOW_BATTERY + * %APM_POWER_STATUS_CHANGE + * %APM_USER_SUSPEND + * %APM_SYS_SUSPEND + * %APM_CRITICAL_SUSPEND + */ +void apm_queue_event(apm_event_t event) +{ + unsigned long flags; + + spin_lock_irqsave(&kapmd_queue_lock, flags); + queue_add_event(&kapmd_queue, event); + spin_unlock_irqrestore(&kapmd_queue_lock, flags); + + wake_up_interruptible(&kapmd_wait); +} +EXPORT_SYMBOL(apm_queue_event); diff --git a/drivers/char/briq_panel.c b/drivers/char/briq_panel.c index 9f8082f..8dcf9d2 100644 --- a/drivers/char/briq_panel.c +++ b/drivers/char/briq_panel.c @@ -8,7 +8,6 @@ #include #include #include -#include #include #include #include @@ -187,7 +186,7 @@ #endif return len; } -static struct file_operations briq_panel_fops = { +static const struct file_operations briq_panel_fops = { .owner = THIS_MODULE, .read = briq_panel_read, .write = briq_panel_write, diff --git a/drivers/char/cyclades.c b/drivers/char/cyclades.c index 3ffa080..54df355 100644 --- a/drivers/char/cyclades.c +++ b/drivers/char/cyclades.c @@ -829,17 +829,18 @@ static unsigned short cy_pci_nboard; static unsigned short cy_isa_nboard; static unsigned short cy_nboard; #ifdef CONFIG_PCI -static unsigned short cy_pci_dev_id[] = { - PCI_DEVICE_ID_CYCLOM_Y_Lo, /* PCI < 1Mb */ - PCI_DEVICE_ID_CYCLOM_Y_Hi, /* PCI > 1Mb */ - PCI_DEVICE_ID_CYCLOM_4Y_Lo, /* 4Y PCI < 1Mb */ - PCI_DEVICE_ID_CYCLOM_4Y_Hi, /* 4Y PCI > 1Mb */ - PCI_DEVICE_ID_CYCLOM_8Y_Lo, /* 8Y PCI < 1Mb */ - PCI_DEVICE_ID_CYCLOM_8Y_Hi, /* 8Y PCI > 1Mb */ - PCI_DEVICE_ID_CYCLOM_Z_Lo, /* Z PCI < 1Mb */ - PCI_DEVICE_ID_CYCLOM_Z_Hi, /* Z PCI > 1Mb */ - 0 /* end of table */ +static struct pci_device_id cy_pci_dev_id[] __devinitdata = { + { PCI_DEVICE(PCI_VENDOR_ID_CYCLADES, PCI_DEVICE_ID_CYCLOM_Y_Lo) }, /* PCI < 1Mb */ + { PCI_DEVICE(PCI_VENDOR_ID_CYCLADES, PCI_DEVICE_ID_CYCLOM_Y_Hi) }, /* PCI > 1Mb */ + { PCI_DEVICE(PCI_VENDOR_ID_CYCLADES, PCI_DEVICE_ID_CYCLOM_4Y_Lo) }, /* 4Y PCI < 1Mb */ + { PCI_DEVICE(PCI_VENDOR_ID_CYCLADES, PCI_DEVICE_ID_CYCLOM_4Y_Hi) }, /* 4Y PCI > 1Mb */ + { PCI_DEVICE(PCI_VENDOR_ID_CYCLADES, PCI_DEVICE_ID_CYCLOM_8Y_Lo) }, /* 8Y PCI < 1Mb */ + { PCI_DEVICE(PCI_VENDOR_ID_CYCLADES, PCI_DEVICE_ID_CYCLOM_8Y_Hi) }, /* 8Y PCI > 1Mb */ + { PCI_DEVICE(PCI_VENDOR_ID_CYCLADES, PCI_DEVICE_ID_CYCLOM_Z_Lo) }, /* Z PCI < 1Mb */ + { PCI_DEVICE(PCI_VENDOR_ID_CYCLADES, PCI_DEVICE_ID_CYCLOM_Z_Hi) }, /* Z PCI > 1Mb */ + { } /* end of table */ }; +MODULE_DEVICE_TABLE(pci, cy_pci_dev_id); #endif static void cy_start(struct tty_struct *); @@ -4488,7 +4489,6 @@ #endif CY_UNLOCK(info, flags); } tty_wakeup(tty); - wake_up_interruptible(&tty->write_wait); } /* cy_flush_buffer */ /* @@ -4759,7 +4759,7 @@ #ifdef CONFIG_PCI for (i = 0; i < NR_CARDS; i++) { /* look for a Cyclades card by vendor and device id */ - while ((device_id = cy_pci_dev_id[dev_index]) != 0) { + while ((device_id = cy_pci_dev_id[dev_index].device) != 0) { if ((pdev = pci_get_device(PCI_VENDOR_ID_CYCLADES, device_id, pdev)) == NULL) { dev_index++; /* try next device id */ diff --git a/drivers/char/drm/drmP.h b/drivers/char/drm/drmP.h index 6dcdceb..85d99e2 100644 --- a/drivers/char/drm/drmP.h +++ b/drivers/char/drm/drmP.h @@ -532,11 +532,13 @@ typedef struct drm_mm_node { int free; unsigned long start; unsigned long size; + struct drm_mm *mm; void *private; } drm_mm_node_t; typedef struct drm_mm { - drm_mm_node_t root_node; + struct list_head fl_entry; + struct list_head ml_entry; } drm_mm_t; /** @@ -843,9 +845,6 @@ extern void drm_mem_init(void); extern int drm_mem_info(char *buf, char **start, off_t offset, int request, int *eof, void *data); extern void *drm_realloc(void *oldpt, size_t oldsize, size_t size, int area); -extern void *drm_ioremap(unsigned long offset, unsigned long size, - drm_device_t * dev); -extern void drm_ioremapfree(void *pt, unsigned long size, drm_device_t * dev); extern DRM_AGP_MEM *drm_alloc_agp(drm_device_t * dev, int pages, u32 type); extern int drm_free_agp(DRM_AGP_MEM * handle, int pages); @@ -1053,33 +1052,18 @@ extern void drm_sysfs_device_remove(stru extern drm_mm_node_t *drm_mm_get_block(drm_mm_node_t * parent, unsigned long size, unsigned alignment); -extern void drm_mm_put_block(drm_mm_t *mm, drm_mm_node_t *cur); +void drm_mm_put_block(drm_mm_node_t * cur); extern drm_mm_node_t *drm_mm_search_free(const drm_mm_t *mm, unsigned long size, unsigned alignment, int best_match); extern int drm_mm_init(drm_mm_t *mm, unsigned long start, unsigned long size); extern void drm_mm_takedown(drm_mm_t *mm); +extern int drm_mm_clean(drm_mm_t *mm); +extern unsigned long drm_mm_tail_space(drm_mm_t *mm); +extern int drm_mm_remove_space_from_tail(drm_mm_t *mm, unsigned long size); +extern int drm_mm_add_space_to_tail(drm_mm_t *mm, unsigned long size); -/* Inline replacements for DRM_IOREMAP macros */ -static __inline__ void drm_core_ioremap(struct drm_map *map, - struct drm_device *dev) -{ - map->handle = drm_ioremap(map->offset, map->size, dev); -} - -#if 0 -static __inline__ void drm_core_ioremap_nocache(struct drm_map *map, - struct drm_device *dev) -{ - map->handle = drm_ioremap_nocache(map->offset, map->size, dev); -} -#endif /* 0 */ - -static __inline__ void drm_core_ioremapfree(struct drm_map *map, - struct drm_device *dev) -{ - if (map->handle && map->size) - drm_ioremapfree(map->handle, map->size, dev); -} +extern void drm_core_ioremap(struct drm_map *map, struct drm_device *dev); +extern void drm_core_ioremapfree(struct drm_map *map, struct drm_device *dev); static __inline__ struct drm_map *drm_core_findmap(struct drm_device *dev, unsigned int token) diff --git a/drivers/char/drm/drm_bufs.c b/drivers/char/drm/drm_bufs.c index 9f65f56..a6828cc 100644 --- a/drivers/char/drm/drm_bufs.c +++ b/drivers/char/drm/drm_bufs.c @@ -79,14 +79,14 @@ #endif if (!use_hashed_handle) { int ret; - hash->key = user_token; + hash->key = user_token >> PAGE_SHIFT; ret = drm_ht_insert_item(&dev->map_hash, hash); if (ret != -EINVAL) return ret; } return drm_ht_just_insert_please(&dev->map_hash, hash, user_token, 32 - PAGE_SHIFT - 3, - PAGE_SHIFT, DRM_MAP_HASH_OFFSET); + 0, DRM_MAP_HASH_OFFSET >> PAGE_SHIFT); } /** @@ -178,11 +178,11 @@ #endif } } if (map->type == _DRM_REGISTERS) - map->handle = drm_ioremap(map->offset, map->size, dev); + map->handle = ioremap(map->offset, map->size); break; case _DRM_SHM: - map->handle = vmalloc_32(map->size); + map->handle = vmalloc_user(map->size); DRM_DEBUG("%lu %d %p\n", map->size, drm_order(map->size), map->handle); if (!map->handle) { @@ -238,7 +238,7 @@ #endif list = drm_alloc(sizeof(*list), DRM_MEM_MAPS); if (!list) { if (map->type == _DRM_REGISTERS) - drm_ioremapfree(map->handle, map->size, dev); + iounmap(map->handle); drm_free(map, sizeof(*map), DRM_MEM_MAPS); return -EINVAL; } @@ -255,14 +255,14 @@ #endif ret = drm_map_handle(dev, &list->hash, user_token, 0); if (ret) { if (map->type == _DRM_REGISTERS) - drm_ioremapfree(map->handle, map->size, dev); + iounmap(map->handle); drm_free(map, sizeof(*map), DRM_MEM_MAPS); drm_free(list, sizeof(*list), DRM_MEM_MAPS); mutex_unlock(&dev->struct_mutex); return ret; } - list->user_token = list->hash.key; + list->user_token = list->hash.key << PAGE_SHIFT; mutex_unlock(&dev->struct_mutex); *maplist = list; @@ -347,7 +347,8 @@ int drm_rmmap_locked(drm_device_t *dev, if (r_list->map == map) { list_del(list); - drm_ht_remove_key(&dev->map_hash, r_list->user_token); + drm_ht_remove_key(&dev->map_hash, + r_list->user_token >> PAGE_SHIFT); drm_free(list, sizeof(*list), DRM_MEM_MAPS); break; } @@ -362,7 +363,7 @@ int drm_rmmap_locked(drm_device_t *dev, switch (map->type) { case _DRM_REGISTERS: - drm_ioremapfree(map->handle, map->size, dev); + iounmap(map->handle); /* FALLTHROUGH */ case _DRM_FRAME_BUFFER: if (drm_core_has_MTRR(dev) && map->mtrr >= 0) { diff --git a/drivers/char/drm/drm_drv.c b/drivers/char/drm/drm_drv.c index a70af0d..f5b9b24 100644 --- a/drivers/char/drm/drm_drv.c +++ b/drivers/char/drm/drm_drv.c @@ -371,7 +371,7 @@ void drm_exit(struct drm_driver *driver) EXPORT_SYMBOL(drm_exit); /** File operations structure */ -static struct file_operations drm_stub_fops = { +static const struct file_operations drm_stub_fops = { .owner = THIS_MODULE, .open = drm_stub_open }; diff --git a/drivers/char/drm/drm_memory.c b/drivers/char/drm/drm_memory.c index 5681cae..92a8670 100644 --- a/drivers/char/drm/drm_memory.c +++ b/drivers/char/drm/drm_memory.c @@ -79,28 +79,6 @@ void *drm_realloc(void *oldpt, size_t ol } #if __OS_HAS_AGP -/* - * Find the drm_map that covers the range [offset, offset+size). - */ -static drm_map_t *drm_lookup_map(unsigned long offset, - unsigned long size, drm_device_t * dev) -{ - struct list_head *list; - drm_map_list_t *r_list; - drm_map_t *map; - - list_for_each(list, &dev->maplist->head) { - r_list = (drm_map_list_t *) list; - map = r_list->map; - if (!map) - continue; - if (map->offset <= offset - && (offset + size) <= (map->offset + map->size)) - return map; - } - return NULL; -} - static void *agp_remap(unsigned long offset, unsigned long size, drm_device_t * dev) { @@ -169,13 +147,6 @@ int drm_unbind_agp(DRM_AGP_MEM * handle) } #else /* __OS_HAS_AGP */ - -static inline drm_map_t *drm_lookup_map(unsigned long offset, - unsigned long size, drm_device_t * dev) -{ - return NULL; -} - static inline void *agp_remap(unsigned long offset, unsigned long size, drm_device_t * dev) { @@ -184,57 +155,28 @@ static inline void *agp_remap(unsigned l #endif /* agp */ -void *drm_ioremap(unsigned long offset, unsigned long size, - drm_device_t * dev) -{ - if (drm_core_has_AGP(dev) && dev->agp && dev->agp->cant_use_aperture) { - drm_map_t *map = drm_lookup_map(offset, size, dev); - - if (map && map->type == _DRM_AGP) - return agp_remap(offset, size, dev); - } - return ioremap(offset, size); -} -EXPORT_SYMBOL(drm_ioremap); +#endif /* debug_memory */ -#if 0 -void *drm_ioremap_nocache(unsigned long offset, - unsigned long size, drm_device_t * dev) +void drm_core_ioremap(struct drm_map *map, struct drm_device *dev) { - if (drm_core_has_AGP(dev) && dev->agp && dev->agp->cant_use_aperture) { - drm_map_t *map = drm_lookup_map(offset, size, dev); - - if (map && map->type == _DRM_AGP) - return agp_remap(offset, size, dev); - } - return ioremap_nocache(offset, size); + if (drm_core_has_AGP(dev) && + dev->agp && dev->agp->cant_use_aperture && map->type == _DRM_AGP) + map->handle = agp_remap(map->offset, map->size, dev); + else + map->handle = ioremap(map->offset, map->size); } -#endif /* 0 */ +EXPORT_SYMBOL(drm_core_ioremap); -void drm_ioremapfree(void *pt, unsigned long size, - drm_device_t * dev) +void drm_core_ioremapfree(struct drm_map *map, struct drm_device *dev) { - /* - * This is a bit ugly. It would be much cleaner if the DRM API would use separate - * routines for handling mappings in the AGP space. Hopefully this can be done in - * a future revision of the interface... - */ - if (drm_core_has_AGP(dev) && dev->agp && dev->agp->cant_use_aperture - && ((unsigned long)pt >= VMALLOC_START - && (unsigned long)pt < VMALLOC_END)) { - unsigned long offset; - drm_map_t *map; - - offset = drm_follow_page(pt) | ((unsigned long)pt & ~PAGE_MASK); - map = drm_lookup_map(offset, size, dev); - if (map && map->type == _DRM_AGP) { - vunmap(pt); - return; - } - } - - iounmap(pt); + if (!map->handle || !map->size) + return; + + if (drm_core_has_AGP(dev) && + dev->agp && dev->agp->cant_use_aperture && map->type == _DRM_AGP) + vunmap(map->handle); + else + iounmap(map->handle); } -EXPORT_SYMBOL(drm_ioremapfree); +EXPORT_SYMBOL(drm_core_ioremapfree); -#endif /* debug_memory */ diff --git a/drivers/char/drm/drm_memory.h b/drivers/char/drm/drm_memory.h index f1b97af..63e425b 100644 --- a/drivers/char/drm/drm_memory.h +++ b/drivers/char/drm/drm_memory.h @@ -56,26 +56,6 @@ # define PAGE_AGP PAGE_KERNEL # endif #endif -static inline unsigned long drm_follow_page(void *vaddr) -{ - pgd_t *pgd = pgd_offset_k((unsigned long)vaddr); - pud_t *pud = pud_offset(pgd, (unsigned long)vaddr); - pmd_t *pmd = pmd_offset(pud, (unsigned long)vaddr); - pte_t *ptep = pte_offset_kernel(pmd, (unsigned long)vaddr); - return pte_pfn(*ptep) << PAGE_SHIFT; -} - #else /* __OS_HAS_AGP */ -static inline unsigned long drm_follow_page(void *vaddr) -{ - return 0; -} - #endif - -void *drm_ioremap(unsigned long offset, unsigned long size, - drm_device_t * dev); - -void drm_ioremapfree(void *pt, unsigned long size, - drm_device_t * dev); diff --git a/drivers/char/drm/drm_memory_debug.h b/drivers/char/drm/drm_memory_debug.h index 74581af..6463271 100644 --- a/drivers/char/drm/drm_memory_debug.h +++ b/drivers/char/drm/drm_memory_debug.h @@ -205,76 +205,6 @@ void drm_free (void *pt, size_t size, in } } -void *drm_ioremap (unsigned long offset, unsigned long size, - drm_device_t * dev) { - void *pt; - - if (!size) { - DRM_MEM_ERROR(DRM_MEM_MAPPINGS, - "Mapping 0 bytes at 0x%08lx\n", offset); - return NULL; - } - - if (!(pt = drm_ioremap(offset, size, dev))) { - spin_lock(&drm_mem_lock); - ++drm_mem_stats[DRM_MEM_MAPPINGS].fail_count; - spin_unlock(&drm_mem_lock); - return NULL; - } - spin_lock(&drm_mem_lock); - ++drm_mem_stats[DRM_MEM_MAPPINGS].succeed_count; - drm_mem_stats[DRM_MEM_MAPPINGS].bytes_allocated += size; - spin_unlock(&drm_mem_lock); - return pt; -} - -#if 0 -void *drm_ioremap_nocache (unsigned long offset, unsigned long size, - drm_device_t * dev) { - void *pt; - - if (!size) { - DRM_MEM_ERROR(DRM_MEM_MAPPINGS, - "Mapping 0 bytes at 0x%08lx\n", offset); - return NULL; - } - - if (!(pt = drm_ioremap_nocache(offset, size, dev))) { - spin_lock(&drm_mem_lock); - ++drm_mem_stats[DRM_MEM_MAPPINGS].fail_count; - spin_unlock(&drm_mem_lock); - return NULL; - } - spin_lock(&drm_mem_lock); - ++drm_mem_stats[DRM_MEM_MAPPINGS].succeed_count; - drm_mem_stats[DRM_MEM_MAPPINGS].bytes_allocated += size; - spin_unlock(&drm_mem_lock); - return pt; -} -#endif /* 0 */ - -void drm_ioremapfree (void *pt, unsigned long size, drm_device_t * dev) { - int alloc_count; - int free_count; - - if (!pt) - DRM_MEM_ERROR(DRM_MEM_MAPPINGS, - "Attempt to free NULL pointer\n"); - else - drm_ioremapfree(pt, size, dev); - - spin_lock(&drm_mem_lock); - drm_mem_stats[DRM_MEM_MAPPINGS].bytes_freed += size; - free_count = ++drm_mem_stats[DRM_MEM_MAPPINGS].free_count; - alloc_count = drm_mem_stats[DRM_MEM_MAPPINGS].succeed_count; - spin_unlock(&drm_mem_lock); - if (free_count > alloc_count) { - DRM_MEM_ERROR(DRM_MEM_MAPPINGS, - "Excess frees: %d frees, %d allocs\n", - free_count, alloc_count); - } -} - #if __OS_HAS_AGP DRM_AGP_MEM *drm_alloc_agp (drm_device_t *dev, int pages, u32 type) { diff --git a/drivers/char/drm/drm_mm.c b/drivers/char/drm/drm_mm.c index 617526b..9b46b85 100644 --- a/drivers/char/drm/drm_mm.c +++ b/drivers/char/drm/drm_mm.c @@ -42,36 +42,131 @@ */ #include "drmP.h" +#include + +unsigned long drm_mm_tail_space(drm_mm_t *mm) +{ + struct list_head *tail_node; + drm_mm_node_t *entry; + + tail_node = mm->ml_entry.prev; + entry = list_entry(tail_node, drm_mm_node_t, ml_entry); + if (!entry->free) + return 0; + + return entry->size; +} + +int drm_mm_remove_space_from_tail(drm_mm_t *mm, unsigned long size) +{ + struct list_head *tail_node; + drm_mm_node_t *entry; + + tail_node = mm->ml_entry.prev; + entry = list_entry(tail_node, drm_mm_node_t, ml_entry); + if (!entry->free) + return -ENOMEM; + + if (entry->size <= size) + return -ENOMEM; + + entry->size -= size; + return 0; +} + + +static int drm_mm_create_tail_node(drm_mm_t *mm, + unsigned long start, + unsigned long size) +{ + drm_mm_node_t *child; + + child = (drm_mm_node_t *) + drm_alloc(sizeof(*child), DRM_MEM_MM); + if (!child) + return -ENOMEM; + + child->free = 1; + child->size = size; + child->start = start; + child->mm = mm; + + list_add_tail(&child->ml_entry, &mm->ml_entry); + list_add_tail(&child->fl_entry, &mm->fl_entry); + + return 0; +} + + +int drm_mm_add_space_to_tail(drm_mm_t *mm, unsigned long size) +{ + struct list_head *tail_node; + drm_mm_node_t *entry; + + tail_node = mm->ml_entry.prev; + entry = list_entry(tail_node, drm_mm_node_t, ml_entry); + if (!entry->free) { + return drm_mm_create_tail_node(mm, entry->start + entry->size, size); + } + entry->size += size; + return 0; +} + +static drm_mm_node_t *drm_mm_split_at_start(drm_mm_node_t *parent, + unsigned long size) +{ + drm_mm_node_t *child; + + child = (drm_mm_node_t *) + drm_alloc(sizeof(*child), DRM_MEM_MM); + if (!child) + return NULL; + + INIT_LIST_HEAD(&child->fl_entry); + + child->free = 0; + child->size = size; + child->start = parent->start; + child->mm = parent->mm; + + list_add_tail(&child->ml_entry, &parent->ml_entry); + INIT_LIST_HEAD(&child->fl_entry); + + parent->size -= size; + parent->start += size; + return child; +} + + drm_mm_node_t *drm_mm_get_block(drm_mm_node_t * parent, unsigned long size, unsigned alignment) { + drm_mm_node_t *align_splitoff = NULL; drm_mm_node_t *child; + unsigned tmp = 0; if (alignment) - size += alignment - 1; + tmp = parent->start % alignment; + + if (tmp) { + align_splitoff = drm_mm_split_at_start(parent, alignment - tmp); + if (!align_splitoff) + return NULL; + } if (parent->size == size) { list_del_init(&parent->fl_entry); parent->free = 0; return parent; } else { - child = (drm_mm_node_t *) drm_alloc(sizeof(*child), DRM_MEM_MM); - if (!child) - return NULL; - - INIT_LIST_HEAD(&child->ml_entry); - INIT_LIST_HEAD(&child->fl_entry); + child = drm_mm_split_at_start(parent, size); + } - child->free = 0; - child->size = size; - child->start = parent->start; + if (align_splitoff) + drm_mm_put_block(align_splitoff); - list_add_tail(&child->ml_entry, &parent->ml_entry); - parent->size -= size; - parent->start += size; - } return child; } @@ -80,12 +175,12 @@ drm_mm_node_t *drm_mm_get_block(drm_mm_n * Otherwise add to the free stack. */ -void drm_mm_put_block(drm_mm_t * mm, drm_mm_node_t * cur) +void drm_mm_put_block(drm_mm_node_t * cur) { - drm_mm_node_t *list_root = &mm->root_node; + drm_mm_t *mm = cur->mm; struct list_head *cur_head = &cur->ml_entry; - struct list_head *root_head = &list_root->ml_entry; + struct list_head *root_head = &mm->ml_entry; drm_mm_node_t *prev_node = NULL; drm_mm_node_t *next_node; @@ -116,7 +211,7 @@ void drm_mm_put_block(drm_mm_t * mm, drm } if (!merged) { cur->free = 1; - list_add(&cur->fl_entry, &list_root->fl_entry); + list_add(&cur->fl_entry, &mm->fl_entry); } else { list_del(&cur->ml_entry); drm_free(cur, sizeof(*cur), DRM_MEM_MM); @@ -128,20 +223,30 @@ drm_mm_node_t *drm_mm_search_free(const unsigned alignment, int best_match) { struct list_head *list; - const struct list_head *free_stack = &mm->root_node.fl_entry; + const struct list_head *free_stack = &mm->fl_entry; drm_mm_node_t *entry; drm_mm_node_t *best; unsigned long best_size; + unsigned wasted; best = NULL; best_size = ~0UL; - if (alignment) - size += alignment - 1; - list_for_each(list, free_stack) { entry = list_entry(list, drm_mm_node_t, fl_entry); - if (entry->size >= size) { + wasted = 0; + + if (entry->size < size) + continue; + + if (alignment) { + register unsigned tmp = entry->start % alignment; + if (tmp) + wasted += alignment - tmp; + } + + + if (entry->size >= size + wasted) { if (!best_match) return entry; if (size < best_size) { @@ -154,40 +259,32 @@ drm_mm_node_t *drm_mm_search_free(const return best; } -int drm_mm_init(drm_mm_t * mm, unsigned long start, unsigned long size) +int drm_mm_clean(drm_mm_t * mm) { - drm_mm_node_t *child; - - INIT_LIST_HEAD(&mm->root_node.ml_entry); - INIT_LIST_HEAD(&mm->root_node.fl_entry); - child = (drm_mm_node_t *) drm_alloc(sizeof(*child), DRM_MEM_MM); - if (!child) - return -ENOMEM; - - INIT_LIST_HEAD(&child->ml_entry); - INIT_LIST_HEAD(&child->fl_entry); + struct list_head *head = &mm->ml_entry; - child->start = start; - child->size = size; - child->free = 1; + return (head->next->next == head); +} - list_add(&child->fl_entry, &mm->root_node.fl_entry); - list_add(&child->ml_entry, &mm->root_node.ml_entry); +int drm_mm_init(drm_mm_t * mm, unsigned long start, unsigned long size) +{ + INIT_LIST_HEAD(&mm->ml_entry); + INIT_LIST_HEAD(&mm->fl_entry); - return 0; + return drm_mm_create_tail_node(mm, start, size); } EXPORT_SYMBOL(drm_mm_init); void drm_mm_takedown(drm_mm_t * mm) { - struct list_head *bnode = mm->root_node.fl_entry.next; + struct list_head *bnode = mm->fl_entry.next; drm_mm_node_t *entry; entry = list_entry(bnode, drm_mm_node_t, fl_entry); - if (entry->ml_entry.next != &mm->root_node.ml_entry || - entry->fl_entry.next != &mm->root_node.fl_entry) { + if (entry->ml_entry.next != &mm->ml_entry || + entry->fl_entry.next != &mm->fl_entry) { DRM_ERROR("Memory manager not clean. Delaying takedown\n"); return; } diff --git a/drivers/char/drm/drm_pciids.h b/drivers/char/drm/drm_pciids.h index 09398d5..ad54b84 100644 --- a/drivers/char/drm/drm_pciids.h +++ b/drivers/char/drm/drm_pciids.h @@ -226,12 +226,14 @@ #define viadrv_PCI_IDS \ {0x1106, 0x3022, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \ {0x1106, 0x3118, PCI_ANY_ID, PCI_ANY_ID, 0, 0, VIA_PRO_GROUP_A}, \ {0x1106, 0x3122, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \ + {0x1106, 0x7204, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \ {0x1106, 0x7205, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \ {0x1106, 0x3108, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \ {0x1106, 0x3304, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \ {0x1106, 0x3157, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \ {0x1106, 0x3344, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \ - {0x1106, 0x7204, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \ + {0x1106, 0x3343, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \ + {0x1106, 0x3230, PCI_ANY_ID, PCI_ANY_ID, 0, 0, VIA_DX9_0}, \ {0, 0, 0} #define i810_PCI_IDS \ diff --git a/drivers/char/drm/drm_proc.c b/drivers/char/drm/drm_proc.c index 62d5fe1..7fd0da7 100644 --- a/drivers/char/drm/drm_proc.c +++ b/drivers/char/drm/drm_proc.c @@ -500,7 +500,7 @@ #endif for (pt = dev->vmalist; pt; pt = pt->next) { if (!(vma = pt->vma)) continue; - DRM_PROC_PRINT("\n%5d 0x%08lx-0x%08lx %c%c%c%c%c%c 0x%08lx", + DRM_PROC_PRINT("\n%5d 0x%08lx-0x%08lx %c%c%c%c%c%c 0x%08lx000", pt->pid, vma->vm_start, vma->vm_end, @@ -510,7 +510,7 @@ #endif vma->vm_flags & VM_MAYSHARE ? 's' : 'p', vma->vm_flags & VM_LOCKED ? 'l' : '-', vma->vm_flags & VM_IO ? 'i' : '-', - vma->vm_pgoff << PAGE_SHIFT); + vma->vm_pgoff); #if defined(__i386__) pgprot = pgprot_val(vma->vm_page_prot); diff --git a/drivers/char/drm/drm_sman.c b/drivers/char/drm/drm_sman.c index 19c81d2..e15db6d 100644 --- a/drivers/char/drm/drm_sman.c +++ b/drivers/char/drm/drm_sman.c @@ -101,10 +101,9 @@ static void *drm_sman_mm_allocate(void * static void drm_sman_mm_free(void *private, void *ref) { - drm_mm_t *mm = (drm_mm_t *) private; drm_mm_node_t *node = (drm_mm_node_t *) ref; - drm_mm_put_block(mm, node); + drm_mm_put_block(node); } static void drm_sman_mm_destroy(void *private) diff --git a/drivers/char/drm/drm_vm.c b/drivers/char/drm/drm_vm.c index b9cfc07..54a6328 100644 --- a/drivers/char/drm/drm_vm.c +++ b/drivers/char/drm/drm_vm.c @@ -70,7 +70,7 @@ static __inline__ struct page *drm_do_vm if (!dev->agp || !dev->agp->cant_use_aperture) goto vm_nopage_error; - if (drm_ht_find_item(&dev->map_hash, vma->vm_pgoff << PAGE_SHIFT, &hash)) + if (drm_ht_find_item(&dev->map_hash, vma->vm_pgoff, &hash)) goto vm_nopage_error; r_list = drm_hash_entry(hash, drm_map_list_t, hash); @@ -227,7 +227,7 @@ static void drm_vm_shm_close(struct vm_a map->size); DRM_DEBUG("mtrr_del = %d\n", retcode); } - drm_ioremapfree(map->handle, map->size, dev); + iounmap(map->handle); break; case _DRM_SHM: vfree(map->handle); @@ -463,8 +463,8 @@ static int drm_mmap_dma(struct file *fil lock_kernel(); dev = priv->head->dev; dma = dev->dma; - DRM_DEBUG("start = 0x%lx, end = 0x%lx, offset = 0x%lx\n", - vma->vm_start, vma->vm_end, vma->vm_pgoff << PAGE_SHIFT); + DRM_DEBUG("start = 0x%lx, end = 0x%lx, page offset = 0x%lx\n", + vma->vm_start, vma->vm_end, vma->vm_pgoff); /* Length must match exact page count */ if (!dma || (length >> PAGE_SHIFT) != dma->page_count) { @@ -537,8 +537,8 @@ int drm_mmap(struct file *filp, struct v unsigned long offset = 0; drm_hash_item_t *hash; - DRM_DEBUG("start = 0x%lx, end = 0x%lx, offset = 0x%lx\n", - vma->vm_start, vma->vm_end, vma->vm_pgoff << PAGE_SHIFT); + DRM_DEBUG("start = 0x%lx, end = 0x%lx, page offset = 0x%lx\n", + vma->vm_start, vma->vm_end, vma->vm_pgoff); if (!priv->authenticated) return -EACCES; @@ -547,7 +547,7 @@ int drm_mmap(struct file *filp, struct v * the AGP mapped at physical address 0 * --BenH. */ - if (!(vma->vm_pgoff << PAGE_SHIFT) + if (!vma->vm_pgoff #if __OS_HAS_AGP && (!dev->agp || dev->agp->agp_info.device->vendor != PCI_VENDOR_ID_APPLE) @@ -555,7 +555,7 @@ #endif ) return drm_mmap_dma(filp, vma); - if (drm_ht_find_item(&dev->map_hash, vma->vm_pgoff << PAGE_SHIFT, &hash)) { + if (drm_ht_find_item(&dev->map_hash, vma->vm_pgoff, &hash)) { DRM_ERROR("Could not find map\n"); return -EINVAL; } diff --git a/drivers/char/drm/ffb_context.c b/drivers/char/drm/ffb_context.c index 1383727..ac9ab40 100644 --- a/drivers/char/drm/ffb_context.c +++ b/drivers/char/drm/ffb_context.c @@ -7,7 +7,6 @@ * for authors. */ -#include #include #include "ffb.h" diff --git a/drivers/char/drm/ffb_drv.c b/drivers/char/drm/ffb_drv.c index dd45111..9a19879 100644 --- a/drivers/char/drm/ffb_drv.c +++ b/drivers/char/drm/ffb_drv.c @@ -9,7 +9,6 @@ #include "drmP.h" #include "ffb_drv.h" -#include #include #include #include diff --git a/drivers/char/drm/i810_dma.c b/drivers/char/drm/i810_dma.c index fa2de70..603d17f 100644 --- a/drivers/char/drm/i810_dma.c +++ b/drivers/char/drm/i810_dma.c @@ -112,7 +112,7 @@ static int i810_mmap_buffers(struct file return 0; } -static struct file_operations i810_buffer_fops = { +static const struct file_operations i810_buffer_fops = { .open = drm_open, .release = drm_release, .ioctl = drm_ioctl, @@ -219,8 +219,7 @@ static int i810_dma_cleanup(drm_device_t (drm_i810_private_t *) dev->dev_private; if (dev_priv->ring.virtual_start) { - drm_ioremapfree((void *)dev_priv->ring.virtual_start, - dev_priv->ring.Size, dev); + drm_core_ioremapfree(&dev_priv->ring.map, dev); } if (dev_priv->hw_status_page) { pci_free_consistent(dev->pdev, PAGE_SIZE, @@ -236,9 +235,9 @@ static int i810_dma_cleanup(drm_device_t for (i = 0; i < dma->buf_count; i++) { drm_buf_t *buf = dma->buflist[i]; drm_i810_buf_priv_t *buf_priv = buf->dev_private; + if (buf_priv->kernel_virtual && buf->total) - drm_ioremapfree(buf_priv->kernel_virtual, - buf->total, dev); + drm_core_ioremapfree(&buf_priv->map, dev); } } return 0; @@ -311,8 +310,15 @@ static int i810_freelist_init(drm_device *buf_priv->in_use = I810_BUF_FREE; - buf_priv->kernel_virtual = drm_ioremap(buf->bus_address, - buf->total, dev); + buf_priv->map.offset = buf->bus_address; + buf_priv->map.size = buf->total; + buf_priv->map.type = _DRM_AGP; + buf_priv->map.flags = 0; + buf_priv->map.mtrr = 0; + + drm_core_ioremap(&buf_priv->map, dev); + buf_priv->kernel_virtual = buf_priv->map.handle; + } return 0; } @@ -363,18 +369,24 @@ static int i810_dma_initialize(drm_devic dev_priv->ring.End = init->ring_end; dev_priv->ring.Size = init->ring_size; - dev_priv->ring.virtual_start = drm_ioremap(dev->agp->base + - init->ring_start, - init->ring_size, dev); + dev_priv->ring.map.offset = dev->agp->base + init->ring_start; + dev_priv->ring.map.size = init->ring_size; + dev_priv->ring.map.type = _DRM_AGP; + dev_priv->ring.map.flags = 0; + dev_priv->ring.map.mtrr = 0; - if (dev_priv->ring.virtual_start == NULL) { + drm_core_ioremap(&dev_priv->ring.map, dev); + + if (dev_priv->ring.map.handle == NULL) { dev->dev_private = (void *)dev_priv; i810_dma_cleanup(dev); DRM_ERROR("can not ioremap virtual address for" " ring buffer\n"); - return -ENOMEM; + return DRM_ERR(ENOMEM); } + dev_priv->ring.virtual_start = dev_priv->ring.map.handle; + dev_priv->ring.tail_mask = dev_priv->ring.Size - 1; dev_priv->w = init->w; diff --git a/drivers/char/drm/i810_drv.h b/drivers/char/drm/i810_drv.h index e8cf3ff..e6df49f 100644 --- a/drivers/char/drm/i810_drv.h +++ b/drivers/char/drm/i810_drv.h @@ -61,6 +61,7 @@ typedef struct drm_i810_buf_priv { int currently_mapped; void *virtual; void *kernel_virtual; + drm_local_map_t map; } drm_i810_buf_priv_t; typedef struct _drm_i810_ring_buffer { @@ -72,6 +73,7 @@ typedef struct _drm_i810_ring_buffer { int head; int tail; int space; + drm_local_map_t map; } drm_i810_ring_buffer_t; typedef struct drm_i810_private { diff --git a/drivers/char/drm/i830_dma.c b/drivers/char/drm/i830_dma.c index 4f0e574..3314a9f 100644 --- a/drivers/char/drm/i830_dma.c +++ b/drivers/char/drm/i830_dma.c @@ -114,7 +114,7 @@ static int i830_mmap_buffers(struct file return 0; } -static struct file_operations i830_buffer_fops = { +static const struct file_operations i830_buffer_fops = { .open = drm_open, .release = drm_release, .ioctl = drm_ioctl, @@ -223,8 +223,7 @@ static int i830_dma_cleanup(drm_device_t (drm_i830_private_t *) dev->dev_private; if (dev_priv->ring.virtual_start) { - drm_ioremapfree((void *)dev_priv->ring.virtual_start, - dev_priv->ring.Size, dev); + drm_core_ioremapfree(&dev_priv->ring.map, dev); } if (dev_priv->hw_status_page) { pci_free_consistent(dev->pdev, PAGE_SIZE, @@ -242,8 +241,7 @@ static int i830_dma_cleanup(drm_device_t drm_buf_t *buf = dma->buflist[i]; drm_i830_buf_priv_t *buf_priv = buf->dev_private; if (buf_priv->kernel_virtual && buf->total) - drm_ioremapfree(buf_priv->kernel_virtual, - buf->total, dev); + drm_core_ioremapfree(&buf_priv->map, dev); } } return 0; @@ -320,8 +318,14 @@ static int i830_freelist_init(drm_device *buf_priv->in_use = I830_BUF_FREE; - buf_priv->kernel_virtual = drm_ioremap(buf->bus_address, - buf->total, dev); + buf_priv->map.offset = buf->bus_address; + buf_priv->map.size = buf->total; + buf_priv->map.type = _DRM_AGP; + buf_priv->map.flags = 0; + buf_priv->map.mtrr = 0; + + drm_core_ioremap(&buf_priv->map, dev); + buf_priv->kernel_virtual = buf_priv->map.handle; } return 0; } @@ -373,18 +377,24 @@ static int i830_dma_initialize(drm_devic dev_priv->ring.End = init->ring_end; dev_priv->ring.Size = init->ring_size; - dev_priv->ring.virtual_start = drm_ioremap(dev->agp->base + - init->ring_start, - init->ring_size, dev); + dev_priv->ring.map.offset = dev->agp->base + init->ring_start; + dev_priv->ring.map.size = init->ring_size; + dev_priv->ring.map.type = _DRM_AGP; + dev_priv->ring.map.flags = 0; + dev_priv->ring.map.mtrr = 0; + + drm_core_ioremap(&dev_priv->ring.map, dev); - if (dev_priv->ring.virtual_start == NULL) { + if (dev_priv->ring.map.handle == NULL) { dev->dev_private = (void *)dev_priv; i830_dma_cleanup(dev); DRM_ERROR("can not ioremap virtual address for" " ring buffer\n"); - return -ENOMEM; + return DRM_ERR(ENOMEM); } + dev_priv->ring.virtual_start = dev_priv->ring.map.handle; + dev_priv->ring.tail_mask = dev_priv->ring.Size - 1; dev_priv->w = init->w; diff --git a/drivers/char/drm/i830_drv.h b/drivers/char/drm/i830_drv.h index 85bc5be..e91f94a 100644 --- a/drivers/char/drm/i830_drv.h +++ b/drivers/char/drm/i830_drv.h @@ -68,6 +68,7 @@ typedef struct drm_i830_buf_priv { int currently_mapped; void __user *virtual; void *kernel_virtual; + drm_local_map_t map; } drm_i830_buf_priv_t; typedef struct _drm_i830_ring_buffer { @@ -79,6 +80,7 @@ typedef struct _drm_i830_ring_buffer { int head; int tail; int space; + drm_local_map_t map; } drm_i830_ring_buffer_t; typedef struct drm_i830_private { diff --git a/drivers/char/drm/via_dma.c b/drivers/char/drm/via_dma.c index a691ae7..c0539c6 100644 --- a/drivers/char/drm/via_dma.c +++ b/drivers/char/drm/via_dma.c @@ -190,6 +190,11 @@ static int via_initialize(drm_device_t * return DRM_ERR(EFAULT); } + if (dev_priv->chipset == VIA_DX9_0) { + DRM_ERROR("AGP DMA is not supported on this chip\n"); + return DRM_ERR(EINVAL); + } + dev_priv->ring.map.offset = dev->agp->base + init->offset; dev_priv->ring.map.size = init->size; dev_priv->ring.map.type = 0; @@ -480,6 +485,7 @@ static int via_hook_segment(drm_via_priv VIA_WRITE(VIA_REG_TRANSET, (HC_ParaType_PreCR << 16)); VIA_WRITE(VIA_REG_TRANSPACE, pause_addr_hi); VIA_WRITE(VIA_REG_TRANSPACE, pause_addr_lo); + VIA_READ(VIA_REG_TRANSPACE); } } return paused; @@ -557,8 +563,9 @@ static void via_cmdbuf_start(drm_via_pri VIA_WRITE(VIA_REG_TRANSPACE, pause_addr_hi); VIA_WRITE(VIA_REG_TRANSPACE, pause_addr_lo); - + DRM_WRITEMEMORYBARRIER(); VIA_WRITE(VIA_REG_TRANSPACE, command | HC_HAGPCMNT_MASK); + VIA_READ(VIA_REG_TRANSPACE); } static void via_pad_cache(drm_via_private_t * dev_priv, int qwords) diff --git a/drivers/char/drm/via_dmablit.c b/drivers/char/drm/via_dmablit.c index 806f9ce..2881a06 100644 --- a/drivers/char/drm/via_dmablit.c +++ b/drivers/char/drm/via_dmablit.c @@ -218,7 +218,9 @@ via_fire_dmablit(drm_device_t *dev, drm_ VIA_WRITE(VIA_PCI_DMA_MR0 + engine*0x04, VIA_DMA_MR_CM | VIA_DMA_MR_TDIE); VIA_WRITE(VIA_PCI_DMA_BCR0 + engine*0x10, 0); VIA_WRITE(VIA_PCI_DMA_DPR0 + engine*0x10, vsg->chain_start); + DRM_WRITEMEMORYBARRIER(); VIA_WRITE(VIA_PCI_DMA_CSR0 + engine*0x04, VIA_DMA_CSR_DE | VIA_DMA_CSR_TS); + VIA_READ(VIA_PCI_DMA_CSR0 + engine*0x04); } /* @@ -374,10 +376,8 @@ via_dmablit_handler(drm_device_t *dev, i blitq->cur = cur; blitq->num_outstanding--; blitq->end = jiffies + DRM_HZ; - if (!timer_pending(&blitq->poll_timer)) { - blitq->poll_timer.expires = jiffies+1; - add_timer(&blitq->poll_timer); - } + if (!timer_pending(&blitq->poll_timer)) + mod_timer(&blitq->poll_timer, jiffies + 1); } else { if (timer_pending(&blitq->poll_timer)) { del_timer(&blitq->poll_timer); @@ -476,8 +476,7 @@ via_dmablit_timer(unsigned long data) via_dmablit_handler(dev, engine, 0); if (!timer_pending(&blitq->poll_timer)) { - blitq->poll_timer.expires = jiffies+1; - add_timer(&blitq->poll_timer); + mod_timer(&blitq->poll_timer, jiffies + 1); /* * Rerun handler to delete timer if engines are off, and @@ -572,9 +571,8 @@ via_init_dmablit(drm_device_t *dev) } DRM_INIT_WAITQUEUE(&blitq->busy_queue); INIT_WORK(&blitq->wq, via_dmablit_workqueue); - init_timer(&blitq->poll_timer); - blitq->poll_timer.function = &via_dmablit_timer; - blitq->poll_timer.data = (unsigned long) blitq; + setup_timer(&blitq->poll_timer, via_dmablit_timer, + (unsigned long)blitq); } } diff --git a/drivers/char/drm/via_drv.h b/drivers/char/drm/via_drv.h index d21b5b7..8b8778d 100644 --- a/drivers/char/drm/via_drv.h +++ b/drivers/char/drm/via_drv.h @@ -29,10 +29,10 @@ #define DRIVER_AUTHOR "Various" #define DRIVER_NAME "via" #define DRIVER_DESC "VIA Unichrome / Pro" -#define DRIVER_DATE "20060529" +#define DRIVER_DATE "20061227" #define DRIVER_MAJOR 2 -#define DRIVER_MINOR 10 +#define DRIVER_MINOR 11 #define DRIVER_PATCHLEVEL 0 #include "via_verifier.h" @@ -79,7 +79,7 @@ typedef struct drm_via_private { char pci_buf[VIA_PCI_BUF_SIZE]; const uint32_t *fire_offsets[VIA_FIRE_BUF_SIZE]; uint32_t num_fire_offsets; - int pro_group_a; + int chipset; drm_via_irq_t via_irqs[VIA_NUM_IRQS]; unsigned num_irqs; maskarray_t *irq_masks; @@ -96,8 +96,9 @@ typedef struct drm_via_private { } drm_via_private_t; enum via_family { - VIA_OTHER = 0, - VIA_PRO_GROUP_A, + VIA_OTHER = 0, /* Baseline */ + VIA_PRO_GROUP_A, /* Another video engine and DMA commands */ + VIA_DX9_0 /* Same video as pro_group_a, but 3D is unsupported */ }; /* VIA MMIO register access */ diff --git a/drivers/char/drm/via_irq.c b/drivers/char/drm/via_irq.c index c33d068..1ac5941 100644 --- a/drivers/char/drm/via_irq.c +++ b/drivers/char/drm/via_irq.c @@ -258,12 +258,16 @@ void via_driver_irq_preinstall(drm_devic dev_priv->irq_enable_mask = VIA_IRQ_VBLANK_ENABLE; dev_priv->irq_pending_mask = VIA_IRQ_VBLANK_PENDING; - dev_priv->irq_masks = (dev_priv->pro_group_a) ? - via_pro_group_a_irqs : via_unichrome_irqs; - dev_priv->num_irqs = (dev_priv->pro_group_a) ? - via_num_pro_group_a : via_num_unichrome; - dev_priv->irq_map = (dev_priv->pro_group_a) ? - via_irqmap_pro_group_a : via_irqmap_unichrome; + if (dev_priv->chipset == VIA_PRO_GROUP_A || + dev_priv->chipset == VIA_DX9_0) { + dev_priv->irq_masks = via_pro_group_a_irqs; + dev_priv->num_irqs = via_num_pro_group_a; + dev_priv->irq_map = via_irqmap_pro_group_a; + } else { + dev_priv->irq_masks = via_unichrome_irqs; + dev_priv->num_irqs = via_num_unichrome; + dev_priv->irq_map = via_irqmap_unichrome; + } for (i = 0; i < dev_priv->num_irqs; ++i) { atomic_set(&cur_irq->irq_received, 0); diff --git a/drivers/char/drm/via_map.c b/drivers/char/drm/via_map.c index 782011e..4e3fc07 100644 --- a/drivers/char/drm/via_map.c +++ b/drivers/char/drm/via_map.c @@ -106,8 +106,7 @@ int via_driver_load(drm_device_t *dev, u dev->dev_private = (void *)dev_priv; - if (chipset == VIA_PRO_GROUP_A) - dev_priv->pro_group_a = 1; + dev_priv->chipset = chipset; ret = drm_sman_init(&dev_priv->sman, 2, 12, 8); if (ret) { diff --git a/drivers/char/drm/via_verifier.c b/drivers/char/drm/via_verifier.c index 70c897c..2e7e080 100644 --- a/drivers/char/drm/via_verifier.c +++ b/drivers/char/drm/via_verifier.c @@ -306,6 +306,7 @@ static __inline__ int finish_current_seq unsigned long lo = ~0, hi = 0, tmp; uint32_t *addr, *pitch, *height, tex; unsigned i; + int npot; if (end > 9) end = 9; @@ -316,12 +317,15 @@ static __inline__ int finish_current_seq &(cur_seq->t_addr[tex = cur_seq->texture][start]); pitch = &(cur_seq->pitch[tex][start]); height = &(cur_seq->height[tex][start]); - + npot = cur_seq->tex_npot[tex]; for (i = start; i <= end; ++i) { tmp = *addr++; if (tmp < lo) lo = tmp; - tmp += (*height++ << *pitch++); + if (i == 0 && npot) + tmp += (*height++ * *pitch++); + else + tmp += (*height++ << *pitch++); if (tmp > hi) hi = tmp; } @@ -443,13 +447,21 @@ investigate_hazard(uint32_t cmd, hazard_ return 0; case check_texture_addr3: cur_seq->unfinished = tex_address; - tmp = ((cmd >> 24) - 0x2B); - cur_seq->pitch[cur_seq->texture][tmp] = - (cmd & 0x00F00000) >> 20; - if (!tmp && (cmd & 0x000FFFFF)) { - DRM_ERROR - ("Unimplemented texture level 0 pitch mode.\n"); - return 2; + tmp = ((cmd >> 24) - HC_SubA_HTXnL0Pit); + if (tmp == 0 && + (cmd & HC_HTXnEnPit_MASK)) { + cur_seq->pitch[cur_seq->texture][tmp] = + (cmd & HC_HTXnLnPit_MASK); + cur_seq->tex_npot[cur_seq->texture] = 1; + } else { + cur_seq->pitch[cur_seq->texture][tmp] = + (cmd & HC_HTXnLnPitE_MASK) >> HC_HTXnLnPitE_SHIFT; + cur_seq->tex_npot[cur_seq->texture] = 0; + if (cmd & 0x000FFFFF) { + DRM_ERROR + ("Unimplemented texture level 0 pitch mode.\n"); + return 2; + } } return 0; case check_texture_addr4: @@ -961,7 +973,13 @@ via_verify_command_stream(const uint32_t uint32_t cmd; const uint32_t *buf_end = buf + (size >> 2); verifier_state_t state = state_command; - int pro_group_a = dev_priv->pro_group_a; + int cme_video; + int supported_3d; + + cme_video = (dev_priv->chipset == VIA_PRO_GROUP_A || + dev_priv->chipset == VIA_DX9_0); + + supported_3d = dev_priv->chipset != VIA_DX9_0; hc_state->dev = dev; hc_state->unfinished = no_sequence; @@ -986,17 +1004,21 @@ via_verify_command_stream(const uint32_t state = via_check_vheader6(&buf, buf_end); break; case state_command: - if (HALCYON_HEADER2 == (cmd = *buf)) + if ((HALCYON_HEADER2 == (cmd = *buf)) && + supported_3d) state = state_header2; else if ((cmd & HALCYON_HEADER1MASK) == HALCYON_HEADER1) state = state_header1; - else if (pro_group_a + else if (cme_video && (cmd & VIA_VIDEOMASK) == VIA_VIDEO_HEADER5) state = state_vheader5; - else if (pro_group_a + else if (cme_video && (cmd & VIA_VIDEOMASK) == VIA_VIDEO_HEADER6) state = state_vheader6; - else { + else if ((cmd == HALCYON_HEADER2) && !supported_3d) { + DRM_ERROR("Accelerated 3D is not supported on this chipset yet.\n"); + state = state_error; + } else { DRM_ERROR ("Invalid / Unimplemented DMA HEADER command. 0x%x\n", cmd); diff --git a/drivers/char/drm/via_verifier.h b/drivers/char/drm/via_verifier.h index 256590f..b77f59d 100644 --- a/drivers/char/drm/via_verifier.h +++ b/drivers/char/drm/via_verifier.h @@ -43,6 +43,7 @@ typedef struct { uint32_t tex_level_lo[2]; uint32_t tex_level_hi[2]; uint32_t tex_palette_size[2]; + uint32_t tex_npot[2]; drm_via_sequence_t unfinished; int agp_texture; int multitex; diff --git a/drivers/char/ds1302.c b/drivers/char/ds1302.c index bcdb107..fada6dd 100644 --- a/drivers/char/ds1302.c +++ b/drivers/char/ds1302.c @@ -120,7 +120,6 @@ get_rtc_time(struct rtc_time *rtc_tm) unsigned long flags; local_irq_save(flags); - local_irq_disable(); rtc_tm->tm_sec = CMOS_READ(RTC_SECONDS); rtc_tm->tm_min = CMOS_READ(RTC_MINUTES); @@ -219,7 +218,6 @@ rtc_ioctl(struct inode *inode, struct fi BIN_TO_BCD(yrs); local_irq_save(flags); - local_irq_disable(); CMOS_WRITE(yrs, RTC_YEAR); CMOS_WRITE(mon, RTC_MONTH); CMOS_WRITE(day, RTC_DAY_OF_MONTH); diff --git a/drivers/char/ds1620.c b/drivers/char/ds1620.c index 48cb8f0..3d7efc2 100644 --- a/drivers/char/ds1620.c +++ b/drivers/char/ds1620.c @@ -3,7 +3,6 @@ * thermometer driver (as used in the Rebel.com NetWinder) */ #include -#include #include #include #include diff --git a/drivers/char/dsp56k.c b/drivers/char/dsp56k.c index 06f2dbf..db984e4 100644 --- a/drivers/char/dsp56k.c +++ b/drivers/char/dsp56k.c @@ -25,7 +25,6 @@ #include #include /* for kmalloc() and kfree() */ -#include /* for struct wait_queue etc */ #include #include #include diff --git a/drivers/char/dtlk.c b/drivers/char/dtlk.c index d4005e9..d8dbdb9 100644 --- a/drivers/char/dtlk.c +++ b/drivers/char/dtlk.c @@ -72,6 +72,7 @@ #define TRACE_TEXT(str) ((void) 0) #define TRACE_RET ((void) 0) #endif /* TRACING */ +static void dtlk_timer_tick(unsigned long data); static int dtlk_major; static int dtlk_port_lpc; @@ -81,7 +82,7 @@ static int dtlk_has_indexing; static unsigned int dtlk_portlist[] = {0x25e, 0x29e, 0x2de, 0x31e, 0x35e, 0x39e, 0}; static wait_queue_head_t dtlk_process_list; -static struct timer_list dtlk_timer; +static DEFINE_TIMER(dtlk_timer, dtlk_timer_tick, 0, 0); /* prototypes for file_operations struct */ static ssize_t dtlk_read(struct file *, char __user *, @@ -117,7 +118,6 @@ static char dtlk_write_tts(char); /* static void dtlk_handle_error(char, char, unsigned int); */ -static void dtlk_timer_tick(unsigned long data); static ssize_t dtlk_read(struct file *file, char __user *buf, size_t count, loff_t * ppos) @@ -318,7 +318,7 @@ static int dtlk_release(struct inode *in } TRACE_RET; - del_timer(&dtlk_timer); + del_timer_sync(&dtlk_timer); return 0; } @@ -336,8 +336,6 @@ static int __init dtlk_init(void) if (dtlk_dev_probe() == 0) printk(", MAJOR %d\n", dtlk_major); - init_timer(&dtlk_timer); - dtlk_timer.function = dtlk_timer_tick; init_waitqueue_head(&dtlk_process_list); return 0; diff --git a/drivers/char/epca.c b/drivers/char/epca.c index a0f822c..88fc24f 100644 --- a/drivers/char/epca.c +++ b/drivers/char/epca.c @@ -844,7 +844,6 @@ static void pc_flush_buffer(struct tty_s fepcmd(ch, STOUT, (unsigned) tail, 0, 0, 0); memoff(ch); spin_unlock_irqrestore(&epca_lock, flags); - wake_up_interruptible(&tty->write_wait); tty_wakeup(tty); } /* End pc_flush_buffer */ @@ -1795,7 +1794,6 @@ static void doevent(int crd) { /* Begin if LOWWAIT */ ch->statusflags &= ~LOWWAIT; tty_wakeup(tty); - wake_up_interruptible(&tty->write_wait); } /* End if LOWWAIT */ } else if (event & EMPTYTX_IND) { /* Begin EMPTYTX_IND */ /* This event is generated by setup_empty_event */ @@ -1803,7 +1801,6 @@ static void doevent(int crd) if (ch->statusflags & EMPTYWAIT) { /* Begin if EMPTYWAIT */ ch->statusflags &= ~EMPTYWAIT; tty_wakeup(tty); - wake_up_interruptible(&tty->write_wait); } /* End if EMPTYWAIT */ } /* End EMPTYTX_IND */ } /* End if valid tty */ diff --git a/drivers/char/generic_nvram.c b/drivers/char/generic_nvram.c index 43ff598..2398e86 100644 --- a/drivers/char/generic_nvram.c +++ b/drivers/char/generic_nvram.c @@ -117,7 +117,7 @@ #endif /* CONFIG_PPC_PMAC */ return 0; } -struct file_operations nvram_fops = { +const struct file_operations nvram_fops = { .owner = THIS_MODULE, .llseek = nvram_llseek, .read = read_nvram, diff --git a/drivers/char/generic_serial.c b/drivers/char/generic_serial.c index e769811..337bbcd 100644 --- a/drivers/char/generic_serial.c +++ b/drivers/char/generic_serial.c @@ -382,7 +382,6 @@ void gs_flush_buffer(struct tty_struct * port->xmit_cnt = port->xmit_head = port->xmit_tail = 0; spin_unlock_irqrestore (&port->driver_lock, flags); - wake_up_interruptible(&tty->write_wait); tty_wakeup(tty); func_exit (); } diff --git a/drivers/char/hangcheck-timer.c b/drivers/char/hangcheck-timer.c index 1aa93a7..ae76a9f 100644 --- a/drivers/char/hangcheck-timer.c +++ b/drivers/char/hangcheck-timer.c @@ -117,7 +117,7 @@ __setup("hcheck_reboot", hangcheck_parse __setup("hcheck_dump_tasks", hangcheck_parse_dump_tasks); #endif /* not MODULE */ -#if defined(CONFIG_X86_64) || defined(CONFIG_S390) +#if defined(CONFIG_S390) # define HAVE_MONOTONIC # define TIMER_FREQ 1000000000ULL #elif defined(CONFIG_IA64) diff --git a/drivers/char/hpet.c b/drivers/char/hpet.c index 20dc3be..0be700f 100644 --- a/drivers/char/hpet.c +++ b/drivers/char/hpet.c @@ -703,7 +703,7 @@ int hpet_control(struct hpet_task *tp, u static ctl_table hpet_table[] = { { - .ctl_name = 1, + .ctl_name = CTL_UNNUMBERED, .procname = "max-user-freq", .data = &hpet_max_freq, .maxlen = sizeof(int), @@ -715,7 +715,7 @@ static ctl_table hpet_table[] = { static ctl_table hpet_root[] = { { - .ctl_name = 1, + .ctl_name = CTL_UNNUMBERED, .procname = "hpet", .maxlen = 0, .mode = 0555, @@ -1018,7 +1018,7 @@ static int __init hpet_init(void) if (result < 0) return -ENODEV; - sysctl_header = register_sysctl_table(dev_root, 0); + sysctl_header = register_sysctl_table(dev_root); result = acpi_bus_register_driver(&hpet_acpi_driver); if (result < 0) { diff --git a/drivers/char/hvc_beat.c b/drivers/char/hvc_beat.c new file mode 100644 index 0000000..6f019f1 --- /dev/null +++ b/drivers/char/hvc_beat.c @@ -0,0 +1,134 @@ +/* + * Beat hypervisor console driver + * + * (C) Copyright 2006 TOSHIBA CORPORATION + * + * This code is based on drivers/char/hvc_rtas.c: + * (C) Copyright IBM Corporation 2001-2005 + * (C) Copyright Red Hat, Inc. 2005 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "hvc_console.h" + +extern int64_t beat_get_term_char(uint64_t, uint64_t *, uint64_t *, uint64_t *); +extern int64_t beat_put_term_char(uint64_t, uint64_t, uint64_t, uint64_t); + +struct hvc_struct *hvc_beat_dev = NULL; + +/* bug: only one queue is available regardless of vtermno */ +static int hvc_beat_get_chars(uint32_t vtermno, char *buf, int cnt) +{ + static unsigned char q[sizeof(unsigned long) * 2] + __attribute__((aligned(sizeof(unsigned long)))); + static int qlen = 0; + unsigned long got; + +again: + if (qlen) { + if (qlen > cnt) { + memcpy(buf, q, cnt); + qlen -= cnt; + memmove(q + cnt, q, qlen); + return cnt; + } else { /* qlen <= cnt */ + int r; + + memcpy(buf, q, qlen); + r = qlen; + qlen = 0; + return r; + } + } + if (beat_get_term_char(vtermno, &got, + ((unsigned long *)q), ((unsigned long *)q) + 1) == 0) { + qlen = got; + goto again; + } + return 0; +} + +static int hvc_beat_put_chars(uint32_t vtermno, const char *buf, int cnt) +{ + unsigned long kb[2]; + int rest, nlen; + + for (rest = cnt; rest > 0; rest -= nlen) { + nlen = (rest > 16) ? 16 : rest; + memcpy(kb, buf, nlen); + beat_put_term_char(vtermno, rest, kb[0], kb[1]); + rest -= nlen; + } + return cnt; +} + +static struct hv_ops hvc_beat_get_put_ops = { + .get_chars = hvc_beat_get_chars, + .put_chars = hvc_beat_put_chars, +}; + +static int hvc_beat_useit = 1; + +static int hvc_beat_config(char *p) +{ + hvc_beat_useit = simple_strtoul(p, NULL, 0); + return 0; +} + +static int hvc_beat_console_init(void) +{ + if (hvc_beat_useit && machine_is_compatible("Beat")) { + hvc_instantiate(0, 0, &hvc_beat_get_put_ops); + } + return 0; +} + +/* temp */ +static int hvc_beat_init(void) +{ + struct hvc_struct *hp; + + if (!firmware_has_feature(FW_FEATURE_BEAT)) + return -ENODEV; + + hp = hvc_alloc(0, NO_IRQ, &hvc_beat_get_put_ops, 16); + if (IS_ERR(hp)) + return PTR_ERR(hp); + hvc_beat_dev = hp; + return 0; +} + +static void __exit hvc_beat_exit(void) +{ + if (hvc_beat_dev) + hvc_remove(hvc_beat_dev); +} + +module_init(hvc_beat_init); +module_exit(hvc_beat_exit); + +__setup("hvc_beat=", hvc_beat_config); + +console_initcall(hvc_beat_console_init); diff --git a/drivers/char/hvsi.c b/drivers/char/hvsi.c index d780683..50315d6 100644 --- a/drivers/char/hvsi.c +++ b/drivers/char/hvsi.c @@ -39,7 +39,6 @@ #include #include #include #include -#include #include #include #include diff --git a/drivers/char/hw_random/intel-rng.c b/drivers/char/hw_random/intel-rng.c index f22e78e..cc1046e 100644 --- a/drivers/char/hw_random/intel-rng.c +++ b/drivers/char/hw_random/intel-rng.c @@ -96,49 +96,49 @@ #define INTEL_FWH_DEVICE_CODE_4M 0xad */ static const struct pci_device_id pci_tbl[] = { /* AA - { 0x8086, 0x2418, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0, }, */ - { 0x8086, 0x2410, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0, }, /* AA */ + { PCI_DEVICE(0x8086, 0x2418) }, */ + { PCI_DEVICE(0x8086, 0x2410) }, /* AA */ /* AB - { 0x8086, 0x2428, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0, }, */ - { 0x8086, 0x2420, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0, }, /* AB */ + { PCI_DEVICE(0x8086, 0x2428) }, */ + { PCI_DEVICE(0x8086, 0x2420) }, /* AB */ /* ?? - { 0x8086, 0x2430, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0, }, */ + { PCI_DEVICE(0x8086, 0x2430) }, */ /* BAM, CAM, DBM, FBM, GxM - { 0x8086, 0x2448, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0, }, */ - { 0x8086, 0x244c, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0, }, /* BAM */ - { 0x8086, 0x248c, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0, }, /* CAM */ - { 0x8086, 0x24cc, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0, }, /* DBM */ - { 0x8086, 0x2641, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0, }, /* FBM */ - { 0x8086, 0x27b9, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0, }, /* GxM */ - { 0x8086, 0x27bd, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0, }, /* GxM DH */ + { PCI_DEVICE(0x8086, 0x2448) }, */ + { PCI_DEVICE(0x8086, 0x244c) }, /* BAM */ + { PCI_DEVICE(0x8086, 0x248c) }, /* CAM */ + { PCI_DEVICE(0x8086, 0x24cc) }, /* DBM */ + { PCI_DEVICE(0x8086, 0x2641) }, /* FBM */ + { PCI_DEVICE(0x8086, 0x27b9) }, /* GxM */ + { PCI_DEVICE(0x8086, 0x27bd) }, /* GxM DH */ /* BA, CA, DB, Ex, 6300, Fx, 631x/632x, Gx - { 0x8086, 0x244e, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0, }, */ - { 0x8086, 0x2440, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0, }, /* BA */ - { 0x8086, 0x2480, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0, }, /* CA */ - { 0x8086, 0x24c0, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0, }, /* DB */ - { 0x8086, 0x24d0, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0, }, /* Ex */ - { 0x8086, 0x25a1, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0, }, /* 6300 */ - { 0x8086, 0x2640, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0, }, /* Fx */ - { 0x8086, 0x2670, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0, }, /* 631x/632x */ - { 0x8086, 0x2671, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0, }, /* 631x/632x */ - { 0x8086, 0x2672, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0, }, /* 631x/632x */ - { 0x8086, 0x2673, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0, }, /* 631x/632x */ - { 0x8086, 0x2674, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0, }, /* 631x/632x */ - { 0x8086, 0x2675, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0, }, /* 631x/632x */ - { 0x8086, 0x2676, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0, }, /* 631x/632x */ - { 0x8086, 0x2677, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0, }, /* 631x/632x */ - { 0x8086, 0x2678, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0, }, /* 631x/632x */ - { 0x8086, 0x2679, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0, }, /* 631x/632x */ - { 0x8086, 0x267a, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0, }, /* 631x/632x */ - { 0x8086, 0x267b, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0, }, /* 631x/632x */ - { 0x8086, 0x267c, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0, }, /* 631x/632x */ - { 0x8086, 0x267d, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0, }, /* 631x/632x */ - { 0x8086, 0x267e, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0, }, /* 631x/632x */ - { 0x8086, 0x267f, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0, }, /* 631x/632x */ - { 0x8086, 0x27b8, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0, }, /* Gx */ + { PCI_DEVICE(0x8086, 0x244e) }, */ + { PCI_DEVICE(0x8086, 0x2440) }, /* BA */ + { PCI_DEVICE(0x8086, 0x2480) }, /* CA */ + { PCI_DEVICE(0x8086, 0x24c0) }, /* DB */ + { PCI_DEVICE(0x8086, 0x24d0) }, /* Ex */ + { PCI_DEVICE(0x8086, 0x25a1) }, /* 6300 */ + { PCI_DEVICE(0x8086, 0x2640) }, /* Fx */ + { PCI_DEVICE(0x8086, 0x2670) }, /* 631x/632x */ + { PCI_DEVICE(0x8086, 0x2671) }, /* 631x/632x */ + { PCI_DEVICE(0x8086, 0x2672) }, /* 631x/632x */ + { PCI_DEVICE(0x8086, 0x2673) }, /* 631x/632x */ + { PCI_DEVICE(0x8086, 0x2674) }, /* 631x/632x */ + { PCI_DEVICE(0x8086, 0x2675) }, /* 631x/632x */ + { PCI_DEVICE(0x8086, 0x2676) }, /* 631x/632x */ + { PCI_DEVICE(0x8086, 0x2677) }, /* 631x/632x */ + { PCI_DEVICE(0x8086, 0x2678) }, /* 631x/632x */ + { PCI_DEVICE(0x8086, 0x2679) }, /* 631x/632x */ + { PCI_DEVICE(0x8086, 0x267a) }, /* 631x/632x */ + { PCI_DEVICE(0x8086, 0x267b) }, /* 631x/632x */ + { PCI_DEVICE(0x8086, 0x267c) }, /* 631x/632x */ + { PCI_DEVICE(0x8086, 0x267d) }, /* 631x/632x */ + { PCI_DEVICE(0x8086, 0x267e) }, /* 631x/632x */ + { PCI_DEVICE(0x8086, 0x267f) }, /* 631x/632x */ + { PCI_DEVICE(0x8086, 0x27b8) }, /* Gx */ /* E - { 0x8086, 0x245e, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0, }, */ - { 0x8086, 0x2450, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0, }, /* E */ + { PCI_DEVICE(0x8086, 0x245e) }, */ + { PCI_DEVICE(0x8086, 0x2450) }, /* E */ { 0, }, /* terminate list */ }; MODULE_DEVICE_TABLE(pci, pci_tbl); diff --git a/drivers/char/ip2/i2lib.c b/drivers/char/ip2/i2lib.c index 7804576..f86fa0c 100644 --- a/drivers/char/ip2/i2lib.c +++ b/drivers/char/ip2/i2lib.c @@ -80,7 +80,7 @@ static int i2RetryFlushOutput(i2ChanStrP // Not a documented part of the library routines (careful...) but the Diagnostic // i2diag.c finds them useful to help the throughput in certain limited // single-threaded operations. -static void iiSendPendingMail(i2eBordStrPtr); +static inline void iiSendPendingMail(i2eBordStrPtr); static void serviceOutgoingFifo(i2eBordStrPtr); // Functions defined in ip2.c as part of interrupt handling @@ -150,6 +150,13 @@ i2Validate ( i2ChanStrPtr pCh ) == (CHANNEL_MAGIC | CHANNEL_SUPPORT)); } +static void iiSendPendingMail_t(unsigned long data) +{ + i2eBordStrPtr pB = (i2eBordStrPtr)data; + + iiSendPendingMail(pB); +} + //****************************************************************************** // Function: iiSendPendingMail(pB) // Parameters: Pointer to a board structure @@ -184,12 +191,9 @@ iiSendPendingMail(i2eBordStrPtr pB) /\/\|=mhw=|\/\/ */ if( ++pB->SendPendingRetry < 16 ) { - - init_timer( &(pB->SendPendingTimer) ); - pB->SendPendingTimer.expires = jiffies + 1; - pB->SendPendingTimer.function = (void*)(unsigned long)iiSendPendingMail; - pB->SendPendingTimer.data = (unsigned long)pB; - add_timer( &(pB->SendPendingTimer) ); + setup_timer(&pB->SendPendingTimer, + iiSendPendingMail_t, (unsigned long)pB); + mod_timer(&pB->SendPendingTimer, jiffies + 1); } else { printk( KERN_ERR "IP2: iiSendPendingMail unable to queue outbound mail\n" ); } @@ -1265,8 +1269,10 @@ i2RetryFlushOutput(i2ChanStrPtr pCh) // soon as all the data is completely sent. //****************************************************************************** static void -i2DrainWakeup(i2ChanStrPtr pCh) +i2DrainWakeup(unsigned long d) { + i2ChanStrPtr pCh = (i2ChanStrPtr)d; + ip2trace (CHANN, ITRC_DRAIN, 10, 1, pCh->BookmarkTimer.expires ); pCh->BookmarkTimer.expires = 0; @@ -1292,14 +1298,12 @@ i2DrainOutput(i2ChanStrPtr pCh, int time } if ((timeout > 0) && (pCh->BookmarkTimer.expires == 0 )) { // One per customer (channel) - init_timer( &(pCh->BookmarkTimer) ); - pCh->BookmarkTimer.expires = jiffies + timeout; - pCh->BookmarkTimer.function = (void*)(unsigned long)i2DrainWakeup; - pCh->BookmarkTimer.data = (unsigned long)pCh; + setup_timer(&pCh->BookmarkTimer, i2DrainWakeup, + (unsigned long)pCh); ip2trace (CHANN, ITRC_DRAIN, 1, 1, pCh->BookmarkTimer.expires ); - add_timer( &(pCh->BookmarkTimer) ); + mod_timer(&pCh->BookmarkTimer, jiffies + timeout); } i2QueueCommands( PTYPE_INLINE, pCh, -1, 1, CMD_BMARK_REQ ); @@ -1373,15 +1377,7 @@ ip2_owake( PTTY tp) ip2trace (CHANN, ITRC_SICMD, 10, 2, tp->flags, (1 << TTY_DO_WRITE_WAKEUP) ); - wake_up_interruptible ( &tp->write_wait ); - if ( ( tp->flags & (1 << TTY_DO_WRITE_WAKEUP) ) - && tp->ldisc.write_wakeup ) - { - (tp->ldisc.write_wakeup) ( tp ); - - ip2trace (CHANN, ITRC_SICMD, 11, 0 ); - - } + tty_wakeup(tp); } static inline void diff --git a/drivers/char/ip2/ip2main.c b/drivers/char/ip2/ip2main.c index 7c70310..83c7258 100644 --- a/drivers/char/ip2/ip2main.c +++ b/drivers/char/ip2/ip2main.c @@ -1271,8 +1271,8 @@ static void do_input(struct work_struct // code duplicated from n_tty (ldisc) static inline void isig(int sig, struct tty_struct *tty, int flush) { - if (tty->pgrp > 0) - kill_pg(tty->pgrp, sig, 1); + if (tty->pgrp) + kill_pgrp(tty->pgrp, sig, 1); if (flush || !L_NOFLSH(tty)) { if ( tty->ldisc.flush_buffer ) tty->ldisc.flush_buffer(tty); diff --git a/drivers/char/ipmi/ipmi_devintf.c b/drivers/char/ipmi/ipmi_devintf.c index ff2d052..c2aa44e 100644 --- a/drivers/char/ipmi/ipmi_devintf.c +++ b/drivers/char/ipmi/ipmi_devintf.c @@ -35,7 +35,6 @@ #include #include #include #include -#include #include #include #include diff --git a/drivers/char/ipmi/ipmi_msghandler.c b/drivers/char/ipmi/ipmi_msghandler.c index 53582b5..8e222f2 100644 --- a/drivers/char/ipmi/ipmi_msghandler.c +++ b/drivers/char/ipmi/ipmi_msghandler.c @@ -34,7 +34,6 @@ #include #include #include -#include #include #include #include @@ -406,13 +405,14 @@ static void clean_up_interface_data(ipmi free_smi_msg_list(&intf->waiting_msgs); free_recv_msg_list(&intf->waiting_events); - /* Wholesale remove all the entries from the list in the - * interface and wait for RCU to know that none are in use. */ + /* + * Wholesale remove all the entries from the list in the + * interface and wait for RCU to know that none are in use. + */ mutex_lock(&intf->cmd_rcvrs_mutex); - list_add_rcu(&list, &intf->cmd_rcvrs); - list_del_rcu(&intf->cmd_rcvrs); + INIT_LIST_HEAD(&list); + list_splice_init_rcu(&intf->cmd_rcvrs, &list, synchronize_rcu); mutex_unlock(&intf->cmd_rcvrs_mutex); - synchronize_rcu(); list_for_each_entry_safe(rcvr, rcvr2, &list, link) kfree(rcvr); @@ -451,7 +451,7 @@ int ipmi_smi_watcher_register(struct ipm mutex_lock(&ipmi_interfaces_mutex); /* Build a list of things to deliver. */ - list_for_each_entry_rcu(intf, &ipmi_interfaces, link) { + list_for_each_entry(intf, &ipmi_interfaces, link) { if (intf->intf_num == -1) continue; e = kmalloc(sizeof(*e), GFP_KERNEL); @@ -1886,7 +1886,6 @@ #ifdef CONFIG_PROC_FS kfree(entry); rv = -ENOMEM; } else { - file->nlink = 1; file->data = data; file->read_proc = read_proc; file->write_proc = write_proc; @@ -2760,9 +2759,15 @@ #endif synchronize_rcu(); kref_put(&intf->refcount, intf_free); } else { - /* After this point the interface is legal to use. */ + /* + * Keep memory order straight for RCU readers. Make + * sure everything else is committed to memory before + * setting intf_num to mark the interface valid. + */ + smp_wmb(); intf->intf_num = i; mutex_unlock(&ipmi_interfaces_mutex); + /* After this point the interface is legal to use. */ call_smi_watchers(i, intf->si_dev); mutex_unlock(&smi_watchers_mutex); } @@ -3923,6 +3928,14 @@ #ifdef CONFIG_IPMI_PANIC_STRING /* Interface was not ready yet. */ continue; + /* + * intf_num is used as an marker to tell if the + * interface is valid. Thus we need a read barrier to + * make sure data fetched before checking intf_num + * won't be used. + */ + smp_rmb(); + /* First job here is to figure out where to send the OEM events. There's no way in IPMI to send OEM events using an event send command, so we have to diff --git a/drivers/char/ipmi/ipmi_poweroff.c b/drivers/char/ipmi/ipmi_poweroff.c index 9d23136..e02893b 100644 --- a/drivers/char/ipmi/ipmi_poweroff.c +++ b/drivers/char/ipmi/ipmi_poweroff.c @@ -686,7 +686,7 @@ static int ipmi_poweroff_init (void) printk(KERN_INFO PFX "Power cycle is enabled.\n"); #ifdef CONFIG_PROC_FS - ipmi_table_header = register_sysctl_table(ipmi_root_table, 1); + ipmi_table_header = register_sysctl_table(ipmi_root_table); if (!ipmi_table_header) { printk(KERN_ERR PFX "Unable to register powercycle sysctl\n"); rv = -ENOMEM; diff --git a/drivers/char/ipmi/ipmi_si_intf.c b/drivers/char/ipmi/ipmi_si_intf.c index f1afd26..a7b33d2 100644 --- a/drivers/char/ipmi/ipmi_si_intf.c +++ b/drivers/char/ipmi/ipmi_si_intf.c @@ -1802,7 +1802,7 @@ static __devinit int try_init_acpi(struc return -ENODEV; } - if (spmi->addr.address_space_id == ACPI_ADR_SPACE_SYSTEM_MEMORY) + if (spmi->addr.space_id == ACPI_ADR_SPACE_SYSTEM_MEMORY) addr_space = IPMI_MEM_ADDR_SPACE; else addr_space = IPMI_IO_ADDR_SPACE; @@ -1848,19 +1848,19 @@ static __devinit int try_init_acpi(struc info->irq_setup = NULL; } - if (spmi->addr.register_bit_width) { + if (spmi->addr.bit_width) { /* A (hopefully) properly formed register bit width. */ - info->io.regspacing = spmi->addr.register_bit_width / 8; + info->io.regspacing = spmi->addr.bit_width / 8; } else { info->io.regspacing = DEFAULT_REGSPACING; } info->io.regsize = info->io.regspacing; - info->io.regshift = spmi->addr.register_bit_offset; + info->io.regshift = spmi->addr.bit_offset; - if (spmi->addr.address_space_id == ACPI_ADR_SPACE_SYSTEM_MEMORY) { + if (spmi->addr.space_id == ACPI_ADR_SPACE_SYSTEM_MEMORY) { info->io_setup = mem_setup; info->io.addr_type = IPMI_IO_ADDR_SPACE; - } else if (spmi->addr.address_space_id == ACPI_ADR_SPACE_SYSTEM_IO) { + } else if (spmi->addr.space_id == ACPI_ADR_SPACE_SYSTEM_IO) { info->io_setup = port_setup; info->io.addr_type = IPMI_MEM_ADDR_SPACE; } else { @@ -1888,10 +1888,8 @@ static __devinit void acpi_find_bmc(void return; for (i = 0; ; i++) { - status = acpi_get_firmware_table("SPMI", i+1, - ACPI_LOGICAL_ADDRESSING, - (struct acpi_table_header **) - &spmi); + status = acpi_get_table(ACPI_SIG_SPMI, i+1, + (struct acpi_table_header **)&spmi); if (status != AE_OK) return; diff --git a/drivers/char/isicom.c b/drivers/char/isicom.c index 01084ab..43ab9ed 100644 --- a/drivers/char/isicom.c +++ b/drivers/char/isicom.c @@ -183,7 +183,7 @@ static DEFINE_TIMER(tx, isicom_tx, 0, 0) /* baud index mappings from linux defns to isi */ static signed char linuxb_to_isib[] = { - -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 11, 13, 15, 16, 17, 18, 19 + -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 11, 13, 15, 16, 17, 18, 19, 20, 21 }; struct isi_board { @@ -213,8 +213,6 @@ struct isi_port { struct tty_struct * tty; wait_queue_head_t close_wait; wait_queue_head_t open_wait; - struct work_struct hangup_tq; - struct work_struct bh_tqueue; unsigned char * xmit_buf; int xmit_head; int xmit_tail; @@ -510,7 +508,7 @@ static void isicom_tx(unsigned long _dat if (port->xmit_cnt <= 0) port->status &= ~ISI_TXOK; if (port->xmit_cnt <= WAKEUP_CHARS) - schedule_work(&port->bh_tqueue); + tty_wakeup(tty); unlock_card(&isi_card[card]); } @@ -524,21 +522,6 @@ sched_again: mod_timer(&tx, jiffies + msecs_to_jiffies(10)); } -/* Interrupt handlers */ - - -static void isicom_bottomhalf(struct work_struct *work) -{ - struct isi_port *port = container_of(work, struct isi_port, bh_tqueue); - struct tty_struct *tty = port->tty; - - if (!tty) - return; - - tty_wakeup(tty); - wake_up_interruptible(&tty->write_wait); -} - /* * Main interrupt handler routine */ @@ -557,6 +540,11 @@ static irqreturn_t isicom_interrupt(int return IRQ_NONE; base = card->base; + + /* did the card interrupt us? */ + if (!(inw(base + 0x0e) & 0x02)) + return IRQ_NONE; + spin_lock(&card->card_lock); /* @@ -581,6 +569,7 @@ static irqreturn_t isicom_interrupt(int port = card->ports + channel; if (!(port->flags & ASYNC_INITIALIZED)) { outw(0x0000, base+0x04); /* enable interrupts */ + spin_unlock(&card->card_lock); return IRQ_HANDLED; } @@ -609,7 +598,7 @@ static irqreturn_t isicom_interrupt(int pr_dbg("interrupt: DCD->low.\n" ); port->status &= ~ISI_DCD; - schedule_work(&port->hangup_tq); + tty_hangup(tty); } } else if (header & ISI_DCD) { /* Carrier has been detected */ @@ -631,7 +620,7 @@ static irqreturn_t isicom_interrupt(int /* start tx ing */ port->status |= (ISI_TXOK | ISI_CTS); - schedule_work(&port->bh_tqueue); + tty_wakeup(tty); } } else if (!(header & ISI_CTS)) { port->tty->hw_stopped = 1; @@ -695,6 +684,7 @@ static irqreturn_t isicom_interrupt(int tty_flip_buffer_push(tty); } outw(0x0000, base+0x04); /* enable interrupts */ + spin_unlock(&card->card_lock); return IRQ_HANDLED; } @@ -720,7 +710,8 @@ static void isicom_config_port(struct is * respectively. */ - if (baud < 1 || baud > 2) + /* 1,2,3,4 => 57.6, 115.2, 230, 460 kbps resp. */ + if (baud < 1 || baud > 4) port->tty->termios->c_cflag &= ~CBAUDEX; else baud += 15; @@ -736,6 +727,10 @@ static void isicom_config_port(struct is baud++; /* 57.6 Kbps */ if ((port->flags & ASYNC_SPD_MASK) == ASYNC_SPD_VHI) baud +=2; /* 115 Kbps */ + if ((port->flags & ASYNC_SPD_MASK) == ASYNC_SPD_SHI) + baud += 3; /* 230 kbps*/ + if ((port->flags & ASYNC_SPD_MASK) == ASYNC_SPD_WARP) + baud += 4; /* 460 kbps*/ } if (linuxb_to_isib[baud] == -1) { /* hang up */ @@ -1460,17 +1455,6 @@ static void isicom_start(struct tty_stru port->status |= ISI_TXOK; } -/* hangup et all */ -static void do_isicom_hangup(struct work_struct *work) -{ - struct isi_port *port = container_of(work, struct isi_port, hangup_tq); - struct tty_struct *tty; - - tty = port->tty; - if (tty) - tty_hangup(tty); -} - static void isicom_hangup(struct tty_struct *tty) { struct isi_port *port = tty->driver_data; @@ -1503,7 +1487,6 @@ static void isicom_flush_buffer(struct t port->xmit_cnt = port->xmit_head = port->xmit_tail = 0; spin_unlock_irqrestore(&card->card_lock, flags); - wake_up_interruptible(&tty->write_wait); tty_wakeup(tty); } @@ -1536,7 +1519,7 @@ static int __devinit reset_card(struct p { struct isi_board *board = pci_get_drvdata(pdev); unsigned long base = board->base; - unsigned int portcount = 0; + unsigned int sig, portcount = 0; int retval = 0; dev_dbg(&pdev->dev, "ISILoad:Resetting Card%d at 0x%lx\n", card + 1, @@ -1544,27 +1527,35 @@ static int __devinit reset_card(struct p inw(base + 0x8); - mdelay(10); + msleep(10); outw(0, base + 0x8); /* Reset */ - msleep(3000); + msleep(1000); - *signature = inw(base + 0x4) & 0xff; + sig = inw(base + 0x4) & 0xff; + + if (sig != 0xa5 && sig != 0xbb && sig != 0xcc && sig != 0xdd && + sig != 0xee) { + dev_warn(&pdev->dev, "ISILoad:Card%u reset failure (Possible " + "bad I/O Port Address 0x%lx).\n", card + 1, base); + dev_dbg(&pdev->dev, "Sig=0x%x\n", sig); + retval = -EIO; + goto end; + } + + msleep(10); portcount = inw(base + 0x2); - if (!(inw(base + 0xe) & 0x1) || ((portcount != 0) && - (portcount != 4) && (portcount != 8))) { - dev_dbg(&pdev->dev, "base+0x2=0x%lx, base+0xe=0x%lx\n", - inw(base + 0x2), inw(base + 0xe)); - dev_err(&pdev->dev, "ISILoad:PCI Card%d reset failure " - "(Possible bad I/O Port Address 0x%lx).\n", - card + 1, base); + if (!inw(base + 0xe) & 0x1 || (portcount != 0 && portcount != 4 && + portcount != 8 && portcount != 16)) { + dev_err(&pdev->dev, "ISILoad:PCI Card%d reset failure.", + card + 1); retval = -EIO; goto end; } - switch (*signature) { + switch (sig) { case 0xa5: case 0xbb: case 0xdd: @@ -1572,16 +1563,13 @@ static int __devinit reset_card(struct p board->shift_count = 12; break; case 0xcc: + case 0xee: board->port_count = 16; board->shift_count = 11; break; - default: - dev_warn(&pdev->dev, "ISILoad:Card%d reset failure (Possible " - "bad I/O Port Address 0x%lx).\n", card + 1, base); - dev_dbg(&pdev->dev, "Sig=0x%lx\n", signature); - retval = -EIO; } dev_info(&pdev->dev, "-Done\n"); + *signature = sig; end: return retval; @@ -1757,7 +1745,7 @@ end: /* * Insmod can set static symbols so keep these static */ -static int card; +static unsigned int card_count; static int __devinit isicom_probe(struct pci_dev *pdev, const struct pci_device_id *ent) @@ -1767,7 +1755,7 @@ static int __devinit isicom_probe(struct u8 pciirq; struct isi_board *board = NULL; - if (card >= BOARD_COUNT) + if (card_count >= BOARD_COUNT) goto err; ioaddr = pci_resource_start(pdev, 3); @@ -1785,7 +1773,7 @@ static int __devinit isicom_probe(struct board->index = index; board->base = ioaddr; board->irq = pciirq; - card++; + card_count++; pci_set_drvdata(pdev, board); @@ -1795,7 +1783,7 @@ static int __devinit isicom_probe(struct "will be disabled.\n", board->base, board->base + 15, index + 1); retval = -EBUSY; - goto err; + goto errdec; } retval = request_irq(board->irq, isicom_interrupt, @@ -1824,8 +1812,10 @@ errunri: free_irq(board->irq, board); errunrr: pci_release_region(pdev, 3); -err: +errdec: board->base = 0; + card_count--; +err: return retval; } @@ -1839,6 +1829,8 @@ static void __devexit isicom_remove(stru free_irq(board->irq, board); pci_release_region(pdev, 3); + board->base = 0; + card_count--; } static int __init isicom_init(void) @@ -1846,8 +1838,6 @@ static int __init isicom_init(void) int retval, idx, channel; struct isi_port *port; - card = 0; - for(idx = 0; idx < BOARD_COUNT; idx++) { port = &isi_ports[idx * 16]; isi_card[idx].ports = port; @@ -1858,8 +1848,6 @@ static int __init isicom_init(void) port->channel = channel; port->close_delay = 50 * HZ/100; port->closing_wait = 3000 * HZ/100; - INIT_WORK(&port->hangup_tq, do_isicom_hangup); - INIT_WORK(&port->bh_tqueue, isicom_bottomhalf); port->status = 0; init_waitqueue_head(&port->open_wait); init_waitqueue_head(&port->close_wait); diff --git a/drivers/char/istallion.c b/drivers/char/istallion.c index 68645d3..7b279d1 100644 --- a/drivers/char/istallion.c +++ b/drivers/char/istallion.c @@ -2424,7 +2424,6 @@ static int stli_hostcmd(struct stlibrd * if (tty != NULL) { tty_wakeup(tty); EBRDENABLE(brdp); - wake_up_interruptible(&tty->write_wait); } } diff --git a/drivers/char/keyboard.c b/drivers/char/keyboard.c index 7a6c1c0..cb8d691 100644 --- a/drivers/char/keyboard.c +++ b/drivers/char/keyboard.c @@ -595,15 +595,8 @@ static void fn_spawn_con(struct vc_data static void fn_SAK(struct vc_data *vc) { - struct tty_struct *tty = vc->vc_tty; - - /* - * SAK should also work in all raw modes and reset - * them properly. - */ - if (tty) - do_SAK(tty); - reset_vc(vc); + struct work_struct *SAK_work = &vc_cons[fg_console].SAK_work; + schedule_work(SAK_work); } static void fn_null(struct vc_data *vc) diff --git a/drivers/char/mbcs.c b/drivers/char/mbcs.c index 0afb7ba..57f9115 100644 --- a/drivers/char/mbcs.c +++ b/drivers/char/mbcs.c @@ -46,7 +46,7 @@ LIST_HEAD(soft_list); /* * file operations */ -struct file_operations mbcs_ops = { +const struct file_operations mbcs_ops = { .open = mbcs_open, .llseek = mbcs_sram_llseek, .read = mbcs_sram_read, diff --git a/drivers/char/moxa.c b/drivers/char/moxa.c index f391a24..7dbaee8 100644 --- a/drivers/char/moxa.c +++ b/drivers/char/moxa.c @@ -11,15 +11,6 @@ * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ /* @@ -55,36 +46,20 @@ #include #include #include -#define MOXA_VERSION "5.1k" +#define MOXA_VERSION "5.1k" -#define MOXAMAJOR 172 -#define MOXACUMAJOR 173 +#define MOXAMAJOR 172 +#define MOXACUMAJOR 173 -#define put_to_user(arg1, arg2) put_user(arg1, (unsigned long *)arg2) -#define get_from_user(arg1, arg2) get_user(arg1, (unsigned int *)arg2) - -#define MAX_BOARDS 4 /* Don't change this value */ +#define MAX_BOARDS 4 /* Don't change this value */ #define MAX_PORTS_PER_BOARD 32 /* Don't change this value */ -#define MAX_PORTS 128 /* Don't change this value */ +#define MAX_PORTS (MAX_BOARDS * MAX_PORTS_PER_BOARD) /* * Define the Moxa PCI vendor and device IDs. */ -#define MOXA_BUS_TYPE_ISA 0 -#define MOXA_BUS_TYPE_PCI 1 - -#ifndef PCI_VENDOR_ID_MOXA -#define PCI_VENDOR_ID_MOXA 0x1393 -#endif -#ifndef PCI_DEVICE_ID_CP204J -#define PCI_DEVICE_ID_CP204J 0x2040 -#endif -#ifndef PCI_DEVICE_ID_C218 -#define PCI_DEVICE_ID_C218 0x2180 -#endif -#ifndef PCI_DEVICE_ID_C320 -#define PCI_DEVICE_ID_C320 0x3200 -#endif +#define MOXA_BUS_TYPE_ISA 0 +#define MOXA_BUS_TYPE_PCI 1 enum { MOXA_BOARD_C218_PCI = 1, @@ -105,47 +80,56 @@ static char *moxa_brdname[] = #ifdef CONFIG_PCI static struct pci_device_id moxa_pcibrds[] = { - { PCI_VENDOR_ID_MOXA, PCI_DEVICE_ID_C218, PCI_ANY_ID, PCI_ANY_ID, - 0, 0, MOXA_BOARD_C218_PCI }, - { PCI_VENDOR_ID_MOXA, PCI_DEVICE_ID_C320, PCI_ANY_ID, PCI_ANY_ID, - 0, 0, MOXA_BOARD_C320_PCI }, - { PCI_VENDOR_ID_MOXA, PCI_DEVICE_ID_CP204J, PCI_ANY_ID, PCI_ANY_ID, - 0, 0, MOXA_BOARD_CP204J }, + { PCI_DEVICE(PCI_VENDOR_ID_MOXA, PCI_DEVICE_ID_MOXA_C218), + .driver_data = MOXA_BOARD_C218_PCI }, + { PCI_DEVICE(PCI_VENDOR_ID_MOXA, PCI_DEVICE_ID_MOXA_C320), + .driver_data = MOXA_BOARD_C320_PCI }, + { PCI_DEVICE(PCI_VENDOR_ID_MOXA, PCI_DEVICE_ID_MOXA_CP204J), + .driver_data = MOXA_BOARD_CP204J }, { 0 } }; MODULE_DEVICE_TABLE(pci, moxa_pcibrds); #endif /* CONFIG_PCI */ -typedef struct _moxa_isa_board_conf { +struct moxa_isa_board_conf { int boardType; int numPorts; unsigned long baseAddr; -} moxa_isa_board_conf; +}; -static moxa_isa_board_conf moxa_isa_boards[] = +static struct moxa_isa_board_conf moxa_isa_boards[] = { /* {MOXA_BOARD_C218_ISA,8,0xDC000}, */ }; -typedef struct _moxa_pci_devinfo { - ushort busNum; - ushort devNum; - struct pci_dev *pdev; -} moxa_pci_devinfo; - -typedef struct _moxa_board_conf { +static struct moxa_board_conf { int boardType; int numPorts; unsigned long baseAddr; int busType; - moxa_pci_devinfo pciInfo; -} moxa_board_conf; -static moxa_board_conf moxa_boards[MAX_BOARDS]; -static void __iomem *moxaBaseAddr[MAX_BOARDS]; -static int loadstat[MAX_BOARDS]; + int loadstat; + + void __iomem *basemem; + void __iomem *intNdx; + void __iomem *intPend; + void __iomem *intTable; +} moxa_boards[MAX_BOARDS]; + +struct mxser_mstatus { + tcflag_t cflag; + int cts; + int dsr; + int ri; + int dcd; +}; + +struct moxaq_str { + int inq; + int outq; +}; -struct moxa_str { +struct moxa_port { int type; int port; int close_delay; @@ -159,18 +143,18 @@ struct moxa_str { int cflag; wait_queue_head_t open_wait; wait_queue_head_t close_wait; - struct work_struct tqueue; -}; -struct mxser_mstatus { - tcflag_t cflag; - int cts; - int dsr; - int ri; - int dcd; -}; + struct timer_list emptyTimer; -static struct mxser_mstatus GMStatus[MAX_PORTS]; + char chkPort; + char lineCtrl; + void __iomem *tableAddr; + long curBaud; + char DCDState; + char lowChkFlag; + + ushort breakCnt; +}; /* statusflags */ #define TXSTOPPED 0x1 @@ -178,25 +162,17 @@ #define LOWWAIT 0x2 #define EMPTYWAIT 0x4 #define THROTTLE 0x8 -/* event */ -#define MOXA_EVENT_HANGUP 1 - #define SERIAL_DO_RESTART - -#define SERIAL_TYPE_NORMAL 1 - #define WAKEUP_CHARS 256 -#define PORTNO(x) ((x)->index) - static int verbose = 0; static int ttymajor = MOXAMAJOR; /* Variables for insmod */ #ifdef MODULE -static int baseaddr[] = {0, 0, 0, 0}; -static int type[] = {0, 0, 0, 0}; -static int numports[] = {0, 0, 0, 0}; +static int baseaddr[4]; +static int type[4]; +static int numports[4]; #endif MODULE_AUTHOR("William Chen"); @@ -210,19 +186,9 @@ #endif module_param(ttymajor, int, 0); module_param(verbose, bool, 0644); -static struct tty_driver *moxaDriver; -static struct moxa_str moxaChannels[MAX_PORTS]; -static unsigned char *moxaXmitBuff; -static int moxaTimer_on; -static struct timer_list moxaTimer; -static int moxaEmptyTimer_on[MAX_PORTS]; -static struct timer_list moxaEmptyTimer[MAX_PORTS]; -static struct semaphore moxaBuffSem; - /* * static functions: */ -static void do_moxa_softint(struct work_struct *); static int moxa_open(struct tty_struct *, struct file *); static void moxa_close(struct tty_struct *, struct file *); static int moxa_write(struct tty_struct *, const unsigned char *, int); @@ -244,11 +210,11 @@ static int moxa_tiocmset(struct tty_stru static void moxa_poll(unsigned long); static void set_tty_param(struct tty_struct *); static int block_till_ready(struct tty_struct *, struct file *, - struct moxa_str *); + struct moxa_port *); static void setup_empty_event(struct tty_struct *); static void check_xmit_empty(unsigned long); -static void shut_down(struct moxa_str *); -static void receive_data(struct moxa_str *); +static void shut_down(struct moxa_port *); +static void receive_data(struct moxa_port *); /* * moxa board interface functions: */ @@ -278,8 +244,8 @@ static void MoxaPortTxDisable(int); static void MoxaPortTxEnable(int); static int MoxaPortResetBrkCnt(int); static void MoxaPortSendBreak(int, int); -static int moxa_get_serial_info(struct moxa_str *, struct serial_struct __user *); -static int moxa_set_serial_info(struct moxa_str *, struct serial_struct __user *); +static int moxa_get_serial_info(struct moxa_port *, struct serial_struct __user *); +static int moxa_set_serial_info(struct moxa_port *, struct serial_struct __user *); static void MoxaSetFifo(int port, int enable); static const struct tty_operations moxa_ops = { @@ -302,12 +268,41 @@ static const struct tty_operations moxa_ .tiocmset = moxa_tiocmset, }; +static struct tty_driver *moxaDriver; +static struct moxa_port moxa_ports[MAX_PORTS]; +static DEFINE_TIMER(moxaTimer, moxa_poll, 0, 0); static DEFINE_SPINLOCK(moxa_lock); #ifdef CONFIG_PCI -static int moxa_get_PCI_conf(struct pci_dev *p, int board_type, moxa_board_conf * board) +static int __devinit moxa_pci_probe(struct pci_dev *pdev, + const struct pci_device_id *ent) { - board->baseAddr = pci_resource_start (p, 2); + struct moxa_board_conf *board; + unsigned int i; + int board_type = ent->driver_data; + int retval; + + retval = pci_enable_device(pdev); + if (retval) + goto err; + + for (i = 0; i < MAX_BOARDS; i++) + if (moxa_boards[i].basemem == NULL) + break; + + retval = -ENODEV; + if (i >= MAX_BOARDS) { + if (verbose) + printk("More than %d MOXA Intellio family boards " + "found. Board is ignored.\n", MAX_BOARDS); + goto err; + } + + board = &moxa_boards[i]; + board->basemem = pci_iomap(pdev, 2, 0x4000); + if (board->basemem == NULL) + goto err; + board->boardType = board_type; switch (board_type) { case MOXA_BOARD_C218_ISA: @@ -323,27 +318,40 @@ static int moxa_get_PCI_conf(struct pci_ break; } board->busType = MOXA_BUS_TYPE_PCI; - board->pciInfo.busNum = p->bus->number; - board->pciInfo.devNum = p->devfn >> 3; - board->pciInfo.pdev = p; - /* don't lose the reference in the next pci_get_device iteration */ - pci_dev_get(p); + + pci_set_drvdata(pdev, board); return (0); +err: + return retval; } + +static void __devexit moxa_pci_remove(struct pci_dev *pdev) +{ + struct moxa_board_conf *brd = pci_get_drvdata(pdev); + + pci_iounmap(pdev, brd->basemem); + brd->basemem = NULL; +} + +static struct pci_driver moxa_pci_driver = { + .name = "moxa", + .id_table = moxa_pcibrds, + .probe = moxa_pci_probe, + .remove = __devexit_p(moxa_pci_remove) +}; #endif /* CONFIG_PCI */ static int __init moxa_init(void) { - int i, numBoards; - struct moxa_str *ch; + int i, numBoards, retval = 0; + struct moxa_port *ch; printk(KERN_INFO "MOXA Intellio family driver version %s\n", MOXA_VERSION); moxaDriver = alloc_tty_driver(MAX_PORTS + 1); if (!moxaDriver) return -ENOMEM; - init_MUTEX(&moxaBuffSem); moxaDriver->owner = THIS_MODULE; moxaDriver->name = "ttyMX"; moxaDriver->major = ttymajor; @@ -351,40 +359,25 @@ static int __init moxa_init(void) moxaDriver->type = TTY_DRIVER_TYPE_SERIAL; moxaDriver->subtype = SERIAL_TYPE_NORMAL; moxaDriver->init_termios = tty_std_termios; - moxaDriver->init_termios.c_iflag = 0; - moxaDriver->init_termios.c_oflag = 0; moxaDriver->init_termios.c_cflag = B9600 | CS8 | CREAD | CLOCAL | HUPCL; - moxaDriver->init_termios.c_lflag = 0; moxaDriver->init_termios.c_ispeed = 9600; moxaDriver->init_termios.c_ospeed = 9600; moxaDriver->flags = TTY_DRIVER_REAL_RAW; tty_set_operations(moxaDriver, &moxa_ops); - moxaXmitBuff = NULL; - - for (i = 0, ch = moxaChannels; i < MAX_PORTS; i++, ch++) { + for (i = 0, ch = moxa_ports; i < MAX_PORTS; i++, ch++) { ch->type = PORT_16550A; ch->port = i; - INIT_WORK(&ch->tqueue, do_moxa_softint); - ch->tty = NULL; ch->close_delay = 5 * HZ / 10; ch->closing_wait = 30 * HZ; - ch->count = 0; - ch->blocked_open = 0; ch->cflag = B9600 | CS8 | CREAD | CLOCAL | HUPCL; init_waitqueue_head(&ch->open_wait); init_waitqueue_head(&ch->close_wait); - } - for (i = 0; i < MAX_BOARDS; i++) { - moxa_boards[i].boardType = 0; - moxa_boards[i].numPorts = 0; - moxa_boards[i].baseAddr = 0; - moxa_boards[i].busType = 0; - moxa_boards[i].pciInfo.busNum = 0; - moxa_boards[i].pciInfo.devNum = 0; + setup_timer(&ch->emptyTimer, check_xmit_empty, + (unsigned long)ch); } - MoxaDriverInit(); + printk("Tty devices major number = %d\n", ttymajor); if (tty_register_driver(moxaDriver)) { @@ -392,18 +385,8 @@ static int __init moxa_init(void) put_tty_driver(moxaDriver); return -1; } - for (i = 0; i < MAX_PORTS; i++) { - init_timer(&moxaEmptyTimer[i]); - moxaEmptyTimer[i].function = check_xmit_empty; - moxaEmptyTimer[i].data = (unsigned long) & moxaChannels[i]; - moxaEmptyTimer_on[i] = 0; - } - init_timer(&moxaTimer); - moxaTimer.function = moxa_poll; - moxaTimer.expires = jiffies + (HZ / 50); - moxaTimer_on = 1; - add_timer(&moxaTimer); + mod_timer(&moxaTimer, jiffies + HZ / 50); /* Find the boards defined in source code */ numBoards = 0; @@ -451,35 +434,22 @@ #ifdef MODULE } } #endif - /* Find PCI boards here */ + #ifdef CONFIG_PCI - { - struct pci_dev *p = NULL; - int n = ARRAY_SIZE(moxa_pcibrds) - 1; - i = 0; - while (i < n) { - while ((p = pci_get_device(moxa_pcibrds[i].vendor, moxa_pcibrds[i].device, p))!=NULL) - { - if (pci_enable_device(p)) - continue; - if (numBoards >= MAX_BOARDS) { - if (verbose) - printk("More than %d MOXA Intellio family boards found. Board is ignored.", MAX_BOARDS); - } else { - moxa_get_PCI_conf(p, moxa_pcibrds[i].driver_data, - &moxa_boards[numBoards]); - numBoards++; - } - } - i++; - } + retval = pci_register_driver(&moxa_pci_driver); + if (retval) { + printk(KERN_ERR "Can't register moxa pci driver!\n"); + if (numBoards) + retval = 0; } #endif + for (i = 0; i < numBoards; i++) { - moxaBaseAddr[i] = ioremap((unsigned long) moxa_boards[i].baseAddr, 0x4000); + moxa_boards[i].basemem = ioremap(moxa_boards[i].baseAddr, + 0x4000); } - return (0); + return retval; } static void __exit moxa_exit(void) @@ -489,23 +459,22 @@ static void __exit moxa_exit(void) if (verbose) printk("Unloading module moxa ...\n"); - if (moxaTimer_on) - del_timer(&moxaTimer); + del_timer_sync(&moxaTimer); for (i = 0; i < MAX_PORTS; i++) - if (moxaEmptyTimer_on[i]) - del_timer(&moxaEmptyTimer[i]); + del_timer_sync(&moxa_ports[i].emptyTimer); if (tty_unregister_driver(moxaDriver)) printk("Couldn't unregister MOXA Intellio family serial driver\n"); put_tty_driver(moxaDriver); - for (i = 0; i < MAX_BOARDS; i++) { - if (moxaBaseAddr[i]) - iounmap(moxaBaseAddr[i]); - if (moxa_boards[i].busType == MOXA_BUS_TYPE_PCI) - pci_dev_put(moxa_boards[i].pciInfo.pdev); - } +#ifdef CONFIG_PCI + pci_unregister_driver(&moxa_pci_driver); +#endif + + for (i = 0; i < MAX_BOARDS; i++) + if (moxa_boards[i].basemem) + iounmap(moxa_boards[i].basemem); if (verbose) printk("Done\n"); @@ -514,28 +483,13 @@ static void __exit moxa_exit(void) module_init(moxa_init); module_exit(moxa_exit); -static void do_moxa_softint(struct work_struct *work) -{ - struct moxa_str *ch = container_of(work, struct moxa_str, tqueue); - struct tty_struct *tty; - - if (ch && (tty = ch->tty)) { - if (test_and_clear_bit(MOXA_EVENT_HANGUP, &ch->event)) { - tty_hangup(tty); /* FIXME: module removal race here - AKPM */ - wake_up_interruptible(&ch->open_wait); - ch->asyncflags &= ~ASYNC_NORMAL_ACTIVE; - } - } -} - static int moxa_open(struct tty_struct *tty, struct file *filp) { - struct moxa_str *ch; + struct moxa_port *ch; int port; int retval; - unsigned long page; - port = PORTNO(tty); + port = tty->index; if (port == MAX_PORTS) { return (0); } @@ -543,23 +497,8 @@ static int moxa_open(struct tty_struct * tty->driver_data = NULL; return (-ENODEV); } - down(&moxaBuffSem); - if (!moxaXmitBuff) { - page = get_zeroed_page(GFP_KERNEL); - if (!page) { - up(&moxaBuffSem); - return (-ENOMEM); - } - /* This test is guarded by the BuffSem so no longer needed - delete me in 2.5 */ - if (moxaXmitBuff) - free_page(page); - else - moxaXmitBuff = (unsigned char *) page; - } - up(&moxaBuffSem); - ch = &moxaChannels[port]; + ch = &moxa_ports[port]; ch->count++; tty->driver_data = ch; ch->tty = tty; @@ -585,10 +524,10 @@ static int moxa_open(struct tty_struct * static void moxa_close(struct tty_struct *tty, struct file *filp) { - struct moxa_str *ch; + struct moxa_port *ch; int port; - port = PORTNO(tty); + port = tty->index; if (port == MAX_PORTS) { return; } @@ -605,7 +544,7 @@ #endif if (tty_hung_up_p(filp)) { return; } - ch = (struct moxa_str *) tty->driver_data; + ch = (struct moxa_port *) tty->driver_data; if ((tty->count == 1) && (ch->count != 1)) { printk("moxa_close: bad serial port count; tty->count is 1, " @@ -626,8 +565,7 @@ #endif if (ch->asyncflags & ASYNC_INITIALIZED) { setup_empty_event(tty); tty_wait_until_sent(tty, 30 * HZ); /* 30 seconds timeout */ - moxaEmptyTimer_on[ch->port] = 0; - del_timer(&moxaEmptyTimer[ch->port]); + del_timer_sync(&moxa_ports[ch->port].emptyTimer); } shut_down(ch); MoxaPortFlushData(port, 2); @@ -652,11 +590,11 @@ #endif static int moxa_write(struct tty_struct *tty, const unsigned char *buf, int count) { - struct moxa_str *ch; + struct moxa_port *ch; int len, port; unsigned long flags; - ch = (struct moxa_str *) tty->driver_data; + ch = (struct moxa_port *) tty->driver_data; if (ch == NULL) return (0); port = ch->port; @@ -675,11 +613,11 @@ static int moxa_write(struct tty_struct static int moxa_write_room(struct tty_struct *tty) { - struct moxa_str *ch; + struct moxa_port *ch; if (tty->stopped) return (0); - ch = (struct moxa_str *) tty->driver_data; + ch = (struct moxa_port *) tty->driver_data; if (ch == NULL) return (0); return (MoxaPortTxFree(ch->port)); @@ -687,7 +625,7 @@ static int moxa_write_room(struct tty_st static void moxa_flush_buffer(struct tty_struct *tty) { - struct moxa_str *ch = (struct moxa_str *) tty->driver_data; + struct moxa_port *ch = (struct moxa_port *) tty->driver_data; if (ch == NULL) return; @@ -698,7 +636,7 @@ static void moxa_flush_buffer(struct tty static int moxa_chars_in_buffer(struct tty_struct *tty) { int chars; - struct moxa_str *ch = (struct moxa_str *) tty->driver_data; + struct moxa_port *ch = (struct moxa_port *) tty->driver_data; /* * Sigh...I have to check if driver_data is NULL here, because @@ -730,17 +668,16 @@ static void moxa_flush_chars(struct tty_ static void moxa_put_char(struct tty_struct *tty, unsigned char c) { - struct moxa_str *ch; + struct moxa_port *ch; int port; unsigned long flags; - ch = (struct moxa_str *) tty->driver_data; + ch = (struct moxa_port *) tty->driver_data; if (ch == NULL) return; port = ch->port; spin_lock_irqsave(&moxa_lock, flags); - moxaXmitBuff[0] = c; - MoxaPortWriteData(port, moxaXmitBuff, 1); + MoxaPortWriteData(port, &c, 1); spin_unlock_irqrestore(&moxa_lock, flags); /************************************************ if ( !(ch->statusflags & LOWWAIT) && (MoxaPortTxFree(port) <= 100) ) @@ -750,11 +687,11 @@ static void moxa_put_char(struct tty_str static int moxa_tiocmget(struct tty_struct *tty, struct file *file) { - struct moxa_str *ch = (struct moxa_str *) tty->driver_data; + struct moxa_port *ch = (struct moxa_port *) tty->driver_data; int port; int flag = 0, dtr, rts; - port = PORTNO(tty); + port = tty->index; if ((port != MAX_PORTS) && (!ch)) return (-EINVAL); @@ -776,11 +713,11 @@ static int moxa_tiocmget(struct tty_stru static int moxa_tiocmset(struct tty_struct *tty, struct file *file, unsigned int set, unsigned int clear) { - struct moxa_str *ch = (struct moxa_str *) tty->driver_data; + struct moxa_port *ch = (struct moxa_port *) tty->driver_data; int port; int dtr, rts; - port = PORTNO(tty); + port = tty->index; if ((port != MAX_PORTS) && (!ch)) return (-EINVAL); @@ -800,12 +737,12 @@ static int moxa_tiocmset(struct tty_stru static int moxa_ioctl(struct tty_struct *tty, struct file *file, unsigned int cmd, unsigned long arg) { - struct moxa_str *ch = (struct moxa_str *) tty->driver_data; + struct moxa_port *ch = (struct moxa_port *) tty->driver_data; register int port; void __user *argp = (void __user *)arg; int retval; - port = PORTNO(tty); + port = tty->index; if ((port != MAX_PORTS) && (!ch)) return (-EINVAL); @@ -853,14 +790,14 @@ static int moxa_ioctl(struct tty_struct static void moxa_throttle(struct tty_struct *tty) { - struct moxa_str *ch = (struct moxa_str *) tty->driver_data; + struct moxa_port *ch = (struct moxa_port *) tty->driver_data; ch->statusflags |= THROTTLE; } static void moxa_unthrottle(struct tty_struct *tty) { - struct moxa_str *ch = (struct moxa_str *) tty->driver_data; + struct moxa_port *ch = (struct moxa_port *) tty->driver_data; ch->statusflags &= ~THROTTLE; } @@ -868,7 +805,7 @@ static void moxa_unthrottle(struct tty_s static void moxa_set_termios(struct tty_struct *tty, struct ktermios *old_termios) { - struct moxa_str *ch = (struct moxa_str *) tty->driver_data; + struct moxa_port *ch = (struct moxa_port *) tty->driver_data; if (ch == NULL) return; @@ -880,7 +817,7 @@ static void moxa_set_termios(struct tty_ static void moxa_stop(struct tty_struct *tty) { - struct moxa_str *ch = (struct moxa_str *) tty->driver_data; + struct moxa_port *ch = (struct moxa_port *) tty->driver_data; if (ch == NULL) return; @@ -891,7 +828,7 @@ static void moxa_stop(struct tty_struct static void moxa_start(struct tty_struct *tty) { - struct moxa_str *ch = (struct moxa_str *) tty->driver_data; + struct moxa_port *ch = (struct moxa_port *) tty->driver_data; if (ch == NULL) return; @@ -905,7 +842,7 @@ static void moxa_start(struct tty_struct static void moxa_hangup(struct tty_struct *tty) { - struct moxa_str *ch = (struct moxa_str *) tty->driver_data; + struct moxa_port *ch = (struct moxa_port *) tty->driver_data; moxa_flush_buffer(tty); shut_down(ch); @@ -919,24 +856,20 @@ static void moxa_hangup(struct tty_struc static void moxa_poll(unsigned long ignored) { register int card; - struct moxa_str *ch; + struct moxa_port *ch; struct tty_struct *tp; int i, ports; - moxaTimer_on = 0; del_timer(&moxaTimer); if (MoxaDriverPoll() < 0) { - moxaTimer.function = moxa_poll; - moxaTimer.expires = jiffies + (HZ / 50); - moxaTimer_on = 1; - add_timer(&moxaTimer); + mod_timer(&moxaTimer, jiffies + HZ / 50); return; } for (card = 0; card < MAX_BOARDS; card++) { if ((ports = MoxaPortsOfCard(card)) <= 0) continue; - ch = &moxaChannels[card * MAX_PORTS_PER_BOARD]; + ch = &moxa_ports[card * MAX_PORTS_PER_BOARD]; for (i = 0; i < ports; i++, ch++) { if ((ch->asyncflags & ASYNC_INITIALIZED) == 0) continue; @@ -962,18 +895,16 @@ static void moxa_poll(unsigned long igno if (MoxaPortDCDON(ch->port)) wake_up_interruptible(&ch->open_wait); else { - set_bit(MOXA_EVENT_HANGUP, &ch->event); - schedule_work(&ch->tqueue); + tty_hangup(tp); + wake_up_interruptible(&ch->open_wait); + ch->asyncflags &= ~ASYNC_NORMAL_ACTIVE; } } } } } - moxaTimer.function = moxa_poll; - moxaTimer.expires = jiffies + (HZ / 50); - moxaTimer_on = 1; - add_timer(&moxaTimer); + mod_timer(&moxaTimer, jiffies + HZ / 50); } /******************************************************************************/ @@ -981,10 +912,10 @@ static void moxa_poll(unsigned long igno static void set_tty_param(struct tty_struct *tty) { register struct ktermios *ts; - struct moxa_str *ch; + struct moxa_port *ch; int rts, cts, txflow, rxflow, xany; - ch = (struct moxa_str *) tty->driver_data; + ch = (struct moxa_port *) tty->driver_data; ts = tty->termios; if (ts->c_cflag & CLOCAL) ch->asyncflags &= ~ASYNC_CHECK_CD; @@ -1004,7 +935,7 @@ static void set_tty_param(struct tty_str } static int block_till_ready(struct tty_struct *tty, struct file *filp, - struct moxa_str *ch) + struct moxa_port *ch) { DECLARE_WAITQUEUE(wait,current); unsigned long flags; @@ -1095,40 +1026,33 @@ #endif static void setup_empty_event(struct tty_struct *tty) { - struct moxa_str *ch = tty->driver_data; + struct moxa_port *ch = tty->driver_data; unsigned long flags; spin_lock_irqsave(&moxa_lock, flags); ch->statusflags |= EMPTYWAIT; - moxaEmptyTimer_on[ch->port] = 0; - del_timer(&moxaEmptyTimer[ch->port]); - moxaEmptyTimer[ch->port].expires = jiffies + HZ; - moxaEmptyTimer_on[ch->port] = 1; - add_timer(&moxaEmptyTimer[ch->port]); + mod_timer(&moxa_ports[ch->port].emptyTimer, jiffies + HZ); spin_unlock_irqrestore(&moxa_lock, flags); } static void check_xmit_empty(unsigned long data) { - struct moxa_str *ch; + struct moxa_port *ch; - ch = (struct moxa_str *) data; - moxaEmptyTimer_on[ch->port] = 0; - del_timer(&moxaEmptyTimer[ch->port]); + ch = (struct moxa_port *) data; + del_timer_sync(&moxa_ports[ch->port].emptyTimer); if (ch->tty && (ch->statusflags & EMPTYWAIT)) { if (MoxaPortTxQueue(ch->port) == 0) { ch->statusflags &= ~EMPTYWAIT; tty_wakeup(ch->tty); return; } - moxaEmptyTimer[ch->port].expires = jiffies + HZ; - moxaEmptyTimer_on[ch->port] = 1; - add_timer(&moxaEmptyTimer[ch->port]); + mod_timer(&moxa_ports[ch->port].emptyTimer, jiffies + HZ); } else ch->statusflags &= ~EMPTYWAIT; } -static void shut_down(struct moxa_str *ch) +static void shut_down(struct moxa_port *ch) { struct tty_struct *tp; @@ -1148,7 +1072,7 @@ static void shut_down(struct moxa_str *c ch->asyncflags &= ~ASYNC_INITIALIZED; } -static void receive_data(struct moxa_str *ch) +static void receive_data(struct moxa_port *ch) { struct tty_struct *tp; struct ktermios *ts; @@ -1465,35 +1389,21 @@ #define MX_PARODD 0xC0 /* * Query */ -#define QueryPort MAX_PORTS - - struct mon_str { int tick; int rxcnt[MAX_PORTS]; int txcnt[MAX_PORTS]; }; -typedef struct mon_str mon_st; #define DCD_changed 0x01 #define DCD_oldstate 0x80 static unsigned char moxaBuff[10240]; -static void __iomem *moxaIntNdx[MAX_BOARDS]; -static void __iomem *moxaIntPend[MAX_BOARDS]; -static void __iomem *moxaIntTable[MAX_BOARDS]; -static char moxaChkPort[MAX_PORTS]; -static char moxaLineCtrl[MAX_PORTS]; -static void __iomem *moxaTableAddr[MAX_PORTS]; -static long moxaCurBaud[MAX_PORTS]; -static char moxaDCDState[MAX_PORTS]; -static char moxaLowChkFlag[MAX_PORTS]; static int moxaLowWaterChk; static int moxaCard; -static mon_st moxaLog; -static int moxaFuncTout; -static ushort moxaBreakCnt[MAX_PORTS]; +static struct mon_str moxaLog; +static int moxaFuncTout = HZ / 2; static void moxadelay(int); static void moxafunc(void __iomem *, int, ushort); @@ -1514,16 +1424,18 @@ static int moxaloadc320(int, void __iome *****************************************************************************/ void MoxaDriverInit(void) { - int i; + struct moxa_port *p; + unsigned int i; moxaFuncTout = HZ / 2; /* 500 mini-seconds */ moxaCard = 0; moxaLog.tick = 0; moxaLowWaterChk = 0; for (i = 0; i < MAX_PORTS; i++) { - moxaChkPort[i] = 0; - moxaLowChkFlag[i] = 0; - moxaLineCtrl[i] = 0; + p = &moxa_ports[i]; + p->chkPort = 0; + p->lowChkFlag = 0; + p->lineCtrl = 0; moxaLog.rxcnt[i] = 0; moxaLog.txcnt[i] = 0; } @@ -1545,19 +1457,12 @@ #define MOXA_GET_MAJOR (MOXA + #define MOXA_GET_CUMAJOR (MOXA + 64) #define MOXA_GETMSTATUS (MOXA + 65) - -struct moxaq_str { - int inq; - int outq; -}; - struct dl_str { char __user *buf; int len; int cardno; }; -static struct moxaq_str temp_queue[MAX_PORTS]; static struct dl_str dltmp; void MoxaPortFlushData(int port, int mode) @@ -1565,10 +1470,10 @@ void MoxaPortFlushData(int port, int mod void __iomem *ofsAddr; if ((mode < 0) || (mode > 2)) return; - ofsAddr = moxaTableAddr[port]; + ofsAddr = moxa_ports[port].tableAddr; moxafunc(ofsAddr, FC_FlushQueue, mode); if (mode != 1) { - moxaLowChkFlag[port] = 0; + moxa_ports[port].lowChkFlag = 0; low_water_check(ofsAddr); } } @@ -1580,7 +1485,7 @@ int MoxaDriverIoctl(unsigned int cmd, un int MoxaPortTxQueue(int), MoxaPortRxQueue(int); void __user *argp = (void __user *)arg; - if (port == QueryPort) { + if (port == MAX_PORTS) { if ((cmd != MOXA_GET_CONF) && (cmd != MOXA_INIT_DRIVER) && (cmd != MOXA_LOAD_BIOS) && (cmd != MOXA_FIND_BOARD) && (cmd != MOXA_LOAD_C320B) && (cmd != MOXA_LOAD_CODE) && (cmd != MOXA_GETDATACOUNT) && @@ -1590,7 +1495,8 @@ int MoxaDriverIoctl(unsigned int cmd, un } switch (cmd) { case MOXA_GET_CONF: - if(copy_to_user(argp, &moxa_boards, MAX_BOARDS * sizeof(moxa_board_conf))) + if(copy_to_user(argp, &moxa_boards, MAX_BOARDS * + sizeof(struct moxa_board_conf))) return -EFAULT; return (0); case MOXA_INIT_DRIVER: @@ -1599,23 +1505,27 @@ int MoxaDriverIoctl(unsigned int cmd, un return (0); case MOXA_GETDATACOUNT: moxaLog.tick = jiffies; - if(copy_to_user(argp, &moxaLog, sizeof(mon_st))) + if(copy_to_user(argp, &moxaLog, sizeof(struct mon_str))) return -EFAULT; return (0); case MOXA_FLUSH_QUEUE: MoxaPortFlushData(port, arg); return (0); - case MOXA_GET_IOQUEUE: - for (i = 0; i < MAX_PORTS; i++) { - if (moxaChkPort[i]) { - temp_queue[i].inq = MoxaPortRxQueue(i); - temp_queue[i].outq = MoxaPortTxQueue(i); + case MOXA_GET_IOQUEUE: { + struct moxaq_str __user *argm = argp; + struct moxaq_str tmp; + + for (i = 0; i < MAX_PORTS; i++, argm++) { + memset(&tmp, 0, sizeof(tmp)); + if (moxa_ports[i].chkPort) { + tmp.inq = MoxaPortRxQueue(i); + tmp.outq = MoxaPortTxQueue(i); } + if (copy_to_user(argm, &tmp, sizeof(tmp))) + return -EFAULT; } - if(copy_to_user(argp, temp_queue, sizeof(struct moxaq_str) * MAX_PORTS)) - return -EFAULT; return (0); - case MOXA_GET_OQUEUE: + } case MOXA_GET_OQUEUE: i = MoxaPortTxQueue(port); return put_user(i, (unsigned long __user *)argp); case MOXA_GET_IQUEUE: @@ -1630,33 +1540,36 @@ int MoxaDriverIoctl(unsigned int cmd, un if(copy_to_user(argp, &i, sizeof(int))) return -EFAULT; return 0; - case MOXA_GETMSTATUS: - for (i = 0; i < MAX_PORTS; i++) { - GMStatus[i].ri = 0; - GMStatus[i].dcd = 0; - GMStatus[i].dsr = 0; - GMStatus[i].cts = 0; - if (!moxaChkPort[i]) { - continue; + case MOXA_GETMSTATUS: { + struct mxser_mstatus __user *argm = argp; + struct mxser_mstatus tmp; + struct moxa_port *p; + + for (i = 0; i < MAX_PORTS; i++, argm++) { + p = &moxa_ports[i]; + memset(&tmp, 0, sizeof(tmp)); + if (!p->chkPort) { + goto copy; } else { - status = MoxaPortLineStatus(moxaChannels[i].port); + status = MoxaPortLineStatus(p->port); if (status & 1) - GMStatus[i].cts = 1; + tmp.cts = 1; if (status & 2) - GMStatus[i].dsr = 1; + tmp.dsr = 1; if (status & 4) - GMStatus[i].dcd = 1; + tmp.dcd = 1; } - if (!moxaChannels[i].tty || !moxaChannels[i].tty->termios) - GMStatus[i].cflag = moxaChannels[i].cflag; + if (!p->tty || !p->tty->termios) + tmp.cflag = p->cflag; else - GMStatus[i].cflag = moxaChannels[i].tty->termios->c_cflag; + tmp.cflag = p->tty->termios->c_cflag; +copy: + if (copy_to_user(argm, &tmp, sizeof(tmp))) + return -EFAULT; } - if(copy_to_user(argp, GMStatus, sizeof(struct mxser_mstatus) * MAX_PORTS)) - return -EFAULT; return 0; - default: + } default: return (-ENOIOCTLCMD); case MOXA_LOAD_BIOS: case MOXA_FIND_BOARD: @@ -1694,6 +1607,7 @@ int MoxaDriverIoctl(unsigned int cmd, un int MoxaDriverPoll(void) { + struct moxa_board_conf *brd; register ushort temp; register int card; void __iomem *ofsAddr; @@ -1703,43 +1617,44 @@ int MoxaDriverPoll(void) if (moxaCard == 0) return (-1); for (card = 0; card < MAX_BOARDS; card++) { - if (loadstat[card] == 0) + brd = &moxa_boards[card]; + if (brd->loadstat == 0) continue; - if ((ports = moxa_boards[card].numPorts) == 0) + if ((ports = brd->numPorts) == 0) continue; - if (readb(moxaIntPend[card]) == 0xff) { - ip = moxaIntTable[card] + readb(moxaIntNdx[card]); + if (readb(brd->intPend) == 0xff) { + ip = brd->intTable + readb(brd->intNdx); p = card * MAX_PORTS_PER_BOARD; ports <<= 1; for (port = 0; port < ports; port += 2, p++) { if ((temp = readw(ip + port)) != 0) { writew(0, ip + port); - ofsAddr = moxaTableAddr[p]; + ofsAddr = moxa_ports[p].tableAddr; if (temp & IntrTx) writew(readw(ofsAddr + HostStat) & ~WakeupTx, ofsAddr + HostStat); if (temp & IntrBreak) { - moxaBreakCnt[p]++; + moxa_ports[p].breakCnt++; } if (temp & IntrLine) { if (readb(ofsAddr + FlagStat) & DCD_state) { - if ((moxaDCDState[p] & DCD_oldstate) == 0) - moxaDCDState[p] = (DCD_oldstate | + if ((moxa_ports[p].DCDState & DCD_oldstate) == 0) + moxa_ports[p].DCDState = (DCD_oldstate | DCD_changed); } else { - if (moxaDCDState[p] & DCD_oldstate) - moxaDCDState[p] = DCD_changed; + if (moxa_ports[p].DCDState & DCD_oldstate) + moxa_ports[p].DCDState = DCD_changed; } } } } - writeb(0, moxaIntPend[card]); + writeb(0, brd->intPend); } if (moxaLowWaterChk) { p = card * MAX_PORTS_PER_BOARD; for (port = 0; port < ports; port++, p++) { - if (moxaLowChkFlag[p]) { - moxaLowChkFlag[p] = 0; - ofsAddr = moxaTableAddr[p]; + if (moxa_ports[p].lowChkFlag) { + moxa_ports[p].lowChkFlag = 0; + ofsAddr = moxa_ports[p].tableAddr; low_water_check(ofsAddr); } } @@ -1767,9 +1682,7 @@ int MoxaPortsOfCard(int cardno) * 2. MoxaPortEnable(int port); * * 3. MoxaPortDisable(int port); * * 4. MoxaPortGetMaxBaud(int port); * - * 5. MoxaPortGetCurBaud(int port); * * 6. MoxaPortSetBaud(int port, long baud); * - * 7. MoxaPortSetMode(int port, int databit, int stopbit, int parity); * * 8. MoxaPortSetTermio(int port, unsigned char *termio); * * 9. MoxaPortGetLineOut(int port, int *dtrState, int *rtsState); * * 10. MoxaPortLineCtrl(int port, int dtrState, int rtsState); * @@ -1780,18 +1693,12 @@ int MoxaPortsOfCard(int cardno) * 15. MoxaPortFlushData(int port, int mode); * * 16. MoxaPortWriteData(int port, unsigned char * buffer, int length); * * 17. MoxaPortReadData(int port, struct tty_struct *tty); * - * 18. MoxaPortTxBufSize(int port); * - * 19. MoxaPortRxBufSize(int port); * * 20. MoxaPortTxQueue(int port); * * 21. MoxaPortTxFree(int port); * * 22. MoxaPortRxQueue(int port); * - * 23. MoxaPortRxFree(int port); * * 24. MoxaPortTxDisable(int port); * * 25. MoxaPortTxEnable(int port); * - * 26. MoxaPortGetBrkCnt(int port); * * 27. MoxaPortResetBrkCnt(int port); * - * 28. MoxaPortSetXonXoff(int port, int xonValue, int xoffValue); * - * 29. MoxaPortIsTxHold(int port); * * 30. MoxaPortSendBreak(int port, int ticks); * *****************************************************************************/ /* @@ -1878,15 +1785,6 @@ int MoxaPortsOfCard(int cardno) * 38400/57600/115200 bps * * - * Function 9: Get the current baud rate of this port. - * Syntax: - * long MoxaPortGetCurBaud(int port); - * int port : port number (0 - 127) - * - * return: 0 : this port is invalid - * 50 - 115200 bps - * - * * Function 10: Setting baud rate of this port. * Syntax: * long MoxaPortSetBaud(int port, long baud); @@ -1900,18 +1798,6 @@ int MoxaPortsOfCard(int cardno) * baud rate will be the maximun baud rate. * * - * Function 11: Setting the data-bits/stop-bits/parity of this port - * Syntax: - * int MoxaPortSetMode(int port, int databits, int stopbits, int parity); - * int port : port number (0 - 127) - * int databits : data bits (8/7/6/5) - * int stopbits : stop bits (2/1/0, 0 show 1.5 stop bits) - int parity : parity (0:None,1:Odd,2:Even,3:Mark,4:Space) - * - * return: -1 : invalid parameter - * 0 : setting O.K. - * - * * Function 12: Configure the port. * Syntax: * int MoxaPortSetTermio(int port, struct ktermios *termio, speed_t baud); @@ -2016,22 +1902,6 @@ int MoxaPortsOfCard(int cardno) * return: 0 - length : real read data length * * - * Function 22: Get the Tx buffer size of this port - * Syntax: - * int MoxaPortTxBufSize(int port); - * int port : port number (0 - 127) - * - * return: .. : Tx buffer size - * - * - * Function 23: Get the Rx buffer size of this port - * Syntax: - * int MoxaPortRxBufSize(int port); - * int port : port number (0 - 127) - * - * return: .. : Rx buffer size - * - * * Function 24: Get the Tx buffer current queued data bytes * Syntax: * int MoxaPortTxQueue(int port); @@ -2056,14 +1926,6 @@ int MoxaPortsOfCard(int cardno) * return: .. : Rx buffer current queued data bytes * * - * Function 27: Get the Rx buffer current free space - * Syntax: - * int MoxaPortRxFree(int port); - * int port : port number (0 - 127) - * - * return: .. : Rx buffer current free space - * - * * Function 28: Disable port data transmission. * Syntax: * void MoxaPortTxDisable(int port); @@ -2076,14 +1938,6 @@ int MoxaPortsOfCard(int cardno) * int port : port number (0 - 127) * * - * Function 30: Get the received BREAK signal count. - * Syntax: - * int MoxaPortGetBrkCnt(int port); - * int port : port number (0 - 127) - * - * return: 0 - .. : BREAK signal count - * - * * Function 31: Get the received BREAK signal count and reset it. * Syntax: * int MoxaPortResetBrkCnt(int port); @@ -2092,25 +1946,6 @@ int MoxaPortsOfCard(int cardno) * return: 0 - .. : BREAK signal count * * - * Function 32: Set the S/W flow control new XON/XOFF value, default - * XON is 0x11 & XOFF is 0x13. - * Syntax: - * void MoxaPortSetXonXoff(int port, int xonValue, int xoffValue); - * int port : port number (0 - 127) - * int xonValue : new XON value (0 - 255) - * int xoffValue : new XOFF value (0 - 255) - * - * - * Function 33: Check this port's transmission is hold by remote site - * because the flow control. - * Syntax: - * int MoxaPortIsTxHold(int port); - * int port : port number (0 - 127) - * - * return: 0 : normal - * 1 : hold by remote site - * - * * Function 34: Send out a BREAK signal. * Syntax: * void MoxaPortSendBreak(int port, int ms100); @@ -2125,7 +1960,7 @@ int MoxaPortIsValid(int port) if (moxaCard == 0) return (0); - if (moxaChkPort[port] == 0) + if (moxa_ports[port].chkPort == 0) return (0); return (1); } @@ -2136,9 +1971,9 @@ void MoxaPortEnable(int port) int MoxaPortLineStatus(int); short lowwater = 512; - ofsAddr = moxaTableAddr[port]; + ofsAddr = moxa_ports[port].tableAddr; writew(lowwater, ofsAddr + Low_water); - moxaBreakCnt[port] = 0; + moxa_ports[port].breakCnt = 0; if ((moxa_boards[port / MAX_PORTS_PER_BOARD].boardType == MOXA_BOARD_C320_ISA) || (moxa_boards[port / MAX_PORTS_PER_BOARD].boardType == MOXA_BOARD_C320_PCI)) { moxafunc(ofsAddr, FC_SetBreakIrq, 0); @@ -2155,7 +1990,7 @@ void MoxaPortEnable(int port) void MoxaPortDisable(int port) { - void __iomem *ofsAddr = moxaTableAddr[port]; + void __iomem *ofsAddr = moxa_ports[port].tableAddr; moxafunc(ofsAddr, FC_SetFlowCtl, 0); /* disable flow control */ moxafunc(ofsAddr, FC_ClrLineIrq, Magic_code); @@ -2181,7 +2016,7 @@ long MoxaPortSetBaud(int port, long baud if ((baud < 50L) || ((max = MoxaPortGetMaxBaud(port)) == 0)) return (0); - ofsAddr = moxaTableAddr[port]; + ofsAddr = moxa_ports[port].tableAddr; if (baud > max) baud = max; if (max == 38400L) @@ -2193,7 +2028,7 @@ long MoxaPortSetBaud(int port, long baud val = clock / baud; moxafunc(ofsAddr, FC_SetBaud, val); baud = clock / val; - moxaCurBaud[port] = baud; + moxa_ports[port].curBaud = baud; return (baud); } @@ -2203,9 +2038,9 @@ int MoxaPortSetTermio(int port, struct k tcflag_t cflag; tcflag_t mode = 0; - if (moxaChkPort[port] == 0 || termio == 0) + if (moxa_ports[port].chkPort == 0 || termio == 0) return (-1); - ofsAddr = moxaTableAddr[port]; + ofsAddr = moxa_ports[port].tableAddr; cflag = termio->c_cflag; /* termio->c_cflag */ mode = termio->c_cflag & CSIZE; @@ -2259,13 +2094,13 @@ int MoxaPortGetLineOut(int port, int *dt if (!MoxaPortIsValid(port)) return (-1); if (dtrState) { - if (moxaLineCtrl[port] & DTR_ON) + if (moxa_ports[port].lineCtrl & DTR_ON) *dtrState = 1; else *dtrState = 0; } if (rtsState) { - if (moxaLineCtrl[port] & RTS_ON) + if (moxa_ports[port].lineCtrl & RTS_ON) *rtsState = 1; else *rtsState = 0; @@ -2278,13 +2113,13 @@ void MoxaPortLineCtrl(int port, int dtr, void __iomem *ofsAddr; int mode; - ofsAddr = moxaTableAddr[port]; + ofsAddr = moxa_ports[port].tableAddr; mode = 0; if (dtr) mode |= DTR_ON; if (rts) mode |= RTS_ON; - moxaLineCtrl[port] = mode; + moxa_ports[port].lineCtrl = mode; moxafunc(ofsAddr, FC_LineControl, mode); } @@ -2293,7 +2128,7 @@ void MoxaPortFlowCtrl(int port, int rts, void __iomem *ofsAddr; int mode; - ofsAddr = moxaTableAddr[port]; + ofsAddr = moxa_ports[port].tableAddr; mode = 0; if (rts) mode |= RTS_FlowCtl; @@ -2313,7 +2148,7 @@ int MoxaPortLineStatus(int port) void __iomem *ofsAddr; int val; - ofsAddr = moxaTableAddr[port]; + ofsAddr = moxa_ports[port].tableAddr; if ((moxa_boards[port / MAX_PORTS_PER_BOARD].boardType == MOXA_BOARD_C320_ISA) || (moxa_boards[port / MAX_PORTS_PER_BOARD].boardType == MOXA_BOARD_C320_PCI)) { moxafunc(ofsAddr, FC_LineStatus, 0); @@ -2324,11 +2159,11 @@ int MoxaPortLineStatus(int port) val &= 0x0B; if (val & 8) { val |= 4; - if ((moxaDCDState[port] & DCD_oldstate) == 0) - moxaDCDState[port] = (DCD_oldstate | DCD_changed); + if ((moxa_ports[port].DCDState & DCD_oldstate) == 0) + moxa_ports[port].DCDState = (DCD_oldstate | DCD_changed); } else { - if (moxaDCDState[port] & DCD_oldstate) - moxaDCDState[port] = DCD_changed; + if (moxa_ports[port].DCDState & DCD_oldstate) + moxa_ports[port].DCDState = DCD_changed; } val &= 7; return (val); @@ -2338,10 +2173,10 @@ int MoxaPortDCDChange(int port) { int n; - if (moxaChkPort[port] == 0) + if (moxa_ports[port].chkPort == 0) return (0); - n = moxaDCDState[port]; - moxaDCDState[port] &= ~DCD_changed; + n = moxa_ports[port].DCDState; + moxa_ports[port].DCDState &= ~DCD_changed; n &= DCD_changed; return (n); } @@ -2350,32 +2185,15 @@ int MoxaPortDCDON(int port) { int n; - if (moxaChkPort[port] == 0) + if (moxa_ports[port].chkPort == 0) return (0); - if (moxaDCDState[port] & DCD_oldstate) + if (moxa_ports[port].DCDState & DCD_oldstate) n = 1; else n = 0; return (n); } - -/* - int MoxaDumpMem(int port, unsigned char * buffer, int len) - { - int i; - unsigned long baseAddr,ofsAddr,ofs; - - baseAddr = moxaBaseAddr[port / MAX_PORTS_PER_BOARD]; - ofs = baseAddr + DynPage_addr + pageofs; - if (len > 0x2000L) - len = 0x2000L; - for (i = 0; i < len; i++) - buffer[i] = readb(ofs+i); - } - */ - - int MoxaPortWriteData(int port, unsigned char * buffer, int len) { int c, total, i; @@ -2385,8 +2203,8 @@ int MoxaPortWriteData(int port, unsigned ushort pageno, pageofs, bufhead; void __iomem *baseAddr, *ofsAddr, *ofs; - ofsAddr = moxaTableAddr[port]; - baseAddr = moxaBaseAddr[port / MAX_PORTS_PER_BOARD]; + ofsAddr = moxa_ports[port].tableAddr; + baseAddr = moxa_boards[port / MAX_PORTS_PER_BOARD].basemem; tx_mask = readw(ofsAddr + TX_mask); spage = readw(ofsAddr + Page_txb); epage = readw(ofsAddr + EndPage_txb); @@ -2448,8 +2266,8 @@ int MoxaPortReadData(int port, struct tt ushort pageno, bufhead; void __iomem *baseAddr, *ofsAddr, *ofs; - ofsAddr = moxaTableAddr[port]; - baseAddr = moxaBaseAddr[port / MAX_PORTS_PER_BOARD]; + ofsAddr = moxa_ports[port].tableAddr; + baseAddr = moxa_boards[port / MAX_PORTS_PER_BOARD].basemem; head = readw(ofsAddr + RXrptr); tail = readw(ofsAddr + RXwptr); rx_mask = readw(ofsAddr + RX_mask); @@ -2504,7 +2322,7 @@ int MoxaPortReadData(int port, struct tt } if ((readb(ofsAddr + FlagStat) & Xoff_state) && (remain < LowWater)) { moxaLowWaterChk = 1; - moxaLowChkFlag[port] = 1; + moxa_ports[port].lowChkFlag = 1; } return (total); } @@ -2516,7 +2334,7 @@ int MoxaPortTxQueue(int port) ushort rptr, wptr, mask; int len; - ofsAddr = moxaTableAddr[port]; + ofsAddr = moxa_ports[port].tableAddr; rptr = readw(ofsAddr + TXrptr); wptr = readw(ofsAddr + TXwptr); mask = readw(ofsAddr + TX_mask); @@ -2530,7 +2348,7 @@ int MoxaPortTxFree(int port) ushort rptr, wptr, mask; int len; - ofsAddr = moxaTableAddr[port]; + ofsAddr = moxa_ports[port].tableAddr; rptr = readw(ofsAddr + TXrptr); wptr = readw(ofsAddr + TXwptr); mask = readw(ofsAddr + TX_mask); @@ -2544,7 +2362,7 @@ int MoxaPortRxQueue(int port) ushort rptr, wptr, mask; int len; - ofsAddr = moxaTableAddr[port]; + ofsAddr = moxa_ports[port].tableAddr; rptr = readw(ofsAddr + RXrptr); wptr = readw(ofsAddr + RXwptr); mask = readw(ofsAddr + RX_mask); @@ -2557,7 +2375,7 @@ void MoxaPortTxDisable(int port) { void __iomem *ofsAddr; - ofsAddr = moxaTableAddr[port]; + ofsAddr = moxa_ports[port].tableAddr; moxafunc(ofsAddr, FC_SetXoffState, Magic_code); } @@ -2565,7 +2383,7 @@ void MoxaPortTxEnable(int port) { void __iomem *ofsAddr; - ofsAddr = moxaTableAddr[port]; + ofsAddr = moxa_ports[port].tableAddr; moxafunc(ofsAddr, FC_SetXonState, Magic_code); } @@ -2573,8 +2391,8 @@ void MoxaPortTxEnable(int port) int MoxaPortResetBrkCnt(int port) { ushort cnt; - cnt = moxaBreakCnt[port]; - moxaBreakCnt[port] = 0; + cnt = moxa_ports[port].breakCnt; + moxa_ports[port].breakCnt = 0; return (cnt); } @@ -2583,7 +2401,7 @@ void MoxaPortSendBreak(int port, int ms1 { void __iomem *ofsAddr; - ofsAddr = moxaTableAddr[port]; + ofsAddr = moxa_ports[port].tableAddr; if (ms100) { moxafunc(ofsAddr, FC_SendBreak, Magic_code); moxadelay(ms100 * (HZ / 10)); @@ -2594,7 +2412,7 @@ void MoxaPortSendBreak(int port, int ms1 moxafunc(ofsAddr, FC_StopBreak, Magic_code); } -static int moxa_get_serial_info(struct moxa_str *info, +static int moxa_get_serial_info(struct moxa_port *info, struct serial_struct __user *retinfo) { struct serial_struct tmp; @@ -2616,7 +2434,7 @@ static int moxa_get_serial_info(struct m } -static int moxa_set_serial_info(struct moxa_str *info, +static int moxa_set_serial_info(struct moxa_port *info, struct serial_struct __user *new_info) { struct serial_struct new_serial; @@ -2713,7 +2531,7 @@ static int moxaloadbios(int cardno, unsi if(copy_from_user(moxaBuff, tmp, len)) return -EFAULT; - baseAddr = moxaBaseAddr[cardno]; + baseAddr = moxa_boards[cardno].basemem; writeb(HW_reset, baseAddr + Control_reg); /* reset */ moxadelay(1); /* delay 10 ms */ for (i = 0; i < 4096; i++) @@ -2729,7 +2547,7 @@ static int moxafindcard(int cardno) void __iomem *baseAddr; ushort tmp; - baseAddr = moxaBaseAddr[cardno]; + baseAddr = moxa_boards[cardno].basemem; switch (moxa_boards[cardno].boardType) { case MOXA_BOARD_C218_ISA: case MOXA_BOARD_C218_PCI: @@ -2762,7 +2580,7 @@ static int moxaload320b(int cardno, unsi return -EINVAL; if(copy_from_user(moxaBuff, tmp, len)) return -EFAULT; - baseAddr = moxaBaseAddr[cardno]; + baseAddr = moxa_boards[cardno].basemem; writew(len - 7168 - 2, baseAddr + C320bapi_len); writeb(1, baseAddr + Control_reg); /* Select Page 1 */ for (i = 0; i < 7168; i++) @@ -2780,7 +2598,7 @@ static int moxaloadcode(int cardno, unsi if(copy_from_user(moxaBuff, tmp, len)) return -EFAULT; - baseAddr = moxaBaseAddr[cardno]; + baseAddr = moxa_boards[cardno].basemem; switch (moxa_boards[cardno].boardType) { case MOXA_BOARD_C218_ISA: case MOXA_BOARD_C218_PCI: @@ -2790,11 +2608,13 @@ static int moxaloadcode(int cardno, unsi return (retval); port = cardno * MAX_PORTS_PER_BOARD; for (i = 0; i < moxa_boards[cardno].numPorts; i++, port++) { - moxaChkPort[port] = 1; - moxaCurBaud[port] = 9600L; - moxaDCDState[port] = 0; - moxaTableAddr[port] = baseAddr + Extern_table + Extern_size * i; - ofsAddr = moxaTableAddr[port]; + struct moxa_port *p = &moxa_ports[port]; + + p->chkPort = 1; + p->curBaud = 9600L; + p->DCDState = 0; + p->tableAddr = baseAddr + Extern_table + Extern_size * i; + ofsAddr = p->tableAddr; writew(C218rx_mask, ofsAddr + RX_mask); writew(C218tx_mask, ofsAddr + TX_mask); writew(C218rx_spage + i * C218buf_pageno, ofsAddr + Page_rxb); @@ -2812,11 +2632,13 @@ static int moxaloadcode(int cardno, unsi return (retval); port = cardno * MAX_PORTS_PER_BOARD; for (i = 0; i < moxa_boards[cardno].numPorts; i++, port++) { - moxaChkPort[port] = 1; - moxaCurBaud[port] = 9600L; - moxaDCDState[port] = 0; - moxaTableAddr[port] = baseAddr + Extern_table + Extern_size * i; - ofsAddr = moxaTableAddr[port]; + struct moxa_port *p = &moxa_ports[port]; + + p->chkPort = 1; + p->curBaud = 9600L; + p->DCDState = 0; + p->tableAddr = baseAddr + Extern_table + Extern_size * i; + ofsAddr = p->tableAddr; if (moxa_boards[cardno].numPorts == 8) { writew(C320p8rx_mask, ofsAddr + RX_mask); writew(C320p8tx_mask, ofsAddr + TX_mask); @@ -2852,7 +2674,7 @@ static int moxaloadcode(int cardno, unsi } break; } - loadstat[cardno] = 1; + moxa_boards[cardno].loadstat = 1; return (0); } @@ -2926,9 +2748,9 @@ static int moxaloadc218(int cardno, void return (-1); } moxaCard = 1; - moxaIntNdx[cardno] = baseAddr + IRQindex; - moxaIntPend[cardno] = baseAddr + IRQpending; - moxaIntTable[cardno] = baseAddr + IRQtable; + moxa_boards[cardno].intNdx = baseAddr + IRQindex; + moxa_boards[cardno].intPend = baseAddr + IRQpending; + moxa_boards[cardno].intTable = baseAddr + IRQtable; return (0); } @@ -3021,25 +2843,15 @@ static int moxaloadc320(int cardno, void if (readw(baseAddr + Magic_no) != Magic_code) return (-102); moxaCard = 1; - moxaIntNdx[cardno] = baseAddr + IRQindex; - moxaIntPend[cardno] = baseAddr + IRQpending; - moxaIntTable[cardno] = baseAddr + IRQtable; + moxa_boards[cardno].intNdx = baseAddr + IRQindex; + moxa_boards[cardno].intPend = baseAddr + IRQpending; + moxa_boards[cardno].intTable = baseAddr + IRQtable; return (0); } -#if 0 -long MoxaPortGetCurBaud(int port) -{ - - if (moxaChkPort[port] == 0) - return (0); - return (moxaCurBaud[port]); -} -#endif /* 0 */ - static void MoxaSetFifo(int port, int enable) { - void __iomem *ofsAddr = moxaTableAddr[port]; + void __iomem *ofsAddr = moxa_ports[port].tableAddr; if (!enable) { moxafunc(ofsAddr, FC_SetRxFIFOTrig, 0); @@ -3049,132 +2861,3 @@ static void MoxaSetFifo(int port, int en moxafunc(ofsAddr, FC_SetTxFIFOCnt, 16); } } - -#if 0 -int MoxaPortSetMode(int port, int databits, int stopbits, int parity) -{ - void __iomem *ofsAddr; - int val; - - val = 0; - switch (databits) { - case 5: - val |= 0; - break; - case 6: - val |= 1; - break; - case 7: - val |= 2; - break; - case 8: - val |= 3; - break; - default: - return (-1); - } - switch (stopbits) { - case 0: - val |= 0; - break; /* stop bits 1.5 */ - case 1: - val |= 0; - break; - case 2: - val |= 4; - break; - default: - return (-1); - } - switch (parity) { - case 0: - val |= 0x00; - break; /* None */ - case 1: - val |= 0x08; - break; /* Odd */ - case 2: - val |= 0x18; - break; /* Even */ - case 3: - val |= 0x28; - break; /* Mark */ - case 4: - val |= 0x38; - break; /* Space */ - default: - return (-1); - } - ofsAddr = moxaTableAddr[port]; - moxafunc(ofsAddr, FC_SetMode, val); - return (0); -} - -int MoxaPortTxBufSize(int port) -{ - void __iomem *ofsAddr; - int size; - - ofsAddr = moxaTableAddr[port]; - size = readw(ofsAddr + TX_mask); - return (size); -} - -int MoxaPortRxBufSize(int port) -{ - void __iomem *ofsAddr; - int size; - - ofsAddr = moxaTableAddr[port]; - size = readw(ofsAddr + RX_mask); - return (size); -} - -int MoxaPortRxFree(int port) -{ - void __iomem *ofsAddr; - ushort rptr, wptr, mask; - int len; - - ofsAddr = moxaTableAddr[port]; - rptr = readw(ofsAddr + RXrptr); - wptr = readw(ofsAddr + RXwptr); - mask = readw(ofsAddr + RX_mask); - len = mask - ((wptr - rptr) & mask); - return (len); -} -int MoxaPortGetBrkCnt(int port) -{ - return (moxaBreakCnt[port]); -} - -void MoxaPortSetXonXoff(int port, int xonValue, int xoffValue) -{ - void __iomem *ofsAddr; - - ofsAddr = moxaTableAddr[port]; - writew(xonValue, ofsAddr + FuncArg); - writew(xoffValue, ofsAddr + FuncArg1); - writew(FC_SetXonXoff, ofsAddr + FuncCode); - wait_finish(ofsAddr); -} - -int MoxaPortIsTxHold(int port) -{ - void __iomem *ofsAddr; - int val; - - ofsAddr = moxaTableAddr[port]; - if ((moxa_boards[port / MAX_PORTS_PER_BOARD].boardType == MOXA_BOARD_C320_ISA) || - (moxa_boards[port / MAX_PORTS_PER_BOARD].boardType == MOXA_BOARD_C320_PCI)) { - moxafunc(ofsAddr, FC_GetCCSR, 0); - val = readw(ofsAddr + FuncArg); - if (val & 0x04) - return (1); - } else { - if (readw(ofsAddr + FlagStat) & Tx_flowOff) - return (1); - } - return (0); -} -#endif diff --git a/drivers/char/mspec.c b/drivers/char/mspec.c index 235e892..7ac3061 100644 --- a/drivers/char/mspec.c +++ b/drivers/char/mspec.c @@ -291,7 +291,7 @@ uncached_mmap(struct file *file, struct return mspec_mmap(file, vma, MSPEC_UNCACHED); } -static struct file_operations fetchop_fops = { +static const struct file_operations fetchop_fops = { .owner = THIS_MODULE, .mmap = fetchop_mmap }; @@ -302,7 +302,7 @@ static struct miscdevice fetchop_miscdev .fops = &fetchop_fops }; -static struct file_operations cached_fops = { +static const struct file_operations cached_fops = { .owner = THIS_MODULE, .mmap = cached_mmap }; @@ -313,7 +313,7 @@ static struct miscdevice cached_miscdev .fops = &cached_fops }; -static struct file_operations uncached_fops = { +static const struct file_operations uncached_fops = { .owner = THIS_MODULE, .mmap = uncached_mmap }; diff --git a/drivers/char/mxser.c b/drivers/char/mxser.c index 83f604b..a61fb6d 100644 --- a/drivers/char/mxser.c +++ b/drivers/char/mxser.c @@ -321,8 +321,6 @@ struct mxser_struct { unsigned long event; int count; /* # of fd on device */ int blocked_open; /* # of blocked opens */ - long session; /* Session of opening process */ - long pgrp; /* pgrp of opening process */ unsigned char *xmit_buf; int xmit_head; int xmit_tail; @@ -1001,15 +999,12 @@ static int mxser_open(struct tty_struct mxser_change_speed(info, NULL); } - info->session = process_session(current); - info->pgrp = process_group(current); - /* status = mxser_get_msr(info->base, 0, info->port); mxser_check_modem_status(info, status); */ -/* unmark here for very high baud rate (ex. 921600 bps) used */ + /* unmark here for very high baud rate (ex. 921600 bps) used */ tty->low_latency = 1; return 0; } @@ -1254,9 +1249,7 @@ static void mxser_flush_buffer(struct tt spin_unlock_irqrestore(&info->slock, flags); /* above added by shinhay */ - wake_up_interruptible(&tty->write_wait); - if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && tty->ldisc.write_wakeup) - (tty->ldisc.write_wakeup) (tty); + tty_wakeup(tty); } static int mxser_ioctl(struct tty_struct *tty, struct file *file, unsigned int cmd, unsigned long arg) diff --git a/drivers/char/mxser.h b/drivers/char/mxser.h index 7e188a4..9fe2849 100644 --- a/drivers/char/mxser.h +++ b/drivers/char/mxser.h @@ -439,12 +439,4 @@ #define DISABLE_MOXA_MUST_XON_ANY_FLOW_C #define READ_MOXA_MUST_GDL(baseio) inb((baseio)+MOXA_MUST_GDL_REGISTER) - -#ifndef INIT_WORK -#define INIT_WORK(_work, _func, _data){ \ - _data->tqueue.routine = _func;\ - _data->tqueue.data = _data;\ - } -#endif - #endif diff --git a/drivers/char/mxser_new.c b/drivers/char/mxser_new.c index 1bb030b..9af07e4 100644 --- a/drivers/char/mxser_new.c +++ b/drivers/char/mxser_new.c @@ -49,22 +49,25 @@ #include #include "mxser_new.h" -#define MXSER_VERSION "2.0" +#define MXSER_VERSION "2.0.1" /* 1.9.15 */ #define MXSERMAJOR 174 #define MXSERCUMAJOR 175 -#define MXSER_EVENT_TXLOW 1 - #define MXSER_BOARDS 4 /* Max. boards */ #define MXSER_PORTS_PER_BOARD 8 /* Max. ports per board */ #define MXSER_PORTS (MXSER_BOARDS * MXSER_PORTS_PER_BOARD) -#define MXSER_ISR_PASS_LIMIT 99999L +#define MXSER_ISR_PASS_LIMIT 100 #define MXSER_ERR_IOADDR -1 #define MXSER_ERR_IRQ -2 #define MXSER_ERR_IRQ_CONFLIT -3 #define MXSER_ERR_VECTOR -4 +/*CheckIsMoxaMust return value*/ +#define MOXA_OTHER_UART 0x00 +#define MOXA_MUST_MU150_HWID 0x01 +#define MOXA_MUST_MU860_HWID 0x02 + #define WAKEUP_CHARS 256 #define UART_MCR_AFE 0x20 @@ -176,6 +179,18 @@ static struct pci_device_id mxser_pcibrd }; MODULE_DEVICE_TABLE(pci, mxser_pcibrds); +static int mxvar_baud_table[] = { + 0, 50, 75, 110, 134, 150, 200, 300, 600, 1200, 1800, 2400, + 4800, 9600, 19200, 38400, 57600, 115200, 230400, 460800, 921600 +}; +static unsigned int mxvar_baud_table1[] = { + 0, B50, B75, B110, B134, B150, B200, B300, B600, B1200, B1800, B2400, + B4800, B9600, B19200, B38400, B57600, B115200, B230400, B460800, B921600 +}; +#define BAUD_TABLE_NO ARRAY_SIZE(mxvar_baud_table) + +#define B_SPEC B2000000 + static int ioaddr[MXSER_BOARDS] = { 0, 0, 0, 0 }; static int ttymajor = MXSERMAJOR; static int calloutmajor = MXSERCUMAJOR; @@ -237,8 +252,7 @@ struct mxser_port { long realbaud; int type; /* UART type */ int flags; /* defined in tty.h */ - long session; /* Session of opening process */ - long pgrp; /* pgrp of opening process */ + int speed; int x_char; /* xon/xoff character */ int IER; /* Interrupt Enable Register */ @@ -267,14 +281,11 @@ struct mxser_port { int xmit_cnt; struct ktermios normal_termios; - struct ktermios callout_termios; struct mxser_mon mon_data; spinlock_t slock; - struct work_struct tqueue; wait_queue_head_t open_wait; - wait_queue_head_t close_wait; wait_queue_head_t delta_msr_wait; }; @@ -313,10 +324,9 @@ static int mxvar_diagflag; static unsigned char mxser_msr[MXSER_PORTS + 1]; static struct mxser_mon_ext mon_data_ext; static int mxser_set_baud_method[MXSER_PORTS + 1]; -static spinlock_t gm_lock; #ifdef CONFIG_PCI -static int CheckIsMoxaMust(int io) +static int __devinit CheckIsMoxaMust(int io) { u8 oldmcr, hwid; int i; @@ -360,15 +370,6 @@ static void process_txrx_fifo(struct mxs } } -static void mxser_do_softint(struct work_struct *work) -{ - struct mxser_port *info = container_of(work, struct mxser_port, tqueue); - struct tty_struct *tty = info->tty; - - if (test_and_clear_bit(MXSER_EVENT_TXLOW, &info->event)) - tty_wakeup(tty); -} - static unsigned char mxser_get_msr(int baseaddr, int mode, int port) { unsigned char status = 0; @@ -456,10 +457,10 @@ static int mxser_block_til_ready(struct static int mxser_set_baud(struct mxser_port *info, long newspd) { + unsigned int i; int quot = 0; unsigned char cval; int ret = 0; - unsigned long flags; if (!info->tty || !info->tty->termios) return ret; @@ -471,29 +472,34 @@ static int mxser_set_baud(struct mxser_p return 0; info->realbaud = newspd; - if (newspd == 134) { - quot = (2 * info->baud_base / 269); - } else if (newspd) { - quot = info->baud_base / newspd; - if (quot == 0) - quot = 1; + for (i = 0; i < BAUD_TABLE_NO; i++) + if (newspd == mxvar_baud_table[i]) + break; + if (i == BAUD_TABLE_NO) { + quot = info->baud_base / info->speed; + if (info->speed <= 0 || info->speed > info->max_baud) + quot = 0; } else { - quot = 0; + if (newspd == 134) { + quot = (2 * info->baud_base / 269); + } else if (newspd) { + quot = info->baud_base / newspd; + if (quot == 0) + quot = 1; + } else { + quot = 0; + } } info->timeout = ((info->xmit_fifo_size * HZ * 10 * quot) / info->baud_base); info->timeout += HZ / 50; /* Add .02 seconds of slop */ if (quot) { - spin_lock_irqsave(&info->slock, flags); info->MCR |= UART_MCR_DTR; outb(info->MCR, info->ioaddr + UART_MCR); - spin_unlock_irqrestore(&info->slock, flags); } else { - spin_lock_irqsave(&info->slock, flags); info->MCR &= ~UART_MCR_DTR; outb(info->MCR, info->ioaddr + UART_MCR); - spin_unlock_irqrestore(&info->slock, flags); return ret; } @@ -505,6 +511,18 @@ static int mxser_set_baud(struct mxser_p outb(quot >> 8, info->ioaddr + UART_DLM); /* MS of divisor */ outb(cval, info->ioaddr + UART_LCR); /* reset DLAB */ + if (i == BAUD_TABLE_NO) { + quot = info->baud_base % info->speed; + quot *= 8; + if ((quot % info->speed) > (info->speed / 2)) { + quot /= info->speed; + quot++; + } else { + quot /= info->speed; + } + SET_MOXA_MUST_ENUM_VALUE(info->ioaddr, quot); + } else + SET_MOXA_MUST_ENUM_VALUE(info->ioaddr, 0); return ret; } @@ -520,7 +538,6 @@ static int mxser_change_speed(struct mxs int ret = 0; unsigned char status; long baud; - unsigned long flags; if (!info->tty || !info->tty->termios) return ret; @@ -529,7 +546,10 @@ static int mxser_change_speed(struct mxs return ret; if (mxser_set_baud_method[info->tty->index] == 0) { - baud = tty_get_baud_rate(info->tty); + if ((cflag & CBAUD) == B_SPEC) + baud = info->speed; + else + baud = tty_get_baud_rate(info->tty); mxser_set_baud(info, baud); } @@ -612,8 +632,8 @@ static int mxser_change_speed(struct mxs outb(info->IER, info->ioaddr + UART_IER); } - set_bit(MXSER_EVENT_TXLOW, &info->event); - schedule_work(&info->tqueue); } + tty_wakeup(info->tty); + } } else { if (!(status & UART_MSR_CTS)) { info->tty->hw_stopped = 1; @@ -668,7 +688,6 @@ static int mxser_change_speed(struct mxs } } if (info->board->chip_flag) { - spin_lock_irqsave(&info->slock, flags); SET_MOXA_MUST_XON1_VALUE(info->ioaddr, START_CHAR(info->tty)); SET_MOXA_MUST_XOFF1_VALUE(info->ioaddr, STOP_CHAR(info->tty)); if (I_IXON(info->tty)) { @@ -681,7 +700,6 @@ static int mxser_change_speed(struct mxs } else { DISABLE_MOXA_MUST_TX_SOFTWARE_FLOW_CONTROL(info->ioaddr); } - spin_unlock_irqrestore(&info->slock, flags); } @@ -708,7 +726,6 @@ static void mxser_check_modem_status(str if ((port->flags & ASYNC_CHECK_CD) && (status & UART_MSR_DDCD)) { if (status & UART_MSR_DCD) wake_up_interruptible(&port->open_wait); - schedule_work(&port->tqueue); } if (port->flags & ASYNC_CTS_FLOW) { @@ -724,8 +741,7 @@ static void mxser_check_modem_status(str outb(port->IER, port->ioaddr + UART_IER); } - set_bit(MXSER_EVENT_TXLOW, &port->event); - schedule_work(&port->tqueue); + tty_wakeup(port->tty); } } else { if (!(status & UART_MSR_CTS)) { @@ -836,10 +852,10 @@ static int mxser_startup(struct mxser_po /* * and set the speed of the serial port */ - spin_unlock_irqrestore(&info->slock, flags); mxser_change_speed(info, NULL); - info->flags |= ASYNC_INITIALIZED; + spin_unlock_irqrestore(&info->slock, flags); + return 0; } @@ -909,11 +925,9 @@ static void mxser_shutdown(struct mxser_ static int mxser_open(struct tty_struct *tty, struct file *filp) { struct mxser_port *info; + unsigned long flags; int retval, line; - /* initialize driver_data in case something fails */ - tty->driver_data = NULL; - line = tty->index; if (line == MXSER_PORTS) return 0; @@ -928,7 +942,9 @@ static int mxser_open(struct tty_struct /* * Start up serial port */ + spin_lock_irqsave(&info->slock, flags); info->count++; + spin_unlock_irqrestore(&info->slock, flags); retval = mxser_startup(info); if (retval) return retval; @@ -937,17 +953,6 @@ static int mxser_open(struct tty_struct if (retval) return retval; - if ((info->count == 1) && (info->flags & ASYNC_SPLIT_TERMIOS)) { - if (tty->driver->subtype == SERIAL_TYPE_NORMAL) - *tty->termios = info->normal_termios; - else - *tty->termios = info->callout_termios; - mxser_change_speed(info, NULL); - } - - info->session = process_session(current); - info->pgrp = process_group(current); - /* unmark here for very high baud rate (ex. 921600 bps) used */ tty->low_latency = 1; return 0; @@ -1054,8 +1059,6 @@ static void mxser_close(struct tty_struc } info->flags &= ~(ASYNC_NORMAL_ACTIVE | ASYNC_CLOSING); - wake_up_interruptible(&info->close_wait); - } static int mxser_write(struct tty_struct *tty, const unsigned char *buf, int count) @@ -1222,6 +1225,7 @@ static int mxser_set_serial_info(struct struct serial_struct __user *new_info) { struct serial_struct new_serial; + unsigned long sl_flags; unsigned int flags; int retval = 0; @@ -1264,8 +1268,11 @@ static int mxser_set_serial_info(struct process_txrx_fifo(info); if (info->flags & ASYNC_INITIALIZED) { - if (flags != (info->flags & ASYNC_SPD_MASK)) + if (flags != (info->flags & ASYNC_SPD_MASK)) { + spin_lock_irqsave(&info->slock, sl_flags); mxser_change_speed(info, NULL); + spin_unlock_irqrestore(&info->slock, sl_flags); + } } else retval = mxser_startup(info); @@ -1373,11 +1380,10 @@ static int mxser_tiocmset(struct tty_str return 0; } -static int mxser_program_mode(int port) +static int __init mxser_program_mode(int port) { int id, i, j, n; - spin_lock(&gm_lock); outb(0, port); outb(0, port); outb(0, port); @@ -1385,7 +1391,6 @@ static int mxser_program_mode(int port) (void)inb(port); outb(0, port); (void)inb(port); - spin_unlock(&gm_lock); id = inb(port + 1) & 0x1F; if ((id != C168_ASIC_ID) && @@ -1410,7 +1415,7 @@ static int mxser_program_mode(int port) return id; } -static void mxser_normal_mode(int port) +static void __init mxser_normal_mode(int port) { int i, n; @@ -1443,7 +1448,7 @@ #define EN0_DCFG 0x00E /* Data configura #define EN0_PORT 0x010 /* Rcv missed frame error counter RD */ #define ENC_PAGE0 0x000 /* Select page 0 of chip registers */ #define ENC_PAGE3 0x0C0 /* Select page 3 of chip registers */ -static int mxser_read_register(int port, unsigned short *regs) +static int __init mxser_read_register(int port, unsigned short *regs) { int i, k, value, id; unsigned int j; @@ -1644,6 +1649,7 @@ static int mxser_ioctl(struct tty_struct struct serial_icounter_struct __user *p_cuser; unsigned long templ; unsigned long flags; + unsigned int i; void __user *argp = (void __user *)arg; int retval; @@ -1682,6 +1688,36 @@ static int mxser_ioctl(struct tty_struct return 0; } + if (cmd == MOXA_SET_SPECIAL_BAUD_RATE) { + int speed; + + if (get_user(speed, (int __user *)argp)) + return -EFAULT; + if (speed <= 0 || speed > info->max_baud) + return -EFAULT; + if (!info->tty || !info->tty->termios || !info->ioaddr) + return 0; + info->tty->termios->c_cflag &= ~(CBAUD | CBAUDEX); + for (i = 0; i < BAUD_TABLE_NO; i++) + if (speed == mxvar_baud_table[i]) + break; + if (i == BAUD_TABLE_NO) { + info->tty->termios->c_cflag |= B_SPEC; + } else if (speed != 0) + info->tty->termios->c_cflag |= mxvar_baud_table1[i]; + + info->speed = speed; + spin_lock_irqsave(&info->slock, flags); + mxser_change_speed(info, NULL); + spin_unlock_irqrestore(&info->slock, flags); + + return 0; + } else if (cmd == MOXA_GET_SPECIAL_BAUD_RATE) { + if (copy_to_user(argp, &info->speed, sizeof(int))) + return -EFAULT; + return 0; + } + if (cmd != TIOCGSERIAL && cmd != TIOCMIWAIT && cmd != TIOCGICOUNT && test_bit(TTY_IO_ERROR, &tty->flags)) return -EIO; @@ -1799,7 +1835,9 @@ static int mxser_ioctl(struct tty_struct long baud; if (get_user(baud, (long __user *)argp)) return -EFAULT; + spin_lock_irqsave(&info->slock, flags); mxser_set_baud(info, baud); + spin_unlock_irqrestore(&info->slock, flags); return 0; } case MOXA_ASPP_GETBAUD: @@ -1976,7 +2014,9 @@ static void mxser_set_termios(struct tty if ((tty->termios->c_cflag != old_termios->c_cflag) || (RELEVANT_IFLAG(tty->termios->c_iflag) != RELEVANT_IFLAG(old_termios->c_iflag))) { + spin_lock_irqsave(&info->slock, flags); mxser_change_speed(info, old_termios); + spin_unlock_irqrestore(&info->slock, flags); if ((old_termios->c_cflag & CRTSCTS) && !(tty->termios->c_cflag & CRTSCTS)) { @@ -2066,7 +2106,7 @@ #endif /* * This routine is called by tty_hangup() when a hangup is signaled. */ -void mxser_hangup(struct tty_struct *tty) +static void mxser_hangup(struct tty_struct *tty) { struct mxser_port *info = tty->driver_data; @@ -2105,9 +2145,6 @@ static void mxser_receive_chars(struct m int cnt = 0; int recv_room; int max = 256; - unsigned long flags; - - spin_lock_irqsave(&port->slock, flags); recv_room = tty->receive_room; if ((recv_room == 0) && (!port->ldisc_stop_rx)) @@ -2169,7 +2206,8 @@ intr_old: } else if (*status & UART_LSR_OE) { flag = TTY_OVERRUN; port->icount.overrun++; - } + } else + flag = TTY_BREAK; } tty_insert_flip_char(tty, ch, flag); cnt++; @@ -2191,7 +2229,6 @@ end_intr: mxvar_log.rxcnt[port->tty->index] += cnt; port->mon_data.rxcnt += cnt; port->mon_data.up_rxcnt += cnt; - spin_unlock_irqrestore(&port->slock, flags); tty_flip_buffer_push(tty); } @@ -2199,9 +2236,6 @@ end_intr: static void mxser_transmit_chars(struct mxser_port *port) { int count, cnt; - unsigned long flags; - - spin_lock_irqsave(&port->slock, flags); if (port->x_char) { outb(port->x_char, port->ioaddr + UART_TX); @@ -2210,11 +2244,11 @@ static void mxser_transmit_chars(struct port->mon_data.txcnt++; port->mon_data.up_txcnt++; port->icount.tx++; - goto unlock; + return; } if (port->xmit_buf == 0) - goto unlock; + return; if ((port->xmit_cnt <= 0) || port->tty->stopped || (port->tty->hw_stopped && @@ -2222,7 +2256,7 @@ static void mxser_transmit_chars(struct (!port->board->chip_flag))) { port->IER &= ~UART_IER_THRI; outb(port->IER, port->ioaddr + UART_IER); - goto unlock; + return; } cnt = port->xmit_cnt; @@ -2240,16 +2274,13 @@ static void mxser_transmit_chars(struct port->mon_data.up_txcnt += (cnt - port->xmit_cnt); port->icount.tx += (cnt - port->xmit_cnt); - if (port->xmit_cnt < WAKEUP_CHARS) { - set_bit(MXSER_EVENT_TXLOW, &port->event); - schedule_work(&port->tqueue); - } + if (port->xmit_cnt < WAKEUP_CHARS) + tty_wakeup(port->tty); + if (port->xmit_cnt <= 0) { port->IER &= ~UART_IER_THRI; outb(port->IER, port->ioaddr + UART_IER); } -unlock: - spin_unlock_irqrestore(&port->slock, flags); } /* @@ -2261,8 +2292,7 @@ static irqreturn_t mxser_interrupt(int i struct mxser_board *brd = NULL; struct mxser_port *port; int max, irqbits, bits, msr; - int pass_counter = 0; - unsigned int int_cnt; + unsigned int int_cnt, pass_counter = 0; int handled = IRQ_NONE; for (i = 0; i < MXSER_BOARDS; i++) @@ -2276,7 +2306,7 @@ static irqreturn_t mxser_interrupt(int i if (brd == NULL) goto irq_stop; max = brd->info->nports; - while (1) { + while (pass_counter++ < MXSER_ISR_PASS_LIMIT) { irqbits = inb(brd->vector) & brd->vector_mask; if (irqbits == brd->vector_mask) break; @@ -2290,12 +2320,16 @@ static irqreturn_t mxser_interrupt(int i port = &brd->ports[i]; int_cnt = 0; + spin_lock(&port->slock); do { iir = inb(port->ioaddr + UART_IIR); if (iir & UART_IIR_NO_INT) break; iir &= MOXA_MUST_IIR_MASK; - if (!port->tty) { + if (!port->tty || + (port->flags & ASYNC_CLOSING) || + !(port->flags & + ASYNC_INITIALIZED)) { status = inb(port->ioaddr + UART_LSR); outb(0x27, port->ioaddr + UART_FCR); inb(port->ioaddr + UART_MSR); @@ -2341,9 +2375,8 @@ static irqreturn_t mxser_interrupt(int i mxser_transmit_chars(port); } } while (int_cnt++ < MXSER_ISR_PASS_LIMIT); + spin_unlock(&port->slock); } - if (pass_counter++ > MXSER_ISR_PASS_LIMIT) - break; /* Prevent infinite loops */ } irq_stop: @@ -2385,7 +2418,6 @@ static void mxser_release_res(struct mxs #ifdef CONFIG_PCI pci_release_region(pdev, 2); pci_release_region(pdev, 3); - pci_dev_put(pdev); #endif } else { release_region(brd->ports[0].ioaddr, 8 * brd->info->nports); @@ -2420,11 +2452,10 @@ static int __devinit mxser_initbrd(struc info->custom_divisor = info->baud_base * 16; info->close_delay = 5 * HZ / 10; info->closing_wait = 30 * HZ; - INIT_WORK(&info->tqueue, mxser_do_softint); info->normal_termios = mxvar_sdriver->init_termios; init_waitqueue_head(&info->open_wait); - init_waitqueue_head(&info->close_wait); init_waitqueue_head(&info->delta_msr_wait); + info->speed = 9600; memset(&info->mon_data, 0, sizeof(struct mxser_mon)); info->err_shadow = 0; spin_lock_init(&info->slock); @@ -2433,22 +2464,17 @@ static int __devinit mxser_initbrd(struc outb(inb(info->ioaddr + UART_IER) & 0xf0, info->ioaddr + UART_IER); } - /* - * Allocate the IRQ if necessary - */ - retval = request_irq(brd->irq, mxser_interrupt, - (brd->ports[0].flags & ASYNC_SHARE_IRQ) ? IRQF_SHARED : - IRQF_DISABLED, "mxser", brd); + retval = request_irq(brd->irq, mxser_interrupt, IRQF_SHARED, "mxser", + brd); if (retval) { printk(KERN_ERR "Board %s: Request irq failed, IRQ (%d) may " "conflict with another device.\n", brd->info->name, brd->irq); /* We hold resources, we need to release them. */ mxser_release_res(brd, pdev, 0); - return retval; } - return 0; + return retval; } static int __init mxser_get_ISA_conf(int cap, struct mxser_board *brd) @@ -2633,8 +2659,9 @@ #ifdef CONFIG_PCI } /* mxser_initbrd will hook ISR. */ - if (mxser_initbrd(brd, pdev) < 0) - goto err_relvec; + retval = mxser_initbrd(brd, pdev); + if (retval) + goto err_null; for (i = 0; i < brd->info->nports; i++) tty_register_device(mxvar_sdriver, brd->idx + i, &pdev->dev); @@ -2642,10 +2669,9 @@ #ifdef CONFIG_PCI pci_set_drvdata(pdev, brd); return 0; -err_relvec: - pci_release_region(pdev, 3); err_relio: pci_release_region(pdev, 2); +err_null: brd->info = NULL; err: return retval; @@ -2663,6 +2689,7 @@ static void __devexit mxser_remove(struc tty_unregister_device(mxvar_sdriver, brd->idx + i); mxser_release_res(brd, pdev, 1); + brd->info = NULL; } static struct pci_driver mxser_driver = { @@ -2684,7 +2711,6 @@ static int __init mxser_module_init(void mxvar_sdriver = alloc_tty_driver(MXSER_PORTS + 1); if (!mxvar_sdriver) return -ENOMEM; - spin_lock_init(&gm_lock); printk(KERN_INFO "MOXA Smartio/Industio family driver version %s\n", MXSER_VERSION); diff --git a/drivers/char/mxser_new.h b/drivers/char/mxser_new.h index a08f0ec..d42f776 100644 --- a/drivers/char/mxser_new.h +++ b/drivers/char/mxser_new.h @@ -26,18 +26,8 @@ #define RS485_2WIRE_MODE 1 #define RS422_MODE 2 #define RS485_4WIRE_MODE 3 #define OP_MODE_MASK 3 -// above add by Victor Yu. 01-05-2004 - -#define TTY_THRESHOLD_THROTTLE 128 - -#define LO_WATER (TTY_FLIPBUF_SIZE) -#define HI_WATER (TTY_FLIPBUF_SIZE*2*3/4) - -// added by James. 03-11-2004. -#define MOXA_SDS_GETICOUNTER (MOXA + 68) -#define MOXA_SDS_RSTICOUNTER (MOXA + 69) -// (above) added by James. +#define MOXA_SDS_RSTICOUNTER (MOXA + 69) #define MOXA_ASPP_OQUEUE (MOXA + 70) #define MOXA_ASPP_SETBAUD (MOXA + 71) #define MOXA_ASPP_GETBAUD (MOXA + 72) @@ -45,7 +35,8 @@ #define MOXA_ASPP_MON (MOXA + 73) #define MOXA_ASPP_LSTATUS (MOXA + 74) #define MOXA_ASPP_MON_EXT (MOXA + 75) #define MOXA_SET_BAUD_METHOD (MOXA + 76) - +#define MOXA_SET_SPECIAL_BAUD_RATE (MOXA + 77) +#define MOXA_GET_SPECIAL_BAUD_RATE (MOXA + 78) /* --------------------------------------------------- */ @@ -55,51 +46,46 @@ #define NPPI_NOTIFY_HW_OVERRUN 0x04 #define NPPI_NOTIFY_SW_OVERRUN 0x08 #define NPPI_NOTIFY_BREAK 0x10 -#define NPPI_NOTIFY_CTSHOLD 0x01 // Tx hold by CTS low -#define NPPI_NOTIFY_DSRHOLD 0x02 // Tx hold by DSR low -#define NPPI_NOTIFY_XOFFHOLD 0x08 // Tx hold by Xoff received -#define NPPI_NOTIFY_XOFFXENT 0x10 // Xoff Sent - -//CheckIsMoxaMust return value -#define MOXA_OTHER_UART 0x00 -#define MOXA_MUST_MU150_HWID 0x01 -#define MOXA_MUST_MU860_HWID 0x02 - -// follow just for Moxa Must chip define. -// -// when LCR register (offset 0x03) write following value, -// the Must chip will enter enchance mode. And write value -// on EFR (offset 0x02) bit 6,7 to change bank. +#define NPPI_NOTIFY_CTSHOLD 0x01 /* Tx hold by CTS low */ +#define NPPI_NOTIFY_DSRHOLD 0x02 /* Tx hold by DSR low */ +#define NPPI_NOTIFY_XOFFHOLD 0x08 /* Tx hold by Xoff received */ +#define NPPI_NOTIFY_XOFFXENT 0x10 /* Xoff Sent */ + +/* follow just for Moxa Must chip define. */ +/* */ +/* when LCR register (offset 0x03) write following value, */ +/* the Must chip will enter enchance mode. And write value */ +/* on EFR (offset 0x02) bit 6,7 to change bank. */ #define MOXA_MUST_ENTER_ENCHANCE 0xBF -// when enhance mode enable, access on general bank register +/* when enhance mode enable, access on general bank register */ #define MOXA_MUST_GDL_REGISTER 0x07 #define MOXA_MUST_GDL_MASK 0x7F #define MOXA_MUST_GDL_HAS_BAD_DATA 0x80 -#define MOXA_MUST_LSR_RERR 0x80 // error in receive FIFO -// enchance register bank select and enchance mode setting register -// when LCR register equal to 0xBF +#define MOXA_MUST_LSR_RERR 0x80 /* error in receive FIFO */ +/* enchance register bank select and enchance mode setting register */ +/* when LCR register equal to 0xBF */ #define MOXA_MUST_EFR_REGISTER 0x02 -// enchance mode enable +/* enchance mode enable */ #define MOXA_MUST_EFR_EFRB_ENABLE 0x10 -// enchance reister bank set 0, 1, 2 +/* enchance reister bank set 0, 1, 2 */ #define MOXA_MUST_EFR_BANK0 0x00 #define MOXA_MUST_EFR_BANK1 0x40 #define MOXA_MUST_EFR_BANK2 0x80 #define MOXA_MUST_EFR_BANK3 0xC0 #define MOXA_MUST_EFR_BANK_MASK 0xC0 -// set XON1 value register, when LCR=0xBF and change to bank0 +/* set XON1 value register, when LCR=0xBF and change to bank0 */ #define MOXA_MUST_XON1_REGISTER 0x04 -// set XON2 value register, when LCR=0xBF and change to bank0 +/* set XON2 value register, when LCR=0xBF and change to bank0 */ #define MOXA_MUST_XON2_REGISTER 0x05 -// set XOFF1 value register, when LCR=0xBF and change to bank0 +/* set XOFF1 value register, when LCR=0xBF and change to bank0 */ #define MOXA_MUST_XOFF1_REGISTER 0x06 -// set XOFF2 value register, when LCR=0xBF and change to bank0 +/* set XOFF2 value register, when LCR=0xBF and change to bank0 */ #define MOXA_MUST_XOFF2_REGISTER 0x07 #define MOXA_MUST_RBRTL_REGISTER 0x04 @@ -111,32 +97,32 @@ #define MOXA_MUST_HWID_REGISTER 0x05 #define MOXA_MUST_ECR_REGISTER 0x06 #define MOXA_MUST_CSR_REGISTER 0x07 -// good data mode enable +/* good data mode enable */ #define MOXA_MUST_FCR_GDA_MODE_ENABLE 0x20 -// only good data put into RxFIFO +/* only good data put into RxFIFO */ #define MOXA_MUST_FCR_GDA_ONLY_ENABLE 0x10 -// enable CTS interrupt +/* enable CTS interrupt */ #define MOXA_MUST_IER_ECTSI 0x80 -// enable RTS interrupt +/* enable RTS interrupt */ #define MOXA_MUST_IER_ERTSI 0x40 -// enable Xon/Xoff interrupt +/* enable Xon/Xoff interrupt */ #define MOXA_MUST_IER_XINT 0x20 -// enable GDA interrupt +/* enable GDA interrupt */ #define MOXA_MUST_IER_EGDAI 0x10 #define MOXA_MUST_RECV_ISR (UART_IER_RDI | MOXA_MUST_IER_EGDAI) -// GDA interrupt pending +/* GDA interrupt pending */ #define MOXA_MUST_IIR_GDA 0x1C #define MOXA_MUST_IIR_RDA 0x04 #define MOXA_MUST_IIR_RTO 0x0C #define MOXA_MUST_IIR_LSR 0x06 -// recieved Xon/Xoff or specical interrupt pending +/* recieved Xon/Xoff or specical interrupt pending */ #define MOXA_MUST_IIR_XSC 0x10 -// RTS/CTS change state interrupt pending +/* RTS/CTS change state interrupt pending */ #define MOXA_MUST_IIR_RTSCTS 0x20 #define MOXA_MUST_IIR_MASK 0x3E @@ -144,307 +130,164 @@ #define MOXA_MUST_MCR_XON_FLAG 0x40 #define MOXA_MUST_MCR_XON_ANY 0x80 #define MOXA_MUST_MCR_TX_XON 0x08 - -// software flow control on chip mask value +/* software flow control on chip mask value */ #define MOXA_MUST_EFR_SF_MASK 0x0F -// send Xon1/Xoff1 +/* send Xon1/Xoff1 */ #define MOXA_MUST_EFR_SF_TX1 0x08 -// send Xon2/Xoff2 +/* send Xon2/Xoff2 */ #define MOXA_MUST_EFR_SF_TX2 0x04 -// send Xon1,Xon2/Xoff1,Xoff2 +/* send Xon1,Xon2/Xoff1,Xoff2 */ #define MOXA_MUST_EFR_SF_TX12 0x0C -// don't send Xon/Xoff +/* don't send Xon/Xoff */ #define MOXA_MUST_EFR_SF_TX_NO 0x00 -// Tx software flow control mask +/* Tx software flow control mask */ #define MOXA_MUST_EFR_SF_TX_MASK 0x0C -// don't receive Xon/Xoff +/* don't receive Xon/Xoff */ #define MOXA_MUST_EFR_SF_RX_NO 0x00 -// receive Xon1/Xoff1 +/* receive Xon1/Xoff1 */ #define MOXA_MUST_EFR_SF_RX1 0x02 -// receive Xon2/Xoff2 +/* receive Xon2/Xoff2 */ #define MOXA_MUST_EFR_SF_RX2 0x01 -// receive Xon1,Xon2/Xoff1,Xoff2 +/* receive Xon1,Xon2/Xoff1,Xoff2 */ #define MOXA_MUST_EFR_SF_RX12 0x03 -// Rx software flow control mask +/* Rx software flow control mask */ #define MOXA_MUST_EFR_SF_RX_MASK 0x03 -//#define MOXA_MUST_MIN_XOFFLIMIT 66 -//#define MOXA_MUST_MIN_XONLIMIT 20 -//#define ID1_RX_TRIG 120 - - -#define CHECK_MOXA_MUST_XOFFLIMIT(info) { \ - if ( (info)->IsMoxaMustChipFlag && \ - (info)->HandFlow.XoffLimit < MOXA_MUST_MIN_XOFFLIMIT ) { \ - (info)->HandFlow.XoffLimit = MOXA_MUST_MIN_XOFFLIMIT; \ - (info)->HandFlow.XonLimit = MOXA_MUST_MIN_XONLIMIT; \ - } \ -} - -#define ENABLE_MOXA_MUST_ENCHANCE_MODE(baseio) { \ - u8 __oldlcr, __efr; \ - __oldlcr = inb((baseio)+UART_LCR); \ +#define ENABLE_MOXA_MUST_ENCHANCE_MODE(baseio) do { \ + u8 __oldlcr, __efr; \ + __oldlcr = inb((baseio)+UART_LCR); \ outb(MOXA_MUST_ENTER_ENCHANCE, (baseio)+UART_LCR); \ - __efr = inb((baseio)+MOXA_MUST_EFR_REGISTER); \ - __efr |= MOXA_MUST_EFR_EFRB_ENABLE; \ - outb(__efr, (baseio)+MOXA_MUST_EFR_REGISTER); \ - outb(__oldlcr, (baseio)+UART_LCR); \ -} - -#define DISABLE_MOXA_MUST_ENCHANCE_MODE(baseio) { \ - u8 __oldlcr, __efr; \ - __oldlcr = inb((baseio)+UART_LCR); \ + __efr = inb((baseio)+MOXA_MUST_EFR_REGISTER); \ + __efr |= MOXA_MUST_EFR_EFRB_ENABLE; \ + outb(__efr, (baseio)+MOXA_MUST_EFR_REGISTER); \ + outb(__oldlcr, (baseio)+UART_LCR); \ +} while (0) + +#define DISABLE_MOXA_MUST_ENCHANCE_MODE(baseio) do { \ + u8 __oldlcr, __efr; \ + __oldlcr = inb((baseio)+UART_LCR); \ outb(MOXA_MUST_ENTER_ENCHANCE, (baseio)+UART_LCR); \ - __efr = inb((baseio)+MOXA_MUST_EFR_REGISTER); \ - __efr &= ~MOXA_MUST_EFR_EFRB_ENABLE; \ - outb(__efr, (baseio)+MOXA_MUST_EFR_REGISTER); \ - outb(__oldlcr, (baseio)+UART_LCR); \ -} - -#define SET_MOXA_MUST_XON1_VALUE(baseio, Value) { \ - u8 __oldlcr, __efr; \ - __oldlcr = inb((baseio)+UART_LCR); \ + __efr = inb((baseio)+MOXA_MUST_EFR_REGISTER); \ + __efr &= ~MOXA_MUST_EFR_EFRB_ENABLE; \ + outb(__efr, (baseio)+MOXA_MUST_EFR_REGISTER); \ + outb(__oldlcr, (baseio)+UART_LCR); \ +} while (0) + +#define SET_MOXA_MUST_XON1_VALUE(baseio, Value) do { \ + u8 __oldlcr, __efr; \ + __oldlcr = inb((baseio)+UART_LCR); \ outb(MOXA_MUST_ENTER_ENCHANCE, (baseio)+UART_LCR); \ - __efr = inb((baseio)+MOXA_MUST_EFR_REGISTER); \ - __efr &= ~MOXA_MUST_EFR_BANK_MASK; \ - __efr |= MOXA_MUST_EFR_BANK0; \ - outb(__efr, (baseio)+MOXA_MUST_EFR_REGISTER); \ + __efr = inb((baseio)+MOXA_MUST_EFR_REGISTER); \ + __efr &= ~MOXA_MUST_EFR_BANK_MASK; \ + __efr |= MOXA_MUST_EFR_BANK0; \ + outb(__efr, (baseio)+MOXA_MUST_EFR_REGISTER); \ outb((u8)(Value), (baseio)+MOXA_MUST_XON1_REGISTER); \ - outb(__oldlcr, (baseio)+UART_LCR); \ -} + outb(__oldlcr, (baseio)+UART_LCR); \ +} while (0) -#define SET_MOXA_MUST_XON2_VALUE(baseio, Value) { \ - u8 __oldlcr, __efr; \ - __oldlcr = inb((baseio)+UART_LCR); \ +#define SET_MOXA_MUST_XOFF1_VALUE(baseio, Value) do { \ + u8 __oldlcr, __efr; \ + __oldlcr = inb((baseio)+UART_LCR); \ outb(MOXA_MUST_ENTER_ENCHANCE, (baseio)+UART_LCR); \ - __efr = inb((baseio)+MOXA_MUST_EFR_REGISTER); \ - __efr &= ~MOXA_MUST_EFR_BANK_MASK; \ - __efr |= MOXA_MUST_EFR_BANK0; \ - outb(__efr, (baseio)+MOXA_MUST_EFR_REGISTER); \ - outb((u8)(Value), (baseio)+MOXA_MUST_XON2_REGISTER); \ - outb(__oldlcr, (baseio)+UART_LCR); \ -} - -#define SET_MOXA_MUST_XOFF1_VALUE(baseio, Value) { \ - u8 __oldlcr, __efr; \ - __oldlcr = inb((baseio)+UART_LCR); \ - outb(MOXA_MUST_ENTER_ENCHANCE, (baseio)+UART_LCR); \ - __efr = inb((baseio)+MOXA_MUST_EFR_REGISTER); \ - __efr &= ~MOXA_MUST_EFR_BANK_MASK; \ - __efr |= MOXA_MUST_EFR_BANK0; \ - outb(__efr, (baseio)+MOXA_MUST_EFR_REGISTER); \ + __efr = inb((baseio)+MOXA_MUST_EFR_REGISTER); \ + __efr &= ~MOXA_MUST_EFR_BANK_MASK; \ + __efr |= MOXA_MUST_EFR_BANK0; \ + outb(__efr, (baseio)+MOXA_MUST_EFR_REGISTER); \ outb((u8)(Value), (baseio)+MOXA_MUST_XOFF1_REGISTER); \ - outb(__oldlcr, (baseio)+UART_LCR); \ -} + outb(__oldlcr, (baseio)+UART_LCR); \ +} while (0) -#define SET_MOXA_MUST_XOFF2_VALUE(baseio, Value) { \ - u8 __oldlcr, __efr; \ - __oldlcr = inb((baseio)+UART_LCR); \ - outb(MOXA_MUST_ENTER_ENCHANCE, (baseio)+UART_LCR); \ - __efr = inb((baseio)+MOXA_MUST_EFR_REGISTER); \ - __efr &= ~MOXA_MUST_EFR_BANK_MASK; \ - __efr |= MOXA_MUST_EFR_BANK0; \ - outb(__efr, (baseio)+MOXA_MUST_EFR_REGISTER); \ - outb((u8)(Value), (baseio)+MOXA_MUST_XOFF2_REGISTER); \ - outb(__oldlcr, (baseio)+UART_LCR); \ -} - -#define SET_MOXA_MUST_RBRTL_VALUE(baseio, Value) { \ - u8 __oldlcr, __efr; \ - __oldlcr = inb((baseio)+UART_LCR); \ - outb(MOXA_MUST_ENTER_ENCHANCE, (baseio)+UART_LCR); \ - __efr = inb((baseio)+MOXA_MUST_EFR_REGISTER); \ - __efr &= ~MOXA_MUST_EFR_BANK_MASK; \ - __efr |= MOXA_MUST_EFR_BANK1; \ - outb(__efr, (baseio)+MOXA_MUST_EFR_REGISTER); \ - outb((u8)(Value), (baseio)+MOXA_MUST_RBRTL_REGISTER); \ - outb(__oldlcr, (baseio)+UART_LCR); \ -} - -#define SET_MOXA_MUST_RBRTH_VALUE(baseio, Value) { \ - u8 __oldlcr, __efr; \ - __oldlcr = inb((baseio)+UART_LCR); \ - outb(MOXA_MUST_ENTER_ENCHANCE, (baseio)+UART_LCR); \ - __efr = inb((baseio)+MOXA_MUST_EFR_REGISTER); \ - __efr &= ~MOXA_MUST_EFR_BANK_MASK; \ - __efr |= MOXA_MUST_EFR_BANK1; \ - outb(__efr, (baseio)+MOXA_MUST_EFR_REGISTER); \ - outb((u8)(Value), (baseio)+MOXA_MUST_RBRTH_REGISTER); \ - outb(__oldlcr, (baseio)+UART_LCR); \ -} - -#define SET_MOXA_MUST_RBRTI_VALUE(baseio, Value) { \ - u8 __oldlcr, __efr; \ - __oldlcr = inb((baseio)+UART_LCR); \ - outb(MOXA_MUST_ENTER_ENCHANCE, (baseio)+UART_LCR); \ - __efr = inb((baseio)+MOXA_MUST_EFR_REGISTER); \ - __efr &= ~MOXA_MUST_EFR_BANK_MASK; \ - __efr |= MOXA_MUST_EFR_BANK1; \ - outb(__efr, (baseio)+MOXA_MUST_EFR_REGISTER); \ - outb((u8)(Value), (baseio)+MOXA_MUST_RBRTI_REGISTER); \ - outb(__oldlcr, (baseio)+UART_LCR); \ -} - -#define SET_MOXA_MUST_THRTL_VALUE(baseio, Value) { \ - u8 __oldlcr, __efr; \ - __oldlcr = inb((baseio)+UART_LCR); \ - outb(MOXA_MUST_ENTER_ENCHANCE, (baseio)+UART_LCR); \ - __efr = inb((baseio)+MOXA_MUST_EFR_REGISTER); \ - __efr &= ~MOXA_MUST_EFR_BANK_MASK; \ - __efr |= MOXA_MUST_EFR_BANK1; \ - outb(__efr, (baseio)+MOXA_MUST_EFR_REGISTER); \ - outb((u8)(Value), (baseio)+MOXA_MUST_THRTL_REGISTER); \ - outb(__oldlcr, (baseio)+UART_LCR); \ -} - -//#define MOXA_MUST_RBRL_VALUE 4 -#define SET_MOXA_MUST_FIFO_VALUE(info) { \ - u8 __oldlcr, __efr; \ - __oldlcr = inb((info)->ioaddr+UART_LCR); \ - outb(MOXA_MUST_ENTER_ENCHANCE, (info)->ioaddr+UART_LCR); \ +#define SET_MOXA_MUST_FIFO_VALUE(info) do { \ + u8 __oldlcr, __efr; \ + __oldlcr = inb((info)->ioaddr+UART_LCR); \ + outb(MOXA_MUST_ENTER_ENCHANCE, (info)->ioaddr+UART_LCR);\ __efr = inb((info)->ioaddr+MOXA_MUST_EFR_REGISTER); \ - __efr &= ~MOXA_MUST_EFR_BANK_MASK; \ - __efr |= MOXA_MUST_EFR_BANK1; \ + __efr &= ~MOXA_MUST_EFR_BANK_MASK; \ + __efr |= MOXA_MUST_EFR_BANK1; \ outb(__efr, (info)->ioaddr+MOXA_MUST_EFR_REGISTER); \ - outb((u8)((info)->rx_high_water), (info)->ioaddr+MOXA_MUST_RBRTH_REGISTER); \ - outb((u8)((info)->rx_trigger), (info)->ioaddr+MOXA_MUST_RBRTI_REGISTER); \ - outb((u8)((info)->rx_low_water), (info)->ioaddr+MOXA_MUST_RBRTL_REGISTER); \ - outb(__oldlcr, (info)->ioaddr+UART_LCR); \ -} - - - -#define SET_MOXA_MUST_ENUM_VALUE(baseio, Value) { \ - u8 __oldlcr, __efr; \ - __oldlcr = inb((baseio)+UART_LCR); \ + outb((u8)((info)->rx_high_water), (info)->ioaddr+ \ + MOXA_MUST_RBRTH_REGISTER); \ + outb((u8)((info)->rx_trigger), (info)->ioaddr+ \ + MOXA_MUST_RBRTI_REGISTER); \ + outb((u8)((info)->rx_low_water), (info)->ioaddr+ \ + MOXA_MUST_RBRTL_REGISTER); \ + outb(__oldlcr, (info)->ioaddr+UART_LCR); \ +} while (0) + +#define SET_MOXA_MUST_ENUM_VALUE(baseio, Value) do { \ + u8 __oldlcr, __efr; \ + __oldlcr = inb((baseio)+UART_LCR); \ outb(MOXA_MUST_ENTER_ENCHANCE, (baseio)+UART_LCR); \ - __efr = inb((baseio)+MOXA_MUST_EFR_REGISTER); \ - __efr &= ~MOXA_MUST_EFR_BANK_MASK; \ - __efr |= MOXA_MUST_EFR_BANK2; \ - outb(__efr, (baseio)+MOXA_MUST_EFR_REGISTER); \ + __efr = inb((baseio)+MOXA_MUST_EFR_REGISTER); \ + __efr &= ~MOXA_MUST_EFR_BANK_MASK; \ + __efr |= MOXA_MUST_EFR_BANK2; \ + outb(__efr, (baseio)+MOXA_MUST_EFR_REGISTER); \ outb((u8)(Value), (baseio)+MOXA_MUST_ENUM_REGISTER); \ - outb(__oldlcr, (baseio)+UART_LCR); \ -} + outb(__oldlcr, (baseio)+UART_LCR); \ +} while (0) -#define GET_MOXA_MUST_HARDWARE_ID(baseio, pId) { \ - u8 __oldlcr, __efr; \ - __oldlcr = inb((baseio)+UART_LCR); \ - outb(MOXA_MUST_ENTER_ENCHANCE, (baseio)+UART_LCR); \ - __efr = inb((baseio)+MOXA_MUST_EFR_REGISTER); \ - __efr &= ~MOXA_MUST_EFR_BANK_MASK; \ - __efr |= MOXA_MUST_EFR_BANK2; \ - outb(__efr, (baseio)+MOXA_MUST_EFR_REGISTER); \ - *pId = inb((baseio)+MOXA_MUST_HWID_REGISTER); \ - outb(__oldlcr, (baseio)+UART_LCR); \ -} - -#define SET_MOXA_MUST_NO_SOFTWARE_FLOW_CONTROL(baseio) { \ - u8 __oldlcr, __efr; \ - __oldlcr = inb((baseio)+UART_LCR); \ - outb(MOXA_MUST_ENTER_ENCHANCE, (baseio)+UART_LCR); \ - __efr = inb((baseio)+MOXA_MUST_EFR_REGISTER); \ - __efr &= ~MOXA_MUST_EFR_SF_MASK; \ - outb(__efr, (baseio)+MOXA_MUST_EFR_REGISTER); \ - outb(__oldlcr, (baseio)+UART_LCR); \ -} - -#define SET_MOXA_MUST_JUST_TX_SOFTWARE_FLOW_CONTROL(baseio) { \ - u8 __oldlcr, __efr; \ - __oldlcr = inb((baseio)+UART_LCR); \ +#define GET_MOXA_MUST_HARDWARE_ID(baseio, pId) do { \ + u8 __oldlcr, __efr; \ + __oldlcr = inb((baseio)+UART_LCR); \ outb(MOXA_MUST_ENTER_ENCHANCE, (baseio)+UART_LCR); \ - __efr = inb((baseio)+MOXA_MUST_EFR_REGISTER); \ - __efr &= ~MOXA_MUST_EFR_SF_MASK; \ - __efr |= MOXA_MUST_EFR_SF_TX1; \ - outb(__efr, (baseio)+MOXA_MUST_EFR_REGISTER); \ - outb(__oldlcr, (baseio)+UART_LCR); \ -} - -#define ENABLE_MOXA_MUST_TX_SOFTWARE_FLOW_CONTROL(baseio) { \ - u8 __oldlcr, __efr; \ - __oldlcr = inb((baseio)+UART_LCR); \ + __efr = inb((baseio)+MOXA_MUST_EFR_REGISTER); \ + __efr &= ~MOXA_MUST_EFR_BANK_MASK; \ + __efr |= MOXA_MUST_EFR_BANK2; \ + outb(__efr, (baseio)+MOXA_MUST_EFR_REGISTER); \ + *pId = inb((baseio)+MOXA_MUST_HWID_REGISTER); \ + outb(__oldlcr, (baseio)+UART_LCR); \ +} while (0) + +#define SET_MOXA_MUST_NO_SOFTWARE_FLOW_CONTROL(baseio) do { \ + u8 __oldlcr, __efr; \ + __oldlcr = inb((baseio)+UART_LCR); \ outb(MOXA_MUST_ENTER_ENCHANCE, (baseio)+UART_LCR); \ - __efr = inb((baseio)+MOXA_MUST_EFR_REGISTER); \ - __efr &= ~MOXA_MUST_EFR_SF_TX_MASK; \ - __efr |= MOXA_MUST_EFR_SF_TX1; \ - outb(__efr, (baseio)+MOXA_MUST_EFR_REGISTER); \ - outb(__oldlcr, (baseio)+UART_LCR); \ -} - -#define DISABLE_MOXA_MUST_TX_SOFTWARE_FLOW_CONTROL(baseio) { \ - u8 __oldlcr, __efr; \ - __oldlcr = inb((baseio)+UART_LCR); \ + __efr = inb((baseio)+MOXA_MUST_EFR_REGISTER); \ + __efr &= ~MOXA_MUST_EFR_SF_MASK; \ + outb(__efr, (baseio)+MOXA_MUST_EFR_REGISTER); \ + outb(__oldlcr, (baseio)+UART_LCR); \ +} while (0) + +#define ENABLE_MOXA_MUST_TX_SOFTWARE_FLOW_CONTROL(baseio) do { \ + u8 __oldlcr, __efr; \ + __oldlcr = inb((baseio)+UART_LCR); \ outb(MOXA_MUST_ENTER_ENCHANCE, (baseio)+UART_LCR); \ - __efr = inb((baseio)+MOXA_MUST_EFR_REGISTER); \ - __efr &= ~MOXA_MUST_EFR_SF_TX_MASK; \ - outb(__efr, (baseio)+MOXA_MUST_EFR_REGISTER); \ - outb(__oldlcr, (baseio)+UART_LCR); \ -} - -#define SET_MOXA_MUST_JUST_RX_SOFTWARE_FLOW_CONTROL(baseio) { \ - u8 __oldlcr, __efr; \ - __oldlcr = inb((baseio)+UART_LCR); \ + __efr = inb((baseio)+MOXA_MUST_EFR_REGISTER); \ + __efr &= ~MOXA_MUST_EFR_SF_TX_MASK; \ + __efr |= MOXA_MUST_EFR_SF_TX1; \ + outb(__efr, (baseio)+MOXA_MUST_EFR_REGISTER); \ + outb(__oldlcr, (baseio)+UART_LCR); \ +} while (0) + +#define DISABLE_MOXA_MUST_TX_SOFTWARE_FLOW_CONTROL(baseio) do { \ + u8 __oldlcr, __efr; \ + __oldlcr = inb((baseio)+UART_LCR); \ outb(MOXA_MUST_ENTER_ENCHANCE, (baseio)+UART_LCR); \ - __efr = inb((baseio)+MOXA_MUST_EFR_REGISTER); \ - __efr &= ~MOXA_MUST_EFR_SF_MASK; \ - __efr |= MOXA_MUST_EFR_SF_RX1; \ - outb(__efr, (baseio)+MOXA_MUST_EFR_REGISTER); \ - outb(__oldlcr, (baseio)+UART_LCR); \ -} - -#define ENABLE_MOXA_MUST_RX_SOFTWARE_FLOW_CONTROL(baseio) { \ - u8 __oldlcr, __efr; \ - __oldlcr = inb((baseio)+UART_LCR); \ + __efr = inb((baseio)+MOXA_MUST_EFR_REGISTER); \ + __efr &= ~MOXA_MUST_EFR_SF_TX_MASK; \ + outb(__efr, (baseio)+MOXA_MUST_EFR_REGISTER); \ + outb(__oldlcr, (baseio)+UART_LCR); \ +} while (0) + +#define ENABLE_MOXA_MUST_RX_SOFTWARE_FLOW_CONTROL(baseio) do { \ + u8 __oldlcr, __efr; \ + __oldlcr = inb((baseio)+UART_LCR); \ outb(MOXA_MUST_ENTER_ENCHANCE, (baseio)+UART_LCR); \ - __efr = inb((baseio)+MOXA_MUST_EFR_REGISTER); \ - __efr &= ~MOXA_MUST_EFR_SF_RX_MASK; \ - __efr |= MOXA_MUST_EFR_SF_RX1; \ - outb(__efr, (baseio)+MOXA_MUST_EFR_REGISTER); \ - outb(__oldlcr, (baseio)+UART_LCR); \ -} - -#define DISABLE_MOXA_MUST_RX_SOFTWARE_FLOW_CONTROL(baseio) { \ - u8 __oldlcr, __efr; \ - __oldlcr = inb((baseio)+UART_LCR); \ + __efr = inb((baseio)+MOXA_MUST_EFR_REGISTER); \ + __efr &= ~MOXA_MUST_EFR_SF_RX_MASK; \ + __efr |= MOXA_MUST_EFR_SF_RX1; \ + outb(__efr, (baseio)+MOXA_MUST_EFR_REGISTER); \ + outb(__oldlcr, (baseio)+UART_LCR); \ +} while (0) + +#define DISABLE_MOXA_MUST_RX_SOFTWARE_FLOW_CONTROL(baseio) do { \ + u8 __oldlcr, __efr; \ + __oldlcr = inb((baseio)+UART_LCR); \ outb(MOXA_MUST_ENTER_ENCHANCE, (baseio)+UART_LCR); \ - __efr = inb((baseio)+MOXA_MUST_EFR_REGISTER); \ - __efr &= ~MOXA_MUST_EFR_SF_RX_MASK; \ - outb(__efr, (baseio)+MOXA_MUST_EFR_REGISTER); \ - outb(__oldlcr, (baseio)+UART_LCR); \ -} - -#define ENABLE_MOXA_MUST_TX_RX_SOFTWARE_FLOW_CONTROL(baseio) { \ - u8 __oldlcr, __efr; \ - __oldlcr = inb((baseio)+UART_LCR); \ - outb(MOXA_MUST_ENTER_ENCHANCE, (baseio)+UART_LCR); \ - __efr = inb((baseio)+MOXA_MUST_EFR_REGISTER); \ - __efr &= ~MOXA_MUST_EFR_SF_MASK; \ - __efr |= (MOXA_MUST_EFR_SF_RX1|MOXA_MUST_EFR_SF_TX1); \ - outb(__efr, (baseio)+MOXA_MUST_EFR_REGISTER); \ - outb(__oldlcr, (baseio)+UART_LCR); \ -} - -#define ENABLE_MOXA_MUST_XON_ANY_FLOW_CONTROL(baseio) { \ - u8 __oldmcr; \ - __oldmcr = inb((baseio)+UART_MCR); \ - __oldmcr |= MOXA_MUST_MCR_XON_ANY; \ - outb(__oldmcr, (baseio)+UART_MCR); \ -} - -#define DISABLE_MOXA_MUST_XON_ANY_FLOW_CONTROL(baseio) { \ - u8 __oldmcr; \ - __oldmcr = inb((baseio)+UART_MCR); \ - __oldmcr &= ~MOXA_MUST_MCR_XON_ANY; \ - outb(__oldmcr, (baseio)+UART_MCR); \ -} - -#define READ_MOXA_MUST_GDL(baseio) inb((baseio)+MOXA_MUST_GDL_REGISTER) - - -#ifndef INIT_WORK -#define INIT_WORK(_work, _func, _data){ \ - _data->tqueue.routine = _func;\ - _data->tqueue.data = _data;\ - } -#endif + __efr = inb((baseio)+MOXA_MUST_EFR_REGISTER); \ + __efr &= ~MOXA_MUST_EFR_SF_RX_MASK; \ + outb(__efr, (baseio)+MOXA_MUST_EFR_REGISTER); \ + outb(__oldlcr, (baseio)+UART_LCR); \ +} while (0) #endif diff --git a/drivers/char/n_r3964.c b/drivers/char/n_r3964.c index dc6d418..65f2d3a 100644 --- a/drivers/char/n_r3964.c +++ b/drivers/char/n_r3964.c @@ -60,62 +60,56 @@ #include #include #include #include -#include /* used in new tty drivers */ -#include /* used in new tty drivers */ +#include /* used in new tty drivers */ +#include /* used in new tty drivers */ #include #include #include #include #include - -//#define DEBUG_QUEUE +/*#define DEBUG_QUEUE*/ /* Log successful handshake and protocol operations */ -//#define DEBUG_PROTO_S +/*#define DEBUG_PROTO_S*/ /* Log handshake and protocol errors: */ -//#define DEBUG_PROTO_E +/*#define DEBUG_PROTO_E*/ /* Log Linediscipline operations (open, close, read, write...): */ -//#define DEBUG_LDISC +/*#define DEBUG_LDISC*/ /* Log module and memory operations (init, cleanup; kmalloc, kfree): */ -//#define DEBUG_MODUL +/*#define DEBUG_MODUL*/ /* Macro helpers for debug output: */ -#define TRACE(format, args...) printk("r3964: " format "\n" , ## args); +#define TRACE(format, args...) printk("r3964: " format "\n" , ## args) #ifdef DEBUG_MODUL -#define TRACE_M(format, args...) printk("r3964: " format "\n" , ## args); +#define TRACE_M(format, args...) printk("r3964: " format "\n" , ## args) #else -#define TRACE_M(fmt, arg...) /**/ +#define TRACE_M(fmt, arg...) do {} while (0) #endif - #ifdef DEBUG_PROTO_S -#define TRACE_PS(format, args...) printk("r3964: " format "\n" , ## args); +#define TRACE_PS(format, args...) printk("r3964: " format "\n" , ## args) #else -#define TRACE_PS(fmt, arg...) /**/ +#define TRACE_PS(fmt, arg...) do {} while (0) #endif - #ifdef DEBUG_PROTO_E -#define TRACE_PE(format, args...) printk("r3964: " format "\n" , ## args); +#define TRACE_PE(format, args...) printk("r3964: " format "\n" , ## args) #else -#define TRACE_PE(fmt, arg...) /**/ +#define TRACE_PE(fmt, arg...) do {} while (0) #endif - #ifdef DEBUG_LDISC -#define TRACE_L(format, args...) printk("r3964: " format "\n" , ## args); +#define TRACE_L(format, args...) printk("r3964: " format "\n" , ## args) #else -#define TRACE_L(fmt, arg...) /**/ +#define TRACE_L(fmt, arg...) do {} while (0) #endif - #ifdef DEBUG_QUEUE -#define TRACE_Q(format, args...) printk("r3964: " format "\n" , ## args); +#define TRACE_Q(format, args...) printk("r3964: " format "\n" , ## args) #else -#define TRACE_Q(fmt, arg...) /**/ +#define TRACE_Q(fmt, arg...) do {} while (0) #endif - static void add_tx_queue(struct r3964_info *, struct r3964_block_header *); static void remove_from_tx_queue(struct r3964_info *pInfo, int error_code); static void put_char(struct r3964_info *pInfo, unsigned char ch); @@ -126,937 +120,830 @@ static void receive_char(struct r3964_in static void receive_error(struct r3964_info *pInfo, const char flag); static void on_timeout(unsigned long priv); static int enable_signals(struct r3964_info *pInfo, struct pid *pid, int arg); -static int read_telegram(struct r3964_info *pInfo, struct pid *pid, unsigned char __user *buf); +static int read_telegram(struct r3964_info *pInfo, struct pid *pid, + unsigned char __user * buf); static void add_msg(struct r3964_client_info *pClient, int msg_id, int arg, - int error_code, struct r3964_block_header *pBlock); -static struct r3964_message* remove_msg(struct r3964_info *pInfo, - struct r3964_client_info *pClient); -static void remove_client_block(struct r3964_info *pInfo, - struct r3964_client_info *pClient); + int error_code, struct r3964_block_header *pBlock); +static struct r3964_message *remove_msg(struct r3964_info *pInfo, + struct r3964_client_info *pClient); +static void remove_client_block(struct r3964_info *pInfo, + struct r3964_client_info *pClient); -static int r3964_open(struct tty_struct *tty); +static int r3964_open(struct tty_struct *tty); static void r3964_close(struct tty_struct *tty); static ssize_t r3964_read(struct tty_struct *tty, struct file *file, - unsigned char __user *buf, size_t nr); -static ssize_t r3964_write(struct tty_struct * tty, struct file * file, - const unsigned char * buf, size_t nr); -static int r3964_ioctl(struct tty_struct * tty, struct file * file, - unsigned int cmd, unsigned long arg); -static void r3964_set_termios(struct tty_struct *tty, struct ktermios * old); -static unsigned int r3964_poll(struct tty_struct * tty, struct file * file, - struct poll_table_struct *wait); + unsigned char __user * buf, size_t nr); +static ssize_t r3964_write(struct tty_struct *tty, struct file *file, + const unsigned char *buf, size_t nr); +static int r3964_ioctl(struct tty_struct *tty, struct file *file, + unsigned int cmd, unsigned long arg); +static void r3964_set_termios(struct tty_struct *tty, struct ktermios *old); +static unsigned int r3964_poll(struct tty_struct *tty, struct file *file, + struct poll_table_struct *wait); static void r3964_receive_buf(struct tty_struct *tty, const unsigned char *cp, - char *fp, int count); + char *fp, int count); static struct tty_ldisc tty_ldisc_N_R3964 = { - .owner = THIS_MODULE, - .magic = TTY_LDISC_MAGIC, - .name = "R3964", - .open = r3964_open, - .close = r3964_close, - .read = r3964_read, - .write = r3964_write, - .ioctl = r3964_ioctl, + .owner = THIS_MODULE, + .magic = TTY_LDISC_MAGIC, + .name = "R3964", + .open = r3964_open, + .close = r3964_close, + .read = r3964_read, + .write = r3964_write, + .ioctl = r3964_ioctl, .set_termios = r3964_set_termios, - .poll = r3964_poll, + .poll = r3964_poll, .receive_buf = r3964_receive_buf, }; - - static void dump_block(const unsigned char *block, unsigned int length) { - unsigned int i,j; - char linebuf[16*3+1]; - - for(i=0;ilock, flags); - - pHeader->next = NULL; - - if(pInfo->tx_last == NULL) - { - pInfo->tx_first = pInfo->tx_last = pHeader; - } - else - { - pInfo->tx_last->next = pHeader; - pInfo->tx_last = pHeader; - } - - spin_unlock_irqrestore(&pInfo->lock, flags); - - TRACE_Q("add_tx_queue %p, length %d, tx_first = %p", - pHeader, pHeader->length, pInfo->tx_first ); + unsigned long flags; + + spin_lock_irqsave(&pInfo->lock, flags); + + pHeader->next = NULL; + + if (pInfo->tx_last == NULL) { + pInfo->tx_first = pInfo->tx_last = pHeader; + } else { + pInfo->tx_last->next = pHeader; + pInfo->tx_last = pHeader; + } + + spin_unlock_irqrestore(&pInfo->lock, flags); + + TRACE_Q("add_tx_queue %p, length %d, tx_first = %p", + pHeader, pHeader->length, pInfo->tx_first); } static void remove_from_tx_queue(struct r3964_info *pInfo, int error_code) { - struct r3964_block_header *pHeader; - unsigned long flags; + struct r3964_block_header *pHeader; + unsigned long flags; #ifdef DEBUG_QUEUE - struct r3964_block_header *pDump; + struct r3964_block_header *pDump; #endif - - pHeader = pInfo->tx_first; - if(pHeader==NULL) - return; + pHeader = pInfo->tx_first; + + if (pHeader == NULL) + return; #ifdef DEBUG_QUEUE - printk("r3964: remove_from_tx_queue: %p, length %u - ", - pHeader, pHeader->length ); - for(pDump=pHeader;pDump;pDump=pDump->next) - printk("%p ", pDump); - printk("\n"); + printk("r3964: remove_from_tx_queue: %p, length %u - ", + pHeader, pHeader->length); + for (pDump = pHeader; pDump; pDump = pDump->next) + printk("%p ", pDump); + printk("\n"); #endif + if (pHeader->owner) { + if (error_code) { + add_msg(pHeader->owner, R3964_MSG_ACK, 0, + error_code, NULL); + } else { + add_msg(pHeader->owner, R3964_MSG_ACK, pHeader->length, + error_code, NULL); + } + wake_up_interruptible(&pInfo->read_wait); + } + + spin_lock_irqsave(&pInfo->lock, flags); + + pInfo->tx_first = pHeader->next; + if (pInfo->tx_first == NULL) { + pInfo->tx_last = NULL; + } + + spin_unlock_irqrestore(&pInfo->lock, flags); + + kfree(pHeader); + TRACE_M("remove_from_tx_queue - kfree %p", pHeader); - if(pHeader->owner) - { - if(error_code) - { - add_msg(pHeader->owner, R3964_MSG_ACK, 0, - error_code, NULL); - } - else - { - add_msg(pHeader->owner, R3964_MSG_ACK, pHeader->length, - error_code, NULL); - } - wake_up_interruptible (&pInfo->read_wait); - } - - spin_lock_irqsave(&pInfo->lock, flags); - - pInfo->tx_first = pHeader->next; - if(pInfo->tx_first==NULL) - { - pInfo->tx_last = NULL; - } - - spin_unlock_irqrestore(&pInfo->lock, flags); - - kfree(pHeader); - TRACE_M("remove_from_tx_queue - kfree %p",pHeader); - - TRACE_Q("remove_from_tx_queue: tx_first = %p, tx_last = %p", - pInfo->tx_first, pInfo->tx_last ); + TRACE_Q("remove_from_tx_queue: tx_first = %p, tx_last = %p", + pInfo->tx_first, pInfo->tx_last); } -static void add_rx_queue(struct r3964_info *pInfo, struct r3964_block_header *pHeader) +static void add_rx_queue(struct r3964_info *pInfo, + struct r3964_block_header *pHeader) { - unsigned long flags; - - spin_lock_irqsave(&pInfo->lock, flags); - - pHeader->next = NULL; - - if(pInfo->rx_last == NULL) - { - pInfo->rx_first = pInfo->rx_last = pHeader; - } - else - { - pInfo->rx_last->next = pHeader; - pInfo->rx_last = pHeader; - } - pInfo->blocks_in_rx_queue++; - - spin_unlock_irqrestore(&pInfo->lock, flags); - - TRACE_Q("add_rx_queue: %p, length = %d, rx_first = %p, count = %d", - pHeader, pHeader->length, - pInfo->rx_first, pInfo->blocks_in_rx_queue); + unsigned long flags; + + spin_lock_irqsave(&pInfo->lock, flags); + + pHeader->next = NULL; + + if (pInfo->rx_last == NULL) { + pInfo->rx_first = pInfo->rx_last = pHeader; + } else { + pInfo->rx_last->next = pHeader; + pInfo->rx_last = pHeader; + } + pInfo->blocks_in_rx_queue++; + + spin_unlock_irqrestore(&pInfo->lock, flags); + + TRACE_Q("add_rx_queue: %p, length = %d, rx_first = %p, count = %d", + pHeader, pHeader->length, + pInfo->rx_first, pInfo->blocks_in_rx_queue); } static void remove_from_rx_queue(struct r3964_info *pInfo, - struct r3964_block_header *pHeader) + struct r3964_block_header *pHeader) { - unsigned long flags; - struct r3964_block_header *pFind; - - if(pHeader==NULL) - return; - - TRACE_Q("remove_from_rx_queue: rx_first = %p, rx_last = %p, count = %d", - pInfo->rx_first, pInfo->rx_last, pInfo->blocks_in_rx_queue ); - TRACE_Q("remove_from_rx_queue: %p, length %u", - pHeader, pHeader->length ); - - spin_lock_irqsave(&pInfo->lock, flags); - - if(pInfo->rx_first == pHeader) - { - /* Remove the first block in the linked list: */ - pInfo->rx_first = pHeader->next; - - if(pInfo->rx_first==NULL) - { - pInfo->rx_last = NULL; - } - pInfo->blocks_in_rx_queue--; - } - else - { - /* Find block to remove: */ - for(pFind=pInfo->rx_first; pFind; pFind=pFind->next) - { - if(pFind->next == pHeader) - { - /* Got it. */ - pFind->next = pHeader->next; - pInfo->blocks_in_rx_queue--; - if(pFind->next==NULL) - { - /* Oh, removed the last one! */ - pInfo->rx_last = pFind; - } - break; - } - } - } - - spin_unlock_irqrestore(&pInfo->lock, flags); - - kfree(pHeader); - TRACE_M("remove_from_rx_queue - kfree %p",pHeader); - - TRACE_Q("remove_from_rx_queue: rx_first = %p, rx_last = %p, count = %d", - pInfo->rx_first, pInfo->rx_last, pInfo->blocks_in_rx_queue ); + unsigned long flags; + struct r3964_block_header *pFind; + + if (pHeader == NULL) + return; + + TRACE_Q("remove_from_rx_queue: rx_first = %p, rx_last = %p, count = %d", + pInfo->rx_first, pInfo->rx_last, pInfo->blocks_in_rx_queue); + TRACE_Q("remove_from_rx_queue: %p, length %u", + pHeader, pHeader->length); + + spin_lock_irqsave(&pInfo->lock, flags); + + if (pInfo->rx_first == pHeader) { + /* Remove the first block in the linked list: */ + pInfo->rx_first = pHeader->next; + + if (pInfo->rx_first == NULL) { + pInfo->rx_last = NULL; + } + pInfo->blocks_in_rx_queue--; + } else { + /* Find block to remove: */ + for (pFind = pInfo->rx_first; pFind; pFind = pFind->next) { + if (pFind->next == pHeader) { + /* Got it. */ + pFind->next = pHeader->next; + pInfo->blocks_in_rx_queue--; + if (pFind->next == NULL) { + /* Oh, removed the last one! */ + pInfo->rx_last = pFind; + } + break; + } + } + } + + spin_unlock_irqrestore(&pInfo->lock, flags); + + kfree(pHeader); + TRACE_M("remove_from_rx_queue - kfree %p", pHeader); + + TRACE_Q("remove_from_rx_queue: rx_first = %p, rx_last = %p, count = %d", + pInfo->rx_first, pInfo->rx_last, pInfo->blocks_in_rx_queue); } static void put_char(struct r3964_info *pInfo, unsigned char ch) { - struct tty_struct *tty = pInfo->tty; + struct tty_struct *tty = pInfo->tty; - if(tty==NULL) - return; + if (tty == NULL) + return; - if(tty->driver->put_char) - { - tty->driver->put_char(tty, ch); - } - pInfo->bcc ^= ch; + if (tty->driver->put_char) { + tty->driver->put_char(tty, ch); + } + pInfo->bcc ^= ch; } static void flush(struct r3964_info *pInfo) { - struct tty_struct *tty = pInfo->tty; + struct tty_struct *tty = pInfo->tty; - if(tty==NULL) - return; + if (tty == NULL) + return; - if(tty->driver->flush_chars) - { - tty->driver->flush_chars(tty); - } + if (tty->driver->flush_chars) { + tty->driver->flush_chars(tty); + } } static void trigger_transmit(struct r3964_info *pInfo) { - unsigned long flags; - + unsigned long flags; - spin_lock_irqsave(&pInfo->lock, flags); + spin_lock_irqsave(&pInfo->lock, flags); - if((pInfo->state == R3964_IDLE) && (pInfo->tx_first!=NULL)) - { - pInfo->state = R3964_TX_REQUEST; - pInfo->nRetry=0; - pInfo->flags &= ~R3964_ERROR; - mod_timer(&pInfo->tmr, jiffies + R3964_TO_QVZ); + if ((pInfo->state == R3964_IDLE) && (pInfo->tx_first != NULL)) { + pInfo->state = R3964_TX_REQUEST; + pInfo->nRetry = 0; + pInfo->flags &= ~R3964_ERROR; + mod_timer(&pInfo->tmr, jiffies + R3964_TO_QVZ); - spin_unlock_irqrestore(&pInfo->lock, flags); + spin_unlock_irqrestore(&pInfo->lock, flags); - TRACE_PS("trigger_transmit - sent STX"); + TRACE_PS("trigger_transmit - sent STX"); - put_char(pInfo, STX); - flush(pInfo); + put_char(pInfo, STX); + flush(pInfo); - pInfo->bcc = 0; - } - else - { - spin_unlock_irqrestore(&pInfo->lock, flags); - } + pInfo->bcc = 0; + } else { + spin_unlock_irqrestore(&pInfo->lock, flags); + } } static void retry_transmit(struct r3964_info *pInfo) { - if(pInfo->nRetrynRetry); - pInfo->bcc = 0; - put_char(pInfo, STX); - flush(pInfo); - pInfo->state = R3964_TX_REQUEST; - pInfo->nRetry++; - mod_timer(&pInfo->tmr, jiffies + R3964_TO_QVZ); - } - else - { - TRACE_PE("transmission failed after %d retries", - R3964_MAX_RETRIES); - - remove_from_tx_queue(pInfo, R3964_TX_FAIL); - - put_char(pInfo, NAK); - flush(pInfo); - pInfo->state = R3964_IDLE; - - trigger_transmit(pInfo); - } + if (pInfo->nRetry < R3964_MAX_RETRIES) { + TRACE_PE("transmission failed. Retry #%d", pInfo->nRetry); + pInfo->bcc = 0; + put_char(pInfo, STX); + flush(pInfo); + pInfo->state = R3964_TX_REQUEST; + pInfo->nRetry++; + mod_timer(&pInfo->tmr, jiffies + R3964_TO_QVZ); + } else { + TRACE_PE("transmission failed after %d retries", + R3964_MAX_RETRIES); + + remove_from_tx_queue(pInfo, R3964_TX_FAIL); + + put_char(pInfo, NAK); + flush(pInfo); + pInfo->state = R3964_IDLE; + + trigger_transmit(pInfo); + } } - static void transmit_block(struct r3964_info *pInfo) { - struct tty_struct *tty = pInfo->tty; - struct r3964_block_header *pBlock = pInfo->tx_first; - int room=0; - - if((tty==NULL) || (pBlock==NULL)) - { - return; - } - - if(tty->driver->write_room) - room=tty->driver->write_room(tty); - - TRACE_PS("transmit_block %p, room %d, length %d", - pBlock, room, pBlock->length); - - while(pInfo->tx_position < pBlock->length) - { - if(room<2) - break; - - if(pBlock->data[pInfo->tx_position]==DLE) - { - /* send additional DLE char: */ - put_char(pInfo, DLE); - } - put_char(pInfo, pBlock->data[pInfo->tx_position++]); - - room--; - } - - if((pInfo->tx_position == pBlock->length) && (room>=3)) - { - put_char(pInfo, DLE); - put_char(pInfo, ETX); - if(pInfo->flags & R3964_BCC) - { - put_char(pInfo, pInfo->bcc); - } - pInfo->state = R3964_WAIT_FOR_TX_ACK; - mod_timer(&pInfo->tmr, jiffies + R3964_TO_QVZ); - } - flush(pInfo); + struct tty_struct *tty = pInfo->tty; + struct r3964_block_header *pBlock = pInfo->tx_first; + int room = 0; + + if ((tty == NULL) || (pBlock == NULL)) { + return; + } + + if (tty->driver->write_room) + room = tty->driver->write_room(tty); + + TRACE_PS("transmit_block %p, room %d, length %d", + pBlock, room, pBlock->length); + + while (pInfo->tx_position < pBlock->length) { + if (room < 2) + break; + + if (pBlock->data[pInfo->tx_position] == DLE) { + /* send additional DLE char: */ + put_char(pInfo, DLE); + } + put_char(pInfo, pBlock->data[pInfo->tx_position++]); + + room--; + } + + if ((pInfo->tx_position == pBlock->length) && (room >= 3)) { + put_char(pInfo, DLE); + put_char(pInfo, ETX); + if (pInfo->flags & R3964_BCC) { + put_char(pInfo, pInfo->bcc); + } + pInfo->state = R3964_WAIT_FOR_TX_ACK; + mod_timer(&pInfo->tmr, jiffies + R3964_TO_QVZ); + } + flush(pInfo); } static void on_receive_block(struct r3964_info *pInfo) { - unsigned int length; - struct r3964_client_info *pClient; - struct r3964_block_header *pBlock; - - length=pInfo->rx_position; - - /* compare byte checksum characters: */ - if(pInfo->flags & R3964_BCC) - { - if(pInfo->bcc!=pInfo->last_rx) - { - TRACE_PE("checksum error - got %x but expected %x", - pInfo->last_rx, pInfo->bcc); - pInfo->flags |= R3964_CHECKSUM; - } - } - - /* check for errors (parity, overrun,...): */ - if(pInfo->flags & R3964_ERROR) - { - TRACE_PE("on_receive_block - transmission failed error %x", - pInfo->flags & R3964_ERROR); - - put_char(pInfo, NAK); - flush(pInfo); - if(pInfo->nRetrystate=R3964_WAIT_FOR_RX_REPEAT; - pInfo->nRetry++; - mod_timer(&pInfo->tmr, jiffies + R3964_TO_RX_PANIC); - } - else - { - TRACE_PE("on_receive_block - failed after max retries"); - pInfo->state=R3964_IDLE; - } - return; - } - - - /* received block; submit DLE: */ - put_char(pInfo, DLE); - flush(pInfo); - del_timer_sync(&pInfo->tmr); - TRACE_PS(" rx success: got %d chars", length); - - /* prepare struct r3964_block_header: */ - pBlock = kmalloc(length+sizeof(struct r3964_block_header), GFP_KERNEL); - TRACE_M("on_receive_block - kmalloc %p",pBlock); - - if(pBlock==NULL) - return; - - pBlock->length = length; - pBlock->data = ((unsigned char*)pBlock)+sizeof(struct r3964_block_header); - pBlock->locks = 0; - pBlock->next = NULL; - pBlock->owner = NULL; - - memcpy(pBlock->data, pInfo->rx_buf, length); - - /* queue block into rx_queue: */ - add_rx_queue(pInfo, pBlock); - - /* notify attached client processes: */ - for(pClient=pInfo->firstClient; pClient; pClient=pClient->next) - { - if(pClient->sig_flags & R3964_SIG_DATA) - { - add_msg(pClient, R3964_MSG_DATA, length, R3964_OK, pBlock); - } - } - wake_up_interruptible (&pInfo->read_wait); - - pInfo->state = R3964_IDLE; - - trigger_transmit(pInfo); -} + unsigned int length; + struct r3964_client_info *pClient; + struct r3964_block_header *pBlock; + + length = pInfo->rx_position; + + /* compare byte checksum characters: */ + if (pInfo->flags & R3964_BCC) { + if (pInfo->bcc != pInfo->last_rx) { + TRACE_PE("checksum error - got %x but expected %x", + pInfo->last_rx, pInfo->bcc); + pInfo->flags |= R3964_CHECKSUM; + } + } + + /* check for errors (parity, overrun,...): */ + if (pInfo->flags & R3964_ERROR) { + TRACE_PE("on_receive_block - transmission failed error %x", + pInfo->flags & R3964_ERROR); + + put_char(pInfo, NAK); + flush(pInfo); + if (pInfo->nRetry < R3964_MAX_RETRIES) { + pInfo->state = R3964_WAIT_FOR_RX_REPEAT; + pInfo->nRetry++; + mod_timer(&pInfo->tmr, jiffies + R3964_TO_RX_PANIC); + } else { + TRACE_PE("on_receive_block - failed after max retries"); + pInfo->state = R3964_IDLE; + } + return; + } + + /* received block; submit DLE: */ + put_char(pInfo, DLE); + flush(pInfo); + del_timer_sync(&pInfo->tmr); + TRACE_PS(" rx success: got %d chars", length); + + /* prepare struct r3964_block_header: */ + pBlock = kmalloc(length + sizeof(struct r3964_block_header), + GFP_KERNEL); + TRACE_M("on_receive_block - kmalloc %p", pBlock); + + if (pBlock == NULL) + return; + + pBlock->length = length; + pBlock->data = ((unsigned char *)pBlock) + + sizeof(struct r3964_block_header); + pBlock->locks = 0; + pBlock->next = NULL; + pBlock->owner = NULL; + + memcpy(pBlock->data, pInfo->rx_buf, length); + + /* queue block into rx_queue: */ + add_rx_queue(pInfo, pBlock); + + /* notify attached client processes: */ + for (pClient = pInfo->firstClient; pClient; pClient = pClient->next) { + if (pClient->sig_flags & R3964_SIG_DATA) { + add_msg(pClient, R3964_MSG_DATA, length, R3964_OK, + pBlock); + } + } + wake_up_interruptible(&pInfo->read_wait); + pInfo->state = R3964_IDLE; + + trigger_transmit(pInfo); +} static void receive_char(struct r3964_info *pInfo, const unsigned char c) { - switch(pInfo->state) - { - case R3964_TX_REQUEST: - if(c==DLE) - { - TRACE_PS("TX_REQUEST - got DLE"); - - pInfo->state = R3964_TRANSMITTING; - pInfo->tx_position = 0; - - transmit_block(pInfo); - } - else if(c==STX) - { - if(pInfo->nRetry==0) - { - TRACE_PE("TX_REQUEST - init conflict"); - if(pInfo->priority == R3964_SLAVE) - { - goto start_receiving; - } - } - else - { - TRACE_PE("TX_REQUEST - secondary init conflict!?" - " Switching to SLAVE mode for next rx."); - goto start_receiving; - } - } - else - { - TRACE_PE("TX_REQUEST - char != DLE: %x", c); - retry_transmit(pInfo); - } - break; - case R3964_TRANSMITTING: - if(c==NAK) - { - TRACE_PE("TRANSMITTING - got NAK"); - retry_transmit(pInfo); - } - else - { - TRACE_PE("TRANSMITTING - got invalid char"); - - pInfo->state = R3964_WAIT_ZVZ_BEFORE_TX_RETRY; - mod_timer(&pInfo->tmr, jiffies + R3964_TO_ZVZ); - } - break; - case R3964_WAIT_FOR_TX_ACK: - if(c==DLE) - { - TRACE_PS("WAIT_FOR_TX_ACK - got DLE"); - remove_from_tx_queue(pInfo, R3964_OK); - - pInfo->state = R3964_IDLE; - trigger_transmit(pInfo); - } - else - { - retry_transmit(pInfo); - } - break; - case R3964_WAIT_FOR_RX_REPEAT: - /* FALLTROUGH */ - case R3964_IDLE: - if(c==STX) - { - /* Prevent rx_queue from overflow: */ - if(pInfo->blocks_in_rx_queue >= R3964_MAX_BLOCKS_IN_RX_QUEUE) - { - TRACE_PE("IDLE - got STX but no space in rx_queue!"); - pInfo->state=R3964_WAIT_FOR_RX_BUF; - mod_timer(&pInfo->tmr, jiffies + R3964_TO_NO_BUF); - break; - } + switch (pInfo->state) { + case R3964_TX_REQUEST: + if (c == DLE) { + TRACE_PS("TX_REQUEST - got DLE"); + + pInfo->state = R3964_TRANSMITTING; + pInfo->tx_position = 0; + + transmit_block(pInfo); + } else if (c == STX) { + if (pInfo->nRetry == 0) { + TRACE_PE("TX_REQUEST - init conflict"); + if (pInfo->priority == R3964_SLAVE) { + goto start_receiving; + } + } else { + TRACE_PE("TX_REQUEST - secondary init " + "conflict!? Switching to SLAVE mode " + "for next rx."); + goto start_receiving; + } + } else { + TRACE_PE("TX_REQUEST - char != DLE: %x", c); + retry_transmit(pInfo); + } + break; + case R3964_TRANSMITTING: + if (c == NAK) { + TRACE_PE("TRANSMITTING - got NAK"); + retry_transmit(pInfo); + } else { + TRACE_PE("TRANSMITTING - got invalid char"); + + pInfo->state = R3964_WAIT_ZVZ_BEFORE_TX_RETRY; + mod_timer(&pInfo->tmr, jiffies + R3964_TO_ZVZ); + } + break; + case R3964_WAIT_FOR_TX_ACK: + if (c == DLE) { + TRACE_PS("WAIT_FOR_TX_ACK - got DLE"); + remove_from_tx_queue(pInfo, R3964_OK); + + pInfo->state = R3964_IDLE; + trigger_transmit(pInfo); + } else { + retry_transmit(pInfo); + } + break; + case R3964_WAIT_FOR_RX_REPEAT: + /* FALLTROUGH */ + case R3964_IDLE: + if (c == STX) { + /* Prevent rx_queue from overflow: */ + if (pInfo->blocks_in_rx_queue >= + R3964_MAX_BLOCKS_IN_RX_QUEUE) { + TRACE_PE("IDLE - got STX but no space in " + "rx_queue!"); + pInfo->state = R3964_WAIT_FOR_RX_BUF; + mod_timer(&pInfo->tmr, + jiffies + R3964_TO_NO_BUF); + break; + } start_receiving: - /* Ok, start receiving: */ - TRACE_PS("IDLE - got STX"); - pInfo->rx_position = 0; - pInfo->last_rx = 0; - pInfo->flags &= ~R3964_ERROR; - pInfo->state=R3964_RECEIVING; - mod_timer(&pInfo->tmr, jiffies + R3964_TO_ZVZ); - pInfo->nRetry = 0; - put_char(pInfo, DLE); - flush(pInfo); - pInfo->bcc = 0; - } - break; - case R3964_RECEIVING: - if(pInfo->rx_position < RX_BUF_SIZE) - { - pInfo->bcc ^= c; - - if(c==DLE) - { - if(pInfo->last_rx==DLE) - { - pInfo->last_rx = 0; - goto char_to_buf; - } - pInfo->last_rx = DLE; - break; - } - else if((c==ETX) && (pInfo->last_rx==DLE)) - { - if(pInfo->flags & R3964_BCC) - { - pInfo->state = R3964_WAIT_FOR_BCC; - mod_timer(&pInfo->tmr, jiffies + R3964_TO_ZVZ); - } - else - { - on_receive_block(pInfo); - } - } - else - { - pInfo->last_rx = c; + /* Ok, start receiving: */ + TRACE_PS("IDLE - got STX"); + pInfo->rx_position = 0; + pInfo->last_rx = 0; + pInfo->flags &= ~R3964_ERROR; + pInfo->state = R3964_RECEIVING; + mod_timer(&pInfo->tmr, jiffies + R3964_TO_ZVZ); + pInfo->nRetry = 0; + put_char(pInfo, DLE); + flush(pInfo); + pInfo->bcc = 0; + } + break; + case R3964_RECEIVING: + if (pInfo->rx_position < RX_BUF_SIZE) { + pInfo->bcc ^= c; + + if (c == DLE) { + if (pInfo->last_rx == DLE) { + pInfo->last_rx = 0; + goto char_to_buf; + } + pInfo->last_rx = DLE; + break; + } else if ((c == ETX) && (pInfo->last_rx == DLE)) { + if (pInfo->flags & R3964_BCC) { + pInfo->state = R3964_WAIT_FOR_BCC; + mod_timer(&pInfo->tmr, + jiffies + R3964_TO_ZVZ); + } else { + on_receive_block(pInfo); + } + } else { + pInfo->last_rx = c; char_to_buf: - pInfo->rx_buf[pInfo->rx_position++] = c; - mod_timer(&pInfo->tmr, jiffies + R3964_TO_ZVZ); - } - } - /* else: overflow-msg? BUF_SIZE>MTU; should not happen? */ - break; - case R3964_WAIT_FOR_BCC: - pInfo->last_rx = c; - on_receive_block(pInfo); - break; - } + pInfo->rx_buf[pInfo->rx_position++] = c; + mod_timer(&pInfo->tmr, jiffies + R3964_TO_ZVZ); + } + } + /* else: overflow-msg? BUF_SIZE>MTU; should not happen? */ + break; + case R3964_WAIT_FOR_BCC: + pInfo->last_rx = c; + on_receive_block(pInfo); + break; + } } static void receive_error(struct r3964_info *pInfo, const char flag) { - switch (flag) - { - case TTY_NORMAL: - break; - case TTY_BREAK: - TRACE_PE("received break") - pInfo->flags |= R3964_BREAK; - break; - case TTY_PARITY: - TRACE_PE("parity error") - pInfo->flags |= R3964_PARITY; - break; - case TTY_FRAME: - TRACE_PE("frame error") - pInfo->flags |= R3964_FRAME; - break; - case TTY_OVERRUN: - TRACE_PE("frame overrun") - pInfo->flags |= R3964_OVERRUN; - break; - default: - TRACE_PE("receive_error - unknown flag %d", flag); - pInfo->flags |= R3964_UNKNOWN; - break; - } + switch (flag) { + case TTY_NORMAL: + break; + case TTY_BREAK: + TRACE_PE("received break"); + pInfo->flags |= R3964_BREAK; + break; + case TTY_PARITY: + TRACE_PE("parity error"); + pInfo->flags |= R3964_PARITY; + break; + case TTY_FRAME: + TRACE_PE("frame error"); + pInfo->flags |= R3964_FRAME; + break; + case TTY_OVERRUN: + TRACE_PE("frame overrun"); + pInfo->flags |= R3964_OVERRUN; + break; + default: + TRACE_PE("receive_error - unknown flag %d", flag); + pInfo->flags |= R3964_UNKNOWN; + break; + } } static void on_timeout(unsigned long priv) { - struct r3964_info *pInfo = (void *)priv; - - switch(pInfo->state) - { - case R3964_TX_REQUEST: - TRACE_PE("TX_REQUEST - timeout"); - retry_transmit(pInfo); - break; - case R3964_WAIT_ZVZ_BEFORE_TX_RETRY: - put_char(pInfo, NAK); - flush(pInfo); - retry_transmit(pInfo); - break; - case R3964_WAIT_FOR_TX_ACK: - TRACE_PE("WAIT_FOR_TX_ACK - timeout"); - retry_transmit(pInfo); - break; - case R3964_WAIT_FOR_RX_BUF: - TRACE_PE("WAIT_FOR_RX_BUF - timeout"); - put_char(pInfo, NAK); - flush(pInfo); - pInfo->state=R3964_IDLE; - break; - case R3964_RECEIVING: - TRACE_PE("RECEIVING - timeout after %d chars", - pInfo->rx_position); - put_char(pInfo, NAK); - flush(pInfo); - pInfo->state=R3964_IDLE; - break; - case R3964_WAIT_FOR_RX_REPEAT: - TRACE_PE("WAIT_FOR_RX_REPEAT - timeout"); - pInfo->state=R3964_IDLE; - break; - case R3964_WAIT_FOR_BCC: - TRACE_PE("WAIT_FOR_BCC - timeout"); - put_char(pInfo, NAK); - flush(pInfo); - pInfo->state=R3964_IDLE; - break; - } + struct r3964_info *pInfo = (void *)priv; + + switch (pInfo->state) { + case R3964_TX_REQUEST: + TRACE_PE("TX_REQUEST - timeout"); + retry_transmit(pInfo); + break; + case R3964_WAIT_ZVZ_BEFORE_TX_RETRY: + put_char(pInfo, NAK); + flush(pInfo); + retry_transmit(pInfo); + break; + case R3964_WAIT_FOR_TX_ACK: + TRACE_PE("WAIT_FOR_TX_ACK - timeout"); + retry_transmit(pInfo); + break; + case R3964_WAIT_FOR_RX_BUF: + TRACE_PE("WAIT_FOR_RX_BUF - timeout"); + put_char(pInfo, NAK); + flush(pInfo); + pInfo->state = R3964_IDLE; + break; + case R3964_RECEIVING: + TRACE_PE("RECEIVING - timeout after %d chars", + pInfo->rx_position); + put_char(pInfo, NAK); + flush(pInfo); + pInfo->state = R3964_IDLE; + break; + case R3964_WAIT_FOR_RX_REPEAT: + TRACE_PE("WAIT_FOR_RX_REPEAT - timeout"); + pInfo->state = R3964_IDLE; + break; + case R3964_WAIT_FOR_BCC: + TRACE_PE("WAIT_FOR_BCC - timeout"); + put_char(pInfo, NAK); + flush(pInfo); + pInfo->state = R3964_IDLE; + break; + } } -static struct r3964_client_info *findClient( - struct r3964_info *pInfo, struct pid *pid) +static struct r3964_client_info *findClient(struct r3964_info *pInfo, + struct pid *pid) { - struct r3964_client_info *pClient; - - for(pClient=pInfo->firstClient; pClient; pClient=pClient->next) - { - if(pClient->pid == pid) - { - return pClient; - } - } - return NULL; + struct r3964_client_info *pClient; + + for (pClient = pInfo->firstClient; pClient; pClient = pClient->next) { + if (pClient->pid == pid) { + return pClient; + } + } + return NULL; } static int enable_signals(struct r3964_info *pInfo, struct pid *pid, int arg) { - struct r3964_client_info *pClient; - struct r3964_client_info **ppClient; - struct r3964_message *pMsg; - - if((arg & R3964_SIG_ALL)==0) - { - /* Remove client from client list */ - for(ppClient=&pInfo->firstClient; *ppClient; ppClient=&(*ppClient)->next) - { - pClient = *ppClient; - - if(pClient->pid == pid) - { - TRACE_PS("removing client %d from client list", pid_nr(pid)); - *ppClient = pClient->next; - while(pClient->msg_count) - { - pMsg=remove_msg(pInfo, pClient); - if(pMsg) - { - kfree(pMsg); - TRACE_M("enable_signals - msg kfree %p",pMsg); - } - } - put_pid(pClient->pid); - kfree(pClient); - TRACE_M("enable_signals - kfree %p",pClient); - return 0; - } - } - return -EINVAL; - } - else - { - pClient=findClient(pInfo, pid); - if(pClient) - { - /* update signal options */ - pClient->sig_flags=arg; - } - else - { - /* add client to client list */ - pClient=kmalloc(sizeof(struct r3964_client_info), GFP_KERNEL); - TRACE_M("enable_signals - kmalloc %p",pClient); - if(pClient==NULL) - return -ENOMEM; - - TRACE_PS("add client %d to client list", pid_nr(pid)); - spin_lock_init(&pClient->lock); - pClient->sig_flags=arg; - pClient->pid = get_pid(pid); - pClient->next=pInfo->firstClient; - pClient->first_msg = NULL; - pClient->last_msg = NULL; - pClient->next_block_to_read = NULL; - pClient->msg_count = 0; - pInfo->firstClient=pClient; - } - } - - return 0; + struct r3964_client_info *pClient; + struct r3964_client_info **ppClient; + struct r3964_message *pMsg; + + if ((arg & R3964_SIG_ALL) == 0) { + /* Remove client from client list */ + for (ppClient = &pInfo->firstClient; *ppClient; + ppClient = &(*ppClient)->next) { + pClient = *ppClient; + + if (pClient->pid == pid) { + TRACE_PS("removing client %d from client list", + pid_nr(pid)); + *ppClient = pClient->next; + while (pClient->msg_count) { + pMsg = remove_msg(pInfo, pClient); + if (pMsg) { + kfree(pMsg); + TRACE_M("enable_signals - msg " + "kfree %p", pMsg); + } + } + put_pid(pClient->pid); + kfree(pClient); + TRACE_M("enable_signals - kfree %p", pClient); + return 0; + } + } + return -EINVAL; + } else { + pClient = findClient(pInfo, pid); + if (pClient) { + /* update signal options */ + pClient->sig_flags = arg; + } else { + /* add client to client list */ + pClient = kmalloc(sizeof(struct r3964_client_info), + GFP_KERNEL); + TRACE_M("enable_signals - kmalloc %p", pClient); + if (pClient == NULL) + return -ENOMEM; + + TRACE_PS("add client %d to client list", pid_nr(pid)); + spin_lock_init(&pClient->lock); + pClient->sig_flags = arg; + pClient->pid = get_pid(pid); + pClient->next = pInfo->firstClient; + pClient->first_msg = NULL; + pClient->last_msg = NULL; + pClient->next_block_to_read = NULL; + pClient->msg_count = 0; + pInfo->firstClient = pClient; + } + } + + return 0; } -static int read_telegram(struct r3964_info *pInfo, struct pid *pid, unsigned char __user *buf) +static int read_telegram(struct r3964_info *pInfo, struct pid *pid, + unsigned char __user * buf) { - struct r3964_client_info *pClient; - struct r3964_block_header *block; - - if(!buf) - { - return -EINVAL; - } - - pClient=findClient(pInfo,pid); - if(pClient==NULL) - { - return -EINVAL; - } - - block=pClient->next_block_to_read; - if(!block) - { - return 0; - } - else - { - if (copy_to_user (buf, block->data, block->length)) - return -EFAULT; - - remove_client_block(pInfo, pClient); - return block->length; - } - - return -EINVAL; + struct r3964_client_info *pClient; + struct r3964_block_header *block; + + if (!buf) { + return -EINVAL; + } + + pClient = findClient(pInfo, pid); + if (pClient == NULL) { + return -EINVAL; + } + + block = pClient->next_block_to_read; + if (!block) { + return 0; + } else { + if (copy_to_user(buf, block->data, block->length)) + return -EFAULT; + + remove_client_block(pInfo, pClient); + return block->length; + } + + return -EINVAL; } static void add_msg(struct r3964_client_info *pClient, int msg_id, int arg, - int error_code, struct r3964_block_header *pBlock) + int error_code, struct r3964_block_header *pBlock) { - struct r3964_message *pMsg; - unsigned long flags; - - if(pClient->msg_countmsg_count < R3964_MAX_MSG_COUNT - 1) { queue_the_message: - pMsg = kmalloc(sizeof(struct r3964_message), - error_code?GFP_ATOMIC:GFP_KERNEL); - TRACE_M("add_msg - kmalloc %p",pMsg); - if(pMsg==NULL) { - return; - } - - spin_lock_irqsave(&pClient->lock, flags); - - pMsg->msg_id = msg_id; - pMsg->arg = arg; - pMsg->error_code = error_code; - pMsg->block = pBlock; - pMsg->next = NULL; - - if(pClient->last_msg==NULL) - { - pClient->first_msg=pClient->last_msg=pMsg; - } - else - { - pClient->last_msg->next = pMsg; - pClient->last_msg=pMsg; - } - - pClient->msg_count++; - - if(pBlock!=NULL) - { - pBlock->locks++; - } - spin_unlock_irqrestore(&pClient->lock, flags); - } - else - { - if((pClient->last_msg->msg_id == R3964_MSG_ACK) - && (pClient->last_msg->error_code==R3964_OVERFLOW)) - { - pClient->last_msg->arg++; - TRACE_PE("add_msg - inc prev OVERFLOW-msg"); - } - else - { - msg_id = R3964_MSG_ACK; - arg = 0; - error_code = R3964_OVERFLOW; - pBlock = NULL; - TRACE_PE("add_msg - queue OVERFLOW-msg"); - goto queue_the_message; - } - } - /* Send SIGIO signal to client process: */ - if(pClient->sig_flags & R3964_USE_SIGIO) - { - kill_pid(pClient->pid, SIGIO, 1); - } + pMsg = kmalloc(sizeof(struct r3964_message), + error_code ? GFP_ATOMIC : GFP_KERNEL); + TRACE_M("add_msg - kmalloc %p", pMsg); + if (pMsg == NULL) { + return; + } + + spin_lock_irqsave(&pClient->lock, flags); + + pMsg->msg_id = msg_id; + pMsg->arg = arg; + pMsg->error_code = error_code; + pMsg->block = pBlock; + pMsg->next = NULL; + + if (pClient->last_msg == NULL) { + pClient->first_msg = pClient->last_msg = pMsg; + } else { + pClient->last_msg->next = pMsg; + pClient->last_msg = pMsg; + } + + pClient->msg_count++; + + if (pBlock != NULL) { + pBlock->locks++; + } + spin_unlock_irqrestore(&pClient->lock, flags); + } else { + if ((pClient->last_msg->msg_id == R3964_MSG_ACK) + && (pClient->last_msg->error_code == R3964_OVERFLOW)) { + pClient->last_msg->arg++; + TRACE_PE("add_msg - inc prev OVERFLOW-msg"); + } else { + msg_id = R3964_MSG_ACK; + arg = 0; + error_code = R3964_OVERFLOW; + pBlock = NULL; + TRACE_PE("add_msg - queue OVERFLOW-msg"); + goto queue_the_message; + } + } + /* Send SIGIO signal to client process: */ + if (pClient->sig_flags & R3964_USE_SIGIO) { + kill_pid(pClient->pid, SIGIO, 1); + } } static struct r3964_message *remove_msg(struct r3964_info *pInfo, - struct r3964_client_info *pClient) + struct r3964_client_info *pClient) { - struct r3964_message *pMsg=NULL; - unsigned long flags; - - if(pClient->first_msg) - { - spin_lock_irqsave(&pClient->lock, flags); - - pMsg = pClient->first_msg; - pClient->first_msg = pMsg->next; - if(pClient->first_msg==NULL) - { - pClient->last_msg = NULL; - } - - pClient->msg_count--; - if(pMsg->block) - { - remove_client_block(pInfo, pClient); - pClient->next_block_to_read = pMsg->block; - } - spin_unlock_irqrestore(&pClient->lock, flags); - } - return pMsg; + struct r3964_message *pMsg = NULL; + unsigned long flags; + + if (pClient->first_msg) { + spin_lock_irqsave(&pClient->lock, flags); + + pMsg = pClient->first_msg; + pClient->first_msg = pMsg->next; + if (pClient->first_msg == NULL) { + pClient->last_msg = NULL; + } + + pClient->msg_count--; + if (pMsg->block) { + remove_client_block(pInfo, pClient); + pClient->next_block_to_read = pMsg->block; + } + spin_unlock_irqrestore(&pClient->lock, flags); + } + return pMsg; } -static void remove_client_block(struct r3964_info *pInfo, - struct r3964_client_info *pClient) +static void remove_client_block(struct r3964_info *pInfo, + struct r3964_client_info *pClient) { - struct r3964_block_header *block; - - TRACE_PS("remove_client_block PID %d", pid_nr(pClient->pid)); - - block=pClient->next_block_to_read; - if(block) - { - block->locks--; - if(block->locks==0) - { - remove_from_rx_queue(pInfo, block); - } - } - pClient->next_block_to_read = NULL; -} + struct r3964_block_header *block; + + TRACE_PS("remove_client_block PID %d", pid_nr(pClient->pid)); + block = pClient->next_block_to_read; + if (block) { + block->locks--; + if (block->locks == 0) { + remove_from_rx_queue(pInfo, block); + } + } + pClient->next_block_to_read = NULL; +} /************************************************************* * Line discipline routines @@ -1064,342 +951,318 @@ static void remove_client_block(struct r static int r3964_open(struct tty_struct *tty) { - struct r3964_info *pInfo; - - TRACE_L("open"); - TRACE_L("tty=%p, PID=%d, disc_data=%p", - tty, current->pid, tty->disc_data); - - pInfo=kmalloc(sizeof(struct r3964_info), GFP_KERNEL); - TRACE_M("r3964_open - info kmalloc %p",pInfo); - - if(!pInfo) - { - printk(KERN_ERR "r3964: failed to alloc info structure\n"); - return -ENOMEM; - } - - pInfo->rx_buf = kmalloc(RX_BUF_SIZE, GFP_KERNEL); - TRACE_M("r3964_open - rx_buf kmalloc %p",pInfo->rx_buf); - - if(!pInfo->rx_buf) - { - printk(KERN_ERR "r3964: failed to alloc receive buffer\n"); - kfree(pInfo); - TRACE_M("r3964_open - info kfree %p",pInfo); - return -ENOMEM; - } - - pInfo->tx_buf = kmalloc(TX_BUF_SIZE, GFP_KERNEL); - TRACE_M("r3964_open - tx_buf kmalloc %p",pInfo->tx_buf); - - if(!pInfo->tx_buf) - { - printk(KERN_ERR "r3964: failed to alloc transmit buffer\n"); - kfree(pInfo->rx_buf); - TRACE_M("r3964_open - rx_buf kfree %p",pInfo->rx_buf); - kfree(pInfo); - TRACE_M("r3964_open - info kfree %p",pInfo); - return -ENOMEM; - } - - spin_lock_init(&pInfo->lock); - pInfo->tty = tty; - init_waitqueue_head (&pInfo->read_wait); - pInfo->priority = R3964_MASTER; - pInfo->rx_first = pInfo->rx_last = NULL; - pInfo->tx_first = pInfo->tx_last = NULL; - pInfo->rx_position = 0; - pInfo->tx_position = 0; - pInfo->last_rx = 0; - pInfo->blocks_in_rx_queue = 0; - pInfo->firstClient=NULL; - pInfo->state=R3964_IDLE; - pInfo->flags = R3964_DEBUG; - pInfo->nRetry = 0; - - tty->disc_data = pInfo; - tty->receive_room = 65536; - - init_timer(&pInfo->tmr); - pInfo->tmr.data = (unsigned long)pInfo; - pInfo->tmr.function = on_timeout; - - return 0; + struct r3964_info *pInfo; + + TRACE_L("open"); + TRACE_L("tty=%p, PID=%d, disc_data=%p", + tty, current->pid, tty->disc_data); + + pInfo = kmalloc(sizeof(struct r3964_info), GFP_KERNEL); + TRACE_M("r3964_open - info kmalloc %p", pInfo); + + if (!pInfo) { + printk(KERN_ERR "r3964: failed to alloc info structure\n"); + return -ENOMEM; + } + + pInfo->rx_buf = kmalloc(RX_BUF_SIZE, GFP_KERNEL); + TRACE_M("r3964_open - rx_buf kmalloc %p", pInfo->rx_buf); + + if (!pInfo->rx_buf) { + printk(KERN_ERR "r3964: failed to alloc receive buffer\n"); + kfree(pInfo); + TRACE_M("r3964_open - info kfree %p", pInfo); + return -ENOMEM; + } + + pInfo->tx_buf = kmalloc(TX_BUF_SIZE, GFP_KERNEL); + TRACE_M("r3964_open - tx_buf kmalloc %p", pInfo->tx_buf); + + if (!pInfo->tx_buf) { + printk(KERN_ERR "r3964: failed to alloc transmit buffer\n"); + kfree(pInfo->rx_buf); + TRACE_M("r3964_open - rx_buf kfree %p", pInfo->rx_buf); + kfree(pInfo); + TRACE_M("r3964_open - info kfree %p", pInfo); + return -ENOMEM; + } + + spin_lock_init(&pInfo->lock); + pInfo->tty = tty; + init_waitqueue_head(&pInfo->read_wait); + pInfo->priority = R3964_MASTER; + pInfo->rx_first = pInfo->rx_last = NULL; + pInfo->tx_first = pInfo->tx_last = NULL; + pInfo->rx_position = 0; + pInfo->tx_position = 0; + pInfo->last_rx = 0; + pInfo->blocks_in_rx_queue = 0; + pInfo->firstClient = NULL; + pInfo->state = R3964_IDLE; + pInfo->flags = R3964_DEBUG; + pInfo->nRetry = 0; + + tty->disc_data = pInfo; + tty->receive_room = 65536; + + setup_timer(&pInfo->tmr, on_timeout, (unsigned long)pInfo); + + return 0; } static void r3964_close(struct tty_struct *tty) { - struct r3964_info *pInfo=(struct r3964_info*)tty->disc_data; - struct r3964_client_info *pClient, *pNext; - struct r3964_message *pMsg; - struct r3964_block_header *pHeader, *pNextHeader; - unsigned long flags; - - TRACE_L("close"); - - /* - * Make sure that our task queue isn't activated. If it - * is, take it out of the linked list. - */ - del_timer_sync(&pInfo->tmr); - - /* Remove client-structs and message queues: */ - pClient=pInfo->firstClient; - while(pClient) - { - pNext=pClient->next; - while(pClient->msg_count) - { - pMsg=remove_msg(pInfo, pClient); - if(pMsg) - { - kfree(pMsg); - TRACE_M("r3964_close - msg kfree %p",pMsg); - } - } - put_pid(pClient->pid); - kfree(pClient); - TRACE_M("r3964_close - client kfree %p",pClient); - pClient=pNext; - } - /* Remove jobs from tx_queue: */ - spin_lock_irqsave(&pInfo->lock, flags); - pHeader=pInfo->tx_first; - pInfo->tx_first=pInfo->tx_last=NULL; + struct r3964_info *pInfo = (struct r3964_info *)tty->disc_data; + struct r3964_client_info *pClient, *pNext; + struct r3964_message *pMsg; + struct r3964_block_header *pHeader, *pNextHeader; + unsigned long flags; + + TRACE_L("close"); + + /* + * Make sure that our task queue isn't activated. If it + * is, take it out of the linked list. + */ + del_timer_sync(&pInfo->tmr); + + /* Remove client-structs and message queues: */ + pClient = pInfo->firstClient; + while (pClient) { + pNext = pClient->next; + while (pClient->msg_count) { + pMsg = remove_msg(pInfo, pClient); + if (pMsg) { + kfree(pMsg); + TRACE_M("r3964_close - msg kfree %p", pMsg); + } + } + put_pid(pClient->pid); + kfree(pClient); + TRACE_M("r3964_close - client kfree %p", pClient); + pClient = pNext; + } + /* Remove jobs from tx_queue: */ + spin_lock_irqsave(&pInfo->lock, flags); + pHeader = pInfo->tx_first; + pInfo->tx_first = pInfo->tx_last = NULL; spin_unlock_irqrestore(&pInfo->lock, flags); - - while(pHeader) - { - pNextHeader=pHeader->next; - kfree(pHeader); - pHeader=pNextHeader; + + while (pHeader) { + pNextHeader = pHeader->next; + kfree(pHeader); + pHeader = pNextHeader; } - /* Free buffers: */ - wake_up_interruptible(&pInfo->read_wait); - kfree(pInfo->rx_buf); - TRACE_M("r3964_close - rx_buf kfree %p",pInfo->rx_buf); - kfree(pInfo->tx_buf); - TRACE_M("r3964_close - tx_buf kfree %p",pInfo->tx_buf); - kfree(pInfo); - TRACE_M("r3964_close - info kfree %p",pInfo); + /* Free buffers: */ + wake_up_interruptible(&pInfo->read_wait); + kfree(pInfo->rx_buf); + TRACE_M("r3964_close - rx_buf kfree %p", pInfo->rx_buf); + kfree(pInfo->tx_buf); + TRACE_M("r3964_close - tx_buf kfree %p", pInfo->tx_buf); + kfree(pInfo); + TRACE_M("r3964_close - info kfree %p", pInfo); } static ssize_t r3964_read(struct tty_struct *tty, struct file *file, - unsigned char __user *buf, size_t nr) + unsigned char __user * buf, size_t nr) { - struct r3964_info *pInfo=(struct r3964_info*)tty->disc_data; - struct r3964_client_info *pClient; - struct r3964_message *pMsg; - struct r3964_client_message theMsg; - DECLARE_WAITQUEUE (wait, current); - - int count; - - TRACE_L("read()"); - - pClient=findClient(pInfo, task_pid(current)); - if(pClient) - { - pMsg = remove_msg(pInfo, pClient); - if(pMsg==NULL) - { - /* no messages available. */ - if (file->f_flags & O_NONBLOCK) - { - return -EAGAIN; - } - /* block until there is a message: */ - add_wait_queue(&pInfo->read_wait, &wait); + struct r3964_info *pInfo = (struct r3964_info *)tty->disc_data; + struct r3964_client_info *pClient; + struct r3964_message *pMsg; + struct r3964_client_message theMsg; + DECLARE_WAITQUEUE(wait, current); + + int count; + + TRACE_L("read()"); + + pClient = findClient(pInfo, task_pid(current)); + if (pClient) { + pMsg = remove_msg(pInfo, pClient); + if (pMsg == NULL) { + /* no messages available. */ + if (file->f_flags & O_NONBLOCK) { + return -EAGAIN; + } + /* block until there is a message: */ + add_wait_queue(&pInfo->read_wait, &wait); repeat: - current->state = TASK_INTERRUPTIBLE; - pMsg = remove_msg(pInfo, pClient); - if (!pMsg && !signal_pending(current)) - { - schedule(); - goto repeat; - } - current->state = TASK_RUNNING; - remove_wait_queue(&pInfo->read_wait, &wait); - } - - /* If we still haven't got a message, we must have been signalled */ - - if (!pMsg) return -EINTR; - - /* deliver msg to client process: */ - theMsg.msg_id = pMsg->msg_id; - theMsg.arg = pMsg->arg; - theMsg.error_code = pMsg->error_code; - count = sizeof(struct r3964_client_message); - - kfree(pMsg); - TRACE_M("r3964_read - msg kfree %p",pMsg); - - if (copy_to_user(buf,&theMsg, count)) - return -EFAULT; - - TRACE_PS("read - return %d", count); - return count; - } - return -EPERM; + current->state = TASK_INTERRUPTIBLE; + pMsg = remove_msg(pInfo, pClient); + if (!pMsg && !signal_pending(current)) { + schedule(); + goto repeat; + } + current->state = TASK_RUNNING; + remove_wait_queue(&pInfo->read_wait, &wait); + } + + /* If we still haven't got a message, we must have been signalled */ + + if (!pMsg) + return -EINTR; + + /* deliver msg to client process: */ + theMsg.msg_id = pMsg->msg_id; + theMsg.arg = pMsg->arg; + theMsg.error_code = pMsg->error_code; + count = sizeof(struct r3964_client_message); + + kfree(pMsg); + TRACE_M("r3964_read - msg kfree %p", pMsg); + + if (copy_to_user(buf, &theMsg, count)) + return -EFAULT; + + TRACE_PS("read - return %d", count); + return count; + } + return -EPERM; } -static ssize_t r3964_write(struct tty_struct * tty, struct file * file, +static ssize_t r3964_write(struct tty_struct *tty, struct file *file, const unsigned char *data, size_t count) { - struct r3964_info *pInfo=(struct r3964_info*)tty->disc_data; - struct r3964_block_header *pHeader; - struct r3964_client_info *pClient; - unsigned char *new_data; - - TRACE_L("write request, %d characters", count); + struct r3964_info *pInfo = (struct r3964_info *)tty->disc_data; + struct r3964_block_header *pHeader; + struct r3964_client_info *pClient; + unsigned char *new_data; + + TRACE_L("write request, %d characters", count); /* * Verify the pointers */ - if(!pInfo) - return -EIO; + if (!pInfo) + return -EIO; /* * Ensure that the caller does not wish to send too much. */ - if (count > R3964_MTU) - { - if (pInfo->flags & R3964_DEBUG) - { - TRACE_L (KERN_WARNING - "r3964_write: truncating user packet " - "from %u to mtu %d", count, R3964_MTU); - } - count = R3964_MTU; - } + if (count > R3964_MTU) { + if (pInfo->flags & R3964_DEBUG) { + TRACE_L(KERN_WARNING "r3964_write: truncating user " + "packet from %u to mtu %d", count, R3964_MTU); + } + count = R3964_MTU; + } /* * Allocate a buffer for the data and copy it from the buffer with header prepended */ - new_data = kmalloc (count+sizeof(struct r3964_block_header), GFP_KERNEL); - TRACE_M("r3964_write - kmalloc %p",new_data); - if (new_data == NULL) { - if (pInfo->flags & R3964_DEBUG) - { - printk (KERN_ERR - "r3964_write: no memory\n"); - } - return -ENOSPC; - } - - pHeader = (struct r3964_block_header *)new_data; - pHeader->data = new_data + sizeof(struct r3964_block_header); - pHeader->length = count; - pHeader->locks = 0; - pHeader->owner = NULL; - - pClient=findClient(pInfo, task_pid(current)); - if(pClient) - { - pHeader->owner = pClient; - } - - memcpy(pHeader->data, data, count); /* We already verified this */ - - if(pInfo->flags & R3964_DEBUG) - { - dump_block(pHeader->data, count); - } + new_data = kmalloc(count + sizeof(struct r3964_block_header), + GFP_KERNEL); + TRACE_M("r3964_write - kmalloc %p", new_data); + if (new_data == NULL) { + if (pInfo->flags & R3964_DEBUG) { + printk(KERN_ERR "r3964_write: no memory\n"); + } + return -ENOSPC; + } + + pHeader = (struct r3964_block_header *)new_data; + pHeader->data = new_data + sizeof(struct r3964_block_header); + pHeader->length = count; + pHeader->locks = 0; + pHeader->owner = NULL; + + pClient = findClient(pInfo, task_pid(current)); + if (pClient) { + pHeader->owner = pClient; + } + + memcpy(pHeader->data, data, count); /* We already verified this */ + + if (pInfo->flags & R3964_DEBUG) { + dump_block(pHeader->data, count); + } /* * Add buffer to transmit-queue: */ - add_tx_queue(pInfo, pHeader); - trigger_transmit(pInfo); - - return 0; + add_tx_queue(pInfo, pHeader); + trigger_transmit(pInfo); + + return 0; } -static int r3964_ioctl(struct tty_struct * tty, struct file * file, - unsigned int cmd, unsigned long arg) +static int r3964_ioctl(struct tty_struct *tty, struct file *file, + unsigned int cmd, unsigned long arg) { - struct r3964_info *pInfo=(struct r3964_info*)tty->disc_data; - if(pInfo==NULL) - return -EINVAL; - switch(cmd) - { - case R3964_ENABLE_SIGNALS: - return enable_signals(pInfo, task_pid(current), arg); - case R3964_SETPRIORITY: - if(argR3964_SLAVE) - return -EINVAL; - pInfo->priority = arg & 0xff; - return 0; - case R3964_USE_BCC: - if(arg) - pInfo->flags |= R3964_BCC; - else - pInfo->flags &= ~R3964_BCC; - return 0; - case R3964_READ_TELEGRAM: - return read_telegram(pInfo, task_pid(current), (unsigned char __user *)arg); - default: - return -ENOIOCTLCMD; - } + struct r3964_info *pInfo = (struct r3964_info *)tty->disc_data; + if (pInfo == NULL) + return -EINVAL; + switch (cmd) { + case R3964_ENABLE_SIGNALS: + return enable_signals(pInfo, task_pid(current), arg); + case R3964_SETPRIORITY: + if (arg < R3964_MASTER || arg > R3964_SLAVE) + return -EINVAL; + pInfo->priority = arg & 0xff; + return 0; + case R3964_USE_BCC: + if (arg) + pInfo->flags |= R3964_BCC; + else + pInfo->flags &= ~R3964_BCC; + return 0; + case R3964_READ_TELEGRAM: + return read_telegram(pInfo, task_pid(current), + (unsigned char __user *)arg); + default: + return -ENOIOCTLCMD; + } } -static void r3964_set_termios(struct tty_struct *tty, struct ktermios * old) +static void r3964_set_termios(struct tty_struct *tty, struct ktermios *old) { - TRACE_L("set_termios"); + TRACE_L("set_termios"); } /* Called without the kernel lock held - fine */ -static unsigned int r3964_poll(struct tty_struct * tty, struct file * file, - struct poll_table_struct *wait) +static unsigned int r3964_poll(struct tty_struct *tty, struct file *file, + struct poll_table_struct *wait) { - struct r3964_info *pInfo=(struct r3964_info*)tty->disc_data; - struct r3964_client_info *pClient; - struct r3964_message *pMsg=NULL; - unsigned long flags; - int result = POLLOUT; - - TRACE_L("POLL"); - - pClient=findClient(pInfo, task_pid(current)); - if(pClient) - { - poll_wait(file, &pInfo->read_wait, wait); - spin_lock_irqsave(&pInfo->lock, flags); - pMsg=pClient->first_msg; - spin_unlock_irqrestore(&pInfo->lock, flags); - if(pMsg) - result |= POLLIN | POLLRDNORM; - } - else - { - result = -EINVAL; - } - return result; + struct r3964_info *pInfo = (struct r3964_info *)tty->disc_data; + struct r3964_client_info *pClient; + struct r3964_message *pMsg = NULL; + unsigned long flags; + int result = POLLOUT; + + TRACE_L("POLL"); + + pClient = findClient(pInfo, task_pid(current)); + if (pClient) { + poll_wait(file, &pInfo->read_wait, wait); + spin_lock_irqsave(&pInfo->lock, flags); + pMsg = pClient->first_msg; + spin_unlock_irqrestore(&pInfo->lock, flags); + if (pMsg) + result |= POLLIN | POLLRDNORM; + } else { + result = -EINVAL; + } + return result; } static void r3964_receive_buf(struct tty_struct *tty, const unsigned char *cp, - char *fp, int count) + char *fp, int count) { - struct r3964_info *pInfo=(struct r3964_info*)tty->disc_data; - const unsigned char *p; - char *f, flags = 0; - int i; - - for (i=count, p = cp, f = fp; i; i--, p++) { - if (f) - flags = *f++; - if(flags==TTY_NORMAL) - { - receive_char(pInfo, *p); - } - else - { - receive_error(pInfo, flags); - } - - } + struct r3964_info *pInfo = (struct r3964_info *)tty->disc_data; + const unsigned char *p; + char *f, flags = 0; + int i; + + for (i = count, p = cp, f = fp; i; i--, p++) { + if (f) + flags = *f++; + if (flags == TTY_NORMAL) { + receive_char(pInfo, *p); + } else { + receive_error(pInfo, flags); + } + + } } MODULE_LICENSE("GPL"); diff --git a/drivers/char/n_tty.c b/drivers/char/n_tty.c index 2bdb014..6ac3ca4 100644 --- a/drivers/char/n_tty.c +++ b/drivers/char/n_tty.c @@ -579,8 +579,8 @@ static void eraser(unsigned char c, stru static inline void isig(int sig, struct tty_struct *tty, int flush) { - if (tty->pgrp > 0) - kill_pg(tty->pgrp, sig, 1); + if (tty->pgrp) + kill_pgrp(tty->pgrp, sig, 1); if (flush || !L_NOFLSH(tty)) { n_tty_flush_buffer(tty); if (tty->driver->flush_buffer) @@ -1184,13 +1184,13 @@ static int job_control(struct tty_struct /* don't stop on /dev/console */ if (file->f_op->write != redirected_tty_write && current->signal->tty == tty) { - if (tty->pgrp <= 0) - printk("read_chan: tty->pgrp <= 0!\n"); - else if (process_group(current) != tty->pgrp) { + if (!tty->pgrp) + printk("read_chan: no tty->pgrp!\n"); + else if (task_pgrp(current) != tty->pgrp) { if (is_ignored(SIGTTIN) || - is_orphaned_pgrp(process_group(current))) + is_current_pgrp_orphaned()) return -EIO; - kill_pg(process_group(current), SIGTTIN, 1); + kill_pgrp(task_pgrp(current), SIGTTIN, 1); return -ERESTARTSYS; } } diff --git a/drivers/char/nvram.c b/drivers/char/nvram.c index a39f19c..204deaa 100644 --- a/drivers/char/nvram.c +++ b/drivers/char/nvram.c @@ -37,7 +37,6 @@ #define NVRAM_VERSION "1.2" #include -#include #include #include diff --git a/drivers/char/nwbutton.c b/drivers/char/nwbutton.c index 2d26497..2604246 100644 --- a/drivers/char/nwbutton.c +++ b/drivers/char/nwbutton.c @@ -23,8 +23,11 @@ #include #define __NWBUTTON_C /* Tell the header file who we are */ #include "nwbutton.h" +static void button_sequence_finished (unsigned long parameters); + static int button_press_count; /* The count of button presses */ -static struct timer_list button_timer; /* Times for the end of a sequence */ +/* Times for the end of a sequence */ +static DEFINE_TIMER(button_timer, button_sequence_finished, 0, 0); static DECLARE_WAIT_QUEUE_HEAD(button_wait_queue); /* Used for blocking read */ static char button_output_buffer[32]; /* Stores data to write out of device */ static int bcount; /* The number of bytes in the buffer */ @@ -146,14 +149,8 @@ #endif /* CONFIG_NWBUTTON_REBOOT */ static irqreturn_t button_handler (int irq, void *dev_id) { - if (button_press_count) { - del_timer (&button_timer); - } button_press_count++; - init_timer (&button_timer); - button_timer.function = button_sequence_finished; - button_timer.expires = (jiffies + bdelay); - add_timer (&button_timer); + mod_timer(&button_timer, jiffies + bdelay); return IRQ_HANDLED; } diff --git a/drivers/char/nwflash.c b/drivers/char/nwflash.c index 206cf6f..ba012c2 100644 --- a/drivers/char/nwflash.c +++ b/drivers/char/nwflash.c @@ -21,7 +21,6 @@ #include #include #include #include -#include #include #include #include diff --git a/drivers/char/pcmcia/cm4000_cs.c b/drivers/char/pcmcia/cm4000_cs.c index 211c93f..e91b43a 100644 --- a/drivers/char/pcmcia/cm4000_cs.c +++ b/drivers/char/pcmcia/cm4000_cs.c @@ -946,8 +946,7 @@ release_io: return_with_timer: DEBUGP(7, dev, "<- monitor_card (returns with timer)\n"); - dev->timer.expires = jiffies + dev->mdelay; - add_timer(&dev->timer); + mod_timer(&dev->timer, jiffies + dev->mdelay); clear_bit(LOCK_MONITOR, &dev->flags); } @@ -1406,12 +1405,9 @@ static void start_monitor(struct cm4000_ DEBUGP(3, dev, "-> start_monitor\n"); if (!dev->monitor_running) { DEBUGP(5, dev, "create, init and add timer\n"); - init_timer(&dev->timer); + setup_timer(&dev->timer, monitor_card, (unsigned long)dev); dev->monitor_running = 1; - dev->timer.expires = jiffies; - dev->timer.data = (unsigned long) dev; - dev->timer.function = monitor_card; - add_timer(&dev->timer); + mod_timer(&dev->timer, jiffies); } else DEBUGP(5, dev, "monitor already running\n"); DEBUGP(3, dev, "<- start_monitor\n"); diff --git a/drivers/char/pcmcia/cm4040_cs.c b/drivers/char/pcmcia/cm4040_cs.c index 9b1ff7e..0e82968 100644 --- a/drivers/char/pcmcia/cm4040_cs.c +++ b/drivers/char/pcmcia/cm4040_cs.c @@ -632,8 +632,7 @@ static int reader_probe(struct pcmcia_de init_waitqueue_head(&dev->poll_wait); init_waitqueue_head(&dev->read_wait); init_waitqueue_head(&dev->write_wait); - init_timer(&dev->poll_timer); - dev->poll_timer.function = &cm4040_do_poll; + setup_timer(&dev->poll_timer, cm4040_do_poll, 0); ret = reader_config(link, i); if (ret) diff --git a/drivers/char/pcmcia/synclink_cs.c b/drivers/char/pcmcia/synclink_cs.c index f108c13..8d025e9 100644 --- a/drivers/char/pcmcia/synclink_cs.c +++ b/drivers/char/pcmcia/synclink_cs.c @@ -887,10 +887,8 @@ static void bh_transmit(MGSLPC_INFO *inf if (debug_level >= DEBUG_LEVEL_BH) printk("bh_transmit() entry on %s\n", info->device_name); - if (tty) { + if (tty) tty_wakeup(tty); - wake_up_interruptible(&tty->write_wait); - } } static void bh_status(MGSLPC_INFO *info) @@ -1363,9 +1361,7 @@ static int startup(MGSLPC_INFO * info) memset(&info->icount, 0, sizeof(info->icount)); - init_timer(&info->tx_timer); - info->tx_timer.data = (unsigned long)info; - info->tx_timer.function = tx_timeout; + setup_timer(&info->tx_timer, tx_timeout, (unsigned long)info); /* Allocate and claim adapter resources */ retval = claim_resources(info); @@ -1410,7 +1406,7 @@ static void shutdown(MGSLPC_INFO * info) wake_up_interruptible(&info->status_event_wait_q); wake_up_interruptible(&info->event_wait_q); - del_timer(&info->tx_timer); + del_timer_sync(&info->tx_timer); if (info->tx_buf) { free_page((unsigned long) info->tx_buf); @@ -3551,8 +3547,8 @@ static void tx_start(MGSLPC_INFO *info) } else { info->tx_active = 1; tx_ready(info); - info->tx_timer.expires = jiffies + msecs_to_jiffies(5000); - add_timer(&info->tx_timer); + mod_timer(&info->tx_timer, jiffies + + msecs_to_jiffies(5000)); } } diff --git a/drivers/char/pty.c b/drivers/char/pty.c index c07a1b5..de14aea 100644 --- a/drivers/char/pty.c +++ b/drivers/char/pty.c @@ -14,7 +14,6 @@ #include /* For EXPORT_SYMBOL */ #include -#include #include #include #include diff --git a/drivers/char/random.c b/drivers/char/random.c index 13d0b13..b9dc7aa 100644 --- a/drivers/char/random.c +++ b/drivers/char/random.c @@ -1117,14 +1117,14 @@ random_ioctl(struct inode * inode, struc } } -struct file_operations random_fops = { +const struct file_operations random_fops = { .read = random_read, .write = random_write, .poll = random_poll, .ioctl = random_ioctl, }; -struct file_operations urandom_fops = { +const struct file_operations urandom_fops = { .read = urandom_read, .write = random_write, .ioctl = random_ioctl, diff --git a/drivers/char/raw.c b/drivers/char/raw.c index 645e20a..1f0d7c6 100644 --- a/drivers/char/raw.c +++ b/drivers/char/raw.c @@ -154,7 +154,7 @@ static int raw_ctl_ioctl(struct inode *i goto out; } - if (rq.raw_minor < 0 || rq.raw_minor >= MAX_RAW_MINORS) { + if (rq.raw_minor <= 0 || rq.raw_minor >= MAX_RAW_MINORS) { err = -EINVAL; goto out; } diff --git a/drivers/char/rio/rio_linux.c b/drivers/char/rio/rio_linux.c index e79b2ed..85c1618 100644 --- a/drivers/char/rio/rio_linux.c +++ b/drivers/char/rio/rio_linux.c @@ -418,8 +418,7 @@ static void rio_pollfunc(unsigned long d func_enter(); rio_interrupt(0, &p->RIOHosts[data]); - p->RIOHosts[data].timer.expires = jiffies + rio_poll; - add_timer(&p->RIOHosts[data].timer); + mod_timer(&p->RIOHosts[data].timer, jiffies + rio_poll); func_exit(); } @@ -1154,13 +1153,10 @@ #endif /* PCI */ /* Init the timer "always" to make sure that it can safely be deleted when we unload... */ - init_timer(&hp->timer); + setup_timer(&hp->timer, rio_pollfunc, i); if (!hp->Ivec) { rio_dprintk(RIO_DEBUG_INIT, "Starting polling at %dj intervals.\n", rio_poll); - hp->timer.data = i; - hp->timer.function = rio_pollfunc; - hp->timer.expires = jiffies + rio_poll; - add_timer(&hp->timer); + mod_timer(&hp->timer, jiffies + rio_poll); } } @@ -1191,7 +1187,7 @@ static void __exit rio_exit(void) rio_dprintk(RIO_DEBUG_INIT, "freed irq %d.\n", hp->Ivec); } /* It is safe/allowed to del_timer a non-active timer */ - del_timer(&hp->timer); + del_timer_sync(&hp->timer); if (hp->Caddr) iounmap(hp->Caddr); if (hp->Type == RIO_PCI) diff --git a/drivers/char/rio/riointr.c b/drivers/char/rio/riointr.c index eeda40c..ebc7634 100644 --- a/drivers/char/rio/riointr.c +++ b/drivers/char/rio/riointr.c @@ -162,13 +162,8 @@ void RIOTxEnable(char *en) rio_spin_unlock_irqrestore(&PortP->portSem, flags); - if (PortP->gs.xmit_cnt <= (PortP->gs.wakeup_chars + 2 * PKT_MAX_DATA_LEN)) { - rio_dprintk(RIO_DEBUG_INTR, "Waking up.... ldisc:%d (%d/%d)....", (int) (PortP->gs.tty->flags & (1 << TTY_DO_WRITE_WAKEUP)), PortP->gs.wakeup_chars, PortP->gs.xmit_cnt); - if ((PortP->gs.tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && PortP->gs.tty->ldisc.write_wakeup) - (PortP->gs.tty->ldisc.write_wakeup) (PortP->gs.tty); - rio_dprintk(RIO_DEBUG_INTR, "(%d/%d)\n", PortP->gs.wakeup_chars, PortP->gs.xmit_cnt); - wake_up_interruptible(&PortP->gs.tty->write_wait); - } + if (PortP->gs.xmit_cnt <= (PortP->gs.wakeup_chars + 2 * PKT_MAX_DATA_LEN)) + tty_wakeup(PortP->gs.tty); } diff --git a/drivers/char/riscom8.c b/drivers/char/riscom8.c index e2a94bf..7014525 100644 --- a/drivers/char/riscom8.c +++ b/drivers/char/riscom8.c @@ -1229,7 +1229,6 @@ static void rc_flush_buffer(struct tty_s port->xmit_cnt = port->xmit_head = port->xmit_tail = 0; restore_flags(flags); - wake_up_interruptible(&tty->write_wait); tty_wakeup(tty); } @@ -1570,10 +1569,8 @@ static void do_softint(struct work_struc if(!(tty = port->tty)) return; - if (test_and_clear_bit(RS_EVENT_WRITE_WAKEUP, &port->event)) { + if (test_and_clear_bit(RS_EVENT_WRITE_WAKEUP, &port->event)) tty_wakeup(tty); - wake_up_interruptible(&tty->write_wait); - } } static const struct tty_operations riscom_ops = { diff --git a/drivers/char/rocket.c b/drivers/char/rocket.c index e94a62e..76357c8 100644 --- a/drivers/char/rocket.c +++ b/drivers/char/rocket.c @@ -106,6 +106,8 @@ #define ROCKET_DATE "12-June-2003" /****** RocketPort Local Variables ******/ +static void rp_do_poll(unsigned long dummy); + static struct tty_driver *rocket_driver; static struct rocket_version driver_version = { @@ -116,7 +118,7 @@ static struct r_port *rp_table[MAX_RP_PO static unsigned int xmit_flags[NUM_BOARDS]; /* Bit significant, indicates port had data to transmit. */ /* eg. Bit 0 indicates port 0 has xmit data, ... */ static atomic_t rp_num_ports_open; /* Number of serial ports open */ -static struct timer_list rocket_timer; +static DEFINE_TIMER(rocket_timer, rp_do_poll, 0, 0); static unsigned long board1; /* ISA addresses, retrieved from rocketport.conf */ static unsigned long board2; @@ -474,7 +476,6 @@ #endif if (info->xmit_cnt < WAKEUP_CHARS) { tty_wakeup(tty); - wake_up_interruptible(&tty->write_wait); #ifdef ROCKETPORT_HAVE_POLL_WAIT wake_up_interruptible(&tty->poll_wait); #endif @@ -1772,7 +1773,6 @@ #endif end: if (info->xmit_cnt < WAKEUP_CHARS) { tty_wakeup(tty); - wake_up_interruptible(&tty->write_wait); #ifdef ROCKETPORT_HAVE_POLL_WAIT wake_up_interruptible(&tty->poll_wait); #endif @@ -1841,7 +1841,6 @@ static void rp_flush_buffer(struct tty_s info->xmit_cnt = info->xmit_head = info->xmit_tail = 0; spin_unlock_irqrestore(&info->slock, flags); - wake_up_interruptible(&tty->write_wait); #ifdef ROCKETPORT_HAVE_POLL_WAIT wake_up_interruptible(&tty->poll_wait); #endif @@ -2371,12 +2370,6 @@ static int __init rp_init(void) return -ENOMEM; /* - * Set up the timer channel. - */ - init_timer(&rocket_timer); - rocket_timer.function = rp_do_poll; - - /* * Initialize the array of pointers to our own internal state * structures. */ diff --git a/drivers/char/rtc.c b/drivers/char/rtc.c index 664f36c..c7dac9b 100644 --- a/drivers/char/rtc.c +++ b/drivers/char/rtc.c @@ -135,7 +135,9 @@ static struct fasync_struct *rtc_async_q static DECLARE_WAIT_QUEUE_HEAD(rtc_wait); #ifdef RTC_IRQ -static struct timer_list rtc_irq_timer; +static void rtc_dropped_irq(unsigned long data); + +static DEFINE_TIMER(rtc_irq_timer, rtc_dropped_irq, 0, 0); #endif static ssize_t rtc_read(struct file *file, char __user *buf, @@ -150,8 +152,6 @@ #endif static void get_rtc_alm_time (struct rtc_time *alm_tm); #ifdef RTC_IRQ -static void rtc_dropped_irq(unsigned long data); - static void set_rtc_irq_bit_locked(unsigned char bit); static void mask_rtc_irq_bit_locked(unsigned char bit); @@ -282,7 +282,7 @@ #endif */ static ctl_table rtc_table[] = { { - .ctl_name = 1, + .ctl_name = CTL_UNNUMBERED, .procname = "max-user-freq", .data = &rtc_max_user_freq, .maxlen = sizeof(int), @@ -294,9 +294,8 @@ static ctl_table rtc_table[] = { static ctl_table rtc_root[] = { { - .ctl_name = 1, + .ctl_name = CTL_UNNUMBERED, .procname = "rtc", - .maxlen = 0, .mode = 0555, .child = rtc_table, }, @@ -307,7 +306,6 @@ static ctl_table dev_root[] = { { .ctl_name = CTL_DEV, .procname = "dev", - .maxlen = 0, .mode = 0555, .child = rtc_root, }, @@ -318,7 +316,7 @@ static struct ctl_table_header *sysctl_h static int __init init_sysctl(void) { - sysctl_header = register_sysctl_table(dev_root, 0); + sysctl_header = register_sysctl_table(dev_root); return 0; } @@ -454,8 +452,8 @@ #ifdef RTC_IRQ spin_lock_irqsave (&rtc_lock, flags); if (!(rtc_status & RTC_TIMER_ON)) { - rtc_irq_timer.expires = jiffies + HZ/rtc_freq + 2*HZ/100; - add_timer(&rtc_irq_timer); + mod_timer(&rtc_irq_timer, jiffies + HZ/rtc_freq + + 2*HZ/100); rtc_status |= RTC_TIMER_ON; } set_rtc_irq_bit_locked(RTC_PIE); @@ -1084,8 +1082,6 @@ #ifdef RTC_IRQ if (rtc_has_irq == 0) goto no_irq2; - init_timer(&rtc_irq_timer); - rtc_irq_timer.function = rtc_dropped_irq; spin_lock_irq(&rtc_lock); rtc_freq = 1024; if (!hpet_set_periodic_freq(rtc_freq)) { diff --git a/drivers/char/scan_keyb.c b/drivers/char/scan_keyb.c deleted file mode 100644 index 2b5bb4f..0000000 --- a/drivers/char/scan_keyb.c +++ /dev/null @@ -1,149 +0,0 @@ -/* - * $Id: scan_keyb.c,v 1.2 2000/07/04 06:24:42 yaegashi Exp $ - * Copyright (C) 2000 YAEGASHI Takeshi - * Generic scan keyboard driver - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#define SCANHZ (HZ/20) - -struct scan_keyboard { - struct scan_keyboard *next; - int (*scan)(unsigned char *buffer); - const unsigned char *table; - unsigned char *s0, *s1; - int length; -}; - -static int scan_jiffies=0; -static struct scan_keyboard *keyboards=NULL; -struct timer_list scan_timer; - -static void check_kbd(const unsigned char *table, - unsigned char *new, unsigned char *old, int length) -{ - int need_tasklet_schedule=0; - unsigned int xor, bit; - - while(length-->0) { - if((xor=*new^*old)==0) { - table+=8; - } - else { - for(bit=0x01; bit<0x100; bit<<=1) { - if(xor&bit) { - handle_scancode(*table, !(*new&bit)); - need_tasklet_schedule=1; -#if 0 - printk("0x%x %s\n", *table, (*new&bit)?"released":"pressed"); -#endif - } - table++; - } - } - new++; old++; - } - - if(need_tasklet_schedule) - tasklet_schedule(&keyboard_tasklet); -} - - -static void scan_kbd(unsigned long dummy) -{ - struct scan_keyboard *kbd; - - scan_jiffies++; - - for(kbd=keyboards; kbd!=NULL; kbd=kbd->next) { - if(scan_jiffies&1) { - if(!kbd->scan(kbd->s0)) - check_kbd(kbd->table, - kbd->s0, kbd->s1, kbd->length); - else - memcpy(kbd->s0, kbd->s1, kbd->length); - } - else { - if(!kbd->scan(kbd->s1)) - check_kbd(kbd->table, - kbd->s1, kbd->s0, kbd->length); - else - memcpy(kbd->s1, kbd->s0, kbd->length); - } - - } - - init_timer(&scan_timer); - scan_timer.expires = jiffies + SCANHZ; - scan_timer.data = 0; - scan_timer.function = scan_kbd; - add_timer(&scan_timer); -} - - -int register_scan_keyboard(int (*scan)(unsigned char *buffer), - const unsigned char *table, - int length) -{ - struct scan_keyboard *kbd; - - kbd = kmalloc(sizeof(struct scan_keyboard), GFP_KERNEL); - if (kbd == NULL) - goto error_out; - - kbd->scan=scan; - kbd->table=table; - kbd->length=length; - - kbd->s0 = kmalloc(length, GFP_KERNEL); - if (kbd->s0 == NULL) - goto error_free_kbd; - - kbd->s1 = kmalloc(length, GFP_KERNEL); - if (kbd->s1 == NULL) - goto error_free_s0; - - memset(kbd->s0, -1, kbd->length); - memset(kbd->s1, -1, kbd->length); - - kbd->next=keyboards; - keyboards=kbd; - - return 0; - - error_free_s0: - kfree(kbd->s0); - - error_free_kbd: - kfree(kbd); - - error_out: - return -ENOMEM; -} - - -void __init scan_kbd_init(void) -{ - init_timer(&scan_timer); - scan_timer.expires = jiffies + SCANHZ; - scan_timer.data = 0; - scan_timer.function = scan_kbd; - add_timer(&scan_timer); - - printk(KERN_INFO "Generic scan keyboard driver initialized\n"); -} diff --git a/drivers/char/scan_keyb.h b/drivers/char/scan_keyb.h deleted file mode 100644 index b4b6112..0000000 --- a/drivers/char/scan_keyb.h +++ /dev/null @@ -1,15 +0,0 @@ -#ifndef __DRIVER_CHAR_SCAN_KEYB_H -#define __DRIVER_CHAR_SCAN_KEYB_H -/* - * $Id: scan_keyb.h,v 1.1 2000/06/10 21:45:30 yaegashi Exp $ - * Copyright (C) 2000 YAEGASHI Takeshi - * Generic scan keyboard driver - */ - -int register_scan_keyboard(int (*scan)(unsigned char *buffer), - const unsigned char *table, - int length); - -void __init scan_kbd_init(void); - -#endif diff --git a/drivers/char/ser_a2232.c b/drivers/char/ser_a2232.c index 75de5f6..3c86914 100644 --- a/drivers/char/ser_a2232.c +++ b/drivers/char/ser_a2232.c @@ -86,7 +86,6 @@ #define A2232_SUPPRESS_RTSCTS_WARNING #include #include -#include #include #include #include diff --git a/drivers/char/serial167.c b/drivers/char/serial167.c index af50d32..5fd314a 100644 --- a/drivers/char/serial167.c +++ b/drivers/char/serial167.c @@ -111,12 +111,13 @@ #define PccIMLR 0x3f /* This is the per-port data structure */ struct cyclades_port cy_port[] = { - /* CARD# */ - {-1 }, /* ttyS0 */ - {-1 }, /* ttyS1 */ - {-1 }, /* ttyS2 */ - {-1 }, /* ttyS3 */ + /* CARD# */ + {-1}, /* ttyS0 */ + {-1}, /* ttyS1 */ + {-1}, /* ttyS2 */ + {-1}, /* ttyS3 */ }; + #define NR_PORTS ARRAY_SIZE(cy_port) /* @@ -128,42 +129,46 @@ #define NR_PORTS ARRAY_SIZE(cy_po * HI VHI */ static int baud_table[] = { - 0, 50, 75, 110, 134, 150, 200, 300, 600, 1200, - 1800, 2400, 4800, 9600, 19200, 38400, 57600, 76800,115200,150000, - 0}; + 0, 50, 75, 110, 134, 150, 200, 300, 600, 1200, + 1800, 2400, 4800, 9600, 19200, 38400, 57600, 76800, 115200, 150000, + 0 +}; #if 0 -static char baud_co[] = { /* 25 MHz clock option table */ - /* value => 00 01 02 03 04 */ - /* divide by 8 32 128 512 2048 */ - 0x00, 0x04, 0x04, 0x04, 0x04, 0x04, 0x03, 0x03, 0x03, 0x02, - 0x02, 0x02, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; +static char baud_co[] = { /* 25 MHz clock option table */ + /* value => 00 01 02 03 04 */ + /* divide by 8 32 128 512 2048 */ + 0x00, 0x04, 0x04, 0x04, 0x04, 0x04, 0x03, 0x03, 0x03, 0x02, + 0x02, 0x02, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 +}; -static char baud_bpr[] = { /* 25 MHz baud rate period table */ - 0x00, 0xf5, 0xa3, 0x6f, 0x5c, 0x51, 0xf5, 0xa3, 0x51, 0xa3, - 0x6d, 0x51, 0xa3, 0x51, 0xa3, 0x51, 0x36, 0x29, 0x1b, 0x15}; +static char baud_bpr[] = { /* 25 MHz baud rate period table */ + 0x00, 0xf5, 0xa3, 0x6f, 0x5c, 0x51, 0xf5, 0xa3, 0x51, 0xa3, + 0x6d, 0x51, 0xa3, 0x51, 0xa3, 0x51, 0x36, 0x29, 0x1b, 0x15 +}; #endif /* I think 166 brd clocks 2401 at 20MHz.... */ /* These values are written directly to tcor, and >> 5 for writing to rcor */ -static u_char baud_co[] = { /* 20 MHz clock option table */ - 0x00, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x60, 0x60, 0x40, - 0x40, 0x40, 0x20, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; +static u_char baud_co[] = { /* 20 MHz clock option table */ + 0x00, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x60, 0x60, 0x40, + 0x40, 0x40, 0x20, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 +}; /* These values written directly to tbpr/rbpr */ -static u_char baud_bpr[] = { /* 20 MHz baud rate period table */ - 0x00, 0xc0, 0x80, 0x58, 0x6c, 0x40, 0xc0, 0x81, 0x40, 0x81, - 0x57, 0x40, 0x81, 0x40, 0x81, 0x40, 0x2b, 0x20, 0x15, 0x10}; - -static u_char baud_cor4[] = { /* receive threshold */ - 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, - 0x0a, 0x0a, 0x0a, 0x09, 0x09, 0x08, 0x08, 0x08, 0x08, 0x07}; - +static u_char baud_bpr[] = { /* 20 MHz baud rate period table */ + 0x00, 0xc0, 0x80, 0x58, 0x6c, 0x40, 0xc0, 0x81, 0x40, 0x81, + 0x57, 0x40, 0x81, 0x40, 0x81, 0x40, 0x2b, 0x20, 0x15, 0x10 +}; +static u_char baud_cor4[] = { /* receive threshold */ + 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, + 0x0a, 0x0a, 0x0a, 0x09, 0x09, 0x08, 0x08, 0x08, 0x08, 0x07 +}; static void shutdown(struct cyclades_port *); -static int startup (struct cyclades_port *); +static int startup(struct cyclades_port *); static void cy_throttle(struct tty_struct *); static void cy_unthrottle(struct tty_struct *); static void config_setup(struct cyclades_port *); @@ -174,16 +179,16 @@ #endif #ifdef CONFIG_REMOTE_DEBUG static void debug_setup(void); -void queueDebugChar (int c); +void queueDebugChar(int c); int getDebugChar(void); #define DEBUG_PORT 1 #define DEBUG_LEN 256 typedef struct { - int in; - int out; - unsigned char buf[DEBUG_LEN]; + int in; + int out; + unsigned char buf[DEBUG_LEN]; } debugq; debugq debugiq; @@ -196,7 +201,7 @@ #endif * delay, but this wild guess will do for now. */ -void my_udelay (long us) +void my_udelay(long us) { u_char x; volatile u_char *p = &x; @@ -207,62 +212,73 @@ void my_udelay (long us) x |= *p; } -static inline int -serial_paranoia_check(struct cyclades_port *info, char *name, - const char *routine) +static inline int serial_paranoia_check(struct cyclades_port *info, char *name, + const char *routine) { #ifdef SERIAL_PARANOIA_CHECK - static const char *badmagic = - "Warning: bad magic number for serial struct (%s) in %s\n"; - static const char *badinfo = - "Warning: null cyclades_port for (%s) in %s\n"; - static const char *badrange = - "Warning: cyclades_port out of range for (%s) in %s\n"; - - if (!info) { - printk(badinfo, name, routine); - return 1; - } - - if( (long)info < (long)(&cy_port[0]) - || (long)(&cy_port[NR_PORTS]) < (long)info ){ - printk(badrange, name, routine); - return 1; - } - - if (info->magic != CYCLADES_MAGIC) { - printk(badmagic, name, routine); - return 1; - } + if (!info) { + printk("Warning: null cyclades_port for (%s) in %s\n", name, + routine); + return 1; + } + + if ((long)info < (long)(&cy_port[0]) + || (long)(&cy_port[NR_PORTS]) < (long)info) { + printk("Warning: cyclades_port out of range for (%s) in %s\n", + name, routine); + return 1; + } + + if (info->magic != CYCLADES_MAGIC) { + printk("Warning: bad magic number for serial struct (%s) in " + "%s\n", name, routine); + return 1; + } #endif return 0; -} /* serial_paranoia_check */ +} /* serial_paranoia_check */ #if 0 /* The following diagnostic routines allow the driver to spew information on the screen, even (especially!) during interrupts. */ -void -SP(char *data){ - unsigned long flags; - local_irq_save(flags); - console_print(data); - local_irq_restore(flags); +void SP(char *data) +{ + unsigned long flags; + local_irq_save(flags); + console_print(data); + local_irq_restore(flags); } + char scrn[2]; -void -CP(char data){ - unsigned long flags; - local_irq_save(flags); - scrn[0] = data; - console_print(scrn); - local_irq_restore(flags); -}/* CP */ +void CP(char data) +{ + unsigned long flags; + local_irq_save(flags); + scrn[0] = data; + console_print(scrn); + local_irq_restore(flags); +} /* CP */ -void CP1(int data) { (data<10)? CP(data+'0'): CP(data+'A'-10); }/* CP1 */ -void CP2(int data) { CP1((data>>4) & 0x0f); CP1( data & 0x0f); }/* CP2 */ -void CP4(int data) { CP2((data>>8) & 0xff); CP2(data & 0xff); }/* CP4 */ -void CP8(long data) { CP4((data>>16) & 0xffff); CP4(data & 0xffff); }/* CP8 */ +void CP1(int data) +{ + (data < 10) ? CP(data + '0') : CP(data + 'A' - 10); +} /* CP1 */ +void CP2(int data) +{ + CP1((data >> 4) & 0x0f); + CP1(data & 0x0f); +} /* CP2 */ +void CP4(int data) +{ + CP2((data >> 8) & 0xff); + CP2(data & 0xff); +} /* CP4 */ +void CP8(long data) +{ + CP4((data >> 16) & 0xffff); + CP4(data & 0xffff); +} /* CP8 */ #endif /* This routine waits up to 1000 micro-seconds for the previous @@ -270,87 +286,78 @@ #endif new command. An error is returned if the previous command didn't finish within the time limit. */ -u_short -write_cy_cmd(volatile u_char *base_addr, u_char cmd) +u_short write_cy_cmd(volatile u_char * base_addr, u_char cmd) { - unsigned long flags; - volatile int i; + unsigned long flags; + volatile int i; - local_irq_save(flags); + local_irq_save(flags); /* Check to see that the previous command has completed */ - for(i = 0 ; i < 100 ; i++){ - if (base_addr[CyCCR] == 0){ - break; - } - my_udelay(10L); + for (i = 0; i < 100; i++) { + if (base_addr[CyCCR] == 0) { + break; + } + my_udelay(10L); } /* if the CCR never cleared, the previous command - didn't finish within the "reasonable time" */ - if ( i == 10 ) { - local_irq_restore(flags); - return (-1); + didn't finish within the "reasonable time" */ + if (i == 10) { + local_irq_restore(flags); + return (-1); } /* Issue the new command */ base_addr[CyCCR] = cmd; - local_irq_restore(flags); - return(0); -} /* write_cy_cmd */ - + local_irq_restore(flags); + return (0); +} /* write_cy_cmd */ /* cy_start and cy_stop provide software output flow control as a function of XON/XOFF, software CTS, and other such stuff. */ -static void -cy_stop(struct tty_struct *tty) +static void cy_stop(struct tty_struct *tty) { - struct cyclades_port *info = (struct cyclades_port *)tty->driver_data; - volatile unsigned char *base_addr = (unsigned char *)BASE_ADDR; - int channel; - unsigned long flags; + struct cyclades_port *info = (struct cyclades_port *)tty->driver_data; + volatile unsigned char *base_addr = (unsigned char *)BASE_ADDR; + int channel; + unsigned long flags; #ifdef SERIAL_DEBUG_OTHER - printk("cy_stop %s\n", tty->name); /* */ + printk("cy_stop %s\n", tty->name); /* */ #endif - if (serial_paranoia_check(info, tty->name, "cy_stop")) - return; - - channel = info->line; + if (serial_paranoia_check(info, tty->name, "cy_stop")) + return; - local_irq_save(flags); - base_addr[CyCAR] = (u_char)(channel); /* index channel */ - base_addr[CyIER] &= ~(CyTxMpty|CyTxRdy); - local_irq_restore(flags); + channel = info->line; - return; -} /* cy_stop */ + local_irq_save(flags); + base_addr[CyCAR] = (u_char) (channel); /* index channel */ + base_addr[CyIER] &= ~(CyTxMpty | CyTxRdy); + local_irq_restore(flags); +} /* cy_stop */ -static void -cy_start(struct tty_struct *tty) +static void cy_start(struct tty_struct *tty) { - struct cyclades_port *info = (struct cyclades_port *)tty->driver_data; - volatile unsigned char *base_addr = (unsigned char *)BASE_ADDR; - int channel; - unsigned long flags; + struct cyclades_port *info = (struct cyclades_port *)tty->driver_data; + volatile unsigned char *base_addr = (unsigned char *)BASE_ADDR; + int channel; + unsigned long flags; #ifdef SERIAL_DEBUG_OTHER - printk("cy_start %s\n", tty->name); /* */ + printk("cy_start %s\n", tty->name); /* */ #endif - if (serial_paranoia_check(info, tty->name, "cy_start")) - return; - - channel = info->line; + if (serial_paranoia_check(info, tty->name, "cy_start")) + return; - local_irq_save(flags); - base_addr[CyCAR] = (u_char)(channel); - base_addr[CyIER] |= CyTxMpty; - local_irq_restore(flags); - - return; -} /* cy_start */ + channel = info->line; + local_irq_save(flags); + base_addr[CyCAR] = (u_char) (channel); + base_addr[CyIER] |= CyTxMpty; + local_irq_restore(flags); +} /* cy_start */ /* * This routine is used by the interrupt handler to schedule @@ -358,332 +365,332 @@ #endif * (also known as the "bottom half"). This can be called any * number of times for any channel without harm. */ -static inline void -cy_sched_event(struct cyclades_port *info, int event) +static inline void cy_sched_event(struct cyclades_port *info, int event) { - info->event |= 1 << event; /* remember what kind of event and who */ - schedule_work(&info->tqueue); -} /* cy_sched_event */ - + info->event |= 1 << event; /* remember what kind of event and who */ + schedule_work(&info->tqueue); +} /* cy_sched_event */ /* The real interrupt service routines are called whenever the card wants its hand held--chars received, out buffer empty, modem change, etc. */ -static irqreturn_t -cd2401_rxerr_interrupt(int irq, void *dev_id) +static irqreturn_t cd2401_rxerr_interrupt(int irq, void *dev_id) { - struct tty_struct *tty; - struct cyclades_port *info; - volatile unsigned char *base_addr = (unsigned char *)BASE_ADDR; - unsigned char err, rfoc; - int channel; - char data; - - /* determine the channel and change to that context */ - channel = (u_short ) (base_addr[CyLICR] >> 2); - info = &cy_port[channel]; - info->last_active = jiffies; - - if ((err = base_addr[CyRISR]) & CyTIMEOUT) { - /* This is a receive timeout interrupt, ignore it */ - base_addr[CyREOIR] = CyNOTRANS; - return IRQ_HANDLED; - } - - /* Read a byte of data if there is any - assume the error - * is associated with this character */ + struct tty_struct *tty; + struct cyclades_port *info; + volatile unsigned char *base_addr = (unsigned char *)BASE_ADDR; + unsigned char err, rfoc; + int channel; + char data; + + /* determine the channel and change to that context */ + channel = (u_short) (base_addr[CyLICR] >> 2); + info = &cy_port[channel]; + info->last_active = jiffies; + + if ((err = base_addr[CyRISR]) & CyTIMEOUT) { + /* This is a receive timeout interrupt, ignore it */ + base_addr[CyREOIR] = CyNOTRANS; + return IRQ_HANDLED; + } - if ((rfoc = base_addr[CyRFOC]) != 0) - data = base_addr[CyRDR]; - else - data = 0; + /* Read a byte of data if there is any - assume the error + * is associated with this character */ - /* if there is nowhere to put the data, discard it */ - if(info->tty == 0) { + if ((rfoc = base_addr[CyRFOC]) != 0) + data = base_addr[CyRDR]; + else + data = 0; + + /* if there is nowhere to put the data, discard it */ + if (info->tty == 0) { + base_addr[CyREOIR] = rfoc ? 0 : CyNOTRANS; + return IRQ_HANDLED; + } else { /* there is an open port for this data */ + tty = info->tty; + if (err & info->ignore_status_mask) { + base_addr[CyREOIR] = rfoc ? 0 : CyNOTRANS; + return IRQ_HANDLED; + } + if (tty_buffer_request_room(tty, 1) != 0) { + if (err & info->read_status_mask) { + if (err & CyBREAK) { + tty_insert_flip_char(tty, data, + TTY_BREAK); + if (info->flags & ASYNC_SAK) { + do_SAK(tty); + } + } else if (err & CyFRAME) { + tty_insert_flip_char(tty, data, + TTY_FRAME); + } else if (err & CyPARITY) { + tty_insert_flip_char(tty, data, + TTY_PARITY); + } else if (err & CyOVERRUN) { + tty_insert_flip_char(tty, 0, + TTY_OVERRUN); + /* + If the flip buffer itself is + overflowing, we still loose + the next incoming character. + */ + if (tty_buffer_request_room(tty, 1) != + 0) { + tty_insert_flip_char(tty, data, + TTY_FRAME); + } + /* These two conditions may imply */ + /* a normal read should be done. */ + /* else if(data & CyTIMEOUT) */ + /* else if(data & CySPECHAR) */ + } else { + tty_insert_flip_char(tty, 0, + TTY_NORMAL); + } + } else { + tty_insert_flip_char(tty, data, TTY_NORMAL); + } + } else { + /* there was a software buffer overrun + and nothing could be done about it!!! */ + } + } + tty_schedule_flip(tty); + /* end of service */ base_addr[CyREOIR] = rfoc ? 0 : CyNOTRANS; return IRQ_HANDLED; - } - else { /* there is an open port for this data */ - tty = info->tty; - if(err & info->ignore_status_mask){ - base_addr[CyREOIR] = rfoc ? 0 : CyNOTRANS; - return IRQ_HANDLED; - } - if (tty_buffer_request_room(tty, 1) != 0){ - if (err & info->read_status_mask){ - if(err & CyBREAK){ - tty_insert_flip_char(tty, data, TTY_BREAK); - if (info->flags & ASYNC_SAK){ - do_SAK(tty); - } - }else if(err & CyFRAME){ - tty_insert_flip_char(tty, data, TTY_FRAME); - }else if(err & CyPARITY){ - tty_insert_flip_char(tty, data, TTY_PARITY); - }else if(err & CyOVERRUN){ - tty_insert_flip_char(tty, 0, TTY_OVERRUN); - /* - If the flip buffer itself is - overflowing, we still loose - the next incoming character. - */ - if (tty_buffer_request_room(tty, 1) != 0){ - tty_insert_flip_char(tty, data, TTY_FRAME); - } - /* These two conditions may imply */ - /* a normal read should be done. */ - /* else if(data & CyTIMEOUT) */ - /* else if(data & CySPECHAR) */ - }else{ - tty_insert_flip_char(tty, 0, TTY_NORMAL); - } - }else{ - tty_insert_flip_char(tty, data, TTY_NORMAL); - } - }else{ - /* there was a software buffer overrun - and nothing could be done about it!!! */ - } - } - tty_schedule_flip(tty); - /* end of service */ - base_addr[CyREOIR] = rfoc ? 0 : CyNOTRANS; - return IRQ_HANDLED; -} /* cy_rxerr_interrupt */ - -static irqreturn_t -cd2401_modem_interrupt(int irq, void *dev_id) +} /* cy_rxerr_interrupt */ + +static irqreturn_t cd2401_modem_interrupt(int irq, void *dev_id) { - struct cyclades_port *info; - volatile unsigned char *base_addr = (unsigned char *)BASE_ADDR; - int channel; - int mdm_change; - int mdm_status; - - - /* determine the channel and change to that context */ - channel = (u_short ) (base_addr[CyLICR] >> 2); - info = &cy_port[channel]; - info->last_active = jiffies; - - mdm_change = base_addr[CyMISR]; - mdm_status = base_addr[CyMSVR1]; - - if(info->tty == 0){ /* nowhere to put the data, ignore it */ - ; - }else{ - if((mdm_change & CyDCD) - && (info->flags & ASYNC_CHECK_CD)){ - if(mdm_status & CyDCD){ + struct cyclades_port *info; + volatile unsigned char *base_addr = (unsigned char *)BASE_ADDR; + int channel; + int mdm_change; + int mdm_status; + + /* determine the channel and change to that context */ + channel = (u_short) (base_addr[CyLICR] >> 2); + info = &cy_port[channel]; + info->last_active = jiffies; + + mdm_change = base_addr[CyMISR]; + mdm_status = base_addr[CyMSVR1]; + + if (info->tty == 0) { /* nowhere to put the data, ignore it */ + ; + } else { + if ((mdm_change & CyDCD) + && (info->flags & ASYNC_CHECK_CD)) { + if (mdm_status & CyDCD) { /* CP('!'); */ - cy_sched_event(info, Cy_EVENT_OPEN_WAKEUP); - } else { + cy_sched_event(info, Cy_EVENT_OPEN_WAKEUP); + } else { /* CP('@'); */ - cy_sched_event(info, Cy_EVENT_HANGUP); - } - } - if((mdm_change & CyCTS) - && (info->flags & ASYNC_CTS_FLOW)){ - if(info->tty->stopped){ - if(mdm_status & CyCTS){ - /* !!! cy_start isn't used because... */ - info->tty->stopped = 0; - base_addr[CyIER] |= CyTxMpty; - cy_sched_event(info, Cy_EVENT_WRITE_WAKEUP); + cy_sched_event(info, Cy_EVENT_HANGUP); + } } - }else{ - if(!(mdm_status & CyCTS)){ - /* !!! cy_stop isn't used because... */ - info->tty->stopped = 1; - base_addr[CyIER] &= ~(CyTxMpty|CyTxRdy); + if ((mdm_change & CyCTS) + && (info->flags & ASYNC_CTS_FLOW)) { + if (info->tty->stopped) { + if (mdm_status & CyCTS) { + /* !!! cy_start isn't used because... */ + info->tty->stopped = 0; + base_addr[CyIER] |= CyTxMpty; + cy_sched_event(info, + Cy_EVENT_WRITE_WAKEUP); + } + } else { + if (!(mdm_status & CyCTS)) { + /* !!! cy_stop isn't used because... */ + info->tty->stopped = 1; + base_addr[CyIER] &= + ~(CyTxMpty | CyTxRdy); + } + } + } + if (mdm_status & CyDSR) { } - } - } - if(mdm_status & CyDSR){ } - } - base_addr[CyMEOIR] = 0; - return IRQ_HANDLED; -} /* cy_modem_interrupt */ + base_addr[CyMEOIR] = 0; + return IRQ_HANDLED; +} /* cy_modem_interrupt */ -static irqreturn_t -cd2401_tx_interrupt(int irq, void *dev_id) +static irqreturn_t cd2401_tx_interrupt(int irq, void *dev_id) { - struct cyclades_port *info; - volatile unsigned char *base_addr = (unsigned char *)BASE_ADDR; - int channel; - int char_count, saved_cnt; - int outch; + struct cyclades_port *info; + volatile unsigned char *base_addr = (unsigned char *)BASE_ADDR; + int channel; + int char_count, saved_cnt; + int outch; - /* determine the channel and change to that context */ - channel = (u_short ) (base_addr[CyLICR] >> 2); + /* determine the channel and change to that context */ + channel = (u_short) (base_addr[CyLICR] >> 2); #ifdef CONFIG_REMOTE_DEBUG - if (channel == DEBUG_PORT) { - panic ("TxInt on debug port!!!"); - } + if (channel == DEBUG_PORT) { + panic("TxInt on debug port!!!"); + } #endif - info = &cy_port[channel]; + info = &cy_port[channel]; - /* validate the port number (as configured and open) */ - if( (channel < 0) || (NR_PORTS <= channel) ){ - base_addr[CyIER] &= ~(CyTxMpty|CyTxRdy); - base_addr[CyTEOIR] = CyNOTRANS; - return IRQ_HANDLED; - } - info->last_active = jiffies; - if(info->tty == 0){ - base_addr[CyIER] &= ~(CyTxMpty|CyTxRdy); - if (info->xmit_cnt < WAKEUP_CHARS) { - cy_sched_event(info, Cy_EVENT_WRITE_WAKEUP); - } - base_addr[CyTEOIR] = CyNOTRANS; - return IRQ_HANDLED; - } - - /* load the on-chip space available for outbound data */ - saved_cnt = char_count = base_addr[CyTFTC]; - - if(info->x_char) { /* send special char */ - outch = info->x_char; - base_addr[CyTDR] = outch; - char_count--; - info->x_char = 0; - } - - if (info->x_break){ - /* The Cirrus chip requires the "Embedded Transmit - Commands" of start break, delay, and end break - sequences to be sent. The duration of the - break is given in TICs, which runs at HZ - (typically 100) and the PPR runs at 200 Hz, - so the delay is duration * 200/HZ, and thus a - break can run from 1/100 sec to about 5/4 sec. - Need to check these values - RGH 141095. - */ - base_addr[CyTDR] = 0; /* start break */ - base_addr[CyTDR] = 0x81; - base_addr[CyTDR] = 0; /* delay a bit */ - base_addr[CyTDR] = 0x82; - base_addr[CyTDR] = info->x_break*200/HZ; - base_addr[CyTDR] = 0; /* terminate break */ - base_addr[CyTDR] = 0x83; - char_count -= 7; - info->x_break = 0; - } - - while (char_count > 0){ - if (!info->xmit_cnt){ - base_addr[CyIER] &= ~(CyTxMpty|CyTxRdy); - break; - } - if (info->xmit_buf == 0){ - base_addr[CyIER] &= ~(CyTxMpty|CyTxRdy); - break; - } - if (info->tty->stopped || info->tty->hw_stopped){ - base_addr[CyIER] &= ~(CyTxMpty|CyTxRdy); - break; - } - /* Because the Embedded Transmit Commands have been - enabled, we must check to see if the escape - character, NULL, is being sent. If it is, we - must ensure that there is room for it to be - doubled in the output stream. Therefore we - no longer advance the pointer when the character - is fetched, but rather wait until after the check - for a NULL output character. (This is necessary - because there may not be room for the two chars - needed to send a NULL. - */ - outch = info->xmit_buf[info->xmit_tail]; - if( outch ){ - info->xmit_cnt--; - info->xmit_tail = (info->xmit_tail + 1) - & (PAGE_SIZE - 1); - base_addr[CyTDR] = outch; - char_count--; - }else{ - if(char_count > 1){ - info->xmit_cnt--; - info->xmit_tail = (info->xmit_tail + 1) - & (PAGE_SIZE - 1); + /* validate the port number (as configured and open) */ + if ((channel < 0) || (NR_PORTS <= channel)) { + base_addr[CyIER] &= ~(CyTxMpty | CyTxRdy); + base_addr[CyTEOIR] = CyNOTRANS; + return IRQ_HANDLED; + } + info->last_active = jiffies; + if (info->tty == 0) { + base_addr[CyIER] &= ~(CyTxMpty | CyTxRdy); + if (info->xmit_cnt < WAKEUP_CHARS) { + cy_sched_event(info, Cy_EVENT_WRITE_WAKEUP); + } + base_addr[CyTEOIR] = CyNOTRANS; + return IRQ_HANDLED; + } + + /* load the on-chip space available for outbound data */ + saved_cnt = char_count = base_addr[CyTFTC]; + + if (info->x_char) { /* send special char */ + outch = info->x_char; base_addr[CyTDR] = outch; - base_addr[CyTDR] = 0; char_count--; - char_count--; - }else{ - break; - } + info->x_char = 0; } - } - if (info->xmit_cnt < WAKEUP_CHARS) { - cy_sched_event(info, Cy_EVENT_WRITE_WAKEUP); - } - base_addr[CyTEOIR] = (char_count != saved_cnt) ? 0 : CyNOTRANS; - return IRQ_HANDLED; -} /* cy_tx_interrupt */ + if (info->x_break) { + /* The Cirrus chip requires the "Embedded Transmit + Commands" of start break, delay, and end break + sequences to be sent. The duration of the + break is given in TICs, which runs at HZ + (typically 100) and the PPR runs at 200 Hz, + so the delay is duration * 200/HZ, and thus a + break can run from 1/100 sec to about 5/4 sec. + Need to check these values - RGH 141095. + */ + base_addr[CyTDR] = 0; /* start break */ + base_addr[CyTDR] = 0x81; + base_addr[CyTDR] = 0; /* delay a bit */ + base_addr[CyTDR] = 0x82; + base_addr[CyTDR] = info->x_break * 200 / HZ; + base_addr[CyTDR] = 0; /* terminate break */ + base_addr[CyTDR] = 0x83; + char_count -= 7; + info->x_break = 0; + } + + while (char_count > 0) { + if (!info->xmit_cnt) { + base_addr[CyIER] &= ~(CyTxMpty | CyTxRdy); + break; + } + if (info->xmit_buf == 0) { + base_addr[CyIER] &= ~(CyTxMpty | CyTxRdy); + break; + } + if (info->tty->stopped || info->tty->hw_stopped) { + base_addr[CyIER] &= ~(CyTxMpty | CyTxRdy); + break; + } + /* Because the Embedded Transmit Commands have been + enabled, we must check to see if the escape + character, NULL, is being sent. If it is, we + must ensure that there is room for it to be + doubled in the output stream. Therefore we + no longer advance the pointer when the character + is fetched, but rather wait until after the check + for a NULL output character. (This is necessary + because there may not be room for the two chars + needed to send a NULL. + */ + outch = info->xmit_buf[info->xmit_tail]; + if (outch) { + info->xmit_cnt--; + info->xmit_tail = (info->xmit_tail + 1) + & (PAGE_SIZE - 1); + base_addr[CyTDR] = outch; + char_count--; + } else { + if (char_count > 1) { + info->xmit_cnt--; + info->xmit_tail = (info->xmit_tail + 1) + & (PAGE_SIZE - 1); + base_addr[CyTDR] = outch; + base_addr[CyTDR] = 0; + char_count--; + char_count--; + } else { + break; + } + } + } + + if (info->xmit_cnt < WAKEUP_CHARS) { + cy_sched_event(info, Cy_EVENT_WRITE_WAKEUP); + } + base_addr[CyTEOIR] = (char_count != saved_cnt) ? 0 : CyNOTRANS; + return IRQ_HANDLED; +} /* cy_tx_interrupt */ -static irqreturn_t -cd2401_rx_interrupt(int irq, void *dev_id) +static irqreturn_t cd2401_rx_interrupt(int irq, void *dev_id) { - struct tty_struct *tty; - struct cyclades_port *info; - volatile unsigned char *base_addr = (unsigned char *)BASE_ADDR; - int channel; - char data; - int char_count; - int save_cnt; - int len; - - /* determine the channel and change to that context */ - channel = (u_short ) (base_addr[CyLICR] >> 2); - info = &cy_port[channel]; - info->last_active = jiffies; - save_cnt = char_count = base_addr[CyRFOC]; + struct tty_struct *tty; + struct cyclades_port *info; + volatile unsigned char *base_addr = (unsigned char *)BASE_ADDR; + int channel; + char data; + int char_count; + int save_cnt; + int len; + + /* determine the channel and change to that context */ + channel = (u_short) (base_addr[CyLICR] >> 2); + info = &cy_port[channel]; + info->last_active = jiffies; + save_cnt = char_count = base_addr[CyRFOC]; #ifdef CONFIG_REMOTE_DEBUG - if (channel == DEBUG_PORT) { - while (char_count--) { - data = base_addr[CyRDR]; - queueDebugChar(data); - } - } - else + if (channel == DEBUG_PORT) { + while (char_count--) { + data = base_addr[CyRDR]; + queueDebugChar(data); + } + } else #endif - /* if there is nowhere to put the data, discard it */ - if(info->tty == 0){ - while(char_count--){ - data = base_addr[CyRDR]; - } - }else{ /* there is an open port for this data */ - tty = info->tty; - /* load # characters available from the chip */ + /* if there is nowhere to put the data, discard it */ + if (info->tty == 0) { + while (char_count--) { + data = base_addr[CyRDR]; + } + } else { /* there is an open port for this data */ + tty = info->tty; + /* load # characters available from the chip */ #ifdef CYCLOM_ENABLE_MONITORING - ++info->mon.int_count; - info->mon.char_count += char_count; - if (char_count > info->mon.char_max) - info->mon.char_max = char_count; - info->mon.char_last = char_count; -#endif - len = tty_buffer_request_room(tty, char_count); - while(len--){ - data = base_addr[CyRDR]; - tty_insert_flip_char(tty, data, TTY_NORMAL); + ++info->mon.int_count; + info->mon.char_count += char_count; + if (char_count > info->mon.char_max) + info->mon.char_max = char_count; + info->mon.char_last = char_count; +#endif + len = tty_buffer_request_room(tty, char_count); + while (len--) { + data = base_addr[CyRDR]; + tty_insert_flip_char(tty, data, TTY_NORMAL); #ifdef CYCLOM_16Y_HACK - udelay(10L); + udelay(10L); #endif - } - tty_schedule_flip(tty); - } - /* end of service */ - base_addr[CyREOIR] = save_cnt ? 0 : CyNOTRANS; - return IRQ_HANDLED; -} /* cy_rx_interrupt */ + } + tty_schedule_flip(tty); + } + /* end of service */ + base_addr[CyREOIR] = save_cnt ? 0 : CyNOTRANS; + return IRQ_HANDLED; +} /* cy_rx_interrupt */ /* * This routine is used to handle the "bottom half" processing for the @@ -705,192 +712,188 @@ #endif * structure) to the bottom half of the driver. Previous kernels * had to poll every port to see if that port needed servicing. */ -static void -do_softint(struct work_struct *ugly_api) +static void do_softint(struct work_struct *ugly_api) { - struct cyclades_port *info = container_of(ugly_api, struct cyclades_port, tqueue); - struct tty_struct *tty; - - tty = info->tty; - if (!tty) - return; + struct cyclades_port *info = + container_of(ugly_api, struct cyclades_port, tqueue); + struct tty_struct *tty; - if (test_and_clear_bit(Cy_EVENT_HANGUP, &info->event)) { - tty_hangup(info->tty); - wake_up_interruptible(&info->open_wait); - info->flags &= ~ASYNC_NORMAL_ACTIVE; - } - if (test_and_clear_bit(Cy_EVENT_OPEN_WAKEUP, &info->event)) { - wake_up_interruptible(&info->open_wait); - } - if (test_and_clear_bit(Cy_EVENT_WRITE_WAKEUP, &info->event)) { - tty_wakeup(tty); - } -} /* do_softint */ + tty = info->tty; + if (!tty) + return; + if (test_and_clear_bit(Cy_EVENT_HANGUP, &info->event)) { + tty_hangup(info->tty); + wake_up_interruptible(&info->open_wait); + info->flags &= ~ASYNC_NORMAL_ACTIVE; + } + if (test_and_clear_bit(Cy_EVENT_OPEN_WAKEUP, &info->event)) { + wake_up_interruptible(&info->open_wait); + } + if (test_and_clear_bit(Cy_EVENT_WRITE_WAKEUP, &info->event)) { + tty_wakeup(tty); + } +} /* do_softint */ /* This is called whenever a port becomes active; interrupts are enabled and DTR & RTS are turned on. */ -static int -startup(struct cyclades_port * info) +static int startup(struct cyclades_port *info) { - unsigned long flags; - volatile unsigned char *base_addr = (unsigned char *)BASE_ADDR; - int channel; + unsigned long flags; + volatile unsigned char *base_addr = (unsigned char *)BASE_ADDR; + int channel; - if (info->flags & ASYNC_INITIALIZED){ - return 0; - } + if (info->flags & ASYNC_INITIALIZED) { + return 0; + } - if (!info->type){ - if (info->tty){ - set_bit(TTY_IO_ERROR, &info->tty->flags); + if (!info->type) { + if (info->tty) { + set_bit(TTY_IO_ERROR, &info->tty->flags); + } + return 0; } - return 0; - } - if (!info->xmit_buf){ - info->xmit_buf = (unsigned char *) get_zeroed_page (GFP_KERNEL); - if (!info->xmit_buf){ - return -ENOMEM; + if (!info->xmit_buf) { + info->xmit_buf = (unsigned char *)get_zeroed_page(GFP_KERNEL); + if (!info->xmit_buf) { + return -ENOMEM; + } } - } - config_setup(info); + config_setup(info); - channel = info->line; + channel = info->line; #ifdef SERIAL_DEBUG_OPEN - printk("startup channel %d\n", channel); + printk("startup channel %d\n", channel); #endif - local_irq_save(flags); - base_addr[CyCAR] = (u_char)channel; - write_cy_cmd(base_addr,CyENB_RCVR|CyENB_XMTR); + local_irq_save(flags); + base_addr[CyCAR] = (u_char) channel; + write_cy_cmd(base_addr, CyENB_RCVR | CyENB_XMTR); - base_addr[CyCAR] = (u_char)channel; /* !!! Is this needed? */ + base_addr[CyCAR] = (u_char) channel; /* !!! Is this needed? */ base_addr[CyMSVR1] = CyRTS; /* CP('S');CP('1'); */ base_addr[CyMSVR2] = CyDTR; #ifdef SERIAL_DEBUG_DTR - printk("cyc: %d: raising DTR\n", __LINE__); - printk(" status: 0x%x, 0x%x\n", base_addr[CyMSVR1], base_addr[CyMSVR2]); + printk("cyc: %d: raising DTR\n", __LINE__); + printk(" status: 0x%x, 0x%x\n", base_addr[CyMSVR1], + base_addr[CyMSVR2]); #endif base_addr[CyIER] |= CyRxData; info->flags |= ASYNC_INITIALIZED; - if (info->tty){ - clear_bit(TTY_IO_ERROR, &info->tty->flags); + if (info->tty) { + clear_bit(TTY_IO_ERROR, &info->tty->flags); } info->xmit_cnt = info->xmit_head = info->xmit_tail = 0; - local_irq_restore(flags); + local_irq_restore(flags); #ifdef SERIAL_DEBUG_OPEN - printk(" done\n"); + printk(" done\n"); #endif - return 0; -} /* startup */ + return 0; +} /* startup */ -void -start_xmit( struct cyclades_port *info ) +void start_xmit(struct cyclades_port *info) { - unsigned long flags; - volatile unsigned char *base_addr = (u_char *)BASE_ADDR; - int channel; + unsigned long flags; + volatile unsigned char *base_addr = (u_char *) BASE_ADDR; + int channel; - channel = info->line; - local_irq_save(flags); + channel = info->line; + local_irq_save(flags); base_addr[CyCAR] = channel; base_addr[CyIER] |= CyTxMpty; - local_irq_restore(flags); -} /* start_xmit */ + local_irq_restore(flags); +} /* start_xmit */ /* * This routine shuts down a serial port; interrupts are disabled, * and DTR is dropped if the hangup on close termio flag is on. */ -static void -shutdown(struct cyclades_port * info) +static void shutdown(struct cyclades_port *info) { - unsigned long flags; - volatile unsigned char *base_addr = (u_char *)BASE_ADDR; - int channel; + unsigned long flags; + volatile unsigned char *base_addr = (u_char *) BASE_ADDR; + int channel; - if (!(info->flags & ASYNC_INITIALIZED)){ + if (!(info->flags & ASYNC_INITIALIZED)) { /* CP('$'); */ - return; - } + return; + } - channel = info->line; + channel = info->line; #ifdef SERIAL_DEBUG_OPEN - printk("shutdown channel %d\n", channel); + printk("shutdown channel %d\n", channel); #endif - /* !!! REALLY MUST WAIT FOR LAST CHARACTER TO BE - SENT BEFORE DROPPING THE LINE !!! (Perhaps - set some flag that is read when XMTY happens.) - Other choices are to delay some fixed interval - or schedule some later processing. - */ - local_irq_save(flags); - if (info->xmit_buf){ - free_page((unsigned long) info->xmit_buf); - info->xmit_buf = NULL; + /* !!! REALLY MUST WAIT FOR LAST CHARACTER TO BE + SENT BEFORE DROPPING THE LINE !!! (Perhaps + set some flag that is read when XMTY happens.) + Other choices are to delay some fixed interval + or schedule some later processing. + */ + local_irq_save(flags); + if (info->xmit_buf) { + free_page((unsigned long)info->xmit_buf); + info->xmit_buf = NULL; } - base_addr[CyCAR] = (u_char)channel; + base_addr[CyCAR] = (u_char) channel; if (!info->tty || (info->tty->termios->c_cflag & HUPCL)) { - base_addr[CyMSVR1] = 0; + base_addr[CyMSVR1] = 0; /* CP('C');CP('1'); */ - base_addr[CyMSVR2] = 0; + base_addr[CyMSVR2] = 0; #ifdef SERIAL_DEBUG_DTR - printk("cyc: %d: dropping DTR\n", __LINE__); - printk(" status: 0x%x, 0x%x\n", base_addr[CyMSVR1], base_addr[CyMSVR2]); + printk("cyc: %d: dropping DTR\n", __LINE__); + printk(" status: 0x%x, 0x%x\n", base_addr[CyMSVR1], + base_addr[CyMSVR2]); #endif - } - write_cy_cmd(base_addr,CyDIS_RCVR); - /* it may be appropriate to clear _XMIT at - some later date (after testing)!!! */ + } + write_cy_cmd(base_addr, CyDIS_RCVR); + /* it may be appropriate to clear _XMIT at + some later date (after testing)!!! */ - if (info->tty){ - set_bit(TTY_IO_ERROR, &info->tty->flags); + if (info->tty) { + set_bit(TTY_IO_ERROR, &info->tty->flags); } info->flags &= ~ASYNC_INITIALIZED; - local_irq_restore(flags); + local_irq_restore(flags); #ifdef SERIAL_DEBUG_OPEN - printk(" done\n"); + printk(" done\n"); #endif - return; -} /* shutdown */ +} /* shutdown */ /* * This routine finds or computes the various line characteristics. */ -static void -config_setup(struct cyclades_port * info) +static void config_setup(struct cyclades_port *info) { - unsigned long flags; - volatile unsigned char *base_addr = (u_char *)BASE_ADDR; - int channel; - unsigned cflag; - int i; - unsigned char ti, need_init_chan = 0; - - if (!info->tty || !info->tty->termios){ - return; - } - if (info->line == -1){ - return; - } - cflag = info->tty->termios->c_cflag; - - /* baud rate */ - i = cflag & CBAUD; + unsigned long flags; + volatile unsigned char *base_addr = (u_char *) BASE_ADDR; + int channel; + unsigned cflag; + int i; + unsigned char ti, need_init_chan = 0; + + if (!info->tty || !info->tty->termios) { + return; + } + if (info->line == -1) { + return; + } + cflag = info->tty->termios->c_cflag; + + /* baud rate */ + i = cflag & CBAUD; #ifdef CBAUDEX /* Starting with kernel 1.1.65, there is direct support for higher baud rates. The following code supports those @@ -900,120 +903,123 @@ #ifdef CBAUDEX is still the possibility of supporting 75 kbit/sec with the Cyclades board.) */ - if (i & CBAUDEX) { - if (i == B57600) - i = 16; - else if(i == B115200) - i = 18; + if (i & CBAUDEX) { + if (i == B57600) + i = 16; + else if (i == B115200) + i = 18; #ifdef B78600 - else if(i == B78600) - i = 17; + else if (i == B78600) + i = 17; #endif - else - info->tty->termios->c_cflag &= ~CBAUDEX; - } -#endif - if (i == 15) { - if ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_HI) - i += 1; - if ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_VHI) - i += 3; - } - /* Don't ever change the speed of the console port. It will - * run at the speed specified in bootinfo, or at 19.2K */ - /* Actually, it should run at whatever speed 166Bug was using */ - /* Note info->timeout isn't used at present */ - if (info != serial_console_info) { - info->tbpr = baud_bpr[i]; /* Tx BPR */ - info->tco = baud_co[i]; /* Tx CO */ - info->rbpr = baud_bpr[i]; /* Rx BPR */ - info->rco = baud_co[i] >> 5; /* Rx CO */ - if (baud_table[i] == 134) { - info->timeout = (info->xmit_fifo_size*HZ*30/269) + 2; - /* get it right for 134.5 baud */ - } else if (baud_table[i]) { - info->timeout = (info->xmit_fifo_size*HZ*15/baud_table[i]) + 2; - /* this needs to be propagated into the card info */ + else + info->tty->termios->c_cflag &= ~CBAUDEX; + } +#endif + if (i == 15) { + if ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_HI) + i += 1; + if ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_VHI) + i += 3; + } + /* Don't ever change the speed of the console port. It will + * run at the speed specified in bootinfo, or at 19.2K */ + /* Actually, it should run at whatever speed 166Bug was using */ + /* Note info->timeout isn't used at present */ + if (info != serial_console_info) { + info->tbpr = baud_bpr[i]; /* Tx BPR */ + info->tco = baud_co[i]; /* Tx CO */ + info->rbpr = baud_bpr[i]; /* Rx BPR */ + info->rco = baud_co[i] >> 5; /* Rx CO */ + if (baud_table[i] == 134) { + info->timeout = + (info->xmit_fifo_size * HZ * 30 / 269) + 2; + /* get it right for 134.5 baud */ + } else if (baud_table[i]) { + info->timeout = + (info->xmit_fifo_size * HZ * 15 / baud_table[i]) + + 2; + /* this needs to be propagated into the card info */ + } else { + info->timeout = 0; + } + } + /* By tradition (is it a standard?) a baud rate of zero + implies the line should be/has been closed. A bit + later in this routine such a test is performed. */ + + /* byte size and parity */ + info->cor7 = 0; + info->cor6 = 0; + info->cor5 = 0; + info->cor4 = (info->default_threshold ? info->default_threshold : baud_cor4[i]); /* receive threshold */ + /* Following two lines added 101295, RGH. */ + /* It is obviously wrong to access CyCORx, and not info->corx here, + * try and remember to fix it later! */ + channel = info->line; + base_addr[CyCAR] = (u_char) channel; + if (C_CLOCAL(info->tty)) { + if (base_addr[CyIER] & CyMdmCh) + base_addr[CyIER] &= ~CyMdmCh; /* without modem intr */ + /* ignore 1->0 modem transitions */ + if (base_addr[CyCOR4] & (CyDSR | CyCTS | CyDCD)) + base_addr[CyCOR4] &= ~(CyDSR | CyCTS | CyDCD); + /* ignore 0->1 modem transitions */ + if (base_addr[CyCOR5] & (CyDSR | CyCTS | CyDCD)) + base_addr[CyCOR5] &= ~(CyDSR | CyCTS | CyDCD); } else { - info->timeout = 0; - } - } - /* By tradition (is it a standard?) a baud rate of zero - implies the line should be/has been closed. A bit - later in this routine such a test is performed. */ - - /* byte size and parity */ - info->cor7 = 0; - info->cor6 = 0; - info->cor5 = 0; - info->cor4 = (info->default_threshold - ? info->default_threshold - : baud_cor4[i]); /* receive threshold */ - /* Following two lines added 101295, RGH. */ - /* It is obviously wrong to access CyCORx, and not info->corx here, - * try and remember to fix it later! */ - channel = info->line; - base_addr[CyCAR] = (u_char)channel; - if (C_CLOCAL(info->tty)) { - if (base_addr[CyIER] & CyMdmCh) - base_addr[CyIER] &= ~CyMdmCh; /* without modem intr */ - /* ignore 1->0 modem transitions */ - if (base_addr[CyCOR4] & (CyDSR|CyCTS|CyDCD)) - base_addr[CyCOR4] &= ~(CyDSR|CyCTS|CyDCD); - /* ignore 0->1 modem transitions */ - if (base_addr[CyCOR5] & (CyDSR|CyCTS|CyDCD)) - base_addr[CyCOR5] &= ~(CyDSR|CyCTS|CyDCD); - } else { - if ((base_addr[CyIER] & CyMdmCh) != CyMdmCh) - base_addr[CyIER] |= CyMdmCh; /* with modem intr */ - /* act on 1->0 modem transitions */ - if ((base_addr[CyCOR4] & (CyDSR|CyCTS|CyDCD)) != (CyDSR|CyCTS|CyDCD)) - base_addr[CyCOR4] |= CyDSR|CyCTS|CyDCD; - /* act on 0->1 modem transitions */ - if ((base_addr[CyCOR5] & (CyDSR|CyCTS|CyDCD)) != (CyDSR|CyCTS|CyDCD)) - base_addr[CyCOR5] |= CyDSR|CyCTS|CyDCD; - } - info->cor3 = (cflag & CSTOPB) ? Cy_2_STOP : Cy_1_STOP; - info->cor2 = CyETC; - switch(cflag & CSIZE){ - case CS5: - info->cor1 = Cy_5_BITS; - break; - case CS6: - info->cor1 = Cy_6_BITS; - break; - case CS7: - info->cor1 = Cy_7_BITS; - break; - case CS8: - info->cor1 = Cy_8_BITS; - break; - } - if (cflag & PARENB){ - if (cflag & PARODD){ - info->cor1 |= CyPARITY_O; - }else{ - info->cor1 |= CyPARITY_E; - } - }else{ - info->cor1 |= CyPARITY_NONE; - } - - /* CTS flow control flag */ + if ((base_addr[CyIER] & CyMdmCh) != CyMdmCh) + base_addr[CyIER] |= CyMdmCh; /* with modem intr */ + /* act on 1->0 modem transitions */ + if ((base_addr[CyCOR4] & (CyDSR | CyCTS | CyDCD)) != + (CyDSR | CyCTS | CyDCD)) + base_addr[CyCOR4] |= CyDSR | CyCTS | CyDCD; + /* act on 0->1 modem transitions */ + if ((base_addr[CyCOR5] & (CyDSR | CyCTS | CyDCD)) != + (CyDSR | CyCTS | CyDCD)) + base_addr[CyCOR5] |= CyDSR | CyCTS | CyDCD; + } + info->cor3 = (cflag & CSTOPB) ? Cy_2_STOP : Cy_1_STOP; + info->cor2 = CyETC; + switch (cflag & CSIZE) { + case CS5: + info->cor1 = Cy_5_BITS; + break; + case CS6: + info->cor1 = Cy_6_BITS; + break; + case CS7: + info->cor1 = Cy_7_BITS; + break; + case CS8: + info->cor1 = Cy_8_BITS; + break; + } + if (cflag & PARENB) { + if (cflag & PARODD) { + info->cor1 |= CyPARITY_O; + } else { + info->cor1 |= CyPARITY_E; + } + } else { + info->cor1 |= CyPARITY_NONE; + } + + /* CTS flow control flag */ #if 0 - /* Don't complcate matters for now! RGH 141095 */ - if (cflag & CRTSCTS){ - info->flags |= ASYNC_CTS_FLOW; - info->cor2 |= CyCtsAE; - }else{ - info->flags &= ~ASYNC_CTS_FLOW; - info->cor2 &= ~CyCtsAE; - } -#endif - if (cflag & CLOCAL) - info->flags &= ~ASYNC_CHECK_CD; - else - info->flags |= ASYNC_CHECK_CD; + /* Don't complcate matters for now! RGH 141095 */ + if (cflag & CRTSCTS) { + info->flags |= ASYNC_CTS_FLOW; + info->cor2 |= CyCtsAE; + } else { + info->flags &= ~ASYNC_CTS_FLOW; + info->cor2 &= ~CyCtsAE; + } +#endif + if (cflag & CLOCAL) + info->flags &= ~ASYNC_CHECK_CD; + else + info->flags |= ASYNC_CHECK_CD; /*********************************************** The hardware option, CyRtsAO, presents RTS when @@ -1025,149 +1031,146 @@ #endif cable. Contact Marcio Saito for details. ***********************************************/ - channel = info->line; + channel = info->line; - local_irq_save(flags); - base_addr[CyCAR] = (u_char)channel; + local_irq_save(flags); + base_addr[CyCAR] = (u_char) channel; /* CyCMR set once only in mvme167_init_serial() */ if (base_addr[CyLICR] != channel << 2) - base_addr[CyLICR] = channel << 2; + base_addr[CyLICR] = channel << 2; if (base_addr[CyLIVR] != 0x5c) - base_addr[CyLIVR] = 0x5c; + base_addr[CyLIVR] = 0x5c; - /* tx and rx baud rate */ + /* tx and rx baud rate */ if (base_addr[CyCOR1] != info->cor1) - need_init_chan = 1; + need_init_chan = 1; if (base_addr[CyTCOR] != info->tco) - base_addr[CyTCOR] = info->tco; + base_addr[CyTCOR] = info->tco; if (base_addr[CyTBPR] != info->tbpr) - base_addr[CyTBPR] = info->tbpr; + base_addr[CyTBPR] = info->tbpr; if (base_addr[CyRCOR] != info->rco) - base_addr[CyRCOR] = info->rco; + base_addr[CyRCOR] = info->rco; if (base_addr[CyRBPR] != info->rbpr) - base_addr[CyRBPR] = info->rbpr; + base_addr[CyRBPR] = info->rbpr; /* set line characteristics according configuration */ if (base_addr[CySCHR1] != START_CHAR(info->tty)) - base_addr[CySCHR1] = START_CHAR(info->tty); + base_addr[CySCHR1] = START_CHAR(info->tty); if (base_addr[CySCHR2] != STOP_CHAR(info->tty)) - base_addr[CySCHR2] = STOP_CHAR(info->tty); + base_addr[CySCHR2] = STOP_CHAR(info->tty); if (base_addr[CySCRL] != START_CHAR(info->tty)) - base_addr[CySCRL] = START_CHAR(info->tty); + base_addr[CySCRL] = START_CHAR(info->tty); if (base_addr[CySCRH] != START_CHAR(info->tty)) - base_addr[CySCRH] = START_CHAR(info->tty); + base_addr[CySCRH] = START_CHAR(info->tty); if (base_addr[CyCOR1] != info->cor1) - base_addr[CyCOR1] = info->cor1; + base_addr[CyCOR1] = info->cor1; if (base_addr[CyCOR2] != info->cor2) - base_addr[CyCOR2] = info->cor2; + base_addr[CyCOR2] = info->cor2; if (base_addr[CyCOR3] != info->cor3) - base_addr[CyCOR3] = info->cor3; + base_addr[CyCOR3] = info->cor3; if (base_addr[CyCOR4] != info->cor4) - base_addr[CyCOR4] = info->cor4; + base_addr[CyCOR4] = info->cor4; if (base_addr[CyCOR5] != info->cor5) - base_addr[CyCOR5] = info->cor5; + base_addr[CyCOR5] = info->cor5; if (base_addr[CyCOR6] != info->cor6) - base_addr[CyCOR6] = info->cor6; + base_addr[CyCOR6] = info->cor6; if (base_addr[CyCOR7] != info->cor7) - base_addr[CyCOR7] = info->cor7; + base_addr[CyCOR7] = info->cor7; if (need_init_chan) - write_cy_cmd(base_addr,CyINIT_CHAN); + write_cy_cmd(base_addr, CyINIT_CHAN); - base_addr[CyCAR] = (u_char)channel; /* !!! Is this needed? */ + base_addr[CyCAR] = (u_char) channel; /* !!! Is this needed? */ /* 2ms default rx timeout */ ti = info->default_timeout ? info->default_timeout : 0x02; if (base_addr[CyRTPRL] != ti) - base_addr[CyRTPRL] = ti; + base_addr[CyRTPRL] = ti; if (base_addr[CyRTPRH] != 0) - base_addr[CyRTPRH] = 0; + base_addr[CyRTPRH] = 0; /* Set up RTS here also ????? RGH 141095 */ - if(i == 0){ /* baud rate is zero, turn off line */ - if ((base_addr[CyMSVR2] & CyDTR) == CyDTR) - base_addr[CyMSVR2] = 0; + if (i == 0) { /* baud rate is zero, turn off line */ + if ((base_addr[CyMSVR2] & CyDTR) == CyDTR) + base_addr[CyMSVR2] = 0; #ifdef SERIAL_DEBUG_DTR - printk("cyc: %d: dropping DTR\n", __LINE__); - printk(" status: 0x%x, 0x%x\n", base_addr[CyMSVR1], base_addr[CyMSVR2]); + printk("cyc: %d: dropping DTR\n", __LINE__); + printk(" status: 0x%x, 0x%x\n", base_addr[CyMSVR1], + base_addr[CyMSVR2]); #endif - }else{ - if ((base_addr[CyMSVR2] & CyDTR) != CyDTR) - base_addr[CyMSVR2] = CyDTR; + } else { + if ((base_addr[CyMSVR2] & CyDTR) != CyDTR) + base_addr[CyMSVR2] = CyDTR; #ifdef SERIAL_DEBUG_DTR - printk("cyc: %d: raising DTR\n", __LINE__); - printk(" status: 0x%x, 0x%x\n", base_addr[CyMSVR1], base_addr[CyMSVR2]); + printk("cyc: %d: raising DTR\n", __LINE__); + printk(" status: 0x%x, 0x%x\n", base_addr[CyMSVR1], + base_addr[CyMSVR2]); #endif } - if (info->tty){ - clear_bit(TTY_IO_ERROR, &info->tty->flags); + if (info->tty) { + clear_bit(TTY_IO_ERROR, &info->tty->flags); } - local_irq_restore(flags); - -} /* config_setup */ + local_irq_restore(flags); +} /* config_setup */ -static void -cy_put_char(struct tty_struct *tty, unsigned char ch) +static void cy_put_char(struct tty_struct *tty, unsigned char ch) { - struct cyclades_port *info = (struct cyclades_port *)tty->driver_data; - unsigned long flags; + struct cyclades_port *info = (struct cyclades_port *)tty->driver_data; + unsigned long flags; #ifdef SERIAL_DEBUG_IO - printk("cy_put_char %s(0x%02x)\n", tty->name, ch); + printk("cy_put_char %s(0x%02x)\n", tty->name, ch); #endif - if (serial_paranoia_check(info, tty->name, "cy_put_char")) - return; + if (serial_paranoia_check(info, tty->name, "cy_put_char")) + return; - if (!info->xmit_buf) - return; + if (!info->xmit_buf) + return; - local_irq_save(flags); + local_irq_save(flags); if (info->xmit_cnt >= PAGE_SIZE - 1) { - local_irq_restore(flags); - return; + local_irq_restore(flags); + return; } info->xmit_buf[info->xmit_head++] = ch; info->xmit_head &= PAGE_SIZE - 1; info->xmit_cnt++; - local_irq_restore(flags); -} /* cy_put_char */ - + local_irq_restore(flags); +} /* cy_put_char */ -static void -cy_flush_chars(struct tty_struct *tty) +static void cy_flush_chars(struct tty_struct *tty) { - struct cyclades_port *info = (struct cyclades_port *)tty->driver_data; - unsigned long flags; - volatile unsigned char *base_addr = (u_char *)BASE_ADDR; - int channel; - + struct cyclades_port *info = (struct cyclades_port *)tty->driver_data; + unsigned long flags; + volatile unsigned char *base_addr = (u_char *) BASE_ADDR; + int channel; + #ifdef SERIAL_DEBUG_IO - printk("cy_flush_chars %s\n", tty->name); /* */ + printk("cy_flush_chars %s\n", tty->name); /* */ #endif - if (serial_paranoia_check(info, tty->name, "cy_flush_chars")) - return; + if (serial_paranoia_check(info, tty->name, "cy_flush_chars")) + return; - if (info->xmit_cnt <= 0 || tty->stopped - || tty->hw_stopped || !info->xmit_buf) - return; + if (info->xmit_cnt <= 0 || tty->stopped + || tty->hw_stopped || !info->xmit_buf) + return; - channel = info->line; + channel = info->line; - local_irq_save(flags); + local_irq_save(flags); base_addr[CyCAR] = channel; base_addr[CyIER] |= CyTxMpty; - local_irq_restore(flags); -} /* cy_flush_chars */ - + local_irq_restore(flags); +} /* cy_flush_chars */ /* This routine gets called when tty_write has put something into the write_queue. If the port is not already transmitting stuff, @@ -1175,650 +1178,616 @@ #endif routine will then ensure that the characters are sent. If the port is already active, there is no need to kick it. */ -static int -cy_write(struct tty_struct * tty, - const unsigned char *buf, int count) +static int cy_write(struct tty_struct *tty, const unsigned char *buf, int count) { - struct cyclades_port *info = (struct cyclades_port *)tty->driver_data; - unsigned long flags; - int c, total = 0; + struct cyclades_port *info = (struct cyclades_port *)tty->driver_data; + unsigned long flags; + int c, total = 0; #ifdef SERIAL_DEBUG_IO - printk("cy_write %s\n", tty->name); /* */ + printk("cy_write %s\n", tty->name); /* */ #endif - if (serial_paranoia_check(info, tty->name, "cy_write")){ - return 0; - } - - if (!info->xmit_buf){ - return 0; - } - - while (1) { - local_irq_save(flags); - c = min_t(int, count, min(SERIAL_XMIT_SIZE - info->xmit_cnt - 1, - SERIAL_XMIT_SIZE - info->xmit_head)); - if (c <= 0) { - local_irq_restore(flags); - break; - } - - memcpy(info->xmit_buf + info->xmit_head, buf, c); - info->xmit_head = (info->xmit_head + c) & (SERIAL_XMIT_SIZE-1); - info->xmit_cnt += c; - local_irq_restore(flags); - - buf += c; - count -= c; - total += c; - } - - if (info->xmit_cnt - && !tty->stopped - && !tty->hw_stopped ) { - start_xmit(info); - } - return total; -} /* cy_write */ + if (serial_paranoia_check(info, tty->name, "cy_write")) { + return 0; + } + if (!info->xmit_buf) { + return 0; + } -static int -cy_write_room(struct tty_struct *tty) + while (1) { + local_irq_save(flags); + c = min_t(int, count, min(SERIAL_XMIT_SIZE - info->xmit_cnt - 1, + SERIAL_XMIT_SIZE - info->xmit_head)); + if (c <= 0) { + local_irq_restore(flags); + break; + } + + memcpy(info->xmit_buf + info->xmit_head, buf, c); + info->xmit_head = + (info->xmit_head + c) & (SERIAL_XMIT_SIZE - 1); + info->xmit_cnt += c; + local_irq_restore(flags); + + buf += c; + count -= c; + total += c; + } + + if (info->xmit_cnt && !tty->stopped && !tty->hw_stopped) { + start_xmit(info); + } + return total; +} /* cy_write */ + +static int cy_write_room(struct tty_struct *tty) { - struct cyclades_port *info = (struct cyclades_port *)tty->driver_data; - int ret; - + struct cyclades_port *info = (struct cyclades_port *)tty->driver_data; + int ret; + #ifdef SERIAL_DEBUG_IO - printk("cy_write_room %s\n", tty->name); /* */ + printk("cy_write_room %s\n", tty->name); /* */ #endif - if (serial_paranoia_check(info, tty->name, "cy_write_room")) - return 0; - ret = PAGE_SIZE - info->xmit_cnt - 1; - if (ret < 0) - ret = 0; - return ret; -} /* cy_write_room */ - + if (serial_paranoia_check(info, tty->name, "cy_write_room")) + return 0; + ret = PAGE_SIZE - info->xmit_cnt - 1; + if (ret < 0) + ret = 0; + return ret; +} /* cy_write_room */ -static int -cy_chars_in_buffer(struct tty_struct *tty) +static int cy_chars_in_buffer(struct tty_struct *tty) { - struct cyclades_port *info = (struct cyclades_port *)tty->driver_data; - + struct cyclades_port *info = (struct cyclades_port *)tty->driver_data; + #ifdef SERIAL_DEBUG_IO - printk("cy_chars_in_buffer %s %d\n", tty->name, info->xmit_cnt); /* */ + printk("cy_chars_in_buffer %s %d\n", tty->name, info->xmit_cnt); /* */ #endif - if (serial_paranoia_check(info, tty->name, "cy_chars_in_buffer")) - return 0; - - return info->xmit_cnt; -} /* cy_chars_in_buffer */ + if (serial_paranoia_check(info, tty->name, "cy_chars_in_buffer")) + return 0; + return info->xmit_cnt; +} /* cy_chars_in_buffer */ -static void -cy_flush_buffer(struct tty_struct *tty) +static void cy_flush_buffer(struct tty_struct *tty) { - struct cyclades_port *info = (struct cyclades_port *)tty->driver_data; - unsigned long flags; - + struct cyclades_port *info = (struct cyclades_port *)tty->driver_data; + unsigned long flags; + #ifdef SERIAL_DEBUG_IO - printk("cy_flush_buffer %s\n", tty->name); /* */ + printk("cy_flush_buffer %s\n", tty->name); /* */ #endif - if (serial_paranoia_check(info, tty->name, "cy_flush_buffer")) - return; - local_irq_save(flags); + if (serial_paranoia_check(info, tty->name, "cy_flush_buffer")) + return; + local_irq_save(flags); info->xmit_cnt = info->xmit_head = info->xmit_tail = 0; - local_irq_restore(flags); - tty_wakeup(tty); -} /* cy_flush_buffer */ - + local_irq_restore(flags); + tty_wakeup(tty); +} /* cy_flush_buffer */ /* This routine is called by the upper-layer tty layer to signal that incoming characters should be throttled or that the throttle should be released. */ -static void -cy_throttle(struct tty_struct * tty) +static void cy_throttle(struct tty_struct *tty) { - struct cyclades_port *info = (struct cyclades_port *)tty->driver_data; - unsigned long flags; - volatile unsigned char *base_addr = (u_char *)BASE_ADDR; - int channel; + struct cyclades_port *info = (struct cyclades_port *)tty->driver_data; + unsigned long flags; + volatile unsigned char *base_addr = (u_char *) BASE_ADDR; + int channel; #ifdef SERIAL_DEBUG_THROTTLE - char buf[64]; - - printk("throttle %s: %d....\n", tty_name(tty, buf), - tty->ldisc.chars_in_buffer(tty)); - printk("cy_throttle %s\n", tty->name); + char buf[64]; + + printk("throttle %s: %d....\n", tty_name(tty, buf), + tty->ldisc.chars_in_buffer(tty)); + printk("cy_throttle %s\n", tty->name); #endif - if (serial_paranoia_check(info, tty->name, "cy_nthrottle")){ - return; - } + if (serial_paranoia_check(info, tty->name, "cy_nthrottle")) { + return; + } - if (I_IXOFF(tty)) { - info->x_char = STOP_CHAR(tty); - /* Should use the "Send Special Character" feature!!! */ - } + if (I_IXOFF(tty)) { + info->x_char = STOP_CHAR(tty); + /* Should use the "Send Special Character" feature!!! */ + } - channel = info->line; + channel = info->line; - local_irq_save(flags); - base_addr[CyCAR] = (u_char)channel; + local_irq_save(flags); + base_addr[CyCAR] = (u_char) channel; base_addr[CyMSVR1] = 0; - local_irq_restore(flags); - - return; -} /* cy_throttle */ - + local_irq_restore(flags); +} /* cy_throttle */ -static void -cy_unthrottle(struct tty_struct * tty) +static void cy_unthrottle(struct tty_struct *tty) { - struct cyclades_port *info = (struct cyclades_port *)tty->driver_data; - unsigned long flags; - volatile unsigned char *base_addr = (u_char *)BASE_ADDR; - int channel; + struct cyclades_port *info = (struct cyclades_port *)tty->driver_data; + unsigned long flags; + volatile unsigned char *base_addr = (u_char *) BASE_ADDR; + int channel; #ifdef SERIAL_DEBUG_THROTTLE - char buf[64]; - - printk("throttle %s: %d....\n", tty_name(tty, buf), - tty->ldisc.chars_in_buffer(tty)); - printk("cy_unthrottle %s\n", tty->name); + char buf[64]; + + printk("throttle %s: %d....\n", tty_name(tty, buf), + tty->ldisc.chars_in_buffer(tty)); + printk("cy_unthrottle %s\n", tty->name); #endif - if (serial_paranoia_check(info, tty->name, "cy_nthrottle")){ - return; - } + if (serial_paranoia_check(info, tty->name, "cy_nthrottle")) { + return; + } - if (I_IXOFF(tty)) { - info->x_char = START_CHAR(tty); - /* Should use the "Send Special Character" feature!!! */ - } + if (I_IXOFF(tty)) { + info->x_char = START_CHAR(tty); + /* Should use the "Send Special Character" feature!!! */ + } - channel = info->line; + channel = info->line; - local_irq_save(flags); - base_addr[CyCAR] = (u_char)channel; + local_irq_save(flags); + base_addr[CyCAR] = (u_char) channel; base_addr[CyMSVR1] = CyRTS; - local_irq_restore(flags); - - return; -} /* cy_unthrottle */ + local_irq_restore(flags); +} /* cy_unthrottle */ static int -get_serial_info(struct cyclades_port * info, - struct serial_struct __user * retinfo) +get_serial_info(struct cyclades_port *info, + struct serial_struct __user * retinfo) { - struct serial_struct tmp; + struct serial_struct tmp; /* CP('g'); */ - if (!retinfo) - return -EFAULT; - memset(&tmp, 0, sizeof(tmp)); - tmp.type = info->type; - tmp.line = info->line; - tmp.port = info->line; - tmp.irq = 0; - tmp.flags = info->flags; - tmp.baud_base = 0; /*!!!*/ - tmp.close_delay = info->close_delay; - tmp.custom_divisor = 0; /*!!!*/ - tmp.hub6 = 0; /*!!!*/ - return copy_to_user(retinfo,&tmp,sizeof(*retinfo)) ? -EFAULT : 0; -} /* get_serial_info */ + if (!retinfo) + return -EFAULT; + memset(&tmp, 0, sizeof(tmp)); + tmp.type = info->type; + tmp.line = info->line; + tmp.port = info->line; + tmp.irq = 0; + tmp.flags = info->flags; + tmp.baud_base = 0; /*!!! */ + tmp.close_delay = info->close_delay; + tmp.custom_divisor = 0; /*!!! */ + tmp.hub6 = 0; /*!!! */ + return copy_to_user(retinfo, &tmp, sizeof(*retinfo)) ? -EFAULT : 0; +} /* get_serial_info */ static int -set_serial_info(struct cyclades_port * info, - struct serial_struct __user * new_info) +set_serial_info(struct cyclades_port *info, + struct serial_struct __user * new_info) { - struct serial_struct new_serial; - struct cyclades_port old_info; + struct serial_struct new_serial; + struct cyclades_port old_info; /* CP('s'); */ - if (!new_info) - return -EFAULT; - if (copy_from_user(&new_serial,new_info,sizeof(new_serial))) - return -EFAULT; - old_info = *info; + if (!new_info) + return -EFAULT; + if (copy_from_user(&new_serial, new_info, sizeof(new_serial))) + return -EFAULT; + old_info = *info; + + if (!capable(CAP_SYS_ADMIN)) { + if ((new_serial.close_delay != info->close_delay) || + ((new_serial.flags & ASYNC_FLAGS & ~ASYNC_USR_MASK) != + (info->flags & ASYNC_FLAGS & ~ASYNC_USR_MASK))) + return -EPERM; + info->flags = ((info->flags & ~ASYNC_USR_MASK) | + (new_serial.flags & ASYNC_USR_MASK)); + goto check_and_exit; + } - if (!capable(CAP_SYS_ADMIN)) { - if ((new_serial.close_delay != info->close_delay) || - ((new_serial.flags & ASYNC_FLAGS & ~ASYNC_USR_MASK) != - (info->flags & ASYNC_FLAGS & ~ASYNC_USR_MASK))) - return -EPERM; - info->flags = ((info->flags & ~ASYNC_USR_MASK) | - (new_serial.flags & ASYNC_USR_MASK)); - goto check_and_exit; - } + /* + * OK, past this point, all the error checking has been done. + * At this point, we start making changes..... + */ + info->flags = ((info->flags & ~ASYNC_FLAGS) | + (new_serial.flags & ASYNC_FLAGS)); + info->close_delay = new_serial.close_delay; - /* - * OK, past this point, all the error checking has been done. - * At this point, we start making changes..... - */ +check_and_exit: + if (info->flags & ASYNC_INITIALIZED) { + config_setup(info); + return 0; + } + return startup(info); +} /* set_serial_info */ - info->flags = ((info->flags & ~ASYNC_FLAGS) | - (new_serial.flags & ASYNC_FLAGS)); - info->close_delay = new_serial.close_delay; +static int cy_tiocmget(struct tty_struct *tty, struct file *file) +{ + struct cyclades_port *info = (struct cyclades_port *)tty->driver_data; + int channel; + volatile unsigned char *base_addr = (u_char *) BASE_ADDR; + unsigned long flags; + unsigned char status; + channel = info->line; -check_and_exit: - if (info->flags & ASYNC_INITIALIZED){ - config_setup(info); - return 0; - }else{ - return startup(info); - } -} /* set_serial_info */ + local_irq_save(flags); + base_addr[CyCAR] = (u_char) channel; + status = base_addr[CyMSVR1] | base_addr[CyMSVR2]; + local_irq_restore(flags); -static int -cy_tiocmget(struct tty_struct *tty, struct file *file) -{ - struct cyclades_port * info = (struct cyclades_port *)tty->driver_data; - int channel; - volatile unsigned char *base_addr = (u_char *)BASE_ADDR; - unsigned long flags; - unsigned char status; - - channel = info->line; - - local_irq_save(flags); - base_addr[CyCAR] = (u_char)channel; - status = base_addr[CyMSVR1] | base_addr[CyMSVR2]; - local_irq_restore(flags); - - return ((status & CyRTS) ? TIOCM_RTS : 0) - | ((status & CyDTR) ? TIOCM_DTR : 0) - | ((status & CyDCD) ? TIOCM_CAR : 0) - | ((status & CyDSR) ? TIOCM_DSR : 0) - | ((status & CyCTS) ? TIOCM_CTS : 0); -} /* cy_tiocmget */ + return ((status & CyRTS) ? TIOCM_RTS : 0) + | ((status & CyDTR) ? TIOCM_DTR : 0) + | ((status & CyDCD) ? TIOCM_CAR : 0) + | ((status & CyDSR) ? TIOCM_DSR : 0) + | ((status & CyCTS) ? TIOCM_CTS : 0); +} /* cy_tiocmget */ static int cy_tiocmset(struct tty_struct *tty, struct file *file, unsigned int set, unsigned int clear) { - struct cyclades_port * info = (struct cyclades_port *)tty->driver_data; - int channel; - volatile unsigned char *base_addr = (u_char *)BASE_ADDR; - unsigned long flags; - - channel = info->line; - - if (set & TIOCM_RTS){ - local_irq_save(flags); - base_addr[CyCAR] = (u_char)channel; + struct cyclades_port *info = (struct cyclades_port *)tty->driver_data; + int channel; + volatile unsigned char *base_addr = (u_char *) BASE_ADDR; + unsigned long flags; + + channel = info->line; + + if (set & TIOCM_RTS) { + local_irq_save(flags); + base_addr[CyCAR] = (u_char) channel; base_addr[CyMSVR1] = CyRTS; - local_irq_restore(flags); + local_irq_restore(flags); } - if (set & TIOCM_DTR){ - local_irq_save(flags); - base_addr[CyCAR] = (u_char)channel; + if (set & TIOCM_DTR) { + local_irq_save(flags); + base_addr[CyCAR] = (u_char) channel; /* CP('S');CP('2'); */ - base_addr[CyMSVR2] = CyDTR; + base_addr[CyMSVR2] = CyDTR; #ifdef SERIAL_DEBUG_DTR - printk("cyc: %d: raising DTR\n", __LINE__); - printk(" status: 0x%x, 0x%x\n", base_addr[CyMSVR1], base_addr[CyMSVR2]); + printk("cyc: %d: raising DTR\n", __LINE__); + printk(" status: 0x%x, 0x%x\n", base_addr[CyMSVR1], + base_addr[CyMSVR2]); #endif - local_irq_restore(flags); + local_irq_restore(flags); } - if (clear & TIOCM_RTS){ - local_irq_save(flags); - base_addr[CyCAR] = (u_char)channel; + if (clear & TIOCM_RTS) { + local_irq_save(flags); + base_addr[CyCAR] = (u_char) channel; base_addr[CyMSVR1] = 0; - local_irq_restore(flags); + local_irq_restore(flags); } - if (clear & TIOCM_DTR){ - local_irq_save(flags); - base_addr[CyCAR] = (u_char)channel; + if (clear & TIOCM_DTR) { + local_irq_save(flags); + base_addr[CyCAR] = (u_char) channel; /* CP('C');CP('2'); */ - base_addr[CyMSVR2] = 0; + base_addr[CyMSVR2] = 0; #ifdef SERIAL_DEBUG_DTR - printk("cyc: %d: dropping DTR\n", __LINE__); - printk(" status: 0x%x, 0x%x\n", base_addr[CyMSVR1], base_addr[CyMSVR2]); + printk("cyc: %d: dropping DTR\n", __LINE__); + printk(" status: 0x%x, 0x%x\n", base_addr[CyMSVR1], + base_addr[CyMSVR2]); #endif - local_irq_restore(flags); + local_irq_restore(flags); } - return 0; -} /* set_modem_info */ - -static void -send_break( struct cyclades_port * info, int duration) -{ /* Let the transmit ISR take care of this (since it - requires stuffing characters into the output stream). - */ - info->x_break = duration; - if (!info->xmit_cnt ) { - start_xmit(info); - } -} /* send_break */ + return 0; +} /* set_modem_info */ + +static void send_break(struct cyclades_port *info, int duration) +{ /* Let the transmit ISR take care of this (since it + requires stuffing characters into the output stream). + */ + info->x_break = duration; + if (!info->xmit_cnt) { + start_xmit(info); + } +} /* send_break */ static int -get_mon_info(struct cyclades_port * info, struct cyclades_monitor __user * mon) +get_mon_info(struct cyclades_port *info, struct cyclades_monitor __user * mon) { - if (copy_to_user(mon, &info->mon, sizeof(struct cyclades_monitor))) - return -EFAULT; - info->mon.int_count = 0; - info->mon.char_count = 0; - info->mon.char_max = 0; - info->mon.char_last = 0; - return 0; + if (copy_to_user(mon, &info->mon, sizeof(struct cyclades_monitor))) + return -EFAULT; + info->mon.int_count = 0; + info->mon.char_count = 0; + info->mon.char_max = 0; + info->mon.char_last = 0; + return 0; } -static int -set_threshold(struct cyclades_port * info, unsigned long __user *arg) +static int set_threshold(struct cyclades_port *info, unsigned long __user * arg) { - volatile unsigned char *base_addr = (u_char *)BASE_ADDR; - unsigned long value; - int channel; - - if (get_user(value, arg)) - return -EFAULT; - - channel = info->line; - info->cor4 &= ~CyREC_FIFO; - info->cor4 |= value & CyREC_FIFO; - base_addr[CyCOR4] = info->cor4; - return 0; + volatile unsigned char *base_addr = (u_char *) BASE_ADDR; + unsigned long value; + int channel; + + if (get_user(value, arg)) + return -EFAULT; + + channel = info->line; + info->cor4 &= ~CyREC_FIFO; + info->cor4 |= value & CyREC_FIFO; + base_addr[CyCOR4] = info->cor4; + return 0; } static int -get_threshold(struct cyclades_port * info, unsigned long __user *value) +get_threshold(struct cyclades_port *info, unsigned long __user * value) { - volatile unsigned char *base_addr = (u_char *)BASE_ADDR; - int channel; - unsigned long tmp; - - channel = info->line; - - tmp = base_addr[CyCOR4] & CyREC_FIFO; - return put_user(tmp,value); + volatile unsigned char *base_addr = (u_char *) BASE_ADDR; + int channel; + unsigned long tmp; + + channel = info->line; + + tmp = base_addr[CyCOR4] & CyREC_FIFO; + return put_user(tmp, value); } static int -set_default_threshold(struct cyclades_port * info, unsigned long __user *arg) +set_default_threshold(struct cyclades_port *info, unsigned long __user * arg) { - unsigned long value; + unsigned long value; - if (get_user(value, arg)) - return -EFAULT; + if (get_user(value, arg)) + return -EFAULT; - info->default_threshold = value & 0x0f; - return 0; + info->default_threshold = value & 0x0f; + return 0; } static int -get_default_threshold(struct cyclades_port * info, unsigned long __user *value) +get_default_threshold(struct cyclades_port *info, unsigned long __user * value) { - return put_user(info->default_threshold,value); + return put_user(info->default_threshold, value); } -static int -set_timeout(struct cyclades_port * info, unsigned long __user *arg) +static int set_timeout(struct cyclades_port *info, unsigned long __user * arg) { - volatile unsigned char *base_addr = (u_char *)BASE_ADDR; - int channel; - unsigned long value; - - if (get_user(value, arg)) - return -EFAULT; - - channel = info->line; - - base_addr[CyRTPRL] = value & 0xff; - base_addr[CyRTPRH] = (value >> 8) & 0xff; - return 0; + volatile unsigned char *base_addr = (u_char *) BASE_ADDR; + int channel; + unsigned long value; + + if (get_user(value, arg)) + return -EFAULT; + + channel = info->line; + + base_addr[CyRTPRL] = value & 0xff; + base_addr[CyRTPRH] = (value >> 8) & 0xff; + return 0; } -static int -get_timeout(struct cyclades_port * info, unsigned long __user *value) +static int get_timeout(struct cyclades_port *info, unsigned long __user * value) { - volatile unsigned char *base_addr = (u_char *)BASE_ADDR; - int channel; - unsigned long tmp; - - channel = info->line; - - tmp = base_addr[CyRTPRL]; - return put_user(tmp,value); + volatile unsigned char *base_addr = (u_char *) BASE_ADDR; + int channel; + unsigned long tmp; + + channel = info->line; + + tmp = base_addr[CyRTPRL]; + return put_user(tmp, value); } -static int -set_default_timeout(struct cyclades_port * info, unsigned long value) +static int set_default_timeout(struct cyclades_port *info, unsigned long value) { - info->default_timeout = value & 0xff; - return 0; + info->default_timeout = value & 0xff; + return 0; } static int -get_default_timeout(struct cyclades_port * info, unsigned long __user *value) +get_default_timeout(struct cyclades_port *info, unsigned long __user * value) { - return put_user(info->default_timeout,value); + return put_user(info->default_timeout, value); } static int -cy_ioctl(struct tty_struct *tty, struct file * file, - unsigned int cmd, unsigned long arg) +cy_ioctl(struct tty_struct *tty, struct file *file, + unsigned int cmd, unsigned long arg) { - unsigned long val; - struct cyclades_port * info = (struct cyclades_port *)tty->driver_data; - int ret_val = 0; - void __user *argp = (void __user *)arg; + unsigned long val; + struct cyclades_port *info = (struct cyclades_port *)tty->driver_data; + int ret_val = 0; + void __user *argp = (void __user *)arg; #ifdef SERIAL_DEBUG_OTHER - printk("cy_ioctl %s, cmd = %x arg = %lx\n", tty->name, cmd, arg); /* */ -#endif - - switch (cmd) { - case CYGETMON: - ret_val = get_mon_info(info, argp); - break; - case CYGETTHRESH: - ret_val = get_threshold(info, argp); - break; - case CYSETTHRESH: - ret_val = set_threshold(info, argp); - break; - case CYGETDEFTHRESH: - ret_val = get_default_threshold(info, argp); - break; - case CYSETDEFTHRESH: - ret_val = set_default_threshold(info, argp); - break; - case CYGETTIMEOUT: - ret_val = get_timeout(info, argp); - break; - case CYSETTIMEOUT: - ret_val = set_timeout(info, argp); - break; - case CYGETDEFTIMEOUT: - ret_val = get_default_timeout(info, argp); - break; - case CYSETDEFTIMEOUT: - ret_val = set_default_timeout(info, (unsigned long)arg); - break; - case TCSBRK: /* SVID version: non-zero arg --> no break */ - ret_val = tty_check_change(tty); - if (ret_val) - break; - tty_wait_until_sent(tty,0); - if (!arg) - send_break(info, HZ/4); /* 1/4 second */ - break; - case TCSBRKP: /* support for POSIX tcsendbreak() */ - ret_val = tty_check_change(tty); - if (ret_val) + printk("cy_ioctl %s, cmd = %x arg = %lx\n", tty->name, cmd, arg); /* */ +#endif + + switch (cmd) { + case CYGETMON: + ret_val = get_mon_info(info, argp); + break; + case CYGETTHRESH: + ret_val = get_threshold(info, argp); + break; + case CYSETTHRESH: + ret_val = set_threshold(info, argp); + break; + case CYGETDEFTHRESH: + ret_val = get_default_threshold(info, argp); + break; + case CYSETDEFTHRESH: + ret_val = set_default_threshold(info, argp); + break; + case CYGETTIMEOUT: + ret_val = get_timeout(info, argp); + break; + case CYSETTIMEOUT: + ret_val = set_timeout(info, argp); + break; + case CYGETDEFTIMEOUT: + ret_val = get_default_timeout(info, argp); + break; + case CYSETDEFTIMEOUT: + ret_val = set_default_timeout(info, (unsigned long)arg); + break; + case TCSBRK: /* SVID version: non-zero arg --> no break */ + ret_val = tty_check_change(tty); + if (ret_val) + break; + tty_wait_until_sent(tty, 0); + if (!arg) + send_break(info, HZ / 4); /* 1/4 second */ + break; + case TCSBRKP: /* support for POSIX tcsendbreak() */ + ret_val = tty_check_change(tty); + if (ret_val) + break; + tty_wait_until_sent(tty, 0); + send_break(info, arg ? arg * (HZ / 10) : HZ / 4); break; - tty_wait_until_sent(tty,0); - send_break(info, arg ? arg*(HZ/10) : HZ/4); - break; /* The following commands are incompletely implemented!!! */ - case TIOCGSOFTCAR: - ret_val = put_user(C_CLOCAL(tty) ? 1 : 0, (unsigned long __user *) argp); - break; - case TIOCSSOFTCAR: - ret_val = get_user(val, (unsigned long __user *) argp); - if (ret_val) - break; - tty->termios->c_cflag = - ((tty->termios->c_cflag & ~CLOCAL) | (val ? CLOCAL : 0)); - break; - case TIOCGSERIAL: - ret_val = get_serial_info(info, argp); - break; - case TIOCSSERIAL: - ret_val = set_serial_info(info, argp); - break; - default: - ret_val = -ENOIOCTLCMD; - } + case TIOCGSOFTCAR: + ret_val = + put_user(C_CLOCAL(tty) ? 1 : 0, + (unsigned long __user *)argp); + break; + case TIOCSSOFTCAR: + ret_val = get_user(val, (unsigned long __user *)argp); + if (ret_val) + break; + tty->termios->c_cflag = + ((tty->termios->c_cflag & ~CLOCAL) | (val ? CLOCAL : 0)); + break; + case TIOCGSERIAL: + ret_val = get_serial_info(info, argp); + break; + case TIOCSSERIAL: + ret_val = set_serial_info(info, argp); + break; + default: + ret_val = -ENOIOCTLCMD; + } #ifdef SERIAL_DEBUG_OTHER - printk("cy_ioctl done\n"); + printk("cy_ioctl done\n"); #endif - return ret_val; -} /* cy_ioctl */ - + return ret_val; +} /* cy_ioctl */ - - -static void -cy_set_termios(struct tty_struct *tty, struct ktermios * old_termios) +static void cy_set_termios(struct tty_struct *tty, struct ktermios *old_termios) { - struct cyclades_port *info = (struct cyclades_port *)tty->driver_data; + struct cyclades_port *info = (struct cyclades_port *)tty->driver_data; #ifdef SERIAL_DEBUG_OTHER - printk("cy_set_termios %s\n", tty->name); + printk("cy_set_termios %s\n", tty->name); #endif - if (tty->termios->c_cflag == old_termios->c_cflag) - return; - config_setup(info); + if (tty->termios->c_cflag == old_termios->c_cflag) + return; + config_setup(info); - if ((old_termios->c_cflag & CRTSCTS) && - !(tty->termios->c_cflag & CRTSCTS)) { - tty->stopped = 0; - cy_start(tty); - } + if ((old_termios->c_cflag & CRTSCTS) && + !(tty->termios->c_cflag & CRTSCTS)) { + tty->stopped = 0; + cy_start(tty); + } #ifdef tytso_patch_94Nov25_1726 - if (!(old_termios->c_cflag & CLOCAL) && - (tty->termios->c_cflag & CLOCAL)) - wake_up_interruptible(&info->open_wait); + if (!(old_termios->c_cflag & CLOCAL) && + (tty->termios->c_cflag & CLOCAL)) + wake_up_interruptible(&info->open_wait); #endif +} /* cy_set_termios */ - return; -} /* cy_set_termios */ - - -static void -cy_close(struct tty_struct * tty, struct file * filp) +static void cy_close(struct tty_struct *tty, struct file *filp) { - struct cyclades_port * info = (struct cyclades_port *)tty->driver_data; + struct cyclades_port *info = (struct cyclades_port *)tty->driver_data; /* CP('C'); */ #ifdef SERIAL_DEBUG_OTHER - printk("cy_close %s\n", tty->name); + printk("cy_close %s\n", tty->name); #endif - if (!info - || serial_paranoia_check(info, tty->name, "cy_close")){ - return; - } + if (!info || serial_paranoia_check(info, tty->name, "cy_close")) { + return; + } #ifdef SERIAL_DEBUG_OPEN - printk("cy_close %s, count = %d\n", tty->name, info->count); -#endif - - if ((tty->count == 1) && (info->count != 1)) { - /* - * Uh, oh. tty->count is 1, which means that the tty - * structure will be freed. Info->count should always - * be one in these conditions. If it's greater than - * one, we've got real problems, since it means the - * serial port won't be shutdown. - */ - printk("cy_close: bad serial port count; tty->count is 1, " - "info->count is %d\n", info->count); - info->count = 1; - } + printk("cy_close %s, count = %d\n", tty->name, info->count); +#endif + + if ((tty->count == 1) && (info->count != 1)) { + /* + * Uh, oh. tty->count is 1, which means that the tty + * structure will be freed. Info->count should always + * be one in these conditions. If it's greater than + * one, we've got real problems, since it means the + * serial port won't be shutdown. + */ + printk("cy_close: bad serial port count; tty->count is 1, " + "info->count is %d\n", info->count); + info->count = 1; + } #ifdef SERIAL_DEBUG_COUNT - printk("cyc: %d: decrementing count to %d\n", __LINE__, info->count - 1); + printk("cyc: %d: decrementing count to %d\n", __LINE__, + info->count - 1); #endif - if (--info->count < 0) { - printk("cy_close: bad serial port count for ttys%d: %d\n", - info->line, info->count); + if (--info->count < 0) { + printk("cy_close: bad serial port count for ttys%d: %d\n", + info->line, info->count); #ifdef SERIAL_DEBUG_COUNT - printk("cyc: %d: setting count to 0\n", __LINE__); + printk("cyc: %d: setting count to 0\n", __LINE__); #endif - info->count = 0; - } - if (info->count) - return; - info->flags |= ASYNC_CLOSING; - if (info->flags & ASYNC_INITIALIZED) - tty_wait_until_sent(tty, 3000); /* 30 seconds timeout */ - shutdown(info); - if (tty->driver->flush_buffer) - tty->driver->flush_buffer(tty); - tty_ldisc_flush(tty); - info->event = 0; - info->tty = NULL; - if (info->blocked_open) { - if (info->close_delay) { - msleep_interruptible(jiffies_to_msecs(info->close_delay)); + info->count = 0; } - wake_up_interruptible(&info->open_wait); - } - info->flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CLOSING); - wake_up_interruptible(&info->close_wait); + if (info->count) + return; + info->flags |= ASYNC_CLOSING; + if (info->flags & ASYNC_INITIALIZED) + tty_wait_until_sent(tty, 3000); /* 30 seconds timeout */ + shutdown(info); + if (tty->driver->flush_buffer) + tty->driver->flush_buffer(tty); + tty_ldisc_flush(tty); + info->event = 0; + info->tty = NULL; + if (info->blocked_open) { + if (info->close_delay) { + msleep_interruptible(jiffies_to_msecs + (info->close_delay)); + } + wake_up_interruptible(&info->open_wait); + } + info->flags &= ~(ASYNC_NORMAL_ACTIVE | ASYNC_CLOSING); + wake_up_interruptible(&info->close_wait); #ifdef SERIAL_DEBUG_OTHER - printk("cy_close done\n"); + printk("cy_close done\n"); #endif - - return; -} /* cy_close */ +} /* cy_close */ /* * cy_hangup() --- called by tty_hangup() when a hangup is signaled. */ -void -cy_hangup(struct tty_struct *tty) +void cy_hangup(struct tty_struct *tty) { - struct cyclades_port * info = (struct cyclades_port *)tty->driver_data; - + struct cyclades_port *info = (struct cyclades_port *)tty->driver_data; + #ifdef SERIAL_DEBUG_OTHER - printk("cy_hangup %s\n", tty->name); /* */ + printk("cy_hangup %s\n", tty->name); /* */ #endif - if (serial_paranoia_check(info, tty->name, "cy_hangup")) - return; - - shutdown(info); + if (serial_paranoia_check(info, tty->name, "cy_hangup")) + return; + + shutdown(info); #if 0 - info->event = 0; - info->count = 0; + info->event = 0; + info->count = 0; #ifdef SERIAL_DEBUG_COUNT - printk("cyc: %d: setting count to 0\n", __LINE__); + printk("cyc: %d: setting count to 0\n", __LINE__); #endif - info->tty = 0; + info->tty = 0; #endif - info->flags &= ~ASYNC_NORMAL_ACTIVE; - wake_up_interruptible(&info->open_wait); -} /* cy_hangup */ - - + info->flags &= ~ASYNC_NORMAL_ACTIVE; + wake_up_interruptible(&info->open_wait); +} /* cy_hangup */ /* * ------------------------------------------------------------ @@ -1827,177 +1796,180 @@ #endif */ static int -block_til_ready(struct tty_struct *tty, struct file * filp, - struct cyclades_port *info) +block_til_ready(struct tty_struct *tty, struct file *filp, + struct cyclades_port *info) { - DECLARE_WAITQUEUE(wait, current); - unsigned long flags; - int channel; - int retval; - volatile u_char *base_addr = (u_char *)BASE_ADDR; - - /* - * If the device is in the middle of being closed, then block - * until it's done, and then try again. - */ - if (info->flags & ASYNC_CLOSING) { - interruptible_sleep_on(&info->close_wait); - if (info->flags & ASYNC_HUP_NOTIFY){ - return -EAGAIN; - }else{ - return -ERESTARTSYS; - } - } - - /* - * If non-blocking mode is set, then make the check up front - * and then exit. - */ - if (filp->f_flags & O_NONBLOCK) { - info->flags |= ASYNC_NORMAL_ACTIVE; - return 0; - } - - /* - * Block waiting for the carrier detect and the line to become - * free (i.e., not in use by the callout). While we are in - * this loop, info->count is dropped by one, so that - * cy_close() knows when to free things. We restore it upon - * exit, either normal or abnormal. - */ - retval = 0; - add_wait_queue(&info->open_wait, &wait); + DECLARE_WAITQUEUE(wait, current); + unsigned long flags; + int channel; + int retval; + volatile u_char *base_addr = (u_char *) BASE_ADDR; + + /* + * If the device is in the middle of being closed, then block + * until it's done, and then try again. + */ + if (info->flags & ASYNC_CLOSING) { + interruptible_sleep_on(&info->close_wait); + if (info->flags & ASYNC_HUP_NOTIFY) { + return -EAGAIN; + } else { + return -ERESTARTSYS; + } + } + + /* + * If non-blocking mode is set, then make the check up front + * and then exit. + */ + if (filp->f_flags & O_NONBLOCK) { + info->flags |= ASYNC_NORMAL_ACTIVE; + return 0; + } + + /* + * Block waiting for the carrier detect and the line to become + * free (i.e., not in use by the callout). While we are in + * this loop, info->count is dropped by one, so that + * cy_close() knows when to free things. We restore it upon + * exit, either normal or abnormal. + */ + retval = 0; + add_wait_queue(&info->open_wait, &wait); #ifdef SERIAL_DEBUG_OPEN - printk("block_til_ready before block: %s, count = %d\n", - tty->name, info->count);/**/ + printk("block_til_ready before block: %s, count = %d\n", + tty->name, info->count); + /**/ #endif - info->count--; + info->count--; #ifdef SERIAL_DEBUG_COUNT - printk("cyc: %d: decrementing count to %d\n", __LINE__, info->count); + printk("cyc: %d: decrementing count to %d\n", __LINE__, info->count); #endif - info->blocked_open++; + info->blocked_open++; - channel = info->line; + channel = info->line; - while (1) { - local_irq_save(flags); - base_addr[CyCAR] = (u_char)channel; - base_addr[CyMSVR1] = CyRTS; + while (1) { + local_irq_save(flags); + base_addr[CyCAR] = (u_char) channel; + base_addr[CyMSVR1] = CyRTS; /* CP('S');CP('4'); */ - base_addr[CyMSVR2] = CyDTR; + base_addr[CyMSVR2] = CyDTR; #ifdef SERIAL_DEBUG_DTR - printk("cyc: %d: raising DTR\n", __LINE__); - printk(" status: 0x%x, 0x%x\n", base_addr[CyMSVR1], base_addr[CyMSVR2]); -#endif - local_irq_restore(flags); - set_current_state(TASK_INTERRUPTIBLE); - if (tty_hung_up_p(filp) - || !(info->flags & ASYNC_INITIALIZED) ){ - if (info->flags & ASYNC_HUP_NOTIFY) { - retval = -EAGAIN; - }else{ - retval = -ERESTARTSYS; - } - break; - } - local_irq_save(flags); - base_addr[CyCAR] = (u_char)channel; + printk("cyc: %d: raising DTR\n", __LINE__); + printk(" status: 0x%x, 0x%x\n", base_addr[CyMSVR1], + base_addr[CyMSVR2]); +#endif + local_irq_restore(flags); + set_current_state(TASK_INTERRUPTIBLE); + if (tty_hung_up_p(filp) + || !(info->flags & ASYNC_INITIALIZED)) { + if (info->flags & ASYNC_HUP_NOTIFY) { + retval = -EAGAIN; + } else { + retval = -ERESTARTSYS; + } + break; + } + local_irq_save(flags); + base_addr[CyCAR] = (u_char) channel; /* CP('L');CP1(1 && C_CLOCAL(tty)); CP1(1 && (base_addr[CyMSVR1] & CyDCD) ); */ - if (!(info->flags & ASYNC_CLOSING) - && (C_CLOCAL(tty) - || (base_addr[CyMSVR1] & CyDCD))) { - local_irq_restore(flags); - break; - } - local_irq_restore(flags); - if (signal_pending(current)) { - retval = -ERESTARTSYS; - break; - } + if (!(info->flags & ASYNC_CLOSING) + && (C_CLOCAL(tty) + || (base_addr[CyMSVR1] & CyDCD))) { + local_irq_restore(flags); + break; + } + local_irq_restore(flags); + if (signal_pending(current)) { + retval = -ERESTARTSYS; + break; + } #ifdef SERIAL_DEBUG_OPEN - printk("block_til_ready blocking: %s, count = %d\n", - tty->name, info->count);/**/ -#endif - schedule(); - } - current->state = TASK_RUNNING; - remove_wait_queue(&info->open_wait, &wait); - if (!tty_hung_up_p(filp)){ - info->count++; + printk("block_til_ready blocking: %s, count = %d\n", + tty->name, info->count); + /**/ +#endif + schedule(); + } + current->state = TASK_RUNNING; + remove_wait_queue(&info->open_wait, &wait); + if (!tty_hung_up_p(filp)) { + info->count++; #ifdef SERIAL_DEBUG_COUNT - printk("cyc: %d: incrementing count to %d\n", __LINE__, info->count); + printk("cyc: %d: incrementing count to %d\n", __LINE__, + info->count); #endif - } - info->blocked_open--; + } + info->blocked_open--; #ifdef SERIAL_DEBUG_OPEN - printk("block_til_ready after blocking: %s, count = %d\n", - tty->name, info->count);/**/ + printk("block_til_ready after blocking: %s, count = %d\n", + tty->name, info->count); + /**/ #endif - if (retval) - return retval; - info->flags |= ASYNC_NORMAL_ACTIVE; - return 0; -} /* block_til_ready */ + if (retval) + return retval; + info->flags |= ASYNC_NORMAL_ACTIVE; + return 0; +} /* block_til_ready */ /* * This routine is called whenever a serial port is opened. It * performs the serial-specific initialization for the tty structure. */ -int -cy_open(struct tty_struct *tty, struct file * filp) +int cy_open(struct tty_struct *tty, struct file *filp) { - struct cyclades_port *info; - int retval, line; + struct cyclades_port *info; + int retval, line; /* CP('O'); */ - line = tty->index; - if ((line < 0) || (NR_PORTS <= line)){ - return -ENODEV; - } - info = &cy_port[line]; - if (info->line < 0){ - return -ENODEV; - } + line = tty->index; + if ((line < 0) || (NR_PORTS <= line)) { + return -ENODEV; + } + info = &cy_port[line]; + if (info->line < 0) { + return -ENODEV; + } #ifdef SERIAL_DEBUG_OTHER - printk("cy_open %s\n", tty->name); /* */ + printk("cy_open %s\n", tty->name); /* */ #endif - if (serial_paranoia_check(info, tty->name, "cy_open")){ - return -ENODEV; - } + if (serial_paranoia_check(info, tty->name, "cy_open")) { + return -ENODEV; + } #ifdef SERIAL_DEBUG_OPEN - printk("cy_open %s, count = %d\n", tty->name, info->count);/**/ + printk("cy_open %s, count = %d\n", tty->name, info->count); + /**/ #endif - info->count++; + info->count++; #ifdef SERIAL_DEBUG_COUNT - printk("cyc: %d: incrementing count to %d\n", __LINE__, info->count); + printk("cyc: %d: incrementing count to %d\n", __LINE__, info->count); #endif - tty->driver_data = info; - info->tty = tty; + tty->driver_data = info; + info->tty = tty; - /* - * Start up serial port - */ - retval = startup(info); - if (retval){ - return retval; - } + /* + * Start up serial port + */ + retval = startup(info); + if (retval) { + return retval; + } - retval = block_til_ready(tty, filp, info); - if (retval) { + retval = block_til_ready(tty, filp, info); + if (retval) { #ifdef SERIAL_DEBUG_OPEN - printk("cy_open returning after block_til_ready with %d\n", - retval); + printk("cy_open returning after block_til_ready with %d\n", + retval); #endif - return retval; - } - + return retval; + } #ifdef SERIAL_DEBUG_OPEN - printk("cy_open done\n");/**/ + printk("cy_open done\n"); + /**/ #endif - return 0; -} /* cy_open */ - - + return 0; +} /* cy_open */ /* * --------------------------------------------------------------------- @@ -2012,11 +1984,10 @@ #endif * number, and identifies which options were configured into this * driver. */ -static void -show_version(void) +static void show_version(void) { - printk("MVME166/167 cd2401 driver\n"); -} /* show_version */ + printk("MVME166/167 cd2401 driver\n"); +} /* show_version */ /* initialize chips on card -- return number of valid chips (which is number of ports/4) */ @@ -2030,10 +2001,9 @@ show_version(void) * ... I wonder what I should do if this fails ... */ -void -mvme167_serial_console_setup(int cflag) +void mvme167_serial_console_setup(int cflag) { - volatile unsigned char* base_addr = (u_char *)BASE_ADDR; + volatile unsigned char *base_addr = (u_char *) BASE_ADDR; int ch; u_char spd; u_char rcor, rbpr, badspeed = 0; @@ -2062,21 +2032,21 @@ mvme167_serial_console_setup(int cflag) /* OK, we have chosen a speed, now reset and reinitialise */ - my_udelay(20000L); /* Allow time for any active o/p to complete */ - if(base_addr[CyCCR] != 0x00){ - local_irq_restore(flags); - /* printk(" chip is never idle (CCR != 0)\n"); */ - return; - } + my_udelay(20000L); /* Allow time for any active o/p to complete */ + if (base_addr[CyCCR] != 0x00) { + local_irq_restore(flags); + /* printk(" chip is never idle (CCR != 0)\n"); */ + return; + } - base_addr[CyCCR] = CyCHIP_RESET; /* Reset the chip */ - my_udelay(1000L); + base_addr[CyCCR] = CyCHIP_RESET; /* Reset the chip */ + my_udelay(1000L); - if(base_addr[CyGFRCR] == 0x00){ - local_irq_restore(flags); - /* printk(" chip is not responding (GFRCR stayed 0)\n"); */ - return; - } + if (base_addr[CyGFRCR] == 0x00) { + local_irq_restore(flags); + /* printk(" chip is not responding (GFRCR stayed 0)\n"); */ + return; + } /* * System clock is 20Mhz, divided by 2048, so divide by 10 for a 1.0ms @@ -2085,9 +2055,9 @@ mvme167_serial_console_setup(int cflag) base_addr[CyTPR] = 10; - base_addr[CyPILR1] = 0x01; /* Interrupt level for modem change */ - base_addr[CyPILR2] = 0x02; /* Interrupt level for tx ints */ - base_addr[CyPILR3] = 0x03; /* Interrupt level for rx ints */ + base_addr[CyPILR1] = 0x01; /* Interrupt level for modem change */ + base_addr[CyPILR2] = 0x02; /* Interrupt level for tx ints */ + base_addr[CyPILR3] = 0x03; /* Interrupt level for rx ints */ /* * Attempt to set up all channels to something reasonable, and @@ -2095,11 +2065,11 @@ mvme167_serial_console_setup(int cflag) * the ammount of fiddling we have to do in normal running. */ - for (ch = 3; ch >= 0 ; ch--) { - base_addr[CyCAR] = (u_char)ch; + for (ch = 3; ch >= 0; ch--) { + base_addr[CyCAR] = (u_char) ch; base_addr[CyIER] = 0; base_addr[CyCMR] = CyASYNC; - base_addr[CyLICR] = (u_char)ch << 2; + base_addr[CyLICR] = (u_char) ch << 2; base_addr[CyLIVR] = 0x5c; base_addr[CyTCOR] = baud_co[spd]; base_addr[CyTBPR] = baud_bpr[spd]; @@ -2118,29 +2088,30 @@ mvme167_serial_console_setup(int cflag) base_addr[CyCOR7] = 0; base_addr[CyRTPRL] = 2; base_addr[CyRTPRH] = 0; - base_addr[CyMSVR1] = 0; - base_addr[CyMSVR2] = 0; - write_cy_cmd(base_addr,CyINIT_CHAN|CyDIS_RCVR|CyDIS_XMTR); + base_addr[CyMSVR1] = 0; + base_addr[CyMSVR2] = 0; + write_cy_cmd(base_addr, CyINIT_CHAN | CyDIS_RCVR | CyDIS_XMTR); } /* * Now do specials for channel zero.... */ - base_addr[CyMSVR1] = CyRTS; - base_addr[CyMSVR2] = CyDTR; + base_addr[CyMSVR1] = CyRTS; + base_addr[CyMSVR2] = CyDTR; base_addr[CyIER] = CyRxData; - write_cy_cmd(base_addr,CyENB_RCVR|CyENB_XMTR); + write_cy_cmd(base_addr, CyENB_RCVR | CyENB_XMTR); local_irq_restore(flags); my_udelay(20000L); /* Let it all settle down */ - printk("CD2401 initialised, chip is rev 0x%02x\n", base_addr[CyGFRCR]); + printk("CD2401 initialised, chip is rev 0x%02x\n", base_addr[CyGFRCR]); if (badspeed) - printk(" WARNING: Failed to identify line speed, rcor=%02x,rbpr=%02x\n", - rcor >> 5, rbpr); -} /* serial_console_init */ + printk + (" WARNING: Failed to identify line speed, rcor=%02x,rbpr=%02x\n", + rcor >> 5, rbpr); +} /* serial_console_init */ static const struct tty_operations cy_ops = { .open = cy_open, @@ -2161,6 +2132,7 @@ static const struct tty_operations cy_op .tiocmget = cy_tiocmget, .tiocmset = cy_tiocmset, }; + /* The serial driver boot-time initialization code! Hardware I/O ports are mapped to character special devices on a first found, first allocated manner. That is, this code searches @@ -2177,214 +2149,214 @@ static const struct tty_operations cy_op If there are more cards with more ports than have been statically allocated above, a warning is printed and the extra ports are ignored. */ -static int __init -serial167_init(void) +static int __init serial167_init(void) { - struct cyclades_port *info; - int ret = 0; - int good_ports = 0; - int port_num = 0; - int index; - int DefSpeed; + struct cyclades_port *info; + int ret = 0; + int good_ports = 0; + int port_num = 0; + int index; + int DefSpeed; #ifdef notyet - struct sigaction sa; + struct sigaction sa; #endif - if (!(mvme16x_config &MVME16x_CONFIG_GOT_CD2401)) - return 0; + if (!(mvme16x_config & MVME16x_CONFIG_GOT_CD2401)) + return 0; - cy_serial_driver = alloc_tty_driver(NR_PORTS); - if (!cy_serial_driver) - return -ENOMEM; + cy_serial_driver = alloc_tty_driver(NR_PORTS); + if (!cy_serial_driver) + return -ENOMEM; #if 0 -scrn[1] = '\0'; + scrn[1] = '\0'; #endif - show_version(); + show_version(); - /* Has "console=0,9600n8" been used in bootinfo to change speed? */ - if (serial_console_cflag) - DefSpeed = serial_console_cflag & 0017; - else { - DefSpeed = initial_console_speed; - serial_console_info = &cy_port[0]; - serial_console_cflag = DefSpeed | CS8; + /* Has "console=0,9600n8" been used in bootinfo to change speed? */ + if (serial_console_cflag) + DefSpeed = serial_console_cflag & 0017; + else { + DefSpeed = initial_console_speed; + serial_console_info = &cy_port[0]; + serial_console_cflag = DefSpeed | CS8; #if 0 - serial_console = 64; /*callout_driver.minor_start*/ -#endif - } - - /* Initialize the tty_driver structure */ - - cy_serial_driver->owner = THIS_MODULE; - cy_serial_driver->name = "ttyS"; - cy_serial_driver->major = TTY_MAJOR; - cy_serial_driver->minor_start = 64; - cy_serial_driver->type = TTY_DRIVER_TYPE_SERIAL; - cy_serial_driver->subtype = SERIAL_TYPE_NORMAL; - cy_serial_driver->init_termios = tty_std_termios; - cy_serial_driver->init_termios.c_cflag = - B9600 | CS8 | CREAD | HUPCL | CLOCAL; - cy_serial_driver->flags = TTY_DRIVER_REAL_RAW; - tty_set_operations(cy_serial_driver, &cy_ops); + serial_console = 64; /*callout_driver.minor_start */ +#endif + } - ret = tty_register_driver(cy_serial_driver); - if (ret) { - printk(KERN_ERR "Couldn't register MVME166/7 serial driver\n"); - put_tty_driver(cy_serial_driver); - return ret; - } + /* Initialize the tty_driver structure */ - port_num = 0; - info = cy_port; - for (index = 0; index < 1; index++) { + cy_serial_driver->owner = THIS_MODULE; + cy_serial_driver->name = "ttyS"; + cy_serial_driver->major = TTY_MAJOR; + cy_serial_driver->minor_start = 64; + cy_serial_driver->type = TTY_DRIVER_TYPE_SERIAL; + cy_serial_driver->subtype = SERIAL_TYPE_NORMAL; + cy_serial_driver->init_termios = tty_std_termios; + cy_serial_driver->init_termios.c_cflag = + B9600 | CS8 | CREAD | HUPCL | CLOCAL; + cy_serial_driver->flags = TTY_DRIVER_REAL_RAW; + tty_set_operations(cy_serial_driver, &cy_ops); + + ret = tty_register_driver(cy_serial_driver); + if (ret) { + printk(KERN_ERR "Couldn't register MVME166/7 serial driver\n"); + put_tty_driver(cy_serial_driver); + return ret; + } - good_ports = 4; + port_num = 0; + info = cy_port; + for (index = 0; index < 1; index++) { - if(port_num < NR_PORTS){ - while( good_ports-- && port_num < NR_PORTS){ + good_ports = 4; + + if (port_num < NR_PORTS) { + while (good_ports-- && port_num < NR_PORTS) { /*** initialize port ***/ - info->magic = CYCLADES_MAGIC; - info->type = PORT_CIRRUS; - info->card = index; - info->line = port_num; - info->flags = STD_COM_FLAGS; - info->tty = NULL; - info->xmit_fifo_size = 12; - info->cor1 = CyPARITY_NONE|Cy_8_BITS; - info->cor2 = CyETC; - info->cor3 = Cy_1_STOP; - info->cor4 = 0x08; /* _very_ small receive threshold */ - info->cor5 = 0; - info->cor6 = 0; - info->cor7 = 0; - info->tbpr = baud_bpr[DefSpeed]; /* Tx BPR */ - info->tco = baud_co[DefSpeed]; /* Tx CO */ - info->rbpr = baud_bpr[DefSpeed]; /* Rx BPR */ - info->rco = baud_co[DefSpeed] >> 5; /* Rx CO */ - info->close_delay = 0; - info->x_char = 0; - info->event = 0; - info->count = 0; + info->magic = CYCLADES_MAGIC; + info->type = PORT_CIRRUS; + info->card = index; + info->line = port_num; + info->flags = STD_COM_FLAGS; + info->tty = NULL; + info->xmit_fifo_size = 12; + info->cor1 = CyPARITY_NONE | Cy_8_BITS; + info->cor2 = CyETC; + info->cor3 = Cy_1_STOP; + info->cor4 = 0x08; /* _very_ small receive threshold */ + info->cor5 = 0; + info->cor6 = 0; + info->cor7 = 0; + info->tbpr = baud_bpr[DefSpeed]; /* Tx BPR */ + info->tco = baud_co[DefSpeed]; /* Tx CO */ + info->rbpr = baud_bpr[DefSpeed]; /* Rx BPR */ + info->rco = baud_co[DefSpeed] >> 5; /* Rx CO */ + info->close_delay = 0; + info->x_char = 0; + info->event = 0; + info->count = 0; #ifdef SERIAL_DEBUG_COUNT - printk("cyc: %d: setting count to 0\n", __LINE__); -#endif - info->blocked_open = 0; - info->default_threshold = 0; - info->default_timeout = 0; - INIT_WORK(&info->tqueue, do_softint); - init_waitqueue_head(&info->open_wait); - init_waitqueue_head(&info->close_wait); - /* info->session */ - /* info->pgrp */ + printk("cyc: %d: setting count to 0\n", + __LINE__); +#endif + info->blocked_open = 0; + info->default_threshold = 0; + info->default_timeout = 0; + INIT_WORK(&info->tqueue, do_softint); + init_waitqueue_head(&info->open_wait); + init_waitqueue_head(&info->close_wait); + /* info->session */ + /* info->pgrp */ /*** !!!!!!!! this may expose new bugs !!!!!!!!! *********/ - info->read_status_mask = CyTIMEOUT| CySPECHAR| CyBREAK - | CyPARITY| CyFRAME| CyOVERRUN; - /* info->timeout */ - - printk("ttyS%d ", info->line); - port_num++;info++; - if(!(port_num & 7)){ - printk("\n "); + info->read_status_mask = + CyTIMEOUT | CySPECHAR | CyBREAK | CyPARITY | + CyFRAME | CyOVERRUN; + /* info->timeout */ + + printk("ttyS%d ", info->line); + port_num++; + info++; + if (!(port_num & 7)) { + printk("\n "); + } + } } - } - } - printk("\n"); - } - while( port_num < NR_PORTS){ - info->line = -1; - port_num++;info++; - } + printk("\n"); + } + while (port_num < NR_PORTS) { + info->line = -1; + port_num++; + info++; + } #ifdef CONFIG_REMOTE_DEBUG - debug_setup(); -#endif - ret = request_irq(MVME167_IRQ_SER_ERR, cd2401_rxerr_interrupt, 0, - "cd2401_errors", cd2401_rxerr_interrupt); - if (ret) { - printk(KERN_ERR "Could't get cd2401_errors IRQ"); - goto cleanup_serial_driver; - } - - ret = request_irq(MVME167_IRQ_SER_MODEM, cd2401_modem_interrupt, 0, - "cd2401_modem", cd2401_modem_interrupt); - if (ret) { - printk(KERN_ERR "Could't get cd2401_modem IRQ"); - goto cleanup_irq_cd2401_errors; - } - - ret = request_irq(MVME167_IRQ_SER_TX, cd2401_tx_interrupt, 0, - "cd2401_txints", cd2401_tx_interrupt); - if (ret) { - printk(KERN_ERR "Could't get cd2401_txints IRQ"); - goto cleanup_irq_cd2401_modem; - } - - ret = request_irq(MVME167_IRQ_SER_RX, cd2401_rx_interrupt, 0, - "cd2401_rxints", cd2401_rx_interrupt); - if (ret) { - printk(KERN_ERR "Could't get cd2401_rxints IRQ"); - goto cleanup_irq_cd2401_txints; - } - - /* Now we have registered the interrupt handlers, allow the interrupts */ - - pcc2chip[PccSCCMICR] = 0x15; /* Serial ints are level 5 */ - pcc2chip[PccSCCTICR] = 0x15; - pcc2chip[PccSCCRICR] = 0x15; - - pcc2chip[PccIMLR] = 3; /* Allow PCC2 ints above 3!? */ - - return 0; + debug_setup(); +#endif + ret = request_irq(MVME167_IRQ_SER_ERR, cd2401_rxerr_interrupt, 0, + "cd2401_errors", cd2401_rxerr_interrupt); + if (ret) { + printk(KERN_ERR "Could't get cd2401_errors IRQ"); + goto cleanup_serial_driver; + } + + ret = request_irq(MVME167_IRQ_SER_MODEM, cd2401_modem_interrupt, 0, + "cd2401_modem", cd2401_modem_interrupt); + if (ret) { + printk(KERN_ERR "Could't get cd2401_modem IRQ"); + goto cleanup_irq_cd2401_errors; + } + + ret = request_irq(MVME167_IRQ_SER_TX, cd2401_tx_interrupt, 0, + "cd2401_txints", cd2401_tx_interrupt); + if (ret) { + printk(KERN_ERR "Could't get cd2401_txints IRQ"); + goto cleanup_irq_cd2401_modem; + } + + ret = request_irq(MVME167_IRQ_SER_RX, cd2401_rx_interrupt, 0, + "cd2401_rxints", cd2401_rx_interrupt); + if (ret) { + printk(KERN_ERR "Could't get cd2401_rxints IRQ"); + goto cleanup_irq_cd2401_txints; + } + + /* Now we have registered the interrupt handlers, allow the interrupts */ + + pcc2chip[PccSCCMICR] = 0x15; /* Serial ints are level 5 */ + pcc2chip[PccSCCTICR] = 0x15; + pcc2chip[PccSCCRICR] = 0x15; + + pcc2chip[PccIMLR] = 3; /* Allow PCC2 ints above 3!? */ + + return 0; cleanup_irq_cd2401_txints: - free_irq(MVME167_IRQ_SER_TX, cd2401_tx_interrupt); + free_irq(MVME167_IRQ_SER_TX, cd2401_tx_interrupt); cleanup_irq_cd2401_modem: - free_irq(MVME167_IRQ_SER_MODEM, cd2401_modem_interrupt); + free_irq(MVME167_IRQ_SER_MODEM, cd2401_modem_interrupt); cleanup_irq_cd2401_errors: - free_irq(MVME167_IRQ_SER_ERR, cd2401_rxerr_interrupt); + free_irq(MVME167_IRQ_SER_ERR, cd2401_rxerr_interrupt); cleanup_serial_driver: - if (tty_unregister_driver(cy_serial_driver)) - printk(KERN_ERR "Couldn't unregister MVME166/7 serial driver\n"); - put_tty_driver(cy_serial_driver); - return ret; -} /* serial167_init */ + if (tty_unregister_driver(cy_serial_driver)) + printk(KERN_ERR + "Couldn't unregister MVME166/7 serial driver\n"); + put_tty_driver(cy_serial_driver); + return ret; +} /* serial167_init */ module_init(serial167_init); - #ifdef CYCLOM_SHOW_STATUS -static void -show_status(int line_num) +static void show_status(int line_num) { - volatile unsigned char *base_addr = (u_char *)BASE_ADDR; - int channel; - struct cyclades_port * info; - unsigned long flags; - - info = &cy_port[line_num]; - channel = info->line; - printk(" channel %d\n", channel);/**/ - - printk(" cy_port\n"); - printk(" card line flags = %d %d %x\n", - info->card, info->line, info->flags); - printk(" *tty read_status_mask timeout xmit_fifo_size = %lx %x %x %x\n", - (long)info->tty, info->read_status_mask, - info->timeout, info->xmit_fifo_size); - printk(" cor1,cor2,cor3,cor4,cor5,cor6,cor7 = %x %x %x %x %x %x %x\n", - info->cor1, info->cor2, info->cor3, info->cor4, info->cor5, - info->cor6, info->cor7); - printk(" tbpr,tco,rbpr,rco = %d %d %d %d\n", - info->tbpr, info->tco, info->rbpr, info->rco); - printk(" close_delay event count = %d %d %d\n", - info->close_delay, info->event, info->count); - printk(" x_char blocked_open = %x %x\n", - info->x_char, info->blocked_open); - printk(" open_wait = %lx %lx %lx\n", - (long)info->open_wait); - - - local_irq_save(flags); + volatile unsigned char *base_addr = (u_char *) BASE_ADDR; + int channel; + struct cyclades_port *info; + unsigned long flags; + + info = &cy_port[line_num]; + channel = info->line; + printk(" channel %d\n", channel); + /**/ printk(" cy_port\n"); + printk(" card line flags = %d %d %x\n", + info->card, info->line, info->flags); + printk + (" *tty read_status_mask timeout xmit_fifo_size = %lx %x %x %x\n", + (long)info->tty, info->read_status_mask, info->timeout, + info->xmit_fifo_size); + printk(" cor1,cor2,cor3,cor4,cor5,cor6,cor7 = %x %x %x %x %x %x %x\n", + info->cor1, info->cor2, info->cor3, info->cor4, info->cor5, + info->cor6, info->cor7); + printk(" tbpr,tco,rbpr,rco = %d %d %d %d\n", info->tbpr, info->tco, + info->rbpr, info->rco); + printk(" close_delay event count = %d %d %d\n", info->close_delay, + info->event, info->count); + printk(" x_char blocked_open = %x %x\n", info->x_char, + info->blocked_open); + printk(" open_wait = %lx %lx %lx\n", (long)info->open_wait); + + local_irq_save(flags); /* Global Registers */ @@ -2398,7 +2370,7 @@ show_status(int line_num) printk(" CyMIR %x\n", base_addr[CyMIR]); printk(" CyTPR %x\n", base_addr[CyTPR]); - base_addr[CyCAR] = (u_char)channel; + base_addr[CyCAR] = (u_char) channel; /* Virtual Registers */ @@ -2442,11 +2414,10 @@ #endif printk(" CyTBPR %x\n", base_addr[CyTBPR]); printk(" CyTCOR %x\n", base_addr[CyTCOR]); - local_irq_restore(flags); -} /* show_status */ + local_irq_restore(flags); +} /* show_status */ #endif - #if 0 /* Dummy routine in mvme16x/config.c for now */ @@ -2459,61 +2430,67 @@ void console_setup(char *str, int *ints) int cflag = 0; /* Sanity check. */ - if (ints[0] > 3 || ints[1] > 3) return; + if (ints[0] > 3 || ints[1] > 3) + return; /* Get baud, bits and parity */ baud = 2400; bits = 8; parity = 'n'; - if (ints[2]) baud = ints[2]; + if (ints[2]) + baud = ints[2]; if ((s = strchr(str, ','))) { do { s++; - } while(*s >= '0' && *s <= '9'); - if (*s) parity = *s++; - if (*s) bits = *s - '0'; + } while (*s >= '0' && *s <= '9'); + if (*s) + parity = *s++; + if (*s) + bits = *s - '0'; } /* Now construct a cflag setting. */ - switch(baud) { - case 1200: - cflag |= B1200; - break; - case 9600: - cflag |= B9600; - break; - case 19200: - cflag |= B19200; - break; - case 38400: - cflag |= B38400; - break; - case 2400: - default: - cflag |= B2400; - break; + switch (baud) { + case 1200: + cflag |= B1200; + break; + case 9600: + cflag |= B9600; + break; + case 19200: + cflag |= B19200; + break; + case 38400: + cflag |= B38400; + break; + case 2400: + default: + cflag |= B2400; + break; } - switch(bits) { - case 7: - cflag |= CS7; - break; - default: - case 8: - cflag |= CS8; - break; + switch (bits) { + case 7: + cflag |= CS7; + break; + default: + case 8: + cflag |= CS8; + break; } - switch(parity) { - case 'o': case 'O': - cflag |= PARODD; - break; - case 'e': case 'E': - cflag |= PARENB; - break; + switch (parity) { + case 'o': + case 'O': + cflag |= PARODD; + break; + case 'e': + case 'E': + cflag |= PARENB; + break; } serial_console_info = &cy_port[ints[1]]; serial_console_cflag = cflag; - serial_console = ints[1] + 64; /*callout_driver.minor_start*/ + serial_console = ints[1] + 64; /*callout_driver.minor_start */ } #endif @@ -2532,9 +2509,10 @@ #endif * The console must be locked when we get here. */ -void serial167_console_write(struct console *co, const char *str, unsigned count) +void serial167_console_write(struct console *co, const char *str, + unsigned count) { - volatile unsigned char *base_addr = (u_char *)BASE_ADDR; + volatile unsigned char *base_addr = (u_char *) BASE_ADDR; unsigned long flags; volatile u_char sink; u_char ier; @@ -2547,7 +2525,7 @@ void serial167_console_write(struct cons /* Ensure transmitter is enabled! */ port = 0; - base_addr[CyCAR] = (u_char)port; + base_addr[CyCAR] = (u_char) port; while (base_addr[CyCCR]) ; base_addr[CyCCR] = CyENB_XMTR; @@ -2556,8 +2534,7 @@ void serial167_console_write(struct cons base_addr[CyIER] = CyTxMpty; while (1) { - if (pcc2chip[PccSCCTICR] & 0x20) - { + if (pcc2chip[PccSCCTICR] & 0x20) { /* We have a Tx int. Acknowledge it */ sink = pcc2chip[PccTPIACKR]; if ((base_addr[CyLICR] >> 2) == port) { @@ -2571,18 +2548,15 @@ void serial167_console_write(struct cons str++; i++; do_lf = 0; - } - else if (*str == '\n') { + } else if (*str == '\n') { base_addr[CyTDR] = '\r'; do_lf = 1; - } - else { + } else { base_addr[CyTDR] = *str++; i++; } base_addr[CyTEOIR] = 0; - } - else + } else base_addr[CyTEOIR] = CyNOTRANS; } } @@ -2592,45 +2566,44 @@ void serial167_console_write(struct cons local_irq_restore(flags); } -static struct tty_driver *serial167_console_device(struct console *c, int *index) +static struct tty_driver *serial167_console_device(struct console *c, + int *index) { *index = c->index; return cy_serial_driver; } - static int __init serial167_console_setup(struct console *co, char *options) { return 0; } - static struct console sercons = { - .name = "ttyS", - .write = serial167_console_write, - .device = serial167_console_device, - .setup = serial167_console_setup, - .flags = CON_PRINTBUFFER, - .index = -1, + .name = "ttyS", + .write = serial167_console_write, + .device = serial167_console_device, + .setup = serial167_console_setup, + .flags = CON_PRINTBUFFER, + .index = -1, }; - static int __init serial167_console_init(void) { if (vme_brdtype == VME_TYPE_MVME166 || - vme_brdtype == VME_TYPE_MVME167 || - vme_brdtype == VME_TYPE_MVME177) { + vme_brdtype == VME_TYPE_MVME167 || + vme_brdtype == VME_TYPE_MVME177) { mvme167_serial_console_setup(0); register_console(&sercons); } return 0; } + console_initcall(serial167_console_init); #ifdef CONFIG_REMOTE_DEBUG -void putDebugChar (int c) +void putDebugChar(int c) { - volatile unsigned char *base_addr = (u_char *)BASE_ADDR; + volatile unsigned char *base_addr = (u_char *) BASE_ADDR; unsigned long flags; volatile u_char sink; u_char ier; @@ -2641,7 +2614,7 @@ void putDebugChar (int c) /* Ensure transmitter is enabled! */ port = DEBUG_PORT; - base_addr[CyCAR] = (u_char)port; + base_addr[CyCAR] = (u_char) port; while (base_addr[CyCCR]) ; base_addr[CyCCR] = CyENB_XMTR; @@ -2650,16 +2623,14 @@ void putDebugChar (int c) base_addr[CyIER] = CyTxMpty; while (1) { - if (pcc2chip[PccSCCTICR] & 0x20) - { + if (pcc2chip[PccSCCTICR] & 0x20) { /* We have a Tx int. Acknowledge it */ sink = pcc2chip[PccTPIACKR]; if ((base_addr[CyLICR] >> 2) == port) { base_addr[CyTDR] = c; base_addr[CyTEOIR] = 0; break; - } - else + } else base_addr[CyTEOIR] = CyNOTRANS; } } @@ -2671,7 +2642,7 @@ void putDebugChar (int c) int getDebugChar() { - volatile unsigned char *base_addr = (u_char *)BASE_ADDR; + volatile unsigned char *base_addr = (u_char *) BASE_ADDR; unsigned long flags; volatile u_char sink; u_char ier; @@ -2693,7 +2664,7 @@ int getDebugChar() /* Ensure receiver is enabled! */ port = DEBUG_PORT; - base_addr[CyCAR] = (u_char)port; + base_addr[CyCAR] = (u_char) port; #if 0 while (base_addr[CyCCR]) ; @@ -2703,31 +2674,30 @@ #endif base_addr[CyIER] = CyRxData; while (1) { - if (pcc2chip[PccSCCRICR] & 0x20) - { + if (pcc2chip[PccSCCRICR] & 0x20) { /* We have a Rx int. Acknowledge it */ sink = pcc2chip[PccRPIACKR]; if ((base_addr[CyLICR] >> 2) == port) { int cnt = base_addr[CyRFOC]; - while (cnt-- > 0) - { + while (cnt-- > 0) { c = base_addr[CyRDR]; if (c == 0) - printk ("!! debug char is null (cnt=%d) !!", cnt); + printk + ("!! debug char is null (cnt=%d) !!", + cnt); else - queueDebugChar (c); + queueDebugChar(c); } base_addr[CyREOIR] = 0; i = debugiq.out; if (i == debugiq.in) - panic ("Debug input queue empty!"); + panic("Debug input queue empty!"); c = debugiq.buf[i]; if (++i == DEBUG_LEN) i = 0; debugiq.out = i; break; - } - else + } else base_addr[CyREOIR] = CyNOTRANS; } } @@ -2739,7 +2709,7 @@ #endif return (c); } -void queueDebugChar (int c) +void queueDebugChar(int c) { int i; @@ -2751,73 +2721,71 @@ void queueDebugChar (int c) debugiq.in = i; } -static void -debug_setup() +static void debug_setup() { - unsigned long flags; - volatile unsigned char *base_addr = (u_char *)BASE_ADDR; - int i, cflag; + unsigned long flags; + volatile unsigned char *base_addr = (u_char *) BASE_ADDR; + int i, cflag; - cflag = B19200; + cflag = B19200; - local_irq_save(flags); + local_irq_save(flags); - for (i = 0; i < 4; i++) - { - base_addr[CyCAR] = i; - base_addr[CyLICR] = i << 2; - } + for (i = 0; i < 4; i++) { + base_addr[CyCAR] = i; + base_addr[CyLICR] = i << 2; + } - debugiq.in = debugiq.out = 0; + debugiq.in = debugiq.out = 0; - base_addr[CyCAR] = DEBUG_PORT; + base_addr[CyCAR] = DEBUG_PORT; - /* baud rate */ - i = cflag & CBAUD; + /* baud rate */ + i = cflag & CBAUD; - base_addr[CyIER] = 0; + base_addr[CyIER] = 0; - base_addr[CyCMR] = CyASYNC; - base_addr[CyLICR] = DEBUG_PORT << 2; - base_addr[CyLIVR] = 0x5c; + base_addr[CyCMR] = CyASYNC; + base_addr[CyLICR] = DEBUG_PORT << 2; + base_addr[CyLIVR] = 0x5c; - /* tx and rx baud rate */ + /* tx and rx baud rate */ - base_addr[CyTCOR] = baud_co[i]; - base_addr[CyTBPR] = baud_bpr[i]; - base_addr[CyRCOR] = baud_co[i] >> 5; - base_addr[CyRBPR] = baud_bpr[i]; + base_addr[CyTCOR] = baud_co[i]; + base_addr[CyTBPR] = baud_bpr[i]; + base_addr[CyRCOR] = baud_co[i] >> 5; + base_addr[CyRBPR] = baud_bpr[i]; - /* set line characteristics according configuration */ + /* set line characteristics according configuration */ - base_addr[CySCHR1] = 0; - base_addr[CySCHR2] = 0; - base_addr[CySCRL] = 0; - base_addr[CySCRH] = 0; - base_addr[CyCOR1] = Cy_8_BITS | CyPARITY_NONE; - base_addr[CyCOR2] = 0; - base_addr[CyCOR3] = Cy_1_STOP; - base_addr[CyCOR4] = baud_cor4[i]; - base_addr[CyCOR5] = 0; - base_addr[CyCOR6] = 0; - base_addr[CyCOR7] = 0; + base_addr[CySCHR1] = 0; + base_addr[CySCHR2] = 0; + base_addr[CySCRL] = 0; + base_addr[CySCRH] = 0; + base_addr[CyCOR1] = Cy_8_BITS | CyPARITY_NONE; + base_addr[CyCOR2] = 0; + base_addr[CyCOR3] = Cy_1_STOP; + base_addr[CyCOR4] = baud_cor4[i]; + base_addr[CyCOR5] = 0; + base_addr[CyCOR6] = 0; + base_addr[CyCOR7] = 0; - write_cy_cmd(base_addr,CyINIT_CHAN); - write_cy_cmd(base_addr,CyENB_RCVR); + write_cy_cmd(base_addr, CyINIT_CHAN); + write_cy_cmd(base_addr, CyENB_RCVR); - base_addr[CyCAR] = DEBUG_PORT; /* !!! Is this needed? */ + base_addr[CyCAR] = DEBUG_PORT; /* !!! Is this needed? */ - base_addr[CyRTPRL] = 2; - base_addr[CyRTPRH] = 0; + base_addr[CyRTPRL] = 2; + base_addr[CyRTPRH] = 0; - base_addr[CyMSVR1] = CyRTS; - base_addr[CyMSVR2] = CyDTR; + base_addr[CyMSVR1] = CyRTS; + base_addr[CyMSVR2] = CyDTR; - base_addr[CyIER] = CyRxData; + base_addr[CyIER] = CyRxData; - local_irq_restore(flags); + local_irq_restore(flags); -} /* debug_setup */ +} /* debug_setup */ #endif diff --git a/drivers/char/sonypi.c b/drivers/char/sonypi.c index 17d54e1..7823757 100644 --- a/drivers/char/sonypi.c +++ b/drivers/char/sonypi.c @@ -36,7 +36,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/char/specialix.c b/drivers/char/specialix.c index 20946f5..baf7234 100644 --- a/drivers/char/specialix.c +++ b/drivers/char/specialix.c @@ -459,10 +459,9 @@ void missed_irq (unsigned long data) if (irq) { printk (KERN_INFO "Missed interrupt... Calling int from timer. \n"); sx_interrupt (((struct specialix_board *)data)->irq, - (void*)data, NULL); + (void*)data); } - missed_irq_timer.expires = jiffies + sx_poll; - add_timer (&missed_irq_timer); + mod_timer(&missed_irq_timer, jiffies + sx_poll); } #endif @@ -597,11 +596,8 @@ #endif dprintk (SX_DEBUG_INIT, " GFCR = 0x%02x\n", sx_in_off(bp, CD186x_GFRCR) ); #ifdef SPECIALIX_TIMER - init_timer (&missed_irq_timer); - missed_irq_timer.function = missed_irq; - missed_irq_timer.data = (unsigned long) bp; - missed_irq_timer.expires = jiffies + sx_poll; - add_timer (&missed_irq_timer); + setup_timer(&missed_irq_timer, missed_irq, (unsigned long)bp); + mod_timer(&missed_irq_timer, jiffies + sx_poll); #endif printk(KERN_INFO"sx%d: specialix IO8+ board detected at 0x%03x, IRQ %d, CD%d Rev. %c.\n", @@ -2350,10 +2346,8 @@ static void do_softint(struct work_struc return; } - if (test_and_clear_bit(RS_EVENT_WRITE_WAKEUP, &port->event)) { + if (test_and_clear_bit(RS_EVENT_WRITE_WAKEUP, &port->event)) tty_wakeup(tty); - //wake_up_interruptible(&tty->write_wait); - } func_exit(); } @@ -2561,7 +2555,7 @@ static void __exit specialix_exit_module if (sx_board[i].flags & SX_BOARD_PRESENT) sx_release_io_range(&sx_board[i]); #ifdef SPECIALIX_TIMER - del_timer (&missed_irq_timer); + del_timer_sync(&missed_irq_timer); #endif func_exit(); diff --git a/drivers/char/synclink.c b/drivers/char/synclink.c index 3fa625d..ce4db6f 100644 --- a/drivers/char/synclink.c +++ b/drivers/char/synclink.c @@ -1148,10 +1148,8 @@ static void mgsl_bh_transmit(struct mgsl printk( "%s(%d):mgsl_bh_transmit() entry on %s\n", __FILE__,__LINE__,info->device_name); - if (tty) { + if (tty) tty_wakeup(tty); - wake_up_interruptible(&tty->write_wait); - } /* if transmitter idle and loopmode_send_done_requested * then start echoing RxD to TxD @@ -1800,9 +1798,7 @@ static int startup(struct mgsl_struct * memset(&info->icount, 0, sizeof(info->icount)); - init_timer(&info->tx_timer); - info->tx_timer.data = (unsigned long)info; - info->tx_timer.function = mgsl_tx_timeout; + setup_timer(&info->tx_timer, mgsl_tx_timeout, (unsigned long)info); /* Allocate and claim adapter resources */ retval = mgsl_claim_resources(info); @@ -1853,7 +1849,7 @@ static void shutdown(struct mgsl_struct wake_up_interruptible(&info->status_event_wait_q); wake_up_interruptible(&info->event_wait_q); - del_timer(&info->tx_timer); + del_timer_sync(&info->tx_timer); if (info->xmit_buf) { free_page((unsigned long) info->xmit_buf); @@ -2340,7 +2336,6 @@ static void mgsl_flush_buffer(struct tty del_timer(&info->tx_timer); spin_unlock_irqrestore(&info->irq_spinlock,flags); - wake_up_interruptible(&tty->write_wait); tty_wakeup(tty); } @@ -5713,8 +5708,8 @@ static void usc_start_transmitter( struc usc_TCmd( info, TCmd_SendFrame ); - info->tx_timer.expires = jiffies + msecs_to_jiffies(5000); - add_timer(&info->tx_timer); + mod_timer(&info->tx_timer, jiffies + + msecs_to_jiffies(5000)); } info->tx_active = 1; } diff --git a/drivers/char/synclink_gt.c b/drivers/char/synclink_gt.c index 792c79c..0a367cd 100644 --- a/drivers/char/synclink_gt.c +++ b/drivers/char/synclink_gt.c @@ -1045,7 +1045,6 @@ static void flush_buffer(struct tty_stru info->tx_count = 0; spin_unlock_irqrestore(&info->lock,flags); - wake_up_interruptible(&tty->write_wait); tty_wakeup(tty); } @@ -1826,8 +1825,7 @@ static void rx_async(struct slgt_info *i if (i < count) { /* receive buffer not completed */ info->rbuf_index += i; - info->rx_timer.expires = jiffies + 1; - add_timer(&info->rx_timer); + mod_timer(&info->rx_timer, jiffies + 1); break; } @@ -1933,10 +1931,8 @@ static void bh_transmit(struct slgt_info struct tty_struct *tty = info->tty; DBGBH(("%s bh_transmit\n", info->device_name)); - if (tty) { + if (tty) tty_wakeup(tty); - wake_up_interruptible(&tty->write_wait); - } } static void dsr_change(struct slgt_info *info) @@ -3343,13 +3339,8 @@ static struct slgt_info *alloc_dev(int a info->adapter_num = adapter_num; info->port_num = port_num; - init_timer(&info->tx_timer); - info->tx_timer.data = (unsigned long)info; - info->tx_timer.function = tx_timeout; - - init_timer(&info->rx_timer); - info->rx_timer.data = (unsigned long)info; - info->rx_timer.function = rx_timeout; + setup_timer(&info->tx_timer, tx_timeout, (unsigned long)info); + setup_timer(&info->rx_timer, rx_timeout, (unsigned long)info); /* Copy configuration info to device instance data */ info->pdev = pdev; @@ -3797,10 +3788,9 @@ static void tx_start(struct slgt_info *i } } - if (info->params.mode == MGSL_MODE_HDLC) { - info->tx_timer.expires = jiffies + msecs_to_jiffies(5000); - add_timer(&info->tx_timer); - } + if (info->params.mode == MGSL_MODE_HDLC) + mod_timer(&info->tx_timer, jiffies + + msecs_to_jiffies(5000)); } else { tdma_reset(info); /* set 1st descriptor address */ diff --git a/drivers/char/synclinkmp.c b/drivers/char/synclinkmp.c index 8f4d67a..ef93d05 100644 --- a/drivers/char/synclinkmp.c +++ b/drivers/char/synclinkmp.c @@ -1258,7 +1258,6 @@ static void flush_buffer(struct tty_stru del_timer(&info->tx_timer); spin_unlock_irqrestore(&info->lock,flags); - wake_up_interruptible(&tty->write_wait); tty_wakeup(tty); } @@ -2127,10 +2126,8 @@ void bh_transmit(SLMP_INFO *info) printk( "%s(%d):%s bh_transmit() entry\n", __FILE__,__LINE__,info->device_name); - if (tty) { + if (tty) tty_wakeup(tty); - wake_up_interruptible(&tty->write_wait); - } } void bh_status(SLMP_INFO *info) @@ -2747,8 +2744,7 @@ static int startup(SLMP_INFO * info) change_params(info); - info->status_timer.expires = jiffies + msecs_to_jiffies(10); - add_timer(&info->status_timer); + mod_timer(&info->status_timer, jiffies + msecs_to_jiffies(10)); if (info->tty) clear_bit(TTY_IO_ERROR, &info->tty->flags); @@ -3844,13 +3840,9 @@ static SLMP_INFO *alloc_dev(int adapter_ info->bus_type = MGSL_BUS_TYPE_PCI; info->irq_flags = IRQF_SHARED; - init_timer(&info->tx_timer); - info->tx_timer.data = (unsigned long)info; - info->tx_timer.function = tx_timeout; - - init_timer(&info->status_timer); - info->status_timer.data = (unsigned long)info; - info->status_timer.function = status_timeout; + setup_timer(&info->tx_timer, tx_timeout, (unsigned long)info); + setup_timer(&info->status_timer, status_timeout, + (unsigned long)info); /* Store the PCI9050 misc control register value because a flaw * in the PCI9050 prevents LCR registers from being read if @@ -4294,8 +4286,8 @@ void tx_start(SLMP_INFO *info) write_reg(info, TXDMA + DIR, 0x40); /* enable Tx DMA interrupts (EOM) */ write_reg(info, TXDMA + DSR, 0xf2); /* clear Tx DMA IRQs, enable Tx DMA */ - info->tx_timer.expires = jiffies + msecs_to_jiffies(5000); - add_timer(&info->tx_timer); + mod_timer(&info->tx_timer, jiffies + + msecs_to_jiffies(5000)); } else { tx_load_fifo(info); @@ -5577,10 +5569,7 @@ void status_timeout(unsigned long contex if (status) isr_io_pin(info,status); - info->status_timer.data = (unsigned long)info; - info->status_timer.function = status_timeout; - info->status_timer.expires = jiffies + msecs_to_jiffies(10); - add_timer(&info->status_timer); + mod_timer(&info->status_timer, jiffies + msecs_to_jiffies(10)); } diff --git a/drivers/char/sysrq.c b/drivers/char/sysrq.c index 7fd3cd5..1d8c4ae 100644 --- a/drivers/char/sysrq.c +++ b/drivers/char/sysrq.c @@ -36,6 +36,7 @@ #include #include #include #include +#include #include #include @@ -88,9 +89,8 @@ static struct sysrq_key_op sysrq_logleve #ifdef CONFIG_VT static void sysrq_handle_SAK(int key, struct tty_struct *tty) { - if (tty) - do_SAK(tty); - reset_vc(vc_cons[fg_console].d); + struct work_struct *SAK_work = &vc_cons[fg_console].SAK_work; + schedule_work(SAK_work); } static struct sysrq_key_op sysrq_SAK_op = { .handler = sysrq_handle_SAK, @@ -159,6 +159,17 @@ static struct sysrq_key_op sysrq_sync_op .enable_mask = SYSRQ_ENABLE_SYNC, }; +static void sysrq_handle_show_timers(int key, struct tty_struct *tty) +{ + sysrq_timer_list_show(); +} + +static struct sysrq_key_op sysrq_show_timers_op = { + .handler = sysrq_handle_show_timers, + .help_msg = "show-all-timers(Q)", + .action_msg = "Show Pending Timers", +}; + static void sysrq_handle_mountro(int key, struct tty_struct *tty) { emergency_remount(); @@ -336,7 +347,7 @@ static struct sysrq_key_op *sysrq_key_ta /* o: This will often be registered as 'Off' at init time */ NULL, /* o */ &sysrq_showregs_op, /* p */ - NULL, /* q */ + &sysrq_show_timers_op, /* q */ &sysrq_unraw_op, /* r */ &sysrq_sync_op, /* s */ &sysrq_showstate_op, /* t */ diff --git a/drivers/char/tlclk.c b/drivers/char/tlclk.c index 4fac2bd..35e5803 100644 --- a/drivers/char/tlclk.c +++ b/drivers/char/tlclk.c @@ -29,7 +29,6 @@ #include #include -#include #include /* printk() */ #include /* everything... */ #include /* error codes */ diff --git a/drivers/char/toshiba.c b/drivers/char/toshiba.c index 07067c3..5422f99 100644 --- a/drivers/char/toshiba.c +++ b/drivers/char/toshiba.c @@ -58,7 +58,6 @@ #define TOSH_DEBUG 0 #include #include -#include #include #include #include @@ -68,6 +67,7 @@ #include #include #include #include +#include #include @@ -298,12 +298,10 @@ static int tosh_ioctl(struct inode *ip, * Print the information for /proc/toshiba */ #ifdef CONFIG_PROC_FS -static int tosh_get_info(char *buffer, char **start, off_t fpos, int length) +static int proc_toshiba_show(struct seq_file *m, void *v) { - char *temp; int key; - temp = buffer; key = tosh_fn_status(); /* Arguments @@ -314,8 +312,7 @@ static int tosh_get_info(char *buffer, c 4) BIOS date (in SCI date format) 5) Fn Key status */ - - temp += sprintf(temp, "1.1 0x%04x %d.%d %d.%d 0x%04x 0x%02x\n", + seq_printf(m, "1.1 0x%04x %d.%d %d.%d 0x%04x 0x%02x\n", tosh_id, (tosh_sci & 0xff00)>>8, tosh_sci & 0xff, @@ -323,9 +320,21 @@ static int tosh_get_info(char *buffer, c tosh_bios & 0xff, tosh_date, key); + return 0; +} - return temp-buffer; +static int proc_toshiba_open(struct inode *inode, struct file *file) +{ + return single_open(file, proc_toshiba_show, NULL); } + +static const struct file_operations proc_toshiba_fops = { + .owner = THIS_MODULE, + .open = proc_toshiba_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, +}; #endif @@ -508,10 +517,15 @@ static int __init toshiba_init(void) return retval; #ifdef CONFIG_PROC_FS - /* register the proc entry */ - if (create_proc_info_entry("toshiba", 0, NULL, tosh_get_info) == NULL) { - misc_deregister(&tosh_device); - return -ENOMEM; + { + struct proc_dir_entry *pde; + + pde = create_proc_entry("toshiba", 0, NULL); + if (!pde) { + misc_deregister(&tosh_device); + return -ENOMEM; + } + pde->proc_fops = &proc_toshiba_fops; } #endif diff --git a/drivers/char/tpm/tpm.c b/drivers/char/tpm/tpm.c index 33e1f66..e5a254a 100644 --- a/drivers/char/tpm/tpm.c +++ b/drivers/char/tpm/tpm.c @@ -23,7 +23,6 @@ * */ -#include #include #include #include "tpm.h" @@ -1107,9 +1106,8 @@ #define DEVNAME_SIZE 7 INIT_WORK(&chip->work, timeout_work); - init_timer(&chip->user_read_timer); - chip->user_read_timer.function = user_reader_timeout; - chip->user_read_timer.data = (unsigned long) chip; + setup_timer(&chip->user_read_timer, user_reader_timeout, + (unsigned long)chip); memcpy(&chip->vendor, entry, sizeof(struct tpm_vendor_specific)); diff --git a/drivers/char/tpm/tpm_bios.c b/drivers/char/tpm/tpm_bios.c index a611972..4eba32b 100644 --- a/drivers/char/tpm/tpm_bios.c +++ b/drivers/char/tpm/tpm_bios.c @@ -372,10 +372,8 @@ static int read_log(struct tpm_bios_log } /* Find TCPA entry in RSDT (ACPI_LOGICAL_ADDRESSING) */ - status = acpi_get_firmware_table(ACPI_TCPA_SIG, 1, - ACPI_LOGICAL_ADDRESSING, - (struct acpi_table_header **) - &buff); + status = acpi_get_table(ACPI_SIG_TCPA, 1, + (struct acpi_table_header **)&buff); if (ACPI_FAILURE(status)) { printk(KERN_ERR "%s: ERROR - Could not get TCPA table\n", @@ -409,7 +407,7 @@ static int read_log(struct tpm_bios_log log->bios_event_log_end = log->bios_event_log + len; - acpi_os_map_memory(start, len, (void *) &virt); + virt = acpi_os_map_memory(start, len); memcpy(log->bios_event_log, virt, len); @@ -443,7 +441,7 @@ static int tpm_ascii_bios_measurements_o return err; } -struct file_operations tpm_ascii_bios_measurements_ops = { +const struct file_operations tpm_ascii_bios_measurements_ops = { .open = tpm_ascii_bios_measurements_open, .read = seq_read, .llseek = seq_lseek, @@ -476,7 +474,7 @@ static int tpm_binary_bios_measurements_ return err; } -struct file_operations tpm_binary_bios_measurements_ops = { +const struct file_operations tpm_binary_bios_measurements_ops = { .open = tpm_binary_bios_measurements_open, .read = seq_read, .llseek = seq_lseek, diff --git a/drivers/char/tty_io.c b/drivers/char/tty_io.c index 47a6eac..5289254 100644 --- a/drivers/char/tty_io.c +++ b/drivers/char/tty_io.c @@ -154,7 +154,9 @@ static int tty_release(struct inode *, s int tty_ioctl(struct inode * inode, struct file * file, unsigned int cmd, unsigned long arg); static int tty_fasync(int fd, struct file * filp, int on); -static void release_mem(struct tty_struct *tty, int idx); +static void release_tty(struct tty_struct *tty, int idx); +static struct pid *__proc_set_tty(struct task_struct *tsk, + struct tty_struct *tty); /** * alloc_tty_struct - allocate a tty object @@ -1109,17 +1111,17 @@ int tty_check_change(struct tty_struct * { if (current->signal->tty != tty) return 0; - if (tty->pgrp <= 0) { - printk(KERN_WARNING "tty_check_change: tty->pgrp <= 0!\n"); + if (!tty->pgrp) { + printk(KERN_WARNING "tty_check_change: tty->pgrp == NULL!\n"); return 0; } - if (process_group(current) == tty->pgrp) + if (task_pgrp(current) == tty->pgrp) return 0; if (is_ignored(SIGTTOU)) return 0; - if (is_orphaned_pgrp(process_group(current))) + if (is_current_pgrp_orphaned()) return -EIO; - (void) kill_pg(process_group(current), SIGTTOU, 1); + (void) kill_pgrp(task_pgrp(current), SIGTTOU, 1); return -ERESTARTSYS; } @@ -1354,8 +1356,8 @@ static void do_tty_hangup(struct work_st tty_release is called */ read_lock(&tasklist_lock); - if (tty->session > 0) { - do_each_task_pid(tty->session, PIDTYPE_SID, p) { + if (tty->session) { + do_each_pid_task(tty->session, PIDTYPE_SID, p) { spin_lock_irq(&p->sighand->siglock); if (p->signal->tty == tty) p->signal->tty = NULL; @@ -1365,16 +1367,17 @@ static void do_tty_hangup(struct work_st } __group_send_sig_info(SIGHUP, SEND_SIG_PRIV, p); __group_send_sig_info(SIGCONT, SEND_SIG_PRIV, p); - if (tty->pgrp > 0) - p->signal->tty_old_pgrp = tty->pgrp; + put_pid(p->signal->tty_old_pgrp); /* A noop */ + if (tty->pgrp) + p->signal->tty_old_pgrp = get_pid(tty->pgrp); spin_unlock_irq(&p->sighand->siglock); - } while_each_task_pid(tty->session, PIDTYPE_SID, p); + } while_each_pid_task(tty->session, PIDTYPE_SID, p); } read_unlock(&tasklist_lock); tty->flags = 0; - tty->session = 0; - tty->pgrp = -1; + tty->session = NULL; + tty->pgrp = NULL; tty->ctrl_status = 0; /* * If one of the devices matches a console pointer, we @@ -1459,12 +1462,12 @@ int tty_hung_up_p(struct file * filp) EXPORT_SYMBOL(tty_hung_up_p); -static void session_clear_tty(pid_t session) +static void session_clear_tty(struct pid *session) { struct task_struct *p; - do_each_task_pid(session, PIDTYPE_SID, p) { + do_each_pid_task(session, PIDTYPE_SID, p) { proc_clear_tty(p); - } while_each_task_pid(session, PIDTYPE_SID, p); + } while_each_pid_task(session, PIDTYPE_SID, p); } /** @@ -1494,46 +1497,54 @@ static void session_clear_tty(pid_t sess void disassociate_ctty(int on_exit) { struct tty_struct *tty; - int tty_pgrp = -1; - int session; + struct pid *tty_pgrp = NULL; lock_kernel(); mutex_lock(&tty_mutex); tty = get_current_tty(); if (tty) { - tty_pgrp = tty->pgrp; + tty_pgrp = get_pid(tty->pgrp); mutex_unlock(&tty_mutex); /* XXX: here we race, there is nothing protecting tty */ if (on_exit && tty->driver->type != TTY_DRIVER_TYPE_PTY) tty_vhangup(tty); - } else { - pid_t old_pgrp = current->signal->tty_old_pgrp; + } else if (on_exit) { + struct pid *old_pgrp; + spin_lock_irq(¤t->sighand->siglock); + old_pgrp = current->signal->tty_old_pgrp; + current->signal->tty_old_pgrp = NULL; + spin_unlock_irq(¤t->sighand->siglock); if (old_pgrp) { - kill_pg(old_pgrp, SIGHUP, on_exit); - kill_pg(old_pgrp, SIGCONT, on_exit); + kill_pgrp(old_pgrp, SIGHUP, on_exit); + kill_pgrp(old_pgrp, SIGCONT, on_exit); + put_pid(old_pgrp); } mutex_unlock(&tty_mutex); unlock_kernel(); return; } - if (tty_pgrp > 0) { - kill_pg(tty_pgrp, SIGHUP, on_exit); + if (tty_pgrp) { + kill_pgrp(tty_pgrp, SIGHUP, on_exit); if (!on_exit) - kill_pg(tty_pgrp, SIGCONT, on_exit); + kill_pgrp(tty_pgrp, SIGCONT, on_exit); + put_pid(tty_pgrp); } spin_lock_irq(¤t->sighand->siglock); + tty_pgrp = current->signal->tty_old_pgrp; current->signal->tty_old_pgrp = 0; - session = process_session(current); spin_unlock_irq(¤t->sighand->siglock); + put_pid(tty_pgrp); mutex_lock(&tty_mutex); /* It is possible that do_tty_hangup has free'd this tty */ tty = get_current_tty(); if (tty) { - tty->session = 0; - tty->pgrp = 0; + put_pid(tty->session); + put_pid(tty->pgrp); + tty->session = NULL; + tty->pgrp = NULL; } else { #ifdef TTY_DEBUG_HANGUP printk(KERN_DEBUG "error attempted to write to tty [0x%p]" @@ -1544,7 +1555,7 @@ #endif /* Now clear signal->tty under the lock */ read_lock(&tasklist_lock); - session_clear_tty(session); + session_clear_tty(task_session(current)); read_unlock(&tasklist_lock); unlock_kernel(); } @@ -1612,7 +1623,6 @@ void start_tty(struct tty_struct *tty) /* If we have a running line discipline it may need kicking */ tty_wakeup(tty); - wake_up_interruptible(&tty->write_wait); } EXPORT_SYMBOL(start_tty); @@ -2003,7 +2013,7 @@ static int init_dev(struct tty_driver *d /* * All structures have been allocated, so now we install them. - * Failures after this point use release_mem to clean up, so + * Failures after this point use release_tty to clean up, so * there's no need to null out the local pointers. */ if (!(driver->flags & TTY_DRIVER_DEVPTS_MEM)) { @@ -2024,8 +2034,8 @@ static int init_dev(struct tty_driver *d /* * Structures all installed ... call the ldisc open routines. - * If we fail here just call release_mem to clean up. No need - * to decrement the use counts, as release_mem doesn't care. + * If we fail here just call release_tty to clean up. No need + * to decrement the use counts, as release_tty doesn't care. */ if (tty->ldisc.open) { @@ -2095,17 +2105,17 @@ fail_no_mem: retval = -ENOMEM; goto end_init; - /* call the tty release_mem routine to clean out this slot */ + /* call the tty release_tty routine to clean out this slot */ release_mem_out: if (printk_ratelimit()) printk(KERN_INFO "init_dev: ldisc open failed, " "clearing slot %d\n", idx); - release_mem(tty, idx); + release_tty(tty, idx); goto end_init; } /** - * release_mem - release tty structure memory + * release_one_tty - release tty structure memory * * Releases memory associated with a tty structure, and clears out the * driver table slots. This function is called when a device is no longer @@ -2117,37 +2127,14 @@ release_mem_out: * of ttys that the driver keeps. * FIXME: should we require tty_mutex is held here ?? */ - -static void release_mem(struct tty_struct *tty, int idx) +static void release_one_tty(struct tty_struct *tty, int idx) { - struct tty_struct *o_tty; - struct ktermios *tp; int devpts = tty->driver->flags & TTY_DRIVER_DEVPTS_MEM; - - if ((o_tty = tty->link) != NULL) { - if (!devpts) - o_tty->driver->ttys[idx] = NULL; - if (o_tty->driver->flags & TTY_DRIVER_RESET_TERMIOS) { - tp = o_tty->termios; - if (!devpts) - o_tty->driver->termios[idx] = NULL; - kfree(tp); - - tp = o_tty->termios_locked; - if (!devpts) - o_tty->driver->termios_locked[idx] = NULL; - kfree(tp); - } - o_tty->magic = 0; - o_tty->driver->refcount--; - file_list_lock(); - list_del_init(&o_tty->tty_files); - file_list_unlock(); - free_tty_struct(o_tty); - } + struct ktermios *tp; if (!devpts) tty->driver->ttys[idx] = NULL; + if (tty->driver->flags & TTY_DRIVER_RESET_TERMIOS) { tp = tty->termios; if (!devpts) @@ -2160,15 +2147,39 @@ static void release_mem(struct tty_struc kfree(tp); } + tty->magic = 0; tty->driver->refcount--; + file_list_lock(); list_del_init(&tty->tty_files); file_list_unlock(); - module_put(tty->driver->owner); + free_tty_struct(tty); } +/** + * release_tty - release tty structure memory + * + * Release both @tty and a possible linked partner (think pty pair), + * and decrement the refcount of the backing module. + * + * Locking: + * tty_mutex - sometimes only + * takes the file list lock internally when working on the list + * of ttys that the driver keeps. + * FIXME: should we require tty_mutex is held here ?? + */ +static void release_tty(struct tty_struct *tty, int idx) +{ + struct tty_driver *driver = tty->driver; + + if (tty->link) + release_one_tty(tty->link, idx); + release_one_tty(tty, idx); + module_put(driver->owner); +} + /* * Even releasing the tty structures is a tricky business.. We have * to be very careful that the structures are all released at the @@ -2436,10 +2447,10 @@ #endif tty_set_termios_ldisc(o_tty,N_TTY); } /* - * The release_mem function takes care of the details of clearing + * The release_tty function takes care of the details of clearing * the slots and preserving the termios structure. */ - release_mem(tty, idx); + release_tty(tty, idx); #ifdef CONFIG_UNIX98_PTYS /* Make this pty number available for reallocation */ @@ -2481,6 +2492,7 @@ static int tty_open(struct inode * inode int index; dev_t device = inode->i_rdev; unsigned short saved_flags = filp->f_flags; + struct pid *old_pgrp; nonseekable_open(inode, filp); @@ -2574,15 +2586,17 @@ #endif goto retry_open; } + old_pgrp = NULL; mutex_lock(&tty_mutex); spin_lock_irq(¤t->sighand->siglock); if (!noctty && current->signal->leader && !current->signal->tty && - tty->session == 0) - __proc_set_tty(current, tty); + tty->session == NULL) + old_pgrp = __proc_set_tty(current, tty); spin_unlock_irq(¤t->sighand->siglock); mutex_unlock(&tty_mutex); + put_pid(old_pgrp); return 0; } @@ -2721,9 +2735,18 @@ static int tty_fasync(int fd, struct fil return retval; if (on) { + enum pid_type type; + struct pid *pid; if (!waitqueue_active(&tty->read_wait)) tty->minimum_to_wake = 1; - retval = f_setown(filp, (-tty->pgrp) ? : current->pid, 0); + if (tty->pgrp) { + pid = tty->pgrp; + type = PIDTYPE_PGID; + } else { + pid = task_pid(current); + type = PIDTYPE_PID; + } + retval = __f_setown(filp, pid, type, 0); if (retval) return retval; } else { @@ -2825,10 +2848,10 @@ #ifdef CONFIG_VT } } #endif - if (tty->pgrp > 0) - kill_pg(tty->pgrp, SIGWINCH, 1); - if ((real_tty->pgrp != tty->pgrp) && (real_tty->pgrp > 0)) - kill_pg(real_tty->pgrp, SIGWINCH, 1); + if (tty->pgrp) + kill_pgrp(tty->pgrp, SIGWINCH, 1); + if ((real_tty->pgrp != tty->pgrp) && real_tty->pgrp) + kill_pgrp(real_tty->pgrp, SIGWINCH, 1); tty->winsize = tmp_ws; real_tty->winsize = tmp_ws; done: @@ -2913,8 +2936,7 @@ static int fionbio(struct file *file, in static int tiocsctty(struct tty_struct *tty, int arg) { int ret = 0; - if (current->signal->leader && - (process_session(current) == tty->session)) + if (current->signal->leader && (task_session(current) == tty->session)) return ret; mutex_lock(&tty_mutex); @@ -2927,7 +2949,7 @@ static int tiocsctty(struct tty_struct * goto unlock; } - if (tty->session > 0) { + if (tty->session) { /* * This tty is already the controlling * tty for another session group! @@ -2970,7 +2992,7 @@ static int tiocgpgrp(struct tty_struct * */ if (tty == real_tty && current->signal->tty != real_tty) return -ENOTTY; - return put_user(real_tty->pgrp, p); + return put_user(pid_nr(real_tty->pgrp), p); } /** @@ -2987,7 +3009,8 @@ static int tiocgpgrp(struct tty_struct * static int tiocspgrp(struct tty_struct *tty, struct tty_struct *real_tty, pid_t __user *p) { - pid_t pgrp; + struct pid *pgrp; + pid_t pgrp_nr; int retval = tty_check_change(real_tty); if (retval == -EIO) @@ -2996,16 +3019,26 @@ static int tiocspgrp(struct tty_struct * return retval; if (!current->signal->tty || (current->signal->tty != real_tty) || - (real_tty->session != process_session(current))) + (real_tty->session != task_session(current))) return -ENOTTY; - if (get_user(pgrp, p)) + if (get_user(pgrp_nr, p)) return -EFAULT; - if (pgrp < 0) + if (pgrp_nr < 0) return -EINVAL; - if (session_of_pgrp(pgrp) != process_session(current)) - return -EPERM; - real_tty->pgrp = pgrp; - return 0; + rcu_read_lock(); + pgrp = find_pid(pgrp_nr); + retval = -ESRCH; + if (!pgrp) + goto out_unlock; + retval = -EPERM; + if (session_of_pgrp(pgrp) != task_session(current)) + goto out_unlock; + retval = 0; + put_pid(real_tty->pgrp); + real_tty->pgrp = get_pid(pgrp); +out_unlock: + rcu_read_unlock(); + return retval; } /** @@ -3028,9 +3061,9 @@ static int tiocgsid(struct tty_struct *t */ if (tty == real_tty && current->signal->tty != real_tty) return -ENOTTY; - if (real_tty->session <= 0) + if (!real_tty->session) return -ENOTTY; - return put_user(real_tty->session, p); + return put_user(pid_nr(real_tty->session), p); } /** @@ -3324,15 +3357,13 @@ #endif * Nasty bug: do_SAK is being called in interrupt context. This can * deadlock. We punt it up to process context. AKPM - 16Mar2001 */ -static void __do_SAK(struct work_struct *work) +void __do_SAK(struct tty_struct *tty) { - struct tty_struct *tty = - container_of(work, struct tty_struct, SAK_work); #ifdef TTY_SOFT_SAK tty_hangup(tty); #else struct task_struct *g, *p; - int session; + struct pid *session; int i; struct file *filp; struct fdtable *fdt; @@ -3348,12 +3379,12 @@ #else read_lock(&tasklist_lock); /* Kill the entire session */ - do_each_task_pid(session, PIDTYPE_SID, p) { + do_each_pid_task(session, PIDTYPE_SID, p) { printk(KERN_NOTICE "SAK: killed process %d" " (%s): process_session(p)==tty->session\n", p->pid, p->comm); send_sig(SIGKILL, p, 1); - } while_each_task_pid(session, PIDTYPE_SID, p); + } while_each_pid_task(session, PIDTYPE_SID, p); /* Now kill any processes that happen to have the * tty open. */ @@ -3394,6 +3425,13 @@ #else #endif } +static void do_SAK_work(struct work_struct *work) +{ + struct tty_struct *tty = + container_of(work, struct tty_struct, SAK_work); + __do_SAK(tty); +} + /* * The tq handling here is a little racy - tty->SAK_work may already be queued. * Fortunately we don't need to worry, because if ->SAK_work is already queued, @@ -3404,7 +3442,6 @@ void do_SAK(struct tty_struct *tty) { if (!tty) return; - PREPARE_WORK(&tty->SAK_work, __do_SAK); schedule_work(&tty->SAK_work); } @@ -3515,7 +3552,8 @@ static void initialize_tty_struct(struct memset(tty, 0, sizeof(struct tty_struct)); tty->magic = TTY_MAGIC; tty_ldisc_assign(tty, tty_ldisc_get(N_TTY)); - tty->pgrp = -1; + tty->session = NULL; + tty->pgrp = NULL; tty->overrun_time = jiffies; tty->buf.head = tty->buf.tail = NULL; tty_buffer_init(tty); @@ -3529,7 +3567,7 @@ static void initialize_tty_struct(struct mutex_init(&tty->atomic_write_lock); spin_lock_init(&tty->read_lock); INIT_LIST_HEAD(&tty->tty_files); - INIT_WORK(&tty->SAK_work, NULL); + INIT_WORK(&tty->SAK_work, do_SAK_work); } /* @@ -3786,21 +3824,28 @@ void proc_clear_tty(struct task_struct * } EXPORT_SYMBOL(proc_clear_tty); -void __proc_set_tty(struct task_struct *tsk, struct tty_struct *tty) +static struct pid *__proc_set_tty(struct task_struct *tsk, struct tty_struct *tty) { + struct pid *old_pgrp; if (tty) { - tty->session = process_session(tsk); - tty->pgrp = process_group(tsk); + tty->session = get_pid(task_session(tsk)); + tty->pgrp = get_pid(task_pgrp(tsk)); } + old_pgrp = tsk->signal->tty_old_pgrp; tsk->signal->tty = tty; - tsk->signal->tty_old_pgrp = 0; + tsk->signal->tty_old_pgrp = NULL; + return old_pgrp; } void proc_set_tty(struct task_struct *tsk, struct tty_struct *tty) { + struct pid *old_pgrp; + spin_lock_irq(&tsk->sighand->siglock); - __proc_set_tty(tsk, tty); + old_pgrp = __proc_set_tty(tsk, tty); spin_unlock_irq(&tsk->sighand->siglock); + + put_pid(old_pgrp); } struct tty_struct *get_current_tty(void) diff --git a/drivers/char/tty_ioctl.c b/drivers/char/tty_ioctl.c index dee47f4..fd471cb 100644 --- a/drivers/char/tty_ioctl.c +++ b/drivers/char/tty_ioctl.c @@ -225,7 +225,7 @@ #ifdef BOTHER /** * tty_termios_encode_baud_rate - * @termios: termios structure + * @termios: ktermios structure holding user requested state * @ispeed: input speed * @ospeed: output speed * @@ -233,7 +233,10 @@ #ifdef BOTHER * used as a library helper for drivers os that they can report back * the actual speed selected when it differs from the speed requested * - * For now input and output speed must agree. + * For maximal back compatibility with legacy SYS5/POSIX *nix behaviour + * we need to carefully set the bits when the user does not get the + * desired speed. We allow small margins and preserve as much of possible + * of the input intent to keep compatiblity. * * Locking: Caller should hold termios lock. This is already held * when calling this function from the driver termios handler. @@ -242,32 +245,44 @@ #ifdef BOTHER void tty_termios_encode_baud_rate(struct ktermios *termios, speed_t ibaud, speed_t obaud) { int i = 0; - int ifound = 0, ofound = 0; + int ifound = -1, ofound = -1; + int iclose = ibaud/50, oclose = obaud/50; + int ibinput = 0; termios->c_ispeed = ibaud; termios->c_ospeed = obaud; + /* If the user asked for a precise weird speed give a precise weird + answer. If they asked for a Bfoo speed they many have problems + digesting non-exact replies so fuzz a bit */ + + if ((termios->c_cflag & CBAUD) == BOTHER) + oclose = 0; + if (((termios->c_cflag >> IBSHIFT) & CBAUD) == BOTHER) + iclose = 0; + if ((termios->c_cflag >> IBSHIFT) & CBAUD) + ibinput = 1; /* An input speed was specified */ + termios->c_cflag &= ~CBAUD; - /* Identical speed means no input encoding (ie B0 << IBSHIFT)*/ - if (termios->c_ispeed == termios->c_ospeed) - ifound = 1; do { - if (obaud == baud_table[i]) { + if (obaud - oclose >= baud_table[i] && obaud + oclose <= baud_table[i]) { termios->c_cflag |= baud_bits[i]; - ofound = 1; - /* So that if ibaud == obaud we don't set it */ - continue; + ofound = i; } - if (ibaud == baud_table[i]) { - termios->c_cflag |= (baud_bits[i] << IBSHIFT); - ifound = 1; + if (ibaud - iclose >= baud_table[i] && ibaud + iclose <= baud_table[i]) { + /* For the case input == output don't set IBAUD bits if the user didn't do so */ + if (ofound != i || ibinput) + termios->c_cflag |= (baud_bits[i] << IBSHIFT); + ifound = i; } } while(++i < n_baud_table); - if (!ofound) + if (ofound == -1) termios->c_cflag |= BOTHER; - if (!ifound) + /* Set exact input bits only if the input and output differ or the + user already did */ + if (ifound == -1 && (ibaud != obaud || ibinput)) termios->c_cflag |= (BOTHER << IBSHIFT); } diff --git a/drivers/char/vc_screen.c b/drivers/char/vc_screen.c index 2677651..7919303 100644 --- a/drivers/char/vc_screen.c +++ b/drivers/char/vc_screen.c @@ -25,7 +25,6 @@ #include #include #include #include -#include #include #include #include diff --git a/drivers/char/viotape.c b/drivers/char/viotape.c index 9438512..13faf8d 100644 --- a/drivers/char/viotape.c +++ b/drivers/char/viotape.c @@ -872,7 +872,7 @@ free_op: return ret; } -struct file_operations viotap_fops = { +const struct file_operations viotap_fops = { owner: THIS_MODULE, read: viotap_read, write: viotap_write, diff --git a/drivers/char/vme_scc.c b/drivers/char/vme_scc.c index e01317c..bef6d88 100644 --- a/drivers/char/vme_scc.c +++ b/drivers/char/vme_scc.c @@ -17,7 +17,6 @@ #include #include #include #include -#include #include #include #include diff --git a/drivers/char/vt.c b/drivers/char/vt.c index 06c32a3..c3f8e38 100644 --- a/drivers/char/vt.c +++ b/drivers/char/vt.c @@ -136,9 +136,6 @@ #define CTRL_ALWAYS 0x0800f501 /* Cannot #define DEFAULT_BELL_PITCH 750 #define DEFAULT_BELL_DURATION (HZ/8) -extern void vcs_make_sysfs(struct tty_struct *tty); -extern void vcs_remove_sysfs(struct tty_struct *tty); - struct vc vc_cons [MAX_NR_CONSOLES]; #ifndef VT_SINGLE_DRIVER @@ -213,7 +210,7 @@ static int scrollback_delta; */ int (*console_blank_hook)(int); -static struct timer_list console_timer; +static DEFINE_TIMER(console_timer, blank_screen_t, 0, 0); static int blank_state; static int blank_timer_expired; enum { @@ -869,8 +866,8 @@ int vc_resize(struct vc_data *vc, unsign ws.ws_col = vc->vc_cols; ws.ws_ypixel = vc->vc_scan_lines; if ((ws.ws_row != cws->ws_row || ws.ws_col != cws->ws_col) && - vc->vc_tty->pgrp > 0) - kill_pg(vc->vc_tty->pgrp, SIGWINCH, 1); + vc->vc_tty->pgrp) + kill_pgrp(vc->vc_tty->pgrp, SIGWINCH, 1); *cws = ws; } @@ -2628,8 +2625,6 @@ static int __init con_init(void) for (i = 0; i < MAX_NR_CONSOLES; i++) con_driver_map[i] = conswitchp; - init_timer(&console_timer); - console_timer.function = blank_screen_t; if (blankinterval) { blank_state = blank_normal_wait; mod_timer(&console_timer, jiffies + blankinterval); @@ -2640,6 +2635,7 @@ static int __init con_init(void) */ for (currcons = 0; currcons < MIN_NR_CONSOLES; currcons++) { vc_cons[currcons].d = vc = alloc_bootmem(sizeof(struct vc_data)); + INIT_WORK(&vc_cons[currcons].SAK_work, vc_SAK); visual_init(vc, currcons, 1); vc->vc_screenbuf = (unsigned short *)alloc_bootmem(vc->vc_screenbuf_size); vc->vc_kmalloced = 0; diff --git a/drivers/char/vt_ioctl.c b/drivers/char/vt_ioctl.c index dc8368e..3a5d301 100644 --- a/drivers/char/vt_ioctl.c +++ b/drivers/char/vt_ioctl.c @@ -672,7 +672,8 @@ #endif vc->vt_mode = tmp; /* the frsig is ignored, so we set it to 0 */ vc->vt_mode.frsig = 0; - put_pid(xchg(&vc->vt_pid, get_pid(task_pid(current)))); + put_pid(vc->vt_pid); + vc->vt_pid = get_pid(task_pid(current)); /* no switch is required -- saw@shade.msu.ru */ vc->vt_newvt = -1; release_console_sem(); @@ -1063,12 +1064,35 @@ void reset_vc(struct vc_data *vc) vc->vt_mode.relsig = 0; vc->vt_mode.acqsig = 0; vc->vt_mode.frsig = 0; - put_pid(xchg(&vc->vt_pid, NULL)); + put_pid(vc->vt_pid); + vc->vt_pid = NULL; vc->vt_newvt = -1; if (!in_interrupt()) /* Via keyboard.c:SAK() - akpm */ reset_palette(vc); } +void vc_SAK(struct work_struct *work) +{ + struct vc *vc_con = + container_of(work, struct vc, SAK_work); + struct vc_data *vc; + struct tty_struct *tty; + + acquire_console_sem(); + vc = vc_con->d; + if (vc) { + tty = vc->vc_tty; + /* + * SAK should also work in all raw modes and reset + * them properly. + */ + if (tty) + __do_SAK(tty); + reset_vc(vc); + } + release_console_sem(); +} + /* * Performs the back end of a vt switch */ diff --git a/drivers/char/watchdog/acquirewdt.c b/drivers/char/watchdog/acquirewdt.c index 154d67e..85269c3 100644 --- a/drivers/char/watchdog/acquirewdt.c +++ b/drivers/char/watchdog/acquirewdt.c @@ -48,46 +48,52 @@ * It can be 1, 2, 10, 20, 110 or 220 seconds. */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include +/* + * Includes, defines, variables, module parameters, ... + */ +/* Includes */ +#include /* For module specific items */ +#include /* For new moduleparam's */ +#include /* For standard types (like size_t) */ +#include /* For the -ENODEV/... values */ +#include /* For printk/panic/... */ +#include /* For MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR) */ +#include /* For the watchdog specific items */ +#include /* For file operations */ +#include /* For io-port access */ +#include /* For platform_driver framework */ +#include /* For __init/__exit/... */ + +#include /* For copy_to_user/put_user/... */ +#include /* For inb/outb/... */ + +/* Module information */ +#define DRV_NAME "acquirewdt" +#define PFX DRV_NAME ": " #define WATCHDOG_NAME "Acquire WDT" -#define PFX WATCHDOG_NAME ": " #define WATCHDOG_HEARTBEAT 0 /* There is no way to see what the correct time-out period is */ +/* internal variables */ +static struct platform_device *acq_platform_device; /* the watchdog platform device */ static unsigned long acq_is_open; static char expect_close; -/* - * You must set these - there is no sane way to probe for this board. - */ - -static int wdt_stop = 0x43; +/* module parameters */ +static int wdt_stop = 0x43; /* You must set this - there is no sane way to probe for this board. */ module_param(wdt_stop, int, 0); MODULE_PARM_DESC(wdt_stop, "Acquire WDT 'stop' io port (default 0x43)"); -static int wdt_start = 0x443; +static int wdt_start = 0x443; /* You must set this - there is no sane way to probe for this board. */ module_param(wdt_start, int, 0); MODULE_PARM_DESC(wdt_start, "Acquire WDT 'start' io port (default 0x443)"); static int nowayout = WATCHDOG_NOWAYOUT; module_param(nowayout, int, 0); -MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=CONFIG_WATCHDOG_NOWAYOUT)"); +MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=" __MODULE_STRING(WATCHDOG_NOWAYOUT) ")"); /* - * Kernel methods. + * Watchdog Operations */ static void acq_keepalive(void) @@ -103,7 +109,7 @@ static void acq_stop(void) } /* - * /dev/watchdog handling. + * /dev/watchdog handling */ static ssize_t acq_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos) @@ -143,7 +149,7 @@ static int acq_ioctl(struct inode *inode { .options = WDIOF_KEEPALIVEPING | WDIOF_MAGICCLOSE, .firmware_version = 1, - .identity = "Acquire WDT", + .identity = WATCHDOG_NAME, }; switch(cmd) @@ -214,20 +220,6 @@ static int acq_close(struct inode *inode } /* - * Notifier for system down - */ - -static int acq_notify_sys(struct notifier_block *this, unsigned long code, - void *unused) -{ - if(code==SYS_DOWN || code==SYS_HALT) { - /* Turn the WDT off */ - acq_stop(); - } - return NOTIFY_DONE; -} - -/* * Kernel Interfaces */ @@ -240,29 +232,20 @@ static const struct file_operations acq_ .release = acq_close, }; -static struct miscdevice acq_miscdev= -{ - .minor = WATCHDOG_MINOR, - .name = "watchdog", - .fops = &acq_fops, +static struct miscdevice acq_miscdev = { + .minor = WATCHDOG_MINOR, + .name = "watchdog", + .fops = &acq_fops, }; /* - * The WDT card needs to learn about soft shutdowns in order to - * turn the timebomb registers off. + * Init & exit routines */ -static struct notifier_block acq_notifier = -{ - .notifier_call = acq_notify_sys, -}; - -static int __init acq_init(void) +static int __devinit acq_probe(struct platform_device *dev) { int ret; - printk(KERN_INFO "WDT driver for Acquire single board computer initialising.\n"); - if (wdt_stop != wdt_start) { if (!request_region(wdt_stop, 1, WATCHDOG_NAME)) { printk (KERN_ERR PFX "I/O address 0x%04x already in use\n", @@ -279,18 +262,11 @@ static int __init acq_init(void) goto unreg_stop; } - ret = register_reboot_notifier(&acq_notifier); - if (ret != 0) { - printk (KERN_ERR PFX "cannot register reboot notifier (err=%d)\n", - ret); - goto unreg_regions; - } - ret = misc_register(&acq_miscdev); if (ret != 0) { printk (KERN_ERR PFX "cannot register miscdev on minor=%d (err=%d)\n", WATCHDOG_MINOR, ret); - goto unreg_reboot; + goto unreg_regions; } printk (KERN_INFO PFX "initialized. (nowayout=%d)\n", @@ -298,8 +274,6 @@ static int __init acq_init(void) return 0; -unreg_reboot: - unregister_reboot_notifier(&acq_notifier); unreg_regions: release_region(wdt_start, 1); unreg_stop: @@ -309,13 +283,60 @@ out: return ret; } -static void __exit acq_exit(void) +static int __devexit acq_remove(struct platform_device *dev) { misc_deregister(&acq_miscdev); - unregister_reboot_notifier(&acq_notifier); + release_region(wdt_start,1); if(wdt_stop != wdt_start) release_region(wdt_stop,1); - release_region(wdt_start,1); + + return 0; +} + +static void acq_shutdown(struct platform_device *dev) +{ + /* Turn the WDT off if we have a soft shutdown */ + acq_stop(); +} + +static struct platform_driver acquirewdt_driver = { + .probe = acq_probe, + .remove = __devexit_p(acq_remove), + .shutdown = acq_shutdown, + .driver = { + .owner = THIS_MODULE, + .name = DRV_NAME, + }, +}; + +static int __init acq_init(void) +{ + int err; + + printk(KERN_INFO "WDT driver for Acquire single board computer initialising.\n"); + + err = platform_driver_register(&acquirewdt_driver); + if (err) + return err; + + acq_platform_device = platform_device_register_simple(DRV_NAME, -1, NULL, 0); + if (IS_ERR(acq_platform_device)) { + err = PTR_ERR(acq_platform_device); + goto unreg_platform_driver; + } + + return 0; + +unreg_platform_driver: + platform_driver_unregister(&acquirewdt_driver); + return err; +} + +static void __exit acq_exit(void) +{ + platform_device_unregister(acq_platform_device); + platform_driver_unregister(&acquirewdt_driver); + printk(KERN_INFO PFX "Watchdog Module Unloaded.\n"); } module_init(acq_init); diff --git a/drivers/char/watchdog/advantechwdt.c b/drivers/char/watchdog/advantechwdt.c index 9d73276..8121cc2 100644 --- a/drivers/char/watchdog/advantechwdt.c +++ b/drivers/char/watchdog/advantechwdt.c @@ -35,18 +35,19 @@ #include #include #include #include -#include -#include +#include #include #include #include #include +#define DRV_NAME "advantechwdt" +#define PFX DRV_NAME ": " #define WATCHDOG_NAME "Advantech WDT" -#define PFX WATCHDOG_NAME ": " #define WATCHDOG_TIMEOUT 60 /* 60 sec default timeout */ +static struct platform_device *advwdt_platform_device; /* the watchdog platform device */ static unsigned long advwdt_is_open; static char adv_expect_close; @@ -75,10 +76,10 @@ MODULE_PARM_DESC(timeout, "Watchdog time static int nowayout = WATCHDOG_NOWAYOUT; module_param(nowayout, int, 0); -MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=CONFIG_WATCHDOG_NOWAYOUT)"); +MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=" __MODULE_STRING(WATCHDOG_NOWAYOUT) ")"); /* - * Kernel methods. + * Watchdog Operations */ static void @@ -94,6 +95,20 @@ advwdt_disable(void) inb_p(wdt_stop); } +static int +advwdt_set_heartbeat(int t) +{ + if ((t < 1) || (t > 63)) + return -EINVAL; + + timeout = t; + return 0; +} + +/* + * /dev/watchdog handling + */ + static ssize_t advwdt_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos) { @@ -126,7 +141,7 @@ advwdt_ioctl(struct inode *inode, struct static struct watchdog_info ident = { .options = WDIOF_KEEPALIVEPING | WDIOF_SETTIMEOUT | WDIOF_MAGICCLOSE, .firmware_version = 1, - .identity = "Advantech WDT", + .identity = WATCHDOG_NAME, }; switch (cmd) { @@ -146,9 +161,8 @@ advwdt_ioctl(struct inode *inode, struct case WDIOC_SETTIMEOUT: if (get_user(new_timeout, p)) return -EFAULT; - if ((new_timeout < 1) || (new_timeout > 63)) + if (advwdt_set_heartbeat(new_timeout)) return -EINVAL; - timeout = new_timeout; advwdt_ping(); /* Fall */ @@ -209,21 +223,6 @@ advwdt_close(struct inode *inode, struct } /* - * Notifier for system down - */ - -static int -advwdt_notify_sys(struct notifier_block *this, unsigned long code, - void *unused) -{ - if (code == SYS_DOWN || code == SYS_HALT) { - /* Turn the WDT off */ - advwdt_disable(); - } - return NOTIFY_DONE; -} - -/* * Kernel Interfaces */ @@ -237,33 +236,20 @@ static const struct file_operations advw }; static struct miscdevice advwdt_miscdev = { - .minor = WATCHDOG_MINOR, - .name = "watchdog", - .fops = &advwdt_fops, + .minor = WATCHDOG_MINOR, + .name = "watchdog", + .fops = &advwdt_fops, }; /* - * The WDT needs to learn about soft shutdowns in order to - * turn the timebomb registers off. + * Init & exit routines */ -static struct notifier_block advwdt_notifier = { - .notifier_call = advwdt_notify_sys, -}; - -static int __init -advwdt_init(void) +static int __devinit +advwdt_probe(struct platform_device *dev) { int ret; - printk(KERN_INFO "WDT driver for Advantech single board computer initialising.\n"); - - if (timeout < 1 || timeout > 63) { - timeout = WATCHDOG_TIMEOUT; - printk (KERN_INFO PFX "timeout value must be 1<=x<=63, using %d\n", - timeout); - } - if (wdt_stop != wdt_start) { if (!request_region(wdt_stop, 1, WATCHDOG_NAME)) { printk (KERN_ERR PFX "I/O address 0x%04x already in use\n", @@ -280,18 +266,18 @@ advwdt_init(void) goto unreg_stop; } - ret = register_reboot_notifier(&advwdt_notifier); - if (ret != 0) { - printk (KERN_ERR PFX "cannot register reboot notifier (err=%d)\n", - ret); - goto unreg_regions; + /* Check that the heartbeat value is within it's range ; if not reset to the default */ + if (advwdt_set_heartbeat(timeout)) { + advwdt_set_heartbeat(WATCHDOG_TIMEOUT); + printk (KERN_INFO PFX "timeout value must be 1<=x<=63, using %d\n", + timeout); } ret = misc_register(&advwdt_miscdev); if (ret != 0) { printk (KERN_ERR PFX "cannot register miscdev on minor=%d (err=%d)\n", WATCHDOG_MINOR, ret); - goto unreg_reboot; + goto unreg_regions; } printk (KERN_INFO PFX "initialized. timeout=%d sec (nowayout=%d)\n", @@ -299,8 +285,6 @@ advwdt_init(void) out: return ret; -unreg_reboot: - unregister_reboot_notifier(&advwdt_notifier); unreg_regions: release_region(wdt_start, 1); unreg_stop: @@ -309,14 +293,64 @@ unreg_stop: goto out; } -static void __exit -advwdt_exit(void) +static int __devexit +advwdt_remove(struct platform_device *dev) { misc_deregister(&advwdt_miscdev); - unregister_reboot_notifier(&advwdt_notifier); + release_region(wdt_start,1); if(wdt_stop != wdt_start) release_region(wdt_stop,1); - release_region(wdt_start,1); + + return 0; +} + +static void +advwdt_shutdown(struct platform_device *dev) +{ + /* Turn the WDT off if we have a soft shutdown */ + advwdt_disable(); +} + +static struct platform_driver advwdt_driver = { + .probe = advwdt_probe, + .remove = __devexit_p(advwdt_remove), + .shutdown = advwdt_shutdown, + .driver = { + .owner = THIS_MODULE, + .name = DRV_NAME, + }, +}; + +static int __init +advwdt_init(void) +{ + int err; + + printk(KERN_INFO "WDT driver for Advantech single board computer initialising.\n"); + + err = platform_driver_register(&advwdt_driver); + if (err) + return err; + + advwdt_platform_device = platform_device_register_simple(DRV_NAME, -1, NULL, 0); + if (IS_ERR(advwdt_platform_device)) { + err = PTR_ERR(advwdt_platform_device); + goto unreg_platform_driver; + } + + return 0; + +unreg_platform_driver: + platform_driver_unregister(&advwdt_driver); + return err; +} + +static void __exit +advwdt_exit(void) +{ + platform_device_unregister(advwdt_platform_device); + platform_driver_unregister(&advwdt_driver); + printk(KERN_INFO PFX "Watchdog Module Unloaded.\n"); } module_init(advwdt_init); diff --git a/drivers/char/watchdog/alim1535_wdt.c b/drivers/char/watchdog/alim1535_wdt.c index 01b0d13..e3f6a7d 100644 --- a/drivers/char/watchdog/alim1535_wdt.c +++ b/drivers/char/watchdog/alim1535_wdt.c @@ -40,7 +40,7 @@ MODULE_PARM_DESC(timeout, "Watchdog time static int nowayout = WATCHDOG_NOWAYOUT; module_param(nowayout, int, 0); -MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=CONFIG_WATCHDOG_NOWAYOUT)"); +MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=" __MODULE_STRING(WATCHDOG_NOWAYOUT) ")"); /* * ali_start - start watchdog countdown diff --git a/drivers/char/watchdog/alim7101_wdt.c b/drivers/char/watchdog/alim7101_wdt.c index bf25d0a..67aed9f 100644 --- a/drivers/char/watchdog/alim7101_wdt.c +++ b/drivers/char/watchdog/alim7101_wdt.c @@ -69,7 +69,7 @@ module_param(use_gpio, int, 0); MODULE_PARM_DESC(use_gpio, "Use the gpio watchdog. (required by old cobalt boards)"); static void wdt_timer_ping(unsigned long); -static struct timer_list timer; +static DEFINE_TIMER(timer, wdt_timer_ping, 0, 1); static unsigned long next_heartbeat; static unsigned long wdt_is_open; static char wdt_expect_close; @@ -78,7 +78,7 @@ static struct pci_dev *alim7101_pmu; static int nowayout = WATCHDOG_NOWAYOUT; module_param(nowayout, int, 0); MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=" - __stringify(CONFIG_WATCHDOG_NOWAYOUT) ")"); + __MODULE_STRING(WATCHDOG_NOWAYOUT) ")"); /* * Whack the dog @@ -108,8 +108,7 @@ static void wdt_timer_ping(unsigned long printk(KERN_WARNING PFX "Heartbeat lost! Will not ping the watchdog\n"); } /* Re-set the timer interval */ - timer.expires = jiffies + WDT_INTERVAL; - add_timer(&timer); + mod_timer(&timer, jiffies + WDT_INTERVAL); } /* @@ -147,9 +146,7 @@ static void wdt_startup(void) wdt_change(WDT_ENABLE); /* Start the timer */ - timer.expires = jiffies + WDT_INTERVAL; - add_timer(&timer); - + mod_timer(&timer, jiffies + WDT_INTERVAL); printk(KERN_INFO PFX "Watchdog timer is now enabled.\n"); } @@ -380,10 +377,6 @@ static int __init alim7101_wdt_init(void timeout); } - init_timer(&timer); - timer.function = wdt_timer_ping; - timer.data = 1; - rc = misc_register(&wdt_miscdev); if (rc) { printk(KERN_ERR PFX "cannot register miscdev on minor=%d (err=%d)\n", @@ -417,10 +410,8 @@ module_init(alim7101_wdt_init); module_exit(alim7101_wdt_unload); static struct pci_device_id alim7101_pci_tbl[] __devinitdata = { - { PCI_VENDOR_ID_AL, PCI_DEVICE_ID_AL_M1533, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, - { PCI_VENDOR_ID_AL, PCI_DEVICE_ID_AL_M7101, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, + { PCI_DEVICE(PCI_VENDOR_ID_AL, PCI_DEVICE_ID_AL_M1533) }, + { PCI_DEVICE(PCI_VENDOR_ID_AL, PCI_DEVICE_ID_AL_M7101) }, { } }; diff --git a/drivers/char/watchdog/booke_wdt.c b/drivers/char/watchdog/booke_wdt.c index 4889022..0e23f29 100644 --- a/drivers/char/watchdog/booke_wdt.c +++ b/drivers/char/watchdog/booke_wdt.c @@ -35,7 +35,7 @@ #include #ifdef CONFIG_FSL_BOOKE #define WDT_PERIOD_DEFAULT 63 /* Ex. wdt_period=28 bus=333Mhz , reset=~40sec */ #else -#define WDT_PERIOD_DEFAULT 4 /* Refer to the PPC40x and PPC4xx manuals */ +#define WDT_PERIOD_DEFAULT 3 /* Refer to the PPC40x and PPC4xx manuals */ #endif /* for timing information */ u32 booke_wdt_enabled = 0; @@ -48,12 +48,22 @@ #define WDTP(x) (TCR_WP(x)) #endif /* + * booke_wdt_ping: + */ +static __inline__ void booke_wdt_ping(void) +{ + mtspr(SPRN_TSR, TSR_ENW|TSR_WIS); +} + +/* * booke_wdt_enable: */ static __inline__ void booke_wdt_enable(void) { u32 val; + /* clear status before enabling watchdog */ + booke_wdt_ping(); val = mfspr(SPRN_TCR); val |= (TCR_WIE|TCR_WRC(WRC_CHIP)|WDTP(booke_wdt_period)); @@ -61,14 +71,6 @@ static __inline__ void booke_wdt_enable( } /* - * booke_wdt_ping: - */ -static __inline__ void booke_wdt_ping(void) -{ - mtspr(SPRN_TSR, TSR_ENW|TSR_WIS); -} - -/* * booke_wdt_write: */ static ssize_t booke_wdt_write (struct file *file, const char __user *buf, diff --git a/drivers/char/watchdog/cpu5wdt.c b/drivers/char/watchdog/cpu5wdt.c index 00bdabb..bcd7e36 100644 --- a/drivers/char/watchdog/cpu5wdt.c +++ b/drivers/char/watchdog/cpu5wdt.c @@ -80,10 +80,8 @@ static void cpu5wdt_trigger(unsigned lon outb(1, port + CPU5WDT_TRIGGER_REG); /* requeue?? */ - if( cpu5wdt_device.queue && ticks ) { - cpu5wdt_device.timer.expires = jiffies + CPU5WDT_INTERVAL; - add_timer(&cpu5wdt_device.timer); - } + if (cpu5wdt_device.queue && ticks) + mod_timer(&cpu5wdt_device.timer, jiffies + CPU5WDT_INTERVAL); else { /* ticks doesn't matter anyway */ complete(&cpu5wdt_device.stop); @@ -109,8 +107,7 @@ static void cpu5wdt_start(void) outb(1, port + CPU5WDT_MODE_REG); outb(0, port + CPU5WDT_RESET_REG); outb(0, port + CPU5WDT_ENABLE_REG); - cpu5wdt_device.timer.expires = jiffies + CPU5WDT_INTERVAL; - add_timer(&cpu5wdt_device.timer); + mod_timer(&cpu5wdt_device.timer, jiffies + CPU5WDT_INTERVAL); } /* if process dies, counter is not decremented */ cpu5wdt_device.running++; @@ -245,9 +242,7 @@ static int __devinit cpu5wdt_init(void) clear_bit(0, &cpu5wdt_device.inuse); - init_timer(&cpu5wdt_device.timer); - cpu5wdt_device.timer.function = cpu5wdt_trigger; - cpu5wdt_device.timer.data = 0; + setup_timer(&cpu5wdt_device.timer, cpu5wdt_trigger, 0); cpu5wdt_device.default_ticks = ticks; diff --git a/drivers/char/watchdog/eurotechwdt.c b/drivers/char/watchdog/eurotechwdt.c index e228d6e..f70387f 100644 --- a/drivers/char/watchdog/eurotechwdt.c +++ b/drivers/char/watchdog/eurotechwdt.c @@ -73,7 +73,7 @@ #define WDT_TIMEOUT 60 / static int nowayout = WATCHDOG_NOWAYOUT; module_param(nowayout, int, 0); -MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=CONFIG_WATCHDOG_NOWAYOUT)"); +MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=" __MODULE_STRING(WATCHDOG_NOWAYOUT) ")"); /* * Some symbolic names diff --git a/drivers/char/watchdog/i6300esb.c b/drivers/char/watchdog/i6300esb.c index fb64df4..c598250 100644 --- a/drivers/char/watchdog/i6300esb.c +++ b/drivers/char/watchdog/i6300esb.c @@ -91,7 +91,7 @@ MODULE_PARM_DESC(heartbeat, "Watchdog he static int nowayout = WATCHDOG_NOWAYOUT; module_param(nowayout, int, 0); -MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=CONFIG_WATCHDOG_NOWAYOUT)"); +MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=" __MODULE_STRING(WATCHDOG_NOWAYOUT) ")"); /* * Some i6300ESB specific functions diff --git a/drivers/char/watchdog/i8xx_tco.c b/drivers/char/watchdog/i8xx_tco.c index e0627d7..a62ef48 100644 --- a/drivers/char/watchdog/i8xx_tco.c +++ b/drivers/char/watchdog/i8xx_tco.c @@ -109,7 +109,7 @@ MODULE_PARM_DESC(heartbeat, "Watchdog he static int nowayout = WATCHDOG_NOWAYOUT; module_param(nowayout, int, 0); -MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=CONFIG_WATCHDOG_NOWAYOUT)"); +MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=" __MODULE_STRING(WATCHDOG_NOWAYOUT) ")"); /* * Some TCO specific functions diff --git a/drivers/char/watchdog/iTCO_wdt.c b/drivers/char/watchdog/iTCO_wdt.c index 7eac922..3c9684c 100644 --- a/drivers/char/watchdog/iTCO_wdt.c +++ b/drivers/char/watchdog/iTCO_wdt.c @@ -1,7 +1,7 @@ /* * intel TCO Watchdog Driver (Used in i82801 and i6300ESB chipsets) * - * (c) Copyright 2006 Wim Van Sebroeck . + * (c) Copyright 2006-2007 Wim Van Sebroeck . * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -49,7 +49,7 @@ /* Module and version information */ #define DRV_NAME "iTCO_wdt" #define DRV_VERSION "1.01" -#define DRV_RELDATE "11-Nov-2006" +#define DRV_RELDATE "21-Jan-2007" #define PFX DRV_NAME ": " /* Includes */ @@ -187,7 +187,7 @@ MODULE_PARM_DESC(heartbeat, "Watchdog he static int nowayout = WATCHDOG_NOWAYOUT; module_param(nowayout, int, 0); -MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=CONFIG_WATCHDOG_NOWAYOUT)"); +MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=" __MODULE_STRING(WATCHDOG_NOWAYOUT) ")"); /* iTCO Vendor Specific Support hooks */ #ifdef CONFIG_ITCO_VENDOR_SUPPORT @@ -539,7 +539,7 @@ static int iTCO_wdt_ioctl (struct inode * Kernel Interfaces */ -static struct file_operations iTCO_wdt_fops = { +static const struct file_operations iTCO_wdt_fops = { .owner = THIS_MODULE, .llseek = no_llseek, .write = iTCO_wdt_write, diff --git a/drivers/char/watchdog/ib700wdt.c b/drivers/char/watchdog/ib700wdt.c index c1ed209..c3a60f5 100644 --- a/drivers/char/watchdog/ib700wdt.c +++ b/drivers/char/watchdog/ib700wdt.c @@ -3,8 +3,8 @@ * * (c) Copyright 2001 Charles Howes * - * Based on advantechwdt.c which is based on acquirewdt.c which - * is based on wdt.c. + * Based on advantechwdt.c which is based on acquirewdt.c which + * is based on wdt.c. * * (c) Copyright 2000-2001 Marek Michalkiewicz * @@ -25,9 +25,9 @@ * * (c) Copyright 1995 Alan Cox * - * 14-Dec-2001 Matt Domsch - * Added nowayout module option to override CONFIG_WATCHDOG_NOWAYOUT - * Added timeout module option to override default + * 14-Dec-2001 Matt Domsch + * Added nowayout module option to override CONFIG_WATCHDOG_NOWAYOUT + * Added timeout module option to override default * */ @@ -36,22 +36,24 @@ #include #include #include #include -#include #include -#include #include #include #include +#include #include #include #include +static struct platform_device *ibwdt_platform_device; static unsigned long ibwdt_is_open; static spinlock_t ibwdt_lock; static char expect_close; -#define PFX "ib700wdt: " +/* Module information */ +#define DRV_NAME "ib700wdt" +#define PFX DRV_NAME ": " /* * @@ -118,20 +120,51 @@ static int wd_margin = WD_TIMO; static int nowayout = WATCHDOG_NOWAYOUT; module_param(nowayout, int, 0); -MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=CONFIG_WATCHDOG_NOWAYOUT)"); +MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=" __MODULE_STRING(WATCHDOG_NOWAYOUT) ")"); /* - * Kernel methods. + * Watchdog Operations */ static void ibwdt_ping(void) { + spin_lock(&ibwdt_lock); + /* Write a watchdog value */ outb_p(wd_margin, WDT_START); + + spin_unlock(&ibwdt_lock); } +static void +ibwdt_disable(void) +{ + spin_lock(&ibwdt_lock); + outb_p(0, WDT_STOP); + spin_unlock(&ibwdt_lock); +} + +static int +ibwdt_set_heartbeat(int t) +{ + int i; + + if ((t < 0) || (t > 30)) + return -EINVAL; + + for (i = 0x0F; i > -1; i--) + if (wd_times[i] > t) + break; + wd_margin = i; + return 0; +} + +/* + * /dev/watchdog handling + */ + static ssize_t ibwdt_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos) { @@ -159,7 +192,7 @@ static int ibwdt_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) { - int i, new_margin; + int new_margin; void __user *argp = (void __user *)arg; int __user *p = argp; @@ -176,6 +209,7 @@ ibwdt_ioctl(struct inode *inode, struct break; case WDIOC_GETSTATUS: + case WDIOC_GETBOOTSTATUS: return put_user(0, p); case WDIOC_KEEPALIVE: @@ -185,18 +219,33 @@ ibwdt_ioctl(struct inode *inode, struct case WDIOC_SETTIMEOUT: if (get_user(new_margin, p)) return -EFAULT; - if ((new_margin < 0) || (new_margin > 30)) + if (ibwdt_set_heartbeat(new_margin)) return -EINVAL; - for (i = 0x0F; i > -1; i--) - if (wd_times[i] > new_margin) - break; - wd_margin = i; ibwdt_ping(); /* Fall */ case WDIOC_GETTIMEOUT: return put_user(wd_times[wd_margin], p); - break; + + case WDIOC_SETOPTIONS: + { + int options, retval = -EINVAL; + + if (get_user(options, p)) + return -EFAULT; + + if (options & WDIOS_DISABLECARD) { + ibwdt_disable(); + retval = 0; + } + + if (options & WDIOS_ENABLECARD) { + ibwdt_ping(); + retval = 0; + } + + return retval; + } default: return -ENOTTY; @@ -207,9 +256,7 @@ ibwdt_ioctl(struct inode *inode, struct static int ibwdt_open(struct inode *inode, struct file *file) { - spin_lock(&ibwdt_lock); if (test_and_set_bit(0, &ibwdt_is_open)) { - spin_unlock(&ibwdt_lock); return -EBUSY; } if (nowayout) @@ -217,41 +264,24 @@ ibwdt_open(struct inode *inode, struct f /* Activate */ ibwdt_ping(); - spin_unlock(&ibwdt_lock); return nonseekable_open(inode, file); } static int ibwdt_close(struct inode *inode, struct file *file) { - spin_lock(&ibwdt_lock); - if (expect_close == 42) - outb_p(0, WDT_STOP); - else + if (expect_close == 42) { + ibwdt_disable(); + } else { printk(KERN_CRIT PFX "WDT device closed unexpectedly. WDT will not stop!\n"); - + ibwdt_ping(); + } clear_bit(0, &ibwdt_is_open); expect_close = 0; - spin_unlock(&ibwdt_lock); return 0; } /* - * Notifier for system down - */ - -static int -ibwdt_notify_sys(struct notifier_block *this, unsigned long code, - void *unused) -{ - if (code == SYS_DOWN || code == SYS_HALT) { - /* Turn the WDT off */ - outb_p(0, WDT_STOP); - } - return NOTIFY_DONE; -} - -/* * Kernel Interfaces */ @@ -271,26 +301,14 @@ static struct miscdevice ibwdt_miscdev = }; /* - * The WDT needs to learn about soft shutdowns in order to - * turn the timebomb registers off. + * Init & exit routines */ -static struct notifier_block ibwdt_notifier = { - .notifier_call = ibwdt_notify_sys, -}; - -static int __init ibwdt_init(void) +static int __devinit ibwdt_probe(struct platform_device *dev) { int res; - printk(KERN_INFO PFX "WDT driver for IB700 single board computer initialising.\n"); - spin_lock_init(&ibwdt_lock); - res = misc_register(&ibwdt_miscdev); - if (res) { - printk (KERN_ERR PFX "failed to register misc device\n"); - goto out_nomisc; - } #if WDT_START != WDT_STOP if (!request_region(WDT_STOP, 1, "IB700 WDT")) { @@ -305,34 +323,78 @@ #endif res = -EIO; goto out_nostartreg; } - res = register_reboot_notifier(&ibwdt_notifier); + + res = misc_register(&ibwdt_miscdev); if (res) { - printk (KERN_ERR PFX "Failed to register reboot notifier.\n"); - goto out_noreboot; + printk (KERN_ERR PFX "failed to register misc device\n"); + goto out_nomisc; } return 0; -out_noreboot: +out_nomisc: release_region(WDT_START, 1); out_nostartreg: #if WDT_START != WDT_STOP release_region(WDT_STOP, 1); #endif out_nostopreg: - misc_deregister(&ibwdt_miscdev); -out_nomisc: return res; } -static void __exit -ibwdt_exit(void) +static int __devexit ibwdt_remove(struct platform_device *dev) { misc_deregister(&ibwdt_miscdev); - unregister_reboot_notifier(&ibwdt_notifier); + release_region(WDT_START,1); #if WDT_START != WDT_STOP release_region(WDT_STOP,1); #endif - release_region(WDT_START,1); + return 0; +} + +static void ibwdt_shutdown(struct platform_device *dev) +{ + /* Turn the WDT off if we have a soft shutdown */ + ibwdt_disable(); +} + +static struct platform_driver ibwdt_driver = { + .probe = ibwdt_probe, + .remove = __devexit_p(ibwdt_remove), + .shutdown = ibwdt_shutdown, + .driver = { + .owner = THIS_MODULE, + .name = DRV_NAME, + }, +}; + +static int __init ibwdt_init(void) +{ + int err; + + printk(KERN_INFO PFX "WDT driver for IB700 single board computer initialising.\n"); + + err = platform_driver_register(&ibwdt_driver); + if (err) + return err; + + ibwdt_platform_device = platform_device_register_simple(DRV_NAME, -1, NULL, 0); + if (IS_ERR(ibwdt_platform_device)) { + err = PTR_ERR(ibwdt_platform_device); + goto unreg_platform_driver; + } + + return 0; + +unreg_platform_driver: + platform_driver_unregister(&ibwdt_driver); + return err; +} + +static void __exit ibwdt_exit(void) +{ + platform_device_unregister(ibwdt_platform_device); + platform_driver_unregister(&ibwdt_driver); + printk(KERN_INFO PFX "Watchdog Module Unloaded.\n"); } module_init(ibwdt_init); diff --git a/drivers/char/watchdog/ibmasr.c b/drivers/char/watchdog/ibmasr.c index dd6760f..8195f50 100644 --- a/drivers/char/watchdog/ibmasr.c +++ b/drivers/char/watchdog/ibmasr.c @@ -396,7 +396,7 @@ module_init(ibmasr_init); module_exit(ibmasr_exit); module_param(nowayout, int, 0); -MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=CONFIG_WATCHDOG_NOWAYOUT)"); +MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=" __MODULE_STRING(WATCHDOG_NOWAYOUT) ")"); MODULE_DESCRIPTION("IBM Automatic Server Restart driver"); MODULE_AUTHOR("Andrey Panin"); diff --git a/drivers/char/watchdog/indydog.c b/drivers/char/watchdog/indydog.c index 0bc2393..788245b 100644 --- a/drivers/char/watchdog/indydog.c +++ b/drivers/char/watchdog/indydog.c @@ -32,7 +32,7 @@ #define WATCHDOG_TIMEOUT 30 /* 30 sec d static int nowayout = WATCHDOG_NOWAYOUT; module_param(nowayout, int, 0); -MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=CONFIG_WATCHDOG_NOWAYOUT)"); +MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=" __MODULE_STRING(WATCHDOG_NOWAYOUT) ")"); static void indydog_start(void) { diff --git a/drivers/char/watchdog/machzwd.c b/drivers/char/watchdog/machzwd.c index 276577d..81fb3de 100644 --- a/drivers/char/watchdog/machzwd.c +++ b/drivers/char/watchdog/machzwd.c @@ -95,7 +95,7 @@ MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR); static int nowayout = WATCHDOG_NOWAYOUT; module_param(nowayout, int, 0); -MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=CONFIG_WATCHDOG_NOWAYOUT)"); +MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=" __MODULE_STRING(WATCHDOG_NOWAYOUT) ")"); #define PFX "machzwd" @@ -118,12 +118,14 @@ static int action = 0; module_param(action, int, 0); MODULE_PARM_DESC(action, "after watchdog resets, generate: 0 = RESET(*) 1 = SMI 2 = NMI 3 = SCI"); +static void zf_ping(unsigned long data); + static int zf_action = GEN_RESET; static unsigned long zf_is_open; static char zf_expect_close; static spinlock_t zf_lock; static spinlock_t zf_port_lock; -static struct timer_list zf_timer; +static DEFINE_TIMER(zf_timer, zf_ping, 0, 0); static unsigned long next_heartbeat = 0; @@ -220,9 +222,7 @@ static void zf_timer_on(void) next_heartbeat = jiffies + ZF_USER_TIMEO; /* start the timer for internal ping */ - zf_timer.expires = jiffies + ZF_HW_TIMEO; - - add_timer(&zf_timer); + mod_timer(&zf_timer, jiffies + ZF_HW_TIMEO); /* start watchdog timer */ ctrl_reg = zf_get_control(); @@ -260,8 +260,7 @@ static void zf_ping(unsigned long data) zf_set_control(ctrl_reg); spin_unlock_irqrestore(&zf_port_lock, flags); - zf_timer.expires = jiffies + ZF_HW_TIMEO; - add_timer(&zf_timer); + mod_timer(&zf_timer, jiffies + ZF_HW_TIMEO); }else{ printk(KERN_CRIT PFX ": I will reset your machine\n"); } @@ -325,7 +324,7 @@ static int zf_ioctl(struct inode *inode, return put_user(0, p); case WDIOC_KEEPALIVE: - zf_ping(0); + zf_ping(NULL); break; default: @@ -465,11 +464,6 @@ static int __init zf_init(void) zf_set_status(0); zf_set_control(0); - /* this is the timer that will do the hard work */ - init_timer(&zf_timer); - zf_timer.function = zf_ping; - zf_timer.data = 0; - return 0; no_reboot: diff --git a/drivers/char/watchdog/mixcomwd.c b/drivers/char/watchdog/mixcomwd.c index c2dac0a..f35e284 100644 --- a/drivers/char/watchdog/mixcomwd.c +++ b/drivers/char/watchdog/mixcomwd.c @@ -56,16 +56,18 @@ #define MIXCOM_ID 0x11 #define FLASHCOM_WATCHDOG_OFFSET 0x4 #define FLASHCOM_ID 0x18 +static void mixcomwd_timerfun(unsigned long d); + static unsigned long mixcomwd_opened; /* long req'd for setbit --RR */ static int watchdog_port; static int mixcomwd_timer_alive; -static DEFINE_TIMER(mixcomwd_timer, NULL, 0, 0); +static DEFINE_TIMER(mixcomwd_timer, mixcomwd_timerfun, 0, 0); static char expect_close; static int nowayout = WATCHDOG_NOWAYOUT; module_param(nowayout, int, 0); -MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=CONFIG_WATCHDOG_NOWAYOUT)"); +MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=" __MODULE_STRING(WATCHDOG_NOWAYOUT) ")"); static void mixcomwd_ping(void) { @@ -77,7 +79,7 @@ static void mixcomwd_timerfun(unsigned l { mixcomwd_ping(); - mod_timer(&mixcomwd_timer,jiffies+ 5*HZ); + mod_timer(&mixcomwd_timer, jiffies + 5 * HZ); } /* @@ -114,12 +116,8 @@ static int mixcomwd_release(struct inode printk(KERN_ERR "mixcomwd: release called while internal timer alive"); return -EBUSY; } - init_timer(&mixcomwd_timer); - mixcomwd_timer.expires=jiffies + 5 * HZ; - mixcomwd_timer.function=mixcomwd_timerfun; - mixcomwd_timer.data=0; mixcomwd_timer_alive=1; - add_timer(&mixcomwd_timer); + mod_timer(&mixcomwd_timer, jiffies + 5 * HZ); } else { printk(KERN_CRIT "mixcomwd: WDT device closed unexpectedly. WDT will not stop!\n"); } @@ -285,7 +283,7 @@ static void __exit mixcomwd_exit(void) if(mixcomwd_timer_alive) { printk(KERN_WARNING "mixcomwd: I quit now, hardware will" " probably reboot!\n"); - del_timer(&mixcomwd_timer); + del_timer_sync(&mixcomwd_timer); mixcomwd_timer_alive=0; } } diff --git a/drivers/char/watchdog/omap_wdt.c b/drivers/char/watchdog/omap_wdt.c index 6c6f973..84074a6 100644 --- a/drivers/char/watchdog/omap_wdt.c +++ b/drivers/char/watchdog/omap_wdt.c @@ -230,7 +230,7 @@ omap_wdt_ioctl(struct inode *inode, stru } } -static struct file_operations omap_wdt_fops = { +static const struct file_operations omap_wdt_fops = { .owner = THIS_MODULE, .write = omap_wdt_write, .ioctl = omap_wdt_ioctl, diff --git a/drivers/char/watchdog/pc87413_wdt.c b/drivers/char/watchdog/pc87413_wdt.c index 1d447e3..3d3deae 100644 --- a/drivers/char/watchdog/pc87413_wdt.c +++ b/drivers/char/watchdog/pc87413_wdt.c @@ -526,7 +526,7 @@ static int pc87413_notify_sys(struct not /* -- Module's structures ---------------------------------------*/ -static struct file_operations pc87413_fops = { +static const struct file_operations pc87413_fops = { .owner = THIS_MODULE, .llseek = no_llseek, .write = pc87413_write, @@ -631,5 +631,5 @@ module_param(timeout, int, 0); MODULE_PARM_DESC(timeout, "Watchdog timeout in minutes (default=" __MODULE_STRING(timeout) ")."); module_param(nowayout, int, 0); -MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=CONFIG_WATCHDOG_NOWAYOUT)"); +MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=" __MODULE_STRING(WATCHDOG_NOWAYOUT) ")"); diff --git a/drivers/char/watchdog/pcwd.c b/drivers/char/watchdog/pcwd.c index 8e1e6e4..6e8b570 100644 --- a/drivers/char/watchdog/pcwd.c +++ b/drivers/char/watchdog/pcwd.c @@ -2,7 +2,7 @@ * PC Watchdog Driver * by Ken Hollis (khollis@bitgate.com) * - * Permission granted from Simon Machell (73244.1270@compuserve.com) + * Permission granted from Simon Machell (smachell@berkprod.com) * Written for the Linux Kernel, and GPLed by Ken Hollis * * 960107 Added request_region routines, modulized the whole thing. @@ -70,8 +70,8 @@ #include /* For copy_to_ #include /* For inb/outb/... */ /* Module and version information */ -#define WATCHDOG_VERSION "1.17" -#define WATCHDOG_DATE "12 Feb 2006" +#define WATCHDOG_VERSION "1.18" +#define WATCHDOG_DATE "21 Jan 2007" #define WATCHDOG_DRIVER_NAME "ISA-PC Watchdog" #define WATCHDOG_NAME "pcwd" #define PFX WATCHDOG_NAME ": " @@ -132,6 +132,18 @@ #define CMD_ISA_DELAY_TIME_4SECS 0x0B #define CMD_ISA_DELAY_TIME_8SECS 0x0C #define CMD_ISA_RESET_RELAYS 0x0D +/* Watchdog's Dip Switch heartbeat values */ +static const int heartbeat_tbl [] = { + 20, /* OFF-OFF-OFF = 20 Sec */ + 40, /* OFF-OFF-ON = 40 Sec */ + 60, /* OFF-ON-OFF = 1 Min */ + 300, /* OFF-ON-ON = 5 Min */ + 600, /* ON-OFF-OFF = 10 Min */ + 1800, /* ON-OFF-ON = 30 Min */ + 3600, /* ON-ON-OFF = 1 Hour */ + 7200, /* ON-ON-ON = 2 hour */ +}; + /* * We are using an kernel timer to do the pinging of the watchdog * every ~500ms. We try to set the internal heartbeat of the @@ -167,14 +179,14 @@ static int debug = QUIET; module_param(debug, int, 0); MODULE_PARM_DESC(debug, "Debug level: 0=Quiet, 1=Verbose, 2=Debug (default=0)"); -#define WATCHDOG_HEARTBEAT 60 /* 60 sec default heartbeat */ +#define WATCHDOG_HEARTBEAT 0 /* default heartbeat = delay-time from dip-switches */ static int heartbeat = WATCHDOG_HEARTBEAT; module_param(heartbeat, int, 0); -MODULE_PARM_DESC(heartbeat, "Watchdog heartbeat in seconds. (2<=heartbeat<=7200, default=" __MODULE_STRING(WATCHDOG_HEARTBEAT) ")"); +MODULE_PARM_DESC(heartbeat, "Watchdog heartbeat in seconds. (2<=heartbeat<=7200 or 0=delay-time from dip-switches, default=" __MODULE_STRING(WATCHDOG_HEARTBEAT) ")"); static int nowayout = WATCHDOG_NOWAYOUT; module_param(nowayout, int, 0); -MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=CONFIG_WATCHDOG_NOWAYOUT)"); +MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=" __MODULE_STRING(WATCHDOG_NOWAYOUT) ")"); /* * Internal functions @@ -831,9 +843,7 @@ static int __devinit pcwatchdog_init(int /* clear the "card caused reboot" flag */ pcwd_clear_status(); - init_timer(&pcwd_private.timer); - pcwd_private.timer.function = pcwd_timer_ping; - pcwd_private.timer.data = 0; + setup_timer(&pcwd_private.timer, pcwd_timer_ping, 0); /* Disable the board */ pcwd_stop(); @@ -844,6 +854,10 @@ static int __devinit pcwatchdog_init(int /* Show info about the card itself */ pcwd_show_card_info(); + /* If heartbeat = 0 then we use the heartbeat from the dip-switches */ + if (heartbeat == 0) + heartbeat = heartbeat_tbl[(pcwd_get_option_switches() & 0x07)]; + /* Check that the heartbeat value is within it's range ; if not reset to the default */ if (pcwd_set_heartbeat(heartbeat)) { pcwd_set_heartbeat(WATCHDOG_HEARTBEAT); diff --git a/drivers/char/watchdog/pcwd_pci.c b/drivers/char/watchdog/pcwd_pci.c index f4872c8..61a89e9 100644 --- a/drivers/char/watchdog/pcwd_pci.c +++ b/drivers/char/watchdog/pcwd_pci.c @@ -1,7 +1,7 @@ /* * Berkshire PCI-PC Watchdog Card Driver * - * (c) Copyright 2003-2005 Wim Van Sebroeck . + * (c) Copyright 2003-2007 Wim Van Sebroeck . * * Based on source code of the following authors: * Ken Hollis , @@ -51,8 +51,8 @@ #include /* For copy_to_ #include /* For inb/outb/... */ /* Module and version information */ -#define WATCHDOG_VERSION "1.02" -#define WATCHDOG_DATE "03 Sep 2005" +#define WATCHDOG_VERSION "1.03" +#define WATCHDOG_DATE "21 Jan 2007" #define WATCHDOG_DRIVER_NAME "PCI-PC Watchdog" #define WATCHDOG_NAME "pcwd_pci" #define PFX WATCHDOG_NAME ": " @@ -96,6 +96,18 @@ #define CMD_READ_WATCHDOG_TIMEOUT 0x18 #define CMD_WRITE_WATCHDOG_TIMEOUT 0x19 #define CMD_GET_CLEAR_RESET_COUNT 0x84 +/* Watchdog's Dip Switch heartbeat values */ +static const int heartbeat_tbl [] = { + 5, /* OFF-OFF-OFF = 5 Sec */ + 10, /* OFF-OFF-ON = 10 Sec */ + 30, /* OFF-ON-OFF = 30 Sec */ + 60, /* OFF-ON-ON = 1 Min */ + 300, /* ON-OFF-OFF = 5 Min */ + 600, /* ON-OFF-ON = 10 Min */ + 1800, /* ON-ON-OFF = 30 Min */ + 3600, /* ON-ON-ON = 1 hour */ +}; + /* We can only use 1 card due to the /dev/watchdog restriction */ static int cards_found; @@ -119,14 +131,14 @@ static int debug = QUIET; module_param(debug, int, 0); MODULE_PARM_DESC(debug, "Debug level: 0=Quiet, 1=Verbose, 2=Debug (default=0)"); -#define WATCHDOG_HEARTBEAT 2 /* 2 sec default heartbeat */ +#define WATCHDOG_HEARTBEAT 0 /* default heartbeat = delay-time from dip-switches */ static int heartbeat = WATCHDOG_HEARTBEAT; module_param(heartbeat, int, 0); -MODULE_PARM_DESC(heartbeat, "Watchdog heartbeat in seconds. (0= DEBUG) printk(KERN_DEBUG PFX "Watchdog keepalive signal send\n"); @@ -373,7 +387,9 @@ static int pcipcwd_get_temperature(int * if (!pcipcwd_private.supports_temp) return -ENODEV; + spin_lock(&pcipcwd_private.io_lock); *temperature = inb_p(pcipcwd_private.io_addr); + spin_unlock(&pcipcwd_private.io_lock); /* * Convert celsius to fahrenheit, since this was @@ -711,6 +727,10 @@ static int __devinit pcipcwd_card_init(s /* Show info about the card itself */ pcipcwd_show_card_info(); + /* If heartbeat = 0 then we use the heartbeat from the dip-switches */ + if (heartbeat == 0) + heartbeat = heartbeat_tbl[(pcipcwd_get_option_switches() & 0x07)]; + /* Check that the heartbeat value is within it's range ; if not reset to the default */ if (pcipcwd_set_heartbeat(heartbeat)) { pcipcwd_set_heartbeat(WATCHDOG_HEARTBEAT); @@ -798,6 +818,8 @@ static int __init pcipcwd_init_module(vo static void __exit pcipcwd_cleanup_module(void) { pci_unregister_driver(&pcipcwd_driver); + + printk(KERN_INFO PFX "Watchdog Module Unloaded.\n"); } module_init(pcipcwd_init_module); diff --git a/drivers/char/watchdog/pcwd_usb.c b/drivers/char/watchdog/pcwd_usb.c index 2da5ac9..31037f9 100644 --- a/drivers/char/watchdog/pcwd_usb.c +++ b/drivers/char/watchdog/pcwd_usb.c @@ -1,7 +1,7 @@ /* * Berkshire USB-PC Watchdog Card Driver * - * (c) Copyright 2004 Wim Van Sebroeck . + * (c) Copyright 2004-2007 Wim Van Sebroeck . * * Based on source code of the following authors: * Ken Hollis , @@ -24,26 +24,25 @@ * http://www.berkprod.com/ or http://www.pcwatchdog.com/ */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include +#include /* For module specific items */ +#include /* For new moduleparam's */ +#include /* For standard types (like size_t) */ +#include /* For the -ENODEV/... values */ +#include /* For printk/panic/... */ +#include /* For mdelay function */ +#include /* For MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR) */ +#include /* For the watchdog specific items */ +#include /* For notifier support */ +#include /* For reboot_notifier stuff */ +#include /* For __init/__exit/... */ +#include /* For file operations */ +#include /* For USB functions */ +#include /* For kmalloc, ... */ +#include /* For mutex locking */ #include /* For HID_REQ_SET_REPORT & HID_DT_REPORT */ +#include /* For copy_to_user/put_user/... */ + #ifdef CONFIG_USB_DEBUG static int debug = 1; @@ -57,8 +56,8 @@ #define dbg(format, arg...) do { if (deb /* Module and Version Information */ -#define DRIVER_VERSION "1.01" -#define DRIVER_DATE "15 Mar 2005" +#define DRIVER_VERSION "1.02" +#define DRIVER_DATE "21 Jan 2007" #define DRIVER_AUTHOR "Wim Van Sebroeck " #define DRIVER_DESC "Berkshire USB-PC Watchdog driver" #define DRIVER_LICENSE "GPL" @@ -75,14 +74,14 @@ MODULE_ALIAS_MISCDEV(TEMP_MINOR); module_param(debug, int, 0); MODULE_PARM_DESC(debug, "Debug enabled or not"); -#define WATCHDOG_HEARTBEAT 2 /* 2 sec default heartbeat */ +#define WATCHDOG_HEARTBEAT 0 /* default heartbeat = delay-time from dip-switches */ static int heartbeat = WATCHDOG_HEARTBEAT; module_param(heartbeat, int, 0); -MODULE_PARM_DESC(heartbeat, "Watchdog heartbeat in seconds. (0start); wdt_clk = clk_get(&pdev->dev, "wdt_ck"); - if (!wdt_clk) { + if (IS_ERR(wdt_clk)) { + ret = PTR_ERR(wdt_clk); release_resource(wdt_mem); kfree(wdt_mem); goto out; diff --git a/drivers/char/watchdog/rm9k_wdt.c b/drivers/char/watchdog/rm9k_wdt.c index 7576a13..5c921e4 100644 --- a/drivers/char/watchdog/rm9k_wdt.c +++ b/drivers/char/watchdog/rm9k_wdt.c @@ -95,7 +95,7 @@ MODULE_PARM_DESC(nowayout, "Watchdog can /* Kernel interfaces */ -static struct file_operations fops = { +static const struct file_operations fops = { .owner = THIS_MODULE, .open = wdt_gpi_open, .release = wdt_gpi_release, @@ -192,7 +192,7 @@ static int wdt_gpi_open(struct inode *in locked = 0; } - res = request_irq(wd_irq, wdt_gpi_irqhdl, SA_SHIRQ | SA_INTERRUPT, + res = request_irq(wd_irq, wdt_gpi_irqhdl, IRQF_SHARED | IRQF_DISABLED, wdt_gpi_name, &miscdev); if (unlikely(res)) return res; diff --git a/drivers/char/watchdog/s3c2410_wdt.c b/drivers/char/watchdog/s3c2410_wdt.c index 18cb050..dff6cb5 100644 --- a/drivers/char/watchdog/s3c2410_wdt.c +++ b/drivers/char/watchdog/s3c2410_wdt.c @@ -78,7 +78,7 @@ MODULE_PARM_DESC(tmr_margin, "Watchdog t MODULE_PARM_DESC(tmr_atboot, "Watchdog is started at boot time if set to 1, default=" __MODULE_STRING(CONFIG_S3C2410_WATCHDOG_ATBOOT)); -MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=CONFIG_WATCHDOG_NOWAYOUT)"); +MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=" __MODULE_STRING(WATCHDOG_NOWAYOUT) ")"); MODULE_PARM_DESC(soft_noboot, "Watchdog action, set to 1 to ignore reboots, 0 to reboot (default depends on ONLY_TESTING)"); @@ -366,13 +366,15 @@ static int s3c2410wdt_probe(struct platf wdt_mem = request_mem_region(res->start, size, pdev->name); if (wdt_mem == NULL) { printk(KERN_INFO PFX "failed to get memory region\n"); - return -ENOENT; + ret = -ENOENT; + goto err_req; } wdt_base = ioremap(res->start, size); if (wdt_base == 0) { printk(KERN_INFO PFX "failed to ioremap() region\n"); - return -EINVAL; + ret = -EINVAL; + goto err_req; } DBG("probe: mapped wdt_base=%p\n", wdt_base); @@ -380,22 +382,21 @@ static int s3c2410wdt_probe(struct platf res = platform_get_resource(pdev, IORESOURCE_IRQ, 0); if (res == NULL) { printk(KERN_INFO PFX "failed to get irq resource\n"); - iounmap(wdt_base); - return -ENOENT; + ret = -ENOENT; + goto err_map; } ret = request_irq(res->start, s3c2410wdt_irq, 0, pdev->name, pdev); if (ret != 0) { printk(KERN_INFO PFX "failed to install irq (%d)\n", ret); - iounmap(wdt_base); - return ret; + goto err_map; } wdt_clock = clk_get(&pdev->dev, "watchdog"); - if (wdt_clock == NULL) { + if (IS_ERR(wdt_clock)) { printk(KERN_INFO PFX "failed to find watchdog clock source\n"); - iounmap(wdt_base); - return -ENOENT; + ret = PTR_ERR(wdt_clock); + goto err_irq; } clk_enable(wdt_clock); @@ -418,8 +419,7 @@ static int s3c2410wdt_probe(struct platf if (ret) { printk (KERN_ERR PFX "cannot register miscdev on minor=%d (%d)\n", WATCHDOG_MINOR, ret); - iounmap(wdt_base); - return ret; + goto err_clk; } if (tmr_atboot && started == 0) { @@ -434,26 +434,36 @@ static int s3c2410wdt_probe(struct platf } return 0; + + err_clk: + clk_disable(wdt_clock); + clk_put(wdt_clock); + + err_irq: + free_irq(wdt_irq->start, pdev); + + err_map: + iounmap(wdt_base); + + err_req: + release_resource(wdt_mem); + kfree(wdt_mem); + + return ret; } static int s3c2410wdt_remove(struct platform_device *dev) { - if (wdt_mem != NULL) { - release_resource(wdt_mem); - kfree(wdt_mem); - wdt_mem = NULL; - } + release_resource(wdt_mem); + kfree(wdt_mem); + wdt_mem = NULL; - if (wdt_irq != NULL) { - free_irq(wdt_irq->start, dev); - wdt_irq = NULL; - } + free_irq(wdt_irq->start, dev); + wdt_irq = NULL; - if (wdt_clock != NULL) { - clk_disable(wdt_clock); - clk_put(wdt_clock); - wdt_clock = NULL; - } + clk_disable(wdt_clock); + clk_put(wdt_clock); + wdt_clock = NULL; iounmap(wdt_base); misc_deregister(&s3c2410wdt_miscdev); diff --git a/drivers/char/watchdog/sbc60xxwdt.c b/drivers/char/watchdog/sbc60xxwdt.c index c7b2045..b628203 100644 --- a/drivers/char/watchdog/sbc60xxwdt.c +++ b/drivers/char/watchdog/sbc60xxwdt.c @@ -100,10 +100,10 @@ MODULE_PARM_DESC(timeout, "Watchdog time static int nowayout = WATCHDOG_NOWAYOUT; module_param(nowayout, int, 0); -MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=CONFIG_WATCHDOG_NOWAYOUT)"); +MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=" __MODULE_STRING(WATCHDOG_NOWAYOUT) ")"); static void wdt_timer_ping(unsigned long); -static struct timer_list timer; +static DEFINE_TIMER(timer, wdt_timer_ping, 0, 0); static unsigned long next_heartbeat; static unsigned long wdt_is_open; static char wdt_expect_close; @@ -122,8 +122,7 @@ static void wdt_timer_ping(unsigned long /* Ping the WDT by reading from wdt_start */ inb_p(wdt_start); /* Re-set the timer interval */ - timer.expires = jiffies + WDT_INTERVAL; - add_timer(&timer); + mod_timer(&timer, jiffies + WDT_INTERVAL); } else { printk(KERN_WARNING PFX "Heartbeat lost! Will not ping the watchdog\n"); } @@ -138,8 +137,7 @@ static void wdt_startup(void) next_heartbeat = jiffies + (timeout * HZ); /* Start the timer */ - timer.expires = jiffies + WDT_INTERVAL; - add_timer(&timer); + mod_timer(&timer, jiffies + WDT_INTERVAL); printk(KERN_INFO PFX "Watchdog timer is now enabled.\n"); } @@ -363,10 +361,6 @@ static int __init sbc60xxwdt_init(void) } } - init_timer(&timer); - timer.function = wdt_timer_ping; - timer.data = 0; - rc = misc_register(&wdt_miscdev); if (rc) { diff --git a/drivers/char/watchdog/sbc8360.c b/drivers/char/watchdog/sbc8360.c index 41fc6f8..67ae426 100644 --- a/drivers/char/watchdog/sbc8360.c +++ b/drivers/char/watchdog/sbc8360.c @@ -204,7 +204,7 @@ module_param(timeout, int, 0); MODULE_PARM_DESC(timeout, "Index into timeout table (0-63) (default=27 (60s))"); module_param(nowayout, int, 0); MODULE_PARM_DESC(nowayout, - "Watchdog cannot be stopped once started (default=CONFIG_WATCHDOG_NOWAYOUT)"); + "Watchdog cannot be stopped once started (default=" __MODULE_STRING(WATCHDOG_NOWAYOUT) ")"); /* * Kernel methods. diff --git a/drivers/char/watchdog/sbc_epx_c3.c b/drivers/char/watchdog/sbc_epx_c3.c index 8882b42..82cbd88 100644 --- a/drivers/char/watchdog/sbc_epx_c3.c +++ b/drivers/char/watchdog/sbc_epx_c3.c @@ -35,7 +35,7 @@ #define WATCHDOG_TIMEOUT 1 /* 1 sec def static int nowayout = WATCHDOG_NOWAYOUT; module_param(nowayout, int, 0); -MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=CONFIG_WATCHDOG_NOWAYOUT)"); +MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=" __MODULE_STRING(WATCHDOG_NOWAYOUT) ")"); #define EPXC3_WATCHDOG_CTL_REG 0x1ee /* write 1 to enable, 0 to disable */ #define EPXC3_WATCHDOG_PET_REG 0x1ef /* write anything to pet once enabled */ diff --git a/drivers/char/watchdog/sc1200wdt.c b/drivers/char/watchdog/sc1200wdt.c index e323983..1e4a8d7 100644 --- a/drivers/char/watchdog/sc1200wdt.c +++ b/drivers/char/watchdog/sc1200wdt.c @@ -92,7 +92,7 @@ MODULE_PARM_DESC(timeout, "range is 0-25 static int nowayout = WATCHDOG_NOWAYOUT; module_param(nowayout, int, 0); -MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=CONFIG_WATCHDOG_NOWAYOUT)"); +MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=" __MODULE_STRING(WATCHDOG_NOWAYOUT) ")"); diff --git a/drivers/char/watchdog/sc520_wdt.c b/drivers/char/watchdog/sc520_wdt.c index caec37b..2676a43 100644 --- a/drivers/char/watchdog/sc520_wdt.c +++ b/drivers/char/watchdog/sc520_wdt.c @@ -97,7 +97,7 @@ MODULE_PARM_DESC(timeout, "Watchdog time static int nowayout = WATCHDOG_NOWAYOUT; module_param(nowayout, int, 0); -MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=CONFIG_WATCHDOG_NOWAYOUT)"); +MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=" __MODULE_STRING(WATCHDOG_NOWAYOUT) ")"); /* * AMD Elan SC520 - Watchdog Timer Registers @@ -121,7 +121,7 @@ #define WDT_ENB 0x8000 /* [15] Watchdog static __u16 __iomem *wdtmrctl; static void wdt_timer_ping(unsigned long); -static struct timer_list timer; +static DEFINE_TIMER(timer, wdt_timer_ping, 0, 0); static unsigned long next_heartbeat; static unsigned long wdt_is_open; static char wdt_expect_close; @@ -145,8 +145,7 @@ static void wdt_timer_ping(unsigned long spin_unlock(&wdt_spinlock); /* Re-set the timer interval */ - timer.expires = jiffies + WDT_INTERVAL; - add_timer(&timer); + mod_timer(&timer, jiffies + WDT_INTERVAL); } else { printk(KERN_WARNING PFX "Heartbeat lost! Will not ping the watchdog\n"); } @@ -179,8 +178,7 @@ static int wdt_startup(void) next_heartbeat = jiffies + (timeout * HZ); /* Start the timer */ - timer.expires = jiffies + WDT_INTERVAL; - add_timer(&timer); + mod_timer(&timer, jiffies + WDT_INTERVAL); /* Start the watchdog */ wdt_config(WDT_ENB | WDT_WRST_ENB | WDT_EXP_SEL_04); @@ -389,10 +387,6 @@ static int __init sc520_wdt_init(void) spin_lock_init(&wdt_spinlock); - init_timer(&timer); - timer.function = wdt_timer_ping; - timer.data = 0; - /* Check that the timeout value is within it's range ; if not reset to the default */ if (wdt_set_heartbeat(timeout)) { wdt_set_heartbeat(WATCHDOG_TIMEOUT); diff --git a/drivers/char/watchdog/shwdt.c b/drivers/char/watchdog/shwdt.c index dc40362..cecbedd 100644 --- a/drivers/char/watchdog/shwdt.c +++ b/drivers/char/watchdog/shwdt.c @@ -65,10 +65,12 @@ static int clock_division_ratio = WTCSR_ #define next_ping_period(cks) msecs_to_jiffies(cks - 4) +static void sh_wdt_ping(unsigned long data); + static unsigned long shwdt_is_open; static struct watchdog_info sh_wdt_info; static char shwdt_expect_close; -static struct timer_list timer; +static DEFINE_TIMER(timer, sh_wdt_ping, 0, 0); static unsigned long next_heartbeat; #define WATCHDOG_HEARTBEAT 30 /* 30 sec default heartbeat */ @@ -433,10 +435,6 @@ static int __init sh_wdt_init(void) "be 1<=x<=3600, using %d\n", heartbeat); } - init_timer(&timer); - timer.function = sh_wdt_ping; - timer.data = 0; - rc = register_reboot_notifier(&sh_wdt_notifier); if (unlikely(rc)) { printk(KERN_ERR PFX "Can't register reboot notifier (err=%d)\n", diff --git a/drivers/char/watchdog/smsc37b787_wdt.c b/drivers/char/watchdog/smsc37b787_wdt.c index 9f56913..d3cb0a7 100644 --- a/drivers/char/watchdog/smsc37b787_wdt.c +++ b/drivers/char/watchdog/smsc37b787_wdt.c @@ -510,7 +510,7 @@ static int wb_smsc_wdt_notify_sys(struct /* -- Module's structures ---------------------------------------*/ -static struct file_operations wb_smsc_wdt_fops = +static const struct file_operations wb_smsc_wdt_fops = { .owner = THIS_MODULE, .llseek = no_llseek, @@ -624,4 +624,4 @@ module_param(timeout, int, 0); MODULE_PARM_DESC(timeout, "range is 1-255 units, default is 60"); module_param(nowayout, int, 0); -MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=CONFIG_WATCHDOG_NOWAYOUT)"); +MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=" __MODULE_STRING(WATCHDOG_NOWAYOUT) ")"); diff --git a/drivers/char/watchdog/softdog.c b/drivers/char/watchdog/softdog.c index 4067e1f..9c36949 100644 --- a/drivers/char/watchdog/softdog.c +++ b/drivers/char/watchdog/softdog.c @@ -59,7 +59,7 @@ MODULE_PARM_DESC(soft_margin, "Watchdog static int nowayout = WATCHDOG_NOWAYOUT; module_param(nowayout, int, 0); -MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=CONFIG_WATCHDOG_NOWAYOUT)"); +MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=" __MODULE_STRING(WATCHDOG_NOWAYOUT) ")"); #ifdef ONLY_TESTING static int soft_noboot = 1; diff --git a/drivers/char/watchdog/w83627hf_wdt.c b/drivers/char/watchdog/w83627hf_wdt.c index 07d4bff..337ee42 100644 --- a/drivers/char/watchdog/w83627hf_wdt.c +++ b/drivers/char/watchdog/w83627hf_wdt.c @@ -58,7 +58,7 @@ MODULE_PARM_DESC(timeout, "Watchdog time static int nowayout = WATCHDOG_NOWAYOUT; module_param(nowayout, int, 0); -MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=CONFIG_WATCHDOG_NOWAYOUT)"); +MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=" __MODULE_STRING(WATCHDOG_NOWAYOUT) ")"); /* * Kernel methods. diff --git a/drivers/char/watchdog/w83697hf_wdt.c b/drivers/char/watchdog/w83697hf_wdt.c index 7768b55..d9e821d 100644 --- a/drivers/char/watchdog/w83697hf_wdt.c +++ b/drivers/char/watchdog/w83697hf_wdt.c @@ -60,7 +60,7 @@ MODULE_PARM_DESC(timeout, "Watchdog time static int nowayout = WATCHDOG_NOWAYOUT; module_param(nowayout, int, 0); -MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=CONFIG_WATCHDOG_NOWAYOUT)"); +MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=" __MODULE_STRING(WATCHDOG_NOWAYOUT) ")"); /* * Kernel methods. @@ -323,7 +323,7 @@ wdt_notify_sys(struct notifier_block *th * Kernel Interfaces */ -static struct file_operations wdt_fops = { +static const struct file_operations wdt_fops = { .owner = THIS_MODULE, .llseek = no_llseek, .write = wdt_write, diff --git a/drivers/char/watchdog/w83877f_wdt.c b/drivers/char/watchdog/w83877f_wdt.c index b0e5f84..3c88fe1 100644 --- a/drivers/char/watchdog/w83877f_wdt.c +++ b/drivers/char/watchdog/w83877f_wdt.c @@ -87,10 +87,10 @@ MODULE_PARM_DESC(timeout, "Watchdog time static int nowayout = WATCHDOG_NOWAYOUT; module_param(nowayout, int, 0); -MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=CONFIG_WATCHDOG_NOWAYOUT)"); +MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=" __MODULE_STRING(WATCHDOG_NOWAYOUT) ")"); static void wdt_timer_ping(unsigned long); -static struct timer_list timer; +static DEFINE_TIMER(timer, wdt_timer_ping, 0, 0); static unsigned long next_heartbeat; static unsigned long wdt_is_open; static char wdt_expect_close; @@ -114,8 +114,7 @@ static void wdt_timer_ping(unsigned long inb_p(WDT_PING); /* Re-set the timer interval */ - timer.expires = jiffies + WDT_INTERVAL; - add_timer(&timer); + mod_timer(&timer, jiffies + WDT_INTERVAL); spin_unlock(&wdt_spinlock); @@ -155,8 +154,7 @@ static void wdt_startup(void) next_heartbeat = jiffies + (timeout * HZ); /* Start the timer */ - timer.expires = jiffies + WDT_INTERVAL; - add_timer(&timer); + mod_timer(&timer, jiffies + WDT_INTERVAL); wdt_change(WDT_ENABLE); @@ -377,10 +375,6 @@ static int __init w83877f_wdt_init(void) goto err_out_region1; } - init_timer(&timer); - timer.function = wdt_timer_ping; - timer.data = 0; - rc = misc_register(&wdt_miscdev); if (rc) { diff --git a/drivers/char/watchdog/w83977f_wdt.c b/drivers/char/watchdog/w83977f_wdt.c index 2c8d5d8..1579684 100644 --- a/drivers/char/watchdog/w83977f_wdt.c +++ b/drivers/char/watchdog/w83977f_wdt.c @@ -59,7 +59,7 @@ MODULE_PARM_DESC(testmode,"Watchdog test static int nowayout = WATCHDOG_NOWAYOUT; module_param(nowayout, int, 0); -MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=CONFIG_WATCHDOG_NOWAYOUT)"); +MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=" __MODULE_STRING(WATCHDOG_NOWAYOUT) ")"); /* * Start the watchdog diff --git a/drivers/char/watchdog/wafer5823wdt.c b/drivers/char/watchdog/wafer5823wdt.c index 163e028..950905d 100644 --- a/drivers/char/watchdog/wafer5823wdt.c +++ b/drivers/char/watchdog/wafer5823wdt.c @@ -65,7 +65,7 @@ MODULE_PARM_DESC(timeout, "Watchdog time static int nowayout = WATCHDOG_NOWAYOUT; module_param(nowayout, int, 0); -MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=CONFIG_WATCHDOG_NOWAYOUT)"); +MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=" __MODULE_STRING(WATCHDOG_NOWAYOUT) ")"); static void wafwdt_ping(void) { diff --git a/drivers/char/watchdog/wdt.c b/drivers/char/watchdog/wdt.c index 517fbd8..0a3de6a 100644 --- a/drivers/char/watchdog/wdt.c +++ b/drivers/char/watchdog/wdt.c @@ -64,7 +64,7 @@ MODULE_PARM_DESC(heartbeat, "Watchdog he static int nowayout = WATCHDOG_NOWAYOUT; module_param(nowayout, int, 0); -MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=CONFIG_WATCHDOG_NOWAYOUT)"); +MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=" __MODULE_STRING(WATCHDOG_NOWAYOUT) ")"); /* You must set these - there is no sane way to probe for this board. */ static int io=0x240; diff --git a/drivers/char/watchdog/wdt977.c b/drivers/char/watchdog/wdt977.c index 6253041..7d300ff 100644 --- a/drivers/char/watchdog/wdt977.c +++ b/drivers/char/watchdog/wdt977.c @@ -68,7 +68,7 @@ MODULE_PARM_DESC(testmode,"Watchdog test static int nowayout = WATCHDOG_NOWAYOUT; module_param(nowayout, int, 0); -MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=CONFIG_WATCHDOG_NOWAYOUT)"); +MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=" __MODULE_STRING(WATCHDOG_NOWAYOUT) ")"); /* * Start the watchdog diff --git a/drivers/char/watchdog/wdt_pci.c b/drivers/char/watchdog/wdt_pci.c index ce1261c..6baf4ae 100644 --- a/drivers/char/watchdog/wdt_pci.c +++ b/drivers/char/watchdog/wdt_pci.c @@ -90,7 +90,7 @@ MODULE_PARM_DESC(heartbeat, "Watchdog he static int nowayout = WATCHDOG_NOWAYOUT; module_param(nowayout, int, 0); -MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=CONFIG_WATCHDOG_NOWAYOUT)"); +MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=" __MODULE_STRING(WATCHDOG_NOWAYOUT) ")"); #ifdef CONFIG_WDT_501_PCI /* Support for the Fan Tachometer on the PCI-WDT501 */ diff --git a/drivers/clocksource/acpi_pm.c b/drivers/clocksource/acpi_pm.c index b6bcdbb..ccaa6a3 100644 --- a/drivers/clocksource/acpi_pm.c +++ b/drivers/clocksource/acpi_pm.c @@ -16,15 +16,13 @@ * This file is licensed under the GPL v2. */ +#include #include #include #include #include #include -/* Number of PMTMR ticks expected during calibration run */ -#define PMTMR_TICKS_PER_SEC 3579545 - /* * The I/O port the PMTMR resides at. * The location is detected during setup_arch(), @@ -32,15 +30,13 @@ #define PMTMR_TICKS_PER_SEC 3579545 */ u32 pmtmr_ioport __read_mostly; -#define ACPI_PM_MASK CLOCKSOURCE_MASK(24) /* limit it to 24 bits */ - static inline u32 read_pmtmr(void) { /* mask the output to 24 bits */ return inl(pmtmr_ioport) & ACPI_PM_MASK; } -static cycle_t acpi_pm_read_verified(void) +u32 acpi_pm_read_verified(void) { u32 v1 = 0, v2 = 0, v3 = 0; @@ -57,7 +53,12 @@ static cycle_t acpi_pm_read_verified(voi } while (unlikely((v1 > v2 && v1 < v3) || (v2 > v3 && v2 < v1) || (v3 > v1 && v3 < v2))); - return (cycle_t)v2; + return v2; +} + +static cycle_t acpi_pm_read_slow(void) +{ + return (cycle_t)acpi_pm_read_verified(); } static cycle_t acpi_pm_read(void) @@ -72,7 +73,8 @@ static struct clocksource clocksource_ac .mask = (cycle_t)ACPI_PM_MASK, .mult = 0, /*to be caluclated*/ .shift = 22, - .is_continuous = 1, + .flags = CLOCK_SOURCE_IS_CONTINUOUS, + }; @@ -87,7 +89,7 @@ __setup("acpi_pm_good", acpi_pm_good_set static inline void acpi_pm_need_workaround(void) { - clocksource_acpi_pm.read = acpi_pm_read_verified; + clocksource_acpi_pm.read = acpi_pm_read_slow; clocksource_acpi_pm.rating = 110; } diff --git a/drivers/clocksource/cyclone.c b/drivers/clocksource/cyclone.c index bf4d3d5..4f3925c 100644 --- a/drivers/clocksource/cyclone.c +++ b/drivers/clocksource/cyclone.c @@ -31,7 +31,7 @@ static struct clocksource clocksource_cy .mask = CYCLONE_TIMER_MASK, .mult = 10, .shift = 0, - .is_continuous = 1, + .flags = CLOCK_SOURCE_IS_CONTINUOUS, }; static int __init init_cyclone_clocksource(void) diff --git a/drivers/clocksource/scx200_hrt.c b/drivers/clocksource/scx200_hrt.c index 22915cc..b92da67 100644 --- a/drivers/clocksource/scx200_hrt.c +++ b/drivers/clocksource/scx200_hrt.c @@ -57,7 +57,7 @@ static struct clocksource cs_hrt = { .rating = 250, .read = read_hrt, .mask = CLOCKSOURCE_MASK(32), - .is_continuous = 1, + .flags = CLOCK_SOURCE_IS_CONTINUOUS, /* mult, shift are set based on mhz27 flag */ }; diff --git a/drivers/cpufreq/Kconfig b/drivers/cpufreq/Kconfig index 491779a..d155e81 100644 --- a/drivers/cpufreq/Kconfig +++ b/drivers/cpufreq/Kconfig @@ -16,7 +16,7 @@ config CPU_FREQ if CPU_FREQ config CPU_FREQ_TABLE - def_tristate m + tristate config CPU_FREQ_DEBUG bool "Enable CPUfreq debugging" diff --git a/drivers/cpufreq/cpufreq.c b/drivers/cpufreq/cpufreq.c index a45cc89..f52facc 100644 --- a/drivers/cpufreq/cpufreq.c +++ b/drivers/cpufreq/cpufreq.c @@ -41,8 +41,67 @@ static struct cpufreq_driver *cpufreq_dr static struct cpufreq_policy *cpufreq_cpu_data[NR_CPUS]; static DEFINE_SPINLOCK(cpufreq_driver_lock); +/* + * cpu_policy_rwsem is a per CPU reader-writer semaphore designed to cure + * all cpufreq/hotplug/workqueue/etc related lock issues. + * + * The rules for this semaphore: + * - Any routine that wants to read from the policy structure will + * do a down_read on this semaphore. + * - Any routine that will write to the policy structure and/or may take away + * the policy altogether (eg. CPU hotplug), will hold this lock in write + * mode before doing so. + * + * Additional rules: + * - All holders of the lock should check to make sure that the CPU they + * are concerned with are online after they get the lock. + * - Governor routines that can be called in cpufreq hotplug path should not + * take this sem as top level hotplug notifier handler takes this. + */ +static DEFINE_PER_CPU(int, policy_cpu); +static DEFINE_PER_CPU(struct rw_semaphore, cpu_policy_rwsem); + +#define lock_policy_rwsem(mode, cpu) \ +int lock_policy_rwsem_##mode \ +(int cpu) \ +{ \ + int policy_cpu = per_cpu(policy_cpu, cpu); \ + BUG_ON(policy_cpu == -1); \ + down_##mode(&per_cpu(cpu_policy_rwsem, policy_cpu)); \ + if (unlikely(!cpu_online(cpu))) { \ + up_##mode(&per_cpu(cpu_policy_rwsem, policy_cpu)); \ + return -1; \ + } \ + \ + return 0; \ +} + +lock_policy_rwsem(read, cpu); +EXPORT_SYMBOL_GPL(lock_policy_rwsem_read); + +lock_policy_rwsem(write, cpu); +EXPORT_SYMBOL_GPL(lock_policy_rwsem_write); + +void unlock_policy_rwsem_read(int cpu) +{ + int policy_cpu = per_cpu(policy_cpu, cpu); + BUG_ON(policy_cpu == -1); + up_read(&per_cpu(cpu_policy_rwsem, policy_cpu)); +} +EXPORT_SYMBOL_GPL(unlock_policy_rwsem_read); + +void unlock_policy_rwsem_write(int cpu) +{ + int policy_cpu = per_cpu(policy_cpu, cpu); + BUG_ON(policy_cpu == -1); + up_write(&per_cpu(cpu_policy_rwsem, policy_cpu)); +} +EXPORT_SYMBOL_GPL(unlock_policy_rwsem_write); + + /* internal prototypes */ static int __cpufreq_governor(struct cpufreq_policy *policy, unsigned int event); +static unsigned int __cpufreq_get(unsigned int cpu); static void handle_update(struct work_struct *work); /** @@ -415,12 +474,8 @@ (struct cpufreq_policy * policy, const c if (ret != 1) \ return -EINVAL; \ \ - lock_cpu_hotplug(); \ - mutex_lock(&policy->lock); \ ret = __cpufreq_set_policy(policy, &new_policy); \ policy->user_policy.object = policy->object; \ - mutex_unlock(&policy->lock); \ - unlock_cpu_hotplug(); \ \ return ret ? ret : count; \ } @@ -434,7 +489,7 @@ store_one(scaling_max_freq,max); static ssize_t show_cpuinfo_cur_freq (struct cpufreq_policy * policy, char *buf) { - unsigned int cur_freq = cpufreq_get(policy->cpu); + unsigned int cur_freq = __cpufreq_get(policy->cpu); if (!cur_freq) return sprintf(buf, ""); return sprintf(buf, "%u\n", cur_freq); @@ -479,18 +534,12 @@ static ssize_t store_scaling_governor (s &new_policy.governor)) return -EINVAL; - lock_cpu_hotplug(); - /* Do not use cpufreq_set_policy here or the user_policy.max will be wrongly overridden */ - mutex_lock(&policy->lock); ret = __cpufreq_set_policy(policy, &new_policy); policy->user_policy.policy = policy->policy; policy->user_policy.governor = policy->governor; - mutex_unlock(&policy->lock); - - unlock_cpu_hotplug(); if (ret) return ret; @@ -595,11 +644,17 @@ static ssize_t show(struct kobject * kob policy = cpufreq_cpu_get(policy->cpu); if (!policy) return -EINVAL; + + if (lock_policy_rwsem_read(policy->cpu) < 0) + return -EINVAL; + if (fattr->show) ret = fattr->show(policy, buf); else ret = -EIO; + unlock_policy_rwsem_read(policy->cpu); + cpufreq_cpu_put(policy); return ret; } @@ -613,11 +668,17 @@ static ssize_t store(struct kobject * ko policy = cpufreq_cpu_get(policy->cpu); if (!policy) return -EINVAL; + + if (lock_policy_rwsem_write(policy->cpu) < 0) + return -EINVAL; + if (fattr->store) ret = fattr->store(policy, buf, count); else ret = -EIO; + unlock_policy_rwsem_write(policy->cpu); + cpufreq_cpu_put(policy); return ret; } @@ -691,8 +752,10 @@ #endif policy->cpu = cpu; policy->cpus = cpumask_of_cpu(cpu); - mutex_init(&policy->lock); - mutex_lock(&policy->lock); + /* Initially set CPU itself as the policy_cpu */ + per_cpu(policy_cpu, cpu) = cpu; + lock_policy_rwsem_write(cpu); + init_completion(&policy->kobj_unregister); INIT_WORK(&policy->update, handle_update); @@ -702,7 +765,7 @@ #endif ret = cpufreq_driver->init(policy); if (ret) { dprintk("initialization failed\n"); - mutex_unlock(&policy->lock); + unlock_policy_rwsem_write(cpu); goto err_out; } @@ -716,6 +779,14 @@ #ifdef CONFIG_SMP */ managed_policy = cpufreq_cpu_get(j); if (unlikely(managed_policy)) { + + /* Set proper policy_cpu */ + unlock_policy_rwsem_write(cpu); + per_cpu(policy_cpu, cpu) = managed_policy->cpu; + + if (lock_policy_rwsem_write(cpu) < 0) + goto err_out_driver_exit; + spin_lock_irqsave(&cpufreq_driver_lock, flags); managed_policy->cpus = policy->cpus; cpufreq_cpu_data[cpu] = managed_policy; @@ -726,13 +797,13 @@ #ifdef CONFIG_SMP &managed_policy->kobj, "cpufreq"); if (ret) { - mutex_unlock(&policy->lock); + unlock_policy_rwsem_write(cpu); goto err_out_driver_exit; } cpufreq_debug_enable_ratelimit(); - mutex_unlock(&policy->lock); ret = 0; + unlock_policy_rwsem_write(cpu); goto err_out_driver_exit; /* call driver->exit() */ } } @@ -746,7 +817,7 @@ #endif ret = kobject_register(&policy->kobj); if (ret) { - mutex_unlock(&policy->lock); + unlock_policy_rwsem_write(cpu); goto err_out_driver_exit; } /* set up files for this cpu device */ @@ -761,8 +832,10 @@ #endif sysfs_create_file(&policy->kobj, &scaling_cur_freq.attr); spin_lock_irqsave(&cpufreq_driver_lock, flags); - for_each_cpu_mask(j, policy->cpus) + for_each_cpu_mask(j, policy->cpus) { cpufreq_cpu_data[j] = policy; + per_cpu(policy_cpu, j) = policy->cpu; + } spin_unlock_irqrestore(&cpufreq_driver_lock, flags); /* symlink affected CPUs */ @@ -778,14 +851,14 @@ #endif ret = sysfs_create_link(&cpu_sys_dev->kobj, &policy->kobj, "cpufreq"); if (ret) { - mutex_unlock(&policy->lock); + unlock_policy_rwsem_write(cpu); goto err_out_unregister; } } policy->governor = NULL; /* to assure that the starting sequence is * run in cpufreq_set_policy */ - mutex_unlock(&policy->lock); + unlock_policy_rwsem_write(cpu); /* set default policy */ ret = cpufreq_set_policy(&new_policy); @@ -826,11 +899,13 @@ module_out: /** - * cpufreq_remove_dev - remove a CPU device + * __cpufreq_remove_dev - remove a CPU device * * Removes the cpufreq interface for a CPU device. + * Caller should already have policy_rwsem in write mode for this CPU. + * This routine frees the rwsem before returning. */ -static int cpufreq_remove_dev (struct sys_device * sys_dev) +static int __cpufreq_remove_dev (struct sys_device * sys_dev) { unsigned int cpu = sys_dev->id; unsigned long flags; @@ -849,6 +924,7 @@ #endif if (!data) { spin_unlock_irqrestore(&cpufreq_driver_lock, flags); cpufreq_debug_enable_ratelimit(); + unlock_policy_rwsem_write(cpu); return -EINVAL; } cpufreq_cpu_data[cpu] = NULL; @@ -865,6 +941,7 @@ #ifdef CONFIG_SMP sysfs_remove_link(&sys_dev->kobj, "cpufreq"); cpufreq_cpu_put(data); cpufreq_debug_enable_ratelimit(); + unlock_policy_rwsem_write(cpu); return 0; } #endif @@ -873,6 +950,7 @@ #endif if (!kobject_get(&data->kobj)) { spin_unlock_irqrestore(&cpufreq_driver_lock, flags); cpufreq_debug_enable_ratelimit(); + unlock_policy_rwsem_write(cpu); return -EFAULT; } @@ -906,10 +984,10 @@ #else spin_unlock_irqrestore(&cpufreq_driver_lock, flags); #endif - mutex_lock(&data->lock); if (cpufreq_driver->target) __cpufreq_governor(data, CPUFREQ_GOV_STOP); - mutex_unlock(&data->lock); + + unlock_policy_rwsem_write(cpu); kobject_unregister(&data->kobj); @@ -933,6 +1011,18 @@ #endif } +static int cpufreq_remove_dev (struct sys_device * sys_dev) +{ + unsigned int cpu = sys_dev->id; + int retval; + if (unlikely(lock_policy_rwsem_write(cpu))) + BUG(); + + retval = __cpufreq_remove_dev(sys_dev); + return retval; +} + + static void handle_update(struct work_struct *work) { struct cpufreq_policy *policy = @@ -980,9 +1070,12 @@ unsigned int cpufreq_quick_get(unsigned unsigned int ret_freq = 0; if (policy) { - mutex_lock(&policy->lock); + if (unlikely(lock_policy_rwsem_read(cpu))) + return ret_freq; + ret_freq = policy->cur; - mutex_unlock(&policy->lock); + + unlock_policy_rwsem_read(cpu); cpufreq_cpu_put(policy); } @@ -991,24 +1084,13 @@ unsigned int cpufreq_quick_get(unsigned EXPORT_SYMBOL(cpufreq_quick_get); -/** - * cpufreq_get - get the current CPU frequency (in kHz) - * @cpu: CPU number - * - * Get the CPU current (static) CPU frequency - */ -unsigned int cpufreq_get(unsigned int cpu) +static unsigned int __cpufreq_get(unsigned int cpu) { - struct cpufreq_policy *policy = cpufreq_cpu_get(cpu); + struct cpufreq_policy *policy = cpufreq_cpu_data[cpu]; unsigned int ret_freq = 0; - if (!policy) - return 0; - if (!cpufreq_driver->get) - goto out; - - mutex_lock(&policy->lock); + return (ret_freq); ret_freq = cpufreq_driver->get(cpu); @@ -1022,11 +1104,33 @@ unsigned int cpufreq_get(unsigned int cp } } - mutex_unlock(&policy->lock); + return (ret_freq); +} -out: - cpufreq_cpu_put(policy); +/** + * cpufreq_get - get the current CPU frequency (in kHz) + * @cpu: CPU number + * + * Get the CPU current (static) CPU frequency + */ +unsigned int cpufreq_get(unsigned int cpu) +{ + unsigned int ret_freq = 0; + struct cpufreq_policy *policy = cpufreq_cpu_get(cpu); + + if (!policy) + goto out; + + if (unlikely(lock_policy_rwsem_read(cpu))) + goto out_policy; + + ret_freq = __cpufreq_get(cpu); + unlock_policy_rwsem_read(cpu); + +out_policy: + cpufreq_cpu_put(policy); +out: return (ret_freq); } EXPORT_SYMBOL(cpufreq_get); @@ -1278,7 +1382,6 @@ EXPORT_SYMBOL(cpufreq_unregister_notifie *********************************************************************/ -/* Must be called with lock_cpu_hotplug held */ int __cpufreq_driver_target(struct cpufreq_policy *policy, unsigned int target_freq, unsigned int relation) @@ -1304,20 +1407,19 @@ int cpufreq_driver_target(struct cpufreq if (!policy) return -EINVAL; - lock_cpu_hotplug(); - mutex_lock(&policy->lock); + if (unlikely(lock_policy_rwsem_write(policy->cpu))) + return -EINVAL; ret = __cpufreq_driver_target(policy, target_freq, relation); - mutex_unlock(&policy->lock); - unlock_cpu_hotplug(); + unlock_policy_rwsem_write(policy->cpu); cpufreq_cpu_put(policy); return ret; } EXPORT_SYMBOL_GPL(cpufreq_driver_target); -int cpufreq_driver_getavg(struct cpufreq_policy *policy) +int __cpufreq_driver_getavg(struct cpufreq_policy *policy) { int ret = 0; @@ -1325,20 +1427,15 @@ int cpufreq_driver_getavg(struct cpufreq if (!policy) return -EINVAL; - mutex_lock(&policy->lock); - if (cpu_online(policy->cpu) && cpufreq_driver->getavg) ret = cpufreq_driver->getavg(policy->cpu); - mutex_unlock(&policy->lock); - cpufreq_cpu_put(policy); return ret; } -EXPORT_SYMBOL_GPL(cpufreq_driver_getavg); +EXPORT_SYMBOL_GPL(__cpufreq_driver_getavg); /* - * Locking: Must be called with the lock_cpu_hotplug() lock held * when "event" is CPUFREQ_GOV_LIMITS */ @@ -1420,9 +1517,7 @@ int cpufreq_get_policy(struct cpufreq_po if (!cpu_policy) return -EINVAL; - mutex_lock(&cpu_policy->lock); memcpy(policy, cpu_policy, sizeof(struct cpufreq_policy)); - mutex_unlock(&cpu_policy->lock); cpufreq_cpu_put(cpu_policy); return 0; @@ -1433,7 +1528,6 @@ EXPORT_SYMBOL(cpufreq_get_policy); /* * data : current policy. * policy : policy to be set. - * Locking: Must be called with the lock_cpu_hotplug() lock held */ static int __cpufreq_set_policy(struct cpufreq_policy *data, struct cpufreq_policy *policy) @@ -1539,10 +1633,9 @@ int cpufreq_set_policy(struct cpufreq_po if (!data) return -EINVAL; - lock_cpu_hotplug(); + if (unlikely(lock_policy_rwsem_write(policy->cpu))) + return -EINVAL; - /* lock this CPU */ - mutex_lock(&data->lock); ret = __cpufreq_set_policy(data, policy); data->user_policy.min = data->min; @@ -1550,9 +1643,8 @@ int cpufreq_set_policy(struct cpufreq_po data->user_policy.policy = data->policy; data->user_policy.governor = data->governor; - mutex_unlock(&data->lock); + unlock_policy_rwsem_write(policy->cpu); - unlock_cpu_hotplug(); cpufreq_cpu_put(data); return ret; @@ -1576,8 +1668,8 @@ int cpufreq_update_policy(unsigned int c if (!data) return -ENODEV; - lock_cpu_hotplug(); - mutex_lock(&data->lock); + if (unlikely(lock_policy_rwsem_write(cpu))) + return -EINVAL; dprintk("updating policy for CPU %u\n", cpu); memcpy(&policy, data, sizeof(struct cpufreq_policy)); @@ -1602,8 +1694,8 @@ int cpufreq_update_policy(unsigned int c ret = __cpufreq_set_policy(data, &policy); - mutex_unlock(&data->lock); - unlock_cpu_hotplug(); + unlock_policy_rwsem_write(cpu); + cpufreq_cpu_put(data); return ret; } @@ -1613,31 +1705,28 @@ static int cpufreq_cpu_callback(struct n unsigned long action, void *hcpu) { unsigned int cpu = (unsigned long)hcpu; - struct cpufreq_policy *policy; struct sys_device *sys_dev; + struct cpufreq_policy *policy; sys_dev = get_cpu_sysdev(cpu); - if (sys_dev) { switch (action) { case CPU_ONLINE: cpufreq_add_dev(sys_dev); break; case CPU_DOWN_PREPARE: - /* - * We attempt to put this cpu in lowest frequency - * possible before going down. This will permit - * hardware-managed P-State to switch other related - * threads to min or higher speeds if possible. - */ + if (unlikely(lock_policy_rwsem_write(cpu))) + BUG(); + policy = cpufreq_cpu_data[cpu]; if (policy) { - cpufreq_driver_target(policy, policy->min, + __cpufreq_driver_target(policy, policy->min, CPUFREQ_RELATION_H); } + __cpufreq_remove_dev(sys_dev); break; - case CPU_DEAD: - cpufreq_remove_dev(sys_dev); + case CPU_DOWN_FAILED: + cpufreq_add_dev(sys_dev); break; } } @@ -1751,3 +1840,16 @@ int cpufreq_unregister_driver(struct cpu return 0; } EXPORT_SYMBOL_GPL(cpufreq_unregister_driver); + +static int __init cpufreq_core_init(void) +{ + int cpu; + + for_each_possible_cpu(cpu) { + per_cpu(policy_cpu, cpu) = -1; + init_rwsem(&per_cpu(cpu_policy_rwsem, cpu)); + } + return 0; +} + +core_initcall(cpufreq_core_init); diff --git a/drivers/cpufreq/cpufreq_conservative.c b/drivers/cpufreq/cpufreq_conservative.c index eef0270..26f440c 100644 --- a/drivers/cpufreq/cpufreq_conservative.c +++ b/drivers/cpufreq/cpufreq_conservative.c @@ -23,7 +23,6 @@ #include #include #include #include -#include #include #include #include @@ -430,14 +429,12 @@ static void dbs_check_cpu(int cpu) static void do_dbs_timer(struct work_struct *work) { int i; - lock_cpu_hotplug(); mutex_lock(&dbs_mutex); for_each_online_cpu(i) dbs_check_cpu(i); schedule_delayed_work(&dbs_work, usecs_to_jiffies(dbs_tuners_ins.sampling_rate)); mutex_unlock(&dbs_mutex); - unlock_cpu_hotplug(); } static inline void dbs_timer_init(void) diff --git a/drivers/cpufreq/cpufreq_ondemand.c b/drivers/cpufreq/cpufreq_ondemand.c index f697449..d60bcb9 100644 --- a/drivers/cpufreq/cpufreq_ondemand.c +++ b/drivers/cpufreq/cpufreq_ondemand.c @@ -52,19 +52,20 @@ #define TRANSITION_LATENCY_LIMIT (10 * static void do_dbs_timer(struct work_struct *work); /* Sampling types */ -enum dbs_sample {DBS_NORMAL_SAMPLE, DBS_SUB_SAMPLE}; +enum {DBS_NORMAL_SAMPLE, DBS_SUB_SAMPLE}; struct cpu_dbs_info_s { cputime64_t prev_cpu_idle; cputime64_t prev_cpu_wall; struct cpufreq_policy *cur_policy; struct delayed_work work; - enum dbs_sample sample_type; - unsigned int enable; struct cpufreq_frequency_table *freq_table; unsigned int freq_lo; unsigned int freq_lo_jiffies; unsigned int freq_hi_jiffies; + int cpu; + unsigned int enable:1, + sample_type:1; }; static DEFINE_PER_CPU(struct cpu_dbs_info_s, cpu_dbs_info); @@ -402,7 +403,7 @@ static void dbs_check_cpu(struct cpu_dbs if (load < (dbs_tuners_ins.up_threshold - 10)) { unsigned int freq_next, freq_cur; - freq_cur = cpufreq_driver_getavg(policy); + freq_cur = __cpufreq_driver_getavg(policy); if (!freq_cur) freq_cur = policy->cur; @@ -423,9 +424,11 @@ static void dbs_check_cpu(struct cpu_dbs static void do_dbs_timer(struct work_struct *work) { - unsigned int cpu = smp_processor_id(); - struct cpu_dbs_info_s *dbs_info = &per_cpu(cpu_dbs_info, cpu); - enum dbs_sample sample_type = dbs_info->sample_type; + struct cpu_dbs_info_s *dbs_info = + container_of(work, struct cpu_dbs_info_s, work.work); + unsigned int cpu = dbs_info->cpu; + int sample_type = dbs_info->sample_type; + /* We want all CPUs to do sampling nearly on same jiffy */ int delay = usecs_to_jiffies(dbs_tuners_ins.sampling_rate); @@ -434,15 +437,19 @@ static void do_dbs_timer(struct work_str delay -= jiffies % delay; - if (!dbs_info->enable) + if (lock_policy_rwsem_write(cpu) < 0) + return; + + if (!dbs_info->enable) { + unlock_policy_rwsem_write(cpu); return; + } + /* Common NORMAL_SAMPLE setup */ dbs_info->sample_type = DBS_NORMAL_SAMPLE; if (!dbs_tuners_ins.powersave_bias || sample_type == DBS_NORMAL_SAMPLE) { - lock_cpu_hotplug(); dbs_check_cpu(dbs_info); - unlock_cpu_hotplug(); if (dbs_info->freq_lo) { /* Setup timer for SUB_SAMPLE */ dbs_info->sample_type = DBS_SUB_SAMPLE; @@ -454,26 +461,27 @@ static void do_dbs_timer(struct work_str CPUFREQ_RELATION_H); } queue_delayed_work_on(cpu, kondemand_wq, &dbs_info->work, delay); + unlock_policy_rwsem_write(cpu); } -static inline void dbs_timer_init(unsigned int cpu) +static inline void dbs_timer_init(struct cpu_dbs_info_s *dbs_info) { - struct cpu_dbs_info_s *dbs_info = &per_cpu(cpu_dbs_info, cpu); /* We want all CPUs to do sampling nearly on same jiffy */ int delay = usecs_to_jiffies(dbs_tuners_ins.sampling_rate); delay -= jiffies % delay; + dbs_info->enable = 1; ondemand_powersave_bias_init(); - INIT_DELAYED_WORK_NAR(&dbs_info->work, do_dbs_timer); dbs_info->sample_type = DBS_NORMAL_SAMPLE; - queue_delayed_work_on(cpu, kondemand_wq, &dbs_info->work, delay); + INIT_DELAYED_WORK_NAR(&dbs_info->work, do_dbs_timer); + queue_delayed_work_on(dbs_info->cpu, kondemand_wq, &dbs_info->work, + delay); } static inline void dbs_timer_exit(struct cpu_dbs_info_s *dbs_info) { dbs_info->enable = 0; cancel_delayed_work(&dbs_info->work); - flush_workqueue(kondemand_wq); } static int cpufreq_governor_dbs(struct cpufreq_policy *policy, @@ -502,21 +510,9 @@ static int cpufreq_governor_dbs(struct c mutex_lock(&dbs_mutex); dbs_enable++; - if (dbs_enable == 1) { - kondemand_wq = create_workqueue("kondemand"); - if (!kondemand_wq) { - printk(KERN_ERR - "Creation of kondemand failed\n"); - dbs_enable--; - mutex_unlock(&dbs_mutex); - return -ENOSPC; - } - } rc = sysfs_create_group(&policy->kobj, &dbs_attr_group); if (rc) { - if (dbs_enable == 1) - destroy_workqueue(kondemand_wq); dbs_enable--; mutex_unlock(&dbs_mutex); return rc; @@ -530,7 +526,7 @@ static int cpufreq_governor_dbs(struct c j_dbs_info->prev_cpu_idle = get_cpu_idle_time(j); j_dbs_info->prev_cpu_wall = get_jiffies_64(); } - this_dbs_info->enable = 1; + this_dbs_info->cpu = cpu; /* * Start the timerschedule work, when this governor * is used for first time @@ -550,7 +546,7 @@ static int cpufreq_governor_dbs(struct c dbs_tuners_ins.sampling_rate = def_sampling_rate; } - dbs_timer_init(policy->cpu); + dbs_timer_init(this_dbs_info); mutex_unlock(&dbs_mutex); break; @@ -560,9 +556,6 @@ static int cpufreq_governor_dbs(struct c dbs_timer_exit(this_dbs_info); sysfs_remove_group(&policy->kobj, &dbs_attr_group); dbs_enable--; - if (dbs_enable == 0) - destroy_workqueue(kondemand_wq); - mutex_unlock(&dbs_mutex); break; @@ -591,12 +584,18 @@ static struct cpufreq_governor cpufreq_g static int __init cpufreq_gov_dbs_init(void) { + kondemand_wq = create_workqueue("kondemand"); + if (!kondemand_wq) { + printk(KERN_ERR "Creation of kondemand failed\n"); + return -EFAULT; + } return cpufreq_register_governor(&cpufreq_gov_dbs); } static void __exit cpufreq_gov_dbs_exit(void) { cpufreq_unregister_governor(&cpufreq_gov_dbs); + destroy_workqueue(kondemand_wq); } @@ -608,3 +607,4 @@ MODULE_LICENSE("GPL"); module_init(cpufreq_gov_dbs_init); module_exit(cpufreq_gov_dbs_exit); + diff --git a/drivers/cpufreq/cpufreq_stats.c b/drivers/cpufreq/cpufreq_stats.c index 91ad342..d1c7cac 100644 --- a/drivers/cpufreq/cpufreq_stats.c +++ b/drivers/cpufreq/cpufreq_stats.c @@ -370,12 +370,10 @@ __exit cpufreq_stats_exit(void) cpufreq_unregister_notifier(¬ifier_trans_block, CPUFREQ_TRANSITION_NOTIFIER); unregister_hotcpu_notifier(&cpufreq_stat_cpu_notifier); - lock_cpu_hotplug(); for_each_online_cpu(cpu) { cpufreq_stat_cpu_callback(&cpufreq_stat_cpu_notifier, CPU_DEAD, (void *)(long)cpu); } - unlock_cpu_hotplug(); } MODULE_AUTHOR ("Zou Nan hai "); diff --git a/drivers/cpufreq/cpufreq_userspace.c b/drivers/cpufreq/cpufreq_userspace.c index 2a4eb0b..860345c 100644 --- a/drivers/cpufreq/cpufreq_userspace.c +++ b/drivers/cpufreq/cpufreq_userspace.c @@ -71,7 +71,6 @@ static int cpufreq_set(unsigned int freq dprintk("cpufreq_set for cpu %u, freq %u kHz\n", policy->cpu, freq); - lock_cpu_hotplug(); mutex_lock(&userspace_mutex); if (!cpu_is_managed[policy->cpu]) goto err; @@ -94,7 +93,6 @@ static int cpufreq_set(unsigned int freq err: mutex_unlock(&userspace_mutex); - unlock_cpu_hotplug(); return ret; } diff --git a/drivers/crypto/Kconfig b/drivers/crypto/Kconfig index 879250d..ff8c4be 100644 --- a/drivers/crypto/Kconfig +++ b/drivers/crypto/Kconfig @@ -51,6 +51,8 @@ config CRYPTO_DEV_PADLOCK_SHA If unsure say M. The compiled module will be called padlock-sha.ko +source "arch/s390/crypto/Kconfig" + config CRYPTO_DEV_GEODE tristate "Support for the Geode LX AES engine" depends on CRYPTO && X86_32 && PCI diff --git a/drivers/crypto/geode-aes.c b/drivers/crypto/geode-aes.c index 43a6839..0eb6284 100644 --- a/drivers/crypto/geode-aes.c +++ b/drivers/crypto/geode-aes.c @@ -8,7 +8,6 @@ #include #include -#include #include #include #include @@ -457,7 +456,7 @@ static struct pci_driver geode_aes_drive static int __init geode_aes_init(void) { - return pci_module_init(&geode_aes_driver); + return pci_register_driver(&geode_aes_driver); } static void __exit diff --git a/drivers/edac/e752x_edac.c b/drivers/edac/e752x_edac.c index c82bc0e..8bcc887 100644 --- a/drivers/edac/e752x_edac.c +++ b/drivers/edac/e752x_edac.c @@ -285,8 +285,9 @@ static void do_process_ce(struct mem_ctl if (!pvt->map_type) row = 7 - row; - edac_mc_handle_ce(mci, page, 0, sec1_syndrome, row, channel, - "e752x CE"); + /* e752x mc reads 34:6 of the DRAM linear address */ + edac_mc_handle_ce(mci, page, offset_in_page(sec1_add << 4), + sec1_syndrome, row, channel, "e752x CE"); } static inline void process_ce(struct mem_ctl_info *mci, u16 error_one, @@ -319,8 +320,10 @@ static void do_process_ue(struct mem_ctl ((block_page >> 1) & 3) : edac_mc_find_csrow_by_page(mci, block_page); - edac_mc_handle_ue(mci, block_page, 0, row, - "e752x UE from Read"); + /* e752x mc reads 34:6 of the DRAM linear address */ + edac_mc_handle_ue(mci, block_page, + offset_in_page(error_2b << 4), + row, "e752x UE from Read"); } if (error_one & 0x0404) { error_2b = scrb_add; @@ -333,8 +336,10 @@ static void do_process_ue(struct mem_ctl ((block_page >> 1) & 3) : edac_mc_find_csrow_by_page(mci, block_page); - edac_mc_handle_ue(mci, block_page, 0, row, - "e752x UE from Scruber"); + /* e752x mc reads 34:6 of the DRAM linear address */ + edac_mc_handle_ue(mci, block_page, + offset_in_page(error_2b << 4), + row, "e752x UE from Scruber"); } } @@ -556,17 +561,17 @@ static void e752x_check_sysbus(struct e7 error32 = (stat32 >> 16) & 0x3ff; stat32 = stat32 & 0x3ff; - if(stat32 & 0x083) - sysbus_error(1, stat32 & 0x083, error_found, handle_error); + if(stat32 & 0x087) + sysbus_error(1, stat32 & 0x087, error_found, handle_error); - if(stat32 & 0x37c) - sysbus_error(0, stat32 & 0x37c, error_found, handle_error); + if(stat32 & 0x378) + sysbus_error(0, stat32 & 0x378, error_found, handle_error); - if(error32 & 0x083) - sysbus_error(1, error32 & 0x083, error_found, handle_error); + if(error32 & 0x087) + sysbus_error(1, error32 & 0x087, error_found, handle_error); - if(error32 & 0x37c) - sysbus_error(0, error32 & 0x37c, error_found, handle_error); + if(error32 & 0x378) + sysbus_error(0, error32 & 0x378, error_found, handle_error); } static void e752x_check_membuf (struct e752x_error_info *info, @@ -782,7 +787,12 @@ static void e752x_init_csrows(struct mem u8 value; u32 dra, drc, cumul_size; - pci_read_config_dword(pdev, E752X_DRA, &dra); + dra = 0; + for (index=0; index < 4; index++) { + u8 dra_reg; + pci_read_config_byte(pdev, E752X_DRA+index, &dra_reg); + dra |= dra_reg << (index * 8); + } pci_read_config_dword(pdev, E752X_DRC, &drc); drc_chan = dual_channel_active(ddrcsr); drc_drbg = drc_chan + 1; /* 128 in dual mode, 64 in single */ diff --git a/drivers/edac/edac_mc.c b/drivers/edac/edac_mc.c index 1b4fc92..7b62230 100644 --- a/drivers/edac/edac_mc.c +++ b/drivers/edac/edac_mc.c @@ -927,6 +927,57 @@ static ssize_t mci_reset_counters_store( return count; } +/* memory scrubbing */ +static ssize_t mci_sdram_scrub_rate_store(struct mem_ctl_info *mci, + const char *data, size_t count) +{ + u32 bandwidth = -1; + + if (mci->set_sdram_scrub_rate) { + + memctrl_int_store(&bandwidth, data, count); + + if (!(*mci->set_sdram_scrub_rate)(mci, &bandwidth)) { + edac_printk(KERN_DEBUG, EDAC_MC, + "Scrub rate set successfully, applied: %d\n", + bandwidth); + } else { + /* FIXME: error codes maybe? */ + edac_printk(KERN_DEBUG, EDAC_MC, + "Scrub rate set FAILED, could not apply: %d\n", + bandwidth); + } + } else { + /* FIXME: produce "not implemented" ERROR for user-side. */ + edac_printk(KERN_WARNING, EDAC_MC, + "Memory scrubbing 'set'control is not implemented!\n"); + } + return count; +} + +static ssize_t mci_sdram_scrub_rate_show(struct mem_ctl_info *mci, char *data) +{ + u32 bandwidth = -1; + + if (mci->get_sdram_scrub_rate) { + if (!(*mci->get_sdram_scrub_rate)(mci, &bandwidth)) { + edac_printk(KERN_DEBUG, EDAC_MC, + "Scrub rate successfully, fetched: %d\n", + bandwidth); + } else { + /* FIXME: error codes maybe? */ + edac_printk(KERN_DEBUG, EDAC_MC, + "Scrub rate fetch FAILED, got: %d\n", + bandwidth); + } + } else { + /* FIXME: produce "not implemented" ERROR for user-side. */ + edac_printk(KERN_WARNING, EDAC_MC, + "Memory scrubbing 'get' control is not implemented!\n"); + } + return sprintf(data, "%d\n", bandwidth); +} + /* default attribute files for the MCI object */ static ssize_t mci_ue_count_show(struct mem_ctl_info *mci, char *data) { @@ -1033,6 +1084,9 @@ MCIDEV_ATTR(ce_noinfo_count,S_IRUGO,mci_ MCIDEV_ATTR(ue_count,S_IRUGO,mci_ue_count_show,NULL); MCIDEV_ATTR(ce_count,S_IRUGO,mci_ce_count_show,NULL); +/* memory scrubber attribute file */ +MCIDEV_ATTR(sdram_scrub_rate,S_IRUGO|S_IWUSR,mci_sdram_scrub_rate_show,mci_sdram_scrub_rate_store); + static struct mcidev_attribute *mci_attr[] = { &mci_attr_reset_counters, &mci_attr_mc_name, @@ -1042,6 +1096,7 @@ static struct mcidev_attribute *mci_attr &mci_attr_ce_noinfo_count, &mci_attr_ue_count, &mci_attr_ce_count, + &mci_attr_sdram_scrub_rate, NULL }; @@ -1442,11 +1497,11 @@ #endif /* set load time so that error rate can be tracked */ mci->start_time = jiffies; - if (edac_create_sysfs_mci_device(mci)) { - edac_mc_printk(mci, KERN_WARNING, + if (edac_create_sysfs_mci_device(mci)) { + edac_mc_printk(mci, KERN_WARNING, "failed to create sysfs device\n"); - goto fail1; - } + goto fail1; + } /* Report action taken */ edac_mc_printk(mci, KERN_INFO, "Giving out device to %s %s: DEV %s\n", @@ -1703,6 +1758,116 @@ void edac_mc_handle_ue_no_info(struct me EXPORT_SYMBOL_GPL(edac_mc_handle_ue_no_info); +/************************************************************* + * On Fully Buffered DIMM modules, this help function is + * called to process UE events + */ +void edac_mc_handle_fbd_ue(struct mem_ctl_info *mci, + unsigned int csrow, + unsigned int channela, + unsigned int channelb, + char *msg) +{ + int len = EDAC_MC_LABEL_LEN * 4; + char labels[len + 1]; + char *pos = labels; + int chars; + + if (csrow >= mci->nr_csrows) { + /* something is wrong */ + edac_mc_printk(mci, KERN_ERR, + "INTERNAL ERROR: row out of range (%d >= %d)\n", + csrow, mci->nr_csrows); + edac_mc_handle_ue_no_info(mci, "INTERNAL ERROR"); + return; + } + + if (channela >= mci->csrows[csrow].nr_channels) { + /* something is wrong */ + edac_mc_printk(mci, KERN_ERR, + "INTERNAL ERROR: channel-a out of range " + "(%d >= %d)\n", + channela, mci->csrows[csrow].nr_channels); + edac_mc_handle_ue_no_info(mci, "INTERNAL ERROR"); + return; + } + + if (channelb >= mci->csrows[csrow].nr_channels) { + /* something is wrong */ + edac_mc_printk(mci, KERN_ERR, + "INTERNAL ERROR: channel-b out of range " + "(%d >= %d)\n", + channelb, mci->csrows[csrow].nr_channels); + edac_mc_handle_ue_no_info(mci, "INTERNAL ERROR"); + return; + } + + mci->ue_count++; + mci->csrows[csrow].ue_count++; + + /* Generate the DIMM labels from the specified channels */ + chars = snprintf(pos, len + 1, "%s", + mci->csrows[csrow].channels[channela].label); + len -= chars; pos += chars; + chars = snprintf(pos, len + 1, "-%s", + mci->csrows[csrow].channels[channelb].label); + + if (log_ue) + edac_mc_printk(mci, KERN_EMERG, + "UE row %d, channel-a= %d channel-b= %d " + "labels \"%s\": %s\n", csrow, channela, channelb, + labels, msg); + + if (panic_on_ue) + panic("UE row %d, channel-a= %d channel-b= %d " + "labels \"%s\": %s\n", csrow, channela, + channelb, labels, msg); +} +EXPORT_SYMBOL(edac_mc_handle_fbd_ue); + +/************************************************************* + * On Fully Buffered DIMM modules, this help function is + * called to process CE events + */ +void edac_mc_handle_fbd_ce(struct mem_ctl_info *mci, + unsigned int csrow, + unsigned int channel, + char *msg) +{ + + /* Ensure boundary values */ + if (csrow >= mci->nr_csrows) { + /* something is wrong */ + edac_mc_printk(mci, KERN_ERR, + "INTERNAL ERROR: row out of range (%d >= %d)\n", + csrow, mci->nr_csrows); + edac_mc_handle_ce_no_info(mci, "INTERNAL ERROR"); + return; + } + if (channel >= mci->csrows[csrow].nr_channels) { + /* something is wrong */ + edac_mc_printk(mci, KERN_ERR, + "INTERNAL ERROR: channel out of range (%d >= %d)\n", + channel, mci->csrows[csrow].nr_channels); + edac_mc_handle_ce_no_info(mci, "INTERNAL ERROR"); + return; + } + + if (log_ce) + /* FIXME - put in DIMM location */ + edac_mc_printk(mci, KERN_WARNING, + "CE row %d, channel %d, label \"%s\": %s\n", + csrow, channel, + mci->csrows[csrow].channels[channel].label, + msg); + + mci->ce_count++; + mci->csrows[csrow].ce_count++; + mci->csrows[csrow].channels[channel].ce_count++; +} +EXPORT_SYMBOL(edac_mc_handle_fbd_ce); + + /* * Iterate over all MC instances and check for ECC, et al, errors */ @@ -1806,7 +1971,7 @@ static void __exit edac_mc_exit(void) debugf0("%s()\n", __func__); kthread_stop(edac_thread); - /* tear down the sysfs device */ + /* tear down the sysfs device */ edac_sysfs_memctrl_teardown(); edac_sysfs_pci_teardown(); } diff --git a/drivers/edac/edac_mc.h b/drivers/edac/edac_mc.h index a1cfd4e..713444c 100644 --- a/drivers/edac/edac_mc.h +++ b/drivers/edac/edac_mc.h @@ -123,7 +123,9 @@ enum mem_type { MEM_RDR, /* Registered single data rate SDRAM */ MEM_DDR, /* Double data rate SDRAM */ MEM_RDDR, /* Registered Double data rate SDRAM */ - MEM_RMBS /* Rambus DRAM */ + MEM_RMBS, /* Rambus DRAM */ + MEM_DDR2, /* DDR2 RAM */ + MEM_FB_DDR2, /* fully buffered DDR2 */ }; #define MEM_FLAG_EMPTY BIT(MEM_EMPTY) @@ -137,6 +139,8 @@ #define MEM_FLAG_RDR BIT(MEM_RDR) #define MEM_FLAG_DDR BIT(MEM_DDR) #define MEM_FLAG_RDDR BIT(MEM_RDDR) #define MEM_FLAG_RMBS BIT(MEM_RMBS) +#define MEM_FLAG_DDR2 BIT(MEM_DDR2) +#define MEM_FLAG_FB_DDR2 BIT(MEM_FB_DDR2) /* chipset Error Detection and Correction capabilities and mode */ enum edac_type { @@ -315,8 +319,21 @@ struct mem_ctl_info { unsigned long scrub_cap; /* chipset scrub capabilities */ enum scrub_type scrub_mode; /* current scrub mode */ + /* Translates sdram memory scrub rate given in bytes/sec to the + internal representation and configures whatever else needs + to be configured. + */ + int (*set_sdram_scrub_rate) (struct mem_ctl_info *mci, u32 *bw); + + /* Get the current sdram memory scrub rate from the internal + representation and converts it to the closest matching + bandwith in bytes/sec. + */ + int (*get_sdram_scrub_rate) (struct mem_ctl_info *mci, u32 *bw); + /* pointer to edac checking routine */ void (*edac_check) (struct mem_ctl_info * mci); + /* * Remaps memory pages: controller pages to physical pages. * For most MC's, this will be NULL. @@ -441,6 +458,15 @@ extern void edac_mc_handle_ue(struct mem int row, const char *msg); extern void edac_mc_handle_ue_no_info(struct mem_ctl_info *mci, const char *msg); +extern void edac_mc_handle_fbd_ue(struct mem_ctl_info *mci, + unsigned int csrow, + unsigned int channel0, + unsigned int channel1, + char *msg); +extern void edac_mc_handle_fbd_ce(struct mem_ctl_info *mci, + unsigned int csrow, + unsigned int channel, + char *msg); /* * This kmalloc's and initializes all the structures. diff --git a/drivers/fc4/fc_syms.c b/drivers/fc4/fc_syms.c index 8700a80..bd3918d 100644 --- a/drivers/fc4/fc_syms.c +++ b/drivers/fc4/fc_syms.c @@ -6,7 +6,6 @@ #include #ifdef CONFIG_MODULES -#include #include #include #include diff --git a/drivers/fc4/soc.c b/drivers/fc4/soc.c index b09dfc7..d517734 100644 --- a/drivers/fc4/soc.c +++ b/drivers/fc4/soc.c @@ -22,7 +22,6 @@ static char *version = #include #include -#include #include #include #include diff --git a/drivers/fc4/socal.c b/drivers/fc4/socal.c index a6b1ae2..c903ebf 100644 --- a/drivers/fc4/socal.c +++ b/drivers/fc4/socal.c @@ -17,7 +17,6 @@ static char *version = #include #include -#include #include #include #include diff --git a/drivers/firmware/edd.c b/drivers/firmware/edd.c index 5c261e1..d8806e4 100644 --- a/drivers/firmware/edd.c +++ b/drivers/firmware/edd.c @@ -233,6 +233,8 @@ edd_show_interface(struct edd_device *ed /** * edd_show_raw_data() - copies raw data to buffer for userspace to parse + * @edev: target edd_device + * @buf: output buffer * * Returns: number of bytes written, or -EINVAL on failure */ @@ -634,8 +636,8 @@ static decl_subsys(edd,&ktype_edd,NULL); /** * edd_dev_is_type() - is this EDD device a 'type' device? - * @edev - * @type - a host bus or interface identifier string per the EDD spec + * @edev: target edd_device + * @type: a host bus or interface identifier string per the EDD spec * * Returns 1 (TRUE) if it is a 'type' device, 0 otherwise. */ @@ -657,7 +659,7 @@ edd_dev_is_type(struct edd_device *edev, /** * edd_get_pci_dev() - finds pci_dev that matches edev - * @edev - edd_device + * @edev: edd_device * * Returns pci_dev if found, or NULL */ diff --git a/drivers/firmware/pcdp.c b/drivers/firmware/pcdp.c index c2ad72f..2b4b76e 100644 --- a/drivers/firmware/pcdp.c +++ b/drivers/firmware/pcdp.c @@ -26,7 +26,7 @@ #ifdef CONFIG_SERIAL_8250_CONSOLE static char options[64], *p = options; char parity; - mmio = (uart->addr.address_space_id == ACPI_ADR_SPACE_SYSTEM_MEMORY); + mmio = (uart->addr.space_id == ACPI_ADR_SPACE_SYSTEM_MEMORY); p += sprintf(p, "console=uart,%s,0x%lx", mmio ? "mmio" : "io", uart->addr.address); if (uart->baud) { diff --git a/drivers/hid/Kconfig b/drivers/hid/Kconfig index ec796ad..850788f 100644 --- a/drivers/hid/Kconfig +++ b/drivers/hid/Kconfig @@ -22,5 +22,19 @@ config HID If unsure, say Y +config HID_DEBUG + bool "HID debugging support" + depends on HID + ---help--- + This option lets the HID layer output diagnostics about its internal + state, resolve HID usages, dump HID fields, etc. Individual HID drivers + use this debugging facility to output information about individual HID + devices, etc. + + This feature is useful for those who are either debugging the HID parser + or any HID hardware device. + + If unsure, say N + endmenu diff --git a/drivers/hid/Makefile b/drivers/hid/Makefile index 6432392..52e97d8 100644 --- a/drivers/hid/Makefile +++ b/drivers/hid/Makefile @@ -1,15 +1,8 @@ # # Makefile for the HID driver # - -# Multipart objects. -hid-objs := hid-core.o hid-input.o - -# Optional parts of multipart objects. +hid-objs := hid-core.o hid-input.o obj-$(CONFIG_HID) += hid.o - -ifeq ($(CONFIG_INPUT_DEBUG),y) -EXTRA_CFLAGS += -DDEBUG -endif +hid-$(CONFIG_HID_DEBUG) += hid-debug.o diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c index 49f18f5..7452399 100644 --- a/drivers/hid/hid-core.c +++ b/drivers/hid/hid-core.c @@ -18,7 +18,6 @@ #include #include #include #include -#include #include #include #include @@ -28,11 +27,9 @@ #include #include #include -#undef DEBUG -#undef DEBUG_DATA - #include #include +#include /* * Version Information @@ -951,7 +948,7 @@ int hid_input_report(struct hid_device * return -1; } -#ifdef DEBUG_DATA +#ifdef CONFIG_HID_DEBUG printk(KERN_DEBUG __FILE__ ": report (size %u) (%snumbered)\n", size, report_enum->numbered ? "" : "un"); #endif @@ -961,7 +958,7 @@ #endif size--; } -#ifdef DEBUG_DATA +#ifdef CONFIG_HID_DEBUG { int i; printk(KERN_DEBUG __FILE__ ": report %d (size %u) = ", n, size); diff --git a/drivers/hid/hid-debug.c b/drivers/hid/hid-debug.c new file mode 100644 index 0000000..89241be --- /dev/null +++ b/drivers/hid/hid-debug.c @@ -0,0 +1,764 @@ +/* + * $Id: hid-debug.h,v 1.8 2001/09/25 09:37:57 vojtech Exp $ + * + * (c) 1999 Andreas Gal + * (c) 2000-2001 Vojtech Pavlik + * (c) 2007 Jiri Kosina + * + * Some debug stuff for the HID parser. + */ + +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Should you need to contact me, the author, you can do so either by + * e-mail - mail your message to , or by paper mail: + * Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic + */ + +#include + +struct hid_usage_entry { + unsigned page; + unsigned usage; + char *description; +}; + +static const struct hid_usage_entry hid_usage_table[] = { + { 0, 0, "Undefined" }, + { 1, 0, "GenericDesktop" }, + {0, 0x01, "Pointer"}, + {0, 0x02, "Mouse"}, + {0, 0x04, "Joystick"}, + {0, 0x05, "GamePad"}, + {0, 0x06, "Keyboard"}, + {0, 0x07, "Keypad"}, + {0, 0x08, "MultiAxis"}, + {0, 0x30, "X"}, + {0, 0x31, "Y"}, + {0, 0x32, "Z"}, + {0, 0x33, "Rx"}, + {0, 0x34, "Ry"}, + {0, 0x35, "Rz"}, + {0, 0x36, "Slider"}, + {0, 0x37, "Dial"}, + {0, 0x38, "Wheel"}, + {0, 0x39, "HatSwitch"}, + {0, 0x3a, "CountedBuffer"}, + {0, 0x3b, "ByteCount"}, + {0, 0x3c, "MotionWakeup"}, + {0, 0x3d, "Start"}, + {0, 0x3e, "Select"}, + {0, 0x40, "Vx"}, + {0, 0x41, "Vy"}, + {0, 0x42, "Vz"}, + {0, 0x43, "Vbrx"}, + {0, 0x44, "Vbry"}, + {0, 0x45, "Vbrz"}, + {0, 0x46, "Vno"}, + {0, 0x80, "SystemControl"}, + {0, 0x81, "SystemPowerDown"}, + {0, 0x82, "SystemSleep"}, + {0, 0x83, "SystemWakeUp"}, + {0, 0x84, "SystemContextMenu"}, + {0, 0x85, "SystemMainMenu"}, + {0, 0x86, "SystemAppMenu"}, + {0, 0x87, "SystemMenuHelp"}, + {0, 0x88, "SystemMenuExit"}, + {0, 0x89, "SystemMenuSelect"}, + {0, 0x8a, "SystemMenuRight"}, + {0, 0x8b, "SystemMenuLeft"}, + {0, 0x8c, "SystemMenuUp"}, + {0, 0x8d, "SystemMenuDown"}, + {0, 0x90, "D-PadUp"}, + {0, 0x91, "D-PadDown"}, + {0, 0x92, "D-PadRight"}, + {0, 0x93, "D-PadLeft"}, + { 2, 0, "Simulation" }, + {0, 0xb0, "Aileron"}, + {0, 0xb1, "AileronTrim"}, + {0, 0xb2, "Anti-Torque"}, + {0, 0xb3, "Autopilot"}, + {0, 0xb4, "Chaff"}, + {0, 0xb5, "Collective"}, + {0, 0xb6, "DiveBrake"}, + {0, 0xb7, "ElectronicCountermeasures"}, + {0, 0xb8, "Elevator"}, + {0, 0xb9, "ElevatorTrim"}, + {0, 0xba, "Rudder"}, + {0, 0xbb, "Throttle"}, + {0, 0xbc, "FlightCommunications"}, + {0, 0xbd, "FlareRelease"}, + {0, 0xbe, "LandingGear"}, + {0, 0xbf, "ToeBrake"}, + { 7, 0, "Keyboard" }, + { 8, 0, "LED" }, + {0, 0x01, "NumLock"}, + {0, 0x02, "CapsLock"}, + {0, 0x03, "ScrollLock"}, + {0, 0x04, "Compose"}, + {0, 0x05, "Kana"}, + {0, 0x4b, "GenericIndicator"}, + { 9, 0, "Button" }, + { 10, 0, "Ordinal" }, + { 12, 0, "Consumer" }, + {0, 0x238, "HorizontalWheel"}, + { 13, 0, "Digitizers" }, + {0, 0x01, "Digitizer"}, + {0, 0x02, "Pen"}, + {0, 0x03, "LightPen"}, + {0, 0x04, "TouchScreen"}, + {0, 0x05, "TouchPad"}, + {0, 0x20, "Stylus"}, + {0, 0x21, "Puck"}, + {0, 0x22, "Finger"}, + {0, 0x30, "TipPressure"}, + {0, 0x31, "BarrelPressure"}, + {0, 0x32, "InRange"}, + {0, 0x33, "Touch"}, + {0, 0x34, "UnTouch"}, + {0, 0x35, "Tap"}, + {0, 0x39, "TabletFunctionKey"}, + {0, 0x3a, "ProgramChangeKey"}, + {0, 0x3c, "Invert"}, + {0, 0x42, "TipSwitch"}, + {0, 0x43, "SecondaryTipSwitch"}, + {0, 0x44, "BarrelSwitch"}, + {0, 0x45, "Eraser"}, + {0, 0x46, "TabletPick"}, + { 15, 0, "PhysicalInterfaceDevice" }, + {0, 0x00, "Undefined"}, + {0, 0x01, "Physical_Interface_Device"}, + {0, 0x20, "Normal"}, + {0, 0x21, "Set_Effect_Report"}, + {0, 0x22, "Effect_Block_Index"}, + {0, 0x23, "Parameter_Block_Offset"}, + {0, 0x24, "ROM_Flag"}, + {0, 0x25, "Effect_Type"}, + {0, 0x26, "ET_Constant_Force"}, + {0, 0x27, "ET_Ramp"}, + {0, 0x28, "ET_Custom_Force_Data"}, + {0, 0x30, "ET_Square"}, + {0, 0x31, "ET_Sine"}, + {0, 0x32, "ET_Triangle"}, + {0, 0x33, "ET_Sawtooth_Up"}, + {0, 0x34, "ET_Sawtooth_Down"}, + {0, 0x40, "ET_Spring"}, + {0, 0x41, "ET_Damper"}, + {0, 0x42, "ET_Inertia"}, + {0, 0x43, "ET_Friction"}, + {0, 0x50, "Duration"}, + {0, 0x51, "Sample_Period"}, + {0, 0x52, "Gain"}, + {0, 0x53, "Trigger_Button"}, + {0, 0x54, "Trigger_Repeat_Interval"}, + {0, 0x55, "Axes_Enable"}, + {0, 0x56, "Direction_Enable"}, + {0, 0x57, "Direction"}, + {0, 0x58, "Type_Specific_Block_Offset"}, + {0, 0x59, "Block_Type"}, + {0, 0x5A, "Set_Envelope_Report"}, + {0, 0x5B, "Attack_Level"}, + {0, 0x5C, "Attack_Time"}, + {0, 0x5D, "Fade_Level"}, + {0, 0x5E, "Fade_Time"}, + {0, 0x5F, "Set_Condition_Report"}, + {0, 0x60, "CP_Offset"}, + {0, 0x61, "Positive_Coefficient"}, + {0, 0x62, "Negative_Coefficient"}, + {0, 0x63, "Positive_Saturation"}, + {0, 0x64, "Negative_Saturation"}, + {0, 0x65, "Dead_Band"}, + {0, 0x66, "Download_Force_Sample"}, + {0, 0x67, "Isoch_Custom_Force_Enable"}, + {0, 0x68, "Custom_Force_Data_Report"}, + {0, 0x69, "Custom_Force_Data"}, + {0, 0x6A, "Custom_Force_Vendor_Defined_Data"}, + {0, 0x6B, "Set_Custom_Force_Report"}, + {0, 0x6C, "Custom_Force_Data_Offset"}, + {0, 0x6D, "Sample_Count"}, + {0, 0x6E, "Set_Periodic_Report"}, + {0, 0x6F, "Offset"}, + {0, 0x70, "Magnitude"}, + {0, 0x71, "Phase"}, + {0, 0x72, "Period"}, + {0, 0x73, "Set_Constant_Force_Report"}, + {0, 0x74, "Set_Ramp_Force_Report"}, + {0, 0x75, "Ramp_Start"}, + {0, 0x76, "Ramp_End"}, + {0, 0x77, "Effect_Operation_Report"}, + {0, 0x78, "Effect_Operation"}, + {0, 0x79, "Op_Effect_Start"}, + {0, 0x7A, "Op_Effect_Start_Solo"}, + {0, 0x7B, "Op_Effect_Stop"}, + {0, 0x7C, "Loop_Count"}, + {0, 0x7D, "Device_Gain_Report"}, + {0, 0x7E, "Device_Gain"}, + {0, 0x7F, "PID_Pool_Report"}, + {0, 0x80, "RAM_Pool_Size"}, + {0, 0x81, "ROM_Pool_Size"}, + {0, 0x82, "ROM_Effect_Block_Count"}, + {0, 0x83, "Simultaneous_Effects_Max"}, + {0, 0x84, "Pool_Alignment"}, + {0, 0x85, "PID_Pool_Move_Report"}, + {0, 0x86, "Move_Source"}, + {0, 0x87, "Move_Destination"}, + {0, 0x88, "Move_Length"}, + {0, 0x89, "PID_Block_Load_Report"}, + {0, 0x8B, "Block_Load_Status"}, + {0, 0x8C, "Block_Load_Success"}, + {0, 0x8D, "Block_Load_Full"}, + {0, 0x8E, "Block_Load_Error"}, + {0, 0x8F, "Block_Handle"}, + {0, 0x90, "PID_Block_Free_Report"}, + {0, 0x91, "Type_Specific_Block_Handle"}, + {0, 0x92, "PID_State_Report"}, + {0, 0x94, "Effect_Playing"}, + {0, 0x95, "PID_Device_Control_Report"}, + {0, 0x96, "PID_Device_Control"}, + {0, 0x97, "DC_Enable_Actuators"}, + {0, 0x98, "DC_Disable_Actuators"}, + {0, 0x99, "DC_Stop_All_Effects"}, + {0, 0x9A, "DC_Device_Reset"}, + {0, 0x9B, "DC_Device_Pause"}, + {0, 0x9C, "DC_Device_Continue"}, + {0, 0x9F, "Device_Paused"}, + {0, 0xA0, "Actuators_Enabled"}, + {0, 0xA4, "Safety_Switch"}, + {0, 0xA5, "Actuator_Override_Switch"}, + {0, 0xA6, "Actuator_Power"}, + {0, 0xA7, "Start_Delay"}, + {0, 0xA8, "Parameter_Block_Size"}, + {0, 0xA9, "Device_Managed_Pool"}, + {0, 0xAA, "Shared_Parameter_Blocks"}, + {0, 0xAB, "Create_New_Effect_Report"}, + {0, 0xAC, "RAM_Pool_Available"}, + { 0x84, 0, "Power Device" }, + { 0x84, 0x02, "PresentStatus" }, + { 0x84, 0x03, "ChangeStatus" }, + { 0x84, 0x04, "UPS" }, + { 0x84, 0x05, "PowerSupply" }, + { 0x84, 0x10, "BatterySystem" }, + { 0x84, 0x11, "BatterySystemID" }, + { 0x84, 0x12, "Battery" }, + { 0x84, 0x13, "BatteryID" }, + { 0x84, 0x14, "Charger" }, + { 0x84, 0x15, "ChargerID" }, + { 0x84, 0x16, "PowerConverter" }, + { 0x84, 0x17, "PowerConverterID" }, + { 0x84, 0x18, "OutletSystem" }, + { 0x84, 0x19, "OutletSystemID" }, + { 0x84, 0x1a, "Input" }, + { 0x84, 0x1b, "InputID" }, + { 0x84, 0x1c, "Output" }, + { 0x84, 0x1d, "OutputID" }, + { 0x84, 0x1e, "Flow" }, + { 0x84, 0x1f, "FlowID" }, + { 0x84, 0x20, "Outlet" }, + { 0x84, 0x21, "OutletID" }, + { 0x84, 0x22, "Gang" }, + { 0x84, 0x24, "PowerSummary" }, + { 0x84, 0x25, "PowerSummaryID" }, + { 0x84, 0x30, "Voltage" }, + { 0x84, 0x31, "Current" }, + { 0x84, 0x32, "Frequency" }, + { 0x84, 0x33, "ApparentPower" }, + { 0x84, 0x35, "PercentLoad" }, + { 0x84, 0x40, "ConfigVoltage" }, + { 0x84, 0x41, "ConfigCurrent" }, + { 0x84, 0x43, "ConfigApparentPower" }, + { 0x84, 0x53, "LowVoltageTransfer" }, + { 0x84, 0x54, "HighVoltageTransfer" }, + { 0x84, 0x56, "DelayBeforeStartup" }, + { 0x84, 0x57, "DelayBeforeShutdown" }, + { 0x84, 0x58, "Test" }, + { 0x84, 0x5a, "AudibleAlarmControl" }, + { 0x84, 0x60, "Present" }, + { 0x84, 0x61, "Good" }, + { 0x84, 0x62, "InternalFailure" }, + { 0x84, 0x65, "Overload" }, + { 0x84, 0x66, "OverCharged" }, + { 0x84, 0x67, "OverTemperature" }, + { 0x84, 0x68, "ShutdownRequested" }, + { 0x84, 0x69, "ShutdownImminent" }, + { 0x84, 0x6b, "SwitchOn/Off" }, + { 0x84, 0x6c, "Switchable" }, + { 0x84, 0x6d, "Used" }, + { 0x84, 0x6e, "Boost" }, + { 0x84, 0x73, "CommunicationLost" }, + { 0x84, 0xfd, "iManufacturer" }, + { 0x84, 0xfe, "iProduct" }, + { 0x84, 0xff, "iSerialNumber" }, + { 0x85, 0, "Battery System" }, + { 0x85, 0x01, "SMBBatteryMode" }, + { 0x85, 0x02, "SMBBatteryStatus" }, + { 0x85, 0x03, "SMBAlarmWarning" }, + { 0x85, 0x04, "SMBChargerMode" }, + { 0x85, 0x05, "SMBChargerStatus" }, + { 0x85, 0x06, "SMBChargerSpecInfo" }, + { 0x85, 0x07, "SMBSelectorState" }, + { 0x85, 0x08, "SMBSelectorPresets" }, + { 0x85, 0x09, "SMBSelectorInfo" }, + { 0x85, 0x29, "RemainingCapacityLimit" }, + { 0x85, 0x2c, "CapacityMode" }, + { 0x85, 0x42, "BelowRemainingCapacityLimit" }, + { 0x85, 0x44, "Charging" }, + { 0x85, 0x45, "Discharging" }, + { 0x85, 0x4b, "NeedReplacement" }, + { 0x85, 0x66, "RemainingCapacity" }, + { 0x85, 0x68, "RunTimeToEmpty" }, + { 0x85, 0x6a, "AverageTimeToFull" }, + { 0x85, 0x83, "DesignCapacity" }, + { 0x85, 0x85, "ManufacturerDate" }, + { 0x85, 0x89, "iDeviceChemistry" }, + { 0x85, 0x8b, "Rechargable" }, + { 0x85, 0x8f, "iOEMInformation" }, + { 0x85, 0x8d, "CapacityGranularity1" }, + { 0x85, 0xd0, "ACPresent" }, + /* pages 0xff00 to 0xffff are vendor-specific */ + { 0xffff, 0, "Vendor-specific-FF" }, + { 0, 0, NULL } +}; + +static void resolv_usage_page(unsigned page) { + const struct hid_usage_entry *p; + + for (p = hid_usage_table; p->description; p++) + if (p->page == page) { + printk("%s", p->description); + return; + } + printk("%04x", page); +} + +void hid_resolv_usage(unsigned usage) { + const struct hid_usage_entry *p; + + resolv_usage_page(usage >> 16); + printk("."); + for (p = hid_usage_table; p->description; p++) + if (p->page == (usage >> 16)) { + for(++p; p->description && p->usage != 0; p++) + if (p->usage == (usage & 0xffff)) { + printk("%s", p->description); + return; + } + break; + } + printk("%04x", usage & 0xffff); +} +EXPORT_SYMBOL_GPL(hid_resolv_usage); + +__inline__ static void tab(int n) { + while (n--) printk(" "); +} + +void hid_dump_field(struct hid_field *field, int n) { + int j; + + if (field->physical) { + tab(n); + printk("Physical("); + hid_resolv_usage(field->physical); printk(")\n"); + } + if (field->logical) { + tab(n); + printk("Logical("); + hid_resolv_usage(field->logical); printk(")\n"); + } + tab(n); printk("Usage(%d)\n", field->maxusage); + for (j = 0; j < field->maxusage; j++) { + tab(n+2); hid_resolv_usage(field->usage[j].hid); printk("\n"); + } + if (field->logical_minimum != field->logical_maximum) { + tab(n); printk("Logical Minimum(%d)\n", field->logical_minimum); + tab(n); printk("Logical Maximum(%d)\n", field->logical_maximum); + } + if (field->physical_minimum != field->physical_maximum) { + tab(n); printk("Physical Minimum(%d)\n", field->physical_minimum); + tab(n); printk("Physical Maximum(%d)\n", field->physical_maximum); + } + if (field->unit_exponent) { + tab(n); printk("Unit Exponent(%d)\n", field->unit_exponent); + } + if (field->unit) { + char *systems[5] = { "None", "SI Linear", "SI Rotation", "English Linear", "English Rotation" }; + char *units[5][8] = { + { "None", "None", "None", "None", "None", "None", "None", "None" }, + { "None", "Centimeter", "Gram", "Seconds", "Kelvin", "Ampere", "Candela", "None" }, + { "None", "Radians", "Gram", "Seconds", "Kelvin", "Ampere", "Candela", "None" }, + { "None", "Inch", "Slug", "Seconds", "Fahrenheit", "Ampere", "Candela", "None" }, + { "None", "Degrees", "Slug", "Seconds", "Fahrenheit", "Ampere", "Candela", "None" } + }; + + int i; + int sys; + __u32 data = field->unit; + + /* First nibble tells us which system we're in. */ + sys = data & 0xf; + data >>= 4; + + if(sys > 4) { + tab(n); printk("Unit(Invalid)\n"); + } + else { + int earlier_unit = 0; + + tab(n); printk("Unit(%s : ", systems[sys]); + + for (i=1 ; i>= 4; + if (nibble != 0) { + if(earlier_unit++ > 0) + printk("*"); + printk("%s", units[sys][i]); + if(nibble != 1) { + /* This is a _signed_ nibble(!) */ + + int val = nibble & 0x7; + if(nibble & 0x08) + val = -((0x7 & ~val) +1); + printk("^%d", val); + } + } + } + printk(")\n"); + } + } + tab(n); printk("Report Size(%u)\n", field->report_size); + tab(n); printk("Report Count(%u)\n", field->report_count); + tab(n); printk("Report Offset(%u)\n", field->report_offset); + + tab(n); printk("Flags( "); + j = field->flags; + printk("%s", HID_MAIN_ITEM_CONSTANT & j ? "Constant " : ""); + printk("%s", HID_MAIN_ITEM_VARIABLE & j ? "Variable " : "Array "); + printk("%s", HID_MAIN_ITEM_RELATIVE & j ? "Relative " : "Absolute "); + printk("%s", HID_MAIN_ITEM_WRAP & j ? "Wrap " : ""); + printk("%s", HID_MAIN_ITEM_NONLINEAR & j ? "NonLinear " : ""); + printk("%s", HID_MAIN_ITEM_NO_PREFERRED & j ? "NoPrefferedState " : ""); + printk("%s", HID_MAIN_ITEM_NULL_STATE & j ? "NullState " : ""); + printk("%s", HID_MAIN_ITEM_VOLATILE & j ? "Volatile " : ""); + printk("%s", HID_MAIN_ITEM_BUFFERED_BYTE & j ? "BufferedByte " : ""); + printk(")\n"); +} +EXPORT_SYMBOL_GPL(hid_dump_field); + +void hid_dump_device(struct hid_device *device) { + struct hid_report_enum *report_enum; + struct hid_report *report; + struct list_head *list; + unsigned i,k; + static char *table[] = {"INPUT", "OUTPUT", "FEATURE"}; + + for (i = 0; i < HID_REPORT_TYPES; i++) { + report_enum = device->report_enum + i; + list = report_enum->report_list.next; + while (list != &report_enum->report_list) { + report = (struct hid_report *) list; + tab(2); + printk("%s", table[i]); + if (report->id) + printk("(%d)", report->id); + printk("[%s]", table[report->type]); + printk("\n"); + for (k = 0; k < report->maxfield; k++) { + tab(4); + printk("Field(%d)\n", k); + hid_dump_field(report->field[k], 6); + } + list = list->next; + } + } +} +EXPORT_SYMBOL_GPL(hid_dump_device); + +void hid_dump_input(struct hid_usage *usage, __s32 value) { + printk("hid-debug: input "); + hid_resolv_usage(usage->hid); + printk(" = %d\n", value); +} +EXPORT_SYMBOL_GPL(hid_dump_input); + +static char *events[EV_MAX + 1] = { + [EV_SYN] = "Sync", [EV_KEY] = "Key", + [EV_REL] = "Relative", [EV_ABS] = "Absolute", + [EV_MSC] = "Misc", [EV_LED] = "LED", + [EV_SND] = "Sound", [EV_REP] = "Repeat", + [EV_FF] = "ForceFeedback", [EV_PWR] = "Power", + [EV_FF_STATUS] = "ForceFeedbackStatus", +}; + +static char *syncs[2] = { + [SYN_REPORT] = "Report", [SYN_CONFIG] = "Config", +}; +static char *keys[KEY_MAX + 1] = { + [KEY_RESERVED] = "Reserved", [KEY_ESC] = "Esc", + [KEY_1] = "1", [KEY_2] = "2", + [KEY_3] = "3", [KEY_4] = "4", + [KEY_5] = "5", [KEY_6] = "6", + [KEY_7] = "7", [KEY_8] = "8", + [KEY_9] = "9", [KEY_0] = "0", + [KEY_MINUS] = "Minus", [KEY_EQUAL] = "Equal", + [KEY_BACKSPACE] = "Backspace", [KEY_TAB] = "Tab", + [KEY_Q] = "Q", [KEY_W] = "W", + [KEY_E] = "E", [KEY_R] = "R", + [KEY_T] = "T", [KEY_Y] = "Y", + [KEY_U] = "U", [KEY_I] = "I", + [KEY_O] = "O", [KEY_P] = "P", + [KEY_LEFTBRACE] = "LeftBrace", [KEY_RIGHTBRACE] = "RightBrace", + [KEY_ENTER] = "Enter", [KEY_LEFTCTRL] = "LeftControl", + [KEY_A] = "A", [KEY_S] = "S", + [KEY_D] = "D", [KEY_F] = "F", + [KEY_G] = "G", [KEY_H] = "H", + [KEY_J] = "J", [KEY_K] = "K", + [KEY_L] = "L", [KEY_SEMICOLON] = "Semicolon", + [KEY_APOSTROPHE] = "Apostrophe", [KEY_GRAVE] = "Grave", + [KEY_LEFTSHIFT] = "LeftShift", [KEY_BACKSLASH] = "BackSlash", + [KEY_Z] = "Z", [KEY_X] = "X", + [KEY_C] = "C", [KEY_V] = "V", + [KEY_B] = "B", [KEY_N] = "N", + [KEY_M] = "M", [KEY_COMMA] = "Comma", + [KEY_DOT] = "Dot", [KEY_SLASH] = "Slash", + [KEY_RIGHTSHIFT] = "RightShift", [KEY_KPASTERISK] = "KPAsterisk", + [KEY_LEFTALT] = "LeftAlt", [KEY_SPACE] = "Space", + [KEY_CAPSLOCK] = "CapsLock", [KEY_F1] = "F1", + [KEY_F2] = "F2", [KEY_F3] = "F3", + [KEY_F4] = "F4", [KEY_F5] = "F5", + [KEY_F6] = "F6", [KEY_F7] = "F7", + [KEY_F8] = "F8", [KEY_F9] = "F9", + [KEY_F10] = "F10", [KEY_NUMLOCK] = "NumLock", + [KEY_SCROLLLOCK] = "ScrollLock", [KEY_KP7] = "KP7", + [KEY_KP8] = "KP8", [KEY_KP9] = "KP9", + [KEY_KPMINUS] = "KPMinus", [KEY_KP4] = "KP4", + [KEY_KP5] = "KP5", [KEY_KP6] = "KP6", + [KEY_KPPLUS] = "KPPlus", [KEY_KP1] = "KP1", + [KEY_KP2] = "KP2", [KEY_KP3] = "KP3", + [KEY_KP0] = "KP0", [KEY_KPDOT] = "KPDot", + [KEY_ZENKAKUHANKAKU] = "Zenkaku/Hankaku", [KEY_102ND] = "102nd", + [KEY_F11] = "F11", [KEY_F12] = "F12", + [KEY_RO] = "RO", [KEY_KATAKANA] = "Katakana", + [KEY_HIRAGANA] = "HIRAGANA", [KEY_HENKAN] = "Henkan", + [KEY_KATAKANAHIRAGANA] = "Katakana/Hiragana", [KEY_MUHENKAN] = "Muhenkan", + [KEY_KPJPCOMMA] = "KPJpComma", [KEY_KPENTER] = "KPEnter", + [KEY_RIGHTCTRL] = "RightCtrl", [KEY_KPSLASH] = "KPSlash", + [KEY_SYSRQ] = "SysRq", [KEY_RIGHTALT] = "RightAlt", + [KEY_LINEFEED] = "LineFeed", [KEY_HOME] = "Home", + [KEY_UP] = "Up", [KEY_PAGEUP] = "PageUp", + [KEY_LEFT] = "Left", [KEY_RIGHT] = "Right", + [KEY_END] = "End", [KEY_DOWN] = "Down", + [KEY_PAGEDOWN] = "PageDown", [KEY_INSERT] = "Insert", + [KEY_DELETE] = "Delete", [KEY_MACRO] = "Macro", + [KEY_MUTE] = "Mute", [KEY_VOLUMEDOWN] = "VolumeDown", + [KEY_VOLUMEUP] = "VolumeUp", [KEY_POWER] = "Power", + [KEY_KPEQUAL] = "KPEqual", [KEY_KPPLUSMINUS] = "KPPlusMinus", + [KEY_PAUSE] = "Pause", [KEY_KPCOMMA] = "KPComma", + [KEY_HANGUEL] = "Hangeul", [KEY_HANJA] = "Hanja", + [KEY_YEN] = "Yen", [KEY_LEFTMETA] = "LeftMeta", + [KEY_RIGHTMETA] = "RightMeta", [KEY_COMPOSE] = "Compose", + [KEY_STOP] = "Stop", [KEY_AGAIN] = "Again", + [KEY_PROPS] = "Props", [KEY_UNDO] = "Undo", + [KEY_FRONT] = "Front", [KEY_COPY] = "Copy", + [KEY_OPEN] = "Open", [KEY_PASTE] = "Paste", + [KEY_FIND] = "Find", [KEY_CUT] = "Cut", + [KEY_HELP] = "Help", [KEY_MENU] = "Menu", + [KEY_CALC] = "Calc", [KEY_SETUP] = "Setup", + [KEY_SLEEP] = "Sleep", [KEY_WAKEUP] = "WakeUp", + [KEY_FILE] = "File", [KEY_SENDFILE] = "SendFile", + [KEY_DELETEFILE] = "DeleteFile", [KEY_XFER] = "X-fer", + [KEY_PROG1] = "Prog1", [KEY_PROG2] = "Prog2", + [KEY_WWW] = "WWW", [KEY_MSDOS] = "MSDOS", + [KEY_COFFEE] = "Coffee", [KEY_DIRECTION] = "Direction", + [KEY_CYCLEWINDOWS] = "CycleWindows", [KEY_MAIL] = "Mail", + [KEY_BOOKMARKS] = "Bookmarks", [KEY_COMPUTER] = "Computer", + [KEY_BACK] = "Back", [KEY_FORWARD] = "Forward", + [KEY_CLOSECD] = "CloseCD", [KEY_EJECTCD] = "EjectCD", + [KEY_EJECTCLOSECD] = "EjectCloseCD", [KEY_NEXTSONG] = "NextSong", + [KEY_PLAYPAUSE] = "PlayPause", [KEY_PREVIOUSSONG] = "PreviousSong", + [KEY_STOPCD] = "StopCD", [KEY_RECORD] = "Record", + [KEY_REWIND] = "Rewind", [KEY_PHONE] = "Phone", + [KEY_ISO] = "ISOKey", [KEY_CONFIG] = "Config", + [KEY_HOMEPAGE] = "HomePage", [KEY_REFRESH] = "Refresh", + [KEY_EXIT] = "Exit", [KEY_MOVE] = "Move", + [KEY_EDIT] = "Edit", [KEY_SCROLLUP] = "ScrollUp", + [KEY_SCROLLDOWN] = "ScrollDown", [KEY_KPLEFTPAREN] = "KPLeftParenthesis", + [KEY_KPRIGHTPAREN] = "KPRightParenthesis", [KEY_NEW] = "New", + [KEY_REDO] = "Redo", [KEY_F13] = "F13", + [KEY_F14] = "F14", [KEY_F15] = "F15", + [KEY_F16] = "F16", [KEY_F17] = "F17", + [KEY_F18] = "F18", [KEY_F19] = "F19", + [KEY_F20] = "F20", [KEY_F21] = "F21", + [KEY_F22] = "F22", [KEY_F23] = "F23", + [KEY_F24] = "F24", [KEY_PLAYCD] = "PlayCD", + [KEY_PAUSECD] = "PauseCD", [KEY_PROG3] = "Prog3", + [KEY_PROG4] = "Prog4", [KEY_SUSPEND] = "Suspend", + [KEY_CLOSE] = "Close", [KEY_PLAY] = "Play", + [KEY_FASTFORWARD] = "FastForward", [KEY_BASSBOOST] = "BassBoost", + [KEY_PRINT] = "Print", [KEY_HP] = "HP", + [KEY_CAMERA] = "Camera", [KEY_SOUND] = "Sound", + [KEY_QUESTION] = "Question", [KEY_EMAIL] = "Email", + [KEY_CHAT] = "Chat", [KEY_SEARCH] = "Search", + [KEY_CONNECT] = "Connect", [KEY_FINANCE] = "Finance", + [KEY_SPORT] = "Sport", [KEY_SHOP] = "Shop", + [KEY_ALTERASE] = "AlternateErase", [KEY_CANCEL] = "Cancel", + [KEY_BRIGHTNESSDOWN] = "BrightnessDown", [KEY_BRIGHTNESSUP] = "BrightnessUp", + [KEY_MEDIA] = "Media", [KEY_UNKNOWN] = "Unknown", + [BTN_0] = "Btn0", [BTN_1] = "Btn1", + [BTN_2] = "Btn2", [BTN_3] = "Btn3", + [BTN_4] = "Btn4", [BTN_5] = "Btn5", + [BTN_6] = "Btn6", [BTN_7] = "Btn7", + [BTN_8] = "Btn8", [BTN_9] = "Btn9", + [BTN_LEFT] = "LeftBtn", [BTN_RIGHT] = "RightBtn", + [BTN_MIDDLE] = "MiddleBtn", [BTN_SIDE] = "SideBtn", + [BTN_EXTRA] = "ExtraBtn", [BTN_FORWARD] = "ForwardBtn", + [BTN_BACK] = "BackBtn", [BTN_TASK] = "TaskBtn", + [BTN_TRIGGER] = "Trigger", [BTN_THUMB] = "ThumbBtn", + [BTN_THUMB2] = "ThumbBtn2", [BTN_TOP] = "TopBtn", + [BTN_TOP2] = "TopBtn2", [BTN_PINKIE] = "PinkieBtn", + [BTN_BASE] = "BaseBtn", [BTN_BASE2] = "BaseBtn2", + [BTN_BASE3] = "BaseBtn3", [BTN_BASE4] = "BaseBtn4", + [BTN_BASE5] = "BaseBtn5", [BTN_BASE6] = "BaseBtn6", + [BTN_DEAD] = "BtnDead", [BTN_A] = "BtnA", + [BTN_B] = "BtnB", [BTN_C] = "BtnC", + [BTN_X] = "BtnX", [BTN_Y] = "BtnY", + [BTN_Z] = "BtnZ", [BTN_TL] = "BtnTL", + [BTN_TR] = "BtnTR", [BTN_TL2] = "BtnTL2", + [BTN_TR2] = "BtnTR2", [BTN_SELECT] = "BtnSelect", + [BTN_START] = "BtnStart", [BTN_MODE] = "BtnMode", + [BTN_THUMBL] = "BtnThumbL", [BTN_THUMBR] = "BtnThumbR", + [BTN_TOOL_PEN] = "ToolPen", [BTN_TOOL_RUBBER] = "ToolRubber", + [BTN_TOOL_BRUSH] = "ToolBrush", [BTN_TOOL_PENCIL] = "ToolPencil", + [BTN_TOOL_AIRBRUSH] = "ToolAirbrush", [BTN_TOOL_FINGER] = "ToolFinger", + [BTN_TOOL_MOUSE] = "ToolMouse", [BTN_TOOL_LENS] = "ToolLens", + [BTN_TOUCH] = "Touch", [BTN_STYLUS] = "Stylus", + [BTN_STYLUS2] = "Stylus2", [BTN_TOOL_DOUBLETAP] = "ToolDoubleTap", + [BTN_TOOL_TRIPLETAP] = "ToolTripleTap", [BTN_GEAR_DOWN] = "WheelBtn", + [BTN_GEAR_UP] = "Gear up", [KEY_OK] = "Ok", + [KEY_SELECT] = "Select", [KEY_GOTO] = "Goto", + [KEY_CLEAR] = "Clear", [KEY_POWER2] = "Power2", + [KEY_OPTION] = "Option", [KEY_INFO] = "Info", + [KEY_TIME] = "Time", [KEY_VENDOR] = "Vendor", + [KEY_ARCHIVE] = "Archive", [KEY_PROGRAM] = "Program", + [KEY_CHANNEL] = "Channel", [KEY_FAVORITES] = "Favorites", + [KEY_EPG] = "EPG", [KEY_PVR] = "PVR", + [KEY_MHP] = "MHP", [KEY_LANGUAGE] = "Language", + [KEY_TITLE] = "Title", [KEY_SUBTITLE] = "Subtitle", + [KEY_ANGLE] = "Angle", [KEY_ZOOM] = "Zoom", + [KEY_MODE] = "Mode", [KEY_KEYBOARD] = "Keyboard", + [KEY_SCREEN] = "Screen", [KEY_PC] = "PC", + [KEY_TV] = "TV", [KEY_TV2] = "TV2", + [KEY_VCR] = "VCR", [KEY_VCR2] = "VCR2", + [KEY_SAT] = "Sat", [KEY_SAT2] = "Sat2", + [KEY_CD] = "CD", [KEY_TAPE] = "Tape", + [KEY_RADIO] = "Radio", [KEY_TUNER] = "Tuner", + [KEY_PLAYER] = "Player", [KEY_TEXT] = "Text", + [KEY_DVD] = "DVD", [KEY_AUX] = "Aux", + [KEY_MP3] = "MP3", [KEY_AUDIO] = "Audio", + [KEY_VIDEO] = "Video", [KEY_DIRECTORY] = "Directory", + [KEY_LIST] = "List", [KEY_MEMO] = "Memo", + [KEY_CALENDAR] = "Calendar", [KEY_RED] = "Red", + [KEY_GREEN] = "Green", [KEY_YELLOW] = "Yellow", + [KEY_BLUE] = "Blue", [KEY_CHANNELUP] = "ChannelUp", + [KEY_CHANNELDOWN] = "ChannelDown", [KEY_FIRST] = "First", + [KEY_LAST] = "Last", [KEY_AB] = "AB", + [KEY_NEXT] = "Next", [KEY_RESTART] = "Restart", + [KEY_SLOW] = "Slow", [KEY_SHUFFLE] = "Shuffle", + [KEY_BREAK] = "Break", [KEY_PREVIOUS] = "Previous", + [KEY_DIGITS] = "Digits", [KEY_TEEN] = "TEEN", + [KEY_TWEN] = "TWEN", [KEY_DEL_EOL] = "DeleteEOL", + [KEY_DEL_EOS] = "DeleteEOS", [KEY_INS_LINE] = "InsertLine", + [KEY_DEL_LINE] = "DeleteLine", + [KEY_SEND] = "Send", [KEY_REPLY] = "Reply", + [KEY_FORWARDMAIL] = "ForwardMail", [KEY_SAVE] = "Save", + [KEY_DOCUMENTS] = "Documents", + [KEY_FN] = "Fn", [KEY_FN_ESC] = "Fn+ESC", + [KEY_FN_1] = "Fn+1", [KEY_FN_2] = "Fn+2", + [KEY_FN_B] = "Fn+B", [KEY_FN_D] = "Fn+D", + [KEY_FN_E] = "Fn+E", [KEY_FN_F] = "Fn+F", + [KEY_FN_S] = "Fn+S", + [KEY_FN_F1] = "Fn+F1", [KEY_FN_F2] = "Fn+F2", + [KEY_FN_F3] = "Fn+F3", [KEY_FN_F4] = "Fn+F4", + [KEY_FN_F5] = "Fn+F5", [KEY_FN_F6] = "Fn+F6", + [KEY_FN_F7] = "Fn+F7", [KEY_FN_F8] = "Fn+F8", + [KEY_FN_F9] = "Fn+F9", [KEY_FN_F10] = "Fn+F10", + [KEY_FN_F11] = "Fn+F11", [KEY_FN_F12] = "Fn+F12", + [KEY_KBDILLUMTOGGLE] = "KbdIlluminationToggle", + [KEY_KBDILLUMDOWN] = "KbdIlluminationDown", + [KEY_KBDILLUMUP] = "KbdIlluminationUp", + [KEY_SWITCHVIDEOMODE] = "SwitchVideoMode", +}; + +static char *relatives[REL_MAX + 1] = { + [REL_X] = "X", [REL_Y] = "Y", + [REL_Z] = "Z", [REL_RX] = "Rx", + [REL_RY] = "Ry", [REL_RZ] = "Rz", + [REL_HWHEEL] = "HWheel", [REL_DIAL] = "Dial", + [REL_WHEEL] = "Wheel", [REL_MISC] = "Misc", +}; + +static char *absolutes[ABS_MAX + 1] = { + [ABS_X] = "X", [ABS_Y] = "Y", + [ABS_Z] = "Z", [ABS_RX] = "Rx", + [ABS_RY] = "Ry", [ABS_RZ] = "Rz", + [ABS_THROTTLE] = "Throttle", [ABS_RUDDER] = "Rudder", + [ABS_WHEEL] = "Wheel", [ABS_GAS] = "Gas", + [ABS_BRAKE] = "Brake", [ABS_HAT0X] = "Hat0X", + [ABS_HAT0Y] = "Hat0Y", [ABS_HAT1X] = "Hat1X", + [ABS_HAT1Y] = "Hat1Y", [ABS_HAT2X] = "Hat2X", + [ABS_HAT2Y] = "Hat2Y", [ABS_HAT3X] = "Hat3X", + [ABS_HAT3Y] = "Hat 3Y", [ABS_PRESSURE] = "Pressure", + [ABS_DISTANCE] = "Distance", [ABS_TILT_X] = "XTilt", + [ABS_TILT_Y] = "YTilt", [ABS_TOOL_WIDTH] = "Tool Width", + [ABS_VOLUME] = "Volume", [ABS_MISC] = "Misc", +}; + +static char *misc[MSC_MAX + 1] = { + [MSC_SERIAL] = "Serial", [MSC_PULSELED] = "Pulseled", + [MSC_GESTURE] = "Gesture", [MSC_RAW] = "RawData" +}; + +static char *leds[LED_MAX + 1] = { + [LED_NUML] = "NumLock", [LED_CAPSL] = "CapsLock", + [LED_SCROLLL] = "ScrollLock", [LED_COMPOSE] = "Compose", + [LED_KANA] = "Kana", [LED_SLEEP] = "Sleep", + [LED_SUSPEND] = "Suspend", [LED_MUTE] = "Mute", + [LED_MISC] = "Misc", +}; + +static char *repeats[REP_MAX + 1] = { + [REP_DELAY] = "Delay", [REP_PERIOD] = "Period" +}; + +static char *sounds[SND_MAX + 1] = { + [SND_CLICK] = "Click", [SND_BELL] = "Bell", + [SND_TONE] = "Tone" +}; + +static char **names[EV_MAX + 1] = { + [EV_SYN] = syncs, [EV_KEY] = keys, + [EV_REL] = relatives, [EV_ABS] = absolutes, + [EV_MSC] = misc, [EV_LED] = leds, + [EV_SND] = sounds, [EV_REP] = repeats, +}; + +void hid_resolv_event(__u8 type, __u16 code) { + + printk("%s.%s", events[type] ? events[type] : "?", + names[type] ? (names[type][code] ? names[type][code] : "?") : "?"); +} +EXPORT_SYMBOL_GPL(hid_resolv_event); + diff --git a/drivers/hid/hid-input.c b/drivers/hid/hid-input.c index c7a6833..25d180a 100644 --- a/drivers/hid/hid-input.c +++ b/drivers/hid/hid-input.c @@ -31,9 +31,8 @@ #include #include #include -#undef DEBUG - #include +#include static int hid_pb_fnmode = 1; module_param_named(pb_fnmode, hid_pb_fnmode, int, 0644); @@ -252,9 +251,9 @@ static void hidinput_configure_usage(str field->hidinput = hidinput; -#ifdef DEBUG +#ifdef CONFIG_HID_DEBUG printk(KERN_DEBUG "Mapping: "); - resolv_usage(usage->hid); + hid_resolv_usage(usage->hid); printk(" ---> "); #endif @@ -682,14 +681,14 @@ #endif field->dpad = usage->code; } -#ifdef DEBUG - resolv_event(usage->type, usage->code); + hid_resolv_event(usage->type, usage->code); +#ifdef CONFIG_HID_DEBUG printk("\n"); #endif return; ignore: -#ifdef DEBUG +#ifdef CONFIG_HID_DEBUG printk("IGNORED\n"); #endif return; @@ -804,6 +803,18 @@ int hidinput_find_field(struct hid_devic } EXPORT_SYMBOL_GPL(hidinput_find_field); +static int hidinput_open(struct input_dev *dev) +{ + struct hid_device *hid = dev->private; + return hid->hid_open(hid); +} + +static void hidinput_close(struct input_dev *dev) +{ + struct hid_device *hid = dev->private; + hid->hid_close(hid); +} + /* * Register the input device; print a message. * Configure the input layer interface @@ -816,6 +827,7 @@ int hidinput_connect(struct hid_device * struct hid_input *hidinput = NULL; struct input_dev *input_dev; int i, j, k; + int max_report_type = HID_OUTPUT_REPORT; INIT_LIST_HEAD(&hid->inputs); @@ -828,7 +840,10 @@ int hidinput_connect(struct hid_device * if (i == hid->maxcollection) return -1; - for (k = HID_INPUT_REPORT; k <= HID_OUTPUT_REPORT; k++) + if (hid->quirks & HID_QUIRK_SKIP_OUTPUT_REPORTS) + max_report_type = HID_INPUT_REPORT; + + for (k = HID_INPUT_REPORT; k <= max_report_type; k++) list_for_each_entry(report, &hid->report_enum[k].report_list, list) { if (!report->maxfield) @@ -846,8 +861,8 @@ int hidinput_connect(struct hid_device * input_dev->private = hid; input_dev->event = hid->hidinput_input_event; - input_dev->open = hid->hidinput_open; - input_dev->close = hid->hidinput_close; + input_dev->open = hidinput_open; + input_dev->close = hidinput_close; input_dev->name = hid->name; input_dev->phys = hid->phys; diff --git a/drivers/hwmon/ams/ams-input.c b/drivers/hwmon/ams/ams-input.c index f126aa4..1821016 100644 --- a/drivers/hwmon/ams/ams-input.c +++ b/drivers/hwmon/ams/ams-input.c @@ -153,7 +153,7 @@ int ams_input_init(void) } /* Call with ams_info.lock held! */ -void ams_input_exit() +void ams_input_exit(void) { ams_input_disable(); device_remove_file(&ams_info.of_dev->dev, &dev_attr_joystick); diff --git a/drivers/hwmon/vt8231.c b/drivers/hwmon/vt8231.c index 93f93d4..a6a4aa0 100644 --- a/drivers/hwmon/vt8231.c +++ b/drivers/hwmon/vt8231.c @@ -727,7 +727,6 @@ int vt8231_detect(struct i2c_adapter *ad client->addr = isa_address; client->adapter = adapter; client->driver = &vt8231_driver; - client->dev.parent = &adapter->dev; /* Fill in the remaining client fields and put into the global list */ strlcpy(client->name, "vt8231", I2C_NAME_SIZE); diff --git a/drivers/i2c/busses/Kconfig b/drivers/i2c/busses/Kconfig index 9367c4c..4d44a2d 100644 --- a/drivers/i2c/busses/Kconfig +++ b/drivers/i2c/busses/Kconfig @@ -183,6 +183,7 @@ config I2C_PIIX4 ATI IXP200 ATI IXP300 ATI IXP400 + ATI SB600 Serverworks OSB4 Serverworks CSB5 Serverworks CSB6 @@ -341,6 +342,13 @@ config I2C_PARPORT_LIGHT This support is also available as a module. If so, the module will be called i2c-parport-light. +config I2C_PASEMI + tristate "PA Semi SMBus interface" +# depends on PPC_PASEMI && I2C && PCI + depends on I2C && PCI + help + Supports the PA Semi PWRficient on-chip SMBus interfaces. + config I2C_PROSAVAGE tristate "S3/VIA (Pro)Savage" depends on I2C && PCI @@ -499,11 +507,11 @@ config I2C_VIA will be called i2c-via. config I2C_VIAPRO - tristate "VIA 82C596/82C686/82xx" + tristate "VIA VT82C596/82C686/82xx and CX700" depends on I2C && PCI help If you say yes to this option, support will be included for the VIA - 82C596/82C686/82xx I2C interfaces. Specifically, the following + VT82C596 and later SMBus interface. Specifically, the following chipsets are supported: VT82C596A/B VT82C686A/B @@ -512,6 +520,7 @@ config I2C_VIAPRO VT8235 VT8237R/A VT8251 + CX700 This driver can also be built as a module. If so, the module will be called i2c-viapro. diff --git a/drivers/i2c/busses/Makefile b/drivers/i2c/busses/Makefile index 37196c1..03505aa 100644 --- a/drivers/i2c/busses/Makefile +++ b/drivers/i2c/busses/Makefile @@ -27,6 +27,7 @@ obj-$(CONFIG_I2C_OCORES) += i2c-ocores.o obj-$(CONFIG_I2C_OMAP) += i2c-omap.o obj-$(CONFIG_I2C_PARPORT) += i2c-parport.o obj-$(CONFIG_I2C_PARPORT_LIGHT) += i2c-parport-light.o +obj-$(CONFIG_I2C_PASEMI) += i2c-pasemi.o obj-$(CONFIG_I2C_PCA_ISA) += i2c-pca-isa.o obj-$(CONFIG_I2C_PIIX4) += i2c-piix4.o obj-$(CONFIG_I2C_PNX) += i2c-pnx.o diff --git a/drivers/i2c/busses/i2c-ali1535.c b/drivers/i2c/busses/i2c-ali1535.c index e75d339..6fd8ad7 100644 --- a/drivers/i2c/busses/i2c-ali1535.c +++ b/drivers/i2c/busses/i2c-ali1535.c @@ -57,7 +57,6 @@ #include #include #include #include -#include #include #include #include @@ -475,6 +474,7 @@ static const struct i2c_algorithm smbus_ static struct i2c_adapter ali1535_adapter = { .owner = THIS_MODULE, + .id = I2C_HW_SMBUS_ALI1535, .class = I2C_CLASS_HWMON, .algo = &smbus_algorithm, }; diff --git a/drivers/i2c/busses/i2c-ali1563.c b/drivers/i2c/busses/i2c-ali1563.c index 8e1e3f8..6b68074 100644 --- a/drivers/i2c/busses/i2c-ali1563.c +++ b/drivers/i2c/busses/i2c-ali1563.c @@ -314,35 +314,11 @@ static u32 ali1563_func(struct i2c_adapt } -static void ali1563_enable(struct pci_dev * dev) -{ - u16 ctrl; - - pci_read_config_word(dev,ALI1563_SMBBA,&ctrl); - ctrl |= 0x7; - pci_write_config_word(dev,ALI1563_SMBBA,ctrl); -} - static int __devinit ali1563_setup(struct pci_dev * dev) { u16 ctrl; pci_read_config_word(dev,ALI1563_SMBBA,&ctrl); - printk("ali1563: SMBus control = %04x\n",ctrl); - - /* Check if device is even enabled first */ - if (!(ctrl & ALI1563_SMB_IOEN)) { - dev_warn(&dev->dev,"I/O space not enabled, trying manually\n"); - ali1563_enable(dev); - } - if (!(ctrl & ALI1563_SMB_IOEN)) { - dev_warn(&dev->dev,"I/O space still not enabled, giving up\n"); - goto Err; - } - if (!(ctrl & ALI1563_SMB_HOSTEN)) { - dev_warn(&dev->dev,"Host Controller not enabled\n"); - goto Err; - } /* SMB I/O Base in high 12 bits and must be aligned with the * size of the I/O space. */ @@ -351,11 +327,31 @@ static int __devinit ali1563_setup(struc dev_warn(&dev->dev,"ali1563_smba Uninitialized\n"); goto Err; } + + /* Check if device is enabled */ + if (!(ctrl & ALI1563_SMB_HOSTEN)) { + dev_warn(&dev->dev, "Host Controller not enabled\n"); + goto Err; + } + if (!(ctrl & ALI1563_SMB_IOEN)) { + dev_warn(&dev->dev, "I/O space not enabled, trying manually\n"); + pci_write_config_word(dev, ALI1563_SMBBA, + ctrl | ALI1563_SMB_IOEN); + pci_read_config_word(dev, ALI1563_SMBBA, &ctrl); + if (!(ctrl & ALI1563_SMB_IOEN)) { + dev_err(&dev->dev, "I/O space still not enabled, " + "giving up\n"); + goto Err; + } + } + if (!request_region(ali1563_smba, ALI1563_SMB_IOSIZE, ali1563_pci_driver.name)) { - dev_warn(&dev->dev,"Could not allocate I/O space"); + dev_err(&dev->dev, "Could not allocate I/O space at 0x%04x\n", + ali1563_smba); goto Err; } + dev_info(&dev->dev, "Found ALi1563 SMBus at 0x%04x\n", ali1563_smba); return 0; Err: @@ -374,6 +370,7 @@ static const struct i2c_algorithm ali156 static struct i2c_adapter ali1563_adapter = { .owner = THIS_MODULE, + .id = I2C_HW_SMBUS_ALI1563, .class = I2C_CLASS_HWMON, .algo = &ali1563_algorithm, }; @@ -384,13 +381,18 @@ static int __devinit ali1563_probe(struc int error; if ((error = ali1563_setup(dev))) - return error; + goto exit; ali1563_adapter.dev.parent = &dev->dev; sprintf(ali1563_adapter.name,"SMBus ALi 1563 Adapter @ %04x", ali1563_smba); if ((error = i2c_add_adapter(&ali1563_adapter))) - ali1563_shutdown(dev); - printk("%s: Returning %d\n",__FUNCTION__,error); + goto exit_shutdown; + return 0; + +exit_shutdown: + ali1563_shutdown(dev); +exit: + dev_warn(&dev->dev, "ALi1563 SMBus probe failed (%d)\n", error); return error; } diff --git a/drivers/i2c/busses/i2c-ali15x3.c b/drivers/i2c/busses/i2c-ali15x3.c index 3f11b6e..e4e0df1 100644 --- a/drivers/i2c/busses/i2c-ali15x3.c +++ b/drivers/i2c/busses/i2c-ali15x3.c @@ -64,7 +64,6 @@ #include #include #include #include -#include #include #include #include @@ -470,6 +469,7 @@ static const struct i2c_algorithm smbus_ static struct i2c_adapter ali15x3_adapter = { .owner = THIS_MODULE, + .id = I2C_HW_SMBUS_ALI15X3, .class = I2C_CLASS_HWMON, .algo = &smbus_algorithm, }; diff --git a/drivers/i2c/busses/i2c-amd756-s4882.c b/drivers/i2c/busses/i2c-amd756-s4882.c index 08e9157..e5e96c8 100644 --- a/drivers/i2c/busses/i2c-amd756-s4882.c +++ b/drivers/i2c/busses/i2c-amd756-s4882.c @@ -184,12 +184,14 @@ static int __init amd756_s4882_init(void s4882_algo[0].smbus_xfer = amd756_access_virt0; s4882_adapter[0] = amd756_smbus; s4882_adapter[0].algo = s4882_algo; + s4882_adapter[0].dev.parent = amd756_smbus.dev.parent; for (i = 1; i < 5; i++) { s4882_algo[i] = *(amd756_smbus.algo); s4882_adapter[i] = amd756_smbus; sprintf(s4882_adapter[i].name, "SMBus 8111 adapter (CPU%d)", i-1); s4882_adapter[i].algo = s4882_algo+i; + s4882_adapter[i].dev.parent = amd756_smbus.dev.parent; } s4882_algo[1].smbus_xfer = amd756_access_virt1; s4882_algo[2].smbus_xfer = amd756_access_virt2; diff --git a/drivers/i2c/busses/i2c-amd756.c b/drivers/i2c/busses/i2c-amd756.c index 2d21afd..fa6155a 100644 --- a/drivers/i2c/busses/i2c-amd756.c +++ b/drivers/i2c/busses/i2c-amd756.c @@ -42,7 +42,6 @@ #include #include #include #include -#include #include #include #include @@ -301,6 +300,7 @@ static const struct i2c_algorithm smbus_ struct i2c_adapter amd756_smbus = { .owner = THIS_MODULE, + .id = I2C_HW_SMBUS_AMD756, .class = I2C_CLASS_HWMON, .algo = &smbus_algorithm, }; diff --git a/drivers/i2c/busses/i2c-amd8111.c b/drivers/i2c/busses/i2c-amd8111.c index 0fbc718..5bba3fb 100644 --- a/drivers/i2c/busses/i2c-amd8111.c +++ b/drivers/i2c/busses/i2c-amd8111.c @@ -12,7 +12,6 @@ #include #include #include #include -#include #include #include #include @@ -76,7 +75,8 @@ static unsigned int amd_ec_wait_write(st udelay(1); if (!timeout) { - dev_warn(&smbus->dev->dev, "Timeout while waiting for IBF to clear\n"); + dev_warn(&smbus->dev->dev, + "Timeout while waiting for IBF to clear\n"); return -1; } @@ -91,14 +91,16 @@ static unsigned int amd_ec_wait_read(str udelay(1); if (!timeout) { - dev_warn(&smbus->dev->dev, "Timeout while waiting for OBF to set\n"); + dev_warn(&smbus->dev->dev, + "Timeout while waiting for OBF to set\n"); return -1; } return 0; } -static unsigned int amd_ec_read(struct amd_smbus *smbus, unsigned char address, unsigned char *data) +static unsigned int amd_ec_read(struct amd_smbus *smbus, unsigned char address, + unsigned char *data) { if (amd_ec_wait_write(smbus)) return -1; @@ -115,7 +117,8 @@ static unsigned int amd_ec_read(struct a return 0; } -static unsigned int amd_ec_write(struct amd_smbus *smbus, unsigned char address, unsigned char data) +static unsigned int amd_ec_write(struct amd_smbus *smbus, unsigned char address, + unsigned char data) { if (amd_ec_wait_write(smbus)) return -1; @@ -175,18 +178,19 @@ #define AMD_SMB_PRTCL_I2C_BLOCK_DATA 0x4 #define AMD_SMB_PRTCL_PEC 0x80 -static s32 amd8111_access(struct i2c_adapter * adap, u16 addr, unsigned short flags, - char read_write, u8 command, int size, union i2c_smbus_data * data) +static s32 amd8111_access(struct i2c_adapter * adap, u16 addr, + unsigned short flags, char read_write, u8 command, int size, + union i2c_smbus_data * data) { struct amd_smbus *smbus = adap->algo_data; unsigned char protocol, len, pec, temp[2]; int i; - protocol = (read_write == I2C_SMBUS_READ) ? AMD_SMB_PRTCL_READ : AMD_SMB_PRTCL_WRITE; + protocol = (read_write == I2C_SMBUS_READ) ? AMD_SMB_PRTCL_READ + : AMD_SMB_PRTCL_WRITE; pec = (flags & I2C_CLIENT_PEC) ? AMD_SMB_PRTCL_PEC : 0; switch (size) { - case I2C_SMBUS_QUICK: protocol |= AMD_SMB_PRTCL_QUICK; read_write = I2C_SMBUS_WRITE; @@ -208,8 +212,10 @@ static s32 amd8111_access(struct i2c_ada case I2C_SMBUS_WORD_DATA: amd_ec_write(smbus, AMD_SMB_CMD, command); if (read_write == I2C_SMBUS_WRITE) { - amd_ec_write(smbus, AMD_SMB_DATA, data->word); - amd_ec_write(smbus, AMD_SMB_DATA + 1, data->word >> 8); + amd_ec_write(smbus, AMD_SMB_DATA, + data->word & 0xff); + amd_ec_write(smbus, AMD_SMB_DATA + 1, + data->word >> 8); } protocol |= AMD_SMB_PRTCL_WORD_DATA | pec; break; @@ -217,27 +223,31 @@ static s32 amd8111_access(struct i2c_ada case I2C_SMBUS_BLOCK_DATA: amd_ec_write(smbus, AMD_SMB_CMD, command); if (read_write == I2C_SMBUS_WRITE) { - len = min_t(u8, data->block[0], 32); + len = min_t(u8, data->block[0], + I2C_SMBUS_BLOCK_MAX); amd_ec_write(smbus, AMD_SMB_BCNT, len); for (i = 0; i < len; i++) - amd_ec_write(smbus, AMD_SMB_DATA + i, data->block[i + 1]); + amd_ec_write(smbus, AMD_SMB_DATA + i, + data->block[i + 1]); } protocol |= AMD_SMB_PRTCL_BLOCK_DATA | pec; break; case I2C_SMBUS_I2C_BLOCK_DATA: - len = min_t(u8, data->block[0], 32); + len = min_t(u8, data->block[0], + I2C_SMBUS_BLOCK_MAX); amd_ec_write(smbus, AMD_SMB_CMD, command); amd_ec_write(smbus, AMD_SMB_BCNT, len); if (read_write == I2C_SMBUS_WRITE) for (i = 0; i < len; i++) - amd_ec_write(smbus, AMD_SMB_DATA + i, data->block[i + 1]); + amd_ec_write(smbus, AMD_SMB_DATA + i, + data->block[i + 1]); protocol |= AMD_SMB_PRTCL_I2C_BLOCK_DATA; break; case I2C_SMBUS_PROC_CALL: amd_ec_write(smbus, AMD_SMB_CMD, command); - amd_ec_write(smbus, AMD_SMB_DATA, data->word); + amd_ec_write(smbus, AMD_SMB_DATA, data->word & 0xff); amd_ec_write(smbus, AMD_SMB_DATA + 1, data->word >> 8); protocol = AMD_SMB_PRTCL_PROC_CALL | pec; read_write = I2C_SMBUS_READ; @@ -248,7 +258,8 @@ static s32 amd8111_access(struct i2c_ada amd_ec_write(smbus, AMD_SMB_CMD, command); amd_ec_write(smbus, AMD_SMB_BCNT, len); for (i = 0; i < len; i++) - amd_ec_write(smbus, AMD_SMB_DATA + i, data->block[i + 1]); + amd_ec_write(smbus, AMD_SMB_DATA + i, + data->block[i + 1]); protocol = AMD_SMB_PRTCL_BLOCK_PROC_CALL | pec; read_write = I2C_SMBUS_READ; break; @@ -280,7 +291,6 @@ static s32 amd8111_access(struct i2c_ada return 0; switch (size) { - case I2C_SMBUS_BYTE: case I2C_SMBUS_BYTE_DATA: amd_ec_read(smbus, AMD_SMB_DATA, &data->byte); @@ -296,10 +306,11 @@ static s32 amd8111_access(struct i2c_ada case I2C_SMBUS_BLOCK_DATA: case I2C_SMBUS_BLOCK_PROC_CALL: amd_ec_read(smbus, AMD_SMB_BCNT, &len); - len = min_t(u8, len, 32); + len = min_t(u8, len, I2C_SMBUS_BLOCK_MAX); case I2C_SMBUS_I2C_BLOCK_DATA: for (i = 0; i < len; i++) - amd_ec_read(smbus, AMD_SMB_DATA + i, data->block + i + 1); + amd_ec_read(smbus, AMD_SMB_DATA + i, + data->block + i + 1); data->block[0] = len; break; } @@ -310,7 +321,8 @@ static s32 amd8111_access(struct i2c_ada static u32 amd8111_func(struct i2c_adapter *adapter) { - return I2C_FUNC_SMBUS_QUICK | I2C_FUNC_SMBUS_BYTE | I2C_FUNC_SMBUS_BYTE_DATA | + return I2C_FUNC_SMBUS_QUICK | I2C_FUNC_SMBUS_BYTE | + I2C_FUNC_SMBUS_BYTE_DATA | I2C_FUNC_SMBUS_WORD_DATA | I2C_FUNC_SMBUS_BLOCK_DATA | I2C_FUNC_SMBUS_PROC_CALL | I2C_FUNC_SMBUS_BLOCK_PROC_CALL | I2C_FUNC_SMBUS_I2C_BLOCK | I2C_FUNC_SMBUS_HWPEC_CALC; @@ -329,12 +341,13 @@ static struct pci_device_id amd8111_ids[ MODULE_DEVICE_TABLE (pci, amd8111_ids); -static int __devinit amd8111_probe(struct pci_dev *dev, const struct pci_device_id *id) +static int __devinit amd8111_probe(struct pci_dev *dev, + const struct pci_device_id *id) { struct amd_smbus *smbus; - int error = -ENODEV; + int error; - if (~pci_resource_flags(dev, 0) & IORESOURCE_IO) + if (!(pci_resource_flags(dev, 0) & IORESOURCE_IO)) return -ENODEV; smbus = kzalloc(sizeof(struct amd_smbus), GFP_KERNEL); @@ -345,12 +358,15 @@ static int __devinit amd8111_probe(struc smbus->base = pci_resource_start(dev, 0); smbus->size = pci_resource_len(dev, 0); - if (!request_region(smbus->base, smbus->size, amd8111_driver.name)) + if (!request_region(smbus->base, smbus->size, amd8111_driver.name)) { + error = -EBUSY; goto out_kfree; + } smbus->adapter.owner = THIS_MODULE; snprintf(smbus->adapter.name, I2C_NAME_SIZE, "SMBus2 AMD8111 adapter at %04x", smbus->base); + smbus->adapter.id = I2C_HW_SMBUS_AMD8111; smbus->adapter.class = I2C_CLASS_HWMON; smbus->adapter.algo = &smbus_algorithm; smbus->adapter.algo_data = smbus; @@ -358,11 +374,11 @@ static int __devinit amd8111_probe(struc /* set up the driverfs linkage to our parent device */ smbus->adapter.dev.parent = &dev->dev; + pci_write_config_dword(smbus->dev, AMD_PCI_MISC, 0); error = i2c_add_adapter(&smbus->adapter); if (error) goto out_release_region; - pci_write_config_dword(smbus->dev, AMD_PCI_MISC, 0); pci_set_drvdata(dev, smbus); return 0; @@ -370,10 +386,9 @@ static int __devinit amd8111_probe(struc release_region(smbus->base, smbus->size); out_kfree: kfree(smbus); - return -1; + return error; } - static void __devexit amd8111_remove(struct pci_dev *dev) { struct amd_smbus *smbus = pci_get_drvdata(dev); @@ -395,7 +410,6 @@ static int __init i2c_amd8111_init(void) return pci_register_driver(&amd8111_driver); } - static void __exit i2c_amd8111_exit(void) { pci_unregister_driver(&amd8111_driver); diff --git a/drivers/i2c/busses/i2c-i801.c b/drivers/i2c/busses/i2c-i801.c index ae625b8..21f2671 100644 --- a/drivers/i2c/busses/i2c-i801.c +++ b/drivers/i2c/busses/i2c-i801.c @@ -48,7 +48,6 @@ #include #include #include #include -#include #include #include #include @@ -123,7 +122,7 @@ static int i801_transaction(void) dev_dbg(&I801_dev->dev, "Failed! (%02x)\n", temp); return -1; } else { - dev_dbg(&I801_dev->dev, "Successfull!\n"); + dev_dbg(&I801_dev->dev, "Successful!\n"); } } @@ -442,6 +441,7 @@ static const struct i2c_algorithm smbus_ static struct i2c_adapter i801_adapter = { .owner = THIS_MODULE, + .id = I2C_HW_SMBUS_I801, .class = I2C_CLASS_HWMON, .algo = &smbus_algorithm, }; diff --git a/drivers/i2c/busses/i2c-i810.c b/drivers/i2c/busses/i2c-i810.c index 10c98bc..42e8d94 100644 --- a/drivers/i2c/busses/i2c-i810.c +++ b/drivers/i2c/busses/i2c-i810.c @@ -171,6 +171,7 @@ static struct i2c_algo_bit_data i810_i2c static struct i2c_adapter i810_i2c_adapter = { .owner = THIS_MODULE, + .id = I2C_HW_B_I810, .name = "I810/I815 I2C Adapter", .algo_data = &i810_i2c_bit_data, }; @@ -186,6 +187,7 @@ static struct i2c_algo_bit_data i810_ddc static struct i2c_adapter i810_ddc_adapter = { .owner = THIS_MODULE, + .id = I2C_HW_B_I810, .name = "I810/I815 DDC Adapter", .algo_data = &i810_ddc_bit_data, }; diff --git a/drivers/i2c/busses/i2c-ibm_iic.c b/drivers/i2c/busses/i2c-ibm_iic.c index 1898e99..8b14d14 100644 --- a/drivers/i2c/busses/i2c-ibm_iic.c +++ b/drivers/i2c/busses/i2c-ibm_iic.c @@ -727,6 +727,7 @@ static int __devinit iic_probe(struct oc /* Register it with i2c layer */ adap = &dev->adap; + adap->dev.parent = &ocp->dev; strcpy(adap->name, "IBM IIC"); i2c_set_adapdata(adap, dev); adap->id = I2C_HW_OCP; diff --git a/drivers/i2c/busses/i2c-iop3xx.c b/drivers/i2c/busses/i2c-iop3xx.c index d108ab4..20ee4f7 100644 --- a/drivers/i2c/busses/i2c-iop3xx.c +++ b/drivers/i2c/busses/i2c-iop3xx.c @@ -36,7 +36,6 @@ #include #include #include #include -#include #include #include diff --git a/drivers/i2c/busses/i2c-isa.c b/drivers/i2c/busses/i2c-isa.c index 8ed59a2..5f33bc9 100644 --- a/drivers/i2c/busses/i2c-isa.c +++ b/drivers/i2c/busses/i2c-isa.c @@ -39,6 +39,7 @@ #include #include #include #include +#include static u32 isa_func(struct i2c_adapter *adapter); diff --git a/drivers/i2c/busses/i2c-mv64xxx.c b/drivers/i2c/busses/i2c-mv64xxx.c index 4901736..a3283b9 100644 --- a/drivers/i2c/busses/i2c-mv64xxx.c +++ b/drivers/i2c/busses/i2c-mv64xxx.c @@ -520,6 +520,7 @@ mv64xxx_i2c_probe(struct platform_device rc = -ENXIO; goto exit_unmap_regs; } + drv_data->adapter.dev.parent = &pd->dev; drv_data->adapter.id = I2C_HW_MV64XXX; drv_data->adapter.algo = &mv64xxx_i2c_algo; drv_data->adapter.owner = THIS_MODULE; diff --git a/drivers/i2c/busses/i2c-nforce2.c b/drivers/i2c/busses/i2c-nforce2.c index ad37c10..1514ec5 100644 --- a/drivers/i2c/busses/i2c-nforce2.c +++ b/drivers/i2c/busses/i2c-nforce2.c @@ -44,7 +44,6 @@ #include #include #include #include -#include #include #include #include @@ -57,7 +56,6 @@ MODULE_DESCRIPTION("nForce2/3/4/5xx SMBu struct nforce2_smbus { - struct pci_dev *dev; struct i2c_adapter adapter; int base; int size; @@ -230,7 +228,6 @@ static int __devinit nforce2_probe_smb ( smbus->base = iobase & PCI_BASE_ADDRESS_IO_MASK; smbus->size = 64; } - smbus->dev = dev; if (!request_region(smbus->base, smbus->size, nforce2_driver.name)) { dev_err(&smbus->adapter.dev, "Error requesting region %02x .. %02X for %s\n", @@ -238,6 +235,7 @@ static int __devinit nforce2_probe_smb ( return -1; } smbus->adapter.owner = THIS_MODULE; + smbus->adapter.id = I2C_HW_SMBUS_NFORCE2; smbus->adapter.class = I2C_CLASS_HWMON; smbus->adapter.algo = &smbus_algorithm; smbus->adapter.algo_data = smbus; diff --git a/drivers/i2c/busses/i2c-ocores.c b/drivers/i2c/busses/i2c-ocores.c index f28a76d..e417c2c 100644 --- a/drivers/i2c/busses/i2c-ocores.c +++ b/drivers/i2c/busses/i2c-ocores.c @@ -11,7 +11,6 @@ #include #include -#include #include #include #include diff --git a/drivers/i2c/busses/i2c-parport.h b/drivers/i2c/busses/i2c-parport.h index 9ddd816..ed69d84 100644 --- a/drivers/i2c/busses/i2c-parport.h +++ b/drivers/i2c/busses/i2c-parport.h @@ -88,6 +88,13 @@ static struct adapter_parm adapter_parm[ .getscl = { 0x40, STAT, 0 }, .init = { 0xfc, DATA, 0 }, }, + /* type 7: One For All JP1 parallel port adapter */ + { + .setsda = { 0x01, DATA, 0 }, + .setscl = { 0x02, DATA, 0 }, + .getsda = { 0x80, STAT, 1 }, + .init = { 0x04, DATA, 1 }, + }, }; static int type = -1; @@ -101,4 +108,5 @@ MODULE_PARM_DESC(type, " 4 = ADM1032 evaluation board\n" " 5 = ADM1025, ADM1030 and ADM1031 evaluation boards\n" " 6 = Barco LPT->DVI (K5800236) adapter\n" + " 7 = One For All JP1 parallel port adapter\n" ); diff --git a/drivers/i2c/busses/i2c-pasemi.c b/drivers/i2c/busses/i2c-pasemi.c new file mode 100644 index 0000000..f54fb5d --- /dev/null +++ b/drivers/i2c/busses/i2c-pasemi.c @@ -0,0 +1,426 @@ +/* + * Copyright (C) 2006-2007 PA Semi, Inc + * + * SMBus host driver for PA Semi PWRficient + * + * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +static struct pci_driver pasemi_smb_driver; + +struct pasemi_smbus { + struct pci_dev *dev; + struct i2c_adapter adapter; + unsigned long base; + int size; +}; + +/* Register offsets */ +#define REG_MTXFIFO 0x00 +#define REG_MRXFIFO 0x04 +#define REG_SMSTA 0x14 +#define REG_CTL 0x1c + +/* Register defs */ +#define MTXFIFO_READ 0x00000400 +#define MTXFIFO_STOP 0x00000200 +#define MTXFIFO_START 0x00000100 +#define MTXFIFO_DATA_M 0x000000ff + +#define MRXFIFO_EMPTY 0x00000100 +#define MRXFIFO_DATA_M 0x000000ff + +#define SMSTA_XEN 0x08000000 + +#define CTL_MRR 0x00000400 +#define CTL_MTR 0x00000200 +#define CTL_CLK_M 0x000000ff + +#define CLK_100K_DIV 84 +#define CLK_400K_DIV 21 + +static inline void reg_write(struct pasemi_smbus *smbus, int reg, int val) +{ + dev_dbg(&smbus->dev->dev, "smbus write reg %lx val %08x\n", + smbus->base + reg, val); + outl(val, smbus->base + reg); +} + +static inline int reg_read(struct pasemi_smbus *smbus, int reg) +{ + int ret; + ret = inl(smbus->base + reg); + dev_dbg(&smbus->dev->dev, "smbus read reg %lx val %08x\n", + smbus->base + reg, ret); + return ret; +} + +#define TXFIFO_WR(smbus, reg) reg_write((smbus), REG_MTXFIFO, (reg)) +#define RXFIFO_RD(smbus) reg_read((smbus), REG_MRXFIFO) + +static void pasemi_smb_clear(struct pasemi_smbus *smbus) +{ + unsigned int status; + + status = reg_read(smbus, REG_SMSTA); + reg_write(smbus, REG_SMSTA, status); +} + +static unsigned int pasemi_smb_waitready(struct pasemi_smbus *smbus) +{ + int timeout = 10; + unsigned int status; + + status = reg_read(smbus, REG_SMSTA); + + while (!(status & SMSTA_XEN) && timeout--) { + msleep(1); + status = reg_read(smbus, REG_SMSTA); + } + + if (timeout < 0) { + dev_warn(&smbus->dev->dev, "Timeout, status 0x%08x\n", status); + reg_write(smbus, REG_SMSTA, status); + return -ETIME; + } + + /* Clear XEN */ + reg_write(smbus, REG_SMSTA, SMSTA_XEN); + + return 0; +} + +static int pasemi_i2c_xfer_msg(struct i2c_adapter *adapter, + struct i2c_msg *msg, int stop) +{ + struct pasemi_smbus *smbus = adapter->algo_data; + int read, i, err; + u32 rd; + + read = msg->flags & I2C_M_RD ? 1 : 0; + + TXFIFO_WR(smbus, MTXFIFO_START | (msg->addr << 1) | read); + + if (read) { + TXFIFO_WR(smbus, msg->len | MTXFIFO_READ | + (stop ? MTXFIFO_STOP : 0)); + + err = pasemi_smb_waitready(smbus); + if (err) + goto reset_out; + + for (i = 0; i < msg->len; i++) { + rd = RXFIFO_RD(smbus); + if (rd & MRXFIFO_EMPTY) { + err = -ENODATA; + goto reset_out; + } + msg->buf[i] = rd & MRXFIFO_DATA_M; + } + } else { + for (i = 0; i < msg->len - 1; i++) + TXFIFO_WR(smbus, msg->buf[i]); + + TXFIFO_WR(smbus, msg->buf[msg->len] | + (stop ? MTXFIFO_STOP : 0)); + } + + return 0; + + reset_out: + reg_write(smbus, REG_CTL, (CTL_MTR | CTL_MRR | + (CLK_100K_DIV & CTL_CLK_M))); + return err; +} + +static int pasemi_i2c_xfer(struct i2c_adapter *adapter, + struct i2c_msg *msgs, int num) +{ + struct pasemi_smbus *smbus = adapter->algo_data; + int ret, i; + + pasemi_smb_clear(smbus); + + ret = 0; + + for (i = 0; i < num && !ret; i++) + ret = pasemi_i2c_xfer_msg(adapter, &msgs[i], (i == (num - 1))); + + return ret ? ret : num; +} + +static int pasemi_smb_xfer(struct i2c_adapter *adapter, + u16 addr, unsigned short flags, char read_write, u8 command, + int size, union i2c_smbus_data *data) +{ + struct pasemi_smbus *smbus = adapter->algo_data; + unsigned int rd; + int read_flag, err; + int len = 0, i; + + /* All our ops take 8-bit shifted addresses */ + addr <<= 1; + read_flag = read_write == I2C_SMBUS_READ; + + pasemi_smb_clear(smbus); + + switch (size) { + case I2C_SMBUS_QUICK: + TXFIFO_WR(smbus, addr | read_flag | MTXFIFO_START | + MTXFIFO_STOP); + break; + case I2C_SMBUS_BYTE: + TXFIFO_WR(smbus, addr | read_flag | MTXFIFO_START); + if (read_write) + TXFIFO_WR(smbus, 1 | MTXFIFO_STOP | MTXFIFO_READ); + else + TXFIFO_WR(smbus, MTXFIFO_STOP | command); + break; + case I2C_SMBUS_BYTE_DATA: + TXFIFO_WR(smbus, addr | MTXFIFO_START); + TXFIFO_WR(smbus, command); + if (read_write) { + TXFIFO_WR(smbus, addr | I2C_SMBUS_READ | MTXFIFO_START); + TXFIFO_WR(smbus, 1 | MTXFIFO_READ | MTXFIFO_STOP); + } else { + TXFIFO_WR(smbus, MTXFIFO_STOP | data->byte); + } + break; + case I2C_SMBUS_WORD_DATA: + TXFIFO_WR(smbus, addr | MTXFIFO_START); + TXFIFO_WR(smbus, command); + if (read_write) { + TXFIFO_WR(smbus, addr | I2C_SMBUS_READ | MTXFIFO_START); + TXFIFO_WR(smbus, 2 | MTXFIFO_READ | MTXFIFO_STOP); + } else { + TXFIFO_WR(smbus, data->word & MTXFIFO_DATA_M); + TXFIFO_WR(smbus, MTXFIFO_STOP | (data->word >> 8)); + } + break; + case I2C_SMBUS_BLOCK_DATA: + TXFIFO_WR(smbus, addr | MTXFIFO_START); + TXFIFO_WR(smbus, command); + if (read_write) { + TXFIFO_WR(smbus, addr | I2C_SMBUS_READ | MTXFIFO_START); + TXFIFO_WR(smbus, 1 | MTXFIFO_READ); + rd = RXFIFO_RD(smbus); + len = min_t(u8, (rd & MRXFIFO_DATA_M), + I2C_SMBUS_BLOCK_MAX); + TXFIFO_WR(smbus, (len + 1) | MTXFIFO_READ | + MTXFIFO_STOP); + } else { + len = min_t(u8, data->block[0], I2C_SMBUS_BLOCK_MAX); + TXFIFO_WR(smbus, len); + for (i = 1; i < len; i++) + TXFIFO_WR(smbus, data->block[i]); + TXFIFO_WR(smbus, data->block[len] | MTXFIFO_STOP); + } + break; + case I2C_SMBUS_PROC_CALL: + read_write = I2C_SMBUS_READ; + TXFIFO_WR(smbus, addr | MTXFIFO_START); + TXFIFO_WR(smbus, command); + TXFIFO_WR(smbus, data->word & MTXFIFO_DATA_M); + TXFIFO_WR(smbus, (data->word >> 8) & MTXFIFO_DATA_M); + TXFIFO_WR(smbus, addr | I2C_SMBUS_READ | MTXFIFO_START); + TXFIFO_WR(smbus, 2 | MTXFIFO_STOP | MTXFIFO_READ); + break; + case I2C_SMBUS_BLOCK_PROC_CALL: + len = min_t(u8, data->block[0], I2C_SMBUS_BLOCK_MAX - 1); + read_write = I2C_SMBUS_READ; + TXFIFO_WR(smbus, addr | MTXFIFO_START); + TXFIFO_WR(smbus, command); + TXFIFO_WR(smbus, len); + for (i = 1; i <= len; i++) + TXFIFO_WR(smbus, data->block[i]); + TXFIFO_WR(smbus, addr | I2C_SMBUS_READ); + TXFIFO_WR(smbus, MTXFIFO_READ | 1); + rd = RXFIFO_RD(smbus); + len = min_t(u8, (rd & MRXFIFO_DATA_M), + I2C_SMBUS_BLOCK_MAX - len); + TXFIFO_WR(smbus, (len + 1) | MTXFIFO_READ | MTXFIFO_STOP); + break; + + default: + dev_warn(&adapter->dev, "Unsupported transaction %d\n", size); + return -EINVAL; + } + + err = pasemi_smb_waitready(smbus); + if (err) + goto reset_out; + + if (read_write == I2C_SMBUS_WRITE) + return 0; + + switch (size) { + case I2C_SMBUS_BYTE: + case I2C_SMBUS_BYTE_DATA: + rd = RXFIFO_RD(smbus); + if (rd & MRXFIFO_EMPTY) { + err = -ENODATA; + goto reset_out; + } + data->byte = rd & MRXFIFO_DATA_M; + break; + case I2C_SMBUS_WORD_DATA: + case I2C_SMBUS_PROC_CALL: + rd = RXFIFO_RD(smbus); + if (rd & MRXFIFO_EMPTY) { + err = -ENODATA; + goto reset_out; + } + data->word = rd & MRXFIFO_DATA_M; + rd = RXFIFO_RD(smbus); + if (rd & MRXFIFO_EMPTY) { + err = -ENODATA; + goto reset_out; + } + data->word |= (rd & MRXFIFO_DATA_M) << 8; + break; + case I2C_SMBUS_BLOCK_DATA: + case I2C_SMBUS_BLOCK_PROC_CALL: + data->block[0] = len; + for (i = 1; i <= len; i ++) { + rd = RXFIFO_RD(smbus); + if (rd & MRXFIFO_EMPTY) { + err = -ENODATA; + goto reset_out; + } + data->block[i] = rd & MRXFIFO_DATA_M; + } + break; + } + + return 0; + + reset_out: + reg_write(smbus, REG_CTL, (CTL_MTR | CTL_MRR | + (CLK_100K_DIV & CTL_CLK_M))); + return err; +} + +static u32 pasemi_smb_func(struct i2c_adapter *adapter) +{ + return I2C_FUNC_SMBUS_QUICK | I2C_FUNC_SMBUS_BYTE | + I2C_FUNC_SMBUS_BYTE_DATA | I2C_FUNC_SMBUS_WORD_DATA | + I2C_FUNC_SMBUS_BLOCK_DATA | I2C_FUNC_SMBUS_PROC_CALL | + I2C_FUNC_SMBUS_BLOCK_PROC_CALL | I2C_FUNC_I2C; +} + +static const struct i2c_algorithm smbus_algorithm = { + .master_xfer = pasemi_i2c_xfer, + .smbus_xfer = pasemi_smb_xfer, + .functionality = pasemi_smb_func, +}; + +static int __devinit pasemi_smb_probe(struct pci_dev *dev, + const struct pci_device_id *id) +{ + struct pasemi_smbus *smbus; + int error; + + if (!(pci_resource_flags(dev, 0) & IORESOURCE_IO)) + return -ENODEV; + + smbus = kzalloc(sizeof(struct pasemi_smbus), GFP_KERNEL); + if (!smbus) + return -ENOMEM; + + smbus->dev = dev; + smbus->base = pci_resource_start(dev, 0); + smbus->size = pci_resource_len(dev, 0); + + if (!request_region(smbus->base, smbus->size, + pasemi_smb_driver.name)) { + error = -EBUSY; + goto out_kfree; + } + + smbus->adapter.owner = THIS_MODULE; + snprintf(smbus->adapter.name, I2C_NAME_SIZE, + "PA Semi SMBus adapter at 0x%lx", smbus->base); + smbus->adapter.class = I2C_CLASS_HWMON; + smbus->adapter.algo = &smbus_algorithm; + smbus->adapter.algo_data = smbus; + + /* set up the driverfs linkage to our parent device */ + smbus->adapter.dev.parent = &dev->dev; + + reg_write(smbus, REG_CTL, (CTL_MTR | CTL_MRR | + (CLK_100K_DIV & CTL_CLK_M))); + + error = i2c_add_adapter(&smbus->adapter); + if (error) + goto out_release_region; + + pci_set_drvdata(dev, smbus); + + return 0; + + out_release_region: + release_region(smbus->base, smbus->size); + out_kfree: + kfree(smbus); + return error; +} + +static void __devexit pasemi_smb_remove(struct pci_dev *dev) +{ + struct pasemi_smbus *smbus = pci_get_drvdata(dev); + + i2c_del_adapter(&smbus->adapter); + release_region(smbus->base, smbus->size); + kfree(smbus); +} + +static struct pci_device_id pasemi_smb_ids[] = { + { PCI_DEVICE(0x1959, 0xa003) }, + { 0, } +}; + +MODULE_DEVICE_TABLE(pci, pasemi_smb_ids); + +static struct pci_driver pasemi_smb_driver = { + .name = "i2c-pasemi", + .id_table = pasemi_smb_ids, + .probe = pasemi_smb_probe, + .remove = __devexit_p(pasemi_smb_remove), +}; + +static int __init pasemi_smb_init(void) +{ + return pci_register_driver(&pasemi_smb_driver); +} + +static void __exit pasemi_smb_exit(void) +{ + pci_unregister_driver(&pasemi_smb_driver); +} + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR ("Olof Johansson "); +MODULE_DESCRIPTION("PA Semi PWRficient SMBus driver"); + +module_init(pasemi_smb_init); +module_exit(pasemi_smb_exit); diff --git a/drivers/i2c/busses/i2c-piix4.c b/drivers/i2c/busses/i2c-piix4.c index 30c7a1b..d888293 100644 --- a/drivers/i2c/busses/i2c-piix4.c +++ b/drivers/i2c/busses/i2c-piix4.c @@ -23,6 +23,7 @@ Supports: Intel PIIX4, 440MX Serverworks OSB4, CSB5, CSB6, HT-1000 + ATI IXP200, IXP300, IXP400, SB600 SMSC Victory66 Note: we assume there can only be one device, with one SMBus interface. @@ -34,7 +35,6 @@ #include #include #include #include -#include #include #include #include @@ -383,6 +383,7 @@ static const struct i2c_algorithm smbus_ static struct i2c_adapter piix4_adapter = { .owner = THIS_MODULE, + .id = I2C_HW_SMBUS_PIIX4, .class = I2C_CLASS_HWMON, .algo = &smbus_algorithm, }; @@ -396,6 +397,8 @@ static struct pci_device_id piix4_ids[] .driver_data = 0 }, { PCI_DEVICE(PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_IXP400_SMBUS), .driver_data = 0 }, + { PCI_DEVICE(PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_IXP600_SMBUS), + .driver_data = 0 }, { PCI_DEVICE(PCI_VENDOR_ID_SERVERWORKS, PCI_DEVICE_ID_SERVERWORKS_OSB4), .driver_data = 0 }, { PCI_DEVICE(PCI_VENDOR_ID_SERVERWORKS, PCI_DEVICE_ID_SERVERWORKS_CSB5), diff --git a/drivers/i2c/busses/i2c-powermac.c b/drivers/i2c/busses/i2c-powermac.c index 648d555..1425d22 100644 --- a/drivers/i2c/busses/i2c-powermac.c +++ b/drivers/i2c/busses/i2c-powermac.c @@ -25,7 +25,6 @@ #include #include #include #include -#include #include #include #include diff --git a/drivers/i2c/busses/i2c-s3c2410.c b/drivers/i2c/busses/i2c-s3c2410.c index 4ca6de2..556f244 100644 --- a/drivers/i2c/busses/i2c-s3c2410.c +++ b/drivers/i2c/busses/i2c-s3c2410.c @@ -28,7 +28,6 @@ #include #include #include #include -#include #include #include #include diff --git a/drivers/i2c/busses/i2c-savage4.c b/drivers/i2c/busses/i2c-savage4.c index 844b4ff..b7fb65c 100644 --- a/drivers/i2c/busses/i2c-savage4.c +++ b/drivers/i2c/busses/i2c-savage4.c @@ -145,6 +145,7 @@ static struct i2c_algo_bit_data sav_i2c_ static struct i2c_adapter savage4_i2c_adapter = { .owner = THIS_MODULE, + .id = I2C_HW_B_SAVAGE, .name = "I2C Savage4 adapter", .algo_data = &sav_i2c_bit_data, }; diff --git a/drivers/i2c/busses/i2c-sis5595.c b/drivers/i2c/busses/i2c-sis5595.c index 38bbfd8..d333bab 100644 --- a/drivers/i2c/busses/i2c-sis5595.c +++ b/drivers/i2c/busses/i2c-sis5595.c @@ -365,6 +365,7 @@ static const struct i2c_algorithm smbus_ static struct i2c_adapter sis5595_adapter = { .owner = THIS_MODULE, + .id = I2C_HW_SMBUS_SIS5595, .class = I2C_CLASS_HWMON, .algo = &smbus_algorithm, }; diff --git a/drivers/i2c/busses/i2c-sis630.c b/drivers/i2c/busses/i2c-sis630.c index dec0baf..172bacf 100644 --- a/drivers/i2c/busses/i2c-sis630.c +++ b/drivers/i2c/busses/i2c-sis630.c @@ -457,6 +457,7 @@ static const struct i2c_algorithm smbus_ static struct i2c_adapter sis630_adapter = { .owner = THIS_MODULE, + .id = I2C_HW_SMBUS_SIS630, .class = I2C_CLASS_HWMON, .algo = &smbus_algorithm, }; diff --git a/drivers/i2c/busses/i2c-sis96x.c b/drivers/i2c/busses/i2c-sis96x.c index 7fd07fb..73dae44 100644 --- a/drivers/i2c/busses/i2c-sis96x.c +++ b/drivers/i2c/busses/i2c-sis96x.c @@ -37,7 +37,6 @@ #include #include #include #include -#include #include #include #include @@ -249,6 +248,7 @@ static const struct i2c_algorithm smbus_ static struct i2c_adapter sis96x_adapter = { .owner = THIS_MODULE, + .id = I2C_HW_SMBUS_SIS96X, .class = I2C_CLASS_HWMON, .algo = &smbus_algorithm, }; diff --git a/drivers/i2c/busses/i2c-via.c b/drivers/i2c/busses/i2c-via.c index 15d7e00..bbcc621 100644 --- a/drivers/i2c/busses/i2c-via.c +++ b/drivers/i2c/busses/i2c-via.c @@ -86,6 +86,7 @@ static struct i2c_algo_bit_data bit_data static struct i2c_adapter vt586b_adapter = { .owner = THIS_MODULE, + .id = I2C_HW_B_VIA, .class = I2C_CLASS_HWMON, .name = "VIA i2c", .algo_data = &bit_data, diff --git a/drivers/i2c/busses/i2c-viapro.c b/drivers/i2c/busses/i2c-viapro.c index efc6bbf..03c5fc8 100644 --- a/drivers/i2c/busses/i2c-viapro.c +++ b/drivers/i2c/busses/i2c-viapro.c @@ -4,7 +4,7 @@ Copyright (c) 1998 - 2002 Frodo Looijaard , Philip Edelbrock , Kyösti Mälkki , Mark D. Studebaker - Copyright (C) 2005 Jean Delvare + Copyright (C) 2005 - 2007 Jean Delvare 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 @@ -36,6 +36,7 @@ VT8237R 0x3227 yes VT8237A 0x3337 yes VT8251 0x3287 yes + CX700 0x8324 yes Note: we assume there can only be one device, with one SMBus interface. */ @@ -306,6 +307,7 @@ static const struct i2c_algorithm smbus_ static struct i2c_adapter vt596_adapter = { .owner = THIS_MODULE, + .id = I2C_HW_SMBUS_VIA2, .class = I2C_CLASS_HWMON, .algo = &smbus_algorithm, }; @@ -383,6 +385,7 @@ found: dev_dbg(&pdev->dev, "VT596_smba = 0x%X\n", vt596_smba); switch (pdev->device) { + case PCI_DEVICE_ID_VIA_CX700: case PCI_DEVICE_ID_VIA_8251: case PCI_DEVICE_ID_VIA_8237: case PCI_DEVICE_ID_VIA_8237A: @@ -442,6 +445,8 @@ static struct pci_device_id vt596_ids[] .driver_data = SMBBA1 }, { PCI_DEVICE(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8251), .driver_data = SMBBA3 }, + { PCI_DEVICE(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_CX700), + .driver_data = SMBBA3 }, { 0, } }; diff --git a/drivers/i2c/busses/i2c-voodoo3.c b/drivers/i2c/busses/i2c-voodoo3.c index b0377b8..88a3447 100644 --- a/drivers/i2c/busses/i2c-voodoo3.c +++ b/drivers/i2c/busses/i2c-voodoo3.c @@ -165,6 +165,7 @@ static struct i2c_algo_bit_data voo_i2c_ static struct i2c_adapter voodoo3_i2c_adapter = { .owner = THIS_MODULE, + .id = I2C_HW_B_VOO, .class = I2C_CLASS_TV_ANALOG, .name = "I2C Voodoo3/Banshee adapter", .algo_data = &voo_i2c_bit_data, @@ -181,6 +182,7 @@ static struct i2c_algo_bit_data voo_ddc_ static struct i2c_adapter voodoo3_ddc_adapter = { .owner = THIS_MODULE, + .id = I2C_HW_B_VOO, .class = I2C_CLASS_DDC, .name = "DDC Voodoo3/Banshee adapter", .algo_data = &voo_ddc_bit_data, diff --git a/drivers/i2c/busses/scx200_acb.c b/drivers/i2c/busses/scx200_acb.c index 714bae7..0b082c5 100644 --- a/drivers/i2c/busses/scx200_acb.c +++ b/drivers/i2c/busses/scx200_acb.c @@ -428,7 +428,7 @@ static __init int scx200_acb_probe(struc } static __init struct scx200_acb_iface *scx200_create_iface(const char *text, - int index) + struct device *dev, int index) { struct scx200_acb_iface *iface; struct i2c_adapter *adapter; @@ -446,6 +446,7 @@ static __init struct scx200_acb_iface *s adapter->id = I2C_HW_SMBUS_SCX200; adapter->algo = &scx200_acb_algorithm; adapter->class = I2C_CLASS_HWMON; + adapter->dev.parent = dev; mutex_init(&iface->mutex); @@ -486,7 +487,7 @@ static __init int scx200_create_pci(cons struct scx200_acb_iface *iface; int rc; - iface = scx200_create_iface(text, 0); + iface = scx200_create_iface(text, &pdev->dev, 0); if (iface == NULL) return -ENOMEM; @@ -524,7 +525,7 @@ static int __init scx200_create_isa(cons struct scx200_acb_iface *iface; int rc; - iface = scx200_create_iface(text, index); + iface = scx200_create_iface(text, NULL, index); if (iface == NULL) return -ENOMEM; diff --git a/drivers/i2c/busses/scx200_i2c.c b/drivers/i2c/busses/scx200_i2c.c index 6cd96e4..c3022a0 100644 --- a/drivers/i2c/busses/scx200_i2c.c +++ b/drivers/i2c/busses/scx200_i2c.c @@ -81,6 +81,7 @@ static struct i2c_algo_bit_data scx200_i static struct i2c_adapter scx200_i2c_ops = { .owner = THIS_MODULE, + .id = I2C_HW_B_SCX200, .algo_data = &scx200_i2c_data, .name = "NatSemi SCx200 I2C", }; diff --git a/drivers/i2c/chips/eeprom.c b/drivers/i2c/chips/eeprom.c index cec3a0c..bfce13c 100644 --- a/drivers/i2c/chips/eeprom.c +++ b/drivers/i2c/chips/eeprom.c @@ -30,7 +30,6 @@ #include #include #include #include -#include #include #include #include diff --git a/drivers/i2c/chips/isp1301_omap.c b/drivers/i2c/chips/isp1301_omap.c index ccdf3e9..9fafadb 100644 --- a/drivers/i2c/chips/isp1301_omap.c +++ b/drivers/i2c/chips/isp1301_omap.c @@ -27,7 +27,7 @@ #include #include #include #include -#include +#include #include #include #include diff --git a/drivers/i2c/chips/tps65010.c b/drivers/i2c/chips/tps65010.c index 4ee56de..214fbb1 100644 --- a/drivers/i2c/chips/tps65010.c +++ b/drivers/i2c/chips/tps65010.c @@ -308,7 +308,7 @@ static int dbg_tps_open(struct inode *in return single_open(file, dbg_show, inode->i_private); } -static struct file_operations debug_fops = { +static const struct file_operations debug_fops = { .open = dbg_tps_open, .read = seq_read, .llseek = seq_lseek, diff --git a/drivers/i2c/i2c-core.c b/drivers/i2c/i2c-core.c index b05378a..21fe140 100644 --- a/drivers/i2c/i2c-core.c +++ b/drivers/i2c/i2c-core.c @@ -32,6 +32,7 @@ #include #include #include #include +#include #include @@ -40,49 +41,72 @@ static LIST_HEAD(drivers); static DEFINE_MUTEX(core_lists); static DEFINE_IDR(i2c_adapter_idr); + +/* ------------------------------------------------------------------------- */ + /* match always succeeds, as we want the probe() to tell if we really accept this match */ static int i2c_device_match(struct device *dev, struct device_driver *drv) { return 1; } -static int i2c_bus_suspend(struct device * dev, pm_message_t state) +static int i2c_device_probe(struct device *dev) { - int rc = 0; + return -ENODEV; +} - if (dev->driver && dev->driver->suspend) - rc = dev->driver->suspend(dev, state); - return rc; +static int i2c_device_remove(struct device *dev) +{ + return 0; } -static int i2c_bus_resume(struct device * dev) +static void i2c_device_shutdown(struct device *dev) { - int rc = 0; - - if (dev->driver && dev->driver->resume) - rc = dev->driver->resume(dev); - return rc; + struct i2c_driver *driver; + + if (!dev->driver) + return; + driver = to_i2c_driver(dev->driver); + if (driver->shutdown) + driver->shutdown(to_i2c_client(dev)); } -static int i2c_device_probe(struct device *dev) +static int i2c_device_suspend(struct device * dev, pm_message_t mesg) { - return -ENODEV; + struct i2c_driver *driver; + + if (!dev->driver) + return 0; + driver = to_i2c_driver(dev->driver); + if (!driver->suspend) + return 0; + return driver->suspend(to_i2c_client(dev), mesg); } -static int i2c_device_remove(struct device *dev) +static int i2c_device_resume(struct device * dev) { - return 0; + struct i2c_driver *driver; + + if (!dev->driver) + return 0; + driver = to_i2c_driver(dev->driver); + if (!driver->resume) + return 0; + return driver->resume(to_i2c_client(dev)); } struct bus_type i2c_bus_type = { - .name = "i2c", - .match = i2c_device_match, - .probe = i2c_device_probe, - .remove = i2c_device_remove, - .suspend = i2c_bus_suspend, - .resume = i2c_bus_resume, + .name = "i2c", + .match = i2c_device_match, + .probe = i2c_device_probe, + .remove = i2c_device_remove, + .shutdown = i2c_device_shutdown, + .suspend = i2c_device_suspend, + .resume = i2c_device_resume, }; +/* ------------------------------------------------------------------------- */ + void i2c_adapter_dev_release(struct device *dev) { struct i2c_adapter *adap = dev_to_i2c_adapter(dev); @@ -193,9 +217,8 @@ int i2c_add_adapter(struct i2c_adapter * */ if (adap->dev.parent == NULL) { adap->dev.parent = &platform_bus; - printk(KERN_WARNING "**WARNING** I2C adapter driver [%s] " - "forgot to specify physical device; fix it!\n", - adap->name); + pr_debug("I2C adapter driver [%s] forgot to specify " + "physical device\n", adap->name); } sprintf(adap->dev.bus_id, "i2c-%d", adap->nr); adap->dev.driver = &i2c_adapter_driver; diff --git a/drivers/i2c/i2c-dev.c b/drivers/i2c/i2c-dev.c index ac5bd2a..cb4fa9b 100644 --- a/drivers/i2c/i2c-dev.c +++ b/drivers/i2c/i2c-dev.c @@ -392,7 +392,7 @@ static int i2cdev_release(struct inode * return 0; } -static struct file_operations i2cdev_fops = { +static const struct file_operations i2cdev_fops = { .owner = THIS_MODULE, .llseek = no_llseek, .read = i2cdev_read, diff --git a/drivers/ide/Kconfig b/drivers/ide/Kconfig index 3f82805..ec03341 100644 --- a/drivers/ide/Kconfig +++ b/drivers/ide/Kconfig @@ -167,6 +167,13 @@ config BLK_DEV_IDECS Support for Compact Flash cards, outboard IDE disks, tape drives, and CD-ROM drives connected through a PCMCIA card. +config BLK_DEV_DELKIN + tristate "Cardbus IDE support (Delkin/ASKA/Workbit)" + depends on CARDBUS && PCI + help + Support for Delkin, ASKA, and Workbit Cardbus CompactFlash + Adapters. This may also work for similar SD and XD adapters. + config BLK_DEV_IDECD tristate "Include IDE/ATAPI CDROM support" ---help--- @@ -264,6 +271,13 @@ config BLK_DEV_IDESCSI If both this SCSI emulation and native ATAPI support are compiled into the kernel, the native support will be used. +config BLK_DEV_IDEACPI + bool "IDE ACPI support" + depends on ACPI + ---help--- + Implement ACPI support for generic IDE devices. On modern + machines ACPI support is required to properly handle ACPI S3 states. + config IDE_TASK_IOCTL bool "IDE Taskfile Access" help @@ -606,6 +620,11 @@ config BLK_DEV_PIIX the kernel to change PIO, DMA and UDMA speeds and to configure the chip to optimum performance. +config BLK_DEV_IT8213 + tristate "IT8213 IDE support" + help + This driver adds support for the ITE 8213 IDE controller. + config BLK_DEV_IT821X tristate "IT821X IDE support" help @@ -742,6 +761,11 @@ config BLK_DEV_VIA82CXXX This allows the kernel to change PIO, DMA and UDMA speeds and to configure the chip to optimum performance. +config BLK_DEV_TC86C001 + tristate "Toshiba TC86C001 support" + help + This driver adds support for Toshiba TC86C001 GOKU-S chip. + endif config BLK_DEV_IDE_PMAC diff --git a/drivers/ide/Makefile b/drivers/ide/Makefile index 569fae7..d9f029e 100644 --- a/drivers/ide/Makefile +++ b/drivers/ide/Makefile @@ -22,6 +22,7 @@ ide-core-$(CONFIG_BLK_DEV_IDEPCI) += set ide-core-$(CONFIG_BLK_DEV_IDEDMA) += ide-dma.o ide-core-$(CONFIG_PROC_FS) += ide-proc.o ide-core-$(CONFIG_BLK_DEV_IDEPNP) += ide-pnp.o +ide-core-$(CONFIG_BLK_DEV_IDEACPI) += ide-acpi.o # built-in only drivers from arm/ ide-core-$(CONFIG_IDE_ARM) += arm/ide_arm.o diff --git a/drivers/ide/ide-acpi.c b/drivers/ide/ide-acpi.c new file mode 100644 index 0000000..17aea65 --- /dev/null +++ b/drivers/ide/ide-acpi.c @@ -0,0 +1,697 @@ +/* + * ide-acpi.c + * Provides ACPI support for IDE drives. + * + * Copyright (C) 2005 Intel Corp. + * Copyright (C) 2005 Randy Dunlap + * Copyright (C) 2006 SUSE Linux Products GmbH + * Copyright (C) 2006 Hannes Reinecke + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#define REGS_PER_GTF 7 +struct taskfile_array { + u8 tfa[REGS_PER_GTF]; /* regs. 0x1f1 - 0x1f7 */ +}; + +struct GTM_buffer { + u32 PIO_speed0; + u32 DMA_speed0; + u32 PIO_speed1; + u32 DMA_speed1; + u32 GTM_flags; +}; + +struct ide_acpi_drive_link { + ide_drive_t *drive; + acpi_handle obj_handle; + u8 idbuff[512]; +}; + +struct ide_acpi_hwif_link { + ide_hwif_t *hwif; + acpi_handle obj_handle; + struct GTM_buffer gtm; + struct ide_acpi_drive_link master; + struct ide_acpi_drive_link slave; +}; + +#undef DEBUGGING +/* note: adds function name and KERN_DEBUG */ +#ifdef DEBUGGING +#define DEBPRINT(fmt, args...) \ + printk(KERN_DEBUG "%s: " fmt, __FUNCTION__, ## args) +#else +#define DEBPRINT(fmt, args...) do {} while (0) +#endif /* DEBUGGING */ + +extern int ide_noacpi; +extern int ide_noacpitfs; +extern int ide_noacpionboot; + +/** + * ide_get_dev_handle - finds acpi_handle and PCI device.function + * @dev: device to locate + * @handle: returned acpi_handle for @dev + * @pcidevfn: return PCI device.func for @dev + * + * Returns the ACPI object handle to the corresponding PCI device. + * + * Returns 0 on success, <0 on error. + */ +static int ide_get_dev_handle(struct device *dev, acpi_handle *handle, + acpi_integer *pcidevfn) +{ + struct pci_dev *pdev = to_pci_dev(dev); + unsigned int bus, devnum, func; + acpi_integer addr; + acpi_handle dev_handle; + struct acpi_buffer buffer = {.length = ACPI_ALLOCATE_BUFFER, + .pointer = NULL}; + acpi_status status; + struct acpi_device_info *dinfo = NULL; + int ret = -ENODEV; + + bus = pdev->bus->number; + devnum = PCI_SLOT(pdev->devfn); + func = PCI_FUNC(pdev->devfn); + /* ACPI _ADR encoding for PCI bus: */ + addr = (acpi_integer)(devnum << 16 | func); + + DEBPRINT("ENTER: pci %02x:%02x.%01x\n", bus, devnum, func); + + dev_handle = DEVICE_ACPI_HANDLE(dev); + if (!dev_handle) { + DEBPRINT("no acpi handle for device\n"); + goto err; + } + + status = acpi_get_object_info(dev_handle, &buffer); + if (ACPI_FAILURE(status)) { + DEBPRINT("get_object_info for device failed\n"); + goto err; + } + dinfo = buffer.pointer; + if (dinfo && (dinfo->valid & ACPI_VALID_ADR) && + dinfo->address == addr) { + *pcidevfn = addr; + *handle = dev_handle; + } else { + DEBPRINT("get_object_info for device has wrong " + " address: %llu, should be %u\n", + dinfo ? (unsigned long long)dinfo->address : -1ULL, + (unsigned int)addr); + goto err; + } + + DEBPRINT("for dev=0x%x.%x, addr=0x%llx, *handle=0x%p\n", + devnum, func, (unsigned long long)addr, *handle); + ret = 0; +err: + kfree(dinfo); + return ret; +} + +/** + * ide_acpi_hwif_get_handle - Get ACPI object handle for a given hwif + * @hwif: device to locate + * + * Retrieves the object handle for a given hwif. + * + * Returns handle on success, 0 on error. + */ +static acpi_handle ide_acpi_hwif_get_handle(ide_hwif_t *hwif) +{ + struct device *dev = hwif->gendev.parent; + acpi_handle dev_handle; + acpi_integer pcidevfn; + acpi_handle chan_handle; + int err; + + DEBPRINT("ENTER: device %s\n", hwif->name); + + if (!dev) { + DEBPRINT("no PCI device for %s\n", hwif->name); + return NULL; + } + + err = ide_get_dev_handle(dev, &dev_handle, &pcidevfn); + if (err < 0) { + DEBPRINT("ide_get_dev_handle failed (%d)\n", err); + return NULL; + } + + /* get child objects of dev_handle == channel objects, + * + _their_ children == drive objects */ + /* channel is hwif->channel */ + chan_handle = acpi_get_child(dev_handle, hwif->channel); + DEBPRINT("chan adr=%d: handle=0x%p\n", + hwif->channel, chan_handle); + + return chan_handle; +} + +/** + * ide_acpi_drive_get_handle - Get ACPI object handle for a given drive + * @drive: device to locate + * + * Retrieves the object handle of a given drive. According to the ACPI + * spec the drive is a child of the hwif. + * + * Returns handle on success, 0 on error. + */ +static acpi_handle ide_acpi_drive_get_handle(ide_drive_t *drive) +{ + ide_hwif_t *hwif = HWIF(drive); + int port; + acpi_handle drive_handle; + + if (!hwif->acpidata) + return NULL; + + if (!hwif->acpidata->obj_handle) + return NULL; + + port = hwif->channel ? drive->dn - 2: drive->dn; + + DEBPRINT("ENTER: %s at channel#: %d port#: %d\n", + drive->name, hwif->channel, port); + + + /* TBD: could also check ACPI object VALID bits */ + drive_handle = acpi_get_child(hwif->acpidata->obj_handle, port); + DEBPRINT("drive %s handle 0x%p\n", drive->name, drive_handle); + + return drive_handle; +} + +/** + * do_drive_get_GTF - get the drive bootup default taskfile settings + * @drive: the drive for which the taskfile settings should be retrieved + * @gtf_length: number of bytes of _GTF data returned at @gtf_address + * @gtf_address: buffer containing _GTF taskfile arrays + * + * The _GTF method has no input parameters. + * It returns a variable number of register set values (registers + * hex 1F1..1F7, taskfiles). + * The is not known in advance, so have ACPI-CA + * allocate the buffer as needed and return it, then free it later. + * + * The returned @gtf_length and @gtf_address are only valid if the + * function return value is 0. + */ +static int do_drive_get_GTF(ide_drive_t *drive, + unsigned int *gtf_length, unsigned long *gtf_address, + unsigned long *obj_loc) +{ + acpi_status status; + struct acpi_buffer output; + union acpi_object *out_obj; + ide_hwif_t *hwif = HWIF(drive); + struct device *dev = hwif->gendev.parent; + int err = -ENODEV; + int port; + + *gtf_length = 0; + *gtf_address = 0UL; + *obj_loc = 0UL; + + if (ide_noacpi) + return 0; + + if (!dev) { + DEBPRINT("no PCI device for %s\n", hwif->name); + goto out; + } + + if (!hwif->acpidata) { + DEBPRINT("no ACPI data for %s\n", hwif->name); + goto out; + } + + port = hwif->channel ? drive->dn - 2: drive->dn; + + if (!drive->acpidata) { + if (port == 0) { + drive->acpidata = &hwif->acpidata->master; + hwif->acpidata->master.drive = drive; + } else { + drive->acpidata = &hwif->acpidata->slave; + hwif->acpidata->slave.drive = drive; + } + } + + DEBPRINT("ENTER: %s at %s, port#: %d, hard_port#: %d\n", + hwif->name, dev->bus_id, port, hwif->channel); + + if (!drive->present) { + DEBPRINT("%s drive %d:%d not present\n", + hwif->name, hwif->channel, port); + goto out; + } + + /* Get this drive's _ADR info. if not already known. */ + if (!drive->acpidata->obj_handle) { + drive->acpidata->obj_handle = ide_acpi_drive_get_handle(drive); + if (!drive->acpidata->obj_handle) { + DEBPRINT("No ACPI object found for %s\n", + drive->name); + goto out; + } + } + + /* Setting up output buffer */ + output.length = ACPI_ALLOCATE_BUFFER; + output.pointer = NULL; /* ACPI-CA sets this; save/free it later */ + + /* _GTF has no input parameters */ + err = -EIO; + status = acpi_evaluate_object(drive->acpidata->obj_handle, "_GTF", + NULL, &output); + if (ACPI_FAILURE(status)) { + printk(KERN_DEBUG + "%s: Run _GTF error: status = 0x%x\n", + __FUNCTION__, status); + goto out; + } + + if (!output.length || !output.pointer) { + DEBPRINT("Run _GTF: " + "length or ptr is NULL (0x%llx, 0x%p)\n", + (unsigned long long)output.length, + output.pointer); + goto out; + } + + out_obj = output.pointer; + if (out_obj->type != ACPI_TYPE_BUFFER) { + DEBPRINT("Run _GTF: error: " + "expected object type of ACPI_TYPE_BUFFER, " + "got 0x%x\n", out_obj->type); + err = -ENOENT; + kfree(output.pointer); + goto out; + } + + if (!out_obj->buffer.length || !out_obj->buffer.pointer || + out_obj->buffer.length % REGS_PER_GTF) { + printk(KERN_ERR + "%s: unexpected GTF length (%d) or addr (0x%p)\n", + __FUNCTION__, out_obj->buffer.length, + out_obj->buffer.pointer); + err = -ENOENT; + kfree(output.pointer); + goto out; + } + + *gtf_length = out_obj->buffer.length; + *gtf_address = (unsigned long)out_obj->buffer.pointer; + *obj_loc = (unsigned long)out_obj; + DEBPRINT("returning gtf_length=%d, gtf_address=0x%lx, obj_loc=0x%lx\n", + *gtf_length, *gtf_address, *obj_loc); + err = 0; +out: + return err; +} + +/** + * taskfile_load_raw - send taskfile registers to drive + * @drive: drive to which output is sent + * @gtf: raw ATA taskfile register set (0x1f1 - 0x1f7) + * + * Outputs IDE taskfile to the drive. + */ +static int taskfile_load_raw(ide_drive_t *drive, + const struct taskfile_array *gtf) +{ + ide_task_t args; + int err = 0; + + DEBPRINT("(0x1f1-1f7): hex: " + "%02x %02x %02x %02x %02x %02x %02x\n", + gtf->tfa[0], gtf->tfa[1], gtf->tfa[2], + gtf->tfa[3], gtf->tfa[4], gtf->tfa[5], gtf->tfa[6]); + + memset(&args, 0, sizeof(ide_task_t)); + args.command_type = IDE_DRIVE_TASK_NO_DATA; + args.data_phase = TASKFILE_IN; + args.handler = &task_no_data_intr; + + /* convert gtf to IDE Taskfile */ + args.tfRegister[1] = gtf->tfa[0]; /* 0x1f1 */ + args.tfRegister[2] = gtf->tfa[1]; /* 0x1f2 */ + args.tfRegister[3] = gtf->tfa[2]; /* 0x1f3 */ + args.tfRegister[4] = gtf->tfa[3]; /* 0x1f4 */ + args.tfRegister[5] = gtf->tfa[4]; /* 0x1f5 */ + args.tfRegister[6] = gtf->tfa[5]; /* 0x1f6 */ + args.tfRegister[7] = gtf->tfa[6]; /* 0x1f7 */ + + if (ide_noacpitfs) { + DEBPRINT("_GTF execution disabled\n"); + return err; + } + + err = ide_raw_taskfile(drive, &args, NULL); + if (err) + printk(KERN_ERR "%s: ide_raw_taskfile failed: %u\n", + __FUNCTION__, err); + + return err; +} + +/** + * do_drive_set_taskfiles - write the drive taskfile settings from _GTF + * @drive: the drive to which the taskfile command should be sent + * @gtf_length: total number of bytes of _GTF taskfiles + * @gtf_address: location of _GTF taskfile arrays + * + * Write {gtf_address, length gtf_length} in groups of + * REGS_PER_GTF bytes. + */ +static int do_drive_set_taskfiles(ide_drive_t *drive, + unsigned int gtf_length, + unsigned long gtf_address) +{ + int rc = -ENODEV, err; + int gtf_count = gtf_length / REGS_PER_GTF; + int ix; + struct taskfile_array *gtf; + + if (ide_noacpi) + return 0; + + DEBPRINT("ENTER: %s, hard_port#: %d\n", drive->name, drive->dn); + + if (!drive->present) + goto out; + if (!gtf_count) /* shouldn't be here */ + goto out; + + DEBPRINT("total GTF bytes=%u (0x%x), gtf_count=%d, addr=0x%lx\n", + gtf_length, gtf_length, gtf_count, gtf_address); + + if (gtf_length % REGS_PER_GTF) { + printk(KERN_ERR "%s: unexpected GTF length (%d)\n", + __FUNCTION__, gtf_length); + goto out; + } + + rc = 0; + for (ix = 0; ix < gtf_count; ix++) { + gtf = (struct taskfile_array *) + (gtf_address + ix * REGS_PER_GTF); + + /* send all TaskFile registers (0x1f1-0x1f7) *in*that*order* */ + err = taskfile_load_raw(drive, gtf); + if (err) + rc = err; + } + +out: + return rc; +} + +/** + * ide_acpi_exec_tfs - get then write drive taskfile settings + * @drive: the drive for which the taskfile settings should be + * written. + * + * According to the ACPI spec this should be called after _STM + * has been evaluated for the interface. Some ACPI vendors interpret + * that as a hard requirement and modify the taskfile according + * to the Identify Drive information passed down with _STM. + * So one should really make sure to call this only after _STM has + * been executed. + */ +int ide_acpi_exec_tfs(ide_drive_t *drive) +{ + int ret; + unsigned int gtf_length; + unsigned long gtf_address; + unsigned long obj_loc; + + if (ide_noacpi) + return 0; + + DEBPRINT("call get_GTF, drive=%s port=%d\n", drive->name, drive->dn); + + ret = do_drive_get_GTF(drive, >f_length, >f_address, &obj_loc); + if (ret < 0) { + DEBPRINT("get_GTF error (%d)\n", ret); + return ret; + } + + DEBPRINT("call set_taskfiles, drive=%s\n", drive->name); + + ret = do_drive_set_taskfiles(drive, gtf_length, gtf_address); + kfree((void *)obj_loc); + if (ret < 0) { + DEBPRINT("set_taskfiles error (%d)\n", ret); + } + + DEBPRINT("ret=%d\n", ret); + + return ret; +} +EXPORT_SYMBOL_GPL(ide_acpi_exec_tfs); + +/** + * ide_acpi_get_timing - get the channel (controller) timings + * @hwif: target IDE interface (channel) + * + * This function executes the _GTM ACPI method for the target channel. + * + */ +void ide_acpi_get_timing(ide_hwif_t *hwif) +{ + acpi_status status; + struct acpi_buffer output; + union acpi_object *out_obj; + + if (ide_noacpi) + return; + + DEBPRINT("ENTER:\n"); + + if (!hwif->acpidata) { + DEBPRINT("no ACPI data for %s\n", hwif->name); + return; + } + + /* Setting up output buffer for _GTM */ + output.length = ACPI_ALLOCATE_BUFFER; + output.pointer = NULL; /* ACPI-CA sets this; save/free it later */ + + /* _GTM has no input parameters */ + status = acpi_evaluate_object(hwif->acpidata->obj_handle, "_GTM", + NULL, &output); + + DEBPRINT("_GTM status: %d, outptr: 0x%p, outlen: 0x%llx\n", + status, output.pointer, + (unsigned long long)output.length); + + if (ACPI_FAILURE(status)) { + DEBPRINT("Run _GTM error: status = 0x%x\n", status); + return; + } + + if (!output.length || !output.pointer) { + DEBPRINT("Run _GTM: length or ptr is NULL (0x%llx, 0x%p)\n", + (unsigned long long)output.length, + output.pointer); + kfree(output.pointer); + return; + } + + out_obj = output.pointer; + if (out_obj->type != ACPI_TYPE_BUFFER) { + kfree(output.pointer); + DEBPRINT("Run _GTM: error: " + "expected object type of ACPI_TYPE_BUFFER, " + "got 0x%x\n", out_obj->type); + return; + } + + if (!out_obj->buffer.length || !out_obj->buffer.pointer || + out_obj->buffer.length != sizeof(struct GTM_buffer)) { + kfree(output.pointer); + printk(KERN_ERR + "%s: unexpected _GTM length (0x%x)[should be 0x%zx] or " + "addr (0x%p)\n", + __FUNCTION__, out_obj->buffer.length, + sizeof(struct GTM_buffer), out_obj->buffer.pointer); + return; + } + + memcpy(&hwif->acpidata->gtm, out_obj->buffer.pointer, + sizeof(struct GTM_buffer)); + + DEBPRINT("_GTM info: ptr: 0x%p, len: 0x%x, exp.len: 0x%Zx\n", + out_obj->buffer.pointer, out_obj->buffer.length, + sizeof(struct GTM_buffer)); + + DEBPRINT("_GTM fields: 0x%x, 0x%x, 0x%x, 0x%x, 0x%x\n", + hwif->acpidata->gtm.PIO_speed0, + hwif->acpidata->gtm.DMA_speed0, + hwif->acpidata->gtm.PIO_speed1, + hwif->acpidata->gtm.DMA_speed1, + hwif->acpidata->gtm.GTM_flags); + + kfree(output.pointer); +} +EXPORT_SYMBOL_GPL(ide_acpi_get_timing); + +/** + * ide_acpi_push_timing - set the channel (controller) timings + * @hwif: target IDE interface (channel) + * + * This function executes the _STM ACPI method for the target channel. + * + * _STM requires Identify Drive data, which has to passed as an argument. + * Unfortunately hd_driveid is a mangled version which we can't readily + * use; hence we'll get the information afresh. + */ +void ide_acpi_push_timing(ide_hwif_t *hwif) +{ + acpi_status status; + struct acpi_object_list input; + union acpi_object in_params[3]; + struct ide_acpi_drive_link *master = &hwif->acpidata->master; + struct ide_acpi_drive_link *slave = &hwif->acpidata->slave; + + if (ide_noacpi) + return; + + DEBPRINT("ENTER:\n"); + + if (!hwif->acpidata) { + DEBPRINT("no ACPI data for %s\n", hwif->name); + return; + } + + /* Give the GTM buffer + drive Identify data to the channel via the + * _STM method: */ + /* setup input parameters buffer for _STM */ + input.count = 3; + input.pointer = in_params; + in_params[0].type = ACPI_TYPE_BUFFER; + in_params[0].buffer.length = sizeof(struct GTM_buffer); + in_params[0].buffer.pointer = (u8 *)&hwif->acpidata->gtm; + in_params[1].type = ACPI_TYPE_BUFFER; + in_params[1].buffer.length = sizeof(struct hd_driveid); + in_params[1].buffer.pointer = (u8 *)&master->idbuff; + in_params[2].type = ACPI_TYPE_BUFFER; + in_params[2].buffer.length = sizeof(struct hd_driveid); + in_params[2].buffer.pointer = (u8 *)&slave->idbuff; + /* Output buffer: _STM has no output */ + + status = acpi_evaluate_object(hwif->acpidata->obj_handle, "_STM", + &input, NULL); + + if (ACPI_FAILURE(status)) { + DEBPRINT("Run _STM error: status = 0x%x\n", status); + } + DEBPRINT("_STM status: %d\n", status); +} +EXPORT_SYMBOL_GPL(ide_acpi_push_timing); + +/** + * ide_acpi_init - initialize the ACPI link for an IDE interface + * @hwif: target IDE interface (channel) + * + * The ACPI spec is not quite clear when the drive identify buffer + * should be obtained. Calling IDENTIFY DEVICE during shutdown + * is not the best of ideas as the drive might already being put to + * sleep. And obviously we can't call it during resume. + * So we get the information during startup; but this means that + * any changes during run-time will be lost after resume. + */ +void ide_acpi_init(ide_hwif_t *hwif) +{ + int unit; + int err; + struct ide_acpi_drive_link *master; + struct ide_acpi_drive_link *slave; + + hwif->acpidata = kzalloc(sizeof(struct ide_acpi_hwif_link), GFP_KERNEL); + if (!hwif->acpidata) + return; + + hwif->acpidata->obj_handle = ide_acpi_hwif_get_handle(hwif); + if (!hwif->acpidata->obj_handle) { + DEBPRINT("no ACPI object for %s found\n", hwif->name); + kfree(hwif->acpidata); + hwif->acpidata = NULL; + return; + } + + /* + * The ACPI spec mandates that we send information + * for both drives, regardless whether they are connected + * or not. + */ + hwif->acpidata->master.drive = &hwif->drives[0]; + hwif->drives[0].acpidata = &hwif->acpidata->master; + master = &hwif->acpidata->master; + + hwif->acpidata->slave.drive = &hwif->drives[1]; + hwif->drives[1].acpidata = &hwif->acpidata->slave; + slave = &hwif->acpidata->slave; + + + /* + * Send IDENTIFY for each drive + */ + if (master->drive->present) { + err = taskfile_lib_get_identify(master->drive, master->idbuff); + if (err) { + DEBPRINT("identify device %s failed (%d)\n", + master->drive->name, err); + } + } + + if (slave->drive->present) { + err = taskfile_lib_get_identify(slave->drive, slave->idbuff); + if (err) { + DEBPRINT("identify device %s failed (%d)\n", + slave->drive->name, err); + } + } + + if (ide_noacpionboot) { + DEBPRINT("ACPI methods disabled on boot\n"); + return; + } + + /* + * ACPI requires us to call _STM on startup + */ + ide_acpi_get_timing(hwif); + ide_acpi_push_timing(hwif); + + for (unit = 0; unit < MAX_DRIVES; ++unit) { + ide_drive_t *drive = &hwif->drives[unit]; + + if (drive->present) { + /* Execute ACPI startup code */ + ide_acpi_exec_tfs(drive); + } + } +} +EXPORT_SYMBOL_GPL(ide_acpi_init); diff --git a/drivers/ide/ide-probe.c b/drivers/ide/ide-probe.c index 5a5c565..176bbc8 100644 --- a/drivers/ide/ide-probe.c +++ b/drivers/ide/ide-probe.c @@ -1384,6 +1384,9 @@ #endif /* CONFIG_BLK_DEV_HD */ done: init_gendisk(hwif); + + ide_acpi_init(hwif); + hwif->present = 1; /* success */ return 1; diff --git a/drivers/ide/ide-proc.c b/drivers/ide/ide-proc.c index aa049da..afb71c6 100644 --- a/drivers/ide/ide-proc.c +++ b/drivers/ide/ide-proc.c @@ -26,7 +26,6 @@ #include #include #include -#include #include #include #include @@ -413,7 +412,6 @@ void ide_add_proc_entries(struct proc_di while (p->name != NULL) { ent = create_proc_entry(p->name, p->mode, dir); if (!ent) return; - ent->nlink = 1; ent->data = data; ent->read_proc = p->read_proc; ent->write_proc = p->write_proc; @@ -549,7 +547,7 @@ static int ide_drivers_open(struct inode return single_open(file, &ide_drivers_show, NULL); } -static struct file_operations ide_drivers_operations = { +static const struct file_operations ide_drivers_operations = { .open = ide_drivers_open, .read = seq_read, .llseek = seq_lseek, diff --git a/drivers/ide/ide-tape.c b/drivers/ide/ide-tape.c index b3bcd1d..c6eec04 100644 --- a/drivers/ide/ide-tape.c +++ b/drivers/ide/ide-tape.c @@ -4779,7 +4779,7 @@ static ide_driver_t idetape_driver = { /* * Our character device supporting functions, passed to register_chrdev. */ -static struct file_operations idetape_fops = { +static const struct file_operations idetape_fops = { .owner = THIS_MODULE, .read = idetape_chrdev_read, .write = idetape_chrdev_write, diff --git a/drivers/ide/ide.c b/drivers/ide/ide.c index 6c9bd51..c750f6c 100644 --- a/drivers/ide/ide.c +++ b/drivers/ide/ide.c @@ -187,6 +187,12 @@ #endif EXPORT_SYMBOL(noautodma); +#ifdef CONFIG_BLK_DEV_IDEACPI +int ide_noacpi = 0; +int ide_noacpitfs = 1; +int ide_noacpionboot = 1; +#endif + /* * This is declared extern in ide.h, for access by other IDE modules: */ @@ -1214,10 +1220,15 @@ EXPORT_SYMBOL(system_bus_clock); static int generic_ide_suspend(struct device *dev, pm_message_t mesg) { ide_drive_t *drive = dev->driver_data; + ide_hwif_t *hwif = HWIF(drive); struct request rq; struct request_pm_state rqpm; ide_task_t args; + /* Call ACPI _GTM only once */ + if (!(drive->dn % 2)) + ide_acpi_get_timing(hwif); + memset(&rq, 0, sizeof(rq)); memset(&rqpm, 0, sizeof(rqpm)); memset(&args, 0, sizeof(args)); @@ -1235,10 +1246,17 @@ static int generic_ide_suspend(struct de static int generic_ide_resume(struct device *dev) { ide_drive_t *drive = dev->driver_data; + ide_hwif_t *hwif = HWIF(drive); struct request rq; struct request_pm_state rqpm; ide_task_t args; + /* Call ACPI _STM only once */ + if (!(drive->dn % 2)) + ide_acpi_push_timing(hwif); + + ide_acpi_exec_tfs(drive); + memset(&rq, 0, sizeof(rq)); memset(&rqpm, 0, sizeof(rqpm)); memset(&args, 0, sizeof(args)); @@ -1543,6 +1561,24 @@ #ifdef CONFIG_BLK_DEV_IDEPCI } #endif /* CONFIG_BLK_DEV_IDEPCI */ +#ifdef CONFIG_BLK_DEV_IDEACPI + if (!strcmp(s, "ide=noacpi")) { + //printk(" : Disable IDE ACPI support.\n"); + ide_noacpi = 1; + return 1; + } + if (!strcmp(s, "ide=acpigtf")) { + //printk(" : Enable IDE ACPI _GTF support.\n"); + ide_noacpitfs = 0; + return 1; + } + if (!strcmp(s, "ide=acpionboot")) { + //printk(" : Call IDE ACPI methods on boot.\n"); + ide_noacpionboot = 0; + return 1; + } +#endif /* CONFIG_BLK_DEV_IDEACPI */ + /* * Look for drive options: "hdx=" */ diff --git a/drivers/ide/legacy/ide-cs.c b/drivers/ide/legacy/ide-cs.c index 7efd28a..a5023cd 100644 --- a/drivers/ide/legacy/ide-cs.c +++ b/drivers/ide/legacy/ide-cs.c @@ -34,7 +34,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/ide/pci/Makefile b/drivers/ide/pci/Makefile index fef0896..6591ff4 100644 --- a/drivers/ide/pci/Makefile +++ b/drivers/ide/pci/Makefile @@ -9,9 +9,10 @@ obj-$(CONFIG_BLK_DEV_CS5530) += cs5530. obj-$(CONFIG_BLK_DEV_CS5535) += cs5535.o obj-$(CONFIG_BLK_DEV_SC1200) += sc1200.o obj-$(CONFIG_BLK_DEV_CY82C693) += cy82c693.o +obj-$(CONFIG_BLK_DEV_DELKIN) += delkin_cb.o obj-$(CONFIG_BLK_DEV_HPT34X) += hpt34x.o obj-$(CONFIG_BLK_DEV_HPT366) += hpt366.o -#obj-$(CONFIG_BLK_DEV_HPT37X) += hpt37x.o +obj-$(CONFIG_BLK_DEV_IT8213) += it8213.o obj-$(CONFIG_BLK_DEV_IT821X) += it821x.o obj-$(CONFIG_BLK_DEV_JMICRON) += jmicron.o obj-$(CONFIG_BLK_DEV_NS87415) += ns87415.o @@ -26,6 +27,7 @@ obj-$(CONFIG_BLK_DEV_SIIMAGE) += siimag obj-$(CONFIG_BLK_DEV_SIS5513) += sis5513.o obj-$(CONFIG_BLK_DEV_SL82C105) += sl82c105.o obj-$(CONFIG_BLK_DEV_SLC90E66) += slc90e66.o +obj-$(CONFIG_BLK_DEV_TC86C001) += tc86c001.o obj-$(CONFIG_BLK_DEV_TRIFLEX) += triflex.o obj-$(CONFIG_BLK_DEV_TRM290) += trm290.o obj-$(CONFIG_BLK_DEV_VIA82CXXX) += via82cxxx.o diff --git a/drivers/ide/pci/delkin_cb.c b/drivers/ide/pci/delkin_cb.c new file mode 100644 index 0000000..e2672fc --- /dev/null +++ b/drivers/ide/pci/delkin_cb.c @@ -0,0 +1,140 @@ +/* + * linux/drivers/ide/pci/delkin_cb.c + * + * Created 20 Oct 2004 by Mark Lord + * + * Basic support for Delkin/ASKA/Workbit Cardbus CompactFlash adapter + * + * Modeled after the 16-bit PCMCIA driver: ide-cs.c + * + * This is slightly peculiar, in that it is a PCI driver, + * but is NOT an IDE PCI driver -- the IDE layer does not directly + * support hot insertion/removal of PCI interfaces, so this driver + * is unable to use the IDE PCI interfaces. Instead, it uses the + * same interfaces as the ide-cs (PCMCIA) driver uses. + * On the plus side, the driver is also smaller/simpler this way. + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file COPYING in the main directory of this archive for + * more details. + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* + * No chip documentation has yet been found, + * so these configuration values were pulled from + * a running Win98 system using "debug". + * This gives around 3MByte/second read performance, + * which is about 2/3 of what the chip is capable of. + * + * There is also a 4KByte mmio region on the card, + * but its purpose has yet to be reverse-engineered. + */ +static const u8 setup[] = { + 0x00, 0x05, 0xbe, 0x01, 0x20, 0x8f, 0x00, 0x00, + 0xa4, 0x1f, 0xb3, 0x1b, 0x00, 0x00, 0x00, 0x80, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xa4, 0x83, 0x02, 0x13, +}; + +static int __devinit +delkin_cb_probe (struct pci_dev *dev, const struct pci_device_id *id) +{ + unsigned long base; + hw_regs_t hw; + ide_hwif_t *hwif = NULL; + ide_drive_t *drive; + int i, rc; + + rc = pci_enable_device(dev); + if (rc) { + printk(KERN_ERR "delkin_cb: pci_enable_device failed (%d)\n", rc); + return rc; + } + rc = pci_request_regions(dev, "delkin_cb"); + if (rc) { + printk(KERN_ERR "delkin_cb: pci_request_regions failed (%d)\n", rc); + pci_disable_device(dev); + return rc; + } + base = pci_resource_start(dev, 0); + outb(0x02, base + 0x1e); /* set nIEN to block interrupts */ + inb(base + 0x17); /* read status to clear interrupts */ + for (i = 0; i < sizeof(setup); ++i) { + if (setup[i]) + outb(setup[i], base + i); + } + pci_release_regions(dev); /* IDE layer handles regions itself */ + + memset(&hw, 0, sizeof(hw)); + ide_std_init_ports(&hw, base + 0x10, base + 0x1e); + hw.irq = dev->irq; + hw.chipset = ide_pci; /* this enables IRQ sharing */ + + rc = ide_register_hw_with_fixup(&hw, &hwif, ide_undecoded_slave); + if (rc < 0) { + printk(KERN_ERR "delkin_cb: ide_register_hw failed (%d)\n", rc); + pci_disable_device(dev); + return -ENODEV; + } + pci_set_drvdata(dev, hwif); + hwif->pci_dev = dev; + drive = &hwif->drives[0]; + if (drive->present) { + drive->io_32bit = 1; + drive->unmask = 1; + } + return 0; +} + +static void +delkin_cb_remove (struct pci_dev *dev) +{ + ide_hwif_t *hwif = pci_get_drvdata(dev); + + if (hwif) + ide_unregister(hwif->index); + pci_disable_device(dev); +} + +static struct pci_device_id delkin_cb_pci_tbl[] __devinitdata = { + { 0x1145, 0xf021, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, + { 0, }, +}; +MODULE_DEVICE_TABLE(pci, delkin_cb_pci_tbl); + +static struct pci_driver driver = { + .name = "Delkin-ASKA-Workbit Cardbus IDE", + .id_table = delkin_cb_pci_tbl, + .probe = delkin_cb_probe, + .remove = delkin_cb_remove, +}; + +static int +delkin_cb_init (void) +{ + return pci_module_init(&driver); +} + +static void +delkin_cb_exit (void) +{ + pci_unregister_driver(&driver); +} + +module_init(delkin_cb_init); +module_exit(delkin_cb_exit); + +MODULE_AUTHOR("Mark Lord"); +MODULE_DESCRIPTION("Basic support for Delkin/ASKA/Workbit Cardbus IDE"); +MODULE_LICENSE("GPL"); + diff --git a/drivers/ide/pci/hpt366.c b/drivers/ide/pci/hpt366.c index b486442..05be8fa 100644 --- a/drivers/ide/pci/hpt366.c +++ b/drivers/ide/pci/hpt366.c @@ -1,5 +1,5 @@ /* - * linux/drivers/ide/pci/hpt366.c Version 0.36 April 25, 2003 + * linux/drivers/ide/pci/hpt366.c Version 1.01 Dec 23, 2006 * * Copyright (C) 1999-2003 Andre Hedrick * Portions Copyright (C) 2001 Sun Microsystems, Inc. @@ -60,13 +60,10 @@ * channel caused the cached register value to get out of sync with the * actual one, the channels weren't serialized, the turnaround shouldn't * be done on 66 MHz PCI bus - * - avoid calibrating PLL twice as the second time results in a wrong PCI - * frequency and thus in the wrong timings for the secondary channel - * - disable UltraATA/133 for HPT372 by default (50 MHz DPLL clock do not - * allow for this speed anyway) - * - add support for HPT302N and HPT371N clocking (the same as for HPT372N) - * - HPT371/N are single channel chips, so avoid touching the primary channel - * which exists only virtually (there's no pins for it) + * - disable UltraATA/100 for HPT370 by default as the 33 MHz clock being used + * does not allow for this speed anyway + * - avoid touching disabled channels (e.g. HPT371/N are single channel chips, + * their primary channel is kind of virtual, it isn't tied to any pins) * - fix/remove bad/unused timing tables and use one set of tables for the whole * HPT37x chip family; save space by introducing the separate transfer mode * table in which the mode lookup is done @@ -76,11 +73,47 @@ * and for HPT36x the obsolete HDIO_TRISTATE_HWIF handler was called instead * - pass to init_chipset() handlers a copy of the IDE PCI device structure as * they tamper with its fields - * - * + * - pass to the init_setup handlers a copy of the ide_pci_device_t structure + * since they may tamper with its fields + * - prefix the driver startup messages with the real chip name + * - claim the extra 240 bytes of I/O space for all chips + * - optimize the rate masking/filtering and the drive list lookup code + * - use pci_get_slot() to get to the function 1 of HPT36x/374 + * - cache offset of the channel's misc. control registers (MCRs) being used + * throughout the driver + * - only touch the relevant MCR when detecting the cable type on HPT374's + * function 1 + * - rename all the register related variables consistently + * - move all the interrupt twiddling code from the speedproc handlers into + * init_hwif_hpt366(), also grouping all the DMA related code together there + * - merge two HPT37x speedproc handlers, fix the PIO timing register mask and + * separate the UltraDMA and MWDMA masks there to avoid changing PIO timings + * when setting an UltraDMA mode + * - fix hpt3xx_tune_drive() to set the PIO mode requested, not always select + * the best possible one + * - clean up DMA timeout handling for HPT370 + * - switch to using the enumeration type to differ between the numerous chip + * variants, matching PCI device/revision ID with the chip type early, at the + * init_setup stage + * - extend the hpt_info structure to hold the DPLL and PCI clock frequencies, + * stop duplicating it for each channel by storing the pointer in the pci_dev + * structure: first, at the init_setup stage, point it to a static "template" + * with only the chip type and its specific base DPLL frequency, the highest + * supported DMA mode, and the chip settings table pointer filled, then, at + * the init_chipset stage, allocate per-chip instance and fill it with the + * rest of the necessary information + * - get rid of the constant thresholds in the HPT37x PCI clock detection code, + * switch to calculating PCI clock frequency based on the chip's base DPLL + * frequency + * - switch to using the DPLL clock and enable UltraATA/133 mode by default on + * anything newer than HPT370/A + * - fold PCI clock detection and DPLL setup code into init_chipset_hpt366(), + * also fixing the interchanged 25/40 MHz PCI clock cases for HPT36x chips; + * unify HPT36x/37x timing setup code and the speedproc handlers by joining + * the register setting lists into the table indexed by the clock selected + * Sergei Shtylyov, or */ - #include #include #include @@ -332,93 +365,159 @@ static u32 sixty_six_base_hpt37x[] = { }; #define HPT366_DEBUG_DRIVE_INFO 0 -#define HPT374_ALLOW_ATA133_6 0 -#define HPT371_ALLOW_ATA133_6 0 -#define HPT302_ALLOW_ATA133_6 0 -#define HPT372_ALLOW_ATA133_6 0 -#define HPT370_ALLOW_ATA100_5 1 +#define HPT374_ALLOW_ATA133_6 1 +#define HPT371_ALLOW_ATA133_6 1 +#define HPT302_ALLOW_ATA133_6 1 +#define HPT372_ALLOW_ATA133_6 1 +#define HPT370_ALLOW_ATA100_5 0 #define HPT366_ALLOW_ATA66_4 1 #define HPT366_ALLOW_ATA66_3 1 #define HPT366_MAX_DEVS 8 -#define F_LOW_PCI_33 0x23 -#define F_LOW_PCI_40 0x29 -#define F_LOW_PCI_50 0x2d -#define F_LOW_PCI_66 0x42 +/* Supported ATA clock frequencies */ +enum ata_clock { + ATA_CLOCK_25MHZ, + ATA_CLOCK_33MHZ, + ATA_CLOCK_40MHZ, + ATA_CLOCK_50MHZ, + ATA_CLOCK_66MHZ, + NUM_ATA_CLOCKS +}; /* - * Hold all the highpoint quirks and revision information in one - * place. + * Hold all the HighPoint chip information in one place. */ -struct hpt_info -{ +struct hpt_info { + u8 chip_type; /* Chip type */ u8 max_mode; /* Speeds allowed */ - int revision; /* Chipset revision */ - int flags; /* Chipset properties */ -#define PLL_MODE 1 -#define IS_3xxN 2 -#define PCI_66MHZ 4 - /* Speed table */ - u32 *speed; + u8 dpll_clk; /* DPLL clock in MHz */ + u8 pci_clk; /* PCI clock in MHz */ + u32 **settings; /* Chipset settings table */ }; -/* - * This wants fixing so that we do everything not by classrev - * (which breaks on the newest chips) but by creating an - * enumeration of chip variants and using that - */ +/* Supported HighPoint chips */ +enum { + HPT36x, + HPT370, + HPT370A, + HPT374, + HPT372, + HPT372A, + HPT302, + HPT371, + HPT372N, + HPT302N, + HPT371N +}; + +static u32 *hpt36x_settings[NUM_ATA_CLOCKS] = { + twenty_five_base_hpt36x, + thirty_three_base_hpt36x, + forty_base_hpt36x, + NULL, + NULL +}; + +static u32 *hpt37x_settings[NUM_ATA_CLOCKS] = { + NULL, + thirty_three_base_hpt37x, + NULL, + fifty_base_hpt37x, + sixty_six_base_hpt37x +}; + +static struct hpt_info hpt36x __devinitdata = { + .chip_type = HPT36x, + .max_mode = (HPT366_ALLOW_ATA66_4 || HPT366_ALLOW_ATA66_3) ? 2 : 1, + .dpll_clk = 0, /* no DPLL */ + .settings = hpt36x_settings +}; + +static struct hpt_info hpt370 __devinitdata = { + .chip_type = HPT370, + .max_mode = HPT370_ALLOW_ATA100_5 ? 3 : 2, + .dpll_clk = 48, + .settings = hpt37x_settings +}; + +static struct hpt_info hpt370a __devinitdata = { + .chip_type = HPT370A, + .max_mode = HPT370_ALLOW_ATA100_5 ? 3 : 2, + .dpll_clk = 48, + .settings = hpt37x_settings +}; + +static struct hpt_info hpt374 __devinitdata = { + .chip_type = HPT374, + .max_mode = HPT374_ALLOW_ATA133_6 ? 4 : 3, + .dpll_clk = 48, + .settings = hpt37x_settings +}; + +static struct hpt_info hpt372 __devinitdata = { + .chip_type = HPT372, + .max_mode = HPT372_ALLOW_ATA133_6 ? 4 : 3, + .dpll_clk = 55, + .settings = hpt37x_settings +}; + +static struct hpt_info hpt372a __devinitdata = { + .chip_type = HPT372A, + .max_mode = HPT372_ALLOW_ATA133_6 ? 4 : 3, + .dpll_clk = 66, + .settings = hpt37x_settings +}; + +static struct hpt_info hpt302 __devinitdata = { + .chip_type = HPT302, + .max_mode = HPT302_ALLOW_ATA133_6 ? 4 : 3, + .dpll_clk = 66, + .settings = hpt37x_settings +}; + +static struct hpt_info hpt371 __devinitdata = { + .chip_type = HPT371, + .max_mode = HPT371_ALLOW_ATA133_6 ? 4 : 3, + .dpll_clk = 66, + .settings = hpt37x_settings +}; + +static struct hpt_info hpt372n __devinitdata = { + .chip_type = HPT372N, + .max_mode = HPT372_ALLOW_ATA133_6 ? 4 : 3, + .dpll_clk = 77, + .settings = hpt37x_settings +}; + +static struct hpt_info hpt302n __devinitdata = { + .chip_type = HPT302N, + .max_mode = HPT302_ALLOW_ATA133_6 ? 4 : 3, + .dpll_clk = 77, +}; -static __devinit u32 hpt_revision (struct pci_dev *dev) +static struct hpt_info hpt371n __devinitdata = { + .chip_type = HPT371N, + .max_mode = HPT371_ALLOW_ATA133_6 ? 4 : 3, + .dpll_clk = 77, + .settings = hpt37x_settings +}; + +static int check_in_drive_list(ide_drive_t *drive, const char **list) { - u32 class_rev; - pci_read_config_dword(dev, PCI_CLASS_REVISION, &class_rev); - class_rev &= 0xff; - - switch(dev->device) { - /* Remap new 372N onto 372 */ - case PCI_DEVICE_ID_TTI_HPT372N: - class_rev = PCI_DEVICE_ID_TTI_HPT372; break; - case PCI_DEVICE_ID_TTI_HPT374: - class_rev = PCI_DEVICE_ID_TTI_HPT374; break; - case PCI_DEVICE_ID_TTI_HPT371: - class_rev = PCI_DEVICE_ID_TTI_HPT371; break; - case PCI_DEVICE_ID_TTI_HPT302: - class_rev = PCI_DEVICE_ID_TTI_HPT302; break; - case PCI_DEVICE_ID_TTI_HPT372: - class_rev = PCI_DEVICE_ID_TTI_HPT372; break; - default: - break; - } - return class_rev; -} + struct hd_driveid *id = drive->id; -static int check_in_drive_lists(ide_drive_t *drive, const char **list); + while (*list) + if (!strcmp(*list++,id->model)) + return 1; + return 0; +} -static u8 hpt3xx_ratemask (ide_drive_t *drive) +static u8 hpt3xx_ratemask(ide_drive_t *drive) { - ide_hwif_t *hwif = drive->hwif; - struct hpt_info *info = ide_get_hwifdata(hwif); - u8 mode = 0; - - /* FIXME: TODO - move this to set info->mode once at boot */ - - if (info->revision >= 8) { /* HPT374 */ - mode = (HPT374_ALLOW_ATA133_6) ? 4 : 3; - } else if (info->revision >= 7) { /* HPT371 */ - mode = (HPT371_ALLOW_ATA133_6) ? 4 : 3; - } else if (info->revision >= 6) { /* HPT302 */ - mode = (HPT302_ALLOW_ATA133_6) ? 4 : 3; - } else if (info->revision >= 5) { /* HPT372 */ - mode = (HPT372_ALLOW_ATA133_6) ? 4 : 3; - } else if (info->revision >= 4) { /* HPT370A */ - mode = (HPT370_ALLOW_ATA100_5) ? 3 : 2; - } else if (info->revision >= 3) { /* HPT370 */ - mode = (HPT370_ALLOW_ATA100_5) ? 3 : 2; - mode = (check_in_drive_lists(drive, bad_ata33)) ? 0 : mode; - } else { /* HPT366 and HPT368 */ - mode = (check_in_drive_lists(drive, bad_ata33)) ? 0 : 2; - } + struct hpt_info *info = pci_get_drvdata(HWIF(drive)->pci_dev); + u8 mode = info->max_mode; + if (!eighty_ninty_three(drive) && mode) mode = min(mode, (u8)1); return mode; @@ -429,75 +528,61 @@ static u8 hpt3xx_ratemask (ide_drive_t * * either PIO or UDMA modes 0,4,5 */ -static u8 hpt3xx_ratefilter (ide_drive_t *drive, u8 speed) +static u8 hpt3xx_ratefilter(ide_drive_t *drive, u8 speed) { - ide_hwif_t *hwif = drive->hwif; - struct hpt_info *info = ide_get_hwifdata(hwif); + struct hpt_info *info = pci_get_drvdata(HWIF(drive)->pci_dev); + u8 chip_type = info->chip_type; u8 mode = hpt3xx_ratemask(drive); if (drive->media != ide_disk) return min(speed, (u8)XFER_PIO_4); - switch(mode) { + switch (mode) { case 0x04: - speed = min(speed, (u8)XFER_UDMA_6); + speed = min_t(u8, speed, XFER_UDMA_6); break; case 0x03: - speed = min(speed, (u8)XFER_UDMA_5); - if (info->revision >= 5) + speed = min_t(u8, speed, XFER_UDMA_5); + if (chip_type >= HPT374) break; - if (check_in_drive_lists(drive, bad_ata100_5)) - speed = min(speed, (u8)XFER_UDMA_4); - break; + if (!check_in_drive_list(drive, bad_ata100_5)) + goto check_bad_ata33; + /* fall thru */ case 0x02: - speed = min(speed, (u8)XFER_UDMA_4); - /* - * CHECK ME, Does this need to be set to 5 ?? - */ - if (info->revision >= 3) - break; - if ((check_in_drive_lists(drive, bad_ata66_4)) || - (!(HPT366_ALLOW_ATA66_4))) - speed = min(speed, (u8)XFER_UDMA_3); - if ((check_in_drive_lists(drive, bad_ata66_3)) || - (!(HPT366_ALLOW_ATA66_3))) - speed = min(speed, (u8)XFER_UDMA_2); - break; + speed = min_t(u8, speed, XFER_UDMA_4); + + /* + * CHECK ME, Does this need to be changed to HPT374 ?? + */ + if (chip_type >= HPT370) + goto check_bad_ata33; + if (HPT366_ALLOW_ATA66_4 && + !check_in_drive_list(drive, bad_ata66_4)) + goto check_bad_ata33; + + speed = min_t(u8, speed, XFER_UDMA_3); + if (HPT366_ALLOW_ATA66_3 && + !check_in_drive_list(drive, bad_ata66_3)) + goto check_bad_ata33; + /* fall thru */ case 0x01: - speed = min(speed, (u8)XFER_UDMA_2); - /* - * CHECK ME, Does this need to be set to 5 ?? - */ - if (info->revision >= 3) + speed = min_t(u8, speed, XFER_UDMA_2); + + check_bad_ata33: + if (chip_type >= HPT370A) break; - if (check_in_drive_lists(drive, bad_ata33)) - speed = min(speed, (u8)XFER_MW_DMA_2); - break; + if (!check_in_drive_list(drive, bad_ata33)) + break; + /* fall thru */ case 0x00: default: - speed = min(speed, (u8)XFER_MW_DMA_2); + speed = min_t(u8, speed, XFER_MW_DMA_2); break; } return speed; } -static int check_in_drive_lists (ide_drive_t *drive, const char **list) -{ - struct hd_driveid *id = drive->id; - - if (quirk_drives == list) { - while (*list) - if (strstr(id->model, *list++)) - return 1; - } else { - while (*list) - if (!strcmp(*list++,id->model)) - return 1; - } - return 0; -} - -static u32 pci_bus_clock_list(u8 speed, u32 *chipset_table) +static u32 get_speed_setting(u8 speed, struct hpt_info *info) { int i; @@ -510,228 +595,161 @@ static u32 pci_bus_clock_list(u8 speed, for (i = 0; i < ARRAY_SIZE(xfer_speeds) - 1; i++) if (xfer_speeds[i] == speed) break; - return chipset_table[i]; + /* + * NOTE: info->settings only points to the pointer + * to the list of the actual register values + */ + return (*info->settings)[i]; } static int hpt36x_tune_chipset(ide_drive_t *drive, u8 xferspeed) { - ide_hwif_t *hwif = drive->hwif; - struct pci_dev *dev = hwif->pci_dev; - struct hpt_info *info = ide_get_hwifdata(hwif); - u8 speed = hpt3xx_ratefilter(drive, xferspeed); - u8 regtime = (drive->select.b.unit & 0x01) ? 0x44 : 0x40; - u8 regfast = (hwif->channel) ? 0x55 : 0x51; - u8 drive_fast = 0; - u32 reg1 = 0, reg2 = 0; - - /* - * Disable the "fast interrupt" prediction. - */ - pci_read_config_byte(dev, regfast, &drive_fast); - if (drive_fast & 0x80) - pci_write_config_byte(dev, regfast, drive_fast & ~0x80); - - reg2 = pci_bus_clock_list(speed, info->speed); + ide_hwif_t *hwif = HWIF(drive); + struct pci_dev *dev = hwif->pci_dev; + struct hpt_info *info = pci_get_drvdata(dev); + u8 speed = hpt3xx_ratefilter(drive, xferspeed); + u8 itr_addr = drive->dn ? 0x44 : 0x40; + u32 itr_mask = speed < XFER_MW_DMA_0 ? 0x30070000 : + (speed < XFER_UDMA_0 ? 0xc0070000 : 0xc03800ff); + u32 new_itr = get_speed_setting(speed, info); + u32 old_itr = 0; /* - * Disable on-chip PIO FIFO/buffer - * (to avoid problems handling I/O errors later) + * Disable on-chip PIO FIFO/buffer (and PIO MST mode as well) + * to avoid problems handling I/O errors later */ - pci_read_config_dword(dev, regtime, ®1); - if (speed >= XFER_MW_DMA_0) { - reg2 = (reg2 & ~0xc0000000) | (reg1 & 0xc0000000); - } else { - reg2 = (reg2 & ~0x30070000) | (reg1 & 0x30070000); - } - reg2 &= ~0x80000000; + pci_read_config_dword(dev, itr_addr, &old_itr); + new_itr = (new_itr & ~itr_mask) | (old_itr & itr_mask); + new_itr &= ~0xc0000000; - pci_write_config_dword(dev, regtime, reg2); + pci_write_config_dword(dev, itr_addr, new_itr); return ide_config_drive_speed(drive, speed); } -static int hpt370_tune_chipset(ide_drive_t *drive, u8 xferspeed) +static int hpt37x_tune_chipset(ide_drive_t *drive, u8 xferspeed) { - ide_hwif_t *hwif = drive->hwif; - struct pci_dev *dev = hwif->pci_dev; - struct hpt_info *info = ide_get_hwifdata(hwif); - u8 speed = hpt3xx_ratefilter(drive, xferspeed); - u8 regfast = (drive->hwif->channel) ? 0x55 : 0x51; - u8 drive_pci = 0x40 + (drive->dn * 4); - u8 new_fast = 0, drive_fast = 0; - u32 list_conf = 0, drive_conf = 0; - u32 conf_mask = (speed >= XFER_MW_DMA_0) ? 0xc0000000 : 0x30070000; - - /* - * Disable the "fast interrupt" prediction. - * don't holdoff on interrupts. (== 0x01 despite what the docs say) - */ - pci_read_config_byte(dev, regfast, &drive_fast); - new_fast = drive_fast; - if (new_fast & 0x02) - new_fast &= ~0x02; - -#ifdef HPT_DELAY_INTERRUPT - if (new_fast & 0x01) - new_fast &= ~0x01; -#else - if ((new_fast & 0x01) == 0) - new_fast |= 0x01; -#endif - if (new_fast != drive_fast) - pci_write_config_byte(dev, regfast, new_fast); - - list_conf = pci_bus_clock_list(speed, info->speed); - - pci_read_config_dword(dev, drive_pci, &drive_conf); - list_conf = (list_conf & ~conf_mask) | (drive_conf & conf_mask); + ide_hwif_t *hwif = HWIF(drive); + struct pci_dev *dev = hwif->pci_dev; + struct hpt_info *info = pci_get_drvdata(dev); + u8 speed = hpt3xx_ratefilter(drive, xferspeed); + u8 itr_addr = 0x40 + (drive->dn * 4); + u32 itr_mask = speed < XFER_MW_DMA_0 ? 0x303c0000 : + (speed < XFER_UDMA_0 ? 0xc03c0000 : 0xc1c001ff); + u32 new_itr = get_speed_setting(speed, info); + u32 old_itr = 0; + + pci_read_config_dword(dev, itr_addr, &old_itr); + new_itr = (new_itr & ~itr_mask) | (old_itr & itr_mask); if (speed < XFER_MW_DMA_0) - list_conf &= ~0x80000000; /* Disable on-chip PIO FIFO/buffer */ - pci_write_config_dword(dev, drive_pci, list_conf); + new_itr &= ~0x80000000; /* Disable on-chip PIO FIFO/buffer */ + pci_write_config_dword(dev, itr_addr, new_itr); return ide_config_drive_speed(drive, speed); } -static int hpt372_tune_chipset(ide_drive_t *drive, u8 xferspeed) +static int hpt3xx_tune_chipset(ide_drive_t *drive, u8 speed) { - ide_hwif_t *hwif = drive->hwif; - struct pci_dev *dev = hwif->pci_dev; - struct hpt_info *info = ide_get_hwifdata(hwif); - u8 speed = hpt3xx_ratefilter(drive, xferspeed); - u8 regfast = (drive->hwif->channel) ? 0x55 : 0x51; - u8 drive_fast = 0, drive_pci = 0x40 + (drive->dn * 4); - u32 list_conf = 0, drive_conf = 0; - u32 conf_mask = (speed >= XFER_MW_DMA_0) ? 0xc0000000 : 0x30070000; - - /* - * Disable the "fast interrupt" prediction. - * don't holdoff on interrupts. (== 0x01 despite what the docs say) - */ - pci_read_config_byte(dev, regfast, &drive_fast); - drive_fast &= ~0x07; - pci_write_config_byte(dev, regfast, drive_fast); - - list_conf = pci_bus_clock_list(speed, info->speed); - pci_read_config_dword(dev, drive_pci, &drive_conf); - list_conf = (list_conf & ~conf_mask) | (drive_conf & conf_mask); - if (speed < XFER_MW_DMA_0) - list_conf &= ~0x80000000; /* Disable on-chip PIO FIFO/buffer */ - pci_write_config_dword(dev, drive_pci, list_conf); - - return ide_config_drive_speed(drive, speed); -} + ide_hwif_t *hwif = HWIF(drive); + struct hpt_info *info = pci_get_drvdata(hwif->pci_dev); -static int hpt3xx_tune_chipset (ide_drive_t *drive, u8 speed) -{ - ide_hwif_t *hwif = drive->hwif; - struct hpt_info *info = ide_get_hwifdata(hwif); - - if (info->revision >= 8) - return hpt372_tune_chipset(drive, speed); /* not a typo */ - else if (info->revision >= 5) - return hpt372_tune_chipset(drive, speed); - else if (info->revision >= 3) - return hpt370_tune_chipset(drive, speed); + if (info->chip_type >= HPT370) + return hpt37x_tune_chipset(drive, speed); else /* hpt368: hpt_minimum_revision(dev, 2) */ return hpt36x_tune_chipset(drive, speed); } -static void hpt3xx_tune_drive (ide_drive_t *drive, u8 pio) +static void hpt3xx_tune_drive(ide_drive_t *drive, u8 pio) { - pio = ide_get_best_pio_mode(drive, 255, pio, NULL); - (void) hpt3xx_tune_chipset(drive, (XFER_PIO_0 + pio)); + pio = ide_get_best_pio_mode(drive, pio, 4, NULL); + (void) hpt3xx_tune_chipset (drive, XFER_PIO_0 + pio); } /* * This allows the configuration of ide_pci chipset registers * for cards that learn about the drive's UDMA, DMA, PIO capabilities - * after the drive is reported by the OS. Initially for designed for + * after the drive is reported by the OS. Initially designed for * HPT366 UDMA chipset by HighPoint|Triones Technologies, Inc. * - * check_in_drive_lists(drive, bad_ata66_4) - * check_in_drive_lists(drive, bad_ata66_3) - * check_in_drive_lists(drive, bad_ata33) - * */ -static int config_chipset_for_dma (ide_drive_t *drive) +static int config_chipset_for_dma(ide_drive_t *drive) { u8 speed = ide_dma_speed(drive, hpt3xx_ratemask(drive)); - ide_hwif_t *hwif = drive->hwif; - struct hpt_info *info = ide_get_hwifdata(hwif); if (!speed) return 0; - /* If we don't have any timings we can't do a lot */ - if (info->speed == NULL) - return 0; - (void) hpt3xx_tune_chipset(drive, speed); return ide_dma_enable(drive); } -static int hpt3xx_quirkproc (ide_drive_t *drive) +static int hpt3xx_quirkproc(ide_drive_t *drive) { - return ((int) check_in_drive_lists(drive, quirk_drives)); + struct hd_driveid *id = drive->id; + const char **list = quirk_drives; + + while (*list) + if (strstr(id->model, *list++)) + return 1; + return 0; } -static void hpt3xx_intrproc (ide_drive_t *drive) +static void hpt3xx_intrproc(ide_drive_t *drive) { - ide_hwif_t *hwif = drive->hwif; + ide_hwif_t *hwif = HWIF(drive); if (drive->quirk_list) return; /* drives in the quirk_list may not like intr setups/cleanups */ - hwif->OUTB(drive->ctl|2, IDE_CONTROL_REG); + hwif->OUTB(drive->ctl | 2, IDE_CONTROL_REG); } -static void hpt3xx_maskproc (ide_drive_t *drive, int mask) +static void hpt3xx_maskproc(ide_drive_t *drive, int mask) { - ide_hwif_t *hwif = drive->hwif; - struct hpt_info *info = ide_get_hwifdata(hwif); - struct pci_dev *dev = hwif->pci_dev; + ide_hwif_t *hwif = HWIF(drive); + struct pci_dev *dev = hwif->pci_dev; + struct hpt_info *info = pci_get_drvdata(dev); if (drive->quirk_list) { - if (info->revision >= 3) { - u8 reg5a = 0; - pci_read_config_byte(dev, 0x5a, ®5a); - if (((reg5a & 0x10) >> 4) != mask) - pci_write_config_byte(dev, 0x5a, mask ? (reg5a | 0x10) : (reg5a & ~0x10)); + if (info->chip_type >= HPT370) { + u8 scr1 = 0; + + pci_read_config_byte(dev, 0x5a, &scr1); + if (((scr1 & 0x10) >> 4) != mask) { + if (mask) + scr1 |= 0x10; + else + scr1 &= ~0x10; + pci_write_config_byte(dev, 0x5a, scr1); + } } else { - if (mask) { + if (mask) disable_irq(hwif->irq); - } else { - enable_irq(hwif->irq); - } + else + enable_irq (hwif->irq); } - } else { - if (IDE_CONTROL_REG) - hwif->OUTB(mask ? (drive->ctl | 2) : - (drive->ctl & ~2), - IDE_CONTROL_REG); - } + } else + hwif->OUTB(mask ? (drive->ctl | 2) : (drive->ctl & ~2), + IDE_CONTROL_REG); } -static int hpt366_config_drive_xfer_rate (ide_drive_t *drive) +static int hpt366_config_drive_xfer_rate(ide_drive_t *drive) { - ide_hwif_t *hwif = drive->hwif; + ide_hwif_t *hwif = HWIF(drive); struct hd_driveid *id = drive->id; drive->init_speed = 0; if ((id->capability & 1) && drive->autodma) { - - if (ide_use_dma(drive)) { - if (config_chipset_for_dma(drive)) - return hwif->ide_dma_on(drive); - } + if (ide_use_dma(drive) && config_chipset_for_dma(drive)) + return hwif->ide_dma_on(drive); goto fast_ata_pio; } else if ((id->capability & 8) || (id->field_valid & 2)) { fast_ata_pio: - hpt3xx_tune_drive(drive, 5); + hpt3xx_tune_drive(drive, 255); return hwif->ide_dma_off_quietly(drive); } /* IORDY not supported */ @@ -739,31 +757,48 @@ fast_ata_pio: } /* - * This is specific to the HPT366 UDMA bios chipset + * This is specific to the HPT366 UDMA chipset * by HighPoint|Triones Technologies, Inc. */ -static int hpt366_ide_dma_lostirq (ide_drive_t *drive) +static int hpt366_ide_dma_lostirq(ide_drive_t *drive) { - struct pci_dev *dev = HWIF(drive)->pci_dev; - u8 reg50h = 0, reg52h = 0, reg5ah = 0; - - pci_read_config_byte(dev, 0x50, ®50h); - pci_read_config_byte(dev, 0x52, ®52h); - pci_read_config_byte(dev, 0x5a, ®5ah); - printk("%s: (%s) reg50h=0x%02x, reg52h=0x%02x, reg5ah=0x%02x\n", - drive->name, __FUNCTION__, reg50h, reg52h, reg5ah); - if (reg5ah & 0x10) - pci_write_config_byte(dev, 0x5a, reg5ah & ~0x10); + struct pci_dev *dev = HWIF(drive)->pci_dev; + u8 mcr1 = 0, mcr3 = 0, scr1 = 0; + + pci_read_config_byte(dev, 0x50, &mcr1); + pci_read_config_byte(dev, 0x52, &mcr3); + pci_read_config_byte(dev, 0x5a, &scr1); + printk("%s: (%s) mcr1=0x%02x, mcr3=0x%02x, scr1=0x%02x\n", + drive->name, __FUNCTION__, mcr1, mcr3, scr1); + if (scr1 & 0x10) + pci_write_config_byte(dev, 0x5a, scr1 & ~0x10); return __ide_dma_lostirq(drive); } -static void hpt370_clear_engine (ide_drive_t *drive) +static void hpt370_clear_engine(ide_drive_t *drive) { - u8 regstate = HWIF(drive)->channel ? 0x54 : 0x50; - pci_write_config_byte(HWIF(drive)->pci_dev, regstate, 0x37); + ide_hwif_t *hwif = HWIF(drive); + + pci_write_config_byte(hwif->pci_dev, hwif->select_data, 0x37); udelay(10); } +static void hpt370_irq_timeout(ide_drive_t *drive) +{ + ide_hwif_t *hwif = HWIF(drive); + u16 bfifo = 0; + u8 dma_cmd; + + pci_read_config_word(hwif->pci_dev, hwif->select_data + 2, &bfifo); + printk(KERN_DEBUG "%s: %d bytes in FIFO\n", drive->name, bfifo & 0x1ff); + + /* get DMA command mode */ + dma_cmd = hwif->INB(hwif->dma_command); + /* stop DMA */ + hwif->OUTB(dma_cmd & ~0x1, hwif->dma_command); + hpt370_clear_engine(drive); +} + static void hpt370_ide_dma_start(ide_drive_t *drive) { #ifdef HPT_RESET_STATE_ENGINE @@ -772,64 +807,35 @@ #endif ide_dma_start(drive); } -static int hpt370_ide_dma_end (ide_drive_t *drive) +static int hpt370_ide_dma_end(ide_drive_t *drive) { ide_hwif_t *hwif = HWIF(drive); - u8 dma_stat = hwif->INB(hwif->dma_status); + u8 dma_stat = hwif->INB(hwif->dma_status); if (dma_stat & 0x01) { /* wait a little */ udelay(20); dma_stat = hwif->INB(hwif->dma_status); + if (dma_stat & 0x01) + hpt370_irq_timeout(drive); } - if ((dma_stat & 0x01) != 0) - /* fallthrough */ - (void) HWIF(drive)->ide_dma_timeout(drive); - return __ide_dma_end(drive); } -static void hpt370_lostirq_timeout (ide_drive_t *drive) +static int hpt370_ide_dma_timeout(ide_drive_t *drive) { - ide_hwif_t *hwif = HWIF(drive); - u8 bfifo = 0, reginfo = hwif->channel ? 0x56 : 0x52; - u8 dma_stat = 0, dma_cmd = 0; - - pci_read_config_byte(HWIF(drive)->pci_dev, reginfo, &bfifo); - printk(KERN_DEBUG "%s: %d bytes in FIFO\n", drive->name, bfifo); - hpt370_clear_engine(drive); - /* get dma command mode */ - dma_cmd = hwif->INB(hwif->dma_command); - /* stop dma */ - hwif->OUTB(dma_cmd & ~0x1, hwif->dma_command); - dma_stat = hwif->INB(hwif->dma_status); - /* clear errors */ - hwif->OUTB(dma_stat | 0x6, hwif->dma_status); -} - -static int hpt370_ide_dma_timeout (ide_drive_t *drive) -{ - hpt370_lostirq_timeout(drive); - hpt370_clear_engine(drive); + hpt370_irq_timeout(drive); return __ide_dma_timeout(drive); } -static int hpt370_ide_dma_lostirq (ide_drive_t *drive) -{ - hpt370_lostirq_timeout(drive); - hpt370_clear_engine(drive); - return __ide_dma_lostirq(drive); -} - /* returns 1 if DMA IRQ issued, 0 otherwise */ static int hpt374_ide_dma_test_irq(ide_drive_t *drive) { ide_hwif_t *hwif = HWIF(drive); u16 bfifo = 0; - u8 reginfo = hwif->channel ? 0x56 : 0x52; - u8 dma_stat; + u8 dma_stat; - pci_read_config_word(hwif->pci_dev, reginfo, &bfifo); + pci_read_config_word(hwif->pci_dev, hwif->select_data + 2, &bfifo); if (bfifo & 0x1FF) { // printk("%s: %d bytes in FIFO\n", drive->name, bfifo); return 0; @@ -837,7 +843,7 @@ static int hpt374_ide_dma_test_irq(ide_d dma_stat = hwif->INB(hwif->dma_status); /* return 1 if INTR asserted */ - if ((dma_stat & 4) == 4) + if (dma_stat & 4) return 1; if (!drive->waiting_for_dma) @@ -846,17 +852,17 @@ static int hpt374_ide_dma_test_irq(ide_d return 0; } -static int hpt374_ide_dma_end (ide_drive_t *drive) +static int hpt374_ide_dma_end(ide_drive_t *drive) { - struct pci_dev *dev = HWIF(drive)->pci_dev; ide_hwif_t *hwif = HWIF(drive); - u8 msc_stat = 0, mscreg = hwif->channel ? 0x54 : 0x50; - u8 bwsr_stat = 0, bwsr_mask = hwif->channel ? 0x02 : 0x01; - - pci_read_config_byte(dev, 0x6a, &bwsr_stat); - pci_read_config_byte(dev, mscreg, &msc_stat); - if ((bwsr_stat & bwsr_mask) == bwsr_mask) - pci_write_config_byte(dev, mscreg, msc_stat|0x30); + struct pci_dev *dev = hwif->pci_dev; + u8 mcr = 0, mcr_addr = hwif->select_data; + u8 bwsr = 0, mask = hwif->channel ? 0x02 : 0x01; + + pci_read_config_byte(dev, 0x6a, &bwsr); + pci_read_config_byte(dev, mcr_addr, &mcr); + if (bwsr & mask) + pci_write_config_byte(dev, mcr_addr, mcr | 0x30); return __ide_dma_end(drive); } @@ -866,40 +872,37 @@ static int hpt374_ide_dma_end (ide_drive * @mode: clocking mode (0x21 for write, 0x23 otherwise) * * Switch the DPLL clock on the HPT3xxN devices. This is a right mess. - * NOTE: avoid touching the disabled primary channel on HPT371N -- it - * doesn't physically exist anyway... */ static void hpt3xxn_set_clock(ide_hwif_t *hwif, u8 mode) { - u8 mcr1, scr2 = hwif->INB(hwif->dma_master + 0x7b); + u8 scr2 = hwif->INB(hwif->dma_master + 0x7b); if ((scr2 & 0x7f) == mode) return; - /* MISC. control register 1 has the channel enable bit... */ - mcr1 = hwif->INB(hwif->dma_master + 0x70); - /* Tristate the bus */ - if (mcr1 & 0x04) - hwif->OUTB(0x80, hwif->dma_master + 0x73); + hwif->OUTB(0x80, hwif->dma_master + 0x73); hwif->OUTB(0x80, hwif->dma_master + 0x77); /* Switch clock and reset channels */ hwif->OUTB(mode, hwif->dma_master + 0x7b); hwif->OUTB(0xc0, hwif->dma_master + 0x79); - /* Reset state machines */ - if (mcr1 & 0x04) - hwif->OUTB(0x37, hwif->dma_master + 0x70); - hwif->OUTB(0x37, hwif->dma_master + 0x74); + /* + * Reset the state machines. + * NOTE: avoid accidentally enabling the disabled channels. + */ + hwif->OUTB(hwif->INB(hwif->dma_master + 0x70) | 0x32, + hwif->dma_master + 0x70); + hwif->OUTB(hwif->INB(hwif->dma_master + 0x74) | 0x32, + hwif->dma_master + 0x74); /* Complete reset */ hwif->OUTB(0x00, hwif->dma_master + 0x79); /* Reconnect channels to bus */ - if (mcr1 & 0x04) - hwif->OUTB(0x00, hwif->dma_master + 0x73); + hwif->OUTB(0x00, hwif->dma_master + 0x73); hwif->OUTB(0x00, hwif->dma_master + 0x77); } @@ -914,14 +917,12 @@ static void hpt3xxn_set_clock(ide_hwif_t static void hpt3xxn_rw_disk(ide_drive_t *drive, struct request *rq) { - ide_hwif_t *hwif = HWIF(drive); - u8 wantclock = rq_data_dir(rq) ? 0x23 : 0x21; - - hpt3xxn_set_clock(hwif, wantclock); + hpt3xxn_set_clock(HWIF(drive), rq_data_dir(rq) ? 0x23 : 0x21); } /* * Set/get power state for a drive. + * NOTE: affects both drives on each channel. * * When we turn the power back on, we need to re-initialize things. */ @@ -929,26 +930,18 @@ #define TRISTATE_BIT 0x8000 static int hpt3xx_busproc(ide_drive_t *drive, int state) { - ide_hwif_t *hwif = drive->hwif; + ide_hwif_t *hwif = HWIF(drive); struct pci_dev *dev = hwif->pci_dev; - u8 tristate, resetmask, bus_reg = 0; - u16 tri_reg = 0; + u8 mcr_addr = hwif->select_data + 2; + u8 resetmask = hwif->channel ? 0x80 : 0x40; + u8 bsr2 = 0; + u16 mcr = 0; hwif->bus_state = state; - if (hwif->channel) { - /* secondary channel */ - tristate = 0x56; - resetmask = 0x80; - } else { - /* primary channel */ - tristate = 0x52; - resetmask = 0x40; - } - /* Grab the status. */ - pci_read_config_word(dev, tristate, &tri_reg); - pci_read_config_byte(dev, 0x59, &bus_reg); + pci_read_config_word(dev, mcr_addr, &mcr); + pci_read_config_byte(dev, 0x59, &bsr2); /* * Set the state. We don't set it if we don't need to do so. @@ -956,22 +949,22 @@ static int hpt3xx_busproc(ide_drive_t *d */ switch (state) { case BUSSTATE_ON: - if (!(bus_reg & resetmask)) + if (!(bsr2 & resetmask)) return 0; hwif->drives[0].failures = hwif->drives[1].failures = 0; - pci_write_config_byte(dev, 0x59, bus_reg & ~resetmask); - pci_write_config_word(dev, tristate, tri_reg & ~TRISTATE_BIT); + pci_write_config_byte(dev, 0x59, bsr2 & ~resetmask); + pci_write_config_word(dev, mcr_addr, mcr & ~TRISTATE_BIT); return 0; case BUSSTATE_OFF: - if ((bus_reg & resetmask) && !(tri_reg & TRISTATE_BIT)) + if ((bsr2 & resetmask) && !(mcr & TRISTATE_BIT)) return 0; - tri_reg &= ~TRISTATE_BIT; + mcr &= ~TRISTATE_BIT; break; case BUSSTATE_TRISTATE: - if ((bus_reg & resetmask) && (tri_reg & TRISTATE_BIT)) + if ((bsr2 & resetmask) && (mcr & TRISTATE_BIT)) return 0; - tri_reg |= TRISTATE_BIT; + mcr |= TRISTATE_BIT; break; default: return -EINVAL; @@ -980,268 +973,320 @@ static int hpt3xx_busproc(ide_drive_t *d hwif->drives[0].failures = hwif->drives[0].max_failures + 1; hwif->drives[1].failures = hwif->drives[1].max_failures + 1; - pci_write_config_word(dev, tristate, tri_reg); - pci_write_config_byte(dev, 0x59, bus_reg | resetmask); + pci_write_config_word(dev, mcr_addr, mcr); + pci_write_config_byte(dev, 0x59, bsr2 | resetmask); return 0; } -static void __devinit hpt366_clocking(ide_hwif_t *hwif) +/** + * hpt37x_calibrate_dpll - calibrate the DPLL + * @dev: PCI device + * + * Perform a calibration cycle on the DPLL. + * Returns 1 if this succeeds + */ +static int __devinit hpt37x_calibrate_dpll(struct pci_dev *dev, u16 f_low, u16 f_high) { - u32 reg1 = 0; - struct hpt_info *info = ide_get_hwifdata(hwif); + u32 dpll = (f_high << 16) | f_low | 0x100; + u8 scr2; + int i; - pci_read_config_dword(hwif->pci_dev, 0x40, ®1); + pci_write_config_dword(dev, 0x5c, dpll); - /* detect bus speed by looking at control reg timing: */ - switch((reg1 >> 8) & 7) { - case 5: - info->speed = forty_base_hpt36x; - break; - case 9: - info->speed = twenty_five_base_hpt36x; - break; - case 7: - default: - info->speed = thirty_three_base_hpt36x; + /* Wait for oscillator ready */ + for(i = 0; i < 0x5000; ++i) { + udelay(50); + pci_read_config_byte(dev, 0x5b, &scr2); + if (scr2 & 0x80) break; } + /* See if it stays ready (we'll just bail out if it's not yet) */ + for(i = 0; i < 0x1000; ++i) { + pci_read_config_byte(dev, 0x5b, &scr2); + /* DPLL destabilized? */ + if(!(scr2 & 0x80)) + return 0; + } + /* Turn off tuning, we have the DPLL set */ + pci_read_config_dword (dev, 0x5c, &dpll); + pci_write_config_dword(dev, 0x5c, (dpll & ~0x100)); + return 1; } -static void __devinit hpt37x_clocking(ide_hwif_t *hwif) +static unsigned int __devinit init_chipset_hpt366(struct pci_dev *dev, const char *name) { - struct hpt_info *info = ide_get_hwifdata(hwif); - struct pci_dev *dev = hwif->pci_dev; - int adjust, i; - u16 freq = 0; - u32 pll, temp = 0; - u8 reg5bh = 0, mcr1 = 0; - + struct hpt_info *info = kmalloc(sizeof(struct hpt_info), GFP_KERNEL); + unsigned long io_base = pci_resource_start(dev, 4); + u8 pci_clk, dpll_clk = 0; /* PCI and DPLL clock in MHz */ + enum ata_clock clock; + + if (info == NULL) { + printk(KERN_ERR "%s: out of memory!\n", name); + return -ENOMEM; + } + /* - * default to pci clock. make sure MA15/16 are set to output - * to prevent drives having problems with 40-pin cables. Needed - * for some drives such as IBM-DTLA which will not enter ready - * state on reset when PDIAG is a input. - * - * ToDo: should we set 0x21 when using PLL mode ? + * Copy everything from a static "template" structure + * to just allocated per-chip hpt_info structure. */ - pci_write_config_byte(dev, 0x5b, 0x23); + *info = *(struct hpt_info *)pci_get_drvdata(dev); /* - * We'll have to read f_CNT value in order to determine - * the PCI clock frequency according to the following ratio: - * - * f_CNT = Fpci * 192 / Fdpll - * - * First try reading the register in which the HighPoint BIOS - * saves f_CNT value before reprogramming the DPLL from its - * default setting (which differs for the various chips). - * NOTE: This register is only accessible via I/O space. - * - * In case the signature check fails, we'll have to resort to - * reading the f_CNT register itself in hopes that nobody has - * touched the DPLL yet... + * FIXME: Not portable. Also, why do we enable the ROM in the first place? + * We don't seem to be using it. */ - temp = inl(pci_resource_start(dev, 4) + 0x90); - if ((temp & 0xFFFFF000) != 0xABCDE000) { - printk(KERN_WARNING "HPT37X: no clock data saved by BIOS\n"); - - /* Calculate the average value of f_CNT */ - for (temp = i = 0; i < 128; i++) { - pci_read_config_word(dev, 0x78, &freq); - temp += freq & 0x1ff; - mdelay(1); - } - freq = temp / 128; - } else - freq = temp & 0x1ff; + if (dev->resource[PCI_ROM_RESOURCE].start) + pci_write_config_dword(dev, PCI_ROM_ADDRESS, + dev->resource[PCI_ROM_RESOURCE].start | PCI_ROM_ADDRESS_ENABLE); + + pci_write_config_byte(dev, PCI_CACHE_LINE_SIZE, (L1_CACHE_BYTES / 4)); + pci_write_config_byte(dev, PCI_LATENCY_TIMER, 0x78); + pci_write_config_byte(dev, PCI_MIN_GNT, 0x08); + pci_write_config_byte(dev, PCI_MAX_LAT, 0x08); /* - * HPT3xxN chips use different PCI clock information. - * Currently we always set up the PLL for them. + * First, try to estimate the PCI clock frequency... */ + if (info->chip_type >= HPT370) { + u8 scr1 = 0; + u16 f_cnt = 0; + u32 temp = 0; - if (info->flags & IS_3xxN) { - if(freq < 0x55) - pll = F_LOW_PCI_33; - else if(freq < 0x70) - pll = F_LOW_PCI_40; - else if(freq < 0x7F) - pll = F_LOW_PCI_50; - else - pll = F_LOW_PCI_66; + /* Interrupt force enable. */ + pci_read_config_byte(dev, 0x5a, &scr1); + if (scr1 & 0x10) + pci_write_config_byte(dev, 0x5a, scr1 & ~0x10); - printk(KERN_INFO "HPT3xxN detected, FREQ: %d, PLL: %d\n", freq, pll); - } - else - { - if(freq < 0x9C) - pll = F_LOW_PCI_33; - else if(freq < 0xb0) - pll = F_LOW_PCI_40; - else if(freq <0xc8) - pll = F_LOW_PCI_50; + /* + * HighPoint does this for HPT372A. + * NOTE: This register is only writeable via I/O space. + */ + if (info->chip_type == HPT372A) + outb(0x0e, io_base + 0x9c); + + /* + * Default to PCI clock. Make sure MA15/16 are set to output + * to prevent drives having problems with 40-pin cables. + */ + pci_write_config_byte(dev, 0x5b, 0x23); + + /* + * We'll have to read f_CNT value in order to determine + * the PCI clock frequency according to the following ratio: + * + * f_CNT = Fpci * 192 / Fdpll + * + * First try reading the register in which the HighPoint BIOS + * saves f_CNT value before reprogramming the DPLL from its + * default setting (which differs for the various chips). + * NOTE: This register is only accessible via I/O space. + * + * In case the signature check fails, we'll have to resort to + * reading the f_CNT register itself in hopes that nobody has + * touched the DPLL yet... + */ + temp = inl(io_base + 0x90); + if ((temp & 0xFFFFF000) != 0xABCDE000) { + int i; + + printk(KERN_WARNING "%s: no clock data saved by BIOS\n", + name); + + /* Calculate the average value of f_CNT. */ + for (temp = i = 0; i < 128; i++) { + pci_read_config_word(dev, 0x78, &f_cnt); + temp += f_cnt & 0x1ff; + mdelay(1); + } + f_cnt = temp / 128; + } else + f_cnt = temp & 0x1ff; + + dpll_clk = info->dpll_clk; + pci_clk = (f_cnt * dpll_clk) / 192; + + /* Clamp PCI clock to bands. */ + if (pci_clk < 40) + pci_clk = 33; + else if(pci_clk < 45) + pci_clk = 40; + else if(pci_clk < 55) + pci_clk = 50; else - pll = F_LOW_PCI_66; - - if (pll == F_LOW_PCI_33) { - info->speed = thirty_three_base_hpt37x; - printk(KERN_DEBUG "HPT37X: using 33MHz PCI clock\n"); - } else if (pll == F_LOW_PCI_40) { - /* Unsupported */ - } else if (pll == F_LOW_PCI_50) { - info->speed = fifty_base_hpt37x; - printk(KERN_DEBUG "HPT37X: using 50MHz PCI clock\n"); - } else { - info->speed = sixty_six_base_hpt37x; - printk(KERN_DEBUG "HPT37X: using 66MHz PCI clock\n"); + pci_clk = 66; + + printk(KERN_INFO "%s: DPLL base: %d MHz, f_CNT: %d, " + "assuming %d MHz PCI\n", name, dpll_clk, f_cnt, pci_clk); + } else { + u32 itr1 = 0; + + pci_read_config_dword(dev, 0x40, &itr1); + + /* Detect PCI clock by looking at cmd_high_time. */ + switch((itr1 >> 8) & 0x07) { + case 0x09: + pci_clk = 40; + break; + case 0x05: + pci_clk = 25; + break; + case 0x07: + default: + pci_clk = 33; + break; } } - if (pll == F_LOW_PCI_66) - info->flags |= PCI_66MHZ; + /* Let's assume we'll use PCI clock for the ATA clock... */ + switch (pci_clk) { + case 25: + clock = ATA_CLOCK_25MHZ; + break; + case 33: + default: + clock = ATA_CLOCK_33MHZ; + break; + case 40: + clock = ATA_CLOCK_40MHZ; + break; + case 50: + clock = ATA_CLOCK_50MHZ; + break; + case 66: + clock = ATA_CLOCK_66MHZ; + break; + } /* - * only try the pll if we don't have a table for the clock - * speed that we're running at. NOTE: the internal PLL will - * result in slow reads when using a 33MHz PCI clock. we also - * don't like to use the PLL because it will cause glitches - * on PRST/SRST when the HPT state engine gets reset. + * Only try the DPLL if we don't have a table for the PCI clock that + * we are running at for HPT370/A, always use it for anything newer... * - * ToDo: Use 66MHz PLL when ATA133 devices are present on a - * 372 device so we can get ATA133 support + * NOTE: Using the internal DPLL results in slow reads on 33 MHz PCI. + * We also don't like using the DPLL because this causes glitches + * on PRST-/SRST- when the state engine gets reset... */ - if (info->speed) - goto init_hpt37X_done; + if (info->chip_type >= HPT374 || info->settings[clock] == NULL) { + u16 f_low, delta = pci_clk < 50 ? 2 : 4; + int adjust; + + /* + * Select 66 MHz DPLL clock only if UltraATA/133 mode is + * supported/enabled, use 50 MHz DPLL clock otherwise... + */ + if (info->max_mode == 0x04) { + dpll_clk = 66; + clock = ATA_CLOCK_66MHZ; + } else if (dpll_clk) { /* HPT36x chips don't have DPLL */ + dpll_clk = 50; + clock = ATA_CLOCK_50MHZ; + } - info->flags |= PLL_MODE; - - /* - * Adjust the PLL based upon the PCI clock, enable it, and - * wait for stabilization... - */ - adjust = 0; - freq = (pll < F_LOW_PCI_50) ? 2 : 4; - while (adjust++ < 6) { - pci_write_config_dword(dev, 0x5c, (freq + pll) << 16 | - pll | 0x100); - - /* wait for clock stabilization */ - for (i = 0; i < 0x50000; i++) { - pci_read_config_byte(dev, 0x5b, ®5bh); - if (reg5bh & 0x80) { - /* spin looking for the clock to destabilize */ - for (i = 0; i < 0x1000; ++i) { - pci_read_config_byte(dev, 0x5b, - ®5bh); - if ((reg5bh & 0x80) == 0) - goto pll_recal; - } - pci_read_config_dword(dev, 0x5c, &pll); - pci_write_config_dword(dev, 0x5c, - pll & ~0x100); - pci_write_config_byte(dev, 0x5b, 0x21); - - info->speed = fifty_base_hpt37x; - printk("HPT37X: using 50MHz internal PLL\n"); - goto init_hpt37X_done; - } + if (info->settings[clock] == NULL) { + printk(KERN_ERR "%s: unknown bus timing!\n", name); + kfree(info); + return -EIO; } -pll_recal: - if (adjust & 1) - pll -= (adjust >> 1); - else - pll += (adjust >> 1); - } -init_hpt37X_done: - if (!info->speed) - printk(KERN_ERR "HPT37x%s: unknown bus timing [%d %d].\n", - (info->flags & IS_3xxN) ? "N" : "", pll, freq); - /* - * Reset the state engines. - * NOTE: avoid accidentally enabling the primary channel on HPT371N. - */ - pci_read_config_byte(dev, 0x50, &mcr1); - if (mcr1 & 0x04) - pci_write_config_byte(dev, 0x50, 0x37); - pci_write_config_byte(dev, 0x54, 0x37); - udelay(100); -} + /* Select the DPLL clock. */ + pci_write_config_byte(dev, 0x5b, 0x21); -static int __devinit init_hpt37x(struct pci_dev *dev) -{ - u8 reg5ah; + /* + * Adjust the DPLL based upon PCI clock, enable it, + * and wait for stabilization... + */ + f_low = (pci_clk * 48) / dpll_clk; - pci_read_config_byte(dev, 0x5a, ®5ah); - /* interrupt force enable */ - pci_write_config_byte(dev, 0x5a, (reg5ah & ~0x10)); - return 0; -} + for (adjust = 0; adjust < 8; adjust++) { + if(hpt37x_calibrate_dpll(dev, f_low, f_low + delta)) + break; -static int __devinit init_hpt366(struct pci_dev *dev) -{ - u32 reg1 = 0; - u8 drive_fast = 0; + /* + * See if it'll settle at a fractionally different clock + */ + if (adjust & 1) + f_low -= adjust >> 1; + else + f_low += adjust >> 1; + } + if (adjust == 8) { + printk(KERN_ERR "%s: DPLL did not stabilize!\n", name); + kfree(info); + return -EIO; + } - /* - * Disable the "fast interrupt" prediction. - */ - pci_read_config_byte(dev, 0x51, &drive_fast); - if (drive_fast & 0x80) - pci_write_config_byte(dev, 0x51, drive_fast & ~0x80); - pci_read_config_dword(dev, 0x40, ®1); - - return 0; -} + printk("%s: using %d MHz DPLL clock\n", name, dpll_clk); + } else { + /* Mark the fact that we're not using the DPLL. */ + dpll_clk = 0; -static unsigned int __devinit init_chipset_hpt366(struct pci_dev *dev, const char *name) -{ - int ret = 0; + printk("%s: using %d MHz PCI clock\n", name, pci_clk); + } /* - * FIXME: Not portable. Also, why do we enable the ROM in the first place? - * We don't seem to be using it. + * Advance the table pointer to a slot which points to the list + * of the register values settings matching the clock being used. */ - if (dev->resource[PCI_ROM_RESOURCE].start) - pci_write_config_dword(dev, PCI_ROM_ADDRESS, - dev->resource[PCI_ROM_RESOURCE].start | PCI_ROM_ADDRESS_ENABLE); + info->settings += clock; - pci_write_config_byte(dev, PCI_CACHE_LINE_SIZE, (L1_CACHE_BYTES / 4)); - pci_write_config_byte(dev, PCI_LATENCY_TIMER, 0x78); - pci_write_config_byte(dev, PCI_MIN_GNT, 0x08); - pci_write_config_byte(dev, PCI_MAX_LAT, 0x08); + /* Store the clock frequencies. */ + info->dpll_clk = dpll_clk; + info->pci_clk = pci_clk; - if (hpt_revision(dev) >= 3) - ret = init_hpt37x(dev); - else - ret = init_hpt366(dev); + /* Point to this chip's own instance of the hpt_info structure. */ + pci_set_drvdata(dev, info); - if (ret) - return ret; + if (info->chip_type >= HPT370) { + u8 mcr1, mcr4; + + /* + * Reset the state engines. + * NOTE: Avoid accidentally enabling the disabled channels. + */ + pci_read_config_byte (dev, 0x50, &mcr1); + pci_read_config_byte (dev, 0x54, &mcr4); + pci_write_config_byte(dev, 0x50, (mcr1 | 0x32)); + pci_write_config_byte(dev, 0x54, (mcr4 | 0x32)); + udelay(100); + } + + /* + * On HPT371N, if ATA clock is 66 MHz we must set bit 2 in + * the MISC. register to stretch the UltraDMA Tss timing. + * NOTE: This register is only writeable via I/O space. + */ + if (info->chip_type == HPT371N && clock == ATA_CLOCK_66MHZ) + + outb(inb(io_base + 0x9c) | 0x04, io_base + 0x9c); return dev->irq; } static void __devinit init_hwif_hpt366(ide_hwif_t *hwif) { - struct pci_dev *dev = hwif->pci_dev; - struct hpt_info *info = ide_get_hwifdata(hwif); - u8 ata66 = 0, regmask = (hwif->channel) ? 0x01 : 0x02; + struct pci_dev *dev = hwif->pci_dev; + struct hpt_info *info = pci_get_drvdata(dev); int serialize = HPT_SERIALIZE_IO; - + u8 scr1 = 0, ata66 = (hwif->channel) ? 0x01 : 0x02; + u8 chip_type = info->chip_type; + u8 new_mcr, old_mcr = 0; + + /* Cache the channel's MISC. control registers' offset */ + hwif->select_data = hwif->channel ? 0x54 : 0x50; + hwif->tuneproc = &hpt3xx_tune_drive; hwif->speedproc = &hpt3xx_tune_chipset; hwif->quirkproc = &hpt3xx_quirkproc; hwif->intrproc = &hpt3xx_intrproc; hwif->maskproc = &hpt3xx_maskproc; - + hwif->busproc = &hpt3xx_busproc; + /* * HPT3xxN chips have some complications: * * - on 33 MHz PCI we must clock switch * - on 66 MHz PCI we must NOT use the PCI clock */ - if ((info->flags & (IS_3xxN | PCI_66MHZ)) == IS_3xxN) { + if (chip_type >= HPT372N && info->dpll_clk && info->pci_clk < 66) { /* * Clock is shared between the channels, * so we'll have to serialize them... :-( @@ -1250,200 +1295,171 @@ static void __devinit init_hwif_hpt366(i hwif->rw_disk = &hpt3xxn_rw_disk; } + /* Serialize access to this device if needed */ + if (serialize && hwif->mate) + hwif->serialized = hwif->mate->serialized = 1; + + /* + * Disable the "fast interrupt" prediction. Don't hold off + * on interrupts. (== 0x01 despite what the docs say) + */ + pci_read_config_byte(dev, hwif->select_data + 1, &old_mcr); + + if (info->chip_type >= HPT374) + new_mcr = old_mcr & ~0x07; + else if (info->chip_type >= HPT370) { + new_mcr = old_mcr; + new_mcr &= ~0x02; + +#ifdef HPT_DELAY_INTERRUPT + new_mcr &= ~0x01; +#else + new_mcr |= 0x01; +#endif + } else /* HPT366 and HPT368 */ + new_mcr = old_mcr & ~0x80; + + if (new_mcr != old_mcr) + pci_write_config_byte(dev, hwif->select_data + 1, new_mcr); + + if (!hwif->dma_base) { + hwif->drives[0].autotune = hwif->drives[1].autotune = 1; + return; + } + + hwif->ultra_mask = 0x7f; + hwif->mwdma_mask = 0x07; + /* * The HPT37x uses the CBLID pins as outputs for MA15/MA16 - * address lines to access an external eeprom. To read valid + * address lines to access an external EEPROM. To read valid * cable detect state the pins must be enabled as inputs. */ - if (info->revision >= 8 && (PCI_FUNC(dev->devfn) & 1)) { + if (chip_type == HPT374 && (PCI_FUNC(dev->devfn) & 1)) { /* * HPT374 PCI function 1 * - set bit 15 of reg 0x52 to enable TCBLID as input * - set bit 15 of reg 0x56 to enable FCBLID as input */ - u16 mcr3, mcr6; - pci_read_config_word(dev, 0x52, &mcr3); - pci_read_config_word(dev, 0x56, &mcr6); - pci_write_config_word(dev, 0x52, mcr3 | 0x8000); - pci_write_config_word(dev, 0x56, mcr6 | 0x8000); + u8 mcr_addr = hwif->select_data + 2; + u16 mcr; + + pci_read_config_word (dev, mcr_addr, &mcr); + pci_write_config_word(dev, mcr_addr, (mcr | 0x8000)); /* now read cable id register */ - pci_read_config_byte(dev, 0x5a, &ata66); - pci_write_config_word(dev, 0x52, mcr3); - pci_write_config_word(dev, 0x56, mcr6); - } else if (info->revision >= 3) { + pci_read_config_byte (dev, 0x5a, &scr1); + pci_write_config_word(dev, mcr_addr, mcr); + } else if (chip_type >= HPT370) { /* * HPT370/372 and 374 pcifn 0 - * - clear bit 0 of 0x5b to enable P/SCBLID as inputs + * - clear bit 0 of reg 0x5b to enable P/SCBLID as inputs */ - u8 scr2; - pci_read_config_byte(dev, 0x5b, &scr2); - pci_write_config_byte(dev, 0x5b, scr2 & ~1); - /* now read cable id register */ - pci_read_config_byte(dev, 0x5a, &ata66); - pci_write_config_byte(dev, 0x5b, scr2); - } else { - pci_read_config_byte(dev, 0x5a, &ata66); - } + u8 scr2 = 0; -#ifdef DEBUG - printk("HPT366: reg5ah=0x%02x ATA-%s Cable Port%d\n", - ata66, (ata66 & regmask) ? "33" : "66", - PCI_FUNC(hwif->pci_dev->devfn)); -#endif /* DEBUG */ - - /* Serialize access to this device */ - if (serialize && hwif->mate) - hwif->serialized = hwif->mate->serialized = 1; + pci_read_config_byte (dev, 0x5b, &scr2); + pci_write_config_byte(dev, 0x5b, (scr2 & ~1)); + /* now read cable id register */ + pci_read_config_byte (dev, 0x5a, &scr1); + pci_write_config_byte(dev, 0x5b, scr2); + } else + pci_read_config_byte (dev, 0x5a, &scr1); - /* - * Set up ioctl for power status. - * NOTE: power affects both drives on each channel. - */ - hwif->busproc = &hpt3xx_busproc; + if (!hwif->udma_four) + hwif->udma_four = (scr1 & ata66) ? 0 : 1; - if (!hwif->dma_base) { - hwif->drives[0].autotune = 1; - hwif->drives[1].autotune = 1; - return; - } + hwif->ide_dma_check = &hpt366_config_drive_xfer_rate; - hwif->ultra_mask = 0x7f; - hwif->mwdma_mask = 0x07; - - if (!(hwif->udma_four)) - hwif->udma_four = ((ata66 & regmask) ? 0 : 1); - hwif->ide_dma_check = &hpt366_config_drive_xfer_rate; - - if (info->revision >= 8) { - hwif->ide_dma_test_irq = &hpt374_ide_dma_test_irq; - hwif->ide_dma_end = &hpt374_ide_dma_end; - } else if (info->revision >= 5) { - hwif->ide_dma_test_irq = &hpt374_ide_dma_test_irq; - hwif->ide_dma_end = &hpt374_ide_dma_end; - } else if (info->revision >= 3) { - hwif->dma_start = &hpt370_ide_dma_start; - hwif->ide_dma_end = &hpt370_ide_dma_end; - hwif->ide_dma_timeout = &hpt370_ide_dma_timeout; - hwif->ide_dma_lostirq = &hpt370_ide_dma_lostirq; - } else if (info->revision >= 2) - hwif->ide_dma_lostirq = &hpt366_ide_dma_lostirq; - else - hwif->ide_dma_lostirq = &hpt366_ide_dma_lostirq; + if (chip_type >= HPT374) { + hwif->ide_dma_test_irq = &hpt374_ide_dma_test_irq; + hwif->ide_dma_end = &hpt374_ide_dma_end; + } else if (chip_type >= HPT370) { + hwif->dma_start = &hpt370_ide_dma_start; + hwif->ide_dma_end = &hpt370_ide_dma_end; + hwif->ide_dma_timeout = &hpt370_ide_dma_timeout; + } else + hwif->ide_dma_lostirq = &hpt366_ide_dma_lostirq; if (!noautodma) hwif->autodma = 1; - hwif->drives[0].autodma = hwif->autodma; - hwif->drives[1].autodma = hwif->autodma; + hwif->drives[0].autodma = hwif->drives[1].autodma = hwif->autodma; } static void __devinit init_dma_hpt366(ide_hwif_t *hwif, unsigned long dmabase) { - struct hpt_info *info = ide_get_hwifdata(hwif); - u8 masterdma = 0, slavedma = 0; - u8 dma_new = 0, dma_old = 0; - u8 primary = hwif->channel ? 0x4b : 0x43; - u8 secondary = hwif->channel ? 0x4f : 0x47; + struct pci_dev *dev = hwif->pci_dev; + u8 masterdma = 0, slavedma = 0; + u8 dma_new = 0, dma_old = 0; unsigned long flags; if (!dmabase) return; - if(info->speed == NULL) { - printk(KERN_WARNING "hpt366: no known IDE timings, disabling DMA.\n"); - return; - } - - dma_old = hwif->INB(dmabase+2); + dma_old = hwif->INB(dmabase + 2); local_irq_save(flags); dma_new = dma_old; - pci_read_config_byte(hwif->pci_dev, primary, &masterdma); - pci_read_config_byte(hwif->pci_dev, secondary, &slavedma); + pci_read_config_byte(dev, hwif->channel ? 0x4b : 0x43, &masterdma); + pci_read_config_byte(dev, hwif->channel ? 0x4f : 0x47, &slavedma); if (masterdma & 0x30) dma_new |= 0x20; - if (slavedma & 0x30) dma_new |= 0x40; + if ( slavedma & 0x30) dma_new |= 0x40; if (dma_new != dma_old) - hwif->OUTB(dma_new, dmabase+2); + hwif->OUTB(dma_new, dmabase + 2); local_irq_restore(flags); ide_setup_dma(hwif, dmabase, 8); } -/* - * We "borrow" this hook in order to set the data structures - * up early enough before dma or init_hwif calls are made. - */ - -static void __devinit init_iops_hpt366(ide_hwif_t *hwif) -{ - struct hpt_info *info = kzalloc(sizeof(struct hpt_info), GFP_KERNEL); - struct pci_dev *dev = hwif->pci_dev; - u16 did = dev->device; - u8 rid = 0; - - if(info == NULL) { - printk(KERN_WARNING "hpt366: out of memory.\n"); - return; - } - ide_set_hwifdata(hwif, info); - - /* Avoid doing the same thing twice. */ - if (hwif->channel && hwif->mate) { - memcpy(info, ide_get_hwifdata(hwif->mate), sizeof(struct hpt_info)); - return; - } - - pci_read_config_byte(dev, PCI_CLASS_REVISION, &rid); - - if (( did == PCI_DEVICE_ID_TTI_HPT366 && rid == 6) || - ((did == PCI_DEVICE_ID_TTI_HPT372 || - did == PCI_DEVICE_ID_TTI_HPT302 || - did == PCI_DEVICE_ID_TTI_HPT371) && rid > 1) || - did == PCI_DEVICE_ID_TTI_HPT372N) - info->flags |= IS_3xxN; - - info->revision = hpt_revision(dev); - - if (info->revision >= 3) - hpt37x_clocking(hwif); - else - hpt366_clocking(hwif); -} - static int __devinit init_setup_hpt374(struct pci_dev *dev, ide_pci_device_t *d) { - struct pci_dev *findev = NULL; + struct pci_dev *dev2; if (PCI_FUNC(dev->devfn) & 1) return -ENODEV; - while ((findev = pci_find_device(PCI_ANY_ID, PCI_ANY_ID, findev)) != NULL) { - if ((findev->vendor == dev->vendor) && - (findev->device == dev->device) && - ((findev->devfn - dev->devfn) == 1) && - (PCI_FUNC(findev->devfn) & 1)) { - if (findev->irq != dev->irq) { - /* FIXME: we need a core pci_set_interrupt() */ - findev->irq = dev->irq; - printk(KERN_WARNING "%s: pci-config space interrupt " - "fixed.\n", d->name); - } - return ide_setup_pci_devices(dev, findev, d); + pci_set_drvdata(dev, &hpt374); + + if ((dev2 = pci_get_slot(dev->bus, dev->devfn + 1)) != NULL) { + int ret; + + pci_set_drvdata(dev2, &hpt374); + + if (dev2->irq != dev->irq) { + /* FIXME: we need a core pci_set_interrupt() */ + dev2->irq = dev->irq; + printk(KERN_WARNING "%s: PCI config space interrupt " + "fixed.\n", d->name); } + ret = ide_setup_pci_devices(dev, dev2, d); + if (ret < 0) + pci_dev_put(dev2); + return ret; } return ide_setup_pci_device(dev, d); } -static int __devinit init_setup_hpt37x(struct pci_dev *dev, ide_pci_device_t *d) +static int __devinit init_setup_hpt372n(struct pci_dev *dev, ide_pci_device_t *d) { + pci_set_drvdata(dev, &hpt372n); + return ide_setup_pci_device(dev, d); } static int __devinit init_setup_hpt371(struct pci_dev *dev, ide_pci_device_t *d) { - u8 mcr1 = 0; + struct hpt_info *info; + u8 rev = 0, mcr1 = 0; + + pci_read_config_byte(dev, PCI_REVISION_ID, &rev); + + if (rev > 1) { + d->name = "HPT371N"; + + info = &hpt371n; + } else + info = &hpt371; /* * HPT371 chips physically have only one channel, the secondary one, @@ -1453,59 +1469,94 @@ static int __devinit init_setup_hpt371(s */ pci_read_config_byte(dev, 0x50, &mcr1); if (mcr1 & 0x04) - pci_write_config_byte(dev, 0x50, (mcr1 & ~0x04)); + pci_write_config_byte(dev, 0x50, mcr1 & ~0x04); + + pci_set_drvdata(dev, info); + + return ide_setup_pci_device(dev, d); +} + +static int __devinit init_setup_hpt372a(struct pci_dev *dev, ide_pci_device_t *d) +{ + struct hpt_info *info; + u8 rev = 0; + + pci_read_config_byte(dev, PCI_REVISION_ID, &rev); + + if (rev > 1) { + d->name = "HPT372N"; + + info = &hpt372n; + } else + info = &hpt372a; + pci_set_drvdata(dev, info); + + return ide_setup_pci_device(dev, d); +} + +static int __devinit init_setup_hpt302(struct pci_dev *dev, ide_pci_device_t *d) +{ + struct hpt_info *info; + u8 rev = 0; + + pci_read_config_byte(dev, PCI_REVISION_ID, &rev); + + if (rev > 1) { + d->name = "HPT302N"; + + info = &hpt302n; + } else + info = &hpt302; + pci_set_drvdata(dev, info); return ide_setup_pci_device(dev, d); } static int __devinit init_setup_hpt366(struct pci_dev *dev, ide_pci_device_t *d) { - struct pci_dev *findev = NULL; - u8 pin1 = 0, pin2 = 0; - unsigned int class_rev; - char *chipset_names[] = {"HPT366", "HPT366", "HPT368", - "HPT370", "HPT370A", "HPT372", - "HPT372N" }; + struct pci_dev *dev2; + u8 rev = 0; + static char *chipset_names[] = { "HPT366", "HPT366", "HPT368", + "HPT370", "HPT370A", "HPT372", + "HPT372N" }; + static struct hpt_info *info[] = { &hpt36x, &hpt36x, &hpt36x, + &hpt370, &hpt370a, &hpt372, + &hpt372n }; if (PCI_FUNC(dev->devfn) & 1) return -ENODEV; - pci_read_config_dword(dev, PCI_CLASS_REVISION, &class_rev); - class_rev &= 0xff; + pci_read_config_byte(dev, PCI_REVISION_ID, &rev); - if(dev->device == PCI_DEVICE_ID_TTI_HPT372N) - class_rev = 6; + if (rev > 6) + rev = 6; - if(class_rev <= 6) - d->name = chipset_names[class_rev]; - - switch(class_rev) { - case 6: - case 5: - case 4: - case 3: - goto init_single; - default: - break; - } + d->name = chipset_names[rev]; + + pci_set_drvdata(dev, info[rev]); + + if (rev > 2) + goto init_single; d->channels = 1; - pci_read_config_byte(dev, PCI_INTERRUPT_PIN, &pin1); - while ((findev = pci_find_device(PCI_ANY_ID, PCI_ANY_ID, findev)) != NULL) { - if ((findev->vendor == dev->vendor) && - (findev->device == dev->device) && - ((findev->devfn - dev->devfn) == 1) && - (PCI_FUNC(findev->devfn) & 1)) { - pci_read_config_byte(findev, PCI_INTERRUPT_PIN, &pin2); - if ((pin1 != pin2) && (dev->irq == findev->irq)) { - d->bootable = ON_BOARD; - printk("%s: onboard version of chipset, " - "pin1=%d pin2=%d\n", d->name, - pin1, pin2); - } - return ide_setup_pci_devices(dev, findev, d); + if ((dev2 = pci_get_slot(dev->bus, dev->devfn + 1)) != NULL) { + u8 pin1 = 0, pin2 = 0; + int ret; + + pci_set_drvdata(dev2, info[rev]); + + pci_read_config_byte(dev, PCI_INTERRUPT_PIN, &pin1); + pci_read_config_byte(dev2, PCI_INTERRUPT_PIN, &pin2); + if (pin1 != pin2 && dev->irq == dev2->irq) { + d->bootable = ON_BOARD; + printk("%s: onboard version of chipset, pin1=%d pin2=%d\n", + d->name, pin1, pin2); } + ret = ide_setup_pci_devices(dev, dev2, d); + if (ret < 0) + pci_dev_put(dev2); + return ret; } init_single: return ide_setup_pci_device(dev, d); @@ -1516,64 +1567,68 @@ static ide_pci_device_t hpt366_chipsets[ .name = "HPT366", .init_setup = init_setup_hpt366, .init_chipset = init_chipset_hpt366, - .init_iops = init_iops_hpt366, .init_hwif = init_hwif_hpt366, .init_dma = init_dma_hpt366, .channels = 2, .autodma = AUTODMA, + .enablebits = {{0x50,0x04,0x04}, {0x54,0x04,0x04}}, .bootable = OFF_BOARD, .extra = 240 },{ /* 1 */ .name = "HPT372A", - .init_setup = init_setup_hpt37x, + .init_setup = init_setup_hpt372a, .init_chipset = init_chipset_hpt366, - .init_iops = init_iops_hpt366, .init_hwif = init_hwif_hpt366, .init_dma = init_dma_hpt366, .channels = 2, .autodma = AUTODMA, + .enablebits = {{0x50,0x04,0x04}, {0x54,0x04,0x04}}, .bootable = OFF_BOARD, + .extra = 240 },{ /* 2 */ .name = "HPT302", - .init_setup = init_setup_hpt37x, + .init_setup = init_setup_hpt302, .init_chipset = init_chipset_hpt366, - .init_iops = init_iops_hpt366, .init_hwif = init_hwif_hpt366, .init_dma = init_dma_hpt366, .channels = 2, .autodma = AUTODMA, + .enablebits = {{0x50,0x04,0x04}, {0x54,0x04,0x04}}, .bootable = OFF_BOARD, + .extra = 240 },{ /* 3 */ .name = "HPT371", .init_setup = init_setup_hpt371, .init_chipset = init_chipset_hpt366, - .init_iops = init_iops_hpt366, .init_hwif = init_hwif_hpt366, .init_dma = init_dma_hpt366, .channels = 2, .autodma = AUTODMA, .enablebits = {{0x50,0x04,0x04}, {0x54,0x04,0x04}}, .bootable = OFF_BOARD, + .extra = 240 },{ /* 4 */ .name = "HPT374", .init_setup = init_setup_hpt374, .init_chipset = init_chipset_hpt366, - .init_iops = init_iops_hpt366, .init_hwif = init_hwif_hpt366, .init_dma = init_dma_hpt366, .channels = 2, /* 4 */ .autodma = AUTODMA, + .enablebits = {{0x50,0x04,0x04}, {0x54,0x04,0x04}}, .bootable = OFF_BOARD, + .extra = 240 },{ /* 5 */ .name = "HPT372N", - .init_setup = init_setup_hpt37x, + .init_setup = init_setup_hpt372n, .init_chipset = init_chipset_hpt366, - .init_iops = init_iops_hpt366, .init_hwif = init_hwif_hpt366, .init_dma = init_dma_hpt366, .channels = 2, /* 4 */ .autodma = AUTODMA, + .enablebits = {{0x50,0x04,0x04}, {0x54,0x04,0x04}}, .bootable = OFF_BOARD, + .extra = 240 } }; diff --git a/drivers/ide/pci/it8213.c b/drivers/ide/pci/it8213.c new file mode 100644 index 0000000..63248b6 --- /dev/null +++ b/drivers/ide/pci/it8213.c @@ -0,0 +1,362 @@ +/* + * ITE 8213 IDE driver + * + * Copyright (C) 2006 Jack Lee + * Copyright (C) 2006 Alan Cox + * Copyright (C) 2007 Bartlomiej Zolnierkiewicz + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +/* + * it8213_ratemask - Compute available modes + * @drive: IDE drive + * + * Compute the available speeds for the devices on the interface. This + * is all modes to ATA133 clipped by drive cable setup. + */ + +static u8 it8213_ratemask (ide_drive_t *drive) +{ + u8 mode = 4; + if (!eighty_ninty_three(drive)) + mode = min_t(u8, mode, 1); + return mode; +} + +/** + * it8213_dma_2_pio - return the PIO mode matching DMA + * @xfer_rate: transfer speed + * + * Returns the nearest equivalent PIO timing for the PIO or DMA + * mode requested by the controller. + */ + +static u8 it8213_dma_2_pio (u8 xfer_rate) { + switch(xfer_rate) { + case XFER_UDMA_6: + case XFER_UDMA_5: + case XFER_UDMA_4: + case XFER_UDMA_3: + case XFER_UDMA_2: + case XFER_UDMA_1: + case XFER_UDMA_0: + case XFER_MW_DMA_2: + case XFER_PIO_4: + return 4; + case XFER_MW_DMA_1: + case XFER_PIO_3: + return 3; + case XFER_SW_DMA_2: + case XFER_PIO_2: + return 2; + case XFER_MW_DMA_0: + case XFER_SW_DMA_1: + case XFER_SW_DMA_0: + case XFER_PIO_1: + case XFER_PIO_0: + case XFER_PIO_SLOW: + default: + return 0; + } +} + +/* + * it8213_tuneproc - tune a drive + * @drive: drive to tune + * @pio: desired PIO mode + * + * Set the interface PIO mode. + */ + +static void it8213_tuneproc (ide_drive_t *drive, u8 pio) +{ + ide_hwif_t *hwif = HWIF(drive); + struct pci_dev *dev = hwif->pci_dev; + int is_slave = drive->dn & 1; + int master_port = 0x40; + int slave_port = 0x44; + unsigned long flags; + u16 master_data; + u8 slave_data; + static DEFINE_SPINLOCK(tune_lock); + int control = 0; + + static const u8 timings[][2]= { + { 0, 0 }, + { 0, 0 }, + { 1, 0 }, + { 2, 1 }, + { 2, 3 }, }; + + pio = ide_get_best_pio_mode(drive, pio, 4, NULL); + + spin_lock_irqsave(&tune_lock, flags); + pci_read_config_word(dev, master_port, &master_data); + + if (pio > 1) + control |= 1; /* Programmable timing on */ + if (drive->media != ide_disk) + control |= 4; /* ATAPI */ + if (pio > 2) + control |= 2; /* IORDY */ + if (is_slave) { + master_data |= 0x4000; + master_data &= ~0x0070; + if (pio > 1) + master_data = master_data | (control << 4); + pci_read_config_byte(dev, slave_port, &slave_data); + slave_data = slave_data & 0xf0; + slave_data = slave_data | (timings[pio][0] << 2) | timings[pio][1]; + } else { + master_data &= ~0x3307; + if (pio > 1) + master_data = master_data | control; + master_data = master_data | (timings[pio][0] << 12) | (timings[pio][1] << 8); + } + pci_write_config_word(dev, master_port, master_data); + if (is_slave) + pci_write_config_byte(dev, slave_port, slave_data); + spin_unlock_irqrestore(&tune_lock, flags); +} + +/** + * it8213_tune_chipset - set controller timings + * @drive: Drive to set up + * @xferspeed: speed we want to achieve + * + * Tune the ITE chipset for the desired mode. If we can't achieve + * the desired mode then tune for a lower one, but ultimately + * make the thing work. + */ + +static int it8213_tune_chipset (ide_drive_t *drive, u8 xferspeed) +{ + + ide_hwif_t *hwif = HWIF(drive); + struct pci_dev *dev = hwif->pci_dev; + u8 maslave = 0x40; + u8 speed = ide_rate_filter(it8213_ratemask(drive), xferspeed); + int a_speed = 3 << (drive->dn * 4); + int u_flag = 1 << drive->dn; + int v_flag = 0x01 << drive->dn; + int w_flag = 0x10 << drive->dn; + int u_speed = 0; + u16 reg4042, reg4a; + u8 reg48, reg54, reg55; + + pci_read_config_word(dev, maslave, ®4042); + pci_read_config_byte(dev, 0x48, ®48); + pci_read_config_word(dev, 0x4a, ®4a); + pci_read_config_byte(dev, 0x54, ®54); + pci_read_config_byte(dev, 0x55, ®55); + + switch(speed) { + case XFER_UDMA_6: + case XFER_UDMA_4: + case XFER_UDMA_2: u_speed = 2 << (drive->dn * 4); break; + case XFER_UDMA_5: + case XFER_UDMA_3: + case XFER_UDMA_1: u_speed = 1 << (drive->dn * 4); break; + case XFER_UDMA_0: u_speed = 0 << (drive->dn * 4); break; + break; + case XFER_MW_DMA_2: + case XFER_MW_DMA_1: + case XFER_SW_DMA_2: + break; + case XFER_PIO_4: + case XFER_PIO_3: + case XFER_PIO_2: + case XFER_PIO_1: + case XFER_PIO_0: + break; + default: + return -1; + } + + if (speed >= XFER_UDMA_0) { + if (!(reg48 & u_flag)) + pci_write_config_byte(dev, 0x48, reg48 | u_flag); + if (speed >= XFER_UDMA_5) { + pci_write_config_byte(dev, 0x55, (u8) reg55|w_flag); + } else { + pci_write_config_byte(dev, 0x55, (u8) reg55 & ~w_flag); + } + + if ((reg4a & a_speed) != u_speed) + pci_write_config_word(dev, 0x4a, (reg4a & ~a_speed) | u_speed); + if (speed > XFER_UDMA_2) { + if (!(reg54 & v_flag)) + pci_write_config_byte(dev, 0x54, reg54 | v_flag); + } else + pci_write_config_byte(dev, 0x54, reg54 & ~v_flag); + } else { + if (reg48 & u_flag) + pci_write_config_byte(dev, 0x48, reg48 & ~u_flag); + if (reg4a & a_speed) + pci_write_config_word(dev, 0x4a, reg4a & ~a_speed); + if (reg54 & v_flag) + pci_write_config_byte(dev, 0x54, reg54 & ~v_flag); + if (reg55 & w_flag) + pci_write_config_byte(dev, 0x55, (u8) reg55 & ~w_flag); + } + it8213_tuneproc(drive, it8213_dma_2_pio(speed)); + return ide_config_drive_speed(drive, speed); +} + +/* + * config_chipset_for_dma - configure for DMA + * @drive: drive to configure + * + * Called by the IDE layer when it wants the timings set up. + */ + +static int config_chipset_for_dma (ide_drive_t *drive) +{ + u8 speed = ide_dma_speed(drive, it8213_ratemask(drive)); + + if (!speed) + return 0; + + it8213_tune_chipset(drive, speed); + + return ide_dma_enable(drive); +} + +/** + * it8213_configure_drive_for_dma - set up for DMA transfers + * @drive: drive we are going to set up + * + * Set up the drive for DMA, tune the controller and drive as + * required. If the drive isn't suitable for DMA or we hit + * other problems then we will drop down to PIO and set up + * PIO appropriately + */ + +static int it8213_config_drive_for_dma (ide_drive_t *drive) +{ + ide_hwif_t *hwif = drive->hwif; + + if (ide_use_dma(drive)) { + if (config_chipset_for_dma(drive)) + return hwif->ide_dma_on(drive); + } + + hwif->speedproc(drive, XFER_PIO_0 + + ide_get_best_pio_mode(drive, 255, 4, NULL)); + + return hwif->ide_dma_off_quietly(drive); +} + +/** + * init_hwif_it8213 - set up hwif structs + * @hwif: interface to set up + * + * We do the basic set up of the interface structure. The IT8212 + * requires several custom handlers so we override the default + * ide DMA handlers appropriately + */ + +static void __devinit init_hwif_it8213(ide_hwif_t *hwif) +{ + u8 reg42h = 0, ata66 = 0; + + hwif->speedproc = &it8213_tune_chipset; + hwif->tuneproc = &it8213_tuneproc; + + hwif->autodma = 0; + + hwif->drives[0].autotune = 1; + hwif->drives[1].autotune = 1; + + if (!hwif->dma_base) + return; + + hwif->atapi_dma = 1; + hwif->ultra_mask = 0x7f; + hwif->mwdma_mask = 0x06; + hwif->swdma_mask = 0x04; + + pci_read_config_byte(hwif->pci_dev, 0x42, ®42h); + ata66 = (reg42h & 0x02) ? 0 : 1; + + hwif->ide_dma_check = &it8213_config_drive_for_dma; + if (!(hwif->udma_four)) + hwif->udma_four = ata66; + + /* + * The BIOS often doesn't set up DMA on this controller + * so we always do it. + */ + if (!noautodma) + hwif->autodma = 1; + + hwif->drives[0].autodma = hwif->autodma; + hwif->drives[1].autodma = hwif->autodma; +} + + +#define DECLARE_ITE_DEV(name_str) \ + { \ + .name = name_str, \ + .init_hwif = init_hwif_it8213, \ + .channels = 1, \ + .autodma = AUTODMA, \ + .enablebits = {{0x41,0x80,0x80}}, \ + .bootable = ON_BOARD, \ + } + +static ide_pci_device_t it8213_chipsets[] __devinitdata = { + /* 0 */ DECLARE_ITE_DEV("IT8213"), +}; + + +/** + * it8213_init_one - pci layer discovery entry + * @dev: PCI device + * @id: ident table entry + * + * Called by the PCI code when it finds an ITE8213 controller. As + * this device follows the standard interfaces we can use the + * standard helper functions to do almost all the work for us. + */ + +static int __devinit it8213_init_one(struct pci_dev *dev, const struct pci_device_id *id) +{ + ide_setup_pci_device(dev, &it8213_chipsets[id->driver_data]); + return 0; +} + + +static struct pci_device_id it8213_pci_tbl[] = { + { PCI_VENDOR_ID_ITE, 0x8213, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, + { 0, }, +}; + +MODULE_DEVICE_TABLE(pci, it8213_pci_tbl); + +static struct pci_driver driver = { + .name = "ITE8213_IDE", + .id_table = it8213_pci_tbl, + .probe = it8213_init_one, +}; + +static int __init it8213_ide_init(void) +{ + return ide_pci_register_driver(&driver); +} + +module_init(it8213_ide_init); + +MODULE_AUTHOR("Jack Lee, Alan Cox"); +MODULE_DESCRIPTION("PCI driver module for the ITE 8213"); +MODULE_LICENSE("GPL"); diff --git a/drivers/ide/pci/pdc202xx_new.c b/drivers/ide/pci/pdc202xx_new.c index 77a9aaa..236a031 100644 --- a/drivers/ide/pci/pdc202xx_new.c +++ b/drivers/ide/pci/pdc202xx_new.c @@ -92,26 +92,6 @@ static u8 pdcnew_ratemask(ide_drive_t *d return mode; } -static int check_in_drive_lists(ide_drive_t *drive, const char **list) -{ - struct hd_driveid *id = drive->id; - - if (pdc_quirk_drives == list) { - while (*list) { - if (strstr(id->model, *list++)) { - return 2; - } - } - } else { - while (*list) { - if (!strcmp(*list++,id->model)) { - return 1; - } - } - } - return 0; -} - /** * get_indexed_reg - Get indexed register * @hwif: for the port address @@ -249,13 +229,6 @@ static int pdcnew_tune_chipset(ide_drive return err; } -/* 0 1 2 3 4 5 6 7 8 - * 960, 480, 390, 300, 240, 180, 120, 90, 60 - * 180, 150, 120, 90, 60 - * DMA_Speed - * 180, 120, 90, 90, 90, 60, 30 - * 11, 5, 4, 3, 2, 1, 0 - */ static void pdcnew_tune_drive(ide_drive_t *drive, u8 pio) { pio = ide_get_best_pio_mode(drive, pio, 4, NULL); @@ -313,12 +286,10 @@ static int pdcnew_config_drive_xfer_rate drive->init_speed = 0; - if (id && (id->capability & 1) && drive->autodma) { + if ((id->capability & 1) && drive->autodma) { - if (ide_use_dma(drive)) { - if (config_chipset_for_dma(drive)) - return hwif->ide_dma_on(drive); - } + if (ide_use_dma(drive) && config_chipset_for_dma(drive)) + return hwif->ide_dma_on(drive); goto fast_ata_pio; @@ -333,21 +304,12 @@ fast_ata_pio: static int pdcnew_quirkproc(ide_drive_t *drive) { - return check_in_drive_lists(drive, pdc_quirk_drives); -} + const char **list, *model = drive->id->model; -static int pdcnew_ide_dma_lostirq(ide_drive_t *drive) -{ - if (HWIF(drive)->resetproc != NULL) - HWIF(drive)->resetproc(drive); - return __ide_dma_lostirq(drive); -} - -static int pdcnew_ide_dma_timeout(ide_drive_t *drive) -{ - if (HWIF(drive)->resetproc != NULL) - HWIF(drive)->resetproc(drive); - return __ide_dma_timeout(drive); + for (list = pdc_quirk_drives; *list != NULL; list++) + if (strstr(model, *list) != NULL) + return 2; + return 0; } static void pdcnew_reset(ide_drive_t *drive) @@ -599,8 +561,6 @@ static void __devinit init_hwif_pdc202ne hwif->err_stops_fifo = 1; hwif->ide_dma_check = &pdcnew_config_drive_xfer_rate; - hwif->ide_dma_lostirq = &pdcnew_ide_dma_lostirq; - hwif->ide_dma_timeout = &pdcnew_ide_dma_timeout; if (!hwif->udma_four) hwif->udma_four = pdcnew_cable_detect(hwif) ? 0 : 1; diff --git a/drivers/ide/pci/pdc202xx_old.c b/drivers/ide/pci/pdc202xx_old.c index 143239c..730e8d1 100644 --- a/drivers/ide/pci/pdc202xx_old.c +++ b/drivers/ide/pci/pdc202xx_old.c @@ -123,26 +123,6 @@ static u8 pdc202xx_ratemask (ide_drive_t return mode; } -static int check_in_drive_lists (ide_drive_t *drive, const char **list) -{ - struct hd_driveid *id = drive->id; - - if (pdc_quirk_drives == list) { - while (*list) { - if (strstr(id->model, *list++)) { - return 2; - } - } - } else { - while (*list) { - if (!strcmp(*list++,id->model)) { - return 1; - } - } - } - return 0; -} - static int pdc202xx_tune_chipset (ide_drive_t *drive, u8 xferspeed) { ide_hwif_t *hwif = HWIF(drive); @@ -377,7 +357,12 @@ fast_ata_pio: static int pdc202xx_quirkproc (ide_drive_t *drive) { - return ((int) check_in_drive_lists(drive, pdc_quirk_drives)); + const char **list, *model = drive->id->model; + + for (list = pdc_quirk_drives; *list != NULL; list++) + if (strstr(model, *list) != NULL) + return 2; + return 0; } static void pdc202xx_old_ide_dma_start(ide_drive_t *drive) diff --git a/drivers/ide/pci/piix.c b/drivers/ide/pci/piix.c index edb37f3..52cfc2a 100644 --- a/drivers/ide/pci/piix.c +++ b/drivers/ide/pci/piix.c @@ -1,5 +1,5 @@ /* - * linux/drivers/ide/pci/piix.c Version 0.45 May 12, 2006 + * linux/drivers/ide/pci/piix.c Version 0.46 December 3, 2006 * * Copyright (C) 1998-1999 Andrzej Krzysztofowicz, Author and Maintainer * Copyright (C) 1998-2000 Andre Hedrick @@ -163,7 +163,7 @@ static u8 piix_ratemask (ide_drive_t *dr * if the drive cannot see an 80pin cable. */ if (!eighty_ninty_three(drive)) - mode = min(mode, (u8)1); + mode = min_t(u8, mode, 1); return mode; } @@ -216,7 +216,7 @@ static void piix_tune_drive (ide_drive_t { ide_hwif_t *hwif = HWIF(drive); struct pci_dev *dev = hwif->pci_dev; - int is_slave = (&hwif->drives[1] == drive); + int is_slave = drive->dn & 1; int master_port = hwif->channel ? 0x42 : 0x40; int slave_port = 0x44; unsigned long flags; @@ -225,7 +225,7 @@ static void piix_tune_drive (ide_drive_t static DEFINE_SPINLOCK(tune_lock); int control = 0; - /* ISP RTC */ + /* ISP RTC */ static const u8 timings[][2]= { { 0, 0 }, { 0, 0 }, @@ -233,7 +233,7 @@ static void piix_tune_drive (ide_drive_t { 2, 1 }, { 2, 3 }, }; - pio = ide_get_best_pio_mode(drive, pio, 5, NULL); + pio = ide_get_best_pio_mode(drive, pio, 4, NULL); /* * Master vs slave is synchronized above us but the slave register is @@ -243,25 +243,24 @@ static void piix_tune_drive (ide_drive_t spin_lock_irqsave(&tune_lock, flags); pci_read_config_word(dev, master_port, &master_data); - if (pio >= 2) + if (pio > 1) control |= 1; /* Programmable timing on */ if (drive->media == ide_disk) control |= 4; /* Prefetch, post write */ - if (pio >= 3) + if (pio > 2) control |= 2; /* IORDY */ if (is_slave) { - master_data = master_data | 0x4000; + master_data |= 0x4000; + master_data &= ~0x0070; if (pio > 1) { /* enable PPE, IE and TIME */ master_data = master_data | (control << 4); - } else { - master_data &= ~0x0070; } pci_read_config_byte(dev, slave_port, &slave_data); slave_data = slave_data & (hwif->channel ? 0x0f : 0xf0); slave_data = slave_data | (((timings[pio][0] << 2) | timings[pio][1]) << (hwif->channel ? 4 : 0)); } else { - master_data = master_data & 0xccf8; + master_data &= ~0x3307; if (pio > 1) { /* enable PPE, IE and TIME */ master_data = master_data | control; @@ -539,13 +538,19 @@ static ide_pci_device_t piix_pci_info[] /* 0 */ DECLARE_PIIX_DEV("PIIXa"), /* 1 */ DECLARE_PIIX_DEV("PIIXb"), - { /* 2 */ + /* 2 */ + { /* + * MPIIX actually has only a single IDE channel mapped to + * the primary or secondary ports depending on the value + * of the bit 14 of the IDETIM register at offset 0x6c + */ .name = "MPIIX", .init_hwif = init_hwif_piix, .channels = 2, .autodma = NODMA, - .enablebits = {{0x6D,0x80,0x80}, {0x6F,0x80,0x80}}, + .enablebits = {{0x6d,0xc0,0x80}, {0x6d,0xc0,0xc0}}, .bootable = ON_BOARD, + .flags = IDEPCI_FLAG_ISA_PORTS }, /* 3 */ DECLARE_PIIX_DEV("PIIX3"), diff --git a/drivers/ide/pci/slc90e66.c b/drivers/ide/pci/slc90e66.c index 90e79c0..2663ddb 100644 --- a/drivers/ide/pci/slc90e66.c +++ b/drivers/ide/pci/slc90e66.c @@ -1,5 +1,5 @@ /* - * linux/drivers/ide/pci/slc90e66.c Version 0.12 May 12, 2006 + * linux/drivers/ide/pci/slc90e66.c Version 0.13 December 30, 2006 * * Copyright (C) 2000-2002 Andre Hedrick * Copyright (C) 2006 MontaVista Software, Inc. @@ -26,7 +26,7 @@ static u8 slc90e66_ratemask (ide_drive_t u8 mode = 2; if (!eighty_ninty_three(drive)) - mode = min(mode, (u8)1); + mode = min_t(u8, mode, 1); return mode; } @@ -65,36 +65,47 @@ static void slc90e66_tune_drive (ide_dri { ide_hwif_t *hwif = HWIF(drive); struct pci_dev *dev = hwif->pci_dev; - int is_slave = (&hwif->drives[1] == drive); + int is_slave = drive->dn & 1; int master_port = hwif->channel ? 0x42 : 0x40; int slave_port = 0x44; unsigned long flags; u16 master_data; u8 slave_data; - /* ISP RTC */ + int control = 0; + /* ISP RTC */ static const u8 timings[][2]= { - { 0, 0 }, - { 0, 0 }, - { 1, 0 }, - { 2, 1 }, - { 2, 3 }, }; + { 0, 0 }, + { 0, 0 }, + { 1, 0 }, + { 2, 1 }, + { 2, 3 }, }; - pio = ide_get_best_pio_mode(drive, pio, 5, NULL); + pio = ide_get_best_pio_mode(drive, pio, 4, NULL); spin_lock_irqsave(&ide_lock, flags); pci_read_config_word(dev, master_port, &master_data); + + if (pio > 1) + control |= 1; /* Programmable timing on */ + if (drive->media == ide_disk) + control |= 4; /* Prefetch, post write */ + if (pio > 2) + control |= 2; /* IORDY */ if (is_slave) { - master_data = master_data | 0x4000; - if (pio > 1) + master_data |= 0x4000; + master_data &= ~0x0070; + if (pio > 1) { /* enable PPE, IE and TIME */ - master_data = master_data | 0x0070; + master_data = master_data | (control << 4); + } pci_read_config_byte(dev, slave_port, &slave_data); slave_data = slave_data & (hwif->channel ? 0x0f : 0xf0); slave_data = slave_data | (((timings[pio][0] << 2) | timings[pio][1]) << (hwif->channel ? 4 : 0)); } else { - master_data = master_data & 0xccf8; - if (pio > 1) + master_data &= ~0x3307; + if (pio > 1) { /* enable PPE, IE and TIME */ - master_data = master_data | 0x0007; + master_data = master_data | control; + } master_data = master_data | (timings[pio][0] << 12) | (timings[pio][1] << 8); } pci_write_config_word(dev, master_port, master_data); @@ -173,7 +184,7 @@ static int slc90e66_config_drive_xfer_ra drive->init_speed = 0; - if (id && (id->capability & 1) && drive->autodma) { + if ((id->capability & 1) && drive->autodma) { if (ide_use_dma(drive) && slc90e66_config_drive_for_dma(drive)) return hwif->ide_dma_on(drive); @@ -201,7 +212,7 @@ static void __devinit init_hwif_slc90e66 hwif->irq = hwif->channel ? 15 : 14; hwif->speedproc = &slc90e66_tune_chipset; - hwif->tuneproc = &slc90e66_tune_drive; + hwif->tuneproc = &slc90e66_tune_drive; pci_read_config_byte(hwif->pci_dev, 0x47, ®47); @@ -213,14 +224,16 @@ static void __devinit init_hwif_slc90e66 hwif->atapi_dma = 1; hwif->ultra_mask = 0x1f; - hwif->mwdma_mask = 0x07; - hwif->swdma_mask = 0x07; + hwif->mwdma_mask = 0x06; + hwif->swdma_mask = 0x04; - if (!(hwif->udma_four)) + if (!hwif->udma_four) { /* bit[0(1)]: 0:80, 1:40 */ hwif->udma_four = (reg47 & mask) ? 0 : 1; + } hwif->ide_dma_check = &slc90e66_config_drive_xfer_rate; + if (!noautodma) hwif->autodma = 1; hwif->drives[0].autodma = hwif->autodma; diff --git a/drivers/ide/pci/tc86c001.c b/drivers/ide/pci/tc86c001.c new file mode 100644 index 0000000..2ad72bb --- /dev/null +++ b/drivers/ide/pci/tc86c001.c @@ -0,0 +1,309 @@ +/* + * drivers/ide/pci/tc86c001.c Version 1.00 Dec 12, 2006 + * + * Copyright (C) 2002 Toshiba Corporation + * Copyright (C) 2005-2006 MontaVista Software, Inc. + * + * This file is licensed under the terms of the GNU General Public + * License version 2. This program is licensed "as is" without any + * warranty of any kind, whether express or implied. + */ + +#include +#include +#include + +static inline u8 tc86c001_ratemask(ide_drive_t *drive) +{ + return eighty_ninty_three(drive) ? 2 : 1; +} + +static int tc86c001_tune_chipset(ide_drive_t *drive, u8 speed) +{ + ide_hwif_t *hwif = HWIF(drive); + unsigned long scr_port = hwif->config_data + (drive->dn ? 0x02 : 0x00); + u16 mode, scr = hwif->INW(scr_port); + + speed = ide_rate_filter(tc86c001_ratemask(drive), speed); + + switch (speed) { + case XFER_UDMA_4: mode = 0x00c0; break; + case XFER_UDMA_3: mode = 0x00b0; break; + case XFER_UDMA_2: mode = 0x00a0; break; + case XFER_UDMA_1: mode = 0x0090; break; + case XFER_UDMA_0: mode = 0x0080; break; + case XFER_MW_DMA_2: mode = 0x0070; break; + case XFER_MW_DMA_1: mode = 0x0060; break; + case XFER_MW_DMA_0: mode = 0x0050; break; + case XFER_PIO_4: mode = 0x0400; break; + case XFER_PIO_3: mode = 0x0300; break; + case XFER_PIO_2: mode = 0x0200; break; + case XFER_PIO_1: mode = 0x0100; break; + case XFER_PIO_0: + default: mode = 0x0000; break; + } + + scr &= (speed < XFER_MW_DMA_0) ? 0xf8ff : 0xff0f; + scr |= mode; + hwif->OUTW(scr, scr_port); + + return ide_config_drive_speed(drive, speed); +} + +static void tc86c001_tune_drive(ide_drive_t *drive, u8 pio) +{ + pio = ide_get_best_pio_mode(drive, pio, 4, NULL); + (void) tc86c001_tune_chipset(drive, XFER_PIO_0 + pio); +} + +/* + * HACKITY HACK + * + * This is a workaround for the limitation 5 of the TC86C001 IDE controller: + * if a DMA transfer terminates prematurely, the controller leaves the device's + * interrupt request (INTRQ) pending and does not generate a PCI interrupt (or + * set the interrupt bit in the DMA status register), thus no PCI interrupt + * will occur until a DMA transfer has been successfully completed. + * + * We work around this by initiating dummy, zero-length DMA transfer on + * a DMA timeout expiration. I found no better way to do this with the current + * IDE core than to temporarily replace a higher level driver's timer expiry + * handler with our own backing up to that handler in case our recovery fails. + */ +static int tc86c001_timer_expiry(ide_drive_t *drive) +{ + ide_hwif_t *hwif = HWIF(drive); + ide_expiry_t *expiry = ide_get_hwifdata(hwif); + ide_hwgroup_t *hwgroup = HWGROUP(drive); + u8 dma_stat = hwif->INB(hwif->dma_status); + + /* Restore a higher level driver's expiry handler first. */ + hwgroup->expiry = expiry; + + if ((dma_stat & 5) == 1) { /* DMA active and no interrupt */ + unsigned long sc_base = hwif->config_data; + unsigned long twcr_port = sc_base + (drive->dn ? 0x06 : 0x04); + u8 dma_cmd = hwif->INB(hwif->dma_command); + + printk(KERN_WARNING "%s: DMA interrupt possibly stuck, " + "attempting recovery...\n", drive->name); + + /* Stop DMA */ + hwif->OUTB(dma_cmd & ~0x01, hwif->dma_command); + + /* Setup the dummy DMA transfer */ + hwif->OUTW(0, sc_base + 0x0a); /* Sector Count */ + hwif->OUTW(0, twcr_port); /* Transfer Word Count 1 or 2 */ + + /* Start the dummy DMA transfer */ + hwif->OUTB(0x00, hwif->dma_command); /* clear R_OR_WCTR for write */ + hwif->OUTB(0x01, hwif->dma_command); /* set START_STOPBM */ + + /* + * If an interrupt was pending, it should come thru shortly. + * If not, a higher level driver's expiry handler should + * eventually cause some kind of recovery from the DMA stall. + */ + return WAIT_MIN_SLEEP; + } + + /* Chain to the restored expiry handler if DMA wasn't active. */ + if (likely(expiry != NULL)) + return expiry(drive); + + /* If there was no handler, "emulate" that for ide_timer_expiry()... */ + return -1; +} + +static void tc86c001_dma_start(ide_drive_t *drive) +{ + ide_hwif_t *hwif = HWIF(drive); + ide_hwgroup_t *hwgroup = HWGROUP(drive); + unsigned long sc_base = hwif->config_data; + unsigned long twcr_port = sc_base + (drive->dn ? 0x06 : 0x04); + unsigned long nsectors = hwgroup->rq->nr_sectors; + + /* + * We have to manually load the sector count and size into + * the appropriate system control registers for DMA to work + * with LBA48 and ATAPI devices... + */ + hwif->OUTW(nsectors, sc_base + 0x0a); /* Sector Count */ + hwif->OUTW(SECTOR_SIZE / 2, twcr_port); /* Transfer Word Count 1/2 */ + + /* Install our timeout expiry hook, saving the current handler... */ + ide_set_hwifdata(hwif, hwgroup->expiry); + hwgroup->expiry = &tc86c001_timer_expiry; + + ide_dma_start(drive); +} + +static int tc86c001_busproc(ide_drive_t *drive, int state) +{ + ide_hwif_t *hwif = HWIF(drive); + unsigned long sc_base = hwif->config_data; + u16 scr1; + + /* System Control 1 Register bit 11 (ATA Hard Reset) read */ + scr1 = hwif->INW(sc_base + 0x00); + + switch (state) { + case BUSSTATE_ON: + if (!(scr1 & 0x0800)) + return 0; + scr1 &= ~0x0800; + + hwif->drives[0].failures = hwif->drives[1].failures = 0; + break; + case BUSSTATE_OFF: + if (scr1 & 0x0800) + return 0; + scr1 |= 0x0800; + + hwif->drives[0].failures = hwif->drives[0].max_failures + 1; + hwif->drives[1].failures = hwif->drives[1].max_failures + 1; + break; + default: + return -EINVAL; + } + + /* System Control 1 Register bit 11 (ATA Hard Reset) write */ + hwif->OUTW(scr1, sc_base + 0x00); + return 0; +} + +static int config_chipset_for_dma(ide_drive_t *drive) +{ + u8 speed = ide_dma_speed(drive, tc86c001_ratemask(drive)); + + if (!speed) + return 0; + + (void) tc86c001_tune_chipset(drive, speed); + return ide_dma_enable(drive); +} + +static int tc86c001_config_drive_xfer_rate(ide_drive_t *drive) +{ + ide_hwif_t *hwif = HWIF(drive); + struct hd_driveid *id = drive->id; + + if ((id->capability & 1) && drive->autodma) { + + if (ide_use_dma(drive) && config_chipset_for_dma(drive)) + return hwif->ide_dma_on(drive); + + goto fast_ata_pio; + + } else if ((id->capability & 8) || (id->field_valid & 2)) { +fast_ata_pio: + tc86c001_tune_drive(drive, 255); + return hwif->ide_dma_off_quietly(drive); + } + /* IORDY not supported */ + return 0; +} + +static void __devinit init_hwif_tc86c001(ide_hwif_t *hwif) +{ + unsigned long sc_base = pci_resource_start(hwif->pci_dev, 5); + u16 scr1 = hwif->INW(sc_base + 0x00);; + + /* System Control 1 Register bit 15 (Soft Reset) set */ + hwif->OUTW(scr1 | 0x8000, sc_base + 0x00); + + /* System Control 1 Register bit 14 (FIFO Reset) set */ + hwif->OUTW(scr1 | 0x4000, sc_base + 0x00); + + /* System Control 1 Register: reset clear */ + hwif->OUTW(scr1 & ~0xc000, sc_base + 0x00); + + /* Store the system control register base for convenience... */ + hwif->config_data = sc_base; + + hwif->tuneproc = &tc86c001_tune_drive; + hwif->speedproc = &tc86c001_tune_chipset; + hwif->busproc = &tc86c001_busproc; + + hwif->drives[0].autotune = hwif->drives[1].autotune = 1; + + if (!hwif->dma_base) + return; + + /* + * Sector Count Control Register bits 0 and 1 set: + * software sets Sector Count Register for master and slave device + */ + hwif->OUTW(0x0003, sc_base + 0x0c); + + /* Sector Count Register limit */ + hwif->rqsize = 0xffff; + + hwif->atapi_dma = 1; + hwif->ultra_mask = 0x1f; + hwif->mwdma_mask = 0x07; + + hwif->ide_dma_check = &tc86c001_config_drive_xfer_rate; + hwif->dma_start = &tc86c001_dma_start; + + if (!hwif->udma_four) { + /* + * System Control 1 Register bit 13 (PDIAGN): + * 0=80-pin cable, 1=40-pin cable + */ + scr1 = hwif->INW(sc_base + 0x00); + hwif->udma_four = (scr1 & 0x2000) ? 0 : 1; + } + + if (!noautodma) + hwif->autodma = 1; + hwif->drives[0].autodma = hwif->drives[1].autodma = hwif->autodma; +} + +static unsigned int __devinit init_chipset_tc86c001(struct pci_dev *dev, + const char *name) +{ + int err = pci_request_region(dev, 5, name); + + if (err) + printk(KERN_ERR "%s: system control regs already in use", name); + return err; +} + +static ide_pci_device_t tc86c001_chipset __devinitdata = { + .name = "TC86C001", + .init_chipset = init_chipset_tc86c001, + .init_hwif = init_hwif_tc86c001, + .channels = 1, + .autodma = AUTODMA, + .bootable = OFF_BOARD +}; + +static int __devinit tc86c001_init_one(struct pci_dev *dev, + const struct pci_device_id *id) +{ + return ide_setup_pci_device(dev, &tc86c001_chipset); +} + +static struct pci_device_id tc86c001_pci_tbl[] = { + { PCI_VENDOR_ID_TOSHIBA_2, PCI_DEVICE_ID_TOSHIBA_TC86C001_IDE, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, + { 0, } +}; +MODULE_DEVICE_TABLE(pci, tc86c001_pci_tbl); + +static struct pci_driver driver = { + .name = "TC86C001", + .id_table = tc86c001_pci_tbl, + .probe = tc86c001_init_one +}; + +static int __init tc86c001_ide_init(void) +{ + return ide_pci_register_driver(&driver); +} +module_init(tc86c001_ide_init); + +MODULE_AUTHOR("MontaVista Software, Inc. "); +MODULE_DESCRIPTION("PCI driver module for TC86C001 IDE"); +MODULE_LICENSE("GPL"); diff --git a/drivers/ide/ppc/mpc8xx.c b/drivers/ide/ppc/mpc8xx.c index 0ac9da3..82de2d7 100644 --- a/drivers/ide/ppc/mpc8xx.c +++ b/drivers/ide/ppc/mpc8xx.c @@ -12,7 +12,6 @@ */ #include -#include #include #include #include diff --git a/drivers/ide/ppc/pmac.c b/drivers/ide/ppc/pmac.c index 91c5344..d8ea237 100644 --- a/drivers/ide/ppc/pmac.c +++ b/drivers/ide/ppc/pmac.c @@ -24,7 +24,6 @@ */ #include #include -#include #include #include #include diff --git a/drivers/ide/setup-pci.c b/drivers/ide/setup-pci.c index 695e239..a52c80f 100644 --- a/drivers/ide/setup-pci.c +++ b/drivers/ide/setup-pci.c @@ -783,10 +783,11 @@ static LIST_HEAD(ide_pci_drivers); * Returns are the same as for pci_register_driver */ -int __ide_pci_register_driver(struct pci_driver *driver, struct module *module) +int __ide_pci_register_driver(struct pci_driver *driver, struct module *module, + const char *mod_name) { if(!pre_init) - return __pci_register_driver(driver, module); + return __pci_register_driver(driver, module, mod_name); driver->driver.owner = module; list_add_tail(&driver->node, &ide_pci_drivers); return 0; @@ -862,6 +863,6 @@ void __init ide_scan_pcibus (int scan_di { list_del(l); d = list_entry(l, struct pci_driver, node); - __pci_register_driver(d, d->driver.owner); + __pci_register_driver(d, d->driver.owner, d->driver.mod_name); } } diff --git a/drivers/ieee1394/.gitignore b/drivers/ieee1394/.gitignore deleted file mode 100644 index 33da10a..0000000 --- a/drivers/ieee1394/.gitignore +++ /dev/null @@ -1 +0,0 @@ -oui.c diff --git a/drivers/ieee1394/Kconfig b/drivers/ieee1394/Kconfig index e7d5657..b8a4734 100644 --- a/drivers/ieee1394/Kconfig +++ b/drivers/ieee1394/Kconfig @@ -35,20 +35,6 @@ config IEEE1394_VERBOSEDEBUG Say Y if you really want or need the debugging output, everyone else says N. -config IEEE1394_OUI_DB - bool "OUI Database built-in (deprecated)" - depends on IEEE1394 - help - If you say Y here, then an OUI list (vendor unique ID's) will be - compiled into the ieee1394 module. This doesn't really do much - except being able to display the vendor of a hardware node. The - downside is that it adds about 300k to the size of the module, - or kernel (depending on whether you compile ieee1394 as a - module, or static in the kernel). - - This option is not needed for userspace programs like gscanbus - to show this information. - config IEEE1394_EXTRA_CONFIG_ROMS bool "Build in extra config rom entries for certain functionality" depends on IEEE1394 @@ -66,13 +52,6 @@ config IEEE1394_CONFIG_ROM_IP1394 with MacOSX and WinXP IP-over-1394), enable this option and the eth1394 option below. -config IEEE1394_EXPORT_FULL_API - bool "Export all symbols of ieee1394's API (deprecated)" - depends on IEEE1394 - default n - help - This option will be removed soon. Don't worry, say N. - comment "Device Drivers" depends on IEEE1394 diff --git a/drivers/ieee1394/Makefile b/drivers/ieee1394/Makefile index d9650d3..489c133 100644 --- a/drivers/ieee1394/Makefile +++ b/drivers/ieee1394/Makefile @@ -5,9 +5,6 @@ # ieee1394-objs := ieee1394_core.o ieee1394_transactions.o hosts.o \ highlevel.o csr.o nodemgr.o dma.o iso.o \ csr1212.o config_roms.o -ifdef CONFIG_IEEE1394_OUI_DB -ieee1394-objs += oui.o -endif obj-$(CONFIG_IEEE1394) += ieee1394.o obj-$(CONFIG_IEEE1394_PCILYNX) += pcilynx.o @@ -18,10 +15,3 @@ obj-$(CONFIG_IEEE1394_SBP2) += sbp2.o obj-$(CONFIG_IEEE1394_DV1394) += dv1394.o obj-$(CONFIG_IEEE1394_ETH1394) += eth1394.o -quiet_cmd_oui2c = OUI2C $@ - cmd_oui2c = $(CONFIG_SHELL) $(srctree)/$(src)/oui2c.sh < $< > $@ - -targets := oui.c -$(obj)/oui.o: $(obj)/oui.c -$(obj)/oui.c: $(src)/oui.db $(src)/oui2c.sh FORCE - $(call if_changed,oui2c) diff --git a/drivers/ieee1394/csr1212.c b/drivers/ieee1394/csr1212.c index 586f71e..c28f639 100644 --- a/drivers/ieee1394/csr1212.c +++ b/drivers/ieee1394/csr1212.c @@ -47,14 +47,14 @@ #define __C (1 << CSR1212_KV_TYPE_CSR_OF #define __D (1 << CSR1212_KV_TYPE_DIRECTORY) #define __L (1 << CSR1212_KV_TYPE_LEAF) static const u_int8_t csr1212_key_id_type_map[0x30] = { - 0, /* Reserved */ + __C, /* used by Apple iSight */ __D | __L, /* Descriptor */ __I | __D | __L, /* Bus_Dependent_Info */ __I | __D | __L, /* Vendor */ __I, /* Hardware_Version */ 0, 0, /* Reserved */ - __D | __L, /* Module */ - 0, 0, 0, 0, /* Reserved */ + __D | __L | __I, /* Module */ + __I, 0, 0, 0, /* used by Apple iSight, Reserved */ __I, /* Node_Capabilities */ __L, /* EUI_64 */ 0, 0, 0, /* Reserved */ @@ -1234,6 +1234,12 @@ static int csr1212_parse_bus_info_block( csr->private); if (ret != CSR1212_SUCCESS) return ret; + + /* check ROM header's info_length */ + if (i == 0 && + CSR1212_BE32_TO_CPU(csr->cache_head->data[0]) >> 24 != + bytes_to_quads(csr->bus_info_len) - 1) + return CSR1212_EINVAL; } bi = (struct csr1212_bus_info_block_img*)csr->cache_head->data; @@ -1250,9 +1256,6 @@ static int csr1212_parse_bus_info_block( return ret; } - if (bytes_to_quads(csr->bus_info_len - sizeof(csr1212_quad_t)) != bi->length) - return CSR1212_EINVAL; - #if 0 /* Apparently there are too many differnt wrong implementations of the * CRC algorithm that verifying them is moot. */ diff --git a/drivers/ieee1394/dv1394.c b/drivers/ieee1394/dv1394.c index 1084da4..dee9529 100644 --- a/drivers/ieee1394/dv1394.c +++ b/drivers/ieee1394/dv1394.c @@ -2147,7 +2147,7 @@ out: } static struct cdev dv1394_cdev; -static struct file_operations dv1394_fops= +static const struct file_operations dv1394_fops= { .owner = THIS_MODULE, .poll = dv1394_poll, @@ -2255,49 +2255,37 @@ static int dv1394_init(struct ti_ohci *o return 0; } -static void dv1394_un_init(struct video_card *video) +static void dv1394_remove_host(struct hpsb_host *host) { - /* obviously nobody has the driver open at this point */ - do_dv1394_shutdown(video, 1); - kfree(video); -} - - -static void dv1394_remove_host (struct hpsb_host *host) -{ - struct video_card *video; + struct video_card *video, *tmp_video; unsigned long flags; - int id = host->id; + int found_ohci_card = 0; - /* We only work with the OHCI-1394 driver */ - if (strcmp(host->driver->name, OHCI1394_DRIVER_NAME)) - return; - - /* find the corresponding video_cards */ do { - struct video_card *tmp_vid; - video = NULL; - spin_lock_irqsave(&dv1394_cards_lock, flags); - list_for_each_entry(tmp_vid, &dv1394_cards, list) { - if ((tmp_vid->id >> 2) == id) { - list_del(&tmp_vid->list); - video = tmp_vid; + list_for_each_entry(tmp_video, &dv1394_cards, list) { + if ((tmp_video->id >> 2) == host->id) { + list_del(&tmp_video->list); + video = tmp_video; + found_ohci_card = 1; break; } } spin_unlock_irqrestore(&dv1394_cards_lock, flags); - if (video) - dv1394_un_init(video); - } while (video != NULL); + if (video) { + do_dv1394_shutdown(video, 1); + kfree(video); + } + } while (video); - class_device_destroy(hpsb_protocol_class, - MKDEV(IEEE1394_MAJOR, IEEE1394_MINOR_BLOCK_DV1394 * 16 + (id<<2))); + if (found_ohci_card) + class_device_destroy(hpsb_protocol_class, MKDEV(IEEE1394_MAJOR, + IEEE1394_MINOR_BLOCK_DV1394 * 16 + (host->id << 2))); } -static void dv1394_add_host (struct hpsb_host *host) +static void dv1394_add_host(struct hpsb_host *host) { struct ti_ohci *ohci; int id = host->id; diff --git a/drivers/ieee1394/eth1394.c b/drivers/ieee1394/eth1394.c index 97e5c3d..a953135 100644 --- a/drivers/ieee1394/eth1394.c +++ b/drivers/ieee1394/eth1394.c @@ -43,7 +43,6 @@ #include -#include #include #include #include diff --git a/drivers/ieee1394/hosts.c b/drivers/ieee1394/hosts.c index ee82a53..32a1309 100644 --- a/drivers/ieee1394/hosts.c +++ b/drivers/ieee1394/hosts.c @@ -190,14 +190,19 @@ int hpsb_add_host(struct hpsb_host *host { if (hpsb_default_host_entry(host)) return -ENOMEM; - hpsb_add_extra_config_roms(host); - highlevel_add_host(host); - return 0; } +void hpsb_resume_host(struct hpsb_host *host) +{ + if (host->driver->set_hw_config_rom) + host->driver->set_hw_config_rom(host, + host->csr.rom->bus_info_data); + host->driver->devctl(host, RESET_BUS, SHORT_RESET); +} + void hpsb_remove_host(struct hpsb_host *host) { host->is_shutdown = 1; @@ -206,9 +211,7 @@ void hpsb_remove_host(struct hpsb_host * flush_scheduled_work(); host->driver = &dummy_driver; - highlevel_remove_host(host); - hpsb_remove_extra_config_roms(host); class_device_unregister(&host->class_dev); diff --git a/drivers/ieee1394/hosts.h b/drivers/ieee1394/hosts.h index d553e38..4bf4fb7 100644 --- a/drivers/ieee1394/hosts.h +++ b/drivers/ieee1394/hosts.h @@ -61,9 +61,9 @@ struct hpsb_host { struct device device; struct class_device class_dev; - int update_config_rom; struct delayed_work delayed_reset; - unsigned int config_roms; + unsigned config_roms:31; + unsigned update_config_rom:1; struct list_head addr_space; u64 low_addr_space; /* upper bound of physical DMA area */ @@ -200,7 +200,8 @@ struct hpsb_host_driver { struct hpsb_host *hpsb_alloc_host(struct hpsb_host_driver *drv, size_t extra, struct device *dev); int hpsb_add_host(struct hpsb_host *host); -void hpsb_remove_host(struct hpsb_host *h); +void hpsb_resume_host(struct hpsb_host *host); +void hpsb_remove_host(struct hpsb_host *host); /* Updates the configuration rom image of a host. rom_version must be the * current version, otherwise it will fail with return value -1. If this diff --git a/drivers/ieee1394/ieee1394_core.c b/drivers/ieee1394/ieee1394_core.c index 9a48ca2..1521e57 100644 --- a/drivers/ieee1394/ieee1394_core.c +++ b/drivers/ieee1394/ieee1394_core.c @@ -1178,6 +1178,7 @@ module_exit(ieee1394_cleanup); /** hosts.c **/ EXPORT_SYMBOL(hpsb_alloc_host); EXPORT_SYMBOL(hpsb_add_host); +EXPORT_SYMBOL(hpsb_resume_host); EXPORT_SYMBOL(hpsb_remove_host); EXPORT_SYMBOL(hpsb_update_config_rom_image); @@ -1195,10 +1196,6 @@ EXPORT_SYMBOL(hpsb_selfid_complete); EXPORT_SYMBOL(hpsb_packet_sent); EXPORT_SYMBOL(hpsb_packet_received); EXPORT_SYMBOL_GPL(hpsb_disable_irm); -#ifdef CONFIG_IEEE1394_EXPORT_FULL_API -EXPORT_SYMBOL(hpsb_send_phy_config); -EXPORT_SYMBOL(hpsb_send_packet_and_wait); -#endif /** ieee1394_transactions.c **/ EXPORT_SYMBOL(hpsb_get_tlabel); @@ -1229,20 +1226,12 @@ EXPORT_SYMBOL(hpsb_set_hostinfo_key); EXPORT_SYMBOL(hpsb_get_hostinfo_bykey); EXPORT_SYMBOL(hpsb_set_hostinfo); EXPORT_SYMBOL(highlevel_host_reset); -#ifdef CONFIG_IEEE1394_EXPORT_FULL_API -EXPORT_SYMBOL(highlevel_add_host); -EXPORT_SYMBOL(highlevel_remove_host); -#endif /** nodemgr.c **/ EXPORT_SYMBOL(hpsb_node_fill_packet); EXPORT_SYMBOL(hpsb_node_write); EXPORT_SYMBOL(__hpsb_register_protocol); EXPORT_SYMBOL(hpsb_unregister_protocol); -#ifdef CONFIG_IEEE1394_EXPORT_FULL_API -EXPORT_SYMBOL(ieee1394_bus_type); -EXPORT_SYMBOL(nodemgr_for_each_host); -#endif /** csr.c **/ EXPORT_SYMBOL(hpsb_update_config_rom); @@ -1287,13 +1276,3 @@ EXPORT_SYMBOL(csr1212_read); EXPORT_SYMBOL(csr1212_parse_keyval); EXPORT_SYMBOL(_csr1212_read_keyval); EXPORT_SYMBOL(_csr1212_destroy_keyval); -#ifdef CONFIG_IEEE1394_EXPORT_FULL_API -EXPORT_SYMBOL(csr1212_create_csr); -EXPORT_SYMBOL(csr1212_init_local_csr); -EXPORT_SYMBOL(csr1212_new_immediate); -EXPORT_SYMBOL(csr1212_associate_keyval); -EXPORT_SYMBOL(csr1212_new_string_descriptor_leaf); -EXPORT_SYMBOL(csr1212_destroy_csr); -EXPORT_SYMBOL(csr1212_generate_csr_image); -EXPORT_SYMBOL(csr1212_parse_csr); -#endif diff --git a/drivers/ieee1394/iso.c b/drivers/ieee1394/iso.c index 08bd15d..c6227e5 100644 --- a/drivers/ieee1394/iso.c +++ b/drivers/ieee1394/iso.c @@ -10,7 +10,6 @@ */ #include -#include #include #include "hosts.h" diff --git a/drivers/ieee1394/nodemgr.c b/drivers/ieee1394/nodemgr.c index 61307ca..ba9faef 100644 --- a/drivers/ieee1394/nodemgr.c +++ b/drivers/ieee1394/nodemgr.c @@ -41,22 +41,6 @@ struct nodemgr_csr_info { }; -static char *nodemgr_find_oui_name(int oui) -{ -#ifdef CONFIG_IEEE1394_OUI_DB - extern struct oui_list_struct { - int oui; - char *name; - } oui_list[]; - int i; - - for (i = 0; oui_list[i].name; i++) - if (oui_list[i].oui == oui) - return oui_list[i].name; -#endif - return NULL; -} - /* * Correct the speed map entry. This is necessary * - for nodes with link speed < phy speed, @@ -274,7 +258,6 @@ static struct device_driver nodemgr_mid_ struct device nodemgr_dev_template_host = { .bus = &ieee1394_bus_type, .release = nodemgr_release_host, - .driver = &nodemgr_mid_layer_driver, }; @@ -473,11 +456,9 @@ fw_attr(ne, struct node_entry, nodeid, u fw_attr(ne, struct node_entry, vendor_id, unsigned int, "0x%06x\n") fw_attr_td(ne, struct node_entry, vendor_name_kv) -fw_attr(ne, struct node_entry, vendor_oui, const char *, "%s\n") fw_attr(ne, struct node_entry, guid, unsigned long long, "0x%016Lx\n") fw_attr(ne, struct node_entry, guid_vendor_id, unsigned int, "0x%06x\n") -fw_attr(ne, struct node_entry, guid_vendor_oui, const char *, "%s\n") fw_attr(ne, struct node_entry, in_limbo, int, "%d\n"); static struct device_attribute *const fw_ne_attrs[] = { @@ -503,7 +484,6 @@ fw_attr(ud, struct unit_directory, model fw_attr(ud, struct unit_directory, specifier_id, unsigned int, "0x%06x\n") fw_attr(ud, struct unit_directory, version, unsigned int, "0x%06x\n") fw_attr_td(ud, struct unit_directory, vendor_name_kv) -fw_attr(ud, struct unit_directory, vendor_oui, const char *, "%s\n") fw_attr_td(ud, struct unit_directory, model_name_kv) static struct device_attribute *const fw_ud_attrs[] = { @@ -865,7 +845,6 @@ static struct node_entry *nodemgr_create ne->guid = guid; ne->guid_vendor_id = (guid >> 40) & 0xffffff; - ne->guid_vendor_oui = nodemgr_find_oui_name(ne->guid_vendor_id); ne->csr = csr; memcpy(&ne->device, &nodemgr_dev_template_ne, @@ -885,9 +864,6 @@ static struct node_entry *nodemgr_create goto fail_classdevreg; get_device(&ne->device); - if (ne->guid_vendor_oui && - device_create_file(&ne->device, &dev_attr_ne_guid_vendor_oui)) - goto fail_addoiu; nodemgr_create_ne_dev_files(ne); nodemgr_update_bus_options(ne); @@ -898,8 +874,6 @@ static struct node_entry *nodemgr_create return ne; -fail_addoiu: - put_device(&ne->device); fail_classdevreg: device_unregister(&ne->device); fail_devreg: @@ -975,15 +949,10 @@ static void nodemgr_register_device(stru goto fail_classdevreg; get_device(&ud->device); - if (ud->vendor_oui && - device_create_file(&ud->device, &dev_attr_ud_vendor_oui)) - goto fail_addoui; nodemgr_create_ud_dev_files(ud); return; -fail_addoui: - put_device(&ud->device); fail_classdevreg: device_unregister(&ud->device); fail_devreg: @@ -1020,9 +989,6 @@ static struct unit_directory *nodemgr_pr if (kv->key.type == CSR1212_KV_TYPE_IMMEDIATE) { ud->vendor_id = kv->value.immediate; ud->flags |= UNIT_DIRECTORY_VENDOR_ID; - - if (ud->vendor_id) - ud->vendor_oui = nodemgr_find_oui_name(ud->vendor_id); } break; @@ -1153,9 +1119,6 @@ static void nodemgr_process_root_directo switch (kv->key.id) { case CSR1212_KV_ID_VENDOR: ne->vendor_id = kv->value.immediate; - - if (ne->vendor_id) - ne->vendor_oui = nodemgr_find_oui_name(ne->vendor_id); break; case CSR1212_KV_ID_NODE_CAPABILITIES: @@ -1183,9 +1146,6 @@ static void nodemgr_process_root_directo last_key_id = kv->key.id; } - if (ne->vendor_oui && - device_create_file(&ne->device, &dev_attr_ne_vendor_oui)) - goto fail; if (ne->vendor_name_kv && device_create_file(&ne->device, &dev_attr_ne_vendor_name_kv)) goto fail; @@ -1889,22 +1849,31 @@ int init_ieee1394_nodemgr(void) error = class_register(&nodemgr_ne_class); if (error) - return error; - + goto fail_ne; error = class_register(&nodemgr_ud_class); - if (error) { - class_unregister(&nodemgr_ne_class); - return error; - } + if (error) + goto fail_ud; error = driver_register(&nodemgr_mid_layer_driver); + if (error) + goto fail_ml; + /* This driver is not used if nodemgr is off (disable_nodemgr=1). */ + nodemgr_dev_template_host.driver = &nodemgr_mid_layer_driver; + hpsb_register_highlevel(&nodemgr_highlevel); return 0; + +fail_ml: + class_unregister(&nodemgr_ud_class); +fail_ud: + class_unregister(&nodemgr_ne_class); +fail_ne: + return error; } void cleanup_ieee1394_nodemgr(void) { hpsb_unregister_highlevel(&nodemgr_highlevel); - + driver_unregister(&nodemgr_mid_layer_driver); class_unregister(&nodemgr_ud_class); class_unregister(&nodemgr_ne_class); } diff --git a/drivers/ieee1394/nodemgr.h b/drivers/ieee1394/nodemgr.h index e25cbad..4147303 100644 --- a/drivers/ieee1394/nodemgr.h +++ b/drivers/ieee1394/nodemgr.h @@ -70,7 +70,6 @@ struct unit_directory { quadlet_t vendor_id; struct csr1212_keyval *vendor_name_kv; - const char *vendor_oui; quadlet_t model_id; struct csr1212_keyval *model_name_kv; @@ -93,7 +92,6 @@ struct unit_directory { struct node_entry { u64 guid; /* GUID of this node */ u32 guid_vendor_id; /* Top 24bits of guid */ - const char *guid_vendor_oui; /* OUI name of guid vendor id */ struct hpsb_host *host; /* Host this node is attached to */ nodeid_t nodeid; /* NodeID */ @@ -104,7 +102,6 @@ struct node_entry { /* The following is read from the config rom */ u32 vendor_id; struct csr1212_keyval *vendor_name_kv; - const char *vendor_oui; u32 capabilities; diff --git a/drivers/ieee1394/ohci1394.c b/drivers/ieee1394/ohci1394.c index 628130a..e982d60 100644 --- a/drivers/ieee1394/ohci1394.c +++ b/drivers/ieee1394/ohci1394.c @@ -102,7 +102,6 @@ #include #include #include #include -#include #include #include #include @@ -3281,14 +3280,11 @@ #endif PRINT(KERN_WARNING, "PCI resource length of 0x%llx too small!", (unsigned long long)pci_resource_len(dev, 0)); - /* Seems PCMCIA handles this internally. Not sure why. Seems - * pretty bogus to force a driver to special case this. */ -#ifndef PCMCIA - if (!request_mem_region (ohci_base, OHCI1394_REGISTER_SIZE, OHCI1394_DRIVER_NAME)) + if (!request_mem_region(ohci_base, OHCI1394_REGISTER_SIZE, + OHCI1394_DRIVER_NAME)) FAIL(-ENOMEM, "MMIO resource (0x%llx - 0x%llx) unavailable", (unsigned long long)ohci_base, (unsigned long long)ohci_base + OHCI1394_REGISTER_SIZE); -#endif ohci->init_state = OHCI_INIT_HAVE_MEM_REGION; ohci->registers = ioremap(ohci_base, OHCI1394_REGISTER_SIZE); @@ -3509,10 +3505,8 @@ static void ohci1394_pci_remove(struct p iounmap(ohci->registers); case OHCI_INIT_HAVE_MEM_REGION: -#ifndef PCMCIA release_mem_region(pci_resource_start(ohci->dev, 0), OHCI1394_REGISTER_SIZE); -#endif #ifdef CONFIG_PPC_PMAC /* On UniNorth, power down the cable and turn off the chip clock @@ -3541,9 +3535,6 @@ static int ohci1394_pci_suspend(struct p int err; struct ti_ohci *ohci = pci_get_drvdata(pdev); - printk(KERN_INFO "%s does not fully support suspend and resume yet\n", - OHCI1394_DRIVER_NAME); - if (!ohci) { printk(KERN_ERR "%s: tried to suspend nonexisting host\n", OHCI1394_DRIVER_NAME); @@ -3630,15 +3621,14 @@ #endif /* CONFIG_PPC_PMAC */ mdelay(50); ohci_initialize(ohci); + hpsb_resume_host(ohci->host); return 0; } #endif /* CONFIG_PM */ -#define PCI_CLASS_FIREWIRE_OHCI ((PCI_CLASS_SERIAL_FIREWIRE << 8) | 0x10) - static struct pci_device_id ohci1394_pci_tbl[] = { { - .class = PCI_CLASS_FIREWIRE_OHCI, + .class = PCI_CLASS_SERIAL_FIREWIRE_OHCI, .class_mask = PCI_ANY_ID, .vendor = PCI_ANY_ID, .device = PCI_ANY_ID, diff --git a/drivers/ieee1394/oui.db b/drivers/ieee1394/oui.db deleted file mode 100644 index 592c8a6..0000000 --- a/drivers/ieee1394/oui.db +++ /dev/null @@ -1,7048 +0,0 @@ -000000 XEROX CORPORATION -000001 XEROX CORPORATION -000002 XEROX CORPORATION -000003 XEROX CORPORATION -000004 XEROX CORPORATION -000005 XEROX CORPORATION -000006 XEROX CORPORATION -000007 XEROX CORPORATION -000008 XEROX CORPORATION -000009 XEROX CORPORATION -00000A OMRON TATEISI ELECTRONICS CO. -00000B MATRIX CORPORATION -00000C CISCO SYSTEMS, INC. -00000D FIBRONICS LTD. -00000E FUJITSU LIMITED -00000F NEXT, INC. -000010 SYTEK INC. -000011 NORMEREL SYSTEMES -000012 INFORMATION TECHNOLOGY LIMITED -000013 CAMEX -000014 NETRONIX -000015 DATAPOINT CORPORATION -000016 DU PONT PIXEL SYSTEMS . -000017 TEKELEC -000018 WEBSTER COMPUTER CORPORATION -000019 APPLIED DYNAMICS INTERNATIONAL -00001A ADVANCED MICRO DEVICES -00001B NOVELL INC. -00001C BELL TECHNOLOGIES -00001D CABLETRON SYSTEMS, INC. -00001E TELSIST INDUSTRIA ELECTRONICA -00001F Telco Systems, Inc. -000020 DATAINDUSTRIER DIAB AB -000021 SUREMAN COMP. & COMMUN. CORP. -000022 VISUAL TECHNOLOGY INC. -000023 ABB INDUSTRIAL SYSTEMS AB -000024 CONNECT AS -000025 RAMTEK CORP. -000026 SHA-KEN CO., LTD. -000027 JAPAN RADIO COMPANY -000028 PRODIGY SYSTEMS CORPORATION -000029 IMC NETWORKS CORP. -00002A TRW - SEDD/INP -00002B CRISP AUTOMATION, INC -00002C AUTOTOTE LIMITED -00002D CHROMATICS INC -00002E SOCIETE EVIRA -00002F TIMEPLEX INC. -000030 VG LABORATORY SYSTEMS LTD -000031 QPSX COMMUNICATIONS PTY LTD -000032 Marconi plc -000033 EGAN MACHINERY COMPANY -000034 NETWORK RESOURCES CORPORATION -000035 SPECTRAGRAPHICS CORPORATION -000036 ATARI CORPORATION -000037 OXFORD METRICS LIMITED -000038 CSS LABS -000039 TOSHIBA CORPORATION -00003A CHYRON CORPORATION -00003B i Controls, Inc. -00003C AUSPEX SYSTEMS INC. -00003D UNISYS -00003E SIMPACT -00003F SYNTREX, INC. -000040 APPLICON, INC. -000041 ICE CORPORATION -000042 METIER MANAGEMENT SYSTEMS LTD. -000043 MICRO TECHNOLOGY -000044 CASTELLE CORPORATION -000045 FORD AEROSPACE & COMM. CORP. -000046 OLIVETTI NORTH AMERICA -000047 NICOLET INSTRUMENTS CORP. -000048 SEIKO EPSON CORPORATION -000049 APRICOT COMPUTERS, LTD -00004A ADC CODENOLL TECHNOLOGY CORP. -00004B ICL DATA OY -00004C NEC CORPORATION -00004D DCI CORPORATION -00004E AMPEX CORPORATION -00004F LOGICRAFT, INC. -000050 RADISYS CORPORATION -000051 HOB ELECTRONIC GMBH & CO. KG -000052 Intrusion.com, Inc. -000053 COMPUCORP -000054 MODICON, INC. -000055 COMMISSARIAT A L`ENERGIE ATOM. -000056 DR. B. STRUCK -000057 SCITEX CORPORATION LTD. -000058 RACORE COMPUTER PRODUCTS INC. -000059 HELLIGE GMBH -00005A SysKonnect GmbH -00005B ELTEC ELEKTRONIK AG -00005C TELEMATICS INTERNATIONAL INC. -00005D CS TELECOM -00005E USC INFORMATION SCIENCES INST -00005F SUMITOMO ELECTRIC IND., LTD. -000060 KONTRON ELEKTRONIK GMBH -000061 GATEWAY COMMUNICATIONS -000062 BULL HN INFORMATION SYSTEMS -000063 DR.ING.SEUFERT GMBH -000064 YOKOGAWA DIGITAL COMPUTER CORP -000065 NETWORK ASSOCIATES, INC. -000066 TALARIS SYSTEMS, INC. -000067 SOFT * RITE, INC. -000068 ROSEMOUNT CONTROLS -000069 CONCORD COMMUNICATIONS INC -00006A COMPUTER CONSOLES INC. -00006B SILICON GRAPHICS INC./MIPS -00006D CRAY COMMUNICATIONS, LTD. -00006E ARTISOFT, INC. -00006F Madge Ltd. -000070 HCL LIMITED -000071 ADRA SYSTEMS INC. -000072 MINIWARE TECHNOLOGY -000073 SIECOR CORPORATION -000074 RICOH COMPANY LTD. -000075 Nortel Networks -000076 ABEKAS VIDEO SYSTEM -000077 INTERPHASE CORPORATION -000078 LABTAM LIMITED -000079 NETWORTH INCORPORATED -00007A DANA COMPUTER INC. -00007B RESEARCH MACHINES -00007C AMPERE INCORPORATED -00007D SUN MICROSYSTEMS, INC. -00007E CLUSTRIX CORPORATION -00007F LINOTYPE-HELL AG -000080 CRAY COMMUNICATIONS A/S -000081 BAY NETWORKS -000082 LECTRA SYSTEMES SA -000083 TADPOLE TECHNOLOGY PLC -000084 SUPERNET -000085 CANON INC. -000086 MEGAHERTZ CORPORATION -000087 HITACHI, LTD. -000088 COMPUTER NETWORK TECH. CORP. -000089 CAYMAN SYSTEMS INC. -00008A DATAHOUSE INFORMATION SYSTEMS -00008B INFOTRON -00008C Alloy Computer Products (Australia) Pty Ltd -00008D VERDIX CORPORATION -00008E SOLBOURNE COMPUTER, INC. -00008F RAYTHEON COMPANY -000090 MICROCOM -000091 ANRITSU CORPORATION -000092 COGENT DATA TECHNOLOGIES -000093 PROTEON INC. -000094 ASANTE TECHNOLOGIES -000095 SONY TEKTRONIX CORP. -000096 MARCONI ELECTRONICS LTD. -000097 EPOCH SYSTEMS -000098 CROSSCOMM CORPORATION -000099 MTX, INC. -00009A RC COMPUTER A/S -00009B INFORMATION INTERNATIONAL, INC -00009C ROLM MIL-SPEC COMPUTERS -00009D LOCUS COMPUTING CORPORATION -00009E MARLI S.A. -00009F AMERISTAR TECHNOLOGIES INC. -0000A0 TOKYO SANYO ELECTRIC CO. LTD. -0000A1 MARQUETTE ELECTRIC CO. -0000A2 BAY NETWORKS -0000A3 NETWORK APPLICATION TECHNOLOGY -0000A4 ACORN COMPUTERS LIMITED -0000A5 COMPATIBLE SYSTEMS CORP. -0000A6 NETWORK GENERAL CORPORATION -0000A7 NETWORK COMPUTING DEVICES INC. -0000A8 STRATUS COMPUTER INC. -0000A9 NETWORK SYSTEMS CORP. -0000AA XEROX CORPORATION -0000AB LOGIC MODELING CORPORATION -0000AC CONWARE COMPUTER CONSULTING -0000AD BRUKER INSTRUMENTS INC. -0000AE DASSAULT ELECTRONIQUE -0000AF NUCLEAR DATA INSTRUMENTATION -0000B0 RND-RAD NETWORK DEVICES -0000B1 ALPHA MICROSYSTEMS INC. -0000B2 TELEVIDEO SYSTEMS, INC. -0000B3 CIMLINC INCORPORATED -0000B4 EDIMAX COMPUTER COMPANY -0000B5 DATABILITY SOFTWARE SYS. INC. -0000B6 MICRO-MATIC RESEARCH -0000B7 DOVE COMPUTER CORPORATION -0000B8 SEIKOSHA CO., LTD. -0000B9 MCDONNELL DOUGLAS COMPUTER SYS -0000BA SIIG, INC. -0000BB TRI-DATA -0000BC ALLEN-BRADLEY CO. INC. -0000BD MITSUBISHI CABLE COMPANY -0000BE THE NTI GROUP -0000BF SYMMETRIC COMPUTER SYSTEMS -0000C0 WESTERN DIGITAL CORPORATION -0000C1 Madge Ltd. -0000C2 INFORMATION PRESENTATION TECH. -0000C3 HARRIS CORP COMPUTER SYS DIV -0000C4 WATERS DIV. OF MILLIPORE -0000C5 FARALLON COMPUTING/NETOPIA -0000C6 EON SYSTEMS -0000C7 ARIX CORPORATION -0000C8 ALTOS COMPUTER SYSTEMS -0000C9 EMULEX CORPORATION -0000CA APPLITEK -0000CB COMPU-SHACK ELECTRONIC GMBH -0000CC DENSAN CO., LTD. -0000CD Allied Telesyn Research Ltd. -0000CE MEGADATA CORP. -0000CF HAYES MICROCOMPUTER PRODUCTS -0000D0 DEVELCON ELECTRONICS LTD. -0000D1 ADAPTEC INCORPORATED -0000D2 SBE, INC. -0000D3 WANG LABORATORIES INC. -0000D4 PURE DATA LTD. -0000D5 MICROGNOSIS INTERNATIONAL -0000D6 PUNCH LINE HOLDING -0000D7 DARTMOUTH COLLEGE -0000D8 NOVELL, INC. -0000D9 NIPPON TELEGRAPH & TELEPHONE -0000DA ATEX -0000DB BRITISH TELECOMMUNICATIONS PLC -0000DC HAYES MICROCOMPUTER PRODUCTS -0000DD TCL INCORPORATED -0000DE CETIA -0000DF BELL & HOWELL PUB SYS DIV -0000E0 QUADRAM CORP. -0000E1 GRID SYSTEMS -0000E2 ACER TECHNOLOGIES CORP. -0000E3 INTEGRATED MICRO PRODUCTS LTD -0000E4 IN2 GROUPE INTERTECHNIQUE -0000E5 SIGMEX LTD. -0000E6 APTOR PRODUITS DE COMM INDUST -0000E7 STAR GATE TECHNOLOGIES -0000E8 ACCTON TECHNOLOGY CORP. -0000E9 ISICAD, INC. -0000EA UPNOD AB -0000EB MATSUSHITA COMM. IND. CO. LTD. -0000EC MICROPROCESS -0000ED APRIL -0000EE NETWORK DESIGNERS, LTD. -0000EF KTI -0000F0 SAMSUNG ELECTRONICS CO., LTD. -0000F1 MAGNA COMPUTER CORPORATION -0000F2 SPIDER COMMUNICATIONS -0000F3 GANDALF DATA LIMITED -0000F4 ALLIED TELESYN INTERNATIONAL -0000F5 DIAMOND SALES LIMITED -0000F6 APPLIED MICROSYSTEMS CORP. -0000F7 YOUTH KEEP ENTERPRISE CO LTD -0000F8 DIGITAL EQUIPMENT CORPORATION -0000F9 QUOTRON SYSTEMS INC. -0000FA MICROSAGE COMPUTER SYSTEMS INC -0000FB RECHNER ZUR KOMMUNIKATION -0000FC MEIKO -0000FD HIGH LEVEL HARDWARE -0000FE ANNAPOLIS MICRO SYSTEMS -0000FF CAMTEC ELECTRONICS LTD. -000100 EQUIP'TRANS -000102 3COM CORPORATION -000103 3COM CORPORATION -000104 DVICO Co., Ltd. -000105 BECKHOFF GmbH -000106 Tews Datentechnik GmbH -000107 Leiser GmbH -000108 AVLAB Technology, Inc. -000109 Nagano Japan Radio Co., Ltd. -00010A CIS TECHNOLOGY INC. -00010B Space CyberLink, Inc. -00010C System Talks Inc. -00010D CORECO, INC. -00010E Bri-Link Technologies Co., Ltd -00010F Nishan Systems, Inc. -000110 Gotham Networks -000111 iDigm Inc. -000112 Shark Multimedia Inc. -000113 OLYMPUS CORPORATION -000114 KANDA TSUSHIN KOGYO CO., LTD. -000115 EXTRATECH CORPORATION -000116 Netspect Technologies, Inc. -000117 CANAL + -000118 EZ Digital Co., Ltd. -000119 Action Controls Pty. Ltd. -00011A EEH DataLink GmbH -00011B Unizone Technologies, Inc. -00011C Universal Talkware Corporation -00011D Centillium Communications -00011E Precidia Technologies, Inc. -00011F RC Networks, Inc. -000120 OSCILLOQUARTZ S.A. -000121 RapidStream Inc. -000122 Trend Communications, Ltd. -000123 DIGITAL ELECTRONICS CORP. -000124 Acer Incorporated -000125 YAESU MUSEN CO., LTD. -000126 PAC Labs -000127 The OPEN Group Limited -000128 EnjoyWeb, Inc. -000129 DFI Inc. -00012A Telematica Sistems Inteligente -00012B TELENET Co., Ltd. -00012C Aravox Technologies, Inc. -00012D Komodo Technology -00012E PC Partner Ltd. -00012F Twinhead International Corp -000130 Extreme Networks -000131 Detection Systems, Inc. -000132 Dranetz - BMI -000133 KYOWA Electronic Instruments C -000134 SIG Positec Systems AG -000135 KDC Corp. -000136 CyberTAN Technology, Inc. -000137 IT Farm Corporation -000138 XAVi Technologies Corp. -000139 Point Multimedia Systems -00013A SHELCAD COMMUNICATIONS, LTD. -00013B BNA SYSTEMS -00013C TIW SYSTEMS -00013D RiscStation Ltd. -00013E Ascom Tateco AB -00013F Neighbor World Co., Ltd. -000140 Sendtek Corporation -000141 CABLE PRINT -000142 Cisco Systems, Inc. -000143 Cisco Systems, Inc. -000144 Cereva Networks, Inc. -000145 WINSYSTEMS, INC. -000146 Tesco Controls, Inc. -000147 Zhone Technologies -000148 X-traWeb Inc. -000149 T.D.T. Transfer Data Test GmbH -00014A SONY COMPUTER SCIENCE LABS., I -00014B Ennovate Networks, Inc. -00014C Berkeley Process Control -00014D Shin Kin Enterprises Co., Ltd -00014E WIN Enterprises, Inc. -00014F LUMINOUS Networks, Inc. -000150 GILAT COMMUNICATIONS, LTD. -000151 Ensemble Communications -000152 CHROMATEK INC. -000153 ARCHTEK TELECOM CORPORATION -000154 G3M Corporation -000155 Promise Technology, Inc. -000156 FIREWIREDIRECT.COM, INC. -000157 SYSWAVE CO., LTD -000158 Electro Industries/Gauge Tech -000159 S1 Corporation -00015A Digital Video Broadcasting -00015B ITALTEL S.p.A/RF-UP-I -00015C CADANT INC. -00015D Sun Microsystems, Inc -00015E BEST TECHNOLOGY CO., LTD. -00015F DIGITAL DESIGN GmbH -000160 ELMEX Co., LTD. -000161 Meta Machine Technology -000162 Cygnet Technologies, Inc. -000163 Cisco Systems, Inc. -000164 Cisco Systems, Inc. -000165 AirSwitch Corporation -000166 TC GROUP A/S -000167 HIOKI E.E. CORPORATION -000168 VITANA CORPORATION -000169 Celestix Networks Pte Ltd. -00016A ALITEC -00016B LightChip, Inc. -00016C FOXCONN -00016D CarrierComm Inc. -00016E Conklin Corporation -00016F HAITAI ELECTRONICS CO., LTD. -000170 ESE Embedded System Engineer'g -000171 Allied Data Technologies -000172 TechnoLand Co., LTD. -000173 JNI Corporation -000174 CyberOptics Corporation -000175 Radiant Communications Corp. -000176 Orient Silver Enterprises -000177 EDSL -000178 MARGI Systems, Inc. -000179 WIRELESS TECHNOLOGY, INC. -00017A Chengdu Maipu Electric Industrial Co., Ltd. -00017B Heidelberger Druckmaschinen AG -00017C AG-E GmbH -00017D ThermoQuest -00017E ADTEK System Science Co., Ltd. -00017F Experience Music Project -000180 AOpen, Inc. -000181 Nortel Networks -000182 DICA TECHNOLOGIES AG -000183 ANITE TELECOMS -000184 SIEB & MEYER AG -000185 Aloka Co., Ltd. -000186 DISCH GmbH -000187 i2SE GmbH -000188 LXCO Technologies ag -000189 Refraction Technology, Inc. -00018A ROI COMPUTER AG -00018B NetLinks Co., Ltd. -00018C Mega Vision -00018D AudeSi Technologies -00018E Logitec Corporation -00018F Kenetec, Inc. -000190 SMK-M -000191 SYRED Data Systems -000192 Texas Digital Systems -000193 Hanbyul Telecom Co., Ltd. -000194 Capital Equipment Corporation -000195 Sena Technologies, Inc. -000196 Cisco Systems, Inc. -000197 Cisco Systems, Inc. -000198 Darim Vision -000199 HeiSei Electronics -00019A LEUNIG GmbH -00019B Kyoto Microcomputer Co., Ltd. -00019C JDS Uniphase Inc. -00019D E-Control Systems, Inc. -00019E ESS Technology, Inc. -00019F Phonex Broadband -0001A0 Infinilink Corporation -0001A1 Mag-Tek, Inc. -0001A2 Logical Co., Ltd. -0001A3 GENESYS LOGIC, INC. -0001A4 Microlink Corporation -0001A5 Nextcomm, Inc. -0001A6 Scientific-Atlanta Arcodan A/S -0001A7 UNEX TECHNOLOGY CORPORATION -0001A8 Welltech Computer Co., Ltd. -0001A9 BMW AG -0001AA Airspan Communications, Ltd. -0001AB Main Street Networks -0001AC Sitara Networks, Inc. -0001AD Coach Master International d.b.a. CMI Worldwide, Inc. -0001AE Trex Enterprises -0001AF Motorola Computer Group -0001B0 Fulltek Technology Co., Ltd. -0001B1 General Bandwidth -0001B2 Digital Processing Systems, Inc. -0001B3 Precision Electronic Manufacturing -0001B4 Wayport, Inc. -0001B5 Turin Networks, Inc. -0001B6 SAEJIN T&M Co., Ltd. -0001B7 Centos, Inc. -0001B8 Netsensity, Inc. -0001B9 SKF Condition Monitoring -0001BA IC-Net, Inc. -0001BB Frequentis -0001BC Brains Corporation -0001BD Peterson Electro-Musical Products, Inc. -0001BE Gigalink Co., Ltd. -0001BF Teleforce Co., Ltd. -0001C0 CompuLab, Ltd. -0001C1 Vitesse Semiconductor Corporation -0001C2 ARK Research Corp. -0001C3 Acromag, Inc. -0001C4 NeoWave, Inc. -0001C5 Simpler Networks -0001C6 Quarry Technologies -0001C7 Cisco Systems, Inc. -0001C8 THOMAS CONRAD CORP. -0001C8 CONRAD CORP. -0001C9 Cisco Systems, Inc. -0001CA Geocast Network Systems, Inc. -0001CB NetGame, Ltd. -0001CC Japan Total Design Communication Co., Ltd. -0001CD ARtem -0001CE Custom Micro Products, Ltd. -0001CF Alpha Data Parallel Systems, Ltd. -0001D0 VitalPoint, Inc. -0001D1 CoNet Communications, Inc. -0001D2 MacPower Peripherals, Ltd. -0001D3 PAXCOMM, Inc. -0001D4 Leisure Time, Inc. -0001D5 HAEDONG INFO & COMM CO., LTD -0001D6 MAN Roland Druckmaschinen AG -0001D7 F5 Networks, Inc. -0001D8 Teltronics, Inc. -0001D9 Sigma, Inc. -0001DA WINCOMM Corporation -0001DB Freecom Technologies GmbH -0001DC Activetelco -0001DD Avail Networks -0001DE Trango Systems, Inc. -0001DF ISDN Communications, Ltd. -0001E0 Fast Systems, Inc. -0001E1 Kinpo Electronics, Inc. -0001E2 Ando Electric Corporation -0001E3 Siemens AG -0001E4 Sitera, Inc. -0001E5 Supernet, Inc. -0001E6 Hewlett-Packard Company -0001E7 Hewlett-Packard Company -0001E8 Force10 Networks, Inc. -0001E9 Litton Marine Systems B.V. -0001EA Cirilium Corp. -0001EB C-COM Corporation -0001EC Ericsson Group -0001ED SETA Corp. -0001EE Comtrol Europe, Ltd. -0001EF Camtel Technology Corp. -0001F0 Tridium, Inc. -0001F1 Innovative Concepts, Inc. -0001F2 Mark of the Unicorn, Inc. -0001F3 QPS, Inc. -0001F4 Enterasys Networks -0001F5 ERIM S.A. -0001F6 Association of Musical Electronics Industry -0001F7 Image Display Systems, Inc. -0001F8 Adherent Systems, Ltd. -0001F9 TeraGlobal Communications Corp. -0001FA HOROSCAS -0001FB DoTop Technology, Inc. -0001FC Keyence Corporation -0001FD Digital Voice Systems, Inc. -0001FE DIGITAL EQUIPMENT CORPORATION -0001FF Data Direct Networks, Inc. -000200 Net & Sys Co., Ltd. -000201 IFM Electronic gmbh -000202 Amino Communications, Ltd. -000203 Woonsang Telecom, Inc. -000204 Bodmann Industries Elektronik GmbH -000205 Hitachi Denshi, Ltd. -000206 Telital R&D Denmark A/S -000207 VisionGlobal Network Corp. -000208 Unify Networks, Inc. -000209 Shenzhen SED Information Technology Co., Ltd. -00020A Gefran Spa -00020B Native Networks, Inc. -00020C Metro-Optix -00020D Micronpc.com -00020E Laurel Networks, Inc. -00020F AATR -000210 Fenecom -000211 Nature Worldwide Technology Corp. -000212 SierraCom -000213 S.D.E.L. -000214 DTVRO -000215 Cotas Computer Technology A/B -000216 Cisco Systems, Inc. -000217 Cisco Systems, Inc. -000218 Advanced Scientific Corp -000219 Paralon Technologies -00021A Zuma Networks -00021B Kollmorgen-Servotronix -00021C Network Elements, Inc. -00021D Data General Communication Ltd. -00021E SIMTEL S.R.L. -00021F Aculab PLC -000220 Canon Aptex, Inc. -000221 DSP Application, Ltd. -000222 Chromisys, Inc. -000223 ClickTV -000224 Lantern Communications, Inc. -000225 Certus Technology, Inc. -000226 XESystems, Inc. -000227 ESD GmbH -000228 Necsom, Ltd. -000229 Adtec Corporation -00022A Asound Electronic -00022B Tamura Electric Works, Ltd. -00022C ABB Bomem, Inc. -00022D Agere Systems -00022E TEAC Corp. R& D -00022F P-Cube, Ltd. -000230 Intersoft Electronics -000231 Ingersoll-Rand -000232 Avision, Inc. -000233 Mantra Communications, Inc. -000234 Imperial Technology, Inc. -000235 Paragon Networks International -000236 INIT GmbH -000237 Cosmo Research Corp. -000238 Serome Technology, Inc. -000239 Visicom -00023A ZSK Stickmaschinen GmbH -00023B Redback Networks -00023C Creative Technology, Ltd. -00023D NuSpeed, Inc. -00023E Selta Telematica S.p.a -00023F Compal Electronics, Inc. -000240 Seedek Co., Ltd. -000241 Amer.com -000242 Videoframe Systems -000243 Raysis Co., Ltd. -000244 SURECOM Technology Co. -000245 Lampus Co, Ltd. -000246 All-Win Tech Co., Ltd. -000247 Great Dragon Information Technology (Group) Co., Ltd. -000248 Pilz GmbH & Co. -000249 Aviv Infocom Co, Ltd. -00024A Cisco Systems, Inc. -00024B Cisco Systems, Inc. -00024C SiByte, Inc. -00024D Mannesman Dematic Colby Pty. Ltd. -00024E Datacard Group -00024F IPM Datacom S.R.L. -000250 Geyser Networks, Inc. -000251 Soma Networks -000252 Carrier Corporation -000253 Televideo, Inc. -000254 WorldGate -000255 IBM Corporation -000256 Alpha Processor, Inc. -000257 Microcom Corp. -000258 Flying Packets Communications -000259 Tsann Kuen China (Shanghai)Enterprise Co., Ltd. IT Group -00025A Catena Networks -00025B Cambridge Silicon Radio -00025C SCI Systems (Kunshan) Co., Ltd. -00025D Calix Networks -00025E High Technology Ltd -00025F Nortel Networks -000260 Accordion Networks, Inc. -000261 i3 Micro Technology AB -000262 Soyo Group Soyo Com Tech Co., Ltd -000263 UPS Manufacturing SRL -000264 AudioRamp.com -000265 Virditech Co. Ltd. -000266 Thermalogic Corporation -000267 NODE RUNNER, INC. -000268 Harris Government Communications -000269 Nadatel Co., Ltd -00026A Cocess Telecom Co., Ltd. -00026B BCM Computers Co., Ltd. -00026C Philips CFT -00026D Adept Telecom -00026E NeGeN Access, Inc. -00026F Senao International Co., Ltd. -000270 Crewave Co., Ltd. -000271 Vpacket Communications -000272 CC&C Technologies, Inc. -000273 Coriolis Networks -000274 Tommy Technologies Corp. -000275 SMART Technologies, Inc. -000276 Primax Electronics Ltd. -000277 Cash Systemes Industrie -000278 Samsung Electro-Mechanics Co., Ltd. -000279 Control Applications, Ltd. -00027A IOI Technology Corporation -00027B Amplify Net, Inc. -00027C Trilithic, Inc. -00027D Cisco Systems, Inc. -00027E Cisco Systems, Inc. -00027F ask-technologies.com -000280 Mu Net, Inc. -000281 Madge Ltd. -000282 ViaClix, Inc. -000283 Spectrum Controls, Inc. -000284 Alstom T&D P&C -000285 Riverstone Networks -000286 Occam Networks -000287 Adapcom -000288 GLOBAL VILLAGE COMMUNICATION -000289 DNE Technologies -00028A Ambit Microsystems Corporation -00028B VDSL Systems OY -00028C Micrel-Synergy Semiconductor -00028D Movita Technologies, Inc. -00028E Rapid 5 Networks, Inc. -00028F Globetek, Inc. -000290 Woorigisool, Inc. -000291 Open Network Co., Ltd. -000292 Logic Innovations, Inc. -000293 Solid Data Systems -000294 Tokyo Sokushin Co., Ltd. -000295 IP.Access Limited -000296 Lectron Co,. Ltd. -000297 C-COR.net -000298 Broadframe Corporation -000299 Apex, Inc. -00029A Storage Apps -00029B Kreatel Communications AB -00029C 3COM -00029D Merix Corp. -00029E Information Equipment Co., Ltd. -00029F L-3 Communication Aviation Recorders -0002A0 Flatstack Ltd. -0002A1 World Wide Packets -0002A2 Hilscher GmbH -0002A3 ABB Power Automation -0002A4 AddPac Technology Co., Ltd. -0002A5 Compaq Computer Corporation -0002A6 Effinet Systems Co., Ltd. -0002A7 Vivace Networks -0002A8 Air Link Technology -0002A9 RACOM, s.r.o. -0002AA PLcom Co., Ltd. -0002AB CTC Union Technologies Co., Ltd. -0002AC 3PAR data -0002AD Pentax Corpotation -0002AE Scannex Electronics Ltd. -0002AF TeleCruz Technology, Inc. -0002B0 Hokubu Communication & Industrial Co., Ltd. -0002B1 Anritsu, Ltd. -0002B2 Cablevision -0002B3 Intel Corporation -0002B4 DAPHNE -0002B5 Avnet, Inc. -0002B6 Acrosser Technology Co., Ltd. -0002B7 Watanabe Electric Industry Co., Ltd. -0002B8 WHI KONSULT AB -0002B9 Cisco Systems, Inc. -0002BA Cisco Systems, Inc. -0002BB Continuous Computing -0002BC LVL 7 Systems, Inc. -0002BD Bionet Co., Ltd. -0002BE Totsu Engineering, Inc. -0002BF dotRocket, Inc. -0002C0 Bencent Tzeng Industry Co., Ltd. -0002C1 Innovative Electronic Designs, Inc. -0002C2 Net Vision Telecom -0002C3 Arelnet Ltd. -0002C4 Vector International BUBA -0002C5 Evertz Microsystems Ltd. -0002C6 Data Track Technology PLC -0002C7 ALPS ELECTRIC Co., Ltd. -0002C8 Technocom Communications Technology (pte) Ltd -0002C9 Mellanox Technologies -0002CA EndPoints, Inc. -0002CB TriState Ltd. -0002CC M.C.C.I -0002CD TeleDream, Inc. -0002CE FoxJet, Inc. -0002CF ZyGate Communications, Inc. -0002D0 Comdial Corporation -0002D1 Vivotek, Inc. -0002D2 Workstation AG -0002D3 NetBotz, Inc. -0002D4 PDA Peripherals, Inc. -0002D5 ACR -0002D6 NICE Systems -0002D7 EMPEG Ltd -0002D8 BRECIS Communications Corporation -0002D9 Reliable Controls -0002DA ExiO Communications, Inc. -0002DB NETSEC -0002DC Fujitsu General Limited -0002DD Bromax Communications, Ltd. -0002DE Astrodesign, Inc. -0002DF Net Com Systems, Inc. -0002E0 ETAS GmbH -0002E1 Integrated Network Corporation -0002E2 NDC Infared Engineering -0002E3 LITE-ON Communications, Inc. -0002E4 JC HYUN Systems, Inc. -0002E5 Timeware Ltd. -0002E6 Gould Instrument Systems, Inc. -0002E7 CAB GmbH & Co KG -0002E8 E.D.&A. -0002E9 CS Systemes De Securite - C3S -0002EA Videonics, Inc. -0002EB Pico Communications -0002EC Maschoff Design Engineering -0002ED DXO Telecom Co., Ltd. -0002EE Nokia Danmark A/S -0002EF CCC Network Systems Group Ltd. -0002F0 AME Optimedia Technology Co., Ltd. -0002F1 Pinetron Co., Ltd. -0002F2 eDevice, Inc. -0002F3 Media Serve Co., Ltd. -0002F4 PCTEL, Inc. -0002F5 VIVE Synergies, Inc. -0002F6 Equipe Communications -0002F7 ARM -0002F8 SEAKR Engineering, Inc. -0002F9 Mimos Semiconductor SDN BHD -0002FA DX Antenna Co., Ltd. -0002FB Baumuller Aulugen-Systemtechnik GmbH -0002FC Cisco Systems, Inc. -0002FD Cisco Systems, Inc. -0002FE Viditec, Inc. -0002FF Handan BroadInfoCom -000300 NetContinuum, Inc. -000301 Avantas Networks Corporation -000302 Oasys Telecom, Inc. -000303 JAMA Electronics Co., Ltd. -000304 Pacific Broadband Communications -000305 Smart Network Devices GmbH -000306 Fusion In Tech Co., Ltd. -000307 Secure Works, Inc. -000308 AM Communications, Inc. -000309 Texcel Technology PLC -00030A Argus Technologies -00030B Hunter Technology, Inc. -00030C Telesoft Technologies Ltd. -00030D Uniwill Computer Corp. -00030E Core Communications Co., Ltd. -00030F Digital China (Shanghai) Networks Ltd. -000310 Link Evolution Corp. -000311 Micro Technology Co., Ltd. -000312 TR-Systemtechnik GmbH -000313 Access Media SPA -000314 Teleware Network Systems -000315 Cidco Incorporated -000316 Nobell Communications, Inc. -000317 Merlin Systems, Inc. -000318 Cyras Systems, Inc. -000319 Infineon AG -00031A Beijing Broad Telecom Ltd., China -00031B Cellvision Systems, Inc. -00031C Svenska Hardvarufabriken AB -00031D Taiwan Commate Computer, Inc. -00031E Optranet, Inc. -00031F Condev Ltd. -000320 Xpeed, Inc. -000321 Reco Research Co., Ltd. -000322 IDIS Co., Ltd. -000323 Cornet Technology, Inc. -000324 SANYO Multimedia Tottori Co., Ltd. -000325 Arima Computer Corp. -000326 Iwasaki Information Systems Co., Ltd. -000327 ACT'L -000328 Mace Group, Inc. -000329 F3, Inc. -00032A UniData Communication Systems, Inc. -00032B GAI Datenfunksysteme GmbH -00032C ABB Industrie AG -00032D IBASE Technology, Inc. -00032E Scope Information Management, Ltd. -00032F Global Sun Technology, Inc. -000330 Imagenics, Co., Ltd. -000331 Cisco Systems, Inc. -000332 Cisco Systems, Inc. -000333 Digitel Co., Ltd. -000334 Newport Electronics -000335 Mirae Technology -000336 Zetes Technologies -000337 Vaone, Inc. -000338 Oak Technology -000339 Eurologic Systems, Ltd. -00033A Silicon Wave, Inc. -00033B TAMI Tech Co., Ltd. -00033C Daiden Co., Ltd. -00033D ILSHin Lab -00033E Tateyama System Laboratory Co., Ltd. -00033F BigBand Networks, Ltd. -000340 Floware Wireless Systems, Ltd. -000341 Axon Digital Design -000342 Nortel Networks -000343 Martin Professional A/S -000344 Tietech.Co., Ltd. -000345 Routrek Networks Corporation -000346 Hitachi Kokusai Electric, Inc. -000347 Intel Corporation -000348 Norscan Instruments, Ltd. -000349 Vidicode Datacommunicatie B.V. -00034A RIAS Corporation -00034B Nortel Networks -00034C Shanghai DigiVision Technology Co., Ltd. -00034D Chiaro Networks, Ltd. -00034E Pos Data Company, Ltd. -00034F Sur-Gard Security -000350 BTICINO SPA -000351 Diebold, Inc. -000352 Colubris Networks -000353 Mitac, Inc. -000354 Fiber Logic Communications -000355 TeraBeam Internet Systems -000356 Wincor Nixdorf GmbH & Co KG -000357 Intervoice-Brite, Inc. -000358 iCable System Co., Ltd. -000359 DigitalSis -00035A Photron Limited -00035B BridgeWave Communications -00035C Saint Song Corp. -00035D Bosung Hi-Net Co., Ltd. -00035E Metropolitan Area Networks, Inc. -00035F Prueftechnik Condition Monitoring GmbH & Co. KG -000360 PAC Interactive Technology, Inc. -000361 Widcomm, Inc. -000362 Vodtel Communications, Inc. -000363 Miraesys Co., Ltd. -000364 Scenix Semiconductor, Inc. -000365 Kira Information & Communications, Ltd. -000366 ASM Pacific Technology -000367 Jasmine Networks, Inc. -000368 Embedone Co., Ltd. -000369 Nippon Antenna Co., Ltd. -00036A Mainnet, Ltd. -00036B Cisco Systems, Inc. -00036C Cisco Systems, Inc. -00036D Runtop, Inc. -00036E Nicon Systems (Pty) Limited -00036F Telsey SPA -000370 NXTV, Inc. -000371 Acomz Networks Corp. -000372 ULAN -000373 Aselsan A.S -000374 Hunter Watertech -000375 NetMedia, Inc. -000376 Graphtec Technology, Inc. -000377 Gigabit Wireless -000378 HUMAX Co., Ltd. -000379 Proscend Communications, Inc. -00037A Taiyo Yuden Co., Ltd. -00037B IDEC IZUMI Corporation -00037C Coax Media -00037D Stellcom -00037E PORTech Communications, Inc. -00037F Atheros Communications, Inc. -000380 SSH Communications Security Corp. -000381 Ingenico International -000382 A-One Co., Ltd. -000383 Metera Networks, Inc. -000384 AETA -000385 Actelis Networks, Inc. -000386 Ho Net, Inc. -000387 Blaze Network Products -000388 Fastfame Technology Co., Ltd. -000389 Plantronics -00038A America Online, Inc. -00038B PLUS-ONE I&T, Inc. -00038C Total Impact -00038D PCS Revenue Control Systems, Inc. -00038E Atoga Systems, Inc. -00038F Weinschel Corporation -000390 Digital Video Communications, Inc. -000392 Hyundai Teletek Co., Ltd. -000393 Apple Computer, Inc. -000394 Connect One -000395 California Amplifier -000396 EZ Cast Co., Ltd. -000397 Watchfront Electronics -000398 WISI -000399 Dongju Informations & Communications Co., Ltd. -00039A nSine, Ltd. -00039B NetChip Technology, Inc. -00039C OptiMight Communications, Inc. -00039D BENQ CORPORATION -00039E Tera System Co., Ltd. -00039F Cisco Systems, Inc. -0003A0 Cisco Systems, Inc. -0003A1 HIPER Information & Communication, Inc. -0003A2 Catapult Communications -0003A3 MAVIX, Ltd. -0003A4 Data Storage and Information Management -0003A5 Medea Corporation -0003A7 Unixtar Technology, Inc. -0003A8 IDOT Computers, Inc. -0003A9 AXCENT Media AG -0003AA Watlow -0003AB Bridge Information Systems -0003AC Fronius Schweissmaschinen -0003AD Emerson Energy Systems AB -0003AE Allied Advanced Manufacturing Pte, Ltd. -0003AF Paragea Communications -0003B0 Xsense Technology Corp. -0003B1 Abbott Laboratories HPD -0003B2 Radware -0003B3 IA Link Systems Co., Ltd. -0003B4 Macrotek International Corp. -0003B5 Entra Technology Co. -0003B6 QSI Corporation -0003B7 ZACCESS Systems -0003B8 NetKit Solutions, LLC -0003B9 Hualong Telecom Co., Ltd. -0003BA Sun Microsystems -0003BB Signal Communications Limited -0003BC COT GmbH -0003BD OmniCluster Technologies, Inc. -0003BE Netility -0003BF Centerpoint Broadband Technologies, Inc. -0003C0 RFTNC Co., Ltd. -0003C1 Packet Dynamics Ltd -0003C2 Solphone K.K. -0003C3 Micronik Multimedia -0003C4 Tomra Systems ASA -0003C5 Mobotix AG -0003C6 ICUE Systems, Inc. -0003C7 hopf Elektronik GmbH -0003C8 CML Emergency Services -0003C9 TECOM Co., Ltd. -0003CA MTS Systems Corp. -0003CB Nippon Systems Development Co., Ltd. -0003CC Momentum Computer, Inc. -0003CD Clovertech, Inc. -0003CE ETEN Technologies, Inc. -0003CF Muxcom, Inc. -0003D0 KOANKEISO Co., Ltd. -0003D1 Takaya Corporation -0003D2 Crossbeam Systems, Inc. -0003D3 Internet Energy Systems, Inc. -0003D4 Alloptic, Inc. -0003D5 Advanced Communications Co., Ltd. -0003D6 RADVision, Ltd. -0003D7 NextNet Wireless, Inc. -0003D8 iMPath Networks, Inc. -0003D9 Secheron SA -0003DA Takamisawa Cybernetics Co., Ltd. -0003DB Apogee Electronics Corp. -0003DC Lexar Media, Inc. -0003DD Comark Corp. -0003DE OTC Wireless -0003DF Desana Systems -0003E0 RadioFrame Networks, Inc. -0003E1 Winmate Communication, Inc. -0003E2 Comspace Corporation -0003E3 Cisco Systems, Inc. -0003E4 Cisco Systems, Inc. -0003E5 Hermstedt SG -0003E6 Entone Technologies, Inc. -0003E7 Logostek Co. Ltd. -0003E8 Wavelength Digital Limited -0003E9 Akara Canada, Inc. -0003EA Mega System Technologies, Inc. -0003EB Atrica -0003EC ICG Research, Inc. -0003ED Shinkawa Electric Co., Ltd. -0003EE MKNet Corporation -0003EF Oneline AG -0003F0 Redfern Broadband Networks -0003F1 Cicada Semiconductor, Inc. -0003F2 Seneca Networks -0003F3 Dazzle Multimedia, Inc. -0003F4 NetBurner -0003F5 Chip2Chip -0003F6 Allegro Networks, Inc. -0003F7 Plast-Control GmbH -0003F8 SanCastle Technologies, Inc. -0003F9 Pleiades Communications, Inc. -0003FA TiMetra Networks -0003FB Toko Seiki Company, Ltd. -0003FC Intertex Data AB -0003FD Cisco Systems, Inc. -0003FE Cisco Systems, Inc. -0003FF Connectix -000400 LEXMARK INTERNATIONAL, INC. -000401 Osaki Electric Co., Ltd. -000402 Nexsan Technologies, Ltd. -000403 Nexsi Corporation -000404 Makino Milling Machine Co., Ltd. -000405 ACN Technologies -000406 Fa. Metabox AG -000407 Topcon Positioning Systems, Inc. -000408 Sanko Electronics Co., Ltd. -000409 Cratos Networks -00040A Sage Systems -00040B 3com Europe Ltd. -00040C KANNO Work's Ltd. -00040D Avaya, Inc. -00040E AVM GmbH -00040F Asus Network Technologies, Inc. -000410 Spinnaker Networks, Inc. -000411 Inkra Networks, Inc. -000412 WaveSmith Networks, Inc. -000413 SNOM Technology AG -000414 Umezawa Musen Denki Co., Ltd. -000415 Rasteme Systems Co., Ltd. -000416 Parks S/A Comunicacoes Digitais -000417 ELAU AG -000418 Teltronic S.A.U. -000419 Fibercycle Networks, Inc. -00041A ines GmbH -00041B Digital Interfaces Ltd. -00041C ipDialog, Inc. -00041D Corega of America -00041E Shikoku Instrumentation Co., Ltd. -00041F Sony Computer Entertainment, Inc. -000420 Slim Devices, Inc. -000421 Ocular Networks -000422 Gordon Kapes, Inc. -000423 Intel Corporation -000424 TMC s.r.l. -000425 Atmel Corporation -000426 Autosys -000427 Cisco Systems, Inc. -000428 Cisco Systems, Inc. -000429 Pixord Corporation -00042A Wireless Networks, Inc. -00042B IT Access Co., Ltd. -00042C Minet, Inc. -00042D Sarian Systems, Ltd. -00042E Netous Technologies, Ltd. -00042F International Communications Products, Inc. -000430 Netgem -000431 GlobalStreams, Inc. -000432 Voyetra Turtle Beach, Inc. -000433 Cyberboard A/S -000434 Accelent Systems, Inc. -000435 Comptek International, Inc. -000436 ELANsat Technologies, Inc. -000437 Powin Information Technology, Inc. -000438 Nortel Networks -000439 Rosco Entertainment Technology, Inc. -00043A Intelligent Telecommunications, Inc. -00043B Lava Computer Mfg., Inc. -00043C SONOS Co., Ltd. -00043D INDEL AG -00043E Telencomm -00043F Electronic Systems Technology, Inc. -000440 cyberPIXIE, Inc. -000441 Half Dome Systems, Inc. -000442 NACT -000443 Agilent Technologies, Inc. -000444 Western Multiplex Corporation -000445 LMS Skalar Instruments GmbH -000446 CYZENTECH Co., Ltd. -000447 Acrowave Systems Co., Ltd. -000448 Polaroid Professional Imaging -000449 Mapletree Networks -00044A iPolicy Networks, Inc. -00044B NVIDIA -00044C JENOPTIK -00044D Cisco Systems, Inc. -00044E Cisco Systems, Inc. -00044F Leukhardt Systemelektronik GmbH -000450 DMD Computers SRL -000451 Medrad, Inc. -000452 RocketLogix, Inc. -000453 YottaYotta, Inc. -000454 Quadriga UK -000455 ANTARA.net -000456 PipingHot Networks -000457 Universal Access Technology, Inc. -000458 Fusion X Co., Ltd. -000459 Veristar Corporation -00045A The Linksys Group, Inc. -00045B Techsan Electronics Co., Ltd. -00045C Mobiwave Pte Ltd -00045D BEKA Elektronik -00045E PolyTrax Information Technology AG -00045F Evalue Technology, Inc. -000460 Knilink Technology, Inc. -000461 EPOX Computer Co., Ltd. -000462 DAKOS Data & Communication Co., Ltd. -000463 Bosch Security Systems -000464 Fantasma Networks, Inc. -000465 i.s.t isdn-support technik GmbH -000466 ARMITEL Co. -000467 Wuhan Research Institute of MII -000468 Vivity, Inc. -000469 Innocom, Inc. -00046A Navini Networks -00046B Palm Wireless, Inc. -00046C Cyber Technology Co., Ltd. -00046D Cisco Systems, Inc. -00046E Cisco Systems, Inc. -00046F Digitel S/A Industria Eletronica -000470 ipUnplugged AB -000471 IPrad -000472 Telelynx, Inc. -000473 Photonex Corporation -000474 LEGRAND -000475 3 Com Corporation -000476 3 Com Corporation -000477 Scalant Systems, Inc. -000478 G. Star Technology Corporation -000479 Radius Co., Ltd. -00047A AXXESSIT ASA -00047B Schlumberger -00047C Skidata AG -00047D Pelco -00047E NKF Electronics -00047F Chr. Mayr GmbH & Co. KG -000480 Foundry Networks, Inc. -000481 Econolite Control Products, Inc. -000482 Medialogic Corp. -000483 Deltron Technology, Inc. -000484 Amann GmbH -000485 PicoLight -000486 ITTC, University of Kansas -000487 Cogency Semiconductor, Inc. -000488 Eurotherm Action Incorporated. -000489 YAFO Networks, Inc. -00048A Temia Vertriebs GmbH -00048B Poscon Corporation -00048C Nayna Networks, Inc. -00048D Tone Commander Systems, Inc. -00048E Ohm Tech Labs, Inc. -00048F TD Systems Corp. -000490 Optical Access -000491 Technovision, Inc. -000492 Hive Internet, Ltd. -000493 Tsinghua Unisplendour Co., Ltd. -000494 Breezecom, Ltd. -000495 Tejas Networks -000496 Extreme Networks -000497 MacroSystem Digital Video AG -000499 Chino Corporation -00049A Cisco Systems, Inc. -00049B Cisco Systems, Inc. -00049C Surgient Networks, Inc. -00049D Ipanema Technologies -00049E Wirelink Co., Ltd. -00049F Metrowerks -0004A0 Verity Instruments, Inc. -0004A1 Pathway Connectivity -0004A2 L.S.I. Japan Co., Ltd. -0004A3 Microchip Technology, Inc. -0004A4 NetEnabled, Inc. -0004A5 Barco Projection Systems NV -0004A6 SAF Tehnika Ltd. -0004A7 FabiaTech Corporation -0004A8 Broadmax Technologies, Inc. -0004A9 SandStream Technologies, Inc. -0004AA Jetstream Communications -0004AB Comverse Network Systems, Inc. -0004AC IBM CORP. -0004AD Malibu Networks -0004AE Liquid Metronics -0004AF Digital Fountain, Inc. -0004B0 ELESIGN Co., Ltd. -0004B1 Signal Technology, Inc. -0004B2 ESSEGI SRL -0004B3 Videotek, Inc. -0004B4 CIAC -0004B5 Equitrac Corporation -0004B6 Stratex Networks, Inc. -0004B7 AMB i.t. Holding -0004B8 Kumahira Co., Ltd. -0004B9 S.I. Soubou, Inc. -0004BA KDD Media Will Corporation -0004BB Bardac Corporation -0004BC Giantec, Inc. -0004BD Motorola BCS -0004BE OptXCon, Inc. -0004BF VersaLogic Corp. -0004C0 Cisco Systems, Inc. -0004C1 Cisco Systems, Inc. -0004C2 Magnipix, Inc. -0004C3 CASTOR Informatique -0004C4 Allen & Heath Limited -0004C5 ASE Technologies, USA -0004C6 Yamaha Motor Co., Ltd. -0004C7 NetMount -0004C8 LIBA Maschinenfabrik GmbH -0004C9 Micro Electron Co., Ltd. -0004CA FreeMs Corp. -0004CB Tdsoft Communication, Ltd. -0004CC Peek Traffic B.V. -0004CD Informedia Research Group -0004CE Patria Ailon -0004CF Seagate Technology -0004D0 Softlink s.r.o. -0004D1 Drew Technologies, Inc. -0004D2 Adcon Telemetry AG -0004D3 Toyokeiki Co., Ltd. -0004D4 Proview Electronics Co., Ltd. -0004D5 Hitachi Communication Systems, Inc. -0004D6 Takagi Industrial Co., Ltd. -0004D7 Omitec Instrumentation Ltd. -0004D8 IPWireless, Inc. -0004D9 Titan Electronics, Inc. -0004DA Relax Technology, Inc. -0004DB Tellus Group Corp. -0004DC Nortel Networks -0004DD Cisco Systems, Inc. -0004DE Cisco Systems, Inc. -0004DF Teracom Telematica Ltda. -0004E0 Procket Networks -0004E1 Infinior Microsystems -0004E2 SMC Networks, Inc. -0004E3 Accton Technology Corp. -0004E4 Daeryung Ind., Inc. -0004E5 Glonet Systems, Inc. -0004E6 Banyan Network Private Limited -0004E7 Lightpointe Communications, Inc -0004E8 IER, Inc. -0004E9 Infiniswitch Corporation -0004EA Hewlett-Packard Company -0004EB Paxonet Communications, Inc. -0004EC Memobox SA -0004ED Billion Electric Co., Ltd. -0004EE Lincoln Electric Company -0004EF Polestar Corp. -0004F0 International Computers, Ltd -0004F1 WhereNet -0004F2 Circa Communications, Ltd. -0004F3 FS FORTH-SYSTEME GmbH -0004F4 Infinite Electronics Inc. -0004F5 SnowShore Networks, Inc. -0004F6 Amphus -0004F7 Omega Band, Inc. -0004F8 QUALICABLE TV Industria E Com., Ltda -0004F9 Xtera Communications, Inc. -0004FA MIST Inc. -0004FB Commtech, Inc. -0004FC Stratus Computer (DE), Inc. -0004FD Japan Control Engineering Co., Ltd. -0004FE Pelago Networks -0004FF Acronet Co., Ltd. -000500 Cisco Systems, Inc. -000501 Cisco Systems, Inc. -000502 APPLE COMPUTER -000503 ICONAG -000504 Naray Information & Communication Enterprise -000505 Systems Integration Solutions, Inc. -000506 Reddo Networks AB -000507 Fine Appliance Corp. -000508 Inetcam, Inc. -000509 AVOC Nishimura Ltd. -00050A ICS Spa -00050B SICOM Systems, Inc. -00050C Network Photonics, Inc. -00050D Midstream Technologies, Inc. -00050E 3ware, Inc. -00050F Tanaka S/S Ltd. -000510 Infinite Shanghai Communication Terminals Ltd. -000511 Complementary Technologies Ltd -000512 MeshNetworks, Inc. -000513 VTLinx Multimedia Systems, Inc. -000514 KDT Systems Co., Ltd. -000515 Nuark Co., Ltd. -000516 SMART Modular Technologies -000517 Shellcomm, Inc. -000518 Jupiters Technology -000519 Siemens Building Technologies AG, -00051A 3Com Europe Ltd. -00051B Magic Control Technology Corporation -00051C Xnet Technology Corp. -00051D Airocon, Inc. -00051E Brocade Communications Systems, Inc. -00051F Taijin Media Co., Ltd. -000520 Smartronix, Inc. -000521 Control Microsystems -000522 LEA*D Corporation, Inc. -000523 AVL List GmbH -000524 BTL System (HK) Limited -000525 Puretek Industrial Co., Ltd. -000526 IPAS GmbH -000527 SJ Tek Co. Ltd -000528 New Focus, Inc. -000529 Shanghai Broadan Communication Technology Co., Ltd -00052A Ikegami Tsushinki Co., Ltd. -00052B HORIBA, Ltd. -00052C Supreme Magic Corporation -00052D Zoltrix International Limited -00052E Cinta Networks -00052F Leviton Voice and Data -000530 Andiamo Systems, Inc. -000531 Cisco Systems, Inc. -000532 Cisco Systems, Inc. -000533 Sanera Systems, Inc. -000534 Northstar Engineering Ltd. -000535 Chip PC Ltd. -000536 Danam Communications, Inc. -000537 Nets Technology Co., Ltd. -000538 Merilus, Inc. -000539 A Brand New World in Sweden AB -00053A Willowglen Services Pte Ltd -00053B Harbour Networks Ltd., Co. Beijing -00053C Xircom -00053D Agere Systems -00053E KID Systeme GmbH -00053F VisionTek, Inc. -000540 FAST Corporation -000541 Advanced Systems Co., Ltd. -000542 Otari, Inc. -000543 IQ Wireless GmbH -000544 Valley Technologies, Inc. -000545 Internet Photonics -000546 K-Solutions Inc. -000547 Starent Networks -000548 Disco Corporation -000549 Salira Optical Network Systems -00054A Ario Data Networks, Inc. -00054B Micro Innovation AG -00054C RF Innovations Pty Ltd -00054D Brans Technologies, Inc. -00054E Philips Components -000550 Digi-Tech Communications Limited -000551 F & S Elektronik Systeme GmbH -000552 Xycotec Computer GmbH -000553 DVC Company, Inc. -000554 Rangestar Wireless -000555 Japan Cash Machine Co., Ltd. -000556 360 Systems -000557 Agile TV Corporation -000558 Synchronous, Inc. -000559 Intracom S.A. -00055A Power Dsine Ltd. -00055B Charles Industries, Ltd. -00055C Kowa Company, Ltd. -00055D D-Link Systems, Inc. -00055E Cisco Systems, Inc. -00055F Cisco Systems, Inc. -000560 LEADER COMM.CO., LTD -000561 nac Image Technology, Inc. -000562 Digital View Limited -000563 J-Works, Inc. -000564 Tsinghua Bitway Co., Ltd. -000565 Tailyn Communication Company Ltd. -000566 Secui.com Corporation -000567 Etymonic Design, Inc. -000568 Piltofish Networks AB -000569 VMWARE, Inc. -00056A Heuft Systemtechnik GmbH -00056B C.P. Technology Co., Ltd. -00056C Hung Chang Co., Ltd. -00056D Pacific Corporation -00056E National Enhance Technology, Inc. -00056F Innomedia Technologies Pvt. Ltd. -000570 Baydel Ltd. -000571 Seiwa Electronics Co. -000572 Deonet Co., Ltd. -000573 Cisco Systems, Inc. -000574 Cisco Systems, Inc. -000575 CDS-Electronics BV -000576 NSM Technology Ltd. -000577 SM Information & Communication -000579 Universal Control Solution Corp. -00057A Hatteras Networks -00057B Chung Nam Electronic Co., Ltd. -00057C RCO Security AB -00057D Sun Communications, Inc. -00057E Eckelmann Steuerungstechnik GmbH -00057F Acqis Technology -000580 Fibrolan Ltd. -000581 Snell & Wilcox Ltd. -000582 ClearCube Technology -000583 ImageCom Limited -000584 AbsoluteValue Systems, Inc. -000585 Juniper Networks, Inc. -000586 Lucent Technologies -000587 Locus, Incorporated -000588 Sensoria Corp. -000589 National Datacomputer -00058A Netcom Co., Ltd. -00058B IPmental, Inc. -00058C Opentech Inc. -00058D Lynx Photonic Networks, Inc. -00058E Flextronics International GmbH & Co. Nfg. KG -00058F CLCsoft co. -000590 Swissvoice Ltd. -000591 Active Silicon Ltd. -000592 Pultek Corp. -000593 Grammar Engine Inc. -000594 IXXAT Automation GmbH -000595 Alesis Corporation -000596 Genotech Co., Ltd. -000597 Eagle Traffic Control Systems -000598 CRONOS S.r.l. -000599 DRS Test and Energy Management or DRS-TEM -00059A Cisco Systems, Inc. -00059B Cisco Systems, Inc. -00059C Kleinknecht GmbH, Ing. Buero -00059D Daniel Computing Systems, Inc. -00059E Zinwell Corporation -00059F Yotta Networks, Inc. -0005A0 MOBILINE Kft. -0005A1 Zenocom -0005A2 CELOX Networks -0005A3 QEI, Inc. -0005A4 Lucid Voice Ltd. -0005A5 KOTT -0005A6 Extron Electronics -0005A7 Hyperchip, Inc. -0005A8 WYLE ELECTRONICS -0005A9 Princeton Networks, Inc. -0005AA Moore Industries International Inc. -0005AB Cyber Fone, Inc. -0005AC Northern Digital, Inc. -0005AD Topspin Communications, Inc. -0005AE Mediaport USA -0005AF InnoScan Computing A/S -0005B0 Korea Computer Technology Co., Ltd. -0005B1 ASB Technology BV -0005B2 Medison Co., Ltd. -0005B3 Asahi-Engineering Co., Ltd. -0005B4 Aceex Corporation -0005B5 Broadcom Technologies -0005B6 INSYS Microelectronics GmbH -0005B7 Arbor Technology Corp. -0005B8 Electronic Design Associates, Inc. -0005B9 Airvana, Inc. -0005BA Area Netwoeks, Inc. -0005BB Myspace AB -0005BC Resorsys Ltd. -0005BD ROAX BV -0005BE Kongsberg Seatex AS -0005BF JustEzy Technology, Inc. -0005C0 Digital Network Alacarte Co., Ltd. -0005C1 A-Kyung Motion, Inc. -0005C2 Soronti, Inc. -0005C3 Pacific Instruments, Inc. -0005C4 Telect, Inc. -0005C5 Flaga HF -0005C6 Triz Communications -0005C7 I/F-COM A/S -0005C8 VERYTECH -0005C9 LG Innotek -0005CA Hitron Technology, Inc. -0005CB ROIS Technologies, Inc. -0005CC Sumtel Communications, Inc. -0005CD Denon, Ltd. -0005CE Prolink Microsystems Corporation -0005CF Thunder River Technologies, Inc. -0005D0 Solinet Systems -0005D1 Metavector Technologies -0005D2 DAP Technologies -0005D3 eProduction Solutions, Inc. -0005D4 FutureSmart Networks, Inc. -0005D5 Speedcom Wireless -0005D6 Titan Wireless -0005D7 Vista Imaging, Inc. -0005D8 Arescom, Inc. -0005D9 Techno Valley, Inc. -0005DA Apex Automationstechnik -0005DB Nentec GmbH -0005DC Cisco Systems, Inc. -0005DD Cisco Systems, Inc. -0005DE Gi Fone Korea, Inc. -0005DF Electronic Innovation, Inc. -0005E0 Empirix Corp. -0005E1 Trellis Photonics, Ltd. -0005E2 Creativ Network Technologies -0005E3 LightSand Communications, Inc. -0005E4 Red Lion Controls L.P. -0005E5 Renishaw PLC -0005E6 Egenera, Inc. -0005E7 Netrake Corp. -0005E8 TurboWave, Inc. -0005E9 Unicess Network, Inc. -0005EA Rednix -0005EB Blue Ridge Networks, Inc. -0005EC Mosaic Systems Inc. -0005ED Technikum Joanneum GmbH -0005EE BEWATOR Group -0005EF ADOIR Digital Technology -0005F0 SATEC -0005F1 Vrcom, Inc. -0005F2 Power R, Inc. -0005F3 Weboyn -0005F4 System Base Co., Ltd. -0005F5 OYO Geospace Corp. -0005F6 Young Chang Co. Ltd. -0005F7 Analog Devices, Inc. -0005F8 Real Time Access, Inc. -0005F9 TOA Corporation -0005FA IPOptical, Inc. -0005FB ShareGate, Inc. -0005FC Schenck Pegasus Corp. -0005FD PacketLight Networks Ltd. -0005FE Traficon N.V. -0005FF SNS Solutions, Inc. -000600 Tokyo Electronic Industry Co., Ltd. -000601 Otanikeiki Co., Ltd. -000602 Cirkitech Electronics Co. -000603 Baker Hughes Inc. -000604 @Track Communications, Inc. -000605 Inncom International, Inc. -000606 RapidWAN, Inc. -000607 Omni Directional Control Technology Inc. -000608 At-Sky SAS -000609 Crossport Systems -00060A Blue2space -00060B Paceline Systems Corporation -00060C Melco Industries, Inc. -00060D Wave7 Optics -00060E IGYS Systems, Inc. -00060F Narad Networks Inc -000610 Abeona Networks Inc -000611 Zeus Wireless, Inc. -000612 Accusys, Inc. -000613 Kawasaki Microelectronics Incorporated -000614 Prism Holdings -000615 Kimoto Electric Co., Ltd. -000616 Tel Net Co., Ltd. -000617 Redswitch Inc. -000618 DigiPower Manufacturing Inc. -000619 Connection Technology Systems -00061A Zetari Inc. -00061B Portable Systems, IBM Japan Co, Ltd -00061C Hoshino Metal Industries, Ltd. -00061D MIP Telecom, Inc. -00061E Maxan Systems -00061F Vision Components GmbH -000620 Serial System Ltd. -000621 Hinox, Co., Ltd. -000622 Chung Fu Chen Yeh Enterprise Corp. -000623 MGE UPS Systems France -000624 Gentner Communications Corp. -000625 The Linksys Group, Inc. -000626 MWE GmbH -000627 Uniwide Technologies, Inc. -000628 Cisco Systems, Inc. -000629 IBM CORPORATION -00062A Cisco Systems, Inc. -00062B INTRASERVER TECHNOLOGY -00062C Network Robots, Inc. -00062D TouchStar Technologies, L.L.C. -00062E Aristos Logic Corp. -00062F Pivotech Systems Inc. -000630 Adtranz Sweden -000631 Optical Solutions, Inc. -000632 Mesco Engineering GmbH -000633 Heimann Biometric Systems GmbH -000634 GTE Airfone Inc. -000635 PacketAir Networks, Inc. -000636 Jedai Broadband Networks -000637 Toptrend-Meta Information (ShenZhen) Inc. -000638 Sungjin C&C Co., Ltd. -000639 Newtec -00063A Dura Micro, Inc. -00063B Arcturus Networks, Inc. -00063C NMI Electronics Ltd -00063D Microwave Data Systems Inc. -00063E Opthos Inc. -00063F Everex Communications Inc. -000640 White Rock Networks -000641 ITCN -000642 Genetel Systems Inc. -000643 SONO Computer Co., Ltd. -000644 NEIX Inc. -000645 Meisei Electric Co. Ltd. -000646 ShenZhen XunBao Network Technology Co Ltd -000647 Etrali S.A. -000648 Seedsware, Inc. -000649 Quante -00064A Honeywell Co., Ltd. (KOREA) -00064B Alexon Co., Ltd. -00064C Invicta Networks, Inc. -00064D Sencore -00064E Broad Net Technology Inc. -00064F PRO-NETS Technology Corporation -000650 Tiburon Networks, Inc. -000651 Aspen Networks Inc. -000652 Cisco Systems, Inc. -000653 Cisco Systems, Inc. -000654 Maxxio Technologies -000655 Yipee, Inc. -000656 Tactel AB -000657 Market Central, Inc. -000658 Helmut Fischer GmbH & Co. KG -000659 EAL (Apeldoorn) B.V. -00065A Strix Systems -00065B Dell Computer Corp. -00065C Malachite Technologies, Inc. -00065D Heidelberg Web Systems -00065E Photuris, Inc. -00065F ECI Telecom - NGTS Ltd. -000660 NADEX Co., Ltd. -000661 NIA Home Technologies Corp. -000662 MBM Technology Ltd. -000663 Human Technology Co., Ltd. -000664 Fostex Corporation -000665 Sunny Giken, Inc. -000666 Roving Networks -000667 Tripp Lite -000668 Vicon Industries Inc. -000669 Datasound Laboratories Ltd -00066A InfiniCon Systems, Inc. -00066B Sysmex Corporation -00066C Robinson Corporation -00066D Compuprint S.P.A. -00066E Delta Electronics, Inc. -00066F Korea Data Systems -000670 Upponetti Oy -000671 Softing AG -000672 Netezza -000673 Optelecom, Inc. -000674 Spectrum Control, Inc. -000675 Banderacom, Inc. -000676 Novra Technologies Inc. -000677 SICK AG -000678 Marantz Japan, Inc. -000679 Konami Corporation -00067A JMP Systems -00067B Toplink C&C Corporation -00067C CISCO SYSTEMS, INC. -00067D Takasago Ltd. -00067E WinCom Systems, Inc. -00067F Rearden Steel Technologies -000680 Card Access, Inc. -000681 Goepel Electronic GmbH -000682 Convedia -000683 Bravara Communications, Inc. -000684 Biacore AB -000685 NetNearU Corporation -000686 ZARDCOM Co., Ltd. -000687 Omnitron Systems Technology, Inc. -000688 Telways Communication Co., Ltd. -000689 yLez Technologies Pte Ltd -00068A NeuronNet Co. Ltd. R&D Center -00068B AirRunner Technologies, Inc. -00068C 3Com Corporation -00068D SANgate Systems -00068E HID Corporation -00068F Telemonitor, Inc. -000690 Euracom Communication GmbH -000691 PT Inovacao -000692 Intruvert Networks, Inc. -000693 Flexus Computer Technology, Inc. -000694 Mobillian Corporation -000695 Ensure Technologies, Inc. -000696 Advent Networks -000697 R & D Center -000698 egnite Software GmbH -000699 Vida Design Co. -00069A e & Tel -00069B AVT Audio Video Technologies GmbH -00069C Transmode Systems AB -00069D Petards Mobile Intelligence -00069E UNIQA, Inc. -00069F Kuokoa Networks -0006A0 Mx Imaging -0006A1 Celsian Technologies, Inc. -0006A2 Microtune, Inc. -0006A3 Bitran Corporation -0006A4 INNOWELL Corp. -0006A5 PINON Corp. -0006A6 Artistic Licence (UK) Ltd -0006A7 Primarion -0006A8 KC Technology, Inc. -0006A9 Universal Instruments Corp. -0006AA Miltope Corporation -0006AB W-Link Systems, Inc. -0006AC Intersoft Co. -0006AD KB Electronics Ltd. -0006AE Himachal Futuristic Communications Ltd -0006B0 Comtech EF Data Corp. -0006B1 Sonicwall -0006B2 Linxtek Co. -0006B3 Diagraph Corporation -0006B4 Vorne Industries, Inc. -0006B5 Luminent, Inc. -0006B6 Nir-Or Israel Ltd. -0006B7 TELEM GmbH -0006B8 Bandspeed Pty Ltd -0006B9 A5TEK Corp. -0006BA Westwave Communications -0006BB ATI Technologies Inc. -0006BC Macrolink, Inc. -0006BD BNTECHNOLOGY Co., Ltd. -0006BE Baumer Optronic GmbH -0006BF Accella Technologies Co., Ltd. -0006C0 United Internetworks, Inc. -0006C1 CISCO SYSTEMS, INC. -0006C2 Smartmatic Corporation -0006C3 Schindler Elevators Ltd. -0006C4 Piolink Inc. -0006C5 INNOVI Technologies Limited -0006C6 lesswire AG -0006C7 RFNET Technologies Pte Ltd (S) -0006C8 Sumitomo Metal Micro Devices, Inc. -0006C9 Technical Marketing Research, Inc. -0006CA American Computer & Digital Components, Inc. (ACDC) -0006CB Jotron Electronics A/S -0006CC JMI Electronics Co., Ltd. -0006CD CreoScitex Corporation Ltd. -0006CE DATENO -0006CF Thales Avionics In-Flight Systems, LLC -0006D0 Elgar Electronics Corp. -0006D1 Tahoe Networks, Inc. -0006D2 Tundra Semiconductor Corp. -0006D3 Alpha Telecom, Inc. U.S.A. -0006D4 Interactive Objects, Inc. -0006D5 Diamond Systems Corp. -0006D6 Cisco Systems, Inc. -0006D7 Cisco Systems, Inc. -0006D8 Maple Optical Systems -0006D9 IPM-Net S.p.A. -0006DA ITRAN Communications Ltd. -0006DB ICHIPS Co., Ltd. -0006DC Syabas Technology (Amquest) -0006DD AT & T Laboratories - Cambridge Ltd -0006DE Flash Technology -0006DF AIDONIC Corporation -0006E0 MAT Co., Ltd. -0006E1 Techno Trade s.a -0006E2 Ceemax Technology Co., Ltd. -0006E3 Quantitative Imaging Corporation -0006E4 Citel Technologies Ltd. -0006E5 Fujian Newland Computer Ltd. Co. -0006E6 DongYang Telecom Co., Ltd. -0006E7 Bit Blitz Communications Inc. -0006E8 Optical Network Testing, Inc. -0006E9 Intime Corp. -0006EA ELZET80 Mikrocomputer GmbH&Co. KG -0006EB Global Data -0006EC M/A COM Private Radio System Inc. -0006ED Inara Networks -0006EE Shenyang Neu-era Information & Technology Stock Co., Ltd -0006EF Maxxan Systems, Inc. -0006F0 Digeo, Inc. -0006F1 Optillion -0006F2 Platys Communications -0006F3 AcceLight Networks -0006F4 Prime Electronics & Satellitics Inc. -0006F9 Mitsui Zosen Systems Research Inc. -0006FA IP SQUARE Co, Ltd. -0006FB Hitachi Printing Solutions, Ltd. -0006FC Fnet Co., Ltd. -0006FD Comjet Information Systems Corp. -0006FE Celion Networks, Inc. -0006FF Sheba Systems Co., Ltd. -000700 Zettamedia Korea -000701 RACAL-DATACOM -000702 Varian Medical Systems -000703 CSEE Transport -000705 Endress & Hauser GmbH & Co -000706 Sanritz Corporation -000707 Interalia Inc. -000708 Bitrage Inc. -000709 Westerstrand Urfabrik AB -00070A Unicom Automation Co., Ltd. -00070B Octal, SA -00070C SVA-Intrusion.com Co. Ltd. -00070D Cisco Systems Inc. -00070E Cisco Systems Inc. -00070F Fujant, Inc. -000710 Adax, Inc. -000711 Acterna -000712 JAL Information Technology -000713 IP One, Inc. -000714 Brightcom -000715 General Research of Electronics, Inc. -000716 J & S Marine Ltd. -000717 Wieland Electric GmbH -000718 iCanTek Co., Ltd. -000719 Mobiis Co., Ltd. -00071A Finedigital Inc. -00071B Position Technology Inc. -00071C AT&T Fixed Wireless Services -00071D Satelsa Sistemas Y Aplicaciones De Telecomunicaciones, S.A. -00071E Tri-M Engineering / Nupak Dev. Corp. -00071F European Systems Integration -000720 Trutzschler GmbH & Co. KG -000721 Formac Elektronik GmbH -000722 Nielsen Media Research -000723 ELCON Systemtechnik GmbH -000724 Telemax Co., Ltd. -000725 Bematech International Corp. -000727 Zi Corporation (HK) Ltd. -000728 Neo Telecom -000729 Kistler Instrumente AG -00072A Innovance Networks -00072B Jung Myung Telecom Co., Ltd. -00072C Fabricom -00072D CNSystems -00072E North Node AB -00072F Instransa, Inc. -000730 Hutchison OPTEL Telecom Technology Co., Ltd. -000731 Spiricon, Inc. -000732 AAEON Technology Inc. -000733 DANCONTROL Engineering -000734 ONStor, Inc. -000735 Flarion Technologies, Inc. -000736 Data Video Technologies Co., Ltd. -000737 Soriya Co. Ltd. -000738 Young Technology Co., Ltd. -000739 Motion Media Technology Ltd. -00073A Inventel Systemes -00073B Tenovis GmbH & Co KG -00073C Telecom Design -00073D Nanjing Postel Telecommunications Co., Ltd. -00073E China Great-Wall Computer Shenzhen Co., Ltd. -00073F Woojyun Systec Co., Ltd. -000740 Melco Inc. -000741 Sierra Automated Systems -000742 Current Technologies -000743 Chelsio Communications -000744 Unico, Inc. -000745 Radlan Computer Communications Ltd. -000746 Interlink BT, LLC -000747 Mecalc -000748 The Imaging Source Europe -000749 CENiX Inc. -00074A Carl Valentin GmbH -00074B Daihen Corporation -00074C Beicom Inc. -00074D Zebra Technologies Corp. -00074E Naughty boy co., Ltd. -00074F Cisco Systems, Inc. -000750 Cisco Systems, Inc. -000751 m.u.t. - GmbH -000752 Rhythm Watch Co., Ltd. -000753 Beijing Qxcomm Technology Co., Ltd. -000754 Xyterra Computing, Inc. -000755 Lafon SA -000756 Juyoung Telecom -000757 Topcall International AG -000758 Dragonwave -000759 Boris Manufacturing Corp. -00075A Air Products and Chemicals, Inc. -00075B Gibson Guitars -00075C ENCAD, Inc. -00075D Celleritas Inc. -00075E Pulsar Technologies, Inc. -00075F VCS Video Communication Systems AG -000760 TOMIS Information & Telecom Corp. -000761 Logitech SA -000762 Group Sense Limited -000763 Sunniwell Cyber Tech. Co., Ltd. -000764 YoungWoo Telecom Co. Ltd. -000765 Jade Quantum Technologies, Inc. -000766 Chou Chin Industrial Co., Ltd. -000767 Yuxing Electronics Company Limited -000768 Danfoss A/S -000769 Italiana Macchi SpA -00076A NEXTEYE Co., Ltd. -00076B Stralfors AB -00076C Daehanet, Inc. -00076D Flexlight Networks -00076E Sinetica Corporation Ltd. -00076F Synoptics Limited -000770 Locusnetworks Corporation -000771 Embedded System Corporation -000772 Alcatel Shanghai Bell Co., Ltd. -000773 Ascom Powerline Communications Ltd. -000774 GuangZhou Thinker Technology Co. Ltd. -000775 Valence Semiconductor, Inc. -000776 Federal APD -000777 Motah Ltd. -000778 GERSTEL GmbH & Co. KG -000779 Sungil Telecom Co., Ltd. -00077A Infoware System Co., Ltd. -00077B Millimetrix Broadband Networks -00077C OnTime Networks -00077E Elrest GmbH -00077F J Communications Co., Ltd. -000780 Bluegiga Technologies OY -000781 Itron Inc. -000782 Nauticus Networks, Inc. -000783 SynCom Network, Inc. -000784 Cisco Systems Inc. -000785 Cisco Systems Inc. -000786 Wireless Networks Inc. -000787 Idea System Co., Ltd. -000788 Clipcomm, Inc. -000789 Eastel Systems Corporation -00078A Mentor Data System Inc. -00078B Wegener Communications, Inc. -00078C Elektronikspecialisten i Borlange AB -00078D NetEngines Ltd. -00078E Garz & Friche GmbH -00078F Emkay Innovative Products -000790 Tri-M Technologies (s) Limited -000791 International Data Communications, Inc. -000792 Suetron Electronic GmbH -000794 Simple Devices, Inc. -000795 Elitegroup Computer System Co. (ECS) -000796 LSI Systems, Inc. -000797 Netpower Co., Ltd. -000798 Selea SRL -000799 Tipping Point Technologies, Inc. -00079A SmartSight Networks Inc. -00079B Aurora Networks -00079C Golden Electronics Technology Co., Ltd. -00079D Musashi Co., Ltd. -00079E Ilinx Co., Ltd. -00079F Action Digital Inc. -0007A0 e-Watch Inc. -0007A1 VIASYS Healthcare GmbH -0007A2 Opteon Corporation -0007A3 Ositis Software, Inc. -0007A4 GN Netcom Ltd. -0007A5 Y.D.K Co. Ltd. -0007A6 Home Automation, Inc. -0007A7 A-Z Inc. -0007A8 Haier Group Technologies Ltd. -0007A9 Novasonics -0007AA Quantum Data Inc. -0007AC Eolring -0007AD Pentacon GmbH Foto-und Feinwerktechnik -0007AE Layer N Networks -0007AF N-Tron Corp. -0007B0 Office Details, Inc. -0007B1 Equator Technologies -0007B2 Transaccess S.A. -0007B3 Cisco Systems Inc. -0007B4 Cisco Systems Inc. -0007B5 Any One Wireless Ltd. -0007B6 Telecom Technology Ltd. -0007B7 Samurai Ind. Prods Eletronicos Ltda -0007B8 American Predator Corp. -0007B9 Ginganet Corporation -0007BA Xebeo Communications, Inc. -0007BB Candera Inc. -0007BC Identix Inc. -0007BD Radionet Ltd. -0007BE DataLogic SpA -0007BF Armillaire Technologies, Inc. -0007C0 NetZerver Inc. -0007C1 Overture Networks, Inc. -0007C2 Netsys Telecom -0007C3 Cirpack -0007C4 JEAN Co. Ltd. -0007C5 Gcom, Inc. -0007C6 VDS Vosskuhler GmbH -0007C7 Synectics Systems Limited -0007C8 Brain21, Inc. -0007C9 Technol Seven Co., Ltd. -0007CA Creatix Polymedia Ges Fur Kommunikaitonssysteme -0007CB Freebox SA -0007CC Kaba Benzing GmbH -0007CD NMTEL Co., Ltd. -0007CE Cabletime Limited -0007CF Anoto AB -0007D0 Automat Engenharia de Automaoa Ltda. -0007D1 Spectrum Signal Processing Inc. -0007D2 Logopak Systeme -0007D3 Stork Digital Imaging B.V. -0007D4 Zhejiang Yutong Network Communication Co Ltd. -0007D5 3e Technologies Int;., Inc. -0007D6 Commil Ltd. -0007D7 Caporis Networks AG -0007D8 Hitron Systems Inc. -0007D9 Splicecom -0007DA Neuro Telecom Co., Ltd. -0007DB Kirana Networks, Inc. -0007DC Atek Co, Ltd. -0007DD Cradle Technologies -0007DE eCopilt AB -0007DF Vbrick Systems Inc. -0007E0 Palm Inc. -0007E1 WIS Communications Co. Ltd. -0007E2 Bitworks, Inc. -0007E3 Navcom Technology, Inc. -0007E4 SoftRadio Co., Ltd. -0007E5 Coup Corporation -0007E6 edgeflow Canada Inc. -0007E7 FreeWave Technologies -0007E8 St. Bernard Software -0007E9 Intel Corporation -0007EA Massana, Inc. -0007EB Cisco Systems Inc. -0007EC Cisco Systems Inc. -0007ED Altera Corporation -0007EE telco Informationssysteme GmbH -0007EF Lockheed Martin Tactical Systems -0007F0 LogiSync Corporation -0007F1 TeraBurst Networks Inc. -0007F2 IOA Corporation -0007F3 Think Engine Networks -0007F4 Eletex Co., Ltd. -0007F5 Bridgeco Co AG -0007F6 Qqest Software Systems -0007F7 Galtronics -0007F8 ITDevices, Inc. -0007F9 Phonetics, Inc. -0007FA ITT Co., Ltd. -0007FB Giga Stream UMTS Technologies GmbH -0007FC Adept Systems Inc. -0007FD LANergy Ltd. -0007FE Rigaku Corporation -0007FF Gluon Networks -000800 MULTITECH SYSTEMS, INC. -000801 HighSpeed Surfing Inc. -000802 Compaq Computer Corporation -000803 Cos Tron -000804 ICA Inc. -000805 Techno-Holon Corporation -000806 Raonet Systems, Inc. -000807 Access Devices Limited -000808 PPT Vision, Inc. -000809 Systemonic AG -00080A Espera-Werke GmbH -00080B Birka BPA Informationssystem AB -00080C VDA elettronica SrL -00080D Toshiba -00080E Motorola, BCS -00080F Proximion Fiber Optics AB -000810 Key Technology, Inc. -000811 VOIX Corporation -000812 GM-2 Corporation -000813 Diskbank, Inc. -000814 TIL Technologies -000815 CATS Co., Ltd. -000816 Bluetags A/S -000817 EmergeCore Networks LLC -000818 Pixelworks, Inc. -000819 Banksys -00081A Sanrad Intelligence Storage Communications (2000) Ltd. -00081B Windigo Systems -00081C @pos.com -00081D Ipsil, Incorporated -00081E Repeatit AB -00081F Pou Yuen Tech Corp. Ltd. -000820 Cisco Systems Inc. -000821 Cisco Systems Inc. -000822 InPro Comm -000823 Texa Corp. -000824 Promatek Industries Ltd. -000825 Acme Packet -000826 Colorado Med Tech -000827 Pirelli Cables & Systems -000828 Koei Engineering Ltd. -000829 Aval Nagasaki Corporation -00082A Powerwallz Network Security -00082B Wooksung Electronics, Inc. -00082C Homag AG -00082D Indus Teqsite Private Limited -00082E Multitone Electronics PLC -00084E DivergeNet, Inc. -00084F Qualstar Corporation -000850 Arizona Instrument Corp. -000851 Canadian Bank Note Company, Ltd. -000852 Davolink Co. Inc. -000853 Schleicher GmbH & Co. Relaiswerke KG -000854 Netronix, Inc. -000855 NASA-Goddard Space Flight Center -000856 Gamatronic Electronic Industries Ltd. -000857 Polaris Networks, Inc. -000858 Novatechnology Inc. -000859 ShenZhen Unitone Electronics Co., Ltd. -00085A IntiGate Inc. -00085B Hanbit Electronics Co., Ltd. -00085C Shanghai Dare Technologies Co. Ltd. -00085D Aastra -00085E PCO AG -00085F Picanol N.V. -000860 LodgeNet Entertainment Corp. -000861 SoftEnergy Co., Ltd. -000862 NEC Eluminant Technologies, Inc. -000863 Entrisphere Inc. -000864 Fasy S.p.A. -000865 JASCOM CO., LTD -000866 DSX Access Systems, Inc. -000867 Uptime Devices -000868 PurOptix -000869 Command-e Technology Co.,Ltd. -00086A Industrie Technik IPS GmbH -00086B MIPSYS -00086C Plasmon LMS -00086D Missouri FreeNet -00086E Hyglo AB -00086F Resources Computer Network Ltd. -000870 Rasvia Systems, Inc. -000871 NORTHDATA Co., Ltd. -000872 Sorenson Technologies, Inc. -000873 DAP Design B.V. -000874 Dell Computer Corp. -000875 Acorp Electronics Corp. -000876 SDSystem -000877 Liebert HIROSS S.p.A. -000878 Benchmark Storage Innovations -000879 CEM Corporation -00087A Wipotec GmbH -00087B RTX Telecom A/S -00087C Cisco Systems, Inc. -00087D Cisco Systems Inc. -00087E Bon Electro-Telecom Inc. -00087F SPAUN electronic GmbH & Co. KG -000880 BroadTel Canada Communications inc. -000881 DIGITAL HANDS CO.,LTD. -000882 SIGMA CORPORATION -000883 Hewlett-Packard Company -000884 Index Braille AB -000885 EMS Dr. Thomas Wuensche -000886 Hansung Teliann, Inc. -000887 Maschinenfabrik Reinhausen GmbH -000888 OULLIM Information Technology Inc,. -000889 Echostar Technologies Corp -00088A Minds@Work -00088B Tropic Networks Inc. -00088C Quanta Network Systems Inc. -00088D Sigma-Links Inc. -00088E Nihon Computer Co., Ltd. -00088F ADVANCED DIGITAL TECHNOLOGY -000890 AVILINKS SA -000891 Lyan Inc. -000892 EM Solutions -000894 InnoVISION Multimedia Ltd. -000895 DIRC Technologie GmbH & Co.KG -000896 Printronix, Inc. -000897 Quake Technologies -000898 Gigabit Optics Corporation -000899 Netbind, Inc. -00089A Alcatel Microelectronics -00089B ICP Electronics Inc. -00089C Elecs Industry Co., Ltd. -00089D UHD-Elektronik -00089E Beijing Enter-Net co.LTD -00089F EFM Networks -0008A0 Stotz Feinmesstechnik GmbH -0008A1 CNet Technology Inc. -0008A2 ADI Engineering, Inc. -0008A3 Cisco Systems -0008A4 Cisco Systems -0008A5 Peninsula Systems Inc. -0008A6 Multiware & Image Co., Ltd. -0008A7 iLogic Inc. -0008A8 Systec Co., Ltd. -0008A9 SangSang Technology, Inc. -0008AA KARAM -0008AB EnerLinx.com, Inc. -0008AD Toyo-Linx Co., Ltd. -0008AE Packetfront -0008AF Novatec Corporation -0008B0 BKtel communications GmbH -0008B1 ProQuent Systems -0008B2 SHENZHEN COMPASS TECHNOLOGY DEVELOPMENT CO.,LTD -0008B3 Fastwel -0008B4 SYSPOL -0008B5 TAI GUEN ENTERPRISE CO., LTD -0008B6 RouteFree, Inc. -0008B7 HIT Incorporated -0008B8 E.F. Johnson -0008B9 KAON MEDIA Co., Ltd. -0008BA Erskine Systems Ltd -0008BB NetExcell -0008BC Ilevo AB -0008BD TEPG-US -0008BE XENPAK MSA Group -0008BF Aptus Elektronik AB -0008C0 ASA SYSTEMS -0008C1 Avistar Communications Corporation -0008C2 Cisco Systems -0008C3 Contex A/S -0008C4 Hikari Co.,Ltd. -0008C5 Liontech Co., Ltd. -0008C6 Philips Consumer Communications -0008C7 COMPAQ COMPUTER CORPORATION -0008C8 Soneticom, Inc. -0008C9 TechniSat Digital GmbH -0008CA TwinHan Technology Co.,Ltd -0008CB Zeta Broadband Inc. -0008CC Remotec, Inc. -0008CD With-Net Inc -0008CF Nippon Koei Power Systems Co., Ltd. -0008D0 Musashi Engineering Co., LTD. -0008D1 KAREL INC. -0008D2 ZOOM Networks Inc. -0008D3 Hercules Technologies S.A. -0008D4 IneoQuest Technologies, Inc -0008D5 Vanguard Managed Solutions -0008D6 HASSNET Inc. -0008D7 HOW CORPORATION -0008D8 Dowkey Microwave -0008D9 Mitadenshi Co.,LTD -0008DA SofaWare Technologies Ltd. -0008DB Corrigent Systems -0008DC Wiznet -0008DD Telena Communications, Inc. -0008DE 3UP Systems -0008DF Alistel Inc. -0008E0 ATO Technology Ltd. -0008E1 Barix AG -0008E2 Cisco Systems -0008E3 Cisco Systems -0008E4 Envenergy Inc -0008E5 IDK Corporation -0008E6 Littlefeet -0008E7 SHI ControlSystems,Ltd. -0008E8 Excel Master Ltd. -0008E9 NextGig -0008EA Motion Control Engineering, Inc -0008EB ROMWin Co.,Ltd. -0008EC Zonu, Inc. -0008ED ST&T Instrument Corp. -0008EE Logic Product Development -0008EF DIBAL,S.A. -0008F0 Next Generation Systems, Inc. -0008F1 Voltaire -0008F2 C&S Technology -0008F3 WANY -0008F4 Bluetake Technology Co., Ltd. -0008F5 YESTECHNOLOGY Co.,Ltd. -0008F6 SUMITOMO ELECTRIC HIGHTECHS.co.,ltd. -0008F7 Hitachi Ltd, Semiconductor & Integrated Circuits Gr -0008F8 Guardall Ltd -0008F9 Padcom, Inc. -0008FA Karl E.Brinkmann GmbH -0008FB SonoSite, Inc. -0008FC Gigaphoton Inc. -0008FD BlueKorea Co., Ltd. -0008FE UNIK C&C Co.,Ltd. -0008FF Trilogy Broadcast (Holdings) Ltd -000900 TMT -000901 Shenzhen Shixuntong Information & Technoligy Co -000902 Redline Communications Inc. -000903 Panasas, Inc -000904 MONDIAL electronic -000905 iTEC Technologies Ltd. -000906 Esteem Networks -000907 Chrysalis Development -000908 VTech Technology Corp. -000909 Telenor Connect A/S -00090A SnedFar Technology Co., Ltd. -00090B MTL Instruments PLC -00090C Mayekawa Mfg. Co. Ltd. -00090D LEADER ELECTRONICS CORP. -00090E Helix Technology Inc. -00090F Fortinet Inc. -000910 Simple Access Inc. -000911 Cisco Systems -000912 Cisco Systems -000914 COMPUTROLS INC. -000915 CAS Corp. -000916 Listman Home Technologies, Inc. -000917 WEM Technology Inc -000918 SAMSUNG TECHWIN CO.,LTD -000919 MDS Gateways -00091A Macat Optics & Electronics Co., Ltd. -00091B Digital Generation Inc. -00091C CacheVision, Inc -00091D Proteam Computer Corporation -00091E Firstech Technology Corp. -00091F A&D Co., Ltd. -000920 EpoX COMPUTER CO.,LTD. -000921 Planmeca Oy -000922 Touchless Sensor Technology AG -000923 Heaman System Co., Ltd -000924 Telebau GmbH -000925 VSN Systemen BV -000926 YODA COMMUNICATIONS, INC. -000927 TOYOKEIKI CO.,LTD. -000928 Telecore Inc -000929 Sanyo Industries (UK) Limited -00092A MYTECS Co.,Ltd. -00092B iQstor Networks, Inc. -00092C Hitpoint Inc. -00092D High Tech Computer, Corp. -00092E B&Tech System Inc. -00092F Akom Technology Corporation -000930 AeroConcierge Inc. -000931 Future Internet, Inc. -000932 Omnilux -000933 OPTOVALLEY Co. Ltd. -000934 Dream-Multimedia-Tv GmbH -000935 Sandvine Incorporated -000936 Ipetronik GmbH & Co.KG -000937 Inventec Appliance Corp -000938 Allot Communications -000939 ShibaSoku Co.,Ltd. -00093A Molex Fiber Optics -00093B HYUNDAI NETWORKS INC. -00093C Jacques Technologies P/L -00093D Newisys,Inc. -00093E C&I Technologies -00093F Double-Win Enterpirse CO., LTD -000940 AGFEO GmbH & Co. KG -000941 Allied Telesis K.K. -000942 CRESCO, LTD. -000943 Cisco Systems -000944 Cisco Systems -000945 Palmmicro Communications Inc -000946 Cluster Labs GmbH -000947 Aztek, Inc. -000948 Vista Control Systems, Corp. -000949 Glyph Technologies Inc. -00094A Homenet Communications -00094B FillFactory NV -00094C Communication Weaver Co.,Ltd. -00094D Braintree Communications Pty Ltd -00094E BARTECH SYSTEMS INTERNATIONAL, INC -00094F elmegt GmbH & Co. KG -000950 Independent Storage Corporation -000951 Apogee Instruments, Inc -000952 Auerswald GmbH & Co. KG -000953 Linkage System Integration Co.Ltd. -000954 AMiT spol. s. r. o. -000955 Young Generation International Corp. -000956 Network Systems Group, Ltd. (NSG) -000957 Supercaller, Inc. -000958 INTELNET S.A. -000959 Sitecsoft -00095A RACEWOOD TECHNOLOGY -00095B Netgear, Inc. -00095C Philips Medical Systems - Cardiac and Monitoring Systems (CM -00095D Dialogue Technology Corp. -00095E Masstech Group Inc. -00095F Telebyte, Inc. -000960 YOZAN Inc. -000961 Switchgear and Instrumentation Ltd -000962 Filetrac AS -000963 Dominion Lasercom Inc. -000964 Hi-Techniques -000966 Thales Navigation -000967 Tachyon, Inc -000968 TECHNOVENTURE, INC. -000969 Meret Optical Communications -00096A Cloverleaf Communications Inc. -00096B IBM Corporation -00096C Imedia Semiconductor Corp. -00096D Powernet Technologies Corp. -00096E GIANT ELECTRONICS LTD. -00096F Beijing Zhongqing Elegant Tech. Corp.,Limited -000970 Vibration Research Corporation -000971 Time Management, Inc. -000972 Securebase,Inc -000973 Lenten Technology Co., Ltd. -000974 Innopia Technologies, Inc. -000975 fSONA Communications Corporation -000976 Datasoft ISDN Systems GmbH -000977 Brunner Elektronik AG -000978 AIJI System Co., Ltd. -000979 Advanced Television Systems Committee, Inc. -00097A Louis Design Labs. -00097B Cisco Systems -00097C Cisco Systems -00097D SecWell Networks Oy -00097E IMI TECHNOLOGY CO., LTD -00097F Vsecure 2000 LTD. -000980 Power Zenith Inc. -000981 Newport Networks -000982 Loewe Opta GmbH -000983 Gvision Incorporated -000984 MyCasa Network Inc. -000985 Auto Telecom Company -000986 Metalink LTD. -000987 NISHI NIPPON ELECTRIC WIRE & CABLE CO.,LTD. -000988 Nudian Electron Co., Ltd. -000989 VividLogic Inc. -00098A EqualLogic Inc -00098B Entropic Communications, Inc. -00098C Possio AB -00098D DCT Ltd (Digital Communication Technologies Ltd) -00098E ipcas GmbH -00098F Cetacean Networks -000990 ACKSYS Communications & systems -000991 GE Fanuc Automation Manufacturing, Inc. -000992 InterEpoch Technology,INC. -000993 Visteon Corporation -000994 Cronyx Engineering -000995 Castle Technology Ltd -000996 RDI -000997 Nortel Networks -000998 Capinfo Company Limited -000999 CP GEORGES RENAULT -00099A ELMO COMPANY, LIMITED -00099B Western Telematic Inc. -00099C Naval Research Laboratory -00099D Haliplex Communications -00099E Testech, Inc. -00099F VIDEX INC. -0009A0 Microtechno Corporation -0009A1 Telewise Communications, Inc. -0009A2 Interface Co., Ltd. -0009A3 Leadfly Techologies Corp. Ltd. -0009A4 HARTEC Corporation -0009A5 HANSUNG ELETRONIC INDUSTRIES DEVELOPMENT CO., LTD -0009A6 Ignis Optics, Inc. -0009A7 Bang & Olufsen A/S -0009A8 Eastmode Pte Ltd -0009A9 Ikanos Communications -0009AA Data Comm for Business, Inc. -0009AB Netcontrol Oy -0009AC LANVOICE -0009AD HYUNDAI SYSCOMM, INC. -0009AE OKANO ELECTRIC CO.,LTD -0009AF e-generis -0009B0 Onkyo Corporation -0009B1 Kanematsu Electronics, Ltd. -0009B2 L&F Inc. -0009B3 MCM Systems Ltd -0009B4 KISAN TELECOM CO., LTD. -0009B5 3J Tech. Co., Ltd. -0009B6 Cisco Systems -0009B7 Cisco Systems -0009B8 Entise Systems -0009B9 Action Imaging Solutions -0009BA MAKU Informationstechik GmbH -0009BB MathStar, Inc. -0009BC Digital Safety Technologies Inc. -0009BD Epygi Technologies, Ltd. -0009BE Mamiya-OP Co.,Ltd. -0009BF Nintendo Co.,Ltd. -0009C0 6WIND -0009C1 PROCES-DATA A/S -0009C3 NETAS -0009C4 Medicore Co., Ltd -0009C5 KINGENE Technology Corporation -0009C6 Visionics Corporation -0009C7 Movistec -0009C8 SINAGAWA TSUSHIN KEISOU SERVICE -0009C9 BlueWINC Co., Ltd. -0009CA iMaxNetworks(Shenzhen)Limited. -0009CB HBrain -0009CC Moog GmbH -0009CD HUDSON SOFT CO.,LTD. -0009CE SpaceBridge Semiconductor Corp. -0009CF iAd GmbH -0009D0 Versatel Networks -0009D1 SERANOA NETWORKS INC -0009D2 Mai Logic Inc. -0009D3 Western DataCom Co., Inc. -0009D4 Transtech Networks -0009D5 Signal Communication, Inc. -0009D6 KNC One GmbH -0009D7 DC Security Products -0009D9 Neoscale Systems, Inc -0009DA Control Module Inc. -0009DB eSpace -0009DC Galaxis Technology AG -0009DD Mavin Technology Inc. -0009DE Samjin Information & Communications Co., Ltd. -0009DF Vestel Komunikasyon Sanayi ve Ticaret A.S. -0009E0 XEMICS S.A. -0009E1 Gemtek Technology Co., Ltd. -0009E2 Sinbon Electronics Co., Ltd. -0009E3 Angel Iglesias S.A. -0009E4 K Tech Infosystem Inc. -0009E5 Hottinger Baldwin Messtechnik GmbH -0009E6 Cyber Switching Inc. -0009E7 ADC Techonology -0009E8 Cisco Systems -0009E9 Cisco Systems -0009EA YEM Inc. -0009EB HuMANDATA LTD. -0009EC Daktronics, Inc. -0009ED CipherOptics -0009EE MEIKYO ELECTRIC CO.,LTD -0009EF Vocera Communications -0009F0 Shimizu Technology Inc. -0009F1 Yamaki Electric Corporation -0009F2 Cohu, Inc., Electronics Division -0009F3 WELL Communication Corp. -0009F4 Alcon Laboratories, Inc. -0009F5 Emerson Network Power Co.,Ltd -0009F6 Shenzhen Eastern Digital Tech Ltd. -0009F7 SED, a division of Calian -0009F8 UNIMO TECHNOLOGY CO., LTD. -0009F9 ART JAPAN CO., LTD. -0009FB Philips Medizinsysteme Boeblingen GmbH -0009FC IPFLEX Inc. -0009FD Ubinetics Limited -0009FE Daisy Technologies, Inc. -0009FF X.net 2000 GmbH -000A00 Mediatek Corp. -000A01 SOHOware, Inc. -000A02 ANNSO CO., LTD. -000A03 ENDESA SERVICIOS, S.L. -000A04 3Com Europe Ltd -000A05 Widax Corp. -000A06 Teledex LLC -000A07 WebWayOne Ltd -000A08 ALPINE ELECTRONICS, INC. -000A09 TaraCom Integrated Products, Inc. -000A0A SUNIX Co., Ltd. -000A0B Sealevel Systems, Inc. -000A0C Scientific Research Corporation -000A0D MergeOptics GmbH -000A0E Invivo Research Inc. -000A0F Ilryung Telesys, Inc -000A10 FAST media integrations AG -000A11 ExPet Technologies, Inc -000A12 Azylex Technology, Inc -000A13 Silent Witness -000A14 TECO a.s. -000A15 Silicon Data, Inc -000A16 Lassen Research -000A17 NESTAR COMMUNICATIONS, INC -000A18 Vichel Inc. -000A19 Valere Power, Inc. -000A1A Imerge Ltd -000A1B Stream Labs -000A1C Bridge Information Co., Ltd. -000A1D Optical Communications Products Inc. -000A1E Red-M (Communications) Limited -000A1F ART WARE Telecommunication Co., Ltd. -000A20 SVA Networks, Inc. -000A21 Integra Telecom Co. Ltd -000A22 Amperion Inc -000A23 Parama Networks Inc -000A24 Octave Communications -000A25 CERAGON NETWORKS -000A26 CEIA S.p.A. -000A27 Apple Computer, Inc. -000A28 Motorola -000A29 Pan Dacom Networking AG -000A2A QSI Systems Inc. -000A2B Etherstuff -000A2C Active Tchnology Corporation -000A2E MAPLE NETWORKS CO., LTD -000A2F Artnix Inc. -000A30 Johnson Controls-ASG -000A31 HCV Wireless -000A32 Xsido Corporation -000A33 Sierra Logic, Inc. -000A34 Identicard Systems Incorporated -000A35 Xilinx -000A36 Synelec Telecom Multimedia -000A37 Procera Networks, Inc. -000A38 Netlock Technologies, Inc. -000A39 LoPA Information Technology -000A3A J-THREE INTERNATIONAL Holding Co., Ltd. -000A3B GCT Semiconductor, Inc -000A3C Enerpoint Ltd. -000A3D Elo Sistemas Eletronicos S.A. -000A3E EADS Telecom -000A3F Data East Corporation -000A40 Crown Audio -000A41 Cisco Systems -000A42 Cisco Systems -000A43 Chunghwa Telecom Co., Ltd. -000A44 Avery Dennison Deutschland GmbH -000A45 Audio-Technica Corp. -000A46 ARO Controls SAS -000A47 Allied Vision Technologies -000A48 Albatron Technology -000A49 Acopia Networks -000A4A Targa Systems Ltd. -000A4B DataPower Technology, Inc. -000A4C Molecular Devices Corporation -000A4D Noritz Corporation -000A4E UNITEK Electronics INC. -000A4F Brain Boxes Limited -000A50 REMOTEK CORPORATION -000A51 GyroSignal Technology Co., Ltd. -000A52 Venitek Co. Ltd. -000A53 Intronics, Incorporated -000A54 Laguna Hills, Inc. -000A55 MARKEM Corporation -000A56 HITACHI Maxell Ltd. -000A57 Hewlett-Packard Company - Standards -000A58 Ingenieur-Buero Freyer & Siegel -000A59 HW server -000A5A GreenNET Technologies Co.,Ltd. -000A5B Power-One as -000A5C Carel s.p.a. -000A5D PUC Founder (MSC) Berhad -000A5E 3COM Corporation -000A5F almedio inc. -000A60 Autostar Technology Pte Ltd -000A61 Cellinx Systems Inc. -000A62 Crinis Networks, Inc. -000A63 DHD GmbH -000A64 Eracom Technologies -000A65 GentechMedia.co.,ltd. -000A66 MITSUBISHI ELECTRIC SYSTEM & SERVICE CO.,LTD. -000A67 OngCorp -000A68 SolarFlare Communications, Inc. -000A69 SUNNY bell Technology Co., Ltd. -000A6A SVM Microwaves s.r.o. -000A6B Tadiran Telecom Business Systems LTD -000A6C Walchem Corporation -000A6D EKS Elektronikservice GmbH -000A6E Broadcast Technology Limited -000A6F ZyTera Technologies Inc. -000A70 MPLS Forum -000A71 Avrio Technologies, Inc -000A72 SimpleTech, Inc. -000A73 Scientific Atlanta -000A74 Manticom Networks Inc. -000A75 Cat Electronics -000A76 Beida Jade Bird Huaguang Technology Co.,Ltd -000A77 Bluewire Technologies LLC -000A78 OLITEC -000A79 corega K.K. -000A7A Kyoritsu Electric Co., Ltd. -000A7B Cornelius Consult -000A7C Tecton Ltd -000A7D Valo, Inc. -000A7E The Advantage Group -000A7F Teradon Industries, Inc -000A80 Telkonet Inc. -000A81 TEIMA Audiotex S.L. -000A82 TATSUTA SYSTEM ELECTRONICS CO.,LTD. -000A83 SALTO SYSTEMS S.L. -000A84 Rainsun Enterprise Co., Ltd. -000A85 PLAT'C2,Inc -000A86 Lenze -000A87 Integrated Micromachines Inc. -000A88 InCypher S.A. -000A89 Creval Systems, Inc. -000A8A Cisco Systems -000A8B Cisco Systems -000A8C Guardware Systems Ltd. -000A8D EUROTHERM LIMITED -000A8E Invacom Ltd -000A8F Aska International Inc. -000A90 Bayside Interactive, Inc. -000A91 HemoCue AB -000A92 Presonus Corporation -000A93 W2 Networks, Inc. -000A94 ShangHai cellink CO., LTD -000A95 Apple Computer, Inc. -000A96 MEWTEL TECHNOLOGY INC. -000A97 SONICblue, Inc. -000A98 M+F Gwinner GmbH & Co -000A99 Dataradio Inc. -000A9A Aiptek International Inc -000A9B Towa Meccs Corporation -000A9C Server Technology, Inc. -000A9D King Young Technology Co. Ltd. -000A9E BroadWeb Corportation -000A9F Pannaway Technologies, Inc. -000AA0 Cedar Point Communications -000AA1 V V S Limited -000AA2 SYSTEK INC. -000AA3 SHIMAFUJI ELECTRIC CO.,LTD. -000AA4 SHANGHAI SURVEILLANCE TECHNOLOGY CO,LTD -000AA5 MAXLINK INDUSTRIES LIMITED -000AA6 Hochiki Corporation -000AA7 FEI Company -000AA8 ePipe Pty. Ltd. -000AA9 Brooks Automation GmbH -000AAA AltiGen Communications Inc. -000AAB TOYOTA MACS, INC. -000AAC TerraTec Electronic GmbH -000AAD Stargames Corporation -000AAE Rosemount Process Analytical -000AAF Pipal Systems -000AB0 LOYTEC electronics GmbH -000AB1 GENETEC Corporation -000AB2 Fresnel Wireless Systems -000AB3 Fa. GIRA -000AB4 ETIC Telecommunications -000AB5 Digital Electronic Network -000AB6 COMPUNETIX, INC -000AB7 Cisco Systems -000AB8 Cisco Systems -000AB9 Astera Technologies Corp. -000ABA Arcon Technology Limited -000ABB Taiwan Secom Co,. Ltd -000ABC Seabridge Ltd. -000ABD Rupprecht & Patashnick Co. -000ABE OPNET Technologies CO., LTD. -000ABF HIROTA SS -000AC0 Fuyoh Video Industry CO., LTD. -000AC1 Futuretel -000AC2 FiberHome Telecommunication Technologies CO.,LTD -000AC3 eM Technics Co., Ltd. -000AC4 Daewoo Teletech Co., Ltd -000AC5 Color Kinetics -000AC7 Unication Group -000AC8 ZPSYS CO.,LTD. (Planning&Management) -000AC9 Zambeel Inc -000ACA YOKOYAMA SHOKAI CO.,Ltd. -000ACB XPAK MSA Group -000ACC Winnow Networks, Inc. -000ACD Sunrich Technology Limited -000ACE RADIANTECH, INC. -000ACF PROVIDEO Multimedia Co. Ltd. -000AD0 Niigata Develoment Center, F.I.T. Co., Ltd. -000AD1 MWS -000AD2 JEPICO Corporation -000AD3 INITECH Co., Ltd -000AD4 CoreBell Systems Inc. -000AD5 Brainchild Electronic Co., Ltd. -000AD6 BeamReach Networks -000AD8 IPCserv Technology Corp. -000AD9 Sony Ericsson Mobile Communications AB -000ADB SkyPilot Network, Inc -000ADC RuggedCom Inc. -000ADD InSciTek Microsystems, Inc. -000ADE Happy Communication Co., Ltd. -000ADF Gennum Corporation -000AE0 Fujitsu Softek -000AE1 EG Technology -000AE2 Binatone Electronics International, Ltd -000AE3 YANG MEI TECHNOLOGY CO., LTD -000AE4 Wistron Corp. -000AE5 ScottCare Corporation -000AE6 Elitegroup Computer System Co. (ECS) -000AE7 ELIOP S.A. -000AE8 Cathay Roxus Information Technology Co. LTD -000AE9 AirVast Technology Inc. -000AEA ADAM ELEKTRONIK LTD.STI. -000AEB Shenzhen Tp-link Technology Co; Ltd. -000AEC Koatsu Gas Kogyo Co., Ltd. -000AED HARTING Vending G.m.b.H. & CO KG -000AEE GCD Hard- & Software GmbH -000AEF OTRUM ASA -000AF0 SHIN-OH ELECTRONICS CO., LTD. R&D -000AF1 Clarity Design, Inc. -000AF2 NeoAxiom Corp. -000AF3 Cisco Systems -000AF4 Cisco Systems -000AF5 Airgo Networks, Inc. -000AF6 Computer Process Controls -000AF7 Broadcom Corp. -000AF8 American Telecare Inc. -000AFA Traverse Technologies Australia -000AFB Ambri Limited -000AFC Core Tec Communications, LLC -000AFD Viking Electronic Services -000AFE NovaPal Ltd -000AFF Kilchherr Elektronik AG -000B00 FUJIAN START COMPUTER EQUIPMENT CO.,LTD -000B01 DAIICHI ELECTRONICS CO., LTD. -000B02 Dallmeier electronic -000B03 Taekwang Industrial Co., Ltd -000B04 Volktek Corporation -000B05 Pacific Broadband Networks -000B06 Motorola BCS -000B07 Voxpath Networks -000B08 Pillar Data Systems -000B09 Ifoundry Systems Singapore -000B0A dBm Optics -000B0B Corrent Corporation -000B0C Agile Systems Inc. -000B0D Air2U, Inc. -000B0E Trapeze Networks -000B0F Nyquist Industrial Control BV -000B10 11wave Technonlogy Co.,Ltd -000B11 HIMEJI ABC TRADING CO.,LTD. -000B13 ZETRON INC -000B14 ViewSonic Corporation -000B15 Platypus Technology -000B16 Communication Machinery Corporation -000B17 MKS Instruments -000B19 Vernier Networks, Inc. -000B1A Teltone Corporation -000B1B Systronix, Inc. -000B1D LayerZero Power Systems, Inc. -000B1E KAPPA opto-electronics GmbH -000B1F I CON Computer Co. -000B20 Hirata corporation -000B21 G-Star Communications Inc. -000B22 Environmental Systems and Services -000B23 Efficient Networks, Inc. -000B24 AirLogic -000B25 Aeluros -000B26 Wetek Corporation -000B27 Scion Corporation -000B28 Quatech Inc. -000B29 LG Industrial Systems Co.,Ltd. -000B2A HOWTEL Co., Ltd. -000B2B HOSTNET CORPORATION -000B2C Eiki Industrial Co. Ltd. -000B2D Danfoss Inc. -000B2E Cal-Comp Electronics (Thailand) Public Company Limited Taipe -000B2F bplan GmbH -000B30 Beijing Gongye Science & Technology Co.,Ltd -000B31 Yantai ZhiYang Scientific and technology industry CO., LTD -000B32 VORMETRIC, INC. -000B33 Vivato -000B34 ShangHai Broadband Technologies CO.LTD -000B35 Quad Bit System co., Ltd. -000B36 Productivity Systems, Inc. -000B37 MANUFACTURE DES MONTRES ROLEX SA -000B38 Knuerr AG -000B39 Keisoku Giken Co.,Ltd. -000B3A Fortel DTV, Inc. -000B3B devolo AG -000B3C Cygnal Integrated Products, Inc. -000B3D CONTAL OK Ltd. -000B3E BittWare, Inc -000B3F Anthology Solutions Inc. -000B40 OpNext Inc. -000B41 Ing. Buero Dr. Beutlhauser -000B42 commax Co., Ltd. -000B43 Microscan Systems, Inc. -000B44 Concord IDea Corp. -000B45 Cisco -000B46 Cisco -000B47 Advanced Energy -000B48 sofrel -000B49 RF-Link System Inc. -000B4A Visimetrics (UK) Ltd -000B4B VISIOWAVE SA -000B4C Clarion (M) Sdn Bhd -000B4D Emuzed -000B4E VertexRSI Antenna Products Division -000B4F Verifone, INC. -000B50 Oxygnet -000B51 Micetek International Inc. -000B52 JOYMAX ELECTRONICS CORP. -000B53 INITIUM Co., Ltd. -000B54 BiTMICRO Networks, Inc. -000B55 ADInstruments -000B56 Cybernetics -000B57 Silicon Laboratories -000B58 Astronautics C.A LTD -000B59 ScriptPro, LLC -000B5A HyperEdge -000B5B Rincon Research Corporation -000B5C Newtech Co.,Ltd -000B5D FUJITSU LIMITED -000B5E ATMAVA Ltd -000B5F Cisco Systems -000B60 Cisco Systems -000B61 Friedrich Lütze GmbH &Co. -000B62 Ingenieurbüro Ingo Mohnen -000B64 Kieback & Peter GmbH & Co KG -000B65 Sy.A.C. srl -000B66 Teralink Communications -000B67 Topview Technology Corporation -000B68 Addvalue Communications Pte Ltd -000B69 Franke Finland Oy -000B6A Asiarock Incorporation -000B6B Wistron Neweb Corp. -000B6C Sychip Inc. -000B6D SOLECTRON JAPAN NAKANIIDA -000B6E Neff Instrument Corp. -000B6F Media Streaming Networks Inc -000B70 Load Technology, Inc. -000B71 Litchfield Communications Inc. -000B72 Lawo AG -000B73 Kodeos Communications -000B74 Kingwave Technology Co., Ltd. -000B75 Iosoft Ltd. -000B76 ET&T Co. Ltd. -000B77 Cogent Systems, Inc. -000B78 TAIFATECH INC. -000B79 X-COM, Inc. -000B7B Test-Um Inc. -000B7C Telex Communications -000B7D SOLOMON EXTREME INTERNATIONAL LTD. -000B7E SAGINOMIYA Seisakusho Inc. -000B7F OmniWerks -000B81 Kaparel Corporation -000B82 Grandstream Networks, Inc. -000B83 DATAWATT B.V. -000B84 BODET -000B85 Airespace, Inc. -000B86 Aruba Networks -000B87 American Reliance Inc. -000B88 Vidisco ltd. -000B89 Top Global Technology, Ltd. -000B8A MITEQ Inc. -000B8B KERAJET, S.A. -000B8C flextronics israel -000B8D Avvio Networks -000B8E Ascent Corporation -000B8F AKITA ELECTRONICS SYSTEMS CO.,LTD. -000B90 Covaro Networks, Inc. -000B91 Aglaia Gesellschaft für Bildverarbeitung und Kommunikation m -000B92 Ascom Danmark A/S -000B93 Barmag Electronic -000B94 Digital Monitoring Products, Inc. -000B95 eBet Gaming Systems Pty Ltd -000B96 Innotrac Diagnostics Oy -000B97 Matsushita Electric Industrial Co.,Ltd. -000B98 NiceTechVision -000B99 SensAble Technologies, Inc. -000B9A Shanghai Ulink Telecom Equipment Co. Ltd. -000B9B Sirius System Co, Ltd. -000B9C TriBeam Technologies, Inc. -000B9D TwinMOS Technologies Inc. -000B9E Yasing Technology Corp. -000B9F Neue ELSA GmbH -000BA0 T&L Information Inc. -000BA1 SYSCOM Ltd. -000BA2 Sumitomo Electric Networks, Inc -000BA3 Siemens AG, I&S -000BA4 Shiron Satellite Communications Ltd. (1996) -000BA5 Quasar Cipta Mandiri, PT -000BA6 Miyakawa Electric Works Ltd. -000BA7 Maranti Networks -000BA8 HANBACK ELECTRONICS CO., LTD. -000BAA Aiphone co.,Ltd -000BAB Advantech Technology (CHINA) Co., Ltd. -000BAC 3Com Europe Ltd. -000BAD PC-PoS Inc. -000BAE Vitals System Inc. -000BB0 Sysnet Telematica srl -000BB1 Super Star Technology Co., Ltd. -000BB2 SMALLBIG TECHNOLOGY -000BB3 RiT technologies Ltd. -000BB4 RDC Semiconductor Inc., -000BB5 nStor Technologies, Inc. -000BB6 Mototech Inc. -000BB7 Micro Systems Co.,Ltd. -000BB8 Kihoku Electronic Co. -000BB9 Imsys AB -000BBA Harmonic Broadband Access Networks -000BBB Etin Systems Co., Ltd -000BBC En Garde Systems, Inc. -000BBD Connexionz Limited -000BBE Cisco Systems -000BBF Cisco Systems -000BC0 China IWNComm Co., Ltd. -000BC1 Bay Microsystems, Inc. -000BC2 Corinex Communication Corp. -000BC3 Multiplex, Inc. -000BC4 BIOTRONIK GmbH & Co -000BC5 SMC Networks, Inc. -000BC6 ISAC, Inc. -000BC7 ICET S.p.A. -000BC8 AirFlow Networks -000BC9 Electroline Equipment -000BCA DATAVAN International Corporation -000BCB Fagor Automation , S. Coop -000BCC JUSAN, S.A. -000BCD Compaq (HP) -000BCE Free2move AB -000BCF AGFA NDT INC. -000BD0 XiMeta Technology Americas Inc. -000BD1 Aeronix, Inc. -000BD2 Remopro Technology Inc. -000BD3 cd3o -000BD4 Beijing Wise Technology & Science Development Co.Ltd -000BD5 Nvergence, Inc. -000BD6 Paxton Access Ltd -000BD7 MBB Gelma GmbH -000BD8 Industrial Scientific Corp. -000BD9 General Hydrogen -000BDA EyeCross Co.,Inc. -000BDB Dell ESG PCBA Test -000BDC AKCP -000BDD TOHOKU RICOH Co., LTD. -000BDF Shenzhen RouterD Networks Limited -000BE0 SercoNet Ltd. -000BE2 Lumenera Corporation -000BE3 Key Stream Co., Ltd. -000BE4 Hosiden Corporation -000BE5 HIMS Korea Co., Ltd. -000BE6 Datel Electronics -000BE7 COMFLUX TECHNOLOGY INC. -000BE8 AOIP -000BEA Zultys Technologies -000BEB Systegra AG -000BEC NIPPON ELECTRIC INSTRUMENT, INC. -000BED ELM Inc. -000BEE inc.jet, Incorporated -000BEF Code Corporation -000BF0 MoTEX Products Co., Ltd. -000BF1 LAP Laser Applikations -000BF2 Chih-Kan Technology Co., Ltd. -000BF3 BAE SYSTEMS -000BF5 Shanghai Sibo Telecom Technology Co.,Ltd -000BF6 Nitgen Co., Ltd -000BF7 NIDEK CO.,LTD -000BF8 Infinera -000BF9 Gemstone communications, Inc. -000BFB D-NET International Corporation -000BFC Cisco Systems -000BFD Cisco Systems -000BFE CASTEL Broadband Limited -000BFF Berkeley Camera Engineering -000C00 BEB Industrie-Elektronik AG -000C01 Abatron AG -000C02 ABB Oy -000C03 HDMI Licensing, LLC -000C04 Tecnova -000C05 RPA Reserch Co., Ltd. -000C06 Nixvue Systems Pte Ltd -000C07 Iftest AG -000C08 HUMEX Technologies Corp. -000C09 Hitachi IE Systems Co., Ltd -000C0A Guangdong Province Electronic Technology Research Institute -000C0B Broadbus Technologies -000C0C APPRO TECHNOLOGY INC. -000C0D Communications & Power Industries / Satcom Division -000C0E XtremeSpectrum, Inc. -000C0F Techno-One Co., Ltd -000C10 PNI Corporation -000C11 NIPPON DEMPA CO.,LTD. -000C12 Micro-Optronic-Messtechnik GmbH -000C13 MediaQ -000C14 Diagnostic Instruments, Inc. -000C15 CyberPower Systems, Inc. -000C16 Concorde Microsystems Inc. -000C17 AJA Video Systems Inc -000C18 Zenisu Keisoku Inc. -000C19 Telio Communications GmbH -000C1A Quest Technical Solutions Inc. -000C1B ORACOM Co, Ltd. -000C1C MicroWeb Co., Ltd. -000C1D Mettler & Fuchs AG -000C1E Global Cache -000C1F Glimmerglass Networks -000C20 Fi WIn, Inc. -000C21 Faculty of Science and Technology, Keio University -000C22 Double D Electronics Ltd -000C23 Beijing Lanchuan Tech. Co., Ltd. -000C25 Allied Telesyn Networks -000C26 Weintek Labs. Inc. -000C27 Sammy Corporation -000C28 RIFATRON -000C29 VMware, Inc. -000C2A OCTTEL Communication Co., Ltd. -000C2B ELIAS Technology, Inc. -000C2C Enwiser Inc. -000C2D FullWave Technology Co., Ltd. -000C2E Openet information technology(shenzhen) Co., Ltd. -000C2F SeorimTechnology Co.,Ltd. -000C30 Cisco -000C31 Cisco -000C32 Avionic Design Development GmbH -000C33 Compucase Enterprise Co. Ltd. -000C34 Vixen Co., Ltd. -000C35 KaVo Dental GmbH & Co. KG -000C36 SHARP TAKAYA ELECTRONICS INDUSTRY CO.,LTD. -000C37 Geomation, Inc. -000C38 TelcoBridges Inc. -000C39 Sentinel Wireless Inc. -000C3A Oxance -000C3B Orion Electric Co., Ltd. -000C3C MediaChorus, Inc. -000C3D Glsystech Co., Ltd. -000C3E Crest Audio -000C3F Cogent Defence & Security Networks, -000C40 Altech Controls -000C41 The Linksys Group, Inc. -000C42 Routerboard.com -000C43 Ralink Technology, Corp. -000C44 Automated Interfaces, Inc. -000C45 Animation Technologies Inc. -000C46 Allied Telesyn Inc. -000C47 SK Teletech(R&D Planning Team) -000C48 QoStek Corporation -000C49 Dangaard Telecom RTC Division A/S -000C4A Cygnus Microsystems Private Limited -000C4B Cheops Elektronik -000C4C Arcor AG&Co. -000C4D ACRA CONTROL -000C4E Winbest Technology CO,LT -000C4F UDTech Japan Corporation -000C50 Seagate Technology -000C51 Scientific Technologies Inc. -000C52 Roll Systems Inc. -000C54 Pedestal Networks, Inc -000C55 Microlink Communications Inc. -000C56 Megatel Computer (1986) Corp. -000C57 MACKIE Engineering Services Belgium BVBA -000C58 M&S Systems -000C59 Indyme Electronics, Inc. -000C5A IBSmm Industrieelektronik Multimedia -000C5B HANWANG TECHNOLOGY CO.,LTD -000C5C GTN Systems B.V. -000C5D CHIC TECHNOLOGY (CHINA) CORP. -000C5F Avtec, Inc. -000C60 ACM Systems -000C61 AC Tech corporation DBA Advanced Digital -000C62 ABB Automation Technology Products AB, Control -000C63 Zenith Electronics Corporation -000C64 X2 MSA Group -000C65 Sunin Telecom -000C66 Pronto Networks Inc -000C67 OYO ELECTRIC CO.,LTD -000C68 Oasis Semiconductor, Inc. -000C69 National Radio Astronomy Observatory -000C6A MBARI -000C6B Kurz Industrie-Elektronik GmbH -000C6C Elgato Systems LLC -000C6D BOC Edwards -000C6E ASUSTEK COMPUTER INC. -000C6F Amtek system co.,LTD. -000C70 ACC GmbH -000C71 Wybron, Inc -000C72 Tempearl Industrial Co., Ltd. -000C73 TELSON ELECTRONICS CO., LTD -000C74 RIVERTEC CORPORATION -000C75 Oriental integrated electronics. LTD -000C76 MICRO-STAR INTERNATIONAL CO., LTD. -000C77 Life Racing Ltd -000C78 In-Tech Electronics Limited -000C79 Extel Communications P/L -000C7A DaTARIUS Technologies GmbH -000C7B ALPHA PROJECT Co.,Ltd. -000C7C Internet Information Image Inc. -000C7D TEIKOKU ELECTRIC MFG. CO., LTD -000C7E Tellium Incorporated -000C7F synertronixx GmbH -000C80 Opelcomm Inc. -000C81 Nulec Industries Pty Ltd -000C82 NETWORK TECHNOLOGIES INC -000C83 Logical Solutions -000C84 Eazix, Inc. -000C85 Cisco Systems -000C86 Cisco Systems -000C87 ATI -000C88 Apache Micro Peripherals, Inc. -000C89 AC Electric Vehicles, Ltd. -000C8A Bose Corporation -000C8B Connect Tech Inc -000C8C KODICOM CO.,LTD. -000C8D MATRIX VISION GmbH -000C8E Mentor Engineering Inc -000C8F Nergal s.r.l. -000C90 Octasic Inc. -000C91 Riverhead Networks Inc. -000C92 WolfVision Gmbh -000C93 Xeline Co., Ltd. -000C94 United Electronic Industries, Inc. -000C95 PrimeNet -000C96 OQO, Inc. -000C97 NV ADB TTV Technologies SA -000C98 LETEK Communications Inc. -000C99 HITEL LINK Co.,Ltd -000C9A Hitech Electronics Corp. -000C9B EE Solutions, Inc -000C9C Chongho information & communications -000C9D AirWalk Communications, Inc. -000C9E MemoryLink Corp. -000C9F NKE Corporation -000CA0 StorCase Technology, Inc. -000CA1 SIGMACOM Co., LTD. -000CA2 Scopus Network Technologies Ltd -000CA3 Rancho Technology, Inc. -000CA4 Prompttec Product Management GmbH -000CA6 Mintera Corporation -000CA7 Metro (Suzhou) Technologies Co., Ltd. -000CA8 Garuda Networks Corporation -000CA9 Ebtron Inc. -000CAA Cubic Transportation Systems Inc -000CAB COMMEND International -000CAC Citizen Watch Co., Ltd. -000CAD BTU International -000CAE Ailocom Oy -000CAF TRI TERM CO.,LTD. -000CB0 Star Semiconductor Corporation -000CB1 Salland Engineering (Europe) BV -000CB2 safei Co., Ltd. -000CB3 ROUND Co.,Ltd. -000CB4 Propagate Networks, Inc -000CB5 Premier Technolgies, Inc -000CB6 NANJING SEU MOBILE & INTERNET TECHNOLOGY CO.,LTD -000CB7 Nanjing Huazhuo Electronics Co., Ltd. -000CB8 MEDION AG -000CB9 LEA -000CBA Jamex -000CBB ISKRAEMECO -000CBC Iscutum -000CBD Interface Masters, Inc -000CBF Holy Stone Ent. Co., Ltd. -000CC0 Genera Oy -000CC1 Cooper Industries Inc. -000CC3 BeWAN systems -000CC4 Tiptel AG -000CC5 Nextlink Co., Ltd. -000CC6 Ka-Ro electronics GmbH -000CC7 Intelligent Computer Solutions Inc. -000CC8 Integrated Digital Systems, Inc. -000CC9 ILWOO DATA & TECHNOLOGY CO.,LTD -000CCA Hitachi Global Storage Technologies -000CCB Design Combus Ltd -000CCC Bluesoft Ltd. -000CCD IEC - TC57 -000CCE Cisco Systems -000CCF Cisco Systems -000CD0 Symetrix -000CD1 SFOM Technology Corp. -000CD2 Schaffner EMV AG -000CD3 Prettl Elektronik Radeberg GmbH -000CD4 Positron Public Safety Systems inc. -000CD5 Passave Inc. -000CD6 PARTNER TECH -000CD7 Nallatech Ltd -000CD8 M. K. Juchheim GmbH & Co -000CD9 Itcare Co., Ltd -000CDA FreeHand Systems, Inc. -000CDB Foundry Networks -000CDC BECS Technology, Inc -000CDD AOS Technologies AG -000CDE ABB STOTZ-KONTAKT GmbH -000CDF PULNiX America, Inc -000CE0 Trek Diagnostics Inc. -000CE1 The Open Group -000CE2 Rolls-Royce -000CE3 Option International N.V. -000CE4 NeuroCom International, Inc. -000CE5 Motorola BCS -000CE6 Meru Networks Inc -000CE7 MediaTek Inc. -000CE8 GuangZhou AnJuBao Co., Ltd -000CE9 BLOOMBERG L.P. -000CEA aphona Kommunikationssysteme -000CEB CNMP Networks, Inc. -000CEC Spectracom Corp. -000CED Real Digital Media -000CEE Q-Networks -000CEF Open Networks Engineering Ltd -000CF0 M & N GmbH -000CF1 Intel Corporation -000CF2 GAMESA EÓLICA -000CF3 CALL IMAGE SA -000CF4 AKATSUKI ELECTRIC MFG.CO.,LTD. -000CF5 InfoExpress -000CF6 Sitecom Europe BV -000CF7 Nortel Networks -000CF8 Nortel Networks -000CF9 ITT Flygt AB -000CFA Digital Systems Corp -000CFB Korea Network Systems -000CFC S2io Technologies Corp -000CFE Grand Electronic Co., Ltd -000CFF MRO-TEK LIMITED -000D00 Seaway Networks Inc. -000D01 P&E Microcomputer Systems, Inc. -000D02 NEC Access Technica,Ltd -000D03 Matrics, Inc. -000D04 Foxboro Eckardt Development GmbH -000D05 cybernet manufacturing inc. -000D06 Compulogic Limited -000D07 Calrec Audio Ltd -000D08 AboveCable, Inc. -000D09 Yuehua(Zhuhai) Electronic CO. LTD -000D0A Projectiondesign as -000D0B Melco Inc. -000D0C MDI Security Systems -000D0D ITSupported, LLC -000D0E Inqnet Systems, Inc. -000D0F Finlux Ltd -000D10 Embedtronics Oy -000D11 DENTSPLY - Gendex -000D12 AXELL Corporation -000D13 Wilhelm Rutenbeck GmbH&Co. -000D14 Vtech Innovation LP dba Advanced American Telephones -000D15 Voipac s.r.o. -000D16 UHS Systems Pty Ltd -000D17 Turbo Networks Co.Ltd -000D18 Sunitec Enterprise Co., Ltd. -000D19 ROBE Show lighting -000D1A Mustek System Inc. -000D1B Kyoto Electronics Manufacturing Co., Ltd. -000D1C I2E TELECOM -000D1D HIGH-TEK HARNESS ENT. CO., LTD. -000D1E Control Techniques -000D1F AV Digital -000D20 ASAHIKASEI TECHNOSYSTEM CO.,LTD. -000D21 WISCORE Inc. -000D22 Unitronics -000D23 Smart Solution, Inc -000D24 SENTEC E&E CO., LTD. -000D25 SANDEN CORPORATION -000D26 Primagraphics Limited -000D27 MICROPLEX Printware AG -000D28 Cisco -000D29 Cisco -000D2A Scanmatic AS -000D2B Racal Instruments -000D2C Patapsco Designs Ltd -000D2D NCT Deutschland GmbH -000D2E Matsushita Avionics Systems Corporation -000D2F AIN Comm.Tech.Co., LTD -000D30 IceFyre Semiconductor -000D31 Compellent Technologies, Inc. -000D32 DispenseSource, Inc. -000D33 Prediwave Corp. -000D34 Shell International Exploration and Production, Inc. -000D35 PAC International Ltd -000D36 Wu Han Routon Electronic Co., Ltd -000D37 WIPLUG -000D38 NISSIN INC. -000D39 Network Electronics -000D3A Microsoft Corp. -000D3B Microelectronics Technology Inc. -000D3C i.Tech Dynamic Ltd -000D3E APLUX Communications Ltd. -000D3F VXI Technology -000D40 Verint Loronix Video Solutions -000D41 Siemens AG ICM MP UC RD IT KLF1 -000D42 Newbest Development Limited -000D43 DRS Tactical Systems Inc. -000D45 Tottori SANYO Electric Co., Ltd. -000D46 Eurotherm Drives, Ltd. -000D47 Collex -000D48 AEWIN Technologies Co., Ltd. -000D49 Triton Systems of Delaware, Inc. -000D4A Steag ETA-Optik -000D4B Roku, LLC -000D4C Outline Electronics Ltd. -000D4D Ninelanes -000D4E NDR Co.,LTD. -000D4F Kenwood Corporation -000D50 Galazar Networks -000D51 DIVR Systems, Inc. -000D52 Comart system -000D53 Beijing 5w Communication Corp. -000D54 3Com Europe Ltd -000D55 SANYCOM Technology Co.,Ltd -000D56 Dell PCBA Test -000D57 Fujitsu I-Network Systems Limited. -000D59 Amity Systems, Inc. -000D5A Tiesse SpA -000D5B Smart Empire Investments Limited -000D5C Robert Bosch GmbH, VT-ATMO -000D5D Raritan Computer, Inc -000D5E NEC CustomTechnica, Ltd. -000D5F Minds Inc -000D60 IBM Corporation -000D61 Giga-Byte Technology Co., Ltd. -000D62 Funkwerk Dabendorf GmbH -000D63 DENT Instruments, Inc. -000D64 COMAG Handels AG -000D65 Cisco Systems -000D66 Cisco Systems -000D67 BelAir Networks Inc. -000D68 Vinci Systems, Inc. -000D69 TMT&D Corporation -000D6A Redwood Technologies LTD -000D6B Mita-Teknik A/S -000D6C M-Audio -000D6D K-Tech Devices Corp. -000D6E K-Patents Oy -000D6F Ember Corporation -000D70 Datamax Corporation -000D71 boca systems -000D72 2Wire, Inc -000D73 Technical Support, Inc. -000D74 Sand Network Systems, Inc. -000D75 Kobian Pte Ltd - Taiwan Branch -000D76 Hokuto Denshi Co,. Ltd. -000D77 FalconStor Software -000D78 Engineering & Security -000D79 Dynamic Solutions Co,.Ltd. -000D7A DiGATTO Asia Pacific Pte Ltd -000D7B Consensys Computers Inc. -000D7C Codian Ltd -000D7D Afco Systems -000D7E Axiowave Networks, Inc. -000D7F MIDAS COMMUNICATION TECHNOLOGIES PTE LTD ( Foreign Branch) -000D80 Online Development Inc -000D81 Pepperl+Fuchs GmbH -000D82 PHS srl -000D83 Sanmina-SCI Hungary Ltd. -000D84 Seodu Inchip, Inc. -000D85 Tapwave, Inc. -000D86 Huber + Suhner AG -000D87 Elitegroup Computer System Co. (ECS) -000D88 D-Link Corporation -000D89 Bils Technology Inc -000D8A Winners Electronics Co., Ltd. -000D8B T&D Corporation -000D8C Shanghai Wedone Digital Ltd. CO. -000D8D ProLinx Communication Gateways, Inc. -000D8E Koden Electronics Co., Ltd. -000D8F King Tsushin Kogyo Co., LTD. -000D90 Factum Electronics AB -000D91 Eclipse (HQ Espana) S.L. -000D92 Arima Communication Corporation -000D93 Apple Computer -000D94 AFAR Communications,Inc -000D96 Vtera Technology Inc. -000D97 Tropos Networks, Inc. -000D98 S.W.A.C. Schmitt-Walter Automation Consult GmbH -000D99 Orbital Sciences Corp.; Launch Systems Group -000D9A INFOTEC LTD -000D9C Elan GmbH & Co KG -000D9D Hewlett Packard -000D9E TOKUDEN OHIZUMI SEISAKUSYO Co.,Ltd. -000D9F RF Micro Devices -000DA0 NEDAP N.V. -000DA1 MIRAE ITS Co.,LTD. -000DA2 Infrant Technologies, Inc. -000DA3 Emerging Technologies Limited -000DA4 DOSCH & AMAND SYSTEMS AG -000DA5 Fabric7 Systems, Inc -000DA6 Universal Switching Corporation -000DA8 Teletronics Technology Corporation -000DA9 T.E.A.M. S.L. -000DAA S.A.Tehnology co.,Ltd. -000DAB Parker Hannifin GmbH Electromechanical Division Europe -000DAC Japan CBM Corporation -000DAD Dataprobe Inc -000DAE SAMSUNG HEAVY INDUSTRIES CO., LTD. -000DAF Plexus Corp (UK) Ltd -000DB0 Olym-tech Co.,Ltd. -000DB1 Japan Network Service Co., Ltd. -000DB2 Ammasso, Inc. -000DB3 SDO Communication Corperation -000DB4 NETASQ -000DB5 GLOBALSAT TECHNOLOGY CORPORATION -000DB6 Teknovus, Inc. -000DB7 SANKO ELECTRIC CO,.LTD -000DB8 SCHILLER AG -000DB9 PC Engines GmbH -000DBA Océ Document Technologies GmbH -000DBB Nippon Dentsu Co.,Ltd. -000DBC Cisco Systems -000DBD Cisco Systems -000DBE Bel Fuse Europe Ltd.,UK -000DBF TekTone Sound & Signal Mfg., Inc. -000DC0 Spagat AS -000DC1 SafeWeb Inc -000DC3 First Communication, Inc. -000DC4 Emcore Corporation -000DC5 EchoStar International Corporation -000DC6 DigiRose Technology Co., Ltd. -000DC7 COSMIC ENGINEERING INC. -000DC8 AirMagnet, Inc -000DC9 THALES Elektronik Systeme GmbH -000DCA Tait Electronics -000DCB Petcomkorea Co., Ltd. -000DCC NEOSMART Corp. -000DCD GROUPE TXCOM -000DCE Dynavac Technology Pte Ltd -000DCF Cidra Corp. -000DD0 TetraTec Instruments GmbH -000DD1 Stryker Corporation -000DD2 Simrad Optronics ASA -000DD3 SAMWOO Telecommunication Co.,Ltd. -000DD4 Revivio Inc. -000DD5 O'RITE TECHNOLOGY CO.,LTD -000DD7 Bright -000DD8 BBN -000DD9 Anton Paar GmbH -000DDA ALLIED TELESIS K.K. -000DDB AIRWAVE TECHNOLOGIES INC. -000DDC VAC -000DDD PROFÝLO TELRA ELEKTRONÝK SANAYÝ VE TÝCARET A.Þ. -000DDE Joyteck Co., Ltd. -000DDF Japan Image & Network Inc. -000DE0 ICPDAS Co.,LTD -000DE1 Control Products, Inc. -000DE2 CMZ Sistemi Elettronici -000DE3 AT Sweden AB -000DE4 DIGINICS, Inc. -000DE5 Samsung Thales -000DE6 YOUNGBO ENGINEERING CO.,LTD -000DE7 Snap-on OEM Group -000DE8 Nasaco Electronics Pte. Ltd -000DE9 Napatech Aps -000DEA Kingtel Telecommunication Corp. -000DEB CompXs Limited -000DEC Cisco Systems -000DED Cisco Systems -000DEF Soc. Coop. Bilanciai -000DF0 QCOM TECHNOLOGY INC. -000DF1 IONIX INC. -000DF3 Asmax Solutions -000DF4 Watertek Co. -000DF5 Teletronics International Inc. -000DF6 Technology Thesaurus Corp. -000DF7 Space Dynamics Lab -000DF8 ORGA Kartensysteme GmbH -000DF9 NDS Limited -000DFA Micro Control Systems Ltd. -000DFB Komax AG -000DFC ITFOR Inc. resarch and development -000DFD Huges Hi-Tech Inc., -000DFE Hauppauge Computer Works, Inc. -000DFF CHENMING MOLD INDUSTRY CORP. -000E01 ASIP Technologies Inc. -000E02 Advantech AMT Inc. -000E03 Aarohi Communications, Inc. -000E05 WIRELESS MATRIX CORP. -000E06 Team Simoco Ltd -000E07 Sony Ericsson Mobile Communications AB -000E08 Sipura Technology, Inc. -000E09 Shenzhen Coship Software Co.,LTD. -000E0B Netac Technology Co., Ltd. -000E0C Intel Corporation -000E0D HESCH Schröder GmbH -000E0E ESA elettronica S.P.A. -000E0F ERMME -000E11 BDT Büro- und Datentechnik GmbH & Co. KG -000E12 Adaptive Micro Systems Inc. -000E13 Accu-Sort Systems inc. -000E14 Visionary Solutions, Inc. -000E15 Tadlys LTD -000E16 SouthWing -000E18 MyA Technology -000E19 LogicaCMG Pty Ltd -000E1B IAV GmbH -000E1C Hach Company -000E1F TCL Networks Equipment Co., Ltd. -000E20 PalmSource, Inc. -000E21 MTU Friedrichshafen GmbH -000E23 Incipient, Inc. -000E25 Hannae Technology Co., Ltd -000E26 Gincom Technology Corp. -000E27 Crere Networks, Inc. -000E28 Dynamic Ratings P/L -000E29 Shester Communications Inc -000E2B Safari Technologies -000E2C Netcodec co. -000E2D Hyundai Digital Technology Co.,Ltd. -000E2E Edimax Technology Co., Ltd. -000E2F Disetronic Medical Systems AG -000E30 AERAS Networks, Inc. -000E31 Olympus BioSystems GmbH -000E32 Kontron Medical -000E33 Shuko Electronics Co.,Ltd -000E34 NexxGenCity -000E35 Intel Corp -000E36 HEINESYS, Inc. -000E37 Harms & Wende GmbH & Co.KG -000E38 Cisco Systems -000E39 Cisco Systems -000E3A Cirrus Logic -000E3B Hawking Technologies, Inc. -000E3C TransAct Technoloiges Inc. -000E3D Televic N.V. -000E3E Sun Optronics Inc -000E3F Soronti, Inc. -000E40 Nortel Networks -000E41 NIHON MECHATRONICS CO.,LTD. -000E42 Motic Incoporation Ltd. -000E43 G-Tek Electronics Sdn. Bhd. -000E44 Digital 5, Inc. -000E45 Beijing Newtry Electronic Technology Ltd -000E46 Niigata Seimitsu Co.,Ltd. -000E47 NCI System Co.,Ltd. -000E48 Lipman TransAction Solutions -000E49 Forsway Scandinavia AB -000E4A Changchun Huayu WEBPAD Co.,LTD -000E4B atrium c and i -000E4C Bermai Inc. -000E4D Numesa Inc. -000E4E Waveplus Technology Co., Ltd. -000E4F Trajet GmbH -000E50 Thomson Multi Media -000E51 tecna elettronica srl -000E52 Optium Corporation -000E53 AV TECH CORPORATION -000E54 AlphaCell Wireless Ltd. -000E55 AUVITRAN -000E56 4G Systems GmbH -000E57 Iworld Networking, Inc. -000E58 Rincon Networks -000E5A TELEFIELD inc. -000E5B ParkerVision - Direct2Data -000E5C Motorola BCS -000E5D Com-X Networks -000E5E Beijing Raisecom Science & Technology Development Co.,Ltd -000E5F activ-net GmbH & Co. KG -000E60 360SUN Digital Broadband Corporation -000E61 MICROTROL LIMITED -000E62 Nortel Networks -000E63 Lemke Diagnostics GmbH -000E64 Elphel, Inc -000E65 TransCore -000E66 Hitachi Advanced Digital, Inc. -000E67 Eltis Microelectronics Ltd. -000E68 E-TOP Network Technology Inc. -000E69 China Electric Power Research Institute -000E6A 3COM EUROPE LTD -000E6B Janitza electronics GmbH -000E6C Device Drivers Limited -000E6D Murata Manufacturing Co., Ltd. -000E6E MICRELEC ELECTRONICS S.A -000E6F IRIS Corporation Berhad -000E70 in2 Networks -000E71 Gemstar Technology Development Ltd. -000E72 CTS electronics -000E73 Tpack A/S -000E74 Solar Telecom. Tech -000E75 New York Air Brake Corp. -000E76 GEMSOC INNOVISION INC. -000E77 Decru, Inc. -000E78 Amtelco -000E79 Ample Communications Inc. -000E7B Toshiba -000E7D Electronics Line 3000 Ltd. -000E7E Comprog Oy -000E7F Hewlett Packard -000E81 Instant802 Networks Inc. -000E82 Commtech Wireless -000E83 Cisco Systems -000E84 Cisco Systems -000E85 Catalyst Enterprises, Inc. -000E86 Alcatel North America -000E87 adp Gauselmann GmbH -000E88 VIDEOTRON CORP. -000E89 CLEMATIC -000E8A Avara Technologies Pty. Ltd. -000E8B Astarte Technology Co, Ltd. -000E8C Siemens AG A&D ET -000E8D Systems in Progress Holding GmbH -000E8E SparkLAN Communications, Inc. -000E8F Sercomm Corp. -000E90 PONICO CORP. -000E92 Millinet Co., Ltd. -000E93 Milénio 3 Sistemas Electrónicos, Lda. -000E94 Maas International BV -000E95 Fujiya Denki Seisakusho Co.,Ltd. -000E96 Cubic Defense Applications, Inc. -000E97 Ultracker Technology CO., Inc -000E98 Vitec CC, INC. -000E99 Spectrum Digital, Inc -000E9A BOE TECHNOLOGY GROUP CO.,LTD -000E9C Pemstar -000E9D Video Networks Ltd -000E9E Topfield Co., Ltd -000E9F TEMIC SDS GmbH -000EA0 NetKlass Technology Inc. -000EA1 Formosa Teletek Corporation -000EA2 CyberGuard Corporation -000EA3 CNCR-IT CO.,LTD,HangZhou P.R.CHINA -000EA4 Certance Inc. -000EA5 BLIP Systems -000EA6 ASUSTEK COMPUTER INC. -000EA7 Endace Inc Ltd. -000EA8 United Technologists Europe Limited -000EA9 Shanghai Xun Shi Communications Equipment Ltd. Co. -000EAC MINTRON ENTERPRISE CO., LTD. -000EAD Metanoia Technologies, Inc. -000EAE GAWELL TECHNOLOGIES CORP. -000EAF CASTEL -000EB0 Solutions Radio BV -000EB1 Newcotech,Ltd -000EB2 Micro-Research Finland Oy -000EB3 LeftHand Networks -000EB4 GUANGZHOU GAOKE COMMUNICATIONS TECHNOLOGY CO.LTD. -000EB5 Ecastle Electronics Co., Ltd. -000EB6 Riverbed Technology, Inc. -000EB7 Knovative, Inc. -000EB8 Iiga co.,Ltd -000EB9 HASHIMOTO Electronics Industry Co.,Ltd. -000EBA HANMI SEMICONDUCTOR CO., LTD. -000EBB Everbee Networks -000EBC Cullmann GmbH -000EBD Burdick, a Quinton Compny -000EBE B&B Electronics Manufacturing Co. -000EC0 Nortel Networks -000EC1 MYNAH Technologies -000EC2 Lowrance Electronics, Inc. -000EC3 Logic Controls, Inc. -000EC4 Iskra Transmission d.d. -000EC6 ASIX ELECTRONICS CORP. -000EC7 Appeal Telecom Co.,Ltd. -000EC8 Zoran Corporation -000EC9 YOKO Technology Corp. -000ECB VineSys Technology -000ECC Tableau -000ECD SKOV A/S -000ECE S.I.T.T.I. S.p.A. -000ECF PROFIBUS Nutzerorganisation e.V. -000ED0 Privaris, Inc. -000ED1 Osaka Micro Computer. -000ED2 Filtronic plc -000ED3 Epicenter, Inc. -000ED4 CRESITT INDUSTRIE -000ED5 COPAN Systems Inc. -000ED6 Cisco Systems -000ED7 Cisco Systems -000ED8 Aktino, Inc. -000ED9 Aksys, Ltd. -000EDA C-TECH UNITED CORP. -000EDB XiNCOM Corp. -000EDC Tellion INC. -000EDD SHURE INCORPORATED -000EDE REMEC, Inc. -000EDF PLX Technology -000EE0 Mcharge -000EE1 ExtremeSpeed Inc. -000EE2 Custom Engineering S.p.A. -000EE3 Chiyu Technology Co.,Ltd -000EE5 bitWallet, Inc. -000EE6 Adimos Systems LTD -000EE7 AAC ELECTRONICS CORP. -000EE8 zioncom -000EE9 WayTech Development, Inc. -000EEA Shadong Luneng Jicheng Electronics,Co.,Ltd -000EEB Sandmartin(zhong shan)Electronics Co.,Ltd -000EEC Orban -000EED Nokia Danmark A/S -000EEE Muco Industrie BV -000EF0 Festo AG & Co. KG -000EF1 EZQUEST INC. -000EF3 Smarthome -000EF4 Shenzhen Kasda Digital Technology Co.,Ltd -000EF5 iPAC Technology Co., Ltd. -000EF6 E-TEN Information Systems Co., Ltd. -000EF7 Vulcan Portals Inc -000EF8 SBC ASI -000EF9 REA Elektronik GmbH -000EFA Optoway Technology Incorporation -000EFB Macey Enterprises -000EFC JTAG Technologies B.V. -000EFD FUJI PHOTO OPTICAL CO., LTD. -000EFE EndRun Technologies LLC -000EFF Megasolution,Inc. -000F00 Legra Systems, Inc. -000F01 DIGITALKS INC -000F02 Digicube Technology Co., Ltd -000F03 COM&C CO., LTD -000F04 cim-usa inc -000F05 3B SYSTEM INC. -000F06 Nortel Networks -000F07 Mangrove Systems, Inc. -000F08 Indagon Oy -000F0B Kentima Technologies AB -000F0C SYNCHRONIC ENGINEERING -000F0D Hunt Electronic Co., Ltd. -000F0E WaveSplitter Technologies, Inc. -000F0F Real ID Technology Co., Ltd. -000F10 RDM Corporation -000F11 Prodrive B.V. -000F12 Panasonic AVC Networks Germany GmbH -000F13 Nisca corporation -000F14 Mindray Co., Ltd. -000F15 Kjaerulff1 A/S -000F16 JAY HOW TECHNOLOGY CO., -000F17 Insta Elektro GmbH -000F18 Industrial Control Systems -000F19 Guidant Corporation -000F1A Gaming Support B.V. -000F1B Ego Systems Inc. -000F1C DigitAll World Co., Ltd -000F1D Cosmo Techs Co., Ltd. -000F1E Chengdu KT Electric Co.of High & New Technology -000F1F WW PCBA Test -000F20 WW Ops -000F21 Scientific Atlanta, Inc -000F22 Helius, Inc. -000F23 Cisco Systems -000F24 Cisco Systems -000F25 AimValley B.V. -000F26 WorldAccxx LLC -000F27 TEAL Electronics, Inc. -000F28 Itronix Corporation -000F29 Augmentix Corporation -000F2A Cableware Electronics -000F2B GREENBELL SYSTEMS -000F2C Uplogix, Inc. -001000 CABLE TELEVISION LABORATORIES, INC. -001001 MCK COMMUNICATIONS -001002 ACTIA -001003 IMATRON, INC. -001004 THE BRANTLEY COILE COMPANY,INC -001005 UEC COMMERCIAL -001006 Thales Contact Solutions Ltd. -001007 CISCO SYSTEMS, INC. -001008 VIENNA SYSTEMS CORPORATION -001009 HORO QUARTZ -00100A WILLIAMS COMMUNICATIONS GROUP -00100B CISCO SYSTEMS, INC. -00100C ITO CO., LTD. -00100D CISCO SYSTEMS, INC. -00100E MICRO LINEAR COPORATION -00100F INDUSTRIAL CPU SYSTEMS -001010 INITIO CORPORATION -001011 CISCO SYSTEMS, INC. -001012 PROCESSOR SYSTEMS (I) PVT LTD -001013 INDUSTRIAL COMPUTER SOURCE -001014 CISCO SYSTEMS, INC. -001015 OOmon Inc. -001016 T.SQWARE -001017 MICOS GmbH -001018 BROADCOM CORPORATION -001019 SIRONA DENTAL SYSTEMS GmbH & Co. KG -00101A PictureTel Corp. -00101B CORNET TECHNOLOGY, INC. -00101C OHM TECHNOLOGIES INTL, LLC -00101D WINBOND ELECTRONICS CORP. -00101E MATSUSHITA ELECTRONIC INSTRUMENTS CORP. -00101F CISCO SYSTEMS, INC. -001020 WELCH ALLYN, DATA COLLECTION -001021 ENCANTO NETWORKS, INC. -001022 SatCom Media Corporation -001023 FLOWWISE NETWORKS, INC. -001024 NAGOYA ELECTRIC WORKS CO., LTD -001025 GRAYHILL INC. -001026 ACCELERATED NETWORKS, INC. -001027 L-3 COMMUNICATIONS EAST -001028 COMPUTER TECHNICA, INC. -001029 CISCO SYSTEMS, INC. -00102A ZF MICROSYSTEMS, INC. -00102B UMAX DATA SYSTEMS, INC. -00102C Lasat Networks A/S -00102D HITACHI SOFTWARE ENGINEERING -00102E NETWORK SYSTEMS & TECHNOLOGIES PVT. LTD. -00102F CISCO SYSTEMS, INC. -001030 Wi-LAN, Inc. -001031 OBJECTIVE COMMUNICATIONS, INC. -001032 ALTA TECHNOLOGY -001033 ACCESSLAN COMMUNICATIONS, INC. -001034 GNP Computers -001035 ELITEGROUP COMPUTER SYSTEMS CO., LTD -001036 INTER-TEL INTEGRATED SYSTEMS -001037 CYQ've Technology Co., Ltd. -001038 MICRO RESEARCH INSTITUTE, INC. -001039 Vectron Systems AG -00103A DIAMOND NETWORK TECH -00103B HIPPI NETWORKING FORUM -00103C IC ENSEMBLE, INC. -00103D PHASECOM, LTD. -00103E NETSCHOOLS CORPORATION -00103F TOLLGRADE COMMUNICATIONS, INC. -001040 INTERMEC CORPORATION -001041 BRISTOL BABCOCK, INC. -001042 AlacriTech -001043 A2 CORPORATION -001044 InnoLabs Corporation -001045 Nortel Networks -001046 ALCORN MCBRIDE INC. -001047 ECHO ELETRIC CO. LTD. -001048 HTRC AUTOMATION, INC. -001049 SHORELINE TELEWORKS, INC. -00104A THE PARVUC CORPORATION -00104B 3COM CORPORATION -00104C COMPUTER ACCESS TECHNOLOGY -00104D SURTEC INDUSTRIES, INC. -00104E CEOLOGIC -00104F STORAGE TECHNOLOGY CORPORATION -001050 RION CO., LTD. -001051 CMICRO CORPORATION -001052 METTLER-TOLEDO (ALBSTADT) GMBH -001053 COMPUTER TECHNOLOGY CORP. -001054 CISCO SYSTEMS, INC. -001055 FUJITSU MICROELECTRONICS, INC. -001056 SODICK CO., LTD. -001057 Rebel.com, Inc. -001058 ArrowPoint Communications -001059 DIABLO RESEARCH CO. LLC -00105A 3COM CORPORATION -00105B NET INSIGHT AB -00105C QUANTUM DESIGNS (H.K.) LTD. -00105D Draeger Medical -00105E HEKIMIAN LABORATORIES, INC. -00105F IN-SNEC -001060 BILLIONTON SYSTEMS, INC. -001061 HOSTLINK CORP. -001062 NX SERVER, ILNC. -001063 STARGUIDE DIGITAL NETWORKS -001064 DIGITAL EQUIPMENT CORP. -001065 RADYNE CORPORATION -001066 ADVANCED CONTROL SYSTEMS, INC. -001067 REDBACK NETWORKS, INC. -001068 COMOS TELECOM -001069 HELIOSS COMMUNICATIONS, INC. -00106A DIGITAL MICROWAVE CORPORATION -00106B SONUS NETWORKS, INC. -00106C INFRATEC PLUS GmbH -00106D INTEGRITY COMMUNICATIONS, INC. -00106E TADIRAN COM. LTD. -00106F TRENTON TECHNOLOGY INC. -001070 CARADON TREND LTD. -001071 ADVANET INC. -001072 GVN TECHNOLOGIES, INC. -001073 TECHNOBOX, INC. -001074 ATEN INTERNATIONAL CO., LTD. -001075 Maxtor Corporation -001076 EUREM GmbH -001077 SAF DRIVE SYSTEMS, LTD. -001078 NUERA COMMUNICATIONS, INC. -001079 CISCO SYSTEMS, INC. -00107A AmbiCom, Inc. -00107B CISCO SYSTEMS, INC. -00107C P-COM, INC. -00107D AURORA COMMUNICATIONS, LTD. -00107E BACHMANN ELECTRONIC GmbH -00107F CRESTRON ELECTRONICS, INC. -001080 METAWAVE COMMUNICATIONS -001081 DPS, INC. -001082 JNA TELECOMMUNICATIONS LIMITED -001083 HEWLETT-PACKARD COMPANY -001084 K-BOT COMMUNICATIONS -001085 POLARIS COMMUNICATIONS, INC. -001086 ATTO TECHNOLOGY, INC. -001087 Xstreamis PLC -001088 AMERICAN NETWORKS INC. -001089 WebSonic -00108A TeraLogic, Inc. -00108B LASERANIMATION SOLLINGER GmbH -00108C FUJITSU TELECOMMUNICATIONS EUROPE, LTD. -00108D JOHNSON CONTROLS, INC. -00108E HUGH SYMONS CONCEPT Technologies Ltd. -00108F RAPTOR SYSTEMS -001090 CIMETRICS, INC. -001091 NO WIRES NEEDED BV -001092 NETCORE INC. -001093 CMS COMPUTERS, LTD. -001094 Performance Analysis Broadband, Spirent plc -001095 Thomson Multimedia, Inc. -001096 TRACEWELL SYSTEMS, INC. -001097 WinNet Metropolitan Communications Systems, Inc. -001098 STARNET TECHNOLOGIES, INC. -001099 InnoMedia, Inc. -00109A NETLINE -00109B VIXEL CORPORATION -00109C M-SYSTEM CO., LTD. -00109D CLARINET SYSTEMS, INC. -00109E AWARE, INC. -00109F PAVO, INC. -0010A0 INNOVEX TECHNOLOGIES, INC. -0010A1 KENDIN SEMICONDUCTOR, INC. -0010A2 TNS -0010A3 OMNITRONIX, INC. -0010A4 XIRCOM -0010A5 OXFORD INSTRUMENTS -0010A6 CISCO SYSTEMS, INC. -0010A7 UNEX TECHNOLOGY CORPORATION -0010A8 RELIANCE COMPUTER CORP. -0010A9 ADHOC TECHNOLOGIES -0010AA MEDIA4, INC. -0010AB KOITO INDUSTRIES, LTD. -0010AC IMCI TECHNOLOGIES -0010AD SOFTRONICS USB, INC. -0010AE SHINKO ELECTRIC INDUSTRIES CO. -0010AF TAC SYSTEMS, INC. -0010B0 MERIDIAN TECHNOLOGY CORP. -0010B1 FOR-A CO., LTD. -0010B2 COACTIVE AESTHETICS -0010B3 NOKIA MULTIMEDIA TERMINALS -0010B4 ATMOSPHERE NETWORKS -0010B5 ACCTON TECHNOLOGY CORPORATION -0010B6 ENTRATA COMMUNICATIONS CORP. -0010B7 COYOTE TECHNOLOGIES, LLC -0010B8 ISHIGAKI COMPUTER SYSTEM CO. -0010B9 MAXTOR CORP. -0010BA MARTINHO-DAVIS SYSTEMS, INC. -0010BB DATA & INFORMATION TECHNOLOGY -0010BC Aastra Telecom -0010BD THE TELECOMMUNICATION TECHNOLOGY COMMITTEE -0010BE TELEXIS CORP. -0010BF InterAir Wireless -0010C0 ARMA, INC. -0010C1 OI ELECTRIC CO., LTD. -0010C2 WILLNET, INC. -0010C3 CSI-CONTROL SYSTEMS -0010C4 MEDIA LINKS CO., LTD. -0010C5 PROTOCOL TECHNOLOGIES, INC. -0010C6 USI -0010C7 DATA TRANSMISSION NETWORK -0010C8 COMMUNICATIONS ELECTRONICS SECURITY GROUP -0010C9 MITSUBISHI ELECTRONICS LOGISTIC SUPPORT CO. -0010CA INTEGRAL ACCESS -0010CB FACIT K.K. -0010CC CLP COMPUTER LOGISTIK PLANUNG GmbH -0010CD INTERFACE CONCEPT -0010CE VOLAMP, LTD. -0010CF FIBERLANE COMMUNICATIONS -0010D0 WITCOM, LTD. -0010D1 Top Layer Networks, Inc. -0010D2 NITTO TSUSHINKI CO., LTD -0010D3 GRIPS ELECTRONIC GMBH -0010D4 STORAGE COMPUTER CORPORATION -0010D5 IMASDE CANARIAS, S.A. -0010D6 ITT - A/CD -0010D7 ARGOSY RESEARCH INC. -0010D8 CALISTA -0010D9 IBM JAPAN, FUJISAWA MT+D -0010DA MOTION ENGINEERING, INC. -0010DB NetScreen Technologies, Inc. -0010DC MICRO-STAR INTERNATIONAL CO., LTD. -0010DD ENABLE SEMICONDUCTOR, INC. -0010DE INTERNATIONAL DATACASTING CORPORATION -0010DF RISE COMPUTER INC. -0010E0 COBALT MICROSERVER, INC. -0010E1 S.I. TECH, INC. -0010E2 ArrayComm, Inc. -0010E3 COMPAQ COMPUTER CORPORATION -0010E4 NSI CORPORATION -0010E5 SOLECTRON TEXAS -0010E6 APPLIED INTELLIGENT SYSTEMS, INC. -0010E7 BreezeCom -0010E8 TELOCITY, INCORPORATED -0010E9 RAIDTEC LTD. -0010EA ADEPT TECHNOLOGY -0010EB SELSIUS SYSTEMS, INC. -0010EC RPCG, LLC -0010ED SUNDANCE TECHNOLOGY, INC. -0010EE CTI PRODUCTS, INC. -0010EF DBTEL INCORPORATED -0010F1 I-O CORPORATION -0010F2 ANTEC -0010F3 Nexcom International Co., Ltd. -0010F4 VERTICAL NETWORKS, INC. -0010F5 AMHERST SYSTEMS, INC. -0010F6 CISCO SYSTEMS, INC. -0010F7 IRIICHI TECHNOLOGIES Inc. -0010F8 KENWOOD TMI CORPORATION -0010F9 UNIQUE SYSTEMS, INC. -0010FA ZAYANTE, INC. -0010FB ZIDA TECHNOLOGIES LIMITED -0010FC BROADBAND NETWORKS, INC. -0010FD COCOM A/S -0010FE DIGITAL EQUIPMENT CORPORATION -0010FF CISCO SYSTEMS, INC. -001C7C PERQ SYSTEMS CORPORATION -002000 LEXMARK INTERNATIONAL, INC. -002001 DSP SOLUTIONS, INC. -002002 SERITECH ENTERPRISE CO., LTD. -002003 PIXEL POWER LTD. -002004 YAMATAKE-HONEYWELL CO., LTD. -002005 SIMPLE TECHNOLOGY -002006 GARRETT COMMUNICATIONS, INC. -002007 SFA, INC. -002008 CABLE & COMPUTER TECHNOLOGY -002009 PACKARD BELL ELEC., INC. -00200A SOURCE-COMM CORP. -00200B OCTAGON SYSTEMS CORP. -00200C ADASTRA SYSTEMS CORP. -00200D CARL ZEISS -00200E SATELLITE TECHNOLOGY MGMT, INC -00200F TANBAC CO., LTD. -002010 JEOL SYSTEM TECHNOLOGY CO. LTD -002011 CANOPUS CO., LTD. -002012 CAMTRONICS MEDICAL SYSTEMS -002013 DIVERSIFIED TECHNOLOGY, INC. -002014 GLOBAL VIEW CO., LTD. -002015 ACTIS COMPUTER SA -002016 SHOWA ELECTRIC WIRE & CABLE CO -002017 ORBOTECH -002018 CIS TECHNOLOGY INC. -002019 OHLER GmbH -00201A N-BASE SWITCH COMMUNICATIONS -00201B NORTHERN TELECOM/NETWORK -00201C EXCEL, INC. -00201D KATANA PRODUCTS -00201E NETQUEST CORPORATION -00201F BEST POWER TECHNOLOGY, INC. -002020 MEGATRON COMPUTER INDUSTRIES PTY, LTD. -002021 ALGORITHMS SOFTWARE PVT. LTD. -002022 TEKNIQUE, INC. -002023 T.C. TECHNOLOGIES PTY. LTD -002024 PACIFIC COMMUNICATION SCIENCES -002025 CONTROL TECHNOLOGY, INC. -002026 AMKLY SYSTEMS, INC. -002027 MING FORTUNE INDUSTRY CO., LTD -002028 WEST EGG SYSTEMS, INC. -002029 TELEPROCESSING PRODUCTS, INC. -00202A N.V. DZINE -00202B ADVANCED TELECOMMUNICATIONS MODULES, LTD. -00202C WELLTRONIX CO., LTD. -00202D TAIYO CORPORATION -00202E DAYSTAR DIGITAL -00202F ZETA COMMUNICATIONS, LTD. -002030 ANALOG & DIGITAL SYSTEMS -002031 ERTEC GmbH -002032 ALCATEL TAISEL -002033 SYNAPSE TECHNOLOGIES, INC. -002034 ROTEC INDUSTRIEAUTOMATION GMBH -002035 IBM CORPORATION -002036 BMC SOFTWARE -002037 SEAGATE TECHNOLOGY -002038 VME MICROSYSTEMS INTERNATIONAL CORPORATION -002039 SCINETS -00203A DIGITAL BI0METRICS INC. -00203B WISDM LTD. -00203C EUROTIME AB -00203D NOVAR ELECTRONICS CORPORATION -00203E LogiCan Technologies, Inc. -00203F JUKI CORPORATION -002040 Motorola Broadband Communications Sector -002041 DATA NET -002042 DATAMETRICS CORP. -002043 NEURON COMPANY LIMITED -002044 GENITECH PTY LTD -002045 ION Networks, Inc. -002046 CIPRICO, INC. -002047 STEINBRECHER CORP. -002048 Marconi Communications -002049 COMTRON, INC. -00204A PRONET GMBH -00204B AUTOCOMPUTER CO., LTD. -00204C MITRON COMPUTER PTE LTD. -00204D INOVIS GMBH -00204E NETWORK SECURITY SYSTEMS, INC. -00204F DEUTSCHE AEROSPACE AG -002050 KOREA COMPUTER INC. -002051 Verilink Corporation -002052 RAGULA SYSTEMS -002053 HUNTSVILLE MICROSYSTEMS, INC. -002054 EASTERN RESEARCH, INC. -002055 ALTECH CO., LTD. -002056 NEOPRODUCTS -002057 TITZE DATENTECHNIK GmbH -002058 ALLIED SIGNAL INC. -002059 MIRO COMPUTER PRODUCTS AG -00205A COMPUTER IDENTICS -00205B SKYLINE TECHNOLOGY -00205C InterNet Systems of Florida, Inc. -00205D NANOMATIC OY -00205E CASTLE ROCK, INC. -00205F GAMMADATA COMPUTER GMBH -002060 ALCATEL ITALIA S.p.A. -002061 DYNATECH COMMUNICATIONS, INC. -002062 SCORPION LOGIC, LTD. -002063 WIPRO INFOTECH LTD. -002064 PROTEC MICROSYSTEMS, INC. -002065 SUPERNET NETWORKING INC. -002066 GENERAL MAGIC, INC. -002068 ISDYNE -002069 ISDN SYSTEMS CORPORATION -00206A OSAKA COMPUTER CORP. -00206B KONICA MINOLTA HOLDINGS, INC. -00206C EVERGREEN TECHNOLOGY CORP. -00206D DATA RACE, INC. -00206E XACT, INC. -00206F FLOWPOINT CORPORATION -002070 HYNET, LTD. -002071 IBR GMBH -002072 WORKLINK INNOVATIONS -002073 FUSION SYSTEMS CORPORATION -002074 SUNGWOON SYSTEMS -002075 MOTOROLA COMMUNICATION ISRAEL -002076 REUDO CORPORATION -002077 KARDIOS SYSTEMS CORP. -002078 RUNTOP, INC. -002079 MIKRON GMBH -00207A WiSE Communications, Inc. -00207B Intel Corporation -00207C AUTEC GmbH -00207D ADVANCED COMPUTER APPLICATIONS -00207E FINECOM Co., Ltd. -00207F KYOEI SANGYO CO., LTD. -002080 SYNERGY (UK) LTD. -002081 TITAN ELECTRONICS -002082 ONEAC CORPORATION -002083 PRESTICOM INCORPORATED -002084 OCE PRINTING SYSTEMS, GMBH -002085 EXIDE ELECTRONICS -002086 MICROTECH ELECTRONICS LIMITED -002087 MEMOTEC COMMUNICATIONS CORP. -002088 GLOBAL VILLAGE COMMUNICATION -002089 T3PLUS NETWORKING, INC. -00208A SONIX COMMUNICATIONS, LTD. -00208B LAPIS TECHNOLOGIES, INC. -00208C GALAXY NETWORKS, INC. -00208D CMD TECHNOLOGY -00208E CHEVIN SOFTWARE ENG. LTD. -00208F ECI TELECOM LTD. -002090 ADVANCED COMPRESSION TECHNOLOGY, INC. -002091 J125, NATIONAL SECURITY AGENCY -002092 CHESS ENGINEERING B.V. -002093 LANDINGS TECHNOLOGY CORP. -002094 CUBIX CORPORATION -002095 RIVA ELECTRONICS -002096 Invensys -002097 APPLIED SIGNAL TECHNOLOGY -002098 HECTRONIC AB -002099 BON ELECTRIC CO., LTD. -00209A THE 3DO COMPANY -00209B ERSAT ELECTRONIC GMBH -00209C PRIMARY ACCESS CORP. -00209D LIPPERT AUTOMATIONSTECHNIK -00209E BROWN'S OPERATING SYSTEM SERVICES, LTD. -00209F MERCURY COMPUTER SYSTEMS, INC. -0020A0 OA LABORATORY CO., LTD. -0020A1 DOVATRON -0020A2 GALCOM NETWORKING LTD. -0020A3 DIVICOM INC. -0020A4 MULTIPOINT NETWORKS -0020A5 API ENGINEERING -0020A6 PROXIM, INC. -0020A7 PAIRGAIN TECHNOLOGIES, INC. -0020A8 SAST TECHNOLOGY CORP. -0020A9 WHITE HORSE INDUSTRIAL -0020AA DIGIMEDIA VISION LTD. -0020AB MICRO INDUSTRIES CORP. -0020AC INTERFLEX DATENSYSTEME GMBH -0020AD LINQ SYSTEMS -0020AE ORNET DATA COMMUNICATION TECH. -0020AF 3COM CORPORATION -0020B0 GATEWAY DEVICES, INC. -0020B1 COMTECH RESEARCH INC. -0020B2 GKD Gesellschaft Fur Kommunikation Und Datentechnik -0020B3 SCLTEC COMMUNICATIONS SYSTEMS -0020B4 TERMA ELEKTRONIK AS -0020B5 YASKAWA ELECTRIC CORPORATION -0020B6 AGILE NETWORKS, INC. -0020B7 NAMAQUA COMPUTERWARE -0020B8 PRIME OPTION, INC. -0020B9 METRICOM, INC. -0020BA CENTER FOR HIGH PERFORMANCE -0020BB ZAX CORPORATION -0020BC JTEC PTY LTD. -0020BD NIOBRARA R & D CORPORATION -0020BE LAN ACCESS CORP. -0020BF AEHR TEST SYSTEMS -0020C0 PULSE ELECTRONICS, INC. -0020C1 TAIKO ELECTRIC WORKS, LTD. -0020C2 TEXAS MEMORY SYSTEMS, INC. -0020C3 COUNTER SOLUTIONS LTD. -0020C4 INET,INC. -0020C5 EAGLE TECHNOLOGY -0020C6 NECTEC -0020C7 AKAI Professional M.I. Corp. -0020C8 LARSCOM INCORPORATED -0020C9 VICTRON BV -0020CA DIGITAL OCEAN -0020CB PRETEC ELECTRONICS CORP. -0020CC DIGITAL SERVICES, LTD. -0020CD HYBRID NETWORKS, INC. -0020CE LOGICAL DESIGN GROUP, INC. -0020CF TEST & MEASUREMENT SYSTEMS INC -0020D0 VERSALYNX CORPORATION -0020D1 MICROCOMPUTER SYSTEMS (M) SDN. -0020D2 RAD DATA COMMUNICATIONS, LTD. -0020D3 OST (OUEST STANDARD TELEMATIQU -0020D4 CABLETRON - ZEITTNET INC. -0020D5 VIPA GMBH -0020D6 BREEZECOM -0020D7 JAPAN MINICOMPUTER SYSTEMS CO., Ltd. -0020D8 Nortel Networks -0020D9 PANASONIC TECHNOLOGIES, INC./MIECO-US -0020DA XYLAN CORPORATION -0020DB XNET TECHNOLOGY, INC. -0020DC DENSITRON TAIWAN LTD. -0020DD Cybertec Pty Ltd -0020DE JAPAN DIGITAL LABORAT'Y CO.LTD -0020DF KYOSAN ELECTRIC MFG. CO., LTD. -0020E0 PREMAX ELECTRONICS, INC. -0020E1 ALAMAR ELECTRONICS -0020E2 INFORMATION RESOURCE ENGINEERING -0020E3 MCD KENCOM CORPORATION -0020E4 HSING TECH ENTERPRISE CO., LTD -0020E5 APEX DATA, INC. -0020E6 LIDKOPING MACHINE TOOLS AB -0020E7 B&W NUCLEAR SERVICE COMPANY -0020E8 DATATREK CORPORATION -0020E9 DANTEL -0020EA EFFICIENT NETWORKS, INC. -0020EB CINCINNATI MICROWAVE, INC. -0020EC TECHWARE SYSTEMS CORP. -0020ED GIGA-BYTE TECHNOLOGY CO., LTD. -0020EE GTECH CORPORATION -0020EF USC CORPORATION -0020F0 UNIVERSAL MICROELECTRONICS CO. -0020F1 ALTOS INDIA LIMITED -0020F2 SUN MICROSYSTEMS, INC. -0020F3 RAYNET CORPORATION -0020F4 SPECTRIX CORPORATION -0020F5 PANDATEL AG -0020F6 NET TEK AND KARLNET, INC. -0020F7 CYBERDATA -0020F8 CARRERA COMPUTERS, INC. -0020F9 PARALINK NETWORKS, INC. -0020FA GDE SYSTEMS, INC. -0020FB OCTEL COMMUNICATIONS CORP. -0020FC MATROX -0020FD ITV TECHNOLOGIES, INC. -0020FE TOPWARE INC. / GRAND COMPUTER -0020FF SYMMETRICAL TECHNOLOGIES -003000 ALLWELL TECHNOLOGY CORP. -003001 SMP -003002 Expand Networks -003003 Phasys Ltd. -003004 LEADTEK RESEARCH INC. -003005 Fujitsu Siemens Computers -003006 SUPERPOWER COMPUTER -003007 OPTI, INC. -003008 AVIO DIGITAL, INC. -003009 Tachion Networks, Inc. -00300A AZTECH SYSTEMS LTD. -00300B mPHASE Technologies, Inc. -00300C CONGRUENCY, LTD. -00300D MMC Technology, Inc. -00300E Klotz Digital AG -00300F IMT - Information Management T -003010 VISIONETICS INTERNATIONAL -003011 HMS FIELDBUS SYSTEMS AB -003012 DIGITAL ENGINEERING LTD. -003013 NEC Corporation -003014 DIVIO, INC. -003015 CP CLARE CORP. -003016 ISHIDA CO., LTD. -003017 TERASTACK LTD. -003018 Jetway Information Co., Ltd. -003019 CISCO SYSTEMS, INC. -00301A SMARTBRIDGES PTE. LTD. -00301B SHUTTLE, INC. -00301C ALTVATER AIRDATA SYSTEMS -00301D SKYSTREAM, INC. -00301E 3COM Europe Ltd. -00301F OPTICAL NETWORKS, INC. -003020 TSI, Inc.. -003021 HSING TECH. ENTERPRISE CO.,LTD -003022 Fong Kai Industrial Co., Ltd. -003023 COGENT COMPUTER SYSTEMS, INC. -003024 CISCO SYSTEMS, INC. -003025 CHECKOUT COMPUTER SYSTEMS, LTD -003026 HEITEL -003027 KERBANGO, INC. -003028 FASE Saldatura srl -003029 OPICOM -00302A SOUTHERN INFORMATION -00302B INALP NETWORKS, INC. -00302C SYLANTRO SYSTEMS CORPORATION -00302D QUANTUM BRIDGE COMMUNICATIONS -00302E Hoft & Wessel AG -00302F Smiths Industries -003030 HARMONIX CORPORATION -003031 LIGHTWAVE COMMUNICATIONS, INC. -003032 MagicRam, Inc. -003033 ORIENT TELECOM CO., LTD. -003036 RMP ELEKTRONIKSYSTEME GMBH -003037 Packard Bell Nec Services -003038 XCP, INC. -003039 SOFTBOOK PRESS -00303A MAATEL -00303B PowerCom Technology -00303C ONNTO CORP. -00303D IVA CORPORATION -00303E Radcom Ltd. -00303F TurboComm Tech Inc. -003040 CISCO SYSTEMS, INC. -003041 SAEJIN T & M CO., LTD. -003042 DeTeWe-Deutsche Telephonwerke -003043 IDREAM TECHNOLOGIES, PTE. LTD. -003044 Portsmith LLC -003045 Village Networks, Inc. (VNI) -003046 Controlled Electronic Manageme -003047 NISSEI ELECTRIC CO., LTD. -003048 Supermicro Computer, Inc. -003049 BRYANT TECHNOLOGY, LTD. -00304A FRAUNHOFER INSTITUTE IMS -00304B ORBACOM SYSTEMS, INC. -00304C APPIAN COMMUNICATIONS, INC. -00304D ESI -00304E BUSTEC PRODUCTION LTD. -00304F PLANET Technology Corporation -003050 Versa Technology -003051 ORBIT AVIONIC & COMMUNICATION -003052 ELASTIC NETWORKS -003053 Basler AG -003054 CASTLENET TECHNOLOGY, INC. -003055 Hitachi Semiconductor America, -003056 Beck IPC GmbH -003057 E-Tel Corporation -003058 API MOTION -003059 DIGITAL-LOGIC AG -00305A TELGEN CORPORATION -00305B MODULE DEPARTMENT -00305C SMAR Laboratories Corp. -00305D DIGITRA SYSTEMS, INC. -00305E Abelko Innovation -00305F IMACON APS -003060 STARMATIX, INC. -003061 MobyTEL -003062 PATH 1 NETWORK TECHNOL'S INC. -003063 SANTERA SYSTEMS, INC. -003064 ADLINK TECHNOLOGY, INC. -003065 APPLE COMPUTER, INC. -003066 DIGITAL WIRELESS CORPORATION -003067 BIOSTAR MICROTECH INT'L CORP. -003068 CYBERNETICS TECH. CO., LTD. -003069 IMPACCT TECHNOLOGY CORP. -00306A PENTA MEDIA CO., LTD. -00306B CMOS SYSTEMS, INC. -00306C Hitex Holding GmbH -00306D LUCENT TECHNOLOGIES -00306E HEWLETT PACKARD -00306F SEYEON TECH. CO., LTD. -003070 1Net Corporation -003071 Cisco Systems, Inc. -003072 INTELLIBYTE INC. -003073 International Microsystems, In -003074 EQUIINET LTD. -003075 ADTECH -003076 Akamba Corporation -003077 ONPREM NETWORKS -003078 Cisco Systems, Inc. -003079 CQOS, INC. -00307A Advanced Technology & Systems -00307B Cisco Systems, Inc. -00307C ADID SA -00307D GRE AMERICA, INC. -00307E Redflex Communication Systems -00307F IRLAN LTD. -003080 CISCO SYSTEMS, INC. -003081 ALTOS C&C -003082 TAIHAN ELECTRIC WIRE CO., LTD. -003083 Ivron Systems -003084 ALLIED TELESYN INTERNAIONAL -003085 CISCO SYSTEMS, INC. -003086 Transistor Devices, Inc. -003087 VEGA GRIESHABER KG -003088 Siara Systems, Inc. -003089 Spectrapoint Wireless, LLC -00308A NICOTRA SISTEMI S.P.A -00308B Brix Networks -00308C ADVANCED DIGITAL INFORMATION -00308D PINNACLE SYSTEMS, INC. -00308E CROSS MATCH TECHNOLOGIES, INC. -00308F MICRILOR, Inc. -003090 CYRA TECHNOLOGIES, INC. -003091 TAIWAN FIRST LINE ELEC. CORP. -003092 ModuNORM GmbH -003093 SONNET TECHNOLOGIES, INC. -003094 Cisco Systems, Inc. -003095 Procomp Informatics, Ltd. -003096 CISCO SYSTEMS, INC. -003097 EXOMATIC AB -003098 Global Converging Technologies -003099 BOENIG UND KALLENBACH OHG -00309A ASTRO TERRA CORP. -00309B Smartware -00309C Timing Applications, Inc. -00309D Nimble Microsystems, Inc. -00309E WORKBIT CORPORATION. -00309F AMBER NETWORKS -0030A0 TYCO SUBMARINE SYSTEMS, LTD. -0030A1 WEBGATE Inc. -0030A2 Lightner Engineering -0030A3 CISCO SYSTEMS, INC. -0030A4 Woodwind Communications System -0030A5 ACTIVE POWER -0030A6 VIANET TECHNOLOGIES, LTD. -0030A7 SCHWEITZER ENGINEERING -0030A8 OL'E COMMUNICATIONS, INC. -0030A9 Netiverse, Inc. -0030AA AXUS MICROSYSTEMS, INC. -0030AB DELTA NETWORKS, INC. -0030AC Systeme Lauer GmbH & Co., Ltd. -0030AD SHANGHAI COMMUNICATION -0030AE Times N System, Inc. -0030AF Honeywell GmbH -0030B0 Convergenet Technologies -0030B1 GOC GESELLSCHAFT FUR OPTISCHE -0030B2 WESCAM - HEALDSBURG -0030B3 San Valley Systems, Inc. -0030B4 INTERSIL CORP. -0030B5 Tadiran Microwave Networks -0030B6 CISCO SYSTEMS, INC. -0030B7 Teletrol Systems, Inc. -0030B8 RiverDelta Networks -0030B9 ECTEL -0030BA AC&T SYSTEM CO., LTD. -0030BB CacheFlow, Inc. -0030BC Optronic AG -0030BD BELKIN COMPONENTS -0030BE City-Net Technology, Inc. -0030BF MULTIDATA GMBH -0030C0 Lara Technology, Inc. -0030C1 HEWLETT-PACKARD -0030C2 COMONE -0030C3 FLUECKIGER ELEKTRONIK AG -0030C4 Niigata Canotec Co., Inc. -0030C5 CADENCE DESIGN SYSTEMS -0030C6 CONTROL SOLUTIONS, INC. -0030C7 MACROMATE CORP. -0030C8 GAD LINE, LTD. -0030C9 LuxN, N -0030CA Discovery Com -0030CB OMNI FLOW COMPUTERS, INC. -0030CC Tenor Networks, Inc. -0030CD CONEXANT SYSTEMS, INC. -0030CE Zaffire -0030CF TWO TECHNOLOGIES, INC. -0030D1 INOVA CORPORATION -0030D2 WIN TECHNOLOGIES, CO., LTD. -0030D3 Agilent Technologies -0030D4 COMTIER -0030D5 DResearch GmbH -0030D6 MSC VERTRIEBS GMBH -0030D7 Innovative Systems, L.L.C. -0030D8 SITEK -0030D9 DATACORE SOFTWARE CORP. -0030DA COMTREND CO. -0030DB Mindready Solutions, Inc. -0030DC RIGHTECH CORPORATION -0030DD INDIGITA CORPORATION -0030DE WAGO Kontakttechnik GmbH -0030DF KB/TEL TELECOMUNICACIONES -0030E0 OXFORD SEMICONDUCTOR LTD. -0030E1 ACROTRON SYSTEMS, INC. -0030E2 GARNET SYSTEMS CO., LTD. -0030E3 SEDONA NETWORKS CORP. -0030E4 CHIYODA SYSTEM RIKEN -0030E5 Amper Datos S.A. -0030E6 SIEMENS MEDICAL SYSTEMS -0030E7 CNF MOBILE SOLUTIONS, INC. -0030E8 ENSIM CORP. -0030E9 GMA COMMUNICATION MANUFACT'G -0030EA TeraForce Technology Corporation -0030EB TURBONET COMMUNICATIONS, INC. -0030EC BORGARDT -0030ED Expert Magnetics Corp. -0030EE DSG Technology, Inc. -0030EF NEON TECHNOLOGY, INC. -0030F0 Uniform Industrial Corp. -0030F1 Accton Technology Corp. -0030F2 CISCO SYSTEMS, INC. -0030F3 At Work Computers -0030F4 STARDOT TECHNOLOGIES -0030F5 Wild Lab. Ltd. -0030F6 SECURELOGIX CORPORATION -0030F7 RAMIX INC. -0030F8 Dynapro Systems, Inc. -0030F9 Sollae Systems Co., Ltd. -0030FA TELICA, INC. -0030FB AZS Technology AG -0030FC Terawave Communications, Inc. -0030FD INTEGRATED SYSTEMS DESIGN -0030FE DSA GmbH -0030FF DATAFAB SYSTEMS, INC. -004000 PCI COMPONENTES DA AMZONIA LTD -004001 ZYXEL COMMUNICATIONS, INC. -004002 PERLE SYSTEMS LIMITED -004003 WESTINGHOUSE PROCESS CONTROL -004004 ICM CO. LTD. -004005 ANI COMMUNICATIONS INC. -004006 SAMPO TECHNOLOGY CORPORATION -004007 TELMAT INFORMATIQUE -004008 A PLUS INFO CORPORATION -004009 TACHIBANA TECTRON CO., LTD. -00400A PIVOTAL TECHNOLOGIES, INC. -00400B CISCO SYSTEMS, INC. -00400C GENERAL MICRO SYSTEMS, INC. -00400D LANNET DATA COMMUNICATIONS,LTD -00400E MEMOTEC COMMUNICATIONS, INC. -00400F DATACOM TECHNOLOGIES -004010 SONIC SYSTEMS, INC. -004011 ANDOVER CONTROLS CORPORATION -004012 WINDATA, INC. -004013 NTT DATA COMM. SYSTEMS CORP. -004014 COMSOFT GMBH -004015 ASCOM INFRASYS AG -004016 HADAX ELECTRONICS, INC. -004017 XCD INC. -004018 ADOBE SYSTEMS, INC. -004019 AEON SYSTEMS, INC. -00401A FUJI ELECTRIC CO., LTD. -00401B PRINTER SYSTEMS CORP. -00401C AST RESEARCH, INC. -00401D INVISIBLE SOFTWARE, INC. -00401E ICC -00401F COLORGRAPH LTD -004020 PINACL COMMUNICATION -004021 RASTER GRAPHICS -004022 KLEVER COMPUTERS, INC. -004023 LOGIC CORPORATION -004024 COMPAC INC. -004025 MOLECULAR DYNAMICS -004026 MELCO, INC. -004027 SMC MASSACHUSETTS, INC. -004028 NETCOMM LIMITED -004029 COMPEX -00402A CANOGA-PERKINS -00402B TRIGEM COMPUTER, INC. -00402C ISIS DISTRIBUTED SYSTEMS, INC. -00402D HARRIS ADACOM CORPORATION -00402E PRECISION SOFTWARE, INC. -00402F XLNT DESIGNS INC. -004030 GK COMPUTER -004031 KOKUSAI ELECTRIC CO., LTD -004032 DIGITAL COMMUNICATIONS -004033 ADDTRON TECHNOLOGY CO., LTD. -004034 BUSTEK CORPORATION -004035 OPCOM -004036 TRIBE COMPUTER WORKS, INC. -004037 SEA-ILAN, INC. -004038 TALENT ELECTRIC INCORPORATED -004039 OPTEC DAIICHI DENKO CO., LTD. -00403A IMPACT TECHNOLOGIES -00403B SYNERJET INTERNATIONAL CORP. -00403C FORKS, INC. -00403D TERADATA -00403E RASTER OPS CORPORATION -00403F SSANGYONG COMPUTER SYSTEMS -004040 RING ACCESS, INC. -004041 FUJIKURA LTD. -004042 N.A.T. GMBH -004043 NOKIA TELECOMMUNICATIONS -004044 QNIX COMPUTER CO., LTD. -004045 TWINHEAD CORPORATION -004046 UDC RESEARCH LIMITED -004047 WIND RIVER SYSTEMS -004048 SMD INFORMATICA S.A. -004049 TEGIMENTA AG -00404A WEST AUSTRALIAN DEPARTMENT -00404B MAPLE COMPUTER SYSTEMS -00404C HYPERTEC PTY LTD. -00404D TELECOMMUNICATIONS TECHNIQUES -00404E FLUENT, INC. -00404F SPACE & NAVAL WARFARE SYSTEMS -004050 IRONICS, INCORPORATED -004051 GRACILIS, INC. -004052 STAR TECHNOLOGIES, INC. -004053 AMPRO COMPUTERS -004054 CONNECTION MACHINES SERVICES -004055 METRONIX GMBH -004056 MCM JAPAN LTD. -004057 LOCKHEED - SANDERS -004058 KRONOS, INC. -004059 YOSHIDA KOGYO K. K. -00405A GOLDSTAR INFORMATION & COMM. -00405B FUNASSET LIMITED -00405C FUTURE SYSTEMS, INC. -00405D STAR-TEK, INC. -00405E NORTH HILLS ISRAEL -00405F AFE COMPUTERS LTD. -004060 COMENDEC LTD -004061 DATATECH ENTERPRISES CO., LTD. -004062 E-SYSTEMS, INC./GARLAND DIV. -004063 VIA TECHNOLOGIES, INC. -004064 KLA INSTRUMENTS CORPORATION -004065 GTE SPACENET -004066 HITACHI CABLE, LTD. -004067 OMNIBYTE CORPORATION -004068 EXTENDED SYSTEMS -004069 LEMCOM SYSTEMS, INC. -00406A KENTEK INFORMATION SYSTEMS,INC -00406B SYSGEN -00406C COPERNIQUE -00406D LANCO, INC. -00406E COROLLARY, INC. -00406F SYNC RESEARCH INC. -004070 INTERWARE CO., LTD. -004071 ATM COMPUTER GMBH -004072 Applied Innovation Inc. -004073 BASS ASSOCIATES -004074 CABLE AND WIRELESS -004075 M-TRADE (UK) LTD -004076 Sun Conversion Technologies -004077 MAXTON TECHNOLOGY CORPORATION -004078 WEARNES AUTOMATION PTE LTD -004079 JUKO MANUFACTURE COMPANY, LTD. -00407A SOCIETE D'EXPLOITATION DU CNIT -00407B SCIENTIFIC ATLANTA -00407C QUME CORPORATION -00407D EXTENSION TECHNOLOGY CORP. -00407E EVERGREEN SYSTEMS, INC. -00407F FLIR Systems -004080 ATHENIX CORPORATION -004081 MANNESMANN SCANGRAPHIC GMBH -004082 LABORATORY EQUIPMENT CORP. -004083 TDA INDUSTRIA DE PRODUTOS -004084 HONEYWELL INC. -004085 SAAB INSTRUMENTS AB -004086 MICHELS & KLEBERHOFF COMPUTER -004087 UBITREX CORPORATION -004088 MOBIUS TECHNOLOGIES, INC. -004089 MEIDENSHA CORPORATION -00408A TPS TELEPROCESSING SYS. GMBH -00408B RAYLAN CORPORATION -00408C AXIS COMMUNICATIONS AB -00408D THE GOODYEAR TIRE & RUBBER CO. -00408E DIGILOG, INC. -00408F WM-DATA MINFO AB -004090 ANSEL COMMUNICATIONS -004091 PROCOMP INDUSTRIA ELETRONICA -004092 ASP COMPUTER PRODUCTS, INC. -004093 PAXDATA NETWORKS LTD. -004094 SHOGRAPHICS, INC. -004095 R.P.T. INTERGROUPS INT'L LTD. -004096 Aironet Wireless Communication -004097 DATEX DIVISION OF -004098 DRESSLER GMBH & CO. -004099 NEWGEN SYSTEMS CORP. -00409A NETWORK EXPRESS, INC. -00409B HAL COMPUTER SYSTEMS INC. -00409C TRANSWARE -00409D DIGIBOARD, INC. -00409E CONCURRENT TECHNOLOGIES LTD. -00409F LANCAST/CASAT TECHNOLOGY, INC. -0040A0 GOLDSTAR CO., LTD. -0040A1 ERGO COMPUTING -0040A2 KINGSTAR TECHNOLOGY INC. -0040A3 MICROUNITY SYSTEMS ENGINEERING -0040A4 ROSE ELECTRONICS -0040A5 CLINICOMP INTL. -0040A6 Cray, Inc. -0040A7 ITAUTEC PHILCO S.A. -0040A8 IMF INTERNATIONAL LTD. -0040A9 DATACOM INC. -0040AA VALMET AUTOMATION INC. -0040AB ROLAND DG CORPORATION -0040AC SUPER WORKSTATION, INC. -0040AD SMA REGELSYSTEME GMBH -0040AE DELTA CONTROLS, INC. -0040AF DIGITAL PRODUCTS, INC. -0040B0 BYTEX CORPORATION, ENGINEERING -0040B1 CODONICS INC. -0040B2 SYSTEMFORSCHUNG -0040B3 PAR MICROSYSTEMS CORPORATION -0040B4 NEXTCOM K.K. -0040B5 VIDEO TECHNOLOGY COMPUTERS LTD -0040B6 COMPUTERM CORPORATION -0040B7 STEALTH COMPUTER SYSTEMS -0040B8 IDEA ASSOCIATES -0040B9 MACQ ELECTRONIQUE SA -0040BA ALLIANT COMPUTER SYSTEMS CORP. -0040BB GOLDSTAR CABLE CO., LTD. -0040BC ALGORITHMICS LTD. -0040BD STARLIGHT NETWORKS, INC. -0040BE BOEING DEFENSE & SPACE -0040BF CHANNEL SYSTEMS INTERN'L INC. -0040C0 VISTA CONTROLS CORPORATION -0040C1 BIZERBA-WERKE WILHEIM KRAUT -0040C2 APPLIED COMPUTING DEVICES -0040C3 FISCHER AND PORTER CO. -0040C4 KINKEI SYSTEM CORPORATION -0040C5 MICOM COMMUNICATIONS INC. -0040C6 FIBERNET RESEARCH, INC. -0040C7 RUBY TECH CORPORATION -0040C8 MILAN TECHNOLOGY CORPORATION -0040C9 NCUBE -0040CA FIRST INTERNAT'L COMPUTER, INC -0040CB LANWAN TECHNOLOGIES -0040CC SILCOM MANUF'G TECHNOLOGY INC. -0040CD TERA MICROSYSTEMS, INC. -0040CE NET-SOURCE, INC. -0040CF STRAWBERRY TREE, INC. -0040D0 MITAC INTERNATIONAL CORP. -0040D1 FUKUDA DENSHI CO., LTD. -0040D2 PAGINE CORPORATION -0040D3 KIMPSION INTERNATIONAL CORP. -0040D4 GAGE TALKER CORP. -0040D5 SARTORIUS AG -0040D6 LOCAMATION B.V. -0040D7 STUDIO GEN INC. -0040D8 OCEAN OFFICE AUTOMATION LTD. -0040D9 AMERICAN MEGATRENDS INC. -0040DA TELSPEC LTD -0040DB ADVANCED TECHNICAL SOLUTIONS -0040DC TRITEC ELECTRONIC GMBH -0040DD HONG TECHNOLOGIES -0040DE ELETTRONICA SAN GIORGIO -0040DF DIGALOG SYSTEMS, INC. -0040E0 ATOMWIDE LTD. -0040E1 MARNER INTERNATIONAL, INC. -0040E2 MESA RIDGE TECHNOLOGIES, INC. -0040E3 QUIN SYSTEMS LTD -0040E4 E-M TECHNOLOGY, INC. -0040E5 SYBUS CORPORATION -0040E6 C.A.E.N. -0040E7 ARNOS INSTRUMENTS & COMPUTER -0040E8 CHARLES RIVER DATA SYSTEMS,INC -0040E9 ACCORD SYSTEMS, INC. -0040EA PLAIN TREE SYSTEMS INC -0040EB MARTIN MARIETTA CORPORATION -0040EC MIKASA SYSTEM ENGINEERING -0040ED NETWORK CONTROLS INT'NATL INC. -0040EE OPTIMEM -0040EF HYPERCOM, INC. -0040F0 MICRO SYSTEMS, INC. -0040F1 CHUO ELECTRONICS CO., LTD. -0040F2 JANICH & KLASS COMPUTERTECHNIK -0040F3 NETCOR -0040F4 CAMEO COMMUNICATIONS, INC. -0040F5 OEM ENGINES -0040F6 KATRON COMPUTERS INC. -0040F7 POLAROID MEDICAL IMAGING SYS. -0040F8 SYSTEMHAUS DISCOM -0040F9 COMBINET -0040FA MICROBOARDS, INC. -0040FB CASCADE COMMUNICATIONS CORP. -0040FC IBR COMPUTER TECHNIK GMBH -0040FD LXE -0040FE SYMPLEX COMMUNICATIONS -0040FF TELEBIT CORPORATION -004252 RLX Technologies -005000 NEXO COMMUNICATIONS, INC. -005001 YAMASHITA SYSTEMS CORP. -005002 OMNISEC AG -005003 GRETAG MACBETH AG -005004 3COM CORPORATION -005006 TAC AB -005007 SIEMENS TELECOMMUNICATION SYSTEMS LIMITED -005008 TIVA MICROCOMPUTER CORP. (TMC) -005009 PHILIPS BROADBAND NETWORKS -00500A IRIS TECHNOLOGIES, INC. -00500B CISCO SYSTEMS, INC. -00500C e-Tek Labs, Inc. -00500D SATORI ELECTORIC CO., LTD. -00500E CHROMATIS NETWORKS, INC. -00500F CISCO SYSTEMS, INC. -005010 NovaNET Learning, Inc. -005012 CBL - GMBH -005013 Chaparral Network Storage -005014 CISCO SYSTEMS, INC. -005015 BRIGHT STAR ENGINEERING -005016 SST/WOODHEAD INDUSTRIES -005017 RSR S.R.L. -005018 ADVANCED MULTIMEDIA INTERNET TECHNOLOGY INC. -005019 SPRING TIDE NETWORKS, INC. -00501A UISIQN -00501B ABL CANADA, INC. -00501C JATOM SYSTEMS, INC. -00501E Miranda Technologies, Inc. -00501F MRG SYSTEMS, LTD. -005020 MEDIASTAR CO., LTD. -005021 EIS INTERNATIONAL, INC. -005022 ZONET TECHNOLOGY, INC. -005023 PG DESIGN ELECTRONICS, INC. -005024 NAVIC SYSTEMS, INC. -005026 COSYSTEMS, INC. -005027 GENICOM CORPORATION -005028 AVAL COMMUNICATIONS -005029 1394 PRINTER WORKING GROUP -00502A CISCO SYSTEMS, INC. -00502B GENRAD LTD. -00502C SOYO COMPUTER, INC. -00502D ACCEL, INC. -00502E CAMBEX CORPORATION -00502F TollBridge Technologies, Inc. -005030 FUTURE PLUS SYSTEMS -005031 AEROFLEX LABORATORIES, INC. -005032 PICAZO COMMUNICATIONS, INC. -005033 MAYAN NETWORKS -005036 NETCAM, LTD. -005037 KOGA ELECTRONICS CO. -005038 DAIN TELECOM CO., LTD. -005039 MARINER NETWORKS -00503A DATONG ELECTRONICS LTD. -00503B MEDIAFIRE CORPORATION -00503C TSINGHUA NOVEL ELECTRONICS -00503E CISCO SYSTEMS, INC. -00503F ANCHOR GAMES -005040 EMWARE, INC. -005041 CTX OPTO ELECTRONIC CORP. -005042 SCI MANUFACTURING SINGAPORE PTE, LTD. -005043 MARVELL SEMICONDUCTOR, INC. -005044 ASACA CORPORATION -005045 RIOWORKS SOLUTIONS, INC. -005046 MENICX INTERNATIONAL CO., LTD. -005048 INFOLIBRIA -005049 ELLACOYA NETWORKS, INC. -00504A ELTECO A.S. -00504B BARCONET N.V. -00504C GALIL MOTION CONTROL, INC. -00504D TOKYO ELECTRON DEVICE LTD. -00504E SIERRA MONITOR CORP. -00504F OLENCOM ELECTRONICS -005050 CISCO SYSTEMS, INC. -005051 IWATSU ELECTRIC CO., LTD. -005052 TIARA NETWORKS, INC. -005053 CISCO SYSTEMS, INC. -005054 CISCO SYSTEMS, INC. -005055 DOMS A/S -005056 VMWare, Inc. -005057 BROADBAND ACCESS SYSTEMS -005058 VEGASTREAM LIMITED -005059 SUITE TECHNOLOGY SYSTEMS NETWORK -00505A NETWORK ALCHEMY, INC. -00505B KAWASAKI LSI U.S.A., INC. -00505C TUNDO CORPORATION -00505E DIGITEK MICROLOGIC S.A. -00505F BRAND INNOVATORS -005060 TANDBERG TELECOM AS -005062 KOUWELL ELECTRONICS CORP. ** -005063 OY COMSEL SYSTEM AB -005064 CAE ELECTRONICS -005065 DENSEI-LAMBAD Co., Ltd. -005066 AtecoM GmbH advanced telecomunication modules -005067 AEROCOMM, INC. -005068 ELECTRONIC INDUSTRIES ASSOCIATION -005069 PixStream Incorporated -00506A EDEVA, INC. -00506B SPX-ATEG -00506C G & L BEIJER ELECTRONICS AB -00506D VIDEOJET SYSTEMS -00506E CORDER ENGINEERING CORPORATION -00506F G-CONNECT -005070 CHAINTECH COMPUTER CO., LTD. -005071 AIWA CO., LTD. -005072 CORVIS CORPORATION -005073 CISCO SYSTEMS, INC. -005074 ADVANCED HI-TECH CORP. -005075 KESTREL SOLUTIONS -005076 IBM -005077 PROLIFIC TECHNOLOGY, INC. -005078 MEGATON HOUSE, LTD. -00507A XPEED, INC. -00507B MERLOT COMMUNICATIONS -00507C VIDEOCON AG -00507D IFP -00507E NEWER TECHNOLOGY -00507F DrayTek Corp. -005080 CISCO SYSTEMS, INC. -005081 MURATA MACHINERY, LTD. -005082 FORESSON CORPORATION -005083 GILBARCO, INC. -005084 ATL PRODUCTS -005086 TELKOM SA, LTD. -005087 TERASAKI ELECTRIC CO., LTD. -005088 AMANO CORPORATION -005089 SAFETY MANAGEMENT SYSTEMS -00508B COMPAQ COMPUTER CORPORATION -00508C RSI SYSTEMS -00508D ABIT COMPUTER CORPORATION -00508E OPTIMATION, INC. -00508F ASITA TECHNOLOGIES INT'L LTD. -005090 DCTRI -005091 NETACCESS, INC. -005092 RIGAKU INDUSTRIAL CORPORATION -005093 BOEING -005094 PACE MICRO TECHNOLOGY PLC -005095 PERACOM NETWORKS -005096 SALIX TECHNOLOGIES, INC. -005097 MMC-EMBEDDED COMPUTERTECHNIK GmbH -005098 GLOBALOOP, LTD. -005099 3COM EUROPE, LTD. -00509A TAG ELECTRONIC SYSTEMS -00509B SWITCHCORE AB -00509C BETA RESEARCH -00509D THE INDUSTREE B.V. -00509E Les Technologies SoftAcoustik Inc. -00509F HORIZON COMPUTER -0050A0 DELTA COMPUTER SYSTEMS, INC. -0050A1 CARLO GAVAZZI, INC. -0050A2 CISCO SYSTEMS, INC. -0050A3 TransMedia Communications, Inc. -0050A4 IO TECH, INC. -0050A5 CAPITOL BUSINESS SYSTEMS, LTD. -0050A6 OPTRONICS -0050A7 CISCO SYSTEMS, INC. -0050A8 OpenCon Systems, Inc. -0050A9 MOLDAT WIRELESS TECHNOLGIES -0050AA KONICA MINOLTA HOLDINGS, INC. -0050AB NALTEC, INC. -0050AC MAPLE COMPUTER CORPORATION -0050AD CommUnique Wireless Corp. -0050AE IWAKI ELECTRONICS CO., LTD. -0050AF INTERGON, INC. -0050B0 TECHNOLOGY ATLANTA CORPORATION -0050B1 GIDDINGS & LEWIS -0050B2 BRODEL AUTOMATION -0050B3 VOICEBOARD CORPORATION -0050B4 SATCHWELL CONTROL SYSTEMS, LTD -0050B5 FICHET-BAUCHE -0050B6 GOOD WAY IND. CO., LTD. -0050B7 BOSER TECHNOLOGY CO., LTD. -0050B8 INOVA COMPUTERS GMBH & CO. KG -0050B9 XITRON TECHNOLOGIES, INC. -0050BA D-LINK -0050BB CMS TECHNOLOGIES -0050BC HAMMER STORAGE SOLUTIONS -0050BD CISCO SYSTEMS, INC. -0050BE FAST MULTIMEDIA AG -0050BF MOTOTECH INC. -0050C0 GATAN, INC. -0050C1 GEMFLEX NETWORKS, LTD. -0050C2 IEEE REGISTRATION AUTHORITY -0050C4 IMD -0050C5 ADS TECHNOLOGIES, INC. -0050C6 LOOP TELECOMMUNICATION INTERNATIONAL, INC. -0050C8 ADDONICS COMMUNICATIONS, INC. -0050C9 MASPRO DENKOH CORP. -0050CA NET TO NET TECHNOLOGIES -0050CB JETTER -0050CC XYRATEX -0050CD DIGIANSWER A/S -0050CE LG INTERNATIONAL CORP. -0050CF VANLINK COMMUNICATION TECHNOLOGY RESEARCH INSTITUTE -0050D0 MINERVA SYSTEMS -0050D1 CISCO SYSTEMS, INC. -0050D2 BAE Systems Canada, Inc. -0050D3 DIGITAL AUDIO PROCESSING PTY. LTD. -0050D4 JOOHONG INFORMATION & -0050D5 AD SYSTEMS CORP. -0050D6 ATLAS COPCO TOOLS AB -0050D7 TELSTRAT -0050D8 UNICORN COMPUTER CORP. -0050D9 ENGETRON-ENGENHARIA ELETRONICA IND. e COM. LTDA -0050DA 3COM CORPORATION -0050DB CONTEMPORARY CONTROL -0050DC TAS TELEFONBAU A. SCHWABE GMBH & CO. KG -0050DD SERRA SOLDADURA, S.A. -0050DE SIGNUM SYSTEMS CORP. -0050DF AirFiber, Inc. -0050E1 NS TECH ELECTRONICS SDN BHD -0050E2 CISCO SYSTEMS, INC. -0050E3 Terayon Communications Systems -0050E4 APPLE COMPUTER, INC. -0050E6 HAKUSAN CORPORATION -0050E7 PARADISE INNOVATIONS (ASIA) -0050E8 NOMADIX INC. -0050EA XEL COMMUNICATIONS, INC. -0050EB ALPHA-TOP CORPORATION -0050EC OLICOM A/S -0050ED ANDA NETWORKS -0050EE TEK DIGITEL CORPORATION -0050EF SPE Systemhaus GmbH -0050F0 CISCO SYSTEMS, INC. -0050F1 LIBIT SIGNAL PROCESSING, LTD. -0050F2 MICROSOFT CORP. -0050F3 GLOBAL NET INFORMATION CO., Ltd. -0050F4 SIGMATEK GMBH & CO. KG -0050F6 PAN-INTERNATIONAL INDUSTRIAL CORP. -0050F7 VENTURE MANUFACTURING (SINGAPORE) LTD. -0050F8 ENTREGA TECHNOLOGIES, INC. -0050FA OXTEL, LTD. -0050FB VSK ELECTRONICS -0050FC EDIMAX TECHNOLOGY CO., LTD. -0050FD VISIONCOMM CO., LTD. -0050FE PCTVnet ASA -0050FF HAKKO ELECTRONICS CO., LTD. -006000 XYCOM INC. -006001 InnoSys, Inc. -006002 SCREEN SUBTITLING SYSTEMS, LTD -006003 TERAOKA WEIGH SYSTEM PTE, LTD. -006004 COMPUTADORES MODULARES SA -006005 FEEDBACK DATA LTD. -006006 SOTEC CO., LTD -006007 ACRES GAMING, INC. -006008 3COM CORPORATION -006009 CISCO SYSTEMS, INC. -00600A SORD COMPUTER CORPORATION -00600B LOGWARE GmbH -00600C APPLIED DATA SYSTEMS, INC. -00600D Digital Logic GmbH -00600E WAVENET INTERNATIONAL, INC. -00600F WESTELL, INC. -006010 NETWORK MACHINES, INC. -006011 CRYSTAL SEMICONDUCTOR CORP. -006012 POWER COMPUTING CORPORATION -006013 NETSTAL MASCHINEN AG -006014 EDEC CO., LTD. -006015 NET2NET CORPORATION -006016 CLARIION -006017 TOKIMEC INC. -006018 STELLAR ONE CORPORATION -006019 Roche Diagnostics -00601A KEITHLEY INSTRUMENTS -00601B MESA ELECTRONICS -00601C TELXON CORPORATION -00601D LUCENT TECHNOLOGIES -00601E SOFTLAB, INC. -00601F STALLION TECHNOLOGIES -006020 PIVOTAL NETWORKING, INC. -006021 DSC CORPORATION -006022 VICOM SYSTEMS, INC. -006023 PERICOM SEMICONDUCTOR CORP. -006024 GRADIENT TECHNOLOGIES, INC. -006025 ACTIVE IMAGING PLC -006026 VIKING COMPONENTS, INC. -006027 Superior Modular Products -006028 MACROVISION CORPORATION -006029 CARY PERIPHERALS INC. -00602A SYMICRON COMPUTER COMMUNICATIONS, LTD. -00602B PEAK AUDIO -00602C LINX Data Terminals, Inc. -00602D ALERTON TECHNOLOGIES, INC. -00602E CYCLADES CORPORATION -00602F CISCO SYSTEMS, INC. -006030 VILLAGE TRONIC ENTWICKLUNG -006031 HRK SYSTEMS -006032 I-CUBE, INC. -006033 ACUITY IMAGING, INC. -006034 ROBERT BOSCH GmbH -006035 DALLAS SEMICONDUCTOR, INC. -006036 AUSTRIAN RESEARCH CENTER SEIBERSDORF -006037 PHILIPS SEMICONDUCTORS -006038 Nortel Networks -006039 SanCom Technology, Inc. -00603A QUICK CONTROLS LTD. -00603B AMTEC spa -00603C HAGIWARA SYS-COM CO., LTD. -00603D 3CX -00603E CISCO SYSTEMS, INC. -00603F PATAPSCO DESIGNS -006040 NETRO CORP. -006041 Yokogawa Electric Corporation -006042 TKS (USA), INC. -006043 ComSoft Systems, Inc. -006044 LITTON/POLY-SCIENTIFIC -006045 PATHLIGHT TECHNOLOGIES -006046 VMETRO, INC. -006047 CISCO SYSTEMS, INC. -006048 EMC CORPORATION -006049 VINA TECHNOLOGIES -00604A SAIC IDEAS GROUP -00604B BIODATA GmbH -00604C SAT -00604D MMC NETWORKS, INC. -00604E CYCLE COMPUTER CORPORATION, INC. -00604F SUZUKI MFG. CO., LTD. -006050 INTERNIX INC. -006051 QUALITY SEMICONDUCTOR -006052 PERIPHERALS ENTERPRISE CO., Ltd. -006053 TOYODA MACHINE WORKS, LTD. -006054 CONTROLWARE GMBH -006055 CORNELL UNIVERSITY -006056 NETWORK TOOLS, INC. -006057 MURATA MANUFACTURING CO., LTD. -006058 COPPER MOUNTAIN COMMUNICATIONS, INC. -006059 TECHNICAL COMMUNICATIONS CORP. -00605A CELCORE, INC. -00605B IntraServer Technology, Inc. -00605C CISCO SYSTEMS, INC. -00605D SCANIVALVE CORP. -00605E LIBERTY TECHNOLOGY NETWORKING -00605F NIPPON UNISOFT CORPORATION -006060 DAWNING TECHNOLOGIES, INC. -006061 WHISTLE COMMUNICATIONS CORP. -006062 TELESYNC, INC. -006063 PSION DACOM PLC. -006064 NETCOMM LIMITED -006065 BERNECKER & RAINER INDUSTRIE-ELEKTRONIC GmbH -006066 LACROIX TECHNOLGIE -006067 ACER NETXUS INC. -006068 EICON TECHNOLOGY CORPORATION -006069 BROCADE COMMUNICATIONS SYSTEMS, Inc. -00606A MITSUBISHI WIRELESS COMMUNICATIONS. INC. -00606B Synclayer Inc. -00606C ARESCOM -00606D DIGITAL EQUIPMENT CORP. -00606E DAVICOM SEMICONDUCTOR, INC. -00606F CLARION CORPORATION OF AMERICA -006070 CISCO SYSTEMS, INC. -006071 MIDAS LAB, INC. -006072 VXL INSTRUMENTS, LIMITED -006073 REDCREEK COMMUNICATIONS, INC. -006074 QSC AUDIO PRODUCTS -006075 PENTEK, INC. -006076 SCHLUMBERGER TECHNOLOGIES RETAIL PETROLEUM SYSTEMS -006077 PRISA NETWORKS -006078 POWER MEASUREMENT LTD. -006079 Mainstream Data, Inc. -00607A DVS GmbH -00607B FORE SYSTEMS, INC. -00607C WaveAccess, Ltd. -00607D SENTIENT NETWORKS INC. -00607E GIGALABS, INC. -00607F AURORA TECHNOLOGIES, INC. -006080 MICROTRONIX DATACOM LTD. -006081 TV/COM INTERNATIONAL -006082 NOVALINK TECHNOLOGIES, INC. -006083 CISCO SYSTEMS, INC. -006084 DIGITAL VIDEO -006085 Storage Concepts -006086 LOGIC REPLACEMENT TECH. LTD. -006087 KANSAI ELECTRIC CO., LTD. -006088 WHITE MOUNTAIN DSP, INC. -006089 XATA -00608A CITADEL COMPUTER -00608B ConferTech International -00608C 3COM CORPORATION -00608D UNIPULSE CORP. -00608E HE ELECTRONICS, TECHNOLOGIE & SYSTEMTECHNIK GmbH -00608F TEKRAM TECHNOLOGY CO., LTD. -006090 ABLE COMMUNICATIONS, INC. -006091 FIRST PACIFIC NETWORKS, INC. -006092 MICRO/SYS, INC. -006093 VARIAN -006094 IBM CORP. -006095 ACCU-TIME SYSTEMS, INC. -006096 T.S. MICROTECH INC. -006097 3COM CORPORATION -006098 HT COMMUNICATIONS -006099 LAN MEDIA CORPORATION -00609A NJK TECHNO CO. -00609B ASTRO-MED, INC. -00609C Perkin-Elmer Incorporated -00609D PMI FOOD EQUIPMENT GROUP -00609E ASC X3 - INFORMATION TECHNOLOGY STANDARDS SECRETARIATS -00609F PHAST CORPORATION -0060A0 SWITCHED NETWORK TECHNOLOGIES, INC. -0060A1 VPNet, Inc. -0060A2 NIHON UNISYS LIMITED CO. -0060A3 CONTINUUM TECHNOLOGY CORP. -0060A4 GRINAKER SYSTEM TECHNOLOGIES -0060A5 PERFORMANCE TELECOM CORP. -0060A6 PARTICLE MEASURING SYSTEMS -0060A7 MICROSENS GmbH & CO. KG -0060A8 TIDOMAT AB -0060A9 GESYTEC MbH -0060AA INTELLIGENT DEVICES INC. (IDI) -0060AB LARSCOM INCORPORATED -0060AC RESILIENCE CORPORATION -0060AD MegaChips Corporation -0060AE TRIO INFORMATION SYSTEMS AB -0060AF PACIFIC MICRO DATA, INC. -0060B0 HEWLETT-PACKARD CO. -0060B1 INPUT/OUTPUT, INC. -0060B2 PROCESS CONTROL CORP. -0060B3 Z-COM, INC. -0060B4 GLENAYRE R&D INC. -0060B5 KEBA GmbH -0060B6 LAND COMPUTER CO., LTD. -0060B7 CHANNELMATIC, INC. -0060B8 CORELIS INC. -0060B9 NITSUKO CORPORATION -0060BA SAHARA NETWORKS, INC. -0060BB CABLETRON - NETLINK, INC. -0060BC KeunYoung Electronics & Communication Co., Ltd. -0060BD HUBBELL-PULSECOM -0060BE WEBTRONICS -0060BF MACRAIGOR SYSTEMS, INC. -0060C0 NERA AS -0060C1 WaveSpan Corporation -0060C2 MPL AG -0060C3 NETVISION CORPORATION -0060C4 SOLITON SYSTEMS K.K. -0060C5 ANCOT CORP. -0060C6 DCS AG -0060C7 AMATI COMMUNICATIONS CORP. -0060C8 KUKA WELDING SYSTEMS & ROBOTS -0060C9 ControlNet, Inc. -0060CA HARMONIC SYSTEMS INCORPORATED -0060CB HITACHI ZOSEN CORPORATION -0060CC EMTRAK, INCORPORATED -0060CD VideoServer, Inc. -0060CE ACCLAIM COMMUNICATIONS -0060CF ALTEON NETWORKS, INC. -0060D0 SNMP RESEARCH INCORPORATED -0060D1 CASCADE COMMUNICATIONS -0060D2 LUCENT TECHNOLOGIES TAIWAN TELECOMMUNICATIONS CO., LTD. -0060D3 AT&T -0060D4 ELDAT COMMUNICATION LTD. -0060D5 MIYACHI TECHNOS CORP. -0060D6 NovAtel Wireless Technologies Ltd. -0060D7 ECOLE POLYTECHNIQUE FEDERALE DE LAUSANNE (EPFL) -0060D8 ELMIC SYSTEMS, INC. -0060D9 TRANSYS NETWORKS INC. -0060DA JBM ELECTRONICS CO. -0060DB NTP ELEKTRONIK A/S -0060DC TOYO COMMUNICATION EQUIPMENT Co., Ltd. -0060DD MYRICOM, INC. -0060DE KAYSER-THREDE GmbH -0060DF CNT Corporation -0060E0 AXIOM TECHNOLOGY CO., LTD. -0060E1 ORCKIT COMMUNICATIONS LTD. -0060E2 QUEST ENGINEERING & DEVELOPMENT -0060E3 ARBIN INSTRUMENTS -0060E4 COMPUSERVE, INC. -0060E5 FUJI AUTOMATION CO., LTD. -0060E6 SHOMITI SYSTEMS INCORPORATED -0060E7 RANDATA -0060E8 HITACHI COMPUTER PRODUCTS (AMERICA), INC. -0060E9 ATOP TECHNOLOGIES, INC. -0060EA StreamLogic -0060EB FOURTHTRACK SYSTEMS -0060EC HERMARY OPTO ELECTRONICS INC. -0060ED RICARDO TEST AUTOMATION LTD. -0060EE APOLLO -0060EF FLYTECH TECHNOLOGY CO., LTD. -0060F0 JOHNSON & JOHNSON MEDICAL, INC -0060F1 EXP COMPUTER, INC. -0060F2 LASERGRAPHICS, INC. -0060F3 Performance Analysis Broadband, Spirent plc -0060F4 ADVANCED COMPUTER SOLUTIONS, Inc. -0060F5 ICON WEST, INC. -0060F6 NEXTEST COMMUNICATIONS PRODUCTS, INC. -0060F7 DATAFUSION SYSTEMS -0060F8 Loran International Technologies Inc. -0060F9 DIAMOND LANE COMMUNICATIONS -0060FA EDUCATIONAL TECHNOLOGY RESOURCES, INC. -0060FB PACKETEER, INC. -0060FC CONSERVATION THROUGH INNOVATION LTD. -0060FD NetICs, Inc. -0060FE LYNX SYSTEM DEVELOPERS, INC. -0060FF QuVis, Inc. -0070B0 M/A-COM INC. COMPANIES -0070B3 DATA RECALL LTD. -008000 MULTITECH SYSTEMS, INC. -008001 PERIPHONICS CORPORATION -008002 SATELCOM (UK) LTD -008003 HYTEC ELECTRONICS LTD. -008004 ANTLOW COMMUNICATIONS, LTD. -008005 CACTUS COMPUTER INC. -008006 COMPUADD CORPORATION -008007 DLOG NC-SYSTEME -008008 DYNATECH COMPUTER SYSTEMS -008009 JUPITER SYSTEMS, INC. -00800A JAPAN COMPUTER CORP. -00800B CSK CORPORATION -00800C VIDECOM LIMITED -00800D VOSSWINKEL F.U. -00800E ATLANTIX CORPORATION -00800F STANDARD MICROSYSTEMS -008010 COMMODORE INTERNATIONAL -008011 DIGITAL SYSTEMS INT'L. INC. -008012 INTEGRATED MEASUREMENT SYSTEMS -008013 THOMAS-CONRAD CORPORATION -008014 ESPRIT SYSTEMS -008015 SEIKO SYSTEMS, INC. -008016 WANDEL AND GOLTERMANN -008017 PFU LIMITED -008018 KOBE STEEL, LTD. -008019 DAYNA COMMUNICATIONS, INC. -00801A BELL ATLANTIC -00801B KODIAK TECHNOLOGY -00801C NEWPORT SYSTEMS SOLUTIONS -00801D INTEGRATED INFERENCE MACHINES -00801E XINETRON, INC. -00801F KRUPP ATLAS ELECTRONIK GMBH -008020 NETWORK PRODUCTS -008021 Alcatel Canada Inc. -008022 SCAN-OPTICS -008023 INTEGRATED BUSINESS NETWORKS -008024 KALPANA, INC. -008025 STOLLMANN GMBH -008026 NETWORK PRODUCTS CORPORATION -008027 ADAPTIVE SYSTEMS, INC. -008028 TRADPOST (HK) LTD -008029 EAGLE TECHNOLOGY, INC. -00802A TEST SYSTEMS & SIMULATIONS INC -00802B INTEGRATED MARKETING CO -00802C THE SAGE GROUP PLC -00802D XYLOGICS INC -00802E CASTLE ROCK COMPUTING -00802F NATIONAL INSTRUMENTS CORP. -008030 NEXUS ELECTRONICS -008031 BASYS, CORP. -008032 ACCESS CO., LTD. -008033 FORMATION, INC. -008034 SMT GOUPIL -008035 TECHNOLOGY WORKS, INC. -008036 REFLEX MANUFACTURING SYSTEMS -008037 Ericsson Group -008038 DATA RESEARCH & APPLICATIONS -008039 ALCATEL STC AUSTRALIA -00803A VARITYPER, INC. -00803B APT COMMUNICATIONS, INC. -00803C TVS ELECTRONICS LTD -00803D SURIGIKEN CO., LTD. -00803E SYNERNETICS -00803F TATUNG COMPANY -008040 JOHN FLUKE MANUFACTURING CO. -008041 VEB KOMBINAT ROBOTRON -008042 FORCE COMPUTERS -008043 NETWORLD, INC. -008044 SYSTECH COMPUTER CORP. -008045 MATSUSHITA ELECTRIC IND. CO -008046 UNIVERSITY OF TORONTO -008047 IN-NET CORP. -008048 COMPEX INCORPORATED -008049 NISSIN ELECTRIC CO., LTD. -00804A PRO-LOG -00804B EAGLE TECHNOLOGIES PTY.LTD. -00804C CONTEC CO., LTD. -00804D CYCLONE MICROSYSTEMS, INC. -00804E APEX COMPUTER COMPANY -00804F DAIKIN INDUSTRIES, LTD. -008050 ZIATECH CORPORATION -008051 FIBERMUX -008052 TECHNICALLY ELITE CONCEPTS -008053 INTELLICOM, INC. -008054 FRONTIER TECHNOLOGIES CORP. -008055 FERMILAB -008056 SPHINX ELEKTRONIK GMBH -008057 ADSOFT, LTD. -008058 PRINTER SYSTEMS CORPORATION -008059 STANLEY ELECTRIC CO., LTD -00805A TULIP COMPUTERS INTERNAT'L B.V -00805B CONDOR SYSTEMS, INC. -00805C AGILIS CORPORATION -00805D CANSTAR -00805E LSI LOGIC CORPORATION -00805F COMPAQ COMPUTER CORPORATION -008060 NETWORK INTERFACE CORPORATION -008061 LITTON SYSTEMS, INC. -008062 INTERFACE CO. -008063 RICHARD HIRSCHMANN GMBH & CO. -008064 WYSE TECHNOLOGY -008065 CYBERGRAPHIC SYSTEMS PTY LTD. -008066 ARCOM CONTROL SYSTEMS, LTD. -008067 SQUARE D COMPANY -008068 YAMATECH SCIENTIFIC LTD. -008069 COMPUTONE SYSTEMS -00806A ERI (EMPAC RESEARCH INC.) -00806B SCHMID TELECOMMUNICATION -00806C CEGELEC PROJECTS LTD -00806D CENTURY SYSTEMS CORP. -00806E NIPPON STEEL CORPORATION -00806F ONELAN LTD. -008070 COMPUTADORAS MICRON -008071 SAI TECHNOLOGY -008072 MICROPLEX SYSTEMS LTD. -008073 DWB ASSOCIATES -008074 FISHER CONTROLS -008075 PARSYTEC GMBH -008076 MCNC -008077 BROTHER INDUSTRIES, LTD. -008078 PRACTICAL PERIPHERALS, INC. -008079 MICROBUS DESIGNS LTD. -00807A AITECH SYSTEMS LTD. -00807B ARTEL COMMUNICATIONS CORP. -00807C FIBERCOM, INC. -00807D EQUINOX SYSTEMS INC. -00807E SOUTHERN PACIFIC LTD. -00807F DY-4 INCORPORATED -008080 DATAMEDIA CORPORATION -008081 KENDALL SQUARE RESEARCH CORP. -008082 PEP MODULAR COMPUTERS GMBH -008083 AMDAHL -008084 THE CLOUD INC. -008085 H-THREE SYSTEMS CORPORATION -008086 COMPUTER GENERATION INC. -008087 OKI ELECTRIC INDUSTRY CO., LTD -008088 VICTOR COMPANY OF JAPAN, LTD. -008089 TECNETICS (PTY) LTD. -00808A SUMMIT MICROSYSTEMS CORP. -00808B DACOLL LIMITED -00808C NetScout Systems, Inc. -00808D WESTCOAST TECHNOLOGY B.V. -00808E RADSTONE TECHNOLOGY -00808F C. ITOH ELECTRONICS, INC. -008090 MICROTEK INTERNATIONAL, INC. -008091 TOKYO ELECTRIC CO.,LTD -008092 JAPAN COMPUTER INDUSTRY, INC. -008093 XYRON CORPORATION -008094 ALFA LAVAL AUTOMATION AB -008095 BASIC MERTON HANDELSGES.M.B.H. -008096 HUMAN DESIGNED SYSTEMS, INC. -008097 CENTRALP AUTOMATISMES -008098 TDK CORPORATION -008099 KLOCKNER MOELLER IPC -00809A NOVUS NETWORKS LTD -00809B JUSTSYSTEM CORPORATION -00809C LUXCOM, INC. -00809D Commscraft Ltd. -00809E DATUS GMBH -00809F ALCATEL BUSINESS SYSTEMS -0080A0 EDISA HEWLETT PACKARD S/A -0080A1 MICROTEST, INC. -0080A2 CREATIVE ELECTRONIC SYSTEMS -0080A3 LANTRONIX -0080A4 LIBERTY ELECTRONICS -0080A5 SPEED INTERNATIONAL -0080A6 REPUBLIC TECHNOLOGY, INC. -0080A7 MEASUREX CORP. -0080A8 VITACOM CORPORATION -0080A9 CLEARPOINT RESEARCH -0080AA MAXPEED -0080AB DUKANE NETWORK INTEGRATION -0080AC IMLOGIX, DIVISION OF GENESYS -0080AD CNET TECHNOLOGY, INC. -0080AE HUGHES NETWORK SYSTEMS -0080AF ALLUMER CO., LTD. -0080B0 ADVANCED INFORMATION -0080B1 SOFTCOM A/S -0080B2 NETWORK EQUIPMENT TECHNOLOGIES -0080B3 AVAL DATA CORPORATION -0080B4 SOPHIA SYSTEMS -0080B5 UNITED NETWORKS INC. -0080B6 THEMIS COMPUTER -0080B7 STELLAR COMPUTER -0080B8 BUG, INCORPORATED -0080B9 ARCHE TECHNOLIGIES INC. -0080BA SPECIALIX (ASIA) PTE, LTD -0080BB HUGHES LAN SYSTEMS -0080BC HITACHI ENGINEERING CO., LTD -0080BD THE FURUKAWA ELECTRIC CO., LTD -0080BE ARIES RESEARCH -0080BF TAKAOKA ELECTRIC MFG. CO. LTD. -0080C0 PENRIL DATACOMM -0080C1 LANEX CORPORATION -0080C2 IEEE 802.1 COMMITTEE -0080C3 BICC INFORMATION SYSTEMS & SVC -0080C4 DOCUMENT TECHNOLOGIES, INC. -0080C5 NOVELLCO DE MEXICO -0080C6 NATIONAL DATACOMM CORPORATION -0080C7 XIRCOM -0080C8 D-LINK SYSTEMS, INC. -0080C9 ALBERTA MICROELECTRONIC CENTRE -0080CA NETCOM RESEARCH INCORPORATED -0080CB FALCO DATA PRODUCTS -0080CC MICROWAVE BYPASS SYSTEMS -0080CD MICRONICS COMPUTER, INC. -0080CE BROADCAST TELEVISION SYSTEMS -0080CF EMBEDDED PERFORMANCE INC. -0080D0 COMPUTER PERIPHERALS, INC. -0080D1 KIMTRON CORPORATION -0080D2 SHINNIHONDENKO CO., LTD. -0080D3 SHIVA CORP. -0080D4 CHASE RESEARCH LTD. -0080D5 CADRE TECHNOLOGIES -0080D6 NUVOTECH, INC. -0080D7 Fantum Engineering -0080D8 NETWORK PERIPHERALS INC. -0080D9 EMK ELEKTRONIK -0080DA BRUEL & KJAER -0080DB GRAPHON CORPORATION -0080DC PICKER INTERNATIONAL -0080DD GMX INC/GIMIX -0080DE GIPSI S.A. -0080DF ADC CODENOLL TECHNOLOGY CORP. -0080E0 XTP SYSTEMS, INC. -0080E1 STMICROELECTRONICS -0080E2 T.D.I. CO., LTD. -0080E3 CORAL NETWORK CORPORATION -0080E4 NORTHWEST DIGITAL SYSTEMS, INC -0080E5 MYLEX CORPORATION -0080E6 PEER NETWORKS, INC. -0080E7 LYNWOOD SCIENTIFIC DEV. LTD. -0080E8 CUMULUS CORPORATIION -0080E9 Madge Ltd. -0080EA ADVA Optical Networking Ltd. -0080EB COMPCONTROL B.V. -0080EC SUPERCOMPUTING SOLUTIONS, INC. -0080ED IQ TECHNOLOGIES, INC. -0080EE THOMSON CSF -0080EF RATIONAL -0080F0 Panasonic Communications Co., Ltd. -0080F1 OPUS SYSTEMS -0080F2 RAYCOM SYSTEMS INC -0080F3 SUN ELECTRONICS CORP. -0080F4 TELEMECANIQUE ELECTRIQUE -0080F5 QUANTEL LTD -0080F6 SYNERGY MICROSYSTEMS -0080F7 ZENITH ELECTRONICS -0080F8 MIZAR, INC. -0080F9 HEURIKON CORPORATION -0080FA RWT GMBH -0080FB BVM LIMITED -0080FC AVATAR CORPORATION -0080FD EXSCEED CORPRATION -0080FE AZURE TECHNOLOGIES, INC. -0080FF SOC. DE TELEINFORMATIQUE RTC -009000 DIAMOND MULTIMEDIA -009001 NISHIMU ELECTRONICS INDUSTRIES CO., LTD. -009002 ALLGON AB -009003 APLIO -009004 3COM EUROPE LTD. -009005 PROTECH SYSTEMS CO., LTD. -009006 HAMAMATSU PHOTONICS K.K. -009007 DOMEX TECHNOLOGY CORP. -009008 HanA Systems Inc. -009009 i Controls, Inc. -00900A PROTON ELECTRONIC INDUSTRIAL CO., LTD. -00900B LANNER ELECTRONICS, INC. -00900C CISCO SYSTEMS, INC. -00900D OVERLAND DATA INC. -00900E HANDLINK TECHNOLOGIES, INC. -00900F KAWASAKI HEAVY INDUSTRIES, LTD -009010 SIMULATION LABORATORIES, INC. -009011 WAVTrace, Inc. -009012 GLOBESPAN SEMICONDUCTOR, INC. -009013 SAMSAN CORP. -009014 ROTORK INSTRUMENTS, LTD. -009015 CENTIGRAM COMMUNICATIONS CORP. -009016 ZAC -009017 ZYPCOM, INC. -009018 ITO ELECTRIC INDUSTRY CO, LTD. -009019 HERMES ELECTRONICS CO., LTD. -00901A UNISPHERE SOLUTIONS -00901B DIGITAL CONTROLS -00901C mps Software Gmbh -00901D PEC (NZ) LTD. -00901E SELESTA INGEGNE RIA S.P.A. -00901F ADTEC PRODUCTIONS, INC. -009020 PHILIPS ANALYTICAL X-RAY B.V. -009021 CISCO SYSTEMS, INC. -009022 IVEX -009023 ZILOG INC. -009024 PIPELINKS, INC. -009025 VISION SYSTEMS LTD. PTY -009026 ADVANCED SWITCHING COMMUNICATIONS, INC. -009027 INTEL CORPORATION -009028 NIPPON SIGNAL CO., LTD. -009029 CRYPTO AG -00902A COMMUNICATION DEVICES, INC. -00902B CISCO SYSTEMS, INC. -00902C DATA & CONTROL EQUIPMENT LTD. -00902D DATA ELECTRONICS (AUST.) PTY, LTD. -00902E NAMCO LIMITED -00902F NETCORE SYSTEMS, INC. -009030 HONEYWELL-DATING -009031 MYSTICOM, LTD. -009032 PELCOMBE GROUP LTD. -009033 INNOVAPHONE GmbH -009034 IMAGIC, INC. -009035 ALPHA TELECOM, INC. -009036 ens, inc. -009037 ACUCOMM, INC. -009038 FOUNTAIN TECHNOLOGIES, INC. -009039 SHASTA NETWORKS -00903A NIHON MEDIA TOOL INC. -00903B TriEMS Research Lab, Inc. -00903C ATLANTIC NETWORK SYSTEMS -00903D BIOPAC SYSTEMS, INC. -00903E N.V. PHILIPS INDUSTRIAL ACTIVITIES -00903F AZTEC RADIOMEDIA -009040 Siemens Network Convergence LLC -009041 APPLIED DIGITAL ACCESS -009042 ECCS, Inc. -009043 NICHIBEI DENSHI CO., LTD. -009044 ASSURED DIGITAL, INC. -009045 Marconi Communications -009046 DEXDYNE, LTD. -009047 GIGA FAST E. LTD. -009048 ZEAL CORPORATION -009049 ENTRIDIA CORPORATION -00904A CONCUR SYSTEM TECHNOLOGIES -00904B GemTek Technology Co., Ltd. -00904C EPIGRAM, INC. -00904D SPEC S.A. -00904E DELEM BV -00904F ABB POWER T&D COMPANY, INC. -009050 TELESTE OY -009051 ULTIMATE TECHNOLOGY CORP. -009052 SELCOM ELETTRONICA S.R.L. -009053 DAEWOO ELECTRONICS CO., LTD. -009054 INNOVATIVE SEMICONDUCTORS, INC -009055 PARKER HANNIFIN CORPORATION COMPUMOTOR DIVISION -009056 TELESTREAM, INC. -009057 AANetcom, Inc. -009058 Ultra Electronics Ltd., Command and Control Systems -009059 TELECOM DEVICE K.K. -00905A DEARBORN GROUP, INC. -00905B RAYMOND AND LAE ENGINEERING -00905C EDMI -00905D NETCOM SICHERHEITSTECHNIK GmbH -00905E RAULAND-BORG CORPORATION -00905F CISCO SYSTEMS, INC. -009060 SYSTEM CREATE CORP. -009061 PACIFIC RESEARCH & ENGINEERING CORPORATION -009062 ICP VORTEX COMPUTERSYSTEME GmbH -009063 COHERENT COMMUNICATIONS SYSTEMS CORPORATION -009064 THOMSON BROADCAST SYSTEMS -009065 FINISAR CORPORATION -009066 Troika Networks, Inc. -009067 WalkAbout Computers, Inc. -009068 DVT CORP. -009069 JUNIPER NETWORKS, INC. -00906A TURNSTONE SYSTEMS, INC. -00906B APPLIED RESOURCES, INC. -00906C GWT GLOBAL WEIGHING TECHNOLOGIES GmbH -00906D CISCO SYSTEMS, INC. -00906E PRAXON, INC. -00906F CISCO SYSTEMS, INC. -009070 NEO NETWORKS, INC. -009071 Applied Innovation Inc. -009072 SIMRAD AS -009073 GAIO TECHNOLOGY -009074 ARGON NETWORKS, INC. -009075 NEC DO BRASIL S.A. -009076 FMT AIRCRAFT GATE SUPPORT SYSTEMS AB -009077 ADVANCED FIBRE COMMUNICATIONS -009078 MER TELEMANAGEMENT SOLUTIONS, LTD. -009079 ClearOne, Inc. -00907A SPECTRALINK CORP. -00907B E-TECH, INC. -00907C DIGITALCAST, INC. -00907D Lake Communications -00907E VETRONIX CORP. -00907F WatchGuard Technologies, Inc. -009080 NOT LIMITED, INC. -009081 ALOHA NETWORKS, INC. -009082 FORCE INSTITUTE -009083 TURBO COMMUNICATION, INC. -009084 ATECH SYSTEM -009085 GOLDEN ENTERPRISES, INC. -009086 CISCO SYSTEMS, INC. -009087 ITIS -009088 BAXALL SECURITY LTD. -009089 SOFTCOM MICROSYSTEMS, INC. -00908A BAYLY COMMUNICATIONS, INC. -00908B CELL COMPUTING, INC. -00908C ETREND ELECTRONICS, INC. -00908D VICKERS ELECTRONICS SYSTEMS -00908E Nortel Networks Broadband Access -00908F AUDIO CODES LTD. -009090 I-BUS -009091 DigitalScape, Inc. -009092 CISCO SYSTEMS, INC. -009093 NANAO CORPORATION -009094 OSPREY TECHNOLOGIES, INC. -009095 UNIVERSAL AVIONICS -009096 ASKEY COMPUTER CORP. -009097 SYCAMORE NETWORKS -009098 SBC DESIGNS, INC. -009099 ALLIED TELESIS, K.K. -00909A ONE WORLD SYSTEMS, INC. -00909B MARKPOINT AB -00909C Terayon Communications Systems -00909D GSE SYSTEMS, INC. -00909E Critical IO, LLC -00909F DIGI-DATA CORPORATION -0090A0 8X8 INC. -0090A1 FLYING PIG SYSTEMS, LTD. -0090A2 CYBERTAN TECHNOLOGY, INC. -0090A3 Corecess Inc. -0090A4 ALTIGA NETWORKS -0090A5 SPECTRA LOGIC -0090A6 CISCO SYSTEMS, INC. -0090A7 CLIENTEC CORPORATION -0090A8 NineTiles Networks, Ltd. -0090A9 WESTERN DIGITAL -0090AA INDIGO ACTIVE VISION SYSTEMS LIMITED -0090AB CISCO SYSTEMS, INC. -0090AC OPTIVISION, INC. -0090AD ASPECT ELECTRONICS, INC. -0090AE ITALTEL S.p.A. -0090AF J. MORITA MFG. CORP. -0090B0 VADEM -0090B1 CISCO SYSTEMS, INC. -0090B2 AVICI SYSTEMS INC. -0090B3 AGRANAT SYSTEMS -0090B4 WILLOWBROOK TECHNOLOGIES -0090B5 NIKON CORPORATION -0090B6 FIBEX SYSTEMS -0090B7 DIGITAL LIGHTWAVE, INC. -0090B8 ROHDE & SCHWARZ GMBH & CO. KG -0090B9 BERAN INSTRUMENTS LTD. -0090BA VALID NETWORKS, INC. -0090BB TAINET COMMUNICATION SYSTEM Corp. -0090BC TELEMANN CO., LTD. -0090BD OMNIA COMMUNICATIONS, INC. -0090BE IBC/INTEGRATED BUSINESS COMPUTERS -0090BF CISCO SYSTEMS, INC. -0090C0 K.J. LAW ENGINEERS, INC. -0090C1 Peco II, Inc. -0090C2 JK microsystems, Inc. -0090C3 TOPIC SEMICONDUCTOR CORP. -0090C4 JAVELIN SYSTEMS, INC. -0090C5 INTERNET MAGIC, INC. -0090C6 OPTIM SYSTEMS, INC. -0090C7 ICOM INC. -0090C8 WAVERIDER COMMUNICATIONS (CANADA) INC. -0090C9 DPAC Technologies -0090CA ACCORD VIDEO TELECOMMUNICATIONS, LTD. -0090CB Wireless OnLine, Inc. -0090CC PLANET COMMUNICATIONS, INC. -0090CD ENT-EMPRESA NACIONAL DE TELECOMMUNICACOES, S.A. -0090CE TETRA GmbH -0090CF NORTEL -0090D0 Thomson Belgium -0090D1 LEICHU ENTERPRISE CO., LTD. -0090D2 ARTEL VIDEO SYSTEMS -0090D3 GIESECKE & DEVRIENT GmbH -0090D4 BindView Development Corp. -0090D5 EUPHONIX, INC. -0090D6 CRYSTAL GROUP -0090D7 NetBoost Corp. -0090D8 WHITECROSS SYSTEMS -0090D9 CISCO SYSTEMS, INC. -0090DA DYNARC, INC. -0090DB NEXT LEVEL COMMUNICATIONS -0090DC TECO INFORMATION SYSTEMS -0090DD THE MIHARU COMMUNICATIONS CO., LTD. -0090DE CARDKEY SYSTEMS, INC. -0090DF MITSUBISHI CHEMICAL AMERICA, INC. -0090E0 SYSTRAN CORP. -0090E1 TELENA S.P.A. -0090E2 DISTRIBUTED PROCESSING TECHNOLOGY -0090E3 AVEX ELECTRONICS INC. -0090E4 NEC AMERICA, INC. -0090E5 TEKNEMA, INC. -0090E6 ACER LABORATORIES, INC. -0090E7 HORSCH ELEKTRONIK AG -0090E8 MOXA TECHNOLOGIES CORP., LTD. -0090E9 JANZ COMPUTER AG -0090EA ALPHA TECHNOLOGIES, INC. -0090EB SENTRY TELECOM SYSTEMS -0090EC PYRESCOM -0090ED CENTRAL SYSTEM RESEARCH CO., LTD. -0090EE PERSONAL COMMUNICATIONS TECHNOLOGIES -0090EF INTEGRIX, INC. -0090F0 HARMONIC LIGHTWAVES, LTD. -0090F1 DOT HILL SYSTEMS CORPORATION -0090F2 CISCO SYSTEMS, INC. -0090F3 ASPECT COMMUNICATIONS -0090F4 LIGHTNING INSTRUMENTATION -0090F5 CLEVO CO. -0090F6 ESCALATE NETWORKS, INC. -0090F7 NBASE COMMUNICATIONS LTD. -0090F8 MEDIATRIX TELECOM -0090F9 LEITCH -0090FA GigaNet, Inc. -0090FB PORTWELL, INC. -0090FC NETWORK COMPUTING DEVICES -0090FD CopperCom, Inc. -0090FE ELECOM CO., LTD. (LANEED DIV.) -0090FF TELLUS TECHNOLOGY INC. -0091D6 Crystal Group, Inc. -009D8E CARDIAC RECORDERS, INC. -00A000 CENTILLION NETWORKS, INC. -00A001 WATKINS-JOHNSON COMPANY -00A002 LEEDS & NORTHRUP AUSTRALIA PTY LTD -00A003 STAEFA CONTROL SYSTEM -00A004 NETPOWER, INC. -00A005 DANIEL INSTRUMENTS, LTD. -00A006 IMAGE DATA PROCESSING SYSTEM GROUP -00A007 APEXX TECHNOLOGY, INC. -00A008 NETCORP -00A009 WHITETREE NETWORK -00A00A R.D.C. COMMUNICATION -00A00B COMPUTEX CO., LTD. -00A00C KINGMAX TECHNOLOGY, INC. -00A00D THE PANDA PROJECT -00A00E VISUAL NETWORKS, INC. -00A00F Broadband Technologies -00A010 SYSLOGIC DATENTECHNIK AG -00A011 MUTOH INDUSTRIES LTD. -00A012 B.A.T.M. ADVANCED TECHNOLOGIES -00A013 TELTREND LTD. -00A014 CSIR -00A015 WYLE -00A016 MICROPOLIS CORP. -00A017 J B M CORPORATION -00A018 CREATIVE CONTROLLERS, INC. -00A019 NEBULA CONSULTANTS, INC. -00A01A BINAR ELEKTRONIK AB -00A01B PREMISYS COMMUNICATIONS, INC. -00A01C NASCENT NETWORKS CORPORATION -00A01D SIXNET -00A01E EST CORPORATION -00A01F TRICORD SYSTEMS, INC. -00A020 CITICORP/TTI -00A021 GENERAL DYNAMICS- -00A022 CENTRE FOR DEVELOPMENT OF ADVANCED COMPUTING -00A023 APPLIED CREATIVE TECHNOLOGY, INC. -00A024 3COM CORPORATION -00A025 REDCOM LABS INC. -00A026 TELDAT, S.A. -00A027 FIREPOWER SYSTEMS, INC. -00A028 CONNER PERIPHERALS -00A029 COULTER CORPORATION -00A02A TRANCELL SYSTEMS -00A02B TRANSITIONS RESEARCH CORP. -00A02C interWAVE Communications -00A02D 1394 Trade Association -00A02E BRAND COMMUNICATIONS, LTD. -00A02F PIRELLI CAVI -00A030 CAPTOR NV/SA -00A031 HAZELTINE CORPORATION, MS 1-17 -00A032 GES SINGAPORE PTE. LTD. -00A033 imc MeBsysteme GmbH -00A034 AXEL -00A035 CYLINK CORPORATION -00A036 APPLIED NETWORK TECHNOLOGY -00A037 DATASCOPE CORPORATION -00A038 EMAIL ELECTRONICS -00A039 ROSS TECHNOLOGY, INC. -00A03A KUBOTEK CORPORATION -00A03B TOSHIN ELECTRIC CO., LTD. -00A03C EG&G NUCLEAR INSTRUMENTS -00A03D OPTO-22 -00A03E ATM FORUM -00A03F COMPUTER SOCIETY MICROPROCESSOR & MICROPROCESSOR STANDARDS C -00A040 APPLE COMPUTER -00A041 LEYBOLD-INFICON -00A042 SPUR PRODUCTS CORP. -00A043 AMERICAN TECHNOLOGY LABS, INC. -00A044 NTT IT CO., LTD. -00A045 PHOENIX CONTACT GMBH & CO. -00A046 SCITEX CORP. LTD. -00A047 INTEGRATED FITNESS CORP. -00A048 QUESTECH, LTD. -00A049 DIGITECH INDUSTRIES, INC. -00A04A NISSHIN ELECTRIC CO., LTD. -00A04B TFL LAN INC. -00A04C INNOVATIVE SYSTEMS & TECHNOLOGIES, INC. -00A04D EDA INSTRUMENTS, INC. -00A04E VOELKER TECHNOLOGIES, INC. -00A04F AMERITEC CORP. -00A050 CYPRESS SEMICONDUCTOR -00A051 ANGIA COMMUNICATIONS. INC. -00A052 STANILITE ELECTRONICS PTY. LTD -00A053 COMPACT DEVICES, INC. -00A055 Data Device Corporation -00A056 MICROPROSS -00A057 LANCOM Systems GmbH -00A058 GLORY, LTD. -00A059 HAMILTON HALLMARK -00A05A KOFAX IMAGE PRODUCTS -00A05B MARQUIP, INC. -00A05C INVENTORY CONVERSION, INC./ -00A05D CS COMPUTER SYSTEME GmbH -00A05E MYRIAD LOGIC INC. -00A05F BTG ENGINEERING BV -00A060 ACER PERIPHERALS, INC. -00A061 PURITAN BENNETT -00A062 AES PRODATA -00A063 JRL SYSTEMS, INC. -00A064 KVB/ANALECT -00A065 NEXLAND, INC. -00A066 ISA CO., LTD. -00A067 NETWORK SERVICES GROUP -00A068 BHP LIMITED -00A069 Symmetricom, Inc. -00A06A Verilink Corporation -00A06B DMS DORSCH MIKROSYSTEM GMBH -00A06C SHINDENGEN ELECTRIC MFG. CO., LTD. -00A06D MANNESMANN TALLY CORPORATION -00A06E AUSTRON, INC. -00A06F THE APPCON GROUP, INC. -00A070 COASTCOM -00A071 VIDEO LOTTERY TECHNOLOGIES,INC -00A072 OVATION SYSTEMS LTD. -00A073 COM21, INC. -00A074 PERCEPTION TECHNOLOGY -00A075 MICRON TECHNOLOGY, INC. -00A076 CARDWARE LAB, INC. -00A077 FUJITSU NEXION, INC. -00A078 Marconi Communications -00A079 ALPS ELECTRIC (USA), INC. -00A07A ADVANCED PERIPHERALS TECHNOLOGIES, INC. -00A07B DAWN COMPUTER INCORPORATION -00A07C TONYANG NYLON CO., LTD. -00A07D SEEQ TECHNOLOGY, INC. -00A07E AVID TECHNOLOGY, INC. -00A07F GSM-SYNTEL, LTD. -00A080 ANTARES MICROSYSTEMS -00A081 ALCATEL DATA NETWORKS -00A082 NKT ELEKTRONIK A/S -00A083 ASIMMPHONY TURKEY -00A084 DATAPLEX PTY. LTD. -00A086 AMBER WAVE SYSTEMS, INC. -00A087 Zarlink Semiconductor Ltd. -00A088 ESSENTIAL COMMUNICATIONS -00A089 XPOINT TECHNOLOGIES, INC. -00A08A BROOKTROUT TECHNOLOGY, INC. -00A08B ASTON ELECTRONIC DESIGNS LTD. -00A08C MultiMedia LANs, Inc. -00A08D JACOMO CORPORATION -00A08E Nokia Internet Communications -00A08F DESKNET SYSTEMS, INC. -00A090 TimeStep Corporation -00A091 APPLICOM INTERNATIONAL -00A092 H. BOLLMANN MANUFACTURERS, LTD -00A093 B/E AEROSPACE, Inc. -00A094 COMSAT CORPORATION -00A095 ACACIA NETWORKS, INC. -00A096 MITUMI ELECTRIC CO., LTD. -00A097 JC INFORMATION SYSTEMS -00A098 NETWORK APPLIANCE CORP. -00A099 K-NET LTD. -00A09A NIHON KOHDEN AMERICA -00A09B QPSX COMMUNICATIONS, LTD. -00A09C Xyplex, Inc. -00A09D JOHNATHON FREEMAN TECHNOLOGIES -00A09E ICTV -00A09F COMMVISION CORP. -00A0A0 COMPACT DATA, LTD. -00A0A1 EPIC DATA INC. -00A0A2 DIGICOM S.P.A. -00A0A3 RELIABLE POWER METERS -00A0A4 MICROS SYSTEMS, INC. -00A0A5 TEKNOR MICROSYSTEME, INC. -00A0A6 M.I. SYSTEMS, K.K. -00A0A7 VORAX CORPORATION -00A0A8 RENEX CORPORATION -00A0A9 GN NETTEST (CANADA) NAVTEL DIVISION -00A0AA SPACELABS MEDICAL -00A0AB NETCS INFORMATIONSTECHNIK GMBH -00A0AC GILAT SATELLITE NETWORKS, LTD. -00A0AD MARCONI SPA -00A0AE NUCOM SYSTEMS, INC. -00A0AF WMS INDUSTRIES -00A0B0 I-O DATA DEVICE, INC. -00A0B1 FIRST VIRTUAL CORPORATION -00A0B2 SHIMA SEIKI -00A0B3 ZYKRONIX -00A0B4 TEXAS MICROSYSTEMS, INC. -00A0B5 3H TECHNOLOGY -00A0B6 SANRITZ AUTOMATION CO., LTD. -00A0B7 CORDANT, INC. -00A0B8 SYMBIOS LOGIC INC. -00A0B9 EAGLE TECHNOLOGY, INC. -00A0BA PATTON ELECTRONICS CO. -00A0BB HILAN GMBH -00A0BC VIASAT, INCORPORATED -00A0BD I-TECH CORP. -00A0BE INTEGRATED CIRCUIT SYSTEMS, INC. COMMUNICATIONS GROUP -00A0BF WIRELESS DATA GROUP MOTOROLA -00A0C0 DIGITAL LINK CORP. -00A0C1 ORTIVUS MEDICAL AB -00A0C2 R.A. SYSTEMS CO., LTD. -00A0C3 UNICOMPUTER GMBH -00A0C4 CRISTIE ELECTRONICS LTD. -00A0C5 ZYXEL COMMUNICATION -00A0C6 QUALCOMM INCORPORATED -00A0C7 TADIRAN TELECOMMUNICATIONS -00A0C8 ADTRAN INC. -00A0C9 INTEL CORPORATION - HF1-06 -00A0CA FUJITSU DENSO LTD. -00A0CB ARK TELECOMMUNICATIONS, INC. -00A0CC LITE-ON COMMUNICATIONS, INC. -00A0CD DR. JOHANNES HEIDENHAIN GmbH -00A0CE ASTROCOM CORPORATION -00A0CF SOTAS, INC. -00A0D0 TEN X TECHNOLOGY, INC. -00A0D1 INVENTEC CORPORATION -00A0D2 ALLIED TELESIS INTERNATIONAL CORPORATION -00A0D3 INSTEM COMPUTER SYSTEMS, LTD. -00A0D4 RADIOLAN, INC. -00A0D5 SIERRA WIRELESS INC. -00A0D6 SBE, INC. -00A0D7 KASTEN CHASE APPLIED RESEARCH -00A0D8 SPECTRA - TEK -00A0D9 CONVEX COMPUTER CORPORATION -00A0DA INTEGRATED SYSTEMS Technology, Inc. -00A0DB FISHER & PAYKEL PRODUCTION -00A0DC O.N. ELECTRONIC CO., LTD. -00A0DD AZONIX CORPORATION -00A0DE YAMAHA CORPORATION -00A0DF STS TECHNOLOGIES, INC. -00A0E0 TENNYSON TECHNOLOGIES PTY LTD -00A0E1 WESTPORT RESEARCH ASSOCIATES, INC. -00A0E2 KEISOKU GIKEN CORP. -00A0E3 XKL SYSTEMS CORP. -00A0E4 OPTIQUEST -00A0E5 NHC COMMUNICATIONS -00A0E6 DIALOGIC CORPORATION -00A0E7 CENTRAL DATA CORPORATION -00A0E8 REUTERS HOLDINGS PLC -00A0E9 ELECTRONIC RETAILING SYSTEMS INTERNATIONAL -00A0EA ETHERCOM CORP. -00A0EB Encore Networks -00A0EC TRANSMITTON LTD. -00A0ED PRI AUTOMATION -00A0EE NASHOBA NETWORKS -00A0EF LUCIDATA LTD. -00A0F0 TORONTO MICROELECTRONICS INC. -00A0F1 MTI -00A0F2 INFOTEK COMMUNICATIONS, INC. -00A0F3 STAUBLI -00A0F4 GE -00A0F5 RADGUARD LTD. -00A0F6 AutoGas Systems Inc. -00A0F7 V.I COMPUTER CORP. -00A0F8 SYMBOL TECHNOLOGIES, INC. -00A0F9 BINTEC COMMUNICATIONS GMBH -00A0FA Marconi Communication GmbH -00A0FB TORAY ENGINEERING CO., LTD. -00A0FC IMAGE SCIENCES, INC. -00A0FD SCITEX DIGITAL PRINTING, INC. -00A0FE BOSTON TECHNOLOGY, INC. -00A0FF TELLABS OPERATIONS, INC. -00AA00 INTEL CORPORATION -00AA01 INTEL CORPORATION -00AA02 INTEL CORPORATION -00AA3C OLIVETTI TELECOM SPA (OLTECO) -00B009 Grass Valley Group -00B017 InfoGear Technology Corp. -00B019 Casi-Rusco -00B01C Westport Technologies -00B01E Rantic Labs, Inc. -00B02A ORSYS GmbH -00B02D ViaGate Technologies, Inc. -00B03B HiQ Networks -00B048 Marconi Communications Inc. -00B04A Cisco Systems, Inc. -00B052 Intellon Corporation -00B064 Cisco Systems, Inc. -00B069 Honewell Oy -00B06D Jones Futurex Inc. -00B080 Mannesmann Ipulsys B.V. -00B086 LocSoft Limited -00B08E Cisco Systems, Inc. -00B091 Transmeta Corp. -00B094 Alaris, Inc. -00B09A Morrow Technologies Corp. -00B09D Point Grey Research Inc. -00B0AC SIAE-Microelettronica S.p.A. -00B0AE Symmetricom -00B0B3 Xstreamis PLC -00B0C2 Cisco Systems, Inc. -00B0C7 Tellabs Operations, Inc. -00B0CE TECHNOLOGY RESCUE -00B0D0 Dell Computer Corp. -00B0DB Nextcell, Inc. -00B0DF Reliable Data Technology, Inc. -00B0E7 British Federal Ltd. -00B0EC EACEM -00B0EE Ajile Systems, Inc. -00B0F0 CALY NETWORKS -00B0F5 NetWorth Technologies, Inc. -00BB01 OCTOTHORPE CORP. -00BBF0 UNGERMANN-BASS INC. -00C000 LANOPTICS, LTD. -00C001 DIATEK PATIENT MANAGMENT -00C002 SERCOMM CORPORATION -00C003 GLOBALNET COMMUNICATIONS -00C004 JAPAN BUSINESS COMPUTER CO.LTD -00C005 LIVINGSTON ENTERPRISES, INC. -00C006 NIPPON AVIONICS CO., LTD. -00C007 PINNACLE DATA SYSTEMS, INC. -00C008 SECO SRL -00C009 KT TECHNOLOGY (S) PTE LTD -00C00A MICRO CRAFT -00C00B NORCONTROL A.S. -00C00C RELIA TECHNOLGIES -00C00D ADVANCED LOGIC RESEARCH, INC. -00C00E PSITECH, INC. -00C00F QUANTUM SOFTWARE SYSTEMS LTD. -00C010 HIRAKAWA HEWTECH CORP. -00C011 INTERACTIVE COMPUTING DEVICES -00C012 NETSPAN CORPORATION -00C013 NETRIX -00C014 TELEMATICS CALABASAS INT'L,INC -00C015 NEW MEDIA CORPORATION -00C016 ELECTRONIC THEATRE CONTROLS -00C017 FORTE NETWORKS -00C018 LANART CORPORATION -00C019 LEAP TECHNOLOGY, INC. -00C01A COROMETRICS MEDICAL SYSTEMS -00C01B SOCKET COMMUNICATIONS, INC. -00C01C INTERLINK COMMUNICATIONS LTD. -00C01D GRAND JUNCTION NETWORKS, INC. -00C01E LA FRANCAISE DES JEUX -00C01F S.E.R.C.E.L. -00C020 ARCO ELECTRONIC, CONTROL LTD. -00C021 NETEXPRESS -00C022 LASERMASTER TECHNOLOGIES, INC. -00C023 TUTANKHAMON ELECTRONICS -00C024 EDEN SISTEMAS DE COMPUTACAO SA -00C025 DATAPRODUCTS CORPORATION -00C026 LANS TECHNOLOGY CO., LTD. -00C027 CIPHER SYSTEMS, INC. -00C028 JASCO CORPORATION -00C029 Nexans Deutschland AG - ANS -00C02A OHKURA ELECTRIC CO., LTD. -00C02B GERLOFF GESELLSCHAFT FUR -00C02C CENTRUM COMMUNICATIONS, INC. -00C02D FUJI PHOTO FILM CO., LTD. -00C02E NETWIZ -00C02F OKUMA CORPORATION -00C030 INTEGRATED ENGINEERING B. V. -00C031 DESIGN RESEARCH SYSTEMS, INC. -00C032 I-CUBED LIMITED -00C033 TELEBIT COMMUNICATIONS APS -00C034 TRANSACTION NETWORK -00C035 QUINTAR COMPANY -00C036 RAYTECH ELECTRONIC CORP. -00C037 DYNATEM -00C038 RASTER IMAGE PROCESSING SYSTEM -00C039 TDK SEMICONDUCTOR CORPORATION -00C03A MEN-MIKRO ELEKTRONIK GMBH -00C03B MULTIACCESS COMPUTING CORP. -00C03C TOWER TECH S.R.L. -00C03D WIESEMANN & THEIS GMBH -00C03E FA. GEBR. HELLER GMBH -00C03F STORES AUTOMATED SYSTEMS, INC. -00C040 ECCI -00C041 DIGITAL TRANSMISSION SYSTEMS -00C042 DATALUX CORP. -00C043 STRATACOM -00C044 EMCOM CORPORATION -00C045 ISOLATION SYSTEMS, LTD. -00C046 KEMITRON LTD. -00C047 UNIMICRO SYSTEMS, INC. -00C048 BAY TECHNICAL ASSOCIATES -00C049 U.S. ROBOTICS, INC. -00C04A GROUP 2000 AG -00C04B CREATIVE MICROSYSTEMS -00C04C DEPARTMENT OF FOREIGN AFFAIRS -00C04D MITEC, INC. -00C04E COMTROL CORPORATION -00C04F DELL COMPUTER CORPORATION -00C050 TOYO DENKI SEIZO K.K. -00C051 ADVANCED INTEGRATION RESEARCH -00C052 BURR-BROWN -00C053 DAVOX CORPORATION -00C054 NETWORK PERIPHERALS, LTD. -00C055 MODULAR COMPUTING TECHNOLOGIES -00C056 SOMELEC -00C057 MYCO ELECTRONICS -00C058 DATAEXPERT CORP. -00C059 NIPPON DENSO CO., LTD. -00C05A SEMAPHORE COMMUNICATIONS CORP. -00C05B NETWORKS NORTHWEST, INC. -00C05C ELONEX PLC -00C05D L&N TECHNOLOGIES -00C05E VARI-LITE, INC. -00C05F FINE-PAL COMPANY LIMITED -00C060 ID SCANDINAVIA AS -00C061 SOLECTEK CORPORATION -00C062 IMPULSE TECHNOLOGY -00C063 MORNING STAR TECHNOLOGIES, INC -00C064 GENERAL DATACOMM IND. INC. -00C065 SCOPE COMMUNICATIONS, INC. -00C066 DOCUPOINT, INC. -00C067 UNITED BARCODE INDUSTRIES -00C068 PHILIP DRAKE ELECTRONICS LTD. -00C069 Axxcelera Broadband Wireless -00C06A ZAHNER-ELEKTRIK GMBH & CO. KG -00C06B OSI PLUS CORPORATION -00C06C SVEC COMPUTER CORP. -00C06D BOCA RESEARCH, INC. -00C06E HAFT TECHNOLOGY, INC. -00C06F KOMATSU LTD. -00C070 SECTRA SECURE-TRANSMISSION AB -00C071 AREANEX COMMUNICATIONS, INC. -00C072 KNX LTD. -00C073 XEDIA CORPORATION -00C074 TOYODA AUTOMATIC LOOM -00C075 XANTE CORPORATION -00C076 I-DATA INTERNATIONAL A-S -00C077 DAEWOO TELECOM LTD. -00C078 COMPUTER SYSTEMS ENGINEERING -00C079 FONSYS CO.,LTD. -00C07A PRIVA B.V. -00C07B ASCEND COMMUNICATIONS, INC. -00C07C HIGHTECH INFORMATION -00C07D RISC DEVELOPMENTS LTD. -00C07E KUBOTA CORPORATION ELECTRONIC -00C07F NUPON COMPUTING CORP. -00C080 NETSTAR, INC. -00C081 METRODATA LTD. -00C082 MOORE PRODUCTS CO. -00C083 TRACE MOUNTAIN PRODUCTS, INC. -00C084 DATA LINK CORP. LTD. -00C085 ELECTRONICS FOR IMAGING, INC. -00C086 THE LYNK CORPORATION -00C087 UUNET TECHNOLOGIES, INC. -00C088 EKF ELEKTRONIK GMBH -00C089 TELINDUS DISTRIBUTION -00C08A LAUTERBACH DATENTECHNIK GMBH -00C08B RISQ MODULAR SYSTEMS, INC. -00C08C PERFORMANCE TECHNOLOGIES, INC. -00C08D TRONIX PRODUCT DEVELOPMENT -00C08E NETWORK INFORMATION TECHNOLOGY -00C08F MATSUSHITA ELECTRIC WORKS, LTD -00C090 PRAIM S.R.L. -00C091 JABIL CIRCUIT, INC. -00C092 MENNEN MEDICAL INC. -00C093 ALTA RESEARCH CORP. -00C094 VMX INC. -00C095 ZNYX -00C096 TAMURA CORPORATION -00C097 ARCHIPEL SA -00C098 CHUNTEX ELECTRONIC CO., LTD. -00C099 YOSHIKI INDUSTRIAL CO.,LTD. -00C09A PHOTONICS CORPORATION -00C09B RELIANCE COMM/TEC, R-TEC -00C09C TOA ELECTRONIC LTD. -00C09D DISTRIBUTED SYSTEMS INT'L, INC -00C09E CACHE COMPUTERS, INC. -00C09F QUANTA COMPUTER, INC. -00C0A0 ADVANCE MICRO RESEARCH, INC. -00C0A1 TOKYO DENSHI SEKEI CO. -00C0A2 INTERMEDIUM A/S -00C0A3 DUAL ENTERPRISES CORPORATION -00C0A4 UNIGRAF OY -00C0A5 DICKENS DATA SYSTEMS -00C0A6 EXICOM AUSTRALIA PTY. LTD -00C0A7 SEEL LTD. -00C0A8 GVC CORPORATION -00C0A9 BARRON MCCANN LTD. -00C0AA SILICON VALLEY COMPUTER -00C0AB Telco Systems, Inc. -00C0AC GAMBIT COMPUTER COMMUNICATIONS -00C0AD MARBEN COMMUNICATION SYSTEMS -00C0AE TOWERCOM CO. INC. DBA PC HOUSE -00C0AF TEKLOGIX INC. -00C0B0 GCC TECHNOLOGIES,INC. -00C0B1 GENIUS NET CO. -00C0B2 NORAND CORPORATION -00C0B3 COMSTAT DATACOMM CORPORATION -00C0B4 MYSON TECHNOLOGY, INC. -00C0B5 CORPORATE NETWORK SYSTEMS,INC. -00C0B6 Snap Appliance, Inc. -00C0B7 AMERICAN POWER CONVERSION CORP -00C0B8 FRASER'S HILL LTD. -00C0B9 FUNK SOFTWARE, INC. -00C0BA NETVANTAGE -00C0BB FORVAL CREATIVE, INC. -00C0BC TELECOM AUSTRALIA/CSSC -00C0BD INEX TECHNOLOGIES, INC. -00C0BE ALCATEL - SEL -00C0BF TECHNOLOGY CONCEPTS, LTD. -00C0C0 SHORE MICROSYSTEMS, INC. -00C0C1 QUAD/GRAPHICS, INC. -00C0C2 INFINITE NETWORKS LTD. -00C0C3 ACUSON COMPUTED SONOGRAPHY -00C0C4 COMPUTER OPERATIONAL -00C0C5 SID INFORMATICA -00C0C6 PERSONAL MEDIA CORP. -00C0C7 SPARKTRUM MICROSYSTEMS, INC. -00C0C8 MICRO BYTE PTY. LTD. -00C0C9 ELSAG BAILEY PROCESS -00C0CA ALFA, INC. -00C0CB CONTROL TECHNOLOGY CORPORATION -00C0CC TELESCIENCES CO SYSTEMS, INC. -00C0CD COMELTA, S.A. -00C0CE CEI SYSTEMS & ENGINEERING PTE -00C0CF IMATRAN VOIMA OY -00C0D0 RATOC SYSTEM INC. -00C0D1 COMTREE TECHNOLOGY CORPORATION -00C0D2 SYNTELLECT, INC. -00C0D3 OLYMPUS IMAGE SYSTEMS, INC. -00C0D4 AXON NETWORKS, INC. -00C0D5 QUANCOM ELECTRONIC GMBH -00C0D6 J1 SYSTEMS, INC. -00C0D7 TAIWAN TRADING CENTER DBA -00C0D8 UNIVERSAL DATA SYSTEMS -00C0D9 QUINTE NETWORK CONFIDENTIALITY -00C0DA NICE SYSTEMS LTD. -00C0DB IPC CORPORATION (PTE) LTD. -00C0DC EOS TECHNOLOGIES, INC. -00C0DD QLogic Corporation -00C0DE ZCOMM, INC. -00C0DF KYE Systems Corp. -00C0E0 DSC COMMUNICATION CORP. -00C0E1 SONIC SOLUTIONS -00C0E2 CALCOMP, INC. -00C0E3 OSITECH COMMUNICATIONS, INC. -00C0E4 SIEMENS BUILDING -00C0E5 GESPAC, S.A. -00C0E6 Verilink Corporation -00C0E7 FIBERDATA AB -00C0E8 PLEXCOM, INC. -00C0E9 OAK SOLUTIONS, LTD. -00C0EA ARRAY TECHNOLOGY LTD. -00C0EB SEH COMPUTERTECHNIK GMBH -00C0EC DAUPHIN TECHNOLOGY -00C0ED US ARMY ELECTRONIC -00C0EE KYOCERA CORPORATION -00C0EF ABIT CORPORATION -00C0F0 KINGSTON TECHNOLOGY CORP. -00C0F1 SHINKO ELECTRIC CO., LTD. -00C0F2 TRANSITION NETWORKS -00C0F3 NETWORK COMMUNICATIONS CORP. -00C0F4 INTERLINK SYSTEM CO., LTD. -00C0F5 METACOMP, INC. -00C0F6 CELAN TECHNOLOGY INC. -00C0F7 ENGAGE COMMUNICATION, INC. -00C0F8 ABOUT COMPUTING INC. -00C0F9 HARRIS AND JEFFRIES, INC. -00C0FA CANARY COMMUNICATIONS, INC. -00C0FB ADVANCED TECHNOLOGY LABS -00C0FC ELASTIC REALITY, INC. -00C0FD PROSUM -00C0FE APTEC COMPUTER SYSTEMS, INC. -00C0FF DOT HILL SYSTEMS CORPORATION -00CBBD Cambridge Broadband Ltd. -00CF1C COMMUNICATION MACHINERY CORP. -00D000 FERRAN SCIENTIFIC, INC. -00D001 VST TECHNOLOGIES, INC. -00D002 DITECH CORPORATION -00D003 COMDA ENTERPRISES CORP. -00D004 PENTACOM LTD. -00D005 ZHS ZEITMANAGEMENTSYSTEME -00D006 CISCO SYSTEMS, INC. -00D007 MIC ASSOCIATES, INC. -00D008 MACTELL CORPORATION -00D009 HSING TECH. ENTERPRISE CO. LTD -00D00A LANACCESS TELECOM S.A. -00D00B RHK TECHNOLOGY, INC. -00D00C SNIJDER MICRO SYSTEMS -00D00D MICROMERITICS INSTRUMENT -00D00E PLURIS, INC. -00D00F SPEECH DESIGN GMBH -00D010 CONVERGENT NETWORKS, INC. -00D011 PRISM VIDEO, INC. -00D012 GATEWORKS CORP. -00D013 PRIMEX AEROSPACE COMPANY -00D014 ROOT, INC. -00D015 UNIVEX MICROTECHNOLOGY CORP. -00D016 SCM MICROSYSTEMS, INC. -00D017 SYNTECH INFORMATION CO., LTD. -00D018 QWES. COM, INC. -00D019 DAINIPPON SCREEN CORPORATE -00D01A URMET SUD S.P.A. -00D01B MIMAKI ENGINEERING CO., LTD. -00D01C SBS TECHNOLOGIES, -00D01D FURUNO ELECTRIC CO., LTD. -00D01E PINGTEL CORP. -00D01F CTAM PTY. LTD. -00D020 AIM SYSTEM, INC. -00D021 REGENT ELECTRONICS CORP. -00D022 INCREDIBLE TECHNOLOGIES, INC. -00D023 INFORTREND TECHNOLOGY, INC. -00D024 Cognex Corporation -00D025 XROSSTECH, INC. -00D026 HIRSCHMANN AUSTRIA GMBH -00D027 APPLIED AUTOMATION, INC. -00D028 OMNEON VIDEO NETWORKS -00D029 WAKEFERN FOOD CORPORATION -00D02A Voxent Systems Ltd. -00D02B JETCELL, INC. -00D02C CAMPBELL SCIENTIFIC, INC. -00D02D ADEMCO -00D02E COMMUNICATION AUTOMATION CORP. -00D02F VLSI TECHNOLOGY INC. -00D030 SAFETRAN SYSTEMS CORP. -00D031 INDUSTRIAL LOGIC CORPORATION -00D032 YANO ELECTRIC CO., LTD. -00D033 DALIAN DAXIAN NETWORK -00D034 ORMEC SYSTEMS CORP. -00D035 BEHAVIOR TECH. COMPUTER CORP. -00D036 TECHNOLOGY ATLANTA CORP. -00D037 PHILIPS-DVS-LO BDR -00D038 FIVEMERE, LTD. -00D039 UTILICOM, INC. -00D03A ZONEWORX, INC. -00D03B VISION PRODUCTS PTY. LTD. -00D03C Vieo, Inc. -00D03D GALILEO TECHNOLOGY, LTD. -00D03E ROCKETCHIPS, INC. -00D03F AMERICAN COMMUNICATION -00D040 SYSMATE CO., LTD. -00D041 AMIGO TECHNOLOGY CO., LTD. -00D042 MAHLO GMBH & CO. UG -00D043 ZONAL RETAIL DATA SYSTEMS -00D044 ALIDIAN NETWORKS, INC. -00D045 KVASER AB -00D046 DOLBY LABORATORIES, INC. -00D047 XN TECHNOLOGIES -00D048 ECTON, INC. -00D049 IMPRESSTEK CO., LTD. -00D04A PRESENCE TECHNOLOGY GMBH -00D04B LA CIE GROUP S.A. -00D04C EUROTEL TELECOM LTD. -00D04D DIV OF RESEARCH & STATISTICS -00D04E LOGIBAG -00D04F BITRONICS, INC. -00D050 ISKRATEL -00D051 O2 MICRO, INC. -00D052 ASCEND COMMUNICATIONS, INC. -00D053 CONNECTED SYSTEMS -00D054 SAS INSTITUTE INC. -00D055 KATHREIN-WERKE KG -00D056 SOMAT CORPORATION -00D057 ULTRAK, INC. -00D058 CISCO SYSTEMS, INC. -00D059 AMBIT MICROSYSTEMS CORP. -00D05A SYMBIONICS, LTD. -00D05B ACROLOOP MOTION CONTROL -00D05C TECHNOTREND SYSTEMTECHNIK GMBH -00D05D INTELLIWORXX, INC. -00D05E STRATABEAM TECHNOLOGY, INC. -00D05F VALCOM, INC. -00D060 PANASONIC EUROPEAN -00D061 TREMON ENTERPRISES CO., LTD. -00D062 DIGIGRAM -00D063 CISCO SYSTEMS, INC. -00D064 MULTITEL -00D065 TOKO ELECTRIC -00D066 WINTRISS ENGINEERING CORP. -00D067 CAMPIO COMMUNICATIONS -00D068 IWILL CORPORATION -00D069 TECHNOLOGIC SYSTEMS -00D06A LINKUP SYSTEMS CORPORATION -00D06B SR TELECOM INC. -00D06C SHAREWAVE, INC. -00D06D ACRISON, INC. -00D06E TRENDVIEW RECORDERS LTD. -00D06F KMC CONTROLS -00D070 LONG WELL ELECTRONICS CORP. -00D071 ECHELON CORP. -00D072 BROADLOGIC -00D073 ACN ADVANCED COMMUNICATIONS -00D074 TAQUA SYSTEMS, INC. -00D075 ALARIS MEDICAL SYSTEMS, INC. -00D076 MERRILL LYNCH & CO., INC. -00D077 LUCENT TECHNOLOGIES -00D078 ELTEX OF SWEDEN AB -00D079 CISCO SYSTEMS, INC. -00D07A AMAQUEST COMPUTER CORP. -00D07B COMCAM INTERNATIONAL LTD. -00D07C KOYO ELECTRONICS INC. CO.,LTD. -00D07D COSINE COMMUNICATIONS -00D07E KEYCORP LTD. -00D07F STRATEGY & TECHNOLOGY, LIMITED -00D080 EXABYTE CORPORATION -00D081 REAL TIME DEVICES USA, INC. -00D082 IOWAVE INC. -00D083 INVERTEX, INC. -00D084 NEXCOMM SYSTEMS, INC. -00D085 OTIS ELEVATOR COMPANY -00D086 FOVEON, INC. -00D087 MICROFIRST INC. -00D088 Terayon Communications Systems -00D089 DYNACOLOR, INC. -00D08A PHOTRON USA -00D08B ADVA Limited -00D08C GENOA TECHNOLOGY, INC. -00D08D PHOENIX GROUP, INC. -00D08E NVISION INC. -00D08F ARDENT TECHNOLOGIES, INC. -00D090 CISCO SYSTEMS, INC. -00D091 SMARTSAN SYSTEMS, INC. -00D092 GLENAYRE WESTERN MULTIPLEX -00D093 TQ - COMPONENTS GMBH -00D094 TIMELINE VISTA, INC. -00D095 XYLAN CORPORATION -00D096 3COM EUROPE LTD. -00D097 CISCO SYSTEMS, INC. -00D098 Photon Dynamics Canada Inc. -00D099 ELCARD OY -00D09A FILANET CORPORATION -00D09B SPECTEL LTD. -00D09C KAPADIA COMMUNICATIONS -00D09D VERIS INDUSTRIES -00D09E 2WIRE, INC. -00D09F NOVTEK TEST SYSTEMS -00D0A0 MIPS DENMARK -00D0A1 OSKAR VIERLING GMBH + CO. KG -00D0A2 INTEGRATED DEVICE -00D0A3 VOCAL DATA, INC. -00D0A4 ALANTRO COMMUNICATIONS -00D0A5 AMERICAN ARIUM -00D0A6 LANBIRD TECHNOLOGY CO., LTD. -00D0A7 TOKYO SOKKI KENKYUJO CO., LTD. -00D0A8 NETWORK ENGINES, INC. -00D0A9 SHINANO KENSHI CO., LTD. -00D0AA CHASE COMMUNICATIONS -00D0AB DELTAKABEL TELECOM CV -00D0AC GRAYSON WIRELESS -00D0AD TL INDUSTRIES -00D0AE ORESIS COMMUNICATIONS, INC. -00D0AF CUTLER-HAMMER, INC. -00D0B0 BITSWITCH LTD. -00D0B1 OMEGA ELECTRONICS SA -00D0B2 XIOTECH CORPORATION -00D0B3 DRS FLIGHT SAFETY AND -00D0B4 KATSUJIMA CO., LTD. -00D0B5 IPricot formerly DotCom -00D0B6 CRESCENT NETWORKS, INC. -00D0B7 INTEL CORPORATION -00D0B8 IOMEGA CORP. -00D0B9 MICROTEK INTERNATIONAL, INC. -00D0BA CISCO SYSTEMS, INC. -00D0BB CISCO SYSTEMS, INC. -00D0BC CISCO SYSTEMS, INC. -00D0BD SICAN GMBH -00D0BE EMUTEC INC. -00D0BF PIVOTAL TECHNOLOGIES -00D0C0 CISCO SYSTEMS, INC. -00D0C1 HARMONIC DATA SYSTEMS, LTD. -00D0C2 BALTHAZAR TECHNOLOGY AB -00D0C3 VIVID TECHNOLOGY PTE, LTD. -00D0C4 TERATECH CORPORATION -00D0C5 COMPUTATIONAL SYSTEMS, INC. -00D0C6 THOMAS & BETTS CORP. -00D0C7 PATHWAY, INC. -00D0C8 I/O CONSULTING A/S -00D0C9 ADVANTECH CO., LTD. -00D0CA INTRINSYC SOFTWARE INC. -00D0CB DASAN CO., LTD. -00D0CC TECHNOLOGIES LYRE INC. -00D0CD ATAN TECHNOLOGY INC. -00D0CE ASYST ELECTRONIC -00D0CF MORETON BAY -00D0D0 ZHONGXING TELECOM LTD. -00D0D1 SIROCCO SYSTEMS, INC. -00D0D2 EPILOG CORPORATION -00D0D3 CISCO SYSTEMS, INC. -00D0D4 V-BITS, INC. -00D0D5 GRUNDIG AG -00D0D6 AETHRA TELECOMUNICAZIONI -00D0D7 B2C2, INC. -00D0D8 3Com Corporation -00D0D9 DEDICATED MICROCOMPUTERS -00D0DA TAICOM DATA SYSTEMS CO., LTD. -00D0DB MCQUAY INTERNATIONAL -00D0DC MODULAR MINING SYSTEMS, INC. -00D0DD SUNRISE TELECOM, INC. -00D0DE PHILIPS MULTIMEDIA NETWORK -00D0DF KUZUMI ELECTRONICS, INC. -00D0E0 DOOIN ELECTRONICS CO. -00D0E1 AVIONITEK ISRAEL INC. -00D0E2 MRT MICRO, INC. -00D0E3 ELE-CHEM ENGINEERING CO., LTD. -00D0E4 CISCO SYSTEMS, INC. -00D0E5 SOLIDUM SYSTEMS CORP. -00D0E6 IBOND INC. -00D0E7 VCON TELECOMMUNICATION LTD. -00D0E8 MAC SYSTEM CO., LTD. -00D0E9 ADVANTAGE CENTURY -00D0EA NEXTONE COMMUNICATIONS, INC. -00D0EB LIGHTERA NETWORKS, INC. -00D0EC NAKAYO TELECOMMUNICATIONS, INC -00D0ED XIOX -00D0EE DICTAPHONE CORPORATION -00D0EF IGT -00D0F0 CONVISION TECHNOLOGY GMBH -00D0F1 SEGA ENTERPRISES, LTD. -00D0F2 MONTEREY NETWORKS -00D0F3 SOLARI DI UDINE SPA -00D0F4 CARINTHIAN TECH INSTITUTE -00D0F5 ORANGE MICRO, INC. -00D0F6 Alcatel Canada -00D0F7 NEXT NETS CORPORATION -00D0F8 FUJIAN STAR TERMINAL -00D0F9 ACUTE COMMUNICATIONS CORP. -00D0FA RACAL GUARDATA -00D0FB TEK MICROSYSTEMS, INCORPORATED -00D0FC GRANITE MICROSYSTEMS -00D0FD OPTIMA TELE.COM, INC. -00D0FE ASTRAL POINT -00D0FF CISCO SYSTEMS, INC. -00DD00 UNGERMANN-BASS INC. -00DD01 UNGERMANN-BASS INC. -00DD02 UNGERMANN-BASS INC. -00DD03 UNGERMANN-BASS INC. -00DD04 UNGERMANN-BASS INC. -00DD05 UNGERMANN-BASS INC. -00DD06 UNGERMANN-BASS INC. -00DD07 UNGERMANN-BASS INC. -00DD08 UNGERMANN-BASS INC. -00DD09 UNGERMANN-BASS INC. -00DD0A UNGERMANN-BASS INC. -00DD0B UNGERMANN-BASS INC. -00DD0C UNGERMANN-BASS INC. -00DD0D UNGERMANN-BASS INC. -00DD0E UNGERMANN-BASS INC. -00DD0F UNGERMANN-BASS INC. -00E000 FUJITSU, LTD -00E001 STRAND LIGHTING LIMITED -00E002 CROSSROADS SYSTEMS, INC. -00E003 NOKIA WIRELESS BUSINESS COMMUN -00E004 PMC-SIERRA, INC. -00E005 TECHNICAL CORP. -00E006 SILICON INTEGRATED SYS. CORP. -00E007 NETWORK ALCHEMY LTD. -00E008 AMAZING CONTROLS! INC. -00E009 MARATHON TECHNOLOGIES CORP. -00E00A DIBA, INC. -00E00B ROOFTOP COMMUNICATIONS CORP. -00E00C MOTOROLA -00E00D RADIANT SYSTEMS -00E00E AVALON IMAGING SYSTEMS, INC. -00E00F SHANGHAI BAUD DATA -00E010 HESS SB-AUTOMATENBAU GmbH -00E011 UNIDEN SAN DIEGO R&D CENTER, INC. -00E012 PLUTO TECHNOLOGIES INTERNATIONAL INC. -00E013 EASTERN ELECTRONIC CO., LTD. -00E014 CISCO SYSTEMS, INC. -00E015 HEIWA CORPORATION -00E016 RAPID CITY COMMUNICATIONS -00E017 EXXACT GmbH -00E018 ASUSTEK COMPUTER INC. -00E019 ING. GIORDANO ELETTRONICA -00E01A COMTEC SYSTEMS. CO., LTD. -00E01B SPHERE COMMUNICATIONS, INC. -00E01C MOBILITY ELECTRONICSY -00E01D WebTV NETWORKS, INC. -00E01E CISCO SYSTEMS, INC. -00E01F AVIDIA Systems, Inc. -00E020 TECNOMEN OY -00E021 FREEGATE CORP. -00E022 MediaLight, Inc. -00E023 TELRAD -00E024 GADZOOX NETWORKS -00E025 dit CO., LTD. -00E026 EASTMAN KODAK CO. -00E027 DUX, INC. -00E028 APTIX CORPORATION -00E029 STANDARD MICROSYSTEMS CORP. -00E02A TANDBERG TELEVISION AS -00E02B EXTREME NETWORKS -00E02C AST COMPUTER -00E02D InnoMediaLogic, Inc. -00E02E SPC ELECTRONICS CORPORATION -00E02F MCNS HOLDINGS, L.P. -00E030 MELITA INTERNATIONAL CORP. -00E031 HAGIWARA ELECTRIC CO., LTD. -00E032 MISYS FINANCIAL SYSTEMS, LTD. -00E033 E.E.P.D. GmbH -00E034 CISCO SYSTEMS, INC. -00E035 LOUGHBOROUGH SOUND IMAGES, PLC -00E036 PIONEER CORPORATION -00E037 CENTURY CORPORATION -00E038 PROXIMA CORPORATION -00E039 PARADYNE CORP. -00E03A CABLETRON SYSTEMS, INC. -00E03B PROMINET CORPORATION -00E03C AdvanSys -00E03D FOCON ELECTRONIC SYSTEMS A/S -00E03E ALFATECH, INC. -00E03F JATON CORPORATION -00E040 DeskStation Technology, Inc. -00E041 CSPI -00E042 Pacom Systems Ltd. -00E043 VitalCom -00E044 LSICS CORPORATION -00E045 TOUCHWAVE, INC. -00E046 BENTLY NEVADA CORP. -00E047 INFOCUS SYSTEMS -00E048 SDL COMMUNICATIONS, INC. -00E049 MICROWI ELECTRONIC GmbH -00E04A ENHANCED MESSAGING SYSTEMS, INC -00E04B JUMP INDUSTRIELLE COMPUTERTECHNIK GmbH -00E04C REALTEK SEMICONDUCTOR CORP. -00E04D INTERNET INITIATIVE JAPAN, INC -00E04E SANYO DENKI CO., LTD. -00E04F CISCO SYSTEMS, INC. -00E050 EXECUTONE INFORMATION SYSTEMS, INC. -00E051 TALX CORPORATION -00E052 FOUNDRY NETWORKS, INC. -00E053 CELLPORT LABS, INC. -00E054 KODAI HITEC CO., LTD. -00E055 INGENIERIA ELECTRONICA COMERCIAL INELCOM S.A. -00E056 HOLONTECH CORPORATION -00E057 HAN MICROTELECOM. CO., LTD. -00E058 PHASE ONE DENMARK A/S -00E059 CONTROLLED ENVIRONMENTS, LTD. -00E05A GALEA NETWORK SECURITY -00E05B WEST END SYSTEMS CORP. -00E05C MATSUSHITA KOTOBUKI ELECTRONICS INDUSTRIES, LTD. -00E05D UNITEC CO., LTD. -00E05E JAPAN AVIATION ELECTRONICS INDUSTRY, LTD. -00E05F e-Net, Inc. -00E060 SHERWOOD -00E061 EdgePoint Networks, Inc. -00E062 HOST ENGINEERING -00E063 CABLETRON - YAGO SYSTEMS, INC. -00E064 SAMSUNG ELECTRONICS -00E065 OPTICAL ACCESS INTERNATIONAL -00E066 ProMax Systems, Inc. -00E067 eac AUTOMATION-CONSULTING GmbH -00E068 MERRIMAC SYSTEMS INC. -00E069 JAYCOR -00E06A KAPSCH AG -00E06B W&G SPECIAL PRODUCTS -00E06C AEP Systems International Ltd -00E06D COMPUWARE CORPORATION -00E06E FAR SYSTEMS S.p.A. -00E06F Terayon Communications Systems -00E070 DH TECHNOLOGY -00E071 EPIS MICROCOMPUTER -00E072 LYNK -00E073 NATIONAL AMUSEMENT NETWORK, INC. -00E074 TIERNAN COMMUNICATIONS, INC. -00E075 Verilink Corporation -00E076 DEVELOPMENT CONCEPTS, INC. -00E077 WEBGEAR, INC. -00E078 BERKELEY NETWORKS -00E079 A.T.N.R. -00E07A MIKRODIDAKT AB -00E07B BAY NETWORKS -00E07C METTLER-TOLEDO, INC. -00E07D NETRONIX, INC. -00E07E WALT DISNEY IMAGINEERING -00E07F LOGISTISTEM s.r.l. -00E080 CONTROL RESOURCES CORPORATION -00E081 TYAN COMPUTER CORP. -00E082 ANERMA -00E083 JATO TECHNOLOGIES, INC. -00E084 COMPULITE R&D -00E085 GLOBAL MAINTECH, INC. -00E086 CYBEX COMPUTER PRODUCTS -00E087 LeCroy - Networking Productions Division -00E088 LTX CORPORATION -00E089 ION Networks, Inc. -00E08A GEC AVERY, LTD. -00E08B QLogic Corp. -00E08C NEOPARADIGM LABS, INC. -00E08D PRESSURE SYSTEMS, INC. -00E08E UTSTARCOM -00E08F CISCO SYSTEMS, INC. -00E090 BECKMAN LAB. AUTOMATION DIV. -00E091 LG ELECTRONICS, INC. -00E092 ADMTEK INCORPORATED -00E093 ACKFIN NETWORKS -00E094 OSAI SRL -00E095 ADVANCED-VISION TECHNOLGIES CORP. -00E096 SHIMADZU CORPORATION -00E097 CARRIER ACCESS CORPORATION -00E098 AboCom Systems, Inc. -00E099 SAMSON AG -00E09A POSITRON INDUSTRIES, INC. -00E09B ENGAGE NETWORKS, INC. -00E09C MII -00E09D SARNOFF CORPORATION -00E09E QUANTUM CORPORATION -00E09F PIXEL VISION -00E0A0 WILTRON CO. -00E0A1 HIMA PAUL HILDEBRANDT GmbH Co. KG -00E0A2 MICROSLATE INC. -00E0A3 CISCO SYSTEMS, INC. -00E0A4 ESAOTE S.p.A. -00E0A5 ComCore Semiconductor, Inc. -00E0A6 TELOGY NETWORKS, INC. -00E0A7 IPC INFORMATION SYSTEMS, INC. -00E0A8 SAT GmbH & Co. -00E0A9 FUNAI ELECTRIC CO., LTD. -00E0AA ELECTROSONIC LTD. -00E0AB DIMAT S.A. -00E0AC MIDSCO, INC. -00E0AD EES TECHNOLOGY, LTD. -00E0AE XAQTI CORPORATION -00E0AF GENERAL DYNAMICS INFORMATION SYSTEMS -00E0B0 CISCO SYSTEMS, INC. -00E0B1 PACKET ENGINES, INC. -00E0B2 TELMAX COMMUNICATIONS CORP. -00E0B3 EtherWAN Systems, Inc. -00E0B4 TECHNO SCOPE CO., LTD. -00E0B5 ARDENT COMMUNICATIONS CORP. -00E0B6 Entrada Networks -00E0B7 PI GROUP, LTD. -00E0B8 GATEWAY 2000 -00E0B9 BYAS SYSTEMS -00E0BA BERGHOF AUTOMATIONSTECHNIK GmbH -00E0BB NBX CORPORATION -00E0BC SYMON COMMUNICATIONS, INC. -00E0BD INTERFACE SYSTEMS, INC. -00E0BE GENROCO INTERNATIONAL, INC. -00E0BF TORRENT NETWORKING TECHNOLOGIES CORP. -00E0C0 SEIWA ELECTRIC MFG. CO., LTD. -00E0C1 MEMOREX TELEX JAPAN, LTD. -00E0C2 NECSY S.p.A. -00E0C3 SAKAI SYSTEM DEVELOPMENT CORP. -00E0C4 HORNER ELECTRIC, INC. -00E0C5 BCOM ELECTRONICS INC. -00E0C6 LINK2IT, L.L.C. -00E0C7 EUROTECH SRL -00E0C8 VIRTUAL ACCESS, LTD. -00E0C9 AutomatedLogic Corporation -00E0CA BEST DATA PRODUCTS -00E0CB RESON, INC. -00E0CC HERO SYSTEMS, LTD. -00E0CD SENSIS CORPORATION -00E0CE ARN -00E0CF INTEGRATED DEVICE TECHNOLOGY, INC. -00E0D0 NETSPEED, INC. -00E0D1 TELSIS LIMITED -00E0D2 VERSANET COMMUNICATIONS, INC. -00E0D3 DATENTECHNIK GmbH -00E0D4 EXCELLENT COMPUTER -00E0D5 ARCXEL TECHNOLOGIES, INC. -00E0D6 COMPUTER & COMMUNICATION RESEARCH LAB. -00E0D7 SUNSHINE ELECTRONICS, INC. -00E0D8 LANBit Computer, Inc. -00E0D9 TAZMO CO., LTD. -00E0DA ASSURED ACCESS TECHNOLOGY, INC. -00E0DB ViaVideo Communications, Inc. -00E0DC NEXWARE CORP. -00E0DD ZENITH ELECTRONICS CORPORATION -00E0DE DATAX NV -00E0DF KE KOMMUNIKATIONS-ELECTRONIK -00E0E0 SI ELECTRONICS, LTD. -00E0E1 G2 NETWORKS, INC. -00E0E2 INNOVA CORP. -00E0E3 SK-ELEKTRONIK GmbH -00E0E4 FANUC ROBOTICS NORTH AMERICA, Inc. -00E0E5 CINCO NETWORKS, INC. -00E0E6 INCAA DATACOM B.V. -00E0E7 RAYTHEON E-SYSTEMS, INC. -00E0E8 GRETACODER Data Systems AG -00E0E9 DATA LABS, INC. -00E0EA INNOVAT COMMUNICATIONS, INC. -00E0EB DIGICOM SYSTEMS, INCORPORATED -00E0EC CELESTICA INC. -00E0ED SILICOM, LTD. -00E0EE MAREL HF -00E0EF DIONEX -00E0F0 ABLER TECHNOLOGY, INC. -00E0F1 THAT CORPORATION -00E0F2 ARLOTTO COMNET, INC. -00E0F3 WebSprint Communications, Inc. -00E0F4 INSIDE Technology A/S -00E0F5 TELES AG -00E0F6 DECISION EUROPE -00E0F7 CISCO SYSTEMS, INC. -00E0F8 DICNA CONTROL AB -00E0F9 CISCO SYSTEMS, INC. -00E0FA TRL TECHNOLOGY, LTD. -00E0FB LEIGHTRONIX, INC. -00E0FC HUAWEI TECHNOLOGIES CO., LTD. -00E0FD A-TREND TECHNOLOGY CO., LTD. -00E0FE CISCO SYSTEMS, INC. -00E0FF SECURITY DYNAMICS TECHNOLOGIES, Inc. -00E6D3 NIXDORF COMPUTER CORP. -020701 RACAL-DATACOM -021C7C PERQ SYSTEMS CORPORATION -026086 LOGIC REPLACEMENT TECH. LTD. -02608C 3COM CORPORATION -027001 RACAL-DATACOM -0270B0 M/A-COM INC. COMPANIES -0270B3 DATA RECALL LTD -029D8E CARDIAC RECORDERS INC. -02AA3C OLIVETTI TELECOMM SPA (OLTECO) -02BB01 OCTOTHORPE CORP. -02C08C 3COM CORPORATION -02CF1C COMMUNICATION MACHINERY CORP. -02E6D3 NIXDORF COMPUTER CORPORATION -040AE0 XMIT AG COMPUTER NETWORKS -04E0C4 TRIUMPH-ADLER AG -080001 COMPUTERVISION CORPORATION -080002 BRIDGE COMMUNICATIONS INC. -080003 ADVANCED COMPUTER COMM. -080004 CROMEMCO INCORPORATED -080005 SYMBOLICS INC. -080006 SIEMENS AG -080007 APPLE COMPUTER INC. -080008 BOLT BERANEK AND NEWMAN INC. -080009 HEWLETT PACKARD -08000A NESTAR SYSTEMS INCORPORATED -08000B UNISYS CORPORATION -08000C MIKLYN DEVELOPMENT CO. -08000D INTERNATIONAL COMPUTERS LTD. -08000E NCR CORPORATION -08000F MITEL CORPORATION -080011 TEKTRONIX INC. -080012 BELL ATLANTIC INTEGRATED SYST. -080013 EXXON -080014 EXCELAN -080015 STC BUSINESS SYSTEMS -080016 BARRISTER INFO SYS CORP -080017 NATIONAL SEMICONDUCTOR -080018 PIRELLI FOCOM NETWORKS -080019 GENERAL ELECTRIC CORPORATION -08001A TIARA/ 10NET -08001B DATA GENERAL -08001C KDD-KOKUSAI DEBNSIN DENWA CO. -08001D ABLE COMMUNICATIONS INC. -08001E APOLLO COMPUTER INC. -08001F SHARP CORPORATION -080020 SUN MICROSYSTEMS INC. -080021 3M COMPANY -080022 NBI INC. -080023 Panasonic Communications Co., Ltd. -080024 10NET COMMUNICATIONS/DCA -080025 CONTROL DATA -080026 NORSK DATA A.S. -080027 CADMUS COMPUTER SYSTEMS -080028 Texas Instruments -080029 MEGATEK CORPORATION -08002A MOSAIC TECHNOLOGIES INC. -08002B DIGITAL EQUIPMENT CORPORATION -08002C BRITTON LEE INC. -08002D LAN-TEC INC. -08002E METAPHOR COMPUTER SYSTEMS -08002F PRIME COMPUTER INC. -080030 NETWORK RESEARCH CORPORATION -080030 CERN -080030 ROYAL MELBOURNE INST OF TECH -080031 LITTLE MACHINES INC. -080032 TIGAN INCORPORATED -080033 BAUSCH & LOMB -080034 FILENET CORPORATION -080035 MICROFIVE CORPORATION -080036 INTERGRAPH CORPORATION -080037 FUJI-XEROX CO. LTD. -080038 CII HONEYWELL BULL -080039 SPIDER SYSTEMS LIMITED -08003A ORCATECH INC. -08003B TORUS SYSTEMS LIMITED -08003C SCHLUMBERGER WELL SERVICES -08003D CADNETIX CORPORATIONS -08003E CODEX CORPORATION -08003F FRED KOSCHARA ENTERPRISES -080040 FERRANTI COMPUTER SYS. LIMITED -080041 RACAL-MILGO INFORMATION SYS.. -080042 JAPAN MACNICS CORP. -080043 PIXEL COMPUTER INC. -080044 DAVID SYSTEMS INC. -080045 CONCURRENT COMPUTER CORP. -080046 SONY CORPORATION LTD. -080047 SEQUENT COMPUTER SYSTEMS INC. -080048 EUROTHERM GAUGING SYSTEMS -080049 UNIVATION -08004A BANYAN SYSTEMS INC. -08004B PLANNING RESEARCH CORP. -08004C HYDRA COMPUTER SYSTEMS INC. -08004D CORVUS SYSTEMS INC. -08004E 3COM EUROPE LTD. -08004F CYGNET SYSTEMS -080050 DAISY SYSTEMS CORP. -080051 EXPERDATA -080052 INSYSTEC -080053 MIDDLE EAST TECH. UNIVERSITY -080055 STANFORD TELECOMM. INC. -080056 STANFORD LINEAR ACCEL. CENTER -080057 EVANS & SUTHERLAND -080058 SYSTEMS CONCEPTS -080059 A/S MYCRON -08005A IBM CORPORATION -08005B VTA TECHNOLOGIES INC. -08005C FOUR PHASE SYSTEMS -08005D GOULD INC. -08005E COUNTERPOINT COMPUTER INC. -08005F SABER TECHNOLOGY CORP. -080060 INDUSTRIAL NETWORKING INC. -080061 JAROGATE LTD. -080062 GENERAL DYNAMICS -080063 PLESSEY -080064 AUTOPHON AG -080065 GENRAD INC. -080066 AGFA CORPORATION -080067 COMDESIGN -080068 RIDGE COMPUTERS -080069 SILICON GRAPHICS INC. -08006A ATT BELL LABORATORIES -08006B ACCEL TECHNOLOGIES INC. -08006C SUNTEK TECHNOLOGY INT'L -08006D WHITECHAPEL COMPUTER WORKS -08006E MASSCOMP -08006F PHILIPS APELDOORN B.V. -080070 MITSUBISHI ELECTRIC CORP. -080071 MATRA (DSIE) -080072 XEROX CORP UNIV GRANT PROGRAM -080073 TECMAR INC. -080074 CASIO COMPUTER CO. LTD. -080075 DANSK DATA ELECTRONIK -080076 PC LAN TECHNOLOGIES -080077 TSL COMMUNICATIONS LTD. -080078 ACCELL CORPORATION -080079 THE DROID WORKS -08007A INDATA -08007B SANYO ELECTRIC CO. LTD. -08007C VITALINK COMMUNICATIONS CORP. -08007E AMALGAMATED WIRELESS(AUS) LTD -08007F CARNEGIE-MELLON UNIVERSITY -080080 AES DATA INC. -080081 ,ASTECH INC. -080082 VERITAS SOFTWARE -080083 Seiko Instruments Inc. -080084 TOMEN ELECTRONICS CORP. -080085 ELXSI -080086 KONICA MINOLTA HOLDINGS, INC. -080087 XYPLEX -080088 MCDATA CORPORATION -080089 KINETICS -08008A PERFORMANCE TECHNOLOGY -08008B PYRAMID TECHNOLOGY CORP. -08008C NETWORK RESEARCH CORPORATION -08008D XYVISION INC. -08008E TANDEM COMPUTERS -08008F CHIPCOM CORPORATION -080090 SONOMA SYSTEMS -081443 UNIBRAIN S.A. -08BBCC AK-NORD EDV VERTRIEBSGES. mbH -10005A IBM CORPORATION -1000E8 NATIONAL SEMICONDUCTOR -800010 ATT BELL LABORATORIES -A06A00 Verilink Corporation -AA0000 DIGITAL EQUIPMENT CORPORATION -AA0001 DIGITAL EQUIPMENT CORPORATION -AA0002 DIGITAL EQUIPMENT CORPORATION -AA0003 DIGITAL EQUIPMENT CORPORATION -AA0004 DIGITAL EQUIPMENT CORPORATION diff --git a/drivers/ieee1394/oui2c.sh b/drivers/ieee1394/oui2c.sh deleted file mode 100644 index b9d0e8f..0000000 --- a/drivers/ieee1394/oui2c.sh +++ /dev/null @@ -1,22 +0,0 @@ -#!/bin/sh - -cat <algo_data = &i2c_adapter_data; i2c_adapter_data.data = lynx; + i2c_ad->dev.parent = &dev->dev; PRINTD(KERN_DEBUG, lynx->id,"original eeprom control: %d", reg_read(lynx, SERIAL_EEPROM_CONTROL)); diff --git a/drivers/ieee1394/raw1394.c b/drivers/ieee1394/raw1394.c index ad2108f..aa9ca83 100644 --- a/drivers/ieee1394/raw1394.c +++ b/drivers/ieee1394/raw1394.c @@ -636,27 +636,32 @@ static int state_initialized(struct file case RAW1394_REQ_SET_CARD: spin_lock_irqsave(&host_info_lock, flags); - if (req->req.misc < host_count) { - list_for_each_entry(hi, &host_info_list, list) { - if (!req->req.misc--) - break; - } - get_device(&hi->host->device); // XXX Need to handle failure case - list_add_tail(&fi->list, &hi->file_info_list); - fi->host = hi->host; - fi->state = connected; - - req->req.error = RAW1394_ERROR_NONE; - req->req.generation = get_hpsb_generation(fi->host); - req->req.misc = (fi->host->node_id << 16) - | fi->host->node_count; - if (fi->protocol_version > 3) { - req->req.misc |= - NODEID_TO_NODE(fi->host->irm_id) << 8; - } - } else { + if (req->req.misc >= host_count) { req->req.error = RAW1394_ERROR_INVALID_ARG; + goto out_set_card; } + list_for_each_entry(hi, &host_info_list, list) + if (!req->req.misc--) + break; + get_device(&hi->host->device); /* FIXME handle failure case */ + list_add_tail(&fi->list, &hi->file_info_list); + + /* prevent unloading of the host's low-level driver */ + if (!try_module_get(hi->host->driver->owner)) { + req->req.error = RAW1394_ERROR_ABORTED; + goto out_set_card; + } + WARN_ON(fi->host); + fi->host = hi->host; + fi->state = connected; + + req->req.error = RAW1394_ERROR_NONE; + req->req.generation = get_hpsb_generation(fi->host); + req->req.misc = (fi->host->node_id << 16) + | fi->host->node_count; + if (fi->protocol_version > 3) + req->req.misc |= NODEID_TO_NODE(fi->host->irm_id) << 8; +out_set_card: spin_unlock_irqrestore(&host_info_lock, flags); req->req.length = 0; @@ -2955,6 +2960,11 @@ static int raw1394_release(struct inode put_device(&fi->host->device); } + spin_lock_irqsave(&host_info_lock, flags); + if (fi->host) + module_put(fi->host->driver->owner); + spin_unlock_irqrestore(&host_info_lock, flags); + kfree(fi); return 0; @@ -3003,7 +3013,7 @@ static struct hpsb_highlevel raw1394_hig }; static struct cdev raw1394_cdev; -static struct file_operations raw1394_fops = { +static const struct file_operations raw1394_fops = { .owner = THIS_MODULE, .read = raw1394_read, .write = raw1394_write, diff --git a/drivers/ieee1394/sbp2.c b/drivers/ieee1394/sbp2.c index 4325aac..4edfff4 100644 --- a/drivers/ieee1394/sbp2.c +++ b/drivers/ieee1394/sbp2.c @@ -51,7 +51,6 @@ * Grep for inline FIXME comments below. */ -#include #include #include #include @@ -304,10 +303,11 @@ static struct scsi_host_template sbp2_sh .use_clustering = ENABLE_CLUSTERING, .cmd_per_lun = SBP2_MAX_CMDS, .can_queue = SBP2_MAX_CMDS, - .emulated = 1, .sdev_attrs = sbp2_sysfs_sdev_attrs, }; +/* for match-all entries in sbp2_workarounds_table */ +#define SBP2_ROM_VALUE_WILDCARD 0x1000000 /* * List of devices with known bugs. @@ -329,22 +329,14 @@ static const struct { }, /* Initio bridges, actually only needed for some older ones */ { .firmware_revision = 0x000200, + .model_id = SBP2_ROM_VALUE_WILDCARD, .workarounds = SBP2_WORKAROUND_INQUIRY_36, }, /* Symbios bridge */ { .firmware_revision = 0xa0b800, + .model_id = SBP2_ROM_VALUE_WILDCARD, .workarounds = SBP2_WORKAROUND_128K_MAX_TRANS, }, - /* - * Note about the following Apple iPod blacklist entries: - * - * There are iPods (2nd gen, 3rd gen) with model_id==0. Since our - * matching logic treats 0 as a wildcard, we cannot match this ID - * without rewriting the matching routine. Fortunately these iPods - * do not feature the read_capacity bug according to one report. - * Read_capacity behaviour as well as model_id could change due to - * Apple-supplied firmware updates though. - */ /* iPod 4th generation */ { .firmware_revision = 0x0a2700, .model_id = 0x000021, @@ -1307,11 +1299,13 @@ static void sbp2_parse_unit_directory(st if (!(workarounds & SBP2_WORKAROUND_OVERRIDE)) for (i = 0; i < ARRAY_SIZE(sbp2_workarounds_table); i++) { - if (sbp2_workarounds_table[i].firmware_revision && + if (sbp2_workarounds_table[i].firmware_revision != + SBP2_ROM_VALUE_WILDCARD && sbp2_workarounds_table[i].firmware_revision != (firmware_revision & 0xffff00)) continue; - if (sbp2_workarounds_table[i].model_id && + if (sbp2_workarounds_table[i].model_id != + SBP2_ROM_VALUE_WILDCARD && sbp2_workarounds_table[i].model_id != ud->model_id) continue; workarounds |= sbp2_workarounds_table[i].workarounds; @@ -2017,7 +2011,6 @@ static int sbp2scsi_slave_configure(stru { struct sbp2_lu *lu = (struct sbp2_lu *)sdev->host->hostdata[0]; - blk_queue_dma_alignment(sdev->request_queue, (512 - 1)); sdev->use_10_for_rw = 1; if (sdev->type == TYPE_ROM) diff --git a/drivers/ieee1394/video1394.c b/drivers/ieee1394/video1394.c index 598b19f..95ca26d 100644 --- a/drivers/ieee1394/video1394.c +++ b/drivers/ieee1394/video1394.c @@ -489,6 +489,9 @@ static void wakeup_dma_ir_ctx(unsigned l reset_ir_status(d, i); d->buffer_status[d->buffer_prg_assignment[i]] = VIDEO1394_BUFFER_READY; do_gettimeofday(&d->buffer_time[d->buffer_prg_assignment[i]]); + dma_region_sync_for_cpu(&d->dma, + d->buffer_prg_assignment[i] * d->buf_size, + d->buf_size); } } @@ -1096,6 +1099,8 @@ static long video1394_ioctl(struct file DBGMSG(ohci->host->id, "Starting iso transmit DMA ctx=%d", d->ctx); put_timestamp(ohci, d, d->last_buffer); + dma_region_sync_for_device(&d->dma, + v.buffer * d->buf_size, d->buf_size); /* Tell the controller where the first program is */ reg_write(ohci, d->cmdPtr, @@ -1111,6 +1116,9 @@ static long video1394_ioctl(struct file "Waking up iso transmit dma ctx=%d", d->ctx); put_timestamp(ohci, d, d->last_buffer); + dma_region_sync_for_device(&d->dma, + v.buffer * d->buf_size, d->buf_size); + reg_write(ohci, d->ctrlSet, 0x1000); } } @@ -1269,7 +1277,7 @@ static long video1394_compat_ioctl(struc #endif static struct cdev video1394_cdev; -static struct file_operations video1394_fops= +static const struct file_operations video1394_fops= { .owner = THIS_MODULE, .unlocked_ioctl = video1394_ioctl, diff --git a/drivers/infiniband/Kconfig b/drivers/infiniband/Kconfig index 9edface..66b36de 100644 --- a/drivers/infiniband/Kconfig +++ b/drivers/infiniband/Kconfig @@ -38,6 +38,7 @@ source "drivers/infiniband/hw/mthca/Kcon source "drivers/infiniband/hw/ipath/Kconfig" source "drivers/infiniband/hw/ehca/Kconfig" source "drivers/infiniband/hw/amso1100/Kconfig" +source "drivers/infiniband/hw/cxgb3/Kconfig" source "drivers/infiniband/ulp/ipoib/Kconfig" diff --git a/drivers/infiniband/Makefile b/drivers/infiniband/Makefile index 2b5d109..da2066c 100644 --- a/drivers/infiniband/Makefile +++ b/drivers/infiniband/Makefile @@ -3,6 +3,7 @@ obj-$(CONFIG_INFINIBAND_MTHCA) += hw/mt obj-$(CONFIG_INFINIBAND_IPATH) += hw/ipath/ obj-$(CONFIG_INFINIBAND_EHCA) += hw/ehca/ obj-$(CONFIG_INFINIBAND_AMSO1100) += hw/amso1100/ +obj-$(CONFIG_INFINIBAND_CXGB3) += hw/cxgb3/ obj-$(CONFIG_INFINIBAND_IPOIB) += ulp/ipoib/ obj-$(CONFIG_INFINIBAND_SRP) += ulp/srp/ obj-$(CONFIG_INFINIBAND_ISER) += ulp/iser/ diff --git a/drivers/infiniband/core/addr.c b/drivers/infiniband/core/addr.c index af93979..a91001c 100644 --- a/drivers/infiniband/core/addr.c +++ b/drivers/infiniband/core/addr.c @@ -360,8 +360,7 @@ static int netevent_callback(struct noti if (event == NETEVENT_NEIGH_UPDATE) { struct neighbour *neigh = ctx; - if (neigh->dev->type == ARPHRD_INFINIBAND && - (neigh->nud_state & NUD_VALID)) { + if (neigh->nud_state & NUD_VALID) { set_timeout(jiffies); } } @@ -374,7 +373,7 @@ static struct notifier_block nb = { static int addr_init(void) { - addr_wq = create_singlethread_workqueue("ib_addr_wq"); + addr_wq = create_singlethread_workqueue("ib_addr"); if (!addr_wq) return -ENOMEM; diff --git a/drivers/infiniband/core/cache.c b/drivers/infiniband/core/cache.c index 98272fb..558c9a0 100644 --- a/drivers/infiniband/core/cache.c +++ b/drivers/infiniband/core/cache.c @@ -38,7 +38,6 @@ #include #include #include -#include /* INIT_WORK, schedule_work(), flush_scheduled_work() */ #include diff --git a/drivers/infiniband/core/cma.c b/drivers/infiniband/core/cma.c index 9e0ab04..db88e60 100644 --- a/drivers/infiniband/core/cma.c +++ b/drivers/infiniband/core/cma.c @@ -71,6 +71,7 @@ static struct workqueue_struct *cma_wq; static DEFINE_IDR(sdp_ps); static DEFINE_IDR(tcp_ps); static DEFINE_IDR(udp_ps); +static int next_port; struct cma_device { struct list_head list; @@ -1722,33 +1723,74 @@ static int cma_alloc_port(struct idr *ps unsigned short snum) { struct rdma_bind_list *bind_list; - int port, start, ret; + int port, ret; bind_list = kzalloc(sizeof *bind_list, GFP_KERNEL); if (!bind_list) return -ENOMEM; - start = snum ? snum : sysctl_local_port_range[0]; + do { + ret = idr_get_new_above(ps, bind_list, snum, &port); + } while ((ret == -EAGAIN) && idr_pre_get(ps, GFP_KERNEL)); + + if (ret) + goto err1; + + if (port != snum) { + ret = -EADDRNOTAVAIL; + goto err2; + } + + bind_list->ps = ps; + bind_list->port = (unsigned short) port; + cma_bind_port(bind_list, id_priv); + return 0; +err2: + idr_remove(ps, port); +err1: + kfree(bind_list); + return ret; +} +static int cma_alloc_any_port(struct idr *ps, struct rdma_id_private *id_priv) +{ + struct rdma_bind_list *bind_list; + int port, ret; + + bind_list = kzalloc(sizeof *bind_list, GFP_KERNEL); + if (!bind_list) + return -ENOMEM; + +retry: do { - ret = idr_get_new_above(ps, bind_list, start, &port); + ret = idr_get_new_above(ps, bind_list, next_port, &port); } while ((ret == -EAGAIN) && idr_pre_get(ps, GFP_KERNEL)); if (ret) - goto err; + goto err1; - if ((snum && port != snum) || - (!snum && port > sysctl_local_port_range[1])) { - idr_remove(ps, port); + if (port > sysctl_local_port_range[1]) { + if (next_port != sysctl_local_port_range[0]) { + idr_remove(ps, port); + next_port = sysctl_local_port_range[0]; + goto retry; + } ret = -EADDRNOTAVAIL; - goto err; + goto err2; } + if (port == sysctl_local_port_range[1]) + next_port = sysctl_local_port_range[0]; + else + next_port = port + 1; + bind_list->ps = ps; bind_list->port = (unsigned short) port; cma_bind_port(bind_list, id_priv); return 0; -err: +err2: + idr_remove(ps, port); +err1: kfree(bind_list); return ret; } @@ -1811,7 +1853,7 @@ static int cma_get_port(struct rdma_id_p mutex_lock(&lock); if (cma_any_port(&id_priv->id.route.addr.src_addr)) - ret = cma_alloc_port(ps, id_priv, 0); + ret = cma_alloc_any_port(ps, id_priv); else ret = cma_use_port(ps, id_priv); mutex_unlock(&lock); @@ -2448,7 +2490,11 @@ static int cma_init(void) { int ret; - cma_wq = create_singlethread_workqueue("rdma_cm_wq"); + get_random_bytes(&next_port, sizeof next_port); + next_port = (next_port % (sysctl_local_port_range[1] - + sysctl_local_port_range[0])) + + sysctl_local_port_range[0]; + cma_wq = create_singlethread_workqueue("rdma_cm"); if (!cma_wq) return -ENOMEM; diff --git a/drivers/infiniband/core/device.c b/drivers/infiniband/core/device.c index 63d2a39..7fabb42 100644 --- a/drivers/infiniband/core/device.c +++ b/drivers/infiniband/core/device.c @@ -36,6 +36,7 @@ #include #include #include +#include #include #include #include @@ -93,7 +94,7 @@ #define IB_MANDATORY_FUNC(x) { offsetof( }; int i; - for (i = 0; i < sizeof mandatory_table / sizeof mandatory_table[0]; ++i) { + for (i = 0; i < ARRAY_SIZE(mandatory_table); ++i) { if (!*(void **) ((void *) device + mandatory_table[i].offset)) { printk(KERN_WARNING "Device %s is missing mandatory function %s\n", device->name, mandatory_table[i].name); diff --git a/drivers/infiniband/core/mad.c b/drivers/infiniband/core/mad.c index 5ed141e..13efd41 100644 --- a/drivers/infiniband/core/mad.c +++ b/drivers/infiniband/core/mad.c @@ -642,7 +642,8 @@ static void snoop_recv(struct ib_mad_qp_ spin_unlock_irqrestore(&qp_info->snoop_lock, flags); } -static void build_smp_wc(u64 wr_id, u16 slid, u16 pkey_index, u8 port_num, +static void build_smp_wc(struct ib_qp *qp, + u64 wr_id, u16 slid, u16 pkey_index, u8 port_num, struct ib_wc *wc) { memset(wc, 0, sizeof *wc); @@ -652,7 +653,7 @@ static void build_smp_wc(u64 wr_id, u16 wc->pkey_index = pkey_index; wc->byte_len = sizeof(struct ib_mad) + sizeof(struct ib_grh); wc->src_qp = IB_QP0; - wc->qp_num = IB_QP0; + wc->qp = qp; wc->slid = slid; wc->sl = 0; wc->dlid_path_bits = 0; @@ -713,7 +714,8 @@ static int handle_outgoing_dr_smp(struct goto out; } - build_smp_wc(send_wr->wr_id, be16_to_cpu(smp->dr_slid), + build_smp_wc(mad_agent_priv->agent.qp, + send_wr->wr_id, be16_to_cpu(smp->dr_slid), send_wr->wr.ud.pkey_index, send_wr->wr.ud.port_num, &mad_wc); @@ -2355,7 +2357,8 @@ static void local_completions(struct wor * Defined behavior is to complete response * before request */ - build_smp_wc((unsigned long) local->mad_send_wr, + build_smp_wc(recv_mad_agent->agent.qp, + (unsigned long) local->mad_send_wr, be16_to_cpu(IB_LID_PERMISSIVE), 0, recv_mad_agent->agent.port_num, &wc); diff --git a/drivers/infiniband/core/ucm.c b/drivers/infiniband/core/ucm.c index f15220a..ee51d79 100644 --- a/drivers/infiniband/core/ucm.c +++ b/drivers/infiniband/core/ucm.c @@ -1221,7 +1221,7 @@ static void ib_ucm_release_class_dev(str kfree(dev); } -static struct file_operations ucm_fops = { +static const struct file_operations ucm_fops = { .owner = THIS_MODULE, .open = ib_ucm_open, .release = ib_ucm_close, diff --git a/drivers/infiniband/core/ucma.c b/drivers/infiniband/core/ucma.c index e2e8d32..6b81b98 100644 --- a/drivers/infiniband/core/ucma.c +++ b/drivers/infiniband/core/ucma.c @@ -833,7 +833,7 @@ static int ucma_close(struct inode *inod return 0; } -static struct file_operations ucma_fops = { +static const struct file_operations ucma_fops = { .owner = THIS_MODULE, .open = ucma_open, .release = ucma_close, diff --git a/drivers/infiniband/core/user_mad.c b/drivers/infiniband/core/user_mad.c index 807fbd6..c069ebe 100644 --- a/drivers/infiniband/core/user_mad.c +++ b/drivers/infiniband/core/user_mad.c @@ -771,7 +771,7 @@ static int ib_umad_close(struct inode *i return 0; } -static struct file_operations umad_fops = { +static const struct file_operations umad_fops = { .owner = THIS_MODULE, .read = ib_umad_read, .write = ib_umad_write, @@ -846,7 +846,7 @@ static int ib_umad_sm_close(struct inode return ret; } -static struct file_operations umad_sm_fops = { +static const struct file_operations umad_sm_fops = { .owner = THIS_MODULE, .open = ib_umad_sm_open, .release = ib_umad_sm_close diff --git a/drivers/infiniband/core/uverbs_cmd.c b/drivers/infiniband/core/uverbs_cmd.c index 743247e..df1efbc 100644 --- a/drivers/infiniband/core/uverbs_cmd.c +++ b/drivers/infiniband/core/uverbs_cmd.c @@ -933,7 +933,7 @@ ssize_t ib_uverbs_poll_cq(struct ib_uver resp->wc[i].vendor_err = wc[i].vendor_err; resp->wc[i].byte_len = wc[i].byte_len; resp->wc[i].imm_data = (__u32 __force) wc[i].imm_data; - resp->wc[i].qp_num = wc[i].qp_num; + resp->wc[i].qp_num = wc[i].qp->qp_num; resp->wc[i].src_qp = wc[i].src_qp; resp->wc[i].wc_flags = wc[i].wc_flags; resp->wc[i].pkey_index = wc[i].pkey_index; diff --git a/drivers/infiniband/core/uverbs_main.c b/drivers/infiniband/core/uverbs_main.c index a617ca7..f8bc822 100644 --- a/drivers/infiniband/core/uverbs_main.c +++ b/drivers/infiniband/core/uverbs_main.c @@ -375,7 +375,7 @@ static int ib_uverbs_event_close(struct return 0; } -static struct file_operations uverbs_event_fops = { +static const struct file_operations uverbs_event_fops = { .owner = THIS_MODULE, .read = ib_uverbs_event_read, .poll = ib_uverbs_event_poll, @@ -679,14 +679,14 @@ static int ib_uverbs_close(struct inode return 0; } -static struct file_operations uverbs_fops = { +static const struct file_operations uverbs_fops = { .owner = THIS_MODULE, .write = ib_uverbs_write, .open = ib_uverbs_open, .release = ib_uverbs_close }; -static struct file_operations uverbs_mmap_fops = { +static const struct file_operations uverbs_mmap_fops = { .owner = THIS_MODULE, .write = ib_uverbs_write, .mmap = ib_uverbs_mmap, diff --git a/drivers/infiniband/hw/amso1100/c2.c b/drivers/infiniband/hw/amso1100/c2.c index 27fe242..59243d9 100644 --- a/drivers/infiniband/hw/amso1100/c2.c +++ b/drivers/infiniband/hw/amso1100/c2.c @@ -1073,7 +1073,7 @@ static int __devinit c2_probe(struct pci 0xffffc000) / sizeof(struct c2_rxp_desc); /* Request an interrupt line for the driver */ - ret = request_irq(pcidev->irq, c2_interrupt, SA_SHIRQ, DRV_NAME, c2dev); + ret = request_irq(pcidev->irq, c2_interrupt, IRQF_SHARED, DRV_NAME, c2dev); if (ret) { printk(KERN_ERR PFX "%s: requested IRQ %u is busy\n", pci_name(pcidev), pcidev->irq); diff --git a/drivers/infiniband/hw/amso1100/c2_cq.c b/drivers/infiniband/hw/amso1100/c2_cq.c index 05c9154..5175c99 100644 --- a/drivers/infiniband/hw/amso1100/c2_cq.c +++ b/drivers/infiniband/hw/amso1100/c2_cq.c @@ -153,7 +153,7 @@ static inline int c2_poll_one(struct c2_ entry->status = c2_cqe_status_to_openib(c2_wr_get_result(ce)); entry->wr_id = ce->hdr.context; - entry->qp_num = ce->handle; + entry->qp = &qp->ibqp; entry->wc_flags = 0; entry->slid = 0; entry->sl = 0; diff --git a/drivers/infiniband/hw/cxgb3/Kconfig b/drivers/infiniband/hw/cxgb3/Kconfig new file mode 100644 index 0000000..77977f5 --- /dev/null +++ b/drivers/infiniband/hw/cxgb3/Kconfig @@ -0,0 +1,27 @@ +config INFINIBAND_CXGB3 + tristate "Chelsio RDMA Driver" + depends on CHELSIO_T3 && INFINIBAND && INET + select GENERIC_ALLOCATOR + ---help--- + This is an iWARP/RDMA driver for the Chelsio T3 1GbE and + 10GbE adapters. + + For general information about Chelsio and our products, visit + our website at . + + For customer support, please visit our customer support page at + . + + Please send feedback to . + + To compile this driver as a module, choose M here: the module + will be called iw_cxgb3. + +config INFINIBAND_CXGB3_DEBUG + bool "Verbose debugging output" + depends on INFINIBAND_CXGB3 + default n + ---help--- + This option causes the Chelsio RDMA driver to produce copious + amounts of debug messages. Select this if you are developing + the driver or trying to diagnose a problem. diff --git a/drivers/infiniband/hw/cxgb3/Makefile b/drivers/infiniband/hw/cxgb3/Makefile new file mode 100644 index 0000000..0e110f3 --- /dev/null +++ b/drivers/infiniband/hw/cxgb3/Makefile @@ -0,0 +1,12 @@ +EXTRA_CFLAGS += -I$(TOPDIR)/drivers/net/cxgb3 \ + -I$(TOPDIR)/drivers/infiniband/hw/cxgb3/core + +obj-$(CONFIG_INFINIBAND_CXGB3) += iw_cxgb3.o + +iw_cxgb3-y := iwch_cm.o iwch_ev.o iwch_cq.o iwch_qp.o iwch_mem.o \ + iwch_provider.o iwch.o cxio_hal.o cxio_resource.o + +ifdef CONFIG_INFINIBAND_CXGB3_DEBUG +EXTRA_CFLAGS += -DDEBUG +iw_cxgb3-y += cxio_dbg.o +endif diff --git a/drivers/infiniband/hw/cxgb3/cxio_dbg.c b/drivers/infiniband/hw/cxgb3/cxio_dbg.c new file mode 100644 index 0000000..5a7306f --- /dev/null +++ b/drivers/infiniband/hw/cxgb3/cxio_dbg.c @@ -0,0 +1,207 @@ +/* + * Copyright (c) 2006 Chelsio, Inc. All rights reserved. + * Copyright (c) 2006 Open Grid Computing, Inc. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +#ifdef DEBUG +#include +#include "common.h" +#include "cxgb3_ioctl.h" +#include "cxio_hal.h" +#include "cxio_wr.h" + +void cxio_dump_tpt(struct cxio_rdev *rdev, u32 stag) +{ + struct ch_mem_range *m; + u64 *data; + int rc; + int size = 32; + + m = kmalloc(sizeof(*m) + size, GFP_ATOMIC); + if (!m) { + PDBG("%s couldn't allocate memory.\n", __FUNCTION__); + return; + } + m->mem_id = MEM_PMRX; + m->addr = (stag>>8) * 32 + rdev->rnic_info.tpt_base; + m->len = size; + PDBG("%s TPT addr 0x%x len %d\n", __FUNCTION__, m->addr, m->len); + rc = rdev->t3cdev_p->ctl(rdev->t3cdev_p, RDMA_GET_MEM, m); + if (rc) { + PDBG("%s toectl returned error %d\n", __FUNCTION__, rc); + kfree(m); + return; + } + + data = (u64 *)m->buf; + while (size > 0) { + PDBG("TPT %08x: %016llx\n", m->addr, (unsigned long long) *data); + size -= 8; + data++; + m->addr += 8; + } + kfree(m); +} + +void cxio_dump_pbl(struct cxio_rdev *rdev, u32 pbl_addr, uint len, u8 shift) +{ + struct ch_mem_range *m; + u64 *data; + int rc; + int size, npages; + + shift += 12; + npages = (len + (1ULL << shift) - 1) >> shift; + size = npages * sizeof(u64); + + m = kmalloc(sizeof(*m) + size, GFP_ATOMIC); + if (!m) { + PDBG("%s couldn't allocate memory.\n", __FUNCTION__); + return; + } + m->mem_id = MEM_PMRX; + m->addr = pbl_addr; + m->len = size; + PDBG("%s PBL addr 0x%x len %d depth %d\n", + __FUNCTION__, m->addr, m->len, npages); + rc = rdev->t3cdev_p->ctl(rdev->t3cdev_p, RDMA_GET_MEM, m); + if (rc) { + PDBG("%s toectl returned error %d\n", __FUNCTION__, rc); + kfree(m); + return; + } + + data = (u64 *)m->buf; + while (size > 0) { + PDBG("PBL %08x: %016llx\n", m->addr, (unsigned long long) *data); + size -= 8; + data++; + m->addr += 8; + } + kfree(m); +} + +void cxio_dump_wqe(union t3_wr *wqe) +{ + __be64 *data = (__be64 *)wqe; + uint size = (uint)(be64_to_cpu(*data) & 0xff); + + if (size == 0) + size = 8; + while (size > 0) { + PDBG("WQE %p: %016llx\n", data, + (unsigned long long) be64_to_cpu(*data)); + size--; + data++; + } +} + +void cxio_dump_wce(struct t3_cqe *wce) +{ + __be64 *data = (__be64 *)wce; + int size = sizeof(*wce); + + while (size > 0) { + PDBG("WCE %p: %016llx\n", data, + (unsigned long long) be64_to_cpu(*data)); + size -= 8; + data++; + } +} + +void cxio_dump_rqt(struct cxio_rdev *rdev, u32 hwtid, int nents) +{ + struct ch_mem_range *m; + int size = nents * 64; + u64 *data; + int rc; + + m = kmalloc(sizeof(*m) + size, GFP_ATOMIC); + if (!m) { + PDBG("%s couldn't allocate memory.\n", __FUNCTION__); + return; + } + m->mem_id = MEM_PMRX; + m->addr = ((hwtid)<<10) + rdev->rnic_info.rqt_base; + m->len = size; + PDBG("%s RQT addr 0x%x len %d\n", __FUNCTION__, m->addr, m->len); + rc = rdev->t3cdev_p->ctl(rdev->t3cdev_p, RDMA_GET_MEM, m); + if (rc) { + PDBG("%s toectl returned error %d\n", __FUNCTION__, rc); + kfree(m); + return; + } + + data = (u64 *)m->buf; + while (size > 0) { + PDBG("RQT %08x: %016llx\n", m->addr, (unsigned long long) *data); + size -= 8; + data++; + m->addr += 8; + } + kfree(m); +} + +void cxio_dump_tcb(struct cxio_rdev *rdev, u32 hwtid) +{ + struct ch_mem_range *m; + int size = TCB_SIZE; + u32 *data; + int rc; + + m = kmalloc(sizeof(*m) + size, GFP_ATOMIC); + if (!m) { + PDBG("%s couldn't allocate memory.\n", __FUNCTION__); + return; + } + m->mem_id = MEM_CM; + m->addr = hwtid * size; + m->len = size; + PDBG("%s TCB %d len %d\n", __FUNCTION__, m->addr, m->len); + rc = rdev->t3cdev_p->ctl(rdev->t3cdev_p, RDMA_GET_MEM, m); + if (rc) { + PDBG("%s toectl returned error %d\n", __FUNCTION__, rc); + kfree(m); + return; + } + + data = (u32 *)m->buf; + while (size > 0) { + printk("%2u: %08x %08x %08x %08x %08x %08x %08x %08x\n", + m->addr, + *(data+2), *(data+3), *(data),*(data+1), + *(data+6), *(data+7), *(data+4), *(data+5)); + size -= 32; + data += 8; + m->addr += 32; + } + kfree(m); +} +#endif diff --git a/drivers/infiniband/hw/cxgb3/cxio_hal.c b/drivers/infiniband/hw/cxgb3/cxio_hal.c new file mode 100644 index 0000000..82fa720 --- /dev/null +++ b/drivers/infiniband/hw/cxgb3/cxio_hal.c @@ -0,0 +1,1280 @@ +/* + * Copyright (c) 2006 Chelsio, Inc. All rights reserved. + * Copyright (c) 2006 Open Grid Computing, Inc. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +#include + +#include +#include +#include +#include +#include + +#include "cxio_resource.h" +#include "cxio_hal.h" +#include "cxgb3_offload.h" +#include "sge_defs.h" + +static LIST_HEAD(rdev_list); +static cxio_hal_ev_callback_func_t cxio_ev_cb = NULL; + +static inline struct cxio_rdev *cxio_hal_find_rdev_by_name(char *dev_name) +{ + struct cxio_rdev *rdev; + + list_for_each_entry(rdev, &rdev_list, entry) + if (!strcmp(rdev->dev_name, dev_name)) + return rdev; + return NULL; +} + +static inline struct cxio_rdev *cxio_hal_find_rdev_by_t3cdev(struct t3cdev + *tdev) +{ + struct cxio_rdev *rdev; + + list_for_each_entry(rdev, &rdev_list, entry) + if (rdev->t3cdev_p == tdev) + return rdev; + return NULL; +} + +int cxio_hal_cq_op(struct cxio_rdev *rdev_p, struct t3_cq *cq, + enum t3_cq_opcode op, u32 credit) +{ + int ret; + struct t3_cqe *cqe; + u32 rptr; + + struct rdma_cq_op setup; + setup.id = cq->cqid; + setup.credits = (op == CQ_CREDIT_UPDATE) ? credit : 0; + setup.op = op; + ret = rdev_p->t3cdev_p->ctl(rdev_p->t3cdev_p, RDMA_CQ_OP, &setup); + + if ((ret < 0) || (op == CQ_CREDIT_UPDATE)) + return ret; + + /* + * If the rearm returned an index other than our current index, + * then there might be CQE's in flight (being DMA'd). We must wait + * here for them to complete or the consumer can miss a notification. + */ + if (Q_PTR2IDX((cq->rptr), cq->size_log2) != ret) { + int i=0; + + rptr = cq->rptr; + + /* + * Keep the generation correct by bumping rptr until it + * matches the index returned by the rearm - 1. + */ + while (Q_PTR2IDX((rptr+1), cq->size_log2) != ret) + rptr++; + + /* + * Now rptr is the index for the (last) cqe that was + * in-flight at the time the HW rearmed the CQ. We + * spin until that CQE is valid. + */ + cqe = cq->queue + Q_PTR2IDX(rptr, cq->size_log2); + while (!CQ_VLD_ENTRY(rptr, cq->size_log2, cqe)) { + udelay(1); + if (i++ > 1000000) { + BUG_ON(1); + printk(KERN_ERR "%s: stalled rnic\n", + rdev_p->dev_name); + return -EIO; + } + } + } + return 0; +} + +static inline int cxio_hal_clear_cq_ctx(struct cxio_rdev *rdev_p, u32 cqid) +{ + struct rdma_cq_setup setup; + setup.id = cqid; + setup.base_addr = 0; /* NULL address */ + setup.size = 0; /* disaable the CQ */ + setup.credits = 0; + setup.credit_thres = 0; + setup.ovfl_mode = 0; + return (rdev_p->t3cdev_p->ctl(rdev_p->t3cdev_p, RDMA_CQ_SETUP, &setup)); +} + +int cxio_hal_clear_qp_ctx(struct cxio_rdev *rdev_p, u32 qpid) +{ + u64 sge_cmd; + struct t3_modify_qp_wr *wqe; + struct sk_buff *skb = alloc_skb(sizeof(*wqe), GFP_KERNEL); + if (!skb) { + PDBG("%s alloc_skb failed\n", __FUNCTION__); + return -ENOMEM; + } + wqe = (struct t3_modify_qp_wr *) skb_put(skb, sizeof(*wqe)); + memset(wqe, 0, sizeof(*wqe)); + build_fw_riwrh((struct fw_riwrh *) wqe, T3_WR_QP_MOD, 3, 1, qpid, 7); + wqe->flags = cpu_to_be32(MODQP_WRITE_EC); + sge_cmd = qpid << 8 | 3; + wqe->sge_cmd = cpu_to_be64(sge_cmd); + skb->priority = CPL_PRIORITY_CONTROL; + return (cxgb3_ofld_send(rdev_p->t3cdev_p, skb)); +} + +int cxio_create_cq(struct cxio_rdev *rdev_p, struct t3_cq *cq) +{ + struct rdma_cq_setup setup; + int size = (1UL << (cq->size_log2)) * sizeof(struct t3_cqe); + + cq->cqid = cxio_hal_get_cqid(rdev_p->rscp); + if (!cq->cqid) + return -ENOMEM; + cq->sw_queue = kzalloc(size, GFP_KERNEL); + if (!cq->sw_queue) + return -ENOMEM; + cq->queue = dma_alloc_coherent(&(rdev_p->rnic_info.pdev->dev), + (1UL << (cq->size_log2)) * + sizeof(struct t3_cqe), + &(cq->dma_addr), GFP_KERNEL); + if (!cq->queue) { + kfree(cq->sw_queue); + return -ENOMEM; + } + pci_unmap_addr_set(cq, mapping, cq->dma_addr); + memset(cq->queue, 0, size); + setup.id = cq->cqid; + setup.base_addr = (u64) (cq->dma_addr); + setup.size = 1UL << cq->size_log2; + setup.credits = 65535; + setup.credit_thres = 1; + if (rdev_p->t3cdev_p->type == T3B) + setup.ovfl_mode = 0; + else + setup.ovfl_mode = 1; + return (rdev_p->t3cdev_p->ctl(rdev_p->t3cdev_p, RDMA_CQ_SETUP, &setup)); +} + +int cxio_resize_cq(struct cxio_rdev *rdev_p, struct t3_cq *cq) +{ + struct rdma_cq_setup setup; + setup.id = cq->cqid; + setup.base_addr = (u64) (cq->dma_addr); + setup.size = 1UL << cq->size_log2; + setup.credits = setup.size; + setup.credit_thres = setup.size; /* TBD: overflow recovery */ + setup.ovfl_mode = 1; + return (rdev_p->t3cdev_p->ctl(rdev_p->t3cdev_p, RDMA_CQ_SETUP, &setup)); +} + +static u32 get_qpid(struct cxio_rdev *rdev_p, struct cxio_ucontext *uctx) +{ + struct cxio_qpid_list *entry; + u32 qpid; + int i; + + mutex_lock(&uctx->lock); + if (!list_empty(&uctx->qpids)) { + entry = list_entry(uctx->qpids.next, struct cxio_qpid_list, + entry); + list_del(&entry->entry); + qpid = entry->qpid; + kfree(entry); + } else { + qpid = cxio_hal_get_qpid(rdev_p->rscp); + if (!qpid) + goto out; + for (i = qpid+1; i & rdev_p->qpmask; i++) { + entry = kmalloc(sizeof *entry, GFP_KERNEL); + if (!entry) + break; + entry->qpid = i; + list_add_tail(&entry->entry, &uctx->qpids); + } + } +out: + mutex_unlock(&uctx->lock); + PDBG("%s qpid 0x%x\n", __FUNCTION__, qpid); + return qpid; +} + +static void put_qpid(struct cxio_rdev *rdev_p, u32 qpid, + struct cxio_ucontext *uctx) +{ + struct cxio_qpid_list *entry; + + entry = kmalloc(sizeof *entry, GFP_KERNEL); + if (!entry) + return; + PDBG("%s qpid 0x%x\n", __FUNCTION__, qpid); + entry->qpid = qpid; + mutex_lock(&uctx->lock); + list_add_tail(&entry->entry, &uctx->qpids); + mutex_unlock(&uctx->lock); +} + +void cxio_release_ucontext(struct cxio_rdev *rdev_p, struct cxio_ucontext *uctx) +{ + struct list_head *pos, *nxt; + struct cxio_qpid_list *entry; + + mutex_lock(&uctx->lock); + list_for_each_safe(pos, nxt, &uctx->qpids) { + entry = list_entry(pos, struct cxio_qpid_list, entry); + list_del_init(&entry->entry); + if (!(entry->qpid & rdev_p->qpmask)) + cxio_hal_put_qpid(rdev_p->rscp, entry->qpid); + kfree(entry); + } + mutex_unlock(&uctx->lock); +} + +void cxio_init_ucontext(struct cxio_rdev *rdev_p, struct cxio_ucontext *uctx) +{ + INIT_LIST_HEAD(&uctx->qpids); + mutex_init(&uctx->lock); +} + +int cxio_create_qp(struct cxio_rdev *rdev_p, u32 kernel_domain, + struct t3_wq *wq, struct cxio_ucontext *uctx) +{ + int depth = 1UL << wq->size_log2; + int rqsize = 1UL << wq->rq_size_log2; + + wq->qpid = get_qpid(rdev_p, uctx); + if (!wq->qpid) + return -ENOMEM; + + wq->rq = kzalloc(depth * sizeof(u64), GFP_KERNEL); + if (!wq->rq) + goto err1; + + wq->rq_addr = cxio_hal_rqtpool_alloc(rdev_p, rqsize); + if (!wq->rq_addr) + goto err2; + + wq->sq = kzalloc(depth * sizeof(struct t3_swsq), GFP_KERNEL); + if (!wq->sq) + goto err3; + + wq->queue = dma_alloc_coherent(&(rdev_p->rnic_info.pdev->dev), + depth * sizeof(union t3_wr), + &(wq->dma_addr), GFP_KERNEL); + if (!wq->queue) + goto err4; + + memset(wq->queue, 0, depth * sizeof(union t3_wr)); + pci_unmap_addr_set(wq, mapping, wq->dma_addr); + wq->doorbell = (void __iomem *)rdev_p->rnic_info.kdb_addr; + if (!kernel_domain) + wq->udb = (u64)rdev_p->rnic_info.udbell_physbase + + (wq->qpid << rdev_p->qpshift); + PDBG("%s qpid 0x%x doorbell 0x%p udb 0x%llx\n", __FUNCTION__, + wq->qpid, wq->doorbell, (unsigned long long) wq->udb); + return 0; +err4: + kfree(wq->sq); +err3: + cxio_hal_rqtpool_free(rdev_p, wq->rq_addr, rqsize); +err2: + kfree(wq->rq); +err1: + put_qpid(rdev_p, wq->qpid, uctx); + return -ENOMEM; +} + +int cxio_destroy_cq(struct cxio_rdev *rdev_p, struct t3_cq *cq) +{ + int err; + err = cxio_hal_clear_cq_ctx(rdev_p, cq->cqid); + kfree(cq->sw_queue); + dma_free_coherent(&(rdev_p->rnic_info.pdev->dev), + (1UL << (cq->size_log2)) + * sizeof(struct t3_cqe), cq->queue, + pci_unmap_addr(cq, mapping)); + cxio_hal_put_cqid(rdev_p->rscp, cq->cqid); + return err; +} + +int cxio_destroy_qp(struct cxio_rdev *rdev_p, struct t3_wq *wq, + struct cxio_ucontext *uctx) +{ + dma_free_coherent(&(rdev_p->rnic_info.pdev->dev), + (1UL << (wq->size_log2)) + * sizeof(union t3_wr), wq->queue, + pci_unmap_addr(wq, mapping)); + kfree(wq->sq); + cxio_hal_rqtpool_free(rdev_p, wq->rq_addr, (1UL << wq->rq_size_log2)); + kfree(wq->rq); + put_qpid(rdev_p, wq->qpid, uctx); + return 0; +} + +static void insert_recv_cqe(struct t3_wq *wq, struct t3_cq *cq) +{ + struct t3_cqe cqe; + + PDBG("%s wq %p cq %p sw_rptr 0x%x sw_wptr 0x%x\n", __FUNCTION__, + wq, cq, cq->sw_rptr, cq->sw_wptr); + memset(&cqe, 0, sizeof(cqe)); + cqe.header = cpu_to_be32(V_CQE_STATUS(TPT_ERR_SWFLUSH) | + V_CQE_OPCODE(T3_SEND) | + V_CQE_TYPE(0) | + V_CQE_SWCQE(1) | + V_CQE_QPID(wq->qpid) | + V_CQE_GENBIT(Q_GENBIT(cq->sw_wptr, + cq->size_log2))); + *(cq->sw_queue + Q_PTR2IDX(cq->sw_wptr, cq->size_log2)) = cqe; + cq->sw_wptr++; +} + +void cxio_flush_rq(struct t3_wq *wq, struct t3_cq *cq, int count) +{ + u32 ptr; + + PDBG("%s wq %p cq %p\n", __FUNCTION__, wq, cq); + + /* flush RQ */ + PDBG("%s rq_rptr %u rq_wptr %u skip count %u\n", __FUNCTION__, + wq->rq_rptr, wq->rq_wptr, count); + ptr = wq->rq_rptr + count; + while (ptr++ != wq->rq_wptr) + insert_recv_cqe(wq, cq); +} + +static void insert_sq_cqe(struct t3_wq *wq, struct t3_cq *cq, + struct t3_swsq *sqp) +{ + struct t3_cqe cqe; + + PDBG("%s wq %p cq %p sw_rptr 0x%x sw_wptr 0x%x\n", __FUNCTION__, + wq, cq, cq->sw_rptr, cq->sw_wptr); + memset(&cqe, 0, sizeof(cqe)); + cqe.header = cpu_to_be32(V_CQE_STATUS(TPT_ERR_SWFLUSH) | + V_CQE_OPCODE(sqp->opcode) | + V_CQE_TYPE(1) | + V_CQE_SWCQE(1) | + V_CQE_QPID(wq->qpid) | + V_CQE_GENBIT(Q_GENBIT(cq->sw_wptr, + cq->size_log2))); + cqe.u.scqe.wrid_hi = sqp->sq_wptr; + + *(cq->sw_queue + Q_PTR2IDX(cq->sw_wptr, cq->size_log2)) = cqe; + cq->sw_wptr++; +} + +void cxio_flush_sq(struct t3_wq *wq, struct t3_cq *cq, int count) +{ + __u32 ptr; + struct t3_swsq *sqp = wq->sq + Q_PTR2IDX(wq->sq_rptr, wq->sq_size_log2); + + ptr = wq->sq_rptr + count; + sqp += count; + while (ptr != wq->sq_wptr) { + insert_sq_cqe(wq, cq, sqp); + sqp++; + ptr++; + } +} + +/* + * Move all CQEs from the HWCQ into the SWCQ. + */ +void cxio_flush_hw_cq(struct t3_cq *cq) +{ + struct t3_cqe *cqe, *swcqe; + + PDBG("%s cq %p cqid 0x%x\n", __FUNCTION__, cq, cq->cqid); + cqe = cxio_next_hw_cqe(cq); + while (cqe) { + PDBG("%s flushing hwcq rptr 0x%x to swcq wptr 0x%x\n", + __FUNCTION__, cq->rptr, cq->sw_wptr); + swcqe = cq->sw_queue + Q_PTR2IDX(cq->sw_wptr, cq->size_log2); + *swcqe = *cqe; + swcqe->header |= cpu_to_be32(V_CQE_SWCQE(1)); + cq->sw_wptr++; + cq->rptr++; + cqe = cxio_next_hw_cqe(cq); + } +} + +static inline int cqe_completes_wr(struct t3_cqe *cqe, struct t3_wq *wq) +{ + if (CQE_OPCODE(*cqe) == T3_TERMINATE) + return 0; + + if ((CQE_OPCODE(*cqe) == T3_RDMA_WRITE) && RQ_TYPE(*cqe)) + return 0; + + if ((CQE_OPCODE(*cqe) == T3_READ_RESP) && SQ_TYPE(*cqe)) + return 0; + + if ((CQE_OPCODE(*cqe) == T3_SEND) && RQ_TYPE(*cqe) && + Q_EMPTY(wq->rq_rptr, wq->rq_wptr)) + return 0; + + return 1; +} + +void cxio_count_scqes(struct t3_cq *cq, struct t3_wq *wq, int *count) +{ + struct t3_cqe *cqe; + u32 ptr; + + *count = 0; + ptr = cq->sw_rptr; + while (!Q_EMPTY(ptr, cq->sw_wptr)) { + cqe = cq->sw_queue + (Q_PTR2IDX(ptr, cq->size_log2)); + if ((SQ_TYPE(*cqe) || (CQE_OPCODE(*cqe) == T3_READ_RESP)) && + (CQE_QPID(*cqe) == wq->qpid)) + (*count)++; + ptr++; + } + PDBG("%s cq %p count %d\n", __FUNCTION__, cq, *count); +} + +void cxio_count_rcqes(struct t3_cq *cq, struct t3_wq *wq, int *count) +{ + struct t3_cqe *cqe; + u32 ptr; + + *count = 0; + PDBG("%s count zero %d\n", __FUNCTION__, *count); + ptr = cq->sw_rptr; + while (!Q_EMPTY(ptr, cq->sw_wptr)) { + cqe = cq->sw_queue + (Q_PTR2IDX(ptr, cq->size_log2)); + if (RQ_TYPE(*cqe) && (CQE_OPCODE(*cqe) != T3_READ_RESP) && + (CQE_QPID(*cqe) == wq->qpid) && cqe_completes_wr(cqe, wq)) + (*count)++; + ptr++; + } + PDBG("%s cq %p count %d\n", __FUNCTION__, cq, *count); +} + +static int cxio_hal_init_ctrl_cq(struct cxio_rdev *rdev_p) +{ + struct rdma_cq_setup setup; + setup.id = 0; + setup.base_addr = 0; /* NULL address */ + setup.size = 1; /* enable the CQ */ + setup.credits = 0; + + /* force SGE to redirect to RspQ and interrupt */ + setup.credit_thres = 0; + setup.ovfl_mode = 1; + return (rdev_p->t3cdev_p->ctl(rdev_p->t3cdev_p, RDMA_CQ_SETUP, &setup)); +} + +static int cxio_hal_init_ctrl_qp(struct cxio_rdev *rdev_p) +{ + int err; + u64 sge_cmd, ctx0, ctx1; + u64 base_addr; + struct t3_modify_qp_wr *wqe; + struct sk_buff *skb = alloc_skb(sizeof(*wqe), GFP_KERNEL); + + + if (!skb) { + PDBG("%s alloc_skb failed\n", __FUNCTION__); + return -ENOMEM; + } + err = cxio_hal_init_ctrl_cq(rdev_p); + if (err) { + PDBG("%s err %d initializing ctrl_cq\n", __FUNCTION__, err); + return err; + } + rdev_p->ctrl_qp.workq = dma_alloc_coherent( + &(rdev_p->rnic_info.pdev->dev), + (1 << T3_CTRL_QP_SIZE_LOG2) * + sizeof(union t3_wr), + &(rdev_p->ctrl_qp.dma_addr), + GFP_KERNEL); + if (!rdev_p->ctrl_qp.workq) { + PDBG("%s dma_alloc_coherent failed\n", __FUNCTION__); + return -ENOMEM; + } + pci_unmap_addr_set(&rdev_p->ctrl_qp, mapping, + rdev_p->ctrl_qp.dma_addr); + rdev_p->ctrl_qp.doorbell = (void __iomem *)rdev_p->rnic_info.kdb_addr; + memset(rdev_p->ctrl_qp.workq, 0, + (1 << T3_CTRL_QP_SIZE_LOG2) * sizeof(union t3_wr)); + + mutex_init(&rdev_p->ctrl_qp.lock); + init_waitqueue_head(&rdev_p->ctrl_qp.waitq); + + /* update HW Ctrl QP context */ + base_addr = rdev_p->ctrl_qp.dma_addr; + base_addr >>= 12; + ctx0 = (V_EC_SIZE((1 << T3_CTRL_QP_SIZE_LOG2)) | + V_EC_BASE_LO((u32) base_addr & 0xffff)); + ctx0 <<= 32; + ctx0 |= V_EC_CREDITS(FW_WR_NUM); + base_addr >>= 16; + ctx1 = (u32) base_addr; + base_addr >>= 32; + ctx1 |= ((u64) (V_EC_BASE_HI((u32) base_addr & 0xf) | V_EC_RESPQ(0) | + V_EC_TYPE(0) | V_EC_GEN(1) | + V_EC_UP_TOKEN(T3_CTL_QP_TID) | F_EC_VALID)) << 32; + wqe = (struct t3_modify_qp_wr *) skb_put(skb, sizeof(*wqe)); + memset(wqe, 0, sizeof(*wqe)); + build_fw_riwrh((struct fw_riwrh *) wqe, T3_WR_QP_MOD, 0, 1, + T3_CTL_QP_TID, 7); + wqe->flags = cpu_to_be32(MODQP_WRITE_EC); + sge_cmd = (3ULL << 56) | FW_RI_SGEEC_START << 8 | 3; + wqe->sge_cmd = cpu_to_be64(sge_cmd); + wqe->ctx1 = cpu_to_be64(ctx1); + wqe->ctx0 = cpu_to_be64(ctx0); + PDBG("CtrlQP dma_addr 0x%llx workq %p size %d\n", + (unsigned long long) rdev_p->ctrl_qp.dma_addr, + rdev_p->ctrl_qp.workq, 1 << T3_CTRL_QP_SIZE_LOG2); + skb->priority = CPL_PRIORITY_CONTROL; + return (cxgb3_ofld_send(rdev_p->t3cdev_p, skb)); +} + +static int cxio_hal_destroy_ctrl_qp(struct cxio_rdev *rdev_p) +{ + dma_free_coherent(&(rdev_p->rnic_info.pdev->dev), + (1UL << T3_CTRL_QP_SIZE_LOG2) + * sizeof(union t3_wr), rdev_p->ctrl_qp.workq, + pci_unmap_addr(&rdev_p->ctrl_qp, mapping)); + return cxio_hal_clear_qp_ctx(rdev_p, T3_CTRL_QP_ID); +} + +/* write len bytes of data into addr (32B aligned address) + * If data is NULL, clear len byte of memory to zero. + * caller aquires the ctrl_qp lock before the call + */ +static int cxio_hal_ctrl_qp_write_mem(struct cxio_rdev *rdev_p, u32 addr, + u32 len, void *data, int completion) +{ + u32 i, nr_wqe, copy_len; + u8 *copy_data; + u8 wr_len, utx_len; /* lenght in 8 byte flit */ + enum t3_wr_flags flag; + __be64 *wqe; + u64 utx_cmd; + addr &= 0x7FFFFFF; + nr_wqe = len % 96 ? len / 96 + 1 : len / 96; /* 96B max per WQE */ + PDBG("%s wptr 0x%x rptr 0x%x len %d, nr_wqe %d data %p addr 0x%0x\n", + __FUNCTION__, rdev_p->ctrl_qp.wptr, rdev_p->ctrl_qp.rptr, len, + nr_wqe, data, addr); + utx_len = 3; /* in 32B unit */ + for (i = 0; i < nr_wqe; i++) { + if (Q_FULL(rdev_p->ctrl_qp.rptr, rdev_p->ctrl_qp.wptr, + T3_CTRL_QP_SIZE_LOG2)) { + PDBG("%s ctrl_qp full wtpr 0x%0x rptr 0x%0x, " + "wait for more space i %d\n", __FUNCTION__, + rdev_p->ctrl_qp.wptr, rdev_p->ctrl_qp.rptr, i); + if (wait_event_interruptible(rdev_p->ctrl_qp.waitq, + !Q_FULL(rdev_p->ctrl_qp.rptr, + rdev_p->ctrl_qp.wptr, + T3_CTRL_QP_SIZE_LOG2))) { + PDBG("%s ctrl_qp workq interrupted\n", + __FUNCTION__); + return -ERESTARTSYS; + } + PDBG("%s ctrl_qp wakeup, continue posting work request " + "i %d\n", __FUNCTION__, i); + } + wqe = (__be64 *)(rdev_p->ctrl_qp.workq + (rdev_p->ctrl_qp.wptr % + (1 << T3_CTRL_QP_SIZE_LOG2))); + flag = 0; + if (i == (nr_wqe - 1)) { + /* last WQE */ + flag = completion ? T3_COMPLETION_FLAG : 0; + if (len % 32) + utx_len = len / 32 + 1; + else + utx_len = len / 32; + } + + /* + * Force a CQE to return the credit to the workq in case + * we posted more than half the max QP size of WRs + */ + if ((i != 0) && + (i % (((1 << T3_CTRL_QP_SIZE_LOG2)) >> 1) == 0)) { + flag = T3_COMPLETION_FLAG; + PDBG("%s force completion at i %d\n", __FUNCTION__, i); + } + + /* build the utx mem command */ + wqe += (sizeof(struct t3_bypass_wr) >> 3); + utx_cmd = (T3_UTX_MEM_WRITE << 28) | (addr + i * 3); + utx_cmd <<= 32; + utx_cmd |= (utx_len << 28) | ((utx_len << 2) + 1); + *wqe = cpu_to_be64(utx_cmd); + wqe++; + copy_data = (u8 *) data + i * 96; + copy_len = len > 96 ? 96 : len; + + /* clear memory content if data is NULL */ + if (data) + memcpy(wqe, copy_data, copy_len); + else + memset(wqe, 0, copy_len); + if (copy_len % 32) + memset(((u8 *) wqe) + copy_len, 0, + 32 - (copy_len % 32)); + wr_len = ((sizeof(struct t3_bypass_wr)) >> 3) + 1 + + (utx_len << 2); + wqe = (__be64 *)(rdev_p->ctrl_qp.workq + (rdev_p->ctrl_qp.wptr % + (1 << T3_CTRL_QP_SIZE_LOG2))); + + /* wptr in the WRID[31:0] */ + ((union t3_wrid *)(wqe+1))->id0.low = rdev_p->ctrl_qp.wptr; + + /* + * This must be the last write with a memory barrier + * for the genbit + */ + build_fw_riwrh((struct fw_riwrh *) wqe, T3_WR_BP, flag, + Q_GENBIT(rdev_p->ctrl_qp.wptr, + T3_CTRL_QP_SIZE_LOG2), T3_CTRL_QP_ID, + wr_len); + if (flag == T3_COMPLETION_FLAG) + ring_doorbell(rdev_p->ctrl_qp.doorbell, T3_CTRL_QP_ID); + len -= 96; + rdev_p->ctrl_qp.wptr++; + } + return 0; +} + +/* IN: stag key, pdid, perm, zbva, to, len, page_size, pbl, and pbl_size + * OUT: stag index, actual pbl_size, pbl_addr allocated. + * TBD: shared memory region support + */ +static int __cxio_tpt_op(struct cxio_rdev *rdev_p, u32 reset_tpt_entry, + u32 *stag, u8 stag_state, u32 pdid, + enum tpt_mem_type type, enum tpt_mem_perm perm, + u32 zbva, u64 to, u32 len, u8 page_size, __be64 *pbl, + u32 *pbl_size, u32 *pbl_addr) +{ + int err; + struct tpt_entry tpt; + u32 stag_idx; + u32 wptr; + int rereg = (*stag != T3_STAG_UNSET); + + stag_state = stag_state > 0; + stag_idx = (*stag) >> 8; + + if ((!reset_tpt_entry) && !(*stag != T3_STAG_UNSET)) { + stag_idx = cxio_hal_get_stag(rdev_p->rscp); + if (!stag_idx) + return -ENOMEM; + *stag = (stag_idx << 8) | ((*stag) & 0xFF); + } + PDBG("%s stag_state 0x%0x type 0x%0x pdid 0x%0x, stag_idx 0x%x\n", + __FUNCTION__, stag_state, type, pdid, stag_idx); + + if (reset_tpt_entry) + cxio_hal_pblpool_free(rdev_p, *pbl_addr, *pbl_size << 3); + else if (!rereg) { + *pbl_addr = cxio_hal_pblpool_alloc(rdev_p, *pbl_size << 3); + if (!*pbl_addr) { + return -ENOMEM; + } + } + + mutex_lock(&rdev_p->ctrl_qp.lock); + + /* write PBL first if any - update pbl only if pbl list exist */ + if (pbl) { + + PDBG("%s *pdb_addr 0x%x, pbl_base 0x%x, pbl_size %d\n", + __FUNCTION__, *pbl_addr, rdev_p->rnic_info.pbl_base, + *pbl_size); + err = cxio_hal_ctrl_qp_write_mem(rdev_p, + (*pbl_addr >> 5), + (*pbl_size << 3), pbl, 0); + if (err) + goto ret; + } + + /* write TPT entry */ + if (reset_tpt_entry) + memset(&tpt, 0, sizeof(tpt)); + else { + tpt.valid_stag_pdid = cpu_to_be32(F_TPT_VALID | + V_TPT_STAG_KEY((*stag) & M_TPT_STAG_KEY) | + V_TPT_STAG_STATE(stag_state) | + V_TPT_STAG_TYPE(type) | V_TPT_PDID(pdid)); + BUG_ON(page_size >= 28); + tpt.flags_pagesize_qpid = cpu_to_be32(V_TPT_PERM(perm) | + F_TPT_MW_BIND_ENABLE | + V_TPT_ADDR_TYPE((zbva ? TPT_ZBTO : TPT_VATO)) | + V_TPT_PAGE_SIZE(page_size)); + tpt.rsvd_pbl_addr = reset_tpt_entry ? 0 : + cpu_to_be32(V_TPT_PBL_ADDR(PBL_OFF(rdev_p, *pbl_addr)>>3)); + tpt.len = cpu_to_be32(len); + tpt.va_hi = cpu_to_be32((u32) (to >> 32)); + tpt.va_low_or_fbo = cpu_to_be32((u32) (to & 0xFFFFFFFFULL)); + tpt.rsvd_bind_cnt_or_pstag = 0; + tpt.rsvd_pbl_size = reset_tpt_entry ? 0 : + cpu_to_be32(V_TPT_PBL_SIZE((*pbl_size) >> 2)); + } + err = cxio_hal_ctrl_qp_write_mem(rdev_p, + stag_idx + + (rdev_p->rnic_info.tpt_base >> 5), + sizeof(tpt), &tpt, 1); + + /* release the stag index to free pool */ + if (reset_tpt_entry) + cxio_hal_put_stag(rdev_p->rscp, stag_idx); +ret: + wptr = rdev_p->ctrl_qp.wptr; + mutex_unlock(&rdev_p->ctrl_qp.lock); + if (!err) + if (wait_event_interruptible(rdev_p->ctrl_qp.waitq, + SEQ32_GE(rdev_p->ctrl_qp.rptr, + wptr))) + return -ERESTARTSYS; + return err; +} + +/* IN : stag key, pdid, pbl_size + * Out: stag index, actaul pbl_size, and pbl_addr allocated. + */ +int cxio_allocate_stag(struct cxio_rdev *rdev_p, u32 * stag, u32 pdid, + enum tpt_mem_perm perm, u32 * pbl_size, u32 * pbl_addr) +{ + *stag = T3_STAG_UNSET; + return (__cxio_tpt_op(rdev_p, 0, stag, 0, pdid, TPT_NON_SHARED_MR, + perm, 0, 0ULL, 0, 0, NULL, pbl_size, pbl_addr)); +} + +int cxio_register_phys_mem(struct cxio_rdev *rdev_p, u32 *stag, u32 pdid, + enum tpt_mem_perm perm, u32 zbva, u64 to, u32 len, + u8 page_size, __be64 *pbl, u32 *pbl_size, + u32 *pbl_addr) +{ + *stag = T3_STAG_UNSET; + return __cxio_tpt_op(rdev_p, 0, stag, 1, pdid, TPT_NON_SHARED_MR, perm, + zbva, to, len, page_size, pbl, pbl_size, pbl_addr); +} + +int cxio_reregister_phys_mem(struct cxio_rdev *rdev_p, u32 *stag, u32 pdid, + enum tpt_mem_perm perm, u32 zbva, u64 to, u32 len, + u8 page_size, __be64 *pbl, u32 *pbl_size, + u32 *pbl_addr) +{ + return __cxio_tpt_op(rdev_p, 0, stag, 1, pdid, TPT_NON_SHARED_MR, perm, + zbva, to, len, page_size, pbl, pbl_size, pbl_addr); +} + +int cxio_dereg_mem(struct cxio_rdev *rdev_p, u32 stag, u32 pbl_size, + u32 pbl_addr) +{ + return __cxio_tpt_op(rdev_p, 1, &stag, 0, 0, 0, 0, 0, 0ULL, 0, 0, NULL, + &pbl_size, &pbl_addr); +} + +int cxio_allocate_window(struct cxio_rdev *rdev_p, u32 * stag, u32 pdid) +{ + u32 pbl_size = 0; + *stag = T3_STAG_UNSET; + return __cxio_tpt_op(rdev_p, 0, stag, 0, pdid, TPT_MW, 0, 0, 0ULL, 0, 0, + NULL, &pbl_size, NULL); +} + +int cxio_deallocate_window(struct cxio_rdev *rdev_p, u32 stag) +{ + return __cxio_tpt_op(rdev_p, 1, &stag, 0, 0, 0, 0, 0, 0ULL, 0, 0, NULL, + NULL, NULL); +} + +int cxio_rdma_init(struct cxio_rdev *rdev_p, struct t3_rdma_init_attr *attr) +{ + struct t3_rdma_init_wr *wqe; + struct sk_buff *skb = alloc_skb(sizeof(*wqe), GFP_ATOMIC); + if (!skb) + return -ENOMEM; + PDBG("%s rdev_p %p\n", __FUNCTION__, rdev_p); + wqe = (struct t3_rdma_init_wr *) __skb_put(skb, sizeof(*wqe)); + wqe->wrh.op_seop_flags = cpu_to_be32(V_FW_RIWR_OP(T3_WR_INIT)); + wqe->wrh.gen_tid_len = cpu_to_be32(V_FW_RIWR_TID(attr->tid) | + V_FW_RIWR_LEN(sizeof(*wqe) >> 3)); + wqe->wrid.id1 = 0; + wqe->qpid = cpu_to_be32(attr->qpid); + wqe->pdid = cpu_to_be32(attr->pdid); + wqe->scqid = cpu_to_be32(attr->scqid); + wqe->rcqid = cpu_to_be32(attr->rcqid); + wqe->rq_addr = cpu_to_be32(attr->rq_addr - rdev_p->rnic_info.rqt_base); + wqe->rq_size = cpu_to_be32(attr->rq_size); + wqe->mpaattrs = attr->mpaattrs; + wqe->qpcaps = attr->qpcaps; + wqe->ulpdu_size = cpu_to_be16(attr->tcp_emss); + wqe->flags = cpu_to_be32(attr->flags); + wqe->ord = cpu_to_be32(attr->ord); + wqe->ird = cpu_to_be32(attr->ird); + wqe->qp_dma_addr = cpu_to_be64(attr->qp_dma_addr); + wqe->qp_dma_size = cpu_to_be32(attr->qp_dma_size); + wqe->rsvd = 0; + skb->priority = 0; /* 0=>ToeQ; 1=>CtrlQ */ + return (cxgb3_ofld_send(rdev_p->t3cdev_p, skb)); +} + +void cxio_register_ev_cb(cxio_hal_ev_callback_func_t ev_cb) +{ + cxio_ev_cb = ev_cb; +} + +void cxio_unregister_ev_cb(cxio_hal_ev_callback_func_t ev_cb) +{ + cxio_ev_cb = NULL; +} + +static int cxio_hal_ev_handler(struct t3cdev *t3cdev_p, struct sk_buff *skb) +{ + static int cnt; + struct cxio_rdev *rdev_p = NULL; + struct respQ_msg_t *rsp_msg = (struct respQ_msg_t *) skb->data; + PDBG("%d: %s cq_id 0x%x cq_ptr 0x%x genbit %0x overflow %0x an %0x" + " se %0x notify %0x cqbranch %0x creditth %0x\n", + cnt, __FUNCTION__, RSPQ_CQID(rsp_msg), RSPQ_CQPTR(rsp_msg), + RSPQ_GENBIT(rsp_msg), RSPQ_OVERFLOW(rsp_msg), RSPQ_AN(rsp_msg), + RSPQ_SE(rsp_msg), RSPQ_NOTIFY(rsp_msg), RSPQ_CQBRANCH(rsp_msg), + RSPQ_CREDIT_THRESH(rsp_msg)); + PDBG("CQE: QPID 0x%0x genbit %0x type 0x%0x status 0x%0x opcode %d " + "len 0x%0x wrid_hi_stag 0x%x wrid_low_msn 0x%x\n", + CQE_QPID(rsp_msg->cqe), CQE_GENBIT(rsp_msg->cqe), + CQE_TYPE(rsp_msg->cqe), CQE_STATUS(rsp_msg->cqe), + CQE_OPCODE(rsp_msg->cqe), CQE_LEN(rsp_msg->cqe), + CQE_WRID_HI(rsp_msg->cqe), CQE_WRID_LOW(rsp_msg->cqe)); + rdev_p = (struct cxio_rdev *)t3cdev_p->ulp; + if (!rdev_p) { + PDBG("%s called by t3cdev %p with null ulp\n", __FUNCTION__, + t3cdev_p); + return 0; + } + if (CQE_QPID(rsp_msg->cqe) == T3_CTRL_QP_ID) { + rdev_p->ctrl_qp.rptr = CQE_WRID_LOW(rsp_msg->cqe) + 1; + wake_up_interruptible(&rdev_p->ctrl_qp.waitq); + dev_kfree_skb_irq(skb); + } else if (CQE_QPID(rsp_msg->cqe) == 0xfff8) + dev_kfree_skb_irq(skb); + else if (cxio_ev_cb) + (*cxio_ev_cb) (rdev_p, skb); + else + dev_kfree_skb_irq(skb); + cnt++; + return 0; +} + +/* Caller takes care of locking if needed */ +int cxio_rdev_open(struct cxio_rdev *rdev_p) +{ + struct net_device *netdev_p = NULL; + int err = 0; + if (strlen(rdev_p->dev_name)) { + if (cxio_hal_find_rdev_by_name(rdev_p->dev_name)) { + return -EBUSY; + } + netdev_p = dev_get_by_name(rdev_p->dev_name); + if (!netdev_p) { + return -EINVAL; + } + dev_put(netdev_p); + } else if (rdev_p->t3cdev_p) { + if (cxio_hal_find_rdev_by_t3cdev(rdev_p->t3cdev_p)) { + return -EBUSY; + } + netdev_p = rdev_p->t3cdev_p->lldev; + strncpy(rdev_p->dev_name, rdev_p->t3cdev_p->name, + T3_MAX_DEV_NAME_LEN); + } else { + PDBG("%s t3cdev_p or dev_name must be set\n", __FUNCTION__); + return -EINVAL; + } + + list_add_tail(&rdev_p->entry, &rdev_list); + + PDBG("%s opening rnic dev %s\n", __FUNCTION__, rdev_p->dev_name); + memset(&rdev_p->ctrl_qp, 0, sizeof(rdev_p->ctrl_qp)); + if (!rdev_p->t3cdev_p) + rdev_p->t3cdev_p = T3CDEV(netdev_p); + rdev_p->t3cdev_p->ulp = (void *) rdev_p; + err = rdev_p->t3cdev_p->ctl(rdev_p->t3cdev_p, RDMA_GET_PARAMS, + &(rdev_p->rnic_info)); + if (err) { + printk(KERN_ERR "%s t3cdev_p(%p)->ctl returned error %d.\n", + __FUNCTION__, rdev_p->t3cdev_p, err); + goto err1; + } + err = rdev_p->t3cdev_p->ctl(rdev_p->t3cdev_p, GET_PORTS, + &(rdev_p->port_info)); + if (err) { + printk(KERN_ERR "%s t3cdev_p(%p)->ctl returned error %d.\n", + __FUNCTION__, rdev_p->t3cdev_p, err); + goto err1; + } + + /* + * qpshift is the number of bits to shift the qpid left in order + * to get the correct address of the doorbell for that qp. + */ + cxio_init_ucontext(rdev_p, &rdev_p->uctx); + rdev_p->qpshift = PAGE_SHIFT - + ilog2(65536 >> + ilog2(rdev_p->rnic_info.udbell_len >> + PAGE_SHIFT)); + rdev_p->qpnr = rdev_p->rnic_info.udbell_len >> PAGE_SHIFT; + rdev_p->qpmask = (65536 >> ilog2(rdev_p->qpnr)) - 1; + PDBG("%s rnic %s info: tpt_base 0x%0x tpt_top 0x%0x num stags %d " + "pbl_base 0x%0x pbl_top 0x%0x rqt_base 0x%0x, rqt_top 0x%0x\n", + __FUNCTION__, rdev_p->dev_name, rdev_p->rnic_info.tpt_base, + rdev_p->rnic_info.tpt_top, cxio_num_stags(rdev_p), + rdev_p->rnic_info.pbl_base, + rdev_p->rnic_info.pbl_top, rdev_p->rnic_info.rqt_base, + rdev_p->rnic_info.rqt_top); + PDBG("udbell_len 0x%0x udbell_physbase 0x%lx kdb_addr %p qpshift %lu " + "qpnr %d qpmask 0x%x\n", + rdev_p->rnic_info.udbell_len, + rdev_p->rnic_info.udbell_physbase, rdev_p->rnic_info.kdb_addr, + rdev_p->qpshift, rdev_p->qpnr, rdev_p->qpmask); + + err = cxio_hal_init_ctrl_qp(rdev_p); + if (err) { + printk(KERN_ERR "%s error %d initializing ctrl_qp.\n", + __FUNCTION__, err); + goto err1; + } + err = cxio_hal_init_resource(rdev_p, cxio_num_stags(rdev_p), 0, + 0, T3_MAX_NUM_QP, T3_MAX_NUM_CQ, + T3_MAX_NUM_PD); + if (err) { + printk(KERN_ERR "%s error %d initializing hal resources.\n", + __FUNCTION__, err); + goto err2; + } + err = cxio_hal_pblpool_create(rdev_p); + if (err) { + printk(KERN_ERR "%s error %d initializing pbl mem pool.\n", + __FUNCTION__, err); + goto err3; + } + err = cxio_hal_rqtpool_create(rdev_p); + if (err) { + printk(KERN_ERR "%s error %d initializing rqt mem pool.\n", + __FUNCTION__, err); + goto err4; + } + return 0; +err4: + cxio_hal_pblpool_destroy(rdev_p); +err3: + cxio_hal_destroy_resource(rdev_p->rscp); +err2: + cxio_hal_destroy_ctrl_qp(rdev_p); +err1: + list_del(&rdev_p->entry); + return err; +} + +void cxio_rdev_close(struct cxio_rdev *rdev_p) +{ + if (rdev_p) { + cxio_hal_pblpool_destroy(rdev_p); + cxio_hal_rqtpool_destroy(rdev_p); + list_del(&rdev_p->entry); + rdev_p->t3cdev_p->ulp = NULL; + cxio_hal_destroy_ctrl_qp(rdev_p); + cxio_hal_destroy_resource(rdev_p->rscp); + } +} + +int __init cxio_hal_init(void) +{ + if (cxio_hal_init_rhdl_resource(T3_MAX_NUM_RI)) + return -ENOMEM; + t3_register_cpl_handler(CPL_ASYNC_NOTIF, cxio_hal_ev_handler); + return 0; +} + +void __exit cxio_hal_exit(void) +{ + struct cxio_rdev *rdev, *tmp; + + t3_register_cpl_handler(CPL_ASYNC_NOTIF, NULL); + list_for_each_entry_safe(rdev, tmp, &rdev_list, entry) + cxio_rdev_close(rdev); + cxio_hal_destroy_rhdl_resource(); +} + +static inline void flush_completed_wrs(struct t3_wq *wq, struct t3_cq *cq) +{ + struct t3_swsq *sqp; + __u32 ptr = wq->sq_rptr; + int count = Q_COUNT(wq->sq_rptr, wq->sq_wptr); + + sqp = wq->sq + Q_PTR2IDX(ptr, wq->sq_size_log2); + while (count--) + if (!sqp->signaled) { + ptr++; + sqp = wq->sq + Q_PTR2IDX(ptr, wq->sq_size_log2); + } else if (sqp->complete) { + + /* + * Insert this completed cqe into the swcq. + */ + PDBG("%s moving cqe into swcq sq idx %ld cq idx %ld\n", + __FUNCTION__, Q_PTR2IDX(ptr, wq->sq_size_log2), + Q_PTR2IDX(cq->sw_wptr, cq->size_log2)); + sqp->cqe.header |= htonl(V_CQE_SWCQE(1)); + *(cq->sw_queue + Q_PTR2IDX(cq->sw_wptr, cq->size_log2)) + = sqp->cqe; + cq->sw_wptr++; + sqp->signaled = 0; + break; + } else + break; +} + +static inline void create_read_req_cqe(struct t3_wq *wq, + struct t3_cqe *hw_cqe, + struct t3_cqe *read_cqe) +{ + read_cqe->u.scqe.wrid_hi = wq->oldest_read->sq_wptr; + read_cqe->len = wq->oldest_read->read_len; + read_cqe->header = htonl(V_CQE_QPID(CQE_QPID(*hw_cqe)) | + V_CQE_SWCQE(SW_CQE(*hw_cqe)) | + V_CQE_OPCODE(T3_READ_REQ) | + V_CQE_TYPE(1)); +} + +/* + * Return a ptr to the next read wr in the SWSQ or NULL. + */ +static inline void advance_oldest_read(struct t3_wq *wq) +{ + + u32 rptr = wq->oldest_read - wq->sq + 1; + u32 wptr = Q_PTR2IDX(wq->sq_wptr, wq->sq_size_log2); + + while (Q_PTR2IDX(rptr, wq->sq_size_log2) != wptr) { + wq->oldest_read = wq->sq + Q_PTR2IDX(rptr, wq->sq_size_log2); + + if (wq->oldest_read->opcode == T3_READ_REQ) + return; + rptr++; + } + wq->oldest_read = NULL; +} + +/* + * cxio_poll_cq + * + * Caller must: + * check the validity of the first CQE, + * supply the wq assicated with the qpid. + * + * credit: cq credit to return to sge. + * cqe_flushed: 1 iff the CQE is flushed. + * cqe: copy of the polled CQE. + * + * return value: + * 0 CQE returned, + * -1 CQE skipped, try again. + */ +int cxio_poll_cq(struct t3_wq *wq, struct t3_cq *cq, struct t3_cqe *cqe, + u8 *cqe_flushed, u64 *cookie, u32 *credit) +{ + int ret = 0; + struct t3_cqe *hw_cqe, read_cqe; + + *cqe_flushed = 0; + *credit = 0; + hw_cqe = cxio_next_cqe(cq); + + PDBG("%s CQE OOO %d qpid 0x%0x genbit %d type %d status 0x%0x" + " opcode 0x%0x len 0x%0x wrid_hi_stag 0x%x wrid_low_msn 0x%x\n", + __FUNCTION__, CQE_OOO(*hw_cqe), CQE_QPID(*hw_cqe), + CQE_GENBIT(*hw_cqe), CQE_TYPE(*hw_cqe), CQE_STATUS(*hw_cqe), + CQE_OPCODE(*hw_cqe), CQE_LEN(*hw_cqe), CQE_WRID_HI(*hw_cqe), + CQE_WRID_LOW(*hw_cqe)); + + /* + * skip cqe's not affiliated with a QP. + */ + if (wq == NULL) { + ret = -1; + goto skip_cqe; + } + + /* + * Gotta tweak READ completions: + * 1) the cqe doesn't contain the sq_wptr from the wr. + * 2) opcode not reflected from the wr. + * 3) read_len not reflected from the wr. + * 4) cq_type is RQ_TYPE not SQ_TYPE. + */ + if (RQ_TYPE(*hw_cqe) && (CQE_OPCODE(*hw_cqe) == T3_READ_RESP)) { + + /* + * Don't write to the HWCQ, so create a new read req CQE + * in local memory. + */ + create_read_req_cqe(wq, hw_cqe, &read_cqe); + hw_cqe = &read_cqe; + advance_oldest_read(wq); + } + + /* + * T3A: Discard TERMINATE CQEs. + */ + if (CQE_OPCODE(*hw_cqe) == T3_TERMINATE) { + ret = -1; + wq->error = 1; + goto skip_cqe; + } + + if (CQE_STATUS(*hw_cqe) || wq->error) { + *cqe_flushed = wq->error; + wq->error = 1; + + /* + * T3A inserts errors into the CQE. We cannot return + * these as work completions. + */ + /* incoming write failures */ + if ((CQE_OPCODE(*hw_cqe) == T3_RDMA_WRITE) + && RQ_TYPE(*hw_cqe)) { + ret = -1; + goto skip_cqe; + } + /* incoming read request failures */ + if ((CQE_OPCODE(*hw_cqe) == T3_READ_RESP) && SQ_TYPE(*hw_cqe)) { + ret = -1; + goto skip_cqe; + } + + /* incoming SEND with no receive posted failures */ + if ((CQE_OPCODE(*hw_cqe) == T3_SEND) && RQ_TYPE(*hw_cqe) && + Q_EMPTY(wq->rq_rptr, wq->rq_wptr)) { + ret = -1; + goto skip_cqe; + } + goto proc_cqe; + } + + /* + * RECV completion. + */ + if (RQ_TYPE(*hw_cqe)) { + + /* + * HW only validates 4 bits of MSN. So we must validate that + * the MSN in the SEND is the next expected MSN. If its not, + * then we complete this with TPT_ERR_MSN and mark the wq in + * error. + */ + if (unlikely((CQE_WRID_MSN(*hw_cqe) != (wq->rq_rptr + 1)))) { + wq->error = 1; + hw_cqe->header |= htonl(V_CQE_STATUS(TPT_ERR_MSN)); + goto proc_cqe; + } + goto proc_cqe; + } + + /* + * If we get here its a send completion. + * + * Handle out of order completion. These get stuffed + * in the SW SQ. Then the SW SQ is walked to move any + * now in-order completions into the SW CQ. This handles + * 2 cases: + * 1) reaping unsignaled WRs when the first subsequent + * signaled WR is completed. + * 2) out of order read completions. + */ + if (!SW_CQE(*hw_cqe) && (CQE_WRID_SQ_WPTR(*hw_cqe) != wq->sq_rptr)) { + struct t3_swsq *sqp; + + PDBG("%s out of order completion going in swsq at idx %ld\n", + __FUNCTION__, + Q_PTR2IDX(CQE_WRID_SQ_WPTR(*hw_cqe), wq->sq_size_log2)); + sqp = wq->sq + + Q_PTR2IDX(CQE_WRID_SQ_WPTR(*hw_cqe), wq->sq_size_log2); + sqp->cqe = *hw_cqe; + sqp->complete = 1; + ret = -1; + goto flush_wq; + } + +proc_cqe: + *cqe = *hw_cqe; + + /* + * Reap the associated WR(s) that are freed up with this + * completion. + */ + if (SQ_TYPE(*hw_cqe)) { + wq->sq_rptr = CQE_WRID_SQ_WPTR(*hw_cqe); + PDBG("%s completing sq idx %ld\n", __FUNCTION__, + Q_PTR2IDX(wq->sq_rptr, wq->sq_size_log2)); + *cookie = (wq->sq + + Q_PTR2IDX(wq->sq_rptr, wq->sq_size_log2))->wr_id; + wq->sq_rptr++; + } else { + PDBG("%s completing rq idx %ld\n", __FUNCTION__, + Q_PTR2IDX(wq->rq_rptr, wq->rq_size_log2)); + *cookie = *(wq->rq + Q_PTR2IDX(wq->rq_rptr, wq->rq_size_log2)); + wq->rq_rptr++; + } + +flush_wq: + /* + * Flush any completed cqes that are now in-order. + */ + flush_completed_wrs(wq, cq); + +skip_cqe: + if (SW_CQE(*hw_cqe)) { + PDBG("%s cq %p cqid 0x%x skip sw cqe sw_rptr 0x%x\n", + __FUNCTION__, cq, cq->cqid, cq->sw_rptr); + ++cq->sw_rptr; + } else { + PDBG("%s cq %p cqid 0x%x skip hw cqe rptr 0x%x\n", + __FUNCTION__, cq, cq->cqid, cq->rptr); + ++cq->rptr; + + /* + * T3A: compute credits. + */ + if (((cq->rptr - cq->wptr) > (1 << (cq->size_log2 - 1))) + || ((cq->rptr - cq->wptr) >= 128)) { + *credit = cq->rptr - cq->wptr; + cq->wptr = cq->rptr; + } + } + return ret; +} diff --git a/drivers/infiniband/hw/cxgb3/cxio_hal.h b/drivers/infiniband/hw/cxgb3/cxio_hal.h new file mode 100644 index 0000000..1b97e80 --- /dev/null +++ b/drivers/infiniband/hw/cxgb3/cxio_hal.h @@ -0,0 +1,201 @@ +/* + * Copyright (c) 2006 Chelsio, Inc. All rights reserved. + * Copyright (c) 2006 Open Grid Computing, Inc. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +#ifndef __CXIO_HAL_H__ +#define __CXIO_HAL_H__ + +#include +#include + +#include "t3_cpl.h" +#include "t3cdev.h" +#include "cxgb3_ctl_defs.h" +#include "cxio_wr.h" + +#define T3_CTRL_QP_ID FW_RI_SGEEC_START +#define T3_CTL_QP_TID FW_RI_TID_START +#define T3_CTRL_QP_SIZE_LOG2 8 +#define T3_CTRL_CQ_ID 0 + +/* TBD */ +#define T3_MAX_NUM_RI (1<<15) +#define T3_MAX_NUM_QP (1<<15) +#define T3_MAX_NUM_CQ (1<<15) +#define T3_MAX_NUM_PD (1<<15) +#define T3_MAX_PBL_SIZE 256 +#define T3_MAX_RQ_SIZE 1024 +#define T3_MAX_NUM_STAG (1<<15) + +#define T3_STAG_UNSET 0xffffffff + +#define T3_MAX_DEV_NAME_LEN 32 + +struct cxio_hal_ctrl_qp { + u32 wptr; + u32 rptr; + struct mutex lock; /* for the wtpr, can sleep */ + wait_queue_head_t waitq;/* wait for RspQ/CQE msg */ + union t3_wr *workq; /* the work request queue */ + dma_addr_t dma_addr; /* pci bus address of the workq */ + DECLARE_PCI_UNMAP_ADDR(mapping) + void __iomem *doorbell; +}; + +struct cxio_hal_resource { + struct kfifo *tpt_fifo; + spinlock_t tpt_fifo_lock; + struct kfifo *qpid_fifo; + spinlock_t qpid_fifo_lock; + struct kfifo *cqid_fifo; + spinlock_t cqid_fifo_lock; + struct kfifo *pdid_fifo; + spinlock_t pdid_fifo_lock; +}; + +struct cxio_qpid_list { + struct list_head entry; + u32 qpid; +}; + +struct cxio_ucontext { + struct list_head qpids; + struct mutex lock; +}; + +struct cxio_rdev { + char dev_name[T3_MAX_DEV_NAME_LEN]; + struct t3cdev *t3cdev_p; + struct rdma_info rnic_info; + struct adap_ports port_info; + struct cxio_hal_resource *rscp; + struct cxio_hal_ctrl_qp ctrl_qp; + void *ulp; + unsigned long qpshift; + u32 qpnr; + u32 qpmask; + struct cxio_ucontext uctx; + struct gen_pool *pbl_pool; + struct gen_pool *rqt_pool; + struct list_head entry; +}; + +static inline int cxio_num_stags(struct cxio_rdev *rdev_p) +{ + return min((int)T3_MAX_NUM_STAG, (int)((rdev_p->rnic_info.tpt_top - rdev_p->rnic_info.tpt_base) >> 5)); +} + +typedef void (*cxio_hal_ev_callback_func_t) (struct cxio_rdev * rdev_p, + struct sk_buff * skb); + +#define RSPQ_CQID(rsp) (be32_to_cpu(rsp->cq_ptrid) & 0xffff) +#define RSPQ_CQPTR(rsp) ((be32_to_cpu(rsp->cq_ptrid) >> 16) & 0xffff) +#define RSPQ_GENBIT(rsp) ((be32_to_cpu(rsp->flags) >> 16) & 1) +#define RSPQ_OVERFLOW(rsp) ((be32_to_cpu(rsp->flags) >> 17) & 1) +#define RSPQ_AN(rsp) ((be32_to_cpu(rsp->flags) >> 18) & 1) +#define RSPQ_SE(rsp) ((be32_to_cpu(rsp->flags) >> 19) & 1) +#define RSPQ_NOTIFY(rsp) ((be32_to_cpu(rsp->flags) >> 20) & 1) +#define RSPQ_CQBRANCH(rsp) ((be32_to_cpu(rsp->flags) >> 21) & 1) +#define RSPQ_CREDIT_THRESH(rsp) ((be32_to_cpu(rsp->flags) >> 22) & 1) + +struct respQ_msg_t { + __be32 flags; /* flit 0 */ + __be32 cq_ptrid; + __be64 rsvd; /* flit 1 */ + struct t3_cqe cqe; /* flits 2-3 */ +}; + +enum t3_cq_opcode { + CQ_ARM_AN = 0x2, + CQ_ARM_SE = 0x6, + CQ_FORCE_AN = 0x3, + CQ_CREDIT_UPDATE = 0x7 +}; + +int cxio_rdev_open(struct cxio_rdev *rdev); +void cxio_rdev_close(struct cxio_rdev *rdev); +int cxio_hal_cq_op(struct cxio_rdev *rdev, struct t3_cq *cq, + enum t3_cq_opcode op, u32 credit); +int cxio_hal_clear_qp_ctx(struct cxio_rdev *rdev, u32 qpid); +int cxio_create_cq(struct cxio_rdev *rdev, struct t3_cq *cq); +int cxio_destroy_cq(struct cxio_rdev *rdev, struct t3_cq *cq); +int cxio_resize_cq(struct cxio_rdev *rdev, struct t3_cq *cq); +void cxio_release_ucontext(struct cxio_rdev *rdev, struct cxio_ucontext *uctx); +void cxio_init_ucontext(struct cxio_rdev *rdev, struct cxio_ucontext *uctx); +int cxio_create_qp(struct cxio_rdev *rdev, u32 kernel_domain, struct t3_wq *wq, + struct cxio_ucontext *uctx); +int cxio_destroy_qp(struct cxio_rdev *rdev, struct t3_wq *wq, + struct cxio_ucontext *uctx); +int cxio_peek_cq(struct t3_wq *wr, struct t3_cq *cq, int opcode); +int cxio_allocate_stag(struct cxio_rdev *rdev, u32 * stag, u32 pdid, + enum tpt_mem_perm perm, u32 * pbl_size, u32 * pbl_addr); +int cxio_register_phys_mem(struct cxio_rdev *rdev, u32 * stag, u32 pdid, + enum tpt_mem_perm perm, u32 zbva, u64 to, u32 len, + u8 page_size, __be64 *pbl, u32 *pbl_size, + u32 *pbl_addr); +int cxio_reregister_phys_mem(struct cxio_rdev *rdev, u32 * stag, u32 pdid, + enum tpt_mem_perm perm, u32 zbva, u64 to, u32 len, + u8 page_size, __be64 *pbl, u32 *pbl_size, + u32 *pbl_addr); +int cxio_dereg_mem(struct cxio_rdev *rdev, u32 stag, u32 pbl_size, + u32 pbl_addr); +int cxio_allocate_window(struct cxio_rdev *rdev, u32 * stag, u32 pdid); +int cxio_deallocate_window(struct cxio_rdev *rdev, u32 stag); +int cxio_rdma_init(struct cxio_rdev *rdev, struct t3_rdma_init_attr *attr); +void cxio_register_ev_cb(cxio_hal_ev_callback_func_t ev_cb); +void cxio_unregister_ev_cb(cxio_hal_ev_callback_func_t ev_cb); +u32 cxio_hal_get_rhdl(void); +void cxio_hal_put_rhdl(u32 rhdl); +u32 cxio_hal_get_pdid(struct cxio_hal_resource *rscp); +void cxio_hal_put_pdid(struct cxio_hal_resource *rscp, u32 pdid); +int __init cxio_hal_init(void); +void __exit cxio_hal_exit(void); +void cxio_flush_rq(struct t3_wq *wq, struct t3_cq *cq, int count); +void cxio_flush_sq(struct t3_wq *wq, struct t3_cq *cq, int count); +void cxio_count_rcqes(struct t3_cq *cq, struct t3_wq *wq, int *count); +void cxio_count_scqes(struct t3_cq *cq, struct t3_wq *wq, int *count); +void cxio_flush_hw_cq(struct t3_cq *cq); +int cxio_poll_cq(struct t3_wq *wq, struct t3_cq *cq, struct t3_cqe *cqe, + u8 *cqe_flushed, u64 *cookie, u32 *credit); + +#define MOD "iw_cxgb3: " +#define PDBG(fmt, args...) pr_debug(MOD fmt, ## args) + +#ifdef DEBUG +void cxio_dump_tpt(struct cxio_rdev *rev, u32 stag); +void cxio_dump_pbl(struct cxio_rdev *rev, u32 pbl_addr, uint len, u8 shift); +void cxio_dump_wqe(union t3_wr *wqe); +void cxio_dump_wce(struct t3_cqe *wce); +void cxio_dump_rqt(struct cxio_rdev *rdev, u32 hwtid, int nents); +void cxio_dump_tcb(struct cxio_rdev *rdev, u32 hwtid); +#endif + +#endif diff --git a/drivers/infiniband/hw/cxgb3/cxio_resource.c b/drivers/infiniband/hw/cxgb3/cxio_resource.c new file mode 100644 index 0000000..997aa32 --- /dev/null +++ b/drivers/infiniband/hw/cxgb3/cxio_resource.c @@ -0,0 +1,331 @@ +/* + * Copyright (c) 2006 Chelsio, Inc. All rights reserved. + * Copyright (c) 2006 Open Grid Computing, Inc. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +/* Crude resource management */ +#include +#include +#include +#include +#include +#include +#include "cxio_resource.h" +#include "cxio_hal.h" + +static struct kfifo *rhdl_fifo; +static spinlock_t rhdl_fifo_lock; + +#define RANDOM_SIZE 16 + +static int __cxio_init_resource_fifo(struct kfifo **fifo, + spinlock_t *fifo_lock, + u32 nr, u32 skip_low, + u32 skip_high, + int random) +{ + u32 i, j, entry = 0, idx; + u32 random_bytes; + u32 rarray[16]; + spin_lock_init(fifo_lock); + + *fifo = kfifo_alloc(nr * sizeof(u32), GFP_KERNEL, fifo_lock); + if (IS_ERR(*fifo)) + return -ENOMEM; + + for (i = 0; i < skip_low + skip_high; i++) + __kfifo_put(*fifo, (unsigned char *) &entry, sizeof(u32)); + if (random) { + j = 0; + random_bytes = random32(); + for (i = 0; i < RANDOM_SIZE; i++) + rarray[i] = i + skip_low; + for (i = skip_low + RANDOM_SIZE; i < nr - skip_high; i++) { + if (j >= RANDOM_SIZE) { + j = 0; + random_bytes = random32(); + } + idx = (random_bytes >> (j * 2)) & 0xF; + __kfifo_put(*fifo, + (unsigned char *) &rarray[idx], + sizeof(u32)); + rarray[idx] = i; + j++; + } + for (i = 0; i < RANDOM_SIZE; i++) + __kfifo_put(*fifo, + (unsigned char *) &rarray[i], + sizeof(u32)); + } else + for (i = skip_low; i < nr - skip_high; i++) + __kfifo_put(*fifo, (unsigned char *) &i, sizeof(u32)); + + for (i = 0; i < skip_low + skip_high; i++) + kfifo_get(*fifo, (unsigned char *) &entry, sizeof(u32)); + return 0; +} + +static int cxio_init_resource_fifo(struct kfifo **fifo, spinlock_t * fifo_lock, + u32 nr, u32 skip_low, u32 skip_high) +{ + return (__cxio_init_resource_fifo(fifo, fifo_lock, nr, skip_low, + skip_high, 0)); +} + +static int cxio_init_resource_fifo_random(struct kfifo **fifo, + spinlock_t * fifo_lock, + u32 nr, u32 skip_low, u32 skip_high) +{ + + return (__cxio_init_resource_fifo(fifo, fifo_lock, nr, skip_low, + skip_high, 1)); +} + +static int cxio_init_qpid_fifo(struct cxio_rdev *rdev_p) +{ + u32 i; + + spin_lock_init(&rdev_p->rscp->qpid_fifo_lock); + + rdev_p->rscp->qpid_fifo = kfifo_alloc(T3_MAX_NUM_QP * sizeof(u32), + GFP_KERNEL, + &rdev_p->rscp->qpid_fifo_lock); + if (IS_ERR(rdev_p->rscp->qpid_fifo)) + return -ENOMEM; + + for (i = 16; i < T3_MAX_NUM_QP; i++) + if (!(i & rdev_p->qpmask)) + __kfifo_put(rdev_p->rscp->qpid_fifo, + (unsigned char *) &i, sizeof(u32)); + return 0; +} + +int cxio_hal_init_rhdl_resource(u32 nr_rhdl) +{ + return cxio_init_resource_fifo(&rhdl_fifo, &rhdl_fifo_lock, nr_rhdl, 1, + 0); +} + +void cxio_hal_destroy_rhdl_resource(void) +{ + kfifo_free(rhdl_fifo); +} + +/* nr_* must be power of 2 */ +int cxio_hal_init_resource(struct cxio_rdev *rdev_p, + u32 nr_tpt, u32 nr_pbl, + u32 nr_rqt, u32 nr_qpid, u32 nr_cqid, u32 nr_pdid) +{ + int err = 0; + struct cxio_hal_resource *rscp; + + rscp = kmalloc(sizeof(*rscp), GFP_KERNEL); + if (!rscp) + return -ENOMEM; + rdev_p->rscp = rscp; + err = cxio_init_resource_fifo_random(&rscp->tpt_fifo, + &rscp->tpt_fifo_lock, + nr_tpt, 1, 0); + if (err) + goto tpt_err; + err = cxio_init_qpid_fifo(rdev_p); + if (err) + goto qpid_err; + err = cxio_init_resource_fifo(&rscp->cqid_fifo, &rscp->cqid_fifo_lock, + nr_cqid, 1, 0); + if (err) + goto cqid_err; + err = cxio_init_resource_fifo(&rscp->pdid_fifo, &rscp->pdid_fifo_lock, + nr_pdid, 1, 0); + if (err) + goto pdid_err; + return 0; +pdid_err: + kfifo_free(rscp->cqid_fifo); +cqid_err: + kfifo_free(rscp->qpid_fifo); +qpid_err: + kfifo_free(rscp->tpt_fifo); +tpt_err: + return -ENOMEM; +} + +/* + * returns 0 if no resource available + */ +static inline u32 cxio_hal_get_resource(struct kfifo *fifo) +{ + u32 entry; + if (kfifo_get(fifo, (unsigned char *) &entry, sizeof(u32))) + return entry; + else + return 0; /* fifo emptry */ +} + +static inline void cxio_hal_put_resource(struct kfifo *fifo, u32 entry) +{ + BUG_ON(kfifo_put(fifo, (unsigned char *) &entry, sizeof(u32)) == 0); +} + +u32 cxio_hal_get_rhdl(void) +{ + return cxio_hal_get_resource(rhdl_fifo); +} + +void cxio_hal_put_rhdl(u32 rhdl) +{ + cxio_hal_put_resource(rhdl_fifo, rhdl); +} + +u32 cxio_hal_get_stag(struct cxio_hal_resource *rscp) +{ + return cxio_hal_get_resource(rscp->tpt_fifo); +} + +void cxio_hal_put_stag(struct cxio_hal_resource *rscp, u32 stag) +{ + cxio_hal_put_resource(rscp->tpt_fifo, stag); +} + +u32 cxio_hal_get_qpid(struct cxio_hal_resource *rscp) +{ + u32 qpid = cxio_hal_get_resource(rscp->qpid_fifo); + PDBG("%s qpid 0x%x\n", __FUNCTION__, qpid); + return qpid; +} + +void cxio_hal_put_qpid(struct cxio_hal_resource *rscp, u32 qpid) +{ + PDBG("%s qpid 0x%x\n", __FUNCTION__, qpid); + cxio_hal_put_resource(rscp->qpid_fifo, qpid); +} + +u32 cxio_hal_get_cqid(struct cxio_hal_resource *rscp) +{ + return cxio_hal_get_resource(rscp->cqid_fifo); +} + +void cxio_hal_put_cqid(struct cxio_hal_resource *rscp, u32 cqid) +{ + cxio_hal_put_resource(rscp->cqid_fifo, cqid); +} + +u32 cxio_hal_get_pdid(struct cxio_hal_resource *rscp) +{ + return cxio_hal_get_resource(rscp->pdid_fifo); +} + +void cxio_hal_put_pdid(struct cxio_hal_resource *rscp, u32 pdid) +{ + cxio_hal_put_resource(rscp->pdid_fifo, pdid); +} + +void cxio_hal_destroy_resource(struct cxio_hal_resource *rscp) +{ + kfifo_free(rscp->tpt_fifo); + kfifo_free(rscp->cqid_fifo); + kfifo_free(rscp->qpid_fifo); + kfifo_free(rscp->pdid_fifo); + kfree(rscp); +} + +/* + * PBL Memory Manager. Uses Linux generic allocator. + */ + +#define MIN_PBL_SHIFT 8 /* 256B == min PBL size (32 entries) */ +#define PBL_CHUNK 2*1024*1024 + +u32 cxio_hal_pblpool_alloc(struct cxio_rdev *rdev_p, int size) +{ + unsigned long addr = gen_pool_alloc(rdev_p->pbl_pool, size); + PDBG("%s addr 0x%x size %d\n", __FUNCTION__, (u32)addr, size); + return (u32)addr; +} + +void cxio_hal_pblpool_free(struct cxio_rdev *rdev_p, u32 addr, int size) +{ + PDBG("%s addr 0x%x size %d\n", __FUNCTION__, addr, size); + gen_pool_free(rdev_p->pbl_pool, (unsigned long)addr, size); +} + +int cxio_hal_pblpool_create(struct cxio_rdev *rdev_p) +{ + unsigned long i; + rdev_p->pbl_pool = gen_pool_create(MIN_PBL_SHIFT, -1); + if (rdev_p->pbl_pool) + for (i = rdev_p->rnic_info.pbl_base; + i <= rdev_p->rnic_info.pbl_top - PBL_CHUNK + 1; + i += PBL_CHUNK) + gen_pool_add(rdev_p->pbl_pool, i, PBL_CHUNK, -1); + return rdev_p->pbl_pool ? 0 : -ENOMEM; +} + +void cxio_hal_pblpool_destroy(struct cxio_rdev *rdev_p) +{ + gen_pool_destroy(rdev_p->pbl_pool); +} + +/* + * RQT Memory Manager. Uses Linux generic allocator. + */ + +#define MIN_RQT_SHIFT 10 /* 1KB == mini RQT size (16 entries) */ +#define RQT_CHUNK 2*1024*1024 + +u32 cxio_hal_rqtpool_alloc(struct cxio_rdev *rdev_p, int size) +{ + unsigned long addr = gen_pool_alloc(rdev_p->rqt_pool, size << 6); + PDBG("%s addr 0x%x size %d\n", __FUNCTION__, (u32)addr, size << 6); + return (u32)addr; +} + +void cxio_hal_rqtpool_free(struct cxio_rdev *rdev_p, u32 addr, int size) +{ + PDBG("%s addr 0x%x size %d\n", __FUNCTION__, addr, size << 6); + gen_pool_free(rdev_p->rqt_pool, (unsigned long)addr, size << 6); +} + +int cxio_hal_rqtpool_create(struct cxio_rdev *rdev_p) +{ + unsigned long i; + rdev_p->rqt_pool = gen_pool_create(MIN_RQT_SHIFT, -1); + if (rdev_p->rqt_pool) + for (i = rdev_p->rnic_info.rqt_base; + i <= rdev_p->rnic_info.rqt_top - RQT_CHUNK + 1; + i += RQT_CHUNK) + gen_pool_add(rdev_p->rqt_pool, i, RQT_CHUNK, -1); + return rdev_p->rqt_pool ? 0 : -ENOMEM; +} + +void cxio_hal_rqtpool_destroy(struct cxio_rdev *rdev_p) +{ + gen_pool_destroy(rdev_p->rqt_pool); +} diff --git a/drivers/infiniband/hw/cxgb3/cxio_resource.h b/drivers/infiniband/hw/cxgb3/cxio_resource.h new file mode 100644 index 0000000..a6bbe83 --- /dev/null +++ b/drivers/infiniband/hw/cxgb3/cxio_resource.h @@ -0,0 +1,70 @@ +/* + * Copyright (c) 2006 Chelsio, Inc. All rights reserved. + * Copyright (c) 2006 Open Grid Computing, Inc. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +#ifndef __CXIO_RESOURCE_H__ +#define __CXIO_RESOURCE_H__ + +#include +#include +#include +#include +#include +#include +#include +#include "cxio_hal.h" + +extern int cxio_hal_init_rhdl_resource(u32 nr_rhdl); +extern void cxio_hal_destroy_rhdl_resource(void); +extern int cxio_hal_init_resource(struct cxio_rdev *rdev_p, + u32 nr_tpt, u32 nr_pbl, + u32 nr_rqt, u32 nr_qpid, u32 nr_cqid, + u32 nr_pdid); +extern u32 cxio_hal_get_stag(struct cxio_hal_resource *rscp); +extern void cxio_hal_put_stag(struct cxio_hal_resource *rscp, u32 stag); +extern u32 cxio_hal_get_qpid(struct cxio_hal_resource *rscp); +extern void cxio_hal_put_qpid(struct cxio_hal_resource *rscp, u32 qpid); +extern u32 cxio_hal_get_cqid(struct cxio_hal_resource *rscp); +extern void cxio_hal_put_cqid(struct cxio_hal_resource *rscp, u32 cqid); +extern void cxio_hal_destroy_resource(struct cxio_hal_resource *rscp); + +#define PBL_OFF(rdev_p, a) ( (a) - (rdev_p)->rnic_info.pbl_base ) +extern int cxio_hal_pblpool_create(struct cxio_rdev *rdev_p); +extern void cxio_hal_pblpool_destroy(struct cxio_rdev *rdev_p); +extern u32 cxio_hal_pblpool_alloc(struct cxio_rdev *rdev_p, int size); +extern void cxio_hal_pblpool_free(struct cxio_rdev *rdev_p, u32 addr, int size); + +#define RQT_OFF(rdev_p, a) ( (a) - (rdev_p)->rnic_info.rqt_base ) +extern int cxio_hal_rqtpool_create(struct cxio_rdev *rdev_p); +extern void cxio_hal_rqtpool_destroy(struct cxio_rdev *rdev_p); +extern u32 cxio_hal_rqtpool_alloc(struct cxio_rdev *rdev_p, int size); +extern void cxio_hal_rqtpool_free(struct cxio_rdev *rdev_p, u32 addr, int size); +#endif diff --git a/drivers/infiniband/hw/cxgb3/cxio_wr.h b/drivers/infiniband/hw/cxgb3/cxio_wr.h new file mode 100644 index 0000000..103fc42 --- /dev/null +++ b/drivers/infiniband/hw/cxgb3/cxio_wr.h @@ -0,0 +1,685 @@ +/* + * Copyright (c) 2006 Chelsio, Inc. All rights reserved. + * Copyright (c) 2006 Open Grid Computing, Inc. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +#ifndef __CXIO_WR_H__ +#define __CXIO_WR_H__ + +#include +#include +#include +#include "firmware_exports.h" + +#define T3_MAX_SGE 4 + +#define Q_EMPTY(rptr,wptr) ((rptr)==(wptr)) +#define Q_FULL(rptr,wptr,size_log2) ( (((wptr)-(rptr))>>(size_log2)) && \ + ((rptr)!=(wptr)) ) +#define Q_GENBIT(ptr,size_log2) (!(((ptr)>>size_log2)&0x1)) +#define Q_FREECNT(rptr,wptr,size_log2) ((1UL<> S_FW_RIWR_OP)) & M_FW_RIWR_OP) + +#define S_FW_RIWR_SOPEOP 22 +#define M_FW_RIWR_SOPEOP 0x3 +#define V_FW_RIWR_SOPEOP(x) ((x) << S_FW_RIWR_SOPEOP) + +#define S_FW_RIWR_FLAGS 8 +#define M_FW_RIWR_FLAGS 0x3fffff +#define V_FW_RIWR_FLAGS(x) ((x) << S_FW_RIWR_FLAGS) +#define G_FW_RIWR_FLAGS(x) ((((x) >> S_FW_RIWR_FLAGS)) & M_FW_RIWR_FLAGS) + +#define S_FW_RIWR_TID 8 +#define V_FW_RIWR_TID(x) ((x) << S_FW_RIWR_TID) + +#define S_FW_RIWR_LEN 0 +#define V_FW_RIWR_LEN(x) ((x) << S_FW_RIWR_LEN) + +#define S_FW_RIWR_GEN 31 +#define V_FW_RIWR_GEN(x) ((x) << S_FW_RIWR_GEN) + +struct t3_sge { + __be32 stag; + __be32 len; + __be64 to; +}; + +/* If num_sgle is zero, flit 5+ contains immediate data.*/ +struct t3_send_wr { + struct fw_riwrh wrh; /* 0 */ + union t3_wrid wrid; /* 1 */ + + u8 rdmaop; /* 2 */ + u8 reserved[3]; + __be32 rem_stag; + __be32 plen; /* 3 */ + __be32 num_sgle; + struct t3_sge sgl[T3_MAX_SGE]; /* 4+ */ +}; + +struct t3_local_inv_wr { + struct fw_riwrh wrh; /* 0 */ + union t3_wrid wrid; /* 1 */ + __be32 stag; /* 2 */ + __be32 reserved3; +}; + +struct t3_rdma_write_wr { + struct fw_riwrh wrh; /* 0 */ + union t3_wrid wrid; /* 1 */ + u8 rdmaop; /* 2 */ + u8 reserved[3]; + __be32 stag_sink; + __be64 to_sink; /* 3 */ + __be32 plen; /* 4 */ + __be32 num_sgle; + struct t3_sge sgl[T3_MAX_SGE]; /* 5+ */ +}; + +struct t3_rdma_read_wr { + struct fw_riwrh wrh; /* 0 */ + union t3_wrid wrid; /* 1 */ + u8 rdmaop; /* 2 */ + u8 reserved[3]; + __be32 rem_stag; + __be64 rem_to; /* 3 */ + __be32 local_stag; /* 4 */ + __be32 local_len; + __be64 local_to; /* 5 */ +}; + +enum t3_addr_type { + T3_VA_BASED_TO = 0x0, + T3_ZERO_BASED_TO = 0x1 +} __attribute__ ((packed)); + +enum t3_mem_perms { + T3_MEM_ACCESS_LOCAL_READ = 0x1, + T3_MEM_ACCESS_LOCAL_WRITE = 0x2, + T3_MEM_ACCESS_REM_READ = 0x4, + T3_MEM_ACCESS_REM_WRITE = 0x8 +} __attribute__ ((packed)); + +struct t3_bind_mw_wr { + struct fw_riwrh wrh; /* 0 */ + union t3_wrid wrid; /* 1 */ + u16 reserved; /* 2 */ + u8 type; + u8 perms; + __be32 mr_stag; + __be32 mw_stag; /* 3 */ + __be32 mw_len; + __be64 mw_va; /* 4 */ + __be32 mr_pbl_addr; /* 5 */ + u8 reserved2[3]; + u8 mr_pagesz; +}; + +struct t3_receive_wr { + struct fw_riwrh wrh; /* 0 */ + union t3_wrid wrid; /* 1 */ + u8 pagesz[T3_MAX_SGE]; + __be32 num_sgle; /* 2 */ + struct t3_sge sgl[T3_MAX_SGE]; /* 3+ */ + __be32 pbl_addr[T3_MAX_SGE]; +}; + +struct t3_bypass_wr { + struct fw_riwrh wrh; + union t3_wrid wrid; /* 1 */ +}; + +struct t3_modify_qp_wr { + struct fw_riwrh wrh; /* 0 */ + union t3_wrid wrid; /* 1 */ + __be32 flags; /* 2 */ + __be32 quiesce; /* 2 */ + __be32 max_ird; /* 3 */ + __be32 max_ord; /* 3 */ + __be64 sge_cmd; /* 4 */ + __be64 ctx1; /* 5 */ + __be64 ctx0; /* 6 */ +}; + +enum t3_modify_qp_flags { + MODQP_QUIESCE = 0x01, + MODQP_MAX_IRD = 0x02, + MODQP_MAX_ORD = 0x04, + MODQP_WRITE_EC = 0x08, + MODQP_READ_EC = 0x10, +}; + + +enum t3_mpa_attrs { + uP_RI_MPA_RX_MARKER_ENABLE = 0x1, + uP_RI_MPA_TX_MARKER_ENABLE = 0x2, + uP_RI_MPA_CRC_ENABLE = 0x4, + uP_RI_MPA_IETF_ENABLE = 0x8 +} __attribute__ ((packed)); + +enum t3_qp_caps { + uP_RI_QP_RDMA_READ_ENABLE = 0x01, + uP_RI_QP_RDMA_WRITE_ENABLE = 0x02, + uP_RI_QP_BIND_ENABLE = 0x04, + uP_RI_QP_FAST_REGISTER_ENABLE = 0x08, + uP_RI_QP_STAG0_ENABLE = 0x10 +} __attribute__ ((packed)); + +struct t3_rdma_init_attr { + u32 tid; + u32 qpid; + u32 pdid; + u32 scqid; + u32 rcqid; + u32 rq_addr; + u32 rq_size; + enum t3_mpa_attrs mpaattrs; + enum t3_qp_caps qpcaps; + u16 tcp_emss; + u32 ord; + u32 ird; + u64 qp_dma_addr; + u32 qp_dma_size; + u32 flags; +}; + +struct t3_rdma_init_wr { + struct fw_riwrh wrh; /* 0 */ + union t3_wrid wrid; /* 1 */ + __be32 qpid; /* 2 */ + __be32 pdid; + __be32 scqid; /* 3 */ + __be32 rcqid; + __be32 rq_addr; /* 4 */ + __be32 rq_size; + u8 mpaattrs; /* 5 */ + u8 qpcaps; + __be16 ulpdu_size; + __be32 flags; /* bits 31-1 - reservered */ + /* bit 0 - set if RECV posted */ + __be32 ord; /* 6 */ + __be32 ird; + __be64 qp_dma_addr; /* 7 */ + __be32 qp_dma_size; /* 8 */ + u32 rsvd; +}; + +struct t3_genbit { + u64 flit[15]; + __be64 genbit; +}; + +enum rdma_init_wr_flags { + RECVS_POSTED = 1, +}; + +union t3_wr { + struct t3_send_wr send; + struct t3_rdma_write_wr write; + struct t3_rdma_read_wr read; + struct t3_receive_wr recv; + struct t3_local_inv_wr local_inv; + struct t3_bind_mw_wr bind; + struct t3_bypass_wr bypass; + struct t3_rdma_init_wr init; + struct t3_modify_qp_wr qp_mod; + struct t3_genbit genbit; + u64 flit[16]; +}; + +#define T3_SQ_CQE_FLIT 13 +#define T3_SQ_COOKIE_FLIT 14 + +#define T3_RQ_COOKIE_FLIT 13 +#define T3_RQ_CQE_FLIT 14 + +static inline enum t3_wr_opcode fw_riwrh_opcode(struct fw_riwrh *wqe) +{ + return G_FW_RIWR_OP(be32_to_cpu(wqe->op_seop_flags)); +} + +static inline void build_fw_riwrh(struct fw_riwrh *wqe, enum t3_wr_opcode op, + enum t3_wr_flags flags, u8 genbit, u32 tid, + u8 len) +{ + wqe->op_seop_flags = cpu_to_be32(V_FW_RIWR_OP(op) | + V_FW_RIWR_SOPEOP(M_FW_RIWR_SOPEOP) | + V_FW_RIWR_FLAGS(flags)); + wmb(); + wqe->gen_tid_len = cpu_to_be32(V_FW_RIWR_GEN(genbit) | + V_FW_RIWR_TID(tid) | + V_FW_RIWR_LEN(len)); + /* 2nd gen bit... */ + ((union t3_wr *)wqe)->genbit.genbit = cpu_to_be64(genbit); +} + +/* + * T3 ULP2_TX commands + */ +enum t3_utx_mem_op { + T3_UTX_MEM_READ = 2, + T3_UTX_MEM_WRITE = 3 +}; + +/* T3 MC7 RDMA TPT entry format */ + +enum tpt_mem_type { + TPT_NON_SHARED_MR = 0x0, + TPT_SHARED_MR = 0x1, + TPT_MW = 0x2, + TPT_MW_RELAXED_PROTECTION = 0x3 +}; + +enum tpt_addr_type { + TPT_ZBTO = 0, + TPT_VATO = 1 +}; + +enum tpt_mem_perm { + TPT_LOCAL_READ = 0x8, + TPT_LOCAL_WRITE = 0x4, + TPT_REMOTE_READ = 0x2, + TPT_REMOTE_WRITE = 0x1 +}; + +struct tpt_entry { + __be32 valid_stag_pdid; + __be32 flags_pagesize_qpid; + + __be32 rsvd_pbl_addr; + __be32 len; + __be32 va_hi; + __be32 va_low_or_fbo; + + __be32 rsvd_bind_cnt_or_pstag; + __be32 rsvd_pbl_size; +}; + +#define S_TPT_VALID 31 +#define V_TPT_VALID(x) ((x) << S_TPT_VALID) +#define F_TPT_VALID V_TPT_VALID(1U) + +#define S_TPT_STAG_KEY 23 +#define M_TPT_STAG_KEY 0xFF +#define V_TPT_STAG_KEY(x) ((x) << S_TPT_STAG_KEY) +#define G_TPT_STAG_KEY(x) (((x) >> S_TPT_STAG_KEY) & M_TPT_STAG_KEY) + +#define S_TPT_STAG_STATE 22 +#define V_TPT_STAG_STATE(x) ((x) << S_TPT_STAG_STATE) +#define F_TPT_STAG_STATE V_TPT_STAG_STATE(1U) + +#define S_TPT_STAG_TYPE 20 +#define M_TPT_STAG_TYPE 0x3 +#define V_TPT_STAG_TYPE(x) ((x) << S_TPT_STAG_TYPE) +#define G_TPT_STAG_TYPE(x) (((x) >> S_TPT_STAG_TYPE) & M_TPT_STAG_TYPE) + +#define S_TPT_PDID 0 +#define M_TPT_PDID 0xFFFFF +#define V_TPT_PDID(x) ((x) << S_TPT_PDID) +#define G_TPT_PDID(x) (((x) >> S_TPT_PDID) & M_TPT_PDID) + +#define S_TPT_PERM 28 +#define M_TPT_PERM 0xF +#define V_TPT_PERM(x) ((x) << S_TPT_PERM) +#define G_TPT_PERM(x) (((x) >> S_TPT_PERM) & M_TPT_PERM) + +#define S_TPT_REM_INV_DIS 27 +#define V_TPT_REM_INV_DIS(x) ((x) << S_TPT_REM_INV_DIS) +#define F_TPT_REM_INV_DIS V_TPT_REM_INV_DIS(1U) + +#define S_TPT_ADDR_TYPE 26 +#define V_TPT_ADDR_TYPE(x) ((x) << S_TPT_ADDR_TYPE) +#define F_TPT_ADDR_TYPE V_TPT_ADDR_TYPE(1U) + +#define S_TPT_MW_BIND_ENABLE 25 +#define V_TPT_MW_BIND_ENABLE(x) ((x) << S_TPT_MW_BIND_ENABLE) +#define F_TPT_MW_BIND_ENABLE V_TPT_MW_BIND_ENABLE(1U) + +#define S_TPT_PAGE_SIZE 20 +#define M_TPT_PAGE_SIZE 0x1F +#define V_TPT_PAGE_SIZE(x) ((x) << S_TPT_PAGE_SIZE) +#define G_TPT_PAGE_SIZE(x) (((x) >> S_TPT_PAGE_SIZE) & M_TPT_PAGE_SIZE) + +#define S_TPT_PBL_ADDR 0 +#define M_TPT_PBL_ADDR 0x1FFFFFFF +#define V_TPT_PBL_ADDR(x) ((x) << S_TPT_PBL_ADDR) +#define G_TPT_PBL_ADDR(x) (((x) >> S_TPT_PBL_ADDR) & M_TPT_PBL_ADDR) + +#define S_TPT_QPID 0 +#define M_TPT_QPID 0xFFFFF +#define V_TPT_QPID(x) ((x) << S_TPT_QPID) +#define G_TPT_QPID(x) (((x) >> S_TPT_QPID) & M_TPT_QPID) + +#define S_TPT_PSTAG 0 +#define M_TPT_PSTAG 0xFFFFFF +#define V_TPT_PSTAG(x) ((x) << S_TPT_PSTAG) +#define G_TPT_PSTAG(x) (((x) >> S_TPT_PSTAG) & M_TPT_PSTAG) + +#define S_TPT_PBL_SIZE 0 +#define M_TPT_PBL_SIZE 0xFFFFF +#define V_TPT_PBL_SIZE(x) ((x) << S_TPT_PBL_SIZE) +#define G_TPT_PBL_SIZE(x) (((x) >> S_TPT_PBL_SIZE) & M_TPT_PBL_SIZE) + +/* + * CQE defs + */ +struct t3_cqe { + __be32 header; + __be32 len; + union { + struct { + __be32 stag; + __be32 msn; + } rcqe; + struct { + u32 wrid_hi; + u32 wrid_low; + } scqe; + } u; +}; + +#define S_CQE_OOO 31 +#define M_CQE_OOO 0x1 +#define G_CQE_OOO(x) ((((x) >> S_CQE_OOO)) & M_CQE_OOO) +#define V_CEQ_OOO(x) ((x)<> S_CQE_QPID)) & M_CQE_QPID) +#define V_CQE_QPID(x) ((x)<> S_CQE_SWCQE)) & M_CQE_SWCQE) +#define V_CQE_SWCQE(x) ((x)<> S_CQE_GENBIT) & M_CQE_GENBIT) +#define V_CQE_GENBIT(x) ((x)<> S_CQE_STATUS)) & M_CQE_STATUS) +#define V_CQE_STATUS(x) ((x)<> S_CQE_TYPE)) & M_CQE_TYPE) +#define V_CQE_TYPE(x) ((x)<> S_CQE_OPCODE)) & M_CQE_OPCODE) +#define V_CQE_OPCODE(x) ((x)<queue->flit[13] = 1; +} + +static inline struct t3_cqe *cxio_next_hw_cqe(struct t3_cq *cq) +{ + struct t3_cqe *cqe; + + cqe = cq->queue + (Q_PTR2IDX(cq->rptr, cq->size_log2)); + if (CQ_VLD_ENTRY(cq->rptr, cq->size_log2, cqe)) + return cqe; + return NULL; +} + +static inline struct t3_cqe *cxio_next_sw_cqe(struct t3_cq *cq) +{ + struct t3_cqe *cqe; + + if (!Q_EMPTY(cq->sw_rptr, cq->sw_wptr)) { + cqe = cq->sw_queue + (Q_PTR2IDX(cq->sw_rptr, cq->size_log2)); + return cqe; + } + return NULL; +} + +static inline struct t3_cqe *cxio_next_cqe(struct t3_cq *cq) +{ + struct t3_cqe *cqe; + + if (!Q_EMPTY(cq->sw_rptr, cq->sw_wptr)) { + cqe = cq->sw_queue + (Q_PTR2IDX(cq->sw_rptr, cq->size_log2)); + return cqe; + } + cqe = cq->queue + (Q_PTR2IDX(cq->rptr, cq->size_log2)); + if (CQ_VLD_ENTRY(cq->rptr, cq->size_log2, cqe)) + return cqe; + return NULL; +} + +#endif diff --git a/drivers/infiniband/hw/cxgb3/iwch.c b/drivers/infiniband/hw/cxgb3/iwch.c new file mode 100644 index 0000000..4611afa --- /dev/null +++ b/drivers/infiniband/hw/cxgb3/iwch.c @@ -0,0 +1,189 @@ +/* + * Copyright (c) 2006 Chelsio, Inc. All rights reserved. + * Copyright (c) 2006 Open Grid Computing, Inc. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +#include +#include + +#include + +#include "cxgb3_offload.h" +#include "iwch_provider.h" +#include "iwch_user.h" +#include "iwch.h" +#include "iwch_cm.h" + +#define DRV_VERSION "1.1" + +MODULE_AUTHOR("Boyd Faulkner, Steve Wise"); +MODULE_DESCRIPTION("Chelsio T3 RDMA Driver"); +MODULE_LICENSE("Dual BSD/GPL"); +MODULE_VERSION(DRV_VERSION); + +cxgb3_cpl_handler_func t3c_handlers[NUM_CPL_CMDS]; + +static void open_rnic_dev(struct t3cdev *); +static void close_rnic_dev(struct t3cdev *); + +struct cxgb3_client t3c_client = { + .name = "iw_cxgb3", + .add = open_rnic_dev, + .remove = close_rnic_dev, + .handlers = t3c_handlers, + .redirect = iwch_ep_redirect +}; + +static LIST_HEAD(dev_list); +static DEFINE_MUTEX(dev_mutex); + +static void rnic_init(struct iwch_dev *rnicp) +{ + PDBG("%s iwch_dev %p\n", __FUNCTION__, rnicp); + idr_init(&rnicp->cqidr); + idr_init(&rnicp->qpidr); + idr_init(&rnicp->mmidr); + spin_lock_init(&rnicp->lock); + + rnicp->attr.vendor_id = 0x168; + rnicp->attr.vendor_part_id = 7; + rnicp->attr.max_qps = T3_MAX_NUM_QP - 32; + rnicp->attr.max_wrs = (1UL << 24) - 1; + rnicp->attr.max_sge_per_wr = T3_MAX_SGE; + rnicp->attr.max_sge_per_rdma_write_wr = T3_MAX_SGE; + rnicp->attr.max_cqs = T3_MAX_NUM_CQ - 1; + rnicp->attr.max_cqes_per_cq = (1UL << 24) - 1; + rnicp->attr.max_mem_regs = cxio_num_stags(&rnicp->rdev); + rnicp->attr.max_phys_buf_entries = T3_MAX_PBL_SIZE; + rnicp->attr.max_pds = T3_MAX_NUM_PD - 1; + rnicp->attr.mem_pgsizes_bitmask = 0x7FFF; /* 4KB-128MB */ + rnicp->attr.can_resize_wq = 0; + rnicp->attr.max_rdma_reads_per_qp = 8; + rnicp->attr.max_rdma_read_resources = + rnicp->attr.max_rdma_reads_per_qp * rnicp->attr.max_qps; + rnicp->attr.max_rdma_read_qp_depth = 8; /* IRD */ + rnicp->attr.max_rdma_read_depth = + rnicp->attr.max_rdma_read_qp_depth * rnicp->attr.max_qps; + rnicp->attr.rq_overflow_handled = 0; + rnicp->attr.can_modify_ird = 0; + rnicp->attr.can_modify_ord = 0; + rnicp->attr.max_mem_windows = rnicp->attr.max_mem_regs - 1; + rnicp->attr.stag0_value = 1; + rnicp->attr.zbva_support = 1; + rnicp->attr.local_invalidate_fence = 1; + rnicp->attr.cq_overflow_detection = 1; + return; +} + +static void open_rnic_dev(struct t3cdev *tdev) +{ + struct iwch_dev *rnicp; + static int vers_printed; + + PDBG("%s t3cdev %p\n", __FUNCTION__, tdev); + if (!vers_printed++) + printk(KERN_INFO MOD "Chelsio T3 RDMA Driver - version %s\n", + DRV_VERSION); + rnicp = (struct iwch_dev *)ib_alloc_device(sizeof(*rnicp)); + if (!rnicp) { + printk(KERN_ERR MOD "Cannot allocate ib device\n"); + return; + } + rnicp->rdev.ulp = rnicp; + rnicp->rdev.t3cdev_p = tdev; + + mutex_lock(&dev_mutex); + + if (cxio_rdev_open(&rnicp->rdev)) { + mutex_unlock(&dev_mutex); + printk(KERN_ERR MOD "Unable to open CXIO rdev\n"); + ib_dealloc_device(&rnicp->ibdev); + return; + } + + rnic_init(rnicp); + + list_add_tail(&rnicp->entry, &dev_list); + mutex_unlock(&dev_mutex); + + if (iwch_register_device(rnicp)) { + printk(KERN_ERR MOD "Unable to register device\n"); + close_rnic_dev(tdev); + } + printk(KERN_INFO MOD "Initialized device %s\n", + pci_name(rnicp->rdev.rnic_info.pdev)); + return; +} + +static void close_rnic_dev(struct t3cdev *tdev) +{ + struct iwch_dev *dev, *tmp; + PDBG("%s t3cdev %p\n", __FUNCTION__, tdev); + mutex_lock(&dev_mutex); + list_for_each_entry_safe(dev, tmp, &dev_list, entry) { + if (dev->rdev.t3cdev_p == tdev) { + list_del(&dev->entry); + iwch_unregister_device(dev); + cxio_rdev_close(&dev->rdev); + idr_destroy(&dev->cqidr); + idr_destroy(&dev->qpidr); + idr_destroy(&dev->mmidr); + ib_dealloc_device(&dev->ibdev); + break; + } + } + mutex_unlock(&dev_mutex); +} + +static int __init iwch_init_module(void) +{ + int err; + + err = cxio_hal_init(); + if (err) + return err; + err = iwch_cm_init(); + if (err) + return err; + cxio_register_ev_cb(iwch_ev_dispatch); + cxgb3_register_client(&t3c_client); + return 0; +} + +static void __exit iwch_exit_module(void) +{ + cxgb3_unregister_client(&t3c_client); + cxio_unregister_ev_cb(iwch_ev_dispatch); + iwch_cm_term(); + cxio_hal_exit(); +} + +module_init(iwch_init_module); +module_exit(iwch_exit_module); diff --git a/drivers/infiniband/hw/cxgb3/iwch.h b/drivers/infiniband/hw/cxgb3/iwch.h new file mode 100644 index 0000000..6517ef8 --- /dev/null +++ b/drivers/infiniband/hw/cxgb3/iwch.h @@ -0,0 +1,177 @@ +/* + * Copyright (c) 2006 Chelsio, Inc. All rights reserved. + * Copyright (c) 2006 Open Grid Computing, Inc. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +#ifndef __IWCH_H__ +#define __IWCH_H__ + +#include +#include +#include +#include + +#include + +#include "cxio_hal.h" +#include "cxgb3_offload.h" + +struct iwch_pd; +struct iwch_cq; +struct iwch_qp; +struct iwch_mr; + +struct iwch_rnic_attributes { + u32 vendor_id; + u32 vendor_part_id; + u32 max_qps; + u32 max_wrs; /* Max for any SQ/RQ */ + u32 max_sge_per_wr; + u32 max_sge_per_rdma_write_wr; /* for RDMA Write WR */ + u32 max_cqs; + u32 max_cqes_per_cq; + u32 max_mem_regs; + u32 max_phys_buf_entries; /* for phys buf list */ + u32 max_pds; + + /* + * The memory page sizes supported by this RNIC. + * Bit position i in bitmap indicates page of + * size (4k)^i. Phys block list mode unsupported. + */ + u32 mem_pgsizes_bitmask; + u8 can_resize_wq; + + /* + * The maximum number of RDMA Reads that can be outstanding + * per QP with this RNIC as the target. + */ + u32 max_rdma_reads_per_qp; + + /* + * The maximum number of resources used for RDMA Reads + * by this RNIC with this RNIC as the target. + */ + u32 max_rdma_read_resources; + + /* + * The max depth per QP for initiation of RDMA Read + * by this RNIC. + */ + u32 max_rdma_read_qp_depth; + + /* + * The maximum depth for initiation of RDMA Read + * operations by this RNIC on all QPs + */ + u32 max_rdma_read_depth; + u8 rq_overflow_handled; + u32 can_modify_ird; + u32 can_modify_ord; + u32 max_mem_windows; + u32 stag0_value; + u8 zbva_support; + u8 local_invalidate_fence; + u32 cq_overflow_detection; +}; + +struct iwch_dev { + struct ib_device ibdev; + struct cxio_rdev rdev; + u32 device_cap_flags; + struct iwch_rnic_attributes attr; + struct idr cqidr; + struct idr qpidr; + struct idr mmidr; + spinlock_t lock; + struct list_head entry; +}; + +static inline struct iwch_dev *to_iwch_dev(struct ib_device *ibdev) +{ + return container_of(ibdev, struct iwch_dev, ibdev); +} + +static inline int t3b_device(const struct iwch_dev *rhp) +{ + return rhp->rdev.t3cdev_p->type == T3B; +} + +static inline int t3a_device(const struct iwch_dev *rhp) +{ + return rhp->rdev.t3cdev_p->type == T3A; +} + +static inline struct iwch_cq *get_chp(struct iwch_dev *rhp, u32 cqid) +{ + return idr_find(&rhp->cqidr, cqid); +} + +static inline struct iwch_qp *get_qhp(struct iwch_dev *rhp, u32 qpid) +{ + return idr_find(&rhp->qpidr, qpid); +} + +static inline struct iwch_mr *get_mhp(struct iwch_dev *rhp, u32 mmid) +{ + return idr_find(&rhp->mmidr, mmid); +} + +static inline int insert_handle(struct iwch_dev *rhp, struct idr *idr, + void *handle, u32 id) +{ + int ret; + u32 newid; + + do { + if (!idr_pre_get(idr, GFP_KERNEL)) { + return -ENOMEM; + } + spin_lock_irq(&rhp->lock); + ret = idr_get_new_above(idr, handle, id, &newid); + BUG_ON(newid != id); + spin_unlock_irq(&rhp->lock); + } while (ret == -EAGAIN); + + return ret; +} + +static inline void remove_handle(struct iwch_dev *rhp, struct idr *idr, u32 id) +{ + spin_lock_irq(&rhp->lock); + idr_remove(idr, id); + spin_unlock_irq(&rhp->lock); +} + +extern struct cxgb3_client t3c_client; +extern cxgb3_cpl_handler_func t3c_handlers[NUM_CPL_CMDS]; +extern void iwch_ev_dispatch(struct cxio_rdev *rdev_p, struct sk_buff *skb); + +#endif diff --git a/drivers/infiniband/hw/cxgb3/iwch_cm.c b/drivers/infiniband/hw/cxgb3/iwch_cm.c new file mode 100644 index 0000000..a522b1b --- /dev/null +++ b/drivers/infiniband/hw/cxgb3/iwch_cm.c @@ -0,0 +1,2081 @@ +/* + * Copyright (c) 2006 Chelsio, Inc. All rights reserved. + * Copyright (c) 2006 Open Grid Computing, Inc. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include "tcb.h" +#include "cxgb3_offload.h" +#include "iwch.h" +#include "iwch_provider.h" +#include "iwch_cm.h" + +static char *states[] = { + "idle", + "listen", + "connecting", + "mpa_wait_req", + "mpa_req_sent", + "mpa_req_rcvd", + "mpa_rep_sent", + "fpdu_mode", + "aborting", + "closing", + "moribund", + "dead", + NULL, +}; + +static int ep_timeout_secs = 10; +module_param(ep_timeout_secs, int, 0444); +MODULE_PARM_DESC(ep_timeout_secs, "CM Endpoint operation timeout " + "in seconds (default=10)"); + +static int mpa_rev = 1; +module_param(mpa_rev, int, 0444); +MODULE_PARM_DESC(mpa_rev, "MPA Revision, 0 supports amso1100, " + "1 is spec compliant. (default=1)"); + +static int markers_enabled = 0; +module_param(markers_enabled, int, 0444); +MODULE_PARM_DESC(markers_enabled, "Enable MPA MARKERS (default(0)=disabled)"); + +static int crc_enabled = 1; +module_param(crc_enabled, int, 0444); +MODULE_PARM_DESC(crc_enabled, "Enable MPA CRC (default(1)=enabled)"); + +static int rcv_win = 256 * 1024; +module_param(rcv_win, int, 0444); +MODULE_PARM_DESC(rcv_win, "TCP receive window in bytes (default=256)"); + +static int snd_win = 32 * 1024; +module_param(snd_win, int, 0444); +MODULE_PARM_DESC(snd_win, "TCP send window in bytes (default=32KB)"); + +static unsigned int nocong = 0; +module_param(nocong, uint, 0444); +MODULE_PARM_DESC(nocong, "Turn off congestion control (default=0)"); + +static unsigned int cong_flavor = 1; +module_param(cong_flavor, uint, 0444); +MODULE_PARM_DESC(cong_flavor, "TCP Congestion control flavor (default=1)"); + +static void process_work(struct work_struct *work); +static struct workqueue_struct *workq; +static DECLARE_WORK(skb_work, process_work); + +static struct sk_buff_head rxq; +static cxgb3_cpl_handler_func work_handlers[NUM_CPL_CMDS]; + +static struct sk_buff *get_skb(struct sk_buff *skb, int len, gfp_t gfp); +static void ep_timeout(unsigned long arg); +static void connect_reply_upcall(struct iwch_ep *ep, int status); + +static void start_ep_timer(struct iwch_ep *ep) +{ + PDBG("%s ep %p\n", __FUNCTION__, ep); + if (timer_pending(&ep->timer)) { + PDBG("%s stopped / restarted timer ep %p\n", __FUNCTION__, ep); + del_timer_sync(&ep->timer); + } else + get_ep(&ep->com); + ep->timer.expires = jiffies + ep_timeout_secs * HZ; + ep->timer.data = (unsigned long)ep; + ep->timer.function = ep_timeout; + add_timer(&ep->timer); +} + +static void stop_ep_timer(struct iwch_ep *ep) +{ + PDBG("%s ep %p\n", __FUNCTION__, ep); + del_timer_sync(&ep->timer); + put_ep(&ep->com); +} + +static void release_tid(struct t3cdev *tdev, u32 hwtid, struct sk_buff *skb) +{ + struct cpl_tid_release *req; + + skb = get_skb(skb, sizeof *req, GFP_KERNEL); + if (!skb) + return; + req = (struct cpl_tid_release *) skb_put(skb, sizeof(*req)); + req->wr.wr_hi = htonl(V_WR_OP(FW_WROPCODE_FORWARD)); + OPCODE_TID(req) = htonl(MK_OPCODE_TID(CPL_TID_RELEASE, hwtid)); + skb->priority = CPL_PRIORITY_SETUP; + tdev->send(tdev, skb); + return; +} + +int iwch_quiesce_tid(struct iwch_ep *ep) +{ + struct cpl_set_tcb_field *req; + struct sk_buff *skb = get_skb(NULL, sizeof(*req), GFP_KERNEL); + + if (!skb) + return -ENOMEM; + req = (struct cpl_set_tcb_field *) skb_put(skb, sizeof(*req)); + req->wr.wr_hi = htonl(V_WR_OP(FW_WROPCODE_FORWARD)); + req->wr.wr_lo = htonl(V_WR_TID(ep->hwtid)); + OPCODE_TID(req) = htonl(MK_OPCODE_TID(CPL_SET_TCB_FIELD, ep->hwtid)); + req->reply = 0; + req->cpu_idx = 0; + req->word = htons(W_TCB_RX_QUIESCE); + req->mask = cpu_to_be64(1ULL << S_TCB_RX_QUIESCE); + req->val = cpu_to_be64(1 << S_TCB_RX_QUIESCE); + + skb->priority = CPL_PRIORITY_DATA; + ep->com.tdev->send(ep->com.tdev, skb); + return 0; +} + +int iwch_resume_tid(struct iwch_ep *ep) +{ + struct cpl_set_tcb_field *req; + struct sk_buff *skb = get_skb(NULL, sizeof(*req), GFP_KERNEL); + + if (!skb) + return -ENOMEM; + req = (struct cpl_set_tcb_field *) skb_put(skb, sizeof(*req)); + req->wr.wr_hi = htonl(V_WR_OP(FW_WROPCODE_FORWARD)); + req->wr.wr_lo = htonl(V_WR_TID(ep->hwtid)); + OPCODE_TID(req) = htonl(MK_OPCODE_TID(CPL_SET_TCB_FIELD, ep->hwtid)); + req->reply = 0; + req->cpu_idx = 0; + req->word = htons(W_TCB_RX_QUIESCE); + req->mask = cpu_to_be64(1ULL << S_TCB_RX_QUIESCE); + req->val = 0; + + skb->priority = CPL_PRIORITY_DATA; + ep->com.tdev->send(ep->com.tdev, skb); + return 0; +} + +static void set_emss(struct iwch_ep *ep, u16 opt) +{ + PDBG("%s ep %p opt %u\n", __FUNCTION__, ep, opt); + ep->emss = T3C_DATA(ep->com.tdev)->mtus[G_TCPOPT_MSS(opt)] - 40; + if (G_TCPOPT_TSTAMP(opt)) + ep->emss -= 12; + if (ep->emss < 128) + ep->emss = 128; + PDBG("emss=%d\n", ep->emss); +} + +static enum iwch_ep_state state_read(struct iwch_ep_common *epc) +{ + unsigned long flags; + enum iwch_ep_state state; + + spin_lock_irqsave(&epc->lock, flags); + state = epc->state; + spin_unlock_irqrestore(&epc->lock, flags); + return state; +} + +static inline void __state_set(struct iwch_ep_common *epc, + enum iwch_ep_state new) +{ + epc->state = new; +} + +static void state_set(struct iwch_ep_common *epc, enum iwch_ep_state new) +{ + unsigned long flags; + + spin_lock_irqsave(&epc->lock, flags); + PDBG("%s - %s -> %s\n", __FUNCTION__, states[epc->state], states[new]); + __state_set(epc, new); + spin_unlock_irqrestore(&epc->lock, flags); + return; +} + +static void *alloc_ep(int size, gfp_t gfp) +{ + struct iwch_ep_common *epc; + + epc = kmalloc(size, gfp); + if (epc) { + memset(epc, 0, size); + kref_init(&epc->kref); + spin_lock_init(&epc->lock); + init_waitqueue_head(&epc->waitq); + } + PDBG("%s alloc ep %p\n", __FUNCTION__, epc); + return epc; +} + +void __free_ep(struct kref *kref) +{ + struct iwch_ep_common *epc; + epc = container_of(kref, struct iwch_ep_common, kref); + PDBG("%s ep %p state %s\n", __FUNCTION__, epc, states[state_read(epc)]); + kfree(epc); +} + +static void release_ep_resources(struct iwch_ep *ep) +{ + PDBG("%s ep %p tid %d\n", __FUNCTION__, ep, ep->hwtid); + cxgb3_remove_tid(ep->com.tdev, (void *)ep, ep->hwtid); + dst_release(ep->dst); + l2t_release(L2DATA(ep->com.tdev), ep->l2t); + if (ep->com.tdev->type == T3B) + release_tid(ep->com.tdev, ep->hwtid, NULL); + put_ep(&ep->com); +} + +static void process_work(struct work_struct *work) +{ + struct sk_buff *skb = NULL; + void *ep; + struct t3cdev *tdev; + int ret; + + while ((skb = skb_dequeue(&rxq))) { + ep = *((void **) (skb->cb)); + tdev = *((struct t3cdev **) (skb->cb + sizeof(void *))); + ret = work_handlers[G_OPCODE(ntohl((__force __be32)skb->csum))](tdev, skb, ep); + if (ret & CPL_RET_BUF_DONE) + kfree_skb(skb); + + /* + * ep was referenced in sched(), and is freed here. + */ + put_ep((struct iwch_ep_common *)ep); + } +} + +static int status2errno(int status) +{ + switch (status) { + case CPL_ERR_NONE: + return 0; + case CPL_ERR_CONN_RESET: + return -ECONNRESET; + case CPL_ERR_ARP_MISS: + return -EHOSTUNREACH; + case CPL_ERR_CONN_TIMEDOUT: + return -ETIMEDOUT; + case CPL_ERR_TCAM_FULL: + return -ENOMEM; + case CPL_ERR_CONN_EXIST: + return -EADDRINUSE; + default: + return -EIO; + } +} + +/* + * Try and reuse skbs already allocated... + */ +static struct sk_buff *get_skb(struct sk_buff *skb, int len, gfp_t gfp) +{ + if (skb) { + BUG_ON(skb_cloned(skb)); + skb_trim(skb, 0); + skb_get(skb); + } else { + skb = alloc_skb(len, gfp); + } + return skb; +} + +static struct rtable *find_route(struct t3cdev *dev, __be32 local_ip, + __be32 peer_ip, __be16 local_port, + __be16 peer_port, u8 tos) +{ + struct rtable *rt; + struct flowi fl = { + .oif = 0, + .nl_u = { + .ip4_u = { + .daddr = peer_ip, + .saddr = local_ip, + .tos = tos} + }, + .proto = IPPROTO_TCP, + .uli_u = { + .ports = { + .sport = local_port, + .dport = peer_port} + } + }; + + if (ip_route_output_flow(&rt, &fl, NULL, 0)) + return NULL; + return rt; +} + +static unsigned int find_best_mtu(const struct t3c_data *d, unsigned short mtu) +{ + int i = 0; + + while (i < d->nmtus - 1 && d->mtus[i + 1] <= mtu) + ++i; + return i; +} + +static void arp_failure_discard(struct t3cdev *dev, struct sk_buff *skb) +{ + PDBG("%s t3cdev %p\n", __FUNCTION__, dev); + kfree_skb(skb); +} + +/* + * Handle an ARP failure for an active open. + */ +static void act_open_req_arp_failure(struct t3cdev *dev, struct sk_buff *skb) +{ + printk(KERN_ERR MOD "ARP failure duing connect\n"); + kfree_skb(skb); +} + +/* + * Handle an ARP failure for a CPL_ABORT_REQ. Change it into a no RST variant + * and send it along. + */ +static void abort_arp_failure(struct t3cdev *dev, struct sk_buff *skb) +{ + struct cpl_abort_req *req = cplhdr(skb); + + PDBG("%s t3cdev %p\n", __FUNCTION__, dev); + req->cmd = CPL_ABORT_NO_RST; + cxgb3_ofld_send(dev, skb); +} + +static int send_halfclose(struct iwch_ep *ep, gfp_t gfp) +{ + struct cpl_close_con_req *req; + struct sk_buff *skb; + + PDBG("%s ep %p\n", __FUNCTION__, ep); + skb = get_skb(NULL, sizeof(*req), gfp); + if (!skb) { + printk(KERN_ERR MOD "%s - failed to alloc skb\n", __FUNCTION__); + return -ENOMEM; + } + skb->priority = CPL_PRIORITY_DATA; + set_arp_failure_handler(skb, arp_failure_discard); + req = (struct cpl_close_con_req *) skb_put(skb, sizeof(*req)); + req->wr.wr_hi = htonl(V_WR_OP(FW_WROPCODE_OFLD_CLOSE_CON)); + req->wr.wr_lo = htonl(V_WR_TID(ep->hwtid)); + OPCODE_TID(req) = htonl(MK_OPCODE_TID(CPL_CLOSE_CON_REQ, ep->hwtid)); + l2t_send(ep->com.tdev, skb, ep->l2t); + return 0; +} + +static int send_abort(struct iwch_ep *ep, struct sk_buff *skb, gfp_t gfp) +{ + struct cpl_abort_req *req; + + PDBG("%s ep %p\n", __FUNCTION__, ep); + skb = get_skb(skb, sizeof(*req), gfp); + if (!skb) { + printk(KERN_ERR MOD "%s - failed to alloc skb.\n", + __FUNCTION__); + return -ENOMEM; + } + skb->priority = CPL_PRIORITY_DATA; + set_arp_failure_handler(skb, abort_arp_failure); + req = (struct cpl_abort_req *) skb_put(skb, sizeof(*req)); + req->wr.wr_hi = htonl(V_WR_OP(FW_WROPCODE_OFLD_HOST_ABORT_CON_REQ)); + req->wr.wr_lo = htonl(V_WR_TID(ep->hwtid)); + OPCODE_TID(req) = htonl(MK_OPCODE_TID(CPL_ABORT_REQ, ep->hwtid)); + req->cmd = CPL_ABORT_SEND_RST; + l2t_send(ep->com.tdev, skb, ep->l2t); + return 0; +} + +static int send_connect(struct iwch_ep *ep) +{ + struct cpl_act_open_req *req; + struct sk_buff *skb; + u32 opt0h, opt0l, opt2; + unsigned int mtu_idx; + int wscale; + + PDBG("%s ep %p\n", __FUNCTION__, ep); + + skb = get_skb(NULL, sizeof(*req), GFP_KERNEL); + if (!skb) { + printk(KERN_ERR MOD "%s - failed to alloc skb.\n", + __FUNCTION__); + return -ENOMEM; + } + mtu_idx = find_best_mtu(T3C_DATA(ep->com.tdev), dst_mtu(ep->dst)); + wscale = compute_wscale(rcv_win); + opt0h = V_NAGLE(0) | + V_NO_CONG(nocong) | + V_KEEP_ALIVE(1) | + F_TCAM_BYPASS | + V_WND_SCALE(wscale) | + V_MSS_IDX(mtu_idx) | + V_L2T_IDX(ep->l2t->idx) | V_TX_CHANNEL(ep->l2t->smt_idx); + opt0l = V_TOS((ep->tos >> 2) & M_TOS) | V_RCV_BUFSIZ(rcv_win>>10); + opt2 = V_FLAVORS_VALID(1) | V_CONG_CONTROL_FLAVOR(cong_flavor); + skb->priority = CPL_PRIORITY_SETUP; + set_arp_failure_handler(skb, act_open_req_arp_failure); + + req = (struct cpl_act_open_req *) skb_put(skb, sizeof(*req)); + req->wr.wr_hi = htonl(V_WR_OP(FW_WROPCODE_FORWARD)); + OPCODE_TID(req) = htonl(MK_OPCODE_TID(CPL_ACT_OPEN_REQ, ep->atid)); + req->local_port = ep->com.local_addr.sin_port; + req->peer_port = ep->com.remote_addr.sin_port; + req->local_ip = ep->com.local_addr.sin_addr.s_addr; + req->peer_ip = ep->com.remote_addr.sin_addr.s_addr; + req->opt0h = htonl(opt0h); + req->opt0l = htonl(opt0l); + req->params = 0; + req->opt2 = htonl(opt2); + l2t_send(ep->com.tdev, skb, ep->l2t); + return 0; +} + +static void send_mpa_req(struct iwch_ep *ep, struct sk_buff *skb) +{ + int mpalen; + struct tx_data_wr *req; + struct mpa_message *mpa; + int len; + + PDBG("%s ep %p pd_len %d\n", __FUNCTION__, ep, ep->plen); + + BUG_ON(skb_cloned(skb)); + + mpalen = sizeof(*mpa) + ep->plen; + if (skb->data + mpalen + sizeof(*req) > skb->end) { + kfree_skb(skb); + skb=alloc_skb(mpalen + sizeof(*req), GFP_KERNEL); + if (!skb) { + connect_reply_upcall(ep, -ENOMEM); + return; + } + } + skb_trim(skb, 0); + skb_reserve(skb, sizeof(*req)); + skb_put(skb, mpalen); + skb->priority = CPL_PRIORITY_DATA; + mpa = (struct mpa_message *) skb->data; + memset(mpa, 0, sizeof(*mpa)); + memcpy(mpa->key, MPA_KEY_REQ, sizeof(mpa->key)); + mpa->flags = (crc_enabled ? MPA_CRC : 0) | + (markers_enabled ? MPA_MARKERS : 0); + mpa->private_data_size = htons(ep->plen); + mpa->revision = mpa_rev; + + if (ep->plen) + memcpy(mpa->private_data, ep->mpa_pkt + sizeof(*mpa), ep->plen); + + /* + * Reference the mpa skb. This ensures the data area + * will remain in memory until the hw acks the tx. + * Function tx_ack() will deref it. + */ + skb_get(skb); + set_arp_failure_handler(skb, arp_failure_discard); + skb->h.raw = skb->data; + len = skb->len; + req = (struct tx_data_wr *) skb_push(skb, sizeof(*req)); + req->wr_hi = htonl(V_WR_OP(FW_WROPCODE_OFLD_TX_DATA)); + req->wr_lo = htonl(V_WR_TID(ep->hwtid)); + req->len = htonl(len); + req->param = htonl(V_TX_PORT(ep->l2t->smt_idx) | + V_TX_SNDBUF(snd_win>>15)); + req->flags = htonl(F_TX_IMM_ACK|F_TX_INIT); + req->sndseq = htonl(ep->snd_seq); + BUG_ON(ep->mpa_skb); + ep->mpa_skb = skb; + l2t_send(ep->com.tdev, skb, ep->l2t); + start_ep_timer(ep); + state_set(&ep->com, MPA_REQ_SENT); + return; +} + +static int send_mpa_reject(struct iwch_ep *ep, const void *pdata, u8 plen) +{ + int mpalen; + struct tx_data_wr *req; + struct mpa_message *mpa; + struct sk_buff *skb; + + PDBG("%s ep %p plen %d\n", __FUNCTION__, ep, plen); + + mpalen = sizeof(*mpa) + plen; + + skb = get_skb(NULL, mpalen + sizeof(*req), GFP_KERNEL); + if (!skb) { + printk(KERN_ERR MOD "%s - cannot alloc skb!\n", __FUNCTION__); + return -ENOMEM; + } + skb_reserve(skb, sizeof(*req)); + mpa = (struct mpa_message *) skb_put(skb, mpalen); + memset(mpa, 0, sizeof(*mpa)); + memcpy(mpa->key, MPA_KEY_REP, sizeof(mpa->key)); + mpa->flags = MPA_REJECT; + mpa->revision = mpa_rev; + mpa->private_data_size = htons(plen); + if (plen) + memcpy(mpa->private_data, pdata, plen); + + /* + * Reference the mpa skb again. This ensures the data area + * will remain in memory until the hw acks the tx. + * Function tx_ack() will deref it. + */ + skb_get(skb); + skb->priority = CPL_PRIORITY_DATA; + set_arp_failure_handler(skb, arp_failure_discard); + skb->h.raw = skb->data; + req = (struct tx_data_wr *) skb_push(skb, sizeof(*req)); + req->wr_hi = htonl(V_WR_OP(FW_WROPCODE_OFLD_TX_DATA)); + req->wr_lo = htonl(V_WR_TID(ep->hwtid)); + req->len = htonl(mpalen); + req->param = htonl(V_TX_PORT(ep->l2t->smt_idx) | + V_TX_SNDBUF(snd_win>>15)); + req->flags = htonl(F_TX_IMM_ACK|F_TX_INIT); + req->sndseq = htonl(ep->snd_seq); + BUG_ON(ep->mpa_skb); + ep->mpa_skb = skb; + l2t_send(ep->com.tdev, skb, ep->l2t); + return 0; +} + +static int send_mpa_reply(struct iwch_ep *ep, const void *pdata, u8 plen) +{ + int mpalen; + struct tx_data_wr *req; + struct mpa_message *mpa; + int len; + struct sk_buff *skb; + + PDBG("%s ep %p plen %d\n", __FUNCTION__, ep, plen); + + mpalen = sizeof(*mpa) + plen; + + skb = get_skb(NULL, mpalen + sizeof(*req), GFP_KERNEL); + if (!skb) { + printk(KERN_ERR MOD "%s - cannot alloc skb!\n", __FUNCTION__); + return -ENOMEM; + } + skb->priority = CPL_PRIORITY_DATA; + skb_reserve(skb, sizeof(*req)); + mpa = (struct mpa_message *) skb_put(skb, mpalen); + memset(mpa, 0, sizeof(*mpa)); + memcpy(mpa->key, MPA_KEY_REP, sizeof(mpa->key)); + mpa->flags = (ep->mpa_attr.crc_enabled ? MPA_CRC : 0) | + (markers_enabled ? MPA_MARKERS : 0); + mpa->revision = mpa_rev; + mpa->private_data_size = htons(plen); + if (plen) + memcpy(mpa->private_data, pdata, plen); + + /* + * Reference the mpa skb. This ensures the data area + * will remain in memory until the hw acks the tx. + * Function tx_ack() will deref it. + */ + skb_get(skb); + set_arp_failure_handler(skb, arp_failure_discard); + skb->h.raw = skb->data; + len = skb->len; + req = (struct tx_data_wr *) skb_push(skb, sizeof(*req)); + req->wr_hi = htonl(V_WR_OP(FW_WROPCODE_OFLD_TX_DATA)); + req->wr_lo = htonl(V_WR_TID(ep->hwtid)); + req->len = htonl(len); + req->param = htonl(V_TX_PORT(ep->l2t->smt_idx) | + V_TX_SNDBUF(snd_win>>15)); + req->flags = htonl(F_TX_MORE | F_TX_IMM_ACK | F_TX_INIT); + req->sndseq = htonl(ep->snd_seq); + ep->mpa_skb = skb; + state_set(&ep->com, MPA_REP_SENT); + l2t_send(ep->com.tdev, skb, ep->l2t); + return 0; +} + +static int act_establish(struct t3cdev *tdev, struct sk_buff *skb, void *ctx) +{ + struct iwch_ep *ep = ctx; + struct cpl_act_establish *req = cplhdr(skb); + unsigned int tid = GET_TID(req); + + PDBG("%s ep %p tid %d\n", __FUNCTION__, ep, tid); + + dst_confirm(ep->dst); + + /* setup the hwtid for this connection */ + ep->hwtid = tid; + cxgb3_insert_tid(ep->com.tdev, &t3c_client, ep, tid); + + ep->snd_seq = ntohl(req->snd_isn); + + set_emss(ep, ntohs(req->tcp_opt)); + + /* dealloc the atid */ + cxgb3_free_atid(ep->com.tdev, ep->atid); + + /* start MPA negotiation */ + send_mpa_req(ep, skb); + + return 0; +} + +static void abort_connection(struct iwch_ep *ep, struct sk_buff *skb, gfp_t gfp) +{ + PDBG("%s ep %p\n", __FILE__, ep); + state_set(&ep->com, ABORTING); + send_abort(ep, skb, gfp); +} + +static void close_complete_upcall(struct iwch_ep *ep) +{ + struct iw_cm_event event; + + PDBG("%s ep %p\n", __FUNCTION__, ep); + memset(&event, 0, sizeof(event)); + event.event = IW_CM_EVENT_CLOSE; + if (ep->com.cm_id) { + PDBG("close complete delivered ep %p cm_id %p tid %d\n", + ep, ep->com.cm_id, ep->hwtid); + ep->com.cm_id->event_handler(ep->com.cm_id, &event); + ep->com.cm_id->rem_ref(ep->com.cm_id); + ep->com.cm_id = NULL; + ep->com.qp = NULL; + } +} + +static void peer_close_upcall(struct iwch_ep *ep) +{ + struct iw_cm_event event; + + PDBG("%s ep %p\n", __FUNCTION__, ep); + memset(&event, 0, sizeof(event)); + event.event = IW_CM_EVENT_DISCONNECT; + if (ep->com.cm_id) { + PDBG("peer close delivered ep %p cm_id %p tid %d\n", + ep, ep->com.cm_id, ep->hwtid); + ep->com.cm_id->event_handler(ep->com.cm_id, &event); + } +} + +static void peer_abort_upcall(struct iwch_ep *ep) +{ + struct iw_cm_event event; + + PDBG("%s ep %p\n", __FUNCTION__, ep); + memset(&event, 0, sizeof(event)); + event.event = IW_CM_EVENT_CLOSE; + event.status = -ECONNRESET; + if (ep->com.cm_id) { + PDBG("abort delivered ep %p cm_id %p tid %d\n", ep, + ep->com.cm_id, ep->hwtid); + ep->com.cm_id->event_handler(ep->com.cm_id, &event); + ep->com.cm_id->rem_ref(ep->com.cm_id); + ep->com.cm_id = NULL; + ep->com.qp = NULL; + } +} + +static void connect_reply_upcall(struct iwch_ep *ep, int status) +{ + struct iw_cm_event event; + + PDBG("%s ep %p status %d\n", __FUNCTION__, ep, status); + memset(&event, 0, sizeof(event)); + event.event = IW_CM_EVENT_CONNECT_REPLY; + event.status = status; + event.local_addr = ep->com.local_addr; + event.remote_addr = ep->com.remote_addr; + + if ((status == 0) || (status == -ECONNREFUSED)) { + event.private_data_len = ep->plen; + event.private_data = ep->mpa_pkt + sizeof(struct mpa_message); + } + if (ep->com.cm_id) { + PDBG("%s ep %p tid %d status %d\n", __FUNCTION__, ep, + ep->hwtid, status); + ep->com.cm_id->event_handler(ep->com.cm_id, &event); + } + if (status < 0) { + ep->com.cm_id->rem_ref(ep->com.cm_id); + ep->com.cm_id = NULL; + ep->com.qp = NULL; + } +} + +static void connect_request_upcall(struct iwch_ep *ep) +{ + struct iw_cm_event event; + + PDBG("%s ep %p tid %d\n", __FUNCTION__, ep, ep->hwtid); + memset(&event, 0, sizeof(event)); + event.event = IW_CM_EVENT_CONNECT_REQUEST; + event.local_addr = ep->com.local_addr; + event.remote_addr = ep->com.remote_addr; + event.private_data_len = ep->plen; + event.private_data = ep->mpa_pkt + sizeof(struct mpa_message); + event.provider_data = ep; + if (state_read(&ep->parent_ep->com) != DEAD) + ep->parent_ep->com.cm_id->event_handler( + ep->parent_ep->com.cm_id, + &event); + put_ep(&ep->parent_ep->com); + ep->parent_ep = NULL; +} + +static void established_upcall(struct iwch_ep *ep) +{ + struct iw_cm_event event; + + PDBG("%s ep %p\n", __FUNCTION__, ep); + memset(&event, 0, sizeof(event)); + event.event = IW_CM_EVENT_ESTABLISHED; + if (ep->com.cm_id) { + PDBG("%s ep %p tid %d\n", __FUNCTION__, ep, ep->hwtid); + ep->com.cm_id->event_handler(ep->com.cm_id, &event); + } +} + +static int update_rx_credits(struct iwch_ep *ep, u32 credits) +{ + struct cpl_rx_data_ack *req; + struct sk_buff *skb; + + PDBG("%s ep %p credits %u\n", __FUNCTION__, ep, credits); + skb = get_skb(NULL, sizeof(*req), GFP_KERNEL); + if (!skb) { + printk(KERN_ERR MOD "update_rx_credits - cannot alloc skb!\n"); + return 0; + } + + req = (struct cpl_rx_data_ack *) skb_put(skb, sizeof(*req)); + req->wr.wr_hi = htonl(V_WR_OP(FW_WROPCODE_FORWARD)); + OPCODE_TID(req) = htonl(MK_OPCODE_TID(CPL_RX_DATA_ACK, ep->hwtid)); + req->credit_dack = htonl(V_RX_CREDITS(credits) | V_RX_FORCE_ACK(1)); + skb->priority = CPL_PRIORITY_ACK; + ep->com.tdev->send(ep->com.tdev, skb); + return credits; +} + +static void process_mpa_reply(struct iwch_ep *ep, struct sk_buff *skb) +{ + struct mpa_message *mpa; + u16 plen; + struct iwch_qp_attributes attrs; + enum iwch_qp_attr_mask mask; + int err; + + PDBG("%s ep %p\n", __FUNCTION__, ep); + + /* + * Stop mpa timer. If it expired, then the state has + * changed and we bail since ep_timeout already aborted + * the connection. + */ + stop_ep_timer(ep); + if (state_read(&ep->com) != MPA_REQ_SENT) + return; + + /* + * If we get more than the supported amount of private data + * then we must fail this connection. + */ + if (ep->mpa_pkt_len + skb->len > sizeof(ep->mpa_pkt)) { + err = -EINVAL; + goto err; + } + + /* + * copy the new data into our accumulation buffer. + */ + memcpy(&(ep->mpa_pkt[ep->mpa_pkt_len]), skb->data, skb->len); + ep->mpa_pkt_len += skb->len; + + /* + * if we don't even have the mpa message, then bail. + */ + if (ep->mpa_pkt_len < sizeof(*mpa)) + return; + mpa = (struct mpa_message *) ep->mpa_pkt; + + /* Validate MPA header. */ + if (mpa->revision != mpa_rev) { + err = -EPROTO; + goto err; + } + if (memcmp(mpa->key, MPA_KEY_REP, sizeof(mpa->key))) { + err = -EPROTO; + goto err; + } + + plen = ntohs(mpa->private_data_size); + + /* + * Fail if there's too much private data. + */ + if (plen > MPA_MAX_PRIVATE_DATA) { + err = -EPROTO; + goto err; + } + + /* + * If plen does not account for pkt size + */ + if (ep->mpa_pkt_len > (sizeof(*mpa) + plen)) { + err = -EPROTO; + goto err; + } + + ep->plen = (u8) plen; + + /* + * If we don't have all the pdata yet, then bail. + * We'll continue process when more data arrives. + */ + if (ep->mpa_pkt_len < (sizeof(*mpa) + plen)) + return; + + if (mpa->flags & MPA_REJECT) { + err = -ECONNREFUSED; + goto err; + } + + /* + * If we get here we have accumulated the entire mpa + * start reply message including private data. And + * the MPA header is valid. + */ + state_set(&ep->com, FPDU_MODE); + ep->mpa_attr.crc_enabled = (mpa->flags & MPA_CRC) | crc_enabled ? 1 : 0; + ep->mpa_attr.recv_marker_enabled = markers_enabled; + ep->mpa_attr.xmit_marker_enabled = mpa->flags & MPA_MARKERS ? 1 : 0; + ep->mpa_attr.version = mpa_rev; + PDBG("%s - crc_enabled=%d, recv_marker_enabled=%d, " + "xmit_marker_enabled=%d, version=%d\n", __FUNCTION__, + ep->mpa_attr.crc_enabled, ep->mpa_attr.recv_marker_enabled, + ep->mpa_attr.xmit_marker_enabled, ep->mpa_attr.version); + + attrs.mpa_attr = ep->mpa_attr; + attrs.max_ird = ep->ird; + attrs.max_ord = ep->ord; + attrs.llp_stream_handle = ep; + attrs.next_state = IWCH_QP_STATE_RTS; + + mask = IWCH_QP_ATTR_NEXT_STATE | + IWCH_QP_ATTR_LLP_STREAM_HANDLE | IWCH_QP_ATTR_MPA_ATTR | + IWCH_QP_ATTR_MAX_IRD | IWCH_QP_ATTR_MAX_ORD; + + /* bind QP and TID with INIT_WR */ + err = iwch_modify_qp(ep->com.qp->rhp, + ep->com.qp, mask, &attrs, 1); + if (!err) + goto out; +err: + abort_connection(ep, skb, GFP_KERNEL); +out: + connect_reply_upcall(ep, err); + return; +} + +static void process_mpa_request(struct iwch_ep *ep, struct sk_buff *skb) +{ + struct mpa_message *mpa; + u16 plen; + + PDBG("%s ep %p\n", __FUNCTION__, ep); + + /* + * Stop mpa timer. If it expired, then the state has + * changed and we bail since ep_timeout already aborted + * the connection. + */ + stop_ep_timer(ep); + if (state_read(&ep->com) != MPA_REQ_WAIT) + return; + + /* + * If we get more than the supported amount of private data + * then we must fail this connection. + */ + if (ep->mpa_pkt_len + skb->len > sizeof(ep->mpa_pkt)) { + abort_connection(ep, skb, GFP_KERNEL); + return; + } + + PDBG("%s enter (%s line %u)\n", __FUNCTION__, __FILE__, __LINE__); + + /* + * Copy the new data into our accumulation buffer. + */ + memcpy(&(ep->mpa_pkt[ep->mpa_pkt_len]), skb->data, skb->len); + ep->mpa_pkt_len += skb->len; + + /* + * If we don't even have the mpa message, then bail. + * We'll continue process when more data arrives. + */ + if (ep->mpa_pkt_len < sizeof(*mpa)) + return; + PDBG("%s enter (%s line %u)\n", __FUNCTION__, __FILE__, __LINE__); + mpa = (struct mpa_message *) ep->mpa_pkt; + + /* + * Validate MPA Header. + */ + if (mpa->revision != mpa_rev) { + abort_connection(ep, skb, GFP_KERNEL); + return; + } + + if (memcmp(mpa->key, MPA_KEY_REQ, sizeof(mpa->key))) { + abort_connection(ep, skb, GFP_KERNEL); + return; + } + + plen = ntohs(mpa->private_data_size); + + /* + * Fail if there's too much private data. + */ + if (plen > MPA_MAX_PRIVATE_DATA) { + abort_connection(ep, skb, GFP_KERNEL); + return; + } + + /* + * If plen does not account for pkt size + */ + if (ep->mpa_pkt_len > (sizeof(*mpa) + plen)) { + abort_connection(ep, skb, GFP_KERNEL); + return; + } + ep->plen = (u8) plen; + + /* + * If we don't have all the pdata yet, then bail. + */ + if (ep->mpa_pkt_len < (sizeof(*mpa) + plen)) + return; + + /* + * If we get here we have accumulated the entire mpa + * start reply message including private data. + */ + ep->mpa_attr.crc_enabled = (mpa->flags & MPA_CRC) | crc_enabled ? 1 : 0; + ep->mpa_attr.recv_marker_enabled = markers_enabled; + ep->mpa_attr.xmit_marker_enabled = mpa->flags & MPA_MARKERS ? 1 : 0; + ep->mpa_attr.version = mpa_rev; + PDBG("%s - crc_enabled=%d, recv_marker_enabled=%d, " + "xmit_marker_enabled=%d, version=%d\n", __FUNCTION__, + ep->mpa_attr.crc_enabled, ep->mpa_attr.recv_marker_enabled, + ep->mpa_attr.xmit_marker_enabled, ep->mpa_attr.version); + + state_set(&ep->com, MPA_REQ_RCVD); + + /* drive upcall */ + connect_request_upcall(ep); + return; +} + +static int rx_data(struct t3cdev *tdev, struct sk_buff *skb, void *ctx) +{ + struct iwch_ep *ep = ctx; + struct cpl_rx_data *hdr = cplhdr(skb); + unsigned int dlen = ntohs(hdr->len); + + PDBG("%s ep %p dlen %u\n", __FUNCTION__, ep, dlen); + + skb_pull(skb, sizeof(*hdr)); + skb_trim(skb, dlen); + + switch (state_read(&ep->com)) { + case MPA_REQ_SENT: + process_mpa_reply(ep, skb); + break; + case MPA_REQ_WAIT: + process_mpa_request(ep, skb); + break; + case MPA_REP_SENT: + break; + default: + printk(KERN_ERR MOD "%s Unexpected streaming data." + " ep %p state %d tid %d\n", + __FUNCTION__, ep, state_read(&ep->com), ep->hwtid); + + /* + * The ep will timeout and inform the ULP of the failure. + * See ep_timeout(). + */ + break; + } + + /* update RX credits */ + update_rx_credits(ep, dlen); + + return CPL_RET_BUF_DONE; +} + +/* + * Upcall from the adapter indicating data has been transmitted. + * For us its just the single MPA request or reply. We can now free + * the skb holding the mpa message. + */ +static int tx_ack(struct t3cdev *tdev, struct sk_buff *skb, void *ctx) +{ + struct iwch_ep *ep = ctx; + struct cpl_wr_ack *hdr = cplhdr(skb); + unsigned int credits = ntohs(hdr->credits); + enum iwch_qp_attr_mask mask; + + PDBG("%s ep %p credits %u\n", __FUNCTION__, ep, credits); + + if (credits == 0) + return CPL_RET_BUF_DONE; + BUG_ON(credits != 1); + BUG_ON(ep->mpa_skb == NULL); + kfree_skb(ep->mpa_skb); + ep->mpa_skb = NULL; + dst_confirm(ep->dst); + if (state_read(&ep->com) == MPA_REP_SENT) { + struct iwch_qp_attributes attrs; + + /* bind QP to EP and move to RTS */ + attrs.mpa_attr = ep->mpa_attr; + attrs.max_ird = ep->ord; + attrs.max_ord = ep->ord; + attrs.llp_stream_handle = ep; + attrs.next_state = IWCH_QP_STATE_RTS; + + /* bind QP and TID with INIT_WR */ + mask = IWCH_QP_ATTR_NEXT_STATE | + IWCH_QP_ATTR_LLP_STREAM_HANDLE | + IWCH_QP_ATTR_MPA_ATTR | + IWCH_QP_ATTR_MAX_IRD | + IWCH_QP_ATTR_MAX_ORD; + + ep->com.rpl_err = iwch_modify_qp(ep->com.qp->rhp, + ep->com.qp, mask, &attrs, 1); + + if (!ep->com.rpl_err) { + state_set(&ep->com, FPDU_MODE); + established_upcall(ep); + } + + ep->com.rpl_done = 1; + PDBG("waking up ep %p\n", ep); + wake_up(&ep->com.waitq); + } + return CPL_RET_BUF_DONE; +} + +static int abort_rpl(struct t3cdev *tdev, struct sk_buff *skb, void *ctx) +{ + struct iwch_ep *ep = ctx; + + PDBG("%s ep %p\n", __FUNCTION__, ep); + + close_complete_upcall(ep); + state_set(&ep->com, DEAD); + release_ep_resources(ep); + return CPL_RET_BUF_DONE; +} + +static int act_open_rpl(struct t3cdev *tdev, struct sk_buff *skb, void *ctx) +{ + struct iwch_ep *ep = ctx; + struct cpl_act_open_rpl *rpl = cplhdr(skb); + + PDBG("%s ep %p status %u errno %d\n", __FUNCTION__, ep, rpl->status, + status2errno(rpl->status)); + connect_reply_upcall(ep, status2errno(rpl->status)); + state_set(&ep->com, DEAD); + if (ep->com.tdev->type == T3B) + release_tid(ep->com.tdev, GET_TID(rpl), NULL); + cxgb3_free_atid(ep->com.tdev, ep->atid); + dst_release(ep->dst); + l2t_release(L2DATA(ep->com.tdev), ep->l2t); + put_ep(&ep->com); + return CPL_RET_BUF_DONE; +} + +static int listen_start(struct iwch_listen_ep *ep) +{ + struct sk_buff *skb; + struct cpl_pass_open_req *req; + + PDBG("%s ep %p\n", __FUNCTION__, ep); + skb = get_skb(NULL, sizeof(*req), GFP_KERNEL); + if (!skb) { + printk(KERN_ERR MOD "t3c_listen_start failed to alloc skb!\n"); + return -ENOMEM; + } + + req = (struct cpl_pass_open_req *) skb_put(skb, sizeof(*req)); + req->wr.wr_hi = htonl(V_WR_OP(FW_WROPCODE_FORWARD)); + OPCODE_TID(req) = htonl(MK_OPCODE_TID(CPL_PASS_OPEN_REQ, ep->stid)); + req->local_port = ep->com.local_addr.sin_port; + req->local_ip = ep->com.local_addr.sin_addr.s_addr; + req->peer_port = 0; + req->peer_ip = 0; + req->peer_netmask = 0; + req->opt0h = htonl(F_DELACK | F_TCAM_BYPASS); + req->opt0l = htonl(V_RCV_BUFSIZ(rcv_win>>10)); + req->opt1 = htonl(V_CONN_POLICY(CPL_CONN_POLICY_ASK)); + + skb->priority = 1; + ep->com.tdev->send(ep->com.tdev, skb); + return 0; +} + +static int pass_open_rpl(struct t3cdev *tdev, struct sk_buff *skb, void *ctx) +{ + struct iwch_listen_ep *ep = ctx; + struct cpl_pass_open_rpl *rpl = cplhdr(skb); + + PDBG("%s ep %p status %d error %d\n", __FUNCTION__, ep, + rpl->status, status2errno(rpl->status)); + ep->com.rpl_err = status2errno(rpl->status); + ep->com.rpl_done = 1; + wake_up(&ep->com.waitq); + + return CPL_RET_BUF_DONE; +} + +static int listen_stop(struct iwch_listen_ep *ep) +{ + struct sk_buff *skb; + struct cpl_close_listserv_req *req; + + PDBG("%s ep %p\n", __FUNCTION__, ep); + skb = get_skb(NULL, sizeof(*req), GFP_KERNEL); + if (!skb) { + printk(KERN_ERR MOD "%s - failed to alloc skb\n", __FUNCTION__); + return -ENOMEM; + } + req = (struct cpl_close_listserv_req *) skb_put(skb, sizeof(*req)); + req->wr.wr_hi = htonl(V_WR_OP(FW_WROPCODE_FORWARD)); + OPCODE_TID(req) = htonl(MK_OPCODE_TID(CPL_CLOSE_LISTSRV_REQ, ep->stid)); + skb->priority = 1; + ep->com.tdev->send(ep->com.tdev, skb); + return 0; +} + +static int close_listsrv_rpl(struct t3cdev *tdev, struct sk_buff *skb, + void *ctx) +{ + struct iwch_listen_ep *ep = ctx; + struct cpl_close_listserv_rpl *rpl = cplhdr(skb); + + PDBG("%s ep %p\n", __FUNCTION__, ep); + ep->com.rpl_err = status2errno(rpl->status); + ep->com.rpl_done = 1; + wake_up(&ep->com.waitq); + return CPL_RET_BUF_DONE; +} + +static void accept_cr(struct iwch_ep *ep, __be32 peer_ip, struct sk_buff *skb) +{ + struct cpl_pass_accept_rpl *rpl; + unsigned int mtu_idx; + u32 opt0h, opt0l, opt2; + int wscale; + + PDBG("%s ep %p\n", __FUNCTION__, ep); + BUG_ON(skb_cloned(skb)); + skb_trim(skb, sizeof(*rpl)); + skb_get(skb); + mtu_idx = find_best_mtu(T3C_DATA(ep->com.tdev), dst_mtu(ep->dst)); + wscale = compute_wscale(rcv_win); + opt0h = V_NAGLE(0) | + V_NO_CONG(nocong) | + V_KEEP_ALIVE(1) | + F_TCAM_BYPASS | + V_WND_SCALE(wscale) | + V_MSS_IDX(mtu_idx) | + V_L2T_IDX(ep->l2t->idx) | V_TX_CHANNEL(ep->l2t->smt_idx); + opt0l = V_TOS((ep->tos >> 2) & M_TOS) | V_RCV_BUFSIZ(rcv_win>>10); + opt2 = V_FLAVORS_VALID(1) | V_CONG_CONTROL_FLAVOR(cong_flavor); + + rpl = cplhdr(skb); + rpl->wr.wr_hi = htonl(V_WR_OP(FW_WROPCODE_FORWARD)); + OPCODE_TID(rpl) = htonl(MK_OPCODE_TID(CPL_PASS_ACCEPT_RPL, ep->hwtid)); + rpl->peer_ip = peer_ip; + rpl->opt0h = htonl(opt0h); + rpl->opt0l_status = htonl(opt0l | CPL_PASS_OPEN_ACCEPT); + rpl->opt2 = htonl(opt2); + rpl->rsvd = rpl->opt2; /* workaround for HW bug */ + skb->priority = CPL_PRIORITY_SETUP; + l2t_send(ep->com.tdev, skb, ep->l2t); + + return; +} + +static void reject_cr(struct t3cdev *tdev, u32 hwtid, __be32 peer_ip, + struct sk_buff *skb) +{ + PDBG("%s t3cdev %p tid %u peer_ip %x\n", __FUNCTION__, tdev, hwtid, + peer_ip); + BUG_ON(skb_cloned(skb)); + skb_trim(skb, sizeof(struct cpl_tid_release)); + skb_get(skb); + + if (tdev->type == T3B) + release_tid(tdev, hwtid, skb); + else { + struct cpl_pass_accept_rpl *rpl; + + rpl = cplhdr(skb); + skb->priority = CPL_PRIORITY_SETUP; + rpl->wr.wr_hi = htonl(V_WR_OP(FW_WROPCODE_FORWARD)); + OPCODE_TID(rpl) = htonl(MK_OPCODE_TID(CPL_PASS_ACCEPT_RPL, + hwtid)); + rpl->peer_ip = peer_ip; + rpl->opt0h = htonl(F_TCAM_BYPASS); + rpl->opt0l_status = htonl(CPL_PASS_OPEN_REJECT); + rpl->opt2 = 0; + rpl->rsvd = rpl->opt2; + tdev->send(tdev, skb); + } +} + +static int pass_accept_req(struct t3cdev *tdev, struct sk_buff *skb, void *ctx) +{ + struct iwch_ep *child_ep, *parent_ep = ctx; + struct cpl_pass_accept_req *req = cplhdr(skb); + unsigned int hwtid = GET_TID(req); + struct dst_entry *dst; + struct l2t_entry *l2t; + struct rtable *rt; + struct iff_mac tim; + + PDBG("%s parent ep %p tid %u\n", __FUNCTION__, parent_ep, hwtid); + + if (state_read(&parent_ep->com) != LISTEN) { + printk(KERN_ERR "%s - listening ep not in LISTEN\n", + __FUNCTION__); + goto reject; + } + + /* + * Find the netdev for this connection request. + */ + tim.mac_addr = req->dst_mac; + tim.vlan_tag = ntohs(req->vlan_tag); + if (tdev->ctl(tdev, GET_IFF_FROM_MAC, &tim) < 0 || !tim.dev) { + printk(KERN_ERR + "%s bad dst mac %02x %02x %02x %02x %02x %02x\n", + __FUNCTION__, + req->dst_mac[0], + req->dst_mac[1], + req->dst_mac[2], + req->dst_mac[3], + req->dst_mac[4], + req->dst_mac[5]); + goto reject; + } + + /* Find output route */ + rt = find_route(tdev, + req->local_ip, + req->peer_ip, + req->local_port, + req->peer_port, G_PASS_OPEN_TOS(ntohl(req->tos_tid))); + if (!rt) { + printk(KERN_ERR MOD "%s - failed to find dst entry!\n", + __FUNCTION__); + goto reject; + } + dst = &rt->u.dst; + l2t = t3_l2t_get(tdev, dst->neighbour, dst->neighbour->dev); + if (!l2t) { + printk(KERN_ERR MOD "%s - failed to allocate l2t entry!\n", + __FUNCTION__); + dst_release(dst); + goto reject; + } + child_ep = alloc_ep(sizeof(*child_ep), GFP_KERNEL); + if (!child_ep) { + printk(KERN_ERR MOD "%s - failed to allocate ep entry!\n", + __FUNCTION__); + l2t_release(L2DATA(tdev), l2t); + dst_release(dst); + goto reject; + } + state_set(&child_ep->com, CONNECTING); + child_ep->com.tdev = tdev; + child_ep->com.cm_id = NULL; + child_ep->com.local_addr.sin_family = PF_INET; + child_ep->com.local_addr.sin_port = req->local_port; + child_ep->com.local_addr.sin_addr.s_addr = req->local_ip; + child_ep->com.remote_addr.sin_family = PF_INET; + child_ep->com.remote_addr.sin_port = req->peer_port; + child_ep->com.remote_addr.sin_addr.s_addr = req->peer_ip; + get_ep(&parent_ep->com); + child_ep->parent_ep = parent_ep; + child_ep->tos = G_PASS_OPEN_TOS(ntohl(req->tos_tid)); + child_ep->l2t = l2t; + child_ep->dst = dst; + child_ep->hwtid = hwtid; + init_timer(&child_ep->timer); + cxgb3_insert_tid(tdev, &t3c_client, child_ep, hwtid); + accept_cr(child_ep, req->peer_ip, skb); + goto out; +reject: + reject_cr(tdev, hwtid, req->peer_ip, skb); +out: + return CPL_RET_BUF_DONE; +} + +static int pass_establish(struct t3cdev *tdev, struct sk_buff *skb, void *ctx) +{ + struct iwch_ep *ep = ctx; + struct cpl_pass_establish *req = cplhdr(skb); + + PDBG("%s ep %p\n", __FUNCTION__, ep); + ep->snd_seq = ntohl(req->snd_isn); + + set_emss(ep, ntohs(req->tcp_opt)); + + dst_confirm(ep->dst); + state_set(&ep->com, MPA_REQ_WAIT); + start_ep_timer(ep); + + return CPL_RET_BUF_DONE; +} + +static int peer_close(struct t3cdev *tdev, struct sk_buff *skb, void *ctx) +{ + struct iwch_ep *ep = ctx; + struct iwch_qp_attributes attrs; + unsigned long flags; + int disconnect = 1; + int release = 0; + + PDBG("%s ep %p\n", __FUNCTION__, ep); + dst_confirm(ep->dst); + + spin_lock_irqsave(&ep->com.lock, flags); + switch (ep->com.state) { + case MPA_REQ_WAIT: + __state_set(&ep->com, CLOSING); + break; + case MPA_REQ_SENT: + __state_set(&ep->com, CLOSING); + connect_reply_upcall(ep, -ECONNRESET); + break; + case MPA_REQ_RCVD: + + /* + * We're gonna mark this puppy DEAD, but keep + * the reference on it until the ULP accepts or + * rejects the CR. + */ + __state_set(&ep->com, CLOSING); + get_ep(&ep->com); + break; + case MPA_REP_SENT: + __state_set(&ep->com, CLOSING); + ep->com.rpl_done = 1; + ep->com.rpl_err = -ECONNRESET; + PDBG("waking up ep %p\n", ep); + wake_up(&ep->com.waitq); + break; + case FPDU_MODE: + __state_set(&ep->com, CLOSING); + attrs.next_state = IWCH_QP_STATE_CLOSING; + iwch_modify_qp(ep->com.qp->rhp, ep->com.qp, + IWCH_QP_ATTR_NEXT_STATE, &attrs, 1); + peer_close_upcall(ep); + break; + case ABORTING: + disconnect = 0; + break; + case CLOSING: + start_ep_timer(ep); + __state_set(&ep->com, MORIBUND); + disconnect = 0; + break; + case MORIBUND: + stop_ep_timer(ep); + if (ep->com.cm_id && ep->com.qp) { + attrs.next_state = IWCH_QP_STATE_IDLE; + iwch_modify_qp(ep->com.qp->rhp, ep->com.qp, + IWCH_QP_ATTR_NEXT_STATE, &attrs, 1); + } + close_complete_upcall(ep); + __state_set(&ep->com, DEAD); + release = 1; + disconnect = 0; + break; + case DEAD: + disconnect = 0; + break; + default: + BUG_ON(1); + } + spin_unlock_irqrestore(&ep->com.lock, flags); + if (disconnect) + iwch_ep_disconnect(ep, 0, GFP_KERNEL); + if (release) + release_ep_resources(ep); + return CPL_RET_BUF_DONE; +} + +/* + * Returns whether an ABORT_REQ_RSS message is a negative advice. + */ +static inline int is_neg_adv_abort(unsigned int status) +{ + return status == CPL_ERR_RTX_NEG_ADVICE || + status == CPL_ERR_PERSIST_NEG_ADVICE; +} + +static int peer_abort(struct t3cdev *tdev, struct sk_buff *skb, void *ctx) +{ + struct cpl_abort_req_rss *req = cplhdr(skb); + struct iwch_ep *ep = ctx; + struct cpl_abort_rpl *rpl; + struct sk_buff *rpl_skb; + struct iwch_qp_attributes attrs; + int ret; + int state; + + if (is_neg_adv_abort(req->status)) { + PDBG("%s neg_adv_abort ep %p tid %d\n", __FUNCTION__, ep, + ep->hwtid); + t3_l2t_send_event(ep->com.tdev, ep->l2t); + return CPL_RET_BUF_DONE; + } + + state = state_read(&ep->com); + PDBG("%s ep %p state %u\n", __FUNCTION__, ep, state); + switch (state) { + case CONNECTING: + break; + case MPA_REQ_WAIT: + break; + case MPA_REQ_SENT: + connect_reply_upcall(ep, -ECONNRESET); + break; + case MPA_REP_SENT: + ep->com.rpl_done = 1; + ep->com.rpl_err = -ECONNRESET; + PDBG("waking up ep %p\n", ep); + wake_up(&ep->com.waitq); + break; + case MPA_REQ_RCVD: + + /* + * We're gonna mark this puppy DEAD, but keep + * the reference on it until the ULP accepts or + * rejects the CR. + */ + get_ep(&ep->com); + break; + case MORIBUND: + stop_ep_timer(ep); + case FPDU_MODE: + case CLOSING: + if (ep->com.cm_id && ep->com.qp) { + attrs.next_state = IWCH_QP_STATE_ERROR; + ret = iwch_modify_qp(ep->com.qp->rhp, + ep->com.qp, IWCH_QP_ATTR_NEXT_STATE, + &attrs, 1); + if (ret) + printk(KERN_ERR MOD + "%s - qp <- error failed!\n", + __FUNCTION__); + } + peer_abort_upcall(ep); + break; + case ABORTING: + break; + case DEAD: + PDBG("%s PEER_ABORT IN DEAD STATE!!!!\n", __FUNCTION__); + return CPL_RET_BUF_DONE; + default: + BUG_ON(1); + break; + } + dst_confirm(ep->dst); + + rpl_skb = get_skb(skb, sizeof(*rpl), GFP_KERNEL); + if (!rpl_skb) { + printk(KERN_ERR MOD "%s - cannot allocate skb!\n", + __FUNCTION__); + dst_release(ep->dst); + l2t_release(L2DATA(ep->com.tdev), ep->l2t); + put_ep(&ep->com); + return CPL_RET_BUF_DONE; + } + rpl_skb->priority = CPL_PRIORITY_DATA; + rpl = (struct cpl_abort_rpl *) skb_put(rpl_skb, sizeof(*rpl)); + rpl->wr.wr_hi = htonl(V_WR_OP(FW_WROPCODE_OFLD_HOST_ABORT_CON_RPL)); + rpl->wr.wr_lo = htonl(V_WR_TID(ep->hwtid)); + OPCODE_TID(rpl) = htonl(MK_OPCODE_TID(CPL_ABORT_RPL, ep->hwtid)); + rpl->cmd = CPL_ABORT_NO_RST; + ep->com.tdev->send(ep->com.tdev, rpl_skb); + if (state != ABORTING) { + state_set(&ep->com, DEAD); + release_ep_resources(ep); + } + return CPL_RET_BUF_DONE; +} + +static int close_con_rpl(struct t3cdev *tdev, struct sk_buff *skb, void *ctx) +{ + struct iwch_ep *ep = ctx; + struct iwch_qp_attributes attrs; + unsigned long flags; + int release = 0; + + PDBG("%s ep %p\n", __FUNCTION__, ep); + BUG_ON(!ep); + + /* The cm_id may be null if we failed to connect */ + spin_lock_irqsave(&ep->com.lock, flags); + switch (ep->com.state) { + case CLOSING: + start_ep_timer(ep); + __state_set(&ep->com, MORIBUND); + break; + case MORIBUND: + stop_ep_timer(ep); + if ((ep->com.cm_id) && (ep->com.qp)) { + attrs.next_state = IWCH_QP_STATE_IDLE; + iwch_modify_qp(ep->com.qp->rhp, + ep->com.qp, + IWCH_QP_ATTR_NEXT_STATE, + &attrs, 1); + } + close_complete_upcall(ep); + __state_set(&ep->com, DEAD); + release = 1; + break; + case DEAD: + default: + BUG_ON(1); + break; + } + spin_unlock_irqrestore(&ep->com.lock, flags); + if (release) + release_ep_resources(ep); + return CPL_RET_BUF_DONE; +} + +/* + * T3A does 3 things when a TERM is received: + * 1) send up a CPL_RDMA_TERMINATE message with the TERM packet + * 2) generate an async event on the QP with the TERMINATE opcode + * 3) post a TERMINATE opcde cqe into the associated CQ. + * + * For (1), we save the message in the qp for later consumer consumption. + * For (2), we move the QP into TERMINATE, post a QP event and disconnect. + * For (3), we toss the CQE in cxio_poll_cq(). + * + * terminate() handles case (1)... + */ +static int terminate(struct t3cdev *tdev, struct sk_buff *skb, void *ctx) +{ + struct iwch_ep *ep = ctx; + + PDBG("%s ep %p\n", __FUNCTION__, ep); + skb_pull(skb, sizeof(struct cpl_rdma_terminate)); + PDBG("%s saving %d bytes of term msg\n", __FUNCTION__, skb->len); + memcpy(ep->com.qp->attr.terminate_buffer, skb->data, skb->len); + ep->com.qp->attr.terminate_msg_len = skb->len; + ep->com.qp->attr.is_terminate_local = 0; + return CPL_RET_BUF_DONE; +} + +static int ec_status(struct t3cdev *tdev, struct sk_buff *skb, void *ctx) +{ + struct cpl_rdma_ec_status *rep = cplhdr(skb); + struct iwch_ep *ep = ctx; + + PDBG("%s ep %p tid %u status %d\n", __FUNCTION__, ep, ep->hwtid, + rep->status); + if (rep->status) { + struct iwch_qp_attributes attrs; + + printk(KERN_ERR MOD "%s BAD CLOSE - Aborting tid %u\n", + __FUNCTION__, ep->hwtid); + attrs.next_state = IWCH_QP_STATE_ERROR; + iwch_modify_qp(ep->com.qp->rhp, + ep->com.qp, IWCH_QP_ATTR_NEXT_STATE, + &attrs, 1); + abort_connection(ep, NULL, GFP_KERNEL); + } + return CPL_RET_BUF_DONE; +} + +static void ep_timeout(unsigned long arg) +{ + struct iwch_ep *ep = (struct iwch_ep *)arg; + struct iwch_qp_attributes attrs; + unsigned long flags; + + spin_lock_irqsave(&ep->com.lock, flags); + PDBG("%s ep %p tid %u state %d\n", __FUNCTION__, ep, ep->hwtid, + ep->com.state); + switch (ep->com.state) { + case MPA_REQ_SENT: + connect_reply_upcall(ep, -ETIMEDOUT); + break; + case MPA_REQ_WAIT: + break; + case MORIBUND: + if (ep->com.cm_id && ep->com.qp) { + attrs.next_state = IWCH_QP_STATE_ERROR; + iwch_modify_qp(ep->com.qp->rhp, + ep->com.qp, IWCH_QP_ATTR_NEXT_STATE, + &attrs, 1); + } + break; + default: + BUG(); + } + __state_set(&ep->com, CLOSING); + spin_unlock_irqrestore(&ep->com.lock, flags); + abort_connection(ep, NULL, GFP_ATOMIC); + put_ep(&ep->com); +} + +int iwch_reject_cr(struct iw_cm_id *cm_id, const void *pdata, u8 pdata_len) +{ + int err; + struct iwch_ep *ep = to_ep(cm_id); + PDBG("%s ep %p tid %u\n", __FUNCTION__, ep, ep->hwtid); + + if (state_read(&ep->com) == DEAD) { + put_ep(&ep->com); + return -ECONNRESET; + } + BUG_ON(state_read(&ep->com) != MPA_REQ_RCVD); + state_set(&ep->com, CLOSING); + if (mpa_rev == 0) + abort_connection(ep, NULL, GFP_KERNEL); + else { + err = send_mpa_reject(ep, pdata, pdata_len); + err = send_halfclose(ep, GFP_KERNEL); + } + return 0; +} + +int iwch_accept_cr(struct iw_cm_id *cm_id, struct iw_cm_conn_param *conn_param) +{ + int err; + struct iwch_qp_attributes attrs; + enum iwch_qp_attr_mask mask; + struct iwch_ep *ep = to_ep(cm_id); + struct iwch_dev *h = to_iwch_dev(cm_id->device); + struct iwch_qp *qp = get_qhp(h, conn_param->qpn); + + PDBG("%s ep %p tid %u\n", __FUNCTION__, ep, ep->hwtid); + if (state_read(&ep->com) == DEAD) { + put_ep(&ep->com); + return -ECONNRESET; + } + + BUG_ON(state_read(&ep->com) != MPA_REQ_RCVD); + BUG_ON(!qp); + + if ((conn_param->ord > qp->rhp->attr.max_rdma_read_qp_depth) || + (conn_param->ird > qp->rhp->attr.max_rdma_reads_per_qp)) { + abort_connection(ep, NULL, GFP_KERNEL); + return -EINVAL; + } + + cm_id->add_ref(cm_id); + ep->com.cm_id = cm_id; + ep->com.qp = qp; + + ep->com.rpl_done = 0; + ep->com.rpl_err = 0; + ep->ird = conn_param->ird; + ep->ord = conn_param->ord; + PDBG("%s %d ird %d ord %d\n", __FUNCTION__, __LINE__, ep->ird, ep->ord); + get_ep(&ep->com); + err = send_mpa_reply(ep, conn_param->private_data, + conn_param->private_data_len); + if (err) { + ep->com.cm_id = NULL; + ep->com.qp = NULL; + cm_id->rem_ref(cm_id); + abort_connection(ep, NULL, GFP_KERNEL); + put_ep(&ep->com); + return err; + } + + /* bind QP to EP and move to RTS */ + attrs.mpa_attr = ep->mpa_attr; + attrs.max_ird = ep->ord; + attrs.max_ord = ep->ord; + attrs.llp_stream_handle = ep; + attrs.next_state = IWCH_QP_STATE_RTS; + + /* bind QP and TID with INIT_WR */ + mask = IWCH_QP_ATTR_NEXT_STATE | + IWCH_QP_ATTR_LLP_STREAM_HANDLE | + IWCH_QP_ATTR_MPA_ATTR | + IWCH_QP_ATTR_MAX_IRD | + IWCH_QP_ATTR_MAX_ORD; + + err = iwch_modify_qp(ep->com.qp->rhp, + ep->com.qp, mask, &attrs, 1); + + if (err) { + ep->com.cm_id = NULL; + ep->com.qp = NULL; + cm_id->rem_ref(cm_id); + abort_connection(ep, NULL, GFP_KERNEL); + } else { + state_set(&ep->com, FPDU_MODE); + established_upcall(ep); + } + put_ep(&ep->com); + return err; +} + +int iwch_connect(struct iw_cm_id *cm_id, struct iw_cm_conn_param *conn_param) +{ + int err = 0; + struct iwch_dev *h = to_iwch_dev(cm_id->device); + struct iwch_ep *ep; + struct rtable *rt; + + ep = alloc_ep(sizeof(*ep), GFP_KERNEL); + if (!ep) { + printk(KERN_ERR MOD "%s - cannot alloc ep.\n", __FUNCTION__); + err = -ENOMEM; + goto out; + } + init_timer(&ep->timer); + ep->plen = conn_param->private_data_len; + if (ep->plen) + memcpy(ep->mpa_pkt + sizeof(struct mpa_message), + conn_param->private_data, ep->plen); + ep->ird = conn_param->ird; + ep->ord = conn_param->ord; + ep->com.tdev = h->rdev.t3cdev_p; + + cm_id->add_ref(cm_id); + ep->com.cm_id = cm_id; + ep->com.qp = get_qhp(h, conn_param->qpn); + BUG_ON(!ep->com.qp); + PDBG("%s qpn 0x%x qp %p cm_id %p\n", __FUNCTION__, conn_param->qpn, + ep->com.qp, cm_id); + + /* + * Allocate an active TID to initiate a TCP connection. + */ + ep->atid = cxgb3_alloc_atid(h->rdev.t3cdev_p, &t3c_client, ep); + if (ep->atid == -1) { + printk(KERN_ERR MOD "%s - cannot alloc atid.\n", __FUNCTION__); + err = -ENOMEM; + goto fail2; + } + + /* find a route */ + rt = find_route(h->rdev.t3cdev_p, + cm_id->local_addr.sin_addr.s_addr, + cm_id->remote_addr.sin_addr.s_addr, + cm_id->local_addr.sin_port, + cm_id->remote_addr.sin_port, IPTOS_LOWDELAY); + if (!rt) { + printk(KERN_ERR MOD "%s - cannot find route.\n", __FUNCTION__); + err = -EHOSTUNREACH; + goto fail3; + } + ep->dst = &rt->u.dst; + + /* get a l2t entry */ + ep->l2t = t3_l2t_get(ep->com.tdev, ep->dst->neighbour, + ep->dst->neighbour->dev); + if (!ep->l2t) { + printk(KERN_ERR MOD "%s - cannot alloc l2e.\n", __FUNCTION__); + err = -ENOMEM; + goto fail4; + } + + state_set(&ep->com, CONNECTING); + ep->tos = IPTOS_LOWDELAY; + ep->com.local_addr = cm_id->local_addr; + ep->com.remote_addr = cm_id->remote_addr; + + /* send connect request to rnic */ + err = send_connect(ep); + if (!err) + goto out; + + l2t_release(L2DATA(h->rdev.t3cdev_p), ep->l2t); +fail4: + dst_release(ep->dst); +fail3: + cxgb3_free_atid(ep->com.tdev, ep->atid); +fail2: + put_ep(&ep->com); +out: + return err; +} + +int iwch_create_listen(struct iw_cm_id *cm_id, int backlog) +{ + int err = 0; + struct iwch_dev *h = to_iwch_dev(cm_id->device); + struct iwch_listen_ep *ep; + + + might_sleep(); + + ep = alloc_ep(sizeof(*ep), GFP_KERNEL); + if (!ep) { + printk(KERN_ERR MOD "%s - cannot alloc ep.\n", __FUNCTION__); + err = -ENOMEM; + goto fail1; + } + PDBG("%s ep %p\n", __FUNCTION__, ep); + ep->com.tdev = h->rdev.t3cdev_p; + cm_id->add_ref(cm_id); + ep->com.cm_id = cm_id; + ep->backlog = backlog; + ep->com.local_addr = cm_id->local_addr; + + /* + * Allocate a server TID. + */ + ep->stid = cxgb3_alloc_stid(h->rdev.t3cdev_p, &t3c_client, ep); + if (ep->stid == -1) { + printk(KERN_ERR MOD "%s - cannot alloc atid.\n", __FUNCTION__); + err = -ENOMEM; + goto fail2; + } + + state_set(&ep->com, LISTEN); + err = listen_start(ep); + if (err) + goto fail3; + + /* wait for pass_open_rpl */ + wait_event(ep->com.waitq, ep->com.rpl_done); + err = ep->com.rpl_err; + if (!err) { + cm_id->provider_data = ep; + goto out; + } +fail3: + cxgb3_free_stid(ep->com.tdev, ep->stid); +fail2: + put_ep(&ep->com); +fail1: +out: + return err; +} + +int iwch_destroy_listen(struct iw_cm_id *cm_id) +{ + int err; + struct iwch_listen_ep *ep = to_listen_ep(cm_id); + + PDBG("%s ep %p\n", __FUNCTION__, ep); + + might_sleep(); + state_set(&ep->com, DEAD); + ep->com.rpl_done = 0; + ep->com.rpl_err = 0; + err = listen_stop(ep); + wait_event(ep->com.waitq, ep->com.rpl_done); + cxgb3_free_stid(ep->com.tdev, ep->stid); + err = ep->com.rpl_err; + cm_id->rem_ref(cm_id); + put_ep(&ep->com); + return err; +} + +int iwch_ep_disconnect(struct iwch_ep *ep, int abrupt, gfp_t gfp) +{ + int ret=0; + unsigned long flags; + int close = 0; + + spin_lock_irqsave(&ep->com.lock, flags); + + PDBG("%s ep %p state %s, abrupt %d\n", __FUNCTION__, ep, + states[ep->com.state], abrupt); + + if (ep->com.state == DEAD) { + PDBG("%s already dead ep %p\n", __FUNCTION__, ep); + goto out; + } + + if (abrupt) { + if (ep->com.state != ABORTING) { + ep->com.state = ABORTING; + close = 1; + } + goto out; + } + + switch (ep->com.state) { + case MPA_REQ_WAIT: + case MPA_REQ_SENT: + case MPA_REQ_RCVD: + case MPA_REP_SENT: + case FPDU_MODE: + ep->com.state = CLOSING; + close = 1; + break; + case CLOSING: + start_ep_timer(ep); + ep->com.state = MORIBUND; + close = 1; + break; + case MORIBUND: + break; + default: + BUG(); + break; + } +out: + spin_unlock_irqrestore(&ep->com.lock, flags); + if (close) { + if (abrupt) + ret = send_abort(ep, NULL, gfp); + else + ret = send_halfclose(ep, gfp); + } + return ret; +} + +int iwch_ep_redirect(void *ctx, struct dst_entry *old, struct dst_entry *new, + struct l2t_entry *l2t) +{ + struct iwch_ep *ep = ctx; + + if (ep->dst != old) + return 0; + + PDBG("%s ep %p redirect to dst %p l2t %p\n", __FUNCTION__, ep, new, + l2t); + dst_hold(new); + l2t_release(L2DATA(ep->com.tdev), ep->l2t); + ep->l2t = l2t; + dst_release(old); + ep->dst = new; + return 1; +} + +/* + * All the CM events are handled on a work queue to have a safe context. + */ +static int sched(struct t3cdev *tdev, struct sk_buff *skb, void *ctx) +{ + struct iwch_ep_common *epc = ctx; + + get_ep(epc); + + /* + * Save ctx and tdev in the skb->cb area. + */ + *((void **) skb->cb) = ctx; + *((struct t3cdev **) (skb->cb + sizeof(void *))) = tdev; + + /* + * Queue the skb and schedule the worker thread. + */ + skb_queue_tail(&rxq, skb); + queue_work(workq, &skb_work); + return 0; +} + +int __init iwch_cm_init(void) +{ + skb_queue_head_init(&rxq); + + workq = create_singlethread_workqueue("iw_cxgb3"); + if (!workq) + return -ENOMEM; + + /* + * All upcalls from the T3 Core go to sched() to + * schedule the processing on a work queue. + */ + t3c_handlers[CPL_ACT_ESTABLISH] = sched; + t3c_handlers[CPL_ACT_OPEN_RPL] = sched; + t3c_handlers[CPL_RX_DATA] = sched; + t3c_handlers[CPL_TX_DMA_ACK] = sched; + t3c_handlers[CPL_ABORT_RPL_RSS] = sched; + t3c_handlers[CPL_ABORT_RPL] = sched; + t3c_handlers[CPL_PASS_OPEN_RPL] = sched; + t3c_handlers[CPL_CLOSE_LISTSRV_RPL] = sched; + t3c_handlers[CPL_PASS_ACCEPT_REQ] = sched; + t3c_handlers[CPL_PASS_ESTABLISH] = sched; + t3c_handlers[CPL_PEER_CLOSE] = sched; + t3c_handlers[CPL_CLOSE_CON_RPL] = sched; + t3c_handlers[CPL_ABORT_REQ_RSS] = sched; + t3c_handlers[CPL_RDMA_TERMINATE] = sched; + t3c_handlers[CPL_RDMA_EC_STATUS] = sched; + + /* + * These are the real handlers that are called from a + * work queue. + */ + work_handlers[CPL_ACT_ESTABLISH] = act_establish; + work_handlers[CPL_ACT_OPEN_RPL] = act_open_rpl; + work_handlers[CPL_RX_DATA] = rx_data; + work_handlers[CPL_TX_DMA_ACK] = tx_ack; + work_handlers[CPL_ABORT_RPL_RSS] = abort_rpl; + work_handlers[CPL_ABORT_RPL] = abort_rpl; + work_handlers[CPL_PASS_OPEN_RPL] = pass_open_rpl; + work_handlers[CPL_CLOSE_LISTSRV_RPL] = close_listsrv_rpl; + work_handlers[CPL_PASS_ACCEPT_REQ] = pass_accept_req; + work_handlers[CPL_PASS_ESTABLISH] = pass_establish; + work_handlers[CPL_PEER_CLOSE] = peer_close; + work_handlers[CPL_ABORT_REQ_RSS] = peer_abort; + work_handlers[CPL_CLOSE_CON_RPL] = close_con_rpl; + work_handlers[CPL_RDMA_TERMINATE] = terminate; + work_handlers[CPL_RDMA_EC_STATUS] = ec_status; + return 0; +} + +void __exit iwch_cm_term(void) +{ + flush_workqueue(workq); + destroy_workqueue(workq); +} diff --git a/drivers/infiniband/hw/cxgb3/iwch_cm.h b/drivers/infiniband/hw/cxgb3/iwch_cm.h new file mode 100644 index 0000000..7c810d9 --- /dev/null +++ b/drivers/infiniband/hw/cxgb3/iwch_cm.h @@ -0,0 +1,223 @@ +/* + * Copyright (c) 2006 Chelsio, Inc. All rights reserved. + * Copyright (c) 2006 Open Grid Computing, Inc. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +#ifndef _IWCH_CM_H_ +#define _IWCH_CM_H_ + +#include +#include +#include +#include + +#include +#include + +#include "cxgb3_offload.h" +#include "iwch_provider.h" + +#define MPA_KEY_REQ "MPA ID Req Frame" +#define MPA_KEY_REP "MPA ID Rep Frame" + +#define MPA_MAX_PRIVATE_DATA 256 +#define MPA_REV 0 /* XXX - amso1100 uses rev 0 ! */ +#define MPA_REJECT 0x20 +#define MPA_CRC 0x40 +#define MPA_MARKERS 0x80 +#define MPA_FLAGS_MASK 0xE0 + +#define put_ep(ep) { \ + PDBG("put_ep (via %s:%u) ep %p refcnt %d\n", __FUNCTION__, __LINE__, \ + ep, atomic_read(&((ep)->kref.refcount))); \ + kref_put(&((ep)->kref), __free_ep); \ +} + +#define get_ep(ep) { \ + PDBG("get_ep (via %s:%u) ep %p, refcnt %d\n", __FUNCTION__, __LINE__, \ + ep, atomic_read(&((ep)->kref.refcount))); \ + kref_get(&((ep)->kref)); \ +} + +struct mpa_message { + u8 key[16]; + u8 flags; + u8 revision; + __be16 private_data_size; + u8 private_data[0]; +}; + +struct terminate_message { + u8 layer_etype; + u8 ecode; + __be16 hdrct_rsvd; + u8 len_hdrs[0]; +}; + +#define TERM_MAX_LENGTH (sizeof(struct terminate_message) + 2 + 18 + 28) + +enum iwch_layers_types { + LAYER_RDMAP = 0x00, + LAYER_DDP = 0x10, + LAYER_MPA = 0x20, + RDMAP_LOCAL_CATA = 0x00, + RDMAP_REMOTE_PROT = 0x01, + RDMAP_REMOTE_OP = 0x02, + DDP_LOCAL_CATA = 0x00, + DDP_TAGGED_ERR = 0x01, + DDP_UNTAGGED_ERR = 0x02, + DDP_LLP = 0x03 +}; + +enum iwch_rdma_ecodes { + RDMAP_INV_STAG = 0x00, + RDMAP_BASE_BOUNDS = 0x01, + RDMAP_ACC_VIOL = 0x02, + RDMAP_STAG_NOT_ASSOC = 0x03, + RDMAP_TO_WRAP = 0x04, + RDMAP_INV_VERS = 0x05, + RDMAP_INV_OPCODE = 0x06, + RDMAP_STREAM_CATA = 0x07, + RDMAP_GLOBAL_CATA = 0x08, + RDMAP_CANT_INV_STAG = 0x09, + RDMAP_UNSPECIFIED = 0xff +}; + +enum iwch_ddp_ecodes { + DDPT_INV_STAG = 0x00, + DDPT_BASE_BOUNDS = 0x01, + DDPT_STAG_NOT_ASSOC = 0x02, + DDPT_TO_WRAP = 0x03, + DDPT_INV_VERS = 0x04, + DDPU_INV_QN = 0x01, + DDPU_INV_MSN_NOBUF = 0x02, + DDPU_INV_MSN_RANGE = 0x03, + DDPU_INV_MO = 0x04, + DDPU_MSG_TOOBIG = 0x05, + DDPU_INV_VERS = 0x06 +}; + +enum iwch_mpa_ecodes { + MPA_CRC_ERR = 0x02, + MPA_MARKER_ERR = 0x03 +}; + +enum iwch_ep_state { + IDLE = 0, + LISTEN, + CONNECTING, + MPA_REQ_WAIT, + MPA_REQ_SENT, + MPA_REQ_RCVD, + MPA_REP_SENT, + FPDU_MODE, + ABORTING, + CLOSING, + MORIBUND, + DEAD, +}; + +struct iwch_ep_common { + struct iw_cm_id *cm_id; + struct iwch_qp *qp; + struct t3cdev *tdev; + enum iwch_ep_state state; + struct kref kref; + spinlock_t lock; + struct sockaddr_in local_addr; + struct sockaddr_in remote_addr; + wait_queue_head_t waitq; + int rpl_done; + int rpl_err; +}; + +struct iwch_listen_ep { + struct iwch_ep_common com; + unsigned int stid; + int backlog; +}; + +struct iwch_ep { + struct iwch_ep_common com; + struct iwch_ep *parent_ep; + struct timer_list timer; + unsigned int atid; + u32 hwtid; + u32 snd_seq; + struct l2t_entry *l2t; + struct dst_entry *dst; + struct sk_buff *mpa_skb; + struct iwch_mpa_attributes mpa_attr; + unsigned int mpa_pkt_len; + u8 mpa_pkt[sizeof(struct mpa_message) + MPA_MAX_PRIVATE_DATA]; + u8 tos; + u16 emss; + u16 plen; + u32 ird; + u32 ord; +}; + +static inline struct iwch_ep *to_ep(struct iw_cm_id *cm_id) +{ + return cm_id->provider_data; +} + +static inline struct iwch_listen_ep *to_listen_ep(struct iw_cm_id *cm_id) +{ + return cm_id->provider_data; +} + +static inline int compute_wscale(int win) +{ + int wscale = 0; + + while (wscale < 14 && (65535<cq); + + if (!rd_cqe) + return 0; + + qhp = get_qhp(rhp, CQE_QPID(*rd_cqe)); + if (!qhp) + wq = NULL; + else { + spin_lock(&qhp->lock); + wq = &(qhp->wq); + } + ret = cxio_poll_cq(wq, &(chp->cq), &cqe, &cqe_flushed, &cookie, + &credit); + if (t3a_device(chp->rhp) && credit) { + PDBG("%s updating %d cq credits on id %d\n", __FUNCTION__, + credit, chp->cq.cqid); + cxio_hal_cq_op(&rhp->rdev, &chp->cq, CQ_CREDIT_UPDATE, credit); + } + + if (ret) { + ret = -EAGAIN; + goto out; + } + ret = 1; + + wc->wr_id = cookie; + wc->qp = &qhp->ibqp; + wc->vendor_err = CQE_STATUS(cqe); + + PDBG("%s qpid 0x%x type %d opcode %d status 0x%x wrid hi 0x%x " + "lo 0x%x cookie 0x%llx\n", __FUNCTION__, + CQE_QPID(cqe), CQE_TYPE(cqe), + CQE_OPCODE(cqe), CQE_STATUS(cqe), CQE_WRID_HI(cqe), + CQE_WRID_LOW(cqe), (unsigned long long) cookie); + + if (CQE_TYPE(cqe) == 0) { + if (!CQE_STATUS(cqe)) + wc->byte_len = CQE_LEN(cqe); + else + wc->byte_len = 0; + wc->opcode = IB_WC_RECV; + } else { + switch (CQE_OPCODE(cqe)) { + case T3_RDMA_WRITE: + wc->opcode = IB_WC_RDMA_WRITE; + break; + case T3_READ_REQ: + wc->opcode = IB_WC_RDMA_READ; + wc->byte_len = CQE_LEN(cqe); + break; + case T3_SEND: + case T3_SEND_WITH_SE: + wc->opcode = IB_WC_SEND; + break; + case T3_BIND_MW: + wc->opcode = IB_WC_BIND_MW; + break; + + /* these aren't supported yet */ + case T3_SEND_WITH_INV: + case T3_SEND_WITH_SE_INV: + case T3_LOCAL_INV: + case T3_FAST_REGISTER: + default: + printk(KERN_ERR MOD "Unexpected opcode %d " + "in the CQE received for QPID=0x%0x\n", + CQE_OPCODE(cqe), CQE_QPID(cqe)); + ret = -EINVAL; + goto out; + } + } + + if (cqe_flushed) + wc->status = IB_WC_WR_FLUSH_ERR; + else { + + switch (CQE_STATUS(cqe)) { + case TPT_ERR_SUCCESS: + wc->status = IB_WC_SUCCESS; + break; + case TPT_ERR_STAG: + wc->status = IB_WC_LOC_ACCESS_ERR; + break; + case TPT_ERR_PDID: + wc->status = IB_WC_LOC_PROT_ERR; + break; + case TPT_ERR_QPID: + case TPT_ERR_ACCESS: + wc->status = IB_WC_LOC_ACCESS_ERR; + break; + case TPT_ERR_WRAP: + wc->status = IB_WC_GENERAL_ERR; + break; + case TPT_ERR_BOUND: + wc->status = IB_WC_LOC_LEN_ERR; + break; + case TPT_ERR_INVALIDATE_SHARED_MR: + case TPT_ERR_INVALIDATE_MR_WITH_MW_BOUND: + wc->status = IB_WC_MW_BIND_ERR; + break; + case TPT_ERR_CRC: + case TPT_ERR_MARKER: + case TPT_ERR_PDU_LEN_ERR: + case TPT_ERR_OUT_OF_RQE: + case TPT_ERR_DDP_VERSION: + case TPT_ERR_RDMA_VERSION: + case TPT_ERR_DDP_QUEUE_NUM: + case TPT_ERR_MSN: + case TPT_ERR_TBIT: + case TPT_ERR_MO: + case TPT_ERR_MSN_RANGE: + case TPT_ERR_IRD_OVERFLOW: + case TPT_ERR_OPCODE: + wc->status = IB_WC_FATAL_ERR; + break; + case TPT_ERR_SWFLUSH: + wc->status = IB_WC_WR_FLUSH_ERR; + break; + default: + printk(KERN_ERR MOD "Unexpected cqe_status 0x%x for " + "QPID=0x%0x\n", CQE_STATUS(cqe), CQE_QPID(cqe)); + ret = -EINVAL; + } + } +out: + if (wq) + spin_unlock(&qhp->lock); + return ret; +} + +int iwch_poll_cq(struct ib_cq *ibcq, int num_entries, struct ib_wc *wc) +{ + struct iwch_dev *rhp; + struct iwch_cq *chp; + unsigned long flags; + int npolled; + int err = 0; + + chp = to_iwch_cq(ibcq); + rhp = chp->rhp; + + spin_lock_irqsave(&chp->lock, flags); + for (npolled = 0; npolled < num_entries; ++npolled) { +#ifdef DEBUG + int i=0; +#endif + + /* + * Because T3 can post CQEs that are _not_ associated + * with a WR, we might have to poll again after removing + * one of these. + */ + do { + err = iwch_poll_cq_one(rhp, chp, wc + npolled); +#ifdef DEBUG + BUG_ON(++i > 1000); +#endif + } while (err == -EAGAIN); + if (err <= 0) + break; + } + spin_unlock_irqrestore(&chp->lock, flags); + + if (err < 0) + return err; + else { + return npolled; + } +} diff --git a/drivers/infiniband/hw/cxgb3/iwch_ev.c b/drivers/infiniband/hw/cxgb3/iwch_ev.c new file mode 100644 index 0000000..a6efa8f --- /dev/null +++ b/drivers/infiniband/hw/cxgb3/iwch_ev.c @@ -0,0 +1,231 @@ +/* + * Copyright (c) 2006 Chelsio, Inc. All rights reserved. + * Copyright (c) 2006 Open Grid Computing, Inc. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +#include +#include +#include +#include "iwch_provider.h" +#include "iwch.h" +#include "iwch_cm.h" +#include "cxio_hal.h" +#include "cxio_wr.h" + +static void post_qp_event(struct iwch_dev *rnicp, struct iwch_cq *chp, + struct respQ_msg_t *rsp_msg, + enum ib_event_type ib_event, + int send_term) +{ + struct ib_event event; + struct iwch_qp_attributes attrs; + struct iwch_qp *qhp; + + printk(KERN_ERR "%s - AE qpid 0x%x opcode %d status 0x%x " + "type %d wrid.hi 0x%x wrid.lo 0x%x \n", __FUNCTION__, + CQE_QPID(rsp_msg->cqe), CQE_OPCODE(rsp_msg->cqe), + CQE_STATUS(rsp_msg->cqe), CQE_TYPE(rsp_msg->cqe), + CQE_WRID_HI(rsp_msg->cqe), CQE_WRID_LOW(rsp_msg->cqe)); + + spin_lock(&rnicp->lock); + qhp = get_qhp(rnicp, CQE_QPID(rsp_msg->cqe)); + + if (!qhp) { + printk(KERN_ERR "%s unaffiliated error 0x%x qpid 0x%x\n", + __FUNCTION__, CQE_STATUS(rsp_msg->cqe), + CQE_QPID(rsp_msg->cqe)); + spin_unlock(&rnicp->lock); + return; + } + + if ((qhp->attr.state == IWCH_QP_STATE_ERROR) || + (qhp->attr.state == IWCH_QP_STATE_TERMINATE)) { + PDBG("%s AE received after RTS - " + "qp state %d qpid 0x%x status 0x%x\n", __FUNCTION__, + qhp->attr.state, qhp->wq.qpid, CQE_STATUS(rsp_msg->cqe)); + spin_unlock(&rnicp->lock); + return; + } + + atomic_inc(&qhp->refcnt); + spin_unlock(&rnicp->lock); + + event.event = ib_event; + event.device = chp->ibcq.device; + if (ib_event == IB_EVENT_CQ_ERR) + event.element.cq = &chp->ibcq; + else + event.element.qp = &qhp->ibqp; + + if (qhp->ibqp.event_handler) + (*qhp->ibqp.event_handler)(&event, qhp->ibqp.qp_context); + + if (qhp->attr.state == IWCH_QP_STATE_RTS) { + attrs.next_state = IWCH_QP_STATE_TERMINATE; + iwch_modify_qp(qhp->rhp, qhp, IWCH_QP_ATTR_NEXT_STATE, + &attrs, 1); + if (send_term) + iwch_post_terminate(qhp, rsp_msg); + } + + if (atomic_dec_and_test(&qhp->refcnt)) + wake_up(&qhp->wait); +} + +void iwch_ev_dispatch(struct cxio_rdev *rdev_p, struct sk_buff *skb) +{ + struct iwch_dev *rnicp; + struct respQ_msg_t *rsp_msg = (struct respQ_msg_t *) skb->data; + struct iwch_cq *chp; + struct iwch_qp *qhp; + u32 cqid = RSPQ_CQID(rsp_msg); + + rnicp = (struct iwch_dev *) rdev_p->ulp; + spin_lock(&rnicp->lock); + chp = get_chp(rnicp, cqid); + qhp = get_qhp(rnicp, CQE_QPID(rsp_msg->cqe)); + if (!chp || !qhp) { + printk(KERN_ERR MOD "BAD AE cqid 0x%x qpid 0x%x opcode %d " + "status 0x%x type %d wrid.hi 0x%x wrid.lo 0x%x \n", + cqid, CQE_QPID(rsp_msg->cqe), + CQE_OPCODE(rsp_msg->cqe), CQE_STATUS(rsp_msg->cqe), + CQE_TYPE(rsp_msg->cqe), CQE_WRID_HI(rsp_msg->cqe), + CQE_WRID_LOW(rsp_msg->cqe)); + spin_unlock(&rnicp->lock); + goto out; + } + iwch_qp_add_ref(&qhp->ibqp); + atomic_inc(&chp->refcnt); + spin_unlock(&rnicp->lock); + + /* + * 1) completion of our sending a TERMINATE. + * 2) incoming TERMINATE message. + */ + if ((CQE_OPCODE(rsp_msg->cqe) == T3_TERMINATE) && + (CQE_STATUS(rsp_msg->cqe) == 0)) { + if (SQ_TYPE(rsp_msg->cqe)) { + PDBG("%s QPID 0x%x ep %p disconnecting\n", + __FUNCTION__, qhp->wq.qpid, qhp->ep); + iwch_ep_disconnect(qhp->ep, 0, GFP_ATOMIC); + } else { + PDBG("%s post REQ_ERR AE QPID 0x%x\n", __FUNCTION__, + qhp->wq.qpid); + post_qp_event(rnicp, chp, rsp_msg, + IB_EVENT_QP_REQ_ERR, 0); + iwch_ep_disconnect(qhp->ep, 0, GFP_ATOMIC); + } + goto done; + } + + /* Bad incoming Read request */ + if (SQ_TYPE(rsp_msg->cqe) && + (CQE_OPCODE(rsp_msg->cqe) == T3_READ_RESP)) { + post_qp_event(rnicp, chp, rsp_msg, IB_EVENT_QP_REQ_ERR, 1); + goto done; + } + + /* Bad incoming write */ + if (RQ_TYPE(rsp_msg->cqe) && + (CQE_OPCODE(rsp_msg->cqe) == T3_RDMA_WRITE)) { + post_qp_event(rnicp, chp, rsp_msg, IB_EVENT_QP_REQ_ERR, 1); + goto done; + } + + switch (CQE_STATUS(rsp_msg->cqe)) { + + /* Completion Events */ + case TPT_ERR_SUCCESS: + + /* + * Confirm the destination entry if this is a RECV completion. + */ + if (qhp->ep && SQ_TYPE(rsp_msg->cqe)) + dst_confirm(qhp->ep->dst); + (*chp->ibcq.comp_handler)(&chp->ibcq, chp->ibcq.cq_context); + break; + + case TPT_ERR_STAG: + case TPT_ERR_PDID: + case TPT_ERR_QPID: + case TPT_ERR_ACCESS: + case TPT_ERR_WRAP: + case TPT_ERR_BOUND: + case TPT_ERR_INVALIDATE_SHARED_MR: + case TPT_ERR_INVALIDATE_MR_WITH_MW_BOUND: + printk(KERN_ERR "%s - CQE Err qpid 0x%x opcode %d status 0x%x " + "type %d wrid.hi 0x%x wrid.lo 0x%x \n", __FUNCTION__, + CQE_QPID(rsp_msg->cqe), CQE_OPCODE(rsp_msg->cqe), + CQE_STATUS(rsp_msg->cqe), CQE_TYPE(rsp_msg->cqe), + CQE_WRID_HI(rsp_msg->cqe), CQE_WRID_LOW(rsp_msg->cqe)); + (*chp->ibcq.comp_handler)(&chp->ibcq, chp->ibcq.cq_context); + post_qp_event(rnicp, chp, rsp_msg, IB_EVENT_QP_ACCESS_ERR, 1); + break; + + /* Device Fatal Errors */ + case TPT_ERR_ECC: + case TPT_ERR_ECC_PSTAG: + case TPT_ERR_INTERNAL_ERR: + post_qp_event(rnicp, chp, rsp_msg, IB_EVENT_DEVICE_FATAL, 1); + break; + + /* QP Fatal Errors */ + case TPT_ERR_OUT_OF_RQE: + case TPT_ERR_PBL_ADDR_BOUND: + case TPT_ERR_CRC: + case TPT_ERR_MARKER: + case TPT_ERR_PDU_LEN_ERR: + case TPT_ERR_DDP_VERSION: + case TPT_ERR_RDMA_VERSION: + case TPT_ERR_OPCODE: + case TPT_ERR_DDP_QUEUE_NUM: + case TPT_ERR_MSN: + case TPT_ERR_TBIT: + case TPT_ERR_MO: + case TPT_ERR_MSN_GAP: + case TPT_ERR_MSN_RANGE: + case TPT_ERR_RQE_ADDR_BOUND: + case TPT_ERR_IRD_OVERFLOW: + post_qp_event(rnicp, chp, rsp_msg, IB_EVENT_QP_FATAL, 1); + break; + + default: + printk(KERN_ERR MOD "Unknown T3 status 0x%x QPID 0x%x\n", + CQE_STATUS(rsp_msg->cqe), qhp->wq.qpid); + post_qp_event(rnicp, chp, rsp_msg, IB_EVENT_QP_FATAL, 1); + break; + } +done: + if (atomic_dec_and_test(&chp->refcnt)) + wake_up(&chp->wait); + iwch_qp_rem_ref(&qhp->ibqp); +out: + dev_kfree_skb_irq(skb); +} diff --git a/drivers/infiniband/hw/cxgb3/iwch_mem.c b/drivers/infiniband/hw/cxgb3/iwch_mem.c new file mode 100644 index 0000000..2b6cd53 --- /dev/null +++ b/drivers/infiniband/hw/cxgb3/iwch_mem.c @@ -0,0 +1,172 @@ +/* + * Copyright (c) 2006 Chelsio, Inc. All rights reserved. + * Copyright (c) 2006 Open Grid Computing, Inc. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +#include + +#include +#include + +#include "cxio_hal.h" +#include "iwch.h" +#include "iwch_provider.h" + +int iwch_register_mem(struct iwch_dev *rhp, struct iwch_pd *php, + struct iwch_mr *mhp, + int shift, + __be64 *page_list) +{ + u32 stag; + u32 mmid; + + + if (cxio_register_phys_mem(&rhp->rdev, + &stag, mhp->attr.pdid, + mhp->attr.perms, + mhp->attr.zbva, + mhp->attr.va_fbo, + mhp->attr.len, + shift-12, + page_list, + &mhp->attr.pbl_size, &mhp->attr.pbl_addr)) + return -ENOMEM; + mhp->attr.state = 1; + mhp->attr.stag = stag; + mmid = stag >> 8; + mhp->ibmr.rkey = mhp->ibmr.lkey = stag; + insert_handle(rhp, &rhp->mmidr, mhp, mmid); + PDBG("%s mmid 0x%x mhp %p\n", __FUNCTION__, mmid, mhp); + return 0; +} + +int iwch_reregister_mem(struct iwch_dev *rhp, struct iwch_pd *php, + struct iwch_mr *mhp, + int shift, + __be64 *page_list, + int npages) +{ + u32 stag; + u32 mmid; + + + /* We could support this... */ + if (npages > mhp->attr.pbl_size) + return -ENOMEM; + + stag = mhp->attr.stag; + if (cxio_reregister_phys_mem(&rhp->rdev, + &stag, mhp->attr.pdid, + mhp->attr.perms, + mhp->attr.zbva, + mhp->attr.va_fbo, + mhp->attr.len, + shift-12, + page_list, + &mhp->attr.pbl_size, &mhp->attr.pbl_addr)) + return -ENOMEM; + mhp->attr.state = 1; + mhp->attr.stag = stag; + mmid = stag >> 8; + mhp->ibmr.rkey = mhp->ibmr.lkey = stag; + insert_handle(rhp, &rhp->mmidr, mhp, mmid); + PDBG("%s mmid 0x%x mhp %p\n", __FUNCTION__, mmid, mhp); + return 0; +} + +int build_phys_page_list(struct ib_phys_buf *buffer_list, + int num_phys_buf, + u64 *iova_start, + u64 *total_size, + int *npages, + int *shift, + __be64 **page_list) +{ + u64 mask; + int i, j, n; + + mask = 0; + *total_size = 0; + for (i = 0; i < num_phys_buf; ++i) { + if (i != 0 && buffer_list[i].addr & ~PAGE_MASK) + return -EINVAL; + if (i != 0 && i != num_phys_buf - 1 && + (buffer_list[i].size & ~PAGE_MASK)) + return -EINVAL; + *total_size += buffer_list[i].size; + if (i > 0) + mask |= buffer_list[i].addr; + } + + if (*total_size > 0xFFFFFFFFULL) + return -ENOMEM; + + /* Find largest page shift we can use to cover buffers */ + for (*shift = PAGE_SHIFT; *shift < 27; ++(*shift)) + if (num_phys_buf > 1) { + if ((1ULL << *shift) & mask) + break; + } else + if (1ULL << *shift >= + buffer_list[0].size + + (buffer_list[0].addr & ((1ULL << *shift) - 1))) + break; + + buffer_list[0].size += buffer_list[0].addr & ((1ULL << *shift) - 1); + buffer_list[0].addr &= ~0ull << *shift; + + *npages = 0; + for (i = 0; i < num_phys_buf; ++i) + *npages += (buffer_list[i].size + + (1ULL << *shift) - 1) >> *shift; + + if (!*npages) + return -EINVAL; + + *page_list = kmalloc(sizeof(u64) * *npages, GFP_KERNEL); + if (!*page_list) + return -ENOMEM; + + n = 0; + for (i = 0; i < num_phys_buf; ++i) + for (j = 0; + j < (buffer_list[i].size + (1ULL << *shift) - 1) >> *shift; + ++j) + (*page_list)[n++] = cpu_to_be64(buffer_list[i].addr + + ((u64) j << *shift)); + + PDBG("%s va 0x%llx mask 0x%llx shift %d len %lld pbl_size %d\n", + __FUNCTION__, (unsigned long long) *iova_start, + (unsigned long long) mask, *shift, (unsigned long long) *total_size, + *npages); + + return 0; + +} diff --git a/drivers/infiniband/hw/cxgb3/iwch_provider.c b/drivers/infiniband/hw/cxgb3/iwch_provider.c new file mode 100644 index 0000000..6861087 --- /dev/null +++ b/drivers/infiniband/hw/cxgb3/iwch_provider.c @@ -0,0 +1,1203 @@ +/* + * Copyright (c) 2006 Chelsio, Inc. All rights reserved. + * Copyright (c) 2006 Open Grid Computing, Inc. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include +#include +#include + +#include "cxio_hal.h" +#include "iwch.h" +#include "iwch_provider.h" +#include "iwch_cm.h" +#include "iwch_user.h" + +static int iwch_modify_port(struct ib_device *ibdev, + u8 port, int port_modify_mask, + struct ib_port_modify *props) +{ + return -ENOSYS; +} + +static struct ib_ah *iwch_ah_create(struct ib_pd *pd, + struct ib_ah_attr *ah_attr) +{ + return ERR_PTR(-ENOSYS); +} + +static int iwch_ah_destroy(struct ib_ah *ah) +{ + return -ENOSYS; +} + +static int iwch_multicast_attach(struct ib_qp *ibqp, union ib_gid *gid, u16 lid) +{ + return -ENOSYS; +} + +static int iwch_multicast_detach(struct ib_qp *ibqp, union ib_gid *gid, u16 lid) +{ + return -ENOSYS; +} + +static int iwch_process_mad(struct ib_device *ibdev, + int mad_flags, + u8 port_num, + struct ib_wc *in_wc, + struct ib_grh *in_grh, + struct ib_mad *in_mad, struct ib_mad *out_mad) +{ + return -ENOSYS; +} + +static int iwch_dealloc_ucontext(struct ib_ucontext *context) +{ + struct iwch_dev *rhp = to_iwch_dev(context->device); + struct iwch_ucontext *ucontext = to_iwch_ucontext(context); + struct iwch_mm_entry *mm, *tmp; + + PDBG("%s context %p\n", __FUNCTION__, context); + list_for_each_entry_safe(mm, tmp, &ucontext->mmaps, entry) + kfree(mm); + cxio_release_ucontext(&rhp->rdev, &ucontext->uctx); + kfree(ucontext); + return 0; +} + +static struct ib_ucontext *iwch_alloc_ucontext(struct ib_device *ibdev, + struct ib_udata *udata) +{ + struct iwch_ucontext *context; + struct iwch_dev *rhp = to_iwch_dev(ibdev); + + PDBG("%s ibdev %p\n", __FUNCTION__, ibdev); + context = kzalloc(sizeof(*context), GFP_KERNEL); + if (!context) + return ERR_PTR(-ENOMEM); + cxio_init_ucontext(&rhp->rdev, &context->uctx); + INIT_LIST_HEAD(&context->mmaps); + spin_lock_init(&context->mmap_lock); + return &context->ibucontext; +} + +static int iwch_destroy_cq(struct ib_cq *ib_cq) +{ + struct iwch_cq *chp; + + PDBG("%s ib_cq %p\n", __FUNCTION__, ib_cq); + chp = to_iwch_cq(ib_cq); + + remove_handle(chp->rhp, &chp->rhp->cqidr, chp->cq.cqid); + atomic_dec(&chp->refcnt); + wait_event(chp->wait, !atomic_read(&chp->refcnt)); + + cxio_destroy_cq(&chp->rhp->rdev, &chp->cq); + kfree(chp); + return 0; +} + +static struct ib_cq *iwch_create_cq(struct ib_device *ibdev, int entries, + struct ib_ucontext *ib_context, + struct ib_udata *udata) +{ + struct iwch_dev *rhp; + struct iwch_cq *chp; + struct iwch_create_cq_resp uresp; + struct iwch_create_cq_req ureq; + struct iwch_ucontext *ucontext = NULL; + + PDBG("%s ib_dev %p entries %d\n", __FUNCTION__, ibdev, entries); + rhp = to_iwch_dev(ibdev); + chp = kzalloc(sizeof(*chp), GFP_KERNEL); + if (!chp) + return ERR_PTR(-ENOMEM); + + if (ib_context) { + ucontext = to_iwch_ucontext(ib_context); + if (!t3a_device(rhp)) { + if (ib_copy_from_udata(&ureq, udata, sizeof (ureq))) { + kfree(chp); + return ERR_PTR(-EFAULT); + } + chp->user_rptr_addr = (u32 __user *)(unsigned long)ureq.user_rptr_addr; + } + } + + if (t3a_device(rhp)) { + + /* + * T3A: Add some fluff to handle extra CQEs inserted + * for various errors. + * Additional CQE possibilities: + * TERMINATE, + * incoming RDMA WRITE Failures + * incoming RDMA READ REQUEST FAILUREs + * NOTE: We cannot ensure the CQ won't overflow. + */ + entries += 16; + } + entries = roundup_pow_of_two(entries); + chp->cq.size_log2 = ilog2(entries); + + if (cxio_create_cq(&rhp->rdev, &chp->cq)) { + kfree(chp); + return ERR_PTR(-ENOMEM); + } + chp->rhp = rhp; + chp->ibcq.cqe = (1 << chp->cq.size_log2) - 1; + spin_lock_init(&chp->lock); + atomic_set(&chp->refcnt, 1); + init_waitqueue_head(&chp->wait); + insert_handle(rhp, &rhp->cqidr, chp, chp->cq.cqid); + + if (ucontext) { + struct iwch_mm_entry *mm; + + mm = kmalloc(sizeof *mm, GFP_KERNEL); + if (!mm) { + iwch_destroy_cq(&chp->ibcq); + return ERR_PTR(-ENOMEM); + } + uresp.cqid = chp->cq.cqid; + uresp.size_log2 = chp->cq.size_log2; + spin_lock(&ucontext->mmap_lock); + uresp.key = ucontext->key; + ucontext->key += PAGE_SIZE; + spin_unlock(&ucontext->mmap_lock); + if (ib_copy_to_udata(udata, &uresp, sizeof (uresp))) { + kfree(mm); + iwch_destroy_cq(&chp->ibcq); + return ERR_PTR(-EFAULT); + } + mm->key = uresp.key; + mm->addr = virt_to_phys(chp->cq.queue); + mm->len = PAGE_ALIGN((1UL << uresp.size_log2) * + sizeof (struct t3_cqe)); + insert_mmap(ucontext, mm); + } + PDBG("created cqid 0x%0x chp %p size 0x%0x, dma_addr 0x%0llx\n", + chp->cq.cqid, chp, (1 << chp->cq.size_log2), + (unsigned long long) chp->cq.dma_addr); + return &chp->ibcq; +} + +static int iwch_resize_cq(struct ib_cq *cq, int cqe, struct ib_udata *udata) +{ +#ifdef notyet + struct iwch_cq *chp = to_iwch_cq(cq); + struct t3_cq oldcq, newcq; + int ret; + + PDBG("%s ib_cq %p cqe %d\n", __FUNCTION__, cq, cqe); + + /* We don't downsize... */ + if (cqe <= cq->cqe) + return 0; + + /* create new t3_cq with new size */ + cqe = roundup_pow_of_two(cqe+1); + newcq.size_log2 = ilog2(cqe); + + /* Dont allow resize to less than the current wce count */ + if (cqe < Q_COUNT(chp->cq.rptr, chp->cq.wptr)) { + return -ENOMEM; + } + + /* Quiesce all QPs using this CQ */ + ret = iwch_quiesce_qps(chp); + if (ret) { + return ret; + } + + ret = cxio_create_cq(&chp->rhp->rdev, &newcq); + if (ret) { + return ret; + } + + /* copy CQEs */ + memcpy(newcq.queue, chp->cq.queue, (1 << chp->cq.size_log2) * + sizeof(struct t3_cqe)); + + /* old iwch_qp gets new t3_cq but keeps old cqid */ + oldcq = chp->cq; + chp->cq = newcq; + chp->cq.cqid = oldcq.cqid; + + /* resize new t3_cq to update the HW context */ + ret = cxio_resize_cq(&chp->rhp->rdev, &chp->cq); + if (ret) { + chp->cq = oldcq; + return ret; + } + chp->ibcq.cqe = (1<cq.size_log2) - 1; + + /* destroy old t3_cq */ + oldcq.cqid = newcq.cqid; + ret = cxio_destroy_cq(&chp->rhp->rdev, &oldcq); + if (ret) { + printk(KERN_ERR MOD "%s - cxio_destroy_cq failed %d\n", + __FUNCTION__, ret); + } + + /* add user hooks here */ + + /* resume qps */ + ret = iwch_resume_qps(chp); + return ret; +#else + return -ENOSYS; +#endif +} + +static int iwch_arm_cq(struct ib_cq *ibcq, enum ib_cq_notify notify) +{ + struct iwch_dev *rhp; + struct iwch_cq *chp; + enum t3_cq_opcode cq_op; + int err; + unsigned long flag; + u32 rptr; + + chp = to_iwch_cq(ibcq); + rhp = chp->rhp; + if (notify == IB_CQ_SOLICITED) + cq_op = CQ_ARM_SE; + else + cq_op = CQ_ARM_AN; + if (chp->user_rptr_addr) { + if (get_user(rptr, chp->user_rptr_addr)) + return -EFAULT; + spin_lock_irqsave(&chp->lock, flag); + chp->cq.rptr = rptr; + } else + spin_lock_irqsave(&chp->lock, flag); + PDBG("%s rptr 0x%x\n", __FUNCTION__, chp->cq.rptr); + err = cxio_hal_cq_op(&rhp->rdev, &chp->cq, cq_op, 0); + spin_unlock_irqrestore(&chp->lock, flag); + if (err) + printk(KERN_ERR MOD "Error %d rearming CQID 0x%x\n", err, + chp->cq.cqid); + return err; +} + +static int iwch_mmap(struct ib_ucontext *context, struct vm_area_struct *vma) +{ + int len = vma->vm_end - vma->vm_start; + u32 key = vma->vm_pgoff << PAGE_SHIFT; + struct cxio_rdev *rdev_p; + int ret = 0; + struct iwch_mm_entry *mm; + struct iwch_ucontext *ucontext; + + PDBG("%s pgoff 0x%lx key 0x%x len %d\n", __FUNCTION__, vma->vm_pgoff, + key, len); + + if (vma->vm_start & (PAGE_SIZE-1)) { + return -EINVAL; + } + + rdev_p = &(to_iwch_dev(context->device)->rdev); + ucontext = to_iwch_ucontext(context); + + mm = remove_mmap(ucontext, key, len); + if (!mm) + return -EINVAL; + kfree(mm); + + if ((mm->addr >= rdev_p->rnic_info.udbell_physbase) && + (mm->addr < (rdev_p->rnic_info.udbell_physbase + + rdev_p->rnic_info.udbell_len))) { + + /* + * Map T3 DB register. + */ + if (vma->vm_flags & VM_READ) { + return -EPERM; + } + + vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot); + vma->vm_flags |= VM_DONTCOPY | VM_DONTEXPAND; + vma->vm_flags &= ~VM_MAYREAD; + ret = io_remap_pfn_range(vma, vma->vm_start, + mm->addr >> PAGE_SHIFT, + len, vma->vm_page_prot); + } else { + + /* + * Map WQ or CQ contig dma memory... + */ + ret = remap_pfn_range(vma, vma->vm_start, + mm->addr >> PAGE_SHIFT, + len, vma->vm_page_prot); + } + + return ret; +} + +static int iwch_deallocate_pd(struct ib_pd *pd) +{ + struct iwch_dev *rhp; + struct iwch_pd *php; + + php = to_iwch_pd(pd); + rhp = php->rhp; + PDBG("%s ibpd %p pdid 0x%x\n", __FUNCTION__, pd, php->pdid); + cxio_hal_put_pdid(rhp->rdev.rscp, php->pdid); + kfree(php); + return 0; +} + +static struct ib_pd *iwch_allocate_pd(struct ib_device *ibdev, + struct ib_ucontext *context, + struct ib_udata *udata) +{ + struct iwch_pd *php; + u32 pdid; + struct iwch_dev *rhp; + + PDBG("%s ibdev %p\n", __FUNCTION__, ibdev); + rhp = (struct iwch_dev *) ibdev; + pdid = cxio_hal_get_pdid(rhp->rdev.rscp); + if (!pdid) + return ERR_PTR(-EINVAL); + php = kzalloc(sizeof(*php), GFP_KERNEL); + if (!php) { + cxio_hal_put_pdid(rhp->rdev.rscp, pdid); + return ERR_PTR(-ENOMEM); + } + php->pdid = pdid; + php->rhp = rhp; + if (context) { + if (ib_copy_to_udata(udata, &php->pdid, sizeof (__u32))) { + iwch_deallocate_pd(&php->ibpd); + return ERR_PTR(-EFAULT); + } + } + PDBG("%s pdid 0x%0x ptr 0x%p\n", __FUNCTION__, pdid, php); + return &php->ibpd; +} + +static int iwch_dereg_mr(struct ib_mr *ib_mr) +{ + struct iwch_dev *rhp; + struct iwch_mr *mhp; + u32 mmid; + + PDBG("%s ib_mr %p\n", __FUNCTION__, ib_mr); + /* There can be no memory windows */ + if (atomic_read(&ib_mr->usecnt)) + return -EINVAL; + + mhp = to_iwch_mr(ib_mr); + rhp = mhp->rhp; + mmid = mhp->attr.stag >> 8; + cxio_dereg_mem(&rhp->rdev, mhp->attr.stag, mhp->attr.pbl_size, + mhp->attr.pbl_addr); + remove_handle(rhp, &rhp->mmidr, mmid); + if (mhp->kva) + kfree((void *) (unsigned long) mhp->kva); + PDBG("%s mmid 0x%x ptr %p\n", __FUNCTION__, mmid, mhp); + kfree(mhp); + return 0; +} + +static struct ib_mr *iwch_register_phys_mem(struct ib_pd *pd, + struct ib_phys_buf *buffer_list, + int num_phys_buf, + int acc, + u64 *iova_start) +{ + __be64 *page_list; + int shift; + u64 total_size; + int npages; + struct iwch_dev *rhp; + struct iwch_pd *php; + struct iwch_mr *mhp; + int ret; + + PDBG("%s ib_pd %p\n", __FUNCTION__, pd); + php = to_iwch_pd(pd); + rhp = php->rhp; + + acc = iwch_convert_access(acc); + + + mhp = kzalloc(sizeof(*mhp), GFP_KERNEL); + if (!mhp) + return ERR_PTR(-ENOMEM); + + /* First check that we have enough alignment */ + if ((*iova_start & ~PAGE_MASK) != (buffer_list[0].addr & ~PAGE_MASK)) { + ret = -EINVAL; + goto err; + } + + if (num_phys_buf > 1 && + ((buffer_list[0].addr + buffer_list[0].size) & ~PAGE_MASK)) { + ret = -EINVAL; + goto err; + } + + ret = build_phys_page_list(buffer_list, num_phys_buf, iova_start, + &total_size, &npages, &shift, &page_list); + if (ret) + goto err; + + mhp->rhp = rhp; + mhp->attr.pdid = php->pdid; + mhp->attr.zbva = 0; + + /* NOTE: TPT perms are backwards from BIND WR perms! */ + mhp->attr.perms = (acc & 0x1) << 3; + mhp->attr.perms |= (acc & 0x2) << 1; + mhp->attr.perms |= (acc & 0x4) >> 1; + mhp->attr.perms |= (acc & 0x8) >> 3; + + mhp->attr.va_fbo = *iova_start; + mhp->attr.page_size = shift - 12; + + mhp->attr.len = (u32) total_size; + mhp->attr.pbl_size = npages; + ret = iwch_register_mem(rhp, php, mhp, shift, page_list); + kfree(page_list); + if (ret) { + goto err; + } + return &mhp->ibmr; +err: + kfree(mhp); + return ERR_PTR(ret); + +} + +static int iwch_reregister_phys_mem(struct ib_mr *mr, + int mr_rereg_mask, + struct ib_pd *pd, + struct ib_phys_buf *buffer_list, + int num_phys_buf, + int acc, u64 * iova_start) +{ + + struct iwch_mr mh, *mhp; + struct iwch_pd *php; + struct iwch_dev *rhp; + int new_acc; + __be64 *page_list = NULL; + int shift = 0; + u64 total_size; + int npages; + int ret; + + PDBG("%s ib_mr %p ib_pd %p\n", __FUNCTION__, mr, pd); + + /* There can be no memory windows */ + if (atomic_read(&mr->usecnt)) + return -EINVAL; + + mhp = to_iwch_mr(mr); + rhp = mhp->rhp; + php = to_iwch_pd(mr->pd); + + /* make sure we are on the same adapter */ + if (rhp != php->rhp) + return -EINVAL; + + new_acc = mhp->attr.perms; + + memcpy(&mh, mhp, sizeof *mhp); + + if (mr_rereg_mask & IB_MR_REREG_PD) + php = to_iwch_pd(pd); + if (mr_rereg_mask & IB_MR_REREG_ACCESS) + mh.attr.perms = iwch_convert_access(acc); + if (mr_rereg_mask & IB_MR_REREG_TRANS) + ret = build_phys_page_list(buffer_list, num_phys_buf, + iova_start, + &total_size, &npages, + &shift, &page_list); + + ret = iwch_reregister_mem(rhp, php, &mh, shift, page_list, npages); + kfree(page_list); + if (ret) { + return ret; + } + if (mr_rereg_mask & IB_MR_REREG_PD) + mhp->attr.pdid = php->pdid; + if (mr_rereg_mask & IB_MR_REREG_ACCESS) + mhp->attr.perms = acc; + if (mr_rereg_mask & IB_MR_REREG_TRANS) { + mhp->attr.zbva = 0; + mhp->attr.va_fbo = *iova_start; + mhp->attr.page_size = shift - 12; + mhp->attr.len = (u32) total_size; + mhp->attr.pbl_size = npages; + } + + return 0; +} + + +static struct ib_mr *iwch_reg_user_mr(struct ib_pd *pd, struct ib_umem *region, + int acc, struct ib_udata *udata) +{ + __be64 *pages; + int shift, n, len; + int i, j, k; + int err = 0; + struct ib_umem_chunk *chunk; + struct iwch_dev *rhp; + struct iwch_pd *php; + struct iwch_mr *mhp; + struct iwch_reg_user_mr_resp uresp; + + PDBG("%s ib_pd %p\n", __FUNCTION__, pd); + shift = ffs(region->page_size) - 1; + + php = to_iwch_pd(pd); + rhp = php->rhp; + mhp = kzalloc(sizeof(*mhp), GFP_KERNEL); + if (!mhp) + return ERR_PTR(-ENOMEM); + + n = 0; + list_for_each_entry(chunk, ®ion->chunk_list, list) + n += chunk->nents; + + pages = kmalloc(n * sizeof(u64), GFP_KERNEL); + if (!pages) { + err = -ENOMEM; + goto err; + } + + acc = iwch_convert_access(acc); + + i = n = 0; + + list_for_each_entry(chunk, ®ion->chunk_list, list) + for (j = 0; j < chunk->nmap; ++j) { + len = sg_dma_len(&chunk->page_list[j]) >> shift; + for (k = 0; k < len; ++k) { + pages[i++] = cpu_to_be64(sg_dma_address( + &chunk->page_list[j]) + + region->page_size * k); + } + } + + mhp->rhp = rhp; + mhp->attr.pdid = php->pdid; + mhp->attr.zbva = 0; + mhp->attr.perms = (acc & 0x1) << 3; + mhp->attr.perms |= (acc & 0x2) << 1; + mhp->attr.perms |= (acc & 0x4) >> 1; + mhp->attr.perms |= (acc & 0x8) >> 3; + mhp->attr.va_fbo = region->virt_base; + mhp->attr.page_size = shift - 12; + mhp->attr.len = (u32) region->length; + mhp->attr.pbl_size = i; + err = iwch_register_mem(rhp, php, mhp, shift, pages); + kfree(pages); + if (err) + goto err; + + if (udata && t3b_device(rhp)) { + uresp.pbl_addr = (mhp->attr.pbl_addr - + rhp->rdev.rnic_info.pbl_base) >> 3; + PDBG("%s user resp pbl_addr 0x%x\n", __FUNCTION__, + uresp.pbl_addr); + + if (ib_copy_to_udata(udata, &uresp, sizeof (uresp))) { + iwch_dereg_mr(&mhp->ibmr); + err = -EFAULT; + goto err; + } + } + + return &mhp->ibmr; + +err: + kfree(mhp); + return ERR_PTR(err); +} + +static struct ib_mr *iwch_get_dma_mr(struct ib_pd *pd, int acc) +{ + struct ib_phys_buf bl; + u64 kva; + struct ib_mr *ibmr; + + PDBG("%s ib_pd %p\n", __FUNCTION__, pd); + + /* + * T3 only supports 32 bits of size. + */ + bl.size = 0xffffffff; + bl.addr = 0; + kva = 0; + ibmr = iwch_register_phys_mem(pd, &bl, 1, acc, &kva); + return ibmr; +} + +static struct ib_mw *iwch_alloc_mw(struct ib_pd *pd) +{ + struct iwch_dev *rhp; + struct iwch_pd *php; + struct iwch_mw *mhp; + u32 mmid; + u32 stag = 0; + int ret; + + php = to_iwch_pd(pd); + rhp = php->rhp; + mhp = kzalloc(sizeof(*mhp), GFP_KERNEL); + if (!mhp) + return ERR_PTR(-ENOMEM); + ret = cxio_allocate_window(&rhp->rdev, &stag, php->pdid); + if (ret) { + kfree(mhp); + return ERR_PTR(ret); + } + mhp->rhp = rhp; + mhp->attr.pdid = php->pdid; + mhp->attr.type = TPT_MW; + mhp->attr.stag = stag; + mmid = (stag) >> 8; + insert_handle(rhp, &rhp->mmidr, mhp, mmid); + PDBG("%s mmid 0x%x mhp %p stag 0x%x\n", __FUNCTION__, mmid, mhp, stag); + return &(mhp->ibmw); +} + +static int iwch_dealloc_mw(struct ib_mw *mw) +{ + struct iwch_dev *rhp; + struct iwch_mw *mhp; + u32 mmid; + + mhp = to_iwch_mw(mw); + rhp = mhp->rhp; + mmid = (mw->rkey) >> 8; + cxio_deallocate_window(&rhp->rdev, mhp->attr.stag); + remove_handle(rhp, &rhp->mmidr, mmid); + kfree(mhp); + PDBG("%s ib_mw %p mmid 0x%x ptr %p\n", __FUNCTION__, mw, mmid, mhp); + return 0; +} + +static int iwch_destroy_qp(struct ib_qp *ib_qp) +{ + struct iwch_dev *rhp; + struct iwch_qp *qhp; + struct iwch_qp_attributes attrs; + struct iwch_ucontext *ucontext; + + qhp = to_iwch_qp(ib_qp); + rhp = qhp->rhp; + + if (qhp->attr.state == IWCH_QP_STATE_RTS) { + attrs.next_state = IWCH_QP_STATE_ERROR; + iwch_modify_qp(rhp, qhp, IWCH_QP_ATTR_NEXT_STATE, &attrs, 0); + } + wait_event(qhp->wait, !qhp->ep); + + remove_handle(rhp, &rhp->qpidr, qhp->wq.qpid); + + atomic_dec(&qhp->refcnt); + wait_event(qhp->wait, !atomic_read(&qhp->refcnt)); + + ucontext = ib_qp->uobject ? to_iwch_ucontext(ib_qp->uobject->context) + : NULL; + cxio_destroy_qp(&rhp->rdev, &qhp->wq, + ucontext ? &ucontext->uctx : &rhp->rdev.uctx); + + PDBG("%s ib_qp %p qpid 0x%0x qhp %p\n", __FUNCTION__, + ib_qp, qhp->wq.qpid, qhp); + kfree(qhp); + return 0; +} + +static struct ib_qp *iwch_create_qp(struct ib_pd *pd, + struct ib_qp_init_attr *attrs, + struct ib_udata *udata) +{ + struct iwch_dev *rhp; + struct iwch_qp *qhp; + struct iwch_pd *php; + struct iwch_cq *schp; + struct iwch_cq *rchp; + struct iwch_create_qp_resp uresp; + int wqsize, sqsize, rqsize; + struct iwch_ucontext *ucontext; + + PDBG("%s ib_pd %p\n", __FUNCTION__, pd); + if (attrs->qp_type != IB_QPT_RC) + return ERR_PTR(-EINVAL); + php = to_iwch_pd(pd); + rhp = php->rhp; + schp = get_chp(rhp, ((struct iwch_cq *) attrs->send_cq)->cq.cqid); + rchp = get_chp(rhp, ((struct iwch_cq *) attrs->recv_cq)->cq.cqid); + if (!schp || !rchp) + return ERR_PTR(-EINVAL); + + /* The RQT size must be # of entries + 1 rounded up to a power of two */ + rqsize = roundup_pow_of_two(attrs->cap.max_recv_wr); + if (rqsize == attrs->cap.max_recv_wr) + rqsize = roundup_pow_of_two(attrs->cap.max_recv_wr+1); + + /* T3 doesn't support RQT depth < 16 */ + if (rqsize < 16) + rqsize = 16; + + if (rqsize > T3_MAX_RQ_SIZE) + return ERR_PTR(-EINVAL); + + /* + * NOTE: The SQ and total WQ sizes don't need to be + * a power of two. However, all the code assumes + * they are. EG: Q_FREECNT() and friends. + */ + sqsize = roundup_pow_of_two(attrs->cap.max_send_wr); + wqsize = roundup_pow_of_two(rqsize + sqsize); + PDBG("%s wqsize %d sqsize %d rqsize %d\n", __FUNCTION__, + wqsize, sqsize, rqsize); + qhp = kzalloc(sizeof(*qhp), GFP_KERNEL); + if (!qhp) + return ERR_PTR(-ENOMEM); + qhp->wq.size_log2 = ilog2(wqsize); + qhp->wq.rq_size_log2 = ilog2(rqsize); + qhp->wq.sq_size_log2 = ilog2(sqsize); + ucontext = pd->uobject ? to_iwch_ucontext(pd->uobject->context) : NULL; + if (cxio_create_qp(&rhp->rdev, !udata, &qhp->wq, + ucontext ? &ucontext->uctx : &rhp->rdev.uctx)) { + kfree(qhp); + return ERR_PTR(-ENOMEM); + } + attrs->cap.max_recv_wr = rqsize - 1; + attrs->cap.max_send_wr = sqsize; + qhp->rhp = rhp; + qhp->attr.pd = php->pdid; + qhp->attr.scq = ((struct iwch_cq *) attrs->send_cq)->cq.cqid; + qhp->attr.rcq = ((struct iwch_cq *) attrs->recv_cq)->cq.cqid; + qhp->attr.sq_num_entries = attrs->cap.max_send_wr; + qhp->attr.rq_num_entries = attrs->cap.max_recv_wr; + qhp->attr.sq_max_sges = attrs->cap.max_send_sge; + qhp->attr.sq_max_sges_rdma_write = attrs->cap.max_send_sge; + qhp->attr.rq_max_sges = attrs->cap.max_recv_sge; + qhp->attr.state = IWCH_QP_STATE_IDLE; + qhp->attr.next_state = IWCH_QP_STATE_IDLE; + + /* + * XXX - These don't get passed in from the openib user + * at create time. The CM sets them via a QP modify. + * Need to fix... I think the CM should + */ + qhp->attr.enable_rdma_read = 1; + qhp->attr.enable_rdma_write = 1; + qhp->attr.enable_bind = 1; + qhp->attr.max_ord = 1; + qhp->attr.max_ird = 1; + + spin_lock_init(&qhp->lock); + init_waitqueue_head(&qhp->wait); + atomic_set(&qhp->refcnt, 1); + insert_handle(rhp, &rhp->qpidr, qhp, qhp->wq.qpid); + + if (udata) { + + struct iwch_mm_entry *mm1, *mm2; + + mm1 = kmalloc(sizeof *mm1, GFP_KERNEL); + if (!mm1) { + iwch_destroy_qp(&qhp->ibqp); + return ERR_PTR(-ENOMEM); + } + + mm2 = kmalloc(sizeof *mm2, GFP_KERNEL); + if (!mm2) { + kfree(mm1); + iwch_destroy_qp(&qhp->ibqp); + return ERR_PTR(-ENOMEM); + } + + uresp.qpid = qhp->wq.qpid; + uresp.size_log2 = qhp->wq.size_log2; + uresp.sq_size_log2 = qhp->wq.sq_size_log2; + uresp.rq_size_log2 = qhp->wq.rq_size_log2; + spin_lock(&ucontext->mmap_lock); + uresp.key = ucontext->key; + ucontext->key += PAGE_SIZE; + uresp.db_key = ucontext->key; + ucontext->key += PAGE_SIZE; + spin_unlock(&ucontext->mmap_lock); + if (ib_copy_to_udata(udata, &uresp, sizeof (uresp))) { + kfree(mm1); + kfree(mm2); + iwch_destroy_qp(&qhp->ibqp); + return ERR_PTR(-EFAULT); + } + mm1->key = uresp.key; + mm1->addr = virt_to_phys(qhp->wq.queue); + mm1->len = PAGE_ALIGN(wqsize * sizeof (union t3_wr)); + insert_mmap(ucontext, mm1); + mm2->key = uresp.db_key; + mm2->addr = qhp->wq.udb & PAGE_MASK; + mm2->len = PAGE_SIZE; + insert_mmap(ucontext, mm2); + } + qhp->ibqp.qp_num = qhp->wq.qpid; + init_timer(&(qhp->timer)); + PDBG("%s sq_num_entries %d, rq_num_entries %d " + "qpid 0x%0x qhp %p dma_addr 0x%llx size %d\n", + __FUNCTION__, qhp->attr.sq_num_entries, qhp->attr.rq_num_entries, + qhp->wq.qpid, qhp, (unsigned long long) qhp->wq.dma_addr, + 1 << qhp->wq.size_log2); + return &qhp->ibqp; +} + +static int iwch_ib_modify_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr, + int attr_mask, struct ib_udata *udata) +{ + struct iwch_dev *rhp; + struct iwch_qp *qhp; + enum iwch_qp_attr_mask mask = 0; + struct iwch_qp_attributes attrs; + + PDBG("%s ib_qp %p\n", __FUNCTION__, ibqp); + + /* iwarp does not support the RTR state */ + if ((attr_mask & IB_QP_STATE) && (attr->qp_state == IB_QPS_RTR)) + attr_mask &= ~IB_QP_STATE; + + /* Make sure we still have something left to do */ + if (!attr_mask) + return 0; + + memset(&attrs, 0, sizeof attrs); + qhp = to_iwch_qp(ibqp); + rhp = qhp->rhp; + + attrs.next_state = iwch_convert_state(attr->qp_state); + attrs.enable_rdma_read = (attr->qp_access_flags & + IB_ACCESS_REMOTE_READ) ? 1 : 0; + attrs.enable_rdma_write = (attr->qp_access_flags & + IB_ACCESS_REMOTE_WRITE) ? 1 : 0; + attrs.enable_bind = (attr->qp_access_flags & IB_ACCESS_MW_BIND) ? 1 : 0; + + + mask |= (attr_mask & IB_QP_STATE) ? IWCH_QP_ATTR_NEXT_STATE : 0; + mask |= (attr_mask & IB_QP_ACCESS_FLAGS) ? + (IWCH_QP_ATTR_ENABLE_RDMA_READ | + IWCH_QP_ATTR_ENABLE_RDMA_WRITE | + IWCH_QP_ATTR_ENABLE_RDMA_BIND) : 0; + + return iwch_modify_qp(rhp, qhp, mask, &attrs, 0); +} + +void iwch_qp_add_ref(struct ib_qp *qp) +{ + PDBG("%s ib_qp %p\n", __FUNCTION__, qp); + atomic_inc(&(to_iwch_qp(qp)->refcnt)); +} + +void iwch_qp_rem_ref(struct ib_qp *qp) +{ + PDBG("%s ib_qp %p\n", __FUNCTION__, qp); + if (atomic_dec_and_test(&(to_iwch_qp(qp)->refcnt))) + wake_up(&(to_iwch_qp(qp)->wait)); +} + +struct ib_qp *iwch_get_qp(struct ib_device *dev, int qpn) +{ + PDBG("%s ib_dev %p qpn 0x%x\n", __FUNCTION__, dev, qpn); + return (struct ib_qp *)get_qhp(to_iwch_dev(dev), qpn); +} + + +static int iwch_query_pkey(struct ib_device *ibdev, + u8 port, u16 index, u16 * pkey) +{ + PDBG("%s ibdev %p\n", __FUNCTION__, ibdev); + *pkey = 0; + return 0; +} + +static int iwch_query_gid(struct ib_device *ibdev, u8 port, + int index, union ib_gid *gid) +{ + struct iwch_dev *dev; + + PDBG("%s ibdev %p, port %d, index %d, gid %p\n", + __FUNCTION__, ibdev, port, index, gid); + dev = to_iwch_dev(ibdev); + BUG_ON(port == 0 || port > 2); + memset(&(gid->raw[0]), 0, sizeof(gid->raw)); + memcpy(&(gid->raw[0]), dev->rdev.port_info.lldevs[port-1]->dev_addr, 6); + return 0; +} + +static int iwch_query_device(struct ib_device *ibdev, + struct ib_device_attr *props) +{ + + struct iwch_dev *dev; + PDBG("%s ibdev %p\n", __FUNCTION__, ibdev); + + dev = to_iwch_dev(ibdev); + memset(props, 0, sizeof *props); + memcpy(&props->sys_image_guid, dev->rdev.t3cdev_p->lldev->dev_addr, 6); + props->device_cap_flags = dev->device_cap_flags; + props->vendor_id = (u32)dev->rdev.rnic_info.pdev->vendor; + props->vendor_part_id = (u32)dev->rdev.rnic_info.pdev->device; + props->max_mr_size = ~0ull; + props->max_qp = dev->attr.max_qps; + props->max_qp_wr = dev->attr.max_wrs; + props->max_sge = dev->attr.max_sge_per_wr; + props->max_sge_rd = 1; + props->max_qp_rd_atom = dev->attr.max_rdma_reads_per_qp; + props->max_cq = dev->attr.max_cqs; + props->max_cqe = dev->attr.max_cqes_per_cq; + props->max_mr = dev->attr.max_mem_regs; + props->max_pd = dev->attr.max_pds; + props->local_ca_ack_delay = 0; + + return 0; +} + +static int iwch_query_port(struct ib_device *ibdev, + u8 port, struct ib_port_attr *props) +{ + PDBG("%s ibdev %p\n", __FUNCTION__, ibdev); + props->max_mtu = IB_MTU_4096; + props->lid = 0; + props->lmc = 0; + props->sm_lid = 0; + props->sm_sl = 0; + props->state = IB_PORT_ACTIVE; + props->phys_state = 0; + props->port_cap_flags = + IB_PORT_CM_SUP | + IB_PORT_SNMP_TUNNEL_SUP | + IB_PORT_REINIT_SUP | + IB_PORT_DEVICE_MGMT_SUP | + IB_PORT_VENDOR_CLASS_SUP | IB_PORT_BOOT_MGMT_SUP; + props->gid_tbl_len = 1; + props->pkey_tbl_len = 1; + props->qkey_viol_cntr = 0; + props->active_width = 2; + props->active_speed = 2; + props->max_msg_sz = -1; + + return 0; +} + +static ssize_t show_rev(struct class_device *cdev, char *buf) +{ + struct iwch_dev *dev = container_of(cdev, struct iwch_dev, + ibdev.class_dev); + PDBG("%s class dev 0x%p\n", __FUNCTION__, cdev); + return sprintf(buf, "%d\n", dev->rdev.t3cdev_p->type); +} + +static ssize_t show_fw_ver(struct class_device *cdev, char *buf) +{ + struct iwch_dev *dev = container_of(cdev, struct iwch_dev, + ibdev.class_dev); + struct ethtool_drvinfo info; + struct net_device *lldev = dev->rdev.t3cdev_p->lldev; + + PDBG("%s class dev 0x%p\n", __FUNCTION__, cdev); + lldev->ethtool_ops->get_drvinfo(lldev, &info); + return sprintf(buf, "%s\n", info.fw_version); +} + +static ssize_t show_hca(struct class_device *cdev, char *buf) +{ + struct iwch_dev *dev = container_of(cdev, struct iwch_dev, + ibdev.class_dev); + struct ethtool_drvinfo info; + struct net_device *lldev = dev->rdev.t3cdev_p->lldev; + + PDBG("%s class dev 0x%p\n", __FUNCTION__, cdev); + lldev->ethtool_ops->get_drvinfo(lldev, &info); + return sprintf(buf, "%s\n", info.driver); +} + +static ssize_t show_board(struct class_device *cdev, char *buf) +{ + struct iwch_dev *dev = container_of(cdev, struct iwch_dev, + ibdev.class_dev); + PDBG("%s class dev 0x%p\n", __FUNCTION__, dev); + return sprintf(buf, "%x.%x\n", dev->rdev.rnic_info.pdev->vendor, + dev->rdev.rnic_info.pdev->device); +} + +static CLASS_DEVICE_ATTR(hw_rev, S_IRUGO, show_rev, NULL); +static CLASS_DEVICE_ATTR(fw_ver, S_IRUGO, show_fw_ver, NULL); +static CLASS_DEVICE_ATTR(hca_type, S_IRUGO, show_hca, NULL); +static CLASS_DEVICE_ATTR(board_id, S_IRUGO, show_board, NULL); + +static struct class_device_attribute *iwch_class_attributes[] = { + &class_device_attr_hw_rev, + &class_device_attr_fw_ver, + &class_device_attr_hca_type, + &class_device_attr_board_id +}; + +int iwch_register_device(struct iwch_dev *dev) +{ + int ret; + int i; + + PDBG("%s iwch_dev %p\n", __FUNCTION__, dev); + strlcpy(dev->ibdev.name, "cxgb3_%d", IB_DEVICE_NAME_MAX); + memset(&dev->ibdev.node_guid, 0, sizeof(dev->ibdev.node_guid)); + memcpy(&dev->ibdev.node_guid, dev->rdev.t3cdev_p->lldev->dev_addr, 6); + dev->ibdev.owner = THIS_MODULE; + dev->device_cap_flags = + (IB_DEVICE_ZERO_STAG | + IB_DEVICE_SEND_W_INV | IB_DEVICE_MEM_WINDOW); + + dev->ibdev.uverbs_cmd_mask = + (1ull << IB_USER_VERBS_CMD_GET_CONTEXT) | + (1ull << IB_USER_VERBS_CMD_QUERY_DEVICE) | + (1ull << IB_USER_VERBS_CMD_QUERY_PORT) | + (1ull << IB_USER_VERBS_CMD_ALLOC_PD) | + (1ull << IB_USER_VERBS_CMD_DEALLOC_PD) | + (1ull << IB_USER_VERBS_CMD_REG_MR) | + (1ull << IB_USER_VERBS_CMD_DEREG_MR) | + (1ull << IB_USER_VERBS_CMD_CREATE_COMP_CHANNEL) | + (1ull << IB_USER_VERBS_CMD_CREATE_CQ) | + (1ull << IB_USER_VERBS_CMD_DESTROY_CQ) | + (1ull << IB_USER_VERBS_CMD_REQ_NOTIFY_CQ) | + (1ull << IB_USER_VERBS_CMD_CREATE_QP) | + (1ull << IB_USER_VERBS_CMD_MODIFY_QP) | + (1ull << IB_USER_VERBS_CMD_POLL_CQ) | + (1ull << IB_USER_VERBS_CMD_DESTROY_QP) | + (1ull << IB_USER_VERBS_CMD_POST_SEND) | + (1ull << IB_USER_VERBS_CMD_POST_RECV); + dev->ibdev.node_type = RDMA_NODE_RNIC; + memcpy(dev->ibdev.node_desc, IWCH_NODE_DESC, sizeof(IWCH_NODE_DESC)); + dev->ibdev.phys_port_cnt = dev->rdev.port_info.nports; + dev->ibdev.dma_device = &(dev->rdev.rnic_info.pdev->dev); + dev->ibdev.class_dev.dev = &(dev->rdev.rnic_info.pdev->dev); + dev->ibdev.query_device = iwch_query_device; + dev->ibdev.query_port = iwch_query_port; + dev->ibdev.modify_port = iwch_modify_port; + dev->ibdev.query_pkey = iwch_query_pkey; + dev->ibdev.query_gid = iwch_query_gid; + dev->ibdev.alloc_ucontext = iwch_alloc_ucontext; + dev->ibdev.dealloc_ucontext = iwch_dealloc_ucontext; + dev->ibdev.mmap = iwch_mmap; + dev->ibdev.alloc_pd = iwch_allocate_pd; + dev->ibdev.dealloc_pd = iwch_deallocate_pd; + dev->ibdev.create_ah = iwch_ah_create; + dev->ibdev.destroy_ah = iwch_ah_destroy; + dev->ibdev.create_qp = iwch_create_qp; + dev->ibdev.modify_qp = iwch_ib_modify_qp; + dev->ibdev.destroy_qp = iwch_destroy_qp; + dev->ibdev.create_cq = iwch_create_cq; + dev->ibdev.destroy_cq = iwch_destroy_cq; + dev->ibdev.resize_cq = iwch_resize_cq; + dev->ibdev.poll_cq = iwch_poll_cq; + dev->ibdev.get_dma_mr = iwch_get_dma_mr; + dev->ibdev.reg_phys_mr = iwch_register_phys_mem; + dev->ibdev.rereg_phys_mr = iwch_reregister_phys_mem; + dev->ibdev.reg_user_mr = iwch_reg_user_mr; + dev->ibdev.dereg_mr = iwch_dereg_mr; + dev->ibdev.alloc_mw = iwch_alloc_mw; + dev->ibdev.bind_mw = iwch_bind_mw; + dev->ibdev.dealloc_mw = iwch_dealloc_mw; + + dev->ibdev.attach_mcast = iwch_multicast_attach; + dev->ibdev.detach_mcast = iwch_multicast_detach; + dev->ibdev.process_mad = iwch_process_mad; + + dev->ibdev.req_notify_cq = iwch_arm_cq; + dev->ibdev.post_send = iwch_post_send; + dev->ibdev.post_recv = iwch_post_receive; + + + dev->ibdev.iwcm = + (struct iw_cm_verbs *) kmalloc(sizeof(struct iw_cm_verbs), + GFP_KERNEL); + dev->ibdev.iwcm->connect = iwch_connect; + dev->ibdev.iwcm->accept = iwch_accept_cr; + dev->ibdev.iwcm->reject = iwch_reject_cr; + dev->ibdev.iwcm->create_listen = iwch_create_listen; + dev->ibdev.iwcm->destroy_listen = iwch_destroy_listen; + dev->ibdev.iwcm->add_ref = iwch_qp_add_ref; + dev->ibdev.iwcm->rem_ref = iwch_qp_rem_ref; + dev->ibdev.iwcm->get_qp = iwch_get_qp; + + ret = ib_register_device(&dev->ibdev); + if (ret) + goto bail1; + + for (i = 0; i < ARRAY_SIZE(iwch_class_attributes); ++i) { + ret = class_device_create_file(&dev->ibdev.class_dev, + iwch_class_attributes[i]); + if (ret) { + goto bail2; + } + } + return 0; +bail2: + ib_unregister_device(&dev->ibdev); +bail1: + return ret; +} + +void iwch_unregister_device(struct iwch_dev *dev) +{ + int i; + + PDBG("%s iwch_dev %p\n", __FUNCTION__, dev); + for (i = 0; i < ARRAY_SIZE(iwch_class_attributes); ++i) + class_device_remove_file(&dev->ibdev.class_dev, + iwch_class_attributes[i]); + ib_unregister_device(&dev->ibdev); + return; +} diff --git a/drivers/infiniband/hw/cxgb3/iwch_provider.h b/drivers/infiniband/hw/cxgb3/iwch_provider.h new file mode 100644 index 0000000..61e3278 --- /dev/null +++ b/drivers/infiniband/hw/cxgb3/iwch_provider.h @@ -0,0 +1,367 @@ +/* + * Copyright (c) 2006 Chelsio, Inc. All rights reserved. + * Copyright (c) 2006 Open Grid Computing, Inc. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +#ifndef __IWCH_PROVIDER_H__ +#define __IWCH_PROVIDER_H__ + +#include +#include +#include +#include +#include "t3cdev.h" +#include "iwch.h" +#include "cxio_wr.h" +#include "cxio_hal.h" + +struct iwch_pd { + struct ib_pd ibpd; + u32 pdid; + struct iwch_dev *rhp; +}; + +static inline struct iwch_pd *to_iwch_pd(struct ib_pd *ibpd) +{ + return container_of(ibpd, struct iwch_pd, ibpd); +} + +struct tpt_attributes { + u32 stag; + u32 state:1; + u32 type:2; + u32 rsvd:1; + enum tpt_mem_perm perms; + u32 remote_invaliate_disable:1; + u32 zbva:1; + u32 mw_bind_enable:1; + u32 page_size:5; + + u32 pdid; + u32 qpid; + u32 pbl_addr; + u32 len; + u64 va_fbo; + u32 pbl_size; +}; + +struct iwch_mr { + struct ib_mr ibmr; + struct iwch_dev *rhp; + u64 kva; + struct tpt_attributes attr; +}; + +typedef struct iwch_mw iwch_mw_handle; + +static inline struct iwch_mr *to_iwch_mr(struct ib_mr *ibmr) +{ + return container_of(ibmr, struct iwch_mr, ibmr); +} + +struct iwch_mw { + struct ib_mw ibmw; + struct iwch_dev *rhp; + u64 kva; + struct tpt_attributes attr; +}; + +static inline struct iwch_mw *to_iwch_mw(struct ib_mw *ibmw) +{ + return container_of(ibmw, struct iwch_mw, ibmw); +} + +struct iwch_cq { + struct ib_cq ibcq; + struct iwch_dev *rhp; + struct t3_cq cq; + spinlock_t lock; + atomic_t refcnt; + wait_queue_head_t wait; + u32 __user *user_rptr_addr; +}; + +static inline struct iwch_cq *to_iwch_cq(struct ib_cq *ibcq) +{ + return container_of(ibcq, struct iwch_cq, ibcq); +} + +enum IWCH_QP_FLAGS { + QP_QUIESCED = 0x01 +}; + +struct iwch_mpa_attributes { + u8 recv_marker_enabled; + u8 xmit_marker_enabled; /* iWARP: enable inbound Read Resp. */ + u8 crc_enabled; + u8 version; /* 0 or 1 */ +}; + +struct iwch_qp_attributes { + u32 scq; + u32 rcq; + u32 sq_num_entries; + u32 rq_num_entries; + u32 sq_max_sges; + u32 sq_max_sges_rdma_write; + u32 rq_max_sges; + u32 state; + u8 enable_rdma_read; + u8 enable_rdma_write; /* enable inbound Read Resp. */ + u8 enable_bind; + u8 enable_mmid0_fastreg; /* Enable STAG0 + Fast-register */ + /* + * Next QP state. If specify the current state, only the + * QP attributes will be modified. + */ + u32 max_ord; + u32 max_ird; + u32 pd; /* IN */ + u32 next_state; + char terminate_buffer[52]; + u32 terminate_msg_len; + u8 is_terminate_local; + struct iwch_mpa_attributes mpa_attr; /* IN-OUT */ + struct iwch_ep *llp_stream_handle; + char *stream_msg_buf; /* Last stream msg. before Idle -> RTS */ + u32 stream_msg_buf_len; /* Only on Idle -> RTS */ +}; + +struct iwch_qp { + struct ib_qp ibqp; + struct iwch_dev *rhp; + struct iwch_ep *ep; + struct iwch_qp_attributes attr; + struct t3_wq wq; + spinlock_t lock; + atomic_t refcnt; + wait_queue_head_t wait; + enum IWCH_QP_FLAGS flags; + struct timer_list timer; +}; + +static inline int qp_quiesced(struct iwch_qp *qhp) +{ + return qhp->flags & QP_QUIESCED; +} + +static inline struct iwch_qp *to_iwch_qp(struct ib_qp *ibqp) +{ + return container_of(ibqp, struct iwch_qp, ibqp); +} + +void iwch_qp_add_ref(struct ib_qp *qp); +void iwch_qp_rem_ref(struct ib_qp *qp); +struct ib_qp *iwch_get_qp(struct ib_device *dev, int qpn); + +struct iwch_ucontext { + struct ib_ucontext ibucontext; + struct cxio_ucontext uctx; + u32 key; + spinlock_t mmap_lock; + struct list_head mmaps; +}; + +static inline struct iwch_ucontext *to_iwch_ucontext(struct ib_ucontext *c) +{ + return container_of(c, struct iwch_ucontext, ibucontext); +} + +struct iwch_mm_entry { + struct list_head entry; + u64 addr; + u32 key; + unsigned len; +}; + +static inline struct iwch_mm_entry *remove_mmap(struct iwch_ucontext *ucontext, + u32 key, unsigned len) +{ + struct list_head *pos, *nxt; + struct iwch_mm_entry *mm; + + spin_lock(&ucontext->mmap_lock); + list_for_each_safe(pos, nxt, &ucontext->mmaps) { + + mm = list_entry(pos, struct iwch_mm_entry, entry); + if (mm->key == key && mm->len == len) { + list_del_init(&mm->entry); + spin_unlock(&ucontext->mmap_lock); + PDBG("%s key 0x%x addr 0x%llx len %d\n", __FUNCTION__, + key, (unsigned long long) mm->addr, mm->len); + return mm; + } + } + spin_unlock(&ucontext->mmap_lock); + return NULL; +} + +static inline void insert_mmap(struct iwch_ucontext *ucontext, + struct iwch_mm_entry *mm) +{ + spin_lock(&ucontext->mmap_lock); + PDBG("%s key 0x%x addr 0x%llx len %d\n", __FUNCTION__, + mm->key, (unsigned long long) mm->addr, mm->len); + list_add_tail(&mm->entry, &ucontext->mmaps); + spin_unlock(&ucontext->mmap_lock); +} + +enum iwch_qp_attr_mask { + IWCH_QP_ATTR_NEXT_STATE = 1 << 0, + IWCH_QP_ATTR_ENABLE_RDMA_READ = 1 << 7, + IWCH_QP_ATTR_ENABLE_RDMA_WRITE = 1 << 8, + IWCH_QP_ATTR_ENABLE_RDMA_BIND = 1 << 9, + IWCH_QP_ATTR_MAX_ORD = 1 << 11, + IWCH_QP_ATTR_MAX_IRD = 1 << 12, + IWCH_QP_ATTR_LLP_STREAM_HANDLE = 1 << 22, + IWCH_QP_ATTR_STREAM_MSG_BUFFER = 1 << 23, + IWCH_QP_ATTR_MPA_ATTR = 1 << 24, + IWCH_QP_ATTR_QP_CONTEXT_ACTIVATE = 1 << 25, + IWCH_QP_ATTR_VALID_MODIFY = (IWCH_QP_ATTR_ENABLE_RDMA_READ | + IWCH_QP_ATTR_ENABLE_RDMA_WRITE | + IWCH_QP_ATTR_MAX_ORD | + IWCH_QP_ATTR_MAX_IRD | + IWCH_QP_ATTR_LLP_STREAM_HANDLE | + IWCH_QP_ATTR_STREAM_MSG_BUFFER | + IWCH_QP_ATTR_MPA_ATTR | + IWCH_QP_ATTR_QP_CONTEXT_ACTIVATE) +}; + +int iwch_modify_qp(struct iwch_dev *rhp, + struct iwch_qp *qhp, + enum iwch_qp_attr_mask mask, + struct iwch_qp_attributes *attrs, + int internal); + +enum iwch_qp_state { + IWCH_QP_STATE_IDLE, + IWCH_QP_STATE_RTS, + IWCH_QP_STATE_ERROR, + IWCH_QP_STATE_TERMINATE, + IWCH_QP_STATE_CLOSING, + IWCH_QP_STATE_TOT +}; + +static inline int iwch_convert_state(enum ib_qp_state ib_state) +{ + switch (ib_state) { + case IB_QPS_RESET: + case IB_QPS_INIT: + return IWCH_QP_STATE_IDLE; + case IB_QPS_RTS: + return IWCH_QP_STATE_RTS; + case IB_QPS_SQD: + return IWCH_QP_STATE_CLOSING; + case IB_QPS_SQE: + return IWCH_QP_STATE_TERMINATE; + case IB_QPS_ERR: + return IWCH_QP_STATE_ERROR; + default: + return -1; + } +} + +enum iwch_mem_perms { + IWCH_MEM_ACCESS_LOCAL_READ = 1 << 0, + IWCH_MEM_ACCESS_LOCAL_WRITE = 1 << 1, + IWCH_MEM_ACCESS_REMOTE_READ = 1 << 2, + IWCH_MEM_ACCESS_REMOTE_WRITE = 1 << 3, + IWCH_MEM_ACCESS_ATOMICS = 1 << 4, + IWCH_MEM_ACCESS_BINDING = 1 << 5, + IWCH_MEM_ACCESS_LOCAL = + (IWCH_MEM_ACCESS_LOCAL_READ | IWCH_MEM_ACCESS_LOCAL_WRITE), + IWCH_MEM_ACCESS_REMOTE = + (IWCH_MEM_ACCESS_REMOTE_WRITE | IWCH_MEM_ACCESS_REMOTE_READ) + /* cannot go beyond 1 << 31 */ +} __attribute__ ((packed)); + +static inline u32 iwch_convert_access(int acc) +{ + return (acc & IB_ACCESS_REMOTE_WRITE ? IWCH_MEM_ACCESS_REMOTE_WRITE : 0) + | (acc & IB_ACCESS_REMOTE_READ ? IWCH_MEM_ACCESS_REMOTE_READ : 0) | + (acc & IB_ACCESS_LOCAL_WRITE ? IWCH_MEM_ACCESS_LOCAL_WRITE : 0) | + (acc & IB_ACCESS_MW_BIND ? IWCH_MEM_ACCESS_BINDING : 0) | + IWCH_MEM_ACCESS_LOCAL_READ; +} + +enum iwch_mmid_state { + IWCH_STAG_STATE_VALID, + IWCH_STAG_STATE_INVALID +}; + +enum iwch_qp_query_flags { + IWCH_QP_QUERY_CONTEXT_NONE = 0x0, /* No ctx; Only attrs */ + IWCH_QP_QUERY_CONTEXT_GET = 0x1, /* Get ctx + attrs */ + IWCH_QP_QUERY_CONTEXT_SUSPEND = 0x2, /* Not Supported */ + + /* + * Quiesce QP context; Consumer + * will NOT replay outstanding WR + */ + IWCH_QP_QUERY_CONTEXT_QUIESCE = 0x4, + IWCH_QP_QUERY_CONTEXT_REMOVE = 0x8, + IWCH_QP_QUERY_TEST_USERWRITE = 0x32 /* Test special */ +}; + +int iwch_post_send(struct ib_qp *ibqp, struct ib_send_wr *wr, + struct ib_send_wr **bad_wr); +int iwch_post_receive(struct ib_qp *ibqp, struct ib_recv_wr *wr, + struct ib_recv_wr **bad_wr); +int iwch_bind_mw(struct ib_qp *qp, + struct ib_mw *mw, + struct ib_mw_bind *mw_bind); +int iwch_poll_cq(struct ib_cq *ibcq, int num_entries, struct ib_wc *wc); +int iwch_post_terminate(struct iwch_qp *qhp, struct respQ_msg_t *rsp_msg); +int iwch_register_device(struct iwch_dev *dev); +void iwch_unregister_device(struct iwch_dev *dev); +int iwch_quiesce_qps(struct iwch_cq *chp); +int iwch_resume_qps(struct iwch_cq *chp); +void stop_read_rep_timer(struct iwch_qp *qhp); +int iwch_register_mem(struct iwch_dev *rhp, struct iwch_pd *php, + struct iwch_mr *mhp, + int shift, + __be64 *page_list); +int iwch_reregister_mem(struct iwch_dev *rhp, struct iwch_pd *php, + struct iwch_mr *mhp, + int shift, + __be64 *page_list, + int npages); +int build_phys_page_list(struct ib_phys_buf *buffer_list, + int num_phys_buf, + u64 *iova_start, + u64 *total_size, + int *npages, + int *shift, + __be64 **page_list); + + +#define IWCH_NODE_DESC "cxgb3 Chelsio Communications" + +#endif diff --git a/drivers/infiniband/hw/cxgb3/iwch_qp.c b/drivers/infiniband/hw/cxgb3/iwch_qp.c new file mode 100644 index 0000000..e066727 --- /dev/null +++ b/drivers/infiniband/hw/cxgb3/iwch_qp.c @@ -0,0 +1,1007 @@ +/* + * Copyright (c) 2006 Chelsio, Inc. All rights reserved. + * Copyright (c) 2006 Open Grid Computing, Inc. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +#include "iwch_provider.h" +#include "iwch.h" +#include "iwch_cm.h" +#include "cxio_hal.h" + +#define NO_SUPPORT -1 + +static inline int iwch_build_rdma_send(union t3_wr *wqe, struct ib_send_wr *wr, + u8 * flit_cnt) +{ + int i; + u32 plen; + + switch (wr->opcode) { + case IB_WR_SEND: + case IB_WR_SEND_WITH_IMM: + if (wr->send_flags & IB_SEND_SOLICITED) + wqe->send.rdmaop = T3_SEND_WITH_SE; + else + wqe->send.rdmaop = T3_SEND; + wqe->send.rem_stag = 0; + break; +#if 0 /* Not currently supported */ + case TYPE_SEND_INVALIDATE: + case TYPE_SEND_INVALIDATE_IMMEDIATE: + wqe->send.rdmaop = T3_SEND_WITH_INV; + wqe->send.rem_stag = cpu_to_be32(wr->wr.rdma.rkey); + break; + case TYPE_SEND_SE_INVALIDATE: + wqe->send.rdmaop = T3_SEND_WITH_SE_INV; + wqe->send.rem_stag = cpu_to_be32(wr->wr.rdma.rkey); + break; +#endif + default: + break; + } + if (wr->num_sge > T3_MAX_SGE) + return -EINVAL; + wqe->send.reserved[0] = 0; + wqe->send.reserved[1] = 0; + wqe->send.reserved[2] = 0; + if (wr->opcode == IB_WR_SEND_WITH_IMM) { + plen = 4; + wqe->send.sgl[0].stag = wr->imm_data; + wqe->send.sgl[0].len = __constant_cpu_to_be32(0); + wqe->send.num_sgle = __constant_cpu_to_be32(0); + *flit_cnt = 5; + } else { + plen = 0; + for (i = 0; i < wr->num_sge; i++) { + if ((plen + wr->sg_list[i].length) < plen) { + return -EMSGSIZE; + } + plen += wr->sg_list[i].length; + wqe->send.sgl[i].stag = + cpu_to_be32(wr->sg_list[i].lkey); + wqe->send.sgl[i].len = + cpu_to_be32(wr->sg_list[i].length); + wqe->send.sgl[i].to = cpu_to_be64(wr->sg_list[i].addr); + } + wqe->send.num_sgle = cpu_to_be32(wr->num_sge); + *flit_cnt = 4 + ((wr->num_sge) << 1); + } + wqe->send.plen = cpu_to_be32(plen); + return 0; +} + +static inline int iwch_build_rdma_write(union t3_wr *wqe, struct ib_send_wr *wr, + u8 *flit_cnt) +{ + int i; + u32 plen; + if (wr->num_sge > T3_MAX_SGE) + return -EINVAL; + wqe->write.rdmaop = T3_RDMA_WRITE; + wqe->write.reserved[0] = 0; + wqe->write.reserved[1] = 0; + wqe->write.reserved[2] = 0; + wqe->write.stag_sink = cpu_to_be32(wr->wr.rdma.rkey); + wqe->write.to_sink = cpu_to_be64(wr->wr.rdma.remote_addr); + + if (wr->opcode == IB_WR_RDMA_WRITE_WITH_IMM) { + plen = 4; + wqe->write.sgl[0].stag = wr->imm_data; + wqe->write.sgl[0].len = __constant_cpu_to_be32(0); + wqe->write.num_sgle = __constant_cpu_to_be32(0); + *flit_cnt = 6; + } else { + plen = 0; + for (i = 0; i < wr->num_sge; i++) { + if ((plen + wr->sg_list[i].length) < plen) { + return -EMSGSIZE; + } + plen += wr->sg_list[i].length; + wqe->write.sgl[i].stag = + cpu_to_be32(wr->sg_list[i].lkey); + wqe->write.sgl[i].len = + cpu_to_be32(wr->sg_list[i].length); + wqe->write.sgl[i].to = + cpu_to_be64(wr->sg_list[i].addr); + } + wqe->write.num_sgle = cpu_to_be32(wr->num_sge); + *flit_cnt = 5 + ((wr->num_sge) << 1); + } + wqe->write.plen = cpu_to_be32(plen); + return 0; +} + +static inline int iwch_build_rdma_read(union t3_wr *wqe, struct ib_send_wr *wr, + u8 *flit_cnt) +{ + if (wr->num_sge > 1) + return -EINVAL; + wqe->read.rdmaop = T3_READ_REQ; + wqe->read.reserved[0] = 0; + wqe->read.reserved[1] = 0; + wqe->read.reserved[2] = 0; + wqe->read.rem_stag = cpu_to_be32(wr->wr.rdma.rkey); + wqe->read.rem_to = cpu_to_be64(wr->wr.rdma.remote_addr); + wqe->read.local_stag = cpu_to_be32(wr->sg_list[0].lkey); + wqe->read.local_len = cpu_to_be32(wr->sg_list[0].length); + wqe->read.local_to = cpu_to_be64(wr->sg_list[0].addr); + *flit_cnt = sizeof(struct t3_rdma_read_wr) >> 3; + return 0; +} + +/* + * TBD: this is going to be moved to firmware. Missing pdid/qpid check for now. + */ +static inline int iwch_sgl2pbl_map(struct iwch_dev *rhp, + struct ib_sge *sg_list, u32 num_sgle, + u32 * pbl_addr, u8 * page_size) +{ + int i; + struct iwch_mr *mhp; + u32 offset; + for (i = 0; i < num_sgle; i++) { + + mhp = get_mhp(rhp, (sg_list[i].lkey) >> 8); + if (!mhp) { + PDBG("%s %d\n", __FUNCTION__, __LINE__); + return -EIO; + } + if (!mhp->attr.state) { + PDBG("%s %d\n", __FUNCTION__, __LINE__); + return -EIO; + } + if (mhp->attr.zbva) { + PDBG("%s %d\n", __FUNCTION__, __LINE__); + return -EIO; + } + + if (sg_list[i].addr < mhp->attr.va_fbo) { + PDBG("%s %d\n", __FUNCTION__, __LINE__); + return -EINVAL; + } + if (sg_list[i].addr + ((u64) sg_list[i].length) < + sg_list[i].addr) { + PDBG("%s %d\n", __FUNCTION__, __LINE__); + return -EINVAL; + } + if (sg_list[i].addr + ((u64) sg_list[i].length) > + mhp->attr.va_fbo + ((u64) mhp->attr.len)) { + PDBG("%s %d\n", __FUNCTION__, __LINE__); + return -EINVAL; + } + offset = sg_list[i].addr - mhp->attr.va_fbo; + offset += ((u32) mhp->attr.va_fbo) % + (1UL << (12 + mhp->attr.page_size)); + pbl_addr[i] = ((mhp->attr.pbl_addr - + rhp->rdev.rnic_info.pbl_base) >> 3) + + (offset >> (12 + mhp->attr.page_size)); + page_size[i] = mhp->attr.page_size; + } + return 0; +} + +static inline int iwch_build_rdma_recv(struct iwch_dev *rhp, + union t3_wr *wqe, + struct ib_recv_wr *wr) +{ + int i, err = 0; + u32 pbl_addr[4]; + u8 page_size[4]; + if (wr->num_sge > T3_MAX_SGE) + return -EINVAL; + err = iwch_sgl2pbl_map(rhp, wr->sg_list, wr->num_sge, pbl_addr, + page_size); + if (err) + return err; + wqe->recv.pagesz[0] = page_size[0]; + wqe->recv.pagesz[1] = page_size[1]; + wqe->recv.pagesz[2] = page_size[2]; + wqe->recv.pagesz[3] = page_size[3]; + wqe->recv.num_sgle = cpu_to_be32(wr->num_sge); + for (i = 0; i < wr->num_sge; i++) { + wqe->recv.sgl[i].stag = cpu_to_be32(wr->sg_list[i].lkey); + wqe->recv.sgl[i].len = cpu_to_be32(wr->sg_list[i].length); + + /* to in the WQE == the offset into the page */ + wqe->recv.sgl[i].to = cpu_to_be64(((u32) wr->sg_list[i].addr) % + (1UL << (12 + page_size[i]))); + + /* pbl_addr is the adapters address in the PBL */ + wqe->recv.pbl_addr[i] = cpu_to_be32(pbl_addr[i]); + } + for (; i < T3_MAX_SGE; i++) { + wqe->recv.sgl[i].stag = 0; + wqe->recv.sgl[i].len = 0; + wqe->recv.sgl[i].to = 0; + wqe->recv.pbl_addr[i] = 0; + } + return 0; +} + +int iwch_post_send(struct ib_qp *ibqp, struct ib_send_wr *wr, + struct ib_send_wr **bad_wr) +{ + int err = 0; + u8 t3_wr_flit_cnt; + enum t3_wr_opcode t3_wr_opcode = 0; + enum t3_wr_flags t3_wr_flags; + struct iwch_qp *qhp; + u32 idx; + union t3_wr *wqe; + u32 num_wrs; + unsigned long flag; + struct t3_swsq *sqp; + + qhp = to_iwch_qp(ibqp); + spin_lock_irqsave(&qhp->lock, flag); + if (qhp->attr.state > IWCH_QP_STATE_RTS) { + spin_unlock_irqrestore(&qhp->lock, flag); + return -EINVAL; + } + num_wrs = Q_FREECNT(qhp->wq.sq_rptr, qhp->wq.sq_wptr, + qhp->wq.sq_size_log2); + if (num_wrs <= 0) { + spin_unlock_irqrestore(&qhp->lock, flag); + return -ENOMEM; + } + while (wr) { + if (num_wrs == 0) { + err = -ENOMEM; + *bad_wr = wr; + break; + } + idx = Q_PTR2IDX(qhp->wq.wptr, qhp->wq.size_log2); + wqe = (union t3_wr *) (qhp->wq.queue + idx); + t3_wr_flags = 0; + if (wr->send_flags & IB_SEND_SOLICITED) + t3_wr_flags |= T3_SOLICITED_EVENT_FLAG; + if (wr->send_flags & IB_SEND_FENCE) + t3_wr_flags |= T3_READ_FENCE_FLAG; + if (wr->send_flags & IB_SEND_SIGNALED) + t3_wr_flags |= T3_COMPLETION_FLAG; + sqp = qhp->wq.sq + + Q_PTR2IDX(qhp->wq.sq_wptr, qhp->wq.sq_size_log2); + switch (wr->opcode) { + case IB_WR_SEND: + case IB_WR_SEND_WITH_IMM: + t3_wr_opcode = T3_WR_SEND; + err = iwch_build_rdma_send(wqe, wr, &t3_wr_flit_cnt); + break; + case IB_WR_RDMA_WRITE: + case IB_WR_RDMA_WRITE_WITH_IMM: + t3_wr_opcode = T3_WR_WRITE; + err = iwch_build_rdma_write(wqe, wr, &t3_wr_flit_cnt); + break; + case IB_WR_RDMA_READ: + t3_wr_opcode = T3_WR_READ; + t3_wr_flags = 0; /* T3 reads are always signaled */ + err = iwch_build_rdma_read(wqe, wr, &t3_wr_flit_cnt); + if (err) + break; + sqp->read_len = wqe->read.local_len; + if (!qhp->wq.oldest_read) + qhp->wq.oldest_read = sqp; + break; + default: + PDBG("%s post of type=%d TBD!\n", __FUNCTION__, + wr->opcode); + err = -EINVAL; + } + if (err) { + *bad_wr = wr; + break; + } + wqe->send.wrid.id0.hi = qhp->wq.sq_wptr; + sqp->wr_id = wr->wr_id; + sqp->opcode = wr2opcode(t3_wr_opcode); + sqp->sq_wptr = qhp->wq.sq_wptr; + sqp->complete = 0; + sqp->signaled = (wr->send_flags & IB_SEND_SIGNALED); + + build_fw_riwrh((void *) wqe, t3_wr_opcode, t3_wr_flags, + Q_GENBIT(qhp->wq.wptr, qhp->wq.size_log2), + 0, t3_wr_flit_cnt); + PDBG("%s cookie 0x%llx wq idx 0x%x swsq idx %ld opcode %d\n", + __FUNCTION__, (unsigned long long) wr->wr_id, idx, + Q_PTR2IDX(qhp->wq.sq_wptr, qhp->wq.sq_size_log2), + sqp->opcode); + wr = wr->next; + num_wrs--; + ++(qhp->wq.wptr); + ++(qhp->wq.sq_wptr); + } + spin_unlock_irqrestore(&qhp->lock, flag); + ring_doorbell(qhp->wq.doorbell, qhp->wq.qpid); + return err; +} + +int iwch_post_receive(struct ib_qp *ibqp, struct ib_recv_wr *wr, + struct ib_recv_wr **bad_wr) +{ + int err = 0; + struct iwch_qp *qhp; + u32 idx; + union t3_wr *wqe; + u32 num_wrs; + unsigned long flag; + + qhp = to_iwch_qp(ibqp); + spin_lock_irqsave(&qhp->lock, flag); + if (qhp->attr.state > IWCH_QP_STATE_RTS) { + spin_unlock_irqrestore(&qhp->lock, flag); + return -EINVAL; + } + num_wrs = Q_FREECNT(qhp->wq.rq_rptr, qhp->wq.rq_wptr, + qhp->wq.rq_size_log2) - 1; + if (!wr) { + spin_unlock_irqrestore(&qhp->lock, flag); + return -EINVAL; + } + while (wr) { + idx = Q_PTR2IDX(qhp->wq.wptr, qhp->wq.size_log2); + wqe = (union t3_wr *) (qhp->wq.queue + idx); + if (num_wrs) + err = iwch_build_rdma_recv(qhp->rhp, wqe, wr); + else + err = -ENOMEM; + if (err) { + *bad_wr = wr; + break; + } + qhp->wq.rq[Q_PTR2IDX(qhp->wq.rq_wptr, qhp->wq.rq_size_log2)] = + wr->wr_id; + build_fw_riwrh((void *) wqe, T3_WR_RCV, T3_COMPLETION_FLAG, + Q_GENBIT(qhp->wq.wptr, qhp->wq.size_log2), + 0, sizeof(struct t3_receive_wr) >> 3); + PDBG("%s cookie 0x%llx idx 0x%x rq_wptr 0x%x rw_rptr 0x%x " + "wqe %p \n", __FUNCTION__, (unsigned long long) wr->wr_id, + idx, qhp->wq.rq_wptr, qhp->wq.rq_rptr, wqe); + ++(qhp->wq.rq_wptr); + ++(qhp->wq.wptr); + wr = wr->next; + num_wrs--; + } + spin_unlock_irqrestore(&qhp->lock, flag); + ring_doorbell(qhp->wq.doorbell, qhp->wq.qpid); + return err; +} + +int iwch_bind_mw(struct ib_qp *qp, + struct ib_mw *mw, + struct ib_mw_bind *mw_bind) +{ + struct iwch_dev *rhp; + struct iwch_mw *mhp; + struct iwch_qp *qhp; + union t3_wr *wqe; + u32 pbl_addr; + u8 page_size; + u32 num_wrs; + unsigned long flag; + struct ib_sge sgl; + int err=0; + enum t3_wr_flags t3_wr_flags; + u32 idx; + struct t3_swsq *sqp; + + qhp = to_iwch_qp(qp); + mhp = to_iwch_mw(mw); + rhp = qhp->rhp; + + spin_lock_irqsave(&qhp->lock, flag); + if (qhp->attr.state > IWCH_QP_STATE_RTS) { + spin_unlock_irqrestore(&qhp->lock, flag); + return -EINVAL; + } + num_wrs = Q_FREECNT(qhp->wq.sq_rptr, qhp->wq.sq_wptr, + qhp->wq.sq_size_log2); + if ((num_wrs) <= 0) { + spin_unlock_irqrestore(&qhp->lock, flag); + return -ENOMEM; + } + idx = Q_PTR2IDX(qhp->wq.wptr, qhp->wq.size_log2); + PDBG("%s: idx 0x%0x, mw 0x%p, mw_bind 0x%p\n", __FUNCTION__, idx, + mw, mw_bind); + wqe = (union t3_wr *) (qhp->wq.queue + idx); + + t3_wr_flags = 0; + if (mw_bind->send_flags & IB_SEND_SIGNALED) + t3_wr_flags = T3_COMPLETION_FLAG; + + sgl.addr = mw_bind->addr; + sgl.lkey = mw_bind->mr->lkey; + sgl.length = mw_bind->length; + wqe->bind.reserved = 0; + wqe->bind.type = T3_VA_BASED_TO; + + /* TBD: check perms */ + wqe->bind.perms = iwch_convert_access(mw_bind->mw_access_flags); + wqe->bind.mr_stag = cpu_to_be32(mw_bind->mr->lkey); + wqe->bind.mw_stag = cpu_to_be32(mw->rkey); + wqe->bind.mw_len = cpu_to_be32(mw_bind->length); + wqe->bind.mw_va = cpu_to_be64(mw_bind->addr); + err = iwch_sgl2pbl_map(rhp, &sgl, 1, &pbl_addr, &page_size); + if (err) { + spin_unlock_irqrestore(&qhp->lock, flag); + return err; + } + wqe->send.wrid.id0.hi = qhp->wq.sq_wptr; + sqp = qhp->wq.sq + Q_PTR2IDX(qhp->wq.sq_wptr, qhp->wq.sq_size_log2); + sqp->wr_id = mw_bind->wr_id; + sqp->opcode = T3_BIND_MW; + sqp->sq_wptr = qhp->wq.sq_wptr; + sqp->complete = 0; + sqp->signaled = (mw_bind->send_flags & IB_SEND_SIGNALED); + wqe->bind.mr_pbl_addr = cpu_to_be32(pbl_addr); + wqe->bind.mr_pagesz = page_size; + wqe->flit[T3_SQ_COOKIE_FLIT] = mw_bind->wr_id; + build_fw_riwrh((void *)wqe, T3_WR_BIND, t3_wr_flags, + Q_GENBIT(qhp->wq.wptr, qhp->wq.size_log2), 0, + sizeof(struct t3_bind_mw_wr) >> 3); + ++(qhp->wq.wptr); + ++(qhp->wq.sq_wptr); + spin_unlock_irqrestore(&qhp->lock, flag); + + ring_doorbell(qhp->wq.doorbell, qhp->wq.qpid); + + return err; +} + +static inline void build_term_codes(int t3err, u8 *layer_type, u8 *ecode, + int tagged) +{ + switch (t3err) { + case TPT_ERR_STAG: + if (tagged == 1) { + *layer_type = LAYER_DDP|DDP_TAGGED_ERR; + *ecode = DDPT_INV_STAG; + } else if (tagged == 2) { + *layer_type = LAYER_RDMAP|RDMAP_REMOTE_PROT; + *ecode = RDMAP_INV_STAG; + } + break; + case TPT_ERR_PDID: + case TPT_ERR_QPID: + case TPT_ERR_ACCESS: + if (tagged == 1) { + *layer_type = LAYER_DDP|DDP_TAGGED_ERR; + *ecode = DDPT_STAG_NOT_ASSOC; + } else if (tagged == 2) { + *layer_type = LAYER_RDMAP|RDMAP_REMOTE_PROT; + *ecode = RDMAP_STAG_NOT_ASSOC; + } + break; + case TPT_ERR_WRAP: + *layer_type = LAYER_RDMAP|RDMAP_REMOTE_PROT; + *ecode = RDMAP_TO_WRAP; + break; + case TPT_ERR_BOUND: + if (tagged == 1) { + *layer_type = LAYER_DDP|DDP_TAGGED_ERR; + *ecode = DDPT_BASE_BOUNDS; + } else if (tagged == 2) { + *layer_type = LAYER_RDMAP|RDMAP_REMOTE_PROT; + *ecode = RDMAP_BASE_BOUNDS; + } else { + *layer_type = LAYER_DDP|DDP_UNTAGGED_ERR; + *ecode = DDPU_MSG_TOOBIG; + } + break; + case TPT_ERR_INVALIDATE_SHARED_MR: + case TPT_ERR_INVALIDATE_MR_WITH_MW_BOUND: + *layer_type = LAYER_RDMAP|RDMAP_REMOTE_OP; + *ecode = RDMAP_CANT_INV_STAG; + break; + case TPT_ERR_ECC: + case TPT_ERR_ECC_PSTAG: + case TPT_ERR_INTERNAL_ERR: + *layer_type = LAYER_RDMAP|RDMAP_LOCAL_CATA; + *ecode = 0; + break; + case TPT_ERR_OUT_OF_RQE: + *layer_type = LAYER_DDP|DDP_UNTAGGED_ERR; + *ecode = DDPU_INV_MSN_NOBUF; + break; + case TPT_ERR_PBL_ADDR_BOUND: + *layer_type = LAYER_DDP|DDP_TAGGED_ERR; + *ecode = DDPT_BASE_BOUNDS; + break; + case TPT_ERR_CRC: + *layer_type = LAYER_MPA|DDP_LLP; + *ecode = MPA_CRC_ERR; + break; + case TPT_ERR_MARKER: + *layer_type = LAYER_MPA|DDP_LLP; + *ecode = MPA_MARKER_ERR; + break; + case TPT_ERR_PDU_LEN_ERR: + *layer_type = LAYER_DDP|DDP_UNTAGGED_ERR; + *ecode = DDPU_MSG_TOOBIG; + break; + case TPT_ERR_DDP_VERSION: + if (tagged) { + *layer_type = LAYER_DDP|DDP_TAGGED_ERR; + *ecode = DDPT_INV_VERS; + } else { + *layer_type = LAYER_DDP|DDP_UNTAGGED_ERR; + *ecode = DDPU_INV_VERS; + } + break; + case TPT_ERR_RDMA_VERSION: + *layer_type = LAYER_RDMAP|RDMAP_REMOTE_OP; + *ecode = RDMAP_INV_VERS; + break; + case TPT_ERR_OPCODE: + *layer_type = LAYER_RDMAP|RDMAP_REMOTE_OP; + *ecode = RDMAP_INV_OPCODE; + break; + case TPT_ERR_DDP_QUEUE_NUM: + *layer_type = LAYER_DDP|DDP_UNTAGGED_ERR; + *ecode = DDPU_INV_QN; + break; + case TPT_ERR_MSN: + case TPT_ERR_MSN_GAP: + case TPT_ERR_MSN_RANGE: + case TPT_ERR_IRD_OVERFLOW: + *layer_type = LAYER_DDP|DDP_UNTAGGED_ERR; + *ecode = DDPU_INV_MSN_RANGE; + break; + case TPT_ERR_TBIT: + *layer_type = LAYER_DDP|DDP_LOCAL_CATA; + *ecode = 0; + break; + case TPT_ERR_MO: + *layer_type = LAYER_DDP|DDP_UNTAGGED_ERR; + *ecode = DDPU_INV_MO; + break; + default: + *layer_type = LAYER_RDMAP|DDP_LOCAL_CATA; + *ecode = 0; + break; + } +} + +/* + * This posts a TERMINATE with layer=RDMA, type=catastrophic. + */ +int iwch_post_terminate(struct iwch_qp *qhp, struct respQ_msg_t *rsp_msg) +{ + union t3_wr *wqe; + struct terminate_message *term; + int status; + int tagged = 0; + struct sk_buff *skb; + + PDBG("%s %d\n", __FUNCTION__, __LINE__); + skb = alloc_skb(40, GFP_ATOMIC); + if (!skb) { + printk(KERN_ERR "%s cannot send TERMINATE!\n", __FUNCTION__); + return -ENOMEM; + } + wqe = (union t3_wr *)skb_put(skb, 40); + memset(wqe, 0, 40); + wqe->send.rdmaop = T3_TERMINATE; + + /* immediate data length */ + wqe->send.plen = htonl(4); + + /* immediate data starts here. */ + term = (struct terminate_message *)wqe->send.sgl; + if (rsp_msg) { + status = CQE_STATUS(rsp_msg->cqe); + if (CQE_OPCODE(rsp_msg->cqe) == T3_RDMA_WRITE) + tagged = 1; + if ((CQE_OPCODE(rsp_msg->cqe) == T3_READ_REQ) || + (CQE_OPCODE(rsp_msg->cqe) == T3_READ_RESP)) + tagged = 2; + } else { + status = TPT_ERR_INTERNAL_ERR; + } + build_term_codes(status, &term->layer_etype, &term->ecode, tagged); + build_fw_riwrh((void *)wqe, T3_WR_SEND, + T3_COMPLETION_FLAG | T3_NOTIFY_FLAG, 1, + qhp->ep->hwtid, 5); + skb->priority = CPL_PRIORITY_DATA; + return cxgb3_ofld_send(qhp->rhp->rdev.t3cdev_p, skb); +} + +/* + * Assumes qhp lock is held. + */ +static void __flush_qp(struct iwch_qp *qhp, unsigned long *flag) +{ + struct iwch_cq *rchp, *schp; + int count; + + rchp = get_chp(qhp->rhp, qhp->attr.rcq); + schp = get_chp(qhp->rhp, qhp->attr.scq); + + PDBG("%s qhp %p rchp %p schp %p\n", __FUNCTION__, qhp, rchp, schp); + /* take a ref on the qhp since we must release the lock */ + atomic_inc(&qhp->refcnt); + spin_unlock_irqrestore(&qhp->lock, *flag); + + /* locking heirarchy: cq lock first, then qp lock. */ + spin_lock_irqsave(&rchp->lock, *flag); + spin_lock(&qhp->lock); + cxio_flush_hw_cq(&rchp->cq); + cxio_count_rcqes(&rchp->cq, &qhp->wq, &count); + cxio_flush_rq(&qhp->wq, &rchp->cq, count); + spin_unlock(&qhp->lock); + spin_unlock_irqrestore(&rchp->lock, *flag); + + /* locking heirarchy: cq lock first, then qp lock. */ + spin_lock_irqsave(&schp->lock, *flag); + spin_lock(&qhp->lock); + cxio_flush_hw_cq(&schp->cq); + cxio_count_scqes(&schp->cq, &qhp->wq, &count); + cxio_flush_sq(&qhp->wq, &schp->cq, count); + spin_unlock(&qhp->lock); + spin_unlock_irqrestore(&schp->lock, *flag); + + /* deref */ + if (atomic_dec_and_test(&qhp->refcnt)) + wake_up(&qhp->wait); + + spin_lock_irqsave(&qhp->lock, *flag); +} + +static inline void flush_qp(struct iwch_qp *qhp, unsigned long *flag) +{ + if (t3b_device(qhp->rhp)) + cxio_set_wq_in_error(&qhp->wq); + else + __flush_qp(qhp, flag); +} + + +/* + * Return non zero if at least one RECV was pre-posted. + */ +static inline int rqes_posted(struct iwch_qp *qhp) +{ + return fw_riwrh_opcode((struct fw_riwrh *)qhp->wq.queue) == T3_WR_RCV; +} + +static int rdma_init(struct iwch_dev *rhp, struct iwch_qp *qhp, + enum iwch_qp_attr_mask mask, + struct iwch_qp_attributes *attrs) +{ + struct t3_rdma_init_attr init_attr; + int ret; + + init_attr.tid = qhp->ep->hwtid; + init_attr.qpid = qhp->wq.qpid; + init_attr.pdid = qhp->attr.pd; + init_attr.scqid = qhp->attr.scq; + init_attr.rcqid = qhp->attr.rcq; + init_attr.rq_addr = qhp->wq.rq_addr; + init_attr.rq_size = 1 << qhp->wq.rq_size_log2; + init_attr.mpaattrs = uP_RI_MPA_IETF_ENABLE | + qhp->attr.mpa_attr.recv_marker_enabled | + (qhp->attr.mpa_attr.xmit_marker_enabled << 1) | + (qhp->attr.mpa_attr.crc_enabled << 2); + + /* + * XXX - The IWCM doesn't quite handle getting these + * attrs set before going into RTS. For now, just turn + * them on always... + */ +#if 0 + init_attr.qpcaps = qhp->attr.enableRdmaRead | + (qhp->attr.enableRdmaWrite << 1) | + (qhp->attr.enableBind << 2) | + (qhp->attr.enable_stag0_fastreg << 3) | + (qhp->attr.enable_stag0_fastreg << 4); +#else + init_attr.qpcaps = 0x1f; +#endif + init_attr.tcp_emss = qhp->ep->emss; + init_attr.ord = qhp->attr.max_ord; + init_attr.ird = qhp->attr.max_ird; + init_attr.qp_dma_addr = qhp->wq.dma_addr; + init_attr.qp_dma_size = (1UL << qhp->wq.size_log2); + init_attr.flags = rqes_posted(qhp) ? RECVS_POSTED : 0; + PDBG("%s init_attr.rq_addr 0x%x init_attr.rq_size = %d " + "flags 0x%x qpcaps 0x%x\n", __FUNCTION__, + init_attr.rq_addr, init_attr.rq_size, + init_attr.flags, init_attr.qpcaps); + ret = cxio_rdma_init(&rhp->rdev, &init_attr); + PDBG("%s ret %d\n", __FUNCTION__, ret); + return ret; +} + +int iwch_modify_qp(struct iwch_dev *rhp, struct iwch_qp *qhp, + enum iwch_qp_attr_mask mask, + struct iwch_qp_attributes *attrs, + int internal) +{ + int ret = 0; + struct iwch_qp_attributes newattr = qhp->attr; + unsigned long flag; + int disconnect = 0; + int terminate = 0; + int abort = 0; + int free = 0; + struct iwch_ep *ep = NULL; + + PDBG("%s qhp %p qpid 0x%x ep %p state %d -> %d\n", __FUNCTION__, + qhp, qhp->wq.qpid, qhp->ep, qhp->attr.state, + (mask & IWCH_QP_ATTR_NEXT_STATE) ? attrs->next_state : -1); + + spin_lock_irqsave(&qhp->lock, flag); + + /* Process attr changes if in IDLE */ + if (mask & IWCH_QP_ATTR_VALID_MODIFY) { + if (qhp->attr.state != IWCH_QP_STATE_IDLE) { + ret = -EIO; + goto out; + } + if (mask & IWCH_QP_ATTR_ENABLE_RDMA_READ) + newattr.enable_rdma_read = attrs->enable_rdma_read; + if (mask & IWCH_QP_ATTR_ENABLE_RDMA_WRITE) + newattr.enable_rdma_write = attrs->enable_rdma_write; + if (mask & IWCH_QP_ATTR_ENABLE_RDMA_BIND) + newattr.enable_bind = attrs->enable_bind; + if (mask & IWCH_QP_ATTR_MAX_ORD) { + if (attrs->max_ord > + rhp->attr.max_rdma_read_qp_depth) { + ret = -EINVAL; + goto out; + } + newattr.max_ord = attrs->max_ord; + } + if (mask & IWCH_QP_ATTR_MAX_IRD) { + if (attrs->max_ird > + rhp->attr.max_rdma_reads_per_qp) { + ret = -EINVAL; + goto out; + } + newattr.max_ird = attrs->max_ird; + } + qhp->attr = newattr; + } + + if (!(mask & IWCH_QP_ATTR_NEXT_STATE)) + goto out; + if (qhp->attr.state == attrs->next_state) + goto out; + + switch (qhp->attr.state) { + case IWCH_QP_STATE_IDLE: + switch (attrs->next_state) { + case IWCH_QP_STATE_RTS: + if (!(mask & IWCH_QP_ATTR_LLP_STREAM_HANDLE)) { + ret = -EINVAL; + goto out; + } + if (!(mask & IWCH_QP_ATTR_MPA_ATTR)) { + ret = -EINVAL; + goto out; + } + qhp->attr.mpa_attr = attrs->mpa_attr; + qhp->attr.llp_stream_handle = attrs->llp_stream_handle; + qhp->ep = qhp->attr.llp_stream_handle; + qhp->attr.state = IWCH_QP_STATE_RTS; + + /* + * Ref the endpoint here and deref when we + * disassociate the endpoint from the QP. This + * happens in CLOSING->IDLE transition or *->ERROR + * transition. + */ + get_ep(&qhp->ep->com); + spin_unlock_irqrestore(&qhp->lock, flag); + ret = rdma_init(rhp, qhp, mask, attrs); + spin_lock_irqsave(&qhp->lock, flag); + if (ret) + goto err; + break; + case IWCH_QP_STATE_ERROR: + qhp->attr.state = IWCH_QP_STATE_ERROR; + flush_qp(qhp, &flag); + break; + default: + ret = -EINVAL; + goto out; + } + break; + case IWCH_QP_STATE_RTS: + switch (attrs->next_state) { + case IWCH_QP_STATE_CLOSING: + BUG_ON(atomic_read(&qhp->ep->com.kref.refcount) < 2); + qhp->attr.state = IWCH_QP_STATE_CLOSING; + if (!internal) { + abort=0; + disconnect = 1; + ep = qhp->ep; + } + break; + case IWCH_QP_STATE_TERMINATE: + qhp->attr.state = IWCH_QP_STATE_TERMINATE; + if (!internal) + terminate = 1; + break; + case IWCH_QP_STATE_ERROR: + qhp->attr.state = IWCH_QP_STATE_ERROR; + if (!internal) { + abort=1; + disconnect = 1; + ep = qhp->ep; + } + goto err; + break; + default: + ret = -EINVAL; + goto out; + } + break; + case IWCH_QP_STATE_CLOSING: + if (!internal) { + ret = -EINVAL; + goto out; + } + switch (attrs->next_state) { + case IWCH_QP_STATE_IDLE: + qhp->attr.state = IWCH_QP_STATE_IDLE; + qhp->attr.llp_stream_handle = NULL; + put_ep(&qhp->ep->com); + qhp->ep = NULL; + wake_up(&qhp->wait); + break; + case IWCH_QP_STATE_ERROR: + goto err; + default: + ret = -EINVAL; + goto err; + } + break; + case IWCH_QP_STATE_ERROR: + if (attrs->next_state != IWCH_QP_STATE_IDLE) { + ret = -EINVAL; + goto out; + } + + if (!Q_EMPTY(qhp->wq.sq_rptr, qhp->wq.sq_wptr) || + !Q_EMPTY(qhp->wq.rq_rptr, qhp->wq.rq_wptr)) { + ret = -EINVAL; + goto out; + } + qhp->attr.state = IWCH_QP_STATE_IDLE; + memset(&qhp->attr, 0, sizeof(qhp->attr)); + break; + case IWCH_QP_STATE_TERMINATE: + if (!internal) { + ret = -EINVAL; + goto out; + } + goto err; + break; + default: + printk(KERN_ERR "%s in a bad state %d\n", + __FUNCTION__, qhp->attr.state); + ret = -EINVAL; + goto err; + break; + } + goto out; +err: + PDBG("%s disassociating ep %p qpid 0x%x\n", __FUNCTION__, qhp->ep, + qhp->wq.qpid); + + /* disassociate the LLP connection */ + qhp->attr.llp_stream_handle = NULL; + ep = qhp->ep; + qhp->ep = NULL; + qhp->attr.state = IWCH_QP_STATE_ERROR; + free=1; + wake_up(&qhp->wait); + BUG_ON(!ep); + flush_qp(qhp, &flag); +out: + spin_unlock_irqrestore(&qhp->lock, flag); + + if (terminate) + iwch_post_terminate(qhp, NULL); + + /* + * If disconnect is 1, then we need to initiate a disconnect + * on the EP. This can be a normal close (RTS->CLOSING) or + * an abnormal close (RTS/CLOSING->ERROR). + */ + if (disconnect) + iwch_ep_disconnect(ep, abort, GFP_KERNEL); + + /* + * If free is 1, then we've disassociated the EP from the QP + * and we need to dereference the EP. + */ + if (free) + put_ep(&ep->com); + + PDBG("%s exit state %d\n", __FUNCTION__, qhp->attr.state); + return ret; +} + +static int quiesce_qp(struct iwch_qp *qhp) +{ + spin_lock_irq(&qhp->lock); + iwch_quiesce_tid(qhp->ep); + qhp->flags |= QP_QUIESCED; + spin_unlock_irq(&qhp->lock); + return 0; +} + +static int resume_qp(struct iwch_qp *qhp) +{ + spin_lock_irq(&qhp->lock); + iwch_resume_tid(qhp->ep); + qhp->flags &= ~QP_QUIESCED; + spin_unlock_irq(&qhp->lock); + return 0; +} + +int iwch_quiesce_qps(struct iwch_cq *chp) +{ + int i; + struct iwch_qp *qhp; + + for (i=0; i < T3_MAX_NUM_QP; i++) { + qhp = get_qhp(chp->rhp, i); + if (!qhp) + continue; + if ((qhp->attr.rcq == chp->cq.cqid) && !qp_quiesced(qhp)) { + quiesce_qp(qhp); + continue; + } + if ((qhp->attr.scq == chp->cq.cqid) && !qp_quiesced(qhp)) + quiesce_qp(qhp); + } + return 0; +} + +int iwch_resume_qps(struct iwch_cq *chp) +{ + int i; + struct iwch_qp *qhp; + + for (i=0; i < T3_MAX_NUM_QP; i++) { + qhp = get_qhp(chp->rhp, i); + if (!qhp) + continue; + if ((qhp->attr.rcq == chp->cq.cqid) && qp_quiesced(qhp)) { + resume_qp(qhp); + continue; + } + if ((qhp->attr.scq == chp->cq.cqid) && qp_quiesced(qhp)) + resume_qp(qhp); + } + return 0; +} diff --git a/drivers/infiniband/hw/cxgb3/iwch_user.h b/drivers/infiniband/hw/cxgb3/iwch_user.h new file mode 100644 index 0000000..c4e7fbe --- /dev/null +++ b/drivers/infiniband/hw/cxgb3/iwch_user.h @@ -0,0 +1,67 @@ +/* + * Copyright (c) 2006 Chelsio, Inc. All rights reserved. + * Copyright (c) 2006 Open Grid Computing, Inc. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +#ifndef __IWCH_USER_H__ +#define __IWCH_USER_H__ + +#define IWCH_UVERBS_ABI_VERSION 1 + +/* + * Make sure that all structs defined in this file remain laid out so + * that they pack the same way on 32-bit and 64-bit architectures (to + * avoid incompatibility between 32-bit userspace and 64-bit kernels). + * In particular do not use pointer types -- pass pointers in __u64 + * instead. + */ +struct iwch_create_cq_req { + __u64 user_rptr_addr; +}; + +struct iwch_create_cq_resp { + __u64 key; + __u32 cqid; + __u32 size_log2; +}; + +struct iwch_create_qp_resp { + __u64 key; + __u64 db_key; + __u32 qpid; + __u32 size_log2; + __u32 sq_size_log2; + __u32 rq_size_log2; +}; + +struct iwch_reg_user_mr_resp { + __u32 pbl_addr; +}; +#endif diff --git a/drivers/infiniband/hw/cxgb3/tcb.h b/drivers/infiniband/hw/cxgb3/tcb.h new file mode 100644 index 0000000..c702dc1 --- /dev/null +++ b/drivers/infiniband/hw/cxgb3/tcb.h @@ -0,0 +1,632 @@ +/* + * Copyright (c) 2007 Chelsio, Inc. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +#ifndef _TCB_DEFS_H +#define _TCB_DEFS_H + +#define W_TCB_T_STATE 0 +#define S_TCB_T_STATE 0 +#define M_TCB_T_STATE 0xfULL +#define V_TCB_T_STATE(x) ((x) << S_TCB_T_STATE) + +#define W_TCB_TIMER 0 +#define S_TCB_TIMER 4 +#define M_TCB_TIMER 0x1ULL +#define V_TCB_TIMER(x) ((x) << S_TCB_TIMER) + +#define W_TCB_DACK_TIMER 0 +#define S_TCB_DACK_TIMER 5 +#define M_TCB_DACK_TIMER 0x1ULL +#define V_TCB_DACK_TIMER(x) ((x) << S_TCB_DACK_TIMER) + +#define W_TCB_DEL_FLAG 0 +#define S_TCB_DEL_FLAG 6 +#define M_TCB_DEL_FLAG 0x1ULL +#define V_TCB_DEL_FLAG(x) ((x) << S_TCB_DEL_FLAG) + +#define W_TCB_L2T_IX 0 +#define S_TCB_L2T_IX 7 +#define M_TCB_L2T_IX 0x7ffULL +#define V_TCB_L2T_IX(x) ((x) << S_TCB_L2T_IX) + +#define W_TCB_SMAC_SEL 0 +#define S_TCB_SMAC_SEL 18 +#define M_TCB_SMAC_SEL 0x3ULL +#define V_TCB_SMAC_SEL(x) ((x) << S_TCB_SMAC_SEL) + +#define W_TCB_TOS 0 +#define S_TCB_TOS 20 +#define M_TCB_TOS 0x3fULL +#define V_TCB_TOS(x) ((x) << S_TCB_TOS) + +#define W_TCB_MAX_RT 0 +#define S_TCB_MAX_RT 26 +#define M_TCB_MAX_RT 0xfULL +#define V_TCB_MAX_RT(x) ((x) << S_TCB_MAX_RT) + +#define W_TCB_T_RXTSHIFT 0 +#define S_TCB_T_RXTSHIFT 30 +#define M_TCB_T_RXTSHIFT 0xfULL +#define V_TCB_T_RXTSHIFT(x) ((x) << S_TCB_T_RXTSHIFT) + +#define W_TCB_T_DUPACKS 1 +#define S_TCB_T_DUPACKS 2 +#define M_TCB_T_DUPACKS 0xfULL +#define V_TCB_T_DUPACKS(x) ((x) << S_TCB_T_DUPACKS) + +#define W_TCB_T_MAXSEG 1 +#define S_TCB_T_MAXSEG 6 +#define M_TCB_T_MAXSEG 0xfULL +#define V_TCB_T_MAXSEG(x) ((x) << S_TCB_T_MAXSEG) + +#define W_TCB_T_FLAGS1 1 +#define S_TCB_T_FLAGS1 10 +#define M_TCB_T_FLAGS1 0xffffffffULL +#define V_TCB_T_FLAGS1(x) ((x) << S_TCB_T_FLAGS1) + +#define W_TCB_T_MIGRATION 1 +#define S_TCB_T_MIGRATION 20 +#define M_TCB_T_MIGRATION 0x1ULL +#define V_TCB_T_MIGRATION(x) ((x) << S_TCB_T_MIGRATION) + +#define W_TCB_T_FLAGS2 2 +#define S_TCB_T_FLAGS2 10 +#define M_TCB_T_FLAGS2 0x7fULL +#define V_TCB_T_FLAGS2(x) ((x) << S_TCB_T_FLAGS2) + +#define W_TCB_SND_SCALE 2 +#define S_TCB_SND_SCALE 17 +#define M_TCB_SND_SCALE 0xfULL +#define V_TCB_SND_SCALE(x) ((x) << S_TCB_SND_SCALE) + +#define W_TCB_RCV_SCALE 2 +#define S_TCB_RCV_SCALE 21 +#define M_TCB_RCV_SCALE 0xfULL +#define V_TCB_RCV_SCALE(x) ((x) << S_TCB_RCV_SCALE) + +#define W_TCB_SND_UNA_RAW 2 +#define S_TCB_SND_UNA_RAW 25 +#define M_TCB_SND_UNA_RAW 0x7ffffffULL +#define V_TCB_SND_UNA_RAW(x) ((x) << S_TCB_SND_UNA_RAW) + +#define W_TCB_SND_NXT_RAW 3 +#define S_TCB_SND_NXT_RAW 20 +#define M_TCB_SND_NXT_RAW 0x7ffffffULL +#define V_TCB_SND_NXT_RAW(x) ((x) << S_TCB_SND_NXT_RAW) + +#define W_TCB_RCV_NXT 4 +#define S_TCB_RCV_NXT 15 +#define M_TCB_RCV_NXT 0xffffffffULL +#define V_TCB_RCV_NXT(x) ((x) << S_TCB_RCV_NXT) + +#define W_TCB_RCV_ADV 5 +#define S_TCB_RCV_ADV 15 +#define M_TCB_RCV_ADV 0xffffULL +#define V_TCB_RCV_ADV(x) ((x) << S_TCB_RCV_ADV) + +#define W_TCB_SND_MAX_RAW 5 +#define S_TCB_SND_MAX_RAW 31 +#define M_TCB_SND_MAX_RAW 0x7ffffffULL +#define V_TCB_SND_MAX_RAW(x) ((x) << S_TCB_SND_MAX_RAW) + +#define W_TCB_SND_CWND 6 +#define S_TCB_SND_CWND 26 +#define M_TCB_SND_CWND 0x7ffffffULL +#define V_TCB_SND_CWND(x) ((x) << S_TCB_SND_CWND) + +#define W_TCB_SND_SSTHRESH 7 +#define S_TCB_SND_SSTHRESH 21 +#define M_TCB_SND_SSTHRESH 0x7ffffffULL +#define V_TCB_SND_SSTHRESH(x) ((x) << S_TCB_SND_SSTHRESH) + +#define W_TCB_T_RTT_TS_RECENT_AGE 8 +#define S_TCB_T_RTT_TS_RECENT_AGE 16 +#define M_TCB_T_RTT_TS_RECENT_AGE 0xffffffffULL +#define V_TCB_T_RTT_TS_RECENT_AGE(x) ((x) << S_TCB_T_RTT_TS_RECENT_AGE) + +#define W_TCB_T_RTSEQ_RECENT 9 +#define S_TCB_T_RTSEQ_RECENT 16 +#define M_TCB_T_RTSEQ_RECENT 0xffffffffULL +#define V_TCB_T_RTSEQ_RECENT(x) ((x) << S_TCB_T_RTSEQ_RECENT) + +#define W_TCB_T_SRTT 10 +#define S_TCB_T_SRTT 16 +#define M_TCB_T_SRTT 0xffffULL +#define V_TCB_T_SRTT(x) ((x) << S_TCB_T_SRTT) + +#define W_TCB_T_RTTVAR 11 +#define S_TCB_T_RTTVAR 0 +#define M_TCB_T_RTTVAR 0xffffULL +#define V_TCB_T_RTTVAR(x) ((x) << S_TCB_T_RTTVAR) + +#define W_TCB_TS_LAST_ACK_SENT_RAW 11 +#define S_TCB_TS_LAST_ACK_SENT_RAW 16 +#define M_TCB_TS_LAST_ACK_SENT_RAW 0x7ffffffULL +#define V_TCB_TS_LAST_ACK_SENT_RAW(x) ((x) << S_TCB_TS_LAST_ACK_SENT_RAW) + +#define W_TCB_DIP 12 +#define S_TCB_DIP 11 +#define M_TCB_DIP 0xffffffffULL +#define V_TCB_DIP(x) ((x) << S_TCB_DIP) + +#define W_TCB_SIP 13 +#define S_TCB_SIP 11 +#define M_TCB_SIP 0xffffffffULL +#define V_TCB_SIP(x) ((x) << S_TCB_SIP) + +#define W_TCB_DP 14 +#define S_TCB_DP 11 +#define M_TCB_DP 0xffffULL +#define V_TCB_DP(x) ((x) << S_TCB_DP) + +#define W_TCB_SP 14 +#define S_TCB_SP 27 +#define M_TCB_SP 0xffffULL +#define V_TCB_SP(x) ((x) << S_TCB_SP) + +#define W_TCB_TIMESTAMP 15 +#define S_TCB_TIMESTAMP 11 +#define M_TCB_TIMESTAMP 0xffffffffULL +#define V_TCB_TIMESTAMP(x) ((x) << S_TCB_TIMESTAMP) + +#define W_TCB_TIMESTAMP_OFFSET 16 +#define S_TCB_TIMESTAMP_OFFSET 11 +#define M_TCB_TIMESTAMP_OFFSET 0xfULL +#define V_TCB_TIMESTAMP_OFFSET(x) ((x) << S_TCB_TIMESTAMP_OFFSET) + +#define W_TCB_TX_MAX 16 +#define S_TCB_TX_MAX 15 +#define M_TCB_TX_MAX 0xffffffffULL +#define V_TCB_TX_MAX(x) ((x) << S_TCB_TX_MAX) + +#define W_TCB_TX_HDR_PTR_RAW 17 +#define S_TCB_TX_HDR_PTR_RAW 15 +#define M_TCB_TX_HDR_PTR_RAW 0x1ffffULL +#define V_TCB_TX_HDR_PTR_RAW(x) ((x) << S_TCB_TX_HDR_PTR_RAW) + +#define W_TCB_TX_LAST_PTR_RAW 18 +#define S_TCB_TX_LAST_PTR_RAW 0 +#define M_TCB_TX_LAST_PTR_RAW 0x1ffffULL +#define V_TCB_TX_LAST_PTR_RAW(x) ((x) << S_TCB_TX_LAST_PTR_RAW) + +#define W_TCB_TX_COMPACT 18 +#define S_TCB_TX_COMPACT 17 +#define M_TCB_TX_COMPACT 0x1ULL +#define V_TCB_TX_COMPACT(x) ((x) << S_TCB_TX_COMPACT) + +#define W_TCB_RX_COMPACT 18 +#define S_TCB_RX_COMPACT 18 +#define M_TCB_RX_COMPACT 0x1ULL +#define V_TCB_RX_COMPACT(x) ((x) << S_TCB_RX_COMPACT) + +#define W_TCB_RCV_WND 18 +#define S_TCB_RCV_WND 19 +#define M_TCB_RCV_WND 0x7ffffffULL +#define V_TCB_RCV_WND(x) ((x) << S_TCB_RCV_WND) + +#define W_TCB_RX_HDR_OFFSET 19 +#define S_TCB_RX_HDR_OFFSET 14 +#define M_TCB_RX_HDR_OFFSET 0x7ffffffULL +#define V_TCB_RX_HDR_OFFSET(x) ((x) << S_TCB_RX_HDR_OFFSET) + +#define W_TCB_RX_FRAG0_START_IDX_RAW 20 +#define S_TCB_RX_FRAG0_START_IDX_RAW 9 +#define M_TCB_RX_FRAG0_START_IDX_RAW 0x7ffffffULL +#define V_TCB_RX_FRAG0_START_IDX_RAW(x) ((x) << S_TCB_RX_FRAG0_START_IDX_RAW) + +#define W_TCB_RX_FRAG1_START_IDX_OFFSET 21 +#define S_TCB_RX_FRAG1_START_IDX_OFFSET 4 +#define M_TCB_RX_FRAG1_START_IDX_OFFSET 0x7ffffffULL +#define V_TCB_RX_FRAG1_START_IDX_OFFSET(x) ((x) << S_TCB_RX_FRAG1_START_IDX_OFFSET) + +#define W_TCB_RX_FRAG0_LEN 21 +#define S_TCB_RX_FRAG0_LEN 31 +#define M_TCB_RX_FRAG0_LEN 0x7ffffffULL +#define V_TCB_RX_FRAG0_LEN(x) ((x) << S_TCB_RX_FRAG0_LEN) + +#define W_TCB_RX_FRAG1_LEN 22 +#define S_TCB_RX_FRAG1_LEN 26 +#define M_TCB_RX_FRAG1_LEN 0x7ffffffULL +#define V_TCB_RX_FRAG1_LEN(x) ((x) << S_TCB_RX_FRAG1_LEN) + +#define W_TCB_NEWRENO_RECOVER 23 +#define S_TCB_NEWRENO_RECOVER 21 +#define M_TCB_NEWRENO_RECOVER 0x7ffffffULL +#define V_TCB_NEWRENO_RECOVER(x) ((x) << S_TCB_NEWRENO_RECOVER) + +#define W_TCB_PDU_HAVE_LEN 24 +#define S_TCB_PDU_HAVE_LEN 16 +#define M_TCB_PDU_HAVE_LEN 0x1ULL +#define V_TCB_PDU_HAVE_LEN(x) ((x) << S_TCB_PDU_HAVE_LEN) + +#define W_TCB_PDU_LEN 24 +#define S_TCB_PDU_LEN 17 +#define M_TCB_PDU_LEN 0xffffULL +#define V_TCB_PDU_LEN(x) ((x) << S_TCB_PDU_LEN) + +#define W_TCB_RX_QUIESCE 25 +#define S_TCB_RX_QUIESCE 1 +#define M_TCB_RX_QUIESCE 0x1ULL +#define V_TCB_RX_QUIESCE(x) ((x) << S_TCB_RX_QUIESCE) + +#define W_TCB_RX_PTR_RAW 25 +#define S_TCB_RX_PTR_RAW 2 +#define M_TCB_RX_PTR_RAW 0x1ffffULL +#define V_TCB_RX_PTR_RAW(x) ((x) << S_TCB_RX_PTR_RAW) + +#define W_TCB_CPU_NO 25 +#define S_TCB_CPU_NO 19 +#define M_TCB_CPU_NO 0x7fULL +#define V_TCB_CPU_NO(x) ((x) << S_TCB_CPU_NO) + +#define W_TCB_ULP_TYPE 25 +#define S_TCB_ULP_TYPE 26 +#define M_TCB_ULP_TYPE 0xfULL +#define V_TCB_ULP_TYPE(x) ((x) << S_TCB_ULP_TYPE) + +#define W_TCB_RX_FRAG1_PTR_RAW 25 +#define S_TCB_RX_FRAG1_PTR_RAW 30 +#define M_TCB_RX_FRAG1_PTR_RAW 0x1ffffULL +#define V_TCB_RX_FRAG1_PTR_RAW(x) ((x) << S_TCB_RX_FRAG1_PTR_RAW) + +#define W_TCB_RX_FRAG2_START_IDX_OFFSET_RAW 26 +#define S_TCB_RX_FRAG2_START_IDX_OFFSET_RAW 15 +#define M_TCB_RX_FRAG2_START_IDX_OFFSET_RAW 0x7ffffffULL +#define V_TCB_RX_FRAG2_START_IDX_OFFSET_RAW(x) ((x) << S_TCB_RX_FRAG2_START_IDX_OFFSET_RAW) + +#define W_TCB_RX_FRAG2_PTR_RAW 27 +#define S_TCB_RX_FRAG2_PTR_RAW 10 +#define M_TCB_RX_FRAG2_PTR_RAW 0x1ffffULL +#define V_TCB_RX_FRAG2_PTR_RAW(x) ((x) << S_TCB_RX_FRAG2_PTR_RAW) + +#define W_TCB_RX_FRAG2_LEN_RAW 27 +#define S_TCB_RX_FRAG2_LEN_RAW 27 +#define M_TCB_RX_FRAG2_LEN_RAW 0x7ffffffULL +#define V_TCB_RX_FRAG2_LEN_RAW(x) ((x) << S_TCB_RX_FRAG2_LEN_RAW) + +#define W_TCB_RX_FRAG3_PTR_RAW 28 +#define S_TCB_RX_FRAG3_PTR_RAW 22 +#define M_TCB_RX_FRAG3_PTR_RAW 0x1ffffULL +#define V_TCB_RX_FRAG3_PTR_RAW(x) ((x) << S_TCB_RX_FRAG3_PTR_RAW) + +#define W_TCB_RX_FRAG3_LEN_RAW 29 +#define S_TCB_RX_FRAG3_LEN_RAW 7 +#define M_TCB_RX_FRAG3_LEN_RAW 0x7ffffffULL +#define V_TCB_RX_FRAG3_LEN_RAW(x) ((x) << S_TCB_RX_FRAG3_LEN_RAW) + +#define W_TCB_RX_FRAG3_START_IDX_OFFSET_RAW 30 +#define S_TCB_RX_FRAG3_START_IDX_OFFSET_RAW 2 +#define M_TCB_RX_FRAG3_START_IDX_OFFSET_RAW 0x7ffffffULL +#define V_TCB_RX_FRAG3_START_IDX_OFFSET_RAW(x) ((x) << S_TCB_RX_FRAG3_START_IDX_OFFSET_RAW) + +#define W_TCB_PDU_HDR_LEN 30 +#define S_TCB_PDU_HDR_LEN 29 +#define M_TCB_PDU_HDR_LEN 0xffULL +#define V_TCB_PDU_HDR_LEN(x) ((x) << S_TCB_PDU_HDR_LEN) + +#define W_TCB_SLUSH1 31 +#define S_TCB_SLUSH1 5 +#define M_TCB_SLUSH1 0x7ffffULL +#define V_TCB_SLUSH1(x) ((x) << S_TCB_SLUSH1) + +#define W_TCB_ULP_RAW 31 +#define S_TCB_ULP_RAW 24 +#define M_TCB_ULP_RAW 0xffULL +#define V_TCB_ULP_RAW(x) ((x) << S_TCB_ULP_RAW) + +#define W_TCB_DDP_RDMAP_VERSION 25 +#define S_TCB_DDP_RDMAP_VERSION 30 +#define M_TCB_DDP_RDMAP_VERSION 0x1ULL +#define V_TCB_DDP_RDMAP_VERSION(x) ((x) << S_TCB_DDP_RDMAP_VERSION) + +#define W_TCB_MARKER_ENABLE_RX 25 +#define S_TCB_MARKER_ENABLE_RX 31 +#define M_TCB_MARKER_ENABLE_RX 0x1ULL +#define V_TCB_MARKER_ENABLE_RX(x) ((x) << S_TCB_MARKER_ENABLE_RX) + +#define W_TCB_MARKER_ENABLE_TX 26 +#define S_TCB_MARKER_ENABLE_TX 0 +#define M_TCB_MARKER_ENABLE_TX 0x1ULL +#define V_TCB_MARKER_ENABLE_TX(x) ((x) << S_TCB_MARKER_ENABLE_TX) + +#define W_TCB_CRC_ENABLE 26 +#define S_TCB_CRC_ENABLE 1 +#define M_TCB_CRC_ENABLE 0x1ULL +#define V_TCB_CRC_ENABLE(x) ((x) << S_TCB_CRC_ENABLE) + +#define W_TCB_IRS_ULP 26 +#define S_TCB_IRS_ULP 2 +#define M_TCB_IRS_ULP 0x1ffULL +#define V_TCB_IRS_ULP(x) ((x) << S_TCB_IRS_ULP) + +#define W_TCB_ISS_ULP 26 +#define S_TCB_ISS_ULP 11 +#define M_TCB_ISS_ULP 0x1ffULL +#define V_TCB_ISS_ULP(x) ((x) << S_TCB_ISS_ULP) + +#define W_TCB_TX_PDU_LEN 26 +#define S_TCB_TX_PDU_LEN 20 +#define M_TCB_TX_PDU_LEN 0x3fffULL +#define V_TCB_TX_PDU_LEN(x) ((x) << S_TCB_TX_PDU_LEN) + +#define W_TCB_TX_PDU_OUT 27 +#define S_TCB_TX_PDU_OUT 2 +#define M_TCB_TX_PDU_OUT 0x1ULL +#define V_TCB_TX_PDU_OUT(x) ((x) << S_TCB_TX_PDU_OUT) + +#define W_TCB_CQ_IDX_SQ 27 +#define S_TCB_CQ_IDX_SQ 3 +#define M_TCB_CQ_IDX_SQ 0xffffULL +#define V_TCB_CQ_IDX_SQ(x) ((x) << S_TCB_CQ_IDX_SQ) + +#define W_TCB_CQ_IDX_RQ 27 +#define S_TCB_CQ_IDX_RQ 19 +#define M_TCB_CQ_IDX_RQ 0xffffULL +#define V_TCB_CQ_IDX_RQ(x) ((x) << S_TCB_CQ_IDX_RQ) + +#define W_TCB_QP_ID 28 +#define S_TCB_QP_ID 3 +#define M_TCB_QP_ID 0xffffULL +#define V_TCB_QP_ID(x) ((x) << S_TCB_QP_ID) + +#define W_TCB_PD_ID 28 +#define S_TCB_PD_ID 19 +#define M_TCB_PD_ID 0xffffULL +#define V_TCB_PD_ID(x) ((x) << S_TCB_PD_ID) + +#define W_TCB_STAG 29 +#define S_TCB_STAG 3 +#define M_TCB_STAG 0xffffffffULL +#define V_TCB_STAG(x) ((x) << S_TCB_STAG) + +#define W_TCB_RQ_START 30 +#define S_TCB_RQ_START 3 +#define M_TCB_RQ_START 0x3ffffffULL +#define V_TCB_RQ_START(x) ((x) << S_TCB_RQ_START) + +#define W_TCB_RQ_MSN 30 +#define S_TCB_RQ_MSN 29 +#define M_TCB_RQ_MSN 0x3ffULL +#define V_TCB_RQ_MSN(x) ((x) << S_TCB_RQ_MSN) + +#define W_TCB_RQ_MAX_OFFSET 31 +#define S_TCB_RQ_MAX_OFFSET 7 +#define M_TCB_RQ_MAX_OFFSET 0xfULL +#define V_TCB_RQ_MAX_OFFSET(x) ((x) << S_TCB_RQ_MAX_OFFSET) + +#define W_TCB_RQ_WRITE_PTR 31 +#define S_TCB_RQ_WRITE_PTR 11 +#define M_TCB_RQ_WRITE_PTR 0x3ffULL +#define V_TCB_RQ_WRITE_PTR(x) ((x) << S_TCB_RQ_WRITE_PTR) + +#define W_TCB_INB_WRITE_PERM 31 +#define S_TCB_INB_WRITE_PERM 21 +#define M_TCB_INB_WRITE_PERM 0x1ULL +#define V_TCB_INB_WRITE_PERM(x) ((x) << S_TCB_INB_WRITE_PERM) + +#define W_TCB_INB_READ_PERM 31 +#define S_TCB_INB_READ_PERM 22 +#define M_TCB_INB_READ_PERM 0x1ULL +#define V_TCB_INB_READ_PERM(x) ((x) << S_TCB_INB_READ_PERM) + +#define W_TCB_ORD_L_BIT_VLD 31 +#define S_TCB_ORD_L_BIT_VLD 23 +#define M_TCB_ORD_L_BIT_VLD 0x1ULL +#define V_TCB_ORD_L_BIT_VLD(x) ((x) << S_TCB_ORD_L_BIT_VLD) + +#define W_TCB_RDMAP_OPCODE 31 +#define S_TCB_RDMAP_OPCODE 24 +#define M_TCB_RDMAP_OPCODE 0xfULL +#define V_TCB_RDMAP_OPCODE(x) ((x) << S_TCB_RDMAP_OPCODE) + +#define W_TCB_TX_FLUSH 31 +#define S_TCB_TX_FLUSH 28 +#define M_TCB_TX_FLUSH 0x1ULL +#define V_TCB_TX_FLUSH(x) ((x) << S_TCB_TX_FLUSH) + +#define W_TCB_TX_OOS_RXMT 31 +#define S_TCB_TX_OOS_RXMT 29 +#define M_TCB_TX_OOS_RXMT 0x1ULL +#define V_TCB_TX_OOS_RXMT(x) ((x) << S_TCB_TX_OOS_RXMT) + +#define W_TCB_TX_OOS_TXMT 31 +#define S_TCB_TX_OOS_TXMT 30 +#define M_TCB_TX_OOS_TXMT 0x1ULL +#define V_TCB_TX_OOS_TXMT(x) ((x) << S_TCB_TX_OOS_TXMT) + +#define W_TCB_SLUSH_AUX2 31 +#define S_TCB_SLUSH_AUX2 31 +#define M_TCB_SLUSH_AUX2 0x1ULL +#define V_TCB_SLUSH_AUX2(x) ((x) << S_TCB_SLUSH_AUX2) + +#define W_TCB_RX_FRAG1_PTR_RAW2 25 +#define S_TCB_RX_FRAG1_PTR_RAW2 30 +#define M_TCB_RX_FRAG1_PTR_RAW2 0x1ffffULL +#define V_TCB_RX_FRAG1_PTR_RAW2(x) ((x) << S_TCB_RX_FRAG1_PTR_RAW2) + +#define W_TCB_RX_DDP_FLAGS 26 +#define S_TCB_RX_DDP_FLAGS 15 +#define M_TCB_RX_DDP_FLAGS 0x3ffULL +#define V_TCB_RX_DDP_FLAGS(x) ((x) << S_TCB_RX_DDP_FLAGS) + +#define W_TCB_SLUSH_AUX3 26 +#define S_TCB_SLUSH_AUX3 31 +#define M_TCB_SLUSH_AUX3 0x1ffULL +#define V_TCB_SLUSH_AUX3(x) ((x) << S_TCB_SLUSH_AUX3) + +#define W_TCB_RX_DDP_BUF0_OFFSET 27 +#define S_TCB_RX_DDP_BUF0_OFFSET 8 +#define M_TCB_RX_DDP_BUF0_OFFSET 0x3fffffULL +#define V_TCB_RX_DDP_BUF0_OFFSET(x) ((x) << S_TCB_RX_DDP_BUF0_OFFSET) + +#define W_TCB_RX_DDP_BUF0_LEN 27 +#define S_TCB_RX_DDP_BUF0_LEN 30 +#define M_TCB_RX_DDP_BUF0_LEN 0x3fffffULL +#define V_TCB_RX_DDP_BUF0_LEN(x) ((x) << S_TCB_RX_DDP_BUF0_LEN) + +#define W_TCB_RX_DDP_BUF1_OFFSET 28 +#define S_TCB_RX_DDP_BUF1_OFFSET 20 +#define M_TCB_RX_DDP_BUF1_OFFSET 0x3fffffULL +#define V_TCB_RX_DDP_BUF1_OFFSET(x) ((x) << S_TCB_RX_DDP_BUF1_OFFSET) + +#define W_TCB_RX_DDP_BUF1_LEN 29 +#define S_TCB_RX_DDP_BUF1_LEN 10 +#define M_TCB_RX_DDP_BUF1_LEN 0x3fffffULL +#define V_TCB_RX_DDP_BUF1_LEN(x) ((x) << S_TCB_RX_DDP_BUF1_LEN) + +#define W_TCB_RX_DDP_BUF0_TAG 30 +#define S_TCB_RX_DDP_BUF0_TAG 0 +#define M_TCB_RX_DDP_BUF0_TAG 0xffffffffULL +#define V_TCB_RX_DDP_BUF0_TAG(x) ((x) << S_TCB_RX_DDP_BUF0_TAG) + +#define W_TCB_RX_DDP_BUF1_TAG 31 +#define S_TCB_RX_DDP_BUF1_TAG 0 +#define M_TCB_RX_DDP_BUF1_TAG 0xffffffffULL +#define V_TCB_RX_DDP_BUF1_TAG(x) ((x) << S_TCB_RX_DDP_BUF1_TAG) + +#define S_TF_DACK 10 +#define V_TF_DACK(x) ((x) << S_TF_DACK) + +#define S_TF_NAGLE 11 +#define V_TF_NAGLE(x) ((x) << S_TF_NAGLE) + +#define S_TF_RECV_SCALE 12 +#define V_TF_RECV_SCALE(x) ((x) << S_TF_RECV_SCALE) + +#define S_TF_RECV_TSTMP 13 +#define V_TF_RECV_TSTMP(x) ((x) << S_TF_RECV_TSTMP) + +#define S_TF_RECV_SACK 14 +#define V_TF_RECV_SACK(x) ((x) << S_TF_RECV_SACK) + +#define S_TF_TURBO 15 +#define V_TF_TURBO(x) ((x) << S_TF_TURBO) + +#define S_TF_KEEPALIVE 16 +#define V_TF_KEEPALIVE(x) ((x) << S_TF_KEEPALIVE) + +#define S_TF_TCAM_BYPASS 17 +#define V_TF_TCAM_BYPASS(x) ((x) << S_TF_TCAM_BYPASS) + +#define S_TF_CORE_FIN 18 +#define V_TF_CORE_FIN(x) ((x) << S_TF_CORE_FIN) + +#define S_TF_CORE_MORE 19 +#define V_TF_CORE_MORE(x) ((x) << S_TF_CORE_MORE) + +#define S_TF_MIGRATING 20 +#define V_TF_MIGRATING(x) ((x) << S_TF_MIGRATING) + +#define S_TF_ACTIVE_OPEN 21 +#define V_TF_ACTIVE_OPEN(x) ((x) << S_TF_ACTIVE_OPEN) + +#define S_TF_ASK_MODE 22 +#define V_TF_ASK_MODE(x) ((x) << S_TF_ASK_MODE) + +#define S_TF_NON_OFFLOAD 23 +#define V_TF_NON_OFFLOAD(x) ((x) << S_TF_NON_OFFLOAD) + +#define S_TF_MOD_SCHD 24 +#define V_TF_MOD_SCHD(x) ((x) << S_TF_MOD_SCHD) + +#define S_TF_MOD_SCHD_REASON0 25 +#define V_TF_MOD_SCHD_REASON0(x) ((x) << S_TF_MOD_SCHD_REASON0) + +#define S_TF_MOD_SCHD_REASON1 26 +#define V_TF_MOD_SCHD_REASON1(x) ((x) << S_TF_MOD_SCHD_REASON1) + +#define S_TF_MOD_SCHD_RX 27 +#define V_TF_MOD_SCHD_RX(x) ((x) << S_TF_MOD_SCHD_RX) + +#define S_TF_CORE_PUSH 28 +#define V_TF_CORE_PUSH(x) ((x) << S_TF_CORE_PUSH) + +#define S_TF_RCV_COALESCE_ENABLE 29 +#define V_TF_RCV_COALESCE_ENABLE(x) ((x) << S_TF_RCV_COALESCE_ENABLE) + +#define S_TF_RCV_COALESCE_PUSH 30 +#define V_TF_RCV_COALESCE_PUSH(x) ((x) << S_TF_RCV_COALESCE_PUSH) + +#define S_TF_RCV_COALESCE_LAST_PSH 31 +#define V_TF_RCV_COALESCE_LAST_PSH(x) ((x) << S_TF_RCV_COALESCE_LAST_PSH) + +#define S_TF_RCV_COALESCE_HEARTBEAT 32 +#define V_TF_RCV_COALESCE_HEARTBEAT(x) ((x) << S_TF_RCV_COALESCE_HEARTBEAT) + +#define S_TF_HALF_CLOSE 33 +#define V_TF_HALF_CLOSE(x) ((x) << S_TF_HALF_CLOSE) + +#define S_TF_DACK_MSS 34 +#define V_TF_DACK_MSS(x) ((x) << S_TF_DACK_MSS) + +#define S_TF_CCTRL_SEL0 35 +#define V_TF_CCTRL_SEL0(x) ((x) << S_TF_CCTRL_SEL0) + +#define S_TF_CCTRL_SEL1 36 +#define V_TF_CCTRL_SEL1(x) ((x) << S_TF_CCTRL_SEL1) + +#define S_TF_TCP_NEWRENO_FAST_RECOVERY 37 +#define V_TF_TCP_NEWRENO_FAST_RECOVERY(x) ((x) << S_TF_TCP_NEWRENO_FAST_RECOVERY) + +#define S_TF_TX_PACE_AUTO 38 +#define V_TF_TX_PACE_AUTO(x) ((x) << S_TF_TX_PACE_AUTO) + +#define S_TF_PEER_FIN_HELD 39 +#define V_TF_PEER_FIN_HELD(x) ((x) << S_TF_PEER_FIN_HELD) + +#define S_TF_CORE_URG 40 +#define V_TF_CORE_URG(x) ((x) << S_TF_CORE_URG) + +#define S_TF_RDMA_ERROR 41 +#define V_TF_RDMA_ERROR(x) ((x) << S_TF_RDMA_ERROR) + +#define S_TF_SSWS_DISABLED 42 +#define V_TF_SSWS_DISABLED(x) ((x) << S_TF_SSWS_DISABLED) + +#define S_TF_DUPACK_COUNT_ODD 43 +#define V_TF_DUPACK_COUNT_ODD(x) ((x) << S_TF_DUPACK_COUNT_ODD) + +#define S_TF_TX_CHANNEL 44 +#define V_TF_TX_CHANNEL(x) ((x) << S_TF_TX_CHANNEL) + +#define S_TF_RX_CHANNEL 45 +#define V_TF_RX_CHANNEL(x) ((x) << S_TF_RX_CHANNEL) + +#define S_TF_TX_PACE_FIXED 46 +#define V_TF_TX_PACE_FIXED(x) ((x) << S_TF_TX_PACE_FIXED) + +#define S_TF_RDMA_FLM_ERROR 47 +#define V_TF_RDMA_FLM_ERROR(x) ((x) << S_TF_RDMA_FLM_ERROR) + +#define S_TF_RX_FLOW_CONTROL_DISABLE 48 +#define V_TF_RX_FLOW_CONTROL_DISABLE(x) ((x) << S_TF_RX_FLOW_CONTROL_DISABLE) + +#endif /* _TCB_DEFS_H */ diff --git a/drivers/infiniband/hw/ehca/ehca_classes.h b/drivers/infiniband/hw/ehca/ehca_classes.h index 1c72203..cf95ee4 100644 --- a/drivers/infiniband/hw/ehca/ehca_classes.h +++ b/drivers/infiniband/hw/ehca/ehca_classes.h @@ -119,13 +119,14 @@ struct ehca_qp { struct ipz_qp_handle ipz_qp_handle; struct ehca_pfqp pf; struct ib_qp_init_attr init_attr; - u64 uspace_squeue; - u64 uspace_rqueue; - u64 uspace_fwh; struct ehca_cq *send_cq; struct ehca_cq *recv_cq; unsigned int sqerr_purgeflag; struct hlist_node list_entries; + /* mmap counter for resources mapped into user space */ + u32 mm_count_squeue; + u32 mm_count_rqueue; + u32 mm_count_galpa; }; /* must be power of 2 */ @@ -142,13 +143,14 @@ struct ehca_cq { struct ipz_cq_handle ipz_cq_handle; struct ehca_pfcq pf; spinlock_t cb_lock; - u64 uspace_queue; - u64 uspace_fwh; struct hlist_head qp_hashtab[QP_HASHTAB_LEN]; struct list_head entry; u32 nr_callbacks; spinlock_t task_lock; u32 ownpid; + /* mmap counter for resources mapped into user space */ + u32 mm_count_queue; + u32 mm_count_galpa; }; enum ehca_mr_flag { @@ -248,20 +250,6 @@ struct ehca_ucontext { struct ib_ucontext ib_ucontext; }; -struct ehca_module *ehca_module_new(void); - -int ehca_module_delete(struct ehca_module *me); - -int ehca_eq_ctor(struct ehca_eq *eq); - -int ehca_eq_dtor(struct ehca_eq *eq); - -struct ehca_shca *ehca_shca_new(void); - -int ehca_shca_delete(struct ehca_shca *me); - -struct ehca_sport *ehca_sport_new(struct ehca_shca *anchor); - int ehca_init_pd_cache(void); void ehca_cleanup_pd_cache(void); int ehca_init_cq_cache(void); @@ -283,7 +271,6 @@ extern int ehca_port_act_time; extern int ehca_use_hp_mr; struct ipzu_queue_resp { - u64 queue; /* points to first queue entry */ u32 qe_size; /* queue entry size */ u32 act_nr_of_sg; u32 queue_length; /* queue length allocated in bytes */ @@ -296,7 +283,6 @@ struct ehca_create_cq_resp { u32 cq_number; u32 token; struct ipzu_queue_resp ipz_queue; - struct h_galpas galpas; }; struct ehca_create_qp_resp { @@ -309,7 +295,6 @@ struct ehca_create_qp_resp { u32 dummy; /* padding for 8 byte alignment */ struct ipzu_queue_resp ipz_squeue; struct ipzu_queue_resp ipz_rqueue; - struct h_galpas galpas; }; struct ehca_alloc_cq_parms { diff --git a/drivers/infiniband/hw/ehca/ehca_cq.c b/drivers/infiniband/hw/ehca/ehca_cq.c index 6074c89..6ebfa27 100644 --- a/drivers/infiniband/hw/ehca/ehca_cq.c +++ b/drivers/infiniband/hw/ehca/ehca_cq.c @@ -134,14 +134,13 @@ struct ib_cq *ehca_create_cq(struct ib_d if (cqe >= 0xFFFFFFFF - 64 - additional_cqe) return ERR_PTR(-EINVAL); - my_cq = kmem_cache_alloc(cq_cache, GFP_KERNEL); + my_cq = kmem_cache_zalloc(cq_cache, GFP_KERNEL); if (!my_cq) { ehca_err(device, "Out of memory for ehca_cq struct device=%p", device); return ERR_PTR(-ENOMEM); } - memset(my_cq, 0, sizeof(struct ehca_cq)); memset(¶m, 0, sizeof(struct ehca_alloc_cq_parms)); spin_lock_init(&my_cq->spinlock); @@ -267,7 +266,6 @@ struct ib_cq *ehca_create_cq(struct ib_d if (context) { struct ipz_queue *ipz_queue = &my_cq->ipz_queue; struct ehca_create_cq_resp resp; - struct vm_area_struct *vma; memset(&resp, 0, sizeof(resp)); resp.cq_number = my_cq->cq_number; resp.token = my_cq->token; @@ -276,40 +274,14 @@ struct ib_cq *ehca_create_cq(struct ib_d resp.ipz_queue.queue_length = ipz_queue->queue_length; resp.ipz_queue.pagesize = ipz_queue->pagesize; resp.ipz_queue.toggle_state = ipz_queue->toggle_state; - ret = ehca_mmap_nopage(((u64)(my_cq->token) << 32) | 0x12000000, - ipz_queue->queue_length, - (void**)&resp.ipz_queue.queue, - &vma); - if (ret) { - ehca_err(device, "Could not mmap queue pages"); - cq = ERR_PTR(ret); - goto create_cq_exit4; - } - my_cq->uspace_queue = resp.ipz_queue.queue; - resp.galpas = my_cq->galpas; - ret = ehca_mmap_register(my_cq->galpas.user.fw_handle, - (void**)&resp.galpas.kernel.fw_handle, - &vma); - if (ret) { - ehca_err(device, "Could not mmap fw_handle"); - cq = ERR_PTR(ret); - goto create_cq_exit5; - } - my_cq->uspace_fwh = (u64)resp.galpas.kernel.fw_handle; if (ib_copy_to_udata(udata, &resp, sizeof(resp))) { ehca_err(device, "Copy to udata failed."); - goto create_cq_exit6; + goto create_cq_exit4; } } return cq; -create_cq_exit6: - ehca_munmap(my_cq->uspace_fwh, EHCA_PAGESIZE); - -create_cq_exit5: - ehca_munmap(my_cq->uspace_queue, my_cq->ipz_queue.queue_length); - create_cq_exit4: ipz_queue_dtor(&my_cq->ipz_queue); @@ -333,7 +305,6 @@ create_cq_exit1: int ehca_destroy_cq(struct ib_cq *cq) { u64 h_ret; - int ret; struct ehca_cq *my_cq = container_of(cq, struct ehca_cq, ib_cq); int cq_num = my_cq->cq_number; struct ib_device *device = cq->device; @@ -343,6 +314,20 @@ int ehca_destroy_cq(struct ib_cq *cq) u32 cur_pid = current->tgid; unsigned long flags; + if (cq->uobject) { + if (my_cq->mm_count_galpa || my_cq->mm_count_queue) { + ehca_err(device, "Resources still referenced in " + "user space cq_num=%x", my_cq->cq_number); + return -EINVAL; + } + if (my_cq->ownpid != cur_pid) { + ehca_err(device, "Invalid caller pid=%x ownpid=%x " + "cq_num=%x", + cur_pid, my_cq->ownpid, my_cq->cq_number); + return -EINVAL; + } + } + spin_lock_irqsave(&ehca_cq_idr_lock, flags); while (my_cq->nr_callbacks) { spin_unlock_irqrestore(&ehca_cq_idr_lock, flags); @@ -353,25 +338,6 @@ int ehca_destroy_cq(struct ib_cq *cq) idr_remove(&ehca_cq_idr, my_cq->token); spin_unlock_irqrestore(&ehca_cq_idr_lock, flags); - if (my_cq->uspace_queue && my_cq->ownpid != cur_pid) { - ehca_err(device, "Invalid caller pid=%x ownpid=%x", - cur_pid, my_cq->ownpid); - return -EINVAL; - } - - /* un-mmap if vma alloc */ - if (my_cq->uspace_queue ) { - ret = ehca_munmap(my_cq->uspace_queue, - my_cq->ipz_queue.queue_length); - if (ret) - ehca_err(device, "Could not munmap queue ehca_cq=%p " - "cq_num=%x", my_cq, cq_num); - ret = ehca_munmap(my_cq->uspace_fwh, EHCA_PAGESIZE); - if (ret) - ehca_err(device, "Could not munmap fwh ehca_cq=%p " - "cq_num=%x", my_cq, cq_num); - } - h_ret = hipz_h_destroy_cq(adapter_handle, my_cq, 0); if (h_ret == H_R_STATE) { /* cq in err: read err data and destroy it forcibly */ @@ -400,7 +366,7 @@ int ehca_resize_cq(struct ib_cq *cq, int struct ehca_cq *my_cq = container_of(cq, struct ehca_cq, ib_cq); u32 cur_pid = current->tgid; - if (my_cq->uspace_queue && my_cq->ownpid != cur_pid) { + if (cq->uobject && my_cq->ownpid != cur_pid) { ehca_err(cq->device, "Invalid caller pid=%x ownpid=%x", cur_pid, my_cq->ownpid); return -EINVAL; diff --git a/drivers/infiniband/hw/ehca/ehca_eq.c b/drivers/infiniband/hw/ehca/ehca_eq.c index 5281dec..24ceab0 100644 --- a/drivers/infiniband/hw/ehca/ehca_eq.c +++ b/drivers/infiniband/hw/ehca/ehca_eq.c @@ -122,7 +122,7 @@ int ehca_create_eq(struct ehca_shca *shc /* register interrupt handlers and initialize work queues */ if (type == EHCA_EQ) { ret = ibmebus_request_irq(NULL, eq->ist, ehca_interrupt_eq, - SA_INTERRUPT, "ehca_eq", + IRQF_DISABLED, "ehca_eq", (void *)shca); if (ret < 0) ehca_err(ib_dev, "Can't map interrupt handler."); @@ -130,7 +130,7 @@ int ehca_create_eq(struct ehca_shca *shc tasklet_init(&eq->interrupt_task, ehca_tasklet_eq, (long)shca); } else if (type == EHCA_NEQ) { ret = ibmebus_request_irq(NULL, eq->ist, ehca_interrupt_neq, - SA_INTERRUPT, "ehca_neq", + IRQF_DISABLED, "ehca_neq", (void *)shca); if (ret < 0) ehca_err(ib_dev, "Can't map interrupt handler."); diff --git a/drivers/infiniband/hw/ehca/ehca_irq.c b/drivers/infiniband/hw/ehca/ehca_irq.c index c069be8..6c4f9f9 100644 --- a/drivers/infiniband/hw/ehca/ehca_irq.c +++ b/drivers/infiniband/hw/ehca/ehca_irq.c @@ -756,6 +756,8 @@ #ifdef CONFIG_INFINIBAND_EHCA_SCALING if (cpu_online(i)) destroy_comp_task(pool, i); } + free_percpu(pool->cpu_comp_tasks); + kfree(pool); #endif return; diff --git a/drivers/infiniband/hw/ehca/ehca_iverbs.h b/drivers/infiniband/hw/ehca/ehca_iverbs.h index cd7789f..95fd59f 100644 --- a/drivers/infiniband/hw/ehca/ehca_iverbs.h +++ b/drivers/infiniband/hw/ehca/ehca_iverbs.h @@ -171,14 +171,6 @@ int ehca_mmap(struct ib_ucontext *contex void ehca_poll_eqs(unsigned long data); -int ehca_mmap_nopage(u64 foffset,u64 length,void **mapped, - struct vm_area_struct **vma); - -int ehca_mmap_register(u64 physical,void **mapped, - struct vm_area_struct **vma); - -int ehca_munmap(unsigned long addr, size_t len); - #ifdef CONFIG_PPC_64K_PAGES void *ehca_alloc_fw_ctrlblock(gfp_t flags); void ehca_free_fw_ctrlblock(void *ptr); diff --git a/drivers/infiniband/hw/ehca/ehca_main.c b/drivers/infiniband/hw/ehca/ehca_main.c index 6574fbb..1155bcf 100644 --- a/drivers/infiniband/hw/ehca/ehca_main.c +++ b/drivers/infiniband/hw/ehca/ehca_main.c @@ -52,7 +52,7 @@ #include "hcp_if.h" MODULE_LICENSE("Dual BSD/GPL"); MODULE_AUTHOR("Christoph Raisch "); MODULE_DESCRIPTION("IBM eServer HCA InfiniBand Device Driver"); -MODULE_VERSION("SVNEHCA_0019"); +MODULE_VERSION("SVNEHCA_0020"); int ehca_open_aqp1 = 0; int ehca_debug_level = 0; @@ -288,7 +288,7 @@ int ehca_init_device(struct ehca_shca *s strlcpy(shca->ib_device.name, "ehca%d", IB_DEVICE_NAME_MAX); shca->ib_device.owner = THIS_MODULE; - shca->ib_device.uverbs_abi_ver = 5; + shca->ib_device.uverbs_abi_ver = 6; shca->ib_device.uverbs_cmd_mask = (1ull << IB_USER_VERBS_CMD_GET_CONTEXT) | (1ull << IB_USER_VERBS_CMD_QUERY_DEVICE) | @@ -790,7 +790,7 @@ int __init ehca_module_init(void) int ret; printk(KERN_INFO "eHCA Infiniband Device Driver " - "(Rel.: SVNEHCA_0019)\n"); + "(Rel.: SVNEHCA_0020)\n"); idr_init(&ehca_qp_idr); idr_init(&ehca_cq_idr); spin_lock_init(&ehca_qp_idr_lock); diff --git a/drivers/infiniband/hw/ehca/ehca_mrmw.c b/drivers/infiniband/hw/ehca/ehca_mrmw.c index cfb362a..d22ab56 100644 --- a/drivers/infiniband/hw/ehca/ehca_mrmw.c +++ b/drivers/infiniband/hw/ehca/ehca_mrmw.c @@ -53,9 +53,8 @@ static struct ehca_mr *ehca_mr_new(void) { struct ehca_mr *me; - me = kmem_cache_alloc(mr_cache, GFP_KERNEL); + me = kmem_cache_zalloc(mr_cache, GFP_KERNEL); if (me) { - memset(me, 0, sizeof(struct ehca_mr)); spin_lock_init(&me->mrlock); } else ehca_gen_err("alloc failed"); @@ -72,9 +71,8 @@ static struct ehca_mw *ehca_mw_new(void) { struct ehca_mw *me; - me = kmem_cache_alloc(mw_cache, GFP_KERNEL); + me = kmem_cache_zalloc(mw_cache, GFP_KERNEL); if (me) { - memset(me, 0, sizeof(struct ehca_mw)); spin_lock_init(&me->mwlock); } else ehca_gen_err("alloc failed"); diff --git a/drivers/infiniband/hw/ehca/ehca_pd.c b/drivers/infiniband/hw/ehca/ehca_pd.c index d5345e5..79d0591 100644 --- a/drivers/infiniband/hw/ehca/ehca_pd.c +++ b/drivers/infiniband/hw/ehca/ehca_pd.c @@ -50,14 +50,13 @@ struct ib_pd *ehca_alloc_pd(struct ib_de { struct ehca_pd *pd; - pd = kmem_cache_alloc(pd_cache, GFP_KERNEL); + pd = kmem_cache_zalloc(pd_cache, GFP_KERNEL); if (!pd) { ehca_err(device, "device=%p context=%p out of memory", device, context); return ERR_PTR(-ENOMEM); } - memset(pd, 0, sizeof(struct ehca_pd)); pd->ownpid = current->tgid; /* diff --git a/drivers/infiniband/hw/ehca/ehca_qp.c b/drivers/infiniband/hw/ehca/ehca_qp.c index 34b8555..df0516f 100644 --- a/drivers/infiniband/hw/ehca/ehca_qp.c +++ b/drivers/infiniband/hw/ehca/ehca_qp.c @@ -450,13 +450,12 @@ struct ib_qp *ehca_create_qp(struct ib_p if (pd->uobject && udata) context = pd->uobject->context; - my_qp = kmem_cache_alloc(qp_cache, GFP_KERNEL); + my_qp = kmem_cache_zalloc(qp_cache, GFP_KERNEL); if (!my_qp) { ehca_err(pd->device, "pd=%p not enough memory to alloc qp", pd); return ERR_PTR(-ENOMEM); } - memset(my_qp, 0, sizeof(struct ehca_qp)); memset (&parms, 0, sizeof(struct ehca_alloc_qp_parms)); spin_lock_init(&my_qp->spinlock_s); spin_lock_init(&my_qp->spinlock_r); @@ -637,7 +636,6 @@ struct ib_qp *ehca_create_qp(struct ib_p struct ipz_queue *ipz_rqueue = &my_qp->ipz_rqueue; struct ipz_queue *ipz_squeue = &my_qp->ipz_squeue; struct ehca_create_qp_resp resp; - struct vm_area_struct * vma; memset(&resp, 0, sizeof(resp)); resp.qp_num = my_qp->real_qp_num; @@ -651,59 +649,21 @@ struct ib_qp *ehca_create_qp(struct ib_p resp.ipz_rqueue.queue_length = ipz_rqueue->queue_length; resp.ipz_rqueue.pagesize = ipz_rqueue->pagesize; resp.ipz_rqueue.toggle_state = ipz_rqueue->toggle_state; - ret = ehca_mmap_nopage(((u64)(my_qp->token) << 32) | 0x22000000, - ipz_rqueue->queue_length, - (void**)&resp.ipz_rqueue.queue, - &vma); - if (ret) { - ehca_err(pd->device, "Could not mmap rqueue pages"); - goto create_qp_exit3; - } - my_qp->uspace_rqueue = resp.ipz_rqueue.queue; /* squeue properties */ resp.ipz_squeue.qe_size = ipz_squeue->qe_size; resp.ipz_squeue.act_nr_of_sg = ipz_squeue->act_nr_of_sg; resp.ipz_squeue.queue_length = ipz_squeue->queue_length; resp.ipz_squeue.pagesize = ipz_squeue->pagesize; resp.ipz_squeue.toggle_state = ipz_squeue->toggle_state; - ret = ehca_mmap_nopage(((u64)(my_qp->token) << 32) | 0x23000000, - ipz_squeue->queue_length, - (void**)&resp.ipz_squeue.queue, - &vma); - if (ret) { - ehca_err(pd->device, "Could not mmap squeue pages"); - goto create_qp_exit4; - } - my_qp->uspace_squeue = resp.ipz_squeue.queue; - /* fw_handle */ - resp.galpas = my_qp->galpas; - ret = ehca_mmap_register(my_qp->galpas.user.fw_handle, - (void**)&resp.galpas.kernel.fw_handle, - &vma); - if (ret) { - ehca_err(pd->device, "Could not mmap fw_handle"); - goto create_qp_exit5; - } - my_qp->uspace_fwh = (u64)resp.galpas.kernel.fw_handle; - if (ib_copy_to_udata(udata, &resp, sizeof resp)) { ehca_err(pd->device, "Copy to udata failed"); ret = -EINVAL; - goto create_qp_exit6; + goto create_qp_exit3; } } return &my_qp->ib_qp; -create_qp_exit6: - ehca_munmap(my_qp->uspace_fwh, EHCA_PAGESIZE); - -create_qp_exit5: - ehca_munmap(my_qp->uspace_squeue, my_qp->ipz_squeue.queue_length); - -create_qp_exit4: - ehca_munmap(my_qp->uspace_rqueue, my_qp->ipz_rqueue.queue_length); - create_qp_exit3: ipz_queue_dtor(&my_qp->ipz_rqueue); ipz_queue_dtor(&my_qp->ipz_squeue); @@ -931,7 +891,7 @@ static int internal_modify_qp(struct ib_ my_qp->qp_type == IB_QPT_SMI) && statetrans == IB_QPST_SQE2RTS) { /* mark next free wqe if kernel */ - if (my_qp->uspace_squeue == 0) { + if (!ibqp->uobject) { struct ehca_wqe *wqe; /* lock send queue */ spin_lock_irqsave(&my_qp->spinlock_s, spl_flags); @@ -1417,11 +1377,18 @@ int ehca_destroy_qp(struct ib_qp *ibqp) enum ib_qp_type qp_type; unsigned long flags; - if (my_pd->ib_pd.uobject && my_pd->ib_pd.uobject->context && - my_pd->ownpid != cur_pid) { - ehca_err(ibqp->device, "Invalid caller pid=%x ownpid=%x", - cur_pid, my_pd->ownpid); - return -EINVAL; + if (ibqp->uobject) { + if (my_qp->mm_count_galpa || + my_qp->mm_count_rqueue || my_qp->mm_count_squeue) { + ehca_err(ibqp->device, "Resources still referenced in " + "user space qp_num=%x", ibqp->qp_num); + return -EINVAL; + } + if (my_pd->ownpid != cur_pid) { + ehca_err(ibqp->device, "Invalid caller pid=%x ownpid=%x", + cur_pid, my_pd->ownpid); + return -EINVAL; + } } if (my_qp->send_cq) { @@ -1439,24 +1406,6 @@ int ehca_destroy_qp(struct ib_qp *ibqp) idr_remove(&ehca_qp_idr, my_qp->token); spin_unlock_irqrestore(&ehca_qp_idr_lock, flags); - /* un-mmap if vma alloc */ - if (my_qp->uspace_rqueue) { - ret = ehca_munmap(my_qp->uspace_rqueue, - my_qp->ipz_rqueue.queue_length); - if (ret) - ehca_err(ibqp->device, "Could not munmap rqueue " - "qp_num=%x", qp_num); - ret = ehca_munmap(my_qp->uspace_squeue, - my_qp->ipz_squeue.queue_length); - if (ret) - ehca_err(ibqp->device, "Could not munmap squeue " - "qp_num=%x", qp_num); - ret = ehca_munmap(my_qp->uspace_fwh, EHCA_PAGESIZE); - if (ret) - ehca_err(ibqp->device, "Could not munmap fwh qp_num=%x", - qp_num); - } - h_ret = hipz_h_destroy_qp(shca->ipz_hca_handle, my_qp); if (h_ret != H_SUCCESS) { ehca_err(ibqp->device, "hipz_h_destroy_qp() failed rc=%lx " diff --git a/drivers/infiniband/hw/ehca/ehca_reqs.c b/drivers/infiniband/hw/ehca/ehca_reqs.c index b46bda1..08d3f89 100644 --- a/drivers/infiniband/hw/ehca/ehca_reqs.c +++ b/drivers/infiniband/hw/ehca/ehca_reqs.c @@ -579,7 +579,7 @@ poll_cq_one_read_cqe: } else wc->status = IB_WC_SUCCESS; - wc->qp_num = cqe->local_qp_number; + wc->qp = NULL; wc->byte_len = cqe->nr_bytes_transferred; wc->pkey_index = cqe->pkey_index; wc->slid = cqe->rlid; diff --git a/drivers/infiniband/hw/ehca/ehca_uverbs.c b/drivers/infiniband/hw/ehca/ehca_uverbs.c index e08764e..73db920 100644 --- a/drivers/infiniband/hw/ehca/ehca_uverbs.c +++ b/drivers/infiniband/hw/ehca/ehca_uverbs.c @@ -68,105 +68,183 @@ int ehca_dealloc_ucontext(struct ib_ucon return 0; } -struct page *ehca_nopage(struct vm_area_struct *vma, - unsigned long address, int *type) +static void ehca_mm_open(struct vm_area_struct *vma) { - struct page *mypage = NULL; - u64 fileoffset = vma->vm_pgoff << PAGE_SHIFT; - u32 idr_handle = fileoffset >> 32; - u32 q_type = (fileoffset >> 28) & 0xF; /* CQ, QP,... */ - u32 rsrc_type = (fileoffset >> 24) & 0xF; /* sq,rq,cmnd_window */ - u32 cur_pid = current->tgid; - unsigned long flags; - struct ehca_cq *cq; - struct ehca_qp *qp; - struct ehca_pd *pd; - u64 offset; - void *vaddr; + u32 *count = (u32*)vma->vm_private_data; + if (!count) { + ehca_gen_err("Invalid vma struct vm_start=%lx vm_end=%lx", + vma->vm_start, vma->vm_end); + return; + } + (*count)++; + if (!(*count)) + ehca_gen_err("Use count overflow vm_start=%lx vm_end=%lx", + vma->vm_start, vma->vm_end); + ehca_gen_dbg("vm_start=%lx vm_end=%lx count=%x", + vma->vm_start, vma->vm_end, *count); +} - switch (q_type) { - case 1: /* CQ */ - spin_lock_irqsave(&ehca_cq_idr_lock, flags); - cq = idr_find(&ehca_cq_idr, idr_handle); - spin_unlock_irqrestore(&ehca_cq_idr_lock, flags); +static void ehca_mm_close(struct vm_area_struct *vma) +{ + u32 *count = (u32*)vma->vm_private_data; + if (!count) { + ehca_gen_err("Invalid vma struct vm_start=%lx vm_end=%lx", + vma->vm_start, vma->vm_end); + return; + } + (*count)--; + ehca_gen_dbg("vm_start=%lx vm_end=%lx count=%x", + vma->vm_start, vma->vm_end, *count); +} - /* make sure this mmap really belongs to the authorized user */ - if (!cq) { - ehca_gen_err("cq is NULL ret=NOPAGE_SIGBUS"); - return NOPAGE_SIGBUS; +static struct vm_operations_struct vm_ops = { + .open = ehca_mm_open, + .close = ehca_mm_close, +}; + +static int ehca_mmap_fw(struct vm_area_struct *vma, struct h_galpas *galpas, + u32 *mm_count) +{ + int ret; + u64 vsize, physical; + + vsize = vma->vm_end - vma->vm_start; + if (vsize != EHCA_PAGESIZE) { + ehca_gen_err("invalid vsize=%lx", vma->vm_end - vma->vm_start); + return -EINVAL; + } + + physical = galpas->user.fw_handle; + vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot); + ehca_gen_dbg("vsize=%lx physical=%lx", vsize, physical); + /* VM_IO | VM_RESERVED are set by remap_pfn_range() */ + ret = remap_pfn_range(vma, vma->vm_start, physical >> PAGE_SHIFT, + vsize, vma->vm_page_prot); + if (unlikely(ret)) { + ehca_gen_err("remap_pfn_range() failed ret=%x", ret); + return -ENOMEM; + } + + vma->vm_private_data = mm_count; + (*mm_count)++; + vma->vm_ops = &vm_ops; + + return 0; +} + +static int ehca_mmap_queue(struct vm_area_struct *vma, struct ipz_queue *queue, + u32 *mm_count) +{ + int ret; + u64 start, ofs; + struct page *page; + + vma->vm_flags |= VM_RESERVED; + start = vma->vm_start; + for (ofs = 0; ofs < queue->queue_length; ofs += PAGE_SIZE) { + u64 virt_addr = (u64)ipz_qeit_calc(queue, ofs); + page = virt_to_page(virt_addr); + ret = vm_insert_page(vma, start, page); + if (unlikely(ret)) { + ehca_gen_err("vm_insert_page() failed rc=%x", ret); + return ret; } + start += PAGE_SIZE; + } + vma->vm_private_data = mm_count; + (*mm_count)++; + vma->vm_ops = &vm_ops; - if (cq->ownpid != cur_pid) { + return 0; +} + +static int ehca_mmap_cq(struct vm_area_struct *vma, struct ehca_cq *cq, + u32 rsrc_type) +{ + int ret; + + switch (rsrc_type) { + case 1: /* galpa fw handle */ + ehca_dbg(cq->ib_cq.device, "cq_num=%x fw", cq->cq_number); + ret = ehca_mmap_fw(vma, &cq->galpas, &cq->mm_count_galpa); + if (unlikely(ret)) { ehca_err(cq->ib_cq.device, - "Invalid caller pid=%x ownpid=%x", - cur_pid, cq->ownpid); - return NOPAGE_SIGBUS; + "ehca_mmap_fw() failed rc=%x cq_num=%x", + ret, cq->cq_number); + return ret; } + break; - if (rsrc_type == 2) { - ehca_dbg(cq->ib_cq.device, "cq=%p cq queuearea", cq); - offset = address - vma->vm_start; - vaddr = ipz_qeit_calc(&cq->ipz_queue, offset); - ehca_dbg(cq->ib_cq.device, "offset=%lx vaddr=%p", - offset, vaddr); - mypage = virt_to_page(vaddr); + case 2: /* cq queue_addr */ + ehca_dbg(cq->ib_cq.device, "cq_num=%x queue", cq->cq_number); + ret = ehca_mmap_queue(vma, &cq->ipz_queue, &cq->mm_count_queue); + if (unlikely(ret)) { + ehca_err(cq->ib_cq.device, + "ehca_mmap_queue() failed rc=%x cq_num=%x", + ret, cq->cq_number); + return ret; } break; - case 2: /* QP */ - spin_lock_irqsave(&ehca_qp_idr_lock, flags); - qp = idr_find(&ehca_qp_idr, idr_handle); - spin_unlock_irqrestore(&ehca_qp_idr_lock, flags); + default: + ehca_err(cq->ib_cq.device, "bad resource type=%x cq_num=%x", + rsrc_type, cq->cq_number); + return -EINVAL; + } - /* make sure this mmap really belongs to the authorized user */ - if (!qp) { - ehca_gen_err("qp is NULL ret=NOPAGE_SIGBUS"); - return NOPAGE_SIGBUS; + return 0; +} + +static int ehca_mmap_qp(struct vm_area_struct *vma, struct ehca_qp *qp, + u32 rsrc_type) +{ + int ret; + + switch (rsrc_type) { + case 1: /* galpa fw handle */ + ehca_dbg(qp->ib_qp.device, "qp_num=%x fw", qp->ib_qp.qp_num); + ret = ehca_mmap_fw(vma, &qp->galpas, &qp->mm_count_galpa); + if (unlikely(ret)) { + ehca_err(qp->ib_qp.device, + "remap_pfn_range() failed ret=%x qp_num=%x", + ret, qp->ib_qp.qp_num); + return -ENOMEM; } + break; - pd = container_of(qp->ib_qp.pd, struct ehca_pd, ib_pd); - if (pd->ownpid != cur_pid) { + case 2: /* qp rqueue_addr */ + ehca_dbg(qp->ib_qp.device, "qp_num=%x rqueue", + qp->ib_qp.qp_num); + ret = ehca_mmap_queue(vma, &qp->ipz_rqueue, &qp->mm_count_rqueue); + if (unlikely(ret)) { ehca_err(qp->ib_qp.device, - "Invalid caller pid=%x ownpid=%x", - cur_pid, pd->ownpid); - return NOPAGE_SIGBUS; + "ehca_mmap_queue(rq) failed rc=%x qp_num=%x", + ret, qp->ib_qp.qp_num); + return ret; } + break; - if (rsrc_type == 2) { /* rqueue */ - ehca_dbg(qp->ib_qp.device, "qp=%p qp rqueuearea", qp); - offset = address - vma->vm_start; - vaddr = ipz_qeit_calc(&qp->ipz_rqueue, offset); - ehca_dbg(qp->ib_qp.device, "offset=%lx vaddr=%p", - offset, vaddr); - mypage = virt_to_page(vaddr); - } else if (rsrc_type == 3) { /* squeue */ - ehca_dbg(qp->ib_qp.device, "qp=%p qp squeuearea", qp); - offset = address - vma->vm_start; - vaddr = ipz_qeit_calc(&qp->ipz_squeue, offset); - ehca_dbg(qp->ib_qp.device, "offset=%lx vaddr=%p", - offset, vaddr); - mypage = virt_to_page(vaddr); + case 3: /* qp squeue_addr */ + ehca_dbg(qp->ib_qp.device, "qp_num=%x squeue", + qp->ib_qp.qp_num); + ret = ehca_mmap_queue(vma, &qp->ipz_squeue, &qp->mm_count_squeue); + if (unlikely(ret)) { + ehca_err(qp->ib_qp.device, + "ehca_mmap_queue(sq) failed rc=%x qp_num=%x", + ret, qp->ib_qp.qp_num); + return ret; } break; default: - ehca_gen_err("bad queue type %x", q_type); - return NOPAGE_SIGBUS; - } - - if (!mypage) { - ehca_gen_err("Invalid page adr==NULL ret=NOPAGE_SIGBUS"); - return NOPAGE_SIGBUS; + ehca_err(qp->ib_qp.device, "bad resource type=%x qp=num=%x", + rsrc_type, qp->ib_qp.qp_num); + return -EINVAL; } - get_page(mypage); - return mypage; + return 0; } -static struct vm_operations_struct ehcau_vm_ops = { - .nopage = ehca_nopage, -}; - int ehca_mmap(struct ib_ucontext *context, struct vm_area_struct *vma) { u64 fileoffset = vma->vm_pgoff << PAGE_SHIFT; @@ -175,7 +253,6 @@ int ehca_mmap(struct ib_ucontext *contex u32 rsrc_type = (fileoffset >> 24) & 0xF; /* sq,rq,cmnd_window */ u32 cur_pid = current->tgid; u32 ret; - u64 vsize, physical; unsigned long flags; struct ehca_cq *cq; struct ehca_qp *qp; @@ -201,44 +278,12 @@ int ehca_mmap(struct ib_ucontext *contex if (!cq->ib_cq.uobject || cq->ib_cq.uobject->context != context) return -EINVAL; - switch (rsrc_type) { - case 1: /* galpa fw handle */ - ehca_dbg(cq->ib_cq.device, "cq=%p cq triggerarea", cq); - vma->vm_flags |= VM_RESERVED; - vsize = vma->vm_end - vma->vm_start; - if (vsize != EHCA_PAGESIZE) { - ehca_err(cq->ib_cq.device, "invalid vsize=%lx", - vma->vm_end - vma->vm_start); - return -EINVAL; - } - - physical = cq->galpas.user.fw_handle; - vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot); - vma->vm_flags |= VM_IO | VM_RESERVED; - - ehca_dbg(cq->ib_cq.device, - "vsize=%lx physical=%lx", vsize, physical); - ret = remap_pfn_range(vma, vma->vm_start, - physical >> PAGE_SHIFT, vsize, - vma->vm_page_prot); - if (ret) { - ehca_err(cq->ib_cq.device, - "remap_pfn_range() failed ret=%x", - ret); - return -ENOMEM; - } - break; - - case 2: /* cq queue_addr */ - ehca_dbg(cq->ib_cq.device, "cq=%p cq q_addr", cq); - vma->vm_flags |= VM_RESERVED; - vma->vm_ops = &ehcau_vm_ops; - break; - - default: - ehca_err(cq->ib_cq.device, "bad resource type %x", - rsrc_type); - return -EINVAL; + ret = ehca_mmap_cq(vma, cq, rsrc_type); + if (unlikely(ret)) { + ehca_err(cq->ib_cq.device, + "ehca_mmap_cq() failed rc=%x cq_num=%x", + ret, cq->cq_number); + return ret; } break; @@ -262,50 +307,12 @@ int ehca_mmap(struct ib_ucontext *contex if (!qp->ib_qp.uobject || qp->ib_qp.uobject->context != context) return -EINVAL; - switch (rsrc_type) { - case 1: /* galpa fw handle */ - ehca_dbg(qp->ib_qp.device, "qp=%p qp triggerarea", qp); - vma->vm_flags |= VM_RESERVED; - vsize = vma->vm_end - vma->vm_start; - if (vsize != EHCA_PAGESIZE) { - ehca_err(qp->ib_qp.device, "invalid vsize=%lx", - vma->vm_end - vma->vm_start); - return -EINVAL; - } - - physical = qp->galpas.user.fw_handle; - vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot); - vma->vm_flags |= VM_IO | VM_RESERVED; - - ehca_dbg(qp->ib_qp.device, "vsize=%lx physical=%lx", - vsize, physical); - ret = remap_pfn_range(vma, vma->vm_start, - physical >> PAGE_SHIFT, vsize, - vma->vm_page_prot); - if (ret) { - ehca_err(qp->ib_qp.device, - "remap_pfn_range() failed ret=%x", - ret); - return -ENOMEM; - } - break; - - case 2: /* qp rqueue_addr */ - ehca_dbg(qp->ib_qp.device, "qp=%p qp rqueue_addr", qp); - vma->vm_flags |= VM_RESERVED; - vma->vm_ops = &ehcau_vm_ops; - break; - - case 3: /* qp squeue_addr */ - ehca_dbg(qp->ib_qp.device, "qp=%p qp squeue_addr", qp); - vma->vm_flags |= VM_RESERVED; - vma->vm_ops = &ehcau_vm_ops; - break; - - default: - ehca_err(qp->ib_qp.device, "bad resource type %x", - rsrc_type); - return -EINVAL; + ret = ehca_mmap_qp(vma, qp, rsrc_type); + if (unlikely(ret)) { + ehca_err(qp->ib_qp.device, + "ehca_mmap_qp() failed rc=%x qp_num=%x", + ret, qp->ib_qp.qp_num); + return ret; } break; @@ -316,77 +323,3 @@ int ehca_mmap(struct ib_ucontext *contex return 0; } - -int ehca_mmap_nopage(u64 foffset, u64 length, void **mapped, - struct vm_area_struct **vma) -{ - down_write(¤t->mm->mmap_sem); - *mapped = (void*)do_mmap(NULL,0, length, PROT_WRITE, - MAP_SHARED | MAP_ANONYMOUS, - foffset); - up_write(¤t->mm->mmap_sem); - if (!(*mapped)) { - ehca_gen_err("couldn't mmap foffset=%lx length=%lx", - foffset, length); - return -EINVAL; - } - - *vma = find_vma(current->mm, (u64)*mapped); - if (!(*vma)) { - down_write(¤t->mm->mmap_sem); - do_munmap(current->mm, 0, length); - up_write(¤t->mm->mmap_sem); - ehca_gen_err("couldn't find vma queue=%p", *mapped); - return -EINVAL; - } - (*vma)->vm_flags |= VM_RESERVED; - (*vma)->vm_ops = &ehcau_vm_ops; - - return 0; -} - -int ehca_mmap_register(u64 physical, void **mapped, - struct vm_area_struct **vma) -{ - int ret; - unsigned long vsize; - /* ehca hw supports only 4k page */ - ret = ehca_mmap_nopage(0, EHCA_PAGESIZE, mapped, vma); - if (ret) { - ehca_gen_err("could'nt mmap physical=%lx", physical); - return ret; - } - - (*vma)->vm_flags |= VM_RESERVED; - vsize = (*vma)->vm_end - (*vma)->vm_start; - if (vsize != EHCA_PAGESIZE) { - ehca_gen_err("invalid vsize=%lx", - (*vma)->vm_end - (*vma)->vm_start); - return -EINVAL; - } - - (*vma)->vm_page_prot = pgprot_noncached((*vma)->vm_page_prot); - (*vma)->vm_flags |= VM_IO | VM_RESERVED; - - ret = remap_pfn_range((*vma), (*vma)->vm_start, - physical >> PAGE_SHIFT, vsize, - (*vma)->vm_page_prot); - if (ret) { - ehca_gen_err("remap_pfn_range() failed ret=%x", ret); - return -ENOMEM; - } - - return 0; - -} - -int ehca_munmap(unsigned long addr, size_t len) { - int ret = 0; - struct mm_struct *mm = current->mm; - if (mm) { - down_write(&mm->mmap_sem); - ret = do_munmap(mm, addr, len); - up_write(&mm->mmap_sem); - } - return ret; -} diff --git a/drivers/infiniband/hw/ipath/ipath_diag.c b/drivers/infiniband/hw/ipath/ipath_diag.c index 28c087b..0f13a21 100644 --- a/drivers/infiniband/hw/ipath/ipath_diag.c +++ b/drivers/infiniband/hw/ipath/ipath_diag.c @@ -59,7 +59,7 @@ static ssize_t ipath_diag_read(struct fi static ssize_t ipath_diag_write(struct file *fp, const char __user *data, size_t count, loff_t *off); -static struct file_operations diag_file_ops = { +static const struct file_operations diag_file_ops = { .owner = THIS_MODULE, .write = ipath_diag_write, .read = ipath_diag_read, @@ -71,7 +71,7 @@ static ssize_t ipath_diagpkt_write(struc const char __user *data, size_t count, loff_t *off); -static struct file_operations diagpkt_file_ops = { +static const struct file_operations diagpkt_file_ops = { .owner = THIS_MODULE, .write = ipath_diagpkt_write, }; diff --git a/drivers/infiniband/hw/ipath/ipath_file_ops.c b/drivers/infiniband/hw/ipath/ipath_file_ops.c index b932bcb..5d64ff8 100644 --- a/drivers/infiniband/hw/ipath/ipath_file_ops.c +++ b/drivers/infiniband/hw/ipath/ipath_file_ops.c @@ -54,7 +54,7 @@ static ssize_t ipath_write(struct file * static unsigned int ipath_poll(struct file *, struct poll_table_struct *); static int ipath_mmap(struct file *, struct vm_area_struct *); -static struct file_operations ipath_file_ops = { +static const struct file_operations ipath_file_ops = { .owner = THIS_MODULE, .write = ipath_write, .open = ipath_open, @@ -2153,7 +2153,7 @@ bail: static struct class *ipath_class; -static int init_cdev(int minor, char *name, struct file_operations *fops, +static int init_cdev(int minor, char *name, const struct file_operations *fops, struct cdev **cdevp, struct class_device **class_devp) { const dev_t dev = MKDEV(IPATH_MAJOR, minor); @@ -2210,7 +2210,7 @@ done: return ret; } -int ipath_cdev_init(int minor, char *name, struct file_operations *fops, +int ipath_cdev_init(int minor, char *name, const struct file_operations *fops, struct cdev **cdevp, struct class_device **class_devp) { return init_cdev(minor, name, fops, cdevp, class_devp); diff --git a/drivers/infiniband/hw/ipath/ipath_fs.c b/drivers/infiniband/hw/ipath/ipath_fs.c index 79a60f0..5b40a84 100644 --- a/drivers/infiniband/hw/ipath/ipath_fs.c +++ b/drivers/infiniband/hw/ipath/ipath_fs.c @@ -47,7 +47,7 @@ #define IPATHFS_MAGIC 0x726a77 static struct super_block *ipath_super; static int ipathfs_mknod(struct inode *dir, struct dentry *dentry, - int mode, struct file_operations *fops, + int mode, const struct file_operations *fops, void *data) { int error; @@ -81,7 +81,7 @@ bail: static int create_file(const char *name, mode_t mode, struct dentry *parent, struct dentry **dentry, - struct file_operations *fops, void *data) + const struct file_operations *fops, void *data) { int error; @@ -105,7 +105,7 @@ static ssize_t atomic_stats_read(struct sizeof ipath_stats); } -static struct file_operations atomic_stats_ops = { +static const struct file_operations atomic_stats_ops = { .read = atomic_stats_read, }; @@ -127,7 +127,7 @@ static ssize_t atomic_counters_read(stru sizeof counters); } -static struct file_operations atomic_counters_ops = { +static const struct file_operations atomic_counters_ops = { .read = atomic_counters_read, }; @@ -166,7 +166,7 @@ static ssize_t atomic_node_info_read(str sizeof nodeinfo); } -static struct file_operations atomic_node_info_ops = { +static const struct file_operations atomic_node_info_ops = { .read = atomic_node_info_read, }; @@ -291,7 +291,7 @@ static ssize_t atomic_port_info_read(str sizeof portinfo); } -static struct file_operations atomic_port_info_ops = { +static const struct file_operations atomic_port_info_ops = { .read = atomic_port_info_read, }; @@ -394,7 +394,7 @@ bail: return ret; } -static struct file_operations flash_ops = { +static const struct file_operations flash_ops = { .read = flash_read, .write = flash_write, }; diff --git a/drivers/infiniband/hw/ipath/ipath_kernel.h b/drivers/infiniband/hw/ipath/ipath_kernel.h index 986b212..6d8d05f 100644 --- a/drivers/infiniband/hw/ipath/ipath_kernel.h +++ b/drivers/infiniband/hw/ipath/ipath_kernel.h @@ -593,7 +593,7 @@ void ipath_shutdown_device(struct ipath_ void ipath_disarm_senderrbufs(struct ipath_devdata *); struct file_operations; -int ipath_cdev_init(int minor, char *name, struct file_operations *fops, +int ipath_cdev_init(int minor, char *name, const struct file_operations *fops, struct cdev **cdevp, struct class_device **class_devp); void ipath_cdev_cleanup(struct cdev **cdevp, struct class_device **class_devp); diff --git a/drivers/infiniband/hw/ipath/ipath_qp.c b/drivers/infiniband/hw/ipath/ipath_qp.c index 46c1c89..64f07b1 100644 --- a/drivers/infiniband/hw/ipath/ipath_qp.c +++ b/drivers/infiniband/hw/ipath/ipath_qp.c @@ -379,7 +379,7 @@ void ipath_error_qp(struct ipath_qp *qp, wc.vendor_err = 0; wc.byte_len = 0; wc.imm_data = 0; - wc.qp_num = qp->ibqp.qp_num; + wc.qp = &qp->ibqp; wc.src_qp = 0; wc.wc_flags = 0; wc.pkey_index = 0; diff --git a/drivers/infiniband/hw/ipath/ipath_rc.c b/drivers/infiniband/hw/ipath/ipath_rc.c index ce60387..5ff20cb 100644 --- a/drivers/infiniband/hw/ipath/ipath_rc.c +++ b/drivers/infiniband/hw/ipath/ipath_rc.c @@ -702,7 +702,7 @@ void ipath_restart_rc(struct ipath_qp *q wc->opcode = ib_ipath_wc_opcode[wqe->wr.opcode]; wc->vendor_err = 0; wc->byte_len = 0; - wc->qp_num = qp->ibqp.qp_num; + wc->qp = &qp->ibqp; wc->src_qp = qp->remote_qpn; wc->pkey_index = 0; wc->slid = qp->remote_ah_attr.dlid; @@ -836,7 +836,7 @@ static int do_rc_ack(struct ipath_qp *qp wc.opcode = ib_ipath_wc_opcode[wqe->wr.opcode]; wc.vendor_err = 0; wc.byte_len = wqe->length; - wc.qp_num = qp->ibqp.qp_num; + wc.qp = &qp->ibqp; wc.src_qp = qp->remote_qpn; wc.pkey_index = 0; wc.slid = qp->remote_ah_attr.dlid; @@ -951,7 +951,7 @@ static int do_rc_ack(struct ipath_qp *qp wc.opcode = ib_ipath_wc_opcode[wqe->wr.opcode]; wc.vendor_err = 0; wc.byte_len = 0; - wc.qp_num = qp->ibqp.qp_num; + wc.qp = &qp->ibqp; wc.src_qp = qp->remote_qpn; wc.pkey_index = 0; wc.slid = qp->remote_ah_attr.dlid; @@ -1511,7 +1511,7 @@ void ipath_rc_rcv(struct ipath_ibdev *de wc.status = IB_WC_SUCCESS; wc.opcode = IB_WC_RECV; wc.vendor_err = 0; - wc.qp_num = qp->ibqp.qp_num; + wc.qp = &qp->ibqp; wc.src_qp = qp->remote_qpn; wc.pkey_index = 0; wc.slid = qp->remote_ah_attr.dlid; diff --git a/drivers/infiniband/hw/ipath/ipath_ruc.c b/drivers/infiniband/hw/ipath/ipath_ruc.c index f753051..e86cb17 100644 --- a/drivers/infiniband/hw/ipath/ipath_ruc.c +++ b/drivers/infiniband/hw/ipath/ipath_ruc.c @@ -137,7 +137,7 @@ bad_lkey: wc.vendor_err = 0; wc.byte_len = 0; wc.imm_data = 0; - wc.qp_num = qp->ibqp.qp_num; + wc.qp = &qp->ibqp; wc.src_qp = 0; wc.wc_flags = 0; wc.pkey_index = 0; @@ -336,7 +336,7 @@ again: wc.opcode = ib_ipath_wc_opcode[wqe->wr.opcode]; wc.vendor_err = 0; wc.byte_len = 0; - wc.qp_num = sqp->ibqp.qp_num; + wc.qp = &sqp->ibqp; wc.src_qp = sqp->remote_qpn; wc.pkey_index = 0; wc.slid = sqp->remote_ah_attr.dlid; @@ -426,7 +426,7 @@ again: wc.status = IB_WC_SUCCESS; wc.vendor_err = 0; wc.byte_len = wqe->length; - wc.qp_num = qp->ibqp.qp_num; + wc.qp = &qp->ibqp; wc.src_qp = qp->remote_qpn; /* XXX do we know which pkey matched? Only needed for GSI. */ wc.pkey_index = 0; @@ -447,7 +447,7 @@ send_comp: wc.opcode = ib_ipath_wc_opcode[wqe->wr.opcode]; wc.vendor_err = 0; wc.byte_len = wqe->length; - wc.qp_num = sqp->ibqp.qp_num; + wc.qp = &sqp->ibqp; wc.src_qp = 0; wc.pkey_index = 0; wc.slid = 0; diff --git a/drivers/infiniband/hw/ipath/ipath_uc.c b/drivers/infiniband/hw/ipath/ipath_uc.c index e636cfd..325d663 100644 --- a/drivers/infiniband/hw/ipath/ipath_uc.c +++ b/drivers/infiniband/hw/ipath/ipath_uc.c @@ -49,7 +49,7 @@ static void complete_last_send(struct ip wc->opcode = ib_ipath_wc_opcode[wqe->wr.opcode]; wc->vendor_err = 0; wc->byte_len = wqe->length; - wc->qp_num = qp->ibqp.qp_num; + wc->qp = &qp->ibqp; wc->src_qp = qp->remote_qpn; wc->pkey_index = 0; wc->slid = qp->remote_ah_attr.dlid; @@ -411,7 +411,7 @@ void ipath_uc_rcv(struct ipath_ibdev *de wc.status = IB_WC_SUCCESS; wc.opcode = IB_WC_RECV; wc.vendor_err = 0; - wc.qp_num = qp->ibqp.qp_num; + wc.qp = &qp->ibqp; wc.src_qp = qp->remote_qpn; wc.pkey_index = 0; wc.slid = qp->remote_ah_attr.dlid; diff --git a/drivers/infiniband/hw/ipath/ipath_ud.c b/drivers/infiniband/hw/ipath/ipath_ud.c index 49f1102..9a3e546 100644 --- a/drivers/infiniband/hw/ipath/ipath_ud.c +++ b/drivers/infiniband/hw/ipath/ipath_ud.c @@ -66,7 +66,7 @@ bad_lkey: wc.vendor_err = 0; wc.byte_len = 0; wc.imm_data = 0; - wc.qp_num = qp->ibqp.qp_num; + wc.qp = &qp->ibqp; wc.src_qp = 0; wc.wc_flags = 0; wc.pkey_index = 0; @@ -255,7 +255,7 @@ static void ipath_ud_loopback(struct ipa wc->status = IB_WC_SUCCESS; wc->opcode = IB_WC_RECV; wc->vendor_err = 0; - wc->qp_num = qp->ibqp.qp_num; + wc->qp = &qp->ibqp; wc->src_qp = sqp->ibqp.qp_num; /* XXX do we know which pkey matched? Only needed for GSI. */ wc->pkey_index = 0; @@ -474,7 +474,7 @@ done: wc.vendor_err = 0; wc.opcode = IB_WC_SEND; wc.byte_len = len; - wc.qp_num = qp->ibqp.qp_num; + wc.qp = &qp->ibqp; wc.src_qp = 0; wc.wc_flags = 0; /* XXX initialize other fields? */ @@ -651,7 +651,7 @@ void ipath_ud_rcv(struct ipath_ibdev *de wc.status = IB_WC_SUCCESS; wc.opcode = IB_WC_RECV; wc.vendor_err = 0; - wc.qp_num = qp->ibqp.qp_num; + wc.qp = &qp->ibqp; wc.src_qp = src_qp; /* XXX do we know which pkey matched? Only needed for GSI. */ wc.pkey_index = 0; diff --git a/drivers/infiniband/hw/mthca/mthca_cmd.c b/drivers/infiniband/hw/mthca/mthca_cmd.c index 768df72..7131446 100644 --- a/drivers/infiniband/hw/mthca/mthca_cmd.c +++ b/drivers/infiniband/hw/mthca/mthca_cmd.c @@ -1051,7 +1051,11 @@ #define QUERY_DEV_LIM_MAX_ICM_SZ_OFFSET MTHCA_GET(field, outbox, QUERY_DEV_LIM_MAX_EQ_OFFSET); dev_lim->max_eqs = 1 << (field & 0x7); MTHCA_GET(field, outbox, QUERY_DEV_LIM_RSVD_MTT_OFFSET); - dev_lim->reserved_mtts = 1 << (field >> 4); + if (mthca_is_memfree(dev)) + dev_lim->reserved_mtts = ALIGN((1 << (field >> 4)) * sizeof(u64), + MTHCA_MTT_SEG_SIZE) / MTHCA_MTT_SEG_SIZE; + else + dev_lim->reserved_mtts = 1 << (field >> 4); MTHCA_GET(field, outbox, QUERY_DEV_LIM_MAX_MRW_SZ_OFFSET); dev_lim->max_mrw_sz = 1 << field; MTHCA_GET(field, outbox, QUERY_DEV_LIM_RSVD_MRW_OFFSET); @@ -1854,7 +1858,7 @@ #define MAD_IFC_GRH_OFFSET 0x140 memset(inbox + 256, 0, 256); - MTHCA_PUT(inbox, in_wc->qp_num, MAD_IFC_MY_QPN_OFFSET); + MTHCA_PUT(inbox, in_wc->qp->qp_num, MAD_IFC_MY_QPN_OFFSET); MTHCA_PUT(inbox, in_wc->src_qp, MAD_IFC_RQPN_OFFSET); val = in_wc->sl << 4; diff --git a/drivers/infiniband/hw/mthca/mthca_cq.c b/drivers/infiniband/hw/mthca/mthca_cq.c index 1159c8a..efd79ef 100644 --- a/drivers/infiniband/hw/mthca/mthca_cq.c +++ b/drivers/infiniband/hw/mthca/mthca_cq.c @@ -534,7 +534,7 @@ static inline int mthca_poll_one(struct } } - entry->qp_num = (*cur_qp)->qpn; + entry->qp = &(*cur_qp)->ibqp; if (is_send) { wq = &(*cur_qp)->sq; diff --git a/drivers/infiniband/hw/mthca/mthca_dev.h b/drivers/infiniband/hw/mthca/mthca_dev.h index fe5cecf..b7e42ef 100644 --- a/drivers/infiniband/hw/mthca/mthca_dev.h +++ b/drivers/infiniband/hw/mthca/mthca_dev.h @@ -464,6 +464,8 @@ void mthca_uar_free(struct mthca_dev *de int mthca_pd_alloc(struct mthca_dev *dev, int privileged, struct mthca_pd *pd); void mthca_pd_free(struct mthca_dev *dev, struct mthca_pd *pd); +int mthca_write_mtt_size(struct mthca_dev *dev); + struct mthca_mtt *mthca_alloc_mtt(struct mthca_dev *dev, int size); void mthca_free_mtt(struct mthca_dev *dev, struct mthca_mtt *mtt); int mthca_write_mtt(struct mthca_dev *dev, struct mthca_mtt *mtt, diff --git a/drivers/infiniband/hw/mthca/mthca_main.c b/drivers/infiniband/hw/mthca/mthca_main.c index 44bc6cc..0d9b7d0 100644 --- a/drivers/infiniband/hw/mthca/mthca_main.c +++ b/drivers/infiniband/hw/mthca/mthca_main.c @@ -379,7 +379,7 @@ static int mthca_load_fw(struct mthca_de mdev->fw.arbel.fw_icm = mthca_alloc_icm(mdev, mdev->fw.arbel.fw_pages, - GFP_HIGHUSER | __GFP_NOWARN); + GFP_HIGHUSER | __GFP_NOWARN, 0); if (!mdev->fw.arbel.fw_icm) { mthca_err(mdev, "Couldn't allocate FW area, aborting.\n"); return -ENOMEM; @@ -412,7 +412,7 @@ err_unmap_fa: mthca_UNMAP_FA(mdev, &status); err_free: - mthca_free_icm(mdev, mdev->fw.arbel.fw_icm); + mthca_free_icm(mdev, mdev->fw.arbel.fw_icm, 0); return err; } @@ -441,7 +441,7 @@ static int mthca_init_icm(struct mthca_d (unsigned long long) aux_pages << 2); mdev->fw.arbel.aux_icm = mthca_alloc_icm(mdev, aux_pages, - GFP_HIGHUSER | __GFP_NOWARN); + GFP_HIGHUSER | __GFP_NOWARN, 0); if (!mdev->fw.arbel.aux_icm) { mthca_err(mdev, "Couldn't allocate aux memory, aborting.\n"); return -ENOMEM; @@ -464,10 +464,15 @@ static int mthca_init_icm(struct mthca_d goto err_unmap_aux; } + /* CPU writes to non-reserved MTTs, while HCA might DMA to reserved mtts */ + mdev->limits.reserved_mtts = ALIGN(mdev->limits.reserved_mtts * MTHCA_MTT_SEG_SIZE, + dma_get_cache_alignment()) / MTHCA_MTT_SEG_SIZE; + mdev->mr_table.mtt_table = mthca_alloc_icm_table(mdev, init_hca->mtt_base, MTHCA_MTT_SEG_SIZE, mdev->limits.num_mtt_segs, - mdev->limits.reserved_mtts, 1); + mdev->limits.reserved_mtts, + 1, 0); if (!mdev->mr_table.mtt_table) { mthca_err(mdev, "Failed to map MTT context memory, aborting.\n"); err = -ENOMEM; @@ -477,7 +482,8 @@ static int mthca_init_icm(struct mthca_d mdev->mr_table.mpt_table = mthca_alloc_icm_table(mdev, init_hca->mpt_base, dev_lim->mpt_entry_sz, mdev->limits.num_mpts, - mdev->limits.reserved_mrws, 1); + mdev->limits.reserved_mrws, + 1, 1); if (!mdev->mr_table.mpt_table) { mthca_err(mdev, "Failed to map MPT context memory, aborting.\n"); err = -ENOMEM; @@ -487,7 +493,8 @@ static int mthca_init_icm(struct mthca_d mdev->qp_table.qp_table = mthca_alloc_icm_table(mdev, init_hca->qpc_base, dev_lim->qpc_entry_sz, mdev->limits.num_qps, - mdev->limits.reserved_qps, 0); + mdev->limits.reserved_qps, + 0, 0); if (!mdev->qp_table.qp_table) { mthca_err(mdev, "Failed to map QP context memory, aborting.\n"); err = -ENOMEM; @@ -497,7 +504,8 @@ static int mthca_init_icm(struct mthca_d mdev->qp_table.eqp_table = mthca_alloc_icm_table(mdev, init_hca->eqpc_base, dev_lim->eqpc_entry_sz, mdev->limits.num_qps, - mdev->limits.reserved_qps, 0); + mdev->limits.reserved_qps, + 0, 0); if (!mdev->qp_table.eqp_table) { mthca_err(mdev, "Failed to map EQP context memory, aborting.\n"); err = -ENOMEM; @@ -507,7 +515,7 @@ static int mthca_init_icm(struct mthca_d mdev->qp_table.rdb_table = mthca_alloc_icm_table(mdev, init_hca->rdb_base, MTHCA_RDB_ENTRY_SIZE, mdev->limits.num_qps << - mdev->qp_table.rdb_shift, + mdev->qp_table.rdb_shift, 0, 0, 0); if (!mdev->qp_table.rdb_table) { mthca_err(mdev, "Failed to map RDB context memory, aborting\n"); @@ -518,7 +526,8 @@ static int mthca_init_icm(struct mthca_d mdev->cq_table.table = mthca_alloc_icm_table(mdev, init_hca->cqc_base, dev_lim->cqc_entry_sz, mdev->limits.num_cqs, - mdev->limits.reserved_cqs, 0); + mdev->limits.reserved_cqs, + 0, 0); if (!mdev->cq_table.table) { mthca_err(mdev, "Failed to map CQ context memory, aborting.\n"); err = -ENOMEM; @@ -530,7 +539,8 @@ static int mthca_init_icm(struct mthca_d mthca_alloc_icm_table(mdev, init_hca->srqc_base, dev_lim->srq_entry_sz, mdev->limits.num_srqs, - mdev->limits.reserved_srqs, 0); + mdev->limits.reserved_srqs, + 0, 0); if (!mdev->srq_table.table) { mthca_err(mdev, "Failed to map SRQ context memory, " "aborting.\n"); @@ -550,7 +560,7 @@ static int mthca_init_icm(struct mthca_d mdev->limits.num_amgms, mdev->limits.num_mgms + mdev->limits.num_amgms, - 0); + 0, 0); if (!mdev->mcg_table.table) { mthca_err(mdev, "Failed to map MCG context memory, aborting.\n"); err = -ENOMEM; @@ -588,7 +598,7 @@ err_unmap_aux: mthca_UNMAP_ICM_AUX(mdev, &status); err_free_aux: - mthca_free_icm(mdev, mdev->fw.arbel.aux_icm); + mthca_free_icm(mdev, mdev->fw.arbel.aux_icm, 0); return err; } @@ -609,7 +619,7 @@ static void mthca_free_icms(struct mthca mthca_unmap_eq_icm(mdev); mthca_UNMAP_ICM_AUX(mdev, &status); - mthca_free_icm(mdev, mdev->fw.arbel.aux_icm); + mthca_free_icm(mdev, mdev->fw.arbel.aux_icm, 0); } static int mthca_init_arbel(struct mthca_dev *mdev) @@ -693,7 +703,7 @@ err_free_icm: err_stop_fw: mthca_UNMAP_FA(mdev, &status); - mthca_free_icm(mdev, mdev->fw.arbel.fw_icm); + mthca_free_icm(mdev, mdev->fw.arbel.fw_icm, 0); err_disable: if (!(mdev->mthca_flags & MTHCA_FLAG_NO_LAM)) @@ -712,7 +722,7 @@ static void mthca_close_hca(struct mthca mthca_free_icms(mdev); mthca_UNMAP_FA(mdev, &status); - mthca_free_icm(mdev, mdev->fw.arbel.fw_icm); + mthca_free_icm(mdev, mdev->fw.arbel.fw_icm, 0); if (!(mdev->mthca_flags & MTHCA_FLAG_NO_LAM)) mthca_DISABLE_LAM(mdev, &status); diff --git a/drivers/infiniband/hw/mthca/mthca_memfree.c b/drivers/infiniband/hw/mthca/mthca_memfree.c index 6b19645..0b9d053 100644 --- a/drivers/infiniband/hw/mthca/mthca_memfree.c +++ b/drivers/infiniband/hw/mthca/mthca_memfree.c @@ -35,6 +35,9 @@ */ #include +#include + +#include #include "mthca_memfree.h" #include "mthca_dev.h" @@ -58,22 +61,42 @@ struct mthca_user_db_table { } page[0]; }; -void mthca_free_icm(struct mthca_dev *dev, struct mthca_icm *icm) +static void mthca_free_icm_pages(struct mthca_dev *dev, struct mthca_icm_chunk *chunk) +{ + int i; + + if (chunk->nsg > 0) + pci_unmap_sg(dev->pdev, chunk->mem, chunk->npages, + PCI_DMA_BIDIRECTIONAL); + + for (i = 0; i < chunk->npages; ++i) + __free_pages(chunk->mem[i].page, + get_order(chunk->mem[i].length)); +} + +static void mthca_free_icm_coherent(struct mthca_dev *dev, struct mthca_icm_chunk *chunk) { - struct mthca_icm_chunk *chunk, *tmp; int i; + for (i = 0; i < chunk->npages; ++i) { + dma_free_coherent(&dev->pdev->dev, chunk->mem[i].length, + lowmem_page_address(chunk->mem[i].page), + sg_dma_address(&chunk->mem[i])); + } +} + +void mthca_free_icm(struct mthca_dev *dev, struct mthca_icm *icm, int coherent) +{ + struct mthca_icm_chunk *chunk, *tmp; + if (!icm) return; list_for_each_entry_safe(chunk, tmp, &icm->chunk_list, list) { - if (chunk->nsg > 0) - pci_unmap_sg(dev->pdev, chunk->mem, chunk->npages, - PCI_DMA_BIDIRECTIONAL); - - for (i = 0; i < chunk->npages; ++i) - __free_pages(chunk->mem[i].page, - get_order(chunk->mem[i].length)); + if (coherent) + mthca_free_icm_coherent(dev, chunk); + else + mthca_free_icm_pages(dev, chunk); kfree(chunk); } @@ -81,12 +104,41 @@ void mthca_free_icm(struct mthca_dev *de kfree(icm); } +static int mthca_alloc_icm_pages(struct scatterlist *mem, int order, gfp_t gfp_mask) +{ + mem->page = alloc_pages(gfp_mask, order); + if (!mem->page) + return -ENOMEM; + + mem->length = PAGE_SIZE << order; + mem->offset = 0; + return 0; +} + +static int mthca_alloc_icm_coherent(struct device *dev, struct scatterlist *mem, + int order, gfp_t gfp_mask) +{ + void *buf = dma_alloc_coherent(dev, PAGE_SIZE << order, &sg_dma_address(mem), + gfp_mask); + if (!buf) + return -ENOMEM; + + sg_set_buf(mem, buf, PAGE_SIZE << order); + BUG_ON(mem->offset); + sg_dma_len(mem) = PAGE_SIZE << order; + return 0; +} + struct mthca_icm *mthca_alloc_icm(struct mthca_dev *dev, int npages, - gfp_t gfp_mask) + gfp_t gfp_mask, int coherent) { struct mthca_icm *icm; struct mthca_icm_chunk *chunk = NULL; int cur_order; + int ret; + + /* We use sg_set_buf for coherent allocs, which assumes low memory */ + BUG_ON(coherent && (gfp_mask & __GFP_HIGHMEM)); icm = kmalloc(sizeof *icm, gfp_mask & ~(__GFP_HIGHMEM | __GFP_NOWARN)); if (!icm) @@ -112,21 +164,28 @@ struct mthca_icm *mthca_alloc_icm(struct while (1 << cur_order > npages) --cur_order; - chunk->mem[chunk->npages].page = alloc_pages(gfp_mask, cur_order); - if (chunk->mem[chunk->npages].page) { - chunk->mem[chunk->npages].length = PAGE_SIZE << cur_order; - chunk->mem[chunk->npages].offset = 0; + if (coherent) + ret = mthca_alloc_icm_coherent(&dev->pdev->dev, + &chunk->mem[chunk->npages], + cur_order, gfp_mask); + else + ret = mthca_alloc_icm_pages(&chunk->mem[chunk->npages], + cur_order, gfp_mask); - if (++chunk->npages == MTHCA_ICM_CHUNK_LEN) { + if (!ret) { + ++chunk->npages; + + if (!coherent && chunk->npages == MTHCA_ICM_CHUNK_LEN) { chunk->nsg = pci_map_sg(dev->pdev, chunk->mem, chunk->npages, PCI_DMA_BIDIRECTIONAL); if (chunk->nsg <= 0) goto fail; + } + if (chunk->npages == MTHCA_ICM_CHUNK_LEN) chunk = NULL; - } npages -= 1 << cur_order; } else { @@ -136,7 +195,7 @@ struct mthca_icm *mthca_alloc_icm(struct } } - if (chunk) { + if (!coherent && chunk) { chunk->nsg = pci_map_sg(dev->pdev, chunk->mem, chunk->npages, PCI_DMA_BIDIRECTIONAL); @@ -148,7 +207,7 @@ struct mthca_icm *mthca_alloc_icm(struct return icm; fail: - mthca_free_icm(dev, icm); + mthca_free_icm(dev, icm, coherent); return NULL; } @@ -167,7 +226,7 @@ int mthca_table_get(struct mthca_dev *de table->icm[i] = mthca_alloc_icm(dev, MTHCA_TABLE_CHUNK_SIZE >> PAGE_SHIFT, (table->lowmem ? GFP_KERNEL : GFP_HIGHUSER) | - __GFP_NOWARN); + __GFP_NOWARN, table->coherent); if (!table->icm[i]) { ret = -ENOMEM; goto out; @@ -175,7 +234,7 @@ int mthca_table_get(struct mthca_dev *de if (mthca_MAP_ICM(dev, table->icm[i], table->virt + i * MTHCA_TABLE_CHUNK_SIZE, &status) || status) { - mthca_free_icm(dev, table->icm[i]); + mthca_free_icm(dev, table->icm[i], table->coherent); table->icm[i] = NULL; ret = -ENOMEM; goto out; @@ -204,16 +263,16 @@ void mthca_table_put(struct mthca_dev *d mthca_UNMAP_ICM(dev, table->virt + i * MTHCA_TABLE_CHUNK_SIZE, MTHCA_TABLE_CHUNK_SIZE / MTHCA_ICM_PAGE_SIZE, &status); - mthca_free_icm(dev, table->icm[i]); + mthca_free_icm(dev, table->icm[i], table->coherent); table->icm[i] = NULL; } mutex_unlock(&table->mutex); } -void *mthca_table_find(struct mthca_icm_table *table, int obj) +void *mthca_table_find(struct mthca_icm_table *table, int obj, dma_addr_t *dma_handle) { - int idx, offset, i; + int idx, offset, dma_offset, i; struct mthca_icm_chunk *chunk; struct mthca_icm *icm; struct page *page = NULL; @@ -225,13 +284,22 @@ void *mthca_table_find(struct mthca_icm_ idx = (obj & (table->num_obj - 1)) * table->obj_size; icm = table->icm[idx / MTHCA_TABLE_CHUNK_SIZE]; - offset = idx % MTHCA_TABLE_CHUNK_SIZE; + dma_offset = offset = idx % MTHCA_TABLE_CHUNK_SIZE; if (!icm) goto out; list_for_each_entry(chunk, &icm->chunk_list, list) { for (i = 0; i < chunk->npages; ++i) { + if (dma_handle && dma_offset >= 0) { + if (sg_dma_len(&chunk->mem[i]) > dma_offset) + *dma_handle = sg_dma_address(&chunk->mem[i]) + + dma_offset; + dma_offset -= sg_dma_len(&chunk->mem[i]); + } + /* DMA mapping can merge pages but not split them, + * so if we found the page, dma_handle has already + * been assigned to. */ if (chunk->mem[i].length > offset) { page = chunk->mem[i].page; goto out; @@ -283,7 +351,7 @@ void mthca_table_put_range(struct mthca_ struct mthca_icm_table *mthca_alloc_icm_table(struct mthca_dev *dev, u64 virt, int obj_size, int nobj, int reserved, - int use_lowmem) + int use_lowmem, int use_coherent) { struct mthca_icm_table *table; int num_icm; @@ -302,6 +370,7 @@ struct mthca_icm_table *mthca_alloc_icm_ table->num_obj = nobj; table->obj_size = obj_size; table->lowmem = use_lowmem; + table->coherent = use_coherent; mutex_init(&table->mutex); for (i = 0; i < num_icm; ++i) @@ -314,12 +383,12 @@ struct mthca_icm_table *mthca_alloc_icm_ table->icm[i] = mthca_alloc_icm(dev, chunk_size >> PAGE_SHIFT, (use_lowmem ? GFP_KERNEL : GFP_HIGHUSER) | - __GFP_NOWARN); + __GFP_NOWARN, use_coherent); if (!table->icm[i]) goto err; if (mthca_MAP_ICM(dev, table->icm[i], virt + i * MTHCA_TABLE_CHUNK_SIZE, &status) || status) { - mthca_free_icm(dev, table->icm[i]); + mthca_free_icm(dev, table->icm[i], table->coherent); table->icm[i] = NULL; goto err; } @@ -339,7 +408,7 @@ err: mthca_UNMAP_ICM(dev, virt + i * MTHCA_TABLE_CHUNK_SIZE, MTHCA_TABLE_CHUNK_SIZE / MTHCA_ICM_PAGE_SIZE, &status); - mthca_free_icm(dev, table->icm[i]); + mthca_free_icm(dev, table->icm[i], table->coherent); } kfree(table); @@ -357,7 +426,7 @@ void mthca_free_icm_table(struct mthca_d mthca_UNMAP_ICM(dev, table->virt + i * MTHCA_TABLE_CHUNK_SIZE, MTHCA_TABLE_CHUNK_SIZE / MTHCA_ICM_PAGE_SIZE, &status); - mthca_free_icm(dev, table->icm[i]); + mthca_free_icm(dev, table->icm[i], table->coherent); } kfree(table); diff --git a/drivers/infiniband/hw/mthca/mthca_memfree.h b/drivers/infiniband/hw/mthca/mthca_memfree.h index 6d42947..5941441 100644 --- a/drivers/infiniband/hw/mthca/mthca_memfree.h +++ b/drivers/infiniband/hw/mthca/mthca_memfree.h @@ -69,6 +69,7 @@ struct mthca_icm_table { int num_obj; int obj_size; int lowmem; + int coherent; struct mutex mutex; struct mthca_icm *icm[0]; }; @@ -82,17 +83,17 @@ struct mthca_icm_iter { struct mthca_dev; struct mthca_icm *mthca_alloc_icm(struct mthca_dev *dev, int npages, - gfp_t gfp_mask); -void mthca_free_icm(struct mthca_dev *dev, struct mthca_icm *icm); + gfp_t gfp_mask, int coherent); +void mthca_free_icm(struct mthca_dev *dev, struct mthca_icm *icm, int coherent); struct mthca_icm_table *mthca_alloc_icm_table(struct mthca_dev *dev, u64 virt, int obj_size, int nobj, int reserved, - int use_lowmem); + int use_lowmem, int use_coherent); void mthca_free_icm_table(struct mthca_dev *dev, struct mthca_icm_table *table); int mthca_table_get(struct mthca_dev *dev, struct mthca_icm_table *table, int obj); void mthca_table_put(struct mthca_dev *dev, struct mthca_icm_table *table, int obj); -void *mthca_table_find(struct mthca_icm_table *table, int obj); +void *mthca_table_find(struct mthca_icm_table *table, int obj, dma_addr_t *dma_handle); int mthca_table_get_range(struct mthca_dev *dev, struct mthca_icm_table *table, int start, int end); void mthca_table_put_range(struct mthca_dev *dev, struct mthca_icm_table *table, diff --git a/drivers/infiniband/hw/mthca/mthca_mr.c b/drivers/infiniband/hw/mthca/mthca_mr.c index f71ffa8..6037dd3 100644 --- a/drivers/infiniband/hw/mthca/mthca_mr.c +++ b/drivers/infiniband/hw/mthca/mthca_mr.c @@ -243,8 +243,8 @@ void mthca_free_mtt(struct mthca_dev *de kfree(mtt); } -int mthca_write_mtt(struct mthca_dev *dev, struct mthca_mtt *mtt, - int start_index, u64 *buffer_list, int list_len) +static int __mthca_write_mtt(struct mthca_dev *dev, struct mthca_mtt *mtt, + int start_index, u64 *buffer_list, int list_len) { struct mthca_mailbox *mailbox; __be64 *mtt_entry; @@ -295,6 +295,84 @@ out: return err; } +int mthca_write_mtt_size(struct mthca_dev *dev) +{ + if (dev->mr_table.fmr_mtt_buddy != &dev->mr_table.mtt_buddy) + /* + * Be friendly to WRITE_MTT command + * and leave two empty slots for the + * index and reserved fields of the + * mailbox. + */ + return PAGE_SIZE / sizeof (u64) - 2; + + /* For Arbel, all MTTs must fit in the same page. */ + return mthca_is_memfree(dev) ? (PAGE_SIZE / sizeof (u64)) : 0x7ffffff; +} + +void mthca_tavor_write_mtt_seg(struct mthca_dev *dev, struct mthca_mtt *mtt, + int start_index, u64 *buffer_list, int list_len) +{ + u64 __iomem *mtts; + int i; + + mtts = dev->mr_table.tavor_fmr.mtt_base + mtt->first_seg * MTHCA_MTT_SEG_SIZE + + start_index * sizeof (u64); + for (i = 0; i < list_len; ++i) + mthca_write64_raw(cpu_to_be64(buffer_list[i] | MTHCA_MTT_FLAG_PRESENT), + mtts + i); +} + +void mthca_arbel_write_mtt_seg(struct mthca_dev *dev, struct mthca_mtt *mtt, + int start_index, u64 *buffer_list, int list_len) +{ + __be64 *mtts; + dma_addr_t dma_handle; + int i; + int s = start_index * sizeof (u64); + + /* For Arbel, all MTTs must fit in the same page. */ + BUG_ON(s / PAGE_SIZE != (s + list_len * sizeof(u64) - 1) / PAGE_SIZE); + /* Require full segments */ + BUG_ON(s % MTHCA_MTT_SEG_SIZE); + + mtts = mthca_table_find(dev->mr_table.mtt_table, mtt->first_seg + + s / MTHCA_MTT_SEG_SIZE, &dma_handle); + + BUG_ON(!mtts); + + for (i = 0; i < list_len; ++i) + mtts[i] = cpu_to_be64(buffer_list[i] | MTHCA_MTT_FLAG_PRESENT); + + dma_sync_single(&dev->pdev->dev, dma_handle, list_len * sizeof (u64), DMA_TO_DEVICE); +} + +int mthca_write_mtt(struct mthca_dev *dev, struct mthca_mtt *mtt, + int start_index, u64 *buffer_list, int list_len) +{ + int size = mthca_write_mtt_size(dev); + int chunk; + + if (dev->mr_table.fmr_mtt_buddy != &dev->mr_table.mtt_buddy) + return __mthca_write_mtt(dev, mtt, start_index, buffer_list, list_len); + + while (list_len > 0) { + chunk = min(size, list_len); + if (mthca_is_memfree(dev)) + mthca_arbel_write_mtt_seg(dev, mtt, start_index, + buffer_list, chunk); + else + mthca_tavor_write_mtt_seg(dev, mtt, start_index, + buffer_list, chunk); + + list_len -= chunk; + start_index += chunk; + buffer_list += chunk; + } + + return 0; +} + static inline u32 tavor_hw_index_to_key(u32 ind) { return ind; @@ -524,7 +602,7 @@ int mthca_fmr_alloc(struct mthca_dev *de if (err) goto err_out_mpt_free; - mr->mem.arbel.mpt = mthca_table_find(dev->mr_table.mpt_table, key); + mr->mem.arbel.mpt = mthca_table_find(dev->mr_table.mpt_table, key, NULL); BUG_ON(!mr->mem.arbel.mpt); } else mr->mem.tavor.mpt = dev->mr_table.tavor_fmr.mpt_base + @@ -538,7 +616,8 @@ int mthca_fmr_alloc(struct mthca_dev *de if (mthca_is_memfree(dev)) { mr->mem.arbel.mtts = mthca_table_find(dev->mr_table.mtt_table, - mr->mtt->first_seg); + mr->mtt->first_seg, + &mr->mem.arbel.dma_handle); BUG_ON(!mr->mem.arbel.mtts); } else mr->mem.tavor.mtts = dev->mr_table.tavor_fmr.mtt_base + mtt_seg; @@ -712,6 +791,9 @@ int mthca_arbel_map_phys_fmr(struct ib_f fmr->mem.arbel.mtts[i] = cpu_to_be64(page_list[i] | MTHCA_MTT_FLAG_PRESENT); + dma_sync_single(&dev->pdev->dev, fmr->mem.arbel.dma_handle, + list_len * sizeof(u64), DMA_TO_DEVICE); + fmr->mem.arbel.mpt->key = cpu_to_be32(key); fmr->mem.arbel.mpt->lkey = cpu_to_be32(key); fmr->mem.arbel.mpt->length = cpu_to_be64(list_len * (1ull << fmr->attr.page_shift)); @@ -761,7 +843,7 @@ void mthca_arbel_fmr_unmap(struct mthca_ int mthca_init_mr_table(struct mthca_dev *dev) { unsigned long addr; - int err, i; + int mpts, mtts, err, i; err = mthca_alloc_init(&dev->mr_table.mpt_alloc, dev->limits.num_mpts, @@ -795,13 +877,21 @@ int mthca_init_mr_table(struct mthca_dev err = -EINVAL; goto err_fmr_mpt; } + mpts = mtts = 1 << i; + } else { + mpts = dev->limits.num_mtt_segs; + mtts = dev->limits.num_mpts; + } + + if (!mthca_is_memfree(dev) && + (dev->mthca_flags & MTHCA_FLAG_FMR)) { addr = pci_resource_start(dev->pdev, 4) + ((pci_resource_len(dev->pdev, 4) - 1) & dev->mr_table.mpt_base); dev->mr_table.tavor_fmr.mpt_base = - ioremap(addr, (1 << i) * sizeof(struct mthca_mpt_entry)); + ioremap(addr, mpts * sizeof(struct mthca_mpt_entry)); if (!dev->mr_table.tavor_fmr.mpt_base) { mthca_warn(dev, "MPT ioremap for FMR failed.\n"); @@ -814,19 +904,21 @@ int mthca_init_mr_table(struct mthca_dev dev->mr_table.mtt_base); dev->mr_table.tavor_fmr.mtt_base = - ioremap(addr, (1 << i) * MTHCA_MTT_SEG_SIZE); + ioremap(addr, mtts * MTHCA_MTT_SEG_SIZE); if (!dev->mr_table.tavor_fmr.mtt_base) { mthca_warn(dev, "MTT ioremap for FMR failed.\n"); err = -ENOMEM; goto err_fmr_mtt; } + } - err = mthca_buddy_init(&dev->mr_table.tavor_fmr.mtt_buddy, i); + if (dev->limits.fmr_reserved_mtts) { + err = mthca_buddy_init(&dev->mr_table.tavor_fmr.mtt_buddy, fls(mtts - 1)); if (err) goto err_fmr_mtt_buddy; /* Prevent regular MRs from using FMR keys */ - err = mthca_buddy_alloc(&dev->mr_table.mtt_buddy, i); + err = mthca_buddy_alloc(&dev->mr_table.mtt_buddy, fls(mtts - 1)); if (err) goto err_reserve_fmr; diff --git a/drivers/infiniband/hw/mthca/mthca_profile.c b/drivers/infiniband/hw/mthca/mthca_profile.c index 58d44aa..26bf86d 100644 --- a/drivers/infiniband/hw/mthca/mthca_profile.c +++ b/drivers/infiniband/hw/mthca/mthca_profile.c @@ -277,7 +277,7 @@ u64 mthca_make_profile(struct mthca_dev * out of the MR pool. They don't use additional memory, but * we assign them as part of the HCA profile anyway. */ - if (mthca_is_memfree(dev)) + if (mthca_is_memfree(dev) || BITS_PER_LONG == 64) dev->limits.fmr_reserved_mtts = 0; else dev->limits.fmr_reserved_mtts = request->fmr_reserved_mtts; diff --git a/drivers/infiniband/hw/mthca/mthca_provider.c b/drivers/infiniband/hw/mthca/mthca_provider.c index 7b96751..0725ad7 100644 --- a/drivers/infiniband/hw/mthca/mthca_provider.c +++ b/drivers/infiniband/hw/mthca/mthca_provider.c @@ -1015,6 +1015,7 @@ static struct ib_mr *mthca_reg_user_mr(s int shift, n, len; int i, j, k; int err = 0; + int write_mtt_size; shift = ffs(region->page_size) - 1; @@ -1040,6 +1041,8 @@ static struct ib_mr *mthca_reg_user_mr(s i = n = 0; + write_mtt_size = min(mthca_write_mtt_size(dev), (int) (PAGE_SIZE / sizeof *pages)); + list_for_each_entry(chunk, ®ion->chunk_list, list) for (j = 0; j < chunk->nmap; ++j) { len = sg_dma_len(&chunk->page_list[j]) >> shift; @@ -1047,14 +1050,11 @@ static struct ib_mr *mthca_reg_user_mr(s pages[i++] = sg_dma_address(&chunk->page_list[j]) + region->page_size * k; /* - * Be friendly to WRITE_MTT command - * and leave two empty slots for the - * index and reserved fields of the - * mailbox. + * Be friendly to write_mtt and pass it chunks + * of appropriate size. */ - if (i == PAGE_SIZE / sizeof (u64) - 2) { - err = mthca_write_mtt(dev, mr->mtt, - n, pages, i); + if (i == write_mtt_size) { + err = mthca_write_mtt(dev, mr->mtt, n, pages, i); if (err) goto mtt_done; n += i; diff --git a/drivers/infiniband/hw/mthca/mthca_provider.h b/drivers/infiniband/hw/mthca/mthca_provider.h index 9a5bece..1d266ac 100644 --- a/drivers/infiniband/hw/mthca/mthca_provider.h +++ b/drivers/infiniband/hw/mthca/mthca_provider.h @@ -89,6 +89,7 @@ struct mthca_fmr { struct { struct mthca_mpt_entry *mpt; __be64 *mtts; + dma_addr_t dma_handle; } arbel; } mem; }; diff --git a/drivers/infiniband/hw/mthca/mthca_qp.c b/drivers/infiniband/hw/mthca/mthca_qp.c index 5f5214c..224c93d 100644 --- a/drivers/infiniband/hw/mthca/mthca_qp.c +++ b/drivers/infiniband/hw/mthca/mthca_qp.c @@ -399,7 +399,7 @@ static int to_ib_qp_access_flags(int mth static void to_ib_ah_attr(struct mthca_dev *dev, struct ib_ah_attr *ib_ah_attr, struct mthca_qp_path *path) { - memset(ib_ah_attr, 0, sizeof *path); + memset(ib_ah_attr, 0, sizeof *ib_ah_attr); ib_ah_attr->port_num = (be32_to_cpu(path->port_pkey) >> 24) & 0x3; if (ib_ah_attr->port_num == 0 || ib_ah_attr->port_num > dev->limits.num_ports) diff --git a/drivers/infiniband/hw/mthca/mthca_srq.c b/drivers/infiniband/hw/mthca/mthca_srq.c index 10684da..61974b0 100644 --- a/drivers/infiniband/hw/mthca/mthca_srq.c +++ b/drivers/infiniband/hw/mthca/mthca_srq.c @@ -116,11 +116,16 @@ static void mthca_arbel_init_srq_context struct mthca_srq *srq, struct mthca_arbel_srq_context *context) { - int logsize; + int logsize, max; memset(context, 0, sizeof *context); - logsize = ilog2(srq->max); + /* + * Put max in a temporary variable to work around gcc bug + * triggered by ilog2() on sparc64. + */ + max = srq->max; + logsize = ilog2(max); context->state_logsize_srqn = cpu_to_be32(logsize << 24 | srq->srqn); context->lkey = cpu_to_be32(srq->mr.ibmr.lkey); context->db_index = cpu_to_be32(srq->db_index); diff --git a/drivers/infiniband/ulp/ipoib/Kconfig b/drivers/infiniband/ulp/ipoib/Kconfig index c75322d..af78ccc 100644 --- a/drivers/infiniband/ulp/ipoib/Kconfig +++ b/drivers/infiniband/ulp/ipoib/Kconfig @@ -1,6 +1,6 @@ config INFINIBAND_IPOIB tristate "IP-over-InfiniBand" - depends on INFINIBAND && NETDEVICES && INET + depends on INFINIBAND && NETDEVICES && INET && (IPV6 || IPV6=n) ---help--- Support for the IP-over-InfiniBand protocol (IPoIB). This transports IP packets over InfiniBand so you can use your IB @@ -8,6 +8,20 @@ config INFINIBAND_IPOIB See Documentation/infiniband/ipoib.txt for more information +config INFINIBAND_IPOIB_CM + bool "IP-over-InfiniBand Connected Mode support" + depends on INFINIBAND_IPOIB && EXPERIMENTAL + default n + ---help--- + This option enables experimental support for IPoIB connected mode. + After enabling this option, you need to switch to connected mode through + /sys/class/net/ibXXX/mode to actually create connections, and then increase + the interface MTU with e.g. ifconfig ib0 mtu 65520. + + WARNING: Enabling connected mode will trigger some + packet drops for multicast and UD mode traffic from this interface, + unless you limit mtu for these destinations to 2044. + config INFINIBAND_IPOIB_DEBUG bool "IP-over-InfiniBand debugging" if EMBEDDED depends on INFINIBAND_IPOIB diff --git a/drivers/infiniband/ulp/ipoib/Makefile b/drivers/infiniband/ulp/ipoib/Makefile index 8935e74..98ee38e 100644 --- a/drivers/infiniband/ulp/ipoib/Makefile +++ b/drivers/infiniband/ulp/ipoib/Makefile @@ -5,5 +5,6 @@ ib_ipoib-y := ipoib_main.o \ ipoib_multicast.o \ ipoib_verbs.o \ ipoib_vlan.o +ib_ipoib-$(CONFIG_INFINIBAND_IPOIB_CM) += ipoib_cm.o ib_ipoib-$(CONFIG_INFINIBAND_IPOIB_DEBUG) += ipoib_fs.o diff --git a/drivers/infiniband/ulp/ipoib/ipoib.h b/drivers/infiniband/ulp/ipoib/ipoib.h index 07deee8..2594db2 100644 --- a/drivers/infiniband/ulp/ipoib/ipoib.h +++ b/drivers/infiniband/ulp/ipoib/ipoib.h @@ -62,6 +62,10 @@ enum { IPOIB_ENCAP_LEN = 4, + IPOIB_CM_MTU = 0x10000 - 0x10, /* padding to align header to 16 */ + IPOIB_CM_BUF_SIZE = IPOIB_CM_MTU + IPOIB_ENCAP_LEN, + IPOIB_CM_HEAD_SIZE = IPOIB_CM_BUF_SIZE % PAGE_SIZE, + IPOIB_CM_RX_SG = ALIGN(IPOIB_CM_BUF_SIZE, PAGE_SIZE) / PAGE_SIZE, IPOIB_RX_RING_SIZE = 128, IPOIB_TX_RING_SIZE = 64, IPOIB_MAX_QUEUE_SIZE = 8192, @@ -81,6 +85,8 @@ enum { IPOIB_MCAST_RUN = 6, IPOIB_STOP_REAPER = 7, IPOIB_MCAST_STARTED = 8, + IPOIB_FLAG_NETIF_STOPPED = 9, + IPOIB_FLAG_ADMIN_CM = 10, IPOIB_MAX_BACKOFF_SECONDS = 16, @@ -90,6 +96,13 @@ enum { IPOIB_MCAST_FLAG_ATTACHED = 3, }; +#define IPOIB_OP_RECV (1ul << 31) +#ifdef CONFIG_INFINIBAND_IPOIB_CM +#define IPOIB_CM_OP_SRQ (1ul << 30) +#else +#define IPOIB_CM_OP_SRQ (0) +#endif + /* structs */ struct ipoib_header { @@ -113,6 +126,59 @@ struct ipoib_tx_buf { u64 mapping; }; +struct ib_cm_id; + +struct ipoib_cm_data { + __be32 qpn; /* High byte MUST be ignored on receive */ + __be32 mtu; +}; + +struct ipoib_cm_rx { + struct ib_cm_id *id; + struct ib_qp *qp; + struct list_head list; + struct net_device *dev; + unsigned long jiffies; +}; + +struct ipoib_cm_tx { + struct ib_cm_id *id; + struct ib_cq *cq; + struct ib_qp *qp; + struct list_head list; + struct net_device *dev; + struct ipoib_neigh *neigh; + struct ipoib_path *path; + struct ipoib_tx_buf *tx_ring; + unsigned tx_head; + unsigned tx_tail; + unsigned long flags; + u32 mtu; + struct ib_wc ibwc[IPOIB_NUM_WC]; +}; + +struct ipoib_cm_rx_buf { + struct sk_buff *skb; + u64 mapping[IPOIB_CM_RX_SG]; +}; + +struct ipoib_cm_dev_priv { + struct ib_srq *srq; + struct ipoib_cm_rx_buf *srq_ring; + struct ib_cm_id *id; + struct list_head passive_ids; + struct work_struct start_task; + struct work_struct reap_task; + struct work_struct skb_task; + struct delayed_work stale_task; + struct sk_buff_head skb_queue; + struct list_head start_list; + struct list_head reap_list; + struct ib_wc ibwc[IPOIB_NUM_WC]; + struct ib_sge rx_sge[IPOIB_CM_RX_SG]; + struct ib_recv_wr rx_wr; +}; + /* * Device private locking: tx_lock protects members used in TX fast * path (and we use LLTX so upper layers don't do extra locking). @@ -179,6 +245,10 @@ struct ipoib_dev_priv { struct list_head child_intfs; struct list_head list; +#ifdef CONFIG_INFINIBAND_IPOIB_CM + struct ipoib_cm_dev_priv cm; +#endif + #ifdef CONFIG_INFINIBAND_IPOIB_DEBUG struct list_head fs_list; struct dentry *mcg_dentry; @@ -212,6 +282,9 @@ struct ipoib_path { struct ipoib_neigh { struct ipoib_ah *ah; +#ifdef CONFIG_INFINIBAND_IPOIB_CM + struct ipoib_cm_tx *cm; +#endif union ib_gid dgid; struct sk_buff_head queue; @@ -315,6 +388,146 @@ int ipoib_vlan_delete(struct net_device void ipoib_pkey_poll(struct work_struct *work); int ipoib_pkey_dev_delay_open(struct net_device *dev); +#ifdef CONFIG_INFINIBAND_IPOIB_CM + +#define IPOIB_FLAGS_RC 0x80 +#define IPOIB_FLAGS_UC 0x40 + +/* We don't support UC connections at the moment */ +#define IPOIB_CM_SUPPORTED(ha) (ha[0] & (IPOIB_FLAGS_RC)) + +static inline int ipoib_cm_admin_enabled(struct net_device *dev) +{ + struct ipoib_dev_priv *priv = netdev_priv(dev); + return IPOIB_CM_SUPPORTED(dev->dev_addr) && + test_bit(IPOIB_FLAG_ADMIN_CM, &priv->flags); +} + +static inline int ipoib_cm_enabled(struct net_device *dev, struct neighbour *n) +{ + struct ipoib_dev_priv *priv = netdev_priv(dev); + return IPOIB_CM_SUPPORTED(n->ha) && + test_bit(IPOIB_FLAG_ADMIN_CM, &priv->flags); +} + +static inline int ipoib_cm_up(struct ipoib_neigh *neigh) + +{ + return test_bit(IPOIB_FLAG_OPER_UP, &neigh->cm->flags); +} + +static inline struct ipoib_cm_tx *ipoib_cm_get(struct ipoib_neigh *neigh) +{ + return neigh->cm; +} + +static inline void ipoib_cm_set(struct ipoib_neigh *neigh, struct ipoib_cm_tx *tx) +{ + neigh->cm = tx; +} + +void ipoib_cm_send(struct net_device *dev, struct sk_buff *skb, struct ipoib_cm_tx *tx); +int ipoib_cm_dev_open(struct net_device *dev); +void ipoib_cm_dev_stop(struct net_device *dev); +int ipoib_cm_dev_init(struct net_device *dev); +int ipoib_cm_add_mode_attr(struct net_device *dev); +void ipoib_cm_dev_cleanup(struct net_device *dev); +struct ipoib_cm_tx *ipoib_cm_create_tx(struct net_device *dev, struct ipoib_path *path, + struct ipoib_neigh *neigh); +void ipoib_cm_destroy_tx(struct ipoib_cm_tx *tx); +void ipoib_cm_skb_too_long(struct net_device* dev, struct sk_buff *skb, + unsigned int mtu); +void ipoib_cm_handle_rx_wc(struct net_device *dev, struct ib_wc *wc); +#else + +struct ipoib_cm_tx; + +static inline int ipoib_cm_admin_enabled(struct net_device *dev) +{ + return 0; +} +static inline int ipoib_cm_enabled(struct net_device *dev, struct neighbour *n) + +{ + return 0; +} + +static inline int ipoib_cm_up(struct ipoib_neigh *neigh) + +{ + return 0; +} + +static inline struct ipoib_cm_tx *ipoib_cm_get(struct ipoib_neigh *neigh) +{ + return NULL; +} + +static inline void ipoib_cm_set(struct ipoib_neigh *neigh, struct ipoib_cm_tx *tx) +{ +} + +static inline +void ipoib_cm_send(struct net_device *dev, struct sk_buff *skb, struct ipoib_cm_tx *tx) +{ + return; +} + +static inline +int ipoib_cm_dev_open(struct net_device *dev) +{ + return 0; +} + +static inline +void ipoib_cm_dev_stop(struct net_device *dev) +{ + return; +} + +static inline +int ipoib_cm_dev_init(struct net_device *dev) +{ + return -ENOSYS; +} + +static inline +void ipoib_cm_dev_cleanup(struct net_device *dev) +{ + return; +} + +static inline +struct ipoib_cm_tx *ipoib_cm_create_tx(struct net_device *dev, struct ipoib_path *path, + struct ipoib_neigh *neigh) +{ + return NULL; +} + +static inline +void ipoib_cm_destroy_tx(struct ipoib_cm_tx *tx) +{ + return; +} + +static inline +int ipoib_cm_add_mode_attr(struct net_device *dev) +{ + return 0; +} + +static inline void ipoib_cm_skb_too_long(struct net_device* dev, struct sk_buff *skb, + unsigned int mtu) +{ + dev_kfree_skb_any(skb); +} + +static inline void ipoib_cm_handle_rx_wc(struct net_device *dev, struct ib_wc *wc) +{ +} + +#endif + #ifdef CONFIG_INFINIBAND_IPOIB_DEBUG void ipoib_create_debug_files(struct net_device *dev); void ipoib_delete_debug_files(struct net_device *dev); @@ -392,4 +605,6 @@ #define IPOIB_GID_RAW_ARG(gid) ((u8 *)(g #define IPOIB_GID_ARG(gid) IPOIB_GID_RAW_ARG((gid).raw) +#define IPOIB_QPN(ha) (be32_to_cpup((__be32 *) ha) & 0xffffff) + #endif /* _IPOIB_H */ diff --git a/drivers/infiniband/ulp/ipoib/ipoib_cm.c b/drivers/infiniband/ulp/ipoib/ipoib_cm.c new file mode 100644 index 0000000..2d48387 --- /dev/null +++ b/drivers/infiniband/ulp/ipoib/ipoib_cm.c @@ -0,0 +1,1237 @@ +/* + * Copyright (c) 2006 Mellanox Technologies. All rights reserved + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id$ + */ + +#include +#include +#include +#include +#include + +#ifdef CONFIG_INFINIBAND_IPOIB_DEBUG_DATA +static int data_debug_level; + +module_param_named(cm_data_debug_level, data_debug_level, int, 0644); +MODULE_PARM_DESC(cm_data_debug_level, + "Enable data path debug tracing for connected mode if > 0"); +#endif + +#include "ipoib.h" + +#define IPOIB_CM_IETF_ID 0x1000000000000000ULL + +#define IPOIB_CM_RX_UPDATE_TIME (256 * HZ) +#define IPOIB_CM_RX_TIMEOUT (2 * 256 * HZ) +#define IPOIB_CM_RX_DELAY (3 * 256 * HZ) +#define IPOIB_CM_RX_UPDATE_MASK (0x3) + +struct ipoib_cm_id { + struct ib_cm_id *id; + int flags; + u32 remote_qpn; + u32 remote_mtu; +}; + +static int ipoib_cm_tx_handler(struct ib_cm_id *cm_id, + struct ib_cm_event *event); + +static void ipoib_cm_dma_unmap_rx(struct ipoib_dev_priv *priv, + u64 mapping[IPOIB_CM_RX_SG]) +{ + int i; + + ib_dma_unmap_single(priv->ca, mapping[0], IPOIB_CM_HEAD_SIZE, DMA_FROM_DEVICE); + + for (i = 0; i < IPOIB_CM_RX_SG - 1; ++i) + ib_dma_unmap_single(priv->ca, mapping[i + 1], PAGE_SIZE, DMA_FROM_DEVICE); +} + +static int ipoib_cm_post_receive(struct net_device *dev, int id) +{ + struct ipoib_dev_priv *priv = netdev_priv(dev); + struct ib_recv_wr *bad_wr; + int i, ret; + + priv->cm.rx_wr.wr_id = id | IPOIB_CM_OP_SRQ; + + for (i = 0; i < IPOIB_CM_RX_SG; ++i) + priv->cm.rx_sge[i].addr = priv->cm.srq_ring[id].mapping[i]; + + ret = ib_post_srq_recv(priv->cm.srq, &priv->cm.rx_wr, &bad_wr); + if (unlikely(ret)) { + ipoib_warn(priv, "post srq failed for buf %d (%d)\n", id, ret); + ipoib_cm_dma_unmap_rx(priv, priv->cm.srq_ring[id].mapping); + dev_kfree_skb_any(priv->cm.srq_ring[id].skb); + priv->cm.srq_ring[id].skb = NULL; + } + + return ret; +} + +static int ipoib_cm_alloc_rx_skb(struct net_device *dev, int id, + u64 mapping[IPOIB_CM_RX_SG]) +{ + struct ipoib_dev_priv *priv = netdev_priv(dev); + struct sk_buff *skb; + int i; + + skb = dev_alloc_skb(IPOIB_CM_HEAD_SIZE + 12); + if (unlikely(!skb)) + return -ENOMEM; + + /* + * IPoIB adds a 4 byte header. So we need 12 more bytes to align the + * IP header to a multiple of 16. + */ + skb_reserve(skb, 12); + + mapping[0] = ib_dma_map_single(priv->ca, skb->data, IPOIB_CM_HEAD_SIZE, + DMA_FROM_DEVICE); + if (unlikely(ib_dma_mapping_error(priv->ca, mapping[0]))) { + dev_kfree_skb_any(skb); + return -EIO; + } + + for (i = 0; i < IPOIB_CM_RX_SG - 1; i++) { + struct page *page = alloc_page(GFP_ATOMIC); + + if (!page) + goto partial_error; + skb_fill_page_desc(skb, i, page, 0, PAGE_SIZE); + + mapping[i + 1] = ib_dma_map_page(priv->ca, skb_shinfo(skb)->frags[i].page, + 0, PAGE_SIZE, DMA_TO_DEVICE); + if (unlikely(ib_dma_mapping_error(priv->ca, mapping[i + 1]))) + goto partial_error; + } + + priv->cm.srq_ring[id].skb = skb; + return 0; + +partial_error: + + ib_dma_unmap_single(priv->ca, mapping[0], IPOIB_CM_HEAD_SIZE, DMA_FROM_DEVICE); + + for (; i >= 0; --i) + ib_dma_unmap_single(priv->ca, mapping[i + 1], PAGE_SIZE, DMA_FROM_DEVICE); + + kfree_skb(skb); + return -ENOMEM; +} + +static struct ib_qp *ipoib_cm_create_rx_qp(struct net_device *dev, + struct ipoib_cm_rx *p) +{ + struct ipoib_dev_priv *priv = netdev_priv(dev); + struct ib_qp_init_attr attr = { + .send_cq = priv->cq, /* does not matter, we never send anything */ + .recv_cq = priv->cq, + .srq = priv->cm.srq, + .cap.max_send_wr = 1, /* FIXME: 0 Seems not to work */ + .cap.max_send_sge = 1, /* FIXME: 0 Seems not to work */ + .sq_sig_type = IB_SIGNAL_ALL_WR, + .qp_type = IB_QPT_RC, + .qp_context = p, + }; + return ib_create_qp(priv->pd, &attr); +} + +static int ipoib_cm_modify_rx_qp(struct net_device *dev, + struct ib_cm_id *cm_id, struct ib_qp *qp, + unsigned psn) +{ + struct ipoib_dev_priv *priv = netdev_priv(dev); + struct ib_qp_attr qp_attr; + int qp_attr_mask, ret; + + qp_attr.qp_state = IB_QPS_INIT; + ret = ib_cm_init_qp_attr(cm_id, &qp_attr, &qp_attr_mask); + if (ret) { + ipoib_warn(priv, "failed to init QP attr for INIT: %d\n", ret); + return ret; + } + ret = ib_modify_qp(qp, &qp_attr, qp_attr_mask); + if (ret) { + ipoib_warn(priv, "failed to modify QP to INIT: %d\n", ret); + return ret; + } + qp_attr.qp_state = IB_QPS_RTR; + ret = ib_cm_init_qp_attr(cm_id, &qp_attr, &qp_attr_mask); + if (ret) { + ipoib_warn(priv, "failed to init QP attr for RTR: %d\n", ret); + return ret; + } + qp_attr.rq_psn = psn; + ret = ib_modify_qp(qp, &qp_attr, qp_attr_mask); + if (ret) { + ipoib_warn(priv, "failed to modify QP to RTR: %d\n", ret); + return ret; + } + return 0; +} + +static int ipoib_cm_send_rep(struct net_device *dev, struct ib_cm_id *cm_id, + struct ib_qp *qp, struct ib_cm_req_event_param *req, + unsigned psn) +{ + struct ipoib_dev_priv *priv = netdev_priv(dev); + struct ipoib_cm_data data = {}; + struct ib_cm_rep_param rep = {}; + + data.qpn = cpu_to_be32(priv->qp->qp_num); + data.mtu = cpu_to_be32(IPOIB_CM_BUF_SIZE); + + rep.private_data = &data; + rep.private_data_len = sizeof data; + rep.flow_control = 0; + rep.rnr_retry_count = req->rnr_retry_count; + rep.target_ack_delay = 20; /* FIXME */ + rep.srq = 1; + rep.qp_num = qp->qp_num; + rep.starting_psn = psn; + return ib_send_cm_rep(cm_id, &rep); +} + +static int ipoib_cm_req_handler(struct ib_cm_id *cm_id, struct ib_cm_event *event) +{ + struct net_device *dev = cm_id->context; + struct ipoib_dev_priv *priv = netdev_priv(dev); + struct ipoib_cm_rx *p; + unsigned long flags; + unsigned psn; + int ret; + + ipoib_dbg(priv, "REQ arrived\n"); + p = kzalloc(sizeof *p, GFP_KERNEL); + if (!p) + return -ENOMEM; + p->dev = dev; + p->id = cm_id; + p->qp = ipoib_cm_create_rx_qp(dev, p); + if (IS_ERR(p->qp)) { + ret = PTR_ERR(p->qp); + goto err_qp; + } + + psn = random32() & 0xffffff; + ret = ipoib_cm_modify_rx_qp(dev, cm_id, p->qp, psn); + if (ret) + goto err_modify; + + ret = ipoib_cm_send_rep(dev, cm_id, p->qp, &event->param.req_rcvd, psn); + if (ret) { + ipoib_warn(priv, "failed to send REP: %d\n", ret); + goto err_rep; + } + + cm_id->context = p; + p->jiffies = jiffies; + spin_lock_irqsave(&priv->lock, flags); + list_add(&p->list, &priv->cm.passive_ids); + spin_unlock_irqrestore(&priv->lock, flags); + queue_delayed_work(ipoib_workqueue, + &priv->cm.stale_task, IPOIB_CM_RX_DELAY); + return 0; + +err_rep: +err_modify: + ib_destroy_qp(p->qp); +err_qp: + kfree(p); + return ret; +} + +static int ipoib_cm_rx_handler(struct ib_cm_id *cm_id, + struct ib_cm_event *event) +{ + struct ipoib_cm_rx *p; + struct ipoib_dev_priv *priv; + unsigned long flags; + int ret; + + switch (event->event) { + case IB_CM_REQ_RECEIVED: + return ipoib_cm_req_handler(cm_id, event); + case IB_CM_DREQ_RECEIVED: + p = cm_id->context; + ib_send_cm_drep(cm_id, NULL, 0); + /* Fall through */ + case IB_CM_REJ_RECEIVED: + p = cm_id->context; + priv = netdev_priv(p->dev); + spin_lock_irqsave(&priv->lock, flags); + if (list_empty(&p->list)) + ret = 0; /* Connection is going away already. */ + else { + list_del_init(&p->list); + ret = -ECONNRESET; + } + spin_unlock_irqrestore(&priv->lock, flags); + if (ret) { + ib_destroy_qp(p->qp); + kfree(p); + return ret; + } + return 0; + default: + return 0; + } +} +/* Adjust length of skb with fragments to match received data */ +static void skb_put_frags(struct sk_buff *skb, unsigned int hdr_space, + unsigned int length) +{ + int i, num_frags; + unsigned int size; + + /* put header into skb */ + size = min(length, hdr_space); + skb->tail += size; + skb->len += size; + length -= size; + + num_frags = skb_shinfo(skb)->nr_frags; + for (i = 0; i < num_frags; i++) { + skb_frag_t *frag = &skb_shinfo(skb)->frags[i]; + + if (length == 0) { + /* don't need this page */ + __free_page(frag->page); + --skb_shinfo(skb)->nr_frags; + } else { + size = min(length, (unsigned) PAGE_SIZE); + + frag->size = size; + skb->data_len += size; + skb->truesize += size; + skb->len += size; + length -= size; + } + } +} + +void ipoib_cm_handle_rx_wc(struct net_device *dev, struct ib_wc *wc) +{ + struct ipoib_dev_priv *priv = netdev_priv(dev); + unsigned int wr_id = wc->wr_id & ~IPOIB_CM_OP_SRQ; + struct sk_buff *skb; + struct ipoib_cm_rx *p; + unsigned long flags; + u64 mapping[IPOIB_CM_RX_SG]; + + ipoib_dbg_data(priv, "cm recv completion: id %d, op %d, status: %d\n", + wr_id, wc->opcode, wc->status); + + if (unlikely(wr_id >= ipoib_recvq_size)) { + ipoib_warn(priv, "cm recv completion event with wrid %d (> %d)\n", + wr_id, ipoib_recvq_size); + return; + } + + skb = priv->cm.srq_ring[wr_id].skb; + + if (unlikely(wc->status != IB_WC_SUCCESS)) { + ipoib_dbg(priv, "cm recv error " + "(status=%d, wrid=%d vend_err %x)\n", + wc->status, wr_id, wc->vendor_err); + ++priv->stats.rx_dropped; + goto repost; + } + + if (!likely(wr_id & IPOIB_CM_RX_UPDATE_MASK)) { + p = wc->qp->qp_context; + if (time_after_eq(jiffies, p->jiffies + IPOIB_CM_RX_UPDATE_TIME)) { + spin_lock_irqsave(&priv->lock, flags); + p->jiffies = jiffies; + /* Move this entry to list head, but do + * not re-add it if it has been removed. */ + if (!list_empty(&p->list)) + list_move(&p->list, &priv->cm.passive_ids); + spin_unlock_irqrestore(&priv->lock, flags); + queue_delayed_work(ipoib_workqueue, + &priv->cm.stale_task, IPOIB_CM_RX_DELAY); + } + } + + if (unlikely(ipoib_cm_alloc_rx_skb(dev, wr_id, mapping))) { + /* + * If we can't allocate a new RX buffer, dump + * this packet and reuse the old buffer. + */ + ipoib_dbg(priv, "failed to allocate receive buffer %d\n", wr_id); + ++priv->stats.rx_dropped; + goto repost; + } + + ipoib_cm_dma_unmap_rx(priv, priv->cm.srq_ring[wr_id].mapping); + memcpy(priv->cm.srq_ring[wr_id].mapping, mapping, sizeof mapping); + + ipoib_dbg_data(priv, "received %d bytes, SLID 0x%04x\n", + wc->byte_len, wc->slid); + + skb_put_frags(skb, IPOIB_CM_HEAD_SIZE, wc->byte_len); + + skb->protocol = ((struct ipoib_header *) skb->data)->proto; + skb->mac.raw = skb->data; + skb_pull(skb, IPOIB_ENCAP_LEN); + + dev->last_rx = jiffies; + ++priv->stats.rx_packets; + priv->stats.rx_bytes += skb->len; + + skb->dev = dev; + /* XXX get correct PACKET_ type here */ + skb->pkt_type = PACKET_HOST; + netif_rx_ni(skb); + +repost: + if (unlikely(ipoib_cm_post_receive(dev, wr_id))) + ipoib_warn(priv, "ipoib_cm_post_receive failed " + "for buf %d\n", wr_id); +} + +static inline int post_send(struct ipoib_dev_priv *priv, + struct ipoib_cm_tx *tx, + unsigned int wr_id, + u64 addr, int len) +{ + struct ib_send_wr *bad_wr; + + priv->tx_sge.addr = addr; + priv->tx_sge.length = len; + + priv->tx_wr.wr_id = wr_id; + + return ib_post_send(tx->qp, &priv->tx_wr, &bad_wr); +} + +void ipoib_cm_send(struct net_device *dev, struct sk_buff *skb, struct ipoib_cm_tx *tx) +{ + struct ipoib_dev_priv *priv = netdev_priv(dev); + struct ipoib_tx_buf *tx_req; + u64 addr; + + if (unlikely(skb->len > tx->mtu)) { + ipoib_warn(priv, "packet len %d (> %d) too long to send, dropping\n", + skb->len, tx->mtu); + ++priv->stats.tx_dropped; + ++priv->stats.tx_errors; + ipoib_cm_skb_too_long(dev, skb, tx->mtu - INFINIBAND_ALEN); + return; + } + + ipoib_dbg_data(priv, "sending packet: head 0x%x length %d connection 0x%x\n", + tx->tx_head, skb->len, tx->qp->qp_num); + + /* + * We put the skb into the tx_ring _before_ we call post_send() + * because it's entirely possible that the completion handler will + * run before we execute anything after the post_send(). That + * means we have to make sure everything is properly recorded and + * our state is consistent before we call post_send(). + */ + tx_req = &tx->tx_ring[tx->tx_head & (ipoib_sendq_size - 1)]; + tx_req->skb = skb; + addr = ib_dma_map_single(priv->ca, skb->data, skb->len, DMA_TO_DEVICE); + if (unlikely(ib_dma_mapping_error(priv->ca, addr))) { + ++priv->stats.tx_errors; + dev_kfree_skb_any(skb); + return; + } + + tx_req->mapping = addr; + + if (unlikely(post_send(priv, tx, tx->tx_head & (ipoib_sendq_size - 1), + addr, skb->len))) { + ipoib_warn(priv, "post_send failed\n"); + ++priv->stats.tx_errors; + ib_dma_unmap_single(priv->ca, addr, skb->len, DMA_TO_DEVICE); + dev_kfree_skb_any(skb); + } else { + dev->trans_start = jiffies; + ++tx->tx_head; + + if (tx->tx_head - tx->tx_tail == ipoib_sendq_size) { + ipoib_dbg(priv, "TX ring 0x%x full, stopping kernel net queue\n", + tx->qp->qp_num); + netif_stop_queue(dev); + set_bit(IPOIB_FLAG_NETIF_STOPPED, &tx->flags); + } + } +} + +static void ipoib_cm_handle_tx_wc(struct net_device *dev, struct ipoib_cm_tx *tx, + struct ib_wc *wc) +{ + struct ipoib_dev_priv *priv = netdev_priv(dev); + unsigned int wr_id = wc->wr_id; + struct ipoib_tx_buf *tx_req; + unsigned long flags; + + ipoib_dbg_data(priv, "cm send completion: id %d, op %d, status: %d\n", + wr_id, wc->opcode, wc->status); + + if (unlikely(wr_id >= ipoib_sendq_size)) { + ipoib_warn(priv, "cm send completion event with wrid %d (> %d)\n", + wr_id, ipoib_sendq_size); + return; + } + + tx_req = &tx->tx_ring[wr_id]; + + ib_dma_unmap_single(priv->ca, tx_req->mapping, tx_req->skb->len, DMA_TO_DEVICE); + + /* FIXME: is this right? Shouldn't we only increment on success? */ + ++priv->stats.tx_packets; + priv->stats.tx_bytes += tx_req->skb->len; + + dev_kfree_skb_any(tx_req->skb); + + spin_lock_irqsave(&priv->tx_lock, flags); + ++tx->tx_tail; + if (unlikely(test_bit(IPOIB_FLAG_NETIF_STOPPED, &tx->flags)) && + tx->tx_head - tx->tx_tail <= ipoib_sendq_size >> 1) { + clear_bit(IPOIB_FLAG_NETIF_STOPPED, &tx->flags); + netif_wake_queue(dev); + } + + if (wc->status != IB_WC_SUCCESS && + wc->status != IB_WC_WR_FLUSH_ERR) { + struct ipoib_neigh *neigh; + + ipoib_dbg(priv, "failed cm send event " + "(status=%d, wrid=%d vend_err %x)\n", + wc->status, wr_id, wc->vendor_err); + + spin_lock(&priv->lock); + neigh = tx->neigh; + + if (neigh) { + neigh->cm = NULL; + list_del(&neigh->list); + if (neigh->ah) + ipoib_put_ah(neigh->ah); + ipoib_neigh_free(dev, neigh); + + tx->neigh = NULL; + } + + /* queue would be re-started anyway when TX is destroyed, + * but it makes sense to do it ASAP here. */ + if (test_and_clear_bit(IPOIB_FLAG_NETIF_STOPPED, &tx->flags)) + netif_wake_queue(dev); + + if (test_and_clear_bit(IPOIB_FLAG_INITIALIZED, &tx->flags)) { + list_move(&tx->list, &priv->cm.reap_list); + queue_work(ipoib_workqueue, &priv->cm.reap_task); + } + + clear_bit(IPOIB_FLAG_OPER_UP, &tx->flags); + + spin_unlock(&priv->lock); + } + + spin_unlock_irqrestore(&priv->tx_lock, flags); +} + +static void ipoib_cm_tx_completion(struct ib_cq *cq, void *tx_ptr) +{ + struct ipoib_cm_tx *tx = tx_ptr; + int n, i; + + ib_req_notify_cq(cq, IB_CQ_NEXT_COMP); + do { + n = ib_poll_cq(cq, IPOIB_NUM_WC, tx->ibwc); + for (i = 0; i < n; ++i) + ipoib_cm_handle_tx_wc(tx->dev, tx, tx->ibwc + i); + } while (n == IPOIB_NUM_WC); +} + +int ipoib_cm_dev_open(struct net_device *dev) +{ + struct ipoib_dev_priv *priv = netdev_priv(dev); + int ret; + + if (!IPOIB_CM_SUPPORTED(dev->dev_addr)) + return 0; + + priv->cm.id = ib_create_cm_id(priv->ca, ipoib_cm_rx_handler, dev); + if (IS_ERR(priv->cm.id)) { + printk(KERN_WARNING "%s: failed to create CM ID\n", priv->ca->name); + return IS_ERR(priv->cm.id); + } + + ret = ib_cm_listen(priv->cm.id, cpu_to_be64(IPOIB_CM_IETF_ID | priv->qp->qp_num), + 0, NULL); + if (ret) { + printk(KERN_WARNING "%s: failed to listen on ID 0x%llx\n", priv->ca->name, + IPOIB_CM_IETF_ID | priv->qp->qp_num); + ib_destroy_cm_id(priv->cm.id); + return ret; + } + return 0; +} + +void ipoib_cm_dev_stop(struct net_device *dev) +{ + struct ipoib_dev_priv *priv = netdev_priv(dev); + struct ipoib_cm_rx *p; + unsigned long flags; + + if (!IPOIB_CM_SUPPORTED(dev->dev_addr)) + return; + + ib_destroy_cm_id(priv->cm.id); + spin_lock_irqsave(&priv->lock, flags); + while (!list_empty(&priv->cm.passive_ids)) { + p = list_entry(priv->cm.passive_ids.next, typeof(*p), list); + list_del_init(&p->list); + spin_unlock_irqrestore(&priv->lock, flags); + ib_destroy_cm_id(p->id); + ib_destroy_qp(p->qp); + kfree(p); + spin_lock_irqsave(&priv->lock, flags); + } + spin_unlock_irqrestore(&priv->lock, flags); + + cancel_delayed_work(&priv->cm.stale_task); +} + +static int ipoib_cm_rep_handler(struct ib_cm_id *cm_id, struct ib_cm_event *event) +{ + struct ipoib_cm_tx *p = cm_id->context; + struct ipoib_dev_priv *priv = netdev_priv(p->dev); + struct ipoib_cm_data *data = event->private_data; + struct sk_buff_head skqueue; + struct ib_qp_attr qp_attr; + int qp_attr_mask, ret; + struct sk_buff *skb; + unsigned long flags; + + p->mtu = be32_to_cpu(data->mtu); + + if (p->mtu < priv->dev->mtu + IPOIB_ENCAP_LEN) { + ipoib_warn(priv, "Rejecting connection: mtu %d < device mtu %d + 4\n", + p->mtu, priv->dev->mtu); + return -EINVAL; + } + + qp_attr.qp_state = IB_QPS_RTR; + ret = ib_cm_init_qp_attr(cm_id, &qp_attr, &qp_attr_mask); + if (ret) { + ipoib_warn(priv, "failed to init QP attr for RTR: %d\n", ret); + return ret; + } + + qp_attr.rq_psn = 0 /* FIXME */; + ret = ib_modify_qp(p->qp, &qp_attr, qp_attr_mask); + if (ret) { + ipoib_warn(priv, "failed to modify QP to RTR: %d\n", ret); + return ret; + } + + qp_attr.qp_state = IB_QPS_RTS; + ret = ib_cm_init_qp_attr(cm_id, &qp_attr, &qp_attr_mask); + if (ret) { + ipoib_warn(priv, "failed to init QP attr for RTS: %d\n", ret); + return ret; + } + ret = ib_modify_qp(p->qp, &qp_attr, qp_attr_mask); + if (ret) { + ipoib_warn(priv, "failed to modify QP to RTS: %d\n", ret); + return ret; + } + + skb_queue_head_init(&skqueue); + + spin_lock_irqsave(&priv->lock, flags); + set_bit(IPOIB_FLAG_OPER_UP, &p->flags); + if (p->neigh) + while ((skb = __skb_dequeue(&p->neigh->queue))) + __skb_queue_tail(&skqueue, skb); + spin_unlock_irqrestore(&priv->lock, flags); + + while ((skb = __skb_dequeue(&skqueue))) { + skb->dev = p->dev; + if (dev_queue_xmit(skb)) + ipoib_warn(priv, "dev_queue_xmit failed " + "to requeue packet\n"); + } + + ret = ib_send_cm_rtu(cm_id, NULL, 0); + if (ret) { + ipoib_warn(priv, "failed to send RTU: %d\n", ret); + return ret; + } + return 0; +} + +static struct ib_qp *ipoib_cm_create_tx_qp(struct net_device *dev, struct ib_cq *cq) +{ + struct ipoib_dev_priv *priv = netdev_priv(dev); + struct ib_qp_init_attr attr = {}; + attr.recv_cq = priv->cq; + attr.srq = priv->cm.srq; + attr.cap.max_send_wr = ipoib_sendq_size; + attr.cap.max_send_sge = 1; + attr.sq_sig_type = IB_SIGNAL_ALL_WR; + attr.qp_type = IB_QPT_RC; + attr.send_cq = cq; + return ib_create_qp(priv->pd, &attr); +} + +static int ipoib_cm_send_req(struct net_device *dev, + struct ib_cm_id *id, struct ib_qp *qp, + u32 qpn, + struct ib_sa_path_rec *pathrec) +{ + struct ipoib_dev_priv *priv = netdev_priv(dev); + struct ipoib_cm_data data = {}; + struct ib_cm_req_param req = {}; + + data.qpn = cpu_to_be32(priv->qp->qp_num); + data.mtu = cpu_to_be32(IPOIB_CM_BUF_SIZE); + + req.primary_path = pathrec; + req.alternate_path = NULL; + req.service_id = cpu_to_be64(IPOIB_CM_IETF_ID | qpn); + req.qp_num = qp->qp_num; + req.qp_type = qp->qp_type; + req.private_data = &data; + req.private_data_len = sizeof data; + req.flow_control = 0; + + req.starting_psn = 0; /* FIXME */ + + /* + * Pick some arbitrary defaults here; we could make these + * module parameters if anyone cared about setting them. + */ + req.responder_resources = 4; + req.remote_cm_response_timeout = 20; + req.local_cm_response_timeout = 20; + req.retry_count = 0; /* RFC draft warns against retries */ + req.rnr_retry_count = 0; /* RFC draft warns against retries */ + req.max_cm_retries = 15; + req.srq = 1; + return ib_send_cm_req(id, &req); +} + +static int ipoib_cm_modify_tx_init(struct net_device *dev, + struct ib_cm_id *cm_id, struct ib_qp *qp) +{ + struct ipoib_dev_priv *priv = netdev_priv(dev); + struct ib_qp_attr qp_attr; + int qp_attr_mask, ret; + ret = ib_find_cached_pkey(priv->ca, priv->port, priv->pkey, &qp_attr.pkey_index); + if (ret) { + ipoib_warn(priv, "pkey 0x%x not in cache: %d\n", priv->pkey, ret); + return ret; + } + + qp_attr.qp_state = IB_QPS_INIT; + qp_attr.qp_access_flags = IB_ACCESS_LOCAL_WRITE; + qp_attr.port_num = priv->port; + qp_attr_mask = IB_QP_STATE | IB_QP_ACCESS_FLAGS | IB_QP_PKEY_INDEX | IB_QP_PORT; + + ret = ib_modify_qp(qp, &qp_attr, qp_attr_mask); + if (ret) { + ipoib_warn(priv, "failed to modify tx QP to INIT: %d\n", ret); + return ret; + } + return 0; +} + +static int ipoib_cm_tx_init(struct ipoib_cm_tx *p, u32 qpn, + struct ib_sa_path_rec *pathrec) +{ + struct ipoib_dev_priv *priv = netdev_priv(p->dev); + int ret; + + p->tx_ring = kzalloc(ipoib_sendq_size * sizeof *p->tx_ring, + GFP_KERNEL); + if (!p->tx_ring) { + ipoib_warn(priv, "failed to allocate tx ring\n"); + ret = -ENOMEM; + goto err_tx; + } + + p->cq = ib_create_cq(priv->ca, ipoib_cm_tx_completion, NULL, p, + ipoib_sendq_size + 1); + if (IS_ERR(p->cq)) { + ret = PTR_ERR(p->cq); + ipoib_warn(priv, "failed to allocate tx cq: %d\n", ret); + goto err_cq; + } + + ret = ib_req_notify_cq(p->cq, IB_CQ_NEXT_COMP); + if (ret) { + ipoib_warn(priv, "failed to request completion notification: %d\n", ret); + goto err_req_notify; + } + + p->qp = ipoib_cm_create_tx_qp(p->dev, p->cq); + if (IS_ERR(p->qp)) { + ret = PTR_ERR(p->qp); + ipoib_warn(priv, "failed to allocate tx qp: %d\n", ret); + goto err_qp; + } + + p->id = ib_create_cm_id(priv->ca, ipoib_cm_tx_handler, p); + if (IS_ERR(p->id)) { + ret = PTR_ERR(p->id); + ipoib_warn(priv, "failed to create tx cm id: %d\n", ret); + goto err_id; + } + + ret = ipoib_cm_modify_tx_init(p->dev, p->id, p->qp); + if (ret) { + ipoib_warn(priv, "failed to modify tx qp to rtr: %d\n", ret); + goto err_modify; + } + + ret = ipoib_cm_send_req(p->dev, p->id, p->qp, qpn, pathrec); + if (ret) { + ipoib_warn(priv, "failed to send cm req: %d\n", ret); + goto err_send_cm; + } + + ipoib_dbg(priv, "Request connection 0x%x for gid " IPOIB_GID_FMT " qpn 0x%x\n", + p->qp->qp_num, IPOIB_GID_ARG(pathrec->dgid), qpn); + + return 0; + +err_send_cm: +err_modify: + ib_destroy_cm_id(p->id); +err_id: + p->id = NULL; + ib_destroy_qp(p->qp); +err_req_notify: +err_qp: + p->qp = NULL; + ib_destroy_cq(p->cq); +err_cq: + p->cq = NULL; +err_tx: + return ret; +} + +static void ipoib_cm_tx_destroy(struct ipoib_cm_tx *p) +{ + struct ipoib_dev_priv *priv = netdev_priv(p->dev); + struct ipoib_tx_buf *tx_req; + + ipoib_dbg(priv, "Destroy active connection 0x%x head 0x%x tail 0x%x\n", + p->qp ? p->qp->qp_num : 0, p->tx_head, p->tx_tail); + + if (p->id) + ib_destroy_cm_id(p->id); + + if (p->qp) + ib_destroy_qp(p->qp); + + if (p->cq) + ib_destroy_cq(p->cq); + + if (test_bit(IPOIB_FLAG_NETIF_STOPPED, &p->flags)) + netif_wake_queue(p->dev); + + if (p->tx_ring) { + while ((int) p->tx_tail - (int) p->tx_head < 0) { + tx_req = &p->tx_ring[p->tx_tail & (ipoib_sendq_size - 1)]; + ib_dma_unmap_single(priv->ca, tx_req->mapping, tx_req->skb->len, + DMA_TO_DEVICE); + dev_kfree_skb_any(tx_req->skb); + ++p->tx_tail; + } + + kfree(p->tx_ring); + } + + kfree(p); +} + +static int ipoib_cm_tx_handler(struct ib_cm_id *cm_id, + struct ib_cm_event *event) +{ + struct ipoib_cm_tx *tx = cm_id->context; + struct ipoib_dev_priv *priv = netdev_priv(tx->dev); + struct net_device *dev = priv->dev; + struct ipoib_neigh *neigh; + unsigned long flags; + int ret; + + switch (event->event) { + case IB_CM_DREQ_RECEIVED: + ipoib_dbg(priv, "DREQ received.\n"); + ib_send_cm_drep(cm_id, NULL, 0); + break; + case IB_CM_REP_RECEIVED: + ipoib_dbg(priv, "REP received.\n"); + ret = ipoib_cm_rep_handler(cm_id, event); + if (ret) + ib_send_cm_rej(cm_id, IB_CM_REJ_CONSUMER_DEFINED, + NULL, 0, NULL, 0); + break; + case IB_CM_REQ_ERROR: + case IB_CM_REJ_RECEIVED: + case IB_CM_TIMEWAIT_EXIT: + ipoib_dbg(priv, "CM error %d.\n", event->event); + spin_lock_irqsave(&priv->tx_lock, flags); + spin_lock(&priv->lock); + neigh = tx->neigh; + + if (neigh) { + neigh->cm = NULL; + list_del(&neigh->list); + if (neigh->ah) + ipoib_put_ah(neigh->ah); + ipoib_neigh_free(dev, neigh); + + tx->neigh = NULL; + } + + if (test_and_clear_bit(IPOIB_FLAG_INITIALIZED, &tx->flags)) { + list_move(&tx->list, &priv->cm.reap_list); + queue_work(ipoib_workqueue, &priv->cm.reap_task); + } + + spin_unlock(&priv->lock); + spin_unlock_irqrestore(&priv->tx_lock, flags); + break; + default: + break; + } + + return 0; +} + +struct ipoib_cm_tx *ipoib_cm_create_tx(struct net_device *dev, struct ipoib_path *path, + struct ipoib_neigh *neigh) +{ + struct ipoib_dev_priv *priv = netdev_priv(dev); + struct ipoib_cm_tx *tx; + + tx = kzalloc(sizeof *tx, GFP_ATOMIC); + if (!tx) + return NULL; + + neigh->cm = tx; + tx->neigh = neigh; + tx->path = path; + tx->dev = dev; + list_add(&tx->list, &priv->cm.start_list); + set_bit(IPOIB_FLAG_INITIALIZED, &tx->flags); + queue_work(ipoib_workqueue, &priv->cm.start_task); + return tx; +} + +void ipoib_cm_destroy_tx(struct ipoib_cm_tx *tx) +{ + struct ipoib_dev_priv *priv = netdev_priv(tx->dev); + if (test_and_clear_bit(IPOIB_FLAG_INITIALIZED, &tx->flags)) { + list_move(&tx->list, &priv->cm.reap_list); + queue_work(ipoib_workqueue, &priv->cm.reap_task); + ipoib_dbg(priv, "Reap connection for gid " IPOIB_GID_FMT "\n", + IPOIB_GID_ARG(tx->neigh->dgid)); + tx->neigh = NULL; + } +} + +static void ipoib_cm_tx_start(struct work_struct *work) +{ + struct ipoib_dev_priv *priv = container_of(work, struct ipoib_dev_priv, + cm.start_task); + struct net_device *dev = priv->dev; + struct ipoib_neigh *neigh; + struct ipoib_cm_tx *p; + unsigned long flags; + int ret; + + struct ib_sa_path_rec pathrec; + u32 qpn; + + spin_lock_irqsave(&priv->tx_lock, flags); + spin_lock(&priv->lock); + while (!list_empty(&priv->cm.start_list)) { + p = list_entry(priv->cm.start_list.next, typeof(*p), list); + list_del_init(&p->list); + neigh = p->neigh; + qpn = IPOIB_QPN(neigh->neighbour->ha); + memcpy(&pathrec, &p->path->pathrec, sizeof pathrec); + spin_unlock(&priv->lock); + spin_unlock_irqrestore(&priv->tx_lock, flags); + ret = ipoib_cm_tx_init(p, qpn, &pathrec); + spin_lock_irqsave(&priv->tx_lock, flags); + spin_lock(&priv->lock); + if (ret) { + neigh = p->neigh; + if (neigh) { + neigh->cm = NULL; + list_del(&neigh->list); + if (neigh->ah) + ipoib_put_ah(neigh->ah); + ipoib_neigh_free(dev, neigh); + } + list_del(&p->list); + kfree(p); + } + } + spin_unlock(&priv->lock); + spin_unlock_irqrestore(&priv->tx_lock, flags); +} + +static void ipoib_cm_tx_reap(struct work_struct *work) +{ + struct ipoib_dev_priv *priv = container_of(work, struct ipoib_dev_priv, + cm.reap_task); + struct ipoib_cm_tx *p; + unsigned long flags; + + spin_lock_irqsave(&priv->tx_lock, flags); + spin_lock(&priv->lock); + while (!list_empty(&priv->cm.reap_list)) { + p = list_entry(priv->cm.reap_list.next, typeof(*p), list); + list_del(&p->list); + spin_unlock(&priv->lock); + spin_unlock_irqrestore(&priv->tx_lock, flags); + ipoib_cm_tx_destroy(p); + spin_lock_irqsave(&priv->tx_lock, flags); + spin_lock(&priv->lock); + } + spin_unlock(&priv->lock); + spin_unlock_irqrestore(&priv->tx_lock, flags); +} + +static void ipoib_cm_skb_reap(struct work_struct *work) +{ + struct ipoib_dev_priv *priv = container_of(work, struct ipoib_dev_priv, + cm.skb_task); + struct net_device *dev = priv->dev; + struct sk_buff *skb; + unsigned long flags; + + unsigned mtu = priv->mcast_mtu; + + spin_lock_irqsave(&priv->tx_lock, flags); + spin_lock(&priv->lock); + while ((skb = skb_dequeue(&priv->cm.skb_queue))) { + spin_unlock(&priv->lock); + spin_unlock_irqrestore(&priv->tx_lock, flags); + if (skb->protocol == htons(ETH_P_IP)) + icmp_send(skb, ICMP_DEST_UNREACH, ICMP_FRAG_NEEDED, htonl(mtu)); +#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) + else if (skb->protocol == htons(ETH_P_IPV6)) + icmpv6_send(skb, ICMPV6_PKT_TOOBIG, 0, mtu, dev); +#endif + dev_kfree_skb_any(skb); + spin_lock_irqsave(&priv->tx_lock, flags); + spin_lock(&priv->lock); + } + spin_unlock(&priv->lock); + spin_unlock_irqrestore(&priv->tx_lock, flags); +} + +void ipoib_cm_skb_too_long(struct net_device* dev, struct sk_buff *skb, + unsigned int mtu) +{ + struct ipoib_dev_priv *priv = netdev_priv(dev); + int e = skb_queue_empty(&priv->cm.skb_queue); + + if (skb->dst) + skb->dst->ops->update_pmtu(skb->dst, mtu); + + skb_queue_tail(&priv->cm.skb_queue, skb); + if (e) + queue_work(ipoib_workqueue, &priv->cm.skb_task); +} + +static void ipoib_cm_stale_task(struct work_struct *work) +{ + struct ipoib_dev_priv *priv = container_of(work, struct ipoib_dev_priv, + cm.stale_task.work); + struct ipoib_cm_rx *p; + unsigned long flags; + + spin_lock_irqsave(&priv->lock, flags); + while (!list_empty(&priv->cm.passive_ids)) { + /* List if sorted by LRU, start from tail, + * stop when we see a recently used entry */ + p = list_entry(priv->cm.passive_ids.prev, typeof(*p), list); + if (time_after_eq(jiffies, p->jiffies + IPOIB_CM_RX_TIMEOUT)) + break; + list_del_init(&p->list); + spin_unlock_irqrestore(&priv->lock, flags); + ib_destroy_cm_id(p->id); + ib_destroy_qp(p->qp); + kfree(p); + spin_lock_irqsave(&priv->lock, flags); + } + spin_unlock_irqrestore(&priv->lock, flags); +} + + +static ssize_t show_mode(struct device *d, struct device_attribute *attr, + char *buf) +{ + struct ipoib_dev_priv *priv = netdev_priv(to_net_dev(d)); + + if (test_bit(IPOIB_FLAG_ADMIN_CM, &priv->flags)) + return sprintf(buf, "connected\n"); + else + return sprintf(buf, "datagram\n"); +} + +static ssize_t set_mode(struct device *d, struct device_attribute *attr, + const char *buf, size_t count) +{ + struct net_device *dev = to_net_dev(d); + struct ipoib_dev_priv *priv = netdev_priv(dev); + + /* flush paths if we switch modes so that connections are restarted */ + if (IPOIB_CM_SUPPORTED(dev->dev_addr) && !strcmp(buf, "connected\n")) { + set_bit(IPOIB_FLAG_ADMIN_CM, &priv->flags); + ipoib_warn(priv, "enabling connected mode " + "will cause multicast packet drops\n"); + ipoib_flush_paths(dev); + return count; + } + + if (!strcmp(buf, "datagram\n")) { + clear_bit(IPOIB_FLAG_ADMIN_CM, &priv->flags); + dev->mtu = min(priv->mcast_mtu, dev->mtu); + ipoib_flush_paths(dev); + return count; + } + + return -EINVAL; +} + +static DEVICE_ATTR(mode, S_IWUGO | S_IRUGO, show_mode, set_mode); + +int ipoib_cm_add_mode_attr(struct net_device *dev) +{ + return device_create_file(&dev->dev, &dev_attr_mode); +} + +int ipoib_cm_dev_init(struct net_device *dev) +{ + struct ipoib_dev_priv *priv = netdev_priv(dev); + struct ib_srq_init_attr srq_init_attr = { + .attr = { + .max_wr = ipoib_recvq_size, + .max_sge = IPOIB_CM_RX_SG + } + }; + int ret, i; + + INIT_LIST_HEAD(&priv->cm.passive_ids); + INIT_LIST_HEAD(&priv->cm.reap_list); + INIT_LIST_HEAD(&priv->cm.start_list); + INIT_WORK(&priv->cm.start_task, ipoib_cm_tx_start); + INIT_WORK(&priv->cm.reap_task, ipoib_cm_tx_reap); + INIT_WORK(&priv->cm.skb_task, ipoib_cm_skb_reap); + INIT_DELAYED_WORK(&priv->cm.stale_task, ipoib_cm_stale_task); + + skb_queue_head_init(&priv->cm.skb_queue); + + priv->cm.srq = ib_create_srq(priv->pd, &srq_init_attr); + if (IS_ERR(priv->cm.srq)) { + ret = PTR_ERR(priv->cm.srq); + priv->cm.srq = NULL; + return ret; + } + + priv->cm.srq_ring = kzalloc(ipoib_recvq_size * sizeof *priv->cm.srq_ring, + GFP_KERNEL); + if (!priv->cm.srq_ring) { + printk(KERN_WARNING "%s: failed to allocate CM ring (%d entries)\n", + priv->ca->name, ipoib_recvq_size); + ipoib_cm_dev_cleanup(dev); + return -ENOMEM; + } + + for (i = 0; i < IPOIB_CM_RX_SG; ++i) + priv->cm.rx_sge[i].lkey = priv->mr->lkey; + + priv->cm.rx_sge[0].length = IPOIB_CM_HEAD_SIZE; + for (i = 1; i < IPOIB_CM_RX_SG; ++i) + priv->cm.rx_sge[i].length = PAGE_SIZE; + priv->cm.rx_wr.next = NULL; + priv->cm.rx_wr.sg_list = priv->cm.rx_sge; + priv->cm.rx_wr.num_sge = IPOIB_CM_RX_SG; + + for (i = 0; i < ipoib_recvq_size; ++i) { + if (ipoib_cm_alloc_rx_skb(dev, i, priv->cm.srq_ring[i].mapping)) { + ipoib_warn(priv, "failed to allocate receive buffer %d\n", i); + ipoib_cm_dev_cleanup(dev); + return -ENOMEM; + } + if (ipoib_cm_post_receive(dev, i)) { + ipoib_warn(priv, "ipoib_ib_post_receive failed for buf %d\n", i); + ipoib_cm_dev_cleanup(dev); + return -EIO; + } + } + + priv->dev->dev_addr[0] = IPOIB_FLAGS_RC; + return 0; +} + +void ipoib_cm_dev_cleanup(struct net_device *dev) +{ + struct ipoib_dev_priv *priv = netdev_priv(dev); + int i, ret; + + if (!priv->cm.srq) + return; + + ipoib_dbg(priv, "Cleanup ipoib connected mode.\n"); + + ret = ib_destroy_srq(priv->cm.srq); + if (ret) + ipoib_warn(priv, "ib_destroy_srq failed: %d\n", ret); + + priv->cm.srq = NULL; + if (!priv->cm.srq_ring) + return; + for (i = 0; i < ipoib_recvq_size; ++i) + if (priv->cm.srq_ring[i].skb) { + ipoib_cm_dma_unmap_rx(priv, priv->cm.srq_ring[i].mapping); + dev_kfree_skb_any(priv->cm.srq_ring[i].skb); + priv->cm.srq_ring[i].skb = NULL; + } + kfree(priv->cm.srq_ring); + priv->cm.srq_ring = NULL; +} diff --git a/drivers/infiniband/ulp/ipoib/ipoib_fs.c b/drivers/infiniband/ulp/ipoib/ipoib_fs.c index f1cb836..44c1741 100644 --- a/drivers/infiniband/ulp/ipoib/ipoib_fs.c +++ b/drivers/infiniband/ulp/ipoib/ipoib_fs.c @@ -146,7 +146,7 @@ static int ipoib_mcg_open(struct inode * return 0; } -static struct file_operations ipoib_mcg_fops = { +static const struct file_operations ipoib_mcg_fops = { .owner = THIS_MODULE, .open = ipoib_mcg_open, .read = seq_read, @@ -252,7 +252,7 @@ static int ipoib_path_open(struct inode return 0; } -static struct file_operations ipoib_path_fops = { +static const struct file_operations ipoib_path_fops = { .owner = THIS_MODULE, .open = ipoib_path_open, .read = seq_read, diff --git a/drivers/infiniband/ulp/ipoib/ipoib_ib.c b/drivers/infiniband/ulp/ipoib/ipoib_ib.c index 59d9594..f2aa923 100644 --- a/drivers/infiniband/ulp/ipoib/ipoib_ib.c +++ b/drivers/infiniband/ulp/ipoib/ipoib_ib.c @@ -50,8 +50,6 @@ MODULE_PARM_DESC(data_debug_level, "Enable data path debug tracing if > 0"); #endif -#define IPOIB_OP_RECV (1ul << 31) - static DEFINE_MUTEX(pkey_mutex); struct ipoib_ah *ipoib_create_ah(struct net_device *dev, @@ -268,10 +266,11 @@ static void ipoib_ib_handle_tx_wc(struct spin_lock_irqsave(&priv->tx_lock, flags); ++priv->tx_tail; - if (netif_queue_stopped(dev) && - test_bit(IPOIB_FLAG_ADMIN_UP, &priv->flags) && - priv->tx_head - priv->tx_tail <= ipoib_sendq_size >> 1) + if (unlikely(test_bit(IPOIB_FLAG_NETIF_STOPPED, &priv->flags)) && + priv->tx_head - priv->tx_tail <= ipoib_sendq_size >> 1) { + clear_bit(IPOIB_FLAG_NETIF_STOPPED, &priv->flags); netif_wake_queue(dev); + } spin_unlock_irqrestore(&priv->tx_lock, flags); if (wc->status != IB_WC_SUCCESS && @@ -283,7 +282,9 @@ static void ipoib_ib_handle_tx_wc(struct static void ipoib_ib_handle_wc(struct net_device *dev, struct ib_wc *wc) { - if (wc->wr_id & IPOIB_OP_RECV) + if (wc->wr_id & IPOIB_CM_OP_SRQ) + ipoib_cm_handle_rx_wc(dev, wc); + else if (wc->wr_id & IPOIB_OP_RECV) ipoib_ib_handle_rx_wc(dev, wc); else ipoib_ib_handle_tx_wc(dev, wc); @@ -327,12 +328,12 @@ void ipoib_send(struct net_device *dev, struct ipoib_tx_buf *tx_req; u64 addr; - if (unlikely(skb->len > dev->mtu + INFINIBAND_ALEN)) { + if (unlikely(skb->len > priv->mcast_mtu + INFINIBAND_ALEN)) { ipoib_warn(priv, "packet len %d (> %d) too long to send, dropping\n", - skb->len, dev->mtu + INFINIBAND_ALEN); + skb->len, priv->mcast_mtu + INFINIBAND_ALEN); ++priv->stats.tx_dropped; ++priv->stats.tx_errors; - dev_kfree_skb_any(skb); + ipoib_cm_skb_too_long(dev, skb, priv->mcast_mtu); return; } @@ -372,6 +373,7 @@ void ipoib_send(struct net_device *dev, if (priv->tx_head - priv->tx_tail == ipoib_sendq_size) { ipoib_dbg(priv, "TX ring full, stopping kernel net queue\n"); netif_stop_queue(dev); + set_bit(IPOIB_FLAG_NETIF_STOPPED, &priv->flags); } } } @@ -424,6 +426,13 @@ int ipoib_ib_dev_open(struct net_device return -1; } + ret = ipoib_cm_dev_open(dev); + if (ret) { + ipoib_warn(priv, "ipoib_ib_post_receives returned %d\n", ret); + ipoib_ib_dev_stop(dev); + return -1; + } + clear_bit(IPOIB_STOP_REAPER, &priv->flags); queue_delayed_work(ipoib_workqueue, &priv->ah_reap_task, HZ); @@ -509,6 +518,8 @@ int ipoib_ib_dev_stop(struct net_device clear_bit(IPOIB_FLAG_INITIALIZED, &priv->flags); + ipoib_cm_dev_stop(dev); + /* * Move our QP to the error state and then reinitialize in * when all work requests have completed or have been flushed. diff --git a/drivers/infiniband/ulp/ipoib/ipoib_main.c b/drivers/infiniband/ulp/ipoib/ipoib_main.c index 705eb1d..18d27fd 100644 --- a/drivers/infiniband/ulp/ipoib/ipoib_main.c +++ b/drivers/infiniband/ulp/ipoib/ipoib_main.c @@ -49,8 +49,6 @@ #include #include -#define IPOIB_QPN(ha) (be32_to_cpup((__be32 *) ha) & 0xffffff) - MODULE_AUTHOR("Roland Dreier"); MODULE_DESCRIPTION("IP-over-InfiniBand net driver"); MODULE_LICENSE("Dual BSD/GPL"); @@ -145,6 +143,8 @@ static int ipoib_stop(struct net_device netif_stop_queue(dev); + clear_bit(IPOIB_FLAG_NETIF_STOPPED, &priv->flags); + /* * Now flush workqueue to make sure a scheduled task doesn't * bring our internal state back up. @@ -178,8 +178,18 @@ static int ipoib_change_mtu(struct net_d { struct ipoib_dev_priv *priv = netdev_priv(dev); - if (new_mtu > IPOIB_PACKET_SIZE - IPOIB_ENCAP_LEN) + /* dev->mtu > 2K ==> connected mode */ + if (ipoib_cm_admin_enabled(dev) && new_mtu <= IPOIB_CM_MTU) { + if (new_mtu > priv->mcast_mtu) + ipoib_warn(priv, "mtu > %d will cause multicast packet drops.\n", + priv->mcast_mtu); + dev->mtu = new_mtu; + return 0; + } + + if (new_mtu > IPOIB_PACKET_SIZE - IPOIB_ENCAP_LEN) { return -EINVAL; + } priv->admin_mtu = new_mtu; @@ -414,6 +424,20 @@ static void path_rec_completion(int stat memcpy(&neigh->dgid.raw, &path->pathrec.dgid.raw, sizeof(union ib_gid)); + if (ipoib_cm_enabled(dev, neigh->neighbour)) { + if (!ipoib_cm_get(neigh)) + ipoib_cm_set(neigh, ipoib_cm_create_tx(dev, + path, + neigh)); + if (!ipoib_cm_get(neigh)) { + list_del(&neigh->list); + if (neigh->ah) + ipoib_put_ah(neigh->ah); + ipoib_neigh_free(dev, neigh); + continue; + } + } + while ((skb = __skb_dequeue(&neigh->queue))) __skb_queue_tail(&skqueue, skb); } @@ -520,7 +544,25 @@ static void neigh_add_path(struct sk_buf memcpy(&neigh->dgid.raw, &path->pathrec.dgid.raw, sizeof(union ib_gid)); - ipoib_send(dev, skb, path->ah, IPOIB_QPN(skb->dst->neighbour->ha)); + if (ipoib_cm_enabled(dev, neigh->neighbour)) { + if (!ipoib_cm_get(neigh)) + ipoib_cm_set(neigh, ipoib_cm_create_tx(dev, path, neigh)); + if (!ipoib_cm_get(neigh)) { + list_del(&neigh->list); + if (neigh->ah) + ipoib_put_ah(neigh->ah); + ipoib_neigh_free(dev, neigh); + goto err_drop; + } + if (skb_queue_len(&neigh->queue) < IPOIB_MAX_PATH_REC_QUEUE) + __skb_queue_tail(&neigh->queue, skb); + else { + ipoib_warn(priv, "queue length limit %d. Packet drop.\n", + skb_queue_len(&neigh->queue)); + goto err_drop; + } + } else + ipoib_send(dev, skb, path->ah, IPOIB_QPN(skb->dst->neighbour->ha)); } else { neigh->ah = NULL; @@ -538,6 +580,7 @@ err_list: err_path: ipoib_neigh_free(dev, neigh); +err_drop: ++priv->stats.tx_dropped; dev_kfree_skb_any(skb); @@ -640,7 +683,12 @@ static int ipoib_start_xmit(struct sk_bu neigh = *to_ipoib_neigh(skb->dst->neighbour); - if (likely(neigh->ah)) { + if (ipoib_cm_get(neigh)) { + if (ipoib_cm_up(neigh)) { + ipoib_cm_send(dev, skb, ipoib_cm_get(neigh)); + goto out; + } + } else if (neigh->ah) { if (unlikely(memcmp(&neigh->dgid.raw, skb->dst->neighbour->ha + 4, sizeof(union ib_gid)))) { @@ -805,6 +853,7 @@ struct ipoib_neigh *ipoib_neigh_alloc(st neigh->neighbour = neighbour; *to_ipoib_neigh(neighbour) = neigh; skb_queue_head_init(&neigh->queue); + ipoib_cm_set(neigh, NULL); return neigh; } @@ -818,6 +867,8 @@ void ipoib_neigh_free(struct net_device ++priv->stats.tx_dropped; dev_kfree_skb_any(skb); } + if (ipoib_cm_get(neigh)) + ipoib_cm_destroy_tx(ipoib_cm_get(neigh)); kfree(neigh); } @@ -958,16 +1009,17 @@ struct ipoib_dev_priv *ipoib_intf_alloc( return netdev_priv(dev); } -static ssize_t show_pkey(struct class_device *cdev, char *buf) +static ssize_t show_pkey(struct device *dev, + struct device_attribute *attr, char *buf) { - struct ipoib_dev_priv *priv = - netdev_priv(container_of(cdev, struct net_device, class_dev)); + struct ipoib_dev_priv *priv = netdev_priv(to_net_dev(dev)); return sprintf(buf, "0x%04x\n", priv->pkey); } -static CLASS_DEVICE_ATTR(pkey, S_IRUGO, show_pkey, NULL); +static DEVICE_ATTR(pkey, S_IRUGO, show_pkey, NULL); -static ssize_t create_child(struct class_device *cdev, +static ssize_t create_child(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) { int pkey; @@ -985,14 +1037,14 @@ static ssize_t create_child(struct class */ pkey |= 0x8000; - ret = ipoib_vlan_add(container_of(cdev, struct net_device, class_dev), - pkey); + ret = ipoib_vlan_add(to_net_dev(dev), pkey); return ret ? ret : count; } -static CLASS_DEVICE_ATTR(create_child, S_IWUGO, NULL, create_child); +static DEVICE_ATTR(create_child, S_IWUGO, NULL, create_child); -static ssize_t delete_child(struct class_device *cdev, +static ssize_t delete_child(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) { int pkey; @@ -1004,18 +1056,16 @@ static ssize_t delete_child(struct class if (pkey < 0 || pkey > 0xffff) return -EINVAL; - ret = ipoib_vlan_delete(container_of(cdev, struct net_device, class_dev), - pkey); + ret = ipoib_vlan_delete(to_net_dev(dev), pkey); return ret ? ret : count; } -static CLASS_DEVICE_ATTR(delete_child, S_IWUGO, NULL, delete_child); +static DEVICE_ATTR(delete_child, S_IWUGO, NULL, delete_child); int ipoib_add_pkey_attr(struct net_device *dev) { - return class_device_create_file(&dev->class_dev, - &class_device_attr_pkey); + return device_create_file(&dev->dev, &dev_attr_pkey); } static struct net_device *ipoib_add_port(const char *format, @@ -1081,13 +1131,13 @@ static struct net_device *ipoib_add_port ipoib_create_debug_files(priv->dev); + if (ipoib_cm_add_mode_attr(priv->dev)) + goto sysfs_failed; if (ipoib_add_pkey_attr(priv->dev)) goto sysfs_failed; - if (class_device_create_file(&priv->dev->class_dev, - &class_device_attr_create_child)) + if (device_create_file(&priv->dev->dev, &dev_attr_create_child)) goto sysfs_failed; - if (class_device_create_file(&priv->dev->class_dev, - &class_device_attr_delete_child)) + if (device_create_file(&priv->dev->dev, &dev_attr_delete_child)) goto sysfs_failed; return priv->dev; diff --git a/drivers/infiniband/ulp/ipoib/ipoib_multicast.c b/drivers/infiniband/ulp/ipoib/ipoib_multicast.c index b04b72c..fea737f 100644 --- a/drivers/infiniband/ulp/ipoib/ipoib_multicast.c +++ b/drivers/infiniband/ulp/ipoib/ipoib_multicast.c @@ -597,7 +597,9 @@ void ipoib_mcast_join_task(struct work_s priv->mcast_mtu = ib_mtu_enum_to_int(priv->broadcast->mcmember.mtu) - IPOIB_ENCAP_LEN; - dev->mtu = min(priv->mcast_mtu, priv->admin_mtu); + + if (!ipoib_cm_admin_enabled(dev)) + dev->mtu = min(priv->mcast_mtu, priv->admin_mtu); ipoib_dbg_mcast(priv, "successfully joined all multicast groups\n"); diff --git a/drivers/infiniband/ulp/ipoib/ipoib_verbs.c b/drivers/infiniband/ulp/ipoib/ipoib_verbs.c index 7b717c6..3cb551b 100644 --- a/drivers/infiniband/ulp/ipoib/ipoib_verbs.c +++ b/drivers/infiniband/ulp/ipoib/ipoib_verbs.c @@ -168,35 +168,41 @@ int ipoib_transport_dev_init(struct net_ .qp_type = IB_QPT_UD }; + int ret, size; + priv->pd = ib_alloc_pd(priv->ca); if (IS_ERR(priv->pd)) { printk(KERN_WARNING "%s: failed to allocate PD\n", ca->name); return -ENODEV; } - priv->cq = ib_create_cq(priv->ca, ipoib_ib_completion, NULL, dev, - ipoib_sendq_size + ipoib_recvq_size + 1); + priv->mr = ib_get_dma_mr(priv->pd, IB_ACCESS_LOCAL_WRITE); + if (IS_ERR(priv->mr)) { + printk(KERN_WARNING "%s: ib_get_dma_mr failed\n", ca->name); + goto out_free_pd; + } + + size = ipoib_sendq_size + ipoib_recvq_size + 1; + ret = ipoib_cm_dev_init(dev); + if (!ret) + size += ipoib_recvq_size; + + priv->cq = ib_create_cq(priv->ca, ipoib_ib_completion, NULL, dev, size); if (IS_ERR(priv->cq)) { printk(KERN_WARNING "%s: failed to create CQ\n", ca->name); - goto out_free_pd; + goto out_free_mr; } if (ib_req_notify_cq(priv->cq, IB_CQ_NEXT_COMP)) goto out_free_cq; - priv->mr = ib_get_dma_mr(priv->pd, IB_ACCESS_LOCAL_WRITE); - if (IS_ERR(priv->mr)) { - printk(KERN_WARNING "%s: ib_get_dma_mr failed\n", ca->name); - goto out_free_cq; - } - init_attr.send_cq = priv->cq; init_attr.recv_cq = priv->cq, priv->qp = ib_create_qp(priv->pd, &init_attr); if (IS_ERR(priv->qp)) { printk(KERN_WARNING "%s: failed to create QP\n", ca->name); - goto out_free_mr; + goto out_free_cq; } priv->dev->dev_addr[1] = (priv->qp->qp_num >> 16) & 0xff; @@ -212,12 +218,12 @@ int ipoib_transport_dev_init(struct net_ return 0; -out_free_mr: - ib_dereg_mr(priv->mr); - out_free_cq: ib_destroy_cq(priv->cq); +out_free_mr: + ib_dereg_mr(priv->mr); + out_free_pd: ib_dealloc_pd(priv->pd); return -ENODEV; @@ -235,12 +241,14 @@ void ipoib_transport_dev_cleanup(struct clear_bit(IPOIB_PKEY_ASSIGNED, &priv->flags); } - if (ib_dereg_mr(priv->mr)) - ipoib_warn(priv, "ib_dereg_mr failed\n"); - if (ib_destroy_cq(priv->cq)) ipoib_warn(priv, "ib_cq_destroy failed\n"); + ipoib_cm_dev_cleanup(dev); + + if (ib_dereg_mr(priv->mr)) + ipoib_warn(priv, "ib_dereg_mr failed\n"); + if (ib_dealloc_pd(priv->pd)) ipoib_warn(priv, "ib_dealloc_pd failed\n"); } diff --git a/drivers/infiniband/ulp/ipoib/ipoib_vlan.c b/drivers/infiniband/ulp/ipoib/ipoib_vlan.c index f887780..6762988 100644 --- a/drivers/infiniband/ulp/ipoib/ipoib_vlan.c +++ b/drivers/infiniband/ulp/ipoib/ipoib_vlan.c @@ -42,15 +42,15 @@ #include #include "ipoib.h" -static ssize_t show_parent(struct class_device *class_dev, char *buf) +static ssize_t show_parent(struct device *d, struct device_attribute *attr, + char *buf) { - struct net_device *dev = - container_of(class_dev, struct net_device, class_dev); + struct net_device *dev = to_net_dev(d); struct ipoib_dev_priv *priv = netdev_priv(dev); return sprintf(buf, "%s\n", priv->parent->name); } -static CLASS_DEVICE_ATTR(parent, S_IRUGO, show_parent, NULL); +static DEVICE_ATTR(parent, S_IRUGO, show_parent, NULL); int ipoib_vlan_add(struct net_device *pdev, unsigned short pkey) { @@ -115,11 +115,12 @@ int ipoib_vlan_add(struct net_device *pd ipoib_create_debug_files(priv->dev); + if (ipoib_cm_add_mode_attr(priv->dev)) + goto sysfs_failed; if (ipoib_add_pkey_attr(priv->dev)) goto sysfs_failed; - if (class_device_create_file(&priv->dev->class_dev, - &class_device_attr_parent)) + if (device_create_file(&priv->dev->dev, &dev_attr_parent)) goto sysfs_failed; list_add_tail(&priv->list, &ppriv->child_intfs); diff --git a/drivers/infiniband/ulp/iser/iser_initiator.c b/drivers/infiniband/ulp/iser/iser_initiator.c index 0a7d1ab..89e3728 100644 --- a/drivers/infiniband/ulp/iser/iser_initiator.c +++ b/drivers/infiniband/ulp/iser/iser_initiator.c @@ -567,7 +567,7 @@ void iser_rcv_completion(struct iser_des opcode = hdr->opcode & ISCSI_OPCODE_MASK; if (opcode == ISCSI_OP_SCSI_CMD_RSP) { - itt = hdr->itt & ISCSI_ITT_MASK; /* mask out cid and age bits */ + itt = get_itt(hdr->itt); /* mask out cid and age bits */ if (!(itt < session->cmds_max)) iser_err("itt can't be matched to task!!!" "conn %p opcode %d cmds_max %d itt %d\n", @@ -625,7 +625,7 @@ void iser_snd_completion(struct iser_des /* this arithmetic is legal by libiscsi dd_data allocation */ mtask = (void *) ((long)(void *)tx_desc - sizeof(struct iscsi_mgmt_task)); - if (mtask->hdr->itt == cpu_to_be32(ISCSI_RESERVED_TAG)) { + if (mtask->hdr->itt == RESERVED_ITT) { struct iscsi_session *session = conn->session; spin_lock(&conn->session->lock); diff --git a/drivers/infiniband/ulp/srp/ib_srp.c b/drivers/infiniband/ulp/srp/ib_srp.c index 72611fd..5e8ac57 100644 --- a/drivers/infiniband/ulp/srp/ib_srp.c +++ b/drivers/infiniband/ulp/srp/ib_srp.c @@ -548,6 +548,7 @@ static int srp_reconnect_target(struct s target->tx_head = 0; target->tx_tail = 0; + target->qp_in_error = 0; ret = srp_connect_target(target); if (ret) goto err; @@ -878,6 +879,7 @@ static void srp_completion(struct ib_cq printk(KERN_ERR PFX "failed %s status %d\n", wc.wr_id & SRP_OP_RECV ? "receive" : "send", wc.status); + target->qp_in_error = 1; break; } @@ -1337,6 +1339,8 @@ static int srp_abort(struct scsi_cmnd *s printk(KERN_ERR "SRP abort called\n"); + if (target->qp_in_error) + return FAILED; if (srp_find_req(target, scmnd, &req)) return FAILED; if (srp_send_tsk_mgmt(target, req, SRP_TSK_ABORT_TASK)) @@ -1365,6 +1369,8 @@ static int srp_reset_device(struct scsi_ printk(KERN_ERR "SRP reset_device called\n"); + if (target->qp_in_error) + return FAILED; if (srp_find_req(target, scmnd, &req)) return FAILED; if (srp_send_tsk_mgmt(target, req, SRP_TSK_LUN_RESET)) @@ -1801,6 +1807,7 @@ static ssize_t srp_create_target(struct goto err_free; } + target->qp_in_error = 0; ret = srp_connect_target(target); if (ret) { printk(KERN_ERR PFX "Connection failed\n"); diff --git a/drivers/infiniband/ulp/srp/ib_srp.h b/drivers/infiniband/ulp/srp/ib_srp.h index c217723..2f3319c 100644 --- a/drivers/infiniband/ulp/srp/ib_srp.h +++ b/drivers/infiniband/ulp/srp/ib_srp.h @@ -158,6 +158,7 @@ struct srp_target_port { struct completion done; int status; enum srp_target_state state; + int qp_in_error; }; struct srp_iu { diff --git a/drivers/input/ff-memless.c b/drivers/input/ff-memless.c index eba18b6..d226d93 100644 --- a/drivers/input/ff-memless.c +++ b/drivers/input/ff-memless.c @@ -29,7 +29,7 @@ #include #include #include #include -#include +#include #include "fixp-arith.h" diff --git a/drivers/input/gameport/ns558.c b/drivers/input/gameport/ns558.c index f68dbe6..7b7a546 100644 --- a/drivers/input/gameport/ns558.c +++ b/drivers/input/gameport/ns558.c @@ -151,7 +151,6 @@ static int ns558_isa_probe(int io) return -ENOMEM; } - memset(ns558, 0, sizeof(struct ns558)); ns558->io = io; ns558->size = 1 << i; ns558->gameport = port; diff --git a/drivers/input/input.c b/drivers/input/input.c index 7cf2b4f..efa1b1f 100644 --- a/drivers/input/input.c +++ b/drivers/input/input.c @@ -11,7 +11,6 @@ */ #include -#include #include #include #include @@ -482,7 +481,7 @@ static int input_proc_devices_open(struc return seq_open(file, &input_devices_seq_ops); } -static struct file_operations input_devices_fileops = { +static const struct file_operations input_devices_fileops = { .owner = THIS_MODULE, .open = input_proc_devices_open, .poll = input_proc_devices_poll, @@ -533,7 +532,7 @@ static int input_proc_handlers_open(stru return seq_open(file, &input_handlers_seq_ops); } -static struct file_operations input_handlers_fileops = { +static const struct file_operations input_handlers_fileops = { .owner = THIS_MODULE, .open = input_proc_handlers_open, .read = seq_read, @@ -1142,7 +1141,7 @@ static int input_open_file(struct inode return err; } -static struct file_operations input_fops = { +static const struct file_operations input_fops = { .owner = THIS_MODULE, .open = input_open_file, }; diff --git a/drivers/input/keyboard/Kconfig b/drivers/input/keyboard/Kconfig index 049f2f5..1b81a72 100644 --- a/drivers/input/keyboard/Kconfig +++ b/drivers/input/keyboard/Kconfig @@ -135,12 +135,12 @@ config KEYBOARD_STOWAWAY config KEYBOARD_CORGI tristate "Corgi keyboard" depends on PXA_SHARPSL - default y + default y help - Say Y here to enable the keyboard on the Sharp Zaurus SL-C7xx + Say Y here to enable the keyboard on the Sharp Zaurus SL-C7xx series of PDAs. - To compile this driver as a module, choose M here: the + To compile this driver as a module, choose M here: the module will be called corgikbd. config KEYBOARD_SPITZ @@ -214,4 +214,17 @@ config KEYBOARD_AAED2000 To compile this driver as a module, choose M here: the module will be called aaed2000_kbd. +config KEYBOARD_GPIO + tristate "Buttons on CPU GPIOs (PXA)" + depends on ARCH_PXA + help + This driver implements support for buttons connected + directly to GPIO pins of PXA CPUs. + + Say Y here if your device has buttons connected + directly to GPIO pins of the CPU. + + To compile this driver as a module, choose M here: the + module will be called gpio-keys. + endif diff --git a/drivers/input/keyboard/Makefile b/drivers/input/keyboard/Makefile index 5687979..586a0fe 100644 --- a/drivers/input/keyboard/Makefile +++ b/drivers/input/keyboard/Makefile @@ -16,6 +16,7 @@ obj-$(CONFIG_KEYBOARD_CORGI) += corgikb obj-$(CONFIG_KEYBOARD_SPITZ) += spitzkbd.o obj-$(CONFIG_KEYBOARD_HIL) += hil_kbd.o obj-$(CONFIG_KEYBOARD_HIL_OLD) += hilkbd.o -obj-$(CONFIG_KEYBOARD_OMAP) += omap-keypad.o -obj-$(CONFIG_KEYBOARD_AAED2000) += aaed2000_kbd.o +obj-$(CONFIG_KEYBOARD_OMAP) += omap-keypad.o +obj-$(CONFIG_KEYBOARD_AAED2000) += aaed2000_kbd.o +obj-$(CONFIG_KEYBOARD_GPIO) += gpio_keys.o diff --git a/drivers/input/keyboard/gpio_keys.c b/drivers/input/keyboard/gpio_keys.c new file mode 100644 index 0000000..7ad479e --- /dev/null +++ b/drivers/input/keyboard/gpio_keys.c @@ -0,0 +1,147 @@ +/* + * Driver for keys on GPIO lines capable of generating interrupts. + * + * Copyright 2005 Phil Blundell + * + * 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 + +static irqreturn_t gpio_keys_isr(int irq, void *dev_id) +{ + int i; + struct platform_device *pdev = dev_id; + struct gpio_keys_platform_data *pdata = pdev->dev.platform_data; + struct input_dev *input = platform_get_drvdata(pdev); + + for (i = 0; i < pdata->nbuttons; i++) { + int gpio = pdata->buttons[i].gpio; + if (irq == IRQ_GPIO(gpio)) { + int state = ((GPLR(gpio) & GPIO_bit(gpio)) ? 1 : 0) ^ (pdata->buttons[i].active_low); + + input_report_key(input, pdata->buttons[i].keycode, state); + input_sync(input); + } + } + + return IRQ_HANDLED; +} + +static int __devinit gpio_keys_probe(struct platform_device *pdev) +{ + struct gpio_keys_platform_data *pdata = pdev->dev.platform_data; + struct input_dev *input; + int i, error; + + input = input_allocate_device(); + if (!input) + return -ENOMEM; + + platform_set_drvdata(pdev, input); + + input->evbit[0] = BIT(EV_KEY); + + input->name = pdev->name; + input->phys = "gpio-keys/input0"; + input->cdev.dev = &pdev->dev; + input->private = pdata; + + input->id.bustype = BUS_HOST; + input->id.vendor = 0x0001; + input->id.product = 0x0001; + input->id.version = 0x0100; + + for (i = 0; i < pdata->nbuttons; i++) { + int code = pdata->buttons[i].keycode; + int irq = IRQ_GPIO(pdata->buttons[i].gpio); + + set_irq_type(irq, IRQ_TYPE_EDGE_BOTH); + error = request_irq(irq, gpio_keys_isr, IRQF_SAMPLE_RANDOM, + pdata->buttons[i].desc ? pdata->buttons[i].desc : "gpio_keys", + pdev); + if (error) { + printk(KERN_ERR "gpio-keys: unable to claim irq %d; error %d\n", irq, ret); + goto fail; + } + set_bit(code, input->keybit); + } + + error = input_register_device(input); + if (error) { + printk(KERN_ERR "Unable to register gpio-keys input device\n"); + goto fail; + } + + return 0; + + fail: + for (i = i - 1; i >= 0; i--) + free_irq(IRQ_GPIO(pdata->buttons[i].gpio), pdev); + + input_free_device(input); + + return error; +} + +static int __devexit gpio_keys_remove(struct platform_device *pdev) +{ + struct gpio_keys_platform_data *pdata = pdev->dev.platform_data; + struct input_dev *input = platform_get_drvdata(pdev); + int i; + + for (i = 0; i < pdata->nbuttons; i++) { + int irq = IRQ_GPIO(pdata->buttons[i].gpio); + free_irq(irq, pdev); + } + + input_unregister_device(input); + + return 0; +} + +struct platform_driver gpio_keys_device_driver = { + .probe = gpio_keys_probe, + .remove = __devexit_p(gpio_keys_remove), + .driver = { + .name = "gpio-keys", + } +}; + +static int __init gpio_keys_init(void) +{ + return platform_driver_register(&gpio_keys_device_driver); +} + +static void __exit gpio_keys_exit(void) +{ + platform_driver_unregister(&gpio_keys_device_driver); +} + +module_init(gpio_keys_init); +module_exit(gpio_keys_exit); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Phil Blundell "); +MODULE_DESCRIPTION("Keyboard driver for CPU GPIOs"); diff --git a/drivers/input/keyboard/hilkbd.c b/drivers/input/keyboard/hilkbd.c index 35461ea..255a6ec 100644 --- a/drivers/input/keyboard/hilkbd.c +++ b/drivers/input/keyboard/hilkbd.c @@ -6,10 +6,10 @@ * Copyright (C) 1999-2006 Helge Deller * * Very basic HP Human Interface Loop (HIL) driver. - * This driver handles the keyboard on HP300 (m68k) and on some + * This driver handles the keyboard on HP300 (m68k) and on some * HP700 (parisc) series machines. * - * + * * This file is subject to the terms and conditions of the GNU General Public * License version 2. See the file COPYING in the main directory of this * archive for more details. @@ -64,9 +64,9 @@ #error "HIL is not supported on this pla #endif - + /* HIL helper functions */ - + #define hil_busy() (hil_readb(HILBASE + HIL_CMD) & HIL_BUSY) #define hil_data_available() (hil_readb(HILBASE + HIL_CMD) & HIL_DATA_RDY) #define hil_status() (hil_readb(HILBASE + HIL_CMD)) @@ -75,7 +75,7 @@ #define hil_read_data() (hil_rea #define hil_write_data(x) do { hil_writeb((x), HILBASE + HIL_DATA); } while (0) /* HIL constants */ - + #define HIL_BUSY 0x02 #define HIL_DATA_RDY 0x01 @@ -86,10 +86,10 @@ #define HIL_CNMT 0xB2 /* clear nmi */ #define HIL_INTON 0x5C /* Turn on interrupts. */ #define HIL_INTOFF 0x5D /* Turn off interrupts. */ -#define HIL_READKBDSADR 0xF9 -#define HIL_WRITEKBDSADR 0xE9 +#define HIL_READKBDSADR 0xF9 +#define HIL_WRITEKBDSADR 0xE9 -static unsigned int hphilkeyb_keycode[HIL_KEYCODES_SET1_TBLSIZE] = +static unsigned int hphilkeyb_keycode[HIL_KEYCODES_SET1_TBLSIZE] = { HIL_KEYCODES_SET1 }; /* HIL structure */ @@ -97,11 +97,11 @@ static struct { struct input_dev *dev; unsigned int curdev; - + unsigned char s; unsigned char c; int valid; - + unsigned char data[16]; unsigned int ptr; spinlock_t lock; @@ -115,7 +115,7 @@ static void poll_finished(void) int down; int key; unsigned char scode; - + switch (hil_dev.data[0]) { case 0x40: down = (hil_dev.data[1] & 1) == 0; @@ -127,6 +127,7 @@ static void poll_finished(void) hil_dev.curdev = 0; } + static inline void handle_status(unsigned char s, unsigned char c) { if (c & 0x8) { @@ -143,6 +144,7 @@ static inline void handle_status(unsigne } } + static inline void handle_data(unsigned char s, unsigned char c) { if (hil_dev.curdev) { @@ -152,13 +154,11 @@ static inline void handle_data(unsigned } -/* - * Handle HIL interrupts. - */ +/* handle HIL interrupts */ static irqreturn_t hil_interrupt(int irq, void *handle) { unsigned char s, c; - + s = hil_status(); c = hil_read_data(); @@ -179,10 +179,8 @@ static irqreturn_t hil_interrupt(int irq return IRQ_HANDLED; } -/* - * Send a command to the HIL - */ +/* send a command to the HIL */ static void hil_do(unsigned char cmd, unsigned char *data, unsigned int len) { unsigned long flags; @@ -200,16 +198,14 @@ static void hil_do(unsigned char cmd, un } -/* - * Initialise HIL. - */ - +/* initialise HIL */ static int __init hil_keyb_init(void) { unsigned char c; unsigned int i, kbid; wait_queue_head_t hil_wait; + int err; if (hil_dev.dev) { return -ENODEV; /* already initialized */ @@ -219,15 +215,25 @@ hil_keyb_init(void) if (!hil_dev.dev) return -ENOMEM; hil_dev.dev->private = &hil_dev; - + #if defined(CONFIG_HP300) - if (!hwreg_present((void *)(HILBASE + HIL_DATA))) - return -ENODEV; - - request_region(HILBASE+HIL_DATA, 2, "hil"); + if (!hwreg_present((void *)(HILBASE + HIL_DATA))) { + printk(KERN_ERR "HIL: hardware register was not found\n"); + err = -ENODEV; + goto err1; + } + if (!request_region(HILBASE + HIL_DATA, 2, "hil")) { + printk(KERN_ERR "HIL: IOPORT region already used\n"); + err = -EIO; + goto err1; + } #endif - - request_irq(HIL_IRQ, hil_interrupt, 0, "hil", hil_dev.dev_id); + + err = request_irq(HIL_IRQ, hil_interrupt, 0, "hil", hil_dev.dev_id); + if (err) { + printk(KERN_ERR "HIL: Can't get IRQ\n"); + goto err2; + } /* Turn on interrupts */ hil_do(HIL_INTON, NULL, 0); @@ -239,47 +245,63 @@ #endif init_waitqueue_head(&hil_wait); wait_event_interruptible_timeout(hil_wait, hil_dev.valid, 3*HZ); if (!hil_dev.valid) { - printk(KERN_WARNING "HIL: timed out, assuming no keyboard present.\n"); + printk(KERN_WARNING "HIL: timed out, assuming no keyboard present\n"); } - c = hil_dev.c; + c = hil_dev.c; hil_dev.valid = 0; if (c == 0) { kbid = -1; - printk(KERN_WARNING "HIL: no keyboard present.\n"); + printk(KERN_WARNING "HIL: no keyboard present\n"); } else { kbid = ffz(~c); - /* printk(KERN_INFO "HIL: keyboard found at id %d\n", kbid); */ + printk(KERN_INFO "HIL: keyboard found at id %d\n", kbid); } /* set it to raw mode */ c = 0; hil_do(HIL_WRITEKBDSADR, &c, 1); - + for (i = 0; i < HIL_KEYCODES_SET1_TBLSIZE; i++) if (hphilkeyb_keycode[i] != KEY_RESERVED) set_bit(hphilkeyb_keycode[i], hil_dev.dev->keybit); - hil_dev.dev->evbit[0] = BIT(EV_KEY) | BIT(EV_REP); - hil_dev.dev->ledbit[0] = BIT(LED_NUML) | BIT(LED_CAPSL) | BIT(LED_SCROLLL); - hil_dev.dev->keycodemax = HIL_KEYCODES_SET1_TBLSIZE; - hil_dev.dev->keycodesize = sizeof(hphilkeyb_keycode[0]); - hil_dev.dev->keycode = hphilkeyb_keycode; - hil_dev.dev->name = "HIL keyboard"; - hil_dev.dev->phys = "hpkbd/input0"; + hil_dev.dev->evbit[0] = BIT(EV_KEY) | BIT(EV_REP); + hil_dev.dev->ledbit[0] = BIT(LED_NUML) | BIT(LED_CAPSL) | BIT(LED_SCROLLL); + hil_dev.dev->keycodemax = HIL_KEYCODES_SET1_TBLSIZE; + hil_dev.dev->keycodesize= sizeof(hphilkeyb_keycode[0]); + hil_dev.dev->keycode = hphilkeyb_keycode; + hil_dev.dev->name = "HIL keyboard"; + hil_dev.dev->phys = "hpkbd/input0"; hil_dev.dev->id.bustype = BUS_HIL; hil_dev.dev->id.vendor = PCI_VENDOR_ID_HP; hil_dev.dev->id.product = 0x0001; hil_dev.dev->id.version = 0x0010; - input_register_device(hil_dev.dev); + err = input_register_device(hil_dev.dev); + if (err) { + printk(KERN_ERR "HIL: Can't register device\n"); + goto err3; + } printk(KERN_INFO "input: %s, ID %d at 0x%08lx (irq %d) found and attached\n", - hil_dev.dev->name, kbid, HILBASE, HIL_IRQ); + hil_dev.dev->name, kbid, HILBASE, HIL_IRQ); return 0; + +err3: + hil_do(HIL_INTOFF, NULL, 0); + disable_irq(HIL_IRQ); + free_irq(HIL_IRQ, hil_dev.dev_id); +err2: + release_region(HILBASE + HIL_DATA, 2); +err1: + input_free_device(hil_dev.dev); + hil_dev.dev = NULL; + return err; } + #if defined(CONFIG_PARISC) static int __init hil_init_chip(struct parisc_device *dev) @@ -292,7 +314,7 @@ hil_init_chip(struct parisc_device *dev) hil_base = dev->hpa.start; hil_irq = dev->irq; hil_dev.dev_id = dev; - + printk(KERN_INFO "Found HIL bus at 0x%08lx, IRQ %d\n", hil_base, hil_irq); return hil_keyb_init(); @@ -313,9 +335,6 @@ static struct parisc_driver hil_driver = #endif /* CONFIG_PARISC */ - - - static int __init hil_init(void) { #if defined(CONFIG_PARISC) @@ -349,4 +368,3 @@ #endif module_init(hil_init); module_exit(hil_exit); - diff --git a/drivers/input/misc/Kconfig b/drivers/input/misc/Kconfig index ba0e88c..41b4258 100644 --- a/drivers/input/misc/Kconfig +++ b/drivers/input/misc/Kconfig @@ -50,6 +50,16 @@ config INPUT_WISTRON_BTNS To compile this driver as a module, choose M here: the module will be called wistron_btns. +config INPUT_ATLAS_BTNS + tristate "x86 Atlas button interface" + depends on X86 && ACPI + help + Say Y here for support of Atlas wallmount touchscreen buttons. + The events will show up as scancodes F1 through F9 via evdev. + + To compile this driver as a module, choose M here: the module will + be called atlas_btns. + config INPUT_IXP4XX_BEEPER tristate "IXP4XX Beeper support" depends on ARCH_IXP4XX diff --git a/drivers/input/misc/Makefile b/drivers/input/misc/Makefile index 415c491..e0a8d58 100644 --- a/drivers/input/misc/Makefile +++ b/drivers/input/misc/Makefile @@ -9,5 +9,6 @@ obj-$(CONFIG_INPUT_PCSPKR) += pcspkr.o obj-$(CONFIG_INPUT_M68K_BEEP) += m68kspkr.o obj-$(CONFIG_INPUT_UINPUT) += uinput.o obj-$(CONFIG_INPUT_WISTRON_BTNS) += wistron_btns.o +obj-$(CONFIG_INPUT_ATLAS_BTNS) += atlas_btns.o obj-$(CONFIG_HP_SDC_RTC) += hp_sdc_rtc.o obj-$(CONFIG_INPUT_IXP4XX_BEEPER) += ixp4xx-beeper.o diff --git a/drivers/input/misc/atlas_btns.c b/drivers/input/misc/atlas_btns.c new file mode 100644 index 0000000..0acc3a1 --- /dev/null +++ b/drivers/input/misc/atlas_btns.c @@ -0,0 +1,170 @@ +/* + * atlas_btns.c - Atlas Wallmount Touchscreen ACPI Extras + * + * Copyright (C) 2006 Jaya Kumar + * Based on Toshiba ACPI by John Belmonte and ASUS ACPI + * This work was sponsored by CIS(M) Sdn Bhd. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +#include +#include +#include +#include +#include +#include +#include + +#define ACPI_ATLAS_NAME "Atlas ACPI" +#define ACPI_ATLAS_CLASS "Atlas" +#define ACPI_ATLAS_BUTTON_HID "ASIM0000" + +static struct input_dev *input_dev; + +/* button handling code */ +static acpi_status acpi_atlas_button_setup(acpi_handle region_handle, + u32 function, void *handler_context, void **return_context) +{ + *return_context = + (function != ACPI_REGION_DEACTIVATE) ? handler_context : NULL; + + return AE_OK; +} + +static acpi_status acpi_atlas_button_handler(u32 function, + acpi_physical_address address, + u32 bit_width, acpi_integer *value, + void *handler_context, void *region_context) +{ + acpi_status status; + int keycode; + + if (function == ACPI_WRITE) { + keycode = KEY_F1 + (address & 0x0F); + input_report_key(input_dev, keycode, !(address & 0x10)); + input_sync(input_dev); + status = 0; + } else { + printk(KERN_WARNING "atlas: shrugged on unexpected function" + ":function=%x,address=%lx,value=%x\n", + function, (unsigned long)address, (u32)*value); + status = -EINVAL; + } + + return status; +} + +static int atlas_acpi_button_add(struct acpi_device *device) +{ + acpi_status status; + int err; + + input_dev = input_allocate_device(); + if (!input_dev) { + printk(KERN_ERR "atlas: unable to allocate input device\n"); + return -ENOMEM; + } + + input_dev->name = "Atlas ACPI button driver"; + input_dev->phys = "ASIM0000/atlas/input0"; + input_dev->id.bustype = BUS_HOST; + input_dev->evbit[LONG(EV_KEY)] = BIT(EV_KEY); + + set_bit(KEY_F1, input_dev->keybit); + set_bit(KEY_F2, input_dev->keybit); + set_bit(KEY_F3, input_dev->keybit); + set_bit(KEY_F4, input_dev->keybit); + set_bit(KEY_F5, input_dev->keybit); + set_bit(KEY_F6, input_dev->keybit); + set_bit(KEY_F7, input_dev->keybit); + set_bit(KEY_F8, input_dev->keybit); + set_bit(KEY_F9, input_dev->keybit); + + err = input_register_device(input_dev); + if (err) { + printk(KERN_ERR "atlas: couldn't register input device\n"); + input_free_device(input_dev); + return err; + } + + /* hookup button handler */ + status = acpi_install_address_space_handler(device->handle, + 0x81, &acpi_atlas_button_handler, + &acpi_atlas_button_setup, device); + if (ACPI_FAILURE(status)) { + printk(KERN_ERR "Atlas: Error installing addr spc handler\n"); + input_unregister_device(input_dev); + status = -EINVAL; + } + + return status; +} + +static int atlas_acpi_button_remove(struct acpi_device *device, int type) +{ + acpi_status status; + + status = acpi_remove_address_space_handler(device->handle, + 0x81, &acpi_atlas_button_handler); + if (ACPI_FAILURE(status)) { + printk(KERN_ERR "Atlas: Error removing addr spc handler\n"); + status = -EINVAL; + } + + input_unregister_device(input_dev); + + return status; +} + +static struct acpi_driver atlas_acpi_driver = { + .name = ACPI_ATLAS_NAME, + .class = ACPI_ATLAS_CLASS, + .ids = ACPI_ATLAS_BUTTON_HID, + .ops = { + .add = atlas_acpi_button_add, + .remove = atlas_acpi_button_remove, + }, +}; + +static int __init atlas_acpi_init(void) +{ + int result; + + if (acpi_disabled) + return -ENODEV; + + result = acpi_bus_register_driver(&atlas_acpi_driver); + if (result < 0) { + printk(KERN_ERR "Atlas ACPI: Unable to register driver\n"); + return -ENODEV; + } + + return 0; +} + +static void __exit atlas_acpi_exit(void) +{ + acpi_bus_unregister_driver(&atlas_acpi_driver); +} + +module_init(atlas_acpi_init); +module_exit(atlas_acpi_exit); + +MODULE_AUTHOR("Jaya Kumar"); +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("Atlas button driver"); + diff --git a/drivers/input/misc/hp_sdc_rtc.c b/drivers/input/misc/hp_sdc_rtc.c index 31d5a13..ab76ea4 100644 --- a/drivers/input/misc/hp_sdc_rtc.c +++ b/drivers/input/misc/hp_sdc_rtc.c @@ -670,7 +670,7 @@ #else #endif } -static struct file_operations hp_sdc_rtc_fops = { +static const struct file_operations hp_sdc_rtc_fops = { .owner = THIS_MODULE, .llseek = no_llseek, .read = hp_sdc_rtc_read, diff --git a/drivers/input/misc/uinput.c b/drivers/input/misc/uinput.c index 9516439..4255623 100644 --- a/drivers/input/misc/uinput.c +++ b/drivers/input/misc/uinput.c @@ -627,7 +627,7 @@ static long uinput_ioctl(struct file *fi return retval; } -static struct file_operations uinput_fops = { +static const struct file_operations uinput_fops = { .owner = THIS_MODULE, .open = uinput_open, .release = uinput_release, diff --git a/drivers/input/misc/wistron_btns.c b/drivers/input/misc/wistron_btns.c index 7b9d1c1..e1183ae 100644 --- a/drivers/input/misc/wistron_btns.c +++ b/drivers/input/misc/wistron_btns.c @@ -335,6 +335,17 @@ static struct key_entry keymap_aopen_155 { KE_END, 0 }, }; +static struct key_entry keymap_fs_amilo_d88x0[] = { + { KE_KEY, 0x01, KEY_HELP }, + { KE_KEY, 0x08, KEY_MUTE }, + { KE_KEY, 0x31, KEY_MAIL }, + { KE_KEY, 0x36, KEY_WWW }, + { KE_KEY, 0x11, KEY_PROG1 }, + { KE_KEY, 0x12, KEY_PROG2 }, + { KE_KEY, 0x13, KEY_PROG3 }, + { KE_END, 0 } +}; + /* * If your machine is not here (which is currently rather likely), please send * a list of buttons and their key codes (reported when loading this module @@ -413,6 +424,15 @@ static struct dmi_system_id dmi_ids[] __ }, .driver_data = keymap_wistron_ms2111 }, + { + .callback = dmi_matched, + .ident = "Fujitsu Siemens Amilo D88x0", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU SIEMENS"), + DMI_MATCH(DMI_PRODUCT_NAME, "AMILO D"), + }, + .driver_data = keymap_fs_amilo_d88x0 + }, { NULL, } }; diff --git a/drivers/input/mouse/inport.c b/drivers/input/mouse/inport.c index 13dd967..701ebd5 100644 --- a/drivers/input/mouse/inport.c +++ b/drivers/input/mouse/inport.c @@ -61,7 +61,7 @@ #define INPORT_REG_Y 0x02 #define INPORT_REG_MODE 0x07 #define INPORT_RESET 0x80 -#ifdef CONFIG_INPUT_ATIXL +#ifdef CONFIG_MOUSE_ATIXL #define INPORT_NAME "ATI XL Mouse" #define INPORT_VENDOR 0x0002 #define INPORT_SPEED_30HZ 0x01 diff --git a/drivers/input/mouse/pc110pad.c b/drivers/input/mouse/pc110pad.c index f155c1f..05d992e 100644 --- a/drivers/input/mouse/pc110pad.c +++ b/drivers/input/mouse/pc110pad.c @@ -113,7 +113,7 @@ static int __init pc110pad_init(void) dev = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, NULL); if (dev) { pci_dev_put(dev); - return -ENOENT; + return -ENODEV; } if (!request_region(pc110pad_io, 4, "pc110pad")) { diff --git a/drivers/input/mouse/rpcmouse.c b/drivers/input/mouse/rpcmouse.c index fbdcfd8..355efd0 100644 --- a/drivers/input/mouse/rpcmouse.c +++ b/drivers/input/mouse/rpcmouse.c @@ -18,7 +18,6 @@ */ #include -#include #include #include #include diff --git a/drivers/input/serio/hil_mlc.c b/drivers/input/serio/hil_mlc.c index 49e11e2..4fa93ff 100644 --- a/drivers/input/serio/hil_mlc.c +++ b/drivers/input/serio/hil_mlc.c @@ -59,7 +59,6 @@ #include #include #include #include -#include #include MODULE_AUTHOR("Brian S. Julin "); diff --git a/drivers/input/serio/hp_sdc.c b/drivers/input/serio/hp_sdc.c index 9907ad3..b57370d 100644 --- a/drivers/input/serio/hp_sdc.c +++ b/drivers/input/serio/hp_sdc.c @@ -62,7 +62,6 @@ */ #include -#include #include #include #include diff --git a/drivers/input/serio/i8042.c b/drivers/input/serio/i8042.c index debe944..c3fdfc1 100644 --- a/drivers/input/serio/i8042.c +++ b/drivers/input/serio/i8042.c @@ -371,7 +371,7 @@ static irqreturn_t i8042_interrupt(int i if (unlikely(i8042_suppress_kbd_ack)) if (port_no == I8042_KBD_PORT_NO && (data == 0xfa || data == 0xfe)) { - i8042_suppress_kbd_ack = 0; + i8042_suppress_kbd_ack--; goto out; } @@ -543,6 +543,7 @@ static int __devinit i8042_check_aux(voi { int retval = -1; int irq_registered = 0; + int aux_loop_broken = 0; unsigned long flags; unsigned char param; @@ -572,6 +573,8 @@ static int __devinit i8042_check_aux(voi if (i8042_command(¶m, I8042_CMD_AUX_TEST) || (param && param != 0xfa && param != 0xff)) return -1; + + aux_loop_broken = 1; } /* @@ -595,7 +598,7 @@ static int __devinit i8042_check_aux(voi * used it for a PCI card or somethig else. */ - if (i8042_noloop) { + if (i8042_noloop || aux_loop_broken) { /* * Without LOOP command we can't test AUX IRQ delivery. Assume the port * is working and hope we are right. @@ -838,13 +841,14 @@ static long i8042_panic_blink(long count led ^= 0x01 | 0x04; while (i8042_read_status() & I8042_STR_IBF) DELAY; - i8042_suppress_kbd_ack = 1; + dbg("%02x -> i8042 (panic blink)", 0xed); + i8042_suppress_kbd_ack = 2; i8042_write_data(0xed); /* set leds */ DELAY; while (i8042_read_status() & I8042_STR_IBF) DELAY; DELAY; - i8042_suppress_kbd_ack = 1; + dbg("%02x -> i8042 (panic blink)", led); i8042_write_data(led); DELAY; last_blink = count; diff --git a/drivers/input/serio/serio.c b/drivers/input/serio/serio.c index f0ce822..17c8c63 100644 --- a/drivers/input/serio/serio.c +++ b/drivers/input/serio/serio.c @@ -45,7 +45,7 @@ EXPORT_SYMBOL(serio_interrupt); EXPORT_SYMBOL(__serio_register_port); EXPORT_SYMBOL(serio_unregister_port); EXPORT_SYMBOL(serio_unregister_child_port); -EXPORT_SYMBOL(serio_register_driver); +EXPORT_SYMBOL(__serio_register_driver); EXPORT_SYMBOL(serio_unregister_driver); EXPORT_SYMBOL(serio_open); EXPORT_SYMBOL(serio_close); @@ -789,12 +789,14 @@ static void serio_attach_driver(struct s drv->driver.name, error); } -int serio_register_driver(struct serio_driver *drv) +int __serio_register_driver(struct serio_driver *drv, struct module *owner, const char *mod_name) { int manual_bind = drv->manual_bind; int error; drv->driver.bus = &serio_bus; + drv->driver.owner = owner; + drv->driver.mod_name = mod_name; /* * Temporarily disable automatic binding because probing diff --git a/drivers/input/serio/serio_raw.c b/drivers/input/serio/serio_raw.c index 088ebc3..8873576 100644 --- a/drivers/input/serio/serio_raw.c +++ b/drivers/input/serio/serio_raw.c @@ -234,7 +234,7 @@ static unsigned int serio_raw_poll(struc return 0; } -static struct file_operations serio_raw_fops = { +static const struct file_operations serio_raw_fops = { .owner = THIS_MODULE, .open = serio_raw_open, .release = serio_raw_release, diff --git a/drivers/input/touchscreen/Kconfig b/drivers/input/touchscreen/Kconfig index 6b46c9b..9716180 100644 --- a/drivers/input/touchscreen/Kconfig +++ b/drivers/input/touchscreen/Kconfig @@ -12,13 +12,18 @@ menuconfig INPUT_TOUCHSCREEN if INPUT_TOUCHSCREEN config TOUCHSCREEN_ADS7846 - tristate "ADS 7846 based touchscreens" + tristate "ADS 7846/7843 based touchscreens" depends on SPI_MASTER + depends on HWMON = n || HWMON help Say Y here if you have a touchscreen interface using the - ADS7846 controller, and your board-specific initialization + ADS7846 or ADS7843 controller, and your board-specific setup code includes that in its table of SPI devices. + If HWMON is selected, and the driver is told the reference voltage + on your board, you will also get hwmon interfaces for the voltage + (and on ads7846, temperature) sensors of this chip. + If unsure, say N (but it's safe to say "Y"). To compile this driver as a module, choose M here: the diff --git a/drivers/input/touchscreen/ads7846.c b/drivers/input/touchscreen/ads7846.c index c6164b6..0a26e06 100644 --- a/drivers/input/touchscreen/ads7846.c +++ b/drivers/input/touchscreen/ads7846.c @@ -17,8 +17,9 @@ * 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 @@ -54,7 +55,8 @@ #endif * files. */ -#define TS_POLL_PERIOD msecs_to_jiffies(10) +#define TS_POLL_DELAY (1 * 1000000) /* ns delay before the first sample */ +#define TS_POLL_PERIOD (5 * 1000000) /* ns delay between samples */ /* this driver doesn't aim at the peak continuous sample rate */ #define SAMPLE_BITS (8 /*cmd*/ + 16 /*sample*/ + 2 /* before, after */) @@ -63,12 +65,12 @@ struct ts_event { /* For portability, we can't read 12 bit values using SPI (which * would make the controller deliver them as native byteorder u16 * with msbs zeroed). Instead, we read them as two 8-bit values, - * which need byteswapping then range adjustment. + * *** WHICH NEED BYTESWAPPING *** and range adjustment. */ - __be16 x; - __be16 y; - __be16 z1, z2; - int ignore; + u16 x; + u16 y; + u16 z1, z2; + int ignore; }; struct ads7846 { @@ -76,7 +78,12 @@ struct ads7846 { char phys[32]; struct spi_device *spi; + +#if defined(CONFIG_HWMON) || defined(CONFIG_HWMON_MODULE) struct attribute_group *attr_group; + struct class_device *hwmon; +#endif + u16 model; u16 vref_delay_usecs; u16 x_plate_ohms; @@ -99,13 +106,16 @@ struct ads7846 { u16 debounce_rep; spinlock_t lock; - struct timer_list timer; /* P: lock */ + struct hrtimer timer; unsigned pendown:1; /* P: lock */ unsigned pending:1; /* P: lock */ // FIXME remove "irq_disabled" unsigned irq_disabled:1; /* P: lock */ unsigned disabled:1; + int (*filter)(void *data, int data_idx, int *val); + void *filter_data; + void (*filter_cleanup)(void *data); int (*get_pendown_state)(void); }; @@ -142,15 +152,16 @@ #define ADS_PD10_ALL_ON (3 << 0) /* ADC #define MAX_12BIT ((1<<12)-1) /* leave ADC powered up (disables penirq) between differential samples */ -#define READ_12BIT_DFR(x) (ADS_START | ADS_A2A1A0_d_ ## x \ - | ADS_12_BIT | ADS_DFR) +#define READ_12BIT_DFR(x, adc, vref) (ADS_START | ADS_A2A1A0_d_ ## x \ + | ADS_12_BIT | ADS_DFR | \ + (adc ? ADS_PD10_ADC_ON : 0) | (vref ? ADS_PD10_REF_ON : 0)) -#define READ_Y (READ_12BIT_DFR(y) | ADS_PD10_ADC_ON) -#define READ_Z1 (READ_12BIT_DFR(z1) | ADS_PD10_ADC_ON) -#define READ_Z2 (READ_12BIT_DFR(z2) | ADS_PD10_ADC_ON) +#define READ_Y(vref) (READ_12BIT_DFR(y, 1, vref)) +#define READ_Z1(vref) (READ_12BIT_DFR(z1, 1, vref)) +#define READ_Z2(vref) (READ_12BIT_DFR(z2, 1, vref)) -#define READ_X (READ_12BIT_DFR(x) | ADS_PD10_ADC_ON) -#define PWRDOWN (READ_12BIT_DFR(y) | ADS_PD10_PDOWN) /* LAST */ +#define READ_X(vref) (READ_12BIT_DFR(x, 1, vref)) +#define PWRDOWN (READ_12BIT_DFR(y, 0, 0)) /* LAST */ /* single-ended samples need to first power up reference voltage; * we leave both ADC and VREF powered @@ -158,14 +169,19 @@ #define PWRDOWN (READ_12BIT_DFR(y) | AD #define READ_12BIT_SER(x) (ADS_START | ADS_A2A1A0_ ## x \ | ADS_12_BIT | ADS_SER) -#define REF_ON (READ_12BIT_DFR(x) | ADS_PD10_ALL_ON) -#define REF_OFF (READ_12BIT_DFR(y) | ADS_PD10_PDOWN) +#define REF_ON (READ_12BIT_DFR(x, 1, 1)) +#define REF_OFF (READ_12BIT_DFR(y, 0, 0)) /*--------------------------------------------------------------------------*/ /* * Non-touchscreen sensors only use single-ended conversions. + * The range is GND..vREF. The ads7843 and ads7835 must use external vREF; + * ads7846 lets that pin be unconnected, to use internal vREF. */ +static unsigned vREF_mV; +module_param(vREF_mV, uint, 0); +MODULE_PARM_DESC(vREF_mV, "external vREF voltage, in milliVolts"); struct ser_req { u8 ref_on; @@ -193,50 +209,55 @@ static int ads7846_read12_ser(struct dev struct ser_req *req = kzalloc(sizeof *req, GFP_KERNEL); int status; int sample; - int i; + int use_internal; if (!req) return -ENOMEM; spi_message_init(&req->msg); - /* activate reference, so it has time to settle; */ - req->ref_on = REF_ON; - req->xfer[0].tx_buf = &req->ref_on; - req->xfer[0].len = 1; - req->xfer[1].rx_buf = &req->scratch; - req->xfer[1].len = 2; - - /* - * for external VREF, 0 usec (and assume it's always on); - * for 1uF, use 800 usec; - * no cap, 100 usec. - */ - req->xfer[1].delay_usecs = ts->vref_delay_usecs; + /* FIXME boards with ads7846 might use external vref instead ... */ + use_internal = (ts->model == 7846); + + /* maybe turn on internal vREF, and let it settle */ + if (use_internal) { + req->ref_on = REF_ON; + req->xfer[0].tx_buf = &req->ref_on; + req->xfer[0].len = 1; + spi_message_add_tail(&req->xfer[0], &req->msg); + + req->xfer[1].rx_buf = &req->scratch; + req->xfer[1].len = 2; + + /* for 1uF, settle for 800 usec; no cap, 100 usec. */ + req->xfer[1].delay_usecs = ts->vref_delay_usecs; + spi_message_add_tail(&req->xfer[1], &req->msg); + } /* take sample */ req->command = (u8) command; req->xfer[2].tx_buf = &req->command; req->xfer[2].len = 1; + spi_message_add_tail(&req->xfer[2], &req->msg); + req->xfer[3].rx_buf = &req->sample; req->xfer[3].len = 2; + spi_message_add_tail(&req->xfer[3], &req->msg); /* REVISIT: take a few more samples, and compare ... */ - /* turn off reference */ - req->ref_off = REF_OFF; - req->xfer[4].tx_buf = &req->ref_off; - req->xfer[4].len = 1; - req->xfer[5].rx_buf = &req->scratch; - req->xfer[5].len = 2; - - CS_CHANGE(req->xfer[5]); - - /* group all the transfers together, so we can't interfere with - * reading touchscreen state; disable penirq while sampling - */ - for (i = 0; i < 6; i++) - spi_message_add_tail(&req->xfer[i], &req->msg); + /* maybe off internal vREF */ + if (use_internal) { + req->ref_off = REF_OFF; + req->xfer[4].tx_buf = &req->ref_off; + req->xfer[4].len = 1; + spi_message_add_tail(&req->xfer[4], &req->msg); + + req->xfer[5].rx_buf = &req->scratch; + req->xfer[5].len = 2; + CS_CHANGE(req->xfer[5]); + spi_message_add_tail(&req->xfer[5], &req->msg); + } ts->irq_disabled = 1; disable_irq(spi->irq); @@ -256,25 +277,173 @@ static int ads7846_read12_ser(struct dev return status ? status : sample; } -#define SHOW(name) static ssize_t \ +#if defined(CONFIG_HWMON) || defined(CONFIG_HWMON_MODULE) + +#define SHOW(name, var, adjust) static ssize_t \ name ## _show(struct device *dev, struct device_attribute *attr, char *buf) \ { \ + struct ads7846 *ts = dev_get_drvdata(dev); \ ssize_t v = ads7846_read12_ser(dev, \ - READ_12BIT_SER(name) | ADS_PD10_ALL_ON); \ + READ_12BIT_SER(var) | ADS_PD10_ALL_ON); \ if (v < 0) \ return v; \ - return sprintf(buf, "%u\n", (unsigned) v); \ + return sprintf(buf, "%u\n", adjust(ts, v)); \ } \ static DEVICE_ATTR(name, S_IRUGO, name ## _show, NULL); -SHOW(temp0) -SHOW(temp1) -SHOW(vaux) -SHOW(vbatt) + +/* Sysfs conventions report temperatures in millidegrees Celcius. + * ADS7846 could use the low-accuracy two-sample scheme, but can't do the high + * accuracy scheme without calibration data. For now we won't try either; + * userspace sees raw sensor values, and must scale/calibrate appropriately. + */ +static inline unsigned null_adjust(struct ads7846 *ts, ssize_t v) +{ + return v; +} + +SHOW(temp0, temp0, null_adjust) /* temp1_input */ +SHOW(temp1, temp1, null_adjust) /* temp2_input */ + + +/* sysfs conventions report voltages in millivolts. We can convert voltages + * if we know vREF. userspace may need to scale vAUX to match the board's + * external resistors; we assume that vBATT only uses the internal ones. + */ +static inline unsigned vaux_adjust(struct ads7846 *ts, ssize_t v) +{ + unsigned retval = v; + + /* external resistors may scale vAUX into 0..vREF */ + retval *= vREF_mV; + retval = retval >> 12; + return retval; +} + +static inline unsigned vbatt_adjust(struct ads7846 *ts, ssize_t v) +{ + unsigned retval = vaux_adjust(ts, v); + + /* ads7846 has a resistor ladder to scale this signal down */ + if (ts->model == 7846) + retval *= 4; + return retval; +} + +SHOW(in0_input, vaux, vaux_adjust) +SHOW(in1_input, vbatt, vbatt_adjust) + + +static struct attribute *ads7846_attributes[] = { + &dev_attr_temp0.attr, + &dev_attr_temp1.attr, + &dev_attr_in0_input.attr, + &dev_attr_in1_input.attr, + NULL, +}; + +static struct attribute_group ads7846_attr_group = { + .attrs = ads7846_attributes, +}; + +static struct attribute *ads7843_attributes[] = { + &dev_attr_in0_input.attr, + &dev_attr_in1_input.attr, + NULL, +}; + +static struct attribute_group ads7843_attr_group = { + .attrs = ads7843_attributes, +}; + +static struct attribute *ads7845_attributes[] = { + &dev_attr_in0_input.attr, + NULL, +}; + +static struct attribute_group ads7845_attr_group = { + .attrs = ads7845_attributes, +}; + +static int ads784x_hwmon_register(struct spi_device *spi, struct ads7846 *ts) +{ + struct class_device *hwmon; + int err; + + /* hwmon sensors need a reference voltage */ + switch (ts->model) { + case 7846: + if (!vREF_mV) { + dev_dbg(&spi->dev, "assuming 2.5V internal vREF\n"); + vREF_mV = 2500; + } + break; + case 7845: + case 7843: + if (!vREF_mV) { + dev_warn(&spi->dev, + "external vREF for ADS%d not specified\n", + ts->model); + return 0; + } + break; + } + + /* different chips have different sensor groups */ + switch (ts->model) { + case 7846: + ts->attr_group = &ads7846_attr_group; + break; + case 7845: + ts->attr_group = &ads7845_attr_group; + break; + case 7843: + ts->attr_group = &ads7843_attr_group; + break; + default: + dev_dbg(&spi->dev, "ADS%d not recognized\n", ts->model); + return 0; + } + + err = sysfs_create_group(&spi->dev.kobj, ts->attr_group); + if (err) + return err; + + hwmon = hwmon_device_register(&spi->dev); + if (IS_ERR(hwmon)) { + sysfs_remove_group(&spi->dev.kobj, ts->attr_group); + return PTR_ERR(hwmon); + } + + ts->hwmon = hwmon; + return 0; +} + +static void ads784x_hwmon_unregister(struct spi_device *spi, + struct ads7846 *ts) +{ + if (ts->hwmon) { + sysfs_remove_group(&spi->dev.kobj, ts->attr_group); + hwmon_device_unregister(ts->hwmon); + } +} + +#else +static inline int ads784x_hwmon_register(struct spi_device *spi, + struct ads7846 *ts) +{ + return 0; +} + +static inline void ads784x_hwmon_unregister(struct spi_device *spi, + struct ads7846 *ts) +{ +} +#endif static int is_pen_down(struct device *dev) { - struct ads7846 *ts = dev_get_drvdata(dev); + struct ads7846 *ts = dev_get_drvdata(dev); return ts->pendown; } @@ -318,46 +487,14 @@ static ssize_t ads7846_disable_store(str static DEVICE_ATTR(disable, 0664, ads7846_disable_show, ads7846_disable_store); -static struct attribute *ads7846_attributes[] = { - &dev_attr_temp0.attr, - &dev_attr_temp1.attr, - &dev_attr_vbatt.attr, - &dev_attr_vaux.attr, - &dev_attr_pen_down.attr, - &dev_attr_disable.attr, - NULL, -}; - -static struct attribute_group ads7846_attr_group = { - .attrs = ads7846_attributes, -}; - -/* - * ads7843/7845 don't have temperature sensors, and - * use the other sensors a bit differently too - */ - -static struct attribute *ads7843_attributes[] = { - &dev_attr_vbatt.attr, - &dev_attr_vaux.attr, +static struct attribute *ads784x_attributes[] = { &dev_attr_pen_down.attr, &dev_attr_disable.attr, NULL, }; -static struct attribute_group ads7843_attr_group = { - .attrs = ads7843_attributes, -}; - -static struct attribute *ads7845_attributes[] = { - &dev_attr_vaux.attr, - &dev_attr_pen_down.attr, - &dev_attr_disable.attr, - NULL, -}; - -static struct attribute_group ads7845_attr_group = { - .attrs = ads7845_attributes, +static struct attribute_group ads784x_attr_group = { + .attrs = ads784x_attributes, }; /*--------------------------------------------------------------------------*/ @@ -373,25 +510,22 @@ static struct attribute_group ads7845_at static void ads7846_rx(void *ads) { struct ads7846 *ts = ads; - struct input_dev *input_dev = ts->input; unsigned Rt; - unsigned sync = 0; u16 x, y, z1, z2; - unsigned long flags; - /* adjust: on-wire is a must-ignore bit, a BE12 value, then padding; - * built from two 8 bit values written msb-first. + /* ads7846_rx_val() did in-place conversion (including byteswap) from + * on-the-wire format as part of debouncing to get stable readings. */ - x = (be16_to_cpu(ts->tc.x) >> 3) & 0x0fff; - y = (be16_to_cpu(ts->tc.y) >> 3) & 0x0fff; - z1 = (be16_to_cpu(ts->tc.z1) >> 3) & 0x0fff; - z2 = (be16_to_cpu(ts->tc.z2) >> 3) & 0x0fff; + x = ts->tc.x; + y = ts->tc.y; + z1 = ts->tc.z1; + z2 = ts->tc.z2; /* range filtering */ if (x == MAX_12BIT) x = 0; - if (likely(x && z1 && !device_suspended(&ts->spi->dev))) { + if (likely(x && z1)) { /* compute touch pressure resistance using equation #2 */ Rt = z2; Rt -= z1; @@ -403,100 +537,130 @@ static void ads7846_rx(void *ads) Rt = 0; /* Sample found inconsistent by debouncing or pressure is beyond - * the maximum. Don't report it to user space, repeat at least - * once more the measurement */ + * the maximum. Don't report it to user space, repeat at least + * once more the measurement + */ if (ts->tc.ignore || Rt > ts->pressure_max) { - mod_timer(&ts->timer, jiffies + TS_POLL_PERIOD); +#ifdef VERBOSE + pr_debug("%s: ignored %d pressure %d\n", + ts->spi->dev.bus_id, ts->tc.ignore, Rt); +#endif + hrtimer_start(&ts->timer, ktime_set(0, TS_POLL_PERIOD), + HRTIMER_MODE_REL); return; } - /* NOTE: "pendown" is inferred from pressure; we don't rely on - * being able to check nPENIRQ status, or "friendly" trigger modes - * (both-edges is much better than just-falling or low-level). + /* NOTE: We can't rely on the pressure to determine the pen down + * state, even this controller has a pressure sensor. The pressure + * value can fluctuate for quite a while after lifting the pen and + * in some cases may not even settle at the expected value. * - * REVISIT: some boards may require reading nPENIRQ; it's - * needed on 7843. and 7845 reads pressure differently... - * - * REVISIT: the touchscreen might not be connected; this code - * won't notice that, even if nPENIRQ never fires ... + * The only safe way to check for the pen up condition is in the + * timer by reading the pen signal state (it's a GPIO _and_ IRQ). */ - if (!ts->pendown && Rt != 0) { - input_report_key(input_dev, BTN_TOUCH, 1); - sync = 1; - } else if (ts->pendown && Rt == 0) { - input_report_key(input_dev, BTN_TOUCH, 0); - sync = 1; - } - if (Rt) { - input_report_abs(input_dev, ABS_X, x); - input_report_abs(input_dev, ABS_Y, y); - sync = 1; - } - - if (sync) { - input_report_abs(input_dev, ABS_PRESSURE, Rt); - input_sync(input_dev); - } + struct input_dev *input = ts->input; -#ifdef VERBOSE - if (Rt || ts->pendown) - pr_debug("%s: %d/%d/%d%s\n", ts->spi->dev.bus_id, - x, y, Rt, Rt ? "" : " UP"); + if (!ts->pendown) { + input_report_key(input, BTN_TOUCH, 1); + ts->pendown = 1; +#ifdef VERBOSE + dev_dbg(&ts->spi->dev, "DOWN\n"); #endif + } + input_report_abs(input, ABS_X, x); + input_report_abs(input, ABS_Y, y); + input_report_abs(input, ABS_PRESSURE, Rt); - spin_lock_irqsave(&ts->lock, flags); - - ts->pendown = (Rt != 0); - mod_timer(&ts->timer, jiffies + TS_POLL_PERIOD); + input_sync(input); +#ifdef VERBOSE + dev_dbg(&ts->spi->dev, "%4d/%4d/%4d\n", x, y, Rt); +#endif + } - spin_unlock_irqrestore(&ts->lock, flags); + hrtimer_start(&ts->timer, ktime_set(0, TS_POLL_PERIOD), + HRTIMER_MODE_REL); } -static void ads7846_debounce(void *ads) +static int ads7846_debounce(void *ads, int data_idx, int *val) { struct ads7846 *ts = ads; - struct spi_message *m; - struct spi_transfer *t; - int val; - int status; - m = &ts->msg[ts->msg_idx]; - t = list_entry(m->transfers.prev, struct spi_transfer, transfer_list); - val = (be16_to_cpu(*(__be16 *)t->rx_buf) >> 3) & 0x0fff; - if (!ts->read_cnt || (abs(ts->last_read - val) > ts->debounce_tol)) { + if (!ts->read_cnt || (abs(ts->last_read - *val) > ts->debounce_tol)) { + /* Start over collecting consistent readings. */ + ts->read_rep = 0; /* Repeat it, if this was the first read or the read * wasn't consistent enough. */ if (ts->read_cnt < ts->debounce_max) { - ts->last_read = val; + ts->last_read = *val; ts->read_cnt++; + return ADS7846_FILTER_REPEAT; } else { /* Maximum number of debouncing reached and still * not enough number of consistent readings. Abort * the whole sample, repeat it in the next sampling * period. */ - ts->tc.ignore = 1; ts->read_cnt = 0; - /* Last message will contain ads7846_rx() as the - * completion function. - */ - m = ts->last_msg; + return ADS7846_FILTER_IGNORE; } - /* Start over collecting consistent readings. */ - ts->read_rep = 0; } else { if (++ts->read_rep > ts->debounce_rep) { /* Got a good reading for this coordinate, * go for the next one. */ - ts->tc.ignore = 0; - ts->msg_idx++; ts->read_cnt = 0; ts->read_rep = 0; - m++; - } else + return ADS7846_FILTER_OK; + } else { /* Read more values that are consistent. */ ts->read_cnt++; + return ADS7846_FILTER_REPEAT; + } + } +} + +static int ads7846_no_filter(void *ads, int data_idx, int *val) +{ + return ADS7846_FILTER_OK; +} + +static void ads7846_rx_val(void *ads) +{ + struct ads7846 *ts = ads; + struct spi_message *m; + struct spi_transfer *t; + u16 *rx_val; + int val; + int action; + int status; + + m = &ts->msg[ts->msg_idx]; + t = list_entry(m->transfers.prev, struct spi_transfer, transfer_list); + rx_val = t->rx_buf; + + /* adjust: on-wire is a must-ignore bit, a BE12 value, then padding; + * built from two 8 bit values written msb-first. + */ + val = be16_to_cpu(*rx_val) >> 3; + + action = ts->filter(ts->filter_data, ts->msg_idx, &val); + switch (action) { + case ADS7846_FILTER_REPEAT: + break; + case ADS7846_FILTER_IGNORE: + ts->tc.ignore = 1; + /* Last message will contain ads7846_rx() as the + * completion function. + */ + m = ts->last_msg; + break; + case ADS7846_FILTER_OK: + *rx_val = val; + ts->tc.ignore = 0; + m = &ts->msg[++ts->msg_idx]; + break; + default: + BUG(); } status = spi_async(ts->spi, m); if (status) @@ -504,21 +668,34 @@ static void ads7846_debounce(void *ads) status); } -static void ads7846_timer(unsigned long handle) +static enum hrtimer_restart ads7846_timer(struct hrtimer *handle) { - struct ads7846 *ts = (void *)handle; + struct ads7846 *ts = container_of(handle, struct ads7846, timer); int status = 0; spin_lock_irq(&ts->lock); - if (unlikely(ts->msg_idx && !ts->pendown)) { + if (unlikely(!ts->get_pendown_state() || + device_suspended(&ts->spi->dev))) { + if (ts->pendown) { + struct input_dev *input = ts->input; + + input_report_key(input, BTN_TOUCH, 0); + input_report_abs(input, ABS_PRESSURE, 0); + input_sync(input); + + ts->pendown = 0; +#ifdef VERBOSE + dev_dbg(&ts->spi->dev, "UP\n"); +#endif + } + /* measurement cycle ended */ if (!device_suspended(&ts->spi->dev)) { ts->irq_disabled = 0; enable_irq(ts->spi->irq); } ts->pending = 0; - ts->msg_idx = 0; } else { /* pen is still down, continue with the measurement */ ts->msg_idx = 0; @@ -528,6 +705,7 @@ static void ads7846_timer(unsigned long } spin_unlock_irq(&ts->lock); + return HRTIMER_NORESTART; } static irqreturn_t ads7846_irq(int irq, void *handle) @@ -546,7 +724,8 @@ static irqreturn_t ads7846_irq(int irq, ts->irq_disabled = 1; disable_irq(ts->spi->irq); ts->pending = 1; - mod_timer(&ts->timer, jiffies); + hrtimer_start(&ts->timer, ktime_set(0, TS_POLL_DELAY), + HRTIMER_MODE_REL); } } spin_unlock_irqrestore(&ts->lock, flags); @@ -632,6 +811,7 @@ static int __devinit ads7846_probe(struc struct ads7846_platform_data *pdata = spi->dev.platform_data; struct spi_message *m; struct spi_transfer *x; + int vref; int err; if (!spi->irq) { @@ -665,6 +845,10 @@ static int __devinit ads7846_probe(struc * may not. So we stick to very-portable 8 bit words, both RX and TX. */ spi->bits_per_word = 8; + spi->mode = SPI_MODE_1; + err = spi_setup(spi); + if (err < 0) + return err; ts = kzalloc(sizeof(struct ads7846), GFP_KERNEL); input_dev = input_allocate_device(); @@ -679,8 +863,7 @@ static int __devinit ads7846_probe(struc ts->spi = spi; ts->input = input_dev; - init_timer(&ts->timer); - ts->timer.data = (unsigned long) ts; + hrtimer_init(&ts->timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL); ts->timer.function = ads7846_timer; spin_lock_init(&ts->lock); @@ -689,14 +872,25 @@ static int __devinit ads7846_probe(struc ts->vref_delay_usecs = pdata->vref_delay_usecs ? : 100; ts->x_plate_ohms = pdata->x_plate_ohms ? : 400; ts->pressure_max = pdata->pressure_max ? : ~0; - if (pdata->debounce_max) { + + if (pdata->filter != NULL) { + if (pdata->filter_init != NULL) { + err = pdata->filter_init(pdata, &ts->filter_data); + if (err < 0) + goto err_free_mem; + } + ts->filter = pdata->filter; + ts->filter_cleanup = pdata->filter_cleanup; + } else if (pdata->debounce_max) { ts->debounce_max = pdata->debounce_max; + if (ts->debounce_max < 2) + ts->debounce_max = 2; ts->debounce_tol = pdata->debounce_tol; ts->debounce_rep = pdata->debounce_rep; - if (ts->debounce_rep > ts->debounce_max + 1) - ts->debounce_rep = ts->debounce_max - 1; + ts->filter = ads7846_debounce; + ts->filter_data = ts; } else - ts->debounce_tol = ~0; + ts->filter = ads7846_no_filter; ts->get_pendown_state = pdata->get_pendown_state; snprintf(ts->phys, sizeof(ts->phys), "%s/input0", spi->dev.bus_id); @@ -718,6 +912,8 @@ static int __devinit ads7846_probe(struc input_set_abs_params(input_dev, ABS_PRESSURE, pdata->pressure_min, pdata->pressure_max, 0, 0); + vref = pdata->keep_vref_on; + /* set up the transfers to read touchscreen state; this assumes we * use formula #2 for pressure, not #3. */ @@ -727,7 +923,7 @@ static int __devinit ads7846_probe(struc spi_message_init(m); /* y- still on; turn on only y+ (and ADC) */ - ts->read_y = READ_Y; + ts->read_y = READ_Y(vref); x->tx_buf = &ts->read_y; x->len = 1; spi_message_add_tail(x, m); @@ -737,7 +933,7 @@ static int __devinit ads7846_probe(struc x->len = 2; spi_message_add_tail(x, m); - m->complete = ads7846_debounce; + m->complete = ads7846_rx_val; m->context = ts; m++; @@ -745,7 +941,7 @@ static int __devinit ads7846_probe(struc /* turn y- off, x+ on, then leave in lowpower */ x++; - ts->read_x = READ_X; + ts->read_x = READ_X(vref); x->tx_buf = &ts->read_x; x->len = 1; spi_message_add_tail(x, m); @@ -755,7 +951,7 @@ static int __devinit ads7846_probe(struc x->len = 2; spi_message_add_tail(x, m); - m->complete = ads7846_debounce; + m->complete = ads7846_rx_val; m->context = ts; /* turn y+ off, x- on; we'll use formula #2 */ @@ -764,7 +960,7 @@ static int __devinit ads7846_probe(struc spi_message_init(m); x++; - ts->read_z1 = READ_Z1; + ts->read_z1 = READ_Z1(vref); x->tx_buf = &ts->read_z1; x->len = 1; spi_message_add_tail(x, m); @@ -774,14 +970,14 @@ static int __devinit ads7846_probe(struc x->len = 2; spi_message_add_tail(x, m); - m->complete = ads7846_debounce; + m->complete = ads7846_rx_val; m->context = ts; m++; spi_message_init(m); x++; - ts->read_z2 = READ_Z2; + ts->read_z2 = READ_Z2(vref); x->tx_buf = &ts->read_z2; x->len = 1; spi_message_add_tail(x, m); @@ -791,7 +987,7 @@ static int __devinit ads7846_probe(struc x->len = 2; spi_message_add_tail(x, m); - m->complete = ads7846_debounce; + m->complete = ads7846_rx_val; m->context = ts; } @@ -820,31 +1016,24 @@ static int __devinit ads7846_probe(struc spi->dev.driver->name, ts)) { dev_dbg(&spi->dev, "irq %d busy?\n", spi->irq); err = -EBUSY; - goto err_free_mem; + goto err_cleanup_filter; } + err = ads784x_hwmon_register(spi, ts); + if (err) + goto err_free_irq; + dev_info(&spi->dev, "touchscreen, irq %d\n", spi->irq); - /* take a first sample, leaving nPENIRQ active; avoid + /* take a first sample, leaving nPENIRQ active and vREF off; avoid * the touchscreen, in case it's not connected. */ (void) ads7846_read12_ser(&spi->dev, READ_12BIT_SER(vaux) | ADS_PD10_ALL_ON); - switch (ts->model) { - case 7846: - ts->attr_group = &ads7846_attr_group; - break; - case 7845: - ts->attr_group = &ads7845_attr_group; - break; - default: - ts->attr_group = &ads7843_attr_group; - break; - } - err = sysfs_create_group(&spi->dev.kobj, ts->attr_group); + err = sysfs_create_group(&spi->dev.kobj, &ads784x_attr_group); if (err) - goto err_free_irq; + goto err_remove_hwmon; err = input_register_device(input_dev); if (err) @@ -853,9 +1042,14 @@ static int __devinit ads7846_probe(struc return 0; err_remove_attr_group: - sysfs_remove_group(&spi->dev.kobj, ts->attr_group); + sysfs_remove_group(&spi->dev.kobj, &ads784x_attr_group); + err_remove_hwmon: + ads784x_hwmon_unregister(spi, ts); err_free_irq: free_irq(spi->irq, ts); + err_cleanup_filter: + if (ts->filter_cleanup) + ts->filter_cleanup(ts->filter_data); err_free_mem: input_free_device(input_dev); kfree(ts); @@ -866,16 +1060,20 @@ static int __devexit ads7846_remove(stru { struct ads7846 *ts = dev_get_drvdata(&spi->dev); + ads784x_hwmon_unregister(spi, ts); input_unregister_device(ts->input); ads7846_suspend(spi, PMSG_SUSPEND); - sysfs_remove_group(&spi->dev.kobj, ts->attr_group); + sysfs_remove_group(&spi->dev.kobj, &ads784x_attr_group); free_irq(ts->spi->irq, ts); /* suspend left the IRQ disabled */ enable_irq(ts->spi->irq); + if (ts->filter_cleanup) + ts->filter_cleanup(ts->filter_data); + kfree(ts); dev_dbg(&spi->dev, "unregistered touchscreen\n"); diff --git a/drivers/input/touchscreen/ucb1400_ts.c b/drivers/input/touchscreen/ucb1400_ts.c index 4358a0a..c7db403 100644 --- a/drivers/input/touchscreen/ucb1400_ts.c +++ b/drivers/input/touchscreen/ucb1400_ts.c @@ -83,7 +83,7 @@ #define UCB_ID_1400 0x4304 struct ucb1400 { - ac97_t *ac97; + struct snd_ac97 *ac97; struct input_dev *ts_idev; int irq; diff --git a/drivers/input/tsdev.c b/drivers/input/tsdev.c index a730c46..0300dca 100644 --- a/drivers/input/tsdev.c +++ b/drivers/input/tsdev.c @@ -151,6 +151,10 @@ static int tsdev_open(struct inode *inod int i = iminor(inode) - TSDEV_MINOR_BASE; struct tsdev_list *list; + printk(KERN_WARNING "tsdev (compaq touchscreen emulation) is scheduled " + "for removal.\nSee Documentation/feature-removal-schedule.txt " + "for details.\n"); + if (i >= TSDEV_MINORS || !tsdev_table[i & TSDEV_MINOR_MASK]) return -ENODEV; diff --git a/drivers/isdn/capi/capi.c b/drivers/isdn/capi/capi.c index d22c022..db1260f 100644 --- a/drivers/isdn/capi/capi.c +++ b/drivers/isdn/capi/capi.c @@ -118,6 +118,15 @@ struct capiminor { }; #endif /* CONFIG_ISDN_CAPI_MIDDLEWARE */ +/* FIXME: The following lock is a sledgehammer-workaround to a + * locking issue with the capiminor (and maybe other) data structure(s). + * Access to this data is done in a racy way and crashes the machine with + * a FritzCard DSL driver; sooner or later. This is a workaround + * which trades scalability vs stability, so it doesn't crash the kernel anymore. + * The correct (and scalable) fix for the issue seems to require + * an API change to the drivers... . */ +static DEFINE_SPINLOCK(workaround_lock); + struct capincci { struct capincci *next; u32 ncci; @@ -589,6 +598,7 @@ #ifdef CONFIG_ISDN_CAPI_MIDDLEWARE #endif /* CONFIG_ISDN_CAPI_MIDDLEWARE */ struct capincci *np; u32 ncci; + unsigned long flags; if (CAPIMSG_CMD(skb->data) == CAPI_CONNECT_B3_CONF) { u16 info = CAPIMSG_U16(skb->data, 12); // Info field @@ -603,9 +613,11 @@ #endif /* CONFIG_ISDN_CAPI_MIDDLEWARE */ capincci_alloc(cdev, CAPIMSG_NCCI(skb->data)); up(&cdev->ncci_list_sem); } + spin_lock_irqsave(&workaround_lock, flags); if (CAPIMSG_COMMAND(skb->data) != CAPI_DATA_B3) { skb_queue_tail(&cdev->recvqueue, skb); wake_up_interruptible(&cdev->recvwait); + spin_unlock_irqrestore(&workaround_lock, flags); return; } ncci = CAPIMSG_CONTROL(skb->data); @@ -615,6 +627,7 @@ #endif /* CONFIG_ISDN_CAPI_MIDDLEWARE */ printk(KERN_ERR "BUG: capi_signal: ncci not found\n"); skb_queue_tail(&cdev->recvqueue, skb); wake_up_interruptible(&cdev->recvwait); + spin_unlock_irqrestore(&workaround_lock, flags); return; } #ifndef CONFIG_ISDN_CAPI_MIDDLEWARE @@ -625,6 +638,7 @@ #else /* CONFIG_ISDN_CAPI_MIDDLEWARE */ if (!mp) { skb_queue_tail(&cdev->recvqueue, skb); wake_up_interruptible(&cdev->recvwait); + spin_unlock_irqrestore(&workaround_lock, flags); return; } @@ -660,6 +674,7 @@ #endif wake_up_interruptible(&cdev->recvwait); } #endif /* CONFIG_ISDN_CAPI_MIDDLEWARE */ + spin_unlock_irqrestore(&workaround_lock, flags); } /* -------- file_operations for capidev ----------------------------- */ @@ -988,7 +1003,7 @@ capi_release(struct inode *inode, struct return 0; } -static struct file_operations capi_fops = +static const struct file_operations capi_fops = { .owner = THIS_MODULE, .llseek = no_llseek, @@ -1006,6 +1021,7 @@ #ifdef CONFIG_ISDN_CAPI_MIDDLEWARE static int capinc_tty_open(struct tty_struct * tty, struct file * file) { struct capiminor *mp; + unsigned long flags; if ((mp = capiminor_find(iminor(file->f_path.dentry->d_inode))) == 0) return -ENXIO; @@ -1014,6 +1030,7 @@ static int capinc_tty_open(struct tty_st tty->driver_data = (void *)mp; + spin_lock_irqsave(&workaround_lock, flags); if (atomic_read(&mp->ttyopencount) == 0) mp->tty = tty; atomic_inc(&mp->ttyopencount); @@ -1021,6 +1038,7 @@ #ifdef _DEBUG_REFCOUNT printk(KERN_DEBUG "capinc_tty_open ocount=%d\n", atomic_read(&mp->ttyopencount)); #endif handle_minor_recv(mp); + spin_unlock_irqrestore(&workaround_lock, flags); return 0; } @@ -1054,6 +1072,7 @@ static int capinc_tty_write(struct tty_s { struct capiminor *mp = (struct capiminor *)tty->driver_data; struct sk_buff *skb; + unsigned long flags; #ifdef _DEBUG_TTYFUNCS printk(KERN_DEBUG "capinc_tty_write(count=%d)\n", count); @@ -1066,6 +1085,7 @@ #endif return 0; } + spin_lock_irqsave(&workaround_lock, flags); skb = mp->ttyskb; if (skb) { mp->ttyskb = NULL; @@ -1076,6 +1096,7 @@ #endif skb = alloc_skb(CAPI_DATA_B3_REQ_LEN+count, GFP_ATOMIC); if (!skb) { printk(KERN_ERR "capinc_tty_write: alloc_skb failed\n"); + spin_unlock_irqrestore(&workaround_lock, flags); return -ENOMEM; } @@ -1086,6 +1107,7 @@ #endif mp->outbytes += skb->len; (void)handle_minor_send(mp); (void)handle_minor_recv(mp); + spin_unlock_irqrestore(&workaround_lock, flags); return count; } @@ -1093,6 +1115,7 @@ static void capinc_tty_put_char(struct t { struct capiminor *mp = (struct capiminor *)tty->driver_data; struct sk_buff *skb; + unsigned long flags; #ifdef _DEBUG_TTYFUNCS printk(KERN_DEBUG "capinc_put_char(%u)\n", ch); @@ -1105,10 +1128,12 @@ #endif return; } + spin_lock_irqsave(&workaround_lock, flags); skb = mp->ttyskb; if (skb) { if (skb_tailroom(skb) > 0) { *(skb_put(skb, 1)) = ch; + spin_unlock_irqrestore(&workaround_lock, flags); return; } mp->ttyskb = NULL; @@ -1124,12 +1149,14 @@ #endif } else { printk(KERN_ERR "capinc_put_char: char %u lost\n", ch); } + spin_unlock_irqrestore(&workaround_lock, flags); } static void capinc_tty_flush_chars(struct tty_struct *tty) { struct capiminor *mp = (struct capiminor *)tty->driver_data; struct sk_buff *skb; + unsigned long flags; #ifdef _DEBUG_TTYFUNCS printk(KERN_DEBUG "capinc_tty_flush_chars\n"); @@ -1142,6 +1169,7 @@ #endif return; } + spin_lock_irqsave(&workaround_lock, flags); skb = mp->ttyskb; if (skb) { mp->ttyskb = NULL; @@ -1150,6 +1178,7 @@ #endif (void)handle_minor_send(mp); } (void)handle_minor_recv(mp); + spin_unlock_irqrestore(&workaround_lock, flags); } static int capinc_tty_write_room(struct tty_struct *tty) @@ -1220,12 +1249,15 @@ #endif static void capinc_tty_unthrottle(struct tty_struct * tty) { struct capiminor *mp = (struct capiminor *)tty->driver_data; + unsigned long flags; #ifdef _DEBUG_TTYFUNCS printk(KERN_DEBUG "capinc_tty_unthrottle\n"); #endif if (mp) { + spin_lock_irqsave(&workaround_lock, flags); mp->ttyinstop = 0; handle_minor_recv(mp); + spin_unlock_irqrestore(&workaround_lock, flags); } } @@ -1243,12 +1275,15 @@ #endif static void capinc_tty_start(struct tty_struct *tty) { struct capiminor *mp = (struct capiminor *)tty->driver_data; + unsigned long flags; #ifdef _DEBUG_TTYFUNCS printk(KERN_DEBUG "capinc_tty_start\n"); #endif if (mp) { + spin_lock_irqsave(&workaround_lock, flags); mp->ttyoutstop = 0; (void)handle_minor_send(mp); + spin_unlock_irqrestore(&workaround_lock, flags); } } @@ -1456,7 +1491,7 @@ static struct procfsentries { static void __init proc_init(void) { - int nelem = sizeof(procfsentries)/sizeof(procfsentries[0]); + int nelem = ARRAY_SIZE(procfsentries); int i; for (i=0; i < nelem; i++) { @@ -1468,7 +1503,7 @@ static void __init proc_init(void) static void __exit proc_exit(void) { - int nelem = sizeof(procfsentries)/sizeof(procfsentries[0]); + int nelem = ARRAY_SIZE(procfsentries); int i; for (i=nelem-1; i >= 0; i--) { diff --git a/drivers/isdn/capi/capidrv.c b/drivers/isdn/capi/capidrv.c index c4d438c..2a49cea 100644 --- a/drivers/isdn/capi/capidrv.c +++ b/drivers/isdn/capi/capidrv.c @@ -13,7 +13,6 @@ #include #include #include #include -#include #include #include #include @@ -2218,7 +2217,7 @@ static struct procfsentries { static void __init proc_init(void) { - int nelem = sizeof(procfsentries)/sizeof(procfsentries[0]); + int nelem = ARRAY_SIZE(procfsentries); int i; for (i=0; i < nelem; i++) { @@ -2230,7 +2229,7 @@ static void __init proc_init(void) static void __exit proc_exit(void) { - int nelem = sizeof(procfsentries)/sizeof(procfsentries[0]); + int nelem = ARRAY_SIZE(procfsentries); int i; for (i=nelem-1; i >= 0; i--) { diff --git a/drivers/isdn/capi/kcapi_proc.c b/drivers/isdn/capi/kcapi_proc.c index ca9dc00..31f4fd8 100644 --- a/drivers/isdn/capi/kcapi_proc.c +++ b/drivers/isdn/capi/kcapi_proc.c @@ -113,14 +113,14 @@ static int seq_contrstats_open(struct in return seq_open(file, &seq_contrstats_ops); } -static struct file_operations proc_controller_ops = { +static const struct file_operations proc_controller_ops = { .open = seq_controller_open, .read = seq_read, .llseek = seq_lseek, .release = seq_release, }; -static struct file_operations proc_contrstats_ops = { +static const struct file_operations proc_contrstats_ops = { .open = seq_contrstats_open, .read = seq_read, .llseek = seq_lseek, @@ -218,14 +218,14 @@ seq_applstats_open(struct inode *inode, return seq_open(file, &seq_applstats_ops); } -static struct file_operations proc_applications_ops = { +static const struct file_operations proc_applications_ops = { .open = seq_applications_open, .read = seq_read, .llseek = seq_lseek, .release = seq_release, }; -static struct file_operations proc_applstats_ops = { +static const struct file_operations proc_applstats_ops = { .open = seq_applstats_open, .read = seq_read, .llseek = seq_lseek, @@ -302,7 +302,7 @@ seq_capi_driver_open(struct inode *inode return err; } -static struct file_operations proc_driver_ops = { +static const struct file_operations proc_driver_ops = { .open = seq_capi_driver_open, .read = seq_read, .llseek = seq_lseek, diff --git a/drivers/isdn/divert/divert_procfs.c b/drivers/isdn/divert/divert_procfs.c index 06967da..53a1890 100644 --- a/drivers/isdn/divert/divert_procfs.c +++ b/drivers/isdn/divert/divert_procfs.c @@ -256,7 +256,7 @@ isdn_divert_ioctl(struct inode *inode, s #ifdef CONFIG_PROC_FS -static struct file_operations isdn_fops = +static const struct file_operations isdn_fops = { .owner = THIS_MODULE, .llseek = no_llseek, diff --git a/drivers/isdn/gigaset/Kconfig b/drivers/isdn/gigaset/Kconfig index 708d47a..bcbb650 100644 --- a/drivers/isdn/gigaset/Kconfig +++ b/drivers/isdn/gigaset/Kconfig @@ -7,7 +7,13 @@ config ISDN_DRV_GIGASET select CRC_CCITT select BITREVERSE help - Say m here if you have a Gigaset or Sinus isdn device. + This driver supports the Siemens Gigaset SX205/255 family of + ISDN DECT bases, including the predecessors Gigaset 3070/3075 + and 4170/4175 and their T-Com versions Sinus 45isdn and Sinus + 721X. + If you have one of these devices, say M here and for at least + one of the connection specific parts that follow. + This will build a module called "gigaset". if ISDN_DRV_GIGASET!=n @@ -15,14 +21,25 @@ config GIGASET_BASE tristate "Gigaset base station support" depends on ISDN_DRV_GIGASET && USB help - Say m here if you need to communicate with the base - directly via USB. + Say M here if you want to use the USB interface of the Gigaset + base for connection to your system. + This will build a module called "bas_gigaset". config GIGASET_M105 tristate "Gigaset M105 support" depends on ISDN_DRV_GIGASET && USB help - Say m here if you need the driver for the Gigaset M105 device. + Say M here if you want to connect to the Gigaset base via DECT + using a Gigaset M105 (Sinus 45 Data 2) USB DECT device. + This will build a module called "usb_gigaset". + +config GIGASET_M101 + tristate "Gigaset M101 support" + depends on ISDN_DRV_GIGASET + help + Say M here if you want to connect to the Gigaset base via DECT + using a Gigaset M101 (Sinus 45 Data 1) RS232 DECT device. + This will build a module called "ser_gigaset". config GIGASET_DEBUG bool "Gigaset debugging" diff --git a/drivers/isdn/gigaset/Makefile b/drivers/isdn/gigaset/Makefile index 9b9acf1..077e297 100644 --- a/drivers/isdn/gigaset/Makefile +++ b/drivers/isdn/gigaset/Makefile @@ -1,6 +1,8 @@ gigaset-y := common.o interface.o proc.o ev-layer.o i4l.o usb_gigaset-y := usb-gigaset.o asyncdata.o bas_gigaset-y := bas-gigaset.o isocdata.o +ser_gigaset-y := ser-gigaset.o asyncdata.o obj-$(CONFIG_GIGASET_M105) += usb_gigaset.o gigaset.o obj-$(CONFIG_GIGASET_BASE) += bas_gigaset.o gigaset.o +obj-$(CONFIG_GIGASET_M101) += ser_gigaset.o gigaset.o diff --git a/drivers/isdn/gigaset/asyncdata.c b/drivers/isdn/gigaset/asyncdata.c index 88e958f..ddf5e92 100644 --- a/drivers/isdn/gigaset/asyncdata.c +++ b/drivers/isdn/gigaset/asyncdata.c @@ -13,6 +13,11 @@ * ===================================================================== */ +/* not set by Kbuild when building both ser_gigaset and usb_gigaset */ +#ifndef KBUILD_MODNAME +#define KBUILD_MODNAME "asy_gigaset" +#endif + #include "gigaset.h" #include #include diff --git a/drivers/isdn/gigaset/bas-gigaset.c b/drivers/isdn/gigaset/bas-gigaset.c index b5e7f9c..63e51dd 100644 --- a/drivers/isdn/gigaset/bas-gigaset.c +++ b/drivers/isdn/gigaset/bas-gigaset.c @@ -257,10 +257,10 @@ #ifdef CONFIG_GIGASET_DEBUG urb->transfer_flags); gig_dbg(level, " transfer_buffer=0x%08lx[%d], actual_length=%d, " - "bandwidth=%d, setup_packet=0x%08lx,", + "setup_packet=0x%08lx,", (unsigned long) urb->transfer_buffer, urb->transfer_buffer_length, urb->actual_length, - urb->bandwidth, (unsigned long) urb->setup_packet); + (unsigned long) urb->setup_packet); gig_dbg(level, " start_frame=%d, number_of_packets=%d, interval=%d, " "error_count=%d,", diff --git a/drivers/isdn/gigaset/common.c b/drivers/isdn/gigaset/common.c index 4f75cce..b460a73 100644 --- a/drivers/isdn/gigaset/common.c +++ b/drivers/isdn/gigaset/common.c @@ -640,7 +640,6 @@ struct cardstate *gigaset_initcs(struct return NULL; } mutex_init(&cs->mutex); - mutex_lock(&cs->mutex); gig_dbg(DEBUG_INIT, "allocating bcs[0..%d]", channels - 1); cs->bcs = kmalloc(channels * sizeof(struct bc_state), GFP_KERNEL); @@ -738,6 +737,7 @@ struct cardstate *gigaset_initcs(struct ++cs->cs_init; + /* set up character device */ gigaset_if_init(cs); /* set up device sysfs */ @@ -753,11 +753,9 @@ struct cardstate *gigaset_initcs(struct add_timer(&cs->timer); gig_dbg(DEBUG_INIT, "cs initialized"); - mutex_unlock(&cs->mutex); return cs; error: - mutex_unlock(&cs->mutex); gig_dbg(DEBUG_INIT, "failed"); gigaset_freecs(cs); return NULL; @@ -908,20 +906,7 @@ void gigaset_shutdown(struct cardstate * gig_dbg(DEBUG_CMD, "scheduling SHUTDOWN"); gigaset_schedule_event(cs); - if (wait_event_interruptible(cs->waitqueue, !cs->waiting)) { - warn("%s: aborted", __func__); - //FIXME - } - - if (atomic_read(&cs->mstate) != MS_LOCKED) { - //FIXME? - //gigaset_baud_rate(cs, B115200); - //gigaset_set_line_ctrl(cs, CS8); - //gigaset_set_modem_ctrl(cs, TIOCM_DTR|TIOCM_RTS, 0); - //cs->control_state = 0; - } else { - //FIXME use some saved values? - } + wait_event(cs->waitqueue, !cs->waiting); cleanup_cs(cs); @@ -944,10 +929,7 @@ void gigaset_stop(struct cardstate *cs) gig_dbg(DEBUG_CMD, "scheduling STOP"); gigaset_schedule_event(cs); - if (wait_event_interruptible(cs->waitqueue, !cs->waiting)) { - warn("%s: aborted", __func__); - //FIXME - } + wait_event(cs->waitqueue, !cs->waiting); cleanup_cs(cs); diff --git a/drivers/isdn/gigaset/ev-layer.c b/drivers/isdn/gigaset/ev-layer.c index 44f02db..4661e2c 100644 --- a/drivers/isdn/gigaset/ev-layer.c +++ b/drivers/isdn/gigaset/ev-layer.c @@ -1015,7 +1015,7 @@ static void finish_shutdown(struct cards cs->cmd_result = -ENODEV; cs->waiting = 0; - wake_up_interruptible(&cs->waitqueue); + wake_up(&cs->waitqueue); } static void do_shutdown(struct cardstate *cs) diff --git a/drivers/isdn/gigaset/interface.c b/drivers/isdn/gigaset/interface.c index 458b646..eb50f3d 100644 --- a/drivers/isdn/gigaset/interface.c +++ b/drivers/isdn/gigaset/interface.c @@ -599,19 +599,9 @@ out: static void if_wake(unsigned long data) { struct cardstate *cs = (struct cardstate *) data; - struct tty_struct *tty; - - tty = cs->tty; - if (!tty) - return; - - if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && - tty->ldisc.write_wakeup) { - gig_dbg(DEBUG_IF, "write wakeup call"); - tty->ldisc.write_wakeup(tty); - } - wake_up_interruptible(&tty->write_wait); + if (cs->tty) + tty_wakeup(cs->tty); } /*** interface to common ***/ @@ -625,6 +615,8 @@ void gigaset_if_init(struct cardstate *c return; tasklet_init(&cs->if_wake_tasklet, &if_wake, (unsigned long) cs); + + mutex_lock(&cs->mutex); cs->tty_dev = tty_register_device(drv->tty, cs->minor_index, NULL); if (!IS_ERR(cs->tty_dev)) @@ -633,6 +625,7 @@ void gigaset_if_init(struct cardstate *c warn("could not register device to the tty subsystem"); cs->tty_dev = NULL; } + mutex_unlock(&cs->mutex); } void gigaset_if_free(struct cardstate *cs) diff --git a/drivers/isdn/gigaset/isocdata.c b/drivers/isdn/gigaset/isocdata.c index df988eb..8c0eb52 100644 --- a/drivers/isdn/gigaset/isocdata.c +++ b/drivers/isdn/gigaset/isocdata.c @@ -921,6 +921,8 @@ static void cmd_loop(unsigned char *src, /* end of line */ gig_dbg(DEBUG_TRANSCMD, "%s: End of Command (%d Bytes)", __func__, cbytes); + if (cbytes >= MAX_RESP_SIZE - 1) + dev_warn(cs->dev, "response too large\n"); cs->cbytes = cbytes; gigaset_handle_modem_response(cs); cbytes = 0; @@ -929,8 +931,6 @@ static void cmd_loop(unsigned char *src, /* advance in line buffer, checking for overflow */ if (cbytes < MAX_RESP_SIZE - 1) cbytes++; - else - dev_warn(cs->dev, "response too large\n"); } } diff --git a/drivers/isdn/gigaset/ser-gigaset.c b/drivers/isdn/gigaset/ser-gigaset.c new file mode 100644 index 0000000..c8b7db6 --- /dev/null +++ b/drivers/isdn/gigaset/ser-gigaset.c @@ -0,0 +1,837 @@ +/* This is the serial hardware link layer (HLL) for the Gigaset 307x isdn + * DECT base (aka Sinus 45 isdn) using the RS232 DECT data module M101, + * written as a line discipline. + * + * ===================================================================== + * 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 "gigaset.h" + +#include +#include +#include +#include +#include + +/* Version Information */ +#define DRIVER_AUTHOR "Tilman Schmidt" +#define DRIVER_DESC "Serial Driver for Gigaset 307x using Siemens M101" + +#define GIGASET_MINORS 1 +#define GIGASET_MINOR 0 +#define GIGASET_MODULENAME "ser_gigaset" +#define GIGASET_DEVNAME "ttyGS" + +/* length limit according to Siemens 3070usb-protokoll.doc ch. 2.1 */ +#define IF_WRITEBUF 264 + +MODULE_AUTHOR(DRIVER_AUTHOR); +MODULE_DESCRIPTION(DRIVER_DESC); +MODULE_LICENSE("GPL"); +MODULE_ALIAS_LDISC(N_GIGASET_M101); + +static int startmode = SM_ISDN; +module_param(startmode, int, S_IRUGO); +MODULE_PARM_DESC(startmode, "initial operation mode"); +static int cidmode = 1; +module_param(cidmode, int, S_IRUGO); +MODULE_PARM_DESC(cidmode, "stay in CID mode when idle"); + +static struct gigaset_driver *driver; + +struct ser_cardstate { + struct platform_device dev; + struct tty_struct *tty; + atomic_t refcnt; + struct mutex dead_mutex; +}; + +static struct platform_driver device_driver = { + .driver = { + .name = GIGASET_MODULENAME, + }, +}; + +static void flush_send_queue(struct cardstate *); + +/* transmit data from current open skb + * result: number of bytes sent or error code < 0 + */ +static int write_modem(struct cardstate *cs) +{ + struct tty_struct *tty = cs->hw.ser->tty; + struct bc_state *bcs = &cs->bcs[0]; /* only one channel */ + struct sk_buff *skb = bcs->tx_skb; + int sent; + + if (!tty || !tty->driver || !skb) + return -EFAULT; + + if (!skb->len) { + dev_kfree_skb_any(skb); + bcs->tx_skb = NULL; + return -EINVAL; + } + + set_bit(TTY_DO_WRITE_WAKEUP, &tty->flags); + sent = tty->driver->write(tty, skb->data, skb->len); + gig_dbg(DEBUG_OUTPUT, "write_modem: sent %d", sent); + if (sent < 0) { + /* error */ + flush_send_queue(cs); + return sent; + } + skb_pull(skb, sent); + if (!skb->len) { + /* skb sent completely */ + gigaset_skb_sent(bcs, skb); + + gig_dbg(DEBUG_INTR, "kfree skb (Adr: %lx)!", + (unsigned long) skb); + dev_kfree_skb_any(skb); + bcs->tx_skb = NULL; + } + return sent; +} + +/* + * transmit first queued command buffer + * result: number of bytes sent or error code < 0 + */ +static int send_cb(struct cardstate *cs) +{ + struct tty_struct *tty = cs->hw.ser->tty; + struct cmdbuf_t *cb, *tcb; + unsigned long flags; + int sent = 0; + + if (!tty || !tty->driver) + return -EFAULT; + + cb = cs->cmdbuf; + if (!cb) + return 0; /* nothing to do */ + + if (cb->len) { + set_bit(TTY_DO_WRITE_WAKEUP, &tty->flags); + sent = tty->driver->write(tty, cb->buf + cb->offset, cb->len); + if (sent < 0) { + /* error */ + gig_dbg(DEBUG_OUTPUT, "send_cb: write error %d", sent); + flush_send_queue(cs); + return sent; + } + cb->offset += sent; + cb->len -= sent; + gig_dbg(DEBUG_OUTPUT, "send_cb: sent %d, left %u, queued %u", + sent, cb->len, cs->cmdbytes); + } + + while (cb && !cb->len) { + spin_lock_irqsave(&cs->cmdlock, flags); + cs->cmdbytes -= cs->curlen; + tcb = cb; + cs->cmdbuf = cb = cb->next; + if (cb) { + cb->prev = NULL; + cs->curlen = cb->len; + } else { + cs->lastcmdbuf = NULL; + cs->curlen = 0; + } + spin_unlock_irqrestore(&cs->cmdlock, flags); + + if (tcb->wake_tasklet) + tasklet_schedule(tcb->wake_tasklet); + kfree(tcb); + } + return sent; +} + +/* + * send queue tasklet + * If there is already a skb opened, put data to the transfer buffer + * by calling "write_modem". + * Otherwise take a new skb out of the queue. + */ +static void gigaset_modem_fill(unsigned long data) +{ + struct cardstate *cs = (struct cardstate *) data; + struct bc_state *bcs; + int sent = 0; + + if (!cs || !(bcs = cs->bcs)) { + gig_dbg(DEBUG_OUTPUT, "%s: no cardstate", __func__); + return; + } + if (!bcs->tx_skb) { + /* no skb is being sent; send command if any */ + sent = send_cb(cs); + gig_dbg(DEBUG_OUTPUT, "%s: send_cb -> %d", __func__, sent); + if (sent) + /* something sent or error */ + return; + + /* no command to send; get skb */ + if (!(bcs->tx_skb = skb_dequeue(&bcs->squeue))) + /* no skb either, nothing to do */ + return; + + gig_dbg(DEBUG_INTR, "Dequeued skb (Adr: %lx)", + (unsigned long) bcs->tx_skb); + } + + /* send skb */ + gig_dbg(DEBUG_OUTPUT, "%s: tx_skb", __func__); + if (write_modem(cs) < 0) + gig_dbg(DEBUG_OUTPUT, "%s: write_modem failed", __func__); +} + +/* + * throw away all data queued for sending + */ +static void flush_send_queue(struct cardstate *cs) +{ + struct sk_buff *skb; + struct cmdbuf_t *cb; + unsigned long flags; + + /* command queue */ + spin_lock_irqsave(&cs->cmdlock, flags); + while ((cb = cs->cmdbuf) != NULL) { + cs->cmdbuf = cb->next; + if (cb->wake_tasklet) + tasklet_schedule(cb->wake_tasklet); + kfree(cb); + } + cs->cmdbuf = cs->lastcmdbuf = NULL; + cs->cmdbytes = cs->curlen = 0; + spin_unlock_irqrestore(&cs->cmdlock, flags); + + /* data queue */ + if (cs->bcs->tx_skb) + dev_kfree_skb_any(cs->bcs->tx_skb); + while ((skb = skb_dequeue(&cs->bcs->squeue)) != NULL) + dev_kfree_skb_any(skb); +} + + +/* Gigaset Driver Interface */ +/* ======================== */ + +/* + * queue an AT command string for transmission to the Gigaset device + * parameters: + * cs controller state structure + * buf buffer containing the string to send + * len number of characters to send + * wake_tasklet tasklet to run when transmission is complete, or NULL + * return value: + * number of bytes queued, or error code < 0 + */ +static int gigaset_write_cmd(struct cardstate *cs, const unsigned char *buf, + int len, struct tasklet_struct *wake_tasklet) +{ + struct cmdbuf_t *cb; + unsigned long flags; + + gigaset_dbg_buffer(atomic_read(&cs->mstate) != MS_LOCKED ? + DEBUG_TRANSCMD : DEBUG_LOCKCMD, + "CMD Transmit", len, buf); + + if (len <= 0) + return 0; + + if (!(cb = kmalloc(sizeof(struct cmdbuf_t) + len, GFP_ATOMIC))) { + dev_err(cs->dev, "%s: out of memory!\n", __func__); + return -ENOMEM; + } + + memcpy(cb->buf, buf, len); + cb->len = len; + cb->offset = 0; + cb->next = NULL; + cb->wake_tasklet = wake_tasklet; + + spin_lock_irqsave(&cs->cmdlock, flags); + cb->prev = cs->lastcmdbuf; + if (cs->lastcmdbuf) + cs->lastcmdbuf->next = cb; + else { + cs->cmdbuf = cb; + cs->curlen = len; + } + cs->cmdbytes += len; + cs->lastcmdbuf = cb; + spin_unlock_irqrestore(&cs->cmdlock, flags); + + spin_lock_irqsave(&cs->lock, flags); + if (cs->connected) + tasklet_schedule(&cs->write_tasklet); + spin_unlock_irqrestore(&cs->lock, flags); + return len; +} + +/* + * tty_driver.write_room interface routine + * return number of characters the driver will accept to be written + * parameter: + * controller state structure + * return value: + * number of characters + */ +static int gigaset_write_room(struct cardstate *cs) +{ + unsigned bytes; + + bytes = cs->cmdbytes; + return bytes < IF_WRITEBUF ? IF_WRITEBUF - bytes : 0; +} + +/* + * tty_driver.chars_in_buffer interface routine + * return number of characters waiting to be sent + * parameter: + * controller state structure + * return value: + * number of characters + */ +static int gigaset_chars_in_buffer(struct cardstate *cs) +{ + return cs->cmdbytes; +} + +/* + * implementation of ioctl(GIGASET_BRKCHARS) + * parameter: + * controller state structure + * return value: + * -EINVAL (unimplemented function) + */ +static int gigaset_brkchars(struct cardstate *cs, const unsigned char buf[6]) +{ + /* not implemented */ + return -EINVAL; +} + +/* + * Open B channel + * Called by "do_action" in ev-layer.c + */ +static int gigaset_init_bchannel(struct bc_state *bcs) +{ + /* nothing to do for M10x */ + gigaset_bchannel_up(bcs); + return 0; +} + +/* + * Close B channel + * Called by "do_action" in ev-layer.c + */ +static int gigaset_close_bchannel(struct bc_state *bcs) +{ + /* nothing to do for M10x */ + gigaset_bchannel_down(bcs); + return 0; +} + +/* + * Set up B channel structure + * This is called by "gigaset_initcs" in common.c + */ +static int gigaset_initbcshw(struct bc_state *bcs) +{ + /* unused */ + bcs->hw.ser = NULL; + return 1; +} + +/* + * Free B channel structure + * Called by "gigaset_freebcs" in common.c + */ +static int gigaset_freebcshw(struct bc_state *bcs) +{ + /* unused */ + return 1; +} + +/* + * Reinitialize B channel structure + * This is called by "bcs_reinit" in common.c + */ +static void gigaset_reinitbcshw(struct bc_state *bcs) +{ + /* nothing to do for M10x */ +} + +/* + * Free hardware specific device data + * This will be called by "gigaset_freecs" in common.c + */ +static void gigaset_freecshw(struct cardstate *cs) +{ + tasklet_kill(&cs->write_tasklet); + if (!cs->hw.ser) + return; + dev_set_drvdata(&cs->hw.ser->dev.dev, NULL); + platform_device_unregister(&cs->hw.ser->dev); + kfree(cs->hw.ser); + cs->hw.ser = NULL; +} + +static void gigaset_device_release(struct device *dev) +{ + struct platform_device *pdev = + container_of(dev, struct platform_device, dev); + + /* adapted from platform_device_release() in drivers/base/platform.c */ + //FIXME is this actually necessary? + kfree(dev->platform_data); + kfree(pdev->resource); +} + +/* + * Set up hardware specific device data + * This is called by "gigaset_initcs" in common.c + */ +static int gigaset_initcshw(struct cardstate *cs) +{ + int rc; + + if (!(cs->hw.ser = kzalloc(sizeof(struct ser_cardstate), GFP_KERNEL))) { + err("%s: out of memory!", __func__); + return 0; + } + + cs->hw.ser->dev.name = GIGASET_MODULENAME; + cs->hw.ser->dev.id = cs->minor_index; + cs->hw.ser->dev.dev.release = gigaset_device_release; + if ((rc = platform_device_register(&cs->hw.ser->dev)) != 0) { + err("error %d registering platform device", rc); + kfree(cs->hw.ser); + cs->hw.ser = NULL; + return 0; + } + dev_set_drvdata(&cs->hw.ser->dev.dev, cs); + + tasklet_init(&cs->write_tasklet, + &gigaset_modem_fill, (unsigned long) cs); + return 1; +} + +/* + * set modem control lines + * Parameters: + * card state structure + * modem control line state ([TIOCM_DTR]|[TIOCM_RTS]) + * Called by "gigaset_start" and "gigaset_enterconfigmode" in common.c + * and by "if_lock" and "if_termios" in interface.c + */ +static int gigaset_set_modem_ctrl(struct cardstate *cs, unsigned old_state, unsigned new_state) +{ + struct tty_struct *tty = cs->hw.ser->tty; + unsigned int set, clear; + + if (!tty || !tty->driver || !tty->driver->tiocmset) + return -EFAULT; + set = new_state & ~old_state; + clear = old_state & ~new_state; + if (!set && !clear) + return 0; + gig_dbg(DEBUG_IF, "tiocmset set %x clear %x", set, clear); + return tty->driver->tiocmset(tty, NULL, set, clear); +} + +static int gigaset_baud_rate(struct cardstate *cs, unsigned cflag) +{ + return -EINVAL; +} + +static int gigaset_set_line_ctrl(struct cardstate *cs, unsigned cflag) +{ + return -EINVAL; +} + +static struct gigaset_ops ops = { + gigaset_write_cmd, + gigaset_write_room, + gigaset_chars_in_buffer, + gigaset_brkchars, + gigaset_init_bchannel, + gigaset_close_bchannel, + gigaset_initbcshw, + gigaset_freebcshw, + gigaset_reinitbcshw, + gigaset_initcshw, + gigaset_freecshw, + gigaset_set_modem_ctrl, + gigaset_baud_rate, + gigaset_set_line_ctrl, + gigaset_m10x_send_skb, /* asyncdata.c */ + gigaset_m10x_input, /* asyncdata.c */ +}; + + +/* Line Discipline Interface */ +/* ========================= */ + +/* helper functions for cardstate refcounting */ +static struct cardstate *cs_get(struct tty_struct *tty) +{ + struct cardstate *cs = tty->disc_data; + + if (!cs || !cs->hw.ser) { + gig_dbg(DEBUG_ANY, "%s: no cardstate", __func__); + return NULL; + } + atomic_inc(&cs->hw.ser->refcnt); + return cs; +} + +static void cs_put(struct cardstate *cs) +{ + if (atomic_dec_and_test(&cs->hw.ser->refcnt)) + mutex_unlock(&cs->hw.ser->dead_mutex); +} + +/* + * Called by the tty driver when the line discipline is pushed onto the tty. + * Called in process context. + */ +static int +gigaset_tty_open(struct tty_struct *tty) +{ + struct cardstate *cs; + + gig_dbg(DEBUG_INIT, "Starting HLL for Gigaset M101"); + + info(DRIVER_AUTHOR); + info(DRIVER_DESC); + + if (!driver) { + err("%s: no driver structure", __func__); + return -ENODEV; + } + + /* allocate memory for our device state and intialize it */ + if (!(cs = gigaset_initcs(driver, 1, 1, 0, cidmode, + GIGASET_MODULENAME))) + goto error; + + cs->dev = &cs->hw.ser->dev.dev; + cs->hw.ser->tty = tty; + mutex_init(&cs->hw.ser->dead_mutex); + atomic_set(&cs->hw.ser->refcnt, 1); + + tty->disc_data = cs; + + /* OK.. Initialization of the datastructures and the HW is done.. Now + * startup system and notify the LL that we are ready to run + */ + if (startmode == SM_LOCKED) + atomic_set(&cs->mstate, MS_LOCKED); + if (!gigaset_start(cs)) { + tasklet_kill(&cs->write_tasklet); + goto error; + } + + gig_dbg(DEBUG_INIT, "Startup of HLL done"); + mutex_lock(&cs->hw.ser->dead_mutex); + return 0; + +error: + gig_dbg(DEBUG_INIT, "Startup of HLL failed"); + tty->disc_data = NULL; + gigaset_freecs(cs); + return -ENODEV; +} + +/* + * Called by the tty driver when the line discipline is removed. + * Called from process context. + */ +static void +gigaset_tty_close(struct tty_struct *tty) +{ + struct cardstate *cs = tty->disc_data; + + gig_dbg(DEBUG_INIT, "Stopping HLL for Gigaset M101"); + + if (!cs) { + gig_dbg(DEBUG_INIT, "%s: no cardstate", __func__); + return; + } + + /* prevent other callers from entering ldisc methods */ + tty->disc_data = NULL; + + if (!cs->hw.ser) + err("%s: no hw cardstate", __func__); + else { + /* wait for running methods to finish */ + if (!atomic_dec_and_test(&cs->hw.ser->refcnt)) + mutex_lock(&cs->hw.ser->dead_mutex); + } + + /* stop operations */ + gigaset_stop(cs); + tasklet_kill(&cs->write_tasklet); + flush_send_queue(cs); + cs->dev = NULL; + gigaset_freecs(cs); + + gig_dbg(DEBUG_INIT, "Shutdown of HLL done"); +} + +/* + * Called by the tty driver when the tty line is hung up. + * Wait for I/O to driver to complete and unregister ISDN device. + * This is already done by the close routine, so just call that. + * Called from process context. + */ +static int gigaset_tty_hangup(struct tty_struct *tty) +{ + gigaset_tty_close(tty); + return 0; +} + +/* + * Read on the tty. + * Unused, received data goes only to the Gigaset driver. + */ +static ssize_t +gigaset_tty_read(struct tty_struct *tty, struct file *file, + unsigned char __user *buf, size_t count) +{ + return -EAGAIN; +} + +/* + * Write on the tty. + * Unused, transmit data comes only from the Gigaset driver. + */ +static ssize_t +gigaset_tty_write(struct tty_struct *tty, struct file *file, + const unsigned char *buf, size_t count) +{ + return -EAGAIN; +} + +/* + * Ioctl on the tty. + * Called in process context only. + * May be re-entered by multiple ioctl calling threads. + */ +static int +gigaset_tty_ioctl(struct tty_struct *tty, struct file *file, + unsigned int cmd, unsigned long arg) +{ + struct cardstate *cs = cs_get(tty); + int rc, val; + int __user *p = (int __user *)arg; + + if (!cs) + return -ENXIO; + + switch (cmd) { + case TCGETS: + case TCGETA: + /* pass through to underlying serial device */ + rc = n_tty_ioctl(tty, file, cmd, arg); + break; + + case TCFLSH: + /* flush our buffers and the serial port's buffer */ + switch (arg) { + case TCIFLUSH: + /* no own input buffer to flush */ + break; + case TCIOFLUSH: + case TCOFLUSH: + flush_send_queue(cs); + break; + } + /* flush the serial port's buffer */ + rc = n_tty_ioctl(tty, file, cmd, arg); + break; + + case FIONREAD: + /* unused, always return zero */ + val = 0; + rc = put_user(val, p); + break; + + default: + rc = -ENOIOCTLCMD; + } + + cs_put(cs); + return rc; +} + +/* + * Poll on the tty. + * Unused, always return zero. + */ +static unsigned int +gigaset_tty_poll(struct tty_struct *tty, struct file *file, poll_table *wait) +{ + return 0; +} + +/* + * Called by the tty driver when a block of data has been received. + * Will not be re-entered while running but other ldisc functions + * may be called in parallel. + * Can be called from hard interrupt level as well as soft interrupt + * level or mainline. + * Parameters: + * tty tty structure + * buf buffer containing received characters + * cflags buffer containing error flags for received characters (ignored) + * count number of received characters + */ +static void +gigaset_tty_receive(struct tty_struct *tty, const unsigned char *buf, + char *cflags, int count) +{ + struct cardstate *cs = cs_get(tty); + unsigned tail, head, n; + struct inbuf_t *inbuf; + + if (!cs) + return; + if (!(inbuf = cs->inbuf)) { + dev_err(cs->dev, "%s: no inbuf\n", __func__); + cs_put(cs); + return; + } + + tail = atomic_read(&inbuf->tail); + head = atomic_read(&inbuf->head); + gig_dbg(DEBUG_INTR, "buffer state: %u -> %u, receive %u bytes", + head, tail, count); + + if (head <= tail) { + /* possible buffer wraparound */ + n = min_t(unsigned, count, RBUFSIZE - tail); + memcpy(inbuf->data + tail, buf, n); + tail = (tail + n) % RBUFSIZE; + buf += n; + count -= n; + } + + if (count > 0) { + /* tail < head and some data left */ + n = head - tail - 1; + if (count > n) { + dev_err(cs->dev, + "inbuf overflow, discarding %d bytes\n", + count - n); + count = n; + } + memcpy(inbuf->data + tail, buf, count); + tail += count; + } + + gig_dbg(DEBUG_INTR, "setting tail to %u", tail); + atomic_set(&inbuf->tail, tail); + + /* Everything was received .. Push data into handler */ + gig_dbg(DEBUG_INTR, "%s-->BH", __func__); + gigaset_schedule_event(cs); + cs_put(cs); +} + +/* + * Called by the tty driver when there's room for more data to send. + */ +static void +gigaset_tty_wakeup(struct tty_struct *tty) +{ + struct cardstate *cs = cs_get(tty); + + clear_bit(TTY_DO_WRITE_WAKEUP, &tty->flags); + if (!cs) + return; + tasklet_schedule(&cs->write_tasklet); + cs_put(cs); +} + +static struct tty_ldisc gigaset_ldisc = { + .owner = THIS_MODULE, + .magic = TTY_LDISC_MAGIC, + .name = "ser_gigaset", + .open = gigaset_tty_open, + .close = gigaset_tty_close, + .hangup = gigaset_tty_hangup, + .read = gigaset_tty_read, + .write = gigaset_tty_write, + .ioctl = gigaset_tty_ioctl, + .poll = gigaset_tty_poll, + .receive_buf = gigaset_tty_receive, + .write_wakeup = gigaset_tty_wakeup, +}; + + +/* Initialization / Shutdown */ +/* ========================= */ + +static int __init ser_gigaset_init(void) +{ + int rc; + + gig_dbg(DEBUG_INIT, "%s", __func__); + if ((rc = platform_driver_register(&device_driver)) != 0) { + err("error %d registering platform driver", rc); + return rc; + } + + /* allocate memory for our driver state and intialize it */ + if (!(driver = gigaset_initdriver(GIGASET_MINOR, GIGASET_MINORS, + GIGASET_MODULENAME, GIGASET_DEVNAME, + &ops, THIS_MODULE))) + goto error; + + if ((rc = tty_register_ldisc(N_GIGASET_M101, &gigaset_ldisc)) != 0) { + err("error %d registering line discipline", rc); + goto error; + } + + return 0; + +error: + if (driver) { + gigaset_freedriver(driver); + driver = NULL; + } + platform_driver_unregister(&device_driver); + return rc; +} + +static void __exit ser_gigaset_exit(void) +{ + int rc; + + gig_dbg(DEBUG_INIT, "%s", __func__); + + if (driver) { + gigaset_freedriver(driver); + driver = NULL; + } + + if ((rc = tty_unregister_ldisc(N_GIGASET_M101)) != 0) + err("error %d unregistering line discipline", rc); + + platform_driver_unregister(&device_driver); +} + +module_init(ser_gigaset_init); +module_exit(ser_gigaset_exit); diff --git a/drivers/isdn/hardware/avm/avm_cs.c b/drivers/isdn/hardware/avm/avm_cs.c index eba1046..a5b941c 100644 --- a/drivers/isdn/hardware/avm/avm_cs.c +++ b/drivers/isdn/hardware/avm/avm_cs.c @@ -12,7 +12,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/isdn/hardware/avm/b1dma.c b/drivers/isdn/hardware/avm/b1dma.c index ddd47cd..1e2d38e 100644 --- a/drivers/isdn/hardware/avm/b1dma.c +++ b/drivers/isdn/hardware/avm/b1dma.c @@ -29,7 +29,7 @@ #include static char *revision = "$Revision: 1.1.2.3 $"; -#undef CONFIG_B1DMA_DEBUG +#undef AVM_B1DMA_DEBUG /* ------------------------------------------------------------- */ @@ -391,16 +391,16 @@ static void b1dma_dispatch_tx(avmcard *c _put_slice(&p, skb->data, len); } txlen = (u8 *)p - (u8 *)dma->sendbuf.dmabuf; -#ifdef CONFIG_B1DMA_DEBUG +#ifdef AVM_B1DMA_DEBUG printk(KERN_DEBUG "tx: put msg len=%d\n", txlen); #endif } else { txlen = skb->len-2; -#ifdef CONFIG_B1DMA_POLLDEBUG +#ifdef AVM_B1DMA_POLLDEBUG if (skb->data[2] == SEND_POLLACK) printk(KERN_INFO "%s: send ack\n", card->name); #endif -#ifdef CONFIG_B1DMA_DEBUG +#ifdef AVM_B1DMA_DEBUG printk(KERN_DEBUG "tx: put 0x%x len=%d\n", skb->data[2], txlen); #endif @@ -450,7 +450,7 @@ static void b1dma_handle_rx(avmcard *car u32 ApplId, MsgLen, DataB3Len, NCCI, WindowSize; u8 b1cmd = _get_byte(&p); -#ifdef CONFIG_B1DMA_DEBUG +#ifdef AVM_B1DMA_DEBUG printk(KERN_DEBUG "rx: 0x%x %lu\n", b1cmd, (unsigned long)dma->recvlen); #endif @@ -515,7 +515,7 @@ #endif break; case RECEIVE_START: -#ifdef CONFIG_B1DMA_POLLDEBUG +#ifdef AVM_B1DMA_POLLDEBUG printk(KERN_INFO "%s: receive poll\n", card->name); #endif if (!suppress_pollack) @@ -601,7 +601,7 @@ static void b1dma_handle_interrupt(avmca rxlen = (dma->recvlen + 3) & ~3; b1dma_writel(card, dma->recvbuf.dmaaddr+4, AMCC_RXPTR); b1dma_writel(card, rxlen, AMCC_RXLEN); -#ifdef CONFIG_B1DMA_DEBUG +#ifdef AVM_B1DMA_DEBUG } else { printk(KERN_ERR "%s: rx not complete (%d).\n", card->name, rxlen); diff --git a/drivers/isdn/hardware/avm/c4.c b/drivers/isdn/hardware/avm/c4.c index 2a3eb38..6f5efa8 100644 --- a/drivers/isdn/hardware/avm/c4.c +++ b/drivers/isdn/hardware/avm/c4.c @@ -28,8 +28,8 @@ #include #include #include "avmcard.h" -#undef CONFIG_C4_DEBUG -#undef CONFIG_C4_POLLDEBUG +#undef AVM_C4_DEBUG +#undef AVM_C4_POLLDEBUG /* ------------------------------------------------------------- */ @@ -420,7 +420,7 @@ static void c4_dispatch_tx(avmcard *card skb = skb_dequeue(&dma->send_queue); if (!skb) { -#ifdef CONFIG_C4_DEBUG +#ifdef AVM_C4_DEBUG printk(KERN_DEBUG "%s: tx underrun\n", card->name); #endif return; @@ -444,16 +444,16 @@ #endif _put_slice(&p, skb->data, len); } txlen = (u8 *)p - (u8 *)dma->sendbuf.dmabuf; -#ifdef CONFIG_C4_DEBUG +#ifdef AVM_C4_DEBUG printk(KERN_DEBUG "%s: tx put msg len=%d\n", card->name, txlen); #endif } else { txlen = skb->len-2; -#ifdef CONFIG_C4_POLLDEBUG +#ifdef AVM_C4_POLLDEBUG if (skb->data[2] == SEND_POLLACK) printk(KERN_INFO "%s: ack to c4\n", card->name); #endif -#ifdef CONFIG_C4_DEBUG +#ifdef AVM_C4_DEBUG printk(KERN_DEBUG "%s: tx put 0x%x len=%d\n", card->name, skb->data[2], txlen); #endif @@ -508,7 +508,7 @@ static void c4_handle_rx(avmcard *card) u32 cidx; -#ifdef CONFIG_C4_DEBUG +#ifdef AVM_C4_DEBUG printk(KERN_DEBUG "%s: rx 0x%x len=%lu\n", card->name, b1cmd, (unsigned long)dma->recvlen); #endif @@ -586,7 +586,7 @@ #endif break; case RECEIVE_START: -#ifdef CONFIG_C4_POLLDEBUG +#ifdef AVM_C4_POLLDEBUG printk(KERN_INFO "%s: poll from c4\n", card->name); #endif if (!suppress_pollack) diff --git a/drivers/isdn/hardware/eicon/capifunc.c b/drivers/isdn/hardware/eicon/capifunc.c index 0afd763..ff284ae 100644 --- a/drivers/isdn/hardware/eicon/capifunc.c +++ b/drivers/isdn/hardware/eicon/capifunc.c @@ -187,7 +187,7 @@ static diva_card *find_card_by_ctrl(word */ void *TransmitBufferSet(APPL * appl, dword ref) { - appl->xbuffer_used[ref] = TRUE; + appl->xbuffer_used[ref] = true; DBG_PRV1(("%d:xbuf_used(%d)", appl->Id, ref + 1)) return (void *) ref; } @@ -202,7 +202,7 @@ void *TransmitBufferGet(APPL * appl, voi void TransmitBufferFree(APPL * appl, void *p) { - appl->xbuffer_used[(dword) p] = FALSE; + appl->xbuffer_used[(dword) p] = false; DBG_PRV1(("%d:xbuf_free(%d)", appl->Id, ((dword) p) + 1)) } diff --git a/drivers/isdn/hardware/eicon/debug.c b/drivers/isdn/hardware/eicon/debug.c index d835e74..0db9cc6 100644 --- a/drivers/isdn/hardware/eicon/debug.c +++ b/drivers/isdn/hardware/eicon/debug.c @@ -287,7 +287,7 @@ void* diva_maint_finit (void) { } external_dbg_queue = 0; - for (i = 1; i < (sizeof(clients)/sizeof(clients[0])); i++) { + for (i = 1; i < ARRAY_SIZE(clients); i++) { if (clients[i].pmem) { diva_os_free (0, clients[i].pmem); } @@ -391,7 +391,7 @@ static void DI_register (void *arg) { diva_os_enter_spin_lock (&dbg_q_lock, &old_irql, "register"); - for (id = 1; id < (sizeof(clients)/sizeof(clients[0])); id++) { + for (id = 1; id < ARRAY_SIZE(clients); id++) { if (clients[id].hDbg == hDbg) { /* driver already registered @@ -494,7 +494,7 @@ static void DI_deregister (pDbgHandle hD diva_os_enter_spin_lock (&dbg_adapter_lock, &old_irql1, "read"); diva_os_enter_spin_lock (&dbg_q_lock, &old_irql, "read"); - for (i = 1; i < (sizeof(clients)/sizeof(clients[0])); i++) { + for (i = 1; i < ARRAY_SIZE(clients); i++) { if (clients[i].hDbg == hDbg) { diva_dbg_entry_head_t* pmsg; char tmp[256]; @@ -736,7 +736,7 @@ int diva_get_driver_info (dword id, byte int to_copy; if (!data || !id || (data_length < 17) || - (id >= (sizeof(clients)/sizeof(clients[0])))) { + (id >= ARRAY_SIZE(clients))) { return (-1); } @@ -786,7 +786,7 @@ int diva_get_driver_dbg_mask (dword id, diva_os_spin_lock_magic_t old_irql; int ret = -1; - if (!data || !id || (id >= (sizeof(clients)/sizeof(clients[0])))) { + if (!data || !id || (id >= ARRAY_SIZE(clients))) { return (-1); } diva_os_enter_spin_lock (&dbg_q_lock, &old_irql, "driver info"); @@ -809,7 +809,7 @@ int diva_set_driver_dbg_mask (dword id, int ret = -1; - if (!id || (id >= (sizeof(clients)/sizeof(clients[0])))) { + if (!id || (id >= ARRAY_SIZE(clients))) { return (-1); } @@ -887,7 +887,7 @@ void diva_mnt_add_xdi_adapter (const DES diva_os_enter_spin_lock (&dbg_adapter_lock, &old_irql1, "register"); diva_os_enter_spin_lock (&dbg_q_lock, &old_irql, "register"); - for (id = 1; id < (sizeof(clients)/sizeof(clients[0])); id++) { + for (id = 1; id < ARRAY_SIZE(clients); id++) { if (clients[id].hDbg && (clients[id].request == d->request)) { diva_os_leave_spin_lock (&dbg_q_lock, &old_irql, "register"); diva_os_leave_spin_lock (&dbg_adapter_lock, &old_irql1, "register"); @@ -1037,7 +1037,7 @@ void diva_mnt_remove_xdi_adapter (const diva_os_enter_spin_lock (&dbg_adapter_lock, &old_irql1, "read"); diva_os_enter_spin_lock (&dbg_q_lock, &old_irql, "read"); - for (i = 1; i < (sizeof(clients)/sizeof(clients[0])); i++) { + for (i = 1; i < ARRAY_SIZE(clients); i++) { if (clients[i].hDbg && (clients[i].request == d->request)) { diva_dbg_entry_head_t* pmsg; char tmp[256]; @@ -1115,7 +1115,7 @@ void diva_mnt_remove_xdi_adapter (const void* SuperTraceOpenAdapter (int AdapterNumber) { int i; - for (i = 1; i < (sizeof(clients)/sizeof(clients[0])); i++) { + for (i = 1; i < ARRAY_SIZE(clients); i++) { if (clients[i].hDbg && clients[i].request && (clients[i].logical == AdapterNumber)) { return (&clients[i]); } @@ -1508,7 +1508,7 @@ static void diva_maint_state_change_noti int ch = TraceFilterChannel; int id = TraceFilterIdent; - if ((id >= 0) && (ch >= 0) && (id < sizeof(clients)/sizeof(clients[0])) && + if ((id >= 0) && (ch >= 0) && (id < ARRAY_SIZE(clients)) && (clients[id].Dbg.id == (byte)id) && (clients[id].pIdiLib == hLib)) { if (ch != (int)modem->ChannelNumber) { break; @@ -1555,7 +1555,7 @@ static void diva_maint_state_change_noti int ch = TraceFilterChannel; int id = TraceFilterIdent; - if ((id >= 0) && (ch >= 0) && (id < sizeof(clients)/sizeof(clients[0])) && + if ((id >= 0) && (ch >= 0) && (id < ARRAY_SIZE(clients)) && (clients[id].Dbg.id == (byte)id) && (clients[id].pIdiLib == hLib)) { if (ch != (int)fax->ChannelNumber) { break; @@ -1803,7 +1803,7 @@ static void diva_maint_trace_notify (voi /* Selective trace */ - if ((id >= 0) && (ch >= 0) && (id < sizeof(clients)/sizeof(clients[0])) && + if ((id >= 0) && (ch >= 0) && (id < ARRAY_SIZE(clients)) && (clients[id].Dbg.id == (byte)id) && (clients[id].pIdiLib == hLib)) { const char* p = NULL; int ch_value = -1; @@ -1925,7 +1925,7 @@ int diva_mnt_shutdown_xdi_adapters (void byte * pmem; - for (i = 1; i < (sizeof(clients)/sizeof(clients[0])); i++) { + for (i = 1; i < ARRAY_SIZE(clients); i++) { pmem = NULL; diva_os_enter_spin_lock (&dbg_adapter_lock, &old_irql1, "unload"); @@ -2006,7 +2006,7 @@ int diva_set_trace_filter (int filter_le on = (TraceFilter[0] == 0); - for (i = 1; i < (sizeof(clients)/sizeof(clients[0])); i++) { + for (i = 1; i < ARRAY_SIZE(clients); i++) { if (clients[i].hDbg && clients[i].pIdiLib && clients[i].request) { client_b_on = on && ((clients[i].hDbg->dbgMask & DIVA_MGT_DBG_IFC_BCHANNEL) != 0); client_atap_on = on && ((clients[i].hDbg->dbgMask & DIVA_MGT_DBG_IFC_AUDIO) != 0); @@ -2017,7 +2017,7 @@ int diva_set_trace_filter (int filter_le } } - for (i = 1; i < (sizeof(clients)/sizeof(clients[0])); i++) { + for (i = 1; i < ARRAY_SIZE(clients); i++) { if (clients[i].hDbg && clients[i].pIdiLib && clients[i].request && clients[i].request_pending) { diva_os_leave_spin_lock (&dbg_q_lock, &old_irql, "write_filter"); clients[i].request_pending = 0; diff --git a/drivers/isdn/hardware/eicon/di.c b/drivers/isdn/hardware/eicon/di.c index e1df8d9..ce8df38 100644 --- a/drivers/isdn/hardware/eicon/di.c +++ b/drivers/isdn/hardware/eicon/di.c @@ -173,16 +173,16 @@ #endif xdi_xlog_request (XDI_A_NR(a), this->Id, this->ReqCh, this->MInd, a->IdTypeTable[this->No]); a->ram_out(a, &ReqOut->Req, this->MInd); - more = TRUE; + more = true; } else { xdi_xlog_request (XDI_A_NR(a), this->Id, this->ReqCh, this->Req, a->IdTypeTable[this->No]); this->More |=XMOREF; a->ram_out(a, &ReqOut->Req, this->Req); - more = FALSE; + more = false; if (a->FlowControlIdTable[this->ReqCh] == this->Id) - a->FlowControlSkipTable[this->ReqCh] = TRUE; + a->FlowControlSkipTable[this->ReqCh] = true; /* Note that remove request was sent to the card */ @@ -311,7 +311,7 @@ byte pr_dpc(ADAPTER * a) /* are marked RNR */ if(RNRId && RNRId==a->ram_in(a, &IndIn->IndId)) { a->ram_out(a, &IndIn->Ind, 0); - a->ram_out(a, &IndIn->RNR, TRUE); + a->ram_out(a, &IndIn->RNR, true); } else { Ind = a->ram_in(a, &IndIn->Ind); @@ -331,7 +331,7 @@ byte pr_dpc(ADAPTER * a) dtrc(dprintf("RNR")); a->ram_out(a, &IndIn->Ind, 0); RNRId = a->ram_in(a, &IndIn->IndId); - a->ram_out(a, &IndIn->RNR, TRUE); + a->ram_out(a, &IndIn->RNR, true); } } } @@ -340,7 +340,7 @@ byte pr_dpc(ADAPTER * a) } a->ram_out(a, &PR_RAM->IndOutput, 0); } - return FALSE; + return false; } byte scom_test_int(ADAPTER * a) { @@ -399,7 +399,7 @@ #endif return (0); } if (extended_info_type == DIVA_RC_TYPE_REMOVE_COMPLETE) - a->RcExtensionSupported = TRUE; + a->RcExtensionSupported = true; } a->misc_flags_table[e_no] &= ~DIVA_MISC_FLAGS_REMOVE_PENDING; a->misc_flags_table[e_no] &= ~DIVA_MISC_FLAGS_NO_RC_CANCELLING; @@ -428,7 +428,7 @@ #endif } if (Rc==OK_FC) { a->FlowControlIdTable[Ch] = Id; - a->FlowControlSkipTable[Ch] = FALSE; + a->FlowControlSkipTable[Ch] = false; this->Rc = Rc; this->More &= ~(XBUSY | XMOREC); this->complete=0xff; diff --git a/drivers/isdn/hardware/eicon/divamnt.c b/drivers/isdn/hardware/eicon/divamnt.c index 77155d9..4aba5c5 100644 --- a/drivers/isdn/hardware/eicon/divamnt.c +++ b/drivers/isdn/hardware/eicon/divamnt.c @@ -13,7 +13,6 @@ #include #include #include -#include #include #include #include @@ -164,7 +163,7 @@ static ssize_t divas_maint_read(struct f return (maint_read_write(buf, (int) count)); } -static struct file_operations divas_maint_fops = { +static const struct file_operations divas_maint_fops = { .owner = THIS_MODULE, .llseek = no_llseek, .read = divas_maint_read, diff --git a/drivers/isdn/hardware/eicon/divasi.c b/drivers/isdn/hardware/eicon/divasi.c index fff0d89..556b196 100644 --- a/drivers/isdn/hardware/eicon/divasi.c +++ b/drivers/isdn/hardware/eicon/divasi.c @@ -131,7 +131,7 @@ static void remove_um_idi_proc(void) } } -static struct file_operations divas_idi_fops = { +static const struct file_operations divas_idi_fops = { .owner = THIS_MODULE, .llseek = no_llseek, .read = um_idi_read, diff --git a/drivers/isdn/hardware/eicon/divasmain.c b/drivers/isdn/hardware/eicon/divasmain.c index 91fc92c..5e862e2 100644 --- a/drivers/isdn/hardware/eicon/divasmain.c +++ b/drivers/isdn/hardware/eicon/divasmain.c @@ -12,7 +12,6 @@ #include #include #include -#include #include #include #include @@ -663,7 +662,7 @@ static unsigned int divas_poll(struct fi return (POLLIN | POLLRDNORM); } -static struct file_operations divas_fops = { +static const struct file_operations divas_fops = { .owner = THIS_MODULE, .llseek = no_llseek, .read = divas_read, diff --git a/drivers/isdn/hardware/eicon/divasproc.c b/drivers/isdn/hardware/eicon/divasproc.c index 6a4373a..0632a26 100644 --- a/drivers/isdn/hardware/eicon/divasproc.c +++ b/drivers/isdn/hardware/eicon/divasproc.c @@ -113,7 +113,7 @@ static int divas_close(struct inode *ino return (0); } -static struct file_operations divas_fops = { +static const struct file_operations divas_fops = { .owner = THIS_MODULE, .llseek = no_llseek, .read = divas_read, diff --git a/drivers/isdn/hardware/eicon/message.c b/drivers/isdn/hardware/eicon/message.c index f9b00f1..784232a 100644 --- a/drivers/isdn/hardware/eicon/message.c +++ b/drivers/isdn/hardware/eicon/message.c @@ -253,7 +253,7 @@ extern APPL * application; -static byte remove_started = FALSE; +static byte remove_started = false; static PLCI dummy_plci; @@ -456,12 +456,12 @@ word api_put(APPL * appl, CAPI_MSG * return _QUEUE_FULL; } - c = FALSE; + c = false; if ((((byte *) msg) < ((byte *)(plci->msg_in_queue))) || (((byte *) msg) >= ((byte *)(plci->msg_in_queue)) + sizeof(plci->msg_in_queue))) { if (plci->msg_in_write_pos != plci->msg_in_read_pos) - c = TRUE; + c = true; } if (msg->header.command == _DATA_B3_R) { @@ -506,13 +506,13 @@ word api_put(APPL * appl, CAPI_MSG * return _QUEUE_FULL; } - c = TRUE; + c = true; } } else { if (plci->req_in || plci->internal_command) - c = TRUE; + c = true; else { plci->command = msg->header.command; @@ -626,10 +626,10 @@ word api_parse(byte * msg, word length break; } - if(p>length) return TRUE; + if(p>length) return true; } if(parms) parms[i].info = NULL; - return FALSE; + return false; } void api_save_msg(API_PARSE *in, byte *format, API_SAVE *out) @@ -687,7 +687,7 @@ word api_remove_start(void) word j; if(!remove_started) { - remove_started = TRUE; + remove_started = true; for(i=0;ichannels = 0; @@ -1226,7 +1226,7 @@ byte connect_req(dword Id, word Number, Id = ((word)1<<8)|a->Id; sendf(appl,_CONNECT_R|CONFIRM,Id,Number,"w",0); sendf(appl, _DISCONNECT_I, Id, 0, "w", _L1_ERROR); - return FALSE; + return false; } Info = _OUT_OF_PLCI; if((i=get_plci(a))) @@ -1330,7 +1330,7 @@ byte connect_req(dword Id, word Number, plci->command = _CONNECT_R; plci->number = Number; /* x.31 or D-ch free SAPI in LinkLayer? */ - if(ch==1 && LinkLayer!=3 && LinkLayer!=12) noCh = TRUE; + if(ch==1 && LinkLayer!=3 && LinkLayer!=12) noCh = true; if((ch==0 || ch==2 || noCh || ch==3 || ch==4) && !Info) { /* B-channel used for B3 connections (ch==0), or no B channel */ @@ -1381,7 +1381,7 @@ byte connect_req(dword Id, word Number, plci->command = 0; dbug(1,dprintf("Spoof")); send_req(plci); - return FALSE; + return false; } if(ch==4)add_p(plci,CHI,p_chi); add_s(plci,CPN,&parms[1]); @@ -1395,11 +1395,11 @@ byte connect_req(dword Id, word Number, plci->appl = appl; sig_req(plci,LISTEN_REQ,0); send_req(plci); - return FALSE; + return false; } } send_req(plci); - return FALSE; + return false; } plci->Id = 0; } @@ -1571,7 +1571,7 @@ byte connect_res(dword Id, word Number, byte connect_a_res(dword Id, word Number, DIVA_CAPI_ADAPTER * a, PLCI * plci, APPL * appl, API_PARSE * msg) { dbug(1,dprintf("connect_a_res")); - return FALSE; + return false; } byte disconnect_req(dword Id, word Number, DIVA_CAPI_ADAPTER * a, PLCI * plci, APPL * appl, API_PARSE * msg) @@ -1624,9 +1624,9 @@ byte disconnect_req(dword Id, word Numbe } } - if(!appl) return FALSE; + if(!appl) return false; sendf(appl, _DISCONNECT_R|CONFIRM, Id, Number, "w",Info); - return FALSE; + return false; } byte disconnect_res(dword Id, word Number, DIVA_CAPI_ADAPTER * a, PLCI * plci, APPL * appl, API_PARSE * msg) @@ -1702,7 +1702,7 @@ byte listen_req(dword Id, word Number, D "w",Info); if (a) listen_check(a); - return FALSE; + return false; } byte info_req(dword Id, word Number, DIVA_CAPI_ADAPTER * a, PLCI * plci, APPL * appl, API_PARSE * msg) @@ -1739,7 +1739,7 @@ byte info_req(dword Id, word Number, DIV add_s(plci,KEY,&ai_parms[1]); sig_req(plci,INFO_REQ,0); send_req(plci); - return FALSE; + return false; } if(plci->State && ai_parms[2].length) @@ -1769,7 +1769,7 @@ byte info_req(dword Id, word Number, DIV if((i=get_plci(a))) { rc_plci = &a->plci[i-1]; - appl->NullCREnable = TRUE; + appl->NullCREnable = true; rc_plci->internal_command = C_NCR_FAC_REQ; rc_plci->appl = appl; add_p(rc_plci,CAI,"\x01\x80"); @@ -1788,7 +1788,7 @@ byte info_req(dword Id, word Number, DIV add_ai(rc_plci, &msg[1]); sig_req(rc_plci,NCR_FACILITY,0); send_req(rc_plci); - return FALSE; + return false; /* for application controlled supplementary services */ } } @@ -1811,13 +1811,13 @@ byte info_req(dword Id, word Number, DIV Number, "w",Info); } - return FALSE; + return false; } byte info_res(dword Id, word Number, DIVA_CAPI_ADAPTER * a, PLCI * plci, APPL * appl, API_PARSE * msg) { dbug(1,dprintf("info_res")); - return FALSE; + return false; } byte alert_req(dword Id, word Number, DIVA_CAPI_ADAPTER * a, PLCI * plci, APPL * appl, API_PARSE * msg) @@ -1828,7 +1828,7 @@ byte alert_req(dword Id, word Number, DI dbug(1,dprintf("alert_req")); Info = _WRONG_IDENTIFIER; - ret = FALSE; + ret = false; if(plci) { Info = _ALERT_IGNORED; if(plci->State!=INC_CON_ALERT) { @@ -1922,7 +1922,7 @@ byte facility_req(dword Id, word Number, rplci->appl = appl; sig_req(rplci,S_SUPPORTED,0); send_req(rplci); - return FALSE; + return false; break; case S_LISTEN: @@ -1972,7 +1972,7 @@ byte facility_req(dword Id, word Number, add_s(plci,CAI,&ss_parms[1]); sig_req(plci,CALL_HOLD,0); send_req(plci); - return FALSE; + return false; } else Info = 0x3010; /* wrong state */ break; @@ -1997,13 +1997,13 @@ byte facility_req(dword Id, word Number, plci->internal_command = BLOCK_PLCI; plci->command = 0; dbug(1,dprintf("Spoof")); - return FALSE; + return false; } else { sig_req(plci,CALL_RETRIEVE,0); send_req(plci); - return FALSE; + return false; } } else Info = 0x3010; /* wrong state */ @@ -2123,7 +2123,7 @@ byte facility_req(dword Id, word Number, add_p(plci,CAI,cai); sig_req(plci,S_SERVICE,0); send_req(plci); - return FALSE; + return false; } else Info = 0x3010; /* wrong state */ break; @@ -2265,7 +2265,7 @@ byte facility_req(dword Id, word Number, add_p(rplci,CAI,cai); sig_req(rplci,S_SERVICE,0); send_req(rplci); - return FALSE; + return false; } else { @@ -2291,14 +2291,14 @@ byte facility_req(dword Id, word Number, ss_parms[3].info[3] = (byte)GET_WORD(&(ss_parms[2].info[0])); plci->command = 0; plci->internal_command = CD_REQ_PEND; - appl->CDEnable = TRUE; + appl->CDEnable = true; cai[0] = 1; cai[1] = CALL_DEFLECTION; add_p(plci,CAI,cai); add_p(plci,CPN,ss_parms[3].info); sig_req(plci,S_SERVICE,0); send_req(plci); - return FALSE; + return false; break; case S_CALL_FORWARDING_START: @@ -2337,7 +2337,7 @@ byte facility_req(dword Id, word Number, add_p(rplci,CPN,ss_parms[6].info); sig_req(rplci,S_SERVICE,0); send_req(rplci); - return FALSE; + return false; break; case S_INTERROGATE_DIVERSION: @@ -2456,7 +2456,7 @@ byte facility_req(dword Id, word Number, sig_req(rplci,S_SERVICE,0); send_req(rplci); - return FALSE; + return false; break; case S_MWI_ACTIVATE: @@ -2472,7 +2472,7 @@ byte facility_req(dword Id, word Number, { rplci = &a->plci[i-1]; rplci->appl = appl; - rplci->cr_enquiry=TRUE; + rplci->cr_enquiry=true; add_p(rplci,CAI,"\x01\x80"); add_p(rplci,UID,"\x06\x43\x61\x70\x69\x32\x30"); sig_req(rplci,ASSIGN,DSIG_ID); @@ -2487,7 +2487,7 @@ byte facility_req(dword Id, word Number, else { rplci = plci; - rplci->cr_enquiry=FALSE; + rplci->cr_enquiry=false; } rplci->command = 0; @@ -2509,7 +2509,7 @@ byte facility_req(dword Id, word Number, add_p(rplci,UID,ss_parms[10].info); /* Time */ sig_req(rplci,S_SERVICE,0); send_req(rplci); - return FALSE; + return false; case S_MWI_DEACTIVATE: if(api_parse(&parms->info[1],(word)parms->length,"wbwwss",ss_parms)) @@ -2524,7 +2524,7 @@ byte facility_req(dword Id, word Number, { rplci = &a->plci[i-1]; rplci->appl = appl; - rplci->cr_enquiry=TRUE; + rplci->cr_enquiry=true; add_p(rplci,CAI,"\x01\x80"); add_p(rplci,UID,"\x06\x43\x61\x70\x69\x32\x30"); sig_req(rplci,ASSIGN,DSIG_ID); @@ -2539,7 +2539,7 @@ byte facility_req(dword Id, word Number, else { rplci = plci; - rplci->cr_enquiry=FALSE; + rplci->cr_enquiry=false; } rplci->command = 0; @@ -2556,7 +2556,7 @@ byte facility_req(dword Id, word Number, add_p(rplci,OAD,ss_parms[5].info); /* Controlling User Number */ sig_req(rplci,S_SERVICE,0); send_req(rplci); - return FALSE; + return false; default: Info = 0x300E; /* not supported */ @@ -2597,13 +2597,13 @@ byte facility_req(dword Id, word Number, Id, Number, "wws",Info,selector,SSparms); - return FALSE; + return false; } byte facility_res(dword Id, word Number, DIVA_CAPI_ADAPTER * a, PLCI * plci, APPL * appl, API_PARSE * msg) { dbug(1,dprintf("facility_res")); - return FALSE; + return false; } byte connect_b3_req(dword Id, word Number, DIVA_CAPI_ADAPTER * a, PLCI * plci, APPL * appl, API_PARSE * parms) @@ -2649,7 +2649,7 @@ byte connect_b3_req(dword Id, word Numbe Id, Number, "w",Info); - return FALSE; + return false; } plci->requested_options_conn = 0; @@ -2684,7 +2684,7 @@ byte connect_b3_req(dword Id, word Numbe || (fax_feature_bits & T30_FEATURE_BIT_MORE_DOCUMENTS)) { len = (byte)(&(((T30_INFO *) 0)->universal_6)); - fax_info_change = FALSE; + fax_info_change = false; if (ncpi->length >= 4) { w = GET_WORD(&ncpi->info[3]); @@ -2693,7 +2693,7 @@ byte connect_b3_req(dword Id, word Numbe ((T30_INFO *)(plci->fax_connect_info_buffer))->resolution = (byte)((((T30_INFO *)(plci->fax_connect_info_buffer))->resolution & ~T30_RESOLUTION_R8_0770_OR_200) | ((w & 0x0001) ? T30_RESOLUTION_R8_0770_OR_200 : 0)); - fax_info_change = TRUE; + fax_info_change = true; } fax_control_bits &= ~(T30_CONTROL_BIT_REQUEST_POLLING | T30_CONTROL_BIT_MORE_DOCUMENTS); if (w & 0x0002) /* Fax-polling request */ @@ -2709,7 +2709,7 @@ byte connect_b3_req(dword Id, word Numbe if (((byte) w) != ((T30_INFO *)(plci->fax_connect_info_buffer))->data_format) { ((T30_INFO *)(plci->fax_connect_info_buffer))->data_format = (byte) w; - fax_info_change = TRUE; + fax_info_change = true; } if ((a->man_profile.private_options & (1L << PRIVATE_FAX_SUB_SEP_PWD)) @@ -2781,13 +2781,13 @@ byte connect_b3_req(dword Id, word Numbe { len = (byte)(&(((T30_INFO *) 0)->universal_6)); } - fax_info_change = TRUE; + fax_info_change = true; } if (fax_control_bits != GET_WORD(&((T30_INFO *)plci->fax_connect_info_buffer)->control_bits_low)) { PUT_WORD (&((T30_INFO *)plci->fax_connect_info_buffer)->control_bits_low, fax_control_bits); - fax_info_change = TRUE; + fax_info_change = true; } } if (Info == GOOD) @@ -2798,12 +2798,12 @@ byte connect_b3_req(dword Id, word Numbe if (fax_feature_bits & T30_FEATURE_BIT_MORE_DOCUMENTS) { start_internal_command (Id, plci, fax_connect_info_command); - return FALSE; + return false; } else { start_internal_command (Id, plci, fax_adjust_b23_command); - return FALSE; + return false; } } } @@ -2820,7 +2820,7 @@ byte connect_b3_req(dword Id, word Numbe for (w = 0; w < ncpi->length; w++) plci->internal_req_buffer[2+w] = ncpi->info[1+w]; start_internal_command (Id, plci, rtp_connect_b3_req_command); - return FALSE; + return false; } if(!Info) @@ -2837,7 +2837,7 @@ byte connect_b3_req(dword Id, word Numbe Id, Number, "w",Info); - return FALSE; + return false; } byte connect_b3_res(dword Id, word Number, DIVA_CAPI_ADAPTER * a, PLCI * plci, APPL * appl, API_PARSE * parms) @@ -2909,7 +2909,7 @@ byte connect_b3_res(dword Id, word Numbe plci->fax_connect_info_length = len; ((T30_INFO *)(plci->fax_connect_info_buffer))->code = 0; start_internal_command (Id, plci, fax_connect_ack_command); - return FALSE; + return false; } } @@ -2932,7 +2932,7 @@ byte connect_b3_res(dword Id, word Numbe for (w = 0; w < ncpi->length; w++) plci->internal_req_buffer[2+w] = ncpi->info[1+w]; start_internal_command (Id, plci, rtp_connect_b3_res_command); - return FALSE; + return false; } else @@ -2945,14 +2945,14 @@ byte connect_b3_res(dword Id, word Numbe sendf(appl,_CONNECT_B3_ACTIVE_I,Id,0,"s",""); if (plci->adjust_b_restore) { - plci->adjust_b_restore = FALSE; + plci->adjust_b_restore = false; start_internal_command (Id, plci, adjust_b_restore); } } return 1; } } - return FALSE; + return false; } byte connect_b3_a_res(dword Id, word Number, DIVA_CAPI_ADAPTER * a, PLCI * plci, APPL * appl, API_PARSE * parms) @@ -2972,7 +2972,7 @@ byte connect_b3_a_res(dword Id, word Num channel_xmit_xon (plci); } } - return FALSE; + return false; } byte disconnect_b3_req(dword Id, word Number, DIVA_CAPI_ADAPTER * a, PLCI * plci, APPL * appl, API_PARSE * parms) @@ -3004,7 +3004,7 @@ byte disconnect_b3_req(dword Id, word Nu { plci->send_disc = (byte)ncci; plci->command = 0; - return FALSE; + return false; } else { @@ -3028,7 +3028,7 @@ byte disconnect_b3_req(dword Id, word Nu Id, Number, "w",Info); - return FALSE; + return false; } byte disconnect_b3_res(dword Id, word Number, DIVA_CAPI_ADAPTER * a, PLCI * plci, APPL * appl, API_PARSE * parms) @@ -3084,7 +3084,7 @@ byte disconnect_b3_res(dword Id, word Nu } } } - return FALSE; + return false; } byte data_b3_req(dword Id, word Number, DIVA_CAPI_ADAPTER * a, PLCI * plci, APPL * appl, API_PARSE * parms) @@ -3140,7 +3140,7 @@ byte data_b3_req(dword Id, word Number, } send_data(plci); - return FALSE; + return false; } } if (appl) @@ -3161,7 +3161,7 @@ byte data_b3_req(dword Id, word Number, Number, "ww",GET_WORD(parms[2].info),Info); } - return FALSE; + return false; } byte data_b3_res(dword Id, word Number, DIVA_CAPI_ADAPTER * a, PLCI * plci, APPL * appl, API_PARSE * parms) @@ -3194,7 +3194,7 @@ byte data_b3_res(dword Id, word Number, } } } - return FALSE; + return false; } byte reset_b3_req(dword Id, word Number, DIVA_CAPI_ADAPTER * a, PLCI * plci, APPL * appl, API_PARSE * parms) @@ -3235,7 +3235,7 @@ byte reset_b3_req(dword Id, word Number, Id, Number, "w",Info); - return FALSE; + return false; } byte reset_b3_res(dword Id, word Number, DIVA_CAPI_ADAPTER * a, PLCI * plci, APPL * appl, API_PARSE * parms) @@ -3254,12 +3254,12 @@ byte reset_b3_res(dword Id, word Number, { a->ncci_state[ncci] = CONNECTED; nl_req_ncci(plci,N_RESET_ACK,(byte)ncci); - return TRUE; + return true; } break; } } - return FALSE; + return false; } byte connect_b3_t90_a_res(dword Id, word Number, DIVA_CAPI_ADAPTER * a, PLCI * plci, APPL * appl, API_PARSE * parms) @@ -3292,7 +3292,7 @@ byte connect_b3_t90_a_res(dword Id, word return 1; } } - return FALSE; + return false; } @@ -3378,7 +3378,7 @@ byte select_b_req(dword Id, word Number, plci->internal_command = BLOCK_PLCI; /* lock other commands */ plci->command = 0; dbug(1,dprintf("continue if codec loaded")); - return FALSE; + return false; } } } @@ -3407,12 +3407,12 @@ byte select_b_req(dword Id, word Number, else if (plci->call_dir & CALL_DIR_IN) plci->call_dir = CALL_DIR_IN | CALL_DIR_ANSWER; start_internal_command (Id, plci, select_b_command); - return FALSE; + return false; } } } sendf(appl, _SELECT_B_REQ|CONFIRM, Id, Number, "w", Info); - return FALSE; + return false; } byte manufacturer_req(dword Id, word Number, DIVA_CAPI_ADAPTER * a, PLCI * plci, APPL * appl, API_PARSE * parms) @@ -3489,7 +3489,7 @@ byte manufacturer_req(dword Id, word Num } plci->State = LOCAL_CONNECT; - plci->manufacturer = TRUE; + plci->manufacturer = true; plci->command = _MANUFACTURER_R; plci->m_command = command; plci->number = Number; @@ -3520,7 +3520,7 @@ byte manufacturer_req(dword Id, word Num plci->internal_command = BLOCK_PLCI; /* reject other req meanwhile */ plci->command = 0; send_req(plci); - return FALSE; + return false; } if(dir==1) { sig_req(plci,CALL_REQ,0); @@ -3573,7 +3573,7 @@ byte manufacturer_req(dword Id, word Num } else if(req==LAW_REQ) { - plci->cr_enquiry = TRUE; + plci->cr_enquiry = true; } add_ss(plci,FTY,&m_parms[1]); sig_req(plci,req,0); @@ -3739,7 +3739,7 @@ byte manufacturer_req(dword Id, word Num Id, Number, "dww",_DI_MANU_ID,command,Info); - return FALSE; + return false; } @@ -3760,7 +3760,7 @@ byte manufacturer_res(dword Id, word Num || (msg[1].length == 0) || (GET_DWORD(msg[0].info)!=_DI_MANU_ID)) { - return FALSE; + return false; } indication = GET_WORD(msg[1].info); switch (indication) @@ -3811,7 +3811,7 @@ byte manufacturer_res(dword Id, word Num break; } - return FALSE; + return false; } /*------------------------------------------------------------------*/ @@ -3908,14 +3908,14 @@ void callback(ENTITY * e) plci->nl_req = 0; } if (plci->nl_req) - control_rc (plci, 0, rc, ch, 0, TRUE); + control_rc (plci, 0, rc, ch, 0, true); else { if (req == N_XON) { channel_x_on (plci, ch); if (plci->internal_command) - control_rc (plci, req, rc, ch, 0, TRUE); + control_rc (plci, req, rc, ch, 0, true); } else { @@ -3931,21 +3931,21 @@ void callback(ENTITY * e) } } channel_xmit_xon (plci); - control_rc (plci, 0, rc, ch, global_req, TRUE); + control_rc (plci, 0, rc, ch, global_req, true); } else if (plci->data_sent) { channel_xmit_xon (plci); - plci->data_sent = FALSE; + plci->data_sent = false; plci->NL.XNum = 1; data_rc (plci, ch); if (plci->internal_command) - control_rc (plci, req, rc, ch, 0, TRUE); + control_rc (plci, req, rc, ch, 0, true); } else { channel_xmit_xon (plci); - control_rc (plci, req, rc, ch, 0, TRUE); + control_rc (plci, req, rc, ch, 0, true); } } } @@ -3974,12 +3974,12 @@ void callback(ENTITY * e) if (rc != ASSIGN_OK) e->Id = 0; channel_xmit_xon (plci); - control_rc (plci, 0, rc, ch, global_req, FALSE); + control_rc (plci, 0, rc, ch, global_req, false); } else { channel_xmit_xon (plci); - control_rc (plci, req, rc, ch, 0, FALSE); + control_rc (plci, req, rc, ch, 0, false); } } /* @@ -4065,8 +4065,8 @@ capi_callback_suffix: if (plci->li_notify_update) { - plci->li_notify_update = FALSE; - mixer_notify_update (plci, FALSE); + plci->li_notify_update = false; + mixer_notify_update (plci, false); } } @@ -4428,7 +4428,7 @@ void control_rc(PLCI * plci, byte req, else { sendf(appl,_INFO_R|CONFIRM,Id&0xf,Number,"w",_WRONG_STATE); - appl->NullCREnable = FALSE; + appl->NullCREnable = false; plci_remove(plci); } } @@ -4441,7 +4441,7 @@ void control_rc(PLCI * plci, byte req, else { sendf(appl,_INFO_R|CONFIRM,Id&0xf,Number,"w",_WRONG_STATE); - appl->NullCREnable = FALSE; + appl->NullCREnable = false; } plci_remove(plci); } @@ -4862,7 +4862,7 @@ #define MAXPARMSIDS 31 byte CF_Ind[] = "\x09\x02\x00\x06\x00\x00\x00\x00\x00\x00"; byte Interr_Err_Ind[] = "\x0a\x02\x00\x07\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"; byte CONF_Ind[] = "\x09\x16\x00\x06\x00\x00\0x00\0x00\0x00\0x00"; - byte force_mt_info = FALSE; + byte force_mt_info = false; byte dir; dword d; word w; @@ -4933,7 +4933,7 @@ #define MAXPARMSIDS 31 { if(plci->cr_enquiry && plci->appl) { - plci->cr_enquiry = FALSE; + plci->cr_enquiry = false; /* d = MANU_ID */ /* w = m_command */ /* b = total length */ @@ -5158,7 +5158,7 @@ #define MAXPARMSIDS 31 if(application[i].CDEnable) { if(application[i].Id) sendf(&application[i],_FACILITY_I,Id,0,"ws",3, SS_Ind); - application[i].CDEnable = FALSE; + application[i].CDEnable = false; } } break; @@ -5375,7 +5375,7 @@ #define MAXPARMSIDS 31 if(application[i].CDEnable) { if(application[i].Id) sendf(&application[i],_FACILITY_I,Id,0,"ws",3, SS_Ind); - application[i].CDEnable = FALSE; + application[i].CDEnable = false; } } break; @@ -5730,7 +5730,7 @@ #define MAXPARMSIDS 31 plci, Id, parms, - SendMultiIE(plci,Id,multi_pi_parms, PI, 0x210, TRUE)); + SendMultiIE(plci,Id,multi_pi_parms, PI, 0x210, true)); } } clear_c_ind_mask_bit (plci, MAX_APPL); @@ -6117,38 +6117,38 @@ static void SendSetupInfo(APPL * appl, dbug(1,dprintf("CPN ")); Info_Number = 0x0070; Info_Mask = 0x80; - Info_Sent_Flag = TRUE; + Info_Sent_Flag = true; break; case 8: /* display */ dbug(1,dprintf("display(%d)",i)); Info_Number = 0x0028; Info_Mask = 0x04; - Info_Sent_Flag = TRUE; + Info_Sent_Flag = true; break; case 16: /* Channel Id */ dbug(1,dprintf("CHI")); Info_Number = 0x0018; Info_Mask = 0x100; - Info_Sent_Flag = TRUE; + Info_Sent_Flag = true; mixer_set_bchannel_id (plci, Info_Element); break; case 19: /* Redirected Number */ dbug(1,dprintf("RDN")); Info_Number = 0x0074; Info_Mask = 0x400; - Info_Sent_Flag = TRUE; + Info_Sent_Flag = true; break; case 20: /* Redirected Number extended */ dbug(1,dprintf("RDX")); Info_Number = 0x0073; Info_Mask = 0x400; - Info_Sent_Flag = TRUE; + Info_Sent_Flag = true; break; case 22: /* Redirecing Number */ dbug(1,dprintf("RIN")); Info_Number = 0x0076; Info_Mask = 0x400; - Info_Sent_Flag = TRUE; + Info_Sent_Flag = true; break; default: Info_Number = 0; @@ -6312,7 +6312,7 @@ void SendInfo(PLCI * plci, dword Id, b && plci->adapter->Info_Mask[appl->Id-1] &Info_Mask) { dbug(1,dprintf("NCR_Ind")); - iesent=TRUE; + iesent=true; sendf(&application[j],_INFO_I,Id&0x0f,0,"wS",Info_Number,Info_Element); } } @@ -6330,7 +6330,7 @@ void SendInfo(PLCI * plci, dword Id, b if(test_c_ind_mask_bit (plci, j)) { dbug(1,dprintf("Ovl_Ind")); - iesent=TRUE; + iesent=true; sendf(&application[j],_INFO_I,Id,0,"wS",Info_Number,Info_Element); } } @@ -6340,7 +6340,7 @@ void SendInfo(PLCI * plci, dword Id, b && plci->adapter->Info_Mask[plci->appl->Id-1] &Info_Mask) { dbug(1,dprintf("Std_Ind")); - iesent=TRUE; + iesent=true; sendf(plci->appl,_INFO_I,Id,0,"wS",Info_Number,Info_Element); } } @@ -6391,7 +6391,7 @@ byte SendMultiIE(PLCI * plci, dword Id && appl->Id && plci->adapter->Info_Mask[appl->Id-1] &Info_Mask) { - iesent = TRUE; + iesent = true; dbug(1,dprintf("Mlt_NCR_Ind")); sendf(&application[j],_INFO_I,Id&0x0f,0,"wS",Info_Number,Info_Element); } @@ -6403,7 +6403,7 @@ byte SendMultiIE(PLCI * plci, dword Id { if(test_c_ind_mask_bit (plci, j)) { - iesent = TRUE; + iesent = true; dbug(1,dprintf("Mlt_Ovl_Ind")); sendf(&application[j],_INFO_I,Id,0,"wS",Info_Number,Info_Element); } @@ -6412,7 +6412,7 @@ byte SendMultiIE(PLCI * plci, dword Id else if(Info_Number && plci->adapter->Info_Mask[plci->appl->Id-1] &Info_Mask) { - iesent = TRUE; + iesent = true; dbug(1,dprintf("Mlt_Std_Ind")); sendf(plci->appl,_INFO_I,Id,0,"wS",Info_Number,Info_Element); } @@ -6812,7 +6812,7 @@ void nl_ind(PLCI * plci) } if (((plci->NL.Ind & 0x0f) == N_DISC) || ((plci->NL.Ind & 0x0f) == N_DISC_ACK)) { - if (((T30_INFO *)plci->NL.RBuffer->P)->code < sizeof(fax_info) / sizeof(fax_info[0])) + if (((T30_INFO *)plci->NL.RBuffer->P)->code < ARRAY_SIZE(fax_info)) info = fax_info[((T30_INFO *)plci->NL.RBuffer->P)->code]; else info = _FAX_PROTOCOL_ERROR; @@ -6887,7 +6887,7 @@ void nl_ind(PLCI * plci) (byte)(plci->ncpi_buffer[0] + 1), plci->ncpi_buffer); plci->ncpi_state |= NCPI_NEGOTIATE_B3_SENT; if (plci->nsf_control_bits & T30_NSF_CONTROL_BIT_NEGOTIATE_RESP) - fax_send_edata_ack = FALSE; + fax_send_edata_ack = false; } if (a->manufacturer_features & MANUFACTURER_FEATURE_FAX_PAPER_FORMATS) @@ -6928,7 +6928,7 @@ void nl_ind(PLCI * plci) sendf(plci->appl,_DISCONNECT_B3_I,Id,0,"wS",GOOD,plci->ncpi_buffer); a->ncci_state[ncci] = INC_DIS_PENDING; plci->ncpi_state = 0; - fax_send_edata_ack = FALSE; + fax_send_edata_ack = false; } break; } @@ -7025,7 +7025,7 @@ void nl_ind(PLCI * plci) } if (plci->adjust_b_restore) { - plci->adjust_b_restore = FALSE; + plci->adjust_b_restore = false; start_internal_command (Id, plci, adjust_b_restore); } break; @@ -7041,7 +7041,7 @@ void nl_ind(PLCI * plci) next_internal_command (Id, plci); } ncci_state = a->ncci_state[ncci]; - ncci_remove (plci, ncci, FALSE); + ncci_remove (plci, ncci, false); /* with N_DISC or N_DISC_ACK the IDI frees the respective */ /* channel, so we cannot store the state in ncci_state! The */ @@ -7288,18 +7288,18 @@ word get_plci(DIVA_CAPI_ADAPTER * a) plci->msg_in_read_pos = MSG_IN_QUEUE_SIZE; plci->msg_in_wrap_pos = MSG_IN_QUEUE_SIZE; - plci->data_sent = FALSE; + plci->data_sent = false; plci->send_disc = 0; plci->sig_global_req = 0; plci->sig_remove_id = 0; plci->nl_global_req = 0; plci->nl_remove_id = 0; plci->adv_nl = 0; - plci->manufacturer = FALSE; + plci->manufacturer = false; plci->call_dir = CALL_DIR_OUT | CALL_DIR_ORIGINATE; plci->spoofed_msg = 0; plci->ptyState = 0; - plci->cr_enquiry = FALSE; + plci->cr_enquiry = false; plci->hangup_flow_ctrl_timer = 0; plci->ncci_ring_list = 0; @@ -7972,7 +7972,7 @@ word add_b23(PLCI * plci, API_PARSE * if(!bp->length && plci->tel) { - plci->adv_nl = TRUE; + plci->adv_nl = true; dbug(1,dprintf("Default adv.Nl")); add_p(plci,LLI,lli); plci->B2_prot = 1 /*XPARENT*/; @@ -8022,7 +8022,7 @@ word add_b23(PLCI * plci, API_PARSE * { if(GET_WORD(bp_parms[1].info)!=1 || GET_WORD(bp_parms[2].info)!=0) return _B2_NOT_SUPPORTED; - plci->adv_nl = TRUE; + plci->adv_nl = true; } else if(plci->tel) return _B2_NOT_SUPPORTED; @@ -8840,7 +8840,7 @@ void send_data(PLCI * plci) plci->NL.X = plci->NData; plci->NL.ReqCh = a->ncci_ch[ncci]; dbug(1,dprintf("%x:DREQ(%x:%x)",a->Id,plci->NL.Id,plci->NL.Req)); - plci->data_sent = TRUE; + plci->data_sent = true; plci->data_sent_ptr = data->P; a->request(&plci->NL); } @@ -8995,10 +8995,10 @@ void IndParse(PLCI * plci, word * parm byte ie_compare(byte * ie1, byte * ie2) { word i; - if(!ie1 || ! ie2) return FALSE; - if(!ie1[0]) return FALSE; - for(i=0;i<(word)(ie1[0]+1);i++) if(ie1[i]!=ie2[i]) return FALSE; - return TRUE; + if(!ie1 || ! ie2) return false; + if(!ie1[0]) return false; + for(i=0;i<(word)(ie1[0]+1);i++) if(ie1[i]!=ie2[i]) return false; + return true; } word find_cip(DIVA_CAPI_ADAPTER * a, byte * bc, byte * hlc) @@ -9151,7 +9151,7 @@ word AdvCodecSupport(DIVA_CAPI_ADAPTER plci->tel=ADV_VOICE; } a->AdvSignalAppl = appl; - a->AdvCodecFLAG = TRUE; + a->AdvCodecFLAG = true; a->AdvCodecPLCI = splci; add_p(splci,CAI,"\x01\x15"); add_p(splci,LLI,"\x01\x00"); @@ -9183,7 +9183,7 @@ word AdvCodecSupport(DIVA_CAPI_ADAPTER add_p(splci,UID,"\x06\x43\x61\x70\x69\x32\x30"); sig_req(splci,ASSIGN,0xC0); /* 0xc0 is the TEL_ID */ send_req(splci); - a->scom_appl_disable = TRUE; + a->scom_appl_disable = true; } else{ return 0x2001; /* wrong state, no more plcis */ @@ -9411,7 +9411,7 @@ word CapiRelease(word Id) } if(a->AdvSignalAppl==this) { - this->NullCREnable = FALSE; + this->NullCREnable = false; if (a->AdvCodecPLCI) { plci_remove(a->AdvCodecPLCI); @@ -9433,7 +9433,7 @@ word CapiRelease(word Id) static word plci_remove_check(PLCI *plci) { - if(!plci) return TRUE; + if(!plci) return true; if(!plci->NL.Id && c_ind_mask_empty (plci)) { if(plci->Sig.Id == 0xff) @@ -9446,7 +9446,7 @@ static word plci_remove_check(PLCI *pl { CodecIdCheck(plci->adapter, plci); clear_b1_config (plci); - ncci_remove (plci, 0, FALSE); + ncci_remove (plci, 0, false); plci_free_msg_in_queue (plci); channel_flow_control_remove (plci); plci->Id = 0; @@ -9456,10 +9456,10 @@ static word plci_remove_check(PLCI *pl plci->notifiedcall = 0; } listen_check(plci->adapter); - return TRUE; + return true; } } - return FALSE; + return false; } @@ -9564,7 +9564,7 @@ static struct }; -#define DTMF_DIGIT_MAP_ENTRIES (sizeof(dtmf_digit_map) / sizeof(dtmf_digit_map[0])) +#define DTMF_DIGIT_MAP_ENTRIES ARRAY_SIZE(dtmf_digit_map) static void dtmf_enable_receiver (PLCI *plci, byte enable_mask) @@ -9815,7 +9815,7 @@ static void dtmf_command (dword Id, PLCI } plci->dtmf_rec_active &= ~mask; plci->internal_command = DTMF_COMMAND_2; - dtmf_enable_receiver (plci, FALSE); + dtmf_enable_receiver (plci, false); return; } Rc = OK; @@ -10020,7 +10020,7 @@ static byte dtmf_request (dword Id, word } } start_internal_command (Id, plci, dtmf_command); - return (FALSE); + return (false); case DTMF_SEND_TONE: @@ -10069,8 +10069,7 @@ static byte dtmf_request (dword Id, word PUT_WORD (&result[1], DTMF_INCORRECT_DIGIT); break; } - if (plci->dtmf_send_requests >= - sizeof(plci->dtmf_msg_number_queue) / sizeof(plci->dtmf_msg_number_queue[0])) + if (plci->dtmf_send_requests >= ARRAY_SIZE(plci->dtmf_msg_number_queue)) { dbug (1, dprintf ("[%06lx] %s,%d: DTMF request overrun", UnMapId (Id), (char *)(FILE_), __LINE__)); @@ -10079,7 +10078,7 @@ static byte dtmf_request (dword Id, word } api_save_msg (dtmf_parms, "wwws", &plci->saved_msg); start_internal_command (Id, plci, dtmf_command); - return (FALSE); + return (false); default: dbug (1, dprintf ("[%06lx] %s,%d: DTMF unknown request %04x", @@ -10090,7 +10089,7 @@ static byte dtmf_request (dword Id, word } sendf (appl, _FACILITY_R | CONFIRM, Id & 0xffffL, Number, "wws", Info, SELECTOR_DTMF, result); - return (FALSE); + return (false); } @@ -10842,10 +10841,10 @@ static struct byte to_pc; } xconnect_write_prog[] = { - { LI_COEF_CH_CH, FALSE, FALSE }, - { LI_COEF_CH_PC, FALSE, TRUE }, - { LI_COEF_PC_CH, TRUE, FALSE }, - { LI_COEF_PC_PC, TRUE, TRUE } + { LI_COEF_CH_CH, false, false }, + { LI_COEF_CH_PC, false, true }, + { LI_COEF_PC_CH, true, false }, + { LI_COEF_PC_PC, true, true } }; @@ -10916,7 +10915,7 @@ static byte xconnect_write_coefs_process { dbug (1, dprintf ("[%06x] %s,%d: Channel id wiped out", UnMapId (Id), (char *)(FILE_), __LINE__)); - return (TRUE); + return (true); } i = a->li_base + (plci->li_bchannel_id - 1); j = plci->li_write_channel; @@ -10927,7 +10926,7 @@ static byte xconnect_write_coefs_process { dbug (1, dprintf ("[%06lx] %s,%d: LI write coefs failed %02x", UnMapId (Id), (char *)(FILE_), __LINE__, Rc)); - return (FALSE); + return (false); } } if (li_config_table[i].adapter->manufacturer_features & MANUFACTURER_FEATURE_XCONNECT) @@ -10969,7 +10968,7 @@ static byte xconnect_write_coefs_process { plci->internal_command = plci->li_write_command; if (plci_nl_busy (plci)) - return (TRUE); + return (true); to_ch = (a->li_pri) ? plci->li_bchannel_id - 1 : 0; *(p++) = UDATA_REQUEST_XCONNECT_TO; do @@ -11018,9 +11017,9 @@ static byte xconnect_write_coefs_process li_config_table[i].coef_table[j] ^= xconnect_write_prog[n].mask << 4; } n++; - } while ((n < sizeof(xconnect_write_prog) / sizeof(xconnect_write_prog[0])) + } while ((n < ARRAY_SIZE(xconnect_write_prog)) && ((p - plci->internal_req_buffer) + 16 < INTERNAL_REQ_BUFFER_SIZE)); - if (n == sizeof(xconnect_write_prog) / sizeof(xconnect_write_prog[0])) + if (n == ARRAY_SIZE(xconnect_write_prog)) { do { @@ -11050,7 +11049,7 @@ static byte xconnect_write_coefs_process { plci->internal_command = plci->li_write_command; if (plci_nl_busy (plci)) - return (TRUE); + return (true); if (a->li_pri) { *(p++) = UDATA_REQUEST_SET_MIXER_COEFS_PRI_SYNC; @@ -11090,7 +11089,7 @@ static byte xconnect_write_coefs_process ch_map[j+1] = (byte)(j+1); } } - for (n = 0; n < sizeof(mixer_write_prog_bri) / sizeof(mixer_write_prog_bri[0]); n++) + for (n = 0; n < ARRAY_SIZE(mixer_write_prog_bri); n++) { i = a->li_base + ch_map[mixer_write_prog_bri[n].to_ch]; j = a->li_base + ch_map[mixer_write_prog_bri[n].from_ch]; @@ -11127,7 +11126,7 @@ static byte xconnect_write_coefs_process { plci->internal_command = plci->li_write_command; if (plci_nl_busy (plci)) - return (TRUE); + return (true); if (j < a->li_base) j = a->li_base; if (a->li_pri) @@ -11140,7 +11139,7 @@ static byte xconnect_write_coefs_process w |= MIXER_FEATURE_ENABLE_RX_DATA; *(p++) = (byte) w; *(p++) = (byte)(w >> 8); - for (n = 0; n < sizeof(mixer_write_prog_pri) / sizeof(mixer_write_prog_pri[0]); n++) + for (n = 0; n < ARRAY_SIZE(mixer_write_prog_pri); n++) { *(p++) = (byte)((plci->li_bchannel_id - 1) | mixer_write_prog_pri[n].line_flags); for (j = a->li_base; j < a->li_base + MIXER_CHANNELS_PRI; j++) @@ -11196,7 +11195,7 @@ static byte xconnect_write_coefs_process ch_map[j+1] = (byte)(j+1); } } - for (n = 0; n < sizeof(mixer_write_prog_bri) / sizeof(mixer_write_prog_bri[0]); n++) + for (n = 0; n < ARRAY_SIZE(mixer_write_prog_bri); n++) { i = a->li_base + ch_map[mixer_write_prog_bri[n].to_ch]; j = a->li_base + ch_map[mixer_write_prog_bri[n].from_ch]; @@ -11232,7 +11231,7 @@ static byte xconnect_write_coefs_process plci->NL.Req = plci->nl_req = (byte) N_UDATA; plci->adapter->request (&plci->NL); } - return (TRUE); + return (true); } @@ -11251,7 +11250,7 @@ static void mixer_notify_update (PLCI if (a->profile.Global_Options & GL_LINE_INTERCONNECT_SUPPORTED) { if (others) - plci->li_notify_update = TRUE; + plci->li_notify_update = true; i = 0; do { @@ -11277,7 +11276,7 @@ static void mixer_notify_update (PLCI && (notify_plci->State) && notify_plci->NL.Id && !notify_plci->nl_remove_id) { - notify_plci->li_notify_update = TRUE; + notify_plci->li_notify_update = true; ((CAPI_MSG *) msg)->header.length = 18; ((CAPI_MSG *) msg)->header.appl_id = notify_plci->appl->Id; ((CAPI_MSG *) msg)->header.command = _FACILITY_R; @@ -11299,12 +11298,12 @@ static void mixer_notify_update (PLCI (char *)(FILE_), __LINE__, (dword)((notify_plci->Id << 8) | UnMapController (notify_plci->adapter->Id)), w)); } - notify_plci->li_notify_update = FALSE; + notify_plci->li_notify_update = false; } } } while (others && (notify_plci != NULL)); if (others) - plci->li_notify_update = FALSE; + plci->li_notify_update = false; } } @@ -11318,7 +11317,7 @@ static void mixer_clear_config (PLCI * (dword)((plci->Id << 8) | UnMapController (plci->adapter->Id)), (char *)(FILE_), __LINE__)); - plci->li_notify_update = FALSE; + plci->li_notify_update = false; plci->li_plci_b_write_pos = 0; plci->li_plci_b_read_pos = 0; plci->li_plci_b_req_pos = 0; @@ -12159,7 +12158,7 @@ static byte mixer_request (dword Id, wor plci_b = li_check_plci_b (Id, plci, plci_b_id, plci_b_write_pos, &result[8]); if (plci_b == NULL) break; - li_update_connect (Id, a, plci, plci_b_id, TRUE, li_flags); + li_update_connect (Id, a, plci, plci_b_id, true, li_flags); plci->li_plci_b_queue[plci_b_write_pos] = plci_b_id | LI_PLCI_B_LAST_FLAG; plci_b_write_pos = (plci_b_write_pos == LI_PLCI_B_QUEUE_ENTRIES-1) ? 0 : plci_b_write_pos + 1; plci->li_plci_b_write_pos = plci_b_write_pos; @@ -12188,7 +12187,7 @@ static byte mixer_request (dword Id, wor plci_b_write_pos = plci->li_plci_b_write_pos; participant_parms_pos = 0; result_pos = 7; - li2_update_connect (Id, a, plci, UnMapId (Id), TRUE, li_flags); + li2_update_connect (Id, a, plci, UnMapId (Id), true, li_flags); while (participant_parms_pos < li_req_parms[1].length) { result[result_pos] = 6; @@ -12224,7 +12223,7 @@ static byte mixer_request (dword Id, wor plci_b = li2_check_plci_b (Id, plci, plci_b_id, plci_b_write_pos, &result[result_pos - 2]); if (plci_b != NULL) { - li2_update_connect (Id, a, plci, plci_b_id, TRUE, li_flags); + li2_update_connect (Id, a, plci, plci_b_id, true, li_flags); plci->li_plci_b_queue[plci_b_write_pos] = plci_b_id | ((li_flags & (LI2_FLAG_INTERCONNECT_A_B | LI2_FLAG_INTERCONNECT_B_A | LI2_FLAG_PCCONNECT_A_B | LI2_FLAG_PCCONNECT_B_A)) ? 0 : LI_PLCI_B_DISC_FLAG); @@ -12249,13 +12248,13 @@ static byte mixer_request (dword Id, wor } mixer_calculate_coefs (a); plci->li_channel_bits = li_config_table[a->li_base + (plci->li_bchannel_id - 1)].channel; - mixer_notify_update (plci, TRUE); + mixer_notify_update (plci, true); sendf (appl, _FACILITY_R | CONFIRM, Id & 0xffffL, Number, "wwS", Info, SELECTOR_LINE_INTERCONNECT, result); plci->command = 0; plci->li_cmd = GET_WORD (li_parms[0].info); start_internal_command (Id, plci, mixer_command); - return (FALSE); + return (false); case LI_REQ_DISCONNECT: if (li_parms[1].length == 4) @@ -12283,7 +12282,7 @@ static byte mixer_request (dword Id, wor plci_b = li_check_plci_b (Id, plci, plci_b_id, plci_b_write_pos, &result[8]); if (plci_b == NULL) break; - li_update_connect (Id, a, plci, plci_b_id, FALSE, 0); + li_update_connect (Id, a, plci, plci_b_id, false, 0); plci->li_plci_b_queue[plci_b_write_pos] = plci_b_id | LI_PLCI_B_DISC_FLAG | LI_PLCI_B_LAST_FLAG; plci_b_write_pos = (plci_b_write_pos == LI_PLCI_B_QUEUE_ENTRIES-1) ? 0 : plci_b_write_pos + 1; plci->li_plci_b_write_pos = plci_b_write_pos; @@ -12345,7 +12344,7 @@ static byte mixer_request (dword Id, wor plci_b = li2_check_plci_b (Id, plci, plci_b_id, plci_b_write_pos, &result[result_pos - 2]); if (plci_b != NULL) { - li2_update_connect (Id, a, plci, plci_b_id, FALSE, 0); + li2_update_connect (Id, a, plci, plci_b_id, false, 0); plci->li_plci_b_queue[plci_b_write_pos] = plci_b_id | LI_PLCI_B_DISC_FLAG; plci_b_write_pos = (plci_b_write_pos == LI_PLCI_B_QUEUE_ENTRIES-1) ? 0 : plci_b_write_pos + 1; } @@ -12368,13 +12367,13 @@ static byte mixer_request (dword Id, wor } mixer_calculate_coefs (a); plci->li_channel_bits = li_config_table[a->li_base + (plci->li_bchannel_id - 1)].channel; - mixer_notify_update (plci, TRUE); + mixer_notify_update (plci, true); sendf (appl, _FACILITY_R | CONFIRM, Id & 0xffffL, Number, "wwS", Info, SELECTOR_LINE_INTERCONNECT, result); plci->command = 0; plci->li_cmd = GET_WORD (li_parms[0].info); start_internal_command (Id, plci, mixer_command); - return (FALSE); + return (false); case LI_REQ_SILENT_UPDATE: if (!plci || !plci->State @@ -12384,7 +12383,7 @@ static byte mixer_request (dword Id, wor { dbug (1, dprintf ("[%06lx] %s,%d: Wrong state", UnMapId (Id), (char *)(FILE_), __LINE__)); - return (FALSE); + return (false); } plci_b_write_pos = plci->li_plci_b_write_pos; if (((plci->li_plci_b_read_pos > plci_b_write_pos) ? plci->li_plci_b_read_pos : @@ -12392,7 +12391,7 @@ static byte mixer_request (dword Id, wor { dbug (1, dprintf ("[%06lx] %s,%d: LI request overrun", UnMapId (Id), (char *)(FILE_), __LINE__)); - return (FALSE); + return (false); } i = (plci_b_write_pos == 0) ? LI_PLCI_B_QUEUE_ENTRIES-1 : plci_b_write_pos - 1; if ((plci_b_write_pos == plci->li_plci_b_read_pos) @@ -12408,7 +12407,7 @@ static byte mixer_request (dword Id, wor plci->command = 0; plci->li_cmd = GET_WORD (li_parms[0].info); start_internal_command (Id, plci, mixer_command); - return (FALSE); + return (false); default: dbug (1, dprintf ("[%06lx] %s,%d: LI unknown request %04x", @@ -12418,7 +12417,7 @@ static byte mixer_request (dword Id, wor } sendf (appl, _FACILITY_R | CONFIRM, Id & 0xffffL, Number, "wwS", Info, SELECTOR_LINE_INTERCONNECT, result); - return (FALSE); + return (false); } @@ -12523,7 +12522,7 @@ static void mixer_indication_xconnect_fr if (!plci->internal_command) next_internal_command (Id, plci); } - mixer_notify_update (plci, TRUE); + mixer_notify_update (plci, true); } @@ -12547,12 +12546,12 @@ static byte mixer_notify_source_removed dbug (1, dprintf ("[%06lx] %s,%d: LI request overrun", (dword)((plci->Id << 8) | UnMapController (plci->adapter->Id)), (char *)(FILE_), __LINE__)); - return (FALSE); + return (false); } plci->li_plci_b_queue[plci_b_write_pos] = plci_b_id | LI_PLCI_B_DISC_FLAG; plci_b_write_pos = (plci_b_write_pos == LI_PLCI_B_QUEUE_ENTRIES-1) ? 0 : plci_b_write_pos + 1; plci->li_plci_b_write_pos = plci_b_write_pos; - return (TRUE); + return (true); } @@ -12596,7 +12595,7 @@ static void mixer_remove (PLCI *plci) } mixer_clear_config (plci); mixer_calculate_coefs (a); - mixer_notify_update (plci, TRUE); + mixer_notify_update (plci, true); } li_config_table[i].plci = NULL; plci->li_bchannel_id = 0; @@ -12883,29 +12882,29 @@ static byte ec_request (dword Id, word N case EC_ENABLE_OPERATION: plci->ec_idi_options &= ~LEC_FREEZE_COEFFICIENTS; start_internal_command (Id, plci, ec_command); - return (FALSE); + return (false); case EC_DISABLE_OPERATION: plci->ec_idi_options = LEC_ENABLE_ECHO_CANCELLER | LEC_MANUAL_DISABLE | LEC_ENABLE_NONLINEAR_PROCESSING | LEC_RESET_COEFFICIENTS; start_internal_command (Id, plci, ec_command); - return (FALSE); + return (false); case EC_FREEZE_COEFFICIENTS: plci->ec_idi_options |= LEC_FREEZE_COEFFICIENTS; start_internal_command (Id, plci, ec_command); - return (FALSE); + return (false); case EC_RESUME_COEFFICIENT_UPDATE: plci->ec_idi_options &= ~LEC_FREEZE_COEFFICIENTS; start_internal_command (Id, plci, ec_command); - return (FALSE); + return (false); case EC_RESET_COEFFICIENTS: plci->ec_idi_options |= LEC_RESET_COEFFICIENTS; start_internal_command (Id, plci, ec_command); - return (FALSE); + return (false); default: dbug (1, dprintf ("[%06lx] %s,%d: EC unknown request %04x", @@ -12978,14 +12977,14 @@ static byte ec_request (dword Id, word N case EC_ENABLE_OPERATION: plci->ec_idi_options &= ~LEC_FREEZE_COEFFICIENTS; start_internal_command (Id, plci, ec_command); - return (FALSE); + return (false); case EC_DISABLE_OPERATION: plci->ec_idi_options = LEC_ENABLE_ECHO_CANCELLER | LEC_MANUAL_DISABLE | LEC_ENABLE_NONLINEAR_PROCESSING | LEC_RESET_COEFFICIENTS; start_internal_command (Id, plci, ec_command); - return (FALSE); + return (false); default: dbug (1, dprintf ("[%06lx] %s,%d: EC unknown request %04x", @@ -12999,7 +12998,7 @@ static byte ec_request (dword Id, word N sendf (appl, _FACILITY_R | CONFIRM, Id & 0xffffL, Number, "wws", Info, (appl->appl_flags & APPL_FLAG_PRIV_EC_SPEC) ? PRIV_SELECTOR_ECHO_CANCELLER : SELECTOR_ECHO_CANCELLER, result); - return (FALSE); + return (false); } @@ -13178,7 +13177,7 @@ static void adv_voice_write_coefs (PLCI ch_map[j] = (byte)(j + (plci->li_bchannel_id - 1)); ch_map[j+1] = (byte)(j + (2 - plci->li_bchannel_id)); } - for (n = 0; n < sizeof(mixer_write_prog_bri) / sizeof(mixer_write_prog_bri[0]); n++) + for (n = 0; n < ARRAY_SIZE(mixer_write_prog_bri); n++) { i = a->li_base + ch_map[mixer_write_prog_bri[n].to_ch]; j = a->li_base + ch_map[mixer_write_prog_bri[n].from_ch]; @@ -13563,7 +13562,7 @@ static void adjust_b_clear (PLCI *plci (dword)((plci->Id << 8) | UnMapController (plci->adapter->Id)), (char *)(FILE_), __LINE__)); - plci->adjust_b_restore = FALSE; + plci->adjust_b_restore = false; } @@ -13832,7 +13831,7 @@ static word adjust_b_process (dword Id, } if (plci->adjust_b_mode & ADJUST_B_MODE_USER_CONNECT) { - plci->adjust_b_restore = TRUE; + plci->adjust_b_restore = true; break; } plci->adjust_b_state = ADJUST_B_CONNECT_1; @@ -14603,7 +14602,7 @@ static void channel_request_xon (PLCI static void channel_xmit_extended_xon (PLCI * plci) { DIVA_CAPI_ADAPTER * a; - int max_ch = sizeof(a->ch_flow_control)/sizeof(a->ch_flow_control[0]); + int max_ch = ARRAY_SIZE(a->ch_flow_control); int i, one_requested = 0; if ((!plci) || (!plci->Id) || ((a = plci->adapter) == 0)) { @@ -14628,7 +14627,7 @@ static void channel_xmit_extended_xon (P Try to xmit next X_ON */ static int find_channel_with_pending_x_on (DIVA_CAPI_ADAPTER * a, PLCI * plci) { - int max_ch = sizeof(a->ch_flow_control)/sizeof(a->ch_flow_control[0]); + int max_ch = ARRAY_SIZE(a->ch_flow_control); int i; if (!(plci->adapter->manufacturer_features & MANUFACTURER_FEATURE_XONOFF_FLOW_CONTROL)) { @@ -14768,19 +14767,19 @@ static void group_optimization(DIVA_CAPI { if(application[i].Id && a->CIP_Mask[i] ) { - for(k=0,busy=FALSE; kmax_plci; k++) + for(k=0,busy=false; kmax_plci; k++) { if(a->plci[k].Id) { auxplci = &a->plci[k]; if(auxplci->appl == &application[i]) /* application has a busy PLCI */ { - busy = TRUE; + busy = true; dbug(1,dprintf("Appl 0x%x is busy",i+1)); } else if(test_c_ind_mask_bit (auxplci, i)) /* application has an incoming call pending */ { - busy = TRUE; + busy = true; dbug(1,dprintf("Appl 0x%x has inc. call pending",i+1)); } } @@ -14791,13 +14790,13 @@ static void group_optimization(DIVA_CAPI if(j==MAX_CIP_TYPES) /* all groups are in use but group still not found */ { /* the MAX_CIP_TYPES group enables all calls because of field overflow */ appl_number_group_type[i] = MAX_CIP_TYPES; - group_found=TRUE; + group_found=true; dbug(1,dprintf("Field overflow appl 0x%x",i+1)); } else if( (info_mask_group[j]==a->CIP_Mask[i]) && (cip_mask_group[j]==a->Info_Mask[i]) ) { /* is group already present ? */ appl_number_group_type[i] = j|0x80; /* store the group number for each application */ - group_found=TRUE; + group_found=true; dbug(1,dprintf("Group 0x%x found with appl 0x%x, CIP=0x%lx",appl_number_group_type[i],i+1,info_mask_group[j])); } else if(!info_mask_group[j]) @@ -14805,7 +14804,7 @@ static void group_optimization(DIVA_CAPI appl_number_group_type[i] = j|0x80; /* store the group number for each application */ info_mask_group[j] = a->CIP_Mask[i]; /* store the new CIP mask for the new group */ cip_mask_group[j] = a->Info_Mask[i]; /* store the new Info_Mask for this new group */ - group_found=TRUE; + group_found=true; dbug(1,dprintf("New Group 0x%x established with appl 0x%x, CIP=0x%lx",appl_number_group_type[i],i+1,info_mask_group[j])); } } @@ -14860,7 +14859,7 @@ word CapiRegister(word id) } } - if(appls_found) return TRUE; + if(appls_found) return true; for(i=0; iInitialized = TRUE; + IoAdapter->Initialized = true; /* Check Interrupt @@ -504,7 +504,7 @@ diva_pri_start_adapter(PISDN_ADAPTER IoA if (!IoAdapter->IrqCount) { DBG_ERR(("A: A(%d) interrupt test failed", IoAdapter->ANum)) - IoAdapter->Initialized = FALSE; + IoAdapter->Initialized = false; IoAdapter->stop(IoAdapter); return (-1); } diff --git a/drivers/isdn/hardware/eicon/platform.h b/drivers/isdn/hardware/eicon/platform.h index 2444811..ff09f07 100644 --- a/drivers/isdn/hardware/eicon/platform.h +++ b/drivers/isdn/hardware/eicon/platform.h @@ -71,14 +71,6 @@ #ifndef qword #define qword u64 #endif -#ifndef TRUE -#define TRUE 1 -#endif - -#ifndef FALSE -#define FALSE 0 -#endif - #ifndef NULL #define NULL ((void *) 0) #endif @@ -131,10 +123,6 @@ #define DIVA_OS_MEM_DETACH_ADDRESS(a, x) #define DIVA_OS_MEM_DETACH_CONFIG(a, x) do { } while(0) #define DIVA_OS_MEM_DETACH_CONTROL(a, x) do { } while(0) -#if !defined(DIM) -#define DIM(array) (sizeof (array)/sizeof ((array)[0])) -#endif - #define DIVA_INVALID_FILE_HANDLE ((dword)(-1)) #define DIVAS_CONTAINING_RECORD(address, type, field) \ diff --git a/drivers/isdn/hisax/Kconfig b/drivers/isdn/hisax/Kconfig index 34ab5f7..12d91fb 100644 --- a/drivers/isdn/hisax/Kconfig +++ b/drivers/isdn/hisax/Kconfig @@ -340,8 +340,6 @@ config HISAX_HFC_SX This enables HiSax support for the HFC-S+, HFC-SP and HFC-PCMCIA cards. This code is not finished yet. -# bool ' TESTEMULATOR (EXPERIMENTAL)' CONFIG_HISAX_TESTEMU - config HISAX_ENTERNOW_PCI bool "Formula-n enter:now PCI card" depends on HISAX_NETJET && PCI && (BROKEN || !(SPARC || PPC || PARISC || M68K || (MIPS && !CPU_LITTLE_ENDIAN) || FRV)) diff --git a/drivers/isdn/hisax/Makefile b/drivers/isdn/hisax/Makefile index 293e277..c7a3794 100644 --- a/drivers/isdn/hisax/Makefile +++ b/drivers/isdn/hisax/Makefile @@ -60,5 +60,4 @@ hisax-$(CONFIG_HISAX_SCT_QUADRO) += bkm_ hisax-$(CONFIG_HISAX_GAZEL) += gazel.o isac.o arcofi.o hscx.o hisax-$(CONFIG_HISAX_W6692) += w6692.o hisax-$(CONFIG_HISAX_ENTERNOW_PCI) += enternow_pci.o amd7930_fn.o -#hisax-$(CONFIG_HISAX_TESTEMU) += testemu.o diff --git a/drivers/isdn/hisax/avma1_cs.c b/drivers/isdn/hisax/avma1_cs.c index 9e70c20..fc6cc2c 100644 --- a/drivers/isdn/hisax/avma1_cs.c +++ b/drivers/isdn/hisax/avma1_cs.c @@ -14,7 +14,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/isdn/hisax/config.c b/drivers/isdn/hisax/config.c index 17ec0b7..da4196f 100644 --- a/drivers/isdn/hisax/config.c +++ b/drivers/isdn/hisax/config.c @@ -549,10 +549,6 @@ #if CARD_HSTSAPHIR extern int setup_saphir(struct IsdnCard *card); #endif -#if CARD_TESTEMU -extern int setup_testemu(struct IsdnCard *card); -#endif - #if CARD_BKM_A4T extern int setup_bkm_a4t(struct IsdnCard *card); #endif @@ -1061,11 +1057,6 @@ #if CARD_HSTSAPHIR ret = setup_saphir(card); break; #endif -#if CARD_TESTEMU - case ISDN_CTYPE_TESTEMU: - ret = setup_testemu(card); - break; -#endif #if CARD_BKM_A4T case ISDN_CTYPE_BKM_A4T: ret = setup_bkm_a4t(card); @@ -1881,7 +1872,7 @@ #ifdef CONFIG_HISAX_GAZEL {PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_DJINN_ITOO, PCI_ANY_ID, PCI_ANY_ID}, {PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_OLITEC, PCI_ANY_ID, PCI_ANY_ID}, #endif -#ifdef CONFIG_HISAX_QUADRO +#ifdef CONFIG_HISAX_SCT_QUADRO {PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_9050, PCI_ANY_ID, PCI_ANY_ID}, #endif #ifdef CONFIG_HISAX_NICCY diff --git a/drivers/isdn/hisax/elsa_cs.c b/drivers/isdn/hisax/elsa_cs.c index 79ab9dd..db7e644 100644 --- a/drivers/isdn/hisax/elsa_cs.c +++ b/drivers/isdn/hisax/elsa_cs.c @@ -38,7 +38,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/isdn/hisax/elsa_ser.c b/drivers/isdn/hisax/elsa_ser.c index 0279fb3..ae377e8 100644 --- a/drivers/isdn/hisax/elsa_ser.c +++ b/drivers/isdn/hisax/elsa_ser.c @@ -58,7 +58,7 @@ #endif static inline unsigned int serial_inp(struct IsdnCardState *cs, int offset) { #ifdef SERIAL_DEBUG_REG -#ifdef CONFIG_SERIAL_NOPAUSE_IO +#ifdef ELSA_SERIAL_NOPAUSE_IO u_int val = inb(cs->hw.elsa.base + 8 + offset); debugl1(cs,"inp %s %02x",ModemIn[offset], val); #else @@ -67,7 +67,7 @@ #else #endif return(val); #else -#ifdef CONFIG_SERIAL_NOPAUSE_IO +#ifdef ELSA_SERIAL_NOPAUSE_IO return inb(cs->hw.elsa.base + 8 + offset); #else return inb_p(cs->hw.elsa.base + 8 + offset); @@ -87,13 +87,13 @@ static inline void serial_outp(struct Is int value) { #ifdef SERIAL_DEBUG_REG -#ifdef CONFIG_SERIAL_NOPAUSE_IO +#ifdef ELSA_SERIAL_NOPAUSE_IO debugl1(cs,"outp %s %02x",ModemOut[offset], value); #else debugl1(cs,"outP %s %02x",ModemOut[offset], value); #endif #endif -#ifdef CONFIG_SERIAL_NOPAUSE_IO +#ifdef ELSA_SERIAL_NOPAUSE_IO outb(value, cs->hw.elsa.base + 8 + offset); #else outb_p(value, cs->hw.elsa.base + 8 + offset); diff --git a/drivers/isdn/hisax/hfc4s8s_l1.c b/drivers/isdn/hisax/hfc4s8s_l1.c index a2fa4ec..ab98e13 100644 --- a/drivers/isdn/hisax/hfc4s8s_l1.c +++ b/drivers/isdn/hisax/hfc4s8s_l1.c @@ -199,7 +199,7 @@ typedef struct _hfc4s8s_hw { /***************************/ /* inline function defines */ /***************************/ -#ifdef CONFIG_HISAX_HFC4S8S_PCIMEM /* inline functions mempry mapped */ +#ifdef HISAX_HFC4S8S_PCIMEM /* inline functions memory mapped */ /* memory write and dummy IO read to avoid PCI byte merge problems */ #define Write_hfc8(a,b,c) {(*((volatile u_char *)(a->membase+b)) = c); inb(a->iobase+4);} @@ -305,7 +305,7 @@ wait_busy(hfc4s8s_hw * a) #define PCI_ENA_REGIO 0x01 -#endif /* CONFIG_HISAX_HFC4S8S_PCIMEM */ +#endif /* HISAX_HFC4S8S_PCIMEM */ /******************************************************/ /* function to read critical counter registers that */ @@ -724,12 +724,12 @@ rx_d_frame(struct hfc4s8s_l1 *l1p, int e } else { /* read errornous D frame */ -#ifndef CONFIG_HISAX_HFC4S8S_PCIMEM +#ifndef HISAX_HFC4S8S_PCIMEM SetRegAddr(l1p->hw, A_FIFO_DATA0); #endif while (z1 >= 4) { -#ifdef CONFIG_HISAX_HFC4S8S_PCIMEM +#ifdef HISAX_HFC4S8S_PCIMEM Read_hfc32(l1p->hw, A_FIFO_DATA0); #else fRead_hfc32(l1p->hw); @@ -738,7 +738,7 @@ #endif } while (z1--) -#ifdef CONFIG_HISAX_HFC4S8S_PCIMEM +#ifdef HISAX_HFC4S8S_PCIMEM Read_hfc8(l1p->hw, A_FIFO_DATA0); #else fRead_hfc8(l1p->hw); @@ -752,12 +752,12 @@ #endif cp = skb->data; -#ifndef CONFIG_HISAX_HFC4S8S_PCIMEM +#ifndef HISAX_HFC4S8S_PCIMEM SetRegAddr(l1p->hw, A_FIFO_DATA0); #endif while (z1 >= 4) { -#ifdef CONFIG_HISAX_HFC4S8S_PCIMEM +#ifdef HISAX_HFC4S8S_PCIMEM *((unsigned long *) cp) = Read_hfc32(l1p->hw, A_FIFO_DATA0); #else @@ -768,7 +768,7 @@ #endif } while (z1--) -#ifdef CONFIG_HISAX_HFC4S8S_PCIMEM +#ifdef HISAX_HFC4S8S_PCIMEM *cp++ = Read_hfc8(l1p->hw, A_FIFO_DATA0); #else *cp++ = fRead_hfc8(l1p->hw); @@ -858,12 +858,12 @@ rx_b_frame(struct hfc4s8s_btype *bch) wait_busy(l1->hw); return; } -#ifndef CONFIG_HISAX_HFC4S8S_PCIMEM +#ifndef HISAX_HFC4S8S_PCIMEM SetRegAddr(l1->hw, A_FIFO_DATA0); #endif while (z1 >= 4) { -#ifdef CONFIG_HISAX_HFC4S8S_PCIMEM +#ifdef HISAX_HFC4S8S_PCIMEM *((unsigned long *) bch->rx_ptr) = Read_hfc32(l1->hw, A_FIFO_DATA0); #else @@ -875,7 +875,7 @@ #endif } while (z1--) -#ifdef CONFIG_HISAX_HFC4S8S_PCIMEM +#ifdef HISAX_HFC4S8S_PCIMEM *(bch->rx_ptr++) = Read_hfc8(l1->hw, A_FIFO_DATA0); #else *(bch->rx_ptr++) = fRead_hfc8(l1->hw); @@ -939,12 +939,12 @@ tx_d_frame(struct hfc4s8s_l1 *l1p) if ((skb = skb_dequeue(&l1p->d_tx_queue))) { cp = skb->data; cnt = skb->len; -#ifndef CONFIG_HISAX_HFC4S8S_PCIMEM +#ifndef HISAX_HFC4S8S_PCIMEM SetRegAddr(l1p->hw, A_FIFO_DATA0); #endif while (cnt >= 4) { -#ifdef CONFIG_HISAX_HFC4S8S_PCIMEM +#ifdef HISAX_HFC4S8S_PCIMEM fWrite_hfc32(l1p->hw, A_FIFO_DATA0, *(unsigned long *) cp); #else @@ -955,7 +955,7 @@ #endif cnt -= 4; } -#ifdef CONFIG_HISAX_HFC4S8S_PCIMEM +#ifdef HISAX_HFC4S8S_PCIMEM while (cnt--) fWrite_hfc8(l1p->hw, A_FIFO_DATA0, *cp++); #else @@ -1036,11 +1036,11 @@ tx_b_frame(struct hfc4s8s_btype *bch) cp = skb->data + bch->tx_cnt; bch->tx_cnt += cnt; -#ifndef CONFIG_HISAX_HFC4S8S_PCIMEM +#ifndef HISAX_HFC4S8S_PCIMEM SetRegAddr(l1->hw, A_FIFO_DATA0); #endif while (cnt >= 4) { -#ifdef CONFIG_HISAX_HFC4S8S_PCIMEM +#ifdef HISAX_HFC4S8S_PCIMEM fWrite_hfc32(l1->hw, A_FIFO_DATA0, *(unsigned long *) cp); #else @@ -1051,7 +1051,7 @@ #endif } while (cnt--) -#ifdef CONFIG_HISAX_HFC4S8S_PCIMEM +#ifdef HISAX_HFC4S8S_PCIMEM fWrite_hfc8(l1->hw, A_FIFO_DATA0, *cp++); #else fWrite_hfc8(l1->hw, *cp++); @@ -1280,7 +1280,7 @@ hfc4s8s_interrupt(int intno, void *dev_i if (!hw || !(hw->mr.r_irq_ctrl & M_GLOB_IRQ_EN)) return IRQ_NONE; -#ifndef CONFIG_HISAX_HFC4S8S_PCIMEM +#ifndef HISAX_HFC4S8S_PCIMEM /* read current selected regsister */ old_ioreg = GetRegAddr(hw); #endif @@ -1291,7 +1291,7 @@ #endif if (! (b = (Read_hfc8(hw, R_STATUS) & (M_MISC_IRQSTA | M_FR_IRQSTA))) && !hw->mr.r_irq_statech) { -#ifndef CONFIG_HISAX_HFC4S8S_PCIMEM +#ifndef HISAX_HFC4S8S_PCIMEM SetRegAddr(hw, old_ioreg); #endif return IRQ_NONE; @@ -1321,7 +1321,7 @@ #endif /* queue the request to allow other cards to interrupt */ schedule_work(&hw->tqueue); -#ifndef CONFIG_HISAX_HFC4S8S_PCIMEM +#ifndef HISAX_HFC4S8S_PCIMEM SetRegAddr(hw, old_ioreg); #endif return IRQ_HANDLED; @@ -1470,7 +1470,7 @@ static void release_pci_ports(hfc4s8s_hw * hw) { pci_write_config_word(hw->pdev, PCI_COMMAND, 0); -#ifdef CONFIG_HISAX_HFC4S8S_PCIMEM +#ifdef HISAX_HFC4S8S_PCIMEM if (hw->membase) iounmap((void *) hw->membase); #else @@ -1485,7 +1485,7 @@ #endif static void enable_pci_ports(hfc4s8s_hw * hw) { -#ifdef CONFIG_HISAX_HFC4S8S_PCIMEM +#ifdef HISAX_HFC4S8S_PCIMEM pci_write_config_word(hw->pdev, PCI_COMMAND, PCI_ENA_MEMIO); #else pci_write_config_word(hw->pdev, PCI_COMMAND, PCI_ENA_REGIO); @@ -1560,7 +1560,7 @@ setup_instance(hfc4s8s_hw * hw) hw->irq); goto out; } -#ifdef CONFIG_HISAX_HFC4S8S_PCIMEM +#ifdef HISAX_HFC4S8S_PCIMEM printk(KERN_INFO "HFC-4S/8S: found PCI card at membase 0x%p, irq %d\n", hw->hw_membase, hw->irq); @@ -1613,7 +1613,7 @@ hfc4s8s_probe(struct pci_dev *pdev, cons hw->irq = pdev->irq; hw->iobase = pci_resource_start(pdev, 0); -#ifdef CONFIG_HISAX_HFC4S8S_PCIMEM +#ifdef HISAX_HFC4S8S_PCIMEM hw->hw_membase = (u_char *) pci_resource_start(pdev, 1); hw->membase = ioremap((ulong) hw->hw_membase, 256); #else diff --git a/drivers/isdn/hisax/hfc_usb.c b/drivers/isdn/hisax/hfc_usb.c index 5a6989f..9f44d3e 100644 --- a/drivers/isdn/hisax/hfc_usb.c +++ b/drivers/isdn/hisax/hfc_usb.c @@ -38,7 +38,6 @@ #include #include #include #include -#include #include "hisax.h" #include "hisax_if.h" #include "hfc_usb.h" @@ -183,7 +182,7 @@ typedef struct hfcusb_data { int vend_idx; /* vendor found */ int b_mode[2]; /* B-channel mode */ int l1_activated; /* layer 1 activated */ - int disc_flag; /* TRUE if device was disonnected to avoid some USB actions */ + int disc_flag; /* 'true' if device was disonnected to avoid some USB actions */ int packet_size, iso_packet_size; /* control pipe background handling */ @@ -392,7 +391,7 @@ #ifdef CONFIG_HISAX_DEBUG DBG(ISDN_DBG, "HFC-S USB: PH_DEACTIVATE | INDICATION sent (T3 expire)"); #endif - hfc->l1_activated = FALSE; + hfc->l1_activated = false; handle_led(hfc, LED_S0_OFF); /* deactivate : */ queue_control_request(hfc, HFCUSB_STATES, 0x10, 1); @@ -411,7 +410,7 @@ #ifdef CONFIG_HISAX_DEBUG DBG(ISDN_DBG, "HFC-S USB: PH_DEACTIVATE | INDICATION sent (T4 expire)"); #endif - hfc->l1_activated = FALSE; + hfc->l1_activated = false; handle_led(hfc, LED_S0_OFF); } @@ -452,7 +451,7 @@ #endif #ifdef CONFIG_HISAX_DEBUG DBG(ISDN_DBG, "HFC-S USB: PH_ACTIVATE | INDICATION sent"); #endif - hfc->l1_activated = TRUE; + hfc->l1_activated = true; handle_led(hfc, LED_S0_ON); } else if (state <= 3 /* && activated */ ) { if (old_state == 7 || old_state == 8) { @@ -472,7 +471,7 @@ #ifdef CONFIG_HISAX_DEBUG DBG(ISDN_DBG, "HFC-S USB: PH_DEACTIVATE | INDICATION sent"); #endif - hfc->l1_activated = FALSE; + hfc->l1_activated = false; handle_led(hfc, LED_S0_OFF); } } @@ -622,7 +621,7 @@ tx_iso_complete(struct urb *urb) if (fifo->active && !status) { transp_mode = 0; if (fifon < 4 && hfc->b_mode[fifon / 2] == L1_MODE_TRANS) - transp_mode = TRUE; + transp_mode = true; /* is FifoFull-threshold set for our channel? */ threshbit = threshtable[fifon] & hfc->threshold_mask; @@ -640,7 +639,7 @@ tx_iso_complete(struct urb *urb) tx_iso_complete, urb->context); memset(context_iso_urb->buffer, 0, sizeof(context_iso_urb->buffer)); - frame_complete = FALSE; + frame_complete = false; /* Generate next Iso Packets */ for (k = 0; k < num_isoc_packets; ++k) { if (fifo->skbuff) { @@ -666,7 +665,7 @@ tx_iso_complete(struct urb *urb) /* add 2 byte flags and 16bit CRC at end of ISDN frame */ fifo->bit_line += 32; } - frame_complete = TRUE; + frame_complete = true; } memcpy(context_iso_urb->buffer + @@ -693,7 +692,7 @@ tx_iso_complete(struct urb *urb) } if (frame_complete) { - fifo->delete_flg = TRUE; + fifo->delete_flg = true; fifo->hif->l1l2(fifo->hif, PH_DATA | CONFIRM, (void *) (unsigned long) fifo->skbuff-> @@ -701,9 +700,9 @@ tx_iso_complete(struct urb *urb) if (fifo->skbuff && fifo->delete_flg) { dev_kfree_skb_any(fifo->skbuff); fifo->skbuff = NULL; - fifo->delete_flg = FALSE; + fifo->delete_flg = false; } - frame_complete = FALSE; + frame_complete = false; } } errcode = usb_submit_urb(urb, GFP_ATOMIC); @@ -837,7 +836,7 @@ #endif fifon = fifo->fifonum; transp_mode = 0; if (fifon < 4 && hfc->b_mode[fifon / 2] == L1_MODE_TRANS) - transp_mode = TRUE; + transp_mode = true; if (!fifo->skbuff) { fifo->skbuff = dev_alloc_skb(fifo->max_size + 3); @@ -1176,7 +1175,7 @@ #endif if (fifo->skbuff && fifo->delete_flg) { dev_kfree_skb_any(fifo->skbuff); fifo->skbuff = NULL; - fifo->delete_flg = FALSE; + fifo->delete_flg = false; } fifo->skbuff = arg; /* we have a new buffer */ break; @@ -1262,8 +1261,8 @@ usb_init(hfcusb_data * hfc) hfc->b_mode[0] = L1_MODE_NULL; hfc->b_mode[1] = L1_MODE_NULL; - hfc->l1_activated = FALSE; - hfc->disc_flag = FALSE; + hfc->l1_activated = false; + hfc->disc_flag = false; hfc->led_state = 0; hfc->led_new_data = 0; hfc->old_led_state = 0; @@ -1404,7 +1403,7 @@ #endif /* check for config EOL element */ while (validconf[cfg_used][0]) { - cfg_found = TRUE; + cfg_found = true; vcf = validconf[cfg_used]; /* first endpoint descriptor */ ep = iface->endpoint; @@ -1426,7 +1425,7 @@ #endif idx++; attr = ep->desc.bmAttributes; if (cmptbl[idx] == EP_NUL) { - cfg_found = FALSE; + cfg_found = false; } if (attr == USB_ENDPOINT_XFER_INT && cmptbl[idx] == EP_INT) @@ -1448,7 +1447,7 @@ #ifdef CONFIG_HISAX_DEBUG "HFC-S USB: Interrupt Endpoint interval < %d found - skipping config", vcf[17]); #endif - cfg_found = FALSE; + cfg_found = false; } ep++; } @@ -1456,7 +1455,7 @@ #endif /* all entries must be EP_NOP or EP_NUL for a valid config */ if (cmptbl[i] != EP_NOP && cmptbl[i] != EP_NUL) - cfg_found = FALSE; + cfg_found = false; } if (cfg_found) { if (cfg_used < small_match) { @@ -1656,7 +1655,7 @@ hfc_usb_disconnect(struct usb_interface hfcusb_data *context = usb_get_intfdata(intf); int i; printk(KERN_INFO "HFC-S USB: device disconnect\n"); - context->disc_flag = TRUE; + context->disc_flag = true; usb_set_intfdata(intf, NULL); if (!context) return; diff --git a/drivers/isdn/hisax/hfc_usb.h b/drivers/isdn/hisax/hfc_usb.h index 6349367..471f235 100644 --- a/drivers/isdn/hisax/hfc_usb.h +++ b/drivers/isdn/hisax/hfc_usb.h @@ -12,9 +12,6 @@ #define DRIVER_DESC "HFC-S USB based #define VERBOSE_USB_DEBUG -#define TRUE 1 -#define FALSE 0 - /***********/ /* defines */ diff --git a/drivers/isdn/hisax/hisax.h b/drivers/isdn/hisax/hisax.h index 3f1137e..3cd8d5b 100644 --- a/drivers/isdn/hisax/hisax.h +++ b/drivers/isdn/hisax/hisax.h @@ -795,19 +795,6 @@ struct w6692_hw { struct timer_list timer; }; -#ifdef CONFIG_HISAX_TESTEMU -struct te_hw { - unsigned char *sfifo; - unsigned char *sfifo_w; - unsigned char *sfifo_r; - unsigned char *sfifo_e; - int sfifo_cnt; - unsigned int stat; - wait_queue_head_t rwaitq; - wait_queue_head_t swaitq; -}; -#endif - struct arcofi_msg { struct arcofi_msg *next; u_char receive; @@ -916,9 +903,6 @@ struct IsdnCardState { struct ix1_hw niccy; struct isurf_hw isurf; struct saphir_hw saphir; -#ifdef CONFIG_HISAX_TESTEMU - struct te_hw te; -#endif struct bkm_hw ax; struct gazel_hw gazel; struct w6692_hw w6692; @@ -1175,15 +1159,6 @@ #else #define CARD_HSTSAPHIR 0 #endif -#ifdef CONFIG_HISAX_TESTEMU -#define CARD_TESTEMU 1 -#define ISDN_CTYPE_TESTEMU 99 -#undef ISDN_CTYPE_COUNT -#define ISDN_CTYPE_COUNT ISDN_CTYPE_TESTEMU -#else -#define CARD_TESTEMU 0 -#endif - #ifdef CONFIG_HISAX_BKM_A4T #define CARD_BKM_A4T 1 #ifndef ISDN_CHIP_ISAC diff --git a/drivers/isdn/hisax/isar.c b/drivers/isdn/hisax/isar.c index 6f1a658..9df9e35 100644 --- a/drivers/isdn/hisax/isar.c +++ b/drivers/isdn/hisax/isar.c @@ -431,7 +431,6 @@ reterror: return(ret); } -extern void BChannel_bh(struct BCState *); #define B_LL_NOCARRIER 8 #define B_LL_CONNECT 9 #define B_LL_OK 10 diff --git a/drivers/isdn/hisax/isdnl1.h b/drivers/isdn/hisax/isdnl1.h index 0e88cfa..172ad4c 100644 --- a/drivers/isdn/hisax/isdnl1.h +++ b/drivers/isdn/hisax/isdnl1.h @@ -21,12 +21,11 @@ #define B_RCVBUFREADY 0 #define B_XMTBUFREADY 1 #define B_ACKPENDING 2 -extern void debugl1(struct IsdnCardState *cs, char *fmt, ...); -extern void DChannel_proc_xmt(struct IsdnCardState *cs); -extern void DChannel_proc_rcv(struct IsdnCardState *cs); -extern void l1_msg(struct IsdnCardState *cs, int pr, void *arg); -extern void l1_msg_b(struct PStack *st, int pr, void *arg); - -#ifdef L2FRAME_DEBUG -extern void Logl2Frame(struct IsdnCardState *cs, struct sk_buff *skb, char *buf, int dir); -#endif +void debugl1(struct IsdnCardState *cs, char *fmt, ...); +void DChannel_proc_xmt(struct IsdnCardState *cs); +void DChannel_proc_rcv(struct IsdnCardState *cs); +void l1_msg(struct IsdnCardState *cs, int pr, void *arg); +void l1_msg_b(struct PStack *st, int pr, void *arg); +void Logl2Frame(struct IsdnCardState *cs, struct sk_buff *skb, char *buf, + int dir); +void BChannel_bh(struct work_struct *work); diff --git a/drivers/isdn/hisax/isdnl3.c b/drivers/isdn/hisax/isdnl3.c index 281fa27..935f233 100644 --- a/drivers/isdn/hisax/isdnl3.c +++ b/drivers/isdn/hisax/isdnl3.c @@ -231,18 +231,6 @@ no_l3_proto_spec(struct PStack *st, isdn return(-1); } -#ifdef CONFIG_HISAX_EURO -extern void setstack_dss1(struct PStack *st); -#endif - -#ifdef CONFIG_HISAX_NI1 -extern void setstack_ni1(struct PStack *st); -#endif - -#ifdef CONFIG_HISAX_1TR6 -extern void setstack_1tr6(struct PStack *st); -#endif - struct l3_process *getl3proc(struct PStack *st, int cr) { diff --git a/drivers/isdn/hisax/isdnl3.h b/drivers/isdn/hisax/isdnl3.h index 1dbe029..749498f 100644 --- a/drivers/isdn/hisax/isdnl3.h +++ b/drivers/isdn/hisax/isdnl3.h @@ -25,13 +25,19 @@ struct stateentry { #define l3_debug(st, fmt, args...) HiSax_putstatus(st->l1.hardware, "l3 ", fmt, ## args) -extern void newl3state(struct l3_process *pc, int state); -extern void L3InitTimer(struct l3_process *pc, struct L3Timer *t); -extern void L3DelTimer(struct L3Timer *t); -extern int L3AddTimer(struct L3Timer *t, int millisec, int event); -extern void StopAllL3Timer(struct l3_process *pc); -extern struct sk_buff *l3_alloc_skb(int len); -extern struct l3_process *new_l3_process(struct PStack *st, int cr); -extern void release_l3_process(struct l3_process *p); -extern struct l3_process *getl3proc(struct PStack *st, int cr); -extern void l3_msg(struct PStack *st, int pr, void *arg); +struct PStack; + +void newl3state(struct l3_process *pc, int state); +void L3InitTimer(struct l3_process *pc, struct L3Timer *t); +void L3DelTimer(struct L3Timer *t); +int L3AddTimer(struct L3Timer *t, int millisec, int event); +void StopAllL3Timer(struct l3_process *pc); +struct sk_buff *l3_alloc_skb(int len); +struct l3_process *new_l3_process(struct PStack *st, int cr); +void release_l3_process(struct l3_process *p); +struct l3_process *getl3proc(struct PStack *st, int cr); +void l3_msg(struct PStack *st, int pr, void *arg); +void setstack_dss1(struct PStack *st); +void setstack_ni1(struct PStack *st); +void setstack_1tr6(struct PStack *st); + diff --git a/drivers/isdn/hisax/sedlbauer_cs.c b/drivers/isdn/hisax/sedlbauer_cs.c index 45debde..439cb53 100644 --- a/drivers/isdn/hisax/sedlbauer_cs.c +++ b/drivers/isdn/hisax/sedlbauer_cs.c @@ -38,7 +38,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/isdn/hisax/teles_cs.c b/drivers/isdn/hisax/teles_cs.c index 3e3e182..ab4bd45 100644 --- a/drivers/isdn/hisax/teles_cs.c +++ b/drivers/isdn/hisax/teles_cs.c @@ -19,7 +19,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/isdn/hysdn/boardergo.c b/drivers/isdn/hysdn/boardergo.c index a120649..84dccd5 100644 --- a/drivers/isdn/hysdn/boardergo.c +++ b/drivers/isdn/hysdn/boardergo.c @@ -14,7 +14,6 @@ * */ -#include #include #include #include diff --git a/drivers/isdn/hysdn/hysdn_procconf.c b/drivers/isdn/hysdn/hysdn_procconf.c index 94a9350..dc477e0 100644 --- a/drivers/isdn/hysdn/hysdn_procconf.c +++ b/drivers/isdn/hysdn/hysdn_procconf.c @@ -367,7 +367,7 @@ hysdn_conf_close(struct inode *ino, stru /******************************************************/ /* table for conf filesystem functions defined above. */ /******************************************************/ -static struct file_operations conf_fops = +static const struct file_operations conf_fops = { .llseek = no_llseek, .read = hysdn_conf_read, diff --git a/drivers/isdn/hysdn/hysdn_proclog.c b/drivers/isdn/hysdn/hysdn_proclog.c index 375d956..f7e83a8 100644 --- a/drivers/isdn/hysdn/hysdn_proclog.c +++ b/drivers/isdn/hysdn/hysdn_proclog.c @@ -383,7 +383,7 @@ hysdn_log_poll(struct file *file, poll_t /**************************************************/ /* table for log filesystem functions defined above. */ /**************************************************/ -static struct file_operations log_fops = +static const struct file_operations log_fops = { .llseek = no_llseek, .read = hysdn_log_read, diff --git a/drivers/isdn/hysdn/hysdn_sched.c b/drivers/isdn/hysdn/hysdn_sched.c index 1875877..b7b5aa4 100644 --- a/drivers/isdn/hysdn/hysdn_sched.c +++ b/drivers/isdn/hysdn/hysdn_sched.c @@ -11,7 +11,6 @@ * */ -#include #include #include #include diff --git a/drivers/isdn/i4l/isdn_bsdcomp.c b/drivers/isdn/i4l/isdn_bsdcomp.c index a20f33b..90a2379 100644 --- a/drivers/isdn/i4l/isdn_bsdcomp.c +++ b/drivers/isdn/i4l/isdn_bsdcomp.c @@ -56,7 +56,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/isdn/i4l/isdn_common.c b/drivers/isdn/i4l/isdn_common.c index 6a2ef0a..9c926e4 100644 --- a/drivers/isdn/i4l/isdn_common.c +++ b/drivers/isdn/i4l/isdn_common.c @@ -1822,7 +1822,7 @@ #endif return 0; } -static struct file_operations isdn_fops = +static const struct file_operations isdn_fops = { .owner = THIS_MODULE, .llseek = no_llseek, diff --git a/drivers/isdn/i4l/isdn_tty.c b/drivers/isdn/i4l/isdn_tty.c index fc80afe..ea5f30d 100644 --- a/drivers/isdn/i4l/isdn_tty.c +++ b/drivers/isdn/i4l/isdn_tty.c @@ -1261,7 +1261,6 @@ isdn_tty_flush_buffer(struct tty_struct } isdn_tty_cleanup_xmit(info); info->xmit_count = 0; - wake_up_interruptible(&tty->write_wait); tty_wakeup(tty); } diff --git a/drivers/isdn/pcbit/callbacks.c b/drivers/isdn/pcbit/callbacks.c index f151f36..43ecd0f 100644 --- a/drivers/isdn/pcbit/callbacks.c +++ b/drivers/isdn/pcbit/callbacks.c @@ -15,7 +15,6 @@ * NULL pointer dereference in cb_in_1 (originally fixed in 2.0) */ -#include #include #include diff --git a/drivers/isdn/pcbit/capi.c b/drivers/isdn/pcbit/capi.c index bef321d..47c59e9 100644 --- a/drivers/isdn/pcbit/capi.c +++ b/drivers/isdn/pcbit/capi.c @@ -27,7 +27,6 @@ * encode our number in CallerPN and ConnectedPN */ -#include #include #include diff --git a/drivers/isdn/pcbit/drv.c b/drivers/isdn/pcbit/drv.c index 11c1b0b..8c66bcb 100644 --- a/drivers/isdn/pcbit/drv.c +++ b/drivers/isdn/pcbit/drv.c @@ -19,7 +19,6 @@ #include -#include #include @@ -774,10 +773,6 @@ static void pcbit_logstat(struct pcbit_d dev->dev_if->statcallb(&ictl); } -extern char * isdn_state_table[]; -extern char * strisdnevent(unsigned short); - - void pcbit_state_change(struct pcbit_dev * dev, struct pcbit_chan * chan, unsigned short i, unsigned short ev, unsigned short f) { diff --git a/drivers/isdn/pcbit/edss1.c b/drivers/isdn/pcbit/edss1.c index 93ca7de..37e9626 100644 --- a/drivers/isdn/pcbit/edss1.c +++ b/drivers/isdn/pcbit/edss1.c @@ -15,7 +15,6 @@ * move state/event descriptions to a user space logger */ -#include #include #include @@ -35,12 +34,6 @@ #include "layer2.h" #include "callbacks.h" -extern void pcbit_state_change(struct pcbit_dev *, struct pcbit_chan *, - unsigned short i, unsigned short ev, - unsigned short f); - -extern struct pcbit_dev * dev_pcbit[MAX_PCBIT_CARDS]; - char * isdn_state_table[] = { "Closed", "Call initiated", diff --git a/drivers/isdn/pcbit/edss1.h b/drivers/isdn/pcbit/edss1.h index 6bb5870..0b64f97 100644 --- a/drivers/isdn/pcbit/edss1.h +++ b/drivers/isdn/pcbit/edss1.h @@ -90,9 +90,12 @@ struct fsm_timer_entry { unsigned long timeout; /* in seconds */ }; +extern char * isdn_state_table[]; + +void pcbit_fsm_event(struct pcbit_dev *, struct pcbit_chan *, + unsigned short event, struct callb_data *); +char * strisdnevent(ushort ev); -extern void pcbit_fsm_event(struct pcbit_dev *, struct pcbit_chan *, - unsigned short event, struct callb_data *); #endif diff --git a/drivers/isdn/pcbit/layer2.c b/drivers/isdn/pcbit/layer2.c index eafcce5..5ba2a87 100644 --- a/drivers/isdn/pcbit/layer2.c +++ b/drivers/isdn/pcbit/layer2.c @@ -24,7 +24,6 @@ * re-write/remove debug printks */ -#include #include #include #include @@ -47,22 +46,6 @@ #include "edss1.h" #undef DEBUG_FRAG - -/* - * task queue struct - */ - - - -/* - * Layer 3 packet demultiplexer - * drv.c - */ - -extern void pcbit_l3_receive(struct pcbit_dev *dev, ulong msg, - struct sk_buff *skb, - ushort hdr_len, ushort refnum); - /* * Prototypes */ diff --git a/drivers/isdn/pcbit/module.c b/drivers/isdn/pcbit/module.c index 282073a..04ea241 100644 --- a/drivers/isdn/pcbit/module.c +++ b/drivers/isdn/pcbit/module.c @@ -11,7 +11,6 @@ #include #include -#include #include #include #include @@ -32,9 +31,6 @@ module_param_array(irq, int, NULL, 0); static int num_boards; struct pcbit_dev * dev_pcbit[MAX_PCBIT_CARDS]; -extern void pcbit_terminate(int board); -extern int pcbit_init_dev(int board, int mem_base, int irq); - static int __init pcbit_init(void) { int board; diff --git a/drivers/isdn/pcbit/pcbit.h b/drivers/isdn/pcbit/pcbit.h index 19c18e8..d76fffc 100644 --- a/drivers/isdn/pcbit/pcbit.h +++ b/drivers/isdn/pcbit/pcbit.h @@ -166,6 +166,12 @@ #define L2_STARTING 4 #define L2_RUNNING 5 #define L2_ERROR 6 -extern void pcbit_deliver(struct work_struct *work); +void pcbit_deliver(struct work_struct *work); +int pcbit_init_dev(int board, int mem_base, int irq); +void pcbit_terminate(int board); +void pcbit_l3_receive(struct pcbit_dev * dev, ulong msg, struct sk_buff * skb, + ushort hdr_len, ushort refnum); +void pcbit_state_change(struct pcbit_dev * dev, struct pcbit_chan * chan, + unsigned short i, unsigned short ev, unsigned short f); #endif diff --git a/drivers/isdn/sc/card.h b/drivers/isdn/sc/card.h index 8e44928..4fbfa82 100644 --- a/drivers/isdn/sc/card.h +++ b/drivers/isdn/sc/card.h @@ -26,7 +26,9 @@ #define CARD_H #include #include #include +#include #include "message.h" +#include "scioc.h" /* * Amount of time to wait for a reset to complete @@ -98,4 +100,32 @@ typedef struct { spinlock_t lock; /* local lock */ } board; + +extern board *sc_adapter[]; +extern int cinst; + +void memcpy_toshmem(int card, void *dest, const void *src, size_t n); +void memcpy_fromshmem(int card, void *dest, const void *src, size_t n); +int get_card_from_id(int driver); +int indicate_status(int card, int event, ulong Channel, char *Data); +irqreturn_t interrupt_handler(int interrupt, void *cardptr); +int sndpkt(int devId, int channel, struct sk_buff *data); +void rcvpkt(int card, RspMessage *rcvmsg); +int command(isdn_ctrl *cmd); +int reset(int card); +int startproc(int card); +int send_and_receive(int card, unsigned int procid, unsigned char type, + unsigned char class, unsigned char code, + unsigned char link, unsigned char data_len, + unsigned char *data, RspMessage *mesgdata, int timeout); +void flushreadfifo (int card); +int sendmessage(int card, unsigned int procid, unsigned int type, + unsigned int class, unsigned int code, unsigned int link, + unsigned int data_len, unsigned int *data); +int receivemessage(int card, RspMessage *rspmsg); +int sc_ioctl(int card, scs_ioctl *data); +int setup_buffers(int card, int c); +void check_reset(unsigned long data); +void check_phystat(unsigned long data); + #endif /* CARD_H */ diff --git a/drivers/isdn/sc/command.c b/drivers/isdn/sc/command.c index 04b8a58..b7bb7cb 100644 --- a/drivers/isdn/sc/command.c +++ b/drivers/isdn/sc/command.c @@ -31,19 +31,6 @@ static int setl2(int card, unsigned long static int setl3(int card, unsigned long arg); static int acceptb(int card, unsigned long channel); -extern int cinst; -extern board *sc_adapter[]; - -extern int sc_ioctl(int, scs_ioctl *); -extern int setup_buffers(int, int, unsigned int); -extern int indicate_status(int, int,ulong,char*); -extern void check_reset(unsigned long); -extern int send_and_receive(int, unsigned int, unsigned char, unsigned char, - unsigned char, unsigned char, unsigned char, unsigned char *, - RspMessage *, int); -extern int sendmessage(int, unsigned int, unsigned int, unsigned int, - unsigned int, unsigned int, unsigned int, unsigned int *); - #ifdef DEBUG /* * Translate command codes to strings @@ -208,7 +195,7 @@ static int answer(int card, unsigned lon return -ENODEV; } - if(setup_buffers(card, channel+1, BUFFER_SIZE)) { + if(setup_buffers(card, channel+1)) { hangup(card, channel+1); return -ENOBUFS; } @@ -297,7 +284,7 @@ static int acceptb(int card, unsigned lo return -ENODEV; } - if(setup_buffers(card, channel+1, BUFFER_SIZE)) + if(setup_buffers(card, channel+1)) { hangup(card, channel+1); return -ENOBUFS; diff --git a/drivers/isdn/sc/event.c b/drivers/isdn/sc/event.c index 5736732..498f403 100644 --- a/drivers/isdn/sc/event.c +++ b/drivers/isdn/sc/event.c @@ -20,9 +20,6 @@ #include "hardware.h" #include "message.h" #include "card.h" -extern int cinst; -extern board *sc_adapter[]; - #ifdef DEBUG static char *events[] = { "ISDN_STAT_STAVAIL", "ISDN_STAT_ICALL", diff --git a/drivers/isdn/sc/init.c b/drivers/isdn/sc/init.c index 150759a..0bf7634 100644 --- a/drivers/isdn/sc/init.c +++ b/drivers/isdn/sc/init.c @@ -35,12 +35,6 @@ module_param_array(irq, int, NULL, 0); module_param_array(ram, int, NULL, 0); module_param(do_reset, bool, 0); -extern irqreturn_t interrupt_handler(int, void *); -extern int sndpkt(int, int, int, struct sk_buff *); -extern int command(isdn_ctrl *); -extern int indicate_status(int, int, ulong, char*); -extern int reset(int); - static int identify_board(unsigned long, unsigned int); static int __init sc_init(void) diff --git a/drivers/isdn/sc/interrupt.c b/drivers/isdn/sc/interrupt.c index cd17de1..bef7963 100644 --- a/drivers/isdn/sc/interrupt.c +++ b/drivers/isdn/sc/interrupt.c @@ -21,16 +21,6 @@ #include "message.h" #include "card.h" #include -extern int indicate_status(int, int, ulong, char *); -extern void check_phystat(unsigned long); -extern int receivemessage(int, RspMessage *); -extern int sendmessage(int, unsigned int, unsigned int, unsigned int, - unsigned int, unsigned int, unsigned int, unsigned int *); -extern void rcvpkt(int, RspMessage *); - -extern int cinst; -extern board *sc_adapter[]; - static int get_card_from_irq(int irq) { int i; diff --git a/drivers/isdn/sc/ioctl.c b/drivers/isdn/sc/ioctl.c index 57c4ab9..7817d22 100644 --- a/drivers/isdn/sc/ioctl.c +++ b/drivers/isdn/sc/ioctl.c @@ -12,16 +12,6 @@ #include "message.h" #include "card.h" #include "scioc.h" -extern int indicate_status(int, int, unsigned long, char *); -extern int startproc(int); -extern int reset(int); -extern int send_and_receive(int, unsigned int, unsigned char,unsigned char, - unsigned char,unsigned char, - unsigned char, unsigned char *, RspMessage *, int); - -extern board *sc_adapter[]; - - static int GetStatus(int card, boardInfo *); /* diff --git a/drivers/isdn/sc/message.c b/drivers/isdn/sc/message.c index 0a0fe6b..c5a307e 100644 --- a/drivers/isdn/sc/message.c +++ b/drivers/isdn/sc/message.c @@ -22,16 +22,6 @@ #include "hardware.h" #include "message.h" #include "card.h" -extern board *sc_adapter[]; -extern unsigned int cinst; - -/* - * Obligatory function prototypes - */ -extern int indicate_status(int,ulong,char*); -extern int scm_command(isdn_ctrl *); - - /* * receive a message from the board */ diff --git a/drivers/isdn/sc/packet.c b/drivers/isdn/sc/packet.c index 1e04676..92016a2 100644 --- a/drivers/isdn/sc/packet.c +++ b/drivers/isdn/sc/packet.c @@ -20,16 +20,6 @@ #include "hardware.h" #include "message.h" #include "card.h" -extern board *sc_adapter[]; -extern unsigned int cinst; - -extern int get_card_from_id(int); -extern int indicate_status(int, int,ulong, char*); -extern void memcpy_toshmem(int, void *, const void *, size_t); -extern void memcpy_fromshmem(int, void *, const void *, size_t); -extern int sendmessage(int, unsigned int, unsigned int, unsigned int, - unsigned int, unsigned int, unsigned int, unsigned int *); - int sndpkt(int devId, int channel, struct sk_buff *data) { LLData ReqLnkWrite; diff --git a/drivers/isdn/sc/scioc.h b/drivers/isdn/sc/scioc.h index d08e650..dfb107a 100644 --- a/drivers/isdn/sc/scioc.h +++ b/drivers/isdn/sc/scioc.h @@ -1,3 +1,6 @@ +#ifndef __ISDN_SC_SCIOC_H__ +#define __ISDN_SC_SCIOC_H__ + /* * This software may be used and distributed according to the terms * of the GNU General Public License, incorporated herein by reference. @@ -103,3 +106,6 @@ typedef struct { POTInfo potsinfo; } info; } boardInfo; + +#endif /* __ISDN_SC_SCIOC_H__ */ + diff --git a/drivers/isdn/sc/shmem.c b/drivers/isdn/sc/shmem.c index 6f58862..034d41a 100644 --- a/drivers/isdn/sc/shmem.c +++ b/drivers/isdn/sc/shmem.c @@ -22,12 +22,6 @@ #include "hardware.h" #include "card.h" /* - * Main adapter array - */ -extern board *sc_adapter[]; -extern int cinst; - -/* * */ void memcpy_toshmem(int card, void *dest, const void *src, size_t n) diff --git a/drivers/isdn/sc/timer.c b/drivers/isdn/sc/timer.c index f43282b..cc1b886 100644 --- a/drivers/isdn/sc/timer.c +++ b/drivers/isdn/sc/timer.c @@ -20,14 +20,6 @@ #include "hardware.h" #include "message.h" #include "card.h" -extern board *sc_adapter[]; - -extern void flushreadfifo(int); -extern int startproc(int); -extern int indicate_status(int, int, unsigned long, char *); -extern int sendmessage(int, unsigned int, unsigned int, unsigned int, - unsigned int, unsigned int, unsigned int, unsigned int *); - /* * Write the proper values into the I/O ports following a reset diff --git a/drivers/kvm/kvm.h b/drivers/kvm/kvm.h index 2db1ca4..04574a9 100644 --- a/drivers/kvm/kvm.h +++ b/drivers/kvm/kvm.h @@ -304,6 +304,7 @@ struct kvm { int memory_config_version; int busy; unsigned long rmap_overflow; + struct list_head vm_list; }; struct kvm_stat { @@ -340,6 +341,7 @@ struct kvm_arch_ops { struct kvm_vcpu *(*vcpu_load)(struct kvm_vcpu *vcpu); void (*vcpu_put)(struct kvm_vcpu *vcpu); + void (*vcpu_decache)(struct kvm_vcpu *vcpu); int (*set_guest_debug)(struct kvm_vcpu *vcpu, struct kvm_debug_guest *dbg); @@ -558,7 +560,7 @@ static inline void load_gs(u16 sel) #ifndef load_ldt static inline void load_ldt(u16 sel) { - asm ("lldt %0" : : "g"(sel)); + asm ("lldt %0" : : "rm"(sel)); } #endif diff --git a/drivers/kvm/kvm_main.c b/drivers/kvm/kvm_main.c index b10972e..af86614 100644 --- a/drivers/kvm/kvm_main.c +++ b/drivers/kvm/kvm_main.c @@ -34,6 +34,8 @@ #include #include #include #include +#include +#include #include "x86_emulate.h" #include "segment_descriptor.h" @@ -41,6 +43,9 @@ #include "segment_descriptor.h" MODULE_AUTHOR("Qumranet"); MODULE_LICENSE("GPL"); +static DEFINE_SPINLOCK(kvm_lock); +static LIST_HEAD(vm_list); + struct kvm_arch_ops *kvm_arch_ops; struct kvm_stat kvm_stat; EXPORT_SYMBOL_GPL(kvm_stat); @@ -62,7 +67,7 @@ static struct kvm_stats_debugfs_item { { "halt_exits", &kvm_stat.halt_exits }, { "request_irq", &kvm_stat.request_irq_exits }, { "irq_exits", &kvm_stat.irq_exits }, - { 0, 0 } + { NULL, NULL } }; static struct dentry *debugfs_dir; @@ -205,7 +210,7 @@ static struct kvm_vcpu *vcpu_load(struct mutex_lock(&vcpu->mutex); if (unlikely(!vcpu->vmcs)) { mutex_unlock(&vcpu->mutex); - return 0; + return NULL; } return kvm_arch_ops->vcpu_load(vcpu); } @@ -230,9 +235,13 @@ static int kvm_dev_open(struct inode *in struct kvm_vcpu *vcpu = &kvm->vcpus[i]; mutex_init(&vcpu->mutex); + vcpu->cpu = -1; vcpu->kvm = kvm; vcpu->mmu.root_hpa = INVALID_PAGE; INIT_LIST_HEAD(&vcpu->free_pages); + spin_lock(&kvm_lock); + list_add(&kvm->vm_list, &vm_list); + spin_unlock(&kvm_lock); } filp->private_data = kvm; return 0; @@ -257,9 +266,9 @@ static void kvm_free_physmem_slot(struct if (!dont || free->dirty_bitmap != dont->dirty_bitmap) vfree(free->dirty_bitmap); - free->phys_mem = 0; + free->phys_mem = NULL; free->npages = 0; - free->dirty_bitmap = 0; + free->dirty_bitmap = NULL; } static void kvm_free_physmem(struct kvm *kvm) @@ -267,12 +276,14 @@ static void kvm_free_physmem(struct kvm int i; for (i = 0; i < kvm->nmemslots; ++i) - kvm_free_physmem_slot(&kvm->memslots[i], 0); + kvm_free_physmem_slot(&kvm->memslots[i], NULL); } static void kvm_free_vcpu(struct kvm_vcpu *vcpu) { - vcpu_load(vcpu->kvm, vcpu_slot(vcpu)); + if (!vcpu_load(vcpu->kvm, vcpu_slot(vcpu))) + return; + kvm_mmu_destroy(vcpu); vcpu_put(vcpu); kvm_arch_ops->vcpu_free(vcpu); @@ -290,6 +301,9 @@ static int kvm_dev_release(struct inode { struct kvm *kvm = filp->private_data; + spin_lock(&kvm_lock); + list_del(&kvm->vm_list); + spin_unlock(&kvm_lock); kvm_free_vcpus(kvm); kvm_free_physmem(kvm); kfree(kvm); @@ -544,7 +558,6 @@ static int kvm_dev_ioctl_create_vcpu(str FX_IMAGE_ALIGN); vcpu->guest_fx_image = vcpu->host_fx_image + FX_IMAGE_SIZE; - vcpu->cpu = -1; /* First load will set up TR */ r = kvm_arch_ops->vcpu_create(vcpu); if (r < 0) goto out_free_vcpus; @@ -640,11 +653,11 @@ raced: /* Deallocate if slot is being removed */ if (!npages) - new.phys_mem = 0; + new.phys_mem = NULL; /* Free page dirty bitmap if unneeded */ if (!(new.flags & KVM_MEM_LOG_DIRTY_PAGES)) - new.dirty_bitmap = 0; + new.dirty_bitmap = NULL; r = -ENOMEM; @@ -799,14 +812,14 @@ struct kvm_memory_slot *gfn_to_memslot(s && gfn < memslot->base_gfn + memslot->npages) return memslot; } - return 0; + return NULL; } EXPORT_SYMBOL_GPL(gfn_to_memslot); void mark_page_dirty(struct kvm *kvm, gfn_t gfn) { int i; - struct kvm_memory_slot *memslot = 0; + struct kvm_memory_slot *memslot = NULL; unsigned long rel_gfn; for (i = 0; i < kvm->nmemslots; ++i) { @@ -1360,6 +1373,9 @@ static int kvm_dev_ioctl_run(struct kvm if (!vcpu) return -ENOENT; + /* re-sync apic's tpr */ + vcpu->cr8 = kvm_run->cr8; + if (kvm_run->emulated) { kvm_arch_ops->skip_emulated_instruction(vcpu); kvm_run->emulated = 0; @@ -1778,6 +1794,7 @@ static long kvm_dev_ioctl(struct file *f unsigned int ioctl, unsigned long arg) { struct kvm *kvm = filp->private_data; + void __user *argp = (void __user *)arg; int r = -EINVAL; switch (ioctl) { @@ -1794,12 +1811,12 @@ static long kvm_dev_ioctl(struct file *f struct kvm_run kvm_run; r = -EFAULT; - if (copy_from_user(&kvm_run, (void *)arg, sizeof kvm_run)) + if (copy_from_user(&kvm_run, argp, sizeof kvm_run)) goto out; r = kvm_dev_ioctl_run(kvm, &kvm_run); if (r < 0 && r != -EINTR) goto out; - if (copy_to_user((void *)arg, &kvm_run, sizeof kvm_run)) { + if (copy_to_user(argp, &kvm_run, sizeof kvm_run)) { r = -EFAULT; goto out; } @@ -1809,13 +1826,13 @@ static long kvm_dev_ioctl(struct file *f struct kvm_regs kvm_regs; r = -EFAULT; - if (copy_from_user(&kvm_regs, (void *)arg, sizeof kvm_regs)) + if (copy_from_user(&kvm_regs, argp, sizeof kvm_regs)) goto out; r = kvm_dev_ioctl_get_regs(kvm, &kvm_regs); if (r) goto out; r = -EFAULT; - if (copy_to_user((void *)arg, &kvm_regs, sizeof kvm_regs)) + if (copy_to_user(argp, &kvm_regs, sizeof kvm_regs)) goto out; r = 0; break; @@ -1824,7 +1841,7 @@ static long kvm_dev_ioctl(struct file *f struct kvm_regs kvm_regs; r = -EFAULT; - if (copy_from_user(&kvm_regs, (void *)arg, sizeof kvm_regs)) + if (copy_from_user(&kvm_regs, argp, sizeof kvm_regs)) goto out; r = kvm_dev_ioctl_set_regs(kvm, &kvm_regs); if (r) @@ -1836,13 +1853,13 @@ static long kvm_dev_ioctl(struct file *f struct kvm_sregs kvm_sregs; r = -EFAULT; - if (copy_from_user(&kvm_sregs, (void *)arg, sizeof kvm_sregs)) + if (copy_from_user(&kvm_sregs, argp, sizeof kvm_sregs)) goto out; r = kvm_dev_ioctl_get_sregs(kvm, &kvm_sregs); if (r) goto out; r = -EFAULT; - if (copy_to_user((void *)arg, &kvm_sregs, sizeof kvm_sregs)) + if (copy_to_user(argp, &kvm_sregs, sizeof kvm_sregs)) goto out; r = 0; break; @@ -1851,7 +1868,7 @@ static long kvm_dev_ioctl(struct file *f struct kvm_sregs kvm_sregs; r = -EFAULT; - if (copy_from_user(&kvm_sregs, (void *)arg, sizeof kvm_sregs)) + if (copy_from_user(&kvm_sregs, argp, sizeof kvm_sregs)) goto out; r = kvm_dev_ioctl_set_sregs(kvm, &kvm_sregs); if (r) @@ -1863,13 +1880,13 @@ static long kvm_dev_ioctl(struct file *f struct kvm_translation tr; r = -EFAULT; - if (copy_from_user(&tr, (void *)arg, sizeof tr)) + if (copy_from_user(&tr, argp, sizeof tr)) goto out; r = kvm_dev_ioctl_translate(kvm, &tr); if (r) goto out; r = -EFAULT; - if (copy_to_user((void *)arg, &tr, sizeof tr)) + if (copy_to_user(argp, &tr, sizeof tr)) goto out; r = 0; break; @@ -1878,7 +1895,7 @@ static long kvm_dev_ioctl(struct file *f struct kvm_interrupt irq; r = -EFAULT; - if (copy_from_user(&irq, (void *)arg, sizeof irq)) + if (copy_from_user(&irq, argp, sizeof irq)) goto out; r = kvm_dev_ioctl_interrupt(kvm, &irq); if (r) @@ -1890,7 +1907,7 @@ static long kvm_dev_ioctl(struct file *f struct kvm_debug_guest dbg; r = -EFAULT; - if (copy_from_user(&dbg, (void *)arg, sizeof dbg)) + if (copy_from_user(&dbg, argp, sizeof dbg)) goto out; r = kvm_dev_ioctl_debug_guest(kvm, &dbg); if (r) @@ -1902,7 +1919,7 @@ static long kvm_dev_ioctl(struct file *f struct kvm_memory_region kvm_mem; r = -EFAULT; - if (copy_from_user(&kvm_mem, (void *)arg, sizeof kvm_mem)) + if (copy_from_user(&kvm_mem, argp, sizeof kvm_mem)) goto out; r = kvm_dev_ioctl_set_memory_region(kvm, &kvm_mem); if (r) @@ -1913,7 +1930,7 @@ static long kvm_dev_ioctl(struct file *f struct kvm_dirty_log log; r = -EFAULT; - if (copy_from_user(&log, (void *)arg, sizeof log)) + if (copy_from_user(&log, argp, sizeof log)) goto out; r = kvm_dev_ioctl_get_dirty_log(kvm, &log); if (r) @@ -1921,13 +1938,13 @@ static long kvm_dev_ioctl(struct file *f break; } case KVM_GET_MSRS: - r = msr_io(kvm, (void __user *)arg, get_msr, 1); + r = msr_io(kvm, argp, get_msr, 1); break; case KVM_SET_MSRS: - r = msr_io(kvm, (void __user *)arg, do_set_msr, 0); + r = msr_io(kvm, argp, do_set_msr, 0); break; case KVM_GET_MSR_INDEX_LIST: { - struct kvm_msr_list __user *user_msr_list = (void __user *)arg; + struct kvm_msr_list __user *user_msr_list = argp; struct kvm_msr_list msr_list; unsigned n; @@ -2014,7 +2031,7 @@ static int kvm_reboot(struct notifier_bl * in vmx root mode. */ printk(KERN_INFO "kvm: exiting hardware virtualization\n"); - on_each_cpu(kvm_arch_ops->hardware_disable, 0, 0, 1); + on_each_cpu(kvm_arch_ops->hardware_disable, NULL, 0, 1); } return NOTIFY_OK; } @@ -2024,11 +2041,69 @@ static struct notifier_block kvm_reboot_ .priority = 0, }; +/* + * Make sure that a cpu that is being hot-unplugged does not have any vcpus + * cached on it. + */ +static void decache_vcpus_on_cpu(int cpu) +{ + struct kvm *vm; + struct kvm_vcpu *vcpu; + int i; + + spin_lock(&kvm_lock); + list_for_each_entry(vm, &vm_list, vm_list) + for (i = 0; i < KVM_MAX_VCPUS; ++i) { + vcpu = &vm->vcpus[i]; + /* + * If the vcpu is locked, then it is running on some + * other cpu and therefore it is not cached on the + * cpu in question. + * + * If it's not locked, check the last cpu it executed + * on. + */ + if (mutex_trylock(&vcpu->mutex)) { + if (vcpu->cpu == cpu) { + kvm_arch_ops->vcpu_decache(vcpu); + vcpu->cpu = -1; + } + mutex_unlock(&vcpu->mutex); + } + } + spin_unlock(&kvm_lock); +} + +static int kvm_cpu_hotplug(struct notifier_block *notifier, unsigned long val, + void *v) +{ + int cpu = (long)v; + + switch (val) { + case CPU_DEAD: + case CPU_UP_CANCELED: + decache_vcpus_on_cpu(cpu); + smp_call_function_single(cpu, kvm_arch_ops->hardware_disable, + NULL, 0, 1); + break; + case CPU_UP_PREPARE: + smp_call_function_single(cpu, kvm_arch_ops->hardware_enable, + NULL, 0, 1); + break; + } + return NOTIFY_OK; +} + +static struct notifier_block kvm_cpu_notifier = { + .notifier_call = kvm_cpu_hotplug, + .priority = 20, /* must be > scheduler priority */ +}; + static __init void kvm_init_debug(void) { struct kvm_stats_debugfs_item *p; - debugfs_dir = debugfs_create_dir("kvm", 0); + debugfs_dir = debugfs_create_dir("kvm", NULL); for (p = debugfs_entries; p->name; ++p) p->dentry = debugfs_create_u32(p->name, 0444, debugfs_dir, p->data); @@ -2043,6 +2118,30 @@ static void kvm_exit_debug(void) debugfs_remove(debugfs_dir); } +static int kvm_suspend(struct sys_device *dev, pm_message_t state) +{ + decache_vcpus_on_cpu(raw_smp_processor_id()); + on_each_cpu(kvm_arch_ops->hardware_disable, 0, 0, 1); + return 0; +} + +static int kvm_resume(struct sys_device *dev) +{ + on_each_cpu(kvm_arch_ops->hardware_enable, 0, 0, 1); + return 0; +} + +static struct sysdev_class kvm_sysdev_class = { + set_kset_name("kvm"), + .suspend = kvm_suspend, + .resume = kvm_resume, +}; + +static struct sys_device kvm_sysdev = { + .id = 0, + .cls = &kvm_sysdev_class, +}; + hpa_t bad_page_address; int kvm_init_arch(struct kvm_arch_ops *ops, struct module *module) @@ -2069,9 +2168,20 @@ int kvm_init_arch(struct kvm_arch_ops *o if (r < 0) return r; - on_each_cpu(kvm_arch_ops->hardware_enable, 0, 0, 1); + on_each_cpu(kvm_arch_ops->hardware_enable, NULL, 0, 1); + r = register_cpu_notifier(&kvm_cpu_notifier); + if (r) + goto out_free_1; register_reboot_notifier(&kvm_reboot_notifier); + r = sysdev_class_register(&kvm_sysdev_class); + if (r) + goto out_free_2; + + r = sysdev_register(&kvm_sysdev); + if (r) + goto out_free_3; + kvm_chardev_ops.owner = module; r = misc_register(&kvm_dev); @@ -2083,8 +2193,14 @@ int kvm_init_arch(struct kvm_arch_ops *o return r; out_free: + sysdev_unregister(&kvm_sysdev); +out_free_3: + sysdev_class_unregister(&kvm_sysdev_class); +out_free_2: unregister_reboot_notifier(&kvm_reboot_notifier); - on_each_cpu(kvm_arch_ops->hardware_disable, 0, 0, 1); + unregister_cpu_notifier(&kvm_cpu_notifier); +out_free_1: + on_each_cpu(kvm_arch_ops->hardware_disable, NULL, 0, 1); kvm_arch_ops->hardware_unsetup(); return r; } @@ -2092,9 +2208,11 @@ out_free: void kvm_exit_arch(void) { misc_deregister(&kvm_dev); - + sysdev_unregister(&kvm_sysdev); + sysdev_class_unregister(&kvm_sysdev_class); unregister_reboot_notifier(&kvm_reboot_notifier); - on_each_cpu(kvm_arch_ops->hardware_disable, 0, 0, 1); + unregister_cpu_notifier(&kvm_cpu_notifier); + on_each_cpu(kvm_arch_ops->hardware_disable, NULL, 0, 1); kvm_arch_ops->hardware_unsetup(); kvm_arch_ops = NULL; } diff --git a/drivers/kvm/mmu.c b/drivers/kvm/mmu.c index 22c426c..be79377 100644 --- a/drivers/kvm/mmu.c +++ b/drivers/kvm/mmu.c @@ -333,7 +333,7 @@ static void rmap_desc_remove_entry(struc for (j = RMAP_EXT - 1; !desc->shadow_ptes[j] && j > i; --j) ; desc->shadow_ptes[i] = desc->shadow_ptes[j]; - desc->shadow_ptes[j] = 0; + desc->shadow_ptes[j] = NULL; if (j != 0) return; if (!prev_desc && !desc->more) diff --git a/drivers/kvm/paging_tmpl.h b/drivers/kvm/paging_tmpl.h index 149fa45..b6b90e9 100644 --- a/drivers/kvm/paging_tmpl.h +++ b/drivers/kvm/paging_tmpl.h @@ -443,31 +443,17 @@ static int FNAME(page_fault)(struct kvm_ static gpa_t FNAME(gva_to_gpa)(struct kvm_vcpu *vcpu, gva_t vaddr) { struct guest_walker walker; - pt_element_t guest_pte; - gpa_t gpa; - - FNAME(walk_addr)(&walker, vcpu, vaddr, 0, 0, 0); - guest_pte = *walker.ptep; - FNAME(release_walker)(&walker); - - if (!is_present_pte(guest_pte)) - return UNMAPPED_GVA; - - if (walker.level == PT_DIRECTORY_LEVEL) { - ASSERT((guest_pte & PT_PAGE_SIZE_MASK)); - ASSERT(PTTYPE == 64 || is_pse(vcpu)); + gpa_t gpa = UNMAPPED_GVA; + int r; - gpa = (guest_pte & PT_DIR_BASE_ADDR_MASK) | (vaddr & - (PT_LEVEL_MASK(PT_PAGE_TABLE_LEVEL) | ~PAGE_MASK)); + r = FNAME(walk_addr)(&walker, vcpu, vaddr, 0, 0, 0); - if (PTTYPE == 32 && is_cpuid_PSE36()) - gpa |= (guest_pte & PT32_DIR_PSE36_MASK) << - (32 - PT32_DIR_PSE36_SHIFT); - } else { - gpa = (guest_pte & PT_BASE_ADDR_MASK); - gpa |= (vaddr & ~PAGE_MASK); + if (r) { + gpa = (gpa_t)walker.gfn << PAGE_SHIFT; + gpa |= vaddr & ~PAGE_MASK; } + FNAME(release_walker)(&walker); return gpa; } diff --git a/drivers/kvm/svm.c b/drivers/kvm/svm.c index c79df79..83da4ea 100644 --- a/drivers/kvm/svm.c +++ b/drivers/kvm/svm.c @@ -274,7 +274,7 @@ static void svm_hardware_disable(void *g wrmsrl(MSR_VM_HSAVE_PA, 0); rdmsrl(MSR_EFER, efer); wrmsrl(MSR_EFER, efer & ~MSR_EFER_SVME_MASK); - per_cpu(svm_data, raw_smp_processor_id()) = 0; + per_cpu(svm_data, raw_smp_processor_id()) = NULL; __free_page(svm_data->save_area); kfree(svm_data); } @@ -528,7 +528,13 @@ static void init_vmcb(struct vmcb *vmcb) save->cs.attrib = SVM_SELECTOR_READ_MASK | SVM_SELECTOR_P_MASK | SVM_SELECTOR_S_MASK | SVM_SELECTOR_CODE_MASK; save->cs.limit = 0xffff; - save->cs.base = 0xffff0000; + /* + * cs.base should really be 0xffff0000, but vmx can't handle that, so + * be consistent with it. + * + * Replace when we have real mode working for vmx. + */ + save->cs.base = 0xf0000; save->gdtr.limit = 0xffff; save->idtr.limit = 0xffff; @@ -603,6 +609,10 @@ static void svm_vcpu_put(struct kvm_vcpu put_cpu(); } +static void svm_vcpu_decache(struct kvm_vcpu *vcpu) +{ +} + static void svm_cache_regs(struct kvm_vcpu *vcpu) { vcpu->regs[VCPU_REGS_RAX] = vcpu->svm->vmcb->save.rax; @@ -642,7 +652,7 @@ static struct vmcb_seg *svm_seg(struct k case VCPU_SREG_LDTR: return &save->ldtr; } BUG(); - return 0; + return NULL; } static u64 svm_get_segment_base(struct kvm_vcpu *vcpu, int seg) @@ -723,7 +733,7 @@ #ifdef CONFIG_X86_64 } #endif vcpu->svm->cr0 = cr0; - vcpu->svm->vmcb->save.cr0 = cr0 | CR0_PG_MASK; + vcpu->svm->vmcb->save.cr0 = cr0 | CR0_PG_MASK | CR0_WP_MASK; vcpu->cr0 = cr0; } @@ -934,7 +944,7 @@ static int io_get_override(struct kvm_vc return 0; *addr_override = 0; - *seg = 0; + *seg = NULL; for (i = 0; i < ins_length; i++) switch (inst[i]) { case 0xf0: @@ -1087,7 +1097,7 @@ static int cpuid_interception(struct kvm static int emulate_on_interception(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run) { - if (emulate_instruction(vcpu, 0, 0, 0) != EMULATE_DONE) + if (emulate_instruction(vcpu, NULL, 0, 0) != EMULATE_DONE) printk(KERN_ERR "%s: failed\n", __FUNCTION__); return 1; } @@ -1671,6 +1681,7 @@ static struct kvm_arch_ops svm_arch_ops .vcpu_load = svm_vcpu_load, .vcpu_put = svm_vcpu_put, + .vcpu_decache = svm_vcpu_decache, .set_guest_debug = svm_guest_debug, .get_msr = svm_get_msr, diff --git a/drivers/kvm/vmx.c b/drivers/kvm/vmx.c index 54c35c0..fd4e917 100644 --- a/drivers/kvm/vmx.c +++ b/drivers/kvm/vmx.c @@ -98,7 +98,7 @@ static struct vmx_msr_entry *find_msr_en for (i = 0; i < vcpu->nmsrs; ++i) if (vcpu->guest_msrs[i].index == msr) return &vcpu->guest_msrs[i]; - return 0; + return NULL; } static void vmcs_clear(struct vmcs *vmcs) @@ -125,6 +125,15 @@ static void __vcpu_clear(void *arg) per_cpu(current_vmcs, cpu) = NULL; } +static void vcpu_clear(struct kvm_vcpu *vcpu) +{ + if (vcpu->cpu != raw_smp_processor_id() && vcpu->cpu != -1) + smp_call_function_single(vcpu->cpu, __vcpu_clear, vcpu, 0, 1); + else + __vcpu_clear(vcpu); + vcpu->launched = 0; +} + static unsigned long vmcs_readl(unsigned long field) { unsigned long value; @@ -202,10 +211,8 @@ static struct kvm_vcpu *vmx_vcpu_load(st cpu = get_cpu(); - if (vcpu->cpu != cpu) { - smp_call_function(__vcpu_clear, vcpu, 0, 1); - vcpu->launched = 0; - } + if (vcpu->cpu != cpu) + vcpu_clear(vcpu); if (per_cpu(current_vmcs, cpu) != vcpu->vmcs) { u8 error; @@ -243,6 +250,11 @@ static void vmx_vcpu_put(struct kvm_vcpu put_cpu(); } +static void vmx_vcpu_decache(struct kvm_vcpu *vcpu) +{ + vcpu_clear(vcpu); +} + static unsigned long vmx_get_rflags(struct kvm_vcpu *vcpu) { return vmcs_readl(GUEST_RFLAGS); @@ -502,7 +514,7 @@ static __init int vmx_disabled_by_bios(v return (msr & 5) == 1; /* locked but not enabled */ } -static __init void hardware_enable(void *garbage) +static void hardware_enable(void *garbage) { int cpu = raw_smp_processor_id(); u64 phys_addr = __pa(per_cpu(vmxarea, cpu)); @@ -1375,6 +1387,11 @@ static int handle_external_interrupt(str return 1; } +static int handle_triple_fault(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run) +{ + kvm_run->exit_reason = KVM_EXIT_SHUTDOWN; + return 0; +} static int get_io_count(struct kvm_vcpu *vcpu, u64 *count) { @@ -1635,6 +1652,7 @@ static int (*kvm_vmx_exit_handlers[])(st struct kvm_run *kvm_run) = { [EXIT_REASON_EXCEPTION_NMI] = handle_exception, [EXIT_REASON_EXTERNAL_INTERRUPT] = handle_external_interrupt, + [EXIT_REASON_TRIPLE_FAULT] = handle_triple_fault, [EXIT_REASON_IO_INSTRUCTION] = handle_io, [EXIT_REASON_CR_ACCESS] = handle_cr, [EXIT_REASON_DR_ACCESS] = handle_dr, @@ -1786,10 +1804,10 @@ #endif "kvm_vmx_return: " /* Save guest registers, load host registers, keep flags */ #ifdef CONFIG_X86_64 - "xchg %3, 0(%%rsp) \n\t" + "xchg %3, (%%rsp) \n\t" "mov %%rax, %c[rax](%3) \n\t" "mov %%rbx, %c[rbx](%3) \n\t" - "pushq 0(%%rsp); popq %c[rcx](%3) \n\t" + "pushq (%%rsp); popq %c[rcx](%3) \n\t" "mov %%rdx, %c[rdx](%3) \n\t" "mov %%rsi, %c[rsi](%3) \n\t" "mov %%rdi, %c[rdi](%3) \n\t" @@ -1804,24 +1822,24 @@ #ifdef CONFIG_X86_64 "mov %%r15, %c[r15](%3) \n\t" "mov %%cr2, %%rax \n\t" "mov %%rax, %c[cr2](%3) \n\t" - "mov 0(%%rsp), %3 \n\t" + "mov (%%rsp), %3 \n\t" "pop %%rcx; pop %%r15; pop %%r14; pop %%r13; pop %%r12;" "pop %%r11; pop %%r10; pop %%r9; pop %%r8;" "pop %%rbp; pop %%rdi; pop %%rsi;" "pop %%rdx; pop %%rbx; pop %%rax \n\t" #else - "xchg %3, 0(%%esp) \n\t" + "xchg %3, (%%esp) \n\t" "mov %%eax, %c[rax](%3) \n\t" "mov %%ebx, %c[rbx](%3) \n\t" - "pushl 0(%%esp); popl %c[rcx](%3) \n\t" + "pushl (%%esp); popl %c[rcx](%3) \n\t" "mov %%edx, %c[rdx](%3) \n\t" "mov %%esi, %c[rsi](%3) \n\t" "mov %%edi, %c[rdi](%3) \n\t" "mov %%ebp, %c[rbp](%3) \n\t" "mov %%cr2, %%eax \n\t" "mov %%eax, %c[cr2](%3) \n\t" - "mov 0(%%esp), %3 \n\t" + "mov (%%esp), %3 \n\t" "pop %%ecx; popa \n\t" #endif @@ -1859,15 +1877,7 @@ #endif fx_restore(vcpu->host_fx_image); vcpu->interrupt_window_open = (vmcs_read32(GUEST_INTERRUPTIBILITY_INFO) & 3) == 0; -#ifndef CONFIG_X86_64 asm ("mov %0, %%ds; mov %0, %%es" : : "r"(__USER_DS)); -#endif - - /* - * Profile KVM exit RIPs: - */ - if (unlikely(prof_on == KVM_PROFILING)) - profile_hit(KVM_PROFILING, (void *)vmcs_readl(GUEST_RIP)); kvm_run->exit_type = 0; if (fail) { @@ -1891,6 +1901,12 @@ #endif reload_tss(); } + /* + * Profile KVM exit RIPs: + */ + if (unlikely(prof_on == KVM_PROFILING)) + profile_hit(KVM_PROFILING, (void *)vmcs_readl(GUEST_RIP)); + vcpu->launched = 1; kvm_run->exit_type = KVM_EXIT_TYPE_VM_EXIT; r = kvm_handle_exit(kvm_run, vcpu); @@ -2012,6 +2028,7 @@ static struct kvm_arch_ops vmx_arch_ops .vcpu_load = vmx_vcpu_load, .vcpu_put = vmx_vcpu_put, + .vcpu_decache = vmx_vcpu_decache, .set_guest_debug = set_guest_debug, .get_msr = vmx_get_msr, diff --git a/drivers/kvm/vmx.h b/drivers/kvm/vmx.h index 4c0ab15..d0dc93d 100644 --- a/drivers/kvm/vmx.h +++ b/drivers/kvm/vmx.h @@ -180,6 +180,7 @@ #define VMX_EXIT_REASONS_FAILED_VMENTRY #define EXIT_REASON_EXCEPTION_NMI 0 #define EXIT_REASON_EXTERNAL_INTERRUPT 1 +#define EXIT_REASON_TRIPLE_FAULT 2 #define EXIT_REASON_PENDING_INTERRUPT 7 diff --git a/drivers/macintosh/Kconfig b/drivers/macintosh/Kconfig index a9e747c..1a86387 100644 --- a/drivers/macintosh/Kconfig +++ b/drivers/macintosh/Kconfig @@ -1,6 +1,6 @@ menu "Macintosh device drivers" - depends on PPC || MAC + depends on PPC || MAC || X86 config ADB bool "Apple Desktop Bus (ADB) support" diff --git a/drivers/macintosh/adb.c b/drivers/macintosh/adb.c index 7cec6de..f729eeb 100644 --- a/drivers/macintosh/adb.c +++ b/drivers/macintosh/adb.c @@ -885,7 +885,7 @@ out: return ret; } -static struct file_operations adb_fops = { +static const struct file_operations adb_fops = { .owner = THIS_MODULE, .llseek = no_llseek, .read = adb_read, diff --git a/drivers/macintosh/adbhid.c b/drivers/macintosh/adbhid.c index 1c7d6f2..b77ef51 100644 --- a/drivers/macintosh/adbhid.c +++ b/drivers/macintosh/adbhid.c @@ -574,8 +574,8 @@ static struct adb_request led_request; static int leds_pending[16]; static int leds_req_pending; static int pending_devs[16]; -static int pending_led_start=0; -static int pending_led_end=0; +static int pending_led_start; +static int pending_led_end; static DEFINE_SPINLOCK(leds_lock); static void leds_done(struct adb_request *req) diff --git a/drivers/macintosh/ans-lcd.c b/drivers/macintosh/ans-lcd.c index 2b8a6e8..cdd5a0f 100644 --- a/drivers/macintosh/ans-lcd.c +++ b/drivers/macintosh/ans-lcd.c @@ -121,7 +121,7 @@ anslcd_open( struct inode * inode, struc return 0; } -struct file_operations anslcd_fops = { +const struct file_operations anslcd_fops = { .write = anslcd_write, .ioctl = anslcd_ioctl, .open = anslcd_open, diff --git a/drivers/macintosh/apm_emu.c b/drivers/macintosh/apm_emu.c index 4300c62..c5e4d43 100644 --- a/drivers/macintosh/apm_emu.c +++ b/drivers/macintosh/apm_emu.c @@ -102,7 +102,7 @@ static struct pmu_sleep_notifier apm_sle SLEEP_LEVEL_USERLAND, }; -static char driver_version[] = "0.5"; /* no spaces */ +static const char driver_version[] = "0.5"; /* no spaces */ #ifdef DEBUG static char * apm_event_name[] = { @@ -501,7 +501,7 @@ static int apm_emu_get_info(char *buf, c return p - buf; } -static struct file_operations apm_bios_fops = { +static const struct file_operations apm_bios_fops = { .owner = THIS_MODULE, .read = do_read, .poll = do_poll, diff --git a/drivers/macintosh/mac_hid.c b/drivers/macintosh/mac_hid.c index ee6b4ca..c1fd816 100644 --- a/drivers/macintosh/mac_hid.c +++ b/drivers/macintosh/mac_hid.c @@ -17,10 +17,10 @@ #include static struct input_dev *emumousebtn; static int emumousebtn_input_register(void); -static int mouse_emulate_buttons = 0; +static int mouse_emulate_buttons; static int mouse_button2_keycode = KEY_RIGHTCTRL; /* right control key */ static int mouse_button3_keycode = KEY_RIGHTALT; /* right option key */ -static int mouse_last_keycode = 0; +static int mouse_last_keycode; #if defined(CONFIG_SYSCTL) /* file(s) in /proc/sys/dev/mac_hid */ @@ -138,7 +138,7 @@ int __init mac_hid_init(void) return err; #if defined(CONFIG_SYSCTL) - mac_hid_sysctl_header = register_sysctl_table(mac_hid_root_dir, 1); + mac_hid_sysctl_header = register_sysctl_table(mac_hid_root_dir); #endif /* CONFIG_SYSCTL */ return 0; diff --git a/drivers/macintosh/macio-adb.c b/drivers/macintosh/macio-adb.c index 797cef7..026b67f 100644 --- a/drivers/macintosh/macio-adb.c +++ b/drivers/macintosh/macio-adb.c @@ -6,7 +6,6 @@ #include #include #include #include -#include #include #include #include diff --git a/drivers/macintosh/nvram.c b/drivers/macintosh/nvram.c index 3079187..b195d75 100644 --- a/drivers/macintosh/nvram.c +++ b/drivers/macintosh/nvram.c @@ -100,7 +100,7 @@ static int nvram_ioctl(struct inode *ino return 0; } -struct file_operations nvram_fops = { +const struct file_operations nvram_fops = { .owner = THIS_MODULE, .llseek = nvram_llseek, .read = read_nvram, diff --git a/drivers/macintosh/rack-meter.c b/drivers/macintosh/rack-meter.c index 5ed41fe..f83fad2 100644 --- a/drivers/macintosh/rack-meter.c +++ b/drivers/macintosh/rack-meter.c @@ -171,11 +171,11 @@ static void rackmeter_setup_dbdma(struct /* Make sure dbdma is reset */ DBDMA_DO_RESET(rm->dma_regs); - pr_debug("rackmeter: mark offset=0x%lx\n", + pr_debug("rackmeter: mark offset=0x%zx\n", offsetof(struct rackmeter_dma, mark)); - pr_debug("rackmeter: buf1 offset=0x%lx\n", + pr_debug("rackmeter: buf1 offset=0x%zx\n", offsetof(struct rackmeter_dma, buf1)); - pr_debug("rackmeter: buf2 offset=0x%lx\n", + pr_debug("rackmeter: buf2 offset=0x%zx\n", offsetof(struct rackmeter_dma, buf2)); /* Prepare 4 dbdma commands for the 2 buffers */ diff --git a/drivers/macintosh/smu.c b/drivers/macintosh/smu.c index 6f30459..3096836 100644 --- a/drivers/macintosh/smu.c +++ b/drivers/macintosh/smu.c @@ -1277,7 +1277,7 @@ static int smu_release(struct inode *ino } -static struct file_operations smu_device_fops = { +static const struct file_operations smu_device_fops = { .llseek = no_llseek, .read = smu_read, .write = smu_write, diff --git a/drivers/macintosh/therm_adt746x.c b/drivers/macintosh/therm_adt746x.c index 3d3bf16..a7ce559 100644 --- a/drivers/macintosh/therm_adt746x.c +++ b/drivers/macintosh/therm_adt746x.c @@ -48,11 +48,11 @@ static u8 FAN_SPD_SET[2] = {0x30, 0x31}; static u8 default_limits_local[3] = {70, 50, 70}; /* local, sensor1, sensor2 */ static u8 default_limits_chip[3] = {80, 65, 80}; /* local, sensor1, sensor2 */ -static const char *sensor_location[3] = {NULL, NULL, NULL}; +static const char *sensor_location[3]; -static int limit_adjust = 0; +static int limit_adjust; static int fan_speed = -1; -static int verbose = 0; +static int verbose; MODULE_AUTHOR("Colin Leroy "); MODULE_DESCRIPTION("Driver for ADT746x thermostat in iBook G4 and " diff --git a/drivers/macintosh/via-cuda.c b/drivers/macintosh/via-cuda.c index df66291..d58fcf6 100644 --- a/drivers/macintosh/via-cuda.c +++ b/drivers/macintosh/via-cuda.c @@ -13,7 +13,6 @@ #include #include #include #include -#include #include #include #include @@ -86,7 +85,7 @@ static int data_index; #ifdef CONFIG_PPC static struct device_node *vias; #endif -static int cuda_fully_inited = 0; +static int cuda_fully_inited; #ifdef CONFIG_ADB static int cuda_probe(void); diff --git a/drivers/macintosh/via-macii.c b/drivers/macintosh/via-macii.c index 5d88d5b..1b3bad6 100644 --- a/drivers/macintosh/via-macii.c +++ b/drivers/macintosh/via-macii.c @@ -19,7 +19,6 @@ #include #include #include #include -#include #include #include #include @@ -107,10 +106,10 @@ static enum macii_state { awaiting_reply } macii_state; -static int need_poll = 0; -static int command_byte = 0; -static int last_reply = 0; -static int last_active = 0; +static int need_poll; +static int command_byte; +static int last_reply; +static int last_active; static struct adb_request *current_req; static struct adb_request *last_req; @@ -124,7 +123,7 @@ static int first_byte; static int prefix_len; static int status = ST_IDLE|TREQ; static int last_status; -static int driver_running = 0; +static int driver_running; /* debug level 10 required for ADB logging (should be && debug_adb, ideally) */ diff --git a/drivers/macintosh/via-maciisi.c b/drivers/macintosh/via-maciisi.c index 1f0aa5d..2dc7880 100644 --- a/drivers/macintosh/via-maciisi.c +++ b/drivers/macintosh/via-maciisi.c @@ -18,7 +18,6 @@ #include #include #include -#include #include #include #include @@ -63,10 +62,10 @@ #define ADB_DELAY 150 #undef DEBUG_MACIISI_ADB -static struct adb_request* current_req = NULL; -static struct adb_request* last_req = NULL; +static struct adb_request* current_req; +static struct adb_request* last_req; static unsigned char maciisi_rbuf[16]; -static unsigned char *reply_ptr = NULL; +static unsigned char *reply_ptr; static int data_index; static int reading_reply; static int reply_len; diff --git a/drivers/macintosh/via-pmu.c b/drivers/macintosh/via-pmu.c index 8ca75e5..b6073bd 100644 --- a/drivers/macintosh/via-pmu.c +++ b/drivers/macintosh/via-pmu.c @@ -141,13 +141,13 @@ static volatile int adb_int_pending; static volatile int disable_poll; static struct device_node *vias; static int pmu_kind = PMU_UNKNOWN; -static int pmu_fully_inited = 0; +static int pmu_fully_inited; static int pmu_has_adb; static struct device_node *gpio_node; -static unsigned char __iomem *gpio_reg = NULL; +static unsigned char __iomem *gpio_reg; static int gpio_irq = NO_IRQ; static int gpio_irq_enabled = -1; -static volatile int pmu_suspended = 0; +static volatile int pmu_suspended; static spinlock_t pmu_lock; static u8 pmu_intr_mask; static int pmu_version; @@ -169,7 +169,7 @@ static int option_server_mode; int pmu_battery_count; int pmu_cur_battery; -unsigned int pmu_power_flags; +unsigned int pmu_power_flags = PMU_PWR_AC_PRESENT; struct pmu_battery_info pmu_batteries[PMU_MAX_BATTERIES]; static int query_batt_timer = BATTERY_POLLING_COUNT; static struct adb_request batt_req; @@ -180,7 +180,7 @@ int asleep; BLOCKING_NOTIFIER_HEAD(sleep_notifier_list); #ifdef CONFIG_ADB -static int adb_dev_map = 0; +static int adb_dev_map; static int pmu_adb_flags; static int pmu_probe(void); @@ -516,7 +516,6 @@ #endif /* CONFIG_PPC32 */ proc_get_irqstats, NULL); proc_pmu_options = create_proc_entry("options", 0600, proc_pmu_root); if (proc_pmu_options) { - proc_pmu_options->nlink = 1; proc_pmu_options->read_proc = proc_read_options; proc_pmu_options->write_proc = proc_write_options; } @@ -2673,7 +2672,7 @@ #endif /* CONFIG_PMAC_BACKLIGHT_LEGACY * return error; } -static struct file_operations pmu_device_fops = { +static const struct file_operations pmu_device_fops = { .read = pmu_read, .write = pmu_write, .poll = pmu_fpoll, @@ -2777,7 +2776,7 @@ #endif /* DEBUG_SLEEP */ #if defined(CONFIG_PM) && defined(CONFIG_PPC32) -static int pmu_sys_suspended = 0; +static int pmu_sys_suspended; static int pmu_sys_suspend(struct sys_device *sysdev, pm_message_t state) { @@ -2817,7 +2816,6 @@ static struct sysdev_class pmu_sysclass }; static struct sys_device device_pmu = { - .id = 0, .cls = &pmu_sysclass, }; diff --git a/drivers/macintosh/via-pmu68k.c b/drivers/macintosh/via-pmu68k.c index 93e6ef9..356c721 100644 --- a/drivers/macintosh/via-pmu68k.c +++ b/drivers/macintosh/via-pmu68k.c @@ -22,7 +22,6 @@ #include #include #include #include -#include #include #include #include @@ -96,10 +95,10 @@ static int data_index; static int data_len; static int adb_int_pending; static int pmu_adb_flags; -static int adb_dev_map = 0; +static int adb_dev_map; static struct adb_request bright_req_1, bright_req_2, bright_req_3; static int pmu_kind = PMU_UNKNOWN; -static int pmu_fully_inited = 0; +static int pmu_fully_inited; int asleep; BLOCKING_NOTIFIER_HEAD(sleep_notifier_list); @@ -1040,7 +1039,7 @@ static int pmu_ioctl(struct inode * inod return -EINVAL; } -static struct file_operations pmu_device_fops = { +static const struct file_operations pmu_device_fops = { .read = pmu_read, .write = pmu_write, .ioctl = pmu_ioctl, diff --git a/drivers/macintosh/windfarm_core.c b/drivers/macintosh/windfarm_core.c index e947af9..94c117e 100644 --- a/drivers/macintosh/windfarm_core.c +++ b/drivers/macintosh/windfarm_core.c @@ -94,8 +94,6 @@ static int wf_thread_func(void *data) DBG("wf: thread started\n"); while(!kthread_should_stop()) { - try_to_freeze(); - if (time_after_eq(jiffies, next)) { wf_notify(WF_EVENT_TICK, NULL); if (wf_overtemp) { @@ -118,8 +116,8 @@ static int wf_thread_func(void *data) if (delay <= HZ) schedule_timeout_interruptible(delay); - /* there should be no signal, but oh well */ - if (signal_pending(current)) { + /* there should be no non-suspend signal, but oh well */ + if (signal_pending(current) && !try_to_freeze()) { printk(KERN_WARNING "windfarm: thread got sigl !\n"); break; } diff --git a/drivers/md/bitmap.c b/drivers/md/bitmap.c index 1110816..5554ada 100644 --- a/drivers/md/bitmap.c +++ b/drivers/md/bitmap.c @@ -666,7 +666,7 @@ static void bitmap_file_put(struct bitma if (file) { struct inode *inode = file->f_path.dentry->d_inode; - invalidate_inode_pages(inode->i_mapping); + invalidate_mapping_pages(inode->i_mapping, 0, -1); fput(file); } } @@ -1160,6 +1160,22 @@ int bitmap_startwrite(struct bitmap *bit return 0; } + if (unlikely((*bmc & COUNTER_MAX) == COUNTER_MAX)) { + DEFINE_WAIT(__wait); + /* note that it is safe to do the prepare_to_wait + * after the test as long as we do it before dropping + * the spinlock. + */ + prepare_to_wait(&bitmap->overflow_wait, &__wait, + TASK_UNINTERRUPTIBLE); + spin_unlock_irq(&bitmap->lock); + bitmap->mddev->queue + ->unplug_fn(bitmap->mddev->queue); + schedule(); + finish_wait(&bitmap->overflow_wait, &__wait); + continue; + } + switch(*bmc) { case 0: bitmap_file_set_bit(bitmap, offset); @@ -1169,7 +1185,7 @@ int bitmap_startwrite(struct bitmap *bit case 1: *bmc = 2; } - BUG_ON((*bmc & COUNTER_MAX) == COUNTER_MAX); + (*bmc)++; spin_unlock_irq(&bitmap->lock); @@ -1207,6 +1223,9 @@ void bitmap_endwrite(struct bitmap *bitm if (!success && ! (*bmc & NEEDED_MASK)) *bmc |= NEEDED_MASK; + if ((*bmc & COUNTER_MAX) == COUNTER_MAX) + wake_up(&bitmap->overflow_wait); + (*bmc)--; if (*bmc <= 2) { set_page_attr(bitmap, @@ -1431,6 +1450,7 @@ int bitmap_create(mddev_t *mddev) spin_lock_init(&bitmap->lock); atomic_set(&bitmap->pending_writes, 0); init_waitqueue_head(&bitmap->write_wait); + init_waitqueue_head(&bitmap->overflow_wait); bitmap->mddev = mddev; diff --git a/drivers/md/dm-ioctl.c b/drivers/md/dm-ioctl.c index cd6a184..b441d82 100644 --- a/drivers/md/dm-ioctl.c +++ b/drivers/md/dm-ioctl.c @@ -1473,7 +1473,7 @@ static int ctl_ioctl(struct inode *inode return r; } -static struct file_operations _ctl_fops = { +static const struct file_operations _ctl_fops = { .ioctl = ctl_ioctl, .owner = THIS_MODULE, }; diff --git a/drivers/md/md.c b/drivers/md/md.c index e8807ea..05febfd 100644 --- a/drivers/md/md.c +++ b/drivers/md/md.c @@ -4920,7 +4920,7 @@ static unsigned int mdstat_poll(struct f return mask; } -static struct file_operations md_seq_fops = { +static const struct file_operations md_seq_fops = { .owner = THIS_MODULE, .open = md_seq_open, .read = seq_read, @@ -5581,7 +5581,7 @@ static int __init md_init(void) md_probe, NULL, NULL); register_reboot_notifier(&md_notifier); - raid_table_header = register_sysctl_table(raid_root_table, 1); + raid_table_header = register_sysctl_table(raid_root_table); md_geninit(); return (0); diff --git a/drivers/md/raid5.c b/drivers/md/raid5.c index 467c169..11c3d7b 100644 --- a/drivers/md/raid5.c +++ b/drivers/md/raid5.c @@ -2620,7 +2620,7 @@ static struct bio *remove_bio_from_retry } bi = conf->retry_read_aligned_list; if(bi) { - conf->retry_read_aligned = bi->bi_next; + conf->retry_read_aligned_list = bi->bi_next; bi->bi_next = NULL; bi->bi_phys_segments = 1; /* biased count of active stripes */ bi->bi_hw_segments = 0; /* count of processed stripes */ @@ -2669,6 +2669,27 @@ static int raid5_align_endio(struct bio return 0; } +static int bio_fits_rdev(struct bio *bi) +{ + request_queue_t *q = bdev_get_queue(bi->bi_bdev); + + if ((bi->bi_size>>9) > q->max_sectors) + return 0; + blk_recount_segments(q, bi); + if (bi->bi_phys_segments > q->max_phys_segments || + bi->bi_hw_segments > q->max_hw_segments) + return 0; + + if (q->merge_bvec_fn) + /* it's too hard to apply the merge_bvec_fn at this stage, + * just just give up + */ + return 0; + + return 1; +} + + static int chunk_aligned_read(request_queue_t *q, struct bio * raid_bio) { mddev_t *mddev = q->queuedata; @@ -2715,6 +2736,13 @@ static int chunk_aligned_read(request_qu align_bi->bi_flags &= ~(1 << BIO_SEG_VALID); align_bi->bi_sector += rdev->data_offset; + if (!bio_fits_rdev(align_bi)) { + /* too big in some way */ + bio_put(align_bi); + rdev_dec_pending(rdev, mddev); + return 0; + } + spin_lock_irq(&conf->device_lock); wait_event_lock_irq(conf->wait_for_stripe, conf->quiesce == 0, @@ -3107,7 +3135,9 @@ static int retry_aligned_read(raid5_con last_sector = raid_bio->bi_sector + (raid_bio->bi_size>>9); for (; logical_sector < last_sector; - logical_sector += STRIPE_SECTORS, scnt++) { + logical_sector += STRIPE_SECTORS, + sector += STRIPE_SECTORS, + scnt++) { if (scnt < raid_bio->bi_hw_segments) /* already done this stripe */ @@ -3123,7 +3153,13 @@ static int retry_aligned_read(raid5_con } set_bit(R5_ReadError, &sh->dev[dd_idx].flags); - add_stripe_bio(sh, raid_bio, dd_idx, 0); + if (!add_stripe_bio(sh, raid_bio, dd_idx, 0)) { + release_stripe(sh); + raid_bio->bi_hw_segments = scnt; + conf->retry_read_aligned = raid_bio; + return handled; + } + handle_stripe(sh, NULL); release_stripe(sh); handled++; diff --git a/drivers/media/common/ir-keymaps.c b/drivers/media/common/ir-keymaps.c index f51e02f..0e948a5 100644 --- a/drivers/media/common/ir-keymaps.c +++ b/drivers/media/common/ir-keymaps.c @@ -698,7 +698,6 @@ IR_KEYTAB_TYPE ir_codes_pinnacle_grey[IR [ 0x29 ] = KEY_TEXT, [ 0x2a ] = KEY_MEDIA, [ 0x18 ] = KEY_EPG, - [ 0x27 ] = KEY_RECORD, }; EXPORT_SYMBOL_GPL(ir_codes_pinnacle_grey); diff --git a/drivers/media/common/saa7146_fops.c b/drivers/media/common/saa7146_fops.c index d867a6a..b8dcfa1 100644 --- a/drivers/media/common/saa7146_fops.c +++ b/drivers/media/common/saa7146_fops.c @@ -416,7 +416,7 @@ static ssize_t fops_write(struct file *f } } -static struct file_operations video_fops = +static const struct file_operations video_fops = { .owner = THIS_MODULE, .open = fops_open, diff --git a/drivers/media/dvb/b2c2/flexcop-i2c.c b/drivers/media/dvb/b2c2/flexcop-i2c.c index e0bd2d8..5347a40 100644 --- a/drivers/media/dvb/b2c2/flexcop-i2c.c +++ b/drivers/media/dvb/b2c2/flexcop-i2c.c @@ -190,6 +190,7 @@ int flexcop_i2c_init(struct flexcop_devi fc->i2c_adap.class = I2C_CLASS_TV_DIGITAL; fc->i2c_adap.algo = &flexcop_algo; fc->i2c_adap.algo_data = NULL; + fc->i2c_adap.dev.parent = fc->dev; if ((ret = i2c_add_adapter(&fc->i2c_adap)) < 0) return ret; diff --git a/drivers/media/dvb/dvb-core/dmxdev.c b/drivers/media/dvb/dvb-core/dmxdev.c index 988499d..fc77de4 100644 --- a/drivers/media/dvb/dvb-core/dmxdev.c +++ b/drivers/media/dvb/dvb-core/dmxdev.c @@ -25,7 +25,6 @@ #include #include #include #include -#include #include #include #include diff --git a/drivers/media/dvb/dvb-core/dvbdev.c b/drivers/media/dvb/dvb-core/dvbdev.c index 40774fe..826b47f 100644 --- a/drivers/media/dvb/dvb-core/dvbdev.c +++ b/drivers/media/dvb/dvb-core/dvbdev.c @@ -27,7 +27,6 @@ #include #include #include #include -#include #include #include #include diff --git a/drivers/media/dvb/dvb-usb/dvb-usb-i2c.c b/drivers/media/dvb/dvb-usb/dvb-usb-i2c.c index 55ba020..70df31b 100644 --- a/drivers/media/dvb/dvb-usb/dvb-usb-i2c.c +++ b/drivers/media/dvb/dvb-usb/dvb-usb-i2c.c @@ -27,6 +27,7 @@ #else #endif d->i2c_adap.algo = d->props.i2c_algo; d->i2c_adap.algo_data = NULL; + d->i2c_adap.dev.parent = &d->udev->dev; i2c_set_adapdata(&d->i2c_adap, d); diff --git a/drivers/media/dvb/ttpci/av7110_av.c b/drivers/media/dvb/ttpci/av7110_av.c index 8c577cf..795e6e9 100644 --- a/drivers/media/dvb/ttpci/av7110_av.c +++ b/drivers/media/dvb/ttpci/av7110_av.c @@ -31,7 +31,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/media/dvb/ttpci/av7110_ca.c b/drivers/media/dvb/ttpci/av7110_ca.c index dd9aee3..4251a97 100644 --- a/drivers/media/dvb/ttpci/av7110_ca.c +++ b/drivers/media/dvb/ttpci/av7110_ca.c @@ -29,7 +29,6 @@ */ #include -#include #include #include #include diff --git a/drivers/media/dvb/ttpci/av7110_hw.c b/drivers/media/dvb/ttpci/av7110_hw.c index 37de2e8..4d7150e 100644 --- a/drivers/media/dvb/ttpci/av7110_hw.c +++ b/drivers/media/dvb/ttpci/av7110_hw.c @@ -32,7 +32,6 @@ #include #include #include #include -#include #include #include #include diff --git a/drivers/media/dvb/ttpci/av7110_v4l.c b/drivers/media/dvb/ttpci/av7110_v4l.c index 10cfe31..dbfd5e7 100644 --- a/drivers/media/dvb/ttpci/av7110_v4l.c +++ b/drivers/media/dvb/ttpci/av7110_v4l.c @@ -26,7 +26,6 @@ */ #include -#include #include #include #include diff --git a/drivers/media/dvb/ttusb-budget/dvb-ttusb-budget.c b/drivers/media/dvb/ttusb-budget/dvb-ttusb-budget.c index 60820de..b60cdc9 100644 --- a/drivers/media/dvb/ttusb-budget/dvb-ttusb-budget.c +++ b/drivers/media/dvb/ttusb-budget/dvb-ttusb-budget.c @@ -1690,6 +1690,7 @@ #else #endif ttusb->i2c_adap.algo = &ttusb_dec_algo; ttusb->i2c_adap.algo_data = NULL; + ttusb->i2c_adap.dev.parent = &udev->dev; result = i2c_add_adapter(&ttusb->i2c_adap); if (result) { diff --git a/drivers/media/radio/dsbr100.c b/drivers/media/radio/dsbr100.c index db865a0..df8d052 100644 --- a/drivers/media/radio/dsbr100.c +++ b/drivers/media/radio/dsbr100.c @@ -144,7 +144,7 @@ struct dsbr100_device { /* File system interface */ -static struct file_operations usb_dsbr100_fops = { +static const struct file_operations usb_dsbr100_fops = { .owner = THIS_MODULE, .open = usb_dsbr100_open, .release = usb_dsbr100_close, diff --git a/drivers/media/radio/miropcm20-radio.c b/drivers/media/radio/miropcm20-radio.c index c4312fa..c7c9d1d 100644 --- a/drivers/media/radio/miropcm20-radio.c +++ b/drivers/media/radio/miropcm20-radio.c @@ -216,7 +216,7 @@ static struct pcm20_device pcm20_unit = .muted = 1, }; -static struct file_operations pcm20_fops = { +static const struct file_operations pcm20_fops = { .owner = THIS_MODULE, .open = video_exclusive_open, .release = video_exclusive_release, diff --git a/drivers/media/radio/miropcm20-rds.c b/drivers/media/radio/miropcm20-rds.c index c1b1db6..aed1147 100644 --- a/drivers/media/radio/miropcm20-rds.c +++ b/drivers/media/radio/miropcm20-rds.c @@ -14,7 +14,6 @@ #include #include #include #include -#include /* current, TASK_*, schedule_timeout() */ #include #include #include "miropcm20-rds-core.h" @@ -105,7 +104,7 @@ static ssize_t rds_f_read(struct file *f } } -static struct file_operations rds_fops = { +static const struct file_operations rds_fops = { .owner = THIS_MODULE, .read = rds_f_read, .open = rds_f_open, diff --git a/drivers/media/radio/radio-aimslab.c b/drivers/media/radio/radio-aimslab.c index 3368a89..b2e88ad 100644 --- a/drivers/media/radio/radio-aimslab.c +++ b/drivers/media/radio/radio-aimslab.c @@ -358,7 +358,7 @@ static int rt_ioctl(struct inode *inode, static struct rt_device rtrack_unit; -static struct file_operations rtrack_fops = { +static const struct file_operations rtrack_fops = { .owner = THIS_MODULE, .open = video_exclusive_open, .release = video_exclusive_release, diff --git a/drivers/media/radio/radio-aztech.c b/drivers/media/radio/radio-aztech.c index 3ba5fa8..19d45cc 100644 --- a/drivers/media/radio/radio-aztech.c +++ b/drivers/media/radio/radio-aztech.c @@ -314,7 +314,7 @@ static int az_ioctl(struct inode *inode, static struct az_device aztech_unit; -static struct file_operations aztech_fops = { +static const struct file_operations aztech_fops = { .owner = THIS_MODULE, .open = video_exclusive_open, .release = video_exclusive_release, diff --git a/drivers/media/radio/radio-cadet.c b/drivers/media/radio/radio-cadet.c index 69d4b79..8fbf0d8 100644 --- a/drivers/media/radio/radio-cadet.c +++ b/drivers/media/radio/radio-cadet.c @@ -507,7 +507,7 @@ cadet_poll(struct file *file, struct pol } -static struct file_operations cadet_fops = { +static const struct file_operations cadet_fops = { .owner = THIS_MODULE, .open = cadet_open, .release = cadet_release, diff --git a/drivers/media/radio/radio-gemtek-pci.c b/drivers/media/radio/radio-gemtek-pci.c index eb14106..05e5aa7 100644 --- a/drivers/media/radio/radio-gemtek-pci.c +++ b/drivers/media/radio/radio-gemtek-pci.c @@ -346,7 +346,7 @@ MODULE_DEVICE_TABLE( pci, gemtek_pci_id static int mx = 1; -static struct file_operations gemtek_pci_fops = { +static const struct file_operations gemtek_pci_fops = { .owner = THIS_MODULE, .open = video_exclusive_open, .release = video_exclusive_release, diff --git a/drivers/media/radio/radio-gemtek.c b/drivers/media/radio/radio-gemtek.c index 730fe16..36c4be6 100644 --- a/drivers/media/radio/radio-gemtek.c +++ b/drivers/media/radio/radio-gemtek.c @@ -296,7 +296,7 @@ static int gemtek_ioctl(struct inode *in static struct gemtek_device gemtek_unit; -static struct file_operations gemtek_fops = { +static const struct file_operations gemtek_fops = { .owner = THIS_MODULE, .open = video_exclusive_open, .release = video_exclusive_release, diff --git a/drivers/media/radio/radio-maestro.c b/drivers/media/radio/radio-maestro.c index e8ce5f7..e67b7f2 100644 --- a/drivers/media/radio/radio-maestro.c +++ b/drivers/media/radio/radio-maestro.c @@ -22,7 +22,6 @@ #include #include #include #include -#include #include #include #include @@ -99,7 +98,7 @@ static struct pci_driver maestro_r_drive .remove = __devexit_p(maestro_remove), }; -static struct file_operations maestro_fops = { +static const struct file_operations maestro_fops = { .owner = THIS_MODULE, .open = video_exclusive_open, .release = video_exclusive_release, diff --git a/drivers/media/radio/radio-maxiradio.c b/drivers/media/radio/radio-maxiradio.c index c2eeae7..6beeb74 100644 --- a/drivers/media/radio/radio-maxiradio.c +++ b/drivers/media/radio/radio-maxiradio.c @@ -35,7 +35,6 @@ #include #include #include #include -#include #include #include #include @@ -91,7 +90,7 @@ #define BITS2FREQ(x) ((x) * FREQ_STEP - static int radio_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg); -static struct file_operations maxiradio_fops = { +static const struct file_operations maxiradio_fops = { .owner = THIS_MODULE, .open = video_exclusive_open, .release = video_exclusive_release, diff --git a/drivers/media/radio/radio-rtrack2.c b/drivers/media/radio/radio-rtrack2.c index b9e9848..f668387 100644 --- a/drivers/media/radio/radio-rtrack2.c +++ b/drivers/media/radio/radio-rtrack2.c @@ -262,7 +262,7 @@ static int rt_ioctl(struct inode *inode, static struct rt_device rtrack2_unit; -static struct file_operations rtrack2_fops = { +static const struct file_operations rtrack2_fops = { .owner = THIS_MODULE, .open = video_exclusive_open, .release = video_exclusive_release, diff --git a/drivers/media/radio/radio-sf16fmi.c b/drivers/media/radio/radio-sf16fmi.c index ecc854b..f4619e4 100644 --- a/drivers/media/radio/radio-sf16fmi.c +++ b/drivers/media/radio/radio-sf16fmi.c @@ -265,7 +265,7 @@ static int fmi_ioctl(struct inode *inode static struct fmi_device fmi_unit; -static struct file_operations fmi_fops = { +static const struct file_operations fmi_fops = { .owner = THIS_MODULE, .open = video_exclusive_open, .release = video_exclusive_release, diff --git a/drivers/media/radio/radio-sf16fmr2.c b/drivers/media/radio/radio-sf16fmr2.c index 4444dce..b96fafe 100644 --- a/drivers/media/radio/radio-sf16fmr2.c +++ b/drivers/media/radio/radio-sf16fmr2.c @@ -410,7 +410,7 @@ static int fmr2_ioctl(struct inode *inod static struct fmr2_device fmr2_unit; -static struct file_operations fmr2_fops = { +static const struct file_operations fmr2_fops = { .owner = THIS_MODULE, .open = video_exclusive_open, .release = video_exclusive_release, diff --git a/drivers/media/radio/radio-terratec.c b/drivers/media/radio/radio-terratec.c index f539491..d59a27a 100644 --- a/drivers/media/radio/radio-terratec.c +++ b/drivers/media/radio/radio-terratec.c @@ -338,7 +338,7 @@ static int tt_ioctl(struct inode *inode, static struct tt_device terratec_unit; -static struct file_operations terratec_fops = { +static const struct file_operations terratec_fops = { .owner = THIS_MODULE, .open = video_exclusive_open, .release = video_exclusive_release, diff --git a/drivers/media/radio/radio-trust.c b/drivers/media/radio/radio-trust.c index bb03ad5..6d7f1e7 100644 --- a/drivers/media/radio/radio-trust.c +++ b/drivers/media/radio/radio-trust.c @@ -325,7 +325,7 @@ static int tr_ioctl(struct inode *inode, return video_usercopy(inode, file, cmd, arg, tr_do_ioctl); } -static struct file_operations trust_fops = { +static const struct file_operations trust_fops = { .owner = THIS_MODULE, .open = video_exclusive_open, .release = video_exclusive_release, diff --git a/drivers/media/radio/radio-typhoon.c b/drivers/media/radio/radio-typhoon.c index 4a72b4d..3031fef 100644 --- a/drivers/media/radio/radio-typhoon.c +++ b/drivers/media/radio/radio-typhoon.c @@ -318,7 +318,7 @@ static struct typhoon_device typhoon_uni .mutefreq = CONFIG_RADIO_TYPHOON_MUTEFREQ, }; -static struct file_operations typhoon_fops = { +static const struct file_operations typhoon_fops = { .owner = THIS_MODULE, .open = video_exclusive_open, .release = video_exclusive_release, diff --git a/drivers/media/radio/radio-zoltrix.c b/drivers/media/radio/radio-zoltrix.c index 671fe1b..ec08491 100644 --- a/drivers/media/radio/radio-zoltrix.c +++ b/drivers/media/radio/radio-zoltrix.c @@ -373,7 +373,7 @@ static int zol_ioctl(struct inode *inode static struct zol_device zoltrix_unit; -static struct file_operations zoltrix_fops = +static const struct file_operations zoltrix_fops = { .owner = THIS_MODULE, .open = video_exclusive_open, diff --git a/drivers/media/video/adv7170.c b/drivers/media/video/adv7170.c index 4870958..2aa9ce9 100644 --- a/drivers/media/video/adv7170.c +++ b/drivers/media/video/adv7170.c @@ -42,7 +42,6 @@ #include #include #include #include -#include #include #include diff --git a/drivers/media/video/adv7175.c b/drivers/media/video/adv7175.c index 68e7d7a..a3246a2 100644 --- a/drivers/media/video/adv7175.c +++ b/drivers/media/video/adv7175.c @@ -38,7 +38,6 @@ #include #include #include #include -#include #include #include diff --git a/drivers/media/video/arv.c b/drivers/media/video/arv.c index 4861799..649f52f 100644 --- a/drivers/media/video/arv.c +++ b/drivers/media/video/arv.c @@ -742,7 +742,7 @@ void ar_release(struct video_device *vfd * Video4Linux Module functions * ****************************************************************************/ -static struct file_operations ar_fops = { +static const struct file_operations ar_fops = { .owner = THIS_MODULE, .open = video_exclusive_open, .release = video_exclusive_release, diff --git a/drivers/media/video/bt819.c b/drivers/media/video/bt819.c index e7b38fd..6867386 100644 --- a/drivers/media/video/bt819.c +++ b/drivers/media/video/bt819.c @@ -42,7 +42,6 @@ #include #include #include #include -#include #include #include diff --git a/drivers/media/video/bt856.c b/drivers/media/video/bt856.c index af3b61d..42e2299 100644 --- a/drivers/media/video/bt856.c +++ b/drivers/media/video/bt856.c @@ -42,7 +42,6 @@ #include #include #include #include -#include #include #include diff --git a/drivers/media/video/bt8xx/bttv-driver.c b/drivers/media/video/bt8xx/bttv-driver.c index ab8f970..41fd09d 100644 --- a/drivers/media/video/bt8xx/bttv-driver.c +++ b/drivers/media/video/bt8xx/bttv-driver.c @@ -3174,7 +3174,7 @@ bttv_mmap(struct file *file, struct vm_a return videobuf_mmap_mapper(bttv_queue(fh),vma); } -static struct file_operations bttv_fops = +static const struct file_operations bttv_fops = { .owner = THIS_MODULE, .open = bttv_open, @@ -3332,7 +3332,7 @@ static unsigned int radio_poll(struct fi return cmd.result; } -static struct file_operations radio_fops = +static const struct file_operations radio_fops = { .owner = THIS_MODULE, .open = radio_open, diff --git a/drivers/media/video/bt8xx/bttv-vbi.c b/drivers/media/video/bt8xx/bttv-vbi.c index 63676e7..6fc6b02 100644 --- a/drivers/media/video/bt8xx/bttv-vbi.c +++ b/drivers/media/video/bt8xx/bttv-vbi.c @@ -25,7 +25,6 @@ #include #include #include #include -#include #include #include #include diff --git a/drivers/media/video/bw-qcam.c b/drivers/media/video/bw-qcam.c index 7d0b6e5..7d47cbe 100644 --- a/drivers/media/video/bw-qcam.c +++ b/drivers/media/video/bw-qcam.c @@ -871,7 +871,7 @@ static ssize_t qcam_read(struct file *fi return len; } -static struct file_operations qcam_fops = { +static const struct file_operations qcam_fops = { .owner = THIS_MODULE, .open = video_exclusive_open, .release = video_exclusive_release, diff --git a/drivers/media/video/c-qcam.c b/drivers/media/video/c-qcam.c index a3989bd..925ff17 100644 --- a/drivers/media/video/c-qcam.c +++ b/drivers/media/video/c-qcam.c @@ -684,7 +684,7 @@ static ssize_t qcam_read(struct file *fi } /* video device template */ -static struct file_operations qcam_fops = { +static const struct file_operations qcam_fops = { .owner = THIS_MODULE, .open = video_exclusive_open, .release = video_exclusive_release, diff --git a/drivers/media/video/cafe_ccic.c b/drivers/media/video/cafe_ccic.c index 3083c80..4dae892 100644 --- a/drivers/media/video/cafe_ccic.c +++ b/drivers/media/video/cafe_ccic.c @@ -549,6 +549,7 @@ static int cafe_smbus_setup(struct cafe_ adap->client_unregister = cafe_smbus_detach; adap->algo = &cafe_smbus_algo; strcpy(adap->name, "cafe_ccic"); + adap->dev.parent = &cam->pdev->dev; i2c_set_adapdata(adap, cam); ret = i2c_add_adapter(adap); if (ret) @@ -1715,7 +1716,7 @@ static void cafe_v4l_dev_release(struct * clone it for specific real devices. */ -static struct file_operations cafe_v4l_fops = { +static const struct file_operations cafe_v4l_fops = { .owner = THIS_MODULE, .open = cafe_v4l_open, .release = cafe_v4l_release, @@ -1969,7 +1970,7 @@ static ssize_t cafe_dfs_read_regs(struct s - cafe_debug_buf); } -static struct file_operations cafe_dfs_reg_ops = { +static const struct file_operations cafe_dfs_reg_ops = { .owner = THIS_MODULE, .read = cafe_dfs_read_regs, .open = cafe_dfs_open @@ -1995,7 +1996,7 @@ static ssize_t cafe_dfs_read_cam(struct s - cafe_debug_buf); } -static struct file_operations cafe_dfs_cam_ops = { +static const struct file_operations cafe_dfs_cam_ops = { .owner = THIS_MODULE, .read = cafe_dfs_read_cam, .open = cafe_dfs_open diff --git a/drivers/media/video/cpia.c b/drivers/media/video/cpia.c index 3b31a0d..7e8d5ef 100644 --- a/drivers/media/video/cpia.c +++ b/drivers/media/video/cpia.c @@ -3791,7 +3791,7 @@ static int cpia_mmap(struct file *file, return 0; } -static struct file_operations cpia_fops = { +static const struct file_operations cpia_fops = { .owner = THIS_MODULE, .open = cpia_open, .release = cpia_close, diff --git a/drivers/media/video/cpia2/cpia2_v4l.c b/drivers/media/video/cpia2/cpia2_v4l.c index d09f499..1bda7ad 100644 --- a/drivers/media/video/cpia2/cpia2_v4l.c +++ b/drivers/media/video/cpia2/cpia2_v4l.c @@ -1924,7 +1924,7 @@ static void reset_camera_struct_v4l(stru /*** * The v4l video device structure initialized for this device ***/ -static struct file_operations fops_template = { +static const struct file_operations fops_template = { .owner = THIS_MODULE, .open = cpia2_open, .release = cpia2_close, diff --git a/drivers/media/video/cx88/cx88-blackbird.c b/drivers/media/video/cx88/cx88-blackbird.c index 0cf0360..9a7a299 100644 --- a/drivers/media/video/cx88/cx88-blackbird.c +++ b/drivers/media/video/cx88/cx88-blackbird.c @@ -1051,7 +1051,7 @@ mpeg_mmap(struct file *file, struct vm_a return videobuf_mmap_mapper(&fh->mpegq, vma); } -static struct file_operations mpeg_fops = +static const struct file_operations mpeg_fops = { .owner = THIS_MODULE, .open = mpeg_open, diff --git a/drivers/media/video/cx88/cx88-tvaudio.c b/drivers/media/video/cx88/cx88-tvaudio.c index 2bd84d3..063df03 100644 --- a/drivers/media/video/cx88/cx88-tvaudio.c +++ b/drivers/media/video/cx88/cx88-tvaudio.c @@ -46,7 +46,6 @@ #include #include #include #include -#include #include #include #include diff --git a/drivers/media/video/cx88/cx88-video.c b/drivers/media/video/cx88/cx88-video.c index 8613378..c86a7e0 100644 --- a/drivers/media/video/cx88/cx88-video.c +++ b/drivers/media/video/cx88/cx88-video.c @@ -1808,7 +1808,7 @@ static irqreturn_t cx8800_irq(int irq, v /* ----------------------------------------------------------- */ /* exported stuff */ -static struct file_operations video_fops = +static const struct file_operations video_fops = { .owner = THIS_MODULE, .open = video_open, @@ -1839,7 +1839,7 @@ static struct video_device cx8800_vbi_te .minor = -1, }; -static struct file_operations radio_fops = +static const struct file_operations radio_fops = { .owner = THIS_MODULE, .open = video_open, diff --git a/drivers/media/video/dabusb.c b/drivers/media/video/dabusb.c index 917021f..ff4b238 100644 --- a/drivers/media/video/dabusb.c +++ b/drivers/media/video/dabusb.c @@ -696,7 +696,7 @@ static int dabusb_ioctl (struct inode *i return ret; } -static struct file_operations dabusb_fops = +static const struct file_operations dabusb_fops = { .owner = THIS_MODULE, .llseek = no_llseek, diff --git a/drivers/media/video/em28xx/em28xx-input.c b/drivers/media/video/em28xx/em28xx-input.c index 3ffb568..55d45b0 100644 --- a/drivers/media/video/em28xx/em28xx-input.c +++ b/drivers/media/video/em28xx/em28xx-input.c @@ -25,7 +25,6 @@ #include #include #include #include -#include #include #include #include diff --git a/drivers/media/video/em28xx/em28xx-video.c b/drivers/media/video/em28xx/em28xx-video.c index 36e72c2..bec6760 100644 --- a/drivers/media/video/em28xx/em28xx-video.c +++ b/drivers/media/video/em28xx/em28xx-video.c @@ -1480,7 +1480,7 @@ static int em28xx_v4l2_ioctl(struct inod return ret; } -static struct file_operations em28xx_v4l_fops = { +static const struct file_operations em28xx_v4l_fops = { .owner = THIS_MODULE, .open = em28xx_v4l2_open, .release = em28xx_v4l2_close, diff --git a/drivers/media/video/et61x251/et61x251_core.c b/drivers/media/video/et61x251/et61x251_core.c index 86e353b..49792ae 100644 --- a/drivers/media/video/et61x251/et61x251_core.c +++ b/drivers/media/video/et61x251/et61x251_core.c @@ -2454,7 +2454,7 @@ static int et61x251_ioctl(struct inode* } -static struct file_operations et61x251_fops = { +static const struct file_operations et61x251_fops = { .owner = THIS_MODULE, .open = et61x251_open, .release = et61x251_release, diff --git a/drivers/media/video/indycam.c b/drivers/media/video/indycam.c index 7420b79..5c2c402 100644 --- a/drivers/media/video/indycam.c +++ b/drivers/media/video/indycam.c @@ -17,7 +17,6 @@ #include #include #include #include -#include #include #include diff --git a/drivers/media/video/ir-kbd-i2c.c b/drivers/media/video/ir-kbd-i2c.c index 59edf58..210582d 100644 --- a/drivers/media/video/ir-kbd-i2c.c +++ b/drivers/media/video/ir-kbd-i2c.c @@ -31,7 +31,6 @@ #include #include #include #include -#include #include #include #include diff --git a/drivers/media/video/meye.c b/drivers/media/video/meye.c index 616a35d..98681da 100644 --- a/drivers/media/video/meye.c +++ b/drivers/media/video/meye.c @@ -28,7 +28,6 @@ */ #include #include -#include #include #include #include @@ -1748,7 +1747,7 @@ static int meye_mmap(struct file *file, return 0; } -static struct file_operations meye_fops = { +static const struct file_operations meye_fops = { .owner = THIS_MODULE, .open = meye_open, .release = meye_release, diff --git a/drivers/media/video/ov511.c b/drivers/media/video/ov511.c index b4db2cb..e5edff1 100644 --- a/drivers/media/video/ov511.c +++ b/drivers/media/video/ov511.c @@ -4653,7 +4653,7 @@ ov51x_v4l1_mmap(struct file *file, struc return 0; } -static struct file_operations ov511_fops = { +static const struct file_operations ov511_fops = { .owner = THIS_MODULE, .open = ov51x_v4l1_open, .release = ov51x_v4l1_close, diff --git a/drivers/media/video/pms.c b/drivers/media/video/pms.c index 5d681fa..b5a67f0 100644 --- a/drivers/media/video/pms.c +++ b/drivers/media/video/pms.c @@ -28,7 +28,6 @@ #include #include #include #include -#include #include #include #include @@ -881,7 +880,7 @@ static ssize_t pms_read(struct file *fil return len; } -static struct file_operations pms_fops = { +static const struct file_operations pms_fops = { .owner = THIS_MODULE, .open = video_exclusive_open, .release = video_exclusive_release, diff --git a/drivers/media/video/pvrusb2/pvrusb2-i2c-core.c b/drivers/media/video/pvrusb2/pvrusb2-i2c-core.c index f9bb41d..62a7cfc 100644 --- a/drivers/media/video/pvrusb2/pvrusb2-i2c-core.c +++ b/drivers/media/video/pvrusb2/pvrusb2-i2c-core.c @@ -977,6 +977,7 @@ void pvr2_i2c_core_init(struct pvr2_hdw memcpy(&hdw->i2c_adap,&pvr2_i2c_adap_template,sizeof(hdw->i2c_adap)); memcpy(&hdw->i2c_algo,&pvr2_i2c_algo_template,sizeof(hdw->i2c_algo)); strlcpy(hdw->i2c_adap.name,hdw->name,sizeof(hdw->i2c_adap.name)); + hdw->i2c_adap.dev.parent = &hdw->usb_dev->dev; hdw->i2c_adap.algo = &hdw->i2c_algo; hdw->i2c_adap.algo_data = hdw; hdw->i2c_pend_mask = 0; diff --git a/drivers/media/video/pvrusb2/pvrusb2-v4l2.c b/drivers/media/video/pvrusb2/pvrusb2-v4l2.c index bb40e90..6cf1708 100644 --- a/drivers/media/video/pvrusb2/pvrusb2-v4l2.c +++ b/drivers/media/video/pvrusb2/pvrusb2-v4l2.c @@ -986,7 +986,7 @@ static unsigned int pvr2_v4l2_poll(struc } -static struct file_operations vdev_fops = { +static const struct file_operations vdev_fops = { .owner = THIS_MODULE, .open = pvr2_v4l2_open, .release = pvr2_v4l2_release, diff --git a/drivers/media/video/pwc/pwc-if.c b/drivers/media/video/pwc/pwc-if.c index a996aad..9825fd3 100644 --- a/drivers/media/video/pwc/pwc-if.c +++ b/drivers/media/video/pwc/pwc-if.c @@ -152,7 +152,7 @@ static int pwc_video_ioctl(struct inode unsigned int ioctlnr, unsigned long arg); static int pwc_video_mmap(struct file *file, struct vm_area_struct *vma); -static struct file_operations pwc_fops = { +static const struct file_operations pwc_fops = { .owner = THIS_MODULE, .open = pwc_video_open, .release = pwc_video_close, diff --git a/drivers/media/video/saa5246a.c b/drivers/media/video/saa5246a.c index 77bb940..76f5f5d 100644 --- a/drivers/media/video/saa5246a.c +++ b/drivers/media/video/saa5246a.c @@ -40,7 +40,6 @@ #include #include -#include #include #include #include @@ -817,7 +816,7 @@ static void __exit cleanup_saa_5246a (vo module_init(init_saa_5246a); module_exit(cleanup_saa_5246a); -static struct file_operations saa_fops = { +static const struct file_operations saa_fops = { .owner = THIS_MODULE, .open = saa5246a_open, .release = saa5246a_release, diff --git a/drivers/media/video/saa5249.c b/drivers/media/video/saa5249.c index bb3fb43..3e84737 100644 --- a/drivers/media/video/saa5249.c +++ b/drivers/media/video/saa5249.c @@ -699,7 +699,7 @@ static void __exit cleanup_saa_5249 (voi module_init(init_saa_5249); module_exit(cleanup_saa_5249); -static struct file_operations saa_fops = { +static const struct file_operations saa_fops = { .owner = THIS_MODULE, .open = saa5249_open, .release = saa5249_release, diff --git a/drivers/media/video/saa7111.c b/drivers/media/video/saa7111.c index 686fd47..44dc747 100644 --- a/drivers/media/video/saa7111.c +++ b/drivers/media/video/saa7111.c @@ -41,7 +41,6 @@ #include #include #include #include -#include #include #include diff --git a/drivers/media/video/saa7114.c b/drivers/media/video/saa7114.c index 90398ab..2ce3321 100644 --- a/drivers/media/video/saa7114.c +++ b/drivers/media/video/saa7114.c @@ -44,7 +44,6 @@ #include #include #include #include -#include #include #include diff --git a/drivers/media/video/saa711x.c b/drivers/media/video/saa711x.c index 708fae5..269d711 100644 --- a/drivers/media/video/saa711x.c +++ b/drivers/media/video/saa711x.c @@ -35,7 +35,6 @@ #include #include #include #include -#include #include #include #include diff --git a/drivers/media/video/saa7134/saa6752hs.c b/drivers/media/video/saa7134/saa6752hs.c index afc8f35..57f1f5d 100644 --- a/drivers/media/video/saa7134/saa6752hs.c +++ b/drivers/media/video/saa7134/saa6752hs.c @@ -1,6 +1,5 @@ #include #include -#include #include #include #include diff --git a/drivers/media/video/saa7134/saa7134-empress.c b/drivers/media/video/saa7134/saa7134-empress.c index daaae87..f521603 100644 --- a/drivers/media/video/saa7134/saa7134-empress.c +++ b/drivers/media/video/saa7134/saa7134-empress.c @@ -319,7 +319,7 @@ static int ts_ioctl(struct inode *inode, return video_usercopy(inode, file, cmd, arg, ts_do_ioctl); } -static struct file_operations ts_fops = +static const struct file_operations ts_fops = { .owner = THIS_MODULE, .open = ts_open, diff --git a/drivers/media/video/saa7134/saa7134-input.c b/drivers/media/video/saa7134/saa7134-input.c index 60b38de..e425268 100644 --- a/drivers/media/video/saa7134/saa7134-input.c +++ b/drivers/media/video/saa7134/saa7134-input.c @@ -22,7 +22,6 @@ #include #include #include #include -#include #include #include diff --git a/drivers/media/video/saa7134/saa7134-oss.c b/drivers/media/video/saa7134/saa7134-oss.c index bfcb860..72444f0 100644 --- a/drivers/media/video/saa7134/saa7134-oss.c +++ b/drivers/media/video/saa7134/saa7134-oss.c @@ -563,7 +563,7 @@ static unsigned int dsp_poll(struct file return mask; } -struct file_operations saa7134_dsp_fops = { +const struct file_operations saa7134_dsp_fops = { .owner = THIS_MODULE, .open = dsp_open, .release = dsp_release, @@ -804,7 +804,7 @@ static int mixer_ioctl(struct inode *ino } } -struct file_operations saa7134_mixer_fops = { +const struct file_operations saa7134_mixer_fops = { .owner = THIS_MODULE, .open = mixer_open, .release = mixer_release, diff --git a/drivers/media/video/saa7134/saa7134-video.c b/drivers/media/video/saa7134/saa7134-video.c index 830617e..f2cb630 100644 --- a/drivers/media/video/saa7134/saa7134-video.c +++ b/drivers/media/video/saa7134/saa7134-video.c @@ -2336,7 +2336,7 @@ static int radio_ioctl(struct inode *ino return video_usercopy(inode, file, cmd, arg, radio_do_ioctl); } -static struct file_operations video_fops = +static const struct file_operations video_fops = { .owner = THIS_MODULE, .open = video_open, @@ -2349,7 +2349,7 @@ static struct file_operations video_fops .llseek = no_llseek, }; -static struct file_operations radio_fops = +static const struct file_operations radio_fops = { .owner = THIS_MODULE, .open = video_open, diff --git a/drivers/media/video/saa7134/saa7134.h b/drivers/media/video/saa7134/saa7134.h index e88ad7b..88cd129 100644 --- a/drivers/media/video/saa7134/saa7134.h +++ b/drivers/media/video/saa7134/saa7134.h @@ -683,8 +683,8 @@ int saa_dsp_writel(struct saa7134_dev *d /* ----------------------------------------------------------- */ /* saa7134-oss.c */ -extern struct file_operations saa7134_dsp_fops; -extern struct file_operations saa7134_mixer_fops; +extern const struct file_operations saa7134_dsp_fops; +extern const struct file_operations saa7134_mixer_fops; int saa7134_oss_init1(struct saa7134_dev *dev); int saa7134_oss_fini(struct saa7134_dev *dev); diff --git a/drivers/media/video/saa7185.c b/drivers/media/video/saa7185.c index 9c30841..e0fdb1a 100644 --- a/drivers/media/video/saa7185.c +++ b/drivers/media/video/saa7185.c @@ -38,7 +38,6 @@ #include #include #include #include -#include #include #include diff --git a/drivers/media/video/saa7191.c b/drivers/media/video/saa7191.c index 746cadb..8615a60 100644 --- a/drivers/media/video/saa7191.c +++ b/drivers/media/video/saa7191.c @@ -17,7 +17,6 @@ #include #include #include #include -#include #include #include diff --git a/drivers/media/video/se401.c b/drivers/media/video/se401.c index 7aeec57..038448f 100644 --- a/drivers/media/video/se401.c +++ b/drivers/media/video/se401.c @@ -1185,7 +1185,7 @@ static int se401_mmap(struct file *file, return 0; } -static struct file_operations se401_fops = { +static const struct file_operations se401_fops = { .owner = THIS_MODULE, .open = se401_open, .release = se401_close, diff --git a/drivers/media/video/sn9c102/sn9c102_core.c b/drivers/media/video/sn9c102/sn9c102_core.c index 18458d4..04d4c8f 100644 --- a/drivers/media/video/sn9c102/sn9c102_core.c +++ b/drivers/media/video/sn9c102/sn9c102_core.c @@ -2736,7 +2736,7 @@ static int sn9c102_ioctl(struct inode* i /*****************************************************************************/ -static struct file_operations sn9c102_fops = { +static const struct file_operations sn9c102_fops = { .owner = THIS_MODULE, .open = sn9c102_open, .release = sn9c102_release, diff --git a/drivers/media/video/stradis.c b/drivers/media/video/stradis.c index 525d812..3e736be 100644 --- a/drivers/media/video/stradis.c +++ b/drivers/media/video/stradis.c @@ -1901,7 +1901,7 @@ static int saa_release(struct inode *ino return 0; } -static struct file_operations saa_fops = { +static const struct file_operations saa_fops = { .owner = THIS_MODULE, .open = saa_open, .release = saa_release, diff --git a/drivers/media/video/stv680.c b/drivers/media/video/stv680.c index a1ec3ac..bf3aa8d 100644 --- a/drivers/media/video/stv680.c +++ b/drivers/media/video/stv680.c @@ -1380,7 +1380,7 @@ static ssize_t stv680_read (struct file return realcount; } /* stv680_read */ -static struct file_operations stv680_fops = { +static const struct file_operations stv680_fops = { .owner = THIS_MODULE, .open = stv_open, .release = stv_close, diff --git a/drivers/media/video/tda7432.c b/drivers/media/video/tda7432.c index 78e043a..d1ccc06 100644 --- a/drivers/media/video/tda7432.c +++ b/drivers/media/video/tda7432.c @@ -38,7 +38,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/media/video/tda9875.c b/drivers/media/video/tda9875.c index 827633b..00f0e8b 100644 --- a/drivers/media/video/tda9875.c +++ b/drivers/media/video/tda9875.c @@ -19,7 +19,6 @@ #include #include -#include #include #include #include diff --git a/drivers/media/video/tuner-core.c b/drivers/media/video/tuner-core.c index ee4a493..7be73e3 100644 --- a/drivers/media/video/tuner-core.c +++ b/drivers/media/video/tuner-core.c @@ -7,7 +7,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/media/video/tvmixer.c b/drivers/media/video/tvmixer.c index 1654576..7ea9132 100644 --- a/drivers/media/video/tvmixer.c +++ b/drivers/media/video/tvmixer.c @@ -4,7 +4,6 @@ #include #include #include -#include #include #include #include @@ -228,7 +227,7 @@ static struct i2c_driver driver = { .detach_client = tvmixer_clients, }; -static struct file_operations tvmixer_fops = { +static const struct file_operations tvmixer_fops = { .owner = THIS_MODULE, .llseek = no_llseek, .ioctl = tvmixer_ioctl, diff --git a/drivers/media/video/usbvideo/ibmcam.c b/drivers/media/video/usbvideo/ibmcam.c index 76f771b..14db95e 100644 --- a/drivers/media/video/usbvideo/ibmcam.c +++ b/drivers/media/video/usbvideo/ibmcam.c @@ -15,7 +15,6 @@ */ #include -#include #include #include diff --git a/drivers/media/video/usbvideo/ultracam.c b/drivers/media/video/usbvideo/ultracam.c index 10c58b4..95453c1 100644 --- a/drivers/media/video/usbvideo/ultracam.c +++ b/drivers/media/video/usbvideo/ultracam.c @@ -6,7 +6,6 @@ */ #include -#include #include #include diff --git a/drivers/media/video/usbvideo/usbvideo.c b/drivers/media/video/usbvideo/usbvideo.c index b560c9d..d34d8c8 100644 --- a/drivers/media/video/usbvideo/usbvideo.c +++ b/drivers/media/video/usbvideo/usbvideo.c @@ -945,7 +945,7 @@ static int usbvideo_find_struct(struct u return rv; } -static struct file_operations usbvideo_fops = { +static const struct file_operations usbvideo_fops = { .owner = THIS_MODULE, .open = usbvideo_v4l_open, .release =usbvideo_v4l_close, diff --git a/drivers/media/video/usbvideo/vicam.c b/drivers/media/video/usbvideo/vicam.c index 08f9559..876fd27 100644 --- a/drivers/media/video/usbvideo/vicam.c +++ b/drivers/media/video/usbvideo/vicam.c @@ -1234,7 +1234,7 @@ static inline void vicam_create_proc_ent static inline void vicam_destroy_proc_entry(void *ptr) { } #endif -static struct file_operations vicam_fops = { +static const struct file_operations vicam_fops = { .owner = THIS_MODULE, .open = vicam_open, .release = vicam_close, diff --git a/drivers/media/video/usbvision/usbvision-core.c b/drivers/media/video/usbvision/usbvision-core.c index a807d97..901f664 100644 --- a/drivers/media/video/usbvision/usbvision-core.c +++ b/drivers/media/video/usbvision/usbvision-core.c @@ -24,7 +24,6 @@ */ #include -#include #include #include #include diff --git a/drivers/media/video/usbvision/usbvision-i2c.c b/drivers/media/video/usbvision/usbvision-i2c.c index 858252c..609e1fd 100644 --- a/drivers/media/video/usbvision/usbvision-i2c.c +++ b/drivers/media/video/usbvision/usbvision-i2c.c @@ -34,7 +34,6 @@ #include #include #include #include -#include #include #include #include "usbvision.h" @@ -258,6 +257,7 @@ int usbvision_init_i2c(struct usb_usbvis sprintf(usbvision->i2c_adap.name + strlen(usbvision->i2c_adap.name), " #%d", usbvision->vdev->minor & 0x1f); PDEBUG(DBG_I2C,"Adaptername: %s", usbvision->i2c_adap.name); + usbvision->i2c_adap.dev.parent = &usbvision->dev->dev; i2c_set_adapdata(&usbvision->i2c_adap, usbvision); i2c_set_clientdata(&usbvision->i2c_client, usbvision); diff --git a/drivers/media/video/usbvision/usbvision-video.c b/drivers/media/video/usbvision/usbvision-video.c index 7243337..af33653 100644 --- a/drivers/media/video/usbvision/usbvision-video.c +++ b/drivers/media/video/usbvision/usbvision-video.c @@ -46,7 +46,6 @@ #include #include -#include #include #include #include @@ -1072,7 +1071,7 @@ static int usbvision_v4l2_ioctl(struct i } -static ssize_t usbvision_v4l2_read(struct file *file, char *buf, +static ssize_t usbvision_v4l2_read(struct file *file, char __user *buf, size_t count, loff_t *ppos) { struct video_device *dev = video_devdata(file); @@ -1475,7 +1474,7 @@ static int usbvision_vbi_ioctl(struct in // // Video template -static struct file_operations usbvision_fops = { +static const struct file_operations usbvision_fops = { .owner = THIS_MODULE, .open = usbvision_v4l2_open, .release = usbvision_v4l2_close, @@ -1496,7 +1495,7 @@ static struct video_device usbvision_vid // Radio template -static struct file_operations usbvision_radio_fops = { +static const struct file_operations usbvision_radio_fops = { .owner = THIS_MODULE, .open = usbvision_radio_open, .release = usbvision_radio_close, @@ -1517,7 +1516,7 @@ static struct video_device usbvision_rad // vbi template -static struct file_operations usbvision_vbi_fops = { +static const struct file_operations usbvision_vbi_fops = { .owner = THIS_MODULE, .open = usbvision_vbi_open, .release = usbvision_vbi_close, diff --git a/drivers/media/video/v4l2-common.c b/drivers/media/video/v4l2-common.c index b87d571..b8ee37d 100644 --- a/drivers/media/video/v4l2-common.c +++ b/drivers/media/video/v4l2-common.c @@ -47,7 +47,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/media/video/videodev.c b/drivers/media/video/videodev.c index 6a0e8ca..a786c1f 100644 --- a/drivers/media/video/videodev.c +++ b/drivers/media/video/videodev.c @@ -30,7 +30,6 @@ #define dbgarg2(fmt, arg...) \ #include #include #include -#include #include #include #include @@ -1561,7 +1560,7 @@ out: } -static struct file_operations video_fops; +static const struct file_operations video_fops; /** * video_register_device - register video4linux devices @@ -1709,7 +1708,7 @@ void video_unregister_device(struct vide /* * Video fs operations */ -static struct file_operations video_fops= +static const struct file_operations video_fops= { .owner = THIS_MODULE, .llseek = no_llseek, diff --git a/drivers/media/video/vino.c b/drivers/media/video/vino.c index a373c14..0c658b7 100644 --- a/drivers/media/video/vino.c +++ b/drivers/media/video/vino.c @@ -4390,7 +4390,7 @@ static int vino_ioctl(struct inode *inod // __initdata static int vino_init_stage = 0; -static struct file_operations vino_fops = { +static const struct file_operations vino_fops = { .owner = THIS_MODULE, .open = vino_open, .release = vino_close, diff --git a/drivers/media/video/vivi.c b/drivers/media/video/vivi.c index d4cf556..cfb6b1f 100644 --- a/drivers/media/video/vivi.c +++ b/drivers/media/video/vivi.c @@ -1292,7 +1292,7 @@ vivi_mmap(struct file *file, struct vm_a return ret; } -static struct file_operations vivi_fops = { +static const struct file_operations vivi_fops = { .owner = THIS_MODULE, .open = vivi_open, .release = vivi_release, diff --git a/drivers/media/video/w9966.c b/drivers/media/video/w9966.c index 8d14f30..4736640 100644 --- a/drivers/media/video/w9966.c +++ b/drivers/media/video/w9966.c @@ -183,7 +183,7 @@ static int w9966_v4l_ioctl(struct inode static ssize_t w9966_v4l_read(struct file *file, char __user *buf, size_t count, loff_t *ppos); -static struct file_operations w9966_fops = { +static const struct file_operations w9966_fops = { .owner = THIS_MODULE, .open = video_exclusive_open, .release = video_exclusive_release, diff --git a/drivers/media/video/w9968cf.c b/drivers/media/video/w9968cf.c index 9f403af..8f31613 100644 --- a/drivers/media/video/w9968cf.c +++ b/drivers/media/video/w9968cf.c @@ -399,7 +399,7 @@ #endif /* W9968CF_DEBUG */ ****************************************************************************/ /* Video4linux interface */ -static struct file_operations w9968cf_fops; +static const struct file_operations w9968cf_fops; static int w9968cf_open(struct inode*, struct file*); static int w9968cf_release(struct inode*, struct file*); static int w9968cf_mmap(struct file*, struct vm_area_struct*); @@ -1573,6 +1573,7 @@ static int w9968cf_i2c_init(struct w9968 memcpy(&cam->i2c_adapter, &adap, sizeof(struct i2c_adapter)); strcpy(cam->i2c_adapter.name, "w9968cf"); + cam->i2c_adapter.dev.parent = &cam->usbdev->dev; i2c_set_adapdata(&cam->i2c_adapter, cam); DBG(6, "Registering I2C adapter with kernel...") @@ -3466,7 +3467,7 @@ ioctl_fail: } -static struct file_operations w9968cf_fops = { +static const struct file_operations w9968cf_fops = { .owner = THIS_MODULE, .open = w9968cf_open, .release = w9968cf_release, diff --git a/drivers/media/video/zc0301/zc0301_core.c b/drivers/media/video/zc0301/zc0301_core.c index 52d0f75..8da7f15 100644 --- a/drivers/media/video/zc0301/zc0301_core.c +++ b/drivers/media/video/zc0301/zc0301_core.c @@ -1871,7 +1871,7 @@ static int zc0301_ioctl(struct inode* in } -static struct file_operations zc0301_fops = { +static const struct file_operations zc0301_fops = { .owner = THIS_MODULE, .open = zc0301_open, .release = zc0301_release, diff --git a/drivers/media/video/zc0301/zc0301_sensor.h b/drivers/media/video/zc0301/zc0301_sensor.h index 4363a91..3daf049 100644 --- a/drivers/media/video/zc0301/zc0301_sensor.h +++ b/drivers/media/video/zc0301/zc0301_sensor.h @@ -75,7 +75,6 @@ static const struct usb_device_id zc0301 { ZC0301_USB_DEVICE(0x046d, 0x08ae, 0xff), }, /* PAS202 */ \ { ZC0301_USB_DEVICE(0x055f, 0xd003, 0xff), }, /* TAS5130 */ \ { ZC0301_USB_DEVICE(0x055f, 0xd004, 0xff), }, /* TAS5130 */ \ - { ZC0301_USB_DEVICE(0x046d, 0x08ae, 0xff), }, /* PAS202 */ \ { ZC0301_USB_DEVICE(0x0ac8, 0x0301, 0xff), }, \ { ZC0301_USB_DEVICE(0x0ac8, 0x301b, 0xff), }, /* PB-0330/HV7131 */ \ { ZC0301_USB_DEVICE(0x0ac8, 0x303b, 0xff), }, /* PB-0330 */ \ diff --git a/drivers/media/video/zoran_card.c b/drivers/media/video/zoran_card.c index 4d1eb2f..73162a3 100644 --- a/drivers/media/video/zoran_card.c +++ b/drivers/media/video/zoran_card.c @@ -843,6 +843,7 @@ zoran_register_i2c (struct zoran *zr) sizeof(I2C_NAME(&zr->i2c_adapter)) - 1); i2c_set_adapdata(&zr->i2c_adapter, zr); zr->i2c_adapter.algo_data = &zr->i2c_algo; + zr->i2c_adapter.dev.parent = &zr->pci_dev->dev; return i2c_bit_add_bus(&zr->i2c_adapter); } diff --git a/drivers/media/video/zoran_driver.c b/drivers/media/video/zoran_driver.c index 862a984..0743237 100644 --- a/drivers/media/video/zoran_driver.c +++ b/drivers/media/video/zoran_driver.c @@ -562,7 +562,6 @@ jpg_fbuffer_alloc (struct file *file) jpg_fbuffer_free(file); return -ENOBUFS; } - memset((void *) mem, 0, PAGE_SIZE); fh->jpg_buffers.buffer[i].frag_tab = (u32 *) mem; fh->jpg_buffers.buffer[i].frag_tab_bus = virt_to_bus((void *) mem); @@ -4680,7 +4679,7 @@ zoran_mmap (struct file *file, return 0; } -static struct file_operations zoran_fops = { +static const struct file_operations zoran_fops = { .owner = THIS_MODULE, .open = zoran_open, .release = zoran_close, diff --git a/drivers/media/video/zoran_procfs.c b/drivers/media/video/zoran_procfs.c index c374c76..446ae8d 100644 --- a/drivers/media/video/zoran_procfs.c +++ b/drivers/media/video/zoran_procfs.c @@ -186,7 +186,7 @@ static ssize_t zoran_write(struct file * return count; } -static struct file_operations zoran_operations = { +static const struct file_operations zoran_operations = { .open = zoran_open, .read = seq_read, .write = zoran_write, diff --git a/drivers/message/fusion/Kconfig b/drivers/message/fusion/Kconfig index ea31d84..71037f9 100644 --- a/drivers/message/fusion/Kconfig +++ b/drivers/message/fusion/Kconfig @@ -66,7 +66,7 @@ config FUSION_MAX_SGE config FUSION_CTL tristate "Fusion MPT misc device (ioctl) driver" - depends on FUSION_SPI || FUSION_FC + depends on FUSION_SPI || FUSION_FC || FUSION_SAS ---help--- The Fusion MPT misc device driver provides specialized control of MPT adapters via system ioctl calls. Use of ioctl calls to diff --git a/drivers/message/fusion/Makefile b/drivers/message/fusion/Makefile index 3416913..6003b46 100644 --- a/drivers/message/fusion/Makefile +++ b/drivers/message/fusion/Makefile @@ -8,6 +8,9 @@ #EXTRA_CFLAGS += -DMPT_DEBUG_VERBOSE_EVE #EXTRA_CFLAGS += -DMPT_DEBUG_INIT #EXTRA_CFLAGS += -DMPT_DEBUG_EXIT #EXTRA_CFLAGS += -DMPT_DEBUG_FAIL +#EXTRA_CFLAGS += -DMPT_DEBUG_DV +#EXTRA_CFLAGS += -DMPT_DEBUG_TM +#EXTRA_CFLAGS += -DMPT_DEBUG_REPLY # # driver/module specifics... @@ -20,11 +23,7 @@ #CFLAGS_mptbase.o += -DMPT_DEBUG_IRQ #CFLAGS_mptbase.o += -DMPT_DEBUG_RESET # # For mptscsih: -#CFLAGS_mptscsih.o += -DMPT_DEBUG_DV -#CFLAGS_mptscsih.o += -DMPT_DEBUG_NEGO -#CFLAGS_mptscsih.o += -DMPT_DEBUG_TM #CFLAGS_mptscsih.o += -DMPT_DEBUG_SCSI -#CFLAGS_mptscsih.o += -DMPT_DEBUG_REPLY # # For mptctl: #CFLAGS_mptctl.o += -DMPT_DEBUG_IOCTL diff --git a/drivers/message/fusion/lsi/mpi.h b/drivers/message/fusion/lsi/mpi.h index 81ad776..75223bf 100644 --- a/drivers/message/fusion/lsi/mpi.h +++ b/drivers/message/fusion/lsi/mpi.h @@ -1,12 +1,12 @@ /* - * Copyright (c) 2000-2005 LSI Logic Corporation. + * Copyright (c) 2000-2006 LSI Logic Corporation. * * * Name: mpi.h * Title: MPI Message independent structures and definitions * Creation Date: July 27, 2000 * - * mpi.h Version: 01.05.11 + * mpi.h Version: 01.05.12 * * Version History * --------------- @@ -77,6 +77,7 @@ * 08-03-05 01.05.09 Bumped MPI_HEADER_VERSION_UNIT. * 08-30-05 01.05.10 Added 2 new IOCStatus codes for Target. * 03-27-06 01.05.11 Bumped MPI_HEADER_VERSION_UNIT. + * 10-11-06 01.05.12 Bumped MPI_HEADER_VERSION_UNIT. * -------------------------------------------------------------------------- */ @@ -107,7 +108,7 @@ #define MPI_VERSION_01_05 /* Note: The major versions of 0xe0 through 0xff are reserved */ /* versioning for this MPI header set */ -#define MPI_HEADER_VERSION_UNIT (0x0D) +#define MPI_HEADER_VERSION_UNIT (0x0E) #define MPI_HEADER_VERSION_DEV (0x00) #define MPI_HEADER_VERSION_UNIT_MASK (0xFF00) #define MPI_HEADER_VERSION_UNIT_SHIFT (8) diff --git a/drivers/message/fusion/lsi/mpi_cnfg.h b/drivers/message/fusion/lsi/mpi_cnfg.h index 47e13e3..0e4c8e7 100644 --- a/drivers/message/fusion/lsi/mpi_cnfg.h +++ b/drivers/message/fusion/lsi/mpi_cnfg.h @@ -1,12 +1,12 @@ /* - * Copyright (c) 2000-2005 LSI Logic Corporation. + * Copyright (c) 2000-2006 LSI Logic Corporation. * * * Name: mpi_cnfg.h * Title: MPI Config message, structures, and Pages * Creation Date: July 27, 2000 * - * mpi_cnfg.h Version: 01.05.12 + * mpi_cnfg.h Version: 01.05.13 * * Version History * --------------- @@ -276,6 +276,23 @@ * Added AdditionalControlFlags, MaxTargetPortConnectTime, * ReportDeviceMissingDelay, and IODeviceMissingDelay * fields to SAS IO Unit Page 1. + * 10-11-06 01.05.13 Added NumForceWWID field and ForceWWID array to + * Manufacturing Page 5. + * Added Manufacturing pages 8 through 10. + * Added defines for supported metadata size bits in + * CapabilitiesFlags field of IOC Page 6. + * Added defines for metadata size bits in VolumeSettings + * field of RAID Volume Page 0. + * Added SATA Link Reset settings, Enable SATA Asynchronous + * Notification bit, and HideNonZeroAttachedPhyIdentifiers + * bit to AdditionalControlFlags field of SAS IO Unit + * Page 1. + * Added defines for Enclosure Devices Unmapped and + * Device Limit Exceeded bits in Status field of SAS IO + * Unit Page 2. + * Added more AccessStatus values for SAS Device Page 0. + * Added bit for SATA Asynchronous Notification Support in + * Flags field of SAS Device Page 0. * -------------------------------------------------------------------------- */ @@ -654,17 +671,24 @@ #define MPI_MANPAGE4_IM_RESYNC_CACHE_ENA #define MPI_MANPAGE4_IR_NO_MIX_SAS_SATA (0x01) +#ifndef MPI_MANPAGE5_NUM_FORCEWWID +#define MPI_MANPAGE5_NUM_FORCEWWID (1) +#endif + typedef struct _CONFIG_PAGE_MANUFACTURING_5 { CONFIG_PAGE_HEADER Header; /* 00h */ U64 BaseWWID; /* 04h */ U8 Flags; /* 0Ch */ - U8 Reserved1; /* 0Dh */ + U8 NumForceWWID; /* 0Dh */ U16 Reserved2; /* 0Eh */ + U32 Reserved3; /* 10h */ + U32 Reserved4; /* 14h */ + U64 ForceWWID[MPI_MANPAGE5_NUM_FORCEWWID]; /* 18h */ } CONFIG_PAGE_MANUFACTURING_5, MPI_POINTER PTR_CONFIG_PAGE_MANUFACTURING_5, ManufacturingPage5_t, MPI_POINTER pManufacturingPage5_t; -#define MPI_MANUFACTURING5_PAGEVERSION (0x01) +#define MPI_MANUFACTURING5_PAGEVERSION (0x02) /* defines for the Flags field */ #define MPI_MANPAGE5_TWO_WWID_PER_PHY (0x01) @@ -740,6 +764,36 @@ #define MPI_MANUFACTURING7_PAGEVERSION #define MPI_MANPAGE7_FLAG_USE_SLOT_INFO (0x00000001) +typedef struct _CONFIG_PAGE_MANUFACTURING_8 +{ + CONFIG_PAGE_HEADER Header; /* 00h */ + U32 ProductSpecificInfo;/* 04h */ +} CONFIG_PAGE_MANUFACTURING_8, MPI_POINTER PTR_CONFIG_PAGE_MANUFACTURING_8, + ManufacturingPage8_t, MPI_POINTER pManufacturingPage8_t; + +#define MPI_MANUFACTURING8_PAGEVERSION (0x00) + + +typedef struct _CONFIG_PAGE_MANUFACTURING_9 +{ + CONFIG_PAGE_HEADER Header; /* 00h */ + U32 ProductSpecificInfo;/* 04h */ +} CONFIG_PAGE_MANUFACTURING_9, MPI_POINTER PTR_CONFIG_PAGE_MANUFACTURING_9, + ManufacturingPage9_t, MPI_POINTER pManufacturingPage9_t; + +#define MPI_MANUFACTURING6_PAGEVERSION (0x00) + + +typedef struct _CONFIG_PAGE_MANUFACTURING_10 +{ + CONFIG_PAGE_HEADER Header; /* 00h */ + U32 ProductSpecificInfo;/* 04h */ +} CONFIG_PAGE_MANUFACTURING_10, MPI_POINTER PTR_CONFIG_PAGE_MANUFACTURING_10, + ManufacturingPage10_t, MPI_POINTER pManufacturingPage10_t; + +#define MPI_MANUFACTURING10_PAGEVERSION (0x00) + + /**************************************************************************** * IO Unit Config Pages ****************************************************************************/ @@ -1080,10 +1134,14 @@ typedef struct _CONFIG_PAGE_IOC_6 } CONFIG_PAGE_IOC_6, MPI_POINTER PTR_CONFIG_PAGE_IOC_6, IOCPage6_t, MPI_POINTER pIOCPage6_t; -#define MPI_IOCPAGE6_PAGEVERSION (0x00) +#define MPI_IOCPAGE6_PAGEVERSION (0x01) /* IOC Page 6 Capabilities Flags */ +#define MPI_IOCPAGE6_CAP_FLAGS_MASK_METADATA_SIZE (0x00000006) +#define MPI_IOCPAGE6_CAP_FLAGS_64MB_METADATA_SIZE (0x00000000) +#define MPI_IOCPAGE6_CAP_FLAGS_512MB_METADATA_SIZE (0x00000002) + #define MPI_IOCPAGE6_CAP_FLAGS_GLOBAL_HOT_SPARE (0x00000001) @@ -2160,6 +2218,11 @@ #define MPI_RAIDVOL0_SETTING_OFFLINE_ON_ #define MPI_RAIDVOL0_SETTING_AUTO_CONFIGURE (0x0004) #define MPI_RAIDVOL0_SETTING_PRIORITY_RESYNC (0x0008) #define MPI_RAIDVOL0_SETTING_FAST_DATA_SCRUBBING_0102 (0x0020) /* obsolete */ + +#define MPI_RAIDVOL0_SETTING_MASK_METADATA_SIZE (0x00C0) +#define MPI_RAIDVOL0_SETTING_64MB_METADATA_SIZE (0x0000) +#define MPI_RAIDVOL0_SETTING_512MB_METADATA_SIZE (0x0040) + #define MPI_RAIDVOL0_SETTING_USE_PRODUCT_ID_SUFFIX (0x0010) #define MPI_RAIDVOL0_SETTING_USE_DEFAULTS (0x8000) @@ -2203,7 +2266,7 @@ typedef struct _CONFIG_PAGE_RAID_VOL_0 } CONFIG_PAGE_RAID_VOL_0, MPI_POINTER PTR_CONFIG_PAGE_RAID_VOL_0, RaidVolumePage0_t, MPI_POINTER pRaidVolumePage0_t; -#define MPI_RAIDVOLPAGE0_PAGEVERSION (0x06) +#define MPI_RAIDVOLPAGE0_PAGEVERSION (0x07) /* values for RAID Volume Page 0 InactiveStatus field */ #define MPI_RAIDVOLPAGE0_UNKNOWN_INACTIVE (0x00) @@ -2518,7 +2581,7 @@ typedef struct _CONFIG_PAGE_SAS_IO_UNIT_ } CONFIG_PAGE_SAS_IO_UNIT_1, MPI_POINTER PTR_CONFIG_PAGE_SAS_IO_UNIT_1, SasIOUnitPage1_t, MPI_POINTER pSasIOUnitPage1_t; -#define MPI_SASIOUNITPAGE1_PAGEVERSION (0x06) +#define MPI_SASIOUNITPAGE1_PAGEVERSION (0x07) /* values for SAS IO Unit Page 1 ControlFlags */ #define MPI_SAS_IOUNIT1_CONTROL_DEVICE_SELF_TEST (0x8000) @@ -2544,7 +2607,13 @@ #define MPI_SAS_IOUNIT1_CONTROL_FIRST_LV #define MPI_SAS_IOUNIT1_CONTROL_CLEAR_AFFILIATION (0x0001) /* values for SAS IO Unit Page 1 AdditionalControlFlags */ -#define MPI_SAS_IOUNIT1_ACONTROL_ALLOW_TABLE_TO_TABLE (0x0001) +#define MPI_SAS_IOUNIT1_ACONTROL_SATA_ASYNCHROUNOUS_NOTIFICATION (0x0040) +#define MPI_SAS_IOUNIT1_ACONTROL_HIDE_NONZERO_ATTACHED_PHY_IDENT (0x0020) +#define MPI_SAS_IOUNIT1_ACONTROL_PORT_ENABLE_ONLY_SATA_LINK_RESET (0x0010) +#define MPI_SAS_IOUNIT1_ACONTROL_OTHER_AFFILIATION_SATA_LINK_RESET (0x0008) +#define MPI_SAS_IOUNIT1_ACONTROL_SELF_AFFILIATION_SATA_LINK_RESET (0x0004) +#define MPI_SAS_IOUNIT1_ACONTROL_NO_AFFILIATION_SATA_LINK_RESET (0x0002) +#define MPI_SAS_IOUNIT1_ACONTROL_ALLOW_TABLE_TO_TABLE (0x0001) /* defines for SAS IO Unit Page 1 ReportDeviceMissingDelay */ #define MPI_SAS_IOUNIT1_REPORT_MISSING_TIMEOUT_MASK (0x7F) @@ -2585,9 +2654,11 @@ typedef struct _CONFIG_PAGE_SAS_IO_UNIT_ } CONFIG_PAGE_SAS_IO_UNIT_2, MPI_POINTER PTR_CONFIG_PAGE_SAS_IO_UNIT_2, SasIOUnitPage2_t, MPI_POINTER pSasIOUnitPage2_t; -#define MPI_SASIOUNITPAGE2_PAGEVERSION (0x05) +#define MPI_SASIOUNITPAGE2_PAGEVERSION (0x06) /* values for SAS IO Unit Page 2 Status field */ +#define MPI_SAS_IOUNIT2_STATUS_DEVICE_LIMIT_EXCEEDED (0x08) +#define MPI_SAS_IOUNIT2_STATUS_ENCLOSURE_DEVICES_UNMAPPED (0x04) #define MPI_SAS_IOUNIT2_STATUS_DISABLED_PERSISTENT_MAPPINGS (0x02) #define MPI_SAS_IOUNIT2_STATUS_FULL_PERSISTENT_MAPPINGS (0x01) @@ -2739,24 +2810,38 @@ typedef struct _CONFIG_PAGE_SAS_DEVICE_0 } CONFIG_PAGE_SAS_DEVICE_0, MPI_POINTER PTR_CONFIG_PAGE_SAS_DEVICE_0, SasDevicePage0_t, MPI_POINTER pSasDevicePage0_t; -#define MPI_SASDEVICE0_PAGEVERSION (0x04) +#define MPI_SASDEVICE0_PAGEVERSION (0x05) /* values for SAS Device Page 0 AccessStatus field */ -#define MPI_SAS_DEVICE0_ASTATUS_NO_ERRORS (0x00) -#define MPI_SAS_DEVICE0_ASTATUS_SATA_INIT_FAILED (0x01) -#define MPI_SAS_DEVICE0_ASTATUS_SATA_CAPABILITY_FAILED (0x02) +#define MPI_SAS_DEVICE0_ASTATUS_NO_ERRORS (0x00) +#define MPI_SAS_DEVICE0_ASTATUS_SATA_INIT_FAILED (0x01) +#define MPI_SAS_DEVICE0_ASTATUS_SATA_CAPABILITY_FAILED (0x02) +#define MPI_SAS_DEVICE0_ASTATUS_SATA_AFFILIATION_CONFLICT (0x03) +/* specific values for SATA Init failures */ +#define MPI_SAS_DEVICE0_ASTATUS_SIF_UNKNOWN (0x10) +#define MPI_SAS_DEVICE0_ASTATUS_SIF_AFFILIATION_CONFLICT (0x11) +#define MPI_SAS_DEVICE0_ASTATUS_SIF_DIAG (0x12) +#define MPI_SAS_DEVICE0_ASTATUS_SIF_IDENTIFICATION (0x13) +#define MPI_SAS_DEVICE0_ASTATUS_SIF_CHECK_POWER (0x14) +#define MPI_SAS_DEVICE0_ASTATUS_SIF_PIO_SN (0x15) +#define MPI_SAS_DEVICE0_ASTATUS_SIF_MDMA_SN (0x16) +#define MPI_SAS_DEVICE0_ASTATUS_SIF_UDMA_SN (0x17) +#define MPI_SAS_DEVICE0_ASTATUS_SIF_ZONING_VIOLATION (0x18) +#define MPI_SAS_DEVICE0_ASTATUS_SIF_NOT_ADDRESSABLE (0x19) +#define MPI_SAS_DEVICE0_ASTATUS_SIF_MAX (0x1F) /* values for SAS Device Page 0 Flags field */ -#define MPI_SAS_DEVICE0_FLAGS_SATA_SW_PRESERVE (0x0200) -#define MPI_SAS_DEVICE0_FLAGS_UNSUPPORTED_DEVICE (0x0100) -#define MPI_SAS_DEVICE0_FLAGS_SATA_48BIT_LBA_SUPPORTED (0x0080) -#define MPI_SAS_DEVICE0_FLAGS_SATA_SMART_SUPPORTED (0x0040) -#define MPI_SAS_DEVICE0_FLAGS_SATA_NCQ_SUPPORTED (0x0020) -#define MPI_SAS_DEVICE0_FLAGS_SATA_FUA_SUPPORTED (0x0010) -#define MPI_SAS_DEVICE0_FLAGS_PORT_SELECTOR_ATTACH (0x0008) -#define MPI_SAS_DEVICE0_FLAGS_MAPPING_PERSISTENT (0x0004) -#define MPI_SAS_DEVICE0_FLAGS_DEVICE_MAPPED (0x0002) -#define MPI_SAS_DEVICE0_FLAGS_DEVICE_PRESENT (0x0001) +#define MPI_SAS_DEVICE0_FLAGS_SATA_ASYNCHRONOUS_NOTIFY (0x0400) +#define MPI_SAS_DEVICE0_FLAGS_SATA_SW_PRESERVE (0x0200) +#define MPI_SAS_DEVICE0_FLAGS_UNSUPPORTED_DEVICE (0x0100) +#define MPI_SAS_DEVICE0_FLAGS_SATA_48BIT_LBA_SUPPORTED (0x0080) +#define MPI_SAS_DEVICE0_FLAGS_SATA_SMART_SUPPORTED (0x0040) +#define MPI_SAS_DEVICE0_FLAGS_SATA_NCQ_SUPPORTED (0x0020) +#define MPI_SAS_DEVICE0_FLAGS_SATA_FUA_SUPPORTED (0x0010) +#define MPI_SAS_DEVICE0_FLAGS_PORT_SELECTOR_ATTACH (0x0008) +#define MPI_SAS_DEVICE0_FLAGS_MAPPING_PERSISTENT (0x0004) +#define MPI_SAS_DEVICE0_FLAGS_DEVICE_MAPPED (0x0002) +#define MPI_SAS_DEVICE0_FLAGS_DEVICE_PRESENT (0x0001) /* see mpi_sas.h for values for SAS Device Page 0 DeviceInfo values */ diff --git a/drivers/message/fusion/lsi/mpi_history.txt b/drivers/message/fusion/lsi/mpi_history.txt index 582cfe7..d6b4c60 100644 --- a/drivers/message/fusion/lsi/mpi_history.txt +++ b/drivers/message/fusion/lsi/mpi_history.txt @@ -3,28 +3,28 @@ MPI Header File Change History ============================== - Copyright (c) 2000-2005 LSI Logic Corporation. + Copyright (c) 2000-2006 LSI Logic Corporation. --------------------------------------- - Header Set Release Version: 01.05.13 - Header Set Release Date: 03-27-06 + Header Set Release Version: 01.05.14 + Header Set Release Date: 10-11-06 --------------------------------------- Filename Current version Prior version ---------- --------------- ------------- - mpi.h 01.05.11 01.05.10 - mpi_ioc.h 01.05.11 01.05.10 - mpi_cnfg.h 01.05.12 01.05.11 - mpi_init.h 01.05.07 01.05.06 - mpi_targ.h 01.05.06 01.05.05 + mpi.h 01.05.12 01.05.11 + mpi_ioc.h 01.05.12 01.05.11 + mpi_cnfg.h 01.05.13 01.05.12 + mpi_init.h 01.05.08 01.05.07 + mpi_targ.h 01.05.06 01.05.06 mpi_fc.h 01.05.01 01.05.01 mpi_lan.h 01.05.01 01.05.01 mpi_raid.h 01.05.02 01.05.02 mpi_tool.h 01.05.03 01.05.03 mpi_inb.h 01.05.01 01.05.01 - mpi_sas.h 01.05.03 01.05.02 + mpi_sas.h 01.05.04 01.05.03 mpi_type.h 01.05.02 01.05.02 - mpi_history.txt 01.05.13 01.05.12 + mpi_history.txt 01.05.14 01.05.13 * Date Version Description @@ -94,6 +94,7 @@ mpi.h * 08-03-05 01.05.09 Bumped MPI_HEADER_VERSION_UNIT. * 08-30-05 01.05.10 Added 2 new IOCStatus codes for Target. * 03-27-06 01.05.11 Bumped MPI_HEADER_VERSION_UNIT. + * 10-11-06 01.05.12 Bumped MPI_HEADER_VERSION_UNIT. * -------------------------------------------------------------------------- mpi_ioc.h @@ -182,6 +183,14 @@ mpi_ioc.h * Added MPI_EVENT_SAS_INIT_TABLE_OVERFLOW and event * data structure. * Added MPI_EXT_IMAGE_TYPE_INITIALIZATION. + * 10-11-06 01.05.12 Added MPI_IOCFACTS_EXCEPT_METADATA_UNSUPPORTED. + * Added MaxInitiators field to PortFacts reply. + * Added SAS Device Status Change ReasonCode for + * asynchronous notificaiton. + * Added MPI_EVENT_SAS_EXPANDER_STATUS_CHANGE and event + * data structure. + * Added new ImageType values for FWDownload and FWUpload + * requests. * -------------------------------------------------------------------------- mpi_cnfg.h @@ -447,6 +456,23 @@ mpi_cnfg.h * Added AdditionalControlFlags, MaxTargetPortConnectTime, * ReportDeviceMissingDelay, and IODeviceMissingDelay * fields to SAS IO Unit Page 1. + * 10-11-06 01.05.13 Added NumForceWWID field and ForceWWID array to + * Manufacturing Page 5. + * Added Manufacturing pages 8 through 10. + * Added defines for supported metadata size bits in + * CapabilitiesFlags field of IOC Page 6. + * Added defines for metadata size bits in VolumeSettings + * field of RAID Volume Page 0. + * Added SATA Link Reset settings, Enable SATA Asynchronous + * Notification bit, and HideNonZeroAttachedPhyIdentifiers + * bit to AdditionalControlFlags field of SAS IO Unit + * Page 1. + * Added defines for Enclosure Devices Unmapped and + * Device Limit Exceeded bits in Status field of SAS IO + * Unit Page 2. + * Added more AccessStatus values for SAS Device Page 0. + * Added bit for SATA Asynchronous Notification Support in + * Flags field of SAS Device Page 0. * -------------------------------------------------------------------------- mpi_init.h @@ -490,6 +516,7 @@ mpi_init.h * 08-03-05 01.05.06 Fixed some MPI_SCSIIO32_MSGFLGS_ defines to make them * unique in the first 32 characters. * 03-27-06 01.05.07 Added Task Management type of Clear ACA. + * 10-11-06 01.05.08 Shortened define for Task Management type of Clear ACA. * -------------------------------------------------------------------------- mpi_targ.h @@ -638,6 +665,8 @@ mpi_sas.h * and Remove Device operations to SAS IO Unit Control. * Added DevHandle field to SAS IO Unit Control request and * reply. + * 10-11-06 01.05.04 Fixed the name of a define for Operation field of SAS IO + * Unit Control request. * -------------------------------------------------------------------------- mpi_type.h @@ -653,20 +682,20 @@ mpi_type.h mpi_history.txt Parts list history -Filename 01.05.13 01.05.12 01.05.11 01.05.10 01.05.09 ----------- -------- -------- -------- -------- -------- -mpi.h 01.05.11 01.05.10 01.05.09 01.05.08 01.05.07 -mpi_ioc.h 01.05.11 01.05.10 01.05.09 01.05.09 01.05.08 -mpi_cnfg.h 01.05.12 01.05.11 01.05.10 01.05.09 01.05.08 -mpi_init.h 01.05.07 01.05.06 01.05.06 01.05.05 01.05.04 -mpi_targ.h 01.05.06 01.05.05 01.05.05 01.05.05 01.05.04 -mpi_fc.h 01.05.01 01.05.01 01.05.01 01.05.01 01.05.01 -mpi_lan.h 01.05.01 01.05.01 01.05.01 01.05.01 01.05.01 -mpi_raid.h 01.05.02 01.05.02 01.05.02 01.05.02 01.05.02 -mpi_tool.h 01.05.03 01.05.03 01.05.03 01.05.03 01.05.03 -mpi_inb.h 01.05.01 01.05.01 01.05.01 01.05.01 01.05.01 -mpi_sas.h 01.05.03 01.05.02 01.05.01 01.05.01 01.05.01 -mpi_type.h 01.05.02 01.05.02 01.05.01 01.05.01 01.05.01 +Filename 01.05.13 01.05.13 01.05.12 01.05.11 01.05.10 01.05.09 +---------- -------- -------- -------- -------- -------- -------- +mpi.h 01.05.12 01.05.11 01.05.10 01.05.09 01.05.08 01.05.07 +mpi_ioc.h 01.05.12 01.05.11 01.05.10 01.05.09 01.05.09 01.05.08 +mpi_cnfg.h 01.05.13 01.05.12 01.05.11 01.05.10 01.05.09 01.05.08 +mpi_init.h 01.05.08 01.05.07 01.05.06 01.05.06 01.05.05 01.05.04 +mpi_targ.h 01.05.06 01.05.06 01.05.05 01.05.05 01.05.05 01.05.04 +mpi_fc.h 01.05.01 01.05.01 01.05.01 01.05.01 01.05.01 01.05.01 +mpi_lan.h 01.05.01 01.05.01 01.05.01 01.05.01 01.05.01 01.05.01 +mpi_raid.h 01.05.02 01.05.02 01.05.02 01.05.02 01.05.02 01.05.02 +mpi_tool.h 01.05.03 01.05.03 01.05.03 01.05.03 01.05.03 01.05.03 +mpi_inb.h 01.05.01 01.05.01 01.05.01 01.05.01 01.05.01 01.05.01 +mpi_sas.h 01.05.04 01.05.03 01.05.02 01.05.01 01.05.01 01.05.01 +mpi_type.h 01.05.02 01.05.02 01.05.02 01.05.01 01.05.01 01.05.01 Filename 01.05.08 01.05.07 01.05.06 01.05.05 01.05.04 01.05.03 ---------- -------- -------- -------- -------- -------- -------- diff --git a/drivers/message/fusion/lsi/mpi_init.h b/drivers/message/fusion/lsi/mpi_init.h index c1c6789..ec9dff2 100644 --- a/drivers/message/fusion/lsi/mpi_init.h +++ b/drivers/message/fusion/lsi/mpi_init.h @@ -1,12 +1,12 @@ /* - * Copyright (c) 2000-2005 LSI Logic Corporation. + * Copyright (c) 2000-2006 LSI Logic Corporation. * * * Name: mpi_init.h * Title: MPI initiator mode messages and structures * Creation Date: June 8, 2000 * - * mpi_init.h Version: 01.05.07 + * mpi_init.h Version: 01.05.08 * * Version History * --------------- @@ -53,6 +53,7 @@ * 08-03-05 01.05.06 Fixed some MPI_SCSIIO32_MSGFLGS_ defines to make them * unique in the first 32 characters. * 03-27-06 01.05.07 Added Task Management type of Clear ACA. + * 10-11-06 01.05.08 Shortened define for Task Management type of Clear ACA. * -------------------------------------------------------------------------- */ @@ -428,7 +429,7 @@ #define MPI_SCSITASKMGMT_TASKTYPE_RESET_ #define MPI_SCSITASKMGMT_TASKTYPE_LOGICAL_UNIT_RESET (0x05) #define MPI_SCSITASKMGMT_TASKTYPE_CLEAR_TASK_SET (0x06) #define MPI_SCSITASKMGMT_TASKTYPE_QUERY_TASK (0x07) -#define MPI_SCSITASKMGMT_TASKTYPE_CLEAR_ACA (0x08) +#define MPI_SCSITASKMGMT_TASKTYPE_CLR_ACA (0x08) /* MsgFlags bits */ #define MPI_SCSITASKMGMT_MSGFLAGS_TARGET_RESET_OPTION (0x00) diff --git a/drivers/message/fusion/lsi/mpi_ioc.h b/drivers/message/fusion/lsi/mpi_ioc.h index 18ba407..6c33e33 100644 --- a/drivers/message/fusion/lsi/mpi_ioc.h +++ b/drivers/message/fusion/lsi/mpi_ioc.h @@ -1,12 +1,12 @@ /* - * Copyright (c) 2000-2005 LSI Logic Corporation. + * Copyright (c) 2000-2006 LSI Logic Corporation. * * * Name: mpi_ioc.h * Title: MPI IOC, Port, Event, FW Download, and FW Upload messages * Creation Date: August 11, 2000 * - * mpi_ioc.h Version: 01.05.11 + * mpi_ioc.h Version: 01.05.12 * * Version History * --------------- @@ -98,6 +98,14 @@ * Added MPI_EVENT_SAS_INIT_TABLE_OVERFLOW and event * data structure. * Added MPI_EXT_IMAGE_TYPE_INITIALIZATION. + * 10-11-06 01.05.12 Added MPI_IOCFACTS_EXCEPT_METADATA_UNSUPPORTED. + * Added MaxInitiators field to PortFacts reply. + * Added SAS Device Status Change ReasonCode for + * asynchronous notificaiton. + * Added MPI_EVENT_SAS_EXPANDER_STATUS_CHANGE and event + * data structure. + * Added new ImageType values for FWDownload and FWUpload + * requests. * -------------------------------------------------------------------------- */ @@ -264,6 +272,7 @@ #define MPI_IOCFACTS_EXCEPT_CONFIG_CHECK #define MPI_IOCFACTS_EXCEPT_RAID_CONFIG_INVALID (0x0002) #define MPI_IOCFACTS_EXCEPT_FW_CHECKSUM_FAIL (0x0004) #define MPI_IOCFACTS_EXCEPT_PERSISTENT_TABLE_FULL (0x0008) +#define MPI_IOCFACTS_EXCEPT_METADATA_UNSUPPORTED (0x0010) #define MPI_IOCFACTS_FLAGS_FW_DOWNLOAD_BOOT (0x01) #define MPI_IOCFACTS_FLAGS_REPLY_FIFO_HOST_SIGNAL (0x02) @@ -328,7 +337,8 @@ typedef struct _MSG_PORT_FACTS_REPLY U16 MaxPostedCmdBuffers; /* 1Ch */ U16 MaxPersistentIDs; /* 1Eh */ U16 MaxLanBuckets; /* 20h */ - U16 Reserved4; /* 22h */ + U8 MaxInitiators; /* 22h */ + U8 Reserved4; /* 23h */ U32 Reserved5; /* 24h */ } MSG_PORT_FACTS_REPLY, MPI_POINTER PTR_MSG_PORT_FACTS_REPLY, PortFactsReply_t, MPI_POINTER pPortFactsReply_t; @@ -487,6 +497,7 @@ #define MPI_EVENT_SAS_BROADCAST_PRIMITIV #define MPI_EVENT_SAS_INIT_DEVICE_STATUS_CHANGE (0x00000018) #define MPI_EVENT_SAS_INIT_TABLE_OVERFLOW (0x00000019) #define MPI_EVENT_SAS_SMP_ERROR (0x0000001A) +#define MPI_EVENT_SAS_EXPANDER_STATUS_CHANGE (0x0000001B) #define MPI_EVENT_LOG_ENTRY_ADDED (0x00000021) /* AckRequired field values */ @@ -593,6 +604,7 @@ #define MPI_EVENT_SAS_DEV_STAT_RC_TASK_A #define MPI_EVENT_SAS_DEV_STAT_RC_ABORT_TASK_SET_INTERNAL (0x0A) #define MPI_EVENT_SAS_DEV_STAT_RC_CLEAR_TASK_SET_INTERNAL (0x0B) #define MPI_EVENT_SAS_DEV_STAT_RC_QUERY_TASK_INTERNAL (0x0C) +#define MPI_EVENT_SAS_DEV_STAT_RC_ASYNC_NOTIFICATION (0x0D) /* SCSI Event data for Queue Full event */ @@ -895,6 +907,54 @@ typedef struct _EVENT_DATA_SAS_INIT_TABL MpiEventDataSasInitTableOverflow_t, MPI_POINTER pMpiEventDataSasInitTableOverflow_t; +/* SAS Expander Status Change Event data */ + +typedef struct _EVENT_DATA_SAS_EXPANDER_STATUS_CHANGE +{ + U8 ReasonCode; /* 00h */ + U8 Reserved1; /* 01h */ + U16 Reserved2; /* 02h */ + U8 PhysicalPort; /* 04h */ + U8 Reserved3; /* 05h */ + U16 EnclosureHandle; /* 06h */ + U64 SASAddress; /* 08h */ + U32 DiscoveryStatus; /* 10h */ + U16 DevHandle; /* 14h */ + U16 ParentDevHandle; /* 16h */ + U16 ExpanderChangeCount; /* 18h */ + U16 ExpanderRouteIndexes; /* 1Ah */ + U8 NumPhys; /* 1Ch */ + U8 SASLevel; /* 1Dh */ + U8 Flags; /* 1Eh */ + U8 Reserved4; /* 1Fh */ +} EVENT_DATA_SAS_EXPANDER_STATUS_CHANGE, + MPI_POINTER PTR_EVENT_DATA_SAS_EXPANDER_STATUS_CHANGE, + MpiEventDataSasExpanderStatusChange_t, + MPI_POINTER pMpiEventDataSasExpanderStatusChange_t; + +/* values for ReasonCode field of SAS Expander Status Change Event data */ +#define MPI_EVENT_SAS_EXP_RC_ADDED (0x00) +#define MPI_EVENT_SAS_EXP_RC_NOT_RESPONDING (0x01) + +/* values for DiscoveryStatus field of SAS Expander Status Change Event data */ +#define MPI_EVENT_SAS_EXP_DS_LOOP_DETECTED (0x00000001) +#define MPI_EVENT_SAS_EXP_DS_UNADDRESSABLE_DEVICE (0x00000002) +#define MPI_EVENT_SAS_EXP_DS_MULTIPLE_PORTS (0x00000004) +#define MPI_EVENT_SAS_EXP_DS_EXPANDER_ERR (0x00000008) +#define MPI_EVENT_SAS_EXP_DS_SMP_TIMEOUT (0x00000010) +#define MPI_EVENT_SAS_EXP_DS_OUT_ROUTE_ENTRIES (0x00000020) +#define MPI_EVENT_SAS_EXP_DS_INDEX_NOT_EXIST (0x00000040) +#define MPI_EVENT_SAS_EXP_DS_SMP_FUNCTION_FAILED (0x00000080) +#define MPI_EVENT_SAS_EXP_DS_SMP_CRC_ERROR (0x00000100) +#define MPI_EVENT_SAS_EXP_DS_SUBTRACTIVE_LINK (0x00000200) +#define MPI_EVENT_SAS_EXP_DS_TABLE_LINK (0x00000400) +#define MPI_EVENT_SAS_EXP_DS_UNSUPPORTED_DEVICE (0x00000800) + +/* values for Flags field of SAS Expander Status Change Event data */ +#define MPI_EVENT_SAS_EXP_FLAGS_ROUTE_TABLE_CONFIG (0x02) +#define MPI_EVENT_SAS_EXP_FLAGS_CONFIG_IN_PROGRESS (0x01) + + /***************************************************************************** * @@ -926,6 +986,10 @@ #define MPI_FW_DOWNLOAD_ITYPE_FW #define MPI_FW_DOWNLOAD_ITYPE_BIOS (0x02) #define MPI_FW_DOWNLOAD_ITYPE_NVDATA (0x03) #define MPI_FW_DOWNLOAD_ITYPE_BOOTLOADER (0x04) +#define MPI_FW_DOWNLOAD_ITYPE_MANUFACTURING (0x06) +#define MPI_FW_DOWNLOAD_ITYPE_CONFIG_1 (0x07) +#define MPI_FW_DOWNLOAD_ITYPE_CONFIG_2 (0x08) +#define MPI_FW_DOWNLOAD_ITYPE_MEGARAID (0x09) typedef struct _FWDownloadTCSGE @@ -980,6 +1044,11 @@ #define MPI_FW_UPLOAD_ITYPE_BIOS_FLASH #define MPI_FW_UPLOAD_ITYPE_NVDATA (0x03) #define MPI_FW_UPLOAD_ITYPE_BOOTLOADER (0x04) #define MPI_FW_UPLOAD_ITYPE_FW_BACKUP (0x05) +#define MPI_FW_UPLOAD_ITYPE_MANUFACTURING (0x06) +#define MPI_FW_UPLOAD_ITYPE_CONFIG_1 (0x07) +#define MPI_FW_UPLOAD_ITYPE_CONFIG_2 (0x08) +#define MPI_FW_UPLOAD_ITYPE_MEGARAID (0x09) +#define MPI_FW_UPLOAD_ITYPE_COMPLETE (0x0A) typedef struct _FWUploadTCSGE { diff --git a/drivers/message/fusion/lsi/mpi_log_sas.h b/drivers/message/fusion/lsi/mpi_log_sas.h index 871ebc0..635bbe0 100644 --- a/drivers/message/fusion/lsi/mpi_log_sas.h +++ b/drivers/message/fusion/lsi/mpi_log_sas.h @@ -1,4 +1,3 @@ - /*************************************************************************** * * * Copyright 2003 LSI Logic Corporation. All rights reserved. * @@ -14,7 +13,7 @@ #ifndef IOPI_IOCLOGINFO_H_INCLUDED #define IOPI_IOCLOGINFO_H_INCLUDED #define SAS_LOGINFO_NEXUS_LOSS 0x31170000 -#define SAS_LOGINFO_MASK 0xFFFF0000 +#define SAS_LOGINFO_MASK 0xFFFF0000 /****************************************************************************/ /* IOC LOGINFO defines, 0x00000000 - 0x0FFFFFFF */ @@ -43,129 +42,172 @@ #define IOC_LOGINFO_CODE_SHIFT /****************************************************************************/ /* IOP LOGINFO_CODE defines, valid if IOC_LOGINFO_ORIGINATOR = IOP */ /****************************************************************************/ -#define IOP_LOGINFO_CODE_INVALID_SAS_ADDRESS (0x00010000) -#define IOP_LOGINFO_CODE_UNUSED2 (0x00020000) -#define IOP_LOGINFO_CODE_CONFIG_INVALID_PAGE (0x00030000) -#define IOP_LOGINFO_CODE_CONFIG_INVALID_PAGE_RT (0x00030100) /* Route Table Entry not found */ -#define IOP_LOGINFO_CODE_CONFIG_INVALID_PAGE_PN (0x00030200) /* Invalid Page Number */ -#define IOP_LOGINFO_CODE_CONFIG_INVALID_PAGE_FORM (0x00030300) /* Invalid FORM */ -#define IOP_LOGINFO_CODE_CONFIG_INVALID_PAGE_PT (0x00030400) /* Invalid Page Type */ -#define IOP_LOGINFO_CODE_CONFIG_INVALID_PAGE_DNM (0x00030500) /* Device Not Mapped */ -#define IOP_LOGINFO_CODE_CONFIG_INVALID_PAGE_PERSIST (0x00030600) /* Persistent Page not found */ -#define IOP_LOGINFO_CODE_CONFIG_INVALID_PAGE_DEFAULT (0x00030700) /* Default Page not found */ - -#define IOP_LOGINFO_CODE_DIAG_MSG_ERROR (0x00040000) /* Error handling diag msg - or'd with diag status */ - -#define IOP_LOGINFO_CODE_TASK_TERMINATED (0x00050000) - -#define IOP_LOGINFO_CODE_ENCL_MGMT_READ_ACTION_ERR0R (0x00060001) /* Read Action not supported for SEP msg */ -#define IOP_LOGINFO_CODE_ENCL_MGMT_INVALID_BUS_ID_ERR0R (0x00060002) /* Invalid Bus/ID in SEP msg */ - -#define IOP_LOGINFO_CODE_TARGET_ASSIST_TERMINATED (0x00070001) -#define IOP_LOGINFO_CODE_TARGET_STATUS_SEND_TERMINATED (0x00070002) -#define IOP_LOGINFO_CODE_TARGET_MODE_ABORT_ALL_IO (0x00070003) -#define IOP_LOGINFO_CODE_TARGET_MODE_ABORT_EXACT_IO (0x00070004) -#define IOP_LOGINFO_CODE_TARGET_MODE_ABORT_EXACT_IO_REQ (0x00070005) +#define IOP_LOGINFO_CODE_INVALID_SAS_ADDRESS (0x00010000) +#define IOP_LOGINFO_CODE_UNUSED2 (0x00020000) +#define IOP_LOGINFO_CODE_CONFIG_INVALID_PAGE (0x00030000) +#define IOP_LOGINFO_CODE_CONFIG_INVALID_PAGE_RT (0x00030100) /* Route Table Entry not found */ +#define IOP_LOGINFO_CODE_CONFIG_INVALID_PAGE_PN (0x00030200) /* Invalid Page Number */ +#define IOP_LOGINFO_CODE_CONFIG_INVALID_PAGE_FORM (0x00030300) /* Invalid FORM */ +#define IOP_LOGINFO_CODE_CONFIG_INVALID_PAGE_PT (0x00030400) /* Invalid Page Type */ +#define IOP_LOGINFO_CODE_CONFIG_INVALID_PAGE_DNM (0x00030500) /* Device Not Mapped */ +#define IOP_LOGINFO_CODE_CONFIG_INVALID_PAGE_PERSIST (0x00030600) /* Persistent Page not found */ +#define IOP_LOGINFO_CODE_CONFIG_INVALID_PAGE_DEFAULT (0x00030700) /* Default Page not found */ + +#define IOP_LOGINFO_CODE_FWUPLOAD_NO_FLASH_AVAILABLE (0x0003E000) /* Tried to upload from flash, but there is none */ +#define IOP_LOGINFO_CODE_FWUPLOAD_UNKNOWN_IMAGE_TYPE (0x0003E001) /* ImageType field contents were invalid */ +#define IOP_LOGINFO_CODE_FWUPLOAD_WRONG_IMAGE_SIZE (0x0003E002) /* ImageSize field in TCSGE was bad/offset in MfgPg 4 was wrong */ +#define IOP_LOGINFO_CODE_FWUPLOAD_ENTIRE_FLASH_UPLOAD_FAILED (0x0003E003) /* Error occured while attempting to upload the entire flash */ +#define IOP_LOGINFO_CODE_FWUPLOAD_REGION_UPLOAD_FAILED (0x0003E004) /* Error occured while attempting to upload single flash region */ +#define IOP_LOGINFO_CODE_FWUPLOAD_DMA_FAILURE (0x0003E005) /* Problem occured while DMAing FW to host memory */ + +#define IOP_LOGINFO_CODE_DIAG_MSG_ERROR (0x00040000) /* Error handling diag msg - or'd with diag status */ + +#define IOP_LOGINFO_CODE_TASK_TERMINATED (0x00050000) + +#define IOP_LOGINFO_CODE_ENCL_MGMT_READ_ACTION_ERR0R (0x00060001) /* Read Action not supported for SEP msg */ +#define IOP_LOGINFO_CODE_ENCL_MGMT_INVALID_BUS_ID_ERR0R (0x00060002) /* Invalid Bus/ID in SEP msg */ + +#define IOP_LOGINFO_CODE_TARGET_ASSIST_TERMINATED (0x00070001) +#define IOP_LOGINFO_CODE_TARGET_STATUS_SEND_TERMINATED (0x00070002) +#define IOP_LOGINFO_CODE_TARGET_MODE_ABORT_ALL_IO (0x00070003) +#define IOP_LOGINFO_CODE_TARGET_MODE_ABORT_EXACT_IO (0x00070004) +#define IOP_LOGINFO_CODE_TARGET_MODE_ABORT_EXACT_IO_REQ (0x00070005) /****************************************************************************/ /* PL LOGINFO_CODE defines, valid if IOC_LOGINFO_ORIGINATOR = PL */ /****************************************************************************/ -#define PL_LOGINFO_CODE_OPEN_FAILURE (0x00010000) -#define PL_LOG_INFO_CODE_OPEN_FAILURE_NO_DEST_TIME_OUT (0x00010001) -#define PL_LOGINFO_CODE_OPEN_FAILURE_BAD_DESTINATION (0x00010011) -#define PL_LOGINFO_CODE_OPEN_FAILURE_PROTOCOL_NOT_SUPPORTED (0x00010013) -#define PL_LOGINFO_CODE_OPEN_FAILURE_STP_RESOURCES_BSY (0x00010018) -#define PL_LOGINFO_CODE_OPEN_FAILURE_WRONG_DESTINATION (0x00010019) -#define PL_LOGINFO_CODE_OPEN_FAILURE_ORR_TIMEOUT (0X0001001A) -#define PL_LOGINFO_CODE_OPEN_FAILURE_PATHWAY_BLOCKED (0x0001001B) -#define PL_LOGINFO_CODE_OPEN_FAILURE_AWT_MAXED (0x0001001C) -#define PL_LOGINFO_CODE_INVALID_SGL (0x00020000) -#define PL_LOGINFO_CODE_WRONG_REL_OFF_OR_FRAME_LENGTH (0x00030000) -#define PL_LOGINFO_CODE_FRAME_XFER_ERROR (0x00040000) -#define PL_LOGINFO_CODE_TX_FM_CONNECTED_LOW (0x00050000) -#define PL_LOGINFO_CODE_SATA_NON_NCQ_RW_ERR_BIT_SET (0x00060000) -#define PL_LOGINFO_CODE_SATA_READ_LOG_RECEIVE_DATA_ERR (0x00070000) -#define PL_LOGINFO_CODE_SATA_NCQ_FAIL_ALL_CMDS_AFTR_ERR (0x00080000) -#define PL_LOGINFO_CODE_SATA_ERR_IN_RCV_SET_DEV_BIT_FIS (0x00090000) -#define PL_LOGINFO_CODE_RX_FM_INVALID_MESSAGE (0x000A0000) -#define PL_LOGINFO_CODE_RX_CTX_MESSAGE_VALID_ERROR (0x000B0000) -#define PL_LOGINFO_CODE_RX_FM_CURRENT_FRAME_ERROR (0x000C0000) -#define PL_LOGINFO_CODE_SATA_LINK_DOWN (0x000D0000) -#define PL_LOGINFO_CODE_DISCOVERY_SATA_INIT_W_IOS (0x000E0000) -#define PL_LOGINFO_CODE_CONFIG_INVALID_PAGE (0x000F0000) -#define PL_LOGINFO_CODE_CONFIG_PL_NOT_INITIALIZED (0x000F0001) /* PL not yet initialized, can't do config page req. */ -#define PL_LOGINFO_CODE_CONFIG_INVALID_PAGE_PT (0x000F0100) /* Invalid Page Type */ -#define PL_LOGINFO_CODE_CONFIG_INVALID_PAGE_NUM_PHYS (0x000F0200) /* Invalid Number of Phys */ -#define PL_LOGINFO_CODE_CONFIG_INVALID_PAGE_NOT_IMP (0x000F0300) /* Case Not Handled */ -#define PL_LOGINFO_CODE_CONFIG_INVALID_PAGE_NO_DEV (0x000F0400) /* No Device Found */ -#define PL_LOGINFO_CODE_CONFIG_INVALID_PAGE_FORM (0x000F0500) /* Invalid FORM */ -#define PL_LOGINFO_CODE_CONFIG_INVALID_PAGE_PHY (0x000F0600) /* Invalid Phy */ -#define PL_LOGINFO_CODE_CONFIG_INVALID_PAGE_NO_OWNER (0x000F0700) /* No Owner Found */ -#define PL_LOGINFO_CODE_DSCVRY_SATA_INIT_TIMEOUT (0x00100000) -#define PL_LOGINFO_CODE_RESET (0x00110000) /* See Sub-Codes below */ -#define PL_LOGINFO_CODE_ABORT (0x00120000) /* See Sub-Codes below */ -#define PL_LOGINFO_CODE_IO_NOT_YET_EXECUTED (0x00130000) -#define PL_LOGINFO_CODE_IO_EXECUTED (0x00140000) -#define PL_LOGINFO_CODE_PERS_RESV_OUT_NOT_AFFIL_OWNER (0x00150000) -#define PL_LOGINFO_CODE_OPEN_TXDMA_ABORT (0x00160000) -#define PL_LOGINFO_CODE_IO_DEVICE_MISSING_DELAY_RETRY (0x00170000) -#define PL_LOGINFO_SUB_CODE_OPEN_FAILURE (0x00000100) -#define PL_LOGINFO_SUB_CODE_OPEN_FAILURE_NO_DEST_TIMEOUT (0x00000101) -#define PL_LOGINFO_SUB_CODE_OPEN_FAILURE_ORR_TIMEOUT (0x0000011A) /* Open Reject (Retry) Timeout */ -#define PL_LOGINFO_SUB_CODE_OPEN_FAILURE_PATHWAY_BLOCKED (0x0000011B) -#define PL_LOGINFO_SUB_CODE_OPEN_FAILURE_AWT_MAXED (0x0000011C) /* Arbitration Wait Timer Maxed */ - -#define PL_LOGINFO_SUB_CODE_TARGET_BUS_RESET (0x00000120) -#define PL_LOGINFO_SUB_CODE_TRANSPORT_LAYER (0x00000130) /* Leave lower nibble (1-f) reserved. */ -#define PL_LOGINFO_SUB_CODE_PORT_LAYER (0x00000140) /* Leave lower nibble (1-f) reserved. */ - - -#define PL_LOGINFO_SUB_CODE_INVALID_SGL (0x00000200) -#define PL_LOGINFO_SUB_CODE_WRONG_REL_OFF_OR_FRAME_LENGTH (0x00000300) -#define PL_LOGINFO_SUB_CODE_FRAME_XFER_ERROR (0x00000400) -#define PL_LOGINFO_SUB_CODE_TX_FM_CONNECTED_LOW (0x00000500) -#define PL_LOGINFO_SUB_CODE_SATA_NON_NCQ_RW_ERR_BIT_SET (0x00000600) -#define PL_LOGINFO_SUB_CODE_SATA_READ_LOG_RECEIVE_DATA_ERR (0x00000700) -#define PL_LOGINFO_SUB_CODE_SATA_NCQ_FAIL_ALL_CMDS_AFTR_ERR (0x00000800) -#define PL_LOGINFO_SUB_CODE_SATA_ERR_IN_RCV_SET_DEV_BIT_FIS (0x00000900) -#define PL_LOGINFO_SUB_CODE_RX_FM_INVALID_MESSAGE (0x00000A00) -#define PL_LOGINFO_SUB_CODE_RX_CTX_MESSAGE_VALID_ERROR (0x00000B00) -#define PL_LOGINFO_SUB_CODE_RX_FM_CURRENT_FRAME_ERROR (0x00000C00) -#define PL_LOGINFO_SUB_CODE_SATA_LINK_DOWN (0x00000D00) -#define PL_LOGINFO_SUB_CODE_DISCOVERY_SATA_INIT_W_IOS (0x00000E00) -#define PL_LOGINFO_SUB_CODE_DISCOVERY_REMOTE_SEP_RESET (0x00000E01) -#define PL_LOGINFO_SUB_CODE_SECOND_OPEN (0x00000F00) -#define PL_LOGINFO_SUB_CODE_DSCVRY_SATA_INIT_TIMEOUT (0x00001000) - - -#define PL_LOGINFO_CODE_ENCL_MGMT_SMP_FRAME_FAILURE (0x00200000) /* Can't get SMP Frame */ -#define PL_LOGINFO_CODE_ENCL_MGMT_SMP_READ_ERROR (0x00200010) /* Error occured on SMP Read */ -#define PL_LOGINFO_CODE_ENCL_MGMT_SMP_WRITE_ERROR (0x00200020) /* Error occured on SMP Write */ -#define PL_LOGINFO_CODE_ENCL_MGMT_NOT_SUPPORTED_ON_ENCL (0x00200040) /* Encl Mgmt services not available for this WWID */ -#define PL_LOGINFO_CODE_ENCL_MGMT_ADDR_MODE_NOT_SUPPORTED (0x00200050) /* Address Mode not suppored */ -#define PL_LOGINFO_CODE_ENCL_MGMT_BAD_SLOT_NUM (0x00200060) /* Invalid Slot Number in SEP Msg */ -#define PL_LOGINFO_CODE_ENCL_MGMT_SGPIO_NOT_PRESENT (0x00200070) /* SGPIO not present/enabled */ -#define PL_LOGINFO_CODE_ENCL_MGMT_GPIO_NOT_CONFIGURED (0x00200080) /* GPIO not configured */ -#define PL_LOGINFO_CODE_ENCL_MGMT_GPIO_FRAME_ERROR (0x00200090) /* GPIO can't allocate a frame */ -#define PL_LOGINFO_CODE_ENCL_MGMT_GPIO_CONFIG_PAGE_ERROR (0x002000A0) /* GPIO failed config page request */ -#define PL_LOGINFO_CODE_ENCL_MGMT_SES_FRAME_ALLOC_ERROR (0x002000B0) /* Can't get frame for SES command */ -#define PL_LOGINFO_CODE_ENCL_MGMT_SES_IO_ERROR (0x002000C0) /* I/O execution error */ -#define PL_LOGINFO_CODE_ENCL_MGMT_SES_RETRIES_EXHAUSTED (0x002000D0) /* SEP I/O retries exhausted */ -#define PL_LOGINFO_CODE_ENCL_MGMT_SMP_FRAME_ALLOC_ERROR (0x002000E0) /* Can't get frame for SMP command */ - -#define PL_LOGINFO_DA_SEP_NOT_PRESENT (0x00200100) /* SEP not present when msg received */ -#define PL_LOGINFO_DA_SEP_SINGLE_THREAD_ERROR (0x00200101) /* Can only accept 1 msg at a time */ -#define PL_LOGINFO_DA_SEP_ISTWI_INTR_IN_IDLE_STATE (0x00200102) /* ISTWI interrupt recvd. while IDLE */ -#define PL_LOGINFO_DA_SEP_RECEIVED_NACK_FROM_SLAVE (0x00200103) /* SEP NACK'd, it is busy */ -#define PL_LOGINFO_DA_SEP_DID_NOT_RECEIVE_ACK (0x00200104) /* SEP didn't rcv. ACK (Last Rcvd Bit = 1) */ -#define PL_LOGINFO_DA_SEP_BAD_STATUS_HDR_CHKSUM (0x00200105) /* SEP stopped or sent bad chksum in Hdr */ -#define PL_LOGINFO_DA_SEP_STOP_ON_DATA (0x00200106) /* SEP stopped while transfering data */ -#define PL_LOGINFO_DA_SEP_STOP_ON_SENSE_DATA (0x00200107) /* SEP stopped while transfering sense data */ -#define PL_LOGINFO_DA_SEP_UNSUPPORTED_SCSI_STATUS_1 (0x00200108) /* SEP returned unknown scsi status */ -#define PL_LOGINFO_DA_SEP_UNSUPPORTED_SCSI_STATUS_2 (0x00200109) /* SEP returned unknown scsi status */ -#define PL_LOGINFO_DA_SEP_CHKSUM_ERROR_AFTER_STOP (0x0020010A) /* SEP returned bad chksum after STOP */ -#define PL_LOGINFO_DA_SEP_CHKSUM_ERROR_AFTER_STOP_GETDATA (0x0020010B) /* SEP returned bad chksum after STOP while gettin data*/ -#define PL_LOGINFO_DA_SEP_UNSUPPORTED_COMMAND (0x0020010C) /* SEP doesn't support CDB opcode */ +#define PL_LOGINFO_CODE_OPEN_FAILURE (0x00010000) /* see SUB_CODE_OPEN_FAIL_ below */ + +#define PL_LOGINFO_SUB_CODE_OPEN_FAIL_NO_DEST_TIME_OUT (0x00000001) +#define PL_LOGINFO_SUB_CODE_OPEN_FAIL_PATHWAY_BLOCKED (0x00000002) +#define PL_LOGINFO_SUB_CODE_OPEN_FAIL_RES_CONTINUE0 (0x00000003) +#define PL_LOGINFO_SUB_CODE_OPEN_FAIL_RES_CONTINUE1 (0x00000004) +#define PL_LOGINFO_SUB_CODE_OPEN_FAIL_RES_INITIALIZE0 (0x00000005) +#define PL_LOGINFO_SUB_CODE_OPEN_FAIL_RES_INITIALIZE1 (0x00000006) +#define PL_LOGINFO_SUB_CODE_OPEN_FAIL_RES_STOP0 (0x00000007) +#define PL_LOGINFO_SUB_CODE_OPEN_FAIL_RES_STOP1 (0x00000008) +#define PL_LOGINFO_SUB_CODE_OPEN_FAIL_RETRY (0x00000009) +#define PL_LOGINFO_SUB_CODE_OPEN_FAIL_BREAK (0x0000000A) +#define PL_LOGINFO_SUB_CODE_OPEN_FAIL_UNUSED_0B (0x0000000B) +#define PL_LOGINFO_SUB_CODE_OPEN_FAIL_OPEN_TIMEOUT_EXP (0x0000000C) +#define PL_LOGINFO_SUB_CODE_OPEN_FAIL_UNUSED_0D (0x0000000D) +#define PL_LOGINFO_SUB_CODE_OPEN_FAIL_DVTBLE_ACCSS_FAIL (0x0000000E) +#define PL_LOGINFO_SUB CODE_OPEN_FAIL_BAD_DEST (0x00000011) +#define PL_LOGINFO_SUB_CODE_OPEN_FAIL_RATE_NOT_SUPP (0x00000012) +#define PL_LOGINFO_SUB_CODE_OPEN_FAIL_PROT_NOT_SUPP (0x00000013) +#define PL_LOGINFO_SUB_CODE_OPEN_FAIL_RESERVED_ABANDON0 (0x00000014) +#define PL_LOGINFO_SUB_CODE_OPEN_FAIL_RESERVED_ABANDON1 (0x00000015) +#define PL_LOGINFO_SUB_CODE_OPEN_FAIL_RESERVED_ABANDON2 (0x00000016) +#define PL_LOGINFO_SUB_CODE_OPEN_FAIL_RESERVED_ABANDON3 (0x00000017) +#define PL_LOGINFO_SUB_CODE_OPEN_FAIL_STP_RESOURCES_BSY (0x00000018) +#define PL_LOGINFO_SUB_CODE_OPEN_FAIL_WRONG_DESTINATION (0x00000019) + +#define PL_LOGINFO_SUB_CODE_OPEN_FAIL_PATH_BLOCKED (0x0000001B) /* Retry Timeout */ +#define PL_LOGINFO_SUB_CODE_OPEN_FAIL_AWT_MAXED (0x0000001C) /* Retry Timeout */ + + + +#define PL_LOGINFO_CODE_INVALID_SGL (0x00020000) +#define PL_LOGINFO_CODE_WRONG_REL_OFF_OR_FRAME_LENGTH (0x00030000) +#define PL_LOGINFO_CODE_FRAME_XFER_ERROR (0x00040000) +#define PL_LOGINFO_CODE_TX_FM_CONNECTED_LOW (0x00050000) +#define PL_LOGINFO_CODE_SATA_NON_NCQ_RW_ERR_BIT_SET (0x00060000) +#define PL_LOGINFO_CODE_SATA_READ_LOG_RECEIVE_DATA_ERR (0x00070000) +#define PL_LOGINFO_CODE_SATA_NCQ_FAIL_ALL_CMDS_AFTR_ERR (0x00080000) +#define PL_LOGINFO_CODE_SATA_ERR_IN_RCV_SET_DEV_BIT_FIS (0x00090000) +#define PL_LOGINFO_CODE_RX_FM_INVALID_MESSAGE (0x000A0000) +#define PL_LOGINFO_CODE_RX_CTX_MESSAGE_VALID_ERROR (0x000B0000) +#define PL_LOGINFO_CODE_RX_FM_CURRENT_FRAME_ERROR (0x000C0000) +#define PL_LOGINFO_CODE_SATA_LINK_DOWN (0x000D0000) +#define PL_LOGINFO_CODE_DISCOVERY_SATA_INIT_W_IOS (0x000E0000) +#define PL_LOGINFO_CODE_CONFIG_INVALID_PAGE (0x000F0000) +#define PL_LOGINFO_CODE_CONFIG_PL_NOT_INITIALIZED (0x000F0001) /* PL not yet initialized, can't do config page req. */ +#define PL_LOGINFO_CODE_CONFIG_INVALID_PAGE_PT (0x000F0100) /* Invalid Page Type */ +#define PL_LOGINFO_CODE_CONFIG_INVALID_PAGE_NUM_PHYS (0x000F0200) /* Invalid Number of Phys */ +#define PL_LOGINFO_CODE_CONFIG_INVALID_PAGE_NOT_IMP (0x000F0300) /* Case Not Handled */ +#define PL_LOGINFO_CODE_CONFIG_INVALID_PAGE_NO_DEV (0x000F0400) /* No Device Found */ +#define PL_LOGINFO_CODE_CONFIG_INVALID_PAGE_FORM (0x000F0500) /* Invalid FORM */ +#define PL_LOGINFO_CODE_CONFIG_INVALID_PAGE_PHY (0x000F0600) /* Invalid Phy */ +#define PL_LOGINFO_CODE_CONFIG_INVALID_PAGE_NO_OWNER (0x000F0700) /* No Owner Found */ +#define PL_LOGINFO_CODE_DSCVRY_SATA_INIT_TIMEOUT (0x00100000) +#define PL_LOGINFO_CODE_RESET (0x00110000) /* See Sub-Codes below (PL_LOGINFO_SUB_CODE) */ +#define PL_LOGINFO_CODE_ABORT (0x00120000) /* See Sub-Codes below (PL_LOGINFO_SUB_CODE)*/ +#define PL_LOGINFO_CODE_IO_NOT_YET_EXECUTED (0x00130000) +#define PL_LOGINFO_CODE_IO_EXECUTED (0x00140000) +#define PL_LOGINFO_CODE_PERS_RESV_OUT_NOT_AFFIL_OWNER (0x00150000) +#define PL_LOGINFO_CODE_OPEN_TXDMA_ABORT (0x00160000) +#define PL_LOGINFO_CODE_IO_DEVICE_MISSING_DELAY_RETRY (0x00170000) +#define PL_LOGINFO_CODE_IO_CANCELLED_DUE_TO_R_ERR (0x00180000) +#define PL_LOGINFO_SUB_CODE_OPEN_FAILURE (0x00000100) +#define PL_LOGINFO_SUB_CODE_OPEN_FAILURE_NO_DEST_TIMEOUT (0x00000101) +#define PL_LOGINFO_SUB_CODE_OPEN_FAILURE_SATA_NEG_RATE_2HI (0x00000102) +#define PL_LOGINFO_SUB_CODE_OPEN_FAILURE_RATE_NOT_SUPPORTED (0x00000103) +#define PL_LOGINFO_SUB_CODE_OPEN_FAILURE_BREAK (0x00000104) +#define PL_LOGINFO_SUB_CODE_OPEN_FAILURE_ZONE_VIOLATION (0x00000114) +#define PL_LOGINFO_SUB_CODE_OPEN_FAILURE_ABANDON0 (0x00000114) /* Open Reject (Zone Violation) - available on SAS-2 devices */ +#define PL_LOGINFO_SUB_CODE_OPEN_FAILURE_ABANDON1 (0x00000115) +#define PL_LOGINFO_SUB_CODE_OPEN_FAILURE_ABANDON2 (0x00000116) +#define PL_LOGINFO_SUB_CODE_OPEN_FAILURE_ABANDON3 (0x00000117) +#define PL_LOGINFO_SUB_CODE_OPEN_FAILURE_ORR_TIMEOUT (0x0000011A) /* Open Reject (Retry) Timeout */ +#define PL_LOGINFO_SUB_CODE_OPEN_FAILURE_PATH_BLOCKED (0x0000011B) +#define PL_LOGINFO_SUB_CODE_OPEN_FAILURE_AWT_MAXED (0x0000011C) /* Arbitration Wait Timer Maxed */ + +#define PL_LOGINFO_SUB_CODE_TARGET_BUS_RESET (0x00000120) +#define PL_LOGINFO_SUB_CODE_TRANSPORT_LAYER (0x00000130) /* Leave lower nibble (1-f) reserved. */ +#define PL_LOGINFO_SUB_CODE_PORT_LAYER (0x00000140) /* Leave lower nibble (1-f) reserved. */ + + +#define PL_LOGINFO_SUB_CODE_INVALID_SGL (0x00000200) +#define PL_LOGINFO_SUB_CODE_WRONG_REL_OFF_OR_FRAME_LENGTH (0x00000300) +#define PL_LOGINFO_SUB_CODE_FRAME_XFER_ERROR (0x00000400) /* Bits 0-3 encode Transport Status Register (offset 0x08) */ + /* Bit 0 is Status Bit 0: FrameXferErr */ + /* Bit 1 & 2 are Status Bits 16 and 17: FrameXmitErrStatus */ + /* Bit 3 is Status Bit 18 WriteDataLenghtGTDataLengthErr */ + +#define PL_LOGINFO_SUB_CODE_TX_FM_CONNECTED_LOW (0x00000500) +#define PL_LOGINFO_SUB_CODE_SATA_NON_NCQ_RW_ERR_BIT_SET (0x00000600) +#define PL_LOGINFO_SUB_CODE_SATA_READ_LOG_RECEIVE_DATA_ERR (0x00000700) +#define PL_LOGINFO_SUB_CODE_SATA_NCQ_FAIL_ALL_CMDS_AFTR_ERR (0x00000800) +#define PL_LOGINFO_SUB_CODE_SATA_ERR_IN_RCV_SET_DEV_BIT_FIS (0x00000900) +#define PL_LOGINFO_SUB_CODE_RX_FM_INVALID_MESSAGE (0x00000A00) +#define PL_LOGINFO_SUB_CODE_RX_CTX_MESSAGE_VALID_ERROR (0x00000B00) +#define PL_LOGINFO_SUB_CODE_RX_FM_CURRENT_FRAME_ERROR (0x00000C00) +#define PL_LOGINFO_SUB_CODE_SATA_LINK_DOWN (0x00000D00) +#define PL_LOGINFO_SUB_CODE_DISCOVERY_SATA_INIT_W_IOS (0x00000E00) +#define PL_LOGINFO_SUB_CODE_DISCOVERY_REMOTE_SEP_RESET (0x00000E01) +#define PL_LOGINFO_SUB_CODE_SECOND_OPEN (0x00000F00) +#define PL_LOGINFO_SUB_CODE_DSCVRY_SATA_INIT_TIMEOUT (0x00001000) + +#define PL_LOGINFO_CODE_ENCL_MGMT_SMP_FRAME_FAILURE (0x00200000) /* Can't get SMP Frame */ +#define PL_LOGINFO_CODE_ENCL_MGMT_SMP_READ_ERROR (0x00200010) /* Error occured on SMP Read */ +#define PL_LOGINFO_CODE_ENCL_MGMT_SMP_WRITE_ERROR (0x00200020) /* Error occured on SMP Write */ +#define PL_LOGINFO_CODE_ENCL_MGMT_NOT_SUPPORTED_ON_ENCL (0x00200040) /* Encl Mgmt services not available for this WWID */ +#define PL_LOGINFO_CODE_ENCL_MGMT_ADDR_MODE_NOT_SUPPORTED (0x00200050) /* Address Mode not suppored */ +#define PL_LOGINFO_CODE_ENCL_MGMT_BAD_SLOT_NUM (0x00200060) /* Invalid Slot Number in SEP Msg */ +#define PL_LOGINFO_CODE_ENCL_MGMT_SGPIO_NOT_PRESENT (0x00200070) /* SGPIO not present/enabled */ +#define PL_LOGINFO_CODE_ENCL_MGMT_GPIO_NOT_CONFIGURED (0x00200080) /* GPIO not configured */ +#define PL_LOGINFO_CODE_ENCL_MGMT_GPIO_FRAME_ERROR (0x00200090) /* GPIO can't allocate a frame */ +#define PL_LOGINFO_CODE_ENCL_MGMT_GPIO_CONFIG_PAGE_ERROR (0x002000A0) /* GPIO failed config page request */ +#define PL_LOGINFO_CODE_ENCL_MGMT_SES_FRAME_ALLOC_ERROR (0x002000B0) /* Can't get frame for SES command */ +#define PL_LOGINFO_CODE_ENCL_MGMT_SES_IO_ERROR (0x002000C0) /* I/O execution error */ +#define PL_LOGINFO_CODE_ENCL_MGMT_SES_RETRIES_EXHAUSTED (0x002000D0) /* SEP I/O retries exhausted */ +#define PL_LOGINFO_CODE_ENCL_MGMT_SMP_FRAME_ALLOC_ERROR (0x002000E0) /* Can't get frame for SMP command */ + +#define PL_LOGINFO_DA_SEP_NOT_PRESENT (0x00200100) /* SEP not present when msg received */ +#define PL_LOGINFO_DA_SEP_SINGLE_THREAD_ERROR (0x00200101) /* Can only accept 1 msg at a time */ +#define PL_LOGINFO_DA_SEP_ISTWI_INTR_IN_IDLE_STATE (0x00200102) /* ISTWI interrupt recvd. while IDLE */ +#define PL_LOGINFO_DA_SEP_RECEIVED_NACK_FROM_SLAVE (0x00200103) /* SEP NACK'd, it is busy */ +#define PL_LOGINFO_DA_SEP_DID_NOT_RECEIVE_ACK (0x00200104) /* SEP didn't rcv. ACK (Last Rcvd Bit = 1) */ +#define PL_LOGINFO_DA_SEP_BAD_STATUS_HDR_CHKSUM (0x00200105) /* SEP stopped or sent bad chksum in Hdr */ +#define PL_LOGINFO_DA_SEP_STOP_ON_DATA (0x00200106) /* SEP stopped while transfering data */ +#define PL_LOGINFO_DA_SEP_STOP_ON_SENSE_DATA (0x00200107) /* SEP stopped while transfering sense data */ +#define PL_LOGINFO_DA_SEP_UNSUPPORTED_SCSI_STATUS_1 (0x00200108) /* SEP returned unknown scsi status */ +#define PL_LOGINFO_DA_SEP_UNSUPPORTED_SCSI_STATUS_2 (0x00200109) /* SEP returned unknown scsi status */ +#define PL_LOGINFO_DA_SEP_CHKSUM_ERROR_AFTER_STOP (0x0020010A) /* SEP returned bad chksum after STOP */ +#define PL_LOGINFO_DA_SEP_CHKSUM_ERROR_AFTER_STOP_GETDATA (0x0020010B) /* SEP returned bad chksum after STOP while gettin data*/ +#define PL_LOGINFO_DA_SEP_UNSUPPORTED_COMMAND (0x0020010C) /* SEP doesn't support CDB opcode f/w location 1 */ +#define PL_LOGINFO_DA_SEP_UNSUPPORTED_COMMAND_2 (0x0020010D) /* SEP doesn't support CDB opcode f/w location 2 */ +#define PL_LOGINFO_DA_SEP_UNSUPPORTED_COMMAND_3 (0x0020010E) /* SEP doesn't support CDB opcode f/w location 3 */ /****************************************************************************/ diff --git a/drivers/message/fusion/lsi/mpi_sas.h b/drivers/message/fusion/lsi/mpi_sas.h index 50b8f0a..8e990a0 100644 --- a/drivers/message/fusion/lsi/mpi_sas.h +++ b/drivers/message/fusion/lsi/mpi_sas.h @@ -1,12 +1,12 @@ /* - * Copyright (c) 2004 LSI Logic Corporation. + * Copyright (c) 2004-2006 LSI Logic Corporation. * * * Name: mpi_sas.h * Title: MPI Serial Attached SCSI structures and definitions * Creation Date: August 19, 2004 * - * mpi_sas.h Version: 01.05.03 + * mpi_sas.h Version: 01.05.04 * * Version History * --------------- @@ -21,6 +21,8 @@ * and Remove Device operations to SAS IO Unit Control. * Added DevHandle field to SAS IO Unit Control request and * reply. + * 10-11-06 01.05.04 Fixed the name of a define for Operation field of SAS IO + * Unit Control request. * -------------------------------------------------------------------------- */ @@ -237,7 +239,8 @@ #define MPI_SAS_OP_MAP_CURRENT #define MPI_SAS_OP_SEND_PRIMITIVE (0x0A) #define MPI_SAS_OP_FORCE_FULL_DISCOVERY (0x0B) #define MPI_SAS_OP_TRANSMIT_PORT_SELECT_SIGNAL (0x0C) -#define MPI_SAS_OP_TRANSMIT_REMOVE_DEVICE (0x0D) +#define MPI_SAS_OP_TRANSMIT_REMOVE_DEVICE (0x0D) /* obsolete name */ +#define MPI_SAS_OP_REMOVE_DEVICE (0x0D) /* values for the PrimFlags field */ #define MPI_SAS_PRIMFLAGS_SINGLE (0x08) diff --git a/drivers/message/fusion/mptbase.c b/drivers/message/fusion/mptbase.c index b3f28a0..083acfd 100644 --- a/drivers/message/fusion/mptbase.c +++ b/drivers/message/fusion/mptbase.c @@ -6,7 +6,7 @@ * running LSI Logic Fusion MPT (Message Passing Technology) firmware. * * Copyright (c) 1999-2007 LSI Logic Corporation - * (mailto:mpt_linux_developer@lsil.com) + * (mailto:mpt_linux_developer@lsi.com) * */ /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ @@ -82,6 +82,10 @@ static int mpt_msi_enable; module_param(mpt_msi_enable, int, 0); MODULE_PARM_DESC(mpt_msi_enable, " MSI Support Enable (default=0)"); +static int mpt_channel_mapping; +module_param(mpt_channel_mapping, int, 0); +MODULE_PARM_DESC(mpt_channel_mapping, " Mapping id's to channels (default=0)"); + #ifdef MFCNT static int mfcounter = 0; #define PRINT_MF_COUNT 20000 @@ -173,11 +177,14 @@ static void mpt_get_fw_exp_ver(char *buf //int mpt_HardResetHandler(MPT_ADAPTER *ioc, int sleepFlag); static int ProcessEventNotification(MPT_ADAPTER *ioc, EventNotificationReply_t *evReply, int *evHandlers); -static void mpt_sp_ioc_info(MPT_ADAPTER *ioc, u32 ioc_status, MPT_FRAME_HDR *mf); +#ifdef MPT_DEBUG_REPLY +static void mpt_iocstatus_info(MPT_ADAPTER *ioc, u32 ioc_status, MPT_FRAME_HDR *mf); +#endif static void mpt_fc_log_info(MPT_ADAPTER *ioc, u32 log_info); static void mpt_spi_log_info(MPT_ADAPTER *ioc, u32 log_info); static void mpt_sas_log_info(MPT_ADAPTER *ioc, u32 log_info); static int mpt_read_ioc_pg_3(MPT_ADAPTER *ioc); +static void mpt_inactive_raid_list_free(MPT_ADAPTER *ioc); /* module entry point */ static int __init fusion_init (void); @@ -319,13 +326,11 @@ mpt_reply(MPT_ADAPTER *ioc, u32 pa) else if (ioc->bus_type == SAS) mpt_sas_log_info(ioc, log_info); } - if (ioc_stat & MPI_IOCSTATUS_MASK) { - if (ioc->bus_type == SPI && - cb_idx != mpt_stm_index && - cb_idx != mpt_lan_index) - mpt_sp_ioc_info(ioc, (u32)ioc_stat, mf); - } +#ifdef MPT_DEBUG_REPLY + if (ioc_stat & MPI_IOCSTATUS_MASK) + mpt_iocstatus_info(ioc, (u32)ioc_stat, mf); +#endif /* Check for (valid) IO callback! */ if (cb_idx < 1 || cb_idx >= MPT_MAX_PROTOCOL_DRIVERS || @@ -911,7 +916,7 @@ mpt_add_sge(char *pAddr, u32 flagslength int mpt_send_handshake_request(int handle, MPT_ADAPTER *ioc, int reqBytes, u32 *req, int sleepFlag) { - int r = 0; + int r = 0; u8 *req_as_bytes; int ii; @@ -1811,6 +1816,13 @@ mpt_do_ioc_recovery(MPT_ADAPTER *ioc, u3 * and we try GetLanConfigPages again... */ if ((ret == 0) && (reason == MPT_HOSTEVENT_IOC_BRINGUP)) { + + /* + * Initalize link list for inactive raid volumes. + */ + init_MUTEX(&ioc->raid_data.inactive_list_mutex); + INIT_LIST_HEAD(&ioc->raid_data.inactive_list); + if (ioc->bus_type == SAS) { /* clear persistency table */ @@ -2017,6 +2029,8 @@ mpt_adapter_disable(MPT_ADAPTER *ioc) } kfree(ioc->spi_data.nvram); + mpt_inactive_raid_list_free(ioc); + kfree(ioc->raid_data.pIocPg2); kfree(ioc->raid_data.pIocPg3); ioc->spi_data.nvram = NULL; ioc->raid_data.pIocPg3 = NULL; @@ -2413,6 +2427,9 @@ GetIocFacts(MPT_ADAPTER *ioc, int sleepF facts->FWVersion.Word = le32_to_cpu(facts->FWVersion.Word); facts->ProductID = le16_to_cpu(facts->ProductID); + if ((ioc->facts.ProductID & MPI_FW_HEADER_PID_PROD_MASK) + > MPI_FW_HEADER_PID_PROD_TARGET_SCSI) + ioc->ir_firmware = 1; facts->CurrentHostMfaHighAddr = le32_to_cpu(facts->CurrentHostMfaHighAddr); facts->GlobalCredits = le16_to_cpu(facts->GlobalCredits); @@ -2505,6 +2522,7 @@ GetPortFacts(MPT_ADAPTER *ioc, int portn int ii; int req_sz; int reply_sz; + int max_id; /* IOC *must* NOT be in RESET state! */ if (ioc->last_state == MPI_IOC_STATE_RESET) { @@ -2552,6 +2570,21 @@ GetPortFacts(MPT_ADAPTER *ioc, int portn pfacts->MaxPersistentIDs = le16_to_cpu(pfacts->MaxPersistentIDs); pfacts->MaxLanBuckets = le16_to_cpu(pfacts->MaxLanBuckets); + max_id = (ioc->bus_type == SAS) ? pfacts->PortSCSIID : + pfacts->MaxDevices; + ioc->devices_per_bus = (max_id > 255) ? 256 : max_id; + ioc->number_of_buses = (ioc->devices_per_bus < 256) ? 1 : max_id/256; + + /* + * Place all the devices on channels + * + * (for debuging) + */ + if (mpt_channel_mapping) { + ioc->devices_per_bus = 1; + ioc->number_of_buses = (max_id > 255) ? 255 : max_id; + } + return 0; } @@ -2592,13 +2625,8 @@ SendIocInit(MPT_ADAPTER *ioc, int sleepF ddlprintk((MYIOC_s_INFO_FMT "upload_fw %d facts.Flags=%x\n", ioc->name, ioc->upload_fw, ioc->facts.Flags)); - if(ioc->bus_type == SAS) - ioc_init.MaxDevices = ioc->facts.MaxDevices; - else if(ioc->bus_type == FC) - ioc_init.MaxDevices = MPT_MAX_FC_DEVICES; - else - ioc_init.MaxDevices = MPT_MAX_SCSI_DEVICES; - ioc_init.MaxBuses = MPT_MAX_BUS; + ioc_init.MaxDevices = (U8)ioc->devices_per_bus; + ioc_init.MaxBuses = (U8)ioc->number_of_buses; dinitprintk((MYIOC_s_INFO_FMT "facts.MsgVersion=%x\n", ioc->name, ioc->facts.MsgVersion)); if (ioc->facts.MsgVersion >= MPI_VERSION_01_05) { @@ -2720,9 +2748,7 @@ SendPortEnable(MPT_ADAPTER *ioc, int por /* RAID FW may take a long time to enable */ - if (((ioc->facts.ProductID & MPI_FW_HEADER_PID_PROD_MASK) - > MPI_FW_HEADER_PID_PROD_TARGET_SCSI) || - (ioc->bus_type == SAS)) { + if (ioc->ir_firmware || ioc->bus_type == SAS) { rc = mpt_handshake_req_reply_wait(ioc, req_sz, (u32*)&port_enable, reply_sz, (u16*)&reply_buf, 300 /*seconds*/, sleepFlag); @@ -3193,6 +3219,9 @@ #ifdef MPT_DEBUG u32 diag1val = 0; #endif + /* Clear any existing interrupts */ + CHIPREG_WRITE32(&ioc->chip->IntStatus, 0); + if (ioc->pcidev->device == MPI_MANUFACTPAGE_DEVID_SAS1078) { drsprintk((MYIOC_s_WARN_FMT "%s: Doorbell=%p; 1078 reset " "address=%p\n", ioc->name, __FUNCTION__, @@ -3212,7 +3241,7 @@ #endif " count=%d\n", ioc->name, doorbell, count)); if (doorbell == MPI_IOC_STATE_READY) { - return 0; + return 1; } /* wait 1 sec */ @@ -3224,9 +3253,6 @@ #endif return -1; } - /* Clear any existing interrupts */ - CHIPREG_WRITE32(&ioc->chip->IntStatus, 0); - /* Use "Diagnostic reset" method! (only thing available!) */ diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic); @@ -3942,7 +3968,7 @@ WaitForDoorbellAck(MPT_ADAPTER *ioc, int } } else { while (--cntdn) { - mdelay (1); + udelay (1000); intstat = CHIPREG_READ32(&ioc->chip->IntStatus); if (! (intstat & MPI_HIS_IOP_DOORBELL_STATUS)) break; @@ -3994,7 +4020,7 @@ WaitForDoorbellInt(MPT_ADAPTER *ioc, int intstat = CHIPREG_READ32(&ioc->chip->IntStatus); if (intstat & MPI_HIS_DOORBELL_INTERRUPT) break; - mdelay(1); + udelay (1000); count++; } } @@ -4310,8 +4336,8 @@ mptbase_raid_process_event_data(MPT_ADAP if ((reason >= MPI_EVENT_RAID_RC_PHYSDISK_CREATED && reason <= MPI_EVENT_RAID_RC_PHYSDISK_STATUS_CHANGED) || (reason == MPI_EVENT_RAID_RC_SMART_DATA)) { - printk(MYIOC_s_INFO_FMT "RAID STATUS CHANGE for PhysDisk %d\n", - ioc->name, disk); + printk(MYIOC_s_INFO_FMT "RAID STATUS CHANGE for PhysDisk %d id=%d\n", + ioc->name, disk, volume); } else { printk(MYIOC_s_INFO_FMT "RAID STATUS CHANGE for VolumeID %d\n", ioc->name, volume); @@ -4712,7 +4738,187 @@ mpt_readScsiDevicePageHeaders(MPT_ADAPTE return 0; } -/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ +/** + * mpt_inactive_raid_list_free + * + * This clears this link list. + * + * @ioc - pointer to per adapter structure + * + **/ +static void +mpt_inactive_raid_list_free(MPT_ADAPTER *ioc) +{ + struct inactive_raid_component_info *component_info, *pNext; + + if (list_empty(&ioc->raid_data.inactive_list)) + return; + + down(&ioc->raid_data.inactive_list_mutex); + list_for_each_entry_safe(component_info, pNext, + &ioc->raid_data.inactive_list, list) { + list_del(&component_info->list); + kfree(component_info); + } + up(&ioc->raid_data.inactive_list_mutex); +} + +/** + * mpt_inactive_raid_volumes + * + * This sets up link list of phy_disk_nums for devices belonging in an inactive volume + * + * @ioc - pointer to per adapter structure + * @channel - volume channel + * @id - volume target id + * + * + **/ +static void +mpt_inactive_raid_volumes(MPT_ADAPTER *ioc, u8 channel, u8 id) +{ + CONFIGPARMS cfg; + ConfigPageHeader_t hdr; + dma_addr_t dma_handle; + pRaidVolumePage0_t buffer = NULL; + int i; + RaidPhysDiskPage0_t phys_disk; + struct inactive_raid_component_info *component_info; + int handle_inactive_volumes; + + memset(&cfg, 0 , sizeof(CONFIGPARMS)); + memset(&hdr, 0 , sizeof(ConfigPageHeader_t)); + hdr.PageType = MPI_CONFIG_PAGETYPE_RAID_VOLUME; + cfg.pageAddr = (channel << 8) + id; + cfg.cfghdr.hdr = &hdr; + cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER; + + if (mpt_config(ioc, &cfg) != 0) + goto out; + + if (!hdr.PageLength) + goto out; + + buffer = pci_alloc_consistent(ioc->pcidev, hdr.PageLength * 4, + &dma_handle); + + if (!buffer) + goto out; + + cfg.physAddr = dma_handle; + cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT; + + if (mpt_config(ioc, &cfg) != 0) + goto out; + + if (!buffer->NumPhysDisks) + goto out; + + handle_inactive_volumes = + (buffer->VolumeStatus.Flags & MPI_RAIDVOL0_STATUS_FLAG_VOLUME_INACTIVE || + (buffer->VolumeStatus.Flags & MPI_RAIDVOL0_STATUS_FLAG_ENABLED) == 0 || + buffer->VolumeStatus.State == MPI_RAIDVOL0_STATUS_STATE_FAILED || + buffer->VolumeStatus.State == MPI_RAIDVOL0_STATUS_STATE_MISSING) ? 1 : 0; + + if (!handle_inactive_volumes) + goto out; + + down(&ioc->raid_data.inactive_list_mutex); + for (i = 0; i < buffer->NumPhysDisks; i++) { + if(mpt_raid_phys_disk_pg0(ioc, + buffer->PhysDisk[i].PhysDiskNum, &phys_disk) != 0) + continue; + + if ((component_info = kmalloc(sizeof (*component_info), + GFP_KERNEL)) == NULL) + continue; + + component_info->volumeID = id; + component_info->volumeBus = channel; + component_info->d.PhysDiskNum = phys_disk.PhysDiskNum; + component_info->d.PhysDiskBus = phys_disk.PhysDiskBus; + component_info->d.PhysDiskID = phys_disk.PhysDiskID; + component_info->d.PhysDiskIOC = phys_disk.PhysDiskIOC; + + list_add_tail(&component_info->list, + &ioc->raid_data.inactive_list); + } + up(&ioc->raid_data.inactive_list_mutex); + + out: + if (buffer) + pci_free_consistent(ioc->pcidev, hdr.PageLength * 4, buffer, + dma_handle); +} + +/** + * mpt_raid_phys_disk_pg0 - returns phys disk page zero + * @ioc: Pointer to a Adapter Structure + * @phys_disk_num: io unit unique phys disk num generated by the ioc + * @phys_disk: requested payload data returned + * + * Return: + * 0 on success + * -EFAULT if read of config page header fails or data pointer not NULL + * -ENOMEM if pci_alloc failed + **/ +int +mpt_raid_phys_disk_pg0(MPT_ADAPTER *ioc, u8 phys_disk_num, pRaidPhysDiskPage0_t phys_disk) +{ + CONFIGPARMS cfg; + ConfigPageHeader_t hdr; + dma_addr_t dma_handle; + pRaidPhysDiskPage0_t buffer = NULL; + int rc; + + memset(&cfg, 0 , sizeof(CONFIGPARMS)); + memset(&hdr, 0 , sizeof(ConfigPageHeader_t)); + + hdr.PageType = MPI_CONFIG_PAGETYPE_RAID_PHYSDISK; + cfg.cfghdr.hdr = &hdr; + cfg.physAddr = -1; + cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER; + + if (mpt_config(ioc, &cfg) != 0) { + rc = -EFAULT; + goto out; + } + + if (!hdr.PageLength) { + rc = -EFAULT; + goto out; + } + + buffer = pci_alloc_consistent(ioc->pcidev, hdr.PageLength * 4, + &dma_handle); + + if (!buffer) { + rc = -ENOMEM; + goto out; + } + + cfg.physAddr = dma_handle; + cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT; + cfg.pageAddr = phys_disk_num; + + if (mpt_config(ioc, &cfg) != 0) { + rc = -EFAULT; + goto out; + } + + rc = 0; + memcpy(phys_disk, buffer, sizeof(*buffer)); + phys_disk->MaxLBA = le32_to_cpu(buffer->MaxLBA); + + out: + + if (buffer) + pci_free_consistent(ioc->pcidev, hdr.PageLength * 4, buffer, + dma_handle); + + return rc; +} + /** * mpt_findImVolumes - Identify IDs of hidden disks and RAID Volumes * @ioc: Pointer to a Adapter Strucutre @@ -4722,21 +4928,27 @@ mpt_readScsiDevicePageHeaders(MPT_ADAPTE * 0 on success * -EFAULT if read of config page header fails or data pointer not NULL * -ENOMEM if pci_alloc failed - */ + **/ int mpt_findImVolumes(MPT_ADAPTER *ioc) { IOCPage2_t *pIoc2; u8 *mem; - ConfigPageIoc2RaidVol_t *pIocRv; dma_addr_t ioc2_dma; CONFIGPARMS cfg; ConfigPageHeader_t header; - int jj; int rc = 0; int iocpage2sz; - u8 nVols, nPhys; - u8 vid, vbus, vioc; + int i; + + if (!ioc->ir_firmware) + return 0; + + /* Free the old page + */ + kfree(ioc->raid_data.pIocPg2); + ioc->raid_data.pIocPg2 = NULL; + mpt_inactive_raid_list_free(ioc); /* Read IOCP2 header then the page. */ @@ -4764,55 +4976,23 @@ mpt_findImVolumes(MPT_ADAPTER *ioc) cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT; cfg.physAddr = ioc2_dma; if (mpt_config(ioc, &cfg) != 0) - goto done_and_free; + goto out; + + mem = kmalloc(iocpage2sz, GFP_KERNEL); + if (!mem) + goto out; - if ( (mem = (u8 *)ioc->raid_data.pIocPg2) == NULL ) { - mem = kmalloc(iocpage2sz, GFP_ATOMIC); - if (mem) { - ioc->raid_data.pIocPg2 = (IOCPage2_t *) mem; - } else { - goto done_and_free; - } - } memcpy(mem, (u8 *)pIoc2, iocpage2sz); + ioc->raid_data.pIocPg2 = (IOCPage2_t *) mem; - /* Identify RAID Volume Id's */ - nVols = pIoc2->NumActiveVolumes; - if ( nVols == 0) { - /* No RAID Volume. - */ - goto done_and_free; - } else { - /* At least 1 RAID Volume - */ - pIocRv = pIoc2->RaidVolume; - ioc->raid_data.isRaid = 0; - for (jj = 0; jj < nVols; jj++, pIocRv++) { - vid = pIocRv->VolumeID; - vbus = pIocRv->VolumeBus; - vioc = pIocRv->VolumeIOC; - - /* find the match - */ - if (vbus == 0) { - ioc->raid_data.isRaid |= (1 << vid); - } else { - /* Error! Always bus 0 - */ - } - } - } + mpt_read_ioc_pg_3(ioc); - /* Identify Hidden Physical Disk Id's */ - nPhys = pIoc2->NumActivePhysDisks; - if (nPhys == 0) { - /* No physical disks. - */ - } else { - mpt_read_ioc_pg_3(ioc); - } + for (i = 0; i < pIoc2->NumActiveVolumes ; i++) + mpt_inactive_raid_volumes(ioc, + pIoc2->RaidVolume[i].VolumeBus, + pIoc2->RaidVolume[i].VolumeID); -done_and_free: + out: pci_free_consistent(ioc->pcidev, iocpage2sz, pIoc2, ioc2_dma); return rc; @@ -4865,7 +5045,7 @@ mpt_read_ioc_pg_3(MPT_ADAPTER *ioc) cfg.physAddr = ioc3_dma; cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT; if (mpt_config(ioc, &cfg) == 0) { - mem = kmalloc(iocpage3sz, GFP_ATOMIC); + mem = kmalloc(iocpage3sz, GFP_KERNEL); if (mem) { memcpy(mem, (u8 *)pIoc3, iocpage3sz); ioc->raid_data.pIocPg3 = (IOCPage3_t *) mem; @@ -5679,8 +5859,6 @@ #endif return rc; } -# define EVENT_DESCR_STR_SZ 100 - /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ static void EventDescriptionStr(u8 event, u32 evData0, char *evStr) @@ -5708,9 +5886,6 @@ EventDescriptionStr(u8 event, u32 evData break; case MPI_EVENT_RESCAN: ds = "Bus Rescan Event"; - /* Ok, do we need to do anything here? As far as - I can tell, this is when a new device gets added - to the loop. */ break; case MPI_EVENT_LINK_STATUS_CHANGE: if (evData0 == MPI_EVENT_LINK_STATUS_FAILURE) @@ -5787,48 +5962,63 @@ EventDescriptionStr(u8 event, u32 evData case MPI_EVENT_SAS_DEVICE_STATUS_CHANGE: { u8 id = (u8)(evData0); + u8 channel = (u8)(evData0 >> 8); u8 ReasonCode = (u8)(evData0 >> 16); switch (ReasonCode) { case MPI_EVENT_SAS_DEV_STAT_RC_ADDED: snprintf(evStr, EVENT_DESCR_STR_SZ, - "SAS Device Status Change: Added: id=%d", id); + "SAS Device Status Change: Added: " + "id=%d channel=%d", id, channel); break; case MPI_EVENT_SAS_DEV_STAT_RC_NOT_RESPONDING: snprintf(evStr, EVENT_DESCR_STR_SZ, - "SAS Device Status Change: Deleted: id=%d", id); + "SAS Device Status Change: Deleted: " + "id=%d channel=%d", id, channel); break; case MPI_EVENT_SAS_DEV_STAT_RC_SMART_DATA: snprintf(evStr, EVENT_DESCR_STR_SZ, - "SAS Device Status Change: SMART Data: id=%d", - id); + "SAS Device Status Change: SMART Data: " + "id=%d channel=%d", id, channel); break; case MPI_EVENT_SAS_DEV_STAT_RC_NO_PERSIST_ADDED: snprintf(evStr, EVENT_DESCR_STR_SZ, - "SAS Device Status Change: No Persistancy: id=%d", id); + "SAS Device Status Change: No Persistancy: " + "id=%d channel=%d", id, channel); + break; + case MPI_EVENT_SAS_DEV_STAT_RC_UNSUPPORTED: + snprintf(evStr, EVENT_DESCR_STR_SZ, + "SAS Device Status Change: Unsupported Device " + "Discovered : id=%d channel=%d", id, channel); break; case MPI_EVENT_SAS_DEV_STAT_RC_INTERNAL_DEVICE_RESET: snprintf(evStr, EVENT_DESCR_STR_SZ, - "SAS Device Status Change: Internal Device Reset : id=%d", id); + "SAS Device Status Change: Internal Device " + "Reset : id=%d channel=%d", id, channel); break; case MPI_EVENT_SAS_DEV_STAT_RC_TASK_ABORT_INTERNAL: snprintf(evStr, EVENT_DESCR_STR_SZ, - "SAS Device Status Change: Internal Task Abort : id=%d", id); + "SAS Device Status Change: Internal Task " + "Abort : id=%d channel=%d", id, channel); break; case MPI_EVENT_SAS_DEV_STAT_RC_ABORT_TASK_SET_INTERNAL: snprintf(evStr, EVENT_DESCR_STR_SZ, - "SAS Device Status Change: Internal Abort Task Set : id=%d", id); + "SAS Device Status Change: Internal Abort " + "Task Set : id=%d channel=%d", id, channel); break; case MPI_EVENT_SAS_DEV_STAT_RC_CLEAR_TASK_SET_INTERNAL: snprintf(evStr, EVENT_DESCR_STR_SZ, - "SAS Device Status Change: Internal Clear Task Set : id=%d", id); + "SAS Device Status Change: Internal Clear " + "Task Set : id=%d channel=%d", id, channel); break; case MPI_EVENT_SAS_DEV_STAT_RC_QUERY_TASK_INTERNAL: snprintf(evStr, EVENT_DESCR_STR_SZ, - "SAS Device Status Change: Internal Query Task : id=%d", id); + "SAS Device Status Change: Internal Query " + "Task : id=%d channel=%d", id, channel); break; default: snprintf(evStr, EVENT_DESCR_STR_SZ, - "SAS Device Status Change: Unknown: id=%d", id); + "SAS Device Status Change: Unknown: " + "id=%d channel=%d", id, channel); break; } break; @@ -5837,8 +6027,16 @@ EventDescriptionStr(u8 event, u32 evData ds = "Bus Timer Expired"; break; case MPI_EVENT_QUEUE_FULL: - ds = "Queue Full"; + { + u16 curr_depth = (u16)(evData0 >> 16); + u8 channel = (u8)(evData0 >> 8); + u8 id = (u8)(evData0); + + snprintf(evStr, EVENT_DESCR_STR_SZ, + "Queue Full: channel=%d id=%d depth=%d", + channel, id, curr_depth); break; + } case MPI_EVENT_SAS_SES: ds = "SAS SES Event"; break; @@ -5942,6 +6140,76 @@ EventDescriptionStr(u8 event, u32 evData ds = "SAS Log Entry Added"; break; + case MPI_EVENT_SAS_BROADCAST_PRIMITIVE: + { + u8 phy_num = (u8)(evData0); + u8 port_num = (u8)(evData0 >> 8); + u8 port_width = (u8)(evData0 >> 16); + u8 primative = (u8)(evData0 >> 24); + snprintf(evStr, EVENT_DESCR_STR_SZ, + "SAS Broadcase Primative: phy=%d port=%d " + "width=%d primative=0x%02x", + phy_num, port_num, port_width, primative); + break; + } + + case MPI_EVENT_SAS_INIT_DEVICE_STATUS_CHANGE: + { + u8 reason = (u8)(evData0); + u8 port_num = (u8)(evData0 >> 8); + u16 handle = le16_to_cpu(evData0 >> 16); + + snprintf(evStr, EVENT_DESCR_STR_SZ, + "SAS Initiator Device Status Change: reason=0x%02x " + "port=%d handle=0x%04x", + reason, port_num, handle); + break; + } + + case MPI_EVENT_SAS_INIT_TABLE_OVERFLOW: + { + u8 max_init = (u8)(evData0); + u8 current_init = (u8)(evData0 >> 8); + + snprintf(evStr, EVENT_DESCR_STR_SZ, + "SAS Initiator Device Table Overflow: max initiators=%02d " + "current initators=%02d", + max_init, current_init); + break; + } + case MPI_EVENT_SAS_SMP_ERROR: + { + u8 status = (u8)(evData0); + u8 port_num = (u8)(evData0 >> 8); + u8 result = (u8)(evData0 >> 16); + + if (status == MPI_EVENT_SAS_SMP_FUNCTION_RESULT_VALID) + snprintf(evStr, EVENT_DESCR_STR_SZ, + "SAS SMP Error: port=%d result=0x%02x", + port_num, result); + else if (status == MPI_EVENT_SAS_SMP_CRC_ERROR) + snprintf(evStr, EVENT_DESCR_STR_SZ, + "SAS SMP Error: port=%d : CRC Error", + port_num); + else if (status == MPI_EVENT_SAS_SMP_TIMEOUT) + snprintf(evStr, EVENT_DESCR_STR_SZ, + "SAS SMP Error: port=%d : Timeout", + port_num); + else if (status == MPI_EVENT_SAS_SMP_NO_DESTINATION) + snprintf(evStr, EVENT_DESCR_STR_SZ, + "SAS SMP Error: port=%d : No Destination", + port_num); + else if (status == MPI_EVENT_SAS_SMP_BAD_DESTINATION) + snprintf(evStr, EVENT_DESCR_STR_SZ, + "SAS SMP Error: port=%d : Bad Destination", + port_num); + else + snprintf(evStr, EVENT_DESCR_STR_SZ, + "SAS SMP Error: port=%d : status=0x%02x", + port_num, status); + break; + } + /* * MPT base "custom" events may be added here... */ @@ -6205,10 +6473,11 @@ mpt_spi_log_info(MPT_ADAPTER *ioc, u32 l "Abort", /* 12h */ "IO Not Yet Executed", /* 13h */ "IO Executed", /* 14h */ - "Persistent Reservation Out Not Affiliation Owner", /* 15h */ + "Persistent Reservation Out Not Affiliation " + "Owner", /* 15h */ "Open Transmit DMA Abort", /* 16h */ "IO Device Missing Delay Retry", /* 17h */ - NULL, /* 18h */ + "IO Cancelled Due to Recieve Error", /* 18h */ NULL, /* 19h */ NULL, /* 1Ah */ NULL, /* 1Bh */ @@ -6218,6 +6487,96 @@ mpt_spi_log_info(MPT_ADAPTER *ioc, u32 l NULL, /* 1Fh */ "Enclosure Management" /* 20h */ }; + static char *ir_code_str[] = { + "Raid Action Error", /* 00h */ + NULL, /* 00h */ + NULL, /* 01h */ + NULL, /* 02h */ + NULL, /* 03h */ + NULL, /* 04h */ + NULL, /* 05h */ + NULL, /* 06h */ + NULL /* 07h */ + }; + static char *raid_sub_code_str[] = { + NULL, /* 00h */ + "Volume Creation Failed: Data Passed too " + "Large", /* 01h */ + "Volume Creation Failed: Duplicate Volumes " + "Attempted", /* 02h */ + "Volume Creation Failed: Max Number " + "Supported Volumes Exceeded", /* 03h */ + "Volume Creation Failed: DMA Error", /* 04h */ + "Volume Creation Failed: Invalid Volume Type", /* 05h */ + "Volume Creation Failed: Error Reading " + "MFG Page 4", /* 06h */ + "Volume Creation Failed: Creating Internal " + "Structures", /* 07h */ + NULL, /* 08h */ + NULL, /* 09h */ + NULL, /* 0Ah */ + NULL, /* 0Bh */ + NULL, /* 0Ch */ + NULL, /* 0Dh */ + NULL, /* 0Eh */ + NULL, /* 0Fh */ + "Activation failed: Already Active Volume", /* 10h */ + "Activation failed: Unsupported Volume Type", /* 11h */ + "Activation failed: Too Many Active Volumes", /* 12h */ + "Activation failed: Volume ID in Use", /* 13h */ + "Activation failed: Reported Failure", /* 14h */ + "Activation failed: Importing a Volume", /* 15h */ + NULL, /* 16h */ + NULL, /* 17h */ + NULL, /* 18h */ + NULL, /* 19h */ + NULL, /* 1Ah */ + NULL, /* 1Bh */ + NULL, /* 1Ch */ + NULL, /* 1Dh */ + NULL, /* 1Eh */ + NULL, /* 1Fh */ + "Phys Disk failed: Too Many Phys Disks", /* 20h */ + "Phys Disk failed: Data Passed too Large", /* 21h */ + "Phys Disk failed: DMA Error", /* 22h */ + "Phys Disk failed: Invalid ", /* 23h */ + "Phys Disk failed: Creating Phys Disk Config " + "Page", /* 24h */ + NULL, /* 25h */ + NULL, /* 26h */ + NULL, /* 27h */ + NULL, /* 28h */ + NULL, /* 29h */ + NULL, /* 2Ah */ + NULL, /* 2Bh */ + NULL, /* 2Ch */ + NULL, /* 2Dh */ + NULL, /* 2Eh */ + NULL, /* 2Fh */ + "Compatibility Error: IR Disabled", /* 30h */ + "Compatibility Error: Inquiry Comand Failed", /* 31h */ + "Compatibility Error: Device not Direct Access " + "Device ", /* 32h */ + "Compatibility Error: Removable Device Found", /* 33h */ + "Compatibility Error: Device SCSI Version not " + "2 or Higher", /* 34h */ + "Compatibility Error: SATA Device, 48 BIT LBA " + "not Supported", /* 35h */ + "Compatibility Error: Device doesn't have " + "512 Byte Block Sizes", /* 36h */ + "Compatibility Error: Volume Type Check Failed", /* 37h */ + "Compatibility Error: Volume Type is " + "Unsupported by FW", /* 38h */ + "Compatibility Error: Disk Drive too Small for " + "use in Volume", /* 39h */ + "Compatibility Error: Phys Disk for Create " + "Volume not Found", /* 3Ah */ + "Compatibility Error: Too Many or too Few " + "Disks for Volume Type", /* 3Bh */ + "Compatibility Error: Disk stripe Sizes " + "Must be 64KB", /* 3Ch */ + "Compatibility Error: IME Size Limited to < 2TB", /* 3Dh */ + }; /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ /** @@ -6226,7 +6585,7 @@ mpt_spi_log_info(MPT_ADAPTER *ioc, u32 l * @log_info: U32 LogInfo reply word from the IOC * * Refer to lsi/mpi_log_sas.h. - */ + **/ static void mpt_sas_log_info(MPT_ADAPTER *ioc, u32 log_info) { @@ -6240,56 +6599,165 @@ union loginfo_type { }dw; }; union loginfo_type sas_loginfo; + char *originator_desc = NULL; char *code_desc = NULL; + char *sub_code_desc = NULL; sas_loginfo.loginfo = log_info; if ((sas_loginfo.dw.bus_type != 3 /*SAS*/) && (sas_loginfo.dw.originator < sizeof(originator_str)/sizeof(char*))) return; - if ((sas_loginfo.dw.originator == 0 /*IOP*/) && - (sas_loginfo.dw.code < sizeof(iop_code_str)/sizeof(char*))) { - code_desc = iop_code_str[sas_loginfo.dw.code]; - }else if ((sas_loginfo.dw.originator == 1 /*PL*/) && - (sas_loginfo.dw.code < sizeof(pl_code_str)/sizeof(char*) )) { - code_desc = pl_code_str[sas_loginfo.dw.code]; + + originator_desc = originator_str[sas_loginfo.dw.originator]; + + switch (sas_loginfo.dw.originator) { + + case 0: /* IOP */ + if (sas_loginfo.dw.code < + sizeof(iop_code_str)/sizeof(char*)) + code_desc = iop_code_str[sas_loginfo.dw.code]; + break; + case 1: /* PL */ + if (sas_loginfo.dw.code < + sizeof(pl_code_str)/sizeof(char*)) + code_desc = pl_code_str[sas_loginfo.dw.code]; + break; + case 2: /* IR */ + if (sas_loginfo.dw.code >= + sizeof(ir_code_str)/sizeof(char*)) + break; + code_desc = ir_code_str[sas_loginfo.dw.code]; + if (sas_loginfo.dw.subcode >= + sizeof(raid_sub_code_str)/sizeof(char*)) + break; + if (sas_loginfo.dw.code == 0) + sub_code_desc = + raid_sub_code_str[sas_loginfo.dw.subcode]; + break; + default: + return; } - if (code_desc != NULL) + if (sub_code_desc != NULL) + printk(MYIOC_s_INFO_FMT + "LogInfo(0x%08x): Originator={%s}, Code={%s}," + " SubCode={%s}\n", + ioc->name, log_info, originator_desc, code_desc, + sub_code_desc); + else if (code_desc != NULL) printk(MYIOC_s_INFO_FMT "LogInfo(0x%08x): Originator={%s}, Code={%s}," " SubCode(0x%04x)\n", - ioc->name, - log_info, - originator_str[sas_loginfo.dw.originator], - code_desc, + ioc->name, log_info, originator_desc, code_desc, sas_loginfo.dw.subcode); else printk(MYIOC_s_INFO_FMT "LogInfo(0x%08x): Originator={%s}, Code=(0x%02x)," " SubCode(0x%04x)\n", - ioc->name, - log_info, - originator_str[sas_loginfo.dw.originator], - sas_loginfo.dw.code, - sas_loginfo.dw.subcode); + ioc->name, log_info, originator_desc, + sas_loginfo.dw.code, sas_loginfo.dw.subcode); } +#ifdef MPT_DEBUG_REPLY /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ /** - * mpt_sp_ioc_info - IOC information returned from SCSI Parallel IOC. + * mpt_iocstatus_info_config - IOCSTATUS information for config pages + * @ioc: Pointer to MPT_ADAPTER structure + * ioc_status: U32 IOCStatus word from IOC + * @mf: Pointer to MPT request frame + * + * Refer to lsi/mpi.h. + **/ +static void +mpt_iocstatus_info_config(MPT_ADAPTER *ioc, u32 ioc_status, MPT_FRAME_HDR *mf) +{ + Config_t *pReq = (Config_t *)mf; + char extend_desc[EVENT_DESCR_STR_SZ]; + char *desc = NULL; + u32 form; + u8 page_type; + + if (pReq->Header.PageType == MPI_CONFIG_PAGETYPE_EXTENDED) + page_type = pReq->ExtPageType; + else + page_type = pReq->Header.PageType; + + /* + * ignore invalid page messages for GET_NEXT_HANDLE + */ + form = le32_to_cpu(pReq->PageAddress); + if (ioc_status == MPI_IOCSTATUS_CONFIG_INVALID_PAGE) { + if (page_type == MPI_CONFIG_EXTPAGETYPE_SAS_DEVICE || + page_type == MPI_CONFIG_EXTPAGETYPE_SAS_EXPANDER || + page_type == MPI_CONFIG_EXTPAGETYPE_ENCLOSURE) { + if ((form >> MPI_SAS_DEVICE_PGAD_FORM_SHIFT) == + MPI_SAS_DEVICE_PGAD_FORM_GET_NEXT_HANDLE) + return; + } + if (page_type == MPI_CONFIG_PAGETYPE_FC_DEVICE) + if ((form & MPI_FC_DEVICE_PGAD_FORM_MASK) == + MPI_FC_DEVICE_PGAD_FORM_NEXT_DID) + return; + } + + snprintf(extend_desc, EVENT_DESCR_STR_SZ, + "type=%02Xh, page=%02Xh, action=%02Xh, form=%08Xh", + page_type, pReq->Header.PageNumber, pReq->Action, form); + + switch (ioc_status) { + + case MPI_IOCSTATUS_CONFIG_INVALID_ACTION: /* 0x0020 */ + desc = "Config Page Invalid Action"; + break; + + case MPI_IOCSTATUS_CONFIG_INVALID_TYPE: /* 0x0021 */ + desc = "Config Page Invalid Type"; + break; + + case MPI_IOCSTATUS_CONFIG_INVALID_PAGE: /* 0x0022 */ + desc = "Config Page Invalid Page"; + break; + + case MPI_IOCSTATUS_CONFIG_INVALID_DATA: /* 0x0023 */ + desc = "Config Page Invalid Data"; + break; + + case MPI_IOCSTATUS_CONFIG_NO_DEFAULTS: /* 0x0024 */ + desc = "Config Page No Defaults"; + break; + + case MPI_IOCSTATUS_CONFIG_CANT_COMMIT: /* 0x0025 */ + desc = "Config Page Can't Commit"; + break; + } + + if (!desc) + return; + + printk(MYIOC_s_INFO_FMT "IOCStatus(0x%04X): %s: %s\n", + ioc->name, ioc_status, desc, extend_desc); +} + +/** + * mpt_iocstatus_info - IOCSTATUS information returned from IOC. * @ioc: Pointer to MPT_ADAPTER structure * @ioc_status: U32 IOCStatus word from IOC * @mf: Pointer to MPT request frame * * Refer to lsi/mpi.h. - */ + **/ static void -mpt_sp_ioc_info(MPT_ADAPTER *ioc, u32 ioc_status, MPT_FRAME_HDR *mf) +mpt_iocstatus_info(MPT_ADAPTER *ioc, u32 ioc_status, MPT_FRAME_HDR *mf) { u32 status = ioc_status & MPI_IOCSTATUS_MASK; char *desc = NULL; switch (status) { + +/****************************************************************************/ +/* Common IOCStatus values for all replies */ +/****************************************************************************/ + case MPI_IOCSTATUS_INVALID_FUNCTION: /* 0x0001 */ desc = "Invalid Function"; break; @@ -6322,84 +6790,180 @@ mpt_sp_ioc_info(MPT_ADAPTER *ioc, u32 io desc = "Invalid State"; break; +/****************************************************************************/ +/* Config IOCStatus values */ +/****************************************************************************/ + case MPI_IOCSTATUS_CONFIG_INVALID_ACTION: /* 0x0020 */ case MPI_IOCSTATUS_CONFIG_INVALID_TYPE: /* 0x0021 */ case MPI_IOCSTATUS_CONFIG_INVALID_PAGE: /* 0x0022 */ case MPI_IOCSTATUS_CONFIG_INVALID_DATA: /* 0x0023 */ case MPI_IOCSTATUS_CONFIG_NO_DEFAULTS: /* 0x0024 */ case MPI_IOCSTATUS_CONFIG_CANT_COMMIT: /* 0x0025 */ - /* No message for Config IOCStatus values */ + mpt_iocstatus_info_config(ioc, status, mf); break; +/****************************************************************************/ +/* SCSIIO Reply (SPI, FCP, SAS) initiator values */ +/* */ +/* Look at mptscsih_iocstatus_info_scsiio in mptscsih.c */ +/* */ +/****************************************************************************/ + case MPI_IOCSTATUS_SCSI_RECOVERED_ERROR: /* 0x0040 */ - /* No message for recovered error - desc = "SCSI Recovered Error"; - */ + case MPI_IOCSTATUS_SCSI_DATA_UNDERRUN: /* 0x0045 */ + case MPI_IOCSTATUS_SCSI_INVALID_BUS: /* 0x0041 */ + case MPI_IOCSTATUS_SCSI_INVALID_TARGETID: /* 0x0042 */ + case MPI_IOCSTATUS_SCSI_DEVICE_NOT_THERE: /* 0x0043 */ + case MPI_IOCSTATUS_SCSI_DATA_OVERRUN: /* 0x0044 */ + case MPI_IOCSTATUS_SCSI_IO_DATA_ERROR: /* 0x0046 */ + case MPI_IOCSTATUS_SCSI_PROTOCOL_ERROR: /* 0x0047 */ + case MPI_IOCSTATUS_SCSI_TASK_TERMINATED: /* 0x0048 */ + case MPI_IOCSTATUS_SCSI_RESIDUAL_MISMATCH: /* 0x0049 */ + case MPI_IOCSTATUS_SCSI_TASK_MGMT_FAILED: /* 0x004A */ + case MPI_IOCSTATUS_SCSI_IOC_TERMINATED: /* 0x004B */ + case MPI_IOCSTATUS_SCSI_EXT_TERMINATED: /* 0x004C */ break; - case MPI_IOCSTATUS_SCSI_INVALID_BUS: /* 0x0041 */ - desc = "SCSI Invalid Bus"; +/****************************************************************************/ +/* SCSI Target values */ +/****************************************************************************/ + + case MPI_IOCSTATUS_TARGET_PRIORITY_IO: /* 0x0060 */ + desc = "Target: Priority IO"; break; - case MPI_IOCSTATUS_SCSI_INVALID_TARGETID: /* 0x0042 */ - desc = "SCSI Invalid TargetID"; + case MPI_IOCSTATUS_TARGET_INVALID_PORT: /* 0x0061 */ + desc = "Target: Invalid Port"; break; - case MPI_IOCSTATUS_SCSI_DEVICE_NOT_THERE: /* 0x0043 */ - { - SCSIIORequest_t *pScsiReq = (SCSIIORequest_t *) mf; - U8 cdb = pScsiReq->CDB[0]; - if (cdb != 0x12) { /* Inquiry is issued for device scanning */ - desc = "SCSI Device Not There"; - } + case MPI_IOCSTATUS_TARGET_INVALID_IO_INDEX: /* 0x0062 */ + desc = "Target Invalid IO Index:"; break; - } - case MPI_IOCSTATUS_SCSI_DATA_OVERRUN: /* 0x0044 */ - desc = "SCSI Data Overrun"; + case MPI_IOCSTATUS_TARGET_ABORTED: /* 0x0063 */ + desc = "Target: Aborted"; break; - case MPI_IOCSTATUS_SCSI_DATA_UNDERRUN: /* 0x0045 */ - /* This error is checked in scsi_io_done(). Skip. - desc = "SCSI Data Underrun"; - */ + case MPI_IOCSTATUS_TARGET_NO_CONN_RETRYABLE: /* 0x0064 */ + desc = "Target: No Conn Retryable"; break; - case MPI_IOCSTATUS_SCSI_IO_DATA_ERROR: /* 0x0046 */ - desc = "SCSI I/O Data Error"; + case MPI_IOCSTATUS_TARGET_NO_CONNECTION: /* 0x0065 */ + desc = "Target: No Connection"; break; - case MPI_IOCSTATUS_SCSI_PROTOCOL_ERROR: /* 0x0047 */ - desc = "SCSI Protocol Error"; + case MPI_IOCSTATUS_TARGET_XFER_COUNT_MISMATCH: /* 0x006A */ + desc = "Target: Transfer Count Mismatch"; break; - case MPI_IOCSTATUS_SCSI_TASK_TERMINATED: /* 0x0048 */ - desc = "SCSI Task Terminated"; + case MPI_IOCSTATUS_TARGET_STS_DATA_NOT_SENT: /* 0x006B */ + desc = "Target: STS Data not Sent"; break; - case MPI_IOCSTATUS_SCSI_RESIDUAL_MISMATCH: /* 0x0049 */ - desc = "SCSI Residual Mismatch"; + case MPI_IOCSTATUS_TARGET_DATA_OFFSET_ERROR: /* 0x006D */ + desc = "Target: Data Offset Error"; break; - case MPI_IOCSTATUS_SCSI_TASK_MGMT_FAILED: /* 0x004A */ - desc = "SCSI Task Management Failed"; + case MPI_IOCSTATUS_TARGET_TOO_MUCH_WRITE_DATA: /* 0x006E */ + desc = "Target: Too Much Write Data"; break; - case MPI_IOCSTATUS_SCSI_IOC_TERMINATED: /* 0x004B */ - desc = "SCSI IOC Terminated"; + case MPI_IOCSTATUS_TARGET_IU_TOO_SHORT: /* 0x006F */ + desc = "Target: IU Too Short"; break; - case MPI_IOCSTATUS_SCSI_EXT_TERMINATED: /* 0x004C */ - desc = "SCSI Ext Terminated"; + case MPI_IOCSTATUS_TARGET_ACK_NAK_TIMEOUT: /* 0x0070 */ + desc = "Target: ACK NAK Timeout"; + break; + + case MPI_IOCSTATUS_TARGET_NAK_RECEIVED: /* 0x0071 */ + desc = "Target: Nak Received"; + break; + +/****************************************************************************/ +/* Fibre Channel Direct Access values */ +/****************************************************************************/ + + case MPI_IOCSTATUS_FC_ABORTED: /* 0x0066 */ + desc = "FC: Aborted"; + break; + + case MPI_IOCSTATUS_FC_RX_ID_INVALID: /* 0x0067 */ + desc = "FC: RX ID Invalid"; + break; + + case MPI_IOCSTATUS_FC_DID_INVALID: /* 0x0068 */ + desc = "FC: DID Invalid"; + break; + + case MPI_IOCSTATUS_FC_NODE_LOGGED_OUT: /* 0x0069 */ + desc = "FC: Node Logged Out"; + break; + + case MPI_IOCSTATUS_FC_EXCHANGE_CANCELED: /* 0x006C */ + desc = "FC: Exchange Canceled"; + break; + +/****************************************************************************/ +/* LAN values */ +/****************************************************************************/ + + case MPI_IOCSTATUS_LAN_DEVICE_NOT_FOUND: /* 0x0080 */ + desc = "LAN: Device not Found"; + break; + + case MPI_IOCSTATUS_LAN_DEVICE_FAILURE: /* 0x0081 */ + desc = "LAN: Device Failure"; + break; + + case MPI_IOCSTATUS_LAN_TRANSMIT_ERROR: /* 0x0082 */ + desc = "LAN: Transmit Error"; + break; + + case MPI_IOCSTATUS_LAN_TRANSMIT_ABORTED: /* 0x0083 */ + desc = "LAN: Transmit Aborted"; + break; + + case MPI_IOCSTATUS_LAN_RECEIVE_ERROR: /* 0x0084 */ + desc = "LAN: Receive Error"; + break; + + case MPI_IOCSTATUS_LAN_RECEIVE_ABORTED: /* 0x0085 */ + desc = "LAN: Receive Aborted"; + break; + + case MPI_IOCSTATUS_LAN_PARTIAL_PACKET: /* 0x0086 */ + desc = "LAN: Partial Packet"; + break; + + case MPI_IOCSTATUS_LAN_CANCELED: /* 0x0087 */ + desc = "LAN: Canceled"; + break; + +/****************************************************************************/ +/* Serial Attached SCSI values */ +/****************************************************************************/ + + case MPI_IOCSTATUS_SAS_SMP_REQUEST_FAILED: /* 0x0090 */ + desc = "SAS: SMP Request Failed"; + break; + + case MPI_IOCSTATUS_SAS_SMP_DATA_OVERRUN: /* 0x0090 */ + desc = "SAS: SMP Data Overrun"; break; default: desc = "Others"; break; } - if (desc != NULL) - printk(MYIOC_s_INFO_FMT "IOCStatus(0x%04x): %s\n", ioc->name, status, desc); + + if (!desc) + return; + + printk(MYIOC_s_INFO_FMT "IOCStatus(0x%04X): %s\n", ioc->name, status, desc); } +#endif /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ EXPORT_SYMBOL(mpt_attach); @@ -6434,6 +6998,7 @@ EXPORT_SYMBOL(mpt_findImVolumes); EXPORT_SYMBOL(mpt_alloc_fw_memory); EXPORT_SYMBOL(mpt_free_fw_memory); EXPORT_SYMBOL(mptbase_sas_persist_operation); +EXPORT_SYMBOL(mpt_raid_phys_disk_pg0); /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ /** diff --git a/drivers/message/fusion/mptbase.h b/drivers/message/fusion/mptbase.h index e316708..e3a3927 100644 --- a/drivers/message/fusion/mptbase.h +++ b/drivers/message/fusion/mptbase.h @@ -6,7 +6,7 @@ * running LSI Logic Fusion MPT (Message Passing Technology) firmware. * * Copyright (c) 1999-2007 LSI Logic Corporation - * (mailto:mpt_linux_developer@lsil.com) + * (mailto:mpt_linux_developer@lsi.com) * */ /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ @@ -75,8 +75,8 @@ #ifndef COPYRIGHT #define COPYRIGHT "Copyright (c) 1999-2007 " MODULEAUTHOR #endif -#define MPT_LINUX_VERSION_COMMON "3.04.03" -#define MPT_LINUX_PACKAGE_NAME "@(#)mptlinux-3.04.03" +#define MPT_LINUX_VERSION_COMMON "3.04.04" +#define MPT_LINUX_PACKAGE_NAME "@(#)mptlinux-3.04.04" #define WHAT_MAGIC_STRING "@" "(" "#" ")" #define show_mptmod_ver(s,ver) \ @@ -172,6 +172,9 @@ #else #define MPT_SCSI_SG_DEPTH 40 #endif +/* debug print string length used for events and iocstatus */ +# define EVENT_DESCR_STR_SZ 100 + #ifdef __KERNEL__ /* { */ /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ @@ -334,8 +337,8 @@ typedef struct _VirtTarget { struct scsi_target *starget; u8 tflags; u8 ioc_id; - u8 target_id; - u8 bus_id; + u8 id; + u8 channel; u8 minSyncFactor; /* 0xFF is async */ u8 maxOffset; /* 0 if async */ u8 maxWidth; /* 0 if narrow, 1 if wide */ @@ -344,13 +347,12 @@ typedef struct _VirtTarget { u8 type; /* byte 0 of Inquiry data */ u8 deleted; /* target in process of being removed */ u32 num_luns; - u32 luns[8]; /* Max LUNs is 256 */ } VirtTarget; typedef struct _VirtDevice { VirtTarget *vtarget; u8 configured_lun; - u32 lun; + int lun; } VirtDevice; /* @@ -412,7 +414,7 @@ typedef struct _MPT_IOCTL { u8 rsvd; u8 status; /* current command status */ u8 reset; /* 1 if bus reset allowed */ - u8 target; /* target for reset */ + u8 id; /* target for reset */ struct mutex ioctl_mutex; } MPT_IOCTL; @@ -483,10 +485,24 @@ typedef struct _SasCfgData { */ }SasCfgData; +/* + * Inactive volume link list of raid component data + * @inactive_list + */ +struct inactive_raid_component_info { + struct list_head list; + u8 volumeID; /* volume target id */ + u8 volumeBus; /* volume channel */ + IOC_3_PHYS_DISK d; /* phys disk info */ +}; + typedef struct _RaidCfgData { IOCPage2_t *pIocPg2; /* table of Raid Volumes */ IOCPage3_t *pIocPg3; /* table of physical disks */ - int isRaid; /* bit field, 1 if RAID */ + struct semaphore inactive_list_mutex; + struct list_head inactive_list; /* link list for physical + disk that belong in + inactive volumes */ }RaidCfgData; typedef struct _FcCfgData { @@ -528,6 +544,8 @@ typedef struct _MPT_ADAPTER u32 mem_phys; /* == f4020000 (mmap) */ u32 pio_mem_phys; /* Programmed IO (downloadboot) */ int mem_size; /* mmap memory size */ + int number_of_buses; + int devices_per_bus; int alloc_total; u32 last_state; int active; @@ -607,6 +625,8 @@ #endif u8 persist_reply_frame[MPT_DEFAULT_FRAME_SIZE]; /* persist reply */ LANPage0_t lan_cnfg_page0; LANPage1_t lan_cnfg_page1; + + u8 ir_firmware; /* =1 if IR firmware detected */ /* * Description: errata_flag_1064 * If a PCIX read occurs within 1 or 2 cycles after the chip receives @@ -790,12 +810,6 @@ #else #define ddvprintk(x) #endif -#ifdef MPT_DEBUG_NEGO -#define dnegoprintk(x) printk x -#else -#define dnegoprintk(x) -#endif - #if defined(MPT_DEBUG_DV) || defined(MPT_DEBUG_DV_TINY) #define ddvtprintk(x) printk x #else @@ -957,7 +971,6 @@ typedef struct _MPT_SCSI_HOST { int port; u32 pad0; struct scsi_cmnd **ScsiLookup; - VirtTarget **Targets; MPT_LOCAL_REPLY *pLocal; /* used for internal commands */ struct timer_list timer; /* Pool of memory for holding SCpnts before doing @@ -981,6 +994,7 @@ typedef struct _MPT_SCSI_HOST { int scandv_wait_done; long last_queue_full; u16 tm_iocstatus; + struct list_head target_reset_list; } MPT_SCSI_HOST; /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ @@ -1046,6 +1060,7 @@ extern void mpt_alloc_fw_memory(MPT_ADA extern void mpt_free_fw_memory(MPT_ADAPTER *ioc); extern int mpt_findImVolumes(MPT_ADAPTER *ioc); extern int mptbase_sas_persist_operation(MPT_ADAPTER *ioc, u8 persist_opcode); +extern int mpt_raid_phys_disk_pg0(MPT_ADAPTER *ioc, u8 phys_disk_num, pRaidPhysDiskPage0_t phys_disk); /* * Public data decl's... diff --git a/drivers/message/fusion/mptctl.c b/drivers/message/fusion/mptctl.c index 504632d..9d0f304 100644 --- a/drivers/message/fusion/mptctl.c +++ b/drivers/message/fusion/mptctl.c @@ -5,7 +5,7 @@ * running LSI Logic Fusion MPT (Message Passing Technology) firmware. * * Copyright (c) 1999-2007 LSI Logic Corporation - * (mailto:mpt_linux_developer@lsil.com) + * (mailto:mpt_linux_developer@lsi.com) * */ /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ @@ -313,7 +313,7 @@ static void mptctl_timeout_expired (MPT_ */ dctlprintk((MYIOC_s_INFO_FMT "Calling HardReset! \n", ioctl->ioc->name)); - mpt_HardResetHandler(ioctl->ioc, NO_SLEEP); + mpt_HardResetHandler(ioctl->ioc, CAN_SLEEP); } return; @@ -361,7 +361,7 @@ static int mptctl_bus_reset(MPT_IOCTL *i ioctl->ioc->name, mf)); pScsiTm = (SCSITaskMgmt_t *) mf; - pScsiTm->TargetID = ioctl->target; + pScsiTm->TargetID = ioctl->id; pScsiTm->Bus = hd->port; /* 0 */ pScsiTm->ChainOffset = 0; pScsiTm->Function = MPI_FUNCTION_SCSI_TASK_MGMT; @@ -1159,15 +1159,12 @@ mptctl_getiocinfo (unsigned long arg, un struct mpt_ioctl_iocinfo *karg; MPT_ADAPTER *ioc; struct pci_dev *pdev; - struct Scsi_Host *sh; - MPT_SCSI_HOST *hd; int iocnum; - int numDevices = 0; - unsigned int max_id; - int ii; unsigned int port; int cim_rev; u8 revision; + struct scsi_device *sdev; + VirtDevice *vdev; dctlprintk((": mptctl_getiocinfo called.\n")); /* Add of PCI INFO results in unaligned access for @@ -1257,23 +1254,16 @@ mptctl_getiocinfo (unsigned long arg, un /* Get number of devices */ - if ((sh = ioc->sh) != NULL) { - /* sh->max_id = maximum target ID + 1 - */ - max_id = sh->max_id - 1; - hd = (MPT_SCSI_HOST *) sh->hostdata; - - /* Check all of the target structures and - * keep a counter. - */ - if (hd && hd->Targets) { - for (ii = 0; ii <= max_id; ii++) { - if (hd->Targets[ii]) - numDevices++; - } + karg->numDevices = 0; + if (ioc->sh) { + shost_for_each_device(sdev, ioc->sh) { + vdev = sdev->hostdata; + if (vdev->vtarget->tflags & + MPT_TARGET_FLAGS_RAID_COMPONENT) + continue; + karg->numDevices++; } } - karg->numDevices = numDevices; /* Set the BIOS and FW Version */ @@ -1319,21 +1309,16 @@ mptctl_gettargetinfo (unsigned long arg) struct mpt_ioctl_targetinfo __user *uarg = (void __user *) arg; struct mpt_ioctl_targetinfo karg; MPT_ADAPTER *ioc; - struct Scsi_Host *sh; - MPT_SCSI_HOST *hd; - VirtTarget *vdev; + VirtDevice *vdev; char *pmem; int *pdata; - IOCPage2_t *pIoc2; - IOCPage3_t *pIoc3; int iocnum; int numDevices = 0; - unsigned int max_id; - int id, jj, indexed_lun, lun_index; - u32 lun; + int lun; int maxWordsLeft; int numBytes; - u8 port, devType, bus_id; + u8 port; + struct scsi_device *sdev; dctlprintk(("mptctl_gettargetinfo called.\n")); if (copy_from_user(&karg, uarg, sizeof(struct mpt_ioctl_targetinfo))) { @@ -1389,74 +1374,22 @@ mptctl_gettargetinfo (unsigned long arg) /* Get number of devices */ - if ((sh = ioc->sh) != NULL) { - - max_id = sh->max_id - 1; - hd = (MPT_SCSI_HOST *) sh->hostdata; - - /* Check all of the target structures. - * Save the Id and increment the counter, - * if ptr non-null. - * sh->max_id = maximum target ID + 1 - */ - if (hd && hd->Targets) { - mpt_findImVolumes(ioc); - pIoc2 = ioc->raid_data.pIocPg2; - for ( id = 0; id <= max_id; ) { - if ( pIoc2 && pIoc2->NumActiveVolumes ) { - if ( id == pIoc2->RaidVolume[0].VolumeID ) { - if (maxWordsLeft <= 0) { - printk(KERN_ERR "mptctl_gettargetinfo - " - "buffer is full but volume is available on ioc %d\n, numDevices=%d", iocnum, numDevices); - goto data_space_full; - } - if ( ( pIoc2->RaidVolume[0].Flags & MPI_IOCPAGE2_FLAG_VOLUME_INACTIVE ) == 0 ) - devType = 0x80; - else - devType = 0xC0; - bus_id = pIoc2->RaidVolume[0].VolumeBus; - numDevices++; - *pdata = ( (devType << 24) | (bus_id << 8) | id ); - dctlprintk((KERN_ERR "mptctl_gettargetinfo - " - "volume ioc=%d target=%x numDevices=%d pdata=%p\n", iocnum, *pdata, numDevices, pdata)); - pdata++; - --maxWordsLeft; - goto next_id; - } else { - pIoc3 = ioc->raid_data.pIocPg3; - for ( jj = 0; jj < pIoc3->NumPhysDisks; jj++ ) { - if ( pIoc3->PhysDisk[jj].PhysDiskID == id ) - goto next_id; - } - } - } - if ( (vdev = hd->Targets[id]) ) { - for (jj = 0; jj <= MPT_LAST_LUN; jj++) { - lun_index = (jj >> 5); - indexed_lun = (jj % 32); - lun = (1 << indexed_lun); - if (vdev->luns[lun_index] & lun) { - if (maxWordsLeft <= 0) { - printk(KERN_ERR "mptctl_gettargetinfo - " - "buffer is full but more targets are available on ioc %d numDevices=%d\n", iocnum, numDevices); - goto data_space_full; - } - bus_id = vdev->bus_id; - numDevices++; - *pdata = ( (jj << 16) | (bus_id << 8) | id ); - dctlprintk((KERN_ERR "mptctl_gettargetinfo - " - "target ioc=%d target=%x numDevices=%d pdata=%p\n", iocnum, *pdata, numDevices, pdata)); - pdata++; - --maxWordsLeft; - } - } - } -next_id: - id++; - } + if (ioc->sh){ + shost_for_each_device(sdev, ioc->sh) { + if (!maxWordsLeft) + continue; + vdev = sdev->hostdata; + if (vdev->vtarget->tflags & + MPT_TARGET_FLAGS_RAID_COMPONENT) + continue; + lun = (vdev->vtarget->raidVolume) ? 0x80 : vdev->lun; + *pdata = (((u8)lun << 16) + (vdev->vtarget->channel << 8) + + (vdev->vtarget->id )); + pdata++; + numDevices++; + --maxWordsLeft; } } -data_space_full: karg.numDevices = numDevices; /* Copy part of the data from kernel memory to user memory @@ -1821,6 +1754,7 @@ mptctl_do_mpt_command (struct mpt_ioctl_ int msgContext; u16 req_idx; ulong timeout; + struct scsi_device *sdev; dctlprintk(("mptctl_do_mpt_command called.\n")); bufIn.kptr = bufOut.kptr = NULL; @@ -1902,14 +1836,13 @@ mptctl_do_mpt_command (struct mpt_ioctl_ case MPI_FUNCTION_SCSI_IO_REQUEST: if (ioc->sh) { SCSIIORequest_t *pScsiReq = (SCSIIORequest_t *) mf; - VirtTarget *pTarget = NULL; - MPT_SCSI_HOST *hd = NULL; int qtag = MPI_SCSIIO_CONTROL_UNTAGGED; int scsidir = 0; - int target = (int) pScsiReq->TargetID; int dataSize; + u32 id; - if ((target < 0) || (target >= ioc->sh->max_id)) { + id = (ioc->devices_per_bus == 0) ? 256 : ioc->devices_per_bus; + if (pScsiReq->TargetID > id) { printk(KERN_ERR "%s@%d::mptctl_do_mpt_command - " "Target ID out of bounds. \n", __FILE__, __LINE__); @@ -1917,6 +1850,14 @@ mptctl_do_mpt_command (struct mpt_ioctl_ goto done_free_mem; } + if (pScsiReq->Bus >= ioc->number_of_buses) { + printk(KERN_ERR "%s@%d::mptctl_do_mpt_command - " + "Target Bus out of bounds. \n", + __FILE__, __LINE__); + rc = -ENODEV; + goto done_free_mem; + } + pScsiReq->MsgFlags &= ~MPI_SCSIIO_MSGFLGS_SENSE_WIDTH; pScsiReq->MsgFlags |= mpt_msg_flags(); @@ -1936,13 +1877,15 @@ mptctl_do_mpt_command (struct mpt_ioctl_ cpu_to_le32(ioc->sense_buf_low_dma + (req_idx * MPT_SENSE_BUFFER_ALLOC)); - if ((hd = (MPT_SCSI_HOST *) ioc->sh->hostdata)) { - if (hd->Targets) - pTarget = hd->Targets[target]; - } + shost_for_each_device(sdev, ioc->sh) { + struct scsi_target *starget = scsi_target(sdev); + VirtTarget *vtarget = starget->hostdata; - if (pTarget &&(pTarget->tflags & MPT_TARGET_FLAGS_Q_YES)) - qtag = MPI_SCSIIO_CONTROL_SIMPLEQ; + if ((pScsiReq->TargetID == vtarget->id) && + (pScsiReq->Bus == vtarget->channel) && + (vtarget->tflags & MPT_TARGET_FLAGS_Q_YES)) + qtag = MPI_SCSIIO_CONTROL_SIMPLEQ; + } /* Have the IOCTL driver set the direction based * on the dataOutSize (ordering issue with Sparc). @@ -1959,7 +1902,7 @@ mptctl_do_mpt_command (struct mpt_ioctl_ pScsiReq->DataLength = cpu_to_le32(dataSize); ioc->ioctl->reset = MPTCTL_RESET_OK; - ioc->ioctl->target = target; + ioc->ioctl->id = pScsiReq->TargetID; } else { printk(KERN_ERR "%s@%d::mptctl_do_mpt_command - " @@ -2038,7 +1981,7 @@ mptctl_do_mpt_command (struct mpt_ioctl_ pScsiReq->DataLength = cpu_to_le32(dataSize); ioc->ioctl->reset = MPTCTL_RESET_OK; - ioc->ioctl->target = pScsiReq->TargetID; + ioc->ioctl->id = pScsiReq->TargetID; } else { printk(KERN_ERR "%s@%d::mptctl_do_mpt_command - " "SCSI driver is not loaded. \n", @@ -2719,7 +2662,7 @@ mptctl_hp_targetinfo(unsigned long arg) /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ -static struct file_operations mptctl_fops = { +static const struct file_operations mptctl_fops = { .owner = THIS_MODULE, .llseek = no_llseek, .release = mptctl_release, diff --git a/drivers/message/fusion/mptctl.h b/drivers/message/fusion/mptctl.h index e65a1cf..f7e72c5 100644 --- a/drivers/message/fusion/mptctl.h +++ b/drivers/message/fusion/mptctl.h @@ -6,7 +6,7 @@ * running LSI Logic Fusion MPT (Message Passing Technology) firmware. * * Copyright (c) 1999-2007 LSI Logic Corporation - * (mailto:mpt_linux_developer@lsil.com) + * (mailto:mpt_linux_developer@lsi.com) * */ /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ diff --git a/drivers/message/fusion/mptfc.c b/drivers/message/fusion/mptfc.c index c819c23..0caaf64 100644 --- a/drivers/message/fusion/mptfc.c +++ b/drivers/message/fusion/mptfc.c @@ -4,7 +4,7 @@ * running LSI Logic Fusion MPT (Message Passing Technology) firmware. * * Copyright (c) 1999-2007 LSI Logic Corporation - * (mailto:mpt_linux_developer@lsil.com) + * (mailto:mpt_linux_developer@lsi.com) * */ /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ @@ -53,7 +53,6 @@ #include #include /* for mdelay */ #include /* needed for in_interrupt() proto */ #include /* notifier code */ -#include #include #include @@ -86,6 +85,12 @@ MODULE_PARM_DESC(mptfc_dev_loss_tmo, " I " return following a device loss event." " Default=60."); +/* scsi-mid layer global parmeter is max_report_luns, which is 511 */ +#define MPTFC_MAX_LUN (16895) +static int max_lun = MPTFC_MAX_LUN; +module_param(max_lun, int, 0); +MODULE_PARM_DESC(max_lun, " max lun, default=16895 "); + static int mptfcDoneCtx = -1; static int mptfcTaskCtx = -1; static int mptfcInternalCtx = -1; /* Used only for internal commands */ @@ -292,10 +297,9 @@ mptfc_GetFcDevPage0(MPT_ADAPTER *ioc, in U32 port_id = 0xffffff; int num_targ = 0; int max_bus = ioc->facts.MaxBuses; - int max_targ = ioc->facts.MaxDevices; + int max_targ; - if (max_bus == 0 || max_targ == 0) - goto out; + max_targ = (ioc->facts.MaxDevices == 0) ? 256 : ioc->facts.MaxDevices; data_sz = sizeof(FCDevicePage0_t) * max_bus * max_targ; p_p0 = p0_array = kzalloc(data_sz, GFP_KERNEL); @@ -467,8 +471,8 @@ mptfc_register_dev(MPT_ADAPTER *ioc, int if (ri->starget) { vtarget = ri->starget->hostdata; if (vtarget) { - vtarget->target_id = pg0->CurrentTargetID; - vtarget->bus_id = pg0->CurrentBus; + vtarget->id = pg0->CurrentTargetID; + vtarget->channel = pg0->CurrentBus; } } *((struct mptfc_rport_info **)rport->dd_data) = ri; @@ -540,8 +544,8 @@ mptfc_target_alloc(struct scsi_target *s if (rport) { ri = *((struct mptfc_rport_info **)rport->dd_data); if (ri) { /* better be! */ - vtarget->target_id = ri->pg0.CurrentTargetID; - vtarget->bus_id = ri->pg0.CurrentBus; + vtarget->id = ri->pg0.CurrentTargetID; + vtarget->channel = ri->pg0.CurrentBus; ri->starget = starget; rc = 0; } @@ -592,7 +596,6 @@ mptfc_slave_alloc(struct scsi_device *sd if (vtarget->num_luns == 0) { vtarget->ioc_id = hd->ioc->id; vtarget->tflags = MPT_TARGET_FLAGS_Q_YES; - hd->Targets[sdev->id] = vtarget; } vdev->vtarget = vtarget; @@ -630,16 +633,17 @@ mptfc_qcmd(struct scsi_cmnd *SCpnt, void struct mptfc_rport_info *ri; struct fc_rport *rport = starget_to_rport(scsi_target(SCpnt->device)); int err; + VirtDevice *vdev = SCpnt->device->hostdata; - err = fc_remote_port_chkready(rport); - if (unlikely(err)) { - SCpnt->result = err; + if (!vdev || !vdev->vtarget) { + SCpnt->result = DID_NO_CONNECT << 16; done(SCpnt); return 0; } - if (!SCpnt->device->hostdata) { /* vdev */ - SCpnt->result = DID_NO_CONNECT << 16; + err = fc_remote_port_chkready(rport); + if (unlikely(err)) { + SCpnt->result = err; done(SCpnt); return 0; } @@ -1143,7 +1147,7 @@ mptfc_probe(struct pci_dev *pdev, const printk(MYIOC_s_WARN_FMT "Skipping ioc=%p because SCSI Initiator mode is NOT enabled!\n", ioc->name, ioc); - return -ENODEV; + return 0; } sh = scsi_host_alloc(&mptfc_driver_template, sizeof(MPT_SCSI_HOST)); @@ -1173,10 +1177,9 @@ mptfc_probe(struct pci_dev *pdev, const /* set 16 byte cdb's */ sh->max_cmd_len = 16; - sh->max_id = MPT_MAX_FC_DEVICES<256 ? MPT_MAX_FC_DEVICES : 255; + sh->max_id = ioc->pfacts->MaxDevices; + sh->max_lun = max_lun; - sh->max_lun = MPT_LAST_LUN + 1; - sh->max_channel = 0; sh->this_id = ioc->pfacts[0].PortSCSIID; /* Required entry. @@ -1230,19 +1233,6 @@ mptfc_probe(struct pci_dev *pdev, const dprintk((MYIOC_s_INFO_FMT "ScsiLookup @ %p\n", ioc->name, hd->ScsiLookup)); - /* Allocate memory for the device structures. - * A non-Null pointer at an offset - * indicates a device exists. - * max_id = 1 + maximum id (hosts.h) - */ - hd->Targets = kcalloc(sh->max_id, sizeof(void *), GFP_ATOMIC); - if (!hd->Targets) { - error = -ENOMEM; - goto out_mptfc_probe; - } - - dprintk((KERN_INFO " vdev @ %p\n", hd->Targets)); - /* Clear the TM flags */ hd->tmPending = 0; diff --git a/drivers/message/fusion/mptlan.c b/drivers/message/fusion/mptlan.c index 2936204..b691292 100644 --- a/drivers/message/fusion/mptlan.c +++ b/drivers/message/fusion/mptlan.c @@ -5,6 +5,7 @@ * running LSI Logic Fusion MPT (Message Passing Technology) firmware. * * Copyright (c) 2000-2007 LSI Logic Corporation + * (mailto:mpt_linux_developer@lsi.com) * */ /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ diff --git a/drivers/message/fusion/mptlan.h b/drivers/message/fusion/mptlan.h index 70ab75e..fe438bf 100644 --- a/drivers/message/fusion/mptlan.h +++ b/drivers/message/fusion/mptlan.h @@ -5,6 +5,7 @@ * running LSI Logic Fusion MPT (Message Passing Technology) firmware. * * Copyright (c) 2000-2007 LSI Logic Corporation + * (mailto:mpt_linux_developer@lsi.com) * */ /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ diff --git a/drivers/message/fusion/mptsas.c b/drivers/message/fusion/mptsas.c index 09e9a9d..404c014 100644 --- a/drivers/message/fusion/mptsas.c +++ b/drivers/message/fusion/mptsas.c @@ -4,7 +4,7 @@ * running LSI Logic Fusion MPT (Message Passing Technology) firmware. * * Copyright (c) 1999-2007 LSI Logic Corporation - * (mailto:mpt_linux_developer@lsil.com) + * (mailto:mpt_linux_developer@lsi.com) * Copyright (c) 2005-2007 Dell */ /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ @@ -48,7 +48,7 @@ #include #include #include #include -#include +#include #include #include /* for mdelay */ @@ -83,17 +83,31 @@ MODULE_PARM_DESC(mpt_pt_clear, " Clear persistency table: enable=1 " "(default=MPTSCSIH_PT_CLEAR=0)"); +/* scsi-mid layer global parmeter is max_report_luns, which is 511 */ +#define MPTSAS_MAX_LUN (16895) +static int max_lun = MPTSAS_MAX_LUN; +module_param(max_lun, int, 0); +MODULE_PARM_DESC(max_lun, " max lun, default=16895 "); + static int mptsasDoneCtx = -1; static int mptsasTaskCtx = -1; static int mptsasInternalCtx = -1; /* Used only for internal commands */ static int mptsasMgmtCtx = -1; +static void mptsas_hotplug_work(struct work_struct *work); + +struct mptsas_target_reset_event { + struct list_head list; + EVENT_DATA_SAS_DEVICE_STATUS_CHANGE sas_event_data; + u8 target_reset_issued; +}; enum mptsas_hotplug_action { MPTSAS_ADD_DEVICE, MPTSAS_DEL_DEVICE, MPTSAS_ADD_RAID, MPTSAS_DEL_RAID, + MPTSAS_ADD_INACTIVE_VOLUME, MPTSAS_IGNORE_EVENT, }; @@ -102,14 +116,15 @@ struct mptsas_hotplug_event { MPT_ADAPTER *ioc; enum mptsas_hotplug_action event_type; u64 sas_address; - u32 channel; - u32 id; + u8 channel; + u8 id; u32 device_info; u16 handle; u16 parent_handle; u8 phy_id; - u8 phys_disk_num; - u8 phys_disk_num_valid; + u8 phys_disk_num_valid; /* hrc (hidden raid component) */ + u8 phys_disk_num; /* hrc - unique index*/ + u8 hidden_raid_component; /* hrc - don't expose*/ }; struct mptsas_discovery_event { @@ -134,6 +149,7 @@ struct mptsas_devinfo { u8 port_id; /* sas physical port this device is assoc'd with */ u8 id; /* logical target id of this device */ + u32 phys_disk_num; /* phys disk id, for csmi-ioctls */ u8 channel; /* logical bus number of this device */ u64 sas_address; /* WWN of this device, SATA is assigned by HBA,expander */ @@ -153,6 +169,7 @@ struct mptsas_portinfo_details{ }; struct mptsas_phyinfo { + u16 handle; /* unique id to address this */ u8 phy_id; /* phy index */ u8 port_id; /* firmware port identifier */ u8 negotiated_link_rate; /* nego'd link rate for this phy */ @@ -168,7 +185,6 @@ struct mptsas_phyinfo { struct mptsas_portinfo { struct list_head list; - u16 handle; /* unique id to address this */ u16 num_phys; /* number of phys */ struct mptsas_phyinfo *phy_info; }; @@ -561,22 +577,273 @@ #endif mutex_unlock(&ioc->sas_topology_mutex); } +/** + * csmisas_find_vtarget + * + * @ioc + * @volume_id + * @volume_bus + * + **/ +static VirtTarget * +mptsas_find_vtarget(MPT_ADAPTER *ioc, u8 channel, u8 id) +{ + struct scsi_device *sdev; + VirtDevice *vdev; + VirtTarget *vtarget = NULL; + + shost_for_each_device(sdev, ioc->sh) { + if ((vdev = sdev->hostdata) == NULL) + continue; + if (vdev->vtarget->id == id && + vdev->vtarget->channel == channel) + vtarget = vdev->vtarget; + } + return vtarget; +} + +/** + * mptsas_target_reset + * + * Issues TARGET_RESET to end device using handshaking method + * + * @ioc + * @channel + * @id + * + * Returns (1) success + * (0) failure + * + **/ +static int +mptsas_target_reset(MPT_ADAPTER *ioc, u8 channel, u8 id) +{ + MPT_FRAME_HDR *mf; + SCSITaskMgmt_t *pScsiTm; + + if ((mf = mpt_get_msg_frame(ioc->TaskCtx, ioc)) == NULL) { + dfailprintk((MYIOC_s_WARN_FMT "%s, no msg frames @%d!!\n", + ioc->name,__FUNCTION__, __LINE__)); + return 0; + } + + /* Format the Request + */ + pScsiTm = (SCSITaskMgmt_t *) mf; + memset (pScsiTm, 0, sizeof(SCSITaskMgmt_t)); + pScsiTm->TargetID = id; + pScsiTm->Bus = channel; + pScsiTm->Function = MPI_FUNCTION_SCSI_TASK_MGMT; + pScsiTm->TaskType = MPI_SCSITASKMGMT_TASKTYPE_TARGET_RESET; + pScsiTm->MsgFlags = MPI_SCSITASKMGMT_MSGFLAGS_LIPRESET_RESET_OPTION; + + DBG_DUMP_TM_REQUEST_FRAME(mf); + + if (mpt_send_handshake_request(ioc->TaskCtx, ioc, + sizeof(SCSITaskMgmt_t), (u32 *)mf, NO_SLEEP)) { + mpt_free_msg_frame(ioc, mf); + dfailprintk((MYIOC_s_WARN_FMT "%s, tm handshake failed @%d!!\n", + ioc->name,__FUNCTION__, __LINE__)); + return 0; + } + + return 1; +} + +/** + * mptsas_target_reset_queue + * + * Receive request for TARGET_RESET after recieving an firmware + * event NOT_RESPONDING_EVENT, then put command in link list + * and queue if task_queue already in use. + * + * @ioc + * @sas_event_data + * + **/ static void -mptsas_target_reset(MPT_ADAPTER *ioc, VirtTarget * vtarget) +mptsas_target_reset_queue(MPT_ADAPTER *ioc, + EVENT_DATA_SAS_DEVICE_STATUS_CHANGE *sas_event_data) { - MPT_SCSI_HOST *hd = (MPT_SCSI_HOST *)ioc->sh->hostdata; + MPT_SCSI_HOST *hd = (MPT_SCSI_HOST *)ioc->sh->hostdata; + VirtTarget *vtarget = NULL; + struct mptsas_target_reset_event *target_reset_list; + u8 id, channel; - if (mptscsih_TMHandler(hd, - MPI_SCSITASKMGMT_TASKTYPE_TARGET_RESET, - vtarget->bus_id, vtarget->target_id, 0, 0, 5) < 0) { - hd->tmPending = 0; - hd->tmState = TM_STATE_NONE; - printk(MYIOC_s_WARN_FMT - "Error processing TaskMgmt id=%d TARGET_RESET\n", - ioc->name, vtarget->target_id); + id = sas_event_data->TargetID; + channel = sas_event_data->Bus; + + if (!(vtarget = mptsas_find_vtarget(ioc, channel, id))) + return; + + vtarget->deleted = 1; /* block IO */ + + target_reset_list = kzalloc(sizeof(*target_reset_list), + GFP_ATOMIC); + if (!target_reset_list) { + dfailprintk((MYIOC_s_WARN_FMT "%s, failed to allocate mem @%d..!!\n", + ioc->name,__FUNCTION__, __LINE__)); + return; + } + + memcpy(&target_reset_list->sas_event_data, sas_event_data, + sizeof(*sas_event_data)); + list_add_tail(&target_reset_list->list, &hd->target_reset_list); + + if (hd->resetPending) + return; + + if (mptsas_target_reset(ioc, channel, id)) { + target_reset_list->target_reset_issued = 1; + hd->resetPending = 1; } } +/** + * mptsas_dev_reset_complete + * + * Completion for TARGET_RESET after NOT_RESPONDING_EVENT, + * enable work queue to finish off removing device from upper layers. + * then send next TARGET_RESET in the queue. + * + * @ioc + * + **/ +static void +mptsas_dev_reset_complete(MPT_ADAPTER *ioc) +{ + MPT_SCSI_HOST *hd = (MPT_SCSI_HOST *)ioc->sh->hostdata; + struct list_head *head = &hd->target_reset_list; + struct mptsas_target_reset_event *target_reset_list; + struct mptsas_hotplug_event *ev; + EVENT_DATA_SAS_DEVICE_STATUS_CHANGE *sas_event_data; + u8 id, channel; + __le64 sas_address; + + if (list_empty(head)) + return; + + target_reset_list = list_entry(head->next, struct mptsas_target_reset_event, list); + + sas_event_data = &target_reset_list->sas_event_data; + id = sas_event_data->TargetID; + channel = sas_event_data->Bus; + hd->resetPending = 0; + + /* + * retry target reset + */ + if (!target_reset_list->target_reset_issued) { + if (mptsas_target_reset(ioc, channel, id)) { + target_reset_list->target_reset_issued = 1; + hd->resetPending = 1; + } + return; + } + + /* + * enable work queue to remove device from upper layers + */ + list_del(&target_reset_list->list); + + ev = kzalloc(sizeof(*ev), GFP_ATOMIC); + if (!ev) { + dfailprintk((MYIOC_s_WARN_FMT "%s, failed to allocate mem @%d..!!\n", + ioc->name,__FUNCTION__, __LINE__)); + return; + } + + INIT_WORK(&ev->work, mptsas_hotplug_work); + ev->ioc = ioc; + ev->handle = le16_to_cpu(sas_event_data->DevHandle); + ev->parent_handle = + le16_to_cpu(sas_event_data->ParentDevHandle); + ev->channel = channel; + ev->id =id; + ev->phy_id = sas_event_data->PhyNum; + memcpy(&sas_address, &sas_event_data->SASAddress, + sizeof(__le64)); + ev->sas_address = le64_to_cpu(sas_address); + ev->device_info = le32_to_cpu(sas_event_data->DeviceInfo); + ev->event_type = MPTSAS_DEL_DEVICE; + schedule_work(&ev->work); + kfree(target_reset_list); + + /* + * issue target reset to next device in the queue + */ + + head = &hd->target_reset_list; + if (list_empty(head)) + return; + + target_reset_list = list_entry(head->next, struct mptsas_target_reset_event, + list); + + sas_event_data = &target_reset_list->sas_event_data; + id = sas_event_data->TargetID; + channel = sas_event_data->Bus; + + if (mptsas_target_reset(ioc, channel, id)) { + target_reset_list->target_reset_issued = 1; + hd->resetPending = 1; + } +} + +/** + * mptsas_taskmgmt_complete + * + * @ioc + * @mf + * @mr + * + **/ +static int +mptsas_taskmgmt_complete(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *mr) +{ + mptsas_dev_reset_complete(ioc); + return mptscsih_taskmgmt_complete(ioc, mf, mr); +} + +/** + * mptscsih_ioc_reset + * + * @ioc + * @reset_phase + * + **/ +static int +mptsas_ioc_reset(MPT_ADAPTER *ioc, int reset_phase) +{ + MPT_SCSI_HOST *hd = (MPT_SCSI_HOST *)ioc->sh->hostdata; + struct mptsas_target_reset_event *target_reset_list, *n; + int rc; + + rc = mptscsih_ioc_reset(ioc, reset_phase); + + if (ioc->bus_type != SAS) + goto out; + + if (reset_phase != MPT_IOC_POST_RESET) + goto out; + + if (!hd || !hd->ioc) + goto out; + + if (list_empty(&hd->target_reset_list)) + goto out; + + /* flush the target_reset_list */ + list_for_each_entry_safe(target_reset_list, n, + &hd->target_reset_list, list) { + list_del(&target_reset_list->list); + kfree(target_reset_list); + } + + out: + return rc; +} + static int mptsas_sas_enclosure_pg0(MPT_ADAPTER *ioc, struct mptsas_enclosure *enclosure, u32 form, u32 form_specific) @@ -661,8 +928,7 @@ mptsas_target_alloc(struct scsi_target * struct Scsi_Host *host = dev_to_shost(&starget->dev); MPT_SCSI_HOST *hd = (MPT_SCSI_HOST *)host->hostdata; VirtTarget *vtarget; - u32 target_id; - u32 channel; + u8 id, channel; struct sas_rphy *rphy; struct mptsas_portinfo *p; int i; @@ -673,15 +939,19 @@ mptsas_target_alloc(struct scsi_target * vtarget->starget = starget; vtarget->ioc_id = hd->ioc->id; - vtarget->tflags = MPT_TARGET_FLAGS_Q_YES|MPT_TARGET_FLAGS_VALID_INQUIRY; - - target_id = starget->id; + vtarget->tflags = MPT_TARGET_FLAGS_Q_YES; + id = starget->id; channel = 0; - hd->Targets[target_id] = vtarget; - - if (starget->channel == MPTSAS_RAID_CHANNEL) + /* + * RAID volumes placed beyond the last expected port. + */ + if (starget->channel == MPTSAS_RAID_CHANNEL) { + for (i=0; i < hd->ioc->raid_data.pIocPg2->NumActiveVolumes; i++) + if (id == hd->ioc->raid_data.pIocPg2->RaidVolume[i].VolumeID) + channel = hd->ioc->raid_data.pIocPg2->RaidVolume[i].VolumeBus; goto out; + } rphy = dev_to_rphy(starget->dev.parent); mutex_lock(&hd->ioc->sas_topology_mutex); @@ -690,18 +960,19 @@ mptsas_target_alloc(struct scsi_target * if (p->phy_info[i].attached.sas_address != rphy->identify.sas_address) continue; - target_id = p->phy_info[i].attached.id; + id = p->phy_info[i].attached.id; channel = p->phy_info[i].attached.channel; mptsas_set_starget(&p->phy_info[i], starget); /* * Exposing hidden raid components */ - if (mptscsih_is_phys_disk(hd->ioc, target_id)) { - target_id = mptscsih_raid_id_to_num(hd, - target_id); + if (mptscsih_is_phys_disk(hd->ioc, channel, id)) { + id = mptscsih_raid_id_to_num(hd->ioc, + channel, id); vtarget->tflags |= MPT_TARGET_FLAGS_RAID_COMPONENT; + p->phy_info[i].attached.phys_disk_num = id; } mutex_unlock(&hd->ioc->sas_topology_mutex); goto out; @@ -713,8 +984,8 @@ mptsas_target_alloc(struct scsi_target * return -ENXIO; out: - vtarget->target_id = target_id; - vtarget->bus_id = channel; + vtarget->id = id; + vtarget->channel = channel; starget->hostdata = vtarget; return 0; } @@ -786,7 +1057,8 @@ mptsas_slave_alloc(struct scsi_device *s * Exposing hidden raid components */ if (mptscsih_is_phys_disk(hd->ioc, - p->phy_info[i].attached.id)) + p->phy_info[i].attached.channel, + p->phy_info[i].attached.id)) sdev->no_uld_attach = 1; mutex_unlock(&hd->ioc->sas_topology_mutex); goto out; @@ -808,13 +1080,14 @@ mptsas_qcmd(struct scsi_cmnd *SCpnt, voi { VirtDevice *vdev = SCpnt->device->hostdata; -// scsi_print_command(SCpnt); - if (vdev->vtarget->deleted) { + if (!vdev || !vdev->vtarget || vdev->vtarget->deleted) { SCpnt->result = DID_NO_CONNECT << 16; done(SCpnt); return 0; } +// scsi_print_command(SCpnt); + return mptscsih_qcmd(SCpnt,done); } @@ -1114,9 +1387,6 @@ mptsas_sas_io_unit_pg0(MPT_ADAPTER *ioc, goto out_free_consistent; } - if (port_info->num_phys) - port_info->handle = - le16_to_cpu(buffer->PhyData[0].ControllerDevHandle); for (i = 0; i < port_info->num_phys; i++) { mptsas_print_phy_data(&buffer->PhyData[i]); port_info->phy_info[i].phy_id = i; @@ -1125,6 +1395,8 @@ mptsas_sas_io_unit_pg0(MPT_ADAPTER *ioc, port_info->phy_info[i].negotiated_link_rate = buffer->PhyData[i].NegotiatedLinkRate; port_info->phy_info[i].portinfo = port_info; + port_info->phy_info[i].handle = + le16_to_cpu(buffer->PhyData[i].ControllerDevHandle); } out_free_consistent: @@ -1261,6 +1533,7 @@ mptsas_sas_device_pg0(MPT_ADAPTER *ioc, device_info->phy_id = buffer->PhyNum; device_info->port_id = buffer->PhysicalPort; device_info->id = buffer->TargetID; + device_info->phys_disk_num = ~0; device_info->channel = buffer->Bus; memcpy(&sas_address, &buffer->SASAddress, sizeof(__le64)); device_info->sas_address = le64_to_cpu(sas_address); @@ -1325,7 +1598,6 @@ mptsas_sas_expander_pg0(MPT_ADAPTER *ioc /* save config data */ port_info->num_phys = buffer->NumPhys; - port_info->handle = le16_to_cpu(buffer->DevHandle); port_info->phy_info = kcalloc(port_info->num_phys, sizeof(*port_info->phy_info),GFP_KERNEL); if (!port_info->phy_info) { @@ -1333,8 +1605,11 @@ mptsas_sas_expander_pg0(MPT_ADAPTER *ioc goto out_free_consistent; } - for (i = 0; i < port_info->num_phys; i++) + for (i = 0; i < port_info->num_phys; i++) { port_info->phy_info[i].portinfo = port_info; + port_info->phy_info[i].handle = + le16_to_cpu(buffer->DevHandle); + } out_free_consistent: pci_free_consistent(ioc->pcidev, hdr.ExtPageLength * 4, @@ -1702,7 +1977,6 @@ static int mptsas_probe_hba_phys(MPT_ADAPTER *ioc) { struct mptsas_portinfo *port_info, *hba; - u32 handle = 0xFFFF; int error = -ENOMEM, i; hba = kzalloc(sizeof(*port_info), GFP_KERNEL); @@ -1714,34 +1988,36 @@ mptsas_probe_hba_phys(MPT_ADAPTER *ioc) goto out_free_port_info; mutex_lock(&ioc->sas_topology_mutex); - ioc->handle = hba->handle; - port_info = mptsas_find_portinfo_by_handle(ioc, hba->handle); + ioc->handle = hba->phy_info[0].handle; + port_info = mptsas_find_portinfo_by_handle(ioc, ioc->handle); if (!port_info) { port_info = hba; list_add_tail(&port_info->list, &ioc->sas_topology); } else { - port_info->handle = hba->handle; - for (i = 0; i < hba->num_phys; i++) + for (i = 0; i < hba->num_phys; i++) { port_info->phy_info[i].negotiated_link_rate = hba->phy_info[i].negotiated_link_rate; + port_info->phy_info[i].handle = + hba->phy_info[i].handle; + port_info->phy_info[i].port_id = + hba->phy_info[i].port_id; + } kfree(hba->phy_info); kfree(hba); hba = NULL; } mutex_unlock(&ioc->sas_topology_mutex); - for (i = 0; i < port_info->num_phys; i++) { mptsas_sas_phy_pg0(ioc, &port_info->phy_info[i], (MPI_SAS_PHY_PGAD_FORM_PHY_NUMBER << MPI_SAS_PHY_PGAD_FORM_SHIFT), i); mptsas_sas_device_pg0(ioc, &port_info->phy_info[i].identify, - (MPI_SAS_DEVICE_PGAD_FORM_GET_NEXT_HANDLE << - MPI_SAS_DEVICE_PGAD_FORM_SHIFT), handle); + (MPI_SAS_DEVICE_PGAD_FORM_HANDLE << + MPI_SAS_DEVICE_PGAD_FORM_SHIFT), + port_info->phy_info[i].handle); port_info->phy_info[i].identify.phy_id = - port_info->phy_info[i].phy_id; - handle = port_info->phy_info[i].identify.handle; - + port_info->phy_info[i].phy_id = i; if (port_info->phy_info[i].attached.handle) mptsas_sas_device_pg0(ioc, &port_info->phy_info[i].attached, @@ -1777,12 +2053,12 @@ mptsas_probe_expander_phys(MPT_ADAPTER * goto out; error = mptsas_sas_expander_pg0(ioc, ex, - (MPI_SAS_EXPAND_PGAD_FORM_GET_NEXT_HANDLE << - MPI_SAS_EXPAND_PGAD_FORM_SHIFT), *handle); + (MPI_SAS_EXPAND_PGAD_FORM_GET_NEXT_HANDLE << + MPI_SAS_EXPAND_PGAD_FORM_SHIFT), *handle); if (error) goto out_free_port_info; - *handle = ex->handle; + *handle = ex->phy_info[0].handle; mutex_lock(&ioc->sas_topology_mutex); port_info = mptsas_find_portinfo_by_handle(ioc, *handle); @@ -1790,7 +2066,12 @@ mptsas_probe_expander_phys(MPT_ADAPTER * port_info = ex; list_add_tail(&port_info->list, &ioc->sas_topology); } else { - port_info->handle = ex->handle; + for (i = 0; i < ex->num_phys; i++) { + port_info->phy_info[i].handle = + ex->phy_info[i].handle; + port_info->phy_info[i].port_id = + ex->phy_info[i].port_id; + } kfree(ex->phy_info); kfree(ex); ex = NULL; @@ -1868,8 +2149,6 @@ mptsas_delete_expander_phys(MPT_ADAPTER struct mptsas_portinfo buffer; struct mptsas_portinfo *port_info, *n, *parent; struct mptsas_phyinfo *phy_info; - struct scsi_target * starget; - VirtTarget * vtarget; struct sas_port * port; int i; u64 expander_sas_address; @@ -1884,26 +2163,8 @@ mptsas_delete_expander_phys(MPT_ADAPTER if (mptsas_sas_expander_pg0(ioc, &buffer, (MPI_SAS_EXPAND_PGAD_FORM_HANDLE << - MPI_SAS_EXPAND_PGAD_FORM_SHIFT), port_info->handle)) { - - /* - * Issue target reset to all child end devices - * then mark them deleted to prevent further - * IO going to them. - */ - phy_info = port_info->phy_info; - for (i = 0; i < port_info->num_phys; i++, phy_info++) { - starget = mptsas_get_starget(phy_info); - if (!starget) - continue; - vtarget = starget->hostdata; - if(vtarget->deleted) - continue; - vtarget->deleted = 1; - mptsas_target_reset(ioc, vtarget); - sas_port_delete(mptsas_get_port(phy_info)); - mptsas_port_delete(phy_info->port_details); - } + MPI_SAS_EXPAND_PGAD_FORM_SHIFT), + port_info->phy_info[0].handle)) { /* * Obtain the port_info instance to the parent port @@ -1972,11 +2233,13 @@ mptsas_scan_sas_topology(MPT_ADAPTER *io /* Reporting RAID volumes. */ + if (!ioc->ir_firmware) + goto out; if (!ioc->raid_data.pIocPg2) goto out; if (!ioc->raid_data.pIocPg2->NumActiveVolumes) goto out; - for (i=0; iraid_data.pIocPg2->NumActiveVolumes; i++) { + for (i = 0; i < ioc->raid_data.pIocPg2->NumActiveVolumes; i++) { scsi_add_device(ioc->sh, MPTSAS_RAID_CHANNEL, ioc->raid_data.pIocPg2->RaidVolume[i].VolumeID, 0); } @@ -2030,12 +2293,37 @@ mptsas_find_phyinfo_by_sas_address(MPT_A mutex_lock(&ioc->sas_topology_mutex); list_for_each_entry(port_info, &ioc->sas_topology, list) { for (i = 0; i < port_info->num_phys; i++) { + if (!mptsas_is_end_device( + &port_info->phy_info[i].attached)) + continue; if (port_info->phy_info[i].attached.sas_address != sas_address) continue; + phy_info = &port_info->phy_info[i]; + break; + } + } + mutex_unlock(&ioc->sas_topology_mutex); + return phy_info; +} + +static struct mptsas_phyinfo * +mptsas_find_phyinfo_by_target(MPT_ADAPTER *ioc, u8 channel, u8 id) +{ + struct mptsas_portinfo *port_info; + struct mptsas_phyinfo *phy_info = NULL; + int i; + + mutex_lock(&ioc->sas_topology_mutex); + list_for_each_entry(port_info, &ioc->sas_topology, list) { + for (i = 0; i < port_info->num_phys; i++) { if (!mptsas_is_end_device( &port_info->phy_info[i].attached)) continue; + if (port_info->phy_info[i].attached.id != id) + continue; + if (port_info->phy_info[i].attached.channel != channel) + continue; phy_info = &port_info->phy_info[i]; break; } @@ -2045,7 +2333,7 @@ mptsas_find_phyinfo_by_sas_address(MPT_A } static struct mptsas_phyinfo * -mptsas_find_phyinfo_by_target(MPT_ADAPTER *ioc, u32 id) +mptsas_find_phyinfo_by_phys_disk_num(MPT_ADAPTER *ioc, u8 channel, u8 id) { struct mptsas_portinfo *port_info; struct mptsas_phyinfo *phy_info = NULL; @@ -2054,11 +2342,15 @@ mptsas_find_phyinfo_by_target(MPT_ADAPTE mutex_lock(&ioc->sas_topology_mutex); list_for_each_entry(port_info, &ioc->sas_topology, list) { for (i = 0; i < port_info->num_phys; i++) { - if (port_info->phy_info[i].attached.id != id) - continue; if (!mptsas_is_end_device( &port_info->phy_info[i].attached)) continue; + if (port_info->phy_info[i].attached.phys_disk_num == ~0) + continue; + if (port_info->phy_info[i].attached.phys_disk_num != id) + continue; + if (port_info->phy_info[i].attached.channel != channel) + continue; phy_info = &port_info->phy_info[i]; break; } @@ -2094,6 +2386,76 @@ mptsas_reprobe_target(struct scsi_target mptsas_reprobe_lun); } +static void +mptsas_adding_inactive_raid_components(MPT_ADAPTER *ioc, u8 channel, u8 id) +{ + CONFIGPARMS cfg; + ConfigPageHeader_t hdr; + dma_addr_t dma_handle; + pRaidVolumePage0_t buffer = NULL; + RaidPhysDiskPage0_t phys_disk; + int i; + struct mptsas_hotplug_event *ev; + + memset(&cfg, 0 , sizeof(CONFIGPARMS)); + memset(&hdr, 0 , sizeof(ConfigPageHeader_t)); + hdr.PageType = MPI_CONFIG_PAGETYPE_RAID_VOLUME; + cfg.pageAddr = (channel << 8) + id; + cfg.cfghdr.hdr = &hdr; + cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER; + + if (mpt_config(ioc, &cfg) != 0) + goto out; + + if (!hdr.PageLength) + goto out; + + buffer = pci_alloc_consistent(ioc->pcidev, hdr.PageLength * 4, + &dma_handle); + + if (!buffer) + goto out; + + cfg.physAddr = dma_handle; + cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT; + + if (mpt_config(ioc, &cfg) != 0) + goto out; + + if (!(buffer->VolumeStatus.Flags & + MPI_RAIDVOL0_STATUS_FLAG_VOLUME_INACTIVE)) + goto out; + + if (!buffer->NumPhysDisks) + goto out; + + for (i = 0; i < buffer->NumPhysDisks; i++) { + + if (mpt_raid_phys_disk_pg0(ioc, + buffer->PhysDisk[i].PhysDiskNum, &phys_disk) != 0) + continue; + + ev = kzalloc(sizeof(*ev), GFP_ATOMIC); + if (!ev) { + printk(KERN_WARNING "mptsas: lost hotplug event\n"); + goto out; + } + + INIT_WORK(&ev->work, mptsas_hotplug_work); + ev->ioc = ioc; + ev->id = phys_disk.PhysDiskID; + ev->channel = phys_disk.PhysDiskBus; + ev->phys_disk_num_valid = 1; + ev->phys_disk_num = phys_disk.PhysDiskNum; + ev->event_type = MPTSAS_ADD_DEVICE; + schedule_work(&ev->work); + } + + out: + if (buffer) + pci_free_consistent(ioc->pcidev, hdr.PageLength * 4, buffer, + dma_handle); +} /* * Work queue thread to handle SAS hotplug events */ @@ -2102,6 +2464,7 @@ mptsas_hotplug_work(struct work_struct * { struct mptsas_hotplug_event *ev = container_of(work, struct mptsas_hotplug_event, work); + MPT_ADAPTER *ioc = ev->ioc; struct mptsas_phyinfo *phy_info; struct sas_rphy *rphy; @@ -2114,17 +2477,43 @@ mptsas_hotplug_work(struct work_struct * VirtTarget *vtarget; VirtDevice *vdevice; - mutex_lock(&ioc->sas_discovery_mutex); switch (ev->event_type) { case MPTSAS_DEL_DEVICE: - phy_info = mptsas_find_phyinfo_by_target(ioc, ev->id); + phy_info = NULL; + if (ev->phys_disk_num_valid) { + if (ev->hidden_raid_component){ + if (mptsas_sas_device_pg0(ioc, &sas_device, + (MPI_SAS_DEVICE_PGAD_FORM_BUS_TARGET_ID << + MPI_SAS_DEVICE_PGAD_FORM_SHIFT), + (ev->channel << 8) + ev->id)) { + dfailprintk((MYIOC_s_ERR_FMT + "%s: exit at line=%d\n", ioc->name, + __FUNCTION__, __LINE__)); + break; + } + phy_info = mptsas_find_phyinfo_by_sas_address( + ioc, sas_device.sas_address); + }else + phy_info = mptsas_find_phyinfo_by_phys_disk_num( + ioc, ev->channel, ev->phys_disk_num); + } + + if (!phy_info) + phy_info = mptsas_find_phyinfo_by_target(ioc, + ev->channel, ev->id); /* * Sanity checks, for non-existing phys and remote rphys. */ - if (!phy_info || !phy_info->port_details) { + if (!phy_info){ + dfailprintk((MYIOC_s_ERR_FMT + "%s: exit at line=%d\n", ioc->name, + __FUNCTION__, __LINE__)); + break; + } + if (!phy_info->port_details) { dfailprintk((MYIOC_s_ERR_FMT "%s: exit at line=%d\n", ioc->name, __FUNCTION__, __LINE__)); @@ -2137,6 +2526,7 @@ mptsas_hotplug_work(struct work_struct * __FUNCTION__, __LINE__)); break; } + port = mptsas_get_port(phy_info); if (!port) { dfailprintk((MYIOC_s_ERR_FMT @@ -2159,28 +2549,35 @@ mptsas_hotplug_work(struct work_struct * /* * Handling RAID components */ - if (ev->phys_disk_num_valid) { - vtarget->target_id = ev->phys_disk_num; - vtarget->tflags |= MPT_TARGET_FLAGS_RAID_COMPONENT; + if (ev->phys_disk_num_valid && + ev->hidden_raid_component) { + printk(MYIOC_s_INFO_FMT + "RAID Hidding: channel=%d, id=%d, " + "physdsk %d \n", ioc->name, ev->channel, + ev->id, ev->phys_disk_num); + vtarget->id = ev->phys_disk_num; + vtarget->tflags |= + MPT_TARGET_FLAGS_RAID_COMPONENT; mptsas_reprobe_target(starget, 1); - break; + phy_info->attached.phys_disk_num = + ev->phys_disk_num; + break; } - - vtarget->deleted = 1; - mptsas_target_reset(ioc, vtarget); } - if (phy_info->attached.device_info & MPI_SAS_DEVICE_INFO_SSP_TARGET) + if (phy_info->attached.device_info & + MPI_SAS_DEVICE_INFO_SSP_TARGET) ds = "ssp"; - if (phy_info->attached.device_info & MPI_SAS_DEVICE_INFO_STP_TARGET) + if (phy_info->attached.device_info & + MPI_SAS_DEVICE_INFO_STP_TARGET) ds = "stp"; - if (phy_info->attached.device_info & MPI_SAS_DEVICE_INFO_SATA_DEVICE) + if (phy_info->attached.device_info & + MPI_SAS_DEVICE_INFO_SATA_DEVICE) ds = "sata"; printk(MYIOC_s_INFO_FMT "removing %s device, channel %d, id %d, phy %d\n", ioc->name, ds, ev->channel, ev->id, phy_info->phy_id); - #ifdef MPT_DEBUG_SAS_WIDE dev_printk(KERN_DEBUG, &port->dev, "delete port (%d)\n", port->port_identifier); @@ -2198,14 +2595,14 @@ #endif */ if (mptsas_sas_device_pg0(ioc, &sas_device, (MPI_SAS_DEVICE_PGAD_FORM_BUS_TARGET_ID << - MPI_SAS_DEVICE_PGAD_FORM_SHIFT), ev->id)) { + MPI_SAS_DEVICE_PGAD_FORM_SHIFT), + (ev->channel << 8) + ev->id)) { dfailprintk((MYIOC_s_ERR_FMT "%s: exit at line=%d\n", ioc->name, __FUNCTION__, __LINE__)); break; } - ssleep(2); __mptsas_discovery_work(ioc); phy_info = mptsas_find_phyinfo_by_sas_address(ioc, @@ -2219,7 +2616,8 @@ #endif } starget = mptsas_get_starget(phy_info); - if (starget) { + if (starget && (!ev->hidden_raid_component)){ + vtarget = starget->hostdata; if (!vtarget) { @@ -2232,9 +2630,15 @@ #endif * Handling RAID components */ if (vtarget->tflags & MPT_TARGET_FLAGS_RAID_COMPONENT) { - vtarget->tflags &= ~MPT_TARGET_FLAGS_RAID_COMPONENT; - vtarget->target_id = ev->id; + printk(MYIOC_s_INFO_FMT + "RAID Exposing: channel=%d, id=%d, " + "physdsk %d \n", ioc->name, ev->channel, + ev->id, ev->phys_disk_num); + vtarget->tflags &= + ~MPT_TARGET_FLAGS_RAID_COMPONENT; + vtarget->id = ev->id; mptsas_reprobe_target(starget, 0); + phy_info->attached.phys_disk_num = ~0; } break; } @@ -2243,8 +2647,10 @@ #endif dfailprintk((MYIOC_s_ERR_FMT "%s: exit at line=%d\n", ioc->name, __FUNCTION__, __LINE__)); + if (ev->channel) printk("%d\n", __LINE__); break; } + port = mptsas_get_port(phy_info); if (!port) { dfailprintk((MYIOC_s_ERR_FMT @@ -2252,15 +2658,17 @@ #endif __FUNCTION__, __LINE__)); break; } - memcpy(&phy_info->attached, &sas_device, sizeof(struct mptsas_devinfo)); - if (phy_info->attached.device_info & MPI_SAS_DEVICE_INFO_SSP_TARGET) + if (phy_info->attached.device_info & + MPI_SAS_DEVICE_INFO_SSP_TARGET) ds = "ssp"; - if (phy_info->attached.device_info & MPI_SAS_DEVICE_INFO_STP_TARGET) + if (phy_info->attached.device_info & + MPI_SAS_DEVICE_INFO_STP_TARGET) ds = "stp"; - if (phy_info->attached.device_info & MPI_SAS_DEVICE_INFO_SATA_DEVICE) + if (phy_info->attached.device_info & + MPI_SAS_DEVICE_INFO_SATA_DEVICE) ds = "sata"; printk(MYIOC_s_INFO_FMT @@ -2301,19 +2709,21 @@ #endif break; case MPTSAS_DEL_RAID: sdev = scsi_device_lookup(ioc->sh, MPTSAS_RAID_CHANNEL, - ev->id, 0); + ev->id, 0); if (!sdev) break; printk(MYIOC_s_INFO_FMT "removing raid volume, channel %d, id %d\n", ioc->name, MPTSAS_RAID_CHANNEL, ev->id); vdevice = sdev->hostdata; - vdevice->vtarget->deleted = 1; - mptsas_target_reset(ioc, vdevice->vtarget); scsi_remove_device(sdev); scsi_device_put(sdev); mpt_findImVolumes(ioc); break; + case MPTSAS_ADD_INACTIVE_VOLUME: + mptsas_adding_inactive_raid_components(ioc, + ev->channel, ev->id); + break; case MPTSAS_IGNORE_EVENT: default: break; @@ -2321,7 +2731,6 @@ #endif mutex_unlock(&ioc->sas_discovery_mutex); kfree(ev); - } static void @@ -2339,8 +2748,12 @@ mptsas_send_sas_event(MPT_ADAPTER *ioc, return; switch (sas_event_data->ReasonCode) { - case MPI_EVENT_SAS_DEV_STAT_RC_ADDED: case MPI_EVENT_SAS_DEV_STAT_RC_NOT_RESPONDING: + + mptsas_target_reset_queue(ioc, sas_event_data); + break; + + case MPI_EVENT_SAS_DEV_STAT_RC_ADDED: ev = kzalloc(sizeof(*ev), GFP_ATOMIC); if (!ev) { printk(KERN_WARNING "mptsas: lost hotplug event\n"); @@ -2375,15 +2788,20 @@ mptsas_send_sas_event(MPT_ADAPTER *ioc, mptsas_persist_clear_table); schedule_work(&ioc->sas_persist_task); break; + /* + * TODO, handle other events + */ case MPI_EVENT_SAS_DEV_STAT_RC_SMART_DATA: - /* TODO */ + case MPI_EVENT_SAS_DEV_STAT_RC_UNSUPPORTED: case MPI_EVENT_SAS_DEV_STAT_RC_INTERNAL_DEVICE_RESET: - /* TODO */ + case MPI_EVENT_SAS_DEV_STAT_RC_TASK_ABORT_INTERNAL: + case MPI_EVENT_SAS_DEV_STAT_RC_ABORT_TASK_SET_INTERNAL: + case MPI_EVENT_SAS_DEV_STAT_RC_CLEAR_TASK_SET_INTERNAL: + case MPI_EVENT_SAS_DEV_STAT_RC_QUERY_TASK_INTERNAL: default: break; } } - static void mptsas_send_raid_event(MPT_ADAPTER *ioc, EVENT_DATA_RAID *raid_event_data) @@ -2404,31 +2822,36 @@ mptsas_send_raid_event(MPT_ADAPTER *ioc, INIT_WORK(&ev->work, mptsas_hotplug_work); ev->ioc = ioc; ev->id = raid_event_data->VolumeID; + ev->channel = raid_event_data->VolumeBus; ev->event_type = MPTSAS_IGNORE_EVENT; switch (raid_event_data->ReasonCode) { case MPI_EVENT_RAID_RC_PHYSDISK_DELETED: + ev->phys_disk_num_valid = 1; + ev->phys_disk_num = raid_event_data->PhysDiskNum; ev->event_type = MPTSAS_ADD_DEVICE; break; case MPI_EVENT_RAID_RC_PHYSDISK_CREATED: - ioc->raid_data.isRaid = 1; ev->phys_disk_num_valid = 1; ev->phys_disk_num = raid_event_data->PhysDiskNum; + ev->hidden_raid_component = 1; ev->event_type = MPTSAS_DEL_DEVICE; break; case MPI_EVENT_RAID_RC_PHYSDISK_STATUS_CHANGED: switch (state) { case MPI_PD_STATE_ONLINE: - ioc->raid_data.isRaid = 1; + case MPI_PD_STATE_NOT_COMPATIBLE: ev->phys_disk_num_valid = 1; ev->phys_disk_num = raid_event_data->PhysDiskNum; + ev->hidden_raid_component = 1; ev->event_type = MPTSAS_ADD_DEVICE; break; case MPI_PD_STATE_MISSING: - case MPI_PD_STATE_NOT_COMPATIBLE: case MPI_PD_STATE_OFFLINE_AT_HOST_REQUEST: case MPI_PD_STATE_FAILED_AT_HOST_REQUEST: case MPI_PD_STATE_OFFLINE_FOR_ANOTHER_REASON: + ev->phys_disk_num_valid = 1; + ev->phys_disk_num = raid_event_data->PhysDiskNum; ev->event_type = MPTSAS_DEL_DEVICE; break; default: @@ -2485,6 +2908,35 @@ mptsas_send_discovery_event(MPT_ADAPTER schedule_work(&ev->work); }; +/* + * mptsas_send_ir2_event - handle exposing hidden disk when + * an inactive raid volume is added + * + * @ioc: Pointer to MPT_ADAPTER structure + * @ir2_data + * + */ +static void +mptsas_send_ir2_event(MPT_ADAPTER *ioc, PTR_MPI_EVENT_DATA_IR2 ir2_data) +{ + struct mptsas_hotplug_event *ev; + + if (ir2_data->ReasonCode != + MPI_EVENT_IR2_RC_FOREIGN_CFG_DETECTED) + return; + + ev = kzalloc(sizeof(*ev), GFP_ATOMIC); + if (!ev) + return; + + INIT_WORK(&ev->work, mptsas_hotplug_work); + ev->ioc = ioc; + ev->id = ir2_data->TargetID; + ev->channel = ir2_data->Bus; + ev->event_type = MPTSAS_ADD_INACTIVE_VOLUME; + + schedule_work(&ev->work); +}; static int mptsas_event_process(MPT_ADAPTER *ioc, EventNotificationReply_t *reply) @@ -2524,6 +2976,10 @@ mptsas_event_process(MPT_ADAPTER *ioc, E mptsas_send_discovery_event(ioc, (EVENT_DATA_SAS_DISCOVERY *)reply->Data); break; + case MPI_EVENT_IR2: + mptsas_send_ir2_event(ioc, + (PTR_MPI_EVENT_DATA_IR2)reply->Data); + break; default: rc = mptscsih_event_process(ioc, reply); break; @@ -2611,12 +3067,11 @@ mptsas_probe(struct pci_dev *pdev, const /* set 16 byte cdb's */ sh->max_cmd_len = 16; - sh->max_id = ioc->pfacts->MaxDevices + 1; + sh->max_id = ioc->pfacts[0].PortSCSIID; + sh->max_lun = max_lun; sh->transportt = mptsas_transport_template; - sh->max_lun = MPT_LAST_LUN + 1; - sh->max_channel = 0; sh->this_id = ioc->pfacts[0].PortSCSIID; /* Required entry. @@ -2659,8 +3114,6 @@ mptsas_probe(struct pci_dev *pdev, const sh->sg_tablesize = numSGE; } - spin_unlock_irqrestore(&ioc->FreeQlock, flags); - hd = (MPT_SCSI_HOST *) sh->hostdata; hd->ioc = ioc; @@ -2676,19 +3129,6 @@ mptsas_probe(struct pci_dev *pdev, const dprintk((MYIOC_s_INFO_FMT "ScsiLookup @ %p\n", ioc->name, hd->ScsiLookup)); - /* Allocate memory for the device structures. - * A non-Null pointer at an offset - * indicates a device exists. - * max_id = 1 + maximum id (hosts.h) - */ - hd->Targets = kcalloc(sh->max_id, sizeof(void *), GFP_ATOMIC); - if (!hd->Targets) { - error = -ENOMEM; - goto out_mptsas_probe; - } - - dprintk((KERN_INFO " vtarget @ %p\n", hd->Targets)); - /* Clear the TM flags */ hd->tmPending = 0; @@ -2713,15 +3153,17 @@ mptsas_probe(struct pci_dev *pdev, const ioc->sas_data.ptClear = mpt_pt_clear; + init_waitqueue_head(&hd->scandv_waitq); + hd->scandv_wait_done = 0; + hd->last_queue_full = 0; + INIT_LIST_HEAD(&hd->target_reset_list); + spin_unlock_irqrestore(&ioc->FreeQlock, flags); + if (ioc->sas_data.ptClear==1) { mptbase_sas_persist_operation( ioc, MPI_SAS_OP_CLEAR_ALL_PERSISTENT); } - init_waitqueue_head(&hd->scandv_waitq); - hd->scandv_wait_done = 0; - hd->last_queue_full = 0; - error = scsi_add_host(sh, &ioc->pcidev->dev); if (error) { dprintk((KERN_ERR MYNAM @@ -2745,7 +3187,7 @@ static void __devexit mptsas_remove(stru struct mptsas_portinfo *p, *n; int i; - ioc->sas_discovery_ignore_events=1; + ioc->sas_discovery_ignore_events = 1; sas_remove_host(ioc->sh); mutex_lock(&ioc->sas_topology_mutex); @@ -2800,7 +3242,7 @@ mptsas_init(void) return -ENODEV; mptsasDoneCtx = mpt_register(mptscsih_io_done, MPTSAS_DRIVER); - mptsasTaskCtx = mpt_register(mptscsih_taskmgmt_complete, MPTSAS_DRIVER); + mptsasTaskCtx = mpt_register(mptsas_taskmgmt_complete, MPTSAS_DRIVER); mptsasInternalCtx = mpt_register(mptscsih_scandv_complete, MPTSAS_DRIVER); mptsasMgmtCtx = mpt_register(mptsas_mgmt_done, MPTSAS_DRIVER); @@ -2810,7 +3252,7 @@ mptsas_init(void) ": Registered for IOC event notifications\n")); } - if (mpt_reset_register(mptsasDoneCtx, mptscsih_ioc_reset) == 0) { + if (mpt_reset_register(mptsasDoneCtx, mptsas_ioc_reset) == 0) { dprintk((KERN_INFO MYNAM ": Registered for IOC reset notifications\n")); } diff --git a/drivers/message/fusion/mptscsih.c b/drivers/message/fusion/mptscsih.c index f0cca3e..2a3e9e6 100644 --- a/drivers/message/fusion/mptscsih.c +++ b/drivers/message/fusion/mptscsih.c @@ -4,7 +4,7 @@ * running LSI Logic Fusion MPT (Message Passing Technology) firmware. * * Copyright (c) 1999-2007 LSI Logic Corporation - * (mailto:mpt_linux_developer@lsil.com) + * (mailto:mpt_linux_developer@lsi.com) * */ /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ @@ -54,7 +54,6 @@ #include #include /* for mdelay */ #include /* needed for in_interrupt() proto */ #include /* notifier code */ -#include #include #include @@ -79,43 +78,6 @@ MODULE_LICENSE("GPL"); MODULE_VERSION(my_VERSION); /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ - -typedef struct _BIG_SENSE_BUF { - u8 data[MPT_SENSE_BUFFER_ALLOC]; -} BIG_SENSE_BUF; - -#define MPT_SCANDV_GOOD (0x00000000) /* must be 0 */ -#define MPT_SCANDV_DID_RESET (0x00000001) -#define MPT_SCANDV_SENSE (0x00000002) -#define MPT_SCANDV_SOME_ERROR (0x00000004) -#define MPT_SCANDV_SELECTION_TIMEOUT (0x00000008) -#define MPT_SCANDV_ISSUE_SENSE (0x00000010) -#define MPT_SCANDV_FALLBACK (0x00000020) - -#define MPT_SCANDV_MAX_RETRIES (10) - -#define MPT_ICFLAG_BUF_CAP 0x01 /* ReadBuffer Read Capacity format */ -#define MPT_ICFLAG_ECHO 0x02 /* ReadBuffer Echo buffer format */ -#define MPT_ICFLAG_EBOS 0x04 /* ReadBuffer Echo buffer has EBOS */ -#define MPT_ICFLAG_PHYS_DISK 0x08 /* Any SCSI IO but do Phys Disk Format */ -#define MPT_ICFLAG_TAGGED_CMD 0x10 /* Do tagged IO */ -#define MPT_ICFLAG_DID_RESET 0x20 /* Bus Reset occurred with this command */ -#define MPT_ICFLAG_RESERVED 0x40 /* Reserved has been issued */ - -typedef struct _internal_cmd { - char *data; /* data pointer */ - dma_addr_t data_dma; /* data dma address */ - int size; /* transfer size */ - u8 cmd; /* SCSI Op Code */ - u8 bus; /* bus number */ - u8 id; /* SCSI ID (virtual) */ - u8 lun; - u8 flags; /* Bit Field - See above */ - u8 physDiskNum; /* Phys disk number, -1 else */ - u8 rsvd2; - u8 rsvd; -} INTERNAL_CMD; - /* * Other private/forward protos... */ @@ -131,14 +93,11 @@ static int mptscsih_tm_pending_wait(MPT_ static int mptscsih_tm_wait_for_completion(MPT_SCSI_HOST * hd, ulong timeout ); static int SCPNT_TO_LOOKUP_IDX(struct scsi_cmnd *sc); -static int mptscsih_IssueTaskMgmt(MPT_SCSI_HOST *hd, u8 type, u8 channel, u8 target, u8 lun, int ctx2abort, ulong timeout); +static int mptscsih_IssueTaskMgmt(MPT_SCSI_HOST *hd, u8 type, u8 channel, u8 id, int lun, int ctx2abort, ulong timeout); int mptscsih_ioc_reset(MPT_ADAPTER *ioc, int post_reset); int mptscsih_event_process(MPT_ADAPTER *ioc, EventNotificationReply_t *pEvReply); -static void mptscsih_initTarget(MPT_SCSI_HOST *hd, VirtTarget *vtarget, struct scsi_device *sdev); -static void mptscsih_setTargetNegoParms(MPT_SCSI_HOST *hd, VirtTarget *vtarget, struct scsi_device *sdev); -static int mptscsih_writeIOCPage4(MPT_SCSI_HOST *hd, int target_id, int bus); int mptscsih_scandv_complete(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *r); static int mptscsih_do_cmd(MPT_SCSI_HOST *hd, INTERNAL_CMD *iocmd); static void mptscsih_synchronize_cache(MPT_SCSI_HOST *hd, VirtDevice *vdevice); @@ -517,16 +476,100 @@ mptscsih_issue_sep_command(MPT_ADAPTER * SEPMsg = (SEPRequest_t *)mf; SEPMsg->Function = MPI_FUNCTION_SCSI_ENCLOSURE_PROCESSOR; - SEPMsg->Bus = vtarget->bus_id; - SEPMsg->TargetID = vtarget->target_id; + SEPMsg->Bus = vtarget->channel; + SEPMsg->TargetID = vtarget->id; SEPMsg->Action = MPI_SEP_REQ_ACTION_WRITE_STATUS; SEPMsg->SlotStatus = SlotStatus; devtverboseprintk((MYIOC_s_WARN_FMT - "Sending SEP cmd=%x id=%d bus=%d\n", - ioc->name, SlotStatus, SEPMsg->TargetID, SEPMsg->Bus)); + "Sending SEP cmd=%x channel=%d id=%d\n", + ioc->name, SlotStatus, SEPMsg->Bus, SEPMsg->TargetID)); mpt_put_msg_frame(ioc->DoneCtx, ioc, mf); } +#ifdef MPT_DEBUG_REPLY +/** + * mptscsih_iocstatus_info_scsiio - IOCSTATUS information for SCSIIO + * @ioc: Pointer to MPT_ADAPTER structure + * @ioc_status: U32 IOCStatus word from IOC + * @scsi_status: U8 sam status from target + * @scsi_state: U8 scsi state + * @sc: original scsi cmnd pointer + * @mf: Pointer to MPT request frame + * + * Refer to lsi/mpi.h. + **/ +static void +mptscsih_iocstatus_info_scsiio(MPT_ADAPTER *ioc, u32 ioc_status, + u8 scsi_status, u8 scsi_state, struct scsi_cmnd *sc) +{ + char extend_desc[EVENT_DESCR_STR_SZ]; + char *desc = NULL; + + switch (ioc_status) { + + case MPI_IOCSTATUS_SCSI_INVALID_BUS: /* 0x0041 */ + desc = "SCSI Invalid Bus"; + break; + + case MPI_IOCSTATUS_SCSI_INVALID_TARGETID: /* 0x0042 */ + desc = "SCSI Invalid TargetID"; + break; + + case MPI_IOCSTATUS_SCSI_DEVICE_NOT_THERE: /* 0x0043 */ + /* + * Inquiry is issued for device scanning + */ + if (sc->cmnd[0] != 0x12) + desc = "SCSI Device Not There"; + break; + + case MPI_IOCSTATUS_SCSI_DATA_OVERRUN: /* 0x0044 */ + desc = "SCSI Data Overrun"; + break; + + case MPI_IOCSTATUS_SCSI_IO_DATA_ERROR: /* 0x0046 */ + desc = "SCSI I/O Data Error"; + break; + + case MPI_IOCSTATUS_SCSI_PROTOCOL_ERROR: /* 0x0047 */ + desc = "SCSI Protocol Error"; + break; + + case MPI_IOCSTATUS_SCSI_TASK_TERMINATED: /* 0x0048 */ + desc = "SCSI Task Terminated"; + break; + + case MPI_IOCSTATUS_SCSI_RESIDUAL_MISMATCH: /* 0x0049 */ + desc = "SCSI Residual Mismatch"; + break; + + case MPI_IOCSTATUS_SCSI_TASK_MGMT_FAILED: /* 0x004A */ + desc = "SCSI Task Management Failed"; + break; + + case MPI_IOCSTATUS_SCSI_IOC_TERMINATED: /* 0x004B */ + desc = "SCSI IOC Terminated"; + break; + + case MPI_IOCSTATUS_SCSI_EXT_TERMINATED: /* 0x004C */ + desc = "SCSI Ext Terminated"; + break; + } + + if (!desc) + return; + + snprintf(extend_desc, EVENT_DESCR_STR_SZ, + "[%d:%d:%d:%d] cmd=%02Xh, sam_status=%02Xh state=%02Xh", + sc->device->host->host_no, + sc->device->channel, sc->device->id, sc->device->lun, + sc->cmnd[0], scsi_status, scsi_state); + + printk(MYIOC_s_INFO_FMT "IOCStatus(0x%04X): %s: %s\n", + ioc->name, ioc_status, desc, extend_desc); +} +#endif + /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ /* * mptscsih_io_done - Main SCSI IO callback routine registered to @@ -613,12 +656,14 @@ mptscsih_io_done(MPT_ADAPTER *ioc, MPT_F u32 xfer_cnt; u16 status; u8 scsi_state, scsi_status; + u32 log_info; status = le16_to_cpu(pScsiReply->IOCStatus) & MPI_IOCSTATUS_MASK; scsi_state = pScsiReply->SCSIState; scsi_status = pScsiReply->SCSIStatus; xfer_cnt = le32_to_cpu(pScsiReply->TransferCount); sc->resid = sc->request_bufflen - xfer_cnt; + log_info = le32_to_cpu(pScsiReply->IOCLogInfo); /* * if we get a data underrun indication, yet no data was @@ -633,13 +678,6 @@ mptscsih_io_done(MPT_ADAPTER *ioc, MPT_F status = MPI_IOCSTATUS_SUCCESS; } - dreplyprintk((KERN_NOTICE "Reply ha=%d id=%d lun=%d:\n" - "IOCStatus=%04xh SCSIState=%02xh SCSIStatus=%02xh\n" - "resid=%d bufflen=%d xfer_cnt=%d\n", - ioc->id, sc->device->id, sc->device->lun, - status, scsi_state, scsi_status, sc->resid, - sc->request_bufflen, xfer_cnt)); - if (scsi_state & MPI_SCSI_STATE_AUTOSENSE_VALID) mptscsih_copy_sense_data(sc, hd, mf, pScsiReply); @@ -648,9 +686,10 @@ mptscsih_io_done(MPT_ADAPTER *ioc, MPT_F */ if (scsi_state & MPI_SCSI_STATE_RESPONSE_INFO_VALID && pScsiReply->ResponseInfo) { - printk(KERN_NOTICE "ha=%d id=%d lun=%d: " + printk(KERN_NOTICE "[%d:%d:%d:%d] " "FCP_ResponseInfo=%08xh\n", - ioc->id, sc->device->id, sc->device->lun, + sc->device->host->host_no, sc->device->channel, + sc->device->id, sc->device->lun, le32_to_cpu(pScsiReply->ResponseInfo)); } @@ -695,9 +734,8 @@ mptscsih_io_done(MPT_ADAPTER *ioc, MPT_F if ( ioc->bus_type == SAS ) { u16 ioc_status = le16_to_cpu(pScsiReply->IOCStatus); if (ioc_status & MPI_IOCSTATUS_FLAG_LOG_INFO_AVAILABLE) { - u32 log_info = le32_to_cpu(mr->u.reply.IOCLogInfo); - log_info &=SAS_LOGINFO_MASK; - if (log_info == SAS_LOGINFO_NEXUS_LOSS) { + if ((log_info & SAS_LOGINFO_MASK) + == SAS_LOGINFO_NEXUS_LOSS) { sc->result = (DID_BUS_BUSY << 16); break; } @@ -735,7 +773,8 @@ mptscsih_io_done(MPT_ADAPTER *ioc, MPT_F else /* Sufficient data transfer occurred */ sc->result = (DID_OK << 16) | scsi_status; dreplyprintk((KERN_NOTICE - "RESIDUAL_MISMATCH: result=%x on id=%d\n", sc->result, sc->device->id)); + "RESIDUAL_MISMATCH: result=%x on channel=%d id=%d\n", + sc->result, sc->device->channel, sc->device->id)); break; case MPI_IOCSTATUS_SCSI_DATA_UNDERRUN: /* 0x0045 */ @@ -848,7 +887,28 @@ mptscsih_io_done(MPT_ADAPTER *ioc, MPT_F } /* switch(status) */ - dreplyprintk((KERN_NOTICE " sc->result is %08xh\n", sc->result)); +#ifdef MPT_DEBUG_REPLY + if (sc->result) { + + mptscsih_iocstatus_info_scsiio(ioc, status, + scsi_status, scsi_state, sc); + + dreplyprintk(("%s: [%d:%d:%d:%d] cmd=0x%02x " + "result=0x%08x\n\tiocstatus=0x%04X " + "scsi_state=0x%02X scsi_status=0x%02X " + "loginfo=0x%08X\n", __FUNCTION__, + sc->device->host->host_no, sc->device->channel, sc->device->id, + sc->device->lun, sc->cmnd[0], sc->result, status, + scsi_state, scsi_status, log_info)); + + dreplyprintk(("%s: [%d:%d:%d:%d] resid=%d " + "bufflen=%d xfer_cnt=%d\n", __FUNCTION__, + sc->device->host->host_no, sc->device->channel, sc->device->id, + sc->device->lun, sc->resid, sc->request_bufflen, + xfer_cnt)); + } +#endif + } /* end of address reply case */ /* Unmap the DMA buffers, if any. */ @@ -955,9 +1015,10 @@ mptscsih_search_running_cmds(MPT_SCSI_HO int ii; int max = hd->ioc->req_depth; struct scsi_cmnd *sc; + struct scsi_lun lun; - dsprintk((KERN_INFO MYNAM ": search_running target %d lun %d max %d\n", - vdevice->vtarget->target_id, vdevice->lun, max)); + dsprintk((KERN_INFO MYNAM ": search_running channel %d id %d lun %d max %d\n", + vdevice->vtarget->channel, vdevice->vtarget->id, vdevice->lun, max)); for (ii=0; ii < max; ii++) { if ((sc = hd->ScsiLookup[ii]) != NULL) { @@ -965,10 +1026,14 @@ mptscsih_search_running_cmds(MPT_SCSI_HO mf = (SCSIIORequest_t *)MPT_INDEX_2_MFPTR(hd->ioc, ii); if (mf == NULL) continue; - dsprintk(( "search_running: found (sc=%p, mf = %p) target %d, lun %d \n", - hd->ScsiLookup[ii], mf, mf->TargetID, mf->LUN[1])); - if ((mf->TargetID != ((u8)vdevice->vtarget->target_id)) || (mf->LUN[1] != ((u8) vdevice->lun))) + int_to_scsilun(vdevice->lun, &lun); + if ((mf->Bus != vdevice->vtarget->channel) || + (mf->TargetID != vdevice->vtarget->id) || + memcmp(lun.scsi_lun, mf->LUN, 8)) continue; + dsprintk(( "search_running: found (sc=%p, mf = %p) " + "channel %d id %d, lun %d \n", hd->ScsiLookup[ii], + mf, mf->Bus, mf->TargetID, vdevice->lun)); /* Cleanup */ @@ -1065,12 +1130,6 @@ mptscsih_remove(struct pci_dev *pdev) hd->ScsiLookup = NULL; } - /* - * Free pointer array. - */ - kfree(hd->Targets); - hd->Targets = NULL; - dprintk((MYIOC_s_INFO_FMT "Free'd ScsiLookup (%d) memory\n", hd->ioc->name, sz1)); @@ -1317,14 +1376,6 @@ mptscsih_qcmd(struct scsi_cmnd *SCpnt, v return SCSI_MLQUEUE_HOST_BUSY; } - if ((hd->ioc->bus_type == SPI) && - vdev->vtarget->tflags & MPT_TARGET_FLAGS_RAID_COMPONENT && - mptscsih_raid_id_to_num(hd, SCpnt->device->id) < 0) { - SCpnt->result = DID_NO_CONNECT << 16; - done(SCpnt); - return 0; - } - /* * Put together a MPT SCSI request... */ @@ -1368,8 +1419,8 @@ mptscsih_qcmd(struct scsi_cmnd *SCpnt, v /* Use the above information to set up the message frame */ - pScsiReq->TargetID = (u8) vdev->vtarget->target_id; - pScsiReq->Bus = vdev->vtarget->bus_id; + pScsiReq->TargetID = (u8) vdev->vtarget->id; + pScsiReq->Bus = vdev->vtarget->channel; pScsiReq->ChainOffset = 0; if (vdev->vtarget->tflags & MPT_TARGET_FLAGS_RAID_COMPONENT) pScsiReq->Function = MPI_FUNCTION_RAID_SCSI_IO_PASSTHROUGH; @@ -1379,14 +1430,7 @@ mptscsih_qcmd(struct scsi_cmnd *SCpnt, v pScsiReq->SenseBufferLength = MPT_SENSE_BUFFER_SIZE; pScsiReq->Reserved = 0; pScsiReq->MsgFlags = mpt_msg_flags(); - pScsiReq->LUN[0] = 0; - pScsiReq->LUN[1] = lun; - pScsiReq->LUN[2] = 0; - pScsiReq->LUN[3] = 0; - pScsiReq->LUN[4] = 0; - pScsiReq->LUN[5] = 0; - pScsiReq->LUN[6] = 0; - pScsiReq->LUN[7] = 0; + int_to_scsilun(SCpnt->device->lun, (struct scsi_lun *)pScsiReq->LUN); pScsiReq->Control = cpu_to_le32(scsictl); /* @@ -1491,14 +1535,14 @@ mptscsih_freeChainBuffers(MPT_ADAPTER *i */ /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ -/* +/** * mptscsih_TMHandler - Generic handler for SCSI Task Management. * Fall through to mpt_HardResetHandler if: not operational, too many * failed TM requests or handshake failure. * * @ioc: Pointer to MPT_ADAPTER structure * @type: Task Management type - * @target: Logical Target ID for reset (if appropriate) + * @id: Logical Target ID for reset (if appropriate) * @lun: Logical Unit for reset (if appropriate) * @ctx2abort: Context for the task to be aborted (if appropriate) * @@ -1507,28 +1551,17 @@ mptscsih_freeChainBuffers(MPT_ADAPTER *i * Remark: With old EH code, at most 1 SCSI TaskMgmt function per IOC * will be active. * - * Returns 0 for SUCCESS or -1 if FAILED. - */ + * Returns 0 for SUCCESS, or FAILED. + **/ int -mptscsih_TMHandler(MPT_SCSI_HOST *hd, u8 type, u8 channel, u8 target, u8 lun, int ctx2abort, ulong timeout) +mptscsih_TMHandler(MPT_SCSI_HOST *hd, u8 type, u8 channel, u8 id, int lun, int ctx2abort, ulong timeout) { MPT_ADAPTER *ioc; int rc = -1; - int doTask = 1; u32 ioc_raw_state; unsigned long flags; - /* If FW is being reloaded currently, return success to - * the calling function. - */ - if (hd == NULL) - return 0; - ioc = hd->ioc; - if (ioc == NULL) { - printk(KERN_ERR MYNAM " TMHandler" " NULL ioc!\n"); - return FAILED; - } dtmprintk((MYIOC_s_INFO_FMT "TMHandler Entered!\n", ioc->name)); // SJR - CHECKME - Can we avoid this here? @@ -1541,8 +1574,10 @@ mptscsih_TMHandler(MPT_SCSI_HOST *hd, u8 spin_unlock_irqrestore(&ioc->diagLock, flags); /* Wait a fixed amount of time for the TM pending flag to be cleared. - * If we time out and not bus reset, then we return a FAILED status to the caller. - * The call to mptscsih_tm_pending_wait() will set the pending flag if we are + * If we time out and not bus reset, then we return a FAILED status + * to the caller. + * The call to mptscsih_tm_pending_wait() will set the pending flag + * if we are * successful. Otherwise, reload the FW. */ if (mptscsih_tm_pending_wait(hd) == FAILED) { @@ -1552,18 +1587,16 @@ mptscsih_TMHandler(MPT_SCSI_HOST *hd, u8 hd->ioc->name, hd->tmPending)); return FAILED; } else if (type == MPI_SCSITASKMGMT_TASKTYPE_TARGET_RESET) { - dtmprintk((KERN_INFO MYNAM ": %s: TMHandler target reset: " - "Timed out waiting for last TM (%d) to complete! \n", - hd->ioc->name, hd->tmPending)); + dtmprintk((KERN_INFO MYNAM ": %s: TMHandler target " + "reset: Timed out waiting for last TM (%d) " + "to complete! \n", hd->ioc->name, + hd->tmPending)); return FAILED; } else if (type == MPI_SCSITASKMGMT_TASKTYPE_RESET_BUS) { dtmprintk((KERN_INFO MYNAM ": %s: TMHandler bus reset: " "Timed out waiting for last TM (%d) to complete! \n", hd->ioc->name, hd->tmPending)); - if (hd->tmPending & (1 << MPI_SCSITASKMGMT_TASKTYPE_RESET_BUS)) - return FAILED; - - doTask = 0; + return FAILED; } } else { spin_lock_irqsave(&hd->ioc->FreeQlock, flags); @@ -1571,47 +1604,40 @@ mptscsih_TMHandler(MPT_SCSI_HOST *hd, u8 spin_unlock_irqrestore(&hd->ioc->FreeQlock, flags); } - /* Is operational? - */ ioc_raw_state = mpt_GetIocState(hd->ioc, 0); -#ifdef MPT_DEBUG_RESET if ((ioc_raw_state & MPI_IOC_STATE_MASK) != MPI_IOC_STATE_OPERATIONAL) { printk(MYIOC_s_WARN_FMT - "TM Handler: IOC Not operational(0x%x)!\n", - hd->ioc->name, ioc_raw_state); - } -#endif - - if (doTask && ((ioc_raw_state & MPI_IOC_STATE_MASK) == MPI_IOC_STATE_OPERATIONAL) - && !(ioc_raw_state & MPI_DOORBELL_ACTIVE)) { - - /* Isse the Task Mgmt request. - */ - if (hd->hard_resets < -1) - hd->hard_resets++; - rc = mptscsih_IssueTaskMgmt(hd, type, channel, target, lun, ctx2abort, timeout); - if (rc) { - printk(MYIOC_s_INFO_FMT "Issue of TaskMgmt failed!\n", hd->ioc->name); - } else { - dtmprintk((MYIOC_s_INFO_FMT "Issue of TaskMgmt Successful!\n", hd->ioc->name)); - } + "TM Handler for type=%x: IOC Not operational (0x%x)!\n", + ioc->name, type, ioc_raw_state); + printk(KERN_WARNING " Issuing HardReset!!\n"); + if (mpt_HardResetHandler(ioc, CAN_SLEEP) < 0) + printk((KERN_WARNING "TMHandler: HardReset " + "FAILED!!\n")); + return FAILED; } - /* Only fall through to the HRH if this is a bus reset - */ - if ((type == MPI_SCSITASKMGMT_TASKTYPE_RESET_BUS) && (rc || - ioc->reload_fw || (ioc->alt_ioc && ioc->alt_ioc->reload_fw))) { - dtmprintk((MYIOC_s_INFO_FMT "Calling HardReset! \n", - hd->ioc->name)); - rc = mpt_HardResetHandler(hd->ioc, CAN_SLEEP); + if (ioc_raw_state & MPI_DOORBELL_ACTIVE) { + printk(MYIOC_s_WARN_FMT + "TM Handler for type=%x: ioc_state: " + "DOORBELL_ACTIVE (0x%x)!\n", + ioc->name, type, ioc_raw_state); + return FAILED; } - /* - * Check IOCStatus from TM reply message + /* Isse the Task Mgmt request. */ - if (hd->tm_iocstatus != MPI_IOCSTATUS_SUCCESS) - rc = FAILED; + if (hd->hard_resets < -1) + hd->hard_resets++; + + rc = mptscsih_IssueTaskMgmt(hd, type, channel, id, lun, + ctx2abort, timeout); + if (rc) + printk(MYIOC_s_INFO_FMT "Issue of TaskMgmt failed!\n", + hd->ioc->name); + else + dtmprintk((MYIOC_s_INFO_FMT "Issue of TaskMgmt Successful!\n", + hd->ioc->name)); dtmprintk((MYIOC_s_INFO_FMT "TMHandler rc = %d!\n", hd->ioc->name, rc)); @@ -1620,11 +1646,11 @@ #endif /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ -/* +/** * mptscsih_IssueTaskMgmt - Generic send Task Management function. * @hd: Pointer to MPT_SCSI_HOST structure * @type: Task Management type - * @target: Logical Target ID for reset (if appropriate) + * @id: Logical Target ID for reset (if appropriate) * @lun: Logical Unit for reset (if appropriate) * @ctx2abort: Context for the task to be aborted (if appropriate) * @@ -1633,11 +1659,11 @@ #endif * * Not all fields are meaningfull for all task types. * - * Returns 0 for SUCCESS, -999 for "no msg frames", - * else other non-zero value returned. - */ + * Returns 0 for SUCCESS, or FAILED. + * + **/ static int -mptscsih_IssueTaskMgmt(MPT_SCSI_HOST *hd, u8 type, u8 channel, u8 target, u8 lun, int ctx2abort, ulong timeout) +mptscsih_IssueTaskMgmt(MPT_SCSI_HOST *hd, u8 type, u8 channel, u8 id, int lun, int ctx2abort, ulong timeout) { MPT_FRAME_HDR *mf; SCSITaskMgmt_t *pScsiTm; @@ -1657,7 +1683,7 @@ mptscsih_IssueTaskMgmt(MPT_SCSI_HOST *hd /* Format the Request */ pScsiTm = (SCSITaskMgmt_t *) mf; - pScsiTm->TargetID = target; + pScsiTm->TargetID = id; pScsiTm->Bus = channel; pScsiTm->ChainOffset = 0; pScsiTm->Function = MPI_FUNCTION_SCSI_TASK_MGMT; @@ -1668,42 +1694,59 @@ mptscsih_IssueTaskMgmt(MPT_SCSI_HOST *hd pScsiTm->MsgFlags = (type == MPI_SCSITASKMGMT_TASKTYPE_RESET_BUS) ? MPI_SCSITASKMGMT_MSGFLAGS_LIPRESET_RESET_OPTION : 0; - for (ii= 0; ii < 8; ii++) { - pScsiTm->LUN[ii] = 0; - } - pScsiTm->LUN[1] = lun; + int_to_scsilun(lun, (struct scsi_lun *)pScsiTm->LUN); for (ii=0; ii < 7; ii++) pScsiTm->Reserved2[ii] = 0; pScsiTm->TaskMsgContext = ctx2abort; - dtmprintk((MYIOC_s_INFO_FMT "IssueTaskMgmt: ctx2abort (0x%08x) type=%d\n", - hd->ioc->name, ctx2abort, type)); + dtmprintk((MYIOC_s_INFO_FMT "IssueTaskMgmt: ctx2abort (0x%08x) " + "type=%d\n", hd->ioc->name, ctx2abort, type)); DBG_DUMP_TM_REQUEST_FRAME((u32 *)pScsiTm); if ((retval = mpt_send_handshake_request(hd->ioc->TaskCtx, hd->ioc, - sizeof(SCSITaskMgmt_t), (u32*)pScsiTm, - CAN_SLEEP)) != 0) { - dfailprintk((MYIOC_s_ERR_FMT "_send_handshake FAILED!" - " (hd %p, ioc %p, mf %p) \n", hd->ioc->name, hd, - hd->ioc, mf)); - mpt_free_msg_frame(hd->ioc, mf); - return retval; + sizeof(SCSITaskMgmt_t), (u32*)pScsiTm, CAN_SLEEP)) != 0) { + dfailprintk((MYIOC_s_ERR_FMT "send_handshake FAILED!" + " (hd %p, ioc %p, mf %p, rc=%d) \n", hd->ioc->name, hd, + hd->ioc, mf, retval)); + goto fail_out; } if(mptscsih_tm_wait_for_completion(hd, timeout) == FAILED) { - dfailprintk((MYIOC_s_ERR_FMT "_wait_for_completion FAILED!" + dfailprintk((MYIOC_s_ERR_FMT "task management request TIMED OUT!" " (hd %p, ioc %p, mf %p) \n", hd->ioc->name, hd, hd->ioc, mf)); - mpt_free_msg_frame(hd->ioc, mf); dtmprintk((MYIOC_s_INFO_FMT "Calling HardReset! \n", hd->ioc->name)); retval = mpt_HardResetHandler(hd->ioc, CAN_SLEEP); + dtmprintk((MYIOC_s_INFO_FMT "rc=%d \n", + hd->ioc->name, retval)); + goto fail_out; } + /* + * Handle success case, see if theres a non-zero ioc_status. + */ + if (hd->tm_iocstatus == MPI_IOCSTATUS_SUCCESS || + hd->tm_iocstatus == MPI_IOCSTATUS_SCSI_TASK_TERMINATED || + hd->tm_iocstatus == MPI_IOCSTATUS_SCSI_IOC_TERMINATED) + retval = 0; + else + retval = FAILED; + return retval; + + fail_out: + + /* + * Free task managment mf, and corresponding tm flags + */ + mpt_free_msg_frame(hd->ioc, mf); + hd->tmPending = 0; + hd->tmState = TM_STATE_NONE; + return FAILED; } static int @@ -1728,7 +1771,7 @@ mptscsih_get_tm_timeout(MPT_ADAPTER *ioc * (linux scsi_host_template.eh_abort_handler routine) * * Returns SUCCESS or FAILED. - */ + **/ int mptscsih_abort(struct scsi_cmnd * SCpnt) { @@ -1764,9 +1807,8 @@ mptscsih_abort(struct scsi_cmnd * SCpnt) return SUCCESS; } - if (hd->resetPending) { + if (hd->resetPending) return FAILED; - } if (hd->timeouts < -1) hd->timeouts++; @@ -1789,13 +1831,12 @@ mptscsih_abort(struct scsi_cmnd * SCpnt) vdev = SCpnt->device->hostdata; retval = mptscsih_TMHandler(hd, MPI_SCSITASKMGMT_TASKTYPE_ABORT_TASK, - vdev->vtarget->bus_id, vdev->vtarget->target_id, vdev->lun, + vdev->vtarget->channel, vdev->vtarget->id, vdev->lun, ctx2abort, mptscsih_get_tm_timeout(hd->ioc)); if (SCPNT_TO_LOOKUP_IDX(SCpnt) == scpnt_idx && - SCpnt->serial_number == sn) { + SCpnt->serial_number == sn) retval = FAILED; - } printk (KERN_WARNING MYNAM ": %s: task abort: %s (sc=%p)\n", hd->ioc->name, @@ -1803,12 +1844,8 @@ mptscsih_abort(struct scsi_cmnd * SCpnt) if (retval == 0) return SUCCESS; - - if(retval != FAILED ) { - hd->tmPending = 0; - hd->tmState = TM_STATE_NONE; - } - return FAILED; + else + return FAILED; } /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ @@ -1819,7 +1856,7 @@ mptscsih_abort(struct scsi_cmnd * SCpnt) * (linux scsi_host_template.eh_dev_reset_handler routine) * * Returns SUCCESS or FAILED. - */ + **/ int mptscsih_dev_reset(struct scsi_cmnd * SCpnt) { @@ -1845,7 +1882,7 @@ mptscsih_dev_reset(struct scsi_cmnd * SC vdev = SCpnt->device->hostdata; retval = mptscsih_TMHandler(hd, MPI_SCSITASKMGMT_TASKTYPE_TARGET_RESET, - vdev->vtarget->bus_id, vdev->vtarget->target_id, + vdev->vtarget->channel, vdev->vtarget->id, 0, 0, mptscsih_get_tm_timeout(hd->ioc)); printk (KERN_WARNING MYNAM ": %s: target reset: %s (sc=%p)\n", @@ -1854,14 +1891,11 @@ mptscsih_dev_reset(struct scsi_cmnd * SC if (retval == 0) return SUCCESS; - - if(retval != FAILED ) { - hd->tmPending = 0; - hd->tmState = TM_STATE_NONE; - } - return FAILED; + else + return FAILED; } + /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ /** * mptscsih_bus_reset - Perform a SCSI BUS_RESET! new_eh variant @@ -1870,7 +1904,7 @@ mptscsih_dev_reset(struct scsi_cmnd * SC * (linux scsi_host_template.eh_bus_reset_handler routine) * * Returns SUCCESS or FAILED. - */ + **/ int mptscsih_bus_reset(struct scsi_cmnd * SCpnt) { @@ -1896,7 +1930,7 @@ mptscsih_bus_reset(struct scsi_cmnd * SC vdev = SCpnt->device->hostdata; retval = mptscsih_TMHandler(hd, MPI_SCSITASKMGMT_TASKTYPE_RESET_BUS, - vdev->vtarget->bus_id, 0, 0, 0, mptscsih_get_tm_timeout(hd->ioc)); + vdev->vtarget->channel, 0, 0, 0, mptscsih_get_tm_timeout(hd->ioc)); printk (KERN_WARNING MYNAM ": %s: bus reset: %s (sc=%p)\n", hd->ioc->name, @@ -1904,12 +1938,8 @@ mptscsih_bus_reset(struct scsi_cmnd * SC if (retval == 0) return SUCCESS; - - if(retval != FAILED ) { - hd->tmPending = 0; - hd->tmState = TM_STATE_NONE; - } - return FAILED; + else + return FAILED; } /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ @@ -1992,7 +2022,6 @@ mptscsih_tm_pending_wait(MPT_SCSI_HOST * /** * mptscsih_tm_wait_for_completion - wait for completion of TM task * @hd: Pointer to MPT host structure. - * @timeout: timeout in seconds * * Returns {SUCCESS,FAILED}. */ @@ -2066,7 +2095,7 @@ mptscsih_taskmgmt_response_code(MPT_ADAP * load/init time via the mpt_register() API call. * * Returns 1 indicating alloc'd request frame ptr should be freed. - */ + **/ int mptscsih_taskmgmt_complete(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *mr) { @@ -2076,78 +2105,85 @@ mptscsih_taskmgmt_complete(MPT_ADAPTER * unsigned long flags; u16 iocstatus; u8 tmType; + u32 termination_count; dtmprintk((MYIOC_s_WARN_FMT "TaskMgmt completed (mf=%p,mr=%p)\n", - ioc->name, mf, mr)); - if (ioc->sh) { - /* Depending on the thread, a timer is activated for - * the TM request. Delete this timer on completion of TM. - * Decrement count of outstanding TM requests. - */ - hd = (MPT_SCSI_HOST *)ioc->sh->hostdata; - } else { - dtmprintk((MYIOC_s_WARN_FMT "TaskMgmt Complete: NULL Scsi Host Ptr\n", - ioc->name)); + ioc->name, mf, mr)); + if (!ioc->sh) { + dtmprintk((MYIOC_s_WARN_FMT + "TaskMgmt Complete: NULL Scsi Host Ptr\n", ioc->name)); return 1; } if (mr == NULL) { - dtmprintk((MYIOC_s_WARN_FMT "ERROR! TaskMgmt Reply: NULL Request %p\n", - ioc->name, mf)); + dtmprintk((MYIOC_s_WARN_FMT + "ERROR! TaskMgmt Reply: NULL Request %p\n", ioc->name, mf)); return 1; - } else { - pScsiTmReply = (SCSITaskMgmtReply_t*)mr; - pScsiTmReq = (SCSITaskMgmt_t*)mf; - - /* Figure out if this was ABORT_TASK, TARGET_RESET, or BUS_RESET! */ - tmType = pScsiTmReq->TaskType; + } - if (ioc->facts.MsgVersion >= MPI_VERSION_01_05 && - pScsiTmReply->ResponseCode) - mptscsih_taskmgmt_response_code(ioc, - pScsiTmReply->ResponseCode); + hd = (MPT_SCSI_HOST *)ioc->sh->hostdata; + pScsiTmReply = (SCSITaskMgmtReply_t*)mr; + pScsiTmReq = (SCSITaskMgmt_t*)mf; + tmType = pScsiTmReq->TaskType; + iocstatus = le16_to_cpu(pScsiTmReply->IOCStatus) & MPI_IOCSTATUS_MASK; + termination_count = le32_to_cpu(pScsiTmReply->TerminationCount); + + if (ioc->facts.MsgVersion >= MPI_VERSION_01_05 && + pScsiTmReply->ResponseCode) + mptscsih_taskmgmt_response_code(ioc, + pScsiTmReply->ResponseCode); + DBG_DUMP_TM_REPLY_FRAME((u32 *)pScsiTmReply); + +#if defined(MPT_DEBUG_REPLY) || defined(MPT_DEBUG_TM) + printk("%s: ha=%d [%d:%d:0] task_type=0x%02X " + "iocstatus=0x%04X\n\tloginfo=0x%08X response_code=0x%02X " + "term_cmnds=%d\n", __FUNCTION__, ioc->id, pScsiTmReply->Bus, + pScsiTmReply->TargetID, pScsiTmReq->TaskType, + le16_to_cpu(pScsiTmReply->IOCStatus), + le32_to_cpu(pScsiTmReply->IOCLogInfo),pScsiTmReply->ResponseCode, + le32_to_cpu(pScsiTmReply->TerminationCount)); +#endif + if (!iocstatus) { + dtmprintk((MYIOC_s_WARN_FMT " TaskMgmt SUCCESS\n", ioc->name)); + hd->abortSCpnt = NULL; + goto out; + } - dtmprintk((MYIOC_s_WARN_FMT " TaskType = %d, TerminationCount=%d\n", - ioc->name, tmType, le32_to_cpu(pScsiTmReply->TerminationCount))); - DBG_DUMP_TM_REPLY_FRAME((u32 *)pScsiTmReply); + /* Error? (anything non-zero?) */ - iocstatus = le16_to_cpu(pScsiTmReply->IOCStatus) & MPI_IOCSTATUS_MASK; - hd->tm_iocstatus = iocstatus; - dtmprintk((MYIOC_s_WARN_FMT " SCSI TaskMgmt (%d) IOCStatus=%04x IOCLogInfo=%08x\n", - ioc->name, tmType, iocstatus, le32_to_cpu(pScsiTmReply->IOCLogInfo))); - /* Error? (anything non-zero?) */ - if (iocstatus) { + /* clear flags and continue. + */ + switch (tmType) { - /* clear flags and continue. - */ - if (tmType == MPI_SCSITASKMGMT_TASKTYPE_ABORT_TASK) - hd->abortSCpnt = NULL; + case MPI_SCSITASKMGMT_TASKTYPE_ABORT_TASK: + if (termination_count == 1) + iocstatus = MPI_IOCSTATUS_SCSI_TASK_TERMINATED; + hd->abortSCpnt = NULL; + break; - /* If an internal command is present - * or the TM failed - reload the FW. - * FC FW may respond FAILED to an ABORT - */ - if (tmType == MPI_SCSITASKMGMT_TASKTYPE_RESET_BUS) { - if ((hd->cmdPtr) || - (iocstatus == MPI_IOCSTATUS_SCSI_TASK_MGMT_FAILED)) { - if (mpt_HardResetHandler(ioc, NO_SLEEP) < 0) { - printk((KERN_WARNING - " Firmware Reload FAILED!!\n")); - } - } - } - } else { - dtmprintk((MYIOC_s_WARN_FMT " TaskMgmt SUCCESS\n", ioc->name)); + case MPI_SCSITASKMGMT_TASKTYPE_RESET_BUS: - hd->abortSCpnt = NULL; + /* If an internal command is present + * or the TM failed - reload the FW. + * FC FW may respond FAILED to an ABORT + */ + if (iocstatus == MPI_IOCSTATUS_SCSI_TASK_MGMT_FAILED || + hd->cmdPtr) + if (mpt_HardResetHandler(ioc, NO_SLEEP) < 0) + printk((KERN_WARNING " Firmware Reload FAILED!!\n")); + break; - } + case MPI_SCSITASKMGMT_TASKTYPE_TARGET_RESET: + default: + break; } + out: spin_lock_irqsave(&ioc->FreeQlock, flags); hd->tmPending = 0; - spin_unlock_irqrestore(&ioc->FreeQlock, flags); hd->tmState = TM_STATE_NONE; + hd->tm_iocstatus = iocstatus; + spin_unlock_irqrestore(&ioc->FreeQlock, flags); return 1; } @@ -2191,7 +2227,7 @@ mptscsih_bios_param(struct scsi_device * dprintk((KERN_NOTICE ": bios_param: Id=%i Lun=%i Channel=%i CHS=%i/%i/%i\n", - sdev->id, sdev->lun,sdev->channel,(int)cylinders,heads,sectors)); + sdev->id, sdev->lun, sdev->channel, (int)cylinders, heads, sectors)); return 0; } @@ -2200,115 +2236,78 @@ mptscsih_bios_param(struct scsi_device * * */ int -mptscsih_is_phys_disk(MPT_ADAPTER *ioc, int id) +mptscsih_is_phys_disk(MPT_ADAPTER *ioc, u8 channel, u8 id) { + struct inactive_raid_component_info *component_info; int i; + int rc = 0; - if (!ioc->raid_data.isRaid || !ioc->raid_data.pIocPg3) - return 0; + if (!ioc->raid_data.pIocPg3) + goto out; for (i = 0; i < ioc->raid_data.pIocPg3->NumPhysDisks; i++) { - if (id == ioc->raid_data.pIocPg3->PhysDisk[i].PhysDiskID) - return 1; - } - return 0; -} -EXPORT_SYMBOL(mptscsih_is_phys_disk); - -int -mptscsih_raid_id_to_num(MPT_SCSI_HOST *hd, uint physdiskid) -{ - int i; - - if (!hd->ioc->raid_data.isRaid || !hd->ioc->raid_data.pIocPg3) - return -ENXIO; - - for (i = 0; i < hd->ioc->raid_data.pIocPg3->NumPhysDisks; i++) { - if (physdiskid == - hd->ioc->raid_data.pIocPg3->PhysDisk[i].PhysDiskID) - return hd->ioc->raid_data.pIocPg3->PhysDisk[i].PhysDiskNum; + if ((id == ioc->raid_data.pIocPg3->PhysDisk[i].PhysDiskID) && + (channel == ioc->raid_data.pIocPg3->PhysDisk[i].PhysDiskBus)) { + rc = 1; + goto out; + } } - return -ENXIO; -} -EXPORT_SYMBOL(mptscsih_raid_id_to_num); + /* + * Check inactive list for matching phys disks + */ + if (list_empty(&ioc->raid_data.inactive_list)) + goto out; -/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ -/* - * OS entry point to allow host driver to alloc memory - * for each scsi target. Called once per device the bus scan. - * Return non-zero if allocation fails. - */ -int -mptscsih_target_alloc(struct scsi_target *starget) -{ - VirtTarget *vtarget; + down(&ioc->raid_data.inactive_list_mutex); + list_for_each_entry(component_info, &ioc->raid_data.inactive_list, + list) { + if ((component_info->d.PhysDiskID == id) && + (component_info->d.PhysDiskBus == channel)) + rc = 1; + } + up(&ioc->raid_data.inactive_list_mutex); - vtarget = kzalloc(sizeof(VirtTarget), GFP_KERNEL); - if (!vtarget) - return -ENOMEM; - starget->hostdata = vtarget; - vtarget->starget = starget; - return 0; + out: + return rc; } +EXPORT_SYMBOL(mptscsih_is_phys_disk); -/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ -/* - * OS entry point to allow host driver to alloc memory - * for each scsi device. Called once per device the bus scan. - * Return non-zero if allocation fails. - */ -int -mptscsih_slave_alloc(struct scsi_device *sdev) +u8 +mptscsih_raid_id_to_num(MPT_ADAPTER *ioc, u8 channel, u8 id) { - struct Scsi_Host *host = sdev->host; - MPT_SCSI_HOST *hd = (MPT_SCSI_HOST *)host->hostdata; - VirtTarget *vtarget; - VirtDevice *vdev; - struct scsi_target *starget; + struct inactive_raid_component_info *component_info; + int i; + int rc = -ENXIO; - vdev = kzalloc(sizeof(VirtDevice), GFP_KERNEL); - if (!vdev) { - printk(MYIOC_s_ERR_FMT "slave_alloc kmalloc(%zd) FAILED!\n", - hd->ioc->name, sizeof(VirtDevice)); - return -ENOMEM; + if (!ioc->raid_data.pIocPg3) + goto out; + for (i = 0; i < ioc->raid_data.pIocPg3->NumPhysDisks; i++) { + if ((id == ioc->raid_data.pIocPg3->PhysDisk[i].PhysDiskID) && + (channel == ioc->raid_data.pIocPg3->PhysDisk[i].PhysDiskBus)) { + rc = ioc->raid_data.pIocPg3->PhysDisk[i].PhysDiskNum; + goto out; + } } - vdev->lun = sdev->lun; - sdev->hostdata = vdev; - - starget = scsi_target(sdev); - vtarget = starget->hostdata; + /* + * Check inactive list for matching phys disks + */ + if (list_empty(&ioc->raid_data.inactive_list)) + goto out; - vdev->vtarget = vtarget; - - if (vtarget->num_luns == 0) { - hd->Targets[sdev->id] = vtarget; - vtarget->ioc_id = hd->ioc->id; - vtarget->tflags = MPT_TARGET_FLAGS_Q_YES; - vtarget->target_id = sdev->id; - vtarget->bus_id = sdev->channel; - if (hd->ioc->bus_type == SPI && sdev->channel == 0 && - hd->ioc->raid_data.isRaid & (1 << sdev->id)) { - vtarget->raidVolume = 1; - ddvtprintk((KERN_INFO - "RAID Volume @ id %d\n", sdev->id)); - } + down(&ioc->raid_data.inactive_list_mutex); + list_for_each_entry(component_info, &ioc->raid_data.inactive_list, + list) { + if ((component_info->d.PhysDiskID == id) && + (component_info->d.PhysDiskBus == channel)) + rc = component_info->d.PhysDiskNum; } - vtarget->num_luns++; - return 0; -} + up(&ioc->raid_data.inactive_list_mutex); -/* - * OS entry point to allow for host driver to free allocated memory - * Called if no device present or device being unloaded - */ -void -mptscsih_target_destroy(struct scsi_target *starget) -{ - if (starget->hostdata) - kfree(starget->hostdata); - starget->hostdata = NULL; + out: + return rc; } +EXPORT_SYMBOL(mptscsih_raid_id_to_num); /* * OS entry point to allow for host driver to free allocated memory @@ -2328,11 +2327,7 @@ mptscsih_slave_destroy(struct scsi_devic vdevice = sdev->hostdata; mptscsih_search_running_cmds(hd, vdevice); - vtarget->luns[0] &= ~(1 << vdevice->lun); vtarget->num_luns--; - if (vtarget->num_luns == 0) { - hd->Targets[sdev->id] = NULL; - } mptscsih_synchronize_cache(hd, vdevice); kfree(vdevice); sdev->hostdata = NULL; @@ -2394,15 +2389,14 @@ mptscsih_slave_configure(struct scsi_dev VirtDevice *vdevice; struct scsi_target *starget; MPT_SCSI_HOST *hd = (MPT_SCSI_HOST *)sh->hostdata; - int indexed_lun, lun_index; starget = scsi_target(sdev); vtarget = starget->hostdata; vdevice = sdev->hostdata; dsprintk((MYIOC_s_INFO_FMT - "device @ %p, id=%d, LUN=%d, channel=%d\n", - hd->ioc->name, sdev, sdev->id, sdev->lun, sdev->channel)); + "device @ %p, channel=%d, id=%d, lun=%d\n", + hd->ioc->name, sdev, sdev->channel, sdev->id, sdev->lun)); if (hd->ioc->bus_type == SPI) dsprintk((MYIOC_s_INFO_FMT "sdtr %d wdtr %d ppr %d inq length=%d\n", @@ -2415,11 +2409,7 @@ mptscsih_slave_configure(struct scsi_dev goto slave_configure_exit; } - vdevice->configured_lun=1; - lun_index = (vdevice->lun >> 5); /* 32 luns per lun_index */ - indexed_lun = (vdevice->lun % 32); - vtarget->luns[lun_index] |= (1 << indexed_lun); - mptscsih_initTarget(hd, vtarget, sdev); + vdevice->configured_lun = 1; mptscsih_change_queue_depth(sdev, MPT_SCSI_CMD_PER_DEV_HIGH); dsprintk((MYIOC_s_INFO_FMT @@ -2683,285 +2673,6 @@ mptscsih_event_process(MPT_ADAPTER *ioc, /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ /* - * mptscsih_initTarget - Target, LUN alloc/free functionality. - * @hd: Pointer to MPT_SCSI_HOST structure - * @vtarget: per target private data - * @sdev: SCSI device - * - * NOTE: It's only SAFE to call this routine if data points to - * sane & valid STANDARD INQUIRY data! - * - * Allocate and initialize memory for this target. - * Save inquiry data. - * - */ -static void -mptscsih_initTarget(MPT_SCSI_HOST *hd, VirtTarget *vtarget, - struct scsi_device *sdev) -{ - dinitprintk((MYIOC_s_INFO_FMT "initTarget bus=%d id=%d lun=%d hd=%p\n", - hd->ioc->name, vtarget->bus_id, vtarget->target_id, - sdev->lun, hd)); - - /* Is LUN supported? If so, upper 2 bits will be 0 - * in first byte of inquiry data. - */ - if (sdev->inq_periph_qual != 0) - return; - - if (vtarget == NULL) - return; - - vtarget->type = sdev->type; - - if (hd->ioc->bus_type != SPI) - return; - - if ((sdev->type == TYPE_PROCESSOR) && (hd->ioc->spi_data.Saf_Te)) { - /* Treat all Processors as SAF-TE if - * command line option is set */ - vtarget->tflags |= MPT_TARGET_FLAGS_SAF_TE_ISSUED; - mptscsih_writeIOCPage4(hd, vtarget->target_id, vtarget->bus_id); - }else if ((sdev->type == TYPE_PROCESSOR) && - !(vtarget->tflags & MPT_TARGET_FLAGS_SAF_TE_ISSUED )) { - if (sdev->inquiry_len > 49 ) { - if (sdev->inquiry[44] == 'S' && - sdev->inquiry[45] == 'A' && - sdev->inquiry[46] == 'F' && - sdev->inquiry[47] == '-' && - sdev->inquiry[48] == 'T' && - sdev->inquiry[49] == 'E' ) { - vtarget->tflags |= MPT_TARGET_FLAGS_SAF_TE_ISSUED; - mptscsih_writeIOCPage4(hd, vtarget->target_id, vtarget->bus_id); - } - } - } - mptscsih_setTargetNegoParms(hd, vtarget, sdev); -} - -/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ -/* - * Update the target negotiation parameters based on the - * the Inquiry data, adapter capabilities, and NVRAM settings. - * - */ -static void -mptscsih_setTargetNegoParms(MPT_SCSI_HOST *hd, VirtTarget *target, - struct scsi_device *sdev) -{ - SpiCfgData *pspi_data = &hd->ioc->spi_data; - int id = (int) target->target_id; - int nvram; - u8 width = MPT_NARROW; - u8 factor = MPT_ASYNC; - u8 offset = 0; - u8 nfactor; - u8 noQas = 1; - - target->negoFlags = pspi_data->noQas; - - /* noQas == 0 => device supports QAS. */ - - if (sdev->scsi_level < SCSI_2) { - width = 0; - factor = MPT_ULTRA2; - offset = pspi_data->maxSyncOffset; - target->tflags &= ~MPT_TARGET_FLAGS_Q_YES; - } else { - if (scsi_device_wide(sdev)) { - width = 1; - } - - if (scsi_device_sync(sdev)) { - factor = pspi_data->minSyncFactor; - if (!scsi_device_dt(sdev)) - factor = MPT_ULTRA2; - else { - if (!scsi_device_ius(sdev) && - !scsi_device_qas(sdev)) - factor = MPT_ULTRA160; - else { - factor = MPT_ULTRA320; - if (scsi_device_qas(sdev)) { - ddvtprintk((KERN_INFO "Enabling QAS due to byte56=%02x on id=%d!\n", scsi_device_qas(sdev), id)); - noQas = 0; - } - if (sdev->type == TYPE_TAPE && - scsi_device_ius(sdev)) - target->negoFlags |= MPT_TAPE_NEGO_IDP; - } - } - offset = pspi_data->maxSyncOffset; - - /* If RAID, never disable QAS - * else if non RAID, do not disable - * QAS if bit 1 is set - * bit 1 QAS support, non-raid only - * bit 0 IU support - */ - if (target->raidVolume == 1) { - noQas = 0; - } - } else { - factor = MPT_ASYNC; - offset = 0; - } - } - - if (!sdev->tagged_supported) { - target->tflags &= ~MPT_TARGET_FLAGS_Q_YES; - } - - /* Update tflags based on NVRAM settings. (SCSI only) - */ - if (pspi_data->nvram && (pspi_data->nvram[id] != MPT_HOST_NVRAM_INVALID)) { - nvram = pspi_data->nvram[id]; - nfactor = (nvram & MPT_NVRAM_SYNC_MASK) >> 8; - - if (width) - width = nvram & MPT_NVRAM_WIDE_DISABLE ? 0 : 1; - - if (offset > 0) { - /* Ensure factor is set to the - * maximum of: adapter, nvram, inquiry - */ - if (nfactor) { - if (nfactor < pspi_data->minSyncFactor ) - nfactor = pspi_data->minSyncFactor; - - factor = max(factor, nfactor); - if (factor == MPT_ASYNC) - offset = 0; - } else { - offset = 0; - factor = MPT_ASYNC; - } - } else { - factor = MPT_ASYNC; - } - } - - /* Make sure data is consistent - */ - if ((!width) && (factor < MPT_ULTRA2)) { - factor = MPT_ULTRA2; - } - - /* Save the data to the target structure. - */ - target->minSyncFactor = factor; - target->maxOffset = offset; - target->maxWidth = width; - - target->tflags |= MPT_TARGET_FLAGS_VALID_NEGO; - - /* Disable unused features. - */ - if (!width) - target->negoFlags |= MPT_TARGET_NO_NEGO_WIDE; - - if (!offset) - target->negoFlags |= MPT_TARGET_NO_NEGO_SYNC; - - if ( factor > MPT_ULTRA320 ) - noQas = 0; - - if (noQas && (pspi_data->noQas == 0)) { - pspi_data->noQas |= MPT_TARGET_NO_NEGO_QAS; - target->negoFlags |= MPT_TARGET_NO_NEGO_QAS; - - /* Disable QAS in a mixed configuration case - */ - - ddvtprintk((KERN_INFO "Disabling QAS due to noQas=%02x on id=%d!\n", noQas, id)); - } -} - -/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ - -/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ -/* - * SCSI Config Page functionality ... - */ - -/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ -/* mptscsih_writeIOCPage4 - write IOC Page 4 - * @hd: Pointer to a SCSI Host Structure - * @target_id: write IOC Page4 for this ID & Bus - * - * Return: -EAGAIN if unable to obtain a Message Frame - * or 0 if success. - * - * Remark: We do not wait for a return, write pages sequentially. - */ -static int -mptscsih_writeIOCPage4(MPT_SCSI_HOST *hd, int target_id, int bus) -{ - MPT_ADAPTER *ioc = hd->ioc; - Config_t *pReq; - IOCPage4_t *IOCPage4Ptr; - MPT_FRAME_HDR *mf; - dma_addr_t dataDma; - u16 req_idx; - u32 frameOffset; - u32 flagsLength; - int ii; - - /* Get a MF for this command. - */ - if ((mf = mpt_get_msg_frame(ioc->DoneCtx, ioc)) == NULL) { - dfailprintk((MYIOC_s_WARN_FMT "writeIOCPage4 : no msg frames!\n", - ioc->name)); - return -EAGAIN; - } - - /* Set the request and the data pointers. - * Place data at end of MF. - */ - pReq = (Config_t *)mf; - - req_idx = le16_to_cpu(mf->u.frame.hwhdr.msgctxu.fld.req_idx); - frameOffset = ioc->req_sz - sizeof(IOCPage4_t); - - /* Complete the request frame (same for all requests). - */ - pReq->Action = MPI_CONFIG_ACTION_PAGE_WRITE_CURRENT; - pReq->Reserved = 0; - pReq->ChainOffset = 0; - pReq->Function = MPI_FUNCTION_CONFIG; - pReq->ExtPageLength = 0; - pReq->ExtPageType = 0; - pReq->MsgFlags = 0; - for (ii=0; ii < 8; ii++) { - pReq->Reserved2[ii] = 0; - } - - IOCPage4Ptr = ioc->spi_data.pIocPg4; - dataDma = ioc->spi_data.IocPg4_dma; - ii = IOCPage4Ptr->ActiveSEP++; - IOCPage4Ptr->SEP[ii].SEPTargetID = target_id; - IOCPage4Ptr->SEP[ii].SEPBus = bus; - pReq->Header = IOCPage4Ptr->Header; - pReq->PageAddress = cpu_to_le32(target_id | (bus << 8 )); - - /* Add a SGE to the config request. - */ - flagsLength = MPT_SGE_FLAGS_SSIMPLE_WRITE | - (IOCPage4Ptr->Header.PageLength + ii) * 4; - - mpt_add_sge((char *)&pReq->PageBufferSGE, flagsLength, dataDma); - - dinitprintk((MYIOC_s_INFO_FMT - "writeIOCPage4: MaxSEP=%d ActiveSEP=%d id=%d bus=%d\n", - ioc->name, IOCPage4Ptr->MaxSEP, IOCPage4Ptr->ActiveSEP, target_id, bus)); - - mpt_put_msg_frame(ioc->DoneCtx, ioc, mf); - - return 0; -} - -/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ -/* * Bus Scan and Domain Validation functionality ... */ @@ -3343,7 +3054,7 @@ mptscsih_do_cmd(MPT_SCSI_HOST *hd, INTER pScsiReq->Function = MPI_FUNCTION_RAID_SCSI_IO_PASSTHROUGH; } else { pScsiReq->TargetID = io->id; - pScsiReq->Bus = io->bus; + pScsiReq->Bus = io->channel; pScsiReq->ChainOffset = 0; pScsiReq->Function = MPI_FUNCTION_SCSI_IO_REQUEST; } @@ -3356,9 +3067,7 @@ mptscsih_do_cmd(MPT_SCSI_HOST *hd, INTER pScsiReq->MsgFlags = mpt_msg_flags(); /* MsgContext set in mpt_get_msg_fram call */ - for (ii=0; ii < 8; ii++) - pScsiReq->LUN[ii] = 0; - pScsiReq->LUN[1] = io->lun; + int_to_scsilun(io->lun, (struct scsi_lun *)pScsiReq->LUN); if (io->flags & MPT_ICFLAG_TAGGED_CMD) pScsiReq->Control = cpu_to_le32(dir | MPI_SCSIIO_CONTROL_SIMPLEQ); @@ -3379,7 +3088,7 @@ mptscsih_do_cmd(MPT_SCSI_HOST *hd, INTER + (my_idx * MPT_SENSE_BUFFER_ALLOC)); ddvprintk((MYIOC_s_INFO_FMT "Sending Command 0x%x for (%d:%d:%d)\n", - hd->ioc->name, cmd, io->bus, io->id, io->lun)); + hd->ioc->name, cmd, io->channel, io->id, io->lun)); if (dir == MPI_SCSIIO_CONTROL_READ) { mpt_add_sge((char *) &pScsiReq->SGL, @@ -3462,9 +3171,9 @@ mptscsih_synchronize_cache(MPT_SCSI_HOST iocmd.data_dma = -1; iocmd.size = 0; iocmd.rsvd = iocmd.rsvd2 = 0; - iocmd.bus = vdevice->vtarget->bus_id; - iocmd.id = vdevice->vtarget->target_id; - iocmd.lun = (u8)vdevice->lun; + iocmd.channel = vdevice->vtarget->channel; + iocmd.id = vdevice->vtarget->id; + iocmd.lun = vdevice->lun; if ((vdevice->vtarget->type == TYPE_DISK) && (vdevice->configured_lun)) @@ -3480,9 +3189,6 @@ #endif EXPORT_SYMBOL(mptscsih_proc_info); EXPORT_SYMBOL(mptscsih_info); EXPORT_SYMBOL(mptscsih_qcmd); -EXPORT_SYMBOL(mptscsih_target_alloc); -EXPORT_SYMBOL(mptscsih_slave_alloc); -EXPORT_SYMBOL(mptscsih_target_destroy); EXPORT_SYMBOL(mptscsih_slave_destroy); EXPORT_SYMBOL(mptscsih_slave_configure); EXPORT_SYMBOL(mptscsih_abort); diff --git a/drivers/message/fusion/mptscsih.h b/drivers/message/fusion/mptscsih.h index 187c8af..843c01a 100644 --- a/drivers/message/fusion/mptscsih.h +++ b/drivers/message/fusion/mptscsih.h @@ -6,7 +6,7 @@ * running LSI Logic Fusion MPT (Message Passing Technology) firmware. * * Copyright (c) 1999-2007 LSI Logic Corporation - * (mailto:mpt_linux_developer@lsil.com) + * (mailto:mpt_linux_developer@lsi.com) * */ /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ @@ -53,6 +53,24 @@ #define SCSIHOST_H_INCLUDED * SCSI Public stuff... */ +#define MPT_SCANDV_GOOD (0x00000000) /* must be 0 */ +#define MPT_SCANDV_DID_RESET (0x00000001) +#define MPT_SCANDV_SENSE (0x00000002) +#define MPT_SCANDV_SOME_ERROR (0x00000004) +#define MPT_SCANDV_SELECTION_TIMEOUT (0x00000008) +#define MPT_SCANDV_ISSUE_SENSE (0x00000010) +#define MPT_SCANDV_FALLBACK (0x00000020) + +#define MPT_SCANDV_MAX_RETRIES (10) + +#define MPT_ICFLAG_BUF_CAP 0x01 /* ReadBuffer Read Capacity format */ +#define MPT_ICFLAG_ECHO 0x02 /* ReadBuffer Echo buffer format */ +#define MPT_ICFLAG_EBOS 0x04 /* ReadBuffer Echo buffer has EBOS */ +#define MPT_ICFLAG_PHYS_DISK 0x08 /* Any SCSI IO but do Phys Disk Format */ +#define MPT_ICFLAG_TAGGED_CMD 0x10 /* Do tagged IO */ +#define MPT_ICFLAG_DID_RESET 0x20 /* Bus Reset occurred with this command */ +#define MPT_ICFLAG_RESERVED 0x40 /* Reserved has been issued */ + #define MPT_SCSI_CMD_PER_DEV_HIGH 64 #define MPT_SCSI_CMD_PER_DEV_LOW 32 @@ -69,9 +87,22 @@ #define MPTSCSIH_MIN_SYNC #define MPTSCSIH_SAF_TE 0 #define MPTSCSIH_PT_CLEAR 0 - #endif +typedef struct _internal_cmd { + char *data; /* data pointer */ + dma_addr_t data_dma; /* data dma address */ + int size; /* transfer size */ + u8 cmd; /* SCSI Op Code */ + u8 channel; /* bus number */ + u8 id; /* SCSI ID (virtual) */ + int lun; + u8 flags; /* Bit Field - See above */ + u8 physDiskNum; /* Phys disk number, -1 else */ + u8 rsvd2; + u8 rsvd; +} INTERNAL_CMD; + extern void mptscsih_remove(struct pci_dev *); extern void mptscsih_shutdown(struct pci_dev *); #ifdef CONFIG_PM @@ -81,9 +112,6 @@ #endif extern int mptscsih_proc_info(struct Scsi_Host *host, char *buffer, char **start, off_t offset, int length, int func); extern const char * mptscsih_info(struct Scsi_Host *SChost); extern int mptscsih_qcmd(struct scsi_cmnd *SCpnt, void (*done)(struct scsi_cmnd *)); -extern int mptscsih_target_alloc(struct scsi_target *starget); -extern int mptscsih_slave_alloc(struct scsi_device *device); -extern void mptscsih_target_destroy(struct scsi_target *starget); extern void mptscsih_slave_destroy(struct scsi_device *device); extern int mptscsih_slave_configure(struct scsi_device *device); extern int mptscsih_abort(struct scsi_cmnd * SCpnt); @@ -98,6 +126,6 @@ extern int mptscsih_event_process(MPT_AD extern int mptscsih_ioc_reset(MPT_ADAPTER *ioc, int post_reset); extern int mptscsih_change_queue_depth(struct scsi_device *sdev, int qdepth); extern void mptscsih_timer_expired(unsigned long data); -extern int mptscsih_TMHandler(MPT_SCSI_HOST *hd, u8 type, u8 channel, u8 target, u8 lun, int ctx2abort, ulong timeout); -extern int mptscsih_raid_id_to_num(MPT_SCSI_HOST *hd, uint physdiskid); -extern int mptscsih_is_phys_disk(MPT_ADAPTER *ioc, int id); +extern int mptscsih_TMHandler(MPT_SCSI_HOST *hd, u8 type, u8 channel, u8 id, int lun, int ctx2abort, ulong timeout); +extern u8 mptscsih_raid_id_to_num(MPT_ADAPTER *ioc, u8 channel, u8 id); +extern int mptscsih_is_phys_disk(MPT_ADAPTER *ioc, u8 channel, u8 id); diff --git a/drivers/message/fusion/mptspi.c b/drivers/message/fusion/mptspi.c index 203c661..85f21b5 100644 --- a/drivers/message/fusion/mptspi.c +++ b/drivers/message/fusion/mptspi.c @@ -4,7 +4,7 @@ * running LSI Logic Fusion MPT (Message Passing Technology) firmware. * * Copyright (c) 1999-2007 LSI Logic Corporation - * (mailto:mpt_linux_developer@lsil.com) + * (mailto:mpt_linux_developer@lsi.com) * */ /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ @@ -54,7 +54,6 @@ #include #include /* for mdelay */ #include /* needed for in_interrupt() proto */ #include /* notifier code */ -#include #include #include @@ -65,6 +64,7 @@ #include #include #include #include +#include #include "mptbase.h" #include "mptscsih.h" @@ -95,25 +95,339 @@ static int mptspiDoneCtx = -1; static int mptspiTaskCtx = -1; static int mptspiInternalCtx = -1; /* Used only for internal commands */ +/** + * mptspi_setTargetNegoParms - Update the target negotiation + * parameters based on the the Inquiry data, adapter capabilities, + * and NVRAM settings + * + * @hd: Pointer to a SCSI Host Structure + * @vtarget: per target private data + * @sdev: SCSI device + * + **/ +static void +mptspi_setTargetNegoParms(MPT_SCSI_HOST *hd, VirtTarget *target, + struct scsi_device *sdev) +{ + SpiCfgData *pspi_data = &hd->ioc->spi_data; + int id = (int) target->id; + int nvram; + u8 width = MPT_NARROW; + u8 factor = MPT_ASYNC; + u8 offset = 0; + u8 nfactor; + u8 noQas = 1; + + target->negoFlags = pspi_data->noQas; + + if (sdev->scsi_level < SCSI_2) { + width = 0; + factor = MPT_ULTRA2; + offset = pspi_data->maxSyncOffset; + target->tflags &= ~MPT_TARGET_FLAGS_Q_YES; + } else { + if (scsi_device_wide(sdev)) + width = 1; + + if (scsi_device_sync(sdev)) { + factor = pspi_data->minSyncFactor; + if (!scsi_device_dt(sdev)) + factor = MPT_ULTRA2; + else { + if (!scsi_device_ius(sdev) && + !scsi_device_qas(sdev)) + factor = MPT_ULTRA160; + else { + factor = MPT_ULTRA320; + if (scsi_device_qas(sdev)) { + ddvprintk((KERN_INFO "Enabling QAS due to byte56=%02x on id=%d!\n", scsi_device_qas(sdev), id)); + noQas = 0; + } + if (sdev->type == TYPE_TAPE && + scsi_device_ius(sdev)) + target->negoFlags |= MPT_TAPE_NEGO_IDP; + } + } + offset = pspi_data->maxSyncOffset; + + /* If RAID, never disable QAS + * else if non RAID, do not disable + * QAS if bit 1 is set + * bit 1 QAS support, non-raid only + * bit 0 IU support + */ + if (target->raidVolume == 1) + noQas = 0; + } else { + factor = MPT_ASYNC; + offset = 0; + } + } + + if (!sdev->tagged_supported) + target->tflags &= ~MPT_TARGET_FLAGS_Q_YES; + + /* Update tflags based on NVRAM settings. (SCSI only) + */ + if (pspi_data->nvram && (pspi_data->nvram[id] != MPT_HOST_NVRAM_INVALID)) { + nvram = pspi_data->nvram[id]; + nfactor = (nvram & MPT_NVRAM_SYNC_MASK) >> 8; + + if (width) + width = nvram & MPT_NVRAM_WIDE_DISABLE ? 0 : 1; + + if (offset > 0) { + /* Ensure factor is set to the + * maximum of: adapter, nvram, inquiry + */ + if (nfactor) { + if (nfactor < pspi_data->minSyncFactor ) + nfactor = pspi_data->minSyncFactor; + + factor = max(factor, nfactor); + if (factor == MPT_ASYNC) + offset = 0; + } else { + offset = 0; + factor = MPT_ASYNC; + } + } else { + factor = MPT_ASYNC; + } + } + + /* Make sure data is consistent + */ + if ((!width) && (factor < MPT_ULTRA2)) + factor = MPT_ULTRA2; + + /* Save the data to the target structure. + */ + target->minSyncFactor = factor; + target->maxOffset = offset; + target->maxWidth = width; + + target->tflags |= MPT_TARGET_FLAGS_VALID_NEGO; + + /* Disable unused features. + */ + if (!width) + target->negoFlags |= MPT_TARGET_NO_NEGO_WIDE; + + if (!offset) + target->negoFlags |= MPT_TARGET_NO_NEGO_SYNC; + + if ( factor > MPT_ULTRA320 ) + noQas = 0; + + if (noQas && (pspi_data->noQas == 0)) { + pspi_data->noQas |= MPT_TARGET_NO_NEGO_QAS; + target->negoFlags |= MPT_TARGET_NO_NEGO_QAS; + + /* Disable QAS in a mixed configuration case + */ + + ddvprintk((KERN_INFO "Disabling QAS due to noQas=%02x on id=%d!\n", noQas, id)); + } +} + +/** + * mptspi_writeIOCPage4 - write IOC Page 4 + * @hd: Pointer to a SCSI Host Structure + * @channel: + * @id: write IOC Page4 for this ID & Bus + * + * Return: -EAGAIN if unable to obtain a Message Frame + * or 0 if success. + * + * Remark: We do not wait for a return, write pages sequentially. + **/ +static int +mptspi_writeIOCPage4(MPT_SCSI_HOST *hd, u8 channel , u8 id) +{ + MPT_ADAPTER *ioc = hd->ioc; + Config_t *pReq; + IOCPage4_t *IOCPage4Ptr; + MPT_FRAME_HDR *mf; + dma_addr_t dataDma; + u16 req_idx; + u32 frameOffset; + u32 flagsLength; + int ii; + + /* Get a MF for this command. + */ + if ((mf = mpt_get_msg_frame(ioc->DoneCtx, ioc)) == NULL) { + dfailprintk((MYIOC_s_WARN_FMT "writeIOCPage4 : no msg frames!\n", + ioc->name)); + return -EAGAIN; + } + + /* Set the request and the data pointers. + * Place data at end of MF. + */ + pReq = (Config_t *)mf; + + req_idx = le16_to_cpu(mf->u.frame.hwhdr.msgctxu.fld.req_idx); + frameOffset = ioc->req_sz - sizeof(IOCPage4_t); + + /* Complete the request frame (same for all requests). + */ + pReq->Action = MPI_CONFIG_ACTION_PAGE_WRITE_CURRENT; + pReq->Reserved = 0; + pReq->ChainOffset = 0; + pReq->Function = MPI_FUNCTION_CONFIG; + pReq->ExtPageLength = 0; + pReq->ExtPageType = 0; + pReq->MsgFlags = 0; + for (ii=0; ii < 8; ii++) { + pReq->Reserved2[ii] = 0; + } + + IOCPage4Ptr = ioc->spi_data.pIocPg4; + dataDma = ioc->spi_data.IocPg4_dma; + ii = IOCPage4Ptr->ActiveSEP++; + IOCPage4Ptr->SEP[ii].SEPTargetID = id; + IOCPage4Ptr->SEP[ii].SEPBus = channel; + pReq->Header = IOCPage4Ptr->Header; + pReq->PageAddress = cpu_to_le32(id | (channel << 8 )); + + /* Add a SGE to the config request. + */ + flagsLength = MPT_SGE_FLAGS_SSIMPLE_WRITE | + (IOCPage4Ptr->Header.PageLength + ii) * 4; + + mpt_add_sge((char *)&pReq->PageBufferSGE, flagsLength, dataDma); + + ddvprintk((MYIOC_s_INFO_FMT + "writeIOCPage4: MaxSEP=%d ActiveSEP=%d id=%d bus=%d\n", + ioc->name, IOCPage4Ptr->MaxSEP, IOCPage4Ptr->ActiveSEP, id, channel)); + + mpt_put_msg_frame(ioc->DoneCtx, ioc, mf); + + return 0; +} + +/** + * mptspi_initTarget - Target, LUN alloc/free functionality. + * @hd: Pointer to MPT_SCSI_HOST structure + * @vtarget: per target private data + * @sdev: SCSI device + * + * NOTE: It's only SAFE to call this routine if data points to + * sane & valid STANDARD INQUIRY data! + * + * Allocate and initialize memory for this target. + * Save inquiry data. + * + **/ +static void +mptspi_initTarget(MPT_SCSI_HOST *hd, VirtTarget *vtarget, + struct scsi_device *sdev) +{ + + /* Is LUN supported? If so, upper 2 bits will be 0 + * in first byte of inquiry data. + */ + if (sdev->inq_periph_qual != 0) + return; + + if (vtarget == NULL) + return; + + vtarget->type = sdev->type; + + if ((sdev->type == TYPE_PROCESSOR) && (hd->ioc->spi_data.Saf_Te)) { + /* Treat all Processors as SAF-TE if + * command line option is set */ + vtarget->tflags |= MPT_TARGET_FLAGS_SAF_TE_ISSUED; + mptspi_writeIOCPage4(hd, vtarget->channel, vtarget->id); + }else if ((sdev->type == TYPE_PROCESSOR) && + !(vtarget->tflags & MPT_TARGET_FLAGS_SAF_TE_ISSUED )) { + if (sdev->inquiry_len > 49 ) { + if (sdev->inquiry[44] == 'S' && + sdev->inquiry[45] == 'A' && + sdev->inquiry[46] == 'F' && + sdev->inquiry[47] == '-' && + sdev->inquiry[48] == 'T' && + sdev->inquiry[49] == 'E' ) { + vtarget->tflags |= MPT_TARGET_FLAGS_SAF_TE_ISSUED; + mptspi_writeIOCPage4(hd, vtarget->channel, vtarget->id); + } + } + } + mptspi_setTargetNegoParms(hd, vtarget, sdev); +} + +/** + * mptspi_is_raid - Determines whether target is belonging to volume + * @hd: Pointer to a SCSI HOST structure + * @id: target device id + * + * Return: + * non-zero = true + * zero = false + * + */ +static int +mptspi_is_raid(struct _MPT_SCSI_HOST *hd, u32 id) +{ + int i, rc = 0; + + if (!hd->ioc->raid_data.pIocPg2) + goto out; + + if (!hd->ioc->raid_data.pIocPg2->NumActiveVolumes) + goto out; + for (i=0; i < hd->ioc->raid_data.pIocPg2->NumActiveVolumes; i++) { + if (hd->ioc->raid_data.pIocPg2->RaidVolume[i].VolumeID == id) { + rc = 1; + goto out; + } + } + + out: + return rc; +} + static int mptspi_target_alloc(struct scsi_target *starget) { struct Scsi_Host *shost = dev_to_shost(&starget->dev); struct _MPT_SCSI_HOST *hd = (struct _MPT_SCSI_HOST *)shost->hostdata; - int ret; + VirtTarget *vtarget; if (hd == NULL) return -ENODEV; - ret = mptscsih_target_alloc(starget); - if (ret) - return ret; + vtarget = kzalloc(sizeof(VirtTarget), GFP_KERNEL); + if (!vtarget) + return -ENOMEM; + + vtarget->ioc_id = hd->ioc->id; + vtarget->tflags = MPT_TARGET_FLAGS_Q_YES; + vtarget->id = (u8)starget->id; + vtarget->channel = (u8)starget->channel; + vtarget->starget = starget; + starget->hostdata = vtarget; + + if (starget->channel == 1) { + if (mptscsih_is_phys_disk(hd->ioc, 0, starget->id) == 0) + return 0; + vtarget->tflags |= MPT_TARGET_FLAGS_RAID_COMPONENT; + /* The real channel for this device is zero */ + vtarget->channel = 0; + /* The actual physdisknum (for RAID passthrough) */ + vtarget->id = mptscsih_raid_id_to_num(hd->ioc, 0, + starget->id); + } - /* if we're a device on virtual channel 1 and we're not part - * of an array, just return here (otherwise the setup below - * may actually affect a real physical device on channel 0 */ - if (starget->channel == 1 && - mptscsih_raid_id_to_num(hd, starget->id) < 0) - return 0; + if (starget->channel == 0 && + mptspi_is_raid(hd, starget->id)) { + vtarget->raidVolume = 1; + ddvprintk((KERN_INFO + "RAID Volume @ channel=%d id=%d\n", starget->channel, + starget->id)); + } if (hd->ioc->spi_data.nvram && hd->ioc->spi_data.nvram[starget->id] != MPT_HOST_NVRAM_INVALID) { @@ -132,6 +446,64 @@ static int mptspi_target_alloc(struct sc return 0; } +void +mptspi_target_destroy(struct scsi_target *starget) +{ + if (starget->hostdata) + kfree(starget->hostdata); + starget->hostdata = NULL; +} + +/** + * mptspi_print_write_nego - negotiation parameters debug info that is being sent + * @hd: Pointer to a SCSI HOST structure + * @starget: SCSI target + * @ii: negotiation parameters + * + */ +static void +mptspi_print_write_nego(struct _MPT_SCSI_HOST *hd, struct scsi_target *starget, u32 ii) +{ + ddvprintk((MYIOC_s_INFO_FMT "id=%d Requested = 0x%08x" + " ( %s factor = 0x%02x @ offset = 0x%02x %s%s%s%s%s%s%s%s)\n", + hd->ioc->name, starget->id, ii, + ii & MPI_SCSIDEVPAGE0_NP_WIDE ? "Wide ": "", + ((ii >> 8) & 0xFF), ((ii >> 16) & 0xFF), + ii & MPI_SCSIDEVPAGE0_NP_IU ? "IU ": "", + ii & MPI_SCSIDEVPAGE0_NP_DT ? "DT ": "", + ii & MPI_SCSIDEVPAGE0_NP_QAS ? "QAS ": "", + ii & MPI_SCSIDEVPAGE0_NP_HOLD_MCS ? "HOLDMCS ": "", + ii & MPI_SCSIDEVPAGE0_NP_WR_FLOW ? "WRFLOW ": "", + ii & MPI_SCSIDEVPAGE0_NP_RD_STRM ? "RDSTRM ": "", + ii & MPI_SCSIDEVPAGE0_NP_RTI ? "RTI ": "", + ii & MPI_SCSIDEVPAGE0_NP_PCOMP_EN ? "PCOMP ": "")); +} + +/** + * mptspi_print_read_nego - negotiation parameters debug info that is being read + * @hd: Pointer to a SCSI HOST structure + * @starget: SCSI target + * @ii: negotiation parameters + * + */ +static void +mptspi_print_read_nego(struct _MPT_SCSI_HOST *hd, struct scsi_target *starget, u32 ii) +{ + ddvprintk((MYIOC_s_INFO_FMT "id=%d Read = 0x%08x" + " ( %s factor = 0x%02x @ offset = 0x%02x %s%s%s%s%s%s%s%s)\n", + hd->ioc->name, starget->id, ii, + ii & MPI_SCSIDEVPAGE0_NP_WIDE ? "Wide ": "", + ((ii >> 8) & 0xFF), ((ii >> 16) & 0xFF), + ii & MPI_SCSIDEVPAGE0_NP_IU ? "IU ": "", + ii & MPI_SCSIDEVPAGE0_NP_DT ? "DT ": "", + ii & MPI_SCSIDEVPAGE0_NP_QAS ? "QAS ": "", + ii & MPI_SCSIDEVPAGE0_NP_HOLD_MCS ? "HOLDMCS ": "", + ii & MPI_SCSIDEVPAGE0_NP_WR_FLOW ? "WRFLOW ": "", + ii & MPI_SCSIDEVPAGE0_NP_RD_STRM ? "RDSTRM ": "", + ii & MPI_SCSIDEVPAGE0_NP_RTI ? "RTI ": "", + ii & MPI_SCSIDEVPAGE0_NP_PCOMP_EN ? "PCOMP ": "")); +} + static int mptspi_read_spi_device_pg0(struct scsi_target *starget, struct _CONFIG_PAGE_SCSI_DEVICE_0 *pass_pg0) { @@ -147,7 +519,7 @@ static int mptspi_read_spi_device_pg0(st /* No SPI parameters for RAID devices */ if (starget->channel == 0 && - (hd->ioc->raid_data.isRaid & (1 << starget->id))) + mptspi_is_raid(hd, starget->id)) return -1; size = ioc->spi_data.sdp0length * 4; @@ -185,6 +557,8 @@ static int mptspi_read_spi_device_pg0(st err = 0; memcpy(pass_pg0, pg0, size); + mptspi_print_read_nego(hd, starget, le32_to_cpu(pg0->NegotiatedParameters)); + out_free: dma_free_coherent(&ioc->pcidev->dev, size, pg0, pg0_dma); return err; @@ -233,7 +607,7 @@ static void mptspi_read_parameters(struc } static int -mptscsih_quiesce_raid(MPT_SCSI_HOST *hd, int quiesce, int disk) +mptscsih_quiesce_raid(MPT_SCSI_HOST *hd, int quiesce, u8 channel, u8 id) { MpiRaidActionRequest_t *pReq; MPT_FRAME_HDR *mf; @@ -253,8 +627,8 @@ mptscsih_quiesce_raid(MPT_SCSI_HOST *hd, pReq->Reserved1 = 0; pReq->ChainOffset = 0; pReq->Function = MPI_FUNCTION_RAID_ACTION; - pReq->VolumeID = disk; - pReq->VolumeBus = 0; + pReq->VolumeID = id; + pReq->VolumeBus = channel; pReq->PhysDiskNum = 0; pReq->MsgFlags = 0; pReq->Reserved2 = 0; @@ -263,8 +637,8 @@ mptscsih_quiesce_raid(MPT_SCSI_HOST *hd, mpt_add_sge((char *)&pReq->ActionDataSGE, MPT_SGE_FLAGS_SSIMPLE_READ | 0, (dma_addr_t) -1); - ddvprintk((MYIOC_s_INFO_FMT "RAID Volume action %x id %d\n", - hd->ioc->name, action, io->id)); + ddvprintk((MYIOC_s_INFO_FMT "RAID Volume action=%x channel=%d id=%d\n", + hd->ioc->name, pReq->Action, channel, id)); hd->pLocal = NULL; hd->timer.expires = jiffies + HZ*10; /* 10 second timeout */ @@ -292,12 +666,12 @@ static void mptspi_dv_device(struct _MPT /* no DV on RAID devices */ if (sdev->channel == 0 && - (hd->ioc->raid_data.isRaid & (1 << sdev->id))) + mptspi_is_raid(hd, sdev->id)) return; /* If this is a piece of a RAID, then quiesce first */ if (sdev->channel == 1 && - mptscsih_quiesce_raid(hd, 1, vtarget->target_id) < 0) { + mptscsih_quiesce_raid(hd, 1, vtarget->channel, vtarget->id) < 0) { starget_printk(KERN_ERR, scsi_target(sdev), "Integrated RAID quiesce failed\n"); return; @@ -306,7 +680,7 @@ static void mptspi_dv_device(struct _MPT spi_dv_device(sdev); if (sdev->channel == 1 && - mptscsih_quiesce_raid(hd, 0, vtarget->target_id) < 0) + mptscsih_quiesce_raid(hd, 0, vtarget->channel, vtarget->id) < 0) starget_printk(KERN_ERR, scsi_target(sdev), "Integrated RAID resume failed\n"); @@ -317,54 +691,89 @@ static void mptspi_dv_device(struct _MPT static int mptspi_slave_alloc(struct scsi_device *sdev) { - int ret; MPT_SCSI_HOST *hd = (MPT_SCSI_HOST *)sdev->host->hostdata; - /* gcc doesn't see that all uses of this variable occur within - * the if() statements, so stop it from whining */ - int physdisknum = 0; - - if (sdev->channel == 1) { - physdisknum = mptscsih_raid_id_to_num(hd, sdev->id); + VirtTarget *vtarget; + VirtDevice *vdev; + struct scsi_target *starget; - if (physdisknum < 0) - return physdisknum; + if (sdev->channel == 1 && + mptscsih_is_phys_disk(hd->ioc, 0, sdev->id) == 0) + return -ENXIO; + + vdev = kzalloc(sizeof(VirtDevice), GFP_KERNEL); + if (!vdev) { + printk(MYIOC_s_ERR_FMT "slave_alloc kmalloc(%zd) FAILED!\n", + hd->ioc->name, sizeof(VirtDevice)); + return -ENOMEM; } - ret = mptscsih_slave_alloc(sdev); + vdev->lun = sdev->lun; + sdev->hostdata = vdev; - if (ret) - return ret; + starget = scsi_target(sdev); + vtarget = starget->hostdata; + vdev->vtarget = vtarget; + vtarget->num_luns++; - if (sdev->channel == 1) { - VirtDevice *vdev = sdev->hostdata; + if (sdev->channel == 1) sdev->no_uld_attach = 1; - vdev->vtarget->tflags |= MPT_TARGET_FLAGS_RAID_COMPONENT; - /* The real channel for this device is zero */ - vdev->vtarget->bus_id = 0; - /* The actual physdisknum (for RAID passthrough) */ - vdev->vtarget->target_id = physdisknum; - } return 0; } static int mptspi_slave_configure(struct scsi_device *sdev) { - int ret = mptscsih_slave_configure(sdev); struct _MPT_SCSI_HOST *hd = (struct _MPT_SCSI_HOST *)sdev->host->hostdata; + VirtTarget *vtarget = scsi_target(sdev)->hostdata; + int ret = mptscsih_slave_configure(sdev); if (ret) return ret; + mptspi_initTarget(hd, vtarget, sdev); + + ddvprintk((MYIOC_s_INFO_FMT "id=%d min_period=0x%02x" + " max_offset=0x%02x max_width=%d\n", hd->ioc->name, + sdev->id, spi_min_period(scsi_target(sdev)), + spi_max_offset(scsi_target(sdev)), + spi_max_width(scsi_target(sdev)))); + if ((sdev->channel == 1 || - !(hd->ioc->raid_data.isRaid & (1 << sdev->id))) && + !(mptspi_is_raid(hd, sdev->id))) && !spi_initial_dv(sdev->sdev_target)) mptspi_dv_device(hd, sdev); return 0; } +static int +mptspi_qcmd(struct scsi_cmnd *SCpnt, void (*done)(struct scsi_cmnd *)) +{ + struct _MPT_SCSI_HOST *hd = (MPT_SCSI_HOST *) SCpnt->device->host->hostdata; + VirtDevice *vdev = SCpnt->device->hostdata; + + if (!vdev || !vdev->vtarget) { + SCpnt->result = DID_NO_CONNECT << 16; + done(SCpnt); + return 0; + } + + if (SCpnt->device->channel == 1 && + mptscsih_is_phys_disk(hd->ioc, 0, SCpnt->device->id) == 0) { + SCpnt->result = DID_NO_CONNECT << 16; + done(SCpnt); + return 0; + } + +#ifdef MPT_DEBUG_DV + if (spi_dv_pending(scsi_target(SCpnt->device))) + scsi_print_command(SCpnt); +#endif + + return mptscsih_qcmd(SCpnt,done); +} + static void mptspi_slave_destroy(struct scsi_device *sdev) { struct scsi_target *starget = scsi_target(sdev); @@ -392,11 +801,11 @@ static struct scsi_host_template mptspi_ .proc_info = mptscsih_proc_info, .name = "MPT SPI Host", .info = mptscsih_info, - .queuecommand = mptscsih_qcmd, + .queuecommand = mptspi_qcmd, .target_alloc = mptspi_target_alloc, .slave_alloc = mptspi_slave_alloc, .slave_configure = mptspi_slave_configure, - .target_destroy = mptscsih_target_destroy, + .target_destroy = mptspi_target_destroy, .slave_destroy = mptspi_slave_destroy, .change_queue_depth = mptscsih_change_queue_depth, .eh_abort_handler = mptscsih_abort, @@ -427,7 +836,7 @@ static int mptspi_write_spi_device_pg1(s /* don't allow updating nego parameters on RAID devices */ if (starget->channel == 0 && - (hd->ioc->raid_data.isRaid & (1 << starget->id))) + mptspi_is_raid(hd, starget->id)) return -1; size = ioc->spi_data.sdp1length * 4; @@ -460,6 +869,8 @@ static int mptspi_write_spi_device_pg1(s pg1->Header.PageNumber = hdr.PageNumber; pg1->Header.PageType = hdr.PageType; + mptspi_print_write_nego(hd, starget, le32_to_cpu(pg1->RequestedParameters)); + if (mpt_config(ioc, &cfg)) { starget_printk(KERN_ERR, starget, "mpt_config failed\n"); goto out_free; @@ -672,9 +1083,9 @@ static void mpt_work_wrapper(struct work if (sdev->channel != 1) continue; - /* The target_id is the raid PhysDiskNum, even if + /* The id is the raid PhysDiskNum, even if * starget->id is the actual target address */ - if(vtarget->target_id != disk) + if(vtarget->id != disk) continue; starget_printk(KERN_INFO, vtarget->starget, @@ -727,7 +1138,7 @@ mptspi_deny_binding(struct scsi_target * { struct _MPT_SCSI_HOST *hd = (struct _MPT_SCSI_HOST *)dev_to_shost(starget->dev.parent)->hostdata; - return ((hd->ioc->raid_data.isRaid & (1 << starget->id)) && + return ((mptspi_is_raid(hd, starget->id)) && starget->channel == 0) ? 1 : 0; } @@ -945,14 +1356,13 @@ mptspi_probe(struct pci_dev *pdev, const * max_lun = 1 + actual last lun, * see hosts.h :o( */ - sh->max_id = MPT_MAX_SCSI_DEVICES; + sh->max_id = ioc->devices_per_bus; sh->max_lun = MPT_LAST_LUN + 1; /* * If RAID Firmware Detected, setup virtual channel */ - if ((ioc->facts.ProductID & MPI_FW_HEADER_PID_PROD_MASK) - > MPI_FW_HEADER_PID_PROD_TARGET_SCSI) + if (ioc->ir_firmware) sh->max_channel = 1; else sh->max_channel = 0; @@ -1009,20 +1419,6 @@ mptspi_probe(struct pci_dev *pdev, const dprintk((MYIOC_s_INFO_FMT "ScsiLookup @ %p\n", ioc->name, hd->ScsiLookup)); - /* Allocate memory for the device structures. - * A non-Null pointer at an offset - * indicates a device exists. - * max_id = 1 + maximum id (hosts.h) - */ - hd->Targets = kcalloc(sh->max_id * (sh->max_channel + 1), - sizeof(void *), GFP_ATOMIC); - if (!hd->Targets) { - error = -ENOMEM; - goto out_mptspi_probe; - } - - dprintk((KERN_INFO " vdev @ %p\n", hd->Targets)); - /* Clear the TM flags */ hd->tmPending = 0; diff --git a/drivers/message/i2o/i2o_config.c b/drivers/message/i2o/i2o_config.c index e33d446..8ba275a 100644 --- a/drivers/message/i2o/i2o_config.c +++ b/drivers/message/i2o/i2o_config.c @@ -1111,7 +1111,7 @@ static int cfg_release(struct inode *ino return 0; } -static struct file_operations config_fops = { +static const struct file_operations config_fops = { .owner = THIS_MODULE, .llseek = no_llseek, .ioctl = i2o_cfg_ioctl, diff --git a/drivers/message/i2o/i2o_proc.c b/drivers/message/i2o/i2o_proc.c index a61cb17..06892ac 100644 --- a/drivers/message/i2o/i2o_proc.c +++ b/drivers/message/i2o/i2o_proc.c @@ -1703,133 +1703,133 @@ static int i2o_seq_open_dev_name(struct return single_open(file, i2o_seq_show_dev_name, PDE(inode)->data); }; -static struct file_operations i2o_seq_fops_lct = { +static const struct file_operations i2o_seq_fops_lct = { .open = i2o_seq_open_lct, .read = seq_read, .llseek = seq_lseek, .release = single_release, }; -static struct file_operations i2o_seq_fops_hrt = { +static const struct file_operations i2o_seq_fops_hrt = { .open = i2o_seq_open_hrt, .read = seq_read, .llseek = seq_lseek, .release = single_release, }; -static struct file_operations i2o_seq_fops_status = { +static const struct file_operations i2o_seq_fops_status = { .open = i2o_seq_open_status, .read = seq_read, .llseek = seq_lseek, .release = single_release, }; -static struct file_operations i2o_seq_fops_hw = { +static const struct file_operations i2o_seq_fops_hw = { .open = i2o_seq_open_hw, .read = seq_read, .llseek = seq_lseek, .release = single_release, }; -static struct file_operations i2o_seq_fops_ddm_table = { +static const struct file_operations i2o_seq_fops_ddm_table = { .open = i2o_seq_open_ddm_table, .read = seq_read, .llseek = seq_lseek, .release = single_release, }; -static struct file_operations i2o_seq_fops_driver_store = { +static const struct file_operations i2o_seq_fops_driver_store = { .open = i2o_seq_open_driver_store, .read = seq_read, .llseek = seq_lseek, .release = single_release, }; -static struct file_operations i2o_seq_fops_drivers_stored = { +static const struct file_operations i2o_seq_fops_drivers_stored = { .open = i2o_seq_open_drivers_stored, .read = seq_read, .llseek = seq_lseek, .release = single_release, }; -static struct file_operations i2o_seq_fops_groups = { +static const struct file_operations i2o_seq_fops_groups = { .open = i2o_seq_open_groups, .read = seq_read, .llseek = seq_lseek, .release = single_release, }; -static struct file_operations i2o_seq_fops_phys_device = { +static const struct file_operations i2o_seq_fops_phys_device = { .open = i2o_seq_open_phys_device, .read = seq_read, .llseek = seq_lseek, .release = single_release, }; -static struct file_operations i2o_seq_fops_claimed = { +static const struct file_operations i2o_seq_fops_claimed = { .open = i2o_seq_open_claimed, .read = seq_read, .llseek = seq_lseek, .release = single_release, }; -static struct file_operations i2o_seq_fops_users = { +static const struct file_operations i2o_seq_fops_users = { .open = i2o_seq_open_users, .read = seq_read, .llseek = seq_lseek, .release = single_release, }; -static struct file_operations i2o_seq_fops_priv_msgs = { +static const struct file_operations i2o_seq_fops_priv_msgs = { .open = i2o_seq_open_priv_msgs, .read = seq_read, .llseek = seq_lseek, .release = single_release, }; -static struct file_operations i2o_seq_fops_authorized_users = { +static const struct file_operations i2o_seq_fops_authorized_users = { .open = i2o_seq_open_authorized_users, .read = seq_read, .llseek = seq_lseek, .release = single_release, }; -static struct file_operations i2o_seq_fops_dev_name = { +static const struct file_operations i2o_seq_fops_dev_name = { .open = i2o_seq_open_dev_name, .read = seq_read, .llseek = seq_lseek, .release = single_release, }; -static struct file_operations i2o_seq_fops_dev_identity = { +static const struct file_operations i2o_seq_fops_dev_identity = { .open = i2o_seq_open_dev_identity, .read = seq_read, .llseek = seq_lseek, .release = single_release, }; -static struct file_operations i2o_seq_fops_ddm_identity = { +static const struct file_operations i2o_seq_fops_ddm_identity = { .open = i2o_seq_open_ddm_identity, .read = seq_read, .llseek = seq_lseek, .release = single_release, }; -static struct file_operations i2o_seq_fops_uinfo = { +static const struct file_operations i2o_seq_fops_uinfo = { .open = i2o_seq_open_uinfo, .read = seq_read, .llseek = seq_lseek, .release = single_release, }; -static struct file_operations i2o_seq_fops_sgl_limits = { +static const struct file_operations i2o_seq_fops_sgl_limits = { .open = i2o_seq_open_sgl_limits, .read = seq_read, .llseek = seq_lseek, .release = single_release, }; -static struct file_operations i2o_seq_fops_sensors = { +static const struct file_operations i2o_seq_fops_sensors = { .open = i2o_seq_open_sensors, .read = seq_read, .llseek = seq_lseek, diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig index 00db31c..bedae4a 100644 --- a/drivers/misc/Kconfig +++ b/drivers/misc/Kconfig @@ -42,7 +42,7 @@ config SGI_IOC4 config TIFM_CORE tristate "TI Flash Media interface support (EXPERIMENTAL)" - depends on EXPERIMENTAL + depends on EXPERIMENTAL && PCI help If you want support for Texas Instruments(R) Flash Media adapters you should select this option and then also choose an appropriate @@ -69,6 +69,25 @@ config TIFM_7XX1 To compile this driver as a module, choose M here: the module will be called tifm_7xx1. +config ASUS_LAPTOP + tristate "Asus Laptop Extras (EXPERIMENTAL)" + depends on X86 + depends on ACPI + depends on EXPERIMENTAL && !ACPI_ASUS + depends on LEDS_CLASS + depends on BACKLIGHT_CLASS_DEVICE + ---help--- + This is the new Linux driver for Asus laptops. It may also support some + MEDION, JVC or VICTOR laptops. It makes all the extra buttons generate + standard ACPI events that go through /proc/acpi/events. It also adds + support for video output switching, LCD backlight control, Bluetooth and + Wlan control, and most importantly, allows you to blink those fancy LEDs. + + For more information and a userspace daemon for handling the extra + buttons see . + + If you have an ACPI-compatible ASUS laptop, say Y or M here. + config MSI_LAPTOP tristate "MSI Laptop Extras" depends on X86 diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile index c9e98ab..35da53c 100644 --- a/drivers/misc/Makefile +++ b/drivers/misc/Makefile @@ -6,6 +6,7 @@ obj- := misc.o # Dummy rule to force bui obj-$(CONFIG_IBM_ASM) += ibmasm/ obj-$(CONFIG_HDPU_FEATURES) += hdpuftrs/ obj-$(CONFIG_MSI_LAPTOP) += msi-laptop.o +obj-$(CONFIG_ASUS_LAPTOP) += asus-laptop.o obj-$(CONFIG_LKDTM) += lkdtm.o obj-$(CONFIG_TIFM_CORE) += tifm_core.o obj-$(CONFIG_TIFM_7XX1) += tifm_7xx1.o diff --git a/drivers/misc/asus-laptop.c b/drivers/misc/asus-laptop.c new file mode 100644 index 0000000..861c399 --- /dev/null +++ b/drivers/misc/asus-laptop.c @@ -0,0 +1,1165 @@ +/* + * asus-laptop.c - Asus Laptop Support + * + * + * Copyright (C) 2002-2005 Julien Lerouge, 2003-2006 Karol Kozimor + * Copyright (C) 2006 Corentin Chary + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * + * The development page for this driver is located at + * http://sourceforge.net/projects/acpi4asus/ + * + * Credits: + * Pontus Fuchs - Helper functions, cleanup + * Johann Wiesner - Small compile fixes + * John Belmonte - ACPI code for Toshiba laptop was a good starting point. + * Eric Burghard - LED display support for W1N + * Josh Green - Light Sens support + * Thomas Tuttle - His first patch for led support was very helpfull + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define ASUS_LAPTOP_VERSION "0.40" + +#define ASUS_HOTK_NAME "Asus Laptop Support" +#define ASUS_HOTK_CLASS "hotkey" +#define ASUS_HOTK_DEVICE_NAME "Hotkey" +#define ASUS_HOTK_HID "ATK0100" +#define ASUS_HOTK_FILE "asus-laptop" +#define ASUS_HOTK_PREFIX "\\_SB.ATKD." + +/* + * Some events we use, same for all Asus + */ +#define ATKD_BR_UP 0x10 +#define ATKD_BR_DOWN 0x20 +#define ATKD_LCD_ON 0x33 +#define ATKD_LCD_OFF 0x34 + +/* + * Known bits returned by \_SB.ATKD.HWRS + */ +#define WL_HWRS 0x80 +#define BT_HWRS 0x100 + +/* + * Flags for hotk status + * WL_ON and BT_ON are also used for wireless_status() + */ +#define WL_ON 0x01 //internal Wifi +#define BT_ON 0x02 //internal Bluetooth +#define MLED_ON 0x04 //mail LED +#define TLED_ON 0x08 //touchpad LED +#define RLED_ON 0x10 //Record LED +#define PLED_ON 0x20 //Phone LED +#define LCD_ON 0x40 //LCD backlight + +#define ASUS_LOG ASUS_HOTK_FILE ": " +#define ASUS_ERR KERN_ERR ASUS_LOG +#define ASUS_WARNING KERN_WARNING ASUS_LOG +#define ASUS_NOTICE KERN_NOTICE ASUS_LOG +#define ASUS_INFO KERN_INFO ASUS_LOG +#define ASUS_DEBUG KERN_DEBUG ASUS_LOG + +MODULE_AUTHOR("Julien Lerouge, Karol Kozimor, Corentin Chary"); +MODULE_DESCRIPTION(ASUS_HOTK_NAME); +MODULE_LICENSE("GPL"); + +#define ASUS_HANDLE(object, paths...) \ + static acpi_handle object##_handle = NULL; \ + static char *object##_paths[] = { paths } + +/* LED */ +ASUS_HANDLE(mled_set, ASUS_HOTK_PREFIX "MLED"); +ASUS_HANDLE(tled_set, ASUS_HOTK_PREFIX "TLED"); +ASUS_HANDLE(rled_set, ASUS_HOTK_PREFIX "RLED"); /* W1JC */ +ASUS_HANDLE(pled_set, ASUS_HOTK_PREFIX "PLED"); /* A7J */ + +/* LEDD */ +ASUS_HANDLE(ledd_set, ASUS_HOTK_PREFIX "SLCM"); + +/* Bluetooth and WLAN + * WLED and BLED are not handled like other XLED, because in some dsdt + * they also control the WLAN/Bluetooth device. + */ +ASUS_HANDLE(wl_switch, ASUS_HOTK_PREFIX "WLED"); +ASUS_HANDLE(bt_switch, ASUS_HOTK_PREFIX "BLED"); +ASUS_HANDLE(wireless_status, ASUS_HOTK_PREFIX "RSTS"); /* All new models */ + +/* Brightness */ +ASUS_HANDLE(brightness_set, ASUS_HOTK_PREFIX "SPLV"); +ASUS_HANDLE(brightness_get, ASUS_HOTK_PREFIX "GPLV"); + +/* Backlight */ +ASUS_HANDLE(lcd_switch, "\\_SB.PCI0.SBRG.EC0._Q10", /* All new models */ + "\\_SB.PCI0.ISA.EC0._Q10", /* A1x */ + "\\_SB.PCI0.PX40.ECD0._Q10", /* L3C */ + "\\_SB.PCI0.PX40.EC0.Q10", /* M1A */ + "\\_SB.PCI0.LPCB.EC0._Q10", /* P30 */ + "\\_SB.PCI0.PX40.Q10", /* S1x */ + "\\Q10"); /* A2x, L2D, L3D, M2E */ + +/* Display */ +ASUS_HANDLE(display_set, ASUS_HOTK_PREFIX "SDSP"); +ASUS_HANDLE(display_get, "\\_SB.PCI0.P0P1.VGA.GETD", /* A6B, A6K A6R A7D F3JM L4R M6R A3G + M6A M6V VX-1 V6J V6V W3Z */ + "\\_SB.PCI0.P0P2.VGA.GETD", /* A3E A4K, A4D A4L A6J A7J A8J Z71V M9V + S5A M5A z33A W1Jc W2V */ + "\\_SB.PCI0.P0P3.VGA.GETD", /* A6V A6Q */ + "\\_SB.PCI0.P0PA.VGA.GETD", /* A6T, A6M */ + "\\_SB.PCI0.PCI1.VGAC.NMAP", /* L3C */ + "\\_SB.PCI0.VGA.GETD", /* Z96F */ + "\\ACTD", /* A2D */ + "\\ADVG", /* A4G Z71A W1N W5A W5F M2N M3N M5N M6N S1N S5N */ + "\\DNXT", /* P30 */ + "\\INFB", /* A2H D1 L2D L3D L3H L2E L5D L5C M1A M2E L4L W3V */ + "\\SSTE"); /* A3F A6F A3N A3L M6N W3N W6A */ + +ASUS_HANDLE(ls_switch, ASUS_HOTK_PREFIX "ALSC"); /* Z71A Z71V */ +ASUS_HANDLE(ls_level, ASUS_HOTK_PREFIX "ALSL"); /* Z71A Z71V */ + +/* + * This is the main structure, we can use it to store anything interesting + * about the hotk device + */ +struct asus_hotk { + char *name; //laptop name + struct acpi_device *device; //the device we are in + acpi_handle handle; //the handle of the hotk device + char status; //status of the hotk, for LEDs, ... + u32 ledd_status; //status of the LED display + u8 light_level; //light sensor level + u8 light_switch; //light sensor switch value + u16 event_count[128]; //count for each event TODO make this better +}; + +/* + * This header is made available to allow proper configuration given model, + * revision number , ... this info cannot go in struct asus_hotk because it is + * available before the hotk + */ +static struct acpi_table_header *asus_info; + +/* The actual device the driver binds to */ +static struct asus_hotk *hotk; + +/* + * The hotkey driver declaration + */ +static int asus_hotk_add(struct acpi_device *device); +static int asus_hotk_remove(struct acpi_device *device, int type); +static struct acpi_driver asus_hotk_driver = { + .name = ASUS_HOTK_NAME, + .class = ASUS_HOTK_CLASS, + .ids = ASUS_HOTK_HID, + .ops = { + .add = asus_hotk_add, + .remove = asus_hotk_remove, + }, +}; + +/* The backlight device /sys/class/backlight */ +static struct backlight_device *asus_backlight_device; + +/* + * The backlight class declaration + */ +static int read_brightness(struct backlight_device *bd); +static int update_bl_status(struct backlight_device *bd); +static struct backlight_properties asusbl_data = { + .owner = THIS_MODULE, + .get_brightness = read_brightness, + .update_status = update_bl_status, + .max_brightness = 15, +}; + +/* These functions actually update the LED's, and are called from a + * workqueue. By doing this as separate work rather than when the LED + * subsystem asks, we avoid messing with the Asus ACPI stuff during a + * potentially bad time, such as a timer interrupt. */ +static struct workqueue_struct *led_workqueue; + +#define ASUS_LED(object, ledname) \ + static void object##_led_set(struct led_classdev *led_cdev, \ + enum led_brightness value); \ + static void object##_led_update(struct work_struct *ignored); \ + static int object##_led_wk; \ + DECLARE_WORK(object##_led_work, object##_led_update); \ + static struct led_classdev object##_led = { \ + .name = "asus:" ledname, \ + .brightness_set = object##_led_set, \ + } + +ASUS_LED(mled, "mail"); +ASUS_LED(tled, "touchpad"); +ASUS_LED(rled, "record"); +ASUS_LED(pled, "phone"); + +/* + * This function evaluates an ACPI method, given an int as parameter, the + * method is searched within the scope of the handle, can be NULL. The output + * of the method is written is output, which can also be NULL + * + * returns 1 if write is successful, 0 else. + */ +static int write_acpi_int(acpi_handle handle, const char *method, int val, + struct acpi_buffer *output) +{ + struct acpi_object_list params; //list of input parameters (an int here) + union acpi_object in_obj; //the only param we use + acpi_status status; + + params.count = 1; + params.pointer = &in_obj; + in_obj.type = ACPI_TYPE_INTEGER; + in_obj.integer.value = val; + + status = acpi_evaluate_object(handle, (char *)method, ¶ms, output); + return (status == AE_OK); +} + +static int read_acpi_int(acpi_handle handle, const char *method, int *val, + struct acpi_object_list *params) +{ + struct acpi_buffer output; + union acpi_object out_obj; + acpi_status status; + + output.length = sizeof(out_obj); + output.pointer = &out_obj; + + status = acpi_evaluate_object(handle, (char *)method, params, &output); + *val = out_obj.integer.value; + return (status == AE_OK) && (out_obj.type == ACPI_TYPE_INTEGER); +} + +static int read_wireless_status(int mask) +{ + int status; + + if (!wireless_status_handle) + return (hotk->status & mask) ? 1 : 0; + + if (read_acpi_int(wireless_status_handle, NULL, &status, NULL)) { + return (status & mask) ? 1 : 0; + } else + printk(ASUS_WARNING "Error reading Wireless status\n"); + + return (hotk->status & mask) ? 1 : 0; +} + +/* Generic LED functions */ +static int read_status(int mask) +{ + /* There is a special method for both wireless devices */ + if (mask == BT_ON || mask == WL_ON) + return read_wireless_status(mask); + + return (hotk->status & mask) ? 1 : 0; +} + +static void write_status(acpi_handle handle, int out, int mask, int invert) +{ + hotk->status = (out) ? (hotk->status | mask) : (hotk->status & ~mask); + + if (invert) /* invert target value */ + out = !out & 0x1; + + if (handle && !write_acpi_int(handle, NULL, out, NULL)) + printk(ASUS_WARNING " write failed\n"); +} + +/* /sys/class/led handlers */ +#define ASUS_LED_HANDLER(object, mask, invert) \ + static void object##_led_set(struct led_classdev *led_cdev, \ + enum led_brightness value) \ + { \ + object##_led_wk = value; \ + queue_work(led_workqueue, &object##_led_work); \ + } \ + static void object##_led_update(struct work_struct *ignored) \ + { \ + int value = object##_led_wk; \ + write_status(object##_set_handle, value, (mask), (invert)); \ + } + +ASUS_LED_HANDLER(mled, MLED_ON, 1); +ASUS_LED_HANDLER(pled, PLED_ON, 0); +ASUS_LED_HANDLER(rled, RLED_ON, 0); +ASUS_LED_HANDLER(tled, TLED_ON, 0); + +static int get_lcd_state(void) +{ + return read_status(LCD_ON); +} + +static int set_lcd_state(int value) +{ + int lcd = 0; + acpi_status status = 0; + + lcd = value ? 1 : 0; + + if (lcd == get_lcd_state()) + return 0; + + if (lcd_switch_handle) { + status = acpi_evaluate_object(lcd_switch_handle, + NULL, NULL, NULL); + + if (ACPI_FAILURE(status)) + printk(ASUS_WARNING "Error switching LCD\n"); + } + + write_status(NULL, lcd, LCD_ON, 0); + return 0; +} + +static void lcd_blank(int blank) +{ + struct backlight_device *bd = asus_backlight_device; + + if (bd) { + down(&bd->sem); + if (likely(bd->props)) { + bd->props->power = blank; + if (likely(bd->props->update_status)) + bd->props->update_status(bd); + } + up(&bd->sem); + } +} + +static int read_brightness(struct backlight_device *bd) +{ + int value; + + if (!read_acpi_int(brightness_get_handle, NULL, &value, NULL)) + printk(ASUS_WARNING "Error reading brightness\n"); + + return value; +} + +static int set_brightness(struct backlight_device *bd, int value) +{ + int ret = 0; + + value = (0 < value) ? ((15 < value) ? 15 : value) : 0; + /* 0 <= value <= 15 */ + + if (!write_acpi_int(brightness_set_handle, NULL, value, NULL)) { + printk(ASUS_WARNING "Error changing brightness\n"); + ret = -EIO; + } + + return ret; +} + +static int update_bl_status(struct backlight_device *bd) +{ + int rv; + int value = bd->props->brightness; + + rv = set_brightness(bd, value); + if (rv) + return rv; + + value = (bd->props->power == FB_BLANK_UNBLANK) ? 1 : 0; + return set_lcd_state(value); +} + +/* + * Platform device handlers + */ + +/* + * We write our info in page, we begin at offset off and cannot write more + * than count bytes. We set eof to 1 if we handle those 2 values. We return the + * number of bytes written in page + */ +static ssize_t show_infos(struct device *dev, + struct device_attribute *attr, char *page) +{ + int len = 0; + int temp; + char buf[16]; //enough for all info + /* + * We use the easy way, we don't care of off and count, so we don't set eof + * to 1 + */ + + len += sprintf(page, ASUS_HOTK_NAME " " ASUS_LAPTOP_VERSION "\n"); + len += sprintf(page + len, "Model reference : %s\n", hotk->name); + /* + * The SFUN method probably allows the original driver to get the list + * of features supported by a given model. For now, 0x0100 or 0x0800 + * bit signifies that the laptop is equipped with a Wi-Fi MiniPCI card. + * The significance of others is yet to be found. + */ + if (read_acpi_int(hotk->handle, "SFUN", &temp, NULL)) + len += + sprintf(page + len, "SFUN value : 0x%04x\n", temp); + /* + * Another value for userspace: the ASYM method returns 0x02 for + * battery low and 0x04 for battery critical, its readings tend to be + * more accurate than those provided by _BST. + * Note: since not all the laptops provide this method, errors are + * silently ignored. + */ + if (read_acpi_int(hotk->handle, "ASYM", &temp, NULL)) + len += + sprintf(page + len, "ASYM value : 0x%04x\n", temp); + if (asus_info) { + snprintf(buf, 16, "%d", asus_info->length); + len += sprintf(page + len, "DSDT length : %s\n", buf); + snprintf(buf, 16, "%d", asus_info->checksum); + len += sprintf(page + len, "DSDT checksum : %s\n", buf); + snprintf(buf, 16, "%d", asus_info->revision); + len += sprintf(page + len, "DSDT revision : %s\n", buf); + snprintf(buf, 7, "%s", asus_info->oem_id); + len += sprintf(page + len, "OEM id : %s\n", buf); + snprintf(buf, 9, "%s", asus_info->oem_table_id); + len += sprintf(page + len, "OEM table id : %s\n", buf); + snprintf(buf, 16, "%x", asus_info->oem_revision); + len += sprintf(page + len, "OEM revision : 0x%s\n", buf); + snprintf(buf, 5, "%s", asus_info->asl_compiler_id); + len += sprintf(page + len, "ASL comp vendor id : %s\n", buf); + snprintf(buf, 16, "%x", asus_info->asl_compiler_revision); + len += sprintf(page + len, "ASL comp revision : 0x%s\n", buf); + } + + return len; +} + +static int parse_arg(const char *buf, unsigned long count, int *val) +{ + if (!count) + return 0; + if (count > 31) + return -EINVAL; + if (sscanf(buf, "%i", val) != 1) + return -EINVAL; + return count; +} + +static ssize_t store_status(const char *buf, size_t count, + acpi_handle handle, int mask, int invert) +{ + int rv, value; + int out = 0; + + rv = parse_arg(buf, count, &value); + if (rv > 0) + out = value ? 1 : 0; + + write_status(handle, out, mask, invert); + + return rv; +} + +/* + * LEDD display + */ +static ssize_t show_ledd(struct device *dev, + struct device_attribute *attr, char *buf) +{ + return sprintf(buf, "0x%08x\n", hotk->ledd_status); +} + +static ssize_t store_ledd(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) +{ + int rv, value; + + rv = parse_arg(buf, count, &value); + if (rv > 0) { + if (!write_acpi_int(ledd_set_handle, NULL, value, NULL)) + printk(ASUS_WARNING "LED display write failed\n"); + else + hotk->ledd_status = (u32) value; + } + return rv; +} + +/* + * WLAN + */ +static ssize_t show_wlan(struct device *dev, + struct device_attribute *attr, char *buf) +{ + return sprintf(buf, "%d\n", read_status(WL_ON)); +} + +static ssize_t store_wlan(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) +{ + return store_status(buf, count, wl_switch_handle, WL_ON, 0); +} + +/* + * Bluetooth + */ +static ssize_t show_bluetooth(struct device *dev, + struct device_attribute *attr, char *buf) +{ + return sprintf(buf, "%d\n", read_status(BT_ON)); +} + +static ssize_t store_bluetooth(struct device *dev, + struct device_attribute *attr, const char *buf, + size_t count) +{ + return store_status(buf, count, bt_switch_handle, BT_ON, 0); +} + +/* + * Display + */ +static void set_display(int value) +{ + /* no sanity check needed for now */ + if (!write_acpi_int(display_set_handle, NULL, value, NULL)) + printk(ASUS_WARNING "Error setting display\n"); + return; +} + +static int read_display(void) +{ + int value = 0; + + /* In most of the case, we know how to set the display, but sometime + we can't read it */ + if (display_get_handle) { + if (!read_acpi_int(display_get_handle, NULL, &value, NULL)) + printk(ASUS_WARNING "Error reading display status\n"); + } + + value &= 0x0F; /* needed for some models, shouldn't hurt others */ + + return value; +} + +/* + * Now, *this* one could be more user-friendly, but so far, no-one has + * complained. The significance of bits is the same as in store_disp() + */ +static ssize_t show_disp(struct device *dev, + struct device_attribute *attr, char *buf) +{ + return sprintf(buf, "%d\n", read_display()); +} + +/* + * Experimental support for display switching. As of now: 1 should activate + * the LCD output, 2 should do for CRT, 4 for TV-Out and 8 for DVI. + * Any combination (bitwise) of these will suffice. I never actually tested 4 + * displays hooked up simultaneously, so be warned. See the acpi4asus README + * for more info. + */ +static ssize_t store_disp(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) +{ + int rv, value; + + rv = parse_arg(buf, count, &value); + if (rv > 0) + set_display(value); + return rv; +} + +/* + * Light Sens + */ +static void set_light_sens_switch(int value) +{ + if (!write_acpi_int(ls_switch_handle, NULL, value, NULL)) + printk(ASUS_WARNING "Error setting light sensor switch\n"); + hotk->light_switch = value; +} + +static ssize_t show_lssw(struct device *dev, + struct device_attribute *attr, char *buf) +{ + return sprintf(buf, "%d\n", hotk->light_switch); +} + +static ssize_t store_lssw(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) +{ + int rv, value; + + rv = parse_arg(buf, count, &value); + if (rv > 0) + set_light_sens_switch(value ? 1 : 0); + + return rv; +} + +static void set_light_sens_level(int value) +{ + if (!write_acpi_int(ls_level_handle, NULL, value, NULL)) + printk(ASUS_WARNING "Error setting light sensor level\n"); + hotk->light_level = value; +} + +static ssize_t show_lslvl(struct device *dev, + struct device_attribute *attr, char *buf) +{ + return sprintf(buf, "%d\n", hotk->light_level); +} + +static ssize_t store_lslvl(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) +{ + int rv, value; + + rv = parse_arg(buf, count, &value); + if (rv > 0) { + value = (0 < value) ? ((15 < value) ? 15 : value) : 0; + /* 0 <= value <= 15 */ + set_light_sens_level(value); + } + + return rv; +} + +static void asus_hotk_notify(acpi_handle handle, u32 event, void *data) +{ + /* TODO Find a better way to handle events count. */ + if (!hotk) + return; + + /* + * We need to tell the backlight device when the backlight power is + * switched + */ + if (event == ATKD_LCD_ON) { + write_status(NULL, 1, LCD_ON, 0); + lcd_blank(FB_BLANK_UNBLANK); + } else if (event == ATKD_LCD_OFF) { + write_status(NULL, 0, LCD_ON, 0); + lcd_blank(FB_BLANK_POWERDOWN); + } + + acpi_bus_generate_event(hotk->device, event, + hotk->event_count[event % 128]++); + + return; +} + +#define ASUS_CREATE_DEVICE_ATTR(_name) \ + struct device_attribute dev_attr_##_name = { \ + .attr = { \ + .name = __stringify(_name), \ + .mode = 0, \ + .owner = THIS_MODULE }, \ + .show = NULL, \ + .store = NULL, \ + } + +#define ASUS_SET_DEVICE_ATTR(_name, _mode, _show, _store) \ + do { \ + dev_attr_##_name.attr.mode = _mode; \ + dev_attr_##_name.show = _show; \ + dev_attr_##_name.store = _store; \ + } while(0) + +static ASUS_CREATE_DEVICE_ATTR(infos); +static ASUS_CREATE_DEVICE_ATTR(wlan); +static ASUS_CREATE_DEVICE_ATTR(bluetooth); +static ASUS_CREATE_DEVICE_ATTR(display); +static ASUS_CREATE_DEVICE_ATTR(ledd); +static ASUS_CREATE_DEVICE_ATTR(ls_switch); +static ASUS_CREATE_DEVICE_ATTR(ls_level); + +static struct attribute *asuspf_attributes[] = { + &dev_attr_infos.attr, + &dev_attr_wlan.attr, + &dev_attr_bluetooth.attr, + &dev_attr_display.attr, + &dev_attr_ledd.attr, + &dev_attr_ls_switch.attr, + &dev_attr_ls_level.attr, + NULL +}; + +static struct attribute_group asuspf_attribute_group = { + .attrs = asuspf_attributes +}; + +static struct platform_driver asuspf_driver = { + .driver = { + .name = ASUS_HOTK_FILE, + .owner = THIS_MODULE, + } +}; + +static struct platform_device *asuspf_device; + +static void asus_hotk_add_fs(void) +{ + ASUS_SET_DEVICE_ATTR(infos, 0444, show_infos, NULL); + + if (wl_switch_handle) + ASUS_SET_DEVICE_ATTR(wlan, 0644, show_wlan, store_wlan); + + if (bt_switch_handle) + ASUS_SET_DEVICE_ATTR(bluetooth, 0644, + show_bluetooth, store_bluetooth); + + if (display_set_handle && display_get_handle) + ASUS_SET_DEVICE_ATTR(display, 0644, show_disp, store_disp); + else if (display_set_handle) + ASUS_SET_DEVICE_ATTR(display, 0200, NULL, store_disp); + + if (ledd_set_handle) + ASUS_SET_DEVICE_ATTR(ledd, 0644, show_ledd, store_ledd); + + if (ls_switch_handle && ls_level_handle) { + ASUS_SET_DEVICE_ATTR(ls_level, 0644, show_lslvl, store_lslvl); + ASUS_SET_DEVICE_ATTR(ls_switch, 0644, show_lssw, store_lssw); + } +} + +static int asus_handle_init(char *name, acpi_handle * handle, + char **paths, int num_paths) +{ + int i; + acpi_status status; + + for (i = 0; i < num_paths; i++) { + status = acpi_get_handle(NULL, paths[i], handle); + if (ACPI_SUCCESS(status)) + return 0; + } + + *handle = NULL; + return -ENODEV; +} + +#define ASUS_HANDLE_INIT(object) \ + asus_handle_init(#object, &object##_handle, object##_paths, \ + ARRAY_SIZE(object##_paths)) + +/* + * This function is used to initialize the hotk with right values. In this + * method, we can make all the detection we want, and modify the hotk struct + */ +static int asus_hotk_get_info(void) +{ + struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL }; + union acpi_object *model = NULL; + int bsts_result, hwrs_result; + char *string = NULL; + acpi_status status; + + /* + * Get DSDT headers early enough to allow for differentiating between + * models, but late enough to allow acpi_bus_register_driver() to fail + * before doing anything ACPI-specific. Should we encounter a machine, + * which needs special handling (i.e. its hotkey device has a different + * HID), this bit will be moved. A global variable asus_info contains + * the DSDT header. + */ + status = acpi_get_table(ACPI_SIG_DSDT, 1, &asus_info); + if (ACPI_FAILURE(status)) + printk(ASUS_WARNING "Couldn't get the DSDT table header\n"); + + /* We have to write 0 on init this far for all ASUS models */ + if (!write_acpi_int(hotk->handle, "INIT", 0, &buffer)) { + printk(ASUS_ERR "Hotkey initialization failed\n"); + return -ENODEV; + } + + /* This needs to be called for some laptops to init properly */ + if (!read_acpi_int(hotk->handle, "BSTS", &bsts_result, NULL)) + printk(ASUS_WARNING "Error calling BSTS\n"); + else if (bsts_result) + printk(ASUS_NOTICE "BSTS called, 0x%02x returned\n", + bsts_result); + + /* + * Try to match the object returned by INIT to the specific model. + * Handle every possible object (or the lack of thereof) the DSDT + * writers might throw at us. When in trouble, we pass NULL to + * asus_model_match() and try something completely different. + */ + if (buffer.pointer) { + model = buffer.pointer; + switch (model->type) { + case ACPI_TYPE_STRING: + string = model->string.pointer; + break; + case ACPI_TYPE_BUFFER: + string = model->buffer.pointer; + break; + default: + string = ""; + break; + } + } + hotk->name = kstrdup(string, GFP_KERNEL); + if (!hotk->name) + return -ENOMEM; + + if (*string) + printk(ASUS_NOTICE " %s model detected\n", string); + + ASUS_HANDLE_INIT(mled_set); + ASUS_HANDLE_INIT(tled_set); + ASUS_HANDLE_INIT(rled_set); + ASUS_HANDLE_INIT(pled_set); + + ASUS_HANDLE_INIT(ledd_set); + + /* + * The HWRS method return informations about the hardware. + * 0x80 bit is for WLAN, 0x100 for Bluetooth. + * The significance of others is yet to be found. + * If we don't find the method, we assume the device are present. + */ + if (!read_acpi_int(hotk->handle, "HRWS", &hwrs_result, NULL)) + hwrs_result = WL_HWRS | BT_HWRS; + + if (hwrs_result & WL_HWRS) + ASUS_HANDLE_INIT(wl_switch); + if (hwrs_result & BT_HWRS) + ASUS_HANDLE_INIT(bt_switch); + + ASUS_HANDLE_INIT(wireless_status); + + ASUS_HANDLE_INIT(brightness_set); + ASUS_HANDLE_INIT(brightness_get); + + ASUS_HANDLE_INIT(lcd_switch); + + ASUS_HANDLE_INIT(display_set); + ASUS_HANDLE_INIT(display_get); + + /* There is a lot of models with "ALSL", but a few get + a real light sens, so we need to check it. */ + if (ASUS_HANDLE_INIT(ls_switch)) + ASUS_HANDLE_INIT(ls_level); + + kfree(model); + + return AE_OK; +} + +static int asus_hotk_check(void) +{ + int result = 0; + + result = acpi_bus_get_status(hotk->device); + if (result) + return result; + + if (hotk->device->status.present) { + result = asus_hotk_get_info(); + } else { + printk(ASUS_ERR "Hotkey device not present, aborting\n"); + return -EINVAL; + } + + return result; +} + +static int asus_hotk_found; + +static int asus_hotk_add(struct acpi_device *device) +{ + acpi_status status = AE_OK; + int result; + + if (!device) + return -EINVAL; + + printk(ASUS_NOTICE "Asus Laptop Support version %s\n", + ASUS_LAPTOP_VERSION); + + hotk = kmalloc(sizeof(struct asus_hotk), GFP_KERNEL); + if (!hotk) + return -ENOMEM; + memset(hotk, 0, sizeof(struct asus_hotk)); + + hotk->handle = device->handle; + strcpy(acpi_device_name(device), ASUS_HOTK_DEVICE_NAME); + strcpy(acpi_device_class(device), ASUS_HOTK_CLASS); + acpi_driver_data(device) = hotk; + hotk->device = device; + + result = asus_hotk_check(); + if (result) + goto end; + + asus_hotk_add_fs(); + + /* + * We install the handler, it will receive the hotk in parameter, so, we + * could add other data to the hotk struct + */ + status = acpi_install_notify_handler(hotk->handle, ACPI_SYSTEM_NOTIFY, + asus_hotk_notify, hotk); + if (ACPI_FAILURE(status)) + printk(ASUS_ERR "Error installing notify handler\n"); + + asus_hotk_found = 1; + + /* WLED and BLED are on by default */ + write_status(bt_switch_handle, 1, BT_ON, 0); + write_status(wl_switch_handle, 1, WL_ON, 0); + + /* LCD Backlight is on by default */ + write_status(NULL, 1, LCD_ON, 0); + + /* LED display is off by default */ + hotk->ledd_status = 0xFFF; + + /* Set initial values of light sensor and level */ + hotk->light_switch = 1; /* Default to light sensor disabled */ + hotk->light_level = 0; /* level 5 for sensor sensitivity */ + + if (ls_switch_handle) + set_light_sens_switch(hotk->light_switch); + + if (ls_level_handle) + set_light_sens_level(hotk->light_level); + + end: + if (result) { + kfree(hotk->name); + kfree(hotk); + } + + return result; +} + +static int asus_hotk_remove(struct acpi_device *device, int type) +{ + acpi_status status = 0; + + if (!device || !acpi_driver_data(device)) + return -EINVAL; + + status = acpi_remove_notify_handler(hotk->handle, ACPI_SYSTEM_NOTIFY, + asus_hotk_notify); + if (ACPI_FAILURE(status)) + printk(ASUS_ERR "Error removing notify handler\n"); + + kfree(hotk->name); + kfree(hotk); + + return 0; +} + +static void asus_backlight_exit(void) +{ + if (asus_backlight_device) + backlight_device_unregister(asus_backlight_device); +} + +#define ASUS_LED_UNREGISTER(object) \ + if(object##_led.class_dev \ + && !IS_ERR(object##_led.class_dev)) \ + led_classdev_unregister(&object##_led) + +static void asus_led_exit(void) +{ + ASUS_LED_UNREGISTER(mled); + ASUS_LED_UNREGISTER(tled); + ASUS_LED_UNREGISTER(pled); + ASUS_LED_UNREGISTER(rled); + + destroy_workqueue(led_workqueue); +} + +static void __exit asus_laptop_exit(void) +{ + asus_backlight_exit(); + asus_led_exit(); + + acpi_bus_unregister_driver(&asus_hotk_driver); + sysfs_remove_group(&asuspf_device->dev.kobj, &asuspf_attribute_group); + platform_device_unregister(asuspf_device); + platform_driver_unregister(&asuspf_driver); +} + +static int asus_backlight_init(struct device *dev) +{ + struct backlight_device *bd; + + if (brightness_set_handle && lcd_switch_handle) { + bd = backlight_device_register(ASUS_HOTK_FILE, dev, + NULL, &asusbl_data); + if (IS_ERR(bd)) { + printk(ASUS_ERR + "Could not register asus backlight device\n"); + asus_backlight_device = NULL; + return PTR_ERR(bd); + } + + asus_backlight_device = bd; + + down(&bd->sem); + if (likely(bd->props)) { + bd->props->brightness = read_brightness(NULL); + bd->props->power = FB_BLANK_UNBLANK; + if (likely(bd->props->update_status)) + bd->props->update_status(bd); + } + up(&bd->sem); + } + return 0; +} + +static int asus_led_register(acpi_handle handle, + struct led_classdev *ldev, struct device *dev) +{ + if (!handle) + return 0; + + return led_classdev_register(dev, ldev); +} + +#define ASUS_LED_REGISTER(object, device) \ + asus_led_register(object##_set_handle, &object##_led, device) + +static int asus_led_init(struct device *dev) +{ + int rv; + + rv = ASUS_LED_REGISTER(mled, dev); + if (rv) + return rv; + + rv = ASUS_LED_REGISTER(tled, dev); + if (rv) + return rv; + + rv = ASUS_LED_REGISTER(rled, dev); + if (rv) + return rv; + + rv = ASUS_LED_REGISTER(pled, dev); + if (rv) + return rv; + + led_workqueue = create_singlethread_workqueue("led_workqueue"); + if (!led_workqueue) + return -ENOMEM; + + return 0; +} + +static int __init asus_laptop_init(void) +{ + struct device *dev; + int result; + + if (acpi_disabled) + return -ENODEV; + + if (!acpi_specific_hotkey_enabled) { + printk(ASUS_ERR "Using generic hotkey driver\n"); + return -ENODEV; + } + + result = acpi_bus_register_driver(&asus_hotk_driver); + if (result < 0) + return result; + + /* + * This is a bit of a kludge. We only want this module loaded + * for ASUS systems, but there's currently no way to probe the + * ACPI namespace for ASUS HIDs. So we just return failure if + * we didn't find one, which will cause the module to be + * unloaded. + */ + if (!asus_hotk_found) { + acpi_bus_unregister_driver(&asus_hotk_driver); + return -ENODEV; + } + + dev = acpi_get_physical_device(hotk->device->handle); + + result = asus_backlight_init(dev); + if (result) + goto fail_backlight; + + result = asus_led_init(dev); + if (result) + goto fail_led; + + /* Register platform stuff */ + result = platform_driver_register(&asuspf_driver); + if (result) + goto fail_platform_driver; + + asuspf_device = platform_device_alloc(ASUS_HOTK_FILE, -1); + if (!asuspf_device) { + result = -ENOMEM; + goto fail_platform_device1; + } + + result = platform_device_add(asuspf_device); + if (result) + goto fail_platform_device2; + + result = sysfs_create_group(&asuspf_device->dev.kobj, + &asuspf_attribute_group); + if (result) + goto fail_sysfs; + + return 0; + + fail_sysfs: + platform_device_del(asuspf_device); + + fail_platform_device2: + platform_device_put(asuspf_device); + + fail_platform_device1: + platform_driver_unregister(&asuspf_driver); + + fail_platform_driver: + asus_led_exit(); + + fail_led: + asus_backlight_exit(); + + fail_backlight: + + return result; +} + +module_init(asus_laptop_init); +module_exit(asus_laptop_exit); diff --git a/drivers/misc/hdpuftrs/hdpu_cpustate.c b/drivers/misc/hdpuftrs/hdpu_cpustate.c index 11a801b..ca86f11 100644 --- a/drivers/misc/hdpuftrs/hdpu_cpustate.c +++ b/drivers/misc/hdpuftrs/hdpu_cpustate.c @@ -169,7 +169,7 @@ static struct platform_driver hdpu_cpust /* * The various file operations we support. */ -static struct file_operations cpustate_fops = { +static const struct file_operations cpustate_fops = { owner:THIS_MODULE, open:cpustate_open, release:cpustate_release, diff --git a/drivers/misc/hdpuftrs/hdpu_nexus.c b/drivers/misc/hdpuftrs/hdpu_nexus.c index ea9d5f2..6a51e99 100644 --- a/drivers/misc/hdpuftrs/hdpu_nexus.c +++ b/drivers/misc/hdpuftrs/hdpu_nexus.c @@ -72,11 +72,9 @@ static int hdpu_nexus_probe(struct platf printk("Could not map slot id\n"); hdpu_slot_id = create_proc_entry("sky_slot_id", 0666, &proc_root); hdpu_slot_id->read_proc = hdpu_slot_id_read; - hdpu_slot_id->nlink = 1; hdpu_chassis_id = create_proc_entry("sky_chassis_id", 0666, &proc_root); hdpu_chassis_id->read_proc = hdpu_chassis_id_read; - hdpu_chassis_id->nlink = 1; return 0; } diff --git a/drivers/misc/ibmasm/ibmasmfs.c b/drivers/misc/ibmasm/ibmasmfs.c index b99dc50..c436d3d 100644 --- a/drivers/misc/ibmasm/ibmasmfs.c +++ b/drivers/misc/ibmasm/ibmasmfs.c @@ -156,7 +156,7 @@ static struct inode *ibmasmfs_make_inode static struct dentry *ibmasmfs_create_file (struct super_block *sb, struct dentry *parent, const char *name, - struct file_operations *fops, + const struct file_operations *fops, void *data, int mode) { @@ -581,28 +581,28 @@ static ssize_t remote_settings_file_writ return count; } -static struct file_operations command_fops = { +static const struct file_operations command_fops = { .open = command_file_open, .release = command_file_close, .read = command_file_read, .write = command_file_write, }; -static struct file_operations event_fops = { +static const struct file_operations event_fops = { .open = event_file_open, .release = event_file_close, .read = event_file_read, .write = event_file_write, }; -static struct file_operations r_heartbeat_fops = { +static const struct file_operations r_heartbeat_fops = { .open = r_heartbeat_file_open, .release = r_heartbeat_file_close, .read = r_heartbeat_file_read, .write = r_heartbeat_file_write, }; -static struct file_operations remote_settings_fops = { +static const struct file_operations remote_settings_fops = { .open = remote_settings_file_open, .release = remote_settings_file_close, .read = remote_settings_file_read, diff --git a/drivers/misc/ioc4.c b/drivers/misc/ioc4.c index b995a15..6a5a05d 100644 --- a/drivers/misc/ioc4.c +++ b/drivers/misc/ioc4.c @@ -309,7 +309,7 @@ ioc4_probe(struct pci_dev *pdev, const s ret = -ENODEV; goto out_pci; } - if (!request_region(idd->idd_bar0, sizeof(struct ioc4_misc_regs), + if (!request_mem_region(idd->idd_bar0, sizeof(struct ioc4_misc_regs), "ioc4_misc")) { printk(KERN_WARNING "%s: Unable to request IOC4 misc region " @@ -379,7 +379,7 @@ ioc4_probe(struct pci_dev *pdev, const s return 0; out_misc_region: - release_region(idd->idd_bar0, sizeof(struct ioc4_misc_regs)); + release_mem_region(idd->idd_bar0, sizeof(struct ioc4_misc_regs)); out_pci: kfree(idd); out_idd: @@ -418,7 +418,7 @@ ioc4_remove(struct pci_dev *pdev) "Device removal may be incomplete.\n", __FUNCTION__, pci_name(idd->idd_pdev)); } - release_region(idd->idd_bar0, sizeof(struct ioc4_misc_regs)); + release_mem_region(idd->idd_bar0, sizeof(struct ioc4_misc_regs)); /* Disable IOC4 and relinquish */ pci_disable_device(pdev); diff --git a/drivers/misc/lkdtm.c b/drivers/misc/lkdtm.c index db9d7df..552b795 100644 --- a/drivers/misc/lkdtm.c +++ b/drivers/misc/lkdtm.c @@ -108,8 +108,8 @@ static struct jprobe lkdtm; static int lkdtm_parse_commandline(void); static void lkdtm_handler(void); -static char* cpoint_name = INVALID; -static char* cpoint_type = NONE; +static char* cpoint_name; +static char* cpoint_type; static int cpoint_count = DEFAULT_COUNT; static int recur_count = REC_NUM_DEFAULT; diff --git a/drivers/misc/tifm_7xx1.c b/drivers/misc/tifm_7xx1.c index 2ab7add..bc60e2f 100644 --- a/drivers/misc/tifm_7xx1.c +++ b/drivers/misc/tifm_7xx1.c @@ -11,66 +11,25 @@ #include #include +#include #define DRIVER_NAME "tifm_7xx1" -#define DRIVER_VERSION "0.6" +#define DRIVER_VERSION "0.7" static void tifm_7xx1_eject(struct tifm_adapter *fm, struct tifm_dev *sock) { - int cnt; - unsigned long flags; - - spin_lock_irqsave(&fm->lock, flags); - if (!fm->inhibit_new_cards) { - for (cnt = 0; cnt < fm->max_sockets; cnt++) { - if (fm->sockets[cnt] == sock) { - fm->remove_mask |= (1 << cnt); - queue_work(fm->wq, &fm->media_remover); - break; - } - } - } - spin_unlock_irqrestore(&fm->lock, flags); -} - -static void tifm_7xx1_remove_media(struct work_struct *work) -{ - struct tifm_adapter *fm = - container_of(work, struct tifm_adapter, media_remover); unsigned long flags; - int cnt; - struct tifm_dev *sock; - if (!class_device_get(&fm->cdev)) - return; spin_lock_irqsave(&fm->lock, flags); - for (cnt = 0; cnt < fm->max_sockets; cnt++) { - if (fm->sockets[cnt] && (fm->remove_mask & (1 << cnt))) { - printk(KERN_INFO DRIVER_NAME - ": demand removing card from socket %d\n", cnt); - sock = fm->sockets[cnt]; - fm->sockets[cnt] = NULL; - fm->remove_mask &= ~(1 << cnt); - - writel(0x0e00, sock->addr + SOCK_CONTROL); - - writel((TIFM_IRQ_FIFOMASK | TIFM_IRQ_CARDMASK) << cnt, - fm->addr + FM_CLEAR_INTERRUPT_ENABLE); - writel((TIFM_IRQ_FIFOMASK | TIFM_IRQ_CARDMASK) << cnt, - fm->addr + FM_SET_INTERRUPT_ENABLE); - - spin_unlock_irqrestore(&fm->lock, flags); - device_unregister(&sock->dev); - spin_lock_irqsave(&fm->lock, flags); - } - } + fm->socket_change_set |= 1 << sock->socket_id; + wake_up_all(&fm->change_set_notify); spin_unlock_irqrestore(&fm->lock, flags); - class_device_put(&fm->cdev); } static irqreturn_t tifm_7xx1_isr(int irq, void *dev_id) { struct tifm_adapter *fm = dev_id; + struct tifm_dev *sock; unsigned int irq_status; unsigned int sock_irq_status, cnt; @@ -84,42 +43,32 @@ static irqreturn_t tifm_7xx1_isr(int irq if (irq_status & TIFM_IRQ_ENABLE) { writel(TIFM_IRQ_ENABLE, fm->addr + FM_CLEAR_INTERRUPT_ENABLE); - for (cnt = 0; cnt < fm->max_sockets; cnt++) { - sock_irq_status = (irq_status >> cnt) & - (TIFM_IRQ_FIFOMASK | TIFM_IRQ_CARDMASK); - - if (fm->sockets[cnt]) { - if (sock_irq_status && - fm->sockets[cnt]->signal_irq) - sock_irq_status = fm->sockets[cnt]-> - signal_irq(fm->sockets[cnt], - sock_irq_status); + for (cnt = 0; cnt < fm->num_sockets; cnt++) { + sock = fm->sockets[cnt]; + sock_irq_status = (irq_status >> cnt) + & (TIFM_IRQ_FIFOMASK(1) + | TIFM_IRQ_CARDMASK(1)); - if (irq_status & (1 << cnt)) - fm->remove_mask |= 1 << cnt; - } else { - if (irq_status & (1 << cnt)) - fm->insert_mask |= 1 << cnt; - } + if (sock && sock_irq_status) + sock->signal_irq(sock, sock_irq_status); } + + fm->socket_change_set |= irq_status + & ((1 << fm->num_sockets) - 1); } writel(irq_status, fm->addr + FM_INTERRUPT_STATUS); - if (!fm->inhibit_new_cards) { - if (!fm->remove_mask && !fm->insert_mask) { - writel(TIFM_IRQ_ENABLE, - fm->addr + FM_SET_INTERRUPT_ENABLE); - } else { - queue_work(fm->wq, &fm->media_remover); - queue_work(fm->wq, &fm->media_inserter); - } - } + if (!fm->socket_change_set) + writel(TIFM_IRQ_ENABLE, fm->addr + FM_SET_INTERRUPT_ENABLE); + else + wake_up_all(&fm->change_set_notify); spin_unlock(&fm->lock); return IRQ_HANDLED; } -static tifm_media_id tifm_7xx1_toggle_sock_power(char __iomem *sock_addr, int is_x2) +static tifm_media_id tifm_7xx1_toggle_sock_power(char __iomem *sock_addr, + int is_x2) { unsigned int s_state; int cnt; @@ -127,8 +76,8 @@ static tifm_media_id tifm_7xx1_toggle_so writel(0x0e00, sock_addr + SOCK_CONTROL); for (cnt = 0; cnt < 100; cnt++) { - if (!(TIFM_SOCK_STATE_POWERED & - readl(sock_addr + SOCK_PRESENT_STATE))) + if (!(TIFM_SOCK_STATE_POWERED + & readl(sock_addr + SOCK_PRESENT_STATE))) break; msleep(10); } @@ -151,8 +100,8 @@ static tifm_media_id tifm_7xx1_toggle_so } for (cnt = 0; cnt < 100; cnt++) { - if ((TIFM_SOCK_STATE_POWERED & - readl(sock_addr + SOCK_PRESENT_STATE))) + if ((TIFM_SOCK_STATE_POWERED + & readl(sock_addr + SOCK_PRESENT_STATE))) break; msleep(10); } @@ -170,130 +119,209 @@ tifm_7xx1_sock_addr(char __iomem *base_a return base_addr + ((sock_num + 1) << 10); } -static void tifm_7xx1_insert_media(struct work_struct *work) +static int tifm_7xx1_switch_media(void *data) { - struct tifm_adapter *fm = - container_of(work, struct tifm_adapter, media_inserter); + struct tifm_adapter *fm = data; unsigned long flags; tifm_media_id media_id; char *card_name = "xx"; - int cnt, ok_to_register; - unsigned int insert_mask; - struct tifm_dev *new_sock = NULL; + int cnt, rc; + struct tifm_dev *sock; + unsigned int socket_change_set; - if (!class_device_get(&fm->cdev)) - return; - spin_lock_irqsave(&fm->lock, flags); - insert_mask = fm->insert_mask; - fm->insert_mask = 0; - if (fm->inhibit_new_cards) { + while (1) { + rc = wait_event_interruptible(fm->change_set_notify, + fm->socket_change_set); + if (rc == -ERESTARTSYS) + try_to_freeze(); + + spin_lock_irqsave(&fm->lock, flags); + socket_change_set = fm->socket_change_set; + fm->socket_change_set = 0; + + dev_dbg(fm->dev, "checking media set %x\n", + socket_change_set); + + if (kthread_should_stop()) + socket_change_set = (1 << fm->num_sockets) - 1; spin_unlock_irqrestore(&fm->lock, flags); - class_device_put(&fm->cdev); - return; - } - spin_unlock_irqrestore(&fm->lock, flags); - for (cnt = 0; cnt < fm->max_sockets; cnt++) { - if (!(insert_mask & (1 << cnt))) + if (!socket_change_set) continue; - media_id = tifm_7xx1_toggle_sock_power(tifm_7xx1_sock_addr(fm->addr, cnt), - fm->max_sockets == 2); - if (media_id) { - ok_to_register = 0; - new_sock = tifm_alloc_device(fm, cnt); - if (new_sock) { - new_sock->addr = tifm_7xx1_sock_addr(fm->addr, - cnt); - new_sock->media_id = media_id; - switch (media_id) { - case 1: - card_name = "xd"; - break; - case 2: - card_name = "ms"; - break; - case 3: - card_name = "sd"; - break; - default: - break; - } - snprintf(new_sock->dev.bus_id, BUS_ID_SIZE, - "tifm_%s%u:%u", card_name, fm->id, cnt); + spin_lock_irqsave(&fm->lock, flags); + for (cnt = 0; cnt < fm->num_sockets; cnt++) { + if (!(socket_change_set & (1 << cnt))) + continue; + sock = fm->sockets[cnt]; + if (sock) { printk(KERN_INFO DRIVER_NAME - ": %s card detected in socket %d\n", - card_name, cnt); + ": demand removing card from socket %d\n", + cnt); + fm->sockets[cnt] = NULL; + spin_unlock_irqrestore(&fm->lock, flags); + device_unregister(&sock->dev); spin_lock_irqsave(&fm->lock, flags); - if (!fm->sockets[cnt]) { - fm->sockets[cnt] = new_sock; - ok_to_register = 1; + writel(0x0e00, + tifm_7xx1_sock_addr(fm->addr, cnt) + + SOCK_CONTROL); + } + if (kthread_should_stop()) + continue; + + spin_unlock_irqrestore(&fm->lock, flags); + media_id = tifm_7xx1_toggle_sock_power( + tifm_7xx1_sock_addr(fm->addr, cnt), + fm->num_sockets == 2); + if (media_id) { + sock = tifm_alloc_device(fm); + if (sock) { + sock->addr = tifm_7xx1_sock_addr(fm->addr, + cnt); + sock->media_id = media_id; + sock->socket_id = cnt; + switch (media_id) { + case 1: + card_name = "xd"; + break; + case 2: + card_name = "ms"; + break; + case 3: + card_name = "sd"; + break; + default: + tifm_free_device(&sock->dev); + spin_lock_irqsave(&fm->lock, flags); + continue; + } + snprintf(sock->dev.bus_id, BUS_ID_SIZE, + "tifm_%s%u:%u", card_name, + fm->id, cnt); + printk(KERN_INFO DRIVER_NAME + ": %s card detected in socket %d\n", + card_name, cnt); + if (!device_register(&sock->dev)) { + spin_lock_irqsave(&fm->lock, flags); + if (!fm->sockets[cnt]) { + fm->sockets[cnt] = sock; + sock = NULL; + } + spin_unlock_irqrestore(&fm->lock, flags); + } + if (sock) + tifm_free_device(&sock->dev); } + spin_lock_irqsave(&fm->lock, flags); + } + } + + if (!kthread_should_stop()) { + writel(TIFM_IRQ_FIFOMASK(socket_change_set) + | TIFM_IRQ_CARDMASK(socket_change_set), + fm->addr + FM_CLEAR_INTERRUPT_ENABLE); + writel(TIFM_IRQ_FIFOMASK(socket_change_set) + | TIFM_IRQ_CARDMASK(socket_change_set), + fm->addr + FM_SET_INTERRUPT_ENABLE); + writel(TIFM_IRQ_ENABLE, + fm->addr + FM_SET_INTERRUPT_ENABLE); + spin_unlock_irqrestore(&fm->lock, flags); + } else { + for (cnt = 0; cnt < fm->num_sockets; cnt++) { + if (fm->sockets[cnt]) + fm->socket_change_set |= 1 << cnt; + } + if (!fm->socket_change_set) { + spin_unlock_irqrestore(&fm->lock, flags); + return 0; + } else { spin_unlock_irqrestore(&fm->lock, flags); - if (!ok_to_register || - device_register(&new_sock->dev)) { - spin_lock_irqsave(&fm->lock, flags); - fm->sockets[cnt] = NULL; - spin_unlock_irqrestore(&fm->lock, - flags); - tifm_free_device(&new_sock->dev); - } } } - writel((TIFM_IRQ_FIFOMASK | TIFM_IRQ_CARDMASK) << cnt, - fm->addr + FM_CLEAR_INTERRUPT_ENABLE); - writel((TIFM_IRQ_FIFOMASK | TIFM_IRQ_CARDMASK) << cnt, - fm->addr + FM_SET_INTERRUPT_ENABLE); } - - writel(TIFM_IRQ_ENABLE, fm->addr + FM_SET_INTERRUPT_ENABLE); - class_device_put(&fm->cdev); + return 0; } +#ifdef CONFIG_PM + static int tifm_7xx1_suspend(struct pci_dev *dev, pm_message_t state) { - struct tifm_adapter *fm = pci_get_drvdata(dev); - unsigned long flags; + dev_dbg(&dev->dev, "suspending host\n"); - spin_lock_irqsave(&fm->lock, flags); - fm->inhibit_new_cards = 1; - fm->remove_mask = 0xf; - fm->insert_mask = 0; - writel(TIFM_IRQ_ENABLE, fm->addr + FM_CLEAR_INTERRUPT_ENABLE); - spin_unlock_irqrestore(&fm->lock, flags); - flush_workqueue(fm->wq); - - tifm_7xx1_remove_media(&fm->media_remover); - - pci_set_power_state(dev, PCI_D3hot); - pci_disable_device(dev); - pci_save_state(dev); + pci_save_state(dev); + pci_enable_wake(dev, pci_choose_state(dev, state), 0); + pci_disable_device(dev); + pci_set_power_state(dev, pci_choose_state(dev, state)); return 0; } static int tifm_7xx1_resume(struct pci_dev *dev) { struct tifm_adapter *fm = pci_get_drvdata(dev); + int cnt, rc; unsigned long flags; + tifm_media_id new_ids[fm->num_sockets]; + pci_set_power_state(dev, PCI_D0); pci_restore_state(dev); - pci_enable_device(dev); - pci_set_power_state(dev, PCI_D0); - pci_set_master(dev); + rc = pci_enable_device(dev); + if (rc) + return rc; + pci_set_master(dev); + dev_dbg(&dev->dev, "resuming host\n"); + + for (cnt = 0; cnt < fm->num_sockets; cnt++) + new_ids[cnt] = tifm_7xx1_toggle_sock_power( + tifm_7xx1_sock_addr(fm->addr, cnt), + fm->num_sockets == 2); spin_lock_irqsave(&fm->lock, flags); - fm->inhibit_new_cards = 0; - writel(TIFM_IRQ_SETALL, fm->addr + FM_INTERRUPT_STATUS); - writel(TIFM_IRQ_SETALL, fm->addr + FM_CLEAR_INTERRUPT_ENABLE); - writel(TIFM_IRQ_ENABLE | TIFM_IRQ_SETALLSOCK, - fm->addr + FM_SET_INTERRUPT_ENABLE); - fm->insert_mask = 0xf; + fm->socket_change_set = 0; + for (cnt = 0; cnt < fm->num_sockets; cnt++) { + if (fm->sockets[cnt]) { + if (fm->sockets[cnt]->media_id == new_ids[cnt]) + fm->socket_change_set |= 1 << cnt; + + fm->sockets[cnt]->media_id = new_ids[cnt]; + } + } + + writel(TIFM_IRQ_ENABLE | TIFM_IRQ_SOCKMASK((1 << fm->num_sockets) - 1), + fm->addr + FM_SET_INTERRUPT_ENABLE); + if (!fm->socket_change_set) { + spin_unlock_irqrestore(&fm->lock, flags); + return 0; + } else { + fm->socket_change_set = 0; + spin_unlock_irqrestore(&fm->lock, flags); + } + + wait_event_timeout(fm->change_set_notify, fm->socket_change_set, HZ); + + spin_lock_irqsave(&fm->lock, flags); + writel(TIFM_IRQ_FIFOMASK(fm->socket_change_set) + | TIFM_IRQ_CARDMASK(fm->socket_change_set), + fm->addr + FM_CLEAR_INTERRUPT_ENABLE); + writel(TIFM_IRQ_FIFOMASK(fm->socket_change_set) + | TIFM_IRQ_CARDMASK(fm->socket_change_set), + fm->addr + FM_SET_INTERRUPT_ENABLE); + writel(TIFM_IRQ_ENABLE, + fm->addr + FM_SET_INTERRUPT_ENABLE); + fm->socket_change_set = 0; + spin_unlock_irqrestore(&fm->lock, flags); return 0; } +#else + +#define tifm_7xx1_suspend NULL +#define tifm_7xx1_resume NULL + +#endif /* CONFIG_PM */ + static int tifm_7xx1_probe(struct pci_dev *dev, - const struct pci_device_id *dev_id) + const struct pci_device_id *dev_id) { struct tifm_adapter *fm; int pci_dev_busy = 0; @@ -324,36 +352,34 @@ static int tifm_7xx1_probe(struct pci_de } fm->dev = &dev->dev; - fm->max_sockets = (dev->device == 0x803B) ? 2 : 4; - fm->sockets = kzalloc(sizeof(struct tifm_dev*) * fm->max_sockets, - GFP_KERNEL); + fm->num_sockets = (dev->device == PCI_DEVICE_ID_TI_XX21_XX11_FM) + ? 4 : 2; + fm->sockets = kzalloc(sizeof(struct tifm_dev*) * fm->num_sockets, + GFP_KERNEL); if (!fm->sockets) goto err_out_free; - INIT_WORK(&fm->media_inserter, tifm_7xx1_insert_media); - INIT_WORK(&fm->media_remover, tifm_7xx1_remove_media); fm->eject = tifm_7xx1_eject; pci_set_drvdata(dev, fm); fm->addr = ioremap(pci_resource_start(dev, 0), - pci_resource_len(dev, 0)); + pci_resource_len(dev, 0)); if (!fm->addr) goto err_out_free; - rc = request_irq(dev->irq, tifm_7xx1_isr, SA_SHIRQ, DRIVER_NAME, fm); + rc = request_irq(dev->irq, tifm_7xx1_isr, IRQF_SHARED, DRIVER_NAME, fm); if (rc) goto err_out_unmap; - rc = tifm_add_adapter(fm); + init_waitqueue_head(&fm->change_set_notify); + rc = tifm_add_adapter(fm, tifm_7xx1_switch_media); if (rc) goto err_out_irq; writel(TIFM_IRQ_SETALL, fm->addr + FM_CLEAR_INTERRUPT_ENABLE); - writel(TIFM_IRQ_ENABLE | TIFM_IRQ_SETALLSOCK, - fm->addr + FM_SET_INTERRUPT_ENABLE); - - fm->insert_mask = 0xf; - + writel(TIFM_IRQ_ENABLE | TIFM_IRQ_SOCKMASK((1 << fm->num_sockets) - 1), + fm->addr + FM_SET_INTERRUPT_ENABLE); + wake_up_process(fm->media_switcher); return 0; err_out_irq: @@ -377,19 +403,15 @@ static void tifm_7xx1_remove(struct pci_ struct tifm_adapter *fm = pci_get_drvdata(dev); unsigned long flags; + writel(TIFM_IRQ_SETALL, fm->addr + FM_CLEAR_INTERRUPT_ENABLE); + mmiowb(); + free_irq(dev->irq, fm); + spin_lock_irqsave(&fm->lock, flags); - fm->inhibit_new_cards = 1; - fm->remove_mask = 0xf; - fm->insert_mask = 0; - writel(TIFM_IRQ_ENABLE, fm->addr + FM_CLEAR_INTERRUPT_ENABLE); + fm->socket_change_set = (1 << fm->num_sockets) - 1; spin_unlock_irqrestore(&fm->lock, flags); - flush_workqueue(fm->wq); - - tifm_7xx1_remove_media(&fm->media_remover); - - writel(TIFM_IRQ_SETALL, fm->addr + FM_CLEAR_INTERRUPT_ENABLE); - free_irq(dev->irq, fm); + kthread_stop(fm->media_switcher); tifm_remove_adapter(fm); @@ -404,10 +426,12 @@ static void tifm_7xx1_remove(struct pci_ } static struct pci_device_id tifm_7xx1_pci_tbl [] = { - { PCI_VENDOR_ID_TI, 0x8033, PCI_ANY_ID, PCI_ANY_ID, 0, 0, - 0 }, /* xx21 - the one I have */ - { PCI_VENDOR_ID_TI, 0x803B, PCI_ANY_ID, PCI_ANY_ID, 0, 0, - 0 }, /* xx12 - should be also supported */ + { PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_XX21_XX11_FM, PCI_ANY_ID, + PCI_ANY_ID, 0, 0, 0 }, /* xx21 - the one I have */ + { PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_XX12_FM, PCI_ANY_ID, + PCI_ANY_ID, 0, 0, 0 }, + { PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_XX20_FM, PCI_ANY_ID, + PCI_ANY_ID, 0, 0, 0 }, { } }; diff --git a/drivers/misc/tifm_core.c b/drivers/misc/tifm_core.c index d61df5c..6b10ebe 100644 --- a/drivers/misc/tifm_core.c +++ b/drivers/misc/tifm_core.c @@ -14,7 +14,7 @@ #include #include #define DRIVER_NAME "tifm_core" -#define DRIVER_VERSION "0.6" +#define DRIVER_VERSION "0.7" static DEFINE_IDR(tifm_adapter_idr); static DEFINE_SPINLOCK(tifm_adapter_lock); @@ -60,10 +60,41 @@ static int tifm_uevent(struct device *de return 0; } +#ifdef CONFIG_PM + +static int tifm_device_suspend(struct device *dev, pm_message_t state) +{ + struct tifm_dev *fm_dev = container_of(dev, struct tifm_dev, dev); + struct tifm_driver *drv = fm_dev->drv; + + if (drv && drv->suspend) + return drv->suspend(fm_dev, state); + return 0; +} + +static int tifm_device_resume(struct device *dev) +{ + struct tifm_dev *fm_dev = container_of(dev, struct tifm_dev, dev); + struct tifm_driver *drv = fm_dev->drv; + + if (drv && drv->resume) + return drv->resume(fm_dev); + return 0; +} + +#else + +#define tifm_device_suspend NULL +#define tifm_device_resume NULL + +#endif /* CONFIG_PM */ + static struct bus_type tifm_bus_type = { .name = "tifm", .match = tifm_match, .uevent = tifm_uevent, + .suspend = tifm_device_suspend, + .resume = tifm_device_resume }; static void tifm_free(struct class_device *cdev) @@ -71,8 +102,6 @@ static void tifm_free(struct class_devic struct tifm_adapter *fm = container_of(cdev, struct tifm_adapter, cdev); kfree(fm->sockets); - if (fm->wq) - destroy_workqueue(fm->wq); kfree(fm); } @@ -101,7 +130,8 @@ void tifm_free_adapter(struct tifm_adapt } EXPORT_SYMBOL(tifm_free_adapter); -int tifm_add_adapter(struct tifm_adapter *fm) +int tifm_add_adapter(struct tifm_adapter *fm, + int (*mediathreadfn)(void *data)) { int rc; @@ -113,10 +143,10 @@ int tifm_add_adapter(struct tifm_adapter spin_unlock(&tifm_adapter_lock); if (!rc) { snprintf(fm->cdev.class_id, BUS_ID_SIZE, "tifm%u", fm->id); - strncpy(fm->wq_name, fm->cdev.class_id, KOBJ_NAME_LEN); + fm->media_switcher = kthread_create(mediathreadfn, + fm, "tifm/%u", fm->id); - fm->wq = create_singlethread_workqueue(fm->wq_name); - if (fm->wq) + if (!IS_ERR(fm->media_switcher)) return class_device_add(&fm->cdev); spin_lock(&tifm_adapter_lock); @@ -141,27 +171,27 @@ EXPORT_SYMBOL(tifm_remove_adapter); void tifm_free_device(struct device *dev) { struct tifm_dev *fm_dev = container_of(dev, struct tifm_dev, dev); - if (fm_dev->wq) - destroy_workqueue(fm_dev->wq); kfree(fm_dev); } EXPORT_SYMBOL(tifm_free_device); -struct tifm_dev *tifm_alloc_device(struct tifm_adapter *fm, unsigned int id) +static void tifm_dummy_signal_irq(struct tifm_dev *sock, + unsigned int sock_irq_status) +{ + return; +} + +struct tifm_dev *tifm_alloc_device(struct tifm_adapter *fm) { struct tifm_dev *dev = kzalloc(sizeof(struct tifm_dev), GFP_KERNEL); if (dev) { spin_lock_init(&dev->lock); - snprintf(dev->wq_name, KOBJ_NAME_LEN, "tifm%u:%u", fm->id, id); - dev->wq = create_singlethread_workqueue(dev->wq_name); - if (!dev->wq) { - kfree(dev); - return NULL; - } + dev->dev.parent = fm->dev; dev->dev.bus = &tifm_bus_type; dev->dev.release = tifm_free_device; + dev->signal_irq = tifm_dummy_signal_irq; } return dev; } @@ -219,6 +249,7 @@ static int tifm_device_remove(struct dev struct tifm_driver *drv = fm_dev->drv; if (drv) { + fm_dev->signal_irq = tifm_dummy_signal_irq; if (drv->remove) drv->remove(fm_dev); fm_dev->drv = NULL; @@ -233,6 +264,8 @@ int tifm_register_driver(struct tifm_dri drv->driver.bus = &tifm_bus_type; drv->driver.probe = tifm_device_probe; drv->driver.remove = tifm_device_remove; + drv->driver.suspend = tifm_device_suspend; + drv->driver.resume = tifm_device_resume; return driver_register(&drv->driver); } diff --git a/drivers/mmc/Kconfig b/drivers/mmc/Kconfig index 4224686..12af9c7 100644 --- a/drivers/mmc/Kconfig +++ b/drivers/mmc/Kconfig @@ -111,7 +111,7 @@ config MMC_IMX config MMC_TIFM_SD tristate "TI Flash Media MMC/SD Interface support (EXPERIMENTAL)" - depends on MMC && EXPERIMENTAL + depends on MMC && EXPERIMENTAL && PCI select TIFM_CORE help Say Y here if you want to be able to access MMC/SD cards with diff --git a/drivers/mmc/at91_mci.c b/drivers/mmc/at91_mci.c index aa152f3..2ce50f3 100644 --- a/drivers/mmc/at91_mci.c +++ b/drivers/mmc/at91_mci.c @@ -823,6 +823,9 @@ static int __init at91_mci_probe(struct mmc->ocr_avail = MMC_VDD_32_33 | MMC_VDD_33_34; mmc->caps = MMC_CAP_BYTEBLOCK; + mmc->max_blk_size = 4095; + mmc->max_blk_count = mmc->max_req_size; + host = mmc_priv(mmc); host->mmc = mmc; host->buffer = NULL; diff --git a/drivers/mmc/au1xmmc.c b/drivers/mmc/au1xmmc.c index 800527c..b834be2 100644 --- a/drivers/mmc/au1xmmc.c +++ b/drivers/mmc/au1xmmc.c @@ -152,8 +152,9 @@ static inline int au1xmmc_card_inserted( ? 1 : 0; } -static inline int au1xmmc_card_readonly(struct au1xmmc_host *host) +static int au1xmmc_card_readonly(struct mmc_host *mmc) { + struct au1xmmc_host *host = mmc_priv(mmc); return (bcsr->status & au1xmmc_card_table[host->id].wpstatus) ? 1 : 0; } @@ -193,6 +194,8 @@ static int au1xmmc_send_command(struct a u32 mmccmd = (cmd->opcode << SD_CMD_CI_SHIFT); switch (mmc_resp_type(cmd)) { + case MMC_RSP_NONE: + break; case MMC_RSP_R1: mmccmd |= SD_CMD_RT_1; break; @@ -205,6 +208,10 @@ static int au1xmmc_send_command(struct a case MMC_RSP_R3: mmccmd |= SD_CMD_RT_3; break; + default: + printk(KERN_INFO "au1xmmc: unhandled response type %02x\n", + mmc_resp_type(cmd)); + return MMC_ERR_INVALID; } switch(cmd->opcode) { @@ -878,6 +885,7 @@ static void au1xmmc_init_dma(struct au1x static const struct mmc_host_ops au1xmmc_ops = { .request = au1xmmc_request, .set_ios = au1xmmc_set_ios, + .get_ro = au1xmmc_card_readonly, }; static int __devinit au1xmmc_probe(struct platform_device *pdev) @@ -914,6 +922,9 @@ static int __devinit au1xmmc_probe(struc mmc->max_seg_size = AU1XMMC_DESCRIPTOR_SIZE; mmc->max_phys_segs = AU1XMMC_DESCRIPTOR_COUNT; + mmc->max_blk_size = 2048; + mmc->max_blk_count = 512; + mmc->ocr_avail = AU1XMMC_OCR; host = mmc_priv(mmc); diff --git a/drivers/mmc/imxmmc.c b/drivers/mmc/imxmmc.c index bfb9ff6..b060d4b 100644 --- a/drivers/mmc/imxmmc.c +++ b/drivers/mmc/imxmmc.c @@ -958,8 +958,10 @@ static int imxmci_probe(struct platform_ /* MMC core transfer sizes tunable parameters */ mmc->max_hw_segs = 64; mmc->max_phys_segs = 64; - mmc->max_sectors = 64; /* default 1 << (PAGE_CACHE_SHIFT - 9) */ mmc->max_seg_size = 64*512; /* default PAGE_CACHE_SIZE */ + mmc->max_req_size = 64*512; /* default PAGE_CACHE_SIZE */ + mmc->max_blk_size = 2048; + mmc->max_blk_count = 65535; host = mmc_priv(mmc); host->mmc = mmc; diff --git a/drivers/mmc/mmc.c b/drivers/mmc/mmc.c index 6f2a282..5046a16 100644 --- a/drivers/mmc/mmc.c +++ b/drivers/mmc/mmc.c @@ -103,11 +103,16 @@ mmc_start_request(struct mmc_host *host, mmc_hostname(host), mrq->cmd->opcode, mrq->cmd->arg, mrq->cmd->flags); - WARN_ON(host->card_busy == NULL); + WARN_ON(!host->claimed); mrq->cmd->error = 0; mrq->cmd->mrq = mrq; if (mrq->data) { + BUG_ON(mrq->data->blksz > host->max_blk_size); + BUG_ON(mrq->data->blocks > host->max_blk_count); + BUG_ON(mrq->data->blocks * mrq->data->blksz > + host->max_req_size); + mrq->cmd->data = mrq->data; mrq->data->error = 0; mrq->data->mrq = mrq; @@ -157,7 +162,7 @@ int mmc_wait_for_cmd(struct mmc_host *ho { struct mmc_request mrq; - BUG_ON(host->card_busy == NULL); + BUG_ON(!host->claimed); memset(&mrq, 0, sizeof(struct mmc_request)); @@ -195,7 +200,7 @@ int mmc_wait_for_app_cmd(struct mmc_host int i, err; - BUG_ON(host->card_busy == NULL); + BUG_ON(!host->claimed); BUG_ON(retries < 0); err = MMC_ERR_INVALID; @@ -289,7 +294,10 @@ void mmc_set_data_timeout(struct mmc_dat else limit_us = 100000; - if (timeout_us > limit_us) { + /* + * SDHC cards always use these fixed values. + */ + if (timeout_us > limit_us || mmc_card_blockaddr(card)) { data->timeout_ns = limit_us * 1000; data->timeout_clks = 0; } @@ -320,14 +328,14 @@ int __mmc_claim_host(struct mmc_host *ho spin_lock_irqsave(&host->lock, flags); while (1) { set_current_state(TASK_UNINTERRUPTIBLE); - if (host->card_busy == NULL) + if (!host->claimed) break; spin_unlock_irqrestore(&host->lock, flags); schedule(); spin_lock_irqsave(&host->lock, flags); } set_current_state(TASK_RUNNING); - host->card_busy = card; + host->claimed = 1; spin_unlock_irqrestore(&host->lock, flags); remove_wait_queue(&host->wq, &wait); @@ -353,10 +361,10 @@ void mmc_release_host(struct mmc_host *h { unsigned long flags; - BUG_ON(host->card_busy == NULL); + BUG_ON(!host->claimed); spin_lock_irqsave(&host->lock, flags); - host->card_busy = NULL; + host->claimed = 0; spin_unlock_irqrestore(&host->lock, flags); wake_up(&host->wq); @@ -372,7 +380,7 @@ static inline void mmc_set_ios(struct mm mmc_hostname(host), ios->clock, ios->bus_mode, ios->power_mode, ios->chip_select, ios->vdd, ios->bus_width); - + host->ops->set_ios(host, ios); } @@ -381,7 +389,7 @@ static int mmc_select_card(struct mmc_ho int err; struct mmc_command cmd; - BUG_ON(host->card_busy == NULL); + BUG_ON(!host->claimed); if (host->card_selected == card) return MMC_ERR_NONE; @@ -588,34 +596,65 @@ static void mmc_decode_csd(struct mmc_ca if (mmc_card_sd(card)) { csd_struct = UNSTUFF_BITS(resp, 126, 2); - if (csd_struct != 0) { + + switch (csd_struct) { + case 0: + m = UNSTUFF_BITS(resp, 115, 4); + e = UNSTUFF_BITS(resp, 112, 3); + csd->tacc_ns = (tacc_exp[e] * tacc_mant[m] + 9) / 10; + csd->tacc_clks = UNSTUFF_BITS(resp, 104, 8) * 100; + + m = UNSTUFF_BITS(resp, 99, 4); + e = UNSTUFF_BITS(resp, 96, 3); + csd->max_dtr = tran_exp[e] * tran_mant[m]; + csd->cmdclass = UNSTUFF_BITS(resp, 84, 12); + + e = UNSTUFF_BITS(resp, 47, 3); + m = UNSTUFF_BITS(resp, 62, 12); + csd->capacity = (1 + m) << (e + 2); + + csd->read_blkbits = UNSTUFF_BITS(resp, 80, 4); + csd->read_partial = UNSTUFF_BITS(resp, 79, 1); + csd->write_misalign = UNSTUFF_BITS(resp, 78, 1); + csd->read_misalign = UNSTUFF_BITS(resp, 77, 1); + csd->r2w_factor = UNSTUFF_BITS(resp, 26, 3); + csd->write_blkbits = UNSTUFF_BITS(resp, 22, 4); + csd->write_partial = UNSTUFF_BITS(resp, 21, 1); + break; + case 1: + /* + * This is a block-addressed SDHC card. Most + * interesting fields are unused and have fixed + * values. To avoid getting tripped by buggy cards, + * we assume those fixed values ourselves. + */ + mmc_card_set_blockaddr(card); + + csd->tacc_ns = 0; /* Unused */ + csd->tacc_clks = 0; /* Unused */ + + m = UNSTUFF_BITS(resp, 99, 4); + e = UNSTUFF_BITS(resp, 96, 3); + csd->max_dtr = tran_exp[e] * tran_mant[m]; + csd->cmdclass = UNSTUFF_BITS(resp, 84, 12); + + m = UNSTUFF_BITS(resp, 48, 22); + csd->capacity = (1 + m) << 10; + + csd->read_blkbits = 9; + csd->read_partial = 0; + csd->write_misalign = 0; + csd->read_misalign = 0; + csd->r2w_factor = 4; /* Unused */ + csd->write_blkbits = 9; + csd->write_partial = 0; + break; + default: printk("%s: unrecognised CSD structure version %d\n", mmc_hostname(card->host), csd_struct); mmc_card_set_bad(card); return; } - - m = UNSTUFF_BITS(resp, 115, 4); - e = UNSTUFF_BITS(resp, 112, 3); - csd->tacc_ns = (tacc_exp[e] * tacc_mant[m] + 9) / 10; - csd->tacc_clks = UNSTUFF_BITS(resp, 104, 8) * 100; - - m = UNSTUFF_BITS(resp, 99, 4); - e = UNSTUFF_BITS(resp, 96, 3); - csd->max_dtr = tran_exp[e] * tran_mant[m]; - csd->cmdclass = UNSTUFF_BITS(resp, 84, 12); - - e = UNSTUFF_BITS(resp, 47, 3); - m = UNSTUFF_BITS(resp, 62, 12); - csd->capacity = (1 + m) << (e + 2); - - csd->read_blkbits = UNSTUFF_BITS(resp, 80, 4); - csd->read_partial = UNSTUFF_BITS(resp, 79, 1); - csd->write_misalign = UNSTUFF_BITS(resp, 78, 1); - csd->read_misalign = UNSTUFF_BITS(resp, 77, 1); - csd->r2w_factor = UNSTUFF_BITS(resp, 26, 3); - csd->write_blkbits = UNSTUFF_BITS(resp, 22, 4); - csd->write_partial = UNSTUFF_BITS(resp, 21, 1); } else { /* * We only understand CSD structure v1.1 and v1.2. @@ -848,6 +887,41 @@ static int mmc_send_app_op_cond(struct m return err; } +static int mmc_send_if_cond(struct mmc_host *host, u32 ocr, int *rsd2) +{ + struct mmc_command cmd; + int err, sd2; + static const u8 test_pattern = 0xAA; + + /* + * To support SD 2.0 cards, we must always invoke SD_SEND_IF_COND + * before SD_APP_OP_COND. This command will harmlessly fail for + * SD 1.0 cards. + */ + cmd.opcode = SD_SEND_IF_COND; + cmd.arg = ((ocr & 0xFF8000) != 0) << 8 | test_pattern; + cmd.flags = MMC_RSP_R7 | MMC_CMD_BCR; + + err = mmc_wait_for_cmd(host, &cmd, 0); + if (err == MMC_ERR_NONE) { + if ((cmd.resp[0] & 0xFF) == test_pattern) { + sd2 = 1; + } else { + sd2 = 0; + err = MMC_ERR_FAILED; + } + } else { + /* + * Treat errors as SD 1.0 card. + */ + sd2 = 0; + err = MMC_ERR_NONE; + } + if (rsd2) + *rsd2 = sd2; + return err; +} + /* * Discover cards by requesting their CID. If this command * times out, it is not an error; there are no further cards @@ -1018,7 +1092,8 @@ static void mmc_process_ext_csds(struct mmc_wait_for_req(host, &mrq); if (cmd.error != MMC_ERR_NONE || data.error != MMC_ERR_NONE) { - mmc_card_set_dead(card); + printk("%s: unable to read EXT_CSD, performance " + "might suffer.\n", mmc_hostname(card->host)); continue; } @@ -1034,7 +1109,6 @@ static void mmc_process_ext_csds(struct printk("%s: card is mmc v4 but doesn't support " "any high-speed modes.\n", mmc_hostname(card->host)); - mmc_card_set_bad(card); continue; } @@ -1215,7 +1289,9 @@ static void mmc_read_switch_caps(struct mmc_wait_for_req(host, &mrq); if (cmd.error != MMC_ERR_NONE || data.error != MMC_ERR_NONE) { - mmc_card_set_dead(card); + printk("%s: unable to read switch capabilities, " + "performance might suffer.\n", + mmc_hostname(card->host)); continue; } @@ -1247,12 +1323,8 @@ static void mmc_read_switch_caps(struct mmc_wait_for_req(host, &mrq); - if (cmd.error != MMC_ERR_NONE || data.error != MMC_ERR_NONE) { - mmc_card_set_dead(card); - continue; - } - - if ((status[16] & 0xF) != 1) { + if (cmd.error != MMC_ERR_NONE || data.error != MMC_ERR_NONE || + (status[16] & 0xF) != 1) { printk(KERN_WARNING "%s: Problem switching card " "into high-speed mode!\n", mmc_hostname(host)); @@ -1334,6 +1406,10 @@ static void mmc_setup(struct mmc_host *h mmc_power_up(host); mmc_idle_cards(host); + err = mmc_send_if_cond(host, host->ocr_avail, NULL); + if (err != MMC_ERR_NONE) { + return; + } err = mmc_send_app_op_cond(host, 0, &ocr); /* @@ -1386,10 +1462,21 @@ static void mmc_setup(struct mmc_host *h * all get the idea that they should be ready for CMD2. * (My SanDisk card seems to need this.) */ - if (host->mode == MMC_MODE_SD) - mmc_send_app_op_cond(host, host->ocr, NULL); - else + if (host->mode == MMC_MODE_SD) { + int err, sd2; + err = mmc_send_if_cond(host, host->ocr, &sd2); + if (err == MMC_ERR_NONE) { + /* + * If SD_SEND_IF_COND indicates an SD 2.0 + * compliant card and we should set bit 30 + * of the ocr to indicate that we can handle + * block-addressed SDHC cards. + */ + mmc_send_app_op_cond(host, host->ocr | (sd2 << 30), NULL); + } + } else { mmc_send_op_cond(host, host->ocr, NULL); + } mmc_discover_cards(host); @@ -1519,8 +1606,11 @@ struct mmc_host *mmc_alloc_host(int extr */ host->max_hw_segs = 1; host->max_phys_segs = 1; - host->max_sectors = 1 << (PAGE_CACHE_SHIFT - 9); host->max_seg_size = PAGE_CACHE_SIZE; + + host->max_req_size = PAGE_CACHE_SIZE; + host->max_blk_size = 512; + host->max_blk_count = PAGE_CACHE_SIZE / 512; } return host; diff --git a/drivers/mmc/mmc_block.c b/drivers/mmc/mmc_block.c index 8771357..86439a0 100644 --- a/drivers/mmc/mmc_block.c +++ b/drivers/mmc/mmc_block.c @@ -20,7 +20,6 @@ #include #include #include -#include #include #include #include @@ -237,13 +236,17 @@ static int mmc_blk_issue_rq(struct mmc_q brq.mrq.cmd = &brq.cmd; brq.mrq.data = &brq.data; - brq.cmd.arg = req->sector << 9; + brq.cmd.arg = req->sector; + if (!mmc_card_blockaddr(card)) + brq.cmd.arg <<= 9; brq.cmd.flags = MMC_RSP_R1 | MMC_CMD_ADTC; brq.data.blksz = 1 << md->block_bits; - brq.data.blocks = req->nr_sectors >> (md->block_bits - 9); brq.stop.opcode = MMC_STOP_TRANSMISSION; brq.stop.arg = 0; brq.stop.flags = MMC_RSP_R1B | MMC_CMD_AC; + brq.data.blocks = req->nr_sectors >> (md->block_bits - 9); + if (brq.data.blocks > card->host->max_blk_count) + brq.data.blocks = card->host->max_blk_count; mmc_set_data_timeout(&brq.data, card, rq_data_dir(req) != READ); @@ -375,9 +378,10 @@ #endif spin_unlock_irq(&md->lock); } +flush_queue: + mmc_card_release_host(card); -flush_queue: spin_lock_irq(&md->lock); while (ret) { ret = end_that_request_chunk(req, 0, @@ -494,6 +498,10 @@ mmc_blk_set_blksize(struct mmc_blk_data struct mmc_command cmd; int err; + /* Block-addressed cards ignore MMC_SET_BLOCKLEN. */ + if (mmc_card_blockaddr(card)) + return 0; + mmc_card_claim_host(card); cmd.opcode = MMC_SET_BLOCKLEN; cmd.arg = 1 << md->block_bits; diff --git a/drivers/mmc/mmc_queue.c b/drivers/mmc/mmc_queue.c index 3e35a43..c27e426 100644 --- a/drivers/mmc/mmc_queue.c +++ b/drivers/mmc/mmc_queue.c @@ -147,7 +147,7 @@ int mmc_init_queue(struct mmc_queue *mq, blk_queue_prep_rq(mq->queue, mmc_prep_request); blk_queue_bounce_limit(mq->queue, limit); - blk_queue_max_sectors(mq->queue, host->max_sectors); + blk_queue_max_sectors(mq->queue, host->max_req_size / 512); blk_queue_max_phys_segments(mq->queue, host->max_phys_segs); blk_queue_max_hw_segments(mq->queue, host->max_hw_segs); blk_queue_max_segment_size(mq->queue, host->max_seg_size); diff --git a/drivers/mmc/mmc_sysfs.c b/drivers/mmc/mmc_sysfs.c index e334acd..d32698b 100644 --- a/drivers/mmc/mmc_sysfs.c +++ b/drivers/mmc/mmc_sysfs.c @@ -199,7 +199,7 @@ void mmc_init_card(struct mmc_card *card memset(card, 0, sizeof(struct mmc_card)); card->host = host; device_initialize(&card->dev); - card->dev.parent = mmc_dev(host); + card->dev.parent = mmc_classdev(host); card->dev.bus = &mmc_bus_type; card->dev.release = mmc_release_card; } diff --git a/drivers/mmc/mmci.c b/drivers/mmc/mmci.c index ccfe656..5941dd9 100644 --- a/drivers/mmc/mmci.c +++ b/drivers/mmc/mmci.c @@ -524,15 +524,24 @@ static int mmci_probe(struct amba_device /* * Since we only have a 16-bit data length register, we must * ensure that we don't exceed 2^16-1 bytes in a single request. - * Choose 64 (512-byte) sectors as the limit. */ - mmc->max_sectors = 64; + mmc->max_req_size = 65535; /* * Set the maximum segment size. Since we aren't doing DMA * (yet) we are only limited by the data length register. */ - mmc->max_seg_size = mmc->max_sectors << 9; + mmc->max_seg_size = mmc->max_req_size; + + /* + * Block size can be up to 2048 bytes, but must be a power of two. + */ + mmc->max_blk_size = 2048; + + /* + * No limit on the number of blocks transferred. + */ + mmc->max_blk_count = mmc->max_req_size; spin_lock_init(&host->lock); diff --git a/drivers/mmc/omap.c b/drivers/mmc/omap.c index d30540b..1e96a2f 100644 --- a/drivers/mmc/omap.c +++ b/drivers/mmc/omap.c @@ -1099,8 +1099,10 @@ static int __init mmc_omap_probe(struct */ mmc->max_phys_segs = 32; mmc->max_hw_segs = 32; - mmc->max_sectors = 256; /* NBLK max 11-bits, OMAP also limited by DMA */ - mmc->max_seg_size = mmc->max_sectors * 512; + mmc->max_blk_size = 2048; /* BLEN is 11 bits (+1) */ + mmc->max_blk_count = 2048; /* NBLK is 11 bits (+1) */ + mmc->max_req_size = mmc->max_blk_size * mmc->max_blk_count; + mmc->max_seg_size = mmc->max_req_size; if (host->power_pin >= 0) { if ((ret = omap_request_gpio(host->power_pin)) != 0) { diff --git a/drivers/mmc/pxamci.c b/drivers/mmc/pxamci.c index 6073d99..9774fc6 100644 --- a/drivers/mmc/pxamci.c +++ b/drivers/mmc/pxamci.c @@ -450,6 +450,16 @@ static int pxamci_probe(struct platform_ */ mmc->max_seg_size = PAGE_SIZE; + /* + * Block length register is 10 bits. + */ + mmc->max_blk_size = 1023; + + /* + * Block count register is 16 bits. + */ + mmc->max_blk_count = 65535; + host = mmc_priv(mmc); host->mmc = mmc; host->dma = -1; diff --git a/drivers/mmc/sdhci.c b/drivers/mmc/sdhci.c index c2d13d7..7522f76 100644 --- a/drivers/mmc/sdhci.c +++ b/drivers/mmc/sdhci.c @@ -22,9 +22,6 @@ #include #include "sdhci.h" #define DRIVER_NAME "sdhci" -#define DRIVER_VERSION "0.12" - -#define BUGMAIL "" #define DBG(f, x...) \ pr_debug(DRIVER_NAME " [%s()]: " f, __func__,## x) @@ -37,6 +34,7 @@ #define SDHCI_QUIRK_CLOCK_BEFORE_RESET #define SDHCI_QUIRK_FORCE_DMA (1<<1) /* Controller doesn't like some resets when there is no card inserted. */ #define SDHCI_QUIRK_NO_CARD_NO_RESET (1<<2) +#define SDHCI_QUIRK_SINGLE_POWER_WRITE (1<<3) static const struct pci_device_id pci_ids[] __devinitdata = { { @@ -65,6 +63,14 @@ static const struct pci_device_id pci_id .driver_data = SDHCI_QUIRK_FORCE_DMA, }, + { + .vendor = PCI_VENDOR_ID_ENE, + .device = PCI_DEVICE_ID_ENE_CB712_SD, + .subvendor = PCI_ANY_ID, + .subdevice = PCI_ANY_ID, + .driver_data = SDHCI_QUIRK_SINGLE_POWER_WRITE, + }, + { /* Generic SD host controller */ PCI_DEVICE_CLASS((PCI_CLASS_SYSTEM_SDHCI << 8), 0xFFFF00) }, @@ -145,8 +151,7 @@ static void sdhci_reset(struct sdhci_hos /* hw clears the bit when it's done */ while (readb(host->ioaddr + SDHCI_SOFTWARE_RESET) & mask) { if (timeout == 0) { - printk(KERN_ERR "%s: Reset 0x%x never completed. " - "Please report this to " BUGMAIL ".\n", + printk(KERN_ERR "%s: Reset 0x%x never completed.\n", mmc_hostname(host->mmc), (int)mask); sdhci_dumpregs(host); return; @@ -197,15 +202,9 @@ static void sdhci_deactivate_led(struct * * \*****************************************************************************/ -static inline char* sdhci_kmap_sg(struct sdhci_host* host) +static inline char* sdhci_sg_to_buffer(struct sdhci_host* host) { - host->mapped_sg = kmap_atomic(host->cur_sg->page, KM_BIO_SRC_IRQ); - return host->mapped_sg + host->cur_sg->offset; -} - -static inline void sdhci_kunmap_sg(struct sdhci_host* host) -{ - kunmap_atomic(host->mapped_sg, KM_BIO_SRC_IRQ); + return page_address(host->cur_sg->page) + host->cur_sg->offset; } static inline int sdhci_next_sg(struct sdhci_host* host) @@ -240,7 +239,7 @@ static void sdhci_read_block_pio(struct chunk_remain = 0; data = 0; - buffer = sdhci_kmap_sg(host) + host->offset; + buffer = sdhci_sg_to_buffer(host) + host->offset; while (blksize) { if (chunk_remain == 0) { @@ -264,16 +263,13 @@ static void sdhci_read_block_pio(struct } if (host->remain == 0) { - sdhci_kunmap_sg(host); if (sdhci_next_sg(host) == 0) { BUG_ON(blksize != 0); return; } - buffer = sdhci_kmap_sg(host); + buffer = sdhci_sg_to_buffer(host); } } - - sdhci_kunmap_sg(host); } static void sdhci_write_block_pio(struct sdhci_host *host) @@ -290,7 +286,7 @@ static void sdhci_write_block_pio(struct data = 0; bytes = 0; - buffer = sdhci_kmap_sg(host) + host->offset; + buffer = sdhci_sg_to_buffer(host) + host->offset; while (blksize) { size = min(host->size, host->remain); @@ -314,16 +310,13 @@ static void sdhci_write_block_pio(struct } if (host->remain == 0) { - sdhci_kunmap_sg(host); if (sdhci_next_sg(host) == 0) { BUG_ON(blksize != 0); return; } - buffer = sdhci_kmap_sg(host); + buffer = sdhci_sg_to_buffer(host); } } - - sdhci_kunmap_sg(host); } static void sdhci_transfer_pio(struct sdhci_host *host) @@ -372,7 +365,7 @@ static void sdhci_prepare_data(struct sd /* Sanity checks */ BUG_ON(data->blksz * data->blocks > 524288); - BUG_ON(data->blksz > host->max_block); + BUG_ON(data->blksz > host->mmc->max_blk_size); BUG_ON(data->blocks > 65535); /* timeout in us */ @@ -477,12 +470,11 @@ static void sdhci_finish_data(struct sdh if ((data->error == MMC_ERR_NONE) && blocks) { printk(KERN_ERR "%s: Controller signalled completion even " - "though there were blocks left. Please report this " - "to " BUGMAIL ".\n", mmc_hostname(host->mmc)); + "though there were blocks left.\n", + mmc_hostname(host->mmc)); data->error = MMC_ERR_FAILED; } else if (host->size != 0) { - printk(KERN_ERR "%s: %d bytes were left untransferred. " - "Please report this to " BUGMAIL ".\n", + printk(KERN_ERR "%s: %d bytes were left untransferred.\n", mmc_hostname(host->mmc), host->size); data->error = MMC_ERR_FAILED; } @@ -529,8 +521,7 @@ static void sdhci_send_command(struct sd while (readl(host->ioaddr + SDHCI_PRESENT_STATE) & mask) { if (timeout == 0) { printk(KERN_ERR "%s: Controller never released " - "inhibit bit(s). Please report this to " - BUGMAIL ".\n", mmc_hostname(host->mmc)); + "inhibit bit(s).\n", mmc_hostname(host->mmc)); sdhci_dumpregs(host); cmd->error = MMC_ERR_FAILED; tasklet_schedule(&host->finish_tasklet); @@ -551,8 +542,7 @@ static void sdhci_send_command(struct sd sdhci_set_transfer_mode(host, cmd->data); if ((cmd->flags & MMC_RSP_136) && (cmd->flags & MMC_RSP_BUSY)) { - printk(KERN_ERR "%s: Unsupported response type! " - "Please report this to " BUGMAIL ".\n", + printk(KERN_ERR "%s: Unsupported response type!\n", mmc_hostname(host->mmc)); cmd->error = MMC_ERR_INVALID; tasklet_schedule(&host->finish_tasklet); @@ -650,9 +640,8 @@ static void sdhci_set_clock(struct sdhci while (!((clk = readw(host->ioaddr + SDHCI_CLOCK_CONTROL)) & SDHCI_CLOCK_INT_STABLE)) { if (timeout == 0) { - printk(KERN_ERR "%s: Internal clock never stabilised. " - "Please report this to " BUGMAIL ".\n", - mmc_hostname(host->mmc)); + printk(KERN_ERR "%s: Internal clock never " + "stabilised.\n", mmc_hostname(host->mmc)); sdhci_dumpregs(host); return; } @@ -674,10 +663,17 @@ static void sdhci_set_power(struct sdhci if (host->power == power) return; - writeb(0, host->ioaddr + SDHCI_POWER_CONTROL); - - if (power == (unsigned short)-1) + if (power == (unsigned short)-1) { + writeb(0, host->ioaddr + SDHCI_POWER_CONTROL); goto out; + } + + /* + * Spec says that we should clear the power reg before setting + * a new value. Some controllers don't seem to like this though. + */ + if (!(host->chip->quirks & SDHCI_QUIRK_SINGLE_POWER_WRITE)) + writeb(0, host->ioaddr + SDHCI_POWER_CONTROL); pwr = SDHCI_POWER_ON; @@ -895,9 +891,8 @@ static void sdhci_timeout_timer(unsigned spin_lock_irqsave(&host->lock, flags); if (host->mrq) { - printk(KERN_ERR "%s: Timeout waiting for hardware interrupt. " - "Please report this to " BUGMAIL ".\n", - mmc_hostname(host->mmc)); + printk(KERN_ERR "%s: Timeout waiting for hardware " + "interrupt.\n", mmc_hostname(host->mmc)); sdhci_dumpregs(host); if (host->data) { @@ -931,8 +926,6 @@ static void sdhci_cmd_irq(struct sdhci_h printk(KERN_ERR "%s: Got command interrupt even though no " "command operation was in progress.\n", mmc_hostname(host->mmc)); - printk(KERN_ERR "%s: Please report this to " BUGMAIL ".\n", - mmc_hostname(host->mmc)); sdhci_dumpregs(host); return; } @@ -968,8 +961,6 @@ static void sdhci_data_irq(struct sdhci_ printk(KERN_ERR "%s: Got data interrupt even though no " "data operation was in progress.\n", mmc_hostname(host->mmc)); - printk(KERN_ERR "%s: Please report this to " BUGMAIL ".\n", - mmc_hostname(host->mmc)); sdhci_dumpregs(host); return; @@ -1041,8 +1032,7 @@ static irqreturn_t sdhci_irq(int irq, vo intmask &= SDHCI_INT_BUS_POWER; if (intmask) { - printk(KERN_ERR "%s: Unexpected interrupt 0x%08x. Please " - "report this to " BUGMAIL ".\n", + printk(KERN_ERR "%s: Unexpected interrupt 0x%08x.\n", mmc_hostname(host->mmc), intmask); sdhci_dumpregs(host); @@ -1109,7 +1099,9 @@ static int sdhci_resume (struct pci_dev pci_set_power_state(pdev, PCI_D0); pci_restore_state(pdev); - pci_enable_device(pdev); + ret = pci_enable_device(pdev); + if (ret) + return ret; for (i = 0;i < chip->num_slots;i++) { if (!chip->hosts[i]) @@ -1274,15 +1266,6 @@ static int __devinit sdhci_probe_slot(st if (caps & SDHCI_TIMEOUT_CLK_UNIT) host->timeout_clk *= 1000; - host->max_block = (caps & SDHCI_MAX_BLOCK_MASK) >> SDHCI_MAX_BLOCK_SHIFT; - if (host->max_block >= 3) { - printk(KERN_ERR "%s: Invalid maximum block size.\n", - host->slot_descr); - ret = -ENODEV; - goto unmap; - } - host->max_block = 512 << host->max_block; - /* * Set host parameters. */ @@ -1294,9 +1277,9 @@ static int __devinit sdhci_probe_slot(st mmc->ocr_avail = 0; if (caps & SDHCI_CAN_VDD_330) mmc->ocr_avail |= MMC_VDD_32_33|MMC_VDD_33_34; - else if (caps & SDHCI_CAN_VDD_300) + if (caps & SDHCI_CAN_VDD_300) mmc->ocr_avail |= MMC_VDD_29_30|MMC_VDD_30_31; - else if (caps & SDHCI_CAN_VDD_180) + if (caps & SDHCI_CAN_VDD_180) mmc->ocr_avail |= MMC_VDD_17_18|MMC_VDD_18_19; if ((host->max_clk > 25000000) && !(caps & SDHCI_CAN_DO_HISPD)) { @@ -1326,15 +1309,33 @@ static int __devinit sdhci_probe_slot(st /* * Maximum number of sectors in one transfer. Limited by DMA boundary - * size (512KiB), which means (512 KiB/512=) 1024 entries. + * size (512KiB). */ - mmc->max_sectors = 1024; + mmc->max_req_size = 524288; /* * Maximum segment size. Could be one segment with the maximum number - * of sectors. + * of bytes. + */ + mmc->max_seg_size = mmc->max_req_size; + + /* + * Maximum block size. This varies from controller to controller and + * is specified in the capabilities register. + */ + mmc->max_blk_size = (caps & SDHCI_MAX_BLOCK_MASK) >> SDHCI_MAX_BLOCK_SHIFT; + if (mmc->max_blk_size >= 3) { + printk(KERN_ERR "%s: Invalid maximum block size.\n", + host->slot_descr); + ret = -ENODEV; + goto unmap; + } + mmc->max_blk_size = 512 << mmc->max_blk_size; + + /* + * Maximum block count. */ - mmc->max_seg_size = mmc->max_sectors * 512; + mmc->max_blk_count = 65535; /* * Init tasklets. @@ -1513,8 +1514,7 @@ static struct pci_driver sdhci_driver = static int __init sdhci_drv_init(void) { printk(KERN_INFO DRIVER_NAME - ": Secure Digital Host Controller Interface driver, " - DRIVER_VERSION "\n"); + ": Secure Digital Host Controller Interface driver\n"); printk(KERN_INFO DRIVER_NAME ": Copyright(c) Pierre Ossman\n"); return pci_register_driver(&sdhci_driver); @@ -1536,7 +1536,6 @@ module_param(debug_quirks, uint, 0444); MODULE_AUTHOR("Pierre Ossman "); MODULE_DESCRIPTION("Secure Digital Host Controller Interface driver"); -MODULE_VERSION(DRIVER_VERSION); MODULE_LICENSE("GPL"); MODULE_PARM_DESC(debug_nodma, "Forcefully disable DMA transfers. (default 0)"); diff --git a/drivers/mmc/sdhci.h b/drivers/mmc/sdhci.h index f9d1a0a..e324f0a 100644 --- a/drivers/mmc/sdhci.h +++ b/drivers/mmc/sdhci.h @@ -174,7 +174,6 @@ #define SDHCI_USE_DMA (1<<0) unsigned int max_clk; /* Max possible freq (MHz) */ unsigned int timeout_clk; /* Timeout freq (KHz) */ - unsigned int max_block; /* Max block size (bytes) */ unsigned int clock; /* Current clock (MHz) */ unsigned short power; /* Current voltage */ @@ -184,7 +183,6 @@ #define SDHCI_USE_DMA (1<<0) struct mmc_data *data; /* Current data request */ struct scatterlist *cur_sg; /* We're working on this */ - char *mapped_sg; /* This is where it's mapped */ int num_sg; /* Entries left */ int offset; /* Offset into current sg */ int remain; /* Bytes left in current */ diff --git a/drivers/mmc/tifm_sd.c b/drivers/mmc/tifm_sd.c index fa4a528..0581d09 100644 --- a/drivers/mmc/tifm_sd.c +++ b/drivers/mmc/tifm_sd.c @@ -17,7 +17,7 @@ #include #include #define DRIVER_NAME "tifm_sd" -#define DRIVER_VERSION "0.6" +#define DRIVER_VERSION "0.7" static int no_dma = 0; static int fixed_timeout = 0; @@ -36,8 +36,8 @@ #define TIFM_MMCSD_DPE 0x0020 / #define TIFM_MMCSD_INAB 0x0080 /* abort / initialize command */ #define TIFM_MMCSD_READ 0x8000 -#define TIFM_MMCSD_DATAMASK 0x001d /* set bits: EOFB, BRS, CB, EOC */ -#define TIFM_MMCSD_ERRMASK 0x41e0 /* set bits: CERR, CCRC, CTO, DCRC, DTO */ +#define TIFM_MMCSD_DATAMASK 0x401d /* set bits: CERR, EOFB, BRS, CB, EOC */ +#define TIFM_MMCSD_ERRMASK 0x01e0 /* set bits: CCRC, CTO, DCRC, DTO */ #define TIFM_MMCSD_EOC 0x0001 /* end of command phase */ #define TIFM_MMCSD_CB 0x0004 /* card enter busy state */ #define TIFM_MMCSD_BRS 0x0008 /* block received/sent */ @@ -79,7 +79,6 @@ typedef enum { enum { FIFO_RDY = 0x0001, /* hardware dependent value */ - HOST_REG = 0x0002, EJECT = 0x0004, EJECT_DONE = 0x0008, CARD_BUSY = 0x0010, @@ -95,46 +94,53 @@ struct tifm_sd { card_state_t state; unsigned int clk_freq; unsigned int clk_div; - unsigned long timeout_jiffies; // software timeout - 2 sec + unsigned long timeout_jiffies; + struct tasklet_struct finish_tasklet; + struct timer_list timer; struct mmc_request *req; - struct work_struct cmd_handler; - struct delayed_work abort_handler; - wait_queue_head_t can_eject; + wait_queue_head_t notify; size_t written_blocks; - char *buffer; size_t buffer_size; size_t buffer_pos; }; +static char* tifm_sd_data_buffer(struct mmc_data *data) +{ + return page_address(data->sg->page) + data->sg->offset; +} + static int tifm_sd_transfer_data(struct tifm_dev *sock, struct tifm_sd *host, - unsigned int host_status) + unsigned int host_status) { struct mmc_command *cmd = host->req->cmd; unsigned int t_val = 0, cnt = 0; + char *buffer; if (host_status & TIFM_MMCSD_BRS) { /* in non-dma rx mode BRS fires when fifo is still not empty */ - if (host->buffer && (cmd->data->flags & MMC_DATA_READ)) { + if (no_dma && (cmd->data->flags & MMC_DATA_READ)) { + buffer = tifm_sd_data_buffer(host->req->data); while (host->buffer_size > host->buffer_pos) { t_val = readl(sock->addr + SOCK_MMCSD_DATA); - host->buffer[host->buffer_pos++] = t_val & 0xff; - host->buffer[host->buffer_pos++] = + buffer[host->buffer_pos++] = t_val & 0xff; + buffer[host->buffer_pos++] = (t_val >> 8) & 0xff; } } return 1; - } else if (host->buffer) { + } else if (no_dma) { + buffer = tifm_sd_data_buffer(host->req->data); if ((cmd->data->flags & MMC_DATA_READ) && (host_status & TIFM_MMCSD_AF)) { for (cnt = 0; cnt < TIFM_MMCSD_FIFO_SIZE; cnt++) { t_val = readl(sock->addr + SOCK_MMCSD_DATA); if (host->buffer_size > host->buffer_pos) { - host->buffer[host->buffer_pos++] = + buffer[host->buffer_pos++] = t_val & 0xff; - host->buffer[host->buffer_pos++] = + buffer[host->buffer_pos++] = (t_val >> 8) & 0xff; } } @@ -142,11 +148,12 @@ static int tifm_sd_transfer_data(struct && (host_status & TIFM_MMCSD_AE)) { for (cnt = 0; cnt < TIFM_MMCSD_FIFO_SIZE; cnt++) { if (host->buffer_size > host->buffer_pos) { - t_val = host->buffer[host->buffer_pos++] & 0x00ff; - t_val |= ((host->buffer[host->buffer_pos++]) << 8) - & 0xff00; + t_val = buffer[host->buffer_pos++] + & 0x00ff; + t_val |= ((buffer[host->buffer_pos++]) + << 8) & 0xff00; writel(t_val, - sock->addr + SOCK_MMCSD_DATA); + sock->addr + SOCK_MMCSD_DATA); } } } @@ -206,7 +213,7 @@ static void tifm_sd_exec(struct tifm_sd cmd_mask |= TIFM_MMCSD_READ; dev_dbg(&sock->dev, "executing opcode 0x%x, arg: 0x%x, mask: 0x%x\n", - cmd->opcode, cmd->arg, cmd_mask); + cmd->opcode, cmd->arg, cmd_mask); writel((cmd->arg >> 16) & 0xffff, sock->addr + SOCK_MMCSD_ARG_HIGH); writel(cmd->arg & 0xffff, sock->addr + SOCK_MMCSD_ARG_LOW); @@ -235,69 +242,82 @@ change_state: case IDLE: return; case CMD: - if (host_status & TIFM_MMCSD_EOC) { + if (host_status & (TIFM_MMCSD_EOC | TIFM_MMCSD_CERR)) { tifm_sd_fetch_resp(cmd, sock); if (cmd->data) { host->state = BRS; - } else + } else { host->state = READY; + } goto change_state; } break; case BRS: if (tifm_sd_transfer_data(sock, host, host_status)) { - if (!host->req->stop) { - if (cmd->data->flags & MMC_DATA_WRITE) { - host->state = CARD; + if (cmd->data->flags & MMC_DATA_WRITE) { + host->state = CARD; + } else { + if (no_dma) { + if (host->req->stop) { + tifm_sd_exec(host, host->req->stop); + host->state = SCMD; + } else { + host->state = READY; + } } else { - host->state = - host->buffer ? READY : FIFO; + host->state = FIFO; } - goto change_state; } - tifm_sd_exec(host, host->req->stop); - host->state = SCMD; + goto change_state; } break; case SCMD: if (host_status & TIFM_MMCSD_EOC) { tifm_sd_fetch_resp(host->req->stop, sock); - if (cmd->error) { - host->state = READY; - } else if (cmd->data->flags & MMC_DATA_WRITE) { - host->state = CARD; - } else { - host->state = host->buffer ? READY : FIFO; - } + host->state = READY; goto change_state; } break; case CARD: + dev_dbg(&sock->dev, "waiting for CARD, have %zd blocks\n", + host->written_blocks); if (!(host->flags & CARD_BUSY) && (host->written_blocks == cmd->data->blocks)) { - host->state = host->buffer ? READY : FIFO; + if (no_dma) { + if (host->req->stop) { + tifm_sd_exec(host, host->req->stop); + host->state = SCMD; + } else { + host->state = READY; + } + } else { + host->state = FIFO; + } goto change_state; } break; case FIFO: if (host->flags & FIFO_RDY) { - host->state = READY; host->flags &= ~FIFO_RDY; + if (host->req->stop) { + tifm_sd_exec(host, host->req->stop); + host->state = SCMD; + } else { + host->state = READY; + } goto change_state; } break; case READY: - queue_work(sock->wq, &host->cmd_handler); + tasklet_schedule(&host->finish_tasklet); return; } - queue_delayed_work(sock->wq, &host->abort_handler, - host->timeout_jiffies); } /* Called from interrupt handler */ -static unsigned int tifm_sd_signal_irq(struct tifm_dev *sock, - unsigned int sock_irq_status) +static void tifm_sd_signal_irq(struct tifm_dev *sock, + unsigned int sock_irq_status) { struct tifm_sd *host; unsigned int host_status = 0, fifo_status = 0; @@ -305,7 +325,6 @@ static unsigned int tifm_sd_signal_irq(s spin_lock(&sock->lock); host = mmc_priv((struct mmc_host*)tifm_get_drvdata(sock)); - cancel_delayed_work(&host->abort_handler); if (sock_irq_status & FIFO_EVENT) { fifo_status = readl(sock->addr + SOCK_DMA_FIFO_STATUS); @@ -318,19 +337,14 @@ static unsigned int tifm_sd_signal_irq(s host_status = readl(sock->addr + SOCK_MMCSD_STATUS); writel(host_status, sock->addr + SOCK_MMCSD_STATUS); - if (!(host->flags & HOST_REG)) - queue_work(sock->wq, &host->cmd_handler); if (!host->req) goto done; if (host_status & TIFM_MMCSD_ERRMASK) { - if (host_status & TIFM_MMCSD_CERR) - error_code = MMC_ERR_FAILED; - else if (host_status & - (TIFM_MMCSD_CTO | TIFM_MMCSD_DTO)) + if (host_status & (TIFM_MMCSD_CTO | TIFM_MMCSD_DTO)) error_code = MMC_ERR_TIMEOUT; - else if (host_status & - (TIFM_MMCSD_CCRC | TIFM_MMCSD_DCRC)) + else if (host_status + & (TIFM_MMCSD_CCRC | TIFM_MMCSD_DCRC)) error_code = MMC_ERR_BADCRC; writel(TIFM_FIFO_INT_SETALL, @@ -340,12 +354,11 @@ static unsigned int tifm_sd_signal_irq(s if (host->req->stop) { if (host->state == SCMD) { host->req->stop->error = error_code; - } else if(host->state == BRS) { + } else if (host->state == BRS + || host->state == CARD + || host->state == FIFO) { host->req->cmd->error = error_code; tifm_sd_exec(host, host->req->stop); - queue_delayed_work(sock->wq, - &host->abort_handler, - host->timeout_jiffies); host->state = SCMD; goto done; } else { @@ -359,8 +372,8 @@ static unsigned int tifm_sd_signal_irq(s if (host_status & TIFM_MMCSD_CB) host->flags |= CARD_BUSY; - if ((host_status & TIFM_MMCSD_EOFB) && - (host->flags & CARD_BUSY)) { + if ((host_status & TIFM_MMCSD_EOFB) + && (host->flags & CARD_BUSY)) { host->written_blocks++; host->flags &= ~CARD_BUSY; } @@ -370,22 +383,22 @@ static unsigned int tifm_sd_signal_irq(s tifm_sd_process_cmd(sock, host, host_status); done: dev_dbg(&sock->dev, "host_status %x, fifo_status %x\n", - host_status, fifo_status); + host_status, fifo_status); spin_unlock(&sock->lock); - return sock_irq_status; } -static void tifm_sd_prepare_data(struct tifm_sd *card, struct mmc_command *cmd) +static void tifm_sd_prepare_data(struct tifm_sd *host, struct mmc_command *cmd) { - struct tifm_dev *sock = card->dev; + struct tifm_dev *sock = host->dev; unsigned int dest_cnt; /* DMA style IO */ - + dev_dbg(&sock->dev, "setting dma for %d blocks\n", + cmd->data->blocks); writel(TIFM_FIFO_INT_SETALL, - sock->addr + SOCK_DMA_FIFO_INT_ENABLE_CLEAR); + sock->addr + SOCK_DMA_FIFO_INT_ENABLE_CLEAR); writel(ilog2(cmd->data->blksz) - 2, - sock->addr + SOCK_FIFO_PAGE_SIZE); + sock->addr + SOCK_FIFO_PAGE_SIZE); writel(TIFM_FIFO_ENABLE, sock->addr + SOCK_FIFO_CONTROL); writel(TIFM_FIFO_INTMASK, sock->addr + SOCK_DMA_FIFO_INT_ENABLE_SET); @@ -399,7 +412,7 @@ static void tifm_sd_prepare_data(struct if (cmd->data->flags & MMC_DATA_WRITE) { writel(TIFM_MMCSD_TXDE, sock->addr + SOCK_MMCSD_BUFFER_CONFIG); writel(dest_cnt | TIFM_DMA_TX | TIFM_DMA_EN, - sock->addr + SOCK_DMA_CONTROL); + sock->addr + SOCK_DMA_CONTROL); } else { writel(TIFM_MMCSD_RXDE, sock->addr + SOCK_MMCSD_BUFFER_CONFIG); writel(dest_cnt | TIFM_DMA_EN, sock->addr + SOCK_DMA_CONTROL); @@ -407,7 +420,7 @@ static void tifm_sd_prepare_data(struct } static void tifm_sd_set_data_timeout(struct tifm_sd *host, - struct mmc_data *data) + struct mmc_data *data) { struct tifm_dev *sock = host->dev; unsigned int data_timeout = data->timeout_clks; @@ -416,22 +429,21 @@ static void tifm_sd_set_data_timeout(str return; data_timeout += data->timeout_ns / - ((1000000000 / host->clk_freq) * host->clk_div); - data_timeout *= 10; // call it fudge factor for now + ((1000000000UL / host->clk_freq) * host->clk_div); if (data_timeout < 0xffff) { - writel((~TIFM_MMCSD_DPE) & - readl(sock->addr + SOCK_MMCSD_SDIO_MODE_CONFIG), - sock->addr + SOCK_MMCSD_SDIO_MODE_CONFIG); writel(data_timeout, sock->addr + SOCK_MMCSD_DATA_TO); + writel((~TIFM_MMCSD_DPE) + & readl(sock->addr + SOCK_MMCSD_SDIO_MODE_CONFIG), + sock->addr + SOCK_MMCSD_SDIO_MODE_CONFIG); } else { - writel(TIFM_MMCSD_DPE | - readl(sock->addr + SOCK_MMCSD_SDIO_MODE_CONFIG), - sock->addr + SOCK_MMCSD_SDIO_MODE_CONFIG); data_timeout = (data_timeout >> 10) + 1; - if(data_timeout > 0xffff) + if (data_timeout > 0xffff) data_timeout = 0; /* set to unlimited */ writel(data_timeout, sock->addr + SOCK_MMCSD_DATA_TO); + writel(TIFM_MMCSD_DPE + | readl(sock->addr + SOCK_MMCSD_SDIO_MODE_CONFIG), + sock->addr + SOCK_MMCSD_SDIO_MODE_CONFIG); } } @@ -474,11 +486,10 @@ static void tifm_sd_request(struct mmc_h } host->req = mrq; + mod_timer(&host->timer, jiffies + host->timeout_jiffies); host->state = CMD; - queue_delayed_work(sock->wq, &host->abort_handler, - host->timeout_jiffies); writel(TIFM_CTRL_LED | readl(sock->addr + SOCK_CONTROL), - sock->addr + SOCK_CONTROL); + sock->addr + SOCK_CONTROL); tifm_sd_exec(host, mrq->cmd); spin_unlock_irqrestore(&sock->lock, flags); return; @@ -493,9 +504,9 @@ err_out: mmc_request_done(mmc, mrq); } -static void tifm_sd_end_cmd(struct work_struct *work) +static void tifm_sd_end_cmd(unsigned long data) { - struct tifm_sd *host = container_of(work, struct tifm_sd, cmd_handler); + struct tifm_sd *host = (struct tifm_sd*)data; struct tifm_dev *sock = host->dev; struct mmc_host *mmc = tifm_get_drvdata(sock); struct mmc_request *mrq; @@ -504,6 +515,7 @@ static void tifm_sd_end_cmd(struct work_ spin_lock_irqsave(&sock->lock, flags); + del_timer(&host->timer); mrq = host->req; host->req = NULL; host->state = IDLE; @@ -517,8 +529,8 @@ static void tifm_sd_end_cmd(struct work_ r_data = mrq->cmd->data; if (r_data) { if (r_data->flags & MMC_DATA_WRITE) { - r_data->bytes_xfered = host->written_blocks * - r_data->blksz; + r_data->bytes_xfered = host->written_blocks + * r_data->blksz; } else { r_data->bytes_xfered = r_data->blocks - readl(sock->addr + SOCK_MMCSD_NUM_BLOCKS) - 1; @@ -532,7 +544,7 @@ static void tifm_sd_end_cmd(struct work_ } writel((~TIFM_CTRL_LED) & readl(sock->addr + SOCK_CONTROL), - sock->addr + SOCK_CONTROL); + sock->addr + SOCK_CONTROL); spin_unlock_irqrestore(&sock->lock, flags); mmc_request_done(mmc, mrq); @@ -544,15 +556,6 @@ static void tifm_sd_request_nodma(struct struct tifm_dev *sock = host->dev; unsigned long flags; struct mmc_data *r_data = mrq->cmd->data; - char *t_buffer = NULL; - - if (r_data) { - t_buffer = kmap(r_data->sg->page); - if (!t_buffer) { - printk(KERN_ERR DRIVER_NAME ": kmap failed\n"); - goto err_out; - } - } spin_lock_irqsave(&sock->lock, flags); if (host->flags & EJECT) { @@ -569,15 +572,14 @@ static void tifm_sd_request_nodma(struct if (r_data) { tifm_sd_set_data_timeout(host, r_data); - host->buffer = t_buffer + r_data->sg->offset; - host->buffer_size = mrq->cmd->data->blocks * - mrq->cmd->data->blksz; + host->buffer_size = mrq->cmd->data->blocks + * mrq->cmd->data->blksz; - writel(TIFM_MMCSD_BUFINT | - readl(sock->addr + SOCK_MMCSD_INT_ENABLE), + writel(TIFM_MMCSD_BUFINT + | readl(sock->addr + SOCK_MMCSD_INT_ENABLE), sock->addr + SOCK_MMCSD_INT_ENABLE); - writel(((TIFM_MMCSD_FIFO_SIZE - 1) << 8) | - (TIFM_MMCSD_FIFO_SIZE - 1), + writel(((TIFM_MMCSD_FIFO_SIZE - 1) << 8) + | (TIFM_MMCSD_FIFO_SIZE - 1), sock->addr + SOCK_MMCSD_BUFFER_CONFIG); host->written_blocks = 0; @@ -588,26 +590,22 @@ static void tifm_sd_request_nodma(struct } host->req = mrq; + mod_timer(&host->timer, jiffies + host->timeout_jiffies); host->state = CMD; - queue_delayed_work(sock->wq, &host->abort_handler, - host->timeout_jiffies); writel(TIFM_CTRL_LED | readl(sock->addr + SOCK_CONTROL), - sock->addr + SOCK_CONTROL); + sock->addr + SOCK_CONTROL); tifm_sd_exec(host, mrq->cmd); spin_unlock_irqrestore(&sock->lock, flags); return; err_out: - if (t_buffer) - kunmap(r_data->sg->page); - mrq->cmd->error = MMC_ERR_TIMEOUT; mmc_request_done(mmc, mrq); } -static void tifm_sd_end_cmd_nodma(struct work_struct *work) +static void tifm_sd_end_cmd_nodma(unsigned long data) { - struct tifm_sd *host = container_of(work, struct tifm_sd, cmd_handler); + struct tifm_sd *host = (struct tifm_sd*)data; struct tifm_dev *sock = host->dev; struct mmc_host *mmc = tifm_get_drvdata(sock); struct mmc_request *mrq; @@ -616,6 +614,7 @@ static void tifm_sd_end_cmd_nodma(struct spin_lock_irqsave(&sock->lock, flags); + del_timer(&host->timer); mrq = host->req; host->req = NULL; host->state = IDLE; @@ -633,8 +632,8 @@ static void tifm_sd_end_cmd_nodma(struct sock->addr + SOCK_MMCSD_INT_ENABLE); if (r_data->flags & MMC_DATA_WRITE) { - r_data->bytes_xfered = host->written_blocks * - r_data->blksz; + r_data->bytes_xfered = host->written_blocks + * r_data->blksz; } else { r_data->bytes_xfered = r_data->blocks - readl(sock->addr + SOCK_MMCSD_NUM_BLOCKS) - 1; @@ -642,29 +641,44 @@ static void tifm_sd_end_cmd_nodma(struct r_data->bytes_xfered += r_data->blksz - readl(sock->addr + SOCK_MMCSD_BLOCK_LEN) + 1; } - host->buffer = NULL; host->buffer_pos = 0; host->buffer_size = 0; } writel((~TIFM_CTRL_LED) & readl(sock->addr + SOCK_CONTROL), - sock->addr + SOCK_CONTROL); + sock->addr + SOCK_CONTROL); spin_unlock_irqrestore(&sock->lock, flags); - if (r_data) - kunmap(r_data->sg->page); - mmc_request_done(mmc, mrq); } -static void tifm_sd_abort(struct work_struct *work) +static void tifm_sd_terminate(struct tifm_sd *host) +{ + struct tifm_dev *sock = host->dev; + unsigned long flags; + + writel(0, sock->addr + SOCK_MMCSD_INT_ENABLE); + mmiowb(); + spin_lock_irqsave(&sock->lock, flags); + host->flags |= EJECT; + if (host->req) { + writel(TIFM_FIFO_INT_SETALL, + sock->addr + SOCK_DMA_FIFO_INT_ENABLE_CLEAR); + writel(0, sock->addr + SOCK_DMA_FIFO_INT_ENABLE_SET); + tasklet_schedule(&host->finish_tasklet); + } + spin_unlock_irqrestore(&sock->lock, flags); +} + +static void tifm_sd_abort(unsigned long data) { - struct tifm_sd *host = - container_of(work, struct tifm_sd, abort_handler.work); + struct tifm_sd *host = (struct tifm_sd*)data; printk(KERN_ERR DRIVER_NAME - ": card failed to respond for a long period of time"); + ": card failed to respond for a long period of time"); + + tifm_sd_terminate(host); tifm_eject(host->dev); } @@ -683,9 +697,9 @@ static void tifm_sd_ios(struct mmc_host writel(TIFM_MMCSD_4BBUS | readl(sock->addr + SOCK_MMCSD_CONFIG), sock->addr + SOCK_MMCSD_CONFIG); } else { - writel((~TIFM_MMCSD_4BBUS) & - readl(sock->addr + SOCK_MMCSD_CONFIG), - sock->addr + SOCK_MMCSD_CONFIG); + writel((~TIFM_MMCSD_4BBUS) + & readl(sock->addr + SOCK_MMCSD_CONFIG), + sock->addr + SOCK_MMCSD_CONFIG); } if (ios->clock) { @@ -704,23 +718,24 @@ static void tifm_sd_ios(struct mmc_host if ((20000000 / clk_div1) > (24000000 / clk_div2)) { host->clk_freq = 20000000; host->clk_div = clk_div1; - writel((~TIFM_CTRL_FAST_CLK) & - readl(sock->addr + SOCK_CONTROL), - sock->addr + SOCK_CONTROL); + writel((~TIFM_CTRL_FAST_CLK) + & readl(sock->addr + SOCK_CONTROL), + sock->addr + SOCK_CONTROL); } else { host->clk_freq = 24000000; host->clk_div = clk_div2; - writel(TIFM_CTRL_FAST_CLK | - readl(sock->addr + SOCK_CONTROL), - sock->addr + SOCK_CONTROL); + writel(TIFM_CTRL_FAST_CLK + | readl(sock->addr + SOCK_CONTROL), + sock->addr + SOCK_CONTROL); } } else { host->clk_div = 0; } host->clk_div &= TIFM_MMCSD_CLKMASK; - writel(host->clk_div | ((~TIFM_MMCSD_CLKMASK) & - readl(sock->addr + SOCK_MMCSD_CONFIG)), - sock->addr + SOCK_MMCSD_CONFIG); + writel(host->clk_div + | ((~TIFM_MMCSD_CLKMASK) + & readl(sock->addr + SOCK_MMCSD_CONFIG)), + sock->addr + SOCK_MMCSD_CONFIG); if (ios->bus_mode == MMC_BUSMODE_OPENDRAIN) host->flags |= OPENDRAIN; @@ -734,7 +749,7 @@ static void tifm_sd_ios(struct mmc_host // allow removal. if ((host->flags & EJECT) && ios->power_mode == MMC_POWER_OFF) { host->flags |= EJECT_DONE; - wake_up_all(&host->can_eject); + wake_up_all(&host->notify); } spin_unlock_irqrestore(&sock->lock, flags); @@ -762,20 +777,67 @@ static struct mmc_host_ops tifm_sd_ops = .get_ro = tifm_sd_ro }; -static void tifm_sd_register_host(struct work_struct *work) +static int tifm_sd_initialize_host(struct tifm_sd *host) { - struct tifm_sd *host = container_of(work, struct tifm_sd, cmd_handler); + int rc; + unsigned int host_status = 0; struct tifm_dev *sock = host->dev; - struct mmc_host *mmc = tifm_get_drvdata(sock); - unsigned long flags; - spin_lock_irqsave(&sock->lock, flags); - host->flags |= HOST_REG; - PREPARE_WORK(&host->cmd_handler, - no_dma ? tifm_sd_end_cmd_nodma : tifm_sd_end_cmd); - spin_unlock_irqrestore(&sock->lock, flags); - dev_dbg(&sock->dev, "adding host\n"); - mmc_add_host(mmc); + writel(0, sock->addr + SOCK_MMCSD_INT_ENABLE); + mmiowb(); + host->clk_div = 61; + host->clk_freq = 20000000; + writel(TIFM_MMCSD_RESET, sock->addr + SOCK_MMCSD_SYSTEM_CONTROL); + writel(host->clk_div | TIFM_MMCSD_POWER, + sock->addr + SOCK_MMCSD_CONFIG); + + /* wait up to 0.51 sec for reset */ + for (rc = 2; rc <= 256; rc <<= 1) { + if (1 & readl(sock->addr + SOCK_MMCSD_SYSTEM_STATUS)) { + rc = 0; + break; + } + msleep(rc); + } + + if (rc) { + printk(KERN_ERR DRIVER_NAME + ": controller failed to reset\n"); + return -ENODEV; + } + + writel(0, sock->addr + SOCK_MMCSD_NUM_BLOCKS); + writel(host->clk_div | TIFM_MMCSD_POWER, + sock->addr + SOCK_MMCSD_CONFIG); + writel(TIFM_MMCSD_RXDE, sock->addr + SOCK_MMCSD_BUFFER_CONFIG); + + // command timeout fixed to 64 clocks for now + writel(64, sock->addr + SOCK_MMCSD_COMMAND_TO); + writel(TIFM_MMCSD_INAB, sock->addr + SOCK_MMCSD_COMMAND); + + /* INAB should take much less than reset */ + for (rc = 1; rc <= 16; rc <<= 1) { + host_status = readl(sock->addr + SOCK_MMCSD_STATUS); + writel(host_status, sock->addr + SOCK_MMCSD_STATUS); + if (!(host_status & TIFM_MMCSD_ERRMASK) + && (host_status & TIFM_MMCSD_EOC)) { + rc = 0; + break; + } + msleep(rc); + } + + if (rc) { + printk(KERN_ERR DRIVER_NAME + ": card not ready - probe failed on initialization\n"); + return -ENODEV; + } + + writel(TIFM_MMCSD_DATAMASK | TIFM_MMCSD_ERRMASK, + sock->addr + SOCK_MMCSD_INT_ENABLE); + mmiowb(); + + return 0; } static int tifm_sd_probe(struct tifm_dev *sock) @@ -784,8 +846,8 @@ static int tifm_sd_probe(struct tifm_dev struct tifm_sd *host; int rc = -EIO; - if (!(TIFM_SOCK_STATE_OCCUPIED & - readl(sock->addr + SOCK_PRESENT_STATE))) { + if (!(TIFM_SOCK_STATE_OCCUPIED + & readl(sock->addr + SOCK_PRESENT_STATE))) { printk(KERN_WARNING DRIVER_NAME ": card gone, unexpectedly\n"); return rc; } @@ -795,109 +857,99 @@ static int tifm_sd_probe(struct tifm_dev return -ENOMEM; host = mmc_priv(mmc); - host->dev = sock; - host->clk_div = 61; - init_waitqueue_head(&host->can_eject); - INIT_WORK(&host->cmd_handler, tifm_sd_register_host); - INIT_DELAYED_WORK(&host->abort_handler, tifm_sd_abort); - tifm_set_drvdata(sock, mmc); - sock->signal_irq = tifm_sd_signal_irq; - - host->clk_freq = 20000000; + host->dev = sock; host->timeout_jiffies = msecs_to_jiffies(1000); + init_waitqueue_head(&host->notify); + tasklet_init(&host->finish_tasklet, + no_dma ? tifm_sd_end_cmd_nodma : tifm_sd_end_cmd, + (unsigned long)host); + setup_timer(&host->timer, tifm_sd_abort, (unsigned long)host); + tifm_sd_ops.request = no_dma ? tifm_sd_request_nodma : tifm_sd_request; mmc->ops = &tifm_sd_ops; mmc->ocr_avail = MMC_VDD_32_33 | MMC_VDD_33_34; - mmc->caps = MMC_CAP_4_BIT_DATA; + mmc->caps = MMC_CAP_4_BIT_DATA | MMC_CAP_MULTIWRITE; mmc->f_min = 20000000 / 60; mmc->f_max = 24000000; mmc->max_hw_segs = 1; mmc->max_phys_segs = 1; - mmc->max_sectors = 127; - mmc->max_seg_size = mmc->max_sectors << 11; //2k maximum hw block length - - writel(0, sock->addr + SOCK_MMCSD_INT_ENABLE); - writel(TIFM_MMCSD_RESET, sock->addr + SOCK_MMCSD_SYSTEM_CONTROL); - writel(host->clk_div | TIFM_MMCSD_POWER, - sock->addr + SOCK_MMCSD_CONFIG); + // limited by DMA counter - it's safer to stick with + // block counter has 11 bits though + mmc->max_blk_count = 256; + // 2k maximum hw block length + mmc->max_blk_size = 2048; + mmc->max_req_size = mmc->max_blk_size * mmc->max_blk_count; + mmc->max_seg_size = mmc->max_req_size; + sock->signal_irq = tifm_sd_signal_irq; + rc = tifm_sd_initialize_host(host); - for (rc = 0; rc < 50; rc++) { - /* Wait for reset ack */ - if (1 & readl(sock->addr + SOCK_MMCSD_SYSTEM_STATUS)) { - rc = 0; - break; - } - msleep(10); - } + if (!rc) + rc = mmc_add_host(mmc); + if (rc) + goto out_free_mmc; - if (rc) { - printk(KERN_ERR DRIVER_NAME - ": card not ready - probe failed\n"); - mmc_free_host(mmc); - return -ENODEV; - } + return 0; +out_free_mmc: + mmc_free_host(mmc); + return rc; +} - writel(0, sock->addr + SOCK_MMCSD_NUM_BLOCKS); - writel(host->clk_div | TIFM_MMCSD_POWER, - sock->addr + SOCK_MMCSD_CONFIG); - writel(TIFM_MMCSD_RXDE, sock->addr + SOCK_MMCSD_BUFFER_CONFIG); - writel(TIFM_MMCSD_DATAMASK | TIFM_MMCSD_ERRMASK, - sock->addr + SOCK_MMCSD_INT_ENABLE); +static void tifm_sd_remove(struct tifm_dev *sock) +{ + struct mmc_host *mmc = tifm_get_drvdata(sock); + struct tifm_sd *host = mmc_priv(mmc); - writel(64, sock->addr + SOCK_MMCSD_COMMAND_TO); // command timeout 64 clocks for now - writel(TIFM_MMCSD_INAB, sock->addr + SOCK_MMCSD_COMMAND); - writel(host->clk_div | TIFM_MMCSD_POWER, - sock->addr + SOCK_MMCSD_CONFIG); + del_timer_sync(&host->timer); + tifm_sd_terminate(host); + wait_event_timeout(host->notify, host->flags & EJECT_DONE, + host->timeout_jiffies); + tasklet_kill(&host->finish_tasklet); + mmc_remove_host(mmc); - queue_delayed_work(sock->wq, &host->abort_handler, - host->timeout_jiffies); + /* The meaning of the bit majority in this constant is unknown. */ + writel(0xfff8 & readl(sock->addr + SOCK_CONTROL), + sock->addr + SOCK_CONTROL); - return 0; + tifm_set_drvdata(sock, NULL); + mmc_free_host(mmc); } -static int tifm_sd_host_is_down(struct tifm_dev *sock) +#ifdef CONFIG_PM + +static int tifm_sd_suspend(struct tifm_dev *sock, pm_message_t state) { struct mmc_host *mmc = tifm_get_drvdata(sock); - struct tifm_sd *host = mmc_priv(mmc); - unsigned long flags; - int rc = 0; + int rc; - spin_lock_irqsave(&sock->lock, flags); - rc = (host->flags & EJECT_DONE); - spin_unlock_irqrestore(&sock->lock, flags); + rc = mmc_suspend_host(mmc, state); + /* The meaning of the bit majority in this constant is unknown. */ + writel(0xfff8 & readl(sock->addr + SOCK_CONTROL), + sock->addr + SOCK_CONTROL); return rc; } -static void tifm_sd_remove(struct tifm_dev *sock) +static int tifm_sd_resume(struct tifm_dev *sock) { struct mmc_host *mmc = tifm_get_drvdata(sock); struct tifm_sd *host = mmc_priv(mmc); - unsigned long flags; - spin_lock_irqsave(&sock->lock, flags); - host->flags |= EJECT; - if (host->req) - queue_work(sock->wq, &host->cmd_handler); - spin_unlock_irqrestore(&sock->lock, flags); - wait_event_timeout(host->can_eject, tifm_sd_host_is_down(sock), - host->timeout_jiffies); + if (sock->media_id != FM_SD + || tifm_sd_initialize_host(host)) { + tifm_eject(sock); + return 0; + } else { + return mmc_resume_host(mmc); + } +} - if (host->flags & HOST_REG) - mmc_remove_host(mmc); +#else - /* The meaning of the bit majority in this constant is unknown. */ - writel(0xfff8 & readl(sock->addr + SOCK_CONTROL), - sock->addr + SOCK_CONTROL); - writel(0, sock->addr + SOCK_MMCSD_INT_ENABLE); - writel(TIFM_FIFO_INT_SETALL, - sock->addr + SOCK_DMA_FIFO_INT_ENABLE_CLEAR); - writel(0, sock->addr + SOCK_DMA_FIFO_INT_ENABLE_SET); +#define tifm_sd_suspend NULL +#define tifm_sd_resume NULL - tifm_set_drvdata(sock, NULL); - mmc_free_host(mmc); -} +#endif /* CONFIG_PM */ static tifm_media_id tifm_sd_id_tbl[] = { FM_SD, 0 @@ -910,7 +962,9 @@ static struct tifm_driver tifm_sd_driver }, .id_table = tifm_sd_id_tbl, .probe = tifm_sd_probe, - .remove = tifm_sd_remove + .remove = tifm_sd_remove, + .suspend = tifm_sd_suspend, + .resume = tifm_sd_resume }; static int __init tifm_sd_init(void) diff --git a/drivers/mmc/wbsd.c b/drivers/mmc/wbsd.c index 7a28267..05ccfc4 100644 --- a/drivers/mmc/wbsd.c +++ b/drivers/mmc/wbsd.c @@ -1,7 +1,7 @@ /* * linux/drivers/mmc/wbsd.c - Winbond W83L51xD SD/MMC driver * - * Copyright (C) 2004-2005 Pierre Ossman, All Rights Reserved. + * Copyright (C) 2004-2006 Pierre Ossman, All Rights Reserved. * * 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 @@ -42,7 +42,6 @@ #include #include "wbsd.h" #define DRIVER_NAME "wbsd" -#define DRIVER_VERSION "1.6" #define DBG(x...) \ pr_debug(DRIVER_NAME ": " x) @@ -272,16 +271,9 @@ static inline int wbsd_next_sg(struct wb return host->num_sg; } -static inline char *wbsd_kmap_sg(struct wbsd_host *host) +static inline char *wbsd_sg_to_buffer(struct wbsd_host *host) { - host->mapped_sg = kmap_atomic(host->cur_sg->page, KM_BIO_SRC_IRQ) + - host->cur_sg->offset; - return host->mapped_sg; -} - -static inline void wbsd_kunmap_sg(struct wbsd_host *host) -{ - kunmap_atomic(host->mapped_sg, KM_BIO_SRC_IRQ); + return page_address(host->cur_sg->page) + host->cur_sg->offset; } static inline void wbsd_sg_to_dma(struct wbsd_host *host, struct mmc_data *data) @@ -302,12 +294,11 @@ static inline void wbsd_sg_to_dma(struct * we do not transfer too much. */ for (i = 0; i < len; i++) { - sgbuf = kmap_atomic(sg[i].page, KM_BIO_SRC_IRQ) + sg[i].offset; + sgbuf = page_address(sg[i].page) + sg[i].offset; if (size < sg[i].length) memcpy(dmabuf, sgbuf, size); else memcpy(dmabuf, sgbuf, sg[i].length); - kunmap_atomic(sgbuf, KM_BIO_SRC_IRQ); dmabuf += sg[i].length; if (size < sg[i].length) @@ -347,12 +338,11 @@ static inline void wbsd_dma_to_sg(struct * we do not transfer too much. */ for (i = 0; i < len; i++) { - sgbuf = kmap_atomic(sg[i].page, KM_BIO_SRC_IRQ) + sg[i].offset; + sgbuf = page_address(sg[i].page) + sg[i].offset; if (size < sg[i].length) memcpy(sgbuf, dmabuf, size); else memcpy(sgbuf, dmabuf, sg[i].length); - kunmap_atomic(sgbuf, KM_BIO_SRC_IRQ); dmabuf += sg[i].length; if (size < sg[i].length) @@ -497,7 +487,7 @@ static void wbsd_empty_fifo(struct wbsd_ if (data->bytes_xfered == host->size) return; - buffer = wbsd_kmap_sg(host) + host->offset; + buffer = wbsd_sg_to_buffer(host) + host->offset; /* * Drain the fifo. This has a tendency to loop longer @@ -526,17 +516,13 @@ static void wbsd_empty_fifo(struct wbsd_ /* * Transfer done? */ - if (data->bytes_xfered == host->size) { - wbsd_kunmap_sg(host); + if (data->bytes_xfered == host->size) return; - } /* * End of scatter list entry? */ if (host->remain == 0) { - wbsd_kunmap_sg(host); - /* * Get next entry. Check if last. */ @@ -554,13 +540,11 @@ static void wbsd_empty_fifo(struct wbsd_ return; } - buffer = wbsd_kmap_sg(host); + buffer = wbsd_sg_to_buffer(host); } } } - wbsd_kunmap_sg(host); - /* * This is a very dirty hack to solve a * hardware problem. The chip doesn't trigger @@ -583,7 +567,7 @@ static void wbsd_fill_fifo(struct wbsd_h if (data->bytes_xfered == host->size) return; - buffer = wbsd_kmap_sg(host) + host->offset; + buffer = wbsd_sg_to_buffer(host) + host->offset; /* * Fill the fifo. This has a tendency to loop longer @@ -612,17 +596,13 @@ static void wbsd_fill_fifo(struct wbsd_h /* * Transfer done? */ - if (data->bytes_xfered == host->size) { - wbsd_kunmap_sg(host); + if (data->bytes_xfered == host->size) return; - } /* * End of scatter list entry? */ if (host->remain == 0) { - wbsd_kunmap_sg(host); - /* * Get next entry. Check if last. */ @@ -640,13 +620,11 @@ static void wbsd_fill_fifo(struct wbsd_h return; } - buffer = wbsd_kmap_sg(host); + buffer = wbsd_sg_to_buffer(host); } } } - wbsd_kunmap_sg(host); - /* * The controller stops sending interrupts for * 'FIFO empty' under certain conditions. So we @@ -910,6 +888,45 @@ static void wbsd_request(struct mmc_host */ if (cmd->data && (cmd->error == MMC_ERR_NONE)) { /* + * The hardware is so delightfully stupid that it has a list + * of "data" commands. If a command isn't on this list, it'll + * just go back to the idle state and won't send any data + * interrupts. + */ + switch (cmd->opcode) { + case 11: + case 17: + case 18: + case 20: + case 24: + case 25: + case 26: + case 27: + case 30: + case 42: + case 56: + break; + + /* ACMDs. We don't keep track of state, so we just treat them + * like any other command. */ + case 51: + break; + + default: +#ifdef CONFIG_MMC_DEBUG + printk(KERN_WARNING "%s: Data command %d is not " + "supported by this controller.\n", + mmc_hostname(host->mmc), cmd->opcode); +#endif + cmd->data->error = MMC_ERR_INVALID; + + if (cmd->data->stop) + wbsd_send_command(host, cmd->data->stop); + + goto done; + }; + + /* * Dirty fix for hardware bug. */ if (host->dma == -1) @@ -1343,16 +1360,27 @@ static int __devinit wbsd_alloc_mmc(stru mmc->max_phys_segs = 128; /* - * Maximum number of sectors in one transfer. Also limited by 64kB - * buffer. + * Maximum request size. Also limited by 64KiB buffer. */ - mmc->max_sectors = 128; + mmc->max_req_size = 65536; /* * Maximum segment size. Could be one segment with the maximum number - * of segments. + * of bytes. + */ + mmc->max_seg_size = mmc->max_req_size; + + /* + * Maximum block size. We have 12 bits (= 4095) but have to subtract + * space for CRC. So the maximum is 4095 - 4*2 = 4087. + */ + mmc->max_blk_size = 4087; + + /* + * Maximum block count. There is no real limit so the maximum + * request size will be the only restriction. */ - mmc->max_seg_size = mmc->max_sectors * 512; + mmc->max_blk_count = mmc->max_req_size; dev_set_drvdata(dev, mmc); @@ -2071,8 +2099,7 @@ static int __init wbsd_drv_init(void) int result; printk(KERN_INFO DRIVER_NAME - ": Winbond W83L51xD SD/MMC card interface driver, " - DRIVER_VERSION "\n"); + ": Winbond W83L51xD SD/MMC card interface driver\n"); printk(KERN_INFO DRIVER_NAME ": Copyright(c) Pierre Ossman\n"); #ifdef CONFIG_PNP @@ -2136,7 +2163,6 @@ module_param(dma, int, 0444); MODULE_LICENSE("GPL"); MODULE_AUTHOR("Pierre Ossman "); MODULE_DESCRIPTION("Winbond W83L51xD SD/MMC card interface driver"); -MODULE_VERSION(DRIVER_VERSION); #ifdef CONFIG_PNP MODULE_PARM_DESC(nopnp, "Scan for device instead of relying on PNP. (default 0)"); diff --git a/drivers/mmc/wbsd.h b/drivers/mmc/wbsd.h index 6072993..d06718b 100644 --- a/drivers/mmc/wbsd.h +++ b/drivers/mmc/wbsd.h @@ -154,7 +154,6 @@ #define WBSD_FIGNORE_DETECT (1<<1) /* I struct scatterlist* cur_sg; /* Current SG entry */ unsigned int num_sg; /* Number of entries left */ - void* mapped_sg; /* vaddr of mapped sg */ unsigned int offset; /* Offset into current entry */ unsigned int remain; /* Data left in curren entry */ diff --git a/drivers/mtd/chips/cfi_util.c b/drivers/mtd/chips/cfi_util.c index d8e7a02..2e51496 100644 --- a/drivers/mtd/chips/cfi_util.c +++ b/drivers/mtd/chips/cfi_util.c @@ -14,7 +14,6 @@ #include #include #include -#include #include #include diff --git a/drivers/mtd/devices/block2mtd.c b/drivers/mtd/devices/block2mtd.c index 6d917a4..f9f2ce7 100644 --- a/drivers/mtd/devices/block2mtd.c +++ b/drivers/mtd/devices/block2mtd.c @@ -278,7 +278,8 @@ static void block2mtd_free_device(struct kfree(dev->mtd.name); if (dev->blkdev) { - invalidate_inode_pages(dev->blkdev->bd_inode->i_mapping); + invalidate_mapping_pages(dev->blkdev->bd_inode->i_mapping, + 0, -1); close_bdev_excl(dev->blkdev); } diff --git a/drivers/mtd/devices/doc2001.c b/drivers/mtd/devices/doc2001.c index 0e2a932..fe71a12 100644 --- a/drivers/mtd/devices/doc2001.c +++ b/drivers/mtd/devices/doc2001.c @@ -16,7 +16,6 @@ #include #include #include #include -#include #include #include #include diff --git a/drivers/mtd/devices/doc2001plus.c b/drivers/mtd/devices/doc2001plus.c index 92dbb47..ba4db68 100644 --- a/drivers/mtd/devices/doc2001plus.c +++ b/drivers/mtd/devices/doc2001plus.c @@ -20,7 +20,6 @@ #include #include #include #include -#include #include #include #include diff --git a/drivers/mtd/devices/docecc.c b/drivers/mtd/devices/docecc.c index cd3db72..52b5d63 100644 --- a/drivers/mtd/devices/docecc.c +++ b/drivers/mtd/devices/docecc.c @@ -32,7 +32,6 @@ #include #include #include #include -#include #include #include diff --git a/drivers/mtd/devices/pmc551.c b/drivers/mtd/devices/pmc551.c index 354e165..a4873ab 100644 --- a/drivers/mtd/devices/pmc551.c +++ b/drivers/mtd/devices/pmc551.c @@ -86,7 +86,6 @@ #include #include #include #include -#include #include #include #include diff --git a/drivers/mtd/devices/slram.c b/drivers/mtd/devices/slram.c index 5f49248..d293add 100644 --- a/drivers/mtd/devices/slram.c +++ b/drivers/mtd/devices/slram.c @@ -35,7 +35,6 @@ #include #include #include #include -#include #include #include #include diff --git a/drivers/mtd/ftl.c b/drivers/mtd/ftl.c index 24235d4..c815d0f 100644 --- a/drivers/mtd/ftl.c +++ b/drivers/mtd/ftl.c @@ -61,7 +61,6 @@ #include /*#define PSYCHO_DEBUG */ #include -#include #include #include #include diff --git a/drivers/mtd/inftlmount.c b/drivers/mtd/inftlmount.c index 8f6006f..acf3ba2 100644 --- a/drivers/mtd/inftlmount.c +++ b/drivers/mtd/inftlmount.c @@ -34,7 +34,6 @@ #include #include #include #include -#include #include #include #include diff --git a/drivers/mtd/mtdchar.c b/drivers/mtd/mtdchar.c index 3013d08..61a994e 100644 --- a/drivers/mtd/mtdchar.c +++ b/drivers/mtd/mtdchar.c @@ -759,7 +759,7 @@ #endif return ret; } /* memory_ioctl */ -static struct file_operations mtd_fops = { +static const struct file_operations mtd_fops = { .owner = THIS_MODULE, .llseek = mtd_lseek, .read = mtd_read, diff --git a/drivers/mtd/mtdcore.c b/drivers/mtd/mtdcore.c index 7070110..c153b64 100644 --- a/drivers/mtd/mtdcore.c +++ b/drivers/mtd/mtdcore.c @@ -8,7 +8,6 @@ #include #include -#include #include #include #include diff --git a/drivers/mtd/nand/cafe.c b/drivers/mtd/nand/cafe.c index 65f9bd3..08cb060 100644 --- a/drivers/mtd/nand/cafe.c +++ b/drivers/mtd/nand/cafe.c @@ -597,7 +597,8 @@ static int __devinit cafe_nand_probe(str cafe_writel(cafe, 0xffffffff, NAND_TIMING3); } cafe_writel(cafe, 0xffffffff, NAND_IRQ_MASK); - err = request_irq(pdev->irq, &cafe_nand_interrupt, SA_SHIRQ, "CAFE NAND", mtd); + err = request_irq(pdev->irq, &cafe_nand_interrupt, IRQF_SHARED, + "CAFE NAND", mtd); if (err) { dev_warn(&pdev->dev, "Could not register IRQ %d\n", pdev->irq); diff --git a/drivers/mtd/nftlcore.c b/drivers/mtd/nftlcore.c index 4b1ba4f..e6ef7d7 100644 --- a/drivers/mtd/nftlcore.c +++ b/drivers/mtd/nftlcore.c @@ -20,7 +20,6 @@ #include #include #include #include -#include #include #include diff --git a/drivers/net/3c503.c b/drivers/net/3c503.c index 7e34c4f..bc7e906 100644 --- a/drivers/net/3c503.c +++ b/drivers/net/3c503.c @@ -600,8 +600,7 @@ el2_block_input(struct net_device *dev, count -= semi_count; memcpy_fromio(skb->data + semi_count, base + ei_status.priv, count); } else { - /* Packet is in one chunk -- we can copy + cksum. */ - eth_io_copy_and_sum(skb, base + ring_offset, count, 0); + memcpy_fromio(skb->data, base + ring_offset, count); } return; } diff --git a/drivers/net/3c59x.c b/drivers/net/3c59x.c index 80bdcf8..716a472 100644 --- a/drivers/net/3c59x.c +++ b/drivers/net/3c59x.c @@ -792,8 +792,7 @@ static void poll_vortex(struct net_devic { struct vortex_private *vp = netdev_priv(dev); unsigned long flags; - local_save_flags(flags); - local_irq_disable(); + local_irq_save(flags); (vp->full_bus_master_rx ? boomerang_interrupt:vortex_interrupt)(dev->irq,dev); local_irq_restore(flags); } diff --git a/drivers/net/7990.c b/drivers/net/7990.c index 2d5ba07..1b3d11e 100644 --- a/drivers/net/7990.c +++ b/drivers/net/7990.c @@ -500,7 +500,7 @@ int lance_open (struct net_device *dev) int res; /* Install the Interrupt handler. Or we could shunt this out to specific drivers? */ - if (request_irq(lp->irq, lance_interrupt, SA_SHIRQ, lp->name, dev)) + if (request_irq(lp->irq, lance_interrupt, IRQF_SHARED, lp->name, dev)) return -EAGAIN; res = lance_reset(dev); diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig index 8aa8dd0..38f41a5 100644 --- a/drivers/net/Kconfig +++ b/drivers/net/Kconfig @@ -190,7 +190,7 @@ config MII config MACB tristate "Atmel MACB support" - depends on NET_ETHERNET && AVR32 + depends on NET_ETHERNET && (AVR32 || ARCH_AT91SAM9260 || ARCH_AT91SAM9263) select MII help The Atmel MACB ethernet interface is found on many AT32 and AT91 @@ -235,16 +235,6 @@ config BMAC To compile this driver as a module, choose M here: the module will be called bmac. -config OAKNET - tristate "National DP83902AV (Oak ethernet) support" - depends on NET_ETHERNET && PPC && BROKEN - select CRC32 - help - Say Y if your machine has this type of Ethernet network card. - - To compile this driver as a module, choose M here: the module - will be called oaknet. - config ARIADNE tristate "Ariadne support" depends on NET_ETHERNET && ZORRO @@ -1155,21 +1145,6 @@ config SEEQ8005 . The module will be called seeq8005. -config SKMC - tristate "SKnet MCA support" - depends on NET_ETHERNET && MCA && BROKEN - ---help--- - These are Micro Channel Ethernet adapters. You need to say Y to "MCA - support" in order to use this driver. Supported cards are the SKnet - Junior MC2 and the SKnet MC2(+). The driver automatically - distinguishes between the two cards. Note that using multiple boards - of different type hasn't been tested with this driver. Say Y if you - have one of these Ethernet adapters. - - To compile this driver as a module, choose M here and read - . The module - will be called sk_mca. - config NE2_MCA tristate "NE/2 (ne2000 MCA version) support" depends on NET_ETHERNET && MCA_LEGACY @@ -1788,6 +1763,18 @@ config LAN_SAA9730 workstations. See . +config SC92031 + tristate "Silan SC92031 PCI Fast Ethernet Adapter driver (EXPERIMENTAL)" + depends on NET_PCI && PCI && EXPERIMENTAL + select CRC32 + ---help--- + This is a driver for the Fast Ethernet PCI network cards based on + the Silan SC92031 chip (sometimes also called Rsltek 8139D). If you + have one of these, say Y here. + + To compile this driver as a module, choose M here: the module + will be called sc92031. This is recommended. + config NET_POCKET bool "Pocket and portable adapters" depends on NET_ETHERNET && PARPORT @@ -2348,6 +2335,17 @@ config QLA3XXX To compile this driver as a module, choose M here: the module will be called qla3xxx. +config ATL1 + tristate "Attansic L1 Gigabit Ethernet support (EXPERIMENTAL)" + depends on NET_PCI && PCI && EXPERIMENTAL + select CRC32 + select MII + help + This driver supports the Attansic L1 gigabit ethernet adapter. + + To compile this driver as a module, choose M here. The module + will be called atl1. + endmenu # @@ -2392,6 +2390,24 @@ config CHELSIO_T1_NAPI NAPI is a driver API designed to reduce CPU and interrupt load when the driver is receiving lots of packets from the card. +config CHELSIO_T3 + tristate "Chelsio Communications T3 10Gb Ethernet support" + depends on PCI + help + This driver supports Chelsio T3-based gigabit and 10Gb Ethernet + adapters. + + For general information about Chelsio and our products, visit + our website at . + + For customer support, please visit our customer support page at + . + + Please send feedback to . + + To compile this driver as a module, choose M here: the module + will be called cxgb3. + config EHEA tristate "eHEA Ethernet support" depends on IBMEBUS @@ -2488,6 +2504,13 @@ config NETXEN_NIC help This enables the support for NetXen's Gigabit Ethernet card. +config PASEMI_MAC + tristate "PA Semi 1/10Gbit MAC" + depends on PPC64 && PCI + help + This driver supports the on-chip 1/10Gbit Ethernet controller on + PA Semi's PWRficient line of chips. + endmenu source "drivers/net/tokenring/Kconfig" @@ -2522,7 +2545,7 @@ config RIONET_RX_SIZE config FDDI bool "FDDI driver support" - depends on (PCI || EISA) + depends on (PCI || EISA || TC) help Fiber Distributed Data Interface is a high speed local area network design; essentially a replacement for high speed Ethernet. FDDI can @@ -2532,15 +2555,36 @@ config FDDI will say N. config DEFXX - tristate "Digital DEFEA and DEFPA adapter support" - depends on FDDI && (PCI || EISA) - help - This is support for the DIGITAL series of EISA (DEFEA) and PCI - (DEFPA) controllers which can connect you to a local FDDI network. + tristate "Digital DEFTA/DEFEA/DEFPA adapter support" + depends on FDDI && (PCI || EISA || TC) + ---help--- + This is support for the DIGITAL series of TURBOchannel (DEFTA), + EISA (DEFEA) and PCI (DEFPA) controllers which can connect you + to a local FDDI network. + + To compile this driver as a module, choose M here: the module + will be called defxx. If unsure, say N. + +config DEFXX_MMIO + bool + prompt "Use MMIO instead of PIO" if PCI || EISA + depends on DEFXX + default n if PCI || EISA + default y + ---help--- + This instructs the driver to use EISA or PCI memory-mapped I/O + (MMIO) as appropriate instead of programmed I/O ports (PIO). + Enabling this gives an improvement in processing time in parts + of the driver, but it may cause problems with EISA (DEFEA) + adapters. TURBOchannel does not have the concept of I/O ports, + so MMIO is always used for these (DEFTA) adapters. + + If unsure, say N. config SKFP tristate "SysKonnect FDDI PCI support" depends on FDDI && PCI + select BITREVERSE ---help--- Say Y here if you have a SysKonnect FDDI PCI adapter. The following adapters are supported by this driver: diff --git a/drivers/net/Makefile b/drivers/net/Makefile index 4c0d4e5..33af833 100644 --- a/drivers/net/Makefile +++ b/drivers/net/Makefile @@ -6,8 +6,10 @@ obj-$(CONFIG_E1000) += e1000/ obj-$(CONFIG_IBM_EMAC) += ibm_emac/ obj-$(CONFIG_IXGB) += ixgb/ obj-$(CONFIG_CHELSIO_T1) += chelsio/ +obj-$(CONFIG_CHELSIO_T3) += cxgb3/ obj-$(CONFIG_EHEA) += ehea/ obj-$(CONFIG_BONDING) += bonding/ +obj-$(CONFIG_ATL1) += atl1/ obj-$(CONFIG_GIANFAR) += gianfar_driver.o gianfar_driver-objs := gianfar.o \ @@ -36,8 +38,6 @@ obj-$(CONFIG_CASSINI) += cassini.o obj-$(CONFIG_MACE) += mace.o obj-$(CONFIG_BMAC) += bmac.o -obj-$(CONFIG_OAKNET) += oaknet.o 8390.o - obj-$(CONFIG_DGRS) += dgrs.o obj-$(CONFIG_VORTEX) += 3c59x.o obj-$(CONFIG_TYPHOON) += typhoon.o @@ -137,7 +137,6 @@ obj-$(CONFIG_AT1700) += at1700.o obj-$(CONFIG_EL1) += 3c501.o obj-$(CONFIG_EL16) += 3c507.o obj-$(CONFIG_ELMC) += 3c523.o -obj-$(CONFIG_SKMC) += sk_mca.o obj-$(CONFIG_IBMLANA) += ibmlana.o obj-$(CONFIG_ELMC_II) += 3c527.o obj-$(CONFIG_EL3) += 3c509.o @@ -160,6 +159,7 @@ obj-$(CONFIG_APRICOT) += 82596.o obj-$(CONFIG_LASI_82596) += lasi_82596.o obj-$(CONFIG_MVME16x_NET) += 82596.o obj-$(CONFIG_BVME6000_NET) += 82596.o +obj-$(CONFIG_SC92031) += sc92031.o # This is also a 82596 and should probably be merged obj-$(CONFIG_LP486E) += lp486e.o @@ -196,6 +196,7 @@ obj-$(CONFIG_SMC91X) += smc91x.o obj-$(CONFIG_SMC911X) += smc911x.o obj-$(CONFIG_DM9000) += dm9000.o obj-$(CONFIG_FEC_8XX) += fec_8xx/ +obj-$(CONFIG_PASEMI_MAC) += pasemi_mac.o obj-$(CONFIG_MACB) += macb.o diff --git a/drivers/net/Space.c b/drivers/net/Space.c index 9305eb9..dd8ed45 100644 --- a/drivers/net/Space.c +++ b/drivers/net/Space.c @@ -59,7 +59,6 @@ extern struct net_device *wavelan_probe( extern struct net_device *arlan_probe(int unit); extern struct net_device *el16_probe(int unit); extern struct net_device *elmc_probe(int unit); -extern struct net_device *skmca_probe(int unit); extern struct net_device *elplus_probe(int unit); extern struct net_device *ac3200_probe(int unit); extern struct net_device *es_probe(int unit); @@ -153,9 +152,6 @@ #endif #ifdef CONFIG_ELMC_II /* 3c527 */ {mc32_probe, 0}, #endif -#ifdef CONFIG_SKMC /* SKnet Microchannel */ - {skmca_probe, 0}, -#endif {NULL, 0}, }; diff --git a/drivers/net/ac3200.c b/drivers/net/ac3200.c index c01f87f..644c408 100644 --- a/drivers/net/ac3200.c +++ b/drivers/net/ac3200.c @@ -327,8 +327,7 @@ static void ac_block_input(struct net_de memcpy_fromio(skb->data + semi_count, ei_status.mem + TX_PAGES*256, count); } else { - /* Packet is in one chunk -- we can copy + cksum. */ - eth_io_copy_and_sum(skb, start, count, 0); + memcpy_fromio(skb->data, start, count); } } diff --git a/drivers/net/amd8111e.c b/drivers/net/amd8111e.c index 18896f2..9c399aa 100644 --- a/drivers/net/amd8111e.c +++ b/drivers/net/amd8111e.c @@ -1334,8 +1334,7 @@ #ifdef CONFIG_NET_POLL_CONTROLLER static void amd8111e_poll(struct net_device *dev) { unsigned long flags; - local_save_flags(flags); - local_irq_disable(); + local_irq_save(flags); amd8111e_interrupt(0, dev); local_irq_restore(flags); } diff --git a/drivers/net/arcnet/com20020.c b/drivers/net/arcnet/com20020.c index aa9dd8f..4218075 100644 --- a/drivers/net/arcnet/com20020.c +++ b/drivers/net/arcnet/com20020.c @@ -338,7 +338,8 @@ static void com20020_set_mc_list(struct } #if defined(CONFIG_ARCNET_COM20020_PCI_MODULE) || \ - defined(CONFIG_ARCNET_COM20020_ISA_MODULE) + defined(CONFIG_ARCNET_COM20020_ISA_MODULE) || \ + defined(CONFIG_ARCNET_COM20020_CS_MODULE) EXPORT_SYMBOL(com20020_check); EXPORT_SYMBOL(com20020_found); #endif diff --git a/drivers/net/arm/at91_ether.c b/drivers/net/arm/at91_ether.c index fada15d..1621b8f 100644 --- a/drivers/net/arm/at91_ether.c +++ b/drivers/net/arm/at91_ether.c @@ -641,7 +641,7 @@ static void at91ether_get_drvinfo(struct { strlcpy(info->driver, DRV_NAME, sizeof(info->driver)); strlcpy(info->version, DRV_VERSION, sizeof(info->version)); - strlcpy(info->bus_info, dev->class_dev.dev->bus_id, sizeof(info->bus_info)); + strlcpy(info->bus_info, dev->dev.parent->bus_id, sizeof(info->bus_info)); } static const struct ethtool_ops at91ether_ethtool_ops = { diff --git a/drivers/net/arm/ether1.c b/drivers/net/arm/ether1.c index d6da3ce..a292188 100644 --- a/drivers/net/arm/ether1.c +++ b/drivers/net/arm/ether1.c @@ -33,7 +33,6 @@ #include #include -#include #include #include #include diff --git a/drivers/net/arm/ether3.c b/drivers/net/arm/ether3.c index 4fc2347..8411783 100644 --- a/drivers/net/arm/ether3.c +++ b/drivers/net/arm/ether3.c @@ -48,7 +48,6 @@ #include #include -#include #include #include #include diff --git a/drivers/net/arm/etherh.c b/drivers/net/arm/etherh.c index f3faa4f..61f574a 100644 --- a/drivers/net/arm/etherh.c +++ b/drivers/net/arm/etherh.c @@ -28,7 +28,6 @@ #include #include -#include #include #include #include @@ -587,7 +586,7 @@ static void etherh_get_drvinfo(struct ne { strlcpy(info->driver, DRV_NAME, sizeof(info->driver)); strlcpy(info->version, DRV_VERSION, sizeof(info->version)); - strlcpy(info->bus_info, dev->class_dev.dev->bus_id, + strlcpy(info->bus_info, dev->dev.parent->bus_id, sizeof(info->bus_info)); } diff --git a/drivers/net/atl1/Makefile b/drivers/net/atl1/Makefile new file mode 100644 index 0000000..a6b707e --- /dev/null +++ b/drivers/net/atl1/Makefile @@ -0,0 +1,2 @@ +obj-$(CONFIG_ATL1) += atl1.o +atl1-y += atl1_main.o atl1_hw.o atl1_ethtool.o atl1_param.o diff --git a/drivers/net/atl1/atl1.h b/drivers/net/atl1/atl1.h new file mode 100644 index 0000000..b1c6034 --- /dev/null +++ b/drivers/net/atl1/atl1.h @@ -0,0 +1,283 @@ +/* + * Copyright(c) 2005 - 2006 Attansic Corporation. All rights reserved. + * Copyright(c) 2006 Chris Snook + * Copyright(c) 2006 Jay Cliburn + * + * Derived from Intel e1000 driver + * Copyright(c) 1999 - 2005 Intel Corporation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the Free + * Software Foundation; either version 2 of the License, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef _ATL1_H_ +#define _ATL1_H_ + +#include +#include + +#include "atl1_hw.h" + +/* function prototypes needed by multiple files */ +s32 atl1_up(struct atl1_adapter *adapter); +void atl1_down(struct atl1_adapter *adapter); +int atl1_reset(struct atl1_adapter *adapter); +s32 atl1_setup_ring_resources(struct atl1_adapter *adapter); +void atl1_free_ring_resources(struct atl1_adapter *adapter); + +extern char atl1_driver_name[]; +extern char atl1_driver_version[]; +extern const struct ethtool_ops atl1_ethtool_ops; + +struct atl1_adapter; + +#define ATL1_MAX_INTR 3 + +#define ATL1_DEFAULT_TPD 256 +#define ATL1_MAX_TPD 1024 +#define ATL1_MIN_TPD 64 +#define ATL1_DEFAULT_RFD 512 +#define ATL1_MIN_RFD 128 +#define ATL1_MAX_RFD 2048 + +#define ATL1_GET_DESC(R, i, type) (&(((type *)((R)->desc))[i])) +#define ATL1_RFD_DESC(R, i) ATL1_GET_DESC(R, i, struct rx_free_desc) +#define ATL1_TPD_DESC(R, i) ATL1_GET_DESC(R, i, struct tx_packet_desc) +#define ATL1_RRD_DESC(R, i) ATL1_GET_DESC(R, i, struct rx_return_desc) + +/* + * Some workarounds require millisecond delays and are run during interrupt + * context. Most notably, when establishing link, the phy may need tweaking + * but cannot process phy register reads/writes faster than millisecond + * intervals...and we establish link due to a "link status change" interrupt. + */ + +/* + * wrapper around a pointer to a socket buffer, + * so a DMA handle can be stored along with the buffer + */ +struct atl1_buffer { + struct sk_buff *skb; + u16 length; + u16 alloced; + dma_addr_t dma; +}; + +#define MAX_TX_BUF_LEN 0x3000 /* 12KB */ + +struct atl1_tpd_ring { + void *desc; /* pointer to the descriptor ring memory */ + dma_addr_t dma; /* physical adress of the descriptor ring */ + u16 size; /* length of descriptor ring in bytes */ + u16 count; /* number of descriptors in the ring */ + u16 hw_idx; /* hardware index */ + atomic_t next_to_clean; + atomic_t next_to_use; + struct atl1_buffer *buffer_info; +}; + +struct atl1_rfd_ring { + void *desc; + dma_addr_t dma; + u16 size; + u16 count; + atomic_t next_to_use; + u16 next_to_clean; + struct atl1_buffer *buffer_info; +}; + +struct atl1_rrd_ring { + void *desc; + dma_addr_t dma; + unsigned int size; + u16 count; + u16 next_to_use; + atomic_t next_to_clean; +}; + +struct atl1_ring_header { + void *desc; /* pointer to the descriptor ring memory */ + dma_addr_t dma; /* physical adress of the descriptor ring */ + unsigned int size; /* length of descriptor ring in bytes */ +}; + +struct atl1_cmb { + struct coals_msg_block *cmb; + dma_addr_t dma; +}; + +struct atl1_smb { + struct stats_msg_block *smb; + dma_addr_t dma; +}; + +/* Statistics counters */ +struct atl1_sft_stats { + u64 rx_packets; + u64 tx_packets; + u64 rx_bytes; + u64 tx_bytes; + u64 multicast; + u64 collisions; + u64 rx_errors; + u64 rx_length_errors; + u64 rx_crc_errors; + u64 rx_frame_errors; + u64 rx_fifo_errors; + u64 rx_missed_errors; + u64 tx_errors; + u64 tx_fifo_errors; + u64 tx_aborted_errors; + u64 tx_window_errors; + u64 tx_carrier_errors; + + u64 tx_pause; /* num Pause packet transmitted. */ + u64 excecol; /* num tx packets aborted due to excessive collisions. */ + u64 deffer; /* num deferred tx packets */ + u64 scc; /* num packets subsequently transmitted successfully w/ single prior collision. */ + u64 mcc; /* num packets subsequently transmitted successfully w/ multiple prior collisions. */ + u64 latecol; /* num tx packets w/ late collisions. */ + u64 tx_underun; /* num tx packets aborted due to transmit FIFO underrun, or TRD FIFO underrun */ + u64 tx_trunc; /* num tx packets truncated due to size exceeding MTU, regardless whether truncated by Selene or not. (The name doesn't really reflect the meaning in this case.) */ + u64 rx_pause; /* num Pause packets received. */ + u64 rx_rrd_ov; + u64 rx_trunc; +}; + +/* board specific private data structure */ +#define ATL1_REGS_LEN 8 + +/* Structure containing variables used by the shared code */ +struct atl1_hw { + u8 __iomem *hw_addr; + struct atl1_adapter *back; + enum atl1_dma_order dma_ord; + enum atl1_dma_rcb rcb_value; + enum atl1_dma_req_block dmar_block; + enum atl1_dma_req_block dmaw_block; + u8 preamble_len; + u8 max_retry; /* Retransmission maximum, after which the packet will be discarded */ + u8 jam_ipg; /* IPG to start JAM for collision based flow control in half-duplex mode. In units of 8-bit time */ + u8 ipgt; /* Desired back to back inter-packet gap. The default is 96-bit time */ + u8 min_ifg; /* Minimum number of IFG to enforce in between RX frames. Frame gap below such IFP is dropped */ + u8 ipgr1; /* 64bit Carrier-Sense window */ + u8 ipgr2; /* 96-bit IPG window */ + u8 tpd_burst; /* Number of TPD to prefetch in cache-aligned burst. Each TPD is 16 bytes long */ + u8 rfd_burst; /* Number of RFD to prefetch in cache-aligned burst. Each RFD is 12 bytes long */ + u8 rfd_fetch_gap; + u8 rrd_burst; /* Threshold number of RRDs that can be retired in a burst. Each RRD is 16 bytes long */ + u8 tpd_fetch_th; + u8 tpd_fetch_gap; + u16 tx_jumbo_task_th; + u16 txf_burst; /* Number of data bytes to read in a cache-aligned burst. Each SRAM entry is + 8 bytes long */ + u16 rx_jumbo_th; /* Jumbo packet size for non-VLAN packet. VLAN packets should add 4 bytes */ + u16 rx_jumbo_lkah; + u16 rrd_ret_timer; /* RRD retirement timer. Decrement by 1 after every 512ns passes. */ + u16 lcol; /* Collision Window */ + + u16 cmb_tpd; + u16 cmb_rrd; + u16 cmb_rx_timer; + u16 cmb_tx_timer; + u32 smb_timer; + u16 media_type; + u16 autoneg_advertised; + u16 pci_cmd_word; + + u16 mii_autoneg_adv_reg; + u16 mii_1000t_ctrl_reg; + + u32 mem_rang; + u32 txcw; + u32 max_frame_size; + u32 min_frame_size; + u32 mc_filter_type; + u32 num_mc_addrs; + u32 collision_delta; + u32 tx_packet_delta; + u16 phy_spd_default; + + u16 dev_rev; + u8 revision_id; + + /* spi flash */ + u8 flash_vendor; + + u8 dma_fairness; + u8 mac_addr[ETH_ALEN]; + u8 perm_mac_addr[ETH_ALEN]; + + /* bool phy_preamble_sup; */ + bool phy_configured; +}; + +struct atl1_adapter { + /* OS defined structs */ + struct net_device *netdev; + struct pci_dev *pdev; + struct net_device_stats net_stats; + struct atl1_sft_stats soft_stats; + + struct vlan_group *vlgrp; + u32 rx_buffer_len; + u32 wol; + u16 link_speed; + u16 link_duplex; + spinlock_t lock; + atomic_t irq_sem; + struct work_struct tx_timeout_task; + struct work_struct link_chg_task; + struct work_struct pcie_dma_to_rst_task; + struct timer_list watchdog_timer; + struct timer_list phy_config_timer; + bool phy_timer_pending; + + bool mac_disabled; + + /* All descriptor rings' memory */ + struct atl1_ring_header ring_header; + + /* TX */ + struct atl1_tpd_ring tpd_ring; + spinlock_t mb_lock; + + /* RX */ + struct atl1_rfd_ring rfd_ring; + struct atl1_rrd_ring rrd_ring; + u64 hw_csum_err; + u64 hw_csum_good; + + u32 gorcl; + u64 gorcl_old; + + /* Interrupt Moderator timer ( 2us resolution) */ + u16 imt; + /* Interrupt Clear timer (2us resolution) */ + u16 ict; + + /* MII interface info */ + struct mii_if_info mii; + + /* structs defined in atl1_hw.h */ + u32 bd_number; /* board number */ + bool pci_using_64; + struct atl1_hw hw; + struct atl1_smb smb; + struct atl1_cmb cmb; + + u32 pci_state[16]; +}; + +#endif /* _ATL1_H_ */ diff --git a/drivers/net/atl1/atl1_ethtool.c b/drivers/net/atl1/atl1_ethtool.c new file mode 100644 index 0000000..c11c277 --- /dev/null +++ b/drivers/net/atl1/atl1_ethtool.c @@ -0,0 +1,508 @@ +/* + * Copyright(c) 2005 - 2006 Attansic Corporation. All rights reserved. + * Copyright(c) 2006 Chris Snook + * Copyright(c) 2006 Jay Cliburn + * + * Derived from Intel e1000 driver + * Copyright(c) 1999 - 2005 Intel Corporation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the Free + * Software Foundation; either version 2 of the License, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#include +#include +#include +#include +#include +#include + +#include "atl1.h" + +struct atl1_stats { + char stat_string[ETH_GSTRING_LEN]; + int sizeof_stat; + int stat_offset; +}; + +#define ATL1_STAT(m) sizeof(((struct atl1_adapter *)0)->m), \ + offsetof(struct atl1_adapter, m) + +static struct atl1_stats atl1_gstrings_stats[] = { + {"rx_packets", ATL1_STAT(soft_stats.rx_packets)}, + {"tx_packets", ATL1_STAT(soft_stats.tx_packets)}, + {"rx_bytes", ATL1_STAT(soft_stats.rx_bytes)}, + {"tx_bytes", ATL1_STAT(soft_stats.tx_bytes)}, + {"rx_errors", ATL1_STAT(soft_stats.rx_errors)}, + {"tx_errors", ATL1_STAT(soft_stats.tx_errors)}, + {"rx_dropped", ATL1_STAT(net_stats.rx_dropped)}, + {"tx_dropped", ATL1_STAT(net_stats.tx_dropped)}, + {"multicast", ATL1_STAT(soft_stats.multicast)}, + {"collisions", ATL1_STAT(soft_stats.collisions)}, + {"rx_length_errors", ATL1_STAT(soft_stats.rx_length_errors)}, + {"rx_over_errors", ATL1_STAT(soft_stats.rx_missed_errors)}, + {"rx_crc_errors", ATL1_STAT(soft_stats.rx_crc_errors)}, + {"rx_frame_errors", ATL1_STAT(soft_stats.rx_frame_errors)}, + {"rx_fifo_errors", ATL1_STAT(soft_stats.rx_fifo_errors)}, + {"rx_missed_errors", ATL1_STAT(soft_stats.rx_missed_errors)}, + {"tx_aborted_errors", ATL1_STAT(soft_stats.tx_aborted_errors)}, + {"tx_carrier_errors", ATL1_STAT(soft_stats.tx_carrier_errors)}, + {"tx_fifo_errors", ATL1_STAT(soft_stats.tx_fifo_errors)}, + {"tx_window_errors", ATL1_STAT(soft_stats.tx_window_errors)}, + {"tx_abort_exce_coll", ATL1_STAT(soft_stats.excecol)}, + {"tx_abort_late_coll", ATL1_STAT(soft_stats.latecol)}, + {"tx_deferred_ok", ATL1_STAT(soft_stats.deffer)}, + {"tx_single_coll_ok", ATL1_STAT(soft_stats.scc)}, + {"tx_multi_coll_ok", ATL1_STAT(soft_stats.mcc)}, + {"tx_underun", ATL1_STAT(soft_stats.tx_underun)}, + {"tx_trunc", ATL1_STAT(soft_stats.tx_trunc)}, + {"tx_pause", ATL1_STAT(soft_stats.tx_pause)}, + {"rx_pause", ATL1_STAT(soft_stats.rx_pause)}, + {"rx_rrd_ov", ATL1_STAT(soft_stats.rx_rrd_ov)}, + {"rx_trunc", ATL1_STAT(soft_stats.rx_trunc)} +}; + +static void atl1_get_ethtool_stats(struct net_device *netdev, + struct ethtool_stats *stats, u64 *data) +{ + struct atl1_adapter *adapter = netdev_priv(netdev); + int i; + char *p; + + for (i = 0; i < ARRAY_SIZE(atl1_gstrings_stats); i++) { + p = (char *)adapter+atl1_gstrings_stats[i].stat_offset; + data[i] = (atl1_gstrings_stats[i].sizeof_stat == + sizeof(u64)) ? *(u64 *)p : *(u32 *)p; + } + +} + +static int atl1_get_stats_count(struct net_device *netdev) +{ + return ARRAY_SIZE(atl1_gstrings_stats); +} + +static int atl1_get_settings(struct net_device *netdev, + struct ethtool_cmd *ecmd) +{ + struct atl1_adapter *adapter = netdev_priv(netdev); + struct atl1_hw *hw = &adapter->hw; + + ecmd->supported = (SUPPORTED_10baseT_Half | + SUPPORTED_10baseT_Full | + SUPPORTED_100baseT_Half | + SUPPORTED_100baseT_Full | + SUPPORTED_1000baseT_Full | + SUPPORTED_Autoneg | SUPPORTED_TP); + ecmd->advertising = ADVERTISED_TP; + if (hw->media_type == MEDIA_TYPE_AUTO_SENSOR || + hw->media_type == MEDIA_TYPE_1000M_FULL) { + ecmd->advertising |= ADVERTISED_Autoneg; + if (hw->media_type == MEDIA_TYPE_AUTO_SENSOR) { + ecmd->advertising |= ADVERTISED_Autoneg; + ecmd->advertising |= + (ADVERTISED_10baseT_Half | + ADVERTISED_10baseT_Full | + ADVERTISED_100baseT_Half | + ADVERTISED_100baseT_Full | + ADVERTISED_1000baseT_Full); + } + else + ecmd->advertising |= (ADVERTISED_1000baseT_Full); + } + ecmd->port = PORT_TP; + ecmd->phy_address = 0; + ecmd->transceiver = XCVR_INTERNAL; + + if (netif_carrier_ok(adapter->netdev)) { + u16 link_speed, link_duplex; + atl1_get_speed_and_duplex(hw, &link_speed, &link_duplex); + ecmd->speed = link_speed; + if (link_duplex == FULL_DUPLEX) + ecmd->duplex = DUPLEX_FULL; + else + ecmd->duplex = DUPLEX_HALF; + } else { + ecmd->speed = -1; + ecmd->duplex = -1; + } + if (hw->media_type == MEDIA_TYPE_AUTO_SENSOR || + hw->media_type == MEDIA_TYPE_1000M_FULL) + ecmd->autoneg = AUTONEG_ENABLE; + else + ecmd->autoneg = AUTONEG_DISABLE; + + return 0; +} + +static int atl1_set_settings(struct net_device *netdev, + struct ethtool_cmd *ecmd) +{ + struct atl1_adapter *adapter = netdev_priv(netdev); + struct atl1_hw *hw = &adapter->hw; + u16 phy_data; + int ret_val = 0; + u16 old_media_type = hw->media_type; + + if (netif_running(adapter->netdev)) { + printk(KERN_DEBUG "%s: ethtool shutting down adapter\n", + atl1_driver_name); + atl1_down(adapter); + } + + if (ecmd->autoneg == AUTONEG_ENABLE) + hw->media_type = MEDIA_TYPE_AUTO_SENSOR; + else { + if (ecmd->speed == SPEED_1000) { + if (ecmd->duplex != DUPLEX_FULL) { + printk(KERN_WARNING + "%s: can't force to 1000M half duplex\n", + atl1_driver_name); + ret_val = -EINVAL; + goto exit_sset; + } + hw->media_type = MEDIA_TYPE_1000M_FULL; + } else if (ecmd->speed == SPEED_100) { + if (ecmd->duplex == DUPLEX_FULL) { + hw->media_type = MEDIA_TYPE_100M_FULL; + } else + hw->media_type = MEDIA_TYPE_100M_HALF; + } else { + if (ecmd->duplex == DUPLEX_FULL) + hw->media_type = MEDIA_TYPE_10M_FULL; + else + hw->media_type = MEDIA_TYPE_10M_HALF; + } + } + switch (hw->media_type) { + case MEDIA_TYPE_AUTO_SENSOR: + ecmd->advertising = + ADVERTISED_10baseT_Half | + ADVERTISED_10baseT_Full | + ADVERTISED_100baseT_Half | + ADVERTISED_100baseT_Full | + ADVERTISED_1000baseT_Full | + ADVERTISED_Autoneg | ADVERTISED_TP; + break; + case MEDIA_TYPE_1000M_FULL: + ecmd->advertising = + ADVERTISED_1000baseT_Full | + ADVERTISED_Autoneg | ADVERTISED_TP; + break; + default: + ecmd->advertising = 0; + break; + } + if (atl1_phy_setup_autoneg_adv(hw)) { + ret_val = -EINVAL; + printk(KERN_WARNING + "%s: invalid ethtool speed/duplex setting\n", + atl1_driver_name); + goto exit_sset; + } + if (hw->media_type == MEDIA_TYPE_AUTO_SENSOR || + hw->media_type == MEDIA_TYPE_1000M_FULL) + phy_data = MII_CR_RESET | MII_CR_AUTO_NEG_EN; + else { + switch (hw->media_type) { + case MEDIA_TYPE_100M_FULL: + phy_data = + MII_CR_FULL_DUPLEX | MII_CR_SPEED_100 | + MII_CR_RESET; + break; + case MEDIA_TYPE_100M_HALF: + phy_data = MII_CR_SPEED_100 | MII_CR_RESET; + break; + case MEDIA_TYPE_10M_FULL: + phy_data = + MII_CR_FULL_DUPLEX | MII_CR_SPEED_10 | MII_CR_RESET; + break; + default: /* MEDIA_TYPE_10M_HALF: */ + phy_data = MII_CR_SPEED_10 | MII_CR_RESET; + break; + } + } + atl1_write_phy_reg(hw, MII_BMCR, phy_data); +exit_sset: + if (ret_val) + hw->media_type = old_media_type; + + if (netif_running(adapter->netdev)) { + printk(KERN_DEBUG "%s: ethtool starting adapter\n", + atl1_driver_name); + atl1_up(adapter); + } else if (!ret_val) { + printk(KERN_DEBUG "%s: ethtool resetting adapter\n", + atl1_driver_name); + atl1_reset(adapter); + } + return ret_val; +} + +static void atl1_get_drvinfo(struct net_device *netdev, + struct ethtool_drvinfo *drvinfo) +{ + struct atl1_adapter *adapter = netdev_priv(netdev); + + strncpy(drvinfo->driver, atl1_driver_name, sizeof(drvinfo->driver)); + strncpy(drvinfo->version, atl1_driver_version, + sizeof(drvinfo->version)); + strncpy(drvinfo->fw_version, "N/A", sizeof(drvinfo->fw_version)); + strncpy(drvinfo->bus_info, pci_name(adapter->pdev), + sizeof(drvinfo->bus_info)); + drvinfo->eedump_len = ATL1_EEDUMP_LEN; +} + +static void atl1_get_wol(struct net_device *netdev, + struct ethtool_wolinfo *wol) +{ + struct atl1_adapter *adapter = netdev_priv(netdev); + + wol->supported = WAKE_UCAST | WAKE_MCAST | WAKE_BCAST | WAKE_MAGIC; + wol->wolopts = 0; + if (adapter->wol & ATL1_WUFC_EX) + wol->wolopts |= WAKE_UCAST; + if (adapter->wol & ATL1_WUFC_MC) + wol->wolopts |= WAKE_MCAST; + if (adapter->wol & ATL1_WUFC_BC) + wol->wolopts |= WAKE_BCAST; + if (adapter->wol & ATL1_WUFC_MAG) + wol->wolopts |= WAKE_MAGIC; + return; +} + +static int atl1_set_wol(struct net_device *netdev, + struct ethtool_wolinfo *wol) +{ + struct atl1_adapter *adapter = netdev_priv(netdev); + + if (wol->wolopts & (WAKE_PHY | WAKE_ARP | WAKE_MAGICSECURE)) + return -EOPNOTSUPP; + adapter->wol = 0; + if (wol->wolopts & WAKE_UCAST) + adapter->wol |= ATL1_WUFC_EX; + if (wol->wolopts & WAKE_MCAST) + adapter->wol |= ATL1_WUFC_MC; + if (wol->wolopts & WAKE_BCAST) + adapter->wol |= ATL1_WUFC_BC; + if (wol->wolopts & WAKE_MAGIC) + adapter->wol |= ATL1_WUFC_MAG; + return 0; +} + +static void atl1_get_ringparam(struct net_device *netdev, + struct ethtool_ringparam *ring) +{ + struct atl1_adapter *adapter = netdev_priv(netdev); + struct atl1_tpd_ring *txdr = &adapter->tpd_ring; + struct atl1_rfd_ring *rxdr = &adapter->rfd_ring; + + ring->rx_max_pending = ATL1_MAX_RFD; + ring->tx_max_pending = ATL1_MAX_TPD; + ring->rx_mini_max_pending = 0; + ring->rx_jumbo_max_pending = 0; + ring->rx_pending = rxdr->count; + ring->tx_pending = txdr->count; + ring->rx_mini_pending = 0; + ring->rx_jumbo_pending = 0; +} + +static int atl1_set_ringparam(struct net_device *netdev, + struct ethtool_ringparam *ring) +{ + struct atl1_adapter *adapter = netdev_priv(netdev); + struct atl1_tpd_ring *tpdr = &adapter->tpd_ring; + struct atl1_rrd_ring *rrdr = &adapter->rrd_ring; + struct atl1_rfd_ring *rfdr = &adapter->rfd_ring; + + struct atl1_tpd_ring tpd_old, tpd_new; + struct atl1_rfd_ring rfd_old, rfd_new; + struct atl1_rrd_ring rrd_old, rrd_new; + struct atl1_ring_header rhdr_old, rhdr_new; + int err; + + tpd_old = adapter->tpd_ring; + rfd_old = adapter->rfd_ring; + rrd_old = adapter->rrd_ring; + rhdr_old = adapter->ring_header; + + if (netif_running(adapter->netdev)) + atl1_down(adapter); + + rfdr->count = (u16) max(ring->rx_pending, (u32) ATL1_MIN_RFD); + rfdr->count = rfdr->count > ATL1_MAX_RFD ? ATL1_MAX_RFD : + rfdr->count; + rfdr->count = (rfdr->count + 3) & ~3; + rrdr->count = rfdr->count; + + tpdr->count = (u16) max(ring->tx_pending, (u32) ATL1_MIN_TPD); + tpdr->count = tpdr->count > ATL1_MAX_TPD ? ATL1_MAX_TPD : + tpdr->count; + tpdr->count = (tpdr->count + 3) & ~3; + + if (netif_running(adapter->netdev)) { + /* try to get new resources before deleting old */ + err = atl1_setup_ring_resources(adapter); + if (err) + goto err_setup_ring; + + /* + * save the new, restore the old in order to free it, + * then restore the new back again + */ + + rfd_new = adapter->rfd_ring; + rrd_new = adapter->rrd_ring; + tpd_new = adapter->tpd_ring; + rhdr_new = adapter->ring_header; + adapter->rfd_ring = rfd_old; + adapter->rrd_ring = rrd_old; + adapter->tpd_ring = tpd_old; + adapter->ring_header = rhdr_old; + atl1_free_ring_resources(adapter); + adapter->rfd_ring = rfd_new; + adapter->rrd_ring = rrd_new; + adapter->tpd_ring = tpd_new; + adapter->ring_header = rhdr_new; + + err = atl1_up(adapter); + if (err) + return err; + } + return 0; + +err_setup_ring: + adapter->rfd_ring = rfd_old; + adapter->rrd_ring = rrd_old; + adapter->tpd_ring = tpd_old; + adapter->ring_header = rhdr_old; + atl1_up(adapter); + return err; +} + +static void atl1_get_pauseparam(struct net_device *netdev, + struct ethtool_pauseparam *epause) +{ + struct atl1_adapter *adapter = netdev_priv(netdev); + struct atl1_hw *hw = &adapter->hw; + + if (hw->media_type == MEDIA_TYPE_AUTO_SENSOR || + hw->media_type == MEDIA_TYPE_1000M_FULL) { + epause->autoneg = AUTONEG_ENABLE; + } else { + epause->autoneg = AUTONEG_DISABLE; + } + epause->rx_pause = 1; + epause->tx_pause = 1; +} + +static int atl1_set_pauseparam(struct net_device *netdev, + struct ethtool_pauseparam *epause) +{ + struct atl1_adapter *adapter = netdev_priv(netdev); + struct atl1_hw *hw = &adapter->hw; + + if (hw->media_type == MEDIA_TYPE_AUTO_SENSOR || + hw->media_type == MEDIA_TYPE_1000M_FULL) { + epause->autoneg = AUTONEG_ENABLE; + } else { + epause->autoneg = AUTONEG_DISABLE; + } + + epause->rx_pause = 1; + epause->tx_pause = 1; + + return 0; +} + +static u32 atl1_get_rx_csum(struct net_device *netdev) +{ + return 1; +} + +static void atl1_get_strings(struct net_device *netdev, u32 stringset, + u8 *data) +{ + u8 *p = data; + int i; + + switch (stringset) { + case ETH_SS_STATS: + for (i = 0; i < ARRAY_SIZE(atl1_gstrings_stats); i++) { + memcpy(p, atl1_gstrings_stats[i].stat_string, + ETH_GSTRING_LEN); + p += ETH_GSTRING_LEN; + } + break; + } +} + +static int atl1_nway_reset(struct net_device *netdev) +{ + struct atl1_adapter *adapter = netdev_priv(netdev); + struct atl1_hw *hw = &adapter->hw; + + if (netif_running(netdev)) { + u16 phy_data; + atl1_down(adapter); + + if (hw->media_type == MEDIA_TYPE_AUTO_SENSOR || + hw->media_type == MEDIA_TYPE_1000M_FULL) { + phy_data = MII_CR_RESET | MII_CR_AUTO_NEG_EN; + } else { + switch (hw->media_type) { + case MEDIA_TYPE_100M_FULL: + phy_data = MII_CR_FULL_DUPLEX | + MII_CR_SPEED_100 | MII_CR_RESET; + break; + case MEDIA_TYPE_100M_HALF: + phy_data = MII_CR_SPEED_100 | MII_CR_RESET; + break; + case MEDIA_TYPE_10M_FULL: + phy_data = MII_CR_FULL_DUPLEX | + MII_CR_SPEED_10 | MII_CR_RESET; + break; + default: /* MEDIA_TYPE_10M_HALF */ + phy_data = MII_CR_SPEED_10 | MII_CR_RESET; + } + } + atl1_write_phy_reg(hw, MII_BMCR, phy_data); + atl1_up(adapter); + } + return 0; +} + +const struct ethtool_ops atl1_ethtool_ops = { + .get_settings = atl1_get_settings, + .set_settings = atl1_set_settings, + .get_drvinfo = atl1_get_drvinfo, + .get_wol = atl1_get_wol, + .set_wol = atl1_set_wol, + .get_ringparam = atl1_get_ringparam, + .set_ringparam = atl1_set_ringparam, + .get_pauseparam = atl1_get_pauseparam, + .set_pauseparam = atl1_set_pauseparam, + .get_rx_csum = atl1_get_rx_csum, + .get_tx_csum = ethtool_op_get_tx_csum, + .set_tx_csum = ethtool_op_set_tx_hw_csum, + .get_link = ethtool_op_get_link, + .get_sg = ethtool_op_get_sg, + .set_sg = ethtool_op_set_sg, + .get_strings = atl1_get_strings, + .nway_reset = atl1_nway_reset, + .get_ethtool_stats = atl1_get_ethtool_stats, + .get_stats_count = atl1_get_stats_count, + .get_tso = ethtool_op_get_tso, + .set_tso = ethtool_op_set_tso, +}; diff --git a/drivers/net/atl1/atl1_hw.c b/drivers/net/atl1/atl1_hw.c new file mode 100644 index 0000000..08b2d78 --- /dev/null +++ b/drivers/net/atl1/atl1_hw.c @@ -0,0 +1,718 @@ +/* + * Copyright(c) 2005 - 2006 Attansic Corporation. All rights reserved. + * Copyright(c) 2006 Chris Snook + * Copyright(c) 2006 Jay Cliburn + * + * Derived from Intel e1000 driver + * Copyright(c) 1999 - 2005 Intel Corporation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the Free + * Software Foundation; either version 2 of the License, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#include +#include +#include +#include +#include +#include +#include + +#include "atl1.h" + +/* + * Reset the transmit and receive units; mask and clear all interrupts. + * hw - Struct containing variables accessed by shared code + * return : ATL1_SUCCESS or idle status (if error) + */ +s32 atl1_reset_hw(struct atl1_hw *hw) +{ + u32 icr; + int i; + + /* + * Clear Interrupt mask to stop board from generating + * interrupts & Clear any pending interrupt events + */ + /* + * iowrite32(0, hw->hw_addr + REG_IMR); + * iowrite32(0xffffffff, hw->hw_addr + REG_ISR); + */ + + /* + * Issue Soft Reset to the MAC. This will reset the chip's + * transmit, receive, DMA. It will not effect + * the current PCI configuration. The global reset bit is self- + * clearing, and should clear within a microsecond. + */ + iowrite32(MASTER_CTRL_SOFT_RST, hw->hw_addr + REG_MASTER_CTRL); + ioread32(hw->hw_addr + REG_MASTER_CTRL); + + iowrite16(1, hw->hw_addr + REG_GPHY_ENABLE); + ioread16(hw->hw_addr + REG_GPHY_ENABLE); + + msleep(1); /* delay about 1ms */ + + /* Wait at least 10ms for All module to be Idle */ + for (i = 0; i < 10; i++) { + icr = ioread32(hw->hw_addr + REG_IDLE_STATUS); + if (!icr) + break; + msleep(1); /* delay 1 ms */ + cpu_relax(); /* FIXME: is this still the right way to do this? */ + } + + if (icr) { + printk (KERN_DEBUG "icr = %x\n", icr); + return icr; + } + + return ATL1_SUCCESS; +} + +/* function about EEPROM + * + * check_eeprom_exist + * return 0 if eeprom exist + */ +static int atl1_check_eeprom_exist(struct atl1_hw *hw) +{ + u32 value; + value = ioread32(hw->hw_addr + REG_SPI_FLASH_CTRL); + if (value & SPI_FLASH_CTRL_EN_VPD) { + value &= ~SPI_FLASH_CTRL_EN_VPD; + iowrite32(value, hw->hw_addr + REG_SPI_FLASH_CTRL); + } + + value = ioread16(hw->hw_addr + REG_PCIE_CAP_LIST); + return ((value & 0xFF00) == 0x6C00) ? 0 : 1; +} + +static bool atl1_read_eeprom(struct atl1_hw *hw, u32 offset, u32 *p_value) +{ + int i; + u32 control; + + if (offset & 3) + return false; /* address do not align */ + + iowrite32(0, hw->hw_addr + REG_VPD_DATA); + control = (offset & VPD_CAP_VPD_ADDR_MASK) << VPD_CAP_VPD_ADDR_SHIFT; + iowrite32(control, hw->hw_addr + REG_VPD_CAP); + ioread32(hw->hw_addr + REG_VPD_CAP); + + for (i = 0; i < 10; i++) { + msleep(2); + control = ioread32(hw->hw_addr + REG_VPD_CAP); + if (control & VPD_CAP_VPD_FLAG) + break; + } + if (control & VPD_CAP_VPD_FLAG) { + *p_value = ioread32(hw->hw_addr + REG_VPD_DATA); + return true; + } + return false; /* timeout */ +} + +/* + * Reads the value from a PHY register + * hw - Struct containing variables accessed by shared code + * reg_addr - address of the PHY register to read + */ +s32 atl1_read_phy_reg(struct atl1_hw *hw, u16 reg_addr, u16 *phy_data) +{ + u32 val; + int i; + + val = ((u32) (reg_addr & MDIO_REG_ADDR_MASK)) << MDIO_REG_ADDR_SHIFT | + MDIO_START | MDIO_SUP_PREAMBLE | MDIO_RW | MDIO_CLK_25_4 << + MDIO_CLK_SEL_SHIFT; + iowrite32(val, hw->hw_addr + REG_MDIO_CTRL); + ioread32(hw->hw_addr + REG_MDIO_CTRL); + + for (i = 0; i < MDIO_WAIT_TIMES; i++) { + udelay(2); + val = ioread32(hw->hw_addr + REG_MDIO_CTRL); + if (!(val & (MDIO_START | MDIO_BUSY))) + break; + } + if (!(val & (MDIO_START | MDIO_BUSY))) { + *phy_data = (u16) val; + return ATL1_SUCCESS; + } + return ATL1_ERR_PHY; +} + +#define CUSTOM_SPI_CS_SETUP 2 +#define CUSTOM_SPI_CLK_HI 2 +#define CUSTOM_SPI_CLK_LO 2 +#define CUSTOM_SPI_CS_HOLD 2 +#define CUSTOM_SPI_CS_HI 3 + +static bool atl1_spi_read(struct atl1_hw *hw, u32 addr, u32 *buf) +{ + int i; + u32 value; + + iowrite32(0, hw->hw_addr + REG_SPI_DATA); + iowrite32(addr, hw->hw_addr + REG_SPI_ADDR); + + value = SPI_FLASH_CTRL_WAIT_READY | + (CUSTOM_SPI_CS_SETUP & SPI_FLASH_CTRL_CS_SETUP_MASK) << + SPI_FLASH_CTRL_CS_SETUP_SHIFT | (CUSTOM_SPI_CLK_HI & + SPI_FLASH_CTRL_CLK_HI_MASK) << + SPI_FLASH_CTRL_CLK_HI_SHIFT | (CUSTOM_SPI_CLK_LO & + SPI_FLASH_CTRL_CLK_LO_MASK) << + SPI_FLASH_CTRL_CLK_LO_SHIFT | (CUSTOM_SPI_CS_HOLD & + SPI_FLASH_CTRL_CS_HOLD_MASK) << + SPI_FLASH_CTRL_CS_HOLD_SHIFT | (CUSTOM_SPI_CS_HI & + SPI_FLASH_CTRL_CS_HI_MASK) << + SPI_FLASH_CTRL_CS_HI_SHIFT | (1 & SPI_FLASH_CTRL_INS_MASK) << + SPI_FLASH_CTRL_INS_SHIFT; + + iowrite32(value, hw->hw_addr + REG_SPI_FLASH_CTRL); + + value |= SPI_FLASH_CTRL_START; + iowrite32(value, hw->hw_addr + REG_SPI_FLASH_CTRL); + ioread32(hw->hw_addr + REG_SPI_FLASH_CTRL); + + for (i = 0; i < 10; i++) { + msleep(1); /* 1ms */ + value = ioread32(hw->hw_addr + REG_SPI_FLASH_CTRL); + if (!(value & SPI_FLASH_CTRL_START)) + break; + } + + if (value & SPI_FLASH_CTRL_START) + return false; + + *buf = ioread32(hw->hw_addr + REG_SPI_DATA); + + return true; +} + +/* + * get_permanent_address + * return 0 if get valid mac address, + */ +static int atl1_get_permanent_address(struct atl1_hw *hw) +{ + u32 addr[2]; + u32 i, control; + u16 reg; + u8 eth_addr[ETH_ALEN]; + bool key_valid; + + if (is_valid_ether_addr(hw->perm_mac_addr)) + return 0; + + /* init */ + addr[0] = addr[1] = 0; + + if (!atl1_check_eeprom_exist(hw)) { /* eeprom exist */ + reg = 0; + key_valid = false; + /* Read out all EEPROM content */ + i = 0; + while (1) { + if (atl1_read_eeprom(hw, i + 0x100, &control)) { + if (key_valid) { + if (reg == REG_MAC_STA_ADDR) + addr[0] = control; + else if (reg == (REG_MAC_STA_ADDR + 4)) + addr[1] = control; + key_valid = false; + } else if ((control & 0xff) == 0x5A) { + key_valid = true; + reg = (u16) (control >> 16); + } else + break; /* assume data end while encount an invalid KEYWORD */ + } else + break; /* read error */ + i += 4; + } + +/* + * The following 2 lines are the Attansic originals. Saving for posterity. + * *(u32 *) & eth_addr[2] = LONGSWAP(addr[0]); + * *(u16 *) & eth_addr[0] = SHORTSWAP(*(u16 *) & addr[1]); + */ + *(u32 *) & eth_addr[2] = swab32(addr[0]); + *(u16 *) & eth_addr[0] = swab16(*(u16 *) & addr[1]); + + if (is_valid_ether_addr(eth_addr)) { + memcpy(hw->perm_mac_addr, eth_addr, ETH_ALEN); + return 0; + } + return 1; + } + + /* see if SPI FLAGS exist ? */ + addr[0] = addr[1] = 0; + reg = 0; + key_valid = false; + i = 0; + while (1) { + if (atl1_spi_read(hw, i + 0x1f000, &control)) { + if (key_valid) { + if (reg == REG_MAC_STA_ADDR) + addr[0] = control; + else if (reg == (REG_MAC_STA_ADDR + 4)) + addr[1] = control; + key_valid = false; + } else if ((control & 0xff) == 0x5A) { + key_valid = true; + reg = (u16) (control >> 16); + } else + break; /* data end */ + } else + break; /* read error */ + i += 4; + } + +/* + * The following 2 lines are the Attansic originals. Saving for posterity. + * *(u32 *) & eth_addr[2] = LONGSWAP(addr[0]); + * *(u16 *) & eth_addr[0] = SHORTSWAP(*(u16 *) & addr[1]); + */ + *(u32 *) & eth_addr[2] = swab32(addr[0]); + *(u16 *) & eth_addr[0] = swab16(*(u16 *) & addr[1]); + if (is_valid_ether_addr(eth_addr)) { + memcpy(hw->perm_mac_addr, eth_addr, ETH_ALEN); + return 0; + } + return 1; +} + +/* + * Reads the adapter's MAC address from the EEPROM + * hw - Struct containing variables accessed by shared code + */ +s32 atl1_read_mac_addr(struct atl1_hw *hw) +{ + u16 i; + + if (atl1_get_permanent_address(hw)) + random_ether_addr(hw->perm_mac_addr); + + for (i = 0; i < ETH_ALEN; i++) + hw->mac_addr[i] = hw->perm_mac_addr[i]; + return ATL1_SUCCESS; +} + +/* + * Hashes an address to determine its location in the multicast table + * hw - Struct containing variables accessed by shared code + * mc_addr - the multicast address to hash + * + * atl1_hash_mc_addr + * purpose + * set hash value for a multicast address + * hash calcu processing : + * 1. calcu 32bit CRC for multicast address + * 2. reverse crc with MSB to LSB + */ +u32 atl1_hash_mc_addr(struct atl1_hw *hw, u8 *mc_addr) +{ + u32 crc32, value = 0; + int i; + + crc32 = ether_crc_le(6, mc_addr); + crc32 = ~crc32; + for (i = 0; i < 32; i++) + value |= (((crc32 >> i) & 1) << (31 - i)); + + return value; +} + +/* + * Sets the bit in the multicast table corresponding to the hash value. + * hw - Struct containing variables accessed by shared code + * hash_value - Multicast address hash value + */ +void atl1_hash_set(struct atl1_hw *hw, u32 hash_value) +{ + u32 hash_bit, hash_reg; + u32 mta; + + /* + * The HASH Table is a register array of 2 32-bit registers. + * It is treated like an array of 64 bits. We want to set + * bit BitArray[hash_value]. So we figure out what register + * the bit is in, read it, OR in the new bit, then write + * back the new value. The register is determined by the + * upper 7 bits of the hash value and the bit within that + * register are determined by the lower 5 bits of the value. + */ + hash_reg = (hash_value >> 31) & 0x1; + hash_bit = (hash_value >> 26) & 0x1F; + mta = ioread32((hw + REG_RX_HASH_TABLE) + (hash_reg << 2)); + mta |= (1 << hash_bit); + iowrite32(mta, (hw->hw_addr + REG_RX_HASH_TABLE) + (hash_reg << 2)); +} + +/* + * Writes a value to a PHY register + * hw - Struct containing variables accessed by shared code + * reg_addr - address of the PHY register to write + * data - data to write to the PHY + */ +s32 atl1_write_phy_reg(struct atl1_hw *hw, u32 reg_addr, u16 phy_data) +{ + int i; + u32 val; + + val = ((u32) (phy_data & MDIO_DATA_MASK)) << MDIO_DATA_SHIFT | + (reg_addr & MDIO_REG_ADDR_MASK) << MDIO_REG_ADDR_SHIFT | + MDIO_SUP_PREAMBLE | + MDIO_START | MDIO_CLK_25_4 << MDIO_CLK_SEL_SHIFT; + iowrite32(val, hw->hw_addr + REG_MDIO_CTRL); + ioread32(hw->hw_addr + REG_MDIO_CTRL); + + for (i = 0; i < MDIO_WAIT_TIMES; i++) { + udelay(2); + val = ioread32(hw->hw_addr + REG_MDIO_CTRL); + if (!(val & (MDIO_START | MDIO_BUSY))) + break; + } + + if (!(val & (MDIO_START | MDIO_BUSY))) + return ATL1_SUCCESS; + + return ATL1_ERR_PHY; +} + +/* + * Make L001's PHY out of Power Saving State (bug) + * hw - Struct containing variables accessed by shared code + * when power on, L001's PHY always on Power saving State + * (Gigabit Link forbidden) + */ +static s32 atl1_phy_leave_power_saving(struct atl1_hw *hw) +{ + s32 ret; + ret = atl1_write_phy_reg(hw, 29, 0x0029); + if (ret) + return ret; + return atl1_write_phy_reg(hw, 30, 0); +} + +/* + *TODO: do something or get rid of this + */ +s32 atl1_phy_enter_power_saving(struct atl1_hw *hw) +{ +/* s32 ret_val; + * u16 phy_data; + */ + +/* + ret_val = atl1_write_phy_reg(hw, ...); + ret_val = atl1_write_phy_reg(hw, ...); + .... +*/ + return ATL1_SUCCESS; +} + +/* + * Resets the PHY and make all config validate + * hw - Struct containing variables accessed by shared code + * + * Sets bit 15 and 12 of the MII Control regiser (for F001 bug) + */ +static s32 atl1_phy_reset(struct atl1_hw *hw) +{ + s32 ret_val; + u16 phy_data; + + if (hw->media_type == MEDIA_TYPE_AUTO_SENSOR || + hw->media_type == MEDIA_TYPE_1000M_FULL) + phy_data = MII_CR_RESET | MII_CR_AUTO_NEG_EN; + else { + switch (hw->media_type) { + case MEDIA_TYPE_100M_FULL: + phy_data = + MII_CR_FULL_DUPLEX | MII_CR_SPEED_100 | + MII_CR_RESET; + break; + case MEDIA_TYPE_100M_HALF: + phy_data = MII_CR_SPEED_100 | MII_CR_RESET; + break; + case MEDIA_TYPE_10M_FULL: + phy_data = + MII_CR_FULL_DUPLEX | MII_CR_SPEED_10 | MII_CR_RESET; + break; + default: /* MEDIA_TYPE_10M_HALF: */ + phy_data = MII_CR_SPEED_10 | MII_CR_RESET; + break; + } + } + + ret_val = atl1_write_phy_reg(hw, MII_BMCR, phy_data); + if (ret_val) { + u32 val; + int i; + /* pcie serdes link may be down! */ + printk(KERN_DEBUG "%s: autoneg caused pcie phy link down\n", + atl1_driver_name); + + for (i = 0; i < 25; i++) { + msleep(1); + val = ioread32(hw->hw_addr + REG_MDIO_CTRL); + if (!(val & (MDIO_START | MDIO_BUSY))) + break; + } + + if ((val & (MDIO_START | MDIO_BUSY)) != 0) { + printk(KERN_WARNING + "%s: pcie link down at least for 25ms\n", + atl1_driver_name); + return ret_val; + } + } + return ATL1_SUCCESS; +} + +/* + * Configures PHY autoneg and flow control advertisement settings + * hw - Struct containing variables accessed by shared code + */ +s32 atl1_phy_setup_autoneg_adv(struct atl1_hw *hw) +{ + s32 ret_val; + s16 mii_autoneg_adv_reg; + s16 mii_1000t_ctrl_reg; + + /* Read the MII Auto-Neg Advertisement Register (Address 4). */ + mii_autoneg_adv_reg = MII_AR_DEFAULT_CAP_MASK; + + /* Read the MII 1000Base-T Control Register (Address 9). */ + mii_1000t_ctrl_reg = MII_AT001_CR_1000T_DEFAULT_CAP_MASK; + + /* + * First we clear all the 10/100 mb speed bits in the Auto-Neg + * Advertisement Register (Address 4) and the 1000 mb speed bits in + * the 1000Base-T Control Register (Address 9). + */ + mii_autoneg_adv_reg &= ~MII_AR_SPEED_MASK; + mii_1000t_ctrl_reg &= ~MII_AT001_CR_1000T_SPEED_MASK; + + /* + * Need to parse media_type and set up + * the appropriate PHY registers. + */ + switch (hw->media_type) { + case MEDIA_TYPE_AUTO_SENSOR: + mii_autoneg_adv_reg |= (MII_AR_10T_HD_CAPS | + MII_AR_10T_FD_CAPS | + MII_AR_100TX_HD_CAPS | + MII_AR_100TX_FD_CAPS); + mii_1000t_ctrl_reg |= MII_AT001_CR_1000T_FD_CAPS; + break; + + case MEDIA_TYPE_1000M_FULL: + mii_1000t_ctrl_reg |= MII_AT001_CR_1000T_FD_CAPS; + break; + + case MEDIA_TYPE_100M_FULL: + mii_autoneg_adv_reg |= MII_AR_100TX_FD_CAPS; + break; + + case MEDIA_TYPE_100M_HALF: + mii_autoneg_adv_reg |= MII_AR_100TX_HD_CAPS; + break; + + case MEDIA_TYPE_10M_FULL: + mii_autoneg_adv_reg |= MII_AR_10T_FD_CAPS; + break; + + default: + mii_autoneg_adv_reg |= MII_AR_10T_HD_CAPS; + break; + } + + /* flow control fixed to enable all */ + mii_autoneg_adv_reg |= (MII_AR_ASM_DIR | MII_AR_PAUSE); + + hw->mii_autoneg_adv_reg = mii_autoneg_adv_reg; + hw->mii_1000t_ctrl_reg = mii_1000t_ctrl_reg; + + ret_val = atl1_write_phy_reg(hw, MII_ADVERTISE, mii_autoneg_adv_reg); + if (ret_val) + return ret_val; + + ret_val = atl1_write_phy_reg(hw, MII_AT001_CR, mii_1000t_ctrl_reg); + if (ret_val) + return ret_val; + + return ATL1_SUCCESS; +} + +/* + * Configures link settings. + * hw - Struct containing variables accessed by shared code + * Assumes the hardware has previously been reset and the + * transmitter and receiver are not enabled. + */ +static s32 atl1_setup_link(struct atl1_hw *hw) +{ + s32 ret_val; + + /* + * Options: + * PHY will advertise value(s) parsed from + * autoneg_advertised and fc + * no matter what autoneg is , We will not wait link result. + */ + ret_val = atl1_phy_setup_autoneg_adv(hw); + if (ret_val) { + printk(KERN_DEBUG "%s: error setting up autonegotiation\n", + atl1_driver_name); + return ret_val; + } + /* SW.Reset , En-Auto-Neg if needed */ + ret_val = atl1_phy_reset(hw); + if (ret_val) { + printk(KERN_DEBUG "%s: error resetting the phy\n", + atl1_driver_name); + return ret_val; + } + hw->phy_configured = true; + return ret_val; +} + +static struct atl1_spi_flash_dev flash_table[] = { +/* MFR_NAME WRSR READ PRGM WREN WRDI RDSR RDID SECTOR_ERASE CHIP_ERASE */ + {"Atmel", 0x00, 0x03, 0x02, 0x06, 0x04, 0x05, 0x15, 0x52, 0x62}, + {"SST", 0x01, 0x03, 0x02, 0x06, 0x04, 0x05, 0x90, 0x20, 0x60}, + {"ST", 0x01, 0x03, 0x02, 0x06, 0x04, 0x05, 0xAB, 0xD8, 0xC7}, +}; + +static void atl1_init_flash_opcode(struct atl1_hw *hw) +{ + if (hw->flash_vendor >= sizeof(flash_table) / sizeof(flash_table[0])) + hw->flash_vendor = 0; /* ATMEL */ + + /* Init OP table */ + iowrite8(flash_table[hw->flash_vendor].cmd_program, + hw->hw_addr + REG_SPI_FLASH_OP_PROGRAM); + iowrite8(flash_table[hw->flash_vendor].cmd_sector_erase, + hw->hw_addr + REG_SPI_FLASH_OP_SC_ERASE); + iowrite8(flash_table[hw->flash_vendor].cmd_chip_erase, + hw->hw_addr + REG_SPI_FLASH_OP_CHIP_ERASE); + iowrite8(flash_table[hw->flash_vendor].cmd_rdid, + hw->hw_addr + REG_SPI_FLASH_OP_RDID); + iowrite8(flash_table[hw->flash_vendor].cmd_wren, + hw->hw_addr + REG_SPI_FLASH_OP_WREN); + iowrite8(flash_table[hw->flash_vendor].cmd_rdsr, + hw->hw_addr + REG_SPI_FLASH_OP_RDSR); + iowrite8(flash_table[hw->flash_vendor].cmd_wrsr, + hw->hw_addr + REG_SPI_FLASH_OP_WRSR); + iowrite8(flash_table[hw->flash_vendor].cmd_read, + hw->hw_addr + REG_SPI_FLASH_OP_READ); +} + +/* + * Performs basic configuration of the adapter. + * hw - Struct containing variables accessed by shared code + * Assumes that the controller has previously been reset and is in a + * post-reset uninitialized state. Initializes multicast table, + * and Calls routines to setup link + * Leaves the transmit and receive units disabled and uninitialized. + */ +s32 atl1_init_hw(struct atl1_hw *hw) +{ + u32 ret_val = 0; + + /* Zero out the Multicast HASH table */ + iowrite32(0, hw->hw_addr + REG_RX_HASH_TABLE); + /* clear the old settings from the multicast hash table */ + iowrite32(0, (hw->hw_addr + REG_RX_HASH_TABLE) + (1 << 2)); + + atl1_init_flash_opcode(hw); + + if (!hw->phy_configured) { + /* enable GPHY LinkChange Interrrupt */ + ret_val = atl1_write_phy_reg(hw, 18, 0xC00); + if (ret_val) + return ret_val; + /* make PHY out of power-saving state */ + ret_val = atl1_phy_leave_power_saving(hw); + if (ret_val) + return ret_val; + /* Call a subroutine to configure the link */ + ret_val = atl1_setup_link(hw); + } + return ret_val; +} + +/* + * Detects the current speed and duplex settings of the hardware. + * hw - Struct containing variables accessed by shared code + * speed - Speed of the connection + * duplex - Duplex setting of the connection + */ +s32 atl1_get_speed_and_duplex(struct atl1_hw *hw, u16 *speed, u16 *duplex) +{ + s32 ret_val; + u16 phy_data; + + /* ; --- Read PHY Specific Status Register (17) */ + ret_val = atl1_read_phy_reg(hw, MII_AT001_PSSR, &phy_data); + if (ret_val) + return ret_val; + + if (!(phy_data & MII_AT001_PSSR_SPD_DPLX_RESOLVED)) + return ATL1_ERR_PHY_RES; + + switch (phy_data & MII_AT001_PSSR_SPEED) { + case MII_AT001_PSSR_1000MBS: + *speed = SPEED_1000; + break; + case MII_AT001_PSSR_100MBS: + *speed = SPEED_100; + break; + case MII_AT001_PSSR_10MBS: + *speed = SPEED_10; + break; + default: + printk(KERN_DEBUG "%s: error getting speed\n", + atl1_driver_name); + return ATL1_ERR_PHY_SPEED; + break; + } + if (phy_data & MII_AT001_PSSR_DPLX) + *duplex = FULL_DUPLEX; + else + *duplex = HALF_DUPLEX; + + return ATL1_SUCCESS; +} + +void atl1_set_mac_addr(struct atl1_hw *hw) +{ + u32 value; + /* + * 00-0B-6A-F6-00-DC + * 0: 6AF600DC 1: 000B + * low dword + */ + value = (((u32) hw->mac_addr[2]) << 24) | + (((u32) hw->mac_addr[3]) << 16) | + (((u32) hw->mac_addr[4]) << 8) | (((u32) hw->mac_addr[5])); + iowrite32(value, hw->hw_addr + REG_MAC_STA_ADDR); + /* high dword */ + value = (((u32) hw->mac_addr[0]) << 8) | (((u32) hw->mac_addr[1])); + iowrite32(value, (hw->hw_addr + REG_MAC_STA_ADDR) + (1 << 2)); +} diff --git a/drivers/net/atl1/atl1_hw.h b/drivers/net/atl1/atl1_hw.h new file mode 100644 index 0000000..100c09c --- /dev/null +++ b/drivers/net/atl1/atl1_hw.h @@ -0,0 +1,951 @@ +/* + * Copyright(c) 2005 - 2006 Attansic Corporation. All rights reserved. + * Copyright(c) 2006 Chris Snook + * Copyright(c) 2006 Jay Cliburn + * + * Derived from Intel e1000 driver + * Copyright(c) 1999 - 2005 Intel Corporation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the Free + * Software Foundation; either version 2 of the License, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * There are a lot of defines in here that are unused and/or have cryptic + * names. Please leave them alone, as they're the closest thing we have + * to a spec from Attansic at present. *ahem* -- CHS + */ + +#ifndef _ATL1_HW_H_ +#define _ATL1_HW_H_ + +#include +#include + +struct atl1_adapter; +struct atl1_hw; + +/* function prototypes needed by multiple files */ +s32 atl1_phy_setup_autoneg_adv(struct atl1_hw *hw); +s32 atl1_write_phy_reg(struct atl1_hw *hw, u32 reg_addr, u16 phy_data); +s32 atl1_get_speed_and_duplex(struct atl1_hw *hw, u16 *speed, u16 *duplex); +s32 atl1_read_mac_addr(struct atl1_hw *hw); +s32 atl1_init_hw(struct atl1_hw *hw); +s32 atl1_get_speed_and_duplex(struct atl1_hw *hw, u16 *speed, u16 *duplex); +s32 atl1_set_speed_and_duplex(struct atl1_hw *hw, u16 speed, u16 duplex); +u32 atl1_hash_mc_addr(struct atl1_hw *hw, u8 *mc_addr); +void atl1_hash_set(struct atl1_hw *hw, u32 hash_value); +s32 atl1_read_phy_reg(struct atl1_hw *hw, u16 reg_addr, u16 *phy_data); +void atl1_set_mac_addr(struct atl1_hw *hw); +s32 atl1_phy_enter_power_saving(struct atl1_hw *hw); +s32 atl1_reset_hw(struct atl1_hw *hw); +void atl1_check_options(struct atl1_adapter *adapter); + +/* register definitions */ +#define REG_PCIE_CAP_LIST 0x58 + +#define REG_VPD_CAP 0x6C +#define VPD_CAP_ID_MASK 0xff +#define VPD_CAP_ID_SHIFT 0 +#define VPD_CAP_NEXT_PTR_MASK 0xFF +#define VPD_CAP_NEXT_PTR_SHIFT 8 +#define VPD_CAP_VPD_ADDR_MASK 0x7FFF +#define VPD_CAP_VPD_ADDR_SHIFT 16 +#define VPD_CAP_VPD_FLAG 0x80000000 + +#define REG_VPD_DATA 0x70 + +#define REG_SPI_FLASH_CTRL 0x200 +#define SPI_FLASH_CTRL_STS_NON_RDY 0x1 +#define SPI_FLASH_CTRL_STS_WEN 0x2 +#define SPI_FLASH_CTRL_STS_WPEN 0x80 +#define SPI_FLASH_CTRL_DEV_STS_MASK 0xFF +#define SPI_FLASH_CTRL_DEV_STS_SHIFT 0 +#define SPI_FLASH_CTRL_INS_MASK 0x7 +#define SPI_FLASH_CTRL_INS_SHIFT 8 +#define SPI_FLASH_CTRL_START 0x800 +#define SPI_FLASH_CTRL_EN_VPD 0x2000 +#define SPI_FLASH_CTRL_LDSTART 0x8000 +#define SPI_FLASH_CTRL_CS_HI_MASK 0x3 +#define SPI_FLASH_CTRL_CS_HI_SHIFT 16 +#define SPI_FLASH_CTRL_CS_HOLD_MASK 0x3 +#define SPI_FLASH_CTRL_CS_HOLD_SHIFT 18 +#define SPI_FLASH_CTRL_CLK_LO_MASK 0x3 +#define SPI_FLASH_CTRL_CLK_LO_SHIFT 20 +#define SPI_FLASH_CTRL_CLK_HI_MASK 0x3 +#define SPI_FLASH_CTRL_CLK_HI_SHIFT 22 +#define SPI_FLASH_CTRL_CS_SETUP_MASK 0x3 +#define SPI_FLASH_CTRL_CS_SETUP_SHIFT 24 +#define SPI_FLASH_CTRL_EROM_PGSZ_MASK 0x3 +#define SPI_FLASH_CTRL_EROM_PGSZ_SHIFT 26 +#define SPI_FLASH_CTRL_WAIT_READY 0x10000000 + +#define REG_SPI_ADDR 0x204 + +#define REG_SPI_DATA 0x208 + +#define REG_SPI_FLASH_CONFIG 0x20C +#define SPI_FLASH_CONFIG_LD_ADDR_MASK 0xFFFFFF +#define SPI_FLASH_CONFIG_LD_ADDR_SHIFT 0 +#define SPI_FLASH_CONFIG_VPD_ADDR_MASK 0x3 +#define SPI_FLASH_CONFIG_VPD_ADDR_SHIFT 24 +#define SPI_FLASH_CONFIG_LD_EXIST 0x4000000 + +#define REG_SPI_FLASH_OP_PROGRAM 0x210 +#define REG_SPI_FLASH_OP_SC_ERASE 0x211 +#define REG_SPI_FLASH_OP_CHIP_ERASE 0x212 +#define REG_SPI_FLASH_OP_RDID 0x213 +#define REG_SPI_FLASH_OP_WREN 0x214 +#define REG_SPI_FLASH_OP_RDSR 0x215 +#define REG_SPI_FLASH_OP_WRSR 0x216 +#define REG_SPI_FLASH_OP_READ 0x217 + +#define REG_TWSI_CTRL 0x218 +#define TWSI_CTRL_LD_OFFSET_MASK 0xFF +#define TWSI_CTRL_LD_OFFSET_SHIFT 0 +#define TWSI_CTRL_LD_SLV_ADDR_MASK 0x7 +#define TWSI_CTRL_LD_SLV_ADDR_SHIFT 8 +#define TWSI_CTRL_SW_LDSTART 0x800 +#define TWSI_CTRL_HW_LDSTART 0x1000 +#define TWSI_CTRL_SMB_SLV_ADDR_MASK 0x7F +#define TWSI_CTRL_SMB_SLV_ADDR_SHIFT 15 +#define TWSI_CTRL_LD_EXIST 0x400000 +#define TWSI_CTRL_READ_FREQ_SEL_MASK 0x3 +#define TWSI_CTRL_READ_FREQ_SEL_SHIFT 23 +#define TWSI_CTRL_FREQ_SEL_100K 0 +#define TWSI_CTRL_FREQ_SEL_200K 1 +#define TWSI_CTRL_FREQ_SEL_300K 2 +#define TWSI_CTRL_FREQ_SEL_400K 3 +#define TWSI_CTRL_SMB_SLV_ADDR +#define TWSI_CTRL_WRITE_FREQ_SEL_MASK 0x3 +#define TWSI_CTRL_WRITE_FREQ_SEL_SHIFT 24 + +#define REG_PCIE_DEV_MISC_CTRL 0x21C +#define PCIE_DEV_MISC_CTRL_EXT_PIPE 0x2 +#define PCIE_DEV_MISC_CTRL_RETRY_BUFDIS 0x1 +#define PCIE_DEV_MISC_CTRL_SPIROM_EXIST 0x4 +#define PCIE_DEV_MISC_CTRL_SERDES_ENDIAN 0x8 +#define PCIE_DEV_MISC_CTRL_SERDES_SEL_DIN 0x10 + +/* Selene Master Control Register */ +#define REG_MASTER_CTRL 0x1400 +#define MASTER_CTRL_SOFT_RST 0x1 +#define MASTER_CTRL_MTIMER_EN 0x2 +#define MASTER_CTRL_ITIMER_EN 0x4 +#define MASTER_CTRL_MANUAL_INT 0x8 +#define MASTER_CTRL_REV_NUM_SHIFT 16 +#define MASTER_CTRL_REV_NUM_MASK 0xff +#define MASTER_CTRL_DEV_ID_SHIFT 24 +#define MASTER_CTRL_DEV_ID_MASK 0xff + +/* Timer Initial Value Register */ +#define REG_MANUAL_TIMER_INIT 0x1404 + +/* IRQ ModeratorTimer Initial Value Register */ +#define REG_IRQ_MODU_TIMER_INIT 0x1408 + +#define REG_GPHY_ENABLE 0x140C + +/* IRQ Anti-Lost Timer Initial Value Register */ +#define REG_CMBDISDMA_TIMER 0x140E + +/* Block IDLE Status Register */ +#define REG_IDLE_STATUS 0x1410 +#define IDLE_STATUS_RXMAC 1 +#define IDLE_STATUS_TXMAC 2 +#define IDLE_STATUS_RXQ 4 +#define IDLE_STATUS_TXQ 8 +#define IDLE_STATUS_DMAR 0x10 +#define IDLE_STATUS_DMAW 0x20 +#define IDLE_STATUS_SMB 0x40 +#define IDLE_STATUS_CMB 0x80 + +/* MDIO Control Register */ +#define REG_MDIO_CTRL 0x1414 +#define MDIO_DATA_MASK 0xffff +#define MDIO_DATA_SHIFT 0 +#define MDIO_REG_ADDR_MASK 0x1f +#define MDIO_REG_ADDR_SHIFT 16 +#define MDIO_RW 0x200000 +#define MDIO_SUP_PREAMBLE 0x400000 +#define MDIO_START 0x800000 +#define MDIO_CLK_SEL_SHIFT 24 +#define MDIO_CLK_25_4 0 +#define MDIO_CLK_25_6 2 +#define MDIO_CLK_25_8 3 +#define MDIO_CLK_25_10 4 +#define MDIO_CLK_25_14 5 +#define MDIO_CLK_25_20 6 +#define MDIO_CLK_25_28 7 +#define MDIO_BUSY 0x8000000 +#define MDIO_WAIT_TIMES 30 + +/* MII PHY Status Register */ +#define REG_PHY_STATUS 0x1418 + +/* BIST Control and Status Register0 (for the Packet Memory) */ +#define REG_BIST0_CTRL 0x141c +#define BIST0_NOW 0x1 +#define BIST0_SRAM_FAIL 0x2 +#define BIST0_FUSE_FLAG 0x4 +#define REG_BIST1_CTRL 0x1420 +#define BIST1_NOW 0x1 +#define BIST1_SRAM_FAIL 0x2 +#define BIST1_FUSE_FLAG 0x4 + +/* MAC Control Register */ +#define REG_MAC_CTRL 0x1480 +#define MAC_CTRL_TX_EN 1 +#define MAC_CTRL_RX_EN 2 +#define MAC_CTRL_TX_FLOW 4 +#define MAC_CTRL_RX_FLOW 8 +#define MAC_CTRL_LOOPBACK 0x10 +#define MAC_CTRL_DUPLX 0x20 +#define MAC_CTRL_ADD_CRC 0x40 +#define MAC_CTRL_PAD 0x80 +#define MAC_CTRL_LENCHK 0x100 +#define MAC_CTRL_HUGE_EN 0x200 +#define MAC_CTRL_PRMLEN_SHIFT 10 +#define MAC_CTRL_PRMLEN_MASK 0xf +#define MAC_CTRL_RMV_VLAN 0x4000 +#define MAC_CTRL_PROMIS_EN 0x8000 +#define MAC_CTRL_TX_PAUSE 0x10000 +#define MAC_CTRL_SCNT 0x20000 +#define MAC_CTRL_SRST_TX 0x40000 +#define MAC_CTRL_TX_SIMURST 0x80000 +#define MAC_CTRL_SPEED_SHIFT 20 +#define MAC_CTRL_SPEED_MASK 0x300000 +#define MAC_CTRL_SPEED_1000 2 +#define MAC_CTRL_SPEED_10_100 1 +#define MAC_CTRL_DBG_TX_BKPRESURE 0x400000 +#define MAC_CTRL_TX_HUGE 0x800000 +#define MAC_CTRL_RX_CHKSUM_EN 0x1000000 +#define MAC_CTRL_MC_ALL_EN 0x2000000 +#define MAC_CTRL_BC_EN 0x4000000 +#define MAC_CTRL_DBG 0x8000000 + +/* MAC IPG/IFG Control Register */ +#define REG_MAC_IPG_IFG 0x1484 +#define MAC_IPG_IFG_IPGT_SHIFT 0 +#define MAC_IPG_IFG_IPGT_MASK 0x7f +#define MAC_IPG_IFG_MIFG_SHIFT 8 +#define MAC_IPG_IFG_MIFG_MASK 0xff +#define MAC_IPG_IFG_IPGR1_SHIFT 16 +#define MAC_IPG_IFG_IPGR1_MASK 0x7f +#define MAC_IPG_IFG_IPGR2_SHIFT 24 +#define MAC_IPG_IFG_IPGR2_MASK 0x7f + +/* MAC STATION ADDRESS */ +#define REG_MAC_STA_ADDR 0x1488 + +/* Hash table for multicast address */ +#define REG_RX_HASH_TABLE 0x1490 + +/* MAC Half-Duplex Control Register */ +#define REG_MAC_HALF_DUPLX_CTRL 0x1498 +#define MAC_HALF_DUPLX_CTRL_LCOL_SHIFT 0 +#define MAC_HALF_DUPLX_CTRL_LCOL_MASK 0x3ff +#define MAC_HALF_DUPLX_CTRL_RETRY_SHIFT 12 +#define MAC_HALF_DUPLX_CTRL_RETRY_MASK 0xf +#define MAC_HALF_DUPLX_CTRL_EXC_DEF_EN 0x10000 +#define MAC_HALF_DUPLX_CTRL_NO_BACK_C 0x20000 +#define MAC_HALF_DUPLX_CTRL_NO_BACK_P 0x40000 +#define MAC_HALF_DUPLX_CTRL_ABEBE 0x80000 +#define MAC_HALF_DUPLX_CTRL_ABEBT_SHIFT 20 +#define MAC_HALF_DUPLX_CTRL_ABEBT_MASK 0xf +#define MAC_HALF_DUPLX_CTRL_JAMIPG_SHIFT 24 +#define MAC_HALF_DUPLX_CTRL_JAMIPG_MASK 0xf + +/* Maximum Frame Length Control Register */ +#define REG_MTU 0x149c + +/* Wake-On-Lan control register */ +#define REG_WOL_CTRL 0x14a0 +#define WOL_PATTERN_EN 0x00000001 +#define WOL_PATTERN_PME_EN 0x00000002 +#define WOL_MAGIC_EN 0x00000004 +#define WOL_MAGIC_PME_EN 0x00000008 +#define WOL_LINK_CHG_EN 0x00000010 +#define WOL_LINK_CHG_PME_EN 0x00000020 +#define WOL_PATTERN_ST 0x00000100 +#define WOL_MAGIC_ST 0x00000200 +#define WOL_LINKCHG_ST 0x00000400 +#define WOL_CLK_SWITCH_EN 0x00008000 +#define WOL_PT0_EN 0x00010000 +#define WOL_PT1_EN 0x00020000 +#define WOL_PT2_EN 0x00040000 +#define WOL_PT3_EN 0x00080000 +#define WOL_PT4_EN 0x00100000 +#define WOL_PT5_EN 0x00200000 +#define WOL_PT6_EN 0x00400000 + +/* WOL Length ( 2 DWORD ) */ +#define REG_WOL_PATTERN_LEN 0x14a4 +#define WOL_PT_LEN_MASK 0x7f +#define WOL_PT0_LEN_SHIFT 0 +#define WOL_PT1_LEN_SHIFT 8 +#define WOL_PT2_LEN_SHIFT 16 +#define WOL_PT3_LEN_SHIFT 24 +#define WOL_PT4_LEN_SHIFT 0 +#define WOL_PT5_LEN_SHIFT 8 +#define WOL_PT6_LEN_SHIFT 16 + +/* Internal SRAM Partition Register */ +#define REG_SRAM_RFD_ADDR 0x1500 +#define REG_SRAM_RFD_LEN (REG_SRAM_RFD_ADDR+ 4) +#define REG_SRAM_RRD_ADDR (REG_SRAM_RFD_ADDR+ 8) +#define REG_SRAM_RRD_LEN (REG_SRAM_RFD_ADDR+12) +#define REG_SRAM_TPD_ADDR (REG_SRAM_RFD_ADDR+16) +#define REG_SRAM_TPD_LEN (REG_SRAM_RFD_ADDR+20) +#define REG_SRAM_TRD_ADDR (REG_SRAM_RFD_ADDR+24) +#define REG_SRAM_TRD_LEN (REG_SRAM_RFD_ADDR+28) +#define REG_SRAM_RXF_ADDR (REG_SRAM_RFD_ADDR+32) +#define REG_SRAM_RXF_LEN (REG_SRAM_RFD_ADDR+36) +#define REG_SRAM_TXF_ADDR (REG_SRAM_RFD_ADDR+40) +#define REG_SRAM_TXF_LEN (REG_SRAM_RFD_ADDR+44) +#define REG_SRAM_TCPH_PATH_ADDR (REG_SRAM_RFD_ADDR+48) +#define SRAM_TCPH_ADDR_MASK 0x0fff +#define SRAM_TCPH_ADDR_SHIFT 0 +#define SRAM_PATH_ADDR_MASK 0x0fff +#define SRAM_PATH_ADDR_SHIFT 16 + +/* Load Ptr Register */ +#define REG_LOAD_PTR (REG_SRAM_RFD_ADDR+52) + +/* Descriptor Control register */ +#define REG_DESC_BASE_ADDR_HI 0x1540 +#define REG_DESC_RFD_ADDR_LO (REG_DESC_BASE_ADDR_HI+4) +#define REG_DESC_RRD_ADDR_LO (REG_DESC_BASE_ADDR_HI+8) +#define REG_DESC_TPD_ADDR_LO (REG_DESC_BASE_ADDR_HI+12) +#define REG_DESC_CMB_ADDR_LO (REG_DESC_BASE_ADDR_HI+16) +#define REG_DESC_SMB_ADDR_LO (REG_DESC_BASE_ADDR_HI+20) +#define REG_DESC_RFD_RRD_RING_SIZE (REG_DESC_BASE_ADDR_HI+24) +#define DESC_RFD_RING_SIZE_MASK 0x7ff +#define DESC_RFD_RING_SIZE_SHIFT 0 +#define DESC_RRD_RING_SIZE_MASK 0x7ff +#define DESC_RRD_RING_SIZE_SHIFT 16 +#define REG_DESC_TPD_RING_SIZE (REG_DESC_BASE_ADDR_HI+28) +#define DESC_TPD_RING_SIZE_MASK 0x3ff +#define DESC_TPD_RING_SIZE_SHIFT 0 + +/* TXQ Control Register */ +#define REG_TXQ_CTRL 0x1580 +#define TXQ_CTRL_TPD_BURST_NUM_SHIFT 0 +#define TXQ_CTRL_TPD_BURST_NUM_MASK 0x1f +#define TXQ_CTRL_EN 0x20 +#define TXQ_CTRL_ENH_MODE 0x40 +#define TXQ_CTRL_TPD_FETCH_TH_SHIFT 8 +#define TXQ_CTRL_TPD_FETCH_TH_MASK 0x3f +#define TXQ_CTRL_TXF_BURST_NUM_SHIFT 16 +#define TXQ_CTRL_TXF_BURST_NUM_MASK 0xffff + +/* Jumbo packet Threshold for task offload */ +#define REG_TX_JUMBO_TASK_TH_TPD_IPG 0x1584 +#define TX_JUMBO_TASK_TH_MASK 0x7ff +#define TX_JUMBO_TASK_TH_SHIFT 0 +#define TX_TPD_MIN_IPG_MASK 0x1f +#define TX_TPD_MIN_IPG_SHIFT 16 + +/* RXQ Control Register */ +#define REG_RXQ_CTRL 0x15a0 +#define RXQ_CTRL_RFD_BURST_NUM_SHIFT 0 +#define RXQ_CTRL_RFD_BURST_NUM_MASK 0xff +#define RXQ_CTRL_RRD_BURST_THRESH_SHIFT 8 +#define RXQ_CTRL_RRD_BURST_THRESH_MASK 0xff +#define RXQ_CTRL_RFD_PREF_MIN_IPG_SHIFT 16 +#define RXQ_CTRL_RFD_PREF_MIN_IPG_MASK 0x1f +#define RXQ_CTRL_CUT_THRU_EN 0x40000000 +#define RXQ_CTRL_EN 0x80000000 + +/* Rx jumbo packet threshold and rrd retirement timer */ +#define REG_RXQ_JMBOSZ_RRDTIM (REG_RXQ_CTRL+ 4) +#define RXQ_JMBOSZ_TH_MASK 0x7ff +#define RXQ_JMBOSZ_TH_SHIFT 0 +#define RXQ_JMBO_LKAH_MASK 0xf +#define RXQ_JMBO_LKAH_SHIFT 11 +#define RXQ_RRD_TIMER_MASK 0xffff +#define RXQ_RRD_TIMER_SHIFT 16 + +/* RFD flow control register */ +#define REG_RXQ_RXF_PAUSE_THRESH (REG_RXQ_CTRL+ 8) +#define RXQ_RXF_PAUSE_TH_HI_SHIFT 16 +#define RXQ_RXF_PAUSE_TH_HI_MASK 0xfff +#define RXQ_RXF_PAUSE_TH_LO_SHIFT 0 +#define RXQ_RXF_PAUSE_TH_LO_MASK 0xfff + +/* RRD flow control register */ +#define REG_RXQ_RRD_PAUSE_THRESH (REG_RXQ_CTRL+12) +#define RXQ_RRD_PAUSE_TH_HI_SHIFT 0 +#define RXQ_RRD_PAUSE_TH_HI_MASK 0xfff +#define RXQ_RRD_PAUSE_TH_LO_SHIFT 16 +#define RXQ_RRD_PAUSE_TH_LO_MASK 0xfff + +/* DMA Engine Control Register */ +#define REG_DMA_CTRL 0x15c0 +#define DMA_CTRL_DMAR_IN_ORDER 0x1 +#define DMA_CTRL_DMAR_ENH_ORDER 0x2 +#define DMA_CTRL_DMAR_OUT_ORDER 0x4 +#define DMA_CTRL_RCB_VALUE 0x8 +#define DMA_CTRL_DMAR_BURST_LEN_SHIFT 4 +#define DMA_CTRL_DMAR_BURST_LEN_MASK 7 +#define DMA_CTRL_DMAW_BURST_LEN_SHIFT 7 +#define DMA_CTRL_DMAW_BURST_LEN_MASK 7 +#define DMA_CTRL_DMAR_EN 0x400 +#define DMA_CTRL_DMAW_EN 0x800 + +/* CMB/SMB Control Register */ +#define REG_CSMB_CTRL 0x15d0 +#define CSMB_CTRL_CMB_NOW 1 +#define CSMB_CTRL_SMB_NOW 2 +#define CSMB_CTRL_CMB_EN 4 +#define CSMB_CTRL_SMB_EN 8 + +/* CMB DMA Write Threshold Register */ +#define REG_CMB_WRITE_TH (REG_CSMB_CTRL+ 4) +#define CMB_RRD_TH_SHIFT 0 +#define CMB_RRD_TH_MASK 0x7ff +#define CMB_TPD_TH_SHIFT 16 +#define CMB_TPD_TH_MASK 0x7ff + +/* RX/TX count-down timer to trigger CMB-write. 2us resolution. */ +#define REG_CMB_WRITE_TIMER (REG_CSMB_CTRL+ 8) +#define CMB_RX_TM_SHIFT 0 +#define CMB_RX_TM_MASK 0xffff +#define CMB_TX_TM_SHIFT 16 +#define CMB_TX_TM_MASK 0xffff + +/* Number of packet received since last CMB write */ +#define REG_CMB_RX_PKT_CNT (REG_CSMB_CTRL+12) + +/* Number of packet transmitted since last CMB write */ +#define REG_CMB_TX_PKT_CNT (REG_CSMB_CTRL+16) + +/* SMB auto DMA timer register */ +#define REG_SMB_TIMER (REG_CSMB_CTRL+20) + +/* Mailbox Register */ +#define REG_MAILBOX 0x15f0 +#define MB_RFD_PROD_INDX_SHIFT 0 +#define MB_RFD_PROD_INDX_MASK 0x7ff +#define MB_RRD_CONS_INDX_SHIFT 11 +#define MB_RRD_CONS_INDX_MASK 0x7ff +#define MB_TPD_PROD_INDX_SHIFT 22 +#define MB_TPD_PROD_INDX_MASK 0x3ff + +/* Interrupt Status Register */ +#define REG_ISR 0x1600 +#define ISR_SMB 1 +#define ISR_TIMER 2 +#define ISR_MANUAL 4 +#define ISR_RXF_OV 8 +#define ISR_RFD_UNRUN 0x10 +#define ISR_RRD_OV 0x20 +#define ISR_TXF_UNRUN 0x40 +#define ISR_LINK 0x80 +#define ISR_HOST_RFD_UNRUN 0x100 +#define ISR_HOST_RRD_OV 0x200 +#define ISR_DMAR_TO_RST 0x400 +#define ISR_DMAW_TO_RST 0x800 +#define ISR_GPHY 0x1000 +#define ISR_RX_PKT 0x10000 +#define ISR_TX_PKT 0x20000 +#define ISR_TX_DMA 0x40000 +#define ISR_RX_DMA 0x80000 +#define ISR_CMB_RX 0x100000 +#define ISR_CMB_TX 0x200000 +#define ISR_MAC_RX 0x400000 +#define ISR_MAC_TX 0x800000 +#define ISR_UR_DETECTED 0x1000000 +#define ISR_FERR_DETECTED 0x2000000 +#define ISR_NFERR_DETECTED 0x4000000 +#define ISR_CERR_DETECTED 0x8000000 +#define ISR_PHY_LINKDOWN 0x10000000 +#define ISR_DIS_SMB 0x20000000 +#define ISR_DIS_DMA 0x40000000 +#define ISR_DIS_INT 0x80000000 + +/* Interrupt Mask Register */ +#define REG_IMR 0x1604 + +/* Normal Interrupt mask */ +#define IMR_NORMAL_MASK (\ + ISR_SMB |\ + ISR_GPHY |\ + ISR_PHY_LINKDOWN|\ + ISR_DMAR_TO_RST |\ + ISR_DMAW_TO_RST |\ + ISR_CMB_TX |\ + ISR_CMB_RX ) + +/* Debug Interrupt Mask (enable all interrupt) */ +#define IMR_DEBUG_MASK (\ + ISR_SMB |\ + ISR_TIMER |\ + ISR_MANUAL |\ + ISR_RXF_OV |\ + ISR_RFD_UNRUN |\ + ISR_RRD_OV |\ + ISR_TXF_UNRUN |\ + ISR_LINK |\ + ISR_CMB_TX |\ + ISR_CMB_RX |\ + ISR_RX_PKT |\ + ISR_TX_PKT |\ + ISR_MAC_RX |\ + ISR_MAC_TX ) + +/* Interrupt Status Register */ +#define REG_RFD_RRD_IDX 0x1800 +#define REG_TPD_IDX 0x1804 + +/* MII definition */ +/* PHY Common Register */ +#define MII_AT001_CR 0x09 +#define MII_AT001_SR 0x0A +#define MII_AT001_ESR 0x0F +#define MII_AT001_PSCR 0x10 +#define MII_AT001_PSSR 0x11 + +/* PHY Control Register */ +#define MII_CR_SPEED_SELECT_MSB 0x0040 /* bits 6,13: 10=1000, 01=100, 00=10 */ +#define MII_CR_COLL_TEST_ENABLE 0x0080 /* Collision test enable */ +#define MII_CR_FULL_DUPLEX 0x0100 /* FDX =1, half duplex =0 */ +#define MII_CR_RESTART_AUTO_NEG 0x0200 /* Restart auto negotiation */ +#define MII_CR_ISOLATE 0x0400 /* Isolate PHY from MII */ +#define MII_CR_POWER_DOWN 0x0800 /* Power down */ +#define MII_CR_AUTO_NEG_EN 0x1000 /* Auto Neg Enable */ +#define MII_CR_SPEED_SELECT_LSB 0x2000 /* bits 6,13: 10=1000, 01=100, 00=10 */ +#define MII_CR_LOOPBACK 0x4000 /* 0 = normal, 1 = loopback */ +#define MII_CR_RESET 0x8000 /* 0 = normal, 1 = PHY reset */ +#define MII_CR_SPEED_MASK 0x2040 +#define MII_CR_SPEED_1000 0x0040 +#define MII_CR_SPEED_100 0x2000 +#define MII_CR_SPEED_10 0x0000 + +/* PHY Status Register */ +#define MII_SR_EXTENDED_CAPS 0x0001 /* Extended register capabilities */ +#define MII_SR_JABBER_DETECT 0x0002 /* Jabber Detected */ +#define MII_SR_LINK_STATUS 0x0004 /* Link Status 1 = link */ +#define MII_SR_AUTONEG_CAPS 0x0008 /* Auto Neg Capable */ +#define MII_SR_REMOTE_FAULT 0x0010 /* Remote Fault Detect */ +#define MII_SR_AUTONEG_COMPLETE 0x0020 /* Auto Neg Complete */ +#define MII_SR_PREAMBLE_SUPPRESS 0x0040 /* Preamble may be suppressed */ +#define MII_SR_EXTENDED_STATUS 0x0100 /* Ext. status info in Reg 0x0F */ +#define MII_SR_100T2_HD_CAPS 0x0200 /* 100T2 Half Duplex Capable */ +#define MII_SR_100T2_FD_CAPS 0x0400 /* 100T2 Full Duplex Capable */ +#define MII_SR_10T_HD_CAPS 0x0800 /* 10T Half Duplex Capable */ +#define MII_SR_10T_FD_CAPS 0x1000 /* 10T Full Duplex Capable */ +#define MII_SR_100X_HD_CAPS 0x2000 /* 100X Half Duplex Capable */ +#define MII_SR_100X_FD_CAPS 0x4000 /* 100X Full Duplex Capable */ +#define MII_SR_100T4_CAPS 0x8000 /* 100T4 Capable */ + +/* Link partner ability register. */ +#define MII_LPA_SLCT 0x001f /* Same as advertise selector */ +#define MII_LPA_10HALF 0x0020 /* Can do 10mbps half-duplex */ +#define MII_LPA_10FULL 0x0040 /* Can do 10mbps full-duplex */ +#define MII_LPA_100HALF 0x0080 /* Can do 100mbps half-duplex */ +#define MII_LPA_100FULL 0x0100 /* Can do 100mbps full-duplex */ +#define MII_LPA_100BASE4 0x0200 /* 100BASE-T4 */ +#define MII_LPA_PAUSE 0x0400 /* PAUSE */ +#define MII_LPA_ASYPAUSE 0x0800 /* Asymmetrical PAUSE */ +#define MII_LPA_RFAULT 0x2000 /* Link partner faulted */ +#define MII_LPA_LPACK 0x4000 /* Link partner acked us */ +#define MII_LPA_NPAGE 0x8000 /* Next page bit */ + +/* Autoneg Advertisement Register */ +#define MII_AR_SELECTOR_FIELD 0x0001 /* indicates IEEE 802.3 CSMA/CD */ +#define MII_AR_10T_HD_CAPS 0x0020 /* 10T Half Duplex Capable */ +#define MII_AR_10T_FD_CAPS 0x0040 /* 10T Full Duplex Capable */ +#define MII_AR_100TX_HD_CAPS 0x0080 /* 100TX Half Duplex Capable */ +#define MII_AR_100TX_FD_CAPS 0x0100 /* 100TX Full Duplex Capable */ +#define MII_AR_100T4_CAPS 0x0200 /* 100T4 Capable */ +#define MII_AR_PAUSE 0x0400 /* Pause operation desired */ +#define MII_AR_ASM_DIR 0x0800 /* Asymmetric Pause Direction bit */ +#define MII_AR_REMOTE_FAULT 0x2000 /* Remote Fault detected */ +#define MII_AR_NEXT_PAGE 0x8000 /* Next Page ability supported */ +#define MII_AR_SPEED_MASK 0x01E0 +#define MII_AR_DEFAULT_CAP_MASK 0x0DE0 + +/* 1000BASE-T Control Register */ +#define MII_AT001_CR_1000T_HD_CAPS 0x0100 /* Advertise 1000T HD capability */ +#define MII_AT001_CR_1000T_FD_CAPS 0x0200 /* Advertise 1000T FD capability */ +#define MII_AT001_CR_1000T_REPEATER_DTE 0x0400 /* 1=Repeater/switch device port, 0=DTE device */ +#define MII_AT001_CR_1000T_MS_VALUE 0x0800 /* 1=Configure PHY as Master, 0=Configure PHY as Slave */ +#define MII_AT001_CR_1000T_MS_ENABLE 0x1000 /* 1=Master/Slave manual config value, 0=Automatic Master/Slave config */ +#define MII_AT001_CR_1000T_TEST_MODE_NORMAL 0x0000 /* Normal Operation */ +#define MII_AT001_CR_1000T_TEST_MODE_1 0x2000 /* Transmit Waveform test */ +#define MII_AT001_CR_1000T_TEST_MODE_2 0x4000 /* Master Transmit Jitter test */ +#define MII_AT001_CR_1000T_TEST_MODE_3 0x6000 /* Slave Transmit Jitter test */ +#define MII_AT001_CR_1000T_TEST_MODE_4 0x8000 /* Transmitter Distortion test */ +#define MII_AT001_CR_1000T_SPEED_MASK 0x0300 +#define MII_AT001_CR_1000T_DEFAULT_CAP_MASK 0x0300 + +/* 1000BASE-T Status Register */ +#define MII_AT001_SR_1000T_LP_HD_CAPS 0x0400 /* LP is 1000T HD capable */ +#define MII_AT001_SR_1000T_LP_FD_CAPS 0x0800 /* LP is 1000T FD capable */ +#define MII_AT001_SR_1000T_REMOTE_RX_STATUS 0x1000 /* Remote receiver OK */ +#define MII_AT001_SR_1000T_LOCAL_RX_STATUS 0x2000 /* Local receiver OK */ +#define MII_AT001_SR_1000T_MS_CONFIG_RES 0x4000 /* 1=Local TX is Master, 0=Slave */ +#define MII_AT001_SR_1000T_MS_CONFIG_FAULT 0x8000 /* Master/Slave config fault */ +#define MII_AT001_SR_1000T_REMOTE_RX_STATUS_SHIFT 12 +#define MII_AT001_SR_1000T_LOCAL_RX_STATUS_SHIFT 13 + +/* Extended Status Register */ +#define MII_AT001_ESR_1000T_HD_CAPS 0x1000 /* 1000T HD capable */ +#define MII_AT001_ESR_1000T_FD_CAPS 0x2000 /* 1000T FD capable */ +#define MII_AT001_ESR_1000X_HD_CAPS 0x4000 /* 1000X HD capable */ +#define MII_AT001_ESR_1000X_FD_CAPS 0x8000 /* 1000X FD capable */ + +/* AT001 PHY Specific Control Register */ +#define MII_AT001_PSCR_JABBER_DISABLE 0x0001 /* 1=Jabber Function disabled */ +#define MII_AT001_PSCR_POLARITY_REVERSAL 0x0002 /* 1=Polarity Reversal enabled */ +#define MII_AT001_PSCR_SQE_TEST 0x0004 /* 1=SQE Test enabled */ +#define MII_AT001_PSCR_MAC_POWERDOWN 0x0008 +#define MII_AT001_PSCR_CLK125_DISABLE 0x0010 /* 1=CLK125 low, 0=CLK125 toggling */ +#define MII_AT001_PSCR_MDI_MANUAL_MODE 0x0000 /* MDI Crossover Mode bits 6:5, Manual MDI configuration */ +#define MII_AT001_PSCR_MDIX_MANUAL_MODE 0x0020 /* Manual MDIX configuration */ +#define MII_AT001_PSCR_AUTO_X_1000T 0x0040 /* 1000BASE-T: Auto crossover, 100BASE-TX/10BASE-T: MDI Mode */ +#define MII_AT001_PSCR_AUTO_X_MODE 0x0060 /* Auto crossover enabled all speeds. */ +#define MII_AT001_PSCR_10BT_EXT_DIST_ENABLE 0x0080 /* 1=Enable Extended 10BASE-T distance (Lower 10BASE-T RX Threshold), 0=Normal 10BASE-T RX Threshold */ +#define MII_AT001_PSCR_MII_5BIT_ENABLE 0x0100 /* 1=5-Bit interface in 100BASE-TX, 0=MII interface in 100BASE-TX */ +#define MII_AT001_PSCR_SCRAMBLER_DISABLE 0x0200 /* 1=Scrambler disable */ +#define MII_AT001_PSCR_FORCE_LINK_GOOD 0x0400 /* 1=Force link good */ +#define MII_AT001_PSCR_ASSERT_CRS_ON_TX 0x0800 /* 1=Assert CRS on Transmit */ +#define MII_AT001_PSCR_POLARITY_REVERSAL_SHIFT 1 +#define MII_AT001_PSCR_AUTO_X_MODE_SHIFT 5 +#define MII_AT001_PSCR_10BT_EXT_DIST_ENABLE_SHIFT 7 + +/* AT001 PHY Specific Status Register */ +#define MII_AT001_PSSR_SPD_DPLX_RESOLVED 0x0800 /* 1=Speed & Duplex resolved */ +#define MII_AT001_PSSR_DPLX 0x2000 /* 1=Duplex 0=Half Duplex */ +#define MII_AT001_PSSR_SPEED 0xC000 /* Speed, bits 14:15 */ +#define MII_AT001_PSSR_10MBS 0x0000 /* 00=10Mbs */ +#define MII_AT001_PSSR_100MBS 0x4000 /* 01=100Mbs */ +#define MII_AT001_PSSR_1000MBS 0x8000 /* 10=1000Mbs */ + +/* PCI Command Register Bit Definitions */ +#define PCI_REG_COMMAND 0x04 /* PCI Command Register */ +#define CMD_IO_SPACE 0x0001 +#define CMD_MEMORY_SPACE 0x0002 +#define CMD_BUS_MASTER 0x0004 + +/* Wake Up Filter Control */ +#define ATL1_WUFC_LNKC 0x00000001 /* Link Status Change Wakeup Enable */ +#define ATL1_WUFC_MAG 0x00000002 /* Magic Packet Wakeup Enable */ +#define ATL1_WUFC_EX 0x00000004 /* Directed Exact Wakeup Enable */ +#define ATL1_WUFC_MC 0x00000008 /* Multicast Wakeup Enable */ +#define ATL1_WUFC_BC 0x00000010 /* Broadcast Wakeup Enable */ + +/* Error Codes */ +#define ATL1_SUCCESS 0 +#define ATL1_ERR_EEPROM 1 +#define ATL1_ERR_PHY 2 +#define ATL1_ERR_CONFIG 3 +#define ATL1_ERR_PARAM 4 +#define ATL1_ERR_MAC_TYPE 5 +#define ATL1_ERR_PHY_TYPE 6 +#define ATL1_ERR_PHY_SPEED 7 +#define ATL1_ERR_PHY_RES 8 + +#define SPEED_0 0xffff +#define SPEED_10 10 +#define SPEED_100 100 +#define SPEED_1000 1000 +#define HALF_DUPLEX 1 +#define FULL_DUPLEX 2 + +#define MEDIA_TYPE_AUTO_SENSOR 0 +#define MEDIA_TYPE_1000M_FULL 1 +#define MEDIA_TYPE_100M_FULL 2 +#define MEDIA_TYPE_100M_HALF 3 +#define MEDIA_TYPE_10M_FULL 4 +#define MEDIA_TYPE_10M_HALF 5 + +#define ADVERTISE_10_HALF 0x0001 +#define ADVERTISE_10_FULL 0x0002 +#define ADVERTISE_100_HALF 0x0004 +#define ADVERTISE_100_FULL 0x0008 +#define ADVERTISE_1000_HALF 0x0010 +#define ADVERTISE_1000_FULL 0x0020 +#define AUTONEG_ADVERTISE_SPEED_DEFAULT 0x002F /* Everything but 1000-Half */ +#define AUTONEG_ADVERTISE_10_100_ALL 0x000F /* All 10/100 speeds */ +#define AUTONEG_ADVERTISE_10_ALL 0x0003 /* 10Mbps Full & Half speeds */ + +/* The size (in bytes) of a ethernet packet */ +#define ENET_HEADER_SIZE 14 +#define MAXIMUM_ETHERNET_FRAME_SIZE 1518 /* with FCS */ +#define MINIMUM_ETHERNET_FRAME_SIZE 64 /* with FCS */ +#define ETHERNET_FCS_SIZE 4 +#define MAX_JUMBO_FRAME_SIZE 0x2800 + +#define PHY_AUTO_NEG_TIME 45 /* 4.5 Seconds */ +#define PHY_FORCE_TIME 20 /* 2.0 Seconds */ + +/* For checksumming , the sum of all words in the EEPROM should equal 0xBABA */ +#define EEPROM_SUM 0xBABA + +#define ATL1_EEDUMP_LEN 48 + +/* Statistics counters collected by the MAC */ +struct stats_msg_block { + /* rx */ + u32 rx_ok; /* The number of good packet received. */ + u32 rx_bcast; /* The number of good broadcast packet received. */ + u32 rx_mcast; /* The number of good multicast packet received. */ + u32 rx_pause; /* The number of Pause packet received. */ + u32 rx_ctrl; /* The number of Control packet received other than Pause frame. */ + u32 rx_fcs_err; /* The number of packets with bad FCS. */ + u32 rx_len_err; /* The number of packets with mismatch of length field and actual size. */ + u32 rx_byte_cnt; /* The number of bytes of good packet received. FCS is NOT included. */ + u32 rx_runt; /* The number of packets received that are less than 64 byte long and with good FCS. */ + u32 rx_frag; /* The number of packets received that are less than 64 byte long and with bad FCS. */ + u32 rx_sz_64; /* The number of good and bad packets received that are 64 byte long. */ + u32 rx_sz_65_127; /* The number of good and bad packets received that are between 65 and 127-byte long. */ + u32 rx_sz_128_255; /* The number of good and bad packets received that are between 128 and 255-byte long. */ + u32 rx_sz_256_511; /* The number of good and bad packets received that are between 256 and 511-byte long. */ + u32 rx_sz_512_1023; /* The number of good and bad packets received that are between 512 and 1023-byte long. */ + u32 rx_sz_1024_1518; /* The number of good and bad packets received that are between 1024 and 1518-byte long. */ + u32 rx_sz_1519_max; /* The number of good and bad packets received that are between 1519-byte and MTU. */ + u32 rx_sz_ov; /* The number of good and bad packets received that are more than MTU size Å¡C truncated by Selene. */ + u32 rx_rxf_ov; /* The number of frame dropped due to occurrence of RX FIFO overflow. */ + u32 rx_rrd_ov; /* The number of frame dropped due to occurrence of RRD overflow. */ + u32 rx_align_err; /* Alignment Error */ + u32 rx_bcast_byte_cnt; /* The byte count of broadcast packet received, excluding FCS. */ + u32 rx_mcast_byte_cnt; /* The byte count of multicast packet received, excluding FCS. */ + u32 rx_err_addr; /* The number of packets dropped due to address filtering. */ + + /* tx */ + u32 tx_ok; /* The number of good packet transmitted. */ + u32 tx_bcast; /* The number of good broadcast packet transmitted. */ + u32 tx_mcast; /* The number of good multicast packet transmitted. */ + u32 tx_pause; /* The number of Pause packet transmitted. */ + u32 tx_exc_defer; /* The number of packets transmitted with excessive deferral. */ + u32 tx_ctrl; /* The number of packets transmitted is a control frame, excluding Pause frame. */ + u32 tx_defer; /* The number of packets transmitted that is deferred. */ + u32 tx_byte_cnt; /* The number of bytes of data transmitted. FCS is NOT included. */ + u32 tx_sz_64; /* The number of good and bad packets transmitted that are 64 byte long. */ + u32 tx_sz_65_127; /* The number of good and bad packets transmitted that are between 65 and 127-byte long. */ + u32 tx_sz_128_255; /* The number of good and bad packets transmitted that are between 128 and 255-byte long. */ + u32 tx_sz_256_511; /* The number of good and bad packets transmitted that are between 256 and 511-byte long. */ + u32 tx_sz_512_1023; /* The number of good and bad packets transmitted that are between 512 and 1023-byte long. */ + u32 tx_sz_1024_1518; /* The number of good and bad packets transmitted that are between 1024 and 1518-byte long. */ + u32 tx_sz_1519_max; /* The number of good and bad packets transmitted that are between 1519-byte and MTU. */ + u32 tx_1_col; /* The number of packets subsequently transmitted successfully with a single prior collision. */ + u32 tx_2_col; /* The number of packets subsequently transmitted successfully with multiple prior collisions. */ + u32 tx_late_col; /* The number of packets transmitted with late collisions. */ + u32 tx_abort_col; /* The number of transmit packets aborted due to excessive collisions. */ + u32 tx_underrun; /* The number of transmit packets aborted due to transmit FIFO underrun, or TRD FIFO underrun */ + u32 tx_rd_eop; /* The number of times that read beyond the EOP into the next frame area when TRD was not written timely */ + u32 tx_len_err; /* The number of transmit packets with length field does NOT match the actual frame size. */ + u32 tx_trunc; /* The number of transmit packets truncated due to size exceeding MTU. */ + u32 tx_bcast_byte; /* The byte count of broadcast packet transmitted, excluding FCS. */ + u32 tx_mcast_byte; /* The byte count of multicast packet transmitted, excluding FCS. */ + u32 smb_updated; /* 1: SMB Updated. This is used by software as the indication of the statistics update. + * Software should clear this bit as soon as retrieving the statistics information. */ +}; + +/* Coalescing Message Block */ +struct coals_msg_block { + u32 int_stats; /* interrupt status */ + u16 rrd_prod_idx; /* TRD Producer Index. */ + u16 rfd_cons_idx; /* RFD Consumer Index. */ + u16 update; /* Selene sets this bit every time it DMA the CMB to host memory. + * Software supposes to clear this bit when CMB information is processed. */ + u16 tpd_cons_idx; /* TPD Consumer Index. */ +}; + +/* RRD descriptor */ +struct rx_return_desc { + u8 num_buf; /* Number of RFD buffers used by the received packet */ + u8 resved; + u16 buf_indx; /* RFD Index of the first buffer */ + union { + u32 valid; + struct { + u16 rx_chksum; + u16 pkt_size; + } xsum_sz; + } xsz; + + u16 pkt_flg; /* Packet flags */ + u16 err_flg; /* Error flags */ + u16 resved2; + u16 vlan_tag; /* VLAN TAG */ +}; + +#define PACKET_FLAG_ETH_TYPE 0x0080 +#define PACKET_FLAG_VLAN_INS 0x0100 +#define PACKET_FLAG_ERR 0x0200 +#define PACKET_FLAG_IPV4 0x0400 +#define PACKET_FLAG_UDP 0x0800 +#define PACKET_FLAG_TCP 0x1000 +#define PACKET_FLAG_BCAST 0x2000 +#define PACKET_FLAG_MCAST 0x4000 +#define PACKET_FLAG_PAUSE 0x8000 + +#define ERR_FLAG_CRC 0x0001 +#define ERR_FLAG_CODE 0x0002 +#define ERR_FLAG_DRIBBLE 0x0004 +#define ERR_FLAG_RUNT 0x0008 +#define ERR_FLAG_OV 0x0010 +#define ERR_FLAG_TRUNC 0x0020 +#define ERR_FLAG_IP_CHKSUM 0x0040 +#define ERR_FLAG_L4_CHKSUM 0x0080 +#define ERR_FLAG_LEN 0x0100 +#define ERR_FLAG_DES_ADDR 0x0200 + +/* RFD descriptor */ +struct rx_free_desc { + __le64 buffer_addr; /* Address of the descriptor's data buffer */ + __le16 buf_len; /* Size of the receive buffer in host memory, in byte */ + u16 coalese; /* Update consumer index to host after the reception of this frame */ + /* __attribute__ ((packed)) is required */ +} __attribute__ ((packed)); + +/* tsopu defines */ +#define TSO_PARAM_BUFLEN_MASK 0x3FFF +#define TSO_PARAM_BUFLEN_SHIFT 0 +#define TSO_PARAM_DMAINT_MASK 0x0001 +#define TSO_PARAM_DMAINT_SHIFT 14 +#define TSO_PARAM_PKTNT_MASK 0x0001 +#define TSO_PARAM_PKTINT_SHIFT 15 +#define TSO_PARAM_VLANTAG_MASK 0xFFFF +#define TSO_PARAM_VLAN_SHIFT 16 + +/* tsopl defines */ +#define TSO_PARAM_EOP_MASK 0x0001 +#define TSO_PARAM_EOP_SHIFT 0 +#define TSO_PARAM_COALESCE_MASK 0x0001 +#define TSO_PARAM_COALESCE_SHIFT 1 +#define TSO_PARAM_INSVLAG_MASK 0x0001 +#define TSO_PARAM_INSVLAG_SHIFT 2 +#define TSO_PARAM_CUSTOMCKSUM_MASK 0x0001 +#define TSO_PARAM_CUSTOMCKSUM_SHIFT 3 +#define TSO_PARAM_SEGMENT_MASK 0x0001 +#define TSO_PARAM_SEGMENT_SHIFT 4 +#define TSO_PARAM_IPCKSUM_MASK 0x0001 +#define TSO_PARAM_IPCKSUM_SHIFT 5 +#define TSO_PARAM_TCPCKSUM_MASK 0x0001 +#define TSO_PARAM_TCPCKSUM_SHIFT 6 +#define TSO_PARAM_UDPCKSUM_MASK 0x0001 +#define TSO_PARAM_UDPCKSUM_SHIFT 7 +#define TSO_PARAM_VLANTAGGED_MASK 0x0001 +#define TSO_PARAM_VLANTAGGED_SHIFT 8 +#define TSO_PARAM_ETHTYPE_MASK 0x0001 +#define TSO_PARAM_ETHTYPE_SHIFT 9 +#define TSO_PARAM_IPHL_MASK 0x000F +#define TSO_PARAM_IPHL_SHIFT 10 +#define TSO_PARAM_TCPHDRLEN_MASK 0x000F +#define TSO_PARAM_TCPHDRLEN_SHIFT 14 +#define TSO_PARAM_HDRFLAG_MASK 0x0001 +#define TSO_PARAM_HDRFLAG_SHIFT 18 +#define TSO_PARAM_MSS_MASK 0x1FFF +#define TSO_PARAM_MSS_SHIFT 19 + +/* csumpu defines */ +#define CSUM_PARAM_BUFLEN_MASK 0x3FFF +#define CSUM_PARAM_BUFLEN_SHIFT 0 +#define CSUM_PARAM_DMAINT_MASK 0x0001 +#define CSUM_PARAM_DMAINT_SHIFT 14 +#define CSUM_PARAM_PKTINT_MASK 0x0001 +#define CSUM_PARAM_PKTINT_SHIFT 15 +#define CSUM_PARAM_VALANTAG_MASK 0xFFFF +#define CSUM_PARAM_VALAN_SHIFT 16 + +/* csumpl defines*/ +#define CSUM_PARAM_EOP_MASK 0x0001 +#define CSUM_PARAM_EOP_SHIFT 0 +#define CSUM_PARAM_COALESCE_MASK 0x0001 +#define CSUM_PARAM_COALESCE_SHIFT 1 +#define CSUM_PARAM_INSVLAG_MASK 0x0001 +#define CSUM_PARAM_INSVLAG_SHIFT 2 +#define CSUM_PARAM_CUSTOMCKSUM_MASK 0x0001 +#define CSUM_PARAM_CUSTOMCKSUM_SHIFT 3 +#define CSUM_PARAM_SEGMENT_MASK 0x0001 +#define CSUM_PARAM_SEGMENT_SHIFT 4 +#define CSUM_PARAM_IPCKSUM_MASK 0x0001 +#define CSUM_PARAM_IPCKSUM_SHIFT 5 +#define CSUM_PARAM_TCPCKSUM_MASK 0x0001 +#define CSUM_PARAM_TCPCKSUM_SHIFT 6 +#define CSUM_PARAM_UDPCKSUM_MASK 0x0001 +#define CSUM_PARAM_UDPCKSUM_SHIFT 7 +#define CSUM_PARAM_VLANTAGGED_MASK 0x0001 +#define CSUM_PARAM_VLANTAGGED_SHIFT 8 +#define CSUM_PARAM_ETHTYPE_MASK 0x0001 +#define CSUM_PARAM_ETHTYPE_SHIFT 9 +#define CSUM_PARAM_IPHL_MASK 0x000F +#define CSUM_PARAM_IPHL_SHIFT 10 +#define CSUM_PARAM_PLOADOFFSET_MASK 0x00FF +#define CSUM_PARAM_PLOADOFFSET_SHIFT 16 +#define CSUM_PARAM_XSUMOFFSET_MASK 0x00FF +#define CSUM_PARAM_XSUMOFFSET_SHIFT 24 + +/* TPD descriptor */ +struct tso_param { + /* The order of these declarations is important -- don't change it */ + u32 tsopu; /* tso_param upper word */ + u32 tsopl; /* tso_param lower word */ +}; + +struct csum_param { + /* The order of these declarations is important -- don't change it */ + u32 csumpu; /* csum_param upper word */ + u32 csumpl; /* csum_param lower word */ +}; + +union tpd_descr { + u64 data; + struct csum_param csum; + struct tso_param tso; +}; + +struct tx_packet_desc { + __le64 buffer_addr; + union tpd_descr desc; +}; + +/* DMA Order Settings */ +enum atl1_dma_order { + atl1_dma_ord_in = 1, + atl1_dma_ord_enh = 2, + atl1_dma_ord_out = 4 +}; + +enum atl1_dma_rcb { + atl1_rcb_64 = 0, + atl1_rcb_128 = 1 +}; + +enum atl1_dma_req_block { + atl1_dma_req_128 = 0, + atl1_dma_req_256 = 1, + atl1_dma_req_512 = 2, + atl1_dam_req_1024 = 3, + atl1_dam_req_2048 = 4, + atl1_dma_req_4096 = 5 +}; + +struct atl1_spi_flash_dev { + const char *manu_name; /* manufacturer id */ + /* op-code */ + u8 cmd_wrsr; + u8 cmd_read; + u8 cmd_program; + u8 cmd_wren; + u8 cmd_wrdi; + u8 cmd_rdsr; + u8 cmd_rdid; + u8 cmd_sector_erase; + u8 cmd_chip_erase; +}; + +#endif /* _ATL1_HW_H_ */ diff --git a/drivers/net/atl1/atl1_main.c b/drivers/net/atl1/atl1_main.c new file mode 100644 index 0000000..6655640 --- /dev/null +++ b/drivers/net/atl1/atl1_main.c @@ -0,0 +1,2468 @@ +/* + * Copyright(c) 2005 - 2006 Attansic Corporation. All rights reserved. + * Copyright(c) 2006 Chris Snook + * Copyright(c) 2006 Jay Cliburn + * + * Derived from Intel e1000 driver + * Copyright(c) 1999 - 2005 Intel Corporation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the Free + * Software Foundation; either version 2 of the License, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * The full GNU General Public License is included in this distribution in the + * file called COPYING. + * + * Contact Information: + * Xiong Huang + * Attansic Technology Corp. 3F 147, Xianzheng 9th Road, Zhubei, + * Xinzhu 302, TAIWAN, REPUBLIC OF CHINA + * + * Chris Snook + * Jay Cliburn + * + * This version is adapted from the Attansic reference driver for + * inclusion in the Linux kernel. It is currently under heavy development. + * A very incomplete list of things that need to be dealt with: + * + * TODO: + * Fix TSO; tx performance is horrible with TSO enabled. + * Wake on LAN. + * Add more ethtool functions, including set ring parameters. + * Fix abstruse irq enable/disable condition described here: + * http://marc.theaimsgroup.com/?l=linux-netdev&m=116398508500553&w=2 + * + * NEEDS TESTING: + * VLAN + * multicast + * promiscuous mode + * interrupt coalescing + * SMP torture testing + */ + +#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 "atl1.h" + +#define RUN_REALTIME 0 +#define DRIVER_VERSION "2.0.6" + +char atl1_driver_name[] = "atl1"; +static const char atl1_driver_string[] = "Attansic L1 Ethernet Network Driver"; +static const char atl1_copyright[] = "Copyright(c) 2005-2006 Attansic Corporation."; +char atl1_driver_version[] = DRIVER_VERSION; + +MODULE_AUTHOR + ("Attansic Corporation , Chris Snook , Jay Cliburn "); +MODULE_DESCRIPTION("Attansic 1000M Ethernet Network Driver"); +MODULE_LICENSE("GPL"); +MODULE_VERSION(DRIVER_VERSION); + +/* + * atl1_pci_tbl - PCI Device ID Table + */ +static const struct pci_device_id atl1_pci_tbl[] = { + {PCI_DEVICE(PCI_VENDOR_ID_ATTANSIC, 0x1048)}, + /* required last entry */ + {0,} +}; + +MODULE_DEVICE_TABLE(pci, atl1_pci_tbl); + +/* + * atl1_sw_init - Initialize general software structures (struct atl1_adapter) + * @adapter: board private structure to initialize + * + * atl1_sw_init initializes the Adapter private data structure. + * Fields are initialized based on PCI device information and + * OS network device settings (MTU size). + */ +static int __devinit atl1_sw_init(struct atl1_adapter *adapter) +{ + struct atl1_hw *hw = &adapter->hw; + struct net_device *netdev = adapter->netdev; + struct pci_dev *pdev = adapter->pdev; + + /* PCI config space info */ + pci_read_config_byte(pdev, PCI_REVISION_ID, &hw->revision_id); + + hw->max_frame_size = netdev->mtu + ENET_HEADER_SIZE + ETHERNET_FCS_SIZE; + hw->min_frame_size = MINIMUM_ETHERNET_FRAME_SIZE; + + adapter->wol = 0; + adapter->rx_buffer_len = (hw->max_frame_size + 7) & ~7; + adapter->ict = 50000; /* 100ms */ + adapter->link_speed = SPEED_0; /* hardware init */ + adapter->link_duplex = FULL_DUPLEX; + + hw->phy_configured = false; + hw->preamble_len = 7; + hw->ipgt = 0x60; + hw->min_ifg = 0x50; + hw->ipgr1 = 0x40; + hw->ipgr2 = 0x60; + hw->max_retry = 0xf; + hw->lcol = 0x37; + hw->jam_ipg = 7; + hw->rfd_burst = 8; + hw->rrd_burst = 8; + hw->rfd_fetch_gap = 1; + hw->rx_jumbo_th = adapter->rx_buffer_len / 8; + hw->rx_jumbo_lkah = 1; + hw->rrd_ret_timer = 16; + hw->tpd_burst = 4; + hw->tpd_fetch_th = 16; + hw->txf_burst = 0x100; + hw->tx_jumbo_task_th = (hw->max_frame_size + 7) >> 3; + hw->tpd_fetch_gap = 1; + hw->rcb_value = atl1_rcb_64; + hw->dma_ord = atl1_dma_ord_enh; + hw->dmar_block = atl1_dma_req_256; + hw->dmaw_block = atl1_dma_req_256; + hw->cmb_rrd = 4; + hw->cmb_tpd = 4; + hw->cmb_rx_timer = 1; /* about 2us */ + hw->cmb_tx_timer = 1; /* about 2us */ + hw->smb_timer = 100000; /* about 200ms */ + + atomic_set(&adapter->irq_sem, 0); + spin_lock_init(&adapter->lock); + spin_lock_init(&adapter->mb_lock); + + return 0; +} + +/* + * atl1_setup_mem_resources - allocate Tx / RX descriptor resources + * @adapter: board private structure + * + * Return 0 on success, negative on failure + */ +s32 atl1_setup_ring_resources(struct atl1_adapter *adapter) +{ + struct atl1_tpd_ring *tpd_ring = &adapter->tpd_ring; + struct atl1_rfd_ring *rfd_ring = &adapter->rfd_ring; + struct atl1_rrd_ring *rrd_ring = &adapter->rrd_ring; + struct atl1_ring_header *ring_header = &adapter->ring_header; + struct pci_dev *pdev = adapter->pdev; + int size; + u8 offset = 0; + + size = sizeof(struct atl1_buffer) * (tpd_ring->count + rfd_ring->count); + tpd_ring->buffer_info = kzalloc(size, GFP_KERNEL); + if (unlikely(!tpd_ring->buffer_info)) { + printk(KERN_WARNING "%s: kzalloc failed , size = D%d\n", + atl1_driver_name, size); + goto err_nomem; + } + rfd_ring->buffer_info = + (struct atl1_buffer *)(tpd_ring->buffer_info + tpd_ring->count); + + /* real ring DMA buffer */ + ring_header->size = size = sizeof(struct tx_packet_desc) * + tpd_ring->count + + sizeof(struct rx_free_desc) * rfd_ring->count + + sizeof(struct rx_return_desc) * rrd_ring->count + + sizeof(struct coals_msg_block) + + sizeof(struct stats_msg_block) + + 40; /* "40: for 8 bytes align" huh? -- CHS */ + + ring_header->desc = pci_alloc_consistent(pdev, ring_header->size, + &ring_header->dma); + if (unlikely(!ring_header->desc)) { + printk(KERN_WARNING + "%s: pci_alloc_consistent failed, size = D%d\n", + atl1_driver_name, size); + goto err_nomem; + } + + memset(ring_header->desc, 0, ring_header->size); + + /* init TPD ring */ + tpd_ring->dma = ring_header->dma; + offset = (tpd_ring->dma & 0x7) ? (8 - (ring_header->dma & 0x7)) : 0; + tpd_ring->dma += offset; + tpd_ring->desc = (u8 *) ring_header->desc + offset; + tpd_ring->size = sizeof(struct tx_packet_desc) * tpd_ring->count; + atomic_set(&tpd_ring->next_to_use, 0); + atomic_set(&tpd_ring->next_to_clean, 0); + + /* init RFD ring */ + rfd_ring->dma = tpd_ring->dma + tpd_ring->size; + offset = (rfd_ring->dma & 0x7) ? (8 - (rfd_ring->dma & 0x7)) : 0; + rfd_ring->dma += offset; + rfd_ring->desc = (u8 *) tpd_ring->desc + (tpd_ring->size + offset); + rfd_ring->size = sizeof(struct rx_free_desc) * rfd_ring->count; + rfd_ring->next_to_clean = 0; + /* rfd_ring->next_to_use = rfd_ring->count - 1; */ + atomic_set(&rfd_ring->next_to_use, 0); + + /* init RRD ring */ + rrd_ring->dma = rfd_ring->dma + rfd_ring->size; + offset = (rrd_ring->dma & 0x7) ? (8 - (rrd_ring->dma & 0x7)) : 0; + rrd_ring->dma += offset; + rrd_ring->desc = (u8 *) rfd_ring->desc + (rfd_ring->size + offset); + rrd_ring->size = sizeof(struct rx_return_desc) * rrd_ring->count; + rrd_ring->next_to_use = 0; + atomic_set(&rrd_ring->next_to_clean, 0); + + /* init CMB */ + adapter->cmb.dma = rrd_ring->dma + rrd_ring->size; + offset = (adapter->cmb.dma & 0x7) ? (8 - (adapter->cmb.dma & 0x7)) : 0; + adapter->cmb.dma += offset; + adapter->cmb.cmb = + (struct coals_msg_block *) ((u8 *) rrd_ring->desc + + (rrd_ring->size + offset)); + + /* init SMB */ + adapter->smb.dma = adapter->cmb.dma + sizeof(struct coals_msg_block); + offset = (adapter->smb.dma & 0x7) ? (8 - (adapter->smb.dma & 0x7)) : 0; + adapter->smb.dma += offset; + adapter->smb.smb = (struct stats_msg_block *) + ((u8 *) adapter->cmb.cmb + (sizeof(struct coals_msg_block) + offset)); + + return ATL1_SUCCESS; + +err_nomem: + kfree(tpd_ring->buffer_info); + return -ENOMEM; +} + +/* + * atl1_irq_enable - Enable default interrupt generation settings + * @adapter: board private structure + */ +static void atl1_irq_enable(struct atl1_adapter *adapter) +{ + if (likely(!atomic_dec_and_test(&adapter->irq_sem))) + iowrite32(IMR_NORMAL_MASK, adapter->hw.hw_addr + REG_IMR); +} + +static void atl1_clear_phy_int(struct atl1_adapter *adapter) +{ + u16 phy_data; + unsigned long flags; + + spin_lock_irqsave(&adapter->lock, flags); + atl1_read_phy_reg(&adapter->hw, 19, &phy_data); + spin_unlock_irqrestore(&adapter->lock, flags); +} + +static void atl1_inc_smb(struct atl1_adapter *adapter) +{ + struct stats_msg_block *smb = adapter->smb.smb; + + /* Fill out the OS statistics structure */ + adapter->soft_stats.rx_packets += smb->rx_ok; + adapter->soft_stats.tx_packets += smb->tx_ok; + adapter->soft_stats.rx_bytes += smb->rx_byte_cnt; + adapter->soft_stats.tx_bytes += smb->tx_byte_cnt; + adapter->soft_stats.multicast += smb->rx_mcast; + adapter->soft_stats.collisions += (smb->tx_1_col + + smb->tx_2_col * 2 + + smb->tx_late_col + + smb->tx_abort_col * + adapter->hw.max_retry); + + /* Rx Errors */ + adapter->soft_stats.rx_errors += (smb->rx_frag + + smb->rx_fcs_err + + smb->rx_len_err + + smb->rx_sz_ov + + smb->rx_rxf_ov + + smb->rx_rrd_ov + smb->rx_align_err); + adapter->soft_stats.rx_fifo_errors += smb->rx_rxf_ov; + adapter->soft_stats.rx_length_errors += smb->rx_len_err; + adapter->soft_stats.rx_crc_errors += smb->rx_fcs_err; + adapter->soft_stats.rx_frame_errors += smb->rx_align_err; + adapter->soft_stats.rx_missed_errors += (smb->rx_rrd_ov + + smb->rx_rxf_ov); + + adapter->soft_stats.rx_pause += smb->rx_pause; + adapter->soft_stats.rx_rrd_ov += smb->rx_rrd_ov; + adapter->soft_stats.rx_trunc += smb->rx_sz_ov; + + /* Tx Errors */ + adapter->soft_stats.tx_errors += (smb->tx_late_col + + smb->tx_abort_col + + smb->tx_underrun + smb->tx_trunc); + adapter->soft_stats.tx_fifo_errors += smb->tx_underrun; + adapter->soft_stats.tx_aborted_errors += smb->tx_abort_col; + adapter->soft_stats.tx_window_errors += smb->tx_late_col; + + adapter->soft_stats.excecol += smb->tx_abort_col; + adapter->soft_stats.deffer += smb->tx_defer; + adapter->soft_stats.scc += smb->tx_1_col; + adapter->soft_stats.mcc += smb->tx_2_col; + adapter->soft_stats.latecol += smb->tx_late_col; + adapter->soft_stats.tx_underun += smb->tx_underrun; + adapter->soft_stats.tx_trunc += smb->tx_trunc; + adapter->soft_stats.tx_pause += smb->tx_pause; + + adapter->net_stats.rx_packets = adapter->soft_stats.rx_packets; + adapter->net_stats.tx_packets = adapter->soft_stats.tx_packets; + adapter->net_stats.rx_bytes = adapter->soft_stats.rx_bytes; + adapter->net_stats.tx_bytes = adapter->soft_stats.tx_bytes; + adapter->net_stats.multicast = adapter->soft_stats.multicast; + adapter->net_stats.collisions = adapter->soft_stats.collisions; + adapter->net_stats.rx_errors = adapter->soft_stats.rx_errors; + adapter->net_stats.rx_over_errors = + adapter->soft_stats.rx_missed_errors; + adapter->net_stats.rx_length_errors = + adapter->soft_stats.rx_length_errors; + adapter->net_stats.rx_crc_errors = adapter->soft_stats.rx_crc_errors; + adapter->net_stats.rx_frame_errors = + adapter->soft_stats.rx_frame_errors; + adapter->net_stats.rx_fifo_errors = adapter->soft_stats.rx_fifo_errors; + adapter->net_stats.rx_missed_errors = + adapter->soft_stats.rx_missed_errors; + adapter->net_stats.tx_errors = adapter->soft_stats.tx_errors; + adapter->net_stats.tx_fifo_errors = adapter->soft_stats.tx_fifo_errors; + adapter->net_stats.tx_aborted_errors = + adapter->soft_stats.tx_aborted_errors; + adapter->net_stats.tx_window_errors = + adapter->soft_stats.tx_window_errors; + adapter->net_stats.tx_carrier_errors = + adapter->soft_stats.tx_carrier_errors; +} + +static void atl1_rx_checksum(struct atl1_adapter *adapter, + struct rx_return_desc *rrd, + struct sk_buff *skb) +{ + skb->ip_summed = CHECKSUM_NONE; + + if (unlikely(rrd->pkt_flg & PACKET_FLAG_ERR)) { + if (rrd->err_flg & (ERR_FLAG_CRC | ERR_FLAG_TRUNC | + ERR_FLAG_CODE | ERR_FLAG_OV)) { + adapter->hw_csum_err++; + printk(KERN_DEBUG "%s: rx checksum error\n", + atl1_driver_name); + return; + } + } + + /* not IPv4 */ + if (!(rrd->pkt_flg & PACKET_FLAG_IPV4)) + /* checksum is invalid, but it's not an IPv4 pkt, so ok */ + return; + + /* IPv4 packet */ + if (likely(!(rrd->err_flg & + (ERR_FLAG_IP_CHKSUM | ERR_FLAG_L4_CHKSUM)))) { + skb->ip_summed = CHECKSUM_UNNECESSARY; + adapter->hw_csum_good++; + return; + } + + /* IPv4, but hardware thinks its checksum is wrong */ + printk(KERN_DEBUG "%s: hw csum wrong pkt_flag:%x, err_flag:%x\n", + atl1_driver_name, rrd->pkt_flg, rrd->err_flg); + skb->ip_summed = CHECKSUM_COMPLETE; + skb->csum = htons(rrd->xsz.xsum_sz.rx_chksum); + adapter->hw_csum_err++; + return; +} + +/* + * atl1_alloc_rx_buffers - Replace used receive buffers + * @adapter: address of board private structure + */ +static u16 atl1_alloc_rx_buffers(struct atl1_adapter *adapter) +{ + struct atl1_rfd_ring *rfd_ring = &adapter->rfd_ring; + struct net_device *netdev = adapter->netdev; + struct pci_dev *pdev = adapter->pdev; + struct page *page; + unsigned long offset; + struct atl1_buffer *buffer_info, *next_info; + struct sk_buff *skb; + u16 num_alloc = 0; + u16 rfd_next_to_use, next_next; + struct rx_free_desc *rfd_desc; + + next_next = rfd_next_to_use = atomic_read(&rfd_ring->next_to_use); + if (++next_next == rfd_ring->count) + next_next = 0; + buffer_info = &rfd_ring->buffer_info[rfd_next_to_use]; + next_info = &rfd_ring->buffer_info[next_next]; + + while (!buffer_info->alloced && !next_info->alloced) { + if (buffer_info->skb) { + buffer_info->alloced = 1; + goto next; + } + + rfd_desc = ATL1_RFD_DESC(rfd_ring, rfd_next_to_use); + + skb = dev_alloc_skb(adapter->rx_buffer_len + NET_IP_ALIGN); + if (unlikely(!skb)) { /* Better luck next round */ + adapter->net_stats.rx_dropped++; + break; + } + + /* + * Make buffer alignment 2 beyond a 16 byte boundary + * this will result in a 16 byte aligned IP header after + * the 14 byte MAC header is removed + */ + skb_reserve(skb, NET_IP_ALIGN); + skb->dev = netdev; + + buffer_info->alloced = 1; + buffer_info->skb = skb; + buffer_info->length = (u16) adapter->rx_buffer_len; + page = virt_to_page(skb->data); + offset = (unsigned long)skb->data & ~PAGE_MASK; + buffer_info->dma = pci_map_page(pdev, page, offset, + adapter->rx_buffer_len, + PCI_DMA_FROMDEVICE); + rfd_desc->buffer_addr = cpu_to_le64(buffer_info->dma); + rfd_desc->buf_len = cpu_to_le16(adapter->rx_buffer_len); + rfd_desc->coalese = 0; + +next: + rfd_next_to_use = next_next; + if (unlikely(++next_next == rfd_ring->count)) + next_next = 0; + + buffer_info = &rfd_ring->buffer_info[rfd_next_to_use]; + next_info = &rfd_ring->buffer_info[next_next]; + num_alloc++; + } + + if (num_alloc) { + /* + * Force memory writes to complete before letting h/w + * know there are new descriptors to fetch. (Only + * applicable for weak-ordered memory model archs, + * such as IA-64). + */ + wmb(); + atomic_set(&rfd_ring->next_to_use, (int)rfd_next_to_use); + } + return num_alloc; +} + +static void atl1_intr_rx(struct atl1_adapter *adapter) +{ + int i, count; + u16 length; + u16 rrd_next_to_clean; + u32 value; + struct atl1_rfd_ring *rfd_ring = &adapter->rfd_ring; + struct atl1_rrd_ring *rrd_ring = &adapter->rrd_ring; + struct atl1_buffer *buffer_info; + struct rx_return_desc *rrd; + struct sk_buff *skb; + + count = 0; + + rrd_next_to_clean = atomic_read(&rrd_ring->next_to_clean); + + while (1) { + rrd = ATL1_RRD_DESC(rrd_ring, rrd_next_to_clean); + i = 1; + if (likely(rrd->xsz.valid)) { /* packet valid */ +chk_rrd: + /* check rrd status */ + if (likely(rrd->num_buf == 1)) + goto rrd_ok; + + /* rrd seems to be bad */ + if (unlikely(i-- > 0)) { + /* rrd may not be DMAed completely */ + printk(KERN_DEBUG + "%s: RRD may not be DMAed completely\n", + atl1_driver_name); + udelay(1); + goto chk_rrd; + } + /* bad rrd */ + printk(KERN_DEBUG "%s: bad RRD\n", atl1_driver_name); + /* see if update RFD index */ + if (rrd->num_buf > 1) { + u16 num_buf; + num_buf = + (rrd->xsz.xsum_sz.pkt_size + + adapter->rx_buffer_len - + 1) / adapter->rx_buffer_len; + if (rrd->num_buf == num_buf) { + /* clean alloc flag for bad rrd */ + while (rfd_ring->next_to_clean != + (rrd->buf_indx + num_buf)) { + rfd_ring->buffer_info[rfd_ring-> + next_to_clean].alloced = 0; + if (++rfd_ring->next_to_clean == + rfd_ring->count) { + rfd_ring-> + next_to_clean = 0; + } + } + } + } + + /* update rrd */ + rrd->xsz.valid = 0; + if (++rrd_next_to_clean == rrd_ring->count) + rrd_next_to_clean = 0; + count++; + continue; + } else { /* current rrd still not be updated */ + + break; + } +rrd_ok: + /* clean alloc flag for bad rrd */ + while (rfd_ring->next_to_clean != rrd->buf_indx) { + rfd_ring->buffer_info[rfd_ring->next_to_clean].alloced = + 0; + if (++rfd_ring->next_to_clean == rfd_ring->count) + rfd_ring->next_to_clean = 0; + } + + buffer_info = &rfd_ring->buffer_info[rrd->buf_indx]; + if (++rfd_ring->next_to_clean == rfd_ring->count) + rfd_ring->next_to_clean = 0; + + /* update rrd next to clean */ + if (++rrd_next_to_clean == rrd_ring->count) + rrd_next_to_clean = 0; + count++; + + if (unlikely(rrd->pkt_flg & PACKET_FLAG_ERR)) { + if (!(rrd->err_flg & + (ERR_FLAG_IP_CHKSUM | ERR_FLAG_L4_CHKSUM + | ERR_FLAG_LEN))) { + /* packet error, don't need upstream */ + buffer_info->alloced = 0; + rrd->xsz.valid = 0; + continue; + } + } + + /* Good Receive */ + pci_unmap_page(adapter->pdev, buffer_info->dma, + buffer_info->length, PCI_DMA_FROMDEVICE); + skb = buffer_info->skb; + length = le16_to_cpu(rrd->xsz.xsum_sz.pkt_size); + + skb_put(skb, length - ETHERNET_FCS_SIZE); + + /* Receive Checksum Offload */ + atl1_rx_checksum(adapter, rrd, skb); + skb->protocol = eth_type_trans(skb, adapter->netdev); + + if (adapter->vlgrp && (rrd->pkt_flg & PACKET_FLAG_VLAN_INS)) { + u16 vlan_tag = (rrd->vlan_tag >> 4) | + ((rrd->vlan_tag & 7) << 13) | + ((rrd->vlan_tag & 8) << 9); + vlan_hwaccel_rx(skb, adapter->vlgrp, vlan_tag); + } else + netif_rx(skb); + + /* let protocol layer free skb */ + buffer_info->skb = NULL; + buffer_info->alloced = 0; + rrd->xsz.valid = 0; + + adapter->netdev->last_rx = jiffies; + } + + atomic_set(&rrd_ring->next_to_clean, rrd_next_to_clean); + + atl1_alloc_rx_buffers(adapter); + + /* update mailbox ? */ + if (count) { + u32 tpd_next_to_use; + u32 rfd_next_to_use; + u32 rrd_next_to_clean; + + spin_lock(&adapter->mb_lock); + + tpd_next_to_use = atomic_read(&adapter->tpd_ring.next_to_use); + rfd_next_to_use = + atomic_read(&adapter->rfd_ring.next_to_use); + rrd_next_to_clean = + atomic_read(&adapter->rrd_ring.next_to_clean); + value = ((rfd_next_to_use & MB_RFD_PROD_INDX_MASK) << + MB_RFD_PROD_INDX_SHIFT) | + ((rrd_next_to_clean & MB_RRD_CONS_INDX_MASK) << + MB_RRD_CONS_INDX_SHIFT) | + ((tpd_next_to_use & MB_TPD_PROD_INDX_MASK) << + MB_TPD_PROD_INDX_SHIFT); + iowrite32(value, adapter->hw.hw_addr + REG_MAILBOX); + spin_unlock(&adapter->mb_lock); + } +} + +static void atl1_intr_tx(struct atl1_adapter *adapter) +{ + struct atl1_tpd_ring *tpd_ring = &adapter->tpd_ring; + struct atl1_buffer *buffer_info; + u16 sw_tpd_next_to_clean; + u16 cmb_tpd_next_to_clean; + u8 update = 0; + + sw_tpd_next_to_clean = atomic_read(&tpd_ring->next_to_clean); + cmb_tpd_next_to_clean = le16_to_cpu(adapter->cmb.cmb->tpd_cons_idx); + + while (cmb_tpd_next_to_clean != sw_tpd_next_to_clean) { + struct tx_packet_desc *tpd; + update = 1; + tpd = ATL1_TPD_DESC(tpd_ring, sw_tpd_next_to_clean); + buffer_info = &tpd_ring->buffer_info[sw_tpd_next_to_clean]; + if (buffer_info->dma) { + pci_unmap_page(adapter->pdev, buffer_info->dma, + buffer_info->length, PCI_DMA_TODEVICE); + buffer_info->dma = 0; + } + + if (buffer_info->skb) { + dev_kfree_skb_irq(buffer_info->skb); + buffer_info->skb = NULL; + } + tpd->buffer_addr = 0; + tpd->desc.data = 0; + + if (++sw_tpd_next_to_clean == tpd_ring->count) + sw_tpd_next_to_clean = 0; + } + atomic_set(&tpd_ring->next_to_clean, sw_tpd_next_to_clean); + + if (netif_queue_stopped(adapter->netdev) + && netif_carrier_ok(adapter->netdev)) + netif_wake_queue(adapter->netdev); +} + +static void atl1_check_for_link(struct atl1_adapter *adapter) +{ + struct net_device *netdev = adapter->netdev; + u16 phy_data = 0; + + spin_lock(&adapter->lock); + adapter->phy_timer_pending = false; + atl1_read_phy_reg(&adapter->hw, MII_BMSR, &phy_data); + atl1_read_phy_reg(&adapter->hw, MII_BMSR, &phy_data); + spin_unlock(&adapter->lock); + + /* notify upper layer link down ASAP */ + if (!(phy_data & BMSR_LSTATUS)) { /* Link Down */ + if (netif_carrier_ok(netdev)) { /* old link state: Up */ + printk(KERN_INFO "%s: %s link is down\n", + atl1_driver_name, netdev->name); + adapter->link_speed = SPEED_0; + netif_carrier_off(netdev); + netif_stop_queue(netdev); + } + } + schedule_work(&adapter->link_chg_task); +} + +/* + * atl1_intr - Interrupt Handler + * @irq: interrupt number + * @data: pointer to a network interface device structure + * @pt_regs: CPU registers structure + */ +static irqreturn_t atl1_intr(int irq, void *data) +{ + /*struct atl1_adapter *adapter = ((struct net_device *)data)->priv;*/ + struct atl1_adapter *adapter = netdev_priv(data); + u32 status; + u8 update_rx; + int max_ints = 10; + + status = adapter->cmb.cmb->int_stats; + if (!status) + return IRQ_NONE; + + update_rx = 0; + + do { + /* clear CMB interrupt status at once */ + adapter->cmb.cmb->int_stats = 0; + + if (status & ISR_GPHY) /* clear phy status */ + atl1_clear_phy_int(adapter); + + /* clear ISR status, and Enable CMB DMA/Disable Interrupt */ + iowrite32(status | ISR_DIS_INT, adapter->hw.hw_addr + REG_ISR); + + /* check if SMB intr */ + if (status & ISR_SMB) + atl1_inc_smb(adapter); + + /* check if PCIE PHY Link down */ + if (status & ISR_PHY_LINKDOWN) { + printk(KERN_DEBUG "%s: pcie phy link down %x\n", + atl1_driver_name, status); + if (netif_running(adapter->netdev)) { /* reset MAC */ + iowrite32(0, adapter->hw.hw_addr + REG_IMR); + schedule_work(&adapter->pcie_dma_to_rst_task); + return IRQ_HANDLED; + } + } + + /* check if DMA read/write error ? */ + if (status & (ISR_DMAR_TO_RST | ISR_DMAW_TO_RST)) { + printk(KERN_DEBUG + "%s: pcie DMA r/w error (status = 0x%x)\n", + atl1_driver_name, status); + iowrite32(0, adapter->hw.hw_addr + REG_IMR); + schedule_work(&adapter->pcie_dma_to_rst_task); + return IRQ_HANDLED; + } + + /* link event */ + if (status & ISR_GPHY) { + adapter->soft_stats.tx_carrier_errors++; + atl1_check_for_link(adapter); + } + + /* transmit event */ + if (status & ISR_CMB_TX) + atl1_intr_tx(adapter); + + /* rx exception */ + if (unlikely(status & (ISR_RXF_OV | ISR_RFD_UNRUN | + ISR_RRD_OV | ISR_HOST_RFD_UNRUN | + ISR_HOST_RRD_OV | ISR_CMB_RX))) { + if (status & + (ISR_RXF_OV | ISR_RFD_UNRUN | ISR_RRD_OV | + ISR_HOST_RFD_UNRUN | ISR_HOST_RRD_OV)) + printk(KERN_INFO + "%s: rx exception: status = 0x%x\n", + atl1_driver_name, status); + atl1_intr_rx(adapter); + } + + if (--max_ints < 0) + break; + + } while ((status = adapter->cmb.cmb->int_stats)); + + /* re-enable Interrupt */ + iowrite32(ISR_DIS_SMB | ISR_DIS_DMA, adapter->hw.hw_addr + REG_ISR); + return IRQ_HANDLED; +} + +/* + * atl1_set_multi - Multicast and Promiscuous mode set + * @netdev: network interface device structure + * + * The set_multi entry point is called whenever the multicast address + * list or the network interface flags are updated. This routine is + * responsible for configuring the hardware for proper multicast, + * promiscuous mode, and all-multi behavior. + */ +static void atl1_set_multi(struct net_device *netdev) +{ + struct atl1_adapter *adapter = netdev_priv(netdev); + struct atl1_hw *hw = &adapter->hw; + struct dev_mc_list *mc_ptr; + u32 rctl; + u32 hash_value; + + /* Check for Promiscuous and All Multicast modes */ + rctl = ioread32(hw->hw_addr + REG_MAC_CTRL); + if (netdev->flags & IFF_PROMISC) + rctl |= MAC_CTRL_PROMIS_EN; + else if (netdev->flags & IFF_ALLMULTI) { + rctl |= MAC_CTRL_MC_ALL_EN; + rctl &= ~MAC_CTRL_PROMIS_EN; + } else + rctl &= ~(MAC_CTRL_PROMIS_EN | MAC_CTRL_MC_ALL_EN); + + iowrite32(rctl, hw->hw_addr + REG_MAC_CTRL); + + /* clear the old settings from the multicast hash table */ + iowrite32(0, hw->hw_addr + REG_RX_HASH_TABLE); + iowrite32(0, (hw->hw_addr + REG_RX_HASH_TABLE) + (1 << 2)); + + /* compute mc addresses' hash value ,and put it into hash table */ + for (mc_ptr = netdev->mc_list; mc_ptr; mc_ptr = mc_ptr->next) { + hash_value = atl1_hash_mc_addr(hw, mc_ptr->dmi_addr); + atl1_hash_set(hw, hash_value); + } +} + +static void atl1_setup_mac_ctrl(struct atl1_adapter *adapter) +{ + u32 value; + struct atl1_hw *hw = &adapter->hw; + struct net_device *netdev = adapter->netdev; + /* Config MAC CTRL Register */ + value = MAC_CTRL_TX_EN | MAC_CTRL_RX_EN; + /* duplex */ + if (FULL_DUPLEX == adapter->link_duplex) + value |= MAC_CTRL_DUPLX; + /* speed */ + value |= ((u32) ((SPEED_1000 == adapter->link_speed) ? + MAC_CTRL_SPEED_1000 : MAC_CTRL_SPEED_10_100) << + MAC_CTRL_SPEED_SHIFT); + /* flow control */ + value |= (MAC_CTRL_TX_FLOW | MAC_CTRL_RX_FLOW); + /* PAD & CRC */ + value |= (MAC_CTRL_ADD_CRC | MAC_CTRL_PAD); + /* preamble length */ + value |= (((u32) adapter->hw.preamble_len + & MAC_CTRL_PRMLEN_MASK) << MAC_CTRL_PRMLEN_SHIFT); + /* vlan */ + if (adapter->vlgrp) + value |= MAC_CTRL_RMV_VLAN; + /* rx checksum + if (adapter->rx_csum) + value |= MAC_CTRL_RX_CHKSUM_EN; + */ + /* filter mode */ + value |= MAC_CTRL_BC_EN; + if (netdev->flags & IFF_PROMISC) + value |= MAC_CTRL_PROMIS_EN; + else if (netdev->flags & IFF_ALLMULTI) + value |= MAC_CTRL_MC_ALL_EN; + /* value |= MAC_CTRL_LOOPBACK; */ + iowrite32(value, hw->hw_addr + REG_MAC_CTRL); +} + +static u32 atl1_check_link(struct atl1_adapter *adapter) +{ + struct atl1_hw *hw = &adapter->hw; + struct net_device *netdev = adapter->netdev; + u32 ret_val; + u16 speed, duplex, phy_data; + int reconfig = 0; + + /* MII_BMSR must read twice */ + atl1_read_phy_reg(hw, MII_BMSR, &phy_data); + atl1_read_phy_reg(hw, MII_BMSR, &phy_data); + if (!(phy_data & BMSR_LSTATUS)) { /* link down */ + if (netif_carrier_ok(netdev)) { /* old link state: Up */ + printk(KERN_INFO "%s: link is down\n", + atl1_driver_name); + adapter->link_speed = SPEED_0; + netif_carrier_off(netdev); + netif_stop_queue(netdev); + } + return ATL1_SUCCESS; + } + + /* Link Up */ + ret_val = atl1_get_speed_and_duplex(hw, &speed, &duplex); + if (ret_val) + return ret_val; + + switch (hw->media_type) { + case MEDIA_TYPE_1000M_FULL: + if (speed != SPEED_1000 || duplex != FULL_DUPLEX) + reconfig = 1; + break; + case MEDIA_TYPE_100M_FULL: + if (speed != SPEED_100 || duplex != FULL_DUPLEX) + reconfig = 1; + break; + case MEDIA_TYPE_100M_HALF: + if (speed != SPEED_100 || duplex != HALF_DUPLEX) + reconfig = 1; + break; + case MEDIA_TYPE_10M_FULL: + if (speed != SPEED_10 || duplex != FULL_DUPLEX) + reconfig = 1; + break; + case MEDIA_TYPE_10M_HALF: + if (speed != SPEED_10 || duplex != HALF_DUPLEX) + reconfig = 1; + break; + } + + /* link result is our setting */ + if (!reconfig) { + if (adapter->link_speed != speed + || adapter->link_duplex != duplex) { + adapter->link_speed = speed; + adapter->link_duplex = duplex; + atl1_setup_mac_ctrl(adapter); + printk(KERN_INFO "%s: %s link is up %d Mbps %s\n", + atl1_driver_name, netdev->name, + adapter->link_speed, + adapter->link_duplex == + FULL_DUPLEX ? "full duplex" : "half duplex"); + } + if (!netif_carrier_ok(netdev)) { /* Link down -> Up */ + netif_carrier_on(netdev); + netif_wake_queue(netdev); + } + return ATL1_SUCCESS; + } + + /* change orignal link status */ + if (netif_carrier_ok(netdev)) { + adapter->link_speed = SPEED_0; + netif_carrier_off(netdev); + netif_stop_queue(netdev); + } + + if (hw->media_type != MEDIA_TYPE_AUTO_SENSOR && + hw->media_type != MEDIA_TYPE_1000M_FULL) { + switch (hw->media_type) { + case MEDIA_TYPE_100M_FULL: + phy_data = MII_CR_FULL_DUPLEX | MII_CR_SPEED_100 | + MII_CR_RESET; + break; + case MEDIA_TYPE_100M_HALF: + phy_data = MII_CR_SPEED_100 | MII_CR_RESET; + break; + case MEDIA_TYPE_10M_FULL: + phy_data = + MII_CR_FULL_DUPLEX | MII_CR_SPEED_10 | MII_CR_RESET; + break; + default: /* MEDIA_TYPE_10M_HALF: */ + phy_data = MII_CR_SPEED_10 | MII_CR_RESET; + break; + } + atl1_write_phy_reg(hw, MII_BMCR, phy_data); + return ATL1_SUCCESS; + } + + /* auto-neg, insert timer to re-config phy */ + if (!adapter->phy_timer_pending) { + adapter->phy_timer_pending = true; + mod_timer(&adapter->phy_config_timer, jiffies + 3 * HZ); + } + + return ATL1_SUCCESS; +} + +static void set_flow_ctrl_old(struct atl1_adapter *adapter) +{ + u32 hi, lo, value; + + /* RFD Flow Control */ + value = adapter->rfd_ring.count; + hi = value / 16; + if (hi < 2) + hi = 2; + lo = value * 7 / 8; + + value = ((hi & RXQ_RXF_PAUSE_TH_HI_MASK) << RXQ_RXF_PAUSE_TH_HI_SHIFT) | + ((lo & RXQ_RXF_PAUSE_TH_LO_MASK) << RXQ_RXF_PAUSE_TH_LO_SHIFT); + iowrite32(value, adapter->hw.hw_addr + REG_RXQ_RXF_PAUSE_THRESH); + + /* RRD Flow Control */ + value = adapter->rrd_ring.count; + lo = value / 16; + hi = value * 7 / 8; + if (lo < 2) + lo = 2; + value = ((hi & RXQ_RRD_PAUSE_TH_HI_MASK) << RXQ_RRD_PAUSE_TH_HI_SHIFT) | + ((lo & RXQ_RRD_PAUSE_TH_LO_MASK) << RXQ_RRD_PAUSE_TH_LO_SHIFT); + iowrite32(value, adapter->hw.hw_addr + REG_RXQ_RRD_PAUSE_THRESH); +} + +static void set_flow_ctrl_new(struct atl1_hw *hw) +{ + u32 hi, lo, value; + + /* RXF Flow Control */ + value = ioread32(hw->hw_addr + REG_SRAM_RXF_LEN); + lo = value / 16; + if (lo < 192) + lo = 192; + hi = value * 7 / 8; + if (hi < lo) + hi = lo + 16; + value = ((hi & RXQ_RXF_PAUSE_TH_HI_MASK) << RXQ_RXF_PAUSE_TH_HI_SHIFT) | + ((lo & RXQ_RXF_PAUSE_TH_LO_MASK) << RXQ_RXF_PAUSE_TH_LO_SHIFT); + iowrite32(value, hw->hw_addr + REG_RXQ_RXF_PAUSE_THRESH); + + /* RRD Flow Control */ + value = ioread32(hw->hw_addr + REG_SRAM_RRD_LEN); + lo = value / 8; + hi = value * 7 / 8; + if (lo < 2) + lo = 2; + if (hi < lo) + hi = lo + 3; + value = ((hi & RXQ_RRD_PAUSE_TH_HI_MASK) << RXQ_RRD_PAUSE_TH_HI_SHIFT) | + ((lo & RXQ_RRD_PAUSE_TH_LO_MASK) << RXQ_RRD_PAUSE_TH_LO_SHIFT); + iowrite32(value, hw->hw_addr + REG_RXQ_RRD_PAUSE_THRESH); +} + +/* + * atl1_configure - Configure Transmit&Receive Unit after Reset + * @adapter: board private structure + * + * Configure the Tx /Rx unit of the MAC after a reset. + */ +static u32 atl1_configure(struct atl1_adapter *adapter) +{ + struct atl1_hw *hw = &adapter->hw; + u32 value; + + /* clear interrupt status */ + iowrite32(0xffffffff, adapter->hw.hw_addr + REG_ISR); + + /* set MAC Address */ + value = (((u32) hw->mac_addr[2]) << 24) | + (((u32) hw->mac_addr[3]) << 16) | + (((u32) hw->mac_addr[4]) << 8) | + (((u32) hw->mac_addr[5])); + iowrite32(value, hw->hw_addr + REG_MAC_STA_ADDR); + value = (((u32) hw->mac_addr[0]) << 8) | (((u32) hw->mac_addr[1])); + iowrite32(value, hw->hw_addr + (REG_MAC_STA_ADDR + 4)); + + /* tx / rx ring */ + + /* HI base address */ + iowrite32((u32) ((adapter->tpd_ring.dma & 0xffffffff00000000ULL) >> 32), + hw->hw_addr + REG_DESC_BASE_ADDR_HI); + /* LO base address */ + iowrite32((u32) (adapter->rfd_ring.dma & 0x00000000ffffffffULL), + hw->hw_addr + REG_DESC_RFD_ADDR_LO); + iowrite32((u32) (adapter->rrd_ring.dma & 0x00000000ffffffffULL), + hw->hw_addr + REG_DESC_RRD_ADDR_LO); + iowrite32((u32) (adapter->tpd_ring.dma & 0x00000000ffffffffULL), + hw->hw_addr + REG_DESC_TPD_ADDR_LO); + iowrite32((u32) (adapter->cmb.dma & 0x00000000ffffffffULL), + hw->hw_addr + REG_DESC_CMB_ADDR_LO); + iowrite32((u32) (adapter->smb.dma & 0x00000000ffffffffULL), + hw->hw_addr + REG_DESC_SMB_ADDR_LO); + + /* element count */ + value = adapter->rrd_ring.count; + value <<= 16; + value += adapter->rfd_ring.count; + iowrite32(value, hw->hw_addr + REG_DESC_RFD_RRD_RING_SIZE); + iowrite32(adapter->tpd_ring.count, hw->hw_addr + REG_DESC_TPD_RING_SIZE); + + /* Load Ptr */ + iowrite32(1, hw->hw_addr + REG_LOAD_PTR); + + /* config Mailbox */ + value = ((atomic_read(&adapter->tpd_ring.next_to_use) + & MB_TPD_PROD_INDX_MASK) << MB_TPD_PROD_INDX_SHIFT) | + ((atomic_read(&adapter->rrd_ring.next_to_clean) + & MB_RRD_CONS_INDX_MASK) << MB_RRD_CONS_INDX_SHIFT) | + ((atomic_read(&adapter->rfd_ring.next_to_use) + & MB_RFD_PROD_INDX_MASK) << MB_RFD_PROD_INDX_SHIFT); + iowrite32(value, hw->hw_addr + REG_MAILBOX); + + /* config IPG/IFG */ + value = (((u32) hw->ipgt & MAC_IPG_IFG_IPGT_MASK) + << MAC_IPG_IFG_IPGT_SHIFT) | + (((u32) hw->min_ifg & MAC_IPG_IFG_MIFG_MASK) + << MAC_IPG_IFG_MIFG_SHIFT) | + (((u32) hw->ipgr1 & MAC_IPG_IFG_IPGR1_MASK) + << MAC_IPG_IFG_IPGR1_SHIFT) | + (((u32) hw->ipgr2 & MAC_IPG_IFG_IPGR2_MASK) + << MAC_IPG_IFG_IPGR2_SHIFT); + iowrite32(value, hw->hw_addr + REG_MAC_IPG_IFG); + + /* config Half-Duplex Control */ + value = ((u32) hw->lcol & MAC_HALF_DUPLX_CTRL_LCOL_MASK) | + (((u32) hw->max_retry & MAC_HALF_DUPLX_CTRL_RETRY_MASK) + << MAC_HALF_DUPLX_CTRL_RETRY_SHIFT) | + MAC_HALF_DUPLX_CTRL_EXC_DEF_EN | + (0xa << MAC_HALF_DUPLX_CTRL_ABEBT_SHIFT) | + (((u32) hw->jam_ipg & MAC_HALF_DUPLX_CTRL_JAMIPG_MASK) + << MAC_HALF_DUPLX_CTRL_JAMIPG_SHIFT); + iowrite32(value, hw->hw_addr + REG_MAC_HALF_DUPLX_CTRL); + + /* set Interrupt Moderator Timer */ + iowrite16(adapter->imt, hw->hw_addr + REG_IRQ_MODU_TIMER_INIT); + iowrite32(MASTER_CTRL_ITIMER_EN, hw->hw_addr + REG_MASTER_CTRL); + + /* set Interrupt Clear Timer */ + iowrite16(adapter->ict, hw->hw_addr + REG_CMBDISDMA_TIMER); + + /* set MTU, 4 : VLAN */ + iowrite32(hw->max_frame_size + 4, hw->hw_addr + REG_MTU); + + /* jumbo size & rrd retirement timer */ + value = (((u32) hw->rx_jumbo_th & RXQ_JMBOSZ_TH_MASK) + << RXQ_JMBOSZ_TH_SHIFT) | + (((u32) hw->rx_jumbo_lkah & RXQ_JMBO_LKAH_MASK) + << RXQ_JMBO_LKAH_SHIFT) | + (((u32) hw->rrd_ret_timer & RXQ_RRD_TIMER_MASK) + << RXQ_RRD_TIMER_SHIFT); + iowrite32(value, hw->hw_addr + REG_RXQ_JMBOSZ_RRDTIM); + + /* Flow Control */ + switch (hw->dev_rev) { + case 0x8001: + case 0x9001: + case 0x9002: + case 0x9003: + set_flow_ctrl_old(adapter); + break; + default: + set_flow_ctrl_new(hw); + break; + } + + /* config TXQ */ + value = (((u32) hw->tpd_burst & TXQ_CTRL_TPD_BURST_NUM_MASK) + << TXQ_CTRL_TPD_BURST_NUM_SHIFT) | + (((u32) hw->txf_burst & TXQ_CTRL_TXF_BURST_NUM_MASK) + << TXQ_CTRL_TXF_BURST_NUM_SHIFT) | + (((u32) hw->tpd_fetch_th & TXQ_CTRL_TPD_FETCH_TH_MASK) + << TXQ_CTRL_TPD_FETCH_TH_SHIFT) | TXQ_CTRL_ENH_MODE | TXQ_CTRL_EN; + iowrite32(value, hw->hw_addr + REG_TXQ_CTRL); + + /* min tpd fetch gap & tx jumbo packet size threshold for taskoffload */ + value = (((u32) hw->tx_jumbo_task_th & TX_JUMBO_TASK_TH_MASK) + << TX_JUMBO_TASK_TH_SHIFT) | + (((u32) hw->tpd_fetch_gap & TX_TPD_MIN_IPG_MASK) + << TX_TPD_MIN_IPG_SHIFT); + iowrite32(value, hw->hw_addr + REG_TX_JUMBO_TASK_TH_TPD_IPG); + + /* config RXQ */ + value = (((u32) hw->rfd_burst & RXQ_CTRL_RFD_BURST_NUM_MASK) + << RXQ_CTRL_RFD_BURST_NUM_SHIFT) | + (((u32) hw->rrd_burst & RXQ_CTRL_RRD_BURST_THRESH_MASK) + << RXQ_CTRL_RRD_BURST_THRESH_SHIFT) | + (((u32) hw->rfd_fetch_gap & RXQ_CTRL_RFD_PREF_MIN_IPG_MASK) + << RXQ_CTRL_RFD_PREF_MIN_IPG_SHIFT) | + RXQ_CTRL_CUT_THRU_EN | RXQ_CTRL_EN; + iowrite32(value, hw->hw_addr + REG_RXQ_CTRL); + + /* config DMA Engine */ + value = ((((u32) hw->dmar_block) & DMA_CTRL_DMAR_BURST_LEN_MASK) + << DMA_CTRL_DMAR_BURST_LEN_SHIFT) | + ((((u32) hw->dmaw_block) & DMA_CTRL_DMAR_BURST_LEN_MASK) + << DMA_CTRL_DMAR_BURST_LEN_SHIFT) | + DMA_CTRL_DMAR_EN | DMA_CTRL_DMAW_EN; + value |= (u32) hw->dma_ord; + if (atl1_rcb_128 == hw->rcb_value) + value |= DMA_CTRL_RCB_VALUE; + iowrite32(value, hw->hw_addr + REG_DMA_CTRL); + + /* config CMB / SMB */ + value = hw->cmb_rrd | ((u32) hw->cmb_tpd << 16); + iowrite32(value, hw->hw_addr + REG_CMB_WRITE_TH); + value = hw->cmb_rx_timer | ((u32) hw->cmb_tx_timer << 16); + iowrite32(value, hw->hw_addr + REG_CMB_WRITE_TIMER); + iowrite32(hw->smb_timer, hw->hw_addr + REG_SMB_TIMER); + + /* --- enable CMB / SMB */ + value = CSMB_CTRL_CMB_EN | CSMB_CTRL_SMB_EN; + iowrite32(value, hw->hw_addr + REG_CSMB_CTRL); + + value = ioread32(adapter->hw.hw_addr + REG_ISR); + if (unlikely((value & ISR_PHY_LINKDOWN) != 0)) + value = 1; /* config failed */ + else + value = 0; + + /* clear all interrupt status */ + iowrite32(0x3fffffff, adapter->hw.hw_addr + REG_ISR); + iowrite32(0, adapter->hw.hw_addr + REG_ISR); + return value; +} + +/* + * atl1_irq_disable - Mask off interrupt generation on the NIC + * @adapter: board private structure + */ +static void atl1_irq_disable(struct atl1_adapter *adapter) +{ + atomic_inc(&adapter->irq_sem); + iowrite32(0, adapter->hw.hw_addr + REG_IMR); + ioread32(adapter->hw.hw_addr + REG_IMR); + synchronize_irq(adapter->pdev->irq); +} + +static void atl1_vlan_rx_register(struct net_device *netdev, + struct vlan_group *grp) +{ + struct atl1_adapter *adapter = netdev_priv(netdev); + unsigned long flags; + u32 ctrl; + + spin_lock_irqsave(&adapter->lock, flags); + /* atl1_irq_disable(adapter); */ + adapter->vlgrp = grp; + + if (grp) { + /* enable VLAN tag insert/strip */ + ctrl = ioread32(adapter->hw.hw_addr + REG_MAC_CTRL); + ctrl |= MAC_CTRL_RMV_VLAN; + iowrite32(ctrl, adapter->hw.hw_addr + REG_MAC_CTRL); + } else { + /* disable VLAN tag insert/strip */ + ctrl = ioread32(adapter->hw.hw_addr + REG_MAC_CTRL); + ctrl &= ~MAC_CTRL_RMV_VLAN; + iowrite32(ctrl, adapter->hw.hw_addr + REG_MAC_CTRL); + } + + /* atl1_irq_enable(adapter); */ + spin_unlock_irqrestore(&adapter->lock, flags); +} + +/* FIXME: justify or remove -- CHS */ +static void atl1_vlan_rx_add_vid(struct net_device *netdev, u16 vid) +{ + /* We don't do Vlan filtering */ + return; +} + +/* FIXME: this looks wrong too -- CHS */ +static void atl1_vlan_rx_kill_vid(struct net_device *netdev, u16 vid) +{ + struct atl1_adapter *adapter = netdev_priv(netdev); + unsigned long flags; + + spin_lock_irqsave(&adapter->lock, flags); + /* atl1_irq_disable(adapter); */ + if (adapter->vlgrp) + adapter->vlgrp->vlan_devices[vid] = NULL; + /* atl1_irq_enable(adapter); */ + spin_unlock_irqrestore(&adapter->lock, flags); + /* We don't do Vlan filtering */ + return; +} + +static void atl1_restore_vlan(struct atl1_adapter *adapter) +{ + atl1_vlan_rx_register(adapter->netdev, adapter->vlgrp); + if (adapter->vlgrp) { + u16 vid; + for (vid = 0; vid < VLAN_GROUP_ARRAY_LEN; vid++) { + if (!adapter->vlgrp->vlan_devices[vid]) + continue; + atl1_vlan_rx_add_vid(adapter->netdev, vid); + } + } +} + +static u16 tpd_avail(struct atl1_tpd_ring *tpd_ring) +{ + u16 next_to_clean = atomic_read(&tpd_ring->next_to_clean); + u16 next_to_use = atomic_read(&tpd_ring->next_to_use); + return ((next_to_clean > + next_to_use) ? next_to_clean - next_to_use - + 1 : tpd_ring->count + next_to_clean - next_to_use - 1); +} + +static int atl1_tso(struct atl1_adapter *adapter, struct sk_buff *skb, + struct tso_param *tso) +{ + /* We enter this function holding a spinlock. */ + u8 ipofst; + int err; + + if (skb_shinfo(skb)->gso_size) { + if (skb_header_cloned(skb)) { + err = pskb_expand_head(skb, 0, 0, GFP_ATOMIC); + if (unlikely(err)) + return err; + } + + if (skb->protocol == ntohs(ETH_P_IP)) { + skb->nh.iph->tot_len = 0; + skb->nh.iph->check = 0; + skb->h.th->check = + ~csum_tcpudp_magic(skb->nh.iph->saddr, + skb->nh.iph->daddr, 0, + IPPROTO_TCP, 0); + ipofst = skb->nh.raw - skb->data; + if (ipofst != ENET_HEADER_SIZE) /* 802.3 frame */ + tso->tsopl |= 1 << TSO_PARAM_ETHTYPE_SHIFT; + + tso->tsopl |= (skb->nh.iph->ihl & + CSUM_PARAM_IPHL_MASK) << CSUM_PARAM_IPHL_SHIFT; + tso->tsopl |= ((skb->h.th->doff << 2) & + TSO_PARAM_TCPHDRLEN_MASK) << TSO_PARAM_TCPHDRLEN_SHIFT; + tso->tsopl |= (skb_shinfo(skb)->gso_size & + TSO_PARAM_MSS_MASK) << TSO_PARAM_MSS_SHIFT; + tso->tsopl |= 1 << TSO_PARAM_IPCKSUM_SHIFT; + tso->tsopl |= 1 << TSO_PARAM_TCPCKSUM_SHIFT; + tso->tsopl |= 1 << TSO_PARAM_SEGMENT_SHIFT; + return true; + } + } + return false; +} + +static int atl1_tx_csum(struct atl1_adapter *adapter, struct sk_buff *skb, + struct csum_param *csum) +{ + u8 css, cso; + + if (likely(skb->ip_summed == CHECKSUM_PARTIAL)) { + cso = skb->h.raw - skb->data; + css = (skb->h.raw + skb->csum) - skb->data; + if (unlikely(cso & 0x1)) { + printk(KERN_DEBUG "%s: payload offset != even number\n", + atl1_driver_name); + return -1; + } + csum->csumpl |= (cso & CSUM_PARAM_PLOADOFFSET_MASK) << + CSUM_PARAM_PLOADOFFSET_SHIFT; + csum->csumpl |= (css & CSUM_PARAM_XSUMOFFSET_MASK) << + CSUM_PARAM_XSUMOFFSET_SHIFT; + csum->csumpl |= 1 << CSUM_PARAM_CUSTOMCKSUM_SHIFT; + return true; + } + + return true; +} + +static void atl1_tx_map(struct atl1_adapter *adapter, + struct sk_buff *skb, bool tcp_seg) +{ + /* We enter this function holding a spinlock. */ + struct atl1_tpd_ring *tpd_ring = &adapter->tpd_ring; + struct atl1_buffer *buffer_info; + struct page *page; + int first_buf_len = skb->len; + unsigned long offset; + unsigned int nr_frags; + unsigned int f; + u16 tpd_next_to_use; + u16 proto_hdr_len; + u16 i, m, len12; + + first_buf_len -= skb->data_len; + nr_frags = skb_shinfo(skb)->nr_frags; + tpd_next_to_use = atomic_read(&tpd_ring->next_to_use); + buffer_info = &tpd_ring->buffer_info[tpd_next_to_use]; + if (unlikely(buffer_info->skb)) + BUG(); + buffer_info->skb = NULL; /* put skb in last TPD */ + + if (tcp_seg) { + /* TSO/GSO */ + proto_hdr_len = + ((skb->h.raw - skb->data) + (skb->h.th->doff << 2)); + buffer_info->length = proto_hdr_len; + page = virt_to_page(skb->data); + offset = (unsigned long)skb->data & ~PAGE_MASK; + buffer_info->dma = pci_map_page(adapter->pdev, page, + offset, proto_hdr_len, + PCI_DMA_TODEVICE); + + if (++tpd_next_to_use == tpd_ring->count) + tpd_next_to_use = 0; + + if (first_buf_len > proto_hdr_len) { + len12 = first_buf_len - proto_hdr_len; + m = (len12 + MAX_TX_BUF_LEN - 1) / MAX_TX_BUF_LEN; + for (i = 0; i < m; i++) { + buffer_info = + &tpd_ring->buffer_info[tpd_next_to_use]; + buffer_info->skb = NULL; + buffer_info->length = + (MAX_TX_BUF_LEN >= + len12) ? MAX_TX_BUF_LEN : len12; + len12 -= buffer_info->length; + page = virt_to_page(skb->data + + (proto_hdr_len + + i * MAX_TX_BUF_LEN)); + offset = (unsigned long)(skb->data + + (proto_hdr_len + + i * MAX_TX_BUF_LEN)) & + ~PAGE_MASK; + buffer_info->dma = + pci_map_page(adapter->pdev, page, offset, + buffer_info->length, + PCI_DMA_TODEVICE); + if (++tpd_next_to_use == tpd_ring->count) + tpd_next_to_use = 0; + } + } + } else { + /* not TSO/GSO */ + buffer_info->length = first_buf_len; + page = virt_to_page(skb->data); + offset = (unsigned long)skb->data & ~PAGE_MASK; + buffer_info->dma = pci_map_page(adapter->pdev, page, + offset, first_buf_len, + PCI_DMA_TODEVICE); + if (++tpd_next_to_use == tpd_ring->count) + tpd_next_to_use = 0; + } + + for (f = 0; f < nr_frags; f++) { + struct skb_frag_struct *frag; + u16 lenf, i, m; + + frag = &skb_shinfo(skb)->frags[f]; + lenf = frag->size; + + m = (lenf + MAX_TX_BUF_LEN - 1) / MAX_TX_BUF_LEN; + for (i = 0; i < m; i++) { + buffer_info = &tpd_ring->buffer_info[tpd_next_to_use]; + if (unlikely(buffer_info->skb)) + BUG(); + buffer_info->skb = NULL; + buffer_info->length = + (lenf > MAX_TX_BUF_LEN) ? MAX_TX_BUF_LEN : lenf; + lenf -= buffer_info->length; + buffer_info->dma = + pci_map_page(adapter->pdev, frag->page, + frag->page_offset + i * MAX_TX_BUF_LEN, + buffer_info->length, PCI_DMA_TODEVICE); + + if (++tpd_next_to_use == tpd_ring->count) + tpd_next_to_use = 0; + } + } + + /* last tpd's buffer-info */ + buffer_info->skb = skb; +} + +static void atl1_tx_queue(struct atl1_adapter *adapter, int count, + union tpd_descr *descr) +{ + /* We enter this function holding a spinlock. */ + struct atl1_tpd_ring *tpd_ring = &adapter->tpd_ring; + int j; + u32 val; + struct atl1_buffer *buffer_info; + struct tx_packet_desc *tpd; + u16 tpd_next_to_use = atomic_read(&tpd_ring->next_to_use); + + for (j = 0; j < count; j++) { + buffer_info = &tpd_ring->buffer_info[tpd_next_to_use]; + tpd = ATL1_TPD_DESC(&adapter->tpd_ring, tpd_next_to_use); + tpd->desc.csum.csumpu = descr->csum.csumpu; + tpd->desc.csum.csumpl = descr->csum.csumpl; + tpd->desc.tso.tsopu = descr->tso.tsopu; + tpd->desc.tso.tsopl = descr->tso.tsopl; + tpd->buffer_addr = cpu_to_le64(buffer_info->dma); + tpd->desc.data = descr->data; + tpd->desc.csum.csumpu |= (cpu_to_le16(buffer_info->length) & + CSUM_PARAM_BUFLEN_MASK) << CSUM_PARAM_BUFLEN_SHIFT; + + val = (descr->tso.tsopl >> TSO_PARAM_SEGMENT_SHIFT) & + TSO_PARAM_SEGMENT_MASK; + if (val && !j) + tpd->desc.tso.tsopl |= 1 << TSO_PARAM_HDRFLAG_SHIFT; + + if (j == (count - 1)) + tpd->desc.csum.csumpl |= 1 << CSUM_PARAM_EOP_SHIFT; + + if (++tpd_next_to_use == tpd_ring->count) + tpd_next_to_use = 0; + } + /* + * Force memory writes to complete before letting h/w + * know there are new descriptors to fetch. (Only + * applicable for weak-ordered memory model archs, + * such as IA-64). + */ + wmb(); + + atomic_set(&tpd_ring->next_to_use, (int)tpd_next_to_use); +} + +static void atl1_update_mailbox(struct atl1_adapter *adapter) +{ + unsigned long flags; + u32 tpd_next_to_use; + u32 rfd_next_to_use; + u32 rrd_next_to_clean; + u32 value; + + spin_lock_irqsave(&adapter->mb_lock, flags); + + tpd_next_to_use = atomic_read(&adapter->tpd_ring.next_to_use); + rfd_next_to_use = atomic_read(&adapter->rfd_ring.next_to_use); + rrd_next_to_clean = atomic_read(&adapter->rrd_ring.next_to_clean); + + value = ((rfd_next_to_use & MB_RFD_PROD_INDX_MASK) << + MB_RFD_PROD_INDX_SHIFT) | + ((rrd_next_to_clean & MB_RRD_CONS_INDX_MASK) << + MB_RRD_CONS_INDX_SHIFT) | + ((tpd_next_to_use & MB_TPD_PROD_INDX_MASK) << + MB_TPD_PROD_INDX_SHIFT); + iowrite32(value, adapter->hw.hw_addr + REG_MAILBOX); + + spin_unlock_irqrestore(&adapter->mb_lock, flags); +} + +static int atl1_xmit_frame(struct sk_buff *skb, struct net_device *netdev) +{ + struct atl1_adapter *adapter = netdev_priv(netdev); + int len = skb->len; + int tso; + int count = 1; + int ret_val; + u32 val; + union tpd_descr param; + u16 frag_size; + u16 vlan_tag; + unsigned long flags; + unsigned int nr_frags = 0; + unsigned int mss = 0; + unsigned int f; + unsigned int proto_hdr_len; + + len -= skb->data_len; + + if (unlikely(skb->len == 0)) { + dev_kfree_skb_any(skb); + return NETDEV_TX_OK; + } + + param.data = 0; + param.tso.tsopu = 0; + param.tso.tsopl = 0; + param.csum.csumpu = 0; + param.csum.csumpl = 0; + + /* nr_frags will be nonzero if we're doing scatter/gather (SG) */ + nr_frags = skb_shinfo(skb)->nr_frags; + for (f = 0; f < nr_frags; f++) { + frag_size = skb_shinfo(skb)->frags[f].size; + if (frag_size) + count += + (frag_size + MAX_TX_BUF_LEN - 1) / MAX_TX_BUF_LEN; + } + + /* mss will be nonzero if we're doing segment offload (TSO/GSO) */ + mss = skb_shinfo(skb)->gso_size; + if (mss) { + if (skb->protocol == ntohs(ETH_P_IP)) { + proto_hdr_len = ((skb->h.raw - skb->data) + + (skb->h.th->doff << 2)); + if (unlikely(proto_hdr_len > len)) { + dev_kfree_skb_any(skb); + return NETDEV_TX_OK; + } + /* need additional TPD ? */ + if (proto_hdr_len != len) + count += (len - proto_hdr_len + + MAX_TX_BUF_LEN - 1) / MAX_TX_BUF_LEN; + } + } + + local_irq_save(flags); + if (!spin_trylock(&adapter->lock)) { + /* Can't get lock - tell upper layer to requeue */ + local_irq_restore(flags); + printk(KERN_DEBUG "%s: TX locked\n", atl1_driver_name); + return NETDEV_TX_LOCKED; + } + + if (tpd_avail(&adapter->tpd_ring) < count) { + /* not enough descriptors */ + netif_stop_queue(netdev); + spin_unlock_irqrestore(&adapter->lock, flags); + printk(KERN_DEBUG "%s: TX busy\n", atl1_driver_name); + return NETDEV_TX_BUSY; + } + + param.data = 0; + + if (adapter->vlgrp && vlan_tx_tag_present(skb)) { + vlan_tag = vlan_tx_tag_get(skb); + vlan_tag = (vlan_tag << 4) | (vlan_tag >> 13) | + ((vlan_tag >> 9) & 0x8); + param.csum.csumpl |= 1 << CSUM_PARAM_INSVLAG_SHIFT; + param.csum.csumpu |= (vlan_tag & CSUM_PARAM_VALANTAG_MASK) << + CSUM_PARAM_VALAN_SHIFT; + } + + tso = atl1_tso(adapter, skb, ¶m.tso); + if (tso < 0) { + spin_unlock_irqrestore(&adapter->lock, flags); + dev_kfree_skb_any(skb); + return NETDEV_TX_OK; + } + + if (!tso) { + ret_val = atl1_tx_csum(adapter, skb, ¶m.csum); + if (ret_val < 0) { + spin_unlock_irqrestore(&adapter->lock, flags); + dev_kfree_skb_any(skb); + return NETDEV_TX_OK; + } + } + + val = (param.csum.csumpl >> CSUM_PARAM_SEGMENT_SHIFT) & + CSUM_PARAM_SEGMENT_MASK; + atl1_tx_map(adapter, skb, 1 == val); + atl1_tx_queue(adapter, count, ¶m); + netdev->trans_start = jiffies; + spin_unlock_irqrestore(&adapter->lock, flags); + atl1_update_mailbox(adapter); + return NETDEV_TX_OK; +} + +/* + * atl1_get_stats - Get System Network Statistics + * @netdev: network interface device structure + * + * Returns the address of the device statistics structure. + * The statistics are actually updated from the timer callback. + */ +static struct net_device_stats *atl1_get_stats(struct net_device *netdev) +{ + struct atl1_adapter *adapter = netdev_priv(netdev); + return &adapter->net_stats; +} + +/* + * atl1_clean_rx_ring - Free RFD Buffers + * @adapter: board private structure + */ +static void atl1_clean_rx_ring(struct atl1_adapter *adapter) +{ + struct atl1_rfd_ring *rfd_ring = &adapter->rfd_ring; + struct atl1_rrd_ring *rrd_ring = &adapter->rrd_ring; + struct atl1_buffer *buffer_info; + struct pci_dev *pdev = adapter->pdev; + unsigned long size; + unsigned int i; + + /* Free all the Rx ring sk_buffs */ + for (i = 0; i < rfd_ring->count; i++) { + buffer_info = &rfd_ring->buffer_info[i]; + if (buffer_info->dma) { + pci_unmap_page(pdev, + buffer_info->dma, + buffer_info->length, + PCI_DMA_FROMDEVICE); + buffer_info->dma = 0; + } + if (buffer_info->skb) { + dev_kfree_skb(buffer_info->skb); + buffer_info->skb = NULL; + } + } + + size = sizeof(struct atl1_buffer) * rfd_ring->count; + memset(rfd_ring->buffer_info, 0, size); + + /* Zero out the descriptor ring */ + memset(rfd_ring->desc, 0, rfd_ring->size); + + rfd_ring->next_to_clean = 0; + atomic_set(&rfd_ring->next_to_use, 0); + + rrd_ring->next_to_use = 0; + atomic_set(&rrd_ring->next_to_clean, 0); +} + +/* + * atl1_clean_tx_ring - Free Tx Buffers + * @adapter: board private structure + */ +static void atl1_clean_tx_ring(struct atl1_adapter *adapter) +{ + struct atl1_tpd_ring *tpd_ring = &adapter->tpd_ring; + struct atl1_buffer *buffer_info; + struct pci_dev *pdev = adapter->pdev; + unsigned long size; + unsigned int i; + + /* Free all the Tx ring sk_buffs */ + for (i = 0; i < tpd_ring->count; i++) { + buffer_info = &tpd_ring->buffer_info[i]; + if (buffer_info->dma) { + pci_unmap_page(pdev, buffer_info->dma, + buffer_info->length, PCI_DMA_TODEVICE); + buffer_info->dma = 0; + } + } + + for (i = 0; i < tpd_ring->count; i++) { + buffer_info = &tpd_ring->buffer_info[i]; + if (buffer_info->skb) { + dev_kfree_skb_any(buffer_info->skb); + buffer_info->skb = NULL; + } + } + + size = sizeof(struct atl1_buffer) * tpd_ring->count; + memset(tpd_ring->buffer_info, 0, size); + + /* Zero out the descriptor ring */ + memset(tpd_ring->desc, 0, tpd_ring->size); + + atomic_set(&tpd_ring->next_to_use, 0); + atomic_set(&tpd_ring->next_to_clean, 0); +} + +/* + * atl1_free_ring_resources - Free Tx / RX descriptor Resources + * @adapter: board private structure + * + * Free all transmit software resources + */ +void atl1_free_ring_resources(struct atl1_adapter *adapter) +{ + struct pci_dev *pdev = adapter->pdev; + struct atl1_tpd_ring *tpd_ring = &adapter->tpd_ring; + struct atl1_rfd_ring *rfd_ring = &adapter->rfd_ring; + struct atl1_rrd_ring *rrd_ring = &adapter->rrd_ring; + struct atl1_ring_header *ring_header = &adapter->ring_header; + + atl1_clean_tx_ring(adapter); + atl1_clean_rx_ring(adapter); + + kfree(tpd_ring->buffer_info); + pci_free_consistent(pdev, ring_header->size, ring_header->desc, + ring_header->dma); + + tpd_ring->buffer_info = NULL; + tpd_ring->desc = NULL; + tpd_ring->dma = 0; + + rfd_ring->buffer_info = NULL; + rfd_ring->desc = NULL; + rfd_ring->dma = 0; + + rrd_ring->desc = NULL; + rrd_ring->dma = 0; +} + +s32 atl1_up(struct atl1_adapter *adapter) +{ + struct net_device *netdev = adapter->netdev; + int err; + int irq_flags = IRQF_SAMPLE_RANDOM; + + /* hardware has been reset, we need to reload some things */ + atl1_set_multi(netdev); + atl1_restore_vlan(adapter); + err = atl1_alloc_rx_buffers(adapter); + if (unlikely(!err)) /* no RX BUFFER allocated */ + return -ENOMEM; + + if (unlikely(atl1_configure(adapter))) { + err = -EIO; + goto err_up; + } + + err = pci_enable_msi(adapter->pdev); + if (err) { + dev_info(&adapter->pdev->dev, + "Unable to enable MSI: %d\n", err); + irq_flags |= IRQF_SHARED; + } + + err = request_irq(adapter->pdev->irq, &atl1_intr, irq_flags, + netdev->name, netdev); + if (unlikely(err)) + goto err_up; + + mod_timer(&adapter->watchdog_timer, jiffies); + atl1_irq_enable(adapter); + atl1_check_link(adapter); + return 0; + + /* FIXME: unreachable code! -- CHS */ + /* free irq disable any interrupt */ + iowrite32(0, adapter->hw.hw_addr + REG_IMR); + free_irq(adapter->pdev->irq, netdev); + +err_up: + pci_disable_msi(adapter->pdev); + /* free rx_buffers */ + atl1_clean_rx_ring(adapter); + return err; +} + +void atl1_down(struct atl1_adapter *adapter) +{ + struct net_device *netdev = adapter->netdev; + + del_timer_sync(&adapter->watchdog_timer); + del_timer_sync(&adapter->phy_config_timer); + adapter->phy_timer_pending = false; + + atl1_irq_disable(adapter); + free_irq(adapter->pdev->irq, netdev); + pci_disable_msi(adapter->pdev); + atl1_reset_hw(&adapter->hw); + adapter->cmb.cmb->int_stats = 0; + + adapter->link_speed = SPEED_0; + adapter->link_duplex = -1; + netif_carrier_off(netdev); + netif_stop_queue(netdev); + + atl1_clean_tx_ring(adapter); + atl1_clean_rx_ring(adapter); +} + +/* + * atl1_change_mtu - Change the Maximum Transfer Unit + * @netdev: network interface device structure + * @new_mtu: new value for maximum frame size + * + * Returns 0 on success, negative on failure + */ +static int atl1_change_mtu(struct net_device *netdev, int new_mtu) +{ + struct atl1_adapter *adapter = netdev_priv(netdev); + int old_mtu = netdev->mtu; + int max_frame = new_mtu + ENET_HEADER_SIZE + ETHERNET_FCS_SIZE; + + if ((max_frame < MINIMUM_ETHERNET_FRAME_SIZE) || + (max_frame > MAX_JUMBO_FRAME_SIZE)) { + printk(KERN_WARNING "%s: invalid MTU setting\n", + atl1_driver_name); + return -EINVAL; + } + + adapter->hw.max_frame_size = max_frame; + adapter->hw.tx_jumbo_task_th = (max_frame + 7) >> 3; + adapter->rx_buffer_len = (max_frame + 7) & ~7; + adapter->hw.rx_jumbo_th = adapter->rx_buffer_len / 8; + + netdev->mtu = new_mtu; + if ((old_mtu != new_mtu) && netif_running(netdev)) { + atl1_down(adapter); + atl1_up(adapter); + } + + return 0; +} + +/* + * atl1_set_mac - Change the Ethernet Address of the NIC + * @netdev: network interface device structure + * @p: pointer to an address structure + * + * Returns 0 on success, negative on failure + */ +static int atl1_set_mac(struct net_device *netdev, void *p) +{ + struct atl1_adapter *adapter = netdev_priv(netdev); + struct sockaddr *addr = p; + + if (netif_running(netdev)) + return -EBUSY; + + if (!is_valid_ether_addr(addr->sa_data)) + return -EADDRNOTAVAIL; + + memcpy(netdev->dev_addr, addr->sa_data, netdev->addr_len); + memcpy(adapter->hw.mac_addr, addr->sa_data, netdev->addr_len); + + atl1_set_mac_addr(&adapter->hw); + return 0; +} + +/* + * atl1_watchdog - Timer Call-back + * @data: pointer to netdev cast into an unsigned long + */ +static void atl1_watchdog(unsigned long data) +{ + struct atl1_adapter *adapter = (struct atl1_adapter *)data; + + /* Reset the timer */ + mod_timer(&adapter->watchdog_timer, jiffies + 2 * HZ); +} + +static int mdio_read(struct net_device *netdev, int phy_id, int reg_num) +{ + struct atl1_adapter *adapter = netdev_priv(netdev); + u16 result; + + atl1_read_phy_reg(&adapter->hw, reg_num & 0x1f, &result); + + return result; +} + +static void mdio_write(struct net_device *netdev, int phy_id, int reg_num, int val) +{ + struct atl1_adapter *adapter = netdev_priv(netdev); + + atl1_write_phy_reg(&adapter->hw, reg_num, val); +} + +/* + * atl1_mii_ioctl - + * @netdev: + * @ifreq: + * @cmd: + */ +static int atl1_mii_ioctl(struct net_device *netdev, struct ifreq *ifr, int cmd) +{ + struct atl1_adapter *adapter = netdev_priv(netdev); + unsigned long flags; + int retval; + + if (!netif_running(netdev)) + return -EINVAL; + + spin_lock_irqsave(&adapter->lock, flags); + retval = generic_mii_ioctl(&adapter->mii, if_mii(ifr), cmd, NULL); + spin_unlock_irqrestore(&adapter->lock, flags); + + return retval; +} + +/* + * atl1_ioctl - + * @netdev: + * @ifreq: + * @cmd: + */ +static int atl1_ioctl(struct net_device *netdev, struct ifreq *ifr, int cmd) +{ + switch (cmd) { + case SIOCGMIIPHY: + case SIOCGMIIREG: + case SIOCSMIIREG: + return atl1_mii_ioctl(netdev, ifr, cmd); + default: + return -EOPNOTSUPP; + } +} + +/* + * atl1_tx_timeout - Respond to a Tx Hang + * @netdev: network interface device structure + */ +static void atl1_tx_timeout(struct net_device *netdev) +{ + struct atl1_adapter *adapter = netdev_priv(netdev); + /* Do the reset outside of interrupt context */ + schedule_work(&adapter->tx_timeout_task); +} + +/* + * atl1_phy_config - Timer Call-back + * @data: pointer to netdev cast into an unsigned long + */ +static void atl1_phy_config(unsigned long data) +{ + struct atl1_adapter *adapter = (struct atl1_adapter *)data; + struct atl1_hw *hw = &adapter->hw; + unsigned long flags; + + spin_lock_irqsave(&adapter->lock, flags); + adapter->phy_timer_pending = false; + atl1_write_phy_reg(hw, MII_ADVERTISE, hw->mii_autoneg_adv_reg); + atl1_write_phy_reg(hw, MII_AT001_CR, hw->mii_1000t_ctrl_reg); + atl1_write_phy_reg(hw, MII_BMCR, MII_CR_RESET | MII_CR_AUTO_NEG_EN); + spin_unlock_irqrestore(&adapter->lock, flags); +} + +int atl1_reset(struct atl1_adapter *adapter) +{ + int ret; + + ret = atl1_reset_hw(&adapter->hw); + if (ret != ATL1_SUCCESS) + return ret; + return atl1_init_hw(&adapter->hw); +} + +/* + * atl1_open - Called when a network interface is made active + * @netdev: network interface device structure + * + * Returns 0 on success, negative value on failure + * + * The open entry point is called when a network interface is made + * active by the system (IFF_UP). At this point all resources needed + * for transmit and receive operations are allocated, the interrupt + * handler is registered with the OS, the watchdog timer is started, + * and the stack is notified that the interface is ready. + */ +static int atl1_open(struct net_device *netdev) +{ + struct atl1_adapter *adapter = netdev_priv(netdev); + int err; + + /* allocate transmit descriptors */ + err = atl1_setup_ring_resources(adapter); + if (err) + return err; + + err = atl1_up(adapter); + if (err) + goto err_up; + + return 0; + +err_up: + atl1_reset(adapter); + return err; +} + +/* + * atl1_close - Disables a network interface + * @netdev: network interface device structure + * + * Returns 0, this is not allowed to fail + * + * The close entry point is called when an interface is de-activated + * by the OS. The hardware is still under the drivers control, but + * needs to be disabled. A global MAC reset is issued to stop the + * hardware, and all transmit and receive resources are freed. + */ +static int atl1_close(struct net_device *netdev) +{ + struct atl1_adapter *adapter = netdev_priv(netdev); + atl1_down(adapter); + atl1_free_ring_resources(adapter); + return 0; +} + +/* + * If TPD Buffer size equal to 0, PCIE DMAR_TO_INT + * will assert. We do soft reset <0x1400=1> according + * with the SPEC. BUT, it seemes that PCIE or DMA + * state-machine will not be reset. DMAR_TO_INT will + * assert again and again. + */ +static void atl1_tx_timeout_task(struct work_struct *work) +{ + struct atl1_adapter *adapter = + container_of(work, struct atl1_adapter, tx_timeout_task); + struct net_device *netdev = adapter->netdev; + + netif_device_detach(netdev); + atl1_down(adapter); + atl1_up(adapter); + netif_device_attach(netdev); +} + +/* + * atl1_link_chg_task - deal with link change event Out of interrupt context + */ +static void atl1_link_chg_task(struct work_struct *work) +{ + struct atl1_adapter *adapter = + container_of(work, struct atl1_adapter, link_chg_task); + unsigned long flags; + + spin_lock_irqsave(&adapter->lock, flags); + atl1_check_link(adapter); + spin_unlock_irqrestore(&adapter->lock, flags); +} + +/* + * atl1_pcie_patch - Patch for PCIE module + */ +static void atl1_pcie_patch(struct atl1_adapter *adapter) +{ + u32 value; + value = 0x6500; + iowrite32(value, adapter->hw.hw_addr + 0x12FC); + /* pcie flow control mode change */ + value = ioread32(adapter->hw.hw_addr + 0x1008); + value |= 0x8000; + iowrite32(value, adapter->hw.hw_addr + 0x1008); +} + +/* + * When ACPI resume on some VIA MotherBoard, the Interrupt Disable bit/0x400 + * on PCI Command register is disable. + * The function enable this bit. + * Brackett, 2006/03/15 + */ +static void atl1_via_workaround(struct atl1_adapter *adapter) +{ + unsigned long value; + + value = ioread16(adapter->hw.hw_addr + PCI_COMMAND); + if (value & PCI_COMMAND_INTX_DISABLE) + value &= ~PCI_COMMAND_INTX_DISABLE; + iowrite32(value, adapter->hw.hw_addr + PCI_COMMAND); +} + +/* + * atl1_probe - Device Initialization Routine + * @pdev: PCI device information struct + * @ent: entry in atl1_pci_tbl + * + * Returns 0 on success, negative on failure + * + * atl1_probe initializes an adapter identified by a pci_dev structure. + * The OS initialization, configuring of the adapter private structure, + * and a hardware reset occur. + */ +static int __devinit atl1_probe(struct pci_dev *pdev, + const struct pci_device_id *ent) +{ + struct net_device *netdev; + struct atl1_adapter *adapter; + static int cards_found = 0; + bool pci_using_64 = true; + int err; + + err = pci_enable_device(pdev); + if (err) + return err; + + err = pci_set_dma_mask(pdev, DMA_64BIT_MASK); + if (err) { + err = pci_set_dma_mask(pdev, DMA_32BIT_MASK); + if (err) { + printk(KERN_DEBUG + "%s: no usable DMA configuration, aborting\n", + atl1_driver_name); + goto err_dma; + } + pci_using_64 = false; + } + /* Mark all PCI regions associated with PCI device + * pdev as being reserved by owner atl1_driver_name + */ + err = pci_request_regions(pdev, atl1_driver_name); + if (err) + goto err_request_regions; + + /* Enables bus-mastering on the device and calls + * pcibios_set_master to do the needed arch specific settings + */ + pci_set_master(pdev); + + netdev = alloc_etherdev(sizeof(struct atl1_adapter)); + if (!netdev) { + err = -ENOMEM; + goto err_alloc_etherdev; + } + SET_MODULE_OWNER(netdev); + SET_NETDEV_DEV(netdev, &pdev->dev); + + pci_set_drvdata(pdev, netdev); + adapter = netdev_priv(netdev); + adapter->netdev = netdev; + adapter->pdev = pdev; + adapter->hw.back = adapter; + + adapter->hw.hw_addr = pci_iomap(pdev, 0, 0); + if (!adapter->hw.hw_addr) { + err = -EIO; + goto err_pci_iomap; + } + /* get device revision number */ + adapter->hw.dev_rev = ioread16(adapter->hw.hw_addr + (REG_MASTER_CTRL + 2)); + + /* set default ring resource counts */ + adapter->rfd_ring.count = adapter->rrd_ring.count = ATL1_DEFAULT_RFD; + adapter->tpd_ring.count = ATL1_DEFAULT_TPD; + + adapter->mii.dev = netdev; + adapter->mii.mdio_read = mdio_read; + adapter->mii.mdio_write = mdio_write; + adapter->mii.phy_id_mask = 0x1f; + adapter->mii.reg_num_mask = 0x1f; + + netdev->open = &atl1_open; + netdev->stop = &atl1_close; + netdev->hard_start_xmit = &atl1_xmit_frame; + netdev->get_stats = &atl1_get_stats; + netdev->set_multicast_list = &atl1_set_multi; + netdev->set_mac_address = &atl1_set_mac; + netdev->change_mtu = &atl1_change_mtu; + netdev->do_ioctl = &atl1_ioctl; + netdev->tx_timeout = &atl1_tx_timeout; + netdev->watchdog_timeo = 5 * HZ; + netdev->vlan_rx_register = atl1_vlan_rx_register; + netdev->vlan_rx_add_vid = atl1_vlan_rx_add_vid; + netdev->vlan_rx_kill_vid = atl1_vlan_rx_kill_vid; + netdev->ethtool_ops = &atl1_ethtool_ops; + adapter->bd_number = cards_found; + adapter->pci_using_64 = pci_using_64; + + /* setup the private structure */ + err = atl1_sw_init(adapter); + if (err) + goto err_common; + + netdev->features = NETIF_F_HW_CSUM; + netdev->features |= NETIF_F_SG; + netdev->features |= (NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_RX); + + /* + * FIXME - Until tso performance gets fixed, disable the feature. + * Enable it with ethtool -K if desired. + */ + /* netdev->features |= NETIF_F_TSO; */ + + if (pci_using_64) + netdev->features |= NETIF_F_HIGHDMA; + + netdev->features |= NETIF_F_LLTX; + + /* + * patch for some L1 of old version, + * the final version of L1 may not need these + * patches + */ + /* atl1_pcie_patch(adapter); */ + + /* really reset GPHY core */ + iowrite16(0, adapter->hw.hw_addr + REG_GPHY_ENABLE); + + /* + * reset the controller to + * put the device in a known good starting state + */ + if (atl1_reset_hw(&adapter->hw)) { + err = -EIO; + goto err_common; + } + + /* copy the MAC address out of the EEPROM */ + atl1_read_mac_addr(&adapter->hw); + memcpy(netdev->dev_addr, adapter->hw.mac_addr, netdev->addr_len); + + if (!is_valid_ether_addr(netdev->dev_addr)) { + err = -EIO; + goto err_common; + } + + atl1_check_options(adapter); + + /* pre-init the MAC, and setup link */ + err = atl1_init_hw(&adapter->hw); + if (err) { + err = -EIO; + goto err_common; + } + + atl1_pcie_patch(adapter); + /* assume we have no link for now */ + netif_carrier_off(netdev); + netif_stop_queue(netdev); + + init_timer(&adapter->watchdog_timer); + adapter->watchdog_timer.function = &atl1_watchdog; + adapter->watchdog_timer.data = (unsigned long)adapter; + + init_timer(&adapter->phy_config_timer); + adapter->phy_config_timer.function = &atl1_phy_config; + adapter->phy_config_timer.data = (unsigned long)adapter; + adapter->phy_timer_pending = false; + + INIT_WORK(&adapter->tx_timeout_task, atl1_tx_timeout_task); + + INIT_WORK(&adapter->link_chg_task, atl1_link_chg_task); + + INIT_WORK(&adapter->pcie_dma_to_rst_task, atl1_tx_timeout_task); + + err = register_netdev(netdev); + if (err) + goto err_common; + + cards_found++; + atl1_via_workaround(adapter); + return 0; + +err_common: + pci_iounmap(pdev, adapter->hw.hw_addr); +err_pci_iomap: + free_netdev(netdev); +err_alloc_etherdev: + pci_release_regions(pdev); +err_dma: +err_request_regions: + pci_disable_device(pdev); + return err; +} + +/* + * atl1_remove - Device Removal Routine + * @pdev: PCI device information struct + * + * atl1_remove is called by the PCI subsystem to alert the driver + * that it should release a PCI device. The could be caused by a + * Hot-Plug event, or because the driver is going to be removed from + * memory. + */ +static void __devexit atl1_remove(struct pci_dev *pdev) +{ + struct net_device *netdev = pci_get_drvdata(pdev); + struct atl1_adapter *adapter; + /* Device not available. Return. */ + if (!netdev) + return; + + adapter = netdev_priv(netdev); + iowrite16(0, adapter->hw.hw_addr + REG_GPHY_ENABLE); + unregister_netdev(netdev); + pci_iounmap(pdev, adapter->hw.hw_addr); + pci_release_regions(pdev); + free_netdev(netdev); + pci_disable_device(pdev); +} + +#ifdef CONFIG_PM +static int atl1_suspend(struct pci_dev *pdev, pm_message_t state) +{ + struct net_device *netdev = pci_get_drvdata(pdev); + struct atl1_adapter *adapter = netdev_priv(netdev); + struct atl1_hw *hw = &adapter->hw; + u32 ctrl = 0; + u32 wufc = adapter->wol; + + netif_device_detach(netdev); + if (netif_running(netdev)) + atl1_down(adapter); + + atl1_read_phy_reg(hw, MII_BMSR, (u16 *) & ctrl); + atl1_read_phy_reg(hw, MII_BMSR, (u16 *) & ctrl); + if (ctrl & BMSR_LSTATUS) + wufc &= ~ATL1_WUFC_LNKC; + + /* reduce speed to 10/100M */ + if (wufc) { + atl1_phy_enter_power_saving(hw); + /* if resume, let driver to re- setup link */ + hw->phy_configured = false; + atl1_set_mac_addr(hw); + atl1_set_multi(netdev); + + ctrl = 0; + /* turn on magic packet wol */ + if (wufc & ATL1_WUFC_MAG) + ctrl = WOL_MAGIC_EN | WOL_MAGIC_PME_EN; + + /* turn on Link change WOL */ + if (wufc & ATL1_WUFC_LNKC) + ctrl |= (WOL_LINK_CHG_EN | WOL_LINK_CHG_PME_EN); + iowrite32(ctrl, hw->hw_addr + REG_WOL_CTRL); + + /* turn on all-multi mode if wake on multicast is enabled */ + ctrl = ioread32(hw->hw_addr + REG_MAC_CTRL); + ctrl &= ~MAC_CTRL_DBG; + ctrl &= ~MAC_CTRL_PROMIS_EN; + if (wufc & ATL1_WUFC_MC) + ctrl |= MAC_CTRL_MC_ALL_EN; + else + ctrl &= ~MAC_CTRL_MC_ALL_EN; + + /* turn on broadcast mode if wake on-BC is enabled */ + if (wufc & ATL1_WUFC_BC) + ctrl |= MAC_CTRL_BC_EN; + else + ctrl &= ~MAC_CTRL_BC_EN; + + /* enable RX */ + ctrl |= MAC_CTRL_RX_EN; + iowrite32(ctrl, hw->hw_addr + REG_MAC_CTRL); + pci_enable_wake(pdev, PCI_D3hot, 1); + pci_enable_wake(pdev, PCI_D3cold, 1); /* 4 == D3 cold */ + } else { + iowrite32(0, hw->hw_addr + REG_WOL_CTRL); + pci_enable_wake(pdev, PCI_D3hot, 0); + pci_enable_wake(pdev, PCI_D3cold, 0); /* 4 == D3 cold */ + } + + pci_save_state(pdev); + pci_disable_device(pdev); + + pci_set_power_state(pdev, PCI_D3hot); + + return 0; +} + +static int atl1_resume(struct pci_dev *pdev) +{ + struct net_device *netdev = pci_get_drvdata(pdev); + struct atl1_adapter *adapter = netdev_priv(netdev); + u32 ret_val; + + pci_set_power_state(pdev, 0); + pci_restore_state(pdev); + + ret_val = pci_enable_device(pdev); + pci_enable_wake(pdev, PCI_D3hot, 0); + pci_enable_wake(pdev, PCI_D3cold, 0); + + iowrite32(0, adapter->hw.hw_addr + REG_WOL_CTRL); + atl1_reset(adapter); + + if (netif_running(netdev)) + atl1_up(adapter); + netif_device_attach(netdev); + + atl1_via_workaround(adapter); + + return 0; +} +#else +#define atl1_suspend NULL +#define atl1_resume NULL +#endif + +static struct pci_driver atl1_driver = { + .name = atl1_driver_name, + .id_table = atl1_pci_tbl, + .probe = atl1_probe, + .remove = __devexit_p(atl1_remove), + /* Power Managment Hooks */ + /* probably broken right now -- CHS */ + .suspend = atl1_suspend, + .resume = atl1_resume +}; + +/* + * atl1_exit_module - Driver Exit Cleanup Routine + * + * atl1_exit_module is called just before the driver is removed + * from memory. + */ +static void __exit atl1_exit_module(void) +{ + pci_unregister_driver(&atl1_driver); +} + +/* + * atl1_init_module - Driver Registration Routine + * + * atl1_init_module is the first routine called when the driver is + * loaded. All it does is register with the PCI subsystem. + */ +static int __init atl1_init_module(void) +{ + printk(KERN_INFO "%s - version %s\n", atl1_driver_string, DRIVER_VERSION); + printk(KERN_INFO "%s\n", atl1_copyright); + return pci_register_driver(&atl1_driver); +} + +module_init(atl1_init_module); +module_exit(atl1_exit_module); diff --git a/drivers/net/atl1/atl1_param.c b/drivers/net/atl1/atl1_param.c new file mode 100644 index 0000000..c407214 --- /dev/null +++ b/drivers/net/atl1/atl1_param.c @@ -0,0 +1,206 @@ +/* + * Copyright(c) 2005 - 2006 Attansic Corporation. All rights reserved. + * Copyright(c) 2006 Chris Snook + * Copyright(c) 2006 Jay Cliburn + * + * Derived from Intel e1000 driver + * Copyright(c) 1999 - 2005 Intel Corporation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the Free + * Software Foundation; either version 2 of the License, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#include +#include +#include +#include "atl1.h" + +/* + * This is the only thing that needs to be changed to adjust the + * maximum number of ports that the driver can manage. + */ +#define ATL1_MAX_NIC 4 + +#define OPTION_UNSET -1 +#define OPTION_DISABLED 0 +#define OPTION_ENABLED 1 + +#define ATL1_PARAM_INIT { [0 ... ATL1_MAX_NIC] = OPTION_UNSET } + +/* + * Interrupt Moderate Timer in units of 2 us + * + * Valid Range: 10-65535 + * + * Default Value: 100 (200us) + */ +static int __devinitdata int_mod_timer[ATL1_MAX_NIC+1] = ATL1_PARAM_INIT; +static int num_int_mod_timer = 0; +module_param_array_named(int_mod_timer, int_mod_timer, int, &num_int_mod_timer, 0); +MODULE_PARM_DESC(int_mod_timer, "Interrupt moderator timer"); + +/* + * flash_vendor + * + * Valid Range: 0-2 + * + * 0 - Atmel + * 1 - SST + * 2 - ST + * + * Default Value: 0 + */ +static int __devinitdata flash_vendor[ATL1_MAX_NIC+1] = ATL1_PARAM_INIT; +static int num_flash_vendor = 0; +module_param_array_named(flash_vendor, flash_vendor, int, &num_flash_vendor, 0); +MODULE_PARM_DESC(flash_vendor, "SPI flash vendor"); + +#define DEFAULT_INT_MOD_CNT 100 /* 200us */ +#define MAX_INT_MOD_CNT 65000 +#define MIN_INT_MOD_CNT 50 + +#define FLASH_VENDOR_DEFAULT 0 +#define FLASH_VENDOR_MIN 0 +#define FLASH_VENDOR_MAX 2 + +struct atl1_option { + enum { enable_option, range_option, list_option } type; + char *name; + char *err; + int def; + union { + struct { /* range_option info */ + int min; + int max; + } r; + struct { /* list_option info */ + int nr; + struct atl1_opt_list { + int i; + char *str; + } *p; + } l; + } arg; +}; + +static int __devinit atl1_validate_option(int *value, struct atl1_option *opt) +{ + if (*value == OPTION_UNSET) { + *value = opt->def; + return 0; + } + + switch (opt->type) { + case enable_option: + switch (*value) { + case OPTION_ENABLED: + printk(KERN_INFO "%s: %s Enabled\n", atl1_driver_name, + opt->name); + return 0; + case OPTION_DISABLED: + printk(KERN_INFO "%s: %s Disabled\n", atl1_driver_name, + opt->name); + return 0; + } + break; + case range_option: + if (*value >= opt->arg.r.min && *value <= opt->arg.r.max) { + printk(KERN_INFO "%s: %s set to %i\n", + atl1_driver_name, opt->name, *value); + return 0; + } + break; + case list_option:{ + int i; + struct atl1_opt_list *ent; + + for (i = 0; i < opt->arg.l.nr; i++) { + ent = &opt->arg.l.p[i]; + if (*value == ent->i) { + if (ent->str[0] != '\0') + printk(KERN_INFO "%s: %s\n", + atl1_driver_name, ent->str); + return 0; + } + } + } + break; + + default: + break; + } + + printk(KERN_INFO "%s: invalid %s specified (%i) %s\n", + atl1_driver_name, opt->name, *value, opt->err); + *value = opt->def; + return -1; +} + +/* + * atl1_check_options - Range Checking for Command Line Parameters + * @adapter: board private structure + * + * This routine checks all command line parameters for valid user + * input. If an invalid value is given, or if no user specified + * value exists, a default value is used. The final value is stored + * in a variable in the adapter structure. + */ +void __devinit atl1_check_options(struct atl1_adapter *adapter) +{ + int bd = adapter->bd_number; + if (bd >= ATL1_MAX_NIC) { + printk(KERN_NOTICE "%s: warning: no configuration for board #%i\n", + atl1_driver_name, bd); + printk(KERN_NOTICE "%s: using defaults for all values\n", + atl1_driver_name); + } + { /* Interrupt Moderate Timer */ + struct atl1_option opt = { + .type = range_option, + .name = "Interrupt Moderator Timer", + .err = "using default of " + __MODULE_STRING(DEFAULT_INT_MOD_CNT), + .def = DEFAULT_INT_MOD_CNT, + .arg = {.r = + {.min = MIN_INT_MOD_CNT,.max = MAX_INT_MOD_CNT}} + }; + int val; + if (num_int_mod_timer > bd) { + val = int_mod_timer[bd]; + atl1_validate_option(&val, &opt); + adapter->imt = (u16) val; + } else + adapter->imt = (u16) (opt.def); + } + + { /* Flash Vendor */ + struct atl1_option opt = { + .type = range_option, + .name = "SPI Flash Vendor", + .err = "using default of " + __MODULE_STRING(FLASH_VENDOR_DEFAULT), + .def = DEFAULT_INT_MOD_CNT, + .arg = {.r = + {.min = FLASH_VENDOR_MIN,.max = + FLASH_VENDOR_MAX}} + }; + int val; + if (num_flash_vendor > bd) { + val = flash_vendor[bd]; + atl1_validate_option(&val, &opt); + adapter->hw.flash_vendor = (u8) val; + } else + adapter->hw.flash_vendor = (u8) (opt.def); + } +} diff --git a/drivers/net/au1000_eth.c b/drivers/net/au1000_eth.c index f0b6879..69ae229 100644 --- a/drivers/net/au1000_eth.c +++ b/drivers/net/au1000_eth.c @@ -37,7 +37,6 @@ #include #include -#include #include #include #include diff --git a/drivers/net/b44.c b/drivers/net/b44.c index 303a8d9..5ff7882 100644 --- a/drivers/net/b44.c +++ b/drivers/net/b44.c @@ -721,7 +721,7 @@ static void b44_recycle_rx(struct b44 *b struct ring_info *src_map, *dest_map; struct rx_header *rh; int dest_idx; - u32 ctrl; + __le32 ctrl; dest_idx = dest_idx_unmasked & (B44_RX_RING_SIZE - 1); dest_desc = &bp->rx_ring[dest_idx]; @@ -783,7 +783,7 @@ static int b44_rx(struct b44 *bp, int bu RX_PKT_BUF_SZ, PCI_DMA_FROMDEVICE); rh = (struct rx_header *) skb->data; - len = cpu_to_le16(rh->len); + len = le16_to_cpu(rh->len); if ((len > (RX_PKT_BUF_SZ - bp->rx_offset)) || (rh->flags & cpu_to_le16(RX_FLAG_ERRORS))) { drop_it: @@ -799,7 +799,7 @@ static int b44_rx(struct b44 *bp, int bu do { udelay(2); barrier(); - len = cpu_to_le16(rh->len); + len = le16_to_cpu(rh->len); } while (len == 0 && i++ < 5); if (len == 0) goto drop_it; @@ -2061,7 +2061,7 @@ out: static int b44_read_eeprom(struct b44 *bp, u8 *data) { long i; - u16 *ptr = (u16 *) data; + __le16 *ptr = (__le16 *) data; for (i = 0; i < 128; i += 2) ptr[i / 2] = cpu_to_le16(readw(bp->regs + 4096 + i)); diff --git a/drivers/net/b44.h b/drivers/net/b44.h index 4944507..18fc133 100644 --- a/drivers/net/b44.h +++ b/drivers/net/b44.h @@ -308,8 +308,8 @@ #define B44_MII_TLEDCTRL 27 /* Traffic M #define MII_TLEDCTRL_ENABLE 0x0040 struct dma_desc { - u32 ctrl; - u32 addr; + __le32 ctrl; + __le32 addr; }; /* There are only 12 bits in the DMA engine for descriptor offsetting @@ -327,9 +327,9 @@ #define DESC_CTRL_SOF 0x80000000 /* Star #define RX_COPY_THRESHOLD 256 struct rx_header { - u16 len; - u16 flags; - u16 pad[12]; + __le16 len; + __le16 flags; + __le16 pad[12]; }; #define RX_HEADER_LEN 28 diff --git a/drivers/net/bmac.c b/drivers/net/bmac.c index 4528ce9..c143304 100644 --- a/drivers/net/bmac.c +++ b/drivers/net/bmac.c @@ -18,6 +18,7 @@ #include #include #include #include +#include #include #include #include @@ -140,7 +141,6 @@ #define PRIV_BYTES (sizeof(struct bmac_d + (N_RX_RING + N_TX_RING + 4) * sizeof(struct dbdma_cmd) \ + sizeof(struct sk_buff_head)) -static unsigned char bitrev(unsigned char b); static int bmac_open(struct net_device *dev); static int bmac_close(struct net_device *dev); static int bmac_transmit_packet(struct sk_buff *skb, struct net_device *dev); @@ -586,18 +586,6 @@ bmac_construct_rxbuff(struct sk_buff *sk virt_to_bus(addr), 0); } -/* Bit-reverse one byte of an ethernet hardware address. */ -static unsigned char -bitrev(unsigned char b) -{ - int d = 0, i; - - for (i = 0; i < 8; ++i, b >>= 1) - d = (d << 1) | (b & 1); - return d; -} - - static void bmac_init_tx_ring(struct bmac_data *bp) { @@ -1224,8 +1212,8 @@ bmac_get_station_address(struct net_devi { reset_and_select_srom(dev); data = read_srom(dev, i + EnetAddressOffset/2, SROMAddressBits); - ea[2*i] = bitrev(data & 0x0ff); - ea[2*i+1] = bitrev((data >> 8) & 0x0ff); + ea[2*i] = bitrev8(data & 0x0ff); + ea[2*i+1] = bitrev8((data >> 8) & 0x0ff); } } @@ -1315,7 +1303,7 @@ static int __devinit bmac_probe(struct m rev = addr[0] == 0 && addr[1] == 0xA0; for (j = 0; j < 6; ++j) - dev->dev_addr[j] = rev? bitrev(addr[j]): addr[j]; + dev->dev_addr[j] = rev ? bitrev8(addr[j]): addr[j]; /* Enable chip without interrupts for now */ bmac_enable_and_reset_chip(dev); diff --git a/drivers/net/bnx2.c b/drivers/net/bnx2.c index ee7b75b..5a96d76 100644 --- a/drivers/net/bnx2.c +++ b/drivers/net/bnx2.c @@ -39,12 +39,9 @@ #ifdef NETIF_F_HW_VLAN_TX #include #define BCM_VLAN 1 #endif -#ifdef NETIF_F_TSO #include #include #include -#define BCM_TSO 1 -#endif #include #include #include @@ -1728,7 +1725,7 @@ bnx2_tx_int(struct bnx2 *bp) tx_buf = &bp->tx_buf_ring[sw_ring_cons]; skb = tx_buf->skb; -#ifdef BCM_TSO + /* partial BD completions possible with TSO packets */ if (skb_is_gso(skb)) { u16 last_idx, last_ring_idx; @@ -1744,7 +1741,7 @@ #ifdef BCM_TSO break; } } -#endif + pci_unmap_single(bp->pdev, pci_unmap_addr(tx_buf, mapping), skb_headlen(skb), PCI_DMA_TODEVICE); @@ -4514,7 +4511,6 @@ bnx2_start_xmit(struct sk_buff *skb, str vlan_tag_flags |= (TX_BD_FLAGS_VLAN_TAG | (vlan_tx_tag_get(skb) << 16)); } -#ifdef BCM_TSO if ((mss = skb_shinfo(skb)->gso_size) && (skb->len > (bp->dev->mtu + ETH_HLEN))) { u32 tcp_opt_len, ip_tcp_len; @@ -4547,7 +4543,6 @@ #ifdef BCM_TSO } } else -#endif { mss = 0; } @@ -5544,10 +5539,8 @@ static const struct ethtool_ops bnx2_eth .set_tx_csum = ethtool_op_set_tx_csum, .get_sg = ethtool_op_get_sg, .set_sg = ethtool_op_set_sg, -#ifdef BCM_TSO .get_tso = ethtool_op_get_tso, .set_tso = bnx2_set_tso, -#endif .self_test_count = bnx2_self_test_count, .self_test = bnx2_self_test, .get_strings = bnx2_get_strings, @@ -5954,8 +5947,7 @@ bnx2_init_board(struct pci_dev *pdev, st * responding after a while. * * AMD believes this incompatibility is unique to the 5706, and - * prefers to locally disable MSI rather than globally disabling it - * using pci_msi_quirk. + * prefers to locally disable MSI rather than globally disabling it. */ if (CHIP_NUM(bp) == CHIP_NUM_5706 && disable_msi == 0) { struct pci_dev *amd_8132 = NULL; @@ -6104,9 +6096,7 @@ #endif #ifdef BCM_VLAN dev->features |= NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_RX; #endif -#ifdef BCM_TSO dev->features |= NETIF_F_TSO | NETIF_F_TSO_ECN; -#endif netif_carrier_off(bp->dev); diff --git a/drivers/net/bonding/bond_alb.c b/drivers/net/bonding/bond_alb.c index 3292316..217a2ee 100644 --- a/drivers/net/bonding/bond_alb.c +++ b/drivers/net/bonding/bond_alb.c @@ -184,7 +184,7 @@ static int tlb_initialize(struct bonding spin_lock_init(&(bond_info->tx_hashtbl_lock)); - new_hashtbl = kmalloc(size, GFP_KERNEL); + new_hashtbl = kzalloc(size, GFP_KERNEL); if (!new_hashtbl) { printk(KERN_ERR DRV_NAME ": %s: Error: Failed to allocate TLB hash table\n", @@ -195,8 +195,6 @@ static int tlb_initialize(struct bonding bond_info->tx_hashtbl = new_hashtbl; - memset(bond_info->tx_hashtbl, 0, size); - for (i = 0; i < TLB_HASH_TABLE_SIZE; i++) { tlb_init_table_entry(&bond_info->tx_hashtbl[i], 1); } diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c index 6482aed..a7c8f98 100644 --- a/drivers/net/bonding/bond_main.c +++ b/drivers/net/bonding/bond_main.c @@ -35,7 +35,6 @@ #include #include -#include #include #include #include @@ -1343,14 +1342,12 @@ int bond_enslave(struct net_device *bond "inaccurate.\n", bond_dev->name, slave_dev->name); } - new_slave = kmalloc(sizeof(struct slave), GFP_KERNEL); + new_slave = kzalloc(sizeof(struct slave), GFP_KERNEL); if (!new_slave) { res = -ENOMEM; goto err_undo_flags; } - memset(new_slave, 0, sizeof(struct slave)); - /* save slave's original flags before calling * netdev_set_master and dev_open */ @@ -3122,7 +3119,7 @@ static int bond_info_open(struct inode * return res; } -static struct file_operations bond_info_fops = { +static const struct file_operations bond_info_fops = { .owner = THIS_MODULE, .open = bond_info_open, .read = seq_read, @@ -4704,6 +4701,7 @@ static int bond_check_params(struct bond static struct lock_class_key bonding_netdev_xmit_lock_key; /* Create a new bond based on the specified name and bonding parameters. + * If name is NULL, obtain a suitable "bond%d" name for us. * Caller must NOT hold rtnl_lock; we need to release it here before we * set up our sysfs entries. */ @@ -4713,7 +4711,8 @@ int bond_create(char *name, struct bond_ int res; rtnl_lock(); - bond_dev = alloc_netdev(sizeof(struct bonding), name, ether_setup); + bond_dev = alloc_netdev(sizeof(struct bonding), name ? name : "", + ether_setup); if (!bond_dev) { printk(KERN_ERR DRV_NAME ": %s: eek! can't alloc netdev!\n", @@ -4722,6 +4721,12 @@ int bond_create(char *name, struct bond_ goto out_rtnl; } + if (!name) { + res = dev_alloc_name(bond_dev, "bond%d"); + if (res < 0) + goto out_netdev; + } + /* bond_init() must be called after dev_alloc_name() (for the * /proc files), but before register_netdevice(), because we * need to set function pointers. @@ -4748,14 +4753,19 @@ int bond_create(char *name, struct bond_ rtnl_unlock(); /* allows sysfs registration of net device */ res = bond_create_sysfs_entry(bond_dev->priv); - goto done; + if (res < 0) { + rtnl_lock(); + goto out_bond; + } + + return 0; + out_bond: bond_deinit(bond_dev); out_netdev: free_netdev(bond_dev); out_rtnl: rtnl_unlock(); -done: return res; } @@ -4763,7 +4773,6 @@ static int __init bonding_init(void) { int i; int res; - char new_bond_name[8]; /* Enough room for 999 bonds at init. */ printk(KERN_INFO "%s", version); @@ -4776,8 +4785,7 @@ #ifdef CONFIG_PROC_FS bond_create_proc_dir(); #endif for (i = 0; i < max_bonds; i++) { - sprintf(new_bond_name, "bond%d",i); - res = bond_create(new_bond_name,&bonding_defaults, NULL); + res = bond_create(NULL, &bonding_defaults, NULL); if (res) goto err; } diff --git a/drivers/net/bonding/bond_sysfs.c b/drivers/net/bonding/bond_sysfs.c index ced9ed8..a122baa 100644 --- a/drivers/net/bonding/bond_sysfs.c +++ b/drivers/net/bonding/bond_sysfs.c @@ -22,7 +22,6 @@ */ #include #include -#include #include #include #include @@ -39,8 +38,7 @@ #include /* #define BONDING_DEBUG 1 */ #include "bonding.h" -#define to_class_dev(obj) container_of(obj,struct class_device,kobj) -#define to_net_dev(class) container_of(class, struct net_device, class_dev) +#define to_dev(obj) container_of(obj,struct device,kobj) #define to_bond(cd) ((struct bonding *)(to_net_dev(cd)->priv)) /*---------------------------- Declarations -------------------------------*/ @@ -154,7 +152,7 @@ static ssize_t bonding_store_bonds(struc * If it's > expected, then there's a file open, * and we have to fail. */ - if (atomic_read(&bond->dev->class_dev.kobj.kref.refcount) + if (atomic_read(&bond->dev->dev.kobj.kref.refcount) > expected_refcount){ rtnl_unlock(); printk(KERN_INFO DRV_NAME @@ -201,13 +199,13 @@ int bond_create_slave_symlinks(struct ne int ret = 0; /* first, create a link from the slave back to the master */ - ret = sysfs_create_link(&(slave->class_dev.kobj), &(master->class_dev.kobj), + ret = sysfs_create_link(&(slave->dev.kobj), &(master->dev.kobj), "master"); if (ret) return ret; /* next, create a link from the master to the slave */ sprintf(linkname,"slave_%s",slave->name); - ret = sysfs_create_link(&(master->class_dev.kobj), &(slave->class_dev.kobj), + ret = sysfs_create_link(&(master->dev.kobj), &(slave->dev.kobj), linkname); return ret; @@ -217,20 +215,21 @@ void bond_destroy_slave_symlinks(struct { char linkname[IFNAMSIZ+7]; - sysfs_remove_link(&(slave->class_dev.kobj), "master"); + sysfs_remove_link(&(slave->dev.kobj), "master"); sprintf(linkname,"slave_%s",slave->name); - sysfs_remove_link(&(master->class_dev.kobj), linkname); + sysfs_remove_link(&(master->dev.kobj), linkname); } /* * Show the slaves in the current bond. */ -static ssize_t bonding_show_slaves(struct class_device *cd, char *buf) +static ssize_t bonding_show_slaves(struct device *d, + struct device_attribute *attr, char *buf) { struct slave *slave; int i, res = 0; - struct bonding *bond = to_bond(cd); + struct bonding *bond = to_bond(d); read_lock_bh(&bond->lock); bond_for_each_slave(bond, slave, i) { @@ -254,14 +253,16 @@ static ssize_t bonding_show_slaves(struc * up for this to succeed. * This function is largely the same flow as bonding_update_bonds(). */ -static ssize_t bonding_store_slaves(struct class_device *cd, const char *buffer, size_t count) +static ssize_t bonding_store_slaves(struct device *d, + struct device_attribute *attr, + const char *buffer, size_t count) { char command[IFNAMSIZ + 1] = { 0, }; char *ifname; int i, res, found, ret = count; struct slave *slave; struct net_device *dev = NULL; - struct bonding *bond = to_bond(cd); + struct bonding *bond = to_bond(d); /* Quick sanity check -- is the bond interface up? */ if (!(bond->dev->flags & IFF_UP)) { @@ -387,25 +388,28 @@ out: return ret; } -static CLASS_DEVICE_ATTR(slaves, S_IRUGO | S_IWUSR, bonding_show_slaves, bonding_store_slaves); +static DEVICE_ATTR(slaves, S_IRUGO | S_IWUSR, bonding_show_slaves, bonding_store_slaves); /* * Show and set the bonding mode. The bond interface must be down to * change the mode. */ -static ssize_t bonding_show_mode(struct class_device *cd, char *buf) +static ssize_t bonding_show_mode(struct device *d, + struct device_attribute *attr, char *buf) { - struct bonding *bond = to_bond(cd); + struct bonding *bond = to_bond(d); return sprintf(buf, "%s %d\n", bond_mode_tbl[bond->params.mode].modename, bond->params.mode) + 1; } -static ssize_t bonding_store_mode(struct class_device *cd, const char *buf, size_t count) +static ssize_t bonding_store_mode(struct device *d, + struct device_attribute *attr, + const char *buf, size_t count) { int new_value, ret = count; - struct bonding *bond = to_bond(cd); + struct bonding *bond = to_bond(d); if (bond->dev->flags & IFF_UP) { printk(KERN_ERR DRV_NAME @@ -438,16 +442,18 @@ static ssize_t bonding_store_mode(struct out: return ret; } -static CLASS_DEVICE_ATTR(mode, S_IRUGO | S_IWUSR, bonding_show_mode, bonding_store_mode); +static DEVICE_ATTR(mode, S_IRUGO | S_IWUSR, bonding_show_mode, bonding_store_mode); /* * Show and set the bonding transmit hash method. The bond interface must be down to * change the xmit hash policy. */ -static ssize_t bonding_show_xmit_hash(struct class_device *cd, char *buf) +static ssize_t bonding_show_xmit_hash(struct device *d, + struct device_attribute *attr, + char *buf) { int count; - struct bonding *bond = to_bond(cd); + struct bonding *bond = to_bond(d); if ((bond->params.mode != BOND_MODE_XOR) && (bond->params.mode != BOND_MODE_8023AD)) { @@ -462,10 +468,12 @@ static ssize_t bonding_show_xmit_hash(st return count; } -static ssize_t bonding_store_xmit_hash(struct class_device *cd, const char *buf, size_t count) +static ssize_t bonding_store_xmit_hash(struct device *d, + struct device_attribute *attr, + const char *buf, size_t count) { int new_value, ret = count; - struct bonding *bond = to_bond(cd); + struct bonding *bond = to_bond(d); if (bond->dev->flags & IFF_UP) { printk(KERN_ERR DRV_NAME @@ -501,24 +509,28 @@ static ssize_t bonding_store_xmit_hash(s out: return ret; } -static CLASS_DEVICE_ATTR(xmit_hash_policy, S_IRUGO | S_IWUSR, bonding_show_xmit_hash, bonding_store_xmit_hash); +static DEVICE_ATTR(xmit_hash_policy, S_IRUGO | S_IWUSR, bonding_show_xmit_hash, bonding_store_xmit_hash); /* * Show and set arp_validate. */ -static ssize_t bonding_show_arp_validate(struct class_device *cd, char *buf) +static ssize_t bonding_show_arp_validate(struct device *d, + struct device_attribute *attr, + char *buf) { - struct bonding *bond = to_bond(cd); + struct bonding *bond = to_bond(d); return sprintf(buf, "%s %d\n", arp_validate_tbl[bond->params.arp_validate].modename, bond->params.arp_validate) + 1; } -static ssize_t bonding_store_arp_validate(struct class_device *cd, const char *buf, size_t count) +static ssize_t bonding_store_arp_validate(struct device *d, + struct device_attribute *attr, + const char *buf, size_t count) { int new_value; - struct bonding *bond = to_bond(cd); + struct bonding *bond = to_bond(d); new_value = bond_parse_parm((char *)buf, arp_validate_tbl); if (new_value < 0) { @@ -548,7 +560,7 @@ static ssize_t bonding_store_arp_validat return count; } -static CLASS_DEVICE_ATTR(arp_validate, S_IRUGO | S_IWUSR, bonding_show_arp_validate, bonding_store_arp_validate); +static DEVICE_ATTR(arp_validate, S_IRUGO | S_IWUSR, bonding_show_arp_validate, bonding_store_arp_validate); /* * Show and set the arp timer interval. There are two tricky bits @@ -556,17 +568,21 @@ static CLASS_DEVICE_ATTR(arp_validate, S * MII monitoring. Second, if the ARP timer isn't running, we must * start it. */ -static ssize_t bonding_show_arp_interval(struct class_device *cd, char *buf) +static ssize_t bonding_show_arp_interval(struct device *d, + struct device_attribute *attr, + char *buf) { - struct bonding *bond = to_bond(cd); + struct bonding *bond = to_bond(d); return sprintf(buf, "%d\n", bond->params.arp_interval) + 1; } -static ssize_t bonding_store_arp_interval(struct class_device *cd, const char *buf, size_t count) +static ssize_t bonding_store_arp_interval(struct device *d, + struct device_attribute *attr, + const char *buf, size_t count) { int new_value, ret = count; - struct bonding *bond = to_bond(cd); + struct bonding *bond = to_bond(d); if (sscanf(buf, "%d", &new_value) != 1) { printk(KERN_ERR DRV_NAME @@ -638,15 +654,17 @@ static ssize_t bonding_store_arp_interva out: return ret; } -static CLASS_DEVICE_ATTR(arp_interval, S_IRUGO | S_IWUSR , bonding_show_arp_interval, bonding_store_arp_interval); +static DEVICE_ATTR(arp_interval, S_IRUGO | S_IWUSR , bonding_show_arp_interval, bonding_store_arp_interval); /* * Show and set the arp targets. */ -static ssize_t bonding_show_arp_targets(struct class_device *cd, char *buf) +static ssize_t bonding_show_arp_targets(struct device *d, + struct device_attribute *attr, + char *buf) { int i, res = 0; - struct bonding *bond = to_bond(cd); + struct bonding *bond = to_bond(d); for (i = 0; i < BOND_MAX_ARP_TARGETS; i++) { if (bond->params.arp_targets[i]) @@ -660,11 +678,13 @@ static ssize_t bonding_show_arp_targets( return res; } -static ssize_t bonding_store_arp_targets(struct class_device *cd, const char *buf, size_t count) +static ssize_t bonding_store_arp_targets(struct device *d, + struct device_attribute *attr, + const char *buf, size_t count) { u32 newtarget; int i = 0, done = 0, ret = count; - struct bonding *bond = to_bond(cd); + struct bonding *bond = to_bond(d); u32 *targets; targets = bond->params.arp_targets; @@ -742,24 +762,28 @@ static ssize_t bonding_store_arp_targets out: return ret; } -static CLASS_DEVICE_ATTR(arp_ip_target, S_IRUGO | S_IWUSR , bonding_show_arp_targets, bonding_store_arp_targets); +static DEVICE_ATTR(arp_ip_target, S_IRUGO | S_IWUSR , bonding_show_arp_targets, bonding_store_arp_targets); /* * Show and set the up and down delays. These must be multiples of the * MII monitoring value, and are stored internally as the multiplier. * Thus, we must translate to MS for the real world. */ -static ssize_t bonding_show_downdelay(struct class_device *cd, char *buf) +static ssize_t bonding_show_downdelay(struct device *d, + struct device_attribute *attr, + char *buf) { - struct bonding *bond = to_bond(cd); + struct bonding *bond = to_bond(d); return sprintf(buf, "%d\n", bond->params.downdelay * bond->params.miimon) + 1; } -static ssize_t bonding_store_downdelay(struct class_device *cd, const char *buf, size_t count) +static ssize_t bonding_store_downdelay(struct device *d, + struct device_attribute *attr, + const char *buf, size_t count) { int new_value, ret = count; - struct bonding *bond = to_bond(cd); + struct bonding *bond = to_bond(d); if (!(bond->params.miimon)) { printk(KERN_ERR DRV_NAME @@ -800,20 +824,24 @@ static ssize_t bonding_store_downdelay(s out: return ret; } -static CLASS_DEVICE_ATTR(downdelay, S_IRUGO | S_IWUSR , bonding_show_downdelay, bonding_store_downdelay); +static DEVICE_ATTR(downdelay, S_IRUGO | S_IWUSR , bonding_show_downdelay, bonding_store_downdelay); -static ssize_t bonding_show_updelay(struct class_device *cd, char *buf) +static ssize_t bonding_show_updelay(struct device *d, + struct device_attribute *attr, + char *buf) { - struct bonding *bond = to_bond(cd); + struct bonding *bond = to_bond(d); return sprintf(buf, "%d\n", bond->params.updelay * bond->params.miimon) + 1; } -static ssize_t bonding_store_updelay(struct class_device *cd, const char *buf, size_t count) +static ssize_t bonding_store_updelay(struct device *d, + struct device_attribute *attr, + const char *buf, size_t count) { int new_value, ret = count; - struct bonding *bond = to_bond(cd); + struct bonding *bond = to_bond(d); if (!(bond->params.miimon)) { printk(KERN_ERR DRV_NAME @@ -854,25 +882,29 @@ static ssize_t bonding_store_updelay(str out: return ret; } -static CLASS_DEVICE_ATTR(updelay, S_IRUGO | S_IWUSR , bonding_show_updelay, bonding_store_updelay); +static DEVICE_ATTR(updelay, S_IRUGO | S_IWUSR , bonding_show_updelay, bonding_store_updelay); /* * Show and set the LACP interval. Interface must be down, and the mode * must be set to 802.3ad mode. */ -static ssize_t bonding_show_lacp(struct class_device *cd, char *buf) +static ssize_t bonding_show_lacp(struct device *d, + struct device_attribute *attr, + char *buf) { - struct bonding *bond = to_bond(cd); + struct bonding *bond = to_bond(d); return sprintf(buf, "%s %d\n", bond_lacp_tbl[bond->params.lacp_fast].modename, bond->params.lacp_fast) + 1; } -static ssize_t bonding_store_lacp(struct class_device *cd, const char *buf, size_t count) +static ssize_t bonding_store_lacp(struct device *d, + struct device_attribute *attr, + const char *buf, size_t count) { int new_value, ret = count; - struct bonding *bond = to_bond(cd); + struct bonding *bond = to_bond(d); if (bond->dev->flags & IFF_UP) { printk(KERN_ERR DRV_NAME @@ -906,7 +938,7 @@ static ssize_t bonding_store_lacp(struct out: return ret; } -static CLASS_DEVICE_ATTR(lacp_rate, S_IRUGO | S_IWUSR, bonding_show_lacp, bonding_store_lacp); +static DEVICE_ATTR(lacp_rate, S_IRUGO | S_IWUSR, bonding_show_lacp, bonding_store_lacp); /* * Show and set the MII monitor interval. There are two tricky bits @@ -914,17 +946,21 @@ static CLASS_DEVICE_ATTR(lacp_rate, S_IR * ARP monitoring. Second, if the timer isn't running, we must * start it. */ -static ssize_t bonding_show_miimon(struct class_device *cd, char *buf) +static ssize_t bonding_show_miimon(struct device *d, + struct device_attribute *attr, + char *buf) { - struct bonding *bond = to_bond(cd); + struct bonding *bond = to_bond(d); return sprintf(buf, "%d\n", bond->params.miimon) + 1; } -static ssize_t bonding_store_miimon(struct class_device *cd, const char *buf, size_t count) +static ssize_t bonding_store_miimon(struct device *d, + struct device_attribute *attr, + const char *buf, size_t count) { int new_value, ret = count; - struct bonding *bond = to_bond(cd); + struct bonding *bond = to_bond(d); if (sscanf(buf, "%d", &new_value) != 1) { printk(KERN_ERR DRV_NAME @@ -1000,7 +1036,7 @@ static ssize_t bonding_store_miimon(stru out: return ret; } -static CLASS_DEVICE_ATTR(miimon, S_IRUGO | S_IWUSR, bonding_show_miimon, bonding_store_miimon); +static DEVICE_ATTR(miimon, S_IRUGO | S_IWUSR, bonding_show_miimon, bonding_store_miimon); /* * Show and set the primary slave. The store function is much @@ -1009,10 +1045,12 @@ static CLASS_DEVICE_ATTR(miimon, S_IRUGO * The bond must be a mode that supports a primary for this be * set. */ -static ssize_t bonding_show_primary(struct class_device *cd, char *buf) +static ssize_t bonding_show_primary(struct device *d, + struct device_attribute *attr, + char *buf) { int count = 0; - struct bonding *bond = to_bond(cd); + struct bonding *bond = to_bond(d); if (bond->primary_slave) count = sprintf(buf, "%s\n", bond->primary_slave->dev->name) + 1; @@ -1022,11 +1060,13 @@ static ssize_t bonding_show_primary(stru return count; } -static ssize_t bonding_store_primary(struct class_device *cd, const char *buf, size_t count) +static ssize_t bonding_store_primary(struct device *d, + struct device_attribute *attr, + const char *buf, size_t count) { int i; struct slave *slave; - struct bonding *bond = to_bond(cd); + struct bonding *bond = to_bond(d); write_lock_bh(&bond->lock); if (!USES_PRIMARY(bond->params.mode)) { @@ -1065,22 +1105,26 @@ out: write_unlock_bh(&bond->lock); return count; } -static CLASS_DEVICE_ATTR(primary, S_IRUGO | S_IWUSR, bonding_show_primary, bonding_store_primary); +static DEVICE_ATTR(primary, S_IRUGO | S_IWUSR, bonding_show_primary, bonding_store_primary); /* * Show and set the use_carrier flag. */ -static ssize_t bonding_show_carrier(struct class_device *cd, char *buf) +static ssize_t bonding_show_carrier(struct device *d, + struct device_attribute *attr, + char *buf) { - struct bonding *bond = to_bond(cd); + struct bonding *bond = to_bond(d); return sprintf(buf, "%d\n", bond->params.use_carrier) + 1; } -static ssize_t bonding_store_carrier(struct class_device *cd, const char *buf, size_t count) +static ssize_t bonding_store_carrier(struct device *d, + struct device_attribute *attr, + const char *buf, size_t count) { int new_value, ret = count; - struct bonding *bond = to_bond(cd); + struct bonding *bond = to_bond(d); if (sscanf(buf, "%d", &new_value) != 1) { @@ -1102,16 +1146,18 @@ static ssize_t bonding_store_carrier(str out: return count; } -static CLASS_DEVICE_ATTR(use_carrier, S_IRUGO | S_IWUSR, bonding_show_carrier, bonding_store_carrier); +static DEVICE_ATTR(use_carrier, S_IRUGO | S_IWUSR, bonding_show_carrier, bonding_store_carrier); /* * Show and set currently active_slave. */ -static ssize_t bonding_show_active_slave(struct class_device *cd, char *buf) +static ssize_t bonding_show_active_slave(struct device *d, + struct device_attribute *attr, + char *buf) { struct slave *curr; - struct bonding *bond = to_bond(cd); + struct bonding *bond = to_bond(d); int count; @@ -1126,13 +1172,15 @@ static ssize_t bonding_show_active_slave return count; } -static ssize_t bonding_store_active_slave(struct class_device *cd, const char *buf, size_t count) +static ssize_t bonding_store_active_slave(struct device *d, + struct device_attribute *attr, + const char *buf, size_t count) { int i; struct slave *slave; struct slave *old_active = NULL; struct slave *new_active = NULL; - struct bonding *bond = to_bond(cd); + struct bonding *bond = to_bond(d); write_lock_bh(&bond->lock); if (!USES_PRIMARY(bond->params.mode)) { @@ -1194,16 +1242,18 @@ out: return count; } -static CLASS_DEVICE_ATTR(active_slave, S_IRUGO | S_IWUSR, bonding_show_active_slave, bonding_store_active_slave); +static DEVICE_ATTR(active_slave, S_IRUGO | S_IWUSR, bonding_show_active_slave, bonding_store_active_slave); /* * Show link status of the bond interface. */ -static ssize_t bonding_show_mii_status(struct class_device *cd, char *buf) +static ssize_t bonding_show_mii_status(struct device *d, + struct device_attribute *attr, + char *buf) { struct slave *curr; - struct bonding *bond = to_bond(cd); + struct bonding *bond = to_bond(d); read_lock(&bond->curr_slave_lock); curr = bond->curr_active_slave; @@ -1211,16 +1261,18 @@ static ssize_t bonding_show_mii_status(s return sprintf(buf, "%s\n", (curr) ? "up" : "down") + 1; } -static CLASS_DEVICE_ATTR(mii_status, S_IRUGO, bonding_show_mii_status, NULL); +static DEVICE_ATTR(mii_status, S_IRUGO, bonding_show_mii_status, NULL); /* * Show current 802.3ad aggregator ID. */ -static ssize_t bonding_show_ad_aggregator(struct class_device *cd, char *buf) +static ssize_t bonding_show_ad_aggregator(struct device *d, + struct device_attribute *attr, + char *buf) { int count = 0; - struct bonding *bond = to_bond(cd); + struct bonding *bond = to_bond(d); if (bond->params.mode == BOND_MODE_8023AD) { struct ad_info ad_info; @@ -1231,16 +1283,18 @@ static ssize_t bonding_show_ad_aggregato return count; } -static CLASS_DEVICE_ATTR(ad_aggregator, S_IRUGO, bonding_show_ad_aggregator, NULL); +static DEVICE_ATTR(ad_aggregator, S_IRUGO, bonding_show_ad_aggregator, NULL); /* * Show number of active 802.3ad ports. */ -static ssize_t bonding_show_ad_num_ports(struct class_device *cd, char *buf) +static ssize_t bonding_show_ad_num_ports(struct device *d, + struct device_attribute *attr, + char *buf) { int count = 0; - struct bonding *bond = to_bond(cd); + struct bonding *bond = to_bond(d); if (bond->params.mode == BOND_MODE_8023AD) { struct ad_info ad_info; @@ -1251,16 +1305,18 @@ static ssize_t bonding_show_ad_num_ports return count; } -static CLASS_DEVICE_ATTR(ad_num_ports, S_IRUGO, bonding_show_ad_num_ports, NULL); +static DEVICE_ATTR(ad_num_ports, S_IRUGO, bonding_show_ad_num_ports, NULL); /* * Show current 802.3ad actor key. */ -static ssize_t bonding_show_ad_actor_key(struct class_device *cd, char *buf) +static ssize_t bonding_show_ad_actor_key(struct device *d, + struct device_attribute *attr, + char *buf) { int count = 0; - struct bonding *bond = to_bond(cd); + struct bonding *bond = to_bond(d); if (bond->params.mode == BOND_MODE_8023AD) { struct ad_info ad_info; @@ -1271,16 +1327,18 @@ static ssize_t bonding_show_ad_actor_key return count; } -static CLASS_DEVICE_ATTR(ad_actor_key, S_IRUGO, bonding_show_ad_actor_key, NULL); +static DEVICE_ATTR(ad_actor_key, S_IRUGO, bonding_show_ad_actor_key, NULL); /* * Show current 802.3ad partner key. */ -static ssize_t bonding_show_ad_partner_key(struct class_device *cd, char *buf) +static ssize_t bonding_show_ad_partner_key(struct device *d, + struct device_attribute *attr, + char *buf) { int count = 0; - struct bonding *bond = to_bond(cd); + struct bonding *bond = to_bond(d); if (bond->params.mode == BOND_MODE_8023AD) { struct ad_info ad_info; @@ -1291,16 +1349,18 @@ static ssize_t bonding_show_ad_partner_k return count; } -static CLASS_DEVICE_ATTR(ad_partner_key, S_IRUGO, bonding_show_ad_partner_key, NULL); +static DEVICE_ATTR(ad_partner_key, S_IRUGO, bonding_show_ad_partner_key, NULL); /* * Show current 802.3ad partner mac. */ -static ssize_t bonding_show_ad_partner_mac(struct class_device *cd, char *buf) +static ssize_t bonding_show_ad_partner_mac(struct device *d, + struct device_attribute *attr, + char *buf) { int count = 0; - struct bonding *bond = to_bond(cd); + struct bonding *bond = to_bond(d); if (bond->params.mode == BOND_MODE_8023AD) { struct ad_info ad_info; @@ -1319,30 +1379,30 @@ static ssize_t bonding_show_ad_partner_m return count; } -static CLASS_DEVICE_ATTR(ad_partner_mac, S_IRUGO, bonding_show_ad_partner_mac, NULL); +static DEVICE_ATTR(ad_partner_mac, S_IRUGO, bonding_show_ad_partner_mac, NULL); static struct attribute *per_bond_attrs[] = { - &class_device_attr_slaves.attr, - &class_device_attr_mode.attr, - &class_device_attr_arp_validate.attr, - &class_device_attr_arp_interval.attr, - &class_device_attr_arp_ip_target.attr, - &class_device_attr_downdelay.attr, - &class_device_attr_updelay.attr, - &class_device_attr_lacp_rate.attr, - &class_device_attr_xmit_hash_policy.attr, - &class_device_attr_miimon.attr, - &class_device_attr_primary.attr, - &class_device_attr_use_carrier.attr, - &class_device_attr_active_slave.attr, - &class_device_attr_mii_status.attr, - &class_device_attr_ad_aggregator.attr, - &class_device_attr_ad_num_ports.attr, - &class_device_attr_ad_actor_key.attr, - &class_device_attr_ad_partner_key.attr, - &class_device_attr_ad_partner_mac.attr, + &dev_attr_slaves.attr, + &dev_attr_mode.attr, + &dev_attr_arp_validate.attr, + &dev_attr_arp_interval.attr, + &dev_attr_arp_ip_target.attr, + &dev_attr_downdelay.attr, + &dev_attr_updelay.attr, + &dev_attr_lacp_rate.attr, + &dev_attr_xmit_hash_policy.attr, + &dev_attr_miimon.attr, + &dev_attr_primary.attr, + &dev_attr_use_carrier.attr, + &dev_attr_active_slave.attr, + &dev_attr_mii_status.attr, + &dev_attr_ad_aggregator.attr, + &dev_attr_ad_num_ports.attr, + &dev_attr_ad_actor_key.attr, + &dev_attr_ad_partner_key.attr, + &dev_attr_ad_partner_mac.attr, NULL, }; @@ -1367,11 +1427,26 @@ int bond_create_sysfs(void) if (!firstbond) return -ENODEV; - netdev_class = firstbond->dev->class_dev.class; + netdev_class = firstbond->dev->dev.class; if (!netdev_class) return -ENODEV; ret = class_create_file(netdev_class, &class_attr_bonding_masters); + /* + * Permit multiple loads of the module by ignoring failures to + * create the bonding_masters sysfs file. Bonding devices + * created by second or subsequent loads of the module will + * not be listed in, or controllable by, bonding_masters, but + * will have the usual "bonding" sysfs directory. + * + * This is done to preserve backwards compatibility for + * initscripts/sysconfig, which load bonding multiple times to + * configure multiple bonding devices. + */ + if (ret == -EEXIST) { + netdev_class = NULL; + return 0; + } return ret; @@ -1395,13 +1470,13 @@ int bond_create_sysfs_entry(struct bondi struct net_device *dev = bond->dev; int err; - err = sysfs_create_group(&(dev->class_dev.kobj), &bonding_group); + err = sysfs_create_group(&(dev->dev.kobj), &bonding_group); if (err) { printk(KERN_EMERG "eek! didn't create group!\n"); } if (expected_refcount < 1) - expected_refcount = atomic_read(&bond->dev->class_dev.kobj.kref.refcount); + expected_refcount = atomic_read(&bond->dev->dev.kobj.kref.refcount); return err; } @@ -1412,6 +1487,6 @@ void bond_destroy_sysfs_entry(struct bon { struct net_device *dev = bond->dev; - sysfs_remove_group(&(dev->class_dev.kobj), &bonding_group); + sysfs_remove_group(&(dev->dev.kobj), &bonding_group); } diff --git a/drivers/net/bonding/bonding.h b/drivers/net/bonding/bonding.h index 0978c9a..41aa78b 100644 --- a/drivers/net/bonding/bonding.h +++ b/drivers/net/bonding/bonding.h @@ -22,8 +22,8 @@ #include #include "bond_3ad.h" #include "bond_alb.h" -#define DRV_VERSION "3.1.1" -#define DRV_RELDATE "September 26, 2006" +#define DRV_VERSION "3.1.2" +#define DRV_RELDATE "January 20, 2007" #define DRV_NAME "bonding" #define DRV_DESCRIPTION "Ethernet Channel Bonding Driver" @@ -237,12 +237,13 @@ #define BOND_ARP_VALIDATE_BACKUP (1 << B #define BOND_ARP_VALIDATE_ALL (BOND_ARP_VALIDATE_ACTIVE | \ BOND_ARP_VALIDATE_BACKUP) -extern inline int slave_do_arp_validate(struct bonding *bond, struct slave *slave) +static inline int slave_do_arp_validate(struct bonding *bond, + struct slave *slave) { return bond->params.arp_validate & (1 << slave->state); } -extern inline unsigned long slave_last_rx(struct bonding *bond, +static inline unsigned long slave_last_rx(struct bonding *bond, struct slave *slave) { if (slave_do_arp_validate(bond, slave)) diff --git a/drivers/net/chelsio/common.h b/drivers/net/chelsio/common.h index 74758d2..787f2f2 100644 --- a/drivers/net/chelsio/common.h +++ b/drivers/net/chelsio/common.h @@ -324,7 +324,7 @@ struct board_info { unsigned char mdio_phybaseaddr; struct gmac *gmac; struct gphy *gphy; - struct mdio_ops *mdio_ops; + struct mdio_ops *mdio_ops; const char *desc; }; diff --git a/drivers/net/chelsio/cpl5_cmd.h b/drivers/net/chelsio/cpl5_cmd.h index 35f565b..e36d45b 100644 --- a/drivers/net/chelsio/cpl5_cmd.h +++ b/drivers/net/chelsio/cpl5_cmd.h @@ -103,7 +103,7 @@ enum CPL_opcode { CPL_MIGRATE_C2T_RPL = 0xDD, CPL_ERROR = 0xD7, - /* internal: driver -> TOM */ + /* internal: driver -> TOM */ CPL_MSS_CHANGE = 0xE1 }; @@ -159,8 +159,8 @@ enum { // TX_PKT_LSO ethe }; union opcode_tid { - u32 opcode_tid; - u8 opcode; + u32 opcode_tid; + u8 opcode; }; #define S_OPCODE 24 @@ -234,7 +234,7 @@ struct cpl_pass_accept_req { u32 local_ip; u32 peer_ip; u32 tos_tid; - struct tcp_options tcp_options; + struct tcp_options tcp_options; u8 dst_mac[6]; u16 vlan_tag; u8 src_mac[6]; @@ -250,12 +250,12 @@ struct cpl_pass_accept_rpl { u32 peer_ip; u32 opt0h; union { - u32 opt0l; - struct { - u8 rsvd[3]; - u8 status; + u32 opt0l; + struct { + u8 rsvd[3]; + u8 status; + }; }; - }; }; struct cpl_act_open_req { diff --git a/drivers/net/chelsio/cxgb2.c b/drivers/net/chelsio/cxgb2.c index fd5d821..7d0f24f 100644 --- a/drivers/net/chelsio/cxgb2.c +++ b/drivers/net/chelsio/cxgb2.c @@ -69,14 +69,14 @@ static inline void cancel_mac_stats_upda cancel_delayed_work(&ap->stats_update_task); } -#define MAX_CMDQ_ENTRIES 16384 -#define MAX_CMDQ1_ENTRIES 1024 -#define MAX_RX_BUFFERS 16384 -#define MAX_RX_JUMBO_BUFFERS 16384 +#define MAX_CMDQ_ENTRIES 16384 +#define MAX_CMDQ1_ENTRIES 1024 +#define MAX_RX_BUFFERS 16384 +#define MAX_RX_JUMBO_BUFFERS 16384 #define MAX_TX_BUFFERS_HIGH 16384U #define MAX_TX_BUFFERS_LOW 1536U #define MAX_TX_BUFFERS 1460U -#define MIN_FL_ENTRIES 32 +#define MIN_FL_ENTRIES 32 #define DFLT_MSG_ENABLE (NETIF_MSG_DRV | NETIF_MSG_PROBE | NETIF_MSG_LINK | \ NETIF_MSG_TIMER | NETIF_MSG_IFDOWN | NETIF_MSG_IFUP |\ @@ -143,7 +143,7 @@ static void link_report(struct port_info case SPEED_100: s = "100Mbps"; break; } - printk(KERN_INFO "%s: link up, %s, %s-duplex\n", + printk(KERN_INFO "%s: link up, %s, %s-duplex\n", p->dev->name, s, p->link_config.duplex == DUPLEX_FULL ? "full" : "half"); } @@ -233,7 +233,7 @@ static int cxgb_up(struct adapter *adapt t1_sge_start(adapter->sge); t1_interrupts_enable(adapter); - out_err: +out_err: return err; } @@ -454,51 +454,21 @@ static void get_stats(struct net_device const struct cmac_statistics *s; const struct sge_intr_counts *t; struct sge_port_stats ss; + unsigned int len; s = mac->ops->statistics_update(mac, MAC_STATS_UPDATE_FULL); - *data++ = s->TxOctetsOK; - *data++ = s->TxOctetsBad; - *data++ = s->TxUnicastFramesOK; - *data++ = s->TxMulticastFramesOK; - *data++ = s->TxBroadcastFramesOK; - *data++ = s->TxPauseFrames; - *data++ = s->TxFramesWithDeferredXmissions; - *data++ = s->TxLateCollisions; - *data++ = s->TxTotalCollisions; - *data++ = s->TxFramesAbortedDueToXSCollisions; - *data++ = s->TxUnderrun; - *data++ = s->TxLengthErrors; - *data++ = s->TxInternalMACXmitError; - *data++ = s->TxFramesWithExcessiveDeferral; - *data++ = s->TxFCSErrors; - - *data++ = s->RxOctetsOK; - *data++ = s->RxOctetsBad; - *data++ = s->RxUnicastFramesOK; - *data++ = s->RxMulticastFramesOK; - *data++ = s->RxBroadcastFramesOK; - *data++ = s->RxPauseFrames; - *data++ = s->RxFCSErrors; - *data++ = s->RxAlignErrors; - *data++ = s->RxSymbolErrors; - *data++ = s->RxDataErrors; - *data++ = s->RxSequenceErrors; - *data++ = s->RxRuntErrors; - *data++ = s->RxJabberErrors; - *data++ = s->RxInternalMACRcvError; - *data++ = s->RxInRangeLengthErrors; - *data++ = s->RxOutOfRangeLengthField; - *data++ = s->RxFrameTooLongErrors; + len = sizeof(u64)*(&s->TxFCSErrors + 1 - &s->TxOctetsOK); + memcpy(data, &s->TxOctetsOK, len); + data += len; + + len = sizeof(u64)*(&s->RxFrameTooLongErrors + 1 - &s->RxOctetsOK); + memcpy(data, &s->RxOctetsOK, len); + data += len; t1_sge_get_port_stats(adapter->sge, dev->if_port, &ss); - *data++ = ss.rx_packets; - *data++ = ss.rx_cso_good; - *data++ = ss.tx_packets; - *data++ = ss.tx_cso; - *data++ = ss.tx_tso; - *data++ = ss.vlan_xtract; - *data++ = ss.vlan_insert; + memcpy(data, &ss, sizeof(ss)); + data += sizeof(ss); t = t1_sge_get_intr_counts(adapter->sge); *data++ = t->rx_drops; @@ -749,7 +719,7 @@ static int set_sge_param(struct net_devi return -EINVAL; if (adapter->flags & FULL_INIT_DONE) - return -EBUSY; + return -EBUSY; adapter->params.sge.freelQ_size[!jumbo_fl] = e->rx_pending; adapter->params.sge.freelQ_size[jumbo_fl] = e->rx_jumbo_pending; @@ -764,7 +734,7 @@ static int set_coalesce(struct net_devic struct adapter *adapter = dev->priv; adapter->params.sge.rx_coalesce_usecs = c->rx_coalesce_usecs; - adapter->params.sge.coalesce_enable = c->use_adaptive_rx_coalesce; + adapter->params.sge.coalesce_enable = c->use_adaptive_rx_coalesce; adapter->params.sge.sample_interval_usecs = c->rate_sample_interval; t1_sge_set_coalesce_params(adapter->sge, &adapter->params.sge); return 0; @@ -782,9 +752,9 @@ static int get_coalesce(struct net_devic static int get_eeprom_len(struct net_device *dev) { - struct adapter *adapter = dev->priv; + struct adapter *adapter = dev->priv; - return t1_is_asic(adapter) ? EEPROM_SIZE : 0; + return t1_is_asic(adapter) ? EEPROM_SIZE : 0; } #define EEPROM_MAGIC(ap) \ @@ -848,7 +818,7 @@ static int t1_ioctl(struct net_device *d u32 val; if (!phy->mdio_read) - return -EOPNOTSUPP; + return -EOPNOTSUPP; phy->mdio_read(adapter, data->phy_id, 0, data->reg_num & 0x1f, &val); data->val_out = val; @@ -860,7 +830,7 @@ static int t1_ioctl(struct net_device *d if (!capable(CAP_NET_ADMIN)) return -EPERM; if (!phy->mdio_write) - return -EOPNOTSUPP; + return -EOPNOTSUPP; phy->mdio_write(adapter, data->phy_id, 0, data->reg_num & 0x1f, data->val_in); break; @@ -879,9 +849,9 @@ static int t1_change_mtu(struct net_devi struct cmac *mac = adapter->port[dev->if_port].mac; if (!mac->ops->set_mtu) - return -EOPNOTSUPP; + return -EOPNOTSUPP; if (new_mtu < 68) - return -EINVAL; + return -EINVAL; if ((ret = mac->ops->set_mtu(mac, new_mtu))) return ret; dev->mtu = new_mtu; @@ -1211,9 +1181,9 @@ #endif return 0; - out_release_adapter_res: +out_release_adapter_res: t1_free_sw_modules(adapter); - out_free_dev: +out_free_dev: if (adapter) { if (adapter->regs) iounmap(adapter->regs); @@ -1222,7 +1192,7 @@ #endif free_netdev(adapter->port[i].dev); } pci_release_regions(pdev); - out_disable_pdev: +out_disable_pdev: pci_disable_device(pdev); pci_set_drvdata(pdev, NULL); return err; @@ -1273,28 +1243,27 @@ static int t1_clock(struct adapter *adap int M_MEM_VAL; enum { - M_CORE_BITS = 9, - T_CORE_VAL = 0, - T_CORE_BITS = 2, - N_CORE_VAL = 0, - N_CORE_BITS = 2, - M_MEM_BITS = 9, - T_MEM_VAL = 0, - T_MEM_BITS = 2, - N_MEM_VAL = 0, - N_MEM_BITS = 2, - NP_LOAD = 1 << 17, - S_LOAD_MEM = 1 << 5, - S_LOAD_CORE = 1 << 6, - S_CLOCK = 1 << 3 + M_CORE_BITS = 9, + T_CORE_VAL = 0, + T_CORE_BITS = 2, + N_CORE_VAL = 0, + N_CORE_BITS = 2, + M_MEM_BITS = 9, + T_MEM_VAL = 0, + T_MEM_BITS = 2, + N_MEM_VAL = 0, + N_MEM_BITS = 2, + NP_LOAD = 1 << 17, + S_LOAD_MEM = 1 << 5, + S_LOAD_CORE = 1 << 6, + S_CLOCK = 1 << 3 }; if (!t1_is_T1B(adapter)) return -ENODEV; /* Can't re-clock this chip. */ - if (mode & 2) { + if (mode & 2) return 0; /* show current mode. */ - } if ((adapter->t1powersave & 1) == (mode & 1)) return -EALREADY; /* ASIC already running in mode. */ @@ -1386,26 +1355,26 @@ static inline void t1_sw_reset(struct pc static void __devexit remove_one(struct pci_dev *pdev) { struct net_device *dev = pci_get_drvdata(pdev); + struct adapter *adapter = dev->priv; + int i; - if (dev) { - int i; - struct adapter *adapter = dev->priv; - - for_each_port(adapter, i) - if (test_bit(i, &adapter->registered_device_map)) - unregister_netdev(adapter->port[i].dev); + for_each_port(adapter, i) { + if (test_bit(i, &adapter->registered_device_map)) + unregister_netdev(adapter->port[i].dev); + } - t1_free_sw_modules(adapter); - iounmap(adapter->regs); - while (--i >= 0) - if (adapter->port[i].dev) - free_netdev(adapter->port[i].dev); + t1_free_sw_modules(adapter); + iounmap(adapter->regs); - pci_release_regions(pdev); - pci_disable_device(pdev); - pci_set_drvdata(pdev, NULL); - t1_sw_reset(pdev); + while (--i >= 0) { + if (adapter->port[i].dev) + free_netdev(adapter->port[i].dev); } + + pci_release_regions(pdev); + pci_disable_device(pdev); + pci_set_drvdata(pdev, NULL); + t1_sw_reset(pdev); } static struct pci_driver driver = { diff --git a/drivers/net/chelsio/elmer0.h b/drivers/net/chelsio/elmer0.h index 9ebecaa..eef655c 100644 --- a/drivers/net/chelsio/elmer0.h +++ b/drivers/net/chelsio/elmer0.h @@ -46,14 +46,14 @@ enum { }; /* ELMER0 registers */ -#define A_ELMER0_VERSION 0x100000 -#define A_ELMER0_PHY_CFG 0x100004 -#define A_ELMER0_INT_ENABLE 0x100008 -#define A_ELMER0_INT_CAUSE 0x10000c -#define A_ELMER0_GPI_CFG 0x100010 -#define A_ELMER0_GPI_STAT 0x100014 -#define A_ELMER0_GPO 0x100018 -#define A_ELMER0_PORT0_MI1_CFG 0x400000 +#define A_ELMER0_VERSION 0x100000 +#define A_ELMER0_PHY_CFG 0x100004 +#define A_ELMER0_INT_ENABLE 0x100008 +#define A_ELMER0_INT_CAUSE 0x10000c +#define A_ELMER0_GPI_CFG 0x100010 +#define A_ELMER0_GPI_STAT 0x100014 +#define A_ELMER0_GPO 0x100018 +#define A_ELMER0_PORT0_MI1_CFG 0x400000 #define S_MI1_MDI_ENABLE 0 #define V_MI1_MDI_ENABLE(x) ((x) << S_MI1_MDI_ENABLE) @@ -111,18 +111,18 @@ #define S_MI1_OP_BUSY 31 #define V_MI1_OP_BUSY(x) ((x) << S_MI1_OP_BUSY) #define F_MI1_OP_BUSY V_MI1_OP_BUSY(1U) -#define A_ELMER0_PORT1_MI1_CFG 0x500000 -#define A_ELMER0_PORT1_MI1_ADDR 0x500004 -#define A_ELMER0_PORT1_MI1_DATA 0x500008 -#define A_ELMER0_PORT1_MI1_OP 0x50000c -#define A_ELMER0_PORT2_MI1_CFG 0x600000 -#define A_ELMER0_PORT2_MI1_ADDR 0x600004 -#define A_ELMER0_PORT2_MI1_DATA 0x600008 -#define A_ELMER0_PORT2_MI1_OP 0x60000c -#define A_ELMER0_PORT3_MI1_CFG 0x700000 -#define A_ELMER0_PORT3_MI1_ADDR 0x700004 -#define A_ELMER0_PORT3_MI1_DATA 0x700008 -#define A_ELMER0_PORT3_MI1_OP 0x70000c +#define A_ELMER0_PORT1_MI1_CFG 0x500000 +#define A_ELMER0_PORT1_MI1_ADDR 0x500004 +#define A_ELMER0_PORT1_MI1_DATA 0x500008 +#define A_ELMER0_PORT1_MI1_OP 0x50000c +#define A_ELMER0_PORT2_MI1_CFG 0x600000 +#define A_ELMER0_PORT2_MI1_ADDR 0x600004 +#define A_ELMER0_PORT2_MI1_DATA 0x600008 +#define A_ELMER0_PORT2_MI1_OP 0x60000c +#define A_ELMER0_PORT3_MI1_CFG 0x700000 +#define A_ELMER0_PORT3_MI1_ADDR 0x700004 +#define A_ELMER0_PORT3_MI1_DATA 0x700008 +#define A_ELMER0_PORT3_MI1_OP 0x70000c /* Simple bit definition for GPI and GP0 registers. */ #define ELMER0_GP_BIT0 0x0001 diff --git a/drivers/net/chelsio/espi.c b/drivers/net/chelsio/espi.c index 4192f0f..d7c5406 100644 --- a/drivers/net/chelsio/espi.c +++ b/drivers/net/chelsio/espi.c @@ -202,9 +202,9 @@ static void espi_setup_for_pm3393(adapte static void espi_setup_for_vsc7321(adapter_t *adapter) { - writel(0x1f4, adapter->regs + A_ESPI_SCH_TOKEN0); - writel(0x1f401f4, adapter->regs + A_ESPI_SCH_TOKEN1); - writel(0x1f4, adapter->regs + A_ESPI_SCH_TOKEN2); + writel(0x1f4, adapter->regs + A_ESPI_SCH_TOKEN0); + writel(0x1f401f4, adapter->regs + A_ESPI_SCH_TOKEN1); + writel(0x1f4, adapter->regs + A_ESPI_SCH_TOKEN2); writel(0xa00, adapter->regs + A_ESPI_RX_FIFO_ALMOST_FULL_WATERMARK); writel(0x1ff, adapter->regs + A_ESPI_RX_FIFO_ALMOST_EMPTY_WATERMARK); writel(1, adapter->regs + A_ESPI_CALENDAR_LENGTH); @@ -247,10 +247,10 @@ int t1_espi_init(struct peespi *espi, in writel(V_OUT_OF_SYNC_COUNT(4) | V_DIP2_PARITY_ERR_THRES(3) | V_DIP4_THRES(1), adapter->regs + A_ESPI_MISC_CONTROL); - writel(nports == 4 ? 0x200040 : 0x1000080, + writel(nports == 4 ? 0x200040 : 0x1000080, adapter->regs + A_ESPI_MAXBURST1_MAXBURST2); } else - writel(0x800100, adapter->regs + A_ESPI_MAXBURST1_MAXBURST2); + writel(0x800100, adapter->regs + A_ESPI_MAXBURST1_MAXBURST2); if (mac_type == CHBT_MAC_PM3393) espi_setup_for_pm3393(adapter); @@ -301,7 +301,8 @@ void t1_espi_set_misc_ctrl(adapter_t *ad { struct peespi *espi = adapter->espi; - if (!is_T2(adapter)) return; + if (!is_T2(adapter)) + return; spin_lock(&espi->lock); espi->misc_ctrl = (val & ~MON_MASK) | (espi->misc_ctrl & MON_MASK); @@ -340,32 +341,31 @@ u32 t1_espi_get_mon(adapter_t *adapter, * compare with t1_espi_get_mon(), it reads espiInTxSop[0 ~ 3] in * one shot, since there is no per port counter on the out side. */ -int -t1_espi_get_mon_t204(adapter_t *adapter, u32 *valp, u8 wait) +int t1_espi_get_mon_t204(adapter_t *adapter, u32 *valp, u8 wait) { - struct peespi *espi = adapter->espi; + struct peespi *espi = adapter->espi; u8 i, nport = (u8)adapter->params.nports; - if (!wait) { - if (!spin_trylock(&espi->lock)) - return -1; - } else - spin_lock(&espi->lock); + if (!wait) { + if (!spin_trylock(&espi->lock)) + return -1; + } else + spin_lock(&espi->lock); - if ( (espi->misc_ctrl & MON_MASK) != F_MONITORED_DIRECTION ) { + if ((espi->misc_ctrl & MON_MASK) != F_MONITORED_DIRECTION) { espi->misc_ctrl = (espi->misc_ctrl & ~MON_MASK) | F_MONITORED_DIRECTION; - writel(espi->misc_ctrl, adapter->regs + A_ESPI_MISC_CONTROL); - } + writel(espi->misc_ctrl, adapter->regs + A_ESPI_MISC_CONTROL); + } for (i = 0 ; i < nport; i++, valp++) { if (i) { writel(espi->misc_ctrl | V_MONITORED_PORT_NUM(i), adapter->regs + A_ESPI_MISC_CONTROL); } - *valp = readl(adapter->regs + A_ESPI_SCH_TOKEN3); - } + *valp = readl(adapter->regs + A_ESPI_SCH_TOKEN3); + } - writel(espi->misc_ctrl, adapter->regs + A_ESPI_MISC_CONTROL); - spin_unlock(&espi->lock); - return 0; + writel(espi->misc_ctrl, adapter->regs + A_ESPI_MISC_CONTROL); + spin_unlock(&espi->lock); + return 0; } diff --git a/drivers/net/chelsio/fpga_defs.h b/drivers/net/chelsio/fpga_defs.h index 17a3c2b..ccdb2bc 100644 --- a/drivers/net/chelsio/fpga_defs.h +++ b/drivers/net/chelsio/fpga_defs.h @@ -98,9 +98,9 @@ #define A_MI0_DATA_EXT 0xb0c #define A_MI0_DATA_INT 0xb10 /* GMAC registers */ -#define A_GMAC_MACID_LO 0x28 -#define A_GMAC_MACID_HI 0x2c -#define A_GMAC_CSR 0x30 +#define A_GMAC_MACID_LO 0x28 +#define A_GMAC_MACID_HI 0x2c +#define A_GMAC_CSR 0x30 #define S_INTERFACE 0 #define M_INTERFACE 0x3 diff --git a/drivers/net/chelsio/gmac.h b/drivers/net/chelsio/gmac.h index a2b8ad9..006a2eb 100644 --- a/drivers/net/chelsio/gmac.h +++ b/drivers/net/chelsio/gmac.h @@ -42,8 +42,15 @@ #define _CXGB_GMAC_H_ #include "common.h" -enum { MAC_STATS_UPDATE_FAST, MAC_STATS_UPDATE_FULL }; -enum { MAC_DIRECTION_RX = 1, MAC_DIRECTION_TX = 2 }; +enum { + MAC_STATS_UPDATE_FAST, + MAC_STATS_UPDATE_FULL +}; + +enum { + MAC_DIRECTION_RX = 1, + MAC_DIRECTION_TX = 2 +}; struct cmac_statistics { /* Transmit */ diff --git a/drivers/net/chelsio/ixf1010.c b/drivers/net/chelsio/ixf1010.c index 5b8f144..10b2a9a 100644 --- a/drivers/net/chelsio/ixf1010.c +++ b/drivers/net/chelsio/ixf1010.c @@ -145,48 +145,61 @@ static void disable_port(struct cmac *ma t1_tpi_write(mac->adapter, REG_PORT_ENABLE, val); } -#define RMON_UPDATE(mac, name, stat_name) \ - t1_tpi_read((mac)->adapter, MACREG(mac, REG_##name), &val); \ - (mac)->stats.stat_name += val; - /* * Read the current values of the RMON counters and add them to the cumulative * port statistics. The HW RMON counters are cleared by this operation. */ static void port_stats_update(struct cmac *mac) { - u32 val; + static struct { + unsigned int reg; + unsigned int offset; + } hw_stats[] = { + +#define HW_STAT(name, stat_name) \ + { REG_##name, \ + (&((struct cmac_statistics *)NULL)->stat_name) - (u64 *)NULL } + + /* Rx stats */ + HW_STAT(RxOctetsTotalOK, RxOctetsOK), + HW_STAT(RxOctetsBad, RxOctetsBad), + HW_STAT(RxUCPkts, RxUnicastFramesOK), + HW_STAT(RxMCPkts, RxMulticastFramesOK), + HW_STAT(RxBCPkts, RxBroadcastFramesOK), + HW_STAT(RxJumboPkts, RxJumboFramesOK), + HW_STAT(RxFCSErrors, RxFCSErrors), + HW_STAT(RxAlignErrors, RxAlignErrors), + HW_STAT(RxLongErrors, RxFrameTooLongErrors), + HW_STAT(RxVeryLongErrors, RxFrameTooLongErrors), + HW_STAT(RxPauseMacControlCounter, RxPauseFrames), + HW_STAT(RxDataErrors, RxDataErrors), + HW_STAT(RxJabberErrors, RxJabberErrors), + HW_STAT(RxRuntErrors, RxRuntErrors), + HW_STAT(RxShortErrors, RxRuntErrors), + HW_STAT(RxSequenceErrors, RxSequenceErrors), + HW_STAT(RxSymbolErrors, RxSymbolErrors), + + /* Tx stats (skip collision stats as we are full-duplex only) */ + HW_STAT(TxOctetsTotalOK, TxOctetsOK), + HW_STAT(TxOctetsBad, TxOctetsBad), + HW_STAT(TxUCPkts, TxUnicastFramesOK), + HW_STAT(TxMCPkts, TxMulticastFramesOK), + HW_STAT(TxBCPkts, TxBroadcastFramesOK), + HW_STAT(TxJumboPkts, TxJumboFramesOK), + HW_STAT(TxPauseFrames, TxPauseFrames), + HW_STAT(TxExcessiveLengthDrop, TxLengthErrors), + HW_STAT(TxUnderrun, TxUnderrun), + HW_STAT(TxCRCErrors, TxFCSErrors) + }, *p = hw_stats; + u64 *stats = (u64 *) &mac->stats; + unsigned int i; + + for (i = 0; i < ARRAY_SIZE(hw_stats); i++) { + u32 val; - /* Rx stats */ - RMON_UPDATE(mac, RxOctetsTotalOK, RxOctetsOK); - RMON_UPDATE(mac, RxOctetsBad, RxOctetsBad); - RMON_UPDATE(mac, RxUCPkts, RxUnicastFramesOK); - RMON_UPDATE(mac, RxMCPkts, RxMulticastFramesOK); - RMON_UPDATE(mac, RxBCPkts, RxBroadcastFramesOK); - RMON_UPDATE(mac, RxJumboPkts, RxJumboFramesOK); - RMON_UPDATE(mac, RxFCSErrors, RxFCSErrors); - RMON_UPDATE(mac, RxAlignErrors, RxAlignErrors); - RMON_UPDATE(mac, RxLongErrors, RxFrameTooLongErrors); - RMON_UPDATE(mac, RxVeryLongErrors, RxFrameTooLongErrors); - RMON_UPDATE(mac, RxPauseMacControlCounter, RxPauseFrames); - RMON_UPDATE(mac, RxDataErrors, RxDataErrors); - RMON_UPDATE(mac, RxJabberErrors, RxJabberErrors); - RMON_UPDATE(mac, RxRuntErrors, RxRuntErrors); - RMON_UPDATE(mac, RxShortErrors, RxRuntErrors); - RMON_UPDATE(mac, RxSequenceErrors, RxSequenceErrors); - RMON_UPDATE(mac, RxSymbolErrors, RxSymbolErrors); - - /* Tx stats (skip collision stats as we are full-duplex only) */ - RMON_UPDATE(mac, TxOctetsTotalOK, TxOctetsOK); - RMON_UPDATE(mac, TxOctetsBad, TxOctetsBad); - RMON_UPDATE(mac, TxUCPkts, TxUnicastFramesOK); - RMON_UPDATE(mac, TxMCPkts, TxMulticastFramesOK); - RMON_UPDATE(mac, TxBCPkts, TxBroadcastFramesOK); - RMON_UPDATE(mac, TxJumboPkts, TxJumboFramesOK); - RMON_UPDATE(mac, TxPauseFrames, TxPauseFrames); - RMON_UPDATE(mac, TxExcessiveLengthDrop, TxLengthErrors); - RMON_UPDATE(mac, TxUnderrun, TxUnderrun); - RMON_UPDATE(mac, TxCRCErrors, TxFCSErrors); + t1_tpi_read(mac->adapter, MACREG(mac, p->reg), &val); + stats[p->offset] += val; + } } /* No-op interrupt operation as this MAC does not support interrupts */ @@ -273,7 +286,8 @@ static int mac_set_rx_mode(struct cmac * static int mac_set_mtu(struct cmac *mac, int mtu) { /* MAX_FRAME_SIZE inludes header + FCS, mtu doesn't */ - if (mtu > (MAX_FRAME_SIZE - 14 - 4)) return -EINVAL; + if (mtu > (MAX_FRAME_SIZE - 14 - 4)) + return -EINVAL; t1_tpi_write(mac->adapter, MACREG(mac, REG_MAX_FRAME_SIZE), mtu + 14 + 4); return 0; @@ -357,8 +371,8 @@ static void enable_port(struct cmac *mac val |= (1 << index); t1_tpi_write(adapter, REG_PORT_ENABLE, val); - index <<= 2; - if (is_T2(adapter)) { + index <<= 2; + if (is_T2(adapter)) { /* T204: set the Fifo water level & threshold */ t1_tpi_write(adapter, RX_FIFO_HIGH_WATERMARK_BASE + index, 0x740); t1_tpi_write(adapter, RX_FIFO_LOW_WATERMARK_BASE + index, 0x730); @@ -389,6 +403,10 @@ static int mac_disable(struct cmac *mac, return 0; } +#define RMON_UPDATE(mac, name, stat_name) \ + t1_tpi_read((mac)->adapter, MACREG(mac, REG_##name), &val); \ + (mac)->stats.stat_name += val; + /* * This function is called periodically to accumulate the current values of the * RMON counters into the port statistics. Since the counters are only 32 bits @@ -460,10 +478,12 @@ static struct cmac *ixf1010_mac_create(a struct cmac *mac; u32 val; - if (index > 9) return NULL; + if (index > 9) + return NULL; mac = kzalloc(sizeof(*mac) + sizeof(cmac_instance), GFP_KERNEL); - if (!mac) return NULL; + if (!mac) + return NULL; mac->ops = &ixf1010_ops; mac->instance = (cmac_instance *)(mac + 1); diff --git a/drivers/net/chelsio/mv88e1xxx.c b/drivers/net/chelsio/mv88e1xxx.c index 28ac93f..5867e3b 100644 --- a/drivers/net/chelsio/mv88e1xxx.c +++ b/drivers/net/chelsio/mv88e1xxx.c @@ -73,9 +73,8 @@ static int mv88e1xxx_interrupt_enable(st t1_tpi_read(cphy->adapter, A_ELMER0_INT_ENABLE, &elmer); elmer |= ELMER0_GP_BIT1; - if (is_T2(cphy->adapter)) { - elmer |= ELMER0_GP_BIT2|ELMER0_GP_BIT3|ELMER0_GP_BIT4; - } + if (is_T2(cphy->adapter)) + elmer |= ELMER0_GP_BIT2 | ELMER0_GP_BIT3 | ELMER0_GP_BIT4; t1_tpi_write(cphy->adapter, A_ELMER0_INT_ENABLE, elmer); } return 0; @@ -92,9 +91,8 @@ static int mv88e1xxx_interrupt_disable(s t1_tpi_read(cphy->adapter, A_ELMER0_INT_ENABLE, &elmer); elmer &= ~ELMER0_GP_BIT1; - if (is_T2(cphy->adapter)) { + if (is_T2(cphy->adapter)) elmer &= ~(ELMER0_GP_BIT2|ELMER0_GP_BIT3|ELMER0_GP_BIT4); - } t1_tpi_write(cphy->adapter, A_ELMER0_INT_ENABLE, elmer); } return 0; @@ -112,9 +110,8 @@ static int mv88e1xxx_interrupt_clear(str if (t1_is_asic(cphy->adapter)) { t1_tpi_read(cphy->adapter, A_ELMER0_INT_CAUSE, &elmer); elmer |= ELMER0_GP_BIT1; - if (is_T2(cphy->adapter)) { + if (is_T2(cphy->adapter)) elmer |= ELMER0_GP_BIT2|ELMER0_GP_BIT3|ELMER0_GP_BIT4; - } t1_tpi_write(cphy->adapter, A_ELMER0_INT_CAUSE, elmer); } return 0; @@ -300,7 +297,7 @@ static int mv88e1xxx_interrupt_handler(s /* * Loop until cause reads zero. Need to handle bouncing interrupts. - */ + */ while (1) { u32 cause; @@ -308,15 +305,16 @@ static int mv88e1xxx_interrupt_handler(s MV88E1XXX_INTERRUPT_STATUS_REGISTER, &cause); cause &= INTR_ENABLE_MASK; - if (!cause) break; + if (!cause) + break; if (cause & MV88E1XXX_INTR_LINK_CHNG) { (void) simple_mdio_read(cphy, MV88E1XXX_SPECIFIC_STATUS_REGISTER, &status); - if (status & MV88E1XXX_INTR_LINK_CHNG) { + if (status & MV88E1XXX_INTR_LINK_CHNG) cphy->state |= PHY_LINK_UP; - } else { + else { cphy->state &= ~PHY_LINK_UP; if (cphy->state & PHY_AUTONEG_EN) cphy->state &= ~PHY_AUTONEG_RDY; @@ -360,7 +358,8 @@ static struct cphy *mv88e1xxx_phy_create { struct cphy *cphy = kzalloc(sizeof(*cphy), GFP_KERNEL); - if (!cphy) return NULL; + if (!cphy) + return NULL; cphy_init(cphy, adapter, phy_addr, &mv88e1xxx_ops, mdio_ops); @@ -377,11 +376,11 @@ static struct cphy *mv88e1xxx_phy_create } (void) mv88e1xxx_downshift_set(cphy, 1); /* Enable downshift */ - /* LED */ + /* LED */ if (is_T2(adapter)) { (void) simple_mdio_write(cphy, MV88E1XXX_LED_CONTROL_REGISTER, 0x1); - } + } return cphy; } diff --git a/drivers/net/chelsio/my3126.c b/drivers/net/chelsio/my3126.c index 82fed1d..87dde3e 100644 --- a/drivers/net/chelsio/my3126.c +++ b/drivers/net/chelsio/my3126.c @@ -10,25 +10,25 @@ static int my3126_reset(struct cphy *cph * This can be done through registers. It is not required since * a full chip reset is used. */ - return (0); + return 0; } static int my3126_interrupt_enable(struct cphy *cphy) { schedule_delayed_work(&cphy->phy_update, HZ/30); t1_tpi_read(cphy->adapter, A_ELMER0_GPO, &cphy->elmer_gpo); - return (0); + return 0; } static int my3126_interrupt_disable(struct cphy *cphy) { cancel_rearming_delayed_work(&cphy->phy_update); - return (0); + return 0; } static int my3126_interrupt_clear(struct cphy *cphy) { - return (0); + return 0; } #define OFFSET(REG_ADDR) (REG_ADDR << 2) @@ -102,7 +102,7 @@ static void my3216_poll(struct work_stru static int my3126_set_loopback(struct cphy *cphy, int on) { - return (0); + return 0; } /* To check the activity LED */ @@ -146,7 +146,7 @@ static int my3126_get_link_status(struct if (fc) *fc = PAUSE_RX | PAUSE_TX; - return (0); + return 0; } static void my3126_destroy(struct cphy *cphy) @@ -177,7 +177,7 @@ static struct cphy *my3126_phy_create(ad INIT_DELAYED_WORK(&cphy->phy_update, my3216_poll); cphy->bmsr = 0; - return (cphy); + return cphy; } /* Chip Reset */ @@ -198,7 +198,7 @@ static int my3126_phy_reset(adapter_t * val |= 0x8000; t1_tpi_write(adapter, A_ELMER0_GPO, val); udelay(100); - return (0); + return 0; } struct gphy t1_my3126_ops = { diff --git a/drivers/net/chelsio/pm3393.c b/drivers/net/chelsio/pm3393.c index 63cabeb..69129ed 100644 --- a/drivers/net/chelsio/pm3393.c +++ b/drivers/net/chelsio/pm3393.c @@ -446,17 +446,51 @@ static void pm3393_rmon_update(struct ad *val += 1ull << 40; } -#define RMON_UPDATE(mac, name, stat_name) \ - pm3393_rmon_update((mac)->adapter, OFFSET(name), \ - &(mac)->stats.stat_name, \ - (ro &((name - SUNI1x10GEXP_REG_MSTAT_COUNTER_0_LOW) >> 2))) - - static const struct cmac_statistics *pm3393_update_statistics(struct cmac *mac, int flag) { - u64 ro; - u32 val0, val1, val2, val3; + static struct { + unsigned int reg; + unsigned int offset; + } hw_stats [] = { + +#define HW_STAT(name, stat_name) \ + { name, (&((struct cmac_statistics *)NULL)->stat_name) - (u64 *)NULL } + + /* Rx stats */ + HW_STAT(RxOctetsReceivedOK, RxOctetsOK), + HW_STAT(RxUnicastFramesReceivedOK, RxUnicastFramesOK), + HW_STAT(RxMulticastFramesReceivedOK, RxMulticastFramesOK), + HW_STAT(RxBroadcastFramesReceivedOK, RxBroadcastFramesOK), + HW_STAT(RxPAUSEMACCtrlFramesReceived, RxPauseFrames), + HW_STAT(RxFrameCheckSequenceErrors, RxFCSErrors), + HW_STAT(RxFramesLostDueToInternalMACErrors, + RxInternalMACRcvError), + HW_STAT(RxSymbolErrors, RxSymbolErrors), + HW_STAT(RxInRangeLengthErrors, RxInRangeLengthErrors), + HW_STAT(RxFramesTooLongErrors , RxFrameTooLongErrors), + HW_STAT(RxJabbers, RxJabberErrors), + HW_STAT(RxFragments, RxRuntErrors), + HW_STAT(RxUndersizedFrames, RxRuntErrors), + HW_STAT(RxJumboFramesReceivedOK, RxJumboFramesOK), + HW_STAT(RxJumboOctetsReceivedOK, RxJumboOctetsOK), + + /* Tx stats */ + HW_STAT(TxOctetsTransmittedOK, TxOctetsOK), + HW_STAT(TxFramesLostDueToInternalMACTransmissionError, + TxInternalMACXmitError), + HW_STAT(TxTransmitSystemError, TxFCSErrors), + HW_STAT(TxUnicastFramesTransmittedOK, TxUnicastFramesOK), + HW_STAT(TxMulticastFramesTransmittedOK, TxMulticastFramesOK), + HW_STAT(TxBroadcastFramesTransmittedOK, TxBroadcastFramesOK), + HW_STAT(TxPAUSEMACCtrlFramesTransmitted, TxPauseFrames), + HW_STAT(TxJumboFramesReceivedOK, TxJumboFramesOK), + HW_STAT(TxJumboOctetsReceivedOK, TxJumboOctetsOK) + }, *p = hw_stats; + u64 ro; + u32 val0, val1, val2, val3; + u64 *stats = (u64 *) &mac->stats; + unsigned int i; /* Snap the counters */ pmwrite(mac, SUNI1x10GEXP_REG_MSTAT_CONTROL, @@ -470,35 +504,14 @@ static const struct cmac_statistics *pm3 ro = ((u64)val0 & 0xffff) | (((u64)val1 & 0xffff) << 16) | (((u64)val2 & 0xffff) << 32) | (((u64)val3 & 0xffff) << 48); - /* Rx stats */ - RMON_UPDATE(mac, RxOctetsReceivedOK, RxOctetsOK); - RMON_UPDATE(mac, RxUnicastFramesReceivedOK, RxUnicastFramesOK); - RMON_UPDATE(mac, RxMulticastFramesReceivedOK, RxMulticastFramesOK); - RMON_UPDATE(mac, RxBroadcastFramesReceivedOK, RxBroadcastFramesOK); - RMON_UPDATE(mac, RxPAUSEMACCtrlFramesReceived, RxPauseFrames); - RMON_UPDATE(mac, RxFrameCheckSequenceErrors, RxFCSErrors); - RMON_UPDATE(mac, RxFramesLostDueToInternalMACErrors, - RxInternalMACRcvError); - RMON_UPDATE(mac, RxSymbolErrors, RxSymbolErrors); - RMON_UPDATE(mac, RxInRangeLengthErrors, RxInRangeLengthErrors); - RMON_UPDATE(mac, RxFramesTooLongErrors , RxFrameTooLongErrors); - RMON_UPDATE(mac, RxJabbers, RxJabberErrors); - RMON_UPDATE(mac, RxFragments, RxRuntErrors); - RMON_UPDATE(mac, RxUndersizedFrames, RxRuntErrors); - RMON_UPDATE(mac, RxJumboFramesReceivedOK, RxJumboFramesOK); - RMON_UPDATE(mac, RxJumboOctetsReceivedOK, RxJumboOctetsOK); - - /* Tx stats */ - RMON_UPDATE(mac, TxOctetsTransmittedOK, TxOctetsOK); - RMON_UPDATE(mac, TxFramesLostDueToInternalMACTransmissionError, - TxInternalMACXmitError); - RMON_UPDATE(mac, TxTransmitSystemError, TxFCSErrors); - RMON_UPDATE(mac, TxUnicastFramesTransmittedOK, TxUnicastFramesOK); - RMON_UPDATE(mac, TxMulticastFramesTransmittedOK, TxMulticastFramesOK); - RMON_UPDATE(mac, TxBroadcastFramesTransmittedOK, TxBroadcastFramesOK); - RMON_UPDATE(mac, TxPAUSEMACCtrlFramesTransmitted, TxPauseFrames); - RMON_UPDATE(mac, TxJumboFramesReceivedOK, TxJumboFramesOK); - RMON_UPDATE(mac, TxJumboOctetsReceivedOK, TxJumboOctetsOK); + for (i = 0; i < ARRAY_SIZE(hw_stats); i++) { + unsigned reg = p->reg - SUNI1x10GEXP_REG_MSTAT_COUNTER_0_LOW; + + pm3393_rmon_update((mac)->adapter, OFFSET(p->reg), + stats + p->offset, ro & (reg >> 2)); + } + + return &mac->stats; } @@ -534,9 +547,9 @@ static int pm3393_macaddress_set(struct /* Store local copy */ memcpy(cmac->instance->mac_addr, ma, 6); - lo = ((u32) ma[1] << 8) | (u32) ma[0]; + lo = ((u32) ma[1] << 8) | (u32) ma[0]; mid = ((u32) ma[3] << 8) | (u32) ma[2]; - hi = ((u32) ma[5] << 8) | (u32) ma[4]; + hi = ((u32) ma[5] << 8) | (u32) ma[4]; /* Disable Rx/Tx MAC before configuring it. */ if (enabled) diff --git a/drivers/net/chelsio/sge.c b/drivers/net/chelsio/sge.c index 659cb22..89a6827 100644 --- a/drivers/net/chelsio/sge.c +++ b/drivers/net/chelsio/sge.c @@ -71,12 +71,9 @@ #define SGE_JUMBO_FREEL_SIZE 512 #define SGE_FREEL_REFILL_THRESH 16 #define SGE_RESPQ_E_N 1024 #define SGE_INTRTIMER_NRES 1000 -#define SGE_RX_COPY_THRES 256 #define SGE_RX_SM_BUF_SIZE 1536 #define SGE_TX_DESC_MAX_PLEN 16384 -# define SGE_RX_DROP_THRES 2 - #define SGE_RESPQ_REPLENISH_THRES (SGE_RESPQ_E_N / 4) /* @@ -85,10 +82,6 @@ #define SGE_RESPQ_REPLENISH_THRES (SGE_R */ #define TX_RECLAIM_PERIOD (HZ / 4) -#ifndef NET_IP_ALIGN -# define NET_IP_ALIGN 2 -#endif - #define M_CMD_LEN 0x7fffffff #define V_CMD_LEN(v) (v) #define G_CMD_LEN(v) ((v) & M_CMD_LEN) @@ -195,7 +188,7 @@ struct cmdQ { struct cmdQ_e *entries; /* HW command descriptor Q */ struct cmdQ_ce *centries; /* SW command context descriptor Q */ dma_addr_t dma_addr; /* DMA addr HW command descriptor Q */ - spinlock_t lock; /* Lock to protect cmdQ enqueuing */ + spinlock_t lock; /* Lock to protect cmdQ enqueuing */ }; struct freelQ { @@ -241,9 +234,9 @@ struct sched_port { /* Per T204 device */ struct sched { ktime_t last_updated; /* last time quotas were computed */ - unsigned int max_avail; /* max bits to be sent to any port */ - unsigned int port; /* port index (round robin ports) */ - unsigned int num; /* num skbs in per port queues */ + unsigned int max_avail; /* max bits to be sent to any port */ + unsigned int port; /* port index (round robin ports) */ + unsigned int num; /* num skbs in per port queues */ struct sched_port p[MAX_NPORTS]; struct tasklet_struct sched_tsk;/* tasklet used to run scheduler */ }; @@ -259,10 +252,10 @@ static void restart_sched(unsigned long) * contention. */ struct sge { - struct adapter *adapter; /* adapter backpointer */ + struct adapter *adapter; /* adapter backpointer */ struct net_device *netdev; /* netdevice backpointer */ - struct freelQ freelQ[SGE_FREELQ_N]; /* buffer free lists */ - struct respQ respQ; /* response Q */ + struct freelQ freelQ[SGE_FREELQ_N]; /* buffer free lists */ + struct respQ respQ; /* response Q */ unsigned long stopped_tx_queues; /* bitmap of suspended Tx queues */ unsigned int rx_pkt_pad; /* RX padding for L2 packets */ unsigned int jumbo_fl; /* jumbo freelist Q index */ @@ -460,7 +453,7 @@ static struct sk_buff *sched_skb(struct if (credits < MAX_SKB_FRAGS + 1) goto out; - again: +again: for (i = 0; i < MAX_NPORTS; i++) { s->port = ++s->port & (MAX_NPORTS - 1); skbq = &s->p[s->port].skbq; @@ -483,8 +476,8 @@ static struct sk_buff *sched_skb(struct if (update-- && sched_update_avail(sge)) goto again; - out: - /* If there are more pending skbs, we use the hardware to schedule us +out: + /* If there are more pending skbs, we use the hardware to schedule us * again. */ if (s->num && !skb) { @@ -575,11 +568,10 @@ static int alloc_rx_resources(struct sge q->size = p->freelQ_size[i]; q->dma_offset = sge->rx_pkt_pad ? 0 : NET_IP_ALIGN; size = sizeof(struct freelQ_e) * q->size; - q->entries = (struct freelQ_e *) - pci_alloc_consistent(pdev, size, &q->dma_addr); + q->entries = pci_alloc_consistent(pdev, size, &q->dma_addr); if (!q->entries) goto err_no_mem; - memset(q->entries, 0, size); + size = sizeof(struct freelQ_ce) * q->size; q->centries = kzalloc(size, GFP_KERNEL); if (!q->centries) @@ -613,11 +605,10 @@ static int alloc_rx_resources(struct sge sge->respQ.size = SGE_RESPQ_E_N; sge->respQ.credits = 0; size = sizeof(struct respQ_e) * sge->respQ.size; - sge->respQ.entries = (struct respQ_e *) + sge->respQ.entries = pci_alloc_consistent(pdev, size, &sge->respQ.dma_addr); if (!sge->respQ.entries) goto err_no_mem; - memset(sge->respQ.entries, 0, size); return 0; err_no_mem: @@ -637,20 +628,12 @@ static void free_cmdQ_buffers(struct sge q->in_use -= n; ce = &q->centries[cidx]; while (n--) { - if (q->sop) { - if (likely(pci_unmap_len(ce, dma_len))) { - pci_unmap_single(pdev, - pci_unmap_addr(ce, dma_addr), - pci_unmap_len(ce, dma_len), - PCI_DMA_TODEVICE); + if (likely(pci_unmap_len(ce, dma_len))) { + pci_unmap_single(pdev, pci_unmap_addr(ce, dma_addr), + pci_unmap_len(ce, dma_len), + PCI_DMA_TODEVICE); + if (q->sop) q->sop = 0; - } - } else { - if (likely(pci_unmap_len(ce, dma_len))) { - pci_unmap_page(pdev, pci_unmap_addr(ce, dma_addr), - pci_unmap_len(ce, dma_len), - PCI_DMA_TODEVICE); - } } if (ce->skb) { dev_kfree_skb_any(ce->skb); @@ -711,11 +694,10 @@ static int alloc_tx_resources(struct sge q->stop_thres = 0; spin_lock_init(&q->lock); size = sizeof(struct cmdQ_e) * q->size; - q->entries = (struct cmdQ_e *) - pci_alloc_consistent(pdev, size, &q->dma_addr); + q->entries = pci_alloc_consistent(pdev, size, &q->dma_addr); if (!q->entries) goto err_no_mem; - memset(q->entries, 0, size); + size = sizeof(struct cmdQ_ce) * q->size; q->centries = kzalloc(size, GFP_KERNEL); if (!q->centries) @@ -770,7 +752,7 @@ void t1_set_vlan_accel(struct adapter *a static void configure_sge(struct sge *sge, struct sge_params *p) { struct adapter *ap = sge->adapter; - + writel(0, ap->regs + A_SG_CONTROL); setup_ring_params(ap, sge->cmdQ[0].dma_addr, sge->cmdQ[0].size, A_SG_CMD0BASELWR, A_SG_CMD0BASEUPR, A_SG_CMD0SIZE); @@ -850,7 +832,6 @@ static void refill_free_list(struct sge struct freelQ_e *e = &q->entries[q->pidx]; unsigned int dma_len = q->rx_buffer_size - q->dma_offset; - while (q->credits < q->size) { struct sk_buff *skb; dma_addr_t mapping; @@ -862,6 +843,8 @@ static void refill_free_list(struct sge skb_reserve(skb, q->dma_offset); mapping = pci_map_single(pdev, skb->data, dma_len, PCI_DMA_FROMDEVICE); + skb_reserve(skb, sge->rx_pkt_pad); + ce->skb = skb; pci_unmap_addr_set(ce, dma_addr, mapping); pci_unmap_len_set(ce, dma_len, dma_len); @@ -881,7 +864,6 @@ static void refill_free_list(struct sge } q->credits++; } - } /* @@ -1041,6 +1023,10 @@ static void recycle_fl_buf(struct freelQ } } +static int copybreak __read_mostly = 256; +module_param(copybreak, int, 0); +MODULE_PARM_DESC(copybreak, "Receive copy threshold"); + /** * get_packet - return the next ingress packet buffer * @pdev: the PCI device that received the packet @@ -1060,45 +1046,42 @@ static void recycle_fl_buf(struct freelQ * be copied but there is no memory for the copy. */ static inline struct sk_buff *get_packet(struct pci_dev *pdev, - struct freelQ *fl, unsigned int len, - int dma_pad, int skb_pad, - unsigned int copy_thres, - unsigned int drop_thres) + struct freelQ *fl, unsigned int len) { struct sk_buff *skb; - struct freelQ_ce *ce = &fl->centries[fl->cidx]; + const struct freelQ_ce *ce = &fl->centries[fl->cidx]; - if (len < copy_thres) { - skb = alloc_skb(len + skb_pad, GFP_ATOMIC); - if (likely(skb != NULL)) { - skb_reserve(skb, skb_pad); - skb_put(skb, len); - pci_dma_sync_single_for_cpu(pdev, - pci_unmap_addr(ce, dma_addr), - pci_unmap_len(ce, dma_len), - PCI_DMA_FROMDEVICE); - memcpy(skb->data, ce->skb->data + dma_pad, len); - pci_dma_sync_single_for_device(pdev, - pci_unmap_addr(ce, dma_addr), - pci_unmap_len(ce, dma_len), - PCI_DMA_FROMDEVICE); - } else if (!drop_thres) + if (len < copybreak) { + skb = alloc_skb(len + 2, GFP_ATOMIC); + if (!skb) goto use_orig_buf; + skb_reserve(skb, 2); /* align IP header */ + skb_put(skb, len); + pci_dma_sync_single_for_cpu(pdev, + pci_unmap_addr(ce, dma_addr), + pci_unmap_len(ce, dma_len), + PCI_DMA_FROMDEVICE); + memcpy(skb->data, ce->skb->data, len); + pci_dma_sync_single_for_device(pdev, + pci_unmap_addr(ce, dma_addr), + pci_unmap_len(ce, dma_len), + PCI_DMA_FROMDEVICE); recycle_fl_buf(fl, fl->cidx); return skb; } - if (fl->credits < drop_thres) { +use_orig_buf: + if (fl->credits < 2) { recycle_fl_buf(fl, fl->cidx); return NULL; } -use_orig_buf: pci_unmap_single(pdev, pci_unmap_addr(ce, dma_addr), pci_unmap_len(ce, dma_len), PCI_DMA_FROMDEVICE); skb = ce->skb; - skb_reserve(skb, dma_pad); + prefetch(skb->data); + skb_put(skb, len); return skb; } @@ -1137,6 +1120,7 @@ static void unexpected_offload(struct ad static inline unsigned int compute_large_page_tx_descs(struct sk_buff *skb) { unsigned int count = 0; + if (PAGE_SIZE > SGE_TX_DESC_MAX_PLEN) { unsigned int nfrags = skb_shinfo(skb)->nr_frags; unsigned int i, len = skb->len - skb->data_len; @@ -1343,7 +1327,7 @@ static void restart_sched(unsigned long while ((skb = sched_skb(sge, NULL, credits)) != NULL) { unsigned int genbit, pidx, count; count = 1 + skb_shinfo(skb)->nr_frags; - count += compute_large_page_tx_descs(skb); + count += compute_large_page_tx_descs(skb); q->in_use += count; genbit = q->genbit; pidx = q->pidx; @@ -1375,27 +1359,25 @@ static void restart_sched(unsigned long * * Process an ingress ethernet pakcet and deliver it to the stack. */ -static int sge_rx(struct sge *sge, struct freelQ *fl, unsigned int len) +static void sge_rx(struct sge *sge, struct freelQ *fl, unsigned int len) { struct sk_buff *skb; - struct cpl_rx_pkt *p; + const struct cpl_rx_pkt *p; struct adapter *adapter = sge->adapter; struct sge_port_stats *st; - skb = get_packet(adapter->pdev, fl, len - sge->rx_pkt_pad, - sge->rx_pkt_pad, 2, SGE_RX_COPY_THRES, - SGE_RX_DROP_THRES); + skb = get_packet(adapter->pdev, fl, len - sge->rx_pkt_pad); if (unlikely(!skb)) { sge->stats.rx_drops++; - return 0; + return; } - p = (struct cpl_rx_pkt *)skb->data; - skb_pull(skb, sizeof(*p)); + p = (const struct cpl_rx_pkt *) skb->data; if (p->iff >= adapter->params.nports) { kfree_skb(skb); - return 0; + return; } + __skb_pull(skb, sizeof(*p)); skb->dev = adapter->port[p->iff].dev; skb->dev->last_rx = jiffies; @@ -1427,7 +1409,6 @@ #else netif_rx(skb); #endif } - return 0; } /* @@ -1448,29 +1429,28 @@ static inline int enough_free_Tx_descs(c static void restart_tx_queues(struct sge *sge) { struct adapter *adap = sge->adapter; + int i; - if (enough_free_Tx_descs(&sge->cmdQ[0])) { - int i; + if (!enough_free_Tx_descs(&sge->cmdQ[0])) + return; - for_each_port(adap, i) { - struct net_device *nd = adap->port[i].dev; + for_each_port(adap, i) { + struct net_device *nd = adap->port[i].dev; - if (test_and_clear_bit(nd->if_port, - &sge->stopped_tx_queues) && - netif_running(nd)) { - sge->stats.cmdQ_restarted[2]++; - netif_wake_queue(nd); - } + if (test_and_clear_bit(nd->if_port, &sge->stopped_tx_queues) && + netif_running(nd)) { + sge->stats.cmdQ_restarted[2]++; + netif_wake_queue(nd); } } } /* - * update_tx_info is called from the interrupt handler/NAPI to return cmdQ0 + * update_tx_info is called from the interrupt handler/NAPI to return cmdQ0 * information. */ -static unsigned int update_tx_info(struct adapter *adapter, - unsigned int flags, +static unsigned int update_tx_info(struct adapter *adapter, + unsigned int flags, unsigned int pr0) { struct sge *sge = adapter->sge; @@ -1510,29 +1490,30 @@ static int process_responses(struct adap struct sge *sge = adapter->sge; struct respQ *q = &sge->respQ; struct respQ_e *e = &q->entries[q->cidx]; - int budget_left = budget; + int done = 0; unsigned int flags = 0; unsigned int cmdq_processed[SGE_CMDQ_N] = {0, 0}; - - while (likely(budget_left && e->GenerationBit == q->genbit)) { + while (done < budget && e->GenerationBit == q->genbit) { flags |= e->Qsleeping; - + cmdq_processed[0] += e->Cmdq0CreditReturn; cmdq_processed[1] += e->Cmdq1CreditReturn; - + /* We batch updates to the TX side to avoid cacheline * ping-pong of TX state information on MP where the sender * might run on a different CPU than this function... */ - if (unlikely(flags & F_CMDQ0_ENABLE || cmdq_processed[0] > 64)) { + if (unlikely((flags & F_CMDQ0_ENABLE) || cmdq_processed[0] > 64)) { flags = update_tx_info(adapter, flags, cmdq_processed[0]); cmdq_processed[0] = 0; } + if (unlikely(cmdq_processed[1] > 16)) { sge->cmdQ[1].processed += cmdq_processed[1]; cmdq_processed[1] = 0; } + if (likely(e->DataValid)) { struct freelQ *fl = &sge->freelQ[e->FreelistQid]; @@ -1542,12 +1523,16 @@ static int process_responses(struct adap else sge_rx(sge, fl, e->BufferLength); + ++done; + /* * Note: this depends on each packet consuming a * single free-list buffer; cf. the BUG above. */ if (++fl->cidx == fl->size) fl->cidx = 0; + prefetch(fl->centries[fl->cidx].skb); + if (unlikely(--fl->credits < fl->size - SGE_FREEL_REFILL_THRESH)) refill_free_list(sge, fl); @@ -1566,14 +1551,20 @@ static int process_responses(struct adap writel(q->credits, adapter->regs + A_SG_RSPQUEUECREDIT); q->credits = 0; } - --budget_left; } - flags = update_tx_info(adapter, flags, cmdq_processed[0]); + flags = update_tx_info(adapter, flags, cmdq_processed[0]); sge->cmdQ[1].processed += cmdq_processed[1]; - budget -= budget_left; - return budget; + return done; +} + +static inline int responses_pending(const struct adapter *adapter) +{ + const struct respQ *Q = &adapter->sge->respQ; + const struct respQ_e *e = &Q->entries[Q->cidx]; + + return (e->GenerationBit == Q->genbit); } #ifdef CONFIG_CHELSIO_T1_NAPI @@ -1585,19 +1576,25 @@ #ifdef CONFIG_CHELSIO_T1_NAPI * which the caller must ensure is a valid pure response. Returns 1 if it * encounters a valid data-carrying response, 0 otherwise. */ -static int process_pure_responses(struct adapter *adapter, struct respQ_e *e) +static int process_pure_responses(struct adapter *adapter) { struct sge *sge = adapter->sge; struct respQ *q = &sge->respQ; + struct respQ_e *e = &q->entries[q->cidx]; + const struct freelQ *fl = &sge->freelQ[e->FreelistQid]; unsigned int flags = 0; unsigned int cmdq_processed[SGE_CMDQ_N] = {0, 0}; + prefetch(fl->centries[fl->cidx].skb); + if (e->DataValid) + return 1; + do { flags |= e->Qsleeping; cmdq_processed[0] += e->Cmdq0CreditReturn; cmdq_processed[1] += e->Cmdq1CreditReturn; - + e++; if (unlikely(++q->cidx == q->size)) { q->cidx = 0; @@ -1613,7 +1610,7 @@ static int process_pure_responses(struct sge->stats.pure_rsps++; } while (e->GenerationBit == q->genbit && !e->DataValid); - flags = update_tx_info(adapter, flags, cmdq_processed[0]); + flags = update_tx_info(adapter, flags, cmdq_processed[0]); sge->cmdQ[1].processed += cmdq_processed[1]; return e->GenerationBit == q->genbit; @@ -1627,23 +1624,20 @@ static int process_pure_responses(struct int t1_poll(struct net_device *dev, int *budget) { struct adapter *adapter = dev->priv; - int effective_budget = min(*budget, dev->quota); - int work_done = process_responses(adapter, effective_budget); + int work_done; + work_done = process_responses(adapter, min(*budget, dev->quota)); *budget -= work_done; dev->quota -= work_done; - if (work_done >= effective_budget) + if (unlikely(responses_pending(adapter))) return 1; - spin_lock_irq(&adapter->async_lock); - __netif_rx_complete(dev); + netif_rx_complete(dev); writel(adapter->sge->respQ.cidx, adapter->regs + A_SG_SLEEPING); - writel(adapter->slow_intr_mask | F_PL_INTR_SGE_DATA, - adapter->regs + A_PL_ENABLE); - spin_unlock_irq(&adapter->async_lock); return 0; + } /* @@ -1652,44 +1646,33 @@ int t1_poll(struct net_device *dev, int irqreturn_t t1_interrupt(int irq, void *data) { struct adapter *adapter = data; - struct net_device *dev = adapter->sge->netdev; struct sge *sge = adapter->sge; - u32 cause; - int handled = 0; + int handled; - cause = readl(adapter->regs + A_PL_CAUSE); - if (cause == 0 || cause == ~0) - return IRQ_NONE; + if (likely(responses_pending(adapter))) { + struct net_device *dev = sge->netdev; - spin_lock(&adapter->async_lock); - if (cause & F_PL_INTR_SGE_DATA) { - struct respQ *q = &adapter->sge->respQ; - struct respQ_e *e = &q->entries[q->cidx]; - - handled = 1; - writel(F_PL_INTR_SGE_DATA, adapter->regs + A_PL_CAUSE); - - if (e->GenerationBit == q->genbit && - __netif_rx_schedule_prep(dev)) { - if (e->DataValid || process_pure_responses(adapter, e)) { - /* mask off data IRQ */ - writel(adapter->slow_intr_mask, - adapter->regs + A_PL_ENABLE); - __netif_rx_schedule(sge->netdev); - goto unlock; - } - /* no data, no NAPI needed */ - netif_poll_enable(dev); + writel(F_PL_INTR_SGE_DATA, adapter->regs + A_PL_CAUSE); + if (__netif_rx_schedule_prep(dev)) { + if (process_pure_responses(adapter)) + __netif_rx_schedule(dev); + else { + /* no data, no NAPI needed */ + writel(sge->respQ.cidx, adapter->regs + A_SG_SLEEPING); + netif_poll_enable(dev); /* undo schedule_prep */ + } } - writel(q->cidx, adapter->regs + A_SG_SLEEPING); - } else - handled = t1_slow_intr_handler(adapter); + return IRQ_HANDLED; + } + + spin_lock(&adapter->async_lock); + handled = t1_slow_intr_handler(adapter); + spin_unlock(&adapter->async_lock); if (!handled) sge->stats.unhandled_irqs++; -unlock: - spin_unlock(&adapter->async_lock); + return IRQ_RETVAL(handled != 0); } @@ -1712,17 +1695,13 @@ #else irqreturn_t t1_interrupt(int irq, void *cookie) { int work_done; - struct respQ_e *e; struct adapter *adapter = cookie; - struct respQ *Q = &adapter->sge->respQ; spin_lock(&adapter->async_lock); - e = &Q->entries[Q->cidx]; - prefetch(e); writel(F_PL_INTR_SGE_DATA, adapter->regs + A_PL_CAUSE); - if (likely(e->GenerationBit == Q->genbit)) + if (likely(responses_pending(adapter))) work_done = process_responses(adapter, -1); else work_done = t1_slow_intr_handler(adapter); @@ -1796,7 +1775,7 @@ static int t1_sge_tx(struct sk_buff *skb * through the scheduler. */ if (sge->tx_sched && !qid && skb->dev) { - use_sched: +use_sched: use_sched_skb = 1; /* Note that the scheduler might return a different skb than * the one passed in. @@ -1900,7 +1879,7 @@ int t1_start_xmit(struct sk_buff *skb, s cpl = (struct cpl_tx_pkt *)hdr; } else { /* - * Packets shorter than ETH_HLEN can break the MAC, drop them + * Packets shorter than ETH_HLEN can break the MAC, drop them * early. Also, we may get oversized packets because some * parts of the kernel don't handle our unusual hard_header_len * right, drop those too. @@ -1984,9 +1963,9 @@ send: * then silently discard to avoid leak. */ if (unlikely(ret != NETDEV_TX_OK && skb != orig_skb)) { - dev_kfree_skb_any(skb); + dev_kfree_skb_any(skb); ret = NETDEV_TX_OK; - } + } return ret; } @@ -2099,31 +2078,35 @@ static void espibug_workaround_t204(unsi if (adapter->open_device_map & PORT_MASK) { int i; - if (t1_espi_get_mon_t204(adapter, &(seop[0]), 0) < 0) { + + if (t1_espi_get_mon_t204(adapter, &(seop[0]), 0) < 0) return; - } + for (i = 0; i < nports; i++) { - struct sk_buff *skb = sge->espibug_skb[i]; - if ( (netif_running(adapter->port[i].dev)) && - !(netif_queue_stopped(adapter->port[i].dev)) && - (seop[i] && ((seop[i] & 0xfff) == 0)) && - skb ) { - if (!skb->cb[0]) { - u8 ch_mac_addr[ETH_ALEN] = - {0x0, 0x7, 0x43, 0x0, 0x0, 0x0}; - memcpy(skb->data + sizeof(struct cpl_tx_pkt), - ch_mac_addr, ETH_ALEN); - memcpy(skb->data + skb->len - 10, - ch_mac_addr, ETH_ALEN); - skb->cb[0] = 0xff; - } - - /* bump the reference count to avoid freeing of - * the skb once the DMA has completed. - */ - skb = skb_get(skb); - t1_sge_tx(skb, adapter, 0, adapter->port[i].dev); + struct sk_buff *skb = sge->espibug_skb[i]; + + if (!netif_running(adapter->port[i].dev) || + netif_queue_stopped(adapter->port[i].dev) || + !seop[i] || ((seop[i] & 0xfff) != 0) || !skb) + continue; + + if (!skb->cb[0]) { + u8 ch_mac_addr[ETH_ALEN] = { + 0x0, 0x7, 0x43, 0x0, 0x0, 0x0 + }; + + memcpy(skb->data + sizeof(struct cpl_tx_pkt), + ch_mac_addr, ETH_ALEN); + memcpy(skb->data + skb->len - 10, + ch_mac_addr, ETH_ALEN); + skb->cb[0] = 0xff; } + + /* bump the reference count to avoid freeing of + * the skb once the DMA has completed. + */ + skb = skb_get(skb); + t1_sge_tx(skb, adapter, 0, adapter->port[i].dev); } } mod_timer(&sge->espibug_timer, jiffies + sge->espibug_timeout); @@ -2192,9 +2175,8 @@ struct sge * __devinit t1_sge_create(str if (adapter->params.nports > 1) { tx_sched_init(sge); sge->espibug_timer.function = espibug_workaround_t204; - } else { + } else sge->espibug_timer.function = espibug_workaround; - } sge->espibug_timer.data = (unsigned long)sge->adapter; sge->espibug_timeout = 1; @@ -2202,7 +2184,7 @@ struct sge * __devinit t1_sge_create(str if (adapter->params.nports > 1) sge->espibug_timeout = HZ/100; } - + p->cmdQ_size[0] = SGE_CMDQ0_E_N; p->cmdQ_size[1] = SGE_CMDQ1_E_N; diff --git a/drivers/net/chelsio/subr.c b/drivers/net/chelsio/subr.c index 22ed9a3..c2522cd 100644 --- a/drivers/net/chelsio/subr.c +++ b/drivers/net/chelsio/subr.c @@ -223,13 +223,13 @@ static int fpga_slow_intr(adapter_t *ada t1_sge_intr_error_handler(adapter->sge); if (cause & FPGA_PCIX_INTERRUPT_GMAC) - fpga_phy_intr_handler(adapter); + fpga_phy_intr_handler(adapter); if (cause & FPGA_PCIX_INTERRUPT_TP) { - /* + /* * FPGA doesn't support MC4 interrupts and it requires * this odd layer of indirection for MC5. - */ + */ u32 tp_cause = readl(adapter->regs + FPGA_TP_ADDR_INTERRUPT_CAUSE); /* Clear TP interrupt */ @@ -262,8 +262,7 @@ static int mi1_wait_until_ready(adapter_ udelay(10); } while (busy && --attempts); if (busy) - CH_ALERT("%s: MDIO operation timed out\n", - adapter->name); + CH_ALERT("%s: MDIO operation timed out\n", adapter->name); return busy; } @@ -605,22 +604,23 @@ int t1_elmer0_ext_intr_handler(adapter_t switch (board_info(adapter)->board) { #ifdef CONFIG_CHELSIO_T1_1G - case CHBT_BOARD_CHT204: - case CHBT_BOARD_CHT204E: - case CHBT_BOARD_CHN204: - case CHBT_BOARD_CHT204V: { - int i, port_bit; + case CHBT_BOARD_CHT204: + case CHBT_BOARD_CHT204E: + case CHBT_BOARD_CHN204: + case CHBT_BOARD_CHT204V: { + int i, port_bit; for_each_port(adapter, i) { port_bit = i + 1; - if (!(cause & (1 << port_bit))) continue; + if (!(cause & (1 << port_bit))) + continue; - phy = adapter->port[i].phy; + phy = adapter->port[i].phy; phy_cause = phy->ops->interrupt_handler(phy); if (phy_cause & cphy_cause_link_change) t1_link_changed(adapter, i); } - break; - } + break; + } case CHBT_BOARD_CHT101: if (cause & ELMER0_GP_BIT1) { /* Marvell 88E1111 interrupt */ phy = adapter->port[0].phy; @@ -631,13 +631,13 @@ #ifdef CONFIG_CHELSIO_T1_1G break; case CHBT_BOARD_7500: { int p; - /* + /* * Elmer0's interrupt cause isn't useful here because there is * only one bit that can be set for all 4 ports. This means * we are forced to check every PHY's interrupt status * register to see who initiated the interrupt. - */ - for_each_port(adapter, p) { + */ + for_each_port(adapter, p) { phy = adapter->port[p].phy; phy_cause = phy->ops->interrupt_handler(phy); if (phy_cause & cphy_cause_link_change) @@ -658,7 +658,7 @@ #endif break; case CHBT_BOARD_8000: case CHBT_BOARD_CHT110: - CH_DBG(adapter, INTR, "External interrupt cause 0x%x\n", + CH_DBG(adapter, INTR, "External interrupt cause 0x%x\n", cause); if (cause & ELMER0_GP_BIT1) { /* PMC3393 INTB */ struct cmac *mac = adapter->port[0].mac; @@ -670,9 +670,9 @@ #endif t1_tpi_read(adapter, A_ELMER0_GPI_STAT, &mod_detect); - CH_MSG(adapter, INFO, LINK, "XPAK %s\n", + CH_MSG(adapter, INFO, LINK, "XPAK %s\n", mod_detect ? "removed" : "inserted"); - } + } break; #ifdef CONFIG_CHELSIO_T1_COUGAR case CHBT_BOARD_COUGAR: @@ -688,7 +688,8 @@ #ifdef CONFIG_CHELSIO_T1_COUGAR for_each_port(adapter, i) { port_bit = i ? i + 1 : 0; - if (!(cause & (1 << port_bit))) continue; + if (!(cause & (1 << port_bit))) + continue; phy = adapter->port[i].phy; phy_cause = phy->ops->interrupt_handler(phy); @@ -755,7 +756,7 @@ void t1_interrupts_disable(adapter_t* ad /* Disable PCIX & external chip interrupts. */ if (t1_is_asic(adapter)) - writel(0, adapter->regs + A_PL_ENABLE); + writel(0, adapter->regs + A_PL_ENABLE); /* PCI-X interrupts */ pci_write_config_dword(adapter->pdev, A_PCICFG_INTR_ENABLE, 0); @@ -830,11 +831,11 @@ #endif /* Power sequencing is a work-around for Intel's XPAKs. */ static void power_sequence_xpak(adapter_t* adapter) { - u32 mod_detect; - u32 gpo; + u32 mod_detect; + u32 gpo; - /* Check for XPAK */ - t1_tpi_read(adapter, A_ELMER0_GPI_STAT, &mod_detect); + /* Check for XPAK */ + t1_tpi_read(adapter, A_ELMER0_GPI_STAT, &mod_detect); if (!(ELMER0_GP_BIT5 & mod_detect)) { /* XPAK is present */ t1_tpi_read(adapter, A_ELMER0_GPO, &gpo); @@ -877,31 +878,31 @@ static int board_init(adapter_t *adapter case CHBT_BOARD_N210: case CHBT_BOARD_CHT210: case CHBT_BOARD_COUGAR: - t1_tpi_par(adapter, 0xf); - t1_tpi_write(adapter, A_ELMER0_GPO, 0x800); + t1_tpi_par(adapter, 0xf); + t1_tpi_write(adapter, A_ELMER0_GPO, 0x800); break; case CHBT_BOARD_CHT110: - t1_tpi_par(adapter, 0xf); - t1_tpi_write(adapter, A_ELMER0_GPO, 0x1800); + t1_tpi_par(adapter, 0xf); + t1_tpi_write(adapter, A_ELMER0_GPO, 0x1800); - /* TBD XXX Might not need. This fixes a problem - * described in the Intel SR XPAK errata. - */ - power_sequence_xpak(adapter); + /* TBD XXX Might not need. This fixes a problem + * described in the Intel SR XPAK errata. + */ + power_sequence_xpak(adapter); break; #ifdef CONFIG_CHELSIO_T1_1G - case CHBT_BOARD_CHT204E: - /* add config space write here */ + case CHBT_BOARD_CHT204E: + /* add config space write here */ case CHBT_BOARD_CHT204: case CHBT_BOARD_CHT204V: case CHBT_BOARD_CHN204: - t1_tpi_par(adapter, 0xf); - t1_tpi_write(adapter, A_ELMER0_GPO, 0x804); - break; + t1_tpi_par(adapter, 0xf); + t1_tpi_write(adapter, A_ELMER0_GPO, 0x804); + break; case CHBT_BOARD_CHT101: case CHBT_BOARD_7500: - t1_tpi_par(adapter, 0xf); - t1_tpi_write(adapter, A_ELMER0_GPO, 0x1804); + t1_tpi_par(adapter, 0xf); + t1_tpi_write(adapter, A_ELMER0_GPO, 0x1804); break; #endif } @@ -941,7 +942,7 @@ #endif goto out_err; err = 0; - out_err: +out_err: return err; } @@ -983,7 +984,7 @@ void t1_free_sw_modules(adapter_t *adapt if (adapter->espi) t1_espi_destroy(adapter->espi); #ifdef CONFIG_CHELSIO_T1_COUGAR - if (adapter->cspi) + if (adapter->cspi) t1_cspi_destroy(adapter->cspi); #endif } @@ -1010,7 +1011,7 @@ #ifdef CONFIG_CHELSIO_T1_COUGAR CH_ERR("%s: CSPI initialization failed\n", adapter->name); goto error; - } + } #endif /* diff --git a/drivers/net/chelsio/tp.c b/drivers/net/chelsio/tp.c index 0ca0b6e..6222d58 100644 --- a/drivers/net/chelsio/tp.c +++ b/drivers/net/chelsio/tp.c @@ -17,39 +17,36 @@ #define DROP_PKTS_CNT 1 static void tp_init(adapter_t * ap, const struct tp_params *p, unsigned int tp_clk) { - if (t1_is_asic(ap)) { - u32 val; - - val = F_TP_IN_CSPI_CPL | F_TP_IN_CSPI_CHECK_IP_CSUM | - F_TP_IN_CSPI_CHECK_TCP_CSUM | F_TP_IN_ESPI_ETHERNET; - if (!p->pm_size) - val |= F_OFFLOAD_DISABLE; - else - val |= F_TP_IN_ESPI_CHECK_IP_CSUM | - F_TP_IN_ESPI_CHECK_TCP_CSUM; - writel(val, ap->regs + A_TP_IN_CONFIG); - writel(F_TP_OUT_CSPI_CPL | - F_TP_OUT_ESPI_ETHERNET | - F_TP_OUT_ESPI_GENERATE_IP_CSUM | - F_TP_OUT_ESPI_GENERATE_TCP_CSUM, - ap->regs + A_TP_OUT_CONFIG); - writel(V_IP_TTL(64) | - F_PATH_MTU /* IP DF bit */ | - V_5TUPLE_LOOKUP(p->use_5tuple_mode) | - V_SYN_COOKIE_PARAMETER(29), - ap->regs + A_TP_GLOBAL_CONFIG); - /* - * Enable pause frame deadlock prevention. - */ - if (is_T2(ap) && ap->params.nports > 1) { - u32 drop_ticks = DROP_MSEC * (tp_clk / 1000); - - writel(F_ENABLE_TX_DROP | F_ENABLE_TX_ERROR | - V_DROP_TICKS_CNT(drop_ticks) | - V_NUM_PKTS_DROPPED(DROP_PKTS_CNT), - ap->regs + A_TP_TX_DROP_CONFIG); - } + u32 val; + if (!t1_is_asic(ap)) + return; + + val = F_TP_IN_CSPI_CPL | F_TP_IN_CSPI_CHECK_IP_CSUM | + F_TP_IN_CSPI_CHECK_TCP_CSUM | F_TP_IN_ESPI_ETHERNET; + if (!p->pm_size) + val |= F_OFFLOAD_DISABLE; + else + val |= F_TP_IN_ESPI_CHECK_IP_CSUM | F_TP_IN_ESPI_CHECK_TCP_CSUM; + writel(val, ap->regs + A_TP_IN_CONFIG); + writel(F_TP_OUT_CSPI_CPL | + F_TP_OUT_ESPI_ETHERNET | + F_TP_OUT_ESPI_GENERATE_IP_CSUM | + F_TP_OUT_ESPI_GENERATE_TCP_CSUM, ap->regs + A_TP_OUT_CONFIG); + writel(V_IP_TTL(64) | + F_PATH_MTU /* IP DF bit */ | + V_5TUPLE_LOOKUP(p->use_5tuple_mode) | + V_SYN_COOKIE_PARAMETER(29), ap->regs + A_TP_GLOBAL_CONFIG); + /* + * Enable pause frame deadlock prevention. + */ + if (is_T2(ap) && ap->params.nports > 1) { + u32 drop_ticks = DROP_MSEC * (tp_clk / 1000); + + writel(F_ENABLE_TX_DROP | F_ENABLE_TX_ERROR | + V_DROP_TICKS_CNT(drop_ticks) | + V_NUM_PKTS_DROPPED(DROP_PKTS_CNT), + ap->regs + A_TP_TX_DROP_CONFIG); } } @@ -61,6 +58,7 @@ void t1_tp_destroy(struct petp *tp) struct petp *__devinit t1_tp_create(adapter_t * adapter, struct tp_params *p) { struct petp *tp = kzalloc(sizeof(*tp), GFP_KERNEL); + if (!tp) return NULL; diff --git a/drivers/net/chelsio/vsc7326.c b/drivers/net/chelsio/vsc7326.c index 85dc3b1..534ffa0 100644 --- a/drivers/net/chelsio/vsc7326.c +++ b/drivers/net/chelsio/vsc7326.c @@ -226,22 +226,21 @@ static void run_table(adapter_t *adapter if (ib[i].addr == INITBLOCK_SLEEP) { udelay( ib[i].data ); CH_ERR("sleep %d us\n",ib[i].data); - } else { + } else vsc_write( adapter, ib[i].addr, ib[i].data ); - } } } static int bist_rd(adapter_t *adapter, int moduleid, int address) { - int data=0; - u32 result=0; - - if( (address != 0x0) && - (address != 0x1) && - (address != 0x2) && - (address != 0xd) && - (address != 0xe)) + int data = 0; + u32 result = 0; + + if ((address != 0x0) && + (address != 0x1) && + (address != 0x2) && + (address != 0xd) && + (address != 0xe)) CH_ERR("No bist address: 0x%x\n", address); data = ((0x00 << 24) | ((address & 0xff) << 16) | (0x00 << 8) | @@ -251,27 +250,27 @@ static int bist_rd(adapter_t *adapter, i udelay(10); vsc_read(adapter, REG_RAM_BIST_RESULT, &result); - if((result & (1<<9)) != 0x0) + if ((result & (1 << 9)) != 0x0) CH_ERR("Still in bist read: 0x%x\n", result); - else if((result & (1<<8)) != 0x0) + else if ((result & (1 << 8)) != 0x0) CH_ERR("bist read error: 0x%x\n", result); - return(result & 0xff); + return (result & 0xff); } static int bist_wr(adapter_t *adapter, int moduleid, int address, int value) { - int data=0; - u32 result=0; - - if( (address != 0x0) && - (address != 0x1) && - (address != 0x2) && - (address != 0xd) && - (address != 0xe)) + int data = 0; + u32 result = 0; + + if ((address != 0x0) && + (address != 0x1) && + (address != 0x2) && + (address != 0xd) && + (address != 0xe)) CH_ERR("No bist address: 0x%x\n", address); - if( value>255 ) + if (value > 255) CH_ERR("Suspicious write out of range value: 0x%x\n", value); data = ((0x01 << 24) | ((address & 0xff) << 16) | (value << 8) | @@ -281,12 +280,12 @@ static int bist_wr(adapter_t *adapter, i udelay(5); vsc_read(adapter, REG_RAM_BIST_CMD, &result); - if((result & (1<<27)) != 0x0) + if ((result & (1 << 27)) != 0x0) CH_ERR("Still in bist write: 0x%x\n", result); - else if((result & (1<<26)) != 0x0) + else if ((result & (1 << 26)) != 0x0) CH_ERR("bist write error: 0x%x\n", result); - return(0); + return 0; } static int run_bist(adapter_t *adapter, int moduleid) @@ -295,7 +294,7 @@ static int run_bist(adapter_t *adapter, (void) bist_wr(adapter,moduleid, 0x00, 0x02); (void) bist_wr(adapter,moduleid, 0x01, 0x01); - return(0); + return 0; } static int check_bist(adapter_t *adapter, int moduleid) @@ -309,27 +308,26 @@ static int check_bist(adapter_t *adapter if ((result & 3) != 0x3) CH_ERR("Result: 0x%x BIST error in ram %d, column: 0x%04x\n", result, moduleid, column); - return(0); + return 0; } static int enable_mem(adapter_t *adapter, int moduleid) { /*enable mem*/ (void) bist_wr(adapter,moduleid, 0x00, 0x00); - return(0); + return 0; } static int run_bist_all(adapter_t *adapter) { - int port=0; - u32 val=0; + int port = 0; + u32 val = 0; vsc_write(adapter, REG_MEM_BIST, 0x5); vsc_read(adapter, REG_MEM_BIST, &val); - for(port=0; port<12; port++){ + for (port = 0; port < 12; port++) vsc_write(adapter, REG_DEV_SETUP(port), 0x0); - } udelay(300); vsc_write(adapter, REG_SPI4_MISC, 0x00040409); @@ -352,13 +350,13 @@ static int run_bist_all(adapter_t *adapt udelay(300); vsc_write(adapter, REG_SPI4_MISC, 0x60040400); udelay(300); - for(port=0; port<12; port++){ + for (port = 0; port < 12; port++) vsc_write(adapter, REG_DEV_SETUP(port), 0x1); - } + udelay(300); vsc_write(adapter, REG_MEM_BIST, 0x0); mdelay(10); - return(0); + return 0; } static int mac_intr_handler(struct cmac *mac) @@ -591,40 +589,46 @@ static void rmon_update(struct cmac *mac static void port_stats_update(struct cmac *mac) { - int port = mac->instance->index; + struct { + unsigned int reg; + unsigned int offset; + } hw_stats[] = { + +#define HW_STAT(reg, stat_name) \ + { reg, (&((struct cmac_statistics *)NULL)->stat_name) - (u64 *)NULL } + + /* Rx stats */ + HW_STAT(RxUnicast, RxUnicastFramesOK), + HW_STAT(RxMulticast, RxMulticastFramesOK), + HW_STAT(RxBroadcast, RxBroadcastFramesOK), + HW_STAT(Crc, RxFCSErrors), + HW_STAT(RxAlignment, RxAlignErrors), + HW_STAT(RxOversize, RxFrameTooLongErrors), + HW_STAT(RxPause, RxPauseFrames), + HW_STAT(RxJabbers, RxJabberErrors), + HW_STAT(RxFragments, RxRuntErrors), + HW_STAT(RxUndersize, RxRuntErrors), + HW_STAT(RxSymbolCarrier, RxSymbolErrors), + HW_STAT(RxSize1519ToMax, RxJumboFramesOK), + + /* Tx stats (skip collision stats as we are full-duplex only) */ + HW_STAT(TxUnicast, TxUnicastFramesOK), + HW_STAT(TxMulticast, TxMulticastFramesOK), + HW_STAT(TxBroadcast, TxBroadcastFramesOK), + HW_STAT(TxPause, TxPauseFrames), + HW_STAT(TxUnderrun, TxUnderrun), + HW_STAT(TxSize1519ToMax, TxJumboFramesOK), + }, *p = hw_stats; + unsigned int port = mac->instance->index; + u64 *stats = (u64 *)&mac->stats; + unsigned int i; + + for (i = 0; i < ARRAY_SIZE(hw_stats); i++) + rmon_update(mac, CRA(0x4, port, p->reg), stats + p->offset); - /* Rx stats */ + rmon_update(mac, REG_TX_OK_BYTES(port), &mac->stats.TxOctetsOK); rmon_update(mac, REG_RX_OK_BYTES(port), &mac->stats.RxOctetsOK); rmon_update(mac, REG_RX_BAD_BYTES(port), &mac->stats.RxOctetsBad); - rmon_update(mac, REG_RX_UNICAST(port), &mac->stats.RxUnicastFramesOK); - rmon_update(mac, REG_RX_MULTICAST(port), - &mac->stats.RxMulticastFramesOK); - rmon_update(mac, REG_RX_BROADCAST(port), - &mac->stats.RxBroadcastFramesOK); - rmon_update(mac, REG_CRC(port), &mac->stats.RxFCSErrors); - rmon_update(mac, REG_RX_ALIGNMENT(port), &mac->stats.RxAlignErrors); - rmon_update(mac, REG_RX_OVERSIZE(port), - &mac->stats.RxFrameTooLongErrors); - rmon_update(mac, REG_RX_PAUSE(port), &mac->stats.RxPauseFrames); - rmon_update(mac, REG_RX_JABBERS(port), &mac->stats.RxJabberErrors); - rmon_update(mac, REG_RX_FRAGMENTS(port), &mac->stats.RxRuntErrors); - rmon_update(mac, REG_RX_UNDERSIZE(port), &mac->stats.RxRuntErrors); - rmon_update(mac, REG_RX_SYMBOL_CARRIER(port), - &mac->stats.RxSymbolErrors); - rmon_update(mac, REG_RX_SIZE_1519_TO_MAX(port), - &mac->stats.RxJumboFramesOK); - - /* Tx stats (skip collision stats as we are full-duplex only) */ - rmon_update(mac, REG_TX_OK_BYTES(port), &mac->stats.TxOctetsOK); - rmon_update(mac, REG_TX_UNICAST(port), &mac->stats.TxUnicastFramesOK); - rmon_update(mac, REG_TX_MULTICAST(port), - &mac->stats.TxMulticastFramesOK); - rmon_update(mac, REG_TX_BROADCAST(port), - &mac->stats.TxBroadcastFramesOK); - rmon_update(mac, REG_TX_PAUSE(port), &mac->stats.TxPauseFrames); - rmon_update(mac, REG_TX_UNDERRUN(port), &mac->stats.TxUnderrun); - rmon_update(mac, REG_TX_SIZE_1519_TO_MAX(port), - &mac->stats.TxJumboFramesOK); } /* @@ -686,7 +690,8 @@ static struct cmac *vsc7326_mac_create(a int i; mac = kzalloc(sizeof(*mac) + sizeof(cmac_instance), GFP_KERNEL); - if (!mac) return NULL; + if (!mac) + return NULL; mac->ops = &vsc7326_ops; mac->instance = (cmac_instance *)(mac + 1); diff --git a/drivers/net/chelsio/vsc7326_reg.h b/drivers/net/chelsio/vsc7326_reg.h index 491bcf7..479edbc 100644 --- a/drivers/net/chelsio/vsc7326_reg.h +++ b/drivers/net/chelsio/vsc7326_reg.h @@ -192,73 +192,84 @@ #define REG_TX_IFG(pn) CRA(0x1,pn,0x18) #define REG_HDX(pn) CRA(0x1,pn,0x19) /* Half-duplex config */ /* Statistics */ +/* CRA(0x4,pn,reg) */ +/* reg below */ /* pn = port number, 0-a, a = 10GbE */ -#define REG_RX_IN_BYTES(pn) CRA(0x4,pn,0x00) /* # Rx in octets */ -#define REG_RX_SYMBOL_CARRIER(pn) CRA(0x4,pn,0x01) /* Frames w/ symbol errors */ -#define REG_RX_PAUSE(pn) CRA(0x4,pn,0x02) /* # pause frames received */ -#define REG_RX_UNSUP_OPCODE(pn) CRA(0x4,pn,0x03) /* # control frames with unsupported opcode */ -#define REG_RX_OK_BYTES(pn) CRA(0x4,pn,0x04) /* # octets in good frames */ -#define REG_RX_BAD_BYTES(pn) CRA(0x4,pn,0x05) /* # octets in bad frames */ -#define REG_RX_UNICAST(pn) CRA(0x4,pn,0x06) /* # good unicast frames */ -#define REG_RX_MULTICAST(pn) CRA(0x4,pn,0x07) /* # good multicast frames */ -#define REG_RX_BROADCAST(pn) CRA(0x4,pn,0x08) /* # good broadcast frames */ -#define REG_CRC(pn) CRA(0x4,pn,0x09) /* # frames w/ bad CRC only */ -#define REG_RX_ALIGNMENT(pn) CRA(0x4,pn,0x0a) /* # frames w/ alignment err */ -#define REG_RX_UNDERSIZE(pn) CRA(0x4,pn,0x0b) /* # frames undersize */ -#define REG_RX_FRAGMENTS(pn) CRA(0x4,pn,0x0c) /* # frames undersize w/ crc err */ -#define REG_RX_IN_RANGE_LENGTH_ERROR(pn) CRA(0x4,pn,0x0d) /* # frames with length error */ -#define REG_RX_OUT_OF_RANGE_ERROR(pn) CRA(0x4,pn,0x0e) /* # frames with illegal length field */ -#define REG_RX_OVERSIZE(pn) CRA(0x4,pn,0x0f) /* # frames oversize */ -#define REG_RX_JABBERS(pn) CRA(0x4,pn,0x10) /* # frames oversize w/ crc err */ -#define REG_RX_SIZE_64(pn) CRA(0x4,pn,0x11) /* # frames 64 octets long */ -#define REG_RX_SIZE_65_TO_127(pn) CRA(0x4,pn,0x12) /* # frames 65-127 octets */ -#define REG_RX_SIZE_128_TO_255(pn) CRA(0x4,pn,0x13) /* # frames 128-255 */ -#define REG_RX_SIZE_256_TO_511(pn) CRA(0x4,pn,0x14) /* # frames 256-511 */ -#define REG_RX_SIZE_512_TO_1023(pn) CRA(0x4,pn,0x15) /* # frames 512-1023 */ -#define REG_RX_SIZE_1024_TO_1518(pn) CRA(0x4,pn,0x16) /* # frames 1024-1518 */ -#define REG_RX_SIZE_1519_TO_MAX(pn) CRA(0x4,pn,0x17) /* # frames 1519-max */ -#define REG_TX_OUT_BYTES(pn) CRA(0x4,pn,0x18) /* # octets tx */ -#define REG_TX_PAUSE(pn) CRA(0x4,pn,0x19) /* # pause frames sent */ -#define REG_TX_OK_BYTES(pn) CRA(0x4,pn,0x1a) /* # octets tx OK */ -#define REG_TX_UNICAST(pn) CRA(0x4,pn,0x1b) /* # frames unicast */ -#define REG_TX_MULTICAST(pn) CRA(0x4,pn,0x1c) /* # frames multicast */ -#define REG_TX_BROADCAST(pn) CRA(0x4,pn,0x1d) /* # frames broadcast */ -#define REG_TX_MULTIPLE_COLL(pn) CRA(0x4,pn,0x1e) /* # frames tx after multiple collisions */ -#define REG_TX_LATE_COLL(pn) CRA(0x4,pn,0x1f) /* # late collisions detected */ -#define REG_TX_XCOLL(pn) CRA(0x4,pn,0x20) /* # frames lost, excessive collisions */ -#define REG_TX_DEFER(pn) CRA(0x4,pn,0x21) /* # frames deferred on first tx attempt */ -#define REG_TX_XDEFER(pn) CRA(0x4,pn,0x22) /* # frames excessively deferred */ -#define REG_TX_CSENSE(pn) CRA(0x4,pn,0x23) /* carrier sense errors at frame end */ -#define REG_TX_SIZE_64(pn) CRA(0x4,pn,0x24) /* # frames 64 octets long */ -#define REG_TX_SIZE_65_TO_127(pn) CRA(0x4,pn,0x25) /* # frames 65-127 octets */ -#define REG_TX_SIZE_128_TO_255(pn) CRA(0x4,pn,0x26) /* # frames 128-255 */ -#define REG_TX_SIZE_256_TO_511(pn) CRA(0x4,pn,0x27) /* # frames 256-511 */ -#define REG_TX_SIZE_512_TO_1023(pn) CRA(0x4,pn,0x28) /* # frames 512-1023 */ -#define REG_TX_SIZE_1024_TO_1518(pn) CRA(0x4,pn,0x29) /* # frames 1024-1518 */ -#define REG_TX_SIZE_1519_TO_MAX(pn) CRA(0x4,pn,0x2a) /* # frames 1519-max */ -#define REG_TX_SINGLE_COLL(pn) CRA(0x4,pn,0x2b) /* # frames tx after single collision */ -#define REG_TX_BACKOFF2(pn) CRA(0x4,pn,0x2c) /* # frames tx ok after 2 backoffs/collisions */ -#define REG_TX_BACKOFF3(pn) CRA(0x4,pn,0x2d) /* after 3 backoffs/collisions */ -#define REG_TX_BACKOFF4(pn) CRA(0x4,pn,0x2e) /* after 4 */ -#define REG_TX_BACKOFF5(pn) CRA(0x4,pn,0x2f) /* after 5 */ -#define REG_TX_BACKOFF6(pn) CRA(0x4,pn,0x30) /* after 6 */ -#define REG_TX_BACKOFF7(pn) CRA(0x4,pn,0x31) /* after 7 */ -#define REG_TX_BACKOFF8(pn) CRA(0x4,pn,0x32) /* after 8 */ -#define REG_TX_BACKOFF9(pn) CRA(0x4,pn,0x33) /* after 9 */ -#define REG_TX_BACKOFF10(pn) CRA(0x4,pn,0x34) /* after 10 */ -#define REG_TX_BACKOFF11(pn) CRA(0x4,pn,0x35) /* after 11 */ -#define REG_TX_BACKOFF12(pn) CRA(0x4,pn,0x36) /* after 12 */ -#define REG_TX_BACKOFF13(pn) CRA(0x4,pn,0x37) /* after 13 */ -#define REG_TX_BACKOFF14(pn) CRA(0x4,pn,0x38) /* after 14 */ -#define REG_TX_BACKOFF15(pn) CRA(0x4,pn,0x39) /* after 15 */ -#define REG_TX_UNDERRUN(pn) CRA(0x4,pn,0x3a) /* # frames dropped from underrun */ -#define REG_RX_XGMII_PROT_ERR CRA(0x4,0xa,0x3b) /* # protocol errors detected on XGMII interface */ -#define REG_RX_IPG_SHRINK(pn) CRA(0x4,pn,0x3c) /* # of IPG shrinks detected */ +enum { + RxInBytes = 0x00, // # Rx in octets + RxSymbolCarrier = 0x01, // Frames w/ symbol errors + RxPause = 0x02, // # pause frames received + RxUnsupOpcode = 0x03, // # control frames with unsupported opcode + RxOkBytes = 0x04, // # octets in good frames + RxBadBytes = 0x05, // # octets in bad frames + RxUnicast = 0x06, // # good unicast frames + RxMulticast = 0x07, // # good multicast frames + RxBroadcast = 0x08, // # good broadcast frames + Crc = 0x09, // # frames w/ bad CRC only + RxAlignment = 0x0a, // # frames w/ alignment err + RxUndersize = 0x0b, // # frames undersize + RxFragments = 0x0c, // # frames undersize w/ crc err + RxInRangeLengthError = 0x0d, // # frames with length error + RxOutOfRangeError = 0x0e, // # frames with illegal length field + RxOversize = 0x0f, // # frames oversize + RxJabbers = 0x10, // # frames oversize w/ crc err + RxSize64 = 0x11, // # frames 64 octets long + RxSize65To127 = 0x12, // # frames 65-127 octets + RxSize128To255 = 0x13, // # frames 128-255 + RxSize256To511 = 0x14, // # frames 256-511 + RxSize512To1023 = 0x15, // # frames 512-1023 + RxSize1024To1518 = 0x16, // # frames 1024-1518 + RxSize1519ToMax = 0x17, // # frames 1519-max -#define REG_STAT_STICKY1G(pn) CRA(0x4,pn,0x3e) /* tri-speed sticky bits */ -#define REG_STAT_STICKY10G CRA(0x4,0xa,0x3e) /* 10GbE sticky bits */ -#define REG_STAT_INIT(pn) CRA(0x4,pn,0x3f) /* Clear all statistics */ + TxOutBytes = 0x18, // # octets tx + TxPause = 0x19, // # pause frames sent + TxOkBytes = 0x1a, // # octets tx OK + TxUnicast = 0x1b, // # frames unicast + TxMulticast = 0x1c, // # frames multicast + TxBroadcast = 0x1d, // # frames broadcast + TxMultipleColl = 0x1e, // # frames tx after multiple collisions + TxLateColl = 0x1f, // # late collisions detected + TxXcoll = 0x20, // # frames lost, excessive collisions + TxDefer = 0x21, // # frames deferred on first tx attempt + TxXdefer = 0x22, // # frames excessively deferred + TxCsense = 0x23, // carrier sense errors at frame end + TxSize64 = 0x24, // # frames 64 octets long + TxSize65To127 = 0x25, // # frames 65-127 octets + TxSize128To255 = 0x26, // # frames 128-255 + TxSize256To511 = 0x27, // # frames 256-511 + TxSize512To1023 = 0x28, // # frames 512-1023 + TxSize1024To1518 = 0x29, // # frames 1024-1518 + TxSize1519ToMax = 0x2a, // # frames 1519-max + TxSingleColl = 0x2b, // # frames tx after single collision + TxBackoff2 = 0x2c, // # frames tx ok after 2 backoffs/collisions + TxBackoff3 = 0x2d, // after 3 backoffs/collisions + TxBackoff4 = 0x2e, // after 4 + TxBackoff5 = 0x2f, // after 5 + TxBackoff6 = 0x30, // after 6 + TxBackoff7 = 0x31, // after 7 + TxBackoff8 = 0x32, // after 8 + TxBackoff9 = 0x33, // after 9 + TxBackoff10 = 0x34, // after 10 + TxBackoff11 = 0x35, // after 11 + TxBackoff12 = 0x36, // after 12 + TxBackoff13 = 0x37, // after 13 + TxBackoff14 = 0x38, // after 14 + TxBackoff15 = 0x39, // after 15 + TxUnderrun = 0x3a, // # frames dropped from underrun + // Hole. See REG_RX_XGMII_PROT_ERR below. + RxIpgShrink = 0x3c, // # of IPG shrinks detected + // Duplicate. See REG_STAT_STICKY10G below. + StatSticky1G = 0x3e, // tri-speed sticky bits + StatInit = 0x3f // Clear all statistics +}; + +#define REG_RX_XGMII_PROT_ERR CRA(0x4,0xa,0x3b) /* # protocol errors detected on XGMII interface */ +#define REG_STAT_STICKY10G CRA(0x4,0xa,StatSticky1G) /* 10GbE sticky bits */ + +#define REG_RX_OK_BYTES(pn) CRA(0x4,pn,RxOkBytes) +#define REG_RX_BAD_BYTES(pn) CRA(0x4,pn,RxBadBytes) +#define REG_TX_OK_BYTES(pn) CRA(0x4,pn,TxOkBytes) /* MII-Management Block registers */ /* These are for MII-M interface 0, which is the bidirectional LVTTL one. If diff --git a/drivers/net/chelsio/vsc8244.c b/drivers/net/chelsio/vsc8244.c index c493e78..251d485 100644 --- a/drivers/net/chelsio/vsc8244.c +++ b/drivers/net/chelsio/vsc8244.c @@ -54,7 +54,7 @@ enum { }; #define CFG_CHG_INTR_MASK (VSC_INTR_LINK_CHG | VSC_INTR_NEG_ERR | \ - VSC_INTR_NEG_DONE) + VSC_INTR_NEG_DONE) #define INTR_MASK (CFG_CHG_INTR_MASK | VSC_INTR_TX_FIFO | VSC_INTR_RX_FIFO | \ VSC_INTR_ENABLE) @@ -94,19 +94,18 @@ static int vsc8244_intr_enable(struct cp { simple_mdio_write(cphy, VSC8244_INTR_ENABLE, INTR_MASK); - /* Enable interrupts through Elmer */ + /* Enable interrupts through Elmer */ if (t1_is_asic(cphy->adapter)) { u32 elmer; t1_tpi_read(cphy->adapter, A_ELMER0_INT_ENABLE, &elmer); elmer |= ELMER0_GP_BIT1; - if (is_T2(cphy->adapter)) { + if (is_T2(cphy->adapter)) elmer |= ELMER0_GP_BIT2|ELMER0_GP_BIT3|ELMER0_GP_BIT4; - } t1_tpi_write(cphy->adapter, A_ELMER0_INT_ENABLE, elmer); } - return 0; + return 0; } static int vsc8244_intr_disable(struct cphy *cphy) @@ -118,19 +117,18 @@ static int vsc8244_intr_disable(struct c t1_tpi_read(cphy->adapter, A_ELMER0_INT_ENABLE, &elmer); elmer &= ~ELMER0_GP_BIT1; - if (is_T2(cphy->adapter)) { + if (is_T2(cphy->adapter)) elmer &= ~(ELMER0_GP_BIT2|ELMER0_GP_BIT3|ELMER0_GP_BIT4); - } t1_tpi_write(cphy->adapter, A_ELMER0_INT_ENABLE, elmer); } - return 0; + return 0; } static int vsc8244_intr_clear(struct cphy *cphy) { u32 val; - u32 elmer; + u32 elmer; /* Clear PHY interrupts by reading the register. */ simple_mdio_read(cphy, VSC8244_INTR_ENABLE, &val); @@ -138,13 +136,12 @@ static int vsc8244_intr_clear(struct cph if (t1_is_asic(cphy->adapter)) { t1_tpi_read(cphy->adapter, A_ELMER0_INT_CAUSE, &elmer); elmer |= ELMER0_GP_BIT1; - if (is_T2(cphy->adapter)) { + if (is_T2(cphy->adapter)) elmer |= ELMER0_GP_BIT2|ELMER0_GP_BIT3|ELMER0_GP_BIT4; - } t1_tpi_write(cphy->adapter, A_ELMER0_INT_CAUSE, elmer); } - return 0; + return 0; } /* @@ -179,13 +176,13 @@ static int vsc8244_set_speed_duplex(stru int t1_mdio_set_bits(struct cphy *phy, int mmd, int reg, unsigned int bits) { - int ret; - unsigned int val; + int ret; + unsigned int val; - ret = mdio_read(phy, mmd, reg, &val); - if (!ret) - ret = mdio_write(phy, mmd, reg, val | bits); - return ret; + ret = mdio_read(phy, mmd, reg, &val); + if (!ret) + ret = mdio_write(phy, mmd, reg, val | bits); + return ret; } static int vsc8244_autoneg_enable(struct cphy *cphy) @@ -235,7 +232,7 @@ static int vsc8244_advertise(struct cphy } static int vsc8244_get_link_status(struct cphy *cphy, int *link_ok, - int *speed, int *duplex, int *fc) + int *speed, int *duplex, int *fc) { unsigned int bmcr, status, lpa, adv; int err, sp = -1, dplx = -1, pause = 0; @@ -343,11 +340,13 @@ static struct cphy_ops vsc8244_ops = { .get_link_status = vsc8244_get_link_status }; -static struct cphy* vsc8244_phy_create(adapter_t *adapter, int phy_addr, struct mdio_ops *mdio_ops) +static struct cphy* vsc8244_phy_create(adapter_t *adapter, int phy_addr, + struct mdio_ops *mdio_ops) { struct cphy *cphy = kzalloc(sizeof(*cphy), GFP_KERNEL); - if (!cphy) return NULL; + if (!cphy) + return NULL; cphy_init(cphy, adapter, phy_addr, &vsc8244_ops, mdio_ops); diff --git a/drivers/net/cris/eth_v10.c b/drivers/net/cris/eth_v10.c index a03d781..8eb5712 100644 --- a/drivers/net/cris/eth_v10.c +++ b/drivers/net/cris/eth_v10.c @@ -222,7 +222,6 @@ #include #include -#include #include #include #include diff --git a/drivers/net/cxgb3/Makefile b/drivers/net/cxgb3/Makefile new file mode 100644 index 0000000..3434679 --- /dev/null +++ b/drivers/net/cxgb3/Makefile @@ -0,0 +1,8 @@ +# +# Chelsio T3 driver +# + +obj-$(CONFIG_CHELSIO_T3) += cxgb3.o + +cxgb3-objs := cxgb3_main.o ael1002.o vsc8211.o t3_hw.o mc5.o \ + xgmac.o sge.o l2t.o cxgb3_offload.o diff --git a/drivers/net/cxgb3/adapter.h b/drivers/net/cxgb3/adapter.h new file mode 100644 index 0000000..5c97a64 --- /dev/null +++ b/drivers/net/cxgb3/adapter.h @@ -0,0 +1,279 @@ +/* + * Copyright (c) 2003-2007 Chelsio, Inc. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +/* This file should not be included directly. Include common.h instead. */ + +#ifndef __T3_ADAPTER_H__ +#define __T3_ADAPTER_H__ + +#include +#include +#include +#include +#include +#include +#include "t3cdev.h" +#include +#include +#include + +typedef irqreturn_t(*intr_handler_t) (int, void *); + +struct vlan_group; + +struct port_info { + struct vlan_group *vlan_grp; + const struct port_type_info *port_type; + u8 port_id; + u8 rx_csum_offload; + u8 nqsets; + u8 first_qset; + struct cphy phy; + struct cmac mac; + struct link_config link_config; + struct net_device_stats netstats; + int activity; +}; + +enum { /* adapter flags */ + FULL_INIT_DONE = (1 << 0), + USING_MSI = (1 << 1), + USING_MSIX = (1 << 2), + QUEUES_BOUND = (1 << 3), +}; + +struct rx_desc; +struct rx_sw_desc; + +struct sge_fl { /* SGE per free-buffer list state */ + unsigned int buf_size; /* size of each Rx buffer */ + unsigned int credits; /* # of available Rx buffers */ + unsigned int size; /* capacity of free list */ + unsigned int cidx; /* consumer index */ + unsigned int pidx; /* producer index */ + unsigned int gen; /* free list generation */ + struct rx_desc *desc; /* address of HW Rx descriptor ring */ + struct rx_sw_desc *sdesc; /* address of SW Rx descriptor ring */ + dma_addr_t phys_addr; /* physical address of HW ring start */ + unsigned int cntxt_id; /* SGE context id for the free list */ + unsigned long empty; /* # of times queue ran out of buffers */ +}; + +/* + * Bundle size for grouping offload RX packets for delivery to the stack. + * Don't make this too big as we do prefetch on each packet in a bundle. + */ +# define RX_BUNDLE_SIZE 8 + +struct rsp_desc; + +struct sge_rspq { /* state for an SGE response queue */ + unsigned int credits; /* # of pending response credits */ + unsigned int size; /* capacity of response queue */ + unsigned int cidx; /* consumer index */ + unsigned int gen; /* current generation bit */ + unsigned int polling; /* is the queue serviced through NAPI? */ + unsigned int holdoff_tmr; /* interrupt holdoff timer in 100ns */ + unsigned int next_holdoff; /* holdoff time for next interrupt */ + struct rsp_desc *desc; /* address of HW response ring */ + dma_addr_t phys_addr; /* physical address of the ring */ + unsigned int cntxt_id; /* SGE context id for the response q */ + spinlock_t lock; /* guards response processing */ + struct sk_buff *rx_head; /* offload packet receive queue head */ + struct sk_buff *rx_tail; /* offload packet receive queue tail */ + + unsigned long offload_pkts; + unsigned long offload_bundles; + unsigned long eth_pkts; /* # of ethernet packets */ + unsigned long pure_rsps; /* # of pure (non-data) responses */ + unsigned long imm_data; /* responses with immediate data */ + unsigned long rx_drops; /* # of packets dropped due to no mem */ + unsigned long async_notif; /* # of asynchronous notification events */ + unsigned long empty; /* # of times queue ran out of credits */ + unsigned long nomem; /* # of responses deferred due to no mem */ + unsigned long unhandled_irqs; /* # of spurious intrs */ +}; + +struct tx_desc; +struct tx_sw_desc; + +struct sge_txq { /* state for an SGE Tx queue */ + unsigned long flags; /* HW DMA fetch status */ + unsigned int in_use; /* # of in-use Tx descriptors */ + unsigned int size; /* # of descriptors */ + unsigned int processed; /* total # of descs HW has processed */ + unsigned int cleaned; /* total # of descs SW has reclaimed */ + unsigned int stop_thres; /* SW TX queue suspend threshold */ + unsigned int cidx; /* consumer index */ + unsigned int pidx; /* producer index */ + unsigned int gen; /* current value of generation bit */ + unsigned int unacked; /* Tx descriptors used since last COMPL */ + struct tx_desc *desc; /* address of HW Tx descriptor ring */ + struct tx_sw_desc *sdesc; /* address of SW Tx descriptor ring */ + spinlock_t lock; /* guards enqueueing of new packets */ + unsigned int token; /* WR token */ + dma_addr_t phys_addr; /* physical address of the ring */ + struct sk_buff_head sendq; /* List of backpressured offload packets */ + struct tasklet_struct qresume_tsk; /* restarts the queue */ + unsigned int cntxt_id; /* SGE context id for the Tx q */ + unsigned long stops; /* # of times q has been stopped */ + unsigned long restarts; /* # of queue restarts */ +}; + +enum { /* per port SGE statistics */ + SGE_PSTAT_TSO, /* # of TSO requests */ + SGE_PSTAT_RX_CSUM_GOOD, /* # of successful RX csum offloads */ + SGE_PSTAT_TX_CSUM, /* # of TX checksum offloads */ + SGE_PSTAT_VLANEX, /* # of VLAN tag extractions */ + SGE_PSTAT_VLANINS, /* # of VLAN tag insertions */ + + SGE_PSTAT_MAX /* must be last */ +}; + +struct sge_qset { /* an SGE queue set */ + struct sge_rspq rspq; + struct sge_fl fl[SGE_RXQ_PER_SET]; + struct sge_txq txq[SGE_TXQ_PER_SET]; + struct net_device *netdev; /* associated net device */ + unsigned long txq_stopped; /* which Tx queues are stopped */ + struct timer_list tx_reclaim_timer; /* reclaims TX buffers */ + unsigned long port_stats[SGE_PSTAT_MAX]; +} ____cacheline_aligned; + +struct sge { + struct sge_qset qs[SGE_QSETS]; + spinlock_t reg_lock; /* guards non-atomic SGE registers (eg context) */ +}; + +struct adapter { + struct t3cdev tdev; + struct list_head adapter_list; + void __iomem *regs; + struct pci_dev *pdev; + unsigned long registered_device_map; + unsigned long open_device_map; + unsigned long flags; + + const char *name; + int msg_enable; + unsigned int mmio_len; + + struct adapter_params params; + unsigned int slow_intr_mask; + unsigned long irq_stats[IRQ_NUM_STATS]; + + struct { + unsigned short vec; + char desc[22]; + } msix_info[SGE_QSETS + 1]; + + /* T3 modules */ + struct sge sge; + struct mc7 pmrx; + struct mc7 pmtx; + struct mc7 cm; + struct mc5 mc5; + + struct net_device *port[MAX_NPORTS]; + unsigned int check_task_cnt; + struct delayed_work adap_check_task; + struct work_struct ext_intr_handler_task; + + /* + * Dummy netdevices are needed when using multiple receive queues with + * NAPI as each netdevice can service only one queue. + */ + struct net_device *dummy_netdev[SGE_QSETS - 1]; + + struct dentry *debugfs_root; + + struct mutex mdio_lock; + spinlock_t stats_lock; + spinlock_t work_lock; +}; + +static inline u32 t3_read_reg(struct adapter *adapter, u32 reg_addr) +{ + u32 val = readl(adapter->regs + reg_addr); + + CH_DBG(adapter, MMIO, "read register 0x%x value 0x%x\n", reg_addr, val); + return val; +} + +static inline void t3_write_reg(struct adapter *adapter, u32 reg_addr, u32 val) +{ + CH_DBG(adapter, MMIO, "setting register 0x%x to 0x%x\n", reg_addr, val); + writel(val, adapter->regs + reg_addr); +} + +static inline struct port_info *adap2pinfo(struct adapter *adap, int idx) +{ + return netdev_priv(adap->port[idx]); +} + +/* + * We use the spare atalk_ptr to map a net device to its SGE queue set. + * This is a macro so it can be used as l-value. + */ +#define dev2qset(netdev) ((netdev)->atalk_ptr) + +#define OFFLOAD_DEVMAP_BIT 15 + +#define tdev2adap(d) container_of(d, struct adapter, tdev) + +static inline int offload_running(struct adapter *adapter) +{ + return test_bit(OFFLOAD_DEVMAP_BIT, &adapter->open_device_map); +} + +int t3_offload_tx(struct t3cdev *tdev, struct sk_buff *skb); + +void t3_os_ext_intr_handler(struct adapter *adapter); +void t3_os_link_changed(struct adapter *adapter, int port_id, int link_status, + int speed, int duplex, int fc); + +void t3_sge_start(struct adapter *adap); +void t3_sge_stop(struct adapter *adap); +void t3_free_sge_resources(struct adapter *adap); +void t3_sge_err_intr_handler(struct adapter *adapter); +intr_handler_t t3_intr_handler(struct adapter *adap, int polling); +int t3_eth_xmit(struct sk_buff *skb, struct net_device *dev); +int t3_mgmt_tx(struct adapter *adap, struct sk_buff *skb); +void t3_update_qset_coalesce(struct sge_qset *qs, const struct qset_params *p); +int t3_sge_alloc_qset(struct adapter *adapter, unsigned int id, int nports, + int irq_vec_idx, const struct qset_params *p, + int ntxq, struct net_device *netdev); +int t3_get_desc(const struct sge_qset *qs, unsigned int qnum, unsigned int idx, + unsigned char *data); +irqreturn_t t3_sge_intr_msix(int irq, void *cookie); + +#endif /* __T3_ADAPTER_H__ */ diff --git a/drivers/net/cxgb3/ael1002.c b/drivers/net/cxgb3/ael1002.c new file mode 100644 index 0000000..73a41e6 --- /dev/null +++ b/drivers/net/cxgb3/ael1002.c @@ -0,0 +1,251 @@ +/* + * Copyright (c) 2005-2007 Chelsio, Inc. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +#include "common.h" +#include "regs.h" + +enum { + AEL100X_TX_DISABLE = 9, + AEL100X_TX_CONFIG1 = 0xc002, + AEL1002_PWR_DOWN_HI = 0xc011, + AEL1002_PWR_DOWN_LO = 0xc012, + AEL1002_XFI_EQL = 0xc015, + AEL1002_LB_EN = 0xc017, + + LASI_CTRL = 0x9002, + LASI_STAT = 0x9005 +}; + +static void ael100x_txon(struct cphy *phy) +{ + int tx_on_gpio = phy->addr == 0 ? F_GPIO7_OUT_VAL : F_GPIO2_OUT_VAL; + + msleep(100); + t3_set_reg_field(phy->adapter, A_T3DBG_GPIO_EN, 0, tx_on_gpio); + msleep(30); +} + +static int ael1002_power_down(struct cphy *phy, int enable) +{ + int err; + + err = mdio_write(phy, MDIO_DEV_PMA_PMD, AEL100X_TX_DISABLE, !!enable); + if (!err) + err = t3_mdio_change_bits(phy, MDIO_DEV_PMA_PMD, MII_BMCR, + BMCR_PDOWN, enable ? BMCR_PDOWN : 0); + return err; +} + +static int ael1002_reset(struct cphy *phy, int wait) +{ + int err; + + if ((err = ael1002_power_down(phy, 0)) || + (err = mdio_write(phy, MDIO_DEV_PMA_PMD, AEL100X_TX_CONFIG1, 1)) || + (err = mdio_write(phy, MDIO_DEV_PMA_PMD, AEL1002_PWR_DOWN_HI, 0)) || + (err = mdio_write(phy, MDIO_DEV_PMA_PMD, AEL1002_PWR_DOWN_LO, 0)) || + (err = mdio_write(phy, MDIO_DEV_PMA_PMD, AEL1002_XFI_EQL, 0x18)) || + (err = t3_mdio_change_bits(phy, MDIO_DEV_PMA_PMD, AEL1002_LB_EN, + 0, 1 << 5))) + return err; + return 0; +} + +static int ael1002_intr_noop(struct cphy *phy) +{ + return 0; +} + +static int ael100x_get_link_status(struct cphy *phy, int *link_ok, + int *speed, int *duplex, int *fc) +{ + if (link_ok) { + unsigned int status; + int err = mdio_read(phy, MDIO_DEV_PMA_PMD, MII_BMSR, &status); + + /* + * BMSR_LSTATUS is latch-low, so if it is 0 we need to read it + * once more to get the current link state. + */ + if (!err && !(status & BMSR_LSTATUS)) + err = mdio_read(phy, MDIO_DEV_PMA_PMD, MII_BMSR, + &status); + if (err) + return err; + *link_ok = !!(status & BMSR_LSTATUS); + } + if (speed) + *speed = SPEED_10000; + if (duplex) + *duplex = DUPLEX_FULL; + return 0; +} + +static struct cphy_ops ael1002_ops = { + .reset = ael1002_reset, + .intr_enable = ael1002_intr_noop, + .intr_disable = ael1002_intr_noop, + .intr_clear = ael1002_intr_noop, + .intr_handler = ael1002_intr_noop, + .get_link_status = ael100x_get_link_status, + .power_down = ael1002_power_down, +}; + +void t3_ael1002_phy_prep(struct cphy *phy, struct adapter *adapter, + int phy_addr, const struct mdio_ops *mdio_ops) +{ + cphy_init(phy, adapter, phy_addr, &ael1002_ops, mdio_ops); + ael100x_txon(phy); +} + +static int ael1006_reset(struct cphy *phy, int wait) +{ + return t3_phy_reset(phy, MDIO_DEV_PMA_PMD, wait); +} + +static int ael1006_intr_enable(struct cphy *phy) +{ + return mdio_write(phy, MDIO_DEV_PMA_PMD, LASI_CTRL, 1); +} + +static int ael1006_intr_disable(struct cphy *phy) +{ + return mdio_write(phy, MDIO_DEV_PMA_PMD, LASI_CTRL, 0); +} + +static int ael1006_intr_clear(struct cphy *phy) +{ + u32 val; + + return mdio_read(phy, MDIO_DEV_PMA_PMD, LASI_STAT, &val); +} + +static int ael1006_intr_handler(struct cphy *phy) +{ + unsigned int status; + int err = mdio_read(phy, MDIO_DEV_PMA_PMD, LASI_STAT, &status); + + if (err) + return err; + return (status & 1) ? cphy_cause_link_change : 0; +} + +static int ael1006_power_down(struct cphy *phy, int enable) +{ + return t3_mdio_change_bits(phy, MDIO_DEV_PMA_PMD, MII_BMCR, + BMCR_PDOWN, enable ? BMCR_PDOWN : 0); +} + +static struct cphy_ops ael1006_ops = { + .reset = ael1006_reset, + .intr_enable = ael1006_intr_enable, + .intr_disable = ael1006_intr_disable, + .intr_clear = ael1006_intr_clear, + .intr_handler = ael1006_intr_handler, + .get_link_status = ael100x_get_link_status, + .power_down = ael1006_power_down, +}; + +void t3_ael1006_phy_prep(struct cphy *phy, struct adapter *adapter, + int phy_addr, const struct mdio_ops *mdio_ops) +{ + cphy_init(phy, adapter, phy_addr, &ael1006_ops, mdio_ops); + ael100x_txon(phy); +} + +static struct cphy_ops qt2045_ops = { + .reset = ael1006_reset, + .intr_enable = ael1006_intr_enable, + .intr_disable = ael1006_intr_disable, + .intr_clear = ael1006_intr_clear, + .intr_handler = ael1006_intr_handler, + .get_link_status = ael100x_get_link_status, + .power_down = ael1006_power_down, +}; + +void t3_qt2045_phy_prep(struct cphy *phy, struct adapter *adapter, + int phy_addr, const struct mdio_ops *mdio_ops) +{ + unsigned int stat; + + cphy_init(phy, adapter, phy_addr, &qt2045_ops, mdio_ops); + + /* + * Some cards where the PHY is supposed to be at address 0 actually + * have it at 1. + */ + if (!phy_addr && !mdio_read(phy, MDIO_DEV_PMA_PMD, MII_BMSR, &stat) && + stat == 0xffff) + phy->addr = 1; +} + +static int xaui_direct_reset(struct cphy *phy, int wait) +{ + return 0; +} + +static int xaui_direct_get_link_status(struct cphy *phy, int *link_ok, + int *speed, int *duplex, int *fc) +{ + if (link_ok) { + unsigned int status; + + status = t3_read_reg(phy->adapter, + XGM_REG(A_XGM_SERDES_STAT0, phy->addr)); + *link_ok = !(status & F_LOWSIG0); + } + if (speed) + *speed = SPEED_10000; + if (duplex) + *duplex = DUPLEX_FULL; + return 0; +} + +static int xaui_direct_power_down(struct cphy *phy, int enable) +{ + return 0; +} + +static struct cphy_ops xaui_direct_ops = { + .reset = xaui_direct_reset, + .intr_enable = ael1002_intr_noop, + .intr_disable = ael1002_intr_noop, + .intr_clear = ael1002_intr_noop, + .intr_handler = ael1002_intr_noop, + .get_link_status = xaui_direct_get_link_status, + .power_down = xaui_direct_power_down, +}; + +void t3_xaui_direct_phy_prep(struct cphy *phy, struct adapter *adapter, + int phy_addr, const struct mdio_ops *mdio_ops) +{ + cphy_init(phy, adapter, 1, &xaui_direct_ops, mdio_ops); +} diff --git a/drivers/net/cxgb3/common.h b/drivers/net/cxgb3/common.h new file mode 100644 index 0000000..e23deeb --- /dev/null +++ b/drivers/net/cxgb3/common.h @@ -0,0 +1,729 @@ +/* + * Copyright (c) 2005-2007 Chelsio, Inc. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +#ifndef __CHELSIO_COMMON_H +#define __CHELSIO_COMMON_H + +#include +#include +#include +#include +#include +#include +#include +#include +#include "version.h" + +#define CH_ERR(adap, fmt, ...) dev_err(&adap->pdev->dev, fmt, ## __VA_ARGS__) +#define CH_WARN(adap, fmt, ...) dev_warn(&adap->pdev->dev, fmt, ## __VA_ARGS__) +#define CH_ALERT(adap, fmt, ...) \ + dev_printk(KERN_ALERT, &adap->pdev->dev, fmt, ## __VA_ARGS__) + +/* + * More powerful macro that selectively prints messages based on msg_enable. + * For info and debugging messages. + */ +#define CH_MSG(adapter, level, category, fmt, ...) do { \ + if ((adapter)->msg_enable & NETIF_MSG_##category) \ + dev_printk(KERN_##level, &adapter->pdev->dev, fmt, \ + ## __VA_ARGS__); \ +} while (0) + +#ifdef DEBUG +# define CH_DBG(adapter, category, fmt, ...) \ + CH_MSG(adapter, DEBUG, category, fmt, ## __VA_ARGS__) +#else +# define CH_DBG(adapter, category, fmt, ...) +#endif + +/* Additional NETIF_MSG_* categories */ +#define NETIF_MSG_MMIO 0x8000000 + +struct t3_rx_mode { + struct net_device *dev; + struct dev_mc_list *mclist; + unsigned int idx; +}; + +static inline void init_rx_mode(struct t3_rx_mode *p, struct net_device *dev, + struct dev_mc_list *mclist) +{ + p->dev = dev; + p->mclist = mclist; + p->idx = 0; +} + +static inline u8 *t3_get_next_mcaddr(struct t3_rx_mode *rm) +{ + u8 *addr = NULL; + + if (rm->mclist && rm->idx < rm->dev->mc_count) { + addr = rm->mclist->dmi_addr; + rm->mclist = rm->mclist->next; + rm->idx++; + } + return addr; +} + +enum { + MAX_NPORTS = 2, /* max # of ports */ + MAX_FRAME_SIZE = 10240, /* max MAC frame size, including header + FCS */ + EEPROMSIZE = 8192, /* Serial EEPROM size */ + RSS_TABLE_SIZE = 64, /* size of RSS lookup and mapping tables */ + TCB_SIZE = 128, /* TCB size */ + NMTUS = 16, /* size of MTU table */ + NCCTRL_WIN = 32, /* # of congestion control windows */ +}; + +#define MAX_RX_COALESCING_LEN 16224U + +enum { + PAUSE_RX = 1 << 0, + PAUSE_TX = 1 << 1, + PAUSE_AUTONEG = 1 << 2 +}; + +enum { + SUPPORTED_OFFLOAD = 1 << 24, + SUPPORTED_IRQ = 1 << 25 +}; + +enum { /* adapter interrupt-maintained statistics */ + STAT_ULP_CH0_PBL_OOB, + STAT_ULP_CH1_PBL_OOB, + STAT_PCI_CORR_ECC, + + IRQ_NUM_STATS /* keep last */ +}; + +enum { + SGE_QSETS = 8, /* # of SGE Tx/Rx/RspQ sets */ + SGE_RXQ_PER_SET = 2, /* # of Rx queues per set */ + SGE_TXQ_PER_SET = 3 /* # of Tx queues per set */ +}; + +enum sge_context_type { /* SGE egress context types */ + SGE_CNTXT_RDMA = 0, + SGE_CNTXT_ETH = 2, + SGE_CNTXT_OFLD = 4, + SGE_CNTXT_CTRL = 5 +}; + +enum { + AN_PKT_SIZE = 32, /* async notification packet size */ + IMMED_PKT_SIZE = 48 /* packet size for immediate data */ +}; + +struct sg_ent { /* SGE scatter/gather entry */ + u32 len[2]; + u64 addr[2]; +}; + +#ifndef SGE_NUM_GENBITS +/* Must be 1 or 2 */ +# define SGE_NUM_GENBITS 2 +#endif + +#define TX_DESC_FLITS 16U +#define WR_FLITS (TX_DESC_FLITS + 1 - SGE_NUM_GENBITS) + +struct cphy; +struct adapter; + +struct mdio_ops { + int (*read)(struct adapter *adapter, int phy_addr, int mmd_addr, + int reg_addr, unsigned int *val); + int (*write)(struct adapter *adapter, int phy_addr, int mmd_addr, + int reg_addr, unsigned int val); +}; + +struct adapter_info { + unsigned char nports; /* # of ports */ + unsigned char phy_base_addr; /* MDIO PHY base address */ + unsigned char mdien; + unsigned char mdiinv; + unsigned int gpio_out; /* GPIO output settings */ + unsigned int gpio_intr; /* GPIO IRQ enable mask */ + unsigned long caps; /* adapter capabilities */ + const struct mdio_ops *mdio_ops; /* MDIO operations */ + const char *desc; /* product description */ +}; + +struct port_type_info { + void (*phy_prep)(struct cphy *phy, struct adapter *adapter, + int phy_addr, const struct mdio_ops *ops); + unsigned int caps; + const char *desc; +}; + +struct mc5_stats { + unsigned long parity_err; + unsigned long active_rgn_full; + unsigned long nfa_srch_err; + unsigned long unknown_cmd; + unsigned long reqq_parity_err; + unsigned long dispq_parity_err; + unsigned long del_act_empty; +}; + +struct mc7_stats { + unsigned long corr_err; + unsigned long uncorr_err; + unsigned long parity_err; + unsigned long addr_err; +}; + +struct mac_stats { + u64 tx_octets; /* total # of octets in good frames */ + u64 tx_octets_bad; /* total # of octets in error frames */ + u64 tx_frames; /* all good frames */ + u64 tx_mcast_frames; /* good multicast frames */ + u64 tx_bcast_frames; /* good broadcast frames */ + u64 tx_pause; /* # of transmitted pause frames */ + u64 tx_deferred; /* frames with deferred transmissions */ + u64 tx_late_collisions; /* # of late collisions */ + u64 tx_total_collisions; /* # of total collisions */ + u64 tx_excess_collisions; /* frame errors from excessive collissions */ + u64 tx_underrun; /* # of Tx FIFO underruns */ + u64 tx_len_errs; /* # of Tx length errors */ + u64 tx_mac_internal_errs; /* # of internal MAC errors on Tx */ + u64 tx_excess_deferral; /* # of frames with excessive deferral */ + u64 tx_fcs_errs; /* # of frames with bad FCS */ + + u64 tx_frames_64; /* # of Tx frames in a particular range */ + u64 tx_frames_65_127; + u64 tx_frames_128_255; + u64 tx_frames_256_511; + u64 tx_frames_512_1023; + u64 tx_frames_1024_1518; + u64 tx_frames_1519_max; + + u64 rx_octets; /* total # of octets in good frames */ + u64 rx_octets_bad; /* total # of octets in error frames */ + u64 rx_frames; /* all good frames */ + u64 rx_mcast_frames; /* good multicast frames */ + u64 rx_bcast_frames; /* good broadcast frames */ + u64 rx_pause; /* # of received pause frames */ + u64 rx_fcs_errs; /* # of received frames with bad FCS */ + u64 rx_align_errs; /* alignment errors */ + u64 rx_symbol_errs; /* symbol errors */ + u64 rx_data_errs; /* data errors */ + u64 rx_sequence_errs; /* sequence errors */ + u64 rx_runt; /* # of runt frames */ + u64 rx_jabber; /* # of jabber frames */ + u64 rx_short; /* # of short frames */ + u64 rx_too_long; /* # of oversized frames */ + u64 rx_mac_internal_errs; /* # of internal MAC errors on Rx */ + + u64 rx_frames_64; /* # of Rx frames in a particular range */ + u64 rx_frames_65_127; + u64 rx_frames_128_255; + u64 rx_frames_256_511; + u64 rx_frames_512_1023; + u64 rx_frames_1024_1518; + u64 rx_frames_1519_max; + + u64 rx_cong_drops; /* # of Rx drops due to SGE congestion */ + + unsigned long tx_fifo_parity_err; + unsigned long rx_fifo_parity_err; + unsigned long tx_fifo_urun; + unsigned long rx_fifo_ovfl; + unsigned long serdes_signal_loss; + unsigned long xaui_pcs_ctc_err; + unsigned long xaui_pcs_align_change; +}; + +struct tp_mib_stats { + u32 ipInReceive_hi; + u32 ipInReceive_lo; + u32 ipInHdrErrors_hi; + u32 ipInHdrErrors_lo; + u32 ipInAddrErrors_hi; + u32 ipInAddrErrors_lo; + u32 ipInUnknownProtos_hi; + u32 ipInUnknownProtos_lo; + u32 ipInDiscards_hi; + u32 ipInDiscards_lo; + u32 ipInDelivers_hi; + u32 ipInDelivers_lo; + u32 ipOutRequests_hi; + u32 ipOutRequests_lo; + u32 ipOutDiscards_hi; + u32 ipOutDiscards_lo; + u32 ipOutNoRoutes_hi; + u32 ipOutNoRoutes_lo; + u32 ipReasmTimeout; + u32 ipReasmReqds; + u32 ipReasmOKs; + u32 ipReasmFails; + + u32 reserved[8]; + + u32 tcpActiveOpens; + u32 tcpPassiveOpens; + u32 tcpAttemptFails; + u32 tcpEstabResets; + u32 tcpOutRsts; + u32 tcpCurrEstab; + u32 tcpInSegs_hi; + u32 tcpInSegs_lo; + u32 tcpOutSegs_hi; + u32 tcpOutSegs_lo; + u32 tcpRetransSeg_hi; + u32 tcpRetransSeg_lo; + u32 tcpInErrs_hi; + u32 tcpInErrs_lo; + u32 tcpRtoMin; + u32 tcpRtoMax; +}; + +struct tp_params { + unsigned int nchan; /* # of channels */ + unsigned int pmrx_size; /* total PMRX capacity */ + unsigned int pmtx_size; /* total PMTX capacity */ + unsigned int cm_size; /* total CM capacity */ + unsigned int chan_rx_size; /* per channel Rx size */ + unsigned int chan_tx_size; /* per channel Tx size */ + unsigned int rx_pg_size; /* Rx page size */ + unsigned int tx_pg_size; /* Tx page size */ + unsigned int rx_num_pgs; /* # of Rx pages */ + unsigned int tx_num_pgs; /* # of Tx pages */ + unsigned int ntimer_qs; /* # of timer queues */ +}; + +struct qset_params { /* SGE queue set parameters */ + unsigned int polling; /* polling/interrupt service for rspq */ + unsigned int coalesce_usecs; /* irq coalescing timer */ + unsigned int rspq_size; /* # of entries in response queue */ + unsigned int fl_size; /* # of entries in regular free list */ + unsigned int jumbo_size; /* # of entries in jumbo free list */ + unsigned int txq_size[SGE_TXQ_PER_SET]; /* Tx queue sizes */ + unsigned int cong_thres; /* FL congestion threshold */ +}; + +struct sge_params { + unsigned int max_pkt_size; /* max offload pkt size */ + struct qset_params qset[SGE_QSETS]; +}; + +struct mc5_params { + unsigned int mode; /* selects MC5 width */ + unsigned int nservers; /* size of server region */ + unsigned int nfilters; /* size of filter region */ + unsigned int nroutes; /* size of routing region */ +}; + +/* Default MC5 region sizes */ +enum { + DEFAULT_NSERVERS = 512, + DEFAULT_NFILTERS = 128 +}; + +/* MC5 modes, these must be non-0 */ +enum { + MC5_MODE_144_BIT = 1, + MC5_MODE_72_BIT = 2 +}; + +struct vpd_params { + unsigned int cclk; + unsigned int mclk; + unsigned int uclk; + unsigned int mdc; + unsigned int mem_timing; + u8 eth_base[6]; + u8 port_type[MAX_NPORTS]; + unsigned short xauicfg[2]; +}; + +struct pci_params { + unsigned int vpd_cap_addr; + unsigned int pcie_cap_addr; + unsigned short speed; + unsigned char width; + unsigned char variant; +}; + +enum { + PCI_VARIANT_PCI, + PCI_VARIANT_PCIX_MODE1_PARITY, + PCI_VARIANT_PCIX_MODE1_ECC, + PCI_VARIANT_PCIX_266_MODE2, + PCI_VARIANT_PCIE +}; + +struct adapter_params { + struct sge_params sge; + struct mc5_params mc5; + struct tp_params tp; + struct vpd_params vpd; + struct pci_params pci; + + const struct adapter_info *info; + + unsigned short mtus[NMTUS]; + unsigned short a_wnd[NCCTRL_WIN]; + unsigned short b_wnd[NCCTRL_WIN]; + + unsigned int nports; /* # of ethernet ports */ + unsigned int stats_update_period; /* MAC stats accumulation period */ + unsigned int linkpoll_period; /* link poll period in 0.1s */ + unsigned int rev; /* chip revision */ +}; + +struct trace_params { + u32 sip; + u32 sip_mask; + u32 dip; + u32 dip_mask; + u16 sport; + u16 sport_mask; + u16 dport; + u16 dport_mask; + u32 vlan:12; + u32 vlan_mask:12; + u32 intf:4; + u32 intf_mask:4; + u8 proto; + u8 proto_mask; +}; + +struct link_config { + unsigned int supported; /* link capabilities */ + unsigned int advertising; /* advertised capabilities */ + unsigned short requested_speed; /* speed user has requested */ + unsigned short speed; /* actual link speed */ + unsigned char requested_duplex; /* duplex user has requested */ + unsigned char duplex; /* actual link duplex */ + unsigned char requested_fc; /* flow control user has requested */ + unsigned char fc; /* actual link flow control */ + unsigned char autoneg; /* autonegotiating? */ + unsigned int link_ok; /* link up? */ +}; + +#define SPEED_INVALID 0xffff +#define DUPLEX_INVALID 0xff + +struct mc5 { + struct adapter *adapter; + unsigned int tcam_size; + unsigned char part_type; + unsigned char parity_enabled; + unsigned char mode; + struct mc5_stats stats; +}; + +static inline unsigned int t3_mc5_size(const struct mc5 *p) +{ + return p->tcam_size; +} + +struct mc7 { + struct adapter *adapter; /* backpointer to adapter */ + unsigned int size; /* memory size in bytes */ + unsigned int width; /* MC7 interface width */ + unsigned int offset; /* register address offset for MC7 instance */ + const char *name; /* name of MC7 instance */ + struct mc7_stats stats; /* MC7 statistics */ +}; + +static inline unsigned int t3_mc7_size(const struct mc7 *p) +{ + return p->size; +} + +struct cmac { + struct adapter *adapter; + unsigned int offset; + unsigned int nucast; /* # of address filters for unicast MACs */ + struct mac_stats stats; +}; + +enum { + MAC_DIRECTION_RX = 1, + MAC_DIRECTION_TX = 2, + MAC_RXFIFO_SIZE = 32768 +}; + +/* IEEE 802.3ae specified MDIO devices */ +enum { + MDIO_DEV_PMA_PMD = 1, + MDIO_DEV_WIS = 2, + MDIO_DEV_PCS = 3, + MDIO_DEV_XGXS = 4 +}; + +/* PHY loopback direction */ +enum { + PHY_LOOPBACK_TX = 1, + PHY_LOOPBACK_RX = 2 +}; + +/* PHY interrupt types */ +enum { + cphy_cause_link_change = 1, + cphy_cause_fifo_error = 2 +}; + +/* PHY operations */ +struct cphy_ops { + void (*destroy)(struct cphy *phy); + int (*reset)(struct cphy *phy, int wait); + + int (*intr_enable)(struct cphy *phy); + int (*intr_disable)(struct cphy *phy); + int (*intr_clear)(struct cphy *phy); + int (*intr_handler)(struct cphy *phy); + + int (*autoneg_enable)(struct cphy *phy); + int (*autoneg_restart)(struct cphy *phy); + + int (*advertise)(struct cphy *phy, unsigned int advertise_map); + int (*set_loopback)(struct cphy *phy, int mmd, int dir, int enable); + int (*set_speed_duplex)(struct cphy *phy, int speed, int duplex); + int (*get_link_status)(struct cphy *phy, int *link_ok, int *speed, + int *duplex, int *fc); + int (*power_down)(struct cphy *phy, int enable); +}; + +/* A PHY instance */ +struct cphy { + int addr; /* PHY address */ + struct adapter *adapter; /* associated adapter */ + unsigned long fifo_errors; /* FIFO over/under-flows */ + const struct cphy_ops *ops; /* PHY operations */ + int (*mdio_read)(struct adapter *adapter, int phy_addr, int mmd_addr, + int reg_addr, unsigned int *val); + int (*mdio_write)(struct adapter *adapter, int phy_addr, int mmd_addr, + int reg_addr, unsigned int val); +}; + +/* Convenience MDIO read/write wrappers */ +static inline int mdio_read(struct cphy *phy, int mmd, int reg, + unsigned int *valp) +{ + return phy->mdio_read(phy->adapter, phy->addr, mmd, reg, valp); +} + +static inline int mdio_write(struct cphy *phy, int mmd, int reg, + unsigned int val) +{ + return phy->mdio_write(phy->adapter, phy->addr, mmd, reg, val); +} + +/* Convenience initializer */ +static inline void cphy_init(struct cphy *phy, struct adapter *adapter, + int phy_addr, struct cphy_ops *phy_ops, + const struct mdio_ops *mdio_ops) +{ + phy->adapter = adapter; + phy->addr = phy_addr; + phy->ops = phy_ops; + if (mdio_ops) { + phy->mdio_read = mdio_ops->read; + phy->mdio_write = mdio_ops->write; + } +} + +/* Accumulate MAC statistics every 180 seconds. For 1G we multiply by 10. */ +#define MAC_STATS_ACCUM_SECS 180 + +#define XGM_REG(reg_addr, idx) \ + ((reg_addr) + (idx) * (XGMAC0_1_BASE_ADDR - XGMAC0_0_BASE_ADDR)) + +struct addr_val_pair { + unsigned int reg_addr; + unsigned int val; +}; + +#include "adapter.h" + +#ifndef PCI_VENDOR_ID_CHELSIO +# define PCI_VENDOR_ID_CHELSIO 0x1425 +#endif + +#define for_each_port(adapter, iter) \ + for (iter = 0; iter < (adapter)->params.nports; ++iter) + +#define adapter_info(adap) ((adap)->params.info) + +static inline int uses_xaui(const struct adapter *adap) +{ + return adapter_info(adap)->caps & SUPPORTED_AUI; +} + +static inline int is_10G(const struct adapter *adap) +{ + return adapter_info(adap)->caps & SUPPORTED_10000baseT_Full; +} + +static inline int is_offload(const struct adapter *adap) +{ + return adapter_info(adap)->caps & SUPPORTED_OFFLOAD; +} + +static inline unsigned int core_ticks_per_usec(const struct adapter *adap) +{ + return adap->params.vpd.cclk / 1000; +} + +static inline unsigned int is_pcie(const struct adapter *adap) +{ + return adap->params.pci.variant == PCI_VARIANT_PCIE; +} + +void t3_set_reg_field(struct adapter *adap, unsigned int addr, u32 mask, + u32 val); +void t3_write_regs(struct adapter *adapter, const struct addr_val_pair *p, + int n, unsigned int offset); +int t3_wait_op_done_val(struct adapter *adapter, int reg, u32 mask, + int polarity, int attempts, int delay, u32 *valp); +static inline int t3_wait_op_done(struct adapter *adapter, int reg, u32 mask, + int polarity, int attempts, int delay) +{ + return t3_wait_op_done_val(adapter, reg, mask, polarity, attempts, + delay, NULL); +} +int t3_mdio_change_bits(struct cphy *phy, int mmd, int reg, unsigned int clear, + unsigned int set); +int t3_phy_reset(struct cphy *phy, int mmd, int wait); +int t3_phy_advertise(struct cphy *phy, unsigned int advert); +int t3_set_phy_speed_duplex(struct cphy *phy, int speed, int duplex); + +void t3_intr_enable(struct adapter *adapter); +void t3_intr_disable(struct adapter *adapter); +void t3_intr_clear(struct adapter *adapter); +void t3_port_intr_enable(struct adapter *adapter, int idx); +void t3_port_intr_disable(struct adapter *adapter, int idx); +void t3_port_intr_clear(struct adapter *adapter, int idx); +int t3_slow_intr_handler(struct adapter *adapter); +int t3_phy_intr_handler(struct adapter *adapter); + +void t3_link_changed(struct adapter *adapter, int port_id); +int t3_link_start(struct cphy *phy, struct cmac *mac, struct link_config *lc); +const struct adapter_info *t3_get_adapter_info(unsigned int board_id); +int t3_seeprom_read(struct adapter *adapter, u32 addr, u32 *data); +int t3_seeprom_write(struct adapter *adapter, u32 addr, u32 data); +int t3_seeprom_wp(struct adapter *adapter, int enable); +int t3_read_flash(struct adapter *adapter, unsigned int addr, + unsigned int nwords, u32 *data, int byte_oriented); +int t3_load_fw(struct adapter *adapter, const u8 * fw_data, unsigned int size); +int t3_get_fw_version(struct adapter *adapter, u32 *vers); +int t3_check_fw_version(struct adapter *adapter); +int t3_init_hw(struct adapter *adapter, u32 fw_params); +void mac_prep(struct cmac *mac, struct adapter *adapter, int index); +void early_hw_init(struct adapter *adapter, const struct adapter_info *ai); +int t3_prep_adapter(struct adapter *adapter, const struct adapter_info *ai, + int reset); +void t3_led_ready(struct adapter *adapter); +void t3_fatal_err(struct adapter *adapter); +void t3_set_vlan_accel(struct adapter *adapter, unsigned int ports, int on); +void t3_config_rss(struct adapter *adapter, unsigned int rss_config, + const u8 * cpus, const u16 *rspq); +int t3_read_rss(struct adapter *adapter, u8 * lkup, u16 *map); +int t3_mps_set_active_ports(struct adapter *adap, unsigned int port_mask); +int t3_cim_ctl_blk_read(struct adapter *adap, unsigned int addr, + unsigned int n, unsigned int *valp); +int t3_mc7_bd_read(struct mc7 *mc7, unsigned int start, unsigned int n, + u64 *buf); + +int t3_mac_reset(struct cmac *mac); +void t3b_pcs_reset(struct cmac *mac); +int t3_mac_enable(struct cmac *mac, int which); +int t3_mac_disable(struct cmac *mac, int which); +int t3_mac_set_mtu(struct cmac *mac, unsigned int mtu); +int t3_mac_set_rx_mode(struct cmac *mac, struct t3_rx_mode *rm); +int t3_mac_set_address(struct cmac *mac, unsigned int idx, u8 addr[6]); +int t3_mac_set_num_ucast(struct cmac *mac, int n); +const struct mac_stats *t3_mac_update_stats(struct cmac *mac); +int t3_mac_set_speed_duplex_fc(struct cmac *mac, int speed, int duplex, int fc); + +void t3_mc5_prep(struct adapter *adapter, struct mc5 *mc5, int mode); +int t3_mc5_init(struct mc5 *mc5, unsigned int nservers, unsigned int nfilters, + unsigned int nroutes); +void t3_mc5_intr_handler(struct mc5 *mc5); +int t3_read_mc5_range(const struct mc5 *mc5, unsigned int start, unsigned int n, + u32 *buf); + +int t3_tp_set_coalescing_size(struct adapter *adap, unsigned int size, int psh); +void t3_tp_set_max_rxsize(struct adapter *adap, unsigned int size); +void t3_tp_set_offload_mode(struct adapter *adap, int enable); +void t3_tp_get_mib_stats(struct adapter *adap, struct tp_mib_stats *tps); +void t3_load_mtus(struct adapter *adap, unsigned short mtus[NMTUS], + unsigned short alpha[NCCTRL_WIN], + unsigned short beta[NCCTRL_WIN], unsigned short mtu_cap); +void t3_read_hw_mtus(struct adapter *adap, unsigned short mtus[NMTUS]); +void t3_get_cong_cntl_tab(struct adapter *adap, + unsigned short incr[NMTUS][NCCTRL_WIN]); +void t3_config_trace_filter(struct adapter *adapter, + const struct trace_params *tp, int filter_index, + int invert, int enable); +int t3_config_sched(struct adapter *adap, unsigned int kbps, int sched); + +void t3_sge_prep(struct adapter *adap, struct sge_params *p); +void t3_sge_init(struct adapter *adap, struct sge_params *p); +int t3_sge_init_ecntxt(struct adapter *adapter, unsigned int id, int gts_enable, + enum sge_context_type type, int respq, u64 base_addr, + unsigned int size, unsigned int token, int gen, + unsigned int cidx); +int t3_sge_init_flcntxt(struct adapter *adapter, unsigned int id, + int gts_enable, u64 base_addr, unsigned int size, + unsigned int esize, unsigned int cong_thres, int gen, + unsigned int cidx); +int t3_sge_init_rspcntxt(struct adapter *adapter, unsigned int id, + int irq_vec_idx, u64 base_addr, unsigned int size, + unsigned int fl_thres, int gen, unsigned int cidx); +int t3_sge_init_cqcntxt(struct adapter *adapter, unsigned int id, u64 base_addr, + unsigned int size, int rspq, int ovfl_mode, + unsigned int credits, unsigned int credit_thres); +int t3_sge_enable_ecntxt(struct adapter *adapter, unsigned int id, int enable); +int t3_sge_disable_fl(struct adapter *adapter, unsigned int id); +int t3_sge_disable_rspcntxt(struct adapter *adapter, unsigned int id); +int t3_sge_disable_cqcntxt(struct adapter *adapter, unsigned int id); +int t3_sge_read_ecntxt(struct adapter *adapter, unsigned int id, u32 data[4]); +int t3_sge_read_fl(struct adapter *adapter, unsigned int id, u32 data[4]); +int t3_sge_read_cq(struct adapter *adapter, unsigned int id, u32 data[4]); +int t3_sge_read_rspq(struct adapter *adapter, unsigned int id, u32 data[4]); +int t3_sge_cqcntxt_op(struct adapter *adapter, unsigned int id, unsigned int op, + unsigned int credits); + +void t3_vsc8211_phy_prep(struct cphy *phy, struct adapter *adapter, + int phy_addr, const struct mdio_ops *mdio_ops); +void t3_ael1002_phy_prep(struct cphy *phy, struct adapter *adapter, + int phy_addr, const struct mdio_ops *mdio_ops); +void t3_ael1006_phy_prep(struct cphy *phy, struct adapter *adapter, + int phy_addr, const struct mdio_ops *mdio_ops); +void t3_qt2045_phy_prep(struct cphy *phy, struct adapter *adapter, int phy_addr, + const struct mdio_ops *mdio_ops); +void t3_xaui_direct_phy_prep(struct cphy *phy, struct adapter *adapter, + int phy_addr, const struct mdio_ops *mdio_ops); +#endif /* __CHELSIO_COMMON_H */ diff --git a/drivers/net/cxgb3/cxgb3_ctl_defs.h b/drivers/net/cxgb3/cxgb3_ctl_defs.h new file mode 100644 index 0000000..2095dda --- /dev/null +++ b/drivers/net/cxgb3/cxgb3_ctl_defs.h @@ -0,0 +1,164 @@ +/* + * Copyright (c) 2003-2007 Chelsio, Inc. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +#ifndef _CXGB3_OFFLOAD_CTL_DEFS_H +#define _CXGB3_OFFLOAD_CTL_DEFS_H + +enum { + GET_MAX_OUTSTANDING_WR, + GET_TX_MAX_CHUNK, + GET_TID_RANGE, + GET_STID_RANGE, + GET_RTBL_RANGE, + GET_L2T_CAPACITY, + GET_MTUS, + GET_WR_LEN, + GET_IFF_FROM_MAC, + GET_DDP_PARAMS, + GET_PORTS, + + ULP_ISCSI_GET_PARAMS, + ULP_ISCSI_SET_PARAMS, + + RDMA_GET_PARAMS, + RDMA_CQ_OP, + RDMA_CQ_SETUP, + RDMA_CQ_DISABLE, + RDMA_CTRL_QP_SETUP, + RDMA_GET_MEM, +}; + +/* + * Structure used to describe a TID range. Valid TIDs are [base, base+num). + */ +struct tid_range { + unsigned int base; /* first TID */ + unsigned int num; /* number of TIDs in range */ +}; + +/* + * Structure used to request the size and contents of the MTU table. + */ +struct mtutab { + unsigned int size; /* # of entries in the MTU table */ + const unsigned short *mtus; /* the MTU table values */ +}; + +struct net_device; + +/* + * Structure used to request the adapter net_device owning a given MAC address. + */ +struct iff_mac { + struct net_device *dev; /* the net_device */ + const unsigned char *mac_addr; /* MAC address to lookup */ + u16 vlan_tag; +}; + +struct pci_dev; + +/* + * Structure used to request the TCP DDP parameters. + */ +struct ddp_params { + unsigned int llimit; /* TDDP region start address */ + unsigned int ulimit; /* TDDP region end address */ + unsigned int tag_mask; /* TDDP tag mask */ + struct pci_dev *pdev; +}; + +struct adap_ports { + unsigned int nports; /* number of ports on this adapter */ + struct net_device *lldevs[2]; +}; + +/* + * Structure used to return information to the iscsi layer. + */ +struct ulp_iscsi_info { + unsigned int offset; + unsigned int llimit; + unsigned int ulimit; + unsigned int tagmask; + unsigned int pgsz3; + unsigned int pgsz2; + unsigned int pgsz1; + unsigned int pgsz0; + unsigned int max_rxsz; + unsigned int max_txsz; + struct pci_dev *pdev; +}; + +/* + * Structure used to return information to the RDMA layer. + */ +struct rdma_info { + unsigned int tpt_base; /* TPT base address */ + unsigned int tpt_top; /* TPT last entry address */ + unsigned int pbl_base; /* PBL base address */ + unsigned int pbl_top; /* PBL last entry address */ + unsigned int rqt_base; /* RQT base address */ + unsigned int rqt_top; /* RQT last entry address */ + unsigned int udbell_len; /* user doorbell region length */ + unsigned long udbell_physbase; /* user doorbell physical start addr */ + void __iomem *kdb_addr; /* kernel doorbell register address */ + struct pci_dev *pdev; /* associated PCI device */ +}; + +/* + * Structure used to request an operation on an RDMA completion queue. + */ +struct rdma_cq_op { + unsigned int id; + unsigned int op; + unsigned int credits; +}; + +/* + * Structure used to setup RDMA completion queues. + */ +struct rdma_cq_setup { + unsigned int id; + unsigned long long base_addr; + unsigned int size; + unsigned int credits; + unsigned int credit_thres; + unsigned int ovfl_mode; +}; + +/* + * Structure used to setup the RDMA control egress context. + */ +struct rdma_ctrlqp_setup { + unsigned long long base_addr; + unsigned int size; +}; +#endif /* _CXGB3_OFFLOAD_CTL_DEFS_H */ diff --git a/drivers/net/cxgb3/cxgb3_defs.h b/drivers/net/cxgb3/cxgb3_defs.h new file mode 100644 index 0000000..16e0049 --- /dev/null +++ b/drivers/net/cxgb3/cxgb3_defs.h @@ -0,0 +1,99 @@ +/* + * Copyright (c) 2006-2007 Chelsio, Inc. All rights reserved. + * Copyright (c) 2006-2007 Open Grid Computing, Inc. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +#ifndef _CHELSIO_DEFS_H +#define _CHELSIO_DEFS_H + +#include +#include + +#include "t3cdev.h" + +#include "cxgb3_offload.h" + +#define VALIDATE_TID 1 + +void *cxgb_alloc_mem(unsigned long size); +void cxgb_free_mem(void *addr); +void cxgb_neigh_update(struct neighbour *neigh); +void cxgb_redirect(struct dst_entry *old, struct dst_entry *new); + +/* + * Map an ATID or STID to their entries in the corresponding TID tables. + */ +static inline union active_open_entry *atid2entry(const struct tid_info *t, + unsigned int atid) +{ + return &t->atid_tab[atid - t->atid_base]; +} + +static inline union listen_entry *stid2entry(const struct tid_info *t, + unsigned int stid) +{ + return &t->stid_tab[stid - t->stid_base]; +} + +/* + * Find the connection corresponding to a TID. + */ +static inline struct t3c_tid_entry *lookup_tid(const struct tid_info *t, + unsigned int tid) +{ + return tid < t->ntids ? &(t->tid_tab[tid]) : NULL; +} + +/* + * Find the connection corresponding to a server TID. + */ +static inline struct t3c_tid_entry *lookup_stid(const struct tid_info *t, + unsigned int tid) +{ + if (tid < t->stid_base || tid >= t->stid_base + t->nstids) + return NULL; + return &(stid2entry(t, tid)->t3c_tid); +} + +/* + * Find the connection corresponding to an active-open TID. + */ +static inline struct t3c_tid_entry *lookup_atid(const struct tid_info *t, + unsigned int tid) +{ + if (tid < t->atid_base || tid >= t->atid_base + t->natids) + return NULL; + return &(atid2entry(t, tid)->t3c_tid); +} + +int process_rx(struct t3cdev *dev, struct sk_buff **skbs, int n); +int attach_t3cdev(struct t3cdev *dev); +void detach_t3cdev(struct t3cdev *dev); +#endif diff --git a/drivers/net/cxgb3/cxgb3_ioctl.h b/drivers/net/cxgb3/cxgb3_ioctl.h new file mode 100644 index 0000000..a942818 --- /dev/null +++ b/drivers/net/cxgb3/cxgb3_ioctl.h @@ -0,0 +1,185 @@ +/* + * Copyright (c) 2003-2007 Chelsio, Inc. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +#ifndef __CHIOCTL_H__ +#define __CHIOCTL_H__ + +/* + * Ioctl commands specific to this driver. + */ +enum { + CHELSIO_SETREG = 1024, + CHELSIO_GETREG, + CHELSIO_SETTPI, + CHELSIO_GETTPI, + CHELSIO_GETMTUTAB, + CHELSIO_SETMTUTAB, + CHELSIO_GETMTU, + CHELSIO_SET_PM, + CHELSIO_GET_PM, + CHELSIO_GET_TCAM, + CHELSIO_SET_TCAM, + CHELSIO_GET_TCB, + CHELSIO_GET_MEM, + CHELSIO_LOAD_FW, + CHELSIO_GET_PROTO, + CHELSIO_SET_PROTO, + CHELSIO_SET_TRACE_FILTER, + CHELSIO_SET_QSET_PARAMS, + CHELSIO_GET_QSET_PARAMS, + CHELSIO_SET_QSET_NUM, + CHELSIO_GET_QSET_NUM, + CHELSIO_SET_PKTSCHED, +}; + +struct ch_reg { + uint32_t cmd; + uint32_t addr; + uint32_t val; +}; + +struct ch_cntxt { + uint32_t cmd; + uint32_t cntxt_type; + uint32_t cntxt_id; + uint32_t data[4]; +}; + +/* context types */ +enum { CNTXT_TYPE_EGRESS, CNTXT_TYPE_FL, CNTXT_TYPE_RSP, CNTXT_TYPE_CQ }; + +struct ch_desc { + uint32_t cmd; + uint32_t queue_num; + uint32_t idx; + uint32_t size; + uint8_t data[128]; +}; + +struct ch_mem_range { + uint32_t cmd; + uint32_t mem_id; + uint32_t addr; + uint32_t len; + uint32_t version; + uint8_t buf[0]; +}; + +struct ch_qset_params { + uint32_t cmd; + uint32_t qset_idx; + int32_t txq_size[3]; + int32_t rspq_size; + int32_t fl_size[2]; + int32_t intr_lat; + int32_t polling; + int32_t cong_thres; +}; + +struct ch_pktsched_params { + uint32_t cmd; + uint8_t sched; + uint8_t idx; + uint8_t min; + uint8_t max; + uint8_t binding; +}; + +#ifndef TCB_SIZE +# define TCB_SIZE 128 +#endif + +/* TCB size in 32-bit words */ +#define TCB_WORDS (TCB_SIZE / 4) + +enum { MEM_CM, MEM_PMRX, MEM_PMTX }; /* ch_mem_range.mem_id values */ + +struct ch_mtus { + uint32_t cmd; + uint32_t nmtus; + uint16_t mtus[NMTUS]; +}; + +struct ch_pm { + uint32_t cmd; + uint32_t tx_pg_sz; + uint32_t tx_num_pg; + uint32_t rx_pg_sz; + uint32_t rx_num_pg; + uint32_t pm_total; +}; + +struct ch_tcam { + uint32_t cmd; + uint32_t tcam_size; + uint32_t nservers; + uint32_t nroutes; + uint32_t nfilters; +}; + +struct ch_tcb { + uint32_t cmd; + uint32_t tcb_index; + uint32_t tcb_data[TCB_WORDS]; +}; + +struct ch_tcam_word { + uint32_t cmd; + uint32_t addr; + uint32_t buf[3]; +}; + +struct ch_trace { + uint32_t cmd; + uint32_t sip; + uint32_t sip_mask; + uint32_t dip; + uint32_t dip_mask; + uint16_t sport; + uint16_t sport_mask; + uint16_t dport; + uint16_t dport_mask; + uint32_t vlan:12; + uint32_t vlan_mask:12; + uint32_t intf:4; + uint32_t intf_mask:4; + uint8_t proto; + uint8_t proto_mask; + uint8_t invert_match:1; + uint8_t config_tx:1; + uint8_t config_rx:1; + uint8_t trace_tx:1; + uint8_t trace_rx:1; +}; + +#define SIOCCHIOCTL SIOCDEVPRIVATE + +#endif diff --git a/drivers/net/cxgb3/cxgb3_main.c b/drivers/net/cxgb3/cxgb3_main.c new file mode 100644 index 0000000..43583ed --- /dev/null +++ b/drivers/net/cxgb3/cxgb3_main.c @@ -0,0 +1,2520 @@ +/* + * Copyright (c) 2003-2007 Chelsio, Inc. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "common.h" +#include "cxgb3_ioctl.h" +#include "regs.h" +#include "cxgb3_offload.h" +#include "version.h" + +#include "cxgb3_ctl_defs.h" +#include "t3_cpl.h" +#include "firmware_exports.h" + +enum { + MAX_TXQ_ENTRIES = 16384, + MAX_CTRL_TXQ_ENTRIES = 1024, + MAX_RSPQ_ENTRIES = 16384, + MAX_RX_BUFFERS = 16384, + MAX_RX_JUMBO_BUFFERS = 16384, + MIN_TXQ_ENTRIES = 4, + MIN_CTRL_TXQ_ENTRIES = 4, + MIN_RSPQ_ENTRIES = 32, + MIN_FL_ENTRIES = 32 +}; + +#define PORT_MASK ((1 << MAX_NPORTS) - 1) + +#define DFLT_MSG_ENABLE (NETIF_MSG_DRV | NETIF_MSG_PROBE | NETIF_MSG_LINK | \ + NETIF_MSG_TIMER | NETIF_MSG_IFDOWN | NETIF_MSG_IFUP |\ + NETIF_MSG_RX_ERR | NETIF_MSG_TX_ERR) + +#define EEPROM_MAGIC 0x38E2F10C + +#define CH_DEVICE(devid, ssid, idx) \ + { PCI_VENDOR_ID_CHELSIO, devid, PCI_ANY_ID, ssid, 0, 0, idx } + +static const struct pci_device_id cxgb3_pci_tbl[] = { + CH_DEVICE(0x20, 1, 0), /* PE9000 */ + CH_DEVICE(0x21, 1, 1), /* T302E */ + CH_DEVICE(0x22, 1, 2), /* T310E */ + CH_DEVICE(0x23, 1, 3), /* T320X */ + CH_DEVICE(0x24, 1, 1), /* T302X */ + CH_DEVICE(0x25, 1, 3), /* T320E */ + CH_DEVICE(0x26, 1, 2), /* T310X */ + CH_DEVICE(0x30, 1, 2), /* T3B10 */ + CH_DEVICE(0x31, 1, 3), /* T3B20 */ + CH_DEVICE(0x32, 1, 1), /* T3B02 */ + {0,} +}; + +MODULE_DESCRIPTION(DRV_DESC); +MODULE_AUTHOR("Chelsio Communications"); +MODULE_LICENSE("Dual BSD/GPL"); +MODULE_VERSION(DRV_VERSION); +MODULE_DEVICE_TABLE(pci, cxgb3_pci_tbl); + +static int dflt_msg_enable = DFLT_MSG_ENABLE; + +module_param(dflt_msg_enable, int, 0644); +MODULE_PARM_DESC(dflt_msg_enable, "Chelsio T3 default message enable bitmap"); + +/* + * The driver uses the best interrupt scheme available on a platform in the + * order MSI-X, MSI, legacy pin interrupts. This parameter determines which + * of these schemes the driver may consider as follows: + * + * msi = 2: choose from among all three options + * msi = 1: only consider MSI and pin interrupts + * msi = 0: force pin interrupts + */ +static int msi = 2; + +module_param(msi, int, 0644); +MODULE_PARM_DESC(msi, "whether to use MSI or MSI-X"); + +/* + * The driver enables offload as a default. + * To disable it, use ofld_disable = 1. + */ + +static int ofld_disable = 0; + +module_param(ofld_disable, int, 0644); +MODULE_PARM_DESC(ofld_disable, "whether to enable offload at init time or not"); + +/* + * We have work elements that we need to cancel when an interface is taken + * down. Normally the work elements would be executed by keventd but that + * can deadlock because of linkwatch. If our close method takes the rtnl + * lock and linkwatch is ahead of our work elements in keventd, linkwatch + * will block keventd as it needs the rtnl lock, and we'll deadlock waiting + * for our work to complete. Get our own work queue to solve this. + */ +static struct workqueue_struct *cxgb3_wq; + +/** + * link_report - show link status and link speed/duplex + * @p: the port whose settings are to be reported + * + * Shows the link status, speed, and duplex of a port. + */ +static void link_report(struct net_device *dev) +{ + if (!netif_carrier_ok(dev)) + printk(KERN_INFO "%s: link down\n", dev->name); + else { + const char *s = "10Mbps"; + const struct port_info *p = netdev_priv(dev); + + switch (p->link_config.speed) { + case SPEED_10000: + s = "10Gbps"; + break; + case SPEED_1000: + s = "1000Mbps"; + break; + case SPEED_100: + s = "100Mbps"; + break; + } + + printk(KERN_INFO "%s: link up, %s, %s-duplex\n", dev->name, s, + p->link_config.duplex == DUPLEX_FULL ? "full" : "half"); + } +} + +/** + * t3_os_link_changed - handle link status changes + * @adapter: the adapter associated with the link change + * @port_id: the port index whose limk status has changed + * @link_stat: the new status of the link + * @speed: the new speed setting + * @duplex: the new duplex setting + * @pause: the new flow-control setting + * + * This is the OS-dependent handler for link status changes. The OS + * neutral handler takes care of most of the processing for these events, + * then calls this handler for any OS-specific processing. + */ +void t3_os_link_changed(struct adapter *adapter, int port_id, int link_stat, + int speed, int duplex, int pause) +{ + struct net_device *dev = adapter->port[port_id]; + + /* Skip changes from disabled ports. */ + if (!netif_running(dev)) + return; + + if (link_stat != netif_carrier_ok(dev)) { + if (link_stat) + netif_carrier_on(dev); + else + netif_carrier_off(dev); + link_report(dev); + } +} + +static void cxgb_set_rxmode(struct net_device *dev) +{ + struct t3_rx_mode rm; + struct port_info *pi = netdev_priv(dev); + + init_rx_mode(&rm, dev, dev->mc_list); + t3_mac_set_rx_mode(&pi->mac, &rm); +} + +/** + * link_start - enable a port + * @dev: the device to enable + * + * Performs the MAC and PHY actions needed to enable a port. + */ +static void link_start(struct net_device *dev) +{ + struct t3_rx_mode rm; + struct port_info *pi = netdev_priv(dev); + struct cmac *mac = &pi->mac; + + init_rx_mode(&rm, dev, dev->mc_list); + t3_mac_reset(mac); + t3_mac_set_mtu(mac, dev->mtu); + t3_mac_set_address(mac, 0, dev->dev_addr); + t3_mac_set_rx_mode(mac, &rm); + t3_link_start(&pi->phy, mac, &pi->link_config); + t3_mac_enable(mac, MAC_DIRECTION_RX | MAC_DIRECTION_TX); +} + +static inline void cxgb_disable_msi(struct adapter *adapter) +{ + if (adapter->flags & USING_MSIX) { + pci_disable_msix(adapter->pdev); + adapter->flags &= ~USING_MSIX; + } else if (adapter->flags & USING_MSI) { + pci_disable_msi(adapter->pdev); + adapter->flags &= ~USING_MSI; + } +} + +/* + * Interrupt handler for asynchronous events used with MSI-X. + */ +static irqreturn_t t3_async_intr_handler(int irq, void *cookie) +{ + t3_slow_intr_handler(cookie); + return IRQ_HANDLED; +} + +/* + * Name the MSI-X interrupts. + */ +static void name_msix_vecs(struct adapter *adap) +{ + int i, j, msi_idx = 1, n = sizeof(adap->msix_info[0].desc) - 1; + + snprintf(adap->msix_info[0].desc, n, "%s", adap->name); + adap->msix_info[0].desc[n] = 0; + + for_each_port(adap, j) { + struct net_device *d = adap->port[j]; + const struct port_info *pi = netdev_priv(d); + + for (i = 0; i < pi->nqsets; i++, msi_idx++) { + snprintf(adap->msix_info[msi_idx].desc, n, + "%s (queue %d)", d->name, i); + adap->msix_info[msi_idx].desc[n] = 0; + } + } +} + +static int request_msix_data_irqs(struct adapter *adap) +{ + int i, j, err, qidx = 0; + + for_each_port(adap, i) { + int nqsets = adap2pinfo(adap, i)->nqsets; + + for (j = 0; j < nqsets; ++j) { + err = request_irq(adap->msix_info[qidx + 1].vec, + t3_intr_handler(adap, + adap->sge.qs[qidx]. + rspq.polling), 0, + adap->msix_info[qidx + 1].desc, + &adap->sge.qs[qidx]); + if (err) { + while (--qidx >= 0) + free_irq(adap->msix_info[qidx + 1].vec, + &adap->sge.qs[qidx]); + return err; + } + qidx++; + } + } + return 0; +} + +/** + * setup_rss - configure RSS + * @adap: the adapter + * + * Sets up RSS to distribute packets to multiple receive queues. We + * configure the RSS CPU lookup table to distribute to the number of HW + * receive queues, and the response queue lookup table to narrow that + * down to the response queues actually configured for each port. + * We always configure the RSS mapping for two ports since the mapping + * table has plenty of entries. + */ +static void setup_rss(struct adapter *adap) +{ + int i; + unsigned int nq0 = adap2pinfo(adap, 0)->nqsets; + unsigned int nq1 = adap->port[1] ? adap2pinfo(adap, 1)->nqsets : 1; + u8 cpus[SGE_QSETS + 1]; + u16 rspq_map[RSS_TABLE_SIZE]; + + for (i = 0; i < SGE_QSETS; ++i) + cpus[i] = i; + cpus[SGE_QSETS] = 0xff; /* terminator */ + + for (i = 0; i < RSS_TABLE_SIZE / 2; ++i) { + rspq_map[i] = i % nq0; + rspq_map[i + RSS_TABLE_SIZE / 2] = (i % nq1) + nq0; + } + + t3_config_rss(adap, F_RQFEEDBACKENABLE | F_TNLLKPEN | F_TNLMAPEN | + F_TNLPRTEN | F_TNL2TUPEN | F_TNL4TUPEN | + V_RRCPLCPUSIZE(6), cpus, rspq_map); +} + +/* + * If we have multiple receive queues per port serviced by NAPI we need one + * netdevice per queue as NAPI operates on netdevices. We already have one + * netdevice, namely the one associated with the interface, so we use dummy + * ones for any additional queues. Note that these netdevices exist purely + * so that NAPI has something to work with, they do not represent network + * ports and are not registered. + */ +static int init_dummy_netdevs(struct adapter *adap) +{ + int i, j, dummy_idx = 0; + struct net_device *nd; + + for_each_port(adap, i) { + struct net_device *dev = adap->port[i]; + const struct port_info *pi = netdev_priv(dev); + + for (j = 0; j < pi->nqsets - 1; j++) { + if (!adap->dummy_netdev[dummy_idx]) { + nd = alloc_netdev(0, "", ether_setup); + if (!nd) + goto free_all; + + nd->priv = adap; + nd->weight = 64; + set_bit(__LINK_STATE_START, &nd->state); + adap->dummy_netdev[dummy_idx] = nd; + } + strcpy(adap->dummy_netdev[dummy_idx]->name, dev->name); + dummy_idx++; + } + } + return 0; + +free_all: + while (--dummy_idx >= 0) { + free_netdev(adap->dummy_netdev[dummy_idx]); + adap->dummy_netdev[dummy_idx] = NULL; + } + return -ENOMEM; +} + +/* + * Wait until all NAPI handlers are descheduled. This includes the handlers of + * both netdevices representing interfaces and the dummy ones for the extra + * queues. + */ +static void quiesce_rx(struct adapter *adap) +{ + int i; + struct net_device *dev; + + for_each_port(adap, i) { + dev = adap->port[i]; + while (test_bit(__LINK_STATE_RX_SCHED, &dev->state)) + msleep(1); + } + + for (i = 0; i < ARRAY_SIZE(adap->dummy_netdev); i++) { + dev = adap->dummy_netdev[i]; + if (dev) + while (test_bit(__LINK_STATE_RX_SCHED, &dev->state)) + msleep(1); + } +} + +/** + * setup_sge_qsets - configure SGE Tx/Rx/response queues + * @adap: the adapter + * + * Determines how many sets of SGE queues to use and initializes them. + * We support multiple queue sets per port if we have MSI-X, otherwise + * just one queue set per port. + */ +static int setup_sge_qsets(struct adapter *adap) +{ + int i, j, err, irq_idx = 0, qset_idx = 0, dummy_dev_idx = 0; + unsigned int ntxq = is_offload(adap) ? SGE_TXQ_PER_SET : 1; + + if (adap->params.rev > 0 && !(adap->flags & USING_MSI)) + irq_idx = -1; + + for_each_port(adap, i) { + struct net_device *dev = adap->port[i]; + const struct port_info *pi = netdev_priv(dev); + + for (j = 0; j < pi->nqsets; ++j, ++qset_idx) { + err = t3_sge_alloc_qset(adap, qset_idx, 1, + (adap->flags & USING_MSIX) ? qset_idx + 1 : + irq_idx, + &adap->params.sge.qset[qset_idx], ntxq, + j == 0 ? dev : + adap-> dummy_netdev[dummy_dev_idx++]); + if (err) { + t3_free_sge_resources(adap); + return err; + } + } + } + + return 0; +} + +static ssize_t attr_show(struct device *d, struct device_attribute *attr, + char *buf, + ssize_t(*format) (struct adapter *, char *)) +{ + ssize_t len; + struct adapter *adap = to_net_dev(d)->priv; + + /* Synchronize with ioctls that may shut down the device */ + rtnl_lock(); + len = (*format) (adap, buf); + rtnl_unlock(); + return len; +} + +static ssize_t attr_store(struct device *d, struct device_attribute *attr, + const char *buf, size_t len, + ssize_t(*set) (struct adapter *, unsigned int), + unsigned int min_val, unsigned int max_val) +{ + char *endp; + ssize_t ret; + unsigned int val; + struct adapter *adap = to_net_dev(d)->priv; + + if (!capable(CAP_NET_ADMIN)) + return -EPERM; + + val = simple_strtoul(buf, &endp, 0); + if (endp == buf || val < min_val || val > max_val) + return -EINVAL; + + rtnl_lock(); + ret = (*set) (adap, val); + if (!ret) + ret = len; + rtnl_unlock(); + return ret; +} + +#define CXGB3_SHOW(name, val_expr) \ +static ssize_t format_##name(struct adapter *adap, char *buf) \ +{ \ + return sprintf(buf, "%u\n", val_expr); \ +} \ +static ssize_t show_##name(struct device *d, struct device_attribute *attr, \ + char *buf) \ +{ \ + return attr_show(d, attr, buf, format_##name); \ +} + +static ssize_t set_nfilters(struct adapter *adap, unsigned int val) +{ + if (adap->flags & FULL_INIT_DONE) + return -EBUSY; + if (val && adap->params.rev == 0) + return -EINVAL; + if (val > t3_mc5_size(&adap->mc5) - adap->params.mc5.nservers) + return -EINVAL; + adap->params.mc5.nfilters = val; + return 0; +} + +static ssize_t store_nfilters(struct device *d, struct device_attribute *attr, + const char *buf, size_t len) +{ + return attr_store(d, attr, buf, len, set_nfilters, 0, ~0); +} + +static ssize_t set_nservers(struct adapter *adap, unsigned int val) +{ + if (adap->flags & FULL_INIT_DONE) + return -EBUSY; + if (val > t3_mc5_size(&adap->mc5) - adap->params.mc5.nfilters) + return -EINVAL; + adap->params.mc5.nservers = val; + return 0; +} + +static ssize_t store_nservers(struct device *d, struct device_attribute *attr, + const char *buf, size_t len) +{ + return attr_store(d, attr, buf, len, set_nservers, 0, ~0); +} + +#define CXGB3_ATTR_R(name, val_expr) \ +CXGB3_SHOW(name, val_expr) \ +static DEVICE_ATTR(name, S_IRUGO, show_##name, NULL) + +#define CXGB3_ATTR_RW(name, val_expr, store_method) \ +CXGB3_SHOW(name, val_expr) \ +static DEVICE_ATTR(name, S_IRUGO | S_IWUSR, show_##name, store_method) + +CXGB3_ATTR_R(cam_size, t3_mc5_size(&adap->mc5)); +CXGB3_ATTR_RW(nfilters, adap->params.mc5.nfilters, store_nfilters); +CXGB3_ATTR_RW(nservers, adap->params.mc5.nservers, store_nservers); + +static struct attribute *cxgb3_attrs[] = { + &dev_attr_cam_size.attr, + &dev_attr_nfilters.attr, + &dev_attr_nservers.attr, + NULL +}; + +static struct attribute_group cxgb3_attr_group = {.attrs = cxgb3_attrs }; + +static ssize_t tm_attr_show(struct device *d, struct device_attribute *attr, + char *buf, int sched) +{ + ssize_t len; + unsigned int v, addr, bpt, cpt; + struct adapter *adap = to_net_dev(d)->priv; + + addr = A_TP_TX_MOD_Q1_Q0_RATE_LIMIT - sched / 2; + rtnl_lock(); + t3_write_reg(adap, A_TP_TM_PIO_ADDR, addr); + v = t3_read_reg(adap, A_TP_TM_PIO_DATA); + if (sched & 1) + v >>= 16; + bpt = (v >> 8) & 0xff; + cpt = v & 0xff; + if (!cpt) + len = sprintf(buf, "disabled\n"); + else { + v = (adap->params.vpd.cclk * 1000) / cpt; + len = sprintf(buf, "%u Kbps\n", (v * bpt) / 125); + } + rtnl_unlock(); + return len; +} + +static ssize_t tm_attr_store(struct device *d, struct device_attribute *attr, + const char *buf, size_t len, int sched) +{ + char *endp; + ssize_t ret; + unsigned int val; + struct adapter *adap = to_net_dev(d)->priv; + + if (!capable(CAP_NET_ADMIN)) + return -EPERM; + + val = simple_strtoul(buf, &endp, 0); + if (endp == buf || val > 10000000) + return -EINVAL; + + rtnl_lock(); + ret = t3_config_sched(adap, val, sched); + if (!ret) + ret = len; + rtnl_unlock(); + return ret; +} + +#define TM_ATTR(name, sched) \ +static ssize_t show_##name(struct device *d, struct device_attribute *attr, \ + char *buf) \ +{ \ + return tm_attr_show(d, attr, buf, sched); \ +} \ +static ssize_t store_##name(struct device *d, struct device_attribute *attr, \ + const char *buf, size_t len) \ +{ \ + return tm_attr_store(d, attr, buf, len, sched); \ +} \ +static DEVICE_ATTR(name, S_IRUGO | S_IWUSR, show_##name, store_##name) + +TM_ATTR(sched0, 0); +TM_ATTR(sched1, 1); +TM_ATTR(sched2, 2); +TM_ATTR(sched3, 3); +TM_ATTR(sched4, 4); +TM_ATTR(sched5, 5); +TM_ATTR(sched6, 6); +TM_ATTR(sched7, 7); + +static struct attribute *offload_attrs[] = { + &dev_attr_sched0.attr, + &dev_attr_sched1.attr, + &dev_attr_sched2.attr, + &dev_attr_sched3.attr, + &dev_attr_sched4.attr, + &dev_attr_sched5.attr, + &dev_attr_sched6.attr, + &dev_attr_sched7.attr, + NULL +}; + +static struct attribute_group offload_attr_group = {.attrs = offload_attrs }; + +/* + * Sends an sk_buff to an offload queue driver + * after dealing with any active network taps. + */ +static inline int offload_tx(struct t3cdev *tdev, struct sk_buff *skb) +{ + int ret; + + local_bh_disable(); + ret = t3_offload_tx(tdev, skb); + local_bh_enable(); + return ret; +} + +static int write_smt_entry(struct adapter *adapter, int idx) +{ + struct cpl_smt_write_req *req; + struct sk_buff *skb = alloc_skb(sizeof(*req), GFP_KERNEL); + + if (!skb) + return -ENOMEM; + + req = (struct cpl_smt_write_req *)__skb_put(skb, sizeof(*req)); + req->wr.wr_hi = htonl(V_WR_OP(FW_WROPCODE_FORWARD)); + OPCODE_TID(req) = htonl(MK_OPCODE_TID(CPL_SMT_WRITE_REQ, idx)); + req->mtu_idx = NMTUS - 1; /* should be 0 but there's a T3 bug */ + req->iff = idx; + memset(req->src_mac1, 0, sizeof(req->src_mac1)); + memcpy(req->src_mac0, adapter->port[idx]->dev_addr, ETH_ALEN); + skb->priority = 1; + offload_tx(&adapter->tdev, skb); + return 0; +} + +static int init_smt(struct adapter *adapter) +{ + int i; + + for_each_port(adapter, i) + write_smt_entry(adapter, i); + return 0; +} + +static void init_port_mtus(struct adapter *adapter) +{ + unsigned int mtus = adapter->port[0]->mtu; + + if (adapter->port[1]) + mtus |= adapter->port[1]->mtu << 16; + t3_write_reg(adapter, A_TP_MTU_PORT_TABLE, mtus); +} + +static void send_pktsched_cmd(struct adapter *adap, int sched, int qidx, int lo, + int hi, int port) +{ + struct sk_buff *skb; + struct mngt_pktsched_wr *req; + + skb = alloc_skb(sizeof(*req), GFP_KERNEL | __GFP_NOFAIL); + req = (struct mngt_pktsched_wr *)skb_put(skb, sizeof(*req)); + req->wr_hi = htonl(V_WR_OP(FW_WROPCODE_MNGT)); + req->mngt_opcode = FW_MNGTOPCODE_PKTSCHED_SET; + req->sched = sched; + req->idx = qidx; + req->min = lo; + req->max = hi; + req->binding = port; + t3_mgmt_tx(adap, skb); +} + +static void bind_qsets(struct adapter *adap) +{ + int i, j; + + for_each_port(adap, i) { + const struct port_info *pi = adap2pinfo(adap, i); + + for (j = 0; j < pi->nqsets; ++j) + send_pktsched_cmd(adap, 1, pi->first_qset + j, -1, + -1, i); + } +} + +/** + * cxgb_up - enable the adapter + * @adapter: adapter being enabled + * + * Called when the first port is enabled, this function performs the + * actions necessary to make an adapter operational, such as completing + * the initialization of HW modules, and enabling interrupts. + * + * Must be called with the rtnl lock held. + */ +static int cxgb_up(struct adapter *adap) +{ + int err = 0; + + if (!(adap->flags & FULL_INIT_DONE)) { + err = t3_check_fw_version(adap); + if (err) + goto out; + + err = init_dummy_netdevs(adap); + if (err) + goto out; + + err = t3_init_hw(adap, 0); + if (err) + goto out; + + err = setup_sge_qsets(adap); + if (err) + goto out; + + setup_rss(adap); + adap->flags |= FULL_INIT_DONE; + } + + t3_intr_clear(adap); + + if (adap->flags & USING_MSIX) { + name_msix_vecs(adap); + err = request_irq(adap->msix_info[0].vec, + t3_async_intr_handler, 0, + adap->msix_info[0].desc, adap); + if (err) + goto irq_err; + + if (request_msix_data_irqs(adap)) { + free_irq(adap->msix_info[0].vec, adap); + goto irq_err; + } + } else if ((err = request_irq(adap->pdev->irq, + t3_intr_handler(adap, + adap->sge.qs[0].rspq. + polling), + (adap->flags & USING_MSI) ? + 0 : IRQF_SHARED, + adap->name, adap))) + goto irq_err; + + t3_sge_start(adap); + t3_intr_enable(adap); + + if ((adap->flags & (USING_MSIX | QUEUES_BOUND)) == USING_MSIX) + bind_qsets(adap); + adap->flags |= QUEUES_BOUND; + +out: + return err; +irq_err: + CH_ERR(adap, "request_irq failed, err %d\n", err); + goto out; +} + +/* + * Release resources when all the ports and offloading have been stopped. + */ +static void cxgb_down(struct adapter *adapter) +{ + t3_sge_stop(adapter); + spin_lock_irq(&adapter->work_lock); /* sync with PHY intr task */ + t3_intr_disable(adapter); + spin_unlock_irq(&adapter->work_lock); + + if (adapter->flags & USING_MSIX) { + int i, n = 0; + + free_irq(adapter->msix_info[0].vec, adapter); + for_each_port(adapter, i) + n += adap2pinfo(adapter, i)->nqsets; + + for (i = 0; i < n; ++i) + free_irq(adapter->msix_info[i + 1].vec, + &adapter->sge.qs[i]); + } else + free_irq(adapter->pdev->irq, adapter); + + flush_workqueue(cxgb3_wq); /* wait for external IRQ handler */ + quiesce_rx(adapter); +} + +static void schedule_chk_task(struct adapter *adap) +{ + unsigned int timeo; + + timeo = adap->params.linkpoll_period ? + (HZ * adap->params.linkpoll_period) / 10 : + adap->params.stats_update_period * HZ; + if (timeo) + queue_delayed_work(cxgb3_wq, &adap->adap_check_task, timeo); +} + +static int offload_open(struct net_device *dev) +{ + struct adapter *adapter = dev->priv; + struct t3cdev *tdev = T3CDEV(dev); + int adap_up = adapter->open_device_map & PORT_MASK; + int err = 0; + + if (test_and_set_bit(OFFLOAD_DEVMAP_BIT, &adapter->open_device_map)) + return 0; + + if (!adap_up && (err = cxgb_up(adapter)) < 0) + return err; + + t3_tp_set_offload_mode(adapter, 1); + tdev->lldev = adapter->port[0]; + err = cxgb3_offload_activate(adapter); + if (err) + goto out; + + init_port_mtus(adapter); + t3_load_mtus(adapter, adapter->params.mtus, adapter->params.a_wnd, + adapter->params.b_wnd, + adapter->params.rev == 0 ? + adapter->port[0]->mtu : 0xffff); + init_smt(adapter); + + /* Never mind if the next step fails */ + sysfs_create_group(&tdev->lldev->dev.kobj, &offload_attr_group); + + /* Call back all registered clients */ + cxgb3_add_clients(tdev); + +out: + /* restore them in case the offload module has changed them */ + if (err) { + t3_tp_set_offload_mode(adapter, 0); + clear_bit(OFFLOAD_DEVMAP_BIT, &adapter->open_device_map); + cxgb3_set_dummy_ops(tdev); + } + return err; +} + +static int offload_close(struct t3cdev *tdev) +{ + struct adapter *adapter = tdev2adap(tdev); + + if (!test_bit(OFFLOAD_DEVMAP_BIT, &adapter->open_device_map)) + return 0; + + /* Call back all registered clients */ + cxgb3_remove_clients(tdev); + + sysfs_remove_group(&tdev->lldev->dev.kobj, &offload_attr_group); + + tdev->lldev = NULL; + cxgb3_set_dummy_ops(tdev); + t3_tp_set_offload_mode(adapter, 0); + clear_bit(OFFLOAD_DEVMAP_BIT, &adapter->open_device_map); + + if (!adapter->open_device_map) + cxgb_down(adapter); + + cxgb3_offload_deactivate(adapter); + return 0; +} + +static int cxgb_open(struct net_device *dev) +{ + int err; + struct adapter *adapter = dev->priv; + struct port_info *pi = netdev_priv(dev); + int other_ports = adapter->open_device_map & PORT_MASK; + + if (!adapter->open_device_map && (err = cxgb_up(adapter)) < 0) + return err; + + set_bit(pi->port_id, &adapter->open_device_map); + if (!ofld_disable) { + err = offload_open(dev); + if (err) + printk(KERN_WARNING + "Could not initialize offload capabilities\n"); + } + + link_start(dev); + t3_port_intr_enable(adapter, pi->port_id); + netif_start_queue(dev); + if (!other_ports) + schedule_chk_task(adapter); + + return 0; +} + +static int cxgb_close(struct net_device *dev) +{ + struct adapter *adapter = dev->priv; + struct port_info *p = netdev_priv(dev); + + t3_port_intr_disable(adapter, p->port_id); + netif_stop_queue(dev); + p->phy.ops->power_down(&p->phy, 1); + netif_carrier_off(dev); + t3_mac_disable(&p->mac, MAC_DIRECTION_TX | MAC_DIRECTION_RX); + + spin_lock(&adapter->work_lock); /* sync with update task */ + clear_bit(p->port_id, &adapter->open_device_map); + spin_unlock(&adapter->work_lock); + + if (!(adapter->open_device_map & PORT_MASK)) + cancel_rearming_delayed_workqueue(cxgb3_wq, + &adapter->adap_check_task); + + if (!adapter->open_device_map) + cxgb_down(adapter); + + return 0; +} + +static struct net_device_stats *cxgb_get_stats(struct net_device *dev) +{ + struct adapter *adapter = dev->priv; + struct port_info *p = netdev_priv(dev); + struct net_device_stats *ns = &p->netstats; + const struct mac_stats *pstats; + + spin_lock(&adapter->stats_lock); + pstats = t3_mac_update_stats(&p->mac); + spin_unlock(&adapter->stats_lock); + + ns->tx_bytes = pstats->tx_octets; + ns->tx_packets = pstats->tx_frames; + ns->rx_bytes = pstats->rx_octets; + ns->rx_packets = pstats->rx_frames; + ns->multicast = pstats->rx_mcast_frames; + + ns->tx_errors = pstats->tx_underrun; + ns->rx_errors = pstats->rx_symbol_errs + pstats->rx_fcs_errs + + pstats->rx_too_long + pstats->rx_jabber + pstats->rx_short + + pstats->rx_fifo_ovfl; + + /* detailed rx_errors */ + ns->rx_length_errors = pstats->rx_jabber + pstats->rx_too_long; + ns->rx_over_errors = 0; + ns->rx_crc_errors = pstats->rx_fcs_errs; + ns->rx_frame_errors = pstats->rx_symbol_errs; + ns->rx_fifo_errors = pstats->rx_fifo_ovfl; + ns->rx_missed_errors = pstats->rx_cong_drops; + + /* detailed tx_errors */ + ns->tx_aborted_errors = 0; + ns->tx_carrier_errors = 0; + ns->tx_fifo_errors = pstats->tx_underrun; + ns->tx_heartbeat_errors = 0; + ns->tx_window_errors = 0; + return ns; +} + +static u32 get_msglevel(struct net_device *dev) +{ + struct adapter *adapter = dev->priv; + + return adapter->msg_enable; +} + +static void set_msglevel(struct net_device *dev, u32 val) +{ + struct adapter *adapter = dev->priv; + + adapter->msg_enable = val; +} + +static char stats_strings[][ETH_GSTRING_LEN] = { + "TxOctetsOK ", + "TxFramesOK ", + "TxMulticastFramesOK", + "TxBroadcastFramesOK", + "TxPauseFrames ", + "TxUnderrun ", + "TxExtUnderrun ", + + "TxFrames64 ", + "TxFrames65To127 ", + "TxFrames128To255 ", + "TxFrames256To511 ", + "TxFrames512To1023 ", + "TxFrames1024To1518 ", + "TxFrames1519ToMax ", + + "RxOctetsOK ", + "RxFramesOK ", + "RxMulticastFramesOK", + "RxBroadcastFramesOK", + "RxPauseFrames ", + "RxFCSErrors ", + "RxSymbolErrors ", + "RxShortErrors ", + "RxJabberErrors ", + "RxLengthErrors ", + "RxFIFOoverflow ", + + "RxFrames64 ", + "RxFrames65To127 ", + "RxFrames128To255 ", + "RxFrames256To511 ", + "RxFrames512To1023 ", + "RxFrames1024To1518 ", + "RxFrames1519ToMax ", + + "PhyFIFOErrors ", + "TSO ", + "VLANextractions ", + "VLANinsertions ", + "TxCsumOffload ", + "RxCsumGood ", + "RxDrops " +}; + +static int get_stats_count(struct net_device *dev) +{ + return ARRAY_SIZE(stats_strings); +} + +#define T3_REGMAP_SIZE (3 * 1024) + +static int get_regs_len(struct net_device *dev) +{ + return T3_REGMAP_SIZE; +} + +static int get_eeprom_len(struct net_device *dev) +{ + return EEPROMSIZE; +} + +static void get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info) +{ + u32 fw_vers = 0; + struct adapter *adapter = dev->priv; + + t3_get_fw_version(adapter, &fw_vers); + + strcpy(info->driver, DRV_NAME); + strcpy(info->version, DRV_VERSION); + strcpy(info->bus_info, pci_name(adapter->pdev)); + if (!fw_vers) + strcpy(info->fw_version, "N/A"); + else { + snprintf(info->fw_version, sizeof(info->fw_version), + "%s %u.%u.%u", + G_FW_VERSION_TYPE(fw_vers) ? "T" : "N", + G_FW_VERSION_MAJOR(fw_vers), + G_FW_VERSION_MINOR(fw_vers), + G_FW_VERSION_MICRO(fw_vers)); + } +} + +static void get_strings(struct net_device *dev, u32 stringset, u8 * data) +{ + if (stringset == ETH_SS_STATS) + memcpy(data, stats_strings, sizeof(stats_strings)); +} + +static unsigned long collect_sge_port_stats(struct adapter *adapter, + struct port_info *p, int idx) +{ + int i; + unsigned long tot = 0; + + for (i = 0; i < p->nqsets; ++i) + tot += adapter->sge.qs[i + p->first_qset].port_stats[idx]; + return tot; +} + +static void get_stats(struct net_device *dev, struct ethtool_stats *stats, + u64 *data) +{ + struct adapter *adapter = dev->priv; + struct port_info *pi = netdev_priv(dev); + const struct mac_stats *s; + + spin_lock(&adapter->stats_lock); + s = t3_mac_update_stats(&pi->mac); + spin_unlock(&adapter->stats_lock); + + *data++ = s->tx_octets; + *data++ = s->tx_frames; + *data++ = s->tx_mcast_frames; + *data++ = s->tx_bcast_frames; + *data++ = s->tx_pause; + *data++ = s->tx_underrun; + *data++ = s->tx_fifo_urun; + + *data++ = s->tx_frames_64; + *data++ = s->tx_frames_65_127; + *data++ = s->tx_frames_128_255; + *data++ = s->tx_frames_256_511; + *data++ = s->tx_frames_512_1023; + *data++ = s->tx_frames_1024_1518; + *data++ = s->tx_frames_1519_max; + + *data++ = s->rx_octets; + *data++ = s->rx_frames; + *data++ = s->rx_mcast_frames; + *data++ = s->rx_bcast_frames; + *data++ = s->rx_pause; + *data++ = s->rx_fcs_errs; + *data++ = s->rx_symbol_errs; + *data++ = s->rx_short; + *data++ = s->rx_jabber; + *data++ = s->rx_too_long; + *data++ = s->rx_fifo_ovfl; + + *data++ = s->rx_frames_64; + *data++ = s->rx_frames_65_127; + *data++ = s->rx_frames_128_255; + *data++ = s->rx_frames_256_511; + *data++ = s->rx_frames_512_1023; + *data++ = s->rx_frames_1024_1518; + *data++ = s->rx_frames_1519_max; + + *data++ = pi->phy.fifo_errors; + + *data++ = collect_sge_port_stats(adapter, pi, SGE_PSTAT_TSO); + *data++ = collect_sge_port_stats(adapter, pi, SGE_PSTAT_VLANEX); + *data++ = collect_sge_port_stats(adapter, pi, SGE_PSTAT_VLANINS); + *data++ = collect_sge_port_stats(adapter, pi, SGE_PSTAT_TX_CSUM); + *data++ = collect_sge_port_stats(adapter, pi, SGE_PSTAT_RX_CSUM_GOOD); + *data++ = s->rx_cong_drops; +} + +static inline void reg_block_dump(struct adapter *ap, void *buf, + unsigned int start, unsigned int end) +{ + u32 *p = buf + start; + + for (; start <= end; start += sizeof(u32)) + *p++ = t3_read_reg(ap, start); +} + +static void get_regs(struct net_device *dev, struct ethtool_regs *regs, + void *buf) +{ + struct adapter *ap = dev->priv; + + /* + * Version scheme: + * bits 0..9: chip version + * bits 10..15: chip revision + * bit 31: set for PCIe cards + */ + regs->version = 3 | (ap->params.rev << 10) | (is_pcie(ap) << 31); + + /* + * We skip the MAC statistics registers because they are clear-on-read. + * Also reading multi-register stats would need to synchronize with the + * periodic mac stats accumulation. Hard to justify the complexity. + */ + memset(buf, 0, T3_REGMAP_SIZE); + reg_block_dump(ap, buf, 0, A_SG_RSPQ_CREDIT_RETURN); + reg_block_dump(ap, buf, A_SG_HI_DRB_HI_THRSH, A_ULPRX_PBL_ULIMIT); + reg_block_dump(ap, buf, A_ULPTX_CONFIG, A_MPS_INT_CAUSE); + reg_block_dump(ap, buf, A_CPL_SWITCH_CNTRL, A_CPL_MAP_TBL_DATA); + reg_block_dump(ap, buf, A_SMB_GLOBAL_TIME_CFG, A_XGM_SERDES_STAT3); + reg_block_dump(ap, buf, A_XGM_SERDES_STATUS0, + XGM_REG(A_XGM_SERDES_STAT3, 1)); + reg_block_dump(ap, buf, XGM_REG(A_XGM_SERDES_STATUS0, 1), + XGM_REG(A_XGM_RX_SPI4_SOP_EOP_CNT, 1)); +} + +static int restart_autoneg(struct net_device *dev) +{ + struct port_info *p = netdev_priv(dev); + + if (!netif_running(dev)) + return -EAGAIN; + if (p->link_config.autoneg != AUTONEG_ENABLE) + return -EINVAL; + p->phy.ops->autoneg_restart(&p->phy); + return 0; +} + +static int cxgb3_phys_id(struct net_device *dev, u32 data) +{ + int i; + struct adapter *adapter = dev->priv; + + if (data == 0) + data = 2; + + for (i = 0; i < data * 2; i++) { + t3_set_reg_field(adapter, A_T3DBG_GPIO_EN, F_GPIO0_OUT_VAL, + (i & 1) ? F_GPIO0_OUT_VAL : 0); + if (msleep_interruptible(500)) + break; + } + t3_set_reg_field(adapter, A_T3DBG_GPIO_EN, F_GPIO0_OUT_VAL, + F_GPIO0_OUT_VAL); + return 0; +} + +static int get_settings(struct net_device *dev, struct ethtool_cmd *cmd) +{ + struct port_info *p = netdev_priv(dev); + + cmd->supported = p->link_config.supported; + cmd->advertising = p->link_config.advertising; + + if (netif_carrier_ok(dev)) { + cmd->speed = p->link_config.speed; + cmd->duplex = p->link_config.duplex; + } else { + cmd->speed = -1; + cmd->duplex = -1; + } + + cmd->port = (cmd->supported & SUPPORTED_TP) ? PORT_TP : PORT_FIBRE; + cmd->phy_address = p->phy.addr; + cmd->transceiver = XCVR_EXTERNAL; + cmd->autoneg = p->link_config.autoneg; + cmd->maxtxpkt = 0; + cmd->maxrxpkt = 0; + return 0; +} + +static int speed_duplex_to_caps(int speed, int duplex) +{ + int cap = 0; + + switch (speed) { + case SPEED_10: + if (duplex == DUPLEX_FULL) + cap = SUPPORTED_10baseT_Full; + else + cap = SUPPORTED_10baseT_Half; + break; + case SPEED_100: + if (duplex == DUPLEX_FULL) + cap = SUPPORTED_100baseT_Full; + else + cap = SUPPORTED_100baseT_Half; + break; + case SPEED_1000: + if (duplex == DUPLEX_FULL) + cap = SUPPORTED_1000baseT_Full; + else + cap = SUPPORTED_1000baseT_Half; + break; + case SPEED_10000: + if (duplex == DUPLEX_FULL) + cap = SUPPORTED_10000baseT_Full; + } + return cap; +} + +#define ADVERTISED_MASK (ADVERTISED_10baseT_Half | ADVERTISED_10baseT_Full | \ + ADVERTISED_100baseT_Half | ADVERTISED_100baseT_Full | \ + ADVERTISED_1000baseT_Half | ADVERTISED_1000baseT_Full | \ + ADVERTISED_10000baseT_Full) + +static int set_settings(struct net_device *dev, struct ethtool_cmd *cmd) +{ + struct port_info *p = netdev_priv(dev); + struct link_config *lc = &p->link_config; + + if (!(lc->supported & SUPPORTED_Autoneg)) + return -EOPNOTSUPP; /* can't change speed/duplex */ + + if (cmd->autoneg == AUTONEG_DISABLE) { + int cap = speed_duplex_to_caps(cmd->speed, cmd->duplex); + + if (!(lc->supported & cap) || cmd->speed == SPEED_1000) + return -EINVAL; + lc->requested_speed = cmd->speed; + lc->requested_duplex = cmd->duplex; + lc->advertising = 0; + } else { + cmd->advertising &= ADVERTISED_MASK; + cmd->advertising &= lc->supported; + if (!cmd->advertising) + return -EINVAL; + lc->requested_speed = SPEED_INVALID; + lc->requested_duplex = DUPLEX_INVALID; + lc->advertising = cmd->advertising | ADVERTISED_Autoneg; + } + lc->autoneg = cmd->autoneg; + if (netif_running(dev)) + t3_link_start(&p->phy, &p->mac, lc); + return 0; +} + +static void get_pauseparam(struct net_device *dev, + struct ethtool_pauseparam *epause) +{ + struct port_info *p = netdev_priv(dev); + + epause->autoneg = (p->link_config.requested_fc & PAUSE_AUTONEG) != 0; + epause->rx_pause = (p->link_config.fc & PAUSE_RX) != 0; + epause->tx_pause = (p->link_config.fc & PAUSE_TX) != 0; +} + +static int set_pauseparam(struct net_device *dev, + struct ethtool_pauseparam *epause) +{ + struct port_info *p = netdev_priv(dev); + struct link_config *lc = &p->link_config; + + if (epause->autoneg == AUTONEG_DISABLE) + lc->requested_fc = 0; + else if (lc->supported & SUPPORTED_Autoneg) + lc->requested_fc = PAUSE_AUTONEG; + else + return -EINVAL; + + if (epause->rx_pause) + lc->requested_fc |= PAUSE_RX; + if (epause->tx_pause) + lc->requested_fc |= PAUSE_TX; + if (lc->autoneg == AUTONEG_ENABLE) { + if (netif_running(dev)) + t3_link_start(&p->phy, &p->mac, lc); + } else { + lc->fc = lc->requested_fc & (PAUSE_RX | PAUSE_TX); + if (netif_running(dev)) + t3_mac_set_speed_duplex_fc(&p->mac, -1, -1, lc->fc); + } + return 0; +} + +static u32 get_rx_csum(struct net_device *dev) +{ + struct port_info *p = netdev_priv(dev); + + return p->rx_csum_offload; +} + +static int set_rx_csum(struct net_device *dev, u32 data) +{ + struct port_info *p = netdev_priv(dev); + + p->rx_csum_offload = data; + return 0; +} + +static void get_sge_param(struct net_device *dev, struct ethtool_ringparam *e) +{ + struct adapter *adapter = dev->priv; + + e->rx_max_pending = MAX_RX_BUFFERS; + e->rx_mini_max_pending = 0; + e->rx_jumbo_max_pending = MAX_RX_JUMBO_BUFFERS; + e->tx_max_pending = MAX_TXQ_ENTRIES; + + e->rx_pending = adapter->params.sge.qset[0].fl_size; + e->rx_mini_pending = adapter->params.sge.qset[0].rspq_size; + e->rx_jumbo_pending = adapter->params.sge.qset[0].jumbo_size; + e->tx_pending = adapter->params.sge.qset[0].txq_size[0]; +} + +static int set_sge_param(struct net_device *dev, struct ethtool_ringparam *e) +{ + int i; + struct adapter *adapter = dev->priv; + + if (e->rx_pending > MAX_RX_BUFFERS || + e->rx_jumbo_pending > MAX_RX_JUMBO_BUFFERS || + e->tx_pending > MAX_TXQ_ENTRIES || + e->rx_mini_pending > MAX_RSPQ_ENTRIES || + e->rx_mini_pending < MIN_RSPQ_ENTRIES || + e->rx_pending < MIN_FL_ENTRIES || + e->rx_jumbo_pending < MIN_FL_ENTRIES || + e->tx_pending < adapter->params.nports * MIN_TXQ_ENTRIES) + return -EINVAL; + + if (adapter->flags & FULL_INIT_DONE) + return -EBUSY; + + for (i = 0; i < SGE_QSETS; ++i) { + struct qset_params *q = &adapter->params.sge.qset[i]; + + q->rspq_size = e->rx_mini_pending; + q->fl_size = e->rx_pending; + q->jumbo_size = e->rx_jumbo_pending; + q->txq_size[0] = e->tx_pending; + q->txq_size[1] = e->tx_pending; + q->txq_size[2] = e->tx_pending; + } + return 0; +} + +static int set_coalesce(struct net_device *dev, struct ethtool_coalesce *c) +{ + struct adapter *adapter = dev->priv; + struct qset_params *qsp = &adapter->params.sge.qset[0]; + struct sge_qset *qs = &adapter->sge.qs[0]; + + if (c->rx_coalesce_usecs * 10 > M_NEWTIMER) + return -EINVAL; + + qsp->coalesce_usecs = c->rx_coalesce_usecs; + t3_update_qset_coalesce(qs, qsp); + return 0; +} + +static int get_coalesce(struct net_device *dev, struct ethtool_coalesce *c) +{ + struct adapter *adapter = dev->priv; + struct qset_params *q = adapter->params.sge.qset; + + c->rx_coalesce_usecs = q->coalesce_usecs; + return 0; +} + +static int get_eeprom(struct net_device *dev, struct ethtool_eeprom *e, + u8 * data) +{ + int i, err = 0; + struct adapter *adapter = dev->priv; + + u8 *buf = kmalloc(EEPROMSIZE, GFP_KERNEL); + if (!buf) + return -ENOMEM; + + e->magic = EEPROM_MAGIC; + for (i = e->offset & ~3; !err && i < e->offset + e->len; i += 4) + err = t3_seeprom_read(adapter, i, (u32 *) & buf[i]); + + if (!err) + memcpy(data, buf + e->offset, e->len); + kfree(buf); + return err; +} + +static int set_eeprom(struct net_device *dev, struct ethtool_eeprom *eeprom, + u8 * data) +{ + u8 *buf; + int err = 0; + u32 aligned_offset, aligned_len, *p; + struct adapter *adapter = dev->priv; + + if (eeprom->magic != EEPROM_MAGIC) + return -EINVAL; + + aligned_offset = eeprom->offset & ~3; + aligned_len = (eeprom->len + (eeprom->offset & 3) + 3) & ~3; + + if (aligned_offset != eeprom->offset || aligned_len != eeprom->len) { + buf = kmalloc(aligned_len, GFP_KERNEL); + if (!buf) + return -ENOMEM; + err = t3_seeprom_read(adapter, aligned_offset, (u32 *) buf); + if (!err && aligned_len > 4) + err = t3_seeprom_read(adapter, + aligned_offset + aligned_len - 4, + (u32 *) & buf[aligned_len - 4]); + if (err) + goto out; + memcpy(buf + (eeprom->offset & 3), data, eeprom->len); + } else + buf = data; + + err = t3_seeprom_wp(adapter, 0); + if (err) + goto out; + + for (p = (u32 *) buf; !err && aligned_len; aligned_len -= 4, p++) { + err = t3_seeprom_write(adapter, aligned_offset, *p); + aligned_offset += 4; + } + + if (!err) + err = t3_seeprom_wp(adapter, 1); +out: + if (buf != data) + kfree(buf); + return err; +} + +static void get_wol(struct net_device *dev, struct ethtool_wolinfo *wol) +{ + wol->supported = 0; + wol->wolopts = 0; + memset(&wol->sopass, 0, sizeof(wol->sopass)); +} + +static const struct ethtool_ops cxgb_ethtool_ops = { + .get_settings = get_settings, + .set_settings = set_settings, + .get_drvinfo = get_drvinfo, + .get_msglevel = get_msglevel, + .set_msglevel = set_msglevel, + .get_ringparam = get_sge_param, + .set_ringparam = set_sge_param, + .get_coalesce = get_coalesce, + .set_coalesce = set_coalesce, + .get_eeprom_len = get_eeprom_len, + .get_eeprom = get_eeprom, + .set_eeprom = set_eeprom, + .get_pauseparam = get_pauseparam, + .set_pauseparam = set_pauseparam, + .get_rx_csum = get_rx_csum, + .set_rx_csum = set_rx_csum, + .get_tx_csum = ethtool_op_get_tx_csum, + .set_tx_csum = ethtool_op_set_tx_csum, + .get_sg = ethtool_op_get_sg, + .set_sg = ethtool_op_set_sg, + .get_link = ethtool_op_get_link, + .get_strings = get_strings, + .phys_id = cxgb3_phys_id, + .nway_reset = restart_autoneg, + .get_stats_count = get_stats_count, + .get_ethtool_stats = get_stats, + .get_regs_len = get_regs_len, + .get_regs = get_regs, + .get_wol = get_wol, + .get_tso = ethtool_op_get_tso, + .set_tso = ethtool_op_set_tso, + .get_perm_addr = ethtool_op_get_perm_addr +}; + +static int in_range(int val, int lo, int hi) +{ + return val < 0 || (val <= hi && val >= lo); +} + +static int cxgb_extension_ioctl(struct net_device *dev, void __user *useraddr) +{ + int ret; + u32 cmd; + struct adapter *adapter = dev->priv; + + if (copy_from_user(&cmd, useraddr, sizeof(cmd))) + return -EFAULT; + + switch (cmd) { + case CHELSIO_SETREG:{ + struct ch_reg edata; + + if (!capable(CAP_NET_ADMIN)) + return -EPERM; + if (copy_from_user(&edata, useraddr, sizeof(edata))) + return -EFAULT; + if ((edata.addr & 3) != 0 + || edata.addr >= adapter->mmio_len) + return -EINVAL; + writel(edata.val, adapter->regs + edata.addr); + break; + } + case CHELSIO_GETREG:{ + struct ch_reg edata; + + if (copy_from_user(&edata, useraddr, sizeof(edata))) + return -EFAULT; + if ((edata.addr & 3) != 0 + || edata.addr >= adapter->mmio_len) + return -EINVAL; + edata.val = readl(adapter->regs + edata.addr); + if (copy_to_user(useraddr, &edata, sizeof(edata))) + return -EFAULT; + break; + } + case CHELSIO_SET_QSET_PARAMS:{ + int i; + struct qset_params *q; + struct ch_qset_params t; + + if (!capable(CAP_NET_ADMIN)) + return -EPERM; + if (copy_from_user(&t, useraddr, sizeof(t))) + return -EFAULT; + if (t.qset_idx >= SGE_QSETS) + return -EINVAL; + if (!in_range(t.intr_lat, 0, M_NEWTIMER) || + !in_range(t.cong_thres, 0, 255) || + !in_range(t.txq_size[0], MIN_TXQ_ENTRIES, + MAX_TXQ_ENTRIES) || + !in_range(t.txq_size[1], MIN_TXQ_ENTRIES, + MAX_TXQ_ENTRIES) || + !in_range(t.txq_size[2], MIN_CTRL_TXQ_ENTRIES, + MAX_CTRL_TXQ_ENTRIES) || + !in_range(t.fl_size[0], MIN_FL_ENTRIES, + MAX_RX_BUFFERS) + || !in_range(t.fl_size[1], MIN_FL_ENTRIES, + MAX_RX_JUMBO_BUFFERS) + || !in_range(t.rspq_size, MIN_RSPQ_ENTRIES, + MAX_RSPQ_ENTRIES)) + return -EINVAL; + if ((adapter->flags & FULL_INIT_DONE) && + (t.rspq_size >= 0 || t.fl_size[0] >= 0 || + t.fl_size[1] >= 0 || t.txq_size[0] >= 0 || + t.txq_size[1] >= 0 || t.txq_size[2] >= 0 || + t.polling >= 0 || t.cong_thres >= 0)) + return -EBUSY; + + q = &adapter->params.sge.qset[t.qset_idx]; + + if (t.rspq_size >= 0) + q->rspq_size = t.rspq_size; + if (t.fl_size[0] >= 0) + q->fl_size = t.fl_size[0]; + if (t.fl_size[1] >= 0) + q->jumbo_size = t.fl_size[1]; + if (t.txq_size[0] >= 0) + q->txq_size[0] = t.txq_size[0]; + if (t.txq_size[1] >= 0) + q->txq_size[1] = t.txq_size[1]; + if (t.txq_size[2] >= 0) + q->txq_size[2] = t.txq_size[2]; + if (t.cong_thres >= 0) + q->cong_thres = t.cong_thres; + if (t.intr_lat >= 0) { + struct sge_qset *qs = + &adapter->sge.qs[t.qset_idx]; + + q->coalesce_usecs = t.intr_lat; + t3_update_qset_coalesce(qs, q); + } + if (t.polling >= 0) { + if (adapter->flags & USING_MSIX) + q->polling = t.polling; + else { + /* No polling with INTx for T3A */ + if (adapter->params.rev == 0 && + !(adapter->flags & USING_MSI)) + t.polling = 0; + + for (i = 0; i < SGE_QSETS; i++) { + q = &adapter->params.sge. + qset[i]; + q->polling = t.polling; + } + } + } + break; + } + case CHELSIO_GET_QSET_PARAMS:{ + struct qset_params *q; + struct ch_qset_params t; + + if (copy_from_user(&t, useraddr, sizeof(t))) + return -EFAULT; + if (t.qset_idx >= SGE_QSETS) + return -EINVAL; + + q = &adapter->params.sge.qset[t.qset_idx]; + t.rspq_size = q->rspq_size; + t.txq_size[0] = q->txq_size[0]; + t.txq_size[1] = q->txq_size[1]; + t.txq_size[2] = q->txq_size[2]; + t.fl_size[0] = q->fl_size; + t.fl_size[1] = q->jumbo_size; + t.polling = q->polling; + t.intr_lat = q->coalesce_usecs; + t.cong_thres = q->cong_thres; + + if (copy_to_user(useraddr, &t, sizeof(t))) + return -EFAULT; + break; + } + case CHELSIO_SET_QSET_NUM:{ + struct ch_reg edata; + struct port_info *pi = netdev_priv(dev); + unsigned int i, first_qset = 0, other_qsets = 0; + + if (!capable(CAP_NET_ADMIN)) + return -EPERM; + if (adapter->flags & FULL_INIT_DONE) + return -EBUSY; + if (copy_from_user(&edata, useraddr, sizeof(edata))) + return -EFAULT; + if (edata.val < 1 || + (edata.val > 1 && !(adapter->flags & USING_MSIX))) + return -EINVAL; + + for_each_port(adapter, i) + if (adapter->port[i] && adapter->port[i] != dev) + other_qsets += adap2pinfo(adapter, i)->nqsets; + + if (edata.val + other_qsets > SGE_QSETS) + return -EINVAL; + + pi->nqsets = edata.val; + + for_each_port(adapter, i) + if (adapter->port[i]) { + pi = adap2pinfo(adapter, i); + pi->first_qset = first_qset; + first_qset += pi->nqsets; + } + break; + } + case CHELSIO_GET_QSET_NUM:{ + struct ch_reg edata; + struct port_info *pi = netdev_priv(dev); + + edata.cmd = CHELSIO_GET_QSET_NUM; + edata.val = pi->nqsets; + if (copy_to_user(useraddr, &edata, sizeof(edata))) + return -EFAULT; + break; + } + case CHELSIO_LOAD_FW:{ + u8 *fw_data; + struct ch_mem_range t; + + if (!capable(CAP_NET_ADMIN)) + return -EPERM; + if (copy_from_user(&t, useraddr, sizeof(t))) + return -EFAULT; + + fw_data = kmalloc(t.len, GFP_KERNEL); + if (!fw_data) + return -ENOMEM; + + if (copy_from_user + (fw_data, useraddr + sizeof(t), t.len)) { + kfree(fw_data); + return -EFAULT; + } + + ret = t3_load_fw(adapter, fw_data, t.len); + kfree(fw_data); + if (ret) + return ret; + break; + } + case CHELSIO_SETMTUTAB:{ + struct ch_mtus m; + int i; + + if (!is_offload(adapter)) + return -EOPNOTSUPP; + if (!capable(CAP_NET_ADMIN)) + return -EPERM; + if (offload_running(adapter)) + return -EBUSY; + if (copy_from_user(&m, useraddr, sizeof(m))) + return -EFAULT; + if (m.nmtus != NMTUS) + return -EINVAL; + if (m.mtus[0] < 81) /* accommodate SACK */ + return -EINVAL; + + /* MTUs must be in ascending order */ + for (i = 1; i < NMTUS; ++i) + if (m.mtus[i] < m.mtus[i - 1]) + return -EINVAL; + + memcpy(adapter->params.mtus, m.mtus, + sizeof(adapter->params.mtus)); + break; + } + case CHELSIO_GET_PM:{ + struct tp_params *p = &adapter->params.tp; + struct ch_pm m = {.cmd = CHELSIO_GET_PM }; + + if (!is_offload(adapter)) + return -EOPNOTSUPP; + m.tx_pg_sz = p->tx_pg_size; + m.tx_num_pg = p->tx_num_pgs; + m.rx_pg_sz = p->rx_pg_size; + m.rx_num_pg = p->rx_num_pgs; + m.pm_total = p->pmtx_size + p->chan_rx_size * p->nchan; + if (copy_to_user(useraddr, &m, sizeof(m))) + return -EFAULT; + break; + } + case CHELSIO_SET_PM:{ + struct ch_pm m; + struct tp_params *p = &adapter->params.tp; + + if (!is_offload(adapter)) + return -EOPNOTSUPP; + if (!capable(CAP_NET_ADMIN)) + return -EPERM; + if (adapter->flags & FULL_INIT_DONE) + return -EBUSY; + if (copy_from_user(&m, useraddr, sizeof(m))) + return -EFAULT; + if (!m.rx_pg_sz || (m.rx_pg_sz & (m.rx_pg_sz - 1)) || + !m.tx_pg_sz || (m.tx_pg_sz & (m.tx_pg_sz - 1))) + return -EINVAL; /* not power of 2 */ + if (!(m.rx_pg_sz & 0x14000)) + return -EINVAL; /* not 16KB or 64KB */ + if (!(m.tx_pg_sz & 0x1554000)) + return -EINVAL; + if (m.tx_num_pg == -1) + m.tx_num_pg = p->tx_num_pgs; + if (m.rx_num_pg == -1) + m.rx_num_pg = p->rx_num_pgs; + if (m.tx_num_pg % 24 || m.rx_num_pg % 24) + return -EINVAL; + if (m.rx_num_pg * m.rx_pg_sz > p->chan_rx_size || + m.tx_num_pg * m.tx_pg_sz > p->chan_tx_size) + return -EINVAL; + p->rx_pg_size = m.rx_pg_sz; + p->tx_pg_size = m.tx_pg_sz; + p->rx_num_pgs = m.rx_num_pg; + p->tx_num_pgs = m.tx_num_pg; + break; + } + case CHELSIO_GET_MEM:{ + struct ch_mem_range t; + struct mc7 *mem; + u64 buf[32]; + + if (!is_offload(adapter)) + return -EOPNOTSUPP; + if (!(adapter->flags & FULL_INIT_DONE)) + return -EIO; /* need the memory controllers */ + if (copy_from_user(&t, useraddr, sizeof(t))) + return -EFAULT; + if ((t.addr & 7) || (t.len & 7)) + return -EINVAL; + if (t.mem_id == MEM_CM) + mem = &adapter->cm; + else if (t.mem_id == MEM_PMRX) + mem = &adapter->pmrx; + else if (t.mem_id == MEM_PMTX) + mem = &adapter->pmtx; + else + return -EINVAL; + + /* + * Version scheme: + * bits 0..9: chip version + * bits 10..15: chip revision + */ + t.version = 3 | (adapter->params.rev << 10); + if (copy_to_user(useraddr, &t, sizeof(t))) + return -EFAULT; + + /* + * Read 256 bytes at a time as len can be large and we don't + * want to use huge intermediate buffers. + */ + useraddr += sizeof(t); /* advance to start of buffer */ + while (t.len) { + unsigned int chunk = + min_t(unsigned int, t.len, sizeof(buf)); + + ret = + t3_mc7_bd_read(mem, t.addr / 8, chunk / 8, + buf); + if (ret) + return ret; + if (copy_to_user(useraddr, buf, chunk)) + return -EFAULT; + useraddr += chunk; + t.addr += chunk; + t.len -= chunk; + } + break; + } + case CHELSIO_SET_TRACE_FILTER:{ + struct ch_trace t; + const struct trace_params *tp; + + if (!capable(CAP_NET_ADMIN)) + return -EPERM; + if (!offload_running(adapter)) + return -EAGAIN; + if (copy_from_user(&t, useraddr, sizeof(t))) + return -EFAULT; + + tp = (const struct trace_params *)&t.sip; + if (t.config_tx) + t3_config_trace_filter(adapter, tp, 0, + t.invert_match, + t.trace_tx); + if (t.config_rx) + t3_config_trace_filter(adapter, tp, 1, + t.invert_match, + t.trace_rx); + break; + } + case CHELSIO_SET_PKTSCHED:{ + struct ch_pktsched_params p; + + if (!capable(CAP_NET_ADMIN)) + return -EPERM; + if (!adapter->open_device_map) + return -EAGAIN; /* uP and SGE must be running */ + if (copy_from_user(&p, useraddr, sizeof(p))) + return -EFAULT; + send_pktsched_cmd(adapter, p.sched, p.idx, p.min, p.max, + p.binding); + break; + + } + default: + return -EOPNOTSUPP; + } + return 0; +} + +static int cxgb_ioctl(struct net_device *dev, struct ifreq *req, int cmd) +{ + int ret, mmd; + struct adapter *adapter = dev->priv; + struct port_info *pi = netdev_priv(dev); + struct mii_ioctl_data *data = if_mii(req); + + switch (cmd) { + case SIOCGMIIPHY: + data->phy_id = pi->phy.addr; + /* FALLTHRU */ + case SIOCGMIIREG:{ + u32 val; + struct cphy *phy = &pi->phy; + + if (!phy->mdio_read) + return -EOPNOTSUPP; + if (is_10G(adapter)) { + mmd = data->phy_id >> 8; + if (!mmd) + mmd = MDIO_DEV_PCS; + else if (mmd > MDIO_DEV_XGXS) + return -EINVAL; + + ret = + phy->mdio_read(adapter, data->phy_id & 0x1f, + mmd, data->reg_num, &val); + } else + ret = + phy->mdio_read(adapter, data->phy_id & 0x1f, + 0, data->reg_num & 0x1f, + &val); + if (!ret) + data->val_out = val; + break; + } + case SIOCSMIIREG:{ + struct cphy *phy = &pi->phy; + + if (!capable(CAP_NET_ADMIN)) + return -EPERM; + if (!phy->mdio_write) + return -EOPNOTSUPP; + if (is_10G(adapter)) { + mmd = data->phy_id >> 8; + if (!mmd) + mmd = MDIO_DEV_PCS; + else if (mmd > MDIO_DEV_XGXS) + return -EINVAL; + + ret = + phy->mdio_write(adapter, + data->phy_id & 0x1f, mmd, + data->reg_num, + data->val_in); + } else + ret = + phy->mdio_write(adapter, + data->phy_id & 0x1f, 0, + data->reg_num & 0x1f, + data->val_in); + break; + } + case SIOCCHIOCTL: + return cxgb_extension_ioctl(dev, req->ifr_data); + default: + return -EOPNOTSUPP; + } + return ret; +} + +static int cxgb_change_mtu(struct net_device *dev, int new_mtu) +{ + int ret; + struct adapter *adapter = dev->priv; + struct port_info *pi = netdev_priv(dev); + + if (new_mtu < 81) /* accommodate SACK */ + return -EINVAL; + if ((ret = t3_mac_set_mtu(&pi->mac, new_mtu))) + return ret; + dev->mtu = new_mtu; + init_port_mtus(adapter); + if (adapter->params.rev == 0 && offload_running(adapter)) + t3_load_mtus(adapter, adapter->params.mtus, + adapter->params.a_wnd, adapter->params.b_wnd, + adapter->port[0]->mtu); + return 0; +} + +static int cxgb_set_mac_addr(struct net_device *dev, void *p) +{ + struct adapter *adapter = dev->priv; + struct port_info *pi = netdev_priv(dev); + struct sockaddr *addr = p; + + if (!is_valid_ether_addr(addr->sa_data)) + return -EINVAL; + + memcpy(dev->dev_addr, addr->sa_data, dev->addr_len); + t3_mac_set_address(&pi->mac, 0, dev->dev_addr); + if (offload_running(adapter)) + write_smt_entry(adapter, pi->port_id); + return 0; +} + +/** + * t3_synchronize_rx - wait for current Rx processing on a port to complete + * @adap: the adapter + * @p: the port + * + * Ensures that current Rx processing on any of the queues associated with + * the given port completes before returning. We do this by acquiring and + * releasing the locks of the response queues associated with the port. + */ +static void t3_synchronize_rx(struct adapter *adap, const struct port_info *p) +{ + int i; + + for (i = 0; i < p->nqsets; i++) { + struct sge_rspq *q = &adap->sge.qs[i + p->first_qset].rspq; + + spin_lock_irq(&q->lock); + spin_unlock_irq(&q->lock); + } +} + +static void vlan_rx_register(struct net_device *dev, struct vlan_group *grp) +{ + struct adapter *adapter = dev->priv; + struct port_info *pi = netdev_priv(dev); + + pi->vlan_grp = grp; + if (adapter->params.rev > 0) + t3_set_vlan_accel(adapter, 1 << pi->port_id, grp != NULL); + else { + /* single control for all ports */ + unsigned int i, have_vlans = 0; + for_each_port(adapter, i) + have_vlans |= adap2pinfo(adapter, i)->vlan_grp != NULL; + + t3_set_vlan_accel(adapter, 1, have_vlans); + } + t3_synchronize_rx(adapter, pi); +} + +static void vlan_rx_kill_vid(struct net_device *dev, unsigned short vid) +{ + /* nothing */ +} + +#ifdef CONFIG_NET_POLL_CONTROLLER +static void cxgb_netpoll(struct net_device *dev) +{ + struct adapter *adapter = dev->priv; + struct sge_qset *qs = dev2qset(dev); + + t3_intr_handler(adapter, qs->rspq.polling) (adapter->pdev->irq, + adapter); +} +#endif + +/* + * Periodic accumulation of MAC statistics. + */ +static void mac_stats_update(struct adapter *adapter) +{ + int i; + + for_each_port(adapter, i) { + struct net_device *dev = adapter->port[i]; + struct port_info *p = netdev_priv(dev); + + if (netif_running(dev)) { + spin_lock(&adapter->stats_lock); + t3_mac_update_stats(&p->mac); + spin_unlock(&adapter->stats_lock); + } + } +} + +static void check_link_status(struct adapter *adapter) +{ + int i; + + for_each_port(adapter, i) { + struct net_device *dev = adapter->port[i]; + struct port_info *p = netdev_priv(dev); + + if (!(p->port_type->caps & SUPPORTED_IRQ) && netif_running(dev)) + t3_link_changed(adapter, i); + } +} + +static void t3_adap_check_task(struct work_struct *work) +{ + struct adapter *adapter = container_of(work, struct adapter, + adap_check_task.work); + const struct adapter_params *p = &adapter->params; + + adapter->check_task_cnt++; + + /* Check link status for PHYs without interrupts */ + if (p->linkpoll_period) + check_link_status(adapter); + + /* Accumulate MAC stats if needed */ + if (!p->linkpoll_period || + (adapter->check_task_cnt * p->linkpoll_period) / 10 >= + p->stats_update_period) { + mac_stats_update(adapter); + adapter->check_task_cnt = 0; + } + + /* Schedule the next check update if any port is active. */ + spin_lock(&adapter->work_lock); + if (adapter->open_device_map & PORT_MASK) + schedule_chk_task(adapter); + spin_unlock(&adapter->work_lock); +} + +/* + * Processes external (PHY) interrupts in process context. + */ +static void ext_intr_task(struct work_struct *work) +{ + struct adapter *adapter = container_of(work, struct adapter, + ext_intr_handler_task); + + t3_phy_intr_handler(adapter); + + /* Now reenable external interrupts */ + spin_lock_irq(&adapter->work_lock); + if (adapter->slow_intr_mask) { + adapter->slow_intr_mask |= F_T3DBG; + t3_write_reg(adapter, A_PL_INT_CAUSE0, F_T3DBG); + t3_write_reg(adapter, A_PL_INT_ENABLE0, + adapter->slow_intr_mask); + } + spin_unlock_irq(&adapter->work_lock); +} + +/* + * Interrupt-context handler for external (PHY) interrupts. + */ +void t3_os_ext_intr_handler(struct adapter *adapter) +{ + /* + * Schedule a task to handle external interrupts as they may be slow + * and we use a mutex to protect MDIO registers. We disable PHY + * interrupts in the meantime and let the task reenable them when + * it's done. + */ + spin_lock(&adapter->work_lock); + if (adapter->slow_intr_mask) { + adapter->slow_intr_mask &= ~F_T3DBG; + t3_write_reg(adapter, A_PL_INT_ENABLE0, + adapter->slow_intr_mask); + queue_work(cxgb3_wq, &adapter->ext_intr_handler_task); + } + spin_unlock(&adapter->work_lock); +} + +void t3_fatal_err(struct adapter *adapter) +{ + unsigned int fw_status[4]; + + if (adapter->flags & FULL_INIT_DONE) { + t3_sge_stop(adapter); + t3_intr_disable(adapter); + } + CH_ALERT(adapter, "encountered fatal error, operation suspended\n"); + if (!t3_cim_ctl_blk_read(adapter, 0xa0, 4, fw_status)) + CH_ALERT(adapter, "FW status: 0x%x, 0x%x, 0x%x, 0x%x\n", + fw_status[0], fw_status[1], + fw_status[2], fw_status[3]); + +} + +static int __devinit cxgb_enable_msix(struct adapter *adap) +{ + struct msix_entry entries[SGE_QSETS + 1]; + int i, err; + + for (i = 0; i < ARRAY_SIZE(entries); ++i) + entries[i].entry = i; + + err = pci_enable_msix(adap->pdev, entries, ARRAY_SIZE(entries)); + if (!err) { + for (i = 0; i < ARRAY_SIZE(entries); ++i) + adap->msix_info[i].vec = entries[i].vector; + } else if (err > 0) + dev_info(&adap->pdev->dev, + "only %d MSI-X vectors left, not using MSI-X\n", err); + return err; +} + +static void __devinit print_port_info(struct adapter *adap, + const struct adapter_info *ai) +{ + static const char *pci_variant[] = { + "PCI", "PCI-X", "PCI-X ECC", "PCI-X 266", "PCI Express" + }; + + int i; + char buf[80]; + + if (is_pcie(adap)) + snprintf(buf, sizeof(buf), "%s x%d", + pci_variant[adap->params.pci.variant], + adap->params.pci.width); + else + snprintf(buf, sizeof(buf), "%s %dMHz/%d-bit", + pci_variant[adap->params.pci.variant], + adap->params.pci.speed, adap->params.pci.width); + + for_each_port(adap, i) { + struct net_device *dev = adap->port[i]; + const struct port_info *pi = netdev_priv(dev); + + if (!test_bit(i, &adap->registered_device_map)) + continue; + printk(KERN_INFO "%s: %s %s RNIC (rev %d) %s%s\n", + dev->name, ai->desc, pi->port_type->desc, + adap->params.rev, buf, + (adap->flags & USING_MSIX) ? " MSI-X" : + (adap->flags & USING_MSI) ? " MSI" : ""); + if (adap->name == dev->name && adap->params.vpd.mclk) + printk(KERN_INFO "%s: %uMB CM, %uMB PMTX, %uMB PMRX\n", + adap->name, t3_mc7_size(&adap->cm) >> 20, + t3_mc7_size(&adap->pmtx) >> 20, + t3_mc7_size(&adap->pmrx) >> 20); + } +} + +static int __devinit init_one(struct pci_dev *pdev, + const struct pci_device_id *ent) +{ + static int version_printed; + + int i, err, pci_using_dac = 0; + unsigned long mmio_start, mmio_len; + const struct adapter_info *ai; + struct adapter *adapter = NULL; + struct port_info *pi; + + if (!version_printed) { + printk(KERN_INFO "%s - version %s\n", DRV_DESC, DRV_VERSION); + ++version_printed; + } + + if (!cxgb3_wq) { + cxgb3_wq = create_singlethread_workqueue(DRV_NAME); + if (!cxgb3_wq) { + printk(KERN_ERR DRV_NAME + ": cannot initialize work queue\n"); + return -ENOMEM; + } + } + + err = pci_request_regions(pdev, DRV_NAME); + if (err) { + /* Just info, some other driver may have claimed the device. */ + dev_info(&pdev->dev, "cannot obtain PCI resources\n"); + return err; + } + + err = pci_enable_device(pdev); + if (err) { + dev_err(&pdev->dev, "cannot enable PCI device\n"); + goto out_release_regions; + } + + if (!pci_set_dma_mask(pdev, DMA_64BIT_MASK)) { + pci_using_dac = 1; + err = pci_set_consistent_dma_mask(pdev, DMA_64BIT_MASK); + if (err) { + dev_err(&pdev->dev, "unable to obtain 64-bit DMA for " + "coherent allocations\n"); + goto out_disable_device; + } + } else if ((err = pci_set_dma_mask(pdev, DMA_32BIT_MASK)) != 0) { + dev_err(&pdev->dev, "no usable DMA configuration\n"); + goto out_disable_device; + } + + pci_set_master(pdev); + + mmio_start = pci_resource_start(pdev, 0); + mmio_len = pci_resource_len(pdev, 0); + ai = t3_get_adapter_info(ent->driver_data); + + adapter = kzalloc(sizeof(*adapter), GFP_KERNEL); + if (!adapter) { + err = -ENOMEM; + goto out_disable_device; + } + + adapter->regs = ioremap_nocache(mmio_start, mmio_len); + if (!adapter->regs) { + dev_err(&pdev->dev, "cannot map device registers\n"); + err = -ENOMEM; + goto out_free_adapter; + } + + adapter->pdev = pdev; + adapter->name = pci_name(pdev); + adapter->msg_enable = dflt_msg_enable; + adapter->mmio_len = mmio_len; + + mutex_init(&adapter->mdio_lock); + spin_lock_init(&adapter->work_lock); + spin_lock_init(&adapter->stats_lock); + + INIT_LIST_HEAD(&adapter->adapter_list); + INIT_WORK(&adapter->ext_intr_handler_task, ext_intr_task); + INIT_DELAYED_WORK(&adapter->adap_check_task, t3_adap_check_task); + + for (i = 0; i < ai->nports; ++i) { + struct net_device *netdev; + + netdev = alloc_etherdev(sizeof(struct port_info)); + if (!netdev) { + err = -ENOMEM; + goto out_free_dev; + } + + SET_MODULE_OWNER(netdev); + SET_NETDEV_DEV(netdev, &pdev->dev); + + adapter->port[i] = netdev; + pi = netdev_priv(netdev); + pi->rx_csum_offload = 1; + pi->nqsets = 1; + pi->first_qset = i; + pi->activity = 0; + pi->port_id = i; + netif_carrier_off(netdev); + netdev->irq = pdev->irq; + netdev->mem_start = mmio_start; + netdev->mem_end = mmio_start + mmio_len - 1; + netdev->priv = adapter; + netdev->features |= NETIF_F_SG | NETIF_F_IP_CSUM | NETIF_F_TSO; + netdev->features |= NETIF_F_LLTX; + if (pci_using_dac) + netdev->features |= NETIF_F_HIGHDMA; + + netdev->features |= NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_RX; + netdev->vlan_rx_register = vlan_rx_register; + netdev->vlan_rx_kill_vid = vlan_rx_kill_vid; + + netdev->open = cxgb_open; + netdev->stop = cxgb_close; + netdev->hard_start_xmit = t3_eth_xmit; + netdev->get_stats = cxgb_get_stats; + netdev->set_multicast_list = cxgb_set_rxmode; + netdev->do_ioctl = cxgb_ioctl; + netdev->change_mtu = cxgb_change_mtu; + netdev->set_mac_address = cxgb_set_mac_addr; +#ifdef CONFIG_NET_POLL_CONTROLLER + netdev->poll_controller = cxgb_netpoll; +#endif + netdev->weight = 64; + + SET_ETHTOOL_OPS(netdev, &cxgb_ethtool_ops); + } + + pci_set_drvdata(pdev, adapter->port[0]); + if (t3_prep_adapter(adapter, ai, 1) < 0) { + err = -ENODEV; + goto out_free_dev; + } + + /* + * The card is now ready to go. If any errors occur during device + * registration we do not fail the whole card but rather proceed only + * with the ports we manage to register successfully. However we must + * register at least one net device. + */ + for_each_port(adapter, i) { + err = register_netdev(adapter->port[i]); + if (err) + dev_warn(&pdev->dev, + "cannot register net device %s, skipping\n", + adapter->port[i]->name); + else { + /* + * Change the name we use for messages to the name of + * the first successfully registered interface. + */ + if (!adapter->registered_device_map) + adapter->name = adapter->port[i]->name; + + __set_bit(i, &adapter->registered_device_map); + } + } + if (!adapter->registered_device_map) { + dev_err(&pdev->dev, "could not register any net devices\n"); + goto out_free_dev; + } + + /* Driver's ready. Reflect it on LEDs */ + t3_led_ready(adapter); + + if (is_offload(adapter)) { + __set_bit(OFFLOAD_DEVMAP_BIT, &adapter->registered_device_map); + cxgb3_adapter_ofld(adapter); + } + + /* See what interrupts we'll be using */ + if (msi > 1 && cxgb_enable_msix(adapter) == 0) + adapter->flags |= USING_MSIX; + else if (msi > 0 && pci_enable_msi(pdev) == 0) + adapter->flags |= USING_MSI; + + err = sysfs_create_group(&adapter->port[0]->dev.kobj, + &cxgb3_attr_group); + + print_port_info(adapter, ai); + return 0; + +out_free_dev: + iounmap(adapter->regs); + for (i = ai->nports - 1; i >= 0; --i) + if (adapter->port[i]) + free_netdev(adapter->port[i]); + +out_free_adapter: + kfree(adapter); + +out_disable_device: + pci_disable_device(pdev); +out_release_regions: + pci_release_regions(pdev); + pci_set_drvdata(pdev, NULL); + return err; +} + +static void __devexit remove_one(struct pci_dev *pdev) +{ + struct net_device *dev = pci_get_drvdata(pdev); + + if (dev) { + int i; + struct adapter *adapter = dev->priv; + + t3_sge_stop(adapter); + sysfs_remove_group(&adapter->port[0]->dev.kobj, + &cxgb3_attr_group); + + for_each_port(adapter, i) + if (test_bit(i, &adapter->registered_device_map)) + unregister_netdev(adapter->port[i]); + + if (is_offload(adapter)) { + cxgb3_adapter_unofld(adapter); + if (test_bit(OFFLOAD_DEVMAP_BIT, + &adapter->open_device_map)) + offload_close(&adapter->tdev); + } + + t3_free_sge_resources(adapter); + cxgb_disable_msi(adapter); + + for (i = 0; i < ARRAY_SIZE(adapter->dummy_netdev); i++) + if (adapter->dummy_netdev[i]) { + free_netdev(adapter->dummy_netdev[i]); + adapter->dummy_netdev[i] = NULL; + } + + for_each_port(adapter, i) + if (adapter->port[i]) + free_netdev(adapter->port[i]); + + iounmap(adapter->regs); + kfree(adapter); + pci_release_regions(pdev); + pci_disable_device(pdev); + pci_set_drvdata(pdev, NULL); + } +} + +static struct pci_driver driver = { + .name = DRV_NAME, + .id_table = cxgb3_pci_tbl, + .probe = init_one, + .remove = __devexit_p(remove_one), +}; + +static int __init cxgb3_init_module(void) +{ + int ret; + + cxgb3_offload_init(); + + ret = pci_register_driver(&driver); + return ret; +} + +static void __exit cxgb3_cleanup_module(void) +{ + pci_unregister_driver(&driver); + if (cxgb3_wq) + destroy_workqueue(cxgb3_wq); +} + +module_init(cxgb3_init_module); +module_exit(cxgb3_cleanup_module); diff --git a/drivers/net/cxgb3/cxgb3_offload.c b/drivers/net/cxgb3/cxgb3_offload.c new file mode 100644 index 0000000..c6b7266 --- /dev/null +++ b/drivers/net/cxgb3/cxgb3_offload.c @@ -0,0 +1,1222 @@ +/* + * Copyright (c) 2006-2007 Chelsio, Inc. All rights reserved. + * Copyright (c) 2006-2007 Open Grid Computing, Inc. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "common.h" +#include "regs.h" +#include "cxgb3_ioctl.h" +#include "cxgb3_ctl_defs.h" +#include "cxgb3_defs.h" +#include "l2t.h" +#include "firmware_exports.h" +#include "cxgb3_offload.h" + +static LIST_HEAD(client_list); +static LIST_HEAD(ofld_dev_list); +static DEFINE_MUTEX(cxgb3_db_lock); + +static DEFINE_RWLOCK(adapter_list_lock); +static LIST_HEAD(adapter_list); + +static const unsigned int MAX_ATIDS = 64 * 1024; +static const unsigned int ATID_BASE = 0x100000; + +static inline int offload_activated(struct t3cdev *tdev) +{ + const struct adapter *adapter = tdev2adap(tdev); + + return (test_bit(OFFLOAD_DEVMAP_BIT, &adapter->open_device_map)); +} + +/** + * cxgb3_register_client - register an offload client + * @client: the client + * + * Add the client to the client list, + * and call backs the client for each activated offload device + */ +void cxgb3_register_client(struct cxgb3_client *client) +{ + struct t3cdev *tdev; + + mutex_lock(&cxgb3_db_lock); + list_add_tail(&client->client_list, &client_list); + + if (client->add) { + list_for_each_entry(tdev, &ofld_dev_list, ofld_dev_list) { + if (offload_activated(tdev)) + client->add(tdev); + } + } + mutex_unlock(&cxgb3_db_lock); +} + +EXPORT_SYMBOL(cxgb3_register_client); + +/** + * cxgb3_unregister_client - unregister an offload client + * @client: the client + * + * Remove the client to the client list, + * and call backs the client for each activated offload device. + */ +void cxgb3_unregister_client(struct cxgb3_client *client) +{ + struct t3cdev *tdev; + + mutex_lock(&cxgb3_db_lock); + list_del(&client->client_list); + + if (client->remove) { + list_for_each_entry(tdev, &ofld_dev_list, ofld_dev_list) { + if (offload_activated(tdev)) + client->remove(tdev); + } + } + mutex_unlock(&cxgb3_db_lock); +} + +EXPORT_SYMBOL(cxgb3_unregister_client); + +/** + * cxgb3_add_clients - activate registered clients for an offload device + * @tdev: the offload device + * + * Call backs all registered clients once a offload device is activated + */ +void cxgb3_add_clients(struct t3cdev *tdev) +{ + struct cxgb3_client *client; + + mutex_lock(&cxgb3_db_lock); + list_for_each_entry(client, &client_list, client_list) { + if (client->add) + client->add(tdev); + } + mutex_unlock(&cxgb3_db_lock); +} + +/** + * cxgb3_remove_clients - deactivates registered clients + * for an offload device + * @tdev: the offload device + * + * Call backs all registered clients once a offload device is deactivated + */ +void cxgb3_remove_clients(struct t3cdev *tdev) +{ + struct cxgb3_client *client; + + mutex_lock(&cxgb3_db_lock); + list_for_each_entry(client, &client_list, client_list) { + if (client->remove) + client->remove(tdev); + } + mutex_unlock(&cxgb3_db_lock); +} + +static struct net_device *get_iff_from_mac(struct adapter *adapter, + const unsigned char *mac, + unsigned int vlan) +{ + int i; + + for_each_port(adapter, i) { + const struct vlan_group *grp; + struct net_device *dev = adapter->port[i]; + const struct port_info *p = netdev_priv(dev); + + if (!memcmp(dev->dev_addr, mac, ETH_ALEN)) { + if (vlan && vlan != VLAN_VID_MASK) { + grp = p->vlan_grp; + dev = grp ? grp->vlan_devices[vlan] : NULL; + } else + while (dev->master) + dev = dev->master; + return dev; + } + } + return NULL; +} + +static int cxgb_ulp_iscsi_ctl(struct adapter *adapter, unsigned int req, + void *data) +{ + int ret = 0; + struct ulp_iscsi_info *uiip = data; + + switch (req) { + case ULP_ISCSI_GET_PARAMS: + uiip->pdev = adapter->pdev; + uiip->llimit = t3_read_reg(adapter, A_ULPRX_ISCSI_LLIMIT); + uiip->ulimit = t3_read_reg(adapter, A_ULPRX_ISCSI_ULIMIT); + uiip->tagmask = t3_read_reg(adapter, A_ULPRX_ISCSI_TAGMASK); + /* + * On tx, the iscsi pdu has to be <= tx page size and has to + * fit into the Tx PM FIFO. + */ + uiip->max_txsz = min(adapter->params.tp.tx_pg_size, + t3_read_reg(adapter, A_PM1_TX_CFG) >> 17); + /* on rx, the iscsi pdu has to be < rx page size and the + whole pdu + cpl headers has to fit into one sge buffer */ + uiip->max_rxsz = min_t(unsigned int, + adapter->params.tp.rx_pg_size, + (adapter->sge.qs[0].fl[1].buf_size - + sizeof(struct cpl_rx_data) * 2 - + sizeof(struct cpl_rx_data_ddp))); + break; + case ULP_ISCSI_SET_PARAMS: + t3_write_reg(adapter, A_ULPRX_ISCSI_TAGMASK, uiip->tagmask); + break; + default: + ret = -EOPNOTSUPP; + } + return ret; +} + +/* Response queue used for RDMA events. */ +#define ASYNC_NOTIF_RSPQ 0 + +static int cxgb_rdma_ctl(struct adapter *adapter, unsigned int req, void *data) +{ + int ret = 0; + + switch (req) { + case RDMA_GET_PARAMS:{ + struct rdma_info *req = data; + struct pci_dev *pdev = adapter->pdev; + + req->udbell_physbase = pci_resource_start(pdev, 2); + req->udbell_len = pci_resource_len(pdev, 2); + req->tpt_base = + t3_read_reg(adapter, A_ULPTX_TPT_LLIMIT); + req->tpt_top = t3_read_reg(adapter, A_ULPTX_TPT_ULIMIT); + req->pbl_base = + t3_read_reg(adapter, A_ULPTX_PBL_LLIMIT); + req->pbl_top = t3_read_reg(adapter, A_ULPTX_PBL_ULIMIT); + req->rqt_base = t3_read_reg(adapter, A_ULPRX_RQ_LLIMIT); + req->rqt_top = t3_read_reg(adapter, A_ULPRX_RQ_ULIMIT); + req->kdb_addr = adapter->regs + A_SG_KDOORBELL; + req->pdev = pdev; + break; + } + case RDMA_CQ_OP:{ + unsigned long flags; + struct rdma_cq_op *req = data; + + /* may be called in any context */ + spin_lock_irqsave(&adapter->sge.reg_lock, flags); + ret = t3_sge_cqcntxt_op(adapter, req->id, req->op, + req->credits); + spin_unlock_irqrestore(&adapter->sge.reg_lock, flags); + break; + } + case RDMA_GET_MEM:{ + struct ch_mem_range *t = data; + struct mc7 *mem; + + if ((t->addr & 7) || (t->len & 7)) + return -EINVAL; + if (t->mem_id == MEM_CM) + mem = &adapter->cm; + else if (t->mem_id == MEM_PMRX) + mem = &adapter->pmrx; + else if (t->mem_id == MEM_PMTX) + mem = &adapter->pmtx; + else + return -EINVAL; + + ret = + t3_mc7_bd_read(mem, t->addr / 8, t->len / 8, + (u64 *) t->buf); + if (ret) + return ret; + break; + } + case RDMA_CQ_SETUP:{ + struct rdma_cq_setup *req = data; + + spin_lock_irq(&adapter->sge.reg_lock); + ret = + t3_sge_init_cqcntxt(adapter, req->id, + req->base_addr, req->size, + ASYNC_NOTIF_RSPQ, + req->ovfl_mode, req->credits, + req->credit_thres); + spin_unlock_irq(&adapter->sge.reg_lock); + break; + } + case RDMA_CQ_DISABLE: + spin_lock_irq(&adapter->sge.reg_lock); + ret = t3_sge_disable_cqcntxt(adapter, *(unsigned int *)data); + spin_unlock_irq(&adapter->sge.reg_lock); + break; + case RDMA_CTRL_QP_SETUP:{ + struct rdma_ctrlqp_setup *req = data; + + spin_lock_irq(&adapter->sge.reg_lock); + ret = t3_sge_init_ecntxt(adapter, FW_RI_SGEEC_START, 0, + SGE_CNTXT_RDMA, + ASYNC_NOTIF_RSPQ, + req->base_addr, req->size, + FW_RI_TID_START, 1, 0); + spin_unlock_irq(&adapter->sge.reg_lock); + break; + } + default: + ret = -EOPNOTSUPP; + } + return ret; +} + +static int cxgb_offload_ctl(struct t3cdev *tdev, unsigned int req, void *data) +{ + struct adapter *adapter = tdev2adap(tdev); + struct tid_range *tid; + struct mtutab *mtup; + struct iff_mac *iffmacp; + struct ddp_params *ddpp; + struct adap_ports *ports; + int i; + + switch (req) { + case GET_MAX_OUTSTANDING_WR: + *(unsigned int *)data = FW_WR_NUM; + break; + case GET_WR_LEN: + *(unsigned int *)data = WR_FLITS; + break; + case GET_TX_MAX_CHUNK: + *(unsigned int *)data = 1 << 20; /* 1MB */ + break; + case GET_TID_RANGE: + tid = data; + tid->num = t3_mc5_size(&adapter->mc5) - + adapter->params.mc5.nroutes - + adapter->params.mc5.nfilters - adapter->params.mc5.nservers; + tid->base = 0; + break; + case GET_STID_RANGE: + tid = data; + tid->num = adapter->params.mc5.nservers; + tid->base = t3_mc5_size(&adapter->mc5) - tid->num - + adapter->params.mc5.nfilters - adapter->params.mc5.nroutes; + break; + case GET_L2T_CAPACITY: + *(unsigned int *)data = 2048; + break; + case GET_MTUS: + mtup = data; + mtup->size = NMTUS; + mtup->mtus = adapter->params.mtus; + break; + case GET_IFF_FROM_MAC: + iffmacp = data; + iffmacp->dev = get_iff_from_mac(adapter, iffmacp->mac_addr, + iffmacp->vlan_tag & + VLAN_VID_MASK); + break; + case GET_DDP_PARAMS: + ddpp = data; + ddpp->llimit = t3_read_reg(adapter, A_ULPRX_TDDP_LLIMIT); + ddpp->ulimit = t3_read_reg(adapter, A_ULPRX_TDDP_ULIMIT); + ddpp->tag_mask = t3_read_reg(adapter, A_ULPRX_TDDP_TAGMASK); + break; + case GET_PORTS: + ports = data; + ports->nports = adapter->params.nports; + for_each_port(adapter, i) + ports->lldevs[i] = adapter->port[i]; + break; + case ULP_ISCSI_GET_PARAMS: + case ULP_ISCSI_SET_PARAMS: + if (!offload_running(adapter)) + return -EAGAIN; + return cxgb_ulp_iscsi_ctl(adapter, req, data); + case RDMA_GET_PARAMS: + case RDMA_CQ_OP: + case RDMA_CQ_SETUP: + case RDMA_CQ_DISABLE: + case RDMA_CTRL_QP_SETUP: + case RDMA_GET_MEM: + if (!offload_running(adapter)) + return -EAGAIN; + return cxgb_rdma_ctl(adapter, req, data); + default: + return -EOPNOTSUPP; + } + return 0; +} + +/* + * Dummy handler for Rx offload packets in case we get an offload packet before + * proper processing is setup. This complains and drops the packet as it isn't + * normal to get offload packets at this stage. + */ +static int rx_offload_blackhole(struct t3cdev *dev, struct sk_buff **skbs, + int n) +{ + CH_ERR(tdev2adap(dev), "%d unexpected offload packets, first data %u\n", + n, ntohl(*(__be32 *)skbs[0]->data)); + while (n--) + dev_kfree_skb_any(skbs[n]); + return 0; +} + +static void dummy_neigh_update(struct t3cdev *dev, struct neighbour *neigh) +{ +} + +void cxgb3_set_dummy_ops(struct t3cdev *dev) +{ + dev->recv = rx_offload_blackhole; + dev->neigh_update = dummy_neigh_update; +} + +/* + * Free an active-open TID. + */ +void *cxgb3_free_atid(struct t3cdev *tdev, int atid) +{ + struct tid_info *t = &(T3C_DATA(tdev))->tid_maps; + union active_open_entry *p = atid2entry(t, atid); + void *ctx = p->t3c_tid.ctx; + + spin_lock_bh(&t->atid_lock); + p->next = t->afree; + t->afree = p; + t->atids_in_use--; + spin_unlock_bh(&t->atid_lock); + + return ctx; +} + +EXPORT_SYMBOL(cxgb3_free_atid); + +/* + * Free a server TID and return it to the free pool. + */ +void cxgb3_free_stid(struct t3cdev *tdev, int stid) +{ + struct tid_info *t = &(T3C_DATA(tdev))->tid_maps; + union listen_entry *p = stid2entry(t, stid); + + spin_lock_bh(&t->stid_lock); + p->next = t->sfree; + t->sfree = p; + t->stids_in_use--; + spin_unlock_bh(&t->stid_lock); +} + +EXPORT_SYMBOL(cxgb3_free_stid); + +void cxgb3_insert_tid(struct t3cdev *tdev, struct cxgb3_client *client, + void *ctx, unsigned int tid) +{ + struct tid_info *t = &(T3C_DATA(tdev))->tid_maps; + + t->tid_tab[tid].client = client; + t->tid_tab[tid].ctx = ctx; + atomic_inc(&t->tids_in_use); +} + +EXPORT_SYMBOL(cxgb3_insert_tid); + +/* + * Populate a TID_RELEASE WR. The skb must be already propely sized. + */ +static inline void mk_tid_release(struct sk_buff *skb, unsigned int tid) +{ + struct cpl_tid_release *req; + + skb->priority = CPL_PRIORITY_SETUP; + req = (struct cpl_tid_release *)__skb_put(skb, sizeof(*req)); + req->wr.wr_hi = htonl(V_WR_OP(FW_WROPCODE_FORWARD)); + OPCODE_TID(req) = htonl(MK_OPCODE_TID(CPL_TID_RELEASE, tid)); +} + +static void t3_process_tid_release_list(struct work_struct *work) +{ + struct t3c_data *td = container_of(work, struct t3c_data, + tid_release_task); + struct sk_buff *skb; + struct t3cdev *tdev = td->dev; + + + spin_lock_bh(&td->tid_release_lock); + while (td->tid_release_list) { + struct t3c_tid_entry *p = td->tid_release_list; + + td->tid_release_list = (struct t3c_tid_entry *)p->ctx; + spin_unlock_bh(&td->tid_release_lock); + + skb = alloc_skb(sizeof(struct cpl_tid_release), + GFP_KERNEL | __GFP_NOFAIL); + mk_tid_release(skb, p - td->tid_maps.tid_tab); + cxgb3_ofld_send(tdev, skb); + p->ctx = NULL; + spin_lock_bh(&td->tid_release_lock); + } + spin_unlock_bh(&td->tid_release_lock); +} + +/* use ctx as a next pointer in the tid release list */ +void cxgb3_queue_tid_release(struct t3cdev *tdev, unsigned int tid) +{ + struct t3c_data *td = T3C_DATA(tdev); + struct t3c_tid_entry *p = &td->tid_maps.tid_tab[tid]; + + spin_lock_bh(&td->tid_release_lock); + p->ctx = (void *)td->tid_release_list; + td->tid_release_list = p; + if (!p->ctx) + schedule_work(&td->tid_release_task); + spin_unlock_bh(&td->tid_release_lock); +} + +EXPORT_SYMBOL(cxgb3_queue_tid_release); + +/* + * Remove a tid from the TID table. A client may defer processing its last + * CPL message if it is locked at the time it arrives, and while the message + * sits in the client's backlog the TID may be reused for another connection. + * To handle this we atomically switch the TID association if it still points + * to the original client context. + */ +void cxgb3_remove_tid(struct t3cdev *tdev, void *ctx, unsigned int tid) +{ + struct tid_info *t = &(T3C_DATA(tdev))->tid_maps; + + BUG_ON(tid >= t->ntids); + if (tdev->type == T3A) + (void)cmpxchg(&t->tid_tab[tid].ctx, ctx, NULL); + else { + struct sk_buff *skb; + + skb = alloc_skb(sizeof(struct cpl_tid_release), GFP_ATOMIC); + if (likely(skb)) { + mk_tid_release(skb, tid); + cxgb3_ofld_send(tdev, skb); + t->tid_tab[tid].ctx = NULL; + } else + cxgb3_queue_tid_release(tdev, tid); + } + atomic_dec(&t->tids_in_use); +} + +EXPORT_SYMBOL(cxgb3_remove_tid); + +int cxgb3_alloc_atid(struct t3cdev *tdev, struct cxgb3_client *client, + void *ctx) +{ + int atid = -1; + struct tid_info *t = &(T3C_DATA(tdev))->tid_maps; + + spin_lock_bh(&t->atid_lock); + if (t->afree) { + union active_open_entry *p = t->afree; + + atid = (p - t->atid_tab) + t->atid_base; + t->afree = p->next; + p->t3c_tid.ctx = ctx; + p->t3c_tid.client = client; + t->atids_in_use++; + } + spin_unlock_bh(&t->atid_lock); + return atid; +} + +EXPORT_SYMBOL(cxgb3_alloc_atid); + +int cxgb3_alloc_stid(struct t3cdev *tdev, struct cxgb3_client *client, + void *ctx) +{ + int stid = -1; + struct tid_info *t = &(T3C_DATA(tdev))->tid_maps; + + spin_lock_bh(&t->stid_lock); + if (t->sfree) { + union listen_entry *p = t->sfree; + + stid = (p - t->stid_tab) + t->stid_base; + t->sfree = p->next; + p->t3c_tid.ctx = ctx; + p->t3c_tid.client = client; + t->stids_in_use++; + } + spin_unlock_bh(&t->stid_lock); + return stid; +} + +EXPORT_SYMBOL(cxgb3_alloc_stid); + +static int do_smt_write_rpl(struct t3cdev *dev, struct sk_buff *skb) +{ + struct cpl_smt_write_rpl *rpl = cplhdr(skb); + + if (rpl->status != CPL_ERR_NONE) + printk(KERN_ERR + "Unexpected SMT_WRITE_RPL status %u for entry %u\n", + rpl->status, GET_TID(rpl)); + + return CPL_RET_BUF_DONE; +} + +static int do_l2t_write_rpl(struct t3cdev *dev, struct sk_buff *skb) +{ + struct cpl_l2t_write_rpl *rpl = cplhdr(skb); + + if (rpl->status != CPL_ERR_NONE) + printk(KERN_ERR + "Unexpected L2T_WRITE_RPL status %u for entry %u\n", + rpl->status, GET_TID(rpl)); + + return CPL_RET_BUF_DONE; +} + +static int do_act_open_rpl(struct t3cdev *dev, struct sk_buff *skb) +{ + struct cpl_act_open_rpl *rpl = cplhdr(skb); + unsigned int atid = G_TID(ntohl(rpl->atid)); + struct t3c_tid_entry *t3c_tid; + + t3c_tid = lookup_atid(&(T3C_DATA(dev))->tid_maps, atid); + if (t3c_tid->ctx && t3c_tid->client && t3c_tid->client->handlers && + t3c_tid->client->handlers[CPL_ACT_OPEN_RPL]) { + return t3c_tid->client->handlers[CPL_ACT_OPEN_RPL] (dev, skb, + t3c_tid-> + ctx); + } else { + printk(KERN_ERR "%s: received clientless CPL command 0x%x\n", + dev->name, CPL_ACT_OPEN_RPL); + return CPL_RET_BUF_DONE | CPL_RET_BAD_MSG; + } +} + +static int do_stid_rpl(struct t3cdev *dev, struct sk_buff *skb) +{ + union opcode_tid *p = cplhdr(skb); + unsigned int stid = G_TID(ntohl(p->opcode_tid)); + struct t3c_tid_entry *t3c_tid; + + t3c_tid = lookup_stid(&(T3C_DATA(dev))->tid_maps, stid); + if (t3c_tid->ctx && t3c_tid->client->handlers && + t3c_tid->client->handlers[p->opcode]) { + return t3c_tid->client->handlers[p->opcode] (dev, skb, + t3c_tid->ctx); + } else { + printk(KERN_ERR "%s: received clientless CPL command 0x%x\n", + dev->name, p->opcode); + return CPL_RET_BUF_DONE | CPL_RET_BAD_MSG; + } +} + +static int do_hwtid_rpl(struct t3cdev *dev, struct sk_buff *skb) +{ + union opcode_tid *p = cplhdr(skb); + unsigned int hwtid = G_TID(ntohl(p->opcode_tid)); + struct t3c_tid_entry *t3c_tid; + + t3c_tid = lookup_tid(&(T3C_DATA(dev))->tid_maps, hwtid); + if (t3c_tid->ctx && t3c_tid->client->handlers && + t3c_tid->client->handlers[p->opcode]) { + return t3c_tid->client->handlers[p->opcode] + (dev, skb, t3c_tid->ctx); + } else { + printk(KERN_ERR "%s: received clientless CPL command 0x%x\n", + dev->name, p->opcode); + return CPL_RET_BUF_DONE | CPL_RET_BAD_MSG; + } +} + +static int do_cr(struct t3cdev *dev, struct sk_buff *skb) +{ + struct cpl_pass_accept_req *req = cplhdr(skb); + unsigned int stid = G_PASS_OPEN_TID(ntohl(req->tos_tid)); + struct t3c_tid_entry *t3c_tid; + + t3c_tid = lookup_stid(&(T3C_DATA(dev))->tid_maps, stid); + if (t3c_tid->ctx && t3c_tid->client->handlers && + t3c_tid->client->handlers[CPL_PASS_ACCEPT_REQ]) { + return t3c_tid->client->handlers[CPL_PASS_ACCEPT_REQ] + (dev, skb, t3c_tid->ctx); + } else { + printk(KERN_ERR "%s: received clientless CPL command 0x%x\n", + dev->name, CPL_PASS_ACCEPT_REQ); + return CPL_RET_BUF_DONE | CPL_RET_BAD_MSG; + } +} + +static int do_abort_req_rss(struct t3cdev *dev, struct sk_buff *skb) +{ + union opcode_tid *p = cplhdr(skb); + unsigned int hwtid = G_TID(ntohl(p->opcode_tid)); + struct t3c_tid_entry *t3c_tid; + + t3c_tid = lookup_tid(&(T3C_DATA(dev))->tid_maps, hwtid); + if (t3c_tid->ctx && t3c_tid->client->handlers && + t3c_tid->client->handlers[p->opcode]) { + return t3c_tid->client->handlers[p->opcode] + (dev, skb, t3c_tid->ctx); + } else { + struct cpl_abort_req_rss *req = cplhdr(skb); + struct cpl_abort_rpl *rpl; + + struct sk_buff *skb = + alloc_skb(sizeof(struct cpl_abort_rpl), GFP_ATOMIC); + if (!skb) { + printk("do_abort_req_rss: couldn't get skb!\n"); + goto out; + } + skb->priority = CPL_PRIORITY_DATA; + __skb_put(skb, sizeof(struct cpl_abort_rpl)); + rpl = cplhdr(skb); + rpl->wr.wr_hi = + htonl(V_WR_OP(FW_WROPCODE_OFLD_HOST_ABORT_CON_RPL)); + rpl->wr.wr_lo = htonl(V_WR_TID(GET_TID(req))); + OPCODE_TID(rpl) = + htonl(MK_OPCODE_TID(CPL_ABORT_RPL, GET_TID(req))); + rpl->cmd = req->status; + cxgb3_ofld_send(dev, skb); +out: + return CPL_RET_BUF_DONE; + } +} + +static int do_act_establish(struct t3cdev *dev, struct sk_buff *skb) +{ + struct cpl_act_establish *req = cplhdr(skb); + unsigned int atid = G_PASS_OPEN_TID(ntohl(req->tos_tid)); + struct t3c_tid_entry *t3c_tid; + + t3c_tid = lookup_atid(&(T3C_DATA(dev))->tid_maps, atid); + if (t3c_tid->ctx && t3c_tid->client->handlers && + t3c_tid->client->handlers[CPL_ACT_ESTABLISH]) { + return t3c_tid->client->handlers[CPL_ACT_ESTABLISH] + (dev, skb, t3c_tid->ctx); + } else { + printk(KERN_ERR "%s: received clientless CPL command 0x%x\n", + dev->name, CPL_PASS_ACCEPT_REQ); + return CPL_RET_BUF_DONE | CPL_RET_BAD_MSG; + } +} + +static int do_set_tcb_rpl(struct t3cdev *dev, struct sk_buff *skb) +{ + struct cpl_set_tcb_rpl *rpl = cplhdr(skb); + + if (rpl->status != CPL_ERR_NONE) + printk(KERN_ERR + "Unexpected SET_TCB_RPL status %u for tid %u\n", + rpl->status, GET_TID(rpl)); + return CPL_RET_BUF_DONE; +} + +static int do_trace(struct t3cdev *dev, struct sk_buff *skb) +{ + struct cpl_trace_pkt *p = cplhdr(skb); + + skb->protocol = htons(0xffff); + skb->dev = dev->lldev; + skb_pull(skb, sizeof(*p)); + skb->mac.raw = skb->data; + netif_receive_skb(skb); + return 0; +} + +static int do_term(struct t3cdev *dev, struct sk_buff *skb) +{ + unsigned int hwtid = ntohl(skb->priority) >> 8 & 0xfffff; + unsigned int opcode = G_OPCODE(ntohl(skb->csum)); + struct t3c_tid_entry *t3c_tid; + + t3c_tid = lookup_tid(&(T3C_DATA(dev))->tid_maps, hwtid); + if (t3c_tid->ctx && t3c_tid->client->handlers && + t3c_tid->client->handlers[opcode]) { + return t3c_tid->client->handlers[opcode] (dev, skb, + t3c_tid->ctx); + } else { + printk(KERN_ERR "%s: received clientless CPL command 0x%x\n", + dev->name, opcode); + return CPL_RET_BUF_DONE | CPL_RET_BAD_MSG; + } +} + +static int nb_callback(struct notifier_block *self, unsigned long event, + void *ctx) +{ + switch (event) { + case (NETEVENT_NEIGH_UPDATE):{ + cxgb_neigh_update((struct neighbour *)ctx); + break; + } + case (NETEVENT_PMTU_UPDATE): + break; + case (NETEVENT_REDIRECT):{ + struct netevent_redirect *nr = ctx; + cxgb_redirect(nr->old, nr->new); + cxgb_neigh_update(nr->new->neighbour); + break; + } + default: + break; + } + return 0; +} + +static struct notifier_block nb = { + .notifier_call = nb_callback +}; + +/* + * Process a received packet with an unknown/unexpected CPL opcode. + */ +static int do_bad_cpl(struct t3cdev *dev, struct sk_buff *skb) +{ + printk(KERN_ERR "%s: received bad CPL command 0x%x\n", dev->name, + *skb->data); + return CPL_RET_BUF_DONE | CPL_RET_BAD_MSG; +} + +/* + * Handlers for each CPL opcode + */ +static cpl_handler_func cpl_handlers[NUM_CPL_CMDS]; + +/* + * Add a new handler to the CPL dispatch table. A NULL handler may be supplied + * to unregister an existing handler. + */ +void t3_register_cpl_handler(unsigned int opcode, cpl_handler_func h) +{ + if (opcode < NUM_CPL_CMDS) + cpl_handlers[opcode] = h ? h : do_bad_cpl; + else + printk(KERN_ERR "T3C: handler registration for " + "opcode %x failed\n", opcode); +} + +EXPORT_SYMBOL(t3_register_cpl_handler); + +/* + * T3CDEV's receive method. + */ +int process_rx(struct t3cdev *dev, struct sk_buff **skbs, int n) +{ + while (n--) { + struct sk_buff *skb = *skbs++; + unsigned int opcode = G_OPCODE(ntohl(skb->csum)); + int ret = cpl_handlers[opcode] (dev, skb); + +#if VALIDATE_TID + if (ret & CPL_RET_UNKNOWN_TID) { + union opcode_tid *p = cplhdr(skb); + + printk(KERN_ERR "%s: CPL message (opcode %u) had " + "unknown TID %u\n", dev->name, opcode, + G_TID(ntohl(p->opcode_tid))); + } +#endif + if (ret & CPL_RET_BUF_DONE) + kfree_skb(skb); + } + return 0; +} + +/* + * Sends an sk_buff to a T3C driver after dealing with any active network taps. + */ +int cxgb3_ofld_send(struct t3cdev *dev, struct sk_buff *skb) +{ + int r; + + local_bh_disable(); + r = dev->send(dev, skb); + local_bh_enable(); + return r; +} + +EXPORT_SYMBOL(cxgb3_ofld_send); + +static int is_offloading(struct net_device *dev) +{ + struct adapter *adapter; + int i; + + read_lock_bh(&adapter_list_lock); + list_for_each_entry(adapter, &adapter_list, adapter_list) { + for_each_port(adapter, i) { + if (dev == adapter->port[i]) { + read_unlock_bh(&adapter_list_lock); + return 1; + } + } + } + read_unlock_bh(&adapter_list_lock); + return 0; +} + +void cxgb_neigh_update(struct neighbour *neigh) +{ + struct net_device *dev = neigh->dev; + + if (dev && (is_offloading(dev))) { + struct t3cdev *tdev = T3CDEV(dev); + + BUG_ON(!tdev); + t3_l2t_update(tdev, neigh); + } +} + +static void set_l2t_ix(struct t3cdev *tdev, u32 tid, struct l2t_entry *e) +{ + struct sk_buff *skb; + struct cpl_set_tcb_field *req; + + skb = alloc_skb(sizeof(*req), GFP_ATOMIC); + if (!skb) { + printk(KERN_ERR "%s: cannot allocate skb!\n", __FUNCTION__); + return; + } + skb->priority = CPL_PRIORITY_CONTROL; + req = (struct cpl_set_tcb_field *)skb_put(skb, sizeof(*req)); + req->wr.wr_hi = htonl(V_WR_OP(FW_WROPCODE_FORWARD)); + OPCODE_TID(req) = htonl(MK_OPCODE_TID(CPL_SET_TCB_FIELD, tid)); + req->reply = 0; + req->cpu_idx = 0; + req->word = htons(W_TCB_L2T_IX); + req->mask = cpu_to_be64(V_TCB_L2T_IX(M_TCB_L2T_IX)); + req->val = cpu_to_be64(V_TCB_L2T_IX(e->idx)); + tdev->send(tdev, skb); +} + +void cxgb_redirect(struct dst_entry *old, struct dst_entry *new) +{ + struct net_device *olddev, *newdev; + struct tid_info *ti; + struct t3cdev *tdev; + u32 tid; + int update_tcb; + struct l2t_entry *e; + struct t3c_tid_entry *te; + + olddev = old->neighbour->dev; + newdev = new->neighbour->dev; + if (!is_offloading(olddev)) + return; + if (!is_offloading(newdev)) { + printk(KERN_WARNING "%s: Redirect to non-offload" + "device ignored.\n", __FUNCTION__); + return; + } + tdev = T3CDEV(olddev); + BUG_ON(!tdev); + if (tdev != T3CDEV(newdev)) { + printk(KERN_WARNING "%s: Redirect to different " + "offload device ignored.\n", __FUNCTION__); + return; + } + + /* Add new L2T entry */ + e = t3_l2t_get(tdev, new->neighbour, newdev); + if (!e) { + printk(KERN_ERR "%s: couldn't allocate new l2t entry!\n", + __FUNCTION__); + return; + } + + /* Walk tid table and notify clients of dst change. */ + ti = &(T3C_DATA(tdev))->tid_maps; + for (tid = 0; tid < ti->ntids; tid++) { + te = lookup_tid(ti, tid); + BUG_ON(!te); + if (te->ctx && te->client && te->client->redirect) { + update_tcb = te->client->redirect(te->ctx, old, new, e); + if (update_tcb) { + l2t_hold(L2DATA(tdev), e); + set_l2t_ix(tdev, tid, e); + } + } + } + l2t_release(L2DATA(tdev), e); +} + +/* + * Allocate a chunk of memory using kmalloc or, if that fails, vmalloc. + * The allocated memory is cleared. + */ +void *cxgb_alloc_mem(unsigned long size) +{ + void *p = kmalloc(size, GFP_KERNEL); + + if (!p) + p = vmalloc(size); + if (p) + memset(p, 0, size); + return p; +} + +/* + * Free memory allocated through t3_alloc_mem(). + */ +void cxgb_free_mem(void *addr) +{ + unsigned long p = (unsigned long)addr; + + if (p >= VMALLOC_START && p < VMALLOC_END) + vfree(addr); + else + kfree(addr); +} + +/* + * Allocate and initialize the TID tables. Returns 0 on success. + */ +static int init_tid_tabs(struct tid_info *t, unsigned int ntids, + unsigned int natids, unsigned int nstids, + unsigned int atid_base, unsigned int stid_base) +{ + unsigned long size = ntids * sizeof(*t->tid_tab) + + natids * sizeof(*t->atid_tab) + nstids * sizeof(*t->stid_tab); + + t->tid_tab = cxgb_alloc_mem(size); + if (!t->tid_tab) + return -ENOMEM; + + t->stid_tab = (union listen_entry *)&t->tid_tab[ntids]; + t->atid_tab = (union active_open_entry *)&t->stid_tab[nstids]; + t->ntids = ntids; + t->nstids = nstids; + t->stid_base = stid_base; + t->sfree = NULL; + t->natids = natids; + t->atid_base = atid_base; + t->afree = NULL; + t->stids_in_use = t->atids_in_use = 0; + atomic_set(&t->tids_in_use, 0); + spin_lock_init(&t->stid_lock); + spin_lock_init(&t->atid_lock); + + /* + * Setup the free lists for stid_tab and atid_tab. + */ + if (nstids) { + while (--nstids) + t->stid_tab[nstids - 1].next = &t->stid_tab[nstids]; + t->sfree = t->stid_tab; + } + if (natids) { + while (--natids) + t->atid_tab[natids - 1].next = &t->atid_tab[natids]; + t->afree = t->atid_tab; + } + return 0; +} + +static void free_tid_maps(struct tid_info *t) +{ + cxgb_free_mem(t->tid_tab); +} + +static inline void add_adapter(struct adapter *adap) +{ + write_lock_bh(&adapter_list_lock); + list_add_tail(&adap->adapter_list, &adapter_list); + write_unlock_bh(&adapter_list_lock); +} + +static inline void remove_adapter(struct adapter *adap) +{ + write_lock_bh(&adapter_list_lock); + list_del(&adap->adapter_list); + write_unlock_bh(&adapter_list_lock); +} + +int cxgb3_offload_activate(struct adapter *adapter) +{ + struct t3cdev *dev = &adapter->tdev; + int natids, err; + struct t3c_data *t; + struct tid_range stid_range, tid_range; + struct mtutab mtutab; + unsigned int l2t_capacity; + + t = kcalloc(1, sizeof(*t), GFP_KERNEL); + if (!t) + return -ENOMEM; + + err = -EOPNOTSUPP; + if (dev->ctl(dev, GET_TX_MAX_CHUNK, &t->tx_max_chunk) < 0 || + dev->ctl(dev, GET_MAX_OUTSTANDING_WR, &t->max_wrs) < 0 || + dev->ctl(dev, GET_L2T_CAPACITY, &l2t_capacity) < 0 || + dev->ctl(dev, GET_MTUS, &mtutab) < 0 || + dev->ctl(dev, GET_TID_RANGE, &tid_range) < 0 || + dev->ctl(dev, GET_STID_RANGE, &stid_range) < 0) + goto out_free; + + err = -ENOMEM; + L2DATA(dev) = t3_init_l2t(l2t_capacity); + if (!L2DATA(dev)) + goto out_free; + + natids = min(tid_range.num / 2, MAX_ATIDS); + err = init_tid_tabs(&t->tid_maps, tid_range.num, natids, + stid_range.num, ATID_BASE, stid_range.base); + if (err) + goto out_free_l2t; + + t->mtus = mtutab.mtus; + t->nmtus = mtutab.size; + + INIT_WORK(&t->tid_release_task, t3_process_tid_release_list); + spin_lock_init(&t->tid_release_lock); + INIT_LIST_HEAD(&t->list_node); + t->dev = dev; + + T3C_DATA(dev) = t; + dev->recv = process_rx; + dev->neigh_update = t3_l2t_update; + + /* Register netevent handler once */ + if (list_empty(&adapter_list)) + register_netevent_notifier(&nb); + + add_adapter(adapter); + return 0; + +out_free_l2t: + t3_free_l2t(L2DATA(dev)); + L2DATA(dev) = NULL; +out_free: + kfree(t); + return err; +} + +void cxgb3_offload_deactivate(struct adapter *adapter) +{ + struct t3cdev *tdev = &adapter->tdev; + struct t3c_data *t = T3C_DATA(tdev); + + remove_adapter(adapter); + if (list_empty(&adapter_list)) + unregister_netevent_notifier(&nb); + + free_tid_maps(&t->tid_maps); + T3C_DATA(tdev) = NULL; + t3_free_l2t(L2DATA(tdev)); + L2DATA(tdev) = NULL; + kfree(t); +} + +static inline void register_tdev(struct t3cdev *tdev) +{ + static int unit; + + mutex_lock(&cxgb3_db_lock); + snprintf(tdev->name, sizeof(tdev->name), "ofld_dev%d", unit++); + list_add_tail(&tdev->ofld_dev_list, &ofld_dev_list); + mutex_unlock(&cxgb3_db_lock); +} + +static inline void unregister_tdev(struct t3cdev *tdev) +{ + mutex_lock(&cxgb3_db_lock); + list_del(&tdev->ofld_dev_list); + mutex_unlock(&cxgb3_db_lock); +} + +void __devinit cxgb3_adapter_ofld(struct adapter *adapter) +{ + struct t3cdev *tdev = &adapter->tdev; + + INIT_LIST_HEAD(&tdev->ofld_dev_list); + + cxgb3_set_dummy_ops(tdev); + tdev->send = t3_offload_tx; + tdev->ctl = cxgb_offload_ctl; + tdev->type = adapter->params.rev == 0 ? T3A : T3B; + + register_tdev(tdev); +} + +void __devexit cxgb3_adapter_unofld(struct adapter *adapter) +{ + struct t3cdev *tdev = &adapter->tdev; + + tdev->recv = NULL; + tdev->neigh_update = NULL; + + unregister_tdev(tdev); +} + +void __init cxgb3_offload_init(void) +{ + int i; + + for (i = 0; i < NUM_CPL_CMDS; ++i) + cpl_handlers[i] = do_bad_cpl; + + t3_register_cpl_handler(CPL_SMT_WRITE_RPL, do_smt_write_rpl); + t3_register_cpl_handler(CPL_L2T_WRITE_RPL, do_l2t_write_rpl); + t3_register_cpl_handler(CPL_PASS_OPEN_RPL, do_stid_rpl); + t3_register_cpl_handler(CPL_CLOSE_LISTSRV_RPL, do_stid_rpl); + t3_register_cpl_handler(CPL_PASS_ACCEPT_REQ, do_cr); + t3_register_cpl_handler(CPL_PASS_ESTABLISH, do_hwtid_rpl); + t3_register_cpl_handler(CPL_ABORT_RPL_RSS, do_hwtid_rpl); + t3_register_cpl_handler(CPL_ABORT_RPL, do_hwtid_rpl); + t3_register_cpl_handler(CPL_RX_URG_NOTIFY, do_hwtid_rpl); + t3_register_cpl_handler(CPL_RX_DATA, do_hwtid_rpl); + t3_register_cpl_handler(CPL_TX_DATA_ACK, do_hwtid_rpl); + t3_register_cpl_handler(CPL_TX_DMA_ACK, do_hwtid_rpl); + t3_register_cpl_handler(CPL_ACT_OPEN_RPL, do_act_open_rpl); + t3_register_cpl_handler(CPL_PEER_CLOSE, do_hwtid_rpl); + t3_register_cpl_handler(CPL_CLOSE_CON_RPL, do_hwtid_rpl); + t3_register_cpl_handler(CPL_ABORT_REQ_RSS, do_abort_req_rss); + t3_register_cpl_handler(CPL_ACT_ESTABLISH, do_act_establish); + t3_register_cpl_handler(CPL_SET_TCB_RPL, do_set_tcb_rpl); + t3_register_cpl_handler(CPL_RDMA_TERMINATE, do_term); + t3_register_cpl_handler(CPL_RDMA_EC_STATUS, do_hwtid_rpl); + t3_register_cpl_handler(CPL_TRACE_PKT, do_trace); + t3_register_cpl_handler(CPL_RX_DATA_DDP, do_hwtid_rpl); + t3_register_cpl_handler(CPL_RX_DDP_COMPLETE, do_hwtid_rpl); + t3_register_cpl_handler(CPL_ISCSI_HDR, do_hwtid_rpl); +} diff --git a/drivers/net/cxgb3/cxgb3_offload.h b/drivers/net/cxgb3/cxgb3_offload.h new file mode 100644 index 0000000..0e6beb6 --- /dev/null +++ b/drivers/net/cxgb3/cxgb3_offload.h @@ -0,0 +1,193 @@ +/* + * Copyright (c) 2006-2007 Chelsio, Inc. All rights reserved. + * Copyright (c) 2006-2007 Open Grid Computing, Inc. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +#ifndef _CXGB3_OFFLOAD_H +#define _CXGB3_OFFLOAD_H + +#include +#include + +#include "l2t.h" + +#include "t3cdev.h" +#include "t3_cpl.h" + +struct adapter; + +void cxgb3_offload_init(void); + +void cxgb3_adapter_ofld(struct adapter *adapter); +void cxgb3_adapter_unofld(struct adapter *adapter); +int cxgb3_offload_activate(struct adapter *adapter); +void cxgb3_offload_deactivate(struct adapter *adapter); + +void cxgb3_set_dummy_ops(struct t3cdev *dev); + +/* + * Client registration. Users of T3 driver must register themselves. + * The T3 driver will call the add function of every client for each T3 + * adapter activated, passing up the t3cdev ptr. Each client fills out an + * array of callback functions to process CPL messages. + */ + +void cxgb3_register_client(struct cxgb3_client *client); +void cxgb3_unregister_client(struct cxgb3_client *client); +void cxgb3_add_clients(struct t3cdev *tdev); +void cxgb3_remove_clients(struct t3cdev *tdev); + +typedef int (*cxgb3_cpl_handler_func)(struct t3cdev *dev, + struct sk_buff *skb, void *ctx); + +struct cxgb3_client { + char *name; + void (*add) (struct t3cdev *); + void (*remove) (struct t3cdev *); + cxgb3_cpl_handler_func *handlers; + int (*redirect)(void *ctx, struct dst_entry *old, + struct dst_entry *new, struct l2t_entry *l2t); + struct list_head client_list; +}; + +/* + * TID allocation services. + */ +int cxgb3_alloc_atid(struct t3cdev *dev, struct cxgb3_client *client, + void *ctx); +int cxgb3_alloc_stid(struct t3cdev *dev, struct cxgb3_client *client, + void *ctx); +void *cxgb3_free_atid(struct t3cdev *dev, int atid); +void cxgb3_free_stid(struct t3cdev *dev, int stid); +void cxgb3_insert_tid(struct t3cdev *dev, struct cxgb3_client *client, + void *ctx, unsigned int tid); +void cxgb3_queue_tid_release(struct t3cdev *dev, unsigned int tid); +void cxgb3_remove_tid(struct t3cdev *dev, void *ctx, unsigned int tid); + +struct t3c_tid_entry { + struct cxgb3_client *client; + void *ctx; +}; + +/* CPL message priority levels */ +enum { + CPL_PRIORITY_DATA = 0, /* data messages */ + CPL_PRIORITY_SETUP = 1, /* connection setup messages */ + CPL_PRIORITY_TEARDOWN = 0, /* connection teardown messages */ + CPL_PRIORITY_LISTEN = 1, /* listen start/stop messages */ + CPL_PRIORITY_ACK = 1, /* RX ACK messages */ + CPL_PRIORITY_CONTROL = 1 /* offload control messages */ +}; + +/* Flags for return value of CPL message handlers */ +enum { + CPL_RET_BUF_DONE = 1, /* buffer processing done, buffer may be freed */ + CPL_RET_BAD_MSG = 2, /* bad CPL message (e.g., unknown opcode) */ + CPL_RET_UNKNOWN_TID = 4 /* unexpected unknown TID */ +}; + +typedef int (*cpl_handler_func)(struct t3cdev *dev, struct sk_buff *skb); + +/* + * Returns a pointer to the first byte of the CPL header in an sk_buff that + * contains a CPL message. + */ +static inline void *cplhdr(struct sk_buff *skb) +{ + return skb->data; +} + +void t3_register_cpl_handler(unsigned int opcode, cpl_handler_func h); + +union listen_entry { + struct t3c_tid_entry t3c_tid; + union listen_entry *next; +}; + +union active_open_entry { + struct t3c_tid_entry t3c_tid; + union active_open_entry *next; +}; + +/* + * Holds the size, base address, free list start, etc of the TID, server TID, + * and active-open TID tables for a offload device. + * The tables themselves are allocated dynamically. + */ +struct tid_info { + struct t3c_tid_entry *tid_tab; + unsigned int ntids; + atomic_t tids_in_use; + + union listen_entry *stid_tab; + unsigned int nstids; + unsigned int stid_base; + + union active_open_entry *atid_tab; + unsigned int natids; + unsigned int atid_base; + + /* + * The following members are accessed R/W so we put them in their own + * cache lines. + * + * XXX We could combine the atid fields above with the lock here since + * atids are use once (unlike other tids). OTOH the above fields are + * usually in cache due to tid_tab. + */ + spinlock_t atid_lock ____cacheline_aligned_in_smp; + union active_open_entry *afree; + unsigned int atids_in_use; + + spinlock_t stid_lock ____cacheline_aligned; + union listen_entry *sfree; + unsigned int stids_in_use; +}; + +struct t3c_data { + struct list_head list_node; + struct t3cdev *dev; + unsigned int tx_max_chunk; /* max payload for TX_DATA */ + unsigned int max_wrs; /* max in-flight WRs per connection */ + unsigned int nmtus; + const unsigned short *mtus; + struct tid_info tid_maps; + + struct t3c_tid_entry *tid_release_list; + spinlock_t tid_release_lock; + struct work_struct tid_release_task; +}; + +/* + * t3cdev -> t3c_data accessor + */ +#define T3C_DATA(dev) (*(struct t3c_data **)&(dev)->l4opt) + +#endif diff --git a/drivers/net/cxgb3/firmware_exports.h b/drivers/net/cxgb3/firmware_exports.h new file mode 100644 index 0000000..6a835f6 --- /dev/null +++ b/drivers/net/cxgb3/firmware_exports.h @@ -0,0 +1,177 @@ +/* + * Copyright (c) 2004-2007 Chelsio, Inc. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +#ifndef _FIRMWARE_EXPORTS_H_ +#define _FIRMWARE_EXPORTS_H_ + +/* WR OPCODES supported by the firmware. + */ +#define FW_WROPCODE_FORWARD 0x01 +#define FW_WROPCODE_BYPASS 0x05 + +#define FW_WROPCODE_TUNNEL_TX_PKT 0x03 + +#define FW_WROPOCDE_ULPTX_DATA_SGL 0x00 +#define FW_WROPCODE_ULPTX_MEM_READ 0x02 +#define FW_WROPCODE_ULPTX_PKT 0x04 +#define FW_WROPCODE_ULPTX_INVALIDATE 0x06 + +#define FW_WROPCODE_TUNNEL_RX_PKT 0x07 + +#define FW_WROPCODE_OFLD_GETTCB_RPL 0x08 +#define FW_WROPCODE_OFLD_CLOSE_CON 0x09 +#define FW_WROPCODE_OFLD_TP_ABORT_CON_REQ 0x0A +#define FW_WROPCODE_OFLD_HOST_ABORT_CON_RPL 0x0F +#define FW_WROPCODE_OFLD_HOST_ABORT_CON_REQ 0x0B +#define FW_WROPCODE_OFLD_TP_ABORT_CON_RPL 0x0C +#define FW_WROPCODE_OFLD_TX_DATA 0x0D +#define FW_WROPCODE_OFLD_TX_DATA_ACK 0x0E + +#define FW_WROPCODE_RI_RDMA_INIT 0x10 +#define FW_WROPCODE_RI_RDMA_WRITE 0x11 +#define FW_WROPCODE_RI_RDMA_READ_REQ 0x12 +#define FW_WROPCODE_RI_RDMA_READ_RESP 0x13 +#define FW_WROPCODE_RI_SEND 0x14 +#define FW_WROPCODE_RI_TERMINATE 0x15 +#define FW_WROPCODE_RI_RDMA_READ 0x16 +#define FW_WROPCODE_RI_RECEIVE 0x17 +#define FW_WROPCODE_RI_BIND_MW 0x18 +#define FW_WROPCODE_RI_FASTREGISTER_MR 0x19 +#define FW_WROPCODE_RI_LOCAL_INV 0x1A +#define FW_WROPCODE_RI_MODIFY_QP 0x1B +#define FW_WROPCODE_RI_BYPASS 0x1C + +#define FW_WROPOCDE_RSVD 0x1E + +#define FW_WROPCODE_SGE_EGRESSCONTEXT_RR 0x1F + +#define FW_WROPCODE_MNGT 0x1D +#define FW_MNGTOPCODE_PKTSCHED_SET 0x00 + +/* Maximum size of a WR sent from the host, limited by the SGE. + * + * Note: WR coming from ULP or TP are only limited by CIM. + */ +#define FW_WR_SIZE 128 + +/* Maximum number of outstanding WRs sent from the host. Value must be + * programmed in the CTRL/TUNNEL/QP SGE Egress Context and used by + * offload modules to limit the number of WRs per connection. + */ +#define FW_T3_WR_NUM 16 +#define FW_N3_WR_NUM 7 + +#ifndef N3 +# define FW_WR_NUM FW_T3_WR_NUM +#else +# define FW_WR_NUM FW_N3_WR_NUM +#endif + +/* FW_TUNNEL_NUM corresponds to the number of supported TUNNEL Queues. These + * queues must start at SGE Egress Context FW_TUNNEL_SGEEC_START and must + * start at 'TID' (or 'uP Token') FW_TUNNEL_TID_START. + * + * Ingress Traffic (e.g. DMA completion credit) for TUNNEL Queue[i] is sent + * to RESP Queue[i]. + */ +#define FW_TUNNEL_NUM 8 +#define FW_TUNNEL_SGEEC_START 8 +#define FW_TUNNEL_TID_START 65544 + +/* FW_CTRL_NUM corresponds to the number of supported CTRL Queues. These queues + * must start at SGE Egress Context FW_CTRL_SGEEC_START and must start at 'TID' + * (or 'uP Token') FW_CTRL_TID_START. + * + * Ingress Traffic for CTRL Queue[i] is sent to RESP Queue[i]. + */ +#define FW_CTRL_NUM 8 +#define FW_CTRL_SGEEC_START 65528 +#define FW_CTRL_TID_START 65536 + +/* FW_OFLD_NUM corresponds to the number of supported OFFLOAD Queues. These + * queues must start at SGE Egress Context FW_OFLD_SGEEC_START. + * + * Note: the 'uP Token' in the SGE Egress Context fields is irrelevant for + * OFFLOAD Queues, as the host is responsible for providing the correct TID in + * every WR. + * + * Ingress Trafffic for OFFLOAD Queue[i] is sent to RESP Queue[i]. + */ +#define FW_OFLD_NUM 8 +#define FW_OFLD_SGEEC_START 0 + +/* + * + */ +#define FW_RI_NUM 1 +#define FW_RI_SGEEC_START 65527 +#define FW_RI_TID_START 65552 + +/* + * The RX_PKT_TID + */ +#define FW_RX_PKT_NUM 1 +#define FW_RX_PKT_TID_START 65553 + +/* FW_WRC_NUM corresponds to the number of Work Request Context that supported + * by the firmware. + */ +#define FW_WRC_NUM \ + (65536 + FW_TUNNEL_NUM + FW_CTRL_NUM + FW_RI_NUM + FW_RX_PKT_NUM) + +/* + * FW type and version. + */ +#define S_FW_VERSION_TYPE 28 +#define M_FW_VERSION_TYPE 0xF +#define V_FW_VERSION_TYPE(x) ((x) << S_FW_VERSION_TYPE) +#define G_FW_VERSION_TYPE(x) \ + (((x) >> S_FW_VERSION_TYPE) & M_FW_VERSION_TYPE) + +#define S_FW_VERSION_MAJOR 16 +#define M_FW_VERSION_MAJOR 0xFFF +#define V_FW_VERSION_MAJOR(x) ((x) << S_FW_VERSION_MAJOR) +#define G_FW_VERSION_MAJOR(x) \ + (((x) >> S_FW_VERSION_MAJOR) & M_FW_VERSION_MAJOR) + +#define S_FW_VERSION_MINOR 8 +#define M_FW_VERSION_MINOR 0xFF +#define V_FW_VERSION_MINOR(x) ((x) << S_FW_VERSION_MINOR) +#define G_FW_VERSION_MINOR(x) \ + (((x) >> S_FW_VERSION_MINOR) & M_FW_VERSION_MINOR) + +#define S_FW_VERSION_MICRO 0 +#define M_FW_VERSION_MICRO 0xFF +#define V_FW_VERSION_MICRO(x) ((x) << S_FW_VERSION_MICRO) +#define G_FW_VERSION_MICRO(x) \ + (((x) >> S_FW_VERSION_MICRO) & M_FW_VERSION_MICRO) + +#endif /* _FIRMWARE_EXPORTS_H_ */ diff --git a/drivers/net/cxgb3/l2t.c b/drivers/net/cxgb3/l2t.c new file mode 100644 index 0000000..3c0cb85 --- /dev/null +++ b/drivers/net/cxgb3/l2t.c @@ -0,0 +1,450 @@ +/* + * Copyright (c) 2003-2007 Chelsio, Inc. All rights reserved. + * Copyright (c) 2006-2007 Open Grid Computing, Inc. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +#include +#include +#include +#include +#include +#include +#include "common.h" +#include "t3cdev.h" +#include "cxgb3_defs.h" +#include "l2t.h" +#include "t3_cpl.h" +#include "firmware_exports.h" + +#define VLAN_NONE 0xfff + +/* + * Module locking notes: There is a RW lock protecting the L2 table as a + * whole plus a spinlock per L2T entry. Entry lookups and allocations happen + * under the protection of the table lock, individual entry changes happen + * while holding that entry's spinlock. The table lock nests outside the + * entry locks. Allocations of new entries take the table lock as writers so + * no other lookups can happen while allocating new entries. Entry updates + * take the table lock as readers so multiple entries can be updated in + * parallel. An L2T entry can be dropped by decrementing its reference count + * and therefore can happen in parallel with entry allocation but no entry + * can change state or increment its ref count during allocation as both of + * these perform lookups. + */ + +static inline unsigned int vlan_prio(const struct l2t_entry *e) +{ + return e->vlan >> 13; +} + +static inline unsigned int arp_hash(u32 key, int ifindex, + const struct l2t_data *d) +{ + return jhash_2words(key, ifindex, 0) & (d->nentries - 1); +} + +static inline void neigh_replace(struct l2t_entry *e, struct neighbour *n) +{ + neigh_hold(n); + if (e->neigh) + neigh_release(e->neigh); + e->neigh = n; +} + +/* + * Set up an L2T entry and send any packets waiting in the arp queue. The + * supplied skb is used for the CPL_L2T_WRITE_REQ. Must be called with the + * entry locked. + */ +static int setup_l2e_send_pending(struct t3cdev *dev, struct sk_buff *skb, + struct l2t_entry *e) +{ + struct cpl_l2t_write_req *req; + + if (!skb) { + skb = alloc_skb(sizeof(*req), GFP_ATOMIC); + if (!skb) + return -ENOMEM; + } + + req = (struct cpl_l2t_write_req *)__skb_put(skb, sizeof(*req)); + req->wr.wr_hi = htonl(V_WR_OP(FW_WROPCODE_FORWARD)); + OPCODE_TID(req) = htonl(MK_OPCODE_TID(CPL_L2T_WRITE_REQ, e->idx)); + req->params = htonl(V_L2T_W_IDX(e->idx) | V_L2T_W_IFF(e->smt_idx) | + V_L2T_W_VLAN(e->vlan & VLAN_VID_MASK) | + V_L2T_W_PRIO(vlan_prio(e))); + memcpy(e->dmac, e->neigh->ha, sizeof(e->dmac)); + memcpy(req->dst_mac, e->dmac, sizeof(req->dst_mac)); + skb->priority = CPL_PRIORITY_CONTROL; + cxgb3_ofld_send(dev, skb); + while (e->arpq_head) { + skb = e->arpq_head; + e->arpq_head = skb->next; + skb->next = NULL; + cxgb3_ofld_send(dev, skb); + } + e->arpq_tail = NULL; + e->state = L2T_STATE_VALID; + + return 0; +} + +/* + * Add a packet to the an L2T entry's queue of packets awaiting resolution. + * Must be called with the entry's lock held. + */ +static inline void arpq_enqueue(struct l2t_entry *e, struct sk_buff *skb) +{ + skb->next = NULL; + if (e->arpq_head) + e->arpq_tail->next = skb; + else + e->arpq_head = skb; + e->arpq_tail = skb; +} + +int t3_l2t_send_slow(struct t3cdev *dev, struct sk_buff *skb, + struct l2t_entry *e) +{ +again: + switch (e->state) { + case L2T_STATE_STALE: /* entry is stale, kick off revalidation */ + neigh_event_send(e->neigh, NULL); + spin_lock_bh(&e->lock); + if (e->state == L2T_STATE_STALE) + e->state = L2T_STATE_VALID; + spin_unlock_bh(&e->lock); + case L2T_STATE_VALID: /* fast-path, send the packet on */ + return cxgb3_ofld_send(dev, skb); + case L2T_STATE_RESOLVING: + spin_lock_bh(&e->lock); + if (e->state != L2T_STATE_RESOLVING) { + /* ARP already completed */ + spin_unlock_bh(&e->lock); + goto again; + } + arpq_enqueue(e, skb); + spin_unlock_bh(&e->lock); + + /* + * Only the first packet added to the arpq should kick off + * resolution. However, because the alloc_skb below can fail, + * we allow each packet added to the arpq to retry resolution + * as a way of recovering from transient memory exhaustion. + * A better way would be to use a work request to retry L2T + * entries when there's no memory. + */ + if (!neigh_event_send(e->neigh, NULL)) { + skb = alloc_skb(sizeof(struct cpl_l2t_write_req), + GFP_ATOMIC); + if (!skb) + break; + + spin_lock_bh(&e->lock); + if (e->arpq_head) + setup_l2e_send_pending(dev, skb, e); + else /* we lost the race */ + __kfree_skb(skb); + spin_unlock_bh(&e->lock); + } + } + return 0; +} + +EXPORT_SYMBOL(t3_l2t_send_slow); + +void t3_l2t_send_event(struct t3cdev *dev, struct l2t_entry *e) +{ +again: + switch (e->state) { + case L2T_STATE_STALE: /* entry is stale, kick off revalidation */ + neigh_event_send(e->neigh, NULL); + spin_lock_bh(&e->lock); + if (e->state == L2T_STATE_STALE) { + e->state = L2T_STATE_VALID; + } + spin_unlock_bh(&e->lock); + return; + case L2T_STATE_VALID: /* fast-path, send the packet on */ + return; + case L2T_STATE_RESOLVING: + spin_lock_bh(&e->lock); + if (e->state != L2T_STATE_RESOLVING) { + /* ARP already completed */ + spin_unlock_bh(&e->lock); + goto again; + } + spin_unlock_bh(&e->lock); + + /* + * Only the first packet added to the arpq should kick off + * resolution. However, because the alloc_skb below can fail, + * we allow each packet added to the arpq to retry resolution + * as a way of recovering from transient memory exhaustion. + * A better way would be to use a work request to retry L2T + * entries when there's no memory. + */ + neigh_event_send(e->neigh, NULL); + } + return; +} + +EXPORT_SYMBOL(t3_l2t_send_event); + +/* + * Allocate a free L2T entry. Must be called with l2t_data.lock held. + */ +static struct l2t_entry *alloc_l2e(struct l2t_data *d) +{ + struct l2t_entry *end, *e, **p; + + if (!atomic_read(&d->nfree)) + return NULL; + + /* there's definitely a free entry */ + for (e = d->rover, end = &d->l2tab[d->nentries]; e != end; ++e) + if (atomic_read(&e->refcnt) == 0) + goto found; + + for (e = &d->l2tab[1]; atomic_read(&e->refcnt); ++e) ; +found: + d->rover = e + 1; + atomic_dec(&d->nfree); + + /* + * The entry we found may be an inactive entry that is + * presently in the hash table. We need to remove it. + */ + if (e->state != L2T_STATE_UNUSED) { + int hash = arp_hash(e->addr, e->ifindex, d); + + for (p = &d->l2tab[hash].first; *p; p = &(*p)->next) + if (*p == e) { + *p = e->next; + break; + } + e->state = L2T_STATE_UNUSED; + } + return e; +} + +/* + * Called when an L2T entry has no more users. The entry is left in the hash + * table since it is likely to be reused but we also bump nfree to indicate + * that the entry can be reallocated for a different neighbor. We also drop + * the existing neighbor reference in case the neighbor is going away and is + * waiting on our reference. + * + * Because entries can be reallocated to other neighbors once their ref count + * drops to 0 we need to take the entry's lock to avoid races with a new + * incarnation. + */ +void t3_l2e_free(struct l2t_data *d, struct l2t_entry *e) +{ + spin_lock_bh(&e->lock); + if (atomic_read(&e->refcnt) == 0) { /* hasn't been recycled */ + if (e->neigh) { + neigh_release(e->neigh); + e->neigh = NULL; + } + } + spin_unlock_bh(&e->lock); + atomic_inc(&d->nfree); +} + +EXPORT_SYMBOL(t3_l2e_free); + +/* + * Update an L2T entry that was previously used for the same next hop as neigh. + * Must be called with softirqs disabled. + */ +static inline void reuse_entry(struct l2t_entry *e, struct neighbour *neigh) +{ + unsigned int nud_state; + + spin_lock(&e->lock); /* avoid race with t3_l2t_free */ + + if (neigh != e->neigh) + neigh_replace(e, neigh); + nud_state = neigh->nud_state; + if (memcmp(e->dmac, neigh->ha, sizeof(e->dmac)) || + !(nud_state & NUD_VALID)) + e->state = L2T_STATE_RESOLVING; + else if (nud_state & NUD_CONNECTED) + e->state = L2T_STATE_VALID; + else + e->state = L2T_STATE_STALE; + spin_unlock(&e->lock); +} + +struct l2t_entry *t3_l2t_get(struct t3cdev *cdev, struct neighbour *neigh, + struct net_device *dev) +{ + struct l2t_entry *e; + struct l2t_data *d = L2DATA(cdev); + u32 addr = *(u32 *) neigh->primary_key; + int ifidx = neigh->dev->ifindex; + int hash = arp_hash(addr, ifidx, d); + struct port_info *p = netdev_priv(dev); + int smt_idx = p->port_id; + + write_lock_bh(&d->lock); + for (e = d->l2tab[hash].first; e; e = e->next) + if (e->addr == addr && e->ifindex == ifidx && + e->smt_idx == smt_idx) { + l2t_hold(d, e); + if (atomic_read(&e->refcnt) == 1) + reuse_entry(e, neigh); + goto done; + } + + /* Need to allocate a new entry */ + e = alloc_l2e(d); + if (e) { + spin_lock(&e->lock); /* avoid race with t3_l2t_free */ + e->next = d->l2tab[hash].first; + d->l2tab[hash].first = e; + e->state = L2T_STATE_RESOLVING; + e->addr = addr; + e->ifindex = ifidx; + e->smt_idx = smt_idx; + atomic_set(&e->refcnt, 1); + neigh_replace(e, neigh); + if (neigh->dev->priv_flags & IFF_802_1Q_VLAN) + e->vlan = VLAN_DEV_INFO(neigh->dev)->vlan_id; + else + e->vlan = VLAN_NONE; + spin_unlock(&e->lock); + } +done: + write_unlock_bh(&d->lock); + return e; +} + +EXPORT_SYMBOL(t3_l2t_get); + +/* + * Called when address resolution fails for an L2T entry to handle packets + * on the arpq head. If a packet specifies a failure handler it is invoked, + * otherwise the packets is sent to the offload device. + * + * XXX: maybe we should abandon the latter behavior and just require a failure + * handler. + */ +static void handle_failed_resolution(struct t3cdev *dev, struct sk_buff *arpq) +{ + while (arpq) { + struct sk_buff *skb = arpq; + struct l2t_skb_cb *cb = L2T_SKB_CB(skb); + + arpq = skb->next; + skb->next = NULL; + if (cb->arp_failure_handler) + cb->arp_failure_handler(dev, skb); + else + cxgb3_ofld_send(dev, skb); + } +} + +/* + * Called when the host's ARP layer makes a change to some entry that is + * loaded into the HW L2 table. + */ +void t3_l2t_update(struct t3cdev *dev, struct neighbour *neigh) +{ + struct l2t_entry *e; + struct sk_buff *arpq = NULL; + struct l2t_data *d = L2DATA(dev); + u32 addr = *(u32 *) neigh->primary_key; + int ifidx = neigh->dev->ifindex; + int hash = arp_hash(addr, ifidx, d); + + read_lock_bh(&d->lock); + for (e = d->l2tab[hash].first; e; e = e->next) + if (e->addr == addr && e->ifindex == ifidx) { + spin_lock(&e->lock); + goto found; + } + read_unlock_bh(&d->lock); + return; + +found: + read_unlock(&d->lock); + if (atomic_read(&e->refcnt)) { + if (neigh != e->neigh) + neigh_replace(e, neigh); + + if (e->state == L2T_STATE_RESOLVING) { + if (neigh->nud_state & NUD_FAILED) { + arpq = e->arpq_head; + e->arpq_head = e->arpq_tail = NULL; + } else if (neigh_is_connected(neigh)) + setup_l2e_send_pending(dev, NULL, e); + } else { + e->state = neigh_is_connected(neigh) ? + L2T_STATE_VALID : L2T_STATE_STALE; + if (memcmp(e->dmac, neigh->ha, 6)) + setup_l2e_send_pending(dev, NULL, e); + } + } + spin_unlock_bh(&e->lock); + + if (arpq) + handle_failed_resolution(dev, arpq); +} + +struct l2t_data *t3_init_l2t(unsigned int l2t_capacity) +{ + struct l2t_data *d; + int i, size = sizeof(*d) + l2t_capacity * sizeof(struct l2t_entry); + + d = cxgb_alloc_mem(size); + if (!d) + return NULL; + + d->nentries = l2t_capacity; + d->rover = &d->l2tab[1]; /* entry 0 is not used */ + atomic_set(&d->nfree, l2t_capacity - 1); + rwlock_init(&d->lock); + + for (i = 0; i < l2t_capacity; ++i) { + d->l2tab[i].idx = i; + d->l2tab[i].state = L2T_STATE_UNUSED; + spin_lock_init(&d->l2tab[i].lock); + atomic_set(&d->l2tab[i].refcnt, 0); + } + return d; +} + +void t3_free_l2t(struct l2t_data *d) +{ + cxgb_free_mem(d); +} + diff --git a/drivers/net/cxgb3/l2t.h b/drivers/net/cxgb3/l2t.h new file mode 100644 index 0000000..ba5d2cb --- /dev/null +++ b/drivers/net/cxgb3/l2t.h @@ -0,0 +1,143 @@ +/* + * Copyright (c) 2003-2007 Chelsio, Inc. All rights reserved. + * Copyright (c) 2006-2007 Open Grid Computing, Inc. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +#ifndef _CHELSIO_L2T_H +#define _CHELSIO_L2T_H + +#include +#include "t3cdev.h" +#include + +enum { + L2T_STATE_VALID, /* entry is up to date */ + L2T_STATE_STALE, /* entry may be used but needs revalidation */ + L2T_STATE_RESOLVING, /* entry needs address resolution */ + L2T_STATE_UNUSED /* entry not in use */ +}; + +struct neighbour; +struct sk_buff; + +/* + * Each L2T entry plays multiple roles. First of all, it keeps state for the + * corresponding entry of the HW L2 table and maintains a queue of offload + * packets awaiting address resolution. Second, it is a node of a hash table + * chain, where the nodes of the chain are linked together through their next + * pointer. Finally, each node is a bucket of a hash table, pointing to the + * first element in its chain through its first pointer. + */ +struct l2t_entry { + u16 state; /* entry state */ + u16 idx; /* entry index */ + u32 addr; /* dest IP address */ + int ifindex; /* neighbor's net_device's ifindex */ + u16 smt_idx; /* SMT index */ + u16 vlan; /* VLAN TCI (id: bits 0-11, prio: 13-15 */ + struct neighbour *neigh; /* associated neighbour */ + struct l2t_entry *first; /* start of hash chain */ + struct l2t_entry *next; /* next l2t_entry on chain */ + struct sk_buff *arpq_head; /* queue of packets awaiting resolution */ + struct sk_buff *arpq_tail; + spinlock_t lock; + atomic_t refcnt; /* entry reference count */ + u8 dmac[6]; /* neighbour's MAC address */ +}; + +struct l2t_data { + unsigned int nentries; /* number of entries */ + struct l2t_entry *rover; /* starting point for next allocation */ + atomic_t nfree; /* number of free entries */ + rwlock_t lock; + struct l2t_entry l2tab[0]; +}; + +typedef void (*arp_failure_handler_func)(struct t3cdev * dev, + struct sk_buff * skb); + +/* + * Callback stored in an skb to handle address resolution failure. + */ +struct l2t_skb_cb { + arp_failure_handler_func arp_failure_handler; +}; + +#define L2T_SKB_CB(skb) ((struct l2t_skb_cb *)(skb)->cb) + +static inline void set_arp_failure_handler(struct sk_buff *skb, + arp_failure_handler_func hnd) +{ + L2T_SKB_CB(skb)->arp_failure_handler = hnd; +} + +/* + * Getting to the L2 data from an offload device. + */ +#define L2DATA(dev) ((dev)->l2opt) + +#define W_TCB_L2T_IX 0 +#define S_TCB_L2T_IX 7 +#define M_TCB_L2T_IX 0x7ffULL +#define V_TCB_L2T_IX(x) ((x) << S_TCB_L2T_IX) + +void t3_l2e_free(struct l2t_data *d, struct l2t_entry *e); +void t3_l2t_update(struct t3cdev *dev, struct neighbour *neigh); +struct l2t_entry *t3_l2t_get(struct t3cdev *cdev, struct neighbour *neigh, + struct net_device *dev); +int t3_l2t_send_slow(struct t3cdev *dev, struct sk_buff *skb, + struct l2t_entry *e); +void t3_l2t_send_event(struct t3cdev *dev, struct l2t_entry *e); +struct l2t_data *t3_init_l2t(unsigned int l2t_capacity); +void t3_free_l2t(struct l2t_data *d); + +int cxgb3_ofld_send(struct t3cdev *dev, struct sk_buff *skb); + +static inline int l2t_send(struct t3cdev *dev, struct sk_buff *skb, + struct l2t_entry *e) +{ + if (likely(e->state == L2T_STATE_VALID)) + return cxgb3_ofld_send(dev, skb); + return t3_l2t_send_slow(dev, skb, e); +} + +static inline void l2t_release(struct l2t_data *d, struct l2t_entry *e) +{ + if (atomic_dec_and_test(&e->refcnt)) + t3_l2e_free(d, e); +} + +static inline void l2t_hold(struct l2t_data *d, struct l2t_entry *e) +{ + if (atomic_add_return(1, &e->refcnt) == 1) /* 0 -> 1 transition */ + atomic_dec(&d->nfree); +} + +#endif diff --git a/drivers/net/cxgb3/mc5.c b/drivers/net/cxgb3/mc5.c new file mode 100644 index 0000000..644d62e --- /dev/null +++ b/drivers/net/cxgb3/mc5.c @@ -0,0 +1,473 @@ +/* + * Copyright (c) 2003-2007 Chelsio, Inc. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +#include "common.h" +#include "regs.h" + +enum { + IDT75P52100 = 4, + IDT75N43102 = 5 +}; + +/* DBGI command mode */ +enum { + DBGI_MODE_MBUS = 0, + DBGI_MODE_IDT52100 = 5 +}; + +/* IDT 75P52100 commands */ +#define IDT_CMD_READ 0 +#define IDT_CMD_WRITE 1 +#define IDT_CMD_SEARCH 2 +#define IDT_CMD_LEARN 3 + +/* IDT LAR register address and value for 144-bit mode (low 32 bits) */ +#define IDT_LAR_ADR0 0x180006 +#define IDT_LAR_MODE144 0xffff0000 + +/* IDT SCR and SSR addresses (low 32 bits) */ +#define IDT_SCR_ADR0 0x180000 +#define IDT_SSR0_ADR0 0x180002 +#define IDT_SSR1_ADR0 0x180004 + +/* IDT GMR base address (low 32 bits) */ +#define IDT_GMR_BASE_ADR0 0x180020 + +/* IDT data and mask array base addresses (low 32 bits) */ +#define IDT_DATARY_BASE_ADR0 0 +#define IDT_MSKARY_BASE_ADR0 0x80000 + +/* IDT 75N43102 commands */ +#define IDT4_CMD_SEARCH144 3 +#define IDT4_CMD_WRITE 4 +#define IDT4_CMD_READ 5 + +/* IDT 75N43102 SCR address (low 32 bits) */ +#define IDT4_SCR_ADR0 0x3 + +/* IDT 75N43102 GMR base addresses (low 32 bits) */ +#define IDT4_GMR_BASE0 0x10 +#define IDT4_GMR_BASE1 0x20 +#define IDT4_GMR_BASE2 0x30 + +/* IDT 75N43102 data and mask array base addresses (low 32 bits) */ +#define IDT4_DATARY_BASE_ADR0 0x1000000 +#define IDT4_MSKARY_BASE_ADR0 0x2000000 + +#define MAX_WRITE_ATTEMPTS 5 + +#define MAX_ROUTES 2048 + +/* + * Issue a command to the TCAM and wait for its completion. The address and + * any data required by the command must have been setup by the caller. + */ +static int mc5_cmd_write(struct adapter *adapter, u32 cmd) +{ + t3_write_reg(adapter, A_MC5_DB_DBGI_REQ_CMD, cmd); + return t3_wait_op_done(adapter, A_MC5_DB_DBGI_RSP_STATUS, + F_DBGIRSPVALID, 1, MAX_WRITE_ATTEMPTS, 1); +} + +static inline void dbgi_wr_addr3(struct adapter *adapter, u32 v1, u32 v2, + u32 v3) +{ + t3_write_reg(adapter, A_MC5_DB_DBGI_REQ_ADDR0, v1); + t3_write_reg(adapter, A_MC5_DB_DBGI_REQ_ADDR1, v2); + t3_write_reg(adapter, A_MC5_DB_DBGI_REQ_ADDR2, v3); +} + +static inline void dbgi_wr_data3(struct adapter *adapter, u32 v1, u32 v2, + u32 v3) +{ + t3_write_reg(adapter, A_MC5_DB_DBGI_REQ_DATA0, v1); + t3_write_reg(adapter, A_MC5_DB_DBGI_REQ_DATA1, v2); + t3_write_reg(adapter, A_MC5_DB_DBGI_REQ_DATA2, v3); +} + +static inline void dbgi_rd_rsp3(struct adapter *adapter, u32 *v1, u32 *v2, + u32 *v3) +{ + *v1 = t3_read_reg(adapter, A_MC5_DB_DBGI_RSP_DATA0); + *v2 = t3_read_reg(adapter, A_MC5_DB_DBGI_RSP_DATA1); + *v3 = t3_read_reg(adapter, A_MC5_DB_DBGI_RSP_DATA2); +} + +/* + * Write data to the TCAM register at address (0, 0, addr_lo) using the TCAM + * command cmd. The data to be written must have been set up by the caller. + * Returns -1 on failure, 0 on success. + */ +static int mc5_write(struct adapter *adapter, u32 addr_lo, u32 cmd) +{ + t3_write_reg(adapter, A_MC5_DB_DBGI_REQ_ADDR0, addr_lo); + if (mc5_cmd_write(adapter, cmd) == 0) + return 0; + CH_ERR(adapter, "MC5 timeout writing to TCAM address 0x%x\n", + addr_lo); + return -1; +} + +static int init_mask_data_array(struct mc5 *mc5, u32 mask_array_base, + u32 data_array_base, u32 write_cmd, + int addr_shift) +{ + unsigned int i; + struct adapter *adap = mc5->adapter; + + /* + * We need the size of the TCAM data and mask arrays in terms of + * 72-bit entries. + */ + unsigned int size72 = mc5->tcam_size; + unsigned int server_base = t3_read_reg(adap, A_MC5_DB_SERVER_INDEX); + + if (mc5->mode == MC5_MODE_144_BIT) { + size72 *= 2; /* 1 144-bit entry is 2 72-bit entries */ + server_base *= 2; + } + + /* Clear the data array */ + dbgi_wr_data3(adap, 0, 0, 0); + for (i = 0; i < size72; i++) + if (mc5_write(adap, data_array_base + (i << addr_shift), + write_cmd)) + return -1; + + /* Initialize the mask array. */ + dbgi_wr_data3(adap, 0xffffffff, 0xffffffff, 0xff); + for (i = 0; i < size72; i++) { + if (i == server_base) /* entering server or routing region */ + t3_write_reg(adap, A_MC5_DB_DBGI_REQ_DATA0, + mc5->mode == MC5_MODE_144_BIT ? + 0xfffffff9 : 0xfffffffd); + if (mc5_write(adap, mask_array_base + (i << addr_shift), + write_cmd)) + return -1; + } + return 0; +} + +static int init_idt52100(struct mc5 *mc5) +{ + int i; + struct adapter *adap = mc5->adapter; + + t3_write_reg(adap, A_MC5_DB_RSP_LATENCY, + V_RDLAT(0x15) | V_LRNLAT(0x15) | V_SRCHLAT(0x15)); + t3_write_reg(adap, A_MC5_DB_PART_ID_INDEX, 2); + + /* + * Use GMRs 14-15 for ELOOKUP, GMRs 12-13 for SYN lookups, and + * GMRs 8-9 for ACK- and AOPEN searches. + */ + t3_write_reg(adap, A_MC5_DB_POPEN_DATA_WR_CMD, IDT_CMD_WRITE); + t3_write_reg(adap, A_MC5_DB_POPEN_MASK_WR_CMD, IDT_CMD_WRITE); + t3_write_reg(adap, A_MC5_DB_AOPEN_SRCH_CMD, IDT_CMD_SEARCH); + t3_write_reg(adap, A_MC5_DB_AOPEN_LRN_CMD, IDT_CMD_LEARN); + t3_write_reg(adap, A_MC5_DB_SYN_SRCH_CMD, IDT_CMD_SEARCH | 0x6000); + t3_write_reg(adap, A_MC5_DB_SYN_LRN_CMD, IDT_CMD_LEARN); + t3_write_reg(adap, A_MC5_DB_ACK_SRCH_CMD, IDT_CMD_SEARCH); + t3_write_reg(adap, A_MC5_DB_ACK_LRN_CMD, IDT_CMD_LEARN); + t3_write_reg(adap, A_MC5_DB_ILOOKUP_CMD, IDT_CMD_SEARCH); + t3_write_reg(adap, A_MC5_DB_ELOOKUP_CMD, IDT_CMD_SEARCH | 0x7000); + t3_write_reg(adap, A_MC5_DB_DATA_WRITE_CMD, IDT_CMD_WRITE); + t3_write_reg(adap, A_MC5_DB_DATA_READ_CMD, IDT_CMD_READ); + + /* Set DBGI command mode for IDT TCAM. */ + t3_write_reg(adap, A_MC5_DB_DBGI_CONFIG, DBGI_MODE_IDT52100); + + /* Set up LAR */ + dbgi_wr_data3(adap, IDT_LAR_MODE144, 0, 0); + if (mc5_write(adap, IDT_LAR_ADR0, IDT_CMD_WRITE)) + goto err; + + /* Set up SSRs */ + dbgi_wr_data3(adap, 0xffffffff, 0xffffffff, 0); + if (mc5_write(adap, IDT_SSR0_ADR0, IDT_CMD_WRITE) || + mc5_write(adap, IDT_SSR1_ADR0, IDT_CMD_WRITE)) + goto err; + + /* Set up GMRs */ + for (i = 0; i < 32; ++i) { + if (i >= 12 && i < 15) + dbgi_wr_data3(adap, 0xfffffff9, 0xffffffff, 0xff); + else if (i == 15) + dbgi_wr_data3(adap, 0xfffffff9, 0xffff8007, 0xff); + else + dbgi_wr_data3(adap, 0xffffffff, 0xffffffff, 0xff); + + if (mc5_write(adap, IDT_GMR_BASE_ADR0 + i, IDT_CMD_WRITE)) + goto err; + } + + /* Set up SCR */ + dbgi_wr_data3(adap, 1, 0, 0); + if (mc5_write(adap, IDT_SCR_ADR0, IDT_CMD_WRITE)) + goto err; + + return init_mask_data_array(mc5, IDT_MSKARY_BASE_ADR0, + IDT_DATARY_BASE_ADR0, IDT_CMD_WRITE, 0); +err: + return -EIO; +} + +static int init_idt43102(struct mc5 *mc5) +{ + int i; + struct adapter *adap = mc5->adapter; + + t3_write_reg(adap, A_MC5_DB_RSP_LATENCY, + adap->params.rev == 0 ? V_RDLAT(0xd) | V_SRCHLAT(0x11) : + V_RDLAT(0xd) | V_SRCHLAT(0x12)); + + /* + * Use GMRs 24-25 for ELOOKUP, GMRs 20-21 for SYN lookups, and no mask + * for ACK- and AOPEN searches. + */ + t3_write_reg(adap, A_MC5_DB_POPEN_DATA_WR_CMD, IDT4_CMD_WRITE); + t3_write_reg(adap, A_MC5_DB_POPEN_MASK_WR_CMD, IDT4_CMD_WRITE); + t3_write_reg(adap, A_MC5_DB_AOPEN_SRCH_CMD, + IDT4_CMD_SEARCH144 | 0x3800); + t3_write_reg(adap, A_MC5_DB_SYN_SRCH_CMD, IDT4_CMD_SEARCH144); + t3_write_reg(adap, A_MC5_DB_ACK_SRCH_CMD, IDT4_CMD_SEARCH144 | 0x3800); + t3_write_reg(adap, A_MC5_DB_ILOOKUP_CMD, IDT4_CMD_SEARCH144 | 0x3800); + t3_write_reg(adap, A_MC5_DB_ELOOKUP_CMD, IDT4_CMD_SEARCH144 | 0x800); + t3_write_reg(adap, A_MC5_DB_DATA_WRITE_CMD, IDT4_CMD_WRITE); + t3_write_reg(adap, A_MC5_DB_DATA_READ_CMD, IDT4_CMD_READ); + + t3_write_reg(adap, A_MC5_DB_PART_ID_INDEX, 3); + + /* Set DBGI command mode for IDT TCAM. */ + t3_write_reg(adap, A_MC5_DB_DBGI_CONFIG, DBGI_MODE_IDT52100); + + /* Set up GMRs */ + dbgi_wr_data3(adap, 0xffffffff, 0xffffffff, 0xff); + for (i = 0; i < 7; ++i) + if (mc5_write(adap, IDT4_GMR_BASE0 + i, IDT4_CMD_WRITE)) + goto err; + + for (i = 0; i < 4; ++i) + if (mc5_write(adap, IDT4_GMR_BASE2 + i, IDT4_CMD_WRITE)) + goto err; + + dbgi_wr_data3(adap, 0xfffffff9, 0xffffffff, 0xff); + if (mc5_write(adap, IDT4_GMR_BASE1, IDT4_CMD_WRITE) || + mc5_write(adap, IDT4_GMR_BASE1 + 1, IDT4_CMD_WRITE) || + mc5_write(adap, IDT4_GMR_BASE1 + 4, IDT4_CMD_WRITE)) + goto err; + + dbgi_wr_data3(adap, 0xfffffff9, 0xffff8007, 0xff); + if (mc5_write(adap, IDT4_GMR_BASE1 + 5, IDT4_CMD_WRITE)) + goto err; + + /* Set up SCR */ + dbgi_wr_data3(adap, 0xf0000000, 0, 0); + if (mc5_write(adap, IDT4_SCR_ADR0, IDT4_CMD_WRITE)) + goto err; + + return init_mask_data_array(mc5, IDT4_MSKARY_BASE_ADR0, + IDT4_DATARY_BASE_ADR0, IDT4_CMD_WRITE, 1); +err: + return -EIO; +} + +/* Put MC5 in DBGI mode. */ +static inline void mc5_dbgi_mode_enable(const struct mc5 *mc5) +{ + t3_write_reg(mc5->adapter, A_MC5_DB_CONFIG, + V_TMMODE(mc5->mode == MC5_MODE_72_BIT) | F_DBGIEN); +} + +/* Put MC5 in M-Bus mode. */ +static void mc5_dbgi_mode_disable(const struct mc5 *mc5) +{ + t3_write_reg(mc5->adapter, A_MC5_DB_CONFIG, + V_TMMODE(mc5->mode == MC5_MODE_72_BIT) | + V_COMPEN(mc5->mode == MC5_MODE_72_BIT) | + V_PRTYEN(mc5->parity_enabled) | F_MBUSEN); +} + +/* + * Initialization that requires the OS and protocol layers to already + * be intialized goes here. + */ +int t3_mc5_init(struct mc5 *mc5, unsigned int nservers, unsigned int nfilters, + unsigned int nroutes) +{ + u32 cfg; + int err; + unsigned int tcam_size = mc5->tcam_size; + struct adapter *adap = mc5->adapter; + + if (nroutes > MAX_ROUTES || nroutes + nservers + nfilters > tcam_size) + return -EINVAL; + + /* Reset the TCAM */ + cfg = t3_read_reg(adap, A_MC5_DB_CONFIG) & ~F_TMMODE; + cfg |= V_TMMODE(mc5->mode == MC5_MODE_72_BIT) | F_TMRST; + t3_write_reg(adap, A_MC5_DB_CONFIG, cfg); + if (t3_wait_op_done(adap, A_MC5_DB_CONFIG, F_TMRDY, 1, 500, 0)) { + CH_ERR(adap, "TCAM reset timed out\n"); + return -1; + } + + t3_write_reg(adap, A_MC5_DB_ROUTING_TABLE_INDEX, tcam_size - nroutes); + t3_write_reg(adap, A_MC5_DB_FILTER_TABLE, + tcam_size - nroutes - nfilters); + t3_write_reg(adap, A_MC5_DB_SERVER_INDEX, + tcam_size - nroutes - nfilters - nservers); + + mc5->parity_enabled = 1; + + /* All the TCAM addresses we access have only the low 32 bits non 0 */ + t3_write_reg(adap, A_MC5_DB_DBGI_REQ_ADDR1, 0); + t3_write_reg(adap, A_MC5_DB_DBGI_REQ_ADDR2, 0); + + mc5_dbgi_mode_enable(mc5); + + switch (mc5->part_type) { + case IDT75P52100: + err = init_idt52100(mc5); + break; + case IDT75N43102: + err = init_idt43102(mc5); + break; + default: + CH_ERR(adap, "Unsupported TCAM type %d\n", mc5->part_type); + err = -EINVAL; + break; + } + + mc5_dbgi_mode_disable(mc5); + return err; +} + +/* + * read_mc5_range - dump a part of the memory managed by MC5 + * @mc5: the MC5 handle + * @start: the start address for the dump + * @n: number of 72-bit words to read + * @buf: result buffer + * + * Read n 72-bit words from MC5 memory from the given start location. + */ +int t3_read_mc5_range(const struct mc5 *mc5, unsigned int start, + unsigned int n, u32 *buf) +{ + u32 read_cmd; + int err = 0; + struct adapter *adap = mc5->adapter; + + if (mc5->part_type == IDT75P52100) + read_cmd = IDT_CMD_READ; + else if (mc5->part_type == IDT75N43102) + read_cmd = IDT4_CMD_READ; + else + return -EINVAL; + + mc5_dbgi_mode_enable(mc5); + + while (n--) { + t3_write_reg(adap, A_MC5_DB_DBGI_REQ_ADDR0, start++); + if (mc5_cmd_write(adap, read_cmd)) { + err = -EIO; + break; + } + dbgi_rd_rsp3(adap, buf + 2, buf + 1, buf); + buf += 3; + } + + mc5_dbgi_mode_disable(mc5); + return 0; +} + +#define MC5_INT_FATAL (F_PARITYERR | F_REQQPARERR | F_DISPQPARERR) + +/* + * MC5 interrupt handler + */ +void t3_mc5_intr_handler(struct mc5 *mc5) +{ + struct adapter *adap = mc5->adapter; + u32 cause = t3_read_reg(adap, A_MC5_DB_INT_CAUSE); + + if ((cause & F_PARITYERR) && mc5->parity_enabled) { + CH_ALERT(adap, "MC5 parity error\n"); + mc5->stats.parity_err++; + } + + if (cause & F_REQQPARERR) { + CH_ALERT(adap, "MC5 request queue parity error\n"); + mc5->stats.reqq_parity_err++; + } + + if (cause & F_DISPQPARERR) { + CH_ALERT(adap, "MC5 dispatch queue parity error\n"); + mc5->stats.dispq_parity_err++; + } + + if (cause & F_ACTRGNFULL) + mc5->stats.active_rgn_full++; + if (cause & F_NFASRCHFAIL) + mc5->stats.nfa_srch_err++; + if (cause & F_UNKNOWNCMD) + mc5->stats.unknown_cmd++; + if (cause & F_DELACTEMPTY) + mc5->stats.del_act_empty++; + if (cause & MC5_INT_FATAL) + t3_fatal_err(adap); + + t3_write_reg(adap, A_MC5_DB_INT_CAUSE, cause); +} + +void __devinit t3_mc5_prep(struct adapter *adapter, struct mc5 *mc5, int mode) +{ +#define K * 1024 + + static unsigned int tcam_part_size[] = { /* in K 72-bit entries */ + 64 K, 128 K, 256 K, 32 K + }; + +#undef K + + u32 cfg = t3_read_reg(adapter, A_MC5_DB_CONFIG); + + mc5->adapter = adapter; + mc5->mode = (unsigned char)mode; + mc5->part_type = (unsigned char)G_TMTYPE(cfg); + if (cfg & F_TMTYPEHI) + mc5->part_type |= 4; + + mc5->tcam_size = tcam_part_size[G_TMPARTSIZE(cfg)]; + if (mode == MC5_MODE_144_BIT) + mc5->tcam_size /= 2; +} diff --git a/drivers/net/cxgb3/regs.h b/drivers/net/cxgb3/regs.h new file mode 100644 index 0000000..b56c5f5 --- /dev/null +++ b/drivers/net/cxgb3/regs.h @@ -0,0 +1,2195 @@ +#define A_SG_CONTROL 0x0 + +#define S_DROPPKT 20 +#define V_DROPPKT(x) ((x) << S_DROPPKT) +#define F_DROPPKT V_DROPPKT(1U) + +#define S_EGRGENCTRL 19 +#define V_EGRGENCTRL(x) ((x) << S_EGRGENCTRL) +#define F_EGRGENCTRL V_EGRGENCTRL(1U) + +#define S_USERSPACESIZE 14 +#define M_USERSPACESIZE 0x1f +#define V_USERSPACESIZE(x) ((x) << S_USERSPACESIZE) + +#define S_HOSTPAGESIZE 11 +#define M_HOSTPAGESIZE 0x7 +#define V_HOSTPAGESIZE(x) ((x) << S_HOSTPAGESIZE) + +#define S_FLMODE 9 +#define V_FLMODE(x) ((x) << S_FLMODE) +#define F_FLMODE V_FLMODE(1U) + +#define S_PKTSHIFT 6 +#define M_PKTSHIFT 0x7 +#define V_PKTSHIFT(x) ((x) << S_PKTSHIFT) + +#define S_ONEINTMULTQ 5 +#define V_ONEINTMULTQ(x) ((x) << S_ONEINTMULTQ) +#define F_ONEINTMULTQ V_ONEINTMULTQ(1U) + +#define S_BIGENDIANINGRESS 2 +#define V_BIGENDIANINGRESS(x) ((x) << S_BIGENDIANINGRESS) +#define F_BIGENDIANINGRESS V_BIGENDIANINGRESS(1U) + +#define S_ISCSICOALESCING 1 +#define V_ISCSICOALESCING(x) ((x) << S_ISCSICOALESCING) +#define F_ISCSICOALESCING V_ISCSICOALESCING(1U) + +#define S_GLOBALENABLE 0 +#define V_GLOBALENABLE(x) ((x) << S_GLOBALENABLE) +#define F_GLOBALENABLE V_GLOBALENABLE(1U) + +#define S_AVOIDCQOVFL 24 +#define V_AVOIDCQOVFL(x) ((x) << S_AVOIDCQOVFL) +#define F_AVOIDCQOVFL V_AVOIDCQOVFL(1U) + +#define S_OPTONEINTMULTQ 23 +#define V_OPTONEINTMULTQ(x) ((x) << S_OPTONEINTMULTQ) +#define F_OPTONEINTMULTQ V_OPTONEINTMULTQ(1U) + +#define S_CQCRDTCTRL 22 +#define V_CQCRDTCTRL(x) ((x) << S_CQCRDTCTRL) +#define F_CQCRDTCTRL V_CQCRDTCTRL(1U) + +#define A_SG_KDOORBELL 0x4 + +#define S_SELEGRCNTX 31 +#define V_SELEGRCNTX(x) ((x) << S_SELEGRCNTX) +#define F_SELEGRCNTX V_SELEGRCNTX(1U) + +#define S_EGRCNTX 0 +#define M_EGRCNTX 0xffff +#define V_EGRCNTX(x) ((x) << S_EGRCNTX) + +#define A_SG_GTS 0x8 + +#define S_RSPQ 29 +#define M_RSPQ 0x7 +#define V_RSPQ(x) ((x) << S_RSPQ) +#define G_RSPQ(x) (((x) >> S_RSPQ) & M_RSPQ) + +#define S_NEWTIMER 16 +#define M_NEWTIMER 0x1fff +#define V_NEWTIMER(x) ((x) << S_NEWTIMER) + +#define S_NEWINDEX 0 +#define M_NEWINDEX 0xffff +#define V_NEWINDEX(x) ((x) << S_NEWINDEX) + +#define A_SG_CONTEXT_CMD 0xc + +#define S_CONTEXT_CMD_OPCODE 28 +#define M_CONTEXT_CMD_OPCODE 0xf +#define V_CONTEXT_CMD_OPCODE(x) ((x) << S_CONTEXT_CMD_OPCODE) + +#define S_CONTEXT_CMD_BUSY 27 +#define V_CONTEXT_CMD_BUSY(x) ((x) << S_CONTEXT_CMD_BUSY) +#define F_CONTEXT_CMD_BUSY V_CONTEXT_CMD_BUSY(1U) + +#define S_CQ_CREDIT 20 + +#define M_CQ_CREDIT 0x7f + +#define V_CQ_CREDIT(x) ((x) << S_CQ_CREDIT) + +#define G_CQ_CREDIT(x) (((x) >> S_CQ_CREDIT) & M_CQ_CREDIT) + +#define S_CQ 19 + +#define V_CQ(x) ((x) << S_CQ) +#define F_CQ V_CQ(1U) + +#define S_RESPONSEQ 18 +#define V_RESPONSEQ(x) ((x) << S_RESPONSEQ) +#define F_RESPONSEQ V_RESPONSEQ(1U) + +#define S_EGRESS 17 +#define V_EGRESS(x) ((x) << S_EGRESS) +#define F_EGRESS V_EGRESS(1U) + +#define S_FREELIST 16 +#define V_FREELIST(x) ((x) << S_FREELIST) +#define F_FREELIST V_FREELIST(1U) + +#define S_CONTEXT 0 +#define M_CONTEXT 0xffff +#define V_CONTEXT(x) ((x) << S_CONTEXT) + +#define G_CONTEXT(x) (((x) >> S_CONTEXT) & M_CONTEXT) + +#define A_SG_CONTEXT_DATA0 0x10 + +#define A_SG_CONTEXT_DATA1 0x14 + +#define A_SG_CONTEXT_DATA2 0x18 + +#define A_SG_CONTEXT_DATA3 0x1c + +#define A_SG_CONTEXT_MASK0 0x20 + +#define A_SG_CONTEXT_MASK1 0x24 + +#define A_SG_CONTEXT_MASK2 0x28 + +#define A_SG_CONTEXT_MASK3 0x2c + +#define A_SG_RSPQ_CREDIT_RETURN 0x30 + +#define S_CREDITS 0 +#define M_CREDITS 0xffff +#define V_CREDITS(x) ((x) << S_CREDITS) + +#define A_SG_DATA_INTR 0x34 + +#define S_ERRINTR 31 +#define V_ERRINTR(x) ((x) << S_ERRINTR) +#define F_ERRINTR V_ERRINTR(1U) + +#define A_SG_HI_DRB_HI_THRSH 0x38 + +#define A_SG_HI_DRB_LO_THRSH 0x3c + +#define A_SG_LO_DRB_HI_THRSH 0x40 + +#define A_SG_LO_DRB_LO_THRSH 0x44 + +#define A_SG_RSPQ_FL_STATUS 0x4c + +#define S_RSPQ0DISABLED 8 + +#define A_SG_EGR_RCQ_DRB_THRSH 0x54 + +#define S_HIRCQDRBTHRSH 16 +#define M_HIRCQDRBTHRSH 0x7ff +#define V_HIRCQDRBTHRSH(x) ((x) << S_HIRCQDRBTHRSH) + +#define S_LORCQDRBTHRSH 0 +#define M_LORCQDRBTHRSH 0x7ff +#define V_LORCQDRBTHRSH(x) ((x) << S_LORCQDRBTHRSH) + +#define A_SG_EGR_CNTX_BADDR 0x58 + +#define A_SG_INT_CAUSE 0x5c + +#define S_RSPQDISABLED 3 +#define V_RSPQDISABLED(x) ((x) << S_RSPQDISABLED) +#define F_RSPQDISABLED V_RSPQDISABLED(1U) + +#define S_RSPQCREDITOVERFOW 2 +#define V_RSPQCREDITOVERFOW(x) ((x) << S_RSPQCREDITOVERFOW) +#define F_RSPQCREDITOVERFOW V_RSPQCREDITOVERFOW(1U) + +#define A_SG_INT_ENABLE 0x60 + +#define A_SG_CMDQ_CREDIT_TH 0x64 + +#define S_TIMEOUT 8 +#define M_TIMEOUT 0xffffff +#define V_TIMEOUT(x) ((x) << S_TIMEOUT) + +#define S_THRESHOLD 0 +#define M_THRESHOLD 0xff +#define V_THRESHOLD(x) ((x) << S_THRESHOLD) + +#define A_SG_TIMER_TICK 0x68 + +#define A_SG_CQ_CONTEXT_BADDR 0x6c + +#define A_SG_OCO_BASE 0x70 + +#define S_BASE1 16 +#define M_BASE1 0xffff +#define V_BASE1(x) ((x) << S_BASE1) + +#define A_SG_DRB_PRI_THRESH 0x74 + +#define A_PCIX_INT_ENABLE 0x80 + +#define S_MSIXPARERR 22 +#define M_MSIXPARERR 0x7 + +#define V_MSIXPARERR(x) ((x) << S_MSIXPARERR) + +#define S_CFPARERR 18 +#define M_CFPARERR 0xf + +#define V_CFPARERR(x) ((x) << S_CFPARERR) + +#define S_RFPARERR 14 +#define M_RFPARERR 0xf + +#define V_RFPARERR(x) ((x) << S_RFPARERR) + +#define S_WFPARERR 12 +#define M_WFPARERR 0x3 + +#define V_WFPARERR(x) ((x) << S_WFPARERR) + +#define S_PIOPARERR 11 +#define V_PIOPARERR(x) ((x) << S_PIOPARERR) +#define F_PIOPARERR V_PIOPARERR(1U) + +#define S_DETUNCECCERR 10 +#define V_DETUNCECCERR(x) ((x) << S_DETUNCECCERR) +#define F_DETUNCECCERR V_DETUNCECCERR(1U) + +#define S_DETCORECCERR 9 +#define V_DETCORECCERR(x) ((x) << S_DETCORECCERR) +#define F_DETCORECCERR V_DETCORECCERR(1U) + +#define S_RCVSPLCMPERR 8 +#define V_RCVSPLCMPERR(x) ((x) << S_RCVSPLCMPERR) +#define F_RCVSPLCMPERR V_RCVSPLCMPERR(1U) + +#define S_UNXSPLCMP 7 +#define V_UNXSPLCMP(x) ((x) << S_UNXSPLCMP) +#define F_UNXSPLCMP V_UNXSPLCMP(1U) + +#define S_SPLCMPDIS 6 +#define V_SPLCMPDIS(x) ((x) << S_SPLCMPDIS) +#define F_SPLCMPDIS V_SPLCMPDIS(1U) + +#define S_DETPARERR 5 +#define V_DETPARERR(x) ((x) << S_DETPARERR) +#define F_DETPARERR V_DETPARERR(1U) + +#define S_SIGSYSERR 4 +#define V_SIGSYSERR(x) ((x) << S_SIGSYSERR) +#define F_SIGSYSERR V_SIGSYSERR(1U) + +#define S_RCVMSTABT 3 +#define V_RCVMSTABT(x) ((x) << S_RCVMSTABT) +#define F_RCVMSTABT V_RCVMSTABT(1U) + +#define S_RCVTARABT 2 +#define V_RCVTARABT(x) ((x) << S_RCVTARABT) +#define F_RCVTARABT V_RCVTARABT(1U) + +#define S_SIGTARABT 1 +#define V_SIGTARABT(x) ((x) << S_SIGTARABT) +#define F_SIGTARABT V_SIGTARABT(1U) + +#define S_MSTDETPARERR 0 +#define V_MSTDETPARERR(x) ((x) << S_MSTDETPARERR) +#define F_MSTDETPARERR V_MSTDETPARERR(1U) + +#define A_PCIX_INT_CAUSE 0x84 + +#define A_PCIX_CFG 0x88 + +#define S_CLIDECEN 18 +#define V_CLIDECEN(x) ((x) << S_CLIDECEN) +#define F_CLIDECEN V_CLIDECEN(1U) + +#define A_PCIX_MODE 0x8c + +#define S_PCLKRANGE 6 +#define M_PCLKRANGE 0x3 +#define V_PCLKRANGE(x) ((x) << S_PCLKRANGE) +#define G_PCLKRANGE(x) (((x) >> S_PCLKRANGE) & M_PCLKRANGE) + +#define S_PCIXINITPAT 2 +#define M_PCIXINITPAT 0xf +#define V_PCIXINITPAT(x) ((x) << S_PCIXINITPAT) +#define G_PCIXINITPAT(x) (((x) >> S_PCIXINITPAT) & M_PCIXINITPAT) + +#define S_64BIT 0 +#define V_64BIT(x) ((x) << S_64BIT) +#define F_64BIT V_64BIT(1U) + +#define A_PCIE_INT_ENABLE 0x80 + +#define S_BISTERR 15 +#define M_BISTERR 0xff + +#define V_BISTERR(x) ((x) << S_BISTERR) + +#define S_PCIE_MSIXPARERR 12 +#define M_PCIE_MSIXPARERR 0x7 + +#define V_PCIE_MSIXPARERR(x) ((x) << S_PCIE_MSIXPARERR) + +#define S_PCIE_CFPARERR 11 +#define V_PCIE_CFPARERR(x) ((x) << S_PCIE_CFPARERR) +#define F_PCIE_CFPARERR V_PCIE_CFPARERR(1U) + +#define S_PCIE_RFPARERR 10 +#define V_PCIE_RFPARERR(x) ((x) << S_PCIE_RFPARERR) +#define F_PCIE_RFPARERR V_PCIE_RFPARERR(1U) + +#define S_PCIE_WFPARERR 9 +#define V_PCIE_WFPARERR(x) ((x) << S_PCIE_WFPARERR) +#define F_PCIE_WFPARERR V_PCIE_WFPARERR(1U) + +#define S_PCIE_PIOPARERR 8 +#define V_PCIE_PIOPARERR(x) ((x) << S_PCIE_PIOPARERR) +#define F_PCIE_PIOPARERR V_PCIE_PIOPARERR(1U) + +#define S_UNXSPLCPLERRC 7 +#define V_UNXSPLCPLERRC(x) ((x) << S_UNXSPLCPLERRC) +#define F_UNXSPLCPLERRC V_UNXSPLCPLERRC(1U) + +#define S_UNXSPLCPLERRR 6 +#define V_UNXSPLCPLERRR(x) ((x) << S_UNXSPLCPLERRR) +#define F_UNXSPLCPLERRR V_UNXSPLCPLERRR(1U) + +#define S_PEXERR 0 +#define V_PEXERR(x) ((x) << S_PEXERR) +#define F_PEXERR V_PEXERR(1U) + +#define A_PCIE_INT_CAUSE 0x84 + +#define A_PCIE_CFG 0x88 + +#define S_PCIE_CLIDECEN 16 +#define V_PCIE_CLIDECEN(x) ((x) << S_PCIE_CLIDECEN) +#define F_PCIE_CLIDECEN V_PCIE_CLIDECEN(1U) + +#define S_CRSTWRMMODE 0 +#define V_CRSTWRMMODE(x) ((x) << S_CRSTWRMMODE) +#define F_CRSTWRMMODE V_CRSTWRMMODE(1U) + +#define A_PCIE_MODE 0x8c + +#define S_NUMFSTTRNSEQRX 10 +#define M_NUMFSTTRNSEQRX 0xff +#define V_NUMFSTTRNSEQRX(x) ((x) << S_NUMFSTTRNSEQRX) +#define G_NUMFSTTRNSEQRX(x) (((x) >> S_NUMFSTTRNSEQRX) & M_NUMFSTTRNSEQRX) + +#define A_PCIE_PEX_CTRL0 0x98 + +#define S_NUMFSTTRNSEQ 22 +#define M_NUMFSTTRNSEQ 0xff +#define V_NUMFSTTRNSEQ(x) ((x) << S_NUMFSTTRNSEQ) +#define G_NUMFSTTRNSEQ(x) (((x) >> S_NUMFSTTRNSEQ) & M_NUMFSTTRNSEQ) + +#define S_REPLAYLMT 2 +#define M_REPLAYLMT 0xfffff + +#define V_REPLAYLMT(x) ((x) << S_REPLAYLMT) + +#define A_PCIE_PEX_CTRL1 0x9c + +#define S_T3A_ACKLAT 0 +#define M_T3A_ACKLAT 0x7ff + +#define V_T3A_ACKLAT(x) ((x) << S_T3A_ACKLAT) + +#define S_ACKLAT 0 +#define M_ACKLAT 0x1fff + +#define V_ACKLAT(x) ((x) << S_ACKLAT) + +#define A_PCIE_PEX_ERR 0xa4 + +#define A_T3DBG_GPIO_EN 0xd0 + +#define S_GPIO11_OEN 27 +#define V_GPIO11_OEN(x) ((x) << S_GPIO11_OEN) +#define F_GPIO11_OEN V_GPIO11_OEN(1U) + +#define S_GPIO10_OEN 26 +#define V_GPIO10_OEN(x) ((x) << S_GPIO10_OEN) +#define F_GPIO10_OEN V_GPIO10_OEN(1U) + +#define S_GPIO7_OEN 23 +#define V_GPIO7_OEN(x) ((x) << S_GPIO7_OEN) +#define F_GPIO7_OEN V_GPIO7_OEN(1U) + +#define S_GPIO6_OEN 22 +#define V_GPIO6_OEN(x) ((x) << S_GPIO6_OEN) +#define F_GPIO6_OEN V_GPIO6_OEN(1U) + +#define S_GPIO5_OEN 21 +#define V_GPIO5_OEN(x) ((x) << S_GPIO5_OEN) +#define F_GPIO5_OEN V_GPIO5_OEN(1U) + +#define S_GPIO4_OEN 20 +#define V_GPIO4_OEN(x) ((x) << S_GPIO4_OEN) +#define F_GPIO4_OEN V_GPIO4_OEN(1U) + +#define S_GPIO2_OEN 18 +#define V_GPIO2_OEN(x) ((x) << S_GPIO2_OEN) +#define F_GPIO2_OEN V_GPIO2_OEN(1U) + +#define S_GPIO1_OEN 17 +#define V_GPIO1_OEN(x) ((x) << S_GPIO1_OEN) +#define F_GPIO1_OEN V_GPIO1_OEN(1U) + +#define S_GPIO0_OEN 16 +#define V_GPIO0_OEN(x) ((x) << S_GPIO0_OEN) +#define F_GPIO0_OEN V_GPIO0_OEN(1U) + +#define S_GPIO10_OUT_VAL 10 +#define V_GPIO10_OUT_VAL(x) ((x) << S_GPIO10_OUT_VAL) +#define F_GPIO10_OUT_VAL V_GPIO10_OUT_VAL(1U) + +#define S_GPIO7_OUT_VAL 7 +#define V_GPIO7_OUT_VAL(x) ((x) << S_GPIO7_OUT_VAL) +#define F_GPIO7_OUT_VAL V_GPIO7_OUT_VAL(1U) + +#define S_GPIO6_OUT_VAL 6 +#define V_GPIO6_OUT_VAL(x) ((x) << S_GPIO6_OUT_VAL) +#define F_GPIO6_OUT_VAL V_GPIO6_OUT_VAL(1U) + +#define S_GPIO5_OUT_VAL 5 +#define V_GPIO5_OUT_VAL(x) ((x) << S_GPIO5_OUT_VAL) +#define F_GPIO5_OUT_VAL V_GPIO5_OUT_VAL(1U) + +#define S_GPIO4_OUT_VAL 4 +#define V_GPIO4_OUT_VAL(x) ((x) << S_GPIO4_OUT_VAL) +#define F_GPIO4_OUT_VAL V_GPIO4_OUT_VAL(1U) + +#define S_GPIO2_OUT_VAL 2 +#define V_GPIO2_OUT_VAL(x) ((x) << S_GPIO2_OUT_VAL) +#define F_GPIO2_OUT_VAL V_GPIO2_OUT_VAL(1U) + +#define S_GPIO1_OUT_VAL 1 +#define V_GPIO1_OUT_VAL(x) ((x) << S_GPIO1_OUT_VAL) +#define F_GPIO1_OUT_VAL V_GPIO1_OUT_VAL(1U) + +#define S_GPIO0_OUT_VAL 0 +#define V_GPIO0_OUT_VAL(x) ((x) << S_GPIO0_OUT_VAL) +#define F_GPIO0_OUT_VAL V_GPIO0_OUT_VAL(1U) + +#define A_T3DBG_INT_ENABLE 0xd8 + +#define S_GPIO11 11 +#define V_GPIO11(x) ((x) << S_GPIO11) +#define F_GPIO11 V_GPIO11(1U) + +#define S_GPIO10 10 +#define V_GPIO10(x) ((x) << S_GPIO10) +#define F_GPIO10 V_GPIO10(1U) + +#define S_GPIO7 7 +#define V_GPIO7(x) ((x) << S_GPIO7) +#define F_GPIO7 V_GPIO7(1U) + +#define S_GPIO6 6 +#define V_GPIO6(x) ((x) << S_GPIO6) +#define F_GPIO6 V_GPIO6(1U) + +#define S_GPIO5 5 +#define V_GPIO5(x) ((x) << S_GPIO5) +#define F_GPIO5 V_GPIO5(1U) + +#define S_GPIO4 4 +#define V_GPIO4(x) ((x) << S_GPIO4) +#define F_GPIO4 V_GPIO4(1U) + +#define S_GPIO3 3 +#define V_GPIO3(x) ((x) << S_GPIO3) +#define F_GPIO3 V_GPIO3(1U) + +#define S_GPIO2 2 +#define V_GPIO2(x) ((x) << S_GPIO2) +#define F_GPIO2 V_GPIO2(1U) + +#define S_GPIO1 1 +#define V_GPIO1(x) ((x) << S_GPIO1) +#define F_GPIO1 V_GPIO1(1U) + +#define S_GPIO0 0 +#define V_GPIO0(x) ((x) << S_GPIO0) +#define F_GPIO0 V_GPIO0(1U) + +#define A_T3DBG_INT_CAUSE 0xdc + +#define A_T3DBG_GPIO_ACT_LOW 0xf0 + +#define MC7_PMRX_BASE_ADDR 0x100 + +#define A_MC7_CFG 0x100 + +#define S_IFEN 13 +#define V_IFEN(x) ((x) << S_IFEN) +#define F_IFEN V_IFEN(1U) + +#define S_TERM150 11 +#define V_TERM150(x) ((x) << S_TERM150) +#define F_TERM150 V_TERM150(1U) + +#define S_SLOW 10 +#define V_SLOW(x) ((x) << S_SLOW) +#define F_SLOW V_SLOW(1U) + +#define S_WIDTH 8 +#define M_WIDTH 0x3 +#define V_WIDTH(x) ((x) << S_WIDTH) +#define G_WIDTH(x) (((x) >> S_WIDTH) & M_WIDTH) + +#define S_BKS 6 +#define V_BKS(x) ((x) << S_BKS) +#define F_BKS V_BKS(1U) + +#define S_ORG 5 +#define V_ORG(x) ((x) << S_ORG) +#define F_ORG V_ORG(1U) + +#define S_DEN 2 +#define M_DEN 0x7 +#define V_DEN(x) ((x) << S_DEN) +#define G_DEN(x) (((x) >> S_DEN) & M_DEN) + +#define S_RDY 1 +#define V_RDY(x) ((x) << S_RDY) +#define F_RDY V_RDY(1U) + +#define S_CLKEN 0 +#define V_CLKEN(x) ((x) << S_CLKEN) +#define F_CLKEN V_CLKEN(1U) + +#define A_MC7_MODE 0x104 + +#define S_BUSY 31 +#define V_BUSY(x) ((x) << S_BUSY) +#define F_BUSY V_BUSY(1U) + +#define S_BUSY 31 +#define V_BUSY(x) ((x) << S_BUSY) +#define F_BUSY V_BUSY(1U) + +#define A_MC7_EXT_MODE1 0x108 + +#define A_MC7_EXT_MODE2 0x10c + +#define A_MC7_EXT_MODE3 0x110 + +#define A_MC7_PRE 0x114 + +#define A_MC7_REF 0x118 + +#define S_PREREFDIV 1 +#define M_PREREFDIV 0x3fff +#define V_PREREFDIV(x) ((x) << S_PREREFDIV) + +#define S_PERREFEN 0 +#define V_PERREFEN(x) ((x) << S_PERREFEN) +#define F_PERREFEN V_PERREFEN(1U) + +#define A_MC7_DLL 0x11c + +#define S_DLLENB 1 +#define V_DLLENB(x) ((x) << S_DLLENB) +#define F_DLLENB V_DLLENB(1U) + +#define S_DLLRST 0 +#define V_DLLRST(x) ((x) << S_DLLRST) +#define F_DLLRST V_DLLRST(1U) + +#define A_MC7_PARM 0x120 + +#define S_ACTTOPREDLY 26 +#define M_ACTTOPREDLY 0xf +#define V_ACTTOPREDLY(x) ((x) << S_ACTTOPREDLY) + +#define S_ACTTORDWRDLY 23 +#define M_ACTTORDWRDLY 0x7 +#define V_ACTTORDWRDLY(x) ((x) << S_ACTTORDWRDLY) + +#define S_PRECYC 20 +#define M_PRECYC 0x7 +#define V_PRECYC(x) ((x) << S_PRECYC) + +#define S_REFCYC 13 +#define M_REFCYC 0x7f +#define V_REFCYC(x) ((x) << S_REFCYC) + +#define S_BKCYC 8 +#define M_BKCYC 0x1f +#define V_BKCYC(x) ((x) << S_BKCYC) + +#define S_WRTORDDLY 4 +#define M_WRTORDDLY 0xf +#define V_WRTORDDLY(x) ((x) << S_WRTORDDLY) + +#define S_RDTOWRDLY 0 +#define M_RDTOWRDLY 0xf +#define V_RDTOWRDLY(x) ((x) << S_RDTOWRDLY) + +#define A_MC7_CAL 0x128 + +#define S_BUSY 31 +#define V_BUSY(x) ((x) << S_BUSY) +#define F_BUSY V_BUSY(1U) + +#define S_BUSY 31 +#define V_BUSY(x) ((x) << S_BUSY) +#define F_BUSY V_BUSY(1U) + +#define S_CAL_FAULT 30 +#define V_CAL_FAULT(x) ((x) << S_CAL_FAULT) +#define F_CAL_FAULT V_CAL_FAULT(1U) + +#define S_SGL_CAL_EN 20 +#define V_SGL_CAL_EN(x) ((x) << S_SGL_CAL_EN) +#define F_SGL_CAL_EN V_SGL_CAL_EN(1U) + +#define A_MC7_ERR_ADDR 0x12c + +#define A_MC7_ECC 0x130 + +#define S_ECCCHKEN 1 +#define V_ECCCHKEN(x) ((x) << S_ECCCHKEN) +#define F_ECCCHKEN V_ECCCHKEN(1U) + +#define S_ECCGENEN 0 +#define V_ECCGENEN(x) ((x) << S_ECCGENEN) +#define F_ECCGENEN V_ECCGENEN(1U) + +#define A_MC7_CE_ADDR 0x134 + +#define A_MC7_CE_DATA0 0x138 + +#define A_MC7_CE_DATA1 0x13c + +#define A_MC7_CE_DATA2 0x140 + +#define S_DATA 0 +#define M_DATA 0xff + +#define G_DATA(x) (((x) >> S_DATA) & M_DATA) + +#define A_MC7_UE_ADDR 0x144 + +#define A_MC7_UE_DATA0 0x148 + +#define A_MC7_UE_DATA1 0x14c + +#define A_MC7_UE_DATA2 0x150 + +#define A_MC7_BD_ADDR 0x154 + +#define S_ADDR 3 + +#define M_ADDR 0x1fffffff + +#define A_MC7_BD_DATA0 0x158 + +#define A_MC7_BD_DATA1 0x15c + +#define A_MC7_BD_OP 0x164 + +#define S_OP 0 + +#define V_OP(x) ((x) << S_OP) +#define F_OP V_OP(1U) + +#define F_OP V_OP(1U) +#define A_SF_OP 0x6dc + +#define A_MC7_BIST_ADDR_BEG 0x168 + +#define A_MC7_BIST_ADDR_END 0x16c + +#define A_MC7_BIST_DATA 0x170 + +#define A_MC7_BIST_OP 0x174 + +#define S_CONT 3 +#define V_CONT(x) ((x) << S_CONT) +#define F_CONT V_CONT(1U) + +#define F_CONT V_CONT(1U) + +#define A_MC7_INT_ENABLE 0x178 + +#define S_AE 17 +#define V_AE(x) ((x) << S_AE) +#define F_AE V_AE(1U) + +#define S_PE 2 +#define M_PE 0x7fff + +#define V_PE(x) ((x) << S_PE) + +#define G_PE(x) (((x) >> S_PE) & M_PE) + +#define S_UE 1 +#define V_UE(x) ((x) << S_UE) +#define F_UE V_UE(1U) + +#define S_CE 0 +#define V_CE(x) ((x) << S_CE) +#define F_CE V_CE(1U) + +#define A_MC7_INT_CAUSE 0x17c + +#define MC7_PMTX_BASE_ADDR 0x180 + +#define MC7_CM_BASE_ADDR 0x200 + +#define A_CIM_BOOT_CFG 0x280 + +#define S_BOOTADDR 2 +#define M_BOOTADDR 0x3fffffff +#define V_BOOTADDR(x) ((x) << S_BOOTADDR) + +#define A_CIM_SDRAM_BASE_ADDR 0x28c + +#define A_CIM_SDRAM_ADDR_SIZE 0x290 + +#define A_CIM_HOST_INT_ENABLE 0x298 + +#define A_CIM_HOST_INT_CAUSE 0x29c + +#define S_BLKWRPLINT 12 +#define V_BLKWRPLINT(x) ((x) << S_BLKWRPLINT) +#define F_BLKWRPLINT V_BLKWRPLINT(1U) + +#define S_BLKRDPLINT 11 +#define V_BLKRDPLINT(x) ((x) << S_BLKRDPLINT) +#define F_BLKRDPLINT V_BLKRDPLINT(1U) + +#define S_BLKWRCTLINT 10 +#define V_BLKWRCTLINT(x) ((x) << S_BLKWRCTLINT) +#define F_BLKWRCTLINT V_BLKWRCTLINT(1U) + +#define S_BLKRDCTLINT 9 +#define V_BLKRDCTLINT(x) ((x) << S_BLKRDCTLINT) +#define F_BLKRDCTLINT V_BLKRDCTLINT(1U) + +#define S_BLKWRFLASHINT 8 +#define V_BLKWRFLASHINT(x) ((x) << S_BLKWRFLASHINT) +#define F_BLKWRFLASHINT V_BLKWRFLASHINT(1U) + +#define S_BLKRDFLASHINT 7 +#define V_BLKRDFLASHINT(x) ((x) << S_BLKRDFLASHINT) +#define F_BLKRDFLASHINT V_BLKRDFLASHINT(1U) + +#define S_SGLWRFLASHINT 6 +#define V_SGLWRFLASHINT(x) ((x) << S_SGLWRFLASHINT) +#define F_SGLWRFLASHINT V_SGLWRFLASHINT(1U) + +#define S_WRBLKFLASHINT 5 +#define V_WRBLKFLASHINT(x) ((x) << S_WRBLKFLASHINT) +#define F_WRBLKFLASHINT V_WRBLKFLASHINT(1U) + +#define S_BLKWRBOOTINT 4 +#define V_BLKWRBOOTINT(x) ((x) << S_BLKWRBOOTINT) +#define F_BLKWRBOOTINT V_BLKWRBOOTINT(1U) + +#define S_FLASHRANGEINT 2 +#define V_FLASHRANGEINT(x) ((x) << S_FLASHRANGEINT) +#define F_FLASHRANGEINT V_FLASHRANGEINT(1U) + +#define S_SDRAMRANGEINT 1 +#define V_SDRAMRANGEINT(x) ((x) << S_SDRAMRANGEINT) +#define F_SDRAMRANGEINT V_SDRAMRANGEINT(1U) + +#define S_RSVDSPACEINT 0 +#define V_RSVDSPACEINT(x) ((x) << S_RSVDSPACEINT) +#define F_RSVDSPACEINT V_RSVDSPACEINT(1U) + +#define A_CIM_HOST_ACC_CTRL 0x2b0 + +#define S_HOSTBUSY 17 +#define V_HOSTBUSY(x) ((x) << S_HOSTBUSY) +#define F_HOSTBUSY V_HOSTBUSY(1U) + +#define A_CIM_HOST_ACC_DATA 0x2b4 + +#define A_TP_IN_CONFIG 0x300 + +#define S_NICMODE 14 +#define V_NICMODE(x) ((x) << S_NICMODE) +#define F_NICMODE V_NICMODE(1U) + +#define F_NICMODE V_NICMODE(1U) + +#define S_IPV6ENABLE 15 +#define V_IPV6ENABLE(x) ((x) << S_IPV6ENABLE) +#define F_IPV6ENABLE V_IPV6ENABLE(1U) + +#define A_TP_OUT_CONFIG 0x304 + +#define S_VLANEXTRACTIONENABLE 12 + +#define A_TP_GLOBAL_CONFIG 0x308 + +#define S_TXPACINGENABLE 24 +#define V_TXPACINGENABLE(x) ((x) << S_TXPACINGENABLE) +#define F_TXPACINGENABLE V_TXPACINGENABLE(1U) + +#define S_PATHMTU 15 +#define V_PATHMTU(x) ((x) << S_PATHMTU) +#define F_PATHMTU V_PATHMTU(1U) + +#define S_IPCHECKSUMOFFLOAD 13 +#define V_IPCHECKSUMOFFLOAD(x) ((x) << S_IPCHECKSUMOFFLOAD) +#define F_IPCHECKSUMOFFLOAD V_IPCHECKSUMOFFLOAD(1U) + +#define S_UDPCHECKSUMOFFLOAD 12 +#define V_UDPCHECKSUMOFFLOAD(x) ((x) << S_UDPCHECKSUMOFFLOAD) +#define F_UDPCHECKSUMOFFLOAD V_UDPCHECKSUMOFFLOAD(1U) + +#define S_TCPCHECKSUMOFFLOAD 11 +#define V_TCPCHECKSUMOFFLOAD(x) ((x) << S_TCPCHECKSUMOFFLOAD) +#define F_TCPCHECKSUMOFFLOAD V_TCPCHECKSUMOFFLOAD(1U) + +#define S_IPTTL 0 +#define M_IPTTL 0xff +#define V_IPTTL(x) ((x) << S_IPTTL) + +#define A_TP_CMM_MM_BASE 0x314 + +#define A_TP_CMM_TIMER_BASE 0x318 + +#define S_CMTIMERMAXNUM 28 +#define M_CMTIMERMAXNUM 0x3 +#define V_CMTIMERMAXNUM(x) ((x) << S_CMTIMERMAXNUM) + +#define A_TP_PMM_SIZE 0x31c + +#define A_TP_PMM_TX_BASE 0x320 + +#define A_TP_PMM_RX_BASE 0x328 + +#define A_TP_PMM_RX_PAGE_SIZE 0x32c + +#define A_TP_PMM_RX_MAX_PAGE 0x330 + +#define A_TP_PMM_TX_PAGE_SIZE 0x334 + +#define A_TP_PMM_TX_MAX_PAGE 0x338 + +#define A_TP_TCP_OPTIONS 0x340 + +#define S_MTUDEFAULT 16 +#define M_MTUDEFAULT 0xffff +#define V_MTUDEFAULT(x) ((x) << S_MTUDEFAULT) + +#define S_MTUENABLE 10 +#define V_MTUENABLE(x) ((x) << S_MTUENABLE) +#define F_MTUENABLE V_MTUENABLE(1U) + +#define S_SACKRX 8 +#define V_SACKRX(x) ((x) << S_SACKRX) +#define F_SACKRX V_SACKRX(1U) + +#define S_SACKMODE 4 + +#define M_SACKMODE 0x3 + +#define V_SACKMODE(x) ((x) << S_SACKMODE) + +#define S_WINDOWSCALEMODE 2 +#define M_WINDOWSCALEMODE 0x3 +#define V_WINDOWSCALEMODE(x) ((x) << S_WINDOWSCALEMODE) + +#define S_TIMESTAMPSMODE 0 + +#define M_TIMESTAMPSMODE 0x3 + +#define V_TIMESTAMPSMODE(x) ((x) << S_TIMESTAMPSMODE) + +#define A_TP_DACK_CONFIG 0x344 + +#define S_AUTOSTATE3 30 +#define M_AUTOSTATE3 0x3 +#define V_AUTOSTATE3(x) ((x) << S_AUTOSTATE3) + +#define S_AUTOSTATE2 28 +#define M_AUTOSTATE2 0x3 +#define V_AUTOSTATE2(x) ((x) << S_AUTOSTATE2) + +#define S_AUTOSTATE1 26 +#define M_AUTOSTATE1 0x3 +#define V_AUTOSTATE1(x) ((x) << S_AUTOSTATE1) + +#define S_BYTETHRESHOLD 5 +#define M_BYTETHRESHOLD 0xfffff +#define V_BYTETHRESHOLD(x) ((x) << S_BYTETHRESHOLD) + +#define S_MSSTHRESHOLD 3 +#define M_MSSTHRESHOLD 0x3 +#define V_MSSTHRESHOLD(x) ((x) << S_MSSTHRESHOLD) + +#define S_AUTOCAREFUL 2 +#define V_AUTOCAREFUL(x) ((x) << S_AUTOCAREFUL) +#define F_AUTOCAREFUL V_AUTOCAREFUL(1U) + +#define S_AUTOENABLE 1 +#define V_AUTOENABLE(x) ((x) << S_AUTOENABLE) +#define F_AUTOENABLE V_AUTOENABLE(1U) + +#define S_DACK_MODE 0 +#define V_DACK_MODE(x) ((x) << S_DACK_MODE) +#define F_DACK_MODE V_DACK_MODE(1U) + +#define A_TP_PC_CONFIG 0x348 + +#define S_TXTOSQUEUEMAPMODE 26 +#define V_TXTOSQUEUEMAPMODE(x) ((x) << S_TXTOSQUEUEMAPMODE) +#define F_TXTOSQUEUEMAPMODE V_TXTOSQUEUEMAPMODE(1U) + +#define S_ENABLEEPCMDAFULL 23 +#define V_ENABLEEPCMDAFULL(x) ((x) << S_ENABLEEPCMDAFULL) +#define F_ENABLEEPCMDAFULL V_ENABLEEPCMDAFULL(1U) + +#define S_MODULATEUNIONMODE 22 +#define V_MODULATEUNIONMODE(x) ((x) << S_MODULATEUNIONMODE) +#define F_MODULATEUNIONMODE V_MODULATEUNIONMODE(1U) + +#define S_TXDEFERENABLE 20 +#define V_TXDEFERENABLE(x) ((x) << S_TXDEFERENABLE) +#define F_TXDEFERENABLE V_TXDEFERENABLE(1U) + +#define S_RXCONGESTIONMODE 19 +#define V_RXCONGESTIONMODE(x) ((x) << S_RXCONGESTIONMODE) +#define F_RXCONGESTIONMODE V_RXCONGESTIONMODE(1U) + +#define S_HEARBEATDACK 16 +#define V_HEARBEATDACK(x) ((x) << S_HEARBEATDACK) +#define F_HEARBEATDACK V_HEARBEATDACK(1U) + +#define S_TXCONGESTIONMODE 15 +#define V_TXCONGESTIONMODE(x) ((x) << S_TXCONGESTIONMODE) +#define F_TXCONGESTIONMODE V_TXCONGESTIONMODE(1U) + +#define S_ENABLEOCSPIFULL 30 +#define V_ENABLEOCSPIFULL(x) ((x) << S_ENABLEOCSPIFULL) +#define F_ENABLEOCSPIFULL V_ENABLEOCSPIFULL(1U) + +#define S_LOCKTID 28 +#define V_LOCKTID(x) ((x) << S_LOCKTID) +#define F_LOCKTID V_LOCKTID(1U) + +#define A_TP_PC_CONFIG2 0x34c + +#define S_CHDRAFULL 4 +#define V_CHDRAFULL(x) ((x) << S_CHDRAFULL) +#define F_CHDRAFULL V_CHDRAFULL(1U) + +#define A_TP_TCP_BACKOFF_REG0 0x350 + +#define A_TP_TCP_BACKOFF_REG1 0x354 + +#define A_TP_TCP_BACKOFF_REG2 0x358 + +#define A_TP_TCP_BACKOFF_REG3 0x35c + +#define A_TP_PARA_REG2 0x368 + +#define S_MAXRXDATA 16 +#define M_MAXRXDATA 0xffff +#define V_MAXRXDATA(x) ((x) << S_MAXRXDATA) + +#define S_RXCOALESCESIZE 0 +#define M_RXCOALESCESIZE 0xffff +#define V_RXCOALESCESIZE(x) ((x) << S_RXCOALESCESIZE) + +#define A_TP_PARA_REG3 0x36c + +#define S_TXDATAACKIDX 16 +#define M_TXDATAACKIDX 0xf + +#define V_TXDATAACKIDX(x) ((x) << S_TXDATAACKIDX) + +#define S_TXPACEAUTOSTRICT 10 +#define V_TXPACEAUTOSTRICT(x) ((x) << S_TXPACEAUTOSTRICT) +#define F_TXPACEAUTOSTRICT V_TXPACEAUTOSTRICT(1U) + +#define S_TXPACEFIXED 9 +#define V_TXPACEFIXED(x) ((x) << S_TXPACEFIXED) +#define F_TXPACEFIXED V_TXPACEFIXED(1U) + +#define S_TXPACEAUTO 8 +#define V_TXPACEAUTO(x) ((x) << S_TXPACEAUTO) +#define F_TXPACEAUTO V_TXPACEAUTO(1U) + +#define S_RXCOALESCEENABLE 1 +#define V_RXCOALESCEENABLE(x) ((x) << S_RXCOALESCEENABLE) +#define F_RXCOALESCEENABLE V_RXCOALESCEENABLE(1U) + +#define S_RXCOALESCEPSHEN 0 +#define V_RXCOALESCEPSHEN(x) ((x) << S_RXCOALESCEPSHEN) +#define F_RXCOALESCEPSHEN V_RXCOALESCEPSHEN(1U) + +#define A_TP_PARA_REG4 0x370 + +#define A_TP_PARA_REG6 0x378 + +#define S_T3A_ENABLEESND 13 +#define V_T3A_ENABLEESND(x) ((x) << S_T3A_ENABLEESND) +#define F_T3A_ENABLEESND V_T3A_ENABLEESND(1U) + +#define S_ENABLEESND 11 +#define V_ENABLEESND(x) ((x) << S_ENABLEESND) +#define F_ENABLEESND V_ENABLEESND(1U) + +#define A_TP_PARA_REG7 0x37c + +#define S_PMMAXXFERLEN1 16 +#define M_PMMAXXFERLEN1 0xffff +#define V_PMMAXXFERLEN1(x) ((x) << S_PMMAXXFERLEN1) + +#define S_PMMAXXFERLEN0 0 +#define M_PMMAXXFERLEN0 0xffff +#define V_PMMAXXFERLEN0(x) ((x) << S_PMMAXXFERLEN0) + +#define A_TP_TIMER_RESOLUTION 0x390 + +#define S_TIMERRESOLUTION 16 +#define M_TIMERRESOLUTION 0xff +#define V_TIMERRESOLUTION(x) ((x) << S_TIMERRESOLUTION) + +#define S_TIMESTAMPRESOLUTION 8 +#define M_TIMESTAMPRESOLUTION 0xff +#define V_TIMESTAMPRESOLUTION(x) ((x) << S_TIMESTAMPRESOLUTION) + +#define S_DELAYEDACKRESOLUTION 0 +#define M_DELAYEDACKRESOLUTION 0xff +#define V_DELAYEDACKRESOLUTION(x) ((x) << S_DELAYEDACKRESOLUTION) + +#define A_TP_MSL 0x394 + +#define A_TP_RXT_MIN 0x398 + +#define A_TP_RXT_MAX 0x39c + +#define A_TP_PERS_MIN 0x3a0 + +#define A_TP_PERS_MAX 0x3a4 + +#define A_TP_KEEP_IDLE 0x3a8 + +#define A_TP_KEEP_INTVL 0x3ac + +#define A_TP_INIT_SRTT 0x3b0 + +#define A_TP_DACK_TIMER 0x3b4 + +#define A_TP_FINWAIT2_TIMER 0x3b8 + +#define A_TP_SHIFT_CNT 0x3c0 + +#define S_SYNSHIFTMAX 24 + +#define M_SYNSHIFTMAX 0xff + +#define V_SYNSHIFTMAX(x) ((x) << S_SYNSHIFTMAX) + +#define S_RXTSHIFTMAXR1 20 + +#define M_RXTSHIFTMAXR1 0xf + +#define V_RXTSHIFTMAXR1(x) ((x) << S_RXTSHIFTMAXR1) + +#define S_RXTSHIFTMAXR2 16 + +#define M_RXTSHIFTMAXR2 0xf + +#define V_RXTSHIFTMAXR2(x) ((x) << S_RXTSHIFTMAXR2) + +#define S_PERSHIFTBACKOFFMAX 12 +#define M_PERSHIFTBACKOFFMAX 0xf +#define V_PERSHIFTBACKOFFMAX(x) ((x) << S_PERSHIFTBACKOFFMAX) + +#define S_PERSHIFTMAX 8 +#define M_PERSHIFTMAX 0xf +#define V_PERSHIFTMAX(x) ((x) << S_PERSHIFTMAX) + +#define S_KEEPALIVEMAX 0 + +#define M_KEEPALIVEMAX 0xff + +#define V_KEEPALIVEMAX(x) ((x) << S_KEEPALIVEMAX) + +#define A_TP_MTU_PORT_TABLE 0x3d0 + +#define A_TP_CCTRL_TABLE 0x3dc + +#define A_TP_MTU_TABLE 0x3e4 + +#define A_TP_RSS_MAP_TABLE 0x3e8 + +#define A_TP_RSS_LKP_TABLE 0x3ec + +#define A_TP_RSS_CONFIG 0x3f0 + +#define S_TNL4TUPEN 29 +#define V_TNL4TUPEN(x) ((x) << S_TNL4TUPEN) +#define F_TNL4TUPEN V_TNL4TUPEN(1U) + +#define S_TNL2TUPEN 28 +#define V_TNL2TUPEN(x) ((x) << S_TNL2TUPEN) +#define F_TNL2TUPEN V_TNL2TUPEN(1U) + +#define S_TNLPRTEN 26 +#define V_TNLPRTEN(x) ((x) << S_TNLPRTEN) +#define F_TNLPRTEN V_TNLPRTEN(1U) + +#define S_TNLMAPEN 25 +#define V_TNLMAPEN(x) ((x) << S_TNLMAPEN) +#define F_TNLMAPEN V_TNLMAPEN(1U) + +#define S_TNLLKPEN 24 +#define V_TNLLKPEN(x) ((x) << S_TNLLKPEN) +#define F_TNLLKPEN V_TNLLKPEN(1U) + +#define S_RRCPLCPUSIZE 4 +#define M_RRCPLCPUSIZE 0x7 +#define V_RRCPLCPUSIZE(x) ((x) << S_RRCPLCPUSIZE) + +#define S_RQFEEDBACKENABLE 3 +#define V_RQFEEDBACKENABLE(x) ((x) << S_RQFEEDBACKENABLE) +#define F_RQFEEDBACKENABLE V_RQFEEDBACKENABLE(1U) + +#define S_DISABLE 0 + +#define A_TP_TM_PIO_ADDR 0x418 + +#define A_TP_TM_PIO_DATA 0x41c + +#define A_TP_TX_MOD_QUE_TABLE 0x420 + +#define A_TP_TX_RESOURCE_LIMIT 0x424 + +#define A_TP_TX_MOD_QUEUE_REQ_MAP 0x428 + +#define S_TX_MOD_QUEUE_REQ_MAP 0 +#define M_TX_MOD_QUEUE_REQ_MAP 0xff +#define V_TX_MOD_QUEUE_REQ_MAP(x) ((x) << S_TX_MOD_QUEUE_REQ_MAP) + +#define A_TP_TX_MOD_QUEUE_WEIGHT1 0x42c + +#define A_TP_TX_MOD_QUEUE_WEIGHT0 0x430 + +#define A_TP_MOD_CHANNEL_WEIGHT 0x434 + +#define A_TP_PIO_ADDR 0x440 + +#define A_TP_PIO_DATA 0x444 + +#define A_TP_RESET 0x44c + +#define S_FLSTINITENABLE 1 +#define V_FLSTINITENABLE(x) ((x) << S_FLSTINITENABLE) +#define F_FLSTINITENABLE V_FLSTINITENABLE(1U) + +#define S_TPRESET 0 +#define V_TPRESET(x) ((x) << S_TPRESET) +#define F_TPRESET V_TPRESET(1U) + +#define A_TP_CMM_MM_RX_FLST_BASE 0x460 + +#define A_TP_CMM_MM_TX_FLST_BASE 0x464 + +#define A_TP_CMM_MM_PS_FLST_BASE 0x468 + +#define A_TP_MIB_INDEX 0x450 + +#define A_TP_MIB_RDATA 0x454 + +#define A_TP_CMM_MM_MAX_PSTRUCT 0x46c + +#define A_TP_INT_ENABLE 0x470 + +#define A_TP_INT_CAUSE 0x474 + +#define A_TP_TX_MOD_Q1_Q0_RATE_LIMIT 0x8 + +#define A_TP_TX_DROP_CFG_CH0 0x12b + +#define A_TP_TX_DROP_MODE 0x12f + +#define A_TP_EGRESS_CONFIG 0x145 + +#define S_REWRITEFORCETOSIZE 0 +#define V_REWRITEFORCETOSIZE(x) ((x) << S_REWRITEFORCETOSIZE) +#define F_REWRITEFORCETOSIZE V_REWRITEFORCETOSIZE(1U) + +#define A_TP_TX_TRC_KEY0 0x20 + +#define A_TP_RX_TRC_KEY0 0x120 + +#define A_ULPRX_CTL 0x500 + +#define S_ROUND_ROBIN 4 +#define V_ROUND_ROBIN(x) ((x) << S_ROUND_ROBIN) +#define F_ROUND_ROBIN V_ROUND_ROBIN(1U) + +#define A_ULPRX_INT_ENABLE 0x504 + +#define S_PARERR 0 +#define V_PARERR(x) ((x) << S_PARERR) +#define F_PARERR V_PARERR(1U) + +#define A_ULPRX_INT_CAUSE 0x508 + +#define A_ULPRX_ISCSI_LLIMIT 0x50c + +#define A_ULPRX_ISCSI_ULIMIT 0x510 + +#define A_ULPRX_ISCSI_TAGMASK 0x514 + +#define A_ULPRX_TDDP_LLIMIT 0x51c + +#define A_ULPRX_TDDP_ULIMIT 0x520 + +#define A_ULPRX_STAG_LLIMIT 0x52c + +#define A_ULPRX_STAG_ULIMIT 0x530 + +#define A_ULPRX_RQ_LLIMIT 0x534 +#define A_ULPRX_RQ_LLIMIT 0x534 + +#define A_ULPRX_RQ_ULIMIT 0x538 +#define A_ULPRX_RQ_ULIMIT 0x538 + +#define A_ULPRX_PBL_LLIMIT 0x53c + +#define A_ULPRX_PBL_ULIMIT 0x540 +#define A_ULPRX_PBL_ULIMIT 0x540 + +#define A_ULPRX_TDDP_TAGMASK 0x524 + +#define A_ULPRX_RQ_LLIMIT 0x534 +#define A_ULPRX_RQ_LLIMIT 0x534 + +#define A_ULPRX_RQ_ULIMIT 0x538 +#define A_ULPRX_RQ_ULIMIT 0x538 + +#define A_ULPRX_PBL_ULIMIT 0x540 +#define A_ULPRX_PBL_ULIMIT 0x540 + +#define A_ULPTX_CONFIG 0x580 + +#define S_CFG_RR_ARB 0 +#define V_CFG_RR_ARB(x) ((x) << S_CFG_RR_ARB) +#define F_CFG_RR_ARB V_CFG_RR_ARB(1U) + +#define A_ULPTX_INT_ENABLE 0x584 + +#define S_PBL_BOUND_ERR_CH1 1 +#define V_PBL_BOUND_ERR_CH1(x) ((x) << S_PBL_BOUND_ERR_CH1) +#define F_PBL_BOUND_ERR_CH1 V_PBL_BOUND_ERR_CH1(1U) + +#define S_PBL_BOUND_ERR_CH0 0 +#define V_PBL_BOUND_ERR_CH0(x) ((x) << S_PBL_BOUND_ERR_CH0) +#define F_PBL_BOUND_ERR_CH0 V_PBL_BOUND_ERR_CH0(1U) + +#define A_ULPTX_INT_CAUSE 0x588 + +#define A_ULPTX_TPT_LLIMIT 0x58c + +#define A_ULPTX_TPT_ULIMIT 0x590 + +#define A_ULPTX_PBL_LLIMIT 0x594 + +#define A_ULPTX_PBL_ULIMIT 0x598 + +#define A_ULPTX_DMA_WEIGHT 0x5ac + +#define S_D1_WEIGHT 16 +#define M_D1_WEIGHT 0xffff +#define V_D1_WEIGHT(x) ((x) << S_D1_WEIGHT) + +#define S_D0_WEIGHT 0 +#define M_D0_WEIGHT 0xffff +#define V_D0_WEIGHT(x) ((x) << S_D0_WEIGHT) + +#define A_PM1_RX_CFG 0x5c0 + +#define A_PM1_RX_INT_ENABLE 0x5d8 + +#define S_ZERO_E_CMD_ERROR 18 +#define V_ZERO_E_CMD_ERROR(x) ((x) << S_ZERO_E_CMD_ERROR) +#define F_ZERO_E_CMD_ERROR V_ZERO_E_CMD_ERROR(1U) + +#define S_IESPI0_FIFO2X_RX_FRAMING_ERROR 17 +#define V_IESPI0_FIFO2X_RX_FRAMING_ERROR(x) ((x) << S_IESPI0_FIFO2X_RX_FRAMING_ERROR) +#define F_IESPI0_FIFO2X_RX_FRAMING_ERROR V_IESPI0_FIFO2X_RX_FRAMING_ERROR(1U) + +#define S_IESPI1_FIFO2X_RX_FRAMING_ERROR 16 +#define V_IESPI1_FIFO2X_RX_FRAMING_ERROR(x) ((x) << S_IESPI1_FIFO2X_RX_FRAMING_ERROR) +#define F_IESPI1_FIFO2X_RX_FRAMING_ERROR V_IESPI1_FIFO2X_RX_FRAMING_ERROR(1U) + +#define S_IESPI0_RX_FRAMING_ERROR 15 +#define V_IESPI0_RX_FRAMING_ERROR(x) ((x) << S_IESPI0_RX_FRAMING_ERROR) +#define F_IESPI0_RX_FRAMING_ERROR V_IESPI0_RX_FRAMING_ERROR(1U) + +#define S_IESPI1_RX_FRAMING_ERROR 14 +#define V_IESPI1_RX_FRAMING_ERROR(x) ((x) << S_IESPI1_RX_FRAMING_ERROR) +#define F_IESPI1_RX_FRAMING_ERROR V_IESPI1_RX_FRAMING_ERROR(1U) + +#define S_IESPI0_TX_FRAMING_ERROR 13 +#define V_IESPI0_TX_FRAMING_ERROR(x) ((x) << S_IESPI0_TX_FRAMING_ERROR) +#define F_IESPI0_TX_FRAMING_ERROR V_IESPI0_TX_FRAMING_ERROR(1U) + +#define S_IESPI1_TX_FRAMING_ERROR 12 +#define V_IESPI1_TX_FRAMING_ERROR(x) ((x) << S_IESPI1_TX_FRAMING_ERROR) +#define F_IESPI1_TX_FRAMING_ERROR V_IESPI1_TX_FRAMING_ERROR(1U) + +#define S_OCSPI0_RX_FRAMING_ERROR 11 +#define V_OCSPI0_RX_FRAMING_ERROR(x) ((x) << S_OCSPI0_RX_FRAMING_ERROR) +#define F_OCSPI0_RX_FRAMING_ERROR V_OCSPI0_RX_FRAMING_ERROR(1U) + +#define S_OCSPI1_RX_FRAMING_ERROR 10 +#define V_OCSPI1_RX_FRAMING_ERROR(x) ((x) << S_OCSPI1_RX_FRAMING_ERROR) +#define F_OCSPI1_RX_FRAMING_ERROR V_OCSPI1_RX_FRAMING_ERROR(1U) + +#define S_OCSPI0_TX_FRAMING_ERROR 9 +#define V_OCSPI0_TX_FRAMING_ERROR(x) ((x) << S_OCSPI0_TX_FRAMING_ERROR) +#define F_OCSPI0_TX_FRAMING_ERROR V_OCSPI0_TX_FRAMING_ERROR(1U) + +#define S_OCSPI1_TX_FRAMING_ERROR 8 +#define V_OCSPI1_TX_FRAMING_ERROR(x) ((x) << S_OCSPI1_TX_FRAMING_ERROR) +#define F_OCSPI1_TX_FRAMING_ERROR V_OCSPI1_TX_FRAMING_ERROR(1U) + +#define S_OCSPI0_OFIFO2X_TX_FRAMING_ERROR 7 +#define V_OCSPI0_OFIFO2X_TX_FRAMING_ERROR(x) ((x) << S_OCSPI0_OFIFO2X_TX_FRAMING_ERROR) +#define F_OCSPI0_OFIFO2X_TX_FRAMING_ERROR V_OCSPI0_OFIFO2X_TX_FRAMING_ERROR(1U) + +#define S_OCSPI1_OFIFO2X_TX_FRAMING_ERROR 6 +#define V_OCSPI1_OFIFO2X_TX_FRAMING_ERROR(x) ((x) << S_OCSPI1_OFIFO2X_TX_FRAMING_ERROR) +#define F_OCSPI1_OFIFO2X_TX_FRAMING_ERROR V_OCSPI1_OFIFO2X_TX_FRAMING_ERROR(1U) + +#define S_IESPI_PAR_ERROR 3 +#define M_IESPI_PAR_ERROR 0x7 + +#define V_IESPI_PAR_ERROR(x) ((x) << S_IESPI_PAR_ERROR) + +#define S_OCSPI_PAR_ERROR 0 +#define M_OCSPI_PAR_ERROR 0x7 + +#define V_OCSPI_PAR_ERROR(x) ((x) << S_OCSPI_PAR_ERROR) + +#define A_PM1_RX_INT_CAUSE 0x5dc + +#define A_PM1_TX_CFG 0x5e0 + +#define A_PM1_TX_INT_ENABLE 0x5f8 + +#define S_ZERO_C_CMD_ERROR 18 +#define V_ZERO_C_CMD_ERROR(x) ((x) << S_ZERO_C_CMD_ERROR) +#define F_ZERO_C_CMD_ERROR V_ZERO_C_CMD_ERROR(1U) + +#define S_ICSPI0_FIFO2X_RX_FRAMING_ERROR 17 +#define V_ICSPI0_FIFO2X_RX_FRAMING_ERROR(x) ((x) << S_ICSPI0_FIFO2X_RX_FRAMING_ERROR) +#define F_ICSPI0_FIFO2X_RX_FRAMING_ERROR V_ICSPI0_FIFO2X_RX_FRAMING_ERROR(1U) + +#define S_ICSPI1_FIFO2X_RX_FRAMING_ERROR 16 +#define V_ICSPI1_FIFO2X_RX_FRAMING_ERROR(x) ((x) << S_ICSPI1_FIFO2X_RX_FRAMING_ERROR) +#define F_ICSPI1_FIFO2X_RX_FRAMING_ERROR V_ICSPI1_FIFO2X_RX_FRAMING_ERROR(1U) + +#define S_ICSPI0_RX_FRAMING_ERROR 15 +#define V_ICSPI0_RX_FRAMING_ERROR(x) ((x) << S_ICSPI0_RX_FRAMING_ERROR) +#define F_ICSPI0_RX_FRAMING_ERROR V_ICSPI0_RX_FRAMING_ERROR(1U) + +#define S_ICSPI1_RX_FRAMING_ERROR 14 +#define V_ICSPI1_RX_FRAMING_ERROR(x) ((x) << S_ICSPI1_RX_FRAMING_ERROR) +#define F_ICSPI1_RX_FRAMING_ERROR V_ICSPI1_RX_FRAMING_ERROR(1U) + +#define S_ICSPI0_TX_FRAMING_ERROR 13 +#define V_ICSPI0_TX_FRAMING_ERROR(x) ((x) << S_ICSPI0_TX_FRAMING_ERROR) +#define F_ICSPI0_TX_FRAMING_ERROR V_ICSPI0_TX_FRAMING_ERROR(1U) + +#define S_ICSPI1_TX_FRAMING_ERROR 12 +#define V_ICSPI1_TX_FRAMING_ERROR(x) ((x) << S_ICSPI1_TX_FRAMING_ERROR) +#define F_ICSPI1_TX_FRAMING_ERROR V_ICSPI1_TX_FRAMING_ERROR(1U) + +#define S_OESPI0_RX_FRAMING_ERROR 11 +#define V_OESPI0_RX_FRAMING_ERROR(x) ((x) << S_OESPI0_RX_FRAMING_ERROR) +#define F_OESPI0_RX_FRAMING_ERROR V_OESPI0_RX_FRAMING_ERROR(1U) + +#define S_OESPI1_RX_FRAMING_ERROR 10 +#define V_OESPI1_RX_FRAMING_ERROR(x) ((x) << S_OESPI1_RX_FRAMING_ERROR) +#define F_OESPI1_RX_FRAMING_ERROR V_OESPI1_RX_FRAMING_ERROR(1U) + +#define S_OESPI0_TX_FRAMING_ERROR 9 +#define V_OESPI0_TX_FRAMING_ERROR(x) ((x) << S_OESPI0_TX_FRAMING_ERROR) +#define F_OESPI0_TX_FRAMING_ERROR V_OESPI0_TX_FRAMING_ERROR(1U) + +#define S_OESPI1_TX_FRAMING_ERROR 8 +#define V_OESPI1_TX_FRAMING_ERROR(x) ((x) << S_OESPI1_TX_FRAMING_ERROR) +#define F_OESPI1_TX_FRAMING_ERROR V_OESPI1_TX_FRAMING_ERROR(1U) + +#define S_OESPI0_OFIFO2X_TX_FRAMING_ERROR 7 +#define V_OESPI0_OFIFO2X_TX_FRAMING_ERROR(x) ((x) << S_OESPI0_OFIFO2X_TX_FRAMING_ERROR) +#define F_OESPI0_OFIFO2X_TX_FRAMING_ERROR V_OESPI0_OFIFO2X_TX_FRAMING_ERROR(1U) + +#define S_OESPI1_OFIFO2X_TX_FRAMING_ERROR 6 +#define V_OESPI1_OFIFO2X_TX_FRAMING_ERROR(x) ((x) << S_OESPI1_OFIFO2X_TX_FRAMING_ERROR) +#define F_OESPI1_OFIFO2X_TX_FRAMING_ERROR V_OESPI1_OFIFO2X_TX_FRAMING_ERROR(1U) + +#define S_ICSPI_PAR_ERROR 3 +#define M_ICSPI_PAR_ERROR 0x7 + +#define V_ICSPI_PAR_ERROR(x) ((x) << S_ICSPI_PAR_ERROR) + +#define S_OESPI_PAR_ERROR 0 +#define M_OESPI_PAR_ERROR 0x7 + +#define V_OESPI_PAR_ERROR(x) ((x) << S_OESPI_PAR_ERROR) + +#define A_PM1_TX_INT_CAUSE 0x5fc + +#define A_MPS_CFG 0x600 + +#define S_TPRXPORTEN 4 +#define V_TPRXPORTEN(x) ((x) << S_TPRXPORTEN) +#define F_TPRXPORTEN V_TPRXPORTEN(1U) + +#define S_TPTXPORT1EN 3 +#define V_TPTXPORT1EN(x) ((x) << S_TPTXPORT1EN) +#define F_TPTXPORT1EN V_TPTXPORT1EN(1U) + +#define S_TPTXPORT0EN 2 +#define V_TPTXPORT0EN(x) ((x) << S_TPTXPORT0EN) +#define F_TPTXPORT0EN V_TPTXPORT0EN(1U) + +#define S_PORT1ACTIVE 1 +#define V_PORT1ACTIVE(x) ((x) << S_PORT1ACTIVE) +#define F_PORT1ACTIVE V_PORT1ACTIVE(1U) + +#define S_PORT0ACTIVE 0 +#define V_PORT0ACTIVE(x) ((x) << S_PORT0ACTIVE) +#define F_PORT0ACTIVE V_PORT0ACTIVE(1U) + +#define S_ENFORCEPKT 11 +#define V_ENFORCEPKT(x) ((x) << S_ENFORCEPKT) +#define F_ENFORCEPKT V_ENFORCEPKT(1U) + +#define A_MPS_INT_ENABLE 0x61c + +#define S_MCAPARERRENB 6 +#define M_MCAPARERRENB 0x7 + +#define V_MCAPARERRENB(x) ((x) << S_MCAPARERRENB) + +#define S_RXTPPARERRENB 4 +#define M_RXTPPARERRENB 0x3 + +#define V_RXTPPARERRENB(x) ((x) << S_RXTPPARERRENB) + +#define S_TX1TPPARERRENB 2 +#define M_TX1TPPARERRENB 0x3 + +#define V_TX1TPPARERRENB(x) ((x) << S_TX1TPPARERRENB) + +#define S_TX0TPPARERRENB 0 +#define M_TX0TPPARERRENB 0x3 + +#define V_TX0TPPARERRENB(x) ((x) << S_TX0TPPARERRENB) + +#define A_MPS_INT_CAUSE 0x620 + +#define S_MCAPARERR 6 +#define M_MCAPARERR 0x7 + +#define V_MCAPARERR(x) ((x) << S_MCAPARERR) + +#define S_RXTPPARERR 4 +#define M_RXTPPARERR 0x3 + +#define V_RXTPPARERR(x) ((x) << S_RXTPPARERR) + +#define S_TX1TPPARERR 2 +#define M_TX1TPPARERR 0x3 + +#define V_TX1TPPARERR(x) ((x) << S_TX1TPPARERR) + +#define S_TX0TPPARERR 0 +#define M_TX0TPPARERR 0x3 + +#define V_TX0TPPARERR(x) ((x) << S_TX0TPPARERR) + +#define A_CPL_SWITCH_CNTRL 0x640 + +#define A_CPL_INTR_ENABLE 0x650 + +#define S_CIM_OVFL_ERROR 4 +#define V_CIM_OVFL_ERROR(x) ((x) << S_CIM_OVFL_ERROR) +#define F_CIM_OVFL_ERROR V_CIM_OVFL_ERROR(1U) + +#define S_TP_FRAMING_ERROR 3 +#define V_TP_FRAMING_ERROR(x) ((x) << S_TP_FRAMING_ERROR) +#define F_TP_FRAMING_ERROR V_TP_FRAMING_ERROR(1U) + +#define S_SGE_FRAMING_ERROR 2 +#define V_SGE_FRAMING_ERROR(x) ((x) << S_SGE_FRAMING_ERROR) +#define F_SGE_FRAMING_ERROR V_SGE_FRAMING_ERROR(1U) + +#define S_CIM_FRAMING_ERROR 1 +#define V_CIM_FRAMING_ERROR(x) ((x) << S_CIM_FRAMING_ERROR) +#define F_CIM_FRAMING_ERROR V_CIM_FRAMING_ERROR(1U) + +#define S_ZERO_SWITCH_ERROR 0 +#define V_ZERO_SWITCH_ERROR(x) ((x) << S_ZERO_SWITCH_ERROR) +#define F_ZERO_SWITCH_ERROR V_ZERO_SWITCH_ERROR(1U) + +#define A_CPL_INTR_CAUSE 0x654 + +#define A_CPL_MAP_TBL_DATA 0x65c + +#define A_SMB_GLOBAL_TIME_CFG 0x660 + +#define A_I2C_CFG 0x6a0 + +#define S_I2C_CLKDIV 0 +#define M_I2C_CLKDIV 0xfff +#define V_I2C_CLKDIV(x) ((x) << S_I2C_CLKDIV) + +#define A_MI1_CFG 0x6b0 + +#define S_CLKDIV 5 +#define M_CLKDIV 0xff +#define V_CLKDIV(x) ((x) << S_CLKDIV) + +#define S_ST 3 + +#define M_ST 0x3 + +#define V_ST(x) ((x) << S_ST) + +#define G_ST(x) (((x) >> S_ST) & M_ST) + +#define S_PREEN 2 +#define V_PREEN(x) ((x) << S_PREEN) +#define F_PREEN V_PREEN(1U) + +#define S_MDIINV 1 +#define V_MDIINV(x) ((x) << S_MDIINV) +#define F_MDIINV V_MDIINV(1U) + +#define S_MDIEN 0 +#define V_MDIEN(x) ((x) << S_MDIEN) +#define F_MDIEN V_MDIEN(1U) + +#define A_MI1_ADDR 0x6b4 + +#define S_PHYADDR 5 +#define M_PHYADDR 0x1f +#define V_PHYADDR(x) ((x) << S_PHYADDR) + +#define S_REGADDR 0 +#define M_REGADDR 0x1f +#define V_REGADDR(x) ((x) << S_REGADDR) + +#define A_MI1_DATA 0x6b8 + +#define A_MI1_OP 0x6bc + +#define S_MDI_OP 0 +#define M_MDI_OP 0x3 +#define V_MDI_OP(x) ((x) << S_MDI_OP) + +#define A_SF_DATA 0x6d8 + +#define A_SF_OP 0x6dc + +#define S_BYTECNT 1 +#define M_BYTECNT 0x3 +#define V_BYTECNT(x) ((x) << S_BYTECNT) + +#define A_PL_INT_ENABLE0 0x6e0 + +#define S_T3DBG 23 +#define V_T3DBG(x) ((x) << S_T3DBG) +#define F_T3DBG V_T3DBG(1U) + +#define S_XGMAC0_1 20 +#define V_XGMAC0_1(x) ((x) << S_XGMAC0_1) +#define F_XGMAC0_1 V_XGMAC0_1(1U) + +#define S_XGMAC0_0 19 +#define V_XGMAC0_0(x) ((x) << S_XGMAC0_0) +#define F_XGMAC0_0 V_XGMAC0_0(1U) + +#define S_MC5A 18 +#define V_MC5A(x) ((x) << S_MC5A) +#define F_MC5A V_MC5A(1U) + +#define S_CPL_SWITCH 12 +#define V_CPL_SWITCH(x) ((x) << S_CPL_SWITCH) +#define F_CPL_SWITCH V_CPL_SWITCH(1U) + +#define S_MPS0 11 +#define V_MPS0(x) ((x) << S_MPS0) +#define F_MPS0 V_MPS0(1U) + +#define S_PM1_TX 10 +#define V_PM1_TX(x) ((x) << S_PM1_TX) +#define F_PM1_TX V_PM1_TX(1U) + +#define S_PM1_RX 9 +#define V_PM1_RX(x) ((x) << S_PM1_RX) +#define F_PM1_RX V_PM1_RX(1U) + +#define S_ULP2_TX 8 +#define V_ULP2_TX(x) ((x) << S_ULP2_TX) +#define F_ULP2_TX V_ULP2_TX(1U) + +#define S_ULP2_RX 7 +#define V_ULP2_RX(x) ((x) << S_ULP2_RX) +#define F_ULP2_RX V_ULP2_RX(1U) + +#define S_TP1 6 +#define V_TP1(x) ((x) << S_TP1) +#define F_TP1 V_TP1(1U) + +#define S_CIM 5 +#define V_CIM(x) ((x) << S_CIM) +#define F_CIM V_CIM(1U) + +#define S_MC7_CM 4 +#define V_MC7_CM(x) ((x) << S_MC7_CM) +#define F_MC7_CM V_MC7_CM(1U) + +#define S_MC7_PMTX 3 +#define V_MC7_PMTX(x) ((x) << S_MC7_PMTX) +#define F_MC7_PMTX V_MC7_PMTX(1U) + +#define S_MC7_PMRX 2 +#define V_MC7_PMRX(x) ((x) << S_MC7_PMRX) +#define F_MC7_PMRX V_MC7_PMRX(1U) + +#define S_PCIM0 1 +#define V_PCIM0(x) ((x) << S_PCIM0) +#define F_PCIM0 V_PCIM0(1U) + +#define S_SGE3 0 +#define V_SGE3(x) ((x) << S_SGE3) +#define F_SGE3 V_SGE3(1U) + +#define A_PL_INT_CAUSE0 0x6e4 + +#define A_PL_RST 0x6f0 + +#define S_CRSTWRM 1 +#define V_CRSTWRM(x) ((x) << S_CRSTWRM) +#define F_CRSTWRM V_CRSTWRM(1U) + +#define A_PL_REV 0x6f4 + +#define A_PL_CLI 0x6f8 + +#define A_MC5_DB_CONFIG 0x704 + +#define S_TMTYPEHI 30 +#define V_TMTYPEHI(x) ((x) << S_TMTYPEHI) +#define F_TMTYPEHI V_TMTYPEHI(1U) + +#define S_TMPARTSIZE 28 +#define M_TMPARTSIZE 0x3 +#define V_TMPARTSIZE(x) ((x) << S_TMPARTSIZE) +#define G_TMPARTSIZE(x) (((x) >> S_TMPARTSIZE) & M_TMPARTSIZE) + +#define S_TMTYPE 26 +#define M_TMTYPE 0x3 +#define V_TMTYPE(x) ((x) << S_TMTYPE) +#define G_TMTYPE(x) (((x) >> S_TMTYPE) & M_TMTYPE) + +#define S_COMPEN 17 +#define V_COMPEN(x) ((x) << S_COMPEN) +#define F_COMPEN V_COMPEN(1U) + +#define S_PRTYEN 6 +#define V_PRTYEN(x) ((x) << S_PRTYEN) +#define F_PRTYEN V_PRTYEN(1U) + +#define S_MBUSEN 5 +#define V_MBUSEN(x) ((x) << S_MBUSEN) +#define F_MBUSEN V_MBUSEN(1U) + +#define S_DBGIEN 4 +#define V_DBGIEN(x) ((x) << S_DBGIEN) +#define F_DBGIEN V_DBGIEN(1U) + +#define S_TMRDY 2 +#define V_TMRDY(x) ((x) << S_TMRDY) +#define F_TMRDY V_TMRDY(1U) + +#define S_TMRST 1 +#define V_TMRST(x) ((x) << S_TMRST) +#define F_TMRST V_TMRST(1U) + +#define S_TMMODE 0 +#define V_TMMODE(x) ((x) << S_TMMODE) +#define F_TMMODE V_TMMODE(1U) + +#define F_TMMODE V_TMMODE(1U) + +#define A_MC5_DB_ROUTING_TABLE_INDEX 0x70c + +#define A_MC5_DB_FILTER_TABLE 0x710 + +#define A_MC5_DB_SERVER_INDEX 0x714 + +#define A_MC5_DB_RSP_LATENCY 0x720 + +#define S_RDLAT 16 +#define M_RDLAT 0x1f +#define V_RDLAT(x) ((x) << S_RDLAT) + +#define S_LRNLAT 8 +#define M_LRNLAT 0x1f +#define V_LRNLAT(x) ((x) << S_LRNLAT) + +#define S_SRCHLAT 0 +#define M_SRCHLAT 0x1f +#define V_SRCHLAT(x) ((x) << S_SRCHLAT) + +#define A_MC5_DB_PART_ID_INDEX 0x72c + +#define A_MC5_DB_INT_ENABLE 0x740 + +#define S_DELACTEMPTY 18 +#define V_DELACTEMPTY(x) ((x) << S_DELACTEMPTY) +#define F_DELACTEMPTY V_DELACTEMPTY(1U) + +#define S_DISPQPARERR 17 +#define V_DISPQPARERR(x) ((x) << S_DISPQPARERR) +#define F_DISPQPARERR V_DISPQPARERR(1U) + +#define S_REQQPARERR 16 +#define V_REQQPARERR(x) ((x) << S_REQQPARERR) +#define F_REQQPARERR V_REQQPARERR(1U) + +#define S_UNKNOWNCMD 15 +#define V_UNKNOWNCMD(x) ((x) << S_UNKNOWNCMD) +#define F_UNKNOWNCMD V_UNKNOWNCMD(1U) + +#define S_NFASRCHFAIL 8 +#define V_NFASRCHFAIL(x) ((x) << S_NFASRCHFAIL) +#define F_NFASRCHFAIL V_NFASRCHFAIL(1U) + +#define S_ACTRGNFULL 7 +#define V_ACTRGNFULL(x) ((x) << S_ACTRGNFULL) +#define F_ACTRGNFULL V_ACTRGNFULL(1U) + +#define S_PARITYERR 6 +#define V_PARITYERR(x) ((x) << S_PARITYERR) +#define F_PARITYERR V_PARITYERR(1U) + +#define A_MC5_DB_INT_CAUSE 0x744 + +#define A_MC5_DB_DBGI_CONFIG 0x774 + +#define A_MC5_DB_DBGI_REQ_CMD 0x778 + +#define A_MC5_DB_DBGI_REQ_ADDR0 0x77c + +#define A_MC5_DB_DBGI_REQ_ADDR1 0x780 + +#define A_MC5_DB_DBGI_REQ_ADDR2 0x784 + +#define A_MC5_DB_DBGI_REQ_DATA0 0x788 + +#define A_MC5_DB_DBGI_REQ_DATA1 0x78c + +#define A_MC5_DB_DBGI_REQ_DATA2 0x790 + +#define A_MC5_DB_DBGI_RSP_STATUS 0x7b0 + +#define S_DBGIRSPVALID 0 +#define V_DBGIRSPVALID(x) ((x) << S_DBGIRSPVALID) +#define F_DBGIRSPVALID V_DBGIRSPVALID(1U) + +#define A_MC5_DB_DBGI_RSP_DATA0 0x7b4 + +#define A_MC5_DB_DBGI_RSP_DATA1 0x7b8 + +#define A_MC5_DB_DBGI_RSP_DATA2 0x7bc + +#define A_MC5_DB_POPEN_DATA_WR_CMD 0x7cc + +#define A_MC5_DB_POPEN_MASK_WR_CMD 0x7d0 + +#define A_MC5_DB_AOPEN_SRCH_CMD 0x7d4 + +#define A_MC5_DB_AOPEN_LRN_CMD 0x7d8 + +#define A_MC5_DB_SYN_SRCH_CMD 0x7dc + +#define A_MC5_DB_SYN_LRN_CMD 0x7e0 + +#define A_MC5_DB_ACK_SRCH_CMD 0x7e4 + +#define A_MC5_DB_ACK_LRN_CMD 0x7e8 + +#define A_MC5_DB_ILOOKUP_CMD 0x7ec + +#define A_MC5_DB_ELOOKUP_CMD 0x7f0 + +#define A_MC5_DB_DATA_WRITE_CMD 0x7f4 + +#define A_MC5_DB_DATA_READ_CMD 0x7f8 + +#define XGMAC0_0_BASE_ADDR 0x800 + +#define A_XGM_TX_CTRL 0x800 + +#define S_TXEN 0 +#define V_TXEN(x) ((x) << S_TXEN) +#define F_TXEN V_TXEN(1U) + +#define A_XGM_TX_CFG 0x804 + +#define S_TXPAUSEEN 0 +#define V_TXPAUSEEN(x) ((x) << S_TXPAUSEEN) +#define F_TXPAUSEEN V_TXPAUSEEN(1U) + +#define A_XGM_RX_CTRL 0x80c + +#define S_RXEN 0 +#define V_RXEN(x) ((x) << S_RXEN) +#define F_RXEN V_RXEN(1U) + +#define A_XGM_RX_CFG 0x810 + +#define S_DISPAUSEFRAMES 9 +#define V_DISPAUSEFRAMES(x) ((x) << S_DISPAUSEFRAMES) +#define F_DISPAUSEFRAMES V_DISPAUSEFRAMES(1U) + +#define S_EN1536BFRAMES 8 +#define V_EN1536BFRAMES(x) ((x) << S_EN1536BFRAMES) +#define F_EN1536BFRAMES V_EN1536BFRAMES(1U) + +#define S_ENJUMBO 7 +#define V_ENJUMBO(x) ((x) << S_ENJUMBO) +#define F_ENJUMBO V_ENJUMBO(1U) + +#define S_RMFCS 6 +#define V_RMFCS(x) ((x) << S_RMFCS) +#define F_RMFCS V_RMFCS(1U) + +#define S_ENHASHMCAST 2 +#define V_ENHASHMCAST(x) ((x) << S_ENHASHMCAST) +#define F_ENHASHMCAST V_ENHASHMCAST(1U) + +#define S_COPYALLFRAMES 0 +#define V_COPYALLFRAMES(x) ((x) << S_COPYALLFRAMES) +#define F_COPYALLFRAMES V_COPYALLFRAMES(1U) + +#define A_XGM_RX_HASH_LOW 0x814 + +#define A_XGM_RX_HASH_HIGH 0x818 + +#define A_XGM_RX_EXACT_MATCH_LOW_1 0x81c + +#define A_XGM_RX_EXACT_MATCH_HIGH_1 0x820 + +#define A_XGM_RX_EXACT_MATCH_LOW_2 0x824 + +#define A_XGM_RX_EXACT_MATCH_LOW_3 0x82c + +#define A_XGM_RX_EXACT_MATCH_LOW_4 0x834 + +#define A_XGM_RX_EXACT_MATCH_LOW_5 0x83c + +#define A_XGM_RX_EXACT_MATCH_LOW_6 0x844 + +#define A_XGM_RX_EXACT_MATCH_LOW_7 0x84c + +#define A_XGM_RX_EXACT_MATCH_LOW_8 0x854 + +#define A_XGM_STAT_CTRL 0x880 + +#define S_CLRSTATS 2 +#define V_CLRSTATS(x) ((x) << S_CLRSTATS) +#define F_CLRSTATS V_CLRSTATS(1U) + +#define A_XGM_RXFIFO_CFG 0x884 + +#define S_RXFIFOPAUSEHWM 17 +#define M_RXFIFOPAUSEHWM 0xfff + +#define V_RXFIFOPAUSEHWM(x) ((x) << S_RXFIFOPAUSEHWM) + +#define G_RXFIFOPAUSEHWM(x) (((x) >> S_RXFIFOPAUSEHWM) & M_RXFIFOPAUSEHWM) + +#define S_RXFIFOPAUSELWM 5 +#define M_RXFIFOPAUSELWM 0xfff + +#define V_RXFIFOPAUSELWM(x) ((x) << S_RXFIFOPAUSELWM) + +#define G_RXFIFOPAUSELWM(x) (((x) >> S_RXFIFOPAUSELWM) & M_RXFIFOPAUSELWM) + +#define S_RXSTRFRWRD 1 +#define V_RXSTRFRWRD(x) ((x) << S_RXSTRFRWRD) +#define F_RXSTRFRWRD V_RXSTRFRWRD(1U) + +#define S_DISERRFRAMES 0 +#define V_DISERRFRAMES(x) ((x) << S_DISERRFRAMES) +#define F_DISERRFRAMES V_DISERRFRAMES(1U) + +#define A_XGM_TXFIFO_CFG 0x888 + +#define S_TXFIFOTHRESH 4 +#define M_TXFIFOTHRESH 0x1ff + +#define V_TXFIFOTHRESH(x) ((x) << S_TXFIFOTHRESH) + +#define A_XGM_SERDES_CTRL 0x890 +#define A_XGM_SERDES_CTRL0 0x8e0 + +#define S_SERDESRESET_ 24 +#define V_SERDESRESET_(x) ((x) << S_SERDESRESET_) +#define F_SERDESRESET_ V_SERDESRESET_(1U) + +#define S_RXENABLE 4 +#define V_RXENABLE(x) ((x) << S_RXENABLE) +#define F_RXENABLE V_RXENABLE(1U) + +#define S_TXENABLE 3 +#define V_TXENABLE(x) ((x) << S_TXENABLE) +#define F_TXENABLE V_TXENABLE(1U) + +#define A_XGM_PAUSE_TIMER 0x890 + +#define A_XGM_RGMII_IMP 0x89c + +#define S_XGM_IMPSETUPDATE 6 +#define V_XGM_IMPSETUPDATE(x) ((x) << S_XGM_IMPSETUPDATE) +#define F_XGM_IMPSETUPDATE V_XGM_IMPSETUPDATE(1U) + +#define S_RGMIIIMPPD 3 +#define M_RGMIIIMPPD 0x7 +#define V_RGMIIIMPPD(x) ((x) << S_RGMIIIMPPD) + +#define S_RGMIIIMPPU 0 +#define M_RGMIIIMPPU 0x7 +#define V_RGMIIIMPPU(x) ((x) << S_RGMIIIMPPU) + +#define S_CALRESET 8 +#define V_CALRESET(x) ((x) << S_CALRESET) +#define F_CALRESET V_CALRESET(1U) + +#define S_CALUPDATE 7 +#define V_CALUPDATE(x) ((x) << S_CALUPDATE) +#define F_CALUPDATE V_CALUPDATE(1U) + +#define A_XGM_XAUI_IMP 0x8a0 + +#define S_CALBUSY 31 +#define V_CALBUSY(x) ((x) << S_CALBUSY) +#define F_CALBUSY V_CALBUSY(1U) + +#define S_XGM_CALFAULT 29 +#define V_XGM_CALFAULT(x) ((x) << S_XGM_CALFAULT) +#define F_XGM_CALFAULT V_XGM_CALFAULT(1U) + +#define S_CALIMP 24 +#define M_CALIMP 0x1f +#define V_CALIMP(x) ((x) << S_CALIMP) +#define G_CALIMP(x) (((x) >> S_CALIMP) & M_CALIMP) + +#define S_XAUIIMP 0 +#define M_XAUIIMP 0x7 +#define V_XAUIIMP(x) ((x) << S_XAUIIMP) + +#define A_XGM_RX_MAX_PKT_SIZE 0x8a8 +#define A_XGM_RX_MAX_PKT_SIZE_ERR_CNT 0x9a4 + +#define A_XGM_RESET_CTRL 0x8ac + +#define S_XG2G_RESET_ 3 +#define V_XG2G_RESET_(x) ((x) << S_XG2G_RESET_) +#define F_XG2G_RESET_ V_XG2G_RESET_(1U) + +#define S_RGMII_RESET_ 2 +#define V_RGMII_RESET_(x) ((x) << S_RGMII_RESET_) +#define F_RGMII_RESET_ V_RGMII_RESET_(1U) + +#define S_PCS_RESET_ 1 +#define V_PCS_RESET_(x) ((x) << S_PCS_RESET_) +#define F_PCS_RESET_ V_PCS_RESET_(1U) + +#define S_MAC_RESET_ 0 +#define V_MAC_RESET_(x) ((x) << S_MAC_RESET_) +#define F_MAC_RESET_ V_MAC_RESET_(1U) + +#define A_XGM_PORT_CFG 0x8b8 + +#define S_CLKDIVRESET_ 3 +#define V_CLKDIVRESET_(x) ((x) << S_CLKDIVRESET_) +#define F_CLKDIVRESET_ V_CLKDIVRESET_(1U) + +#define S_PORTSPEED 1 +#define M_PORTSPEED 0x3 + +#define V_PORTSPEED(x) ((x) << S_PORTSPEED) + +#define S_ENRGMII 0 +#define V_ENRGMII(x) ((x) << S_ENRGMII) +#define F_ENRGMII V_ENRGMII(1U) + +#define A_XGM_INT_ENABLE 0x8d4 + +#define S_TXFIFO_PRTY_ERR 17 +#define M_TXFIFO_PRTY_ERR 0x7 + +#define V_TXFIFO_PRTY_ERR(x) ((x) << S_TXFIFO_PRTY_ERR) + +#define S_RXFIFO_PRTY_ERR 14 +#define M_RXFIFO_PRTY_ERR 0x7 + +#define V_RXFIFO_PRTY_ERR(x) ((x) << S_RXFIFO_PRTY_ERR) + +#define S_TXFIFO_UNDERRUN 13 +#define V_TXFIFO_UNDERRUN(x) ((x) << S_TXFIFO_UNDERRUN) +#define F_TXFIFO_UNDERRUN V_TXFIFO_UNDERRUN(1U) + +#define S_RXFIFO_OVERFLOW 12 +#define V_RXFIFO_OVERFLOW(x) ((x) << S_RXFIFO_OVERFLOW) +#define F_RXFIFO_OVERFLOW V_RXFIFO_OVERFLOW(1U) + +#define S_SERDES_LOS 4 +#define M_SERDES_LOS 0xf + +#define V_SERDES_LOS(x) ((x) << S_SERDES_LOS) + +#define S_XAUIPCSCTCERR 3 +#define V_XAUIPCSCTCERR(x) ((x) << S_XAUIPCSCTCERR) +#define F_XAUIPCSCTCERR V_XAUIPCSCTCERR(1U) + +#define S_XAUIPCSALIGNCHANGE 2 +#define V_XAUIPCSALIGNCHANGE(x) ((x) << S_XAUIPCSALIGNCHANGE) +#define F_XAUIPCSALIGNCHANGE V_XAUIPCSALIGNCHANGE(1U) + +#define A_XGM_INT_CAUSE 0x8d8 + +#define A_XGM_XAUI_ACT_CTRL 0x8dc + +#define S_TXACTENABLE 1 +#define V_TXACTENABLE(x) ((x) << S_TXACTENABLE) +#define F_TXACTENABLE V_TXACTENABLE(1U) + +#define A_XGM_SERDES_CTRL0 0x8e0 + +#define S_RESET3 23 +#define V_RESET3(x) ((x) << S_RESET3) +#define F_RESET3 V_RESET3(1U) + +#define S_RESET2 22 +#define V_RESET2(x) ((x) << S_RESET2) +#define F_RESET2 V_RESET2(1U) + +#define S_RESET1 21 +#define V_RESET1(x) ((x) << S_RESET1) +#define F_RESET1 V_RESET1(1U) + +#define S_RESET0 20 +#define V_RESET0(x) ((x) << S_RESET0) +#define F_RESET0 V_RESET0(1U) + +#define S_PWRDN3 19 +#define V_PWRDN3(x) ((x) << S_PWRDN3) +#define F_PWRDN3 V_PWRDN3(1U) + +#define S_PWRDN2 18 +#define V_PWRDN2(x) ((x) << S_PWRDN2) +#define F_PWRDN2 V_PWRDN2(1U) + +#define S_PWRDN1 17 +#define V_PWRDN1(x) ((x) << S_PWRDN1) +#define F_PWRDN1 V_PWRDN1(1U) + +#define S_PWRDN0 16 +#define V_PWRDN0(x) ((x) << S_PWRDN0) +#define F_PWRDN0 V_PWRDN0(1U) + +#define S_RESETPLL23 15 +#define V_RESETPLL23(x) ((x) << S_RESETPLL23) +#define F_RESETPLL23 V_RESETPLL23(1U) + +#define S_RESETPLL01 14 +#define V_RESETPLL01(x) ((x) << S_RESETPLL01) +#define F_RESETPLL01 V_RESETPLL01(1U) + +#define A_XGM_SERDES_STAT0 0x8f0 + +#define S_LOWSIG0 0 +#define V_LOWSIG0(x) ((x) << S_LOWSIG0) +#define F_LOWSIG0 V_LOWSIG0(1U) + +#define A_XGM_SERDES_STAT3 0x8fc + +#define A_XGM_STAT_TX_BYTE_LOW 0x900 + +#define A_XGM_STAT_TX_BYTE_HIGH 0x904 + +#define A_XGM_STAT_TX_FRAME_LOW 0x908 + +#define A_XGM_STAT_TX_FRAME_HIGH 0x90c + +#define A_XGM_STAT_TX_BCAST 0x910 + +#define A_XGM_STAT_TX_MCAST 0x914 + +#define A_XGM_STAT_TX_PAUSE 0x918 + +#define A_XGM_STAT_TX_64B_FRAMES 0x91c + +#define A_XGM_STAT_TX_65_127B_FRAMES 0x920 + +#define A_XGM_STAT_TX_128_255B_FRAMES 0x924 + +#define A_XGM_STAT_TX_256_511B_FRAMES 0x928 + +#define A_XGM_STAT_TX_512_1023B_FRAMES 0x92c + +#define A_XGM_STAT_TX_1024_1518B_FRAMES 0x930 + +#define A_XGM_STAT_TX_1519_MAXB_FRAMES 0x934 + +#define A_XGM_STAT_TX_ERR_FRAMES 0x938 + +#define A_XGM_STAT_RX_BYTES_LOW 0x93c + +#define A_XGM_STAT_RX_BYTES_HIGH 0x940 + +#define A_XGM_STAT_RX_FRAMES_LOW 0x944 + +#define A_XGM_STAT_RX_FRAMES_HIGH 0x948 + +#define A_XGM_STAT_RX_BCAST_FRAMES 0x94c + +#define A_XGM_STAT_RX_MCAST_FRAMES 0x950 + +#define A_XGM_STAT_RX_PAUSE_FRAMES 0x954 + +#define A_XGM_STAT_RX_64B_FRAMES 0x958 + +#define A_XGM_STAT_RX_65_127B_FRAMES 0x95c + +#define A_XGM_STAT_RX_128_255B_FRAMES 0x960 + +#define A_XGM_STAT_RX_256_511B_FRAMES 0x964 + +#define A_XGM_STAT_RX_512_1023B_FRAMES 0x968 + +#define A_XGM_STAT_RX_1024_1518B_FRAMES 0x96c + +#define A_XGM_STAT_RX_1519_MAXB_FRAMES 0x970 + +#define A_XGM_STAT_RX_SHORT_FRAMES 0x974 + +#define A_XGM_STAT_RX_OVERSIZE_FRAMES 0x978 + +#define A_XGM_STAT_RX_JABBER_FRAMES 0x97c + +#define A_XGM_STAT_RX_CRC_ERR_FRAMES 0x980 + +#define A_XGM_STAT_RX_LENGTH_ERR_FRAMES 0x984 + +#define A_XGM_STAT_RX_SYM_CODE_ERR_FRAMES 0x988 + +#define A_XGM_SERDES_STATUS0 0x98c + +#define A_XGM_SERDES_STATUS1 0x990 + +#define S_CMULOCK 31 +#define V_CMULOCK(x) ((x) << S_CMULOCK) +#define F_CMULOCK V_CMULOCK(1U) + +#define A_XGM_RX_MAX_PKT_SIZE_ERR_CNT 0x9a4 + +#define A_XGM_RX_SPI4_SOP_EOP_CNT 0x9ac + +#define XGMAC0_1_BASE_ADDR 0xa00 diff --git a/drivers/net/cxgb3/sge.c b/drivers/net/cxgb3/sge.c new file mode 100644 index 0000000..3f2cf8a --- /dev/null +++ b/drivers/net/cxgb3/sge.c @@ -0,0 +1,2681 @@ +/* + * Copyright (c) 2005-2007 Chelsio, Inc. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +#include +#include +#include +#include +#include +#include +#include +#include "common.h" +#include "regs.h" +#include "sge_defs.h" +#include "t3_cpl.h" +#include "firmware_exports.h" + +#define USE_GTS 0 + +#define SGE_RX_SM_BUF_SIZE 1536 +#define SGE_RX_COPY_THRES 256 + +# define SGE_RX_DROP_THRES 16 + +/* + * Period of the Tx buffer reclaim timer. This timer does not need to run + * frequently as Tx buffers are usually reclaimed by new Tx packets. + */ +#define TX_RECLAIM_PERIOD (HZ / 4) + +/* WR size in bytes */ +#define WR_LEN (WR_FLITS * 8) + +/* + * Types of Tx queues in each queue set. Order here matters, do not change. + */ +enum { TXQ_ETH, TXQ_OFLD, TXQ_CTRL }; + +/* Values for sge_txq.flags */ +enum { + TXQ_RUNNING = 1 << 0, /* fetch engine is running */ + TXQ_LAST_PKT_DB = 1 << 1, /* last packet rang the doorbell */ +}; + +struct tx_desc { + u64 flit[TX_DESC_FLITS]; +}; + +struct rx_desc { + __be32 addr_lo; + __be32 len_gen; + __be32 gen2; + __be32 addr_hi; +}; + +struct tx_sw_desc { /* SW state per Tx descriptor */ + struct sk_buff *skb; +}; + +struct rx_sw_desc { /* SW state per Rx descriptor */ + struct sk_buff *skb; + DECLARE_PCI_UNMAP_ADDR(dma_addr); +}; + +struct rsp_desc { /* response queue descriptor */ + struct rss_header rss_hdr; + __be32 flags; + __be32 len_cq; + u8 imm_data[47]; + u8 intr_gen; +}; + +struct unmap_info { /* packet unmapping info, overlays skb->cb */ + int sflit; /* start flit of first SGL entry in Tx descriptor */ + u16 fragidx; /* first page fragment in current Tx descriptor */ + u16 addr_idx; /* buffer index of first SGL entry in descriptor */ + u32 len; /* mapped length of skb main body */ +}; + +/* + * Maps a number of flits to the number of Tx descriptors that can hold them. + * The formula is + * + * desc = 1 + (flits - 2) / (WR_FLITS - 1). + * + * HW allows up to 4 descriptors to be combined into a WR. + */ +static u8 flit_desc_map[] = { + 0, +#if SGE_NUM_GENBITS == 1 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4 +#elif SGE_NUM_GENBITS == 2 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, +#else +# error "SGE_NUM_GENBITS must be 1 or 2" +#endif +}; + +static inline struct sge_qset *fl_to_qset(const struct sge_fl *q, int qidx) +{ + return container_of(q, struct sge_qset, fl[qidx]); +} + +static inline struct sge_qset *rspq_to_qset(const struct sge_rspq *q) +{ + return container_of(q, struct sge_qset, rspq); +} + +static inline struct sge_qset *txq_to_qset(const struct sge_txq *q, int qidx) +{ + return container_of(q, struct sge_qset, txq[qidx]); +} + +/** + * refill_rspq - replenish an SGE response queue + * @adapter: the adapter + * @q: the response queue to replenish + * @credits: how many new responses to make available + * + * Replenishes a response queue by making the supplied number of responses + * available to HW. + */ +static inline void refill_rspq(struct adapter *adapter, + const struct sge_rspq *q, unsigned int credits) +{ + t3_write_reg(adapter, A_SG_RSPQ_CREDIT_RETURN, + V_RSPQ(q->cntxt_id) | V_CREDITS(credits)); +} + +/** + * need_skb_unmap - does the platform need unmapping of sk_buffs? + * + * Returns true if the platfrom needs sk_buff unmapping. The compiler + * optimizes away unecessary code if this returns true. + */ +static inline int need_skb_unmap(void) +{ + /* + * This structure is used to tell if the platfrom needs buffer + * unmapping by checking if DECLARE_PCI_UNMAP_ADDR defines anything. + */ + struct dummy { + DECLARE_PCI_UNMAP_ADDR(addr); + }; + + return sizeof(struct dummy) != 0; +} + +/** + * unmap_skb - unmap a packet main body and its page fragments + * @skb: the packet + * @q: the Tx queue containing Tx descriptors for the packet + * @cidx: index of Tx descriptor + * @pdev: the PCI device + * + * Unmap the main body of an sk_buff and its page fragments, if any. + * Because of the fairly complicated structure of our SGLs and the desire + * to conserve space for metadata, we keep the information necessary to + * unmap an sk_buff partly in the sk_buff itself (in its cb), and partly + * in the Tx descriptors (the physical addresses of the various data + * buffers). The send functions initialize the state in skb->cb so we + * can unmap the buffers held in the first Tx descriptor here, and we + * have enough information at this point to update the state for the next + * Tx descriptor. + */ +static inline void unmap_skb(struct sk_buff *skb, struct sge_txq *q, + unsigned int cidx, struct pci_dev *pdev) +{ + const struct sg_ent *sgp; + struct unmap_info *ui = (struct unmap_info *)skb->cb; + int nfrags, frag_idx, curflit, j = ui->addr_idx; + + sgp = (struct sg_ent *)&q->desc[cidx].flit[ui->sflit]; + + if (ui->len) { + pci_unmap_single(pdev, be64_to_cpu(sgp->addr[0]), ui->len, + PCI_DMA_TODEVICE); + ui->len = 0; /* so we know for next descriptor for this skb */ + j = 1; + } + + frag_idx = ui->fragidx; + curflit = ui->sflit + 1 + j; + nfrags = skb_shinfo(skb)->nr_frags; + + while (frag_idx < nfrags && curflit < WR_FLITS) { + pci_unmap_page(pdev, be64_to_cpu(sgp->addr[j]), + skb_shinfo(skb)->frags[frag_idx].size, + PCI_DMA_TODEVICE); + j ^= 1; + if (j == 0) { + sgp++; + curflit++; + } + curflit++; + frag_idx++; + } + + if (frag_idx < nfrags) { /* SGL continues into next Tx descriptor */ + ui->fragidx = frag_idx; + ui->addr_idx = j; + ui->sflit = curflit - WR_FLITS - j; /* sflit can be -1 */ + } +} + +/** + * free_tx_desc - reclaims Tx descriptors and their buffers + * @adapter: the adapter + * @q: the Tx queue to reclaim descriptors from + * @n: the number of descriptors to reclaim + * + * Reclaims Tx descriptors from an SGE Tx queue and frees the associated + * Tx buffers. Called with the Tx queue lock held. + */ +static void free_tx_desc(struct adapter *adapter, struct sge_txq *q, + unsigned int n) +{ + struct tx_sw_desc *d; + struct pci_dev *pdev = adapter->pdev; + unsigned int cidx = q->cidx; + + d = &q->sdesc[cidx]; + while (n--) { + if (d->skb) { /* an SGL is present */ + if (need_skb_unmap()) + unmap_skb(d->skb, q, cidx, pdev); + if (d->skb->priority == cidx) + kfree_skb(d->skb); + } + ++d; + if (++cidx == q->size) { + cidx = 0; + d = q->sdesc; + } + } + q->cidx = cidx; +} + +/** + * reclaim_completed_tx - reclaims completed Tx descriptors + * @adapter: the adapter + * @q: the Tx queue to reclaim completed descriptors from + * + * Reclaims Tx descriptors that the SGE has indicated it has processed, + * and frees the associated buffers if possible. Called with the Tx + * queue's lock held. + */ +static inline void reclaim_completed_tx(struct adapter *adapter, + struct sge_txq *q) +{ + unsigned int reclaim = q->processed - q->cleaned; + + if (reclaim) { + free_tx_desc(adapter, q, reclaim); + q->cleaned += reclaim; + q->in_use -= reclaim; + } +} + +/** + * should_restart_tx - are there enough resources to restart a Tx queue? + * @q: the Tx queue + * + * Checks if there are enough descriptors to restart a suspended Tx queue. + */ +static inline int should_restart_tx(const struct sge_txq *q) +{ + unsigned int r = q->processed - q->cleaned; + + return q->in_use - r < (q->size >> 1); +} + +/** + * free_rx_bufs - free the Rx buffers on an SGE free list + * @pdev: the PCI device associated with the adapter + * @rxq: the SGE free list to clean up + * + * Release the buffers on an SGE free-buffer Rx queue. HW fetching from + * this queue should be stopped before calling this function. + */ +static void free_rx_bufs(struct pci_dev *pdev, struct sge_fl *q) +{ + unsigned int cidx = q->cidx; + + while (q->credits--) { + struct rx_sw_desc *d = &q->sdesc[cidx]; + + pci_unmap_single(pdev, pci_unmap_addr(d, dma_addr), + q->buf_size, PCI_DMA_FROMDEVICE); + kfree_skb(d->skb); + d->skb = NULL; + if (++cidx == q->size) + cidx = 0; + } +} + +/** + * add_one_rx_buf - add a packet buffer to a free-buffer list + * @skb: the buffer to add + * @len: the buffer length + * @d: the HW Rx descriptor to write + * @sd: the SW Rx descriptor to write + * @gen: the generation bit value + * @pdev: the PCI device associated with the adapter + * + * Add a buffer of the given length to the supplied HW and SW Rx + * descriptors. + */ +static inline void add_one_rx_buf(struct sk_buff *skb, unsigned int len, + struct rx_desc *d, struct rx_sw_desc *sd, + unsigned int gen, struct pci_dev *pdev) +{ + dma_addr_t mapping; + + sd->skb = skb; + mapping = pci_map_single(pdev, skb->data, len, PCI_DMA_FROMDEVICE); + pci_unmap_addr_set(sd, dma_addr, mapping); + + d->addr_lo = cpu_to_be32(mapping); + d->addr_hi = cpu_to_be32((u64) mapping >> 32); + wmb(); + d->len_gen = cpu_to_be32(V_FLD_GEN1(gen)); + d->gen2 = cpu_to_be32(V_FLD_GEN2(gen)); +} + +/** + * refill_fl - refill an SGE free-buffer list + * @adapter: the adapter + * @q: the free-list to refill + * @n: the number of new buffers to allocate + * @gfp: the gfp flags for allocating new buffers + * + * (Re)populate an SGE free-buffer list with up to @n new packet buffers, + * allocated with the supplied gfp flags. The caller must assure that + * @n does not exceed the queue's capacity. + */ +static void refill_fl(struct adapter *adap, struct sge_fl *q, int n, gfp_t gfp) +{ + struct rx_sw_desc *sd = &q->sdesc[q->pidx]; + struct rx_desc *d = &q->desc[q->pidx]; + + while (n--) { + struct sk_buff *skb = alloc_skb(q->buf_size, gfp); + + if (!skb) + break; + + add_one_rx_buf(skb, q->buf_size, d, sd, q->gen, adap->pdev); + d++; + sd++; + if (++q->pidx == q->size) { + q->pidx = 0; + q->gen ^= 1; + sd = q->sdesc; + d = q->desc; + } + q->credits++; + } + + t3_write_reg(adap, A_SG_KDOORBELL, V_EGRCNTX(q->cntxt_id)); +} + +static inline void __refill_fl(struct adapter *adap, struct sge_fl *fl) +{ + refill_fl(adap, fl, min(16U, fl->size - fl->credits), GFP_ATOMIC); +} + +/** + * recycle_rx_buf - recycle a receive buffer + * @adapter: the adapter + * @q: the SGE free list + * @idx: index of buffer to recycle + * + * Recycles the specified buffer on the given free list by adding it at + * the next available slot on the list. + */ +static void recycle_rx_buf(struct adapter *adap, struct sge_fl *q, + unsigned int idx) +{ + struct rx_desc *from = &q->desc[idx]; + struct rx_desc *to = &q->desc[q->pidx]; + + q->sdesc[q->pidx] = q->sdesc[idx]; + to->addr_lo = from->addr_lo; /* already big endian */ + to->addr_hi = from->addr_hi; /* likewise */ + wmb(); + to->len_gen = cpu_to_be32(V_FLD_GEN1(q->gen)); + to->gen2 = cpu_to_be32(V_FLD_GEN2(q->gen)); + q->credits++; + + if (++q->pidx == q->size) { + q->pidx = 0; + q->gen ^= 1; + } + t3_write_reg(adap, A_SG_KDOORBELL, V_EGRCNTX(q->cntxt_id)); +} + +/** + * alloc_ring - allocate resources for an SGE descriptor ring + * @pdev: the PCI device + * @nelem: the number of descriptors + * @elem_size: the size of each descriptor + * @sw_size: the size of the SW state associated with each ring element + * @phys: the physical address of the allocated ring + * @metadata: address of the array holding the SW state for the ring + * + * Allocates resources for an SGE descriptor ring, such as Tx queues, + * free buffer lists, or response queues. Each SGE ring requires + * space for its HW descriptors plus, optionally, space for the SW state + * associated with each HW entry (the metadata). The function returns + * three values: the virtual address for the HW ring (the return value + * of the function), the physical address of the HW ring, and the address + * of the SW ring. + */ +static void *alloc_ring(struct pci_dev *pdev, size_t nelem, size_t elem_size, + size_t sw_size, dma_addr_t *phys, void *metadata) +{ + size_t len = nelem * elem_size; + void *s = NULL; + void *p = dma_alloc_coherent(&pdev->dev, len, phys, GFP_KERNEL); + + if (!p) + return NULL; + if (sw_size) { + s = kcalloc(nelem, sw_size, GFP_KERNEL); + + if (!s) { + dma_free_coherent(&pdev->dev, len, p, *phys); + return NULL; + } + } + if (metadata) + *(void **)metadata = s; + memset(p, 0, len); + return p; +} + +/** + * free_qset - free the resources of an SGE queue set + * @adapter: the adapter owning the queue set + * @q: the queue set + * + * Release the HW and SW resources associated with an SGE queue set, such + * as HW contexts, packet buffers, and descriptor rings. Traffic to the + * queue set must be quiesced prior to calling this. + */ +void t3_free_qset(struct adapter *adapter, struct sge_qset *q) +{ + int i; + struct pci_dev *pdev = adapter->pdev; + + if (q->tx_reclaim_timer.function) + del_timer_sync(&q->tx_reclaim_timer); + + for (i = 0; i < SGE_RXQ_PER_SET; ++i) + if (q->fl[i].desc) { + spin_lock(&adapter->sge.reg_lock); + t3_sge_disable_fl(adapter, q->fl[i].cntxt_id); + spin_unlock(&adapter->sge.reg_lock); + free_rx_bufs(pdev, &q->fl[i]); + kfree(q->fl[i].sdesc); + dma_free_coherent(&pdev->dev, + q->fl[i].size * + sizeof(struct rx_desc), q->fl[i].desc, + q->fl[i].phys_addr); + } + + for (i = 0; i < SGE_TXQ_PER_SET; ++i) + if (q->txq[i].desc) { + spin_lock(&adapter->sge.reg_lock); + t3_sge_enable_ecntxt(adapter, q->txq[i].cntxt_id, 0); + spin_unlock(&adapter->sge.reg_lock); + if (q->txq[i].sdesc) { + free_tx_desc(adapter, &q->txq[i], + q->txq[i].in_use); + kfree(q->txq[i].sdesc); + } + dma_free_coherent(&pdev->dev, + q->txq[i].size * + sizeof(struct tx_desc), + q->txq[i].desc, q->txq[i].phys_addr); + __skb_queue_purge(&q->txq[i].sendq); + } + + if (q->rspq.desc) { + spin_lock(&adapter->sge.reg_lock); + t3_sge_disable_rspcntxt(adapter, q->rspq.cntxt_id); + spin_unlock(&adapter->sge.reg_lock); + dma_free_coherent(&pdev->dev, + q->rspq.size * sizeof(struct rsp_desc), + q->rspq.desc, q->rspq.phys_addr); + } + + if (q->netdev) + q->netdev->atalk_ptr = NULL; + + memset(q, 0, sizeof(*q)); +} + +/** + * init_qset_cntxt - initialize an SGE queue set context info + * @qs: the queue set + * @id: the queue set id + * + * Initializes the TIDs and context ids for the queues of a queue set. + */ +static void init_qset_cntxt(struct sge_qset *qs, unsigned int id) +{ + qs->rspq.cntxt_id = id; + qs->fl[0].cntxt_id = 2 * id; + qs->fl[1].cntxt_id = 2 * id + 1; + qs->txq[TXQ_ETH].cntxt_id = FW_TUNNEL_SGEEC_START + id; + qs->txq[TXQ_ETH].token = FW_TUNNEL_TID_START + id; + qs->txq[TXQ_OFLD].cntxt_id = FW_OFLD_SGEEC_START + id; + qs->txq[TXQ_CTRL].cntxt_id = FW_CTRL_SGEEC_START + id; + qs->txq[TXQ_CTRL].token = FW_CTRL_TID_START + id; +} + +/** + * sgl_len - calculates the size of an SGL of the given capacity + * @n: the number of SGL entries + * + * Calculates the number of flits needed for a scatter/gather list that + * can hold the given number of entries. + */ +static inline unsigned int sgl_len(unsigned int n) +{ + /* alternatively: 3 * (n / 2) + 2 * (n & 1) */ + return (3 * n) / 2 + (n & 1); +} + +/** + * flits_to_desc - returns the num of Tx descriptors for the given flits + * @n: the number of flits + * + * Calculates the number of Tx descriptors needed for the supplied number + * of flits. + */ +static inline unsigned int flits_to_desc(unsigned int n) +{ + BUG_ON(n >= ARRAY_SIZE(flit_desc_map)); + return flit_desc_map[n]; +} + +/** + * get_packet - return the next ingress packet buffer from a free list + * @adap: the adapter that received the packet + * @fl: the SGE free list holding the packet + * @len: the packet length including any SGE padding + * @drop_thres: # of remaining buffers before we start dropping packets + * + * Get the next packet from a free list and complete setup of the + * sk_buff. If the packet is small we make a copy and recycle the + * original buffer, otherwise we use the original buffer itself. If a + * positive drop threshold is supplied packets are dropped and their + * buffers recycled if (a) the number of remaining buffers is under the + * threshold and the packet is too big to copy, or (b) the packet should + * be copied but there is no memory for the copy. + */ +static struct sk_buff *get_packet(struct adapter *adap, struct sge_fl *fl, + unsigned int len, unsigned int drop_thres) +{ + struct sk_buff *skb = NULL; + struct rx_sw_desc *sd = &fl->sdesc[fl->cidx]; + + prefetch(sd->skb->data); + + if (len <= SGE_RX_COPY_THRES) { + skb = alloc_skb(len, GFP_ATOMIC); + if (likely(skb != NULL)) { + __skb_put(skb, len); + pci_dma_sync_single_for_cpu(adap->pdev, + pci_unmap_addr(sd, + dma_addr), + len, PCI_DMA_FROMDEVICE); + memcpy(skb->data, sd->skb->data, len); + pci_dma_sync_single_for_device(adap->pdev, + pci_unmap_addr(sd, + dma_addr), + len, PCI_DMA_FROMDEVICE); + } else if (!drop_thres) + goto use_orig_buf; + recycle: + recycle_rx_buf(adap, fl, fl->cidx); + return skb; + } + + if (unlikely(fl->credits < drop_thres)) + goto recycle; + + use_orig_buf: + pci_unmap_single(adap->pdev, pci_unmap_addr(sd, dma_addr), + fl->buf_size, PCI_DMA_FROMDEVICE); + skb = sd->skb; + skb_put(skb, len); + __refill_fl(adap, fl); + return skb; +} + +/** + * get_imm_packet - return the next ingress packet buffer from a response + * @resp: the response descriptor containing the packet data + * + * Return a packet containing the immediate data of the given response. + */ +static inline struct sk_buff *get_imm_packet(const struct rsp_desc *resp) +{ + struct sk_buff *skb = alloc_skb(IMMED_PKT_SIZE, GFP_ATOMIC); + + if (skb) { + __skb_put(skb, IMMED_PKT_SIZE); + memcpy(skb->data, resp->imm_data, IMMED_PKT_SIZE); + } + return skb; +} + +/** + * calc_tx_descs - calculate the number of Tx descriptors for a packet + * @skb: the packet + * + * Returns the number of Tx descriptors needed for the given Ethernet + * packet. Ethernet packets require addition of WR and CPL headers. + */ +static inline unsigned int calc_tx_descs(const struct sk_buff *skb) +{ + unsigned int flits; + + if (skb->len <= WR_LEN - sizeof(struct cpl_tx_pkt)) + return 1; + + flits = sgl_len(skb_shinfo(skb)->nr_frags + 1) + 2; + if (skb_shinfo(skb)->gso_size) + flits++; + return flits_to_desc(flits); +} + +/** + * make_sgl - populate a scatter/gather list for a packet + * @skb: the packet + * @sgp: the SGL to populate + * @start: start address of skb main body data to include in the SGL + * @len: length of skb main body data to include in the SGL + * @pdev: the PCI device + * + * Generates a scatter/gather list for the buffers that make up a packet + * and returns the SGL size in 8-byte words. The caller must size the SGL + * appropriately. + */ +static inline unsigned int make_sgl(const struct sk_buff *skb, + struct sg_ent *sgp, unsigned char *start, + unsigned int len, struct pci_dev *pdev) +{ + dma_addr_t mapping; + unsigned int i, j = 0, nfrags; + + if (len) { + mapping = pci_map_single(pdev, start, len, PCI_DMA_TODEVICE); + sgp->len[0] = cpu_to_be32(len); + sgp->addr[0] = cpu_to_be64(mapping); + j = 1; + } + + nfrags = skb_shinfo(skb)->nr_frags; + for (i = 0; i < nfrags; i++) { + skb_frag_t *frag = &skb_shinfo(skb)->frags[i]; + + mapping = pci_map_page(pdev, frag->page, frag->page_offset, + frag->size, PCI_DMA_TODEVICE); + sgp->len[j] = cpu_to_be32(frag->size); + sgp->addr[j] = cpu_to_be64(mapping); + j ^= 1; + if (j == 0) + ++sgp; + } + if (j) + sgp->len[j] = 0; + return ((nfrags + (len != 0)) * 3) / 2 + j; +} + +/** + * check_ring_tx_db - check and potentially ring a Tx queue's doorbell + * @adap: the adapter + * @q: the Tx queue + * + * Ring the doorbel if a Tx queue is asleep. There is a natural race, + * where the HW is going to sleep just after we checked, however, + * then the interrupt handler will detect the outstanding TX packet + * and ring the doorbell for us. + * + * When GTS is disabled we unconditionally ring the doorbell. + */ +static inline void check_ring_tx_db(struct adapter *adap, struct sge_txq *q) +{ +#if USE_GTS + clear_bit(TXQ_LAST_PKT_DB, &q->flags); + if (test_and_set_bit(TXQ_RUNNING, &q->flags) == 0) { + set_bit(TXQ_LAST_PKT_DB, &q->flags); + t3_write_reg(adap, A_SG_KDOORBELL, + F_SELEGRCNTX | V_EGRCNTX(q->cntxt_id)); + } +#else + wmb(); /* write descriptors before telling HW */ + t3_write_reg(adap, A_SG_KDOORBELL, + F_SELEGRCNTX | V_EGRCNTX(q->cntxt_id)); +#endif +} + +static inline void wr_gen2(struct tx_desc *d, unsigned int gen) +{ +#if SGE_NUM_GENBITS == 2 + d->flit[TX_DESC_FLITS - 1] = cpu_to_be64(gen); +#endif +} + +/** + * write_wr_hdr_sgl - write a WR header and, optionally, SGL + * @ndesc: number of Tx descriptors spanned by the SGL + * @skb: the packet corresponding to the WR + * @d: first Tx descriptor to be written + * @pidx: index of above descriptors + * @q: the SGE Tx queue + * @sgl: the SGL + * @flits: number of flits to the start of the SGL in the first descriptor + * @sgl_flits: the SGL size in flits + * @gen: the Tx descriptor generation + * @wr_hi: top 32 bits of WR header based on WR type (big endian) + * @wr_lo: low 32 bits of WR header based on WR type (big endian) + * + * Write a work request header and an associated SGL. If the SGL is + * small enough to fit into one Tx descriptor it has already been written + * and we just need to write the WR header. Otherwise we distribute the + * SGL across the number of descriptors it spans. + */ +static void write_wr_hdr_sgl(unsigned int ndesc, struct sk_buff *skb, + struct tx_desc *d, unsigned int pidx, + const struct sge_txq *q, + const struct sg_ent *sgl, + unsigned int flits, unsigned int sgl_flits, + unsigned int gen, unsigned int wr_hi, + unsigned int wr_lo) +{ + struct work_request_hdr *wrp = (struct work_request_hdr *)d; + struct tx_sw_desc *sd = &q->sdesc[pidx]; + + sd->skb = skb; + if (need_skb_unmap()) { + struct unmap_info *ui = (struct unmap_info *)skb->cb; + + ui->fragidx = 0; + ui->addr_idx = 0; + ui->sflit = flits; + } + + if (likely(ndesc == 1)) { + skb->priority = pidx; + wrp->wr_hi = htonl(F_WR_SOP | F_WR_EOP | V_WR_DATATYPE(1) | + V_WR_SGLSFLT(flits)) | wr_hi; + wmb(); + wrp->wr_lo = htonl(V_WR_LEN(flits + sgl_flits) | + V_WR_GEN(gen)) | wr_lo; + wr_gen2(d, gen); + } else { + unsigned int ogen = gen; + const u64 *fp = (const u64 *)sgl; + struct work_request_hdr *wp = wrp; + + wrp->wr_hi = htonl(F_WR_SOP | V_WR_DATATYPE(1) | + V_WR_SGLSFLT(flits)) | wr_hi; + + while (sgl_flits) { + unsigned int avail = WR_FLITS - flits; + + if (avail > sgl_flits) + avail = sgl_flits; + memcpy(&d->flit[flits], fp, avail * sizeof(*fp)); + sgl_flits -= avail; + ndesc--; + if (!sgl_flits) + break; + + fp += avail; + d++; + sd++; + if (++pidx == q->size) { + pidx = 0; + gen ^= 1; + d = q->desc; + sd = q->sdesc; + } + + sd->skb = skb; + wrp = (struct work_request_hdr *)d; + wrp->wr_hi = htonl(V_WR_DATATYPE(1) | + V_WR_SGLSFLT(1)) | wr_hi; + wrp->wr_lo = htonl(V_WR_LEN(min(WR_FLITS, + sgl_flits + 1)) | + V_WR_GEN(gen)) | wr_lo; + wr_gen2(d, gen); + flits = 1; + } + skb->priority = pidx; + wrp->wr_hi |= htonl(F_WR_EOP); + wmb(); + wp->wr_lo = htonl(V_WR_LEN(WR_FLITS) | V_WR_GEN(ogen)) | wr_lo; + wr_gen2((struct tx_desc *)wp, ogen); + WARN_ON(ndesc != 0); + } +} + +/** + * write_tx_pkt_wr - write a TX_PKT work request + * @adap: the adapter + * @skb: the packet to send + * @pi: the egress interface + * @pidx: index of the first Tx descriptor to write + * @gen: the generation value to use + * @q: the Tx queue + * @ndesc: number of descriptors the packet will occupy + * @compl: the value of the COMPL bit to use + * + * Generate a TX_PKT work request to send the supplied packet. + */ +static void write_tx_pkt_wr(struct adapter *adap, struct sk_buff *skb, + const struct port_info *pi, + unsigned int pidx, unsigned int gen, + struct sge_txq *q, unsigned int ndesc, + unsigned int compl) +{ + unsigned int flits, sgl_flits, cntrl, tso_info; + struct sg_ent *sgp, sgl[MAX_SKB_FRAGS / 2 + 1]; + struct tx_desc *d = &q->desc[pidx]; + struct cpl_tx_pkt *cpl = (struct cpl_tx_pkt *)d; + + cpl->len = htonl(skb->len | 0x80000000); + cntrl = V_TXPKT_INTF(pi->port_id); + + if (vlan_tx_tag_present(skb) && pi->vlan_grp) + cntrl |= F_TXPKT_VLAN_VLD | V_TXPKT_VLAN(vlan_tx_tag_get(skb)); + + tso_info = V_LSO_MSS(skb_shinfo(skb)->gso_size); + if (tso_info) { + int eth_type; + struct cpl_tx_pkt_lso *hdr = (struct cpl_tx_pkt_lso *)cpl; + + d->flit[2] = 0; + cntrl |= V_TXPKT_OPCODE(CPL_TX_PKT_LSO); + hdr->cntrl = htonl(cntrl); + eth_type = skb->nh.raw - skb->data == ETH_HLEN ? + CPL_ETH_II : CPL_ETH_II_VLAN; + tso_info |= V_LSO_ETH_TYPE(eth_type) | + V_LSO_IPHDR_WORDS(skb->nh.iph->ihl) | + V_LSO_TCPHDR_WORDS(skb->h.th->doff); + hdr->lso_info = htonl(tso_info); + flits = 3; + } else { + cntrl |= V_TXPKT_OPCODE(CPL_TX_PKT); + cntrl |= F_TXPKT_IPCSUM_DIS; /* SW calculates IP csum */ + cntrl |= V_TXPKT_L4CSUM_DIS(skb->ip_summed != CHECKSUM_PARTIAL); + cpl->cntrl = htonl(cntrl); + + if (skb->len <= WR_LEN - sizeof(*cpl)) { + q->sdesc[pidx].skb = NULL; + if (!skb->data_len) + memcpy(&d->flit[2], skb->data, skb->len); + else + skb_copy_bits(skb, 0, &d->flit[2], skb->len); + + flits = (skb->len + 7) / 8 + 2; + cpl->wr.wr_hi = htonl(V_WR_BCNTLFLT(skb->len & 7) | + V_WR_OP(FW_WROPCODE_TUNNEL_TX_PKT) + | F_WR_SOP | F_WR_EOP | compl); + wmb(); + cpl->wr.wr_lo = htonl(V_WR_LEN(flits) | V_WR_GEN(gen) | + V_WR_TID(q->token)); + wr_gen2(d, gen); + kfree_skb(skb); + return; + } + + flits = 2; + } + + sgp = ndesc == 1 ? (struct sg_ent *)&d->flit[flits] : sgl; + sgl_flits = make_sgl(skb, sgp, skb->data, skb_headlen(skb), adap->pdev); + if (need_skb_unmap()) + ((struct unmap_info *)skb->cb)->len = skb_headlen(skb); + + write_wr_hdr_sgl(ndesc, skb, d, pidx, q, sgl, flits, sgl_flits, gen, + htonl(V_WR_OP(FW_WROPCODE_TUNNEL_TX_PKT) | compl), + htonl(V_WR_TID(q->token))); +} + +/** + * eth_xmit - add a packet to the Ethernet Tx queue + * @skb: the packet + * @dev: the egress net device + * + * Add a packet to an SGE Tx queue. Runs with softirqs disabled. + */ +int t3_eth_xmit(struct sk_buff *skb, struct net_device *dev) +{ + unsigned int ndesc, pidx, credits, gen, compl; + const struct port_info *pi = netdev_priv(dev); + struct adapter *adap = dev->priv; + struct sge_qset *qs = dev2qset(dev); + struct sge_txq *q = &qs->txq[TXQ_ETH]; + + /* + * The chip min packet length is 9 octets but play safe and reject + * anything shorter than an Ethernet header. + */ + if (unlikely(skb->len < ETH_HLEN)) { + dev_kfree_skb(skb); + return NETDEV_TX_OK; + } + + spin_lock(&q->lock); + reclaim_completed_tx(adap, q); + + credits = q->size - q->in_use; + ndesc = calc_tx_descs(skb); + + if (unlikely(credits < ndesc)) { + if (!netif_queue_stopped(dev)) { + netif_stop_queue(dev); + set_bit(TXQ_ETH, &qs->txq_stopped); + q->stops++; + dev_err(&adap->pdev->dev, + "%s: Tx ring %u full while queue awake!\n", + dev->name, q->cntxt_id & 7); + } + spin_unlock(&q->lock); + return NETDEV_TX_BUSY; + } + + q->in_use += ndesc; + if (unlikely(credits - ndesc < q->stop_thres)) { + q->stops++; + netif_stop_queue(dev); + set_bit(TXQ_ETH, &qs->txq_stopped); +#if !USE_GTS + if (should_restart_tx(q) && + test_and_clear_bit(TXQ_ETH, &qs->txq_stopped)) { + q->restarts++; + netif_wake_queue(dev); + } +#endif + } + + gen = q->gen; + q->unacked += ndesc; + compl = (q->unacked & 8) << (S_WR_COMPL - 3); + q->unacked &= 7; + pidx = q->pidx; + q->pidx += ndesc; + if (q->pidx >= q->size) { + q->pidx -= q->size; + q->gen ^= 1; + } + + /* update port statistics */ + if (skb->ip_summed == CHECKSUM_COMPLETE) + qs->port_stats[SGE_PSTAT_TX_CSUM]++; + if (skb_shinfo(skb)->gso_size) + qs->port_stats[SGE_PSTAT_TSO]++; + if (vlan_tx_tag_present(skb) && pi->vlan_grp) + qs->port_stats[SGE_PSTAT_VLANINS]++; + + dev->trans_start = jiffies; + spin_unlock(&q->lock); + + /* + * We do not use Tx completion interrupts to free DMAd Tx packets. + * This is good for performamce but means that we rely on new Tx + * packets arriving to run the destructors of completed packets, + * which open up space in their sockets' send queues. Sometimes + * we do not get such new packets causing Tx to stall. A single + * UDP transmitter is a good example of this situation. We have + * a clean up timer that periodically reclaims completed packets + * but it doesn't run often enough (nor do we want it to) to prevent + * lengthy stalls. A solution to this problem is to run the + * destructor early, after the packet is queued but before it's DMAd. + * A cons is that we lie to socket memory accounting, but the amount + * of extra memory is reasonable (limited by the number of Tx + * descriptors), the packets do actually get freed quickly by new + * packets almost always, and for protocols like TCP that wait for + * acks to really free up the data the extra memory is even less. + * On the positive side we run the destructors on the sending CPU + * rather than on a potentially different completing CPU, usually a + * good thing. We also run them without holding our Tx queue lock, + * unlike what reclaim_completed_tx() would otherwise do. + * + * Run the destructor before telling the DMA engine about the packet + * to make sure it doesn't complete and get freed prematurely. + */ + if (likely(!skb_shared(skb))) + skb_orphan(skb); + + write_tx_pkt_wr(adap, skb, pi, pidx, gen, q, ndesc, compl); + check_ring_tx_db(adap, q); + return NETDEV_TX_OK; +} + +/** + * write_imm - write a packet into a Tx descriptor as immediate data + * @d: the Tx descriptor to write + * @skb: the packet + * @len: the length of packet data to write as immediate data + * @gen: the generation bit value to write + * + * Writes a packet as immediate data into a Tx descriptor. The packet + * contains a work request at its beginning. We must write the packet + * carefully so the SGE doesn't read accidentally before it's written in + * its entirety. + */ +static inline void write_imm(struct tx_desc *d, struct sk_buff *skb, + unsigned int len, unsigned int gen) +{ + struct work_request_hdr *from = (struct work_request_hdr *)skb->data; + struct work_request_hdr *to = (struct work_request_hdr *)d; + + memcpy(&to[1], &from[1], len - sizeof(*from)); + to->wr_hi = from->wr_hi | htonl(F_WR_SOP | F_WR_EOP | + V_WR_BCNTLFLT(len & 7)); + wmb(); + to->wr_lo = from->wr_lo | htonl(V_WR_GEN(gen) | + V_WR_LEN((len + 7) / 8)); + wr_gen2(d, gen); + kfree_skb(skb); +} + +/** + * check_desc_avail - check descriptor availability on a send queue + * @adap: the adapter + * @q: the send queue + * @skb: the packet needing the descriptors + * @ndesc: the number of Tx descriptors needed + * @qid: the Tx queue number in its queue set (TXQ_OFLD or TXQ_CTRL) + * + * Checks if the requested number of Tx descriptors is available on an + * SGE send queue. If the queue is already suspended or not enough + * descriptors are available the packet is queued for later transmission. + * Must be called with the Tx queue locked. + * + * Returns 0 if enough descriptors are available, 1 if there aren't + * enough descriptors and the packet has been queued, and 2 if the caller + * needs to retry because there weren't enough descriptors at the + * beginning of the call but some freed up in the mean time. + */ +static inline int check_desc_avail(struct adapter *adap, struct sge_txq *q, + struct sk_buff *skb, unsigned int ndesc, + unsigned int qid) +{ + if (unlikely(!skb_queue_empty(&q->sendq))) { + addq_exit:__skb_queue_tail(&q->sendq, skb); + return 1; + } + if (unlikely(q->size - q->in_use < ndesc)) { + struct sge_qset *qs = txq_to_qset(q, qid); + + set_bit(qid, &qs->txq_stopped); + smp_mb__after_clear_bit(); + + if (should_restart_tx(q) && + test_and_clear_bit(qid, &qs->txq_stopped)) + return 2; + + q->stops++; + goto addq_exit; + } + return 0; +} + +/** + * reclaim_completed_tx_imm - reclaim completed control-queue Tx descs + * @q: the SGE control Tx queue + * + * This is a variant of reclaim_completed_tx() that is used for Tx queues + * that send only immediate data (presently just the control queues) and + * thus do not have any sk_buffs to release. + */ +static inline void reclaim_completed_tx_imm(struct sge_txq *q) +{ + unsigned int reclaim = q->processed - q->cleaned; + + q->in_use -= reclaim; + q->cleaned += reclaim; +} + +static inline int immediate(const struct sk_buff *skb) +{ + return skb->len <= WR_LEN && !skb->data_len; +} + +/** + * ctrl_xmit - send a packet through an SGE control Tx queue + * @adap: the adapter + * @q: the control queue + * @skb: the packet + * + * Send a packet through an SGE control Tx queue. Packets sent through + * a control queue must fit entirely as immediate data in a single Tx + * descriptor and have no page fragments. + */ +static int ctrl_xmit(struct adapter *adap, struct sge_txq *q, + struct sk_buff *skb) +{ + int ret; + struct work_request_hdr *wrp = (struct work_request_hdr *)skb->data; + + if (unlikely(!immediate(skb))) { + WARN_ON(1); + dev_kfree_skb(skb); + return NET_XMIT_SUCCESS; + } + + wrp->wr_hi |= htonl(F_WR_SOP | F_WR_EOP); + wrp->wr_lo = htonl(V_WR_TID(q->token)); + + spin_lock(&q->lock); + again:reclaim_completed_tx_imm(q); + + ret = check_desc_avail(adap, q, skb, 1, TXQ_CTRL); + if (unlikely(ret)) { + if (ret == 1) { + spin_unlock(&q->lock); + return NET_XMIT_CN; + } + goto again; + } + + write_imm(&q->desc[q->pidx], skb, skb->len, q->gen); + + q->in_use++; + if (++q->pidx >= q->size) { + q->pidx = 0; + q->gen ^= 1; + } + spin_unlock(&q->lock); + wmb(); + t3_write_reg(adap, A_SG_KDOORBELL, + F_SELEGRCNTX | V_EGRCNTX(q->cntxt_id)); + return NET_XMIT_SUCCESS; +} + +/** + * restart_ctrlq - restart a suspended control queue + * @qs: the queue set cotaining the control queue + * + * Resumes transmission on a suspended Tx control queue. + */ +static void restart_ctrlq(unsigned long data) +{ + struct sk_buff *skb; + struct sge_qset *qs = (struct sge_qset *)data; + struct sge_txq *q = &qs->txq[TXQ_CTRL]; + struct adapter *adap = qs->netdev->priv; + + spin_lock(&q->lock); + again:reclaim_completed_tx_imm(q); + + while (q->in_use < q->size && (skb = __skb_dequeue(&q->sendq)) != NULL) { + + write_imm(&q->desc[q->pidx], skb, skb->len, q->gen); + + if (++q->pidx >= q->size) { + q->pidx = 0; + q->gen ^= 1; + } + q->in_use++; + } + + if (!skb_queue_empty(&q->sendq)) { + set_bit(TXQ_CTRL, &qs->txq_stopped); + smp_mb__after_clear_bit(); + + if (should_restart_tx(q) && + test_and_clear_bit(TXQ_CTRL, &qs->txq_stopped)) + goto again; + q->stops++; + } + + spin_unlock(&q->lock); + t3_write_reg(adap, A_SG_KDOORBELL, + F_SELEGRCNTX | V_EGRCNTX(q->cntxt_id)); +} + +/* + * Send a management message through control queue 0 + */ +int t3_mgmt_tx(struct adapter *adap, struct sk_buff *skb) +{ + return ctrl_xmit(adap, &adap->sge.qs[0].txq[TXQ_CTRL], skb); +} + +/** + * write_ofld_wr - write an offload work request + * @adap: the adapter + * @skb: the packet to send + * @q: the Tx queue + * @pidx: index of the first Tx descriptor to write + * @gen: the generation value to use + * @ndesc: number of descriptors the packet will occupy + * + * Write an offload work request to send the supplied packet. The packet + * data already carry the work request with most fields populated. + */ +static void write_ofld_wr(struct adapter *adap, struct sk_buff *skb, + struct sge_txq *q, unsigned int pidx, + unsigned int gen, unsigned int ndesc) +{ + unsigned int sgl_flits, flits; + struct work_request_hdr *from; + struct sg_ent *sgp, sgl[MAX_SKB_FRAGS / 2 + 1]; + struct tx_desc *d = &q->desc[pidx]; + + if (immediate(skb)) { + q->sdesc[pidx].skb = NULL; + write_imm(d, skb, skb->len, gen); + return; + } + + /* Only TX_DATA builds SGLs */ + + from = (struct work_request_hdr *)skb->data; + memcpy(&d->flit[1], &from[1], skb->h.raw - skb->data - sizeof(*from)); + + flits = (skb->h.raw - skb->data) / 8; + sgp = ndesc == 1 ? (struct sg_ent *)&d->flit[flits] : sgl; + sgl_flits = make_sgl(skb, sgp, skb->h.raw, skb->tail - skb->h.raw, + adap->pdev); + if (need_skb_unmap()) + ((struct unmap_info *)skb->cb)->len = skb->tail - skb->h.raw; + + write_wr_hdr_sgl(ndesc, skb, d, pidx, q, sgl, flits, sgl_flits, + gen, from->wr_hi, from->wr_lo); +} + +/** + * calc_tx_descs_ofld - calculate # of Tx descriptors for an offload packet + * @skb: the packet + * + * Returns the number of Tx descriptors needed for the given offload + * packet. These packets are already fully constructed. + */ +static inline unsigned int calc_tx_descs_ofld(const struct sk_buff *skb) +{ + unsigned int flits, cnt = skb_shinfo(skb)->nr_frags; + + if (skb->len <= WR_LEN && cnt == 0) + return 1; /* packet fits as immediate data */ + + flits = (skb->h.raw - skb->data) / 8; /* headers */ + if (skb->tail != skb->h.raw) + cnt++; + return flits_to_desc(flits + sgl_len(cnt)); +} + +/** + * ofld_xmit - send a packet through an offload queue + * @adap: the adapter + * @q: the Tx offload queue + * @skb: the packet + * + * Send an offload packet through an SGE offload queue. + */ +static int ofld_xmit(struct adapter *adap, struct sge_txq *q, + struct sk_buff *skb) +{ + int ret; + unsigned int ndesc = calc_tx_descs_ofld(skb), pidx, gen; + + spin_lock(&q->lock); + again:reclaim_completed_tx(adap, q); + + ret = check_desc_avail(adap, q, skb, ndesc, TXQ_OFLD); + if (unlikely(ret)) { + if (ret == 1) { + skb->priority = ndesc; /* save for restart */ + spin_unlock(&q->lock); + return NET_XMIT_CN; + } + goto again; + } + + gen = q->gen; + q->in_use += ndesc; + pidx = q->pidx; + q->pidx += ndesc; + if (q->pidx >= q->size) { + q->pidx -= q->size; + q->gen ^= 1; + } + spin_unlock(&q->lock); + + write_ofld_wr(adap, skb, q, pidx, gen, ndesc); + check_ring_tx_db(adap, q); + return NET_XMIT_SUCCESS; +} + +/** + * restart_offloadq - restart a suspended offload queue + * @qs: the queue set cotaining the offload queue + * + * Resumes transmission on a suspended Tx offload queue. + */ +static void restart_offloadq(unsigned long data) +{ + struct sk_buff *skb; + struct sge_qset *qs = (struct sge_qset *)data; + struct sge_txq *q = &qs->txq[TXQ_OFLD]; + struct adapter *adap = qs->netdev->priv; + + spin_lock(&q->lock); + again:reclaim_completed_tx(adap, q); + + while ((skb = skb_peek(&q->sendq)) != NULL) { + unsigned int gen, pidx; + unsigned int ndesc = skb->priority; + + if (unlikely(q->size - q->in_use < ndesc)) { + set_bit(TXQ_OFLD, &qs->txq_stopped); + smp_mb__after_clear_bit(); + + if (should_restart_tx(q) && + test_and_clear_bit(TXQ_OFLD, &qs->txq_stopped)) + goto again; + q->stops++; + break; + } + + gen = q->gen; + q->in_use += ndesc; + pidx = q->pidx; + q->pidx += ndesc; + if (q->pidx >= q->size) { + q->pidx -= q->size; + q->gen ^= 1; + } + __skb_unlink(skb, &q->sendq); + spin_unlock(&q->lock); + + write_ofld_wr(adap, skb, q, pidx, gen, ndesc); + spin_lock(&q->lock); + } + spin_unlock(&q->lock); + +#if USE_GTS + set_bit(TXQ_RUNNING, &q->flags); + set_bit(TXQ_LAST_PKT_DB, &q->flags); +#endif + t3_write_reg(adap, A_SG_KDOORBELL, + F_SELEGRCNTX | V_EGRCNTX(q->cntxt_id)); +} + +/** + * queue_set - return the queue set a packet should use + * @skb: the packet + * + * Maps a packet to the SGE queue set it should use. The desired queue + * set is carried in bits 1-3 in the packet's priority. + */ +static inline int queue_set(const struct sk_buff *skb) +{ + return skb->priority >> 1; +} + +/** + * is_ctrl_pkt - return whether an offload packet is a control packet + * @skb: the packet + * + * Determines whether an offload packet should use an OFLD or a CTRL + * Tx queue. This is indicated by bit 0 in the packet's priority. + */ +static inline int is_ctrl_pkt(const struct sk_buff *skb) +{ + return skb->priority & 1; +} + +/** + * t3_offload_tx - send an offload packet + * @tdev: the offload device to send to + * @skb: the packet + * + * Sends an offload packet. We use the packet priority to select the + * appropriate Tx queue as follows: bit 0 indicates whether the packet + * should be sent as regular or control, bits 1-3 select the queue set. + */ +int t3_offload_tx(struct t3cdev *tdev, struct sk_buff *skb) +{ + struct adapter *adap = tdev2adap(tdev); + struct sge_qset *qs = &adap->sge.qs[queue_set(skb)]; + + if (unlikely(is_ctrl_pkt(skb))) + return ctrl_xmit(adap, &qs->txq[TXQ_CTRL], skb); + + return ofld_xmit(adap, &qs->txq[TXQ_OFLD], skb); +} + +/** + * offload_enqueue - add an offload packet to an SGE offload receive queue + * @q: the SGE response queue + * @skb: the packet + * + * Add a new offload packet to an SGE response queue's offload packet + * queue. If the packet is the first on the queue it schedules the RX + * softirq to process the queue. + */ +static inline void offload_enqueue(struct sge_rspq *q, struct sk_buff *skb) +{ + skb->next = skb->prev = NULL; + if (q->rx_tail) + q->rx_tail->next = skb; + else { + struct sge_qset *qs = rspq_to_qset(q); + + if (__netif_rx_schedule_prep(qs->netdev)) + __netif_rx_schedule(qs->netdev); + q->rx_head = skb; + } + q->rx_tail = skb; +} + +/** + * deliver_partial_bundle - deliver a (partial) bundle of Rx offload pkts + * @tdev: the offload device that will be receiving the packets + * @q: the SGE response queue that assembled the bundle + * @skbs: the partial bundle + * @n: the number of packets in the bundle + * + * Delivers a (partial) bundle of Rx offload packets to an offload device. + */ +static inline void deliver_partial_bundle(struct t3cdev *tdev, + struct sge_rspq *q, + struct sk_buff *skbs[], int n) +{ + if (n) { + q->offload_bundles++; + tdev->recv(tdev, skbs, n); + } +} + +/** + * ofld_poll - NAPI handler for offload packets in interrupt mode + * @dev: the network device doing the polling + * @budget: polling budget + * + * The NAPI handler for offload packets when a response queue is serviced + * by the hard interrupt handler, i.e., when it's operating in non-polling + * mode. Creates small packet batches and sends them through the offload + * receive handler. Batches need to be of modest size as we do prefetches + * on the packets in each. + */ +static int ofld_poll(struct net_device *dev, int *budget) +{ + struct adapter *adapter = dev->priv; + struct sge_qset *qs = dev2qset(dev); + struct sge_rspq *q = &qs->rspq; + int work_done, limit = min(*budget, dev->quota), avail = limit; + + while (avail) { + struct sk_buff *head, *tail, *skbs[RX_BUNDLE_SIZE]; + int ngathered; + + spin_lock_irq(&q->lock); + head = q->rx_head; + if (!head) { + work_done = limit - avail; + *budget -= work_done; + dev->quota -= work_done; + __netif_rx_complete(dev); + spin_unlock_irq(&q->lock); + return 0; + } + + tail = q->rx_tail; + q->rx_head = q->rx_tail = NULL; + spin_unlock_irq(&q->lock); + + for (ngathered = 0; avail && head; avail--) { + prefetch(head->data); + skbs[ngathered] = head; + head = head->next; + skbs[ngathered]->next = NULL; + if (++ngathered == RX_BUNDLE_SIZE) { + q->offload_bundles++; + adapter->tdev.recv(&adapter->tdev, skbs, + ngathered); + ngathered = 0; + } + } + if (head) { /* splice remaining packets back onto Rx queue */ + spin_lock_irq(&q->lock); + tail->next = q->rx_head; + if (!q->rx_head) + q->rx_tail = tail; + q->rx_head = head; + spin_unlock_irq(&q->lock); + } + deliver_partial_bundle(&adapter->tdev, q, skbs, ngathered); + } + work_done = limit - avail; + *budget -= work_done; + dev->quota -= work_done; + return 1; +} + +/** + * rx_offload - process a received offload packet + * @tdev: the offload device receiving the packet + * @rq: the response queue that received the packet + * @skb: the packet + * @rx_gather: a gather list of packets if we are building a bundle + * @gather_idx: index of the next available slot in the bundle + * + * Process an ingress offload pakcet and add it to the offload ingress + * queue. Returns the index of the next available slot in the bundle. + */ +static inline int rx_offload(struct t3cdev *tdev, struct sge_rspq *rq, + struct sk_buff *skb, struct sk_buff *rx_gather[], + unsigned int gather_idx) +{ + rq->offload_pkts++; + skb->mac.raw = skb->nh.raw = skb->h.raw = skb->data; + + if (rq->polling) { + rx_gather[gather_idx++] = skb; + if (gather_idx == RX_BUNDLE_SIZE) { + tdev->recv(tdev, rx_gather, RX_BUNDLE_SIZE); + gather_idx = 0; + rq->offload_bundles++; + } + } else + offload_enqueue(rq, skb); + + return gather_idx; +} + +/** + * restart_tx - check whether to restart suspended Tx queues + * @qs: the queue set to resume + * + * Restarts suspended Tx queues of an SGE queue set if they have enough + * free resources to resume operation. + */ +static void restart_tx(struct sge_qset *qs) +{ + if (test_bit(TXQ_ETH, &qs->txq_stopped) && + should_restart_tx(&qs->txq[TXQ_ETH]) && + test_and_clear_bit(TXQ_ETH, &qs->txq_stopped)) { + qs->txq[TXQ_ETH].restarts++; + if (netif_running(qs->netdev)) + netif_wake_queue(qs->netdev); + } + + if (test_bit(TXQ_OFLD, &qs->txq_stopped) && + should_restart_tx(&qs->txq[TXQ_OFLD]) && + test_and_clear_bit(TXQ_OFLD, &qs->txq_stopped)) { + qs->txq[TXQ_OFLD].restarts++; + tasklet_schedule(&qs->txq[TXQ_OFLD].qresume_tsk); + } + if (test_bit(TXQ_CTRL, &qs->txq_stopped) && + should_restart_tx(&qs->txq[TXQ_CTRL]) && + test_and_clear_bit(TXQ_CTRL, &qs->txq_stopped)) { + qs->txq[TXQ_CTRL].restarts++; + tasklet_schedule(&qs->txq[TXQ_CTRL].qresume_tsk); + } +} + +/** + * rx_eth - process an ingress ethernet packet + * @adap: the adapter + * @rq: the response queue that received the packet + * @skb: the packet + * @pad: amount of padding at the start of the buffer + * + * Process an ingress ethernet pakcet and deliver it to the stack. + * The padding is 2 if the packet was delivered in an Rx buffer and 0 + * if it was immediate data in a response. + */ +static void rx_eth(struct adapter *adap, struct sge_rspq *rq, + struct sk_buff *skb, int pad) +{ + struct cpl_rx_pkt *p = (struct cpl_rx_pkt *)(skb->data + pad); + struct port_info *pi; + + rq->eth_pkts++; + skb_pull(skb, sizeof(*p) + pad); + skb->dev = adap->port[p->iff]; + skb->dev->last_rx = jiffies; + skb->protocol = eth_type_trans(skb, skb->dev); + pi = netdev_priv(skb->dev); + if (pi->rx_csum_offload && p->csum_valid && p->csum == 0xffff && + !p->fragment) { + rspq_to_qset(rq)->port_stats[SGE_PSTAT_RX_CSUM_GOOD]++; + skb->ip_summed = CHECKSUM_UNNECESSARY; + } else + skb->ip_summed = CHECKSUM_NONE; + + if (unlikely(p->vlan_valid)) { + struct vlan_group *grp = pi->vlan_grp; + + rspq_to_qset(rq)->port_stats[SGE_PSTAT_VLANEX]++; + if (likely(grp)) + __vlan_hwaccel_rx(skb, grp, ntohs(p->vlan), + rq->polling); + else + dev_kfree_skb_any(skb); + } else if (rq->polling) + netif_receive_skb(skb); + else + netif_rx(skb); +} + +/** + * handle_rsp_cntrl_info - handles control information in a response + * @qs: the queue set corresponding to the response + * @flags: the response control flags + * + * Handles the control information of an SGE response, such as GTS + * indications and completion credits for the queue set's Tx queues. + * HW coalesces credits, we don't do any extra SW coalescing. + */ +static inline void handle_rsp_cntrl_info(struct sge_qset *qs, u32 flags) +{ + unsigned int credits; + +#if USE_GTS + if (flags & F_RSPD_TXQ0_GTS) + clear_bit(TXQ_RUNNING, &qs->txq[TXQ_ETH].flags); +#endif + + credits = G_RSPD_TXQ0_CR(flags); + if (credits) + qs->txq[TXQ_ETH].processed += credits; + + credits = G_RSPD_TXQ2_CR(flags); + if (credits) + qs->txq[TXQ_CTRL].processed += credits; + +# if USE_GTS + if (flags & F_RSPD_TXQ1_GTS) + clear_bit(TXQ_RUNNING, &qs->txq[TXQ_OFLD].flags); +# endif + credits = G_RSPD_TXQ1_CR(flags); + if (credits) + qs->txq[TXQ_OFLD].processed += credits; +} + +/** + * check_ring_db - check if we need to ring any doorbells + * @adapter: the adapter + * @qs: the queue set whose Tx queues are to be examined + * @sleeping: indicates which Tx queue sent GTS + * + * Checks if some of a queue set's Tx queues need to ring their doorbells + * to resume transmission after idling while they still have unprocessed + * descriptors. + */ +static void check_ring_db(struct adapter *adap, struct sge_qset *qs, + unsigned int sleeping) +{ + if (sleeping & F_RSPD_TXQ0_GTS) { + struct sge_txq *txq = &qs->txq[TXQ_ETH]; + + if (txq->cleaned + txq->in_use != txq->processed && + !test_and_set_bit(TXQ_LAST_PKT_DB, &txq->flags)) { + set_bit(TXQ_RUNNING, &txq->flags); + t3_write_reg(adap, A_SG_KDOORBELL, F_SELEGRCNTX | + V_EGRCNTX(txq->cntxt_id)); + } + } + + if (sleeping & F_RSPD_TXQ1_GTS) { + struct sge_txq *txq = &qs->txq[TXQ_OFLD]; + + if (txq->cleaned + txq->in_use != txq->processed && + !test_and_set_bit(TXQ_LAST_PKT_DB, &txq->flags)) { + set_bit(TXQ_RUNNING, &txq->flags); + t3_write_reg(adap, A_SG_KDOORBELL, F_SELEGRCNTX | + V_EGRCNTX(txq->cntxt_id)); + } + } +} + +/** + * is_new_response - check if a response is newly written + * @r: the response descriptor + * @q: the response queue + * + * Returns true if a response descriptor contains a yet unprocessed + * response. + */ +static inline int is_new_response(const struct rsp_desc *r, + const struct sge_rspq *q) +{ + return (r->intr_gen & F_RSPD_GEN2) == q->gen; +} + +#define RSPD_GTS_MASK (F_RSPD_TXQ0_GTS | F_RSPD_TXQ1_GTS) +#define RSPD_CTRL_MASK (RSPD_GTS_MASK | \ + V_RSPD_TXQ0_CR(M_RSPD_TXQ0_CR) | \ + V_RSPD_TXQ1_CR(M_RSPD_TXQ1_CR) | \ + V_RSPD_TXQ2_CR(M_RSPD_TXQ2_CR)) + +/* How long to delay the next interrupt in case of memory shortage, in 0.1us. */ +#define NOMEM_INTR_DELAY 2500 + +/** + * process_responses - process responses from an SGE response queue + * @adap: the adapter + * @qs: the queue set to which the response queue belongs + * @budget: how many responses can be processed in this round + * + * Process responses from an SGE response queue up to the supplied budget. + * Responses include received packets as well as credits and other events + * for the queues that belong to the response queue's queue set. + * A negative budget is effectively unlimited. + * + * Additionally choose the interrupt holdoff time for the next interrupt + * on this queue. If the system is under memory shortage use a fairly + * long delay to help recovery. + */ +static int process_responses(struct adapter *adap, struct sge_qset *qs, + int budget) +{ + struct sge_rspq *q = &qs->rspq; + struct rsp_desc *r = &q->desc[q->cidx]; + int budget_left = budget; + unsigned int sleeping = 0; + struct sk_buff *offload_skbs[RX_BUNDLE_SIZE]; + int ngathered = 0; + + q->next_holdoff = q->holdoff_tmr; + + while (likely(budget_left && is_new_response(r, q))) { + int eth, ethpad = 0; + struct sk_buff *skb = NULL; + u32 len, flags = ntohl(r->flags); + u32 rss_hi = *(const u32 *)r, rss_lo = r->rss_hdr.rss_hash_val; + + eth = r->rss_hdr.opcode == CPL_RX_PKT; + + if (unlikely(flags & F_RSPD_ASYNC_NOTIF)) { + skb = alloc_skb(AN_PKT_SIZE, GFP_ATOMIC); + if (!skb) + goto no_mem; + + memcpy(__skb_put(skb, AN_PKT_SIZE), r, AN_PKT_SIZE); + skb->data[0] = CPL_ASYNC_NOTIF; + rss_hi = htonl(CPL_ASYNC_NOTIF << 24); + q->async_notif++; + } else if (flags & F_RSPD_IMM_DATA_VALID) { + skb = get_imm_packet(r); + if (unlikely(!skb)) { + no_mem: + q->next_holdoff = NOMEM_INTR_DELAY; + q->nomem++; + /* consume one credit since we tried */ + budget_left--; + break; + } + q->imm_data++; + } else if ((len = ntohl(r->len_cq)) != 0) { + struct sge_fl *fl; + + fl = (len & F_RSPD_FLQ) ? &qs->fl[1] : &qs->fl[0]; + fl->credits--; + skb = get_packet(adap, fl, G_RSPD_LEN(len), + eth ? SGE_RX_DROP_THRES : 0); + if (!skb) + q->rx_drops++; + else if (r->rss_hdr.opcode == CPL_TRACE_PKT) + __skb_pull(skb, 2); + ethpad = 2; + if (++fl->cidx == fl->size) + fl->cidx = 0; + } else + q->pure_rsps++; + + if (flags & RSPD_CTRL_MASK) { + sleeping |= flags & RSPD_GTS_MASK; + handle_rsp_cntrl_info(qs, flags); + } + + r++; + if (unlikely(++q->cidx == q->size)) { + q->cidx = 0; + q->gen ^= 1; + r = q->desc; + } + prefetch(r); + + if (++q->credits >= (q->size / 4)) { + refill_rspq(adap, q, q->credits); + q->credits = 0; + } + + if (likely(skb != NULL)) { + if (eth) + rx_eth(adap, q, skb, ethpad); + else { + /* Preserve the RSS info in csum & priority */ + skb->csum = rss_hi; + skb->priority = rss_lo; + ngathered = rx_offload(&adap->tdev, q, skb, + offload_skbs, ngathered); + } + } + + --budget_left; + } + + deliver_partial_bundle(&adap->tdev, q, offload_skbs, ngathered); + if (sleeping) + check_ring_db(adap, qs, sleeping); + + smp_mb(); /* commit Tx queue .processed updates */ + if (unlikely(qs->txq_stopped != 0)) + restart_tx(qs); + + budget -= budget_left; + return budget; +} + +static inline int is_pure_response(const struct rsp_desc *r) +{ + u32 n = ntohl(r->flags) & (F_RSPD_ASYNC_NOTIF | F_RSPD_IMM_DATA_VALID); + + return (n | r->len_cq) == 0; +} + +/** + * napi_rx_handler - the NAPI handler for Rx processing + * @dev: the net device + * @budget: how many packets we can process in this round + * + * Handler for new data events when using NAPI. + */ +static int napi_rx_handler(struct net_device *dev, int *budget) +{ + struct adapter *adap = dev->priv; + struct sge_qset *qs = dev2qset(dev); + int effective_budget = min(*budget, dev->quota); + + int work_done = process_responses(adap, qs, effective_budget); + *budget -= work_done; + dev->quota -= work_done; + + if (work_done >= effective_budget) + return 1; + + netif_rx_complete(dev); + + /* + * Because we don't atomically flush the following write it is + * possible that in very rare cases it can reach the device in a way + * that races with a new response being written plus an error interrupt + * causing the NAPI interrupt handler below to return unhandled status + * to the OS. To protect against this would require flushing the write + * and doing both the write and the flush with interrupts off. Way too + * expensive and unjustifiable given the rarity of the race. + * + * The race cannot happen at all with MSI-X. + */ + t3_write_reg(adap, A_SG_GTS, V_RSPQ(qs->rspq.cntxt_id) | + V_NEWTIMER(qs->rspq.next_holdoff) | + V_NEWINDEX(qs->rspq.cidx)); + return 0; +} + +/* + * Returns true if the device is already scheduled for polling. + */ +static inline int napi_is_scheduled(struct net_device *dev) +{ + return test_bit(__LINK_STATE_RX_SCHED, &dev->state); +} + +/** + * process_pure_responses - process pure responses from a response queue + * @adap: the adapter + * @qs: the queue set owning the response queue + * @r: the first pure response to process + * + * A simpler version of process_responses() that handles only pure (i.e., + * non data-carrying) responses. Such respones are too light-weight to + * justify calling a softirq under NAPI, so we handle them specially in + * the interrupt handler. The function is called with a pointer to a + * response, which the caller must ensure is a valid pure response. + * + * Returns 1 if it encounters a valid data-carrying response, 0 otherwise. + */ +static int process_pure_responses(struct adapter *adap, struct sge_qset *qs, + struct rsp_desc *r) +{ + struct sge_rspq *q = &qs->rspq; + unsigned int sleeping = 0; + + do { + u32 flags = ntohl(r->flags); + + r++; + if (unlikely(++q->cidx == q->size)) { + q->cidx = 0; + q->gen ^= 1; + r = q->desc; + } + prefetch(r); + + if (flags & RSPD_CTRL_MASK) { + sleeping |= flags & RSPD_GTS_MASK; + handle_rsp_cntrl_info(qs, flags); + } + + q->pure_rsps++; + if (++q->credits >= (q->size / 4)) { + refill_rspq(adap, q, q->credits); + q->credits = 0; + } + } while (is_new_response(r, q) && is_pure_response(r)); + + if (sleeping) + check_ring_db(adap, qs, sleeping); + + smp_mb(); /* commit Tx queue .processed updates */ + if (unlikely(qs->txq_stopped != 0)) + restart_tx(qs); + + return is_new_response(r, q); +} + +/** + * handle_responses - decide what to do with new responses in NAPI mode + * @adap: the adapter + * @q: the response queue + * + * This is used by the NAPI interrupt handlers to decide what to do with + * new SGE responses. If there are no new responses it returns -1. If + * there are new responses and they are pure (i.e., non-data carrying) + * it handles them straight in hard interrupt context as they are very + * cheap and don't deliver any packets. Finally, if there are any data + * signaling responses it schedules the NAPI handler. Returns 1 if it + * schedules NAPI, 0 if all new responses were pure. + * + * The caller must ascertain NAPI is not already running. + */ +static inline int handle_responses(struct adapter *adap, struct sge_rspq *q) +{ + struct sge_qset *qs = rspq_to_qset(q); + struct rsp_desc *r = &q->desc[q->cidx]; + + if (!is_new_response(r, q)) + return -1; + if (is_pure_response(r) && process_pure_responses(adap, qs, r) == 0) { + t3_write_reg(adap, A_SG_GTS, V_RSPQ(q->cntxt_id) | + V_NEWTIMER(q->holdoff_tmr) | V_NEWINDEX(q->cidx)); + return 0; + } + if (likely(__netif_rx_schedule_prep(qs->netdev))) + __netif_rx_schedule(qs->netdev); + return 1; +} + +/* + * The MSI-X interrupt handler for an SGE response queue for the non-NAPI case + * (i.e., response queue serviced in hard interrupt). + */ +irqreturn_t t3_sge_intr_msix(int irq, void *cookie) +{ + struct sge_qset *qs = cookie; + struct adapter *adap = qs->netdev->priv; + struct sge_rspq *q = &qs->rspq; + + spin_lock(&q->lock); + if (process_responses(adap, qs, -1) == 0) + q->unhandled_irqs++; + t3_write_reg(adap, A_SG_GTS, V_RSPQ(q->cntxt_id) | + V_NEWTIMER(q->next_holdoff) | V_NEWINDEX(q->cidx)); + spin_unlock(&q->lock); + return IRQ_HANDLED; +} + +/* + * The MSI-X interrupt handler for an SGE response queue for the NAPI case + * (i.e., response queue serviced by NAPI polling). + */ +irqreturn_t t3_sge_intr_msix_napi(int irq, void *cookie) +{ + struct sge_qset *qs = cookie; + struct adapter *adap = qs->netdev->priv; + struct sge_rspq *q = &qs->rspq; + + spin_lock(&q->lock); + BUG_ON(napi_is_scheduled(qs->netdev)); + + if (handle_responses(adap, q) < 0) + q->unhandled_irqs++; + spin_unlock(&q->lock); + return IRQ_HANDLED; +} + +/* + * The non-NAPI MSI interrupt handler. This needs to handle data events from + * SGE response queues as well as error and other async events as they all use + * the same MSI vector. We use one SGE response queue per port in this mode + * and protect all response queues with queue 0's lock. + */ +static irqreturn_t t3_intr_msi(int irq, void *cookie) +{ + int new_packets = 0; + struct adapter *adap = cookie; + struct sge_rspq *q = &adap->sge.qs[0].rspq; + + spin_lock(&q->lock); + + if (process_responses(adap, &adap->sge.qs[0], -1)) { + t3_write_reg(adap, A_SG_GTS, V_RSPQ(q->cntxt_id) | + V_NEWTIMER(q->next_holdoff) | V_NEWINDEX(q->cidx)); + new_packets = 1; + } + + if (adap->params.nports == 2 && + process_responses(adap, &adap->sge.qs[1], -1)) { + struct sge_rspq *q1 = &adap->sge.qs[1].rspq; + + t3_write_reg(adap, A_SG_GTS, V_RSPQ(q1->cntxt_id) | + V_NEWTIMER(q1->next_holdoff) | + V_NEWINDEX(q1->cidx)); + new_packets = 1; + } + + if (!new_packets && t3_slow_intr_handler(adap) == 0) + q->unhandled_irqs++; + + spin_unlock(&q->lock); + return IRQ_HANDLED; +} + +static int rspq_check_napi(struct net_device *dev, struct sge_rspq *q) +{ + if (!napi_is_scheduled(dev) && is_new_response(&q->desc[q->cidx], q)) { + if (likely(__netif_rx_schedule_prep(dev))) + __netif_rx_schedule(dev); + return 1; + } + return 0; +} + +/* + * The MSI interrupt handler for the NAPI case (i.e., response queues serviced + * by NAPI polling). Handles data events from SGE response queues as well as + * error and other async events as they all use the same MSI vector. We use + * one SGE response queue per port in this mode and protect all response + * queues with queue 0's lock. + */ +irqreturn_t t3_intr_msi_napi(int irq, void *cookie) +{ + int new_packets; + struct adapter *adap = cookie; + struct sge_rspq *q = &adap->sge.qs[0].rspq; + + spin_lock(&q->lock); + + new_packets = rspq_check_napi(adap->sge.qs[0].netdev, q); + if (adap->params.nports == 2) + new_packets += rspq_check_napi(adap->sge.qs[1].netdev, + &adap->sge.qs[1].rspq); + if (!new_packets && t3_slow_intr_handler(adap) == 0) + q->unhandled_irqs++; + + spin_unlock(&q->lock); + return IRQ_HANDLED; +} + +/* + * A helper function that processes responses and issues GTS. + */ +static inline int process_responses_gts(struct adapter *adap, + struct sge_rspq *rq) +{ + int work; + + work = process_responses(adap, rspq_to_qset(rq), -1); + t3_write_reg(adap, A_SG_GTS, V_RSPQ(rq->cntxt_id) | + V_NEWTIMER(rq->next_holdoff) | V_NEWINDEX(rq->cidx)); + return work; +} + +/* + * The legacy INTx interrupt handler. This needs to handle data events from + * SGE response queues as well as error and other async events as they all use + * the same interrupt pin. We use one SGE response queue per port in this mode + * and protect all response queues with queue 0's lock. + */ +static irqreturn_t t3_intr(int irq, void *cookie) +{ + int work_done, w0, w1; + struct adapter *adap = cookie; + struct sge_rspq *q0 = &adap->sge.qs[0].rspq; + struct sge_rspq *q1 = &adap->sge.qs[1].rspq; + + spin_lock(&q0->lock); + + w0 = is_new_response(&q0->desc[q0->cidx], q0); + w1 = adap->params.nports == 2 && + is_new_response(&q1->desc[q1->cidx], q1); + + if (likely(w0 | w1)) { + t3_write_reg(adap, A_PL_CLI, 0); + t3_read_reg(adap, A_PL_CLI); /* flush */ + + if (likely(w0)) + process_responses_gts(adap, q0); + + if (w1) + process_responses_gts(adap, q1); + + work_done = w0 | w1; + } else + work_done = t3_slow_intr_handler(adap); + + spin_unlock(&q0->lock); + return IRQ_RETVAL(work_done != 0); +} + +/* + * Interrupt handler for legacy INTx interrupts for T3B-based cards. + * Handles data events from SGE response queues as well as error and other + * async events as they all use the same interrupt pin. We use one SGE + * response queue per port in this mode and protect all response queues with + * queue 0's lock. + */ +static irqreturn_t t3b_intr(int irq, void *cookie) +{ + u32 map; + struct adapter *adap = cookie; + struct sge_rspq *q0 = &adap->sge.qs[0].rspq; + + t3_write_reg(adap, A_PL_CLI, 0); + map = t3_read_reg(adap, A_SG_DATA_INTR); + + if (unlikely(!map)) /* shared interrupt, most likely */ + return IRQ_NONE; + + spin_lock(&q0->lock); + + if (unlikely(map & F_ERRINTR)) + t3_slow_intr_handler(adap); + + if (likely(map & 1)) + process_responses_gts(adap, q0); + + if (map & 2) + process_responses_gts(adap, &adap->sge.qs[1].rspq); + + spin_unlock(&q0->lock); + return IRQ_HANDLED; +} + +/* + * NAPI interrupt handler for legacy INTx interrupts for T3B-based cards. + * Handles data events from SGE response queues as well as error and other + * async events as they all use the same interrupt pin. We use one SGE + * response queue per port in this mode and protect all response queues with + * queue 0's lock. + */ +static irqreturn_t t3b_intr_napi(int irq, void *cookie) +{ + u32 map; + struct net_device *dev; + struct adapter *adap = cookie; + struct sge_rspq *q0 = &adap->sge.qs[0].rspq; + + t3_write_reg(adap, A_PL_CLI, 0); + map = t3_read_reg(adap, A_SG_DATA_INTR); + + if (unlikely(!map)) /* shared interrupt, most likely */ + return IRQ_NONE; + + spin_lock(&q0->lock); + + if (unlikely(map & F_ERRINTR)) + t3_slow_intr_handler(adap); + + if (likely(map & 1)) { + dev = adap->sge.qs[0].netdev; + + if (likely(__netif_rx_schedule_prep(dev))) + __netif_rx_schedule(dev); + } + if (map & 2) { + dev = adap->sge.qs[1].netdev; + + if (likely(__netif_rx_schedule_prep(dev))) + __netif_rx_schedule(dev); + } + + spin_unlock(&q0->lock); + return IRQ_HANDLED; +} + +/** + * t3_intr_handler - select the top-level interrupt handler + * @adap: the adapter + * @polling: whether using NAPI to service response queues + * + * Selects the top-level interrupt handler based on the type of interrupts + * (MSI-X, MSI, or legacy) and whether NAPI will be used to service the + * response queues. + */ +intr_handler_t t3_intr_handler(struct adapter *adap, int polling) +{ + if (adap->flags & USING_MSIX) + return polling ? t3_sge_intr_msix_napi : t3_sge_intr_msix; + if (adap->flags & USING_MSI) + return polling ? t3_intr_msi_napi : t3_intr_msi; + if (adap->params.rev > 0) + return polling ? t3b_intr_napi : t3b_intr; + return t3_intr; +} + +/** + * t3_sge_err_intr_handler - SGE async event interrupt handler + * @adapter: the adapter + * + * Interrupt handler for SGE asynchronous (non-data) events. + */ +void t3_sge_err_intr_handler(struct adapter *adapter) +{ + unsigned int v, status = t3_read_reg(adapter, A_SG_INT_CAUSE); + + if (status & F_RSPQCREDITOVERFOW) + CH_ALERT(adapter, "SGE response queue credit overflow\n"); + + if (status & F_RSPQDISABLED) { + v = t3_read_reg(adapter, A_SG_RSPQ_FL_STATUS); + + CH_ALERT(adapter, + "packet delivered to disabled response queue " + "(0x%x)\n", (v >> S_RSPQ0DISABLED) & 0xff); + } + + t3_write_reg(adapter, A_SG_INT_CAUSE, status); + if (status & (F_RSPQCREDITOVERFOW | F_RSPQDISABLED)) + t3_fatal_err(adapter); +} + +/** + * sge_timer_cb - perform periodic maintenance of an SGE qset + * @data: the SGE queue set to maintain + * + * Runs periodically from a timer to perform maintenance of an SGE queue + * set. It performs two tasks: + * + * a) Cleans up any completed Tx descriptors that may still be pending. + * Normal descriptor cleanup happens when new packets are added to a Tx + * queue so this timer is relatively infrequent and does any cleanup only + * if the Tx queue has not seen any new packets in a while. We make a + * best effort attempt to reclaim descriptors, in that we don't wait + * around if we cannot get a queue's lock (which most likely is because + * someone else is queueing new packets and so will also handle the clean + * up). Since control queues use immediate data exclusively we don't + * bother cleaning them up here. + * + * b) Replenishes Rx queues that have run out due to memory shortage. + * Normally new Rx buffers are added when existing ones are consumed but + * when out of memory a queue can become empty. We try to add only a few + * buffers here, the queue will be replenished fully as these new buffers + * are used up if memory shortage has subsided. + */ +static void sge_timer_cb(unsigned long data) +{ + spinlock_t *lock; + struct sge_qset *qs = (struct sge_qset *)data; + struct adapter *adap = qs->netdev->priv; + + if (spin_trylock(&qs->txq[TXQ_ETH].lock)) { + reclaim_completed_tx(adap, &qs->txq[TXQ_ETH]); + spin_unlock(&qs->txq[TXQ_ETH].lock); + } + if (spin_trylock(&qs->txq[TXQ_OFLD].lock)) { + reclaim_completed_tx(adap, &qs->txq[TXQ_OFLD]); + spin_unlock(&qs->txq[TXQ_OFLD].lock); + } + lock = (adap->flags & USING_MSIX) ? &qs->rspq.lock : + &adap->sge.qs[0].rspq.lock; + if (spin_trylock_irq(lock)) { + if (!napi_is_scheduled(qs->netdev)) { + if (qs->fl[0].credits < qs->fl[0].size) + __refill_fl(adap, &qs->fl[0]); + if (qs->fl[1].credits < qs->fl[1].size) + __refill_fl(adap, &qs->fl[1]); + } + spin_unlock_irq(lock); + } + mod_timer(&qs->tx_reclaim_timer, jiffies + TX_RECLAIM_PERIOD); +} + +/** + * t3_update_qset_coalesce - update coalescing settings for a queue set + * @qs: the SGE queue set + * @p: new queue set parameters + * + * Update the coalescing settings for an SGE queue set. Nothing is done + * if the queue set is not initialized yet. + */ +void t3_update_qset_coalesce(struct sge_qset *qs, const struct qset_params *p) +{ + if (!qs->netdev) + return; + + qs->rspq.holdoff_tmr = max(p->coalesce_usecs * 10, 1U);/* can't be 0 */ + qs->rspq.polling = p->polling; + qs->netdev->poll = p->polling ? napi_rx_handler : ofld_poll; +} + +/** + * t3_sge_alloc_qset - initialize an SGE queue set + * @adapter: the adapter + * @id: the queue set id + * @nports: how many Ethernet ports will be using this queue set + * @irq_vec_idx: the IRQ vector index for response queue interrupts + * @p: configuration parameters for this queue set + * @ntxq: number of Tx queues for the queue set + * @netdev: net device associated with this queue set + * + * Allocate resources and initialize an SGE queue set. A queue set + * comprises a response queue, two Rx free-buffer queues, and up to 3 + * Tx queues. The Tx queues are assigned roles in the order Ethernet + * queue, offload queue, and control queue. + */ +int t3_sge_alloc_qset(struct adapter *adapter, unsigned int id, int nports, + int irq_vec_idx, const struct qset_params *p, + int ntxq, struct net_device *netdev) +{ + int i, ret = -ENOMEM; + struct sge_qset *q = &adapter->sge.qs[id]; + + init_qset_cntxt(q, id); + init_timer(&q->tx_reclaim_timer); + q->tx_reclaim_timer.data = (unsigned long)q; + q->tx_reclaim_timer.function = sge_timer_cb; + + q->fl[0].desc = alloc_ring(adapter->pdev, p->fl_size, + sizeof(struct rx_desc), + sizeof(struct rx_sw_desc), + &q->fl[0].phys_addr, &q->fl[0].sdesc); + if (!q->fl[0].desc) + goto err; + + q->fl[1].desc = alloc_ring(adapter->pdev, p->jumbo_size, + sizeof(struct rx_desc), + sizeof(struct rx_sw_desc), + &q->fl[1].phys_addr, &q->fl[1].sdesc); + if (!q->fl[1].desc) + goto err; + + q->rspq.desc = alloc_ring(adapter->pdev, p->rspq_size, + sizeof(struct rsp_desc), 0, + &q->rspq.phys_addr, NULL); + if (!q->rspq.desc) + goto err; + + for (i = 0; i < ntxq; ++i) { + /* + * The control queue always uses immediate data so does not + * need to keep track of any sk_buffs. + */ + size_t sz = i == TXQ_CTRL ? 0 : sizeof(struct tx_sw_desc); + + q->txq[i].desc = alloc_ring(adapter->pdev, p->txq_size[i], + sizeof(struct tx_desc), sz, + &q->txq[i].phys_addr, + &q->txq[i].sdesc); + if (!q->txq[i].desc) + goto err; + + q->txq[i].gen = 1; + q->txq[i].size = p->txq_size[i]; + spin_lock_init(&q->txq[i].lock); + skb_queue_head_init(&q->txq[i].sendq); + } + + tasklet_init(&q->txq[TXQ_OFLD].qresume_tsk, restart_offloadq, + (unsigned long)q); + tasklet_init(&q->txq[TXQ_CTRL].qresume_tsk, restart_ctrlq, + (unsigned long)q); + + q->fl[0].gen = q->fl[1].gen = 1; + q->fl[0].size = p->fl_size; + q->fl[1].size = p->jumbo_size; + + q->rspq.gen = 1; + q->rspq.size = p->rspq_size; + spin_lock_init(&q->rspq.lock); + + q->txq[TXQ_ETH].stop_thres = nports * + flits_to_desc(sgl_len(MAX_SKB_FRAGS + 1) + 3); + + if (ntxq == 1) { + q->fl[0].buf_size = SGE_RX_SM_BUF_SIZE + 2 + + sizeof(struct cpl_rx_pkt); + q->fl[1].buf_size = MAX_FRAME_SIZE + 2 + + sizeof(struct cpl_rx_pkt); + } else { + q->fl[0].buf_size = SGE_RX_SM_BUF_SIZE + + sizeof(struct cpl_rx_data); + q->fl[1].buf_size = (16 * 1024) - + SKB_DATA_ALIGN(sizeof(struct skb_shared_info)); + } + + spin_lock(&adapter->sge.reg_lock); + + /* FL threshold comparison uses < */ + ret = t3_sge_init_rspcntxt(adapter, q->rspq.cntxt_id, irq_vec_idx, + q->rspq.phys_addr, q->rspq.size, + q->fl[0].buf_size, 1, 0); + if (ret) + goto err_unlock; + + for (i = 0; i < SGE_RXQ_PER_SET; ++i) { + ret = t3_sge_init_flcntxt(adapter, q->fl[i].cntxt_id, 0, + q->fl[i].phys_addr, q->fl[i].size, + q->fl[i].buf_size, p->cong_thres, 1, + 0); + if (ret) + goto err_unlock; + } + + ret = t3_sge_init_ecntxt(adapter, q->txq[TXQ_ETH].cntxt_id, USE_GTS, + SGE_CNTXT_ETH, id, q->txq[TXQ_ETH].phys_addr, + q->txq[TXQ_ETH].size, q->txq[TXQ_ETH].token, + 1, 0); + if (ret) + goto err_unlock; + + if (ntxq > 1) { + ret = t3_sge_init_ecntxt(adapter, q->txq[TXQ_OFLD].cntxt_id, + USE_GTS, SGE_CNTXT_OFLD, id, + q->txq[TXQ_OFLD].phys_addr, + q->txq[TXQ_OFLD].size, 0, 1, 0); + if (ret) + goto err_unlock; + } + + if (ntxq > 2) { + ret = t3_sge_init_ecntxt(adapter, q->txq[TXQ_CTRL].cntxt_id, 0, + SGE_CNTXT_CTRL, id, + q->txq[TXQ_CTRL].phys_addr, + q->txq[TXQ_CTRL].size, + q->txq[TXQ_CTRL].token, 1, 0); + if (ret) + goto err_unlock; + } + + spin_unlock(&adapter->sge.reg_lock); + q->netdev = netdev; + t3_update_qset_coalesce(q, p); + + /* + * We use atalk_ptr as a backpointer to a qset. In case a device is + * associated with multiple queue sets only the first one sets + * atalk_ptr. + */ + if (netdev->atalk_ptr == NULL) + netdev->atalk_ptr = q; + + refill_fl(adapter, &q->fl[0], q->fl[0].size, GFP_KERNEL); + refill_fl(adapter, &q->fl[1], q->fl[1].size, GFP_KERNEL); + refill_rspq(adapter, &q->rspq, q->rspq.size - 1); + + t3_write_reg(adapter, A_SG_GTS, V_RSPQ(q->rspq.cntxt_id) | + V_NEWTIMER(q->rspq.holdoff_tmr)); + + mod_timer(&q->tx_reclaim_timer, jiffies + TX_RECLAIM_PERIOD); + return 0; + + err_unlock: + spin_unlock(&adapter->sge.reg_lock); + err: + t3_free_qset(adapter, q); + return ret; +} + +/** + * t3_free_sge_resources - free SGE resources + * @adap: the adapter + * + * Frees resources used by the SGE queue sets. + */ +void t3_free_sge_resources(struct adapter *adap) +{ + int i; + + for (i = 0; i < SGE_QSETS; ++i) + t3_free_qset(adap, &adap->sge.qs[i]); +} + +/** + * t3_sge_start - enable SGE + * @adap: the adapter + * + * Enables the SGE for DMAs. This is the last step in starting packet + * transfers. + */ +void t3_sge_start(struct adapter *adap) +{ + t3_set_reg_field(adap, A_SG_CONTROL, F_GLOBALENABLE, F_GLOBALENABLE); +} + +/** + * t3_sge_stop - disable SGE operation + * @adap: the adapter + * + * Disables the DMA engine. This can be called in emeregencies (e.g., + * from error interrupts) or from normal process context. In the latter + * case it also disables any pending queue restart tasklets. Note that + * if it is called in interrupt context it cannot disable the restart + * tasklets as it cannot wait, however the tasklets will have no effect + * since the doorbells are disabled and the driver will call this again + * later from process context, at which time the tasklets will be stopped + * if they are still running. + */ +void t3_sge_stop(struct adapter *adap) +{ + t3_set_reg_field(adap, A_SG_CONTROL, F_GLOBALENABLE, 0); + if (!in_interrupt()) { + int i; + + for (i = 0; i < SGE_QSETS; ++i) { + struct sge_qset *qs = &adap->sge.qs[i]; + + tasklet_kill(&qs->txq[TXQ_OFLD].qresume_tsk); + tasklet_kill(&qs->txq[TXQ_CTRL].qresume_tsk); + } + } +} + +/** + * t3_sge_init - initialize SGE + * @adap: the adapter + * @p: the SGE parameters + * + * Performs SGE initialization needed every time after a chip reset. + * We do not initialize any of the queue sets here, instead the driver + * top-level must request those individually. We also do not enable DMA + * here, that should be done after the queues have been set up. + */ +void t3_sge_init(struct adapter *adap, struct sge_params *p) +{ + unsigned int ctrl, ups = ffs(pci_resource_len(adap->pdev, 2) >> 12); + + ctrl = F_DROPPKT | V_PKTSHIFT(2) | F_FLMODE | F_AVOIDCQOVFL | + F_CQCRDTCTRL | + V_HOSTPAGESIZE(PAGE_SHIFT - 11) | F_BIGENDIANINGRESS | + V_USERSPACESIZE(ups ? ups - 1 : 0) | F_ISCSICOALESCING; +#if SGE_NUM_GENBITS == 1 + ctrl |= F_EGRGENCTRL; +#endif + if (adap->params.rev > 0) { + if (!(adap->flags & (USING_MSIX | USING_MSI))) + ctrl |= F_ONEINTMULTQ | F_OPTONEINTMULTQ; + ctrl |= F_CQCRDTCTRL | F_AVOIDCQOVFL; + } + t3_write_reg(adap, A_SG_CONTROL, ctrl); + t3_write_reg(adap, A_SG_EGR_RCQ_DRB_THRSH, V_HIRCQDRBTHRSH(512) | + V_LORCQDRBTHRSH(512)); + t3_write_reg(adap, A_SG_TIMER_TICK, core_ticks_per_usec(adap) / 10); + t3_write_reg(adap, A_SG_CMDQ_CREDIT_TH, V_THRESHOLD(32) | + V_TIMEOUT(200 * core_ticks_per_usec(adap))); + t3_write_reg(adap, A_SG_HI_DRB_HI_THRSH, 1000); + t3_write_reg(adap, A_SG_HI_DRB_LO_THRSH, 256); + t3_write_reg(adap, A_SG_LO_DRB_HI_THRSH, 1000); + t3_write_reg(adap, A_SG_LO_DRB_LO_THRSH, 256); + t3_write_reg(adap, A_SG_OCO_BASE, V_BASE1(0xfff)); + t3_write_reg(adap, A_SG_DRB_PRI_THRESH, 63 * 1024); +} + +/** + * t3_sge_prep - one-time SGE initialization + * @adap: the associated adapter + * @p: SGE parameters + * + * Performs one-time initialization of SGE SW state. Includes determining + * defaults for the assorted SGE parameters, which admins can change until + * they are used to initialize the SGE. + */ +void __devinit t3_sge_prep(struct adapter *adap, struct sge_params *p) +{ + int i; + + p->max_pkt_size = (16 * 1024) - sizeof(struct cpl_rx_data) - + SKB_DATA_ALIGN(sizeof(struct skb_shared_info)); + + for (i = 0; i < SGE_QSETS; ++i) { + struct qset_params *q = p->qset + i; + + q->polling = adap->params.rev > 0; + q->coalesce_usecs = 5; + q->rspq_size = 1024; + q->fl_size = 4096; + q->jumbo_size = 512; + q->txq_size[TXQ_ETH] = 1024; + q->txq_size[TXQ_OFLD] = 1024; + q->txq_size[TXQ_CTRL] = 256; + q->cong_thres = 0; + } + + spin_lock_init(&adap->sge.reg_lock); +} + +/** + * t3_get_desc - dump an SGE descriptor for debugging purposes + * @qs: the queue set + * @qnum: identifies the specific queue (0..2: Tx, 3:response, 4..5: Rx) + * @idx: the descriptor index in the queue + * @data: where to dump the descriptor contents + * + * Dumps the contents of a HW descriptor of an SGE queue. Returns the + * size of the descriptor. + */ +int t3_get_desc(const struct sge_qset *qs, unsigned int qnum, unsigned int idx, + unsigned char *data) +{ + if (qnum >= 6) + return -EINVAL; + + if (qnum < 3) { + if (!qs->txq[qnum].desc || idx >= qs->txq[qnum].size) + return -EINVAL; + memcpy(data, &qs->txq[qnum].desc[idx], sizeof(struct tx_desc)); + return sizeof(struct tx_desc); + } + + if (qnum == 3) { + if (!qs->rspq.desc || idx >= qs->rspq.size) + return -EINVAL; + memcpy(data, &qs->rspq.desc[idx], sizeof(struct rsp_desc)); + return sizeof(struct rsp_desc); + } + + qnum -= 4; + if (!qs->fl[qnum].desc || idx >= qs->fl[qnum].size) + return -EINVAL; + memcpy(data, &qs->fl[qnum].desc[idx], sizeof(struct rx_desc)); + return sizeof(struct rx_desc); +} diff --git a/drivers/net/cxgb3/sge_defs.h b/drivers/net/cxgb3/sge_defs.h new file mode 100644 index 0000000..514869e --- /dev/null +++ b/drivers/net/cxgb3/sge_defs.h @@ -0,0 +1,251 @@ +/* + * This file is automatically generated --- any changes will be lost. + */ + +#ifndef _SGE_DEFS_H +#define _SGE_DEFS_H + +#define S_EC_CREDITS 0 +#define M_EC_CREDITS 0x7FFF +#define V_EC_CREDITS(x) ((x) << S_EC_CREDITS) +#define G_EC_CREDITS(x) (((x) >> S_EC_CREDITS) & M_EC_CREDITS) + +#define S_EC_GTS 15 +#define V_EC_GTS(x) ((x) << S_EC_GTS) +#define F_EC_GTS V_EC_GTS(1U) + +#define S_EC_INDEX 16 +#define M_EC_INDEX 0xFFFF +#define V_EC_INDEX(x) ((x) << S_EC_INDEX) +#define G_EC_INDEX(x) (((x) >> S_EC_INDEX) & M_EC_INDEX) + +#define S_EC_SIZE 0 +#define M_EC_SIZE 0xFFFF +#define V_EC_SIZE(x) ((x) << S_EC_SIZE) +#define G_EC_SIZE(x) (((x) >> S_EC_SIZE) & M_EC_SIZE) + +#define S_EC_BASE_LO 16 +#define M_EC_BASE_LO 0xFFFF +#define V_EC_BASE_LO(x) ((x) << S_EC_BASE_LO) +#define G_EC_BASE_LO(x) (((x) >> S_EC_BASE_LO) & M_EC_BASE_LO) + +#define S_EC_BASE_HI 0 +#define M_EC_BASE_HI 0xF +#define V_EC_BASE_HI(x) ((x) << S_EC_BASE_HI) +#define G_EC_BASE_HI(x) (((x) >> S_EC_BASE_HI) & M_EC_BASE_HI) + +#define S_EC_RESPQ 4 +#define M_EC_RESPQ 0x7 +#define V_EC_RESPQ(x) ((x) << S_EC_RESPQ) +#define G_EC_RESPQ(x) (((x) >> S_EC_RESPQ) & M_EC_RESPQ) + +#define S_EC_TYPE 7 +#define M_EC_TYPE 0x7 +#define V_EC_TYPE(x) ((x) << S_EC_TYPE) +#define G_EC_TYPE(x) (((x) >> S_EC_TYPE) & M_EC_TYPE) + +#define S_EC_GEN 10 +#define V_EC_GEN(x) ((x) << S_EC_GEN) +#define F_EC_GEN V_EC_GEN(1U) + +#define S_EC_UP_TOKEN 11 +#define M_EC_UP_TOKEN 0xFFFFF +#define V_EC_UP_TOKEN(x) ((x) << S_EC_UP_TOKEN) +#define G_EC_UP_TOKEN(x) (((x) >> S_EC_UP_TOKEN) & M_EC_UP_TOKEN) + +#define S_EC_VALID 31 +#define V_EC_VALID(x) ((x) << S_EC_VALID) +#define F_EC_VALID V_EC_VALID(1U) + +#define S_RQ_MSI_VEC 20 +#define M_RQ_MSI_VEC 0x3F +#define V_RQ_MSI_VEC(x) ((x) << S_RQ_MSI_VEC) +#define G_RQ_MSI_VEC(x) (((x) >> S_RQ_MSI_VEC) & M_RQ_MSI_VEC) + +#define S_RQ_INTR_EN 26 +#define V_RQ_INTR_EN(x) ((x) << S_RQ_INTR_EN) +#define F_RQ_INTR_EN V_RQ_INTR_EN(1U) + +#define S_RQ_GEN 28 +#define V_RQ_GEN(x) ((x) << S_RQ_GEN) +#define F_RQ_GEN V_RQ_GEN(1U) + +#define S_CQ_INDEX 0 +#define M_CQ_INDEX 0xFFFF +#define V_CQ_INDEX(x) ((x) << S_CQ_INDEX) +#define G_CQ_INDEX(x) (((x) >> S_CQ_INDEX) & M_CQ_INDEX) + +#define S_CQ_SIZE 16 +#define M_CQ_SIZE 0xFFFF +#define V_CQ_SIZE(x) ((x) << S_CQ_SIZE) +#define G_CQ_SIZE(x) (((x) >> S_CQ_SIZE) & M_CQ_SIZE) + +#define S_CQ_BASE_HI 0 +#define M_CQ_BASE_HI 0xFFFFF +#define V_CQ_BASE_HI(x) ((x) << S_CQ_BASE_HI) +#define G_CQ_BASE_HI(x) (((x) >> S_CQ_BASE_HI) & M_CQ_BASE_HI) + +#define S_CQ_RSPQ 20 +#define M_CQ_RSPQ 0x3F +#define V_CQ_RSPQ(x) ((x) << S_CQ_RSPQ) +#define G_CQ_RSPQ(x) (((x) >> S_CQ_RSPQ) & M_CQ_RSPQ) + +#define S_CQ_ASYNC_NOTIF 26 +#define V_CQ_ASYNC_NOTIF(x) ((x) << S_CQ_ASYNC_NOTIF) +#define F_CQ_ASYNC_NOTIF V_CQ_ASYNC_NOTIF(1U) + +#define S_CQ_ARMED 27 +#define V_CQ_ARMED(x) ((x) << S_CQ_ARMED) +#define F_CQ_ARMED V_CQ_ARMED(1U) + +#define S_CQ_ASYNC_NOTIF_SOL 28 +#define V_CQ_ASYNC_NOTIF_SOL(x) ((x) << S_CQ_ASYNC_NOTIF_SOL) +#define F_CQ_ASYNC_NOTIF_SOL V_CQ_ASYNC_NOTIF_SOL(1U) + +#define S_CQ_GEN 29 +#define V_CQ_GEN(x) ((x) << S_CQ_GEN) +#define F_CQ_GEN V_CQ_GEN(1U) + +#define S_CQ_OVERFLOW_MODE 31 +#define V_CQ_OVERFLOW_MODE(x) ((x) << S_CQ_OVERFLOW_MODE) +#define F_CQ_OVERFLOW_MODE V_CQ_OVERFLOW_MODE(1U) + +#define S_CQ_CREDITS 0 +#define M_CQ_CREDITS 0xFFFF +#define V_CQ_CREDITS(x) ((x) << S_CQ_CREDITS) +#define G_CQ_CREDITS(x) (((x) >> S_CQ_CREDITS) & M_CQ_CREDITS) + +#define S_CQ_CREDIT_THRES 16 +#define M_CQ_CREDIT_THRES 0x1FFF +#define V_CQ_CREDIT_THRES(x) ((x) << S_CQ_CREDIT_THRES) +#define G_CQ_CREDIT_THRES(x) (((x) >> S_CQ_CREDIT_THRES) & M_CQ_CREDIT_THRES) + +#define S_FL_BASE_HI 0 +#define M_FL_BASE_HI 0xFFFFF +#define V_FL_BASE_HI(x) ((x) << S_FL_BASE_HI) +#define G_FL_BASE_HI(x) (((x) >> S_FL_BASE_HI) & M_FL_BASE_HI) + +#define S_FL_INDEX_LO 20 +#define M_FL_INDEX_LO 0xFFF +#define V_FL_INDEX_LO(x) ((x) << S_FL_INDEX_LO) +#define G_FL_INDEX_LO(x) (((x) >> S_FL_INDEX_LO) & M_FL_INDEX_LO) + +#define S_FL_INDEX_HI 0 +#define M_FL_INDEX_HI 0xF +#define V_FL_INDEX_HI(x) ((x) << S_FL_INDEX_HI) +#define G_FL_INDEX_HI(x) (((x) >> S_FL_INDEX_HI) & M_FL_INDEX_HI) + +#define S_FL_SIZE 4 +#define M_FL_SIZE 0xFFFF +#define V_FL_SIZE(x) ((x) << S_FL_SIZE) +#define G_FL_SIZE(x) (((x) >> S_FL_SIZE) & M_FL_SIZE) + +#define S_FL_GEN 20 +#define V_FL_GEN(x) ((x) << S_FL_GEN) +#define F_FL_GEN V_FL_GEN(1U) + +#define S_FL_ENTRY_SIZE_LO 21 +#define M_FL_ENTRY_SIZE_LO 0x7FF +#define V_FL_ENTRY_SIZE_LO(x) ((x) << S_FL_ENTRY_SIZE_LO) +#define G_FL_ENTRY_SIZE_LO(x) (((x) >> S_FL_ENTRY_SIZE_LO) & M_FL_ENTRY_SIZE_LO) + +#define S_FL_ENTRY_SIZE_HI 0 +#define M_FL_ENTRY_SIZE_HI 0x1FFFFF +#define V_FL_ENTRY_SIZE_HI(x) ((x) << S_FL_ENTRY_SIZE_HI) +#define G_FL_ENTRY_SIZE_HI(x) (((x) >> S_FL_ENTRY_SIZE_HI) & M_FL_ENTRY_SIZE_HI) + +#define S_FL_CONG_THRES 21 +#define M_FL_CONG_THRES 0x3FF +#define V_FL_CONG_THRES(x) ((x) << S_FL_CONG_THRES) +#define G_FL_CONG_THRES(x) (((x) >> S_FL_CONG_THRES) & M_FL_CONG_THRES) + +#define S_FL_GTS 31 +#define V_FL_GTS(x) ((x) << S_FL_GTS) +#define F_FL_GTS V_FL_GTS(1U) + +#define S_FLD_GEN1 31 +#define V_FLD_GEN1(x) ((x) << S_FLD_GEN1) +#define F_FLD_GEN1 V_FLD_GEN1(1U) + +#define S_FLD_GEN2 0 +#define V_FLD_GEN2(x) ((x) << S_FLD_GEN2) +#define F_FLD_GEN2 V_FLD_GEN2(1U) + +#define S_RSPD_TXQ1_CR 0 +#define M_RSPD_TXQ1_CR 0x7F +#define V_RSPD_TXQ1_CR(x) ((x) << S_RSPD_TXQ1_CR) +#define G_RSPD_TXQ1_CR(x) (((x) >> S_RSPD_TXQ1_CR) & M_RSPD_TXQ1_CR) + +#define S_RSPD_TXQ1_GTS 7 +#define V_RSPD_TXQ1_GTS(x) ((x) << S_RSPD_TXQ1_GTS) +#define F_RSPD_TXQ1_GTS V_RSPD_TXQ1_GTS(1U) + +#define S_RSPD_TXQ2_CR 8 +#define M_RSPD_TXQ2_CR 0x7F +#define V_RSPD_TXQ2_CR(x) ((x) << S_RSPD_TXQ2_CR) +#define G_RSPD_TXQ2_CR(x) (((x) >> S_RSPD_TXQ2_CR) & M_RSPD_TXQ2_CR) + +#define S_RSPD_TXQ2_GTS 15 +#define V_RSPD_TXQ2_GTS(x) ((x) << S_RSPD_TXQ2_GTS) +#define F_RSPD_TXQ2_GTS V_RSPD_TXQ2_GTS(1U) + +#define S_RSPD_TXQ0_CR 16 +#define M_RSPD_TXQ0_CR 0x7F +#define V_RSPD_TXQ0_CR(x) ((x) << S_RSPD_TXQ0_CR) +#define G_RSPD_TXQ0_CR(x) (((x) >> S_RSPD_TXQ0_CR) & M_RSPD_TXQ0_CR) + +#define S_RSPD_TXQ0_GTS 23 +#define V_RSPD_TXQ0_GTS(x) ((x) << S_RSPD_TXQ0_GTS) +#define F_RSPD_TXQ0_GTS V_RSPD_TXQ0_GTS(1U) + +#define S_RSPD_EOP 24 +#define V_RSPD_EOP(x) ((x) << S_RSPD_EOP) +#define F_RSPD_EOP V_RSPD_EOP(1U) + +#define S_RSPD_SOP 25 +#define V_RSPD_SOP(x) ((x) << S_RSPD_SOP) +#define F_RSPD_SOP V_RSPD_SOP(1U) + +#define S_RSPD_ASYNC_NOTIF 26 +#define V_RSPD_ASYNC_NOTIF(x) ((x) << S_RSPD_ASYNC_NOTIF) +#define F_RSPD_ASYNC_NOTIF V_RSPD_ASYNC_NOTIF(1U) + +#define S_RSPD_FL0_GTS 27 +#define V_RSPD_FL0_GTS(x) ((x) << S_RSPD_FL0_GTS) +#define F_RSPD_FL0_GTS V_RSPD_FL0_GTS(1U) + +#define S_RSPD_FL1_GTS 28 +#define V_RSPD_FL1_GTS(x) ((x) << S_RSPD_FL1_GTS) +#define F_RSPD_FL1_GTS V_RSPD_FL1_GTS(1U) + +#define S_RSPD_IMM_DATA_VALID 29 +#define V_RSPD_IMM_DATA_VALID(x) ((x) << S_RSPD_IMM_DATA_VALID) +#define F_RSPD_IMM_DATA_VALID V_RSPD_IMM_DATA_VALID(1U) + +#define S_RSPD_OFFLOAD 30 +#define V_RSPD_OFFLOAD(x) ((x) << S_RSPD_OFFLOAD) +#define F_RSPD_OFFLOAD V_RSPD_OFFLOAD(1U) + +#define S_RSPD_GEN1 31 +#define V_RSPD_GEN1(x) ((x) << S_RSPD_GEN1) +#define F_RSPD_GEN1 V_RSPD_GEN1(1U) + +#define S_RSPD_LEN 0 +#define M_RSPD_LEN 0x7FFFFFFF +#define V_RSPD_LEN(x) ((x) << S_RSPD_LEN) +#define G_RSPD_LEN(x) (((x) >> S_RSPD_LEN) & M_RSPD_LEN) + +#define S_RSPD_FLQ 31 +#define V_RSPD_FLQ(x) ((x) << S_RSPD_FLQ) +#define F_RSPD_FLQ V_RSPD_FLQ(1U) + +#define S_RSPD_GEN2 0 +#define V_RSPD_GEN2(x) ((x) << S_RSPD_GEN2) +#define F_RSPD_GEN2 V_RSPD_GEN2(1U) + +#define S_RSPD_INR_VEC 1 +#define M_RSPD_INR_VEC 0x7F +#define V_RSPD_INR_VEC(x) ((x) << S_RSPD_INR_VEC) +#define G_RSPD_INR_VEC(x) (((x) >> S_RSPD_INR_VEC) & M_RSPD_INR_VEC) + +#endif /* _SGE_DEFS_H */ diff --git a/drivers/net/cxgb3/t3_cpl.h b/drivers/net/cxgb3/t3_cpl.h new file mode 100644 index 0000000..b7a1a31 --- /dev/null +++ b/drivers/net/cxgb3/t3_cpl.h @@ -0,0 +1,1444 @@ +/* + * Copyright (c) 2004-2007 Chelsio, Inc. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +#ifndef T3_CPL_H +#define T3_CPL_H + +#if !defined(__LITTLE_ENDIAN_BITFIELD) && !defined(__BIG_ENDIAN_BITFIELD) +# include +#endif + +enum CPL_opcode { + CPL_PASS_OPEN_REQ = 0x1, + CPL_PASS_ACCEPT_RPL = 0x2, + CPL_ACT_OPEN_REQ = 0x3, + CPL_SET_TCB = 0x4, + CPL_SET_TCB_FIELD = 0x5, + CPL_GET_TCB = 0x6, + CPL_PCMD = 0x7, + CPL_CLOSE_CON_REQ = 0x8, + CPL_CLOSE_LISTSRV_REQ = 0x9, + CPL_ABORT_REQ = 0xA, + CPL_ABORT_RPL = 0xB, + CPL_TX_DATA = 0xC, + CPL_RX_DATA_ACK = 0xD, + CPL_TX_PKT = 0xE, + CPL_RTE_DELETE_REQ = 0xF, + CPL_RTE_WRITE_REQ = 0x10, + CPL_RTE_READ_REQ = 0x11, + CPL_L2T_WRITE_REQ = 0x12, + CPL_L2T_READ_REQ = 0x13, + CPL_SMT_WRITE_REQ = 0x14, + CPL_SMT_READ_REQ = 0x15, + CPL_TX_PKT_LSO = 0x16, + CPL_PCMD_READ = 0x17, + CPL_BARRIER = 0x18, + CPL_TID_RELEASE = 0x1A, + + CPL_CLOSE_LISTSRV_RPL = 0x20, + CPL_ERROR = 0x21, + CPL_GET_TCB_RPL = 0x22, + CPL_L2T_WRITE_RPL = 0x23, + CPL_PCMD_READ_RPL = 0x24, + CPL_PCMD_RPL = 0x25, + CPL_PEER_CLOSE = 0x26, + CPL_RTE_DELETE_RPL = 0x27, + CPL_RTE_WRITE_RPL = 0x28, + CPL_RX_DDP_COMPLETE = 0x29, + CPL_RX_PHYS_ADDR = 0x2A, + CPL_RX_PKT = 0x2B, + CPL_RX_URG_NOTIFY = 0x2C, + CPL_SET_TCB_RPL = 0x2D, + CPL_SMT_WRITE_RPL = 0x2E, + CPL_TX_DATA_ACK = 0x2F, + + CPL_ABORT_REQ_RSS = 0x30, + CPL_ABORT_RPL_RSS = 0x31, + CPL_CLOSE_CON_RPL = 0x32, + CPL_ISCSI_HDR = 0x33, + CPL_L2T_READ_RPL = 0x34, + CPL_RDMA_CQE = 0x35, + CPL_RDMA_CQE_READ_RSP = 0x36, + CPL_RDMA_CQE_ERR = 0x37, + CPL_RTE_READ_RPL = 0x38, + CPL_RX_DATA = 0x39, + + CPL_ACT_OPEN_RPL = 0x40, + CPL_PASS_OPEN_RPL = 0x41, + CPL_RX_DATA_DDP = 0x42, + CPL_SMT_READ_RPL = 0x43, + + CPL_ACT_ESTABLISH = 0x50, + CPL_PASS_ESTABLISH = 0x51, + + CPL_PASS_ACCEPT_REQ = 0x70, + + CPL_ASYNC_NOTIF = 0x80, /* fake opcode for async notifications */ + + CPL_TX_DMA_ACK = 0xA0, + CPL_RDMA_READ_REQ = 0xA1, + CPL_RDMA_TERMINATE = 0xA2, + CPL_TRACE_PKT = 0xA3, + CPL_RDMA_EC_STATUS = 0xA5, + + NUM_CPL_CMDS /* must be last and previous entries must be sorted */ +}; + +enum CPL_error { + CPL_ERR_NONE = 0, + CPL_ERR_TCAM_PARITY = 1, + CPL_ERR_TCAM_FULL = 3, + CPL_ERR_CONN_RESET = 20, + CPL_ERR_CONN_EXIST = 22, + CPL_ERR_ARP_MISS = 23, + CPL_ERR_BAD_SYN = 24, + CPL_ERR_CONN_TIMEDOUT = 30, + CPL_ERR_XMIT_TIMEDOUT = 31, + CPL_ERR_PERSIST_TIMEDOUT = 32, + CPL_ERR_FINWAIT2_TIMEDOUT = 33, + CPL_ERR_KEEPALIVE_TIMEDOUT = 34, + CPL_ERR_RTX_NEG_ADVICE = 35, + CPL_ERR_PERSIST_NEG_ADVICE = 36, + CPL_ERR_ABORT_FAILED = 42, + CPL_ERR_GENERAL = 99 +}; + +enum { + CPL_CONN_POLICY_AUTO = 0, + CPL_CONN_POLICY_ASK = 1, + CPL_CONN_POLICY_DENY = 3 +}; + +enum { + ULP_MODE_NONE = 0, + ULP_MODE_ISCSI = 2, + ULP_MODE_RDMA = 4, + ULP_MODE_TCPDDP = 5 +}; + +enum { + ULP_CRC_HEADER = 1 << 0, + ULP_CRC_DATA = 1 << 1 +}; + +enum { + CPL_PASS_OPEN_ACCEPT, + CPL_PASS_OPEN_REJECT +}; + +enum { + CPL_ABORT_SEND_RST = 0, + CPL_ABORT_NO_RST, + CPL_ABORT_POST_CLOSE_REQ = 2 +}; + +enum { /* TX_PKT_LSO ethernet types */ + CPL_ETH_II, + CPL_ETH_II_VLAN, + CPL_ETH_802_3, + CPL_ETH_802_3_VLAN +}; + +enum { /* TCP congestion control algorithms */ + CONG_ALG_RENO, + CONG_ALG_TAHOE, + CONG_ALG_NEWRENO, + CONG_ALG_HIGHSPEED +}; + +union opcode_tid { + __be32 opcode_tid; + __u8 opcode; +}; + +#define S_OPCODE 24 +#define V_OPCODE(x) ((x) << S_OPCODE) +#define G_OPCODE(x) (((x) >> S_OPCODE) & 0xFF) +#define G_TID(x) ((x) & 0xFFFFFF) + +/* tid is assumed to be 24-bits */ +#define MK_OPCODE_TID(opcode, tid) (V_OPCODE(opcode) | (tid)) + +#define OPCODE_TID(cmd) ((cmd)->ot.opcode_tid) + +/* extract the TID from a CPL command */ +#define GET_TID(cmd) (G_TID(ntohl(OPCODE_TID(cmd)))) + +struct tcp_options { + __be16 mss; + __u8 wsf; +#if defined(__LITTLE_ENDIAN_BITFIELD) + __u8:5; + __u8 ecn:1; + __u8 sack:1; + __u8 tstamp:1; +#else + __u8 tstamp:1; + __u8 sack:1; + __u8 ecn:1; + __u8:5; +#endif +}; + +struct rss_header { + __u8 opcode; +#if defined(__LITTLE_ENDIAN_BITFIELD) + __u8 cpu_idx:6; + __u8 hash_type:2; +#else + __u8 hash_type:2; + __u8 cpu_idx:6; +#endif + __be16 cq_idx; + __be32 rss_hash_val; +}; + +#ifndef CHELSIO_FW +struct work_request_hdr { + __be32 wr_hi; + __be32 wr_lo; +}; + +/* wr_hi fields */ +#define S_WR_SGE_CREDITS 0 +#define M_WR_SGE_CREDITS 0xFF +#define V_WR_SGE_CREDITS(x) ((x) << S_WR_SGE_CREDITS) +#define G_WR_SGE_CREDITS(x) (((x) >> S_WR_SGE_CREDITS) & M_WR_SGE_CREDITS) + +#define S_WR_SGLSFLT 8 +#define M_WR_SGLSFLT 0xFF +#define V_WR_SGLSFLT(x) ((x) << S_WR_SGLSFLT) +#define G_WR_SGLSFLT(x) (((x) >> S_WR_SGLSFLT) & M_WR_SGLSFLT) + +#define S_WR_BCNTLFLT 16 +#define M_WR_BCNTLFLT 0xF +#define V_WR_BCNTLFLT(x) ((x) << S_WR_BCNTLFLT) +#define G_WR_BCNTLFLT(x) (((x) >> S_WR_BCNTLFLT) & M_WR_BCNTLFLT) + +#define S_WR_DATATYPE 20 +#define V_WR_DATATYPE(x) ((x) << S_WR_DATATYPE) +#define F_WR_DATATYPE V_WR_DATATYPE(1U) + +#define S_WR_COMPL 21 +#define V_WR_COMPL(x) ((x) << S_WR_COMPL) +#define F_WR_COMPL V_WR_COMPL(1U) + +#define S_WR_EOP 22 +#define V_WR_EOP(x) ((x) << S_WR_EOP) +#define F_WR_EOP V_WR_EOP(1U) + +#define S_WR_SOP 23 +#define V_WR_SOP(x) ((x) << S_WR_SOP) +#define F_WR_SOP V_WR_SOP(1U) + +#define S_WR_OP 24 +#define M_WR_OP 0xFF +#define V_WR_OP(x) ((x) << S_WR_OP) +#define G_WR_OP(x) (((x) >> S_WR_OP) & M_WR_OP) + +/* wr_lo fields */ +#define S_WR_LEN 0 +#define M_WR_LEN 0xFF +#define V_WR_LEN(x) ((x) << S_WR_LEN) +#define G_WR_LEN(x) (((x) >> S_WR_LEN) & M_WR_LEN) + +#define S_WR_TID 8 +#define M_WR_TID 0xFFFFF +#define V_WR_TID(x) ((x) << S_WR_TID) +#define G_WR_TID(x) (((x) >> S_WR_TID) & M_WR_TID) + +#define S_WR_CR_FLUSH 30 +#define V_WR_CR_FLUSH(x) ((x) << S_WR_CR_FLUSH) +#define F_WR_CR_FLUSH V_WR_CR_FLUSH(1U) + +#define S_WR_GEN 31 +#define V_WR_GEN(x) ((x) << S_WR_GEN) +#define F_WR_GEN V_WR_GEN(1U) + +# define WR_HDR struct work_request_hdr wr +# define RSS_HDR +#else +# define WR_HDR +# define RSS_HDR struct rss_header rss_hdr; +#endif + +/* option 0 lower-half fields */ +#define S_CPL_STATUS 0 +#define M_CPL_STATUS 0xFF +#define V_CPL_STATUS(x) ((x) << S_CPL_STATUS) +#define G_CPL_STATUS(x) (((x) >> S_CPL_STATUS) & M_CPL_STATUS) + +#define S_INJECT_TIMER 6 +#define V_INJECT_TIMER(x) ((x) << S_INJECT_TIMER) +#define F_INJECT_TIMER V_INJECT_TIMER(1U) + +#define S_NO_OFFLOAD 7 +#define V_NO_OFFLOAD(x) ((x) << S_NO_OFFLOAD) +#define F_NO_OFFLOAD V_NO_OFFLOAD(1U) + +#define S_ULP_MODE 8 +#define M_ULP_MODE 0xF +#define V_ULP_MODE(x) ((x) << S_ULP_MODE) +#define G_ULP_MODE(x) (((x) >> S_ULP_MODE) & M_ULP_MODE) + +#define S_RCV_BUFSIZ 12 +#define M_RCV_BUFSIZ 0x3FFF +#define V_RCV_BUFSIZ(x) ((x) << S_RCV_BUFSIZ) +#define G_RCV_BUFSIZ(x) (((x) >> S_RCV_BUFSIZ) & M_RCV_BUFSIZ) + +#define S_TOS 26 +#define M_TOS 0x3F +#define V_TOS(x) ((x) << S_TOS) +#define G_TOS(x) (((x) >> S_TOS) & M_TOS) + +/* option 0 upper-half fields */ +#define S_DELACK 0 +#define V_DELACK(x) ((x) << S_DELACK) +#define F_DELACK V_DELACK(1U) + +#define S_NO_CONG 1 +#define V_NO_CONG(x) ((x) << S_NO_CONG) +#define F_NO_CONG V_NO_CONG(1U) + +#define S_SRC_MAC_SEL 2 +#define M_SRC_MAC_SEL 0x3 +#define V_SRC_MAC_SEL(x) ((x) << S_SRC_MAC_SEL) +#define G_SRC_MAC_SEL(x) (((x) >> S_SRC_MAC_SEL) & M_SRC_MAC_SEL) + +#define S_L2T_IDX 4 +#define M_L2T_IDX 0x7FF +#define V_L2T_IDX(x) ((x) << S_L2T_IDX) +#define G_L2T_IDX(x) (((x) >> S_L2T_IDX) & M_L2T_IDX) + +#define S_TX_CHANNEL 15 +#define V_TX_CHANNEL(x) ((x) << S_TX_CHANNEL) +#define F_TX_CHANNEL V_TX_CHANNEL(1U) + +#define S_TCAM_BYPASS 16 +#define V_TCAM_BYPASS(x) ((x) << S_TCAM_BYPASS) +#define F_TCAM_BYPASS V_TCAM_BYPASS(1U) + +#define S_NAGLE 17 +#define V_NAGLE(x) ((x) << S_NAGLE) +#define F_NAGLE V_NAGLE(1U) + +#define S_WND_SCALE 18 +#define M_WND_SCALE 0xF +#define V_WND_SCALE(x) ((x) << S_WND_SCALE) +#define G_WND_SCALE(x) (((x) >> S_WND_SCALE) & M_WND_SCALE) + +#define S_KEEP_ALIVE 22 +#define V_KEEP_ALIVE(x) ((x) << S_KEEP_ALIVE) +#define F_KEEP_ALIVE V_KEEP_ALIVE(1U) + +#define S_MAX_RETRANS 23 +#define M_MAX_RETRANS 0xF +#define V_MAX_RETRANS(x) ((x) << S_MAX_RETRANS) +#define G_MAX_RETRANS(x) (((x) >> S_MAX_RETRANS) & M_MAX_RETRANS) + +#define S_MAX_RETRANS_OVERRIDE 27 +#define V_MAX_RETRANS_OVERRIDE(x) ((x) << S_MAX_RETRANS_OVERRIDE) +#define F_MAX_RETRANS_OVERRIDE V_MAX_RETRANS_OVERRIDE(1U) + +#define S_MSS_IDX 28 +#define M_MSS_IDX 0xF +#define V_MSS_IDX(x) ((x) << S_MSS_IDX) +#define G_MSS_IDX(x) (((x) >> S_MSS_IDX) & M_MSS_IDX) + +/* option 1 fields */ +#define S_RSS_ENABLE 0 +#define V_RSS_ENABLE(x) ((x) << S_RSS_ENABLE) +#define F_RSS_ENABLE V_RSS_ENABLE(1U) + +#define S_RSS_MASK_LEN 1 +#define M_RSS_MASK_LEN 0x7 +#define V_RSS_MASK_LEN(x) ((x) << S_RSS_MASK_LEN) +#define G_RSS_MASK_LEN(x) (((x) >> S_RSS_MASK_LEN) & M_RSS_MASK_LEN) + +#define S_CPU_IDX 4 +#define M_CPU_IDX 0x3F +#define V_CPU_IDX(x) ((x) << S_CPU_IDX) +#define G_CPU_IDX(x) (((x) >> S_CPU_IDX) & M_CPU_IDX) + +#define S_MAC_MATCH_VALID 18 +#define V_MAC_MATCH_VALID(x) ((x) << S_MAC_MATCH_VALID) +#define F_MAC_MATCH_VALID V_MAC_MATCH_VALID(1U) + +#define S_CONN_POLICY 19 +#define M_CONN_POLICY 0x3 +#define V_CONN_POLICY(x) ((x) << S_CONN_POLICY) +#define G_CONN_POLICY(x) (((x) >> S_CONN_POLICY) & M_CONN_POLICY) + +#define S_SYN_DEFENSE 21 +#define V_SYN_DEFENSE(x) ((x) << S_SYN_DEFENSE) +#define F_SYN_DEFENSE V_SYN_DEFENSE(1U) + +#define S_VLAN_PRI 22 +#define M_VLAN_PRI 0x3 +#define V_VLAN_PRI(x) ((x) << S_VLAN_PRI) +#define G_VLAN_PRI(x) (((x) >> S_VLAN_PRI) & M_VLAN_PRI) + +#define S_VLAN_PRI_VALID 24 +#define V_VLAN_PRI_VALID(x) ((x) << S_VLAN_PRI_VALID) +#define F_VLAN_PRI_VALID V_VLAN_PRI_VALID(1U) + +#define S_PKT_TYPE 25 +#define M_PKT_TYPE 0x3 +#define V_PKT_TYPE(x) ((x) << S_PKT_TYPE) +#define G_PKT_TYPE(x) (((x) >> S_PKT_TYPE) & M_PKT_TYPE) + +#define S_MAC_MATCH 27 +#define M_MAC_MATCH 0x1F +#define V_MAC_MATCH(x) ((x) << S_MAC_MATCH) +#define G_MAC_MATCH(x) (((x) >> S_MAC_MATCH) & M_MAC_MATCH) + +/* option 2 fields */ +#define S_CPU_INDEX 0 +#define M_CPU_INDEX 0x7F +#define V_CPU_INDEX(x) ((x) << S_CPU_INDEX) +#define G_CPU_INDEX(x) (((x) >> S_CPU_INDEX) & M_CPU_INDEX) + +#define S_CPU_INDEX_VALID 7 +#define V_CPU_INDEX_VALID(x) ((x) << S_CPU_INDEX_VALID) +#define F_CPU_INDEX_VALID V_CPU_INDEX_VALID(1U) + +#define S_RX_COALESCE 8 +#define M_RX_COALESCE 0x3 +#define V_RX_COALESCE(x) ((x) << S_RX_COALESCE) +#define G_RX_COALESCE(x) (((x) >> S_RX_COALESCE) & M_RX_COALESCE) + +#define S_RX_COALESCE_VALID 10 +#define V_RX_COALESCE_VALID(x) ((x) << S_RX_COALESCE_VALID) +#define F_RX_COALESCE_VALID V_RX_COALESCE_VALID(1U) + +#define S_CONG_CONTROL_FLAVOR 11 +#define M_CONG_CONTROL_FLAVOR 0x3 +#define V_CONG_CONTROL_FLAVOR(x) ((x) << S_CONG_CONTROL_FLAVOR) +#define G_CONG_CONTROL_FLAVOR(x) (((x) >> S_CONG_CONTROL_FLAVOR) & M_CONG_CONTROL_FLAVOR) + +#define S_PACING_FLAVOR 13 +#define M_PACING_FLAVOR 0x3 +#define V_PACING_FLAVOR(x) ((x) << S_PACING_FLAVOR) +#define G_PACING_FLAVOR(x) (((x) >> S_PACING_FLAVOR) & M_PACING_FLAVOR) + +#define S_FLAVORS_VALID 15 +#define V_FLAVORS_VALID(x) ((x) << S_FLAVORS_VALID) +#define F_FLAVORS_VALID V_FLAVORS_VALID(1U) + +#define S_RX_FC_DISABLE 16 +#define V_RX_FC_DISABLE(x) ((x) << S_RX_FC_DISABLE) +#define F_RX_FC_DISABLE V_RX_FC_DISABLE(1U) + +#define S_RX_FC_VALID 17 +#define V_RX_FC_VALID(x) ((x) << S_RX_FC_VALID) +#define F_RX_FC_VALID V_RX_FC_VALID(1U) + +struct cpl_pass_open_req { + WR_HDR; + union opcode_tid ot; + __be16 local_port; + __be16 peer_port; + __be32 local_ip; + __be32 peer_ip; + __be32 opt0h; + __be32 opt0l; + __be32 peer_netmask; + __be32 opt1; +}; + +struct cpl_pass_open_rpl { + RSS_HDR union opcode_tid ot; + __be16 local_port; + __be16 peer_port; + __be32 local_ip; + __be32 peer_ip; + __u8 resvd[7]; + __u8 status; +}; + +struct cpl_pass_establish { + RSS_HDR union opcode_tid ot; + __be16 local_port; + __be16 peer_port; + __be32 local_ip; + __be32 peer_ip; + __be32 tos_tid; + __be16 l2t_idx; + __be16 tcp_opt; + __be32 snd_isn; + __be32 rcv_isn; +}; + +/* cpl_pass_establish.tos_tid fields */ +#define S_PASS_OPEN_TID 0 +#define M_PASS_OPEN_TID 0xFFFFFF +#define V_PASS_OPEN_TID(x) ((x) << S_PASS_OPEN_TID) +#define G_PASS_OPEN_TID(x) (((x) >> S_PASS_OPEN_TID) & M_PASS_OPEN_TID) + +#define S_PASS_OPEN_TOS 24 +#define M_PASS_OPEN_TOS 0xFF +#define V_PASS_OPEN_TOS(x) ((x) << S_PASS_OPEN_TOS) +#define G_PASS_OPEN_TOS(x) (((x) >> S_PASS_OPEN_TOS) & M_PASS_OPEN_TOS) + +/* cpl_pass_establish.l2t_idx fields */ +#define S_L2T_IDX16 5 +#define M_L2T_IDX16 0x7FF +#define V_L2T_IDX16(x) ((x) << S_L2T_IDX16) +#define G_L2T_IDX16(x) (((x) >> S_L2T_IDX16) & M_L2T_IDX16) + +/* cpl_pass_establish.tcp_opt fields (also applies act_open_establish) */ +#define G_TCPOPT_WSCALE_OK(x) (((x) >> 5) & 1) +#define G_TCPOPT_SACK(x) (((x) >> 6) & 1) +#define G_TCPOPT_TSTAMP(x) (((x) >> 7) & 1) +#define G_TCPOPT_SND_WSCALE(x) (((x) >> 8) & 0xf) +#define G_TCPOPT_MSS(x) (((x) >> 12) & 0xf) + +struct cpl_pass_accept_req { + RSS_HDR union opcode_tid ot; + __be16 local_port; + __be16 peer_port; + __be32 local_ip; + __be32 peer_ip; + __be32 tos_tid; + struct tcp_options tcp_options; + __u8 dst_mac[6]; + __be16 vlan_tag; + __u8 src_mac[6]; +#if defined(__LITTLE_ENDIAN_BITFIELD) + __u8:3; + __u8 addr_idx:3; + __u8 port_idx:1; + __u8 exact_match:1; +#else + __u8 exact_match:1; + __u8 port_idx:1; + __u8 addr_idx:3; + __u8:3; +#endif + __u8 rsvd; + __be32 rcv_isn; + __be32 rsvd2; +}; + +struct cpl_pass_accept_rpl { + WR_HDR; + union opcode_tid ot; + __be32 opt2; + __be32 rsvd; + __be32 peer_ip; + __be32 opt0h; + __be32 opt0l_status; +}; + +struct cpl_act_open_req { + WR_HDR; + union opcode_tid ot; + __be16 local_port; + __be16 peer_port; + __be32 local_ip; + __be32 peer_ip; + __be32 opt0h; + __be32 opt0l; + __be32 params; + __be32 opt2; +}; + +/* cpl_act_open_req.params fields */ +#define S_AOPEN_VLAN_PRI 9 +#define M_AOPEN_VLAN_PRI 0x3 +#define V_AOPEN_VLAN_PRI(x) ((x) << S_AOPEN_VLAN_PRI) +#define G_AOPEN_VLAN_PRI(x) (((x) >> S_AOPEN_VLAN_PRI) & M_AOPEN_VLAN_PRI) + +#define S_AOPEN_VLAN_PRI_VALID 11 +#define V_AOPEN_VLAN_PRI_VALID(x) ((x) << S_AOPEN_VLAN_PRI_VALID) +#define F_AOPEN_VLAN_PRI_VALID V_AOPEN_VLAN_PRI_VALID(1U) + +#define S_AOPEN_PKT_TYPE 12 +#define M_AOPEN_PKT_TYPE 0x3 +#define V_AOPEN_PKT_TYPE(x) ((x) << S_AOPEN_PKT_TYPE) +#define G_AOPEN_PKT_TYPE(x) (((x) >> S_AOPEN_PKT_TYPE) & M_AOPEN_PKT_TYPE) + +#define S_AOPEN_MAC_MATCH 14 +#define M_AOPEN_MAC_MATCH 0x1F +#define V_AOPEN_MAC_MATCH(x) ((x) << S_AOPEN_MAC_MATCH) +#define G_AOPEN_MAC_MATCH(x) (((x) >> S_AOPEN_MAC_MATCH) & M_AOPEN_MAC_MATCH) + +#define S_AOPEN_MAC_MATCH_VALID 19 +#define V_AOPEN_MAC_MATCH_VALID(x) ((x) << S_AOPEN_MAC_MATCH_VALID) +#define F_AOPEN_MAC_MATCH_VALID V_AOPEN_MAC_MATCH_VALID(1U) + +#define S_AOPEN_IFF_VLAN 20 +#define M_AOPEN_IFF_VLAN 0xFFF +#define V_AOPEN_IFF_VLAN(x) ((x) << S_AOPEN_IFF_VLAN) +#define G_AOPEN_IFF_VLAN(x) (((x) >> S_AOPEN_IFF_VLAN) & M_AOPEN_IFF_VLAN) + +struct cpl_act_open_rpl { + RSS_HDR union opcode_tid ot; + __be16 local_port; + __be16 peer_port; + __be32 local_ip; + __be32 peer_ip; + __be32 atid; + __u8 rsvd[3]; + __u8 status; +}; + +struct cpl_act_establish { + RSS_HDR union opcode_tid ot; + __be16 local_port; + __be16 peer_port; + __be32 local_ip; + __be32 peer_ip; + __be32 tos_tid; + __be16 l2t_idx; + __be16 tcp_opt; + __be32 snd_isn; + __be32 rcv_isn; +}; + +struct cpl_get_tcb { + WR_HDR; + union opcode_tid ot; + __be16 cpuno; + __be16 rsvd; +}; + +struct cpl_get_tcb_rpl { + RSS_HDR union opcode_tid ot; + __u8 rsvd; + __u8 status; + __be16 len; +}; + +struct cpl_set_tcb { + WR_HDR; + union opcode_tid ot; + __u8 reply; + __u8 cpu_idx; + __be16 len; +}; + +/* cpl_set_tcb.reply fields */ +#define S_NO_REPLY 7 +#define V_NO_REPLY(x) ((x) << S_NO_REPLY) +#define F_NO_REPLY V_NO_REPLY(1U) + +struct cpl_set_tcb_field { + WR_HDR; + union opcode_tid ot; + __u8 reply; + __u8 cpu_idx; + __be16 word; + __be64 mask; + __be64 val; +}; + +struct cpl_set_tcb_rpl { + RSS_HDR union opcode_tid ot; + __u8 rsvd[3]; + __u8 status; +}; + +struct cpl_pcmd { + WR_HDR; + union opcode_tid ot; + __u8 rsvd[3]; +#if defined(__LITTLE_ENDIAN_BITFIELD) + __u8 src:1; + __u8 bundle:1; + __u8 channel:1; + __u8:5; +#else + __u8:5; + __u8 channel:1; + __u8 bundle:1; + __u8 src:1; +#endif + __be32 pcmd_parm[2]; +}; + +struct cpl_pcmd_reply { + RSS_HDR union opcode_tid ot; + __u8 status; + __u8 rsvd; + __be16 len; +}; + +struct cpl_close_con_req { + WR_HDR; + union opcode_tid ot; + __be32 rsvd; +}; + +struct cpl_close_con_rpl { + RSS_HDR union opcode_tid ot; + __u8 rsvd[3]; + __u8 status; + __be32 snd_nxt; + __be32 rcv_nxt; +}; + +struct cpl_close_listserv_req { + WR_HDR; + union opcode_tid ot; + __u8 rsvd0; + __u8 cpu_idx; + __be16 rsvd1; +}; + +struct cpl_close_listserv_rpl { + RSS_HDR union opcode_tid ot; + __u8 rsvd[3]; + __u8 status; +}; + +struct cpl_abort_req_rss { + RSS_HDR union opcode_tid ot; + __be32 rsvd0; + __u8 rsvd1; + __u8 status; + __u8 rsvd2[6]; +}; + +struct cpl_abort_req { + WR_HDR; + union opcode_tid ot; + __be32 rsvd0; + __u8 rsvd1; + __u8 cmd; + __u8 rsvd2[6]; +}; + +struct cpl_abort_rpl_rss { + RSS_HDR union opcode_tid ot; + __be32 rsvd0; + __u8 rsvd1; + __u8 status; + __u8 rsvd2[6]; +}; + +struct cpl_abort_rpl { + WR_HDR; + union opcode_tid ot; + __be32 rsvd0; + __u8 rsvd1; + __u8 cmd; + __u8 rsvd2[6]; +}; + +struct cpl_peer_close { + RSS_HDR union opcode_tid ot; + __be32 rcv_nxt; +}; + +struct tx_data_wr { + __be32 wr_hi; + __be32 wr_lo; + __be32 len; + __be32 flags; + __be32 sndseq; + __be32 param; +}; + +/* tx_data_wr.param fields */ +#define S_TX_PORT 0 +#define M_TX_PORT 0x7 +#define V_TX_PORT(x) ((x) << S_TX_PORT) +#define G_TX_PORT(x) (((x) >> S_TX_PORT) & M_TX_PORT) + +#define S_TX_MSS 4 +#define M_TX_MSS 0xF +#define V_TX_MSS(x) ((x) << S_TX_MSS) +#define G_TX_MSS(x) (((x) >> S_TX_MSS) & M_TX_MSS) + +#define S_TX_QOS 8 +#define M_TX_QOS 0xFF +#define V_TX_QOS(x) ((x) << S_TX_QOS) +#define G_TX_QOS(x) (((x) >> S_TX_QOS) & M_TX_QOS) + +#define S_TX_SNDBUF 16 +#define M_TX_SNDBUF 0xFFFF +#define V_TX_SNDBUF(x) ((x) << S_TX_SNDBUF) +#define G_TX_SNDBUF(x) (((x) >> S_TX_SNDBUF) & M_TX_SNDBUF) + +struct cpl_tx_data { + union opcode_tid ot; + __be32 len; + __be32 rsvd; + __be16 urg; + __be16 flags; +}; + +/* cpl_tx_data.flags fields */ +#define S_TX_ULP_SUBMODE 6 +#define M_TX_ULP_SUBMODE 0xF +#define V_TX_ULP_SUBMODE(x) ((x) << S_TX_ULP_SUBMODE) +#define G_TX_ULP_SUBMODE(x) (((x) >> S_TX_ULP_SUBMODE) & M_TX_ULP_SUBMODE) + +#define S_TX_ULP_MODE 10 +#define M_TX_ULP_MODE 0xF +#define V_TX_ULP_MODE(x) ((x) << S_TX_ULP_MODE) +#define G_TX_ULP_MODE(x) (((x) >> S_TX_ULP_MODE) & M_TX_ULP_MODE) + +#define S_TX_SHOVE 14 +#define V_TX_SHOVE(x) ((x) << S_TX_SHOVE) +#define F_TX_SHOVE V_TX_SHOVE(1U) + +#define S_TX_MORE 15 +#define V_TX_MORE(x) ((x) << S_TX_MORE) +#define F_TX_MORE V_TX_MORE(1U) + +/* additional tx_data_wr.flags fields */ +#define S_TX_CPU_IDX 0 +#define M_TX_CPU_IDX 0x3F +#define V_TX_CPU_IDX(x) ((x) << S_TX_CPU_IDX) +#define G_TX_CPU_IDX(x) (((x) >> S_TX_CPU_IDX) & M_TX_CPU_IDX) + +#define S_TX_URG 16 +#define V_TX_URG(x) ((x) << S_TX_URG) +#define F_TX_URG V_TX_URG(1U) + +#define S_TX_CLOSE 17 +#define V_TX_CLOSE(x) ((x) << S_TX_CLOSE) +#define F_TX_CLOSE V_TX_CLOSE(1U) + +#define S_TX_INIT 18 +#define V_TX_INIT(x) ((x) << S_TX_INIT) +#define F_TX_INIT V_TX_INIT(1U) + +#define S_TX_IMM_ACK 19 +#define V_TX_IMM_ACK(x) ((x) << S_TX_IMM_ACK) +#define F_TX_IMM_ACK V_TX_IMM_ACK(1U) + +#define S_TX_IMM_DMA 20 +#define V_TX_IMM_DMA(x) ((x) << S_TX_IMM_DMA) +#define F_TX_IMM_DMA V_TX_IMM_DMA(1U) + +struct cpl_tx_data_ack { + RSS_HDR union opcode_tid ot; + __be32 ack_seq; +}; + +struct cpl_wr_ack { + RSS_HDR union opcode_tid ot; + __be16 credits; + __be16 rsvd; + __be32 snd_nxt; + __be32 snd_una; +}; + +struct cpl_rdma_ec_status { + RSS_HDR union opcode_tid ot; + __u8 rsvd[3]; + __u8 status; +}; + +struct mngt_pktsched_wr { + __be32 wr_hi; + __be32 wr_lo; + __u8 mngt_opcode; + __u8 rsvd[7]; + __u8 sched; + __u8 idx; + __u8 min; + __u8 max; + __u8 binding; + __u8 rsvd1[3]; +}; + +struct cpl_iscsi_hdr { + RSS_HDR union opcode_tid ot; + __be16 pdu_len_ddp; + __be16 len; + __be32 seq; + __be16 urg; + __u8 rsvd; + __u8 status; +}; + +/* cpl_iscsi_hdr.pdu_len_ddp fields */ +#define S_ISCSI_PDU_LEN 0 +#define M_ISCSI_PDU_LEN 0x7FFF +#define V_ISCSI_PDU_LEN(x) ((x) << S_ISCSI_PDU_LEN) +#define G_ISCSI_PDU_LEN(x) (((x) >> S_ISCSI_PDU_LEN) & M_ISCSI_PDU_LEN) + +#define S_ISCSI_DDP 15 +#define V_ISCSI_DDP(x) ((x) << S_ISCSI_DDP) +#define F_ISCSI_DDP V_ISCSI_DDP(1U) + +struct cpl_rx_data { + RSS_HDR union opcode_tid ot; + __be16 rsvd; + __be16 len; + __be32 seq; + __be16 urg; +#if defined(__LITTLE_ENDIAN_BITFIELD) + __u8 dack_mode:2; + __u8 psh:1; + __u8 heartbeat:1; + __u8:4; +#else + __u8:4; + __u8 heartbeat:1; + __u8 psh:1; + __u8 dack_mode:2; +#endif + __u8 status; +}; + +struct cpl_rx_data_ack { + WR_HDR; + union opcode_tid ot; + __be32 credit_dack; +}; + +/* cpl_rx_data_ack.ack_seq fields */ +#define S_RX_CREDITS 0 +#define M_RX_CREDITS 0x7FFFFFF +#define V_RX_CREDITS(x) ((x) << S_RX_CREDITS) +#define G_RX_CREDITS(x) (((x) >> S_RX_CREDITS) & M_RX_CREDITS) + +#define S_RX_MODULATE 27 +#define V_RX_MODULATE(x) ((x) << S_RX_MODULATE) +#define F_RX_MODULATE V_RX_MODULATE(1U) + +#define S_RX_FORCE_ACK 28 +#define V_RX_FORCE_ACK(x) ((x) << S_RX_FORCE_ACK) +#define F_RX_FORCE_ACK V_RX_FORCE_ACK(1U) + +#define S_RX_DACK_MODE 29 +#define M_RX_DACK_MODE 0x3 +#define V_RX_DACK_MODE(x) ((x) << S_RX_DACK_MODE) +#define G_RX_DACK_MODE(x) (((x) >> S_RX_DACK_MODE) & M_RX_DACK_MODE) + +#define S_RX_DACK_CHANGE 31 +#define V_RX_DACK_CHANGE(x) ((x) << S_RX_DACK_CHANGE) +#define F_RX_DACK_CHANGE V_RX_DACK_CHANGE(1U) + +struct cpl_rx_urg_notify { + RSS_HDR union opcode_tid ot; + __be32 seq; +}; + +struct cpl_rx_ddp_complete { + RSS_HDR union opcode_tid ot; + __be32 ddp_report; +}; + +struct cpl_rx_data_ddp { + RSS_HDR union opcode_tid ot; + __be16 urg; + __be16 len; + __be32 seq; + union { + __be32 nxt_seq; + __be32 ddp_report; + }; + __be32 ulp_crc; + __be32 ddpvld_status; +}; + +/* cpl_rx_data_ddp.ddpvld_status fields */ +#define S_DDP_STATUS 0 +#define M_DDP_STATUS 0xFF +#define V_DDP_STATUS(x) ((x) << S_DDP_STATUS) +#define G_DDP_STATUS(x) (((x) >> S_DDP_STATUS) & M_DDP_STATUS) + +#define S_DDP_VALID 15 +#define M_DDP_VALID 0x1FFFF +#define V_DDP_VALID(x) ((x) << S_DDP_VALID) +#define G_DDP_VALID(x) (((x) >> S_DDP_VALID) & M_DDP_VALID) + +#define S_DDP_PPOD_MISMATCH 15 +#define V_DDP_PPOD_MISMATCH(x) ((x) << S_DDP_PPOD_MISMATCH) +#define F_DDP_PPOD_MISMATCH V_DDP_PPOD_MISMATCH(1U) + +#define S_DDP_PDU 16 +#define V_DDP_PDU(x) ((x) << S_DDP_PDU) +#define F_DDP_PDU V_DDP_PDU(1U) + +#define S_DDP_LLIMIT_ERR 17 +#define V_DDP_LLIMIT_ERR(x) ((x) << S_DDP_LLIMIT_ERR) +#define F_DDP_LLIMIT_ERR V_DDP_LLIMIT_ERR(1U) + +#define S_DDP_PPOD_PARITY_ERR 18 +#define V_DDP_PPOD_PARITY_ERR(x) ((x) << S_DDP_PPOD_PARITY_ERR) +#define F_DDP_PPOD_PARITY_ERR V_DDP_PPOD_PARITY_ERR(1U) + +#define S_DDP_PADDING_ERR 19 +#define V_DDP_PADDING_ERR(x) ((x) << S_DDP_PADDING_ERR) +#define F_DDP_PADDING_ERR V_DDP_PADDING_ERR(1U) + +#define S_DDP_HDRCRC_ERR 20 +#define V_DDP_HDRCRC_ERR(x) ((x) << S_DDP_HDRCRC_ERR) +#define F_DDP_HDRCRC_ERR V_DDP_HDRCRC_ERR(1U) + +#define S_DDP_DATACRC_ERR 21 +#define V_DDP_DATACRC_ERR(x) ((x) << S_DDP_DATACRC_ERR) +#define F_DDP_DATACRC_ERR V_DDP_DATACRC_ERR(1U) + +#define S_DDP_INVALID_TAG 22 +#define V_DDP_INVALID_TAG(x) ((x) << S_DDP_INVALID_TAG) +#define F_DDP_INVALID_TAG V_DDP_INVALID_TAG(1U) + +#define S_DDP_ULIMIT_ERR 23 +#define V_DDP_ULIMIT_ERR(x) ((x) << S_DDP_ULIMIT_ERR) +#define F_DDP_ULIMIT_ERR V_DDP_ULIMIT_ERR(1U) + +#define S_DDP_OFFSET_ERR 24 +#define V_DDP_OFFSET_ERR(x) ((x) << S_DDP_OFFSET_ERR) +#define F_DDP_OFFSET_ERR V_DDP_OFFSET_ERR(1U) + +#define S_DDP_COLOR_ERR 25 +#define V_DDP_COLOR_ERR(x) ((x) << S_DDP_COLOR_ERR) +#define F_DDP_COLOR_ERR V_DDP_COLOR_ERR(1U) + +#define S_DDP_TID_MISMATCH 26 +#define V_DDP_TID_MISMATCH(x) ((x) << S_DDP_TID_MISMATCH) +#define F_DDP_TID_MISMATCH V_DDP_TID_MISMATCH(1U) + +#define S_DDP_INVALID_PPOD 27 +#define V_DDP_INVALID_PPOD(x) ((x) << S_DDP_INVALID_PPOD) +#define F_DDP_INVALID_PPOD V_DDP_INVALID_PPOD(1U) + +#define S_DDP_ULP_MODE 28 +#define M_DDP_ULP_MODE 0xF +#define V_DDP_ULP_MODE(x) ((x) << S_DDP_ULP_MODE) +#define G_DDP_ULP_MODE(x) (((x) >> S_DDP_ULP_MODE) & M_DDP_ULP_MODE) + +/* cpl_rx_data_ddp.ddp_report fields */ +#define S_DDP_OFFSET 0 +#define M_DDP_OFFSET 0x3FFFFF +#define V_DDP_OFFSET(x) ((x) << S_DDP_OFFSET) +#define G_DDP_OFFSET(x) (((x) >> S_DDP_OFFSET) & M_DDP_OFFSET) + +#define S_DDP_URG 24 +#define V_DDP_URG(x) ((x) << S_DDP_URG) +#define F_DDP_URG V_DDP_URG(1U) + +#define S_DDP_PSH 25 +#define V_DDP_PSH(x) ((x) << S_DDP_PSH) +#define F_DDP_PSH V_DDP_PSH(1U) + +#define S_DDP_BUF_COMPLETE 26 +#define V_DDP_BUF_COMPLETE(x) ((x) << S_DDP_BUF_COMPLETE) +#define F_DDP_BUF_COMPLETE V_DDP_BUF_COMPLETE(1U) + +#define S_DDP_BUF_TIMED_OUT 27 +#define V_DDP_BUF_TIMED_OUT(x) ((x) << S_DDP_BUF_TIMED_OUT) +#define F_DDP_BUF_TIMED_OUT V_DDP_BUF_TIMED_OUT(1U) + +#define S_DDP_BUF_IDX 28 +#define V_DDP_BUF_IDX(x) ((x) << S_DDP_BUF_IDX) +#define F_DDP_BUF_IDX V_DDP_BUF_IDX(1U) + +struct cpl_tx_pkt { + WR_HDR; + __be32 cntrl; + __be32 len; +}; + +struct cpl_tx_pkt_lso { + WR_HDR; + __be32 cntrl; + __be32 len; + + __be32 rsvd; + __be32 lso_info; +}; + +/* cpl_tx_pkt*.cntrl fields */ +#define S_TXPKT_VLAN 0 +#define M_TXPKT_VLAN 0xFFFF +#define V_TXPKT_VLAN(x) ((x) << S_TXPKT_VLAN) +#define G_TXPKT_VLAN(x) (((x) >> S_TXPKT_VLAN) & M_TXPKT_VLAN) + +#define S_TXPKT_INTF 16 +#define M_TXPKT_INTF 0xF +#define V_TXPKT_INTF(x) ((x) << S_TXPKT_INTF) +#define G_TXPKT_INTF(x) (((x) >> S_TXPKT_INTF) & M_TXPKT_INTF) + +#define S_TXPKT_IPCSUM_DIS 20 +#define V_TXPKT_IPCSUM_DIS(x) ((x) << S_TXPKT_IPCSUM_DIS) +#define F_TXPKT_IPCSUM_DIS V_TXPKT_IPCSUM_DIS(1U) + +#define S_TXPKT_L4CSUM_DIS 21 +#define V_TXPKT_L4CSUM_DIS(x) ((x) << S_TXPKT_L4CSUM_DIS) +#define F_TXPKT_L4CSUM_DIS V_TXPKT_L4CSUM_DIS(1U) + +#define S_TXPKT_VLAN_VLD 22 +#define V_TXPKT_VLAN_VLD(x) ((x) << S_TXPKT_VLAN_VLD) +#define F_TXPKT_VLAN_VLD V_TXPKT_VLAN_VLD(1U) + +#define S_TXPKT_LOOPBACK 23 +#define V_TXPKT_LOOPBACK(x) ((x) << S_TXPKT_LOOPBACK) +#define F_TXPKT_LOOPBACK V_TXPKT_LOOPBACK(1U) + +#define S_TXPKT_OPCODE 24 +#define M_TXPKT_OPCODE 0xFF +#define V_TXPKT_OPCODE(x) ((x) << S_TXPKT_OPCODE) +#define G_TXPKT_OPCODE(x) (((x) >> S_TXPKT_OPCODE) & M_TXPKT_OPCODE) + +/* cpl_tx_pkt_lso.lso_info fields */ +#define S_LSO_MSS 0 +#define M_LSO_MSS 0x3FFF +#define V_LSO_MSS(x) ((x) << S_LSO_MSS) +#define G_LSO_MSS(x) (((x) >> S_LSO_MSS) & M_LSO_MSS) + +#define S_LSO_ETH_TYPE 14 +#define M_LSO_ETH_TYPE 0x3 +#define V_LSO_ETH_TYPE(x) ((x) << S_LSO_ETH_TYPE) +#define G_LSO_ETH_TYPE(x) (((x) >> S_LSO_ETH_TYPE) & M_LSO_ETH_TYPE) + +#define S_LSO_TCPHDR_WORDS 16 +#define M_LSO_TCPHDR_WORDS 0xF +#define V_LSO_TCPHDR_WORDS(x) ((x) << S_LSO_TCPHDR_WORDS) +#define G_LSO_TCPHDR_WORDS(x) (((x) >> S_LSO_TCPHDR_WORDS) & M_LSO_TCPHDR_WORDS) + +#define S_LSO_IPHDR_WORDS 20 +#define M_LSO_IPHDR_WORDS 0xF +#define V_LSO_IPHDR_WORDS(x) ((x) << S_LSO_IPHDR_WORDS) +#define G_LSO_IPHDR_WORDS(x) (((x) >> S_LSO_IPHDR_WORDS) & M_LSO_IPHDR_WORDS) + +#define S_LSO_IPV6 24 +#define V_LSO_IPV6(x) ((x) << S_LSO_IPV6) +#define F_LSO_IPV6 V_LSO_IPV6(1U) + +struct cpl_trace_pkt { +#ifdef CHELSIO_FW + __u8 rss_opcode; +#if defined(__LITTLE_ENDIAN_BITFIELD) + __u8 err:1; + __u8:7; +#else + __u8:7; + __u8 err:1; +#endif + __u8 rsvd0; +#if defined(__LITTLE_ENDIAN_BITFIELD) + __u8 qid:4; + __u8:4; +#else + __u8:4; + __u8 qid:4; +#endif + __be32 tstamp; +#endif /* CHELSIO_FW */ + + __u8 opcode; +#if defined(__LITTLE_ENDIAN_BITFIELD) + __u8 iff:4; + __u8:4; +#else + __u8:4; + __u8 iff:4; +#endif + __u8 rsvd[4]; + __be16 len; +}; + +struct cpl_rx_pkt { + RSS_HDR __u8 opcode; +#if defined(__LITTLE_ENDIAN_BITFIELD) + __u8 iff:4; + __u8 csum_valid:1; + __u8 ipmi_pkt:1; + __u8 vlan_valid:1; + __u8 fragment:1; +#else + __u8 fragment:1; + __u8 vlan_valid:1; + __u8 ipmi_pkt:1; + __u8 csum_valid:1; + __u8 iff:4; +#endif + __be16 csum; + __be16 vlan; + __be16 len; +}; + +struct cpl_l2t_write_req { + WR_HDR; + union opcode_tid ot; + __be32 params; + __u8 rsvd[2]; + __u8 dst_mac[6]; +}; + +/* cpl_l2t_write_req.params fields */ +#define S_L2T_W_IDX 0 +#define M_L2T_W_IDX 0x7FF +#define V_L2T_W_IDX(x) ((x) << S_L2T_W_IDX) +#define G_L2T_W_IDX(x) (((x) >> S_L2T_W_IDX) & M_L2T_W_IDX) + +#define S_L2T_W_VLAN 11 +#define M_L2T_W_VLAN 0xFFF +#define V_L2T_W_VLAN(x) ((x) << S_L2T_W_VLAN) +#define G_L2T_W_VLAN(x) (((x) >> S_L2T_W_VLAN) & M_L2T_W_VLAN) + +#define S_L2T_W_IFF 23 +#define M_L2T_W_IFF 0xF +#define V_L2T_W_IFF(x) ((x) << S_L2T_W_IFF) +#define G_L2T_W_IFF(x) (((x) >> S_L2T_W_IFF) & M_L2T_W_IFF) + +#define S_L2T_W_PRIO 27 +#define M_L2T_W_PRIO 0x7 +#define V_L2T_W_PRIO(x) ((x) << S_L2T_W_PRIO) +#define G_L2T_W_PRIO(x) (((x) >> S_L2T_W_PRIO) & M_L2T_W_PRIO) + +struct cpl_l2t_write_rpl { + RSS_HDR union opcode_tid ot; + __u8 status; + __u8 rsvd[3]; +}; + +struct cpl_l2t_read_req { + WR_HDR; + union opcode_tid ot; + __be16 rsvd; + __be16 l2t_idx; +}; + +struct cpl_l2t_read_rpl { + RSS_HDR union opcode_tid ot; + __be32 params; + __u8 rsvd[2]; + __u8 dst_mac[6]; +}; + +/* cpl_l2t_read_rpl.params fields */ +#define S_L2T_R_PRIO 0 +#define M_L2T_R_PRIO 0x7 +#define V_L2T_R_PRIO(x) ((x) << S_L2T_R_PRIO) +#define G_L2T_R_PRIO(x) (((x) >> S_L2T_R_PRIO) & M_L2T_R_PRIO) + +#define S_L2T_R_VLAN 8 +#define M_L2T_R_VLAN 0xFFF +#define V_L2T_R_VLAN(x) ((x) << S_L2T_R_VLAN) +#define G_L2T_R_VLAN(x) (((x) >> S_L2T_R_VLAN) & M_L2T_R_VLAN) + +#define S_L2T_R_IFF 20 +#define M_L2T_R_IFF 0xF +#define V_L2T_R_IFF(x) ((x) << S_L2T_R_IFF) +#define G_L2T_R_IFF(x) (((x) >> S_L2T_R_IFF) & M_L2T_R_IFF) + +#define S_L2T_STATUS 24 +#define M_L2T_STATUS 0xFF +#define V_L2T_STATUS(x) ((x) << S_L2T_STATUS) +#define G_L2T_STATUS(x) (((x) >> S_L2T_STATUS) & M_L2T_STATUS) + +struct cpl_smt_write_req { + WR_HDR; + union opcode_tid ot; + __u8 rsvd0; +#if defined(__LITTLE_ENDIAN_BITFIELD) + __u8 mtu_idx:4; + __u8 iff:4; +#else + __u8 iff:4; + __u8 mtu_idx:4; +#endif + __be16 rsvd2; + __be16 rsvd3; + __u8 src_mac1[6]; + __be16 rsvd4; + __u8 src_mac0[6]; +}; + +struct cpl_smt_write_rpl { + RSS_HDR union opcode_tid ot; + __u8 status; + __u8 rsvd[3]; +}; + +struct cpl_smt_read_req { + WR_HDR; + union opcode_tid ot; + __u8 rsvd0; +#if defined(__LITTLE_ENDIAN_BITFIELD) + __u8:4; + __u8 iff:4; +#else + __u8 iff:4; + __u8:4; +#endif + __be16 rsvd2; +}; + +struct cpl_smt_read_rpl { + RSS_HDR union opcode_tid ot; + __u8 status; +#if defined(__LITTLE_ENDIAN_BITFIELD) + __u8 mtu_idx:4; + __u8:4; +#else + __u8:4; + __u8 mtu_idx:4; +#endif + __be16 rsvd2; + __be16 rsvd3; + __u8 src_mac1[6]; + __be16 rsvd4; + __u8 src_mac0[6]; +}; + +struct cpl_rte_delete_req { + WR_HDR; + union opcode_tid ot; + __be32 params; +}; + +/* { cpl_rte_delete_req, cpl_rte_read_req }.params fields */ +#define S_RTE_REQ_LUT_IX 8 +#define M_RTE_REQ_LUT_IX 0x7FF +#define V_RTE_REQ_LUT_IX(x) ((x) << S_RTE_REQ_LUT_IX) +#define G_RTE_REQ_LUT_IX(x) (((x) >> S_RTE_REQ_LUT_IX) & M_RTE_REQ_LUT_IX) + +#define S_RTE_REQ_LUT_BASE 19 +#define M_RTE_REQ_LUT_BASE 0x7FF +#define V_RTE_REQ_LUT_BASE(x) ((x) << S_RTE_REQ_LUT_BASE) +#define G_RTE_REQ_LUT_BASE(x) (((x) >> S_RTE_REQ_LUT_BASE) & M_RTE_REQ_LUT_BASE) + +#define S_RTE_READ_REQ_SELECT 31 +#define V_RTE_READ_REQ_SELECT(x) ((x) << S_RTE_READ_REQ_SELECT) +#define F_RTE_READ_REQ_SELECT V_RTE_READ_REQ_SELECT(1U) + +struct cpl_rte_delete_rpl { + RSS_HDR union opcode_tid ot; + __u8 status; + __u8 rsvd[3]; +}; + +struct cpl_rte_write_req { + WR_HDR; + union opcode_tid ot; +#if defined(__LITTLE_ENDIAN_BITFIELD) + __u8:6; + __u8 write_tcam:1; + __u8 write_l2t_lut:1; +#else + __u8 write_l2t_lut:1; + __u8 write_tcam:1; + __u8:6; +#endif + __u8 rsvd[3]; + __be32 lut_params; + __be16 rsvd2; + __be16 l2t_idx; + __be32 netmask; + __be32 faddr; +}; + +/* cpl_rte_write_req.lut_params fields */ +#define S_RTE_WRITE_REQ_LUT_IX 10 +#define M_RTE_WRITE_REQ_LUT_IX 0x7FF +#define V_RTE_WRITE_REQ_LUT_IX(x) ((x) << S_RTE_WRITE_REQ_LUT_IX) +#define G_RTE_WRITE_REQ_LUT_IX(x) (((x) >> S_RTE_WRITE_REQ_LUT_IX) & M_RTE_WRITE_REQ_LUT_IX) + +#define S_RTE_WRITE_REQ_LUT_BASE 21 +#define M_RTE_WRITE_REQ_LUT_BASE 0x7FF +#define V_RTE_WRITE_REQ_LUT_BASE(x) ((x) << S_RTE_WRITE_REQ_LUT_BASE) +#define G_RTE_WRITE_REQ_LUT_BASE(x) (((x) >> S_RTE_WRITE_REQ_LUT_BASE) & M_RTE_WRITE_REQ_LUT_BASE) + +struct cpl_rte_write_rpl { + RSS_HDR union opcode_tid ot; + __u8 status; + __u8 rsvd[3]; +}; + +struct cpl_rte_read_req { + WR_HDR; + union opcode_tid ot; + __be32 params; +}; + +struct cpl_rte_read_rpl { + RSS_HDR union opcode_tid ot; + __u8 status; + __u8 rsvd0; + __be16 l2t_idx; +#if defined(__LITTLE_ENDIAN_BITFIELD) + __u8:7; + __u8 select:1; +#else + __u8 select:1; + __u8:7; +#endif + __u8 rsvd2[3]; + __be32 addr; +}; + +struct cpl_tid_release { + WR_HDR; + union opcode_tid ot; + __be32 rsvd; +}; + +struct cpl_barrier { + WR_HDR; + __u8 opcode; + __u8 rsvd[7]; +}; + +struct cpl_rdma_read_req { + __u8 opcode; + __u8 rsvd[15]; +}; + +struct cpl_rdma_terminate { +#ifdef CHELSIO_FW + __u8 opcode; + __u8 rsvd[2]; +#if defined(__LITTLE_ENDIAN_BITFIELD) + __u8 rspq:3; + __u8:5; +#else + __u8:5; + __u8 rspq:3; +#endif + __be32 tid_len; +#endif + __be32 msn; + __be32 mo; + __u8 data[0]; +}; + +/* cpl_rdma_terminate.tid_len fields */ +#define S_FLIT_CNT 0 +#define M_FLIT_CNT 0xFF +#define V_FLIT_CNT(x) ((x) << S_FLIT_CNT) +#define G_FLIT_CNT(x) (((x) >> S_FLIT_CNT) & M_FLIT_CNT) + +#define S_TERM_TID 8 +#define M_TERM_TID 0xFFFFF +#define V_TERM_TID(x) ((x) << S_TERM_TID) +#define G_TERM_TID(x) (((x) >> S_TERM_TID) & M_TERM_TID) +#endif /* T3_CPL_H */ diff --git a/drivers/net/cxgb3/t3_hw.c b/drivers/net/cxgb3/t3_hw.c new file mode 100644 index 0000000..365a7f5 --- /dev/null +++ b/drivers/net/cxgb3/t3_hw.c @@ -0,0 +1,3375 @@ +/* + * Copyright (c) 2003-2007 Chelsio, Inc. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +#include "common.h" +#include "regs.h" +#include "sge_defs.h" +#include "firmware_exports.h" + +/** + * t3_wait_op_done_val - wait until an operation is completed + * @adapter: the adapter performing the operation + * @reg: the register to check for completion + * @mask: a single-bit field within @reg that indicates completion + * @polarity: the value of the field when the operation is completed + * @attempts: number of check iterations + * @delay: delay in usecs between iterations + * @valp: where to store the value of the register at completion time + * + * Wait until an operation is completed by checking a bit in a register + * up to @attempts times. If @valp is not NULL the value of the register + * at the time it indicated completion is stored there. Returns 0 if the + * operation completes and -EAGAIN otherwise. + */ + +int t3_wait_op_done_val(struct adapter *adapter, int reg, u32 mask, + int polarity, int attempts, int delay, u32 *valp) +{ + while (1) { + u32 val = t3_read_reg(adapter, reg); + + if (!!(val & mask) == polarity) { + if (valp) + *valp = val; + return 0; + } + if (--attempts == 0) + return -EAGAIN; + if (delay) + udelay(delay); + } +} + +/** + * t3_write_regs - write a bunch of registers + * @adapter: the adapter to program + * @p: an array of register address/register value pairs + * @n: the number of address/value pairs + * @offset: register address offset + * + * Takes an array of register address/register value pairs and writes each + * value to the corresponding register. Register addresses are adjusted + * by the supplied offset. + */ +void t3_write_regs(struct adapter *adapter, const struct addr_val_pair *p, + int n, unsigned int offset) +{ + while (n--) { + t3_write_reg(adapter, p->reg_addr + offset, p->val); + p++; + } +} + +/** + * t3_set_reg_field - set a register field to a value + * @adapter: the adapter to program + * @addr: the register address + * @mask: specifies the portion of the register to modify + * @val: the new value for the register field + * + * Sets a register field specified by the supplied mask to the + * given value. + */ +void t3_set_reg_field(struct adapter *adapter, unsigned int addr, u32 mask, + u32 val) +{ + u32 v = t3_read_reg(adapter, addr) & ~mask; + + t3_write_reg(adapter, addr, v | val); + t3_read_reg(adapter, addr); /* flush */ +} + +/** + * t3_read_indirect - read indirectly addressed registers + * @adap: the adapter + * @addr_reg: register holding the indirect address + * @data_reg: register holding the value of the indirect register + * @vals: where the read register values are stored + * @start_idx: index of first indirect register to read + * @nregs: how many indirect registers to read + * + * Reads registers that are accessed indirectly through an address/data + * register pair. + */ +void t3_read_indirect(struct adapter *adap, unsigned int addr_reg, + unsigned int data_reg, u32 *vals, unsigned int nregs, + unsigned int start_idx) +{ + while (nregs--) { + t3_write_reg(adap, addr_reg, start_idx); + *vals++ = t3_read_reg(adap, data_reg); + start_idx++; + } +} + +/** + * t3_mc7_bd_read - read from MC7 through backdoor accesses + * @mc7: identifies MC7 to read from + * @start: index of first 64-bit word to read + * @n: number of 64-bit words to read + * @buf: where to store the read result + * + * Read n 64-bit words from MC7 starting at word start, using backdoor + * accesses. + */ +int t3_mc7_bd_read(struct mc7 *mc7, unsigned int start, unsigned int n, + u64 *buf) +{ + static const int shift[] = { 0, 0, 16, 24 }; + static const int step[] = { 0, 32, 16, 8 }; + + unsigned int size64 = mc7->size / 8; /* # of 64-bit words */ + struct adapter *adap = mc7->adapter; + + if (start >= size64 || start + n > size64) + return -EINVAL; + + start *= (8 << mc7->width); + while (n--) { + int i; + u64 val64 = 0; + + for (i = (1 << mc7->width) - 1; i >= 0; --i) { + int attempts = 10; + u32 val; + + t3_write_reg(adap, mc7->offset + A_MC7_BD_ADDR, start); + t3_write_reg(adap, mc7->offset + A_MC7_BD_OP, 0); + val = t3_read_reg(adap, mc7->offset + A_MC7_BD_OP); + while ((val & F_BUSY) && attempts--) + val = t3_read_reg(adap, + mc7->offset + A_MC7_BD_OP); + if (val & F_BUSY) + return -EIO; + + val = t3_read_reg(adap, mc7->offset + A_MC7_BD_DATA1); + if (mc7->width == 0) { + val64 = t3_read_reg(adap, + mc7->offset + + A_MC7_BD_DATA0); + val64 |= (u64) val << 32; + } else { + if (mc7->width > 1) + val >>= shift[mc7->width]; + val64 |= (u64) val << (step[mc7->width] * i); + } + start += 8; + } + *buf++ = val64; + } + return 0; +} + +/* + * Initialize MI1. + */ +static void mi1_init(struct adapter *adap, const struct adapter_info *ai) +{ + u32 clkdiv = adap->params.vpd.cclk / (2 * adap->params.vpd.mdc) - 1; + u32 val = F_PREEN | V_MDIINV(ai->mdiinv) | V_MDIEN(ai->mdien) | + V_CLKDIV(clkdiv); + + if (!(ai->caps & SUPPORTED_10000baseT_Full)) + val |= V_ST(1); + t3_write_reg(adap, A_MI1_CFG, val); +} + +#define MDIO_ATTEMPTS 10 + +/* + * MI1 read/write operations for direct-addressed PHYs. + */ +static int mi1_read(struct adapter *adapter, int phy_addr, int mmd_addr, + int reg_addr, unsigned int *valp) +{ + int ret; + u32 addr = V_REGADDR(reg_addr) | V_PHYADDR(phy_addr); + + if (mmd_addr) + return -EINVAL; + + mutex_lock(&adapter->mdio_lock); + t3_write_reg(adapter, A_MI1_ADDR, addr); + t3_write_reg(adapter, A_MI1_OP, V_MDI_OP(2)); + ret = t3_wait_op_done(adapter, A_MI1_OP, F_BUSY, 0, MDIO_ATTEMPTS, 20); + if (!ret) + *valp = t3_read_reg(adapter, A_MI1_DATA); + mutex_unlock(&adapter->mdio_lock); + return ret; +} + +static int mi1_write(struct adapter *adapter, int phy_addr, int mmd_addr, + int reg_addr, unsigned int val) +{ + int ret; + u32 addr = V_REGADDR(reg_addr) | V_PHYADDR(phy_addr); + + if (mmd_addr) + return -EINVAL; + + mutex_lock(&adapter->mdio_lock); + t3_write_reg(adapter, A_MI1_ADDR, addr); + t3_write_reg(adapter, A_MI1_DATA, val); + t3_write_reg(adapter, A_MI1_OP, V_MDI_OP(1)); + ret = t3_wait_op_done(adapter, A_MI1_OP, F_BUSY, 0, MDIO_ATTEMPTS, 20); + mutex_unlock(&adapter->mdio_lock); + return ret; +} + +static const struct mdio_ops mi1_mdio_ops = { + mi1_read, + mi1_write +}; + +/* + * MI1 read/write operations for indirect-addressed PHYs. + */ +static int mi1_ext_read(struct adapter *adapter, int phy_addr, int mmd_addr, + int reg_addr, unsigned int *valp) +{ + int ret; + u32 addr = V_REGADDR(mmd_addr) | V_PHYADDR(phy_addr); + + mutex_lock(&adapter->mdio_lock); + t3_write_reg(adapter, A_MI1_ADDR, addr); + t3_write_reg(adapter, A_MI1_DATA, reg_addr); + t3_write_reg(adapter, A_MI1_OP, V_MDI_OP(0)); + ret = t3_wait_op_done(adapter, A_MI1_OP, F_BUSY, 0, MDIO_ATTEMPTS, 20); + if (!ret) { + t3_write_reg(adapter, A_MI1_OP, V_MDI_OP(3)); + ret = t3_wait_op_done(adapter, A_MI1_OP, F_BUSY, 0, + MDIO_ATTEMPTS, 20); + if (!ret) + *valp = t3_read_reg(adapter, A_MI1_DATA); + } + mutex_unlock(&adapter->mdio_lock); + return ret; +} + +static int mi1_ext_write(struct adapter *adapter, int phy_addr, int mmd_addr, + int reg_addr, unsigned int val) +{ + int ret; + u32 addr = V_REGADDR(mmd_addr) | V_PHYADDR(phy_addr); + + mutex_lock(&adapter->mdio_lock); + t3_write_reg(adapter, A_MI1_ADDR, addr); + t3_write_reg(adapter, A_MI1_DATA, reg_addr); + t3_write_reg(adapter, A_MI1_OP, V_MDI_OP(0)); + ret = t3_wait_op_done(adapter, A_MI1_OP, F_BUSY, 0, MDIO_ATTEMPTS, 20); + if (!ret) { + t3_write_reg(adapter, A_MI1_DATA, val); + t3_write_reg(adapter, A_MI1_OP, V_MDI_OP(1)); + ret = t3_wait_op_done(adapter, A_MI1_OP, F_BUSY, 0, + MDIO_ATTEMPTS, 20); + } + mutex_unlock(&adapter->mdio_lock); + return ret; +} + +static const struct mdio_ops mi1_mdio_ext_ops = { + mi1_ext_read, + mi1_ext_write +}; + +/** + * t3_mdio_change_bits - modify the value of a PHY register + * @phy: the PHY to operate on + * @mmd: the device address + * @reg: the register address + * @clear: what part of the register value to mask off + * @set: what part of the register value to set + * + * Changes the value of a PHY register by applying a mask to its current + * value and ORing the result with a new value. + */ +int t3_mdio_change_bits(struct cphy *phy, int mmd, int reg, unsigned int clear, + unsigned int set) +{ + int ret; + unsigned int val; + + ret = mdio_read(phy, mmd, reg, &val); + if (!ret) { + val &= ~clear; + ret = mdio_write(phy, mmd, reg, val | set); + } + return ret; +} + +/** + * t3_phy_reset - reset a PHY block + * @phy: the PHY to operate on + * @mmd: the device address of the PHY block to reset + * @wait: how long to wait for the reset to complete in 1ms increments + * + * Resets a PHY block and optionally waits for the reset to complete. + * @mmd should be 0 for 10/100/1000 PHYs and the device address to reset + * for 10G PHYs. + */ +int t3_phy_reset(struct cphy *phy, int mmd, int wait) +{ + int err; + unsigned int ctl; + + err = t3_mdio_change_bits(phy, mmd, MII_BMCR, BMCR_PDOWN, BMCR_RESET); + if (err || !wait) + return err; + + do { + err = mdio_read(phy, mmd, MII_BMCR, &ctl); + if (err) + return err; + ctl &= BMCR_RESET; + if (ctl) + msleep(1); + } while (ctl && --wait); + + return ctl ? -1 : 0; +} + +/** + * t3_phy_advertise - set the PHY advertisement registers for autoneg + * @phy: the PHY to operate on + * @advert: bitmap of capabilities the PHY should advertise + * + * Sets a 10/100/1000 PHY's advertisement registers to advertise the + * requested capabilities. + */ +int t3_phy_advertise(struct cphy *phy, unsigned int advert) +{ + int err; + unsigned int val = 0; + + err = mdio_read(phy, 0, MII_CTRL1000, &val); + if (err) + return err; + + val &= ~(ADVERTISE_1000HALF | ADVERTISE_1000FULL); + if (advert & ADVERTISED_1000baseT_Half) + val |= ADVERTISE_1000HALF; + if (advert & ADVERTISED_1000baseT_Full) + val |= ADVERTISE_1000FULL; + + err = mdio_write(phy, 0, MII_CTRL1000, val); + if (err) + return err; + + val = 1; + if (advert & ADVERTISED_10baseT_Half) + val |= ADVERTISE_10HALF; + if (advert & ADVERTISED_10baseT_Full) + val |= ADVERTISE_10FULL; + if (advert & ADVERTISED_100baseT_Half) + val |= ADVERTISE_100HALF; + if (advert & ADVERTISED_100baseT_Full) + val |= ADVERTISE_100FULL; + if (advert & ADVERTISED_Pause) + val |= ADVERTISE_PAUSE_CAP; + if (advert & ADVERTISED_Asym_Pause) + val |= ADVERTISE_PAUSE_ASYM; + return mdio_write(phy, 0, MII_ADVERTISE, val); +} + +/** + * t3_set_phy_speed_duplex - force PHY speed and duplex + * @phy: the PHY to operate on + * @speed: requested PHY speed + * @duplex: requested PHY duplex + * + * Force a 10/100/1000 PHY's speed and duplex. This also disables + * auto-negotiation except for GigE, where auto-negotiation is mandatory. + */ +int t3_set_phy_speed_duplex(struct cphy *phy, int speed, int duplex) +{ + int err; + unsigned int ctl; + + err = mdio_read(phy, 0, MII_BMCR, &ctl); + if (err) + return err; + + if (speed >= 0) { + ctl &= ~(BMCR_SPEED100 | BMCR_SPEED1000 | BMCR_ANENABLE); + if (speed == SPEED_100) + ctl |= BMCR_SPEED100; + else if (speed == SPEED_1000) + ctl |= BMCR_SPEED1000; + } + if (duplex >= 0) { + ctl &= ~(BMCR_FULLDPLX | BMCR_ANENABLE); + if (duplex == DUPLEX_FULL) + ctl |= BMCR_FULLDPLX; + } + if (ctl & BMCR_SPEED1000) /* auto-negotiation required for GigE */ + ctl |= BMCR_ANENABLE; + return mdio_write(phy, 0, MII_BMCR, ctl); +} + +static const struct adapter_info t3_adap_info[] = { + {2, 0, 0, 0, + F_GPIO2_OEN | F_GPIO4_OEN | + F_GPIO2_OUT_VAL | F_GPIO4_OUT_VAL, F_GPIO3 | F_GPIO5, + SUPPORTED_OFFLOAD, + &mi1_mdio_ops, "Chelsio PE9000"}, + {2, 0, 0, 0, + F_GPIO2_OEN | F_GPIO4_OEN | + F_GPIO2_OUT_VAL | F_GPIO4_OUT_VAL, F_GPIO3 | F_GPIO5, + SUPPORTED_OFFLOAD, + &mi1_mdio_ops, "Chelsio T302"}, + {1, 0, 0, 0, + F_GPIO1_OEN | F_GPIO6_OEN | F_GPIO7_OEN | F_GPIO10_OEN | + F_GPIO1_OUT_VAL | F_GPIO6_OUT_VAL | F_GPIO10_OUT_VAL, 0, + SUPPORTED_10000baseT_Full | SUPPORTED_AUI | SUPPORTED_OFFLOAD, + &mi1_mdio_ext_ops, "Chelsio T310"}, + {2, 0, 0, 0, + F_GPIO1_OEN | F_GPIO2_OEN | F_GPIO4_OEN | F_GPIO5_OEN | F_GPIO6_OEN | + F_GPIO7_OEN | F_GPIO10_OEN | F_GPIO11_OEN | F_GPIO1_OUT_VAL | + F_GPIO5_OUT_VAL | F_GPIO6_OUT_VAL | F_GPIO10_OUT_VAL, 0, + SUPPORTED_10000baseT_Full | SUPPORTED_AUI | SUPPORTED_OFFLOAD, + &mi1_mdio_ext_ops, "Chelsio T320"}, +}; + +/* + * Return the adapter_info structure with a given index. Out-of-range indices + * return NULL. + */ +const struct adapter_info *t3_get_adapter_info(unsigned int id) +{ + return id < ARRAY_SIZE(t3_adap_info) ? &t3_adap_info[id] : NULL; +} + +#define CAPS_1G (SUPPORTED_10baseT_Full | SUPPORTED_100baseT_Full | \ + SUPPORTED_1000baseT_Full | SUPPORTED_Autoneg | SUPPORTED_MII) +#define CAPS_10G (SUPPORTED_10000baseT_Full | SUPPORTED_AUI) + +static const struct port_type_info port_types[] = { + {NULL}, + {t3_ael1002_phy_prep, CAPS_10G | SUPPORTED_FIBRE, + "10GBASE-XR"}, + {t3_vsc8211_phy_prep, CAPS_1G | SUPPORTED_TP | SUPPORTED_IRQ, + "10/100/1000BASE-T"}, + {NULL, CAPS_1G | SUPPORTED_TP | SUPPORTED_IRQ, + "10/100/1000BASE-T"}, + {t3_xaui_direct_phy_prep, CAPS_10G | SUPPORTED_TP, "10GBASE-CX4"}, + {NULL, CAPS_10G, "10GBASE-KX4"}, + {t3_qt2045_phy_prep, CAPS_10G | SUPPORTED_TP, "10GBASE-CX4"}, + {t3_ael1006_phy_prep, CAPS_10G | SUPPORTED_FIBRE, + "10GBASE-SR"}, + {NULL, CAPS_10G | SUPPORTED_TP, "10GBASE-CX4"}, +}; + +#undef CAPS_1G +#undef CAPS_10G + +#define VPD_ENTRY(name, len) \ + u8 name##_kword[2]; u8 name##_len; u8 name##_data[len] + +/* + * Partial EEPROM Vital Product Data structure. Includes only the ID and + * VPD-R sections. + */ +struct t3_vpd { + u8 id_tag; + u8 id_len[2]; + u8 id_data[16]; + u8 vpdr_tag; + u8 vpdr_len[2]; + VPD_ENTRY(pn, 16); /* part number */ + VPD_ENTRY(ec, 16); /* EC level */ + VPD_ENTRY(sn, 16); /* serial number */ + VPD_ENTRY(na, 12); /* MAC address base */ + VPD_ENTRY(cclk, 6); /* core clock */ + VPD_ENTRY(mclk, 6); /* mem clock */ + VPD_ENTRY(uclk, 6); /* uP clk */ + VPD_ENTRY(mdc, 6); /* MDIO clk */ + VPD_ENTRY(mt, 2); /* mem timing */ + VPD_ENTRY(xaui0cfg, 6); /* XAUI0 config */ + VPD_ENTRY(xaui1cfg, 6); /* XAUI1 config */ + VPD_ENTRY(port0, 2); /* PHY0 complex */ + VPD_ENTRY(port1, 2); /* PHY1 complex */ + VPD_ENTRY(port2, 2); /* PHY2 complex */ + VPD_ENTRY(port3, 2); /* PHY3 complex */ + VPD_ENTRY(rv, 1); /* csum */ + u32 pad; /* for multiple-of-4 sizing and alignment */ +}; + +#define EEPROM_MAX_POLL 4 +#define EEPROM_STAT_ADDR 0x4000 +#define VPD_BASE 0xc00 + +/** + * t3_seeprom_read - read a VPD EEPROM location + * @adapter: adapter to read + * @addr: EEPROM address + * @data: where to store the read data + * + * Read a 32-bit word from a location in VPD EEPROM using the card's PCI + * VPD ROM capability. A zero is written to the flag bit when the + * addres is written to the control register. The hardware device will + * set the flag to 1 when 4 bytes have been read into the data register. + */ +int t3_seeprom_read(struct adapter *adapter, u32 addr, u32 *data) +{ + u16 val; + int attempts = EEPROM_MAX_POLL; + unsigned int base = adapter->params.pci.vpd_cap_addr; + + if ((addr >= EEPROMSIZE && addr != EEPROM_STAT_ADDR) || (addr & 3)) + return -EINVAL; + + pci_write_config_word(adapter->pdev, base + PCI_VPD_ADDR, addr); + do { + udelay(10); + pci_read_config_word(adapter->pdev, base + PCI_VPD_ADDR, &val); + } while (!(val & PCI_VPD_ADDR_F) && --attempts); + + if (!(val & PCI_VPD_ADDR_F)) { + CH_ERR(adapter, "reading EEPROM address 0x%x failed\n", addr); + return -EIO; + } + pci_read_config_dword(adapter->pdev, base + PCI_VPD_DATA, data); + *data = le32_to_cpu(*data); + return 0; +} + +/** + * t3_seeprom_write - write a VPD EEPROM location + * @adapter: adapter to write + * @addr: EEPROM address + * @data: value to write + * + * Write a 32-bit word to a location in VPD EEPROM using the card's PCI + * VPD ROM capability. + */ +int t3_seeprom_write(struct adapter *adapter, u32 addr, u32 data) +{ + u16 val; + int attempts = EEPROM_MAX_POLL; + unsigned int base = adapter->params.pci.vpd_cap_addr; + + if ((addr >= EEPROMSIZE && addr != EEPROM_STAT_ADDR) || (addr & 3)) + return -EINVAL; + + pci_write_config_dword(adapter->pdev, base + PCI_VPD_DATA, + cpu_to_le32(data)); + pci_write_config_word(adapter->pdev,base + PCI_VPD_ADDR, + addr | PCI_VPD_ADDR_F); + do { + msleep(1); + pci_read_config_word(adapter->pdev, base + PCI_VPD_ADDR, &val); + } while ((val & PCI_VPD_ADDR_F) && --attempts); + + if (val & PCI_VPD_ADDR_F) { + CH_ERR(adapter, "write to EEPROM address 0x%x failed\n", addr); + return -EIO; + } + return 0; +} + +/** + * t3_seeprom_wp - enable/disable EEPROM write protection + * @adapter: the adapter + * @enable: 1 to enable write protection, 0 to disable it + * + * Enables or disables write protection on the serial EEPROM. + */ +int t3_seeprom_wp(struct adapter *adapter, int enable) +{ + return t3_seeprom_write(adapter, EEPROM_STAT_ADDR, enable ? 0xc : 0); +} + +/* + * Convert a character holding a hex digit to a number. + */ +static unsigned int hex2int(unsigned char c) +{ + return isdigit(c) ? c - '0' : toupper(c) - 'A' + 10; +} + +/** + * get_vpd_params - read VPD parameters from VPD EEPROM + * @adapter: adapter to read + * @p: where to store the parameters + * + * Reads card parameters stored in VPD EEPROM. + */ +static int get_vpd_params(struct adapter *adapter, struct vpd_params *p) +{ + int i, addr, ret; + struct t3_vpd vpd; + + /* + * Card information is normally at VPD_BASE but some early cards had + * it at 0. + */ + ret = t3_seeprom_read(adapter, VPD_BASE, (u32 *)&vpd); + if (ret) + return ret; + addr = vpd.id_tag == 0x82 ? VPD_BASE : 0; + + for (i = 0; i < sizeof(vpd); i += 4) { + ret = t3_seeprom_read(adapter, addr + i, + (u32 *)((u8 *)&vpd + i)); + if (ret) + return ret; + } + + p->cclk = simple_strtoul(vpd.cclk_data, NULL, 10); + p->mclk = simple_strtoul(vpd.mclk_data, NULL, 10); + p->uclk = simple_strtoul(vpd.uclk_data, NULL, 10); + p->mdc = simple_strtoul(vpd.mdc_data, NULL, 10); + p->mem_timing = simple_strtoul(vpd.mt_data, NULL, 10); + + /* Old eeproms didn't have port information */ + if (adapter->params.rev == 0 && !vpd.port0_data[0]) { + p->port_type[0] = uses_xaui(adapter) ? 1 : 2; + p->port_type[1] = uses_xaui(adapter) ? 6 : 2; + } else { + p->port_type[0] = hex2int(vpd.port0_data[0]); + p->port_type[1] = hex2int(vpd.port1_data[0]); + p->xauicfg[0] = simple_strtoul(vpd.xaui0cfg_data, NULL, 16); + p->xauicfg[1] = simple_strtoul(vpd.xaui1cfg_data, NULL, 16); + } + + for (i = 0; i < 6; i++) + p->eth_base[i] = hex2int(vpd.na_data[2 * i]) * 16 + + hex2int(vpd.na_data[2 * i + 1]); + return 0; +} + +/* serial flash and firmware constants */ +enum { + SF_ATTEMPTS = 5, /* max retries for SF1 operations */ + SF_SEC_SIZE = 64 * 1024, /* serial flash sector size */ + SF_SIZE = SF_SEC_SIZE * 8, /* serial flash size */ + + /* flash command opcodes */ + SF_PROG_PAGE = 2, /* program page */ + SF_WR_DISABLE = 4, /* disable writes */ + SF_RD_STATUS = 5, /* read status register */ + SF_WR_ENABLE = 6, /* enable writes */ + SF_RD_DATA_FAST = 0xb, /* read flash */ + SF_ERASE_SECTOR = 0xd8, /* erase sector */ + + FW_FLASH_BOOT_ADDR = 0x70000, /* start address of FW in flash */ + FW_VERS_ADDR = 0x77ffc /* flash address holding FW version */ +}; + +/** + * sf1_read - read data from the serial flash + * @adapter: the adapter + * @byte_cnt: number of bytes to read + * @cont: whether another operation will be chained + * @valp: where to store the read data + * + * Reads up to 4 bytes of data from the serial flash. The location of + * the read needs to be specified prior to calling this by issuing the + * appropriate commands to the serial flash. + */ +static int sf1_read(struct adapter *adapter, unsigned int byte_cnt, int cont, + u32 *valp) +{ + int ret; + + if (!byte_cnt || byte_cnt > 4) + return -EINVAL; + if (t3_read_reg(adapter, A_SF_OP) & F_BUSY) + return -EBUSY; + t3_write_reg(adapter, A_SF_OP, V_CONT(cont) | V_BYTECNT(byte_cnt - 1)); + ret = t3_wait_op_done(adapter, A_SF_OP, F_BUSY, 0, SF_ATTEMPTS, 10); + if (!ret) + *valp = t3_read_reg(adapter, A_SF_DATA); + return ret; +} + +/** + * sf1_write - write data to the serial flash + * @adapter: the adapter + * @byte_cnt: number of bytes to write + * @cont: whether another operation will be chained + * @val: value to write + * + * Writes up to 4 bytes of data to the serial flash. The location of + * the write needs to be specified prior to calling this by issuing the + * appropriate commands to the serial flash. + */ +static int sf1_write(struct adapter *adapter, unsigned int byte_cnt, int cont, + u32 val) +{ + if (!byte_cnt || byte_cnt > 4) + return -EINVAL; + if (t3_read_reg(adapter, A_SF_OP) & F_BUSY) + return -EBUSY; + t3_write_reg(adapter, A_SF_DATA, val); + t3_write_reg(adapter, A_SF_OP, + V_CONT(cont) | V_BYTECNT(byte_cnt - 1) | V_OP(1)); + return t3_wait_op_done(adapter, A_SF_OP, F_BUSY, 0, SF_ATTEMPTS, 10); +} + +/** + * flash_wait_op - wait for a flash operation to complete + * @adapter: the adapter + * @attempts: max number of polls of the status register + * @delay: delay between polls in ms + * + * Wait for a flash operation to complete by polling the status register. + */ +static int flash_wait_op(struct adapter *adapter, int attempts, int delay) +{ + int ret; + u32 status; + + while (1) { + if ((ret = sf1_write(adapter, 1, 1, SF_RD_STATUS)) != 0 || + (ret = sf1_read(adapter, 1, 0, &status)) != 0) + return ret; + if (!(status & 1)) + return 0; + if (--attempts == 0) + return -EAGAIN; + if (delay) + msleep(delay); + } +} + +/** + * t3_read_flash - read words from serial flash + * @adapter: the adapter + * @addr: the start address for the read + * @nwords: how many 32-bit words to read + * @data: where to store the read data + * @byte_oriented: whether to store data as bytes or as words + * + * Read the specified number of 32-bit words from the serial flash. + * If @byte_oriented is set the read data is stored as a byte array + * (i.e., big-endian), otherwise as 32-bit words in the platform's + * natural endianess. + */ +int t3_read_flash(struct adapter *adapter, unsigned int addr, + unsigned int nwords, u32 *data, int byte_oriented) +{ + int ret; + + if (addr + nwords * sizeof(u32) > SF_SIZE || (addr & 3)) + return -EINVAL; + + addr = swab32(addr) | SF_RD_DATA_FAST; + + if ((ret = sf1_write(adapter, 4, 1, addr)) != 0 || + (ret = sf1_read(adapter, 1, 1, data)) != 0) + return ret; + + for (; nwords; nwords--, data++) { + ret = sf1_read(adapter, 4, nwords > 1, data); + if (ret) + return ret; + if (byte_oriented) + *data = htonl(*data); + } + return 0; +} + +/** + * t3_write_flash - write up to a page of data to the serial flash + * @adapter: the adapter + * @addr: the start address to write + * @n: length of data to write + * @data: the data to write + * + * Writes up to a page of data (256 bytes) to the serial flash starting + * at the given address. + */ +static int t3_write_flash(struct adapter *adapter, unsigned int addr, + unsigned int n, const u8 *data) +{ + int ret; + u32 buf[64]; + unsigned int i, c, left, val, offset = addr & 0xff; + + if (addr + n > SF_SIZE || offset + n > 256) + return -EINVAL; + + val = swab32(addr) | SF_PROG_PAGE; + + if ((ret = sf1_write(adapter, 1, 0, SF_WR_ENABLE)) != 0 || + (ret = sf1_write(adapter, 4, 1, val)) != 0) + return ret; + + for (left = n; left; left -= c) { + c = min(left, 4U); + for (val = 0, i = 0; i < c; ++i) + val = (val << 8) + *data++; + + ret = sf1_write(adapter, c, c != left, val); + if (ret) + return ret; + } + if ((ret = flash_wait_op(adapter, 5, 1)) != 0) + return ret; + + /* Read the page to verify the write succeeded */ + ret = t3_read_flash(adapter, addr & ~0xff, ARRAY_SIZE(buf), buf, 1); + if (ret) + return ret; + + if (memcmp(data - n, (u8 *) buf + offset, n)) + return -EIO; + return 0; +} + +enum fw_version_type { + FW_VERSION_N3, + FW_VERSION_T3 +}; + +/** + * t3_get_fw_version - read the firmware version + * @adapter: the adapter + * @vers: where to place the version + * + * Reads the FW version from flash. + */ +int t3_get_fw_version(struct adapter *adapter, u32 *vers) +{ + return t3_read_flash(adapter, FW_VERS_ADDR, 1, vers, 0); +} + +/** + * t3_check_fw_version - check if the FW is compatible with this driver + * @adapter: the adapter + * + * Checks if an adapter's FW is compatible with the driver. Returns 0 + * if the versions are compatible, a negative error otherwise. + */ +int t3_check_fw_version(struct adapter *adapter) +{ + int ret; + u32 vers; + unsigned int type, major, minor; + + ret = t3_get_fw_version(adapter, &vers); + if (ret) + return ret; + + type = G_FW_VERSION_TYPE(vers); + major = G_FW_VERSION_MAJOR(vers); + minor = G_FW_VERSION_MINOR(vers); + + if (type == FW_VERSION_T3 && major == 3 && minor == 1) + return 0; + + CH_ERR(adapter, "found wrong FW version(%u.%u), " + "driver needs version 3.1\n", major, minor); + return -EINVAL; +} + +/** + * t3_flash_erase_sectors - erase a range of flash sectors + * @adapter: the adapter + * @start: the first sector to erase + * @end: the last sector to erase + * + * Erases the sectors in the given range. + */ +static int t3_flash_erase_sectors(struct adapter *adapter, int start, int end) +{ + while (start <= end) { + int ret; + + if ((ret = sf1_write(adapter, 1, 0, SF_WR_ENABLE)) != 0 || + (ret = sf1_write(adapter, 4, 0, + SF_ERASE_SECTOR | (start << 8))) != 0 || + (ret = flash_wait_op(adapter, 5, 500)) != 0) + return ret; + start++; + } + return 0; +} + +/* + * t3_load_fw - download firmware + * @adapter: the adapter + * @fw_data: the firrware image to write + * @size: image size + * + * Write the supplied firmware image to the card's serial flash. + * The FW image has the following sections: @size - 8 bytes of code and + * data, followed by 4 bytes of FW version, followed by the 32-bit + * 1's complement checksum of the whole image. + */ +int t3_load_fw(struct adapter *adapter, const u8 *fw_data, unsigned int size) +{ + u32 csum; + unsigned int i; + const u32 *p = (const u32 *)fw_data; + int ret, addr, fw_sector = FW_FLASH_BOOT_ADDR >> 16; + + if (size & 3) + return -EINVAL; + if (size > FW_VERS_ADDR + 8 - FW_FLASH_BOOT_ADDR) + return -EFBIG; + + for (csum = 0, i = 0; i < size / sizeof(csum); i++) + csum += ntohl(p[i]); + if (csum != 0xffffffff) { + CH_ERR(adapter, "corrupted firmware image, checksum %u\n", + csum); + return -EINVAL; + } + + ret = t3_flash_erase_sectors(adapter, fw_sector, fw_sector); + if (ret) + goto out; + + size -= 8; /* trim off version and checksum */ + for (addr = FW_FLASH_BOOT_ADDR; size;) { + unsigned int chunk_size = min(size, 256U); + + ret = t3_write_flash(adapter, addr, chunk_size, fw_data); + if (ret) + goto out; + + addr += chunk_size; + fw_data += chunk_size; + size -= chunk_size; + } + + ret = t3_write_flash(adapter, FW_VERS_ADDR, 4, fw_data); +out: + if (ret) + CH_ERR(adapter, "firmware download failed, error %d\n", ret); + return ret; +} + +#define CIM_CTL_BASE 0x2000 + +/** + * t3_cim_ctl_blk_read - read a block from CIM control region + * + * @adap: the adapter + * @addr: the start address within the CIM control region + * @n: number of words to read + * @valp: where to store the result + * + * Reads a block of 4-byte words from the CIM control region. + */ +int t3_cim_ctl_blk_read(struct adapter *adap, unsigned int addr, + unsigned int n, unsigned int *valp) +{ + int ret = 0; + + if (t3_read_reg(adap, A_CIM_HOST_ACC_CTRL) & F_HOSTBUSY) + return -EBUSY; + + for ( ; !ret && n--; addr += 4) { + t3_write_reg(adap, A_CIM_HOST_ACC_CTRL, CIM_CTL_BASE + addr); + ret = t3_wait_op_done(adap, A_CIM_HOST_ACC_CTRL, F_HOSTBUSY, + 0, 5, 2); + if (!ret) + *valp++ = t3_read_reg(adap, A_CIM_HOST_ACC_DATA); + } + return ret; +} + + +/** + * t3_link_changed - handle interface link changes + * @adapter: the adapter + * @port_id: the port index that changed link state + * + * Called when a port's link settings change to propagate the new values + * to the associated PHY and MAC. After performing the common tasks it + * invokes an OS-specific handler. + */ +void t3_link_changed(struct adapter *adapter, int port_id) +{ + int link_ok, speed, duplex, fc; + struct port_info *pi = adap2pinfo(adapter, port_id); + struct cphy *phy = &pi->phy; + struct cmac *mac = &pi->mac; + struct link_config *lc = &pi->link_config; + + phy->ops->get_link_status(phy, &link_ok, &speed, &duplex, &fc); + + if (link_ok != lc->link_ok && adapter->params.rev > 0 && + uses_xaui(adapter)) { + if (link_ok) + t3b_pcs_reset(mac); + t3_write_reg(adapter, A_XGM_XAUI_ACT_CTRL + mac->offset, + link_ok ? F_TXACTENABLE | F_RXEN : 0); + } + lc->link_ok = link_ok; + lc->speed = speed < 0 ? SPEED_INVALID : speed; + lc->duplex = duplex < 0 ? DUPLEX_INVALID : duplex; + if (lc->requested_fc & PAUSE_AUTONEG) + fc &= lc->requested_fc; + else + fc = lc->requested_fc & (PAUSE_RX | PAUSE_TX); + + if (link_ok && speed >= 0 && lc->autoneg == AUTONEG_ENABLE) { + /* Set MAC speed, duplex, and flow control to match PHY. */ + t3_mac_set_speed_duplex_fc(mac, speed, duplex, fc); + lc->fc = fc; + } + + t3_os_link_changed(adapter, port_id, link_ok, speed, duplex, fc); +} + +/** + * t3_link_start - apply link configuration to MAC/PHY + * @phy: the PHY to setup + * @mac: the MAC to setup + * @lc: the requested link configuration + * + * Set up a port's MAC and PHY according to a desired link configuration. + * - If the PHY can auto-negotiate first decide what to advertise, then + * enable/disable auto-negotiation as desired, and reset. + * - If the PHY does not auto-negotiate just reset it. + * - If auto-negotiation is off set the MAC to the proper speed/duplex/FC, + * otherwise do it later based on the outcome of auto-negotiation. + */ +int t3_link_start(struct cphy *phy, struct cmac *mac, struct link_config *lc) +{ + unsigned int fc = lc->requested_fc & (PAUSE_RX | PAUSE_TX); + + lc->link_ok = 0; + if (lc->supported & SUPPORTED_Autoneg) { + lc->advertising &= ~(ADVERTISED_Asym_Pause | ADVERTISED_Pause); + if (fc) { + lc->advertising |= ADVERTISED_Asym_Pause; + if (fc & PAUSE_RX) + lc->advertising |= ADVERTISED_Pause; + } + phy->ops->advertise(phy, lc->advertising); + + if (lc->autoneg == AUTONEG_DISABLE) { + lc->speed = lc->requested_speed; + lc->duplex = lc->requested_duplex; + lc->fc = (unsigned char)fc; + t3_mac_set_speed_duplex_fc(mac, lc->speed, lc->duplex, + fc); + /* Also disables autoneg */ + phy->ops->set_speed_duplex(phy, lc->speed, lc->duplex); + phy->ops->reset(phy, 0); + } else + phy->ops->autoneg_enable(phy); + } else { + t3_mac_set_speed_duplex_fc(mac, -1, -1, fc); + lc->fc = (unsigned char)fc; + phy->ops->reset(phy, 0); + } + return 0; +} + +/** + * t3_set_vlan_accel - control HW VLAN extraction + * @adapter: the adapter + * @ports: bitmap of adapter ports to operate on + * @on: enable (1) or disable (0) HW VLAN extraction + * + * Enables or disables HW extraction of VLAN tags for the given port. + */ +void t3_set_vlan_accel(struct adapter *adapter, unsigned int ports, int on) +{ + t3_set_reg_field(adapter, A_TP_OUT_CONFIG, + ports << S_VLANEXTRACTIONENABLE, + on ? (ports << S_VLANEXTRACTIONENABLE) : 0); +} + +struct intr_info { + unsigned int mask; /* bits to check in interrupt status */ + const char *msg; /* message to print or NULL */ + short stat_idx; /* stat counter to increment or -1 */ + unsigned short fatal:1; /* whether the condition reported is fatal */ +}; + +/** + * t3_handle_intr_status - table driven interrupt handler + * @adapter: the adapter that generated the interrupt + * @reg: the interrupt status register to process + * @mask: a mask to apply to the interrupt status + * @acts: table of interrupt actions + * @stats: statistics counters tracking interrupt occurences + * + * A table driven interrupt handler that applies a set of masks to an + * interrupt status word and performs the corresponding actions if the + * interrupts described by the mask have occured. The actions include + * optionally printing a warning or alert message, and optionally + * incrementing a stat counter. The table is terminated by an entry + * specifying mask 0. Returns the number of fatal interrupt conditions. + */ +static int t3_handle_intr_status(struct adapter *adapter, unsigned int reg, + unsigned int mask, + const struct intr_info *acts, + unsigned long *stats) +{ + int fatal = 0; + unsigned int status = t3_read_reg(adapter, reg) & mask; + + for (; acts->mask; ++acts) { + if (!(status & acts->mask)) + continue; + if (acts->fatal) { + fatal++; + CH_ALERT(adapter, "%s (0x%x)\n", + acts->msg, status & acts->mask); + } else if (acts->msg) + CH_WARN(adapter, "%s (0x%x)\n", + acts->msg, status & acts->mask); + if (acts->stat_idx >= 0) + stats[acts->stat_idx]++; + } + if (status) /* clear processed interrupts */ + t3_write_reg(adapter, reg, status); + return fatal; +} + +#define SGE_INTR_MASK (F_RSPQDISABLED) +#define MC5_INTR_MASK (F_PARITYERR | F_ACTRGNFULL | F_UNKNOWNCMD | \ + F_REQQPARERR | F_DISPQPARERR | F_DELACTEMPTY | \ + F_NFASRCHFAIL) +#define MC7_INTR_MASK (F_AE | F_UE | F_CE | V_PE(M_PE)) +#define XGM_INTR_MASK (V_TXFIFO_PRTY_ERR(M_TXFIFO_PRTY_ERR) | \ + V_RXFIFO_PRTY_ERR(M_RXFIFO_PRTY_ERR) | \ + F_TXFIFO_UNDERRUN | F_RXFIFO_OVERFLOW) +#define PCIX_INTR_MASK (F_MSTDETPARERR | F_SIGTARABT | F_RCVTARABT | \ + F_RCVMSTABT | F_SIGSYSERR | F_DETPARERR | \ + F_SPLCMPDIS | F_UNXSPLCMP | F_RCVSPLCMPERR | \ + F_DETCORECCERR | F_DETUNCECCERR | F_PIOPARERR | \ + V_WFPARERR(M_WFPARERR) | V_RFPARERR(M_RFPARERR) | \ + V_CFPARERR(M_CFPARERR) /* | V_MSIXPARERR(M_MSIXPARERR) */) +#define PCIE_INTR_MASK (F_UNXSPLCPLERRR | F_UNXSPLCPLERRC | F_PCIE_PIOPARERR |\ + F_PCIE_WFPARERR | F_PCIE_RFPARERR | F_PCIE_CFPARERR | \ + /* V_PCIE_MSIXPARERR(M_PCIE_MSIXPARERR) | */ \ + V_BISTERR(M_BISTERR) | F_PEXERR) +#define ULPRX_INTR_MASK F_PARERR +#define ULPTX_INTR_MASK 0 +#define CPLSW_INTR_MASK (F_TP_FRAMING_ERROR | \ + F_SGE_FRAMING_ERROR | F_CIM_FRAMING_ERROR | \ + F_ZERO_SWITCH_ERROR) +#define CIM_INTR_MASK (F_BLKWRPLINT | F_BLKRDPLINT | F_BLKWRCTLINT | \ + F_BLKRDCTLINT | F_BLKWRFLASHINT | F_BLKRDFLASHINT | \ + F_SGLWRFLASHINT | F_WRBLKFLASHINT | F_BLKWRBOOTINT | \ + F_FLASHRANGEINT | F_SDRAMRANGEINT | F_RSVDSPACEINT) +#define PMTX_INTR_MASK (F_ZERO_C_CMD_ERROR | ICSPI_FRM_ERR | OESPI_FRM_ERR | \ + V_ICSPI_PAR_ERROR(M_ICSPI_PAR_ERROR) | \ + V_OESPI_PAR_ERROR(M_OESPI_PAR_ERROR)) +#define PMRX_INTR_MASK (F_ZERO_E_CMD_ERROR | IESPI_FRM_ERR | OCSPI_FRM_ERR | \ + V_IESPI_PAR_ERROR(M_IESPI_PAR_ERROR) | \ + V_OCSPI_PAR_ERROR(M_OCSPI_PAR_ERROR)) +#define MPS_INTR_MASK (V_TX0TPPARERRENB(M_TX0TPPARERRENB) | \ + V_TX1TPPARERRENB(M_TX1TPPARERRENB) | \ + V_RXTPPARERRENB(M_RXTPPARERRENB) | \ + V_MCAPARERRENB(M_MCAPARERRENB)) +#define PL_INTR_MASK (F_T3DBG | F_XGMAC0_0 | F_XGMAC0_1 | F_MC5A | F_PM1_TX | \ + F_PM1_RX | F_ULP2_TX | F_ULP2_RX | F_TP1 | F_CIM | \ + F_MC7_CM | F_MC7_PMTX | F_MC7_PMRX | F_SGE3 | F_PCIM0 | \ + F_MPS0 | F_CPL_SWITCH) + +/* + * Interrupt handler for the PCIX1 module. + */ +static void pci_intr_handler(struct adapter *adapter) +{ + static const struct intr_info pcix1_intr_info[] = { + {F_MSTDETPARERR, "PCI master detected parity error", -1, 1}, + {F_SIGTARABT, "PCI signaled target abort", -1, 1}, + {F_RCVTARABT, "PCI received target abort", -1, 1}, + {F_RCVMSTABT, "PCI received master abort", -1, 1}, + {F_SIGSYSERR, "PCI signaled system error", -1, 1}, + {F_DETPARERR, "PCI detected parity error", -1, 1}, + {F_SPLCMPDIS, "PCI split completion discarded", -1, 1}, + {F_UNXSPLCMP, "PCI unexpected split completion error", -1, 1}, + {F_RCVSPLCMPERR, "PCI received split completion error", -1, + 1}, + {F_DETCORECCERR, "PCI correctable ECC error", + STAT_PCI_CORR_ECC, 0}, + {F_DETUNCECCERR, "PCI uncorrectable ECC error", -1, 1}, + {F_PIOPARERR, "PCI PIO FIFO parity error", -1, 1}, + {V_WFPARERR(M_WFPARERR), "PCI write FIFO parity error", -1, + 1}, + {V_RFPARERR(M_RFPARERR), "PCI read FIFO parity error", -1, + 1}, + {V_CFPARERR(M_CFPARERR), "PCI command FIFO parity error", -1, + 1}, + {V_MSIXPARERR(M_MSIXPARERR), "PCI MSI-X table/PBA parity " + "error", -1, 1}, + {0} + }; + + if (t3_handle_intr_status(adapter, A_PCIX_INT_CAUSE, PCIX_INTR_MASK, + pcix1_intr_info, adapter->irq_stats)) + t3_fatal_err(adapter); +} + +/* + * Interrupt handler for the PCIE module. + */ +static void pcie_intr_handler(struct adapter *adapter) +{ + static const struct intr_info pcie_intr_info[] = { + {F_PEXERR, "PCI PEX error", -1, 1}, + {F_UNXSPLCPLERRR, + "PCI unexpected split completion DMA read error", -1, 1}, + {F_UNXSPLCPLERRC, + "PCI unexpected split completion DMA command error", -1, 1}, + {F_PCIE_PIOPARERR, "PCI PIO FIFO parity error", -1, 1}, + {F_PCIE_WFPARERR, "PCI write FIFO parity error", -1, 1}, + {F_PCIE_RFPARERR, "PCI read FIFO parity error", -1, 1}, + {F_PCIE_CFPARERR, "PCI command FIFO parity error", -1, 1}, + {V_PCIE_MSIXPARERR(M_PCIE_MSIXPARERR), + "PCI MSI-X table/PBA parity error", -1, 1}, + {V_BISTERR(M_BISTERR), "PCI BIST error", -1, 1}, + {0} + }; + + if (t3_handle_intr_status(adapter, A_PCIE_INT_CAUSE, PCIE_INTR_MASK, + pcie_intr_info, adapter->irq_stats)) + t3_fatal_err(adapter); +} + +/* + * TP interrupt handler. + */ +static void tp_intr_handler(struct adapter *adapter) +{ + static const struct intr_info tp_intr_info[] = { + {0xffffff, "TP parity error", -1, 1}, + {0x1000000, "TP out of Rx pages", -1, 1}, + {0x2000000, "TP out of Tx pages", -1, 1}, + {0} + }; + + if (t3_handle_intr_status(adapter, A_TP_INT_CAUSE, 0xffffffff, + tp_intr_info, NULL)) + t3_fatal_err(adapter); +} + +/* + * CIM interrupt handler. + */ +static void cim_intr_handler(struct adapter *adapter) +{ + static const struct intr_info cim_intr_info[] = { + {F_RSVDSPACEINT, "CIM reserved space write", -1, 1}, + {F_SDRAMRANGEINT, "CIM SDRAM address out of range", -1, 1}, + {F_FLASHRANGEINT, "CIM flash address out of range", -1, 1}, + {F_BLKWRBOOTINT, "CIM block write to boot space", -1, 1}, + {F_WRBLKFLASHINT, "CIM write to cached flash space", -1, 1}, + {F_SGLWRFLASHINT, "CIM single write to flash space", -1, 1}, + {F_BLKRDFLASHINT, "CIM block read from flash space", -1, 1}, + {F_BLKWRFLASHINT, "CIM block write to flash space", -1, 1}, + {F_BLKRDCTLINT, "CIM block read from CTL space", -1, 1}, + {F_BLKWRCTLINT, "CIM block write to CTL space", -1, 1}, + {F_BLKRDPLINT, "CIM block read from PL space", -1, 1}, + {F_BLKWRPLINT, "CIM block write to PL space", -1, 1}, + {0} + }; + + if (t3_handle_intr_status(adapter, A_CIM_HOST_INT_CAUSE, 0xffffffff, + cim_intr_info, NULL)) + t3_fatal_err(adapter); +} + +/* + * ULP RX interrupt handler. + */ +static void ulprx_intr_handler(struct adapter *adapter) +{ + static const struct intr_info ulprx_intr_info[] = { + {F_PARERR, "ULP RX parity error", -1, 1}, + {0} + }; + + if (t3_handle_intr_status(adapter, A_ULPRX_INT_CAUSE, 0xffffffff, + ulprx_intr_info, NULL)) + t3_fatal_err(adapter); +} + +/* + * ULP TX interrupt handler. + */ +static void ulptx_intr_handler(struct adapter *adapter) +{ + static const struct intr_info ulptx_intr_info[] = { + {F_PBL_BOUND_ERR_CH0, "ULP TX channel 0 PBL out of bounds", + STAT_ULP_CH0_PBL_OOB, 0}, + {F_PBL_BOUND_ERR_CH1, "ULP TX channel 1 PBL out of bounds", + STAT_ULP_CH1_PBL_OOB, 0}, + {0} + }; + + if (t3_handle_intr_status(adapter, A_ULPTX_INT_CAUSE, 0xffffffff, + ulptx_intr_info, adapter->irq_stats)) + t3_fatal_err(adapter); +} + +#define ICSPI_FRM_ERR (F_ICSPI0_FIFO2X_RX_FRAMING_ERROR | \ + F_ICSPI1_FIFO2X_RX_FRAMING_ERROR | F_ICSPI0_RX_FRAMING_ERROR | \ + F_ICSPI1_RX_FRAMING_ERROR | F_ICSPI0_TX_FRAMING_ERROR | \ + F_ICSPI1_TX_FRAMING_ERROR) +#define OESPI_FRM_ERR (F_OESPI0_RX_FRAMING_ERROR | \ + F_OESPI1_RX_FRAMING_ERROR | F_OESPI0_TX_FRAMING_ERROR | \ + F_OESPI1_TX_FRAMING_ERROR | F_OESPI0_OFIFO2X_TX_FRAMING_ERROR | \ + F_OESPI1_OFIFO2X_TX_FRAMING_ERROR) + +/* + * PM TX interrupt handler. + */ +static void pmtx_intr_handler(struct adapter *adapter) +{ + static const struct intr_info pmtx_intr_info[] = { + {F_ZERO_C_CMD_ERROR, "PMTX 0-length pcmd", -1, 1}, + {ICSPI_FRM_ERR, "PMTX ispi framing error", -1, 1}, + {OESPI_FRM_ERR, "PMTX ospi framing error", -1, 1}, + {V_ICSPI_PAR_ERROR(M_ICSPI_PAR_ERROR), + "PMTX ispi parity error", -1, 1}, + {V_OESPI_PAR_ERROR(M_OESPI_PAR_ERROR), + "PMTX ospi parity error", -1, 1}, + {0} + }; + + if (t3_handle_intr_status(adapter, A_PM1_TX_INT_CAUSE, 0xffffffff, + pmtx_intr_info, NULL)) + t3_fatal_err(adapter); +} + +#define IESPI_FRM_ERR (F_IESPI0_FIFO2X_RX_FRAMING_ERROR | \ + F_IESPI1_FIFO2X_RX_FRAMING_ERROR | F_IESPI0_RX_FRAMING_ERROR | \ + F_IESPI1_RX_FRAMING_ERROR | F_IESPI0_TX_FRAMING_ERROR | \ + F_IESPI1_TX_FRAMING_ERROR) +#define OCSPI_FRM_ERR (F_OCSPI0_RX_FRAMING_ERROR | \ + F_OCSPI1_RX_FRAMING_ERROR | F_OCSPI0_TX_FRAMING_ERROR | \ + F_OCSPI1_TX_FRAMING_ERROR | F_OCSPI0_OFIFO2X_TX_FRAMING_ERROR | \ + F_OCSPI1_OFIFO2X_TX_FRAMING_ERROR) + +/* + * PM RX interrupt handler. + */ +static void pmrx_intr_handler(struct adapter *adapter) +{ + static const struct intr_info pmrx_intr_info[] = { + {F_ZERO_E_CMD_ERROR, "PMRX 0-length pcmd", -1, 1}, + {IESPI_FRM_ERR, "PMRX ispi framing error", -1, 1}, + {OCSPI_FRM_ERR, "PMRX ospi framing error", -1, 1}, + {V_IESPI_PAR_ERROR(M_IESPI_PAR_ERROR), + "PMRX ispi parity error", -1, 1}, + {V_OCSPI_PAR_ERROR(M_OCSPI_PAR_ERROR), + "PMRX ospi parity error", -1, 1}, + {0} + }; + + if (t3_handle_intr_status(adapter, A_PM1_RX_INT_CAUSE, 0xffffffff, + pmrx_intr_info, NULL)) + t3_fatal_err(adapter); +} + +/* + * CPL switch interrupt handler. + */ +static void cplsw_intr_handler(struct adapter *adapter) +{ + static const struct intr_info cplsw_intr_info[] = { +/* { F_CIM_OVFL_ERROR, "CPL switch CIM overflow", -1, 1 }, */ + {F_TP_FRAMING_ERROR, "CPL switch TP framing error", -1, 1}, + {F_SGE_FRAMING_ERROR, "CPL switch SGE framing error", -1, 1}, + {F_CIM_FRAMING_ERROR, "CPL switch CIM framing error", -1, 1}, + {F_ZERO_SWITCH_ERROR, "CPL switch no-switch error", -1, 1}, + {0} + }; + + if (t3_handle_intr_status(adapter, A_CPL_INTR_CAUSE, 0xffffffff, + cplsw_intr_info, NULL)) + t3_fatal_err(adapter); +} + +/* + * MPS interrupt handler. + */ +static void mps_intr_handler(struct adapter *adapter) +{ + static const struct intr_info mps_intr_info[] = { + {0x1ff, "MPS parity error", -1, 1}, + {0} + }; + + if (t3_handle_intr_status(adapter, A_MPS_INT_CAUSE, 0xffffffff, + mps_intr_info, NULL)) + t3_fatal_err(adapter); +} + +#define MC7_INTR_FATAL (F_UE | V_PE(M_PE) | F_AE) + +/* + * MC7 interrupt handler. + */ +static void mc7_intr_handler(struct mc7 *mc7) +{ + struct adapter *adapter = mc7->adapter; + u32 cause = t3_read_reg(adapter, mc7->offset + A_MC7_INT_CAUSE); + + if (cause & F_CE) { + mc7->stats.corr_err++; + CH_WARN(adapter, "%s MC7 correctable error at addr 0x%x, " + "data 0x%x 0x%x 0x%x\n", mc7->name, + t3_read_reg(adapter, mc7->offset + A_MC7_CE_ADDR), + t3_read_reg(adapter, mc7->offset + A_MC7_CE_DATA0), + t3_read_reg(adapter, mc7->offset + A_MC7_CE_DATA1), + t3_read_reg(adapter, mc7->offset + A_MC7_CE_DATA2)); + } + + if (cause & F_UE) { + mc7->stats.uncorr_err++; + CH_ALERT(adapter, "%s MC7 uncorrectable error at addr 0x%x, " + "data 0x%x 0x%x 0x%x\n", mc7->name, + t3_read_reg(adapter, mc7->offset + A_MC7_UE_ADDR), + t3_read_reg(adapter, mc7->offset + A_MC7_UE_DATA0), + t3_read_reg(adapter, mc7->offset + A_MC7_UE_DATA1), + t3_read_reg(adapter, mc7->offset + A_MC7_UE_DATA2)); + } + + if (G_PE(cause)) { + mc7->stats.parity_err++; + CH_ALERT(adapter, "%s MC7 parity error 0x%x\n", + mc7->name, G_PE(cause)); + } + + if (cause & F_AE) { + u32 addr = 0; + + if (adapter->params.rev > 0) + addr = t3_read_reg(adapter, + mc7->offset + A_MC7_ERR_ADDR); + mc7->stats.addr_err++; + CH_ALERT(adapter, "%s MC7 address error: 0x%x\n", + mc7->name, addr); + } + + if (cause & MC7_INTR_FATAL) + t3_fatal_err(adapter); + + t3_write_reg(adapter, mc7->offset + A_MC7_INT_CAUSE, cause); +} + +#define XGM_INTR_FATAL (V_TXFIFO_PRTY_ERR(M_TXFIFO_PRTY_ERR) | \ + V_RXFIFO_PRTY_ERR(M_RXFIFO_PRTY_ERR)) +/* + * XGMAC interrupt handler. + */ +static int mac_intr_handler(struct adapter *adap, unsigned int idx) +{ + struct cmac *mac = &adap2pinfo(adap, idx)->mac; + u32 cause = t3_read_reg(adap, A_XGM_INT_CAUSE + mac->offset); + + if (cause & V_TXFIFO_PRTY_ERR(M_TXFIFO_PRTY_ERR)) { + mac->stats.tx_fifo_parity_err++; + CH_ALERT(adap, "port%d: MAC TX FIFO parity error\n", idx); + } + if (cause & V_RXFIFO_PRTY_ERR(M_RXFIFO_PRTY_ERR)) { + mac->stats.rx_fifo_parity_err++; + CH_ALERT(adap, "port%d: MAC RX FIFO parity error\n", idx); + } + if (cause & F_TXFIFO_UNDERRUN) + mac->stats.tx_fifo_urun++; + if (cause & F_RXFIFO_OVERFLOW) + mac->stats.rx_fifo_ovfl++; + if (cause & V_SERDES_LOS(M_SERDES_LOS)) + mac->stats.serdes_signal_loss++; + if (cause & F_XAUIPCSCTCERR) + mac->stats.xaui_pcs_ctc_err++; + if (cause & F_XAUIPCSALIGNCHANGE) + mac->stats.xaui_pcs_align_change++; + + t3_write_reg(adap, A_XGM_INT_CAUSE + mac->offset, cause); + if (cause & XGM_INTR_FATAL) + t3_fatal_err(adap); + return cause != 0; +} + +/* + * Interrupt handler for PHY events. + */ +int t3_phy_intr_handler(struct adapter *adapter) +{ + static const int intr_gpio_bits[] = { 8, 0x20 }; + + u32 i, cause = t3_read_reg(adapter, A_T3DBG_INT_CAUSE); + + for_each_port(adapter, i) { + if (cause & intr_gpio_bits[i]) { + struct cphy *phy = &adap2pinfo(adapter, i)->phy; + int phy_cause = phy->ops->intr_handler(phy); + + if (phy_cause & cphy_cause_link_change) + t3_link_changed(adapter, i); + if (phy_cause & cphy_cause_fifo_error) + phy->fifo_errors++; + } + } + + t3_write_reg(adapter, A_T3DBG_INT_CAUSE, cause); + return 0; +} + +/* + * T3 slow path (non-data) interrupt handler. + */ +int t3_slow_intr_handler(struct adapter *adapter) +{ + u32 cause = t3_read_reg(adapter, A_PL_INT_CAUSE0); + + cause &= adapter->slow_intr_mask; + if (!cause) + return 0; + if (cause & F_PCIM0) { + if (is_pcie(adapter)) + pcie_intr_handler(adapter); + else + pci_intr_handler(adapter); + } + if (cause & F_SGE3) + t3_sge_err_intr_handler(adapter); + if (cause & F_MC7_PMRX) + mc7_intr_handler(&adapter->pmrx); + if (cause & F_MC7_PMTX) + mc7_intr_handler(&adapter->pmtx); + if (cause & F_MC7_CM) + mc7_intr_handler(&adapter->cm); + if (cause & F_CIM) + cim_intr_handler(adapter); + if (cause & F_TP1) + tp_intr_handler(adapter); + if (cause & F_ULP2_RX) + ulprx_intr_handler(adapter); + if (cause & F_ULP2_TX) + ulptx_intr_handler(adapter); + if (cause & F_PM1_RX) + pmrx_intr_handler(adapter); + if (cause & F_PM1_TX) + pmtx_intr_handler(adapter); + if (cause & F_CPL_SWITCH) + cplsw_intr_handler(adapter); + if (cause & F_MPS0) + mps_intr_handler(adapter); + if (cause & F_MC5A) + t3_mc5_intr_handler(&adapter->mc5); + if (cause & F_XGMAC0_0) + mac_intr_handler(adapter, 0); + if (cause & F_XGMAC0_1) + mac_intr_handler(adapter, 1); + if (cause & F_T3DBG) + t3_os_ext_intr_handler(adapter); + + /* Clear the interrupts just processed. */ + t3_write_reg(adapter, A_PL_INT_CAUSE0, cause); + t3_read_reg(adapter, A_PL_INT_CAUSE0); /* flush */ + return 1; +} + +/** + * t3_intr_enable - enable interrupts + * @adapter: the adapter whose interrupts should be enabled + * + * Enable interrupts by setting the interrupt enable registers of the + * various HW modules and then enabling the top-level interrupt + * concentrator. + */ +void t3_intr_enable(struct adapter *adapter) +{ + static const struct addr_val_pair intr_en_avp[] = { + {A_SG_INT_ENABLE, SGE_INTR_MASK}, + {A_MC7_INT_ENABLE, MC7_INTR_MASK}, + {A_MC7_INT_ENABLE - MC7_PMRX_BASE_ADDR + MC7_PMTX_BASE_ADDR, + MC7_INTR_MASK}, + {A_MC7_INT_ENABLE - MC7_PMRX_BASE_ADDR + MC7_CM_BASE_ADDR, + MC7_INTR_MASK}, + {A_MC5_DB_INT_ENABLE, MC5_INTR_MASK}, + {A_ULPRX_INT_ENABLE, ULPRX_INTR_MASK}, + {A_TP_INT_ENABLE, 0x3bfffff}, + {A_PM1_TX_INT_ENABLE, PMTX_INTR_MASK}, + {A_PM1_RX_INT_ENABLE, PMRX_INTR_MASK}, + {A_CIM_HOST_INT_ENABLE, CIM_INTR_MASK}, + {A_MPS_INT_ENABLE, MPS_INTR_MASK}, + }; + + adapter->slow_intr_mask = PL_INTR_MASK; + + t3_write_regs(adapter, intr_en_avp, ARRAY_SIZE(intr_en_avp), 0); + + if (adapter->params.rev > 0) { + t3_write_reg(adapter, A_CPL_INTR_ENABLE, + CPLSW_INTR_MASK | F_CIM_OVFL_ERROR); + t3_write_reg(adapter, A_ULPTX_INT_ENABLE, + ULPTX_INTR_MASK | F_PBL_BOUND_ERR_CH0 | + F_PBL_BOUND_ERR_CH1); + } else { + t3_write_reg(adapter, A_CPL_INTR_ENABLE, CPLSW_INTR_MASK); + t3_write_reg(adapter, A_ULPTX_INT_ENABLE, ULPTX_INTR_MASK); + } + + t3_write_reg(adapter, A_T3DBG_GPIO_ACT_LOW, + adapter_info(adapter)->gpio_intr); + t3_write_reg(adapter, A_T3DBG_INT_ENABLE, + adapter_info(adapter)->gpio_intr); + if (is_pcie(adapter)) + t3_write_reg(adapter, A_PCIE_INT_ENABLE, PCIE_INTR_MASK); + else + t3_write_reg(adapter, A_PCIX_INT_ENABLE, PCIX_INTR_MASK); + t3_write_reg(adapter, A_PL_INT_ENABLE0, adapter->slow_intr_mask); + t3_read_reg(adapter, A_PL_INT_ENABLE0); /* flush */ +} + +/** + * t3_intr_disable - disable a card's interrupts + * @adapter: the adapter whose interrupts should be disabled + * + * Disable interrupts. We only disable the top-level interrupt + * concentrator and the SGE data interrupts. + */ +void t3_intr_disable(struct adapter *adapter) +{ + t3_write_reg(adapter, A_PL_INT_ENABLE0, 0); + t3_read_reg(adapter, A_PL_INT_ENABLE0); /* flush */ + adapter->slow_intr_mask = 0; +} + +/** + * t3_intr_clear - clear all interrupts + * @adapter: the adapter whose interrupts should be cleared + * + * Clears all interrupts. + */ +void t3_intr_clear(struct adapter *adapter) +{ + static const unsigned int cause_reg_addr[] = { + A_SG_INT_CAUSE, + A_SG_RSPQ_FL_STATUS, + A_PCIX_INT_CAUSE, + A_MC7_INT_CAUSE, + A_MC7_INT_CAUSE - MC7_PMRX_BASE_ADDR + MC7_PMTX_BASE_ADDR, + A_MC7_INT_CAUSE - MC7_PMRX_BASE_ADDR + MC7_CM_BASE_ADDR, + A_CIM_HOST_INT_CAUSE, + A_TP_INT_CAUSE, + A_MC5_DB_INT_CAUSE, + A_ULPRX_INT_CAUSE, + A_ULPTX_INT_CAUSE, + A_CPL_INTR_CAUSE, + A_PM1_TX_INT_CAUSE, + A_PM1_RX_INT_CAUSE, + A_MPS_INT_CAUSE, + A_T3DBG_INT_CAUSE, + }; + unsigned int i; + + /* Clear PHY and MAC interrupts for each port. */ + for_each_port(adapter, i) + t3_port_intr_clear(adapter, i); + + for (i = 0; i < ARRAY_SIZE(cause_reg_addr); ++i) + t3_write_reg(adapter, cause_reg_addr[i], 0xffffffff); + + t3_write_reg(adapter, A_PL_INT_CAUSE0, 0xffffffff); + t3_read_reg(adapter, A_PL_INT_CAUSE0); /* flush */ +} + +/** + * t3_port_intr_enable - enable port-specific interrupts + * @adapter: associated adapter + * @idx: index of port whose interrupts should be enabled + * + * Enable port-specific (i.e., MAC and PHY) interrupts for the given + * adapter port. + */ +void t3_port_intr_enable(struct adapter *adapter, int idx) +{ + struct cphy *phy = &adap2pinfo(adapter, idx)->phy; + + t3_write_reg(adapter, XGM_REG(A_XGM_INT_ENABLE, idx), XGM_INTR_MASK); + t3_read_reg(adapter, XGM_REG(A_XGM_INT_ENABLE, idx)); /* flush */ + phy->ops->intr_enable(phy); +} + +/** + * t3_port_intr_disable - disable port-specific interrupts + * @adapter: associated adapter + * @idx: index of port whose interrupts should be disabled + * + * Disable port-specific (i.e., MAC and PHY) interrupts for the given + * adapter port. + */ +void t3_port_intr_disable(struct adapter *adapter, int idx) +{ + struct cphy *phy = &adap2pinfo(adapter, idx)->phy; + + t3_write_reg(adapter, XGM_REG(A_XGM_INT_ENABLE, idx), 0); + t3_read_reg(adapter, XGM_REG(A_XGM_INT_ENABLE, idx)); /* flush */ + phy->ops->intr_disable(phy); +} + +/** + * t3_port_intr_clear - clear port-specific interrupts + * @adapter: associated adapter + * @idx: index of port whose interrupts to clear + * + * Clear port-specific (i.e., MAC and PHY) interrupts for the given + * adapter port. + */ +void t3_port_intr_clear(struct adapter *adapter, int idx) +{ + struct cphy *phy = &adap2pinfo(adapter, idx)->phy; + + t3_write_reg(adapter, XGM_REG(A_XGM_INT_CAUSE, idx), 0xffffffff); + t3_read_reg(adapter, XGM_REG(A_XGM_INT_CAUSE, idx)); /* flush */ + phy->ops->intr_clear(phy); +} + +/** + * t3_sge_write_context - write an SGE context + * @adapter: the adapter + * @id: the context id + * @type: the context type + * + * Program an SGE context with the values already loaded in the + * CONTEXT_DATA? registers. + */ +static int t3_sge_write_context(struct adapter *adapter, unsigned int id, + unsigned int type) +{ + t3_write_reg(adapter, A_SG_CONTEXT_MASK0, 0xffffffff); + t3_write_reg(adapter, A_SG_CONTEXT_MASK1, 0xffffffff); + t3_write_reg(adapter, A_SG_CONTEXT_MASK2, 0xffffffff); + t3_write_reg(adapter, A_SG_CONTEXT_MASK3, 0xffffffff); + t3_write_reg(adapter, A_SG_CONTEXT_CMD, + V_CONTEXT_CMD_OPCODE(1) | type | V_CONTEXT(id)); + return t3_wait_op_done(adapter, A_SG_CONTEXT_CMD, F_CONTEXT_CMD_BUSY, + 0, 5, 1); +} + +/** + * t3_sge_init_ecntxt - initialize an SGE egress context + * @adapter: the adapter to configure + * @id: the context id + * @gts_enable: whether to enable GTS for the context + * @type: the egress context type + * @respq: associated response queue + * @base_addr: base address of queue + * @size: number of queue entries + * @token: uP token + * @gen: initial generation value for the context + * @cidx: consumer pointer + * + * Initialize an SGE egress context and make it ready for use. If the + * platform allows concurrent context operations, the caller is + * responsible for appropriate locking. + */ +int t3_sge_init_ecntxt(struct adapter *adapter, unsigned int id, int gts_enable, + enum sge_context_type type, int respq, u64 base_addr, + unsigned int size, unsigned int token, int gen, + unsigned int cidx) +{ + unsigned int credits = type == SGE_CNTXT_OFLD ? 0 : FW_WR_NUM; + + if (base_addr & 0xfff) /* must be 4K aligned */ + return -EINVAL; + if (t3_read_reg(adapter, A_SG_CONTEXT_CMD) & F_CONTEXT_CMD_BUSY) + return -EBUSY; + + base_addr >>= 12; + t3_write_reg(adapter, A_SG_CONTEXT_DATA0, V_EC_INDEX(cidx) | + V_EC_CREDITS(credits) | V_EC_GTS(gts_enable)); + t3_write_reg(adapter, A_SG_CONTEXT_DATA1, V_EC_SIZE(size) | + V_EC_BASE_LO(base_addr & 0xffff)); + base_addr >>= 16; + t3_write_reg(adapter, A_SG_CONTEXT_DATA2, base_addr); + base_addr >>= 32; + t3_write_reg(adapter, A_SG_CONTEXT_DATA3, + V_EC_BASE_HI(base_addr & 0xf) | V_EC_RESPQ(respq) | + V_EC_TYPE(type) | V_EC_GEN(gen) | V_EC_UP_TOKEN(token) | + F_EC_VALID); + return t3_sge_write_context(adapter, id, F_EGRESS); +} + +/** + * t3_sge_init_flcntxt - initialize an SGE free-buffer list context + * @adapter: the adapter to configure + * @id: the context id + * @gts_enable: whether to enable GTS for the context + * @base_addr: base address of queue + * @size: number of queue entries + * @bsize: size of each buffer for this queue + * @cong_thres: threshold to signal congestion to upstream producers + * @gen: initial generation value for the context + * @cidx: consumer pointer + * + * Initialize an SGE free list context and make it ready for use. The + * caller is responsible for ensuring only one context operation occurs + * at a time. + */ +int t3_sge_init_flcntxt(struct adapter *adapter, unsigned int id, + int gts_enable, u64 base_addr, unsigned int size, + unsigned int bsize, unsigned int cong_thres, int gen, + unsigned int cidx) +{ + if (base_addr & 0xfff) /* must be 4K aligned */ + return -EINVAL; + if (t3_read_reg(adapter, A_SG_CONTEXT_CMD) & F_CONTEXT_CMD_BUSY) + return -EBUSY; + + base_addr >>= 12; + t3_write_reg(adapter, A_SG_CONTEXT_DATA0, base_addr); + base_addr >>= 32; + t3_write_reg(adapter, A_SG_CONTEXT_DATA1, + V_FL_BASE_HI((u32) base_addr) | + V_FL_INDEX_LO(cidx & M_FL_INDEX_LO)); + t3_write_reg(adapter, A_SG_CONTEXT_DATA2, V_FL_SIZE(size) | + V_FL_GEN(gen) | V_FL_INDEX_HI(cidx >> 12) | + V_FL_ENTRY_SIZE_LO(bsize & M_FL_ENTRY_SIZE_LO)); + t3_write_reg(adapter, A_SG_CONTEXT_DATA3, + V_FL_ENTRY_SIZE_HI(bsize >> (32 - S_FL_ENTRY_SIZE_LO)) | + V_FL_CONG_THRES(cong_thres) | V_FL_GTS(gts_enable)); + return t3_sge_write_context(adapter, id, F_FREELIST); +} + +/** + * t3_sge_init_rspcntxt - initialize an SGE response queue context + * @adapter: the adapter to configure + * @id: the context id + * @irq_vec_idx: MSI-X interrupt vector index, 0 if no MSI-X, -1 if no IRQ + * @base_addr: base address of queue + * @size: number of queue entries + * @fl_thres: threshold for selecting the normal or jumbo free list + * @gen: initial generation value for the context + * @cidx: consumer pointer + * + * Initialize an SGE response queue context and make it ready for use. + * The caller is responsible for ensuring only one context operation + * occurs at a time. + */ +int t3_sge_init_rspcntxt(struct adapter *adapter, unsigned int id, + int irq_vec_idx, u64 base_addr, unsigned int size, + unsigned int fl_thres, int gen, unsigned int cidx) +{ + unsigned int intr = 0; + + if (base_addr & 0xfff) /* must be 4K aligned */ + return -EINVAL; + if (t3_read_reg(adapter, A_SG_CONTEXT_CMD) & F_CONTEXT_CMD_BUSY) + return -EBUSY; + + base_addr >>= 12; + t3_write_reg(adapter, A_SG_CONTEXT_DATA0, V_CQ_SIZE(size) | + V_CQ_INDEX(cidx)); + t3_write_reg(adapter, A_SG_CONTEXT_DATA1, base_addr); + base_addr >>= 32; + if (irq_vec_idx >= 0) + intr = V_RQ_MSI_VEC(irq_vec_idx) | F_RQ_INTR_EN; + t3_write_reg(adapter, A_SG_CONTEXT_DATA2, + V_CQ_BASE_HI((u32) base_addr) | intr | V_RQ_GEN(gen)); + t3_write_reg(adapter, A_SG_CONTEXT_DATA3, fl_thres); + return t3_sge_write_context(adapter, id, F_RESPONSEQ); +} + +/** + * t3_sge_init_cqcntxt - initialize an SGE completion queue context + * @adapter: the adapter to configure + * @id: the context id + * @base_addr: base address of queue + * @size: number of queue entries + * @rspq: response queue for async notifications + * @ovfl_mode: CQ overflow mode + * @credits: completion queue credits + * @credit_thres: the credit threshold + * + * Initialize an SGE completion queue context and make it ready for use. + * The caller is responsible for ensuring only one context operation + * occurs at a time. + */ +int t3_sge_init_cqcntxt(struct adapter *adapter, unsigned int id, u64 base_addr, + unsigned int size, int rspq, int ovfl_mode, + unsigned int credits, unsigned int credit_thres) +{ + if (base_addr & 0xfff) /* must be 4K aligned */ + return -EINVAL; + if (t3_read_reg(adapter, A_SG_CONTEXT_CMD) & F_CONTEXT_CMD_BUSY) + return -EBUSY; + + base_addr >>= 12; + t3_write_reg(adapter, A_SG_CONTEXT_DATA0, V_CQ_SIZE(size)); + t3_write_reg(adapter, A_SG_CONTEXT_DATA1, base_addr); + base_addr >>= 32; + t3_write_reg(adapter, A_SG_CONTEXT_DATA2, + V_CQ_BASE_HI((u32) base_addr) | V_CQ_RSPQ(rspq) | + V_CQ_GEN(1) | V_CQ_OVERFLOW_MODE(ovfl_mode)); + t3_write_reg(adapter, A_SG_CONTEXT_DATA3, V_CQ_CREDITS(credits) | + V_CQ_CREDIT_THRES(credit_thres)); + return t3_sge_write_context(adapter, id, F_CQ); +} + +/** + * t3_sge_enable_ecntxt - enable/disable an SGE egress context + * @adapter: the adapter + * @id: the egress context id + * @enable: enable (1) or disable (0) the context + * + * Enable or disable an SGE egress context. The caller is responsible for + * ensuring only one context operation occurs at a time. + */ +int t3_sge_enable_ecntxt(struct adapter *adapter, unsigned int id, int enable) +{ + if (t3_read_reg(adapter, A_SG_CONTEXT_CMD) & F_CONTEXT_CMD_BUSY) + return -EBUSY; + + t3_write_reg(adapter, A_SG_CONTEXT_MASK0, 0); + t3_write_reg(adapter, A_SG_CONTEXT_MASK1, 0); + t3_write_reg(adapter, A_SG_CONTEXT_MASK2, 0); + t3_write_reg(adapter, A_SG_CONTEXT_MASK3, F_EC_VALID); + t3_write_reg(adapter, A_SG_CONTEXT_DATA3, V_EC_VALID(enable)); + t3_write_reg(adapter, A_SG_CONTEXT_CMD, + V_CONTEXT_CMD_OPCODE(1) | F_EGRESS | V_CONTEXT(id)); + return t3_wait_op_done(adapter, A_SG_CONTEXT_CMD, F_CONTEXT_CMD_BUSY, + 0, 5, 1); +} + +/** + * t3_sge_disable_fl - disable an SGE free-buffer list + * @adapter: the adapter + * @id: the free list context id + * + * Disable an SGE free-buffer list. The caller is responsible for + * ensuring only one context operation occurs at a time. + */ +int t3_sge_disable_fl(struct adapter *adapter, unsigned int id) +{ + if (t3_read_reg(adapter, A_SG_CONTEXT_CMD) & F_CONTEXT_CMD_BUSY) + return -EBUSY; + + t3_write_reg(adapter, A_SG_CONTEXT_MASK0, 0); + t3_write_reg(adapter, A_SG_CONTEXT_MASK1, 0); + t3_write_reg(adapter, A_SG_CONTEXT_MASK2, V_FL_SIZE(M_FL_SIZE)); + t3_write_reg(adapter, A_SG_CONTEXT_MASK3, 0); + t3_write_reg(adapter, A_SG_CONTEXT_DATA2, 0); + t3_write_reg(adapter, A_SG_CONTEXT_CMD, + V_CONTEXT_CMD_OPCODE(1) | F_FREELIST | V_CONTEXT(id)); + return t3_wait_op_done(adapter, A_SG_CONTEXT_CMD, F_CONTEXT_CMD_BUSY, + 0, 5, 1); +} + +/** + * t3_sge_disable_rspcntxt - disable an SGE response queue + * @adapter: the adapter + * @id: the response queue context id + * + * Disable an SGE response queue. The caller is responsible for + * ensuring only one context operation occurs at a time. + */ +int t3_sge_disable_rspcntxt(struct adapter *adapter, unsigned int id) +{ + if (t3_read_reg(adapter, A_SG_CONTEXT_CMD) & F_CONTEXT_CMD_BUSY) + return -EBUSY; + + t3_write_reg(adapter, A_SG_CONTEXT_MASK0, V_CQ_SIZE(M_CQ_SIZE)); + t3_write_reg(adapter, A_SG_CONTEXT_MASK1, 0); + t3_write_reg(adapter, A_SG_CONTEXT_MASK2, 0); + t3_write_reg(adapter, A_SG_CONTEXT_MASK3, 0); + t3_write_reg(adapter, A_SG_CONTEXT_DATA0, 0); + t3_write_reg(adapter, A_SG_CONTEXT_CMD, + V_CONTEXT_CMD_OPCODE(1) | F_RESPONSEQ | V_CONTEXT(id)); + return t3_wait_op_done(adapter, A_SG_CONTEXT_CMD, F_CONTEXT_CMD_BUSY, + 0, 5, 1); +} + +/** + * t3_sge_disable_cqcntxt - disable an SGE completion queue + * @adapter: the adapter + * @id: the completion queue context id + * + * Disable an SGE completion queue. The caller is responsible for + * ensuring only one context operation occurs at a time. + */ +int t3_sge_disable_cqcntxt(struct adapter *adapter, unsigned int id) +{ + if (t3_read_reg(adapter, A_SG_CONTEXT_CMD) & F_CONTEXT_CMD_BUSY) + return -EBUSY; + + t3_write_reg(adapter, A_SG_CONTEXT_MASK0, V_CQ_SIZE(M_CQ_SIZE)); + t3_write_reg(adapter, A_SG_CONTEXT_MASK1, 0); + t3_write_reg(adapter, A_SG_CONTEXT_MASK2, 0); + t3_write_reg(adapter, A_SG_CONTEXT_MASK3, 0); + t3_write_reg(adapter, A_SG_CONTEXT_DATA0, 0); + t3_write_reg(adapter, A_SG_CONTEXT_CMD, + V_CONTEXT_CMD_OPCODE(1) | F_CQ | V_CONTEXT(id)); + return t3_wait_op_done(adapter, A_SG_CONTEXT_CMD, F_CONTEXT_CMD_BUSY, + 0, 5, 1); +} + +/** + * t3_sge_cqcntxt_op - perform an operation on a completion queue context + * @adapter: the adapter + * @id: the context id + * @op: the operation to perform + * + * Perform the selected operation on an SGE completion queue context. + * The caller is responsible for ensuring only one context operation + * occurs at a time. + */ +int t3_sge_cqcntxt_op(struct adapter *adapter, unsigned int id, unsigned int op, + unsigned int credits) +{ + u32 val; + + if (t3_read_reg(adapter, A_SG_CONTEXT_CMD) & F_CONTEXT_CMD_BUSY) + return -EBUSY; + + t3_write_reg(adapter, A_SG_CONTEXT_DATA0, credits << 16); + t3_write_reg(adapter, A_SG_CONTEXT_CMD, V_CONTEXT_CMD_OPCODE(op) | + V_CONTEXT(id) | F_CQ); + if (t3_wait_op_done_val(adapter, A_SG_CONTEXT_CMD, F_CONTEXT_CMD_BUSY, + 0, 5, 1, &val)) + return -EIO; + + if (op >= 2 && op < 7) { + if (adapter->params.rev > 0) + return G_CQ_INDEX(val); + + t3_write_reg(adapter, A_SG_CONTEXT_CMD, + V_CONTEXT_CMD_OPCODE(0) | F_CQ | V_CONTEXT(id)); + if (t3_wait_op_done(adapter, A_SG_CONTEXT_CMD, + F_CONTEXT_CMD_BUSY, 0, 5, 1)) + return -EIO; + return G_CQ_INDEX(t3_read_reg(adapter, A_SG_CONTEXT_DATA0)); + } + return 0; +} + +/** + * t3_sge_read_context - read an SGE context + * @type: the context type + * @adapter: the adapter + * @id: the context id + * @data: holds the retrieved context + * + * Read an SGE egress context. The caller is responsible for ensuring + * only one context operation occurs at a time. + */ +static int t3_sge_read_context(unsigned int type, struct adapter *adapter, + unsigned int id, u32 data[4]) +{ + if (t3_read_reg(adapter, A_SG_CONTEXT_CMD) & F_CONTEXT_CMD_BUSY) + return -EBUSY; + + t3_write_reg(adapter, A_SG_CONTEXT_CMD, + V_CONTEXT_CMD_OPCODE(0) | type | V_CONTEXT(id)); + if (t3_wait_op_done(adapter, A_SG_CONTEXT_CMD, F_CONTEXT_CMD_BUSY, 0, + 5, 1)) + return -EIO; + data[0] = t3_read_reg(adapter, A_SG_CONTEXT_DATA0); + data[1] = t3_read_reg(adapter, A_SG_CONTEXT_DATA1); + data[2] = t3_read_reg(adapter, A_SG_CONTEXT_DATA2); + data[3] = t3_read_reg(adapter, A_SG_CONTEXT_DATA3); + return 0; +} + +/** + * t3_sge_read_ecntxt - read an SGE egress context + * @adapter: the adapter + * @id: the context id + * @data: holds the retrieved context + * + * Read an SGE egress context. The caller is responsible for ensuring + * only one context operation occurs at a time. + */ +int t3_sge_read_ecntxt(struct adapter *adapter, unsigned int id, u32 data[4]) +{ + if (id >= 65536) + return -EINVAL; + return t3_sge_read_context(F_EGRESS, adapter, id, data); +} + +/** + * t3_sge_read_cq - read an SGE CQ context + * @adapter: the adapter + * @id: the context id + * @data: holds the retrieved context + * + * Read an SGE CQ context. The caller is responsible for ensuring + * only one context operation occurs at a time. + */ +int t3_sge_read_cq(struct adapter *adapter, unsigned int id, u32 data[4]) +{ + if (id >= 65536) + return -EINVAL; + return t3_sge_read_context(F_CQ, adapter, id, data); +} + +/** + * t3_sge_read_fl - read an SGE free-list context + * @adapter: the adapter + * @id: the context id + * @data: holds the retrieved context + * + * Read an SGE free-list context. The caller is responsible for ensuring + * only one context operation occurs at a time. + */ +int t3_sge_read_fl(struct adapter *adapter, unsigned int id, u32 data[4]) +{ + if (id >= SGE_QSETS * 2) + return -EINVAL; + return t3_sge_read_context(F_FREELIST, adapter, id, data); +} + +/** + * t3_sge_read_rspq - read an SGE response queue context + * @adapter: the adapter + * @id: the context id + * @data: holds the retrieved context + * + * Read an SGE response queue context. The caller is responsible for + * ensuring only one context operation occurs at a time. + */ +int t3_sge_read_rspq(struct adapter *adapter, unsigned int id, u32 data[4]) +{ + if (id >= SGE_QSETS) + return -EINVAL; + return t3_sge_read_context(F_RESPONSEQ, adapter, id, data); +} + +/** + * t3_config_rss - configure Rx packet steering + * @adapter: the adapter + * @rss_config: RSS settings (written to TP_RSS_CONFIG) + * @cpus: values for the CPU lookup table (0xff terminated) + * @rspq: values for the response queue lookup table (0xffff terminated) + * + * Programs the receive packet steering logic. @cpus and @rspq provide + * the values for the CPU and response queue lookup tables. If they + * provide fewer values than the size of the tables the supplied values + * are used repeatedly until the tables are fully populated. + */ +void t3_config_rss(struct adapter *adapter, unsigned int rss_config, + const u8 * cpus, const u16 *rspq) +{ + int i, j, cpu_idx = 0, q_idx = 0; + + if (cpus) + for (i = 0; i < RSS_TABLE_SIZE; ++i) { + u32 val = i << 16; + + for (j = 0; j < 2; ++j) { + val |= (cpus[cpu_idx++] & 0x3f) << (8 * j); + if (cpus[cpu_idx] == 0xff) + cpu_idx = 0; + } + t3_write_reg(adapter, A_TP_RSS_LKP_TABLE, val); + } + + if (rspq) + for (i = 0; i < RSS_TABLE_SIZE; ++i) { + t3_write_reg(adapter, A_TP_RSS_MAP_TABLE, + (i << 16) | rspq[q_idx++]); + if (rspq[q_idx] == 0xffff) + q_idx = 0; + } + + t3_write_reg(adapter, A_TP_RSS_CONFIG, rss_config); +} + +/** + * t3_read_rss - read the contents of the RSS tables + * @adapter: the adapter + * @lkup: holds the contents of the RSS lookup table + * @map: holds the contents of the RSS map table + * + * Reads the contents of the receive packet steering tables. + */ +int t3_read_rss(struct adapter *adapter, u8 * lkup, u16 *map) +{ + int i; + u32 val; + + if (lkup) + for (i = 0; i < RSS_TABLE_SIZE; ++i) { + t3_write_reg(adapter, A_TP_RSS_LKP_TABLE, + 0xffff0000 | i); + val = t3_read_reg(adapter, A_TP_RSS_LKP_TABLE); + if (!(val & 0x80000000)) + return -EAGAIN; + *lkup++ = val; + *lkup++ = (val >> 8); + } + + if (map) + for (i = 0; i < RSS_TABLE_SIZE; ++i) { + t3_write_reg(adapter, A_TP_RSS_MAP_TABLE, + 0xffff0000 | i); + val = t3_read_reg(adapter, A_TP_RSS_MAP_TABLE); + if (!(val & 0x80000000)) + return -EAGAIN; + *map++ = val; + } + return 0; +} + +/** + * t3_tp_set_offload_mode - put TP in NIC/offload mode + * @adap: the adapter + * @enable: 1 to select offload mode, 0 for regular NIC + * + * Switches TP to NIC/offload mode. + */ +void t3_tp_set_offload_mode(struct adapter *adap, int enable) +{ + if (is_offload(adap) || !enable) + t3_set_reg_field(adap, A_TP_IN_CONFIG, F_NICMODE, + V_NICMODE(!enable)); +} + +/** + * pm_num_pages - calculate the number of pages of the payload memory + * @mem_size: the size of the payload memory + * @pg_size: the size of each payload memory page + * + * Calculate the number of pages, each of the given size, that fit in a + * memory of the specified size, respecting the HW requirement that the + * number of pages must be a multiple of 24. + */ +static inline unsigned int pm_num_pages(unsigned int mem_size, + unsigned int pg_size) +{ + unsigned int n = mem_size / pg_size; + + return n - n % 24; +} + +#define mem_region(adap, start, size, reg) \ + t3_write_reg((adap), A_ ## reg, (start)); \ + start += size + +/* + * partition_mem - partition memory and configure TP memory settings + * @adap: the adapter + * @p: the TP parameters + * + * Partitions context and payload memory and configures TP's memory + * registers. + */ +static void partition_mem(struct adapter *adap, const struct tp_params *p) +{ + unsigned int m, pstructs, tids = t3_mc5_size(&adap->mc5); + unsigned int timers = 0, timers_shift = 22; + + if (adap->params.rev > 0) { + if (tids <= 16 * 1024) { + timers = 1; + timers_shift = 16; + } else if (tids <= 64 * 1024) { + timers = 2; + timers_shift = 18; + } else if (tids <= 256 * 1024) { + timers = 3; + timers_shift = 20; + } + } + + t3_write_reg(adap, A_TP_PMM_SIZE, + p->chan_rx_size | (p->chan_tx_size >> 16)); + + t3_write_reg(adap, A_TP_PMM_TX_BASE, 0); + t3_write_reg(adap, A_TP_PMM_TX_PAGE_SIZE, p->tx_pg_size); + t3_write_reg(adap, A_TP_PMM_TX_MAX_PAGE, p->tx_num_pgs); + t3_set_reg_field(adap, A_TP_PARA_REG3, V_TXDATAACKIDX(M_TXDATAACKIDX), + V_TXDATAACKIDX(fls(p->tx_pg_size) - 12)); + + t3_write_reg(adap, A_TP_PMM_RX_BASE, 0); + t3_write_reg(adap, A_TP_PMM_RX_PAGE_SIZE, p->rx_pg_size); + t3_write_reg(adap, A_TP_PMM_RX_MAX_PAGE, p->rx_num_pgs); + + pstructs = p->rx_num_pgs + p->tx_num_pgs; + /* Add a bit of headroom and make multiple of 24 */ + pstructs += 48; + pstructs -= pstructs % 24; + t3_write_reg(adap, A_TP_CMM_MM_MAX_PSTRUCT, pstructs); + + m = tids * TCB_SIZE; + mem_region(adap, m, (64 << 10) * 64, SG_EGR_CNTX_BADDR); + mem_region(adap, m, (64 << 10) * 64, SG_CQ_CONTEXT_BADDR); + t3_write_reg(adap, A_TP_CMM_TIMER_BASE, V_CMTIMERMAXNUM(timers) | m); + m += ((p->ntimer_qs - 1) << timers_shift) + (1 << 22); + mem_region(adap, m, pstructs * 64, TP_CMM_MM_BASE); + mem_region(adap, m, 64 * (pstructs / 24), TP_CMM_MM_PS_FLST_BASE); + mem_region(adap, m, 64 * (p->rx_num_pgs / 24), TP_CMM_MM_RX_FLST_BASE); + mem_region(adap, m, 64 * (p->tx_num_pgs / 24), TP_CMM_MM_TX_FLST_BASE); + + m = (m + 4095) & ~0xfff; + t3_write_reg(adap, A_CIM_SDRAM_BASE_ADDR, m); + t3_write_reg(adap, A_CIM_SDRAM_ADDR_SIZE, p->cm_size - m); + + tids = (p->cm_size - m - (3 << 20)) / 3072 - 32; + m = t3_mc5_size(&adap->mc5) - adap->params.mc5.nservers - + adap->params.mc5.nfilters - adap->params.mc5.nroutes; + if (tids < m) + adap->params.mc5.nservers += m - tids; +} + +static inline void tp_wr_indirect(struct adapter *adap, unsigned int addr, + u32 val) +{ + t3_write_reg(adap, A_TP_PIO_ADDR, addr); + t3_write_reg(adap, A_TP_PIO_DATA, val); +} + +static void tp_config(struct adapter *adap, const struct tp_params *p) +{ + t3_write_reg(adap, A_TP_GLOBAL_CONFIG, F_TXPACINGENABLE | F_PATHMTU | + F_IPCHECKSUMOFFLOAD | F_UDPCHECKSUMOFFLOAD | + F_TCPCHECKSUMOFFLOAD | V_IPTTL(64)); + t3_write_reg(adap, A_TP_TCP_OPTIONS, V_MTUDEFAULT(576) | + F_MTUENABLE | V_WINDOWSCALEMODE(1) | + V_TIMESTAMPSMODE(1) | V_SACKMODE(1) | V_SACKRX(1)); + t3_write_reg(adap, A_TP_DACK_CONFIG, V_AUTOSTATE3(1) | + V_AUTOSTATE2(1) | V_AUTOSTATE1(0) | + V_BYTETHRESHOLD(16384) | V_MSSTHRESHOLD(2) | + F_AUTOCAREFUL | F_AUTOENABLE | V_DACK_MODE(1)); + t3_set_reg_field(adap, A_TP_IN_CONFIG, F_IPV6ENABLE | F_NICMODE, + F_IPV6ENABLE | F_NICMODE); + t3_write_reg(adap, A_TP_TX_RESOURCE_LIMIT, 0x18141814); + t3_write_reg(adap, A_TP_PARA_REG4, 0x5050105); + t3_set_reg_field(adap, A_TP_PARA_REG6, + adap->params.rev > 0 ? F_ENABLEESND : F_T3A_ENABLEESND, + 0); + + t3_set_reg_field(adap, A_TP_PC_CONFIG, + F_ENABLEEPCMDAFULL | F_ENABLEOCSPIFULL, + F_TXDEFERENABLE | F_HEARBEATDACK | F_TXCONGESTIONMODE | + F_RXCONGESTIONMODE); + t3_set_reg_field(adap, A_TP_PC_CONFIG2, F_CHDRAFULL, 0); + + if (adap->params.rev > 0) { + tp_wr_indirect(adap, A_TP_EGRESS_CONFIG, F_REWRITEFORCETOSIZE); + t3_set_reg_field(adap, A_TP_PARA_REG3, F_TXPACEAUTO, + F_TXPACEAUTO); + t3_set_reg_field(adap, A_TP_PC_CONFIG, F_LOCKTID, F_LOCKTID); + t3_set_reg_field(adap, A_TP_PARA_REG3, 0, F_TXPACEAUTOSTRICT); + } else + t3_set_reg_field(adap, A_TP_PARA_REG3, 0, F_TXPACEFIXED); + + t3_write_reg(adap, A_TP_TX_MOD_QUEUE_WEIGHT1, 0x12121212); + t3_write_reg(adap, A_TP_TX_MOD_QUEUE_WEIGHT0, 0x12121212); + t3_write_reg(adap, A_TP_MOD_CHANNEL_WEIGHT, 0x1212); +} + +/* Desired TP timer resolution in usec */ +#define TP_TMR_RES 50 + +/* TCP timer values in ms */ +#define TP_DACK_TIMER 50 +#define TP_RTO_MIN 250 + +/** + * tp_set_timers - set TP timing parameters + * @adap: the adapter to set + * @core_clk: the core clock frequency in Hz + * + * Set TP's timing parameters, such as the various timer resolutions and + * the TCP timer values. + */ +static void tp_set_timers(struct adapter *adap, unsigned int core_clk) +{ + unsigned int tre = fls(core_clk / (1000000 / TP_TMR_RES)) - 1; + unsigned int dack_re = fls(core_clk / 5000) - 1; /* 200us */ + unsigned int tstamp_re = fls(core_clk / 1000); /* 1ms, at least */ + unsigned int tps = core_clk >> tre; + + t3_write_reg(adap, A_TP_TIMER_RESOLUTION, V_TIMERRESOLUTION(tre) | + V_DELAYEDACKRESOLUTION(dack_re) | + V_TIMESTAMPRESOLUTION(tstamp_re)); + t3_write_reg(adap, A_TP_DACK_TIMER, + (core_clk >> dack_re) / (1000 / TP_DACK_TIMER)); + t3_write_reg(adap, A_TP_TCP_BACKOFF_REG0, 0x3020100); + t3_write_reg(adap, A_TP_TCP_BACKOFF_REG1, 0x7060504); + t3_write_reg(adap, A_TP_TCP_BACKOFF_REG2, 0xb0a0908); + t3_write_reg(adap, A_TP_TCP_BACKOFF_REG3, 0xf0e0d0c); + t3_write_reg(adap, A_TP_SHIFT_CNT, V_SYNSHIFTMAX(6) | + V_RXTSHIFTMAXR1(4) | V_RXTSHIFTMAXR2(15) | + V_PERSHIFTBACKOFFMAX(8) | V_PERSHIFTMAX(8) | + V_KEEPALIVEMAX(9)); + +#define SECONDS * tps + + t3_write_reg(adap, A_TP_MSL, adap->params.rev > 0 ? 0 : 2 SECONDS); + t3_write_reg(adap, A_TP_RXT_MIN, tps / (1000 / TP_RTO_MIN)); + t3_write_reg(adap, A_TP_RXT_MAX, 64 SECONDS); + t3_write_reg(adap, A_TP_PERS_MIN, 5 SECONDS); + t3_write_reg(adap, A_TP_PERS_MAX, 64 SECONDS); + t3_write_reg(adap, A_TP_KEEP_IDLE, 7200 SECONDS); + t3_write_reg(adap, A_TP_KEEP_INTVL, 75 SECONDS); + t3_write_reg(adap, A_TP_INIT_SRTT, 3 SECONDS); + t3_write_reg(adap, A_TP_FINWAIT2_TIMER, 600 SECONDS); + +#undef SECONDS +} + +/** + * t3_tp_set_coalescing_size - set receive coalescing size + * @adap: the adapter + * @size: the receive coalescing size + * @psh: whether a set PSH bit should deliver coalesced data + * + * Set the receive coalescing size and PSH bit handling. + */ +int t3_tp_set_coalescing_size(struct adapter *adap, unsigned int size, int psh) +{ + u32 val; + + if (size > MAX_RX_COALESCING_LEN) + return -EINVAL; + + val = t3_read_reg(adap, A_TP_PARA_REG3); + val &= ~(F_RXCOALESCEENABLE | F_RXCOALESCEPSHEN); + + if (size) { + val |= F_RXCOALESCEENABLE; + if (psh) + val |= F_RXCOALESCEPSHEN; + t3_write_reg(adap, A_TP_PARA_REG2, V_RXCOALESCESIZE(size) | + V_MAXRXDATA(MAX_RX_COALESCING_LEN)); + } + t3_write_reg(adap, A_TP_PARA_REG3, val); + return 0; +} + +/** + * t3_tp_set_max_rxsize - set the max receive size + * @adap: the adapter + * @size: the max receive size + * + * Set TP's max receive size. This is the limit that applies when + * receive coalescing is disabled. + */ +void t3_tp_set_max_rxsize(struct adapter *adap, unsigned int size) +{ + t3_write_reg(adap, A_TP_PARA_REG7, + V_PMMAXXFERLEN0(size) | V_PMMAXXFERLEN1(size)); +} + +static void __devinit init_mtus(unsigned short mtus[]) +{ + /* + * See draft-mathis-plpmtud-00.txt for the values. The min is 88 so + * it can accomodate max size TCP/IP headers when SACK and timestamps + * are enabled and still have at least 8 bytes of payload. + */ + mtus[0] = 88; + mtus[1] = 256; + mtus[2] = 512; + mtus[3] = 576; + mtus[4] = 808; + mtus[5] = 1024; + mtus[6] = 1280; + mtus[7] = 1492; + mtus[8] = 1500; + mtus[9] = 2002; + mtus[10] = 2048; + mtus[11] = 4096; + mtus[12] = 4352; + mtus[13] = 8192; + mtus[14] = 9000; + mtus[15] = 9600; +} + +/* + * Initial congestion control parameters. + */ +static void __devinit init_cong_ctrl(unsigned short *a, unsigned short *b) +{ + a[0] = a[1] = a[2] = a[3] = a[4] = a[5] = a[6] = a[7] = a[8] = 1; + a[9] = 2; + a[10] = 3; + a[11] = 4; + a[12] = 5; + a[13] = 6; + a[14] = 7; + a[15] = 8; + a[16] = 9; + a[17] = 10; + a[18] = 14; + a[19] = 17; + a[20] = 21; + a[21] = 25; + a[22] = 30; + a[23] = 35; + a[24] = 45; + a[25] = 60; + a[26] = 80; + a[27] = 100; + a[28] = 200; + a[29] = 300; + a[30] = 400; + a[31] = 500; + + b[0] = b[1] = b[2] = b[3] = b[4] = b[5] = b[6] = b[7] = b[8] = 0; + b[9] = b[10] = 1; + b[11] = b[12] = 2; + b[13] = b[14] = b[15] = b[16] = 3; + b[17] = b[18] = b[19] = b[20] = b[21] = 4; + b[22] = b[23] = b[24] = b[25] = b[26] = b[27] = 5; + b[28] = b[29] = 6; + b[30] = b[31] = 7; +} + +/* The minimum additive increment value for the congestion control table */ +#define CC_MIN_INCR 2U + +/** + * t3_load_mtus - write the MTU and congestion control HW tables + * @adap: the adapter + * @mtus: the unrestricted values for the MTU table + * @alphs: the values for the congestion control alpha parameter + * @beta: the values for the congestion control beta parameter + * @mtu_cap: the maximum permitted effective MTU + * + * Write the MTU table with the supplied MTUs capping each at &mtu_cap. + * Update the high-speed congestion control table with the supplied alpha, + * beta, and MTUs. + */ +void t3_load_mtus(struct adapter *adap, unsigned short mtus[NMTUS], + unsigned short alpha[NCCTRL_WIN], + unsigned short beta[NCCTRL_WIN], unsigned short mtu_cap) +{ + static const unsigned int avg_pkts[NCCTRL_WIN] = { + 2, 6, 10, 14, 20, 28, 40, 56, 80, 112, 160, 224, 320, 448, 640, + 896, 1281, 1792, 2560, 3584, 5120, 7168, 10240, 14336, 20480, + 28672, 40960, 57344, 81920, 114688, 163840, 229376 + }; + + unsigned int i, w; + + for (i = 0; i < NMTUS; ++i) { + unsigned int mtu = min(mtus[i], mtu_cap); + unsigned int log2 = fls(mtu); + + if (!(mtu & ((1 << log2) >> 2))) /* round */ + log2--; + t3_write_reg(adap, A_TP_MTU_TABLE, + (i << 24) | (log2 << 16) | mtu); + + for (w = 0; w < NCCTRL_WIN; ++w) { + unsigned int inc; + + inc = max(((mtu - 40) * alpha[w]) / avg_pkts[w], + CC_MIN_INCR); + + t3_write_reg(adap, A_TP_CCTRL_TABLE, (i << 21) | + (w << 16) | (beta[w] << 13) | inc); + } + } +} + +/** + * t3_read_hw_mtus - returns the values in the HW MTU table + * @adap: the adapter + * @mtus: where to store the HW MTU values + * + * Reads the HW MTU table. + */ +void t3_read_hw_mtus(struct adapter *adap, unsigned short mtus[NMTUS]) +{ + int i; + + for (i = 0; i < NMTUS; ++i) { + unsigned int val; + + t3_write_reg(adap, A_TP_MTU_TABLE, 0xff000000 | i); + val = t3_read_reg(adap, A_TP_MTU_TABLE); + mtus[i] = val & 0x3fff; + } +} + +/** + * t3_get_cong_cntl_tab - reads the congestion control table + * @adap: the adapter + * @incr: where to store the alpha values + * + * Reads the additive increments programmed into the HW congestion + * control table. + */ +void t3_get_cong_cntl_tab(struct adapter *adap, + unsigned short incr[NMTUS][NCCTRL_WIN]) +{ + unsigned int mtu, w; + + for (mtu = 0; mtu < NMTUS; ++mtu) + for (w = 0; w < NCCTRL_WIN; ++w) { + t3_write_reg(adap, A_TP_CCTRL_TABLE, + 0xffff0000 | (mtu << 5) | w); + incr[mtu][w] = t3_read_reg(adap, A_TP_CCTRL_TABLE) & + 0x1fff; + } +} + +/** + * t3_tp_get_mib_stats - read TP's MIB counters + * @adap: the adapter + * @tps: holds the returned counter values + * + * Returns the values of TP's MIB counters. + */ +void t3_tp_get_mib_stats(struct adapter *adap, struct tp_mib_stats *tps) +{ + t3_read_indirect(adap, A_TP_MIB_INDEX, A_TP_MIB_RDATA, (u32 *) tps, + sizeof(*tps) / sizeof(u32), 0); +} + +#define ulp_region(adap, name, start, len) \ + t3_write_reg((adap), A_ULPRX_ ## name ## _LLIMIT, (start)); \ + t3_write_reg((adap), A_ULPRX_ ## name ## _ULIMIT, \ + (start) + (len) - 1); \ + start += len + +#define ulptx_region(adap, name, start, len) \ + t3_write_reg((adap), A_ULPTX_ ## name ## _LLIMIT, (start)); \ + t3_write_reg((adap), A_ULPTX_ ## name ## _ULIMIT, \ + (start) + (len) - 1) + +static void ulp_config(struct adapter *adap, const struct tp_params *p) +{ + unsigned int m = p->chan_rx_size; + + ulp_region(adap, ISCSI, m, p->chan_rx_size / 8); + ulp_region(adap, TDDP, m, p->chan_rx_size / 8); + ulptx_region(adap, TPT, m, p->chan_rx_size / 4); + ulp_region(adap, STAG, m, p->chan_rx_size / 4); + ulp_region(adap, RQ, m, p->chan_rx_size / 4); + ulptx_region(adap, PBL, m, p->chan_rx_size / 4); + ulp_region(adap, PBL, m, p->chan_rx_size / 4); + t3_write_reg(adap, A_ULPRX_TDDP_TAGMASK, 0xffffffff); +} + +void t3_config_trace_filter(struct adapter *adapter, + const struct trace_params *tp, int filter_index, + int invert, int enable) +{ + u32 addr, key[4], mask[4]; + + key[0] = tp->sport | (tp->sip << 16); + key[1] = (tp->sip >> 16) | (tp->dport << 16); + key[2] = tp->dip; + key[3] = tp->proto | (tp->vlan << 8) | (tp->intf << 20); + + mask[0] = tp->sport_mask | (tp->sip_mask << 16); + mask[1] = (tp->sip_mask >> 16) | (tp->dport_mask << 16); + mask[2] = tp->dip_mask; + mask[3] = tp->proto_mask | (tp->vlan_mask << 8) | (tp->intf_mask << 20); + + if (invert) + key[3] |= (1 << 29); + if (enable) + key[3] |= (1 << 28); + + addr = filter_index ? A_TP_RX_TRC_KEY0 : A_TP_TX_TRC_KEY0; + tp_wr_indirect(adapter, addr++, key[0]); + tp_wr_indirect(adapter, addr++, mask[0]); + tp_wr_indirect(adapter, addr++, key[1]); + tp_wr_indirect(adapter, addr++, mask[1]); + tp_wr_indirect(adapter, addr++, key[2]); + tp_wr_indirect(adapter, addr++, mask[2]); + tp_wr_indirect(adapter, addr++, key[3]); + tp_wr_indirect(adapter, addr, mask[3]); + t3_read_reg(adapter, A_TP_PIO_DATA); +} + +/** + * t3_config_sched - configure a HW traffic scheduler + * @adap: the adapter + * @kbps: target rate in Kbps + * @sched: the scheduler index + * + * Configure a HW scheduler for the target rate + */ +int t3_config_sched(struct adapter *adap, unsigned int kbps, int sched) +{ + unsigned int v, tps, cpt, bpt, delta, mindelta = ~0; + unsigned int clk = adap->params.vpd.cclk * 1000; + unsigned int selected_cpt = 0, selected_bpt = 0; + + if (kbps > 0) { + kbps *= 125; /* -> bytes */ + for (cpt = 1; cpt <= 255; cpt++) { + tps = clk / cpt; + bpt = (kbps + tps / 2) / tps; + if (bpt > 0 && bpt <= 255) { + v = bpt * tps; + delta = v >= kbps ? v - kbps : kbps - v; + if (delta <= mindelta) { + mindelta = delta; + selected_cpt = cpt; + selected_bpt = bpt; + } + } else if (selected_cpt) + break; + } + if (!selected_cpt) + return -EINVAL; + } + t3_write_reg(adap, A_TP_TM_PIO_ADDR, + A_TP_TX_MOD_Q1_Q0_RATE_LIMIT - sched / 2); + v = t3_read_reg(adap, A_TP_TM_PIO_DATA); + if (sched & 1) + v = (v & 0xffff) | (selected_cpt << 16) | (selected_bpt << 24); + else + v = (v & 0xffff0000) | selected_cpt | (selected_bpt << 8); + t3_write_reg(adap, A_TP_TM_PIO_DATA, v); + return 0; +} + +static int tp_init(struct adapter *adap, const struct tp_params *p) +{ + int busy = 0; + + tp_config(adap, p); + t3_set_vlan_accel(adap, 3, 0); + + if (is_offload(adap)) { + tp_set_timers(adap, adap->params.vpd.cclk * 1000); + t3_write_reg(adap, A_TP_RESET, F_FLSTINITENABLE); + busy = t3_wait_op_done(adap, A_TP_RESET, F_FLSTINITENABLE, + 0, 1000, 5); + if (busy) + CH_ERR(adap, "TP initialization timed out\n"); + } + + if (!busy) + t3_write_reg(adap, A_TP_RESET, F_TPRESET); + return busy; +} + +int t3_mps_set_active_ports(struct adapter *adap, unsigned int port_mask) +{ + if (port_mask & ~((1 << adap->params.nports) - 1)) + return -EINVAL; + t3_set_reg_field(adap, A_MPS_CFG, F_PORT1ACTIVE | F_PORT0ACTIVE, + port_mask << S_PORT0ACTIVE); + return 0; +} + +/* + * Perform the bits of HW initialization that are dependent on the number + * of available ports. + */ +static void init_hw_for_avail_ports(struct adapter *adap, int nports) +{ + int i; + + if (nports == 1) { + t3_set_reg_field(adap, A_ULPRX_CTL, F_ROUND_ROBIN, 0); + t3_set_reg_field(adap, A_ULPTX_CONFIG, F_CFG_RR_ARB, 0); + t3_write_reg(adap, A_MPS_CFG, F_TPRXPORTEN | F_TPTXPORT0EN | + F_PORT0ACTIVE | F_ENFORCEPKT); + t3_write_reg(adap, A_PM1_TX_CFG, 0xc000c000); + } else { + t3_set_reg_field(adap, A_ULPRX_CTL, 0, F_ROUND_ROBIN); + t3_set_reg_field(adap, A_ULPTX_CONFIG, 0, F_CFG_RR_ARB); + t3_write_reg(adap, A_ULPTX_DMA_WEIGHT, + V_D1_WEIGHT(16) | V_D0_WEIGHT(16)); + t3_write_reg(adap, A_MPS_CFG, F_TPTXPORT0EN | F_TPTXPORT1EN | + F_TPRXPORTEN | F_PORT0ACTIVE | F_PORT1ACTIVE | + F_ENFORCEPKT); + t3_write_reg(adap, A_PM1_TX_CFG, 0x80008000); + t3_set_reg_field(adap, A_TP_PC_CONFIG, 0, F_TXTOSQUEUEMAPMODE); + t3_write_reg(adap, A_TP_TX_MOD_QUEUE_REQ_MAP, + V_TX_MOD_QUEUE_REQ_MAP(0xaa)); + for (i = 0; i < 16; i++) + t3_write_reg(adap, A_TP_TX_MOD_QUE_TABLE, + (i << 16) | 0x1010); + } +} + +static int calibrate_xgm(struct adapter *adapter) +{ + if (uses_xaui(adapter)) { + unsigned int v, i; + + for (i = 0; i < 5; ++i) { + t3_write_reg(adapter, A_XGM_XAUI_IMP, 0); + t3_read_reg(adapter, A_XGM_XAUI_IMP); + msleep(1); + v = t3_read_reg(adapter, A_XGM_XAUI_IMP); + if (!(v & (F_XGM_CALFAULT | F_CALBUSY))) { + t3_write_reg(adapter, A_XGM_XAUI_IMP, + V_XAUIIMP(G_CALIMP(v) >> 2)); + return 0; + } + } + CH_ERR(adapter, "MAC calibration failed\n"); + return -1; + } else { + t3_write_reg(adapter, A_XGM_RGMII_IMP, + V_RGMIIIMPPD(2) | V_RGMIIIMPPU(3)); + t3_set_reg_field(adapter, A_XGM_RGMII_IMP, F_XGM_IMPSETUPDATE, + F_XGM_IMPSETUPDATE); + } + return 0; +} + +static void calibrate_xgm_t3b(struct adapter *adapter) +{ + if (!uses_xaui(adapter)) { + t3_write_reg(adapter, A_XGM_RGMII_IMP, F_CALRESET | + F_CALUPDATE | V_RGMIIIMPPD(2) | V_RGMIIIMPPU(3)); + t3_set_reg_field(adapter, A_XGM_RGMII_IMP, F_CALRESET, 0); + t3_set_reg_field(adapter, A_XGM_RGMII_IMP, 0, + F_XGM_IMPSETUPDATE); + t3_set_reg_field(adapter, A_XGM_RGMII_IMP, F_XGM_IMPSETUPDATE, + 0); + t3_set_reg_field(adapter, A_XGM_RGMII_IMP, F_CALUPDATE, 0); + t3_set_reg_field(adapter, A_XGM_RGMII_IMP, 0, F_CALUPDATE); + } +} + +struct mc7_timing_params { + unsigned char ActToPreDly; + unsigned char ActToRdWrDly; + unsigned char PreCyc; + unsigned char RefCyc[5]; + unsigned char BkCyc; + unsigned char WrToRdDly; + unsigned char RdToWrDly; +}; + +/* + * Write a value to a register and check that the write completed. These + * writes normally complete in a cycle or two, so one read should suffice. + * The very first read exists to flush the posted write to the device. + */ +static int wrreg_wait(struct adapter *adapter, unsigned int addr, u32 val) +{ + t3_write_reg(adapter, addr, val); + t3_read_reg(adapter, addr); /* flush */ + if (!(t3_read_reg(adapter, addr) & F_BUSY)) + return 0; + CH_ERR(adapter, "write to MC7 register 0x%x timed out\n", addr); + return -EIO; +} + +static int mc7_init(struct mc7 *mc7, unsigned int mc7_clock, int mem_type) +{ + static const unsigned int mc7_mode[] = { + 0x632, 0x642, 0x652, 0x432, 0x442 + }; + static const struct mc7_timing_params mc7_timings[] = { + {12, 3, 4, {20, 28, 34, 52, 0}, 15, 6, 4}, + {12, 4, 5, {20, 28, 34, 52, 0}, 16, 7, 4}, + {12, 5, 6, {20, 28, 34, 52, 0}, 17, 8, 4}, + {9, 3, 4, {15, 21, 26, 39, 0}, 12, 6, 4}, + {9, 4, 5, {15, 21, 26, 39, 0}, 13, 7, 4} + }; + + u32 val; + unsigned int width, density, slow, attempts; + struct adapter *adapter = mc7->adapter; + const struct mc7_timing_params *p = &mc7_timings[mem_type]; + + val = t3_read_reg(adapter, mc7->offset + A_MC7_CFG); + slow = val & F_SLOW; + width = G_WIDTH(val); + density = G_DEN(val); + + t3_write_reg(adapter, mc7->offset + A_MC7_CFG, val | F_IFEN); + val = t3_read_reg(adapter, mc7->offset + A_MC7_CFG); /* flush */ + msleep(1); + + if (!slow) { + t3_write_reg(adapter, mc7->offset + A_MC7_CAL, F_SGL_CAL_EN); + t3_read_reg(adapter, mc7->offset + A_MC7_CAL); + msleep(1); + if (t3_read_reg(adapter, mc7->offset + A_MC7_CAL) & + (F_BUSY | F_SGL_CAL_EN | F_CAL_FAULT)) { + CH_ERR(adapter, "%s MC7 calibration timed out\n", + mc7->name); + goto out_fail; + } + } + + t3_write_reg(adapter, mc7->offset + A_MC7_PARM, + V_ACTTOPREDLY(p->ActToPreDly) | + V_ACTTORDWRDLY(p->ActToRdWrDly) | V_PRECYC(p->PreCyc) | + V_REFCYC(p->RefCyc[density]) | V_BKCYC(p->BkCyc) | + V_WRTORDDLY(p->WrToRdDly) | V_RDTOWRDLY(p->RdToWrDly)); + + t3_write_reg(adapter, mc7->offset + A_MC7_CFG, + val | F_CLKEN | F_TERM150); + t3_read_reg(adapter, mc7->offset + A_MC7_CFG); /* flush */ + + if (!slow) + t3_set_reg_field(adapter, mc7->offset + A_MC7_DLL, F_DLLENB, + F_DLLENB); + udelay(1); + + val = slow ? 3 : 6; + if (wrreg_wait(adapter, mc7->offset + A_MC7_PRE, 0) || + wrreg_wait(adapter, mc7->offset + A_MC7_EXT_MODE2, 0) || + wrreg_wait(adapter, mc7->offset + A_MC7_EXT_MODE3, 0) || + wrreg_wait(adapter, mc7->offset + A_MC7_EXT_MODE1, val)) + goto out_fail; + + if (!slow) { + t3_write_reg(adapter, mc7->offset + A_MC7_MODE, 0x100); + t3_set_reg_field(adapter, mc7->offset + A_MC7_DLL, F_DLLRST, 0); + udelay(5); + } + + if (wrreg_wait(adapter, mc7->offset + A_MC7_PRE, 0) || + wrreg_wait(adapter, mc7->offset + A_MC7_REF, 0) || + wrreg_wait(adapter, mc7->offset + A_MC7_REF, 0) || + wrreg_wait(adapter, mc7->offset + A_MC7_MODE, + mc7_mode[mem_type]) || + wrreg_wait(adapter, mc7->offset + A_MC7_EXT_MODE1, val | 0x380) || + wrreg_wait(adapter, mc7->offset + A_MC7_EXT_MODE1, val)) + goto out_fail; + + /* clock value is in KHz */ + mc7_clock = mc7_clock * 7812 + mc7_clock / 2; /* ns */ + mc7_clock /= 1000000; /* KHz->MHz, ns->us */ + + t3_write_reg(adapter, mc7->offset + A_MC7_REF, + F_PERREFEN | V_PREREFDIV(mc7_clock)); + t3_read_reg(adapter, mc7->offset + A_MC7_REF); /* flush */ + + t3_write_reg(adapter, mc7->offset + A_MC7_ECC, F_ECCGENEN | F_ECCCHKEN); + t3_write_reg(adapter, mc7->offset + A_MC7_BIST_DATA, 0); + t3_write_reg(adapter, mc7->offset + A_MC7_BIST_ADDR_BEG, 0); + t3_write_reg(adapter, mc7->offset + A_MC7_BIST_ADDR_END, + (mc7->size << width) - 1); + t3_write_reg(adapter, mc7->offset + A_MC7_BIST_OP, V_OP(1)); + t3_read_reg(adapter, mc7->offset + A_MC7_BIST_OP); /* flush */ + + attempts = 50; + do { + msleep(250); + val = t3_read_reg(adapter, mc7->offset + A_MC7_BIST_OP); + } while ((val & F_BUSY) && --attempts); + if (val & F_BUSY) { + CH_ERR(adapter, "%s MC7 BIST timed out\n", mc7->name); + goto out_fail; + } + + /* Enable normal memory accesses. */ + t3_set_reg_field(adapter, mc7->offset + A_MC7_CFG, 0, F_RDY); + return 0; + +out_fail: + return -1; +} + +static void config_pcie(struct adapter *adap) +{ + static const u16 ack_lat[4][6] = { + {237, 416, 559, 1071, 2095, 4143}, + {128, 217, 289, 545, 1057, 2081}, + {73, 118, 154, 282, 538, 1050}, + {67, 107, 86, 150, 278, 534} + }; + static const u16 rpl_tmr[4][6] = { + {711, 1248, 1677, 3213, 6285, 12429}, + {384, 651, 867, 1635, 3171, 6243}, + {219, 354, 462, 846, 1614, 3150}, + {201, 321, 258, 450, 834, 1602} + }; + + u16 val; + unsigned int log2_width, pldsize; + unsigned int fst_trn_rx, fst_trn_tx, acklat, rpllmt; + + pci_read_config_word(adap->pdev, + adap->params.pci.pcie_cap_addr + PCI_EXP_DEVCTL, + &val); + pldsize = (val & PCI_EXP_DEVCTL_PAYLOAD) >> 5; + pci_read_config_word(adap->pdev, + adap->params.pci.pcie_cap_addr + PCI_EXP_LNKCTL, + &val); + + fst_trn_tx = G_NUMFSTTRNSEQ(t3_read_reg(adap, A_PCIE_PEX_CTRL0)); + fst_trn_rx = adap->params.rev == 0 ? fst_trn_tx : + G_NUMFSTTRNSEQRX(t3_read_reg(adap, A_PCIE_MODE)); + log2_width = fls(adap->params.pci.width) - 1; + acklat = ack_lat[log2_width][pldsize]; + if (val & 1) /* check LOsEnable */ + acklat += fst_trn_tx * 4; + rpllmt = rpl_tmr[log2_width][pldsize] + fst_trn_rx * 4; + + if (adap->params.rev == 0) + t3_set_reg_field(adap, A_PCIE_PEX_CTRL1, + V_T3A_ACKLAT(M_T3A_ACKLAT), + V_T3A_ACKLAT(acklat)); + else + t3_set_reg_field(adap, A_PCIE_PEX_CTRL1, V_ACKLAT(M_ACKLAT), + V_ACKLAT(acklat)); + + t3_set_reg_field(adap, A_PCIE_PEX_CTRL0, V_REPLAYLMT(M_REPLAYLMT), + V_REPLAYLMT(rpllmt)); + + t3_write_reg(adap, A_PCIE_PEX_ERR, 0xffffffff); + t3_set_reg_field(adap, A_PCIE_CFG, F_PCIE_CLIDECEN, F_PCIE_CLIDECEN); +} + +/* + * Initialize and configure T3 HW modules. This performs the + * initialization steps that need to be done once after a card is reset. + * MAC and PHY initialization is handled separarely whenever a port is enabled. + * + * fw_params are passed to FW and their value is platform dependent. Only the + * top 8 bits are available for use, the rest must be 0. + */ +int t3_init_hw(struct adapter *adapter, u32 fw_params) +{ + int err = -EIO, attempts = 100; + const struct vpd_params *vpd = &adapter->params.vpd; + + if (adapter->params.rev > 0) + calibrate_xgm_t3b(adapter); + else if (calibrate_xgm(adapter)) + goto out_err; + + if (vpd->mclk) { + partition_mem(adapter, &adapter->params.tp); + + if (mc7_init(&adapter->pmrx, vpd->mclk, vpd->mem_timing) || + mc7_init(&adapter->pmtx, vpd->mclk, vpd->mem_timing) || + mc7_init(&adapter->cm, vpd->mclk, vpd->mem_timing) || + t3_mc5_init(&adapter->mc5, adapter->params.mc5.nservers, + adapter->params.mc5.nfilters, + adapter->params.mc5.nroutes)) + goto out_err; + } + + if (tp_init(adapter, &adapter->params.tp)) + goto out_err; + + t3_tp_set_coalescing_size(adapter, + min(adapter->params.sge.max_pkt_size, + MAX_RX_COALESCING_LEN), 1); + t3_tp_set_max_rxsize(adapter, + min(adapter->params.sge.max_pkt_size, 16384U)); + ulp_config(adapter, &adapter->params.tp); + + if (is_pcie(adapter)) + config_pcie(adapter); + else + t3_set_reg_field(adapter, A_PCIX_CFG, 0, F_CLIDECEN); + + t3_write_reg(adapter, A_PM1_RX_CFG, 0xf000f000); + init_hw_for_avail_ports(adapter, adapter->params.nports); + t3_sge_init(adapter, &adapter->params.sge); + + t3_write_reg(adapter, A_CIM_HOST_ACC_DATA, vpd->uclk | fw_params); + t3_write_reg(adapter, A_CIM_BOOT_CFG, + V_BOOTADDR(FW_FLASH_BOOT_ADDR >> 2)); + t3_read_reg(adapter, A_CIM_BOOT_CFG); /* flush */ + + do { /* wait for uP to initialize */ + msleep(20); + } while (t3_read_reg(adapter, A_CIM_HOST_ACC_DATA) && --attempts); + if (!attempts) + goto out_err; + + err = 0; +out_err: + return err; +} + +/** + * get_pci_mode - determine a card's PCI mode + * @adapter: the adapter + * @p: where to store the PCI settings + * + * Determines a card's PCI mode and associated parameters, such as speed + * and width. + */ +static void __devinit get_pci_mode(struct adapter *adapter, + struct pci_params *p) +{ + static unsigned short speed_map[] = { 33, 66, 100, 133 }; + u32 pci_mode, pcie_cap; + + pcie_cap = pci_find_capability(adapter->pdev, PCI_CAP_ID_EXP); + if (pcie_cap) { + u16 val; + + p->variant = PCI_VARIANT_PCIE; + p->pcie_cap_addr = pcie_cap; + pci_read_config_word(adapter->pdev, pcie_cap + PCI_EXP_LNKSTA, + &val); + p->width = (val >> 4) & 0x3f; + return; + } + + pci_mode = t3_read_reg(adapter, A_PCIX_MODE); + p->speed = speed_map[G_PCLKRANGE(pci_mode)]; + p->width = (pci_mode & F_64BIT) ? 64 : 32; + pci_mode = G_PCIXINITPAT(pci_mode); + if (pci_mode == 0) + p->variant = PCI_VARIANT_PCI; + else if (pci_mode < 4) + p->variant = PCI_VARIANT_PCIX_MODE1_PARITY; + else if (pci_mode < 8) + p->variant = PCI_VARIANT_PCIX_MODE1_ECC; + else + p->variant = PCI_VARIANT_PCIX_266_MODE2; +} + +/** + * init_link_config - initialize a link's SW state + * @lc: structure holding the link state + * @ai: information about the current card + * + * Initializes the SW state maintained for each link, including the link's + * capabilities and default speed/duplex/flow-control/autonegotiation + * settings. + */ +static void __devinit init_link_config(struct link_config *lc, + unsigned int caps) +{ + lc->supported = caps; + lc->requested_speed = lc->speed = SPEED_INVALID; + lc->requested_duplex = lc->duplex = DUPLEX_INVALID; + lc->requested_fc = lc->fc = PAUSE_RX | PAUSE_TX; + if (lc->supported & SUPPORTED_Autoneg) { + lc->advertising = lc->supported; + lc->autoneg = AUTONEG_ENABLE; + lc->requested_fc |= PAUSE_AUTONEG; + } else { + lc->advertising = 0; + lc->autoneg = AUTONEG_DISABLE; + } +} + +/** + * mc7_calc_size - calculate MC7 memory size + * @cfg: the MC7 configuration + * + * Calculates the size of an MC7 memory in bytes from the value of its + * configuration register. + */ +static unsigned int __devinit mc7_calc_size(u32 cfg) +{ + unsigned int width = G_WIDTH(cfg); + unsigned int banks = !!(cfg & F_BKS) + 1; + unsigned int org = !!(cfg & F_ORG) + 1; + unsigned int density = G_DEN(cfg); + unsigned int MBs = ((256 << density) * banks) / (org << width); + + return MBs << 20; +} + +static void __devinit mc7_prep(struct adapter *adapter, struct mc7 *mc7, + unsigned int base_addr, const char *name) +{ + u32 cfg; + + mc7->adapter = adapter; + mc7->name = name; + mc7->offset = base_addr - MC7_PMRX_BASE_ADDR; + cfg = t3_read_reg(adapter, mc7->offset + A_MC7_CFG); + mc7->size = mc7_calc_size(cfg); + mc7->width = G_WIDTH(cfg); +} + +void mac_prep(struct cmac *mac, struct adapter *adapter, int index) +{ + mac->adapter = adapter; + mac->offset = (XGMAC0_1_BASE_ADDR - XGMAC0_0_BASE_ADDR) * index; + mac->nucast = 1; + + if (adapter->params.rev == 0 && uses_xaui(adapter)) { + t3_write_reg(adapter, A_XGM_SERDES_CTRL + mac->offset, + is_10G(adapter) ? 0x2901c04 : 0x2301c04); + t3_set_reg_field(adapter, A_XGM_PORT_CFG + mac->offset, + F_ENRGMII, 0); + } +} + +void early_hw_init(struct adapter *adapter, const struct adapter_info *ai) +{ + u32 val = V_PORTSPEED(is_10G(adapter) ? 3 : 2); + + mi1_init(adapter, ai); + t3_write_reg(adapter, A_I2C_CFG, /* set for 80KHz */ + V_I2C_CLKDIV(adapter->params.vpd.cclk / 80 - 1)); + t3_write_reg(adapter, A_T3DBG_GPIO_EN, + ai->gpio_out | F_GPIO0_OEN | F_GPIO0_OUT_VAL); + + if (adapter->params.rev == 0 || !uses_xaui(adapter)) + val |= F_ENRGMII; + + /* Enable MAC clocks so we can access the registers */ + t3_write_reg(adapter, A_XGM_PORT_CFG, val); + t3_read_reg(adapter, A_XGM_PORT_CFG); + + val |= F_CLKDIVRESET_; + t3_write_reg(adapter, A_XGM_PORT_CFG, val); + t3_read_reg(adapter, A_XGM_PORT_CFG); + t3_write_reg(adapter, XGM_REG(A_XGM_PORT_CFG, 1), val); + t3_read_reg(adapter, A_XGM_PORT_CFG); +} + +/* + * Reset the adapter. PCIe cards lose their config space during reset, PCI-X + * ones don't. + */ +int t3_reset_adapter(struct adapter *adapter) +{ + int i; + uint16_t devid = 0; + + if (is_pcie(adapter)) + pci_save_state(adapter->pdev); + t3_write_reg(adapter, A_PL_RST, F_CRSTWRM | F_CRSTWRMMODE); + + /* + * Delay. Give Some time to device to reset fully. + * XXX The delay time should be modified. + */ + for (i = 0; i < 10; i++) { + msleep(50); + pci_read_config_word(adapter->pdev, 0x00, &devid); + if (devid == 0x1425) + break; + } + + if (devid != 0x1425) + return -1; + + if (is_pcie(adapter)) + pci_restore_state(adapter->pdev); + return 0; +} + +/* + * Initialize adapter SW state for the various HW modules, set initial values + * for some adapter tunables, take PHYs out of reset, and initialize the MDIO + * interface. + */ +int __devinit t3_prep_adapter(struct adapter *adapter, + const struct adapter_info *ai, int reset) +{ + int ret; + unsigned int i, j = 0; + + get_pci_mode(adapter, &adapter->params.pci); + + adapter->params.info = ai; + adapter->params.nports = ai->nports; + adapter->params.rev = t3_read_reg(adapter, A_PL_REV); + adapter->params.linkpoll_period = 0; + adapter->params.stats_update_period = is_10G(adapter) ? + MAC_STATS_ACCUM_SECS : (MAC_STATS_ACCUM_SECS * 10); + adapter->params.pci.vpd_cap_addr = + pci_find_capability(adapter->pdev, PCI_CAP_ID_VPD); + ret = get_vpd_params(adapter, &adapter->params.vpd); + if (ret < 0) + return ret; + + if (reset && t3_reset_adapter(adapter)) + return -1; + + t3_sge_prep(adapter, &adapter->params.sge); + + if (adapter->params.vpd.mclk) { + struct tp_params *p = &adapter->params.tp; + + mc7_prep(adapter, &adapter->pmrx, MC7_PMRX_BASE_ADDR, "PMRX"); + mc7_prep(adapter, &adapter->pmtx, MC7_PMTX_BASE_ADDR, "PMTX"); + mc7_prep(adapter, &adapter->cm, MC7_CM_BASE_ADDR, "CM"); + + p->nchan = ai->nports; + p->pmrx_size = t3_mc7_size(&adapter->pmrx); + p->pmtx_size = t3_mc7_size(&adapter->pmtx); + p->cm_size = t3_mc7_size(&adapter->cm); + p->chan_rx_size = p->pmrx_size / 2; /* only 1 Rx channel */ + p->chan_tx_size = p->pmtx_size / p->nchan; + p->rx_pg_size = 64 * 1024; + p->tx_pg_size = is_10G(adapter) ? 64 * 1024 : 16 * 1024; + p->rx_num_pgs = pm_num_pages(p->chan_rx_size, p->rx_pg_size); + p->tx_num_pgs = pm_num_pages(p->chan_tx_size, p->tx_pg_size); + p->ntimer_qs = p->cm_size >= (128 << 20) || + adapter->params.rev > 0 ? 12 : 6; + + adapter->params.mc5.nservers = DEFAULT_NSERVERS; + adapter->params.mc5.nfilters = adapter->params.rev > 0 ? + DEFAULT_NFILTERS : 0; + adapter->params.mc5.nroutes = 0; + t3_mc5_prep(adapter, &adapter->mc5, MC5_MODE_144_BIT); + + init_mtus(adapter->params.mtus); + init_cong_ctrl(adapter->params.a_wnd, adapter->params.b_wnd); + } + + early_hw_init(adapter, ai); + + for_each_port(adapter, i) { + u8 hw_addr[6]; + struct port_info *p = adap2pinfo(adapter, i); + + while (!adapter->params.vpd.port_type[j]) + ++j; + + p->port_type = &port_types[adapter->params.vpd.port_type[j]]; + p->port_type->phy_prep(&p->phy, adapter, ai->phy_base_addr + j, + ai->mdio_ops); + mac_prep(&p->mac, adapter, j); + ++j; + + /* + * The VPD EEPROM stores the base Ethernet address for the + * card. A port's address is derived from the base by adding + * the port's index to the base's low octet. + */ + memcpy(hw_addr, adapter->params.vpd.eth_base, 5); + hw_addr[5] = adapter->params.vpd.eth_base[5] + i; + + memcpy(adapter->port[i]->dev_addr, hw_addr, + ETH_ALEN); + memcpy(adapter->port[i]->perm_addr, hw_addr, + ETH_ALEN); + init_link_config(&p->link_config, p->port_type->caps); + p->phy.ops->power_down(&p->phy, 1); + if (!(p->port_type->caps & SUPPORTED_IRQ)) + adapter->params.linkpoll_period = 10; + } + + return 0; +} + +void t3_led_ready(struct adapter *adapter) +{ + t3_set_reg_field(adapter, A_T3DBG_GPIO_EN, F_GPIO0_OUT_VAL, + F_GPIO0_OUT_VAL); +} diff --git a/drivers/net/cxgb3/t3cdev.h b/drivers/net/cxgb3/t3cdev.h new file mode 100644 index 0000000..9af3bcd --- /dev/null +++ b/drivers/net/cxgb3/t3cdev.h @@ -0,0 +1,73 @@ +/* + * Copyright (C) 2006-2007 Chelsio Communications. All rights reserved. + * Copyright (C) 2006-2007 Open Grid Computing, Inc. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +#ifndef _T3CDEV_H_ +#define _T3CDEV_H_ + +#include +#include +#include +#include +#include +#include +#include + +#define T3CNAMSIZ 16 + +/* Get the t3cdev associated with a net_device */ +#define T3CDEV(netdev) (struct t3cdev *)(netdev->priv) + +struct cxgb3_client; + +enum t3ctype { + T3A = 0, + T3B +}; + +struct t3cdev { + char name[T3CNAMSIZ]; /* T3C device name */ + enum t3ctype type; + struct list_head ofld_dev_list; /* for list linking */ + struct net_device *lldev; /* LL dev associated with T3C messages */ + struct proc_dir_entry *proc_dir; /* root of proc dir for this T3C */ + int (*send)(struct t3cdev *dev, struct sk_buff *skb); + int (*recv)(struct t3cdev *dev, struct sk_buff **skb, int n); + int (*ctl)(struct t3cdev *dev, unsigned int req, void *data); + void (*neigh_update)(struct t3cdev *dev, struct neighbour *neigh); + void *priv; /* driver private data */ + void *l2opt; /* optional layer 2 data */ + void *l3opt; /* optional layer 3 data */ + void *l4opt; /* optional layer 4 data */ + void *ulp; /* ulp stuff */ +}; + +#endif /* _T3CDEV_H_ */ diff --git a/drivers/net/cxgb3/version.h b/drivers/net/cxgb3/version.h new file mode 100644 index 0000000..2b67dd5 --- /dev/null +++ b/drivers/net/cxgb3/version.h @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2003-2007 Chelsio, Inc. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +/* $Date: 2006/10/31 18:57:51 $ $RCSfile: version.h,v $ $Revision: 1.3 $ */ +#ifndef __CHELSIO_VERSION_H +#define __CHELSIO_VERSION_H +#define DRV_DESC "Chelsio T3 Network Driver" +#define DRV_NAME "cxgb3" +/* Driver version */ +#define DRV_VERSION "1.0" +#endif /* __CHELSIO_VERSION_H */ diff --git a/drivers/net/cxgb3/vsc8211.c b/drivers/net/cxgb3/vsc8211.c new file mode 100644 index 0000000..eee4285 --- /dev/null +++ b/drivers/net/cxgb3/vsc8211.c @@ -0,0 +1,228 @@ +/* + * Copyright (c) 2005-2007 Chelsio, Inc. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +#include "common.h" + +/* VSC8211 PHY specific registers. */ +enum { + VSC8211_INTR_ENABLE = 25, + VSC8211_INTR_STATUS = 26, + VSC8211_AUX_CTRL_STAT = 28, +}; + +enum { + VSC_INTR_RX_ERR = 1 << 0, + VSC_INTR_MS_ERR = 1 << 1, /* master/slave resolution error */ + VSC_INTR_CABLE = 1 << 2, /* cable impairment */ + VSC_INTR_FALSE_CARR = 1 << 3, /* false carrier */ + VSC_INTR_MEDIA_CHG = 1 << 4, /* AMS media change */ + VSC_INTR_RX_FIFO = 1 << 5, /* Rx FIFO over/underflow */ + VSC_INTR_TX_FIFO = 1 << 6, /* Tx FIFO over/underflow */ + VSC_INTR_DESCRAMBL = 1 << 7, /* descrambler lock-lost */ + VSC_INTR_SYMBOL_ERR = 1 << 8, /* symbol error */ + VSC_INTR_NEG_DONE = 1 << 10, /* autoneg done */ + VSC_INTR_NEG_ERR = 1 << 11, /* autoneg error */ + VSC_INTR_LINK_CHG = 1 << 13, /* link change */ + VSC_INTR_ENABLE = 1 << 15, /* interrupt enable */ +}; + +#define CFG_CHG_INTR_MASK (VSC_INTR_LINK_CHG | VSC_INTR_NEG_ERR | \ + VSC_INTR_NEG_DONE) +#define INTR_MASK (CFG_CHG_INTR_MASK | VSC_INTR_TX_FIFO | VSC_INTR_RX_FIFO | \ + VSC_INTR_ENABLE) + +/* PHY specific auxiliary control & status register fields */ +#define S_ACSR_ACTIPHY_TMR 0 +#define M_ACSR_ACTIPHY_TMR 0x3 +#define V_ACSR_ACTIPHY_TMR(x) ((x) << S_ACSR_ACTIPHY_TMR) + +#define S_ACSR_SPEED 3 +#define M_ACSR_SPEED 0x3 +#define G_ACSR_SPEED(x) (((x) >> S_ACSR_SPEED) & M_ACSR_SPEED) + +#define S_ACSR_DUPLEX 5 +#define F_ACSR_DUPLEX (1 << S_ACSR_DUPLEX) + +#define S_ACSR_ACTIPHY 6 +#define F_ACSR_ACTIPHY (1 << S_ACSR_ACTIPHY) + +/* + * Reset the PHY. This PHY completes reset immediately so we never wait. + */ +static int vsc8211_reset(struct cphy *cphy, int wait) +{ + return t3_phy_reset(cphy, 0, 0); +} + +static int vsc8211_intr_enable(struct cphy *cphy) +{ + return mdio_write(cphy, 0, VSC8211_INTR_ENABLE, INTR_MASK); +} + +static int vsc8211_intr_disable(struct cphy *cphy) +{ + return mdio_write(cphy, 0, VSC8211_INTR_ENABLE, 0); +} + +static int vsc8211_intr_clear(struct cphy *cphy) +{ + u32 val; + + /* Clear PHY interrupts by reading the register. */ + return mdio_read(cphy, 0, VSC8211_INTR_STATUS, &val); +} + +static int vsc8211_autoneg_enable(struct cphy *cphy) +{ + return t3_mdio_change_bits(cphy, 0, MII_BMCR, BMCR_PDOWN | BMCR_ISOLATE, + BMCR_ANENABLE | BMCR_ANRESTART); +} + +static int vsc8211_autoneg_restart(struct cphy *cphy) +{ + return t3_mdio_change_bits(cphy, 0, MII_BMCR, BMCR_PDOWN | BMCR_ISOLATE, + BMCR_ANRESTART); +} + +static int vsc8211_get_link_status(struct cphy *cphy, int *link_ok, + int *speed, int *duplex, int *fc) +{ + unsigned int bmcr, status, lpa, adv; + int err, sp = -1, dplx = -1, pause = 0; + + err = mdio_read(cphy, 0, MII_BMCR, &bmcr); + if (!err) + err = mdio_read(cphy, 0, MII_BMSR, &status); + if (err) + return err; + + if (link_ok) { + /* + * BMSR_LSTATUS is latch-low, so if it is 0 we need to read it + * once more to get the current link state. + */ + if (!(status & BMSR_LSTATUS)) + err = mdio_read(cphy, 0, MII_BMSR, &status); + if (err) + return err; + *link_ok = (status & BMSR_LSTATUS) != 0; + } + if (!(bmcr & BMCR_ANENABLE)) { + dplx = (bmcr & BMCR_FULLDPLX) ? DUPLEX_FULL : DUPLEX_HALF; + if (bmcr & BMCR_SPEED1000) + sp = SPEED_1000; + else if (bmcr & BMCR_SPEED100) + sp = SPEED_100; + else + sp = SPEED_10; + } else if (status & BMSR_ANEGCOMPLETE) { + err = mdio_read(cphy, 0, VSC8211_AUX_CTRL_STAT, &status); + if (err) + return err; + + dplx = (status & F_ACSR_DUPLEX) ? DUPLEX_FULL : DUPLEX_HALF; + sp = G_ACSR_SPEED(status); + if (sp == 0) + sp = SPEED_10; + else if (sp == 1) + sp = SPEED_100; + else + sp = SPEED_1000; + + if (fc && dplx == DUPLEX_FULL) { + err = mdio_read(cphy, 0, MII_LPA, &lpa); + if (!err) + err = mdio_read(cphy, 0, MII_ADVERTISE, &adv); + if (err) + return err; + + if (lpa & adv & ADVERTISE_PAUSE_CAP) + pause = PAUSE_RX | PAUSE_TX; + else if ((lpa & ADVERTISE_PAUSE_CAP) && + (lpa & ADVERTISE_PAUSE_ASYM) && + (adv & ADVERTISE_PAUSE_ASYM)) + pause = PAUSE_TX; + else if ((lpa & ADVERTISE_PAUSE_ASYM) && + (adv & ADVERTISE_PAUSE_CAP)) + pause = PAUSE_RX; + } + } + if (speed) + *speed = sp; + if (duplex) + *duplex = dplx; + if (fc) + *fc = pause; + return 0; +} + +static int vsc8211_power_down(struct cphy *cphy, int enable) +{ + return t3_mdio_change_bits(cphy, 0, MII_BMCR, BMCR_PDOWN, + enable ? BMCR_PDOWN : 0); +} + +static int vsc8211_intr_handler(struct cphy *cphy) +{ + unsigned int cause; + int err, cphy_cause = 0; + + err = mdio_read(cphy, 0, VSC8211_INTR_STATUS, &cause); + if (err) + return err; + + cause &= INTR_MASK; + if (cause & CFG_CHG_INTR_MASK) + cphy_cause |= cphy_cause_link_change; + if (cause & (VSC_INTR_RX_FIFO | VSC_INTR_TX_FIFO)) + cphy_cause |= cphy_cause_fifo_error; + return cphy_cause; +} + +static struct cphy_ops vsc8211_ops = { + .reset = vsc8211_reset, + .intr_enable = vsc8211_intr_enable, + .intr_disable = vsc8211_intr_disable, + .intr_clear = vsc8211_intr_clear, + .intr_handler = vsc8211_intr_handler, + .autoneg_enable = vsc8211_autoneg_enable, + .autoneg_restart = vsc8211_autoneg_restart, + .advertise = t3_phy_advertise, + .set_speed_duplex = t3_set_phy_speed_duplex, + .get_link_status = vsc8211_get_link_status, + .power_down = vsc8211_power_down, +}; + +void t3_vsc8211_phy_prep(struct cphy *phy, struct adapter *adapter, + int phy_addr, const struct mdio_ops *mdio_ops) +{ + cphy_init(phy, adapter, phy_addr, &vsc8211_ops, mdio_ops); +} diff --git a/drivers/net/cxgb3/xgmac.c b/drivers/net/cxgb3/xgmac.c new file mode 100644 index 0000000..907a272 --- /dev/null +++ b/drivers/net/cxgb3/xgmac.c @@ -0,0 +1,409 @@ +/* + * Copyright (c) 2005-2007 Chelsio, Inc. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +#include "common.h" +#include "regs.h" + +/* + * # of exact address filters. The first one is used for the station address, + * the rest are available for multicast addresses. + */ +#define EXACT_ADDR_FILTERS 8 + +static inline int macidx(const struct cmac *mac) +{ + return mac->offset / (XGMAC0_1_BASE_ADDR - XGMAC0_0_BASE_ADDR); +} + +static void xaui_serdes_reset(struct cmac *mac) +{ + static const unsigned int clear[] = { + F_PWRDN0 | F_PWRDN1, F_RESETPLL01, F_RESET0 | F_RESET1, + F_PWRDN2 | F_PWRDN3, F_RESETPLL23, F_RESET2 | F_RESET3 + }; + + int i; + struct adapter *adap = mac->adapter; + u32 ctrl = A_XGM_SERDES_CTRL0 + mac->offset; + + t3_write_reg(adap, ctrl, adap->params.vpd.xauicfg[macidx(mac)] | + F_RESET3 | F_RESET2 | F_RESET1 | F_RESET0 | + F_PWRDN3 | F_PWRDN2 | F_PWRDN1 | F_PWRDN0 | + F_RESETPLL23 | F_RESETPLL01); + t3_read_reg(adap, ctrl); + udelay(15); + + for (i = 0; i < ARRAY_SIZE(clear); i++) { + t3_set_reg_field(adap, ctrl, clear[i], 0); + udelay(15); + } +} + +void t3b_pcs_reset(struct cmac *mac) +{ + t3_set_reg_field(mac->adapter, A_XGM_RESET_CTRL + mac->offset, + F_PCS_RESET_, 0); + udelay(20); + t3_set_reg_field(mac->adapter, A_XGM_RESET_CTRL + mac->offset, 0, + F_PCS_RESET_); +} + +int t3_mac_reset(struct cmac *mac) +{ + static const struct addr_val_pair mac_reset_avp[] = { + {A_XGM_TX_CTRL, 0}, + {A_XGM_RX_CTRL, 0}, + {A_XGM_RX_CFG, F_DISPAUSEFRAMES | F_EN1536BFRAMES | + F_RMFCS | F_ENJUMBO | F_ENHASHMCAST}, + {A_XGM_RX_HASH_LOW, 0}, + {A_XGM_RX_HASH_HIGH, 0}, + {A_XGM_RX_EXACT_MATCH_LOW_1, 0}, + {A_XGM_RX_EXACT_MATCH_LOW_2, 0}, + {A_XGM_RX_EXACT_MATCH_LOW_3, 0}, + {A_XGM_RX_EXACT_MATCH_LOW_4, 0}, + {A_XGM_RX_EXACT_MATCH_LOW_5, 0}, + {A_XGM_RX_EXACT_MATCH_LOW_6, 0}, + {A_XGM_RX_EXACT_MATCH_LOW_7, 0}, + {A_XGM_RX_EXACT_MATCH_LOW_8, 0}, + {A_XGM_STAT_CTRL, F_CLRSTATS} + }; + u32 val; + struct adapter *adap = mac->adapter; + unsigned int oft = mac->offset; + + t3_write_reg(adap, A_XGM_RESET_CTRL + oft, F_MAC_RESET_); + t3_read_reg(adap, A_XGM_RESET_CTRL + oft); /* flush */ + + t3_write_regs(adap, mac_reset_avp, ARRAY_SIZE(mac_reset_avp), oft); + t3_set_reg_field(adap, A_XGM_RXFIFO_CFG + oft, + F_RXSTRFRWRD | F_DISERRFRAMES, + uses_xaui(adap) ? 0 : F_RXSTRFRWRD); + + if (uses_xaui(adap)) { + if (adap->params.rev == 0) { + t3_set_reg_field(adap, A_XGM_SERDES_CTRL + oft, 0, + F_RXENABLE | F_TXENABLE); + if (t3_wait_op_done(adap, A_XGM_SERDES_STATUS1 + oft, + F_CMULOCK, 1, 5, 2)) { + CH_ERR(adap, + "MAC %d XAUI SERDES CMU lock failed\n", + macidx(mac)); + return -1; + } + t3_set_reg_field(adap, A_XGM_SERDES_CTRL + oft, 0, + F_SERDESRESET_); + } else + xaui_serdes_reset(mac); + } + + if (adap->params.rev > 0) + t3_write_reg(adap, A_XGM_PAUSE_TIMER + oft, 0xf000); + + val = F_MAC_RESET_; + if (is_10G(adap)) + val |= F_PCS_RESET_; + else if (uses_xaui(adap)) + val |= F_PCS_RESET_ | F_XG2G_RESET_; + else + val |= F_RGMII_RESET_ | F_XG2G_RESET_; + t3_write_reg(adap, A_XGM_RESET_CTRL + oft, val); + t3_read_reg(adap, A_XGM_RESET_CTRL + oft); /* flush */ + if ((val & F_PCS_RESET_) && adap->params.rev) { + msleep(1); + t3b_pcs_reset(mac); + } + + memset(&mac->stats, 0, sizeof(mac->stats)); + return 0; +} + +/* + * Set the exact match register 'idx' to recognize the given Ethernet address. + */ +static void set_addr_filter(struct cmac *mac, int idx, const u8 * addr) +{ + u32 addr_lo, addr_hi; + unsigned int oft = mac->offset + idx * 8; + + addr_lo = (addr[3] << 24) | (addr[2] << 16) | (addr[1] << 8) | addr[0]; + addr_hi = (addr[5] << 8) | addr[4]; + + t3_write_reg(mac->adapter, A_XGM_RX_EXACT_MATCH_LOW_1 + oft, addr_lo); + t3_write_reg(mac->adapter, A_XGM_RX_EXACT_MATCH_HIGH_1 + oft, addr_hi); +} + +/* Set one of the station's unicast MAC addresses. */ +int t3_mac_set_address(struct cmac *mac, unsigned int idx, u8 addr[6]) +{ + if (idx >= mac->nucast) + return -EINVAL; + set_addr_filter(mac, idx, addr); + return 0; +} + +/* + * Specify the number of exact address filters that should be reserved for + * unicast addresses. Caller should reload the unicast and multicast addresses + * after calling this. + */ +int t3_mac_set_num_ucast(struct cmac *mac, int n) +{ + if (n > EXACT_ADDR_FILTERS) + return -EINVAL; + mac->nucast = n; + return 0; +} + +/* Calculate the RX hash filter index of an Ethernet address */ +static int hash_hw_addr(const u8 * addr) +{ + int hash = 0, octet, bit, i = 0, c; + + for (octet = 0; octet < 6; ++octet) + for (c = addr[octet], bit = 0; bit < 8; c >>= 1, ++bit) { + hash ^= (c & 1) << i; + if (++i == 6) + i = 0; + } + return hash; +} + +int t3_mac_set_rx_mode(struct cmac *mac, struct t3_rx_mode *rm) +{ + u32 val, hash_lo, hash_hi; + struct adapter *adap = mac->adapter; + unsigned int oft = mac->offset; + + val = t3_read_reg(adap, A_XGM_RX_CFG + oft) & ~F_COPYALLFRAMES; + if (rm->dev->flags & IFF_PROMISC) + val |= F_COPYALLFRAMES; + t3_write_reg(adap, A_XGM_RX_CFG + oft, val); + + if (rm->dev->flags & IFF_ALLMULTI) + hash_lo = hash_hi = 0xffffffff; + else { + u8 *addr; + int exact_addr_idx = mac->nucast; + + hash_lo = hash_hi = 0; + while ((addr = t3_get_next_mcaddr(rm))) + if (exact_addr_idx < EXACT_ADDR_FILTERS) + set_addr_filter(mac, exact_addr_idx++, addr); + else { + int hash = hash_hw_addr(addr); + + if (hash < 32) + hash_lo |= (1 << hash); + else + hash_hi |= (1 << (hash - 32)); + } + } + + t3_write_reg(adap, A_XGM_RX_HASH_LOW + oft, hash_lo); + t3_write_reg(adap, A_XGM_RX_HASH_HIGH + oft, hash_hi); + return 0; +} + +int t3_mac_set_mtu(struct cmac *mac, unsigned int mtu) +{ + int hwm, lwm; + unsigned int thres, v; + struct adapter *adap = mac->adapter; + + /* + * MAX_FRAME_SIZE inludes header + FCS, mtu doesn't. The HW max + * packet size register includes header, but not FCS. + */ + mtu += 14; + if (mtu > MAX_FRAME_SIZE - 4) + return -EINVAL; + t3_write_reg(adap, A_XGM_RX_MAX_PKT_SIZE + mac->offset, mtu); + + /* + * Adjust the PAUSE frame watermarks. We always set the LWM, and the + * HWM only if flow-control is enabled. + */ + hwm = max(MAC_RXFIFO_SIZE - 3 * mtu, MAC_RXFIFO_SIZE / 2U); + hwm = min(hwm, 3 * MAC_RXFIFO_SIZE / 4 + 1024); + lwm = hwm - 1024; + v = t3_read_reg(adap, A_XGM_RXFIFO_CFG + mac->offset); + v &= ~V_RXFIFOPAUSELWM(M_RXFIFOPAUSELWM); + v |= V_RXFIFOPAUSELWM(lwm / 8); + if (G_RXFIFOPAUSEHWM(v)) + v = (v & ~V_RXFIFOPAUSEHWM(M_RXFIFOPAUSEHWM)) | + V_RXFIFOPAUSEHWM(hwm / 8); + t3_write_reg(adap, A_XGM_RXFIFO_CFG + mac->offset, v); + + /* Adjust the TX FIFO threshold based on the MTU */ + thres = (adap->params.vpd.cclk * 1000) / 15625; + thres = (thres * mtu) / 1000; + if (is_10G(adap)) + thres /= 10; + thres = mtu > thres ? (mtu - thres + 7) / 8 : 0; + thres = max(thres, 8U); /* need at least 8 */ + t3_set_reg_field(adap, A_XGM_TXFIFO_CFG + mac->offset, + V_TXFIFOTHRESH(M_TXFIFOTHRESH), V_TXFIFOTHRESH(thres)); + return 0; +} + +int t3_mac_set_speed_duplex_fc(struct cmac *mac, int speed, int duplex, int fc) +{ + u32 val; + struct adapter *adap = mac->adapter; + unsigned int oft = mac->offset; + + if (duplex >= 0 && duplex != DUPLEX_FULL) + return -EINVAL; + if (speed >= 0) { + if (speed == SPEED_10) + val = V_PORTSPEED(0); + else if (speed == SPEED_100) + val = V_PORTSPEED(1); + else if (speed == SPEED_1000) + val = V_PORTSPEED(2); + else if (speed == SPEED_10000) + val = V_PORTSPEED(3); + else + return -EINVAL; + + t3_set_reg_field(adap, A_XGM_PORT_CFG + oft, + V_PORTSPEED(M_PORTSPEED), val); + } + + val = t3_read_reg(adap, A_XGM_RXFIFO_CFG + oft); + val &= ~V_RXFIFOPAUSEHWM(M_RXFIFOPAUSEHWM); + if (fc & PAUSE_TX) + val |= V_RXFIFOPAUSEHWM(G_RXFIFOPAUSELWM(val) + 128); /* +1KB */ + t3_write_reg(adap, A_XGM_RXFIFO_CFG + oft, val); + + t3_set_reg_field(adap, A_XGM_TX_CFG + oft, F_TXPAUSEEN, + (fc & PAUSE_RX) ? F_TXPAUSEEN : 0); + return 0; +} + +int t3_mac_enable(struct cmac *mac, int which) +{ + int idx = macidx(mac); + struct adapter *adap = mac->adapter; + unsigned int oft = mac->offset; + + if (which & MAC_DIRECTION_TX) { + t3_write_reg(adap, A_XGM_TX_CTRL + oft, F_TXEN); + t3_write_reg(adap, A_TP_PIO_ADDR, A_TP_TX_DROP_CFG_CH0 + idx); + t3_write_reg(adap, A_TP_PIO_DATA, 0xbf000001); + t3_write_reg(adap, A_TP_PIO_ADDR, A_TP_TX_DROP_MODE); + t3_set_reg_field(adap, A_TP_PIO_DATA, 1 << idx, 1 << idx); + } + if (which & MAC_DIRECTION_RX) + t3_write_reg(adap, A_XGM_RX_CTRL + oft, F_RXEN); + return 0; +} + +int t3_mac_disable(struct cmac *mac, int which) +{ + int idx = macidx(mac); + struct adapter *adap = mac->adapter; + + if (which & MAC_DIRECTION_TX) { + t3_write_reg(adap, A_XGM_TX_CTRL + mac->offset, 0); + t3_write_reg(adap, A_TP_PIO_ADDR, A_TP_TX_DROP_CFG_CH0 + idx); + t3_write_reg(adap, A_TP_PIO_DATA, 0xc000001f); + t3_write_reg(adap, A_TP_PIO_ADDR, A_TP_TX_DROP_MODE); + t3_set_reg_field(adap, A_TP_PIO_DATA, 1 << idx, 0); + } + if (which & MAC_DIRECTION_RX) + t3_write_reg(adap, A_XGM_RX_CTRL + mac->offset, 0); + return 0; +} + +/* + * This function is called periodically to accumulate the current values of the + * RMON counters into the port statistics. Since the packet counters are only + * 32 bits they can overflow in ~286 secs at 10G, so the function should be + * called more frequently than that. The byte counters are 45-bit wide, they + * would overflow in ~7.8 hours. + */ +const struct mac_stats *t3_mac_update_stats(struct cmac *mac) +{ +#define RMON_READ(mac, addr) t3_read_reg(mac->adapter, addr + mac->offset) +#define RMON_UPDATE(mac, name, reg) \ + (mac)->stats.name += (u64)RMON_READ(mac, A_XGM_STAT_##reg) +#define RMON_UPDATE64(mac, name, reg_lo, reg_hi) \ + (mac)->stats.name += RMON_READ(mac, A_XGM_STAT_##reg_lo) + \ + ((u64)RMON_READ(mac, A_XGM_STAT_##reg_hi) << 32) + + u32 v, lo; + + RMON_UPDATE64(mac, rx_octets, RX_BYTES_LOW, RX_BYTES_HIGH); + RMON_UPDATE64(mac, rx_frames, RX_FRAMES_LOW, RX_FRAMES_HIGH); + RMON_UPDATE(mac, rx_mcast_frames, RX_MCAST_FRAMES); + RMON_UPDATE(mac, rx_bcast_frames, RX_BCAST_FRAMES); + RMON_UPDATE(mac, rx_fcs_errs, RX_CRC_ERR_FRAMES); + RMON_UPDATE(mac, rx_pause, RX_PAUSE_FRAMES); + RMON_UPDATE(mac, rx_jabber, RX_JABBER_FRAMES); + RMON_UPDATE(mac, rx_short, RX_SHORT_FRAMES); + RMON_UPDATE(mac, rx_symbol_errs, RX_SYM_CODE_ERR_FRAMES); + + RMON_UPDATE(mac, rx_too_long, RX_OVERSIZE_FRAMES); + mac->stats.rx_too_long += RMON_READ(mac, A_XGM_RX_MAX_PKT_SIZE_ERR_CNT); + + RMON_UPDATE(mac, rx_frames_64, RX_64B_FRAMES); + RMON_UPDATE(mac, rx_frames_65_127, RX_65_127B_FRAMES); + RMON_UPDATE(mac, rx_frames_128_255, RX_128_255B_FRAMES); + RMON_UPDATE(mac, rx_frames_256_511, RX_256_511B_FRAMES); + RMON_UPDATE(mac, rx_frames_512_1023, RX_512_1023B_FRAMES); + RMON_UPDATE(mac, rx_frames_1024_1518, RX_1024_1518B_FRAMES); + RMON_UPDATE(mac, rx_frames_1519_max, RX_1519_MAXB_FRAMES); + + RMON_UPDATE64(mac, tx_octets, TX_BYTE_LOW, TX_BYTE_HIGH); + RMON_UPDATE64(mac, tx_frames, TX_FRAME_LOW, TX_FRAME_HIGH); + RMON_UPDATE(mac, tx_mcast_frames, TX_MCAST); + RMON_UPDATE(mac, tx_bcast_frames, TX_BCAST); + RMON_UPDATE(mac, tx_pause, TX_PAUSE); + /* This counts error frames in general (bad FCS, underrun, etc). */ + RMON_UPDATE(mac, tx_underrun, TX_ERR_FRAMES); + + RMON_UPDATE(mac, tx_frames_64, TX_64B_FRAMES); + RMON_UPDATE(mac, tx_frames_65_127, TX_65_127B_FRAMES); + RMON_UPDATE(mac, tx_frames_128_255, TX_128_255B_FRAMES); + RMON_UPDATE(mac, tx_frames_256_511, TX_256_511B_FRAMES); + RMON_UPDATE(mac, tx_frames_512_1023, TX_512_1023B_FRAMES); + RMON_UPDATE(mac, tx_frames_1024_1518, TX_1024_1518B_FRAMES); + RMON_UPDATE(mac, tx_frames_1519_max, TX_1519_MAXB_FRAMES); + + /* The next stat isn't clear-on-read. */ + t3_write_reg(mac->adapter, A_TP_MIB_INDEX, mac->offset ? 51 : 50); + v = t3_read_reg(mac->adapter, A_TP_MIB_RDATA); + lo = (u32) mac->stats.rx_cong_drops; + mac->stats.rx_cong_drops += (u64) (v - lo); + + return &mac->stats; +} diff --git a/drivers/net/declance.c b/drivers/net/declance.c index 4ae0fed..9f7e1db 100644 --- a/drivers/net/declance.c +++ b/drivers/net/declance.c @@ -5,7 +5,7 @@ * * adopted from sunlance.c by Richard van den Berg * - * Copyright (C) 2002, 2003, 2005 Maciej W. Rozycki + * Copyright (C) 2002, 2003, 2005, 2006 Maciej W. Rozycki * * additional sources: * - PMAD-AA TURBOchannel Ethernet Module Functional Specification, @@ -44,6 +44,8 @@ * v0.010: Fixes for the PMAD mapping of the LANCE buffer and for the * PMAX requirement to only use halfword accesses to the * buffer. macro + * + * v0.011: Converted the PMAD to the driver model. macro */ #include @@ -58,6 +60,7 @@ #include #include #include #include +#include #include #include @@ -69,15 +72,16 @@ #include #include #include #include -#include static char version[] __devinitdata = -"declance.c: v0.010 by Linux MIPS DECstation task force\n"; +"declance.c: v0.011 by Linux MIPS DECstation task force\n"; MODULE_AUTHOR("Linux MIPS DECstation task force"); MODULE_DESCRIPTION("DEC LANCE (DECstation onboard, PMAD-xx) driver"); MODULE_LICENSE("GPL"); +#define __unused __attribute__ ((unused)) + /* * card types */ @@ -246,7 +250,6 @@ #define tds_ptr(td, rt, type) \ struct lance_private { struct net_device *next; int type; - int slot; int dma_irq; volatile struct lance_regs *ll; @@ -288,6 +291,7 @@ struct lance_regs { int dec_lance_debug = 2; +static struct tc_driver dec_lance_tc_driver; static struct net_device *root_lance_dev; static inline void writereg(volatile unsigned short *regptr, short value) @@ -1023,7 +1027,7 @@ static void lance_set_multicast_retry(un lance_set_multicast(dev); } -static int __init dec_lance_init(const int type, const int slot) +static int __init dec_lance_probe(struct device *bdev, const int type) { static unsigned version_printed; static const char fmt[] = "declance%d"; @@ -1031,6 +1035,7 @@ static int __init dec_lance_init(const i struct net_device *dev; struct lance_private *lp; volatile struct lance_regs *ll; + resource_size_t start = 0, len = 0; int i, ret; unsigned long esar_base; unsigned char *esar; @@ -1038,14 +1043,18 @@ static int __init dec_lance_init(const i if (dec_lance_debug && version_printed++ == 0) printk(version); - i = 0; - dev = root_lance_dev; - while (dev) { - i++; - lp = (struct lance_private *)dev->priv; - dev = lp->next; + if (bdev) + snprintf(name, sizeof(name), "%s", bdev->bus_id); + else { + i = 0; + dev = root_lance_dev; + while (dev) { + i++; + lp = (struct lance_private *)dev->priv; + dev = lp->next; + } + snprintf(name, sizeof(name), fmt, i); } - snprintf(name, sizeof(name), fmt, i); dev = alloc_etherdev(sizeof(struct lance_private)); if (!dev) { @@ -1063,7 +1072,6 @@ static int __init dec_lance_init(const i spin_lock_init(&lp->lock); lp->type = type; - lp->slot = slot; switch (type) { case ASIC_LANCE: dev->base_addr = CKSEG1ADDR(dec_kn_slot_base + IOASIC_LANCE); @@ -1110,12 +1118,22 @@ static int __init dec_lance_init(const i break; #ifdef CONFIG_TC case PMAD_LANCE: - claim_tc_card(slot); + dev_set_drvdata(bdev, dev); + + start = to_tc_dev(bdev)->resource.start; + len = to_tc_dev(bdev)->resource.end - start + 1; + if (!request_mem_region(start, len, bdev->bus_id)) { + printk(KERN_ERR + "%s: Unable to reserve MMIO resource\n", + bdev->bus_id); + ret = -EBUSY; + goto err_out_dev; + } - dev->mem_start = CKSEG1ADDR(get_tc_base_addr(slot)); + dev->mem_start = CKSEG1ADDR(start); dev->mem_end = dev->mem_start + 0x100000; dev->base_addr = dev->mem_start + 0x100000; - dev->irq = get_tc_irq_nr(slot); + dev->irq = to_tc_dev(bdev)->interrupt; esar_base = dev->mem_start + 0x1c0002; lp->dma_irq = -1; @@ -1174,7 +1192,7 @@ #endif printk(KERN_ERR "%s: declance_init called with unknown type\n", name); ret = -ENODEV; - goto err_out_free_dev; + goto err_out_dev; } ll = (struct lance_regs *) dev->base_addr; @@ -1188,7 +1206,7 @@ #endif "%s: Ethernet station address prom not found!\n", name); ret = -ENODEV; - goto err_out_free_dev; + goto err_out_resource; } /* Check the prom contents */ for (i = 0; i < 8; i++) { @@ -1198,7 +1216,7 @@ #endif printk(KERN_ERR "%s: Something is wrong with the " "ethernet station address prom!\n", name); ret = -ENODEV; - goto err_out_free_dev; + goto err_out_resource; } } @@ -1255,48 +1273,51 @@ #endif if (ret) { printk(KERN_ERR "%s: Unable to register netdev, aborting.\n", name); - goto err_out_free_dev; + goto err_out_resource; } - lp->next = root_lance_dev; - root_lance_dev = dev; + if (!bdev) { + lp->next = root_lance_dev; + root_lance_dev = dev; + } printk("%s: registered as %s.\n", name, dev->name); return 0; -err_out_free_dev: +err_out_resource: + if (bdev) + release_mem_region(start, len); + +err_out_dev: free_netdev(dev); err_out: return ret; } +static void __exit dec_lance_remove(struct device *bdev) +{ + struct net_device *dev = dev_get_drvdata(bdev); + resource_size_t start, len; + + unregister_netdev(dev); + start = to_tc_dev(bdev)->resource.start; + len = to_tc_dev(bdev)->resource.end - start + 1; + release_mem_region(start, len); + free_netdev(dev); +} /* Find all the lance cards on the system and initialize them */ -static int __init dec_lance_probe(void) +static int __init dec_lance_platform_probe(void) { int count = 0; - /* Scan slots for PMAD-AA cards first. */ -#ifdef CONFIG_TC - if (TURBOCHANNEL) { - int slot; - - while ((slot = search_tc_card("PMAD-AA")) >= 0) { - if (dec_lance_init(PMAD_LANCE, slot) < 0) - break; - count++; - } - } -#endif - - /* Then handle onboard devices. */ if (dec_interrupt[DEC_IRQ_LANCE] >= 0) { if (dec_interrupt[DEC_IRQ_LANCE_MERR] >= 0) { - if (dec_lance_init(ASIC_LANCE, -1) >= 0) + if (dec_lance_probe(NULL, ASIC_LANCE) >= 0) count++; } else if (!TURBOCHANNEL) { - if (dec_lance_init(PMAX_LANCE, -1) >= 0) + if (dec_lance_probe(NULL, PMAX_LANCE) >= 0) count++; } } @@ -1304,21 +1325,70 @@ #endif return (count > 0) ? 0 : -ENODEV; } -static void __exit dec_lance_cleanup(void) +static void __exit dec_lance_platform_remove(void) { while (root_lance_dev) { struct net_device *dev = root_lance_dev; struct lance_private *lp = netdev_priv(dev); unregister_netdev(dev); -#ifdef CONFIG_TC - if (lp->slot >= 0) - release_tc_card(lp->slot); -#endif root_lance_dev = lp->next; free_netdev(dev); } } -module_init(dec_lance_probe); -module_exit(dec_lance_cleanup); +#ifdef CONFIG_TC +static int __init dec_lance_tc_probe(struct device *dev); +static int __exit dec_lance_tc_remove(struct device *dev); + +static const struct tc_device_id dec_lance_tc_table[] = { + { "DEC ", "PMAD-AA " }, + { } +}; +MODULE_DEVICE_TABLE(tc, dec_lance_tc_table); + +static struct tc_driver dec_lance_tc_driver = { + .id_table = dec_lance_tc_table, + .driver = { + .name = "declance", + .bus = &tc_bus_type, + .probe = dec_lance_tc_probe, + .remove = __exit_p(dec_lance_tc_remove), + }, +}; + +static int __init dec_lance_tc_probe(struct device *dev) +{ + int status = dec_lance_probe(dev, PMAD_LANCE); + if (!status) + get_device(dev); + return status; +} + +static int __exit dec_lance_tc_remove(struct device *dev) +{ + put_device(dev); + dec_lance_remove(dev); + return 0; +} +#endif + +static int __init dec_lance_init(void) +{ + int status; + + status = tc_register_driver(&dec_lance_tc_driver); + if (!status) + dec_lance_platform_probe(); + return status; +} + +static void __exit dec_lance_exit(void) +{ + dec_lance_platform_remove(); + tc_unregister_driver(&dec_lance_tc_driver); +} + + +module_init(dec_lance_init); +module_exit(dec_lance_exit); diff --git a/drivers/net/defxx.c b/drivers/net/defxx.c index dc3ab3b..07d2731 100644 --- a/drivers/net/defxx.c +++ b/drivers/net/defxx.c @@ -10,10 +10,12 @@ * * Abstract: * A Linux device driver supporting the Digital Equipment Corporation - * FDDI EISA and PCI controller families. Supported adapters include: + * FDDI TURBOchannel, EISA and PCI controller families. Supported + * adapters include: * - * DEC FDDIcontroller/EISA (DEFEA) - * DEC FDDIcontroller/PCI (DEFPA) + * DEC FDDIcontroller/TURBOchannel (DEFTA) + * DEC FDDIcontroller/EISA (DEFEA) + * DEC FDDIcontroller/PCI (DEFPA) * * The original author: * LVS Lawrence V. Stefani @@ -193,24 +195,27 @@ * 14 Aug 2004 macro Fix device names reported. * 14 Jun 2005 macro Use irqreturn_t. * 23 Oct 2006 macro Big-endian host support. + * 14 Dec 2006 macro TURBOchannel support. */ /* Include files */ - -#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 @@ -219,8 +224,8 @@ #include "defxx.h" /* Version information string should be updated prior to each new release! */ #define DRV_NAME "defxx" -#define DRV_VERSION "v1.09" -#define DRV_RELDATE "2006/10/23" +#define DRV_VERSION "v1.10" +#define DRV_RELDATE "2006/12/14" static char version[] __devinitdata = DRV_NAME ": " DRV_VERSION " " DRV_RELDATE @@ -235,12 +240,41 @@ #define SKBUFF_RX_COPYBREAK 200 */ #define NEW_SKB_SIZE (PI_RCV_DATA_K_SIZE_MAX+128) +#define __unused __attribute__ ((unused)) + +#ifdef CONFIG_PCI +#define DFX_BUS_PCI(dev) (dev->bus == &pci_bus_type) +#else +#define DFX_BUS_PCI(dev) 0 +#endif + +#ifdef CONFIG_EISA +#define DFX_BUS_EISA(dev) (dev->bus == &eisa_bus_type) +#else +#define DFX_BUS_EISA(dev) 0 +#endif + +#ifdef CONFIG_TC +#define DFX_BUS_TC(dev) (dev->bus == &tc_bus_type) +#else +#define DFX_BUS_TC(dev) 0 +#endif + +#ifdef CONFIG_DEFXX_MMIO +#define DFX_MMIO 1 +#else +#define DFX_MMIO 0 +#endif + /* Define module-wide (static) routines */ static void dfx_bus_init(struct net_device *dev); +static void dfx_bus_uninit(struct net_device *dev); static void dfx_bus_config_check(DFX_board_t *bp); -static int dfx_driver_init(struct net_device *dev, const char *print_name); +static int dfx_driver_init(struct net_device *dev, + const char *print_name, + resource_size_t bar_start); static int dfx_adap_init(DFX_board_t *bp, int get_buffers); static int dfx_open(struct net_device *dev); @@ -273,13 +307,13 @@ static void dfx_xmt_flush(DFX_board_t * /* Define module-wide (static) variables */ -static struct net_device *root_dfx_eisa_dev; +static struct pci_driver dfx_pci_driver; +static struct eisa_driver dfx_eisa_driver; +static struct tc_driver dfx_tc_driver; /* * ======================= - * = dfx_port_write_byte = - * = dfx_port_read_byte = * = dfx_port_write_long = * = dfx_port_read_long = * ======================= @@ -291,12 +325,11 @@ static struct net_device *root_dfx_eisa_ * None * * Arguments: - * bp - pointer to board information - * offset - register offset from base I/O address - * data - for dfx_port_write_byte and dfx_port_write_long, this - * is a value to write. - * for dfx_port_read_byte and dfx_port_read_byte, this - * is a pointer to store the read value. + * bp - pointer to board information + * offset - register offset from base I/O address + * data - for dfx_port_write_long, this is a value to write; + * for dfx_port_read_long, this is a pointer to store + * the read value * * Functional Description: * These routines perform the correct operation to read or write @@ -310,7 +343,7 @@ static struct net_device *root_dfx_eisa_ * registers using the register offsets defined in DEFXX.H. * * PCI port block base addresses are assigned by the PCI BIOS or system - * firmware. There is one 128 byte port block which can be accessed. It + * firmware. There is one 128 byte port block which can be accessed. It * allows for I/O mapping of both PDQ and PFI registers using the register * offsets defined in DEFXX.H. * @@ -318,7 +351,7 @@ static struct net_device *root_dfx_eisa_ * None * * Assumptions: - * bp->base_addr is a valid base I/O address for this adapter. + * bp->base is a valid base I/O address for this adapter. * offset is a valid register offset for this adapter. * * Side Effects: @@ -329,69 +362,135 @@ static struct net_device *root_dfx_eisa_ * advantage of strict data type checking. */ -static inline void dfx_port_write_byte( - DFX_board_t *bp, - int offset, - u8 data - ) +static inline void dfx_writel(DFX_board_t *bp, int offset, u32 data) +{ + writel(data, bp->base.mem + offset); + mb(); +} - { - u16 port = bp->base_addr + offset; +static inline void dfx_outl(DFX_board_t *bp, int offset, u32 data) +{ + outl(data, bp->base.port + offset); +} - outb(data, port); - } +static void dfx_port_write_long(DFX_board_t *bp, int offset, u32 data) +{ + struct device __unused *bdev = bp->bus_dev; + int dfx_bus_tc = DFX_BUS_TC(bdev); + int dfx_use_mmio = DFX_MMIO || dfx_bus_tc; -static inline void dfx_port_read_byte( - DFX_board_t *bp, - int offset, - u8 *data - ) + if (dfx_use_mmio) + dfx_writel(bp, offset, data); + else + dfx_outl(bp, offset, data); +} - { - u16 port = bp->base_addr + offset; - *data = inb(port); - } +static inline void dfx_readl(DFX_board_t *bp, int offset, u32 *data) +{ + mb(); + *data = readl(bp->base.mem + offset); +} -static inline void dfx_port_write_long( - DFX_board_t *bp, - int offset, - u32 data - ) +static inline void dfx_inl(DFX_board_t *bp, int offset, u32 *data) +{ + *data = inl(bp->base.port + offset); +} - { - u16 port = bp->base_addr + offset; +static void dfx_port_read_long(DFX_board_t *bp, int offset, u32 *data) +{ + struct device __unused *bdev = bp->bus_dev; + int dfx_bus_tc = DFX_BUS_TC(bdev); + int dfx_use_mmio = DFX_MMIO || dfx_bus_tc; - outl(data, port); - } + if (dfx_use_mmio) + dfx_readl(bp, offset, data); + else + dfx_inl(bp, offset, data); +} -static inline void dfx_port_read_long( - DFX_board_t *bp, - int offset, - u32 *data - ) - { - u16 port = bp->base_addr + offset; +/* + * ================ + * = dfx_get_bars = + * ================ + * + * Overview: + * Retrieves the address range used to access control and status + * registers. + * + * Returns: + * None + * + * Arguments: + * bdev - pointer to device information + * bar_start - pointer to store the start address + * bar_len - pointer to store the length of the area + * + * Assumptions: + * I am sure there are some. + * + * Side Effects: + * None + */ +static void dfx_get_bars(struct device *bdev, + resource_size_t *bar_start, resource_size_t *bar_len) +{ + int dfx_bus_pci = DFX_BUS_PCI(bdev); + int dfx_bus_eisa = DFX_BUS_EISA(bdev); + int dfx_bus_tc = DFX_BUS_TC(bdev); + int dfx_use_mmio = DFX_MMIO || dfx_bus_tc; - *data = inl(port); - } + if (dfx_bus_pci) { + int num = dfx_use_mmio ? 0 : 1; + *bar_start = pci_resource_start(to_pci_dev(bdev), num); + *bar_len = pci_resource_len(to_pci_dev(bdev), num); + } + if (dfx_bus_eisa) { + unsigned long base_addr = to_eisa_device(bdev)->base_addr; + resource_size_t bar; + + if (dfx_use_mmio) { + bar = inb(base_addr + PI_ESIC_K_MEM_ADD_CMP_2); + bar <<= 8; + bar |= inb(base_addr + PI_ESIC_K_MEM_ADD_CMP_1); + bar <<= 8; + bar |= inb(base_addr + PI_ESIC_K_MEM_ADD_CMP_0); + bar <<= 16; + *bar_start = bar; + bar = inb(base_addr + PI_ESIC_K_MEM_ADD_MASK_2); + bar <<= 8; + bar |= inb(base_addr + PI_ESIC_K_MEM_ADD_MASK_1); + bar <<= 8; + bar |= inb(base_addr + PI_ESIC_K_MEM_ADD_MASK_0); + bar <<= 16; + *bar_len = (bar | PI_MEM_ADD_MASK_M) + 1; + } else { + *bar_start = base_addr; + *bar_len = PI_ESIC_K_CSR_IO_LEN; + } + } + if (dfx_bus_tc) { + *bar_start = to_tc_dev(bdev)->resource.start + + PI_TC_K_CSR_OFFSET; + *bar_len = PI_TC_K_CSR_LEN; + } +} /* - * ============= - * = dfx_init_one_pci_or_eisa = - * ============= + * ================ + * = dfx_register = + * ================ * * Overview: - * Initializes a supported FDDI EISA or PCI controller + * Initializes a supported FDDI controller * * Returns: * Condition code * * Arguments: - * pdev - pointer to pci device information (NULL for EISA) - * ioaddr - pointer to port (NULL for PCI) + * bdev - pointer to device information * * Functional Description: * @@ -407,56 +506,74 @@ static inline void dfx_port_read_long( * initialized and the board resources are read and stored in * the device structure. */ -static int __devinit dfx_init_one_pci_or_eisa(struct pci_dev *pdev, long ioaddr) +static int __devinit dfx_register(struct device *bdev) { static int version_disp; - char *print_name = DRV_NAME; + int dfx_bus_pci = DFX_BUS_PCI(bdev); + int dfx_bus_tc = DFX_BUS_TC(bdev); + int dfx_use_mmio = DFX_MMIO || dfx_bus_tc; + char *print_name = bdev->bus_id; struct net_device *dev; DFX_board_t *bp; /* board pointer */ + resource_size_t bar_start = 0; /* pointer to port */ + resource_size_t bar_len = 0; /* resource length */ int alloc_size; /* total buffer size used */ - int err; + struct resource *region; + int err = 0; if (!version_disp) { /* display version info if adapter is found */ version_disp = 1; /* set display flag to TRUE so that */ printk(version); /* we only display this string ONCE */ } - if (pdev != NULL) - print_name = pci_name(pdev); - dev = alloc_fddidev(sizeof(*bp)); if (!dev) { - printk(KERN_ERR "%s: unable to allocate fddidev, aborting\n", + printk(KERN_ERR "%s: Unable to allocate fddidev, aborting\n", print_name); return -ENOMEM; } /* Enable PCI device. */ - if (pdev != NULL) { - err = pci_enable_device (pdev); - if (err) goto err_out; - ioaddr = pci_resource_start (pdev, 1); + if (dfx_bus_pci && pci_enable_device(to_pci_dev(bdev))) { + printk(KERN_ERR "%s: Cannot enable PCI device, aborting\n", + print_name); + goto err_out; } SET_MODULE_OWNER(dev); - if (pdev != NULL) - SET_NETDEV_DEV(dev, &pdev->dev); + SET_NETDEV_DEV(dev, bdev); + + bp = netdev_priv(dev); + bp->bus_dev = bdev; + dev_set_drvdata(bdev, dev); - bp = dev->priv; + dfx_get_bars(bdev, &bar_start, &bar_len); - if (!request_region(ioaddr, - pdev ? PFI_K_CSR_IO_LEN : PI_ESIC_K_CSR_IO_LEN, - print_name)) { + if (dfx_use_mmio) + region = request_mem_region(bar_start, bar_len, print_name); + else + region = request_region(bar_start, bar_len, print_name); + if (!region) { printk(KERN_ERR "%s: Cannot reserve I/O resource " - "0x%x @ 0x%lx, aborting\n", print_name, - pdev ? PFI_K_CSR_IO_LEN : PI_ESIC_K_CSR_IO_LEN, ioaddr); + "0x%lx @ 0x%lx, aborting\n", + print_name, (long)bar_len, (long)bar_start); err = -EBUSY; - goto err_out; + goto err_out_disable; } - /* Initialize new device structure */ + /* Set up I/O base address. */ + if (dfx_use_mmio) { + bp->base.mem = ioremap_nocache(bar_start, bar_len); + if (!bp->base.mem) { + printk(KERN_ERR "%s: Cannot map MMIO\n", print_name); + goto err_out_region; + } + } else { + bp->base.port = bar_start; + dev->base_addr = bar_start; + } - dev->base_addr = ioaddr; /* save port (I/O) base address */ + /* Initialize new device structure */ dev->get_stats = dfx_ctl_get_stats; dev->open = dfx_open; @@ -465,22 +582,12 @@ static int __devinit dfx_init_one_pci_or dev->set_multicast_list = dfx_ctl_set_multicast_list; dev->set_mac_address = dfx_ctl_set_mac_address; - if (pdev == NULL) { - /* EISA board */ - bp->bus_type = DFX_BUS_TYPE_EISA; - bp->next = root_dfx_eisa_dev; - root_dfx_eisa_dev = dev; - } else { - /* PCI board */ - bp->bus_type = DFX_BUS_TYPE_PCI; - bp->pci_dev = pdev; - pci_set_drvdata (pdev, dev); - pci_set_master (pdev); - } + if (dfx_bus_pci) + pci_set_master(to_pci_dev(bdev)); - if (dfx_driver_init(dev, print_name) != DFX_K_SUCCESS) { + if (dfx_driver_init(dev, print_name, bar_start) != DFX_K_SUCCESS) { err = -ENODEV; - goto err_out_region; + goto err_out_unmap; } err = register_netdev(dev); @@ -499,44 +606,28 @@ #endif sizeof(PI_CONSUMER_BLOCK) + (PI_ALIGN_K_DESC_BLK - 1); if (bp->kmalloced) - pci_free_consistent(pdev, alloc_size, - bp->kmalloced, bp->kmalloced_dma); + dma_free_coherent(bdev, alloc_size, + bp->kmalloced, bp->kmalloced_dma); + +err_out_unmap: + if (dfx_use_mmio) + iounmap(bp->base.mem); + err_out_region: - release_region(ioaddr, pdev ? PFI_K_CSR_IO_LEN : PI_ESIC_K_CSR_IO_LEN); + if (dfx_use_mmio) + release_mem_region(bar_start, bar_len); + else + release_region(bar_start, bar_len); + +err_out_disable: + if (dfx_bus_pci) + pci_disable_device(to_pci_dev(bdev)); + err_out: free_netdev(dev); return err; } -static int __devinit dfx_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) -{ - return dfx_init_one_pci_or_eisa(pdev, 0); -} - -static int __init dfx_eisa_init(void) -{ - int rc = -ENODEV; - int i; /* used in for loops */ - u16 port; /* temporary I/O (port) address */ - u32 slot_id; /* EISA hardware (slot) ID read from adapter */ - - DBG_printk("In dfx_eisa_init...\n"); - - /* Scan for FDDI EISA controllers */ - - for (i=0; i < DFX_MAX_EISA_SLOTS; i++) /* only scan for up to 16 EISA slots */ - { - port = (i << 12) + PI_ESIC_K_SLOT_ID; /* port = I/O address for reading slot ID */ - slot_id = inl(port); /* read EISA HW (slot) ID */ - if ((slot_id & 0xF0FFFFFF) == DEFEA_PRODUCT_ID) - { - port = (i << 12); /* recalc base addr */ - - if (dfx_init_one_pci_or_eisa(NULL, port) == 0) rc = 0; - } - } - return rc; -} /* * ================ @@ -544,7 +635,7 @@ static int __init dfx_eisa_init(void) * ================ * * Overview: - * Initializes EISA and PCI controller bus-specific logic. + * Initializes the bus-specific controller logic. * * Returns: * None @@ -560,7 +651,7 @@ static int __init dfx_eisa_init(void) * None * * Assumptions: - * dev->base_addr has already been set with the proper + * bp->base has already been set with the proper * base I/O address for this device. * * Side Effects: @@ -571,87 +662,103 @@ static int __init dfx_eisa_init(void) static void __devinit dfx_bus_init(struct net_device *dev) { - DFX_board_t *bp = dev->priv; - u8 val; /* used for I/O read/writes */ + DFX_board_t *bp = netdev_priv(dev); + struct device *bdev = bp->bus_dev; + int dfx_bus_pci = DFX_BUS_PCI(bdev); + int dfx_bus_eisa = DFX_BUS_EISA(bdev); + int dfx_bus_tc = DFX_BUS_TC(bdev); + int dfx_use_mmio = DFX_MMIO || dfx_bus_tc; + u8 val; DBG_printk("In dfx_bus_init...\n"); - /* - * Initialize base I/O address field in bp structure - * - * Note: bp->base_addr is the same as dev->base_addr. - * It's useful because often we'll need to read - * or write registers where we already have the - * bp pointer instead of the dev pointer. Having - * the base address in the bp structure will - * save a pointer dereference. - * - * IMPORTANT!! This field must be defined before - * any of the dfx_port_* inline functions are - * called. - */ - - bp->base_addr = dev->base_addr; - - /* And a pointer back to the net_device struct */ + /* Initialize a pointer back to the net_device struct */ bp->dev = dev; /* Initialize adapter based on bus type */ - if (bp->bus_type == DFX_BUS_TYPE_EISA) - { - /* Get the interrupt level from the ESIC chip */ - - dfx_port_read_byte(bp, PI_ESIC_K_IO_CONFIG_STAT_0, &val); - switch ((val & PI_CONFIG_STAT_0_M_IRQ) >> PI_CONFIG_STAT_0_V_IRQ) - { - case PI_CONFIG_STAT_0_IRQ_K_9: - dev->irq = 9; - break; - - case PI_CONFIG_STAT_0_IRQ_K_10: - dev->irq = 10; - break; + if (dfx_bus_tc) + dev->irq = to_tc_dev(bdev)->interrupt; + if (dfx_bus_eisa) { + unsigned long base_addr = to_eisa_device(bdev)->base_addr; - case PI_CONFIG_STAT_0_IRQ_K_11: - dev->irq = 11; - break; + /* Get the interrupt level from the ESIC chip. */ + val = inb(base_addr + PI_ESIC_K_IO_CONFIG_STAT_0); + val &= PI_CONFIG_STAT_0_M_IRQ; + val >>= PI_CONFIG_STAT_0_V_IRQ; - case PI_CONFIG_STAT_0_IRQ_K_15: - dev->irq = 15; - break; - } - - /* Enable access to I/O on the board by writing 0x03 to Function Control Register */ + switch (val) { + case PI_CONFIG_STAT_0_IRQ_K_9: + dev->irq = 9; + break; - dfx_port_write_byte(bp, PI_ESIC_K_FUNCTION_CNTRL, PI_ESIC_K_FUNCTION_CNTRL_IO_ENB); + case PI_CONFIG_STAT_0_IRQ_K_10: + dev->irq = 10; + break; - /* Set the I/O decode range of the board */ + case PI_CONFIG_STAT_0_IRQ_K_11: + dev->irq = 11; + break; - val = ((dev->base_addr >> 12) << PI_IO_CMP_V_SLOT); - dfx_port_write_byte(bp, PI_ESIC_K_IO_CMP_0_1, val); - dfx_port_write_byte(bp, PI_ESIC_K_IO_CMP_1_1, val); + case PI_CONFIG_STAT_0_IRQ_K_15: + dev->irq = 15; + break; + } - /* Enable access to rest of module (including PDQ and packet memory) */ + /* + * Enable memory decoding (MEMCS0) and/or port decoding + * (IOCS1/IOCS0) as appropriate in Function Control + * Register. One of the port chip selects seems to be + * used for the Burst Holdoff register, but this bit of + * documentation is missing and as yet it has not been + * determined which of the two. This is also the reason + * the size of the decoded port range is twice as large + * as one required by the PDQ. + */ - dfx_port_write_byte(bp, PI_ESIC_K_SLOT_CNTRL, PI_SLOT_CNTRL_M_ENB); + /* Set the decode range of the board. */ + val = ((bp->base.port >> 12) << PI_IO_CMP_V_SLOT); + outb(base_addr + PI_ESIC_K_IO_ADD_CMP_0_1, val); + outb(base_addr + PI_ESIC_K_IO_ADD_CMP_0_0, 0); + outb(base_addr + PI_ESIC_K_IO_ADD_CMP_1_1, val); + outb(base_addr + PI_ESIC_K_IO_ADD_CMP_1_0, 0); + val = PI_ESIC_K_CSR_IO_LEN - 1; + outb(base_addr + PI_ESIC_K_IO_ADD_MASK_0_1, (val >> 8) & 0xff); + outb(base_addr + PI_ESIC_K_IO_ADD_MASK_0_0, val & 0xff); + outb(base_addr + PI_ESIC_K_IO_ADD_MASK_1_1, (val >> 8) & 0xff); + outb(base_addr + PI_ESIC_K_IO_ADD_MASK_1_0, val & 0xff); + + /* Enable the decoders. */ + val = PI_FUNCTION_CNTRL_M_IOCS1 | PI_FUNCTION_CNTRL_M_IOCS0; + if (dfx_use_mmio) + val |= PI_FUNCTION_CNTRL_M_MEMCS0; + outb(base_addr + PI_ESIC_K_FUNCTION_CNTRL, val); /* - * Map PDQ registers into I/O space. This is done by clearing a bit - * in Burst Holdoff register. + * Enable access to the rest of the module + * (including PDQ and packet memory). */ + val = PI_SLOT_CNTRL_M_ENB; + outb(base_addr + PI_ESIC_K_SLOT_CNTRL, val); - dfx_port_read_byte(bp, PI_ESIC_K_BURST_HOLDOFF, &val); - dfx_port_write_byte(bp, PI_ESIC_K_BURST_HOLDOFF, (val & ~PI_BURST_HOLDOFF_M_MEM_MAP)); + /* + * Map PDQ registers into memory or port space. This is + * done with a bit in the Burst Holdoff register. + */ + val = inb(base_addr + PI_DEFEA_K_BURST_HOLDOFF); + if (dfx_use_mmio) + val |= PI_BURST_HOLDOFF_V_MEM_MAP; + else + val &= ~PI_BURST_HOLDOFF_V_MEM_MAP; + outb(base_addr + PI_DEFEA_K_BURST_HOLDOFF, val); /* Enable interrupts at EISA bus interface chip (ESIC) */ - - dfx_port_read_byte(bp, PI_ESIC_K_IO_CONFIG_STAT_0, &val); - dfx_port_write_byte(bp, PI_ESIC_K_IO_CONFIG_STAT_0, (val | PI_CONFIG_STAT_0_M_INT_ENB)); - } - else - { - struct pci_dev *pdev = bp->pci_dev; + val = inb(base_addr + PI_ESIC_K_IO_CONFIG_STAT_0); + val |= PI_CONFIG_STAT_0_M_INT_ENB; + outb(base_addr + PI_ESIC_K_IO_CONFIG_STAT_0, val); + } + if (dfx_bus_pci) { + struct pci_dev *pdev = to_pci_dev(bdev); /* Get the interrupt level from the PCI Configuration Table */ @@ -660,17 +767,70 @@ static void __devinit dfx_bus_init(struc /* Check Latency Timer and set if less than minimal */ pci_read_config_byte(pdev, PCI_LATENCY_TIMER, &val); - if (val < PFI_K_LAT_TIMER_MIN) /* if less than min, override with default */ - { + if (val < PFI_K_LAT_TIMER_MIN) { val = PFI_K_LAT_TIMER_DEF; pci_write_config_byte(pdev, PCI_LATENCY_TIMER, val); - } + } /* Enable interrupts at PCI bus interface chip (PFI) */ + val = PFI_MODE_M_PDQ_INT_ENB | PFI_MODE_M_DMA_ENB; + dfx_port_write_long(bp, PFI_K_REG_MODE_CTRL, val); + } +} - dfx_port_write_long(bp, PFI_K_REG_MODE_CTRL, (PFI_MODE_M_PDQ_INT_ENB | PFI_MODE_M_DMA_ENB)); - } +/* + * ================== + * = dfx_bus_uninit = + * ================== + * + * Overview: + * Uninitializes the bus-specific controller logic. + * + * Returns: + * None + * + * Arguments: + * dev - pointer to device information + * + * Functional Description: + * Perform bus-specific logic uninitialization. + * + * Return Codes: + * None + * + * Assumptions: + * bp->base has already been set with the proper + * base I/O address for this device. + * + * Side Effects: + * Interrupts are disabled at the adapter bus-specific logic. + */ + +static void __devinit dfx_bus_uninit(struct net_device *dev) +{ + DFX_board_t *bp = netdev_priv(dev); + struct device *bdev = bp->bus_dev; + int dfx_bus_pci = DFX_BUS_PCI(bdev); + int dfx_bus_eisa = DFX_BUS_EISA(bdev); + u8 val; + + DBG_printk("In dfx_bus_uninit...\n"); + + /* Uninitialize adapter based on bus type */ + + if (dfx_bus_eisa) { + unsigned long base_addr = to_eisa_device(bdev)->base_addr; + + /* Disable interrupts at EISA bus interface chip (ESIC) */ + val = inb(base_addr + PI_ESIC_K_IO_CONFIG_STAT_0); + val &= ~PI_CONFIG_STAT_0_M_INT_ENB; + outb(base_addr + PI_ESIC_K_IO_CONFIG_STAT_0, val); + } + if (dfx_bus_pci) { + /* Disable interrupts at PCI bus interface chip (PFI) */ + dfx_port_write_long(bp, PFI_K_REG_MODE_CTRL, 0); } +} /* @@ -705,18 +865,16 @@ static void __devinit dfx_bus_init(struc static void __devinit dfx_bus_config_check(DFX_board_t *bp) { + struct device __unused *bdev = bp->bus_dev; + int dfx_bus_eisa = DFX_BUS_EISA(bdev); int status; /* return code from adapter port control call */ - u32 slot_id; /* EISA-bus hardware id (DEC3001, DEC3002,...) */ u32 host_data; /* LW data returned from port control call */ DBG_printk("In dfx_bus_config_check...\n"); /* Configuration check only valid for EISA adapter */ - if (bp->bus_type == DFX_BUS_TYPE_EISA) - { - dfx_port_read_long(bp, PI_ESIC_K_SLOT_ID, &slot_id); - + if (dfx_bus_eisa) { /* * First check if revision 2 EISA controller. Rev. 1 cards used * PDQ revision B, so no workaround needed in this case. Rev. 3 @@ -724,14 +882,11 @@ static void __devinit dfx_bus_config_che * case, either. Only Rev. 2 cards used either Rev. D or E * chips, so we must verify the chip revision on Rev. 2 cards. */ - - if (slot_id == DEFEA_PROD_ID_2) - { + if (to_eisa_device(bdev)->id.driver_data == DEFEA_PROD_ID_2) { /* - * Revision 2 FDDI EISA controller found, so let's check PDQ - * revision of adapter. + * Revision 2 FDDI EISA controller found, + * so let's check PDQ revision of adapter. */ - status = dfx_hw_port_ctrl_req(bp, PI_PCTRL_M_SUB_CMD, PI_SUB_CMD_K_PDQ_REV_GET, @@ -805,13 +960,20 @@ static void __devinit dfx_bus_config_che */ static int __devinit dfx_driver_init(struct net_device *dev, - const char *print_name) + const char *print_name, + resource_size_t bar_start) { - DFX_board_t *bp = dev->priv; - int alloc_size; /* total buffer size needed */ - char *top_v, *curr_v; /* virtual addrs into memory block */ - dma_addr_t top_p, curr_p; /* physical addrs into memory block */ - u32 data; /* host data register value */ + DFX_board_t *bp = netdev_priv(dev); + struct device *bdev = bp->bus_dev; + int dfx_bus_pci = DFX_BUS_PCI(bdev); + int dfx_bus_eisa = DFX_BUS_EISA(bdev); + int dfx_bus_tc = DFX_BUS_TC(bdev); + int dfx_use_mmio = DFX_MMIO || dfx_bus_tc; + int alloc_size; /* total buffer size needed */ + char *top_v, *curr_v; /* virtual addrs into memory block */ + dma_addr_t top_p, curr_p; /* physical addrs into memory block */ + u32 data, le32; /* host data register value */ + char *board_name = NULL; DBG_printk("In dfx_driver_init...\n"); @@ -860,8 +1022,8 @@ static int __devinit dfx_driver_init(str print_name); return(DFX_K_FAILURE); } - data = cpu_to_le32(data); - memcpy(&bp->factory_mac_addr[0], &data, sizeof(u32)); + le32 = cpu_to_le32(data); + memcpy(&bp->factory_mac_addr[0], &le32, sizeof(u32)); if (dfx_hw_port_ctrl_req(bp, PI_PCTRL_M_MLA, PI_PDATA_A_MLA_K_HI, 0, &data) != DFX_K_SUCCESS) { @@ -869,8 +1031,8 @@ static int __devinit dfx_driver_init(str print_name); return(DFX_K_FAILURE); } - data = cpu_to_le32(data); - memcpy(&bp->factory_mac_addr[4], &data, sizeof(u16)); + le32 = cpu_to_le32(data); + memcpy(&bp->factory_mac_addr[4], &le32, sizeof(u16)); /* * Set current address to factory address @@ -880,20 +1042,18 @@ static int __devinit dfx_driver_init(str */ memcpy(dev->dev_addr, bp->factory_mac_addr, FDDI_K_ALEN); - if (bp->bus_type == DFX_BUS_TYPE_EISA) - printk("%s: DEFEA at I/O addr = 0x%lX, IRQ = %d, " - "Hardware addr = %02X-%02X-%02X-%02X-%02X-%02X\n", - print_name, dev->base_addr, dev->irq, - dev->dev_addr[0], dev->dev_addr[1], - dev->dev_addr[2], dev->dev_addr[3], - dev->dev_addr[4], dev->dev_addr[5]); - else - printk("%s: DEFPA at I/O addr = 0x%lX, IRQ = %d, " - "Hardware addr = %02X-%02X-%02X-%02X-%02X-%02X\n", - print_name, dev->base_addr, dev->irq, - dev->dev_addr[0], dev->dev_addr[1], - dev->dev_addr[2], dev->dev_addr[3], - dev->dev_addr[4], dev->dev_addr[5]); + if (dfx_bus_tc) + board_name = "DEFTA"; + if (dfx_bus_eisa) + board_name = "DEFEA"; + if (dfx_bus_pci) + board_name = "DEFPA"; + pr_info("%s: %s at %saddr = 0x%llx, IRQ = %d, " + "Hardware addr = %02X-%02X-%02X-%02X-%02X-%02X\n", + print_name, board_name, dfx_use_mmio ? "" : "I/O ", + (long long)bar_start, dev->irq, + dev->dev_addr[0], dev->dev_addr[1], dev->dev_addr[2], + dev->dev_addr[3], dev->dev_addr[4], dev->dev_addr[5]); /* * Get memory for descriptor block, consumer block, and other buffers @@ -908,8 +1068,9 @@ #ifndef DYNAMIC_BUFFERS #endif sizeof(PI_CONSUMER_BLOCK) + (PI_ALIGN_K_DESC_BLK - 1); - bp->kmalloced = top_v = pci_alloc_consistent(bp->pci_dev, alloc_size, - &bp->kmalloced_dma); + bp->kmalloced = top_v = dma_alloc_coherent(bp->bus_dev, alloc_size, + &bp->kmalloced_dma, + GFP_ATOMIC); if (top_v == NULL) { printk("%s: Could not allocate memory for host buffers " "and structures!\n", print_name); @@ -1219,14 +1380,15 @@ static int dfx_adap_init(DFX_board_t *bp static int dfx_open(struct net_device *dev) { + DFX_board_t *bp = netdev_priv(dev); int ret; - DFX_board_t *bp = dev->priv; DBG_printk("In dfx_open...\n"); /* Register IRQ - support shared interrupts by passing device ptr */ - ret = request_irq(dev->irq, dfx_interrupt, IRQF_SHARED, dev->name, dev); + ret = request_irq(dev->irq, dfx_interrupt, IRQF_SHARED, dev->name, + dev); if (ret) { printk(KERN_ERR "%s: Requested IRQ %d is busy\n", dev->name, dev->irq); return ret; @@ -1309,7 +1471,7 @@ static int dfx_open(struct net_device *d static int dfx_close(struct net_device *dev) { - DFX_board_t *bp = dev->priv; + DFX_board_t *bp = netdev_priv(dev); DBG_printk("In dfx_close...\n"); @@ -1645,7 +1807,7 @@ static void dfx_int_type_0_process(DFX_b static void dfx_int_common(struct net_device *dev) { - DFX_board_t *bp = dev->priv; + DFX_board_t *bp = netdev_priv(dev); PI_UINT32 port_status; /* Port Status register */ /* Process xmt interrupts - frequent case, so always call this routine */ @@ -1715,18 +1877,16 @@ static void dfx_int_common(struct net_de static irqreturn_t dfx_interrupt(int irq, void *dev_id) { - struct net_device *dev = dev_id; - DFX_board_t *bp; /* private board structure pointer */ - - /* Get board pointer only if device structure is valid */ - - bp = dev->priv; - - /* See if we're already servicing an interrupt */ + struct net_device *dev = dev_id; + DFX_board_t *bp = netdev_priv(dev); + struct device *bdev = bp->bus_dev; + int dfx_bus_pci = DFX_BUS_PCI(bdev); + int dfx_bus_eisa = DFX_BUS_EISA(bdev); + int dfx_bus_tc = DFX_BUS_TC(bdev); /* Service adapter interrupts */ - if (bp->bus_type == DFX_BUS_TYPE_PCI) { + if (dfx_bus_pci) { u32 status; dfx_port_read_long(bp, PFI_K_REG_STATUS, &status); @@ -1750,10 +1910,12 @@ static irqreturn_t dfx_interrupt(int irq PFI_MODE_M_DMA_ENB)); spin_unlock(&bp->lock); - } else { + } + if (dfx_bus_eisa) { + unsigned long base_addr = to_eisa_device(bdev)->base_addr; u8 status; - dfx_port_read_byte(bp, PI_ESIC_K_IO_CONFIG_STAT_0, &status); + status = inb(base_addr + PI_ESIC_K_IO_CONFIG_STAT_0); if (!(status & PI_CONFIG_STAT_0_M_PEND)) return IRQ_NONE; @@ -1761,15 +1923,35 @@ static irqreturn_t dfx_interrupt(int irq /* Disable interrupts at the ESIC */ status &= ~PI_CONFIG_STAT_0_M_INT_ENB; - dfx_port_write_byte(bp, PI_ESIC_K_IO_CONFIG_STAT_0, status); + outb(base_addr + PI_ESIC_K_IO_CONFIG_STAT_0, status); /* Call interrupt service routine for this adapter */ dfx_int_common(dev); /* Reenable interrupts at the ESIC */ - dfx_port_read_byte(bp, PI_ESIC_K_IO_CONFIG_STAT_0, &status); + status = inb(base_addr + PI_ESIC_K_IO_CONFIG_STAT_0); status |= PI_CONFIG_STAT_0_M_INT_ENB; - dfx_port_write_byte(bp, PI_ESIC_K_IO_CONFIG_STAT_0, status); + outb(base_addr + PI_ESIC_K_IO_CONFIG_STAT_0, status); + + spin_unlock(&bp->lock); + } + if (dfx_bus_tc) { + u32 status; + + dfx_port_read_long(bp, PI_PDQ_K_REG_PORT_STATUS, &status); + if (!(status & (PI_PSTATUS_M_RCV_DATA_PENDING | + PI_PSTATUS_M_XMT_DATA_PENDING | + PI_PSTATUS_M_SMT_HOST_PENDING | + PI_PSTATUS_M_UNSOL_PENDING | + PI_PSTATUS_M_CMD_RSP_PENDING | + PI_PSTATUS_M_CMD_REQ_PENDING | + PI_PSTATUS_M_TYPE_0_PENDING))) + return IRQ_NONE; + + spin_lock(&bp->lock); + + /* Call interrupt service routine for this adapter */ + dfx_int_common(dev); spin_unlock(&bp->lock); } @@ -1823,7 +2005,7 @@ static irqreturn_t dfx_interrupt(int irq static struct net_device_stats *dfx_ctl_get_stats(struct net_device *dev) { - DFX_board_t *bp = dev->priv; + DFX_board_t *bp = netdev_priv(dev); /* Fill the bp->stats structure with driver-maintained counters */ @@ -2009,8 +2191,8 @@ static struct net_device_stats *dfx_ctl_ */ static void dfx_ctl_set_multicast_list(struct net_device *dev) - { - DFX_board_t *bp = dev->priv; +{ + DFX_board_t *bp = netdev_priv(dev); int i; /* used as index in for loop */ struct dev_mc_list *dmi; /* ptr to multicast addr entry */ @@ -2124,8 +2306,8 @@ static void dfx_ctl_set_multicast_list(s static int dfx_ctl_set_mac_address(struct net_device *dev, void *addr) { - DFX_board_t *bp = dev->priv; struct sockaddr *p_sockaddr = (struct sockaddr *)addr; + DFX_board_t *bp = netdev_priv(dev); /* Copy unicast address to driver-maintained structs and update count */ @@ -2764,9 +2946,9 @@ #ifdef DYNAMIC_BUFFERS my_skb_align(newskb, 128); bp->descr_block_virt->rcv_data[i + j].long_1 = - (u32)pci_map_single(bp->pci_dev, newskb->data, + (u32)dma_map_single(bp->bus_dev, newskb->data, NEW_SKB_SIZE, - PCI_DMA_FROMDEVICE); + DMA_FROM_DEVICE); /* * p_rcv_buff_va is only used inside the * kernel so we put the skb pointer here. @@ -2880,17 +3062,17 @@ #ifdef DYNAMIC_BUFFERS my_skb_align(newskb, 128); skb = (struct sk_buff *)bp->p_rcv_buff_va[entry]; - pci_unmap_single(bp->pci_dev, + dma_unmap_single(bp->bus_dev, bp->descr_block_virt->rcv_data[entry].long_1, NEW_SKB_SIZE, - PCI_DMA_FROMDEVICE); + DMA_FROM_DEVICE); skb_reserve(skb, RCV_BUFF_K_PADDING); bp->p_rcv_buff_va[entry] = (char *)newskb; bp->descr_block_virt->rcv_data[entry].long_1 = - (u32)pci_map_single(bp->pci_dev, + (u32)dma_map_single(bp->bus_dev, newskb->data, NEW_SKB_SIZE, - PCI_DMA_FROMDEVICE); + DMA_FROM_DEVICE); } else skb = NULL; } else @@ -3010,7 +3192,7 @@ static int dfx_xmt_queue_pkt( ) { - DFX_board_t *bp = dev->priv; + DFX_board_t *bp = netdev_priv(dev); u8 prod; /* local transmit producer index */ PI_XMT_DESCR *p_xmt_descr; /* ptr to transmit descriptor block entry */ XMT_DRIVER_DESCR *p_xmt_drv_descr; /* ptr to transmit driver descriptor */ @@ -3116,8 +3298,8 @@ static int dfx_xmt_queue_pkt( */ p_xmt_descr->long_0 = (u32) (PI_XMT_DESCR_M_SOP | PI_XMT_DESCR_M_EOP | ((skb->len) << PI_XMT_DESCR_V_SEG_LEN)); - p_xmt_descr->long_1 = (u32)pci_map_single(bp->pci_dev, skb->data, - skb->len, PCI_DMA_TODEVICE); + p_xmt_descr->long_1 = (u32)dma_map_single(bp->bus_dev, skb->data, + skb->len, DMA_TO_DEVICE); /* * Verify that descriptor is actually available @@ -3220,10 +3402,10 @@ static int dfx_xmt_done(DFX_board_t *bp) /* Return skb to operating system */ comp = bp->rcv_xmt_reg.index.xmt_comp; - pci_unmap_single(bp->pci_dev, + dma_unmap_single(bp->bus_dev, bp->descr_block_virt->xmt_data[comp].long_1, p_xmt_drv_descr->p_skb->len, - PCI_DMA_TODEVICE); + DMA_TO_DEVICE); dev_kfree_skb_irq(p_xmt_drv_descr->p_skb); /* @@ -3344,10 +3526,10 @@ static void dfx_xmt_flush( DFX_board_t * /* Return skb to operating system */ comp = bp->rcv_xmt_reg.index.xmt_comp; - pci_unmap_single(bp->pci_dev, + dma_unmap_single(bp->bus_dev, bp->descr_block_virt->xmt_data[comp].long_1, p_xmt_drv_descr->p_skb->len, - PCI_DMA_TODEVICE); + DMA_TO_DEVICE); dev_kfree_skb(p_xmt_drv_descr->p_skb); /* Increment transmit error counter */ @@ -3375,13 +3557,44 @@ static void dfx_xmt_flush( DFX_board_t * bp->cons_block_virt->xmt_rcv_data = prod_cons; } -static void __devexit dfx_remove_one_pci_or_eisa(struct pci_dev *pdev, struct net_device *dev) +/* + * ================== + * = dfx_unregister = + * ================== + * + * Overview: + * Shuts down an FDDI controller + * + * Returns: + * Condition code + * + * Arguments: + * bdev - pointer to device information + * + * Functional Description: + * + * Return Codes: + * None + * + * Assumptions: + * It compiles so it should work :-( (PCI cards do :-) + * + * Side Effects: + * Device structures for FDDI adapters (fddi0, fddi1, etc) are + * freed. + */ +static void __devexit dfx_unregister(struct device *bdev) { - DFX_board_t *bp = dev->priv; + struct net_device *dev = dev_get_drvdata(bdev); + DFX_board_t *bp = netdev_priv(dev); + int dfx_bus_pci = DFX_BUS_PCI(bdev); + int dfx_bus_tc = DFX_BUS_TC(bdev); + int dfx_use_mmio = DFX_MMIO || dfx_bus_tc; + resource_size_t bar_start = 0; /* pointer to port */ + resource_size_t bar_len = 0; /* resource length */ int alloc_size; /* total buffer size used */ unregister_netdev(dev); - release_region(dev->base_addr, pdev ? PFI_K_CSR_IO_LEN : PI_ESIC_K_CSR_IO_LEN ); alloc_size = sizeof(PI_DESCR_BLOCK) + PI_CMD_REQ_K_SIZE_MAX + PI_CMD_RSP_K_SIZE_MAX + @@ -3391,78 +3604,141 @@ #endif sizeof(PI_CONSUMER_BLOCK) + (PI_ALIGN_K_DESC_BLK - 1); if (bp->kmalloced) - pci_free_consistent(pdev, alloc_size, bp->kmalloced, - bp->kmalloced_dma); + dma_free_coherent(bdev, alloc_size, + bp->kmalloced, bp->kmalloced_dma); + + dfx_bus_uninit(dev); + + dfx_get_bars(bdev, &bar_start, &bar_len); + if (dfx_use_mmio) { + iounmap(bp->base.mem); + release_mem_region(bar_start, bar_len); + } else + release_region(bar_start, bar_len); + + if (dfx_bus_pci) + pci_disable_device(to_pci_dev(bdev)); + free_netdev(dev); } -static void __devexit dfx_remove_one (struct pci_dev *pdev) -{ - struct net_device *dev = pci_get_drvdata(pdev); - dfx_remove_one_pci_or_eisa(pdev, dev); - pci_set_drvdata(pdev, NULL); -} +static int __devinit __unused dfx_dev_register(struct device *); +static int __devexit __unused dfx_dev_unregister(struct device *); -static struct pci_device_id dfx_pci_tbl[] = { - { PCI_VENDOR_ID_DEC, PCI_DEVICE_ID_DEC_FDDI, PCI_ANY_ID, PCI_ANY_ID, }, - { 0, } +#ifdef CONFIG_PCI +static int __devinit dfx_pci_register(struct pci_dev *, + const struct pci_device_id *); +static void __devexit dfx_pci_unregister(struct pci_dev *); + +static struct pci_device_id dfx_pci_table[] = { + { PCI_DEVICE(PCI_VENDOR_ID_DEC, PCI_DEVICE_ID_DEC_FDDI) }, + { } }; -MODULE_DEVICE_TABLE(pci, dfx_pci_tbl); +MODULE_DEVICE_TABLE(pci, dfx_pci_table); -static struct pci_driver dfx_driver = { +static struct pci_driver dfx_pci_driver = { .name = "defxx", - .probe = dfx_init_one, - .remove = __devexit_p(dfx_remove_one), - .id_table = dfx_pci_tbl, + .id_table = dfx_pci_table, + .probe = dfx_pci_register, + .remove = __devexit_p(dfx_pci_unregister), }; -static int dfx_have_pci; -static int dfx_have_eisa; - +static __devinit int dfx_pci_register(struct pci_dev *pdev, + const struct pci_device_id *ent) +{ + return dfx_register(&pdev->dev); +} -static void __exit dfx_eisa_cleanup(void) +static void __devexit dfx_pci_unregister(struct pci_dev *pdev) { - struct net_device *dev = root_dfx_eisa_dev; + dfx_unregister(&pdev->dev); +} +#endif /* CONFIG_PCI */ + +#ifdef CONFIG_EISA +static struct eisa_device_id dfx_eisa_table[] = { + { "DEC3001", DEFEA_PROD_ID_1 }, + { "DEC3002", DEFEA_PROD_ID_2 }, + { "DEC3003", DEFEA_PROD_ID_3 }, + { "DEC3004", DEFEA_PROD_ID_4 }, + { } +}; +MODULE_DEVICE_TABLE(eisa, dfx_eisa_table); + +static struct eisa_driver dfx_eisa_driver = { + .id_table = dfx_eisa_table, + .driver = { + .name = "defxx", + .bus = &eisa_bus_type, + .probe = dfx_dev_register, + .remove = __devexit_p(dfx_dev_unregister), + }, +}; +#endif /* CONFIG_EISA */ + +#ifdef CONFIG_TC +static struct tc_device_id const dfx_tc_table[] = { + { "DEC ", "PMAF-FA " }, + { "DEC ", "PMAF-FD " }, + { "DEC ", "PMAF-FS " }, + { "DEC ", "PMAF-FU " }, + { } +}; +MODULE_DEVICE_TABLE(tc, dfx_tc_table); + +static struct tc_driver dfx_tc_driver = { + .id_table = dfx_tc_table, + .driver = { + .name = "defxx", + .bus = &tc_bus_type, + .probe = dfx_dev_register, + .remove = __devexit_p(dfx_dev_unregister), + }, +}; +#endif /* CONFIG_TC */ - while (dev) - { - struct net_device *tmp; - DFX_board_t *bp; +static int __devinit __unused dfx_dev_register(struct device *dev) +{ + int status; - bp = (DFX_board_t*)dev->priv; - tmp = bp->next; - dfx_remove_one_pci_or_eisa(NULL, dev); - dev = tmp; - } + status = dfx_register(dev); + if (!status) + get_device(dev); + return status; } -static int __init dfx_init(void) +static int __devexit __unused dfx_dev_unregister(struct device *dev) { - int rc_pci, rc_eisa; - - rc_pci = pci_register_driver(&dfx_driver); - if (rc_pci >= 0) dfx_have_pci = 1; + put_device(dev); + dfx_unregister(dev); + return 0; +} - rc_eisa = dfx_eisa_init(); - if (rc_eisa >= 0) dfx_have_eisa = 1; - return ((rc_eisa < 0) ? 0 : rc_eisa) + ((rc_pci < 0) ? 0 : rc_pci); +static int __devinit dfx_init(void) +{ + int status; + + status = pci_register_driver(&dfx_pci_driver); + if (!status) + status = eisa_driver_register(&dfx_eisa_driver); + if (!status) + status = tc_register_driver(&dfx_tc_driver); + return status; } -static void __exit dfx_cleanup(void) +static void __devexit dfx_cleanup(void) { - if (dfx_have_pci) - pci_unregister_driver(&dfx_driver); - if (dfx_have_eisa) - dfx_eisa_cleanup(); - + tc_unregister_driver(&dfx_tc_driver); + eisa_driver_unregister(&dfx_eisa_driver); + pci_unregister_driver(&dfx_pci_driver); } module_init(dfx_init); module_exit(dfx_cleanup); MODULE_AUTHOR("Lawrence V. Stefani"); -MODULE_DESCRIPTION("DEC FDDIcontroller EISA/PCI (DEFEA/DEFPA) driver " +MODULE_DESCRIPTION("DEC FDDIcontroller TC/EISA/PCI (DEFTA/DEFEA/DEFPA) driver " DRV_VERSION " " DRV_RELDATE); MODULE_LICENSE("GPL"); diff --git a/drivers/net/defxx.h b/drivers/net/defxx.h index 2ce8f97..19a6f64 100644 --- a/drivers/net/defxx.h +++ b/drivers/net/defxx.h @@ -26,6 +26,7 @@ * 12-Sep-96 LVS Removed packet request header pointers. * 04 Aug 2003 macro Converted to the DMA API. * 23 Oct 2006 macro Big-endian host support. + * 14 Dec 2006 macro TURBOchannel support. */ #ifndef _DEFXX_H_ @@ -1471,9 +1472,17 @@ #define PI_PDATA_A_INIT_M_BSWAP_INIT \ #endif /* __BIG_ENDIAN */ +/* Define TC PDQ CSR offset and length */ + +#define PI_TC_K_CSR_OFFSET 0x100000 +#define PI_TC_K_CSR_LEN 0x40 /* 64 bytes */ + /* Define EISA controller register offsets */ -#define PI_ESIC_K_BURST_HOLDOFF 0x040 +#define PI_ESIC_K_CSR_IO_LEN 0x80 /* 128 bytes */ + +#define PI_DEFEA_K_BURST_HOLDOFF 0x040 + #define PI_ESIC_K_SLOT_ID 0xC80 #define PI_ESIC_K_SLOT_CNTRL 0xC84 #define PI_ESIC_K_MEM_ADD_CMP_0 0xC85 @@ -1488,14 +1497,14 @@ #define PI_ESIC_K_MEM_ADD_MASK_2 0x #define PI_ESIC_K_MEM_ADD_LO_CMP_0 0xC8E #define PI_ESIC_K_MEM_ADD_LO_CMP_1 0xC8F #define PI_ESIC_K_MEM_ADD_LO_CMP_2 0xC90 -#define PI_ESIC_K_IO_CMP_0_0 0xC91 -#define PI_ESIC_K_IO_CMP_0_1 0xC92 -#define PI_ESIC_K_IO_CMP_1_0 0xC93 -#define PI_ESIC_K_IO_CMP_1_1 0xC94 -#define PI_ESIC_K_IO_CMP_2_0 0xC95 -#define PI_ESIC_K_IO_CMP_2_1 0xC96 -#define PI_ESIC_K_IO_CMP_3_0 0xC97 -#define PI_ESIC_K_IO_CMP_3_1 0xC98 +#define PI_ESIC_K_IO_ADD_CMP_0_0 0xC91 +#define PI_ESIC_K_IO_ADD_CMP_0_1 0xC92 +#define PI_ESIC_K_IO_ADD_CMP_1_0 0xC93 +#define PI_ESIC_K_IO_ADD_CMP_1_1 0xC94 +#define PI_ESIC_K_IO_ADD_CMP_2_0 0xC95 +#define PI_ESIC_K_IO_ADD_CMP_2_1 0xC96 +#define PI_ESIC_K_IO_ADD_CMP_3_0 0xC97 +#define PI_ESIC_K_IO_ADD_CMP_3_1 0xC98 #define PI_ESIC_K_IO_ADD_MASK_0_0 0xC99 #define PI_ESIC_K_IO_ADD_MASK_0_1 0xC9A #define PI_ESIC_K_IO_ADD_MASK_1_0 0xC9B @@ -1518,11 +1527,16 @@ #define PI_ESIC_K_DMA_CONFIG 0x #define PI_ESIC_K_INPUT_PORT 0xCAC #define PI_ESIC_K_OUTPUT_PORT 0xCAD #define PI_ESIC_K_FUNCTION_CNTRL 0xCAE -#define PI_ESIC_K_CSR_IO_LEN PI_ESIC_K_FUNCTION_CNTRL+1 /* always last reg + 1 */ -/* Define the value all drivers must write to the function control register. */ +/* Define the bits in the function control register. */ -#define PI_ESIC_K_FUNCTION_CNTRL_IO_ENB 0x03 +#define PI_FUNCTION_CNTRL_M_IOCS0 0x01 +#define PI_FUNCTION_CNTRL_M_IOCS1 0x02 +#define PI_FUNCTION_CNTRL_M_IOCS2 0x04 +#define PI_FUNCTION_CNTRL_M_IOCS3 0x08 +#define PI_FUNCTION_CNTRL_M_MEMCS0 0x10 +#define PI_FUNCTION_CNTRL_M_MEMCS1 0x20 +#define PI_FUNCTION_CNTRL_M_DMA 0x80 /* Define the bits in the slot control register. */ @@ -1540,6 +1554,10 @@ #define PI_BURST_HOLDOFF_V_HOLDOFF 2 #define PI_BURST_HOLDOFF_V_RESERVED 1 #define PI_BURST_HOLDOFF_V_MEM_MAP 0 +/* Define the implicit mask of the Memory Address Mask Register. */ + +#define PI_MEM_ADD_MASK_M 0x3ff + /* * Define the fields in the IO Compare registers. * The driver must initialize the slot field with the slot ID shifted by the @@ -1577,6 +1595,7 @@ #define DEFEA_PRODUCT_ID 0x0030A310 /* #define DEFEA_PROD_ID_1 0x0130A310 /* DEC product 300, rev 1 */ #define DEFEA_PROD_ID_2 0x0230A310 /* DEC product 300, rev 2 */ #define DEFEA_PROD_ID_3 0x0330A310 /* DEC product 300, rev 3 */ +#define DEFEA_PROD_ID_4 0x0430A310 /* DEC product 300, rev 4 */ /**********************************************/ /* Digital PFI Specification v1.0 Definitions */ @@ -1633,12 +1652,6 @@ #define PFI_STATUS_V_FIFO_FULL 2 #define PFI_STATUS_V_FIFO_EMPTY 1 #define PFI_STATUS_V_DMA_IN_PROGRESS 0 -#define DFX_MAX_EISA_SLOTS 16 /* maximum number of EISA slots to scan */ -#define DFX_MAX_NUM_BOARDS 8 /* maximum number of adapters supported */ - -#define DFX_BUS_TYPE_PCI 0 /* type code for DEC FDDIcontroller/PCI */ -#define DFX_BUS_TYPE_EISA 1 /* type code for DEC FDDIcontroller/EISA */ - #define DFX_FC_PRH2_PRH1_PRH0 0x54003820 /* Packet Request Header bytes + FC */ #define DFX_PRH0_BYTE 0x20 /* Packet Request Header byte 0 */ #define DFX_PRH1_BYTE 0x38 /* Packet Request Header byte 1 */ @@ -1756,10 +1769,11 @@ typedef struct DFX_board_tag /* Store device, bus-specific, and parameter information for this adapter */ struct net_device *dev; /* pointer to device structure */ - struct net_device *next; - u32 bus_type; /* bus type (0 == PCI, 1 == EISA) */ - u16 base_addr; /* base I/O address (same as dev->base_addr) */ - struct pci_dev * pci_dev; + union { + void __iomem *mem; + int port; + } base; /* base address */ + struct device *bus_dev; u32 full_duplex_enb; /* FDDI Full Duplex enable (1 == on, 2 == off) */ u32 req_ttrt; /* requested TTRT value (in 80ns units) */ u32 burst_size; /* adapter burst size (enumerated) */ diff --git a/drivers/net/e1000/e1000.h b/drivers/net/e1000/e1000.h index f091042..689f158 100644 --- a/drivers/net/e1000/e1000.h +++ b/drivers/net/e1000/e1000.h @@ -59,17 +59,13 @@ #include #include #include #include -#ifdef NETIF_F_TSO6 #include -#endif #include #include #include #include #include -#ifdef NETIF_F_TSO #include -#endif #include #include #include @@ -257,7 +253,6 @@ #ifdef CONFIG_E1000_NAPI spinlock_t tx_queue_lock; #endif atomic_t irq_sem; - unsigned int detect_link; unsigned int total_tx_bytes; unsigned int total_tx_packets; unsigned int total_rx_bytes; @@ -348,9 +343,7 @@ #ifdef CONFIG_PCI_MSI boolean_t have_msi; #endif /* to not mess up cache alignment, always add to the bottom */ -#ifdef NETIF_F_TSO boolean_t tso_force; -#endif boolean_t smart_power_down; /* phy smart power down */ boolean_t quad_port_a; unsigned long flags; diff --git a/drivers/net/e1000/e1000_ethtool.c b/drivers/net/e1000/e1000_ethtool.c index fb96c87..44ebc72 100644 --- a/drivers/net/e1000/e1000_ethtool.c +++ b/drivers/net/e1000/e1000_ethtool.c @@ -338,7 +338,6 @@ e1000_set_tx_csum(struct net_device *net return 0; } -#ifdef NETIF_F_TSO static int e1000_set_tso(struct net_device *netdev, uint32_t data) { @@ -352,18 +351,15 @@ e1000_set_tso(struct net_device *netdev, else netdev->features &= ~NETIF_F_TSO; -#ifdef NETIF_F_TSO6 if (data) netdev->features |= NETIF_F_TSO6; else netdev->features &= ~NETIF_F_TSO6; -#endif DPRINTK(PROBE, INFO, "TSO is %s\n", data ? "Enabled" : "Disabled"); adapter->tso_force = TRUE; return 0; } -#endif /* NETIF_F_TSO */ static uint32_t e1000_get_msglevel(struct net_device *netdev) @@ -1971,10 +1967,8 @@ static const struct ethtool_ops e1000_et .set_tx_csum = e1000_set_tx_csum, .get_sg = ethtool_op_get_sg, .set_sg = ethtool_op_set_sg, -#ifdef NETIF_F_TSO .get_tso = ethtool_op_get_tso, .set_tso = e1000_set_tso, -#endif .self_test_count = e1000_diag_test_count, .self_test = e1000_diag_test, .get_strings = e1000_get_strings, diff --git a/drivers/net/e1000/e1000_main.c b/drivers/net/e1000/e1000_main.c index c6259c7..619c892 100644 --- a/drivers/net/e1000/e1000_main.c +++ b/drivers/net/e1000/e1000_main.c @@ -36,7 +36,7 @@ #define DRIVERNAPI #else #define DRIVERNAPI "-NAPI" #endif -#define DRV_VERSION "7.3.15-k2"DRIVERNAPI +#define DRV_VERSION "7.3.20-k2"DRIVERNAPI char e1000_driver_version[] = DRV_VERSION; static char e1000_copyright[] = "Copyright (c) 1999-2006 Intel Corporation."; @@ -990,16 +990,12 @@ #endif netdev->features &= ~NETIF_F_HW_VLAN_FILTER; } -#ifdef NETIF_F_TSO if ((adapter->hw.mac_type >= e1000_82544) && (adapter->hw.mac_type != e1000_82547)) netdev->features |= NETIF_F_TSO; -#ifdef NETIF_F_TSO6 if (adapter->hw.mac_type > e1000_82547_rev_2) netdev->features |= NETIF_F_TSO6; -#endif -#endif if (pci_using_dac) netdev->features |= NETIF_F_HIGHDMA; @@ -2583,15 +2579,22 @@ e1000_watchdog(unsigned long data) if (link) { if (!netif_carrier_ok(netdev)) { + uint32_t ctrl; boolean_t txb2b = 1; e1000_get_speed_and_duplex(&adapter->hw, &adapter->link_speed, &adapter->link_duplex); - DPRINTK(LINK, INFO, "NIC Link is Up %d Mbps %s\n", - adapter->link_speed, - adapter->link_duplex == FULL_DUPLEX ? - "Full Duplex" : "Half Duplex"); + ctrl = E1000_READ_REG(&adapter->hw, CTRL); + DPRINTK(LINK, INFO, "NIC Link is Up %d Mbps %s, " + "Flow Control: %s\n", + adapter->link_speed, + adapter->link_duplex == FULL_DUPLEX ? + "Full Duplex" : "Half Duplex", + ((ctrl & E1000_CTRL_TFCE) && (ctrl & + E1000_CTRL_RFCE)) ? "RX/TX" : ((ctrl & + E1000_CTRL_RFCE) ? "RX" : ((ctrl & + E1000_CTRL_TFCE) ? "TX" : "None" ))); /* tweak tx_queue_len according to speed/duplex * and adjust the timeout factor */ @@ -2619,7 +2622,6 @@ e1000_watchdog(unsigned long data) E1000_WRITE_REG(&adapter->hw, TARC0, tarc0); } -#ifdef NETIF_F_TSO /* disable TSO for pcie and 10/100 speeds, to avoid * some hardware issues */ if (!adapter->tso_force && @@ -2630,22 +2632,17 @@ #ifdef NETIF_F_TSO DPRINTK(PROBE,INFO, "10/100 speed: disabling TSO\n"); netdev->features &= ~NETIF_F_TSO; -#ifdef NETIF_F_TSO6 netdev->features &= ~NETIF_F_TSO6; -#endif break; case SPEED_1000: netdev->features |= NETIF_F_TSO; -#ifdef NETIF_F_TSO6 netdev->features |= NETIF_F_TSO6; -#endif break; default: /* oops */ break; } } -#endif /* enable transmits in the hardware, need to do this * after setting TARC0 */ @@ -2875,7 +2872,6 @@ static int e1000_tso(struct e1000_adapter *adapter, struct e1000_tx_ring *tx_ring, struct sk_buff *skb) { -#ifdef NETIF_F_TSO struct e1000_context_desc *context_desc; struct e1000_buffer *buffer_info; unsigned int i; @@ -2904,7 +2900,6 @@ #ifdef NETIF_F_TSO 0); cmd_length = E1000_TXD_CMD_IP; ipcse = skb->h.raw - skb->data - 1; -#ifdef NETIF_F_TSO6 } else if (skb->protocol == htons(ETH_P_IPV6)) { skb->nh.ipv6h->payload_len = 0; skb->h.th->check = @@ -2914,7 +2909,6 @@ #ifdef NETIF_F_TSO6 IPPROTO_TCP, 0); ipcse = 0; -#endif } ipcss = skb->nh.raw - skb->data; ipcso = (void *)&(skb->nh.iph->check) - (void *)skb->data; @@ -2947,8 +2941,6 @@ #endif return TRUE; } -#endif - return FALSE; } @@ -2968,8 +2960,9 @@ e1000_tx_csum(struct e1000_adapter *adap buffer_info = &tx_ring->buffer_info[i]; context_desc = E1000_CONTEXT_DESC(*tx_ring, i); + context_desc->lower_setup.ip_config = 0; context_desc->upper_setup.tcp_fields.tucss = css; - context_desc->upper_setup.tcp_fields.tucso = css + skb->csum_offset; + context_desc->upper_setup.tcp_fields.tucso = css + skb->csum; context_desc->upper_setup.tcp_fields.tucse = 0; context_desc->tcp_seg_setup.data = 0; context_desc->cmd_and_length = cpu_to_le32(E1000_TXD_CMD_DEXT); @@ -3005,7 +2998,6 @@ e1000_tx_map(struct e1000_adapter *adapt while (len) { buffer_info = &tx_ring->buffer_info[i]; size = min(len, max_per_txd); -#ifdef NETIF_F_TSO /* Workaround for Controller erratum -- * descriptor for non-tso packet in a linear SKB that follows a * tso gets written back prematurely before the data is fully @@ -3020,7 +3012,6 @@ #ifdef NETIF_F_TSO * in TSO mode. Append 4-byte sentinel desc */ if (unlikely(mss && !nr_frags && size == len && size > 8)) size -= 4; -#endif /* work-around for errata 10 and it applies * to all controllers in PCI-X mode * The fix is to make sure that the first descriptor of a @@ -3062,12 +3053,10 @@ #endif while (len) { buffer_info = &tx_ring->buffer_info[i]; size = min(len, max_per_txd); -#ifdef NETIF_F_TSO /* Workaround for premature desc write-backs * in TSO mode. Append 4-byte sentinel desc */ if (unlikely(mss && f == (nr_frags-1) && size == len && size > 8)) size -= 4; -#endif /* Workaround for potential 82544 hang in PCI-X. * Avoid terminating buffers within evenly-aligned * dwords. */ @@ -3292,7 +3281,6 @@ e1000_xmit_frame(struct sk_buff *skb, st if (adapter->hw.mac_type >= e1000_82571) max_per_txd = 8192; -#ifdef NETIF_F_TSO mss = skb_shinfo(skb)->gso_size; /* The controller does a simple calculation to * make sure there is enough room in the FIFO before @@ -3346,16 +3334,10 @@ #ifdef NETIF_F_TSO if ((mss) || (skb->ip_summed == CHECKSUM_PARTIAL)) count++; count++; -#else - if (skb->ip_summed == CHECKSUM_PARTIAL) - count++; -#endif -#ifdef NETIF_F_TSO /* Controller Erratum workaround */ if (!skb->data_len && tx_ring->last_tx_tso && !skb_is_gso(skb)) count++; -#endif count += TXD_USE_COUNT(len, max_txd_pwr); @@ -3602,7 +3584,7 @@ #define PHY_IDLE_ERROR_COUNT_MASK 0x00FF */ if (adapter->link_speed == 0) return; - if (pdev->error_state && pdev->error_state != pci_channel_io_normal) + if (pci_channel_offline(pdev)) return; spin_lock_irqsave(&adapter->stats_lock, flags); @@ -3765,8 +3747,8 @@ #ifdef CONFIG_PCI_MSI * @data: pointer to a network interface device structure **/ -static -irqreturn_t e1000_intr_msi(int irq, void *data) +static irqreturn_t +e1000_intr_msi(int irq, void *data) { struct net_device *netdev = data; struct e1000_adapter *adapter = netdev_priv(netdev); @@ -3774,49 +3756,27 @@ irqreturn_t e1000_intr_msi(int irq, void #ifndef CONFIG_E1000_NAPI int i; #endif + uint32_t icr = E1000_READ_REG(hw, ICR); - /* this code avoids the read of ICR but has to get 1000 interrupts - * at every link change event before it will notice the change */ - if (++adapter->detect_link >= 1000) { - uint32_t icr = E1000_READ_REG(hw, ICR); #ifdef CONFIG_E1000_NAPI - /* read ICR disables interrupts using IAM, so keep up with our - * enable/disable accounting */ - atomic_inc(&adapter->irq_sem); + /* read ICR disables interrupts using IAM, so keep up with our + * enable/disable accounting */ + atomic_inc(&adapter->irq_sem); #endif - adapter->detect_link = 0; - if ((icr & (E1000_ICR_RXSEQ | E1000_ICR_LSC)) && - (icr & E1000_ICR_INT_ASSERTED)) { - hw->get_link_status = 1; - /* 80003ES2LAN workaround-- - * For packet buffer work-around on link down event; - * disable receives here in the ISR and - * reset adapter in watchdog - */ - if (netif_carrier_ok(netdev) && - (adapter->hw.mac_type == e1000_80003es2lan)) { - /* disable receives */ - uint32_t rctl = E1000_READ_REG(hw, RCTL); - E1000_WRITE_REG(hw, RCTL, rctl & ~E1000_RCTL_EN); - } - /* guard against interrupt when we're going down */ - if (!test_bit(__E1000_DOWN, &adapter->flags)) - mod_timer(&adapter->watchdog_timer, - jiffies + 1); + if (icr & (E1000_ICR_RXSEQ | E1000_ICR_LSC)) { + hw->get_link_status = 1; + /* 80003ES2LAN workaround-- For packet buffer work-around on + * link down event; disable receives here in the ISR and reset + * adapter in watchdog */ + if (netif_carrier_ok(netdev) && + (adapter->hw.mac_type == e1000_80003es2lan)) { + /* disable receives */ + uint32_t rctl = E1000_READ_REG(hw, RCTL); + E1000_WRITE_REG(hw, RCTL, rctl & ~E1000_RCTL_EN); } - } else { - E1000_WRITE_REG(hw, ICR, (0xffffffff & ~(E1000_ICR_RXSEQ | - E1000_ICR_LSC))); - /* bummer we have to flush here, but things break otherwise as - * some event appears to be lost or delayed and throughput - * drops. In almost all tests this flush is un-necessary */ - E1000_WRITE_FLUSH(hw); -#ifdef CONFIG_E1000_NAPI - /* Interrupt Auto-Mask (IAM)...upon writing ICR, interrupts are - * masked. No need for the IMC write, but it does mean we - * should account for it ASAP. */ - atomic_inc(&adapter->irq_sem); -#endif + /* guard against interrupt when we're going down */ + if (!test_bit(__E1000_DOWN, &adapter->flags)) + mod_timer(&adapter->watchdog_timer, jiffies + 1); } #ifdef CONFIG_E1000_NAPI @@ -3836,7 +3796,7 @@ #else for (i = 0; i < E1000_MAX_INTR; i++) if (unlikely(!adapter->clean_rx(adapter, adapter->rx_ring) & - !e1000_clean_tx_irq(adapter, adapter->tx_ring))) + e1000_clean_tx_irq(adapter, adapter->tx_ring))) break; if (likely(adapter->itr_setting & 3)) @@ -3939,7 +3899,7 @@ #else for (i = 0; i < E1000_MAX_INTR; i++) if (unlikely(!adapter->clean_rx(adapter, adapter->rx_ring) & - !e1000_clean_tx_irq(adapter, adapter->tx_ring))) + e1000_clean_tx_irq(adapter, adapter->tx_ring))) break; if (likely(adapter->itr_setting & 3)) @@ -3989,7 +3949,7 @@ e1000_clean(struct net_device *poll_dev, poll_dev->quota -= work_done; /* If no Tx and not enough Rx work done, exit the polling mode */ - if ((!tx_cleaned && (work_done == 0)) || + if ((tx_cleaned && (work_done < work_to_do)) || !netif_running(poll_dev)) { quit_polling: if (likely(adapter->itr_setting & 3)) @@ -4019,7 +3979,7 @@ e1000_clean_tx_irq(struct e1000_adapter #ifdef CONFIG_E1000_NAPI unsigned int count = 0; #endif - boolean_t cleaned = FALSE; + boolean_t cleaned = TRUE; unsigned int total_tx_bytes=0, total_tx_packets=0; i = tx_ring->next_to_clean; @@ -4034,10 +3994,13 @@ #endif if (cleaned) { struct sk_buff *skb = buffer_info->skb; - unsigned int segs = skb_shinfo(skb)->gso_segs; + unsigned int segs, bytecount; + segs = skb_shinfo(skb)->gso_segs ?: 1; + /* multiply data chunks by size of headers */ + bytecount = ((segs - 1) * skb_headlen(skb)) + + skb->len; total_tx_packets += segs; - total_tx_packets++; - total_tx_bytes += skb->len; + total_tx_bytes += bytecount; } e1000_unmap_and_free_tx_resource(adapter, buffer_info); tx_desc->upper.data = 0; @@ -4050,7 +4013,10 @@ #endif #ifdef CONFIG_E1000_NAPI #define E1000_TX_WEIGHT 64 /* weight of a sort for tx, to avoid endless transmit cleanup */ - if (count++ == E1000_TX_WEIGHT) break; + if (count++ == E1000_TX_WEIGHT) { + cleaned = FALSE; + break; + } #endif } diff --git a/drivers/net/e1000/e1000_osdep.h b/drivers/net/e1000/e1000_osdep.h index 18afc0c..10af742 100644 --- a/drivers/net/e1000/e1000_osdep.h +++ b/drivers/net/e1000/e1000_osdep.h @@ -48,8 +48,6 @@ #undef TRUE TRUE = 1 } boolean_t; -#define MSGOUT(S, A, B) printk(KERN_DEBUG S "\n", A, B) - #ifdef DBG #define DEBUGOUT(S) printk(KERN_DEBUG S "\n") #define DEBUGOUT1(S, A...) printk(KERN_DEBUG S "\n", A) @@ -58,7 +56,7 @@ #define DEBUGOUT(S) #define DEBUGOUT1(S, A...) #endif -#define DEBUGFUNC(F) DEBUGOUT(F) +#define DEBUGFUNC(F) DEBUGOUT(F "\n") #define DEBUGOUT2 DEBUGOUT1 #define DEBUGOUT3 DEBUGOUT2 #define DEBUGOUT7 DEBUGOUT3 diff --git a/drivers/net/e1000/e1000_param.c b/drivers/net/e1000/e1000_param.c index cf2a279..f8862e2 100644 --- a/drivers/net/e1000/e1000_param.c +++ b/drivers/net/e1000/e1000_param.c @@ -760,22 +760,13 @@ e1000_check_copper_options(struct e1000_ case SPEED_1000: DPRINTK(PROBE, INFO, "1000 Mbps Speed specified without " "Duplex\n"); - DPRINTK(PROBE, INFO, - "Using Autonegotiation at 1000 Mbps " - "Full Duplex only\n"); - adapter->hw.autoneg = adapter->fc_autoneg = 1; - adapter->hw.autoneg_advertised = ADVERTISE_1000_FULL; - break; + goto full_duplex_only; case SPEED_1000 + HALF_DUPLEX: DPRINTK(PROBE, INFO, "Half Duplex is not supported at 1000 Mbps\n"); - DPRINTK(PROBE, INFO, - "Using Autonegotiation at 1000 Mbps " - "Full Duplex only\n"); - adapter->hw.autoneg = adapter->fc_autoneg = 1; - adapter->hw.autoneg_advertised = ADVERTISE_1000_FULL; - break; + /* fall through */ case SPEED_1000 + FULL_DUPLEX: +full_duplex_only: DPRINTK(PROBE, INFO, "Using Autonegotiation at 1000 Mbps Full Duplex only\n"); adapter->hw.autoneg = adapter->fc_autoneg = 1; diff --git a/drivers/net/e2100.c b/drivers/net/e2100.c index c62d9c6..b2b0a96 100644 --- a/drivers/net/e2100.c +++ b/drivers/net/e2100.c @@ -355,8 +355,7 @@ e21_block_input(struct net_device *dev, mem_on(ioaddr, shared_mem, (ring_offset>>8)); - /* Packet is always in one chunk -- we can copy + cksum. */ - eth_io_copy_and_sum(skb, ei_status.mem + (ring_offset & 0xff), count, 0); + memcpy_fromio(skb->data, ei_status.mem + (ring_offset & 0xff), count); mem_off(ioaddr); } diff --git a/drivers/net/ehea/ehea_main.c b/drivers/net/ehea/ehea_main.c index 9de2d38..38b2fa4 100644 --- a/drivers/net/ehea/ehea_main.c +++ b/drivers/net/ehea/ehea_main.c @@ -882,7 +882,7 @@ static int ehea_reg_interrupts(struct ne , "%s-recv%d", dev->name, i); ret = ibmebus_request_irq(NULL, pr->recv_eq->attr.ist1, ehea_recv_irq_handler, - SA_INTERRUPT, pr->int_recv_name, pr); + IRQF_DISABLED, pr->int_recv_name, pr); if (ret) { ehea_error("failed registering irq for ehea_recv_int:" "port_res_nr:%d, ist=%X", i, @@ -899,7 +899,7 @@ static int ehea_reg_interrupts(struct ne ret = ibmebus_request_irq(NULL, port->qp_eq->attr.ist1, ehea_qp_aff_irq_handler, - SA_INTERRUPT, port->int_aff_name, port); + IRQF_DISABLED, port->int_aff_name, port); if (ret) { ehea_error("failed registering irq for qp_aff_irq_handler:" "ist=%X", port->qp_eq->attr.ist1); @@ -916,7 +916,7 @@ static int ehea_reg_interrupts(struct ne "%s-send%d", dev->name, i); ret = ibmebus_request_irq(NULL, pr->send_eq->attr.ist1, ehea_send_irq_handler, - SA_INTERRUPT, pr->int_send_name, + IRQF_DISABLED, pr->int_send_name, pr); if (ret) { ehea_error("failed registering irq for ehea_send " @@ -2539,7 +2539,7 @@ static int __devinit ehea_probe(struct i (unsigned long)adapter); ret = ibmebus_request_irq(NULL, adapter->neq->attr.ist1, - ehea_interrupt_neq, SA_INTERRUPT, + ehea_interrupt_neq, IRQF_DISABLED, "ehea_neq", adapter); if (ret) { dev_err(&dev->ofdev.dev, "requesting NEQ IRQ failed"); diff --git a/drivers/net/es3210.c b/drivers/net/es3210.c index 2d2ea94..822e5bf 100644 --- a/drivers/net/es3210.c +++ b/drivers/net/es3210.c @@ -375,7 +375,7 @@ static void es_block_input(struct net_de memcpy_fromio(skb->data + semi_count, ei_status.mem, count); } else { /* Packet is in one chunk. */ - eth_io_copy_and_sum(skb, xfer_start, count, 0); + memcpy_fromio(skb->data, xfer_start, count); } } diff --git a/drivers/net/fec_8xx/fec_8xx-netta.c b/drivers/net/fec_8xx/fec_8xx-netta.c index 790d9db..e492eb8 100644 --- a/drivers/net/fec_8xx/fec_8xx-netta.c +++ b/drivers/net/fec_8xx/fec_8xx-netta.c @@ -4,7 +4,6 @@ #include #include -#include #include #include #include diff --git a/drivers/net/fec_8xx/fec_main.c b/drivers/net/fec_8xx/fec_main.c index 8e7a56f..77f747a 100644 --- a/drivers/net/fec_8xx/fec_main.c +++ b/drivers/net/fec_8xx/fec_main.c @@ -13,7 +13,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/net/fec_8xx/fec_mii.c b/drivers/net/fec_8xx/fec_mii.c index d3c16b8..e79700a 100644 --- a/drivers/net/fec_8xx/fec_mii.c +++ b/drivers/net/fec_8xx/fec_mii.c @@ -13,7 +13,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/net/forcedeth.c b/drivers/net/forcedeth.c index 93f2b7a..a363148 100644 --- a/drivers/net/forcedeth.c +++ b/drivers/net/forcedeth.c @@ -111,6 +111,7 @@ * 0.57: 14 May 2006: Mac address set in probe/remove and order corrections. * 0.58: 30 Oct 2006: Added support for sideband management unit. * 0.59: 30 Oct 2006: Added support for recoverable error. + * 0.60: 20 Jan 2007: Code optimizations for rings, rx & tx data paths, and stats. * * Known bugs: * We suspect that on some hardware no TX done interrupts are generated. @@ -127,7 +128,7 @@ #define DRIVERNAPI "-NAPI" #else #define DRIVERNAPI #endif -#define FORCEDETH_VERSION "0.59" +#define FORCEDETH_VERSION "0.60" #define DRV_NAME "forcedeth" #include @@ -173,9 +174,10 @@ #define DEV_HAS_MSI 0x0040 #define DEV_HAS_MSI_X 0x0080 /* device supports MSI-X */ #define DEV_HAS_POWER_CNTRL 0x0100 /* device supports power savings */ #define DEV_HAS_PAUSEFRAME_TX 0x0200 /* device supports tx pause frames */ -#define DEV_HAS_STATISTICS 0x0400 /* device supports hw statistics */ -#define DEV_HAS_TEST_EXTENDED 0x0800 /* device supports extended diagnostic test */ -#define DEV_HAS_MGMT_UNIT 0x1000 /* device supports management unit */ +#define DEV_HAS_STATISTICS_V1 0x0400 /* device supports hw statistics version 1 */ +#define DEV_HAS_STATISTICS_V2 0x0800 /* device supports hw statistics version 2 */ +#define DEV_HAS_TEST_EXTENDED 0x1000 /* device supports extended diagnostic test */ +#define DEV_HAS_MGMT_UNIT 0x2000 /* device supports management unit */ enum { NvRegIrqStatus = 0x000, @@ -210,7 +212,7 @@ #define NVREG_UNKSETUP6_VAL 3 * NVREG_POLL_DEFAULT=97 would result in an interval length of 1 ms */ NvRegPollingInterval = 0x00c, -#define NVREG_POLL_DEFAULT_THROUGHPUT 970 +#define NVREG_POLL_DEFAULT_THROUGHPUT 970 /* backup tx cleanup if loop max reached */ #define NVREG_POLL_DEFAULT_CPU 13 NvRegMSIMap0 = 0x020, NvRegMSIMap1 = 0x024, @@ -304,8 +306,8 @@ #define NVREG_TXRXCTL_IDLE 0x0008 #define NVREG_TXRXCTL_RESET 0x0010 #define NVREG_TXRXCTL_RXCHECK 0x0400 #define NVREG_TXRXCTL_DESC_1 0 -#define NVREG_TXRXCTL_DESC_2 0x02100 -#define NVREG_TXRXCTL_DESC_3 0x02200 +#define NVREG_TXRXCTL_DESC_2 0x002100 +#define NVREG_TXRXCTL_DESC_3 0xc02200 #define NVREG_TXRXCTL_VLANSTRIP 0x00040 #define NVREG_TXRXCTL_VLANINS 0x00080 NvRegTxRingPhysAddrHigh = 0x148, @@ -487,7 +489,8 @@ #define NV_RX3_VLAN_TAG_MASK (0x0000FFFF /* Miscelaneous hardware related defines: */ #define NV_PCI_REGSZ_VER1 0x270 -#define NV_PCI_REGSZ_VER2 0x604 +#define NV_PCI_REGSZ_VER2 0x2d4 +#define NV_PCI_REGSZ_VER3 0x604 /* various timeout delays: all in usec */ #define NV_TXRX_RESET_DELAY 4 @@ -518,12 +521,6 @@ #define RX_RING_MIN 128 #define TX_RING_MIN 64 #define RING_MAX_DESC_VER_1 1024 #define RING_MAX_DESC_VER_2_3 16384 -/* - * Difference between the get and put pointers for the tx ring. - * This is used to throttle the amount of data outstanding in the - * tx ring. - */ -#define TX_LIMIT_DIFFERENCE 1 /* rx/tx mac addr + type + vlan + align + slack*/ #define NV_RX_HEADERS (64) @@ -611,9 +608,6 @@ static const struct nv_ethtool_str nv_es { "tx_carrier_errors" }, { "tx_excess_deferral" }, { "tx_retry_error" }, - { "tx_deferral" }, - { "tx_packets" }, - { "tx_pause" }, { "rx_frame_error" }, { "rx_extra_byte" }, { "rx_late_collision" }, @@ -626,11 +620,17 @@ static const struct nv_ethtool_str nv_es { "rx_unicast" }, { "rx_multicast" }, { "rx_broadcast" }, + { "rx_packets" }, + { "rx_errors_total" }, + { "tx_errors_total" }, + + /* version 2 stats */ + { "tx_deferral" }, + { "tx_packets" }, { "rx_bytes" }, + { "tx_pause" }, { "rx_pause" }, - { "rx_drop_frame" }, - { "rx_packets" }, - { "rx_errors_total" } + { "rx_drop_frame" } }; struct nv_ethtool_stats { @@ -643,9 +643,6 @@ struct nv_ethtool_stats { u64 tx_carrier_errors; u64 tx_excess_deferral; u64 tx_retry_error; - u64 tx_deferral; - u64 tx_packets; - u64 tx_pause; u64 rx_frame_error; u64 rx_extra_byte; u64 rx_late_collision; @@ -658,13 +655,22 @@ struct nv_ethtool_stats { u64 rx_unicast; u64 rx_multicast; u64 rx_broadcast; + u64 rx_packets; + u64 rx_errors_total; + u64 tx_errors_total; + + /* version 2 stats */ + u64 tx_deferral; + u64 tx_packets; u64 rx_bytes; + u64 tx_pause; u64 rx_pause; u64 rx_drop_frame; - u64 rx_packets; - u64 rx_errors_total; }; +#define NV_DEV_STATISTICS_V2_COUNT (sizeof(struct nv_ethtool_stats)/sizeof(u64)) +#define NV_DEV_STATISTICS_V1_COUNT (NV_DEV_STATISTICS_V2_COUNT - 6) + /* diagnostics */ #define NV_TEST_COUNT_BASE 3 #define NV_TEST_COUNT_EXTENDED 4 @@ -691,6 +697,12 @@ static const struct register_test nv_reg { 0,0 } }; +struct nv_skb_map { + struct sk_buff *skb; + dma_addr_t dma; + unsigned int dma_len; +}; + /* * SMP locking: * All hardware access under dev->priv->lock, except the performance @@ -741,10 +753,12 @@ struct fe_priv { /* rx specific fields. * Locking: Within irq hander or disable_irq+spin_lock(&np->lock); */ + union ring_type get_rx, put_rx, first_rx, last_rx; + struct nv_skb_map *get_rx_ctx, *put_rx_ctx; + struct nv_skb_map *first_rx_ctx, *last_rx_ctx; + struct nv_skb_map *rx_skb; + union ring_type rx_ring; - unsigned int cur_rx, refill_rx; - struct sk_buff **rx_skbuff; - dma_addr_t *rx_dma; unsigned int rx_buf_sz; unsigned int pkt_limit; struct timer_list oom_kick; @@ -761,15 +775,15 @@ struct fe_priv { /* * tx specific fields. */ + union ring_type get_tx, put_tx, first_tx, last_tx; + struct nv_skb_map *get_tx_ctx, *put_tx_ctx; + struct nv_skb_map *first_tx_ctx, *last_tx_ctx; + struct nv_skb_map *tx_skb; + union ring_type tx_ring; - unsigned int next_tx, nic_tx; - struct sk_buff **tx_skbuff; - dma_addr_t *tx_dma; - unsigned int *tx_dma_len; u32 tx_flags; int tx_ring_size; - int tx_limit_start; - int tx_limit_stop; + int tx_stop; /* vlan fields */ struct vlan_group *vlangrp; @@ -921,16 +935,10 @@ static void free_rings(struct net_device pci_free_consistent(np->pci_dev, sizeof(struct ring_desc_ex) * (np->rx_ring_size + np->tx_ring_size), np->rx_ring.ex, np->ring_addr); } - if (np->rx_skbuff) - kfree(np->rx_skbuff); - if (np->rx_dma) - kfree(np->rx_dma); - if (np->tx_skbuff) - kfree(np->tx_skbuff); - if (np->tx_dma) - kfree(np->tx_dma); - if (np->tx_dma_len) - kfree(np->tx_dma_len); + if (np->rx_skb) + kfree(np->rx_skb); + if (np->tx_skb) + kfree(np->tx_skb); } static int using_multi_irqs(struct net_device *dev) @@ -1279,6 +1287,61 @@ static void nv_mac_reset(struct net_devi pci_push(base); } +static void nv_get_hw_stats(struct net_device *dev) +{ + struct fe_priv *np = netdev_priv(dev); + u8 __iomem *base = get_hwbase(dev); + + np->estats.tx_bytes += readl(base + NvRegTxCnt); + np->estats.tx_zero_rexmt += readl(base + NvRegTxZeroReXmt); + np->estats.tx_one_rexmt += readl(base + NvRegTxOneReXmt); + np->estats.tx_many_rexmt += readl(base + NvRegTxManyReXmt); + np->estats.tx_late_collision += readl(base + NvRegTxLateCol); + np->estats.tx_fifo_errors += readl(base + NvRegTxUnderflow); + np->estats.tx_carrier_errors += readl(base + NvRegTxLossCarrier); + np->estats.tx_excess_deferral += readl(base + NvRegTxExcessDef); + np->estats.tx_retry_error += readl(base + NvRegTxRetryErr); + np->estats.rx_frame_error += readl(base + NvRegRxFrameErr); + np->estats.rx_extra_byte += readl(base + NvRegRxExtraByte); + np->estats.rx_late_collision += readl(base + NvRegRxLateCol); + np->estats.rx_runt += readl(base + NvRegRxRunt); + np->estats.rx_frame_too_long += readl(base + NvRegRxFrameTooLong); + np->estats.rx_over_errors += readl(base + NvRegRxOverflow); + np->estats.rx_crc_errors += readl(base + NvRegRxFCSErr); + np->estats.rx_frame_align_error += readl(base + NvRegRxFrameAlignErr); + np->estats.rx_length_error += readl(base + NvRegRxLenErr); + np->estats.rx_unicast += readl(base + NvRegRxUnicast); + np->estats.rx_multicast += readl(base + NvRegRxMulticast); + np->estats.rx_broadcast += readl(base + NvRegRxBroadcast); + np->estats.rx_packets = + np->estats.rx_unicast + + np->estats.rx_multicast + + np->estats.rx_broadcast; + np->estats.rx_errors_total = + np->estats.rx_crc_errors + + np->estats.rx_over_errors + + np->estats.rx_frame_error + + (np->estats.rx_frame_align_error - np->estats.rx_extra_byte) + + np->estats.rx_late_collision + + np->estats.rx_runt + + np->estats.rx_frame_too_long; + np->estats.tx_errors_total = + np->estats.tx_late_collision + + np->estats.tx_fifo_errors + + np->estats.tx_carrier_errors + + np->estats.tx_excess_deferral + + np->estats.tx_retry_error; + + if (np->driver_data & DEV_HAS_STATISTICS_V2) { + np->estats.tx_deferral += readl(base + NvRegTxDef); + np->estats.tx_packets += readl(base + NvRegTxFrame); + np->estats.rx_bytes += readl(base + NvRegRxCnt); + np->estats.tx_pause += readl(base + NvRegTxPause); + np->estats.rx_pause += readl(base + NvRegRxPause); + np->estats.rx_drop_frame += readl(base + NvRegRxDropFrame); + } +} + /* * nv_get_stats: dev->get_stats function * Get latest stats value from the nic. @@ -1289,10 +1352,19 @@ static struct net_device_stats *nv_get_s { struct fe_priv *np = netdev_priv(dev); - /* It seems that the nic always generates interrupts and doesn't - * accumulate errors internally. Thus the current values in np->stats - * are already up to date. - */ + /* If the nic supports hw counters then retrieve latest values */ + if (np->driver_data & (DEV_HAS_STATISTICS_V1|DEV_HAS_STATISTICS_V2)) { + nv_get_hw_stats(dev); + + /* copy to net_device stats */ + np->stats.tx_bytes = np->estats.tx_bytes; + np->stats.tx_fifo_errors = np->estats.tx_fifo_errors; + np->stats.tx_carrier_errors = np->estats.tx_carrier_errors; + np->stats.rx_crc_errors = np->estats.rx_crc_errors; + np->stats.rx_over_errors = np->estats.rx_over_errors; + np->stats.rx_errors = np->estats.rx_errors_total; + np->stats.tx_errors = np->estats.tx_errors_total; + } return &np->stats; } @@ -1304,43 +1376,63 @@ static struct net_device_stats *nv_get_s static int nv_alloc_rx(struct net_device *dev) { struct fe_priv *np = netdev_priv(dev); - unsigned int refill_rx = np->refill_rx; - int nr; + struct ring_desc* less_rx; - while (np->cur_rx != refill_rx) { - struct sk_buff *skb; - - nr = refill_rx % np->rx_ring_size; - if (np->rx_skbuff[nr] == NULL) { - - skb = dev_alloc_skb(np->rx_buf_sz + NV_RX_ALLOC_PAD); - if (!skb) - break; + less_rx = np->get_rx.orig; + if (less_rx-- == np->first_rx.orig) + less_rx = np->last_rx.orig; + while (np->put_rx.orig != less_rx) { + struct sk_buff *skb = dev_alloc_skb(np->rx_buf_sz + NV_RX_ALLOC_PAD); + if (skb) { skb->dev = dev; - np->rx_skbuff[nr] = skb; + np->put_rx_ctx->skb = skb; + np->put_rx_ctx->dma = pci_map_single(np->pci_dev, skb->data, + skb->end-skb->data, PCI_DMA_FROMDEVICE); + np->put_rx_ctx->dma_len = skb->end-skb->data; + np->put_rx.orig->buf = cpu_to_le32(np->put_rx_ctx->dma); + wmb(); + np->put_rx.orig->flaglen = cpu_to_le32(np->rx_buf_sz | NV_RX_AVAIL); + if (unlikely(np->put_rx.orig++ == np->last_rx.orig)) + np->put_rx.orig = np->first_rx.orig; + if (unlikely(np->put_rx_ctx++ == np->last_rx_ctx)) + np->put_rx_ctx = np->first_rx_ctx; } else { - skb = np->rx_skbuff[nr]; + return 1; } - np->rx_dma[nr] = pci_map_single(np->pci_dev, skb->data, - skb->end-skb->data, PCI_DMA_FROMDEVICE); - if (np->desc_ver == DESC_VER_1 || np->desc_ver == DESC_VER_2) { - np->rx_ring.orig[nr].buf = cpu_to_le32(np->rx_dma[nr]); + } + return 0; +} + +static int nv_alloc_rx_optimized(struct net_device *dev) +{ + struct fe_priv *np = netdev_priv(dev); + struct ring_desc_ex* less_rx; + + less_rx = np->get_rx.ex; + if (less_rx-- == np->first_rx.ex) + less_rx = np->last_rx.ex; + + while (np->put_rx.ex != less_rx) { + struct sk_buff *skb = dev_alloc_skb(np->rx_buf_sz + NV_RX_ALLOC_PAD); + if (skb) { + skb->dev = dev; + np->put_rx_ctx->skb = skb; + np->put_rx_ctx->dma = pci_map_single(np->pci_dev, skb->data, + skb->end-skb->data, PCI_DMA_FROMDEVICE); + np->put_rx_ctx->dma_len = skb->end-skb->data; + np->put_rx.ex->bufhigh = cpu_to_le64(np->put_rx_ctx->dma) >> 32; + np->put_rx.ex->buflow = cpu_to_le64(np->put_rx_ctx->dma) & 0x0FFFFFFFF; wmb(); - np->rx_ring.orig[nr].flaglen = cpu_to_le32(np->rx_buf_sz | NV_RX_AVAIL); + np->put_rx.ex->flaglen = cpu_to_le32(np->rx_buf_sz | NV_RX2_AVAIL); + if (unlikely(np->put_rx.ex++ == np->last_rx.ex)) + np->put_rx.ex = np->first_rx.ex; + if (unlikely(np->put_rx_ctx++ == np->last_rx_ctx)) + np->put_rx_ctx = np->first_rx_ctx; } else { - np->rx_ring.ex[nr].bufhigh = cpu_to_le64(np->rx_dma[nr]) >> 32; - np->rx_ring.ex[nr].buflow = cpu_to_le64(np->rx_dma[nr]) & 0x0FFFFFFFF; - wmb(); - np->rx_ring.ex[nr].flaglen = cpu_to_le32(np->rx_buf_sz | NV_RX2_AVAIL); + return 1; } - dprintk(KERN_DEBUG "%s: nv_alloc_rx: Packet %d marked as Available\n", - dev->name, refill_rx); - refill_rx++; } - np->refill_rx = refill_rx; - if (np->cur_rx - refill_rx == np->rx_ring_size) - return 1; return 0; } @@ -1358,6 +1450,7 @@ static void nv_do_rx_refill(unsigned lon { struct net_device *dev = (struct net_device *) data; struct fe_priv *np = netdev_priv(dev); + int retcode; if (!using_multi_irqs(dev)) { if (np->msi_flags & NV_MSI_X_ENABLED) @@ -1367,7 +1460,11 @@ static void nv_do_rx_refill(unsigned lon } else { disable_irq(np->msi_x_entry[NV_MSI_X_VECTOR_RX].vector); } - if (nv_alloc_rx(dev)) { + if (np->desc_ver == DESC_VER_1 || np->desc_ver == DESC_VER_2) + retcode = nv_alloc_rx(dev); + else + retcode = nv_alloc_rx_optimized(dev); + if (retcode) { spin_lock_irq(&np->lock); if (!np->in_shutdown) mod_timer(&np->oom_kick, jiffies + OOM_REFILL); @@ -1388,56 +1485,81 @@ static void nv_init_rx(struct net_device { struct fe_priv *np = netdev_priv(dev); int i; + np->get_rx = np->put_rx = np->first_rx = np->rx_ring; + if (np->desc_ver == DESC_VER_1 || np->desc_ver == DESC_VER_2) + np->last_rx.orig = &np->rx_ring.orig[np->rx_ring_size-1]; + else + np->last_rx.ex = &np->rx_ring.ex[np->rx_ring_size-1]; + np->get_rx_ctx = np->put_rx_ctx = np->first_rx_ctx = np->rx_skb; + np->last_rx_ctx = &np->rx_skb[np->rx_ring_size-1]; - np->cur_rx = np->rx_ring_size; - np->refill_rx = 0; - for (i = 0; i < np->rx_ring_size; i++) - if (np->desc_ver == DESC_VER_1 || np->desc_ver == DESC_VER_2) + for (i = 0; i < np->rx_ring_size; i++) { + if (np->desc_ver == DESC_VER_1 || np->desc_ver == DESC_VER_2) { np->rx_ring.orig[i].flaglen = 0; - else + np->rx_ring.orig[i].buf = 0; + } else { np->rx_ring.ex[i].flaglen = 0; + np->rx_ring.ex[i].txvlan = 0; + np->rx_ring.ex[i].bufhigh = 0; + np->rx_ring.ex[i].buflow = 0; + } + np->rx_skb[i].skb = NULL; + np->rx_skb[i].dma = 0; + } } static void nv_init_tx(struct net_device *dev) { struct fe_priv *np = netdev_priv(dev); int i; + np->get_tx = np->put_tx = np->first_tx = np->tx_ring; + if (np->desc_ver == DESC_VER_1 || np->desc_ver == DESC_VER_2) + np->last_tx.orig = &np->tx_ring.orig[np->tx_ring_size-1]; + else + np->last_tx.ex = &np->tx_ring.ex[np->tx_ring_size-1]; + np->get_tx_ctx = np->put_tx_ctx = np->first_tx_ctx = np->tx_skb; + np->last_tx_ctx = &np->tx_skb[np->tx_ring_size-1]; - np->next_tx = np->nic_tx = 0; for (i = 0; i < np->tx_ring_size; i++) { - if (np->desc_ver == DESC_VER_1 || np->desc_ver == DESC_VER_2) + if (np->desc_ver == DESC_VER_1 || np->desc_ver == DESC_VER_2) { np->tx_ring.orig[i].flaglen = 0; - else + np->tx_ring.orig[i].buf = 0; + } else { np->tx_ring.ex[i].flaglen = 0; - np->tx_skbuff[i] = NULL; - np->tx_dma[i] = 0; + np->tx_ring.ex[i].txvlan = 0; + np->tx_ring.ex[i].bufhigh = 0; + np->tx_ring.ex[i].buflow = 0; + } + np->tx_skb[i].skb = NULL; + np->tx_skb[i].dma = 0; } } static int nv_init_ring(struct net_device *dev) { + struct fe_priv *np = netdev_priv(dev); + nv_init_tx(dev); nv_init_rx(dev); - return nv_alloc_rx(dev); + if (np->desc_ver == DESC_VER_1 || np->desc_ver == DESC_VER_2) + return nv_alloc_rx(dev); + else + return nv_alloc_rx_optimized(dev); } -static int nv_release_txskb(struct net_device *dev, unsigned int skbnr) +static int nv_release_txskb(struct net_device *dev, struct nv_skb_map* tx_skb) { struct fe_priv *np = netdev_priv(dev); - dprintk(KERN_INFO "%s: nv_release_txskb for skbnr %d\n", - dev->name, skbnr); - - if (np->tx_dma[skbnr]) { - pci_unmap_page(np->pci_dev, np->tx_dma[skbnr], - np->tx_dma_len[skbnr], + if (tx_skb->dma) { + pci_unmap_page(np->pci_dev, tx_skb->dma, + tx_skb->dma_len, PCI_DMA_TODEVICE); - np->tx_dma[skbnr] = 0; + tx_skb->dma = 0; } - - if (np->tx_skbuff[skbnr]) { - dev_kfree_skb_any(np->tx_skbuff[skbnr]); - np->tx_skbuff[skbnr] = NULL; + if (tx_skb->skb) { + dev_kfree_skb_any(tx_skb->skb); + tx_skb->skb = NULL; return 1; } else { return 0; @@ -1450,11 +1572,16 @@ static void nv_drain_tx(struct net_devic unsigned int i; for (i = 0; i < np->tx_ring_size; i++) { - if (np->desc_ver == DESC_VER_1 || np->desc_ver == DESC_VER_2) + if (np->desc_ver == DESC_VER_1 || np->desc_ver == DESC_VER_2) { np->tx_ring.orig[i].flaglen = 0; - else + np->tx_ring.orig[i].buf = 0; + } else { np->tx_ring.ex[i].flaglen = 0; - if (nv_release_txskb(dev, i)) + np->tx_ring.ex[i].txvlan = 0; + np->tx_ring.ex[i].bufhigh = 0; + np->tx_ring.ex[i].buflow = 0; + } + if (nv_release_txskb(dev, &np->tx_skb[i])) np->stats.tx_dropped++; } } @@ -1463,18 +1590,24 @@ static void nv_drain_rx(struct net_devic { struct fe_priv *np = netdev_priv(dev); int i; + for (i = 0; i < np->rx_ring_size; i++) { - if (np->desc_ver == DESC_VER_1 || np->desc_ver == DESC_VER_2) + if (np->desc_ver == DESC_VER_1 || np->desc_ver == DESC_VER_2) { np->rx_ring.orig[i].flaglen = 0; - else + np->rx_ring.orig[i].buf = 0; + } else { np->rx_ring.ex[i].flaglen = 0; + np->rx_ring.ex[i].txvlan = 0; + np->rx_ring.ex[i].bufhigh = 0; + np->rx_ring.ex[i].buflow = 0; + } wmb(); - if (np->rx_skbuff[i]) { - pci_unmap_single(np->pci_dev, np->rx_dma[i], - np->rx_skbuff[i]->end-np->rx_skbuff[i]->data, + if (np->rx_skb[i].skb) { + pci_unmap_single(np->pci_dev, np->rx_skb[i].dma, + np->rx_skb[i].skb->end-np->rx_skb[i].skb->data, PCI_DMA_FROMDEVICE); - dev_kfree_skb(np->rx_skbuff[i]); - np->rx_skbuff[i] = NULL; + dev_kfree_skb(np->rx_skb[i].skb); + np->rx_skb[i].skb = NULL; } } } @@ -1485,6 +1618,11 @@ static void drain_ring(struct net_device nv_drain_rx(dev); } +static inline u32 nv_get_empty_tx_slots(struct fe_priv *np) +{ + return (u32)(np->tx_ring_size - ((np->tx_ring_size + (np->put_tx_ctx - np->get_tx_ctx)) % np->tx_ring_size)); +} + /* * nv_start_xmit: dev->hard_start_xmit function * Called with netif_tx_lock held. @@ -1495,14 +1633,16 @@ static int nv_start_xmit(struct sk_buff u32 tx_flags = 0; u32 tx_flags_extra = (np->desc_ver == DESC_VER_1 ? NV_TX_LASTPACKET : NV_TX2_LASTPACKET); unsigned int fragments = skb_shinfo(skb)->nr_frags; - unsigned int nr = (np->next_tx - 1) % np->tx_ring_size; - unsigned int start_nr = np->next_tx % np->tx_ring_size; unsigned int i; u32 offset = 0; u32 bcnt; u32 size = skb->len-skb->data_len; u32 entries = (size >> NV_TX2_TSO_MAX_SHIFT) + ((size & (NV_TX2_TSO_MAX_SIZE-1)) ? 1 : 0); - u32 tx_flags_vlan = 0; + u32 empty_slots; + struct ring_desc* put_tx; + struct ring_desc* start_tx; + struct ring_desc* prev_tx; + struct nv_skb_map* prev_tx_ctx; /* add fragments to entries count */ for (i = 0; i < fragments; i++) { @@ -1510,34 +1650,35 @@ static int nv_start_xmit(struct sk_buff ((skb_shinfo(skb)->frags[i].size & (NV_TX2_TSO_MAX_SIZE-1)) ? 1 : 0); } - spin_lock_irq(&np->lock); - - if ((np->next_tx - np->nic_tx + entries - 1) > np->tx_limit_stop) { - spin_unlock_irq(&np->lock); + empty_slots = nv_get_empty_tx_slots(np); + if (unlikely(empty_slots <= entries)) { + spin_lock_irq(&np->lock); netif_stop_queue(dev); + np->tx_stop = 1; + spin_unlock_irq(&np->lock); return NETDEV_TX_BUSY; } + start_tx = put_tx = np->put_tx.orig; + /* setup the header buffer */ do { + prev_tx = put_tx; + prev_tx_ctx = np->put_tx_ctx; bcnt = (size > NV_TX2_TSO_MAX_SIZE) ? NV_TX2_TSO_MAX_SIZE : size; - nr = (nr + 1) % np->tx_ring_size; - - np->tx_dma[nr] = pci_map_single(np->pci_dev, skb->data + offset, bcnt, + np->put_tx_ctx->dma = pci_map_single(np->pci_dev, skb->data + offset, bcnt, PCI_DMA_TODEVICE); - np->tx_dma_len[nr] = bcnt; + np->put_tx_ctx->dma_len = bcnt; + put_tx->buf = cpu_to_le32(np->put_tx_ctx->dma); + put_tx->flaglen = cpu_to_le32((bcnt-1) | tx_flags); - if (np->desc_ver == DESC_VER_1 || np->desc_ver == DESC_VER_2) { - np->tx_ring.orig[nr].buf = cpu_to_le32(np->tx_dma[nr]); - np->tx_ring.orig[nr].flaglen = cpu_to_le32((bcnt-1) | tx_flags); - } else { - np->tx_ring.ex[nr].bufhigh = cpu_to_le64(np->tx_dma[nr]) >> 32; - np->tx_ring.ex[nr].buflow = cpu_to_le64(np->tx_dma[nr]) & 0x0FFFFFFFF; - np->tx_ring.ex[nr].flaglen = cpu_to_le32((bcnt-1) | tx_flags); - } tx_flags = np->tx_flags; offset += bcnt; size -= bcnt; + if (unlikely(put_tx++ == np->last_tx.orig)) + put_tx = np->first_tx.orig; + if (unlikely(np->put_tx_ctx++ == np->last_tx_ctx)) + np->put_tx_ctx = np->first_tx_ctx; } while (size); /* setup the fragments */ @@ -1547,58 +1688,174 @@ static int nv_start_xmit(struct sk_buff offset = 0; do { + prev_tx = put_tx; + prev_tx_ctx = np->put_tx_ctx; bcnt = (size > NV_TX2_TSO_MAX_SIZE) ? NV_TX2_TSO_MAX_SIZE : size; - nr = (nr + 1) % np->tx_ring_size; - - np->tx_dma[nr] = pci_map_page(np->pci_dev, frag->page, frag->page_offset+offset, bcnt, - PCI_DMA_TODEVICE); - np->tx_dma_len[nr] = bcnt; + np->put_tx_ctx->dma = pci_map_page(np->pci_dev, frag->page, frag->page_offset+offset, bcnt, + PCI_DMA_TODEVICE); + np->put_tx_ctx->dma_len = bcnt; + put_tx->buf = cpu_to_le32(np->put_tx_ctx->dma); + put_tx->flaglen = cpu_to_le32((bcnt-1) | tx_flags); - if (np->desc_ver == DESC_VER_1 || np->desc_ver == DESC_VER_2) { - np->tx_ring.orig[nr].buf = cpu_to_le32(np->tx_dma[nr]); - np->tx_ring.orig[nr].flaglen = cpu_to_le32((bcnt-1) | tx_flags); - } else { - np->tx_ring.ex[nr].bufhigh = cpu_to_le64(np->tx_dma[nr]) >> 32; - np->tx_ring.ex[nr].buflow = cpu_to_le64(np->tx_dma[nr]) & 0x0FFFFFFFF; - np->tx_ring.ex[nr].flaglen = cpu_to_le32((bcnt-1) | tx_flags); - } offset += bcnt; size -= bcnt; + if (unlikely(put_tx++ == np->last_tx.orig)) + put_tx = np->first_tx.orig; + if (unlikely(np->put_tx_ctx++ == np->last_tx_ctx)) + np->put_tx_ctx = np->first_tx_ctx; } while (size); } /* set last fragment flag */ - if (np->desc_ver == DESC_VER_1 || np->desc_ver == DESC_VER_2) { - np->tx_ring.orig[nr].flaglen |= cpu_to_le32(tx_flags_extra); - } else { - np->tx_ring.ex[nr].flaglen |= cpu_to_le32(tx_flags_extra); + prev_tx->flaglen |= cpu_to_le32(tx_flags_extra); + + /* save skb in this slot's context area */ + prev_tx_ctx->skb = skb; + + if (skb_is_gso(skb)) + tx_flags_extra = NV_TX2_TSO | (skb_shinfo(skb)->gso_size << NV_TX2_TSO_SHIFT); + else + tx_flags_extra = skb->ip_summed == CHECKSUM_PARTIAL ? + NV_TX2_CHECKSUM_L3 | NV_TX2_CHECKSUM_L4 : 0; + + spin_lock_irq(&np->lock); + + /* set tx flags */ + start_tx->flaglen |= cpu_to_le32(tx_flags | tx_flags_extra); + np->put_tx.orig = put_tx; + + spin_unlock_irq(&np->lock); + + dprintk(KERN_DEBUG "%s: nv_start_xmit: entries %d queued for transmission. tx_flags_extra: %x\n", + dev->name, entries, tx_flags_extra); + { + int j; + for (j=0; j<64; j++) { + if ((j%16) == 0) + dprintk("\n%03x:", j); + dprintk(" %02x", ((unsigned char*)skb->data)[j]); + } + dprintk("\n"); + } + + dev->trans_start = jiffies; + writel(NVREG_TXRXCTL_KICK|np->txrxctl_bits, get_hwbase(dev) + NvRegTxRxControl); + return NETDEV_TX_OK; +} + +static int nv_start_xmit_optimized(struct sk_buff *skb, struct net_device *dev) +{ + struct fe_priv *np = netdev_priv(dev); + u32 tx_flags = 0; + u32 tx_flags_extra; + unsigned int fragments = skb_shinfo(skb)->nr_frags; + unsigned int i; + u32 offset = 0; + u32 bcnt; + u32 size = skb->len-skb->data_len; + u32 entries = (size >> NV_TX2_TSO_MAX_SHIFT) + ((size & (NV_TX2_TSO_MAX_SIZE-1)) ? 1 : 0); + u32 empty_slots; + struct ring_desc_ex* put_tx; + struct ring_desc_ex* start_tx; + struct ring_desc_ex* prev_tx; + struct nv_skb_map* prev_tx_ctx; + + /* add fragments to entries count */ + for (i = 0; i < fragments; i++) { + entries += (skb_shinfo(skb)->frags[i].size >> NV_TX2_TSO_MAX_SHIFT) + + ((skb_shinfo(skb)->frags[i].size & (NV_TX2_TSO_MAX_SIZE-1)) ? 1 : 0); + } + + empty_slots = nv_get_empty_tx_slots(np); + if (unlikely(empty_slots <= entries)) { + spin_lock_irq(&np->lock); + netif_stop_queue(dev); + np->tx_stop = 1; + spin_unlock_irq(&np->lock); + return NETDEV_TX_BUSY; + } + + start_tx = put_tx = np->put_tx.ex; + + /* setup the header buffer */ + do { + prev_tx = put_tx; + prev_tx_ctx = np->put_tx_ctx; + bcnt = (size > NV_TX2_TSO_MAX_SIZE) ? NV_TX2_TSO_MAX_SIZE : size; + np->put_tx_ctx->dma = pci_map_single(np->pci_dev, skb->data + offset, bcnt, + PCI_DMA_TODEVICE); + np->put_tx_ctx->dma_len = bcnt; + put_tx->bufhigh = cpu_to_le64(np->put_tx_ctx->dma) >> 32; + put_tx->buflow = cpu_to_le64(np->put_tx_ctx->dma) & 0x0FFFFFFFF; + put_tx->flaglen = cpu_to_le32((bcnt-1) | tx_flags); + + tx_flags = NV_TX2_VALID; + offset += bcnt; + size -= bcnt; + if (unlikely(put_tx++ == np->last_tx.ex)) + put_tx = np->first_tx.ex; + if (unlikely(np->put_tx_ctx++ == np->last_tx_ctx)) + np->put_tx_ctx = np->first_tx_ctx; + } while (size); + + /* setup the fragments */ + for (i = 0; i < fragments; i++) { + skb_frag_t *frag = &skb_shinfo(skb)->frags[i]; + u32 size = frag->size; + offset = 0; + + do { + prev_tx = put_tx; + prev_tx_ctx = np->put_tx_ctx; + bcnt = (size > NV_TX2_TSO_MAX_SIZE) ? NV_TX2_TSO_MAX_SIZE : size; + np->put_tx_ctx->dma = pci_map_page(np->pci_dev, frag->page, frag->page_offset+offset, bcnt, + PCI_DMA_TODEVICE); + np->put_tx_ctx->dma_len = bcnt; + put_tx->bufhigh = cpu_to_le64(np->put_tx_ctx->dma) >> 32; + put_tx->buflow = cpu_to_le64(np->put_tx_ctx->dma) & 0x0FFFFFFFF; + put_tx->flaglen = cpu_to_le32((bcnt-1) | tx_flags); + + offset += bcnt; + size -= bcnt; + if (unlikely(put_tx++ == np->last_tx.ex)) + put_tx = np->first_tx.ex; + if (unlikely(np->put_tx_ctx++ == np->last_tx_ctx)) + np->put_tx_ctx = np->first_tx_ctx; + } while (size); } - np->tx_skbuff[nr] = skb; + /* set last fragment flag */ + prev_tx->flaglen |= cpu_to_le32(NV_TX2_LASTPACKET); + + /* save skb in this slot's context area */ + prev_tx_ctx->skb = skb; -#ifdef NETIF_F_TSO if (skb_is_gso(skb)) tx_flags_extra = NV_TX2_TSO | (skb_shinfo(skb)->gso_size << NV_TX2_TSO_SHIFT); else -#endif - tx_flags_extra = skb->ip_summed == CHECKSUM_PARTIAL ? + tx_flags_extra = skb->ip_summed == CHECKSUM_PARTIAL ? NV_TX2_CHECKSUM_L3 | NV_TX2_CHECKSUM_L4 : 0; /* vlan tag */ - if (np->vlangrp && vlan_tx_tag_present(skb)) { - tx_flags_vlan = NV_TX3_VLAN_TAG_PRESENT | vlan_tx_tag_get(skb); + if (likely(!np->vlangrp)) { + start_tx->txvlan = 0; + } else { + if (vlan_tx_tag_present(skb)) + start_tx->txvlan = cpu_to_le32(NV_TX3_VLAN_TAG_PRESENT | vlan_tx_tag_get(skb)); + else + start_tx->txvlan = 0; } + spin_lock_irq(&np->lock); + /* set tx flags */ - if (np->desc_ver == DESC_VER_1 || np->desc_ver == DESC_VER_2) { - np->tx_ring.orig[start_nr].flaglen |= cpu_to_le32(tx_flags | tx_flags_extra); - } else { - np->tx_ring.ex[start_nr].txvlan = cpu_to_le32(tx_flags_vlan); - np->tx_ring.ex[start_nr].flaglen |= cpu_to_le32(tx_flags | tx_flags_extra); - } + start_tx->flaglen |= cpu_to_le32(tx_flags | tx_flags_extra); + np->put_tx.ex = put_tx; + + spin_unlock_irq(&np->lock); - dprintk(KERN_DEBUG "%s: nv_start_xmit: packet %d (entries %d) queued for transmission. tx_flags_extra: %x\n", - dev->name, np->next_tx, entries, tx_flags_extra); + dprintk(KERN_DEBUG "%s: nv_start_xmit_optimized: entries %d queued for transmission. tx_flags_extra: %x\n", + dev->name, entries, tx_flags_extra); { int j; for (j=0; j<64; j++) { @@ -1609,12 +1866,8 @@ #endif dprintk("\n"); } - np->next_tx += entries; - dev->trans_start = jiffies; - spin_unlock_irq(&np->lock); writel(NVREG_TXRXCTL_KICK|np->txrxctl_bits, get_hwbase(dev) + NvRegTxRxControl); - pci_push(get_hwbase(dev)); return NETDEV_TX_OK; } @@ -1627,26 +1880,22 @@ static void nv_tx_done(struct net_device { struct fe_priv *np = netdev_priv(dev); u32 flags; - unsigned int i; - struct sk_buff *skb; + struct ring_desc* orig_get_tx = np->get_tx.orig; - while (np->nic_tx != np->next_tx) { - i = np->nic_tx % np->tx_ring_size; + while ((np->get_tx.orig != np->put_tx.orig) && + !((flags = le32_to_cpu(np->get_tx.orig->flaglen)) & NV_TX_VALID)) { - if (np->desc_ver == DESC_VER_1 || np->desc_ver == DESC_VER_2) - flags = le32_to_cpu(np->tx_ring.orig[i].flaglen); - else - flags = le32_to_cpu(np->tx_ring.ex[i].flaglen); + dprintk(KERN_DEBUG "%s: nv_tx_done: flags 0x%x.\n", + dev->name, flags); + + pci_unmap_page(np->pci_dev, np->get_tx_ctx->dma, + np->get_tx_ctx->dma_len, + PCI_DMA_TODEVICE); + np->get_tx_ctx->dma = 0; - dprintk(KERN_DEBUG "%s: nv_tx_done: looking at packet %d, flags 0x%x.\n", - dev->name, np->nic_tx, flags); - if (flags & NV_TX_VALID) - break; if (np->desc_ver == DESC_VER_1) { if (flags & NV_TX_LASTPACKET) { - skb = np->tx_skbuff[i]; - if (flags & (NV_TX_RETRYERROR|NV_TX_CARRIERLOST|NV_TX_LATECOLLISION| - NV_TX_UNDERFLOW|NV_TX_ERROR)) { + if (flags & NV_TX_ERROR) { if (flags & NV_TX_UNDERFLOW) np->stats.tx_fifo_errors++; if (flags & NV_TX_CARRIERLOST) @@ -1654,14 +1903,14 @@ static void nv_tx_done(struct net_device np->stats.tx_errors++; } else { np->stats.tx_packets++; - np->stats.tx_bytes += skb->len; + np->stats.tx_bytes += np->get_tx_ctx->skb->len; } + dev_kfree_skb_any(np->get_tx_ctx->skb); + np->get_tx_ctx->skb = NULL; } } else { if (flags & NV_TX2_LASTPACKET) { - skb = np->tx_skbuff[i]; - if (flags & (NV_TX2_RETRYERROR|NV_TX2_CARRIERLOST|NV_TX2_LATECOLLISION| - NV_TX2_UNDERFLOW|NV_TX2_ERROR)) { + if (flags & NV_TX2_ERROR) { if (flags & NV_TX2_UNDERFLOW) np->stats.tx_fifo_errors++; if (flags & NV_TX2_CARRIERLOST) @@ -1669,15 +1918,56 @@ static void nv_tx_done(struct net_device np->stats.tx_errors++; } else { np->stats.tx_packets++; - np->stats.tx_bytes += skb->len; + np->stats.tx_bytes += np->get_tx_ctx->skb->len; } + dev_kfree_skb_any(np->get_tx_ctx->skb); + np->get_tx_ctx->skb = NULL; } } - nv_release_txskb(dev, i); - np->nic_tx++; + if (unlikely(np->get_tx.orig++ == np->last_tx.orig)) + np->get_tx.orig = np->first_tx.orig; + if (unlikely(np->get_tx_ctx++ == np->last_tx_ctx)) + np->get_tx_ctx = np->first_tx_ctx; } - if (np->next_tx - np->nic_tx < np->tx_limit_start) + if (unlikely((np->tx_stop == 1) && (np->get_tx.orig != orig_get_tx))) { + np->tx_stop = 0; netif_wake_queue(dev); + } +} + +static void nv_tx_done_optimized(struct net_device *dev, int limit) +{ + struct fe_priv *np = netdev_priv(dev); + u32 flags; + struct ring_desc_ex* orig_get_tx = np->get_tx.ex; + + while ((np->get_tx.ex != np->put_tx.ex) && + !((flags = le32_to_cpu(np->get_tx.ex->flaglen)) & NV_TX_VALID) && + (limit-- > 0)) { + + dprintk(KERN_DEBUG "%s: nv_tx_done_optimized: flags 0x%x.\n", + dev->name, flags); + + pci_unmap_page(np->pci_dev, np->get_tx_ctx->dma, + np->get_tx_ctx->dma_len, + PCI_DMA_TODEVICE); + np->get_tx_ctx->dma = 0; + + if (flags & NV_TX2_LASTPACKET) { + if (!(flags & NV_TX2_ERROR)) + np->stats.tx_packets++; + dev_kfree_skb_any(np->get_tx_ctx->skb); + np->get_tx_ctx->skb = NULL; + } + if (unlikely(np->get_tx.ex++ == np->last_tx.ex)) + np->get_tx.ex = np->first_tx.ex; + if (unlikely(np->get_tx_ctx++ == np->last_tx_ctx)) + np->get_tx_ctx = np->first_tx_ctx; + } + if (unlikely((np->tx_stop == 1) && (np->get_tx.ex != orig_get_tx))) { + np->tx_stop = 0; + netif_wake_queue(dev); + } } /* @@ -1700,9 +1990,8 @@ static void nv_tx_timeout(struct net_dev { int i; - printk(KERN_INFO "%s: Ring at %lx: next %d nic %d\n", - dev->name, (unsigned long)np->ring_addr, - np->next_tx, np->nic_tx); + printk(KERN_INFO "%s: Ring at %lx\n", + dev->name, (unsigned long)np->ring_addr); printk(KERN_INFO "%s: Dumping tx registers\n", dev->name); for (i=0;i<=np->register_size;i+= 32) { printk(KERN_INFO "%3x: %08x %08x %08x %08x %08x %08x %08x %08x\n", @@ -1750,13 +2039,16 @@ static void nv_tx_timeout(struct net_dev nv_stop_tx(dev); /* 2) check that the packets were not sent already: */ - nv_tx_done(dev); + if (np->desc_ver == DESC_VER_1 || np->desc_ver == DESC_VER_2) + nv_tx_done(dev); + else + nv_tx_done_optimized(dev, np->tx_ring_size); /* 3) if there are dead entries: clear everything */ - if (np->next_tx != np->nic_tx) { + if (np->get_tx_ctx != np->put_tx_ctx) { printk(KERN_DEBUG "%s: tx_timeout: dead entries!\n", dev->name); nv_drain_tx(dev); - np->next_tx = np->nic_tx = 0; + nv_init_tx(dev); setup_hw_rings(dev, NV_SETUP_TX_RING); netif_wake_queue(dev); } @@ -1823,40 +2115,27 @@ static int nv_rx_process(struct net_devi { struct fe_priv *np = netdev_priv(dev); u32 flags; - u32 vlanflags = 0; - int count; - - for (count = 0; count < limit; ++count) { - struct sk_buff *skb; - int len; - int i; - if (np->cur_rx - np->refill_rx >= np->rx_ring_size) - break; /* we scanned the whole ring - do not continue */ - - i = np->cur_rx % np->rx_ring_size; - if (np->desc_ver == DESC_VER_1 || np->desc_ver == DESC_VER_2) { - flags = le32_to_cpu(np->rx_ring.orig[i].flaglen); - len = nv_descr_getlength(&np->rx_ring.orig[i], np->desc_ver); - } else { - flags = le32_to_cpu(np->rx_ring.ex[i].flaglen); - len = nv_descr_getlength_ex(&np->rx_ring.ex[i], np->desc_ver); - vlanflags = le32_to_cpu(np->rx_ring.ex[i].buflow); - } + u32 rx_processed_cnt = 0; + struct sk_buff *skb; + int len; - dprintk(KERN_DEBUG "%s: nv_rx_process: looking at packet %d, flags 0x%x.\n", - dev->name, np->cur_rx, flags); + while((np->get_rx.orig != np->put_rx.orig) && + !((flags = le32_to_cpu(np->get_rx.orig->flaglen)) & NV_RX_AVAIL) && + (rx_processed_cnt++ < limit)) { - if (flags & NV_RX_AVAIL) - break; /* still owned by hardware, */ + dprintk(KERN_DEBUG "%s: nv_rx_process: flags 0x%x.\n", + dev->name, flags); /* * the packet is for us - immediately tear down the pci mapping. * TODO: check if a prefetch of the first cacheline improves * the performance. */ - pci_unmap_single(np->pci_dev, np->rx_dma[i], - np->rx_skbuff[i]->end-np->rx_skbuff[i]->data, + pci_unmap_single(np->pci_dev, np->get_rx_ctx->dma, + np->get_rx_ctx->dma_len, PCI_DMA_FROMDEVICE); + skb = np->get_rx_ctx->skb; + np->get_rx_ctx->skb = NULL; { int j; @@ -1864,123 +2143,228 @@ static int nv_rx_process(struct net_devi for (j=0; j<64; j++) { if ((j%16) == 0) dprintk("\n%03x:", j); - dprintk(" %02x", ((unsigned char*)np->rx_skbuff[i]->data)[j]); + dprintk(" %02x", ((unsigned char*)skb->data)[j]); } dprintk("\n"); } /* look at what we actually got: */ if (np->desc_ver == DESC_VER_1) { - if (!(flags & NV_RX_DESCRIPTORVALID)) - goto next_pkt; - - if (flags & NV_RX_ERROR) { - if (flags & NV_RX_MISSEDFRAME) { - np->stats.rx_missed_errors++; - np->stats.rx_errors++; - goto next_pkt; - } - if (flags & (NV_RX_ERROR1|NV_RX_ERROR2|NV_RX_ERROR3)) { - np->stats.rx_errors++; - goto next_pkt; - } - if (flags & NV_RX_CRCERR) { - np->stats.rx_crc_errors++; - np->stats.rx_errors++; - goto next_pkt; - } - if (flags & NV_RX_OVERFLOW) { - np->stats.rx_over_errors++; - np->stats.rx_errors++; - goto next_pkt; + if (likely(flags & NV_RX_DESCRIPTORVALID)) { + len = flags & LEN_MASK_V1; + if (unlikely(flags & NV_RX_ERROR)) { + if (flags & NV_RX_ERROR4) { + len = nv_getlen(dev, skb->data, len); + if (len < 0) { + np->stats.rx_errors++; + dev_kfree_skb(skb); + goto next_pkt; + } + } + /* framing errors are soft errors */ + else if (flags & NV_RX_FRAMINGERR) { + if (flags & NV_RX_SUBSTRACT1) { + len--; + } + } + /* the rest are hard errors */ + else { + if (flags & NV_RX_MISSEDFRAME) + np->stats.rx_missed_errors++; + if (flags & NV_RX_CRCERR) + np->stats.rx_crc_errors++; + if (flags & NV_RX_OVERFLOW) + np->stats.rx_over_errors++; + np->stats.rx_errors++; + dev_kfree_skb(skb); + goto next_pkt; + } } - if (flags & NV_RX_ERROR4) { - len = nv_getlen(dev, np->rx_skbuff[i]->data, len); - if (len < 0) { + } else { + dev_kfree_skb(skb); + goto next_pkt; + } + } else { + if (likely(flags & NV_RX2_DESCRIPTORVALID)) { + len = flags & LEN_MASK_V2; + if (unlikely(flags & NV_RX2_ERROR)) { + if (flags & NV_RX2_ERROR4) { + len = nv_getlen(dev, skb->data, len); + if (len < 0) { + np->stats.rx_errors++; + dev_kfree_skb(skb); + goto next_pkt; + } + } + /* framing errors are soft errors */ + else if (flags & NV_RX2_FRAMINGERR) { + if (flags & NV_RX2_SUBSTRACT1) { + len--; + } + } + /* the rest are hard errors */ + else { + if (flags & NV_RX2_CRCERR) + np->stats.rx_crc_errors++; + if (flags & NV_RX2_OVERFLOW) + np->stats.rx_over_errors++; np->stats.rx_errors++; + dev_kfree_skb(skb); goto next_pkt; } } - /* framing errors are soft errors. */ - if (flags & NV_RX_FRAMINGERR) { - if (flags & NV_RX_SUBSTRACT1) { - len--; + if ((flags & NV_RX2_CHECKSUMMASK) == NV_RX2_CHECKSUMOK2)/*ip and tcp */ { + skb->ip_summed = CHECKSUM_UNNECESSARY; + } else { + if ((flags & NV_RX2_CHECKSUMMASK) == NV_RX2_CHECKSUMOK1 || + (flags & NV_RX2_CHECKSUMMASK) == NV_RX2_CHECKSUMOK3) { + skb->ip_summed = CHECKSUM_UNNECESSARY; } } - } - } else { - if (!(flags & NV_RX2_DESCRIPTORVALID)) + } else { + dev_kfree_skb(skb); goto next_pkt; + } + } + /* got a valid packet - forward it to the network core */ + skb_put(skb, len); + skb->protocol = eth_type_trans(skb, dev); + dprintk(KERN_DEBUG "%s: nv_rx_process: %d bytes, proto %d accepted.\n", + dev->name, len, skb->protocol); +#ifdef CONFIG_FORCEDETH_NAPI + netif_receive_skb(skb); +#else + netif_rx(skb); +#endif + dev->last_rx = jiffies; + np->stats.rx_packets++; + np->stats.rx_bytes += len; +next_pkt: + if (unlikely(np->get_rx.orig++ == np->last_rx.orig)) + np->get_rx.orig = np->first_rx.orig; + if (unlikely(np->get_rx_ctx++ == np->last_rx_ctx)) + np->get_rx_ctx = np->first_rx_ctx; + } - if (flags & NV_RX2_ERROR) { - if (flags & (NV_RX2_ERROR1|NV_RX2_ERROR2|NV_RX2_ERROR3)) { - np->stats.rx_errors++; - goto next_pkt; - } - if (flags & NV_RX2_CRCERR) { - np->stats.rx_crc_errors++; - np->stats.rx_errors++; - goto next_pkt; - } - if (flags & NV_RX2_OVERFLOW) { - np->stats.rx_over_errors++; - np->stats.rx_errors++; - goto next_pkt; - } + return rx_processed_cnt; +} + +static int nv_rx_process_optimized(struct net_device *dev, int limit) +{ + struct fe_priv *np = netdev_priv(dev); + u32 flags; + u32 vlanflags = 0; + u32 rx_processed_cnt = 0; + struct sk_buff *skb; + int len; + + while((np->get_rx.ex != np->put_rx.ex) && + !((flags = le32_to_cpu(np->get_rx.ex->flaglen)) & NV_RX2_AVAIL) && + (rx_processed_cnt++ < limit)) { + + dprintk(KERN_DEBUG "%s: nv_rx_process_optimized: flags 0x%x.\n", + dev->name, flags); + + /* + * the packet is for us - immediately tear down the pci mapping. + * TODO: check if a prefetch of the first cacheline improves + * the performance. + */ + pci_unmap_single(np->pci_dev, np->get_rx_ctx->dma, + np->get_rx_ctx->dma_len, + PCI_DMA_FROMDEVICE); + skb = np->get_rx_ctx->skb; + np->get_rx_ctx->skb = NULL; + + { + int j; + dprintk(KERN_DEBUG "Dumping packet (flags 0x%x).",flags); + for (j=0; j<64; j++) { + if ((j%16) == 0) + dprintk("\n%03x:", j); + dprintk(" %02x", ((unsigned char*)skb->data)[j]); + } + dprintk("\n"); + } + /* look at what we actually got: */ + if (likely(flags & NV_RX2_DESCRIPTORVALID)) { + len = flags & LEN_MASK_V2; + if (unlikely(flags & NV_RX2_ERROR)) { if (flags & NV_RX2_ERROR4) { - len = nv_getlen(dev, np->rx_skbuff[i]->data, len); + len = nv_getlen(dev, skb->data, len); if (len < 0) { - np->stats.rx_errors++; + dev_kfree_skb(skb); goto next_pkt; } } /* framing errors are soft errors */ - if (flags & NV_RX2_FRAMINGERR) { + else if (flags & NV_RX2_FRAMINGERR) { if (flags & NV_RX2_SUBSTRACT1) { len--; } } + /* the rest are hard errors */ + else { + dev_kfree_skb(skb); + goto next_pkt; + } } - if (np->rx_csum) { - flags &= NV_RX2_CHECKSUMMASK; - if (flags == NV_RX2_CHECKSUMOK1 || - flags == NV_RX2_CHECKSUMOK2 || - flags == NV_RX2_CHECKSUMOK3) { - dprintk(KERN_DEBUG "%s: hw checksum hit!.\n", dev->name); - np->rx_skbuff[i]->ip_summed = CHECKSUM_UNNECESSARY; - } else { - dprintk(KERN_DEBUG "%s: hwchecksum miss!.\n", dev->name); + + if ((flags & NV_RX2_CHECKSUMMASK) == NV_RX2_CHECKSUMOK2)/*ip and tcp */ { + skb->ip_summed = CHECKSUM_UNNECESSARY; + } else { + if ((flags & NV_RX2_CHECKSUMMASK) == NV_RX2_CHECKSUMOK1 || + (flags & NV_RX2_CHECKSUMMASK) == NV_RX2_CHECKSUMOK3) { + skb->ip_summed = CHECKSUM_UNNECESSARY; } } - } - /* got a valid packet - forward it to the network core */ - skb = np->rx_skbuff[i]; - np->rx_skbuff[i] = NULL; - skb_put(skb, len); - skb->protocol = eth_type_trans(skb, dev); - dprintk(KERN_DEBUG "%s: nv_rx_process: packet %d with %d bytes, proto %d accepted.\n", - dev->name, np->cur_rx, len, skb->protocol); + /* got a valid packet - forward it to the network core */ + skb_put(skb, len); + skb->protocol = eth_type_trans(skb, dev); + prefetch(skb->data); + + dprintk(KERN_DEBUG "%s: nv_rx_process_optimized: %d bytes, proto %d accepted.\n", + dev->name, len, skb->protocol); + + if (likely(!np->vlangrp)) { #ifdef CONFIG_FORCEDETH_NAPI - if (np->vlangrp && (vlanflags & NV_RX3_VLAN_TAG_PRESENT)) - vlan_hwaccel_receive_skb(skb, np->vlangrp, - vlanflags & NV_RX3_VLAN_TAG_MASK); - else - netif_receive_skb(skb); + netif_receive_skb(skb); #else - if (np->vlangrp && (vlanflags & NV_RX3_VLAN_TAG_PRESENT)) - vlan_hwaccel_rx(skb, np->vlangrp, - vlanflags & NV_RX3_VLAN_TAG_MASK); - else - netif_rx(skb); + netif_rx(skb); #endif - dev->last_rx = jiffies; - np->stats.rx_packets++; - np->stats.rx_bytes += len; + } else { + vlanflags = le32_to_cpu(np->get_rx.ex->buflow); + if (vlanflags & NV_RX3_VLAN_TAG_PRESENT) { +#ifdef CONFIG_FORCEDETH_NAPI + vlan_hwaccel_receive_skb(skb, np->vlangrp, + vlanflags & NV_RX3_VLAN_TAG_MASK); +#else + vlan_hwaccel_rx(skb, np->vlangrp, + vlanflags & NV_RX3_VLAN_TAG_MASK); +#endif + } else { +#ifdef CONFIG_FORCEDETH_NAPI + netif_receive_skb(skb); +#else + netif_rx(skb); +#endif + } + } + + dev->last_rx = jiffies; + np->stats.rx_packets++; + np->stats.rx_bytes += len; + } else { + dev_kfree_skb(skb); + } next_pkt: - np->cur_rx++; + if (unlikely(np->get_rx.ex++ == np->last_rx.ex)) + np->get_rx.ex = np->first_rx.ex; + if (unlikely(np->get_rx_ctx++ == np->last_rx_ctx)) + np->get_rx_ctx = np->first_rx_ctx; } - return count; + return rx_processed_cnt; } static void set_bufsize(struct net_device *dev) @@ -2456,7 +2840,6 @@ static irqreturn_t nv_nic_irq(int foo, v events = readl(base + NvRegMSIXIrqStatus) & NVREG_IRQSTAT_MASK; writel(NVREG_IRQSTAT_MASK, base + NvRegMSIXIrqStatus); } - pci_push(base); dprintk(KERN_DEBUG "%s: irq: %08x\n", dev->name, events); if (!(events & np->irqmask)) break; @@ -2465,22 +2848,46 @@ static irqreturn_t nv_nic_irq(int foo, v nv_tx_done(dev); spin_unlock(&np->lock); - if (events & NVREG_IRQ_LINK) { +#ifdef CONFIG_FORCEDETH_NAPI + if (events & NVREG_IRQ_RX_ALL) { + netif_rx_schedule(dev); + + /* Disable furthur receive irq's */ + spin_lock(&np->lock); + np->irqmask &= ~NVREG_IRQ_RX_ALL; + + if (np->msi_flags & NV_MSI_X_ENABLED) + writel(NVREG_IRQ_RX_ALL, base + NvRegIrqMask); + else + writel(np->irqmask, base + NvRegIrqMask); + spin_unlock(&np->lock); + } +#else + if (nv_rx_process(dev, dev->weight)) { + if (unlikely(nv_alloc_rx(dev))) { + spin_lock(&np->lock); + if (!np->in_shutdown) + mod_timer(&np->oom_kick, jiffies + OOM_REFILL); + spin_unlock(&np->lock); + } + } +#endif + if (unlikely(events & NVREG_IRQ_LINK)) { spin_lock(&np->lock); nv_link_irq(dev); spin_unlock(&np->lock); } - if (np->need_linktimer && time_after(jiffies, np->link_timeout)) { + if (unlikely(np->need_linktimer && time_after(jiffies, np->link_timeout))) { spin_lock(&np->lock); nv_linkchange(dev); spin_unlock(&np->lock); np->link_timeout = jiffies + LINK_TIMEOUT; } - if (events & (NVREG_IRQ_TX_ERR)) { + if (unlikely(events & (NVREG_IRQ_TX_ERR))) { dprintk(KERN_DEBUG "%s: received irq with events 0x%x. Probably TX fail.\n", dev->name, events); } - if (events & (NVREG_IRQ_UNKNOWN)) { + if (unlikely(events & (NVREG_IRQ_UNKNOWN))) { printk(KERN_DEBUG "%s: received irq with unknown events 0x%x. Please report\n", dev->name, events); } @@ -2501,6 +2908,63 @@ static irqreturn_t nv_nic_irq(int foo, v spin_unlock(&np->lock); break; } + if (unlikely(i > max_interrupt_work)) { + spin_lock(&np->lock); + /* disable interrupts on the nic */ + if (!(np->msi_flags & NV_MSI_X_ENABLED)) + writel(0, base + NvRegIrqMask); + else + writel(np->irqmask, base + NvRegIrqMask); + pci_push(base); + + if (!np->in_shutdown) { + np->nic_poll_irq = np->irqmask; + mod_timer(&np->nic_poll, jiffies + POLL_WAIT); + } + printk(KERN_DEBUG "%s: too many iterations (%d) in nv_nic_irq.\n", dev->name, i); + spin_unlock(&np->lock); + break; + } + + } + dprintk(KERN_DEBUG "%s: nv_nic_irq completed\n", dev->name); + + return IRQ_RETVAL(i); +} + +#define TX_WORK_PER_LOOP 64 +#define RX_WORK_PER_LOOP 64 +/** + * All _optimized functions are used to help increase performance + * (reduce CPU and increase throughput). They use descripter version 3, + * compiler directives, and reduce memory accesses. + */ +static irqreturn_t nv_nic_irq_optimized(int foo, void *data) +{ + struct net_device *dev = (struct net_device *) data; + struct fe_priv *np = netdev_priv(dev); + u8 __iomem *base = get_hwbase(dev); + u32 events; + int i; + + dprintk(KERN_DEBUG "%s: nv_nic_irq_optimized\n", dev->name); + + for (i=0; ; i++) { + if (!(np->msi_flags & NV_MSI_X_ENABLED)) { + events = readl(base + NvRegIrqStatus) & NVREG_IRQSTAT_MASK; + writel(NVREG_IRQSTAT_MASK, base + NvRegIrqStatus); + } else { + events = readl(base + NvRegMSIXIrqStatus) & NVREG_IRQSTAT_MASK; + writel(NVREG_IRQSTAT_MASK, base + NvRegMSIXIrqStatus); + } + dprintk(KERN_DEBUG "%s: irq: %08x\n", dev->name, events); + if (!(events & np->irqmask)) + break; + + spin_lock(&np->lock); + nv_tx_done_optimized(dev, TX_WORK_PER_LOOP); + spin_unlock(&np->lock); + #ifdef CONFIG_FORCEDETH_NAPI if (events & NVREG_IRQ_RX_ALL) { netif_rx_schedule(dev); @@ -2516,15 +2980,53 @@ #ifdef CONFIG_FORCEDETH_NAPI spin_unlock(&np->lock); } #else - nv_rx_process(dev, dev->weight); - if (nv_alloc_rx(dev)) { + if (nv_rx_process_optimized(dev, dev->weight)) { + if (unlikely(nv_alloc_rx_optimized(dev))) { + spin_lock(&np->lock); + if (!np->in_shutdown) + mod_timer(&np->oom_kick, jiffies + OOM_REFILL); + spin_unlock(&np->lock); + } + } +#endif + if (unlikely(events & NVREG_IRQ_LINK)) { spin_lock(&np->lock); - if (!np->in_shutdown) - mod_timer(&np->oom_kick, jiffies + OOM_REFILL); + nv_link_irq(dev); spin_unlock(&np->lock); } -#endif - if (i > max_interrupt_work) { + if (unlikely(np->need_linktimer && time_after(jiffies, np->link_timeout))) { + spin_lock(&np->lock); + nv_linkchange(dev); + spin_unlock(&np->lock); + np->link_timeout = jiffies + LINK_TIMEOUT; + } + if (unlikely(events & (NVREG_IRQ_TX_ERR))) { + dprintk(KERN_DEBUG "%s: received irq with events 0x%x. Probably TX fail.\n", + dev->name, events); + } + if (unlikely(events & (NVREG_IRQ_UNKNOWN))) { + printk(KERN_DEBUG "%s: received irq with unknown events 0x%x. Please report\n", + dev->name, events); + } + if (unlikely(events & NVREG_IRQ_RECOVER_ERROR)) { + spin_lock(&np->lock); + /* disable interrupts on the nic */ + if (!(np->msi_flags & NV_MSI_X_ENABLED)) + writel(0, base + NvRegIrqMask); + else + writel(np->irqmask, base + NvRegIrqMask); + pci_push(base); + + if (!np->in_shutdown) { + np->nic_poll_irq = np->irqmask; + np->recover_error = 1; + mod_timer(&np->nic_poll, jiffies + POLL_WAIT); + } + spin_unlock(&np->lock); + break; + } + + if (unlikely(i > max_interrupt_work)) { spin_lock(&np->lock); /* disable interrupts on the nic */ if (!(np->msi_flags & NV_MSI_X_ENABLED)) @@ -2543,7 +3045,7 @@ #endif } } - dprintk(KERN_DEBUG "%s: nv_nic_irq completed\n", dev->name); + dprintk(KERN_DEBUG "%s: nv_nic_irq_optimized completed\n", dev->name); return IRQ_RETVAL(i); } @@ -2562,20 +3064,19 @@ static irqreturn_t nv_nic_irq_tx(int foo for (i=0; ; i++) { events = readl(base + NvRegMSIXIrqStatus) & NVREG_IRQ_TX_ALL; writel(NVREG_IRQ_TX_ALL, base + NvRegMSIXIrqStatus); - pci_push(base); dprintk(KERN_DEBUG "%s: tx irq: %08x\n", dev->name, events); if (!(events & np->irqmask)) break; spin_lock_irqsave(&np->lock, flags); - nv_tx_done(dev); + nv_tx_done_optimized(dev, TX_WORK_PER_LOOP); spin_unlock_irqrestore(&np->lock, flags); - if (events & (NVREG_IRQ_TX_ERR)) { + if (unlikely(events & (NVREG_IRQ_TX_ERR))) { dprintk(KERN_DEBUG "%s: received irq with events 0x%x. Probably TX fail.\n", dev->name, events); } - if (i > max_interrupt_work) { + if (unlikely(i > max_interrupt_work)) { spin_lock_irqsave(&np->lock, flags); /* disable interrupts on the nic */ writel(NVREG_IRQ_TX_ALL, base + NvRegIrqMask); @@ -2604,7 +3105,10 @@ static int nv_napi_poll(struct net_devic u8 __iomem *base = get_hwbase(dev); unsigned long flags; - pkts = nv_rx_process(dev, limit); + if (np->desc_ver == DESC_VER_1 || np->desc_ver == DESC_VER_2) + pkts = nv_rx_process(dev, limit); + else + pkts = nv_rx_process_optimized(dev, limit); if (nv_alloc_rx(dev)) { spin_lock_irqsave(&np->lock, flags); @@ -2670,20 +3174,20 @@ static irqreturn_t nv_nic_irq_rx(int foo for (i=0; ; i++) { events = readl(base + NvRegMSIXIrqStatus) & NVREG_IRQ_RX_ALL; writel(NVREG_IRQ_RX_ALL, base + NvRegMSIXIrqStatus); - pci_push(base); dprintk(KERN_DEBUG "%s: rx irq: %08x\n", dev->name, events); if (!(events & np->irqmask)) break; - nv_rx_process(dev, dev->weight); - if (nv_alloc_rx(dev)) { - spin_lock_irqsave(&np->lock, flags); - if (!np->in_shutdown) - mod_timer(&np->oom_kick, jiffies + OOM_REFILL); - spin_unlock_irqrestore(&np->lock, flags); + if (nv_rx_process_optimized(dev, dev->weight)) { + if (unlikely(nv_alloc_rx_optimized(dev))) { + spin_lock_irqsave(&np->lock, flags); + if (!np->in_shutdown) + mod_timer(&np->oom_kick, jiffies + OOM_REFILL); + spin_unlock_irqrestore(&np->lock, flags); + } } - if (i > max_interrupt_work) { + if (unlikely(i > max_interrupt_work)) { spin_lock_irqsave(&np->lock, flags); /* disable interrupts on the nic */ writel(NVREG_IRQ_RX_ALL, base + NvRegIrqMask); @@ -2718,11 +3222,15 @@ static irqreturn_t nv_nic_irq_other(int for (i=0; ; i++) { events = readl(base + NvRegMSIXIrqStatus) & NVREG_IRQ_OTHER; writel(NVREG_IRQ_OTHER, base + NvRegMSIXIrqStatus); - pci_push(base); dprintk(KERN_DEBUG "%s: irq: %08x\n", dev->name, events); if (!(events & np->irqmask)) break; + /* check tx in case we reached max loop limit in tx isr */ + spin_lock_irqsave(&np->lock, flags); + nv_tx_done_optimized(dev, TX_WORK_PER_LOOP); + spin_unlock_irqrestore(&np->lock, flags); + if (events & NVREG_IRQ_LINK) { spin_lock_irqsave(&np->lock, flags); nv_link_irq(dev); @@ -2752,7 +3260,7 @@ static irqreturn_t nv_nic_irq_other(int printk(KERN_DEBUG "%s: received irq with unknown events 0x%x. Please report\n", dev->name, events); } - if (i > max_interrupt_work) { + if (unlikely(i > max_interrupt_work)) { spin_lock_irqsave(&np->lock, flags); /* disable interrupts on the nic */ writel(NVREG_IRQ_OTHER, base + NvRegIrqMask); @@ -2835,6 +3343,16 @@ static int nv_request_irq(struct net_dev u8 __iomem *base = get_hwbase(dev); int ret = 1; int i; + irqreturn_t (*handler)(int foo, void *data); + + if (intr_test) { + handler = nv_nic_irq_test; + } else { + if (np->desc_ver == DESC_VER_3) + handler = nv_nic_irq_optimized; + else + handler = nv_nic_irq; + } if (np->msi_flags & NV_MSI_X_CAPABLE) { for (i = 0; i < (np->msi_flags & NV_MSI_X_VECTORS_MASK); i++) { @@ -2872,10 +3390,7 @@ static int nv_request_irq(struct net_dev set_msix_vector_map(dev, NV_MSI_X_VECTOR_OTHER, NVREG_IRQ_OTHER); } else { /* Request irq for all interrupts */ - if ((!intr_test && - request_irq(np->msi_x_entry[NV_MSI_X_VECTOR_ALL].vector, &nv_nic_irq, IRQF_SHARED, dev->name, dev) != 0) || - (intr_test && - request_irq(np->msi_x_entry[NV_MSI_X_VECTOR_ALL].vector, &nv_nic_irq_test, IRQF_SHARED, dev->name, dev) != 0)) { + if (request_irq(np->msi_x_entry[NV_MSI_X_VECTOR_ALL].vector, handler, IRQF_SHARED, dev->name, dev) != 0) { printk(KERN_INFO "forcedeth: request_irq failed %d\n", ret); pci_disable_msix(np->pci_dev); np->msi_flags &= ~NV_MSI_X_ENABLED; @@ -2891,8 +3406,7 @@ static int nv_request_irq(struct net_dev if (ret != 0 && np->msi_flags & NV_MSI_CAPABLE) { if ((ret = pci_enable_msi(np->pci_dev)) == 0) { np->msi_flags |= NV_MSI_ENABLED; - if ((!intr_test && request_irq(np->pci_dev->irq, &nv_nic_irq, IRQF_SHARED, dev->name, dev) != 0) || - (intr_test && request_irq(np->pci_dev->irq, &nv_nic_irq_test, IRQF_SHARED, dev->name, dev) != 0)) { + if (request_irq(np->pci_dev->irq, handler, IRQF_SHARED, dev->name, dev) != 0) { printk(KERN_INFO "forcedeth: request_irq failed %d\n", ret); pci_disable_msi(np->pci_dev); np->msi_flags &= ~NV_MSI_ENABLED; @@ -2907,8 +3421,7 @@ static int nv_request_irq(struct net_dev } } if (ret != 0) { - if ((!intr_test && request_irq(np->pci_dev->irq, &nv_nic_irq, IRQF_SHARED, dev->name, dev) != 0) || - (intr_test && request_irq(np->pci_dev->irq, &nv_nic_irq_test, IRQF_SHARED, dev->name, dev) != 0)) + if (request_irq(np->pci_dev->irq, handler, IRQF_SHARED, dev->name, dev) != 0) goto out_err; } @@ -3051,47 +3564,8 @@ static void nv_do_stats_poll(unsigned lo { struct net_device *dev = (struct net_device *) data; struct fe_priv *np = netdev_priv(dev); - u8 __iomem *base = get_hwbase(dev); - np->estats.tx_bytes += readl(base + NvRegTxCnt); - np->estats.tx_zero_rexmt += readl(base + NvRegTxZeroReXmt); - np->estats.tx_one_rexmt += readl(base + NvRegTxOneReXmt); - np->estats.tx_many_rexmt += readl(base + NvRegTxManyReXmt); - np->estats.tx_late_collision += readl(base + NvRegTxLateCol); - np->estats.tx_fifo_errors += readl(base + NvRegTxUnderflow); - np->estats.tx_carrier_errors += readl(base + NvRegTxLossCarrier); - np->estats.tx_excess_deferral += readl(base + NvRegTxExcessDef); - np->estats.tx_retry_error += readl(base + NvRegTxRetryErr); - np->estats.tx_deferral += readl(base + NvRegTxDef); - np->estats.tx_packets += readl(base + NvRegTxFrame); - np->estats.tx_pause += readl(base + NvRegTxPause); - np->estats.rx_frame_error += readl(base + NvRegRxFrameErr); - np->estats.rx_extra_byte += readl(base + NvRegRxExtraByte); - np->estats.rx_late_collision += readl(base + NvRegRxLateCol); - np->estats.rx_runt += readl(base + NvRegRxRunt); - np->estats.rx_frame_too_long += readl(base + NvRegRxFrameTooLong); - np->estats.rx_over_errors += readl(base + NvRegRxOverflow); - np->estats.rx_crc_errors += readl(base + NvRegRxFCSErr); - np->estats.rx_frame_align_error += readl(base + NvRegRxFrameAlignErr); - np->estats.rx_length_error += readl(base + NvRegRxLenErr); - np->estats.rx_unicast += readl(base + NvRegRxUnicast); - np->estats.rx_multicast += readl(base + NvRegRxMulticast); - np->estats.rx_broadcast += readl(base + NvRegRxBroadcast); - np->estats.rx_bytes += readl(base + NvRegRxCnt); - np->estats.rx_pause += readl(base + NvRegRxPause); - np->estats.rx_drop_frame += readl(base + NvRegRxDropFrame); - np->estats.rx_packets = - np->estats.rx_unicast + - np->estats.rx_multicast + - np->estats.rx_broadcast; - np->estats.rx_errors_total = - np->estats.rx_crc_errors + - np->estats.rx_over_errors + - np->estats.rx_frame_error + - (np->estats.rx_frame_align_error - np->estats.rx_extra_byte) + - np->estats.rx_late_collision + - np->estats.rx_runt + - np->estats.rx_frame_too_long; + nv_get_hw_stats(dev); if (!np->in_shutdown) mod_timer(&np->stats_poll, jiffies + STATS_INTERVAL); @@ -3465,7 +3939,7 @@ static int nv_set_ringparam(struct net_d { struct fe_priv *np = netdev_priv(dev); u8 __iomem *base = get_hwbase(dev); - u8 *rxtx_ring, *rx_skbuff, *tx_skbuff, *rx_dma, *tx_dma, *tx_dma_len; + u8 *rxtx_ring, *rx_skbuff, *tx_skbuff; dma_addr_t ring_addr; if (ring->rx_pending < RX_RING_MIN || @@ -3491,12 +3965,9 @@ static int nv_set_ringparam(struct net_d sizeof(struct ring_desc_ex) * (ring->rx_pending + ring->tx_pending), &ring_addr); } - rx_skbuff = kmalloc(sizeof(struct sk_buff*) * ring->rx_pending, GFP_KERNEL); - rx_dma = kmalloc(sizeof(dma_addr_t) * ring->rx_pending, GFP_KERNEL); - tx_skbuff = kmalloc(sizeof(struct sk_buff*) * ring->tx_pending, GFP_KERNEL); - tx_dma = kmalloc(sizeof(dma_addr_t) * ring->tx_pending, GFP_KERNEL); - tx_dma_len = kmalloc(sizeof(unsigned int) * ring->tx_pending, GFP_KERNEL); - if (!rxtx_ring || !rx_skbuff || !rx_dma || !tx_skbuff || !tx_dma || !tx_dma_len) { + rx_skbuff = kmalloc(sizeof(struct nv_skb_map) * ring->rx_pending, GFP_KERNEL); + tx_skbuff = kmalloc(sizeof(struct nv_skb_map) * ring->tx_pending, GFP_KERNEL); + if (!rxtx_ring || !rx_skbuff || !tx_skbuff) { /* fall back to old rings */ if (np->desc_ver == DESC_VER_1 || np->desc_ver == DESC_VER_2) { if (rxtx_ring) @@ -3509,14 +3980,8 @@ static int nv_set_ringparam(struct net_d } if (rx_skbuff) kfree(rx_skbuff); - if (rx_dma) - kfree(rx_dma); if (tx_skbuff) kfree(tx_skbuff); - if (tx_dma) - kfree(tx_dma); - if (tx_dma_len) - kfree(tx_dma_len); goto exit; } @@ -3538,8 +4003,6 @@ static int nv_set_ringparam(struct net_d /* set new values */ np->rx_ring_size = ring->rx_pending; np->tx_ring_size = ring->tx_pending; - np->tx_limit_stop = ring->tx_pending - TX_LIMIT_DIFFERENCE; - np->tx_limit_start = ring->tx_pending - TX_LIMIT_DIFFERENCE - 1; if (np->desc_ver == DESC_VER_1 || np->desc_ver == DESC_VER_2) { np->rx_ring.orig = (struct ring_desc*)rxtx_ring; np->tx_ring.orig = &np->rx_ring.orig[np->rx_ring_size]; @@ -3547,18 +4010,12 @@ static int nv_set_ringparam(struct net_d np->rx_ring.ex = (struct ring_desc_ex*)rxtx_ring; np->tx_ring.ex = &np->rx_ring.ex[np->rx_ring_size]; } - np->rx_skbuff = (struct sk_buff**)rx_skbuff; - np->rx_dma = (dma_addr_t*)rx_dma; - np->tx_skbuff = (struct sk_buff**)tx_skbuff; - np->tx_dma = (dma_addr_t*)tx_dma; - np->tx_dma_len = (unsigned int*)tx_dma_len; + np->rx_skb = (struct nv_skb_map*)rx_skbuff; + np->tx_skb = (struct nv_skb_map*)tx_skbuff; np->ring_addr = ring_addr; - memset(np->rx_skbuff, 0, sizeof(struct sk_buff*) * np->rx_ring_size); - memset(np->rx_dma, 0, sizeof(dma_addr_t) * np->rx_ring_size); - memset(np->tx_skbuff, 0, sizeof(struct sk_buff*) * np->tx_ring_size); - memset(np->tx_dma, 0, sizeof(dma_addr_t) * np->tx_ring_size); - memset(np->tx_dma_len, 0, sizeof(unsigned int) * np->tx_ring_size); + memset(np->rx_skb, 0, sizeof(struct nv_skb_map) * np->rx_ring_size); + memset(np->tx_skb, 0, sizeof(struct nv_skb_map) * np->tx_ring_size); if (netif_running(dev)) { /* reinit driver view of the queues */ @@ -3727,8 +4184,10 @@ static int nv_get_stats_count(struct net { struct fe_priv *np = netdev_priv(dev); - if (np->driver_data & DEV_HAS_STATISTICS) - return sizeof(struct nv_ethtool_stats)/sizeof(u64); + if (np->driver_data & DEV_HAS_STATISTICS_V1) + return NV_DEV_STATISTICS_V1_COUNT; + else if (np->driver_data & DEV_HAS_STATISTICS_V2) + return NV_DEV_STATISTICS_V2_COUNT; else return 0; } @@ -3955,7 +4414,7 @@ static int nv_loopback_test(struct net_d dprintk(KERN_DEBUG "%s: loopback len mismatch %d vs %d\n", dev->name, len, pkt_len); } else { - rx_skb = np->rx_skbuff[0]; + rx_skb = np->rx_skb[0].skb; for (i = 0; i < pkt_len; i++) { if (rx_skb->data[i] != (u8)(i & 0xff)) { ret = 0; @@ -4315,7 +4774,7 @@ static int nv_open(struct net_device *de mod_timer(&np->oom_kick, jiffies + OOM_REFILL); /* start statistics timer */ - if (np->driver_data & DEV_HAS_STATISTICS) + if (np->driver_data & (DEV_HAS_STATISTICS_V1|DEV_HAS_STATISTICS_V2)) mod_timer(&np->stats_poll, jiffies + STATS_INTERVAL); spin_unlock_irq(&np->lock); @@ -4412,7 +4871,9 @@ static int __devinit nv_probe(struct pci if (err < 0) goto out_disable; - if (id->driver_data & (DEV_HAS_VLAN|DEV_HAS_MSI_X|DEV_HAS_POWER_CNTRL|DEV_HAS_STATISTICS)) + if (id->driver_data & (DEV_HAS_VLAN|DEV_HAS_MSI_X|DEV_HAS_POWER_CNTRL|DEV_HAS_STATISTICS_V2)) + np->register_size = NV_PCI_REGSZ_VER3; + else if (id->driver_data & DEV_HAS_STATISTICS_V1) np->register_size = NV_PCI_REGSZ_VER2; else np->register_size = NV_PCI_REGSZ_VER1; @@ -4475,10 +4936,8 @@ static int __devinit nv_probe(struct pci np->rx_csum = 1; np->txrxctl_bits |= NVREG_TXRXCTL_RXCHECK; dev->features |= NETIF_F_HW_CSUM | NETIF_F_SG; -#ifdef NETIF_F_TSO dev->features |= NETIF_F_TSO; -#endif - } + } np->vlanctl_bits = 0; if (id->driver_data & DEV_HAS_VLAN) { @@ -4512,8 +4971,6 @@ #endif np->rx_ring_size = RX_RING_DEFAULT; np->tx_ring_size = TX_RING_DEFAULT; - np->tx_limit_stop = np->tx_ring_size - TX_LIMIT_DIFFERENCE; - np->tx_limit_start = np->tx_ring_size - TX_LIMIT_DIFFERENCE - 1; if (np->desc_ver == DESC_VER_1 || np->desc_ver == DESC_VER_2) { np->rx_ring.orig = pci_alloc_consistent(pci_dev, @@ -4530,22 +4987,19 @@ #endif goto out_unmap; np->tx_ring.ex = &np->rx_ring.ex[np->rx_ring_size]; } - np->rx_skbuff = kmalloc(sizeof(struct sk_buff*) * np->rx_ring_size, GFP_KERNEL); - np->rx_dma = kmalloc(sizeof(dma_addr_t) * np->rx_ring_size, GFP_KERNEL); - np->tx_skbuff = kmalloc(sizeof(struct sk_buff*) * np->tx_ring_size, GFP_KERNEL); - np->tx_dma = kmalloc(sizeof(dma_addr_t) * np->tx_ring_size, GFP_KERNEL); - np->tx_dma_len = kmalloc(sizeof(unsigned int) * np->tx_ring_size, GFP_KERNEL); - if (!np->rx_skbuff || !np->rx_dma || !np->tx_skbuff || !np->tx_dma || !np->tx_dma_len) + np->rx_skb = kmalloc(sizeof(struct nv_skb_map) * np->rx_ring_size, GFP_KERNEL); + np->tx_skb = kmalloc(sizeof(struct nv_skb_map) * np->tx_ring_size, GFP_KERNEL); + if (!np->rx_skb || !np->tx_skb) goto out_freering; - memset(np->rx_skbuff, 0, sizeof(struct sk_buff*) * np->rx_ring_size); - memset(np->rx_dma, 0, sizeof(dma_addr_t) * np->rx_ring_size); - memset(np->tx_skbuff, 0, sizeof(struct sk_buff*) * np->tx_ring_size); - memset(np->tx_dma, 0, sizeof(dma_addr_t) * np->tx_ring_size); - memset(np->tx_dma_len, 0, sizeof(unsigned int) * np->tx_ring_size); + memset(np->rx_skb, 0, sizeof(struct nv_skb_map) * np->rx_ring_size); + memset(np->tx_skb, 0, sizeof(struct nv_skb_map) * np->tx_ring_size); dev->open = nv_open; dev->stop = nv_close; - dev->hard_start_xmit = nv_start_xmit; + if (np->desc_ver == DESC_VER_1 || np->desc_ver == DESC_VER_2) + dev->hard_start_xmit = nv_start_xmit; + else + dev->hard_start_xmit = nv_start_xmit_optimized; dev->get_stats = nv_get_stats; dev->change_mtu = nv_change_mtu; dev->set_mac_address = nv_set_mac_address; @@ -4553,7 +5007,7 @@ #endif #ifdef CONFIG_NET_POLL_CONTROLLER dev->poll_controller = nv_poll_controller; #endif - dev->weight = 64; + dev->weight = RX_WORK_PER_LOOP; #ifdef CONFIG_FORCEDETH_NAPI dev->poll = nv_napi_poll; #endif @@ -4868,83 +5322,83 @@ static struct pci_device_id pci_tbl[] = }, { /* CK804 Ethernet Controller */ PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_8), - .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA, + .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA|DEV_HAS_STATISTICS_V1, }, { /* CK804 Ethernet Controller */ PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_9), - .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA, + .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA|DEV_HAS_STATISTICS_V1, }, { /* MCP04 Ethernet Controller */ PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_10), - .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA, + .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA|DEV_HAS_STATISTICS_V1, }, { /* MCP04 Ethernet Controller */ PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_11), - .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA, + .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA|DEV_HAS_STATISTICS_V1, }, { /* MCP51 Ethernet Controller */ PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_12), - .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL, + .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_STATISTICS_V1, }, { /* MCP51 Ethernet Controller */ PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_13), - .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL, + .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_STATISTICS_V1, }, { /* MCP55 Ethernet Controller */ PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_14), - .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA|DEV_HAS_VLAN|DEV_HAS_MSI|DEV_HAS_MSI_X|DEV_HAS_POWER_CNTRL|DEV_HAS_PAUSEFRAME_TX|DEV_HAS_STATISTICS|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT, + .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA|DEV_HAS_VLAN|DEV_HAS_MSI|DEV_HAS_MSI_X|DEV_HAS_POWER_CNTRL|DEV_HAS_PAUSEFRAME_TX|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT, }, { /* MCP55 Ethernet Controller */ PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_15), - .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA|DEV_HAS_VLAN|DEV_HAS_MSI|DEV_HAS_MSI_X|DEV_HAS_POWER_CNTRL|DEV_HAS_PAUSEFRAME_TX|DEV_HAS_STATISTICS|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT, + .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA|DEV_HAS_VLAN|DEV_HAS_MSI|DEV_HAS_MSI_X|DEV_HAS_POWER_CNTRL|DEV_HAS_PAUSEFRAME_TX|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT, }, { /* MCP61 Ethernet Controller */ PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_16), - .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX|DEV_HAS_STATISTICS|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT, + .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT, }, { /* MCP61 Ethernet Controller */ PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_17), - .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX|DEV_HAS_STATISTICS|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT, + .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT, }, { /* MCP61 Ethernet Controller */ PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_18), - .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX|DEV_HAS_STATISTICS|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT, + .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT, }, { /* MCP61 Ethernet Controller */ PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_19), - .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX|DEV_HAS_STATISTICS|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT, + .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT, }, { /* MCP65 Ethernet Controller */ PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_20), - .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX|DEV_HAS_STATISTICS|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT, + .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT, }, { /* MCP65 Ethernet Controller */ PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_21), - .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX|DEV_HAS_STATISTICS|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT, + .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT, }, { /* MCP65 Ethernet Controller */ PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_22), - .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX|DEV_HAS_STATISTICS|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT, + .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT, }, { /* MCP65 Ethernet Controller */ PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_23), - .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX|DEV_HAS_STATISTICS|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT, + .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT, }, { /* MCP67 Ethernet Controller */ PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_24), - .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX|DEV_HAS_STATISTICS|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT, + .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT, }, { /* MCP67 Ethernet Controller */ PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_25), - .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX|DEV_HAS_STATISTICS|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT, + .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT, }, { /* MCP67 Ethernet Controller */ PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_26), - .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX|DEV_HAS_STATISTICS|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT, + .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT, }, { /* MCP67 Ethernet Controller */ PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_27), - .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX|DEV_HAS_STATISTICS|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT, + .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT, }, {0,}, }; diff --git a/drivers/net/fs_enet/fs_enet-main.c b/drivers/net/fs_enet/fs_enet-main.c index 889d3a1..4a05c14 100644 --- a/drivers/net/fs_enet/fs_enet-main.c +++ b/drivers/net/fs_enet/fs_enet-main.c @@ -18,7 +18,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/net/fs_enet/fs_enet.h b/drivers/net/fs_enet/fs_enet.h index 92590d8..569be22 100644 --- a/drivers/net/fs_enet/fs_enet.h +++ b/drivers/net/fs_enet/fs_enet.h @@ -9,6 +9,7 @@ #include #include #include +#include #ifdef CONFIG_CPM1 #include diff --git a/drivers/net/fs_enet/mac-fcc.c b/drivers/net/fs_enet/mac-fcc.c index 1ff2597..8545e84 100644 --- a/drivers/net/fs_enet/mac-fcc.c +++ b/drivers/net/fs_enet/mac-fcc.c @@ -15,7 +15,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/net/fs_enet/mac-fec.c b/drivers/net/fs_enet/mac-fec.c index ff68394..cdcfb96 100644 --- a/drivers/net/fs_enet/mac-fec.c +++ b/drivers/net/fs_enet/mac-fec.c @@ -15,7 +15,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/net/fs_enet/mac-scc.c b/drivers/net/fs_enet/mac-scc.c index afd7fca..65925b5 100644 --- a/drivers/net/fs_enet/mac-scc.c +++ b/drivers/net/fs_enet/mac-scc.c @@ -15,7 +15,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/net/fs_enet/mii-bitbang.c b/drivers/net/fs_enet/mii-bitbang.c index 0b9b8b5..f914478 100644 --- a/drivers/net/fs_enet/mii-bitbang.c +++ b/drivers/net/fs_enet/mii-bitbang.c @@ -16,7 +16,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/net/fs_enet/mii-fec.c b/drivers/net/fs_enet/mii-fec.c index baaae3d..235b177 100644 --- a/drivers/net/fs_enet/mii-fec.c +++ b/drivers/net/fs_enet/mii-fec.c @@ -15,7 +15,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/net/gianfar.c b/drivers/net/gianfar.c index baa3514..1be4a84 100644 --- a/drivers/net/gianfar.c +++ b/drivers/net/gianfar.c @@ -65,7 +65,6 @@ */ #include -#include #include #include #include diff --git a/drivers/net/gianfar_ethtool.c b/drivers/net/gianfar_ethtool.c index 6d71bea..7b411c1 100644 --- a/drivers/net/gianfar_ethtool.c +++ b/drivers/net/gianfar_ethtool.c @@ -16,7 +16,6 @@ */ #include -#include #include #include #include @@ -42,8 +41,6 @@ #include #include "gianfar.h" -#define is_power_of_2(x) ((x) != 0 && (((x) & ((x) - 1)) == 0)) - extern void gfar_start(struct net_device *dev); extern int gfar_clean_rx_ring(struct net_device *dev, int rx_work_limit); diff --git a/drivers/net/gianfar_mii.c b/drivers/net/gianfar_mii.c index ff684d4..bcc6b82 100644 --- a/drivers/net/gianfar_mii.c +++ b/drivers/net/gianfar_mii.c @@ -17,7 +17,6 @@ */ #include -#include #include #include #include diff --git a/drivers/net/gianfar_sysfs.c b/drivers/net/gianfar_sysfs.c index 9dd387f..45ffb5d 100644 --- a/drivers/net/gianfar_sysfs.c +++ b/drivers/net/gianfar_sysfs.c @@ -20,7 +20,6 @@ */ #include -#include #include #include #include diff --git a/drivers/net/hamradio/bpqether.c b/drivers/net/hamradio/bpqether.c index 5b788d8..d254269 100644 --- a/drivers/net/hamradio/bpqether.c +++ b/drivers/net/hamradio/bpqether.c @@ -459,7 +459,7 @@ static int bpq_info_open(struct inode *i return seq_open(file, &bpq_seqops); } -static struct file_operations bpq_info_fops = { +static const struct file_operations bpq_info_fops = { .owner = THIS_MODULE, .open = bpq_info_open, .read = seq_read, diff --git a/drivers/net/hamradio/scc.c b/drivers/net/hamradio/scc.c index 2ce047e..6fdaad5 100644 --- a/drivers/net/hamradio/scc.c +++ b/drivers/net/hamradio/scc.c @@ -2083,7 +2083,7 @@ static int scc_net_seq_open(struct inode return seq_open(file, &scc_net_seq_ops); } -static struct file_operations scc_net_seq_fops = { +static const struct file_operations scc_net_seq_fops = { .owner = THIS_MODULE, .open = scc_net_seq_open, .read = seq_read, diff --git a/drivers/net/hamradio/yam.c b/drivers/net/hamradio/yam.c index 6d74f08..08f2711 100644 --- a/drivers/net/hamradio/yam.c +++ b/drivers/net/hamradio/yam.c @@ -804,7 +804,7 @@ static int yam_info_open(struct inode *i return seq_open(file, &yam_seqops); } -static struct file_operations yam_info_fops = { +static const struct file_operations yam_info_fops = { .owner = THIS_MODULE, .open = yam_info_open, .read = seq_read, diff --git a/drivers/net/hp100.c b/drivers/net/hp100.c index 844c136..7dc5185 100644 --- a/drivers/net/hp100.c +++ b/drivers/net/hp100.c @@ -3034,7 +3034,7 @@ #ifdef CONFIG_EISA goto out2; #endif #ifdef CONFIG_PCI - err = pci_module_init(&hp100_pci_driver); + err = pci_register_driver(&hp100_pci_driver); if (err && err != -ENODEV) goto out3; #endif diff --git a/drivers/net/ibm_emac/ibm_emac_core.c b/drivers/net/ibm_emac/ibm_emac_core.c index ffeafb2..dd8ad87 100644 --- a/drivers/net/ibm_emac/ibm_emac_core.c +++ b/drivers/net/ibm_emac/ibm_emac_core.c @@ -21,7 +21,6 @@ #include #include -#include #include #include #include diff --git a/drivers/net/ibmveth.c b/drivers/net/ibmveth.c index 99343b5..458db05 100644 --- a/drivers/net/ibmveth.c +++ b/drivers/net/ibmveth.c @@ -1156,7 +1156,7 @@ static int ibmveth_proc_open(struct inod return rc; } -static struct file_operations ibmveth_proc_fops = { +static const struct file_operations ibmveth_proc_fops = { .owner = THIS_MODULE, .open = ibmveth_proc_open, .read = seq_read, diff --git a/drivers/net/irda/ma600-sir.c b/drivers/net/irda/ma600-sir.c index ebed168..809906d 100644 --- a/drivers/net/irda/ma600-sir.c +++ b/drivers/net/irda/ma600-sir.c @@ -34,7 +34,6 @@ #include #include #include -#include #include diff --git a/drivers/net/irda/vlsi_ir.c b/drivers/net/irda/vlsi_ir.c index e2b1af6..3457e9d 100644 --- a/drivers/net/irda/vlsi_ir.c +++ b/drivers/net/irda/vlsi_ir.c @@ -385,7 +385,7 @@ static int vlsi_seq_open(struct inode *i return single_open(file, vlsi_seq_show, PDE(inode)->data); } -static struct file_operations vlsi_proc_fops = { +static const struct file_operations vlsi_proc_fops = { .owner = THIS_MODULE, .open = vlsi_seq_open, .read = seq_read, diff --git a/drivers/net/iseries_veth.c b/drivers/net/iseries_veth.c index 2194b56..0e9ba3c 100644 --- a/drivers/net/iseries_veth.c +++ b/drivers/net/iseries_veth.c @@ -1102,7 +1102,7 @@ static struct net_device * __init veth_p } kobject_init(&port->kobject); - port->kobject.parent = &dev->class_dev.kobj; + port->kobject.parent = &dev->dev.kobj; port->kobject.ktype = &veth_port_ktype; kobject_set_name(&port->kobject, "veth_port"); if (0 != kobject_add(&port->kobject)) diff --git a/drivers/net/ixgb/ixgb.h b/drivers/net/ixgb/ixgb.h index f4aba43..cf30a10 100644 --- a/drivers/net/ixgb/ixgb.h +++ b/drivers/net/ixgb/ixgb.h @@ -61,9 +61,7 @@ #include #include #include #include -#ifdef NETIF_F_TSO #include -#endif #include #include diff --git a/drivers/net/ixgb/ixgb_ethtool.c b/drivers/net/ixgb/ixgb_ethtool.c index 82c044d..d6628bd 100644 --- a/drivers/net/ixgb/ixgb_ethtool.c +++ b/drivers/net/ixgb/ixgb_ethtool.c @@ -82,10 +82,8 @@ static struct ixgb_stats ixgb_gstrings_s {"tx_restart_queue", IXGB_STAT(restart_queue) }, {"rx_long_length_errors", IXGB_STAT(stats.roc)}, {"rx_short_length_errors", IXGB_STAT(stats.ruc)}, -#ifdef NETIF_F_TSO {"tx_tcp_seg_good", IXGB_STAT(stats.tsctc)}, {"tx_tcp_seg_failed", IXGB_STAT(stats.tsctfc)}, -#endif {"rx_flow_control_xon", IXGB_STAT(stats.xonrxc)}, {"rx_flow_control_xoff", IXGB_STAT(stats.xoffrxc)}, {"tx_flow_control_xon", IXGB_STAT(stats.xontxc)}, @@ -240,7 +238,6 @@ ixgb_set_tx_csum(struct net_device *netd return 0; } -#ifdef NETIF_F_TSO static int ixgb_set_tso(struct net_device *netdev, uint32_t data) { @@ -250,7 +247,6 @@ ixgb_set_tso(struct net_device *netdev, netdev->features &= ~NETIF_F_TSO; return 0; } -#endif /* NETIF_F_TSO */ static uint32_t ixgb_get_msglevel(struct net_device *netdev) @@ -722,10 +718,8 @@ static const struct ethtool_ops ixgb_eth .set_sg = ethtool_op_set_sg, .get_msglevel = ixgb_get_msglevel, .set_msglevel = ixgb_set_msglevel, -#ifdef NETIF_F_TSO .get_tso = ethtool_op_get_tso, .set_tso = ixgb_set_tso, -#endif .get_strings = ixgb_get_strings, .phys_id = ixgb_phys_id, .get_stats_count = ixgb_get_stats_count, diff --git a/drivers/net/ixgb/ixgb_main.c b/drivers/net/ixgb/ixgb_main.c index a083a91..0c36828 100644 --- a/drivers/net/ixgb/ixgb_main.c +++ b/drivers/net/ixgb/ixgb_main.c @@ -456,9 +456,7 @@ #endif NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_RX | NETIF_F_HW_VLAN_FILTER; -#ifdef NETIF_F_TSO netdev->features |= NETIF_F_TSO; -#endif #ifdef NETIF_F_LLTX netdev->features |= NETIF_F_LLTX; #endif @@ -1176,7 +1174,6 @@ #define IXGB_TX_FLAGS_TSO 0x00000004 static int ixgb_tso(struct ixgb_adapter *adapter, struct sk_buff *skb) { -#ifdef NETIF_F_TSO struct ixgb_context_desc *context_desc; unsigned int i; uint8_t ipcss, ipcso, tucss, tucso, hdr_len; @@ -1233,7 +1230,6 @@ #ifdef NETIF_F_TSO return 1; } -#endif return 0; } @@ -1609,7 +1605,7 @@ ixgb_update_stats(struct ixgb_adapter *a struct pci_dev *pdev = adapter->pdev; /* Prevent stats update while adapter is being reset */ - if (pdev->error_state && pdev->error_state != pci_channel_io_normal) + if (pci_channel_offline(pdev)) return; if((netdev->flags & IFF_PROMISC) || (netdev->flags & IFF_ALLMULTI) || diff --git a/drivers/net/macb.c b/drivers/net/macb.c index 25b559b..a41418b 100644 --- a/drivers/net/macb.c +++ b/drivers/net/macb.c @@ -27,8 +27,6 @@ #include #include "macb.h" -#define to_net_dev(class) container_of(class, struct net_device, class_dev) - #define RX_BUFFER_SIZE 128 #define RX_RING_SIZE 512 #define RX_RING_BYTES (sizeof(struct dma_desc) * RX_RING_SIZE) @@ -945,10 +943,10 @@ static int macb_ioctl(struct net_device return ret; } -static ssize_t macb_mii_show(const struct class_device *cd, char *buf, +static ssize_t macb_mii_show(const struct device *_dev, char *buf, unsigned long addr) { - struct net_device *dev = to_net_dev(cd); + struct net_device *dev = to_net_dev(_dev); struct macb *bp = netdev_priv(dev); ssize_t ret = -EINVAL; @@ -962,11 +960,13 @@ static ssize_t macb_mii_show(const struc } #define MII_ENTRY(name, addr) \ -static ssize_t show_##name(struct class_device *cd, char *buf) \ +static ssize_t show_##name(struct device *_dev, \ + struct device_attribute *attr, \ + char *buf) \ { \ - return macb_mii_show(cd, buf, addr); \ + return macb_mii_show(_dev, buf, addr); \ } \ -static CLASS_DEVICE_ATTR(name, S_IRUGO, show_##name, NULL) +static DEVICE_ATTR(name, S_IRUGO, show_##name, NULL) MII_ENTRY(bmcr, MII_BMCR); MII_ENTRY(bmsr, MII_BMSR); @@ -977,13 +977,13 @@ MII_ENTRY(lpa, MII_LPA); MII_ENTRY(expansion, MII_EXPANSION); static struct attribute *macb_mii_attrs[] = { - &class_device_attr_bmcr.attr, - &class_device_attr_bmsr.attr, - &class_device_attr_physid1.attr, - &class_device_attr_physid2.attr, - &class_device_attr_advertise.attr, - &class_device_attr_lpa.attr, - &class_device_attr_expansion.attr, + &dev_attr_bmcr.attr, + &dev_attr_bmsr.attr, + &dev_attr_physid1.attr, + &dev_attr_physid2.attr, + &dev_attr_advertise.attr, + &dev_attr_lpa.attr, + &dev_attr_expansion.attr, NULL, }; @@ -994,17 +994,17 @@ static struct attribute_group macb_mii_g static void macb_unregister_sysfs(struct net_device *net) { - struct class_device *class_dev = &net->class_dev; + struct device *_dev = &net->dev; - sysfs_remove_group(&class_dev->kobj, &macb_mii_group); + sysfs_remove_group(&_dev->kobj, &macb_mii_group); } static int macb_register_sysfs(struct net_device *net) { - struct class_device *class_dev = &net->class_dev; + struct device *_dev = &net->dev; int ret; - ret = sysfs_create_group(&class_dev->kobj, &macb_mii_group); + ret = sysfs_create_group(&_dev->kobj, &macb_mii_group); if (ret) printk(KERN_WARNING "%s: sysfs mii attribute registration failed: %d\n", @@ -1046,6 +1046,14 @@ static int __devinit macb_probe(struct p spin_lock_init(&bp->lock); +#if defined(CONFIG_ARCH_AT91) + bp->pclk = clk_get(&pdev->dev, "macb_clk"); + if (IS_ERR(bp->pclk)) { + dev_err(&pdev->dev, "failed to get macb_clk\n"); + goto err_out_free_dev; + } + clk_enable(bp->pclk); +#else bp->pclk = clk_get(&pdev->dev, "pclk"); if (IS_ERR(bp->pclk)) { dev_err(&pdev->dev, "failed to get pclk\n"); @@ -1059,6 +1067,7 @@ static int __devinit macb_probe(struct p clk_enable(bp->pclk); clk_enable(bp->hclk); +#endif bp->regs = ioremap(regs->start, regs->end - regs->start + 1); if (!bp->regs) { @@ -1068,7 +1077,7 @@ static int __devinit macb_probe(struct p } dev->irq = platform_get_irq(pdev, 0); - err = request_irq(dev->irq, macb_interrupt, SA_SAMPLE_RANDOM, + err = request_irq(dev->irq, macb_interrupt, IRQF_SAMPLE_RANDOM, dev->name, dev); if (err) { printk(KERN_ERR @@ -1119,9 +1128,17 @@ static int __devinit macb_probe(struct p pdata = pdev->dev.platform_data; if (pdata && pdata->is_rmii) +#if defined(CONFIG_ARCH_AT91) + macb_writel(bp, USRIO, (MACB_BIT(RMII) | MACB_BIT(CLKEN)) ); +#else macb_writel(bp, USRIO, 0); +#endif else +#if defined(CONFIG_ARCH_AT91) + macb_writel(bp, USRIO, MACB_BIT(CLKEN)); +#else macb_writel(bp, USRIO, MACB_BIT(MII)); +#endif bp->tx_pending = DEF_TX_RING_PENDING; @@ -1148,9 +1165,11 @@ err_out_free_irq: err_out_iounmap: iounmap(bp->regs); err_out_disable_clocks: +#ifndef CONFIG_ARCH_AT91 clk_disable(bp->hclk); - clk_disable(bp->pclk); clk_put(bp->hclk); +#endif + clk_disable(bp->pclk); err_out_put_pclk: clk_put(bp->pclk); err_out_free_dev: @@ -1173,9 +1192,11 @@ static int __devexit macb_remove(struct unregister_netdev(dev); free_irq(dev->irq, dev); iounmap(bp->regs); +#ifndef CONFIG_ARCH_AT91 clk_disable(bp->hclk); - clk_disable(bp->pclk); clk_put(bp->hclk); +#endif + clk_disable(bp->pclk); clk_put(bp->pclk); free_netdev(dev); platform_set_drvdata(pdev, NULL); diff --git a/drivers/net/macb.h b/drivers/net/macb.h index 27bf0ae..b3bb218 100644 --- a/drivers/net/macb.h +++ b/drivers/net/macb.h @@ -200,7 +200,7 @@ #define MACB_RW_SIZE 2 #define MACB_SOF_OFFSET 30 #define MACB_SOF_SIZE 2 -/* Bitfields in USRIO */ +/* Bitfields in USRIO (AVR32) */ #define MACB_MII_OFFSET 0 #define MACB_MII_SIZE 1 #define MACB_EAM_OFFSET 1 @@ -210,6 +210,12 @@ #define MACB_TX_PAUSE_SIZE 1 #define MACB_TX_PAUSE_ZERO_OFFSET 3 #define MACB_TX_PAUSE_ZERO_SIZE 1 +/* Bitfields in USRIO (AT91) */ +#define MACB_RMII_OFFSET 0 +#define MACB_RMII_SIZE 1 +#define MACB_CLKEN_OFFSET 1 +#define MACB_CLKEN_SIZE 1 + /* Bitfields in WOL */ #define MACB_IP_OFFSET 0 #define MACB_IP_SIZE 16 diff --git a/drivers/net/mace.c b/drivers/net/mace.c index 2907cfb..9ec24f0 100644 --- a/drivers/net/mace.c +++ b/drivers/net/mace.c @@ -15,6 +15,7 @@ #include #include #include #include +#include #include #include #include @@ -74,7 +75,6 @@ struct mace_data { #define PRIV_BYTES (sizeof(struct mace_data) \ + (N_RX_RING + NCMDS_TX * N_TX_RING + 3) * sizeof(struct dbdma_cmd)) -static int bitrev(int); static int mace_open(struct net_device *dev); static int mace_close(struct net_device *dev); static int mace_xmit_start(struct sk_buff *skb, struct net_device *dev); @@ -96,18 +96,6 @@ static void __mace_set_address(struct ne */ static unsigned char *dummy_buf; -/* Bit-reverse one byte of an ethernet hardware address. */ -static inline int -bitrev(int b) -{ - int d = 0, i; - - for (i = 0; i < 8; ++i, b >>= 1) - d = (d << 1) | (b & 1); - return d; -} - - static int __devinit mace_probe(struct macio_dev *mdev, const struct of_device_id *match) { struct device_node *mace = macio_get_of_node(mdev); @@ -173,7 +161,7 @@ static int __devinit mace_probe(struct m rev = addr[0] == 0 && addr[1] == 0xA0; for (j = 0; j < 6; ++j) { - dev->dev_addr[j] = rev? bitrev(addr[j]): addr[j]; + dev->dev_addr[j] = rev ? bitrev8(addr[j]): addr[j]; } mp->chipid = (in_8(&mp->mace->chipid_hi) << 8) | in_8(&mp->mace->chipid_lo); diff --git a/drivers/net/macmace.c b/drivers/net/macmace.c index 464e4a6..5d541e8 100644 --- a/drivers/net/macmace.c +++ b/drivers/net/macmace.c @@ -22,6 +22,7 @@ #include #include #include #include +#include #include #include #include @@ -81,19 +82,6 @@ static irqreturn_t mace_interrupt(int ir static irqreturn_t mace_dma_intr(int irq, void *dev_id); static void mace_tx_timeout(struct net_device *dev); -/* Bit-reverse one byte of an ethernet hardware address. */ - -static int bitrev(int b) -{ - int d = 0, i; - - for (i = 0; i < 8; ++i, b >>= 1) { - d = (d << 1) | (b & 1); - } - - return d; -} - /* * Load a receive DMA channel with a base address and ring length */ @@ -219,12 +207,12 @@ struct net_device *mace_probe(int unit) addr = (void *)MACE_PROM; for (j = 0; j < 6; ++j) { - u8 v=bitrev(addr[j<<4]); + u8 v = bitrev8(addr[j<<4]); checksum ^= v; dev->dev_addr[j] = v; } for (; j < 8; ++j) { - checksum ^= bitrev(addr[j<<4]); + checksum ^= bitrev8(addr[j<<4]); } if (checksum != 0xFF) { diff --git a/drivers/net/macsonic.c b/drivers/net/macsonic.c index 393d995..8ca57a0 100644 --- a/drivers/net/macsonic.c +++ b/drivers/net/macsonic.c @@ -49,6 +49,7 @@ #include #include #include #include +#include #include #include @@ -121,16 +122,12 @@ #define SONIC_READ_PROM(addr) nubus_read * For reversing the PROM address */ -static unsigned char nibbletab[] = {0, 8, 4, 12, 2, 10, 6, 14, - 1, 9, 5, 13, 3, 11, 7, 15}; - static inline void bit_reverse_addr(unsigned char addr[6]) { int i; for(i = 0; i < 6; i++) - addr[i] = ((nibbletab[addr[i] & 0xf] << 4) | - nibbletab[(addr[i] >> 4) &0xf]); + addr[i] = bitrev8(addr[i]); } int __init macsonic_init(struct net_device* dev) diff --git a/drivers/net/meth.c b/drivers/net/meth.c index e1d97cd..d38b7c7 100644 --- a/drivers/net/meth.c +++ b/drivers/net/meth.c @@ -11,7 +11,6 @@ #include #include -#include #include /* printk() */ #include #include diff --git a/drivers/net/mipsnet.c b/drivers/net/mipsnet.c index c946998..f42b9e2 100644 --- a/drivers/net/mipsnet.c +++ b/drivers/net/mipsnet.c @@ -10,7 +10,6 @@ #include #include #include #include -#include #include #include #include diff --git a/drivers/net/mv643xx_eth.c b/drivers/net/mv643xx_eth.c index b3bf864..d98e53e 100644 --- a/drivers/net/mv643xx_eth.c +++ b/drivers/net/mv643xx_eth.c @@ -2780,7 +2780,6 @@ static const struct ethtool_ops mv643xx_ .get_link = mv643xx_eth_get_link, .get_sg = ethtool_op_get_sg, .set_sg = ethtool_op_set_sg, - .get_strings = mv643xx_get_strings, .get_stats_count = mv643xx_get_stats_count, .get_ethtool_stats = mv643xx_get_ethtool_stats, .get_strings = mv643xx_get_strings, diff --git a/drivers/net/myri10ge/myri10ge.c b/drivers/net/myri10ge/myri10ge.c index 61cbd4a..030924f 100644 --- a/drivers/net/myri10ge/myri10ge.c +++ b/drivers/net/myri10ge/myri10ge.c @@ -1412,10 +1412,8 @@ static const struct ethtool_ops myri10ge .set_tx_csum = ethtool_op_set_tx_hw_csum, .get_sg = ethtool_op_get_sg, .set_sg = ethtool_op_set_sg, -#ifdef NETIF_F_TSO .get_tso = ethtool_op_get_tso, .set_tso = ethtool_op_set_tso, -#endif .get_strings = myri10ge_get_strings, .get_stats_count = myri10ge_get_stats_count, .get_ethtool_stats = myri10ge_get_ethtool_stats, @@ -1975,13 +1973,11 @@ again: mss = 0; max_segments = MXGEFW_MAX_SEND_DESC; -#ifdef NETIF_F_TSO if (skb->len > (dev->mtu + ETH_HLEN)) { mss = skb_shinfo(skb)->gso_size; if (mss != 0) max_segments = MYRI10GE_MAX_SEND_DESC_TSO; } -#endif /*NETIF_F_TSO */ if ((unlikely(avail < max_segments))) { /* we are out of transmit resources */ @@ -2013,7 +2009,6 @@ #endif /*NETIF_F_TSO */ cum_len = 0; -#ifdef NETIF_F_TSO if (mss) { /* TSO */ /* this removes any CKSUM flag from before */ flags = (MXGEFW_FLAGS_TSO_HDR | MXGEFW_FLAGS_FIRST); @@ -2029,7 +2024,6 @@ #ifdef NETIF_F_TSO * the checksum by parsing the header. */ pseudo_hdr_offset = mss; } else -#endif /*NETIF_F_TSO */ /* Mark small packets, and pad out tiny packets */ if (skb->len <= MXGEFW_SEND_SMALL_SIZE) { flags |= MXGEFW_FLAGS_SMALL; @@ -2097,7 +2091,6 @@ #endif /*NETIF_F_TSO */ seglen = len; flags_next = flags & ~MXGEFW_FLAGS_FIRST; cum_len_next = cum_len + seglen; -#ifdef NETIF_F_TSO if (mss) { /* TSO */ (req - rdma_count)->rdma_count = rdma_count + 1; @@ -2124,7 +2117,6 @@ #ifdef NETIF_F_TSO (small * MXGEFW_FLAGS_SMALL); } } -#endif /* NETIF_F_TSO */ req->addr_high = high_swapped; req->addr_low = htonl(low); req->pseudo_hdr_offset = htons(pseudo_hdr_offset); @@ -2161,14 +2153,12 @@ #endif /* NETIF_F_TSO */ } (req - rdma_count)->rdma_count = rdma_count; -#ifdef NETIF_F_TSO if (mss) do { req--; req->flags |= MXGEFW_FLAGS_TSO_LAST; } while (!(req->flags & (MXGEFW_FLAGS_TSO_CHOP | MXGEFW_FLAGS_FIRST))); -#endif idx = ((count - 1) + tx->req) & tx->mask; tx->info[idx].last = 1; if (tx->wc_fifo == NULL) diff --git a/drivers/net/netxen/netxen_nic.h b/drivers/net/netxen/netxen_nic.h index e8598b8..3f3896e 100644 --- a/drivers/net/netxen/netxen_nic.h +++ b/drivers/net/netxen/netxen_nic.h @@ -63,11 +63,14 @@ #include #include "netxen_nic_hw.h" -#define NETXEN_NIC_BUILD_NO "2" #define _NETXEN_NIC_LINUX_MAJOR 3 #define _NETXEN_NIC_LINUX_MINOR 3 #define _NETXEN_NIC_LINUX_SUBVERSION 3 -#define NETXEN_NIC_LINUX_VERSIONID "3.3.3" "-" NETXEN_NIC_BUILD_NO +#define NETXEN_NIC_LINUX_VERSIONID "3.3.3" + +#define NUM_FLASH_SECTORS (64) +#define FLASH_SECTOR_SIZE (64 * 1024) +#define FLASH_TOTAL_SIZE (NUM_FLASH_SECTORS * FLASH_SECTOR_SIZE) #define RCV_DESC_RINGSIZE \ (sizeof(struct rcv_desc) * adapter->max_rx_desc_count) @@ -85,6 +88,7 @@ #define NETXEN_NETDEV_STATUS 0x1 #define NETXEN_RCV_PRODUCER_OFFSET 0 #define NETXEN_RCV_PEG_DB_ID 2 #define NETXEN_HOST_DUMMY_DMA_SIZE 1024 +#define FLASH_SUCCESS 0 #define ADDR_IN_WINDOW1(off) \ ((off > NETXEN_CRB_PCIX_HOST2) && (off < NETXEN_CRB_MAX)) ? 1 : 0 @@ -1028,6 +1032,15 @@ void netxen_phantom_init(struct netxen_a void netxen_load_firmware(struct netxen_adapter *adapter); int netxen_pinit_from_rom(struct netxen_adapter *adapter, int verbose); int netxen_rom_fast_read(struct netxen_adapter *adapter, int addr, int *valp); +int netxen_rom_fast_read_words(struct netxen_adapter *adapter, int addr, + u8 *bytes, size_t size); +int netxen_rom_fast_write_words(struct netxen_adapter *adapter, int addr, + u8 *bytes, size_t size); +int netxen_flash_unlock(struct netxen_adapter *adapter); +int netxen_backup_crbinit(struct netxen_adapter *adapter); +int netxen_flash_erase_secondary(struct netxen_adapter *adapter); +int netxen_flash_erase_primary(struct netxen_adapter *adapter); + int netxen_rom_fast_write(struct netxen_adapter *adapter, int addr, int data); int netxen_rom_se(struct netxen_adapter *adapter, int addr); int netxen_do_rom_se(struct netxen_adapter *adapter, int addr); diff --git a/drivers/net/netxen/netxen_nic_ethtool.c b/drivers/net/netxen/netxen_nic_ethtool.c index c381d77..cc0efe2 100644 --- a/drivers/net/netxen/netxen_nic_ethtool.c +++ b/drivers/net/netxen/netxen_nic_ethtool.c @@ -32,6 +32,7 @@ */ #include +#include #include #include #include @@ -94,17 +95,7 @@ #define NETXEN_MAX_EEPROM_LEN 1024 static int netxen_nic_get_eeprom_len(struct net_device *dev) { - struct netxen_port *port = netdev_priv(dev); - struct netxen_adapter *adapter = port->adapter; - int n; - - if ((netxen_rom_fast_read(adapter, 0, &n) == 0) - && (n & NETXEN_ROM_ROUNDUP)) { - n &= ~NETXEN_ROM_ROUNDUP; - if (n < NETXEN_MAX_EEPROM_LEN) - return n; - } - return 0; + return FLASH_TOTAL_SIZE; } static void @@ -440,18 +431,92 @@ netxen_nic_get_eeprom(struct net_device struct netxen_port *port = netdev_priv(dev); struct netxen_adapter *adapter = port->adapter; int offset; + int ret; if (eeprom->len == 0) return -EINVAL; eeprom->magic = (port->pdev)->vendor | ((port->pdev)->device << 16); - for (offset = 0; offset < eeprom->len; offset++) - if (netxen_rom_fast_read - (adapter, (8 * offset) + 8, (int *)eeprom->data) == -1) - return -EIO; + offset = eeprom->offset; + + ret = netxen_rom_fast_read_words(adapter, offset, bytes, + eeprom->len); + if (ret < 0) + return ret; + return 0; } +static int +netxen_nic_set_eeprom(struct net_device *dev, struct ethtool_eeprom *eeprom, + u8 * bytes) +{ + struct netxen_port *port = netdev_priv(dev); + struct netxen_adapter *adapter = port->adapter; + int offset = eeprom->offset; + static int flash_start; + static int ready_to_flash; + int ret; + + if (flash_start == 0) { + ret = netxen_flash_unlock(adapter); + if (ret < 0) { + printk(KERN_ERR "%s: Flash unlock failed.\n", + netxen_nic_driver_name); + return ret; + } + printk(KERN_INFO "%s: flash unlocked. \n", + netxen_nic_driver_name); + ret = netxen_flash_erase_secondary(adapter); + if (ret != FLASH_SUCCESS) { + printk(KERN_ERR "%s: Flash erase failed.\n", + netxen_nic_driver_name); + return ret; + } + printk(KERN_INFO "%s: secondary flash erased successfully.\n", + netxen_nic_driver_name); + flash_start = 1; + return 0; + } + + if (offset == BOOTLD_START) { + ret = netxen_flash_erase_primary(adapter); + if (ret != FLASH_SUCCESS) { + printk(KERN_ERR "%s: Flash erase failed.\n", + netxen_nic_driver_name); + return ret; + } + + ret = netxen_rom_se(adapter, USER_START); + if (ret != FLASH_SUCCESS) + return ret; + ret = netxen_rom_se(adapter, FIXED_START); + if (ret != FLASH_SUCCESS) + return ret; + + printk(KERN_INFO "%s: primary flash erased successfully\n", + netxen_nic_driver_name); + + ret = netxen_backup_crbinit(adapter); + if (ret != FLASH_SUCCESS) { + printk(KERN_ERR "%s: CRBinit backup failed.\n", + netxen_nic_driver_name); + return ret; + } + printk(KERN_INFO "%s: CRBinit backup done.\n", + netxen_nic_driver_name); + ready_to_flash = 1; + } + + if (!ready_to_flash) { + printk(KERN_ERR "%s: Invalid write sequence, returning...\n", + netxen_nic_driver_name); + return -EINVAL; + } + + return netxen_rom_fast_write_words(adapter, offset, bytes, eeprom->len); +} + static void netxen_nic_get_ringparam(struct net_device *dev, struct ethtool_ringparam *ring) { @@ -721,6 +786,7 @@ struct ethtool_ops netxen_nic_ethtool_op .get_link = netxen_nic_get_link, .get_eeprom_len = netxen_nic_get_eeprom_len, .get_eeprom = netxen_nic_get_eeprom, + .set_eeprom = netxen_nic_set_eeprom, .get_ringparam = netxen_nic_get_ringparam, .get_pauseparam = netxen_nic_get_pauseparam, .set_pauseparam = netxen_nic_set_pauseparam, diff --git a/drivers/net/netxen/netxen_nic_init.c b/drivers/net/netxen/netxen_nic_init.c index 973af96..f7bb8c9 100644 --- a/drivers/net/netxen/netxen_nic_init.c +++ b/drivers/net/netxen/netxen_nic_init.c @@ -110,6 +110,7 @@ static void crb_addr_transform_setup(voi crb_addr_transform(CAM); crb_addr_transform(C2C1); crb_addr_transform(C2C0); + crb_addr_transform(SMB); } int netxen_init_firmware(struct netxen_adapter *adapter) @@ -276,6 +277,7 @@ unsigned long netxen_decode_crb_addr(uns static long rom_max_timeout = 10000; static long rom_lock_timeout = 1000000; +static long rom_write_timeout = 700; static inline int rom_lock(struct netxen_adapter *adapter) { @@ -404,7 +406,7 @@ do_rom_fast_read(struct netxen_adapter * { netxen_nic_reg_write(adapter, NETXEN_ROMUSB_ROM_ADDRESS, addr); netxen_nic_reg_write(adapter, NETXEN_ROMUSB_ROM_ABYTE_CNT, 3); - udelay(100); /* prevent bursting on CRB */ + udelay(70); /* prevent bursting on CRB */ netxen_nic_reg_write(adapter, NETXEN_ROMUSB_ROM_DUMMY_BYTE_CNT, 0); netxen_nic_reg_write(adapter, NETXEN_ROMUSB_ROM_INSTR_OPCODE, 0xb); if (netxen_wait_rom_done(adapter)) { @@ -413,13 +415,46 @@ do_rom_fast_read(struct netxen_adapter * } /* reset abyte_cnt and dummy_byte_cnt */ netxen_nic_reg_write(adapter, NETXEN_ROMUSB_ROM_ABYTE_CNT, 0); - udelay(100); /* prevent bursting on CRB */ + udelay(70); /* prevent bursting on CRB */ netxen_nic_reg_write(adapter, NETXEN_ROMUSB_ROM_DUMMY_BYTE_CNT, 0); *valp = netxen_nic_reg_read(adapter, NETXEN_ROMUSB_ROM_RDATA); return 0; } +static inline int +do_rom_fast_read_words(struct netxen_adapter *adapter, int addr, + u8 *bytes, size_t size) +{ + int addridx; + int ret = 0; + + for (addridx = addr; addridx < (addr + size); addridx += 4) { + ret = do_rom_fast_read(adapter, addridx, (int *)bytes); + if (ret != 0) + break; + bytes += 4; + } + + return ret; +} + +int +netxen_rom_fast_read_words(struct netxen_adapter *adapter, int addr, + u8 *bytes, size_t size) +{ + int ret; + + ret = rom_lock(adapter); + if (ret < 0) + return ret; + + ret = do_rom_fast_read_words(adapter, addr, bytes, size); + + netxen_rom_unlock(adapter); + return ret; +} + int netxen_rom_fast_read(struct netxen_adapter *adapter, int addr, int *valp) { int ret; @@ -443,6 +478,152 @@ int netxen_rom_fast_write(struct netxen_ netxen_rom_unlock(adapter); return ret; } + +static inline int do_rom_fast_write_words(struct netxen_adapter *adapter, + int addr, u8 *bytes, size_t size) +{ + int addridx = addr; + int ret = 0; + + while (addridx < (addr + size)) { + int last_attempt = 0; + int timeout = 0; + int data; + + data = *(u32*)bytes; + + ret = do_rom_fast_write(adapter, addridx, data); + if (ret < 0) + return ret; + + while(1) { + int data1; + + do_rom_fast_read(adapter, addridx, &data1); + if (data1 == data) + break; + + if (timeout++ >= rom_write_timeout) { + if (last_attempt++ < 4) { + ret = do_rom_fast_write(adapter, + addridx, data); + if (ret < 0) + return ret; + } + else { + printk(KERN_INFO "Data write did not " + "succeed at address 0x%x\n", addridx); + break; + } + } + } + + bytes += 4; + addridx += 4; + } + + return ret; +} + +int netxen_rom_fast_write_words(struct netxen_adapter *adapter, int addr, + u8 *bytes, size_t size) +{ + int ret = 0; + + ret = rom_lock(adapter); + if (ret < 0) + return ret; + + ret = do_rom_fast_write_words(adapter, addr, bytes, size); + netxen_rom_unlock(adapter); + + return ret; +} + +int netxen_rom_wrsr(struct netxen_adapter *adapter, int data) +{ + int ret; + + ret = netxen_rom_wren(adapter); + if (ret < 0) + return ret; + + netxen_crb_writelit_adapter(adapter, NETXEN_ROMUSB_ROM_WDATA, data); + netxen_crb_writelit_adapter(adapter, + NETXEN_ROMUSB_ROM_INSTR_OPCODE, 0x1); + + ret = netxen_wait_rom_done(adapter); + if (ret < 0) + return ret; + + return netxen_rom_wip_poll(adapter); +} + +int netxen_rom_rdsr(struct netxen_adapter *adapter) +{ + int ret; + + ret = rom_lock(adapter); + if (ret < 0) + return ret; + + ret = netxen_do_rom_rdsr(adapter); + netxen_rom_unlock(adapter); + return ret; +} + +int netxen_backup_crbinit(struct netxen_adapter *adapter) +{ + int ret = FLASH_SUCCESS; + int val; + char *buffer = kmalloc(FLASH_SECTOR_SIZE, GFP_KERNEL); + + if (!buffer) + return -ENOMEM; + /* unlock sector 63 */ + val = netxen_rom_rdsr(adapter); + val = val & 0xe3; + ret = netxen_rom_wrsr(adapter, val); + if (ret != FLASH_SUCCESS) + goto out_kfree; + + ret = netxen_rom_wip_poll(adapter); + if (ret != FLASH_SUCCESS) + goto out_kfree; + + /* copy sector 0 to sector 63 */ + ret = netxen_rom_fast_read_words(adapter, CRBINIT_START, + buffer, FLASH_SECTOR_SIZE); + if (ret != FLASH_SUCCESS) + goto out_kfree; + + ret = netxen_rom_fast_write_words(adapter, FIXED_START, + buffer, FLASH_SECTOR_SIZE); + if (ret != FLASH_SUCCESS) + goto out_kfree; + + /* lock sector 63 */ + val = netxen_rom_rdsr(adapter); + if (!(val & 0x8)) { + val |= (0x1 << 2); + /* lock sector 63 */ + if (netxen_rom_wrsr(adapter, val) == 0) { + ret = netxen_rom_wip_poll(adapter); + if (ret != FLASH_SUCCESS) + goto out_kfree; + + /* lock SR writes */ + ret = netxen_rom_wip_poll(adapter); + if (ret != FLASH_SUCCESS) + goto out_kfree; + } + } + +out_kfree: + kfree(buffer); + return ret; +} + int netxen_do_rom_se(struct netxen_adapter *adapter, int addr) { netxen_rom_wren(adapter); @@ -457,6 +638,27 @@ int netxen_do_rom_se(struct netxen_adapt return netxen_rom_wip_poll(adapter); } +void check_erased_flash(struct netxen_adapter *adapter, int addr) +{ + int i; + int val; + int count = 0, erased_errors = 0; + int range; + + range = (addr == USER_START) ? FIXED_START : addr + FLASH_SECTOR_SIZE; + + for (i = addr; i < range; i += 4) { + netxen_rom_fast_read(adapter, i, &val); + if (val != 0xffffffff) + erased_errors++; + count++; + } + + if (erased_errors) + printk(KERN_INFO "0x%x out of 0x%x words fail to be erased " + "for sector address: %x\n", erased_errors, count, addr); +} + int netxen_rom_se(struct netxen_adapter *adapter, int addr) { int ret = 0; @@ -465,6 +667,68 @@ int netxen_rom_se(struct netxen_adapter } ret = netxen_do_rom_se(adapter, addr); netxen_rom_unlock(adapter); + msleep(30); + check_erased_flash(adapter, addr); + + return ret; +} + +int +netxen_flash_erase_sections(struct netxen_adapter *adapter, int start, int end) +{ + int ret = FLASH_SUCCESS; + int i; + + for (i = start; i < end; i++) { + ret = netxen_rom_se(adapter, i * FLASH_SECTOR_SIZE); + if (ret) + break; + ret = netxen_rom_wip_poll(adapter); + if (ret < 0) + return ret; + } + + return ret; +} + +int +netxen_flash_erase_secondary(struct netxen_adapter *adapter) +{ + int ret = FLASH_SUCCESS; + int start, end; + + start = SECONDARY_START / FLASH_SECTOR_SIZE; + end = USER_START / FLASH_SECTOR_SIZE; + ret = netxen_flash_erase_sections(adapter, start, end); + + return ret; +} + +int +netxen_flash_erase_primary(struct netxen_adapter *adapter) +{ + int ret = FLASH_SUCCESS; + int start, end; + + start = PRIMARY_START / FLASH_SECTOR_SIZE; + end = SECONDARY_START / FLASH_SECTOR_SIZE; + ret = netxen_flash_erase_sections(adapter, start, end); + + return ret; +} + +int netxen_flash_unlock(struct netxen_adapter *adapter) +{ + int ret = 0; + + ret = netxen_rom_wrsr(adapter, 0); + if (ret < 0) + return ret; + + ret = netxen_rom_wren(adapter); + if (ret < 0) + return ret; + return ret; } @@ -543,9 +807,13 @@ int netxen_pinit_from_rom(struct netxen_ } for (i = 0; i < n; i++) { - off = - netxen_decode_crb_addr((unsigned long)buf[i].addr) + - NETXEN_PCI_CRBSPACE; + off = netxen_decode_crb_addr((unsigned long)buf[i].addr); + if (off == NETXEN_ADDR_ERROR) { + printk(KERN_ERR"CRB init value out of range %lx\n", + buf[i].addr); + continue; + } + off += NETXEN_PCI_CRBSPACE; /* skipping cold reboot MAGIC */ if (off == NETXEN_CAM_RAM(0x1fc)) continue; @@ -662,6 +930,7 @@ void netxen_phantom_init(struct netxen_a int loops = 0; if (!pegtune_val) { + val = readl(NETXEN_CRB_NORMALIZE(adapter, CRB_CMDPEG_STATE)); while (val != PHAN_INITIALIZE_COMPLETE && loops < 200000) { udelay(100); schedule(); diff --git a/drivers/net/netxen/netxen_nic_main.c b/drivers/net/netxen/netxen_nic_main.c index 69c1b9d..36ba6a1 100644 --- a/drivers/net/netxen/netxen_nic_main.c +++ b/drivers/net/netxen/netxen_nic_main.c @@ -619,8 +619,8 @@ static int netxen_nic_open(struct net_de } adapter->irq = adapter->ahw.pdev->irq; err = request_irq(adapter->ahw.pdev->irq, &netxen_intr, - SA_SHIRQ | SA_SAMPLE_RANDOM, netdev->name, - adapter); + IRQF_SHARED | IRQF_SAMPLE_RANDOM, + netdev->name, adapter); if (err) { printk(KERN_ERR "request_irq failed with: %d\n", err); netxen_free_hw_resources(adapter); diff --git a/drivers/net/oaknet.c b/drivers/net/oaknet.c deleted file mode 100644 index 702e3e9..0000000 --- a/drivers/net/oaknet.c +++ /dev/null @@ -1,666 +0,0 @@ -/* - * - * Copyright (c) 1999-2000 Grant Erickson - * - * Module name: oaknet.c - * - * Description: - * Driver for the National Semiconductor DP83902AV Ethernet controller - * on-board the IBM PowerPC "Oak" evaluation board. Adapted from the - * various other 8390 drivers written by Donald Becker and Paul Gortmaker. - * - * Additional inspiration from the "tcd8390.c" driver from TiVo, Inc. - * and "enetLib.c" from IBM. - * - */ - -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -#include "8390.h" - - -/* Preprocessor Defines */ - -#if !defined(TRUE) || TRUE != 1 -#define TRUE 1 -#endif - -#if !defined(FALSE) || FALSE != 0 -#define FALSE 0 -#endif - -#define OAKNET_START_PG 0x20 /* First page of TX buffer */ -#define OAKNET_STOP_PG 0x40 /* Last pagge +1 of RX ring */ - -#define OAKNET_WAIT (2 * HZ / 100) /* 20 ms */ - -/* Experimenting with some fixes for a broken driver... */ - -#define OAKNET_DISINT -#define OAKNET_HEADCHECK -#define OAKNET_RWFIX - - -/* Global Variables */ - -static const char *name = "National DP83902AV"; - -static struct net_device *oaknet_devs; - - -/* Function Prototypes */ - -static int oaknet_open(struct net_device *dev); -static int oaknet_close(struct net_device *dev); - -static void oaknet_reset_8390(struct net_device *dev); -static void oaknet_get_8390_hdr(struct net_device *dev, - struct e8390_pkt_hdr *hdr, int ring_page); -static void oaknet_block_input(struct net_device *dev, int count, - struct sk_buff *skb, int ring_offset); -static void oaknet_block_output(struct net_device *dev, int count, - const unsigned char *buf, int start_page); - -static void oaknet_dma_error(struct net_device *dev, const char *name); - - -/* - * int oaknet_init() - * - * Description: - * This routine performs all the necessary platform-specific initiali- - * zation and set-up for the IBM "Oak" evaluation board's National - * Semiconductor DP83902AV "ST-NIC" Ethernet controller. - * - * Input(s): - * N/A - * - * Output(s): - * N/A - * - * Returns: - * 0 if OK, otherwise system error number on error. - * - */ -static int __init oaknet_init(void) -{ - register int i; - int reg0, regd; - int ret = -ENOMEM; - struct net_device *dev; -#if 0 - unsigned long ioaddr = OAKNET_IO_BASE; -#else - unsigned long ioaddr = ioremap(OAKNET_IO_BASE, OAKNET_IO_SIZE); -#endif - bd_t *bip = (bd_t *)__res; - - if (!ioaddr) - return -ENOMEM; - - dev = alloc_ei_netdev(); - if (!dev) - goto out_unmap; - - ret = -EBUSY; - if (!request_region(OAKNET_IO_BASE, OAKNET_IO_SIZE, name)) - goto out_dev; - - /* Quick register check to see if the device is really there. */ - - ret = -ENODEV; - if ((reg0 = ei_ibp(ioaddr)) == 0xFF) - goto out_region; - - /* - * That worked. Now a more thorough check, using the multicast - * address registers, that the device is definitely out there - * and semi-functional. - */ - - ei_obp(E8390_NODMA + E8390_PAGE1 + E8390_STOP, ioaddr + E8390_CMD); - regd = ei_ibp(ioaddr + 0x0D); - ei_obp(0xFF, ioaddr + 0x0D); - ei_obp(E8390_NODMA + E8390_PAGE0, ioaddr + E8390_CMD); - ei_ibp(ioaddr + EN0_COUNTER0); - - /* It's no good. Fix things back up and leave. */ - - ret = -ENODEV; - if (ei_ibp(ioaddr + EN0_COUNTER0) != 0) { - ei_obp(reg0, ioaddr); - ei_obp(regd, ioaddr + 0x0D); - goto out_region; - } - - SET_MODULE_OWNER(dev); - - /* - * This controller is on an embedded board, so the base address - * and interrupt assignments are pre-assigned and unchageable. - */ - - dev->base_addr = ioaddr; - dev->irq = OAKNET_INT; - - /* - * Disable all chip interrupts for now and ACK all pending - * interrupts. - */ - - ei_obp(0x0, ioaddr + EN0_IMR); - ei_obp(0xFF, ioaddr + EN0_ISR); - - /* Attempt to get the interrupt line */ - - ret = -EAGAIN; - if (request_irq(dev->irq, ei_interrupt, 0, name, dev)) { - printk("%s: unable to request interrupt %d.\n", - name, dev->irq); - goto out_region; - } - - /* Tell the world about what and where we've found. */ - - printk("%s: %s at", dev->name, name); - for (i = 0; i < ETHER_ADDR_LEN; ++i) { - dev->dev_addr[i] = bip->bi_enetaddr[i]; - printk("%c%.2x", (i ? ':' : ' '), dev->dev_addr[i]); - } - printk(", found at %#lx, using IRQ %d.\n", dev->base_addr, dev->irq); - - /* Set up some required driver fields and then we're done. */ - - ei_status.name = name; - ei_status.word16 = FALSE; - ei_status.tx_start_page = OAKNET_START_PG; - ei_status.rx_start_page = OAKNET_START_PG + TX_PAGES; - ei_status.stop_page = OAKNET_STOP_PG; - - ei_status.reset_8390 = &oaknet_reset_8390; - ei_status.block_input = &oaknet_block_input; - ei_status.block_output = &oaknet_block_output; - ei_status.get_8390_hdr = &oaknet_get_8390_hdr; - - dev->open = oaknet_open; - dev->stop = oaknet_close; -#ifdef CONFIG_NET_POLL_CONTROLLER - dev->poll_controller = ei_poll; -#endif - - NS8390_init(dev, FALSE); - ret = register_netdev(dev); - if (ret) - goto out_irq; - - oaknet_devs = dev; - return 0; - -out_irq; - free_irq(dev->irq, dev); -out_region: - release_region(OAKNET_IO_BASE, OAKNET_IO_SIZE); -out_dev: - free_netdev(dev); -out_unmap: - iounmap(ioaddr); - return ret; -} - -/* - * static int oaknet_open() - * - * Description: - * This routine is a modest wrapper around ei_open, the 8390-generic, - * driver open routine. This just increments the module usage count - * and passes along the status from ei_open. - * - * Input(s): - * *dev - Pointer to the device structure for this driver. - * - * Output(s): - * *dev - Pointer to the device structure for this driver, potentially - * modified by ei_open. - * - * Returns: - * 0 if OK, otherwise < 0 on error. - * - */ -static int -oaknet_open(struct net_device *dev) -{ - int status = ei_open(dev); - return (status); -} - -/* - * static int oaknet_close() - * - * Description: - * This routine is a modest wrapper around ei_close, the 8390-generic, - * driver close routine. This just decrements the module usage count - * and passes along the status from ei_close. - * - * Input(s): - * *dev - Pointer to the device structure for this driver. - * - * Output(s): - * *dev - Pointer to the device structure for this driver, potentially - * modified by ei_close. - * - * Returns: - * 0 if OK, otherwise < 0 on error. - * - */ -static int -oaknet_close(struct net_device *dev) -{ - int status = ei_close(dev); - return (status); -} - -/* - * static void oaknet_reset_8390() - * - * Description: - * This routine resets the DP83902 chip. - * - * Input(s): - * *dev - Pointer to the device structure for this driver. - * - * Output(s): - * N/A - * - * Returns: - * N/A - * - */ -static void -oaknet_reset_8390(struct net_device *dev) -{ - int base = E8390_BASE; - - /* - * We have no provision of reseting the controller as is done - * in other drivers, such as "ne.c". However, the following - * seems to work well enough in the TiVo driver. - */ - - printk("Resetting %s...\n", dev->name); - ei_obp(E8390_STOP | E8390_NODMA | E8390_PAGE0, base + E8390_CMD); - ei_status.txing = 0; - ei_status.dmaing = 0; -} - -/* - * static void oaknet_get_8390_hdr() - * - * Description: - * This routine grabs the 8390-specific header. It's similar to the - * block input routine, but we don't need to be concerned with ring wrap - * as the header will be at the start of a page, so we optimize accordingly. - * - * Input(s): - * *dev - Pointer to the device structure for this driver. - * *hdr - Pointer to storage for the 8390-specific packet header. - * ring_page - ? - * - * Output(s): - * *hdr - Pointer to the 8390-specific packet header for the just- - * received frame. - * - * Returns: - * N/A - * - */ -static void -oaknet_get_8390_hdr(struct net_device *dev, struct e8390_pkt_hdr *hdr, - int ring_page) -{ - int base = dev->base_addr; - - /* - * This should NOT happen. If it does, it is the LAST thing you'll - * see. - */ - - if (ei_status.dmaing) { - oaknet_dma_error(dev, "oaknet_get_8390_hdr"); - return; - } - - ei_status.dmaing |= 0x01; - outb_p(E8390_NODMA + E8390_PAGE0 + E8390_START, base + OAKNET_CMD); - outb_p(sizeof(struct e8390_pkt_hdr), base + EN0_RCNTLO); - outb_p(0, base + EN0_RCNTHI); - outb_p(0, base + EN0_RSARLO); /* On page boundary */ - outb_p(ring_page, base + EN0_RSARHI); - outb_p(E8390_RREAD + E8390_START, base + OAKNET_CMD); - - if (ei_status.word16) - insw(base + OAKNET_DATA, hdr, - sizeof(struct e8390_pkt_hdr) >> 1); - else - insb(base + OAKNET_DATA, hdr, - sizeof(struct e8390_pkt_hdr)); - - /* Byte-swap the packet byte count */ - - hdr->count = le16_to_cpu(hdr->count); - - outb_p(ENISR_RDC, base + EN0_ISR); /* ACK Remote DMA interrupt */ - ei_status.dmaing &= ~0x01; -} - -/* - * XXX - Document me. - */ -static void -oaknet_block_input(struct net_device *dev, int count, struct sk_buff *skb, - int ring_offset) -{ - int base = OAKNET_BASE; - char *buf = skb->data; - - /* - * This should NOT happen. If it does, it is the LAST thing you'll - * see. - */ - - if (ei_status.dmaing) { - oaknet_dma_error(dev, "oaknet_block_input"); - return; - } - -#ifdef OAKNET_DISINT - save_flags(flags); - cli(); -#endif - - ei_status.dmaing |= 0x01; - ei_obp(E8390_NODMA + E8390_PAGE0 + E8390_START, base + E8390_CMD); - ei_obp(count & 0xff, base + EN0_RCNTLO); - ei_obp(count >> 8, base + EN0_RCNTHI); - ei_obp(ring_offset & 0xff, base + EN0_RSARLO); - ei_obp(ring_offset >> 8, base + EN0_RSARHI); - ei_obp(E8390_RREAD + E8390_START, base + E8390_CMD); - if (ei_status.word16) { - ei_isw(base + E8390_DATA, buf, count >> 1); - if (count & 0x01) { - buf[count - 1] = ei_ib(base + E8390_DATA); -#ifdef OAKNET_HEADCHECK - bytes++; -#endif - } - } else { - ei_isb(base + E8390_DATA, buf, count); - } -#ifdef OAKNET_HEADCHECK - /* - * This was for the ALPHA version only, but enough people have - * been encountering problems so it is still here. If you see - * this message you either 1) have a slightly incompatible clone - * or 2) have noise/speed problems with your bus. - */ - - /* DMA termination address check... */ - { - int addr, tries = 20; - do { - /* DON'T check for 'ei_ibp(EN0_ISR) & ENISR_RDC' here - -- it's broken for Rx on some cards! */ - int high = ei_ibp(base + EN0_RSARHI); - int low = ei_ibp(base + EN0_RSARLO); - addr = (high << 8) + low; - if (((ring_offset + bytes) & 0xff) == low) - break; - } while (--tries > 0); - if (tries <= 0) - printk("%s: RX transfer address mismatch," - "%#4.4x (expected) vs. %#4.4x (actual).\n", - dev->name, ring_offset + bytes, addr); - } -#endif - ei_obp(ENISR_RDC, base + EN0_ISR); /* ACK Remote DMA interrupt */ - ei_status.dmaing &= ~0x01; - -#ifdef OAKNET_DISINT - restore_flags(flags); -#endif -} - -/* - * static void oaknet_block_output() - * - * Description: - * This routine... - * - * Input(s): - * *dev - Pointer to the device structure for this driver. - * count - Number of bytes to be transferred. - * *buf - - * start_page - - * - * Output(s): - * N/A - * - * Returns: - * N/A - * - */ -static void -oaknet_block_output(struct net_device *dev, int count, - const unsigned char *buf, int start_page) -{ - int base = E8390_BASE; -#if 0 - int bug; -#endif - unsigned long start; -#ifdef OAKNET_DISINT - unsigned long flags; -#endif -#ifdef OAKNET_HEADCHECK - int retries = 0; -#endif - - /* Round the count up for word writes. */ - - if (ei_status.word16 && (count & 0x1)) - count++; - - /* - * This should NOT happen. If it does, it is the LAST thing you'll - * see. - */ - - if (ei_status.dmaing) { - oaknet_dma_error(dev, "oaknet_block_output"); - return; - } - -#ifdef OAKNET_DISINT - save_flags(flags); - cli(); -#endif - - ei_status.dmaing |= 0x01; - - /* Make sure we are in page 0. */ - - ei_obp(E8390_PAGE0 + E8390_START + E8390_NODMA, base + E8390_CMD); - -#ifdef OAKNET_HEADCHECK -retry: -#endif - -#if 0 - /* - * The 83902 documentation states that the processor needs to - * do a "dummy read" before doing the remote write to work - * around a chip bug they don't feel like fixing. - */ - - bug = 0; - while (1) { - unsigned int rdhi; - unsigned int rdlo; - - /* Now the normal output. */ - ei_obp(ENISR_RDC, base + EN0_ISR); - ei_obp(count & 0xff, base + EN0_RCNTLO); - ei_obp(count >> 8, base + EN0_RCNTHI); - ei_obp(0x00, base + EN0_RSARLO); - ei_obp(start_page, base + EN0_RSARHI); - - if (bug++) - break; - - /* Perform the dummy read */ - rdhi = ei_ibp(base + EN0_CRDAHI); - rdlo = ei_ibp(base + EN0_CRDALO); - ei_obp(E8390_RREAD + E8390_START, base + E8390_CMD); - - while (1) { - unsigned int nrdhi; - unsigned int nrdlo; - nrdhi = ei_ibp(base + EN0_CRDAHI); - nrdlo = ei_ibp(base + EN0_CRDALO); - if ((rdhi != nrdhi) || (rdlo != nrdlo)) - break; - } - } -#else -#ifdef OAKNET_RWFIX - /* - * Handle the read-before-write bug the same way as the - * Crynwr packet driver -- the Nat'l Semi. method doesn't work. - * Actually this doesn't always work either, but if you have - * problems with your 83902 this is better than nothing! - */ - - ei_obp(0x42, base + EN0_RCNTLO); - ei_obp(0x00, base + EN0_RCNTHI); - ei_obp(0x42, base + EN0_RSARLO); - ei_obp(0x00, base + EN0_RSARHI); - ei_obp(E8390_RREAD + E8390_START, base + E8390_CMD); - /* Make certain that the dummy read has occurred. */ - udelay(6); -#endif - - ei_obp(ENISR_RDC, base + EN0_ISR); - - /* Now the normal output. */ - ei_obp(count & 0xff, base + EN0_RCNTLO); - ei_obp(count >> 8, base + EN0_RCNTHI); - ei_obp(0x00, base + EN0_RSARLO); - ei_obp(start_page, base + EN0_RSARHI); -#endif /* 0/1 */ - - ei_obp(E8390_RWRITE + E8390_START, base + E8390_CMD); - if (ei_status.word16) { - ei_osw(E8390_BASE + E8390_DATA, buf, count >> 1); - } else { - ei_osb(E8390_BASE + E8390_DATA, buf, count); - } - -#ifdef OAKNET_DISINT - restore_flags(flags); -#endif - - start = jiffies; - -#ifdef OAKNET_HEADCHECK - /* - * This was for the ALPHA version only, but enough people have - * been encountering problems so it is still here. - */ - - { - /* DMA termination address check... */ - int addr, tries = 20; - do { - int high = ei_ibp(base + EN0_RSARHI); - int low = ei_ibp(base + EN0_RSARLO); - addr = (high << 8) + low; - if ((start_page << 8) + count == addr) - break; - } while (--tries > 0); - - if (tries <= 0) { - printk("%s: Tx packet transfer address mismatch," - "%#4.4x (expected) vs. %#4.4x (actual).\n", - dev->name, (start_page << 8) + count, addr); - if (retries++ == 0) - goto retry; - } - } -#endif - - while ((ei_ibp(base + EN0_ISR) & ENISR_RDC) == 0) { - if (time_after(jiffies, start + OAKNET_WAIT)) { - printk("%s: timeout waiting for Tx RDC.\n", dev->name); - oaknet_reset_8390(dev); - NS8390_init(dev, TRUE); - break; - } - } - - ei_obp(ENISR_RDC, base + EN0_ISR); /* Ack intr. */ - ei_status.dmaing &= ~0x01; -} - -/* - * static void oaknet_dma_error() - * - * Description: - * This routine prints out a last-ditch informative message to the console - * indicating that a DMA error occurred. If you see this, it's the last - * thing you'll see. - * - * Input(s): - * *dev - Pointer to the device structure for this driver. - * *name - Informative text (e.g. function name) indicating where the - * DMA error occurred. - * - * Output(s): - * N/A - * - * Returns: - * N/A - * - */ -static void -oaknet_dma_error(struct net_device *dev, const char *name) -{ - printk(KERN_EMERG "%s: DMAing conflict in %s." - "[DMAstat:%d][irqlock:%d][intr:%ld]\n", - dev->name, name, ei_status.dmaing, ei_status.irqlock, - dev->interrupt); -} - -/* - * Oak Ethernet module unload interface. - */ -static void __exit oaknet_cleanup_module (void) -{ - /* Convert to loop once driver supports multiple devices. */ - unregister_netdev(oaknet_dev); - free_irq(oaknet_devs->irq, oaknet_devs); - release_region(oaknet_devs->base_addr, OAKNET_IO_SIZE); - iounmap(ioaddr); - free_netdev(oaknet_devs); -} - -module_init(oaknet_init); -module_exit(oaknet_cleanup_module); -MODULE_LICENSE("GPL"); diff --git a/drivers/net/pasemi_mac.c b/drivers/net/pasemi_mac.c new file mode 100644 index 0000000..d670ac7 --- /dev/null +++ b/drivers/net/pasemi_mac.c @@ -0,0 +1,1019 @@ +/* + * Copyright (C) 2006-2007 PA Semi, Inc + * + * Driver for the PA Semi PWRficient onchip 1G/10G Ethernet MACs + * + * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include "pasemi_mac.h" + + +/* TODO list + * + * - Get rid of pci_{read,write}_config(), map registers with ioremap + * for performance + * - PHY support + * - Multicast support + * - Large MTU support + * - Other performance improvements + */ + + +/* Must be a power of two */ +#define RX_RING_SIZE 512 +#define TX_RING_SIZE 512 + +#define TX_DESC(mac, num) ((mac)->tx->desc[(num) & (TX_RING_SIZE-1)]) +#define TX_DESC_INFO(mac, num) ((mac)->tx->desc_info[(num) & (TX_RING_SIZE-1)]) +#define RX_DESC(mac, num) ((mac)->rx->desc[(num) & (RX_RING_SIZE-1)]) +#define RX_DESC_INFO(mac, num) ((mac)->rx->desc_info[(num) & (RX_RING_SIZE-1)]) +#define RX_BUFF(mac, num) ((mac)->rx->buffers[(num) & (RX_RING_SIZE-1)]) + +#define BUF_SIZE 1646 /* 1500 MTU + ETH_HLEN + VLAN_HLEN + 2 64B cachelines */ + +/* XXXOJN these should come out of the device tree some day */ +#define PAS_DMA_CAP_BASE 0xe00d0040 +#define PAS_DMA_CAP_SIZE 0x100 +#define PAS_DMA_COM_BASE 0xe00d0100 +#define PAS_DMA_COM_SIZE 0x100 + +static struct pasdma_status *dma_status; + +static int pasemi_get_mac_addr(struct pasemi_mac *mac) +{ + struct pci_dev *pdev = mac->pdev; + struct device_node *dn = pci_device_to_OF_node(pdev); + const u8 *maddr; + u8 addr[6]; + + if (!dn) { + dev_dbg(&pdev->dev, + "No device node for mac, not configuring\n"); + return -ENOENT; + } + + maddr = get_property(dn, "mac-address", NULL); + if (maddr == NULL) { + dev_warn(&pdev->dev, + "no mac address in device tree, not configuring\n"); + return -ENOENT; + } + + if (sscanf(maddr, "%hhx:%hhx:%hhx:%hhx:%hhx:%hhx", &addr[0], + &addr[1], &addr[2], &addr[3], &addr[4], &addr[5]) != 6) { + dev_warn(&pdev->dev, + "can't parse mac address, not configuring\n"); + return -EINVAL; + } + + memcpy(mac->mac_addr, addr, sizeof(addr)); + return 0; +} + +static int pasemi_mac_setup_rx_resources(struct net_device *dev) +{ + struct pasemi_mac_rxring *ring; + struct pasemi_mac *mac = netdev_priv(dev); + int chan_id = mac->dma_rxch; + + ring = kzalloc(sizeof(*ring), GFP_KERNEL); + + if (!ring) + goto out_ring; + + spin_lock_init(&ring->lock); + + ring->desc_info = kzalloc(sizeof(struct pasemi_mac_buffer) * + RX_RING_SIZE, GFP_KERNEL); + + if (!ring->desc_info) + goto out_desc_info; + + /* Allocate descriptors */ + ring->desc = dma_alloc_coherent(&mac->dma_pdev->dev, + RX_RING_SIZE * + sizeof(struct pas_dma_xct_descr), + &ring->dma, GFP_KERNEL); + + if (!ring->desc) + goto out_desc; + + memset(ring->desc, 0, RX_RING_SIZE * sizeof(struct pas_dma_xct_descr)); + + ring->buffers = dma_alloc_coherent(&mac->dma_pdev->dev, + RX_RING_SIZE * sizeof(u64), + &ring->buf_dma, GFP_KERNEL); + if (!ring->buffers) + goto out_buffers; + + memset(ring->buffers, 0, RX_RING_SIZE * sizeof(u64)); + + pci_write_config_dword(mac->dma_pdev, PAS_DMA_RXCHAN_BASEL(chan_id), + PAS_DMA_RXCHAN_BASEL_BRBL(ring->dma)); + + pci_write_config_dword(mac->dma_pdev, PAS_DMA_RXCHAN_BASEU(chan_id), + PAS_DMA_RXCHAN_BASEU_BRBH(ring->dma >> 32) | + PAS_DMA_RXCHAN_BASEU_SIZ(RX_RING_SIZE >> 2)); + + pci_write_config_dword(mac->dma_pdev, PAS_DMA_RXCHAN_CFG(chan_id), + PAS_DMA_RXCHAN_CFG_HBU(1)); + + pci_write_config_dword(mac->dma_pdev, PAS_DMA_RXINT_BASEL(mac->dma_if), + PAS_DMA_RXINT_BASEL_BRBL(__pa(ring->buffers))); + + pci_write_config_dword(mac->dma_pdev, PAS_DMA_RXINT_BASEU(mac->dma_if), + PAS_DMA_RXINT_BASEU_BRBH(__pa(ring->buffers) >> 32) | + PAS_DMA_RXINT_BASEU_SIZ(RX_RING_SIZE >> 3)); + + ring->next_to_fill = 0; + ring->next_to_clean = 0; + + snprintf(ring->irq_name, sizeof(ring->irq_name), + "%s rx", dev->name); + mac->rx = ring; + + return 0; + +out_buffers: + dma_free_coherent(&mac->dma_pdev->dev, + RX_RING_SIZE * sizeof(struct pas_dma_xct_descr), + mac->rx->desc, mac->rx->dma); +out_desc: + kfree(ring->desc_info); +out_desc_info: + kfree(ring); +out_ring: + return -ENOMEM; +} + + +static int pasemi_mac_setup_tx_resources(struct net_device *dev) +{ + struct pasemi_mac *mac = netdev_priv(dev); + u32 val; + int chan_id = mac->dma_txch; + struct pasemi_mac_txring *ring; + + ring = kzalloc(sizeof(*ring), GFP_KERNEL); + if (!ring) + goto out_ring; + + spin_lock_init(&ring->lock); + + ring->desc_info = kzalloc(sizeof(struct pasemi_mac_buffer) * + TX_RING_SIZE, GFP_KERNEL); + if (!ring->desc_info) + goto out_desc_info; + + /* Allocate descriptors */ + ring->desc = dma_alloc_coherent(&mac->dma_pdev->dev, + TX_RING_SIZE * + sizeof(struct pas_dma_xct_descr), + &ring->dma, GFP_KERNEL); + if (!ring->desc) + goto out_desc; + + memset(ring->desc, 0, TX_RING_SIZE * sizeof(struct pas_dma_xct_descr)); + + pci_write_config_dword(mac->dma_pdev, PAS_DMA_TXCHAN_BASEL(chan_id), + PAS_DMA_TXCHAN_BASEL_BRBL(ring->dma)); + val = PAS_DMA_TXCHAN_BASEU_BRBH(ring->dma >> 32); + val |= PAS_DMA_TXCHAN_BASEU_SIZ(TX_RING_SIZE >> 2); + + pci_write_config_dword(mac->dma_pdev, PAS_DMA_TXCHAN_BASEU(chan_id), val); + + pci_write_config_dword(mac->dma_pdev, PAS_DMA_TXCHAN_CFG(chan_id), + PAS_DMA_TXCHAN_CFG_TY_IFACE | + PAS_DMA_TXCHAN_CFG_TATTR(mac->dma_if) | + PAS_DMA_TXCHAN_CFG_UP | + PAS_DMA_TXCHAN_CFG_WT(2)); + + ring->next_to_use = 0; + ring->next_to_clean = 0; + + snprintf(ring->irq_name, sizeof(ring->irq_name), + "%s tx", dev->name); + mac->tx = ring; + + return 0; + +out_desc: + kfree(ring->desc_info); +out_desc_info: + kfree(ring); +out_ring: + return -ENOMEM; +} + +static void pasemi_mac_free_tx_resources(struct net_device *dev) +{ + struct pasemi_mac *mac = netdev_priv(dev); + unsigned int i; + struct pasemi_mac_buffer *info; + struct pas_dma_xct_descr *dp; + + for (i = 0; i < TX_RING_SIZE; i++) { + info = &TX_DESC_INFO(mac, i); + dp = &TX_DESC(mac, i); + if (info->dma) { + if (info->skb) { + pci_unmap_single(mac->dma_pdev, + info->dma, + info->skb->len, + PCI_DMA_TODEVICE); + dev_kfree_skb_any(info->skb); + } + info->dma = 0; + info->skb = NULL; + dp->mactx = 0; + dp->ptr = 0; + } + } + + dma_free_coherent(&mac->dma_pdev->dev, + TX_RING_SIZE * sizeof(struct pas_dma_xct_descr), + mac->tx->desc, mac->tx->dma); + + kfree(mac->tx->desc_info); + kfree(mac->tx); + mac->tx = NULL; +} + +static void pasemi_mac_free_rx_resources(struct net_device *dev) +{ + struct pasemi_mac *mac = netdev_priv(dev); + unsigned int i; + struct pasemi_mac_buffer *info; + struct pas_dma_xct_descr *dp; + + for (i = 0; i < RX_RING_SIZE; i++) { + info = &RX_DESC_INFO(mac, i); + dp = &RX_DESC(mac, i); + if (info->dma) { + if (info->skb) { + pci_unmap_single(mac->dma_pdev, + info->dma, + info->skb->len, + PCI_DMA_FROMDEVICE); + dev_kfree_skb_any(info->skb); + } + info->dma = 0; + info->skb = NULL; + dp->macrx = 0; + dp->ptr = 0; + } + } + + dma_free_coherent(&mac->dma_pdev->dev, + RX_RING_SIZE * sizeof(struct pas_dma_xct_descr), + mac->rx->desc, mac->rx->dma); + + dma_free_coherent(&mac->dma_pdev->dev, RX_RING_SIZE * sizeof(u64), + mac->rx->buffers, mac->rx->buf_dma); + + kfree(mac->rx->desc_info); + kfree(mac->rx); + mac->rx = NULL; +} + +static void pasemi_mac_replenish_rx_ring(struct net_device *dev) +{ + struct pasemi_mac *mac = netdev_priv(dev); + unsigned int i; + int start = mac->rx->next_to_fill; + unsigned int count; + + count = (mac->rx->next_to_clean + RX_RING_SIZE - + mac->rx->next_to_fill) & (RX_RING_SIZE - 1); + + /* Check to see if we're doing first-time setup */ + if (unlikely(mac->rx->next_to_clean == 0 && mac->rx->next_to_fill == 0)) + count = RX_RING_SIZE; + + if (count <= 0) + return; + + for (i = start; i < start + count; i++) { + struct pasemi_mac_buffer *info = &RX_DESC_INFO(mac, i); + u64 *buff = &RX_BUFF(mac, i); + struct sk_buff *skb; + dma_addr_t dma; + + skb = dev_alloc_skb(BUF_SIZE); + + if (!skb) { + count = i - start; + break; + } + + skb->dev = dev; + + dma = pci_map_single(mac->dma_pdev, skb->data, skb->len, + PCI_DMA_FROMDEVICE); + + if (dma_mapping_error(dma)) { + dev_kfree_skb_irq(info->skb); + count = i - start; + break; + } + + info->skb = skb; + info->dma = dma; + *buff = XCT_RXB_LEN(BUF_SIZE) | XCT_RXB_ADDR(dma); + } + + wmb(); + + pci_write_config_dword(mac->dma_pdev, + PAS_DMA_RXCHAN_INCR(mac->dma_rxch), + count); + pci_write_config_dword(mac->dma_pdev, + PAS_DMA_RXINT_INCR(mac->dma_if), + count); + + mac->rx->next_to_fill += count; +} + +static int pasemi_mac_clean_rx(struct pasemi_mac *mac, int limit) +{ + unsigned int i; + int start, count; + + spin_lock(&mac->rx->lock); + + start = mac->rx->next_to_clean; + count = 0; + + for (i = start; i < (start + RX_RING_SIZE) && count < limit; i++) { + struct pas_dma_xct_descr *dp; + struct pasemi_mac_buffer *info; + struct sk_buff *skb; + unsigned int j, len; + dma_addr_t dma; + + rmb(); + + dp = &RX_DESC(mac, i); + + if (!(dp->macrx & XCT_MACRX_O)) + break; + + count++; + + info = NULL; + + /* We have to scan for our skb since there's no way + * to back-map them from the descriptor, and if we + * have several receive channels then they might not + * show up in the same order as they were put on the + * interface ring. + */ + + dma = (dp->ptr & XCT_PTR_ADDR_M); + for (j = start; j < (start + RX_RING_SIZE); j++) { + info = &RX_DESC_INFO(mac, j); + if (info->dma == dma) + break; + } + + BUG_ON(!info); + BUG_ON(info->dma != dma); + + pci_unmap_single(mac->dma_pdev, info->dma, info->skb->len, + PCI_DMA_FROMDEVICE); + + skb = info->skb; + + len = (dp->macrx & XCT_MACRX_LLEN_M) >> XCT_MACRX_LLEN_S; + + skb_put(skb, len); + + skb->protocol = eth_type_trans(skb, mac->netdev); + + if ((dp->macrx & XCT_MACRX_HTY_M) == XCT_MACRX_HTY_IPV4_OK) { + skb->ip_summed = CHECKSUM_COMPLETE; + skb->csum = (dp->macrx & XCT_MACRX_CSUM_M) >> + XCT_MACRX_CSUM_S; + } else + skb->ip_summed = CHECKSUM_NONE; + + mac->stats.rx_bytes += len; + mac->stats.rx_packets++; + + netif_receive_skb(skb); + + info->dma = 0; + info->skb = NULL; + dp->ptr = 0; + dp->macrx = 0; + } + + mac->rx->next_to_clean += count; + pasemi_mac_replenish_rx_ring(mac->netdev); + + spin_unlock(&mac->rx->lock); + + return count; +} + +static int pasemi_mac_clean_tx(struct pasemi_mac *mac) +{ + int i; + struct pasemi_mac_buffer *info; + struct pas_dma_xct_descr *dp; + int start, count; + int flags; + + spin_lock_irqsave(&mac->tx->lock, flags); + + start = mac->tx->next_to_clean; + count = 0; + + for (i = start; i < mac->tx->next_to_use; i++) { + dp = &TX_DESC(mac, i); + if (!dp || (dp->mactx & XCT_MACTX_O)) + break; + + count++; + + info = &TX_DESC_INFO(mac, i); + + pci_unmap_single(mac->dma_pdev, info->dma, + info->skb->len, PCI_DMA_TODEVICE); + dev_kfree_skb_irq(info->skb); + + info->skb = NULL; + info->dma = 0; + dp->mactx = 0; + dp->ptr = 0; + } + mac->tx->next_to_clean += count; + spin_unlock_irqrestore(&mac->tx->lock, flags); + + return count; +} + + +static irqreturn_t pasemi_mac_rx_intr(int irq, void *data) +{ + struct net_device *dev = data; + struct pasemi_mac *mac = netdev_priv(dev); + unsigned int reg; + + if (!(*mac->rx_status & PAS_STATUS_INT)) + return IRQ_NONE; + + netif_rx_schedule(dev); + pci_write_config_dword(mac->iob_pdev, PAS_IOB_DMA_COM_TIMEOUTCFG, + PAS_IOB_DMA_COM_TIMEOUTCFG_TCNT(0)); + + reg = PAS_IOB_DMA_RXCH_RESET_PINTC | PAS_IOB_DMA_RXCH_RESET_SINTC | + PAS_IOB_DMA_RXCH_RESET_DINTC; + if (*mac->rx_status & PAS_STATUS_TIMER) + reg |= PAS_IOB_DMA_RXCH_RESET_TINTC; + + pci_write_config_dword(mac->iob_pdev, + PAS_IOB_DMA_RXCH_RESET(mac->dma_rxch), reg); + + + return IRQ_HANDLED; +} + +static irqreturn_t pasemi_mac_tx_intr(int irq, void *data) +{ + struct net_device *dev = data; + struct pasemi_mac *mac = netdev_priv(dev); + unsigned int reg; + int was_full; + + was_full = mac->tx->next_to_clean - mac->tx->next_to_use == TX_RING_SIZE; + + if (!(*mac->tx_status & PAS_STATUS_INT)) + return IRQ_NONE; + + pasemi_mac_clean_tx(mac); + + reg = PAS_IOB_DMA_TXCH_RESET_PINTC | PAS_IOB_DMA_TXCH_RESET_SINTC; + if (*mac->tx_status & PAS_STATUS_TIMER) + reg |= PAS_IOB_DMA_TXCH_RESET_TINTC; + + pci_write_config_dword(mac->iob_pdev, PAS_IOB_DMA_TXCH_RESET(mac->dma_txch), + reg); + + if (was_full) + netif_wake_queue(dev); + + return IRQ_HANDLED; +} + +static int pasemi_mac_open(struct net_device *dev) +{ + struct pasemi_mac *mac = netdev_priv(dev); + unsigned int flags; + int ret; + + /* enable rx section */ + pci_write_config_dword(mac->dma_pdev, PAS_DMA_COM_RXCMD, + PAS_DMA_COM_RXCMD_EN); + + /* enable tx section */ + pci_write_config_dword(mac->dma_pdev, PAS_DMA_COM_TXCMD, + PAS_DMA_COM_TXCMD_EN); + + flags = PAS_MAC_CFG_TXP_FCE | PAS_MAC_CFG_TXP_FPC(3) | + PAS_MAC_CFG_TXP_SL(3) | PAS_MAC_CFG_TXP_COB(0xf) | + PAS_MAC_CFG_TXP_TIFT(8) | PAS_MAC_CFG_TXP_TIFG(12); + + pci_write_config_dword(mac->pdev, PAS_MAC_CFG_TXP, flags); + + flags = PAS_MAC_CFG_PCFG_S1 | PAS_MAC_CFG_PCFG_PE | + PAS_MAC_CFG_PCFG_PR | PAS_MAC_CFG_PCFG_CE; + + flags |= PAS_MAC_CFG_PCFG_TSR_1G | PAS_MAC_CFG_PCFG_SPD_1G; + + pci_write_config_dword(mac->iob_pdev, PAS_IOB_DMA_RXCH_CFG(mac->dma_rxch), + PAS_IOB_DMA_RXCH_CFG_CNTTH(30)); + + pci_write_config_dword(mac->iob_pdev, PAS_IOB_DMA_COM_TIMEOUTCFG, + PAS_IOB_DMA_COM_TIMEOUTCFG_TCNT(1000000)); + + pci_write_config_dword(mac->pdev, PAS_MAC_CFG_PCFG, flags); + + ret = pasemi_mac_setup_rx_resources(dev); + if (ret) + goto out_rx_resources; + + ret = pasemi_mac_setup_tx_resources(dev); + if (ret) + goto out_tx_resources; + + pci_write_config_dword(mac->pdev, PAS_MAC_IPC_CHNL, + PAS_MAC_IPC_CHNL_DCHNO(mac->dma_rxch) | + PAS_MAC_IPC_CHNL_BCH(mac->dma_rxch)); + + /* enable rx if */ + pci_write_config_dword(mac->dma_pdev, + PAS_DMA_RXINT_RCMDSTA(mac->dma_if), + PAS_DMA_RXINT_RCMDSTA_EN); + + /* enable rx channel */ + pci_write_config_dword(mac->dma_pdev, + PAS_DMA_RXCHAN_CCMDSTA(mac->dma_rxch), + PAS_DMA_RXCHAN_CCMDSTA_EN | + PAS_DMA_RXCHAN_CCMDSTA_DU); + + /* enable tx channel */ + pci_write_config_dword(mac->dma_pdev, + PAS_DMA_TXCHAN_TCMDSTA(mac->dma_txch), + PAS_DMA_TXCHAN_TCMDSTA_EN); + + pasemi_mac_replenish_rx_ring(dev); + + netif_start_queue(dev); + netif_poll_enable(dev); + + ret = request_irq(mac->dma_pdev->irq + mac->dma_txch, + &pasemi_mac_tx_intr, IRQF_DISABLED, + mac->tx->irq_name, dev); + if (ret) { + dev_err(&mac->pdev->dev, "request_irq of irq %d failed: %d\n", + mac->dma_pdev->irq + mac->dma_txch, ret); + goto out_tx_int; + } + + ret = request_irq(mac->dma_pdev->irq + 20 + mac->dma_rxch, + &pasemi_mac_rx_intr, IRQF_DISABLED, + mac->rx->irq_name, dev); + if (ret) { + dev_err(&mac->pdev->dev, "request_irq of irq %d failed: %d\n", + mac->dma_pdev->irq + 20 + mac->dma_rxch, ret); + goto out_rx_int; + } + + return 0; + +out_rx_int: + free_irq(mac->dma_pdev->irq + mac->dma_txch, dev); +out_tx_int: + netif_poll_disable(dev); + netif_stop_queue(dev); + pasemi_mac_free_tx_resources(dev); +out_tx_resources: + pasemi_mac_free_rx_resources(dev); +out_rx_resources: + + return ret; +} + +#define MAX_RETRIES 5000 + +static int pasemi_mac_close(struct net_device *dev) +{ + struct pasemi_mac *mac = netdev_priv(dev); + unsigned int stat; + int retries; + + netif_stop_queue(dev); + + /* Clean out any pending buffers */ + pasemi_mac_clean_tx(mac); + pasemi_mac_clean_rx(mac, RX_RING_SIZE); + + /* Disable interface */ + pci_write_config_dword(mac->dma_pdev, + PAS_DMA_TXCHAN_TCMDSTA(mac->dma_txch), + PAS_DMA_TXCHAN_TCMDSTA_ST); + pci_write_config_dword(mac->dma_pdev, + PAS_DMA_RXINT_RCMDSTA(mac->dma_if), + PAS_DMA_RXINT_RCMDSTA_ST); + pci_write_config_dword(mac->dma_pdev, + PAS_DMA_RXCHAN_CCMDSTA(mac->dma_rxch), + PAS_DMA_RXCHAN_CCMDSTA_ST); + + for (retries = 0; retries < MAX_RETRIES; retries++) { + pci_read_config_dword(mac->dma_pdev, + PAS_DMA_TXCHAN_TCMDSTA(mac->dma_txch), + &stat); + if (stat & PAS_DMA_TXCHAN_TCMDSTA_ACT) + break; + cond_resched(); + } + + if (!(stat & PAS_DMA_TXCHAN_TCMDSTA_ACT)) { + dev_err(&mac->dma_pdev->dev, "Failed to stop tx channel\n"); + } + + for (retries = 0; retries < MAX_RETRIES; retries++) { + pci_read_config_dword(mac->dma_pdev, + PAS_DMA_RXCHAN_CCMDSTA(mac->dma_rxch), + &stat); + if (stat & PAS_DMA_RXCHAN_CCMDSTA_ACT) + break; + cond_resched(); + } + + if (!(stat & PAS_DMA_RXCHAN_CCMDSTA_ACT)) { + dev_err(&mac->dma_pdev->dev, "Failed to stop rx channel\n"); + } + + for (retries = 0; retries < MAX_RETRIES; retries++) { + pci_read_config_dword(mac->dma_pdev, + PAS_DMA_RXINT_RCMDSTA(mac->dma_if), + &stat); + if (stat & PAS_DMA_RXINT_RCMDSTA_ACT) + break; + cond_resched(); + } + + if (!(stat & PAS_DMA_RXINT_RCMDSTA_ACT)) { + dev_err(&mac->dma_pdev->dev, "Failed to stop rx interface\n"); + } + + /* Then, disable the channel. This must be done separately from + * stopping, since you can't disable when active. + */ + + pci_write_config_dword(mac->dma_pdev, + PAS_DMA_TXCHAN_TCMDSTA(mac->dma_txch), 0); + pci_write_config_dword(mac->dma_pdev, + PAS_DMA_RXCHAN_CCMDSTA(mac->dma_rxch), 0); + pci_write_config_dword(mac->dma_pdev, + PAS_DMA_RXINT_RCMDSTA(mac->dma_if), 0); + + free_irq(mac->dma_pdev->irq + mac->dma_txch, dev); + free_irq(mac->dma_pdev->irq + 20 + mac->dma_rxch, dev); + + /* Free resources */ + pasemi_mac_free_rx_resources(dev); + pasemi_mac_free_tx_resources(dev); + + return 0; +} + +static int pasemi_mac_start_tx(struct sk_buff *skb, struct net_device *dev) +{ + struct pasemi_mac *mac = netdev_priv(dev); + struct pasemi_mac_txring *txring; + struct pasemi_mac_buffer *info; + struct pas_dma_xct_descr *dp; + u64 dflags; + dma_addr_t map; + int flags; + + dflags = XCT_MACTX_O | XCT_MACTX_ST | XCT_MACTX_SS | XCT_MACTX_CRC_PAD; + + if (skb->ip_summed == CHECKSUM_PARTIAL) { + switch (skb->nh.iph->protocol) { + case IPPROTO_TCP: + dflags |= XCT_MACTX_CSUM_TCP; + dflags |= XCT_MACTX_IPH((skb->h.raw - skb->nh.raw) >> 2); + dflags |= XCT_MACTX_IPO(skb->nh.raw - skb->data); + break; + case IPPROTO_UDP: + dflags |= XCT_MACTX_CSUM_UDP; + dflags |= XCT_MACTX_IPH((skb->h.raw - skb->nh.raw) >> 2); + dflags |= XCT_MACTX_IPO(skb->nh.raw - skb->data); + break; + } + } + + map = pci_map_single(mac->dma_pdev, skb->data, skb->len, PCI_DMA_TODEVICE); + + if (dma_mapping_error(map)) + return NETDEV_TX_BUSY; + + txring = mac->tx; + + spin_lock_irqsave(&txring->lock, flags); + + if (txring->next_to_clean - txring->next_to_use == TX_RING_SIZE) { + spin_unlock_irqrestore(&txring->lock, flags); + pasemi_mac_clean_tx(mac); + spin_lock_irqsave(&txring->lock, flags); + + if (txring->next_to_clean - txring->next_to_use == + TX_RING_SIZE) { + /* Still no room -- stop the queue and wait for tx + * intr when there's room. + */ + netif_stop_queue(dev); + goto out_err; + } + } + + + dp = &TX_DESC(mac, txring->next_to_use); + info = &TX_DESC_INFO(mac, txring->next_to_use); + + dp->mactx = dflags | XCT_MACTX_LLEN(skb->len); + dp->ptr = XCT_PTR_LEN(skb->len) | XCT_PTR_ADDR(map); + info->dma = map; + info->skb = skb; + + txring->next_to_use++; + mac->stats.tx_packets++; + mac->stats.tx_bytes += skb->len; + + spin_unlock_irqrestore(&txring->lock, flags); + + pci_write_config_dword(mac->dma_pdev, + PAS_DMA_TXCHAN_INCR(mac->dma_txch), 1); + + return NETDEV_TX_OK; + +out_err: + spin_unlock_irqrestore(&txring->lock, flags); + pci_unmap_single(mac->dma_pdev, map, skb->len, PCI_DMA_TODEVICE); + return NETDEV_TX_BUSY; +} + +static struct net_device_stats *pasemi_mac_get_stats(struct net_device *dev) +{ + struct pasemi_mac *mac = netdev_priv(dev); + + return &mac->stats; +} + +static void pasemi_mac_set_rx_mode(struct net_device *dev) +{ + struct pasemi_mac *mac = netdev_priv(dev); + unsigned int flags; + + pci_read_config_dword(mac->pdev, PAS_MAC_CFG_PCFG, &flags); + + /* Set promiscuous */ + if (dev->flags & IFF_PROMISC) + flags |= PAS_MAC_CFG_PCFG_PR; + else + flags &= ~PAS_MAC_CFG_PCFG_PR; + + pci_write_config_dword(mac->pdev, PAS_MAC_CFG_PCFG, flags); +} + + +static int pasemi_mac_poll(struct net_device *dev, int *budget) +{ + int pkts, limit = min(*budget, dev->quota); + struct pasemi_mac *mac = netdev_priv(dev); + + pkts = pasemi_mac_clean_rx(mac, limit); + + if (pkts < limit) { + /* all done, no more packets present */ + netif_rx_complete(dev); + + /* re-enable receive interrupts */ + pci_write_config_dword(mac->iob_pdev, PAS_IOB_DMA_COM_TIMEOUTCFG, + PAS_IOB_DMA_COM_TIMEOUTCFG_TCNT(1000000)); + return 0; + } else { + /* used up our quantum, so reschedule */ + dev->quota -= pkts; + *budget -= pkts; + return 1; + } +} + +static int __devinit +pasemi_mac_probe(struct pci_dev *pdev, const struct pci_device_id *ent) +{ + static int index = 0; + struct net_device *dev; + struct pasemi_mac *mac; + int err; + + err = pci_enable_device(pdev); + if (err) + return err; + + dev = alloc_etherdev(sizeof(struct pasemi_mac)); + if (dev == NULL) { + dev_err(&pdev->dev, + "pasemi_mac: Could not allocate ethernet device.\n"); + err = -ENOMEM; + goto out_disable_device; + } + + SET_MODULE_OWNER(dev); + pci_set_drvdata(pdev, dev); + SET_NETDEV_DEV(dev, &pdev->dev); + + mac = netdev_priv(dev); + + mac->pdev = pdev; + mac->netdev = dev; + mac->dma_pdev = pci_get_device(PCI_VENDOR_ID_PASEMI, 0xa007, NULL); + + if (!mac->dma_pdev) { + dev_err(&pdev->dev, "Can't find DMA Controller\n"); + err = -ENODEV; + goto out_free_netdev; + } + + mac->iob_pdev = pci_get_device(PCI_VENDOR_ID_PASEMI, 0xa001, NULL); + + if (!mac->iob_pdev) { + dev_err(&pdev->dev, "Can't find I/O Bridge\n"); + err = -ENODEV; + goto out_put_dma_pdev; + } + + /* These should come out of the device tree eventually */ + mac->dma_txch = index; + mac->dma_rxch = index; + + /* We probe GMAC before XAUI, but the DMA interfaces are + * in XAUI, GMAC order. + */ + if (index < 4) + mac->dma_if = index + 2; + else + mac->dma_if = index - 4; + index++; + + switch (pdev->device) { + case 0xa005: + mac->type = MAC_TYPE_GMAC; + break; + case 0xa006: + mac->type = MAC_TYPE_XAUI; + break; + default: + err = -ENODEV; + goto out; + } + + /* get mac addr from device tree */ + if (pasemi_get_mac_addr(mac) || !is_valid_ether_addr(mac->mac_addr)) { + err = -ENODEV; + goto out; + } + memcpy(dev->dev_addr, mac->mac_addr, sizeof(mac->mac_addr)); + + dev->open = pasemi_mac_open; + dev->stop = pasemi_mac_close; + dev->hard_start_xmit = pasemi_mac_start_tx; + dev->get_stats = pasemi_mac_get_stats; + dev->set_multicast_list = pasemi_mac_set_rx_mode; + dev->weight = 64; + dev->poll = pasemi_mac_poll; + dev->features = NETIF_F_HW_CSUM; + + /* The dma status structure is located in the I/O bridge, and + * is cache coherent. + */ + if (!dma_status) + /* XXXOJN This should come from the device tree */ + dma_status = __ioremap(0xfd800000, 0x1000, 0); + + mac->rx_status = &dma_status->rx_sta[mac->dma_rxch]; + mac->tx_status = &dma_status->tx_sta[mac->dma_txch]; + + err = register_netdev(dev); + + if (err) { + dev_err(&mac->pdev->dev, "register_netdev failed with error %d\n", + err); + goto out; + } else + printk(KERN_INFO "%s: PA Semi %s: intf %d, txch %d, rxch %d, " + "hw addr %02x:%02x:%02x:%02x:%02x:%02x\n", + dev->name, mac->type == MAC_TYPE_GMAC ? "GMAC" : "XAUI", + mac->dma_if, mac->dma_txch, mac->dma_rxch, + dev->dev_addr[0], dev->dev_addr[1], dev->dev_addr[2], + dev->dev_addr[3], dev->dev_addr[4], dev->dev_addr[5]); + + return err; + +out: + pci_dev_put(mac->iob_pdev); +out_put_dma_pdev: + pci_dev_put(mac->dma_pdev); +out_free_netdev: + free_netdev(dev); +out_disable_device: + pci_disable_device(pdev); + return err; + +} + +static void __devexit pasemi_mac_remove(struct pci_dev *pdev) +{ + struct net_device *netdev = pci_get_drvdata(pdev); + struct pasemi_mac *mac; + + if (!netdev) + return; + + mac = netdev_priv(netdev); + + unregister_netdev(netdev); + + pci_disable_device(pdev); + pci_dev_put(mac->dma_pdev); + pci_dev_put(mac->iob_pdev); + + pci_set_drvdata(pdev, NULL); + free_netdev(netdev); +} + +static struct pci_device_id pasemi_mac_pci_tbl[] = { + { PCI_DEVICE(PCI_VENDOR_ID_PASEMI, 0xa005) }, + { PCI_DEVICE(PCI_VENDOR_ID_PASEMI, 0xa006) }, +}; + +MODULE_DEVICE_TABLE(pci, pasemi_mac_pci_tbl); + +static struct pci_driver pasemi_mac_driver = { + .name = "pasemi_mac", + .id_table = pasemi_mac_pci_tbl, + .probe = pasemi_mac_probe, + .remove = __devexit_p(pasemi_mac_remove), +}; + +static void __exit pasemi_mac_cleanup_module(void) +{ + pci_unregister_driver(&pasemi_mac_driver); + __iounmap(dma_status); + dma_status = NULL; +} + +int pasemi_mac_init_module(void) +{ + return pci_register_driver(&pasemi_mac_driver); +} + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR ("Olof Johansson "); +MODULE_DESCRIPTION("PA Semi PWRficient Ethernet driver"); + +module_init(pasemi_mac_init_module); +module_exit(pasemi_mac_cleanup_module); diff --git a/drivers/net/pasemi_mac.h b/drivers/net/pasemi_mac.h new file mode 100644 index 0000000..c3e37e4 --- /dev/null +++ b/drivers/net/pasemi_mac.h @@ -0,0 +1,460 @@ +/* + * Copyright (C) 2006 PA Semi, Inc + * + * Driver for the PA6T-1682M onchip 1G/10G Ethernet MACs, soft state and + * hardware register layouts. + * + * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef PASEMI_MAC_H +#define PASEMI_MAC_H + +#include +#include +#include + +struct pasemi_mac_txring { + spinlock_t lock; + struct pas_dma_xct_descr *desc; + dma_addr_t dma; + unsigned int size; + unsigned int next_to_use; + unsigned int next_to_clean; + struct pasemi_mac_buffer *desc_info; + char irq_name[10]; /* "eth%d tx" */ +}; + +struct pasemi_mac_rxring { + spinlock_t lock; + struct pas_dma_xct_descr *desc; /* RX channel descriptor ring */ + dma_addr_t dma; + u64 *buffers; /* RX interface buffer ring */ + dma_addr_t buf_dma; + unsigned int size; + unsigned int next_to_fill; + unsigned int next_to_clean; + struct pasemi_mac_buffer *desc_info; + char irq_name[10]; /* "eth%d rx" */ +}; + +struct pasemi_mac { + struct net_device *netdev; + struct pci_dev *pdev; + struct pci_dev *dma_pdev; + struct pci_dev *iob_pdev; + struct net_device_stats stats; + + /* Pointer to the cacheable per-channel status registers */ + u64 *rx_status; + u64 *tx_status; + + u8 type; +#define MAC_TYPE_GMAC 1 +#define MAC_TYPE_XAUI 2 + u32 dma_txch; + u32 dma_if; + u32 dma_rxch; + + u8 mac_addr[6]; + + struct timer_list rxtimer; + + struct pasemi_mac_txring *tx; + struct pasemi_mac_rxring *rx; +}; + +/* Software status descriptor (desc_info) */ +struct pasemi_mac_buffer { + struct sk_buff *skb; + dma_addr_t dma; +}; + + +/* status register layout in IOB region, at 0xfb800000 */ +struct pasdma_status { + u64 rx_sta[64]; + u64 tx_sta[20]; +}; + +/* descriptor structure */ +struct pas_dma_xct_descr { + union { + u64 mactx; + u64 macrx; + }; + union { + u64 ptr; + u64 rxb; + }; +}; + +/* MAC CFG register offsets */ + +enum { + PAS_MAC_CFG_PCFG = 0x80, + PAS_MAC_CFG_TXP = 0x98, + PAS_MAC_IPC_CHNL = 0x208, +}; + +/* MAC CFG register fields */ +#define PAS_MAC_CFG_PCFG_PE 0x80000000 +#define PAS_MAC_CFG_PCFG_CE 0x40000000 +#define PAS_MAC_CFG_PCFG_BU 0x20000000 +#define PAS_MAC_CFG_PCFG_TT 0x10000000 +#define PAS_MAC_CFG_PCFG_TSR_M 0x0c000000 +#define PAS_MAC_CFG_PCFG_TSR_10M 0x00000000 +#define PAS_MAC_CFG_PCFG_TSR_100M 0x04000000 +#define PAS_MAC_CFG_PCFG_TSR_1G 0x08000000 +#define PAS_MAC_CFG_PCFG_TSR_10G 0x0c000000 +#define PAS_MAC_CFG_PCFG_T24 0x02000000 +#define PAS_MAC_CFG_PCFG_PR 0x01000000 +#define PAS_MAC_CFG_PCFG_CRO_M 0x00ff0000 +#define PAS_MAC_CFG_PCFG_CRO_S 16 +#define PAS_MAC_CFG_PCFG_IPO_M 0x0000ff00 +#define PAS_MAC_CFG_PCFG_IPO_S 8 +#define PAS_MAC_CFG_PCFG_S1 0x00000080 +#define PAS_MAC_CFG_PCFG_IO_M 0x00000060 +#define PAS_MAC_CFG_PCFG_IO_MAC 0x00000000 +#define PAS_MAC_CFG_PCFG_IO_OFF 0x00000020 +#define PAS_MAC_CFG_PCFG_IO_IND_ETH 0x00000040 +#define PAS_MAC_CFG_PCFG_IO_IND_IP 0x00000060 +#define PAS_MAC_CFG_PCFG_LP 0x00000010 +#define PAS_MAC_CFG_PCFG_TS 0x00000008 +#define PAS_MAC_CFG_PCFG_HD 0x00000004 +#define PAS_MAC_CFG_PCFG_SPD_M 0x00000003 +#define PAS_MAC_CFG_PCFG_SPD_10M 0x00000000 +#define PAS_MAC_CFG_PCFG_SPD_100M 0x00000001 +#define PAS_MAC_CFG_PCFG_SPD_1G 0x00000002 +#define PAS_MAC_CFG_PCFG_SPD_10G 0x00000003 +#define PAS_MAC_CFG_TXP_FCF 0x01000000 +#define PAS_MAC_CFG_TXP_FCE 0x00800000 +#define PAS_MAC_CFG_TXP_FC 0x00400000 +#define PAS_MAC_CFG_TXP_FPC_M 0x00300000 +#define PAS_MAC_CFG_TXP_FPC_S 20 +#define PAS_MAC_CFG_TXP_FPC(x) (((x) << PAS_MAC_CFG_TXP_FPC_S) & \ + PAS_MAC_CFG_TXP_FPC_M) +#define PAS_MAC_CFG_TXP_RT 0x00080000 +#define PAS_MAC_CFG_TXP_BL 0x00040000 +#define PAS_MAC_CFG_TXP_SL_M 0x00030000 +#define PAS_MAC_CFG_TXP_SL_S 16 +#define PAS_MAC_CFG_TXP_SL(x) (((x) << PAS_MAC_CFG_TXP_SL_S) & \ + PAS_MAC_CFG_TXP_SL_M) +#define PAS_MAC_CFG_TXP_COB_M 0x0000f000 +#define PAS_MAC_CFG_TXP_COB_S 12 +#define PAS_MAC_CFG_TXP_COB(x) (((x) << PAS_MAC_CFG_TXP_COB_S) & \ + PAS_MAC_CFG_TXP_COB_M) +#define PAS_MAC_CFG_TXP_TIFT_M 0x00000f00 +#define PAS_MAC_CFG_TXP_TIFT_S 8 +#define PAS_MAC_CFG_TXP_TIFT(x) (((x) << PAS_MAC_CFG_TXP_TIFT_S) & \ + PAS_MAC_CFG_TXP_TIFT_M) +#define PAS_MAC_CFG_TXP_TIFG_M 0x000000ff +#define PAS_MAC_CFG_TXP_TIFG_S 0 +#define PAS_MAC_CFG_TXP_TIFG(x) (((x) << PAS_MAC_CFG_TXP_TIFG_S) & \ + PAS_MAC_CFG_TXP_TIFG_M) + +#define PAS_MAC_IPC_CHNL_DCHNO_M 0x003f0000 +#define PAS_MAC_IPC_CHNL_DCHNO_S 16 +#define PAS_MAC_IPC_CHNL_DCHNO(x) (((x) << PAS_MAC_IPC_CHNL_DCHNO_S) & \ + PAS_MAC_IPC_CHNL_DCHNO_M) +#define PAS_MAC_IPC_CHNL_BCH_M 0x0000003f +#define PAS_MAC_IPC_CHNL_BCH_S 0 +#define PAS_MAC_IPC_CHNL_BCH(x) (((x) << PAS_MAC_IPC_CHNL_BCH_S) & \ + PAS_MAC_IPC_CHNL_BCH_M) + +/* All these registers live in the PCI configuration space for the DMA PCI + * device. Use the normal PCI config access functions for them. + */ +enum { + PAS_DMA_COM_TXCMD = 0x100, /* Transmit Command Register */ + PAS_DMA_COM_TXSTA = 0x104, /* Transmit Status Register */ + PAS_DMA_COM_RXCMD = 0x108, /* Receive Command Register */ + PAS_DMA_COM_RXSTA = 0x10c, /* Receive Status Register */ +}; +#define PAS_DMA_COM_TXCMD_EN 0x00000001 /* enable */ +#define PAS_DMA_COM_TXSTA_ACT 0x00000001 /* active */ +#define PAS_DMA_COM_RXCMD_EN 0x00000001 /* enable */ +#define PAS_DMA_COM_RXSTA_ACT 0x00000001 /* active */ + + +/* Per-interface and per-channel registers */ +#define _PAS_DMA_RXINT_STRIDE 0x20 +#define PAS_DMA_RXINT_RCMDSTA(i) (0x200+(i)*_PAS_DMA_RXINT_STRIDE) +#define PAS_DMA_RXINT_RCMDSTA_EN 0x00000001 +#define PAS_DMA_RXINT_RCMDSTA_ST 0x00000002 +#define PAS_DMA_RXINT_RCMDSTA_OO 0x00000100 +#define PAS_DMA_RXINT_RCMDSTA_BP 0x00000200 +#define PAS_DMA_RXINT_RCMDSTA_DR 0x00000400 +#define PAS_DMA_RXINT_RCMDSTA_BT 0x00000800 +#define PAS_DMA_RXINT_RCMDSTA_TB 0x00001000 +#define PAS_DMA_RXINT_RCMDSTA_ACT 0x00010000 +#define PAS_DMA_RXINT_RCMDSTA_DROPS_M 0xfffe0000 +#define PAS_DMA_RXINT_RCMDSTA_DROPS_S 17 +#define PAS_DMA_RXINT_INCR(i) (0x210+(i)*_PAS_DMA_RXINT_STRIDE) +#define PAS_DMA_RXINT_INCR_INCR_M 0x0000ffff +#define PAS_DMA_RXINT_INCR_INCR_S 0 +#define PAS_DMA_RXINT_INCR_INCR(x) ((x) & 0x0000ffff) +#define PAS_DMA_RXINT_BASEL(i) (0x218+(i)*_PAS_DMA_RXINT_STRIDE) +#define PAS_DMA_RXINT_BASEL_BRBL(x) ((x) & ~0x3f) +#define PAS_DMA_RXINT_BASEU(i) (0x21c+(i)*_PAS_DMA_RXINT_STRIDE) +#define PAS_DMA_RXINT_BASEU_BRBH(x) ((x) & 0xfff) +#define PAS_DMA_RXINT_BASEU_SIZ_M 0x3fff0000 /* # of cache lines worth of buffer ring */ +#define PAS_DMA_RXINT_BASEU_SIZ_S 16 /* 0 = 16K */ +#define PAS_DMA_RXINT_BASEU_SIZ(x) (((x) << PAS_DMA_RXINT_BASEU_SIZ_S) & \ + PAS_DMA_RXINT_BASEU_SIZ_M) + + +#define _PAS_DMA_TXCHAN_STRIDE 0x20 /* Size per channel */ +#define _PAS_DMA_TXCHAN_TCMDSTA 0x300 /* Command / Status */ +#define _PAS_DMA_TXCHAN_CFG 0x304 /* Configuration */ +#define _PAS_DMA_TXCHAN_DSCRBU 0x308 /* Descriptor BU Allocation */ +#define _PAS_DMA_TXCHAN_INCR 0x310 /* Descriptor increment */ +#define _PAS_DMA_TXCHAN_CNT 0x314 /* Descriptor count/offset */ +#define _PAS_DMA_TXCHAN_BASEL 0x318 /* Descriptor ring base (low) */ +#define _PAS_DMA_TXCHAN_BASEU 0x31c /* (high) */ +#define PAS_DMA_TXCHAN_TCMDSTA(c) (0x300+(c)*_PAS_DMA_TXCHAN_STRIDE) +#define PAS_DMA_TXCHAN_TCMDSTA_EN 0x00000001 /* Enabled */ +#define PAS_DMA_TXCHAN_TCMDSTA_ST 0x00000002 /* Stop interface */ +#define PAS_DMA_TXCHAN_TCMDSTA_ACT 0x00010000 /* Active */ +#define PAS_DMA_TXCHAN_CFG(c) (0x304+(c)*_PAS_DMA_TXCHAN_STRIDE) +#define PAS_DMA_TXCHAN_CFG_TY_IFACE 0x00000000 /* Type = interface */ +#define PAS_DMA_TXCHAN_CFG_TATTR_M 0x0000003c +#define PAS_DMA_TXCHAN_CFG_TATTR_S 2 +#define PAS_DMA_TXCHAN_CFG_TATTR(x) (((x) << PAS_DMA_TXCHAN_CFG_TATTR_S) & \ + PAS_DMA_TXCHAN_CFG_TATTR_M) +#define PAS_DMA_TXCHAN_CFG_WT_M 0x000001c0 +#define PAS_DMA_TXCHAN_CFG_WT_S 6 +#define PAS_DMA_TXCHAN_CFG_WT(x) (((x) << PAS_DMA_TXCHAN_CFG_WT_S) & \ + PAS_DMA_TXCHAN_CFG_WT_M) +#define PAS_DMA_TXCHAN_CFG_CF 0x00001000 /* Clean first line */ +#define PAS_DMA_TXCHAN_CFG_CL 0x00002000 /* Clean last line */ +#define PAS_DMA_TXCHAN_CFG_UP 0x00004000 /* update tx descr when sent */ +#define PAS_DMA_TXCHAN_INCR(c) (0x310+(c)*_PAS_DMA_TXCHAN_STRIDE) +#define PAS_DMA_TXCHAN_BASEL(c) (0x318+(c)*_PAS_DMA_TXCHAN_STRIDE) +#define PAS_DMA_TXCHAN_BASEL_BRBL_M 0xffffffc0 +#define PAS_DMA_TXCHAN_BASEL_BRBL_S 0 +#define PAS_DMA_TXCHAN_BASEL_BRBL(x) (((x) << PAS_DMA_TXCHAN_BASEL_BRBL_S) & \ + PAS_DMA_TXCHAN_BASEL_BRBL_M) +#define PAS_DMA_TXCHAN_BASEU(c) (0x31c+(c)*_PAS_DMA_TXCHAN_STRIDE) +#define PAS_DMA_TXCHAN_BASEU_BRBH_M 0x00000fff +#define PAS_DMA_TXCHAN_BASEU_BRBH_S 0 +#define PAS_DMA_TXCHAN_BASEU_BRBH(x) (((x) << PAS_DMA_TXCHAN_BASEU_BRBH_S) & \ + PAS_DMA_TXCHAN_BASEU_BRBH_M) +/* # of cache lines worth of buffer ring */ +#define PAS_DMA_TXCHAN_BASEU_SIZ_M 0x3fff0000 +#define PAS_DMA_TXCHAN_BASEU_SIZ_S 16 /* 0 = 16K */ +#define PAS_DMA_TXCHAN_BASEU_SIZ(x) (((x) << PAS_DMA_TXCHAN_BASEU_SIZ_S) & \ + PAS_DMA_TXCHAN_BASEU_SIZ_M) + +#define _PAS_DMA_RXCHAN_STRIDE 0x20 /* Size per channel */ +#define _PAS_DMA_RXCHAN_CCMDSTA 0x800 /* Command / Status */ +#define _PAS_DMA_RXCHAN_CFG 0x804 /* Configuration */ +#define _PAS_DMA_RXCHAN_INCR 0x810 /* Descriptor increment */ +#define _PAS_DMA_RXCHAN_CNT 0x814 /* Descriptor count/offset */ +#define _PAS_DMA_RXCHAN_BASEL 0x818 /* Descriptor ring base (low) */ +#define _PAS_DMA_RXCHAN_BASEU 0x81c /* (high) */ +#define PAS_DMA_RXCHAN_CCMDSTA(c) (0x800+(c)*_PAS_DMA_RXCHAN_STRIDE) +#define PAS_DMA_RXCHAN_CCMDSTA_EN 0x00000001 /* Enabled */ +#define PAS_DMA_RXCHAN_CCMDSTA_ST 0x00000002 /* Stop interface */ +#define PAS_DMA_RXCHAN_CCMDSTA_ACT 0x00010000 /* Active */ +#define PAS_DMA_RXCHAN_CCMDSTA_DU 0x00020000 +#define PAS_DMA_RXCHAN_CFG(c) (0x804+(c)*_PAS_DMA_RXCHAN_STRIDE) +#define PAS_DMA_RXCHAN_CFG_HBU_M 0x00000380 +#define PAS_DMA_RXCHAN_CFG_HBU_S 7 +#define PAS_DMA_RXCHAN_CFG_HBU(x) (((x) << PAS_DMA_RXCHAN_CFG_HBU_S) & \ + PAS_DMA_RXCHAN_CFG_HBU_M) +#define PAS_DMA_RXCHAN_INCR(c) (0x810+(c)*_PAS_DMA_RXCHAN_STRIDE) +#define PAS_DMA_RXCHAN_BASEL(c) (0x818+(c)*_PAS_DMA_RXCHAN_STRIDE) +#define PAS_DMA_RXCHAN_BASEL_BRBL_M 0xffffffc0 +#define PAS_DMA_RXCHAN_BASEL_BRBL_S 0 +#define PAS_DMA_RXCHAN_BASEL_BRBL(x) (((x) << PAS_DMA_RXCHAN_BASEL_BRBL_S) & \ + PAS_DMA_RXCHAN_BASEL_BRBL_M) +#define PAS_DMA_RXCHAN_BASEU(c) (0x81c+(c)*_PAS_DMA_RXCHAN_STRIDE) +#define PAS_DMA_RXCHAN_BASEU_BRBH_M 0x00000fff +#define PAS_DMA_RXCHAN_BASEU_BRBH_S 0 +#define PAS_DMA_RXCHAN_BASEU_BRBH(x) (((x) << PAS_DMA_RXCHAN_BASEU_BRBH_S) & \ + PAS_DMA_RXCHAN_BASEU_BRBH_M) +/* # of cache lines worth of buffer ring */ +#define PAS_DMA_RXCHAN_BASEU_SIZ_M 0x3fff0000 +#define PAS_DMA_RXCHAN_BASEU_SIZ_S 16 /* 0 = 16K */ +#define PAS_DMA_RXCHAN_BASEU_SIZ(x) (((x) << PAS_DMA_RXCHAN_BASEU_SIZ_S) & \ + PAS_DMA_RXCHAN_BASEU_SIZ_M) + +#define PAS_STATUS_PCNT_M 0x000000000000ffffull +#define PAS_STATUS_PCNT_S 0 +#define PAS_STATUS_DCNT_M 0x00000000ffff0000ull +#define PAS_STATUS_DCNT_S 16 +#define PAS_STATUS_BPCNT_M 0x0000ffff00000000ull +#define PAS_STATUS_BPCNT_S 32 +#define PAS_STATUS_TIMER 0x1000000000000000ull +#define PAS_STATUS_ERROR 0x2000000000000000ull +#define PAS_STATUS_SOFT 0x4000000000000000ull +#define PAS_STATUS_INT 0x8000000000000000ull + +#define PAS_IOB_DMA_RXCH_CFG(i) (0x1100 + (i)*4) +#define PAS_IOB_DMA_RXCH_CFG_CNTTH_M 0x00000fff +#define PAS_IOB_DMA_RXCH_CFG_CNTTH_S 0 +#define PAS_IOB_DMA_RXCH_CFG_CNTTH(x) (((x) << PAS_IOB_DMA_RXCH_CFG_CNTTH_S) & \ + PAS_IOB_DMA_RXCH_CFG_CNTTH_M) +#define PAS_IOB_DMA_TXCH_CFG(i) (0x1200 + (i)*4) +#define PAS_IOB_DMA_TXCH_CFG_CNTTH_M 0x00000fff +#define PAS_IOB_DMA_TXCH_CFG_CNTTH_S 0 +#define PAS_IOB_DMA_TXCH_CFG_CNTTH(x) (((x) << PAS_IOB_DMA_TXCH_CFG_CNTTH_S) & \ + PAS_IOB_DMA_TXCH_CFG_CNTTH_M) +#define PAS_IOB_DMA_RXCH_STAT(i) (0x1300 + (i)*4) +#define PAS_IOB_DMA_RXCH_STAT_INTGEN 0x00001000 +#define PAS_IOB_DMA_RXCH_STAT_CNTDEL_M 0x00000fff +#define PAS_IOB_DMA_RXCH_STAT_CNTDEL_S 0 +#define PAS_IOB_DMA_RXCH_STAT_CNTDEL(x) (((x) << PAS_IOB_DMA_RXCH_STAT_CNTDEL_S) &\ + PAS_IOB_DMA_RXCH_STAT_CNTDEL_M) +#define PAS_IOB_DMA_TXCH_STAT(i) (0x1400 + (i)*4) +#define PAS_IOB_DMA_TXCH_STAT_INTGEN 0x00001000 +#define PAS_IOB_DMA_TXCH_STAT_CNTDEL_M 0x00000fff +#define PAS_IOB_DMA_TXCH_STAT_CNTDEL_S 0 +#define PAS_IOB_DMA_TXCH_STAT_CNTDEL(x) (((x) << PAS_IOB_DMA_TXCH_STAT_CNTDEL_S) &\ + PAS_IOB_DMA_TXCH_STAT_CNTDEL_M) +#define PAS_IOB_DMA_RXCH_RESET(i) (0x1500 + (i)*4) +#define PAS_IOB_DMA_RXCH_RESET_PCNT_M 0xffff0000 +#define PAS_IOB_DMA_RXCH_RESET_PCNT_S 0 +#define PAS_IOB_DMA_RXCH_RESET_PCNT(x) (((x) << PAS_IOB_DMA_RXCH_RESET_PCNT_S) & \ + PAS_IOB_DMA_RXCH_RESET_PCNT_M) +#define PAS_IOB_DMA_RXCH_RESET_PCNTRST 0x00000020 +#define PAS_IOB_DMA_RXCH_RESET_DCNTRST 0x00000010 +#define PAS_IOB_DMA_RXCH_RESET_TINTC 0x00000008 +#define PAS_IOB_DMA_RXCH_RESET_DINTC 0x00000004 +#define PAS_IOB_DMA_RXCH_RESET_SINTC 0x00000002 +#define PAS_IOB_DMA_RXCH_RESET_PINTC 0x00000001 +#define PAS_IOB_DMA_TXCH_RESET(i) (0x1600 + (i)*4) +#define PAS_IOB_DMA_TXCH_RESET_PCNT_M 0xffff0000 +#define PAS_IOB_DMA_TXCH_RESET_PCNT_S 0 +#define PAS_IOB_DMA_TXCH_RESET_PCNT(x) (((x) << PAS_IOB_DMA_TXCH_RESET_PCNT_S) & \ + PAS_IOB_DMA_TXCH_RESET_PCNT_M) +#define PAS_IOB_DMA_TXCH_RESET_PCNTRST 0x00000020 +#define PAS_IOB_DMA_TXCH_RESET_DCNTRST 0x00000010 +#define PAS_IOB_DMA_TXCH_RESET_TINTC 0x00000008 +#define PAS_IOB_DMA_TXCH_RESET_DINTC 0x00000004 +#define PAS_IOB_DMA_TXCH_RESET_SINTC 0x00000002 +#define PAS_IOB_DMA_TXCH_RESET_PINTC 0x00000001 + +#define PAS_IOB_DMA_COM_TIMEOUTCFG 0x1700 +#define PAS_IOB_DMA_COM_TIMEOUTCFG_TCNT_M 0x00ffffff +#define PAS_IOB_DMA_COM_TIMEOUTCFG_TCNT_S 0 +#define PAS_IOB_DMA_COM_TIMEOUTCFG_TCNT(x) (((x) << PAS_IOB_DMA_COM_TIMEOUTCFG_TCNT_S) & \ + PAS_IOB_DMA_COM_TIMEOUTCFG_TCNT_M) + +/* Transmit descriptor fields */ +#define XCT_MACTX_T 0x8000000000000000ull +#define XCT_MACTX_ST 0x4000000000000000ull +#define XCT_MACTX_NORES 0x0000000000000000ull +#define XCT_MACTX_8BRES 0x1000000000000000ull +#define XCT_MACTX_24BRES 0x2000000000000000ull +#define XCT_MACTX_40BRES 0x3000000000000000ull +#define XCT_MACTX_I 0x0800000000000000ull +#define XCT_MACTX_O 0x0400000000000000ull +#define XCT_MACTX_E 0x0200000000000000ull +#define XCT_MACTX_VLAN_M 0x0180000000000000ull +#define XCT_MACTX_VLAN_NOP 0x0000000000000000ull +#define XCT_MACTX_VLAN_REMOVE 0x0080000000000000ull +#define XCT_MACTX_VLAN_INSERT 0x0100000000000000ull +#define XCT_MACTX_VLAN_REPLACE 0x0180000000000000ull +#define XCT_MACTX_CRC_M 0x0060000000000000ull +#define XCT_MACTX_CRC_NOP 0x0000000000000000ull +#define XCT_MACTX_CRC_INSERT 0x0020000000000000ull +#define XCT_MACTX_CRC_PAD 0x0040000000000000ull +#define XCT_MACTX_CRC_REPLACE 0x0060000000000000ull +#define XCT_MACTX_SS 0x0010000000000000ull +#define XCT_MACTX_LLEN_M 0x00007fff00000000ull +#define XCT_MACTX_LLEN_S 32ull +#define XCT_MACTX_LLEN(x) ((((long)(x)) << XCT_MACTX_LLEN_S) & \ + XCT_MACTX_LLEN_M) +#define XCT_MACTX_IPH_M 0x00000000f8000000ull +#define XCT_MACTX_IPH_S 27ull +#define XCT_MACTX_IPH(x) ((((long)(x)) << XCT_MACTX_IPH_S) & \ + XCT_MACTX_IPH_M) +#define XCT_MACTX_IPO_M 0x0000000007c00000ull +#define XCT_MACTX_IPO_S 22ull +#define XCT_MACTX_IPO(x) ((((long)(x)) << XCT_MACTX_IPO_S) & \ + XCT_MACTX_IPO_M) +#define XCT_MACTX_CSUM_M 0x0000000000000060ull +#define XCT_MACTX_CSUM_NOP 0x0000000000000000ull +#define XCT_MACTX_CSUM_TCP 0x0000000000000040ull +#define XCT_MACTX_CSUM_UDP 0x0000000000000060ull +#define XCT_MACTX_V6 0x0000000000000010ull +#define XCT_MACTX_C 0x0000000000000004ull +#define XCT_MACTX_AL2 0x0000000000000002ull + +/* Receive descriptor fields */ +#define XCT_MACRX_T 0x8000000000000000ull +#define XCT_MACRX_ST 0x4000000000000000ull +#define XCT_MACRX_NORES 0x0000000000000000ull +#define XCT_MACRX_8BRES 0x1000000000000000ull +#define XCT_MACRX_24BRES 0x2000000000000000ull +#define XCT_MACRX_40BRES 0x3000000000000000ull +#define XCT_MACRX_O 0x0400000000000000ull +#define XCT_MACRX_E 0x0200000000000000ull +#define XCT_MACRX_FF 0x0100000000000000ull +#define XCT_MACRX_PF 0x0080000000000000ull +#define XCT_MACRX_OB 0x0040000000000000ull +#define XCT_MACRX_OD 0x0020000000000000ull +#define XCT_MACRX_FS 0x0010000000000000ull +#define XCT_MACRX_NB_M 0x000fc00000000000ull +#define XCT_MACRX_NB_S 46ULL +#define XCT_MACRX_NB(x) ((((long)(x)) << XCT_MACRX_NB_S) & \ + XCT_MACRX_NB_M) +#define XCT_MACRX_LLEN_M 0x00003fff00000000ull +#define XCT_MACRX_LLEN_S 32ULL +#define XCT_MACRX_LLEN(x) ((((long)(x)) << XCT_MACRX_LLEN_S) & \ + XCT_MACRX_LLEN_M) +#define XCT_MACRX_CRC 0x0000000080000000ull +#define XCT_MACRX_LEN_M 0x0000000060000000ull +#define XCT_MACRX_LEN_TOOSHORT 0x0000000020000000ull +#define XCT_MACRX_LEN_BELOWMIN 0x0000000040000000ull +#define XCT_MACRX_LEN_TRUNC 0x0000000060000000ull +#define XCT_MACRX_CAST_M 0x0000000018000000ull +#define XCT_MACRX_CAST_UNI 0x0000000000000000ull +#define XCT_MACRX_CAST_MULTI 0x0000000008000000ull +#define XCT_MACRX_CAST_BROAD 0x0000000010000000ull +#define XCT_MACRX_CAST_PAUSE 0x0000000018000000ull +#define XCT_MACRX_VLC_M 0x0000000006000000ull +#define XCT_MACRX_FM 0x0000000001000000ull +#define XCT_MACRX_HTY_M 0x0000000000c00000ull +#define XCT_MACRX_HTY_IPV4_OK 0x0000000000000000ull +#define XCT_MACRX_HTY_IPV6 0x0000000000400000ull +#define XCT_MACRX_HTY_IPV4_BAD 0x0000000000800000ull +#define XCT_MACRX_HTY_NONIP 0x0000000000c00000ull +#define XCT_MACRX_IPP_M 0x00000000003f0000ull +#define XCT_MACRX_IPP_S 16 +#define XCT_MACRX_CSUM_M 0x000000000000ffffull +#define XCT_MACRX_CSUM_S 0 + +#define XCT_PTR_T 0x8000000000000000ull +#define XCT_PTR_LEN_M 0x7ffff00000000000ull +#define XCT_PTR_LEN_S 44 +#define XCT_PTR_LEN(x) ((((long)(x)) << XCT_PTR_LEN_S) & \ + XCT_PTR_LEN_M) +#define XCT_PTR_ADDR_M 0x00000fffffffffffull +#define XCT_PTR_ADDR_S 0 +#define XCT_PTR_ADDR(x) ((((long)(x)) << XCT_PTR_ADDR_S) & \ + XCT_PTR_ADDR_M) + +/* Receive interface buffer fields */ +#define XCT_RXB_LEN_M 0x0ffff00000000000ull +#define XCT_RXB_LEN_S 44 +#define XCT_RXB_LEN(x) ((((long)(x)) << XCT_PTR_LEN_S) & XCT_PTR_LEN_M) +#define XCT_RXB_ADDR_M 0x00000fffffffffffull +#define XCT_RXB_ADDR_S 0 +#define XCT_RXB_ADDR(x) ((((long)(x)) << XCT_PTR_ADDR_S) & XCT_PTR_ADDR_M) + + +#endif /* PASEMI_MAC_H */ diff --git a/drivers/net/phy/cicada.c b/drivers/net/phy/cicada.c index ae60e6e..a1bd599 100644 --- a/drivers/net/phy/cicada.c +++ b/drivers/net/phy/cicada.c @@ -14,7 +14,6 @@ * */ #include -#include #include #include #include diff --git a/drivers/net/phy/davicom.c b/drivers/net/phy/davicom.c index aa7983f..519baa3 100644 --- a/drivers/net/phy/davicom.c +++ b/drivers/net/phy/davicom.c @@ -14,7 +14,6 @@ * */ #include -#include #include #include #include diff --git a/drivers/net/phy/fixed.c b/drivers/net/phy/fixed.c index 8613539..66da91b 100644 --- a/drivers/net/phy/fixed.c +++ b/drivers/net/phy/fixed.c @@ -14,7 +14,6 @@ * */ #include -#include #include #include #include diff --git a/drivers/net/phy/lxt.c b/drivers/net/phy/lxt.c index 69d2325..4cf3324 100644 --- a/drivers/net/phy/lxt.c +++ b/drivers/net/phy/lxt.c @@ -14,7 +14,6 @@ * */ #include -#include #include #include #include diff --git a/drivers/net/phy/marvell.c b/drivers/net/phy/marvell.c index 0ad2532..f4d4eb6 100644 --- a/drivers/net/phy/marvell.c +++ b/drivers/net/phy/marvell.c @@ -14,7 +14,6 @@ * */ #include -#include #include #include #include diff --git a/drivers/net/phy/mdio_bus.c b/drivers/net/phy/mdio_bus.c index cf6660c..b31ce27 100644 --- a/drivers/net/phy/mdio_bus.c +++ b/drivers/net/phy/mdio_bus.c @@ -14,7 +14,6 @@ * */ #include -#include #include #include #include diff --git a/drivers/net/phy/phy.c b/drivers/net/phy/phy.c index 9765fa6..c94a1fb 100644 --- a/drivers/net/phy/phy.c +++ b/drivers/net/phy/phy.c @@ -16,7 +16,6 @@ * */ #include -#include #include #include #include diff --git a/drivers/net/phy/phy_device.c b/drivers/net/phy/phy_device.c index a4d7529..fdf45fd 100644 --- a/drivers/net/phy/phy_device.c +++ b/drivers/net/phy/phy_device.c @@ -15,7 +15,6 @@ * */ #include -#include #include #include #include diff --git a/drivers/net/phy/qsemi.c b/drivers/net/phy/qsemi.c index 2b50e17..23062d0 100644 --- a/drivers/net/phy/qsemi.c +++ b/drivers/net/phy/qsemi.c @@ -14,7 +14,6 @@ * */ #include -#include #include #include #include diff --git a/drivers/net/ppp_generic.c b/drivers/net/ppp_generic.c index c6de566..11b575f 100644 --- a/drivers/net/ppp_generic.c +++ b/drivers/net/ppp_generic.c @@ -83,7 +83,7 @@ struct ppp_file { int dead; /* unit/channel has been shut down */ }; -#define PF_TO_X(pf, X) ((X *)((char *)(pf) - offsetof(X, file))) +#define PF_TO_X(pf, X) container_of(pf, X, file) #define PF_TO_PPP(pf) PF_TO_X(pf, struct ppp) #define PF_TO_CHANNEL(pf) PF_TO_X(pf, struct channel) @@ -834,7 +834,7 @@ static int ppp_unattached_ioctl(struct p return err; } -static struct file_operations ppp_device_fops = { +static const struct file_operations ppp_device_fops = { .owner = THIS_MODULE, .read = ppp_read, .write = ppp_write, diff --git a/drivers/net/pppoe.c b/drivers/net/pppoe.c index 315d5c3..860bb0f 100644 --- a/drivers/net/pppoe.c +++ b/drivers/net/pppoe.c @@ -1043,7 +1043,7 @@ static int pppoe_seq_open(struct inode * return seq_open(file, &pppoe_seq_ops); } -static struct file_operations pppoe_seq_fops = { +static const struct file_operations pppoe_seq_fops = { .owner = THIS_MODULE, .open = pppoe_seq_open, .read = seq_read, diff --git a/drivers/net/qla3xxx.c b/drivers/net/qla3xxx.c old mode 100644 new mode 100755 index 8844c20..a142cdf --- a/drivers/net/qla3xxx.c +++ b/drivers/net/qla3xxx.c @@ -22,6 +22,7 @@ #include #include #include #include +#include #include #include #include @@ -63,6 +64,7 @@ MODULE_PARM_DESC(msi, "Turn on Message S static struct pci_device_id ql3xxx_pci_tbl[] __devinitdata = { {PCI_DEVICE(PCI_VENDOR_ID_QLOGIC, QL3022_DEVICE_ID)}, + {PCI_DEVICE(PCI_VENDOR_ID_QLOGIC, QL3032_DEVICE_ID)}, /* required last entry */ {0,} }; @@ -1475,6 +1477,10 @@ static int ql_mii_setup(struct ql3_adapt 2) << 7)) return -1; + if (qdev->device_id == QL3032_DEVICE_ID) + ql_write_page0_reg(qdev, + &port_regs->macMIIMgmtControlReg, 0x0f00000); + /* Divide 125MHz clock by 28 to meet PHY timing requirements */ reg = MAC_MII_CONTROL_CLK_SEL_DIV28; @@ -1706,18 +1712,42 @@ static void ql_process_mac_tx_intr(struc struct ob_mac_iocb_rsp *mac_rsp) { struct ql_tx_buf_cb *tx_cb; + int i; tx_cb = &qdev->tx_buf[mac_rsp->transaction_id]; pci_unmap_single(qdev->pdev, - pci_unmap_addr(tx_cb, mapaddr), - pci_unmap_len(tx_cb, maplen), PCI_DMA_TODEVICE); - dev_kfree_skb_irq(tx_cb->skb); + pci_unmap_addr(&tx_cb->map[0], mapaddr), + pci_unmap_len(&tx_cb->map[0], maplen), + PCI_DMA_TODEVICE); + tx_cb->seg_count--; + if (tx_cb->seg_count) { + for (i = 1; i < tx_cb->seg_count; i++) { + pci_unmap_page(qdev->pdev, + pci_unmap_addr(&tx_cb->map[i], + mapaddr), + pci_unmap_len(&tx_cb->map[i], maplen), + PCI_DMA_TODEVICE); + } + } qdev->stats.tx_packets++; qdev->stats.tx_bytes += tx_cb->skb->len; + dev_kfree_skb_irq(tx_cb->skb); tx_cb->skb = NULL; atomic_inc(&qdev->tx_count); } +/* + * The difference between 3022 and 3032 for inbound completions: + * 3022 uses two buffers per completion. The first buffer contains + * (some) header info, the second the remainder of the headers plus + * the data. For this chip we reserve some space at the top of the + * receive buffer so that the header info in buffer one can be + * prepended to the buffer two. Buffer two is the sent up while + * buffer one is returned to the hardware to be reused. + * 3032 receives all of it's data and headers in one buffer for a + * simpler process. 3032 also supports checksum verification as + * can be seen in ql_process_macip_rx_intr(). + */ static void ql_process_mac_rx_intr(struct ql3_adapter *qdev, struct ib_mac_iocb_rsp *ib_mac_rsp_ptr) { @@ -1740,14 +1770,17 @@ static void ql_process_mac_rx_intr(struc qdev->last_rsp_offset = qdev->small_buf_phy_addr_low + offset; qdev->small_buf_release_cnt++; - /* start of first buffer */ - lrg_buf_phy_addr_low = le32_to_cpu(*curr_ial_ptr); - lrg_buf_cb1 = &qdev->lrg_buf[qdev->lrg_buf_index]; - qdev->lrg_buf_release_cnt++; - if (++qdev->lrg_buf_index == NUM_LARGE_BUFFERS) - qdev->lrg_buf_index = 0; - curr_ial_ptr++; /* 64-bit pointers require two incs. */ - curr_ial_ptr++; + if (qdev->device_id == QL3022_DEVICE_ID) { + /* start of first buffer (3022 only) */ + lrg_buf_phy_addr_low = le32_to_cpu(*curr_ial_ptr); + lrg_buf_cb1 = &qdev->lrg_buf[qdev->lrg_buf_index]; + qdev->lrg_buf_release_cnt++; + if (++qdev->lrg_buf_index == NUM_LARGE_BUFFERS) { + qdev->lrg_buf_index = 0; + } + curr_ial_ptr++; /* 64-bit pointers require two incs. */ + curr_ial_ptr++; + } /* start of second buffer */ lrg_buf_phy_addr_low = le32_to_cpu(*curr_ial_ptr); @@ -1778,7 +1811,8 @@ static void ql_process_mac_rx_intr(struc qdev->ndev->last_rx = jiffies; lrg_buf_cb2->skb = NULL; - ql_release_to_lrg_buf_free_list(qdev, lrg_buf_cb1); + if (qdev->device_id == QL3022_DEVICE_ID) + ql_release_to_lrg_buf_free_list(qdev, lrg_buf_cb1); ql_release_to_lrg_buf_free_list(qdev, lrg_buf_cb2); } @@ -1790,7 +1824,7 @@ static void ql_process_macip_rx_intr(str struct ql_rcv_buf_cb *lrg_buf_cb1 = NULL; struct ql_rcv_buf_cb *lrg_buf_cb2 = NULL; u32 *curr_ial_ptr; - struct sk_buff *skb1, *skb2; + struct sk_buff *skb1 = NULL, *skb2; struct net_device *ndev = qdev->ndev; u16 length = le16_to_cpu(ib_ip_rsp_ptr->length); u16 size = 0; @@ -1806,16 +1840,20 @@ static void ql_process_macip_rx_intr(str qdev->last_rsp_offset = qdev->small_buf_phy_addr_low + offset; qdev->small_buf_release_cnt++; - /* start of first buffer */ - lrg_buf_phy_addr_low = le32_to_cpu(*curr_ial_ptr); - lrg_buf_cb1 = &qdev->lrg_buf[qdev->lrg_buf_index]; - - qdev->lrg_buf_release_cnt++; - if (++qdev->lrg_buf_index == NUM_LARGE_BUFFERS) - qdev->lrg_buf_index = 0; - skb1 = lrg_buf_cb1->skb; - curr_ial_ptr++; /* 64-bit pointers require two incs. */ - curr_ial_ptr++; + if (qdev->device_id == QL3022_DEVICE_ID) { + /* start of first buffer on 3022 */ + lrg_buf_phy_addr_low = le32_to_cpu(*curr_ial_ptr); + lrg_buf_cb1 = &qdev->lrg_buf[qdev->lrg_buf_index]; + qdev->lrg_buf_release_cnt++; + if (++qdev->lrg_buf_index == NUM_LARGE_BUFFERS) + qdev->lrg_buf_index = 0; + skb1 = lrg_buf_cb1->skb; + curr_ial_ptr++; /* 64-bit pointers require two incs. */ + curr_ial_ptr++; + size = ETH_HLEN; + if (*((u16 *) skb1->data) != 0xFFFF) + size += VLAN_ETH_HLEN - ETH_HLEN; + } /* start of second buffer */ lrg_buf_phy_addr_low = le32_to_cpu(*curr_ial_ptr); @@ -1825,18 +1863,6 @@ static void ql_process_macip_rx_intr(str if (++qdev->lrg_buf_index == NUM_LARGE_BUFFERS) qdev->lrg_buf_index = 0; - qdev->stats.rx_packets++; - qdev->stats.rx_bytes += length; - - /* - * Copy the ethhdr from first buffer to second. This - * is necessary for IP completions. - */ - if (*((u16 *) skb1->data) != 0xFFFF) - size = VLAN_ETH_HLEN; - else - size = ETH_HLEN; - skb_put(skb2, length); /* Just the second buffer length here. */ pci_unmap_single(qdev->pdev, pci_unmap_addr(lrg_buf_cb2, mapaddr), @@ -1844,16 +1870,40 @@ static void ql_process_macip_rx_intr(str PCI_DMA_FROMDEVICE); prefetch(skb2->data); - memcpy(skb_push(skb2, size), skb1->data + VLAN_ID_LEN, size); - skb2->dev = qdev->ndev; skb2->ip_summed = CHECKSUM_NONE; + if (qdev->device_id == QL3022_DEVICE_ID) { + /* + * Copy the ethhdr from first buffer to second. This + * is necessary for 3022 IP completions. + */ + memcpy(skb_push(skb2, size), skb1->data + VLAN_ID_LEN, size); + } else { + u16 checksum = le16_to_cpu(ib_ip_rsp_ptr->checksum); + if (checksum & + (IB_IP_IOCB_RSP_3032_ICE | + IB_IP_IOCB_RSP_3032_CE | + IB_IP_IOCB_RSP_3032_NUC)) { + printk(KERN_ERR + "%s: Bad checksum for this %s packet, checksum = %x.\n", + __func__, + ((checksum & + IB_IP_IOCB_RSP_3032_TCP) ? "TCP" : + "UDP"),checksum); + } else if (checksum & IB_IP_IOCB_RSP_3032_TCP) { + skb2->ip_summed = CHECKSUM_UNNECESSARY; + } + } + skb2->dev = qdev->ndev; skb2->protocol = eth_type_trans(skb2, qdev->ndev); netif_receive_skb(skb2); + qdev->stats.rx_packets++; + qdev->stats.rx_bytes += length; ndev->last_rx = jiffies; lrg_buf_cb2->skb = NULL; - ql_release_to_lrg_buf_free_list(qdev, lrg_buf_cb1); + if (qdev->device_id == QL3022_DEVICE_ID) + ql_release_to_lrg_buf_free_list(qdev, lrg_buf_cb1); ql_release_to_lrg_buf_free_list(qdev, lrg_buf_cb2); } @@ -1880,12 +1930,14 @@ static int ql_tx_rx_clean(struct ql3_ada break; case OPCODE_IB_MAC_IOCB: + case OPCODE_IB_3032_MAC_IOCB: ql_process_mac_rx_intr(qdev, (struct ib_mac_iocb_rsp *) net_rsp); (*rx_cleaned)++; break; case OPCODE_IB_IP_IOCB: + case OPCODE_IB_3032_IP_IOCB: ql_process_macip_rx_intr(qdev, (struct ib_ip_iocb_rsp *) net_rsp); (*rx_cleaned)++; @@ -2032,13 +2084,96 @@ static irqreturn_t ql3xxx_isr(int irq, v return IRQ_RETVAL(handled); } +/* + * Get the total number of segments needed for the + * given number of fragments. This is necessary because + * outbound address lists (OAL) will be used when more than + * two frags are given. Each address list has 5 addr/len + * pairs. The 5th pair in each AOL is used to point to + * the next AOL if more frags are coming. + * That is why the frags:segment count ratio is not linear. + */ +static int ql_get_seg_count(unsigned short frags) +{ + switch(frags) { + case 0: return 1; /* just the skb->data seg */ + case 1: return 2; /* skb->data + 1 frag */ + case 2: return 3; /* skb->data + 2 frags */ + case 3: return 5; /* skb->data + 1 frag + 1 AOL containting 2 frags */ + case 4: return 6; + case 5: return 7; + case 6: return 8; + case 7: return 10; + case 8: return 11; + case 9: return 12; + case 10: return 13; + case 11: return 15; + case 12: return 16; + case 13: return 17; + case 14: return 18; + case 15: return 20; + case 16: return 21; + case 17: return 22; + case 18: return 23; + } + return -1; +} + +static void ql_hw_csum_setup(struct sk_buff *skb, + struct ob_mac_iocb_req *mac_iocb_ptr) +{ + struct ethhdr *eth; + struct iphdr *ip = NULL; + u8 offset = ETH_HLEN; + + eth = (struct ethhdr *)(skb->data); + + if (eth->h_proto == __constant_htons(ETH_P_IP)) { + ip = (struct iphdr *)&skb->data[ETH_HLEN]; + } else if (eth->h_proto == htons(ETH_P_8021Q) && + ((struct vlan_ethhdr *)skb->data)-> + h_vlan_encapsulated_proto == __constant_htons(ETH_P_IP)) { + ip = (struct iphdr *)&skb->data[VLAN_ETH_HLEN]; + offset = VLAN_ETH_HLEN; + } + + if (ip) { + if (ip->protocol == IPPROTO_TCP) { + mac_iocb_ptr->flags1 |= OB_3032MAC_IOCB_REQ_TC; + mac_iocb_ptr->ip_hdr_off = offset; + mac_iocb_ptr->ip_hdr_len = ip->ihl; + } else if (ip->protocol == IPPROTO_UDP) { + mac_iocb_ptr->flags1 |= OB_3032MAC_IOCB_REQ_UC; + mac_iocb_ptr->ip_hdr_off = offset; + mac_iocb_ptr->ip_hdr_len = ip->ihl; + } + } +} + +/* + * The difference between 3022 and 3032 sends: + * 3022 only supports a simple single segment transmission. + * 3032 supports checksumming and scatter/gather lists (fragments). + * The 3032 supports sglists by using the 3 addr/len pairs (ALP) + * in the IOCB plus a chain of outbound address lists (OAL) that + * each contain 5 ALPs. The last ALP of the IOCB (3rd) or OAL (5th) + * will used to point to an OAL when more ALP entries are required. + * The IOCB is always the top of the chain followed by one or more + * OALs (when necessary). + */ static int ql3xxx_send(struct sk_buff *skb, struct net_device *ndev) { struct ql3_adapter *qdev = (struct ql3_adapter *)netdev_priv(ndev); struct ql3xxx_port_registers __iomem *port_regs = qdev->mem_map_registers; struct ql_tx_buf_cb *tx_cb; + u32 tot_len = skb->len; + struct oal *oal; + struct oal_entry *oal_entry; + int len; struct ob_mac_iocb_req *mac_iocb_ptr; u64 map; + int seg_cnt, seg = 0; + int frag_cnt = (int)skb_shinfo(skb)->nr_frags; if (unlikely(atomic_read(&qdev->tx_count) < 2)) { if (!netif_queue_stopped(ndev)) @@ -2046,21 +2181,79 @@ static int ql3xxx_send(struct sk_buff *s return NETDEV_TX_BUSY; } tx_cb = &qdev->tx_buf[qdev->req_producer_index] ; + seg_cnt = tx_cb->seg_count = ql_get_seg_count((skb_shinfo(skb)->nr_frags)); + if(seg_cnt == -1) { + printk(KERN_ERR PFX"%s: invalid segment count!\n",__func__); + return NETDEV_TX_OK; + + } mac_iocb_ptr = tx_cb->queue_entry; memset((void *)mac_iocb_ptr, 0, sizeof(struct ob_mac_iocb_req)); mac_iocb_ptr->opcode = qdev->mac_ob_opcode; mac_iocb_ptr->flags |= qdev->mb_bit_mask; mac_iocb_ptr->transaction_id = qdev->req_producer_index; - mac_iocb_ptr->data_len = cpu_to_le16((u16) skb->len); + mac_iocb_ptr->data_len = cpu_to_le16((u16) tot_len); tx_cb->skb = skb; - map = pci_map_single(qdev->pdev, skb->data, skb->len, PCI_DMA_TODEVICE); - mac_iocb_ptr->buf_addr0_low = cpu_to_le32(LS_64BITS(map)); - mac_iocb_ptr->buf_addr0_high = cpu_to_le32(MS_64BITS(map)); - mac_iocb_ptr->buf_0_len = cpu_to_le32(skb->len | OB_MAC_IOCB_REQ_E); - pci_unmap_addr_set(tx_cb, mapaddr, map); - pci_unmap_len_set(tx_cb, maplen, skb->len); - atomic_dec(&qdev->tx_count); + if (skb->ip_summed == CHECKSUM_PARTIAL) + ql_hw_csum_setup(skb, mac_iocb_ptr); + len = skb_headlen(skb); + map = pci_map_single(qdev->pdev, skb->data, len, PCI_DMA_TODEVICE); + oal_entry = (struct oal_entry *)&mac_iocb_ptr->buf_addr0_low; + oal_entry->dma_lo = cpu_to_le32(LS_64BITS(map)); + oal_entry->dma_hi = cpu_to_le32(MS_64BITS(map)); + oal_entry->len = cpu_to_le32(len); + pci_unmap_addr_set(&tx_cb->map[seg], mapaddr, map); + pci_unmap_len_set(&tx_cb->map[seg], maplen, len); + seg++; + + if (!skb_shinfo(skb)->nr_frags) { + /* Terminate the last segment. */ + oal_entry->len = + cpu_to_le32(le32_to_cpu(oal_entry->len) | OAL_LAST_ENTRY); + } else { + int i; + oal = tx_cb->oal; + for (i=0; ifrags[i]; + oal_entry++; + if ((seg == 2 && seg_cnt > 3) || /* Check for continuation */ + (seg == 7 && seg_cnt > 8) || /* requirements. It's strange */ + (seg == 12 && seg_cnt > 13) || /* but necessary. */ + (seg == 17 && seg_cnt > 18)) { + /* Continuation entry points to outbound address list. */ + map = pci_map_single(qdev->pdev, oal, + sizeof(struct oal), + PCI_DMA_TODEVICE); + oal_entry->dma_lo = cpu_to_le32(LS_64BITS(map)); + oal_entry->dma_hi = cpu_to_le32(MS_64BITS(map)); + oal_entry->len = + cpu_to_le32(sizeof(struct oal) | + OAL_CONT_ENTRY); + pci_unmap_addr_set(&tx_cb->map[seg], mapaddr, + map); + pci_unmap_len_set(&tx_cb->map[seg], maplen, + len); + oal_entry = (struct oal_entry *)oal; + oal++; + seg++; + } + map = + pci_map_page(qdev->pdev, frag->page, + frag->page_offset, frag->size, + PCI_DMA_TODEVICE); + oal_entry->dma_lo = cpu_to_le32(LS_64BITS(map)); + oal_entry->dma_hi = cpu_to_le32(MS_64BITS(map)); + oal_entry->len = cpu_to_le32(frag->size); + pci_unmap_addr_set(&tx_cb->map[seg], mapaddr, map); + pci_unmap_len_set(&tx_cb->map[seg], maplen, + frag->size); + } + /* Terminate the last segment. */ + oal_entry->len = + cpu_to_le32(le32_to_cpu(oal_entry->len) | OAL_LAST_ENTRY); + } + wmb(); qdev->req_producer_index++; if (qdev->req_producer_index == NUM_REQ_Q_ENTRIES) qdev->req_producer_index = 0; @@ -2074,8 +2267,10 @@ static int ql3xxx_send(struct sk_buff *s printk(KERN_DEBUG PFX "%s: tx queued, slot %d, len %d\n", ndev->name, qdev->req_producer_index, skb->len); + atomic_dec(&qdev->tx_count); return NETDEV_TX_OK; } + static int ql_alloc_net_req_rsp_queues(struct ql3_adapter *qdev) { qdev->req_q_size = @@ -2359,7 +2554,22 @@ static int ql_alloc_large_buffers(struct return 0; } -static void ql_create_send_free_list(struct ql3_adapter *qdev) +static void ql_free_send_free_list(struct ql3_adapter *qdev) +{ + struct ql_tx_buf_cb *tx_cb; + int i; + + tx_cb = &qdev->tx_buf[0]; + for (i = 0; i < NUM_REQ_Q_ENTRIES; i++) { + if (tx_cb->oal) { + kfree(tx_cb->oal); + tx_cb->oal = NULL; + } + tx_cb++; + } +} + +static int ql_create_send_free_list(struct ql3_adapter *qdev) { struct ql_tx_buf_cb *tx_cb; int i; @@ -2368,11 +2578,16 @@ static void ql_create_send_free_list(str /* Create free list of transmit buffers */ for (i = 0; i < NUM_REQ_Q_ENTRIES; i++) { + tx_cb = &qdev->tx_buf[i]; tx_cb->skb = NULL; tx_cb->queue_entry = req_q_curr; req_q_curr++; + tx_cb->oal = kmalloc(512, GFP_KERNEL); + if (tx_cb->oal == NULL) + return -1; } + return 0; } static int ql_alloc_mem_resources(struct ql3_adapter *qdev) @@ -2447,12 +2662,14 @@ static int ql_alloc_mem_resources(struct /* Initialize the large buffer queue. */ ql_init_large_buffers(qdev); - ql_create_send_free_list(qdev); + if (ql_create_send_free_list(qdev)) + goto err_free_list; qdev->rsp_current = qdev->rsp_q_virt_addr; return 0; - +err_free_list: + ql_free_send_free_list(qdev); err_small_buffers: ql_free_buffer_queues(qdev); err_buffer_queues: @@ -2468,6 +2685,7 @@ err_req_rsp: static void ql_free_mem_resources(struct ql3_adapter *qdev) { + ql_free_send_free_list(qdev); ql_free_large_buffers(qdev); ql_free_small_buffers(qdev); ql_free_buffer_queues(qdev); @@ -2766,11 +2984,20 @@ static int ql_adapter_initialize(struct } /* Enable Ethernet Function */ - value = - (PORT_CONTROL_EF | PORT_CONTROL_ET | PORT_CONTROL_EI | - PORT_CONTROL_HH); - ql_write_page0_reg(qdev, &port_regs->portControl, - ((value << 16) | value)); + if (qdev->device_id == QL3032_DEVICE_ID) { + value = + (QL3032_PORT_CONTROL_EF | QL3032_PORT_CONTROL_KIE | + QL3032_PORT_CONTROL_EIv6 | QL3032_PORT_CONTROL_EIv4); + ql_write_page0_reg(qdev, &port_regs->functionControl, + ((value << 16) | value)); + } else { + value = + (PORT_CONTROL_EF | PORT_CONTROL_ET | PORT_CONTROL_EI | + PORT_CONTROL_HH); + ql_write_page0_reg(qdev, &port_regs->portControl, + ((value << 16) | value)); + } + out: return status; @@ -2917,8 +3144,10 @@ static void ql_display_dev_info(struct n struct pci_dev *pdev = qdev->pdev; printk(KERN_INFO PFX - "\n%s Adapter %d RevisionID %d found on PCI slot %d.\n", - DRV_NAME, qdev->index, qdev->chip_rev_id, qdev->pci_slot); + "\n%s Adapter %d RevisionID %d found %s on PCI slot %d.\n", + DRV_NAME, qdev->index, qdev->chip_rev_id, + (qdev->device_id == QL3032_DEVICE_ID) ? "QLA3032" : "QLA3022", + qdev->pci_slot); printk(KERN_INFO PFX "%s Interface.\n", test_bit(QL_LINK_OPTICAL,&qdev->flags) ? "OPTICAL" : "COPPER"); @@ -2999,7 +3228,7 @@ static int ql_adapter_up(struct ql3_adap { struct net_device *ndev = qdev->ndev; int err; - unsigned long irq_flags = SA_SAMPLE_RANDOM | SA_SHIRQ; + unsigned long irq_flags = IRQF_SAMPLE_RANDOM | IRQF_SHARED; unsigned long hw_flags; if (ql_alloc_mem_resources(qdev)) { @@ -3018,7 +3247,7 @@ static int ql_adapter_up(struct ql3_adap } else { printk(KERN_INFO PFX "%s: MSI Enabled...\n", qdev->ndev->name); set_bit(QL_MSI_ENABLED,&qdev->flags); - irq_flags &= ~SA_SHIRQ; + irq_flags &= ~IRQF_SHARED; } } @@ -3212,15 +3441,22 @@ static void ql_reset_work(struct work_st * Loop through the active list and return the skb. */ for (i = 0; i < NUM_REQ_Q_ENTRIES; i++) { + int j; tx_cb = &qdev->tx_buf[i]; if (tx_cb->skb) { - printk(KERN_DEBUG PFX "%s: Freeing lost SKB.\n", qdev->ndev->name); pci_unmap_single(qdev->pdev, - pci_unmap_addr(tx_cb, mapaddr), - pci_unmap_len(tx_cb, maplen), PCI_DMA_TODEVICE); + pci_unmap_addr(&tx_cb->map[0], mapaddr), + pci_unmap_len(&tx_cb->map[0], maplen), + PCI_DMA_TODEVICE); + for(j=1;jseg_count;j++) { + pci_unmap_page(qdev->pdev, + pci_unmap_addr(&tx_cb->map[j],mapaddr), + pci_unmap_len(&tx_cb->map[j],maplen), + PCI_DMA_TODEVICE); + } dev_kfree_skb(tx_cb->skb); tx_cb->skb = NULL; } @@ -3379,21 +3615,24 @@ static int __devinit ql3xxx_probe(struct SET_MODULE_OWNER(ndev); SET_NETDEV_DEV(ndev, &pdev->dev); - if (pci_using_dac) - ndev->features |= NETIF_F_HIGHDMA; - pci_set_drvdata(pdev, ndev); qdev = netdev_priv(ndev); qdev->index = cards_found; qdev->ndev = ndev; qdev->pdev = pdev; + qdev->device_id = pci_entry->device; qdev->port_link_state = LS_DOWN; if (msi) qdev->msi = 1; qdev->msg_enable = netif_msg_init(debug, default_msg); + if (pci_using_dac) + ndev->features |= NETIF_F_HIGHDMA; + if (qdev->device_id == QL3032_DEVICE_ID) + ndev->features |= (NETIF_F_HW_CSUM | NETIF_F_SG); + qdev->mem_map_registers = ioremap_nocache(pci_resource_start(pdev, 1), pci_resource_len(qdev->pdev, 1)); diff --git a/drivers/net/qla3xxx.h b/drivers/net/qla3xxx.h old mode 100644 new mode 100755 index ea94de7..b2d76ea --- a/drivers/net/qla3xxx.h +++ b/drivers/net/qla3xxx.h @@ -21,7 +21,9 @@ #define OPCODE_UPDATE_NCB_IOCB_FN2 #define OPCODE_UPDATE_NCB_IOCB 0xF0 #define OPCODE_IB_MAC_IOCB 0xF9 +#define OPCODE_IB_3032_MAC_IOCB 0x09 #define OPCODE_IB_IP_IOCB 0xFA +#define OPCODE_IB_3032_IP_IOCB 0x0A #define OPCODE_IB_TCP_IOCB 0xFB #define OPCODE_DUMP_PROTO_IOCB 0xFE #define OPCODE_BUFFER_ALERT_IOCB 0xFB @@ -37,18 +39,23 @@ #define FN1_MA_BITS_MASK 0x80 struct ob_mac_iocb_req { u8 opcode; u8 flags; -#define OB_MAC_IOCB_REQ_MA 0xC0 -#define OB_MAC_IOCB_REQ_F 0x20 -#define OB_MAC_IOCB_REQ_X 0x10 +#define OB_MAC_IOCB_REQ_MA 0xe0 +#define OB_MAC_IOCB_REQ_F 0x10 +#define OB_MAC_IOCB_REQ_X 0x08 #define OB_MAC_IOCB_REQ_D 0x02 #define OB_MAC_IOCB_REQ_I 0x01 - __le16 reserved0; + u8 flags1; +#define OB_3032MAC_IOCB_REQ_IC 0x04 +#define OB_3032MAC_IOCB_REQ_TC 0x02 +#define OB_3032MAC_IOCB_REQ_UC 0x01 + u8 reserved0; __le32 transaction_id; __le16 data_len; - __le16 reserved1; + u8 ip_hdr_off; + u8 ip_hdr_len; + __le32 reserved1; __le32 reserved2; - __le32 reserved3; __le32 buf_addr0_low; __le32 buf_addr0_high; __le32 buf_0_len; @@ -58,8 +65,8 @@ #define OB_MAC_IOCB_REQ_I 0x01 __le32 buf_addr2_low; __le32 buf_addr2_high; __le32 buf_2_len; + __le32 reserved3; __le32 reserved4; - __le32 reserved5; }; /* * The following constants define control bits for buffer @@ -74,6 +81,7 @@ struct ob_mac_iocb_rsp { u8 opcode; u8 flags; #define OB_MAC_IOCB_RSP_P 0x08 +#define OB_MAC_IOCB_RSP_L 0x04 #define OB_MAC_IOCB_RSP_S 0x02 #define OB_MAC_IOCB_RSP_I 0x01 @@ -85,6 +93,7 @@ #define OB_MAC_IOCB_RSP_I 0x01 struct ib_mac_iocb_rsp { u8 opcode; +#define IB_MAC_IOCB_RSP_V 0x80 u8 flags; #define IB_MAC_IOCB_RSP_S 0x80 #define IB_MAC_IOCB_RSP_H1 0x40 @@ -138,6 +147,7 @@ #define OB_IP_IOCB_REQ_R 0x10000000 struct ob_ip_iocb_rsp { u8 opcode; u8 flags; +#define OB_MAC_IOCB_RSP_H 0x10 #define OB_MAC_IOCB_RSP_E 0x08 #define OB_MAC_IOCB_RSP_L 0x04 #define OB_MAC_IOCB_RSP_S 0x02 @@ -220,6 +230,10 @@ #define OB_TCP_IOCB_RSP_SHIFT 4 struct ib_ip_iocb_rsp { u8 opcode; +#define IB_IP_IOCB_RSP_3032_V 0x80 +#define IB_IP_IOCB_RSP_3032_O 0x40 +#define IB_IP_IOCB_RSP_3032_I 0x20 +#define IB_IP_IOCB_RSP_3032_R 0x10 u8 flags; #define IB_IP_IOCB_RSP_S 0x80 #define IB_IP_IOCB_RSP_H1 0x40 @@ -230,6 +244,12 @@ #define IB_IP_IOCB_RSP_MA 0x07 __le16 length; __le16 checksum; +#define IB_IP_IOCB_RSP_3032_ICE 0x01 +#define IB_IP_IOCB_RSP_3032_CE 0x02 +#define IB_IP_IOCB_RSP_3032_NUC 0x04 +#define IB_IP_IOCB_RSP_3032_UDP 0x08 +#define IB_IP_IOCB_RSP_3032_TCP 0x10 +#define IB_IP_IOCB_RSP_3032_IPE 0x20 __le16 reserved; #define IB_IP_IOCB_RSP_R 0x01 __le32 ial_low; @@ -524,6 +544,21 @@ enum { IP_ADDR_INDEX_REG_FUNC_2_SEC = 0x0005, IP_ADDR_INDEX_REG_FUNC_3_PRI = 0x0006, IP_ADDR_INDEX_REG_FUNC_3_SEC = 0x0007, + IP_ADDR_INDEX_REG_6 = 0x0008, + IP_ADDR_INDEX_REG_OFFSET_MASK = 0x0030, + IP_ADDR_INDEX_REG_E = 0x0040, +}; +enum { + QL3032_PORT_CONTROL_DS = 0x0001, + QL3032_PORT_CONTROL_HH = 0x0002, + QL3032_PORT_CONTROL_EIv6 = 0x0004, + QL3032_PORT_CONTROL_EIv4 = 0x0008, + QL3032_PORT_CONTROL_ET = 0x0010, + QL3032_PORT_CONTROL_EF = 0x0020, + QL3032_PORT_CONTROL_DRM = 0x0040, + QL3032_PORT_CONTROL_RLB = 0x0080, + QL3032_PORT_CONTROL_RCB = 0x0100, + QL3032_PORT_CONTROL_KIE = 0x0200, }; enum { @@ -657,7 +692,8 @@ struct ql3xxx_port_registers { u32 internalRamWDataReg; u32 reclaimedBufferAddrRegLow; u32 reclaimedBufferAddrRegHigh; - u32 reserved[2]; + u32 tcpConfiguration; + u32 functionControl; u32 fpgaRevID; u32 localRamAddr; u32 localRamDataAutoIncr; @@ -963,6 +999,7 @@ #define IPSEC_CONFIG_PRESENT 0x0001 #define QL3XXX_VENDOR_ID 0x1077 #define QL3022_DEVICE_ID 0x3022 +#define QL3032_DEVICE_ID 0x3032 /* MTU & Frame Size stuff */ #define NORMAL_MTU_SIZE ETH_DATA_LEN @@ -1038,11 +1075,41 @@ struct ql_rcv_buf_cb { int index; }; +/* + * Original IOCB has 3 sg entries: + * first points to skb-data area + * second points to first frag + * third points to next oal. + * OAL has 5 entries: + * 1 thru 4 point to frags + * fifth points to next oal. + */ +#define MAX_OAL_CNT ((MAX_SKB_FRAGS-1)/4 + 1) + +struct oal_entry { + u32 dma_lo; + u32 dma_hi; + u32 len; +#define OAL_LAST_ENTRY 0x80000000 /* Last valid buffer in list. */ +#define OAL_CONT_ENTRY 0x40000000 /* points to an OAL. (continuation) */ + u32 reserved; +}; + +struct oal { + struct oal_entry oal_entry[5]; +}; + +struct map_list { + DECLARE_PCI_UNMAP_ADDR(mapaddr); + DECLARE_PCI_UNMAP_LEN(maplen); +}; + struct ql_tx_buf_cb { struct sk_buff *skb; struct ob_mac_iocb_req *queue_entry ; - DECLARE_PCI_UNMAP_ADDR(mapaddr); - DECLARE_PCI_UNMAP_LEN(maplen); + int seg_count; + struct oal *oal; + struct map_list map[MAX_SKB_FRAGS+1]; }; /* definitions for type field */ @@ -1189,6 +1256,7 @@ struct ql3_adapter { struct delayed_work reset_work; struct delayed_work tx_timeout_work; u32 max_frame_size; + u32 device_id; }; #endif /* _QLA3XXX_H_ */ diff --git a/drivers/net/r8169.c b/drivers/net/r8169.c index 577babd..5598d86 100644 --- a/drivers/net/r8169.c +++ b/drivers/net/r8169.c @@ -2016,7 +2016,7 @@ static int rtl8169_alloc_rx_skb(struct p if (!skb) goto err_out; - skb_reserve(skb, (align - 1) & (u32)skb->data); + skb_reserve(skb, (align - 1) & (unsigned long)skb->data); *sk_buff = skb; mapping = pci_map_single(pdev, skb->data, rx_buf_sz, @@ -2487,7 +2487,7 @@ static inline int rtl8169_try_rx_copy(st skb = dev_alloc_skb(pkt_size + align); if (skb) { - skb_reserve(skb, (align - 1) & (u32)skb->data); + skb_reserve(skb, (align - 1) & (unsigned long)skb->data); eth_copy_and_sum(skb, sk_buff[0]->data, pkt_size, 0); *sk_buff = skb; rtl8169_mark_to_asic(desc, rx_buf_sz); diff --git a/drivers/net/s2io-regs.h b/drivers/net/s2io-regs.h index a914fef..0e345cb 100644 --- a/drivers/net/s2io-regs.h +++ b/drivers/net/s2io-regs.h @@ -15,7 +15,7 @@ #define _REGS_H #define TBD 0 -typedef struct _XENA_dev_config { +struct XENA_dev_config { /* Convention: mHAL_XXX is mask, vHAL_XXX is value */ /* General Control-Status Registers */ @@ -300,6 +300,7 @@ #define I2C_CONTROL_SET_DATA(val) vBIT(v u64 gpio_control; #define GPIO_CTRL_GPIO_0 BIT(8) u64 misc_control; +#define FAULT_BEHAVIOUR BIT(0) #define EXT_REQ_EN BIT(1) #define MISC_LINK_STABILITY_PRD(val) vBIT(val,29,3) @@ -851,9 +852,9 @@ #define SPI_CONTROL_NACK BIT(5) #define SPI_CONTROL_DONE BIT(6) u64 spi_data; #define SPI_DATA_WRITE(data,len) vBIT(data,0,len) -} XENA_dev_config_t; +}; -#define XENA_REG_SPACE sizeof(XENA_dev_config_t) +#define XENA_REG_SPACE sizeof(struct XENA_dev_config) #define XENA_EEPROM_SPACE (0x01 << 11) #endif /* _REGS_H */ diff --git a/drivers/net/s2io.c b/drivers/net/s2io.c index 1dd66b8..e8e0d94 100644 --- a/drivers/net/s2io.c +++ b/drivers/net/s2io.c @@ -59,7 +59,6 @@ #include #include #include #include -#include #include #include #include @@ -77,7 +76,7 @@ #include #include "s2io.h" #include "s2io-regs.h" -#define DRV_VERSION "2.0.15.2" +#define DRV_VERSION "2.0.16.1" /* S2io Driver name & version. */ static char s2io_driver_name[] = "Neterion"; @@ -86,7 +85,7 @@ static char s2io_driver_version[] = DRV_ static int rxd_size[4] = {32,48,48,64}; static int rxd_count[4] = {127,85,85,63}; -static inline int RXD_IS_UP2DT(RxD_t *rxdp) +static inline int RXD_IS_UP2DT(struct RxD_t *rxdp) { int ret; @@ -111,9 +110,9 @@ #define LINK_IS_UP(val64) (!(val64 & (AD #define TASKLET_IN_USE test_and_set_bit(0, (&sp->tasklet_status)) #define PANIC 1 #define LOW 2 -static inline int rx_buffer_level(nic_t * sp, int rxb_size, int ring) +static inline int rx_buffer_level(struct s2io_nic * sp, int rxb_size, int ring) { - mac_info_t *mac_control; + struct mac_info *mac_control; mac_control = &sp->mac_control; if (rxb_size <= rxd_count[sp->rxd_mode]) @@ -286,7 +285,7 @@ #define S2IO_TIMER_CONF(timer, handle, a static void s2io_vlan_rx_register(struct net_device *dev, struct vlan_group *grp) { - nic_t *nic = dev->priv; + struct s2io_nic *nic = dev->priv; unsigned long flags; spin_lock_irqsave(&nic->tx_lock, flags); @@ -297,7 +296,7 @@ static void s2io_vlan_rx_register(struct /* Unregister the vlan */ static void s2io_vlan_rx_kill_vid(struct net_device *dev, unsigned long vid) { - nic_t *nic = dev->priv; + struct s2io_nic *nic = dev->priv; unsigned long flags; spin_lock_irqsave(&nic->tx_lock, flags); @@ -401,9 +400,10 @@ S2IO_PARM_INT(lro, 0); * aggregation happens until we hit max IP pkt size(64K) */ S2IO_PARM_INT(lro_max_pkts, 0xFFFF); -#ifndef CONFIG_S2IO_NAPI S2IO_PARM_INT(indicate_max_pkts, 0); -#endif + +S2IO_PARM_INT(napi, 1); +S2IO_PARM_INT(ufo, 0); static unsigned int tx_fifo_len[MAX_TX_FIFOS] = {DEFAULT_FIFO_0_LEN, [1 ...(MAX_TX_FIFOS - 1)] = DEFAULT_FIFO_1_7_LEN}; @@ -457,14 +457,14 @@ static int init_shared_mem(struct s2io_n u32 size; void *tmp_v_addr, *tmp_v_addr_next; dma_addr_t tmp_p_addr, tmp_p_addr_next; - RxD_block_t *pre_rxd_blk = NULL; - int i, j, blk_cnt, rx_sz, tx_sz; + struct RxD_block *pre_rxd_blk = NULL; + int i, j, blk_cnt; int lst_size, lst_per_page; struct net_device *dev = nic->dev; unsigned long tmp; - buffAdd_t *ba; + struct buffAdd *ba; - mac_info_t *mac_control; + struct mac_info *mac_control; struct config_param *config; mac_control = &nic->mac_control; @@ -482,13 +482,12 @@ static int init_shared_mem(struct s2io_n return -EINVAL; } - lst_size = (sizeof(TxD_t) * config->max_txds); - tx_sz = lst_size * size; + lst_size = (sizeof(struct TxD) * config->max_txds); lst_per_page = PAGE_SIZE / lst_size; for (i = 0; i < config->tx_fifo_num; i++) { int fifo_len = config->tx_cfg[i].fifo_len; - int list_holder_size = fifo_len * sizeof(list_info_hold_t); + int list_holder_size = fifo_len * sizeof(struct list_info_hold); mac_control->fifos[i].list_info = kmalloc(list_holder_size, GFP_KERNEL); if (!mac_control->fifos[i].list_info) { @@ -579,10 +578,9 @@ static int init_shared_mem(struct s2io_n mac_control->rings[i].block_count; } if (nic->rxd_mode == RXD_MODE_1) - size = (size * (sizeof(RxD1_t))); + size = (size * (sizeof(struct RxD1))); else - size = (size * (sizeof(RxD3_t))); - rx_sz = size; + size = (size * (sizeof(struct RxD3))); for (i = 0; i < config->rx_ring_num; i++) { mac_control->rings[i].rx_curr_get_info.block_index = 0; @@ -600,7 +598,7 @@ static int init_shared_mem(struct s2io_n (rxd_count[nic->rxd_mode] + 1); /* Allocating all the Rx blocks */ for (j = 0; j < blk_cnt; j++) { - rx_block_info_t *rx_blocks; + struct rx_block_info *rx_blocks; int l; rx_blocks = &mac_control->rings[i].rx_blocks[j]; @@ -620,9 +618,11 @@ static int init_shared_mem(struct s2io_n memset(tmp_v_addr, 0, size); rx_blocks->block_virt_addr = tmp_v_addr; rx_blocks->block_dma_addr = tmp_p_addr; - rx_blocks->rxds = kmalloc(sizeof(rxd_info_t)* + rx_blocks->rxds = kmalloc(sizeof(struct rxd_info)* rxd_count[nic->rxd_mode], GFP_KERNEL); + if (!rx_blocks->rxds) + return -ENOMEM; for (l=0; lrxd_mode];l++) { rx_blocks->rxds[l].virt_addr = rx_blocks->block_virt_addr + @@ -645,7 +645,7 @@ static int init_shared_mem(struct s2io_n mac_control->rings[i].rx_blocks[(j + 1) % blk_cnt].block_dma_addr; - pre_rxd_blk = (RxD_block_t *) tmp_v_addr; + pre_rxd_blk = (struct RxD_block *) tmp_v_addr; pre_rxd_blk->reserved_2_pNext_RxD_block = (unsigned long) tmp_v_addr_next; pre_rxd_blk->pNext_RxD_Blk_physical = @@ -661,14 +661,14 @@ static int init_shared_mem(struct s2io_n blk_cnt = config->rx_cfg[i].num_rxd / (rxd_count[nic->rxd_mode]+ 1); mac_control->rings[i].ba = - kmalloc((sizeof(buffAdd_t *) * blk_cnt), + kmalloc((sizeof(struct buffAdd *) * blk_cnt), GFP_KERNEL); if (!mac_control->rings[i].ba) return -ENOMEM; for (j = 0; j < blk_cnt; j++) { int k = 0; mac_control->rings[i].ba[j] = - kmalloc((sizeof(buffAdd_t) * + kmalloc((sizeof(struct buffAdd) * (rxd_count[nic->rxd_mode] + 1)), GFP_KERNEL); if (!mac_control->rings[i].ba[j]) @@ -700,7 +700,7 @@ static int init_shared_mem(struct s2io_n } /* Allocation and initialization of Statistics block */ - size = sizeof(StatInfo_t); + size = sizeof(struct stat_block); mac_control->stats_mem = pci_alloc_consistent (nic->pdev, size, &mac_control->stats_mem_phy); @@ -715,7 +715,7 @@ static int init_shared_mem(struct s2io_n mac_control->stats_mem_sz = size; tmp_v_addr = mac_control->stats_mem; - mac_control->stats_info = (StatInfo_t *) tmp_v_addr; + mac_control->stats_info = (struct stat_block *) tmp_v_addr; memset(tmp_v_addr, 0, size); DBG_PRINT(INIT_DBG, "%s:Ring Mem PHY: 0x%llx\n", dev->name, (unsigned long long) tmp_p_addr); @@ -735,7 +735,7 @@ static void free_shared_mem(struct s2io_ int i, j, blk_cnt, size; void *tmp_v_addr; dma_addr_t tmp_p_addr; - mac_info_t *mac_control; + struct mac_info *mac_control; struct config_param *config; int lst_size, lst_per_page; struct net_device *dev = nic->dev; @@ -746,7 +746,7 @@ static void free_shared_mem(struct s2io_ mac_control = &nic->mac_control; config = &nic->config; - lst_size = (sizeof(TxD_t) * config->max_txds); + lst_size = (sizeof(struct TxD) * config->max_txds); lst_per_page = PAGE_SIZE / lst_size; for (i = 0; i < config->tx_fifo_num; i++) { @@ -809,7 +809,7 @@ static void free_shared_mem(struct s2io_ if (!mac_control->rings[i].ba[j]) continue; while (k != rxd_count[nic->rxd_mode]) { - buffAdd_t *ba = + struct buffAdd *ba = &mac_control->rings[i].ba[j][k]; kfree(ba->ba_0_org); kfree(ba->ba_1_org); @@ -835,9 +835,9 @@ static void free_shared_mem(struct s2io_ * s2io_verify_pci_mode - */ -static int s2io_verify_pci_mode(nic_t *nic) +static int s2io_verify_pci_mode(struct s2io_nic *nic) { - XENA_dev_config_t __iomem *bar0 = nic->bar0; + struct XENA_dev_config __iomem *bar0 = nic->bar0; register u64 val64 = 0; int mode; @@ -868,9 +868,9 @@ static int bus_speed[8] = {33, 133, 133, /** * s2io_print_pci_mode - */ -static int s2io_print_pci_mode(nic_t *nic) +static int s2io_print_pci_mode(struct s2io_nic *nic) { - XENA_dev_config_t __iomem *bar0 = nic->bar0; + struct XENA_dev_config __iomem *bar0 = nic->bar0; register u64 val64 = 0; int mode; struct config_param *config = &nic->config; @@ -938,13 +938,13 @@ static int s2io_print_pci_mode(nic_t *ni static int init_nic(struct s2io_nic *nic) { - XENA_dev_config_t __iomem *bar0 = nic->bar0; + struct XENA_dev_config __iomem *bar0 = nic->bar0; struct net_device *dev = nic->dev; register u64 val64 = 0; void __iomem *add; u32 time; int i, j; - mac_info_t *mac_control; + struct mac_info *mac_control; struct config_param *config; int dtx_cnt = 0; unsigned long long mem_share; @@ -1414,7 +1414,7 @@ static int init_nic(struct s2io_nic *nic val64 = TTI_DATA2_MEM_TX_UFC_A(0x10) | TTI_DATA2_MEM_TX_UFC_B(0x20) | - TTI_DATA2_MEM_TX_UFC_C(0x70) | TTI_DATA2_MEM_TX_UFC_D(0x80); + TTI_DATA2_MEM_TX_UFC_C(0x40) | TTI_DATA2_MEM_TX_UFC_D(0x80); writeq(val64, &bar0->tti_data2_mem); val64 = TTI_CMD_MEM_WE | TTI_CMD_MEM_STROBE_NEW_CMD; @@ -1610,7 +1610,8 @@ static int init_nic(struct s2io_nic *nic * that does not start on an ADB to reduce disconnects. */ if (nic->device_type == XFRAME_II_DEVICE) { - val64 = EXT_REQ_EN | MISC_LINK_STABILITY_PRD(3); + val64 = FAULT_BEHAVIOUR | EXT_REQ_EN | + MISC_LINK_STABILITY_PRD(3); writeq(val64, &bar0->misc_control); val64 = readq(&bar0->pic_control2); val64 &= ~(BIT(13)|BIT(14)|BIT(15)); @@ -1626,7 +1627,7 @@ static int init_nic(struct s2io_nic *nic #define LINK_UP_DOWN_INTERRUPT 1 #define MAC_RMAC_ERR_TIMER 2 -static int s2io_link_fault_indication(nic_t *nic) +static int s2io_link_fault_indication(struct s2io_nic *nic) { if (nic->intr_type != INTA) return MAC_RMAC_ERR_TIMER; @@ -1649,14 +1650,14 @@ static int s2io_link_fault_indication(ni static void en_dis_able_nic_intrs(struct s2io_nic *nic, u16 mask, int flag) { - XENA_dev_config_t __iomem *bar0 = nic->bar0; + struct XENA_dev_config __iomem *bar0 = nic->bar0; register u64 val64 = 0, temp64 = 0; /* Top level interrupt classification */ /* PIC Interrupts */ if ((mask & (TX_PIC_INTR | RX_PIC_INTR))) { /* Enable PIC Intrs in the general intr mask register */ - val64 = TXPIC_INT_M | PIC_RX_INT_M; + val64 = TXPIC_INT_M; if (flag == ENABLE_INTRS) { temp64 = readq(&bar0->general_int_mask); temp64 &= ~((u64) val64); @@ -1694,70 +1695,6 @@ static void en_dis_able_nic_intrs(struct } } - /* DMA Interrupts */ - /* Enabling/Disabling Tx DMA interrupts */ - if (mask & TX_DMA_INTR) { - /* Enable TxDMA Intrs in the general intr mask register */ - val64 = TXDMA_INT_M; - if (flag == ENABLE_INTRS) { - temp64 = readq(&bar0->general_int_mask); - temp64 &= ~((u64) val64); - writeq(temp64, &bar0->general_int_mask); - /* - * Keep all interrupts other than PFC interrupt - * and PCC interrupt disabled in DMA level. - */ - val64 = DISABLE_ALL_INTRS & ~(TXDMA_PFC_INT_M | - TXDMA_PCC_INT_M); - writeq(val64, &bar0->txdma_int_mask); - /* - * Enable only the MISC error 1 interrupt in PFC block - */ - val64 = DISABLE_ALL_INTRS & (~PFC_MISC_ERR_1); - writeq(val64, &bar0->pfc_err_mask); - /* - * Enable only the FB_ECC error interrupt in PCC block - */ - val64 = DISABLE_ALL_INTRS & (~PCC_FB_ECC_ERR); - writeq(val64, &bar0->pcc_err_mask); - } else if (flag == DISABLE_INTRS) { - /* - * Disable TxDMA Intrs in the general intr mask - * register - */ - writeq(DISABLE_ALL_INTRS, &bar0->txdma_int_mask); - writeq(DISABLE_ALL_INTRS, &bar0->pfc_err_mask); - temp64 = readq(&bar0->general_int_mask); - val64 |= temp64; - writeq(val64, &bar0->general_int_mask); - } - } - - /* Enabling/Disabling Rx DMA interrupts */ - if (mask & RX_DMA_INTR) { - /* Enable RxDMA Intrs in the general intr mask register */ - val64 = RXDMA_INT_M; - if (flag == ENABLE_INTRS) { - temp64 = readq(&bar0->general_int_mask); - temp64 &= ~((u64) val64); - writeq(temp64, &bar0->general_int_mask); - /* - * All RxDMA block interrupts are disabled for now - * TODO - */ - writeq(DISABLE_ALL_INTRS, &bar0->rxdma_int_mask); - } else if (flag == DISABLE_INTRS) { - /* - * Disable RxDMA Intrs in the general intr mask - * register - */ - writeq(DISABLE_ALL_INTRS, &bar0->rxdma_int_mask); - temp64 = readq(&bar0->general_int_mask); - val64 |= temp64; - writeq(val64, &bar0->general_int_mask); - } - } - /* MAC Interrupts */ /* Enabling/Disabling MAC interrupts */ if (mask & (TX_MAC_INTR | RX_MAC_INTR)) { @@ -1784,53 +1721,6 @@ static void en_dis_able_nic_intrs(struct } } - /* XGXS Interrupts */ - if (mask & (TX_XGXS_INTR | RX_XGXS_INTR)) { - val64 = TXXGXS_INT_M | RXXGXS_INT_M; - if (flag == ENABLE_INTRS) { - temp64 = readq(&bar0->general_int_mask); - temp64 &= ~((u64) val64); - writeq(temp64, &bar0->general_int_mask); - /* - * All XGXS block error interrupts are disabled for now - * TODO - */ - writeq(DISABLE_ALL_INTRS, &bar0->xgxs_int_mask); - } else if (flag == DISABLE_INTRS) { - /* - * Disable MC Intrs in the general intr mask register - */ - writeq(DISABLE_ALL_INTRS, &bar0->xgxs_int_mask); - temp64 = readq(&bar0->general_int_mask); - val64 |= temp64; - writeq(val64, &bar0->general_int_mask); - } - } - - /* Memory Controller(MC) interrupts */ - if (mask & MC_INTR) { - val64 = MC_INT_M; - if (flag == ENABLE_INTRS) { - temp64 = readq(&bar0->general_int_mask); - temp64 &= ~((u64) val64); - writeq(temp64, &bar0->general_int_mask); - /* - * Enable all MC Intrs. - */ - writeq(0x0, &bar0->mc_int_mask); - writeq(0x0, &bar0->mc_err_mask); - } else if (flag == DISABLE_INTRS) { - /* - * Disable MC Intrs in the general intr mask register - */ - writeq(DISABLE_ALL_INTRS, &bar0->mc_int_mask); - temp64 = readq(&bar0->general_int_mask); - val64 |= temp64; - writeq(val64, &bar0->general_int_mask); - } - } - - /* Tx traffic interrupts */ if (mask & TX_TRAFFIC_INTR) { val64 = TXTRAFFIC_INT_M; @@ -1877,41 +1767,36 @@ static void en_dis_able_nic_intrs(struct } } -static int check_prc_pcc_state(u64 val64, int flag, int rev_id, int herc) +/** + * verify_pcc_quiescent- Checks for PCC quiescent state + * Return: 1 If PCC is quiescence + * 0 If PCC is not quiescence + */ +static int verify_pcc_quiescent(struct s2io_nic *sp, int flag) { - int ret = 0; + int ret = 0, herc; + struct XENA_dev_config __iomem *bar0 = sp->bar0; + u64 val64 = readq(&bar0->adapter_status); + + herc = (sp->device_type == XFRAME_II_DEVICE); if (flag == FALSE) { - if ((!herc && (rev_id >= 4)) || herc) { - if (!(val64 & ADAPTER_STATUS_RMAC_PCC_IDLE) && - ((val64 & ADAPTER_STATUS_RC_PRC_QUIESCENT) == - ADAPTER_STATUS_RC_PRC_QUIESCENT)) { + if ((!herc && (get_xena_rev_id(sp->pdev) >= 4)) || herc) { + if (!(val64 & ADAPTER_STATUS_RMAC_PCC_IDLE)) ret = 1; - } - }else { - if (!(val64 & ADAPTER_STATUS_RMAC_PCC_FOUR_IDLE) && - ((val64 & ADAPTER_STATUS_RC_PRC_QUIESCENT) == - ADAPTER_STATUS_RC_PRC_QUIESCENT)) { + } else { + if (!(val64 & ADAPTER_STATUS_RMAC_PCC_FOUR_IDLE)) ret = 1; - } } } else { - if ((!herc && (rev_id >= 4)) || herc) { + if ((!herc && (get_xena_rev_id(sp->pdev) >= 4)) || herc) { if (((val64 & ADAPTER_STATUS_RMAC_PCC_IDLE) == - ADAPTER_STATUS_RMAC_PCC_IDLE) && - (!(val64 & ADAPTER_STATUS_RC_PRC_QUIESCENT) || - ((val64 & ADAPTER_STATUS_RC_PRC_QUIESCENT) == - ADAPTER_STATUS_RC_PRC_QUIESCENT))) { + ADAPTER_STATUS_RMAC_PCC_IDLE)) ret = 1; - } } else { if (((val64 & ADAPTER_STATUS_RMAC_PCC_FOUR_IDLE) == - ADAPTER_STATUS_RMAC_PCC_FOUR_IDLE) && - (!(val64 & ADAPTER_STATUS_RC_PRC_QUIESCENT) || - ((val64 & ADAPTER_STATUS_RC_PRC_QUIESCENT) == - ADAPTER_STATUS_RC_PRC_QUIESCENT))) { + ADAPTER_STATUS_RMAC_PCC_FOUR_IDLE)) ret = 1; - } } } @@ -1919,9 +1804,6 @@ static int check_prc_pcc_state(u64 val64 } /** * verify_xena_quiescence - Checks whether the H/W is ready - * @val64 : Value read from adapter status register. - * @flag : indicates if the adapter enable bit was ever written once - * before. * Description: Returns whether the H/W is ready to go or not. Depending * on whether adapter enable bit was written or not the comparison * differs and the calling function passes the input argument flag to @@ -1930,24 +1812,63 @@ static int check_prc_pcc_state(u64 val64 * 0 If Xena is not quiescence */ -static int verify_xena_quiescence(nic_t *sp, u64 val64, int flag) +static int verify_xena_quiescence(struct s2io_nic *sp) { - int ret = 0, herc; - u64 tmp64 = ~((u64) val64); - int rev_id = get_xena_rev_id(sp->pdev); + int mode; + struct XENA_dev_config __iomem *bar0 = sp->bar0; + u64 val64 = readq(&bar0->adapter_status); + mode = s2io_verify_pci_mode(sp); - herc = (sp->device_type == XFRAME_II_DEVICE); - if (! - (tmp64 & - (ADAPTER_STATUS_TDMA_READY | ADAPTER_STATUS_RDMA_READY | - ADAPTER_STATUS_PFC_READY | ADAPTER_STATUS_TMAC_BUF_EMPTY | - ADAPTER_STATUS_PIC_QUIESCENT | ADAPTER_STATUS_MC_DRAM_READY | - ADAPTER_STATUS_MC_QUEUES_READY | ADAPTER_STATUS_M_PLL_LOCK | - ADAPTER_STATUS_P_PLL_LOCK))) { - ret = check_prc_pcc_state(val64, flag, rev_id, herc); + if (!(val64 & ADAPTER_STATUS_TDMA_READY)) { + DBG_PRINT(ERR_DBG, "%s", "TDMA is not ready!"); + return 0; + } + if (!(val64 & ADAPTER_STATUS_RDMA_READY)) { + DBG_PRINT(ERR_DBG, "%s", "RDMA is not ready!"); + return 0; + } + if (!(val64 & ADAPTER_STATUS_PFC_READY)) { + DBG_PRINT(ERR_DBG, "%s", "PFC is not ready!"); + return 0; + } + if (!(val64 & ADAPTER_STATUS_TMAC_BUF_EMPTY)) { + DBG_PRINT(ERR_DBG, "%s", "TMAC BUF is not empty!"); + return 0; + } + if (!(val64 & ADAPTER_STATUS_PIC_QUIESCENT)) { + DBG_PRINT(ERR_DBG, "%s", "PIC is not QUIESCENT!"); + return 0; + } + if (!(val64 & ADAPTER_STATUS_MC_DRAM_READY)) { + DBG_PRINT(ERR_DBG, "%s", "MC_DRAM is not ready!"); + return 0; + } + if (!(val64 & ADAPTER_STATUS_MC_QUEUES_READY)) { + DBG_PRINT(ERR_DBG, "%s", "MC_QUEUES is not ready!"); + return 0; + } + if (!(val64 & ADAPTER_STATUS_M_PLL_LOCK)) { + DBG_PRINT(ERR_DBG, "%s", "M_PLL is not locked!"); + return 0; } - return ret; + /* + * In PCI 33 mode, the P_PLL is not used, and therefore, + * the the P_PLL_LOCK bit in the adapter_status register will + * not be asserted. + */ + if (!(val64 & ADAPTER_STATUS_P_PLL_LOCK) && + sp->device_type == XFRAME_II_DEVICE && mode != + PCI_MODE_PCI_33) { + DBG_PRINT(ERR_DBG, "%s", "P_PLL is not locked!"); + return 0; + } + if (!((val64 & ADAPTER_STATUS_RC_PRC_QUIESCENT) == + ADAPTER_STATUS_RC_PRC_QUIESCENT)) { + DBG_PRINT(ERR_DBG, "%s", "RC_PRC is not QUIESCENT!"); + return 0; + } + return 1; } /** @@ -1958,9 +1879,9 @@ static int verify_xena_quiescence(nic_t * */ -static void fix_mac_address(nic_t * sp) +static void fix_mac_address(struct s2io_nic * sp) { - XENA_dev_config_t __iomem *bar0 = sp->bar0; + struct XENA_dev_config __iomem *bar0 = sp->bar0; u64 val64; int i = 0; @@ -1986,11 +1907,11 @@ static void fix_mac_address(nic_t * sp) static int start_nic(struct s2io_nic *nic) { - XENA_dev_config_t __iomem *bar0 = nic->bar0; + struct XENA_dev_config __iomem *bar0 = nic->bar0; struct net_device *dev = nic->dev; register u64 val64 = 0; u16 subid, i; - mac_info_t *mac_control; + struct mac_info *mac_control; struct config_param *config; mac_control = &nic->mac_control; @@ -2052,7 +1973,7 @@ static int start_nic(struct s2io_nic *ni * it. */ val64 = readq(&bar0->adapter_status); - if (!verify_xena_quiescence(nic, val64, nic->device_enabled_once)) { + if (!verify_xena_quiescence(nic)) { DBG_PRINT(ERR_DBG, "%s: device is not ready, ", dev->name); DBG_PRINT(ERR_DBG, "Adapter status reads: 0x%llx\n", (unsigned long long) val64); @@ -2095,11 +2016,12 @@ static int start_nic(struct s2io_nic *ni /** * s2io_txdl_getskb - Get the skb from txdl, unmap and return skb */ -static struct sk_buff *s2io_txdl_getskb(fifo_info_t *fifo_data, TxD_t *txdlp, int get_off) +static struct sk_buff *s2io_txdl_getskb(struct fifo_info *fifo_data, struct \ + TxD *txdlp, int get_off) { - nic_t *nic = fifo_data->nic; + struct s2io_nic *nic = fifo_data->nic; struct sk_buff *skb; - TxD_t *txds; + struct TxD *txds; u16 j, frg_cnt; txds = txdlp; @@ -2113,7 +2035,7 @@ static struct sk_buff *s2io_txdl_getskb( skb = (struct sk_buff *) ((unsigned long) txds->Host_Control); if (!skb) { - memset(txdlp, 0, (sizeof(TxD_t) * fifo_data->max_txds)); + memset(txdlp, 0, (sizeof(struct TxD) * fifo_data->max_txds)); return NULL; } pci_unmap_single(nic->pdev, (dma_addr_t) @@ -2132,7 +2054,7 @@ static struct sk_buff *s2io_txdl_getskb( frag->size, PCI_DMA_TODEVICE); } } - memset(txdlp,0, (sizeof(TxD_t) * fifo_data->max_txds)); + memset(txdlp,0, (sizeof(struct TxD) * fifo_data->max_txds)); return(skb); } @@ -2148,9 +2070,9 @@ static void free_tx_buffers(struct s2io_ { struct net_device *dev = nic->dev; struct sk_buff *skb; - TxD_t *txdp; + struct TxD *txdp; int i, j; - mac_info_t *mac_control; + struct mac_info *mac_control; struct config_param *config; int cnt = 0; @@ -2159,7 +2081,7 @@ static void free_tx_buffers(struct s2io_ for (i = 0; i < config->tx_fifo_num; i++) { for (j = 0; j < config->tx_cfg[i].fifo_len - 1; j++) { - txdp = (TxD_t *) mac_control->fifos[i].list_info[j]. + txdp = (struct TxD *) mac_control->fifos[i].list_info[j]. list_virt_addr; skb = s2io_txdl_getskb(&mac_control->fifos[i], txdp, j); if (skb) { @@ -2187,10 +2109,10 @@ static void free_tx_buffers(struct s2io_ static void stop_nic(struct s2io_nic *nic) { - XENA_dev_config_t __iomem *bar0 = nic->bar0; + struct XENA_dev_config __iomem *bar0 = nic->bar0; register u64 val64 = 0; u16 interruptible; - mac_info_t *mac_control; + struct mac_info *mac_control; struct config_param *config; mac_control = &nic->mac_control; @@ -2208,14 +2130,15 @@ static void stop_nic(struct s2io_nic *ni writeq(val64, &bar0->adapter_control); } -static int fill_rxd_3buf(nic_t *nic, RxD_t *rxdp, struct sk_buff *skb) +static int fill_rxd_3buf(struct s2io_nic *nic, struct RxD_t *rxdp, struct \ + sk_buff *skb) { struct net_device *dev = nic->dev; struct sk_buff *frag_list; void *tmp; /* Buffer-1 receives L3/L4 headers */ - ((RxD3_t*)rxdp)->Buffer1_ptr = pci_map_single + ((struct RxD3*)rxdp)->Buffer1_ptr = pci_map_single (nic->pdev, skb->data, l3l4hdr_size + 4, PCI_DMA_FROMDEVICE); @@ -2226,13 +2149,14 @@ static int fill_rxd_3buf(nic_t *nic, RxD return -ENOMEM ; } frag_list = skb_shinfo(skb)->frag_list; + skb->truesize += frag_list->truesize; frag_list->next = NULL; tmp = (void *)ALIGN((long)frag_list->data, ALIGN_SIZE + 1); frag_list->data = tmp; frag_list->tail = tmp; /* Buffer-2 receives L4 data payload */ - ((RxD3_t*)rxdp)->Buffer2_ptr = pci_map_single(nic->pdev, + ((struct RxD3*)rxdp)->Buffer2_ptr = pci_map_single(nic->pdev, frag_list->data, dev->mtu, PCI_DMA_FROMDEVICE); rxdp->Control_2 |= SET_BUFFER1_SIZE_3(l3l4hdr_size + 4); @@ -2266,18 +2190,16 @@ static int fill_rx_buffers(struct s2io_n { struct net_device *dev = nic->dev; struct sk_buff *skb; - RxD_t *rxdp; + struct RxD_t *rxdp; int off, off1, size, block_no, block_no1; u32 alloc_tab = 0; u32 alloc_cnt; - mac_info_t *mac_control; + struct mac_info *mac_control; struct config_param *config; u64 tmp; - buffAdd_t *ba; -#ifndef CONFIG_S2IO_NAPI + struct buffAdd *ba; unsigned long flags; -#endif - RxD_t *first_rxdp = NULL; + struct RxD_t *first_rxdp = NULL; mac_control = &nic->mac_control; config = &nic->config; @@ -2320,12 +2242,15 @@ #endif DBG_PRINT(INTR_DBG, "%s: Next block at: %p\n", dev->name, rxdp); } -#ifndef CONFIG_S2IO_NAPI - spin_lock_irqsave(&nic->put_lock, flags); - mac_control->rings[ring_no].put_pos = - (block_no * (rxd_count[nic->rxd_mode] + 1)) + off; - spin_unlock_irqrestore(&nic->put_lock, flags); -#endif + if(!napi) { + spin_lock_irqsave(&nic->put_lock, flags); + mac_control->rings[ring_no].put_pos = + (block_no * (rxd_count[nic->rxd_mode] + 1)) + off; + spin_unlock_irqrestore(&nic->put_lock, flags); + } else { + mac_control->rings[ring_no].put_pos = + (block_no * (rxd_count[nic->rxd_mode] + 1)) + off; + } if ((rxdp->Control_1 & RXD_OWN_XENA) && ((nic->rxd_mode >= RXD_MODE_3A) && (rxdp->Control_2 & BIT(0)))) { @@ -2356,9 +2281,9 @@ #endif } if (nic->rxd_mode == RXD_MODE_1) { /* 1 buffer mode - normal operation mode */ - memset(rxdp, 0, sizeof(RxD1_t)); + memset(rxdp, 0, sizeof(struct RxD1)); skb_reserve(skb, NET_IP_ALIGN); - ((RxD1_t*)rxdp)->Buffer0_ptr = pci_map_single + ((struct RxD1*)rxdp)->Buffer0_ptr = pci_map_single (nic->pdev, skb->data, size - NET_IP_ALIGN, PCI_DMA_FROMDEVICE); rxdp->Control_2 = SET_BUFFER0_SIZE_1(size - NET_IP_ALIGN); @@ -2375,7 +2300,7 @@ #endif * payload */ - memset(rxdp, 0, sizeof(RxD3_t)); + memset(rxdp, 0, sizeof(struct RxD3)); ba = &mac_control->rings[ring_no].ba[block_no][off]; skb_reserve(skb, BUF0_LEN); tmp = (u64)(unsigned long) skb->data; @@ -2384,13 +2309,13 @@ #endif skb->data = (void *) (unsigned long)tmp; skb->tail = (void *) (unsigned long)tmp; - if (!(((RxD3_t*)rxdp)->Buffer0_ptr)) - ((RxD3_t*)rxdp)->Buffer0_ptr = + if (!(((struct RxD3*)rxdp)->Buffer0_ptr)) + ((struct RxD3*)rxdp)->Buffer0_ptr = pci_map_single(nic->pdev, ba->ba_0, BUF0_LEN, PCI_DMA_FROMDEVICE); else pci_dma_sync_single_for_device(nic->pdev, - (dma_addr_t) ((RxD3_t*)rxdp)->Buffer0_ptr, + (dma_addr_t) ((struct RxD3*)rxdp)->Buffer0_ptr, BUF0_LEN, PCI_DMA_FROMDEVICE); rxdp->Control_2 = SET_BUFFER0_SIZE_3(BUF0_LEN); if (nic->rxd_mode == RXD_MODE_3B) { @@ -2400,13 +2325,13 @@ #endif * Buffer2 will have L3/L4 header plus * L4 payload */ - ((RxD3_t*)rxdp)->Buffer2_ptr = pci_map_single + ((struct RxD3*)rxdp)->Buffer2_ptr = pci_map_single (nic->pdev, skb->data, dev->mtu + 4, PCI_DMA_FROMDEVICE); /* Buffer-1 will be dummy buffer. Not used */ - if (!(((RxD3_t*)rxdp)->Buffer1_ptr)) { - ((RxD3_t*)rxdp)->Buffer1_ptr = + if (!(((struct RxD3*)rxdp)->Buffer1_ptr)) { + ((struct RxD3*)rxdp)->Buffer1_ptr = pci_map_single(nic->pdev, ba->ba_1, BUF1_LEN, PCI_DMA_FROMDEVICE); @@ -2466,9 +2391,9 @@ static void free_rxd_blk(struct s2io_nic struct net_device *dev = sp->dev; int j; struct sk_buff *skb; - RxD_t *rxdp; - mac_info_t *mac_control; - buffAdd_t *ba; + struct RxD_t *rxdp; + struct mac_info *mac_control; + struct buffAdd *ba; mac_control = &sp->mac_control; for (j = 0 ; j < rxd_count[sp->rxd_mode]; j++) { @@ -2481,41 +2406,41 @@ static void free_rxd_blk(struct s2io_nic } if (sp->rxd_mode == RXD_MODE_1) { pci_unmap_single(sp->pdev, (dma_addr_t) - ((RxD1_t*)rxdp)->Buffer0_ptr, + ((struct RxD1*)rxdp)->Buffer0_ptr, dev->mtu + HEADER_ETHERNET_II_802_3_SIZE + HEADER_802_2_SIZE + HEADER_SNAP_SIZE, PCI_DMA_FROMDEVICE); - memset(rxdp, 0, sizeof(RxD1_t)); + memset(rxdp, 0, sizeof(struct RxD1)); } else if(sp->rxd_mode == RXD_MODE_3B) { ba = &mac_control->rings[ring_no]. ba[blk][j]; pci_unmap_single(sp->pdev, (dma_addr_t) - ((RxD3_t*)rxdp)->Buffer0_ptr, + ((struct RxD3*)rxdp)->Buffer0_ptr, BUF0_LEN, PCI_DMA_FROMDEVICE); pci_unmap_single(sp->pdev, (dma_addr_t) - ((RxD3_t*)rxdp)->Buffer1_ptr, + ((struct RxD3*)rxdp)->Buffer1_ptr, BUF1_LEN, PCI_DMA_FROMDEVICE); pci_unmap_single(sp->pdev, (dma_addr_t) - ((RxD3_t*)rxdp)->Buffer2_ptr, + ((struct RxD3*)rxdp)->Buffer2_ptr, dev->mtu + 4, PCI_DMA_FROMDEVICE); - memset(rxdp, 0, sizeof(RxD3_t)); + memset(rxdp, 0, sizeof(struct RxD3)); } else { pci_unmap_single(sp->pdev, (dma_addr_t) - ((RxD3_t*)rxdp)->Buffer0_ptr, BUF0_LEN, + ((struct RxD3*)rxdp)->Buffer0_ptr, BUF0_LEN, PCI_DMA_FROMDEVICE); pci_unmap_single(sp->pdev, (dma_addr_t) - ((RxD3_t*)rxdp)->Buffer1_ptr, + ((struct RxD3*)rxdp)->Buffer1_ptr, l3l4hdr_size + 4, PCI_DMA_FROMDEVICE); pci_unmap_single(sp->pdev, (dma_addr_t) - ((RxD3_t*)rxdp)->Buffer2_ptr, dev->mtu, + ((struct RxD3*)rxdp)->Buffer2_ptr, dev->mtu, PCI_DMA_FROMDEVICE); - memset(rxdp, 0, sizeof(RxD3_t)); + memset(rxdp, 0, sizeof(struct RxD3)); } dev_kfree_skb(skb); atomic_dec(&sp->rx_bufs_left[ring_no]); @@ -2535,7 +2460,7 @@ static void free_rx_buffers(struct s2io_ { struct net_device *dev = sp->dev; int i, blk = 0, buf_cnt = 0; - mac_info_t *mac_control; + struct mac_info *mac_control; struct config_param *config; mac_control = &sp->mac_control; @@ -2568,15 +2493,13 @@ static void free_rx_buffers(struct s2io_ * 0 on success and 1 if there are No Rx packets to be processed. */ -#if defined(CONFIG_S2IO_NAPI) static int s2io_poll(struct net_device *dev, int *budget) { - nic_t *nic = dev->priv; + struct s2io_nic *nic = dev->priv; int pkt_cnt = 0, org_pkts_to_process; - mac_info_t *mac_control; + struct mac_info *mac_control; struct config_param *config; - XENA_dev_config_t __iomem *bar0 = nic->bar0; - u64 val64 = 0xFFFFFFFFFFFFFFFFULL; + struct XENA_dev_config __iomem *bar0 = nic->bar0; int i; atomic_inc(&nic->isr_cnt); @@ -2588,8 +2511,8 @@ static int s2io_poll(struct net_device * nic->pkts_to_process = dev->quota; org_pkts_to_process = nic->pkts_to_process; - writeq(val64, &bar0->rx_traffic_int); - val64 = readl(&bar0->rx_traffic_int); + writeq(S2IO_MINUS_ONE, &bar0->rx_traffic_int); + readl(&bar0->rx_traffic_int); for (i = 0; i < config->rx_ring_num; i++) { rx_intr_handler(&mac_control->rings[i]); @@ -2615,7 +2538,7 @@ static int s2io_poll(struct net_device * } /* Re enable the Rx interrupts. */ writeq(0x0, &bar0->rx_traffic_mask); - val64 = readl(&bar0->rx_traffic_mask); + readl(&bar0->rx_traffic_mask); atomic_dec(&nic->isr_cnt); return 0; @@ -2633,7 +2556,6 @@ no_rx: atomic_dec(&nic->isr_cnt); return 1; } -#endif #ifdef CONFIG_NET_POLL_CONTROLLER /** @@ -2647,10 +2569,10 @@ #ifdef CONFIG_NET_POLL_CONTROLLER */ static void s2io_netpoll(struct net_device *dev) { - nic_t *nic = dev->priv; - mac_info_t *mac_control; + struct s2io_nic *nic = dev->priv; + struct mac_info *mac_control; struct config_param *config; - XENA_dev_config_t __iomem *bar0 = nic->bar0; + struct XENA_dev_config __iomem *bar0 = nic->bar0; u64 val64 = 0xFFFFFFFFFFFFFFFFULL; int i; @@ -2699,17 +2621,15 @@ #endif * Return Value: * NONE. */ -static void rx_intr_handler(ring_info_t *ring_data) +static void rx_intr_handler(struct ring_info *ring_data) { - nic_t *nic = ring_data->nic; + struct s2io_nic *nic = ring_data->nic; struct net_device *dev = (struct net_device *) nic->dev; int get_block, put_block, put_offset; - rx_curr_get_info_t get_info, put_info; - RxD_t *rxdp; + struct rx_curr_get_info get_info, put_info; + struct RxD_t *rxdp; struct sk_buff *skb; -#ifndef CONFIG_S2IO_NAPI int pkt_cnt = 0; -#endif int i; spin_lock(&nic->rx_lock); @@ -2722,19 +2642,21 @@ #endif get_info = ring_data->rx_curr_get_info; get_block = get_info.block_index; - put_info = ring_data->rx_curr_put_info; + memcpy(&put_info, &ring_data->rx_curr_put_info, sizeof(put_info)); put_block = put_info.block_index; rxdp = ring_data->rx_blocks[get_block].rxds[get_info.offset].virt_addr; -#ifndef CONFIG_S2IO_NAPI - spin_lock(&nic->put_lock); - put_offset = ring_data->put_pos; - spin_unlock(&nic->put_lock); -#else - put_offset = (put_block * (rxd_count[nic->rxd_mode] + 1)) + - put_info.offset; -#endif + if (!napi) { + spin_lock(&nic->put_lock); + put_offset = ring_data->put_pos; + spin_unlock(&nic->put_lock); + } else + put_offset = ring_data->put_pos; + while (RXD_IS_UP2DT(rxdp)) { - /* If your are next to put index then it's FIFO full condition */ + /* + * If your are next to put index then it's + * FIFO full condition + */ if ((get_block == put_block) && (get_info.offset + 1) == put_info.offset) { DBG_PRINT(INTR_DBG, "%s: Ring Full\n",dev->name); @@ -2750,7 +2672,7 @@ #endif } if (nic->rxd_mode == RXD_MODE_1) { pci_unmap_single(nic->pdev, (dma_addr_t) - ((RxD1_t*)rxdp)->Buffer0_ptr, + ((struct RxD1*)rxdp)->Buffer0_ptr, dev->mtu + HEADER_ETHERNET_II_802_3_SIZE + HEADER_802_2_SIZE + @@ -2758,22 +2680,22 @@ #endif PCI_DMA_FROMDEVICE); } else if (nic->rxd_mode == RXD_MODE_3B) { pci_dma_sync_single_for_cpu(nic->pdev, (dma_addr_t) - ((RxD3_t*)rxdp)->Buffer0_ptr, + ((struct RxD3*)rxdp)->Buffer0_ptr, BUF0_LEN, PCI_DMA_FROMDEVICE); pci_unmap_single(nic->pdev, (dma_addr_t) - ((RxD3_t*)rxdp)->Buffer2_ptr, + ((struct RxD3*)rxdp)->Buffer2_ptr, dev->mtu + 4, PCI_DMA_FROMDEVICE); } else { pci_dma_sync_single_for_cpu(nic->pdev, (dma_addr_t) - ((RxD3_t*)rxdp)->Buffer0_ptr, BUF0_LEN, + ((struct RxD3*)rxdp)->Buffer0_ptr, BUF0_LEN, PCI_DMA_FROMDEVICE); pci_unmap_single(nic->pdev, (dma_addr_t) - ((RxD3_t*)rxdp)->Buffer1_ptr, + ((struct RxD3*)rxdp)->Buffer1_ptr, l3l4hdr_size + 4, PCI_DMA_FROMDEVICE); pci_unmap_single(nic->pdev, (dma_addr_t) - ((RxD3_t*)rxdp)->Buffer2_ptr, + ((struct RxD3*)rxdp)->Buffer2_ptr, dev->mtu, PCI_DMA_FROMDEVICE); } prefetch(skb->data); @@ -2792,20 +2714,17 @@ #endif rxdp = ring_data->rx_blocks[get_block].block_virt_addr; } -#ifdef CONFIG_S2IO_NAPI nic->pkts_to_process -= 1; - if (!nic->pkts_to_process) + if ((napi) && (!nic->pkts_to_process)) break; -#else pkt_cnt++; if ((indicate_max_pkts) && (pkt_cnt > indicate_max_pkts)) break; -#endif } if (nic->lro) { /* Clear all LRO sessions before exiting */ for (i=0; ilro0_n[i]; + struct lro *lro = &nic->lro0_n[i]; if (lro->in_use) { update_L3L4_header(nic, lro); queue_rx_frame(lro->parent); @@ -2829,17 +2748,17 @@ #endif * NONE */ -static void tx_intr_handler(fifo_info_t *fifo_data) +static void tx_intr_handler(struct fifo_info *fifo_data) { - nic_t *nic = fifo_data->nic; + struct s2io_nic *nic = fifo_data->nic; struct net_device *dev = (struct net_device *) nic->dev; - tx_curr_get_info_t get_info, put_info; + struct tx_curr_get_info get_info, put_info; struct sk_buff *skb; - TxD_t *txdlp; + struct TxD *txdlp; get_info = fifo_data->tx_curr_get_info; - put_info = fifo_data->tx_curr_put_info; - txdlp = (TxD_t *) fifo_data->list_info[get_info.offset]. + memcpy(&put_info, &fifo_data->tx_curr_put_info, sizeof(put_info)); + txdlp = (struct TxD *) fifo_data->list_info[get_info.offset]. list_virt_addr; while ((!(txdlp->Control_1 & TXD_LIST_OWN_XENA)) && (get_info.offset != put_info.offset) && @@ -2854,11 +2773,10 @@ static void tx_intr_handler(fifo_info_t } if ((err >> 48) == 0xA) { DBG_PRINT(TX_DBG, "TxD returned due \ -to loss of link\n"); + to loss of link\n"); } else { - DBG_PRINT(ERR_DBG, "***TxD error \ -%llx\n", err); + DBG_PRINT(ERR_DBG, "***TxD error %llx\n", err); } } @@ -2877,7 +2795,7 @@ to loss of link\n"); get_info.offset++; if (get_info.offset == get_info.fifo_len + 1) get_info.offset = 0; - txdlp = (TxD_t *) fifo_data->list_info + txdlp = (struct TxD *) fifo_data->list_info [get_info.offset].list_virt_addr; fifo_data->tx_curr_get_info.offset = get_info.offset; @@ -2902,8 +2820,8 @@ to loss of link\n"); static void s2io_mdio_write(u32 mmd_type, u64 addr, u16 value, struct net_device *dev) { u64 val64 = 0x0; - nic_t *sp = dev->priv; - XENA_dev_config_t __iomem *bar0 = sp->bar0; + struct s2io_nic *sp = dev->priv; + struct XENA_dev_config __iomem *bar0 = sp->bar0; //address transaction val64 = val64 | MDIO_MMD_INDX_ADDR(addr) @@ -2951,8 +2869,8 @@ static u64 s2io_mdio_read(u32 mmd_type, { u64 val64 = 0x0; u64 rval64 = 0x0; - nic_t *sp = dev->priv; - XENA_dev_config_t __iomem *bar0 = sp->bar0; + struct s2io_nic *sp = dev->priv; + struct XENA_dev_config __iomem *bar0 = sp->bar0; /* address transaction */ val64 = val64 | MDIO_MMD_INDX_ADDR(addr) @@ -3055,8 +2973,8 @@ static void s2io_updt_xpak_counter(struc u64 val64 = 0x0; u64 addr = 0x0; - nic_t *sp = dev->priv; - StatInfo_t *stat_info = sp->mac_control.stats_info; + struct s2io_nic *sp = dev->priv; + struct stat_block *stat_info = sp->mac_control.stats_info; /* Check the communication with the MDIO slave */ addr = 0x0000; @@ -3154,10 +3072,12 @@ static void s2io_updt_xpak_counter(struc static void alarm_intr_handler(struct s2io_nic *nic) { struct net_device *dev = (struct net_device *) nic->dev; - XENA_dev_config_t __iomem *bar0 = nic->bar0; + struct XENA_dev_config __iomem *bar0 = nic->bar0; register u64 val64 = 0, err_reg = 0; u64 cnt; int i; + if (atomic_read(&nic->card_state) == CARD_DOWN) + return; nic->mac_control.stats_info->sw_stat.ring_full_cnt = 0; /* Handling the XPAK counters update */ if(nic->mac_control.stats_info->xpak_stat.xpak_timer_count < 72000) { @@ -3297,6 +3217,25 @@ static int wait_for_cmd_complete(void __ } return ret; } +/* + * check_pci_device_id - Checks if the device id is supported + * @id : device id + * Description: Function to check if the pci device id is supported by driver. + * Return value: Actual device id if supported else PCI_ANY_ID + */ +static u16 check_pci_device_id(u16 id) +{ + switch (id) { + case PCI_DEVICE_ID_HERC_WIN: + case PCI_DEVICE_ID_HERC_UNI: + return XFRAME_II_DEVICE; + case PCI_DEVICE_ID_S2IO_UNI: + case PCI_DEVICE_ID_S2IO_WIN: + return XFRAME_I_DEVICE; + default: + return PCI_ANY_ID; + } +} /** * s2io_reset - Resets the card. @@ -3308,42 +3247,57 @@ static int wait_for_cmd_complete(void __ * void. */ -static void s2io_reset(nic_t * sp) +static void s2io_reset(struct s2io_nic * sp) { - XENA_dev_config_t __iomem *bar0 = sp->bar0; + struct XENA_dev_config __iomem *bar0 = sp->bar0; u64 val64; u16 subid, pci_cmd; + int i; + u16 val16; + DBG_PRINT(INIT_DBG,"%s - Resetting XFrame card %s\n", + __FUNCTION__, sp->dev->name); /* Back up the PCI-X CMD reg, dont want to lose MMRBC, OST settings */ pci_read_config_word(sp->pdev, PCIX_COMMAND_REGISTER, &(pci_cmd)); + if (sp->device_type == XFRAME_II_DEVICE) { + int ret; + ret = pci_set_power_state(sp->pdev, 3); + if (!ret) + ret = pci_set_power_state(sp->pdev, 0); + else { + DBG_PRINT(ERR_DBG,"%s PME based SW_Reset failed!\n", + __FUNCTION__); + goto old_way; + } + msleep(20); + goto new_way; + } +old_way: val64 = SW_RESET_ALL; writeq(val64, &bar0->sw_reset); - - /* - * At this stage, if the PCI write is indeed completed, the - * card is reset and so is the PCI Config space of the device. - * So a read cannot be issued at this stage on any of the - * registers to ensure the write into "sw_reset" register - * has gone through. - * Question: Is there any system call that will explicitly force - * all the write commands still pending on the bus to be pushed - * through? - * As of now I'am just giving a 250ms delay and hoping that the - * PCI write to sw_reset register is done by this time. - */ - msleep(250); +new_way: if (strstr(sp->product_name, "CX4")) { msleep(750); } + msleep(250); + for (i = 0; i < S2IO_MAX_PCI_CONFIG_SPACE_REINIT; i++) { - /* Restore the PCI state saved during initialization. */ - pci_restore_state(sp->pdev); - pci_write_config_word(sp->pdev, PCIX_COMMAND_REGISTER, - pci_cmd); - s2io_init_pci(sp); + /* Restore the PCI state saved during initialization. */ + pci_restore_state(sp->pdev); + pci_read_config_word(sp->pdev, 0x2, &val16); + if (check_pci_device_id(val16) != (u16)PCI_ANY_ID) + break; + msleep(200); + } - msleep(250); + if (check_pci_device_id(val16) == (u16)PCI_ANY_ID) { + DBG_PRINT(ERR_DBG,"%s SW_Reset failed!\n", __FUNCTION__); + } + + pci_write_config_word(sp->pdev, PCIX_COMMAND_REGISTER, pci_cmd); + + s2io_init_pci(sp); /* Set swapper to enable I/O register access */ s2io_set_swapper(sp); @@ -3399,10 +3353,10 @@ static void s2io_reset(nic_t * sp) * SUCCESS on success and FAILURE on failure. */ -static int s2io_set_swapper(nic_t * sp) +static int s2io_set_swapper(struct s2io_nic * sp) { struct net_device *dev = sp->dev; - XENA_dev_config_t __iomem *bar0 = sp->bar0; + struct XENA_dev_config __iomem *bar0 = sp->bar0; u64 val64, valt, valr; /* @@ -3527,9 +3481,9 @@ #endif return SUCCESS; } -static int wait_for_msix_trans(nic_t *nic, int i) +static int wait_for_msix_trans(struct s2io_nic *nic, int i) { - XENA_dev_config_t __iomem *bar0 = nic->bar0; + struct XENA_dev_config __iomem *bar0 = nic->bar0; u64 val64; int ret = 0, cnt = 0; @@ -3548,9 +3502,9 @@ static int wait_for_msix_trans(nic_t *ni return ret; } -static void restore_xmsi_data(nic_t *nic) +static void restore_xmsi_data(struct s2io_nic *nic) { - XENA_dev_config_t __iomem *bar0 = nic->bar0; + struct XENA_dev_config __iomem *bar0 = nic->bar0; u64 val64; int i; @@ -3566,9 +3520,9 @@ static void restore_xmsi_data(nic_t *nic } } -static void store_xmsi_data(nic_t *nic) +static void store_xmsi_data(struct s2io_nic *nic) { - XENA_dev_config_t __iomem *bar0 = nic->bar0; + struct XENA_dev_config __iomem *bar0 = nic->bar0; u64 val64, addr, data; int i; @@ -3589,9 +3543,9 @@ static void store_xmsi_data(nic_t *nic) } } -int s2io_enable_msi(nic_t *nic) +int s2io_enable_msi(struct s2io_nic *nic) { - XENA_dev_config_t __iomem *bar0 = nic->bar0; + struct XENA_dev_config __iomem *bar0 = nic->bar0; u16 msi_ctrl, msg_val; struct config_param *config = &nic->config; struct net_device *dev = nic->dev; @@ -3639,9 +3593,9 @@ int s2io_enable_msi(nic_t *nic) return 0; } -static int s2io_enable_msi_x(nic_t *nic) +static int s2io_enable_msi_x(struct s2io_nic *nic) { - XENA_dev_config_t __iomem *bar0 = nic->bar0; + struct XENA_dev_config __iomem *bar0 = nic->bar0; u64 tx_mat, rx_mat; u16 msi_control; /* Temp variable */ int ret, i, j, msix_indx = 1; @@ -3749,7 +3703,7 @@ static int s2io_enable_msi_x(nic_t *nic) static int s2io_open(struct net_device *dev) { - nic_t *sp = dev->priv; + struct s2io_nic *sp = dev->priv; int err = 0; /* @@ -3802,7 +3756,7 @@ hw_init_failed: static int s2io_close(struct net_device *dev) { - nic_t *sp = dev->priv; + struct s2io_nic *sp = dev->priv; flush_scheduled_work(); netif_stop_queue(dev); @@ -3828,15 +3782,15 @@ static int s2io_close(struct net_device static int s2io_xmit(struct sk_buff *skb, struct net_device *dev) { - nic_t *sp = dev->priv; + struct s2io_nic *sp = dev->priv; u16 frg_cnt, frg_len, i, queue, queue_len, put_off, get_off; register u64 val64; - TxD_t *txdp; - TxFIFO_element_t __iomem *tx_fifo; + struct TxD *txdp; + struct TxFIFO_element __iomem *tx_fifo; unsigned long flags; u16 vlan_tag = 0; int vlan_priority = 0; - mac_info_t *mac_control; + struct mac_info *mac_control; struct config_param *config; int offload_type; @@ -3864,7 +3818,7 @@ static int s2io_xmit(struct sk_buff *skb put_off = (u16) mac_control->fifos[queue].tx_curr_put_info.offset; get_off = (u16) mac_control->fifos[queue].tx_curr_get_info.offset; - txdp = (TxD_t *) mac_control->fifos[queue].list_info[put_off]. + txdp = (struct TxD *) mac_control->fifos[queue].list_info[put_off]. list_virt_addr; queue_len = mac_control->fifos[queue].tx_curr_put_info.fifo_len + 1; @@ -3887,12 +3841,10 @@ static int s2io_xmit(struct sk_buff *skb } offload_type = s2io_offload_type(skb); -#ifdef NETIF_F_TSO if (offload_type & (SKB_GSO_TCPV4 | SKB_GSO_TCPV6)) { txdp->Control_1 |= TXD_TCP_LSO_EN; txdp->Control_1 |= TXD_TCP_LSO_MSS(s2io_tcp_mss(skb)); } -#endif if (skb->ip_summed == CHECKSUM_PARTIAL) { txdp->Control_2 |= (TXD_TX_CKO_IPV4_EN | TXD_TX_CKO_TCP_EN | @@ -3993,13 +3945,13 @@ #endif static void s2io_alarm_handle(unsigned long data) { - nic_t *sp = (nic_t *)data; + struct s2io_nic *sp = (struct s2io_nic *)data; alarm_intr_handler(sp); mod_timer(&sp->alarm_timer, jiffies + HZ / 2); } -static int s2io_chk_rx_buffers(nic_t *sp, int rng_n) +static int s2io_chk_rx_buffers(struct s2io_nic *sp, int rng_n) { int rxb_size, level; @@ -4031,9 +3983,9 @@ static int s2io_chk_rx_buffers(nic_t *sp static irqreturn_t s2io_msi_handle(int irq, void *dev_id) { struct net_device *dev = (struct net_device *) dev_id; - nic_t *sp = dev->priv; + struct s2io_nic *sp = dev->priv; int i; - mac_info_t *mac_control; + struct mac_info *mac_control; struct config_param *config; atomic_inc(&sp->isr_cnt); @@ -4063,8 +4015,8 @@ static irqreturn_t s2io_msi_handle(int i static irqreturn_t s2io_msix_ring_handle(int irq, void *dev_id) { - ring_info_t *ring = (ring_info_t *)dev_id; - nic_t *sp = ring->nic; + struct ring_info *ring = (struct ring_info *)dev_id; + struct s2io_nic *sp = ring->nic; atomic_inc(&sp->isr_cnt); @@ -4077,17 +4029,17 @@ static irqreturn_t s2io_msix_ring_handle static irqreturn_t s2io_msix_fifo_handle(int irq, void *dev_id) { - fifo_info_t *fifo = (fifo_info_t *)dev_id; - nic_t *sp = fifo->nic; + struct fifo_info *fifo = (struct fifo_info *)dev_id; + struct s2io_nic *sp = fifo->nic; atomic_inc(&sp->isr_cnt); tx_intr_handler(fifo); atomic_dec(&sp->isr_cnt); return IRQ_HANDLED; } -static void s2io_txpic_intr_handle(nic_t *sp) +static void s2io_txpic_intr_handle(struct s2io_nic *sp) { - XENA_dev_config_t __iomem *bar0 = sp->bar0; + struct XENA_dev_config __iomem *bar0 = sp->bar0; u64 val64; val64 = readq(&bar0->pic_int_status); @@ -4109,39 +4061,33 @@ static void s2io_txpic_intr_handle(nic_t } else if (val64 & GPIO_INT_REG_LINK_UP) { val64 = readq(&bar0->adapter_status); - if (verify_xena_quiescence(sp, val64, - sp->device_enabled_once)) { /* Enable Adapter */ - val64 = readq(&bar0->adapter_control); - val64 |= ADAPTER_CNTL_EN; - writeq(val64, &bar0->adapter_control); - val64 |= ADAPTER_LED_ON; - writeq(val64, &bar0->adapter_control); - if (!sp->device_enabled_once) - sp->device_enabled_once = 1; + val64 = readq(&bar0->adapter_control); + val64 |= ADAPTER_CNTL_EN; + writeq(val64, &bar0->adapter_control); + val64 |= ADAPTER_LED_ON; + writeq(val64, &bar0->adapter_control); + if (!sp->device_enabled_once) + sp->device_enabled_once = 1; - s2io_link(sp, LINK_UP); - /* - * unmask link down interrupt and mask link-up - * intr - */ - val64 = readq(&bar0->gpio_int_mask); - val64 &= ~GPIO_INT_MASK_LINK_DOWN; - val64 |= GPIO_INT_MASK_LINK_UP; - writeq(val64, &bar0->gpio_int_mask); + s2io_link(sp, LINK_UP); + /* + * unmask link down interrupt and mask link-up + * intr + */ + val64 = readq(&bar0->gpio_int_mask); + val64 &= ~GPIO_INT_MASK_LINK_DOWN; + val64 |= GPIO_INT_MASK_LINK_UP; + writeq(val64, &bar0->gpio_int_mask); - } }else if (val64 & GPIO_INT_REG_LINK_DOWN) { val64 = readq(&bar0->adapter_status); - if (verify_xena_quiescence(sp, val64, - sp->device_enabled_once)) { - s2io_link(sp, LINK_DOWN); - /* Link is down so unmaks link up interrupt */ - val64 = readq(&bar0->gpio_int_mask); - val64 &= ~GPIO_INT_MASK_LINK_UP; - val64 |= GPIO_INT_MASK_LINK_DOWN; - writeq(val64, &bar0->gpio_int_mask); - } + s2io_link(sp, LINK_DOWN); + /* Link is down so unmaks link up interrupt */ + val64 = readq(&bar0->gpio_int_mask); + val64 &= ~GPIO_INT_MASK_LINK_UP; + val64 |= GPIO_INT_MASK_LINK_DOWN; + writeq(val64, &bar0->gpio_int_mask); } } val64 = readq(&bar0->gpio_int_mask); @@ -4163,11 +4109,11 @@ static void s2io_txpic_intr_handle(nic_t static irqreturn_t s2io_isr(int irq, void *dev_id) { struct net_device *dev = (struct net_device *) dev_id; - nic_t *sp = dev->priv; - XENA_dev_config_t __iomem *bar0 = sp->bar0; + struct s2io_nic *sp = dev->priv; + struct XENA_dev_config __iomem *bar0 = sp->bar0; int i; - u64 reason = 0, val64, org_mask; - mac_info_t *mac_control; + u64 reason = 0; + struct mac_info *mac_control; struct config_param *config; atomic_inc(&sp->isr_cnt); @@ -4185,43 +4131,48 @@ static irqreturn_t s2io_isr(int irq, voi reason = readq(&bar0->general_int_status); if (!reason) { - /* The interrupt was not raised by Xena. */ + /* The interrupt was not raised by us. */ + atomic_dec(&sp->isr_cnt); + return IRQ_NONE; + } + else if (unlikely(reason == S2IO_MINUS_ONE) ) { + /* Disable device and get out */ atomic_dec(&sp->isr_cnt); return IRQ_NONE; } - val64 = 0xFFFFFFFFFFFFFFFFULL; - /* Store current mask before masking all interrupts */ - org_mask = readq(&bar0->general_int_mask); - writeq(val64, &bar0->general_int_mask); + if (napi) { + if (reason & GEN_INTR_RXTRAFFIC) { + if ( likely ( netif_rx_schedule_prep(dev)) ) { + __netif_rx_schedule(dev); + writeq(S2IO_MINUS_ONE, &bar0->rx_traffic_mask); + } + else + writeq(S2IO_MINUS_ONE, &bar0->rx_traffic_int); + } + } else { + /* + * Rx handler is called by default, without checking for the + * cause of interrupt. + * rx_traffic_int reg is an R1 register, writing all 1's + * will ensure that the actual interrupt causing bit get's + * cleared and hence a read can be avoided. + */ + if (reason & GEN_INTR_RXTRAFFIC) + writeq(S2IO_MINUS_ONE, &bar0->rx_traffic_int); -#ifdef CONFIG_S2IO_NAPI - if (reason & GEN_INTR_RXTRAFFIC) { - if (netif_rx_schedule_prep(dev)) { - writeq(val64, &bar0->rx_traffic_mask); - __netif_rx_schedule(dev); + for (i = 0; i < config->rx_ring_num; i++) { + rx_intr_handler(&mac_control->rings[i]); } } -#else - /* - * Rx handler is called by default, without checking for the - * cause of interrupt. - * rx_traffic_int reg is an R1 register, writing all 1's - * will ensure that the actual interrupt causing bit get's - * cleared and hence a read can be avoided. - */ - writeq(val64, &bar0->rx_traffic_int); - for (i = 0; i < config->rx_ring_num; i++) { - rx_intr_handler(&mac_control->rings[i]); - } -#endif /* * tx_traffic_int reg is an R1 register, writing all 1's * will ensure that the actual interrupt causing bit get's * cleared and hence a read can be avoided. */ - writeq(val64, &bar0->tx_traffic_int); + if (reason & GEN_INTR_TXTRAFFIC) + writeq(S2IO_MINUS_ONE, &bar0->tx_traffic_int); for (i = 0; i < config->tx_fifo_num; i++) tx_intr_handler(&mac_control->fifos[i]); @@ -4233,11 +4184,14 @@ #endif * reallocate the buffers from the interrupt handler itself, * else schedule a tasklet to reallocate the buffers. */ -#ifndef CONFIG_S2IO_NAPI - for (i = 0; i < config->rx_ring_num; i++) - s2io_chk_rx_buffers(sp, i); -#endif - writeq(org_mask, &bar0->general_int_mask); + if (!napi) { + for (i = 0; i < config->rx_ring_num; i++) + s2io_chk_rx_buffers(sp, i); + } + + writeq(0, &bar0->general_int_mask); + readl(&bar0->general_int_status); + atomic_dec(&sp->isr_cnt); return IRQ_HANDLED; } @@ -4245,9 +4199,9 @@ #endif /** * s2io_updt_stats - */ -static void s2io_updt_stats(nic_t *sp) +static void s2io_updt_stats(struct s2io_nic *sp) { - XENA_dev_config_t __iomem *bar0 = sp->bar0; + struct XENA_dev_config __iomem *bar0 = sp->bar0; u64 val64; int cnt = 0; @@ -4266,7 +4220,7 @@ static void s2io_updt_stats(nic_t *sp) break; /* Updt failed */ } while(1); } else { - memset(sp->mac_control.stats_info, 0, sizeof(StatInfo_t)); + memset(sp->mac_control.stats_info, 0, sizeof(struct stat_block)); } } @@ -4282,8 +4236,8 @@ static void s2io_updt_stats(nic_t *sp) static struct net_device_stats *s2io_get_stats(struct net_device *dev) { - nic_t *sp = dev->priv; - mac_info_t *mac_control; + struct s2io_nic *sp = dev->priv; + struct mac_info *mac_control; struct config_param *config; @@ -4324,8 +4278,8 @@ static void s2io_set_multicast(struct ne { int i, j, prev_cnt; struct dev_mc_list *mclist; - nic_t *sp = dev->priv; - XENA_dev_config_t __iomem *bar0 = sp->bar0; + struct s2io_nic *sp = dev->priv; + struct XENA_dev_config __iomem *bar0 = sp->bar0; u64 val64 = 0, multi_mac = 0x010203040506ULL, mask = 0xfeffffffffffULL; u64 dis_addr = 0xffffffffffffULL, mac_addr = 0; @@ -4478,8 +4432,8 @@ static void s2io_set_multicast(struct ne static int s2io_set_mac_addr(struct net_device *dev, u8 * addr) { - nic_t *sp = dev->priv; - XENA_dev_config_t __iomem *bar0 = sp->bar0; + struct s2io_nic *sp = dev->priv; + struct XENA_dev_config __iomem *bar0 = sp->bar0; register u64 val64, mac_addr = 0; int i; @@ -4525,7 +4479,7 @@ static int s2io_set_mac_addr(struct net_ static int s2io_ethtool_sset(struct net_device *dev, struct ethtool_cmd *info) { - nic_t *sp = dev->priv; + struct s2io_nic *sp = dev->priv; if ((info->autoneg == AUTONEG_ENABLE) || (info->speed != SPEED_10000) || (info->duplex != DUPLEX_FULL)) return -EINVAL; @@ -4551,7 +4505,7 @@ static int s2io_ethtool_sset(struct net_ static int s2io_ethtool_gset(struct net_device *dev, struct ethtool_cmd *info) { - nic_t *sp = dev->priv; + struct s2io_nic *sp = dev->priv; info->supported = (SUPPORTED_10000baseT_Full | SUPPORTED_FIBRE); info->advertising = (SUPPORTED_10000baseT_Full | SUPPORTED_FIBRE); info->port = PORT_FIBRE; @@ -4584,7 +4538,7 @@ static int s2io_ethtool_gset(struct net_ static void s2io_ethtool_gdrvinfo(struct net_device *dev, struct ethtool_drvinfo *info) { - nic_t *sp = dev->priv; + struct s2io_nic *sp = dev->priv; strncpy(info->driver, s2io_driver_name, sizeof(info->driver)); strncpy(info->version, s2io_driver_version, sizeof(info->version)); @@ -4616,7 +4570,7 @@ static void s2io_ethtool_gregs(struct ne int i; u64 reg; u8 *reg_space = (u8 *) space; - nic_t *sp = dev->priv; + struct s2io_nic *sp = dev->priv; regs->len = XENA_REG_SPACE; regs->version = sp->pdev->subsystem_device; @@ -4638,8 +4592,8 @@ static void s2io_ethtool_gregs(struct ne */ static void s2io_phy_id(unsigned long data) { - nic_t *sp = (nic_t *) data; - XENA_dev_config_t __iomem *bar0 = sp->bar0; + struct s2io_nic *sp = (struct s2io_nic *) data; + struct XENA_dev_config __iomem *bar0 = sp->bar0; u64 val64 = 0; u16 subid; @@ -4676,8 +4630,8 @@ static void s2io_phy_id(unsigned long da static int s2io_ethtool_idnic(struct net_device *dev, u32 data) { u64 val64 = 0, last_gpio_ctrl_val; - nic_t *sp = dev->priv; - XENA_dev_config_t __iomem *bar0 = sp->bar0; + struct s2io_nic *sp = dev->priv; + struct XENA_dev_config __iomem *bar0 = sp->bar0; u16 subid; subid = sp->pdev->subsystem_device; @@ -4725,8 +4679,8 @@ static void s2io_ethtool_getpause_data(s struct ethtool_pauseparam *ep) { u64 val64; - nic_t *sp = dev->priv; - XENA_dev_config_t __iomem *bar0 = sp->bar0; + struct s2io_nic *sp = dev->priv; + struct XENA_dev_config __iomem *bar0 = sp->bar0; val64 = readq(&bar0->rmac_pause_cfg); if (val64 & RMAC_PAUSE_GEN_ENABLE) @@ -4752,8 +4706,8 @@ static int s2io_ethtool_setpause_data(st struct ethtool_pauseparam *ep) { u64 val64; - nic_t *sp = dev->priv; - XENA_dev_config_t __iomem *bar0 = sp->bar0; + struct s2io_nic *sp = dev->priv; + struct XENA_dev_config __iomem *bar0 = sp->bar0; val64 = readq(&bar0->rmac_pause_cfg); if (ep->tx_pause) @@ -4785,12 +4739,12 @@ static int s2io_ethtool_setpause_data(st */ #define S2IO_DEV_ID 5 -static int read_eeprom(nic_t * sp, int off, u64 * data) +static int read_eeprom(struct s2io_nic * sp, int off, u64 * data) { int ret = -1; u32 exit_cnt = 0; u64 val64; - XENA_dev_config_t __iomem *bar0 = sp->bar0; + struct XENA_dev_config __iomem *bar0 = sp->bar0; if (sp->device_type == XFRAME_I_DEVICE) { val64 = I2C_CONTROL_DEV_ID(S2IO_DEV_ID) | I2C_CONTROL_ADDR(off) | @@ -4850,11 +4804,11 @@ static int read_eeprom(nic_t * sp, int o * 0 on success, -1 on failure. */ -static int write_eeprom(nic_t * sp, int off, u64 data, int cnt) +static int write_eeprom(struct s2io_nic * sp, int off, u64 data, int cnt) { int exit_cnt = 0, ret = -1; u64 val64; - XENA_dev_config_t __iomem *bar0 = sp->bar0; + struct XENA_dev_config __iomem *bar0 = sp->bar0; if (sp->device_type == XFRAME_I_DEVICE) { val64 = I2C_CONTROL_DEV_ID(S2IO_DEV_ID) | I2C_CONTROL_ADDR(off) | @@ -4899,7 +4853,7 @@ static int write_eeprom(nic_t * sp, int } return ret; } -static void s2io_vpd_read(nic_t *nic) +static void s2io_vpd_read(struct s2io_nic *nic) { u8 *vpd_data; u8 data; @@ -4914,6 +4868,7 @@ static void s2io_vpd_read(nic_t *nic) strcpy(nic->product_name, "Xframe I 10GbE network adapter"); vpd_addr = 0x50; } + strcpy(nic->serial_num, "NOT AVAILABLE"); vpd_data = kmalloc(256, GFP_KERNEL); if (!vpd_data) @@ -4937,7 +4892,22 @@ static void s2io_vpd_read(nic_t *nic) pci_read_config_dword(nic->pdev, (vpd_addr + 4), (u32 *)&vpd_data[i]); } - if ((!fail) && (vpd_data[1] < VPD_PRODUCT_NAME_LEN)) { + + if(!fail) { + /* read serial number of adapter */ + for (cnt = 0; cnt < 256; cnt++) { + if ((vpd_data[cnt] == 'S') && + (vpd_data[cnt+1] == 'N') && + (vpd_data[cnt+2] < VPD_STRING_LEN)) { + memset(nic->serial_num, 0, VPD_STRING_LEN); + memcpy(nic->serial_num, &vpd_data[cnt + 3], + vpd_data[cnt+2]); + break; + } + } + } + + if ((!fail) && (vpd_data[1] < VPD_STRING_LEN)) { memset(nic->product_name, 0, vpd_data[1]); memcpy(nic->product_name, &vpd_data[3], vpd_data[1]); } @@ -4962,7 +4932,7 @@ static int s2io_ethtool_geeprom(struct n { u32 i, valid; u64 data; - nic_t *sp = dev->priv; + struct s2io_nic *sp = dev->priv; eeprom->magic = sp->pdev->vendor | (sp->pdev->device << 16); @@ -5000,7 +4970,7 @@ static int s2io_ethtool_seeprom(struct n { int len = eeprom->len, cnt = 0; u64 valid = 0, data; - nic_t *sp = dev->priv; + struct s2io_nic *sp = dev->priv; if (eeprom->magic != (sp->pdev->vendor | (sp->pdev->device << 16))) { DBG_PRINT(ERR_DBG, @@ -5044,9 +5014,9 @@ static int s2io_ethtool_seeprom(struct n * 0 on success. */ -static int s2io_register_test(nic_t * sp, uint64_t * data) +static int s2io_register_test(struct s2io_nic * sp, uint64_t * data) { - XENA_dev_config_t __iomem *bar0 = sp->bar0; + struct XENA_dev_config __iomem *bar0 = sp->bar0; u64 val64 = 0, exp_val; int fail = 0; @@ -5111,7 +5081,7 @@ static int s2io_register_test(nic_t * sp * 0 on success. */ -static int s2io_eeprom_test(nic_t * sp, uint64_t * data) +static int s2io_eeprom_test(struct s2io_nic * sp, uint64_t * data) { int fail = 0; u64 ret_data, org_4F0, org_7F0; @@ -5213,7 +5183,7 @@ static int s2io_eeprom_test(nic_t * sp, * 0 on success and -1 on failure. */ -static int s2io_bist_test(nic_t * sp, uint64_t * data) +static int s2io_bist_test(struct s2io_nic * sp, uint64_t * data) { u8 bist = 0; int cnt = 0, ret = -1; @@ -5249,9 +5219,9 @@ static int s2io_bist_test(nic_t * sp, ui * 0 on success. */ -static int s2io_link_test(nic_t * sp, uint64_t * data) +static int s2io_link_test(struct s2io_nic * sp, uint64_t * data) { - XENA_dev_config_t __iomem *bar0 = sp->bar0; + struct XENA_dev_config __iomem *bar0 = sp->bar0; u64 val64; val64 = readq(&bar0->adapter_status); @@ -5276,9 +5246,9 @@ static int s2io_link_test(nic_t * sp, ui * 0 on success. */ -static int s2io_rldram_test(nic_t * sp, uint64_t * data) +static int s2io_rldram_test(struct s2io_nic * sp, uint64_t * data) { - XENA_dev_config_t __iomem *bar0 = sp->bar0; + struct XENA_dev_config __iomem *bar0 = sp->bar0; u64 val64; int cnt, iteration = 0, test_fail = 0; @@ -5380,7 +5350,7 @@ static void s2io_ethtool_test(struct net struct ethtool_test *ethtest, uint64_t * data) { - nic_t *sp = dev->priv; + struct s2io_nic *sp = dev->priv; int orig_state = netif_running(sp->dev); if (ethtest->flags == ETH_TEST_FL_OFFLINE) { @@ -5436,8 +5406,8 @@ static void s2io_get_ethtool_stats(struc u64 * tmp_stats) { int i = 0; - nic_t *sp = dev->priv; - StatInfo_t *stat_info = sp->mac_control.stats_info; + struct s2io_nic *sp = dev->priv; + struct stat_block *stat_info = sp->mac_control.stats_info; s2io_updt_stats(sp); tmp_stats[i++] = @@ -5664,14 +5634,14 @@ static int s2io_ethtool_get_regs_len(str static u32 s2io_ethtool_get_rx_csum(struct net_device * dev) { - nic_t *sp = dev->priv; + struct s2io_nic *sp = dev->priv; return (sp->rx_csum); } static int s2io_ethtool_set_rx_csum(struct net_device *dev, u32 data) { - nic_t *sp = dev->priv; + struct s2io_nic *sp = dev->priv; if (data) sp->rx_csum = 1; @@ -5750,10 +5720,8 @@ static const struct ethtool_ops netdev_e .set_tx_csum = s2io_ethtool_op_set_tx_csum, .get_sg = ethtool_op_get_sg, .set_sg = ethtool_op_set_sg, -#ifdef NETIF_F_TSO .get_tso = s2io_ethtool_op_get_tso, .set_tso = s2io_ethtool_op_set_tso, -#endif .get_ufo = ethtool_op_get_ufo, .set_ufo = ethtool_op_set_ufo, .self_test_count = s2io_ethtool_self_test_count, @@ -5794,7 +5762,7 @@ static int s2io_ioctl(struct net_device static int s2io_change_mtu(struct net_device *dev, int new_mtu) { - nic_t *sp = dev->priv; + struct s2io_nic *sp = dev->priv; if ((new_mtu < MIN_MTU) || (new_mtu > S2IO_JUMBO_SIZE)) { DBG_PRINT(ERR_DBG, "%s: MTU size is invalid.\n", @@ -5813,7 +5781,7 @@ static int s2io_change_mtu(struct net_de if (netif_queue_stopped(dev)) netif_wake_queue(dev); } else { /* Device is down */ - XENA_dev_config_t __iomem *bar0 = sp->bar0; + struct XENA_dev_config __iomem *bar0 = sp->bar0; u64 val64 = new_mtu; writeq(vBIT(val64, 2, 14), &bar0->rmac_max_pyld_len); @@ -5838,9 +5806,9 @@ static int s2io_change_mtu(struct net_de static void s2io_tasklet(unsigned long dev_addr) { struct net_device *dev = (struct net_device *) dev_addr; - nic_t *sp = dev->priv; + struct s2io_nic *sp = dev->priv; int i, ret; - mac_info_t *mac_control; + struct mac_info *mac_control; struct config_param *config; mac_control = &sp->mac_control; @@ -5873,9 +5841,9 @@ static void s2io_tasklet(unsigned long d static void s2io_set_link(struct work_struct *work) { - nic_t *nic = container_of(work, nic_t, set_link_task); + struct s2io_nic *nic = container_of(work, struct s2io_nic, set_link_task); struct net_device *dev = nic->dev; - XENA_dev_config_t __iomem *bar0 = nic->bar0; + struct XENA_dev_config __iomem *bar0 = nic->bar0; register u64 val64; u16 subid; @@ -5894,57 +5862,53 @@ static void s2io_set_link(struct work_st } val64 = readq(&bar0->adapter_status); - if (verify_xena_quiescence(nic, val64, nic->device_enabled_once)) { - if (LINK_IS_UP(val64)) { - val64 = readq(&bar0->adapter_control); - val64 |= ADAPTER_CNTL_EN; - writeq(val64, &bar0->adapter_control); - if (CARDS_WITH_FAULTY_LINK_INDICATORS(nic->device_type, - subid)) { - val64 = readq(&bar0->gpio_control); - val64 |= GPIO_CTRL_GPIO_0; - writeq(val64, &bar0->gpio_control); - val64 = readq(&bar0->gpio_control); - } else { - val64 |= ADAPTER_LED_ON; + if (LINK_IS_UP(val64)) { + if (!(readq(&bar0->adapter_control) & ADAPTER_CNTL_EN)) { + if (verify_xena_quiescence(nic)) { + val64 = readq(&bar0->adapter_control); + val64 |= ADAPTER_CNTL_EN; writeq(val64, &bar0->adapter_control); - } - if (s2io_link_fault_indication(nic) == - MAC_RMAC_ERR_TIMER) { - val64 = readq(&bar0->adapter_status); - if (!LINK_IS_UP(val64)) { - DBG_PRINT(ERR_DBG, "%s:", dev->name); - DBG_PRINT(ERR_DBG, " Link down"); - DBG_PRINT(ERR_DBG, "after "); - DBG_PRINT(ERR_DBG, "enabling "); - DBG_PRINT(ERR_DBG, "device \n"); + if (CARDS_WITH_FAULTY_LINK_INDICATORS( + nic->device_type, subid)) { + val64 = readq(&bar0->gpio_control); + val64 |= GPIO_CTRL_GPIO_0; + writeq(val64, &bar0->gpio_control); + val64 = readq(&bar0->gpio_control); + } else { + val64 |= ADAPTER_LED_ON; + writeq(val64, &bar0->adapter_control); } - } - if (nic->device_enabled_once == FALSE) { nic->device_enabled_once = TRUE; + } else { + DBG_PRINT(ERR_DBG, "%s: Error: ", dev->name); + DBG_PRINT(ERR_DBG, "device is not Quiescent\n"); + netif_stop_queue(dev); } + } + val64 = readq(&bar0->adapter_status); + if (!LINK_IS_UP(val64)) { + DBG_PRINT(ERR_DBG, "%s:", dev->name); + DBG_PRINT(ERR_DBG, " Link down after enabling "); + DBG_PRINT(ERR_DBG, "device \n"); + } else s2io_link(nic, LINK_UP); - } else { - if (CARDS_WITH_FAULTY_LINK_INDICATORS(nic->device_type, - subid)) { - val64 = readq(&bar0->gpio_control); - val64 &= ~GPIO_CTRL_GPIO_0; - writeq(val64, &bar0->gpio_control); - val64 = readq(&bar0->gpio_control); - } - s2io_link(nic, LINK_DOWN); + } else { + if (CARDS_WITH_FAULTY_LINK_INDICATORS(nic->device_type, + subid)) { + val64 = readq(&bar0->gpio_control); + val64 &= ~GPIO_CTRL_GPIO_0; + writeq(val64, &bar0->gpio_control); + val64 = readq(&bar0->gpio_control); } - } else { /* NIC is not Quiescent. */ - DBG_PRINT(ERR_DBG, "%s: Error: ", dev->name); - DBG_PRINT(ERR_DBG, "device is not Quiescent\n"); - netif_stop_queue(dev); + s2io_link(nic, LINK_DOWN); } clear_bit(0, &(nic->link_state)); } -static int set_rxd_buffer_pointer(nic_t *sp, RxD_t *rxdp, buffAdd_t *ba, - struct sk_buff **skb, u64 *temp0, u64 *temp1, - u64 *temp2, int size) +static int set_rxd_buffer_pointer(struct s2io_nic *sp, struct RxD_t *rxdp, + struct buffAdd *ba, + struct sk_buff **skb, u64 *temp0, u64 *temp1, + u64 *temp2, int size) { struct net_device *dev = sp->dev; struct sk_buff *frag_list; @@ -5958,7 +5922,7 @@ static int set_rxd_buffer_pointer(nic_t * using same mapped address for the Rxd * buffer pointer */ - ((RxD1_t*)rxdp)->Buffer0_ptr = *temp0; + ((struct RxD1*)rxdp)->Buffer0_ptr = *temp0; } else { *skb = dev_alloc_skb(size); if (!(*skb)) { @@ -5970,7 +5934,7 @@ static int set_rxd_buffer_pointer(nic_t * such it will be used for next rxd whose * Host Control is NULL */ - ((RxD1_t*)rxdp)->Buffer0_ptr = *temp0 = + ((struct RxD1*)rxdp)->Buffer0_ptr = *temp0 = pci_map_single( sp->pdev, (*skb)->data, size - NET_IP_ALIGN, PCI_DMA_FROMDEVICE); @@ -5979,36 +5943,36 @@ static int set_rxd_buffer_pointer(nic_t } else if ((sp->rxd_mode == RXD_MODE_3B) && (rxdp->Host_Control == 0)) { /* Two buffer Mode */ if (*skb) { - ((RxD3_t*)rxdp)->Buffer2_ptr = *temp2; - ((RxD3_t*)rxdp)->Buffer0_ptr = *temp0; - ((RxD3_t*)rxdp)->Buffer1_ptr = *temp1; + ((struct RxD3*)rxdp)->Buffer2_ptr = *temp2; + ((struct RxD3*)rxdp)->Buffer0_ptr = *temp0; + ((struct RxD3*)rxdp)->Buffer1_ptr = *temp1; } else { *skb = dev_alloc_skb(size); if (!(*skb)) { DBG_PRINT(ERR_DBG, "%s: dev_alloc_skb failed\n", - dev->name); + dev->name); return -ENOMEM; } - ((RxD3_t*)rxdp)->Buffer2_ptr = *temp2 = + ((struct RxD3*)rxdp)->Buffer2_ptr = *temp2 = pci_map_single(sp->pdev, (*skb)->data, dev->mtu + 4, PCI_DMA_FROMDEVICE); - ((RxD3_t*)rxdp)->Buffer0_ptr = *temp0 = + ((struct RxD3*)rxdp)->Buffer0_ptr = *temp0 = pci_map_single( sp->pdev, ba->ba_0, BUF0_LEN, PCI_DMA_FROMDEVICE); rxdp->Host_Control = (unsigned long) (*skb); /* Buffer-1 will be dummy buffer not used */ - ((RxD3_t*)rxdp)->Buffer1_ptr = *temp1 = + ((struct RxD3*)rxdp)->Buffer1_ptr = *temp1 = pci_map_single(sp->pdev, ba->ba_1, BUF1_LEN, PCI_DMA_FROMDEVICE); } } else if ((rxdp->Host_Control == 0)) { /* Three buffer mode */ if (*skb) { - ((RxD3_t*)rxdp)->Buffer0_ptr = *temp0; - ((RxD3_t*)rxdp)->Buffer1_ptr = *temp1; - ((RxD3_t*)rxdp)->Buffer2_ptr = *temp2; + ((struct RxD3*)rxdp)->Buffer0_ptr = *temp0; + ((struct RxD3*)rxdp)->Buffer1_ptr = *temp1; + ((struct RxD3*)rxdp)->Buffer2_ptr = *temp2; } else { *skb = dev_alloc_skb(size); if (!(*skb)) { @@ -6016,11 +5980,11 @@ static int set_rxd_buffer_pointer(nic_t dev->name); return -ENOMEM; } - ((RxD3_t*)rxdp)->Buffer0_ptr = *temp0 = + ((struct RxD3*)rxdp)->Buffer0_ptr = *temp0 = pci_map_single(sp->pdev, ba->ba_0, BUF0_LEN, PCI_DMA_FROMDEVICE); /* Buffer-1 receives L3/L4 headers */ - ((RxD3_t*)rxdp)->Buffer1_ptr = *temp1 = + ((struct RxD3*)rxdp)->Buffer1_ptr = *temp1 = pci_map_single( sp->pdev, (*skb)->data, l3l4hdr_size + 4, PCI_DMA_FROMDEVICE); @@ -6040,14 +6004,15 @@ static int set_rxd_buffer_pointer(nic_t /* * Buffer-2 receives L4 data payload */ - ((RxD3_t*)rxdp)->Buffer2_ptr = *temp2 = + ((struct RxD3*)rxdp)->Buffer2_ptr = *temp2 = pci_map_single( sp->pdev, frag_list->data, dev->mtu, PCI_DMA_FROMDEVICE); } } return 0; } -static void set_rxd_buffer_size(nic_t *sp, RxD_t *rxdp, int size) +static void set_rxd_buffer_size(struct s2io_nic *sp, struct RxD_t *rxdp, + int size) { struct net_device *dev = sp->dev; if (sp->rxd_mode == RXD_MODE_1) { @@ -6063,15 +6028,15 @@ static void set_rxd_buffer_size(nic_t *s } } -static int rxd_owner_bit_reset(nic_t *sp) +static int rxd_owner_bit_reset(struct s2io_nic *sp) { int i, j, k, blk_cnt = 0, size; - mac_info_t * mac_control = &sp->mac_control; + struct mac_info * mac_control = &sp->mac_control; struct config_param *config = &sp->config; struct net_device *dev = sp->dev; - RxD_t *rxdp = NULL; + struct RxD_t *rxdp = NULL; struct sk_buff *skb = NULL; - buffAdd_t *ba = NULL; + struct buffAdd *ba = NULL; u64 temp0_64 = 0, temp1_64 = 0, temp2_64 = 0; /* Calculate the size based on ring mode */ @@ -6110,7 +6075,7 @@ static int rxd_owner_bit_reset(nic_t *s } -static int s2io_add_isr(nic_t * sp) +static int s2io_add_isr(struct s2io_nic * sp) { int ret = 0; struct net_device *dev = sp->dev; @@ -6125,7 +6090,7 @@ static int s2io_add_isr(nic_t * sp) sp->intr_type = INTA; } - /* Store the values of the MSIX table in the nic_t structure */ + /* Store the values of the MSIX table in the struct s2io_nic structure */ store_xmsi_data(sp); /* After proper initialization of H/W, register ISR */ @@ -6180,7 +6145,7 @@ static int s2io_add_isr(nic_t * sp) } return 0; } -static void s2io_rem_isr(nic_t * sp) +static void s2io_rem_isr(struct s2io_nic * sp) { int cnt = 0; struct net_device *dev = sp->dev; @@ -6222,10 +6187,10 @@ static void s2io_rem_isr(nic_t * sp) } while(cnt < 5); } -static void s2io_card_down(nic_t * sp) +static void s2io_card_down(struct s2io_nic * sp) { int cnt = 0; - XENA_dev_config_t __iomem *bar0 = sp->bar0; + struct XENA_dev_config __iomem *bar0 = sp->bar0; unsigned long flags; register u64 val64 = 0; @@ -6256,7 +6221,8 @@ static void s2io_card_down(nic_t * sp) rxd_owner_bit_reset(sp); val64 = readq(&bar0->adapter_status); - if (verify_xena_quiescence(sp, val64, sp->device_enabled_once)) { + if (verify_xena_quiescence(sp)) { + if(verify_pcc_quiescent(sp, sp->device_enabled_once)) break; } @@ -6285,10 +6251,10 @@ static void s2io_card_down(nic_t * sp) clear_bit(0, &(sp->link_state)); } -static int s2io_card_up(nic_t * sp) +static int s2io_card_up(struct s2io_nic * sp) { int i, ret = 0; - mac_info_t *mac_control; + struct mac_info *mac_control; struct config_param *config; struct net_device *dev = (struct net_device *) sp->dev; u16 interruptible; @@ -6319,6 +6285,13 @@ static int s2io_card_up(nic_t * sp) DBG_PRINT(INFO_DBG, "Buf in ring:%d is %d:\n", i, atomic_read(&sp->rx_bufs_left[i])); } + /* Maintain the state prior to the open */ + if (sp->promisc_flg) + sp->promisc_flg = 0; + if (sp->m_cast_flg) { + sp->m_cast_flg = 0; + sp->all_multi_pos= 0; + } /* Setting its receive mode */ s2io_set_multicast(dev); @@ -6380,7 +6353,7 @@ static int s2io_card_up(nic_t * sp) static void s2io_restart_nic(struct work_struct *work) { - nic_t *sp = container_of(work, nic_t, rst_timer_task); + struct s2io_nic *sp = container_of(work, struct s2io_nic, rst_timer_task); struct net_device *dev = sp->dev; s2io_card_down(sp); @@ -6409,7 +6382,7 @@ static void s2io_restart_nic(struct work static void s2io_tx_watchdog(struct net_device *dev) { - nic_t *sp = dev->priv; + struct s2io_nic *sp = dev->priv; if (netif_carrier_ok(dev)) { schedule_work(&sp->rst_timer_task); @@ -6434,16 +6407,16 @@ static void s2io_tx_watchdog(struct net_ * Return value: * SUCCESS on success and -1 on failure. */ -static int rx_osm_handler(ring_info_t *ring_data, RxD_t * rxdp) +static int rx_osm_handler(struct ring_info *ring_data, struct RxD_t * rxdp) { - nic_t *sp = ring_data->nic; + struct s2io_nic *sp = ring_data->nic; struct net_device *dev = (struct net_device *) sp->dev; struct sk_buff *skb = (struct sk_buff *) ((unsigned long) rxdp->Host_Control); int ring_no = ring_data->ring_no; u16 l3_csum, l4_csum; unsigned long long err = rxdp->Control_1 & RXD_T_CODE; - lro_t *lro; + struct lro *lro; skb->dev = dev; @@ -6488,7 +6461,7 @@ static int rx_osm_handler(ring_info_t *r int buf2_len = RXD_GET_BUFFER2_SIZE_3(rxdp->Control_2); unsigned char *buff = skb_push(skb, buf0_len); - buffAdd_t *ba = &ring_data->ba[get_block][get_off]; + struct buffAdd *ba = &ring_data->ba[get_block][get_off]; sp->stats.rx_bytes += buf0_len + buf2_len; memcpy(buff, ba->ba_0, buf0_len); @@ -6498,7 +6471,6 @@ static int rx_osm_handler(ring_info_t *r skb_put(skb, buf1_len); skb->len += buf2_len; skb->data_len += buf2_len; - skb->truesize += buf2_len; skb_put(skb_shinfo(skb)->frag_list, buf2_len); sp->stats.rx_bytes += buf1_len; @@ -6582,23 +6554,20 @@ static int rx_osm_handler(ring_info_t *r if (!sp->lro) { skb->protocol = eth_type_trans(skb, dev); -#ifdef CONFIG_S2IO_NAPI - if (sp->vlgrp && RXD_GET_VLAN_TAG(rxdp->Control_2)) { - /* Queueing the vlan frame to the upper layer */ - vlan_hwaccel_receive_skb(skb, sp->vlgrp, - RXD_GET_VLAN_TAG(rxdp->Control_2)); - } else { - netif_receive_skb(skb); - } -#else if (sp->vlgrp && RXD_GET_VLAN_TAG(rxdp->Control_2)) { /* Queueing the vlan frame to the upper layer */ - vlan_hwaccel_rx(skb, sp->vlgrp, - RXD_GET_VLAN_TAG(rxdp->Control_2)); + if (napi) + vlan_hwaccel_receive_skb(skb, sp->vlgrp, + RXD_GET_VLAN_TAG(rxdp->Control_2)); + else + vlan_hwaccel_rx(skb, sp->vlgrp, + RXD_GET_VLAN_TAG(rxdp->Control_2)); } else { - netif_rx(skb); + if (napi) + netif_receive_skb(skb); + else + netif_rx(skb); } -#endif } else { send_up: queue_rx_frame(skb); @@ -6622,7 +6591,7 @@ aggregate: * void. */ -static void s2io_link(nic_t * sp, int link) +static void s2io_link(struct s2io_nic * sp, int link) { struct net_device *dev = (struct net_device *) sp->dev; @@ -6666,7 +6635,7 @@ static int get_xena_rev_id(struct pci_de * void */ -static void s2io_init_pci(nic_t * sp) +static void s2io_init_pci(struct s2io_nic * sp) { u16 pci_cmd = 0, pcix_cmd = 0; @@ -6699,13 +6668,9 @@ static int s2io_verify_parm(struct pci_d DBG_PRINT(ERR_DBG, "s2io: Default to 8 Rx rings\n"); rx_ring_num = 8; } -#ifdef CONFIG_S2IO_NAPI - if (*dev_intr_type != INTA) { - DBG_PRINT(ERR_DBG, "s2io: NAPI cannot be enabled when " - "MSI/MSI-X is enabled. Defaulting to INTA\n"); - *dev_intr_type = INTA; - } -#endif + if (*dev_intr_type != INTA) + napi = 0; + #ifndef CONFIG_PCI_MSI if (*dev_intr_type != INTA) { DBG_PRINT(ERR_DBG, "s2io: This kernel does not support" @@ -6726,6 +6691,8 @@ #endif "Defaulting to INTA\n"); *dev_intr_type = INTA; } + if ( (rx_ring_num > 1) && (*dev_intr_type != INTA) ) + napi = 0; if (rx_ring_mode > 3) { DBG_PRINT(ERR_DBG, "s2io: Requested ring mode not supported\n"); DBG_PRINT(ERR_DBG, "s2io: Defaulting to 3-buffer mode\n"); @@ -6751,15 +6718,15 @@ #endif static int __devinit s2io_init_nic(struct pci_dev *pdev, const struct pci_device_id *pre) { - nic_t *sp; + struct s2io_nic *sp; struct net_device *dev; int i, j, ret; int dma_flag = FALSE; u32 mac_up, mac_down; u64 val64 = 0, tmp64 = 0; - XENA_dev_config_t __iomem *bar0 = NULL; + struct XENA_dev_config __iomem *bar0 = NULL; u16 subid; - mac_info_t *mac_control; + struct mac_info *mac_control; struct config_param *config; int mode; u8 dev_intr_type = intr_type; @@ -6814,7 +6781,7 @@ s2io_init_nic(struct pci_dev *pdev, cons } } - dev = alloc_etherdev(sizeof(nic_t)); + dev = alloc_etherdev(sizeof(struct s2io_nic)); if (dev == NULL) { DBG_PRINT(ERR_DBG, "Device allocation failed\n"); pci_disable_device(pdev); @@ -6829,7 +6796,7 @@ s2io_init_nic(struct pci_dev *pdev, cons /* Private member variable initialized to s2io NIC structure */ sp = dev->priv; - memset(sp, 0, sizeof(nic_t)); + memset(sp, 0, sizeof(struct s2io_nic)); sp->dev = dev; sp->pdev = pdev; sp->high_dma_flag = dma_flag; @@ -6925,7 +6892,7 @@ s2io_init_nic(struct pci_dev *pdev, cons sp->bar0 = ioremap(pci_resource_start(pdev, 0), pci_resource_len(pdev, 0)); if (!sp->bar0) { - DBG_PRINT(ERR_DBG, "%s: S2IO: cannot remap io mem1\n", + DBG_PRINT(ERR_DBG, "%s: Neterion: cannot remap io mem1\n", dev->name); ret = -ENOMEM; goto bar0_remap_failed; @@ -6934,7 +6901,7 @@ s2io_init_nic(struct pci_dev *pdev, cons sp->bar1 = ioremap(pci_resource_start(pdev, 2), pci_resource_len(pdev, 2)); if (!sp->bar1) { - DBG_PRINT(ERR_DBG, "%s: S2IO: cannot remap io mem2\n", + DBG_PRINT(ERR_DBG, "%s: Neterion: cannot remap io mem2\n", dev->name); ret = -ENOMEM; goto bar1_remap_failed; @@ -6945,7 +6912,7 @@ s2io_init_nic(struct pci_dev *pdev, cons /* Initializing the BAR1 address as the start of the FIFO pointer. */ for (j = 0; j < MAX_TX_FIFOS; j++) { - mac_control->tx_FIFO_start[j] = (TxFIFO_element_t __iomem *) + mac_control->tx_FIFO_start[j] = (struct TxFIFO_element __iomem *) (sp->bar1 + (j * 0x00020000)); } @@ -6966,10 +6933,8 @@ s2io_init_nic(struct pci_dev *pdev, cons * will use eth_mac_addr() for dev->set_mac_address * mac address will be set every time dev->open() is called */ -#if defined(CONFIG_S2IO_NAPI) dev->poll = s2io_poll; dev->weight = 32; -#endif #ifdef CONFIG_NET_POLL_CONTROLLER dev->poll_controller = s2io_netpoll; @@ -6978,13 +6943,9 @@ #endif dev->features |= NETIF_F_SG | NETIF_F_IP_CSUM; if (sp->high_dma_flag == TRUE) dev->features |= NETIF_F_HIGHDMA; -#ifdef NETIF_F_TSO dev->features |= NETIF_F_TSO; -#endif -#ifdef NETIF_F_TSO6 dev->features |= NETIF_F_TSO6; -#endif - if (sp->device_type & XFRAME_II_DEVICE) { + if ((sp->device_type & XFRAME_II_DEVICE) && (ufo)) { dev->features |= NETIF_F_UFO; dev->features |= NETIF_F_HW_CSUM; } @@ -7065,9 +7026,9 @@ #endif /* Initialize spinlocks */ spin_lock_init(&sp->tx_lock); -#ifndef CONFIG_S2IO_NAPI - spin_lock_init(&sp->put_lock); -#endif + + if (!napi) + spin_lock_init(&sp->put_lock); spin_lock_init(&sp->rx_lock); /* @@ -7098,13 +7059,14 @@ #endif DBG_PRINT(ERR_DBG, "%s: Driver version %s\n", dev->name, s2io_driver_version); DBG_PRINT(ERR_DBG, "%s: MAC ADDR: " - "%02x:%02x:%02x:%02x:%02x:%02x\n", dev->name, + "%02x:%02x:%02x:%02x:%02x:%02x", dev->name, sp->def_mac_addr[0].mac_addr[0], sp->def_mac_addr[0].mac_addr[1], sp->def_mac_addr[0].mac_addr[2], sp->def_mac_addr[0].mac_addr[3], sp->def_mac_addr[0].mac_addr[4], sp->def_mac_addr[0].mac_addr[5]); + DBG_PRINT(ERR_DBG, "SERIAL NUMBER: %s\n", sp->serial_num); if (sp->device_type & XFRAME_II_DEVICE) { mode = s2io_print_pci_mode(sp); if (mode < 0) { @@ -7128,9 +7090,9 @@ #endif dev->name); break; } -#ifdef CONFIG_S2IO_NAPI - DBG_PRINT(ERR_DBG, "%s: NAPI enabled\n", dev->name); -#endif + + if (napi) + DBG_PRINT(ERR_DBG, "%s: NAPI enabled\n", dev->name); switch(sp->intr_type) { case INTA: DBG_PRINT(ERR_DBG, "%s: Interrupt type INTA\n", dev->name); @@ -7145,7 +7107,9 @@ #endif if (sp->lro) DBG_PRINT(ERR_DBG, "%s: Large receive offload enabled\n", dev->name); - + if (ufo) + DBG_PRINT(ERR_DBG, "%s: UDP Fragmentation Offload(UFO)" + " enabled\n", dev->name); /* Initialize device name */ sprintf(sp->name, "%s Neterion %s", dev->name, sp->product_name); @@ -7202,7 +7166,7 @@ static void __devexit s2io_rem_nic(struc { struct net_device *dev = (struct net_device *) pci_get_drvdata(pdev); - nic_t *sp; + struct s2io_nic *sp; if (dev == NULL) { DBG_PRINT(ERR_DBG, "Driver Data is NULL!!\n"); @@ -7215,7 +7179,6 @@ static void __devexit s2io_rem_nic(struc free_shared_mem(sp); iounmap(sp->bar0); iounmap(sp->bar1); - pci_disable_device(pdev); if (sp->intr_type != MSI_X) pci_release_regions(pdev); else { @@ -7226,6 +7189,7 @@ static void __devexit s2io_rem_nic(struc } pci_set_drvdata(pdev, NULL); free_netdev(dev); + pci_disable_device(pdev); } /** @@ -7244,7 +7208,7 @@ int __init s2io_starter(void) * Description: This function is the cleanup routine for the driver. It unregist * ers the driver. */ -static void s2io_closer(void) +static __exit void s2io_closer(void) { pci_unregister_driver(&s2io_driver); DBG_PRINT(INIT_DBG, "cleanup done\n"); @@ -7254,7 +7218,7 @@ module_init(s2io_starter); module_exit(s2io_closer); static int check_L2_lro_capable(u8 *buffer, struct iphdr **ip, - struct tcphdr **tcp, RxD_t *rxdp) + struct tcphdr **tcp, struct RxD_t *rxdp) { int ip_off; u8 l2_type = (u8)((rxdp->Control_1 >> 37) & 0x7), ip_len; @@ -7288,7 +7252,7 @@ static int check_L2_lro_capable(u8 *buff return 0; } -static int check_for_socket_match(lro_t *lro, struct iphdr *ip, +static int check_for_socket_match(struct lro *lro, struct iphdr *ip, struct tcphdr *tcp) { DBG_PRINT(INFO_DBG,"%s: Been here...\n", __FUNCTION__); @@ -7303,7 +7267,7 @@ static inline int get_l4_pyld_length(str return(ntohs(ip->tot_len) - (ip->ihl << 2) - (tcp->doff << 2)); } -static void initiate_new_session(lro_t *lro, u8 *l2h, +static void initiate_new_session(struct lro *lro, u8 *l2h, struct iphdr *ip, struct tcphdr *tcp, u32 tcp_pyld_len) { DBG_PRINT(INFO_DBG,"%s: Been here...\n", __FUNCTION__); @@ -7329,12 +7293,12 @@ static void initiate_new_session(lro_t * lro->in_use = 1; } -static void update_L3L4_header(nic_t *sp, lro_t *lro) +static void update_L3L4_header(struct s2io_nic *sp, struct lro *lro) { struct iphdr *ip = lro->iph; struct tcphdr *tcp = lro->tcph; - u16 nchk; - StatInfo_t *statinfo = sp->mac_control.stats_info; + __sum16 nchk; + struct stat_block *statinfo = sp->mac_control.stats_info; DBG_PRINT(INFO_DBG,"%s: Been here...\n", __FUNCTION__); /* Update L3 header */ @@ -7360,7 +7324,7 @@ static void update_L3L4_header(nic_t *sp statinfo->sw_stat.num_aggregations++; } -static void aggregate_new_rx(lro_t *lro, struct iphdr *ip, +static void aggregate_new_rx(struct lro *lro, struct iphdr *ip, struct tcphdr *tcp, u32 l4_pyld) { DBG_PRINT(INFO_DBG,"%s: Been here...\n", __FUNCTION__); @@ -7382,7 +7346,7 @@ static void aggregate_new_rx(lro_t *lro, } } -static int verify_l3_l4_lro_capable(lro_t *l_lro, struct iphdr *ip, +static int verify_l3_l4_lro_capable(struct lro *l_lro, struct iphdr *ip, struct tcphdr *tcp, u32 tcp_pyld_len) { u8 *ptr; @@ -7440,8 +7404,8 @@ static int verify_l3_l4_lro_capable(lro_ } static int -s2io_club_tcp_session(u8 *buffer, u8 **tcp, u32 *tcp_len, lro_t **lro, - RxD_t *rxdp, nic_t *sp) +s2io_club_tcp_session(u8 *buffer, u8 **tcp, u32 *tcp_len, struct lro **lro, + struct RxD_t *rxdp, struct s2io_nic *sp) { struct iphdr *ip; struct tcphdr *tcph; @@ -7458,7 +7422,7 @@ s2io_club_tcp_session(u8 *buffer, u8 **t tcph = (struct tcphdr *)*tcp; *tcp_len = get_l4_pyld_length(ip, tcph); for (i=0; ilro0_n[i]; + struct lro *l_lro = &sp->lro0_n[i]; if (l_lro->in_use) { if (check_for_socket_match(l_lro, ip, tcph)) continue; @@ -7496,7 +7460,7 @@ s2io_club_tcp_session(u8 *buffer, u8 **t } for (i=0; ilro0_n[i]; + struct lro *l_lro = &sp->lro0_n[i]; if (!(l_lro->in_use)) { *lro = l_lro; ret = 3; /* Begin anew */ @@ -7535,9 +7499,9 @@ s2io_club_tcp_session(u8 *buffer, u8 **t return ret; } -static void clear_lro_session(lro_t *lro) +static void clear_lro_session(struct lro *lro) { - static u16 lro_struct_size = sizeof(lro_t); + static u16 lro_struct_size = sizeof(struct lro); memset(lro, 0, lro_struct_size); } @@ -7547,14 +7511,14 @@ static void queue_rx_frame(struct sk_buf struct net_device *dev = skb->dev; skb->protocol = eth_type_trans(skb, dev); -#ifdef CONFIG_S2IO_NAPI - netif_receive_skb(skb); -#else - netif_rx(skb); -#endif + if (napi) + netif_receive_skb(skb); + else + netif_rx(skb); } -static void lro_append_pkt(nic_t *sp, lro_t *lro, struct sk_buff *skb, +static void lro_append_pkt(struct s2io_nic *sp, struct lro *lro, + struct sk_buff *skb, u32 tcp_len) { struct sk_buff *first = lro->parent; @@ -7566,6 +7530,7 @@ static void lro_append_pkt(nic_t *sp, lr lro->last_frag->next = skb; else skb_shinfo(first)->frag_list = skb; + first->truesize += skb->truesize; lro->last_frag = skb; sp->mac_control.stats_info->sw_stat.clubbed_frms_cnt++; return; diff --git a/drivers/net/s2io.h b/drivers/net/s2io.h index 3b0bafd..0de0c65 100644 --- a/drivers/net/s2io.h +++ b/drivers/net/s2io.h @@ -30,6 +30,8 @@ #endif #undef SUCCESS #define SUCCESS 0 #define FAILURE -1 +#define S2IO_MINUS_ONE 0xFFFFFFFFFFFFFFFFULL +#define S2IO_MAX_PCI_CONFIG_SPACE_REINIT 100 #define CHECKBIT(value, nbit) (value & (1 << nbit)) @@ -37,7 +39,7 @@ #define CHECKBIT(value, nbit) (value & ( #define MAX_FLICKER_TIME 60000 /* 60 Secs */ /* Maximum outstanding splits to be configured into xena. */ -typedef enum xena_max_outstanding_splits { +enum { XENA_ONE_SPLIT_TRANSACTION = 0, XENA_TWO_SPLIT_TRANSACTION = 1, XENA_THREE_SPLIT_TRANSACTION = 2, @@ -46,7 +48,7 @@ typedef enum xena_max_outstanding_splits XENA_TWELVE_SPLIT_TRANSACTION = 5, XENA_SIXTEEN_SPLIT_TRANSACTION = 6, XENA_THIRTYTWO_SPLIT_TRANSACTION = 7 -} xena_max_outstanding_splits; +}; #define XENA_MAX_OUTSTANDING_SPLITS(n) (n << 4) /* OS concerned variables and constants */ @@ -77,7 +79,7 @@ #define L4_CKSUM_OK 0xFFFF #define S2IO_JUMBO_SIZE 9600 /* Driver statistics maintained by driver */ -typedef struct { +struct swStat { unsigned long long single_ecc_errs; unsigned long long double_ecc_errs; unsigned long long parity_err_cnt; @@ -92,10 +94,10 @@ typedef struct { unsigned long long flush_max_pkts; unsigned long long sum_avg_pkts_aggregated; unsigned long long num_aggregations; -} swStat_t; +}; /* Xpak releated alarm and warnings */ -typedef struct { +struct xpakStat { u64 alarm_transceiver_temp_high; u64 alarm_transceiver_temp_low; u64 alarm_laser_bias_current_high; @@ -110,11 +112,11 @@ typedef struct { u64 warn_laser_output_power_low; u64 xpak_regs_stat; u32 xpak_timer_count; -} xpakStat_t; +}; /* The statistics block of Xena */ -typedef struct stat_block { +struct stat_block { /* Tx MAC statistics counters. */ __le32 tmac_data_octets; __le32 tmac_frms; @@ -290,9 +292,9 @@ typedef struct stat_block { __le32 reserved_14; __le32 link_fault_cnt; u8 buffer[20]; - swStat_t sw_stat; - xpakStat_t xpak_stat; -} StatInfo_t; + struct swStat sw_stat; + struct xpakStat xpak_stat; +}; /* * Structures representing different init time configuration @@ -315,7 +317,7 @@ static int fifo_map[][MAX_TX_FIFOS] = { }; /* Maintains Per FIFO related information. */ -typedef struct tx_fifo_config { +struct tx_fifo_config { #define MAX_AVAILABLE_TXDS 8192 u32 fifo_len; /* specifies len of FIFO upto 8192, ie no of TxDLs */ /* Priority definition */ @@ -332,11 +334,11 @@ #define TX_FIFO_PRI_7 7 /* u8 f_no_snoop; #define NO_SNOOP_TXD 0x01 #define NO_SNOOP_TXD_BUFFER 0x02 -} tx_fifo_config_t; +}; /* Maintains per Ring related information */ -typedef struct rx_ring_config { +struct rx_ring_config { u32 num_rxd; /*No of RxDs per Rx Ring */ #define RX_RING_PRI_0 0 /* highest */ #define RX_RING_PRI_1 1 @@ -357,7 +359,7 @@ #define RX_RING_ORG_BUFF5 0x05 u8 f_no_snoop; #define NO_SNOOP_RXD 0x01 #define NO_SNOOP_RXD_BUFFER 0x02 -} rx_ring_config_t; +}; /* This structure provides contains values of the tunable parameters * of the H/W @@ -367,7 +369,7 @@ struct config_param { u32 tx_fifo_num; /*Number of Tx FIFOs */ u8 fifo_mapping[MAX_TX_FIFOS]; - tx_fifo_config_t tx_cfg[MAX_TX_FIFOS]; /*Per-Tx FIFO config */ + struct tx_fifo_config tx_cfg[MAX_TX_FIFOS]; /*Per-Tx FIFO config */ u32 max_txds; /*Max no. of Tx buffer descriptor per TxDL */ u64 tx_intr_type; /* Specifies if Tx Intr is UTILZ or PER_LIST type. */ @@ -376,7 +378,7 @@ struct config_param { u32 rx_ring_num; /*Number of receive rings */ #define MAX_RX_BLOCKS_PER_RING 150 - rx_ring_config_t rx_cfg[MAX_RX_RINGS]; /*Per-Rx Ring config */ + struct rx_ring_config rx_cfg[MAX_RX_RINGS]; /*Per-Rx Ring config */ u8 bimodal; /*Flag for setting bimodal interrupts*/ #define HEADER_ETHERNET_II_802_3_SIZE 14 @@ -395,14 +397,14 @@ #define MAX_MTU_JUMBO_VLAN (MAX }; /* Structure representing MAC Addrs */ -typedef struct mac_addr { +struct mac_addr { u8 mac_addr[ETH_ALEN]; -} macaddr_t; +}; /* Structure that represent every FIFO element in the BAR1 * Address location. */ -typedef struct _TxFIFO_element { +struct TxFIFO_element { u64 TxDL_Pointer; u64 List_Control; @@ -413,10 +415,10 @@ #define TX_FIFO_FIRSTNLAST_LIST v #define TX_FIFO_SPECIAL_FUNC BIT(23) #define TX_FIFO_DS_NO_SNOOP BIT(31) #define TX_FIFO_BUFF_NO_SNOOP BIT(30) -} TxFIFO_element_t; +}; /* Tx descriptor structure */ -typedef struct _TxD { +struct TxD { u64 Control_1; /* bit mask */ #define TXD_LIST_OWN_XENA BIT(7) @@ -447,16 +449,16 @@ #define TXD_SET_MARKER vBIT(0x6, u64 Buffer_Pointer; u64 Host_Control; /* reserved for host */ -} TxD_t; +}; /* Structure to hold the phy and virt addr of every TxDL. */ -typedef struct list_info_hold { +struct list_info_hold { dma_addr_t list_phy_addr; void *list_virt_addr; -} list_info_hold_t; +}; /* Rx descriptor structure for 1 buffer mode */ -typedef struct _RxD_t { +struct RxD_t { u64 Host_Control; /* reserved for host */ u64 Control_1; #define RXD_OWN_XENA BIT(7) @@ -481,21 +483,21 @@ #define SET_VLAN_TAG(val) vBIT(val #define SET_NUM_TAG(val) vBIT(val,16,32) -} RxD_t; +}; /* Rx descriptor structure for 1 buffer mode */ -typedef struct _RxD1_t { - struct _RxD_t h; +struct RxD1 { + struct RxD_t h; #define MASK_BUFFER0_SIZE_1 vBIT(0x3FFF,2,14) #define SET_BUFFER0_SIZE_1(val) vBIT(val,2,14) #define RXD_GET_BUFFER0_SIZE_1(_Control_2) \ (u16)((_Control_2 & MASK_BUFFER0_SIZE_1) >> 48) u64 Buffer0_ptr; -} RxD1_t; +}; /* Rx descriptor structure for 3 or 2 buffer mode */ -typedef struct _RxD3_t { - struct _RxD_t h; +struct RxD3 { + struct RxD_t h; #define MASK_BUFFER0_SIZE_3 vBIT(0xFF,2,14) #define MASK_BUFFER1_SIZE_3 vBIT(0xFFFF,16,16) @@ -515,15 +517,15 @@ #define BUF1_LEN 1 u64 Buffer0_ptr; u64 Buffer1_ptr; u64 Buffer2_ptr; -} RxD3_t; +}; /* Structure that represents the Rx descriptor block which contains * 128 Rx descriptors. */ -typedef struct _RxD_block { +struct RxD_block { #define MAX_RXDS_PER_BLOCK_1 127 - RxD1_t rxd[MAX_RXDS_PER_BLOCK_1]; + struct RxD1 rxd[MAX_RXDS_PER_BLOCK_1]; u64 reserved_0; #define END_OF_BLOCK 0xFEFFFFFFFFFFFFFFULL @@ -533,22 +535,22 @@ #define END_OF_BLOCK 0xFEFFFFFFFFFFFF u64 pNext_RxD_Blk_physical; /* Buff0_ptr.In a 32 bit arch * the upper 32 bits should * be 0 */ -} RxD_block_t; +}; #define SIZE_OF_BLOCK 4096 -#define RXD_MODE_1 0 -#define RXD_MODE_3A 1 -#define RXD_MODE_3B 2 +#define RXD_MODE_1 0 /* One Buffer mode */ +#define RXD_MODE_3A 1 /* Three Buffer mode */ +#define RXD_MODE_3B 2 /* Two Buffer mode */ /* Structure to hold virtual addresses of Buf0 and Buf1 in * 2buf mode. */ -typedef struct bufAdd { +struct buffAdd { void *ba_0_org; void *ba_1_org; void *ba_0; void *ba_1; -} buffAdd_t; +}; /* Structure which stores all the MAC control parameters */ @@ -556,43 +558,46 @@ typedef struct bufAdd { * from which the Rx Interrupt processor can start picking * up the RxDs for processing. */ -typedef struct _rx_curr_get_info_t { +struct rx_curr_get_info { u32 block_index; u32 offset; u32 ring_len; -} rx_curr_get_info_t; +}; -typedef rx_curr_get_info_t rx_curr_put_info_t; +struct rx_curr_put_info { + u32 block_index; + u32 offset; + u32 ring_len; +}; /* This structure stores the offset of the TxDl in the FIFO * from which the Tx Interrupt processor can start picking * up the TxDLs for send complete interrupt processing. */ -typedef struct { +struct tx_curr_get_info { u32 offset; u32 fifo_len; -} tx_curr_get_info_t; - -typedef tx_curr_get_info_t tx_curr_put_info_t; +}; +struct tx_curr_put_info { + u32 offset; + u32 fifo_len; +}; -typedef struct rxd_info { +struct rxd_info { void *virt_addr; dma_addr_t dma_addr; -}rxd_info_t; +}; /* Structure that holds the Phy and virt addresses of the Blocks */ -typedef struct rx_block_info { +struct rx_block_info { void *block_virt_addr; dma_addr_t block_dma_addr; - rxd_info_t *rxds; -} rx_block_info_t; - -/* pre declaration of the nic structure */ -typedef struct s2io_nic nic_t; + struct rxd_info *rxds; +}; /* Ring specific structure */ -typedef struct ring_info { +struct ring_info { /* The ring number */ int ring_no; @@ -600,7 +605,7 @@ typedef struct ring_info { * Place holders for the virtual and physical addresses of * all the Rx Blocks */ - rx_block_info_t rx_blocks[MAX_RX_BLOCKS_PER_RING]; + struct rx_block_info rx_blocks[MAX_RX_BLOCKS_PER_RING]; int block_count; int pkt_cnt; @@ -608,26 +613,24 @@ typedef struct ring_info { * Put pointer info which indictes which RxD has to be replenished * with a new buffer. */ - rx_curr_put_info_t rx_curr_put_info; + struct rx_curr_put_info rx_curr_put_info; /* * Get pointer info which indictes which is the last RxD that was * processed by the driver. */ - rx_curr_get_info_t rx_curr_get_info; + struct rx_curr_get_info rx_curr_get_info; -#ifndef CONFIG_S2IO_NAPI /* Index to the absolute position of the put pointer of Rx ring */ int put_pos; -#endif /* Buffer Address store. */ - buffAdd_t **ba; - nic_t *nic; -} ring_info_t; + struct buffAdd **ba; + struct s2io_nic *nic; +}; /* Fifo specific structure */ -typedef struct fifo_info { +struct fifo_info { /* FIFO number */ int fifo_no; @@ -635,40 +638,40 @@ typedef struct fifo_info { int max_txds; /* Place holder of all the TX List's Phy and Virt addresses. */ - list_info_hold_t *list_info; + struct list_info_hold *list_info; /* * Current offset within the tx FIFO where driver would write * new Tx frame */ - tx_curr_put_info_t tx_curr_put_info; + struct tx_curr_put_info tx_curr_put_info; /* * Current offset within tx FIFO from where the driver would start freeing * the buffers */ - tx_curr_get_info_t tx_curr_get_info; + struct tx_curr_get_info tx_curr_get_info; - nic_t *nic; -}fifo_info_t; + struct s2io_nic *nic; +}; /* Information related to the Tx and Rx FIFOs and Rings of Xena * is maintained in this structure. */ -typedef struct mac_info { +struct mac_info { /* tx side stuff */ /* logical pointer of start of each Tx FIFO */ - TxFIFO_element_t __iomem *tx_FIFO_start[MAX_TX_FIFOS]; + struct TxFIFO_element __iomem *tx_FIFO_start[MAX_TX_FIFOS]; /* Fifo specific structure */ - fifo_info_t fifos[MAX_TX_FIFOS]; + struct fifo_info fifos[MAX_TX_FIFOS]; /* Save virtual address of TxD page with zero DMA addr(if any) */ void *zerodma_virt_addr; /* rx side stuff */ /* Ring specific structure */ - ring_info_t rings[MAX_RX_RINGS]; + struct ring_info rings[MAX_RX_RINGS]; u16 rmac_pause_time; u16 mc_pause_threshold_q0q3; @@ -677,14 +680,14 @@ typedef struct mac_info { void *stats_mem; /* orignal pointer to allocated mem */ dma_addr_t stats_mem_phy; /* Physical address of the stat block */ u32 stats_mem_sz; - StatInfo_t *stats_info; /* Logical address of the stat block */ -} mac_info_t; + struct stat_block *stats_info; /* Logical address of the stat block */ +}; /* structure representing the user defined MAC addresses */ -typedef struct { +struct usr_addr { char addr[ETH_ALEN]; int usage_cnt; -} usr_addr_t; +}; /* Default Tunable parameters of the NIC. */ #define DEFAULT_FIFO_0_LEN 4096 @@ -717,36 +720,34 @@ struct msix_info_st { }; /* Data structure to represent a LRO session */ -typedef struct lro { +struct lro { struct sk_buff *parent; struct sk_buff *last_frag; u8 *l2h; struct iphdr *iph; struct tcphdr *tcph; u32 tcp_next_seq; - u32 tcp_ack; + __be32 tcp_ack; int total_len; int frags_len; int sg_num; int in_use; - u16 window; + __be16 window; u32 cur_tsval; u32 cur_tsecr; u8 saw_ts; -}lro_t; +}; /* Structure representing one instance of the NIC */ struct s2io_nic { int rxd_mode; -#ifdef CONFIG_S2IO_NAPI /* * Count of packets to be processed in a given iteration, it will be indicated * by the quota field of the device structure when NAPI is enabled. */ int pkts_to_process; -#endif struct net_device *dev; - mac_info_t mac_control; + struct mac_info mac_control; struct config_param config; struct pci_dev *pdev; void __iomem *bar0; @@ -754,8 +755,8 @@ #endif #define MAX_MAC_SUPPORTED 16 #define MAX_SUPPORTED_MULTICASTS MAX_MAC_SUPPORTED - macaddr_t def_mac_addr[MAX_MAC_SUPPORTED]; - macaddr_t pre_mac_addr[MAX_MAC_SUPPORTED]; + struct mac_addr def_mac_addr[MAX_MAC_SUPPORTED]; + struct mac_addr pre_mac_addr[MAX_MAC_SUPPORTED]; struct net_device_stats stats; int high_dma_flag; @@ -775,9 +776,7 @@ #define MAX_SUPPORTED_MULTICASTS MAX_MAC atomic_t rx_bufs_left[MAX_RX_RINGS]; spinlock_t tx_lock; -#ifndef CONFIG_S2IO_NAPI spinlock_t put_lock; -#endif #define PROMISC 1 #define ALL_MULTI 2 @@ -785,7 +784,7 @@ #define ALL_MULTI 2 #define MAX_ADDRS_SUPPORTED 64 u16 usr_addr_count; u16 mc_addr_count; - usr_addr_t usr_addrs[MAX_ADDRS_SUPPORTED]; + struct usr_addr usr_addrs[MAX_ADDRS_SUPPORTED]; u16 m_cast_flg; u16 all_multi_pos; @@ -841,7 +840,7 @@ #define XFRAME_II_DEVICE 2 u8 device_type; #define MAX_LRO_SESSIONS 32 - lro_t lro0_n[MAX_LRO_SESSIONS]; + struct lro lro0_n[MAX_LRO_SESSIONS]; unsigned long clubbed_frms_cnt; unsigned long sending_both; u8 lro; @@ -855,8 +854,9 @@ #define MSI_X 2 spinlock_t rx_lock; atomic_t isr_cnt; u64 *ufo_in_band_v; -#define VPD_PRODUCT_NAME_LEN 50 - u8 product_name[VPD_PRODUCT_NAME_LEN]; +#define VPD_STRING_LEN 80 + u8 product_name[VPD_STRING_LEN]; + u8 serial_num[VPD_STRING_LEN]; }; #define RESET_ERROR 1; @@ -975,43 +975,50 @@ static void __devexit s2io_rem_nic(struc static int init_shared_mem(struct s2io_nic *sp); static void free_shared_mem(struct s2io_nic *sp); static int init_nic(struct s2io_nic *nic); -static void rx_intr_handler(ring_info_t *ring_data); -static void tx_intr_handler(fifo_info_t *fifo_data); +static void rx_intr_handler(struct ring_info *ring_data); +static void tx_intr_handler(struct fifo_info *fifo_data); static void alarm_intr_handler(struct s2io_nic *sp); static int s2io_starter(void); +static void s2io_closer(void); static void s2io_tx_watchdog(struct net_device *dev); static void s2io_tasklet(unsigned long dev_addr); static void s2io_set_multicast(struct net_device *dev); -static int rx_osm_handler(ring_info_t *ring_data, RxD_t * rxdp); -static void s2io_link(nic_t * sp, int link); -#if defined(CONFIG_S2IO_NAPI) +static int rx_osm_handler(struct ring_info *ring_data, struct RxD_t * rxdp); +static void s2io_link(struct s2io_nic * sp, int link); +static void s2io_reset(struct s2io_nic * sp); static int s2io_poll(struct net_device *dev, int *budget); -#endif -static void s2io_init_pci(nic_t * sp); +static void s2io_init_pci(struct s2io_nic * sp); static int s2io_set_mac_addr(struct net_device *dev, u8 * addr); static void s2io_alarm_handle(unsigned long data); -static int s2io_enable_msi(nic_t *nic); +static int s2io_enable_msi(struct s2io_nic *nic); static irqreturn_t s2io_msi_handle(int irq, void *dev_id); static irqreturn_t s2io_msix_ring_handle(int irq, void *dev_id); static irqreturn_t s2io_msix_fifo_handle(int irq, void *dev_id); static irqreturn_t s2io_isr(int irq, void *dev_id); -static int verify_xena_quiescence(nic_t *sp, u64 val64, int flag); +static int verify_xena_quiescence(struct s2io_nic *sp); static const struct ethtool_ops netdev_ethtool_ops; static void s2io_set_link(struct work_struct *work); -static int s2io_set_swapper(nic_t * sp); -static void s2io_card_down(nic_t *nic); -static int s2io_card_up(nic_t *nic); +static int s2io_set_swapper(struct s2io_nic * sp); +static void s2io_card_down(struct s2io_nic *nic); +static int s2io_card_up(struct s2io_nic *nic); static int get_xena_rev_id(struct pci_dev *pdev); -static void restore_xmsi_data(nic_t *nic); +static int wait_for_cmd_complete(void __iomem *addr, u64 busy_bit); +static int s2io_add_isr(struct s2io_nic * sp); +static void s2io_rem_isr(struct s2io_nic * sp); + +static void restore_xmsi_data(struct s2io_nic *nic); -static int s2io_club_tcp_session(u8 *buffer, u8 **tcp, u32 *tcp_len, lro_t **lro, RxD_t *rxdp, nic_t *sp); -static void clear_lro_session(lro_t *lro); +static int +s2io_club_tcp_session(u8 *buffer, u8 **tcp, u32 *tcp_len, struct lro **lro, + struct RxD_t *rxdp, struct s2io_nic *sp); +static void clear_lro_session(struct lro *lro); static void queue_rx_frame(struct sk_buff *skb); -static void update_L3L4_header(nic_t *sp, lro_t *lro); -static void lro_append_pkt(nic_t *sp, lro_t *lro, struct sk_buff *skb, u32 tcp_len); +static void update_L3L4_header(struct s2io_nic *sp, struct lro *lro); +static void lro_append_pkt(struct s2io_nic *sp, struct lro *lro, + struct sk_buff *skb, u32 tcp_len); #define s2io_tcp_mss(skb) skb_shinfo(skb)->gso_size #define s2io_udp_mss(skb) skb_shinfo(skb)->gso_size diff --git a/drivers/net/sc92031.c b/drivers/net/sc92031.c new file mode 100644 index 0000000..4a926f2 --- /dev/null +++ b/drivers/net/sc92031.c @@ -0,0 +1,1620 @@ +/* Silan SC92031 PCI Fast Ethernet Adapter driver + * + * Based on vendor drivers: + * Silan Fast Ethernet Netcard Driver: + * MODULE_AUTHOR ("gaoyonghong"); + * MODULE_DESCRIPTION ("SILAN Fast Ethernet driver"); + * MODULE_LICENSE("GPL"); + * 8139D Fast Ethernet driver: + * (C) 2002 by gaoyonghong + * MODULE_AUTHOR ("gaoyonghong"); + * MODULE_DESCRIPTION ("Rsltek 8139D PCI Fast Ethernet Adapter driver"); + * MODULE_LICENSE("GPL"); + * Both are almost identical and seem to be based on pci-skeleton.c + * + * Rewritten for 2.6 by Cesar Eduardo Barros + */ + +/* Note about set_mac_address: I don't know how to change the hardware + * matching, so you need to enable IFF_PROMISC when using it. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#define PCI_VENDOR_ID_SILAN 0x1904 +#define PCI_DEVICE_ID_SILAN_SC92031 0x2031 +#define PCI_DEVICE_ID_SILAN_8139D 0x8139 + +#define SC92031_NAME "sc92031" +#define SC92031_DESCRIPTION "Silan SC92031 PCI Fast Ethernet Adapter driver" +#define SC92031_VERSION "2.0c" + +/* BAR 0 is MMIO, BAR 1 is PIO */ +#ifndef SC92031_USE_BAR +#define SC92031_USE_BAR 0 +#endif + +/* Maximum number of multicast addresses to filter (vs. Rx-all-multicast). */ +static int multicast_filter_limit = 64; +module_param(multicast_filter_limit, int, 0); +MODULE_PARM_DESC(multicast_filter_limit, + "Maximum number of filtered multicast addresses"); + +static int media; +module_param(media, int, 0); +MODULE_PARM_DESC(media, "Media type (0x00 = autodetect," + " 0x01 = 10M half, 0x02 = 10M full," + " 0x04 = 100M half, 0x08 = 100M full)"); + +/* Size of the in-memory receive ring. */ +#define RX_BUF_LEN_IDX 3 /* 0==8K, 1==16K, 2==32K, 3==64K ,4==128K*/ +#define RX_BUF_LEN (8192 << RX_BUF_LEN_IDX) + +/* Number of Tx descriptor registers. */ +#define NUM_TX_DESC 4 + +/* max supported ethernet frame size -- must be at least (dev->mtu+14+4).*/ +#define MAX_ETH_FRAME_SIZE 1536 + +/* Size of the Tx bounce buffers -- must be at least (dev->mtu+14+4). */ +#define TX_BUF_SIZE MAX_ETH_FRAME_SIZE +#define TX_BUF_TOT_LEN (TX_BUF_SIZE * NUM_TX_DESC) + +/* The following settings are log_2(bytes)-4: 0 == 16 bytes .. 6==1024, 7==end of packet. */ +#define RX_FIFO_THRESH 7 /* Rx buffer level before first PCI xfer. */ + +/* Time in jiffies before concluding the transmitter is hung. */ +#define TX_TIMEOUT (4*HZ) + +#define SILAN_STATS_NUM 2 /* number of ETHTOOL_GSTATS */ + +/* media options */ +#define AUTOSELECT 0x00 +#define M10_HALF 0x01 +#define M10_FULL 0x02 +#define M100_HALF 0x04 +#define M100_FULL 0x08 + + /* Symbolic offsets to registers. */ +enum silan_registers { + Config0 = 0x00, // Config0 + Config1 = 0x04, // Config1 + RxBufWPtr = 0x08, // Rx buffer writer poiter + IntrStatus = 0x0C, // Interrupt status + IntrMask = 0x10, // Interrupt mask + RxbufAddr = 0x14, // Rx buffer start address + RxBufRPtr = 0x18, // Rx buffer read pointer + Txstatusall = 0x1C, // Transmit status of all descriptors + TxStatus0 = 0x20, // Transmit status (Four 32bit registers). + TxAddr0 = 0x30, // Tx descriptors (also four 32bit). + RxConfig = 0x40, // Rx configuration + MAC0 = 0x44, // Ethernet hardware address. + MAR0 = 0x4C, // Multicast filter. + RxStatus0 = 0x54, // Rx status + TxConfig = 0x5C, // Tx configuration + PhyCtrl = 0x60, // physical control + FlowCtrlConfig = 0x64, // flow control + Miicmd0 = 0x68, // Mii command0 register + Miicmd1 = 0x6C, // Mii command1 register + Miistatus = 0x70, // Mii status register + Timercnt = 0x74, // Timer counter register + TimerIntr = 0x78, // Timer interrupt register + PMConfig = 0x7C, // Power Manager configuration + CRC0 = 0x80, // Power Manager CRC ( Two 32bit regisers) + Wakeup0 = 0x88, // power Manager wakeup( Eight 64bit regiser) + LSBCRC0 = 0xC8, // power Manager LSBCRC(Two 32bit regiser) + TestD0 = 0xD0, + TestD4 = 0xD4, + TestD8 = 0xD8, +}; + +#define MII_BMCR 0 // Basic mode control register +#define MII_BMSR 1 // Basic mode status register +#define MII_JAB 16 +#define MII_OutputStatus 24 + +#define BMCR_FULLDPLX 0x0100 // Full duplex +#define BMCR_ANRESTART 0x0200 // Auto negotiation restart +#define BMCR_ANENABLE 0x1000 // Enable auto negotiation +#define BMCR_SPEED100 0x2000 // Select 100Mbps +#define BMSR_LSTATUS 0x0004 // Link status +#define PHY_16_JAB_ENB 0x1000 +#define PHY_16_PORT_ENB 0x1 + +enum IntrStatusBits { + LinkFail = 0x80000000, + LinkOK = 0x40000000, + TimeOut = 0x20000000, + RxOverflow = 0x0040, + RxOK = 0x0020, + TxOK = 0x0001, + IntrBits = LinkFail|LinkOK|TimeOut|RxOverflow|RxOK|TxOK, +}; + +enum TxStatusBits { + TxCarrierLost = 0x20000000, + TxAborted = 0x10000000, + TxOutOfWindow = 0x08000000, + TxNccShift = 22, + EarlyTxThresShift = 16, + TxStatOK = 0x8000, + TxUnderrun = 0x4000, + TxOwn = 0x2000, +}; + +enum RxStatusBits { + RxStatesOK = 0x80000, + RxBadAlign = 0x40000, + RxHugeFrame = 0x20000, + RxSmallFrame = 0x10000, + RxCRCOK = 0x8000, + RxCrlFrame = 0x4000, + Rx_Broadcast = 0x2000, + Rx_Multicast = 0x1000, + RxAddrMatch = 0x0800, + MiiErr = 0x0400, +}; + +enum RxConfigBits { + RxFullDx = 0x80000000, + RxEnb = 0x40000000, + RxSmall = 0x20000000, + RxHuge = 0x10000000, + RxErr = 0x08000000, + RxAllphys = 0x04000000, + RxMulticast = 0x02000000, + RxBroadcast = 0x01000000, + RxLoopBack = (1 << 23) | (1 << 22), + LowThresholdShift = 12, + HighThresholdShift = 2, +}; + +enum TxConfigBits { + TxFullDx = 0x80000000, + TxEnb = 0x40000000, + TxEnbPad = 0x20000000, + TxEnbHuge = 0x10000000, + TxEnbFCS = 0x08000000, + TxNoBackOff = 0x04000000, + TxEnbPrem = 0x02000000, + TxCareLostCrs = 0x1000000, + TxExdCollNum = 0xf00000, + TxDataRate = 0x80000, +}; + +enum PhyCtrlconfigbits { + PhyCtrlAne = 0x80000000, + PhyCtrlSpd100 = 0x40000000, + PhyCtrlSpd10 = 0x20000000, + PhyCtrlPhyBaseAddr = 0x1f000000, + PhyCtrlDux = 0x800000, + PhyCtrlReset = 0x400000, +}; + +enum FlowCtrlConfigBits { + FlowCtrlFullDX = 0x80000000, + FlowCtrlEnb = 0x40000000, +}; + +enum Config0Bits { + Cfg0_Reset = 0x80000000, + Cfg0_Anaoff = 0x40000000, + Cfg0_LDPS = 0x20000000, +}; + +enum Config1Bits { + Cfg1_EarlyRx = 1 << 31, + Cfg1_EarlyTx = 1 << 30, + + //rx buffer size + Cfg1_Rcv8K = 0x0, + Cfg1_Rcv16K = 0x1, + Cfg1_Rcv32K = 0x3, + Cfg1_Rcv64K = 0x7, + Cfg1_Rcv128K = 0xf, +}; + +enum MiiCmd0Bits { + Mii_Divider = 0x20000000, + Mii_WRITE = 0x400000, + Mii_READ = 0x200000, + Mii_SCAN = 0x100000, + Mii_Tamod = 0x80000, + Mii_Drvmod = 0x40000, + Mii_mdc = 0x20000, + Mii_mdoen = 0x10000, + Mii_mdo = 0x8000, + Mii_mdi = 0x4000, +}; + +enum MiiStatusBits { + Mii_StatusBusy = 0x80000000, +}; + +enum PMConfigBits { + PM_Enable = 1 << 31, + PM_LongWF = 1 << 30, + PM_Magic = 1 << 29, + PM_LANWake = 1 << 28, + PM_LWPTN = (1 << 27 | 1<< 26), + PM_LinkUp = 1 << 25, + PM_WakeUp = 1 << 24, +}; + +/* Locking rules: + * priv->lock protects most of the fields of priv and most of the + * hardware registers. It does not have to protect against softirqs + * between sc92031_disable_interrupts and sc92031_enable_interrupts; + * it also does not need to be used in ->open and ->stop while the + * device interrupts are off. + * Not having to protect against softirqs is very useful due to heavy + * use of mdelay() at _sc92031_reset. + * Functions prefixed with _sc92031_ must be called with the lock held; + * functions prefixed with sc92031_ must be called without the lock held. + * Use mmiowb() before unlocking if the hardware was written to. + */ + +/* Locking rules for the interrupt: + * - the interrupt and the tasklet never run at the same time + * - neither run between sc92031_disable_interrupts and + * sc92031_enable_interrupt + */ + +struct sc92031_priv { + spinlock_t lock; + /* iomap.h cookie */ + void __iomem *port_base; + /* pci device structure */ + struct pci_dev *pdev; + /* tasklet */ + struct tasklet_struct tasklet; + + /* CPU address of rx ring */ + void *rx_ring; + /* PCI address of rx ring */ + dma_addr_t rx_ring_dma_addr; + /* PCI address of rx ring read pointer */ + dma_addr_t rx_ring_tail; + + /* tx ring write index */ + unsigned tx_head; + /* tx ring read index */ + unsigned tx_tail; + /* CPU address of tx bounce buffer */ + void *tx_bufs; + /* PCI address of tx bounce buffer */ + dma_addr_t tx_bufs_dma_addr; + + /* copies of some hardware registers */ + u32 intr_status; + atomic_t intr_mask; + u32 rx_config; + u32 tx_config; + u32 pm_config; + + /* copy of some flags from dev->flags */ + unsigned int mc_flags; + + /* for ETHTOOL_GSTATS */ + u64 tx_timeouts; + u64 rx_loss; + + /* for dev->get_stats */ + long rx_value; + struct net_device_stats stats; +}; + +/* I don't know which registers can be safely read; however, I can guess + * MAC0 is one of them. */ +static inline void _sc92031_dummy_read(void __iomem *port_base) +{ + ioread32(port_base + MAC0); +} + +static u32 _sc92031_mii_wait(void __iomem *port_base) +{ + u32 mii_status; + + do { + udelay(10); + mii_status = ioread32(port_base + Miistatus); + } while (mii_status & Mii_StatusBusy); + + return mii_status; +} + +static u32 _sc92031_mii_cmd(void __iomem *port_base, u32 cmd0, u32 cmd1) +{ + iowrite32(Mii_Divider, port_base + Miicmd0); + + _sc92031_mii_wait(port_base); + + iowrite32(cmd1, port_base + Miicmd1); + iowrite32(Mii_Divider | cmd0, port_base + Miicmd0); + + return _sc92031_mii_wait(port_base); +} + +static void _sc92031_mii_scan(void __iomem *port_base) +{ + _sc92031_mii_cmd(port_base, Mii_SCAN, 0x1 << 6); +} + +static u16 _sc92031_mii_read(void __iomem *port_base, unsigned reg) +{ + return _sc92031_mii_cmd(port_base, Mii_READ, reg << 6) >> 13; +} + +static void _sc92031_mii_write(void __iomem *port_base, unsigned reg, u16 val) +{ + _sc92031_mii_cmd(port_base, Mii_WRITE, (reg << 6) | ((u32)val << 11)); +} + +static void sc92031_disable_interrupts(struct net_device *dev) +{ + struct sc92031_priv *priv = netdev_priv(dev); + void __iomem *port_base = priv->port_base; + + /* tell the tasklet/interrupt not to enable interrupts */ + atomic_set(&priv->intr_mask, 0); + wmb(); + + /* stop interrupts */ + iowrite32(0, port_base + IntrMask); + _sc92031_dummy_read(port_base); + mmiowb(); + + /* wait for any concurrent interrupt/tasklet to finish */ + synchronize_irq(dev->irq); + tasklet_disable(&priv->tasklet); +} + +static void sc92031_enable_interrupts(struct net_device *dev) +{ + struct sc92031_priv *priv = netdev_priv(dev); + void __iomem *port_base = priv->port_base; + + tasklet_enable(&priv->tasklet); + + atomic_set(&priv->intr_mask, IntrBits); + wmb(); + + iowrite32(IntrBits, port_base + IntrMask); + mmiowb(); +} + +static void _sc92031_disable_tx_rx(struct net_device *dev) +{ + struct sc92031_priv *priv = netdev_priv(dev); + void __iomem *port_base = priv->port_base; + + priv->rx_config &= ~RxEnb; + priv->tx_config &= ~TxEnb; + iowrite32(priv->rx_config, port_base + RxConfig); + iowrite32(priv->tx_config, port_base + TxConfig); +} + +static void _sc92031_enable_tx_rx(struct net_device *dev) +{ + struct sc92031_priv *priv = netdev_priv(dev); + void __iomem *port_base = priv->port_base; + + priv->rx_config |= RxEnb; + priv->tx_config |= TxEnb; + iowrite32(priv->rx_config, port_base + RxConfig); + iowrite32(priv->tx_config, port_base + TxConfig); +} + +static void _sc92031_tx_clear(struct net_device *dev) +{ + struct sc92031_priv *priv = netdev_priv(dev); + + while (priv->tx_head - priv->tx_tail > 0) { + priv->tx_tail++; + priv->stats.tx_dropped++; + } + priv->tx_head = priv->tx_tail = 0; +} + +static void _sc92031_set_mar(struct net_device *dev) +{ + struct sc92031_priv *priv = netdev_priv(dev); + void __iomem *port_base = priv->port_base; + u32 mar0 = 0, mar1 = 0; + + if ((dev->flags & IFF_PROMISC) + || dev->mc_count > multicast_filter_limit + || (dev->flags & IFF_ALLMULTI)) + mar0 = mar1 = 0xffffffff; + else if (dev->flags & IFF_MULTICAST) { + struct dev_mc_list *mc_list; + + for (mc_list = dev->mc_list; mc_list; mc_list = mc_list->next) { + u32 crc; + unsigned bit = 0; + + crc = ~ether_crc(ETH_ALEN, mc_list->dmi_addr); + crc >>= 24; + + if (crc & 0x01) bit |= 0x02; + if (crc & 0x02) bit |= 0x01; + if (crc & 0x10) bit |= 0x20; + if (crc & 0x20) bit |= 0x10; + if (crc & 0x40) bit |= 0x08; + if (crc & 0x80) bit |= 0x04; + + if (bit > 31) + mar0 |= 0x1 << (bit - 32); + else + mar1 |= 0x1 << bit; + } + } + + iowrite32(mar0, port_base + MAR0); + iowrite32(mar1, port_base + MAR0 + 4); +} + +static void _sc92031_set_rx_config(struct net_device *dev) +{ + struct sc92031_priv *priv = netdev_priv(dev); + void __iomem *port_base = priv->port_base; + unsigned int old_mc_flags; + u32 rx_config_bits = 0; + + old_mc_flags = priv->mc_flags; + + if (dev->flags & IFF_PROMISC) + rx_config_bits |= RxSmall | RxHuge | RxErr | RxBroadcast + | RxMulticast | RxAllphys; + + if (dev->flags & (IFF_ALLMULTI | IFF_MULTICAST)) + rx_config_bits |= RxMulticast; + + if (dev->flags & IFF_BROADCAST) + rx_config_bits |= RxBroadcast; + + priv->rx_config &= ~(RxSmall | RxHuge | RxErr | RxBroadcast + | RxMulticast | RxAllphys); + priv->rx_config |= rx_config_bits; + + priv->mc_flags = dev->flags & (IFF_PROMISC | IFF_ALLMULTI + | IFF_MULTICAST | IFF_BROADCAST); + + if (netif_carrier_ok(dev) && priv->mc_flags != old_mc_flags) + iowrite32(priv->rx_config, port_base + RxConfig); +} + +static bool _sc92031_check_media(struct net_device *dev) +{ + struct sc92031_priv *priv = netdev_priv(dev); + void __iomem *port_base = priv->port_base; + u16 bmsr; + + bmsr = _sc92031_mii_read(port_base, MII_BMSR); + rmb(); + if (bmsr & BMSR_LSTATUS) { + bool speed_100, duplex_full; + u32 flow_ctrl_config = 0; + u16 output_status = _sc92031_mii_read(port_base, + MII_OutputStatus); + _sc92031_mii_scan(port_base); + + speed_100 = output_status & 0x2; + duplex_full = output_status & 0x4; + + /* Initial Tx/Rx configuration */ + priv->rx_config = (0x40 << LowThresholdShift) | (0x1c0 << HighThresholdShift); + priv->tx_config = 0x48800000; + + /* NOTE: vendor driver had dead code here to enable tx padding */ + + if (!speed_100) + priv->tx_config |= 0x80000; + + // configure rx mode + _sc92031_set_rx_config(dev); + + if (duplex_full) { + priv->rx_config |= RxFullDx; + priv->tx_config |= TxFullDx; + flow_ctrl_config = FlowCtrlFullDX | FlowCtrlEnb; + } else { + priv->rx_config &= ~RxFullDx; + priv->tx_config &= ~TxFullDx; + } + + _sc92031_set_mar(dev); + _sc92031_set_rx_config(dev); + _sc92031_enable_tx_rx(dev); + iowrite32(flow_ctrl_config, port_base + FlowCtrlConfig); + + netif_carrier_on(dev); + + if (printk_ratelimit()) + printk(KERN_INFO "%s: link up, %sMbps, %s-duplex\n", + dev->name, + speed_100 ? "100" : "10", + duplex_full ? "full" : "half"); + return true; + } else { + _sc92031_mii_scan(port_base); + + netif_carrier_off(dev); + + _sc92031_disable_tx_rx(dev); + + if (printk_ratelimit()) + printk(KERN_INFO "%s: link down\n", dev->name); + return false; + } +} + +static void _sc92031_phy_reset(struct net_device *dev) +{ + struct sc92031_priv *priv = netdev_priv(dev); + void __iomem *port_base = priv->port_base; + u32 phy_ctrl; + + phy_ctrl = ioread32(port_base + PhyCtrl); + phy_ctrl &= ~(PhyCtrlDux | PhyCtrlSpd100 | PhyCtrlSpd10); + phy_ctrl |= PhyCtrlAne | PhyCtrlReset; + + switch (media) { + default: + case AUTOSELECT: + phy_ctrl |= PhyCtrlDux | PhyCtrlSpd100 | PhyCtrlSpd10; + break; + case M10_HALF: + phy_ctrl |= PhyCtrlSpd10; + break; + case M10_FULL: + phy_ctrl |= PhyCtrlDux | PhyCtrlSpd10; + break; + case M100_HALF: + phy_ctrl |= PhyCtrlSpd100; + break; + case M100_FULL: + phy_ctrl |= PhyCtrlDux | PhyCtrlSpd100; + break; + } + + iowrite32(phy_ctrl, port_base + PhyCtrl); + mdelay(10); + + phy_ctrl &= ~PhyCtrlReset; + iowrite32(phy_ctrl, port_base + PhyCtrl); + mdelay(1); + + _sc92031_mii_write(port_base, MII_JAB, + PHY_16_JAB_ENB | PHY_16_PORT_ENB); + _sc92031_mii_scan(port_base); + + netif_carrier_off(dev); + netif_stop_queue(dev); +} + +static void _sc92031_reset(struct net_device *dev) +{ + struct sc92031_priv *priv = netdev_priv(dev); + void __iomem *port_base = priv->port_base; + + /* disable PM */ + iowrite32(0, port_base + PMConfig); + + /* soft reset the chip */ + iowrite32(Cfg0_Reset, port_base + Config0); + mdelay(200); + + iowrite32(0, port_base + Config0); + mdelay(10); + + /* disable interrupts */ + iowrite32(0, port_base + IntrMask); + + /* clear multicast address */ + iowrite32(0, port_base + MAR0); + iowrite32(0, port_base + MAR0 + 4); + + /* init rx ring */ + iowrite32(priv->rx_ring_dma_addr, port_base + RxbufAddr); + priv->rx_ring_tail = priv->rx_ring_dma_addr; + + /* init tx ring */ + _sc92031_tx_clear(dev); + + /* clear old register values */ + priv->intr_status = 0; + atomic_set(&priv->intr_mask, 0); + priv->rx_config = 0; + priv->tx_config = 0; + priv->mc_flags = 0; + + /* configure rx buffer size */ + /* NOTE: vendor driver had dead code here to enable early tx/rx */ + iowrite32(Cfg1_Rcv64K, port_base + Config1); + + _sc92031_phy_reset(dev); + _sc92031_check_media(dev); + + /* calculate rx fifo overflow */ + priv->rx_value = 0; + + /* enable PM */ + iowrite32(priv->pm_config, port_base + PMConfig); + + /* clear intr register */ + ioread32(port_base + IntrStatus); +} + +static void _sc92031_tx_tasklet(struct net_device *dev) +{ + struct sc92031_priv *priv = netdev_priv(dev); + void __iomem *port_base = priv->port_base; + + unsigned old_tx_tail; + unsigned entry; + u32 tx_status; + + old_tx_tail = priv->tx_tail; + while (priv->tx_head - priv->tx_tail > 0) { + entry = priv->tx_tail % NUM_TX_DESC; + tx_status = ioread32(port_base + TxStatus0 + entry * 4); + + if (!(tx_status & (TxStatOK | TxUnderrun | TxAborted))) + break; + + priv->tx_tail++; + + if (tx_status & TxStatOK) { + priv->stats.tx_bytes += tx_status & 0x1fff; + priv->stats.tx_packets++; + /* Note: TxCarrierLost is always asserted at 100mbps. */ + priv->stats.collisions += (tx_status >> 22) & 0xf; + } + + if (tx_status & (TxOutOfWindow | TxAborted)) { + priv->stats.tx_errors++; + + if (tx_status & TxAborted) + priv->stats.tx_aborted_errors++; + + if (tx_status & TxCarrierLost) + priv->stats.tx_carrier_errors++; + + if (tx_status & TxOutOfWindow) + priv->stats.tx_window_errors++; + } + + if (tx_status & TxUnderrun) + priv->stats.tx_fifo_errors++; + } + + if (priv->tx_tail != old_tx_tail) + if (netif_queue_stopped(dev)) + netif_wake_queue(dev); +} + +static void _sc92031_rx_tasklet_error(u32 rx_status, + struct sc92031_priv *priv, unsigned rx_size) +{ + if(rx_size > (MAX_ETH_FRAME_SIZE + 4) || rx_size < 16) { + priv->stats.rx_errors++; + priv->stats.rx_length_errors++; + } + + if (!(rx_status & RxStatesOK)) { + priv->stats.rx_errors++; + + if (rx_status & (RxHugeFrame | RxSmallFrame)) + priv->stats.rx_length_errors++; + + if (rx_status & RxBadAlign) + priv->stats.rx_frame_errors++; + + if (!(rx_status & RxCRCOK)) + priv->stats.rx_crc_errors++; + } else + priv->rx_loss++; +} + +static void _sc92031_rx_tasklet(struct net_device *dev) +{ + struct sc92031_priv *priv = netdev_priv(dev); + void __iomem *port_base = priv->port_base; + + dma_addr_t rx_ring_head; + unsigned rx_len; + unsigned rx_ring_offset; + void *rx_ring = priv->rx_ring; + + rx_ring_head = ioread32(port_base + RxBufWPtr); + rmb(); + + /* rx_ring_head is only 17 bits in the RxBufWPtr register. + * we need to change it to 32 bits physical address + */ + rx_ring_head &= (dma_addr_t)(RX_BUF_LEN - 1); + rx_ring_head |= priv->rx_ring_dma_addr & ~(dma_addr_t)(RX_BUF_LEN - 1); + if (rx_ring_head < priv->rx_ring_dma_addr) + rx_ring_head += RX_BUF_LEN; + + if (rx_ring_head >= priv->rx_ring_tail) + rx_len = rx_ring_head - priv->rx_ring_tail; + else + rx_len = RX_BUF_LEN - (priv->rx_ring_tail - rx_ring_head); + + if (!rx_len) + return; + + if (unlikely(rx_len > RX_BUF_LEN)) { + if (printk_ratelimit()) + printk(KERN_ERR "%s: rx packets length > rx buffer\n", + dev->name); + return; + } + + rx_ring_offset = (priv->rx_ring_tail - priv->rx_ring_dma_addr) % RX_BUF_LEN; + + while (rx_len) { + u32 rx_status; + unsigned rx_size, rx_size_align, pkt_size; + struct sk_buff *skb; + + rx_status = le32_to_cpup((__le32 *)(rx_ring + rx_ring_offset)); + rmb(); + + rx_size = rx_status >> 20; + rx_size_align = (rx_size + 3) & ~3; // for 4 bytes aligned + pkt_size = rx_size - 4; // Omit the four octet CRC from the length. + + rx_ring_offset = (rx_ring_offset + 4) % RX_BUF_LEN; + + if (unlikely(rx_status == 0 + || rx_size > (MAX_ETH_FRAME_SIZE + 4) + || rx_size < 16 + || !(rx_status & RxStatesOK))) { + _sc92031_rx_tasklet_error(rx_status, priv, rx_size); + break; + } + + if (unlikely(rx_size_align + 4 > rx_len)) { + if (printk_ratelimit()) + printk(KERN_ERR "%s: rx_len is too small\n", dev->name); + break; + } + + rx_len -= rx_size_align + 4; + + skb = dev_alloc_skb(pkt_size + NET_IP_ALIGN); + if (unlikely(!skb)) { + if (printk_ratelimit()) + printk(KERN_ERR "%s: Couldn't allocate a skb_buff for a packet of size %u\n", + dev->name, pkt_size); + goto next; + } + + skb_reserve(skb, NET_IP_ALIGN); + + if ((rx_ring_offset + pkt_size) > RX_BUF_LEN) { + memcpy(skb_put(skb, RX_BUF_LEN - rx_ring_offset), + rx_ring + rx_ring_offset, RX_BUF_LEN - rx_ring_offset); + memcpy(skb_put(skb, pkt_size - (RX_BUF_LEN - rx_ring_offset)), + rx_ring, pkt_size - (RX_BUF_LEN - rx_ring_offset)); + } else { + memcpy(skb_put(skb, pkt_size), rx_ring + rx_ring_offset, pkt_size); + } + + skb->dev = dev; + skb->protocol = eth_type_trans(skb, dev); + dev->last_rx = jiffies; + netif_rx(skb); + + priv->stats.rx_bytes += pkt_size; + priv->stats.rx_packets++; + + if (rx_status & Rx_Multicast) + priv->stats.multicast++; + + next: + rx_ring_offset = (rx_ring_offset + rx_size_align) % RX_BUF_LEN; + } + mb(); + + priv->rx_ring_tail = rx_ring_head; + iowrite32(priv->rx_ring_tail, port_base + RxBufRPtr); +} + +static void _sc92031_link_tasklet(struct net_device *dev) +{ + struct sc92031_priv *priv = netdev_priv(dev); + + if (_sc92031_check_media(dev)) + netif_wake_queue(dev); + else { + netif_stop_queue(dev); + priv->stats.tx_carrier_errors++; + } +} + +static void sc92031_tasklet(unsigned long data) +{ + struct net_device *dev = (struct net_device *)data; + struct sc92031_priv *priv = netdev_priv(dev); + void __iomem *port_base = priv->port_base; + u32 intr_status, intr_mask; + + intr_status = priv->intr_status; + + spin_lock(&priv->lock); + + if (unlikely(!netif_running(dev))) + goto out; + + if (intr_status & TxOK) + _sc92031_tx_tasklet(dev); + + if (intr_status & RxOK) + _sc92031_rx_tasklet(dev); + + if (intr_status & RxOverflow) + priv->stats.rx_errors++; + + if (intr_status & TimeOut) { + priv->stats.rx_errors++; + priv->stats.rx_length_errors++; + } + + if (intr_status & (LinkFail | LinkOK)) + _sc92031_link_tasklet(dev); + +out: + intr_mask = atomic_read(&priv->intr_mask); + rmb(); + + iowrite32(intr_mask, port_base + IntrMask); + mmiowb(); + + spin_unlock(&priv->lock); +} + +static irqreturn_t sc92031_interrupt(int irq, void *dev_id) +{ + struct net_device *dev = dev_id; + struct sc92031_priv *priv = netdev_priv(dev); + void __iomem *port_base = priv->port_base; + u32 intr_status, intr_mask; + + /* mask interrupts before clearing IntrStatus */ + iowrite32(0, port_base + IntrMask); + _sc92031_dummy_read(port_base); + + intr_status = ioread32(port_base + IntrStatus); + if (unlikely(intr_status == 0xffffffff)) + return IRQ_NONE; // hardware has gone missing + + intr_status &= IntrBits; + if (!intr_status) + goto out_none; + + priv->intr_status = intr_status; + tasklet_schedule(&priv->tasklet); + + return IRQ_HANDLED; + +out_none: + intr_mask = atomic_read(&priv->intr_mask); + rmb(); + + iowrite32(intr_mask, port_base + IntrMask); + mmiowb(); + + return IRQ_NONE; +} + +static struct net_device_stats *sc92031_get_stats(struct net_device *dev) +{ + struct sc92031_priv *priv = netdev_priv(dev); + void __iomem *port_base = priv->port_base; + + // FIXME I do not understand what is this trying to do. + if (netif_running(dev)) { + int temp; + + spin_lock_bh(&priv->lock); + + /* Update the error count. */ + temp = (ioread32(port_base + RxStatus0) >> 16) & 0xffff; + + if (temp == 0xffff) { + priv->rx_value += temp; + priv->stats.rx_fifo_errors = priv->rx_value; + } else { + priv->stats.rx_fifo_errors = temp + priv->rx_value; + } + + spin_unlock_bh(&priv->lock); + } + + return &priv->stats; +} + +static int sc92031_start_xmit(struct sk_buff *skb, struct net_device *dev) +{ + int err = 0; + struct sc92031_priv *priv = netdev_priv(dev); + void __iomem *port_base = priv->port_base; + + unsigned len; + unsigned entry; + u32 tx_status; + + if (unlikely(skb->len > TX_BUF_SIZE)) { + err = -EMSGSIZE; + priv->stats.tx_dropped++; + goto out; + } + + spin_lock_bh(&priv->lock); + + if (unlikely(!netif_carrier_ok(dev))) { + err = -ENOLINK; + priv->stats.tx_dropped++; + goto out_unlock; + } + + BUG_ON(priv->tx_head - priv->tx_tail >= NUM_TX_DESC); + + entry = priv->tx_head++ % NUM_TX_DESC; + + skb_copy_and_csum_dev(skb, priv->tx_bufs + entry * TX_BUF_SIZE); + + len = skb->len; + if (unlikely(len < ETH_ZLEN)) { + memset(priv->tx_bufs + entry * TX_BUF_SIZE + len, + 0, ETH_ZLEN - len); + len = ETH_ZLEN; + } + + wmb(); + + if (len < 100) + tx_status = len; + else if (len < 300) + tx_status = 0x30000 | len; + else + tx_status = 0x50000 | len; + + iowrite32(priv->tx_bufs_dma_addr + entry * TX_BUF_SIZE, + port_base + TxAddr0 + entry * 4); + iowrite32(tx_status, port_base + TxStatus0 + entry * 4); + mmiowb(); + + dev->trans_start = jiffies; + + if (priv->tx_head - priv->tx_tail >= NUM_TX_DESC) + netif_stop_queue(dev); + +out_unlock: + spin_unlock_bh(&priv->lock); + +out: + dev_kfree_skb(skb); + + return err; +} + +static int sc92031_open(struct net_device *dev) +{ + int err; + struct sc92031_priv *priv = netdev_priv(dev); + struct pci_dev *pdev = priv->pdev; + + priv->rx_ring = pci_alloc_consistent(pdev, RX_BUF_LEN, + &priv->rx_ring_dma_addr); + if (unlikely(!priv->rx_ring)) { + err = -ENOMEM; + goto out_alloc_rx_ring; + } + + priv->tx_bufs = pci_alloc_consistent(pdev, TX_BUF_TOT_LEN, + &priv->tx_bufs_dma_addr); + if (unlikely(!priv->tx_bufs)) { + err = -ENOMEM; + goto out_alloc_tx_bufs; + } + priv->tx_head = priv->tx_tail = 0; + + err = request_irq(pdev->irq, sc92031_interrupt, + IRQF_SHARED, dev->name, dev); + if (unlikely(err < 0)) + goto out_request_irq; + + priv->pm_config = 0; + + /* Interrupts already disabled by sc92031_stop or sc92031_probe */ + spin_lock(&priv->lock); + + _sc92031_reset(dev); + mmiowb(); + + spin_unlock(&priv->lock); + sc92031_enable_interrupts(dev); + + if (netif_carrier_ok(dev)) + netif_start_queue(dev); + else + netif_tx_disable(dev); + + return 0; + +out_request_irq: + pci_free_consistent(pdev, TX_BUF_TOT_LEN, priv->tx_bufs, + priv->tx_bufs_dma_addr); +out_alloc_tx_bufs: + pci_free_consistent(pdev, RX_BUF_LEN, priv->rx_ring, + priv->rx_ring_dma_addr); +out_alloc_rx_ring: + return err; +} + +static int sc92031_stop(struct net_device *dev) +{ + struct sc92031_priv *priv = netdev_priv(dev); + struct pci_dev *pdev = priv->pdev; + + netif_tx_disable(dev); + + /* Disable interrupts, stop Tx and Rx. */ + sc92031_disable_interrupts(dev); + + spin_lock(&priv->lock); + + _sc92031_disable_tx_rx(dev); + _sc92031_tx_clear(dev); + mmiowb(); + + spin_unlock(&priv->lock); + + free_irq(pdev->irq, dev); + pci_free_consistent(pdev, TX_BUF_TOT_LEN, priv->tx_bufs, + priv->tx_bufs_dma_addr); + pci_free_consistent(pdev, RX_BUF_LEN, priv->rx_ring, + priv->rx_ring_dma_addr); + + return 0; +} + +static void sc92031_set_multicast_list(struct net_device *dev) +{ + struct sc92031_priv *priv = netdev_priv(dev); + + spin_lock_bh(&priv->lock); + + _sc92031_set_mar(dev); + _sc92031_set_rx_config(dev); + mmiowb(); + + spin_unlock_bh(&priv->lock); +} + +static void sc92031_tx_timeout(struct net_device *dev) +{ + struct sc92031_priv *priv = netdev_priv(dev); + + /* Disable interrupts by clearing the interrupt mask.*/ + sc92031_disable_interrupts(dev); + + spin_lock(&priv->lock); + + priv->tx_timeouts++; + + _sc92031_reset(dev); + mmiowb(); + + spin_unlock(&priv->lock); + + /* enable interrupts */ + sc92031_enable_interrupts(dev); + + if (netif_carrier_ok(dev)) + netif_wake_queue(dev); +} + +#ifdef CONFIG_NET_POLL_CONTROLLER +static void sc92031_poll_controller(struct net_device *dev) +{ + disable_irq(dev->irq); + if (sc92031_interrupt(dev->irq, dev) != IRQ_NONE) + sc92031_tasklet((unsigned long)dev); + enable_irq(dev->irq); +} +#endif + +static int sc92031_ethtool_get_settings(struct net_device *dev, + struct ethtool_cmd *cmd) +{ + struct sc92031_priv *priv = netdev_priv(dev); + void __iomem *port_base = priv->port_base; + u8 phy_address; + u32 phy_ctrl; + u16 output_status; + + spin_lock_bh(&priv->lock); + + phy_address = ioread32(port_base + Miicmd1) >> 27; + phy_ctrl = ioread32(port_base + PhyCtrl); + + output_status = _sc92031_mii_read(port_base, MII_OutputStatus); + _sc92031_mii_scan(port_base); + mmiowb(); + + spin_unlock_bh(&priv->lock); + + cmd->supported = SUPPORTED_10baseT_Half | SUPPORTED_10baseT_Full + | SUPPORTED_100baseT_Half | SUPPORTED_100baseT_Full + | SUPPORTED_Autoneg | SUPPORTED_TP | SUPPORTED_MII; + + cmd->advertising = ADVERTISED_TP | ADVERTISED_MII; + + if ((phy_ctrl & (PhyCtrlDux | PhyCtrlSpd100 | PhyCtrlSpd10)) + == (PhyCtrlDux | PhyCtrlSpd100 | PhyCtrlSpd10)) + cmd->advertising |= ADVERTISED_Autoneg; + + if ((phy_ctrl & PhyCtrlSpd10) == PhyCtrlSpd10) + cmd->advertising |= ADVERTISED_10baseT_Half; + + if ((phy_ctrl & (PhyCtrlSpd10 | PhyCtrlDux)) + == (PhyCtrlSpd10 | PhyCtrlDux)) + cmd->advertising |= ADVERTISED_10baseT_Full; + + if ((phy_ctrl & PhyCtrlSpd100) == PhyCtrlSpd100) + cmd->advertising |= ADVERTISED_100baseT_Half; + + if ((phy_ctrl & (PhyCtrlSpd100 | PhyCtrlDux)) + == (PhyCtrlSpd100 | PhyCtrlDux)) + cmd->advertising |= ADVERTISED_100baseT_Full; + + if (phy_ctrl & PhyCtrlAne) + cmd->advertising |= ADVERTISED_Autoneg; + + cmd->speed = (output_status & 0x2) ? SPEED_100 : SPEED_10; + cmd->duplex = (output_status & 0x4) ? DUPLEX_FULL : DUPLEX_HALF; + cmd->port = PORT_MII; + cmd->phy_address = phy_address; + cmd->transceiver = XCVR_INTERNAL; + cmd->autoneg = (phy_ctrl & PhyCtrlAne) ? AUTONEG_ENABLE : AUTONEG_DISABLE; + + return 0; +} + +static int sc92031_ethtool_set_settings(struct net_device *dev, + struct ethtool_cmd *cmd) +{ + struct sc92031_priv *priv = netdev_priv(dev); + void __iomem *port_base = priv->port_base; + u32 phy_ctrl; + u32 old_phy_ctrl; + + if (!(cmd->speed == SPEED_10 || cmd->speed == SPEED_100)) + return -EINVAL; + if (!(cmd->duplex == DUPLEX_HALF || cmd->duplex == DUPLEX_FULL)) + return -EINVAL; + if (!(cmd->port == PORT_MII)) + return -EINVAL; + if (!(cmd->phy_address == 0x1f)) + return -EINVAL; + if (!(cmd->transceiver == XCVR_INTERNAL)) + return -EINVAL; + if (!(cmd->autoneg == AUTONEG_DISABLE || cmd->autoneg == AUTONEG_ENABLE)) + return -EINVAL; + + if (cmd->autoneg == AUTONEG_ENABLE) { + if (!(cmd->advertising & (ADVERTISED_Autoneg + | ADVERTISED_100baseT_Full + | ADVERTISED_100baseT_Half + | ADVERTISED_10baseT_Full + | ADVERTISED_10baseT_Half))) + return -EINVAL; + + phy_ctrl = PhyCtrlAne; + + // FIXME: I'm not sure what the original code was trying to do + if (cmd->advertising & ADVERTISED_Autoneg) + phy_ctrl |= PhyCtrlDux | PhyCtrlSpd100 | PhyCtrlSpd10; + if (cmd->advertising & ADVERTISED_100baseT_Full) + phy_ctrl |= PhyCtrlDux | PhyCtrlSpd100; + if (cmd->advertising & ADVERTISED_100baseT_Half) + phy_ctrl |= PhyCtrlSpd100; + if (cmd->advertising & ADVERTISED_10baseT_Full) + phy_ctrl |= PhyCtrlSpd10 | PhyCtrlDux; + if (cmd->advertising & ADVERTISED_10baseT_Half) + phy_ctrl |= PhyCtrlSpd10; + } else { + // FIXME: Whole branch guessed + phy_ctrl = 0; + + if (cmd->speed == SPEED_10) + phy_ctrl |= PhyCtrlSpd10; + else /* cmd->speed == SPEED_100 */ + phy_ctrl |= PhyCtrlSpd100; + + if (cmd->duplex == DUPLEX_FULL) + phy_ctrl |= PhyCtrlDux; + } + + spin_lock_bh(&priv->lock); + + old_phy_ctrl = ioread32(port_base + PhyCtrl); + phy_ctrl |= old_phy_ctrl & ~(PhyCtrlAne | PhyCtrlDux + | PhyCtrlSpd100 | PhyCtrlSpd10); + if (phy_ctrl != old_phy_ctrl) + iowrite32(phy_ctrl, port_base + PhyCtrl); + + spin_unlock_bh(&priv->lock); + + return 0; +} + +static void sc92031_ethtool_get_drvinfo(struct net_device *dev, + struct ethtool_drvinfo *drvinfo) +{ + struct sc92031_priv *priv = netdev_priv(dev); + struct pci_dev *pdev = priv->pdev; + + strcpy(drvinfo->driver, SC92031_NAME); + strcpy(drvinfo->version, SC92031_VERSION); + strcpy(drvinfo->bus_info, pci_name(pdev)); +} + +static void sc92031_ethtool_get_wol(struct net_device *dev, + struct ethtool_wolinfo *wolinfo) +{ + struct sc92031_priv *priv = netdev_priv(dev); + void __iomem *port_base = priv->port_base; + u32 pm_config; + + spin_lock_bh(&priv->lock); + pm_config = ioread32(port_base + PMConfig); + spin_unlock_bh(&priv->lock); + + // FIXME: Guessed + wolinfo->supported = WAKE_PHY | WAKE_MAGIC + | WAKE_UCAST | WAKE_MCAST | WAKE_BCAST; + wolinfo->wolopts = 0; + + if (pm_config & PM_LinkUp) + wolinfo->wolopts |= WAKE_PHY; + + if (pm_config & PM_Magic) + wolinfo->wolopts |= WAKE_MAGIC; + + if (pm_config & PM_WakeUp) + // FIXME: Guessed + wolinfo->wolopts |= WAKE_UCAST | WAKE_MCAST | WAKE_BCAST; +} + +static int sc92031_ethtool_set_wol(struct net_device *dev, + struct ethtool_wolinfo *wolinfo) +{ + struct sc92031_priv *priv = netdev_priv(dev); + void __iomem *port_base = priv->port_base; + u32 pm_config; + + spin_lock_bh(&priv->lock); + + pm_config = ioread32(port_base + PMConfig) + & ~(PM_LinkUp | PM_Magic | PM_WakeUp); + + if (wolinfo->wolopts & WAKE_PHY) + pm_config |= PM_LinkUp; + + if (wolinfo->wolopts & WAKE_MAGIC) + pm_config |= PM_Magic; + + // FIXME: Guessed + if (wolinfo->wolopts & (WAKE_UCAST | WAKE_MCAST | WAKE_BCAST)) + pm_config |= PM_WakeUp; + + priv->pm_config = pm_config; + iowrite32(pm_config, port_base + PMConfig); + mmiowb(); + + spin_unlock_bh(&priv->lock); + + return 0; +} + +static int sc92031_ethtool_nway_reset(struct net_device *dev) +{ + int err = 0; + struct sc92031_priv *priv = netdev_priv(dev); + void __iomem *port_base = priv->port_base; + u16 bmcr; + + spin_lock_bh(&priv->lock); + + bmcr = _sc92031_mii_read(port_base, MII_BMCR); + if (!(bmcr & BMCR_ANENABLE)) { + err = -EINVAL; + goto out; + } + + _sc92031_mii_write(port_base, MII_BMCR, bmcr | BMCR_ANRESTART); + +out: + _sc92031_mii_scan(port_base); + mmiowb(); + + spin_unlock_bh(&priv->lock); + + return err; +} + +static const char sc92031_ethtool_stats_strings[SILAN_STATS_NUM][ETH_GSTRING_LEN] = { + "tx_timeout", + "rx_loss", +}; + +static void sc92031_ethtool_get_strings(struct net_device *dev, + u32 stringset, u8 *data) +{ + if (stringset == ETH_SS_STATS) + memcpy(data, sc92031_ethtool_stats_strings, + SILAN_STATS_NUM * ETH_GSTRING_LEN); +} + +static int sc92031_ethtool_get_stats_count(struct net_device *dev) +{ + return SILAN_STATS_NUM; +} + +static void sc92031_ethtool_get_ethtool_stats(struct net_device *dev, + struct ethtool_stats *stats, u64 *data) +{ + struct sc92031_priv *priv = netdev_priv(dev); + + spin_lock_bh(&priv->lock); + data[0] = priv->tx_timeouts; + data[1] = priv->rx_loss; + spin_unlock_bh(&priv->lock); +} + +static struct ethtool_ops sc92031_ethtool_ops = { + .get_settings = sc92031_ethtool_get_settings, + .set_settings = sc92031_ethtool_set_settings, + .get_drvinfo = sc92031_ethtool_get_drvinfo, + .get_wol = sc92031_ethtool_get_wol, + .set_wol = sc92031_ethtool_set_wol, + .nway_reset = sc92031_ethtool_nway_reset, + .get_link = ethtool_op_get_link, + .get_tx_csum = ethtool_op_get_tx_csum, + .get_sg = ethtool_op_get_sg, + .get_tso = ethtool_op_get_tso, + .get_strings = sc92031_ethtool_get_strings, + .get_stats_count = sc92031_ethtool_get_stats_count, + .get_ethtool_stats = sc92031_ethtool_get_ethtool_stats, + .get_perm_addr = ethtool_op_get_perm_addr, + .get_ufo = ethtool_op_get_ufo, +}; + +static int __devinit sc92031_probe(struct pci_dev *pdev, + const struct pci_device_id *id) +{ + int err; + void __iomem* port_base; + struct net_device *dev; + struct sc92031_priv *priv; + u32 mac0, mac1; + + err = pci_enable_device(pdev); + if (unlikely(err < 0)) + goto out_enable_device; + + pci_set_master(pdev); + + err = pci_set_dma_mask(pdev, DMA_32BIT_MASK); + if (unlikely(err < 0)) + goto out_set_dma_mask; + + err = pci_set_consistent_dma_mask(pdev, DMA_32BIT_MASK); + if (unlikely(err < 0)) + goto out_set_dma_mask; + + err = pci_request_regions(pdev, SC92031_NAME); + if (unlikely(err < 0)) + goto out_request_regions; + + port_base = pci_iomap(pdev, SC92031_USE_BAR, 0); + if (unlikely(!port_base)) { + err = -EIO; + goto out_iomap; + } + + dev = alloc_etherdev(sizeof(struct sc92031_priv)); + if (unlikely(!dev)) { + err = -ENOMEM; + goto out_alloc_etherdev; + } + + pci_set_drvdata(pdev, dev); + +#if SC92031_USE_BAR == 0 + dev->mem_start = pci_resource_start(pdev, SC92031_USE_BAR); + dev->mem_end = pci_resource_end(pdev, SC92031_USE_BAR); +#elif SC92031_USE_BAR == 1 + dev->base_addr = pci_resource_start(pdev, SC92031_USE_BAR); +#endif + dev->irq = pdev->irq; + + /* faked with skb_copy_and_csum_dev */ + dev->features = NETIF_F_SG | NETIF_F_HW_CSUM | NETIF_F_HIGHDMA; + + dev->get_stats = sc92031_get_stats; + dev->ethtool_ops = &sc92031_ethtool_ops; + dev->hard_start_xmit = sc92031_start_xmit; + dev->watchdog_timeo = TX_TIMEOUT; + dev->open = sc92031_open; + dev->stop = sc92031_stop; + dev->set_multicast_list = sc92031_set_multicast_list; + dev->tx_timeout = sc92031_tx_timeout; +#ifdef CONFIG_NET_POLL_CONTROLLER + dev->poll_controller = sc92031_poll_controller; +#endif + + priv = netdev_priv(dev); + spin_lock_init(&priv->lock); + priv->port_base = port_base; + priv->pdev = pdev; + tasklet_init(&priv->tasklet, sc92031_tasklet, (unsigned long)dev); + /* Fudge tasklet count so the call to sc92031_enable_interrupts at + * sc92031_open will work correctly */ + tasklet_disable_nosync(&priv->tasklet); + + /* PCI PM Wakeup */ + iowrite32((~PM_LongWF & ~PM_LWPTN) | PM_Enable, port_base + PMConfig); + + mac0 = ioread32(port_base + MAC0); + mac1 = ioread32(port_base + MAC0 + 4); + dev->dev_addr[0] = dev->perm_addr[0] = mac0 >> 24; + dev->dev_addr[1] = dev->perm_addr[1] = mac0 >> 16; + dev->dev_addr[2] = dev->perm_addr[2] = mac0 >> 8; + dev->dev_addr[3] = dev->perm_addr[3] = mac0; + dev->dev_addr[4] = dev->perm_addr[4] = mac1 >> 8; + dev->dev_addr[5] = dev->perm_addr[5] = mac1; + + err = register_netdev(dev); + if (err < 0) + goto out_register_netdev; + + return 0; + +out_register_netdev: + free_netdev(dev); +out_alloc_etherdev: + pci_iounmap(pdev, port_base); +out_iomap: + pci_release_regions(pdev); +out_request_regions: +out_set_dma_mask: + pci_disable_device(pdev); +out_enable_device: + return err; +} + +static void __devexit sc92031_remove(struct pci_dev *pdev) +{ + struct net_device *dev = pci_get_drvdata(pdev); + struct sc92031_priv *priv = netdev_priv(dev); + void __iomem* port_base = priv->port_base; + + unregister_netdev(dev); + free_netdev(dev); + pci_iounmap(pdev, port_base); + pci_release_regions(pdev); + pci_disable_device(pdev); +} + +static int sc92031_suspend(struct pci_dev *pdev, pm_message_t state) +{ + struct net_device *dev = pci_get_drvdata(pdev); + struct sc92031_priv *priv = netdev_priv(dev); + + pci_save_state(pdev); + + if (!netif_running(dev)) + goto out; + + netif_device_detach(dev); + + /* Disable interrupts, stop Tx and Rx. */ + sc92031_disable_interrupts(dev); + + spin_lock(&priv->lock); + + _sc92031_disable_tx_rx(dev); + _sc92031_tx_clear(dev); + mmiowb(); + + spin_unlock(&priv->lock); + +out: + pci_set_power_state(pdev, pci_choose_state(pdev, state)); + + return 0; +} + +static int sc92031_resume(struct pci_dev *pdev) +{ + struct net_device *dev = pci_get_drvdata(pdev); + struct sc92031_priv *priv = netdev_priv(dev); + + pci_restore_state(pdev); + pci_set_power_state(pdev, PCI_D0); + + if (!netif_running(dev)) + goto out; + + /* Interrupts already disabled by sc92031_suspend */ + spin_lock(&priv->lock); + + _sc92031_reset(dev); + mmiowb(); + + spin_unlock(&priv->lock); + sc92031_enable_interrupts(dev); + + netif_device_attach(dev); + + if (netif_carrier_ok(dev)) + netif_wake_queue(dev); + else + netif_tx_disable(dev); + +out: + return 0; +} + +static struct pci_device_id sc92031_pci_device_id_table[] __devinitdata = { + { PCI_DEVICE(PCI_VENDOR_ID_SILAN, PCI_DEVICE_ID_SILAN_SC92031) }, + { PCI_DEVICE(PCI_VENDOR_ID_SILAN, PCI_DEVICE_ID_SILAN_8139D) }, + { 0, } +}; +MODULE_DEVICE_TABLE(pci, sc92031_pci_device_id_table); + +static struct pci_driver sc92031_pci_driver = { + .name = SC92031_NAME, + .id_table = sc92031_pci_device_id_table, + .probe = sc92031_probe, + .remove = __devexit_p(sc92031_remove), + .suspend = sc92031_suspend, + .resume = sc92031_resume, +}; + +static int __init sc92031_init(void) +{ + printk(KERN_INFO SC92031_DESCRIPTION " " SC92031_VERSION "\n"); + return pci_register_driver(&sc92031_pci_driver); +} + +static void __exit sc92031_exit(void) +{ + pci_unregister_driver(&sc92031_pci_driver); +} + +module_init(sc92031_init); +module_exit(sc92031_exit); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Cesar Eduardo Barros "); +MODULE_DESCRIPTION(SC92031_DESCRIPTION); +MODULE_VERSION(SC92031_VERSION); diff --git a/drivers/net/sk_mca.c b/drivers/net/sk_mca.c deleted file mode 100644 index 96e06c5..0000000 --- a/drivers/net/sk_mca.c +++ /dev/null @@ -1,1216 +0,0 @@ -/* -net-3-driver for the SKNET MCA-based cards - -This is an extension to the Linux operating system, and is covered by the -same GNU General Public License that covers that work. - -Copyright 1999 by Alfred Arnold (alfred@ccac.rwth-aachen.de, - alfred.arnold@lancom.de) - -This driver is based both on the 3C523 driver and the SK_G16 driver. - -paper sources: - 'PC Hardware: Aufbau, Funktionsweise, Programmierung' by - Hans-Peter Messmer for the basic Microchannel stuff - - 'Linux Geraetetreiber' by Allesandro Rubini, Kalle Dalheimer - for help on Ethernet driver programming - - 'Ethernet/IEEE 802.3 Family 1992 World Network Data Book/Handbook' by AMD - for documentation on the AM7990 LANCE - - 'SKNET Personal Technisches Manual', Version 1.2 by Schneider&Koch - for documentation on the Junior board - - 'SK-NET MC2+ Technical Manual", Version 1.1 by Schneider&Koch for - documentation on the MC2 bord - - A big thank you to the S&K support for providing me so quickly with - documentation! - - Also see http://www.syskonnect.com/ - - Missing things: - - -> set debug level via ioctl instead of compile-time switches - -> I didn't follow the development of the 2.1.x kernels, so my - assumptions about which things changed with which kernel version - are probably nonsense - -History: - May 16th, 1999 - startup - May 22st, 1999 - added private structure, methods - begun building data structures in RAM - May 23nd, 1999 - can receive frames, send frames - May 24th, 1999 - modularized initialization of LANCE - loadable as module - still Tx problem :-( - May 26th, 1999 - MC2 works - support for multiple devices - display media type for MC2+ - May 28th, 1999 - fixed problem in GetLANCE leaving interrupts turned off - increase TX queue to 4 packets to improve send performance - May 29th, 1999 - a few corrections in statistics, caught rcvr overruns - reinitialization of LANCE/board in critical situations - MCA info implemented - implemented LANCE multicast filter - Jun 6th, 1999 - additions for Linux 2.2 - Dec 25th, 1999 - unfortunately there seem to be newer MC2+ boards that react - on IRQ 3/5/9/10 instead of 3/5/10/11, so we have to autoprobe - in questionable cases... - Dec 28th, 1999 - integrated patches from David Weinehall & Bill Wendling for 2.3 - kernels (isa_...functions). Things are defined in a way that - it still works with 2.0.x 8-) - Dec 30th, 1999 - added handling of the remaining interrupt conditions. That - should cure the spurious hangs. - Jan 30th, 2000 - newer kernels automatically probe more than one board, so the - 'startslot' as a variable is also needed here - June 1st, 2000 - added changes for recent 2.3 kernels - - *************************************************************************/ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -#define _SK_MCA_DRIVER_ -#include "sk_mca.h" - -/* ------------------------------------------------------------------------ - * global static data - not more since we can handle multiple boards and - * have to pack all state info into the device struct! - * ------------------------------------------------------------------------ */ - -static char *MediaNames[Media_Count] = - { "10Base2", "10BaseT", "10Base5", "Unknown" }; - -static unsigned char poly[] = - { 1, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 1, 0, 0, 0, - 1, 0, 0, 0, 0, 0, 1, 1, 0, 0, 1, 0, 0, 0, 0, 0 -}; - -/* ------------------------------------------------------------------------ - * private subfunctions - * ------------------------------------------------------------------------ */ - -/* dump parts of shared memory - only needed during debugging */ - -#ifdef DEBUG -static void dumpmem(struct net_device *dev, u32 start, u32 len) -{ - skmca_priv *priv = netdev_priv(dev); - int z; - - for (z = 0; z < len; z++) { - if ((z & 15) == 0) - printk("%04x:", z); - printk(" %02x", readb(priv->base + start + z)); - if ((z & 15) == 15) - printk("\n"); - } -} - -/* print exact time - ditto */ - -static void PrTime(void) -{ - struct timeval tv; - - do_gettimeofday(&tv); - printk("%9d:%06d: ", tv.tv_sec, tv.tv_usec); -} -#endif - -/* deduce resources out of POS registers */ - -static void __init getaddrs(int slot, int junior, int *base, int *irq, - skmca_medium * medium) -{ - u_char pos0, pos1, pos2; - - if (junior) { - pos0 = mca_read_stored_pos(slot, 2); - *base = ((pos0 & 0x0e) << 13) + 0xc0000; - *irq = ((pos0 & 0x10) >> 4) + 10; - *medium = Media_Unknown; - } else { - /* reset POS 104 Bits 0+1 so the shared memory region goes to the - configured area between 640K and 1M. Afterwards, enable the MC2. - I really don't know what rode SK to do this... */ - - mca_write_pos(slot, 4, - mca_read_stored_pos(slot, 4) & 0xfc); - mca_write_pos(slot, 2, - mca_read_stored_pos(slot, 2) | 0x01); - - pos1 = mca_read_stored_pos(slot, 3); - pos2 = mca_read_stored_pos(slot, 4); - *base = ((pos1 & 0x07) << 14) + 0xc0000; - switch (pos2 & 0x0c) { - case 0: - *irq = 3; - break; - case 4: - *irq = 5; - break; - case 8: - *irq = -10; - break; - case 12: - *irq = -11; - break; - } - *medium = (pos2 >> 6) & 3; - } -} - -/* check for both cards: - When the MC2 is turned off, it was configured for more than 15MB RAM, - is disabled and won't get detected using the standard probe. We - therefore have to scan the slots manually :-( */ - -static int __init dofind(int *junior, int firstslot) -{ - int slot; - unsigned int id; - - for (slot = firstslot; slot < MCA_MAX_SLOT_NR; slot++) { - id = mca_read_stored_pos(slot, 0) - + (((unsigned int) mca_read_stored_pos(slot, 1)) << 8); - - *junior = 0; - if (id == SKNET_MCA_ID) - return slot; - *junior = 1; - if (id == SKNET_JUNIOR_MCA_ID) - return slot; - } - return MCA_NOTFOUND; -} - -/* reset the whole board */ - -static void ResetBoard(struct net_device *dev) -{ - skmca_priv *priv = netdev_priv(dev); - - writeb(CTRL_RESET_ON, priv->ctrladdr); - udelay(10); - writeb(CTRL_RESET_OFF, priv->ctrladdr); -} - -/* wait for LANCE interface to become not busy */ - -static int WaitLANCE(struct net_device *dev) -{ - skmca_priv *priv = netdev_priv(dev); - int t = 0; - - while ((readb(priv->ctrladdr) & STAT_IO_BUSY) == - STAT_IO_BUSY) { - udelay(1); - if (++t > 1000) { - printk("%s: LANCE access timeout", dev->name); - return 0; - } - } - - return 1; -} - -/* set LANCE register - must be atomic */ - -static void SetLANCE(struct net_device *dev, u16 addr, u16 value) -{ - skmca_priv *priv = netdev_priv(dev); - unsigned long flags; - - /* disable interrupts */ - - spin_lock_irqsave(&priv->lock, flags); - - /* wait until no transfer is pending */ - - WaitLANCE(dev); - - /* transfer register address to RAP */ - - writeb(CTRL_RESET_OFF | CTRL_RW_WRITE | CTRL_ADR_RAP, priv->ctrladdr); - writew(addr, priv->ioregaddr); - writeb(IOCMD_GO, priv->cmdaddr); - udelay(1); - WaitLANCE(dev); - - /* transfer data to register */ - - writeb(CTRL_RESET_OFF | CTRL_RW_WRITE | CTRL_ADR_DATA, priv->ctrladdr); - writew(value, priv->ioregaddr); - writeb(IOCMD_GO, priv->cmdaddr); - udelay(1); - WaitLANCE(dev); - - /* reenable interrupts */ - - spin_unlock_irqrestore(&priv->lock, flags); -} - -/* get LANCE register */ - -static u16 GetLANCE(struct net_device *dev, u16 addr) -{ - skmca_priv *priv = netdev_priv(dev); - unsigned long flags; - unsigned int res; - - /* disable interrupts */ - - spin_lock_irqsave(&priv->lock, flags); - - /* wait until no transfer is pending */ - - WaitLANCE(dev); - - /* transfer register address to RAP */ - - writeb(CTRL_RESET_OFF | CTRL_RW_WRITE | CTRL_ADR_RAP, priv->ctrladdr); - writew(addr, priv->ioregaddr); - writeb(IOCMD_GO, priv->cmdaddr); - udelay(1); - WaitLANCE(dev); - - /* transfer data from register */ - - writeb(CTRL_RESET_OFF | CTRL_RW_READ | CTRL_ADR_DATA, priv->ctrladdr); - writeb(IOCMD_GO, priv->cmdaddr); - udelay(1); - WaitLANCE(dev); - res = readw(priv->ioregaddr); - - /* reenable interrupts */ - - spin_unlock_irqrestore(&priv->lock, flags); - - return res; -} - -/* build up descriptors in shared RAM */ - -static void InitDscrs(struct net_device *dev) -{ - skmca_priv *priv = netdev_priv(dev); - u32 bufaddr; - - /* Set up Tx descriptors. The board has only 16K RAM so bits 16..23 - are always 0. */ - - bufaddr = RAM_DATABASE; - { - LANCE_TxDescr descr; - int z; - - for (z = 0; z < TXCOUNT; z++) { - descr.LowAddr = bufaddr; - descr.Flags = 0; - descr.Len = 0xf000; - descr.Status = 0; - memcpy_toio(priv->base + RAM_TXBASE + - (z * sizeof(LANCE_TxDescr)), &descr, - sizeof(LANCE_TxDescr)); - memset_io(priv->base + bufaddr, 0, RAM_BUFSIZE); - bufaddr += RAM_BUFSIZE; - } - } - - /* do the same for the Rx descriptors */ - - { - LANCE_RxDescr descr; - int z; - - for (z = 0; z < RXCOUNT; z++) { - descr.LowAddr = bufaddr; - descr.Flags = RXDSCR_FLAGS_OWN; - descr.MaxLen = -RAM_BUFSIZE; - descr.Len = 0; - memcpy_toio(priv->base + RAM_RXBASE + - (z * sizeof(LANCE_RxDescr)), &descr, - sizeof(LANCE_RxDescr)); - memset_io(priv->base + bufaddr, 0, RAM_BUFSIZE); - bufaddr += RAM_BUFSIZE; - } - } -} - -/* calculate the hash bit position for a given multicast address - taken more or less directly from the AMD datasheet... */ - -static void UpdateCRC(unsigned char *CRC, int bit) -{ - int j; - - /* shift CRC one bit */ - - memmove(CRC + 1, CRC, 32 * sizeof(unsigned char)); - CRC[0] = 0; - - /* if bit XOR controlbit = 1, set CRC = CRC XOR polynomial */ - - if (bit ^ CRC[32]) - for (j = 0; j < 32; j++) - CRC[j] ^= poly[j]; -} - -static unsigned int GetHash(char *address) -{ - unsigned char CRC[33]; - int i, byte, hashcode; - - /* a multicast address has bit 0 in the first byte set */ - - if ((address[0] & 1) == 0) - return -1; - - /* initialize CRC */ - - memset(CRC, 1, sizeof(CRC)); - - /* loop through address bits */ - - for (byte = 0; byte < 6; byte++) - for (i = 0; i < 8; i++) - UpdateCRC(CRC, (address[byte] >> i) & 1); - - /* hashcode is the 6 least significant bits of the CRC */ - - hashcode = 0; - for (i = 0; i < 6; i++) - hashcode = (hashcode << 1) + CRC[i]; - return hashcode; -} - -/* feed ready-built initialization block into LANCE */ - -static void InitLANCE(struct net_device *dev) -{ - skmca_priv *priv = netdev_priv(dev); - - /* build up descriptors. */ - - InitDscrs(dev); - - /* next RX descriptor to be read is the first one. Since the LANCE - will start from the beginning after initialization, we have to - reset out pointers too. */ - - priv->nextrx = 0; - - /* no TX descriptors active */ - - priv->nexttxput = priv->nexttxdone = priv->txbusy = 0; - - /* set up the LANCE bus control register - constant for SKnet boards */ - - SetLANCE(dev, LANCE_CSR3, - CSR3_BSWAP_OFF | CSR3_ALE_LOW | CSR3_BCON_HOLD); - - /* write address of initialization block into LANCE */ - - SetLANCE(dev, LANCE_CSR1, RAM_INITBASE & 0xffff); - SetLANCE(dev, LANCE_CSR2, (RAM_INITBASE >> 16) & 0xff); - - /* we don't get ready until the LANCE has read the init block */ - - netif_stop_queue(dev); - - /* let LANCE read the initialization block. LANCE is ready - when we receive the corresponding interrupt. */ - - SetLANCE(dev, LANCE_CSR0, CSR0_INEA | CSR0_INIT); -} - -/* stop the LANCE so we can reinitialize it */ - -static void StopLANCE(struct net_device *dev) -{ - /* can't take frames any more */ - - netif_stop_queue(dev); - - /* disable interrupts, stop it */ - - SetLANCE(dev, LANCE_CSR0, CSR0_STOP); -} - -/* initialize card and LANCE for proper operation */ - -static void InitBoard(struct net_device *dev) -{ - skmca_priv *priv = netdev_priv(dev); - LANCE_InitBlock block; - - /* Lay out the shared RAM - first we create the init block for the LANCE. - We do not overwrite it later because we need it again when we switch - promiscous mode on/off. */ - - block.Mode = 0; - if (dev->flags & IFF_PROMISC) - block.Mode |= LANCE_INIT_PROM; - memcpy(block.PAdr, dev->dev_addr, 6); - memset(block.LAdrF, 0, sizeof(block.LAdrF)); - block.RdrP = (RAM_RXBASE & 0xffffff) | (LRXCOUNT << 29); - block.TdrP = (RAM_TXBASE & 0xffffff) | (LTXCOUNT << 29); - - memcpy_toio(priv->base + RAM_INITBASE, &block, sizeof(block)); - - /* initialize LANCE. Implicitly sets up other structures in RAM. */ - - InitLANCE(dev); -} - -/* deinitialize card and LANCE */ - -static void DeinitBoard(struct net_device *dev) -{ - /* stop LANCE */ - - StopLANCE(dev); - - /* reset board */ - - ResetBoard(dev); -} - -/* probe for device's irq */ - -static int __init ProbeIRQ(struct net_device *dev) -{ - unsigned long imaskval, njiffies, irq; - u16 csr0val; - - /* enable all interrupts */ - - imaskval = probe_irq_on(); - - /* initialize the board. Wait for interrupt 'Initialization done'. */ - - ResetBoard(dev); - InitBoard(dev); - - njiffies = jiffies + HZ; - do { - csr0val = GetLANCE(dev, LANCE_CSR0); - } - while (((csr0val & CSR0_IDON) == 0) && (jiffies != njiffies)); - - /* turn of interrupts again */ - - irq = probe_irq_off(imaskval); - - /* if we found something, ack the interrupt */ - - if (irq) - SetLANCE(dev, LANCE_CSR0, csr0val | CSR0_IDON); - - /* back to idle state */ - - DeinitBoard(dev); - - return irq; -} - -/* ------------------------------------------------------------------------ - * interrupt handler(s) - * ------------------------------------------------------------------------ */ - -/* LANCE has read initialization block -> start it */ - -static u16 irqstart_handler(struct net_device *dev, u16 oldcsr0) -{ - /* now we're ready to transmit */ - - netif_wake_queue(dev); - - /* reset IDON bit, start LANCE */ - - SetLANCE(dev, LANCE_CSR0, oldcsr0 | CSR0_IDON | CSR0_STRT); - return GetLANCE(dev, LANCE_CSR0); -} - -/* did we lose blocks due to a FIFO overrun ? */ - -static u16 irqmiss_handler(struct net_device *dev, u16 oldcsr0) -{ - skmca_priv *priv = netdev_priv(dev); - - /* update statistics */ - - priv->stat.rx_fifo_errors++; - - /* reset MISS bit */ - - SetLANCE(dev, LANCE_CSR0, oldcsr0 | CSR0_MISS); - return GetLANCE(dev, LANCE_CSR0); -} - -/* receive interrupt */ - -static u16 irqrx_handler(struct net_device *dev, u16 oldcsr0) -{ - skmca_priv *priv = netdev_priv(dev); - LANCE_RxDescr descr; - unsigned int descraddr; - - /* run through queue until we reach a descriptor we do not own */ - - descraddr = RAM_RXBASE + (priv->nextrx * sizeof(LANCE_RxDescr)); - while (1) { - /* read descriptor */ - memcpy_fromio(&descr, priv->base + descraddr, - sizeof(LANCE_RxDescr)); - - /* if we reach a descriptor we do not own, we're done */ - if ((descr.Flags & RXDSCR_FLAGS_OWN) != 0) - break; - -#ifdef DEBUG - PrTime(); - printk("Receive packet on descr %d len %d\n", priv->nextrx, - descr.Len); -#endif - - /* erroneous packet ? */ - if ((descr.Flags & RXDSCR_FLAGS_ERR) != 0) { - priv->stat.rx_errors++; - if ((descr.Flags & RXDSCR_FLAGS_CRC) != 0) - priv->stat.rx_crc_errors++; - else if ((descr.Flags & RXDSCR_FLAGS_CRC) != 0) - priv->stat.rx_frame_errors++; - else if ((descr.Flags & RXDSCR_FLAGS_OFLO) != 0) - priv->stat.rx_fifo_errors++; - } - - /* good packet ? */ - else { - struct sk_buff *skb; - - skb = dev_alloc_skb(descr.Len + 2); - if (skb == NULL) - priv->stat.rx_dropped++; - else { - memcpy_fromio(skb_put(skb, descr.Len), - priv->base + - descr.LowAddr, descr.Len); - skb->dev = dev; - skb->protocol = eth_type_trans(skb, dev); - skb->ip_summed = CHECKSUM_NONE; - priv->stat.rx_packets++; - priv->stat.rx_bytes += descr.Len; - netif_rx(skb); - dev->last_rx = jiffies; - } - } - - /* give descriptor back to LANCE */ - descr.Len = 0; - descr.Flags |= RXDSCR_FLAGS_OWN; - - /* update descriptor in shared RAM */ - memcpy_toio(priv->base + descraddr, &descr, - sizeof(LANCE_RxDescr)); - - /* go to next descriptor */ - priv->nextrx++; - descraddr += sizeof(LANCE_RxDescr); - if (priv->nextrx >= RXCOUNT) { - priv->nextrx = 0; - descraddr = RAM_RXBASE; - } - } - - /* reset RINT bit */ - - SetLANCE(dev, LANCE_CSR0, oldcsr0 | CSR0_RINT); - return GetLANCE(dev, LANCE_CSR0); -} - -/* transmit interrupt */ - -static u16 irqtx_handler(struct net_device *dev, u16 oldcsr0) -{ - skmca_priv *priv = netdev_priv(dev); - LANCE_TxDescr descr; - unsigned int descraddr; - - /* check descriptors at most until no busy one is left */ - - descraddr = - RAM_TXBASE + (priv->nexttxdone * sizeof(LANCE_TxDescr)); - while (priv->txbusy > 0) { - /* read descriptor */ - memcpy_fromio(&descr, priv->base + descraddr, - sizeof(LANCE_TxDescr)); - - /* if the LANCE still owns this one, we've worked out all sent packets */ - if ((descr.Flags & TXDSCR_FLAGS_OWN) != 0) - break; - -#ifdef DEBUG - PrTime(); - printk("Send packet done on descr %d\n", priv->nexttxdone); -#endif - - /* update statistics */ - if ((descr.Flags & TXDSCR_FLAGS_ERR) == 0) { - priv->stat.tx_packets++; - priv->stat.tx_bytes++; - } else { - priv->stat.tx_errors++; - if ((descr.Status & TXDSCR_STATUS_UFLO) != 0) { - priv->stat.tx_fifo_errors++; - InitLANCE(dev); - } - else - if ((descr.Status & TXDSCR_STATUS_LCOL) != - 0) priv->stat.tx_window_errors++; - else if ((descr.Status & TXDSCR_STATUS_LCAR) != 0) - priv->stat.tx_carrier_errors++; - else if ((descr.Status & TXDSCR_STATUS_RTRY) != 0) - priv->stat.tx_aborted_errors++; - } - - /* go to next descriptor */ - priv->nexttxdone++; - descraddr += sizeof(LANCE_TxDescr); - if (priv->nexttxdone >= TXCOUNT) { - priv->nexttxdone = 0; - descraddr = RAM_TXBASE; - } - priv->txbusy--; - } - - /* reset TX interrupt bit */ - - SetLANCE(dev, LANCE_CSR0, oldcsr0 | CSR0_TINT); - oldcsr0 = GetLANCE(dev, LANCE_CSR0); - - /* at least one descriptor is freed. Therefore we can accept - a new one */ - /* inform upper layers we're in business again */ - - netif_wake_queue(dev); - - return oldcsr0; -} - -/* general interrupt entry */ - -static irqreturn_t irq_handler(int irq, void *device) -{ - struct net_device *dev = (struct net_device *) device; - u16 csr0val; - - /* read CSR0 to get interrupt cause */ - - csr0val = GetLANCE(dev, LANCE_CSR0); - - /* in case we're not meant... */ - - if ((csr0val & CSR0_INTR) == 0) - return IRQ_NONE; - -#if 0 - set_bit(LINK_STATE_RXSEM, &dev->state); -#endif - - /* loop through the interrupt bits until everything is clear */ - - do { - if ((csr0val & CSR0_IDON) != 0) - csr0val = irqstart_handler(dev, csr0val); - if ((csr0val & CSR0_RINT) != 0) - csr0val = irqrx_handler(dev, csr0val); - if ((csr0val & CSR0_MISS) != 0) - csr0val = irqmiss_handler(dev, csr0val); - if ((csr0val & CSR0_TINT) != 0) - csr0val = irqtx_handler(dev, csr0val); - if ((csr0val & CSR0_MERR) != 0) { - SetLANCE(dev, LANCE_CSR0, csr0val | CSR0_MERR); - csr0val = GetLANCE(dev, LANCE_CSR0); - } - if ((csr0val & CSR0_BABL) != 0) { - SetLANCE(dev, LANCE_CSR0, csr0val | CSR0_BABL); - csr0val = GetLANCE(dev, LANCE_CSR0); - } - } - while ((csr0val & CSR0_INTR) != 0); - -#if 0 - clear_bit(LINK_STATE_RXSEM, &dev->state); -#endif - return IRQ_HANDLED; -} - -/* ------------------------------------------------------------------------ - * driver methods - * ------------------------------------------------------------------------ */ - -/* MCA info */ - -static int skmca_getinfo(char *buf, int slot, void *d) -{ - int len = 0, i; - struct net_device *dev = (struct net_device *) d; - skmca_priv *priv; - - /* can't say anything about an uninitialized device... */ - - if (dev == NULL) - return len; - priv = netdev_priv(dev); - - /* print info */ - - len += sprintf(buf + len, "IRQ: %d\n", priv->realirq); - len += sprintf(buf + len, "Memory: %#lx-%#lx\n", dev->mem_start, - dev->mem_end - 1); - len += - sprintf(buf + len, "Transceiver: %s\n", - MediaNames[priv->medium]); - len += sprintf(buf + len, "Device: %s\n", dev->name); - len += sprintf(buf + len, "MAC address:"); - for (i = 0; i < 6; i++) - len += sprintf(buf + len, " %02x", dev->dev_addr[i]); - buf[len++] = '\n'; - buf[len] = 0; - - return len; -} - -/* open driver. Means also initialization and start of LANCE */ - -static int skmca_open(struct net_device *dev) -{ - int result; - skmca_priv *priv = netdev_priv(dev); - - /* register resources - only necessary for IRQ */ - result = - request_irq(priv->realirq, irq_handler, - IRQF_SHARED | IRQF_SAMPLE_RANDOM, "sk_mca", dev); - if (result != 0) { - printk("%s: failed to register irq %d\n", dev->name, - dev->irq); - return result; - } - dev->irq = priv->realirq; - - /* set up the card and LANCE */ - - InitBoard(dev); - - /* set up flags */ - - netif_start_queue(dev); - - return 0; -} - -/* close driver. Shut down board and free allocated resources */ - -static int skmca_close(struct net_device *dev) -{ - /* turn off board */ - DeinitBoard(dev); - - /* release resources */ - if (dev->irq != 0) - free_irq(dev->irq, dev); - dev->irq = 0; - - return 0; -} - -/* transmit a block. */ - -static int skmca_tx(struct sk_buff *skb, struct net_device *dev) -{ - skmca_priv *priv = netdev_priv(dev); - LANCE_TxDescr descr; - unsigned int address; - int tmplen, retval = 0; - unsigned long flags; - - /* if we get called with a NULL descriptor, the Ethernet layer thinks - our card is stuck an we should reset it. We'll do this completely: */ - - if (skb == NULL) { - DeinitBoard(dev); - InitBoard(dev); - return 0; /* don't try to free the block here ;-) */ - } - - /* is there space in the Tx queue ? If no, the upper layer gave us a - packet in spite of us not being ready and is really in trouble. - We'll do the dropping for him: */ - if (priv->txbusy >= TXCOUNT) { - priv->stat.tx_dropped++; - retval = -EIO; - goto tx_done; - } - - /* get TX descriptor */ - address = RAM_TXBASE + (priv->nexttxput * sizeof(LANCE_TxDescr)); - memcpy_fromio(&descr, priv->base + address, sizeof(LANCE_TxDescr)); - - /* enter packet length as 2s complement - assure minimum length */ - tmplen = skb->len; - if (tmplen < 60) - tmplen = 60; - descr.Len = 65536 - tmplen; - - /* copy filler into RAM - in case we're filling up... - we're filling a bit more than necessary, but that doesn't harm - since the buffer is far larger... */ - if (tmplen > skb->len) { - char *fill = "NetBSD is a nice OS too! "; - unsigned int destoffs = 0, l = strlen(fill); - - while (destoffs < tmplen) { - memcpy_toio(priv->base + descr.LowAddr + - destoffs, fill, l); - destoffs += l; - } - } - - /* do the real data copying */ - memcpy_toio(priv->base + descr.LowAddr, skb->data, skb->len); - - /* hand descriptor over to LANCE - this is the first and last chunk */ - descr.Flags = - TXDSCR_FLAGS_OWN | TXDSCR_FLAGS_STP | TXDSCR_FLAGS_ENP; - -#ifdef DEBUG - PrTime(); - printk("Send packet on descr %d len %d\n", priv->nexttxput, - skb->len); -#endif - - /* one more descriptor busy */ - - spin_lock_irqsave(&priv->lock, flags); - - priv->nexttxput++; - if (priv->nexttxput >= TXCOUNT) - priv->nexttxput = 0; - priv->txbusy++; - - /* are we saturated ? */ - - if (priv->txbusy >= TXCOUNT) - netif_stop_queue(dev); - - /* write descriptor back to RAM */ - memcpy_toio(priv->base + address, &descr, sizeof(LANCE_TxDescr)); - - /* if no descriptors were active, give the LANCE a hint to read it - immediately */ - - if (priv->txbusy == 0) - SetLANCE(dev, LANCE_CSR0, CSR0_INEA | CSR0_TDMD); - - spin_unlock_irqrestore(&priv->lock, flags); - - tx_done: - - dev_kfree_skb(skb); - - return retval; -} - -/* return pointer to Ethernet statistics */ - -static struct net_device_stats *skmca_stats(struct net_device *dev) -{ - skmca_priv *priv = netdev_priv(dev); - - return &(priv->stat); -} - -/* switch receiver mode. We use the LANCE's multicast filter to prefilter - multicast addresses. */ - -static void skmca_set_multicast_list(struct net_device *dev) -{ - skmca_priv *priv = netdev_priv(dev); - LANCE_InitBlock block; - - /* first stop the LANCE... */ - StopLANCE(dev); - - /* ...then modify the initialization block... */ - memcpy_fromio(&block, priv->base + RAM_INITBASE, sizeof(block)); - if (dev->flags & IFF_PROMISC) - block.Mode |= LANCE_INIT_PROM; - else - block.Mode &= ~LANCE_INIT_PROM; - - if (dev->flags & IFF_ALLMULTI) { /* get all multicasts */ - memset(block.LAdrF, 0xff, sizeof(block.LAdrF)); - } else { /* get selected/no multicasts */ - - struct dev_mc_list *mptr; - int code; - - memset(block.LAdrF, 0, sizeof(block.LAdrF)); - for (mptr = dev->mc_list; mptr != NULL; mptr = mptr->next) { - code = GetHash(mptr->dmi_addr); - block.LAdrF[(code >> 3) & 7] |= 1 << (code & 7); - } - } - - memcpy_toio(priv->base + RAM_INITBASE, &block, sizeof(block)); - - /* ...then reinit LANCE with the correct flags */ - InitLANCE(dev); -} - -/* ------------------------------------------------------------------------ - * hardware check - * ------------------------------------------------------------------------ */ - -static int startslot; /* counts through slots when probing multiple devices */ - -static void cleanup_card(struct net_device *dev) -{ - skmca_priv *priv = netdev_priv(dev); - DeinitBoard(dev); - if (dev->irq != 0) - free_irq(dev->irq, dev); - iounmap(priv->base); - mca_mark_as_unused(priv->slot); - mca_set_adapter_procfn(priv->slot, NULL, NULL); -} - -struct net_device * __init skmca_probe(int unit) -{ - struct net_device *dev; - int force_detect = 0; - int junior, slot, i; - int base = 0, irq = 0; - skmca_priv *priv; - skmca_medium medium; - int err; - - /* can't work without an MCA bus ;-) */ - - if (MCA_bus == 0) - return ERR_PTR(-ENODEV); - - dev = alloc_etherdev(sizeof(skmca_priv)); - if (!dev) - return ERR_PTR(-ENOMEM); - - if (unit >= 0) { - sprintf(dev->name, "eth%d", unit); - netdev_boot_setup_check(dev); - } - - SET_MODULE_OWNER(dev); - - /* start address of 1 --> forced detection */ - - if (dev->mem_start == 1) - force_detect = 1; - - /* search through slots */ - - base = dev->mem_start; - irq = dev->base_addr; - for (slot = startslot; (slot = dofind(&junior, slot)) != -1; slot++) { - /* deduce card addresses */ - - getaddrs(slot, junior, &base, &irq, &medium); - - /* slot already in use ? */ - - if (mca_is_adapter_used(slot)) - continue; - - /* were we looking for something different ? */ - - if (dev->irq && dev->irq != irq) - continue; - if (dev->mem_start && dev->mem_start != base) - continue; - - /* found something that matches */ - - break; - } - - /* nothing found ? */ - - if (slot == -1) { - free_netdev(dev); - return (base || irq) ? ERR_PTR(-ENXIO) : ERR_PTR(-ENODEV); - } - - /* make procfs entries */ - - if (junior) - mca_set_adapter_name(slot, - "SKNET junior MC2 Ethernet Adapter"); - else - mca_set_adapter_name(slot, "SKNET MC2+ Ethernet Adapter"); - mca_set_adapter_procfn(slot, (MCA_ProcFn) skmca_getinfo, dev); - - mca_mark_as_used(slot); - - /* announce success */ - printk("%s: SKNet %s adapter found in slot %d\n", dev->name, - junior ? "Junior MC2" : "MC2+", slot + 1); - - priv = netdev_priv(dev); - priv->base = ioremap(base, 0x4000); - if (!priv->base) { - mca_set_adapter_procfn(slot, NULL, NULL); - mca_mark_as_unused(slot); - free_netdev(dev); - return ERR_PTR(-ENOMEM); - } - - priv->slot = slot; - priv->macbase = priv->base + 0x3fc0; - priv->ioregaddr = priv->base + 0x3ff0; - priv->ctrladdr = priv->base + 0x3ff2; - priv->cmdaddr = priv->base + 0x3ff3; - priv->medium = medium; - memset(&priv->stat, 0, sizeof(struct net_device_stats)); - spin_lock_init(&priv->lock); - - /* set base + irq for this device (irq not allocated so far) */ - dev->irq = 0; - dev->mem_start = base; - dev->mem_end = base + 0x4000; - - /* autoprobe ? */ - if (irq < 0) { - int nirq; - - printk - ("%s: ambigous POS bit combination, must probe for IRQ...\n", - dev->name); - nirq = ProbeIRQ(dev); - if (nirq <= 0) - printk("%s: IRQ probe failed, assuming IRQ %d", - dev->name, priv->realirq = -irq); - else - priv->realirq = nirq; - } else - priv->realirq = irq; - - /* set methods */ - dev->open = skmca_open; - dev->stop = skmca_close; - dev->hard_start_xmit = skmca_tx; - dev->do_ioctl = NULL; - dev->get_stats = skmca_stats; - dev->set_multicast_list = skmca_set_multicast_list; - dev->flags |= IFF_MULTICAST; - - /* copy out MAC address */ - for (i = 0; i < 6; i++) - dev->dev_addr[i] = readb(priv->macbase + (i << 1)); - - /* print config */ - printk("%s: IRQ %d, memory %#lx-%#lx, " - "MAC address %02x:%02x:%02x:%02x:%02x:%02x.\n", - dev->name, priv->realirq, dev->mem_start, dev->mem_end - 1, - dev->dev_addr[0], dev->dev_addr[1], dev->dev_addr[2], - dev->dev_addr[3], dev->dev_addr[4], dev->dev_addr[5]); - printk("%s: %s medium\n", dev->name, MediaNames[priv->medium]); - - /* reset board */ - - ResetBoard(dev); - - startslot = slot + 1; - - err = register_netdev(dev); - if (err) { - cleanup_card(dev); - free_netdev(dev); - dev = ERR_PTR(err); - } - return dev; -} - -/* ------------------------------------------------------------------------ - * modularization support - * ------------------------------------------------------------------------ */ - -#ifdef MODULE -MODULE_LICENSE("GPL"); - -#define DEVMAX 5 - -static struct net_device *moddevs[DEVMAX]; - -int init_module(void) -{ - int z; - - startslot = 0; - for (z = 0; z < DEVMAX; z++) { - struct net_device *dev = skmca_probe(-1); - if (IS_ERR(dev)) - break; - moddevs[z] = dev; - } - if (!z) - return -EIO; - return 0; -} - -void cleanup_module(void) -{ - int z; - - for (z = 0; z < DEVMAX; z++) { - struct net_device *dev = moddevs[z]; - if (dev) { - unregister_netdev(dev); - cleanup_card(dev); - free_netdev(dev); - } - } -} -#endif /* MODULE */ diff --git a/drivers/net/sk_mca.h b/drivers/net/sk_mca.h deleted file mode 100644 index 0dae056..0000000 --- a/drivers/net/sk_mca.h +++ /dev/null @@ -1,170 +0,0 @@ -#ifndef _SK_MCA_INCLUDE_ -#define _SK_MCA_INCLUDE_ - -#ifdef _SK_MCA_DRIVER_ - -/* Adapter ID's */ -#define SKNET_MCA_ID 0x6afd -#define SKNET_JUNIOR_MCA_ID 0x6be9 - -/* media enumeration - defined in a way that it fits onto the MC2+'s - POS registers... */ - -typedef enum { Media_10Base2, Media_10BaseT, - Media_10Base5, Media_Unknown, Media_Count -} skmca_medium; - -/* private structure */ -typedef struct { - unsigned int slot; /* MCA-Slot-# */ - void __iomem *base; - void __iomem *macbase; /* base address of MAC address PROM */ - void __iomem *ioregaddr;/* address of I/O-register (Lo) */ - void __iomem *ctrladdr; /* address of control/stat register */ - void __iomem *cmdaddr; /* address of I/O-command register */ - int nextrx; /* index of next RX descriptor to - be read */ - int nexttxput; /* index of next free TX descriptor */ - int nexttxdone; /* index of next TX descriptor to - be finished */ - int txbusy; /* # of busy TX descriptors */ - struct net_device_stats stat; /* packet statistics */ - int realirq; /* memorizes actual IRQ, even when - currently not allocated */ - skmca_medium medium; /* physical cannector */ - spinlock_t lock; -} skmca_priv; - -/* card registers: control/status register bits */ - -#define CTRL_ADR_DATA 0 /* Bit 0 = 0 ->access data register */ -#define CTRL_ADR_RAP 1 /* Bit 0 = 1 ->access RAP register */ -#define CTRL_RW_WRITE 0 /* Bit 1 = 0 ->write register */ -#define CTRL_RW_READ 2 /* Bit 1 = 1 ->read register */ -#define CTRL_RESET_ON 0 /* Bit 3 = 0 ->reset board */ -#define CTRL_RESET_OFF 8 /* Bit 3 = 1 ->no reset of board */ - -#define STAT_ADR_DATA 0 /* Bit 0 of ctrl register read back */ -#define STAT_ADR_RAP 1 -#define STAT_RW_WRITE 0 /* Bit 1 of ctrl register read back */ -#define STAT_RW_READ 2 -#define STAT_RESET_ON 0 /* Bit 3 of ctrl register read back */ -#define STAT_RESET_OFF 8 -#define STAT_IRQ_ACT 0 /* interrupt pending */ -#define STAT_IRQ_NOACT 16 /* no interrupt pending */ -#define STAT_IO_NOBUSY 0 /* no transfer busy */ -#define STAT_IO_BUSY 32 /* transfer busy */ - -/* I/O command register bits */ - -#define IOCMD_GO 128 /* Bit 7 = 1 -> start register xfer */ - -/* LANCE registers */ - -#define LANCE_CSR0 0 /* Status/Control */ - -#define CSR0_ERR 0x8000 /* general error flag */ -#define CSR0_BABL 0x4000 /* transmitter timeout */ -#define CSR0_CERR 0x2000 /* collision error */ -#define CSR0_MISS 0x1000 /* lost Rx block */ -#define CSR0_MERR 0x0800 /* memory access error */ -#define CSR0_RINT 0x0400 /* receiver interrupt */ -#define CSR0_TINT 0x0200 /* transmitter interrupt */ -#define CSR0_IDON 0x0100 /* initialization done */ -#define CSR0_INTR 0x0080 /* general interrupt flag */ -#define CSR0_INEA 0x0040 /* interrupt enable */ -#define CSR0_RXON 0x0020 /* receiver enabled */ -#define CSR0_TXON 0x0010 /* transmitter enabled */ -#define CSR0_TDMD 0x0008 /* force transmission now */ -#define CSR0_STOP 0x0004 /* stop LANCE */ -#define CSR0_STRT 0x0002 /* start LANCE */ -#define CSR0_INIT 0x0001 /* read initialization block */ - -#define LANCE_CSR1 1 /* addr bit 0..15 of initialization */ -#define LANCE_CSR2 2 /* 16..23 block */ - -#define LANCE_CSR3 3 /* Bus control */ -#define CSR3_BCON_HOLD 0 /* Bit 0 = 0 -> BM1,BM0,HOLD */ -#define CSR3_BCON_BUSRQ 1 /* Bit 0 = 1 -> BUSAK0,BYTE,BUSRQ */ -#define CSR3_ALE_HIGH 0 /* Bit 1 = 0 -> ALE asserted high */ -#define CSR3_ALE_LOW 2 /* Bit 1 = 1 -> ALE asserted low */ -#define CSR3_BSWAP_OFF 0 /* Bit 2 = 0 -> no byte swap */ -#define CSR3_BSWAP_ON 4 /* Bit 2 = 1 -> byte swap */ - -/* LANCE structures */ - -typedef struct { /* LANCE initialization block */ - u16 Mode; /* mode flags */ - u8 PAdr[6]; /* MAC address */ - u8 LAdrF[8]; /* Multicast filter */ - u32 RdrP; /* Receive descriptor */ - u32 TdrP; /* Transmit descriptor */ -} LANCE_InitBlock; - -/* Mode flags init block */ - -#define LANCE_INIT_PROM 0x8000 /* enable promiscous mode */ -#define LANCE_INIT_INTL 0x0040 /* internal loopback */ -#define LANCE_INIT_DRTY 0x0020 /* disable retry */ -#define LANCE_INIT_COLL 0x0010 /* force collision */ -#define LANCE_INIT_DTCR 0x0008 /* disable transmit CRC */ -#define LANCE_INIT_LOOP 0x0004 /* loopback */ -#define LANCE_INIT_DTX 0x0002 /* disable transmitter */ -#define LANCE_INIT_DRX 0x0001 /* disable receiver */ - -typedef struct { /* LANCE Tx descriptor */ - u16 LowAddr; /* bit 0..15 of address */ - u16 Flags; /* bit 16..23 of address + Flags */ - u16 Len; /* 2s complement of packet length */ - u16 Status; /* Result of transmission */ -} LANCE_TxDescr; - -#define TXDSCR_FLAGS_OWN 0x8000 /* LANCE owns descriptor */ -#define TXDSCR_FLAGS_ERR 0x4000 /* summary error flag */ -#define TXDSCR_FLAGS_MORE 0x1000 /* more than one retry needed? */ -#define TXDSCR_FLAGS_ONE 0x0800 /* one retry? */ -#define TXDSCR_FLAGS_DEF 0x0400 /* transmission deferred? */ -#define TXDSCR_FLAGS_STP 0x0200 /* first packet in chain? */ -#define TXDSCR_FLAGS_ENP 0x0100 /* last packet in chain? */ - -#define TXDSCR_STATUS_BUFF 0x8000 /* buffer error? */ -#define TXDSCR_STATUS_UFLO 0x4000 /* silo underflow during transmit? */ -#define TXDSCR_STATUS_LCOL 0x1000 /* late collision? */ -#define TXDSCR_STATUS_LCAR 0x0800 /* loss of carrier? */ -#define TXDSCR_STATUS_RTRY 0x0400 /* retry error? */ - -typedef struct { /* LANCE Rx descriptor */ - u16 LowAddr; /* bit 0..15 of address */ - u16 Flags; /* bit 16..23 of address + Flags */ - u16 MaxLen; /* 2s complement of buffer length */ - u16 Len; /* packet length */ -} LANCE_RxDescr; - -#define RXDSCR_FLAGS_OWN 0x8000 /* LANCE owns descriptor */ -#define RXDSCR_FLAGS_ERR 0x4000 /* summary error flag */ -#define RXDSCR_FLAGS_FRAM 0x2000 /* framing error flag */ -#define RXDSCR_FLAGS_OFLO 0x1000 /* FIFO overflow? */ -#define RXDSCR_FLAGS_CRC 0x0800 /* CRC error? */ -#define RXDSCR_FLAGS_BUFF 0x0400 /* buffer error? */ -#define RXDSCR_FLAGS_STP 0x0200 /* first packet in chain? */ -#define RXDCSR_FLAGS_ENP 0x0100 /* last packet in chain? */ - -/* RAM layout */ - -#define TXCOUNT 4 /* length of TX descriptor queue */ -#define LTXCOUNT 2 /* log2 of it */ -#define RXCOUNT 4 /* length of RX descriptor queue */ -#define LRXCOUNT 2 /* log2 of it */ - -#define RAM_INITBASE 0 /* LANCE init block */ -#define RAM_TXBASE 24 /* Start of TX descriptor queue */ -#define RAM_RXBASE \ -(RAM_TXBASE + (TXCOUNT * 8)) /* Start of RX descriptor queue */ -#define RAM_DATABASE \ -(RAM_RXBASE + (RXCOUNT * 8)) /* Start of data area for frames */ -#define RAM_BUFSIZE 1580 /* max. frame size - should never be - reached */ - -#endif /* _SK_MCA_DRIVER_ */ - -#endif /* _SK_MCA_INCLUDE_ */ diff --git a/drivers/net/skfp/can.c b/drivers/net/skfp/can.c deleted file mode 100644 index 8a49abc..0000000 --- a/drivers/net/skfp/can.c +++ /dev/null @@ -1,83 +0,0 @@ -/****************************************************************************** - * - * (C)Copyright 1998,1999 SysKonnect, - * a business unit of Schneider & Koch & Co. Datensysteme GmbH. - * - * See the file "skfddi.c" for further information. - * - * 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. - * - * The information in this file is provided "AS IS" without warranty. - * - ******************************************************************************/ - -#ifndef lint -static const char xID_sccs[] = "@(#)can.c 1.5 97/04/07 (C) SK " ; -#endif - -/* - * canonical bit order - */ -const u_char canonical[256] = { - 0x00,0x80,0x40,0xc0,0x20,0xa0,0x60,0xe0, - 0x10,0x90,0x50,0xd0,0x30,0xb0,0x70,0xf0, - 0x08,0x88,0x48,0xc8,0x28,0xa8,0x68,0xe8, - 0x18,0x98,0x58,0xd8,0x38,0xb8,0x78,0xf8, - 0x04,0x84,0x44,0xc4,0x24,0xa4,0x64,0xe4, - 0x14,0x94,0x54,0xd4,0x34,0xb4,0x74,0xf4, - 0x0c,0x8c,0x4c,0xcc,0x2c,0xac,0x6c,0xec, - 0x1c,0x9c,0x5c,0xdc,0x3c,0xbc,0x7c,0xfc, - 0x02,0x82,0x42,0xc2,0x22,0xa2,0x62,0xe2, - 0x12,0x92,0x52,0xd2,0x32,0xb2,0x72,0xf2, - 0x0a,0x8a,0x4a,0xca,0x2a,0xaa,0x6a,0xea, - 0x1a,0x9a,0x5a,0xda,0x3a,0xba,0x7a,0xfa, - 0x06,0x86,0x46,0xc6,0x26,0xa6,0x66,0xe6, - 0x16,0x96,0x56,0xd6,0x36,0xb6,0x76,0xf6, - 0x0e,0x8e,0x4e,0xce,0x2e,0xae,0x6e,0xee, - 0x1e,0x9e,0x5e,0xde,0x3e,0xbe,0x7e,0xfe, - 0x01,0x81,0x41,0xc1,0x21,0xa1,0x61,0xe1, - 0x11,0x91,0x51,0xd1,0x31,0xb1,0x71,0xf1, - 0x09,0x89,0x49,0xc9,0x29,0xa9,0x69,0xe9, - 0x19,0x99,0x59,0xd9,0x39,0xb9,0x79,0xf9, - 0x05,0x85,0x45,0xc5,0x25,0xa5,0x65,0xe5, - 0x15,0x95,0x55,0xd5,0x35,0xb5,0x75,0xf5, - 0x0d,0x8d,0x4d,0xcd,0x2d,0xad,0x6d,0xed, - 0x1d,0x9d,0x5d,0xdd,0x3d,0xbd,0x7d,0xfd, - 0x03,0x83,0x43,0xc3,0x23,0xa3,0x63,0xe3, - 0x13,0x93,0x53,0xd3,0x33,0xb3,0x73,0xf3, - 0x0b,0x8b,0x4b,0xcb,0x2b,0xab,0x6b,0xeb, - 0x1b,0x9b,0x5b,0xdb,0x3b,0xbb,0x7b,0xfb, - 0x07,0x87,0x47,0xc7,0x27,0xa7,0x67,0xe7, - 0x17,0x97,0x57,0xd7,0x37,0xb7,0x77,0xf7, - 0x0f,0x8f,0x4f,0xcf,0x2f,0xaf,0x6f,0xef, - 0x1f,0x9f,0x5f,0xdf,0x3f,0xbf,0x7f,0xff -} ; - -#ifdef MAKE_TABLE -int byte_reverse(x) -int x ; -{ - int y = 0 ; - - if (x & 0x01) - y |= 0x80 ; - if (x & 0x02) - y |= 0x40 ; - if (x & 0x04) - y |= 0x20 ; - if (x & 0x08) - y |= 0x10 ; - if (x & 0x10) - y |= 0x08 ; - if (x & 0x20) - y |= 0x04 ; - if (x & 0x40) - y |= 0x02 ; - if (x & 0x80) - y |= 0x01 ; - return(y) ; -} -#endif diff --git a/drivers/net/skfp/drvfbi.c b/drivers/net/skfp/drvfbi.c index 5b47583..4fe624b 100644 --- a/drivers/net/skfp/drvfbi.c +++ b/drivers/net/skfp/drvfbi.c @@ -23,6 +23,7 @@ #include "h/fddi.h" #include "h/smc.h" #include "h/supern_2.h" #include "h/skfbiinc.h" +#include #ifndef lint static const char ID_sccs[] = "@(#)drvfbi.c 1.63 99/02/11 (C) SK " ; @@ -445,16 +446,14 @@ void read_address(struct s_smc *smc, u_c char PmdType ; int i ; - extern const u_char canonical[256] ; - #if (defined(ISA) || defined(MCA)) for (i = 0; i < 4 ;i++) { /* read mac address from board */ smc->hw.fddi_phys_addr.a[i] = - canonical[(inpw(PR_A(i+SA_MAC))&0xff)] ; + bitrev8(inpw(PR_A(i+SA_MAC))); } for (i = 4; i < 6; i++) { smc->hw.fddi_phys_addr.a[i] = - canonical[(inpw(PR_A(i+SA_MAC+PRA_OFF))&0xff)] ; + bitrev8(inpw(PR_A(i+SA_MAC+PRA_OFF))); } #endif #ifdef EISA @@ -464,17 +463,17 @@ #ifdef EISA */ for (i = 0; i < 4 ;i++) { /* read mac address from board */ smc->hw.fddi_phys_addr.a[i] = - canonical[inp(PR_A(i+SA_MAC))] ; + bitrev8(inp(PR_A(i+SA_MAC))); } for (i = 4; i < 6; i++) { smc->hw.fddi_phys_addr.a[i] = - canonical[inp(PR_A(i+SA_MAC+PRA_OFF))] ; + bitrev8(inp(PR_A(i+SA_MAC+PRA_OFF))); } #endif #ifdef PCI for (i = 0; i < 6; i++) { /* read mac address from board */ smc->hw.fddi_phys_addr.a[i] = - canonical[inp(ADDR(B2_MAC_0+i))] ; + bitrev8(inp(ADDR(B2_MAC_0+i))); } #endif #ifndef PCI @@ -493,7 +492,7 @@ #endif if (mac_addr) { for (i = 0; i < 6 ;i++) { smc->hw.fddi_canon_addr.a[i] = mac_addr[i] ; - smc->hw.fddi_home_addr.a[i] = canonical[mac_addr[i]] ; + smc->hw.fddi_home_addr.a[i] = bitrev8(mac_addr[i]); } return ; } @@ -501,7 +500,7 @@ #endif for (i = 0; i < 6 ;i++) { smc->hw.fddi_canon_addr.a[i] = - canonical[smc->hw.fddi_phys_addr.a[i]] ; + bitrev8(smc->hw.fddi_phys_addr.a[i]); } } @@ -1269,11 +1268,8 @@ void driver_get_bia(struct s_smc *smc, s { int i ; - extern const u_char canonical[256] ; - - for (i = 0 ; i < 6 ; i++) { - bia_addr->a[i] = canonical[smc->hw.fddi_phys_addr.a[i]] ; - } + for (i = 0 ; i < 6 ; i++) + bia_addr->a[i] = bitrev8(smc->hw.fddi_phys_addr.a[i]); } void smt_start_watchdog(struct s_smc *smc) diff --git a/drivers/net/skfp/fplustm.c b/drivers/net/skfp/fplustm.c index 0784f55..a45205d 100644 --- a/drivers/net/skfp/fplustm.c +++ b/drivers/net/skfp/fplustm.c @@ -22,7 +22,7 @@ #include "h/types.h" #include "h/fddi.h" #include "h/smc.h" #include "h/supern_2.h" -#include "can.c" +#include #ifndef lint static const char ID_sccs[] = "@(#)fplustm.c 1.32 99/02/23 (C) SK " ; @@ -1073,7 +1073,7 @@ static struct s_fpmc* mac_get_mc_table(s if (can) { p = own->a ; for (i = 0 ; i < 6 ; i++, p++) - *p = canonical[*p] ; + *p = bitrev8(*p); } slot = NULL; for (i = 0, tb = smc->hw.fp.mc.table ; i < FPMAX_MULTICAST ; i++, tb++){ diff --git a/drivers/net/skfp/smt.c b/drivers/net/skfp/smt.c index 99a776a..fe84780 100644 --- a/drivers/net/skfp/smt.c +++ b/drivers/net/skfp/smt.c @@ -18,6 +18,7 @@ #include "h/types.h" #include "h/fddi.h" #include "h/smc.h" #include "h/smt_p.h" +#include #define KERNEL #include "h/smtstate.h" @@ -26,8 +27,6 @@ #ifndef lint static const char ID_sccs[] = "@(#)smt.c 2.43 98/11/23 (C) SK " ; #endif -extern const u_char canonical[256] ; - /* * FC in SMbuf */ @@ -180,7 +179,7 @@ void smt_agent_init(struct s_smc *smc) driver_get_bia(smc,&smc->mib.fddiSMTStationId.sid_node) ; for (i = 0 ; i < 6 ; i ++) { smc->mib.fddiSMTStationId.sid_node.a[i] = - canonical[smc->mib.fddiSMTStationId.sid_node.a[i]] ; + bitrev8(smc->mib.fddiSMTStationId.sid_node.a[i]); } smc->mib.fddiSMTManufacturerData[0] = smc->mib.fddiSMTStationId.sid_node.a[0] ; @@ -2049,9 +2048,8 @@ static void hwm_conv_can(struct s_smc *s SK_UNUSED(smc) ; - for (i = len; i ; i--, data++) { - *data = canonical[*(u_char *)data] ; - } + for (i = len; i ; i--, data++) + *data = bitrev8(*data); } #endif diff --git a/drivers/net/skge.c b/drivers/net/skge.c index 45283f3..e482e7f 100644 --- a/drivers/net/skge.c +++ b/drivers/net/skge.c @@ -42,7 +42,7 @@ #include #include "skge.h" #define DRV_NAME "skge" -#define DRV_VERSION "1.9" +#define DRV_VERSION "1.10" #define PFX DRV_NAME " " #define DEFAULT_TX_RING_SIZE 128 @@ -132,18 +132,93 @@ static void skge_get_regs(struct net_dev } /* Wake on Lan only supported on Yukon chips with rev 1 or above */ -static int wol_supported(const struct skge_hw *hw) +static u32 wol_supported(const struct skge_hw *hw) { - return !((hw->chip_id == CHIP_ID_GENESIS || - (hw->chip_id == CHIP_ID_YUKON && hw->chip_rev == 0))); + if (hw->chip_id == CHIP_ID_YUKON && hw->chip_rev != 0) + return WAKE_MAGIC | WAKE_PHY; + else + return 0; +} + +static u32 pci_wake_enabled(struct pci_dev *dev) +{ + int pm = pci_find_capability(dev, PCI_CAP_ID_PM); + u16 value; + + /* If device doesn't support PM Capabilities, but request is to disable + * wake events, it's a nop; otherwise fail */ + if (!pm) + return 0; + + pci_read_config_word(dev, pm + PCI_PM_PMC, &value); + + value &= PCI_PM_CAP_PME_MASK; + value >>= ffs(PCI_PM_CAP_PME_MASK) - 1; /* First bit of mask */ + + return value != 0; +} + +static void skge_wol_init(struct skge_port *skge) +{ + struct skge_hw *hw = skge->hw; + int port = skge->port; + enum pause_control save_mode; + u32 ctrl; + + /* Bring hardware out of reset */ + skge_write16(hw, B0_CTST, CS_RST_CLR); + skge_write16(hw, SK_REG(port, GMAC_LINK_CTRL), GMLC_RST_CLR); + + skge_write8(hw, SK_REG(port, GPHY_CTRL), GPC_RST_CLR); + skge_write8(hw, SK_REG(port, GMAC_CTRL), GMC_RST_CLR); + + /* Force to 10/100 skge_reset will re-enable on resume */ + save_mode = skge->flow_control; + skge->flow_control = FLOW_MODE_SYMMETRIC; + + ctrl = skge->advertising; + skge->advertising &= ~(ADVERTISED_1000baseT_Half|ADVERTISED_1000baseT_Full); + + skge_phy_reset(skge); + + skge->flow_control = save_mode; + skge->advertising = ctrl; + + /* Set GMAC to no flow control and auto update for speed/duplex */ + gma_write16(hw, port, GM_GP_CTRL, + GM_GPCR_FC_TX_DIS|GM_GPCR_TX_ENA|GM_GPCR_RX_ENA| + GM_GPCR_DUP_FULL|GM_GPCR_FC_RX_DIS|GM_GPCR_AU_FCT_DIS); + + /* Set WOL address */ + memcpy_toio(hw->regs + WOL_REGS(port, WOL_MAC_ADDR), + skge->netdev->dev_addr, ETH_ALEN); + + /* Turn on appropriate WOL control bits */ + skge_write16(hw, WOL_REGS(port, WOL_CTRL_STAT), WOL_CTL_CLEAR_RESULT); + ctrl = 0; + if (skge->wol & WAKE_PHY) + ctrl |= WOL_CTL_ENA_PME_ON_LINK_CHG|WOL_CTL_ENA_LINK_CHG_UNIT; + else + ctrl |= WOL_CTL_DIS_PME_ON_LINK_CHG|WOL_CTL_DIS_LINK_CHG_UNIT; + + if (skge->wol & WAKE_MAGIC) + ctrl |= WOL_CTL_ENA_PME_ON_MAGIC_PKT|WOL_CTL_ENA_MAGIC_PKT_UNIT; + else + ctrl |= WOL_CTL_DIS_PME_ON_MAGIC_PKT|WOL_CTL_DIS_MAGIC_PKT_UNIT;; + + ctrl |= WOL_CTL_DIS_PME_ON_PATTERN|WOL_CTL_DIS_PATTERN_UNIT; + skge_write16(hw, WOL_REGS(port, WOL_CTRL_STAT), ctrl); + + /* block receiver */ + skge_write8(hw, SK_REG(port, RX_GMF_CTRL_T), GMF_RST_SET); } static void skge_get_wol(struct net_device *dev, struct ethtool_wolinfo *wol) { struct skge_port *skge = netdev_priv(dev); - wol->supported = wol_supported(skge->hw) ? WAKE_MAGIC : 0; - wol->wolopts = skge->wol ? WAKE_MAGIC : 0; + wol->supported = wol_supported(skge->hw); + wol->wolopts = skge->wol; } static int skge_set_wol(struct net_device *dev, struct ethtool_wolinfo *wol) @@ -151,23 +226,12 @@ static int skge_set_wol(struct net_devic struct skge_port *skge = netdev_priv(dev); struct skge_hw *hw = skge->hw; - if (wol->wolopts != WAKE_MAGIC && wol->wolopts != 0) + if (wol->wolopts & wol_supported(hw)) return -EOPNOTSUPP; - if (wol->wolopts == WAKE_MAGIC && !wol_supported(hw)) - return -EOPNOTSUPP; - - skge->wol = wol->wolopts == WAKE_MAGIC; - - if (skge->wol) { - memcpy_toio(hw->regs + WOL_MAC_ADDR, dev->dev_addr, ETH_ALEN); - - skge_write16(hw, WOL_CTRL_STAT, - WOL_CTL_ENA_PME_ON_MAGIC_PKT | - WOL_CTL_ENA_MAGIC_PKT_UNIT); - } else - skge_write16(hw, WOL_CTRL_STAT, WOL_CTL_DEFAULT); - + skge->wol = wol->wolopts; + if (!netif_running(dev)) + skge_wol_init(skge); return 0; } @@ -2373,6 +2437,9 @@ static int skge_up(struct net_device *de size_t rx_size, tx_size; int err; + if (!is_valid_ether_addr(dev->dev_addr)) + return -EINVAL; + if (netif_msg_ifup(skge)) printk(KERN_INFO PFX "%s: enabling interface\n", dev->name); @@ -2392,7 +2459,7 @@ static int skge_up(struct net_device *de BUG_ON(skge->dma & 7); if ((u64)skge->dma >> 32 != ((u64) skge->dma + skge->mem_size) >> 32) { - printk(KERN_ERR PFX "pci_alloc_consistent region crosses 4G boundary\n"); + dev_err(&hw->pdev->dev, "pci_alloc_consistent region crosses 4G boundary\n"); err = -EINVAL; goto free_pci_mem; } @@ -3001,6 +3068,7 @@ static void skge_mac_intr(struct skge_hw /* Handle device specific framing and timeout interrupts */ static void skge_error_irq(struct skge_hw *hw) { + struct pci_dev *pdev = hw->pdev; u32 hwstatus = skge_read32(hw, B0_HWE_ISRC); if (hw->chip_id == CHIP_ID_GENESIS) { @@ -3016,12 +3084,12 @@ static void skge_error_irq(struct skge_h } if (hwstatus & IS_RAM_RD_PAR) { - printk(KERN_ERR PFX "Ram read data parity error\n"); + dev_err(&pdev->dev, "Ram read data parity error\n"); skge_write16(hw, B3_RI_CTRL, RI_CLR_RD_PERR); } if (hwstatus & IS_RAM_WR_PAR) { - printk(KERN_ERR PFX "Ram write data parity error\n"); + dev_err(&pdev->dev, "Ram write data parity error\n"); skge_write16(hw, B3_RI_CTRL, RI_CLR_WR_PERR); } @@ -3032,38 +3100,38 @@ static void skge_error_irq(struct skge_h skge_mac_parity(hw, 1); if (hwstatus & IS_R1_PAR_ERR) { - printk(KERN_ERR PFX "%s: receive queue parity error\n", - hw->dev[0]->name); + dev_err(&pdev->dev, "%s: receive queue parity error\n", + hw->dev[0]->name); skge_write32(hw, B0_R1_CSR, CSR_IRQ_CL_P); } if (hwstatus & IS_R2_PAR_ERR) { - printk(KERN_ERR PFX "%s: receive queue parity error\n", - hw->dev[1]->name); + dev_err(&pdev->dev, "%s: receive queue parity error\n", + hw->dev[1]->name); skge_write32(hw, B0_R2_CSR, CSR_IRQ_CL_P); } if (hwstatus & (IS_IRQ_MST_ERR|IS_IRQ_STAT)) { u16 pci_status, pci_cmd; - pci_read_config_word(hw->pdev, PCI_COMMAND, &pci_cmd); - pci_read_config_word(hw->pdev, PCI_STATUS, &pci_status); + pci_read_config_word(pdev, PCI_COMMAND, &pci_cmd); + pci_read_config_word(pdev, PCI_STATUS, &pci_status); - printk(KERN_ERR PFX "%s: PCI error cmd=%#x status=%#x\n", - pci_name(hw->pdev), pci_cmd, pci_status); + dev_err(&pdev->dev, "PCI error cmd=%#x status=%#x\n", + pci_cmd, pci_status); /* Write the error bits back to clear them. */ pci_status &= PCI_STATUS_ERROR_BITS; skge_write8(hw, B2_TST_CTRL1, TST_CFG_WRITE_ON); - pci_write_config_word(hw->pdev, PCI_COMMAND, + pci_write_config_word(pdev, PCI_COMMAND, pci_cmd | PCI_COMMAND_SERR | PCI_COMMAND_PARITY); - pci_write_config_word(hw->pdev, PCI_STATUS, pci_status); + pci_write_config_word(pdev, PCI_STATUS, pci_status); skge_write8(hw, B2_TST_CTRL1, TST_CFG_WRITE_OFF); /* if error still set then just ignore it */ hwstatus = skge_read32(hw, B0_HWE_ISRC); if (hwstatus & IS_IRQ_STAT) { - printk(KERN_INFO PFX "unable to clear error (so ignoring them)\n"); + dev_warn(&hw->pdev->dev, "unable to clear error (so ignoring them)\n"); hw->intr_mask &= ~IS_HW_ERR; } } @@ -3277,8 +3345,8 @@ static int skge_reset(struct skge_hw *hw hw->phy_addr = PHY_ADDR_BCOM; break; default: - printk(KERN_ERR PFX "%s: unsupported phy type 0x%x\n", - pci_name(hw->pdev), hw->phy_type); + dev_err(&hw->pdev->dev, "unsupported phy type 0x%x\n", + hw->phy_type); return -EOPNOTSUPP; } break; @@ -3293,8 +3361,8 @@ static int skge_reset(struct skge_hw *hw break; default: - printk(KERN_ERR PFX "%s: unsupported chip type 0x%x\n", - pci_name(hw->pdev), hw->chip_id); + dev_err(&hw->pdev->dev, "unsupported chip type 0x%x\n", + hw->chip_id); return -EOPNOTSUPP; } @@ -3334,7 +3402,7 @@ static int skge_reset(struct skge_hw *hw /* avoid boards with stuck Hardware error bits */ if ((skge_read32(hw, B0_ISRC) & IS_HW_ERR) && (skge_read32(hw, B0_HWE_ISRC) & IS_IRQ_SENSOR)) { - printk(KERN_WARNING PFX "stuck hardware sensor bit\n"); + dev_warn(&hw->pdev->dev, "stuck hardware sensor bit\n"); hw->intr_mask &= ~IS_HW_ERR; } @@ -3408,7 +3476,7 @@ static struct net_device *skge_devinit(s struct net_device *dev = alloc_etherdev(sizeof(*skge)); if (!dev) { - printk(KERN_ERR "skge etherdev alloc failed"); + dev_err(&hw->pdev->dev, "etherdev alloc failed\n"); return NULL; } @@ -3452,6 +3520,7 @@ #endif skge->duplex = -1; skge->speed = -1; skge->advertising = skge_supported_modes(hw); + skge->wol = pci_wake_enabled(hw->pdev) ? wol_supported(hw) : 0; hw->dev[port] = dev; @@ -3496,15 +3565,13 @@ static int __devinit skge_probe(struct p err = pci_enable_device(pdev); if (err) { - printk(KERN_ERR PFX "%s cannot enable PCI device\n", - pci_name(pdev)); + dev_err(&pdev->dev, "cannot enable PCI device\n"); goto err_out; } err = pci_request_regions(pdev, DRV_NAME); if (err) { - printk(KERN_ERR PFX "%s cannot obtain PCI resources\n", - pci_name(pdev)); + dev_err(&pdev->dev, "cannot obtain PCI resources\n"); goto err_out_disable_pdev; } @@ -3519,8 +3586,7 @@ static int __devinit skge_probe(struct p } if (err) { - printk(KERN_ERR PFX "%s no usable DMA configuration\n", - pci_name(pdev)); + dev_err(&pdev->dev, "no usable DMA configuration\n"); goto err_out_free_regions; } @@ -3538,8 +3604,7 @@ #endif err = -ENOMEM; hw = kzalloc(sizeof(*hw), GFP_KERNEL); if (!hw) { - printk(KERN_ERR PFX "%s: cannot allocate hardware struct\n", - pci_name(pdev)); + dev_err(&pdev->dev, "cannot allocate hardware struct\n"); goto err_out_free_regions; } @@ -3550,8 +3615,7 @@ #endif hw->regs = ioremap_nocache(pci_resource_start(pdev, 0), 0x4000); if (!hw->regs) { - printk(KERN_ERR PFX "%s: cannot map device registers\n", - pci_name(pdev)); + dev_err(&pdev->dev, "cannot map device registers\n"); goto err_out_free_hw; } @@ -3567,23 +3631,19 @@ #endif if (!dev) goto err_out_led_off; - if (!is_valid_ether_addr(dev->dev_addr)) { - printk(KERN_ERR PFX "%s: bad (zero?) ethernet address in rom\n", - pci_name(pdev)); - err = -EIO; - goto err_out_free_netdev; - } + /* Some motherboards are broken and has zero in ROM. */ + if (!is_valid_ether_addr(dev->dev_addr)) + dev_warn(&pdev->dev, "bad (zero?) ethernet address in rom\n"); err = register_netdev(dev); if (err) { - printk(KERN_ERR PFX "%s: cannot register net device\n", - pci_name(pdev)); + dev_err(&pdev->dev, "cannot register net device\n"); goto err_out_free_netdev; } err = request_irq(pdev->irq, skge_intr, IRQF_SHARED, dev->name, hw); if (err) { - printk(KERN_ERR PFX "%s: cannot assign irq %d\n", + dev_err(&pdev->dev, "%s: cannot assign irq %d\n", dev->name, pdev->irq); goto err_out_unregister; } @@ -3594,7 +3654,7 @@ #endif skge_show_addr(dev1); else { /* Failure to register second port need not be fatal */ - printk(KERN_WARNING PFX "register of second port failed\n"); + dev_warn(&pdev->dev, "register of second port failed\n"); hw->dev[1] = NULL; free_netdev(dev1); } @@ -3659,28 +3719,46 @@ static void __devexit skge_remove(struct } #ifdef CONFIG_PM +static int vaux_avail(struct pci_dev *pdev) +{ + int pm_cap; + + pm_cap = pci_find_capability(pdev, PCI_CAP_ID_PM); + if (pm_cap) { + u16 ctl; + pci_read_config_word(pdev, pm_cap + PCI_PM_PMC, &ctl); + if (ctl & PCI_PM_CAP_AUX_POWER) + return 1; + } + return 0; +} + + static int skge_suspend(struct pci_dev *pdev, pm_message_t state) { struct skge_hw *hw = pci_get_drvdata(pdev); - int i, wol = 0; + int i, err, wol = 0; + + err = pci_save_state(pdev); + if (err) + return err; - pci_save_state(pdev); for (i = 0; i < hw->ports; i++) { struct net_device *dev = hw->dev[i]; + struct skge_port *skge = netdev_priv(dev); - if (netif_running(dev)) { - struct skge_port *skge = netdev_priv(dev); + if (netif_running(dev)) + skge_down(dev); + if (skge->wol) + skge_wol_init(skge); - netif_carrier_off(dev); - if (skge->wol) - netif_stop_queue(dev); - else - skge_down(dev); - wol |= skge->wol; - } - netif_device_detach(dev); + wol |= skge->wol; } + if (wol && vaux_avail(pdev)) + skge_write8(hw, B0_POWER_CTRL, + PC_VAUX_ENA | PC_VCC_ENA | PC_VAUX_ON | PC_VCC_OFF); + skge_write32(hw, B0_IMSK, 0); pci_enable_wake(pdev, pci_choose_state(pdev, state), wol); pci_set_power_state(pdev, pci_choose_state(pdev, state)); @@ -3693,8 +3771,14 @@ static int skge_resume(struct pci_dev *p struct skge_hw *hw = pci_get_drvdata(pdev); int i, err; - pci_set_power_state(pdev, PCI_D0); - pci_restore_state(pdev); + err = pci_set_power_state(pdev, PCI_D0); + if (err) + goto out; + + err = pci_restore_state(pdev); + if (err) + goto out; + pci_enable_wake(pdev, PCI_D0, 0); err = skge_reset(hw); @@ -3704,7 +3788,6 @@ static int skge_resume(struct pci_dev *p for (i = 0; i < hw->ports; i++) { struct net_device *dev = hw->dev[i]; - netif_device_attach(dev); if (netif_running(dev)) { err = skge_up(dev); diff --git a/drivers/net/skge.h b/drivers/net/skge.h index f6223c5..17b1b47 100644 --- a/drivers/net/skge.h +++ b/drivers/net/skge.h @@ -876,11 +876,13 @@ enum { WOL_PATT_CNT_0 = 0x0f38,/* 32 bit WOL Pattern Counter 3..0 */ WOL_PATT_CNT_4 = 0x0f3c,/* 24 bit WOL Pattern Counter 6..4 */ }; +#define WOL_REGS(port, x) (x + (port)*0x80) enum { WOL_PATT_RAM_1 = 0x1000,/* WOL Pattern RAM Link 1 */ WOL_PATT_RAM_2 = 0x1400,/* WOL Pattern RAM Link 2 */ }; +#define WOL_PATT_RAM_BASE(port) (WOL_PATT_RAM_1 + (port)*0x400) enum { BASE_XMAC_1 = 0x2000,/* XMAC 1 registers */ diff --git a/drivers/net/sky2.c b/drivers/net/sky2.c index 822dd0b..f2ab3d5 100644 --- a/drivers/net/sky2.c +++ b/drivers/net/sky2.c @@ -49,7 +49,7 @@ #endif #include "sky2.h" #define DRV_NAME "sky2" -#define DRV_VERSION "1.10" +#define DRV_VERSION "1.12" #define PFX DRV_NAME " " /* @@ -105,6 +105,7 @@ static const struct pci_device_id sky2_i { PCI_DEVICE(PCI_VENDOR_ID_DLINK, 0x4b00) }, /* DGE-560T */ { PCI_DEVICE(PCI_VENDOR_ID_DLINK, 0x4001) }, /* DGE-550SX */ { PCI_DEVICE(PCI_VENDOR_ID_DLINK, 0x4B02) }, /* DGE-560SX */ + { PCI_DEVICE(PCI_VENDOR_ID_DLINK, 0x4B03) }, /* DGE-550T */ { PCI_DEVICE(PCI_VENDOR_ID_MARVELL, 0x4340) }, /* 88E8021 */ { PCI_DEVICE(PCI_VENDOR_ID_MARVELL, 0x4341) }, /* 88E8022 */ { PCI_DEVICE(PCI_VENDOR_ID_MARVELL, 0x4342) }, /* 88E8061 */ @@ -126,6 +127,9 @@ static const struct pci_device_id sky2_i { PCI_DEVICE(PCI_VENDOR_ID_MARVELL, 0x4366) }, /* 88EC036 */ { PCI_DEVICE(PCI_VENDOR_ID_MARVELL, 0x4367) }, /* 88EC032 */ { PCI_DEVICE(PCI_VENDOR_ID_MARVELL, 0x4368) }, /* 88EC034 */ + { PCI_DEVICE(PCI_VENDOR_ID_MARVELL, 0x4369) }, /* 88EC042 */ + { PCI_DEVICE(PCI_VENDOR_ID_MARVELL, 0x436A) }, /* 88E8058 */ + { PCI_DEVICE(PCI_VENDOR_ID_MARVELL, 0x436B) }, /* 88E8071 */ { 0 } }; @@ -140,7 +144,7 @@ static const u32 portirq_msk[] = { Y2_IS static const char *yukon2_name[] = { "XL", /* 0xb3 */ "EC Ultra", /* 0xb4 */ - "UNKNOWN", /* 0xb5 */ + "Extreme", /* 0xb5 */ "EC", /* 0xb6 */ "FE", /* 0xb7 */ }; @@ -192,76 +196,52 @@ static u16 gm_phy_read(struct sky2_hw *h return v; } -static void sky2_set_power_state(struct sky2_hw *hw, pci_power_t state) -{ - u16 power_control; - int vaux; - - pr_debug("sky2_set_power_state %d\n", state); - sky2_write8(hw, B2_TST_CTRL1, TST_CFG_WRITE_ON); - - power_control = sky2_pci_read16(hw, hw->pm_cap + PCI_PM_PMC); - vaux = (sky2_read16(hw, B0_CTST) & Y2_VAUX_AVAIL) && - (power_control & PCI_PM_CAP_PME_D3cold); - - power_control = sky2_pci_read16(hw, hw->pm_cap + PCI_PM_CTRL); - - power_control |= PCI_PM_CTRL_PME_STATUS; - power_control &= ~(PCI_PM_CTRL_STATE_MASK); - switch (state) { - case PCI_D0: - /* switch power to VCC (WA for VAUX problem) */ - sky2_write8(hw, B0_POWER_CTRL, - PC_VAUX_ENA | PC_VCC_ENA | PC_VAUX_OFF | PC_VCC_ON); - - /* disable Core Clock Division, */ - sky2_write32(hw, B2_Y2_CLK_CTRL, Y2_CLK_DIV_DIS); - - if (hw->chip_id == CHIP_ID_YUKON_XL && hw->chip_rev > 1) - /* enable bits are inverted */ - sky2_write8(hw, B2_Y2_CLK_GATE, - Y2_PCI_CLK_LNK1_DIS | Y2_COR_CLK_LNK1_DIS | - Y2_CLK_GAT_LNK1_DIS | Y2_PCI_CLK_LNK2_DIS | - Y2_COR_CLK_LNK2_DIS | Y2_CLK_GAT_LNK2_DIS); - else - sky2_write8(hw, B2_Y2_CLK_GATE, 0); +static void sky2_power_on(struct sky2_hw *hw) +{ + /* switch power to VCC (WA for VAUX problem) */ + sky2_write8(hw, B0_POWER_CTRL, + PC_VAUX_ENA | PC_VCC_ENA | PC_VAUX_OFF | PC_VCC_ON); - if (hw->chip_id == CHIP_ID_YUKON_EC_U) { - u32 reg1; + /* disable Core Clock Division, */ + sky2_write32(hw, B2_Y2_CLK_CTRL, Y2_CLK_DIV_DIS); - sky2_pci_write32(hw, PCI_DEV_REG3, 0); - reg1 = sky2_pci_read32(hw, PCI_DEV_REG4); - reg1 &= P_ASPM_CONTROL_MSK; - sky2_pci_write32(hw, PCI_DEV_REG4, reg1); - sky2_pci_write32(hw, PCI_DEV_REG5, 0); - } + if (hw->chip_id == CHIP_ID_YUKON_XL && hw->chip_rev > 1) + /* enable bits are inverted */ + sky2_write8(hw, B2_Y2_CLK_GATE, + Y2_PCI_CLK_LNK1_DIS | Y2_COR_CLK_LNK1_DIS | + Y2_CLK_GAT_LNK1_DIS | Y2_PCI_CLK_LNK2_DIS | + Y2_COR_CLK_LNK2_DIS | Y2_CLK_GAT_LNK2_DIS); + else + sky2_write8(hw, B2_Y2_CLK_GATE, 0); - break; + if (hw->chip_id == CHIP_ID_YUKON_EC_U || hw->chip_id == CHIP_ID_YUKON_EX) { + u32 reg1; - case PCI_D3hot: - case PCI_D3cold: - if (hw->chip_id == CHIP_ID_YUKON_XL && hw->chip_rev > 1) - sky2_write8(hw, B2_Y2_CLK_GATE, 0); - else - /* enable bits are inverted */ - sky2_write8(hw, B2_Y2_CLK_GATE, - Y2_PCI_CLK_LNK1_DIS | Y2_COR_CLK_LNK1_DIS | - Y2_CLK_GAT_LNK1_DIS | Y2_PCI_CLK_LNK2_DIS | - Y2_COR_CLK_LNK2_DIS | Y2_CLK_GAT_LNK2_DIS); - - /* switch power to VAUX */ - if (vaux && state != PCI_D3cold) - sky2_write8(hw, B0_POWER_CTRL, - (PC_VAUX_ENA | PC_VCC_ENA | - PC_VAUX_ON | PC_VCC_OFF)); - break; - default: - printk(KERN_ERR PFX "Unknown power state %d\n", state); + sky2_pci_write32(hw, PCI_DEV_REG3, 0); + reg1 = sky2_pci_read32(hw, PCI_DEV_REG4); + reg1 &= P_ASPM_CONTROL_MSK; + sky2_pci_write32(hw, PCI_DEV_REG4, reg1); + sky2_pci_write32(hw, PCI_DEV_REG5, 0); } +} - sky2_pci_write16(hw, hw->pm_cap + PCI_PM_CTRL, power_control); - sky2_write8(hw, B2_TST_CTRL1, TST_CFG_WRITE_OFF); +static void sky2_power_aux(struct sky2_hw *hw) +{ + if (hw->chip_id == CHIP_ID_YUKON_XL && hw->chip_rev > 1) + sky2_write8(hw, B2_Y2_CLK_GATE, 0); + else + /* enable bits are inverted */ + sky2_write8(hw, B2_Y2_CLK_GATE, + Y2_PCI_CLK_LNK1_DIS | Y2_COR_CLK_LNK1_DIS | + Y2_CLK_GAT_LNK1_DIS | Y2_PCI_CLK_LNK2_DIS | + Y2_COR_CLK_LNK2_DIS | Y2_CLK_GAT_LNK2_DIS); + + /* switch power to VAUX */ + if (sky2_read16(hw, B0_CTST) & Y2_VAUX_AVAIL) + sky2_write8(hw, B0_POWER_CTRL, + (PC_VAUX_ENA | PC_VCC_ENA | + PC_VAUX_ON | PC_VCC_OFF)); } static void sky2_gmac_reset(struct sky2_hw *hw, unsigned port) @@ -313,8 +293,10 @@ static void sky2_phy_init(struct sky2_hw struct sky2_port *sky2 = netdev_priv(hw->dev[port]); u16 ctrl, ct1000, adv, pg, ledctrl, ledover, reg; - if (sky2->autoneg == AUTONEG_ENABLE && - !(hw->chip_id == CHIP_ID_YUKON_XL || hw->chip_id == CHIP_ID_YUKON_EC_U)) { + if (sky2->autoneg == AUTONEG_ENABLE + && !(hw->chip_id == CHIP_ID_YUKON_XL + || hw->chip_id == CHIP_ID_YUKON_EC_U + || hw->chip_id == CHIP_ID_YUKON_EX)) { u16 ectrl = gm_phy_read(hw, port, PHY_MARV_EXT_CTRL); ectrl &= ~(PHY_M_EC_M_DSC_MSK | PHY_M_EC_S_DSC_MSK | @@ -341,8 +323,10 @@ static void sky2_phy_init(struct sky2_hw /* enable automatic crossover */ ctrl |= PHY_M_PC_MDI_XMODE(PHY_M_PC_ENA_AUTO); - if (sky2->autoneg == AUTONEG_ENABLE && - (hw->chip_id == CHIP_ID_YUKON_XL || hw->chip_id == CHIP_ID_YUKON_EC_U)) { + if (sky2->autoneg == AUTONEG_ENABLE + && (hw->chip_id == CHIP_ID_YUKON_XL + || hw->chip_id == CHIP_ID_YUKON_EC_U + || hw->chip_id == CHIP_ID_YUKON_EX)) { ctrl &= ~PHY_M_PC_DSC_MSK; ctrl |= PHY_M_PC_DSC(2) | PHY_M_PC_DOWN_S_ENA; } @@ -497,7 +481,9 @@ static void sky2_phy_init(struct sky2_hw /* restore page register */ gm_phy_write(hw, port, PHY_MARV_EXT_ADR, pg); break; + case CHIP_ID_YUKON_EC_U: + case CHIP_ID_YUKON_EX: pg = gm_phy_read(hw, port, PHY_MARV_EXT_ADR); /* select page 3 to access LED control register */ @@ -539,7 +525,7 @@ static void sky2_phy_init(struct sky2_hw /* set page register to 0 */ gm_phy_write(hw, port, PHY_MARV_EXT_ADR, pg); - } else { + } else if (hw->chip_id != CHIP_ID_YUKON_EX) { gm_phy_write(hw, port, PHY_MARV_LED_CTRL, ledctrl); if (sky2->autoneg == AUTONEG_DISABLE || sky2->speed == SPEED_100) { @@ -591,6 +577,73 @@ static void sky2_phy_reinit(struct sky2_ spin_unlock_bh(&sky2->phy_lock); } +/* Put device in state to listen for Wake On Lan */ +static void sky2_wol_init(struct sky2_port *sky2) +{ + struct sky2_hw *hw = sky2->hw; + unsigned port = sky2->port; + enum flow_control save_mode; + u16 ctrl; + u32 reg1; + + /* Bring hardware out of reset */ + sky2_write16(hw, B0_CTST, CS_RST_CLR); + sky2_write16(hw, SK_REG(port, GMAC_LINK_CTRL), GMLC_RST_CLR); + + sky2_write8(hw, SK_REG(port, GPHY_CTRL), GPC_RST_CLR); + sky2_write8(hw, SK_REG(port, GMAC_CTRL), GMC_RST_CLR); + + /* Force to 10/100 + * sky2_reset will re-enable on resume + */ + save_mode = sky2->flow_mode; + ctrl = sky2->advertising; + + sky2->advertising &= ~(ADVERTISED_1000baseT_Half|ADVERTISED_1000baseT_Full); + sky2->flow_mode = FC_NONE; + sky2_phy_power(hw, port, 1); + sky2_phy_reinit(sky2); + + sky2->flow_mode = save_mode; + sky2->advertising = ctrl; + + /* Set GMAC to no flow control and auto update for speed/duplex */ + gma_write16(hw, port, GM_GP_CTRL, + GM_GPCR_FC_TX_DIS|GM_GPCR_TX_ENA|GM_GPCR_RX_ENA| + GM_GPCR_DUP_FULL|GM_GPCR_FC_RX_DIS|GM_GPCR_AU_FCT_DIS); + + /* Set WOL address */ + memcpy_toio(hw->regs + WOL_REGS(port, WOL_MAC_ADDR), + sky2->netdev->dev_addr, ETH_ALEN); + + /* Turn on appropriate WOL control bits */ + sky2_write16(hw, WOL_REGS(port, WOL_CTRL_STAT), WOL_CTL_CLEAR_RESULT); + ctrl = 0; + if (sky2->wol & WAKE_PHY) + ctrl |= WOL_CTL_ENA_PME_ON_LINK_CHG|WOL_CTL_ENA_LINK_CHG_UNIT; + else + ctrl |= WOL_CTL_DIS_PME_ON_LINK_CHG|WOL_CTL_DIS_LINK_CHG_UNIT; + + if (sky2->wol & WAKE_MAGIC) + ctrl |= WOL_CTL_ENA_PME_ON_MAGIC_PKT|WOL_CTL_ENA_MAGIC_PKT_UNIT; + else + ctrl |= WOL_CTL_DIS_PME_ON_MAGIC_PKT|WOL_CTL_DIS_MAGIC_PKT_UNIT;; + + ctrl |= WOL_CTL_DIS_PME_ON_PATTERN|WOL_CTL_DIS_PATTERN_UNIT; + sky2_write16(hw, WOL_REGS(port, WOL_CTRL_STAT), ctrl); + + /* Turn on legacy PCI-Express PME mode */ + sky2_write8(hw, B2_TST_CTRL1, TST_CFG_WRITE_ON); + reg1 = sky2_pci_read32(hw, PCI_DEV_REG1); + reg1 |= PCI_Y2_PME_LEGACY; + sky2_pci_write32(hw, PCI_DEV_REG1, reg1); + sky2_write8(hw, B2_TST_CTRL1, TST_CFG_WRITE_OFF); + + /* block receiver */ + sky2_write8(hw, SK_REG(port, RX_GMF_CTRL_T), GMF_RST_SET); + +} + static void sky2_mac_init(struct sky2_hw *hw, unsigned port) { struct sky2_port *sky2 = netdev_priv(hw->dev[port]); @@ -684,7 +737,7 @@ static void sky2_mac_init(struct sky2_hw sky2_write8(hw, SK_REG(port, TX_GMF_CTRL_T), GMF_RST_CLR); sky2_write16(hw, SK_REG(port, TX_GMF_CTRL_T), GMF_OPER_ON); - if (hw->chip_id == CHIP_ID_YUKON_EC_U) { + if (hw->chip_id == CHIP_ID_YUKON_EC_U || hw->chip_id == CHIP_ID_YUKON_EX) { sky2_write8(hw, SK_REG(port, RX_GMF_LP_THR), 768/8); sky2_write8(hw, SK_REG(port, RX_GMF_UP_THR), 1024/8); if (hw->dev[port]->mtu > ETH_DATA_LEN) { @@ -1467,6 +1520,9 @@ static void sky2_tx_complete(struct sky2 if (unlikely(netif_msg_tx_done(sky2))) printk(KERN_DEBUG "%s: tx done %u\n", dev->name, idx); + sky2->net_stats.tx_packets++; + sky2->net_stats.tx_bytes += re->skb->len; + dev_kfree_skb_any(re->skb); } @@ -1641,7 +1697,9 @@ static void sky2_link_up(struct sky2_por sky2_write8(hw, SK_REG(port, LNK_LED_REG), LINKLED_ON | LINKLED_BLINK_OFF | LINKLED_LINKSYNC_OFF); - if (hw->chip_id == CHIP_ID_YUKON_XL || hw->chip_id == CHIP_ID_YUKON_EC_U) { + if (hw->chip_id == CHIP_ID_YUKON_XL + || hw->chip_id == CHIP_ID_YUKON_EC_U + || hw->chip_id == CHIP_ID_YUKON_EX) { u16 pg = gm_phy_read(hw, port, PHY_MARV_EXT_ADR); u16 led = PHY_M_LEDC_LOS_CTRL(1); /* link active */ @@ -1734,14 +1792,16 @@ static int sky2_autoneg_done(struct sky2 sky2->duplex = (aux & PHY_M_PS_FULL_DUP) ? DUPLEX_FULL : DUPLEX_HALF; /* Pause bits are offset (9..8) */ - if (hw->chip_id == CHIP_ID_YUKON_XL || hw->chip_id == CHIP_ID_YUKON_EC_U) + if (hw->chip_id == CHIP_ID_YUKON_XL + || hw->chip_id == CHIP_ID_YUKON_EC_U + || hw->chip_id == CHIP_ID_YUKON_EX) aux >>= 6; sky2->flow_status = sky2_flow(aux & PHY_M_PS_RX_P_EN, aux & PHY_M_PS_TX_P_EN); if (sky2->duplex == DUPLEX_HALF && sky2->speed < SPEED_1000 - && hw->chip_id != CHIP_ID_YUKON_EC_U) + && !(hw->chip_id == CHIP_ID_YUKON_EC_U || hw->chip_id == CHIP_ID_YUKON_EX)) sky2->flow_status = FC_NONE; if (aux & PHY_M_PS_RX_P_EN) @@ -1794,48 +1854,37 @@ out: } -/* Transmit timeout is only called if we are running, carries is up +/* Transmit timeout is only called if we are running, carrier is up * and tx queue is full (stopped). + * Called with netif_tx_lock held. */ static void sky2_tx_timeout(struct net_device *dev) { struct sky2_port *sky2 = netdev_priv(dev); struct sky2_hw *hw = sky2->hw; - unsigned txq = txqaddr[sky2->port]; - u16 report, done; + u32 imask; if (netif_msg_timer(sky2)) printk(KERN_ERR PFX "%s: tx timeout\n", dev->name); - report = sky2_read16(hw, sky2->port == 0 ? STAT_TXA1_RIDX : STAT_TXA2_RIDX); - done = sky2_read16(hw, Q_ADDR(txq, Q_DONE)); - printk(KERN_DEBUG PFX "%s: transmit ring %u .. %u report=%u done=%u\n", - dev->name, - sky2->tx_cons, sky2->tx_prod, report, done); + dev->name, sky2->tx_cons, sky2->tx_prod, + sky2_read16(hw, sky2->port == 0 ? STAT_TXA1_RIDX : STAT_TXA2_RIDX), + sky2_read16(hw, Q_ADDR(txqaddr[sky2->port], Q_DONE))); - if (report != done) { - printk(KERN_INFO PFX "status burst pending (irq moderation?)\n"); - - sky2_write8(hw, STAT_TX_TIMER_CTRL, TIM_STOP); - sky2_write8(hw, STAT_TX_TIMER_CTRL, TIM_START); - } else if (report != sky2->tx_cons) { - printk(KERN_INFO PFX "status report lost?\n"); + imask = sky2_read32(hw, B0_IMSK); /* block IRQ in hw */ + sky2_write32(hw, B0_IMSK, 0); + sky2_read32(hw, B0_IMSK); - netif_tx_lock_bh(dev); - sky2_tx_complete(sky2, report); - netif_tx_unlock_bh(dev); - } else { - printk(KERN_INFO PFX "hardware hung? flushing\n"); + netif_poll_disable(hw->dev[0]); /* stop NAPI poll */ + synchronize_irq(hw->pdev->irq); - sky2_write32(hw, Q_ADDR(txq, Q_CSR), BMU_STOP); - sky2_write32(hw, Y2_QADDR(txq, PREF_UNIT_CTRL), PREF_UNIT_RST_SET); + netif_start_queue(dev); /* don't wakeup during flush */ + sky2_tx_complete(sky2, sky2->tx_prod); /* Flush transmit queue */ - sky2_tx_clean(dev); + sky2_write32(hw, B0_IMSK, imask); - sky2_qset(hw, txq); - sky2_prefetch_init(hw, txq, sky2->tx_le_map, TX_RING_SIZE - 1); - } + sky2_phy_reinit(sky2); /* this clears flow control etc */ } static int sky2_change_mtu(struct net_device *dev, int new_mtu) @@ -1849,8 +1898,9 @@ static int sky2_change_mtu(struct net_de if (new_mtu < ETH_ZLEN || new_mtu > ETH_JUMBO_MTU) return -EINVAL; + /* TSO on Yukon Ultra and MTU > 1500 not supported */ if (hw->chip_id == CHIP_ID_YUKON_EC_U && new_mtu > ETH_DATA_LEN) - return -EINVAL; + dev->features &= ~NETIF_F_TSO; if (!netif_running(dev)) { dev->mtu = new_mtu; @@ -2089,6 +2139,8 @@ static int sky2_status_intr(struct sky2_ goto force_update; skb->protocol = eth_type_trans(skb, dev); + sky2->net_stats.rx_packets++; + sky2->net_stats.rx_bytes += skb->len; dev->last_rx = jiffies; #ifdef SKY2_VLAN_TAG_USED @@ -2218,8 +2270,8 @@ static void sky2_hw_intr(struct sky2_hw pci_err = sky2_pci_read16(hw, PCI_STATUS); if (net_ratelimit()) - printk(KERN_ERR PFX "%s: pci hw error (0x%x)\n", - pci_name(hw->pdev), pci_err); + dev_err(&hw->pdev->dev, "PCI hardware error (0x%x)\n", + pci_err); sky2_write8(hw, B2_TST_CTRL1, TST_CFG_WRITE_ON); sky2_pci_write16(hw, PCI_STATUS, @@ -2234,8 +2286,8 @@ static void sky2_hw_intr(struct sky2_hw pex_err = sky2_pci_read32(hw, PEX_UNC_ERR_STAT); if (net_ratelimit()) - printk(KERN_ERR PFX "%s: pci express error (0x%x)\n", - pci_name(hw->pdev), pex_err); + dev_err(&hw->pdev->dev, "PCI Express error (0x%x)\n", + pex_err); /* clear the interrupt */ sky2_write32(hw, B2_TST_CTRL1, TST_CFG_WRITE_ON); @@ -2404,6 +2456,7 @@ static inline u32 sky2_mhz(const struct switch (hw->chip_id) { case CHIP_ID_YUKON_EC: case CHIP_ID_YUKON_EC_U: + case CHIP_ID_YUKON_EX: return 125; /* 125 Mhz */ case CHIP_ID_YUKON_FE: return 100; /* 100 Mhz */ @@ -2423,34 +2476,62 @@ static inline u32 sky2_clk2us(const stru } -static int sky2_reset(struct sky2_hw *hw) +static int __devinit sky2_init(struct sky2_hw *hw) { - u16 status; u8 t8; - int i; sky2_write8(hw, B0_CTST, CS_RST_CLR); hw->chip_id = sky2_read8(hw, B2_CHIP_ID); if (hw->chip_id < CHIP_ID_YUKON_XL || hw->chip_id > CHIP_ID_YUKON_FE) { - printk(KERN_ERR PFX "%s: unsupported chip type 0x%x\n", - pci_name(hw->pdev), hw->chip_id); + dev_err(&hw->pdev->dev, "unsupported chip type 0x%x\n", + hw->chip_id); return -EOPNOTSUPP; } + if (hw->chip_id == CHIP_ID_YUKON_EX) + dev_warn(&hw->pdev->dev, "this driver not yet tested on this chip type\n" + "Please report success or failure to \n"); + + /* Make sure and enable all clocks */ + if (hw->chip_id == CHIP_ID_YUKON_EX || hw->chip_id == CHIP_ID_YUKON_EC_U) + sky2_pci_write32(hw, PCI_DEV_REG3, 0); + hw->chip_rev = (sky2_read8(hw, B2_MAC_CFG) & CFG_CHIP_R_MSK) >> 4; /* This rev is really old, and requires untested workarounds */ if (hw->chip_id == CHIP_ID_YUKON_EC && hw->chip_rev == CHIP_REV_YU_EC_A1) { - printk(KERN_ERR PFX "%s: unsupported revision Yukon-%s (0x%x) rev %d\n", - pci_name(hw->pdev), yukon2_name[hw->chip_id - CHIP_ID_YUKON_XL], - hw->chip_id, hw->chip_rev); + dev_err(&hw->pdev->dev, "unsupported revision Yukon-%s (0x%x) rev %d\n", + yukon2_name[hw->chip_id - CHIP_ID_YUKON_XL], + hw->chip_id, hw->chip_rev); return -EOPNOTSUPP; } + hw->pmd_type = sky2_read8(hw, B2_PMD_TYP); + hw->ports = 1; + t8 = sky2_read8(hw, B2_Y2_HW_RES); + if ((t8 & CFG_DUAL_MAC_MSK) == CFG_DUAL_MAC_MSK) { + if (!(sky2_read8(hw, B2_Y2_CLK_GATE) & Y2_STATUS_LNK2_INAC)) + ++hw->ports; + } + + return 0; +} + +static void sky2_reset(struct sky2_hw *hw) +{ + u16 status; + int i; + /* disable ASF */ if (hw->chip_id <= CHIP_ID_YUKON_EC) { - sky2_write8(hw, B28_Y2_ASF_STAT_CMD, Y2_ASF_RESET); + if (hw->chip_id == CHIP_ID_YUKON_EX) { + status = sky2_read16(hw, HCU_CCSR); + status &= ~(HCU_CCSR_AHB_RST | HCU_CCSR_CPU_RST_MODE | + HCU_CCSR_UC_STATE_MSK); + sky2_write16(hw, HCU_CCSR, status); + } else + sky2_write8(hw, B28_Y2_ASF_STAT_CMD, Y2_ASF_RESET); sky2_write16(hw, B0_CTST, Y2_ASF_DISABLE); } @@ -2472,15 +2553,7 @@ static int sky2_reset(struct sky2_hw *hw sky2_pci_write32(hw, PEX_UNC_ERR_STAT, 0xffffffffUL); - hw->pmd_type = sky2_read8(hw, B2_PMD_TYP); - hw->ports = 1; - t8 = sky2_read8(hw, B2_Y2_HW_RES); - if ((t8 & CFG_DUAL_MAC_MSK) == CFG_DUAL_MAC_MSK) { - if (!(sky2_read8(hw, B2_Y2_CLK_GATE) & Y2_STATUS_LNK2_INAC)) - ++hw->ports; - } - - sky2_set_power_state(hw, PCI_D0); + sky2_power_on(hw); for (i = 0; i < hw->ports; i++) { sky2_write8(hw, SK_REG(i, GMAC_LINK_CTRL), GMLC_RST_SET); @@ -2563,7 +2636,37 @@ static int sky2_reset(struct sky2_hw *hw sky2_write8(hw, STAT_TX_TIMER_CTRL, TIM_START); sky2_write8(hw, STAT_LEV_TIMER_CTRL, TIM_START); sky2_write8(hw, STAT_ISR_TIMER_CTRL, TIM_START); +} + +static inline u8 sky2_wol_supported(const struct sky2_hw *hw) +{ + return sky2_is_copper(hw) ? (WAKE_PHY | WAKE_MAGIC) : 0; +} + +static void sky2_get_wol(struct net_device *dev, struct ethtool_wolinfo *wol) +{ + const struct sky2_port *sky2 = netdev_priv(dev); + + wol->supported = sky2_wol_supported(sky2->hw); + wol->wolopts = sky2->wol; +} + +static int sky2_set_wol(struct net_device *dev, struct ethtool_wolinfo *wol) +{ + struct sky2_port *sky2 = netdev_priv(dev); + struct sky2_hw *hw = sky2->hw; + + if (wol->wolopts & ~sky2_wol_supported(sky2->hw)) + return -EOPNOTSUPP; + + sky2->wol = wol->wolopts; + + if (hw->chip_id == CHIP_ID_YUKON_EC_U) + sky2_write32(hw, B0_CTST, sky2->wol + ? Y2_HW_WOL_ON : Y2_HW_WOL_OFF); + if (!netif_running(dev)) + sky2_wol_init(sky2); return 0; } @@ -2814,25 +2917,9 @@ static void sky2_get_strings(struct net_ } } -/* Use hardware MIB variables for critical path statistics and - * transmit feedback not reported at interrupt. - * Other errors are accounted for in interrupt handler. - */ static struct net_device_stats *sky2_get_stats(struct net_device *dev) { struct sky2_port *sky2 = netdev_priv(dev); - u64 data[13]; - - sky2_phy_stats(sky2, data, ARRAY_SIZE(data)); - - sky2->net_stats.tx_bytes = data[0]; - sky2->net_stats.rx_bytes = data[1]; - sky2->net_stats.tx_packets = data[2] + data[4] + data[6]; - sky2->net_stats.rx_packets = data[3] + data[5] + data[7]; - sky2->net_stats.multicast = data[3] + data[5]; - sky2->net_stats.collisions = data[10]; - sky2->net_stats.tx_aborted_errors = data[12]; - return &sky2->net_stats; } @@ -3191,7 +3278,9 @@ static void sky2_get_regs(struct net_dev static const struct ethtool_ops sky2_ethtool_ops = { .get_settings = sky2_get_settings, .set_settings = sky2_set_settings, - .get_drvinfo = sky2_get_drvinfo, + .get_drvinfo = sky2_get_drvinfo, + .get_wol = sky2_get_wol, + .set_wol = sky2_set_wol, .get_msglevel = sky2_get_msglevel, .set_msglevel = sky2_set_msglevel, .nway_reset = sky2_nway_reset, @@ -3221,13 +3310,14 @@ static const struct ethtool_ops sky2_eth /* Initialize network device */ static __devinit struct net_device *sky2_init_netdev(struct sky2_hw *hw, - unsigned port, int highmem) + unsigned port, + int highmem, int wol) { struct sky2_port *sky2; struct net_device *dev = alloc_etherdev(sizeof(*sky2)); if (!dev) { - printk(KERN_ERR "sky2 etherdev alloc failed"); + dev_err(&hw->pdev->dev, "etherdev alloc failed"); return NULL; } @@ -3269,6 +3359,7 @@ #endif sky2->speed = -1; sky2->advertising = sky2_supported_modes(hw); sky2->rx_csum = 1; + sky2->wol = wol; spin_lock_init(&sky2->phy_lock); sky2->tx_pending = TX_DEF_PENDING; @@ -3278,11 +3369,9 @@ #endif sky2->port = port; - if (hw->chip_id != CHIP_ID_YUKON_EC_U) - dev->features |= NETIF_F_TSO; + dev->features |= NETIF_F_TSO | NETIF_F_IP_CSUM | NETIF_F_SG; if (highmem) dev->features |= NETIF_F_HIGHDMA; - dev->features |= NETIF_F_IP_CSUM | NETIF_F_SG; #ifdef SKY2_VLAN_TAG_USED dev->features |= NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_RX; @@ -3343,8 +3432,7 @@ static int __devinit sky2_test_msi(struc err = request_irq(pdev->irq, sky2_test_intr, 0, DRV_NAME, hw); if (err) { - printk(KERN_ERR PFX "%s: cannot assign irq %d\n", - pci_name(pdev), pdev->irq); + dev_err(&pdev->dev, "cannot assign irq %d\n", pdev->irq); return err; } @@ -3355,9 +3443,8 @@ static int __devinit sky2_test_msi(struc if (!hw->msi) { /* MSI test failed, go back to INTx mode */ - printk(KERN_INFO PFX "%s: No interrupt generated using MSI, " - "switching to INTx mode.\n", - pci_name(pdev)); + dev_info(&pdev->dev, "No interrupt generated using MSI, " + "switching to INTx mode.\n"); err = -EOPNOTSUPP; sky2_write8(hw, B0_CTST, CS_CL_SW_IRQ); @@ -3371,62 +3458,62 @@ static int __devinit sky2_test_msi(struc return err; } +static int __devinit pci_wake_enabled(struct pci_dev *dev) +{ + int pm = pci_find_capability(dev, PCI_CAP_ID_PM); + u16 value; + + if (!pm) + return 0; + if (pci_read_config_word(dev, pm + PCI_PM_CTRL, &value)) + return 0; + return value & PCI_PM_CTRL_PME_ENABLE; +} + static int __devinit sky2_probe(struct pci_dev *pdev, const struct pci_device_id *ent) { - struct net_device *dev, *dev1 = NULL; + struct net_device *dev; struct sky2_hw *hw; - int err, pm_cap, using_dac = 0; + int err, using_dac = 0, wol_default; err = pci_enable_device(pdev); if (err) { - printk(KERN_ERR PFX "%s cannot enable PCI device\n", - pci_name(pdev)); + dev_err(&pdev->dev, "cannot enable PCI device\n"); goto err_out; } err = pci_request_regions(pdev, DRV_NAME); if (err) { - printk(KERN_ERR PFX "%s cannot obtain PCI resources\n", - pci_name(pdev)); + dev_err(&pdev->dev, "cannot obtain PCI resources\n"); goto err_out; } pci_set_master(pdev); - /* Find power-management capability. */ - pm_cap = pci_find_capability(pdev, PCI_CAP_ID_PM); - if (pm_cap == 0) { - printk(KERN_ERR PFX "Cannot find PowerManagement capability, " - "aborting.\n"); - err = -EIO; - goto err_out_free_regions; - } - if (sizeof(dma_addr_t) > sizeof(u32) && !(err = pci_set_dma_mask(pdev, DMA_64BIT_MASK))) { using_dac = 1; err = pci_set_consistent_dma_mask(pdev, DMA_64BIT_MASK); if (err < 0) { - printk(KERN_ERR PFX "%s unable to obtain 64 bit DMA " - "for consistent allocations\n", pci_name(pdev)); + dev_err(&pdev->dev, "unable to obtain 64 bit DMA " + "for consistent allocations\n"); goto err_out_free_regions; } - } else { err = pci_set_dma_mask(pdev, DMA_32BIT_MASK); if (err) { - printk(KERN_ERR PFX "%s no usable DMA configuration\n", - pci_name(pdev)); + dev_err(&pdev->dev, "no usable DMA configuration\n"); goto err_out_free_regions; } } + wol_default = pci_wake_enabled(pdev) ? WAKE_MAGIC : 0; + err = -ENOMEM; hw = kzalloc(sizeof(*hw), GFP_KERNEL); if (!hw) { - printk(KERN_ERR PFX "%s: cannot allocate hardware struct\n", - pci_name(pdev)); + dev_err(&pdev->dev, "cannot allocate hardware struct\n"); goto err_out_free_regions; } @@ -3434,11 +3521,9 @@ static int __devinit sky2_probe(struct p hw->regs = ioremap_nocache(pci_resource_start(pdev, 0), 0x4000); if (!hw->regs) { - printk(KERN_ERR PFX "%s: cannot map device registers\n", - pci_name(pdev)); + dev_err(&pdev->dev, "cannot map device registers\n"); goto err_out_free_hw; } - hw->pm_cap = pm_cap; #ifdef __BIG_ENDIAN /* The sk98lin vendor driver uses hardware byte swapping but @@ -3458,18 +3543,22 @@ #endif if (!hw->st_le) goto err_out_iounmap; - err = sky2_reset(hw); + err = sky2_init(hw); if (err) goto err_out_iounmap; - printk(KERN_INFO PFX "v%s addr 0x%llx irq %d Yukon-%s (0x%x) rev %d\n", + dev_info(&pdev->dev, "v%s addr 0x%llx irq %d Yukon-%s (0x%x) rev %d\n", DRV_VERSION, (unsigned long long)pci_resource_start(pdev, 0), pdev->irq, yukon2_name[hw->chip_id - CHIP_ID_YUKON_XL], hw->chip_id, hw->chip_rev); - dev = sky2_init_netdev(hw, 0, using_dac); - if (!dev) + sky2_reset(hw); + + dev = sky2_init_netdev(hw, 0, using_dac, wol_default); + if (!dev) { + err = -ENOMEM; goto err_out_free_pci; + } if (!disable_msi && pci_enable_msi(pdev) == 0) { err = sky2_test_msi(hw); @@ -3481,32 +3570,33 @@ #endif err = register_netdev(dev); if (err) { - printk(KERN_ERR PFX "%s: cannot register net device\n", - pci_name(pdev)); + dev_err(&pdev->dev, "cannot register net device\n"); goto err_out_free_netdev; } err = request_irq(pdev->irq, sky2_intr, hw->msi ? 0 : IRQF_SHARED, dev->name, hw); if (err) { - printk(KERN_ERR PFX "%s: cannot assign irq %d\n", - pci_name(pdev), pdev->irq); + dev_err(&pdev->dev, "cannot assign irq %d\n", pdev->irq); goto err_out_unregister; } sky2_write32(hw, B0_IMSK, Y2_IS_BASE); sky2_show_addr(dev); - if (hw->ports > 1 && (dev1 = sky2_init_netdev(hw, 1, using_dac))) { - if (register_netdev(dev1) == 0) - sky2_show_addr(dev1); - else { - /* Failure to register second port need not be fatal */ - printk(KERN_WARNING PFX - "register of second port failed\n"); + if (hw->ports > 1) { + struct net_device *dev1; + + dev1 = sky2_init_netdev(hw, 1, using_dac, wol_default); + if (!dev1) + dev_warn(&pdev->dev, "allocation for second device failed\n"); + else if ((err = register_netdev(dev1))) { + dev_warn(&pdev->dev, + "register of second port failed (%d)\n", err); hw->dev[1] = NULL; free_netdev(dev1); - } + } else + sky2_show_addr(dev1); } setup_timer(&hw->idle_timer, sky2_idle, (unsigned long) hw); @@ -3555,7 +3645,8 @@ static void __devexit sky2_remove(struct unregister_netdev(dev1); unregister_netdev(dev0); - sky2_set_power_state(hw, PCI_D3hot); + sky2_power_aux(hw); + sky2_write16(hw, B0_Y2LED, LED_STAT_OFF); sky2_write8(hw, B0_CTST, CS_RST_SET); sky2_read8(hw, B0_CTST); @@ -3580,27 +3671,31 @@ #ifdef CONFIG_PM static int sky2_suspend(struct pci_dev *pdev, pm_message_t state) { struct sky2_hw *hw = pci_get_drvdata(pdev); - int i; - pci_power_t pstate = pci_choose_state(pdev, state); - - if (!(pstate == PCI_D3hot || pstate == PCI_D3cold)) - return -EINVAL; + int i, wol = 0; del_timer_sync(&hw->idle_timer); netif_poll_disable(hw->dev[0]); for (i = 0; i < hw->ports; i++) { struct net_device *dev = hw->dev[i]; + struct sky2_port *sky2 = netdev_priv(dev); - if (netif_running(dev)) { + if (netif_running(dev)) sky2_down(dev); - netif_device_detach(dev); - } + + if (sky2->wol) + sky2_wol_init(sky2); + + wol |= sky2->wol; } sky2_write32(hw, B0_IMSK, 0); + sky2_power_aux(hw); + pci_save_state(pdev); - sky2_set_power_state(hw, pstate); + pci_enable_wake(pdev, pci_choose_state(pdev, state), wol); + pci_set_power_state(pdev, pci_choose_state(pdev, state)); + return 0; } @@ -3609,21 +3704,22 @@ static int sky2_resume(struct pci_dev *p struct sky2_hw *hw = pci_get_drvdata(pdev); int i, err; - pci_restore_state(pdev); - pci_enable_wake(pdev, PCI_D0, 0); - sky2_set_power_state(hw, PCI_D0); + err = pci_set_power_state(pdev, PCI_D0); + if (err) + goto out; - err = sky2_reset(hw); + err = pci_restore_state(pdev); if (err) goto out; + pci_enable_wake(pdev, PCI_D0, 0); + sky2_reset(hw); + sky2_write32(hw, B0_IMSK, Y2_IS_BASE); for (i = 0; i < hw->ports; i++) { struct net_device *dev = hw->dev[i]; if (netif_running(dev)) { - netif_device_attach(dev); - err = sky2_up(dev); if (err) { printk(KERN_ERR PFX "%s: could not up: %d\n", @@ -3636,11 +3732,43 @@ static int sky2_resume(struct pci_dev *p netif_poll_enable(hw->dev[0]); sky2_idle_start(hw); + return 0; out: + dev_err(&pdev->dev, "resume failed (%d)\n", err); + pci_disable_device(pdev); return err; } #endif +static void sky2_shutdown(struct pci_dev *pdev) +{ + struct sky2_hw *hw = pci_get_drvdata(pdev); + int i, wol = 0; + + del_timer_sync(&hw->idle_timer); + netif_poll_disable(hw->dev[0]); + + for (i = 0; i < hw->ports; i++) { + struct net_device *dev = hw->dev[i]; + struct sky2_port *sky2 = netdev_priv(dev); + + if (sky2->wol) { + wol = 1; + sky2_wol_init(sky2); + } + } + + if (wol) + sky2_power_aux(hw); + + pci_enable_wake(pdev, PCI_D3hot, wol); + pci_enable_wake(pdev, PCI_D3cold, wol); + + pci_disable_device(pdev); + pci_set_power_state(pdev, PCI_D3hot); + +} + static struct pci_driver sky2_driver = { .name = DRV_NAME, .id_table = sky2_id_table, @@ -3650,6 +3778,7 @@ #ifdef CONFIG_PM .suspend = sky2_suspend, .resume = sky2_resume, #endif + .shutdown = sky2_shutdown, }; static int __init sky2_init_module(void) diff --git a/drivers/net/sky2.h b/drivers/net/sky2.h index 6ed1d47..3b01895 100644 --- a/drivers/net/sky2.h +++ b/drivers/net/sky2.h @@ -32,6 +32,7 @@ enum pci_dev_reg_1 { PCI_Y2_PHY1_COMA = 1<<28, /* Set PHY 1 to Coma Mode (YUKON-2) */ PCI_Y2_PHY2_POWD = 1<<27, /* Set PHY 2 to Power Down (YUKON-2) */ PCI_Y2_PHY1_POWD = 1<<26, /* Set PHY 1 to Power Down (YUKON-2) */ + PCI_Y2_PME_LEGACY= 1<<15, /* PCI Express legacy power management mode */ }; enum pci_dev_reg_2 { @@ -370,12 +371,9 @@ enum { /* B2_CHIP_ID 8 bit Chip Identification Number */ enum { - CHIP_ID_GENESIS = 0x0a, /* Chip ID for GENESIS */ - CHIP_ID_YUKON = 0xb0, /* Chip ID for YUKON */ - CHIP_ID_YUKON_LITE = 0xb1, /* Chip ID for YUKON-Lite (Rev. A1-A3) */ - CHIP_ID_YUKON_LP = 0xb2, /* Chip ID for YUKON-LP */ CHIP_ID_YUKON_XL = 0xb3, /* Chip ID for YUKON-2 XL */ CHIP_ID_YUKON_EC_U = 0xb4, /* Chip ID for YUKON-2 EC Ultra */ + CHIP_ID_YUKON_EX = 0xb5, /* Chip ID for YUKON-2 Extreme */ CHIP_ID_YUKON_EC = 0xb6, /* Chip ID for YUKON-2 EC */ CHIP_ID_YUKON_FE = 0xb7, /* Chip ID for YUKON-2 FE */ @@ -767,6 +765,24 @@ enum { POLL_LIST_ADDR_HI= 0x0e2c,/* 32 bit Poll. List Start Addr (high) */ }; +enum { + SMB_CFG = 0x0e40, /* 32 bit SMBus Config Register */ + SMB_CSR = 0x0e44, /* 32 bit SMBus Control/Status Register */ +}; + +enum { + CPU_WDOG = 0x0e48, /* 32 bit Watchdog Register */ + CPU_CNTR = 0x0e4C, /* 32 bit Counter Register */ + CPU_TIM = 0x0e50,/* 32 bit Timer Compare Register */ + CPU_AHB_ADDR = 0x0e54, /* 32 bit CPU AHB Debug Register */ + CPU_AHB_WDATA = 0x0e58, /* 32 bit CPU AHB Debug Register */ + CPU_AHB_RDATA = 0x0e5C, /* 32 bit CPU AHB Debug Register */ + HCU_MAP_BASE = 0x0e60, /* 32 bit Reset Mapping Base */ + CPU_AHB_CTRL = 0x0e64, /* 32 bit CPU AHB Debug Register */ + HCU_CCSR = 0x0e68, /* 32 bit CPU Control and Status Register */ + HCU_HCSR = 0x0e6C, /* 32 bit Host Control and Status Register */ +}; + /* ASF Subsystem Registers (Yukon-2 only) */ enum { B28_Y2_SMB_CONFIG = 0x0e40,/* 32 bit ASF SMBus Config Register */ @@ -837,33 +853,27 @@ enum { GMAC_LINK_CTRL = 0x0f10,/* 16 bit Link Control Reg */ /* Wake-up Frame Pattern Match Control Registers (YUKON only) */ - - WOL_REG_OFFS = 0x20,/* HW-Bug: Address is + 0x20 against spec. */ - WOL_CTRL_STAT = 0x0f20,/* 16 bit WOL Control/Status Reg */ WOL_MATCH_CTL = 0x0f22,/* 8 bit WOL Match Control Reg */ WOL_MATCH_RES = 0x0f23,/* 8 bit WOL Match Result Reg */ WOL_MAC_ADDR = 0x0f24,/* 32 bit WOL MAC Address */ - WOL_PATT_PME = 0x0f2a,/* 8 bit WOL PME Match Enable (Yukon-2) */ - WOL_PATT_ASFM = 0x0f2b,/* 8 bit WOL ASF Match Enable (Yukon-2) */ WOL_PATT_RPTR = 0x0f2c,/* 8 bit WOL Pattern Read Pointer */ /* WOL Pattern Length Registers (YUKON only) */ - WOL_PATT_LEN_LO = 0x0f30,/* 32 bit WOL Pattern Length 3..0 */ WOL_PATT_LEN_HI = 0x0f34,/* 24 bit WOL Pattern Length 6..4 */ /* WOL Pattern Counter Registers (YUKON only) */ - - WOL_PATT_CNT_0 = 0x0f38,/* 32 bit WOL Pattern Counter 3..0 */ WOL_PATT_CNT_4 = 0x0f3c,/* 24 bit WOL Pattern Counter 6..4 */ }; +#define WOL_REGS(port, x) (x + (port)*0x80) enum { WOL_PATT_RAM_1 = 0x1000,/* WOL Pattern RAM Link 1 */ WOL_PATT_RAM_2 = 0x1400,/* WOL Pattern RAM Link 2 */ }; +#define WOL_PATT_RAM_BASE(port) (WOL_PATT_RAM_1 + (port)*0x400) enum { BASE_GMAC_1 = 0x2800,/* GMAC 1 registers */ @@ -1654,6 +1664,39 @@ enum { Y2_ASF_CLR_ASFI = 1<<1, /* Clear host IRQ */ Y2_ASF_HOST_IRQ = 1<<0, /* Issue an IRQ to HOST system */ }; +/* HCU_CCSR CPU Control and Status Register */ +enum { + HCU_CCSR_SMBALERT_MONITOR= 1<<27, /* SMBALERT pin monitor */ + HCU_CCSR_CPU_SLEEP = 1<<26, /* CPU sleep status */ + /* Clock Stretching Timeout */ + HCU_CCSR_CS_TO = 1<<25, + HCU_CCSR_WDOG = 1<<24, /* Watchdog Reset */ + + HCU_CCSR_CLR_IRQ_HOST = 1<<17, /* Clear IRQ_HOST */ + HCU_CCSR_SET_IRQ_HCU = 1<<16, /* Set IRQ_HCU */ + + HCU_CCSR_AHB_RST = 1<<9, /* Reset AHB bridge */ + HCU_CCSR_CPU_RST_MODE = 1<<8, /* CPU Reset Mode */ + + HCU_CCSR_SET_SYNC_CPU = 1<<5, + HCU_CCSR_CPU_CLK_DIVIDE_MSK = 3<<3,/* CPU Clock Divide */ + HCU_CCSR_CPU_CLK_DIVIDE_BASE= 1<<3, + HCU_CCSR_OS_PRSNT = 1<<2, /* ASF OS Present */ +/* Microcontroller State */ + HCU_CCSR_UC_STATE_MSK = 3, + HCU_CCSR_UC_STATE_BASE = 1<<0, + HCU_CCSR_ASF_RESET = 0, + HCU_CCSR_ASF_HALTED = 1<<1, + HCU_CCSR_ASF_RUNNING = 1<<0, +}; + +/* HCU_HCSR Host Control and Status Register */ +enum { + HCU_HCSR_SET_IRQ_CPU = 1<<16, /* Set IRQ_CPU */ + + HCU_HCSR_CLR_IRQ_HCU = 1<<1, /* Clear IRQ_HCU */ + HCU_HCSR_SET_IRQ_HOST = 1<<0, /* Set IRQ_HOST */ +}; /* STAT_CTRL 32 bit Status BMU control register (Yukon-2 only) */ enum { @@ -1715,14 +1758,17 @@ enum { GM_IS_RX_COMPL = 1<<0, /* Frame Reception Complete */ #define GMAC_DEF_MSK GM_IS_TX_FF_UR +}; /* GMAC_LINK_CTRL 16 bit GMAC Link Control Reg (YUKON only) */ - /* Bits 15.. 2: reserved */ +enum { /* Bits 15.. 2: reserved */ GMLC_RST_CLR = 1<<1, /* Clear GMAC Link Reset */ GMLC_RST_SET = 1<<0, /* Set GMAC Link Reset */ +}; /* WOL_CTRL_STAT 16 bit WOL Control/Status Reg */ +enum { WOL_CTL_LINK_CHG_OCC = 1<<15, WOL_CTL_MAGIC_PKT_OCC = 1<<14, WOL_CTL_PATTERN_OCC = 1<<13, @@ -1741,17 +1787,6 @@ #define GMAC_DEF_MSK GM_IS_TX_FF_UR WOL_CTL_DIS_PATTERN_UNIT = 1<<0, }; -#define WOL_CTL_DEFAULT \ - (WOL_CTL_DIS_PME_ON_LINK_CHG | \ - WOL_CTL_DIS_PME_ON_PATTERN | \ - WOL_CTL_DIS_PME_ON_MAGIC_PKT | \ - WOL_CTL_DIS_LINK_CHG_UNIT | \ - WOL_CTL_DIS_PATTERN_UNIT | \ - WOL_CTL_DIS_MAGIC_PKT_UNIT) - -/* WOL_MATCH_CTL 8 bit WOL Match Control Reg */ -#define WOL_CTL_PATT_ENA(x) (1 << (x)) - /* Control flags */ enum { @@ -1875,6 +1910,7 @@ #endif u8 autoneg; /* AUTONEG_ENABLE, AUTONEG_DISABLE */ u8 duplex; /* DUPLEX_HALF, DUPLEX_FULL */ u8 rx_csum; + u8 wol; enum flow_control flow_mode; enum flow_control flow_status; @@ -1887,7 +1923,6 @@ struct sky2_hw { struct pci_dev *pdev; struct net_device *dev[2]; - int pm_cap; u8 chip_id; u8 chip_rev; u8 pmd_type; diff --git a/drivers/net/slip.c b/drivers/net/slip.c index a0806d2..2f4b1de 100644 --- a/drivers/net/slip.c +++ b/drivers/net/slip.c @@ -1343,15 +1343,12 @@ #ifdef CONFIG_SLIP_SMART printk(KERN_INFO "SLIP linefill/keepalive option.\n"); #endif - slip_devs = kmalloc(sizeof(struct net_device *)*slip_maxdev, GFP_KERNEL); + slip_devs = kzalloc(sizeof(struct net_device *)*slip_maxdev, GFP_KERNEL); if (!slip_devs) { printk(KERN_ERR "SLIP: Can't allocate slip devices array! Uaargh! (-> No SLIP available)\n"); return -ENOMEM; } - /* Clear the pointer array, we allocate devices when we need them */ - memset(slip_devs, 0, sizeof(struct net_device *)*slip_maxdev); - /* Fill in our line protocol discipline, and register it */ if ((status = tty_register_ldisc(N_SLIP, &sl_ldisc)) != 0) { printk(KERN_ERR "SLIP: can't register line discipline (err = %d)\n", status); diff --git a/drivers/net/smc-mca.c b/drivers/net/smc-mca.c index 7122932..ae1ae34 100644 --- a/drivers/net/smc-mca.c +++ b/drivers/net/smc-mca.c @@ -482,8 +482,7 @@ static void ultramca_block_input(struct count -= semi_count; memcpy_fromio(skb->data + semi_count, ei_status.mem + TX_PAGES * 256, count); } else { - /* Packet is in one chunk -- we can copy + cksum. */ - eth_io_copy_and_sum(skb, xfer_start, count, 0); + memcpy_fromio(skb->data, xfer_start, count); } } diff --git a/drivers/net/smc-ultra.c b/drivers/net/smc-ultra.c index d70bc97..a52b22d 100644 --- a/drivers/net/smc-ultra.c +++ b/drivers/net/smc-ultra.c @@ -454,8 +454,7 @@ ultra_block_input(struct net_device *dev count -= semi_count; memcpy_fromio(skb->data + semi_count, ei_status.mem + TX_PAGES * 256, count); } else { - /* Packet is in one chunk -- we can copy + cksum. */ - eth_io_copy_and_sum(skb, xfer_start, count, 0); + memcpy_fromio(skb->data, xfer_start, count); } outb(0x00, dev->base_addr - ULTRA_NIC_OFFSET); /* Disable memory. */ diff --git a/drivers/net/smc-ultra32.c b/drivers/net/smc-ultra32.c index 2c5319c..88a30e5 100644 --- a/drivers/net/smc-ultra32.c +++ b/drivers/net/smc-ultra32.c @@ -395,8 +395,7 @@ static void ultra32_block_input(struct n memcpy_fromio(skb->data + semi_count, ei_status.mem + TX_PAGES * 256, count); } } else { - /* Packet is in one chunk -- we can copy + cksum. */ - eth_io_copy_and_sum(skb, xfer_start, count, 0); + memcpy_fromio(skb->data, xfer_start, count); } } diff --git a/drivers/net/smc911x.c b/drivers/net/smc911x.c index 43af614..c956141 100644 --- a/drivers/net/smc911x.c +++ b/drivers/net/smc911x.c @@ -1659,7 +1659,7 @@ smc911x_ethtool_getdrvinfo(struct net_de { strncpy(info->driver, CARDNAME, sizeof(info->driver)); strncpy(info->version, version, sizeof(info->version)); - strncpy(info->bus_info, dev->class_dev.dev->bus_id, sizeof(info->bus_info)); + strncpy(info->bus_info, dev->dev.parent->bus_id, sizeof(info->bus_info)); } static int smc911x_ethtool_nwayreset(struct net_device *dev) diff --git a/drivers/net/smc91x.c b/drivers/net/smc91x.c index e62a958..49f4b77 100644 --- a/drivers/net/smc91x.c +++ b/drivers/net/smc91x.c @@ -1712,7 +1712,7 @@ smc_ethtool_getdrvinfo(struct net_device { strncpy(info->driver, CARDNAME, sizeof(info->driver)); strncpy(info->version, version, sizeof(info->version)); - strncpy(info->bus_info, dev->class_dev.dev->bus_id, sizeof(info->bus_info)); + strncpy(info->bus_info, dev->dev.parent->bus_id, sizeof(info->bus_info)); } static int smc_ethtool_nwayreset(struct net_device *dev) diff --git a/drivers/net/spider_net.c b/drivers/net/spider_net.c index 8ea2fc1..64ed8ff 100644 --- a/drivers/net/spider_net.c +++ b/drivers/net/spider_net.c @@ -280,72 +280,67 @@ spider_net_free_chain(struct spider_net_ { struct spider_net_descr *descr; - for (descr = chain->tail; !descr->bus_addr; descr = descr->next) { - pci_unmap_single(card->pdev, descr->bus_addr, - SPIDER_NET_DESCR_SIZE, PCI_DMA_BIDIRECTIONAL); + descr = chain->ring; + do { descr->bus_addr = 0; - } + descr->next_descr_addr = 0; + descr = descr->next; + } while (descr != chain->ring); + + dma_free_coherent(&card->pdev->dev, chain->num_desc, + chain->ring, chain->dma_addr); } /** - * spider_net_init_chain - links descriptor chain + * spider_net_init_chain - alloc and link descriptor chain * @card: card structure * @chain: address of chain - * @start_descr: address of descriptor array - * @no: number of descriptors * - * we manage a circular list that mirrors the hardware structure, + * We manage a circular list that mirrors the hardware structure, * except that the hardware uses bus addresses. * - * returns 0 on success, <0 on failure + * Returns 0 on success, <0 on failure */ static int spider_net_init_chain(struct spider_net_card *card, - struct spider_net_descr_chain *chain, - struct spider_net_descr *start_descr, - int no) + struct spider_net_descr_chain *chain) { int i; struct spider_net_descr *descr; dma_addr_t buf; + size_t alloc_size; - descr = start_descr; - memset(descr, 0, sizeof(*descr) * no); + alloc_size = chain->num_desc * sizeof (struct spider_net_descr); - /* set up the hardware pointers in each descriptor */ - for (i=0; idmac_cmd_status = SPIDER_NET_DESCR_NOT_IN_USE; + chain->ring = dma_alloc_coherent(&card->pdev->dev, alloc_size, + &chain->dma_addr, GFP_KERNEL); + + if (!chain->ring) + return -ENOMEM; - buf = pci_map_single(card->pdev, descr, - SPIDER_NET_DESCR_SIZE, - PCI_DMA_BIDIRECTIONAL); + descr = chain->ring; + memset(descr, 0, alloc_size); - if (pci_dma_mapping_error(buf)) - goto iommu_error; + /* Set up the hardware pointers in each descriptor */ + buf = chain->dma_addr; + for (i=0; i < chain->num_desc; i++, descr++) { + descr->dmac_cmd_status = SPIDER_NET_DESCR_NOT_IN_USE; descr->bus_addr = buf; + descr->next_descr_addr = 0; descr->next = descr + 1; descr->prev = descr - 1; + buf += sizeof(struct spider_net_descr); } /* do actual circular list */ - (descr-1)->next = start_descr; - start_descr->prev = descr-1; + (descr-1)->next = chain->ring; + chain->ring->prev = descr-1; spin_lock_init(&chain->lock); - chain->head = start_descr; - chain->tail = start_descr; - + chain->head = chain->ring; + chain->tail = chain->ring; return 0; - -iommu_error: - descr = start_descr; - for (i=0; i < no; i++, descr++) - if (descr->bus_addr) - pci_unmap_single(card->pdev, descr->bus_addr, - SPIDER_NET_DESCR_SIZE, - PCI_DMA_BIDIRECTIONAL); - return -ENOMEM; } /** @@ -372,21 +367,20 @@ spider_net_free_rx_chain_contents(struct } /** - * spider_net_prepare_rx_descr - reinitializes a rx descriptor + * spider_net_prepare_rx_descr - Reinitialize RX descriptor * @card: card structure * @descr: descriptor to re-init * - * return 0 on succes, <0 on failure + * Return 0 on succes, <0 on failure. * - * allocates a new rx skb, iommu-maps it and attaches it to the descriptor. - * Activate the descriptor state-wise + * Allocates a new rx skb, iommu-maps it and attaches it to the + * descriptor. Mark the descriptor as activated, ready-to-use. */ static int spider_net_prepare_rx_descr(struct spider_net_card *card, struct spider_net_descr *descr) { dma_addr_t buf; - int error = 0; int offset; int bufsize; @@ -414,7 +408,7 @@ spider_net_prepare_rx_descr(struct spide (SPIDER_NET_RXBUF_ALIGN - 1); if (offset) skb_reserve(descr->skb, SPIDER_NET_RXBUF_ALIGN - offset); - /* io-mmu-map the skb */ + /* iommu-map the skb */ buf = pci_map_single(card->pdev, descr->skb->data, SPIDER_NET_MAX_FRAME, PCI_DMA_FROMDEVICE); descr->buf_addr = buf; @@ -425,11 +419,16 @@ spider_net_prepare_rx_descr(struct spide card->spider_stats.rx_iommu_map_error++; descr->dmac_cmd_status = SPIDER_NET_DESCR_NOT_IN_USE; } else { + descr->next_descr_addr = 0; + wmb(); descr->dmac_cmd_status = SPIDER_NET_DESCR_CARDOWNED | SPIDER_NET_DMAC_NOINTR_COMPLETE; + + wmb(); + descr->prev->next_descr_addr = descr->bus_addr; } - return error; + return 0; } /** @@ -493,10 +492,10 @@ spider_net_refill_rx_chain(struct spider } /** - * spider_net_alloc_rx_skbs - allocates rx skbs in rx descriptor chains + * spider_net_alloc_rx_skbs - Allocates rx skbs in rx descriptor chains * @card: card structure * - * returns 0 on success, <0 on failure + * Returns 0 on success, <0 on failure. */ static int spider_net_alloc_rx_skbs(struct spider_net_card *card) @@ -507,16 +506,16 @@ spider_net_alloc_rx_skbs(struct spider_n result = -ENOMEM; chain = &card->rx_chain; - /* put at least one buffer into the chain. if this fails, - * we've got a problem. if not, spider_net_refill_rx_chain - * will do the rest at the end of this function */ + /* Put at least one buffer into the chain. if this fails, + * we've got a problem. If not, spider_net_refill_rx_chain + * will do the rest at the end of this function. */ if (spider_net_prepare_rx_descr(card, chain->head)) goto error; else chain->head = chain->head->next; - /* this will allocate the rest of the rx buffers; if not, it's - * business as usual later on */ + /* This will allocate the rest of the rx buffers; + * if not, it's business as usual later on. */ spider_net_refill_rx_chain(card); spider_net_enable_rxdmac(card); return 0; @@ -707,7 +706,7 @@ spider_net_set_low_watermark(struct spid } /* If TX queue is short, don't even bother with interrupts */ - if (cnt < card->num_tx_desc/4) + if (cnt < card->tx_chain.num_desc/4) return cnt; /* Set low-watermark 3/4th's of the way into the queue. */ @@ -915,16 +914,13 @@ spider_net_do_ioctl(struct net_device *n * spider_net_pass_skb_up - takes an skb from a descriptor and passes it on * @descr: descriptor to process * @card: card structure - * @napi: whether caller is in NAPI context - * - * returns 1 on success, 0 if no packet was passed to the stack * - * iommu-unmaps the skb, fills out skb structure and passes the data to the - * stack. The descriptor state is not changed. + * Fills out skb structure and passes the data to the stack. + * The descriptor state is not changed. */ -static int +static void spider_net_pass_skb_up(struct spider_net_descr *descr, - struct spider_net_card *card, int napi) + struct spider_net_card *card) { struct sk_buff *skb; struct net_device *netdev; @@ -932,23 +928,8 @@ spider_net_pass_skb_up(struct spider_net data_status = descr->data_status; data_error = descr->data_error; - netdev = card->netdev; - /* unmap descriptor */ - pci_unmap_single(card->pdev, descr->buf_addr, SPIDER_NET_MAX_FRAME, - PCI_DMA_FROMDEVICE); - - /* the cases we'll throw away the packet immediately */ - if (data_error & SPIDER_NET_DESTROY_RX_FLAGS) { - if (netif_msg_rx_err(card)) - pr_err("error in received descriptor found, " - "data_status=x%08x, data_error=x%08x\n", - data_status, data_error); - card->spider_stats.rx_desc_error++; - return 0; - } - skb = descr->skb; skb->dev = netdev; skb_put(skb, descr->valid_size); @@ -977,57 +958,72 @@ #define SPIDER_MISALIGN 2 } /* pass skb up to stack */ - if (napi) - netif_receive_skb(skb); - else - netif_rx_ni(skb); + netif_receive_skb(skb); /* update netdevice statistics */ card->netdev_stats.rx_packets++; card->netdev_stats.rx_bytes += skb->len; +} - return 1; +#ifdef DEBUG +static void show_rx_chain(struct spider_net_card *card) +{ + struct spider_net_descr_chain *chain = &card->rx_chain; + struct spider_net_descr *start= chain->tail; + struct spider_net_descr *descr= start; + int status; + + int cnt = 0; + int cstat = spider_net_get_descr_status(descr); + printk(KERN_INFO "RX chain tail at descr=%ld\n", + (start - card->descr) - card->tx_chain.num_desc); + status = cstat; + do + { + status = spider_net_get_descr_status(descr); + if (cstat != status) { + printk(KERN_INFO "Have %d descrs with stat=x%08x\n", cnt, cstat); + cstat = status; + cnt = 0; + } + cnt ++; + descr = descr->next; + } while (descr != start); + printk(KERN_INFO "Last %d descrs with stat=x%08x\n", cnt, cstat); } +#endif /** * spider_net_decode_one_descr - processes an rx descriptor * @card: card structure - * @napi: whether caller is in NAPI context * - * returns 1 if a packet has been sent to the stack, otherwise 0 + * Returns 1 if a packet has been sent to the stack, otherwise 0 * - * processes an rx descriptor by iommu-unmapping the data buffer and passing + * Processes an rx descriptor by iommu-unmapping the data buffer and passing * the packet up to the stack. This function is called in softirq * context, e.g. either bottom half from interrupt or NAPI polling context */ static int -spider_net_decode_one_descr(struct spider_net_card *card, int napi) +spider_net_decode_one_descr(struct spider_net_card *card) { struct spider_net_descr_chain *chain = &card->rx_chain; struct spider_net_descr *descr = chain->tail; int status; - int result; status = spider_net_get_descr_status(descr); - if (status == SPIDER_NET_DESCR_CARDOWNED) { - /* nothing in the descriptor yet */ - result=0; - goto out; - } - - if (status == SPIDER_NET_DESCR_NOT_IN_USE) { - /* not initialized yet, the ring must be empty */ - spider_net_refill_rx_chain(card); - spider_net_enable_rxdmac(card); - result=0; - goto out; - } + /* Nothing in the descriptor, or ring must be empty */ + if ((status == SPIDER_NET_DESCR_CARDOWNED) || + (status == SPIDER_NET_DESCR_NOT_IN_USE)) + return 0; /* descriptor definitively used -- move on tail */ chain->tail = descr->next; - result = 0; + /* unmap descriptor */ + pci_unmap_single(card->pdev, descr->buf_addr, + SPIDER_NET_MAX_FRAME, PCI_DMA_FROMDEVICE); + if ( (status == SPIDER_NET_DESCR_RESPONSE_ERROR) || (status == SPIDER_NET_DESCR_PROTECTION_ERROR) || (status == SPIDER_NET_DESCR_FORCE_END) ) { @@ -1035,31 +1031,55 @@ spider_net_decode_one_descr(struct spide pr_err("%s: dropping RX descriptor with state %d\n", card->netdev->name, status); card->netdev_stats.rx_dropped++; - pci_unmap_single(card->pdev, descr->buf_addr, - SPIDER_NET_MAX_FRAME, PCI_DMA_FROMDEVICE); - dev_kfree_skb_irq(descr->skb); - goto refill; + goto bad_desc; } if ( (status != SPIDER_NET_DESCR_COMPLETE) && (status != SPIDER_NET_DESCR_FRAME_END) ) { - if (netif_msg_rx_err(card)) { - pr_err("%s: RX descriptor with state %d\n", + if (netif_msg_rx_err(card)) + pr_err("%s: RX descriptor with unkown state %d\n", card->netdev->name, status); - card->spider_stats.rx_desc_unk_state++; - } - goto refill; + card->spider_stats.rx_desc_unk_state++; + goto bad_desc; } - /* ok, we've got a packet in descr */ - result = spider_net_pass_skb_up(descr, card, napi); -refill: + /* The cases we'll throw away the packet immediately */ + if (descr->data_error & SPIDER_NET_DESTROY_RX_FLAGS) { + if (netif_msg_rx_err(card)) + pr_err("%s: error in received descriptor found, " + "data_status=x%08x, data_error=x%08x\n", + card->netdev->name, + descr->data_status, descr->data_error); + goto bad_desc; + } + + if (descr->dmac_cmd_status & 0xfefe) { + pr_err("%s: bad status, cmd_status=x%08x\n", + card->netdev->name, + descr->dmac_cmd_status); + pr_err("buf_addr=x%08x\n", descr->buf_addr); + pr_err("buf_size=x%08x\n", descr->buf_size); + pr_err("next_descr_addr=x%08x\n", descr->next_descr_addr); + pr_err("result_size=x%08x\n", descr->result_size); + pr_err("valid_size=x%08x\n", descr->valid_size); + pr_err("data_status=x%08x\n", descr->data_status); + pr_err("data_error=x%08x\n", descr->data_error); + pr_err("bus_addr=x%08x\n", descr->bus_addr); + pr_err("which=%ld\n", descr - card->rx_chain.ring); + + card->spider_stats.rx_desc_error++; + goto bad_desc; + } + + /* Ok, we've got a packet in descr */ + spider_net_pass_skb_up(descr, card); descr->dmac_cmd_status = SPIDER_NET_DESCR_NOT_IN_USE; - /* change the descriptor state: */ - if (!napi) - spider_net_refill_rx_chain(card); -out: - return result; + return 1; + +bad_desc: + dev_kfree_skb_irq(descr->skb); + descr->dmac_cmd_status = SPIDER_NET_DESCR_NOT_IN_USE; + return 0; } /** @@ -1085,7 +1105,7 @@ spider_net_poll(struct net_device *netde packets_to_do = min(*budget, netdev->quota); while (packets_to_do) { - if (spider_net_decode_one_descr(card, 1)) { + if (spider_net_decode_one_descr(card)) { packets_done++; packets_to_do--; } else { @@ -1098,6 +1118,7 @@ spider_net_poll(struct net_device *netde netdev->quota -= packets_done; *budget -= packets_done; spider_net_refill_rx_chain(card); + spider_net_enable_rxdmac(card); /* if all packets are in the stack, enable interrupts and return 0 */ /* if not, return 1 */ @@ -1227,24 +1248,6 @@ spider_net_set_mac(struct net_device *ne } /** - * spider_net_handle_rxram_full - cleans up RX ring upon RX RAM full interrupt - * @card: card structure - * - * spider_net_handle_rxram_full empties the RX ring so that spider can put - * more packets in it and empty its RX RAM. This is called in bottom half - * context - */ -static void -spider_net_handle_rxram_full(struct spider_net_card *card) -{ - while (spider_net_decode_one_descr(card, 0)) - ; - spider_net_enable_rxchtails(card); - spider_net_enable_rxdmac(card); - netif_rx_schedule(card->netdev); -} - -/** * spider_net_handle_error_irq - handles errors raised by an interrupt * @card: card structure * @status_reg: interrupt status register 0 (GHIINT0STS) @@ -1366,10 +1369,10 @@ spider_net_handle_error_irq(struct spide case SPIDER_NET_GRFAFLLINT: /* fallthrough */ case SPIDER_NET_GRMFLLINT: if (netif_msg_intr(card) && net_ratelimit()) - pr_debug("Spider RX RAM full, incoming packets " + pr_err("Spider RX RAM full, incoming packets " "might be discarded!\n"); spider_net_rx_irq_off(card); - tasklet_schedule(&card->rxram_full_tl); + netif_rx_schedule(card->netdev); show_error = 0; break; @@ -1384,7 +1387,7 @@ spider_net_handle_error_irq(struct spide case SPIDER_NET_GDCDCEINT: /* fallthrough */ case SPIDER_NET_GDBDCEINT: /* fallthrough */ case SPIDER_NET_GDADCEINT: - if (netif_msg_intr(card)) + if (netif_msg_intr(card) && net_ratelimit()) pr_err("got descriptor chain end interrupt, " "restarting DMAC %c.\n", 'D'-(i-SPIDER_NET_GDDDCEINT)/3); @@ -1455,7 +1458,7 @@ spider_net_handle_error_irq(struct spide break; } - if ((show_error) && (netif_msg_intr(card))) + if ((show_error) && (netif_msg_intr(card)) && net_ratelimit()) pr_err("Got error interrupt on %s, GHIINT0STS = 0x%08x, " "GHIINT1STS = 0x%08x, GHIINT2STS = 0x%08x\n", card->netdev->name, @@ -1651,27 +1654,18 @@ int spider_net_open(struct net_device *netdev) { struct spider_net_card *card = netdev_priv(netdev); - struct spider_net_descr *descr; - int i, result; + int result; - result = -ENOMEM; - if (spider_net_init_chain(card, &card->tx_chain, card->descr, - card->num_tx_desc)) + result = spider_net_init_chain(card, &card->tx_chain); + if (result) goto alloc_tx_failed; - card->low_watermark = NULL; - /* rx_chain is after tx_chain, so offset is descr + tx_count */ - if (spider_net_init_chain(card, &card->rx_chain, - card->descr + card->num_tx_desc, - card->num_rx_desc)) + result = spider_net_init_chain(card, &card->rx_chain); + if (result) goto alloc_rx_failed; - descr = card->rx_chain.head; - for (i=0; i < card->num_rx_desc; i++, descr++) - descr->next_descr_addr = descr->next->bus_addr; - - /* allocate rx skbs */ + /* Allocate rx skbs */ if (spider_net_alloc_rx_skbs(card)) goto alloc_skbs_failed; @@ -1902,7 +1896,6 @@ spider_net_stop(struct net_device *netde { struct spider_net_card *card = netdev_priv(netdev); - tasklet_kill(&card->rxram_full_tl); netif_poll_disable(netdev); netif_carrier_off(netdev); netif_stop_queue(netdev); @@ -1914,7 +1907,7 @@ spider_net_stop(struct net_device *netde spider_net_write_reg(card, SPIDER_NET_GHIINT2MSK, 0); /* free_irq(netdev->irq, netdev);*/ - free_irq(to_pci_dev(netdev->class_dev.dev)->irq, netdev); + free_irq(to_pci_dev(netdev->dev.parent)->irq, netdev); spider_net_write_reg(card, SPIDER_NET_GDTDMACCNTR, SPIDER_NET_DMA_TX_FEND_VALUE); @@ -1924,6 +1917,7 @@ spider_net_stop(struct net_device *netde /* release chains */ spider_net_release_tx_chain(card, 1); + spider_net_free_rx_chain_contents(card); spider_net_free_rx_chain_contents(card); @@ -2046,9 +2040,6 @@ spider_net_setup_netdev(struct spider_ne pci_set_drvdata(card->pdev, netdev); - card->rxram_full_tl.data = (unsigned long) card; - card->rxram_full_tl.func = - (void (*)(unsigned long)) spider_net_handle_rxram_full; init_timer(&card->tx_timer); card->tx_timer.function = (void (*)(unsigned long)) spider_net_cleanup_tx_ring; @@ -2057,8 +2048,8 @@ spider_net_setup_netdev(struct spider_ne card->options.rx_csum = SPIDER_NET_RX_CSUM_DEFAULT; - card->num_tx_desc = tx_descriptors; - card->num_rx_desc = rx_descriptors; + card->tx_chain.num_desc = tx_descriptors; + card->rx_chain.num_desc = rx_descriptors; spider_net_setup_netdev_ops(netdev); @@ -2107,12 +2098,8 @@ spider_net_alloc_card(void) { struct net_device *netdev; struct spider_net_card *card; - size_t alloc_size; - alloc_size = sizeof (*card) + - sizeof (struct spider_net_descr) * rx_descriptors + - sizeof (struct spider_net_descr) * tx_descriptors; - netdev = alloc_etherdev(alloc_size); + netdev = alloc_etherdev(sizeof(struct spider_net_card)); if (!netdev) return NULL; diff --git a/drivers/net/spider_net.h b/drivers/net/spider_net.h index 3e196df..2fec5cf 100644 --- a/drivers/net/spider_net.h +++ b/drivers/net/spider_net.h @@ -24,7 +24,7 @@ #ifndef _SPIDER_NET_H #define _SPIDER_NET_H -#define VERSION "1.6 A" +#define VERSION "1.6 B" #include "sungem_phy.h" @@ -378,6 +378,9 @@ struct spider_net_descr_chain { spinlock_t lock; struct spider_net_descr *head; struct spider_net_descr *tail; + struct spider_net_descr *ring; + int num_desc; + dma_addr_t dma_addr; }; /* descriptor data_status bits */ @@ -397,8 +400,6 @@ #define SPIDER_NET_DATA_ERR_CKSUM_MASK ( * 701b8000 would be correct, but every packets gets that flag */ #define SPIDER_NET_DESTROY_RX_FLAGS 0x700b8000 -#define SPIDER_NET_DESCR_SIZE 32 - /* this will be bigger some time */ struct spider_net_options { int rx_csum; /* for rx: if 0 ip_summed=NONE, @@ -441,25 +442,16 @@ struct spider_net_card { struct spider_net_descr_chain rx_chain; struct spider_net_descr *low_watermark; - struct net_device_stats netdev_stats; - - struct spider_net_options options; - - spinlock_t intmask_lock; - struct tasklet_struct rxram_full_tl; struct timer_list tx_timer; - struct work_struct tx_timeout_task; atomic_t tx_timeout_task_counter; wait_queue_head_t waitq; /* for ethtool */ int msg_enable; - int num_rx_desc; - int num_tx_desc; + struct net_device_stats netdev_stats; struct spider_net_extra_stats spider_stats; - - struct spider_net_descr descr[0]; + struct spider_net_options options; }; #define pr_err(fmt,arg...) \ diff --git a/drivers/net/spider_net_ethtool.c b/drivers/net/spider_net_ethtool.c index 91b9951..6bcf03f 100644 --- a/drivers/net/spider_net_ethtool.c +++ b/drivers/net/spider_net_ethtool.c @@ -158,9 +158,9 @@ spider_net_ethtool_get_ringparam(struct struct spider_net_card *card = netdev->priv; ering->tx_max_pending = SPIDER_NET_TX_DESCRIPTORS_MAX; - ering->tx_pending = card->num_tx_desc; + ering->tx_pending = card->tx_chain.num_desc; ering->rx_max_pending = SPIDER_NET_RX_DESCRIPTORS_MAX; - ering->rx_pending = card->num_rx_desc; + ering->rx_pending = card->rx_chain.num_desc; } static int spider_net_get_stats_count(struct net_device *netdev) diff --git a/drivers/net/sungem_phy.c b/drivers/net/sungem_phy.c index d21991e..701ba4f 100644 --- a/drivers/net/sungem_phy.c +++ b/drivers/net/sungem_phy.c @@ -22,7 +22,6 @@ #include #include -#include #include #include #include diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c index f4bf62c..81a1c2e 100644 --- a/drivers/net/tg3.c +++ b/drivers/net/tg3.c @@ -4,7 +4,7 @@ * Copyright (C) 2001, 2002, 2003, 2004 David S. Miller (davem@redhat.com) * Copyright (C) 2001, 2002, 2003 Jeff Garzik (jgarzik@pobox.com) * Copyright (C) 2004 Sun Microsystems Inc. - * Copyright (C) 2005 Broadcom Corporation. + * Copyright (C) 2005-2007 Broadcom Corporation. * * Firmware is: * Derived from proprietary unpublished source code, @@ -58,18 +58,14 @@ #else #define TG3_VLAN_TAG_USED 0 #endif -#ifdef NETIF_F_TSO #define TG3_TSO_SUPPORT 1 -#else -#define TG3_TSO_SUPPORT 0 -#endif #include "tg3.h" #define DRV_MODULE_NAME "tg3" #define PFX DRV_MODULE_NAME ": " -#define DRV_MODULE_VERSION "3.72" -#define DRV_MODULE_RELDATE "January 8, 2007" +#define DRV_MODULE_VERSION "3.73" +#define DRV_MODULE_RELDATE "February 12, 2007" #define TG3_DEF_MAC_MODE 0 #define TG3_DEF_RX_MODE 0 @@ -1179,8 +1175,18 @@ static void tg3_nvram_unlock(struct tg3 static void tg3_power_down_phy(struct tg3 *tp) { - if (tp->tg3_flags2 & TG3_FLG2_PHY_SERDES) + if (tp->tg3_flags2 & TG3_FLG2_PHY_SERDES) { + if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5704) { + u32 sg_dig_ctrl = tr32(SG_DIG_CTRL); + u32 serdes_cfg = tr32(MAC_SERDES_CFG); + + sg_dig_ctrl |= + SG_DIG_USING_HW_AUTONEG | SG_DIG_SOFT_RESET; + tw32(SG_DIG_CTRL, sg_dig_ctrl); + tw32(MAC_SERDES_CFG, serdes_cfg | (1 << 15)); + } return; + } if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5906) { u32 val; @@ -1344,7 +1350,8 @@ static int tg3_set_power_state(struct tg tw32_wait_f(TG3PCI_CLOCK_CTRL, base_val | CLOCK_CTRL_ALTCLK | CLOCK_CTRL_PWRDOWN_PLL133, 40); - } else if (tp->tg3_flags2 & TG3_FLG2_5780_CLASS) { + } else if ((tp->tg3_flags2 & TG3_FLG2_5780_CLASS) || + (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5906)) { /* do nothing */ } else if (!((tp->tg3_flags2 & TG3_FLG2_5750_PLUS) && (tp->tg3_flags & TG3_FLAG_ENABLE_ASF))) { @@ -3384,7 +3391,7 @@ next_pkt: } next_pkt_nopost: sw_idx++; - sw_idx %= TG3_RX_RCB_RING_SIZE(tp); + sw_idx &= (TG3_RX_RCB_RING_SIZE(tp) - 1); /* Refresh hw_idx to see if there is new work */ if (sw_idx == hw_idx) { @@ -3728,13 +3735,23 @@ out: tg3_full_unlock(tp); } +static void tg3_dump_short_state(struct tg3 *tp) +{ + printk(KERN_ERR PFX "DEBUG: MAC_TX_STATUS[%08x] MAC_RX_STATUS[%08x]\n", + tr32(MAC_TX_STATUS), tr32(MAC_RX_STATUS)); + printk(KERN_ERR PFX "DEBUG: RDMAC_STATUS[%08x] WDMAC_STATUS[%08x]\n", + tr32(RDMAC_STATUS), tr32(WDMAC_STATUS)); +} + static void tg3_tx_timeout(struct net_device *dev) { struct tg3 *tp = netdev_priv(dev); - if (netif_msg_tx_err(tp)) + if (netif_msg_tx_err(tp)) { printk(KERN_ERR PFX "%s: transmit timed out, resetting\n", dev->name); + tg3_dump_short_state(tp); + } schedule_work(&tp->reset_task); } @@ -3873,7 +3890,6 @@ static int tg3_start_xmit(struct sk_buff entry = tp->tx_prod; base_flags = 0; -#if TG3_TSO_SUPPORT != 0 mss = 0; if (skb->len > (tp->dev->mtu + ETH_HLEN) && (mss = skb_shinfo(skb)->gso_size) != 0) { @@ -3906,11 +3922,6 @@ #if TG3_TSO_SUPPORT != 0 } else if (skb->ip_summed == CHECKSUM_PARTIAL) base_flags |= TXD_FLAG_TCPUDP_CSUM; -#else - mss = 0; - if (skb->ip_summed == CHECKSUM_PARTIAL) - base_flags |= TXD_FLAG_TCPUDP_CSUM; -#endif #if TG3_VLAN_TAG_USED if (tp->vlgrp != NULL && vlan_tx_tag_present(skb)) base_flags |= (TXD_FLAG_VLAN | @@ -3970,7 +3981,6 @@ out_unlock: return NETDEV_TX_OK; } -#if TG3_TSO_SUPPORT != 0 static int tg3_start_xmit_dma_bug(struct sk_buff *, struct net_device *); /* Use GSO to workaround a rare TSO bug that may be triggered when the @@ -4002,7 +4012,6 @@ tg3_tso_bug_end: return NETDEV_TX_OK; } -#endif /* hard_start_xmit for devices that have the 4G bug and/or 40-bit bug and * support TG3_FLG2_HW_TSO_1 or firmware TSO only. @@ -4036,7 +4045,6 @@ static int tg3_start_xmit_dma_bug(struct base_flags = 0; if (skb->ip_summed == CHECKSUM_PARTIAL) base_flags |= TXD_FLAG_TCPUDP_CSUM; -#if TG3_TSO_SUPPORT != 0 mss = 0; if (skb->len > (tp->dev->mtu + ETH_HLEN) && (mss = skb_shinfo(skb)->gso_size) != 0) { @@ -4091,9 +4099,6 @@ #if TG3_TSO_SUPPORT != 0 } } } -#else - mss = 0; -#endif #if TG3_VLAN_TAG_USED if (tp->vlgrp != NULL && vlan_tx_tag_present(skb)) base_flags |= (TXD_FLAG_VLAN | @@ -5329,7 +5334,6 @@ static int tg3_load_5701_a0_firmware_fix return 0; } -#if TG3_TSO_SUPPORT != 0 #define TG3_TSO_FW_RELEASE_MAJOR 0x1 #define TG3_TSO_FW_RELASE_MINOR 0x6 @@ -5906,7 +5910,6 @@ static int tg3_load_tso_firmware(struct return 0; } -#endif /* TG3_TSO_SUPPORT != 0 */ /* tp->lock is held. */ static void __tg3_set_mac_addr(struct tg3 *tp) @@ -6120,7 +6123,6 @@ static int tg3_reset_hw(struct tg3 *tp, tw32(BUFMGR_DMA_DESC_POOL_ADDR, NIC_SRAM_DMA_DESC_POOL_BASE); tw32(BUFMGR_DMA_DESC_POOL_SIZE, NIC_SRAM_DMA_DESC_POOL_SIZE); } -#if TG3_TSO_SUPPORT != 0 else if (tp->tg3_flags2 & TG3_FLG2_TSO_CAPABLE) { int fw_len; @@ -6135,7 +6137,6 @@ #if TG3_TSO_SUPPORT != 0 tw32(BUFMGR_MB_POOL_SIZE, NIC_SRAM_MBUF_POOL_SIZE5705 - fw_len - 0xa00); } -#endif if (tp->dev->mtu <= ETH_DATA_LEN) { tw32(BUFMGR_MB_RDMA_LOW_WATER, @@ -6337,10 +6338,8 @@ #endif if (tp->tg3_flags2 & TG3_FLG2_PCI_EXPRESS) rdmac_mode |= RDMAC_MODE_FIFO_LONG_BURST; -#if TG3_TSO_SUPPORT != 0 if (tp->tg3_flags2 & TG3_FLG2_HW_TSO) rdmac_mode |= (1 << 27); -#endif /* Receive/send statistics. */ if (tp->tg3_flags2 & TG3_FLG2_5750_PLUS) { @@ -6511,10 +6510,8 @@ #endif tw32(RCVBDI_MODE, RCVBDI_MODE_ENABLE | RCVBDI_MODE_RCB_ATTN_ENAB); tw32(RCVDBDI_MODE, RCVDBDI_MODE_ENABLE | RCVDBDI_MODE_INV_RING_SZ); tw32(SNDDATAI_MODE, SNDDATAI_MODE_ENABLE); -#if TG3_TSO_SUPPORT != 0 if (tp->tg3_flags2 & TG3_FLG2_HW_TSO) tw32(SNDDATAI_MODE, SNDDATAI_MODE_ENABLE | 0x8); -#endif tw32(SNDBDI_MODE, SNDBDI_MODE_ENABLE | SNDBDI_MODE_ATTN_ENABLE); tw32(SNDBDS_MODE, SNDBDS_MODE_ENABLE | SNDBDS_MODE_ATTN_ENABLE); @@ -6524,13 +6521,11 @@ #endif return err; } -#if TG3_TSO_SUPPORT != 0 if (tp->tg3_flags2 & TG3_FLG2_TSO_CAPABLE) { err = tg3_load_tso_firmware(tp); if (err) return err; } -#endif tp->tx_mode = TX_MODE_ENABLE; tw32_f(MAC_TX_MODE, tp->tx_mode); @@ -6609,8 +6604,9 @@ #endif u32 tmp; /* Clear CRC stats. */ - if (!tg3_readphy(tp, 0x1e, &tmp)) { - tg3_writephy(tp, 0x1e, tmp | 0x8000); + if (!tg3_readphy(tp, MII_TG3_TEST1, &tmp)) { + tg3_writephy(tp, MII_TG3_TEST1, + tmp | MII_TG3_TEST1_CRC_EN); tg3_readphy(tp, 0x14, &tmp); } } @@ -7434,8 +7430,9 @@ static unsigned long calc_crc_errors(str u32 val; spin_lock_bh(&tp->lock); - if (!tg3_readphy(tp, 0x1e, &val)) { - tg3_writephy(tp, 0x1e, val | 0x8000); + if (!tg3_readphy(tp, MII_TG3_TEST1, &val)) { + tg3_writephy(tp, MII_TG3_TEST1, + val | MII_TG3_TEST1_CRC_EN); tg3_readphy(tp, 0x14, &val); } else val = 0; @@ -8062,7 +8059,6 @@ static void tg3_set_msglevel(struct net_ tp->msg_enable = value; } -#if TG3_TSO_SUPPORT != 0 static int tg3_set_tso(struct net_device *dev, u32 value) { struct tg3 *tp = netdev_priv(dev); @@ -8081,7 +8077,6 @@ static int tg3_set_tso(struct net_device } return ethtool_op_set_tso(dev, value); } -#endif static int tg3_nway_reset(struct net_device *dev) { @@ -9212,10 +9207,8 @@ static const struct ethtool_ops tg3_etht .set_tx_csum = tg3_set_tx_csum, .get_sg = ethtool_op_get_sg, .set_sg = ethtool_op_set_sg, -#if TG3_TSO_SUPPORT != 0 .get_tso = ethtool_op_get_tso, .set_tso = tg3_set_tso, -#endif .self_test_count = tg3_get_test_count, .self_test = tg3_self_test, .get_strings = tg3_get_strings, @@ -10809,7 +10802,9 @@ static int __devinit tg3_get_invariants( if (tp->tg3_flags2 & TG3_FLG2_5705_PLUS) { if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5755 || GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5787) { - tp->tg3_flags2 |= TG3_FLG2_PHY_JITTER_BUG; + if (tp->pdev->device != PCI_DEVICE_ID_TIGON3_5756 && + tp->pdev->device != PCI_DEVICE_ID_TIGON3_5722) + tp->tg3_flags2 |= TG3_FLG2_PHY_JITTER_BUG; if (tp->pdev->device == PCI_DEVICE_ID_TIGON3_5755M) tp->tg3_flags2 |= TG3_FLG2_PHY_ADJUST_TRIM; } else if (GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5906) @@ -11344,6 +11339,7 @@ static int __devinit tg3_test_dma(struct if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5703 || GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5704) { u32 ccval = (tr32(TG3PCI_CLOCK_CTRL) & 0x1f); + u32 read_water = 0x7; /* If the 5704 is behind the EPB bridge, we can * do the less restrictive ONE_DMA workaround for @@ -11355,8 +11351,13 @@ static int __devinit tg3_test_dma(struct else if (ccval == 0x6 || ccval == 0x7) tp->dma_rwctrl |= DMA_RWCTRL_ONE_DMA; + if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5703) + read_water = 4; /* Set bit 23 to enable PCIX hw bug fix */ - tp->dma_rwctrl |= 0x009f0000; + tp->dma_rwctrl |= + (read_water << DMA_RWCTRL_READ_WATER_SHIFT) | + (0x3 << DMA_RWCTRL_WRITE_WATER_SHIFT) | + (1 << 23); } else if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5780) { /* 5780 always in PCIX mode */ tp->dma_rwctrl |= 0x00144000; @@ -11856,7 +11857,6 @@ #endif tg3_init_bufmgr_config(tp); -#if TG3_TSO_SUPPORT != 0 if (tp->tg3_flags2 & TG3_FLG2_HW_TSO) { tp->tg3_flags2 |= TG3_FLG2_TSO_CAPABLE; } @@ -11881,7 +11881,6 @@ #if TG3_TSO_SUPPORT != 0 dev->features |= NETIF_F_TSO6; } -#endif if (tp->pci_chip_rev_id == CHIPREV_ID_5705_A1 && !(tp->tg3_flags2 & TG3_FLG2_TSO_CAPABLE) && @@ -12048,6 +12047,9 @@ static int tg3_suspend(struct pci_dev *p tp->tg3_flags &= ~TG3_FLAG_INIT_COMPLETE; tg3_full_unlock(tp); + /* Save MSI address and data for resume. */ + pci_save_state(pdev); + err = tg3_set_power_state(tp, pci_choose_state(pdev, state)); if (err) { tg3_full_lock(tp, 0); diff --git a/drivers/net/tg3.h b/drivers/net/tg3.h index 80f59ac..45d477e 100644 --- a/drivers/net/tg3.h +++ b/drivers/net/tg3.h @@ -1660,6 +1660,7 @@ #define MII_TG3_EPHY_SHADOW_EN 0x80 #define MII_TG3_TEST1 0x1e #define MII_TG3_TEST1_TRIM_EN 0x0010 +#define MII_TG3_TEST1_CRC_EN 0x8000 /* There are two ways to manage the TX descriptors on the tigon3. * Either the descriptors are in host DMA'able memory, or they diff --git a/drivers/net/tsi108_eth.c b/drivers/net/tsi108_eth.c index 893808a..d92c5c5 100644 --- a/drivers/net/tsi108_eth.c +++ b/drivers/net/tsi108_eth.c @@ -38,7 +38,6 @@ #include #include #include #include -#include #include #include #include diff --git a/drivers/net/tun.c b/drivers/net/tun.c index 151a2e1..5643d1e 100644 --- a/drivers/net/tun.c +++ b/drivers/net/tun.c @@ -744,7 +744,7 @@ static int tun_chr_close(struct inode *i return 0; } -static struct file_operations tun_fops = { +static const struct file_operations tun_fops = { .owner = THIS_MODULE, .llseek = no_llseek, .read = do_sync_read, diff --git a/drivers/net/ucc_geth.c b/drivers/net/ucc_geth.c index 7e4b23c..a2fc2bb 100644 --- a/drivers/net/ucc_geth.c +++ b/drivers/net/ucc_geth.c @@ -1709,75 +1709,13 @@ static void adjust_link(struct net_devic if (mii_info->speed != ugeth->oldspeed) { switch (mii_info->speed) { case 1000: -#ifdef CONFIG_PPC_MPC836x -/* FIXME: This code is for 100Mbs BUG fixing, -remove this when it is fixed!!! */ - if (ugeth->ug_info->enet_interface == - ENET_1000_GMII) - /* Run the commands which initialize the PHY */ - { - tempval = - (u32) mii_info->mdio_read(ugeth-> - dev, mii_info->mii_id, 0x1b); - tempval |= 0x000f; - mii_info->mdio_write(ugeth->dev, - mii_info->mii_id, 0x1b, - (u16) tempval); - tempval = - (u32) mii_info->mdio_read(ugeth-> - dev, mii_info->mii_id, - MII_BMCR); - mii_info->mdio_write(ugeth->dev, - mii_info->mii_id, MII_BMCR, - (u16) (tempval | BMCR_RESET)); - } else if (ugeth->ug_info->enet_interface == - ENET_1000_RGMII) - /* Run the commands which initialize the PHY */ - { - tempval = - (u32) mii_info->mdio_read(ugeth-> - dev, mii_info->mii_id, 0x1b); - tempval = (tempval & ~0x000f) | 0x000b; - mii_info->mdio_write(ugeth->dev, - mii_info->mii_id, 0x1b, - (u16) tempval); - tempval = - (u32) mii_info->mdio_read(ugeth-> - dev, mii_info->mii_id, - MII_BMCR); - mii_info->mdio_write(ugeth->dev, - mii_info->mii_id, MII_BMCR, - (u16) (tempval | BMCR_RESET)); - } - msleep(4000); -#endif /* CONFIG_MPC8360 */ - adjust_enet_interface(ugeth); + ugeth->ug_info->enet_interface = ENET_1000_RGMII; break; case 100: - case 10: -#ifdef CONFIG_PPC_MPC836x -/* FIXME: This code is for 100Mbs BUG fixing, -remove this lines when it will be fixed!!! */ ugeth->ug_info->enet_interface = ENET_100_RGMII; - tempval = - (u32) mii_info->mdio_read(ugeth->dev, - mii_info->mii_id, - 0x1b); - tempval = (tempval & ~0x000f) | 0x000b; - mii_info->mdio_write(ugeth->dev, - mii_info->mii_id, 0x1b, - (u16) tempval); - tempval = - (u32) mii_info->mdio_read(ugeth->dev, - mii_info->mii_id, - MII_BMCR); - mii_info->mdio_write(ugeth->dev, - mii_info->mii_id, MII_BMCR, - (u16) (tempval | - BMCR_RESET)); - msleep(4000); -#endif /* CONFIG_MPC8360 */ - adjust_enet_interface(ugeth); + break; + case 10: + ugeth->ug_info->enet_interface = ENET_10_RGMII; break; default: ugeth_warn @@ -1785,6 +1723,7 @@ #endif /* CONFIG_MPC8360 */ dev->name, mii_info->speed); break; } + adjust_enet_interface(ugeth); ugeth_info("%s: Speed %dBT", dev->name, mii_info->speed); @@ -2865,8 +2804,8 @@ static int ucc_geth_startup(struct ucc_g if (UCC_GETH_TX_BD_RING_ALIGNMENT > 4) align = UCC_GETH_TX_BD_RING_ALIGNMENT; ugeth->tx_bd_ring_offset[j] = - (u32) (kmalloc((u32) (length + align), - GFP_KERNEL)); + kmalloc((u32) (length + align), GFP_KERNEL); + if (ugeth->tx_bd_ring_offset[j] != 0) ugeth->p_tx_bd_ring[j] = (void*)((ugeth->tx_bd_ring_offset[j] + @@ -2901,7 +2840,7 @@ static int ucc_geth_startup(struct ucc_g if (UCC_GETH_RX_BD_RING_ALIGNMENT > 4) align = UCC_GETH_RX_BD_RING_ALIGNMENT; ugeth->rx_bd_ring_offset[j] = - (u32) (kmalloc((u32) (length + align), GFP_KERNEL)); + kmalloc((u32) (length + align), GFP_KERNEL); if (ugeth->rx_bd_ring_offset[j] != 0) ugeth->p_rx_bd_ring[j] = (void*)((ugeth->rx_bd_ring_offset[j] + @@ -2927,10 +2866,9 @@ static int ucc_geth_startup(struct ucc_g /* Init Tx bds */ for (j = 0; j < ug_info->numQueuesTx; j++) { /* Setup the skbuff rings */ - ugeth->tx_skbuff[j] = - (struct sk_buff **)kmalloc(sizeof(struct sk_buff *) * - ugeth->ug_info->bdRingLenTx[j], - GFP_KERNEL); + ugeth->tx_skbuff[j] = kmalloc(sizeof(struct sk_buff *) * + ugeth->ug_info->bdRingLenTx[j], + GFP_KERNEL); if (ugeth->tx_skbuff[j] == NULL) { ugeth_err("%s: Could not allocate tx_skbuff", @@ -2959,10 +2897,9 @@ static int ucc_geth_startup(struct ucc_g /* Init Rx bds */ for (j = 0; j < ug_info->numQueuesRx; j++) { /* Setup the skbuff rings */ - ugeth->rx_skbuff[j] = - (struct sk_buff **)kmalloc(sizeof(struct sk_buff *) * - ugeth->ug_info->bdRingLenRx[j], - GFP_KERNEL); + ugeth->rx_skbuff[j] = kmalloc(sizeof(struct sk_buff *) * + ugeth->ug_info->bdRingLenRx[j], + GFP_KERNEL); if (ugeth->rx_skbuff[j] == NULL) { ugeth_err("%s: Could not allocate rx_skbuff", @@ -3453,8 +3390,7 @@ static int ucc_geth_startup(struct ucc_g * allocated resources can be released when the channel is freed. */ if (!(ugeth->p_init_enet_param_shadow = - (struct ucc_geth_init_pram *) kmalloc(sizeof(struct ucc_geth_init_pram), - GFP_KERNEL))) { + kmalloc(sizeof(struct ucc_geth_init_pram), GFP_KERNEL))) { ugeth_err ("%s: Can not allocate memory for" " p_UccInitEnetParamShadows.", __FUNCTION__); @@ -4003,8 +3939,8 @@ static void ugeth_phy_startup_timer(unsi /* Grab the PHY interrupt, if necessary/possible */ if (ugeth->ug_info->board_flags & FSL_UGETH_BRD_HAS_PHY_INTR) { if (request_irq(ugeth->ug_info->phy_interrupt, - phy_interrupt, - SA_SHIRQ, "phy_interrupt", mii_info->dev) < 0) { + phy_interrupt, IRQF_SHARED, + "phy_interrupt", mii_info->dev) < 0) { ugeth_err("%s: Can't get IRQ %d (PHY)", mii_info->dev->name, ugeth->ug_info->phy_interrupt); @@ -4136,6 +4072,7 @@ static int ucc_geth_probe(struct of_devi static int mii_mng_configured = 0; const phandle *ph; const unsigned int *prop; + const void *mac_addr; ugeth_vdbg("%s: IN", __FUNCTION__); @@ -4261,7 +4198,12 @@ #endif /* CONFIG_UGETH_NAPI */ ugeth->ug_info = ug_info; ugeth->dev = dev; - memcpy(dev->dev_addr, get_property(np, "mac-address", NULL), 6); + + mac_addr = get_property(np, "mac-address", NULL); + if (mac_addr == NULL) + mac_addr = get_property(np, "local-mac-address", NULL); + if (mac_addr) + memcpy(dev->dev_addr, mac_addr, 6); return 0; } diff --git a/drivers/net/ucc_geth_phy.c b/drivers/net/ucc_geth_phy.c index 3c86592..9373d89 100644 --- a/drivers/net/ucc_geth_phy.c +++ b/drivers/net/ucc_geth_phy.c @@ -18,7 +18,6 @@ */ #include -#include #include #include #include @@ -376,6 +375,8 @@ static int marvell_init(struct ugeth_mii ugphy_vdbg("%s: IN", __FUNCTION__); ucc_geth_phy_write(mii_info, 0x14, 0x0cd2); + ucc_geth_phy_write(mii_info, 0x1b, + (ucc_geth_phy_read(mii_info, 0x1b) & ~0x000f) | 0x000b); ucc_geth_phy_write(mii_info, MII_BMCR, ucc_geth_phy_read(mii_info, MII_BMCR) | BMCR_RESET); msleep(4000); diff --git a/drivers/net/wan/Kconfig b/drivers/net/wan/Kconfig index 21f76f5..61708cf 100644 --- a/drivers/net/wan/Kconfig +++ b/drivers/net/wan/Kconfig @@ -235,6 +235,19 @@ comment "Cyclades-PC300 MLPPP support is comment "Refer to the file README.mlppp, provided by PC300 package." depends on WAN && HDLC && PC300 && (PPP=n || !PPP_MULTILINK || PPP_SYNC_TTY=n || !HDLC_PPP) +config PC300TOO + tristate "Cyclades PC300 RSV/X21 alternative support" + depends on HDLC && PCI + help + Alternative driver for PC300 RSV/X21 PCI cards made by + Cyclades, Inc. If you have such a card, say Y here and see + . + + To compile this as a module, choose M here: the module + will be called pc300too. + + If unsure, say N here. + config N2 tristate "SDL RISCom/N2 support" depends on HDLC && ISA @@ -344,17 +357,6 @@ config DLCI To compile this driver as a module, choose M here: the module will be called dlci. -config DLCI_COUNT - int "Max open DLCI" - depends on DLCI - default "24" - help - Maximal number of logical point-to-point frame relay connections - (the identifiers of which are called DCLIs) that the driver can - handle. - - The default is probably fine. - config DLCI_MAX int "Max DLCI per device" depends on DLCI diff --git a/drivers/net/wan/Makefile b/drivers/net/wan/Makefile index 83ec2c8..d61fef3 100644 --- a/drivers/net/wan/Makefile +++ b/drivers/net/wan/Makefile @@ -41,6 +41,7 @@ obj-$(CONFIG_N2) += n2.o obj-$(CONFIG_C101) += c101.o obj-$(CONFIG_WANXL) += wanxl.o obj-$(CONFIG_PCI200SYN) += pci200syn.o +obj-$(CONFIG_PC300TOO) += pc300too.o clean-files := wanxlfw.inc $(obj)/wanxl.o: $(obj)/wanxlfw.inc diff --git a/drivers/net/wan/cosa.c b/drivers/net/wan/cosa.c index 6c7dfb5..e91b5a8 100644 --- a/drivers/net/wan/cosa.c +++ b/drivers/net/wan/cosa.c @@ -311,7 +311,7 @@ #ifdef COSA_FASYNC_WORKING static int cosa_fasync(struct inode *inode, struct file *file, int on); #endif -static struct file_operations cosa_fops = { +static const struct file_operations cosa_fops = { .owner = THIS_MODULE, .llseek = no_llseek, .read = cosa_read, diff --git a/drivers/net/wan/cycx_drv.c b/drivers/net/wan/cycx_drv.c index e6d0057..d347d59 100644 --- a/drivers/net/wan/cycx_drv.c +++ b/drivers/net/wan/cycx_drv.c @@ -53,7 +53,6 @@ #include #include /* printk(), and other useful stuff */ #include /* offsetof(), etc. */ #include /* return codes */ -#include /* for jiffies, HZ, etc. */ #include /* API definitions */ #include /* CYCX firmware module definitions */ #include /* udelay, msleep_interruptible */ diff --git a/drivers/net/wan/hdlc.c b/drivers/net/wan/hdlc.c index db354e0..9040d7c 100644 --- a/drivers/net/wan/hdlc.c +++ b/drivers/net/wan/hdlc.c @@ -222,7 +222,7 @@ int hdlc_ioctl(struct net_device *dev, s return -EINVAL; } -void hdlc_setup(struct net_device *dev) +static void hdlc_setup(struct net_device *dev) { hdlc_device *hdlc = dev_to_hdlc(dev); @@ -325,7 +325,6 @@ MODULE_LICENSE("GPL v2"); EXPORT_SYMBOL(hdlc_open); EXPORT_SYMBOL(hdlc_close); EXPORT_SYMBOL(hdlc_ioctl); -EXPORT_SYMBOL(hdlc_setup); EXPORT_SYMBOL(alloc_hdlcdev); EXPORT_SYMBOL(unregister_hdlc_device); EXPORT_SYMBOL(register_hdlc_protocol); diff --git a/drivers/net/wan/pc300too.c b/drivers/net/wan/pc300too.c new file mode 100644 index 0000000..bc156b5 --- /dev/null +++ b/drivers/net/wan/pc300too.c @@ -0,0 +1,565 @@ +/* + * Cyclades PC300 synchronous serial card driver for Linux + * + * Copyright (C) 2000-2007 Krzysztof Halasa + * + * 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 published by the Free Software Foundation. + * + * For information see . + * + * Sources of information: + * Hitachi HD64572 SCA-II User's Manual + * Cyclades PC300 Linux driver + * + * This driver currently supports only PC300/RSV (V.24/V.35) and + * PC300/X21 cards. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "hd64572.h" + +static const char* version = "Cyclades PC300 driver version: 1.17"; +static const char* devname = "PC300"; + +#undef DEBUG_PKT +#define DEBUG_RINGS + +#define PC300_PLX_SIZE 0x80 /* PLX control window size (128 B) */ +#define PC300_SCA_SIZE 0x400 /* SCA window size (1 KB) */ +#define ALL_PAGES_ALWAYS_MAPPED +#define NEED_DETECT_RAM +#define NEED_SCA_MSCI_INTR +#define MAX_TX_BUFFERS 10 + +static int pci_clock_freq = 33000000; +static int use_crystal_clock = 0; +static unsigned int CLOCK_BASE; + +/* Masks to access the init_ctrl PLX register */ +#define PC300_CLKSEL_MASK (0x00000004UL) +#define PC300_CHMEDIA_MASK(port) (0x00000020UL << ((port) * 3)) +#define PC300_CTYPE_MASK (0x00000800UL) + + +enum { PC300_RSV = 1, PC300_X21, PC300_TE }; /* card types */ + +/* + * PLX PCI9050-1 local configuration and shared runtime registers. + * This structure can be used to access 9050 registers (memory mapped). + */ +typedef struct { + u32 loc_addr_range[4]; /* 00-0Ch : Local Address Ranges */ + u32 loc_rom_range; /* 10h : Local ROM Range */ + u32 loc_addr_base[4]; /* 14-20h : Local Address Base Addrs */ + u32 loc_rom_base; /* 24h : Local ROM Base */ + u32 loc_bus_descr[4]; /* 28-34h : Local Bus Descriptors */ + u32 rom_bus_descr; /* 38h : ROM Bus Descriptor */ + u32 cs_base[4]; /* 3C-48h : Chip Select Base Addrs */ + u32 intr_ctrl_stat; /* 4Ch : Interrupt Control/Status */ + u32 init_ctrl; /* 50h : EEPROM ctrl, Init Ctrl, etc */ +}plx9050; + + + +typedef struct port_s { + struct net_device *dev; + struct card_s *card; + spinlock_t lock; /* TX lock */ + sync_serial_settings settings; + int rxpart; /* partial frame received, next frame invalid*/ + unsigned short encoding; + unsigned short parity; + unsigned int iface; + u16 rxin; /* rx ring buffer 'in' pointer */ + u16 txin; /* tx ring buffer 'in' and 'last' pointers */ + u16 txlast; + u8 rxs, txs, tmc; /* SCA registers */ + u8 phy_node; /* physical port # - 0 or 1 */ +}port_t; + + + +typedef struct card_s { + int type; /* RSV, X21, etc. */ + int n_ports; /* 1 or 2 ports */ + u8 __iomem *rambase; /* buffer memory base (virtual) */ + u8 __iomem *scabase; /* SCA memory base (virtual) */ + plx9050 __iomem *plxbase; /* PLX registers memory base (virtual) */ + u32 init_ctrl_value; /* Saved value - 9050 bug workaround */ + u16 rx_ring_buffers; /* number of buffers in a ring */ + u16 tx_ring_buffers; + u16 buff_offset; /* offset of first buffer of first channel */ + u8 irq; /* interrupt request level */ + + port_t ports[2]; +}card_t; + + +#define sca_in(reg, card) readb(card->scabase + (reg)) +#define sca_out(value, reg, card) writeb(value, card->scabase + (reg)) +#define sca_inw(reg, card) readw(card->scabase + (reg)) +#define sca_outw(value, reg, card) writew(value, card->scabase + (reg)) +#define sca_inl(reg, card) readl(card->scabase + (reg)) +#define sca_outl(value, reg, card) writel(value, card->scabase + (reg)) + +#define port_to_card(port) (port->card) +#define log_node(port) (port->phy_node) +#define phy_node(port) (port->phy_node) +#define winbase(card) (card->rambase) +#define get_port(card, port) ((port) < (card)->n_ports ? \ + (&(card)->ports[port]) : (NULL)) + +#include "hd6457x.c" + + +static void pc300_set_iface(port_t *port) +{ + card_t *card = port->card; + u32 __iomem * init_ctrl = &card->plxbase->init_ctrl; + u16 msci = get_msci(port); + u8 rxs = port->rxs & CLK_BRG_MASK; + u8 txs = port->txs & CLK_BRG_MASK; + + sca_out(EXS_TES1, (phy_node(port) ? MSCI1_OFFSET : MSCI0_OFFSET) + EXS, + port_to_card(port)); + switch(port->settings.clock_type) { + case CLOCK_INT: + rxs |= CLK_BRG; /* BRG output */ + txs |= CLK_PIN_OUT | CLK_TX_RXCLK; /* RX clock */ + break; + + case CLOCK_TXINT: + rxs |= CLK_LINE; /* RXC input */ + txs |= CLK_PIN_OUT | CLK_BRG; /* BRG output */ + break; + + case CLOCK_TXFROMRX: + rxs |= CLK_LINE; /* RXC input */ + txs |= CLK_PIN_OUT | CLK_TX_RXCLK; /* RX clock */ + break; + + default: /* EXTernal clock */ + rxs |= CLK_LINE; /* RXC input */ + txs |= CLK_PIN_OUT | CLK_LINE; /* TXC input */ + break; + } + + port->rxs = rxs; + port->txs = txs; + sca_out(rxs, msci + RXS, card); + sca_out(txs, msci + TXS, card); + sca_set_port(port); + + if (port->card->type == PC300_RSV) { + if (port->iface == IF_IFACE_V35) + writel(card->init_ctrl_value | + PC300_CHMEDIA_MASK(port->phy_node), init_ctrl); + else + writel(card->init_ctrl_value & + ~PC300_CHMEDIA_MASK(port->phy_node), init_ctrl); + } +} + + + +static int pc300_open(struct net_device *dev) +{ + port_t *port = dev_to_port(dev); + + int result = hdlc_open(dev); + if (result) + return result; + + sca_open(dev); + pc300_set_iface(port); + return 0; +} + + + +static int pc300_close(struct net_device *dev) +{ + sca_close(dev); + hdlc_close(dev); + return 0; +} + + + +static int pc300_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) +{ + const size_t size = sizeof(sync_serial_settings); + sync_serial_settings new_line; + sync_serial_settings __user *line = ifr->ifr_settings.ifs_ifsu.sync; + int new_type; + port_t *port = dev_to_port(dev); + +#ifdef DEBUG_RINGS + if (cmd == SIOCDEVPRIVATE) { + sca_dump_rings(dev); + return 0; + } +#endif + if (cmd != SIOCWANDEV) + return hdlc_ioctl(dev, ifr, cmd); + + if (ifr->ifr_settings.type == IF_GET_IFACE) { + ifr->ifr_settings.type = port->iface; + if (ifr->ifr_settings.size < size) { + ifr->ifr_settings.size = size; /* data size wanted */ + return -ENOBUFS; + } + if (copy_to_user(line, &port->settings, size)) + return -EFAULT; + return 0; + + } + + if (port->card->type == PC300_X21 && + (ifr->ifr_settings.type == IF_IFACE_SYNC_SERIAL || + ifr->ifr_settings.type == IF_IFACE_X21)) + new_type = IF_IFACE_X21; + + else if (port->card->type == PC300_RSV && + (ifr->ifr_settings.type == IF_IFACE_SYNC_SERIAL || + ifr->ifr_settings.type == IF_IFACE_V35)) + new_type = IF_IFACE_V35; + + else if (port->card->type == PC300_RSV && + ifr->ifr_settings.type == IF_IFACE_V24) + new_type = IF_IFACE_V24; + + else + return hdlc_ioctl(dev, ifr, cmd); + + if (!capable(CAP_NET_ADMIN)) + return -EPERM; + + if (copy_from_user(&new_line, line, size)) + return -EFAULT; + + if (new_line.clock_type != CLOCK_EXT && + new_line.clock_type != CLOCK_TXFROMRX && + new_line.clock_type != CLOCK_INT && + new_line.clock_type != CLOCK_TXINT) + return -EINVAL; /* No such clock setting */ + + if (new_line.loopback != 0 && new_line.loopback != 1) + return -EINVAL; + + memcpy(&port->settings, &new_line, size); /* Update settings */ + port->iface = new_type; + pc300_set_iface(port); + return 0; +} + + + +static void pc300_pci_remove_one(struct pci_dev *pdev) +{ + int i; + card_t *card = pci_get_drvdata(pdev); + + for (i = 0; i < 2; i++) + if (card->ports[i].card) { + struct net_device *dev = port_to_dev(&card->ports[i]); + unregister_hdlc_device(dev); + } + + if (card->irq) + free_irq(card->irq, card); + + if (card->rambase) + iounmap(card->rambase); + if (card->scabase) + iounmap(card->scabase); + if (card->plxbase) + iounmap(card->plxbase); + + pci_release_regions(pdev); + pci_disable_device(pdev); + pci_set_drvdata(pdev, NULL); + if (card->ports[0].dev) + free_netdev(card->ports[0].dev); + if (card->ports[1].dev) + free_netdev(card->ports[1].dev); + kfree(card); +} + + + +static int __devinit pc300_pci_init_one(struct pci_dev *pdev, + const struct pci_device_id *ent) +{ + card_t *card; + u8 rev_id; + u32 __iomem *p; + int i; + u32 ramsize; + u32 ramphys; /* buffer memory base */ + u32 scaphys; /* SCA memory base */ + u32 plxphys; /* PLX registers memory base */ + +#ifndef MODULE + static int printed_version; + if (!printed_version++) + printk(KERN_INFO "%s\n", version); +#endif + + i = pci_enable_device(pdev); + if (i) + return i; + + i = pci_request_regions(pdev, "PC300"); + if (i) { + pci_disable_device(pdev); + return i; + } + + card = kmalloc(sizeof(card_t), GFP_KERNEL); + if (card == NULL) { + printk(KERN_ERR "pc300: unable to allocate memory\n"); + pci_release_regions(pdev); + pci_disable_device(pdev); + return -ENOBUFS; + } + memset(card, 0, sizeof(card_t)); + pci_set_drvdata(pdev, card); + + if (pdev->device == PCI_DEVICE_ID_PC300_TE_1 || + pdev->device == PCI_DEVICE_ID_PC300_TE_2) + card->type = PC300_TE; /* not fully supported */ + else if (card->init_ctrl_value & PC300_CTYPE_MASK) + card->type = PC300_X21; + else + card->type = PC300_RSV; + + if (pdev->device == PCI_DEVICE_ID_PC300_RX_1 || + pdev->device == PCI_DEVICE_ID_PC300_TE_1) + card->n_ports = 1; + else + card->n_ports = 2; + + for (i = 0; i < card->n_ports; i++) + if (!(card->ports[i].dev = alloc_hdlcdev(&card->ports[i]))) { + printk(KERN_ERR "pc300: unable to allocate memory\n"); + pc300_pci_remove_one(pdev); + return -ENOMEM; + } + + pci_read_config_byte(pdev, PCI_REVISION_ID, &rev_id); + if (pci_resource_len(pdev, 0) != PC300_PLX_SIZE || + pci_resource_len(pdev, 2) != PC300_SCA_SIZE || + pci_resource_len(pdev, 3) < 16384) { + printk(KERN_ERR "pc300: invalid card EEPROM parameters\n"); + pc300_pci_remove_one(pdev); + return -EFAULT; + } + + plxphys = pci_resource_start(pdev,0) & PCI_BASE_ADDRESS_MEM_MASK; + card->plxbase = ioremap(plxphys, PC300_PLX_SIZE); + + scaphys = pci_resource_start(pdev,2) & PCI_BASE_ADDRESS_MEM_MASK; + card->scabase = ioremap(scaphys, PC300_SCA_SIZE); + + ramphys = pci_resource_start(pdev,3) & PCI_BASE_ADDRESS_MEM_MASK; + card->rambase = ioremap(ramphys, pci_resource_len(pdev,3)); + + if (card->plxbase == NULL || + card->scabase == NULL || + card->rambase == NULL) { + printk(KERN_ERR "pc300: ioremap() failed\n"); + pc300_pci_remove_one(pdev); + } + + /* PLX PCI 9050 workaround for local configuration register read bug */ + pci_write_config_dword(pdev, PCI_BASE_ADDRESS_0, scaphys); + card->init_ctrl_value = readl(&((plx9050 __iomem *)card->scabase)->init_ctrl); + pci_write_config_dword(pdev, PCI_BASE_ADDRESS_0, plxphys); + + /* Reset PLX */ + p = &card->plxbase->init_ctrl; + writel(card->init_ctrl_value | 0x40000000, p); + readl(p); /* Flush the write - do not use sca_flush */ + udelay(1); + + writel(card->init_ctrl_value, p); + readl(p); /* Flush the write - do not use sca_flush */ + udelay(1); + + /* Reload Config. Registers from EEPROM */ + writel(card->init_ctrl_value | 0x20000000, p); + readl(p); /* Flush the write - do not use sca_flush */ + udelay(1); + + writel(card->init_ctrl_value, p); + readl(p); /* Flush the write - do not use sca_flush */ + udelay(1); + + ramsize = sca_detect_ram(card, card->rambase, + pci_resource_len(pdev, 3)); + + if (use_crystal_clock) + card->init_ctrl_value &= ~PC300_CLKSEL_MASK; + else + card->init_ctrl_value |= PC300_CLKSEL_MASK; + + writel(card->init_ctrl_value, &card->plxbase->init_ctrl); + /* number of TX + RX buffers for one port */ + i = ramsize / (card->n_ports * (sizeof(pkt_desc) + HDLC_MAX_MRU)); + card->tx_ring_buffers = min(i / 2, MAX_TX_BUFFERS); + card->rx_ring_buffers = i - card->tx_ring_buffers; + + card->buff_offset = card->n_ports * sizeof(pkt_desc) * + (card->tx_ring_buffers + card->rx_ring_buffers); + + printk(KERN_INFO "pc300: PC300/%s, %u KB RAM at 0x%x, IRQ%u, " + "using %u TX + %u RX packets rings\n", + card->type == PC300_X21 ? "X21" : + card->type == PC300_TE ? "TE" : "RSV", + ramsize / 1024, ramphys, pdev->irq, + card->tx_ring_buffers, card->rx_ring_buffers); + + if (card->tx_ring_buffers < 1) { + printk(KERN_ERR "pc300: RAM test failed\n"); + pc300_pci_remove_one(pdev); + return -EFAULT; + } + + /* Enable interrupts on the PCI bridge, LINTi1 active low */ + writew(0x0041, &card->plxbase->intr_ctrl_stat); + + /* Allocate IRQ */ + if (request_irq(pdev->irq, sca_intr, IRQF_SHARED, devname, card)) { + printk(KERN_WARNING "pc300: could not allocate IRQ%d.\n", + pdev->irq); + pc300_pci_remove_one(pdev); + return -EBUSY; + } + card->irq = pdev->irq; + + sca_init(card, 0); + + // COTE not set - allows better TX DMA settings + // sca_out(sca_in(PCR, card) | PCR_COTE, PCR, card); + + sca_out(0x10, BTCR, card); + + for (i = 0; i < card->n_ports; i++) { + port_t *port = &card->ports[i]; + struct net_device *dev = port_to_dev(port); + hdlc_device *hdlc = dev_to_hdlc(dev); + port->phy_node = i; + + spin_lock_init(&port->lock); + SET_MODULE_OWNER(dev); + dev->irq = card->irq; + dev->mem_start = ramphys; + dev->mem_end = ramphys + ramsize - 1; + dev->tx_queue_len = 50; + dev->do_ioctl = pc300_ioctl; + dev->open = pc300_open; + dev->stop = pc300_close; + hdlc->attach = sca_attach; + hdlc->xmit = sca_xmit; + port->settings.clock_type = CLOCK_EXT; + port->card = card; + if (card->type == PC300_X21) + port->iface = IF_IFACE_X21; + else + port->iface = IF_IFACE_V35; + + if (register_hdlc_device(dev)) { + printk(KERN_ERR "pc300: unable to register hdlc " + "device\n"); + port->card = NULL; + pc300_pci_remove_one(pdev); + return -ENOBUFS; + } + sca_init_sync_port(port); /* Set up SCA memory */ + + printk(KERN_INFO "%s: PC300 node %d\n", + dev->name, port->phy_node); + } + return 0; +} + + + +static struct pci_device_id pc300_pci_tbl[] __devinitdata = { + { PCI_VENDOR_ID_CYCLADES, PCI_DEVICE_ID_PC300_RX_1, PCI_ANY_ID, + PCI_ANY_ID, 0, 0, 0 }, + { PCI_VENDOR_ID_CYCLADES, PCI_DEVICE_ID_PC300_RX_2, PCI_ANY_ID, + PCI_ANY_ID, 0, 0, 0 }, + { PCI_VENDOR_ID_CYCLADES, PCI_DEVICE_ID_PC300_TE_1, PCI_ANY_ID, + PCI_ANY_ID, 0, 0, 0 }, + { PCI_VENDOR_ID_CYCLADES, PCI_DEVICE_ID_PC300_TE_2, PCI_ANY_ID, + PCI_ANY_ID, 0, 0, 0 }, + { 0, } +}; + + +static struct pci_driver pc300_pci_driver = { + .name = "PC300", + .id_table = pc300_pci_tbl, + .probe = pc300_pci_init_one, + .remove = pc300_pci_remove_one, +}; + + +static int __init pc300_init_module(void) +{ +#ifdef MODULE + printk(KERN_INFO "%s\n", version); +#endif + if (pci_clock_freq < 1000000 || pci_clock_freq > 80000000) { + printk(KERN_ERR "pc300: Invalid PCI clock frequency\n"); + return -EINVAL; + } + if (use_crystal_clock != 0 && use_crystal_clock != 1) { + printk(KERN_ERR "pc300: Invalid 'use_crystal_clock' value\n"); + return -EINVAL; + } + + CLOCK_BASE = use_crystal_clock ? 24576000 : pci_clock_freq; + + return pci_module_init(&pc300_pci_driver); +} + + + +static void __exit pc300_cleanup_module(void) +{ + pci_unregister_driver(&pc300_pci_driver); +} + +MODULE_AUTHOR("Krzysztof Halasa "); +MODULE_DESCRIPTION("Cyclades PC300 serial port driver"); +MODULE_LICENSE("GPL v2"); +MODULE_DEVICE_TABLE(pci, pc300_pci_tbl); +module_param(pci_clock_freq, int, 0444); +MODULE_PARM_DESC(pci_clock_freq, "System PCI clock frequency in Hz"); +module_param(use_crystal_clock, int, 0444); +MODULE_PARM_DESC(use_crystal_clock, + "Use 24.576 MHz clock instead of PCI clock"); +module_init(pc300_init_module); +module_exit(pc300_cleanup_module); diff --git a/drivers/net/wan/pci200syn.c b/drivers/net/wan/pci200syn.c index a6b9c33..ca06a00 100644 --- a/drivers/net/wan/pci200syn.c +++ b/drivers/net/wan/pci200syn.c @@ -17,7 +17,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/net/wan/z85230.c b/drivers/net/wan/z85230.c index 59ddd21..8dbcf83 100644 --- a/drivers/net/wan/z85230.c +++ b/drivers/net/wan/z85230.c @@ -331,8 +331,7 @@ static void z8530_rtsdtr(struct z8530_ch static void z8530_rx(struct z8530_channel *c) { u8 ch,stat; - spin_lock(c->lock); - + while(1) { /* FIFO empty ? */ @@ -390,7 +389,6 @@ static void z8530_rx(struct z8530_channe */ write_zsctrl(c, ERR_RES); write_zsctrl(c, RES_H_IUS); - spin_unlock(c->lock); } @@ -406,7 +404,6 @@ static void z8530_rx(struct z8530_channe static void z8530_tx(struct z8530_channel *c) { - spin_lock(c->lock); while(c->txcount) { /* FIFO full ? */ if(!(read_zsreg(c, R0)&4)) @@ -434,7 +431,6 @@ static void z8530_tx(struct z8530_channe z8530_tx_done(c); write_zsctrl(c, RES_H_IUS); - spin_unlock(c->lock); } /** @@ -452,7 +448,6 @@ static void z8530_status(struct z8530_ch { u8 status, altered; - spin_lock(chan->lock); status=read_zsreg(chan, R0); altered=chan->status^status; @@ -487,7 +482,6 @@ static void z8530_status(struct z8530_ch } write_zsctrl(chan, RES_EXT_INT); write_zsctrl(chan, RES_H_IUS); - spin_unlock(chan->lock); } struct z8530_irqhandler z8530_sync= @@ -511,7 +505,6 @@ EXPORT_SYMBOL(z8530_sync); static void z8530_dma_rx(struct z8530_channel *chan) { - spin_lock(chan->lock); if(chan->rxdma_on) { /* Special condition check only */ @@ -534,7 +527,6 @@ static void z8530_dma_rx(struct z8530_ch /* DMA is off right now, drain the slow way */ z8530_rx(chan); } - spin_unlock(chan->lock); } /** @@ -547,7 +539,6 @@ static void z8530_dma_rx(struct z8530_ch static void z8530_dma_tx(struct z8530_channel *chan) { - spin_lock(chan->lock); if(!chan->dma_tx) { printk(KERN_WARNING "Hey who turned the DMA off?\n"); @@ -557,7 +548,6 @@ static void z8530_dma_tx(struct z8530_ch /* This shouldnt occur in DMA mode */ printk(KERN_ERR "DMA tx - bogus event!\n"); z8530_tx(chan); - spin_unlock(chan->lock); } /** @@ -596,7 +586,6 @@ static void z8530_dma_status(struct z853 } } - spin_lock(chan->lock); if(altered&chan->dcdcheck) { if(status&chan->dcdcheck) @@ -618,7 +607,6 @@ static void z8530_dma_status(struct z853 write_zsctrl(chan, RES_EXT_INT); write_zsctrl(chan, RES_H_IUS); - spin_unlock(chan->lock); } struct z8530_irqhandler z8530_dma_sync= diff --git a/drivers/net/wd.c b/drivers/net/wd.c index 7f38012..a032681 100644 --- a/drivers/net/wd.c +++ b/drivers/net/wd.c @@ -433,7 +433,7 @@ wd_block_input(struct net_device *dev, i memcpy_fromio(skb->data + semi_count, ei_status.mem + TX_PAGES * 256, count); } else { /* Packet is in one chunk -- we can copy + cksum. */ - eth_io_copy_and_sum(skb, xfer_start, count, 0); + memcpy_fromio(skb->data, xfer_start, count); } /* Turn off 16 bit access so that reboot works. ISA brain-damage */ diff --git a/drivers/net/wireless/airo.c b/drivers/net/wireless/airo.c index 44a2270..b08055a 100644 --- a/drivers/net/wireless/airo.c +++ b/drivers/net/wireless/airo.c @@ -4430,53 +4430,53 @@ static int proc_BSSList_open( struct ino static int proc_config_open( struct inode *inode, struct file *file ); static int proc_wepkey_open( struct inode *inode, struct file *file ); -static struct file_operations proc_statsdelta_ops = { +static const struct file_operations proc_statsdelta_ops = { .read = proc_read, .open = proc_statsdelta_open, .release = proc_close }; -static struct file_operations proc_stats_ops = { +static const struct file_operations proc_stats_ops = { .read = proc_read, .open = proc_stats_open, .release = proc_close }; -static struct file_operations proc_status_ops = { +static const struct file_operations proc_status_ops = { .read = proc_read, .open = proc_status_open, .release = proc_close }; -static struct file_operations proc_SSID_ops = { +static const struct file_operations proc_SSID_ops = { .read = proc_read, .write = proc_write, .open = proc_SSID_open, .release = proc_close }; -static struct file_operations proc_BSSList_ops = { +static const struct file_operations proc_BSSList_ops = { .read = proc_read, .write = proc_write, .open = proc_BSSList_open, .release = proc_close }; -static struct file_operations proc_APList_ops = { +static const struct file_operations proc_APList_ops = { .read = proc_read, .write = proc_write, .open = proc_APList_open, .release = proc_close }; -static struct file_operations proc_config_ops = { +static const struct file_operations proc_config_ops = { .read = proc_read, .write = proc_write, .open = proc_config_open, .release = proc_close }; -static struct file_operations proc_wepkey_ops = { +static const struct file_operations proc_wepkey_ops = { .read = proc_read, .write = proc_write, .open = proc_wepkey_open, diff --git a/drivers/net/wireless/arlan-proc.c b/drivers/net/wireless/arlan-proc.c index 5fa9854..015abd9 100644 --- a/drivers/net/wireless/arlan-proc.c +++ b/drivers/net/wireless/arlan-proc.c @@ -1216,7 +1216,7 @@ #endif static ctl_table arlan_root_table[] = { { - .ctl_name = 254, + .ctl_name = CTL_ARLAN, .procname = "arlan", .maxlen = 0, .mode = 0555, @@ -1244,7 +1244,7 @@ int __init init_arlan_proc(void) return 0; for (i = 0; i < MAX_ARLANS && arlan_device[i]; i++) arlan_table[i].ctl_name = i + 1; - arlan_device_sysctl_header = register_sysctl_table(arlan_root_table, 0); + arlan_device_sysctl_header = register_sysctl_table(arlan_root_table); if (!arlan_device_sysctl_header) return -1; diff --git a/drivers/net/wireless/atmel.c b/drivers/net/wireless/atmel.c index 10bcb48..23eba69 100644 --- a/drivers/net/wireless/atmel.c +++ b/drivers/net/wireless/atmel.c @@ -42,7 +42,6 @@ #include #include -#include #include #include #include diff --git a/drivers/net/wireless/bcm43xx/bcm43xx.h b/drivers/net/wireless/bcm43xx/bcm43xx.h index 8286678..3a064de 100644 --- a/drivers/net/wireless/bcm43xx/bcm43xx.h +++ b/drivers/net/wireless/bcm43xx/bcm43xx.h @@ -352,6 +352,10 @@ #define BCM43xx_UCODEFLAG_UNKGPHY 0x0020 #define BCM43xx_UCODEFLAG_UNKPACTRL 0x0040 #define BCM43xx_UCODEFLAG_JAPAN 0x0080 +/* Hardware Radio Enable masks */ +#define BCM43xx_MMIO_RADIO_HWENABLED_HI_MASK (1 << 16) +#define BCM43xx_MMIO_RADIO_HWENABLED_LO_MASK (1 << 4) + /* Generic-Interrupt reasons. */ #define BCM43xx_IRQ_READY (1 << 0) #define BCM43xx_IRQ_BEACON (1 << 1) @@ -758,7 +762,8 @@ struct bcm43xx_private { bad_frames_preempt:1, /* Use "Bad Frames Preemption" (default off) */ reg124_set_0x4:1, /* Some variable to keep track of IRQ stuff. */ short_preamble:1, /* TRUE, if short preamble is enabled. */ - firmware_norelease:1; /* Do not release the firmware. Used on suspend. */ + firmware_norelease:1, /* Do not release the firmware. Used on suspend. */ + radio_hw_enable:1; /* TRUE if radio is hardware enabled */ struct bcm43xx_stats stats; diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_debugfs.c b/drivers/net/wireless/bcm43xx/bcm43xx_debugfs.c index b9df06a..35dbe45 100644 --- a/drivers/net/wireless/bcm43xx/bcm43xx_debugfs.c +++ b/drivers/net/wireless/bcm43xx/bcm43xx_debugfs.c @@ -355,37 +355,37 @@ out_up: #undef fappend -static struct file_operations devinfo_fops = { +static const struct file_operations devinfo_fops = { .read = devinfo_read_file, .write = write_file_dummy, .open = open_file_generic, }; -static struct file_operations spromdump_fops = { +static const struct file_operations spromdump_fops = { .read = spromdump_read_file, .write = write_file_dummy, .open = open_file_generic, }; -static struct file_operations drvinfo_fops = { +static const struct file_operations drvinfo_fops = { .read = drvinfo_read_file, .write = write_file_dummy, .open = open_file_generic, }; -static struct file_operations tsf_fops = { +static const struct file_operations tsf_fops = { .read = tsf_read_file, .write = tsf_write_file, .open = open_file_generic, }; -static struct file_operations txstat_fops = { +static const struct file_operations txstat_fops = { .read = txstat_read_file, .write = write_file_dummy, .open = open_file_generic, }; -static struct file_operations restart_fops = { +static const struct file_operations restart_fops = { .write = restart_write_file, .open = open_file_generic, }; diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_leds.c b/drivers/net/wireless/bcm43xx/bcm43xx_leds.c index 7d383a2..8f198be 100644 --- a/drivers/net/wireless/bcm43xx/bcm43xx_leds.c +++ b/drivers/net/wireless/bcm43xx/bcm43xx_leds.c @@ -26,6 +26,7 @@ */ #include "bcm43xx_leds.h" +#include "bcm43xx_radio.h" #include "bcm43xx.h" #include @@ -108,6 +109,7 @@ static void bcm43xx_led_init_hardcoded(s switch (led_index) { case 0: led->behaviour = BCM43xx_LED_ACTIVITY; + led->activelow = 1; if (bcm->board_vendor == PCI_VENDOR_ID_COMPAQ) led->behaviour = BCM43xx_LED_RADIO_ALL; break; @@ -199,20 +201,21 @@ void bcm43xx_leds_update(struct bcm43xx_ turn_on = activity; break; case BCM43xx_LED_RADIO_ALL: - turn_on = radio->enabled; + turn_on = radio->enabled && bcm43xx_is_hw_radio_enabled(bcm); break; case BCM43xx_LED_RADIO_A: case BCM43xx_LED_BCM4303_2: - turn_on = (radio->enabled && phy->type == BCM43xx_PHYTYPE_A); + turn_on = (radio->enabled && bcm43xx_is_hw_radio_enabled(bcm) && + phy->type == BCM43xx_PHYTYPE_A); break; case BCM43xx_LED_RADIO_B: case BCM43xx_LED_BCM4303_1: - turn_on = (radio->enabled && + turn_on = (radio->enabled && bcm43xx_is_hw_radio_enabled(bcm) && (phy->type == BCM43xx_PHYTYPE_B || phy->type == BCM43xx_PHYTYPE_G)); break; case BCM43xx_LED_MODE_BG: - if (phy->type == BCM43xx_PHYTYPE_G && + if (phy->type == BCM43xx_PHYTYPE_G && bcm43xx_is_hw_radio_enabled(bcm) && 1/*FIXME: using G rates.*/) turn_on = 1; break; diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_main.c b/drivers/net/wireless/bcm43xx/bcm43xx_main.c index 91b752e..23aaf1e 100644 --- a/drivers/net/wireless/bcm43xx/bcm43xx_main.c +++ b/drivers/net/wireless/bcm43xx/bcm43xx_main.c @@ -2441,6 +2441,9 @@ static int bcm43xx_chip_init(struct bcm4 if (err) goto err_gpio_cleanup; bcm43xx_radio_turn_on(bcm); + bcm->radio_hw_enable = bcm43xx_is_hw_radio_enabled(bcm); + dprintk(KERN_INFO PFX "Radio %s by hardware\n", + (bcm->radio_hw_enable == 0) ? "disabled" : "enabled"); bcm43xx_write16(bcm, 0x03E6, 0x0000); err = bcm43xx_phy_init(bcm); @@ -3175,9 +3178,24 @@ static void bcm43xx_periodic_every30sec( static void bcm43xx_periodic_every15sec(struct bcm43xx_private *bcm) { + bcm43xx_phy_xmitpower(bcm); //FIXME: unless scanning? + //TODO for APHY (temperature?) +} + +static void bcm43xx_periodic_every1sec(struct bcm43xx_private *bcm) +{ struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm); struct bcm43xx_radioinfo *radio = bcm43xx_current_radio(bcm); + int radio_hw_enable; + /* check if radio hardware enabled status changed */ + radio_hw_enable = bcm43xx_is_hw_radio_enabled(bcm); + if (unlikely(bcm->radio_hw_enable != radio_hw_enable)) { + bcm->radio_hw_enable = radio_hw_enable; + dprintk(KERN_INFO PFX "Radio hardware status changed to %s\n", + (radio_hw_enable == 0) ? "disabled" : "enabled"); + bcm43xx_leds_update(bcm, 0); + } if (phy->type == BCM43xx_PHYTYPE_G) { //TODO: update_aci_moving_average if (radio->aci_enable && radio->aci_wlan_automatic) { @@ -3201,21 +3219,21 @@ static void bcm43xx_periodic_every15sec( //TODO: implement rev1 workaround } } - bcm43xx_phy_xmitpower(bcm); //FIXME: unless scanning? - //TODO for APHY (temperature?) } static void do_periodic_work(struct bcm43xx_private *bcm) { - if (bcm->periodic_state % 8 == 0) + if (bcm->periodic_state % 120 == 0) bcm43xx_periodic_every120sec(bcm); - if (bcm->periodic_state % 4 == 0) + if (bcm->periodic_state % 60 == 0) bcm43xx_periodic_every60sec(bcm); - if (bcm->periodic_state % 2 == 0) + if (bcm->periodic_state % 30 == 0) bcm43xx_periodic_every30sec(bcm); - bcm43xx_periodic_every15sec(bcm); + if (bcm->periodic_state % 15 == 0) + bcm43xx_periodic_every15sec(bcm); + bcm43xx_periodic_every1sec(bcm); - schedule_delayed_work(&bcm->periodic_work, HZ * 15); + schedule_delayed_work(&bcm->periodic_work, HZ); } static void bcm43xx_periodic_work_handler(struct work_struct *work) @@ -3228,7 +3246,7 @@ static void bcm43xx_periodic_work_handle unsigned long orig_trans_start = 0; mutex_lock(&bcm->mutex); - if (unlikely(bcm->periodic_state % 4 == 0)) { + if (unlikely(bcm->periodic_state % 60 == 0)) { /* Periodic work will take a long time, so we want it to * be preemtible. */ @@ -3260,7 +3278,7 @@ static void bcm43xx_periodic_work_handle do_periodic_work(bcm); - if (unlikely(bcm->periodic_state % 4 == 0)) { + if (unlikely(bcm->periodic_state % 60 == 0)) { spin_lock_irqsave(&bcm->irq_lock, flags); tasklet_enable(&bcm->isr_tasklet); bcm43xx_interrupt_enable(bcm, savedirqs); diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_radio.c b/drivers/net/wireless/bcm43xx/bcm43xx_radio.c index bb9c484..af19a07 100644 --- a/drivers/net/wireless/bcm43xx/bcm43xx_radio.c +++ b/drivers/net/wireless/bcm43xx/bcm43xx_radio.c @@ -1981,6 +1981,7 @@ void bcm43xx_radio_turn_on(struct bcm43x } radio->enabled = 1; dprintk(KERN_INFO PFX "Radio turned on\n"); + bcm43xx_leds_update(bcm, 0); } void bcm43xx_radio_turn_off(struct bcm43xx_private *bcm) @@ -2001,6 +2002,7 @@ void bcm43xx_radio_turn_off(struct bcm43 bcm43xx_phy_write(bcm, 0x0015, 0xAA00); radio->enabled = 0; dprintk(KERN_INFO PFX "Radio turned off\n"); + bcm43xx_leds_update(bcm, 0); } void bcm43xx_radio_clear_tssi(struct bcm43xx_private *bcm) diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_radio.h b/drivers/net/wireless/bcm43xx/bcm43xx_radio.h index 9ed1803..77a98a5 100644 --- a/drivers/net/wireless/bcm43xx/bcm43xx_radio.h +++ b/drivers/net/wireless/bcm43xx/bcm43xx_radio.h @@ -65,6 +65,22 @@ void bcm43xx_radio_init2060(struct bcm43 void bcm43xx_radio_turn_on(struct bcm43xx_private *bcm); void bcm43xx_radio_turn_off(struct bcm43xx_private *bcm); +static inline +int bcm43xx_is_hw_radio_enabled(struct bcm43xx_private *bcm) +{ + /* function to return state of hardware enable of radio + * returns 0 if radio disabled, 1 if radio enabled + */ + if (bcm->current_core->rev >= 3) + return ((bcm43xx_read32(bcm, BCM43xx_MMIO_RADIO_HWENABLED_HI) + & BCM43xx_MMIO_RADIO_HWENABLED_HI_MASK) + == 0) ? 1 : 0; + else + return ((bcm43xx_read16(bcm, BCM43xx_MMIO_RADIO_HWENABLED_LO) + & BCM43xx_MMIO_RADIO_HWENABLED_LO_MASK) + == 0) ? 0 : 1; +} + int bcm43xx_radio_selectchannel(struct bcm43xx_private *bcm, u8 channel, int synthetic_pu_workaround); diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_wx.c b/drivers/net/wireless/bcm43xx/bcm43xx_wx.c index a659442..d2ca949 100644 --- a/drivers/net/wireless/bcm43xx/bcm43xx_wx.c +++ b/drivers/net/wireless/bcm43xx/bcm43xx_wx.c @@ -33,7 +33,6 @@ #include #include #include #include -#include /* for capable() */ #include #include "bcm43xx.h" diff --git a/drivers/net/wireless/hostap/hostap_main.c b/drivers/net/wireless/hostap/hostap_main.c index 04c19ce..9077e6e 100644 --- a/drivers/net/wireless/hostap/hostap_main.c +++ b/drivers/net/wireless/hostap/hostap_main.c @@ -84,7 +84,7 @@ struct net_device * hostap_add_interface if (strchr(dev->name, '%')) ret = dev_alloc_name(dev, dev->name); - SET_NETDEV_DEV(dev, mdev->class_dev.dev); + SET_NETDEV_DEV(dev, mdev->dev.parent); if (ret >= 0) ret = register_netdevice(dev); diff --git a/drivers/net/wireless/ipw2200.c b/drivers/net/wireless/ipw2200.c index 22cb3fb..c878a2f 100644 --- a/drivers/net/wireless/ipw2200.c +++ b/drivers/net/wireless/ipw2200.c @@ -9166,7 +9166,7 @@ static int ipw_wx_set_rts(struct net_dev { struct ipw_priv *priv = ieee80211_priv(dev); mutex_lock(&priv->mutex); - if (wrqu->rts.disabled) + if (wrqu->rts.disabled || !wrqu->rts.fixed) priv->rts_threshold = DEFAULT_RTS_THRESHOLD; else { if (wrqu->rts.value < MIN_RTS_THRESHOLD || @@ -9255,7 +9255,7 @@ static int ipw_wx_set_frag(struct net_de { struct ipw_priv *priv = ieee80211_priv(dev); mutex_lock(&priv->mutex); - if (wrqu->frag.disabled) + if (wrqu->frag.disabled || !wrqu->frag.fixed) priv->ieee->fts = DEFAULT_FTS; else { if (wrqu->frag.value < MIN_FRAG_THRESHOLD || diff --git a/drivers/net/wireless/orinoco.c b/drivers/net/wireless/orinoco.c index 936c888..4e7f6cf 100644 --- a/drivers/net/wireless/orinoco.c +++ b/drivers/net/wireless/orinoco.c @@ -2059,7 +2059,7 @@ static int determine_firmware(struct net int err; struct comp_id nic_id, sta_id; unsigned int firmver; - char tmp[SYMBOL_MAX_VER_LEN+1]; + char tmp[SYMBOL_MAX_VER_LEN+1] __attribute__((aligned(2))); /* Get the hardware version */ err = HERMES_READ_RECORD(hw, USER_BAP, HERMES_RID_NICID, &nic_id); @@ -4293,8 +4293,8 @@ static void orinoco_get_drvinfo(struct n strncpy(info->driver, DRIVER_NAME, sizeof(info->driver) - 1); strncpy(info->version, DRIVER_VERSION, sizeof(info->version) - 1); strncpy(info->fw_version, priv->fw_name, sizeof(info->fw_version) - 1); - if (dev->class_dev.dev) - strncpy(info->bus_info, dev->class_dev.dev->bus_id, + if (dev->dev.parent) + strncpy(info->bus_info, dev->dev.parent->bus_id, sizeof(info->bus_info) - 1); else snprintf(info->bus_info, sizeof(info->bus_info) - 1, diff --git a/drivers/net/wireless/orinoco_cs.c b/drivers/net/wireless/orinoco_cs.c index d08ae8d..d1e5022 100644 --- a/drivers/net/wireless/orinoco_cs.c +++ b/drivers/net/wireless/orinoco_cs.c @@ -332,7 +332,7 @@ orinoco_cs_config(struct pcmcia_device * /* Finally, report what we've done */ printk(KERN_DEBUG "%s: " DRIVER_NAME " at %s, irq %d, io " - "0x%04x-0x%04x\n", dev->name, dev->class_dev.dev->bus_id, + "0x%04x-0x%04x\n", dev->name, dev->dev.parent->bus_id, link->irq.AssignedIRQ, link->io.BasePort1, link->io.BasePort1 + link->io.NumPorts1 - 1); diff --git a/drivers/net/wireless/prism54/islpci_dev.c b/drivers/net/wireless/prism54/islpci_dev.c index f057fd9..a037b11 100644 --- a/drivers/net/wireless/prism54/islpci_dev.c +++ b/drivers/net/wireless/prism54/islpci_dev.c @@ -21,6 +21,7 @@ #include #include +#include #include #include #include @@ -787,6 +788,17 @@ islpci_set_multicast_list(struct net_dev } #endif +static void islpci_ethtool_get_drvinfo(struct net_device *dev, + struct ethtool_drvinfo *info) +{ + strcpy(info->driver, DRV_NAME); + strcpy(info->version, DRV_VERSION); +} + +static struct ethtool_ops islpci_ethtool_ops = { + .get_drvinfo = islpci_ethtool_get_drvinfo, +}; + struct net_device * islpci_setup(struct pci_dev *pdev) { @@ -813,6 +825,7 @@ #endif ndev->do_ioctl = &prism54_ioctl; ndev->wireless_handlers = (struct iw_handler_def *) &prism54_handler_def; + ndev->ethtool_ops = &islpci_ethtool_ops; ndev->hard_start_xmit = &islpci_eth_transmit; /* ndev->set_multicast_list = &islpci_set_multicast_list; */ diff --git a/drivers/net/wireless/prism54/islpci_dev.h b/drivers/net/wireless/prism54/islpci_dev.h index a9aa166..736666d 100644 --- a/drivers/net/wireless/prism54/islpci_dev.h +++ b/drivers/net/wireless/prism54/islpci_dev.h @@ -211,4 +211,8 @@ islpci_trigger(islpci_private *priv) int islpci_free_memory(islpci_private *); struct net_device *islpci_setup(struct pci_dev *); + +#define DRV_NAME "prism54" +#define DRV_VERSION "1.2" + #endif /* _ISLPCI_DEV_H */ diff --git a/drivers/net/wireless/prism54/islpci_hotplug.c b/drivers/net/wireless/prism54/islpci_hotplug.c index 58257b4..3dcb13b 100644 --- a/drivers/net/wireless/prism54/islpci_hotplug.c +++ b/drivers/net/wireless/prism54/islpci_hotplug.c @@ -28,9 +28,6 @@ #include "islpci_dev.h" #include "islpci_mgt.h" /* for pc_debug */ #include "isl_oid.h" -#define DRV_NAME "prism54" -#define DRV_VERSION "1.2" - MODULE_AUTHOR("[Intersil] R.Bastings and W.Termorshuizen, The prism54.org Development Team "); MODULE_DESCRIPTION("The Prism54 802.11 Wireless LAN adapter"); MODULE_LICENSE("GPL"); diff --git a/drivers/net/wireless/spectrum_cs.c b/drivers/net/wireless/spectrum_cs.c index cf2d148..af70460 100644 --- a/drivers/net/wireless/spectrum_cs.c +++ b/drivers/net/wireless/spectrum_cs.c @@ -806,7 +806,7 @@ spectrum_cs_config(struct pcmcia_device /* Finally, report what we've done */ printk(KERN_DEBUG "%s: " DRIVER_NAME " at %s, irq %d, io " - "0x%04x-0x%04x\n", dev->name, dev->class_dev.dev->bus_id, + "0x%04x-0x%04x\n", dev->name, dev->dev.parent->bus_id, link->irq.AssignedIRQ, link->io.BasePort1, link->io.BasePort1 + link->io.NumPorts1 - 1); diff --git a/drivers/net/wireless/strip.c b/drivers/net/wireless/strip.c index ce3a8ba..f5ce1c6 100644 --- a/drivers/net/wireless/strip.c +++ b/drivers/net/wireless/strip.c @@ -1160,7 +1160,7 @@ static int strip_seq_open(struct inode * return seq_open(file, &strip_seq_ops); } -static struct file_operations strip_seq_fops = { +static const struct file_operations strip_seq_fops = { .owner = THIS_MODULE, .open = strip_seq_open, .read = seq_read, diff --git a/drivers/net/wireless/zd1211rw/zd_chip.c b/drivers/net/wireless/zd1211rw/zd_chip.c index 78ea72f..12dfc0b 100644 --- a/drivers/net/wireless/zd1211rw/zd_chip.c +++ b/drivers/net/wireless/zd1211rw/zd_chip.c @@ -84,6 +84,18 @@ static void print_id(struct zd_chip *chi dev_info(zd_chip_dev(chip), "%s\n", buffer); } +static zd_addr_t inc_addr(zd_addr_t addr) +{ + u16 a = (u16)addr; + /* Control registers use byte addressing, but everything else uses word + * addressing. */ + if ((a & 0xf000) == CR_START) + a += 2; + else + a += 1; + return (zd_addr_t)a; +} + /* Read a variable number of 32-bit values. Parameter count is not allowed to * exceed USB_MAX_IOREAD32_COUNT. */ @@ -114,7 +126,7 @@ int zd_ioread32v_locked(struct zd_chip * for (i = 0; i < count; i++) { int j = 2*i; /* We read the high word always first. */ - a16[j] = zd_inc_word(addr[i]); + a16[j] = inc_addr(addr[i]); a16[j+1] = addr[i]; } @@ -163,7 +175,7 @@ int _zd_iowrite32v_locked(struct zd_chip j = 2*i; /* We write the high word always first. */ ioreqs16[j].value = ioreqs[i].value >> 16; - ioreqs16[j].addr = zd_inc_word(ioreqs[i].addr); + ioreqs16[j].addr = inc_addr(ioreqs[i].addr); ioreqs16[j+1].value = ioreqs[i].value; ioreqs16[j+1].addr = ioreqs[i].addr; } @@ -466,7 +478,8 @@ static int read_values(struct zd_chip *c ZD_ASSERT(mutex_is_locked(&chip->mutex)); for (i = 0;;) { - r = zd_ioread32_locked(chip, &v, e2p_addr+i/2); + r = zd_ioread32_locked(chip, &v, + (zd_addr_t)((u16)e2p_addr+i/2)); if (r) return r; v -= guard; @@ -798,47 +811,18 @@ static int hw_reset_phy(struct zd_chip * static int zd1211_hw_init_hmac(struct zd_chip *chip) { static const struct zd_ioreq32 ioreqs[] = { - { CR_ACK_TIMEOUT_EXT, 0x20 }, - { CR_ADDA_MBIAS_WARMTIME, 0x30000808 }, { CR_ZD1211_RETRY_MAX, 0x2 }, - { CR_SNIFFER_ON, 0 }, - { CR_RX_FILTER, STA_RX_FILTER }, - { CR_GROUP_HASH_P1, 0x00 }, - { CR_GROUP_HASH_P2, 0x80000000 }, - { CR_REG1, 0xa4 }, - { CR_ADDA_PWR_DWN, 0x7f }, - { CR_BCN_PLCP_CFG, 0x00f00401 }, - { CR_PHY_DELAY, 0x00 }, - { CR_ACK_TIMEOUT_EXT, 0x80 }, - { CR_ADDA_PWR_DWN, 0x00 }, - { CR_ACK_TIME_80211, 0x100 }, - { CR_RX_PE_DELAY, 0x70 }, - { CR_PS_CTRL, 0x10000000 }, - { CR_RTS_CTS_RATE, 0x02030203 }, { CR_RX_THRESHOLD, 0x000c0640 }, - { CR_AFTER_PNP, 0x1 }, - { CR_WEP_PROTECT, 0x114 }, }; - int r; - dev_dbg_f(zd_chip_dev(chip), "\n"); ZD_ASSERT(mutex_is_locked(&chip->mutex)); - r = zd_iowrite32a_locked(chip, ioreqs, ARRAY_SIZE(ioreqs)); -#ifdef DEBUG - if (r) { - dev_err(zd_chip_dev(chip), - "error in zd_iowrite32a_locked. Error number %d\n", r); - } -#endif /* DEBUG */ - return r; + return zd_iowrite32a_locked(chip, ioreqs, ARRAY_SIZE(ioreqs)); } static int zd1211b_hw_init_hmac(struct zd_chip *chip) { static const struct zd_ioreq32 ioreqs[] = { - { CR_ACK_TIMEOUT_EXT, 0x20 }, - { CR_ADDA_MBIAS_WARMTIME, 0x30000808 }, { CR_ZD1211B_RETRY_MAX, 0x02020202 }, { CR_ZD1211B_TX_PWR_CTL4, 0x007f003f }, { CR_ZD1211B_TX_PWR_CTL3, 0x007f003f }, @@ -847,6 +831,20 @@ static int zd1211b_hw_init_hmac(struct z { CR_ZD1211B_AIFS_CTL1, 0x00280028 }, { CR_ZD1211B_AIFS_CTL2, 0x008C003C }, { CR_ZD1211B_TXOP, 0x01800824 }, + { CR_RX_THRESHOLD, 0x000c0eff, }, + }; + + dev_dbg_f(zd_chip_dev(chip), "\n"); + ZD_ASSERT(mutex_is_locked(&chip->mutex)); + return zd_iowrite32a_locked(chip, ioreqs, ARRAY_SIZE(ioreqs)); +} + +static int hw_init_hmac(struct zd_chip *chip) +{ + int r; + static const struct zd_ioreq32 ioreqs[] = { + { CR_ACK_TIMEOUT_EXT, 0x20 }, + { CR_ADDA_MBIAS_WARMTIME, 0x30000808 }, { CR_SNIFFER_ON, 0 }, { CR_RX_FILTER, STA_RX_FILTER }, { CR_GROUP_HASH_P1, 0x00 }, @@ -861,25 +859,16 @@ static int zd1211b_hw_init_hmac(struct z { CR_RX_PE_DELAY, 0x70 }, { CR_PS_CTRL, 0x10000000 }, { CR_RTS_CTS_RATE, 0x02030203 }, - { CR_RX_THRESHOLD, 0x000c0eff, }, { CR_AFTER_PNP, 0x1 }, { CR_WEP_PROTECT, 0x114 }, + { CR_IFS_VALUE, IFS_VALUE_DEFAULT }, }; - int r; - - dev_dbg_f(zd_chip_dev(chip), "\n"); ZD_ASSERT(mutex_is_locked(&chip->mutex)); r = zd_iowrite32a_locked(chip, ioreqs, ARRAY_SIZE(ioreqs)); - if (r) { - dev_dbg_f(zd_chip_dev(chip), - "error in zd_iowrite32a_locked. Error number %d\n", r); - } - return r; -} + if (r) + return r; -static int hw_init_hmac(struct zd_chip *chip) -{ return chip->is_zd1211b ? zd1211b_hw_init_hmac(chip) : zd1211_hw_init_hmac(chip); } @@ -974,16 +963,14 @@ static int hw_init(struct zd_chip *chip) if (r) return r; - /* Although the vendor driver defaults to a different value during - * init, it overwrites the IFS value with the following every time - * the channel changes. We should aim to be more intelligent... */ - r = zd_iowrite32_locked(chip, IFS_VALUE_DEFAULT, CR_IFS_VALUE); - if (r) - return r; - return set_beacon_interval(chip, 100); } +static zd_addr_t fw_reg_addr(struct zd_chip *chip, u16 offset) +{ + return (zd_addr_t)((u16)chip->fw_regs_base + offset); +} + #ifdef DEBUG static int dump_cr(struct zd_chip *chip, const zd_addr_t addr, const char *addr_string) @@ -1018,9 +1005,11 @@ static int test_init(struct zd_chip *chi static void dump_fw_registers(struct zd_chip *chip) { - static const zd_addr_t addr[4] = { - FW_FIRMWARE_VER, FW_USB_SPEED, FW_FIX_TX_RATE, - FW_LINK_STATUS + const zd_addr_t addr[4] = { + fw_reg_addr(chip, FW_REG_FIRMWARE_VER), + fw_reg_addr(chip, FW_REG_USB_SPEED), + fw_reg_addr(chip, FW_REG_FIX_TX_RATE), + fw_reg_addr(chip, FW_REG_LED_LINK_STATUS), }; int r; @@ -1046,7 +1035,8 @@ static int print_fw_version(struct zd_ch int r; u16 version; - r = zd_ioread16_locked(chip, &version, FW_FIRMWARE_VER); + r = zd_ioread16_locked(chip, &version, + fw_reg_addr(chip, FW_REG_FIRMWARE_VER)); if (r) return r; @@ -1126,6 +1116,22 @@ int zd_chip_disable_hwint(struct zd_chip return r; } +static int read_fw_regs_offset(struct zd_chip *chip) +{ + int r; + + ZD_ASSERT(mutex_is_locked(&chip->mutex)); + r = zd_ioread16_locked(chip, (u16*)&chip->fw_regs_base, + FWRAW_REGS_ADDR); + if (r) + return r; + dev_dbg_f(zd_chip_dev(chip), "fw_regs_base: %#06hx\n", + (u16)chip->fw_regs_base); + + return 0; +} + + int zd_chip_init_hw(struct zd_chip *chip, u8 device_type) { int r; @@ -1145,7 +1151,7 @@ #endif if (r) goto out; - r = zd_usb_init_hw(&chip->usb); + r = read_fw_regs_offset(chip); if (r) goto out; @@ -1325,15 +1331,15 @@ u8 zd_chip_get_channel(struct zd_chip *c int zd_chip_control_leds(struct zd_chip *chip, enum led_status status) { - static const zd_addr_t a[] = { - FW_LINK_STATUS, + const zd_addr_t a[] = { + fw_reg_addr(chip, FW_REG_LED_LINK_STATUS), CR_LED, }; int r; u16 v[ARRAY_SIZE(a)]; struct zd_ioreq16 ioreqs[ARRAY_SIZE(a)] = { - [0] = { FW_LINK_STATUS }, + [0] = { fw_reg_addr(chip, FW_REG_LED_LINK_STATUS) }, [1] = { CR_LED }, }; u16 other_led; diff --git a/drivers/net/wireless/zd1211rw/zd_chip.h b/drivers/net/wireless/zd1211rw/zd_chip.h index a4e3cee..b07569e 100644 --- a/drivers/net/wireless/zd1211rw/zd_chip.h +++ b/drivers/net/wireless/zd1211rw/zd_chip.h @@ -18,7 +18,6 @@ #ifndef _ZD_CHIP_H #define _ZD_CHIP_H -#include "zd_types.h" #include "zd_rf.h" #include "zd_usb.h" @@ -27,6 +26,37 @@ #include "zd_usb.h" * adds a processor for handling the USB protocol. */ +/* Address space */ +enum { + /* CONTROL REGISTERS */ + CR_START = 0x9000, + + + /* FIRMWARE */ + FW_START = 0xee00, + + + /* EEPROM */ + E2P_START = 0xf800, + E2P_LEN = 0x800, + + /* EEPROM layout */ + E2P_LOAD_CODE_LEN = 0xe, /* base 0xf800 */ + E2P_LOAD_VECT_LEN = 0x9, /* base 0xf80e */ + /* E2P_DATA indexes into this */ + E2P_DATA_LEN = 0x7e, /* base 0xf817 */ + E2P_BOOT_CODE_LEN = 0x760, /* base 0xf895 */ + E2P_INTR_VECT_LEN = 0xb, /* base 0xfff5 */ + + /* Some precomputed offsets into the EEPROM */ + E2P_DATA_OFFSET = E2P_LOAD_CODE_LEN + E2P_LOAD_VECT_LEN, + E2P_BOOT_CODE_OFFSET = E2P_DATA_OFFSET + E2P_DATA_LEN, +}; + +#define CTL_REG(offset) ((zd_addr_t)(CR_START + (offset))) +#define E2P_DATA(offset) ((zd_addr_t)(E2P_START + E2P_DATA_OFFSET + (offset))) +#define FWRAW_DATA(offset) ((zd_addr_t)(FW_START + (offset))) + /* 8-bit hardware registers */ #define CR0 CTL_REG(0x0000) #define CR1 CTL_REG(0x0004) @@ -302,7 +332,7 @@ #define CR255 CTL_REG(0x03FC) #define CR_MAX_PHY_REG 255 -/* Taken from the ZYDAS driver, not all of them are relevant for the ZSD1211 +/* Taken from the ZYDAS driver, not all of them are relevant for the ZD1211 * driver. */ @@ -594,81 +624,71 @@ #define E2P_CHANNEL_COUNT 14 /* * Upper 16 bit contains the regulatory domain. */ -#define E2P_SUBID E2P_REG(0x00) -#define E2P_POD E2P_REG(0x02) -#define E2P_MAC_ADDR_P1 E2P_REG(0x04) -#define E2P_MAC_ADDR_P2 E2P_REG(0x06) -#define E2P_PWR_CAL_VALUE1 E2P_REG(0x08) -#define E2P_PWR_CAL_VALUE2 E2P_REG(0x0a) -#define E2P_PWR_CAL_VALUE3 E2P_REG(0x0c) -#define E2P_PWR_CAL_VALUE4 E2P_REG(0x0e) -#define E2P_PWR_INT_VALUE1 E2P_REG(0x10) -#define E2P_PWR_INT_VALUE2 E2P_REG(0x12) -#define E2P_PWR_INT_VALUE3 E2P_REG(0x14) -#define E2P_PWR_INT_VALUE4 E2P_REG(0x16) +#define E2P_SUBID E2P_DATA(0x00) +#define E2P_POD E2P_DATA(0x02) +#define E2P_MAC_ADDR_P1 E2P_DATA(0x04) +#define E2P_MAC_ADDR_P2 E2P_DATA(0x06) +#define E2P_PWR_CAL_VALUE1 E2P_DATA(0x08) +#define E2P_PWR_CAL_VALUE2 E2P_DATA(0x0a) +#define E2P_PWR_CAL_VALUE3 E2P_DATA(0x0c) +#define E2P_PWR_CAL_VALUE4 E2P_DATA(0x0e) +#define E2P_PWR_INT_VALUE1 E2P_DATA(0x10) +#define E2P_PWR_INT_VALUE2 E2P_DATA(0x12) +#define E2P_PWR_INT_VALUE3 E2P_DATA(0x14) +#define E2P_PWR_INT_VALUE4 E2P_DATA(0x16) /* Contains a bit for each allowed channel. It gives for Europe (ETSI 0x30) * also only 11 channels. */ -#define E2P_ALLOWED_CHANNEL E2P_REG(0x18) - -#define E2P_PHY_REG E2P_REG(0x1a) -#define E2P_DEVICE_VER E2P_REG(0x20) -#define E2P_36M_CAL_VALUE1 E2P_REG(0x28) -#define E2P_36M_CAL_VALUE2 E2P_REG(0x2a) -#define E2P_36M_CAL_VALUE3 E2P_REG(0x2c) -#define E2P_36M_CAL_VALUE4 E2P_REG(0x2e) -#define E2P_11A_INT_VALUE1 E2P_REG(0x30) -#define E2P_11A_INT_VALUE2 E2P_REG(0x32) -#define E2P_11A_INT_VALUE3 E2P_REG(0x34) -#define E2P_11A_INT_VALUE4 E2P_REG(0x36) -#define E2P_48M_CAL_VALUE1 E2P_REG(0x38) -#define E2P_48M_CAL_VALUE2 E2P_REG(0x3a) -#define E2P_48M_CAL_VALUE3 E2P_REG(0x3c) -#define E2P_48M_CAL_VALUE4 E2P_REG(0x3e) -#define E2P_48M_INT_VALUE1 E2P_REG(0x40) -#define E2P_48M_INT_VALUE2 E2P_REG(0x42) -#define E2P_48M_INT_VALUE3 E2P_REG(0x44) -#define E2P_48M_INT_VALUE4 E2P_REG(0x46) -#define E2P_54M_CAL_VALUE1 E2P_REG(0x48) /* ??? */ -#define E2P_54M_CAL_VALUE2 E2P_REG(0x4a) -#define E2P_54M_CAL_VALUE3 E2P_REG(0x4c) -#define E2P_54M_CAL_VALUE4 E2P_REG(0x4e) -#define E2P_54M_INT_VALUE1 E2P_REG(0x50) -#define E2P_54M_INT_VALUE2 E2P_REG(0x52) -#define E2P_54M_INT_VALUE3 E2P_REG(0x54) -#define E2P_54M_INT_VALUE4 E2P_REG(0x56) - -/* All 16 bit values */ -#define FW_FIRMWARE_VER FW_REG(0) -/* non-zero if USB high speed connection */ -#define FW_USB_SPEED FW_REG(1) -#define FW_FIX_TX_RATE FW_REG(2) -/* Seems to be able to control LEDs over the firmware */ -#define FW_LINK_STATUS FW_REG(3) -#define FW_SOFT_RESET FW_REG(4) -#define FW_FLASH_CHK FW_REG(5) +#define E2P_ALLOWED_CHANNEL E2P_DATA(0x18) + +#define E2P_PHY_REG E2P_DATA(0x1a) +#define E2P_DEVICE_VER E2P_DATA(0x20) +#define E2P_36M_CAL_VALUE1 E2P_DATA(0x28) +#define E2P_36M_CAL_VALUE2 E2P_DATA(0x2a) +#define E2P_36M_CAL_VALUE3 E2P_DATA(0x2c) +#define E2P_36M_CAL_VALUE4 E2P_DATA(0x2e) +#define E2P_11A_INT_VALUE1 E2P_DATA(0x30) +#define E2P_11A_INT_VALUE2 E2P_DATA(0x32) +#define E2P_11A_INT_VALUE3 E2P_DATA(0x34) +#define E2P_11A_INT_VALUE4 E2P_DATA(0x36) +#define E2P_48M_CAL_VALUE1 E2P_DATA(0x38) +#define E2P_48M_CAL_VALUE2 E2P_DATA(0x3a) +#define E2P_48M_CAL_VALUE3 E2P_DATA(0x3c) +#define E2P_48M_CAL_VALUE4 E2P_DATA(0x3e) +#define E2P_48M_INT_VALUE1 E2P_DATA(0x40) +#define E2P_48M_INT_VALUE2 E2P_DATA(0x42) +#define E2P_48M_INT_VALUE3 E2P_DATA(0x44) +#define E2P_48M_INT_VALUE4 E2P_DATA(0x46) +#define E2P_54M_CAL_VALUE1 E2P_DATA(0x48) /* ??? */ +#define E2P_54M_CAL_VALUE2 E2P_DATA(0x4a) +#define E2P_54M_CAL_VALUE3 E2P_DATA(0x4c) +#define E2P_54M_CAL_VALUE4 E2P_DATA(0x4e) +#define E2P_54M_INT_VALUE1 E2P_DATA(0x50) +#define E2P_54M_INT_VALUE2 E2P_DATA(0x52) +#define E2P_54M_INT_VALUE3 E2P_DATA(0x54) +#define E2P_54M_INT_VALUE4 E2P_DATA(0x56) + +/* This word contains the base address of the FW_REG_ registers below */ +#define FWRAW_REGS_ADDR FWRAW_DATA(0x1d) + +/* All 16 bit values, offset from the address in FWRAW_REGS_ADDR */ +enum { + FW_REG_FIRMWARE_VER = 0, + /* non-zero if USB high speed connection */ + FW_REG_USB_SPEED = 1, + FW_REG_FIX_TX_RATE = 2, + /* Seems to be able to control LEDs over the firmware */ + FW_REG_LED_LINK_STATUS = 3, + FW_REG_SOFT_RESET = 4, + FW_REG_FLASH_CHK = 5, +}; +/* Values for FW_LINK_STATUS */ #define FW_LINK_OFF 0x0 #define FW_LINK_TX 0x1 /* 0x2 - link led on? */ enum { - CR_BASE_OFFSET = 0x9000, - FW_START_OFFSET = 0xee00, - FW_BASE_ADDR_OFFSET = FW_START_OFFSET + 0x1d, - EEPROM_START_OFFSET = 0xf800, - EEPROM_SIZE = 0x800, /* words */ - LOAD_CODE_SIZE = 0xe, /* words */ - LOAD_VECT_SIZE = 0x10000 - 0xfff7, /* words */ - EEPROM_REGS_OFFSET = LOAD_CODE_SIZE + LOAD_VECT_SIZE, - EEPROM_REGS_SIZE = 0x7e, /* words */ - E2P_BASE_OFFSET = EEPROM_START_OFFSET + - EEPROM_REGS_OFFSET, -}; - -#define FW_REG_TABLE_ADDR USB_ADDR(FW_START_OFFSET + 0x1d) - -enum { /* indices for ofdm_cal_values */ OFDM_36M_INDEX = 0, OFDM_48M_INDEX = 1, @@ -679,6 +699,8 @@ struct zd_chip { struct zd_usb usb; struct zd_rf rf; struct mutex mutex; + /* Base address of FW_REG_ registers */ + zd_addr_t fw_regs_base; u8 e2p_mac[ETH_ALEN]; /* EepSetPoint in the vendor driver */ u8 pwr_cal_values[E2P_CHANNEL_COUNT]; diff --git a/drivers/net/wireless/zd1211rw/zd_def.h b/drivers/net/wireless/zd1211rw/zd_def.h index fb22f62..deb99d1 100644 --- a/drivers/net/wireless/zd1211rw/zd_def.h +++ b/drivers/net/wireless/zd1211rw/zd_def.h @@ -23,6 +23,8 @@ #include #include #include +typedef u16 __nocast zd_addr_t; + #define dev_printk_f(level, dev, fmt, args...) \ dev_printk(level, dev, "%s() " fmt, __func__, ##args) diff --git a/drivers/net/wireless/zd1211rw/zd_ieee80211.h b/drivers/net/wireless/zd1211rw/zd_ieee80211.h index 26b8298..c4f36d3 100644 --- a/drivers/net/wireless/zd1211rw/zd_ieee80211.h +++ b/drivers/net/wireless/zd1211rw/zd_ieee80211.h @@ -2,7 +2,6 @@ #ifndef _ZD_IEEE80211_H #define _ZD_IEEE80211_H #include -#include "zd_types.h" /* Additional definitions from the standards. */ diff --git a/drivers/net/wireless/zd1211rw/zd_rf.h b/drivers/net/wireless/zd1211rw/zd_rf.h index 676b373..a57732e 100644 --- a/drivers/net/wireless/zd1211rw/zd_rf.h +++ b/drivers/net/wireless/zd1211rw/zd_rf.h @@ -18,8 +18,6 @@ #ifndef _ZD_RF_H #define _ZD_RF_H -#include "zd_types.h" - #define UW2451_RF 0x2 #define UCHIP_RF 0x3 #define AL2230_RF 0x4 diff --git a/drivers/net/wireless/zd1211rw/zd_types.h b/drivers/net/wireless/zd1211rw/zd_types.h deleted file mode 100644 index 0155a15..0000000 --- a/drivers/net/wireless/zd1211rw/zd_types.h +++ /dev/null @@ -1,71 +0,0 @@ -/* zd_types.h - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#ifndef _ZD_TYPES_H -#define _ZD_TYPES_H - -#include - -/* We have three register spaces mapped into the overall USB address space of - * 64K words (16-bit values). There is the control register space of - * double-word registers, the eeprom register space and the firmware register - * space. The control register space is byte mapped, the others are word - * mapped. - * - * For that reason, we are using byte offsets for control registers and word - * offsets for everything else. - */ - -typedef u32 __nocast zd_addr_t; - -enum { - ADDR_BASE_MASK = 0xff000000, - ADDR_OFFSET_MASK = 0x0000ffff, - ADDR_ZERO_MASK = 0x00ff0000, - NULL_BASE = 0x00000000, - USB_BASE = 0x01000000, - CR_BASE = 0x02000000, - CR_MAX_OFFSET = 0x0b30, - E2P_BASE = 0x03000000, - E2P_MAX_OFFSET = 0x007e, - FW_BASE = 0x04000000, - FW_MAX_OFFSET = 0x0005, -}; - -#define ZD_ADDR_BASE(addr) ((u32)(addr) & ADDR_BASE_MASK) -#define ZD_OFFSET(addr) ((u32)(addr) & ADDR_OFFSET_MASK) - -#define ZD_ADDR(base, offset) \ - ((zd_addr_t)(((base) & ADDR_BASE_MASK) | ((offset) & ADDR_OFFSET_MASK))) - -#define ZD_NULL_ADDR ((zd_addr_t)0) -#define USB_REG(offset) ZD_ADDR(USB_BASE, offset) /* word addressing */ -#define CTL_REG(offset) ZD_ADDR(CR_BASE, offset) /* byte addressing */ -#define E2P_REG(offset) ZD_ADDR(E2P_BASE, offset) /* word addressing */ -#define FW_REG(offset) ZD_ADDR(FW_BASE, offset) /* word addressing */ - -static inline zd_addr_t zd_inc_word(zd_addr_t addr) -{ - u32 base = ZD_ADDR_BASE(addr); - u32 offset = ZD_OFFSET(addr); - - offset += base == CR_BASE ? 2 : 1; - - return base | offset; -} - -#endif /* _ZD_TYPES_H */ diff --git a/drivers/net/wireless/zd1211rw/zd_usb.c b/drivers/net/wireless/zd1211rw/zd_usb.c index 605e96e..75ef556 100644 --- a/drivers/net/wireless/zd1211rw/zd_usb.c +++ b/drivers/net/wireless/zd1211rw/zd_usb.c @@ -58,6 +58,10 @@ static struct usb_device_id usb_ids[] = { USB_DEVICE(0x079b, 0x0062), .driver_info = DEVICE_ZD1211B }, { USB_DEVICE(0x1582, 0x6003), .driver_info = DEVICE_ZD1211B }, { USB_DEVICE(0x050d, 0x705c), .driver_info = DEVICE_ZD1211B }, + { USB_DEVICE(0x083a, 0x4505), .driver_info = DEVICE_ZD1211B }, + { USB_DEVICE(0x0471, 0x1236), .driver_info = DEVICE_ZD1211B }, + { USB_DEVICE(0x13b1, 0x0024), .driver_info = DEVICE_ZD1211B }, + { USB_DEVICE(0x0586, 0x340f), .driver_info = DEVICE_ZD1211B }, /* "Driverless" devices that need ejecting */ { USB_DEVICE(0x0ace, 0x2011), .driver_info = DEVICE_INSTALLER }, {} @@ -73,96 +77,6 @@ MODULE_DEVICE_TABLE(usb, usb_ids); #define FW_ZD1211_PREFIX "zd1211/zd1211_" #define FW_ZD1211B_PREFIX "zd1211/zd1211b_" -/* register address handling */ - -#ifdef DEBUG -static int check_addr(struct zd_usb *usb, zd_addr_t addr) -{ - u32 base = ZD_ADDR_BASE(addr); - u32 offset = ZD_OFFSET(addr); - - if ((u32)addr & ADDR_ZERO_MASK) - goto invalid_address; - switch (base) { - case USB_BASE: - break; - case CR_BASE: - if (offset > CR_MAX_OFFSET) { - dev_dbg(zd_usb_dev(usb), - "CR offset %#010x larger than" - " CR_MAX_OFFSET %#10x\n", - offset, CR_MAX_OFFSET); - goto invalid_address; - } - if (offset & 1) { - dev_dbg(zd_usb_dev(usb), - "CR offset %#010x is not a multiple of 2\n", - offset); - goto invalid_address; - } - break; - case E2P_BASE: - if (offset > E2P_MAX_OFFSET) { - dev_dbg(zd_usb_dev(usb), - "E2P offset %#010x larger than" - " E2P_MAX_OFFSET %#010x\n", - offset, E2P_MAX_OFFSET); - goto invalid_address; - } - break; - case FW_BASE: - if (!usb->fw_base_offset) { - dev_dbg(zd_usb_dev(usb), - "ERROR: fw base offset has not been set\n"); - return -EAGAIN; - } - if (offset > FW_MAX_OFFSET) { - dev_dbg(zd_usb_dev(usb), - "FW offset %#10x is larger than" - " FW_MAX_OFFSET %#010x\n", - offset, FW_MAX_OFFSET); - goto invalid_address; - } - break; - default: - dev_dbg(zd_usb_dev(usb), - "address has unsupported base %#010x\n", addr); - goto invalid_address; - } - - return 0; -invalid_address: - dev_dbg(zd_usb_dev(usb), - "ERROR: invalid address: %#010x\n", addr); - return -EINVAL; -} -#endif /* DEBUG */ - -static u16 usb_addr(struct zd_usb *usb, zd_addr_t addr) -{ - u32 base; - u16 offset; - - base = ZD_ADDR_BASE(addr); - offset = ZD_OFFSET(addr); - - ZD_ASSERT(check_addr(usb, addr) == 0); - - switch (base) { - case CR_BASE: - offset += CR_BASE_OFFSET; - break; - case E2P_BASE: - offset += E2P_BASE_OFFSET; - break; - case FW_BASE: - offset += usb->fw_base_offset; - break; - } - - return offset; -} - /* USB device initialization */ static int request_fw_file( @@ -295,14 +209,13 @@ static int handle_version_mismatch(struc if (r) goto error; - r = upload_code(udev, ur_fw->data, ur_fw->size, FW_START_OFFSET, - REBOOT); + r = upload_code(udev, ur_fw->data, ur_fw->size, FW_START, REBOOT); if (r) goto error; - offset = ((EEPROM_REGS_OFFSET + EEPROM_REGS_SIZE) * sizeof(u16)); + offset = (E2P_BOOT_CODE_OFFSET * sizeof(u16)); r = upload_code(udev, ub_fw->data + offset, ub_fw->size - offset, - E2P_BASE_OFFSET + EEPROM_REGS_SIZE, REBOOT); + E2P_START + E2P_BOOT_CODE_OFFSET, REBOOT); /* At this point, the vendor driver downloads the whole firmware * image, hacks around with version IDs, and uploads it again, @@ -331,7 +244,7 @@ static int upload_firmware(struct usb_de if (r) goto error; - fw_bcdDevice = get_word(ub_fw->data, EEPROM_REGS_OFFSET); + fw_bcdDevice = get_word(ub_fw->data, E2P_DATA_OFFSET); if (fw_bcdDevice != bcdDevice) { dev_info(&udev->dev, @@ -357,8 +270,7 @@ static int upload_firmware(struct usb_de if (r) goto error; - r = upload_code(udev, uph_fw->data, uph_fw->size, FW_START_OFFSET, - REBOOT); + r = upload_code(udev, uph_fw->data, uph_fw->size, FW_START, REBOOT); if (r) { dev_err(&udev->dev, "Could not upload firmware code uph. Error number %d\n", @@ -858,7 +770,7 @@ static inline void init_usb_interrupt(st spin_lock_init(&intr->lock); intr->interval = int_urb_interval(zd_usb_to_usbdev(usb)); init_completion(&intr->read_regs.completion); - intr->read_regs.cr_int_addr = cpu_to_le16(usb_addr(usb, CR_INTERRUPT)); + intr->read_regs.cr_int_addr = cpu_to_le16((u16)CR_INTERRUPT); } static inline void init_usb_rx(struct zd_usb *usb) @@ -890,22 +802,6 @@ void zd_usb_init(struct zd_usb *usb, str init_usb_rx(usb); } -int zd_usb_init_hw(struct zd_usb *usb) -{ - int r; - struct zd_chip *chip = zd_usb_to_chip(usb); - - ZD_ASSERT(mutex_is_locked(&chip->mutex)); - r = zd_ioread16_locked(chip, &usb->fw_base_offset, - USB_REG((u16)FW_BASE_ADDR_OFFSET)); - if (r) - return r; - dev_dbg_f(zd_usb_dev(usb), "fw_base_offset: %#06hx\n", - usb->fw_base_offset); - - return 0; -} - void zd_usb_clear(struct zd_usb *usb) { usb_set_intfdata(usb->intf, NULL); @@ -1253,7 +1149,7 @@ int zd_usb_ioread16v(struct zd_usb *usb, return -ENOMEM; req->id = cpu_to_le16(USB_REQ_READ_REGS); for (i = 0; i < count; i++) - req->addr[i] = cpu_to_le16(usb_addr(usb, addresses[i])); + req->addr[i] = cpu_to_le16((u16)addresses[i]); udev = zd_usb_to_usbdev(usb); prepare_read_regs_int(usb); @@ -1318,7 +1214,7 @@ int zd_usb_iowrite16v(struct zd_usb *usb req->id = cpu_to_le16(USB_REQ_WRITE_REGS); for (i = 0; i < count; i++) { struct reg_data *rw = &req->reg_writes[i]; - rw->addr = cpu_to_le16(usb_addr(usb, ioreqs[i].addr)); + rw->addr = cpu_to_le16((u16)ioreqs[i].addr); rw->value = cpu_to_le16(ioreqs[i].value); } diff --git a/drivers/net/wireless/zd1211rw/zd_usb.h b/drivers/net/wireless/zd1211rw/zd_usb.h index 317d37c..506ea6a 100644 --- a/drivers/net/wireless/zd1211rw/zd_usb.h +++ b/drivers/net/wireless/zd1211rw/zd_usb.h @@ -25,7 +25,6 @@ #include #include #include "zd_def.h" -#include "zd_types.h" enum devicetype { DEVICE_ZD1211 = 0, @@ -181,15 +180,14 @@ struct zd_usb_tx { spinlock_t lock; }; -/* Contains the usb parts. The structure doesn't require a lock, because intf - * and fw_base_offset, will not be changed after initialization. +/* Contains the usb parts. The structure doesn't require a lock because intf + * will not be changed after initialization. */ struct zd_usb { struct zd_usb_interrupt intr; struct zd_usb_rx rx; struct zd_usb_tx tx; struct usb_interface *intf; - u16 fw_base_offset; }; #define zd_usb_dev(usb) (&usb->intf->dev) diff --git a/drivers/oprofile/event_buffer.c b/drivers/oprofile/event_buffer.c index 04d6417..00e937e 100644 --- a/drivers/oprofile/event_buffer.c +++ b/drivers/oprofile/event_buffer.c @@ -181,7 +181,7 @@ out: return retval; } -struct file_operations event_buffer_fops = { +const struct file_operations event_buffer_fops = { .open = event_buffer_open, .release = event_buffer_release, .read = event_buffer_read, diff --git a/drivers/oprofile/event_buffer.h b/drivers/oprofile/event_buffer.h index 9241627..9b6a4eb 100644 --- a/drivers/oprofile/event_buffer.h +++ b/drivers/oprofile/event_buffer.h @@ -41,7 +41,7 @@ #define NO_COOKIE 0UL /* add data to the event buffer */ void add_event_entry(unsigned long data); -extern struct file_operations event_buffer_fops; +extern const struct file_operations event_buffer_fops; /* mutex between sync_cpu_buffers() and the * file reading code. diff --git a/drivers/oprofile/oprofile_files.c b/drivers/oprofile/oprofile_files.c index a72006c..ef953ba 100644 --- a/drivers/oprofile/oprofile_files.c +++ b/drivers/oprofile/oprofile_files.c @@ -44,7 +44,7 @@ static ssize_t depth_write(struct file * } -static struct file_operations depth_fops = { +static const struct file_operations depth_fops = { .read = depth_read, .write = depth_write }; @@ -56,7 +56,7 @@ static ssize_t pointer_size_read(struct } -static struct file_operations pointer_size_fops = { +static const struct file_operations pointer_size_fops = { .read = pointer_size_read, }; @@ -67,7 +67,7 @@ static ssize_t cpu_type_read(struct file } -static struct file_operations cpu_type_fops = { +static const struct file_operations cpu_type_fops = { .read = cpu_type_read, }; @@ -101,7 +101,7 @@ static ssize_t enable_write(struct file } -static struct file_operations enable_fops = { +static const struct file_operations enable_fops = { .read = enable_read, .write = enable_write, }; @@ -114,7 +114,7 @@ static ssize_t dump_write(struct file * } -static struct file_operations dump_fops = { +static const struct file_operations dump_fops = { .write = dump_write, }; diff --git a/drivers/oprofile/oprofilefs.c b/drivers/oprofile/oprofilefs.c index 5756401..6e67b42 100644 --- a/drivers/oprofile/oprofilefs.c +++ b/drivers/oprofile/oprofilefs.c @@ -115,14 +115,14 @@ static int default_open(struct inode * i } -static struct file_operations ulong_fops = { +static const struct file_operations ulong_fops = { .read = ulong_read_file, .write = ulong_write_file, .open = default_open, }; -static struct file_operations ulong_ro_fops = { +static const struct file_operations ulong_ro_fops = { .read = ulong_read_file, .open = default_open, }; @@ -182,7 +182,7 @@ static ssize_t atomic_read_file(struct f } -static struct file_operations atomic_ro_fops = { +static const struct file_operations atomic_ro_fops = { .read = atomic_read_file, .open = default_open, }; diff --git a/drivers/parisc/ccio-dma.c b/drivers/parisc/ccio-dma.c index fe3f5f5..894fdb9 100644 --- a/drivers/parisc/ccio-dma.c +++ b/drivers/parisc/ccio-dma.c @@ -1091,7 +1091,7 @@ static int ccio_proc_info_open(struct in return single_open(file, &ccio_proc_info, NULL); } -static struct file_operations ccio_proc_info_fops = { +static const struct file_operations ccio_proc_info_fops = { .owner = THIS_MODULE, .open = ccio_proc_info_open, .read = seq_read, @@ -1127,7 +1127,7 @@ static int ccio_proc_bitmap_open(struct return single_open(file, &ccio_proc_bitmap_info, NULL); } -static struct file_operations ccio_proc_bitmap_fops = { +static const struct file_operations ccio_proc_bitmap_fops = { .owner = THIS_MODULE, .open = ccio_proc_bitmap_open, .read = seq_read, diff --git a/drivers/parisc/eisa.c b/drivers/parisc/eisa.c index e97cecb..309076b 100644 --- a/drivers/parisc/eisa.c +++ b/drivers/parisc/eisa.c @@ -33,7 +33,6 @@ #include #include #include #include -#include #include #include diff --git a/drivers/parisc/eisa_eeprom.c b/drivers/parisc/eisa_eeprom.c index e13aafa..86e9c84 100644 --- a/drivers/parisc/eisa_eeprom.c +++ b/drivers/parisc/eisa_eeprom.c @@ -97,7 +97,7 @@ static int eisa_eeprom_release(struct in /* * The various file operations we support. */ -static struct file_operations eisa_eeprom_fops = { +static const struct file_operations eisa_eeprom_fops = { .owner = THIS_MODULE, .llseek = eisa_eeprom_llseek, .read = eisa_eeprom_read, diff --git a/drivers/parisc/led.c b/drivers/parisc/led.c index 8dac2ba..9a731c1 100644 --- a/drivers/parisc/led.c +++ b/drivers/parisc/led.c @@ -252,7 +252,6 @@ static int __init led_create_procfs(void proc_pdc_root->owner = THIS_MODULE; ent = create_proc_entry("led", S_IFREG|S_IRUGO|S_IWUSR, proc_pdc_root); if (!ent) return -1; - ent->nlink = 1; ent->data = (void *)LED_NOLCD; /* LED */ ent->read_proc = led_proc_read; ent->write_proc = led_proc_write; @@ -262,7 +261,6 @@ static int __init led_create_procfs(void { ent = create_proc_entry("lcd", S_IFREG|S_IRUGO|S_IWUSR, proc_pdc_root); if (!ent) return -1; - ent->nlink = 1; ent->data = (void *)LED_HASLCD; /* LCD */ ent->read_proc = led_proc_read; ent->write_proc = led_proc_write; diff --git a/drivers/parisc/sba_iommu.c b/drivers/parisc/sba_iommu.c index f1e7ccd..76a29da 100644 --- a/drivers/parisc/sba_iommu.c +++ b/drivers/parisc/sba_iommu.c @@ -1799,7 +1799,7 @@ sba_proc_open(struct inode *i, struct fi return single_open(f, &sba_proc_info, NULL); } -static struct file_operations sba_proc_fops = { +static const struct file_operations sba_proc_fops = { .owner = THIS_MODULE, .open = sba_proc_open, .read = seq_read, @@ -1831,7 +1831,7 @@ sba_proc_bitmap_open(struct inode *i, st return single_open(f, &sba_proc_bitmap_info, NULL); } -static struct file_operations sba_proc_bitmap_fops = { +static const struct file_operations sba_proc_bitmap_fops = { .owner = THIS_MODULE, .open = sba_proc_bitmap_open, .read = seq_read, diff --git a/drivers/parport/parport_cs.c b/drivers/parport/parport_cs.c index e60b4bf..316c06f 100644 --- a/drivers/parport/parport_cs.c +++ b/drivers/parport/parport_cs.c @@ -37,7 +37,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/parport/parport_gsc.c b/drivers/parport/parport_gsc.c index a7c5ead..17bf993 100644 --- a/drivers/parport/parport_gsc.c +++ b/drivers/parport/parport_gsc.c @@ -23,7 +23,6 @@ #undef DEBUG /* undef for production */ #include #include -#include #include #include #include diff --git a/drivers/parport/procfs.c b/drivers/parport/procfs.c index 2e744a2..bdbdab9 100644 --- a/drivers/parport/procfs.c +++ b/drivers/parport/procfs.c @@ -233,12 +233,12 @@ #undef printmode return copy_to_user(result, buffer, len) ? -EFAULT : 0; } -#define PARPORT_PORT_DIR(child) { 0, NULL, NULL, 0, 0555, child } -#define PARPORT_PARPORT_DIR(child) { DEV_PARPORT, "parport", \ - NULL, 0, 0555, child } -#define PARPORT_DEV_DIR(child) { CTL_DEV, "dev", NULL, 0, 0555, child } -#define PARPORT_DEVICES_ROOT_DIR { DEV_PARPORT_DEVICES, "devices", \ - NULL, 0, 0555, NULL } +#define PARPORT_PORT_DIR(CHILD) { .ctl_name = 0, .procname = NULL, .mode = 0555, .child = CHILD } +#define PARPORT_PARPORT_DIR(CHILD) { .ctl_name = DEV_PARPORT, .procname = "parport", \ + .mode = 0555, .child = CHILD } +#define PARPORT_DEV_DIR(CHILD) { .ctl_name = CTL_DEV, .procname = "dev", .mode = 0555, .child = CHILD } +#define PARPORT_DEVICES_ROOT_DIR { .ctl_name = DEV_PARPORT_DEVICES, .procname = "devices", \ + .mode = 0555, .child = NULL } static const unsigned long parport_min_timeslice_value = PARPORT_MIN_TIMESLICE_VALUE; @@ -263,50 +263,118 @@ struct parport_sysctl_table { }; static const struct parport_sysctl_table parport_sysctl_template = { - NULL, + .sysctl_header = NULL, { - { DEV_PARPORT_SPINTIME, "spintime", - NULL, sizeof(int), 0644, NULL, - &proc_dointvec_minmax, NULL, NULL, - (void*) &parport_min_spintime_value, - (void*) &parport_max_spintime_value }, - { DEV_PARPORT_BASE_ADDR, "base-addr", - NULL, 0, 0444, NULL, - &do_hardware_base_addr }, - { DEV_PARPORT_IRQ, "irq", - NULL, 0, 0444, NULL, - &do_hardware_irq }, - { DEV_PARPORT_DMA, "dma", - NULL, 0, 0444, NULL, - &do_hardware_dma }, - { DEV_PARPORT_MODES, "modes", - NULL, 0, 0444, NULL, - &do_hardware_modes }, + { + .ctl_name = DEV_PARPORT_SPINTIME, + .procname = "spintime", + .data = NULL, + .maxlen = sizeof(int), + .mode = 0644, + .proc_handler = &proc_dointvec_minmax, + .extra1 = (void*) &parport_min_spintime_value, + .extra2 = (void*) &parport_max_spintime_value + }, + { + .ctl_name = DEV_PARPORT_BASE_ADDR, + .procname = "base-addr", + .data = NULL, + .maxlen = 0, + .mode = 0444, + .proc_handler = &do_hardware_base_addr + }, + { + .ctl_name = DEV_PARPORT_IRQ, + .procname = "irq", + .data = NULL, + .maxlen = 0, + .mode = 0444, + .proc_handler = &do_hardware_irq + }, + { + .ctl_name = DEV_PARPORT_DMA, + .procname = "dma", + .data = NULL, + .maxlen = 0, + .mode = 0444, + .proc_handler = &do_hardware_dma + }, + { + .ctl_name = DEV_PARPORT_MODES, + .procname = "modes", + .data = NULL, + .maxlen = 0, + .mode = 0444, + .proc_handler = &do_hardware_modes + }, PARPORT_DEVICES_ROOT_DIR, #ifdef CONFIG_PARPORT_1284 - { DEV_PARPORT_AUTOPROBE, "autoprobe", - NULL, 0, 0444, NULL, - &do_autoprobe }, - { DEV_PARPORT_AUTOPROBE + 1, "autoprobe0", - NULL, 0, 0444, NULL, - &do_autoprobe }, - { DEV_PARPORT_AUTOPROBE + 2, "autoprobe1", - NULL, 0, 0444, NULL, - &do_autoprobe }, - { DEV_PARPORT_AUTOPROBE + 3, "autoprobe2", - NULL, 0, 0444, NULL, - &do_autoprobe }, - { DEV_PARPORT_AUTOPROBE + 4, "autoprobe3", - NULL, 0, 0444, NULL, - &do_autoprobe }, + { + .ctl_name = DEV_PARPORT_AUTOPROBE, + .procname = "autoprobe", + .data = NULL, + .maxlen = 0, + .mode = 0444, + .proc_handler = &do_autoprobe + }, + { + .ctl_name = DEV_PARPORT_AUTOPROBE + 1, + .procname = "autoprobe0", + .data = NULL, + .maxlen = 0, + .mode = 0444, + .proc_handler = &do_autoprobe + }, + { + .ctl_name = DEV_PARPORT_AUTOPROBE + 2, + .procname = "autoprobe1", + .data = NULL, + .maxlen = 0, + .mode = 0444, + .proc_handler = &do_autoprobe + }, + { + .ctl_name = DEV_PARPORT_AUTOPROBE + 3, + .procname = "autoprobe2", + .data = NULL, + .maxlen = 0, + .mode = 0444, + .proc_handler = &do_autoprobe + }, + { + .ctl_name = DEV_PARPORT_AUTOPROBE + 4, + .procname = "autoprobe3", + .data = NULL, + .maxlen = 0, + .mode = 0444, + .proc_handler = &do_autoprobe + }, #endif /* IEEE 1284 support */ - {0} + {} }, - { {DEV_PARPORT_DEVICES_ACTIVE, "active", NULL, 0, 0444, NULL, - &do_active_device }, {0}}, - { PARPORT_PORT_DIR(NULL), {0}}, - { PARPORT_PARPORT_DIR(NULL), {0}}, - { PARPORT_DEV_DIR(NULL), {0}} + { + { + .ctl_name = DEV_PARPORT_DEVICES_ACTIVE, + .procname = "active", + .data = NULL, + .maxlen = 0, + .mode = 0444, + .proc_handler = &do_active_device + }, + {} + }, + { + PARPORT_PORT_DIR(NULL), + {} + }, + { + PARPORT_PARPORT_DIR(NULL), + {} + }, + { + PARPORT_DEV_DIR(NULL), + {} + } }; struct parport_device_sysctl_table @@ -322,19 +390,46 @@ struct parport_device_sysctl_table static const struct parport_device_sysctl_table parport_device_sysctl_template = { - NULL, + .sysctl_header = NULL, + { + { + .ctl_name = DEV_PARPORT_DEVICE_TIMESLICE, + .procname = "timeslice", + .data = NULL, + .maxlen = sizeof(int), + .mode = 0644, + .proc_handler = &proc_doulongvec_ms_jiffies_minmax, + .extra1 = (void*) &parport_min_timeslice_value, + .extra2 = (void*) &parport_max_timeslice_value + }, + }, + { + { + .ctl_name = 0, + .procname = NULL, + .data = NULL, + .maxlen = 0, + .mode = 0555, + .child = NULL + }, + {} + }, { - { DEV_PARPORT_DEVICE_TIMESLICE, "timeslice", - NULL, sizeof(int), 0644, NULL, - &proc_doulongvec_ms_jiffies_minmax, NULL, NULL, - (void*) &parport_min_timeslice_value, - (void*) &parport_max_timeslice_value }, + PARPORT_DEVICES_ROOT_DIR, + {} + }, + { + PARPORT_PORT_DIR(NULL), + {} }, - { {0, NULL, NULL, 0, 0555, NULL}, {0}}, - { PARPORT_DEVICES_ROOT_DIR, {0}}, - { PARPORT_PORT_DIR(NULL), {0}}, - { PARPORT_PARPORT_DIR(NULL), {0}}, - { PARPORT_DEV_DIR(NULL), {0}} + { + PARPORT_PARPORT_DIR(NULL), + {} + }, + { + PARPORT_DEV_DIR(NULL), + {} + } }; struct parport_default_sysctl_table @@ -351,28 +446,47 @@ extern int parport_default_spintime; static struct parport_default_sysctl_table parport_default_sysctl_table = { - NULL, + .sysctl_header = NULL, + { + { + .ctl_name = DEV_PARPORT_DEFAULT_TIMESLICE, + .procname = "timeslice", + .data = &parport_default_timeslice, + .maxlen = sizeof(parport_default_timeslice), + .mode = 0644, + .proc_handler = &proc_doulongvec_ms_jiffies_minmax, + .extra1 = (void*) &parport_min_timeslice_value, + .extra2 = (void*) &parport_max_timeslice_value + }, + { + .ctl_name = DEV_PARPORT_DEFAULT_SPINTIME, + .procname = "spintime", + .data = &parport_default_spintime, + .maxlen = sizeof(parport_default_spintime), + .mode = 0644, + .proc_handler = &proc_dointvec_minmax, + .extra1 = (void*) &parport_min_spintime_value, + .extra2 = (void*) &parport_max_spintime_value + }, + {} + }, { - { DEV_PARPORT_DEFAULT_TIMESLICE, "timeslice", - &parport_default_timeslice, - sizeof(parport_default_timeslice), 0644, NULL, - &proc_doulongvec_ms_jiffies_minmax, NULL, NULL, - (void*) &parport_min_timeslice_value, - (void*) &parport_max_timeslice_value }, - { DEV_PARPORT_DEFAULT_SPINTIME, "spintime", - &parport_default_spintime, - sizeof(parport_default_spintime), 0644, NULL, - &proc_dointvec_minmax, NULL, NULL, - (void*) &parport_min_spintime_value, - (void*) &parport_max_spintime_value }, - {0} + { + .ctl_name = DEV_PARPORT_DEFAULT, + .procname = "default", + .mode = 0555, + .child = parport_default_sysctl_table.vars + }, + {} }, - { { DEV_PARPORT_DEFAULT, "default", NULL, 0, 0555, - parport_default_sysctl_table.vars },{0}}, { - PARPORT_PARPORT_DIR(parport_default_sysctl_table.default_dir), - {0}}, - { PARPORT_DEV_DIR(parport_default_sysctl_table.parport_dir), {0}} + PARPORT_PARPORT_DIR(parport_default_sysctl_table.default_dir), + {} + }, + { + PARPORT_DEV_DIR(parport_default_sysctl_table.parport_dir), + {} + } }; @@ -404,7 +518,7 @@ int parport_proc_register(struct parport t->parport_dir[0].child = t->port_dir; t->dev_dir[0].child = t->parport_dir; - t->sysctl_header = register_sysctl_table(t->dev_dir, 0); + t->sysctl_header = register_sysctl_table(t->dev_dir); if (t->sysctl_header == NULL) { kfree(t); t = NULL; @@ -460,7 +574,7 @@ #endif /* IEEE 1284 support or not */ t->device_dir[0].child = t->vars; t->vars[0].data = &device->timeslice; - t->sysctl_header = register_sysctl_table(t->dev_dir, 0); + t->sysctl_header = register_sysctl_table(t->dev_dir); if (t->sysctl_header == NULL) { kfree(t); t = NULL; @@ -483,7 +597,7 @@ int parport_device_proc_unregister(struc static int __init parport_default_proc_register(void) { parport_default_sysctl_table.sysctl_header = - register_sysctl_table(parport_default_sysctl_table.dev_dir, 0); + register_sysctl_table(parport_default_sysctl_table.dev_dir); return 0; } diff --git a/drivers/pci/Kconfig b/drivers/pci/Kconfig index 3cfb0a3..5ea5bc7 100644 --- a/drivers/pci/Kconfig +++ b/drivers/pci/Kconfig @@ -4,7 +4,7 @@ # config PCI_MSI bool "Message Signaled Interrupts (MSI and MSI-X)" depends on PCI - depends on (X86_LOCAL_APIC && X86_IO_APIC) || IA64 + depends on (X86_LOCAL_APIC && X86_IO_APIC) || IA64 || SPARC64 help This allows device drivers to enable MSI (Message Signaled Interrupts). Message Signaled Interrupts enable a device to diff --git a/drivers/pci/hotplug/Kconfig b/drivers/pci/hotplug/Kconfig index adce420..be92695 100644 --- a/drivers/pci/hotplug/Kconfig +++ b/drivers/pci/hotplug/Kconfig @@ -145,15 +145,6 @@ config HOTPLUG_PCI_SHPC When in doubt, say N. -config HOTPLUG_PCI_SHPC_POLL_EVENT_MODE - bool "Use polling mechanism for hot-plug events (for testing purpose)" - depends on HOTPLUG_PCI_SHPC - help - Say Y here if you want to use the polling mechanism for hot-plug - events for early platform testing. - - When in doubt, say N. - config HOTPLUG_PCI_RPA tristate "RPA PCI Hotplug driver" depends on HOTPLUG_PCI && PPC_PSERIES && PPC64 && !HOTPLUG_PCI_FAKE diff --git a/drivers/pci/hotplug/acpiphp_glue.c b/drivers/pci/hotplug/acpiphp_glue.c index bd1faeb..fca978f 100644 --- a/drivers/pci/hotplug/acpiphp_glue.c +++ b/drivers/pci/hotplug/acpiphp_glue.c @@ -773,13 +773,13 @@ static int get_gsi_base(acpi_handle hand goto out; table = obj->buffer.pointer; - switch (((acpi_table_entry_header *)table)->type) { - case ACPI_MADT_IOSAPIC: - *gsi_base = ((struct acpi_table_iosapic *)table)->global_irq_base; + switch (((struct acpi_subtable_header *)table)->type) { + case ACPI_MADT_TYPE_IO_SAPIC: + *gsi_base = ((struct acpi_madt_io_sapic *)table)->global_irq_base; result = 0; break; - case ACPI_MADT_IOAPIC: - *gsi_base = ((struct acpi_table_ioapic *)table)->global_irq_base; + case ACPI_MADT_TYPE_IO_APIC: + *gsi_base = ((struct acpi_madt_io_apic *)table)->global_irq_base; result = 0; break; default: diff --git a/drivers/pci/hotplug/cpqphp_sysfs.c b/drivers/pci/hotplug/cpqphp_sysfs.c index 634f74d..a13abf5 100644 --- a/drivers/pci/hotplug/cpqphp_sysfs.c +++ b/drivers/pci/hotplug/cpqphp_sysfs.c @@ -202,7 +202,7 @@ static int release(struct inode *inode, return 0; } -static struct file_operations debug_ops = { +static const struct file_operations debug_ops = { .owner = THIS_MODULE, .open = open, .llseek = lseek, diff --git a/drivers/pci/hotplug/ibmphp_ebda.c b/drivers/pci/hotplug/ibmphp_ebda.c index 05e4f5a..600ed7b 100644 --- a/drivers/pci/hotplug/ibmphp_ebda.c +++ b/drivers/pci/hotplug/ibmphp_ebda.c @@ -28,7 +28,6 @@ */ #include -#include #include #include #include diff --git a/drivers/pci/hotplug/pciehp.h b/drivers/pci/hotplug/pciehp.h index 4fb12fc..d19fcae 100644 --- a/drivers/pci/hotplug/pciehp.h +++ b/drivers/pci/hotplug/pciehp.h @@ -44,15 +44,20 @@ extern int pciehp_poll_time; extern int pciehp_debug; extern int pciehp_force; -/*#define dbg(format, arg...) do { if (pciehp_debug) printk(KERN_DEBUG "%s: " format, MY_NAME , ## arg); } while (0)*/ -#define dbg(format, arg...) do { if (pciehp_debug) printk("%s: " format, MY_NAME , ## arg); } while (0) -#define err(format, arg...) printk(KERN_ERR "%s: " format, MY_NAME , ## arg) -#define info(format, arg...) printk(KERN_INFO "%s: " format, MY_NAME , ## arg) -#define warn(format, arg...) printk(KERN_WARNING "%s: " format, MY_NAME , ## arg) - +#define dbg(format, arg...) \ + do { \ + if (pciehp_debug) \ + printk("%s: " format, MY_NAME , ## arg); \ + } while (0) +#define err(format, arg...) \ + printk(KERN_ERR "%s: " format, MY_NAME , ## arg) +#define info(format, arg...) \ + printk(KERN_INFO "%s: " format, MY_NAME , ## arg) +#define warn(format, arg...) \ + printk(KERN_WARNING "%s: " format, MY_NAME , ## arg) +#define SLOT_NAME_SIZE 10 struct slot { - struct slot *next; u8 bus; u8 device; u32 number; @@ -63,6 +68,8 @@ struct slot { struct hpc_ops *hpc_ops; struct hotplug_slot *hotplug_slot; struct list_head slot_list; + char name[SLOT_NAME_SIZE]; + unsigned long last_emi_toggle; }; struct event_info { @@ -70,34 +77,15 @@ struct event_info { u8 hp_slot; }; -typedef u8(*php_intr_callback_t) (u8 hp_slot, void *instance_id); - -struct php_ctlr_state_s { - struct php_ctlr_state_s *pnext; - struct pci_dev *pci_dev; - unsigned int irq; - unsigned long flags; /* spinlock's */ - u32 slot_device_offset; - u32 num_slots; - struct timer_list int_poll_timer; /* Added for poll event */ - php_intr_callback_t attention_button_callback; - php_intr_callback_t switch_change_callback; - php_intr_callback_t presence_change_callback; - php_intr_callback_t power_fault_callback; - void *callback_instance_id; - struct ctrl_reg *creg; /* Ptr to controller register space */ -}; - #define MAX_EVENTS 10 struct controller { struct controller *next; struct mutex crit_sect; /* critical section mutex */ struct mutex ctrl_lock; /* controller lock */ - struct php_ctlr_state_s *hpc_ctlr_handle; /* HPC controller handle */ int num_slots; /* Number of slots on ctlr */ int slot_num_inc; /* 1 or -1 */ struct pci_dev *pci_dev; - struct pci_bus *pci_bus; + struct list_head slot_list; struct event_info event_queue[MAX_EVENTS]; struct slot *slot; struct hpc_ops *hpc_ops; @@ -112,6 +100,8 @@ struct controller { u8 ctrlcap; u16 vendor_id; u8 cap_base; + struct timer_list poll_timer; + volatile int cmd_busy; }; #define INT_BUTTON_IGNORE 0 @@ -131,8 +121,6 @@ #define BLINKINGOFF_STATE 2 #define POWERON_STATE 3 #define POWEROFF_STATE 4 -#define PCI_TO_PCI_BRIDGE_CLASS 0x00060400 - /* Error messages */ #define INTERLOCK_OPEN 0x00000002 #define ADD_NOT_SUPPORTED 0x00000003 @@ -144,10 +132,6 @@ #define DEVICE_TYPE_NOT_SUPPORTED 0x0000 #define WRONG_BUS_FREQUENCY 0x0000000D #define POWER_FAILURE 0x0000000E -#define REMOVE_NOT_SUPPORTED 0x00000003 - -#define DISABLE_CARD 1 - /* Field definitions in Slot Capabilities Register */ #define ATTN_BUTTN_PRSN 0x00000001 #define PWR_CTRL_PRSN 0x00000002 @@ -155,6 +139,7 @@ #define MRL_SENS_PRSN 0x00000004 #define ATTN_LED_PRSN 0x00000008 #define PWR_LED_PRSN 0x00000010 #define HP_SUPR_RM_SUP 0x00000020 +#define EMI_PRSN 0x00020000 #define ATTN_BUTTN(cap) (cap & ATTN_BUTTN_PRSN) #define POWER_CTRL(cap) (cap & PWR_CTRL_PRSN) @@ -162,130 +147,65 @@ #define MRL_SENS(cap) (cap & MRL_SENS_P #define ATTN_LED(cap) (cap & ATTN_LED_PRSN) #define PWR_LED(cap) (cap & PWR_LED_PRSN) #define HP_SUPR_RM(cap) (cap & HP_SUPR_RM_SUP) - -/* - * error Messages - */ -#define msg_initialization_err "Initialization failure, error=%d\n" -#define msg_button_on "PCI slot #%s - powering on due to button press.\n" -#define msg_button_off "PCI slot #%s - powering off due to button press.\n" -#define msg_button_cancel "PCI slot #%s - action canceled due to button press.\n" -#define msg_button_ignore "PCI slot #%s - button press ignored. (action in progress...)\n" - -/* controller functions */ -extern int pciehp_event_start_thread (void); -extern void pciehp_event_stop_thread (void); -extern int pciehp_enable_slot (struct slot *slot); -extern int pciehp_disable_slot (struct slot *slot); - -extern u8 pciehp_handle_attention_button (u8 hp_slot, void *inst_id); -extern u8 pciehp_handle_switch_change (u8 hp_slot, void *inst_id); -extern u8 pciehp_handle_presence_change (u8 hp_slot, void *inst_id); -extern u8 pciehp_handle_power_fault (u8 hp_slot, void *inst_id); -/* extern void long_delay (int delay); */ - -/* pci functions */ -extern int pciehp_configure_device (struct slot *p_slot); -extern int pciehp_unconfigure_device (struct slot *p_slot); - - +#define EMI(cap) (cap & EMI_PRSN) + +extern int pciehp_event_start_thread(void); +extern void pciehp_event_stop_thread(void); +extern int pciehp_enable_slot(struct slot *slot); +extern int pciehp_disable_slot(struct slot *slot); +extern u8 pciehp_handle_attention_button(u8 hp_slot, struct controller *ctrl); +extern u8 pciehp_handle_switch_change(u8 hp_slot, struct controller *ctrl); +extern u8 pciehp_handle_presence_change(u8 hp_slot, struct controller *ctrl); +extern u8 pciehp_handle_power_fault(u8 hp_slot, struct controller *ctrl); +extern int pciehp_configure_device(struct slot *p_slot); +extern int pciehp_unconfigure_device(struct slot *p_slot); +int pcie_init(struct controller *ctrl, struct pcie_device *dev); /* Global variables */ extern struct controller *pciehp_ctrl_list; -/* Inline functions */ - static inline struct slot *pciehp_find_slot(struct controller *ctrl, u8 device) { - struct slot *p_slot, *tmp_slot = NULL; - - p_slot = ctrl->slot; + struct slot *slot; - while (p_slot && (p_slot->device != device)) { - tmp_slot = p_slot; - p_slot = p_slot->next; + list_for_each_entry(slot, &ctrl->slot_list, slot_list) { + if (slot->device == device) + return slot; } - if (p_slot == NULL) { - err("ERROR: pciehp_find_slot device=0x%x\n", device); - p_slot = tmp_slot; - } - - return p_slot; -} - -static inline int wait_for_ctrl_irq(struct controller *ctrl) -{ - int retval = 0; - - DECLARE_WAITQUEUE(wait, current); - - add_wait_queue(&ctrl->queue, &wait); - if (!pciehp_poll_mode) - /* Sleep for up to 1 second */ - msleep_interruptible(1000); - else - msleep_interruptible(2500); - - remove_wait_queue(&ctrl->queue, &wait); - if (signal_pending(current)) - retval = -EINTR; - - return retval; -} - -#define SLOT_NAME_SIZE 10 -static inline void make_slot_name(char *buffer, int buffer_size, struct slot *slot) -{ - snprintf(buffer, buffer_size, "%04d_%04d", slot->bus, slot->number); + err("%s: slot (device=0x%x) not found\n", __FUNCTION__, device); + return NULL; } -enum php_ctlr_type { - PCI, - ISA, - ACPI -}; - -int pcie_init(struct controller *ctrl, struct pcie_device *dev); - -/* This has no meaning for PCI Express, as there is only 1 slot per port */ -int pcie_get_ctlr_slot_config(struct controller *ctrl, - int *num_ctlr_slots, - int *first_device_num, - int *physical_slot_num, - u8 *ctrlcap); - struct hpc_ops { - int (*power_on_slot) (struct slot *slot); - int (*power_off_slot) (struct slot *slot); - int (*get_power_status) (struct slot *slot, u8 *status); - int (*get_attention_status) (struct slot *slot, u8 *status); - int (*set_attention_status) (struct slot *slot, u8 status); - int (*get_latch_status) (struct slot *slot, u8 *status); - int (*get_adapter_status) (struct slot *slot, u8 *status); - - int (*get_max_bus_speed) (struct slot *slot, enum pci_bus_speed *speed); - int (*get_cur_bus_speed) (struct slot *slot, enum pci_bus_speed *speed); - - int (*get_max_lnk_width) (struct slot *slot, enum pcie_link_width *value); - int (*get_cur_lnk_width) (struct slot *slot, enum pcie_link_width *value); - - int (*query_power_fault) (struct slot *slot); - void (*green_led_on) (struct slot *slot); - void (*green_led_off) (struct slot *slot); - void (*green_led_blink) (struct slot *slot); - void (*release_ctlr) (struct controller *ctrl); - int (*check_lnk_status) (struct controller *ctrl); + int (*power_on_slot)(struct slot *slot); + int (*power_off_slot)(struct slot *slot); + int (*get_power_status)(struct slot *slot, u8 *status); + int (*get_attention_status)(struct slot *slot, u8 *status); + int (*set_attention_status)(struct slot *slot, u8 status); + int (*get_latch_status)(struct slot *slot, u8 *status); + int (*get_adapter_status)(struct slot *slot, u8 *status); + int (*get_emi_status)(struct slot *slot, u8 *status); + int (*toggle_emi)(struct slot *slot); + int (*get_max_bus_speed)(struct slot *slot, enum pci_bus_speed *speed); + int (*get_cur_bus_speed)(struct slot *slot, enum pci_bus_speed *speed); + int (*get_max_lnk_width)(struct slot *slot, enum pcie_link_width *val); + int (*get_cur_lnk_width)(struct slot *slot, enum pcie_link_width *val); + int (*query_power_fault)(struct slot *slot); + void (*green_led_on)(struct slot *slot); + void (*green_led_off)(struct slot *slot); + void (*green_led_blink)(struct slot *slot); + void (*release_ctlr)(struct controller *ctrl); + int (*check_lnk_status)(struct controller *ctrl); }; - #ifdef CONFIG_ACPI #include #include #include #include -#define pciehp_get_hp_hw_control_from_firmware(dev) \ +#define pciehp_get_hp_hw_control_from_firmware(dev) \ pciehp_acpi_get_hp_hw_control_from_firmware(dev) static inline int pciehp_get_hp_params_from_firmware(struct pci_dev *dev, struct hotplug_params *hpp) diff --git a/drivers/pci/hotplug/pciehp_core.c b/drivers/pci/hotplug/pciehp_core.c index f13f313..a92eda6 100644 --- a/drivers/pci/hotplug/pciehp_core.c +++ b/drivers/pci/hotplug/pciehp_core.c @@ -34,6 +34,7 @@ #include #include #include "pciehp.h" #include +#include /* Global variables */ int pciehp_debug; @@ -87,6 +88,95 @@ static struct hotplug_slot_ops pciehp_ho .get_cur_bus_speed = get_cur_bus_speed, }; +/* + * Check the status of the Electro Mechanical Interlock (EMI) + */ +static int get_lock_status(struct hotplug_slot *hotplug_slot, u8 *value) +{ + struct slot *slot = hotplug_slot->private; + return (slot->hpc_ops->get_emi_status(slot, value)); +} + +/* + * sysfs interface for the Electro Mechanical Interlock (EMI) + * 1 == locked, 0 == unlocked + */ +static ssize_t lock_read_file(struct hotplug_slot *slot, char *buf) +{ + int retval; + u8 value; + + retval = get_lock_status(slot, &value); + if (retval) + goto lock_read_exit; + retval = sprintf (buf, "%d\n", value); + +lock_read_exit: + return retval; +} + +/* + * Change the status of the Electro Mechanical Interlock (EMI) + * This is a toggle - in addition there must be at least 1 second + * in between toggles. + */ +static int set_lock_status(struct hotplug_slot *hotplug_slot, u8 status) +{ + struct slot *slot = hotplug_slot->private; + int retval; + u8 value; + + mutex_lock(&slot->ctrl->crit_sect); + + /* has it been >1 sec since our last toggle? */ + if ((get_seconds() - slot->last_emi_toggle) < 1) + return -EINVAL; + + /* see what our current state is */ + retval = get_lock_status(hotplug_slot, &value); + if (retval || (value == status)) + goto set_lock_exit; + + slot->hpc_ops->toggle_emi(slot); +set_lock_exit: + mutex_unlock(&slot->ctrl->crit_sect); + return 0; +} + +/* + * sysfs interface which allows the user to toggle the Electro Mechanical + * Interlock. Valid values are either 0 or 1. 0 == unlock, 1 == lock + */ +static ssize_t lock_write_file(struct hotplug_slot *slot, const char *buf, + size_t count) +{ + unsigned long llock; + u8 lock; + int retval = 0; + + llock = simple_strtoul(buf, NULL, 10); + lock = (u8)(llock & 0xff); + + switch (lock) { + case 0: + case 1: + retval = set_lock_status(slot, lock); + break; + default: + err ("%d is an invalid lock value\n", lock); + retval = -EINVAL; + } + if (retval) + return retval; + return count; +} + +static struct hotplug_slot_attribute hotplug_slot_attr_lock = { + .attr = {.name = "lock", .mode = S_IFREG | S_IRUGO | S_IWUSR}, + .show = lock_read_file, + .store = lock_write_file +}; + /** * release_slot - free up the memory used by a slot * @hotplug_slot: slot to free @@ -98,148 +188,108 @@ static void release_slot(struct hotplug_ dbg("%s - physical_slot = %s\n", __FUNCTION__, hotplug_slot->name); kfree(slot->hotplug_slot->info); - kfree(slot->hotplug_slot->name); kfree(slot->hotplug_slot); kfree(slot); } +static void make_slot_name(struct slot *slot) +{ + snprintf(slot->hotplug_slot->name, SLOT_NAME_SIZE, "%04d_%04d", + slot->bus, slot->number); +} + static int init_slots(struct controller *ctrl) { struct slot *slot; - struct hpc_ops *hpc_ops; struct hotplug_slot *hotplug_slot; - struct hotplug_slot_info *hotplug_slot_info; - u8 number_of_slots; - u8 slot_device; - u32 slot_number; - int result = -ENOMEM; + struct hotplug_slot_info *info; + int retval = -ENOMEM; + int i; - number_of_slots = ctrl->num_slots; - slot_device = ctrl->slot_device_offset; - slot_number = ctrl->first_slot; - - while (number_of_slots) { + for (i = 0; i < ctrl->num_slots; i++) { slot = kzalloc(sizeof(*slot), GFP_KERNEL); if (!slot) goto error; - slot->hotplug_slot = - kzalloc(sizeof(*(slot->hotplug_slot)), - GFP_KERNEL); - if (!slot->hotplug_slot) + hotplug_slot = kzalloc(sizeof(*hotplug_slot), GFP_KERNEL); + if (!hotplug_slot) goto error_slot; - hotplug_slot = slot->hotplug_slot; + slot->hotplug_slot = hotplug_slot; - hotplug_slot->info = - kzalloc(sizeof(*(hotplug_slot->info)), - GFP_KERNEL); - if (!hotplug_slot->info) + info = kzalloc(sizeof(*info), GFP_KERNEL); + if (!info) goto error_hpslot; - hotplug_slot_info = hotplug_slot->info; - hotplug_slot->name = kmalloc(SLOT_NAME_SIZE, GFP_KERNEL); - if (!hotplug_slot->name) - goto error_info; + hotplug_slot->info = info; - slot->ctrl = ctrl; - slot->bus = ctrl->slot_bus; - slot->device = slot_device; - slot->hpc_ops = hpc_ops = ctrl->hpc_ops; + hotplug_slot->name = slot->name; + slot->hp_slot = i; + slot->ctrl = ctrl; + slot->bus = ctrl->pci_dev->subordinate->number; + slot->device = ctrl->slot_device_offset + i; + slot->hpc_ops = ctrl->hpc_ops; slot->number = ctrl->first_slot; - slot->hp_slot = slot_device - ctrl->slot_device_offset; /* register this slot with the hotplug pci core */ hotplug_slot->private = slot; hotplug_slot->release = &release_slot; - make_slot_name(hotplug_slot->name, SLOT_NAME_SIZE, slot); + make_slot_name(slot); hotplug_slot->ops = &pciehp_hotplug_slot_ops; - hpc_ops->get_power_status(slot, - &(hotplug_slot_info->power_status)); - hpc_ops->get_attention_status(slot, - &(hotplug_slot_info->attention_status)); - hpc_ops->get_latch_status(slot, - &(hotplug_slot_info->latch_status)); - hpc_ops->get_adapter_status(slot, - &(hotplug_slot_info->adapter_status)); + get_power_status(hotplug_slot, &info->power_status); + get_attention_status(hotplug_slot, &info->attention_status); + get_latch_status(hotplug_slot, &info->latch_status); + get_adapter_status(hotplug_slot, &info->adapter_status); dbg("Registering bus=%x dev=%x hp_slot=%x sun=%x " - "slot_device_offset=%x\n", - slot->bus, slot->device, slot->hp_slot, slot->number, - ctrl->slot_device_offset); - result = pci_hp_register(hotplug_slot); - if (result) { - err ("pci_hp_register failed with error %d\n", result); - goto error_name; + "slot_device_offset=%x\n", slot->bus, slot->device, + slot->hp_slot, slot->number, ctrl->slot_device_offset); + retval = pci_hp_register(hotplug_slot); + if (retval) { + err ("pci_hp_register failed with error %d\n", retval); + goto error_info; + } + /* create additional sysfs entries */ + if (EMI(ctrl->ctrlcap)) { + retval = sysfs_create_file(&hotplug_slot->kobj, + &hotplug_slot_attr_lock.attr); + if (retval) { + pci_hp_deregister(hotplug_slot); + err("cannot create additional sysfs entries\n"); + goto error_info; + } } - slot->next = ctrl->slot; - ctrl->slot = slot; - - number_of_slots--; - slot_device++; - slot_number += ctrl->slot_num_inc; + list_add(&slot->slot_list, &ctrl->slot_list); } return 0; - -error_name: - kfree(hotplug_slot->name); error_info: - kfree(hotplug_slot_info); + kfree(info); error_hpslot: kfree(hotplug_slot); error_slot: kfree(slot); error: - return result; -} - - -static int cleanup_slots (struct controller * ctrl) -{ - struct slot *old_slot, *next_slot; - - old_slot = ctrl->slot; - ctrl->slot = NULL; - - while (old_slot) { - next_slot = old_slot->next; - pci_hp_deregister (old_slot->hotplug_slot); - old_slot = next_slot; - } - - - return(0); + return retval; } -static int get_ctlr_slot_config(struct controller *ctrl) +static void cleanup_slots(struct controller *ctrl) { - int num_ctlr_slots; /* Not needed; PCI Express has 1 slot per port*/ - int first_device_num; /* Not needed */ - int physical_slot_num; - u8 ctrlcap; - int rc; + struct list_head *tmp; + struct list_head *next; + struct slot *slot; - rc = pcie_get_ctlr_slot_config(ctrl, &num_ctlr_slots, &first_device_num, &physical_slot_num, &ctrlcap); - if (rc) { - err("%s: get_ctlr_slot_config fail for b:d (%x:%x)\n", __FUNCTION__, ctrl->bus, ctrl->device); - return (-1); + list_for_each_safe(tmp, next, &ctrl->slot_list) { + slot = list_entry(tmp, struct slot, slot_list); + list_del(&slot->slot_list); + if (EMI(ctrl->ctrlcap)) + sysfs_remove_file(&slot->hotplug_slot->kobj, + &hotplug_slot_attr_lock.attr); + pci_hp_deregister(slot->hotplug_slot); } - - ctrl->num_slots = num_ctlr_slots; /* PCI Express has 1 slot per port */ - ctrl->slot_device_offset = first_device_num; - ctrl->first_slot = physical_slot_num; - ctrl->ctrlcap = ctrlcap; - - dbg("%s: bus(0x%x) num_slot(0x%x) 1st_dev(0x%x) psn(0x%x) ctrlcap(%x) for b:d (%x:%x)\n", - __FUNCTION__, ctrl->slot_bus, num_ctlr_slots, first_device_num, physical_slot_num, ctrlcap, - ctrl->bus, ctrl->device); - - return (0); } - /* * set_attention_status - Turns the Amber LED for a slot on, off or blink */ @@ -378,8 +428,6 @@ static int pciehp_probe(struct pcie_devi int rc; struct controller *ctrl; struct slot *t_slot; - int first_device_num = 0 ; /* first PCI device number supported by this PCIE */ - int num_ctlr_slots; /* number of slots supported by this HPC */ u8 value; struct pci_dev *pdev; @@ -388,6 +436,7 @@ static int pciehp_probe(struct pcie_devi err("%s : out of memory\n", __FUNCTION__); goto err_out_none; } + INIT_LIST_HEAD(&ctrl->slot_list); pdev = dev->port; ctrl->pci_dev = pdev; @@ -400,13 +449,6 @@ static int pciehp_probe(struct pcie_devi pci_set_drvdata(pdev, ctrl); - ctrl->pci_bus = kmalloc(sizeof(*ctrl->pci_bus), GFP_KERNEL); - if (!ctrl->pci_bus) { - err("%s: out of memory\n", __FUNCTION__); - rc = -ENOMEM; - goto err_out_unmap_mmio_region; - } - memcpy (ctrl->pci_bus, pdev->bus, sizeof (*ctrl->pci_bus)); ctrl->bus = pdev->bus->number; /* ctrl bus */ ctrl->slot_bus = pdev->subordinate->number; /* bus controlled by this HPC */ @@ -415,26 +457,14 @@ static int pciehp_probe(struct pcie_devi dbg("%s: ctrl bus=0x%x, device=%x, function=%x, irq=%x\n", __FUNCTION__, ctrl->bus, ctrl->device, ctrl->function, pdev->irq); - /* - * Save configuration headers for this and subordinate PCI buses - */ - - rc = get_ctlr_slot_config(ctrl); - if (rc) { - err(msg_initialization_err, rc); - goto err_out_free_ctrl_bus; - } - first_device_num = ctrl->slot_device_offset; - num_ctlr_slots = ctrl->num_slots; - /* Setup the slot information structures */ rc = init_slots(ctrl); if (rc) { - err(msg_initialization_err, 6); - goto err_out_free_ctrl_slot; + err("%s: slot initialization failed\n", PCIE_MODULE_NAME); + goto err_out_release_ctlr; } - t_slot = pciehp_find_slot(ctrl, first_device_num); + t_slot = pciehp_find_slot(ctrl, ctrl->slot_device_offset); /* Finish setting up the hot plug ctrl device */ ctrl->next_event = 0; @@ -447,32 +477,18 @@ static int pciehp_probe(struct pcie_devi pciehp_ctrl_list = ctrl; } - /* Wait for exclusive access to hardware */ - mutex_lock(&ctrl->ctrl_lock); - t_slot->hpc_ops->get_adapter_status(t_slot, &value); /* Check if slot is occupied */ - if ((POWER_CTRL(ctrl->ctrlcap)) && !value) { rc = t_slot->hpc_ops->power_off_slot(t_slot); /* Power off slot if not occupied*/ - if (rc) { - /* Done with exclusive hardware access */ - mutex_unlock(&ctrl->ctrl_lock); + if (rc) goto err_out_free_ctrl_slot; - } else - /* Wait for the command to complete */ - wait_for_ctrl_irq (ctrl); } - /* Done with exclusive hardware access */ - mutex_unlock(&ctrl->ctrl_lock); - return 0; err_out_free_ctrl_slot: cleanup_slots(ctrl); -err_out_free_ctrl_bus: - kfree(ctrl->pci_bus); -err_out_unmap_mmio_region: +err_out_release_ctlr: ctrl->hpc_ops->release_ctlr(ctrl); err_out_free_ctrl: kfree(ctrl); @@ -506,8 +522,6 @@ static void __exit unload_pciehpd(void) while (ctrl) { cleanup_slots(ctrl); - kfree (ctrl->pci_bus); - ctrl->hpc_ops->release_ctlr(ctrl); tctrl = ctrl; diff --git a/drivers/pci/hotplug/pciehp_ctrl.c b/drivers/pci/hotplug/pciehp_ctrl.c index 372c63e..4283ef5 100644 --- a/drivers/pci/hotplug/pciehp_ctrl.c +++ b/drivers/pci/hotplug/pciehp_ctrl.c @@ -48,9 +48,8 @@ static inline char *slot_name(struct slo return p_slot->hotplug_slot->name; } -u8 pciehp_handle_attention_button(u8 hp_slot, void *inst_id) +u8 pciehp_handle_attention_button(u8 hp_slot, struct controller *ctrl) { - struct controller *ctrl = (struct controller *) inst_id; struct slot *p_slot; u8 rc = 0; u8 getstatus; @@ -101,9 +100,8 @@ u8 pciehp_handle_attention_button(u8 hp_ } -u8 pciehp_handle_switch_change(u8 hp_slot, void *inst_id) +u8 pciehp_handle_switch_change(u8 hp_slot, struct controller *ctrl) { - struct controller *ctrl = (struct controller *) inst_id; struct slot *p_slot; u8 rc = 0; u8 getstatus; @@ -143,9 +141,8 @@ u8 pciehp_handle_switch_change(u8 hp_slo return rc; } -u8 pciehp_handle_presence_change(u8 hp_slot, void *inst_id) +u8 pciehp_handle_presence_change(u8 hp_slot, struct controller *ctrl) { - struct controller *ctrl = (struct controller *) inst_id; struct slot *p_slot; u8 presence_save, rc = 0; struct event_info *taskInfo; @@ -187,9 +184,8 @@ u8 pciehp_handle_presence_change(u8 hp_s return rc; } -u8 pciehp_handle_power_fault(u8 hp_slot, void *inst_id) +u8 pciehp_handle_power_fault(u8 hp_slot, struct controller *ctrl) { - struct controller *ctrl = (struct controller *) inst_id; struct slot *p_slot; u8 rc = 0; struct event_info *taskInfo; @@ -233,35 +229,25 @@ u8 pciehp_handle_power_fault(u8 hp_slot, static void set_slot_off(struct controller *ctrl, struct slot * pslot) { - /* Wait for exclusive access to hardware */ - mutex_lock(&ctrl->ctrl_lock); - /* turn off slot, turn on Amber LED, turn off Green LED if supported*/ if (POWER_CTRL(ctrl->ctrlcap)) { if (pslot->hpc_ops->power_off_slot(pslot)) { - err("%s: Issue of Slot Power Off command failed\n", __FUNCTION__); - mutex_unlock(&ctrl->ctrl_lock); + err("%s: Issue of Slot Power Off command failed\n", + __FUNCTION__); return; } - wait_for_ctrl_irq (ctrl); } - if (PWR_LED(ctrl->ctrlcap)) { + if (PWR_LED(ctrl->ctrlcap)) pslot->hpc_ops->green_led_off(pslot); - wait_for_ctrl_irq (ctrl); - } - if (ATTN_LED(ctrl->ctrlcap)) { - if (pslot->hpc_ops->set_attention_status(pslot, 1)) { - err("%s: Issue of Set Attention Led command failed\n", __FUNCTION__); - mutex_unlock(&ctrl->ctrl_lock); + if (ATTN_LED(ctrl->ctrlcap)) { + if (pslot->hpc_ops->set_attention_status(pslot, 1)) { + err("%s: Issue of Set Attention Led command failed\n", + __FUNCTION__); return; } - wait_for_ctrl_irq (ctrl); } - - /* Done with exclusive hardware access */ - mutex_unlock(&ctrl->ctrl_lock); } /** @@ -274,7 +260,7 @@ static void set_slot_off(struct controll static int board_added(struct slot *p_slot) { u8 hp_slot; - int rc = 0; + int retval = 0; struct controller *ctrl = p_slot->ctrl; hp_slot = p_slot->device - ctrl->slot_device_offset; @@ -283,53 +269,38 @@ static int board_added(struct slot *p_sl __FUNCTION__, p_slot->device, ctrl->slot_device_offset, hp_slot); - /* Wait for exclusive access to hardware */ - mutex_lock(&ctrl->ctrl_lock); - if (POWER_CTRL(ctrl->ctrlcap)) { /* Power on slot */ - rc = p_slot->hpc_ops->power_on_slot(p_slot); - if (rc) { - mutex_unlock(&ctrl->ctrl_lock); - return -1; - } - - /* Wait for the command to complete */ - wait_for_ctrl_irq (ctrl); + retval = p_slot->hpc_ops->power_on_slot(p_slot); + if (retval) + return retval; } - if (PWR_LED(ctrl->ctrlcap)) { + if (PWR_LED(ctrl->ctrlcap)) p_slot->hpc_ops->green_led_blink(p_slot); - - /* Wait for the command to complete */ - wait_for_ctrl_irq (ctrl); - } - - /* Done with exclusive hardware access */ - mutex_unlock(&ctrl->ctrl_lock); /* Wait for ~1 second */ - wait_for_ctrl_irq (ctrl); + msleep(1000); - /* Check link training status */ - rc = p_slot->hpc_ops->check_lnk_status(ctrl); - if (rc) { + /* Check link training status */ + retval = p_slot->hpc_ops->check_lnk_status(ctrl); + if (retval) { err("%s: Failed to check link status\n", __FUNCTION__); set_slot_off(ctrl, p_slot); - return rc; + return retval; } /* Check for a power fault */ if (p_slot->hpc_ops->query_power_fault(p_slot)) { dbg("%s: power fault detected\n", __FUNCTION__); - rc = POWER_FAILURE; + retval = POWER_FAILURE; goto err_exit; } - rc = pciehp_configure_device(p_slot); - if (rc) { + retval = pciehp_configure_device(p_slot); + if (retval) { err("Cannot add device 0x%x:%x\n", p_slot->bus, - p_slot->device); + p_slot->device); goto err_exit; } @@ -338,26 +309,16 @@ static int board_added(struct slot *p_sl */ if (pcie_mch_quirk) pci_fixup_device(pci_fixup_final, ctrl->pci_dev); - if (PWR_LED(ctrl->ctrlcap)) { - /* Wait for exclusive access to hardware */ - mutex_lock(&ctrl->ctrl_lock); - + if (PWR_LED(ctrl->ctrlcap)) p_slot->hpc_ops->green_led_on(p_slot); - - /* Wait for the command to complete */ - wait_for_ctrl_irq (ctrl); - - /* Done with exclusive hardware access */ - mutex_unlock(&ctrl->ctrl_lock); - } + return 0; err_exit: set_slot_off(ctrl, p_slot); - return -1; + return retval; } - /** * remove_board - Turns off slot and LED's * @@ -366,44 +327,32 @@ static int remove_board(struct slot *p_s { u8 device; u8 hp_slot; - int rc; + int retval = 0; struct controller *ctrl = p_slot->ctrl; - if (pciehp_unconfigure_device(p_slot)) - return 1; + retval = pciehp_unconfigure_device(p_slot); + if (retval) + return retval; device = p_slot->device; - hp_slot = p_slot->device - ctrl->slot_device_offset; p_slot = pciehp_find_slot(ctrl, hp_slot + ctrl->slot_device_offset); dbg("In %s, hp_slot = %d\n", __FUNCTION__, hp_slot); - /* Wait for exclusive access to hardware */ - mutex_lock(&ctrl->ctrl_lock); - if (POWER_CTRL(ctrl->ctrlcap)) { /* power off slot */ - rc = p_slot->hpc_ops->power_off_slot(p_slot); - if (rc) { - err("%s: Issue of Slot Disable command failed\n", __FUNCTION__); - mutex_unlock(&ctrl->ctrl_lock); - return rc; + retval = p_slot->hpc_ops->power_off_slot(p_slot); + if (retval) { + err("%s: Issue of Slot Disable command failed\n", + __FUNCTION__); + return retval; } - /* Wait for the command to complete */ - wait_for_ctrl_irq (ctrl); } - if (PWR_LED(ctrl->ctrlcap)) { + if (PWR_LED(ctrl->ctrlcap)) /* turn off Green LED */ p_slot->hpc_ops->green_led_off(p_slot); - - /* Wait for the command to complete */ - wait_for_ctrl_irq (ctrl); - } - - /* Done with exclusive hardware access */ - mutex_unlock(&ctrl->ctrl_lock); return 0; } @@ -448,18 +397,10 @@ static void pciehp_pushbutton_thread(uns dbg("%s: adding bus:device(%x:%x)\n", __FUNCTION__, p_slot->bus, p_slot->device); - if (pciehp_enable_slot(p_slot) && PWR_LED(p_slot->ctrl->ctrlcap)) { - /* Wait for exclusive access to hardware */ - mutex_lock(&p_slot->ctrl->ctrl_lock); - + if (pciehp_enable_slot(p_slot) && + PWR_LED(p_slot->ctrl->ctrlcap)) p_slot->hpc_ops->green_led_off(p_slot); - /* Wait for the command to complete */ - wait_for_ctrl_irq (p_slot->ctrl); - - /* Done with exclusive hardware access */ - mutex_unlock(&p_slot->ctrl->ctrl_lock); - } p_slot->state = STATIC_STATE; } @@ -498,18 +439,10 @@ static void pciehp_surprise_rm_thread(un dbg("%s: adding bus:device(%x:%x)\n", __FUNCTION__, p_slot->bus, p_slot->device); - if (pciehp_enable_slot(p_slot) && PWR_LED(p_slot->ctrl->ctrlcap)) { - /* Wait for exclusive access to hardware */ - mutex_lock(&p_slot->ctrl->ctrl_lock); - + if (pciehp_enable_slot(p_slot) && + PWR_LED(p_slot->ctrl->ctrlcap)) p_slot->hpc_ops->green_led_off(p_slot); - /* Wait for the command to complete */ - wait_for_ctrl_irq (p_slot->ctrl); - - /* Done with exclusive hardware access */ - mutex_unlock(&p_slot->ctrl->ctrl_lock); - } p_slot->state = STATIC_STATE; } @@ -620,46 +553,24 @@ static void interrupt_event_handler(stru switch (p_slot->state) { case BLINKINGOFF_STATE: - /* Wait for exclusive access to hardware */ - mutex_lock(&ctrl->ctrl_lock); - - if (PWR_LED(ctrl->ctrlcap)) { + if (PWR_LED(ctrl->ctrlcap)) p_slot->hpc_ops->green_led_on(p_slot); - /* Wait for the command to complete */ - wait_for_ctrl_irq (ctrl); - } - if (ATTN_LED(ctrl->ctrlcap)) { - p_slot->hpc_ops->set_attention_status(p_slot, 0); - /* Wait for the command to complete */ - wait_for_ctrl_irq (ctrl); - } - /* Done with exclusive hardware access */ - mutex_unlock(&ctrl->ctrl_lock); + if (ATTN_LED(ctrl->ctrlcap)) + p_slot->hpc_ops->set_attention_status(p_slot, 0); break; case BLINKINGON_STATE: - /* Wait for exclusive access to hardware */ - mutex_lock(&ctrl->ctrl_lock); - - if (PWR_LED(ctrl->ctrlcap)) { + if (PWR_LED(ctrl->ctrlcap)) p_slot->hpc_ops->green_led_off(p_slot); - /* Wait for the command to complete */ - wait_for_ctrl_irq (ctrl); - } - if (ATTN_LED(ctrl->ctrlcap)){ - p_slot->hpc_ops->set_attention_status(p_slot, 0); - /* Wait for the command to complete */ - wait_for_ctrl_irq (ctrl); - } - /* Done with exclusive hardware access */ - mutex_unlock(&ctrl->ctrl_lock); + if (ATTN_LED(ctrl->ctrlcap)) + p_slot->hpc_ops->set_attention_status(p_slot, 0); break; default: warn("Not a valid state\n"); return; } - info(msg_button_cancel, slot_name(p_slot)); + info("PCI slot #%s - action canceled due to button press.\n", slot_name(p_slot)); p_slot->state = STATIC_STATE; } /* ***********Button Pressed (No action on 1st press...) */ @@ -672,34 +583,21 @@ static void interrupt_event_handler(stru /* slot is on */ dbg("slot is on\n"); p_slot->state = BLINKINGOFF_STATE; - info(msg_button_off, slot_name(p_slot)); + info("PCI slot #%s - powering off due to button press.\n", slot_name(p_slot)); } else { /* slot is off */ dbg("slot is off\n"); p_slot->state = BLINKINGON_STATE; - info(msg_button_on, slot_name(p_slot)); + info("PCI slot #%s - powering on due to button press.\n", slot_name(p_slot)); } - /* Wait for exclusive access to hardware */ - mutex_lock(&ctrl->ctrl_lock); - /* blink green LED and turn off amber */ - if (PWR_LED(ctrl->ctrlcap)) { + if (PWR_LED(ctrl->ctrlcap)) p_slot->hpc_ops->green_led_blink(p_slot); - /* Wait for the command to complete */ - wait_for_ctrl_irq (ctrl); - } - if (ATTN_LED(ctrl->ctrlcap)) { + if (ATTN_LED(ctrl->ctrlcap)) p_slot->hpc_ops->set_attention_status(p_slot, 0); - /* Wait for the command to complete */ - wait_for_ctrl_irq (ctrl); - } - - /* Done with exclusive hardware access */ - mutex_unlock(&ctrl->ctrl_lock); - init_timer(&p_slot->task_event); p_slot->task_event.expires = jiffies + 5 * HZ; /* 5 second delay */ p_slot->task_event.function = (void (*)(unsigned long)) pushbutton_helper_thread; @@ -712,21 +610,11 @@ static void interrupt_event_handler(stru else if (ctrl->event_queue[loop].event_type == INT_POWER_FAULT) { if (POWER_CTRL(ctrl->ctrlcap)) { dbg("power fault\n"); - /* Wait for exclusive access to hardware */ - mutex_lock(&ctrl->ctrl_lock); - - if (ATTN_LED(ctrl->ctrlcap)) { + if (ATTN_LED(ctrl->ctrlcap)) p_slot->hpc_ops->set_attention_status(p_slot, 1); - wait_for_ctrl_irq (ctrl); - } - if (PWR_LED(ctrl->ctrlcap)) { + if (PWR_LED(ctrl->ctrlcap)) p_slot->hpc_ops->green_led_off(p_slot); - wait_for_ctrl_irq (ctrl); - } - - /* Done with exclusive hardware access */ - mutex_unlock(&ctrl->ctrl_lock); } } /***********SURPRISE REMOVAL********************/ @@ -754,7 +642,6 @@ static void interrupt_event_handler(stru } } - int pciehp_enable_slot(struct slot *p_slot) { u8 getstatus = 0; diff --git a/drivers/pci/hotplug/pciehp_hpc.c b/drivers/pci/hotplug/pciehp_hpc.c index 25d3aad..fbc64aa 100644 --- a/drivers/pci/hotplug/pciehp_hpc.c +++ b/drivers/pci/hotplug/pciehp_hpc.c @@ -35,6 +35,7 @@ #include #include #include #include +#include #include "../pci.h" #include "pciehp.h" @@ -105,34 +106,30 @@ enum ctrl_offsets { ROOTCTRL = offsetof(struct ctrl_reg, root_ctrl), ROOTSTATUS = offsetof(struct ctrl_reg, root_status), }; -static int pcie_cap_base = 0; /* Base of the PCI Express capability item structure */ - -#define PCIE_CAP_ID(cb) ( cb + PCIECAPID ) -#define NXT_CAP_PTR(cb) ( cb + NXTCAPPTR ) -#define CAP_REG(cb) ( cb + CAPREG ) -#define DEV_CAP(cb) ( cb + DEVCAP ) -#define DEV_CTRL(cb) ( cb + DEVCTRL ) -#define DEV_STATUS(cb) ( cb + DEVSTATUS ) -#define LNK_CAP(cb) ( cb + LNKCAP ) -#define LNK_CTRL(cb) ( cb + LNKCTRL ) -#define LNK_STATUS(cb) ( cb + LNKSTATUS ) -#define SLOT_CAP(cb) ( cb + SLOTCAP ) -#define SLOT_CTRL(cb) ( cb + SLOTCTRL ) -#define SLOT_STATUS(cb) ( cb + SLOTSTATUS ) -#define ROOT_CTRL(cb) ( cb + ROOTCTRL ) -#define ROOT_STATUS(cb) ( cb + ROOTSTATUS ) - -#define hp_register_read_word(pdev, reg , value) \ - pci_read_config_word(pdev, reg, &value) - -#define hp_register_read_dword(pdev, reg , value) \ - pci_read_config_dword(pdev, reg, &value) - -#define hp_register_write_word(pdev, reg , value) \ - pci_write_config_word(pdev, reg, value) - -#define hp_register_dwrite_word(pdev, reg , value) \ - pci_write_config_dword(pdev, reg, value) + +static inline int pciehp_readw(struct controller *ctrl, int reg, u16 *value) +{ + struct pci_dev *dev = ctrl->pci_dev; + return pci_read_config_word(dev, ctrl->cap_base + reg, value); +} + +static inline int pciehp_readl(struct controller *ctrl, int reg, u32 *value) +{ + struct pci_dev *dev = ctrl->pci_dev; + return pci_read_config_dword(dev, ctrl->cap_base + reg, value); +} + +static inline int pciehp_writew(struct controller *ctrl, int reg, u16 value) +{ + struct pci_dev *dev = ctrl->pci_dev; + return pci_write_config_word(dev, ctrl->cap_base + reg, value); +} + +static inline int pciehp_writel(struct controller *ctrl, int reg, u32 value) +{ + struct pci_dev *dev = ctrl->pci_dev; + return pci_write_config_dword(dev, ctrl->cap_base + reg, value); +} /* Field definitions in PCI Express Capabilities Register */ #define CAP_VER 0x000F @@ -196,6 +193,7 @@ #define HP_INTR_ENABLE 0x0020 #define ATTN_LED_CTRL 0x00C0 #define PWR_LED_CTRL 0x0300 #define PWR_CTRL 0x0400 +#define EMI_CTRL 0x0800 /* Attention indicator and Power indicator states */ #define LED_ON 0x01 @@ -206,6 +204,10 @@ #define LED_OFF 0x11 #define POWER_ON 0 #define POWER_OFF 0x0400 +/* EMI Status defines */ +#define EMI_DISENGAGED 0 +#define EMI_ENGAGED 1 + /* Field definitions in Slot Status Register */ #define ATTN_BUTTN_PRESSED 0x0001 #define PWR_FAULT_DETECTED 0x0002 @@ -214,114 +216,117 @@ #define PRSN_DETECT_CHANGED 0x0008 #define CMD_COMPLETED 0x0010 #define MRL_STATE 0x0020 #define PRSN_STATE 0x0040 +#define EMI_STATE 0x0080 +#define EMI_STATUS_BIT 7 static spinlock_t hpc_event_lock; DEFINE_DBG_BUFFER /* Debug string buffer for entire HPC defined here */ -static struct php_ctlr_state_s *php_ctlr_list_head; /* HPC state linked list */ static int ctlr_seq_num = 0; /* Controller sequence # */ -static spinlock_t list_lock; - -static irqreturn_t pcie_isr(int IRQ, void *dev_id); -static void start_int_poll_timer(struct php_ctlr_state_s *php_ctlr, int seconds); +static irqreturn_t pcie_isr(int irq, void *dev_id); +static void start_int_poll_timer(struct controller *ctrl, int sec); /* This is the interrupt polling timeout function. */ -static void int_poll_timeout(unsigned long lphp_ctlr) +static void int_poll_timeout(unsigned long data) { - struct php_ctlr_state_s *php_ctlr = (struct php_ctlr_state_s *)lphp_ctlr; + struct controller *ctrl = (struct controller *)data; DBG_ENTER_ROUTINE - if ( !php_ctlr ) { - err("%s: Invalid HPC controller handle!\n", __FUNCTION__); - return; - } - /* Poll for interrupt events. regs == NULL => polling */ - pcie_isr( 0, (void *)php_ctlr ); - - init_timer(&php_ctlr->int_poll_timer); + pcie_isr(0, ctrl); + init_timer(&ctrl->poll_timer); if (!pciehp_poll_time) pciehp_poll_time = 2; /* reset timer to poll in 2 secs if user doesn't specify at module installation*/ - start_int_poll_timer(php_ctlr, pciehp_poll_time); - - return; + start_int_poll_timer(ctrl, pciehp_poll_time); } /* This function starts the interrupt polling timer. */ -static void start_int_poll_timer(struct php_ctlr_state_s *php_ctlr, int seconds) +static void start_int_poll_timer(struct controller *ctrl, int sec) { - if (!php_ctlr) { - err("%s: Invalid HPC controller handle!\n", __FUNCTION__); - return; - } + /* Clamp to sane value */ + if ((sec <= 0) || (sec > 60)) + sec = 2; + + ctrl->poll_timer.function = &int_poll_timeout; + ctrl->poll_timer.data = (unsigned long)ctrl; + ctrl->poll_timer.expires = jiffies + sec * HZ; + add_timer(&ctrl->poll_timer); +} - if ( ( seconds <= 0 ) || ( seconds > 60 ) ) - seconds = 2; /* Clamp to sane value */ +static inline int pcie_wait_cmd(struct controller *ctrl) +{ + int retval = 0; + unsigned int msecs = pciehp_poll_mode ? 2500 : 1000; + unsigned long timeout = msecs_to_jiffies(msecs); + int rc; - php_ctlr->int_poll_timer.function = &int_poll_timeout; - php_ctlr->int_poll_timer.data = (unsigned long)php_ctlr; /* Instance data */ - php_ctlr->int_poll_timer.expires = jiffies + seconds * HZ; - add_timer(&php_ctlr->int_poll_timer); + rc = wait_event_interruptible_timeout(ctrl->queue, + !ctrl->cmd_busy, timeout); + if (!rc) + dbg("Command not completed in 1000 msec\n"); + else if (rc < 0) { + retval = -EINTR; + info("Command was interrupted by a signal\n"); + } - return; + return retval; } static int pcie_write_cmd(struct slot *slot, u16 cmd) { - struct php_ctlr_state_s *php_ctlr = slot->ctrl->hpc_ctlr_handle; + struct controller *ctrl = slot->ctrl; int retval = 0; u16 slot_status; DBG_ENTER_ROUTINE - - if (!php_ctlr) { - err("%s: Invalid HPC controller handle!\n", __FUNCTION__); - return -1; - } - retval = hp_register_read_word(php_ctlr->pci_dev, SLOT_STATUS(slot->ctrl->cap_base), slot_status); + mutex_lock(&ctrl->ctrl_lock); + + retval = pciehp_readw(ctrl, SLOTSTATUS, &slot_status); if (retval) { - err("%s : hp_register_read_word SLOT_STATUS failed\n", __FUNCTION__); - return retval; - } - + err("%s: Cannot read SLOTSTATUS register\n", __FUNCTION__); + goto out; + } + if ((slot_status & CMD_COMPLETED) == CMD_COMPLETED ) { - /* After 1 sec and CMD_COMPLETED still not set, just proceed forward to issue - the next command according to spec. Just print out the error message */ - dbg("%s : CMD_COMPLETED not clear after 1 sec.\n", __FUNCTION__); + /* After 1 sec and CMD_COMPLETED still not set, just + proceed forward to issue the next command according + to spec. Just print out the error message */ + dbg("%s: CMD_COMPLETED not clear after 1 sec.\n", + __FUNCTION__); } - retval = hp_register_write_word(php_ctlr->pci_dev, SLOT_CTRL(slot->ctrl->cap_base), cmd | CMD_CMPL_INTR_ENABLE); + ctrl->cmd_busy = 1; + retval = pciehp_writew(ctrl, SLOTCTRL, (cmd | CMD_CMPL_INTR_ENABLE)); if (retval) { - err("%s : hp_register_write_word SLOT_CTRL failed\n", __FUNCTION__); - return retval; + err("%s: Cannot write to SLOTCTRL register\n", __FUNCTION__); + goto out; } + /* + * Wait for command completion. + */ + retval = pcie_wait_cmd(ctrl); + out: + mutex_unlock(&ctrl->ctrl_lock); DBG_LEAVE_ROUTINE return retval; } static int hpc_check_lnk_status(struct controller *ctrl) { - struct php_ctlr_state_s *php_ctlr = ctrl->hpc_ctlr_handle; u16 lnk_status; int retval = 0; DBG_ENTER_ROUTINE - if (!php_ctlr) { - err("%s: Invalid HPC controller handle!\n", __FUNCTION__); - return -1; - } - - retval = hp_register_read_word(php_ctlr->pci_dev, LNK_STATUS(ctrl->cap_base), lnk_status); - + retval = pciehp_readw(ctrl, LNKSTATUS, &lnk_status); if (retval) { - err("%s : hp_register_read_word LNK_STATUS failed\n", __FUNCTION__); + err("%s: Cannot read LNKSTATUS register\n", __FUNCTION__); return retval; } @@ -340,26 +345,21 @@ static int hpc_check_lnk_status(struct c static int hpc_get_attention_status(struct slot *slot, u8 *status) { - struct php_ctlr_state_s *php_ctlr = slot->ctrl->hpc_ctlr_handle; + struct controller *ctrl = slot->ctrl; u16 slot_ctrl; u8 atten_led_state; int retval = 0; DBG_ENTER_ROUTINE - if (!php_ctlr) { - err("%s: Invalid HPC controller handle!\n", __FUNCTION__); - return -1; - } - - retval = hp_register_read_word(php_ctlr->pci_dev, SLOT_CTRL(slot->ctrl->cap_base), slot_ctrl); - + retval = pciehp_readw(ctrl, SLOTCTRL, &slot_ctrl); if (retval) { - err("%s : hp_register_read_word SLOT_CTRL failed\n", __FUNCTION__); + err("%s: Cannot read SLOTCTRL register\n", __FUNCTION__); return retval; } - dbg("%s: SLOT_CTRL %x, value read %x\n", __FUNCTION__,SLOT_CTRL(slot->ctrl->cap_base), slot_ctrl); + dbg("%s: SLOTCTRL %x, value read %x\n", + __FUNCTION__, ctrl->cap_base + SLOTCTRL, slot_ctrl); atten_led_state = (slot_ctrl & ATTN_LED_CTRL) >> 6; @@ -385,27 +385,22 @@ static int hpc_get_attention_status(stru return 0; } -static int hpc_get_power_status(struct slot * slot, u8 *status) +static int hpc_get_power_status(struct slot *slot, u8 *status) { - struct php_ctlr_state_s *php_ctlr = slot->ctrl->hpc_ctlr_handle; + struct controller *ctrl = slot->ctrl; u16 slot_ctrl; u8 pwr_state; int retval = 0; DBG_ENTER_ROUTINE - if (!php_ctlr) { - err("%s: Invalid HPC controller handle!\n", __FUNCTION__); - return -1; - } - - retval = hp_register_read_word(php_ctlr->pci_dev, SLOT_CTRL(slot->ctrl->cap_base), slot_ctrl); - + retval = pciehp_readw(ctrl, SLOTCTRL, &slot_ctrl); if (retval) { - err("%s : hp_register_read_word SLOT_CTRL failed\n", __FUNCTION__); + err("%s: Cannot read SLOTCTRL register\n", __FUNCTION__); return retval; } - dbg("%s: SLOT_CTRL %x value read %x\n", __FUNCTION__, SLOT_CTRL(slot->ctrl->cap_base), slot_ctrl); + dbg("%s: SLOTCTRL %x value read %x\n", + __FUNCTION__, ctrl->cap_base + SLOTCTRL, slot_ctrl); pwr_state = (slot_ctrl & PWR_CTRL) >> 10; @@ -428,21 +423,15 @@ static int hpc_get_power_status(struct s static int hpc_get_latch_status(struct slot *slot, u8 *status) { - struct php_ctlr_state_s *php_ctlr = slot->ctrl->hpc_ctlr_handle; + struct controller *ctrl = slot->ctrl; u16 slot_status; int retval = 0; DBG_ENTER_ROUTINE - if (!php_ctlr) { - err("%s: Invalid HPC controller handle!\n", __FUNCTION__); - return -1; - } - - retval = hp_register_read_word(php_ctlr->pci_dev, SLOT_STATUS(slot->ctrl->cap_base), slot_status); - + retval = pciehp_readw(ctrl, SLOTSTATUS, &slot_status); if (retval) { - err("%s : hp_register_read_word SLOT_STATUS failed\n", __FUNCTION__); + err("%s: Cannot read SLOTSTATUS register\n", __FUNCTION__); return retval; } @@ -454,22 +443,16 @@ static int hpc_get_latch_status(struct s static int hpc_get_adapter_status(struct slot *slot, u8 *status) { - struct php_ctlr_state_s *php_ctlr = slot->ctrl->hpc_ctlr_handle; + struct controller *ctrl = slot->ctrl; u16 slot_status; u8 card_state; int retval = 0; DBG_ENTER_ROUTINE - if (!php_ctlr) { - err("%s: Invalid HPC controller handle!\n", __FUNCTION__); - return -1; - } - - retval = hp_register_read_word(php_ctlr->pci_dev, SLOT_STATUS(slot->ctrl->cap_base), slot_status); - + retval = pciehp_readw(ctrl, SLOTSTATUS, &slot_status); if (retval) { - err("%s : hp_register_read_word SLOT_STATUS failed\n", __FUNCTION__); + err("%s: Cannot read SLOTSTATUS register\n", __FUNCTION__); return retval; } card_state = (u8)((slot_status & PRSN_STATE) >> 6); @@ -479,24 +462,18 @@ static int hpc_get_adapter_status(struct return 0; } -static int hpc_query_power_fault(struct slot * slot) +static int hpc_query_power_fault(struct slot *slot) { - struct php_ctlr_state_s *php_ctlr = slot->ctrl->hpc_ctlr_handle; + struct controller *ctrl = slot->ctrl; u16 slot_status; u8 pwr_fault; int retval = 0; DBG_ENTER_ROUTINE - if (!php_ctlr) { - err("%s: Invalid HPC controller handle!\n", __FUNCTION__); - return -1; - } - - retval = hp_register_read_word(php_ctlr->pci_dev, SLOT_STATUS(slot->ctrl->cap_base), slot_status); - + retval = pciehp_readw(ctrl, SLOTSTATUS, &slot_status); if (retval) { - err("%s : Cannot check for power fault\n", __FUNCTION__); + err("%s: Cannot check for power fault\n", __FUNCTION__); return retval; } pwr_fault = (u8)((slot_status & PWR_FAULT_DETECTED) >> 1); @@ -505,28 +482,63 @@ static int hpc_query_power_fault(struct return pwr_fault; } -static int hpc_set_attention_status(struct slot *slot, u8 value) +static int hpc_get_emi_status(struct slot *slot, u8 *status) { - struct php_ctlr_state_s *php_ctlr = slot->ctrl->hpc_ctlr_handle; + struct controller *ctrl = slot->ctrl; + u16 slot_status; + int retval = 0; + + DBG_ENTER_ROUTINE + + retval = pciehp_readw(ctrl, SLOTSTATUS, &slot_status); + if (retval) { + err("%s : Cannot check EMI status\n", __FUNCTION__); + return retval; + } + *status = (slot_status & EMI_STATE) >> EMI_STATUS_BIT; + + DBG_LEAVE_ROUTINE + return retval; +} + +static int hpc_toggle_emi(struct slot *slot) +{ + struct controller *ctrl = slot->ctrl; u16 slot_cmd = 0; u16 slot_ctrl; int rc = 0; DBG_ENTER_ROUTINE - if (!php_ctlr) { - err("%s: Invalid HPC controller handle!\n", __FUNCTION__); - return -1; + rc = pciehp_readw(ctrl, SLOTCTRL, &slot_ctrl); + if (rc) { + err("%s : hp_register_read_word SLOT_CTRL failed\n", + __FUNCTION__); + return rc; } - if (slot->hp_slot >= php_ctlr->num_slots) { - err("%s: Invalid HPC slot number!\n", __FUNCTION__); - return -1; - } - rc = hp_register_read_word(php_ctlr->pci_dev, SLOT_CTRL(slot->ctrl->cap_base), slot_ctrl); + slot_cmd = (slot_ctrl | EMI_CTRL); + if (!pciehp_poll_mode) + slot_cmd = slot_cmd | HP_INTR_ENABLE; + pcie_write_cmd(slot, slot_cmd); + slot->last_emi_toggle = get_seconds(); + DBG_LEAVE_ROUTINE + return rc; +} + +static int hpc_set_attention_status(struct slot *slot, u8 value) +{ + struct controller *ctrl = slot->ctrl; + u16 slot_cmd = 0; + u16 slot_ctrl; + int rc = 0; + + DBG_ENTER_ROUTINE + + rc = pciehp_readw(ctrl, SLOTCTRL, &slot_ctrl); if (rc) { - err("%s : hp_register_read_word SLOT_CTRL failed\n", __FUNCTION__); + err("%s: Cannot read SLOTCTRL register\n", __FUNCTION__); return rc; } @@ -547,7 +559,8 @@ static int hpc_set_attention_status(stru slot_cmd = slot_cmd | HP_INTR_ENABLE; pcie_write_cmd(slot, slot_cmd); - dbg("%s: SLOT_CTRL %x write cmd %x\n", __FUNCTION__, SLOT_CTRL(slot->ctrl->cap_base), slot_cmd); + dbg("%s: SLOTCTRL %x write cmd %x\n", + __FUNCTION__, ctrl->cap_base + SLOTCTRL, slot_cmd); DBG_LEAVE_ROUTINE return rc; @@ -556,27 +569,16 @@ static int hpc_set_attention_status(stru static void hpc_set_green_led_on(struct slot *slot) { - struct php_ctlr_state_s *php_ctlr = slot->ctrl->hpc_ctlr_handle; + struct controller *ctrl = slot->ctrl; u16 slot_cmd; u16 slot_ctrl; int rc = 0; DBG_ENTER_ROUTINE - if (!php_ctlr) { - err("%s: Invalid HPC controller handle!\n", __FUNCTION__); - return ; - } - - if (slot->hp_slot >= php_ctlr->num_slots) { - err("%s: Invalid HPC slot number!\n", __FUNCTION__); - return ; - } - - rc = hp_register_read_word(php_ctlr->pci_dev, SLOT_CTRL(slot->ctrl->cap_base), slot_ctrl); - + rc = pciehp_readw(ctrl, SLOTCTRL, &slot_ctrl); if (rc) { - err("%s : hp_register_read_word SLOT_CTRL failed\n", __FUNCTION__); + err("%s: Cannot read SLOTCTRL register\n", __FUNCTION__); return; } slot_cmd = (slot_ctrl & ~PWR_LED_CTRL) | 0x0100; @@ -585,34 +587,24 @@ static void hpc_set_green_led_on(struct pcie_write_cmd(slot, slot_cmd); - dbg("%s: SLOT_CTRL %x write cmd %x\n",__FUNCTION__, SLOT_CTRL(slot->ctrl->cap_base), slot_cmd); + dbg("%s: SLOTCTRL %x write cmd %x\n", + __FUNCTION__, ctrl->cap_base + SLOTCTRL, slot_cmd); DBG_LEAVE_ROUTINE return; } static void hpc_set_green_led_off(struct slot *slot) { - struct php_ctlr_state_s *php_ctlr = slot->ctrl->hpc_ctlr_handle; + struct controller *ctrl = slot->ctrl; u16 slot_cmd; u16 slot_ctrl; int rc = 0; DBG_ENTER_ROUTINE - if (!php_ctlr) { - err("%s: Invalid HPC controller handle!\n", __FUNCTION__); - return ; - } - - if (slot->hp_slot >= php_ctlr->num_slots) { - err("%s: Invalid HPC slot number!\n", __FUNCTION__); - return ; - } - - rc = hp_register_read_word(php_ctlr->pci_dev, SLOT_CTRL(slot->ctrl->cap_base), slot_ctrl); - + rc = pciehp_readw(ctrl, SLOTCTRL, &slot_ctrl); if (rc) { - err("%s : hp_register_read_word SLOT_CTRL failed\n", __FUNCTION__); + err("%s: Cannot read SLOTCTRL register\n", __FUNCTION__); return; } @@ -621,7 +613,8 @@ static void hpc_set_green_led_off(struct if (!pciehp_poll_mode) slot_cmd = slot_cmd | HP_INTR_ENABLE; pcie_write_cmd(slot, slot_cmd); - dbg("%s: SLOT_CTRL %x write cmd %x\n", __FUNCTION__, SLOT_CTRL(slot->ctrl->cap_base), slot_cmd); + dbg("%s: SLOTCTRL %x write cmd %x\n", + __FUNCTION__, ctrl->cap_base + SLOTCTRL, slot_cmd); DBG_LEAVE_ROUTINE return; @@ -629,27 +622,16 @@ static void hpc_set_green_led_off(struct static void hpc_set_green_led_blink(struct slot *slot) { - struct php_ctlr_state_s *php_ctlr = slot->ctrl->hpc_ctlr_handle; + struct controller *ctrl = slot->ctrl; u16 slot_cmd; u16 slot_ctrl; int rc = 0; DBG_ENTER_ROUTINE - if (!php_ctlr) { - err("%s: Invalid HPC controller handle!\n", __FUNCTION__); - return ; - } - - if (slot->hp_slot >= php_ctlr->num_slots) { - err("%s: Invalid HPC slot number!\n", __FUNCTION__); - return ; - } - - rc = hp_register_read_word(php_ctlr->pci_dev, SLOT_CTRL(slot->ctrl->cap_base), slot_ctrl); - + rc = pciehp_readw(ctrl, SLOTCTRL, &slot_ctrl); if (rc) { - err("%s : hp_register_read_word SLOT_CTRL failed\n", __FUNCTION__); + err("%s: Cannot read SLOTCTRL register\n", __FUNCTION__); return; } @@ -659,126 +641,54 @@ static void hpc_set_green_led_blink(stru slot_cmd = slot_cmd | HP_INTR_ENABLE; pcie_write_cmd(slot, slot_cmd); - dbg("%s: SLOT_CTRL %x write cmd %x\n",__FUNCTION__, SLOT_CTRL(slot->ctrl->cap_base), slot_cmd); + dbg("%s: SLOTCTRL %x write cmd %x\n", + __FUNCTION__, ctrl->cap_base + SLOTCTRL, slot_cmd); DBG_LEAVE_ROUTINE return; } -int pcie_get_ctlr_slot_config(struct controller *ctrl, - int *num_ctlr_slots, /* number of slots in this HPC; only 1 in PCIE */ - int *first_device_num, /* PCI dev num of the first slot in this PCIE */ - int *physical_slot_num, /* phy slot num of the first slot in this PCIE */ - u8 *ctrlcap) -{ - struct php_ctlr_state_s *php_ctlr = ctrl->hpc_ctlr_handle; - u32 slot_cap; - int rc = 0; - - DBG_ENTER_ROUTINE - - if (!php_ctlr) { - err("%s: Invalid HPC controller handle!\n", __FUNCTION__); - return -1; - } - - *first_device_num = 0; - *num_ctlr_slots = 1; - - rc = hp_register_read_dword(php_ctlr->pci_dev, SLOT_CAP(ctrl->cap_base), slot_cap); - - if (rc) { - err("%s : hp_register_read_dword SLOT_CAP failed\n", __FUNCTION__); - return -1; - } - - *physical_slot_num = slot_cap >> 19; - dbg("%s: PSN %d \n", __FUNCTION__, *physical_slot_num); - - *ctrlcap = slot_cap & 0x0000007f; - - DBG_LEAVE_ROUTINE - return 0; -} - static void hpc_release_ctlr(struct controller *ctrl) { - struct php_ctlr_state_s *php_ctlr = ctrl->hpc_ctlr_handle; - struct php_ctlr_state_s *p, *p_prev; - DBG_ENTER_ROUTINE - if (!php_ctlr) { - err("%s: Invalid HPC controller handle!\n", __FUNCTION__); - return ; - } - - if (pciehp_poll_mode) { - del_timer(&php_ctlr->int_poll_timer); - } else { - if (php_ctlr->irq) { - free_irq(php_ctlr->irq, ctrl); - php_ctlr->irq = 0; - } - } - if (php_ctlr->pci_dev) - php_ctlr->pci_dev = NULL; - - spin_lock(&list_lock); - p = php_ctlr_list_head; - p_prev = NULL; - while (p) { - if (p == php_ctlr) { - if (p_prev) - p_prev->pnext = p->pnext; - else - php_ctlr_list_head = p->pnext; - break; - } else { - p_prev = p; - p = p->pnext; - } - } - spin_unlock(&list_lock); - - kfree(php_ctlr); + if (pciehp_poll_mode) + del_timer(&ctrl->poll_timer); + else + free_irq(ctrl->pci_dev->irq, ctrl); DBG_LEAVE_ROUTINE - } static int hpc_power_on_slot(struct slot * slot) { - struct php_ctlr_state_s *php_ctlr = slot->ctrl->hpc_ctlr_handle; + struct controller *ctrl = slot->ctrl; u16 slot_cmd; u16 slot_ctrl, slot_status; - int retval = 0; DBG_ENTER_ROUTINE - if (!php_ctlr) { - err("%s: Invalid HPC controller handle!\n", __FUNCTION__); - return -1; - } - dbg("%s: slot->hp_slot %x\n", __FUNCTION__, slot->hp_slot); - if (slot->hp_slot >= php_ctlr->num_slots) { - err("%s: Invalid HPC slot number!\n", __FUNCTION__); - return -1; - } /* Clear sticky power-fault bit from previous power failures */ - hp_register_read_word(php_ctlr->pci_dev, - SLOT_STATUS(slot->ctrl->cap_base), slot_status); + retval = pciehp_readw(ctrl, SLOTSTATUS, &slot_status); + if (retval) { + err("%s: Cannot read SLOTSTATUS register\n", __FUNCTION__); + return retval; + } slot_status &= PWR_FAULT_DETECTED; - if (slot_status) - hp_register_write_word(php_ctlr->pci_dev, - SLOT_STATUS(slot->ctrl->cap_base), slot_status); - - retval = hp_register_read_word(php_ctlr->pci_dev, SLOT_CTRL(slot->ctrl->cap_base), slot_ctrl); + if (slot_status) { + retval = pciehp_writew(ctrl, SLOTSTATUS, slot_status); + if (retval) { + err("%s: Cannot write to SLOTSTATUS register\n", + __FUNCTION__); + return retval; + } + } + retval = pciehp_readw(ctrl, SLOTCTRL, &slot_ctrl); if (retval) { - err("%s : hp_register_read_word SLOT_CTRL failed\n", __FUNCTION__); + err("%s: Cannot read SLOTCTRL register\n", __FUNCTION__); return retval; } @@ -798,7 +708,8 @@ static int hpc_power_on_slot(struct slot err("%s: Write %x command failed!\n", __FUNCTION__, slot_cmd); return -1; } - dbg("%s: SLOT_CTRL %x write cmd %x\n",__FUNCTION__, SLOT_CTRL(slot->ctrl->cap_base), slot_cmd); + dbg("%s: SLOTCTRL %x write cmd %x\n", + __FUNCTION__, ctrl->cap_base + SLOTCTRL, slot_cmd); DBG_LEAVE_ROUTINE @@ -807,29 +718,18 @@ static int hpc_power_on_slot(struct slot static int hpc_power_off_slot(struct slot * slot) { - struct php_ctlr_state_s *php_ctlr = slot->ctrl->hpc_ctlr_handle; + struct controller *ctrl = slot->ctrl; u16 slot_cmd; u16 slot_ctrl; - int retval = 0; DBG_ENTER_ROUTINE - if (!php_ctlr) { - err("%s: Invalid HPC controller handle!\n", __FUNCTION__); - return -1; - } - dbg("%s: slot->hp_slot %x\n", __FUNCTION__, slot->hp_slot); - slot->hp_slot = 0; - if (slot->hp_slot >= php_ctlr->num_slots) { - err("%s: Invalid HPC slot number!\n", __FUNCTION__); - return -1; - } - retval = hp_register_read_word(php_ctlr->pci_dev, SLOT_CTRL(slot->ctrl->cap_base), slot_ctrl); + retval = pciehp_readw(ctrl, SLOTCTRL, &slot_ctrl); if (retval) { - err("%s : hp_register_read_word SLOT_CTRL failed\n", __FUNCTION__); + err("%s: Cannot read SLOTCTRL register\n", __FUNCTION__); return retval; } @@ -854,47 +754,25 @@ static int hpc_power_off_slot(struct slo err("%s: Write command failed!\n", __FUNCTION__); return -1; } - dbg("%s: SLOT_CTRL %x write cmd %x\n",__FUNCTION__, SLOT_CTRL(slot->ctrl->cap_base), slot_cmd); + dbg("%s: SLOTCTRL %x write cmd %x\n", + __FUNCTION__, ctrl->cap_base + SLOTCTRL, slot_cmd); DBG_LEAVE_ROUTINE return retval; } -static irqreturn_t pcie_isr(int IRQ, void *dev_id) +static irqreturn_t pcie_isr(int irq, void *dev_id) { - struct controller *ctrl = NULL; - struct php_ctlr_state_s *php_ctlr; - u8 schedule_flag = 0; + struct controller *ctrl = (struct controller *)dev_id; u16 slot_status, intr_detect, intr_loc; u16 temp_word; int hp_slot = 0; /* only 1 slot per PCI Express port */ int rc = 0; - if (!dev_id) - return IRQ_NONE; - - if (!pciehp_poll_mode) { - ctrl = dev_id; - php_ctlr = ctrl->hpc_ctlr_handle; - } else { - php_ctlr = dev_id; - ctrl = (struct controller *)php_ctlr->callback_instance_id; - } - - if (!ctrl) { - dbg("%s: dev_id %p ctlr == NULL\n", __FUNCTION__, (void*) dev_id); - return IRQ_NONE; - } - - if (!php_ctlr) { - dbg("%s: php_ctlr == NULL\n", __FUNCTION__); - return IRQ_NONE; - } - - rc = hp_register_read_word(php_ctlr->pci_dev, SLOT_STATUS(ctrl->cap_base), slot_status); + rc = pciehp_readw(ctrl, SLOTSTATUS, &slot_status); if (rc) { - err("%s : hp_register_read_word SLOT_STATUS failed\n", __FUNCTION__); + err("%s: Cannot read SLOTSTATUS register\n", __FUNCTION__); return IRQ_NONE; } @@ -910,33 +788,38 @@ static irqreturn_t pcie_isr(int IRQ, voi dbg("%s: intr_loc %x\n", __FUNCTION__, intr_loc); /* Mask Hot-plug Interrupt Enable */ if (!pciehp_poll_mode) { - rc = hp_register_read_word(php_ctlr->pci_dev, SLOT_CTRL(ctrl->cap_base), temp_word); + rc = pciehp_readw(ctrl, SLOTCTRL, &temp_word); if (rc) { - err("%s : hp_register_read_word SLOT_CTRL failed\n", __FUNCTION__); + err("%s: Cannot read SLOT_CTRL register\n", + __FUNCTION__); return IRQ_NONE; } - dbg("%s: hp_register_read_word SLOT_CTRL with value %x\n", __FUNCTION__, temp_word); + dbg("%s: pciehp_readw(SLOTCTRL) with value %x\n", + __FUNCTION__, temp_word); temp_word = (temp_word & ~HP_INTR_ENABLE & ~CMD_CMPL_INTR_ENABLE) | 0x00; - - rc = hp_register_write_word(php_ctlr->pci_dev, SLOT_CTRL(ctrl->cap_base), temp_word); + rc = pciehp_writew(ctrl, SLOTCTRL, temp_word); if (rc) { - err("%s : hp_register_write_word SLOT_CTRL failed\n", __FUNCTION__); + err("%s: Cannot write to SLOTCTRL register\n", + __FUNCTION__); return IRQ_NONE; } - - rc = hp_register_read_word(php_ctlr->pci_dev, SLOT_STATUS(ctrl->cap_base), slot_status); + + rc = pciehp_readw(ctrl, SLOTSTATUS, &slot_status); if (rc) { - err("%s : hp_register_read_word SLOT_STATUS failed\n", __FUNCTION__); + err("%s: Cannot read SLOT_STATUS register\n", + __FUNCTION__); return IRQ_NONE; } - dbg("%s: hp_register_read_word SLOT_STATUS with value %x\n", __FUNCTION__, slot_status); + dbg("%s: pciehp_readw(SLOTSTATUS) with value %x\n", + __FUNCTION__, slot_status); /* Clear command complete interrupt caused by this write */ temp_word = 0x1f; - rc = hp_register_write_word(php_ctlr->pci_dev, SLOT_STATUS(ctrl->cap_base), temp_word); + rc = pciehp_writew(ctrl, SLOTSTATUS, temp_word); if (rc) { - err("%s : hp_register_write_word SLOT_STATUS failed\n", __FUNCTION__); + err("%s: Cannot write to SLOTSTATUS register\n", + __FUNCTION__); return IRQ_NONE; } } @@ -945,60 +828,65 @@ static irqreturn_t pcie_isr(int IRQ, voi /* * Command Complete Interrupt Pending */ + ctrl->cmd_busy = 0; wake_up_interruptible(&ctrl->queue); } - if ((php_ctlr->switch_change_callback) && (intr_loc & MRL_SENS_CHANGED)) - schedule_flag += php_ctlr->switch_change_callback( - hp_slot, php_ctlr->callback_instance_id); - if ((php_ctlr->attention_button_callback) && (intr_loc & ATTN_BUTTN_PRESSED)) - schedule_flag += php_ctlr->attention_button_callback( - hp_slot, php_ctlr->callback_instance_id); - if ((php_ctlr->presence_change_callback) && (intr_loc & PRSN_DETECT_CHANGED)) - schedule_flag += php_ctlr->presence_change_callback( - hp_slot , php_ctlr->callback_instance_id); - if ((php_ctlr->power_fault_callback) && (intr_loc & PWR_FAULT_DETECTED)) - schedule_flag += php_ctlr->power_fault_callback( - hp_slot, php_ctlr->callback_instance_id); + if (intr_loc & MRL_SENS_CHANGED) + pciehp_handle_switch_change(hp_slot, ctrl); + + if (intr_loc & ATTN_BUTTN_PRESSED) + pciehp_handle_attention_button(hp_slot, ctrl); + + if (intr_loc & PRSN_DETECT_CHANGED) + pciehp_handle_presence_change(hp_slot, ctrl); + + if (intr_loc & PWR_FAULT_DETECTED) + pciehp_handle_power_fault(hp_slot, ctrl); /* Clear all events after serving them */ temp_word = 0x1F; - rc = hp_register_write_word(php_ctlr->pci_dev, SLOT_STATUS(ctrl->cap_base), temp_word); + rc = pciehp_writew(ctrl, SLOTSTATUS, temp_word); if (rc) { - err("%s : hp_register_write_word SLOT_STATUS failed\n", __FUNCTION__); + err("%s: Cannot write to SLOTSTATUS register\n", __FUNCTION__); return IRQ_NONE; } /* Unmask Hot-plug Interrupt Enable */ if (!pciehp_poll_mode) { - rc = hp_register_read_word(php_ctlr->pci_dev, SLOT_CTRL(ctrl->cap_base), temp_word); + rc = pciehp_readw(ctrl, SLOTCTRL, &temp_word); if (rc) { - err("%s : hp_register_read_word SLOT_CTRL failed\n", __FUNCTION__); + err("%s: Cannot read SLOTCTRL register\n", + __FUNCTION__); return IRQ_NONE; } dbg("%s: Unmask Hot-plug Interrupt Enable\n", __FUNCTION__); temp_word = (temp_word & ~HP_INTR_ENABLE) | HP_INTR_ENABLE; - rc = hp_register_write_word(php_ctlr->pci_dev, SLOT_CTRL(ctrl->cap_base), temp_word); + rc = pciehp_writew(ctrl, SLOTCTRL, temp_word); if (rc) { - err("%s : hp_register_write_word SLOT_CTRL failed\n", __FUNCTION__); + err("%s: Cannot write to SLOTCTRL register\n", + __FUNCTION__); return IRQ_NONE; } - - rc = hp_register_read_word(php_ctlr->pci_dev, SLOT_STATUS(ctrl->cap_base), slot_status); + + rc = pciehp_readw(ctrl, SLOTSTATUS, &slot_status); if (rc) { - err("%s : hp_register_read_word SLOT_STATUS failed\n", __FUNCTION__); + err("%s: Cannot read SLOT_STATUS register\n", + __FUNCTION__); return IRQ_NONE; } /* Clear command complete interrupt caused by this write */ temp_word = 0x1F; - rc = hp_register_write_word(php_ctlr->pci_dev, SLOT_STATUS(ctrl->cap_base), temp_word); + rc = pciehp_writew(ctrl, SLOTSTATUS, temp_word); if (rc) { - err("%s : hp_register_write_word SLOT_STATUS failed\n", __FUNCTION__); + err("%s: Cannot write to SLOTSTATUS failed\n", + __FUNCTION__); return IRQ_NONE; } - dbg("%s: hp_register_write_word SLOT_STATUS with value %x\n", __FUNCTION__, temp_word); + dbg("%s: pciehp_writew(SLOTSTATUS) with value %x\n", + __FUNCTION__, temp_word); } return IRQ_HANDLED; @@ -1006,27 +894,16 @@ static irqreturn_t pcie_isr(int IRQ, voi static int hpc_get_max_lnk_speed (struct slot *slot, enum pci_bus_speed *value) { - struct php_ctlr_state_s *php_ctlr = slot->ctrl->hpc_ctlr_handle; + struct controller *ctrl = slot->ctrl; enum pcie_link_speed lnk_speed; u32 lnk_cap; int retval = 0; DBG_ENTER_ROUTINE - if (!php_ctlr) { - err("%s: Invalid HPC controller handle!\n", __FUNCTION__); - return -1; - } - - if (slot->hp_slot >= php_ctlr->num_slots) { - err("%s: Invalid HPC slot number!\n", __FUNCTION__); - return -1; - } - - retval = hp_register_read_dword(php_ctlr->pci_dev, LNK_CAP(slot->ctrl->cap_base), lnk_cap); - + retval = pciehp_readl(ctrl, LNKCAP, &lnk_cap); if (retval) { - err("%s : hp_register_read_dword LNK_CAP failed\n", __FUNCTION__); + err("%s: Cannot read LNKCAP register\n", __FUNCTION__); return retval; } @@ -1047,27 +924,16 @@ static int hpc_get_max_lnk_speed (struct static int hpc_get_max_lnk_width (struct slot *slot, enum pcie_link_width *value) { - struct php_ctlr_state_s *php_ctlr = slot->ctrl->hpc_ctlr_handle; + struct controller *ctrl = slot->ctrl; enum pcie_link_width lnk_wdth; u32 lnk_cap; int retval = 0; DBG_ENTER_ROUTINE - if (!php_ctlr) { - err("%s: Invalid HPC controller handle!\n", __FUNCTION__); - return -1; - } - - if (slot->hp_slot >= php_ctlr->num_slots) { - err("%s: Invalid HPC slot number!\n", __FUNCTION__); - return -1; - } - - retval = hp_register_read_dword(php_ctlr->pci_dev, LNK_CAP(slot->ctrl->cap_base), lnk_cap); - + retval = pciehp_readl(ctrl, LNKCAP, &lnk_cap); if (retval) { - err("%s : hp_register_read_dword LNK_CAP failed\n", __FUNCTION__); + err("%s: Cannot read LNKCAP register\n", __FUNCTION__); return retval; } @@ -1109,27 +975,16 @@ static int hpc_get_max_lnk_width (struct static int hpc_get_cur_lnk_speed (struct slot *slot, enum pci_bus_speed *value) { - struct php_ctlr_state_s *php_ctlr = slot->ctrl->hpc_ctlr_handle; + struct controller *ctrl = slot->ctrl; enum pcie_link_speed lnk_speed = PCI_SPEED_UNKNOWN; int retval = 0; u16 lnk_status; DBG_ENTER_ROUTINE - if (!php_ctlr) { - err("%s: Invalid HPC controller handle!\n", __FUNCTION__); - return -1; - } - - if (slot->hp_slot >= php_ctlr->num_slots) { - err("%s: Invalid HPC slot number!\n", __FUNCTION__); - return -1; - } - - retval = hp_register_read_word(php_ctlr->pci_dev, LNK_STATUS(slot->ctrl->cap_base), lnk_status); - + retval = pciehp_readw(ctrl, LNKSTATUS, &lnk_status); if (retval) { - err("%s : hp_register_read_word LNK_STATUS failed\n", __FUNCTION__); + err("%s: Cannot read LNKSTATUS register\n", __FUNCTION__); return retval; } @@ -1150,27 +1005,16 @@ static int hpc_get_cur_lnk_speed (struct static int hpc_get_cur_lnk_width (struct slot *slot, enum pcie_link_width *value) { - struct php_ctlr_state_s *php_ctlr = slot->ctrl->hpc_ctlr_handle; + struct controller *ctrl = slot->ctrl; enum pcie_link_width lnk_wdth = PCIE_LNK_WIDTH_UNKNOWN; int retval = 0; u16 lnk_status; DBG_ENTER_ROUTINE - if (!php_ctlr) { - err("%s: Invalid HPC controller handle!\n", __FUNCTION__); - return -1; - } - - if (slot->hp_slot >= php_ctlr->num_slots) { - err("%s: Invalid HPC slot number!\n", __FUNCTION__); - return -1; - } - - retval = hp_register_read_word(php_ctlr->pci_dev, LNK_STATUS(slot->ctrl->cap_base), lnk_status); - + retval = pciehp_readw(ctrl, LNKSTATUS, &lnk_status); if (retval) { - err("%s : hp_register_read_word LNK_STATUS failed\n", __FUNCTION__); + err("%s: Cannot read LNKSTATUS register\n", __FUNCTION__); return retval; } @@ -1218,6 +1062,8 @@ static struct hpc_ops pciehp_hpc_ops = { .get_attention_status = hpc_get_attention_status, .get_latch_status = hpc_get_latch_status, .get_adapter_status = hpc_get_adapter_status, + .get_emi_status = hpc_get_emi_status, + .toggle_emi = hpc_toggle_emi, .get_max_bus_speed = hpc_get_max_lnk_speed, .get_cur_bus_speed = hpc_get_cur_lnk_speed, @@ -1305,38 +1151,24 @@ #endif int pcie_init(struct controller * ctrl, struct pcie_device *dev) { - struct php_ctlr_state_s *php_ctlr, *p; - void *instance_id = ctrl; int rc; static int first = 1; u16 temp_word; u16 cap_reg; u16 intr_enable = 0; u32 slot_cap; - int cap_base, saved_cap_base; + int cap_base; u16 slot_status, slot_ctrl; struct pci_dev *pdev; DBG_ENTER_ROUTINE - spin_lock_init(&list_lock); - php_ctlr = kmalloc(sizeof(struct php_ctlr_state_s), GFP_KERNEL); - - if (!php_ctlr) { /* allocate controller state data */ - err("%s: HPC controller memory allocation error!\n", __FUNCTION__); - goto abort; - } - - memset(php_ctlr, 0, sizeof(struct php_ctlr_state_s)); - pdev = dev->port; - php_ctlr->pci_dev = pdev; /* save pci_dev in context */ + ctrl->pci_dev = pdev; /* save pci_dev in context */ dbg("%s: hotplug controller vendor id 0x%x device id 0x%x\n", __FUNCTION__, pdev->vendor, pdev->device); - saved_cap_base = pcie_cap_base; - if ((cap_base = pci_find_capability(pdev, PCI_CAP_ID_EXP)) == 0) { dbg("%s: Can't find PCI_CAP_ID_EXP (0x10)\n", __FUNCTION__); goto abort_free_ctlr; @@ -1344,14 +1176,15 @@ int pcie_init(struct controller * ctrl, ctrl->cap_base = cap_base; - dbg("%s: pcie_cap_base %x\n", __FUNCTION__, pcie_cap_base); + dbg("%s: pcie_cap_base %x\n", __FUNCTION__, cap_base); - rc = hp_register_read_word(pdev, CAP_REG(ctrl->cap_base), cap_reg); + rc = pciehp_readw(ctrl, CAPREG, &cap_reg); if (rc) { - err("%s : hp_register_read_word CAP_REG failed\n", __FUNCTION__); + err("%s: Cannot read CAPREG register\n", __FUNCTION__); goto abort_free_ctlr; } - dbg("%s: CAP_REG offset %x cap_reg %x\n", __FUNCTION__, CAP_REG(ctrl->cap_base), cap_reg); + dbg("%s: CAPREG offset %x cap_reg %x\n", + __FUNCTION__, ctrl->cap_base + CAPREG, cap_reg); if (((cap_reg & SLOT_IMPL) == 0) || (((cap_reg & DEV_PORT_TYPE) != 0x0040) && ((cap_reg & DEV_PORT_TYPE) != 0x0060))) { @@ -1359,31 +1192,34 @@ int pcie_init(struct controller * ctrl, goto abort_free_ctlr; } - rc = hp_register_read_dword(php_ctlr->pci_dev, SLOT_CAP(ctrl->cap_base), slot_cap); + rc = pciehp_readl(ctrl, SLOTCAP, &slot_cap); if (rc) { - err("%s : hp_register_read_word CAP_REG failed\n", __FUNCTION__); + err("%s: Cannot read SLOTCAP register\n", __FUNCTION__); goto abort_free_ctlr; } - dbg("%s: SLOT_CAP offset %x slot_cap %x\n", __FUNCTION__, SLOT_CAP(ctrl->cap_base), slot_cap); + dbg("%s: SLOTCAP offset %x slot_cap %x\n", + __FUNCTION__, ctrl->cap_base + SLOTCAP, slot_cap); if (!(slot_cap & HP_CAP)) { dbg("%s : This slot is not hot-plug capable\n", __FUNCTION__); goto abort_free_ctlr; } /* For debugging purpose */ - rc = hp_register_read_word(php_ctlr->pci_dev, SLOT_STATUS(ctrl->cap_base), slot_status); + rc = pciehp_readw(ctrl, SLOTSTATUS, &slot_status); if (rc) { - err("%s : hp_register_read_word SLOT_STATUS failed\n", __FUNCTION__); + err("%s: Cannot read SLOTSTATUS register\n", __FUNCTION__); goto abort_free_ctlr; } - dbg("%s: SLOT_STATUS offset %x slot_status %x\n", __FUNCTION__, SLOT_STATUS(ctrl->cap_base), slot_status); + dbg("%s: SLOTSTATUS offset %x slot_status %x\n", + __FUNCTION__, ctrl->cap_base + SLOTSTATUS, slot_status); - rc = hp_register_read_word(php_ctlr->pci_dev, SLOT_CTRL(ctrl->cap_base), slot_ctrl); + rc = pciehp_readw(ctrl, SLOTCTRL, &slot_ctrl); if (rc) { - err("%s : hp_register_read_word SLOT_CTRL failed\n", __FUNCTION__); + err("%s: Cannot read SLOTCTRL register\n", __FUNCTION__); goto abort_free_ctlr; } - dbg("%s: SLOT_CTRL offset %x slot_ctrl %x\n", __FUNCTION__, SLOT_CTRL(ctrl->cap_base), slot_ctrl); + dbg("%s: SLOTCTRL offset %x slot_ctrl %x\n", + __FUNCTION__, ctrl->cap_base + SLOTCTRL, slot_ctrl); if (first) { spin_lock_init(&hpc_event_lock); @@ -1405,69 +1241,64 @@ int pcie_init(struct controller * ctrl, /* setup wait queue */ init_waitqueue_head(&ctrl->queue); - /* find the IRQ */ - php_ctlr->irq = dev->irq; - - /* Save interrupt callback info */ - php_ctlr->attention_button_callback = pciehp_handle_attention_button; - php_ctlr->switch_change_callback = pciehp_handle_switch_change; - php_ctlr->presence_change_callback = pciehp_handle_presence_change; - php_ctlr->power_fault_callback = pciehp_handle_power_fault; - php_ctlr->callback_instance_id = instance_id; - /* return PCI Controller Info */ - php_ctlr->slot_device_offset = 0; - php_ctlr->num_slots = 1; + ctrl->slot_device_offset = 0; + ctrl->num_slots = 1; + ctrl->first_slot = slot_cap >> 19; + ctrl->ctrlcap = slot_cap & 0x0000007f; /* Mask Hot-plug Interrupt Enable */ - rc = hp_register_read_word(pdev, SLOT_CTRL(ctrl->cap_base), temp_word); + rc = pciehp_readw(ctrl, SLOTCTRL, &temp_word); if (rc) { - err("%s : hp_register_read_word SLOT_CTRL failed\n", __FUNCTION__); + err("%s: Cannot read SLOTCTRL register\n", __FUNCTION__); goto abort_free_ctlr; } - dbg("%s: SLOT_CTRL %x value read %x\n", __FUNCTION__, SLOT_CTRL(ctrl->cap_base), temp_word); + dbg("%s: SLOTCTRL %x value read %x\n", + __FUNCTION__, ctrl->cap_base + SLOTCTRL, temp_word); temp_word = (temp_word & ~HP_INTR_ENABLE & ~CMD_CMPL_INTR_ENABLE) | 0x00; - rc = hp_register_write_word(pdev, SLOT_CTRL(ctrl->cap_base), temp_word); + rc = pciehp_writew(ctrl, SLOTCTRL, temp_word); if (rc) { - err("%s : hp_register_write_word SLOT_CTRL failed\n", __FUNCTION__); + err("%s: Cannot write to SLOTCTRL register\n", __FUNCTION__); goto abort_free_ctlr; } - rc = hp_register_read_word(php_ctlr->pci_dev, SLOT_STATUS(ctrl->cap_base), slot_status); + rc = pciehp_readw(ctrl, SLOTSTATUS, &slot_status); if (rc) { - err("%s : hp_register_read_word SLOT_STATUS failed\n", __FUNCTION__); + err("%s: Cannot read SLOTSTATUS register\n", __FUNCTION__); goto abort_free_ctlr; } temp_word = 0x1F; /* Clear all events */ - rc = hp_register_write_word(php_ctlr->pci_dev, SLOT_STATUS(ctrl->cap_base), temp_word); + rc = pciehp_writew(ctrl, SLOTSTATUS, temp_word); if (rc) { - err("%s : hp_register_write_word SLOT_STATUS failed\n", __FUNCTION__); + err("%s: Cannot write to SLOTSTATUS register\n", __FUNCTION__); goto abort_free_ctlr; } - if (pciehp_poll_mode) {/* Install interrupt polling code */ - /* Install and start the interrupt polling timer */ - init_timer(&php_ctlr->int_poll_timer); - start_int_poll_timer( php_ctlr, 10 ); /* start with 10 second delay */ + if (pciehp_poll_mode) { + /* Install interrupt polling timer. Start with 10 sec delay */ + init_timer(&ctrl->poll_timer); + start_int_poll_timer(ctrl, 10); } else { /* Installs the interrupt handler */ - rc = request_irq(php_ctlr->irq, pcie_isr, IRQF_SHARED, MY_NAME, (void *) ctrl); - dbg("%s: request_irq %d for hpc%d (returns %d)\n", __FUNCTION__, php_ctlr->irq, ctlr_seq_num, rc); + rc = request_irq(ctrl->pci_dev->irq, pcie_isr, IRQF_SHARED, + MY_NAME, (void *)ctrl); + dbg("%s: request_irq %d for hpc%d (returns %d)\n", + __FUNCTION__, ctrl->pci_dev->irq, ctlr_seq_num, rc); if (rc) { - err("Can't get irq %d for the hotplug controller\n", php_ctlr->irq); + err("Can't get irq %d for the hotplug controller\n", + ctrl->pci_dev->irq); goto abort_free_ctlr; } } - dbg("pciehp ctrl b:d:f:irq=0x%x:%x:%x:%x\n", pdev->bus->number, PCI_SLOT(pdev->devfn), PCI_FUNC(pdev->devfn), dev->irq); - rc = hp_register_read_word(pdev, SLOT_CTRL(ctrl->cap_base), temp_word); + rc = pciehp_readw(ctrl, SLOTCTRL, &temp_word); if (rc) { - err("%s : hp_register_read_word SLOT_CTRL failed\n", __FUNCTION__); + err("%s: Cannot read SLOTCTRL register\n", __FUNCTION__); goto abort_free_irq; } @@ -1491,21 +1322,21 @@ int pcie_init(struct controller * ctrl, } /* Unmask Hot-plug Interrupt Enable for the interrupt notification mechanism case */ - rc = hp_register_write_word(pdev, SLOT_CTRL(ctrl->cap_base), temp_word); + rc = pciehp_writew(ctrl, SLOTCTRL, temp_word); if (rc) { - err("%s : hp_register_write_word SLOT_CTRL failed\n", __FUNCTION__); + err("%s: Cannot write to SLOTCTRL register\n", __FUNCTION__); goto abort_free_irq; } - rc = hp_register_read_word(php_ctlr->pci_dev, SLOT_STATUS(ctrl->cap_base), slot_status); + rc = pciehp_readw(ctrl, SLOTSTATUS, &slot_status); if (rc) { - err("%s : hp_register_read_word SLOT_STATUS failed\n", __FUNCTION__); + err("%s: Cannot read SLOTSTATUS register\n", __FUNCTION__); goto abort_disable_intr; } temp_word = 0x1F; /* Clear all events */ - rc = hp_register_write_word(php_ctlr->pci_dev, SLOT_STATUS(ctrl->cap_base), temp_word); + rc = pciehp_writew(ctrl, SLOTSTATUS, temp_word); if (rc) { - err("%s : hp_register_write_word SLOT_STATUS failed\n", __FUNCTION__); + err("%s: Cannot write to SLOTSTATUS register\n", __FUNCTION__); goto abort_disable_intr; } @@ -1518,24 +1349,7 @@ int pcie_init(struct controller * ctrl, goto abort_disable_intr; } - /* Add this HPC instance into the HPC list */ - spin_lock(&list_lock); - if (php_ctlr_list_head == 0) { - php_ctlr_list_head = php_ctlr; - p = php_ctlr_list_head; - p->pnext = NULL; - } else { - p = php_ctlr_list_head; - - while (p->pnext) - p = p->pnext; - - p->pnext = php_ctlr; - } - spin_unlock(&list_lock); - ctlr_seq_num++; - ctrl->hpc_ctlr_handle = php_ctlr; ctrl->hpc_ops = &pciehp_hpc_ops; DBG_LEAVE_ROUTINE @@ -1543,24 +1357,21 @@ int pcie_init(struct controller * ctrl, /* We end up here for the many possible ways to fail this API. */ abort_disable_intr: - rc = hp_register_read_word(pdev, SLOT_CTRL(ctrl->cap_base), temp_word); + rc = pciehp_readw(ctrl, SLOTCTRL, &temp_word); if (!rc) { temp_word &= ~(intr_enable | HP_INTR_ENABLE); - rc = hp_register_write_word(pdev, SLOT_CTRL(ctrl->cap_base), temp_word); + rc = pciehp_writew(ctrl, SLOTCTRL, temp_word); } if (rc) err("%s : disabling interrupts failed\n", __FUNCTION__); abort_free_irq: if (pciehp_poll_mode) - del_timer_sync(&php_ctlr->int_poll_timer); + del_timer_sync(&ctrl->poll_timer); else - free_irq(php_ctlr->irq, ctrl); + free_irq(ctrl->pci_dev->irq, ctrl); abort_free_ctlr: - pcie_cap_base = saved_cap_base; - kfree(php_ctlr); -abort: DBG_LEAVE_ROUTINE return -1; } diff --git a/drivers/pci/hotplug/sgi_hotplug.c b/drivers/pci/hotplug/sgi_hotplug.c index 5d188c5..78cf071 100644 --- a/drivers/pci/hotplug/sgi_hotplug.c +++ b/drivers/pci/hotplug/sgi_hotplug.c @@ -28,6 +28,8 @@ #include #include #include #include +#include +#include #include "../pci.h" @@ -35,14 +37,17 @@ MODULE_LICENSE("GPL"); MODULE_AUTHOR("SGI (prarit@sgi.com, dickie@sgi.com, habeck@sgi.com)"); MODULE_DESCRIPTION("SGI Altix Hot Plug PCI Controller Driver"); -#define PCIIO_ASIC_TYPE_TIOCA 4 + +/* SAL call error codes. Keep in sync with prom header io/include/pcibr.h */ #define PCI_SLOT_ALREADY_UP 2 /* slot already up */ #define PCI_SLOT_ALREADY_DOWN 3 /* slot already down */ #define PCI_L1_ERR 7 /* L1 console command error */ #define PCI_EMPTY_33MHZ 15 /* empty 33 MHz bus */ + + +#define PCIIO_ASIC_TYPE_TIOCA 4 #define PCI_L1_QSIZE 128 /* our L1 message buffer size */ #define SN_MAX_HP_SLOTS 32 /* max hotplug slots */ -#define SGI_HOTPLUG_PROM_REV 0x0430 /* Min. required PROM version */ #define SN_SLOT_NAME_SIZE 33 /* size of name string */ /* internal list head */ @@ -227,7 +232,7 @@ static void sn_bus_free_data(struct pci_ } static int sn_slot_enable(struct hotplug_slot *bss_hotplug_slot, - int device_num) + int device_num, char **ssdt) { struct slot *slot = bss_hotplug_slot->private; struct pcibus_info *pcibus_info; @@ -240,7 +245,8 @@ static int sn_slot_enable(struct hotplug * Power-on and initialize the slot in the SN * PCI infrastructure. */ - rc = sal_pcibr_slot_enable(pcibus_info, device_num, &resp); + rc = sal_pcibr_slot_enable(pcibus_info, device_num, &resp, ssdt); + if (rc == PCI_SLOT_ALREADY_UP) { dev_dbg(slot->pci_bus->self, "is already active\n"); @@ -335,6 +341,7 @@ static int enable_slot(struct hotplug_sl int func, num_funcs; int new_ppb = 0; int rc; + char *ssdt = NULL; void pcibios_fixup_device_resources(struct pci_dev *); /* Serialize the Linux PCI infrastructure */ @@ -342,14 +349,29 @@ static int enable_slot(struct hotplug_sl /* * Power-on and initialize the slot in the SN - * PCI infrastructure. + * PCI infrastructure. Also, retrieve the ACPI SSDT + * table for the slot (if ACPI capable PROM). */ - rc = sn_slot_enable(bss_hotplug_slot, slot->device_num); + rc = sn_slot_enable(bss_hotplug_slot, slot->device_num, &ssdt); if (rc) { mutex_unlock(&sn_hotplug_mutex); return rc; } + if (ssdt) + ssdt = __va(ssdt); + /* Add the new SSDT for the slot to the ACPI namespace */ + if (SN_ACPI_BASE_SUPPORT() && ssdt) { + acpi_status ret; + + ret = acpi_load_table((struct acpi_table_header *)ssdt); + if (ACPI_FAILURE(ret)) { + printk(KERN_ERR "%s: acpi_load_table failed (0x%x)\n", + __FUNCTION__, ret); + /* try to continue on */ + } + } + num_funcs = pci_scan_slot(slot->pci_bus, PCI_DEVFN(slot->device_num + 1, 0)); if (!num_funcs) { @@ -374,7 +396,10 @@ static int enable_slot(struct hotplug_sl * pdi_host_pcidev_info). */ pcibios_fixup_device_resources(dev); - sn_pci_fixup_slot(dev); + if (SN_ACPI_BASE_SUPPORT()) + sn_acpi_slot_fixup(dev); + else + sn_io_slot_fixup(dev); if (dev->hdr_type == PCI_HEADER_TYPE_BRIDGE) { unsigned char sec_bus; pci_read_config_byte(dev, PCI_SECONDARY_BUS, @@ -388,6 +413,63 @@ static int enable_slot(struct hotplug_sl } } + /* + * Add the slot's devices to the ACPI infrastructure */ + if (SN_ACPI_BASE_SUPPORT() && ssdt) { + unsigned long adr; + struct acpi_device *pdevice; + struct acpi_device *device; + acpi_handle phandle; + acpi_handle chandle = NULL; + acpi_handle rethandle; + acpi_status ret; + + phandle = PCI_CONTROLLER(slot->pci_bus)->acpi_handle; + + if (acpi_bus_get_device(phandle, &pdevice)) { + dev_dbg(slot->pci_bus->self, + "no parent device, assuming NULL\n"); + pdevice = NULL; + } + + /* + * Walk the rootbus node's immediate children looking for + * the slot's device node(s). There can be more than + * one for multifunction devices. + */ + for (;;) { + rethandle = NULL; + ret = acpi_get_next_object(ACPI_TYPE_DEVICE, + phandle, chandle, + &rethandle); + + if (ret == AE_NOT_FOUND || rethandle == NULL) + break; + + chandle = rethandle; + + ret = acpi_evaluate_integer(chandle, METHOD_NAME__ADR, + NULL, &adr); + + if (ACPI_SUCCESS(ret) && + (adr>>16) == (slot->device_num + 1)) { + + ret = acpi_bus_add(&device, pdevice, chandle, + ACPI_BUS_TYPE_DEVICE); + if (ACPI_FAILURE(ret)) { + printk(KERN_ERR "%s: acpi_bus_add " + "failed (0x%x) for slot %d " + "func %d\n", __FUNCTION__, + ret, (int)(adr>>16), + (int)(adr&0xffff)); + /* try to continue on */ + } else { + acpi_bus_start(device); + } + } + } + } + /* Call the driver for the new device */ pci_bus_add_devices(slot->pci_bus); /* Call the drivers for the new devices subordinate to PPB */ @@ -412,6 +494,7 @@ static int disable_slot(struct hotplug_s struct pci_dev *dev; int func; int rc; + acpi_owner_id ssdt_id = 0; /* Acquire update access to the bus */ mutex_lock(&sn_hotplug_mutex); @@ -422,6 +505,52 @@ static int disable_slot(struct hotplug_s if (rc) goto leaving; + /* free the ACPI resources for the slot */ + if (SN_ACPI_BASE_SUPPORT() && + PCI_CONTROLLER(slot->pci_bus)->acpi_handle) { + unsigned long adr; + struct acpi_device *device; + acpi_handle phandle; + acpi_handle chandle = NULL; + acpi_handle rethandle; + acpi_status ret; + + /* Get the rootbus node pointer */ + phandle = PCI_CONTROLLER(slot->pci_bus)->acpi_handle; + + /* + * Walk the rootbus node's immediate children looking for + * the slot's device node(s). There can be more than + * one for multifunction devices. + */ + for (;;) { + rethandle = NULL; + ret = acpi_get_next_object(ACPI_TYPE_DEVICE, + phandle, chandle, + &rethandle); + + if (ret == AE_NOT_FOUND || rethandle == NULL) + break; + + chandle = rethandle; + + ret = acpi_evaluate_integer(chandle, + METHOD_NAME__ADR, + NULL, &adr); + if (ACPI_SUCCESS(ret) && + (adr>>16) == (slot->device_num + 1)) { + /* retain the owner id */ + acpi_get_id(chandle, &ssdt_id); + + ret = acpi_bus_get_device(chandle, + &device); + if (ACPI_SUCCESS(ret)) + acpi_bus_trim(device, 1); + } + } + + } + /* Free the SN resources assigned to the Linux device.*/ for (func = 0; func < 8; func++) { dev = pci_get_slot(slot->pci_bus, @@ -434,6 +563,18 @@ static int disable_slot(struct hotplug_s } } + /* Remove the SSDT for the slot from the ACPI namespace */ + if (SN_ACPI_BASE_SUPPORT() && ssdt_id) { + acpi_status ret; + ret = acpi_unload_table_id(ssdt_id); + if (ACPI_FAILURE(ret)) { + printk(KERN_ERR "%s: acpi_unload_table_id " + "failed (0x%x) for id %d\n", + __FUNCTION__, ret, ssdt_id); + /* try to continue on */ + } + } + /* free the collected sysdata pointers */ sn_bus_free_sysdata(); diff --git a/drivers/pci/hotplug/shpchp.h b/drivers/pci/hotplug/shpchp.h index 3ca6a4f..01d31a1 100644 --- a/drivers/pci/hotplug/shpchp.h +++ b/drivers/pci/hotplug/shpchp.h @@ -106,7 +106,7 @@ struct controller { }; /* Define AMD SHPC ID */ -#define PCI_DEVICE_ID_AMD_GOLAM_7450 0x7450 +#define PCI_DEVICE_ID_AMD_GOLAM_7450 0x7450 #define PCI_DEVICE_ID_AMD_POGO_7458 0x7458 /* AMD PCIX bridge registers */ @@ -221,7 +221,7 @@ enum ctrl_offsets { }; static inline struct slot *get_slot(struct hotplug_slot *hotplug_slot) -{ +{ return hotplug_slot->private; } diff --git a/drivers/pci/hotplug/shpchp_core.c b/drivers/pci/hotplug/shpchp_core.c index 590cd3c..5f4bc08 100644 --- a/drivers/pci/hotplug/shpchp_core.c +++ b/drivers/pci/hotplug/shpchp_core.c @@ -401,10 +401,6 @@ static int __init shpcd_init(void) { int retval = 0; -#ifdef CONFIG_HOTPLUG_PCI_SHPC_POLL_EVENT_MODE - shpchp_poll_mode = 1; -#endif - retval = pci_register_driver(&shpc_driver); dbg("%s: pci_register_driver = %d\n", __FUNCTION__, retval); info(DRIVER_DESC " version: " DRIVER_VERSION "\n"); diff --git a/drivers/pci/hotplug/shpchp_ctrl.c b/drivers/pci/hotplug/shpchp_ctrl.c index 6bb8473..b746bd2 100644 --- a/drivers/pci/hotplug/shpchp_ctrl.c +++ b/drivers/pci/hotplug/shpchp_ctrl.c @@ -64,7 +64,7 @@ u8 shpchp_handle_attention_button(u8 hp_ /* Attention Button Change */ dbg("shpchp: Attention button interrupt received.\n"); - + p_slot = shpchp_find_slot(ctrl, hp_slot + ctrl->slot_device_offset); p_slot->hpc_ops->get_adapter_status(p_slot, &(p_slot->presence_save)); @@ -128,7 +128,7 @@ u8 shpchp_handle_presence_change(u8 hp_s p_slot = shpchp_find_slot(ctrl, hp_slot + ctrl->slot_device_offset); - /* + /* * Save the presence state */ p_slot->hpc_ops->get_adapter_status(p_slot, &(p_slot->presence_save)); @@ -184,12 +184,12 @@ u8 shpchp_handle_power_fault(u8 hp_slot, return 1; } -/* The following routines constitute the bulk of the +/* The following routines constitute the bulk of the hotplug controller logic */ static int change_bus_speed(struct controller *ctrl, struct slot *p_slot, enum pci_bus_speed speed) -{ +{ int rc = 0; dbg("%s: change to speed %d\n", __FUNCTION__, speed); @@ -204,7 +204,7 @@ static int change_bus_speed(struct contr static int fix_bus_speed(struct controller *ctrl, struct slot *pslot, u8 flag, enum pci_bus_speed asp, enum pci_bus_speed bsp, enum pci_bus_speed msp) -{ +{ int rc = 0; /* @@ -257,23 +257,23 @@ static int board_added(struct slot *p_sl err("%s: Failed to power on slot\n", __FUNCTION__); return -1; } - + if ((ctrl->pci_dev->vendor == 0x8086) && (ctrl->pci_dev->device == 0x0332)) { if (slots_not_empty) return WRONG_BUS_FREQUENCY; - + if ((rc = p_slot->hpc_ops->set_bus_speed_mode(p_slot, PCI_SPEED_33MHz))) { err("%s: Issue of set bus speed mode command failed\n", __FUNCTION__); return WRONG_BUS_FREQUENCY; } - + /* turn on board, blink green LED, turn off Amber LED */ if ((rc = p_slot->hpc_ops->slot_enable(p_slot))) { err("%s: Issue of Slot Enable command failed\n", __FUNCTION__); return rc; } } - + rc = p_slot->hpc_ops->get_adapter_speed(p_slot, &asp); if (rc) { err("%s: Can't get adapter speed or bus mode mismatch\n", @@ -378,7 +378,7 @@ static int remove_board(struct slot *p_s err("%s: Issue of Slot Disable command failed\n", __FUNCTION__); return rc; } - + rc = p_slot->hpc_ops->set_attention_status(p_slot, 0); if (rc) { err("%s: Issue of Set Attention command failed\n", __FUNCTION__); diff --git a/drivers/pci/hotplug/shpchp_hpc.c b/drivers/pci/hotplug/shpchp_hpc.c index b7bede4..5183a45 100644 --- a/drivers/pci/hotplug/shpchp_hpc.c +++ b/drivers/pci/hotplug/shpchp_hpc.c @@ -35,38 +35,6 @@ #include #include "shpchp.h" -#ifdef DEBUG -#define DBG_K_TRACE_ENTRY ((unsigned int)0x00000001) /* On function entry */ -#define DBG_K_TRACE_EXIT ((unsigned int)0x00000002) /* On function exit */ -#define DBG_K_INFO ((unsigned int)0x00000004) /* Info messages */ -#define DBG_K_ERROR ((unsigned int)0x00000008) /* Error messages */ -#define DBG_K_TRACE (DBG_K_TRACE_ENTRY|DBG_K_TRACE_EXIT) -#define DBG_K_STANDARD (DBG_K_INFO|DBG_K_ERROR|DBG_K_TRACE) -/* Redefine this flagword to set debug level */ -#define DEBUG_LEVEL DBG_K_STANDARD - -#define DEFINE_DBG_BUFFER char __dbg_str_buf[256]; - -#define DBG_PRINT( dbg_flags, args... ) \ - do { \ - if ( DEBUG_LEVEL & ( dbg_flags ) ) \ - { \ - int len; \ - len = sprintf( __dbg_str_buf, "%s:%d: %s: ", \ - __FILE__, __LINE__, __FUNCTION__ ); \ - sprintf( __dbg_str_buf + len, args ); \ - printk( KERN_NOTICE "%s\n", __dbg_str_buf ); \ - } \ - } while (0) - -#define DBG_ENTER_ROUTINE DBG_PRINT (DBG_K_TRACE_ENTRY, "%s", "[Entry]"); -#define DBG_LEAVE_ROUTINE DBG_PRINT (DBG_K_TRACE_EXIT, "%s", "[Exit]"); -#else -#define DEFINE_DBG_BUFFER -#define DBG_ENTER_ROUTINE -#define DBG_LEAVE_ROUTINE -#endif /* DEBUG */ - /* Slot Available Register I field definition */ #define SLOT_33MHZ 0x0000001f #define SLOT_66MHZ_PCIX 0x00001f00 @@ -211,7 +179,6 @@ #define DWORD_DATA 0x4 #define SLOT_EVENT_LATCH 0x2 #define SLOT_SERR_INT_MASK 0x3 -DEFINE_DBG_BUFFER /* Debug string buffer for entire HPC defined here */ static atomic_t shpchp_num_controllers = ATOMIC_INIT(0); static irqreturn_t shpc_isr(int irq, void *dev_id); @@ -268,8 +235,6 @@ static void int_poll_timeout(unsigned lo { struct controller *ctrl = (struct controller *)data; - DBG_ENTER_ROUTINE - /* Poll for interrupt events. regs == NULL => polling */ shpc_isr(0, ctrl); @@ -278,8 +243,6 @@ static void int_poll_timeout(unsigned lo shpchp_poll_time = 2; /* default polling interval is 2 sec */ start_int_poll_timer(ctrl, shpchp_poll_time); - - DBG_LEAVE_ROUTINE } /* @@ -353,8 +316,6 @@ static int shpc_write_cmd(struct slot *s int retval = 0; u16 temp_word; - DBG_ENTER_ROUTINE - mutex_lock(&slot->ctrl->cmd_lock); if (!shpc_poll_ctrl_busy(ctrl)) { @@ -368,9 +329,9 @@ static int shpc_write_cmd(struct slot *s ++t_slot; temp_word = (t_slot << 8) | (cmd & 0xFF); dbg("%s: t_slot %x cmd %x\n", __FUNCTION__, t_slot, cmd); - + /* To make sure the Controller Busy bit is 0 before we send out the - * command. + * command. */ shpc_writew(ctrl, CMD, temp_word); @@ -389,20 +350,14 @@ static int shpc_write_cmd(struct slot *s } out: mutex_unlock(&slot->ctrl->cmd_lock); - - DBG_LEAVE_ROUTINE return retval; } static int hpc_check_cmd_status(struct controller *ctrl) { - u16 cmd_status; int retval = 0; + u16 cmd_status = shpc_readw(ctrl, CMD_STATUS) & 0x000F; - DBG_ENTER_ROUTINE - - cmd_status = shpc_readw(ctrl, CMD_STATUS) & 0x000F; - switch (cmd_status >> 1) { case 0: retval = 0; @@ -423,7 +378,6 @@ static int hpc_check_cmd_status(struct c retval = cmd_status; } - DBG_LEAVE_ROUTINE return retval; } @@ -431,13 +385,8 @@ static int hpc_check_cmd_status(struct c static int hpc_get_attention_status(struct slot *slot, u8 *status) { struct controller *ctrl = slot->ctrl; - u32 slot_reg; - u8 state; - - DBG_ENTER_ROUTINE - - slot_reg = shpc_readl(ctrl, SLOT_REG(slot->hp_slot)); - state = (slot_reg & ATN_LED_STATE_MASK) >> ATN_LED_STATE_SHIFT; + u32 slot_reg = shpc_readl(ctrl, SLOT_REG(slot->hp_slot)); + u8 state = (slot_reg & ATN_LED_STATE_MASK) >> ATN_LED_STATE_SHIFT; switch (state) { case ATN_LED_STATE_ON: @@ -454,20 +403,14 @@ static int hpc_get_attention_status(stru break; } - DBG_LEAVE_ROUTINE return 0; } static int hpc_get_power_status(struct slot * slot, u8 *status) { struct controller *ctrl = slot->ctrl; - u32 slot_reg; - u8 state; - - DBG_ENTER_ROUTINE - - slot_reg = shpc_readl(ctrl, SLOT_REG(slot->hp_slot)); - state = (slot_reg & SLOT_STATE_MASK) >> SLOT_STATE_SHIFT; + u32 slot_reg = shpc_readl(ctrl, SLOT_REG(slot->hp_slot)); + u8 state = (slot_reg & SLOT_STATE_MASK) >> SLOT_STATE_SHIFT; switch (state) { case SLOT_STATE_PWRONLY: @@ -484,7 +427,6 @@ static int hpc_get_power_status(struct s break; } - DBG_LEAVE_ROUTINE return 0; } @@ -492,30 +434,21 @@ static int hpc_get_power_status(struct s static int hpc_get_latch_status(struct slot *slot, u8 *status) { struct controller *ctrl = slot->ctrl; - u32 slot_reg; - - DBG_ENTER_ROUTINE + u32 slot_reg = shpc_readl(ctrl, SLOT_REG(slot->hp_slot)); - slot_reg = shpc_readl(ctrl, SLOT_REG(slot->hp_slot)); *status = !!(slot_reg & MRL_SENSOR); /* 0 -> close; 1 -> open */ - DBG_LEAVE_ROUTINE return 0; } static int hpc_get_adapter_status(struct slot *slot, u8 *status) { struct controller *ctrl = slot->ctrl; - u32 slot_reg; - u8 state; - - DBG_ENTER_ROUTINE + u32 slot_reg = shpc_readl(ctrl, SLOT_REG(slot->hp_slot)); + u8 state = (slot_reg & PRSNT_MASK) >> PRSNT_SHIFT; - slot_reg = shpc_readl(ctrl, SLOT_REG(slot->hp_slot)); - state = (slot_reg & PRSNT_MASK) >> PRSNT_SHIFT; *status = (state != 0x3) ? 1 : 0; - DBG_LEAVE_ROUTINE return 0; } @@ -523,11 +456,8 @@ static int hpc_get_prog_int(struct slot { struct controller *ctrl = slot->ctrl; - DBG_ENTER_ROUTINE - *prog_int = shpc_readb(ctrl, PROG_INTERFACE); - DBG_LEAVE_ROUTINE return 0; } @@ -539,8 +469,6 @@ static int hpc_get_adapter_speed(struct u8 m66_cap = !!(slot_reg & MHZ66_CAP); u8 pi, pcix_cap; - DBG_ENTER_ROUTINE - if ((retval = hpc_get_prog_int(slot, &pi))) return retval; @@ -582,21 +510,15 @@ static int hpc_get_adapter_speed(struct } dbg("Adapter speed = %d\n", *value); - DBG_LEAVE_ROUTINE return retval; } static int hpc_get_mode1_ECC_cap(struct slot *slot, u8 *mode) { - struct controller *ctrl = slot->ctrl; - u16 sec_bus_status; - u8 pi; int retval = 0; - - DBG_ENTER_ROUTINE - - pi = shpc_readb(ctrl, PROG_INTERFACE); - sec_bus_status = shpc_readw(ctrl, SEC_BUS_CONFIG); + struct controller *ctrl = slot->ctrl; + u16 sec_bus_status = shpc_readw(ctrl, SEC_BUS_CONFIG); + u8 pi = shpc_readb(ctrl, PROG_INTERFACE); if (pi == 2) { *mode = (sec_bus_status & 0x0100) >> 8; @@ -605,21 +527,14 @@ static int hpc_get_mode1_ECC_cap(struct } dbg("Mode 1 ECC cap = %d\n", *mode); - - DBG_LEAVE_ROUTINE return retval; } static int hpc_query_power_fault(struct slot * slot) { struct controller *ctrl = slot->ctrl; - u32 slot_reg; - - DBG_ENTER_ROUTINE - - slot_reg = shpc_readl(ctrl, SLOT_REG(slot->hp_slot)); + u32 slot_reg = shpc_readl(ctrl, SLOT_REG(slot->hp_slot)); - DBG_LEAVE_ROUTINE /* Note: Logic 0 => fault */ return !(slot_reg & POWER_FAULT); } @@ -629,7 +544,7 @@ static int hpc_set_attention_status(stru u8 slot_cmd = 0; switch (value) { - case 0 : + case 0 : slot_cmd = SET_ATTN_OFF; /* OFF */ break; case 1: @@ -666,8 +581,6 @@ static void hpc_release_ctlr(struct cont int i; u32 slot_reg, serr_int; - DBG_ENTER_ROUTINE - /* * Mask event interrupts and SERRs of all slots */ @@ -708,61 +621,43 @@ static void hpc_release_ctlr(struct cont */ if (atomic_dec_and_test(&shpchp_num_controllers)) destroy_workqueue(shpchp_wq); - - DBG_LEAVE_ROUTINE } static int hpc_power_on_slot(struct slot * slot) { int retval; - DBG_ENTER_ROUTINE - retval = shpc_write_cmd(slot, slot->hp_slot, SET_SLOT_PWR); - if (retval) { + if (retval) err("%s: Write command failed!\n", __FUNCTION__); - return retval; - } - - DBG_LEAVE_ROUTINE - return 0; + return retval; } static int hpc_slot_enable(struct slot * slot) { int retval; - DBG_ENTER_ROUTINE - /* Slot - Enable, Power Indicator - Blink, Attention Indicator - Off */ retval = shpc_write_cmd(slot, slot->hp_slot, SET_SLOT_ENABLE | SET_PWR_BLINK | SET_ATTN_OFF); - if (retval) { + if (retval) err("%s: Write command failed!\n", __FUNCTION__); - return retval; - } - DBG_LEAVE_ROUTINE - return 0; + return retval; } static int hpc_slot_disable(struct slot * slot) { int retval; - DBG_ENTER_ROUTINE - /* Slot - Disable, Power Indicator - Off, Attention Indicator - On */ retval = shpc_write_cmd(slot, slot->hp_slot, SET_SLOT_DISABLE | SET_PWR_OFF | SET_ATTN_ON); - if (retval) { + if (retval) err("%s: Write command failed!\n", __FUNCTION__); - return retval; - } - DBG_LEAVE_ROUTINE - return 0; + return retval; } static int hpc_set_bus_speed_mode(struct slot * slot, enum pci_bus_speed value) @@ -771,8 +666,6 @@ static int hpc_set_bus_speed_mode(struct struct controller *ctrl = slot->ctrl; u8 pi, cmd; - DBG_ENTER_ROUTINE - pi = shpc_readb(ctrl, PROG_INTERFACE); if ((pi == 1) && (value > PCI_SPEED_133MHz_PCIX)) return -EINVAL; @@ -828,7 +721,6 @@ static int hpc_set_bus_speed_mode(struct if (retval) err("%s: Write command failed!\n", __FUNCTION__); - DBG_LEAVE_ROUTINE return retval; } @@ -843,7 +735,7 @@ static irqreturn_t shpc_isr(int irq, voi if (!intr_loc) return IRQ_NONE; - dbg("%s: intr_loc = %x\n",__FUNCTION__, intr_loc); + dbg("%s: intr_loc = %x\n",__FUNCTION__, intr_loc); if(!shpchp_poll_mode) { /* @@ -856,12 +748,12 @@ static irqreturn_t shpc_isr(int irq, voi shpc_writel(ctrl, SERR_INTR_ENABLE, serr_int); intr_loc2 = shpc_readl(ctrl, INTR_LOC); - dbg("%s: intr_loc2 = %x\n",__FUNCTION__, intr_loc2); + dbg("%s: intr_loc2 = %x\n",__FUNCTION__, intr_loc2); } if (intr_loc & CMD_INTR_PENDING) { - /* - * Command Complete Interrupt Pending + /* + * Command Complete Interrupt Pending * RO only - clear by writing 1 to the Command Completion * Detect bit in Controller SERR-INT register */ @@ -875,7 +767,7 @@ static irqreturn_t shpc_isr(int irq, voi if (!(intr_loc & ~CMD_INTR_PENDING)) goto out; - for (hp_slot = 0; hp_slot < ctrl->num_slots; hp_slot++) { + for (hp_slot = 0; hp_slot < ctrl->num_slots; hp_slot++) { /* To find out which slot has interrupt pending */ if (!(intr_loc & SLOT_INTR_PENDING(hp_slot))) continue; @@ -907,7 +799,7 @@ static irqreturn_t shpc_isr(int irq, voi serr_int &= ~(GLOBAL_INTR_MASK | SERR_INTR_RSVDZ_MASK); shpc_writel(ctrl, SERR_INTR_ENABLE, serr_int); } - + return IRQ_HANDLED; } @@ -920,8 +812,6 @@ static int hpc_get_max_bus_speed (struct u32 slot_avail1 = shpc_readl(ctrl, SLOT_AVAIL1); u32 slot_avail2 = shpc_readl(ctrl, SLOT_AVAIL2); - DBG_ENTER_ROUTINE - if (pi == 2) { if (slot_avail2 & SLOT_133MHZ_PCIX_533) bus_speed = PCI_SPEED_133MHz_PCIX_533; @@ -954,7 +844,7 @@ static int hpc_get_max_bus_speed (struct *value = bus_speed; dbg("Max bus speed = %d\n", bus_speed); - DBG_LEAVE_ROUTINE + return retval; } @@ -967,8 +857,6 @@ static int hpc_get_cur_bus_speed (struct u8 pi = shpc_readb(ctrl, PROG_INTERFACE); u8 speed_mode = (pi == 2) ? (sec_bus_reg & 0xF) : (sec_bus_reg & 0x7); - DBG_ENTER_ROUTINE - if ((pi == 1) && (speed_mode > 4)) { *value = PCI_SPEED_UNKNOWN; return -ENODEV; @@ -1024,7 +912,6 @@ static int hpc_get_cur_bus_speed (struct } dbg("Current bus speed = %d\n", bus_speed); - DBG_LEAVE_ROUTINE return retval; } @@ -1032,7 +919,7 @@ static struct hpc_ops shpchp_hpc_ops = { .power_on_slot = hpc_power_on_slot, .slot_enable = hpc_slot_enable, .slot_disable = hpc_slot_disable, - .set_bus_speed_mode = hpc_set_bus_speed_mode, + .set_bus_speed_mode = hpc_set_bus_speed_mode, .set_attention_status = hpc_set_attention_status, .get_power_status = hpc_get_power_status, .get_attention_status = hpc_get_attention_status, @@ -1049,7 +936,7 @@ static struct hpc_ops shpchp_hpc_ops = { .green_led_on = hpc_set_green_led_on, .green_led_off = hpc_set_green_led_off, .green_led_blink = hpc_set_green_led_blink, - + .release_ctlr = hpc_release_ctlr, }; @@ -1061,8 +948,6 @@ int shpc_init(struct controller *ctrl, s u32 tempdword, slot_reg, slot_config; u8 i; - DBG_ENTER_ROUTINE - ctrl->pci_dev = pdev; /* pci_dev of the P2P bridge */ if ((pdev->vendor == PCI_VENDOR_ID_AMD) || (pdev->device == @@ -1108,9 +993,9 @@ int shpc_init(struct controller *ctrl, s ctrl->mmio_size = 0x24 + 0x4 * num_slots; } - info("HPC vendor_id %x device_id %x ss_vid %x ss_did %x\n", pdev->vendor, pdev->device, pdev->subsystem_vendor, + info("HPC vendor_id %x device_id %x ss_vid %x ss_did %x\n", pdev->vendor, pdev->device, pdev->subsystem_vendor, pdev->subsystem_device); - + rc = pci_enable_device(pdev); if (rc) { err("%s: pci_enable_device failed\n", __FUNCTION__); @@ -1172,7 +1057,7 @@ int shpc_init(struct controller *ctrl, s slot_reg &= ~SLOT_REG_RSVDZ_MASK; shpc_writel(ctrl, SLOT_REG(hp_slot), slot_reg); } - + if (shpchp_poll_mode) { /* Install interrupt polling timer. Start with 10 sec delay */ init_timer(&ctrl->poll_timer); @@ -1184,7 +1069,7 @@ int shpc_init(struct controller *ctrl, s info("Can't get msi for the hotplug controller\n"); info("Use INTx for the hotplug controller\n"); } - + rc = request_irq(ctrl->pci_dev->irq, shpc_isr, IRQF_SHARED, MY_NAME, (void *)ctrl); dbg("%s: request_irq %d for hpc%d (returns %d)\n", @@ -1235,13 +1120,11 @@ int shpc_init(struct controller *ctrl, s dbg("%s: SERR_INTR_ENABLE = %x\n", __FUNCTION__, tempdword); } - DBG_LEAVE_ROUTINE return 0; /* We end up here for the many possible ways to fail this API. */ abort_iounmap: iounmap(ctrl->creg); abort: - DBG_LEAVE_ROUTINE return rc; } diff --git a/drivers/pci/msi.c b/drivers/pci/msi.c index ed3f7e1..68555c1 100644 --- a/drivers/pci/msi.c +++ b/drivers/pci/msi.c @@ -24,8 +24,6 @@ #include #include "pci.h" #include "msi.h" -static DEFINE_SPINLOCK(msi_lock); -static struct msi_desc* msi_desc[NR_IRQS] = { [0 ... NR_IRQS-1] = NULL }; static struct kmem_cache* msi_cachep; static int pci_msi_enable = 1; @@ -44,13 +42,13 @@ static void msi_set_mask_bit(unsigned in { struct msi_desc *entry; - entry = msi_desc[irq]; + entry = get_irq_msi(irq); BUG_ON(!entry || !entry->dev); switch (entry->msi_attrib.type) { case PCI_CAP_ID_MSI: if (entry->msi_attrib.maskbit) { - int pos; - u32 mask_bits; + int pos; + u32 mask_bits; pos = (long)entry->mask_base; pci_read_config_dword(entry->dev, pos, &mask_bits); @@ -74,7 +72,7 @@ static void msi_set_mask_bit(unsigned in void read_msi_msg(unsigned int irq, struct msi_msg *msg) { - struct msi_desc *entry = get_irq_data(irq); + struct msi_desc *entry = get_irq_msi(irq); switch(entry->msi_attrib.type) { case PCI_CAP_ID_MSI: { @@ -113,7 +111,7 @@ void read_msi_msg(unsigned int irq, stru void write_msi_msg(unsigned int irq, struct msi_msg *msg) { - struct msi_desc *entry = get_irq_data(irq); + struct msi_desc *entry = get_irq_msi(irq); switch (entry->msi_attrib.type) { case PCI_CAP_ID_MSI: { @@ -162,6 +160,7 @@ void unmask_msi_irq(unsigned int irq) } static int msi_free_irq(struct pci_dev* dev, int irq); + static int msi_init(void) { static int status = -ENOMEM; @@ -169,13 +168,6 @@ static int msi_init(void) if (!status) return status; - if (pci_msi_quirk) { - pci_msi_enable = 0; - printk(KERN_WARNING "PCI: MSI quirk detected. MSI disabled.\n"); - status = -EINVAL; - return status; - } - status = msi_cache_init(); if (status < 0) { pci_msi_enable = 0; @@ -200,46 +192,6 @@ static struct msi_desc* alloc_msi_entry( return entry; } -static void attach_msi_entry(struct msi_desc *entry, int irq) -{ - unsigned long flags; - - spin_lock_irqsave(&msi_lock, flags); - msi_desc[irq] = entry; - spin_unlock_irqrestore(&msi_lock, flags); -} - -static int create_msi_irq(void) -{ - struct msi_desc *entry; - int irq; - - entry = alloc_msi_entry(); - if (!entry) - return -ENOMEM; - - irq = create_irq(); - if (irq < 0) { - kmem_cache_free(msi_cachep, entry); - return -EBUSY; - } - - set_irq_data(irq, entry); - - return irq; -} - -static void destroy_msi_irq(unsigned int irq) -{ - struct msi_desc *entry; - - entry = get_irq_data(irq); - set_irq_chip(irq, NULL); - set_irq_data(irq, NULL); - destroy_irq(irq); - kmem_cache_free(msi_cachep, entry); -} - static void enable_msi_mode(struct pci_dev *dev, int pos, int type) { u16 control; @@ -278,36 +230,8 @@ void disable_msi_mode(struct pci_dev *de pci_intx(dev, 1); /* enable intx */ } -static int msi_lookup_irq(struct pci_dev *dev, int type) -{ - int irq; - unsigned long flags; - - spin_lock_irqsave(&msi_lock, flags); - for (irq = 0; irq < NR_IRQS; irq++) { - if (!msi_desc[irq] || msi_desc[irq]->dev != dev || - msi_desc[irq]->msi_attrib.type != type || - msi_desc[irq]->msi_attrib.default_irq != dev->irq) - continue; - spin_unlock_irqrestore(&msi_lock, flags); - /* This pre-assigned MSI irq for this device - already exits. Override dev->irq with this irq */ - dev->irq = irq; - return 0; - } - spin_unlock_irqrestore(&msi_lock, flags); - - return -EACCES; -} - -void pci_scan_msi_device(struct pci_dev *dev) -{ - if (!dev) - return; -} - #ifdef CONFIG_PM -int pci_save_msi_state(struct pci_dev *dev) +static int __pci_save_msi_state(struct pci_dev *dev) { int pos, i = 0; u16 control; @@ -345,7 +269,7 @@ int pci_save_msi_state(struct pci_dev *d return 0; } -void pci_restore_msi_state(struct pci_dev *dev) +static void __pci_restore_msi_state(struct pci_dev *dev) { int i = 0, pos; u16 control; @@ -373,14 +297,16 @@ void pci_restore_msi_state(struct pci_de kfree(save_state); } -int pci_save_msix_state(struct pci_dev *dev) +static int __pci_save_msix_state(struct pci_dev *dev) { int pos; - int temp; int irq, head, tail = 0; u16 control; struct pci_cap_saved_state *save_state; + if (!dev->msix_enabled) + return 0; + pos = pci_find_capability(dev, PCI_CAP_ID_MSIX); if (pos <= 0 || dev->no_msi) return 0; @@ -398,38 +324,46 @@ int pci_save_msix_state(struct pci_dev * *((u16 *)&save_state->data[0]) = control; /* save the table */ - temp = dev->irq; - if (msi_lookup_irq(dev, PCI_CAP_ID_MSIX)) { - kfree(save_state); - return -EINVAL; - } - - irq = head = dev->irq; + irq = head = dev->first_msi_irq; while (head != tail) { struct msi_desc *entry; - entry = msi_desc[irq]; + entry = get_irq_msi(irq); read_msi_msg(irq, &entry->msg_save); - tail = msi_desc[irq]->link.tail; + tail = entry->link.tail; irq = tail; } - dev->irq = temp; save_state->cap_nr = PCI_CAP_ID_MSIX; pci_add_saved_cap(dev, save_state); return 0; } -void pci_restore_msix_state(struct pci_dev *dev) +int pci_save_msi_state(struct pci_dev *dev) +{ + int rc; + + rc = __pci_save_msi_state(dev); + if (rc) + return rc; + + rc = __pci_save_msix_state(dev); + + return rc; +} + +static void __pci_restore_msix_state(struct pci_dev *dev) { u16 save; int pos; int irq, head, tail = 0; struct msi_desc *entry; - int temp; struct pci_cap_saved_state *save_state; + if (!dev->msix_enabled) + return; + save_state = pci_find_saved_cap(dev, PCI_CAP_ID_MSIX); if (!save_state) return; @@ -442,23 +376,25 @@ void pci_restore_msix_state(struct pci_d return; /* route the table */ - temp = dev->irq; - if (msi_lookup_irq(dev, PCI_CAP_ID_MSIX)) - return; - irq = head = dev->irq; + irq = head = dev->first_msi_irq; while (head != tail) { - entry = msi_desc[irq]; + entry = get_irq_msi(irq); write_msi_msg(irq, &entry->msg_save); - tail = msi_desc[irq]->link.tail; + tail = entry->link.tail; irq = tail; } - dev->irq = temp; pci_write_config_word(dev, msi_control_reg(pos), save); enable_msi_mode(dev, pos, PCI_CAP_ID_MSIX); } -#endif + +void pci_restore_msi_state(struct pci_dev *dev) +{ + __pci_restore_msi_state(dev); + __pci_restore_msix_state(dev); +} +#endif /* CONFIG_PM */ /** * msi_capability_init - configure device's MSI capability structure @@ -471,7 +407,6 @@ #endif **/ static int msi_capability_init(struct pci_dev *dev) { - int status; struct msi_desc *entry; int pos, irq; u16 control; @@ -479,13 +414,10 @@ static int msi_capability_init(struct pc pos = pci_find_capability(dev, PCI_CAP_ID_MSI); pci_read_config_word(dev, msi_control_reg(pos), &control); /* MSI Entry Initialization */ - irq = create_msi_irq(); - if (irq < 0) - return irq; + entry = alloc_msi_entry(); + if (!entry) + return -ENOMEM; - entry = get_irq_data(irq); - entry->link.head = irq; - entry->link.tail = irq; entry->msi_attrib.type = PCI_CAP_ID_MSI; entry->msi_attrib.is_64 = is_64bit_address(control); entry->msi_attrib.entry_nr = 0; @@ -511,13 +443,16 @@ static int msi_capability_init(struct pc maskbits); } /* Configure MSI capability structure */ - status = arch_setup_msi_irq(irq, dev); - if (status < 0) { - destroy_msi_irq(irq); - return status; + irq = arch_setup_msi_irq(dev, entry); + if (irq < 0) { + kmem_cache_free(msi_cachep, entry); + return irq; } + entry->link.head = irq; + entry->link.tail = irq; + dev->first_msi_irq = irq; + set_irq_msi(irq, entry); - attach_msi_entry(entry, irq); /* Set MSI enabled bits */ enable_msi_mode(dev, pos, PCI_CAP_ID_MSI); @@ -539,7 +474,6 @@ static int msix_capability_init(struct p struct msix_entry *entries, int nvec) { struct msi_desc *head = NULL, *tail = NULL, *entry = NULL; - int status; int irq, pos, i, j, nr_entries, temp = 0; unsigned long phys_addr; u32 table_offset; @@ -562,13 +496,11 @@ static int msix_capability_init(struct p /* MSI-X Table Initialization */ for (i = 0; i < nvec; i++) { - irq = create_msi_irq(); - if (irq < 0) + entry = alloc_msi_entry(); + if (!entry) break; - entry = get_irq_data(irq); j = entries[i].entry; - entries[i].vector = irq; entry->msi_attrib.type = PCI_CAP_ID_MSIX; entry->msi_attrib.is_64 = 1; entry->msi_attrib.entry_nr = j; @@ -577,6 +509,14 @@ static int msix_capability_init(struct p entry->msi_attrib.pos = pos; entry->dev = dev; entry->mask_base = base; + + /* Configure MSI-X capability structure */ + irq = arch_setup_msi_irq(dev, entry); + if (irq < 0) { + kmem_cache_free(msi_cachep, entry); + break; + } + entries[i].vector = irq; if (!head) { entry->link.head = irq; entry->link.tail = irq; @@ -589,14 +529,8 @@ static int msix_capability_init(struct p } temp = irq; tail = entry; - /* Configure MSI-X capability structure */ - status = arch_setup_msi_irq(irq, dev); - if (status < 0) { - destroy_msi_irq(irq); - break; - } - attach_msi_entry(entry, irq); + set_irq_msi(irq, entry); } if (i != nvec) { int avail = i - 1; @@ -613,6 +547,7 @@ static int msix_capability_init(struct p avail = -EBUSY; return avail; } + dev->first_msi_irq = entries[0].vector; /* Set MSI-X enabled bits */ enable_msi_mode(dev, pos, PCI_CAP_ID_MSIX); @@ -660,13 +595,11 @@ int pci_msi_supported(struct pci_dev * d **/ int pci_enable_msi(struct pci_dev* dev) { - int pos, temp, status; + int pos, status; if (pci_msi_supported(dev) < 0) return -EINVAL; - temp = dev->irq; - status = msi_init(); if (status < 0) return status; @@ -675,15 +608,14 @@ int pci_enable_msi(struct pci_dev* dev) if (!pos) return -EINVAL; - WARN_ON(!msi_lookup_irq(dev, PCI_CAP_ID_MSI)); + WARN_ON(!!dev->msi_enabled); /* Check whether driver already requested for MSI-X irqs */ pos = pci_find_capability(dev, PCI_CAP_ID_MSIX); - if (pos > 0 && !msi_lookup_irq(dev, PCI_CAP_ID_MSIX)) { + if (pos > 0 && dev->msix_enabled) { printk(KERN_INFO "PCI: %s: Can't enable MSI. " - "Device already has MSI-X irq assigned\n", + "Device already has MSI-X enabled\n", pci_name(dev)); - dev->irq = temp; return -EINVAL; } status = msi_capability_init(dev); @@ -695,13 +627,15 @@ void pci_disable_msi(struct pci_dev* dev struct msi_desc *entry; int pos, default_irq; u16 control; - unsigned long flags; if (!pci_msi_enable) return; if (!dev) return; + if (!dev->msi_enabled) + return; + pos = pci_find_capability(dev, PCI_CAP_ID_MSI); if (!pos) return; @@ -710,28 +644,26 @@ void pci_disable_msi(struct pci_dev* dev if (!(control & PCI_MSI_FLAGS_ENABLE)) return; + disable_msi_mode(dev, pos, PCI_CAP_ID_MSI); - spin_lock_irqsave(&msi_lock, flags); - entry = msi_desc[dev->irq]; + entry = get_irq_msi(dev->first_msi_irq); if (!entry || !entry->dev || entry->msi_attrib.type != PCI_CAP_ID_MSI) { - spin_unlock_irqrestore(&msi_lock, flags); return; } - if (irq_has_action(dev->irq)) { - spin_unlock_irqrestore(&msi_lock, flags); + if (irq_has_action(dev->first_msi_irq)) { printk(KERN_WARNING "PCI: %s: pci_disable_msi() called without " "free_irq() on MSI irq %d\n", - pci_name(dev), dev->irq); - BUG_ON(irq_has_action(dev->irq)); + pci_name(dev), dev->first_msi_irq); + BUG_ON(irq_has_action(dev->first_msi_irq)); } else { default_irq = entry->msi_attrib.default_irq; - spin_unlock_irqrestore(&msi_lock, flags); - msi_free_irq(dev, dev->irq); + msi_free_irq(dev, dev->first_msi_irq); /* Restore dev->irq to its default pin-assertion irq */ dev->irq = default_irq; } + dev->first_msi_irq = 0; } static int msi_free_irq(struct pci_dev* dev, int irq) @@ -739,27 +671,20 @@ static int msi_free_irq(struct pci_dev* struct msi_desc *entry; int head, entry_nr, type; void __iomem *base; - unsigned long flags; - arch_teardown_msi_irq(irq); - - spin_lock_irqsave(&msi_lock, flags); - entry = msi_desc[irq]; + entry = get_irq_msi(irq); if (!entry || entry->dev != dev) { - spin_unlock_irqrestore(&msi_lock, flags); return -EINVAL; } type = entry->msi_attrib.type; entry_nr = entry->msi_attrib.entry_nr; head = entry->link.head; base = entry->mask_base; - msi_desc[entry->link.head]->link.tail = entry->link.tail; - msi_desc[entry->link.tail]->link.head = entry->link.head; - entry->dev = NULL; - msi_desc[irq] = NULL; - spin_unlock_irqrestore(&msi_lock, flags); + get_irq_msi(entry->link.head)->link.tail = entry->link.tail; + get_irq_msi(entry->link.tail)->link.head = entry->link.head; - destroy_msi_irq(irq); + arch_teardown_msi_irq(irq); + kmem_cache_free(msi_cachep, entry); if (type == PCI_CAP_ID_MSIX) { writel(1, base + entry_nr * PCI_MSIX_ENTRY_SIZE + @@ -790,7 +715,7 @@ static int msi_free_irq(struct pci_dev* int pci_enable_msix(struct pci_dev* dev, struct msix_entry *entries, int nvec) { int status, pos, nr_entries; - int i, j, temp; + int i, j; u16 control; if (!entries || pci_msi_supported(dev) < 0) @@ -818,16 +743,14 @@ int pci_enable_msix(struct pci_dev* dev, return -EINVAL; /* duplicate entry */ } } - temp = dev->irq; - WARN_ON(!msi_lookup_irq(dev, PCI_CAP_ID_MSIX)); + WARN_ON(!!dev->msix_enabled); /* Check whether driver already requested for MSI irq */ if (pci_find_capability(dev, PCI_CAP_ID_MSI) > 0 && - !msi_lookup_irq(dev, PCI_CAP_ID_MSI)) { + dev->msi_enabled) { printk(KERN_INFO "PCI: %s: Can't enable MSI-X. " "Device already has an MSI irq assigned\n", pci_name(dev)); - dev->irq = temp; return -EINVAL; } status = msix_capability_init(dev, entries, nvec); @@ -836,7 +759,8 @@ int pci_enable_msix(struct pci_dev* dev, void pci_disable_msix(struct pci_dev* dev) { - int pos, temp; + int irq, head, tail = 0, warning = 0; + int pos; u16 control; if (!pci_msi_enable) @@ -844,6 +768,9 @@ void pci_disable_msix(struct pci_dev* de if (!dev) return; + if (!dev->msix_enabled) + return; + pos = pci_find_capability(dev, PCI_CAP_ID_MSIX); if (!pos) return; @@ -854,31 +781,23 @@ void pci_disable_msix(struct pci_dev* de disable_msi_mode(dev, pos, PCI_CAP_ID_MSIX); - temp = dev->irq; - if (!msi_lookup_irq(dev, PCI_CAP_ID_MSIX)) { - int irq, head, tail = 0, warning = 0; - unsigned long flags; - - irq = head = dev->irq; - dev->irq = temp; /* Restore pin IRQ */ - while (head != tail) { - spin_lock_irqsave(&msi_lock, flags); - tail = msi_desc[irq]->link.tail; - spin_unlock_irqrestore(&msi_lock, flags); - if (irq_has_action(irq)) - warning = 1; - else if (irq != head) /* Release MSI-X irq */ - msi_free_irq(dev, irq); - irq = tail; - } - msi_free_irq(dev, irq); - if (warning) { - printk(KERN_WARNING "PCI: %s: pci_disable_msix() called without " - "free_irq() on all MSI-X irqs\n", - pci_name(dev)); - BUG_ON(warning > 0); - } + irq = head = dev->first_msi_irq; + while (head != tail) { + tail = get_irq_msi(irq)->link.tail; + if (irq_has_action(irq)) + warning = 1; + else if (irq != head) /* Release MSI-X irq */ + msi_free_irq(dev, irq); + irq = tail; + } + msi_free_irq(dev, irq); + if (warning) { + printk(KERN_WARNING "PCI: %s: pci_disable_msix() called without " + "free_irq() on all MSI-X irqs\n", + pci_name(dev)); + BUG_ON(warning > 0); } + dev->first_msi_irq = 0; } /** @@ -892,35 +811,26 @@ void pci_disable_msix(struct pci_dev* de **/ void msi_remove_pci_irq_vectors(struct pci_dev* dev) { - int pos, temp; - unsigned long flags; - if (!pci_msi_enable || !dev) return; - temp = dev->irq; /* Save IOAPIC IRQ */ - pos = pci_find_capability(dev, PCI_CAP_ID_MSI); - if (pos > 0 && !msi_lookup_irq(dev, PCI_CAP_ID_MSI)) { - if (irq_has_action(dev->irq)) { + if (dev->msi_enabled) { + if (irq_has_action(dev->first_msi_irq)) { printk(KERN_WARNING "PCI: %s: msi_remove_pci_irq_vectors() " "called without free_irq() on MSI irq %d\n", - pci_name(dev), dev->irq); - BUG_ON(irq_has_action(dev->irq)); + pci_name(dev), dev->first_msi_irq); + BUG_ON(irq_has_action(dev->first_msi_irq)); } else /* Release MSI irq assigned to this device */ - msi_free_irq(dev, dev->irq); - dev->irq = temp; /* Restore IOAPIC IRQ */ + msi_free_irq(dev, dev->first_msi_irq); } - pos = pci_find_capability(dev, PCI_CAP_ID_MSIX); - if (pos > 0 && !msi_lookup_irq(dev, PCI_CAP_ID_MSIX)) { + if (dev->msix_enabled) { int irq, head, tail = 0, warning = 0; void __iomem *base = NULL; - irq = head = dev->irq; + irq = head = dev->first_msi_irq; while (head != tail) { - spin_lock_irqsave(&msi_lock, flags); - tail = msi_desc[irq]->link.tail; - base = msi_desc[irq]->mask_base; - spin_unlock_irqrestore(&msi_lock, flags); + tail = get_irq_msi(irq)->link.tail; + base = get_irq_msi(irq)->mask_base; if (irq_has_action(irq)) warning = 1; else if (irq != head) /* Release MSI-X irq */ @@ -935,7 +845,6 @@ void msi_remove_pci_irq_vectors(struct p pci_name(dev)); BUG_ON(warning > 0); } - dev->irq = temp; /* Restore IOAPIC IRQ */ } } diff --git a/drivers/pci/pci-driver.c b/drivers/pci/pci-driver.c index 92d5e8d..4438ae1 100644 --- a/drivers/pci/pci-driver.c +++ b/drivers/pci/pci-driver.c @@ -324,8 +324,7 @@ static int pci_default_resume(struct pci /* restore the PCI config space */ pci_restore_state(pci_dev); /* if the device was enabled before suspend, reenable */ - if (atomic_read(&pci_dev->enable_cnt)) - retval = __pci_enable_device(pci_dev); + retval = __pci_reenable_device(pci_dev); /* if the device was busmaster before the suspend, make it busmaster again */ if (pci_dev->is_busmaster) pci_set_master(pci_dev); @@ -422,7 +421,8 @@ static struct kobj_type pci_driver_kobj_ * If no error occurred, the driver remains registered even if * no device was claimed during registration. */ -int __pci_register_driver(struct pci_driver *drv, struct module *owner) +int __pci_register_driver(struct pci_driver *drv, struct module *owner, + const char *mod_name) { int error; @@ -430,6 +430,7 @@ int __pci_register_driver(struct pci_dri drv->driver.name = drv->name; drv->driver.bus = &pci_bus_type; drv->driver.owner = owner; + drv->driver.mod_name = mod_name; drv->driver.kobj.ktype = &pci_driver_kobj_type; if (pci_multithread_probe) diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c index 206c834..8b44cff 100644 --- a/drivers/pci/pci.c +++ b/drivers/pci/pci.c @@ -392,6 +392,14 @@ pci_set_power_state(struct pci_dev *dev, if (state > PCI_D3hot) state = PCI_D3hot; + /* + * If the device or the parent bridge can't support PCI PM, ignore + * the request if we're doing anything besides putting it into D0 + * (which would only happen on boot). + */ + if ((state == PCI_D1 || state == PCI_D2) && pci_no_d1d2(dev)) + return 0; + /* Validate current state: * Can enter D0 from any state, but if we can only go deeper * to sleep if we're already in a low power state @@ -403,13 +411,6 @@ pci_set_power_state(struct pci_dev *dev, } else if (dev->current_state == state) return 0; /* we're already there */ - /* - * If the device or the parent bridge can't support PCI PM, ignore - * the request if we're doing anything besides putting it into D0 - * (which would only happen on boot). - */ - if ((state == PCI_D1 || state == PCI_D2) && pci_no_d1d2(dev)) - return 0; /* find PCI PM capability in list */ pm = pci_find_capability(dev, PCI_CAP_ID_PM); @@ -633,8 +634,6 @@ pci_save_state(struct pci_dev *dev) pci_read_config_dword(dev, i * 4,&dev->saved_config_space[i]); if ((i = pci_save_msi_state(dev)) != 0) return i; - if ((i = pci_save_msix_state(dev)) != 0) - return i; if ((i = pci_save_pcie_state(dev)) != 0) return i; if ((i = pci_save_pcix_state(dev)) != 0) @@ -672,22 +671,11 @@ pci_restore_state(struct pci_dev *dev) } pci_restore_pcix_state(dev); pci_restore_msi_state(dev); - pci_restore_msix_state(dev); + return 0; } -/** - * pci_enable_device_bars - Initialize some of a device for use - * @dev: PCI device to be initialized - * @bars: bitmask of BAR's that must be configured - * - * Initialize device before it's used by a driver. Ask low-level code - * to enable selected I/O and memory resources. Wake up the device if it - * was suspended. Beware, this function can fail. - */ - -int -pci_enable_device_bars(struct pci_dev *dev, int bars) +static int do_pci_enable_device(struct pci_dev *dev, int bars) { int err; @@ -697,30 +685,47 @@ pci_enable_device_bars(struct pci_dev *d err = pcibios_enable_device(dev, bars); if (err < 0) return err; + pci_fixup_device(pci_fixup_enable, dev); + + return 0; +} + +/** + * __pci_reenable_device - Resume abandoned device + * @dev: PCI device to be resumed + * + * Note this function is a backend of pci_default_resume and is not supposed + * to be called by normal code, write proper resume handler and use it instead. + */ +int +__pci_reenable_device(struct pci_dev *dev) +{ + if (atomic_read(&dev->enable_cnt)) + return do_pci_enable_device(dev, (1 << PCI_NUM_RESOURCES) - 1); return 0; } /** - * __pci_enable_device - Initialize device before it's used by a driver. + * pci_enable_device_bars - Initialize some of a device for use * @dev: PCI device to be initialized + * @bars: bitmask of BAR's that must be configured * * Initialize device before it's used by a driver. Ask low-level code - * to enable I/O and memory. Wake up the device if it was suspended. - * Beware, this function can fail. - * - * Note this function is a backend and is not supposed to be called by - * normal code, use pci_enable_device() instead. + * to enable selected I/O and memory resources. Wake up the device if it + * was suspended. Beware, this function can fail. */ int -__pci_enable_device(struct pci_dev *dev) +pci_enable_device_bars(struct pci_dev *dev, int bars) { int err; - err = pci_enable_device_bars(dev, (1 << PCI_NUM_RESOURCES) - 1); - if (err) - return err; - pci_fixup_device(pci_fixup_enable, dev); - return 0; + if (atomic_add_return(1, &dev->enable_cnt) > 1) + return 0; /* already enabled */ + + err = do_pci_enable_device(dev, bars); + if (err < 0) + atomic_dec(&dev->enable_cnt); + return err; } /** @@ -736,13 +741,105 @@ __pci_enable_device(struct pci_dev *dev) */ int pci_enable_device(struct pci_dev *dev) { - int result; - if (atomic_add_return(1, &dev->enable_cnt) > 1) - return 0; /* already enabled */ - result = __pci_enable_device(dev); - if (result < 0) - atomic_dec(&dev->enable_cnt); - return result; + return pci_enable_device_bars(dev, (1 << PCI_NUM_RESOURCES) - 1); +} + +/* + * Managed PCI resources. This manages device on/off, intx/msi/msix + * on/off and BAR regions. pci_dev itself records msi/msix status, so + * there's no need to track it separately. pci_devres is initialized + * when a device is enabled using managed PCI device enable interface. + */ +struct pci_devres { + unsigned int disable:1; + unsigned int orig_intx:1; + unsigned int restore_intx:1; + u32 region_mask; +}; + +static void pcim_release(struct device *gendev, void *res) +{ + struct pci_dev *dev = container_of(gendev, struct pci_dev, dev); + struct pci_devres *this = res; + int i; + + if (dev->msi_enabled) + pci_disable_msi(dev); + if (dev->msix_enabled) + pci_disable_msix(dev); + + for (i = 0; i < DEVICE_COUNT_RESOURCE; i++) + if (this->region_mask & (1 << i)) + pci_release_region(dev, i); + + if (this->restore_intx) + pci_intx(dev, this->orig_intx); + + if (this->disable) + pci_disable_device(dev); +} + +static struct pci_devres * get_pci_dr(struct pci_dev *pdev) +{ + struct pci_devres *dr, *new_dr; + + dr = devres_find(&pdev->dev, pcim_release, NULL, NULL); + if (dr) + return dr; + + new_dr = devres_alloc(pcim_release, sizeof(*new_dr), GFP_KERNEL); + if (!new_dr) + return NULL; + return devres_get(&pdev->dev, new_dr, NULL, NULL); +} + +static struct pci_devres * find_pci_dr(struct pci_dev *pdev) +{ + if (pci_is_managed(pdev)) + return devres_find(&pdev->dev, pcim_release, NULL, NULL); + return NULL; +} + +/** + * pcim_enable_device - Managed pci_enable_device() + * @pdev: PCI device to be initialized + * + * Managed pci_enable_device(). + */ +int pcim_enable_device(struct pci_dev *pdev) +{ + struct pci_devres *dr; + int rc; + + dr = get_pci_dr(pdev); + if (unlikely(!dr)) + return -ENOMEM; + WARN_ON(!!dr->disable); + + rc = pci_enable_device(pdev); + if (!rc) { + pdev->is_managed = 1; + dr->disable = 1; + } + return rc; +} + +/** + * pcim_pin_device - Pin managed PCI device + * @pdev: PCI device to pin + * + * Pin managed PCI device @pdev. Pinned device won't be disabled on + * driver detach. @pdev must have been enabled with + * pcim_enable_device(). + */ +void pcim_pin_device(struct pci_dev *pdev) +{ + struct pci_devres *dr; + + dr = find_pci_dr(pdev); + WARN_ON(!dr || !dr->disable); + if (dr) + dr->disable = 0; } /** @@ -768,8 +865,13 @@ void __attribute__ ((weak)) pcibios_disa void pci_disable_device(struct pci_dev *dev) { + struct pci_devres *dr; u16 pci_command; + dr = find_pci_dr(dev); + if (dr) + dr->disable = 0; + if (atomic_sub_return(1, &dev->enable_cnt) != 0) return; @@ -868,6 +970,8 @@ pci_get_interrupt_pin(struct pci_dev *de */ void pci_release_region(struct pci_dev *pdev, int bar) { + struct pci_devres *dr; + if (pci_resource_len(pdev, bar) == 0) return; if (pci_resource_flags(pdev, bar) & IORESOURCE_IO) @@ -876,6 +980,10 @@ void pci_release_region(struct pci_dev * else if (pci_resource_flags(pdev, bar) & IORESOURCE_MEM) release_mem_region(pci_resource_start(pdev, bar), pci_resource_len(pdev, bar)); + + dr = find_pci_dr(pdev); + if (dr) + dr->region_mask &= ~(1 << bar); } /** @@ -894,6 +1002,8 @@ void pci_release_region(struct pci_dev * */ int pci_request_region(struct pci_dev *pdev, int bar, const char *res_name) { + struct pci_devres *dr; + if (pci_resource_len(pdev, bar) == 0) return 0; @@ -907,7 +1017,11 @@ int pci_request_region(struct pci_dev *p pci_resource_len(pdev, bar), res_name)) goto err_out; } - + + dr = find_pci_dr(pdev); + if (dr) + dr->region_mask |= 1 << bar; + return 0; err_out: @@ -921,6 +1035,47 @@ err_out: return -EBUSY; } +/** + * pci_release_selected_regions - Release selected PCI I/O and memory resources + * @pdev: PCI device whose resources were previously reserved + * @bars: Bitmask of BARs to be released + * + * Release selected PCI I/O and memory resources previously reserved. + * Call this function only after all use of the PCI regions has ceased. + */ +void pci_release_selected_regions(struct pci_dev *pdev, int bars) +{ + int i; + + for (i = 0; i < 6; i++) + if (bars & (1 << i)) + pci_release_region(pdev, i); +} + +/** + * pci_request_selected_regions - Reserve selected PCI I/O and memory resources + * @pdev: PCI device whose resources are to be reserved + * @bars: Bitmask of BARs to be requested + * @res_name: Name to be associated with resource + */ +int pci_request_selected_regions(struct pci_dev *pdev, int bars, + const char *res_name) +{ + int i; + + for (i = 0; i < 6; i++) + if (bars & (1 << i)) + if(pci_request_region(pdev, i, res_name)) + goto err_out; + return 0; + +err_out: + while(--i >= 0) + if (bars & (1 << i)) + pci_release_region(pdev, i); + + return -EBUSY; +} /** * pci_release_regions - Release reserved PCI I/O and memory resources @@ -933,10 +1088,7 @@ err_out: void pci_release_regions(struct pci_dev *pdev) { - int i; - - for (i = 0; i < 6; i++) - pci_release_region(pdev, i); + pci_release_selected_regions(pdev, (1 << 6) - 1); } /** @@ -954,18 +1106,7 @@ void pci_release_regions(struct pci_dev */ int pci_request_regions(struct pci_dev *pdev, const char *res_name) { - int i; - - for (i = 0; i < 6; i++) - if(pci_request_region(pdev, i, res_name)) - goto err_out; - return 0; - -err_out: - while(--i >= 0) - pci_release_region(pdev, i); - - return -EBUSY; + return pci_request_selected_regions(pdev, ((1 << 6) - 1), res_name); } /** @@ -1118,7 +1259,15 @@ pci_intx(struct pci_dev *pdev, int enabl } if (new != pci_command) { + struct pci_devres *dr; + pci_write_config_word(pdev, PCI_COMMAND, new); + + dr = find_pci_dr(pdev); + if (dr && !dr->restore_intx) { + dr->restore_intx = 1; + dr->orig_intx = !enable; + } } } @@ -1148,7 +1297,23 @@ pci_set_consistent_dma_mask(struct pci_d return 0; } #endif - + +/** + * pci_select_bars - Make BAR mask from the type of resource + * @pdev: the PCI device for which BAR mask is made + * @flags: resource type mask to be selected + * + * This helper routine makes bar mask from the type of resource. + */ +int pci_select_bars(struct pci_dev *dev, unsigned long flags) +{ + int i, bars = 0; + for (i = 0; i < PCI_NUM_RESOURCES; i++) + if (pci_resource_flags(dev, i) & flags) + bars |= (1 << i); + return bars; +} + static int __devinit pci_init(void) { struct pci_dev *dev = NULL; @@ -1181,15 +1346,11 @@ early_param("pci", pci_setup); device_initcall(pci_init); -#if defined(CONFIG_ISA) || defined(CONFIG_EISA) -/* FIXME: Some boxes have multiple ISA bridges! */ -struct pci_dev *isa_bridge; -EXPORT_SYMBOL(isa_bridge); -#endif - EXPORT_SYMBOL_GPL(pci_restore_bars); EXPORT_SYMBOL(pci_enable_device_bars); EXPORT_SYMBOL(pci_enable_device); +EXPORT_SYMBOL(pcim_enable_device); +EXPORT_SYMBOL(pcim_pin_device); EXPORT_SYMBOL(pci_disable_device); EXPORT_SYMBOL(pci_find_capability); EXPORT_SYMBOL(pci_bus_find_capability); @@ -1197,6 +1358,8 @@ EXPORT_SYMBOL(pci_release_regions); EXPORT_SYMBOL(pci_request_regions); EXPORT_SYMBOL(pci_release_region); EXPORT_SYMBOL(pci_request_region); +EXPORT_SYMBOL(pci_release_selected_regions); +EXPORT_SYMBOL(pci_request_selected_regions); EXPORT_SYMBOL(pci_set_master); EXPORT_SYMBOL(pci_set_mwi); EXPORT_SYMBOL(pci_clear_mwi); @@ -1205,13 +1368,10 @@ EXPORT_SYMBOL(pci_set_dma_mask); EXPORT_SYMBOL(pci_set_consistent_dma_mask); EXPORT_SYMBOL(pci_assign_resource); EXPORT_SYMBOL(pci_find_parent_resource); +EXPORT_SYMBOL(pci_select_bars); EXPORT_SYMBOL(pci_set_power_state); EXPORT_SYMBOL(pci_save_state); EXPORT_SYMBOL(pci_restore_state); EXPORT_SYMBOL(pci_enable_wake); -/* Quirk info */ - -EXPORT_SYMBOL(isa_dma_bridge_buggy); -EXPORT_SYMBOL(pci_pci_problems); diff --git a/drivers/pci/pci.h b/drivers/pci/pci.h index 398852f..a4f2d58 100644 --- a/drivers/pci/pci.h +++ b/drivers/pci/pci.h @@ -1,6 +1,6 @@ /* Functions internal to the PCI core code */ -extern int __must_check __pci_enable_device(struct pci_dev *); +extern int __must_check __pci_reenable_device(struct pci_dev *); extern int pci_uevent(struct device *dev, char **envp, int num_envp, char *buffer, int buffer_size); extern int pci_create_sysfs_dev_files(struct pci_dev *pdev); @@ -43,12 +43,8 @@ extern void pci_remove_legacy_files(stru /* Lock for read/write access to pci device and bus lists */ extern struct rw_semaphore pci_bus_sem; -#ifdef CONFIG_PCI_MSI -extern int pci_msi_quirk; -#else -#define pci_msi_quirk 0 -#endif extern unsigned int pci_pm_d3_delay; + #ifdef CONFIG_PCI_MSI void disable_msi_mode(struct pci_dev *dev, int pos, int type); void pci_no_msi(void); @@ -56,17 +52,15 @@ #else static inline void disable_msi_mode(struct pci_dev *dev, int pos, int type) { } static inline void pci_no_msi(void) { } #endif + #if defined(CONFIG_PCI_MSI) && defined(CONFIG_PM) int pci_save_msi_state(struct pci_dev *dev); -int pci_save_msix_state(struct pci_dev *dev); void pci_restore_msi_state(struct pci_dev *dev); -void pci_restore_msix_state(struct pci_dev *dev); #else static inline int pci_save_msi_state(struct pci_dev *dev) { return 0; } -static inline int pci_save_msix_state(struct pci_dev *dev) { return 0; } static inline void pci_restore_msi_state(struct pci_dev *dev) {} -static inline void pci_restore_msix_state(struct pci_dev *dev) {} #endif + static inline int pci_no_d1d2(struct pci_dev *dev) { unsigned int parent_dstates = 0; diff --git a/drivers/pci/pcie/aer/aerdrv.c b/drivers/pci/pcie/aer/aerdrv.c index 6f5fabb..b164de0 100644 --- a/drivers/pci/pcie/aer/aerdrv.c +++ b/drivers/pci/pcie/aer/aerdrv.c @@ -220,7 +220,7 @@ static int __devinit aer_probe (struct p } /* Request IRQ ISR */ - if ((status = request_irq(dev->irq, aer_irq, SA_SHIRQ, "aerdrv", + if ((status = request_irq(dev->irq, aer_irq, IRQF_SHARED, "aerdrv", dev))) { printk(KERN_DEBUG "%s: Request ISR fails on PCIE device[%s]\n", __FUNCTION__, device->bus_id); diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c index 0e0401d..2fe1d69 100644 --- a/drivers/pci/probe.c +++ b/drivers/pci/probe.c @@ -144,6 +144,32 @@ static u32 pci_size(u32 base, u32 maxbas return size; } +static u64 pci_size64(u64 base, u64 maxbase, u64 mask) +{ + u64 size = mask & maxbase; /* Find the significant bits */ + if (!size) + return 0; + + /* Get the lowest of them to find the decode size, and + from that the extent. */ + size = (size & ~(size-1)) - 1; + + /* base == maxbase can be valid only if the BAR has + already been programmed with all 1s. */ + if (base == maxbase && ((base | size) & mask) != mask) + return 0; + + return size; +} + +static inline int is_64bit_memory(u32 mask) +{ + if ((mask & (PCI_BASE_ADDRESS_SPACE|PCI_BASE_ADDRESS_MEM_TYPE_MASK)) == + (PCI_BASE_ADDRESS_SPACE_MEMORY|PCI_BASE_ADDRESS_MEM_TYPE_64)) + return 1; + return 0; +} + static void pci_read_bases(struct pci_dev *dev, unsigned int howmany, int rom) { unsigned int pos, reg, next; @@ -151,6 +177,10 @@ static void pci_read_bases(struct pci_de struct resource *res; for(pos=0; posresource[pos]; res->name = pci_name(dev); @@ -163,9 +193,16 @@ static void pci_read_bases(struct pci_de continue; if (l == 0xffffffff) l = 0; - if ((l & PCI_BASE_ADDRESS_SPACE) == PCI_BASE_ADDRESS_SPACE_MEMORY) { + raw_sz = sz; + if ((l & PCI_BASE_ADDRESS_SPACE) == + PCI_BASE_ADDRESS_SPACE_MEMORY) { sz = pci_size(l, sz, (u32)PCI_BASE_ADDRESS_MEM_MASK); - if (!sz) + /* + * For 64bit prefetchable memory sz could be 0, if the + * real size is bigger than 4G, so we need to check + * szhi for that. + */ + if (!is_64bit_memory(l) && !sz) continue; res->start = l & PCI_BASE_ADDRESS_MEM_MASK; res->flags |= l & ~PCI_BASE_ADDRESS_MEM_MASK; @@ -178,30 +215,36 @@ static void pci_read_bases(struct pci_de } res->end = res->start + (unsigned long) sz; res->flags |= pci_calc_resource_flags(l); - if ((l & (PCI_BASE_ADDRESS_SPACE | PCI_BASE_ADDRESS_MEM_TYPE_MASK)) - == (PCI_BASE_ADDRESS_SPACE_MEMORY | PCI_BASE_ADDRESS_MEM_TYPE_64)) { + if (is_64bit_memory(l)) { u32 szhi, lhi; + pci_read_config_dword(dev, reg+4, &lhi); pci_write_config_dword(dev, reg+4, ~0); pci_read_config_dword(dev, reg+4, &szhi); pci_write_config_dword(dev, reg+4, lhi); - szhi = pci_size(lhi, szhi, 0xffffffff); + sz64 = ((u64)szhi << 32) | raw_sz; + l64 = ((u64)lhi << 32) | l; + sz64 = pci_size64(l64, sz64, PCI_BASE_ADDRESS_MEM_MASK); next++; #if BITS_PER_LONG == 64 - res->start |= ((unsigned long) lhi) << 32; - res->end = res->start + sz; - if (szhi) { - /* This BAR needs > 4GB? Wow. */ - res->end |= (unsigned long)szhi<<32; + if (!sz64) { + res->start = 0; + res->end = 0; + res->flags = 0; + continue; } + res->start = l64 & PCI_BASE_ADDRESS_MEM_MASK; + res->end = res->start + sz64; #else - if (szhi) { - printk(KERN_ERR "PCI: Unable to handle 64-bit BAR for device %s\n", pci_name(dev)); + if (sz64 > 0x100000000ULL) { + printk(KERN_ERR "PCI: Unable to handle 64-bit " + "BAR for device %s\n", pci_name(dev)); res->start = 0; res->flags = 0; } else if (lhi) { /* 64-bit wide address, treat as disabled */ - pci_write_config_dword(dev, reg, l & ~(u32)PCI_BASE_ADDRESS_MEM_MASK); + pci_write_config_dword(dev, reg, + l & ~(u32)PCI_BASE_ADDRESS_MEM_MASK); pci_write_config_dword(dev, reg+4, 0); res->start = 0; res->end = sz; @@ -902,7 +945,6 @@ pci_scan_single_device(struct pci_bus *b return NULL; pci_device_add(dev, bus); - pci_scan_msi_device(dev); return dev; } diff --git a/drivers/pci/proc.c b/drivers/pci/proc.c index 4a6760a..ed87aa5 100644 --- a/drivers/pci/proc.c +++ b/drivers/pci/proc.c @@ -287,7 +287,7 @@ static int proc_bus_pci_release(struct i } #endif /* HAVE_PCI_MMAP */ -static struct file_operations proc_bus_pci_operations = { +static const struct file_operations proc_bus_pci_operations = { .llseek = proc_bus_pci_lseek, .read = proc_bus_pci_read, .write = proc_bus_pci_write, @@ -456,7 +456,7 @@ static int proc_bus_pci_dev_open(struct { return seq_open(file, &proc_bus_pci_devices_op); } -static struct file_operations proc_bus_pci_dev_operations = { +static const struct file_operations proc_bus_pci_dev_operations = { .open = proc_bus_pci_dev_open, .read = seq_read, .llseek = seq_lseek, diff --git a/drivers/pci/quirks.c b/drivers/pci/quirks.c index c913ea4..1e6eda2 100644 --- a/drivers/pci/quirks.c +++ b/drivers/pci/quirks.c @@ -61,7 +61,8 @@ DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_I This appears to be BIOS not version dependent. So presumably there is a chipset level fix */ -int isa_dma_bridge_buggy; /* Exported */ +int isa_dma_bridge_buggy; +EXPORT_SYMBOL(isa_dma_bridge_buggy); static void __devinit quirk_isa_dma_hangs(struct pci_dev *dev) { @@ -83,6 +84,7 @@ DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_NE DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_NEC, PCI_DEVICE_ID_NEC_CBUS_3, quirk_isa_dma_hangs ); int pci_pci_problems; +EXPORT_SYMBOL(pci_pci_problems); /* * Chipsets where PCI->PCI transfers vanish or hang @@ -94,6 +96,8 @@ static void __devinit quirk_nopcipci(str pci_pci_problems |= PCIPCI_FAIL; } } +DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_5597, quirk_nopcipci ); +DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_496, quirk_nopcipci ); static void __devinit quirk_nopciamd(struct pci_dev *dev) { @@ -105,9 +109,6 @@ static void __devinit quirk_nopciamd(str pci_pci_problems |= PCIAGP_FAIL; } } - -DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_5597, quirk_nopcipci ); -DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_496, quirk_nopcipci ); DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_8151_0, quirk_nopciamd ); /* @@ -870,7 +871,7 @@ static void __devinit quirk_sb600_sata(s pci_write_config_byte(pdev, 0xa, 6); pci_write_config_byte(pdev, 0x40, tmp); - pdev->class = 0x010601; + pdev->class = PCI_CLASS_STORAGE_SATA_AHCI; } } DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_IXP600_SATA, quirk_sb600_sata); @@ -976,52 +977,51 @@ static void __init asus_hides_smbus_host case 0x1626: /* L3C notebook */ asus_hides_smbus = 1; } - if (dev->device == PCI_DEVICE_ID_INTEL_82845G_HB) + else if (dev->device == PCI_DEVICE_ID_INTEL_82845G_HB) switch(dev->subsystem_device) { case 0x80b1: /* P4GE-V */ case 0x80b2: /* P4PE */ case 0x8093: /* P4B533-V */ asus_hides_smbus = 1; } - if (dev->device == PCI_DEVICE_ID_INTEL_82850_HB) + else if (dev->device == PCI_DEVICE_ID_INTEL_82850_HB) switch(dev->subsystem_device) { case 0x8030: /* P4T533 */ asus_hides_smbus = 1; } - if (dev->device == PCI_DEVICE_ID_INTEL_7205_0) + else if (dev->device == PCI_DEVICE_ID_INTEL_7205_0) switch (dev->subsystem_device) { case 0x8070: /* P4G8X Deluxe */ asus_hides_smbus = 1; } - if (dev->device == PCI_DEVICE_ID_INTEL_E7501_MCH) + else if (dev->device == PCI_DEVICE_ID_INTEL_E7501_MCH) switch (dev->subsystem_device) { case 0x80c9: /* PU-DLS */ asus_hides_smbus = 1; } - if (dev->device == PCI_DEVICE_ID_INTEL_82855GM_HB) + else if (dev->device == PCI_DEVICE_ID_INTEL_82855GM_HB) switch (dev->subsystem_device) { case 0x1751: /* M2N notebook */ case 0x1821: /* M5N notebook */ asus_hides_smbus = 1; } - if (dev->device == PCI_DEVICE_ID_INTEL_82855PM_HB) + else if (dev->device == PCI_DEVICE_ID_INTEL_82855PM_HB) switch (dev->subsystem_device) { case 0x184b: /* W1N notebook */ case 0x186a: /* M6Ne notebook */ asus_hides_smbus = 1; } - if (dev->device == PCI_DEVICE_ID_INTEL_82865_HB) + else if (dev->device == PCI_DEVICE_ID_INTEL_82865_HB) switch (dev->subsystem_device) { case 0x80f2: /* P4P800-X */ asus_hides_smbus = 1; } - if (dev->device == PCI_DEVICE_ID_INTEL_82915GM_HB) { + else if (dev->device == PCI_DEVICE_ID_INTEL_82915GM_HB) switch (dev->subsystem_device) { case 0x1882: /* M6V notebook */ case 0x1977: /* A6VA notebook */ asus_hides_smbus = 1; } - } } else if (unlikely(dev->subsystem_vendor == PCI_VENDOR_ID_HP)) { if (dev->device == PCI_DEVICE_ID_INTEL_82855PM_HB) switch(dev->subsystem_device) { @@ -1029,25 +1029,24 @@ static void __init asus_hides_smbus_host case 0x0890: /* HP Compaq nc6000 */ asus_hides_smbus = 1; } - if (dev->device == PCI_DEVICE_ID_INTEL_82865_HB) + else if (dev->device == PCI_DEVICE_ID_INTEL_82865_HB) switch (dev->subsystem_device) { case 0x12bc: /* HP D330L */ case 0x12bd: /* HP D530 */ asus_hides_smbus = 1; } - if (dev->device == PCI_DEVICE_ID_INTEL_82915GM_HB) { + else if (dev->device == PCI_DEVICE_ID_INTEL_82915GM_HB) switch (dev->subsystem_device) { case 0x099c: /* HP Compaq nx6110 */ asus_hides_smbus = 1; } - } } else if (unlikely(dev->subsystem_vendor == PCI_VENDOR_ID_TOSHIBA)) { if (dev->device == PCI_DEVICE_ID_INTEL_82855GM_HB) switch(dev->subsystem_device) { case 0x0001: /* Toshiba Satellite A40 */ asus_hides_smbus = 1; } - if (dev->device == PCI_DEVICE_ID_INTEL_82855PM_HB) + else if (dev->device == PCI_DEVICE_ID_INTEL_82855PM_HB) switch(dev->subsystem_device) { case 0x0001: /* Toshiba Tecra M2 */ asus_hides_smbus = 1; @@ -1136,6 +1135,14 @@ static void quirk_sis_96x_smbus(struct p pci_write_config_byte(dev, 0x77, val & ~0x10); } } +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_961, quirk_sis_96x_smbus ); +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_962, quirk_sis_96x_smbus ); +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_963, quirk_sis_96x_smbus ); +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_LPC, quirk_sis_96x_smbus ); +DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_961, quirk_sis_96x_smbus ); +DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_962, quirk_sis_96x_smbus ); +DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_963, quirk_sis_96x_smbus ); +DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_LPC, quirk_sis_96x_smbus ); /* * ... This is further complicated by the fact that some SiS96x south @@ -1145,8 +1152,6 @@ static void quirk_sis_96x_smbus(struct p * * We can also enable the sis96x bit in the discovery register.. */ -static int __devinitdata sis_96x_compatible = 0; - #define SIS_DETECT_REGISTER 0x40 static void quirk_sis_503(struct pci_dev *dev) @@ -1162,9 +1167,6 @@ static void quirk_sis_503(struct pci_dev return; } - /* Make people aware that we changed the config.. */ - printk(KERN_WARNING "Uncovering SIS%x that hid as a SIS503 (compatible=%d)\n", devid, sis_96x_compatible); - /* * Ok, it now shows up as a 96x.. run the 96x quirk by * hand in case it has already been processed. @@ -1173,20 +1175,10 @@ static void quirk_sis_503(struct pci_dev dev->device = devid; quirk_sis_96x_smbus(dev); } - -static void __init quirk_sis_96x_compatible(struct pci_dev *dev) -{ - sis_96x_compatible = 1; -} -DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_645, quirk_sis_96x_compatible ); -DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_646, quirk_sis_96x_compatible ); -DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_648, quirk_sis_96x_compatible ); -DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_650, quirk_sis_96x_compatible ); -DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_651, quirk_sis_96x_compatible ); -DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_735, quirk_sis_96x_compatible ); - DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_503, quirk_sis_503 ); DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_503, quirk_sis_503 ); + + /* * On ASUS A8V and A8V Deluxe boards, the onboard AC97 audio controller * and MC97 modem controller are disabled when a second PCI soundcard is @@ -1217,21 +1209,8 @@ static void asus_hides_ac97_lpc(struct p } } DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8237, asus_hides_ac97_lpc ); - - -DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_961, quirk_sis_96x_smbus ); -DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_962, quirk_sis_96x_smbus ); -DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_963, quirk_sis_96x_smbus ); -DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_LPC, quirk_sis_96x_smbus ); - DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8237, asus_hides_ac97_lpc ); - -DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_961, quirk_sis_96x_smbus ); -DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_962, quirk_sis_96x_smbus ); -DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_963, quirk_sis_96x_smbus ); -DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_LPC, quirk_sis_96x_smbus ); - #if defined(CONFIG_ATA) || defined(CONFIG_ATA_MODULE) /* @@ -1276,7 +1255,6 @@ static void quirk_jmicron_dualfn(struct break; } } - DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_JMICRON, PCI_ANY_ID, quirk_jmicron_dualfn); DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_JMICRON, PCI_ANY_ID, quirk_jmicron_dualfn); @@ -1420,6 +1398,7 @@ #endif /* CONFIG_SATA_INTEL_COMBINED */ int pcie_mch_quirk; +EXPORT_SYMBOL(pcie_mch_quirk); static void __devinit quirk_pcie_mch(struct pci_dev *pdev) { @@ -1481,6 +1460,24 @@ DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_IN DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x260a, quirk_intel_pcie_pm); DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x260b, quirk_intel_pcie_pm); +/* + * Toshiba TC86C001 IDE controller reports the standard 8-byte BAR0 size + * but the PIO transfers won't work if BAR0 falls at the odd 8 bytes. + * Re-allocate the region if needed... + */ +static void __init quirk_tc86c001_ide(struct pci_dev *dev) +{ + struct resource *r = &dev->resource[0]; + + if (r->start & 0x8) { + r->start = 0; + r->end = 0xf; + } +} +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_TOSHIBA_2, + PCI_DEVICE_ID_TOSHIBA_TC86C001_IDE, + quirk_tc86c001_ide); + static void __devinit quirk_netmos(struct pci_dev *dev) { unsigned int num_parallel = (dev->subsystem_device & 0xf0) >> 4; @@ -1646,6 +1643,7 @@ void pci_fixup_device(enum pci_fixup_pas } pci_do_fixups(dev, start, end); } +EXPORT_SYMBOL(pci_fixup_device); /* Enable 1k I/O space granularity on the Intel P64H2 */ static void __devinit quirk_p64h2_1k_io(struct pci_dev *dev) @@ -1673,6 +1671,31 @@ static void __devinit quirk_p64h2_1k_io( } DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x1460, quirk_p64h2_1k_io); +/* Fix the IOBL_ADR for 1k I/O space granularity on the Intel P64H2 + * The IOBL_ADR gets re-written to 4k boundaries in pci_setup_bridge() + * in drivers/pci/setup-bus.c + */ +static void __devinit quirk_p64h2_1k_io_fix_iobl(struct pci_dev *dev) +{ + u16 en1k, iobl_adr, iobl_adr_1k; + struct resource *res = dev->resource + PCI_BRIDGE_RESOURCES; + + pci_read_config_word(dev, 0x40, &en1k); + + if (en1k & 0x200) { + pci_read_config_word(dev, PCI_IO_BASE, &iobl_adr); + + iobl_adr_1k = iobl_adr | (res->start >> 8) | (res->end & 0xfc00); + + if (iobl_adr != iobl_adr_1k) { + printk(KERN_INFO "PCI: Fixing P64H2 IOBL_ADR from 0x%x to 0x%x for 1 KB Granularity\n", + iobl_adr,iobl_adr_1k); + pci_write_config_word(dev, PCI_IO_BASE, iobl_adr_1k); + } + } +} +DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x1460, quirk_p64h2_1k_io_fix_iobl); + /* Under some circumstances, AER is not linked with extended capabilities. * Force it to be linked by setting the corresponding control bit in the * config space. @@ -1695,9 +1718,6 @@ DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_N quirk_nvidia_ck804_pcie_aer_ext_cap); #ifdef CONFIG_PCI_MSI -/* To disable MSI globally */ -int pci_msi_quirk; - /* The Serverworks PCI-X chipset does not support MSI. We cannot easily rely * on setting PCI_BUS_FLAGS_NO_MSI in its bus flags because there are actually * some other busses controlled by the chipset even if Linux is not aware of it. @@ -1706,8 +1726,8 @@ int pci_msi_quirk; */ static void __init quirk_svw_msi(struct pci_dev *dev) { - pci_msi_quirk = 1; - printk(KERN_WARNING "PCI: MSI quirk detected. pci_msi_quirk set.\n"); + pci_no_msi(); + printk(KERN_WARNING "PCI: MSI quirk detected. MSI deactivated.\n"); } DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_SERVERWORKS, PCI_DEVICE_ID_SERVERWORKS_GCNB_LE, quirk_svw_msi); @@ -1788,8 +1808,3 @@ static void __devinit quirk_nvidia_ck804 DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_CK804_PCIE, quirk_nvidia_ck804_msi_ht_cap); #endif /* CONFIG_PCI_MSI */ - -EXPORT_SYMBOL(pcie_mch_quirk); -#ifdef CONFIG_HOTPLUG -EXPORT_SYMBOL(pci_fixup_device); -#endif diff --git a/drivers/pci/search.c b/drivers/pci/search.c index b2653c4..ff98ead 100644 --- a/drivers/pci/search.c +++ b/drivers/pci/search.c @@ -358,43 +358,6 @@ exit: } /** - * pci_find_device_reverse - begin or continue searching for a PCI device by vendor/device id - * @vendor: PCI vendor id to match, or %PCI_ANY_ID to match all vendor ids - * @device: PCI device id to match, or %PCI_ANY_ID to match all device ids - * @from: Previous PCI device found in search, or %NULL for new search. - * - * Iterates through the list of known PCI devices in the reverse order of - * pci_find_device(). - * If a PCI device is found with a matching @vendor and @device, a pointer to - * its device structure is returned. Otherwise, %NULL is returned. - * A new search is initiated by passing %NULL as the @from argument. - * Otherwise if @from is not %NULL, searches continue from previous device - * on the global list. - */ -struct pci_dev * -pci_find_device_reverse(unsigned int vendor, unsigned int device, const struct pci_dev *from) -{ - struct list_head *n; - struct pci_dev *dev; - - WARN_ON(in_interrupt()); - down_read(&pci_bus_sem); - n = from ? from->global_list.prev : pci_devices.prev; - - while (n && (n != &pci_devices)) { - dev = pci_dev_g(n); - if ((vendor == PCI_ANY_ID || dev->vendor == vendor) && - (device == PCI_ANY_ID || dev->device == device)) - goto exit; - n = n->prev; - } - dev = NULL; -exit: - up_read(&pci_bus_sem); - return dev; -} - -/** * pci_get_class - begin or continue searching for a PCI device by class * @class: search for a PCI device with this class designation * @from: Previous PCI device found in search, or %NULL for new search. @@ -469,7 +432,6 @@ EXPORT_SYMBOL(pci_dev_present); EXPORT_SYMBOL(pci_find_present); EXPORT_SYMBOL(pci_find_device); -EXPORT_SYMBOL(pci_find_device_reverse); EXPORT_SYMBOL(pci_find_slot); /* For boot time work */ EXPORT_SYMBOL(pci_find_bus); diff --git a/drivers/pci/syscall.c b/drivers/pci/syscall.c index 87fafc0..9d37fec 100644 --- a/drivers/pci/syscall.c +++ b/drivers/pci/syscall.c @@ -7,7 +7,6 @@ * magic northbridge registers.. */ -#include #include #include #include diff --git a/drivers/pcmcia/at91_cf.c b/drivers/pcmcia/at91_cf.c index 3334f22..b318628 100644 --- a/drivers/pcmcia/at91_cf.c +++ b/drivers/pcmcia/at91_cf.c @@ -11,7 +11,6 @@ #include #include -#include #include #include #include diff --git a/drivers/pcmcia/cistpl.c b/drivers/pcmcia/cistpl.c index 912c03e..d154dee 100644 --- a/drivers/pcmcia/cistpl.c +++ b/drivers/pcmcia/cistpl.c @@ -21,7 +21,6 @@ #include #include #include #include -#include #include #include #include diff --git a/drivers/pcmcia/cs.c b/drivers/pcmcia/cs.c index 606a467..ac00424 100644 --- a/drivers/pcmcia/cs.c +++ b/drivers/pcmcia/cs.c @@ -110,7 +110,7 @@ int pcmcia_socket_dev_suspend(struct dev down_read(&pcmcia_socket_list_rwsem); list_for_each_entry(socket, &pcmcia_socket_list, socket_list) { - if (socket->dev.dev != dev) + if (socket->dev.parent != dev) continue; mutex_lock(&socket->skt_mutex); socket_suspend(socket); @@ -128,7 +128,7 @@ int pcmcia_socket_dev_resume(struct devi down_read(&pcmcia_socket_list_rwsem); list_for_each_entry(socket, &pcmcia_socket_list, socket_list) { - if (socket->dev.dev != dev) + if (socket->dev.parent != dev) continue; mutex_lock(&socket->skt_mutex); socket_resume(socket); @@ -143,12 +143,12 @@ EXPORT_SYMBOL(pcmcia_socket_dev_resume); struct pcmcia_socket * pcmcia_get_socket(struct pcmcia_socket *skt) { - struct class_device *cl_dev = class_device_get(&skt->dev); - if (!cl_dev) + struct device *dev = get_device(&skt->dev); + if (!dev) return NULL; - skt = class_get_devdata(cl_dev); + skt = dev_get_drvdata(dev); if (!try_module_get(skt->owner)) { - class_device_put(&skt->dev); + put_device(&skt->dev); return NULL; } return (skt); @@ -159,14 +159,14 @@ EXPORT_SYMBOL(pcmcia_get_socket); void pcmcia_put_socket(struct pcmcia_socket *skt) { module_put(skt->owner); - class_device_put(&skt->dev); + put_device(&skt->dev); } EXPORT_SYMBOL(pcmcia_put_socket); -static void pcmcia_release_socket(struct class_device *class_dev) +static void pcmcia_release_socket(struct device *dev) { - struct pcmcia_socket *socket = class_get_devdata(class_dev); + struct pcmcia_socket *socket = dev_get_drvdata(dev); complete(&socket->socket_released); } @@ -181,7 +181,7 @@ int pcmcia_register_socket(struct pcmcia struct task_struct *tsk; int ret; - if (!socket || !socket->ops || !socket->dev.dev || !socket->resource_ops) + if (!socket || !socket->ops || !socket->dev.parent || !socket->resource_ops) return -EINVAL; cs_dbg(socket, 0, "pcmcia_register_socket(0x%p)\n", socket->ops); @@ -226,9 +226,9 @@ #ifndef CONFIG_CARDBUS #endif /* set proper values in socket->dev */ - socket->dev.class_data = socket; + dev_set_drvdata(&socket->dev, socket); socket->dev.class = &pcmcia_socket_class; - snprintf(socket->dev.class_id, BUS_ID_SIZE, "pcmcia_socket%u", socket->sock); + snprintf(socket->dev.bus_id, BUS_ID_SIZE, "pcmcia_socket%u", socket->sock); /* base address = 0, map = 0 */ socket->cis_mem.flags = 0; @@ -640,7 +640,7 @@ static int pccardd(void *__skt) skt->ops->set_socket(skt, &skt->socket); /* register with the device core */ - ret = class_device_register(&skt->dev); + ret = device_register(&skt->dev); if (ret) { printk(KERN_WARNING "PCMCIA: unable to register socket 0x%p\n", skt); @@ -689,7 +689,7 @@ static int pccardd(void *__skt) remove_wait_queue(&skt->thread_wait, &wait); /* remove from the device core */ - class_device_unregister(&skt->dev); + device_unregister(&skt->dev); return 0; } @@ -904,7 +904,7 @@ int pcmcia_insert_card(struct pcmcia_soc EXPORT_SYMBOL(pcmcia_insert_card); -static int pcmcia_socket_uevent(struct class_device *dev, char **envp, +static int pcmcia_socket_uevent(struct device *dev, char **envp, int num_envp, char *buffer, int buffer_size) { struct pcmcia_socket *s = container_of(dev, struct pcmcia_socket, dev); @@ -930,8 +930,8 @@ static void pcmcia_release_socket_class( struct class pcmcia_socket_class = { .name = "pcmcia_socket", - .uevent = pcmcia_socket_uevent, - .release = pcmcia_release_socket, + .dev_uevent = pcmcia_socket_uevent, + .dev_release = pcmcia_release_socket, .class_release = pcmcia_release_socket_class, }; EXPORT_SYMBOL(pcmcia_socket_class); diff --git a/drivers/pcmcia/cs_internal.h b/drivers/pcmcia/cs_internal.h index f573ea0..9fa207e 100644 --- a/drivers/pcmcia/cs_internal.h +++ b/drivers/pcmcia/cs_internal.h @@ -142,7 +142,7 @@ struct pcmcia_callback{ int pccard_register_pcmcia(struct pcmcia_socket *s, struct pcmcia_callback *c); -#define cs_socket_name(skt) ((skt)->dev.class_id) +#define cs_socket_name(skt) ((skt)->dev.bus_id) #ifdef DEBUG extern int cs_debug_level(int); @@ -158,6 +158,6 @@ #define cs_dbg(skt, lvl, fmt, arg...) do #endif #define cs_err(skt, fmt, arg...) \ - printk(KERN_ERR "cs: %s: " fmt, (skt)->dev.class_id , ## arg) + printk(KERN_ERR "cs: %s: " fmt, (skt)->dev.bus_id , ## arg) #endif /* _LINUX_CS_INTERNAL_H */ diff --git a/drivers/pcmcia/ds.c b/drivers/pcmcia/ds.c index 7355eb4..18e111e 100644 --- a/drivers/pcmcia/ds.c +++ b/drivers/pcmcia/ds.c @@ -572,7 +572,7 @@ struct pcmcia_device * pcmcia_device_add p_dev->func = function; p_dev->dev.bus = &pcmcia_bus_type; - p_dev->dev.parent = s->dev.dev; + p_dev->dev.parent = s->dev.parent; p_dev->dev.release = pcmcia_release_dev; bus_id_len = sprintf (p_dev->dev.bus_id, "%d.%d", p_dev->socket->sock, p_dev->device_no); @@ -1328,10 +1328,10 @@ static struct pcmcia_callback pcmcia_bus .resume = pcmcia_bus_resume, }; -static int __devinit pcmcia_bus_add_socket(struct class_device *class_dev, +static int __devinit pcmcia_bus_add_socket(struct device *dev, struct class_interface *class_intf) { - struct pcmcia_socket *socket = class_get_devdata(class_dev); + struct pcmcia_socket *socket = dev_get_drvdata(dev); int ret; socket = pcmcia_get_socket(socket); @@ -1364,10 +1364,10 @@ #endif return 0; } -static void pcmcia_bus_remove_socket(struct class_device *class_dev, +static void pcmcia_bus_remove_socket(struct device *dev, struct class_interface *class_intf) { - struct pcmcia_socket *socket = class_get_devdata(class_dev); + struct pcmcia_socket *socket = dev_get_drvdata(dev); if (!socket) return; @@ -1389,8 +1389,8 @@ static void pcmcia_bus_remove_socket(str /* the pcmcia_bus_interface is used to handle pcmcia socket devices */ static struct class_interface pcmcia_bus_interface = { .class = &pcmcia_socket_class, - .add = &pcmcia_bus_add_socket, - .remove = &pcmcia_bus_remove_socket, + .add_dev = &pcmcia_bus_add_socket, + .remove_dev = &pcmcia_bus_remove_socket, }; diff --git a/drivers/pcmcia/i82092.c b/drivers/pcmcia/i82092.c index c2ea07a..df21e2d 100644 --- a/drivers/pcmcia/i82092.c +++ b/drivers/pcmcia/i82092.c @@ -161,7 +161,7 @@ static int __devinit i82092aa_pci_probe( pci_set_drvdata(dev, &sockets[i].socket); for (i = 0; idev; + sockets[i].socket.dev.parent = &dev->dev; sockets[i].socket.ops = &i82092aa_operations; sockets[i].socket.resource_ops = &pccard_nonstatic_ops; ret = pcmcia_register_socket(&sockets[i].socket); diff --git a/drivers/pcmcia/i82365.c b/drivers/pcmcia/i82365.c index ea74f98..71b3370 100644 --- a/drivers/pcmcia/i82365.c +++ b/drivers/pcmcia/i82365.c @@ -40,7 +40,6 @@ #include #include #include #include -#include #include #include #include @@ -1298,7 +1297,7 @@ static int __init init_i82365(void) /* register sockets with the pcmcia core */ for (i = 0; i < sockets; i++) { - socket[i].socket.dev.dev = &i82365_device->dev; + socket[i].socket.dev.parent = &i82365_device->dev; socket[i].socket.ops = &pcic_operations; socket[i].socket.resource_ops = &pccard_nonstatic_ops; socket[i].socket.owner = THIS_MODULE; diff --git a/drivers/pcmcia/m32r_cfc.c b/drivers/pcmcia/m32r_cfc.c index 3c22ac4..e4a9410 100644 --- a/drivers/pcmcia/m32r_cfc.c +++ b/drivers/pcmcia/m32r_cfc.c @@ -16,7 +16,6 @@ #include #include #include #include -#include #include #include #include diff --git a/drivers/pcmcia/m32r_pcc.c b/drivers/pcmcia/m32r_pcc.c index bbf0258..67d28ee 100644 --- a/drivers/pcmcia/m32r_pcc.c +++ b/drivers/pcmcia/m32r_pcc.c @@ -16,7 +16,6 @@ #include #include #include #include -#include #include #include #include @@ -722,7 +721,7 @@ #endif /* Set up interrupt handler(s) */ for (i = 0 ; i < pcc_sockets ; i++) { - socket[i].socket.dev.dev = &pcc_device.dev; + socket[i].socket.dev.parent = &pcc_device.dev; socket[i].socket.ops = &pcc_operations; socket[i].socket.resource_ops = &pccard_static_ops; socket[i].socket.owner = THIS_MODULE; diff --git a/drivers/pcmcia/m8xx_pcmcia.c b/drivers/pcmcia/m8xx_pcmcia.c index 3b72be8..d059c91 100644 --- a/drivers/pcmcia/m8xx_pcmcia.c +++ b/drivers/pcmcia/m8xx_pcmcia.c @@ -46,7 +46,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/pcmcia/omap_cf.c b/drivers/pcmcia/omap_cf.c index e65a6b8..76f7cbc 100644 --- a/drivers/pcmcia/omap_cf.c +++ b/drivers/pcmcia/omap_cf.c @@ -11,7 +11,6 @@ #include #include -#include #include #include #include diff --git a/drivers/pcmcia/pcmcia_ioctl.c b/drivers/pcmcia/pcmcia_ioctl.c index 327372b..27523c5 100644 --- a/drivers/pcmcia/pcmcia_ioctl.c +++ b/drivers/pcmcia/pcmcia_ioctl.c @@ -59,7 +59,6 @@ typedef struct user_info_t { #ifdef DEBUG extern int ds_pc_debug; -#define cs_socket_name(skt) ((skt)->dev.class_id) #define ds_dbg(lvl, fmt, arg...) do { \ if (ds_pc_debug >= lvl) \ @@ -766,7 +765,7 @@ free_out: /*====================================================================*/ -static struct file_operations ds_fops = { +static const struct file_operations ds_fops = { .owner = THIS_MODULE, .open = ds_open, .release = ds_release, diff --git a/drivers/pcmcia/pcmcia_resource.c b/drivers/pcmcia/pcmcia_resource.c index b9201c2..0ce39de 100644 --- a/drivers/pcmcia/pcmcia_resource.c +++ b/drivers/pcmcia/pcmcia_resource.c @@ -48,7 +48,6 @@ #endif #ifdef DEBUG extern int ds_pc_debug; -#define cs_socket_name(skt) ((skt)->dev.class_id) #define ds_dbg(skt, lvl, fmt, arg...) do { \ if (ds_pc_debug >= lvl) \ diff --git a/drivers/pcmcia/pd6729.c b/drivers/pcmcia/pd6729.c index 360c248..dd0ddf1 100644 --- a/drivers/pcmcia/pd6729.c +++ b/drivers/pcmcia/pd6729.c @@ -682,7 +682,7 @@ static int __devinit pd6729_pci_probe(st socket[i].socket.ops = &pd6729_operations; socket[i].socket.resource_ops = &pccard_nonstatic_ops; - socket[i].socket.dev.dev = &dev->dev; + socket[i].socket.dev.parent = &dev->dev; socket[i].socket.driver_data = &socket[i]; } diff --git a/drivers/pcmcia/pxa2xx_lubbock.c b/drivers/pcmcia/pxa2xx_lubbock.c index a92f111..5e9b9a3 100644 --- a/drivers/pcmcia/pxa2xx_lubbock.c +++ b/drivers/pcmcia/pxa2xx_lubbock.c @@ -16,7 +16,6 @@ */ #include #include -#include #include #include #include diff --git a/drivers/pcmcia/rsrc_nonstatic.c b/drivers/pcmcia/rsrc_nonstatic.c index c3176b1..bfcaad6 100644 --- a/drivers/pcmcia/rsrc_nonstatic.c +++ b/drivers/pcmcia/rsrc_nonstatic.c @@ -616,7 +616,7 @@ static int nonstatic_adjust_io_region(st static struct resource *nonstatic_find_io_region(unsigned long base, int num, unsigned long align, struct pcmcia_socket *s) { - struct resource *res = make_resource(0, num, IORESOURCE_IO, s->dev.class_id); + struct resource *res = make_resource(0, num, IORESOURCE_IO, s->dev.bus_id); struct socket_data *s_data = s->resource_data; struct pcmcia_align_data data; unsigned long min = base; @@ -650,7 +650,7 @@ #endif static struct resource * nonstatic_find_mem_region(u_long base, u_long num, u_long align, int low, struct pcmcia_socket *s) { - struct resource *res = make_resource(0, num, IORESOURCE_MEM, s->dev.class_id); + struct resource *res = make_resource(0, num, IORESOURCE_MEM, s->dev.bus_id); struct socket_data *s_data = s->resource_data; struct pcmcia_align_data data; unsigned long min, max; @@ -897,9 +897,10 @@ EXPORT_SYMBOL(pccard_nonstatic_ops); /* sysfs interface to the resource database */ -static ssize_t show_io_db(struct class_device *class_dev, char *buf) +static ssize_t show_io_db(struct device *dev, + struct device_attribute *attr, char *buf) { - struct pcmcia_socket *s = class_get_devdata(class_dev); + struct pcmcia_socket *s = dev_get_drvdata(dev); struct socket_data *data; struct resource_map *p; ssize_t ret = 0; @@ -920,9 +921,11 @@ static ssize_t show_io_db(struct class_d return (ret); } -static ssize_t store_io_db(struct class_device *class_dev, const char *buf, size_t count) +static ssize_t store_io_db(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) { - struct pcmcia_socket *s = class_get_devdata(class_dev); + struct pcmcia_socket *s = dev_get_drvdata(dev); unsigned long start_addr, end_addr; unsigned int add = ADD_MANAGED_RESOURCE; ssize_t ret = 0; @@ -947,11 +950,12 @@ static ssize_t store_io_db(struct class_ return ret ? ret : count; } -static CLASS_DEVICE_ATTR(available_resources_io, 0600, show_io_db, store_io_db); +static DEVICE_ATTR(available_resources_io, 0600, show_io_db, store_io_db); -static ssize_t show_mem_db(struct class_device *class_dev, char *buf) +static ssize_t show_mem_db(struct device *dev, + struct device_attribute *attr, char *buf) { - struct pcmcia_socket *s = class_get_devdata(class_dev); + struct pcmcia_socket *s = dev_get_drvdata(dev); struct socket_data *data; struct resource_map *p; ssize_t ret = 0; @@ -972,9 +976,11 @@ static ssize_t show_mem_db(struct class_ return (ret); } -static ssize_t store_mem_db(struct class_device *class_dev, const char *buf, size_t count) +static ssize_t store_mem_db(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) { - struct pcmcia_socket *s = class_get_devdata(class_dev); + struct pcmcia_socket *s = dev_get_drvdata(dev); unsigned long start_addr, end_addr; unsigned int add = ADD_MANAGED_RESOURCE; ssize_t ret = 0; @@ -999,25 +1005,25 @@ static ssize_t store_mem_db(struct class return ret ? ret : count; } -static CLASS_DEVICE_ATTR(available_resources_mem, 0600, show_mem_db, store_mem_db); +static DEVICE_ATTR(available_resources_mem, 0600, show_mem_db, store_mem_db); -static struct class_device_attribute *pccard_rsrc_attributes[] = { - &class_device_attr_available_resources_io, - &class_device_attr_available_resources_mem, +static struct device_attribute *pccard_rsrc_attributes[] = { + &dev_attr_available_resources_io, + &dev_attr_available_resources_mem, NULL, }; -static int __devinit pccard_sysfs_add_rsrc(struct class_device *class_dev, +static int __devinit pccard_sysfs_add_rsrc(struct device *dev, struct class_interface *class_intf) { - struct pcmcia_socket *s = class_get_devdata(class_dev); - struct class_device_attribute **attr; + struct pcmcia_socket *s = dev_get_drvdata(dev); + struct device_attribute **attr; int ret = 0; if (s->resource_ops != &pccard_nonstatic_ops) return 0; for (attr = pccard_rsrc_attributes; *attr; attr++) { - ret = class_device_create_file(class_dev, *attr); + ret = device_create_file(dev, *attr); if (ret) break; } @@ -1025,23 +1031,23 @@ static int __devinit pccard_sysfs_add_rs return ret; } -static void __devexit pccard_sysfs_remove_rsrc(struct class_device *class_dev, +static void __devexit pccard_sysfs_remove_rsrc(struct device *dev, struct class_interface *class_intf) { - struct pcmcia_socket *s = class_get_devdata(class_dev); - struct class_device_attribute **attr; + struct pcmcia_socket *s = dev_get_drvdata(dev); + struct device_attribute **attr; if (s->resource_ops != &pccard_nonstatic_ops) return; for (attr = pccard_rsrc_attributes; *attr; attr++) - class_device_remove_file(class_dev, *attr); + device_remove_file(dev, *attr); } static struct class_interface pccard_rsrc_interface = { .class = &pcmcia_socket_class, - .add = &pccard_sysfs_add_rsrc, - .remove = __devexit_p(&pccard_sysfs_remove_rsrc), + .add_dev = &pccard_sysfs_add_rsrc, + .remove_dev = __devexit_p(&pccard_sysfs_remove_rsrc), }; static int __init nonstatic_sysfs_init(void) diff --git a/drivers/pcmcia/sa1100_badge4.c b/drivers/pcmcia/sa1100_badge4.c index 19b1e12..62bfc75 100644 --- a/drivers/pcmcia/sa1100_badge4.c +++ b/drivers/pcmcia/sa1100_badge4.c @@ -14,7 +14,6 @@ */ #include #include -#include #include #include #include diff --git a/drivers/pcmcia/sa1100_cerf.c b/drivers/pcmcia/sa1100_cerf.c index eb89928..549a152 100644 --- a/drivers/pcmcia/sa1100_cerf.c +++ b/drivers/pcmcia/sa1100_cerf.c @@ -7,7 +7,6 @@ */ #include #include -#include #include #include #include diff --git a/drivers/pcmcia/sa1100_h3600.c b/drivers/pcmcia/sa1100_h3600.c index 64fd5e3..e549187 100644 --- a/drivers/pcmcia/sa1100_h3600.c +++ b/drivers/pcmcia/sa1100_h3600.c @@ -6,7 +6,6 @@ */ #include #include -#include #include #include #include diff --git a/drivers/pcmcia/sa1100_jornada720.c b/drivers/pcmcia/sa1100_jornada720.c index 7a87298..af485ae 100644 --- a/drivers/pcmcia/sa1100_jornada720.c +++ b/drivers/pcmcia/sa1100_jornada720.c @@ -6,7 +6,6 @@ */ #include #include -#include #include #include #include diff --git a/drivers/pcmcia/sa1100_neponset.c b/drivers/pcmcia/sa1100_neponset.c index 5e34b3e..5bc9e95 100644 --- a/drivers/pcmcia/sa1100_neponset.c +++ b/drivers/pcmcia/sa1100_neponset.c @@ -5,7 +5,6 @@ */ #include #include -#include #include #include #include diff --git a/drivers/pcmcia/sa1100_shannon.c b/drivers/pcmcia/sa1100_shannon.c index 7bc9e59..9456f54 100644 --- a/drivers/pcmcia/sa1100_shannon.c +++ b/drivers/pcmcia/sa1100_shannon.c @@ -6,7 +6,6 @@ */ #include #include -#include #include #include diff --git a/drivers/pcmcia/sa1100_simpad.c b/drivers/pcmcia/sa1100_simpad.c index c2ecf11..04d6f7f 100644 --- a/drivers/pcmcia/sa1100_simpad.c +++ b/drivers/pcmcia/sa1100_simpad.c @@ -6,7 +6,6 @@ */ #include #include -#include #include #include diff --git a/drivers/pcmcia/soc_common.c b/drivers/pcmcia/soc_common.c index e433704..d2a3bea 100644 --- a/drivers/pcmcia/soc_common.c +++ b/drivers/pcmcia/soc_common.c @@ -478,10 +478,10 @@ dump_bits(char **p, const char *prefix, * * Returns: the number of characters added to the buffer */ -static ssize_t show_status(struct class_device *class_dev, char *buf) +static ssize_t show_status(struct device *dev, char *buf) { struct soc_pcmcia_socket *skt = - container_of(class_dev, struct soc_pcmcia_socket, socket.dev); + container_of(dev, struct soc_pcmcia_socket, socket.dev); char *p = buf; p+=sprintf(p, "slot : %d\n", skt->nr); @@ -747,7 +747,7 @@ int soc_common_drv_pcmcia_probe(struct d add_timer(&skt->poll_timer); - class_device_create_file(&skt->socket.dev, &class_device_attr_status); + device_create_file(&skt->socket.dev, &device_attr_status); } dev_set_drvdata(dev, sinfo); diff --git a/drivers/pcmcia/socket_sysfs.c b/drivers/pcmcia/socket_sysfs.c index b005602..ea5765c 100644 --- a/drivers/pcmcia/socket_sysfs.c +++ b/drivers/pcmcia/socket_sysfs.c @@ -40,7 +40,8 @@ #include "cs_internal.h" #define to_socket(_dev) container_of(_dev, struct pcmcia_socket, dev) -static ssize_t pccard_show_type(struct class_device *dev, char *buf) +static ssize_t pccard_show_type(struct device *dev, struct device_attribute *attr, + char *buf) { struct pcmcia_socket *s = to_socket(dev); @@ -50,9 +51,10 @@ static ssize_t pccard_show_type(struct c return sprintf(buf, "32-bit\n"); return sprintf(buf, "16-bit\n"); } -static CLASS_DEVICE_ATTR(card_type, 0444, pccard_show_type, NULL); +static DEVICE_ATTR(card_type, 0444, pccard_show_type, NULL); -static ssize_t pccard_show_voltage(struct class_device *dev, char *buf) +static ssize_t pccard_show_voltage(struct device *dev, struct device_attribute *attr, + char *buf) { struct pcmcia_socket *s = to_socket(dev); @@ -63,28 +65,31 @@ static ssize_t pccard_show_voltage(struc s->socket.Vcc % 10); return sprintf(buf, "X.XV\n"); } -static CLASS_DEVICE_ATTR(card_voltage, 0444, pccard_show_voltage, NULL); +static DEVICE_ATTR(card_voltage, 0444, pccard_show_voltage, NULL); -static ssize_t pccard_show_vpp(struct class_device *dev, char *buf) +static ssize_t pccard_show_vpp(struct device *dev, struct device_attribute *attr, + char *buf) { struct pcmcia_socket *s = to_socket(dev); if (!(s->state & SOCKET_PRESENT)) return -ENODEV; return sprintf(buf, "%d.%dV\n", s->socket.Vpp / 10, s->socket.Vpp % 10); } -static CLASS_DEVICE_ATTR(card_vpp, 0444, pccard_show_vpp, NULL); +static DEVICE_ATTR(card_vpp, 0444, pccard_show_vpp, NULL); -static ssize_t pccard_show_vcc(struct class_device *dev, char *buf) +static ssize_t pccard_show_vcc(struct device *dev, struct device_attribute *attr, + char *buf) { struct pcmcia_socket *s = to_socket(dev); if (!(s->state & SOCKET_PRESENT)) return -ENODEV; return sprintf(buf, "%d.%dV\n", s->socket.Vcc / 10, s->socket.Vcc % 10); } -static CLASS_DEVICE_ATTR(card_vcc, 0444, pccard_show_vcc, NULL); +static DEVICE_ATTR(card_vcc, 0444, pccard_show_vcc, NULL); -static ssize_t pccard_store_insert(struct class_device *dev, const char *buf, size_t count) +static ssize_t pccard_store_insert(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) { ssize_t ret; struct pcmcia_socket *s = to_socket(dev); @@ -96,16 +101,20 @@ static ssize_t pccard_store_insert(struc return ret ? ret : count; } -static CLASS_DEVICE_ATTR(card_insert, 0200, NULL, pccard_store_insert); +static DEVICE_ATTR(card_insert, 0200, NULL, pccard_store_insert); -static ssize_t pccard_show_card_pm_state(struct class_device *dev, char *buf) +static ssize_t pccard_show_card_pm_state(struct device *dev, + struct device_attribute *attr, + char *buf) { struct pcmcia_socket *s = to_socket(dev); return sprintf(buf, "%s\n", s->state & SOCKET_SUSPEND ? "off" : "on"); } -static ssize_t pccard_store_card_pm_state(struct class_device *dev, const char *buf, size_t count) +static ssize_t pccard_store_card_pm_state(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) { ssize_t ret = -EINVAL; struct pcmcia_socket *s = to_socket(dev); @@ -120,9 +129,11 @@ static ssize_t pccard_store_card_pm_stat return ret ? -ENODEV : count; } -static CLASS_DEVICE_ATTR(card_pm_state, 0644, pccard_show_card_pm_state, pccard_store_card_pm_state); +static DEVICE_ATTR(card_pm_state, 0644, pccard_show_card_pm_state, pccard_store_card_pm_state); -static ssize_t pccard_store_eject(struct class_device *dev, const char *buf, size_t count) +static ssize_t pccard_store_eject(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) { ssize_t ret; struct pcmcia_socket *s = to_socket(dev); @@ -134,16 +145,20 @@ static ssize_t pccard_store_eject(struct return ret ? ret : count; } -static CLASS_DEVICE_ATTR(card_eject, 0200, NULL, pccard_store_eject); +static DEVICE_ATTR(card_eject, 0200, NULL, pccard_store_eject); -static ssize_t pccard_show_irq_mask(struct class_device *dev, char *buf) +static ssize_t pccard_show_irq_mask(struct device *dev, + struct device_attribute *attr, + char *buf) { struct pcmcia_socket *s = to_socket(dev); return sprintf(buf, "0x%04x\n", s->irq_mask); } -static ssize_t pccard_store_irq_mask(struct class_device *dev, const char *buf, size_t count) +static ssize_t pccard_store_irq_mask(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) { ssize_t ret; struct pcmcia_socket *s = to_socket(dev); @@ -161,16 +176,19 @@ static ssize_t pccard_store_irq_mask(str return ret ? ret : count; } -static CLASS_DEVICE_ATTR(card_irq_mask, 0600, pccard_show_irq_mask, pccard_store_irq_mask); +static DEVICE_ATTR(card_irq_mask, 0600, pccard_show_irq_mask, pccard_store_irq_mask); -static ssize_t pccard_show_resource(struct class_device *dev, char *buf) +static ssize_t pccard_show_resource(struct device *dev, + struct device_attribute *attr, char *buf) { struct pcmcia_socket *s = to_socket(dev); return sprintf(buf, "%s\n", s->resource_setup_done ? "yes" : "no"); } -static ssize_t pccard_store_resource(struct class_device *dev, const char *buf, size_t count) +static ssize_t pccard_store_resource(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) { unsigned long flags; struct pcmcia_socket *s = to_socket(dev); @@ -196,7 +214,7 @@ static ssize_t pccard_store_resource(str return count; } -static CLASS_DEVICE_ATTR(available_resources_setup_done, 0600, pccard_show_resource, pccard_store_resource); +static DEVICE_ATTR(available_resources_setup_done, 0600, pccard_show_resource, pccard_store_resource); static ssize_t pccard_extract_cis(struct pcmcia_socket *s, char *buf, loff_t off, size_t count) @@ -279,7 +297,7 @@ static ssize_t pccard_show_cis(struct ko if (off + count > size) count = size - off; - s = to_socket(container_of(kobj, struct class_device, kobj)); + s = to_socket(container_of(kobj, struct device, kobj)); if (!(s->state & SOCKET_PRESENT)) return -ENODEV; @@ -296,7 +314,7 @@ static ssize_t pccard_show_cis(struct ko static ssize_t pccard_store_cis(struct kobject *kobj, char *buf, loff_t off, size_t count) { - struct pcmcia_socket *s = to_socket(container_of(kobj, struct class_device, kobj)); + struct pcmcia_socket *s = to_socket(container_of(kobj, struct device, kobj)); cisdump_t *cis; int error; @@ -335,16 +353,16 @@ static ssize_t pccard_store_cis(struct k } -static struct class_device_attribute *pccard_socket_attributes[] = { - &class_device_attr_card_type, - &class_device_attr_card_voltage, - &class_device_attr_card_vpp, - &class_device_attr_card_vcc, - &class_device_attr_card_insert, - &class_device_attr_card_pm_state, - &class_device_attr_card_eject, - &class_device_attr_card_irq_mask, - &class_device_attr_available_resources_setup_done, +static struct device_attribute *pccard_socket_attributes[] = { + &dev_attr_card_type, + &dev_attr_card_voltage, + &dev_attr_card_vpp, + &dev_attr_card_vcc, + &dev_attr_card_insert, + &dev_attr_card_pm_state, + &dev_attr_card_eject, + &dev_attr_card_irq_mask, + &dev_attr_available_resources_setup_done, NULL, }; @@ -355,35 +373,35 @@ static struct bin_attribute pccard_cis_a .write = pccard_store_cis, }; -static int __devinit pccard_sysfs_add_socket(struct class_device *class_dev, +static int __devinit pccard_sysfs_add_socket(struct device *dev, struct class_interface *class_intf) { - struct class_device_attribute **attr; + struct device_attribute **attr; int ret = 0; for (attr = pccard_socket_attributes; *attr; attr++) { - ret = class_device_create_file(class_dev, *attr); + ret = device_create_file(dev, *attr); if (ret) break; } if (!ret) - ret = sysfs_create_bin_file(&class_dev->kobj, &pccard_cis_attr); + ret = sysfs_create_bin_file(&dev->kobj, &pccard_cis_attr); return ret; } -static void __devexit pccard_sysfs_remove_socket(struct class_device *class_dev, +static void __devexit pccard_sysfs_remove_socket(struct device *dev, struct class_interface *class_intf) { - struct class_device_attribute **attr; + struct device_attribute **attr; - sysfs_remove_bin_file(&class_dev->kobj, &pccard_cis_attr); + sysfs_remove_bin_file(&dev->kobj, &pccard_cis_attr); for (attr = pccard_socket_attributes; *attr; attr++) - class_device_remove_file(class_dev, *attr); + device_remove_file(dev, *attr); } struct class_interface pccard_sysfs_interface = { .class = &pcmcia_socket_class, - .add = &pccard_sysfs_add_socket, - .remove = __devexit_p(&pccard_sysfs_remove_socket), + .add_dev = &pccard_sysfs_add_socket, + .remove_dev = __devexit_p(&pccard_sysfs_remove_socket), }; diff --git a/drivers/pcmcia/tcic.c b/drivers/pcmcia/tcic.c index 2d2f415..c158cf3 100644 --- a/drivers/pcmcia/tcic.c +++ b/drivers/pcmcia/tcic.c @@ -512,7 +512,7 @@ static int __init init_tcic(void) for (i = 0; i < sockets; i++) { socket_table[i].socket.ops = &tcic_operations; socket_table[i].socket.resource_ops = &pccard_nonstatic_ops; - socket_table[i].socket.dev.dev = &tcic_device.dev; + socket_table[i].socket.dev.parent = &tcic_device.dev; ret = pcmcia_register_socket(&socket_table[i].socket); if (ret && i) pcmcia_unregister_socket(&socket_table[0].socket); diff --git a/drivers/pcmcia/vrc4171_card.c b/drivers/pcmcia/vrc4171_card.c index e90d8e8..206e26c 100644 --- a/drivers/pcmcia/vrc4171_card.c +++ b/drivers/pcmcia/vrc4171_card.c @@ -22,7 +22,6 @@ #include #include #include #include -#include #include #include diff --git a/drivers/pcmcia/yenta_socket.c b/drivers/pcmcia/yenta_socket.c index da471bd..20853a0 100644 --- a/drivers/pcmcia/yenta_socket.c +++ b/drivers/pcmcia/yenta_socket.c @@ -12,7 +12,6 @@ */ #include #include -#include #include #include #include @@ -1104,7 +1103,7 @@ static int __devinit yenta_probe (struct /* prepare pcmcia_socket */ socket->socket.ops = ¥ta_socket_operations; socket->socket.resource_ops = &pccard_nonstatic_ops; - socket->socket.dev.dev = &dev->dev; + socket->socket.dev.parent = &dev->dev; socket->socket.driver_data = socket; socket->socket.owner = THIS_MODULE; socket->socket.features = SS_CAP_PAGE_REGS | SS_CAP_PCCARD; diff --git a/drivers/pnp/base.h b/drivers/pnp/base.h index 6b8c4cf..31a633f 100644 --- a/drivers/pnp/base.h +++ b/drivers/pnp/base.h @@ -1,4 +1,3 @@ -extern struct bus_type pnp_bus_type; extern spinlock_t pnp_lock; void *pnp_alloc(long size); int pnp_interface_attach_device(struct pnp_dev *dev); diff --git a/drivers/pnp/isapnp/proc.c b/drivers/pnp/isapnp/proc.c index d21f3c1..40b724e 100644 --- a/drivers/pnp/isapnp/proc.c +++ b/drivers/pnp/isapnp/proc.c @@ -85,7 +85,7 @@ static ssize_t isapnp_proc_bus_read(stru return nbytes; } -static struct file_operations isapnp_proc_bus_file_operations = +static const struct file_operations isapnp_proc_bus_file_operations = { .llseek = isapnp_proc_bus_lseek, .read = isapnp_proc_bus_read, diff --git a/drivers/pnp/pnpacpi/Kconfig b/drivers/pnp/pnpacpi/Kconfig index b185417..ad27e5e 100644 --- a/drivers/pnp/pnpacpi/Kconfig +++ b/drivers/pnp/pnpacpi/Kconfig @@ -2,8 +2,8 @@ # # Plug and Play ACPI configuration # config PNPACPI - bool "Plug and Play ACPI support (EXPERIMENTAL)" - depends on PNP && ACPI && EXPERIMENTAL + bool "Plug and Play ACPI support" + depends on PNP && ACPI default y ---help--- Linux uses the PNPACPI to autodetect built-in diff --git a/drivers/pnp/pnpbios/rsparser.c b/drivers/pnp/pnpbios/rsparser.c index 95b7968..3c2ab83 100644 --- a/drivers/pnp/pnpbios/rsparser.c +++ b/drivers/pnp/pnpbios/rsparser.c @@ -530,7 +530,6 @@ pnpbios_parse_compatible_ids(unsigned ch dev_id = kzalloc(sizeof (struct pnp_id), GFP_KERNEL); if (!dev_id) return NULL; - memset(dev_id, 0, sizeof(struct pnp_id)); pnpid32_to_pnpid(p[1] | p[2] << 8 | p[3] << 16 | p[4] << 24,id); memcpy(&dev_id->id, id, 7); pnp_add_id(dev_id, dev); diff --git a/drivers/pnp/system.c b/drivers/pnp/system.c index d42015c..2065e74 100644 --- a/drivers/pnp/system.c +++ b/drivers/pnp/system.c @@ -3,7 +3,8 @@ * * Some code is based on pnpbios_core.c * Copyright 2002 Adam Belay - * + * (c) Copyright 2007 Hewlett-Packard Development Company, L.P. + * Bjorn Helgaas */ #include @@ -21,18 +22,21 @@ static const struct pnp_device_id pnp_de { "", 0 } }; -static void reserve_ioport_range(char *pnpid, int start, int end) +static void reserve_range(char *pnpid, int start, int end, int port) { struct resource *res; char *regionid; regionid = kmalloc(16, GFP_KERNEL); - if ( regionid == NULL ) + if (regionid == NULL) return; snprintf(regionid, 16, "pnp %s", pnpid); - res = request_region(start,end-start+1,regionid); - if ( res == NULL ) - kfree( regionid ); + if (port) + res = request_region(start,end-start+1,regionid); + else + res = request_mem_region(start,end-start+1,regionid); + if (res == NULL) + kfree(regionid); else res->flags &= ~IORESOURCE_BUSY; /* @@ -41,26 +45,20 @@ static void reserve_ioport_range(char *p * have double reservations. */ printk(KERN_INFO - "pnp: %s: ioport range 0x%x-0x%x %s reserved\n", - pnpid, start, end, - NULL != res ? "has been" : "could not be" - ); - - return; + "pnp: %s: %s range 0x%x-0x%x %s reserved\n", + pnpid, port ? "ioport" : "iomem", start, end, + NULL != res ? "has been" : "could not be"); } -static void reserve_resources_of_dev( struct pnp_dev *dev ) +static void reserve_resources_of_dev(struct pnp_dev *dev) { int i; - for (i=0;idev.bus_id, pnp_port_start(dev, i), + pnp_port_end(dev, i), 1); + } + + for (i = 0; i < PNP_MAX_MEM; i++) { + if (!pnp_mem_valid(dev, i)) continue; - reserve_ioport_range( - dev->dev.bus_id, - pnp_port_start(dev, i), - pnp_port_end(dev, i) - ); + + reserve_range(dev->dev.bus_id, pnp_mem_start(dev, i), + pnp_mem_end(dev, i), 0); } return; diff --git a/drivers/ps3/Makefile b/drivers/ps3/Makefile index 8433eb7..96958c0 100644 --- a/drivers/ps3/Makefile +++ b/drivers/ps3/Makefile @@ -1,2 +1,2 @@ -obj-y += system-bus.o obj-$(CONFIG_PS3_VUART) += vuart.o +obj-$(CONFIG_PS3_PS3AV) += ps3av.o ps3av_cmd.o diff --git a/drivers/ps3/ps3av.c b/drivers/ps3/ps3av.c new file mode 100644 index 0000000..1926b4d --- /dev/null +++ b/drivers/ps3/ps3av.c @@ -0,0 +1,974 @@ +/* + * Copyright (C) 2006 Sony Computer Entertainment Inc. + * Copyright 2006, 2007 Sony Corporation + * + * AV backend support for PS3 + * + * 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. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "vuart.h" + +#define BUFSIZE 4096 /* vuart buf size */ +#define PS3AV_BUF_SIZE 512 /* max packet size */ + +static int timeout = 5000; /* in msec ( 5 sec ) */ +module_param(timeout, int, 0644); + +static struct ps3av ps3av; + +static struct ps3_vuart_port_device ps3av_dev = { + .match_id = PS3_MATCH_ID_AV_SETTINGS +}; + +/* color space */ +#define YUV444 PS3AV_CMD_VIDEO_CS_YUV444_8 +#define RGB8 PS3AV_CMD_VIDEO_CS_RGB_8 +/* format */ +#define XRGB PS3AV_CMD_VIDEO_FMT_X8R8G8B8 +/* aspect */ +#define A_N PS3AV_CMD_AV_ASPECT_4_3 +#define A_W PS3AV_CMD_AV_ASPECT_16_9 +static const struct avset_video_mode { + u32 cs; + u32 fmt; + u32 vid; + u32 aspect; + u32 x; + u32 y; + u32 interlace; + u32 freq; +} video_mode_table[] = { + { 0, }, /* auto */ + {YUV444, XRGB, PS3AV_CMD_VIDEO_VID_480I, A_N, 720, 480, 1, 60}, + {YUV444, XRGB, PS3AV_CMD_VIDEO_VID_480P, A_N, 720, 480, 0, 60}, + {YUV444, XRGB, PS3AV_CMD_VIDEO_VID_720P_60HZ, A_N, 1280, 720, 0, 60}, + {YUV444, XRGB, PS3AV_CMD_VIDEO_VID_1080I_60HZ, A_W, 1920, 1080, 1, 60}, + {YUV444, XRGB, PS3AV_CMD_VIDEO_VID_1080P_60HZ, A_W, 1920, 1080, 0, 60}, + {YUV444, XRGB, PS3AV_CMD_VIDEO_VID_576I, A_N, 720, 576, 1, 50}, + {YUV444, XRGB, PS3AV_CMD_VIDEO_VID_576P, A_N, 720, 576, 0, 50}, + {YUV444, XRGB, PS3AV_CMD_VIDEO_VID_720P_50HZ, A_N, 1280, 720, 0, 50}, + {YUV444, XRGB, PS3AV_CMD_VIDEO_VID_1080I_50HZ, A_W, 1920, 1080, 1, 50}, + {YUV444, XRGB, PS3AV_CMD_VIDEO_VID_1080P_50HZ, A_W, 1920, 1080, 0, 50}, + { RGB8, XRGB, PS3AV_CMD_VIDEO_VID_WXGA, A_W, 1280, 768, 0, 60}, + { RGB8, XRGB, PS3AV_CMD_VIDEO_VID_SXGA, A_N, 1280, 1024, 0, 60}, + { RGB8, XRGB, PS3AV_CMD_VIDEO_VID_WUXGA, A_W, 1920, 1200, 0, 60}, +}; + +/* supported CIDs */ +static u32 cmd_table[] = { + /* init */ + PS3AV_CID_AV_INIT, + PS3AV_CID_AV_FIN, + PS3AV_CID_VIDEO_INIT, + PS3AV_CID_AUDIO_INIT, + + /* set */ + PS3AV_CID_AV_ENABLE_EVENT, + PS3AV_CID_AV_DISABLE_EVENT, + + PS3AV_CID_AV_VIDEO_CS, + PS3AV_CID_AV_VIDEO_MUTE, + PS3AV_CID_AV_VIDEO_DISABLE_SIG, + PS3AV_CID_AV_AUDIO_PARAM, + PS3AV_CID_AV_AUDIO_MUTE, + PS3AV_CID_AV_HDMI_MODE, + PS3AV_CID_AV_TV_MUTE, + + PS3AV_CID_VIDEO_MODE, + PS3AV_CID_VIDEO_FORMAT, + PS3AV_CID_VIDEO_PITCH, + + PS3AV_CID_AUDIO_MODE, + PS3AV_CID_AUDIO_MUTE, + PS3AV_CID_AUDIO_ACTIVE, + PS3AV_CID_AUDIO_INACTIVE, + PS3AV_CID_AVB_PARAM, + + /* get */ + PS3AV_CID_AV_GET_HW_CONF, + PS3AV_CID_AV_GET_MONITOR_INFO, + + /* event */ + PS3AV_CID_EVENT_UNPLUGGED, + PS3AV_CID_EVENT_PLUGGED, + PS3AV_CID_EVENT_HDCP_DONE, + PS3AV_CID_EVENT_HDCP_FAIL, + PS3AV_CID_EVENT_HDCP_AUTH, + PS3AV_CID_EVENT_HDCP_ERROR, + + 0 +}; + +#define PS3AV_EVENT_CMD_MASK 0x10000000 +#define PS3AV_EVENT_ID_MASK 0x0000ffff +#define PS3AV_CID_MASK 0xffffffff +#define PS3AV_REPLY_BIT 0x80000000 + +#define ps3av_event_get_port_id(cid) ((cid >> 16) & 0xff) + +static u32 *ps3av_search_cmd_table(u32 cid, u32 mask) +{ + u32 *table; + int i; + + table = cmd_table; + for (i = 0;; table++, i++) { + if ((*table & mask) == (cid & mask)) + break; + if (*table == 0) + return NULL; + } + return table; +} + +static int ps3av_parse_event_packet(const struct ps3av_reply_hdr *hdr) +{ + u32 *table; + + if (hdr->cid & PS3AV_EVENT_CMD_MASK) { + table = ps3av_search_cmd_table(hdr->cid, PS3AV_EVENT_CMD_MASK); + if (table) + dev_dbg(&ps3av_dev.core, + "recv event packet cid:%08x port:0x%x size:%d\n", + hdr->cid, ps3av_event_get_port_id(hdr->cid), + hdr->size); + else + printk(KERN_ERR + "%s: failed event packet, cid:%08x size:%d\n", + __FUNCTION__, hdr->cid, hdr->size); + return 1; /* receive event packet */ + } + return 0; +} + +static int ps3av_send_cmd_pkt(const struct ps3av_send_hdr *send_buf, + struct ps3av_reply_hdr *recv_buf, int write_len, + int read_len) +{ + int res; + u32 cmd; + int event; + + if (!ps3av.available) + return -ENODEV; + + /* send pkt */ + res = ps3av_vuart_write(ps3av.dev, send_buf, write_len); + if (res < 0) { + dev_dbg(&ps3av_dev.core, + "%s: ps3av_vuart_write() failed (result=%d)\n", + __FUNCTION__, res); + return res; + } + + /* recv pkt */ + cmd = send_buf->cid; + do { + /* read header */ + res = ps3av_vuart_read(ps3av.dev, recv_buf, PS3AV_HDR_SIZE, + timeout); + if (res != PS3AV_HDR_SIZE) { + dev_dbg(&ps3av_dev.core, + "%s: ps3av_vuart_read() failed (result=%d)\n", + __FUNCTION__, res); + return res; + } + + /* read body */ + res = ps3av_vuart_read(ps3av.dev, &recv_buf->cid, + recv_buf->size, timeout); + if (res < 0) { + dev_dbg(&ps3av_dev.core, + "%s: ps3av_vuart_read() failed (result=%d)\n", + __FUNCTION__, res); + return res; + } + res += PS3AV_HDR_SIZE; /* total len */ + event = ps3av_parse_event_packet(recv_buf); + /* ret > 0 event packet */ + } while (event); + + if ((cmd | PS3AV_REPLY_BIT) != recv_buf->cid) { + dev_dbg(&ps3av_dev.core, "%s: reply err (result=%x)\n", + __FUNCTION__, recv_buf->cid); + return -EINVAL; + } + + return 0; +} + +static int ps3av_process_reply_packet(struct ps3av_send_hdr *cmd_buf, + const struct ps3av_reply_hdr *recv_buf, + int user_buf_size) +{ + int return_len; + + if (recv_buf->version != PS3AV_VERSION) { + dev_dbg(&ps3av_dev.core, "reply_packet invalid version:%x\n", + recv_buf->version); + return -EFAULT; + } + return_len = recv_buf->size + PS3AV_HDR_SIZE; + if (return_len > user_buf_size) + return_len = user_buf_size; + memcpy(cmd_buf, recv_buf, return_len); + return 0; /* success */ +} + +void ps3av_set_hdr(u32 cid, u16 size, struct ps3av_send_hdr *hdr) +{ + hdr->version = PS3AV_VERSION; + hdr->size = size - PS3AV_HDR_SIZE; + hdr->cid = cid; +} + +int ps3av_do_pkt(u32 cid, u16 send_len, size_t usr_buf_size, + struct ps3av_send_hdr *buf) +{ + int res = 0; + union { + struct ps3av_reply_hdr reply_hdr; + u8 raw[PS3AV_BUF_SIZE]; + } recv_buf; + + u32 *table; + + BUG_ON(!ps3av.available); + + if (down_interruptible(&ps3av.sem)) + return -ERESTARTSYS; + + table = ps3av_search_cmd_table(cid, PS3AV_CID_MASK); + BUG_ON(!table); + BUG_ON(send_len < PS3AV_HDR_SIZE); + BUG_ON(usr_buf_size < send_len); + BUG_ON(usr_buf_size > PS3AV_BUF_SIZE); + + /* create header */ + ps3av_set_hdr(cid, send_len, buf); + + /* send packet via vuart */ + res = ps3av_send_cmd_pkt(buf, &recv_buf.reply_hdr, send_len, + usr_buf_size); + if (res < 0) { + printk(KERN_ERR + "%s: ps3av_send_cmd_pkt() failed (result=%d)\n", + __FUNCTION__, res); + goto err; + } + + /* process reply packet */ + res = ps3av_process_reply_packet(buf, &recv_buf.reply_hdr, + usr_buf_size); + if (res < 0) { + printk(KERN_ERR "%s: put_return_status() failed (result=%d)\n", + __FUNCTION__, res); + goto err; + } + + up(&ps3av.sem); + return 0; + + err: + up(&ps3av.sem); + printk(KERN_ERR "%s: failed cid:%x res:%d\n", __FUNCTION__, cid, res); + return res; +} + +static int ps3av_set_av_video_mute(u32 mute) +{ + int i, num_of_av_port, res; + + num_of_av_port = ps3av.av_hw_conf.num_of_hdmi + + ps3av.av_hw_conf.num_of_avmulti; + /* video mute on */ + for (i = 0; i < num_of_av_port; i++) { + res = ps3av_cmd_av_video_mute(1, &ps3av.av_port[i], mute); + if (res < 0) + return -1; + } + + return 0; +} + +static int ps3av_set_video_disable_sig(void) +{ + int i, num_of_hdmi_port, num_of_av_port, res; + + num_of_hdmi_port = ps3av.av_hw_conf.num_of_hdmi; + num_of_av_port = ps3av.av_hw_conf.num_of_hdmi + + ps3av.av_hw_conf.num_of_avmulti; + + /* tv mute */ + for (i = 0; i < num_of_hdmi_port; i++) { + res = ps3av_cmd_av_tv_mute(ps3av.av_port[i], + PS3AV_CMD_MUTE_ON); + if (res < 0) + return -1; + } + msleep(100); + + /* video mute on */ + for (i = 0; i < num_of_av_port; i++) { + res = ps3av_cmd_av_video_disable_sig(ps3av.av_port[i]); + if (res < 0) + return -1; + if (i < num_of_hdmi_port) { + res = ps3av_cmd_av_tv_mute(ps3av.av_port[i], + PS3AV_CMD_MUTE_OFF); + if (res < 0) + return -1; + } + } + msleep(300); + + return 0; +} + +static int ps3av_set_audio_mute(u32 mute) +{ + int i, num_of_av_port, num_of_opt_port, res; + + num_of_av_port = ps3av.av_hw_conf.num_of_hdmi + + ps3av.av_hw_conf.num_of_avmulti; + num_of_opt_port = ps3av.av_hw_conf.num_of_spdif; + + for (i = 0; i < num_of_av_port; i++) { + res = ps3av_cmd_av_audio_mute(1, &ps3av.av_port[i], mute); + if (res < 0) + return -1; + } + for (i = 0; i < num_of_opt_port; i++) { + res = ps3av_cmd_audio_mute(1, &ps3av.opt_port[i], mute); + if (res < 0) + return -1; + } + + return 0; +} + +int ps3av_set_audio_mode(u32 ch, u32 fs, u32 word_bits, u32 format, u32 source) +{ + struct ps3av_pkt_avb_param avb_param; + int i, num_of_audio, vid, res; + struct ps3av_pkt_audio_mode audio_mode; + u32 len = 0; + + num_of_audio = ps3av.av_hw_conf.num_of_hdmi + + ps3av.av_hw_conf.num_of_avmulti + + ps3av.av_hw_conf.num_of_spdif; + + avb_param.num_of_video_pkt = 0; + avb_param.num_of_audio_pkt = PS3AV_AVB_NUM_AUDIO; /* always 0 */ + avb_param.num_of_av_video_pkt = 0; + avb_param.num_of_av_audio_pkt = ps3av.av_hw_conf.num_of_hdmi; + + vid = video_mode_table[ps3av.ps3av_mode].vid; + + /* audio mute */ + ps3av_set_audio_mute(PS3AV_CMD_MUTE_ON); + + /* audio inactive */ + res = ps3av_cmd_audio_active(0, ps3av.audio_port); + if (res < 0) + dev_dbg(&ps3av_dev.core, + "ps3av_cmd_audio_active OFF failed\n"); + + /* audio_pkt */ + for (i = 0; i < num_of_audio; i++) { + ps3av_cmd_set_audio_mode(&audio_mode, ps3av.av_port[i], ch, fs, + word_bits, format, source); + if (i < ps3av.av_hw_conf.num_of_hdmi) { + /* hdmi only */ + len += ps3av_cmd_set_av_audio_param(&avb_param.buf[len], + ps3av.av_port[i], + &audio_mode, vid); + } + /* audio_mode pkt should be sent separately */ + res = ps3av_cmd_audio_mode(&audio_mode); + if (res < 0) + dev_dbg(&ps3av_dev.core, + "ps3av_cmd_audio_mode failed, port:%x\n", i); + } + + /* send command using avb pkt */ + len += offsetof(struct ps3av_pkt_avb_param, buf); + res = ps3av_cmd_avb_param(&avb_param, len); + if (res < 0) + dev_dbg(&ps3av_dev.core, "ps3av_cmd_avb_param failed\n"); + + /* audio mute */ + ps3av_set_audio_mute(PS3AV_CMD_MUTE_OFF); + + /* audio active */ + res = ps3av_cmd_audio_active(1, ps3av.audio_port); + if (res < 0) + dev_dbg(&ps3av_dev.core, "ps3av_cmd_audio_active ON failed\n"); + + return 0; +} + +EXPORT_SYMBOL_GPL(ps3av_set_audio_mode); + +static int ps3av_set_videomode(void) +{ + /* av video mute */ + ps3av_set_av_video_mute(PS3AV_CMD_MUTE_ON); + + /* wake up ps3avd to do the actual video mode setting */ + up(&ps3av.ping); + + return 0; +} + +static void ps3av_set_videomode_cont(u32 id, u32 old_id) +{ + struct ps3av_pkt_avb_param avb_param; + int i; + u32 len = 0, av_video_cs; + const struct avset_video_mode *video_mode; + int res; + + video_mode = &video_mode_table[id & PS3AV_MODE_MASK]; + + avb_param.num_of_video_pkt = PS3AV_AVB_NUM_VIDEO; /* num of head */ + avb_param.num_of_audio_pkt = 0; + avb_param.num_of_av_video_pkt = ps3av.av_hw_conf.num_of_hdmi + + ps3av.av_hw_conf.num_of_avmulti; + avb_param.num_of_av_audio_pkt = 0; + + /* video signal off */ + ps3av_set_video_disable_sig(); + + /* Retail PS3 product doesn't support this */ + if (id & PS3AV_MODE_HDCP_OFF) { + res = ps3av_cmd_av_hdmi_mode(PS3AV_CMD_AV_HDMI_HDCP_OFF); + if (res == PS3AV_STATUS_UNSUPPORTED_HDMI_MODE) + dev_dbg(&ps3av_dev.core, "Not supported\n"); + else if (res) + dev_dbg(&ps3av_dev.core, + "ps3av_cmd_av_hdmi_mode failed\n"); + } else if (old_id & PS3AV_MODE_HDCP_OFF) { + res = ps3av_cmd_av_hdmi_mode(PS3AV_CMD_AV_HDMI_MODE_NORMAL); + if (res < 0 && res != PS3AV_STATUS_UNSUPPORTED_HDMI_MODE) + dev_dbg(&ps3av_dev.core, + "ps3av_cmd_av_hdmi_mode failed\n"); + } + + /* video_pkt */ + for (i = 0; i < avb_param.num_of_video_pkt; i++) + len += ps3av_cmd_set_video_mode(&avb_param.buf[len], + ps3av.head[i], video_mode->vid, + video_mode->fmt, id); + /* av_video_pkt */ + for (i = 0; i < avb_param.num_of_av_video_pkt; i++) { + if (id & PS3AV_MODE_DVI || id & PS3AV_MODE_RGB) + av_video_cs = RGB8; + else + av_video_cs = video_mode->cs; +#ifndef PS3AV_HDMI_YUV + if (ps3av.av_port[i] == PS3AV_CMD_AVPORT_HDMI_0 || + ps3av.av_port[i] == PS3AV_CMD_AVPORT_HDMI_1) + av_video_cs = RGB8; /* use RGB for HDMI */ +#endif + len += ps3av_cmd_set_av_video_cs(&avb_param.buf[len], + ps3av.av_port[i], + video_mode->vid, av_video_cs, + video_mode->aspect, id); + } + /* send command using avb pkt */ + len += offsetof(struct ps3av_pkt_avb_param, buf); + res = ps3av_cmd_avb_param(&avb_param, len); + if (res == PS3AV_STATUS_NO_SYNC_HEAD) + printk(KERN_WARNING + "%s: Command failed. Please try your request again. \n", + __FUNCTION__); + else if (res) + dev_dbg(&ps3av_dev.core, "ps3av_cmd_avb_param failed\n"); + + msleep(1500); + /* av video mute */ + ps3av_set_av_video_mute(PS3AV_CMD_MUTE_OFF); +} + +static int ps3avd(void *p) +{ + struct ps3av *info = p; + + daemonize("ps3avd"); + while (1) { + down(&info->ping); + ps3av_set_videomode_cont(info->ps3av_mode, + info->ps3av_mode_old); + up(&info->pong); + } + return 0; +} + +static int ps3av_vid2table_id(int vid) +{ + int i; + + for (i = 1; i < ARRAY_SIZE(video_mode_table); i++) + if (video_mode_table[i].vid == vid) + return i; + return -1; +} + +static int ps3av_resbit2vid(u32 res_50, u32 res_60) +{ + int vid = -1; + + if (res_50 > res_60) { /* if res_50 == res_60, res_60 will be used */ + if (res_50 & PS3AV_RESBIT_1920x1080P) + vid = PS3AV_CMD_VIDEO_VID_1080P_50HZ; + else if (res_50 & PS3AV_RESBIT_1920x1080I) + vid = PS3AV_CMD_VIDEO_VID_1080I_50HZ; + else if (res_50 & PS3AV_RESBIT_1280x720P) + vid = PS3AV_CMD_VIDEO_VID_720P_50HZ; + else if (res_50 & PS3AV_RESBIT_720x576P) + vid = PS3AV_CMD_VIDEO_VID_576P; + else + vid = -1; + } else { + if (res_60 & PS3AV_RESBIT_1920x1080P) + vid = PS3AV_CMD_VIDEO_VID_1080P_60HZ; + else if (res_60 & PS3AV_RESBIT_1920x1080I) + vid = PS3AV_CMD_VIDEO_VID_1080I_60HZ; + else if (res_60 & PS3AV_RESBIT_1280x720P) + vid = PS3AV_CMD_VIDEO_VID_720P_60HZ; + else if (res_60 & PS3AV_RESBIT_720x480P) + vid = PS3AV_CMD_VIDEO_VID_480P; + else + vid = -1; + } + return vid; +} + +static int ps3av_hdmi_get_vid(struct ps3av_info_monitor *info) +{ + u32 res_50, res_60; + int vid = -1; + + if (info->monitor_type != PS3AV_MONITOR_TYPE_HDMI) + return -1; + + /* check native resolution */ + res_50 = info->res_50.native & PS3AV_RES_MASK_50; + res_60 = info->res_60.native & PS3AV_RES_MASK_60; + if (res_50 || res_60) { + vid = ps3av_resbit2vid(res_50, res_60); + return vid; + } + + /* check resolution */ + res_50 = info->res_50.res_bits & PS3AV_RES_MASK_50; + res_60 = info->res_60.res_bits & PS3AV_RES_MASK_60; + if (res_50 || res_60) { + vid = ps3av_resbit2vid(res_50, res_60); + return vid; + } + + if (ps3av.region & PS3AV_REGION_60) + vid = PS3AV_DEFAULT_HDMI_VID_REG_60; + else + vid = PS3AV_DEFAULT_HDMI_VID_REG_50; + return vid; +} + +static int ps3av_auto_videomode(struct ps3av_pkt_av_get_hw_conf *av_hw_conf, + int boot) +{ + int i, res, vid = -1, dvi = 0, rgb = 0; + struct ps3av_pkt_av_get_monitor_info monitor_info; + struct ps3av_info_monitor *info; + + /* get vid for hdmi */ + for (i = 0; i < av_hw_conf->num_of_hdmi; i++) { + res = ps3av_cmd_video_get_monitor_info(&monitor_info, + PS3AV_CMD_AVPORT_HDMI_0 + + i); + if (res < 0) + return -1; + + ps3av_cmd_av_monitor_info_dump(&monitor_info); + info = &monitor_info.info; + /* check DVI */ + if (info->monitor_type == PS3AV_MONITOR_TYPE_DVI) { + dvi = PS3AV_MODE_DVI; + break; + } + /* check HDMI */ + vid = ps3av_hdmi_get_vid(info); + if (vid != -1) { + /* got valid vid */ + break; + } + } + + if (dvi) { + /* DVI mode */ + vid = PS3AV_DEFAULT_DVI_VID; + } else if (vid == -1) { + /* no HDMI interface or HDMI is off */ + if (ps3av.region & PS3AV_REGION_60) + vid = PS3AV_DEFAULT_AVMULTI_VID_REG_60; + else + vid = PS3AV_DEFAULT_AVMULTI_VID_REG_50; + if (ps3av.region & PS3AV_REGION_RGB) + rgb = PS3AV_MODE_RGB; + } else if (boot) { + /* HDMI: using DEFAULT HDMI_VID while booting up */ + info = &monitor_info.info; + if (ps3av.region & PS3AV_REGION_60) { + if (info->res_60.res_bits & PS3AV_RESBIT_720x480P) + vid = PS3AV_DEFAULT_HDMI_VID_REG_60; + else if (info->res_50.res_bits & PS3AV_RESBIT_720x576P) + vid = PS3AV_DEFAULT_HDMI_VID_REG_50; + else { + /* default */ + vid = PS3AV_DEFAULT_HDMI_VID_REG_60; + } + } else { + if (info->res_50.res_bits & PS3AV_RESBIT_720x576P) + vid = PS3AV_DEFAULT_HDMI_VID_REG_50; + else if (info->res_60.res_bits & PS3AV_RESBIT_720x480P) + vid = PS3AV_DEFAULT_HDMI_VID_REG_60; + else { + /* default */ + vid = PS3AV_DEFAULT_HDMI_VID_REG_50; + } + } + } + + return (ps3av_vid2table_id(vid) | dvi | rgb); +} + +static int ps3av_get_hw_conf(struct ps3av *ps3av) +{ + int i, j, k, res; + + /* get av_hw_conf */ + res = ps3av_cmd_av_get_hw_conf(&ps3av->av_hw_conf); + if (res < 0) + return -1; + + ps3av_cmd_av_hw_conf_dump(&ps3av->av_hw_conf); + + for (i = 0; i < PS3AV_HEAD_MAX; i++) + ps3av->head[i] = PS3AV_CMD_VIDEO_HEAD_A + i; + for (i = 0; i < PS3AV_OPT_PORT_MAX; i++) + ps3av->opt_port[i] = PS3AV_CMD_AVPORT_SPDIF_0 + i; + for (i = 0; i < ps3av->av_hw_conf.num_of_hdmi; i++) + ps3av->av_port[i] = PS3AV_CMD_AVPORT_HDMI_0 + i; + for (j = 0; j < ps3av->av_hw_conf.num_of_avmulti; j++) + ps3av->av_port[i + j] = PS3AV_CMD_AVPORT_AVMULTI_0 + j; + for (k = 0; k < ps3av->av_hw_conf.num_of_spdif; k++) + ps3av->av_port[i + j + k] = PS3AV_CMD_AVPORT_SPDIF_0 + k; + + /* set all audio port */ + ps3av->audio_port = PS3AV_CMD_AUDIO_PORT_HDMI_0 + | PS3AV_CMD_AUDIO_PORT_HDMI_1 + | PS3AV_CMD_AUDIO_PORT_AVMULTI_0 + | PS3AV_CMD_AUDIO_PORT_SPDIF_0 | PS3AV_CMD_AUDIO_PORT_SPDIF_1; + + return 0; +} + +/* set mode using id */ +int ps3av_set_video_mode(u32 id, int boot) +{ + int size; + u32 option; + + size = ARRAY_SIZE(video_mode_table); + if ((id & PS3AV_MODE_MASK) > size - 1 || id < 0) { + dev_dbg(&ps3av_dev.core, "%s: error id :%d\n", __FUNCTION__, + id); + return -EINVAL; + } + + /* auto mode */ + option = id & ~PS3AV_MODE_MASK; + if ((id & PS3AV_MODE_MASK) == 0) { + id = ps3av_auto_videomode(&ps3av.av_hw_conf, boot); + if (id < 1) { + printk(KERN_ERR "%s: invalid id :%d\n", __FUNCTION__, + id); + return -EINVAL; + } + id |= option; + } + + /* set videomode */ + down(&ps3av.pong); + ps3av.ps3av_mode_old = ps3av.ps3av_mode; + ps3av.ps3av_mode = id; + if (ps3av_set_videomode()) + ps3av.ps3av_mode = ps3av.ps3av_mode_old; + + return 0; +} + +EXPORT_SYMBOL_GPL(ps3av_set_video_mode); + +int ps3av_set_mode(u32 id, int boot) +{ + int res; + + res = ps3av_set_video_mode(id, boot); + if (res) + return res; + + res = ps3av_set_audio_mode(PS3AV_CMD_AUDIO_NUM_OF_CH_2, + PS3AV_CMD_AUDIO_FS_48K, + PS3AV_CMD_AUDIO_WORD_BITS_16, + PS3AV_CMD_AUDIO_FORMAT_PCM, + PS3AV_CMD_AUDIO_SOURCE_SERIAL); + if (res) + return res; + + return 0; +} + +EXPORT_SYMBOL_GPL(ps3av_set_mode); + +int ps3av_get_mode(void) +{ + return ps3av.ps3av_mode; +} + +EXPORT_SYMBOL_GPL(ps3av_get_mode); + +int ps3av_get_scanmode(int id) +{ + int size; + + id = id & PS3AV_MODE_MASK; + size = ARRAY_SIZE(video_mode_table); + if (id > size - 1 || id < 0) { + printk(KERN_ERR "%s: invalid mode %d\n", __FUNCTION__, id); + return -EINVAL; + } + return video_mode_table[id].interlace; +} + +EXPORT_SYMBOL_GPL(ps3av_get_scanmode); + +int ps3av_get_refresh_rate(int id) +{ + int size; + + id = id & PS3AV_MODE_MASK; + size = ARRAY_SIZE(video_mode_table); + if (id > size - 1 || id < 0) { + printk(KERN_ERR "%s: invalid mode %d\n", __FUNCTION__, id); + return -EINVAL; + } + return video_mode_table[id].freq; +} + +EXPORT_SYMBOL_GPL(ps3av_get_refresh_rate); + +/* get resolution by video_mode */ +int ps3av_video_mode2res(u32 id, u32 *xres, u32 *yres) +{ + int size; + + id = id & PS3AV_MODE_MASK; + size = ARRAY_SIZE(video_mode_table); + if (id > size - 1 || id < 0) { + printk(KERN_ERR "%s: invalid mode %d\n", __FUNCTION__, id); + return -EINVAL; + } + *xres = video_mode_table[id].x; + *yres = video_mode_table[id].y; + return 0; +} + +EXPORT_SYMBOL_GPL(ps3av_video_mode2res); + +/* mute */ +int ps3av_video_mute(int mute) +{ + return ps3av_set_av_video_mute(mute ? PS3AV_CMD_MUTE_ON + : PS3AV_CMD_MUTE_OFF); +} + +EXPORT_SYMBOL_GPL(ps3av_video_mute); + +int ps3av_audio_mute(int mute) +{ + return ps3av_set_audio_mute(mute ? PS3AV_CMD_MUTE_ON + : PS3AV_CMD_MUTE_OFF); +} + +EXPORT_SYMBOL_GPL(ps3av_audio_mute); + +int ps3av_dev_open(void) +{ + int status = 0; + + mutex_lock(&ps3av.mutex); + if (!ps3av.open_count++) { + status = lv1_gpu_open(0); + if (status) { + printk(KERN_ERR "%s: lv1_gpu_open failed %d\n", + __FUNCTION__, status); + ps3av.open_count--; + } + } + mutex_unlock(&ps3av.mutex); + + return status; +} + +EXPORT_SYMBOL_GPL(ps3av_dev_open); + +int ps3av_dev_close(void) +{ + int status = 0; + + mutex_lock(&ps3av.mutex); + if (ps3av.open_count <= 0) { + printk(KERN_ERR "%s: GPU already closed\n", __FUNCTION__); + status = -1; + } else if (!--ps3av.open_count) { + status = lv1_gpu_close(); + if (status) + printk(KERN_WARNING "%s: lv1_gpu_close failed %d\n", + __FUNCTION__, status); + } + mutex_unlock(&ps3av.mutex); + + return status; +} + +EXPORT_SYMBOL_GPL(ps3av_dev_close); + +static int ps3av_probe(struct ps3_vuart_port_device *dev) +{ + int res; + u32 id; + + dev_dbg(&ps3av_dev.core, "init ...\n"); + dev_dbg(&ps3av_dev.core, " timeout=%d\n", timeout); + + memset(&ps3av, 0, sizeof(ps3av)); + + init_MUTEX(&ps3av.sem); + init_MUTEX_LOCKED(&ps3av.ping); + init_MUTEX(&ps3av.pong); + mutex_init(&ps3av.mutex); + ps3av.ps3av_mode = 0; + ps3av.dev = dev; + kernel_thread(ps3avd, &ps3av, CLONE_KERNEL); + + ps3av.available = 1; + switch (ps3_os_area_get_av_multi_out()) { + case PS3_PARAM_AV_MULTI_OUT_NTSC: + ps3av.region = PS3AV_REGION_60; + break; + case PS3_PARAM_AV_MULTI_OUT_PAL_YCBCR: + case PS3_PARAM_AV_MULTI_OUT_SECAM: + ps3av.region = PS3AV_REGION_50; + break; + case PS3_PARAM_AV_MULTI_OUT_PAL_RGB: + ps3av.region = PS3AV_REGION_50 | PS3AV_REGION_RGB; + break; + default: + ps3av.region = PS3AV_REGION_60; + break; + } + + /* init avsetting modules */ + res = ps3av_cmd_init(); + if (res < 0) + printk(KERN_ERR "%s: ps3av_cmd_init failed %d\n", __FUNCTION__, + res); + + ps3av_get_hw_conf(&ps3av); + id = ps3av_auto_videomode(&ps3av.av_hw_conf, 1); + mutex_lock(&ps3av.mutex); + ps3av.ps3av_mode = id; + mutex_unlock(&ps3av.mutex); + + dev_dbg(&ps3av_dev.core, "init...done\n"); + + return 0; +} + +static int ps3av_remove(struct ps3_vuart_port_device *dev) +{ + if (ps3av.available) { + ps3av_cmd_fin(); + ps3av.available = 0; + } + + return 0; +} + +static void ps3av_shutdown(struct ps3_vuart_port_device *dev) +{ + ps3av_remove(dev); +} + +static struct ps3_vuart_port_driver ps3av_driver = { + .match_id = PS3_MATCH_ID_AV_SETTINGS, + .core = { + .name = "ps3_av", + }, + .probe = ps3av_probe, + .remove = ps3av_remove, + .shutdown = ps3av_shutdown, +}; + +static int ps3av_module_init(void) +{ + int error = ps3_vuart_port_driver_register(&ps3av_driver); + if (error) { + printk(KERN_ERR + "%s: ps3_vuart_port_driver_register failed %d\n", + __FUNCTION__, error); + return error; + } + + error = ps3_vuart_port_device_register(&ps3av_dev); + if (error) + printk(KERN_ERR + "%s: ps3_vuart_port_device_register failed %d\n", + __FUNCTION__, error); + + return error; +} + +static void __exit ps3av_module_exit(void) +{ + device_unregister(&ps3av_dev.core); + ps3_vuart_port_driver_unregister(&ps3av_driver); +} + +subsys_initcall(ps3av_module_init); +module_exit(ps3av_module_exit); diff --git a/drivers/ps3/ps3av_cmd.c b/drivers/ps3/ps3av_cmd.c new file mode 100644 index 0000000..21c97c8 --- /dev/null +++ b/drivers/ps3/ps3av_cmd.c @@ -0,0 +1,1020 @@ +/* + * Copyright (C) 2006 Sony Computer Entertainment Inc. + * Copyright 2006, 2007 Sony Corporation + * + * AV backend support for PS3 + * + * 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. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#include +#include +#include +#include +#include +#include + +#include "vuart.h" + +static const struct video_fmt { + u32 format; + u32 order; +} ps3av_video_fmt_table[] = { + { PS3AV_CMD_VIDEO_FORMAT_ARGB_8BIT, PS3AV_CMD_VIDEO_ORDER_RGB }, + { PS3AV_CMD_VIDEO_FORMAT_ARGB_8BIT, PS3AV_CMD_VIDEO_ORDER_BGR }, +}; + +static const struct { + int cs; + u32 av; + u32 bl; +} ps3av_cs_video2av_table[] = { + { + .cs = PS3AV_CMD_VIDEO_CS_RGB_8, + .av = PS3AV_CMD_AV_CS_RGB_8, + .bl = PS3AV_CMD_AV_CS_8 + }, { + .cs = PS3AV_CMD_VIDEO_CS_RGB_10, + .av = PS3AV_CMD_AV_CS_RGB_8, + .bl = PS3AV_CMD_AV_CS_8 + }, { + .cs = PS3AV_CMD_VIDEO_CS_RGB_12, + .av = PS3AV_CMD_AV_CS_RGB_8, + .bl = PS3AV_CMD_AV_CS_8 + }, { + .cs = PS3AV_CMD_VIDEO_CS_YUV444_8, + .av = PS3AV_CMD_AV_CS_YUV444_8, + .bl = PS3AV_CMD_AV_CS_8 + }, { + .cs = PS3AV_CMD_VIDEO_CS_YUV444_10, + .av = PS3AV_CMD_AV_CS_YUV444_8, + .bl = PS3AV_CMD_AV_CS_10 + }, { + .cs = PS3AV_CMD_VIDEO_CS_YUV444_12, + .av = PS3AV_CMD_AV_CS_YUV444_8, + .bl = PS3AV_CMD_AV_CS_10 + }, { + .cs = PS3AV_CMD_VIDEO_CS_YUV422_8, + .av = PS3AV_CMD_AV_CS_YUV422_8, + .bl = PS3AV_CMD_AV_CS_10 + }, { + .cs = PS3AV_CMD_VIDEO_CS_YUV422_10, + .av = PS3AV_CMD_AV_CS_YUV422_8, + .bl = PS3AV_CMD_AV_CS_10 + }, { + .cs = PS3AV_CMD_VIDEO_CS_YUV422_12, + .av = PS3AV_CMD_AV_CS_YUV422_8, + .bl = PS3AV_CMD_AV_CS_12 + }, { + .cs = PS3AV_CMD_VIDEO_CS_XVYCC_8, + .av = PS3AV_CMD_AV_CS_XVYCC_8, + .bl = PS3AV_CMD_AV_CS_12 + }, { + .cs = PS3AV_CMD_VIDEO_CS_XVYCC_10, + .av = PS3AV_CMD_AV_CS_XVYCC_8, + .bl = PS3AV_CMD_AV_CS_12 + }, { + .cs = PS3AV_CMD_VIDEO_CS_XVYCC_12, + .av = PS3AV_CMD_AV_CS_XVYCC_8, + .bl = PS3AV_CMD_AV_CS_12 + } +}; + +static u32 ps3av_cs_video2av(int cs) +{ + unsigned int i; + + for (i = 0; i < ARRAY_SIZE(ps3av_cs_video2av_table); i++) + if (ps3av_cs_video2av_table[i].cs == cs) + return ps3av_cs_video2av_table[i].av; + + return PS3AV_CMD_AV_CS_RGB_8; +} + +static u32 ps3av_cs_video2av_bitlen(int cs) +{ + unsigned int i; + + for (i = 0; i < ARRAY_SIZE(ps3av_cs_video2av_table); i++) + if (ps3av_cs_video2av_table[i].cs == cs) + return ps3av_cs_video2av_table[i].bl; + + return PS3AV_CMD_AV_CS_8; +} + +static const struct { + int vid; + u32 av; +} ps3av_vid_video2av_table[] = { + { PS3AV_CMD_VIDEO_VID_480I, PS3AV_CMD_AV_VID_480I }, + { PS3AV_CMD_VIDEO_VID_480P, PS3AV_CMD_AV_VID_480P }, + { PS3AV_CMD_VIDEO_VID_576I, PS3AV_CMD_AV_VID_576I }, + { PS3AV_CMD_VIDEO_VID_576P, PS3AV_CMD_AV_VID_576P }, + { PS3AV_CMD_VIDEO_VID_1080I_60HZ, PS3AV_CMD_AV_VID_1080I_60HZ }, + { PS3AV_CMD_VIDEO_VID_720P_60HZ, PS3AV_CMD_AV_VID_720P_60HZ }, + { PS3AV_CMD_VIDEO_VID_1080P_60HZ, PS3AV_CMD_AV_VID_1080P_60HZ }, + { PS3AV_CMD_VIDEO_VID_1080I_50HZ, PS3AV_CMD_AV_VID_1080I_50HZ }, + { PS3AV_CMD_VIDEO_VID_720P_50HZ, PS3AV_CMD_AV_VID_720P_50HZ }, + { PS3AV_CMD_VIDEO_VID_1080P_50HZ, PS3AV_CMD_AV_VID_1080P_50HZ }, + { PS3AV_CMD_VIDEO_VID_WXGA, PS3AV_CMD_AV_VID_WXGA }, + { PS3AV_CMD_VIDEO_VID_SXGA, PS3AV_CMD_AV_VID_SXGA }, + { PS3AV_CMD_VIDEO_VID_WUXGA, PS3AV_CMD_AV_VID_WUXGA } +}; + +static u32 ps3av_vid_video2av(int vid) +{ + unsigned int i; + + for (i = 0; i < ARRAY_SIZE(ps3av_vid_video2av_table); i++) + if (ps3av_vid_video2av_table[i].vid == vid) + return ps3av_vid_video2av_table[i].av; + + return PS3AV_CMD_AV_VID_480P; +} + +int ps3av_cmd_init(void) +{ + int res; + struct ps3av_pkt_av_init av_init; + struct ps3av_pkt_video_init video_init; + struct ps3av_pkt_audio_init audio_init; + + /* video init */ + memset(&video_init, 0, sizeof(video_init)); + + res = ps3av_do_pkt(PS3AV_CID_VIDEO_INIT, sizeof(video_init.send_hdr), + sizeof(video_init), &video_init.send_hdr); + if (res < 0) + return res; + + res = get_status(&video_init); + if (res) { + printk(KERN_ERR "PS3AV_CID_VIDEO_INIT: failed %x\n", res); + return res; + } + + /* audio init */ + memset(&audio_init, 0, sizeof(audio_init)); + + res = ps3av_do_pkt(PS3AV_CID_AUDIO_INIT, sizeof(audio_init.send_hdr), + sizeof(audio_init), &audio_init.send_hdr); + if (res < 0) + return res; + + res = get_status(&audio_init); + if (res) { + printk(KERN_ERR "PS3AV_CID_AUDIO_INIT: failed %x\n", res); + return res; + } + + /* av init */ + memset(&av_init, 0, sizeof(av_init)); + av_init.event_bit = 0; + + res = ps3av_do_pkt(PS3AV_CID_AV_INIT, sizeof(av_init), sizeof(av_init), + &av_init.send_hdr); + if (res < 0) + return res; + + res = get_status(&av_init); + if (res) + printk(KERN_ERR "PS3AV_CID_AV_INIT: failed %x\n", res); + + return res; +} + +int ps3av_cmd_fin(void) +{ + int res; + struct ps3av_pkt_av_fin av_fin; + + memset(&av_fin, 0, sizeof(av_fin)); + + res = ps3av_do_pkt(PS3AV_CID_AV_FIN, sizeof(av_fin.send_hdr), + sizeof(av_fin), &av_fin.send_hdr); + if (res < 0) + return res; + + res = get_status(&av_fin); + if (res) + printk(KERN_ERR "PS3AV_CID_AV_FIN: failed %x\n", res); + + return res; +} + +int ps3av_cmd_av_video_mute(int num_of_port, u32 *port, u32 mute) +{ + int i, send_len, res; + struct ps3av_pkt_av_video_mute av_video_mute; + + if (num_of_port > PS3AV_MUTE_PORT_MAX) + return -EINVAL; + + memset(&av_video_mute, 0, sizeof(av_video_mute)); + for (i = 0; i < num_of_port; i++) { + av_video_mute.mute[i].avport = port[i]; + av_video_mute.mute[i].mute = mute; + } + + send_len = sizeof(av_video_mute.send_hdr) + + sizeof(struct ps3av_av_mute) * num_of_port; + res = ps3av_do_pkt(PS3AV_CID_AV_VIDEO_MUTE, send_len, + sizeof(av_video_mute), &av_video_mute.send_hdr); + if (res < 0) + return res; + + res = get_status(&av_video_mute); + if (res) + printk(KERN_ERR "PS3AV_CID_AV_VIDEO_MUTE: failed %x\n", res); + + return res; +} + +int ps3av_cmd_av_video_disable_sig(u32 port) +{ + int res; + struct ps3av_pkt_av_video_disable_sig av_video_sig; + + memset(&av_video_sig, 0, sizeof(av_video_sig)); + av_video_sig.avport = port; + + res = ps3av_do_pkt(PS3AV_CID_AV_VIDEO_DISABLE_SIG, + sizeof(av_video_sig), sizeof(av_video_sig), + &av_video_sig.send_hdr); + if (res < 0) + return res; + + res = get_status(&av_video_sig); + if (res) + printk(KERN_ERR + "PS3AV_CID_AV_VIDEO_DISABLE_SIG: failed %x port:%x\n", + res, port); + + return res; +} + +int ps3av_cmd_av_tv_mute(u32 avport, u32 mute) +{ + int res; + struct ps3av_pkt_av_tv_mute tv_mute; + + memset(&tv_mute, 0, sizeof(tv_mute)); + tv_mute.avport = avport; + tv_mute.mute = mute; + + res = ps3av_do_pkt(PS3AV_CID_AV_TV_MUTE, sizeof(tv_mute), + sizeof(tv_mute), &tv_mute.send_hdr); + if (res < 0) + return res; + + res = get_status(&tv_mute); + if (res) + printk(KERN_ERR "PS3AV_CID_AV_TV_MUTE: failed %x port:%x\n", + res, avport); + + return res; +} + +int ps3av_cmd_enable_event(void) +{ + int res; + struct ps3av_pkt_av_event av_event; + + memset(&av_event, 0, sizeof(av_event)); + av_event.event_bit = PS3AV_CMD_EVENT_BIT_UNPLUGGED | + PS3AV_CMD_EVENT_BIT_PLUGGED | PS3AV_CMD_EVENT_BIT_HDCP_DONE; + + res = ps3av_do_pkt(PS3AV_CID_AV_ENABLE_EVENT, sizeof(av_event), + sizeof(av_event), &av_event.send_hdr); + if (res < 0) + return res; + + res = get_status(&av_event); + if (res) + printk(KERN_ERR "PS3AV_CID_AV_ENABLE_EVENT: failed %x\n", res); + + return res; +} + +int ps3av_cmd_av_hdmi_mode(u8 mode) +{ + int res; + struct ps3av_pkt_av_hdmi_mode hdmi_mode; + + memset(&hdmi_mode, 0, sizeof(hdmi_mode)); + hdmi_mode.mode = mode; + + res = ps3av_do_pkt(PS3AV_CID_AV_HDMI_MODE, sizeof(hdmi_mode), + sizeof(hdmi_mode), &hdmi_mode.send_hdr); + if (res < 0) + return res; + + res = get_status(&hdmi_mode); + if (res && res != PS3AV_STATUS_UNSUPPORTED_HDMI_MODE) + printk(KERN_ERR "PS3AV_CID_AV_HDMI_MODE: failed %x\n", res); + + return res; +} + +u32 ps3av_cmd_set_av_video_cs(void *p, u32 avport, int video_vid, int cs_out, + int aspect, u32 id) +{ + struct ps3av_pkt_av_video_cs *av_video_cs; + + av_video_cs = (struct ps3av_pkt_av_video_cs *)p; + if (video_vid == -1) + video_vid = PS3AV_CMD_VIDEO_VID_720P_60HZ; + if (cs_out == -1) + cs_out = PS3AV_CMD_VIDEO_CS_YUV444_8; + if (aspect == -1) + aspect = 0; + + memset(av_video_cs, 0, sizeof(*av_video_cs)); + ps3av_set_hdr(PS3AV_CID_AV_VIDEO_CS, sizeof(*av_video_cs), + &av_video_cs->send_hdr); + av_video_cs->avport = avport; + /* should be same as video_mode.resolution */ + av_video_cs->av_vid = ps3av_vid_video2av(video_vid); + av_video_cs->av_cs_out = ps3av_cs_video2av(cs_out); + /* should be same as video_mode.video_cs_out */ + av_video_cs->av_cs_in = ps3av_cs_video2av(PS3AV_CMD_VIDEO_CS_RGB_8); + av_video_cs->bitlen_out = ps3av_cs_video2av_bitlen(cs_out); + av_video_cs->aspect = aspect; + if (id & PS3AV_MODE_DITHER) { + av_video_cs->dither = PS3AV_CMD_AV_DITHER_ON + | PS3AV_CMD_AV_DITHER_8BIT; + } else { + /* default off */ + av_video_cs->dither = PS3AV_CMD_AV_DITHER_OFF; + } + + return sizeof(*av_video_cs); +} + +u32 ps3av_cmd_set_video_mode(void *p, u32 head, int video_vid, int video_fmt, + u32 id) +{ + struct ps3av_pkt_video_mode *video_mode; + u32 x, y; + + video_mode = (struct ps3av_pkt_video_mode *)p; + if (video_vid == -1) + video_vid = PS3AV_CMD_VIDEO_VID_720P_60HZ; + if (video_fmt == -1) + video_fmt = PS3AV_CMD_VIDEO_FMT_X8R8G8B8; + + if (ps3av_video_mode2res(id, &x, &y)) + return 0; + + /* video mode */ + memset(video_mode, 0, sizeof(*video_mode)); + ps3av_set_hdr(PS3AV_CID_VIDEO_MODE, sizeof(*video_mode), + &video_mode->send_hdr); + video_mode->video_head = head; + if (video_vid == PS3AV_CMD_VIDEO_VID_480I + && head == PS3AV_CMD_VIDEO_HEAD_B) + video_mode->video_vid = PS3AV_CMD_VIDEO_VID_480I_A; + else + video_mode->video_vid = video_vid; + video_mode->width = (u16) x; + video_mode->height = (u16) y; + video_mode->pitch = video_mode->width * 4; /* line_length */ + video_mode->video_out_format = PS3AV_CMD_VIDEO_OUT_FORMAT_RGB_12BIT; + video_mode->video_format = ps3av_video_fmt_table[video_fmt].format; + video_mode->video_order = ps3av_video_fmt_table[video_fmt].order; + + pr_debug("%s: video_mode:vid:%x width:%d height:%d pitch:%d out_format:%d format:%x order:%x\n", + __FUNCTION__, video_vid, video_mode->width, video_mode->height, + video_mode->pitch, video_mode->video_out_format, + video_mode->video_format, video_mode->video_order); + return sizeof(*video_mode); +} + +int ps3av_cmd_video_format_black(u32 head, u32 video_fmt, u32 mute) +{ + int res; + struct ps3av_pkt_video_format video_format; + + memset(&video_format, 0, sizeof(video_format)); + video_format.video_head = head; + if (mute != PS3AV_CMD_MUTE_OFF) + video_format.video_format = PS3AV_CMD_VIDEO_FORMAT_BLACK; + else + video_format.video_format = + ps3av_video_fmt_table[video_fmt].format; + video_format.video_order = ps3av_video_fmt_table[video_fmt].order; + + res = ps3av_do_pkt(PS3AV_CID_VIDEO_FORMAT, sizeof(video_format), + sizeof(video_format), &video_format.send_hdr); + if (res < 0) + return res; + + res = get_status(&video_format); + if (res) + printk(KERN_ERR "PS3AV_CID_VIDEO_FORMAT: failed %x\n", res); + + return res; +} + + +int ps3av_cmd_av_audio_mute(int num_of_port, u32 *port, u32 mute) +{ + int i, res; + struct ps3av_pkt_av_audio_mute av_audio_mute; + + if (num_of_port > PS3AV_MUTE_PORT_MAX) + return -EINVAL; + + /* audio mute */ + memset(&av_audio_mute, 0, sizeof(av_audio_mute)); + for (i = 0; i < num_of_port; i++) { + av_audio_mute.mute[i].avport = port[i]; + av_audio_mute.mute[i].mute = mute; + } + + res = ps3av_do_pkt(PS3AV_CID_AV_AUDIO_MUTE, + sizeof(av_audio_mute.send_hdr) + + sizeof(struct ps3av_av_mute) * num_of_port, + sizeof(av_audio_mute), &av_audio_mute.send_hdr); + if (res < 0) + return res; + + res = get_status(&av_audio_mute); + if (res) + printk(KERN_ERR "PS3AV_CID_AV_AUDIO_MUTE: failed %x\n", res); + + return res; +} + +static const struct { + u32 fs; + u8 mclk; +} ps3av_cnv_mclk_table[] = { + { PS3AV_CMD_AUDIO_FS_44K, PS3AV_CMD_AV_MCLK_512 }, + { PS3AV_CMD_AUDIO_FS_48K, PS3AV_CMD_AV_MCLK_512 }, + { PS3AV_CMD_AUDIO_FS_88K, PS3AV_CMD_AV_MCLK_256 }, + { PS3AV_CMD_AUDIO_FS_96K, PS3AV_CMD_AV_MCLK_256 }, + { PS3AV_CMD_AUDIO_FS_176K, PS3AV_CMD_AV_MCLK_128 }, + { PS3AV_CMD_AUDIO_FS_192K, PS3AV_CMD_AV_MCLK_128 } +}; + +static u8 ps3av_cnv_mclk(u32 fs) +{ + unsigned int i; + + for (i = 0; i < ARRAY_SIZE(ps3av_cnv_mclk_table); i++) + if (ps3av_cnv_mclk_table[i].fs == fs) + return ps3av_cnv_mclk_table[i].mclk; + + printk(KERN_ERR "%s failed, fs:%x\n", __FUNCTION__, fs); + return 0; +} + +#define BASE PS3AV_CMD_AUDIO_FS_44K + +static const u32 ps3av_ns_table[][5] = { + /* D1, D2, D3, D4, D5 */ + [PS3AV_CMD_AUDIO_FS_44K-BASE] { 6272, 6272, 17836, 17836, 8918 }, + [PS3AV_CMD_AUDIO_FS_48K-BASE] { 6144, 6144, 11648, 11648, 5824 }, + [PS3AV_CMD_AUDIO_FS_88K-BASE] { 12544, 12544, 35672, 35672, 17836 }, + [PS3AV_CMD_AUDIO_FS_96K-BASE] { 12288, 12288, 23296, 23296, 11648 }, + [PS3AV_CMD_AUDIO_FS_176K-BASE] { 25088, 25088, 71344, 71344, 35672 }, + [PS3AV_CMD_AUDIO_FS_192K-BASE] { 24576, 24576, 46592, 46592, 23296 } +}; + +static void ps3av_cnv_ns(u8 *ns, u32 fs, u32 video_vid) +{ + u32 av_vid, ns_val; + u8 *p = ns; + int d; + + d = ns_val = 0; + av_vid = ps3av_vid_video2av(video_vid); + switch (av_vid) { + case PS3AV_CMD_AV_VID_480I: + case PS3AV_CMD_AV_VID_576I: + d = 0; + break; + case PS3AV_CMD_AV_VID_480P: + case PS3AV_CMD_AV_VID_576P: + d = 1; + break; + case PS3AV_CMD_AV_VID_1080I_60HZ: + case PS3AV_CMD_AV_VID_1080I_50HZ: + d = 2; + break; + case PS3AV_CMD_AV_VID_720P_60HZ: + case PS3AV_CMD_AV_VID_720P_50HZ: + d = 3; + break; + case PS3AV_CMD_AV_VID_1080P_60HZ: + case PS3AV_CMD_AV_VID_1080P_50HZ: + case PS3AV_CMD_AV_VID_WXGA: + case PS3AV_CMD_AV_VID_SXGA: + case PS3AV_CMD_AV_VID_WUXGA: + d = 4; + break; + default: + printk(KERN_ERR "%s failed, vid:%x\n", __FUNCTION__, + video_vid); + break; + } + + if (fs < PS3AV_CMD_AUDIO_FS_44K || fs > PS3AV_CMD_AUDIO_FS_192K) + printk(KERN_ERR "%s failed, fs:%x\n", __FUNCTION__, fs); + else + ns_val = ps3av_ns_table[PS3AV_CMD_AUDIO_FS_44K-BASE][d]; + + *p++ = ns_val & 0x000000FF; + *p++ = (ns_val & 0x0000FF00) >> 8; + *p = (ns_val & 0x00FF0000) >> 16; +} + +#undef BASE + +static u8 ps3av_cnv_enable(u32 source, u8 *enable) +{ + u8 *p, ret = 0; + + if (source == PS3AV_CMD_AUDIO_SOURCE_SPDIF) { + ret = 0x03; + } else if (source == PS3AV_CMD_AUDIO_SOURCE_SERIAL) { + p = enable; + ret = ((p[0] << 4) + (p[1] << 5) + (p[2] << 6) + (p[3] << 7)) | + 0x01; + } else + printk(KERN_ERR "%s failed, source:%x\n", __FUNCTION__, + source); + return ret; +} + +static u8 ps3av_cnv_fifomap(u8 *map) +{ + u8 *p, ret = 0; + + p = map; + ret = p[0] + (p[1] << 2) + (p[2] << 4) + (p[3] << 6); + return ret; +} + +static u8 ps3av_cnv_inputlen(u32 word_bits) +{ + u8 ret = 0; + + switch (word_bits) { + case PS3AV_CMD_AUDIO_WORD_BITS_16: + ret = PS3AV_CMD_AV_INPUTLEN_16; + break; + case PS3AV_CMD_AUDIO_WORD_BITS_20: + ret = PS3AV_CMD_AV_INPUTLEN_20; + break; + case PS3AV_CMD_AUDIO_WORD_BITS_24: + ret = PS3AV_CMD_AV_INPUTLEN_24; + break; + default: + printk(KERN_ERR "%s failed, word_bits:%x\n", __FUNCTION__, + word_bits); + break; + } + return ret; +} + +static u8 ps3av_cnv_layout(u32 num_of_ch) +{ + if (num_of_ch > PS3AV_CMD_AUDIO_NUM_OF_CH_8) { + printk(KERN_ERR "%s failed, num_of_ch:%x\n", __FUNCTION__, + num_of_ch); + return 0; + } + + return num_of_ch == PS3AV_CMD_AUDIO_NUM_OF_CH_2 ? 0x0 : 0x1; +} + +static void ps3av_cnv_info(struct ps3av_audio_info_frame *info, + const struct ps3av_pkt_audio_mode *mode) +{ + info->pb1.cc = mode->audio_num_of_ch + 1; /* CH2:0x01 --- CH8:0x07 */ + info->pb1.ct = 0; + info->pb2.sf = 0; + info->pb2.ss = 0; + + info->pb3 = 0; /* check mode->audio_format ?? */ + info->pb4 = mode->audio_layout; + info->pb5.dm = mode->audio_downmix; + info->pb5.lsv = mode->audio_downmix_level; +} + +static void ps3av_cnv_chstat(u8 *chstat, u8 *cs_info) +{ + memcpy(chstat, cs_info, 5); +} + +u32 ps3av_cmd_set_av_audio_param(void *p, u32 port, + const struct ps3av_pkt_audio_mode *audio_mode, + u32 video_vid) +{ + struct ps3av_pkt_av_audio_param *param; + + param = (struct ps3av_pkt_av_audio_param *)p; + + memset(param, 0, sizeof(*param)); + ps3av_set_hdr(PS3AV_CID_AV_AUDIO_PARAM, sizeof(*param), + ¶m->send_hdr); + + param->avport = port; + param->mclk = ps3av_cnv_mclk(audio_mode->audio_fs) | 0x80; + ps3av_cnv_ns(param->ns, audio_mode->audio_fs, video_vid); + param->enable = ps3av_cnv_enable(audio_mode->audio_source, + audio_mode->audio_enable); + param->swaplr = 0x09; + param->fifomap = ps3av_cnv_fifomap(audio_mode->audio_map); + param->inputctrl = 0x49; + param->inputlen = ps3av_cnv_inputlen(audio_mode->audio_word_bits); + param->layout = ps3av_cnv_layout(audio_mode->audio_num_of_ch); + ps3av_cnv_info(¶m->info, audio_mode); + ps3av_cnv_chstat(param->chstat, audio_mode->audio_cs_info); + + return sizeof(*param); +} + +/* default cs val */ +static const u8 ps3av_mode_cs_info[] = { + 0x00, 0x09, 0x00, 0x02, 0x01, 0x00, 0x00, 0x00 +}; + +#define CS_44 0x00 +#define CS_48 0x02 +#define CS_88 0x08 +#define CS_96 0x0a +#define CS_176 0x0c +#define CS_192 0x0e +#define CS_MASK 0x0f +#define CS_BIT 0x40 + +void ps3av_cmd_set_audio_mode(struct ps3av_pkt_audio_mode *audio, u32 avport, + u32 ch, u32 fs, u32 word_bits, u32 format, + u32 source) +{ + int spdif_through, spdif_bitstream; + int i; + + if (!(ch | fs | format | word_bits | source)) { + ch = PS3AV_CMD_AUDIO_NUM_OF_CH_2; + fs = PS3AV_CMD_AUDIO_FS_48K; + word_bits = PS3AV_CMD_AUDIO_WORD_BITS_16; + format = PS3AV_CMD_AUDIO_FORMAT_PCM; + source = PS3AV_CMD_AUDIO_SOURCE_SERIAL; + } + spdif_through = spdif_bitstream = 0; /* XXX not supported */ + + /* audio mode */ + memset(audio, 0, sizeof(*audio)); + ps3av_set_hdr(PS3AV_CID_AUDIO_MODE, sizeof(*audio), &audio->send_hdr); + + audio->avport = (u8) avport; + audio->mask = 0x0FFF; /* XXX set all */ + audio->audio_num_of_ch = ch; + audio->audio_fs = fs; + audio->audio_word_bits = word_bits; + audio->audio_format = format; + audio->audio_source = source; + + switch (ch) { + case PS3AV_CMD_AUDIO_NUM_OF_CH_8: + audio->audio_enable[3] = 1; + /* fall through */ + case PS3AV_CMD_AUDIO_NUM_OF_CH_6: + audio->audio_enable[2] = 1; + audio->audio_enable[1] = 1; + /* fall through */ + case PS3AV_CMD_AUDIO_NUM_OF_CH_2: + default: + audio->audio_enable[0] = 1; + } + + /* audio swap L/R */ + for (i = 0; i < 4; i++) + audio->audio_swap[i] = PS3AV_CMD_AUDIO_SWAP_0; /* no swap */ + + /* audio serial input mapping */ + audio->audio_map[0] = PS3AV_CMD_AUDIO_MAP_OUTPUT_0; + audio->audio_map[1] = PS3AV_CMD_AUDIO_MAP_OUTPUT_1; + audio->audio_map[2] = PS3AV_CMD_AUDIO_MAP_OUTPUT_2; + audio->audio_map[3] = PS3AV_CMD_AUDIO_MAP_OUTPUT_3; + + /* audio speaker layout */ + if (avport == PS3AV_CMD_AVPORT_HDMI_0 || + avport == PS3AV_CMD_AVPORT_HDMI_1) { + switch (ch) { + case PS3AV_CMD_AUDIO_NUM_OF_CH_8: + audio->audio_layout = PS3AV_CMD_AUDIO_LAYOUT_8CH; + break; + case PS3AV_CMD_AUDIO_NUM_OF_CH_6: + audio->audio_layout = PS3AV_CMD_AUDIO_LAYOUT_6CH; + break; + case PS3AV_CMD_AUDIO_NUM_OF_CH_2: + default: + audio->audio_layout = PS3AV_CMD_AUDIO_LAYOUT_2CH; + break; + } + } else { + audio->audio_layout = PS3AV_CMD_AUDIO_LAYOUT_2CH; + } + + /* audio downmix permission */ + audio->audio_downmix = PS3AV_CMD_AUDIO_DOWNMIX_PERMITTED; + /* audio downmix level shift (0:0dB to 15:15dB) */ + audio->audio_downmix_level = 0; /* 0dB */ + + /* set ch status */ + for (i = 0; i < 8; i++) + audio->audio_cs_info[i] = ps3av_mode_cs_info[i]; + + switch (fs) { + case PS3AV_CMD_AUDIO_FS_44K: + audio->audio_cs_info[3] &= ~CS_MASK; + audio->audio_cs_info[3] |= CS_44; + break; + case PS3AV_CMD_AUDIO_FS_88K: + audio->audio_cs_info[3] &= ~CS_MASK; + audio->audio_cs_info[3] |= CS_88; + break; + case PS3AV_CMD_AUDIO_FS_96K: + audio->audio_cs_info[3] &= ~CS_MASK; + audio->audio_cs_info[3] |= CS_96; + break; + case PS3AV_CMD_AUDIO_FS_176K: + audio->audio_cs_info[3] &= ~CS_MASK; + audio->audio_cs_info[3] |= CS_176; + break; + case PS3AV_CMD_AUDIO_FS_192K: + audio->audio_cs_info[3] &= ~CS_MASK; + audio->audio_cs_info[3] |= CS_192; + break; + default: + break; + } + + /* pass through setting */ + if (spdif_through && + (avport == PS3AV_CMD_AVPORT_SPDIF_0 || + avport == PS3AV_CMD_AVPORT_SPDIF_1)) { + audio->audio_word_bits = PS3AV_CMD_AUDIO_WORD_BITS_16; + audio->audio_source = PS3AV_CMD_AUDIO_SOURCE_SPDIF; + if (spdif_bitstream) { + audio->audio_format = PS3AV_CMD_AUDIO_FORMAT_BITSTREAM; + audio->audio_cs_info[0] |= CS_BIT; + } + } +} + +int ps3av_cmd_audio_mode(struct ps3av_pkt_audio_mode *audio_mode) +{ + int res; + + res = ps3av_do_pkt(PS3AV_CID_AUDIO_MODE, sizeof(*audio_mode), + sizeof(*audio_mode), &audio_mode->send_hdr); + if (res < 0) + return res; + + res = get_status(audio_mode); + if (res) + printk(KERN_ERR "PS3AV_CID_AUDIO_MODE: failed %x\n", res); + + return res; +} + +int ps3av_cmd_audio_mute(int num_of_port, u32 *port, u32 mute) +{ + int i, res; + struct ps3av_pkt_audio_mute audio_mute; + + if (num_of_port > PS3AV_OPT_PORT_MAX) + return -EINVAL; + + /* audio mute */ + memset(&audio_mute, 0, sizeof(audio_mute)); + for (i = 0; i < num_of_port; i++) { + audio_mute.mute[i].avport = port[i]; + audio_mute.mute[i].mute = mute; + } + + res = ps3av_do_pkt(PS3AV_CID_AUDIO_MUTE, + sizeof(audio_mute.send_hdr) + + sizeof(struct ps3av_audio_mute) * num_of_port, + sizeof(audio_mute), &audio_mute.send_hdr); + if (res < 0) + return res; + + res = get_status(&audio_mute); + if (res) + printk(KERN_ERR "PS3AV_CID_AUDIO_MUTE: failed %x\n", res); + + return res; +} + +int ps3av_cmd_audio_active(int active, u32 port) +{ + int res; + struct ps3av_pkt_audio_active audio_active; + u32 cid; + + /* audio active */ + memset(&audio_active, 0, sizeof(audio_active)); + audio_active.audio_port = port; + cid = active ? PS3AV_CID_AUDIO_ACTIVE : PS3AV_CID_AUDIO_INACTIVE; + + res = ps3av_do_pkt(cid, sizeof(audio_active), sizeof(audio_active), + &audio_active.send_hdr); + if (res < 0) + return res; + + res = get_status(&audio_active); + if (res) + printk(KERN_ERR "PS3AV_CID_AUDIO_ACTIVE:%x failed %x\n", cid, + res); + + return res; +} + +int ps3av_cmd_avb_param(struct ps3av_pkt_avb_param *avb, u32 send_len) +{ + int res; + + ps3fb_flip_ctl(0); /* flip off */ + + /* avb packet */ + res = ps3av_do_pkt(PS3AV_CID_AVB_PARAM, send_len, sizeof(*avb), + &avb->send_hdr); + if (res < 0) + goto out; + + res = get_status(avb); + if (res) + pr_debug("%s: PS3AV_CID_AVB_PARAM: failed %x\n", __FUNCTION__, + res); + + out: + ps3fb_flip_ctl(1); /* flip on */ + return res; +} + +int ps3av_cmd_av_get_hw_conf(struct ps3av_pkt_av_get_hw_conf *hw_conf) +{ + int res; + + memset(hw_conf, 0, sizeof(*hw_conf)); + + res = ps3av_do_pkt(PS3AV_CID_AV_GET_HW_CONF, sizeof(hw_conf->send_hdr), + sizeof(*hw_conf), &hw_conf->send_hdr); + if (res < 0) + return res; + + res = get_status(hw_conf); + if (res) + printk(KERN_ERR "PS3AV_CID_AV_GET_HW_CONF: failed %x\n", res); + + return res; +} + +int ps3av_cmd_video_get_monitor_info(struct ps3av_pkt_av_get_monitor_info *info, + u32 avport) +{ + int res; + + memset(info, 0, sizeof(*info)); + info->avport = avport; + + res = ps3av_do_pkt(PS3AV_CID_AV_GET_MONITOR_INFO, + sizeof(info->send_hdr) + sizeof(info->avport) + + sizeof(info->reserved), + sizeof(*info), &info->send_hdr); + if (res < 0) + return res; + + res = get_status(info); + if (res) + printk(KERN_ERR "PS3AV_CID_AV_GET_MONITOR_INFO: failed %x\n", + res); + + return res; +} + +#ifdef PS3AV_DEBUG +void ps3av_cmd_av_hw_conf_dump(const struct ps3av_pkt_av_get_hw_conf *hw_conf) +{ + printk("av_h_conf:num of hdmi:%d\n", hw_conf->num_of_hdmi); + printk("av_h_conf:num of avmulti:%d\n", hw_conf->num_of_avmulti); + printk("av_h_conf:num of spdif:%d\n", hw_conf->num_of_spdif); +} + +void ps3av_cmd_av_monitor_info_dump(const struct ps3av_pkt_av_get_monitor_info *monitor_info) +{ + const struct ps3av_info_monitor *info = &monitor_info->info; + const struct ps3av_info_audio *audio = info->audio; + int i; + + printk("Monitor Info: size%d\n", monitor_info->send_hdr.size); + + printk("avport:%02x\n", info->avport); + printk("monitor_id:"); + for (i = 0; i < 10; i++) + printk("%02x ", info->monitor_id[i]); + printk("\nmonitor_type:%02x\n", info->monitor_type); + printk("monitor_name:"); + for (i = 0; i < 16; i++) + printk("%c", info->monitor_name[i]); + + /* resolution */ + printk("\nresolution_60: bits:%08x native:%08x\n", + info->res_60.res_bits, info->res_60.native); + printk("resolution_50: bits:%08x native:%08x\n", + info->res_50.res_bits, info->res_50.native); + printk("resolution_other: bits:%08x native:%08x\n", + info->res_other.res_bits, info->res_other.native); + printk("resolution_vesa: bits:%08x native:%08x\n", + info->res_vesa.res_bits, info->res_vesa.native); + + /* color space */ + printk("color space rgb:%02x\n", info->cs.rgb); + printk("color space yuv444:%02x\n", info->cs.yuv444); + printk("color space yuv422:%02x\n", info->cs.yuv422); + + /* color info */ + printk("color info red:X %04x Y %04x\n", + info->color.red_x, info->color.red_y); + printk("color info green:X %04x Y %04x\n", + info->color.green_x, info->color.green_y); + printk("color info blue:X %04x Y %04x\n", + info->color.blue_x, info->color.blue_y); + printk("color info white:X %04x Y %04x\n", + info->color.white_x, info->color.white_y); + printk("color info gamma: %08x\n", info->color.gamma); + + /* other info */ + printk("supported_AI:%02x\n", info->supported_ai); + printk("speaker_info:%02x\n", info->speaker_info); + printk("num of audio:%02x\n", info->num_of_audio_block); + + /* audio block */ + for (i = 0; i < info->num_of_audio_block; i++) { + printk("audio[%d] type:%02x max_ch:%02x fs:%02x sbit:%02x\n", + i, audio->type, audio->max_num_of_ch, audio->fs, + audio->sbit); + audio++; + } +} +#endif /* PS3AV_DEBUG */ + +#define PS3AV_AV_LAYOUT_0 (PS3AV_CMD_AV_LAYOUT_32 \ + | PS3AV_CMD_AV_LAYOUT_44 \ + | PS3AV_CMD_AV_LAYOUT_48) + +#define PS3AV_AV_LAYOUT_1 (PS3AV_AV_LAYOUT_0 \ + | PS3AV_CMD_AV_LAYOUT_88 \ + | PS3AV_CMD_AV_LAYOUT_96 \ + | PS3AV_CMD_AV_LAYOUT_176 \ + | PS3AV_CMD_AV_LAYOUT_192) + +/************************* vuart ***************************/ + +#define POLLING_INTERVAL 25 /* in msec */ + +int ps3av_vuart_write(struct ps3_vuart_port_device *dev, const void *buf, + unsigned long size) +{ + int error = ps3_vuart_write(dev, buf, size); + return error ? error : size; +} + +int ps3av_vuart_read(struct ps3_vuart_port_device *dev, void *buf, + unsigned long size, int timeout) +{ + int error; + int loopcnt = 0; + + timeout = (timeout + POLLING_INTERVAL - 1) / POLLING_INTERVAL; + while (loopcnt++ <= timeout) { + error = ps3_vuart_read(dev, buf, size); + if (!error) + return size; + if (error != -EAGAIN) { + printk(KERN_ERR "%s: ps3_vuart_read failed %d\n", + __FUNCTION__, error); + return error; + } + msleep(POLLING_INTERVAL); + } + return -EWOULDBLOCK; +} diff --git a/drivers/ps3/system-bus.c b/drivers/ps3/system-bus.c deleted file mode 100644 index d79f949..0000000 --- a/drivers/ps3/system-bus.c +++ /dev/null @@ -1,362 +0,0 @@ -/* - * PS3 system bus driver. - * - * Copyright (C) 2006 Sony Computer Entertainment Inc. - * Copyright 2006 Sony Corp. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#include -#include -#include -#include -#include - -#include -#include -#include -#include - -#define dump_mmio_region(_a) _dump_mmio_region(_a, __func__, __LINE__) -static void _dump_mmio_region(const struct ps3_mmio_region* r, - const char* func, int line) -{ - pr_debug("%s:%d: dev %u:%u\n", func, line, r->did.bus_id, - r->did.dev_id); - pr_debug("%s:%d: bus_addr %lxh\n", func, line, r->bus_addr); - pr_debug("%s:%d: len %lxh\n", func, line, r->len); - pr_debug("%s:%d: lpar_addr %lxh\n", func, line, r->lpar_addr); -} - -int ps3_mmio_region_create(struct ps3_mmio_region *r) -{ - int result; - - result = lv1_map_device_mmio_region(r->did.bus_id, r->did.dev_id, - r->bus_addr, r->len, r->page_size, &r->lpar_addr); - - if (result) { - pr_debug("%s:%d: lv1_map_device_mmio_region failed: %s\n", - __func__, __LINE__, ps3_result(result)); - r->lpar_addr = r->len = r->bus_addr = 0; - } - - dump_mmio_region(r); - return result; -} - -int ps3_free_mmio_region(struct ps3_mmio_region *r) -{ - int result; - - result = lv1_unmap_device_mmio_region(r->did.bus_id, r->did.dev_id, - r->bus_addr); - - if (result) - pr_debug("%s:%d: lv1_unmap_device_mmio_region failed: %s\n", - __func__, __LINE__, ps3_result(result)); - - r->lpar_addr = r->len = r->bus_addr = 0; - return result; -} - -static int ps3_system_bus_match(struct device *_dev, - struct device_driver *_drv) -{ - int result; - struct ps3_system_bus_driver *drv = to_ps3_system_bus_driver(_drv); - struct ps3_system_bus_device *dev = to_ps3_system_bus_device(_dev); - - result = dev->match_id == drv->match_id; - - pr_info("%s:%d: dev=%u(%s), drv=%u(%s): %s\n", __func__, __LINE__, - dev->match_id, dev->core.bus_id, drv->match_id, drv->core.name, - (result ? "match" : "miss")); - return result; -} - -static int ps3_system_bus_probe(struct device *_dev) -{ - int result; - struct ps3_system_bus_device *dev = to_ps3_system_bus_device(_dev); - struct ps3_system_bus_driver *drv = - to_ps3_system_bus_driver(_dev->driver); - - result = lv1_open_device(dev->did.bus_id, dev->did.dev_id, 0); - - if (result) { - pr_debug("%s:%d: lv1_open_device failed (%d)\n", - __func__, __LINE__, result); - result = -EACCES; - goto clean_none; - } - - if (dev->d_region->did.bus_id) { - result = ps3_dma_region_create(dev->d_region); - - if (result) { - pr_debug("%s:%d: ps3_dma_region_create failed (%d)\n", - __func__, __LINE__, result); - BUG_ON("check region type"); - result = -EINVAL; - goto clean_device; - } - } - - BUG_ON(!drv); - - if (drv->probe) - result = drv->probe(dev); - else - pr_info("%s:%d: %s no probe method\n", __func__, __LINE__, - dev->core.bus_id); - - if (result) { - pr_debug("%s:%d: drv->probe failed\n", __func__, __LINE__); - goto clean_dma; - } - - return result; - -clean_dma: - ps3_dma_region_free(dev->d_region); -clean_device: - lv1_close_device(dev->did.bus_id, dev->did.dev_id); -clean_none: - return result; -} - -static int ps3_system_bus_remove(struct device *_dev) -{ - struct ps3_system_bus_device *dev = to_ps3_system_bus_device(_dev); - struct ps3_system_bus_driver *drv = - to_ps3_system_bus_driver(_dev->driver); - - if (drv->remove) - drv->remove(dev); - else - pr_info("%s:%d: %s no remove method\n", __func__, __LINE__, - dev->core.bus_id); - - ps3_dma_region_free(dev->d_region); - ps3_free_mmio_region(dev->m_region); - lv1_close_device(dev->did.bus_id, dev->did.dev_id); - - return 0; -} - -struct bus_type ps3_system_bus_type = { - .name = "ps3_system_bus", - .match = ps3_system_bus_match, - .probe = ps3_system_bus_probe, - .remove = ps3_system_bus_remove, -}; - -int __init ps3_system_bus_init(void) -{ - int result; - - if (!firmware_has_feature(FW_FEATURE_PS3_LV1)) - return 0; - - result = bus_register(&ps3_system_bus_type); - BUG_ON(result); - return result; -} - -core_initcall(ps3_system_bus_init); - -/* Allocates a contiguous real buffer and creates mappings over it. - * Returns the virtual address of the buffer and sets dma_handle - * to the dma address (mapping) of the first page. - */ - -static void * ps3_alloc_coherent(struct device *_dev, size_t size, - dma_addr_t *dma_handle, gfp_t flag) -{ - int result; - struct ps3_system_bus_device *dev = to_ps3_system_bus_device(_dev); - unsigned long virt_addr; - - BUG_ON(!dev->d_region->bus_addr); - - flag &= ~(__GFP_DMA | __GFP_HIGHMEM); - flag |= __GFP_ZERO; - - virt_addr = __get_free_pages(flag, get_order(size)); - - if (!virt_addr) { - pr_debug("%s:%d: get_free_pages failed\n", __func__, __LINE__); - goto clean_none; - } - - result = ps3_dma_map(dev->d_region, virt_addr, size, dma_handle); - - if (result) { - pr_debug("%s:%d: ps3_dma_map failed (%d)\n", - __func__, __LINE__, result); - BUG_ON("check region type"); - goto clean_alloc; - } - - return (void*)virt_addr; - -clean_alloc: - free_pages(virt_addr, get_order(size)); -clean_none: - dma_handle = NULL; - return NULL; -} - -static void ps3_free_coherent(struct device *_dev, size_t size, void *vaddr, - dma_addr_t dma_handle) -{ - struct ps3_system_bus_device *dev = to_ps3_system_bus_device(_dev); - - ps3_dma_unmap(dev->d_region, dma_handle, size); - free_pages((unsigned long)vaddr, get_order(size)); -} - -/* Creates TCEs for a user provided buffer. The user buffer must be - * contiguous real kernel storage (not vmalloc). The address of the buffer - * passed here is the kernel (virtual) address of the buffer. The buffer - * need not be page aligned, the dma_addr_t returned will point to the same - * byte within the page as vaddr. - */ - -static dma_addr_t ps3_map_single(struct device *_dev, void *ptr, size_t size, - enum dma_data_direction direction) -{ - struct ps3_system_bus_device *dev = to_ps3_system_bus_device(_dev); - int result; - unsigned long bus_addr; - - result = ps3_dma_map(dev->d_region, (unsigned long)ptr, size, - &bus_addr); - - if (result) { - pr_debug("%s:%d: ps3_dma_map failed (%d)\n", - __func__, __LINE__, result); - } - - return bus_addr; -} - -static void ps3_unmap_single(struct device *_dev, dma_addr_t dma_addr, - size_t size, enum dma_data_direction direction) -{ - struct ps3_system_bus_device *dev = to_ps3_system_bus_device(_dev); - int result; - - result = ps3_dma_unmap(dev->d_region, dma_addr, size); - - if (result) { - pr_debug("%s:%d: ps3_dma_unmap failed (%d)\n", - __func__, __LINE__, result); - } -} - -static int ps3_map_sg(struct device *_dev, struct scatterlist *sg, int nents, - enum dma_data_direction direction) -{ -#if defined(CONFIG_PS3_DYNAMIC_DMA) - BUG_ON("do"); -#endif - return 0; -} - -static void ps3_unmap_sg(struct device *_dev, struct scatterlist *sg, - int nents, enum dma_data_direction direction) -{ -#if defined(CONFIG_PS3_DYNAMIC_DMA) - BUG_ON("do"); -#endif -} - -static int ps3_dma_supported(struct device *_dev, u64 mask) -{ - return 1; -} - -static struct dma_mapping_ops ps3_dma_ops = { - .alloc_coherent = ps3_alloc_coherent, - .free_coherent = ps3_free_coherent, - .map_single = ps3_map_single, - .unmap_single = ps3_unmap_single, - .map_sg = ps3_map_sg, - .unmap_sg = ps3_unmap_sg, - .dma_supported = ps3_dma_supported -}; - -/** - * ps3_system_bus_release_device - remove a device from the system bus - */ - -static void ps3_system_bus_release_device(struct device *_dev) -{ - struct ps3_system_bus_device *dev = to_ps3_system_bus_device(_dev); - kfree(dev); -} - -/** - * ps3_system_bus_device_register - add a device to the system bus - * - * ps3_system_bus_device_register() expects the dev object to be allocated - * dynamically by the caller. The system bus takes ownership of the dev - * object and frees the object in ps3_system_bus_release_device(). - */ - -int ps3_system_bus_device_register(struct ps3_system_bus_device *dev) -{ - int result; - static unsigned int dev_count = 1; - - dev->core.parent = NULL; - dev->core.bus = &ps3_system_bus_type; - dev->core.release = ps3_system_bus_release_device; - - dev->core.archdata.of_node = NULL; - dev->core.archdata.dma_ops = &ps3_dma_ops; - dev->core.archdata.numa_node = 0; - - snprintf(dev->core.bus_id, sizeof(dev->core.bus_id), "sb_%02x", - dev_count++); - - pr_debug("%s:%d add %s\n", __func__, __LINE__, dev->core.bus_id); - - result = device_register(&dev->core); - return result; -} - -EXPORT_SYMBOL_GPL(ps3_system_bus_device_register); - -int ps3_system_bus_driver_register(struct ps3_system_bus_driver *drv) -{ - int result; - - drv->core.bus = &ps3_system_bus_type; - - result = driver_register(&drv->core); - return result; -} - -EXPORT_SYMBOL_GPL(ps3_system_bus_driver_register); - -void ps3_system_bus_driver_unregister(struct ps3_system_bus_driver *drv) -{ - driver_unregister(&drv->core); -} - -EXPORT_SYMBOL_GPL(ps3_system_bus_driver_unregister); diff --git a/drivers/ps3/vuart.c b/drivers/ps3/vuart.c index 6974f65..ef8fd4c 100644 --- a/drivers/ps3/vuart.c +++ b/drivers/ps3/vuart.c @@ -783,8 +783,8 @@ static int ps3_vuart_probe(struct device vuart_private.in_use++; if (vuart_private.in_use == 1) { - result = ps3_alloc_vuart_irq((void*)&vuart_private.bmp.status, - &vuart_private.virq); + result = ps3_alloc_vuart_irq(PS3_BINDING_CPU_ANY, + (void*)&vuart_private.bmp.status, &vuart_private.virq); if (result) { dev_dbg(&dev->core, @@ -867,6 +867,22 @@ static int ps3_vuart_remove(struct devic return 0; } +static void ps3_vuart_shutdown(struct device *_dev) +{ + struct ps3_vuart_port_device *dev = to_ps3_vuart_port_device(_dev); + struct ps3_vuart_port_driver *drv = + to_ps3_vuart_port_driver(_dev->driver); + + dev_dbg(&dev->core, "%s:%d: %s\n", __func__, __LINE__, + dev->core.bus_id); + + if (drv->shutdown) + drv->shutdown(dev); + else + dev_dbg(&dev->core, "%s:%d: %s no shutdown method\n", __func__, + __LINE__, dev->core.bus_id); +} + /** * ps3_vuart - The vuart instance. * @@ -878,6 +894,7 @@ struct bus_type ps3_vuart = { .match = ps3_vuart_match, .probe = ps3_vuart_probe, .remove = ps3_vuart_remove, + .shutdown = ps3_vuart_shutdown, }; int __init ps3_vuart_init(void) diff --git a/drivers/ps3/vuart.h b/drivers/ps3/vuart.h index 28fd89f..2cbf728 100644 --- a/drivers/ps3/vuart.h +++ b/drivers/ps3/vuart.h @@ -21,37 +21,6 @@ #if !defined(_PS3_VUART_H) #define _PS3_VUART_H -struct ps3_vuart_stats { - unsigned long bytes_written; - unsigned long bytes_read; - unsigned long tx_interrupts; - unsigned long rx_interrupts; - unsigned long disconnect_interrupts; -}; - -/** - * struct ps3_vuart_port_device - a device on a vuart port - */ - -struct ps3_vuart_port_device { - enum ps3_match_id match_id; - struct device core; - - /* private driver variables */ - unsigned int port_number; - unsigned long interrupt_mask; - struct { - spinlock_t lock; - struct list_head head; - } tx_list; - struct { - unsigned long bytes_held; - spinlock_t lock; - struct list_head head; - } rx_list; - struct ps3_vuart_stats stats; -}; - /** * struct ps3_vuart_port_driver - a driver for a device on a vuart port */ @@ -61,6 +30,7 @@ struct ps3_vuart_port_driver { struct device_driver core; int (*probe)(struct ps3_vuart_port_device *); int (*remove)(struct ps3_vuart_port_device *); + void (*shutdown)(struct ps3_vuart_port_device *); int (*tx_event)(struct ps3_vuart_port_device *dev); int (*rx_event)(struct ps3_vuart_port_device *dev); int (*disconnect_event)(struct ps3_vuart_port_device *dev); @@ -68,9 +38,9 @@ struct ps3_vuart_port_driver { /* int (*resume)(struct ps3_vuart_port_device *); */ }; -int ps3_vuart_port_device_register(struct ps3_vuart_port_device *dev); int ps3_vuart_port_driver_register(struct ps3_vuart_port_driver *drv); void ps3_vuart_port_driver_unregister(struct ps3_vuart_port_driver *drv); + int ps3_vuart_write(struct ps3_vuart_port_device *dev, const void* buf, unsigned int bytes); int ps3_vuart_read(struct ps3_vuart_port_device *dev, void* buf, @@ -86,9 +56,4 @@ static inline struct ps3_vuart_port_devi return container_of(_dev, struct ps3_vuart_port_device, core); } -int ps3_vuart_write(struct ps3_vuart_port_device *dev, const void* buf, - unsigned int bytes); -int ps3_vuart_read(struct ps3_vuart_port_device *dev, void* buf, - unsigned int bytes); - #endif diff --git a/drivers/rapidio/rio-scan.c b/drivers/rapidio/rio-scan.c index 7bf7b2c..f935c1f 100644 --- a/drivers/rapidio/rio-scan.c +++ b/drivers/rapidio/rio-scan.c @@ -326,14 +326,17 @@ static struct rio_dev *rio_setup_device( rio_mport_read_config_32(port, destid, hopcount, RIO_DST_OPS_CAR, &rdev->dst_ops); - if (rio_device_has_destid(port, rdev->src_ops, rdev->dst_ops) - && do_enum) { - rio_set_device_id(port, destid, hopcount, next_destid); - rdev->destid = next_destid++; - if (next_destid == port->host_deviceid) - next_destid++; + if (rio_device_has_destid(port, rdev->src_ops, rdev->dst_ops)) { + if (do_enum) { + rio_set_device_id(port, destid, hopcount, next_destid); + rdev->destid = next_destid++; + if (next_destid == port->host_deviceid) + next_destid++; + } else + rdev->destid = rio_get_device_id(port, destid, hopcount); } else - rdev->destid = rio_get_device_id(port, destid, hopcount); + /* Switch device has an associated destID */ + rdev->destid = RIO_INVALID_DESTID; /* If a PE has both switch and other functions, show it as a switch */ if (rio_is_switch(rdev)) { @@ -347,7 +350,7 @@ static struct rio_dev *rio_setup_device( } rswitch->switchid = next_switchid; rswitch->hopcount = hopcount; - rswitch->destid = 0xffff; + rswitch->destid = destid; /* Initialize switch route table */ for (rdid = 0; rdid < RIO_MAX_ROUTE_ENTRIES; rdid++) rswitch->route_table[rdid] = RIO_INVALID_ROUTE; @@ -422,7 +425,7 @@ rio_sport_is_active(struct rio_mport *po /** * rio_route_add_entry- Add a route entry to a switch routing table * @mport: Master port to send transaction - * @rdev: Switch device + * @rswitch: Switch device * @table: Routing table ID * @route_destid: Destination ID to be routed * @route_port: Port number to be routed @@ -434,18 +437,18 @@ rio_sport_is_active(struct rio_mport *po * %RIO_GLOBAL_TABLE in @table. Returns %0 on success or %-EINVAL * on failure. */ -static int rio_route_add_entry(struct rio_mport *mport, struct rio_dev *rdev, +static int rio_route_add_entry(struct rio_mport *mport, struct rio_switch *rswitch, u16 table, u16 route_destid, u8 route_port) { - return rdev->rswitch->add_entry(mport, rdev->rswitch->destid, - rdev->rswitch->hopcount, table, + return rswitch->add_entry(mport, rswitch->destid, + rswitch->hopcount, table, route_destid, route_port); } /** * rio_route_get_entry- Read a route entry in a switch routing table * @mport: Master port to send transaction - * @rdev: Switch device + * @rswitch: Switch device * @table: Routing table ID * @route_destid: Destination ID to be routed * @route_port: Pointer to read port number into @@ -458,11 +461,11 @@ static int rio_route_add_entry(struct ri * on failure. */ static int -rio_route_get_entry(struct rio_mport *mport, struct rio_dev *rdev, u16 table, +rio_route_get_entry(struct rio_mport *mport, struct rio_switch *rswitch, u16 table, u16 route_destid, u8 * route_port) { - return rdev->rswitch->get_entry(mport, rdev->rswitch->destid, - rdev->rswitch->hopcount, table, + return rswitch->get_entry(mport, rswitch->destid, + rswitch->hopcount, table, route_destid, route_port); } @@ -552,6 +555,8 @@ static int rio_enum_peer(struct rio_net int port_num; int num_ports; int cur_destid; + int sw_destid; + int sw_inport; struct rio_dev *rdev; u16 destid; int tmp; @@ -594,15 +599,17 @@ static int rio_enum_peer(struct rio_net if (rio_is_switch(rdev)) { next_switchid++; + sw_inport = rio_get_swpinfo_inport(port, RIO_ANY_DESTID, hopcount); + rio_route_add_entry(port, rdev->rswitch, RIO_GLOBAL_TABLE, + port->host_deviceid, sw_inport); + rdev->rswitch->route_table[port->host_deviceid] = sw_inport; for (destid = 0; destid < next_destid; destid++) { - rio_route_add_entry(port, rdev, RIO_GLOBAL_TABLE, - destid, rio_get_swpinfo_inport(port, - RIO_ANY_DESTID, - hopcount)); - rdev->rswitch->route_table[destid] = - rio_get_swpinfo_inport(port, RIO_ANY_DESTID, - hopcount); + if (destid == port->host_deviceid) + continue; + rio_route_add_entry(port, rdev->rswitch, RIO_GLOBAL_TABLE, + destid, sw_inport); + rdev->rswitch->route_table[destid] = sw_inport; } num_ports = @@ -610,9 +617,9 @@ static int rio_enum_peer(struct rio_net pr_debug( "RIO: found %s (vid %4.4x did %4.4x) with %d ports\n", rio_name(rdev), rdev->vid, rdev->did, num_ports); + sw_destid = next_destid; for (port_num = 0; port_num < num_ports; port_num++) { - if (rio_get_swpinfo_inport - (port, RIO_ANY_DESTID, hopcount) == port_num) + if (sw_inport == port_num) continue; cur_destid = next_destid; @@ -622,7 +629,7 @@ static int rio_enum_peer(struct rio_net pr_debug( "RIO: scanning device on port %d\n", port_num); - rio_route_add_entry(port, rdev, + rio_route_add_entry(port, rdev->rswitch, RIO_GLOBAL_TABLE, RIO_ANY_DESTID, port_num); @@ -633,7 +640,9 @@ static int rio_enum_peer(struct rio_net if (next_destid > cur_destid) { for (destid = cur_destid; destid < next_destid; destid++) { - rio_route_add_entry(port, rdev, + if (destid == port->host_deviceid) + continue; + rio_route_add_entry(port, rdev->rswitch, RIO_GLOBAL_TABLE, destid, port_num); @@ -641,10 +650,18 @@ static int rio_enum_peer(struct rio_net route_table[destid] = port_num; } - rdev->rswitch->destid = cur_destid; } } } + + /* Check for empty switch */ + if (next_destid == sw_destid) { + next_destid++; + if (next_destid == port->host_deviceid) + next_destid++; + } + + rdev->rswitch->destid = sw_destid; } else pr_debug("RIO: found %s (vid %4.4x did %4.4x)\n", rio_name(rdev), rdev->vid, rdev->did); @@ -721,7 +738,7 @@ rio_disc_peer(struct rio_net *net, struc port_num); for (ndestid = 0; ndestid < RIO_ANY_DESTID; ndestid++) { - rio_route_get_entry(port, rdev, + rio_route_get_entry(port, rdev->rswitch, RIO_GLOBAL_TABLE, ndestid, &route_port); @@ -798,6 +815,44 @@ static struct rio_net __devinit *rio_all } /** + * rio_update_route_tables- Updates route tables in switches + * @port: Master port associated with the RIO network + * + * For each enumerated device, ensure that each switch in a system + * has correct routing entries. Add routes for devices that where + * unknown dirung the first enumeration pass through the switch. + */ +static void rio_update_route_tables(struct rio_mport *port) +{ + struct rio_dev *rdev; + struct rio_switch *rswitch; + u8 sport; + u16 destid; + + list_for_each_entry(rdev, &rio_devices, global_list) { + + destid = (rio_is_switch(rdev))?rdev->rswitch->destid:rdev->destid; + + list_for_each_entry(rswitch, &rio_switches, node) { + + if (rio_is_switch(rdev) && (rdev->rswitch == rswitch)) + continue; + + if (RIO_INVALID_ROUTE == rswitch->route_table[destid]) { + + sport = rio_get_swpinfo_inport(port, + rswitch->destid, rswitch->hopcount); + + if (rswitch->add_entry) { + rio_route_add_entry(port, rswitch, RIO_GLOBAL_TABLE, destid, sport); + rswitch->route_table[destid] = sport; + } + } + } + } +} + +/** * rio_enum_mport- Start enumeration through a master port * @mport: Master port to send transactions * @@ -838,6 +893,7 @@ int rio_enum_mport(struct rio_mport *mpo rc = -EBUSY; goto out; } + rio_update_route_tables(mport); rio_clear_locks(mport); } else { printk(KERN_INFO "RIO: master port %d link inactive\n", @@ -865,8 +921,8 @@ static void rio_build_route_tables(void) if (rio_is_switch(rdev)) for (i = 0; i < RIO_MAX_ROUTE_ENTRIES; i++) { if (rio_route_get_entry - (rdev->net->hport, rdev, RIO_GLOBAL_TABLE, i, - &sport) < 0) + (rdev->net->hport, rdev->rswitch, RIO_GLOBAL_TABLE, + i, &sport) < 0) continue; rdev->rswitch->route_table[i] = sport; } diff --git a/drivers/rapidio/rio-sysfs.c b/drivers/rapidio/rio-sysfs.c index 5687b8f..eed9143 100644 --- a/drivers/rapidio/rio-sysfs.c +++ b/drivers/rapidio/rio-sysfs.c @@ -14,7 +14,6 @@ #include #include #include #include -#include /* for capable() */ #include "rio.h" diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig index 09660e2..4bbca50 100644 --- a/drivers/rtc/Kconfig +++ b/drivers/rtc/Kconfig @@ -1,4 +1,4 @@ -\# +# # RTC class/drivers configuration # @@ -95,6 +95,29 @@ config RTC_INTF_DEV_UIE_EMUL comment "RTC drivers" depends on RTC_CLASS +# this 'CMOS' RTC driver is arch dependent because +# requires defining CMOS_READ/CMOS_WRITE, and a +# global rtc_lock ... it's not yet just another platform_device. + +config RTC_DRV_CMOS + tristate "PC-style 'CMOS' real time clock" + depends on RTC_CLASS && (X86_PC || ALPHA || ARM26 || ARM \ + || M32R || ATARI || POWERPC) + help + Say "yes" here to get direct support for the real time clock + found in every PC or ACPI-based system, and some other boards. + Specifically the original MC146818, compatibles like those in + PC south bridges, the DS12887 or M48T86, some multifunction + or LPC bus chips, and so on. + + Your system will need to define the platform device used by + this driver, otherwise it won't be accessible. This means + you can safely enable this driver if you don't know whether + or not your board has this kind of hardware. + + This driver can also be built as a module. If so, the module + will be called rtc-cmos. + config RTC_DRV_X1205 tristate "Xicor/Intersil X1205" depends on RTC_CLASS && I2C diff --git a/drivers/rtc/Makefile b/drivers/rtc/Makefile index e6beeda..92bfe1b 100644 --- a/drivers/rtc/Makefile +++ b/drivers/rtc/Makefile @@ -15,6 +15,7 @@ obj-$(CONFIG_RTC_INTF_SYSFS) += rtc-sysf obj-$(CONFIG_RTC_INTF_PROC) += rtc-proc.o obj-$(CONFIG_RTC_INTF_DEV) += rtc-dev.o +obj-$(CONFIG_RTC_DRV_CMOS) += rtc-cmos.o obj-$(CONFIG_RTC_DRV_X1205) += rtc-x1205.o obj-$(CONFIG_RTC_DRV_ISL1208) += rtc-isl1208.o obj-$(CONFIG_RTC_DRV_TEST) += rtc-test.o diff --git a/drivers/rtc/rtc-cmos.c b/drivers/rtc/rtc-cmos.c new file mode 100644 index 0000000..85bf795 --- /dev/null +++ b/drivers/rtc/rtc-cmos.c @@ -0,0 +1,725 @@ +/* + * RTC class driver for "CMOS RTC": PCs, ACPI, etc + * + * Copyright (C) 1996 Paul Gortmaker (drivers/char/rtc.c) + * Copyright (C) 2006 David Brownell (convert to new framework) + * + * 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. + */ + +/* + * The original "cmos clock" chip was an MC146818 chip, now obsolete. + * That defined the register interface now provided by all PCs, some + * non-PC systems, and incorporated into ACPI. Modern PC chipsets + * integrate an MC146818 clone in their southbridge, and boards use + * that instead of discrete clones like the DS12887 or M48T86. There + * are also clones that connect using the LPC bus. + * + * That register API is also used directly by various other drivers + * (notably for integrated NVRAM), infrastructure (x86 has code to + * bypass the RTC framework, directly reading the RTC during boot + * and updating minutes/seconds for systems using NTP synch) and + * utilities (like userspace 'hwclock', if no /dev node exists). + * + * So **ALL** calls to CMOS_READ and CMOS_WRITE must be done with + * interrupts disabled, holding the global rtc_lock, to exclude those + * other drivers and utilities on correctly configured systems. + */ +#include +#include +#include +#include +#include +#include +#include + +/* this is for "generic access to PC-style RTC" using CMOS_READ/CMOS_WRITE */ +#include + + +struct cmos_rtc { + struct rtc_device *rtc; + struct device *dev; + int irq; + struct resource *iomem; + + u8 suspend_ctrl; + + /* newer hardware extends the original register set */ + u8 day_alrm; + u8 mon_alrm; + u8 century; +}; + +/* both platform and pnp busses use negative numbers for invalid irqs */ +#define is_valid_irq(n) ((n) >= 0) + +static const char driver_name[] = "rtc_cmos"; + +/*----------------------------------------------------------------*/ + +static int cmos_read_time(struct device *dev, struct rtc_time *t) +{ + /* REVISIT: if the clock has a "century" register, use + * that instead of the heuristic in get_rtc_time(). + * That'll make Y3K compatility (year > 2070) easy! + */ + get_rtc_time(t); + return 0; +} + +static int cmos_set_time(struct device *dev, struct rtc_time *t) +{ + /* REVISIT: set the "century" register if available + * + * NOTE: this ignores the issue whereby updating the seconds + * takes effect exactly 500ms after we write the register. + * (Also queueing and other delays before we get this far.) + */ + return set_rtc_time(t); +} + +static int cmos_read_alarm(struct device *dev, struct rtc_wkalrm *t) +{ + struct cmos_rtc *cmos = dev_get_drvdata(dev); + unsigned char rtc_control; + + if (!is_valid_irq(cmos->irq)) + return -EIO; + + /* Basic alarms only support hour, minute, and seconds fields. + * Some also support day and month, for alarms up to a year in + * the future. + */ + t->time.tm_mday = -1; + t->time.tm_mon = -1; + + spin_lock_irq(&rtc_lock); + t->time.tm_sec = CMOS_READ(RTC_SECONDS_ALARM); + t->time.tm_min = CMOS_READ(RTC_MINUTES_ALARM); + t->time.tm_hour = CMOS_READ(RTC_HOURS_ALARM); + + if (cmos->day_alrm) { + t->time.tm_mday = CMOS_READ(cmos->day_alrm); + if (!t->time.tm_mday) + t->time.tm_mday = -1; + + if (cmos->mon_alrm) { + t->time.tm_mon = CMOS_READ(cmos->mon_alrm); + if (!t->time.tm_mon) + t->time.tm_mon = -1; + } + } + + rtc_control = CMOS_READ(RTC_CONTROL); + spin_unlock_irq(&rtc_lock); + + /* REVISIT this assumes PC style usage: always BCD */ + + if (((unsigned)t->time.tm_sec) < 0x60) + t->time.tm_sec = BCD2BIN(t->time.tm_sec); + else + t->time.tm_sec = -1; + if (((unsigned)t->time.tm_min) < 0x60) + t->time.tm_min = BCD2BIN(t->time.tm_min); + else + t->time.tm_min = -1; + if (((unsigned)t->time.tm_hour) < 0x24) + t->time.tm_hour = BCD2BIN(t->time.tm_hour); + else + t->time.tm_hour = -1; + + if (cmos->day_alrm) { + if (((unsigned)t->time.tm_mday) <= 0x31) + t->time.tm_mday = BCD2BIN(t->time.tm_mday); + else + t->time.tm_mday = -1; + if (cmos->mon_alrm) { + if (((unsigned)t->time.tm_mon) <= 0x12) + t->time.tm_mon = BCD2BIN(t->time.tm_mon) - 1; + else + t->time.tm_mon = -1; + } + } + t->time.tm_year = -1; + + t->enabled = !!(rtc_control & RTC_AIE); + t->pending = 0; + + return 0; +} + +static int cmos_set_alarm(struct device *dev, struct rtc_wkalrm *t) +{ + struct cmos_rtc *cmos = dev_get_drvdata(dev); + unsigned char mon, mday, hrs, min, sec; + unsigned char rtc_control, rtc_intr; + + if (!is_valid_irq(cmos->irq)) + return -EIO; + + /* REVISIT this assumes PC style usage: always BCD */ + + /* Writing 0xff means "don't care" or "match all". */ + + mon = t->time.tm_mon; + mon = (mon < 12) ? BIN2BCD(mon) : 0xff; + mon++; + + mday = t->time.tm_mday; + mday = (mday >= 1 && mday <= 31) ? BIN2BCD(mday) : 0xff; + + hrs = t->time.tm_hour; + hrs = (hrs < 24) ? BIN2BCD(hrs) : 0xff; + + min = t->time.tm_min; + min = (min < 60) ? BIN2BCD(min) : 0xff; + + sec = t->time.tm_sec; + sec = (sec < 60) ? BIN2BCD(sec) : 0xff; + + spin_lock_irq(&rtc_lock); + + /* next rtc irq must not be from previous alarm setting */ + rtc_control = CMOS_READ(RTC_CONTROL); + rtc_control &= ~RTC_AIE; + CMOS_WRITE(rtc_control, RTC_CONTROL); + rtc_intr = CMOS_READ(RTC_INTR_FLAGS); + if (rtc_intr) + rtc_update_irq(&cmos->rtc->class_dev, 1, rtc_intr); + + /* update alarm */ + CMOS_WRITE(hrs, RTC_HOURS_ALARM); + CMOS_WRITE(min, RTC_MINUTES_ALARM); + CMOS_WRITE(sec, RTC_SECONDS_ALARM); + + /* the system may support an "enhanced" alarm */ + if (cmos->day_alrm) { + CMOS_WRITE(mday, cmos->day_alrm); + if (cmos->mon_alrm) + CMOS_WRITE(mon, cmos->mon_alrm); + } + + if (t->enabled) { + rtc_control |= RTC_AIE; + CMOS_WRITE(rtc_control, RTC_CONTROL); + rtc_intr = CMOS_READ(RTC_INTR_FLAGS); + if (rtc_intr) + rtc_update_irq(&cmos->rtc->class_dev, 1, rtc_intr); + } + + spin_unlock_irq(&rtc_lock); + + return 0; +} + +static int cmos_set_freq(struct device *dev, int freq) +{ + struct cmos_rtc *cmos = dev_get_drvdata(dev); + int f; + unsigned long flags; + + if (!is_valid_irq(cmos->irq)) + return -ENXIO; + + /* 0 = no irqs; 1 = 2^15 Hz ... 15 = 2^0 Hz */ + f = ffs(freq); + if (f != 0) { + if (f-- > 16 || freq != (1 << f)) + return -EINVAL; + f = 16 - f; + } + + spin_lock_irqsave(&rtc_lock, flags); + CMOS_WRITE(RTC_REF_CLCK_32KHZ | f, RTC_FREQ_SELECT); + spin_unlock_irqrestore(&rtc_lock, flags); + + return 0; +} + +#if defined(CONFIG_RTC_INTF_DEV) || defined(CONFIG_RTC_INTF_DEV_MODULE) + +static int +cmos_rtc_ioctl(struct device *dev, unsigned int cmd, unsigned long arg) +{ + struct cmos_rtc *cmos = dev_get_drvdata(dev); + unsigned char rtc_control, rtc_intr; + unsigned long flags; + + switch (cmd) { + case RTC_AIE_OFF: + case RTC_AIE_ON: + case RTC_UIE_OFF: + case RTC_UIE_ON: + case RTC_PIE_OFF: + case RTC_PIE_ON: + if (!is_valid_irq(cmos->irq)) + return -EINVAL; + break; + default: + return -ENOIOCTLCMD; + } + + spin_lock_irqsave(&rtc_lock, flags); + rtc_control = CMOS_READ(RTC_CONTROL); + switch (cmd) { + case RTC_AIE_OFF: /* alarm off */ + rtc_control &= ~RTC_AIE; + break; + case RTC_AIE_ON: /* alarm on */ + rtc_control |= RTC_AIE; + break; + case RTC_UIE_OFF: /* update off */ + rtc_control &= ~RTC_UIE; + break; + case RTC_UIE_ON: /* update on */ + rtc_control |= RTC_UIE; + break; + case RTC_PIE_OFF: /* periodic off */ + rtc_control &= ~RTC_PIE; + break; + case RTC_PIE_ON: /* periodic on */ + rtc_control |= RTC_PIE; + break; + } + CMOS_WRITE(rtc_control, RTC_CONTROL); + rtc_intr = CMOS_READ(RTC_INTR_FLAGS); + if (rtc_intr) + rtc_update_irq(&cmos->rtc->class_dev, 1, rtc_intr); + spin_unlock_irqrestore(&rtc_lock, flags); + return 0; +} + +#else +#define cmos_rtc_ioctl NULL +#endif + +#if defined(CONFIG_RTC_INTF_PROC) || defined(CONFIG_RTC_INTF_PROC_MODULE) + +static int cmos_procfs(struct device *dev, struct seq_file *seq) +{ + struct cmos_rtc *cmos = dev_get_drvdata(dev); + unsigned char rtc_control, valid; + + spin_lock_irq(&rtc_lock); + rtc_control = CMOS_READ(RTC_CONTROL); + valid = CMOS_READ(RTC_VALID); + spin_unlock_irq(&rtc_lock); + + /* NOTE: at least ICH6 reports battery status using a different + * (non-RTC) bit; and SQWE is ignored on many current systems. + */ + return seq_printf(seq, + "periodic_IRQ\t: %s\n" + "update_IRQ\t: %s\n" + // "square_wave\t: %s\n" + // "BCD\t\t: %s\n" + "DST_enable\t: %s\n" + "periodic_freq\t: %d\n" + "batt_status\t: %s\n", + (rtc_control & RTC_PIE) ? "yes" : "no", + (rtc_control & RTC_UIE) ? "yes" : "no", + // (rtc_control & RTC_SQWE) ? "yes" : "no", + // (rtc_control & RTC_DM_BINARY) ? "no" : "yes", + (rtc_control & RTC_DST_EN) ? "yes" : "no", + cmos->rtc->irq_freq, + (valid & RTC_VRT) ? "okay" : "dead"); +} + +#else +#define cmos_procfs NULL +#endif + +static const struct rtc_class_ops cmos_rtc_ops = { + .ioctl = cmos_rtc_ioctl, + .read_time = cmos_read_time, + .set_time = cmos_set_time, + .read_alarm = cmos_read_alarm, + .set_alarm = cmos_set_alarm, + .proc = cmos_procfs, + .irq_set_freq = cmos_set_freq, +}; + +/*----------------------------------------------------------------*/ + +static struct cmos_rtc cmos_rtc; + +static irqreturn_t cmos_interrupt(int irq, void *p) +{ + u8 irqstat; + + spin_lock(&rtc_lock); + irqstat = CMOS_READ(RTC_INTR_FLAGS); + spin_unlock(&rtc_lock); + + if (irqstat) { + /* NOTE: irqstat may have e.g. RTC_PF set + * even when RTC_PIE is clear... + */ + rtc_update_irq(p, 1, irqstat); + return IRQ_HANDLED; + } else + return IRQ_NONE; +} + +#ifdef CONFIG_PNPACPI +#define is_pnpacpi() 1 +#define INITSECTION + +#else +#define is_pnpacpi() 0 +#define INITSECTION __init +#endif + +static int INITSECTION +cmos_do_probe(struct device *dev, struct resource *ports, int rtc_irq) +{ + struct cmos_rtc_board_info *info = dev->platform_data; + int retval = 0; + unsigned char rtc_control; + + /* there can be only one ... */ + if (cmos_rtc.dev) + return -EBUSY; + + if (!ports) + return -ENODEV; + + cmos_rtc.irq = rtc_irq; + cmos_rtc.iomem = ports; + + /* For ACPI systems the info comes from the FADT. On others, + * board specific setup provides it as appropriate. + */ + if (info) { + cmos_rtc.day_alrm = info->rtc_day_alarm; + cmos_rtc.mon_alrm = info->rtc_mon_alarm; + cmos_rtc.century = info->rtc_century; + } + + cmos_rtc.rtc = rtc_device_register(driver_name, dev, + &cmos_rtc_ops, THIS_MODULE); + if (IS_ERR(cmos_rtc.rtc)) + return PTR_ERR(cmos_rtc.rtc); + + cmos_rtc.dev = dev; + dev_set_drvdata(dev, &cmos_rtc); + + /* platform and pnp busses handle resources incompatibly. + * + * REVISIT for non-x86 systems we may need to handle io memory + * resources: ioremap them, and request_mem_region(). + */ + if (is_pnpacpi()) { + retval = request_resource(&ioport_resource, ports); + if (retval < 0) { + dev_dbg(dev, "i/o registers already in use\n"); + goto cleanup0; + } + } + rename_region(ports, cmos_rtc.rtc->class_dev.class_id); + + spin_lock_irq(&rtc_lock); + + /* force periodic irq to CMOS reset default of 1024Hz; + * + * REVISIT it's been reported that at least one x86_64 ALI mobo + * doesn't use 32KHz here ... for portability we might need to + * do something about other clock frequencies. + */ + CMOS_WRITE(RTC_REF_CLCK_32KHZ | 0x06, RTC_FREQ_SELECT); + cmos_rtc.rtc->irq_freq = 1024; + + /* disable irqs. + * + * NOTE after changing RTC_xIE bits we always read INTR_FLAGS; + * allegedly some older rtcs need that to handle irqs properly + */ + rtc_control = CMOS_READ(RTC_CONTROL); + rtc_control &= ~(RTC_PIE | RTC_AIE | RTC_UIE); + CMOS_WRITE(rtc_control, RTC_CONTROL); + CMOS_READ(RTC_INTR_FLAGS); + + spin_unlock_irq(&rtc_lock); + + /* FIXME teach the alarm code how to handle binary mode; + * doesn't know 12-hour mode either. + */ + if (!(rtc_control & RTC_24H) || (rtc_control & (RTC_DM_BINARY))) { + dev_dbg(dev, "only 24-hr BCD mode supported\n"); + retval = -ENXIO; + goto cleanup1; + } + + if (is_valid_irq(rtc_irq)) + retval = request_irq(rtc_irq, cmos_interrupt, IRQF_DISABLED, + cmos_rtc.rtc->class_dev.class_id, + &cmos_rtc.rtc->class_dev); + if (retval < 0) { + dev_dbg(dev, "IRQ %d is already in use\n", rtc_irq); + goto cleanup1; + } + + /* REVISIT optionally make 50 or 114 bytes NVRAM available, + * like rtc-ds1553, rtc-ds1742 ... this will often include + * registers for century, and day/month alarm. + */ + + pr_info("%s: alarms up to one %s%s\n", + cmos_rtc.rtc->class_dev.class_id, + is_valid_irq(rtc_irq) + ? (cmos_rtc.mon_alrm + ? "year" + : (cmos_rtc.day_alrm + ? "month" : "day")) + : "no", + cmos_rtc.century ? ", y3k" : "" + ); + + return 0; + +cleanup1: + rename_region(ports, NULL); +cleanup0: + rtc_device_unregister(cmos_rtc.rtc); + return retval; +} + +static void cmos_do_shutdown(void) +{ + unsigned char rtc_control; + + spin_lock_irq(&rtc_lock); + rtc_control = CMOS_READ(RTC_CONTROL); + rtc_control &= ~(RTC_PIE|RTC_AIE|RTC_UIE); + CMOS_WRITE(rtc_control, RTC_CONTROL); + CMOS_READ(RTC_INTR_FLAGS); + spin_unlock_irq(&rtc_lock); +} + +static void __exit cmos_do_remove(struct device *dev) +{ + struct cmos_rtc *cmos = dev_get_drvdata(dev); + + cmos_do_shutdown(); + + if (is_pnpacpi()) + release_resource(cmos->iomem); + rename_region(cmos->iomem, NULL); + + if (is_valid_irq(cmos->irq)) + free_irq(cmos->irq, &cmos_rtc.rtc->class_dev); + + rtc_device_unregister(cmos_rtc.rtc); + + cmos_rtc.dev = NULL; + dev_set_drvdata(dev, NULL); +} + +#ifdef CONFIG_PM + +static int cmos_suspend(struct device *dev, pm_message_t mesg) +{ + struct cmos_rtc *cmos = dev_get_drvdata(dev); + int do_wake = device_may_wakeup(dev); + unsigned char tmp, irqstat; + + /* only the alarm might be a wakeup event source */ + spin_lock_irq(&rtc_lock); + cmos->suspend_ctrl = tmp = CMOS_READ(RTC_CONTROL); + if (tmp & (RTC_PIE|RTC_AIE|RTC_UIE)) { + if (do_wake) + tmp &= ~(RTC_PIE|RTC_UIE); + else + tmp &= ~(RTC_PIE|RTC_AIE|RTC_UIE); + CMOS_WRITE(tmp, RTC_CONTROL); + irqstat = CMOS_READ(RTC_INTR_FLAGS); + } else + irqstat = 0; + spin_unlock_irq(&rtc_lock); + + if (irqstat) + rtc_update_irq(&cmos->rtc->class_dev, 1, irqstat); + + /* ACPI HOOK: enable ACPI_EVENT_RTC when (tmp & RTC_AIE) + * ... it'd be best if we could do that under rtc_lock. + */ + + pr_debug("%s: suspend%s, ctrl %02x\n", + cmos_rtc.rtc->class_dev.class_id, + (tmp & RTC_AIE) ? ", alarm may wake" : "", + tmp); + + return 0; +} + +static int cmos_resume(struct device *dev) +{ + struct cmos_rtc *cmos = dev_get_drvdata(dev); + unsigned char tmp = cmos->suspend_ctrl; + + /* REVISIT: a mechanism to resync the system clock (jiffies) + * on resume should be portable between platforms ... + */ + + /* re-enable any irqs previously active */ + if (tmp & (RTC_PIE|RTC_AIE|RTC_UIE)) { + + /* ACPI HOOK: disable ACPI_EVENT_RTC when (tmp & RTC_AIE) */ + + spin_lock_irq(&rtc_lock); + CMOS_WRITE(tmp, RTC_CONTROL); + tmp = CMOS_READ(RTC_INTR_FLAGS); + spin_unlock_irq(&rtc_lock); + if (tmp) + rtc_update_irq(&cmos->rtc->class_dev, 1, tmp); + } + + pr_debug("%s: resume, ctrl %02x\n", + cmos_rtc.rtc->class_dev.class_id, + cmos->suspend_ctrl); + + + return 0; +} + +#else +#define cmos_suspend NULL +#define cmos_resume NULL +#endif + +/*----------------------------------------------------------------*/ + +/* The "CMOS" RTC normally lives on the platform_bus. On ACPI systems, + * the device node may alternatively be created as a PNP device. + */ + +#ifdef CONFIG_PNPACPI + +#include + +static int __devinit +cmos_pnp_probe(struct pnp_dev *pnp, const struct pnp_device_id *id) +{ + /* REVISIT paranoia argues for a shutdown notifier, since PNP + * drivers can't provide shutdown() methods to disable IRQs. + * Or better yet, fix PNP to allow those methods... + */ + return cmos_do_probe(&pnp->dev, + &pnp->res.port_resource[0], + pnp->res.irq_resource[0].start); +} + +static void __exit cmos_pnp_remove(struct pnp_dev *pnp) +{ + cmos_do_remove(&pnp->dev); +} + +#ifdef CONFIG_PM + +static int cmos_pnp_suspend(struct pnp_dev *pnp, pm_message_t mesg) +{ + return cmos_suspend(&pnp->dev, mesg); +} + +static int cmos_pnp_resume(struct pnp_dev *pnp) +{ + return cmos_resume(&pnp->dev); +} + +#else +#define cmos_pnp_suspend NULL +#define cmos_pnp_resume NULL +#endif + + +static const struct pnp_device_id rtc_ids[] = { + { .id = "PNP0b00", }, + { .id = "PNP0b01", }, + { .id = "PNP0b02", }, + { }, +}; +MODULE_DEVICE_TABLE(pnp, rtc_ids); + +static struct pnp_driver cmos_pnp_driver = { + .name = (char *) driver_name, + .id_table = rtc_ids, + .probe = cmos_pnp_probe, + .remove = __exit_p(cmos_pnp_remove), + + /* flag ensures resume() gets called, and stops syslog spam */ + .flags = PNP_DRIVER_RES_DO_NOT_CHANGE, + .suspend = cmos_pnp_suspend, + .resume = cmos_pnp_resume, +}; + +static int __init cmos_init(void) +{ + return pnp_register_driver(&cmos_pnp_driver); +} +module_init(cmos_init); + +static void __exit cmos_exit(void) +{ + pnp_unregister_driver(&cmos_pnp_driver); +} +module_exit(cmos_exit); + +#else /* no PNPACPI */ + +/*----------------------------------------------------------------*/ + +/* Platform setup should have set up an RTC device, when PNPACPI is + * unavailable ... this is the normal case, common even on PCs. + */ + +static int __init cmos_platform_probe(struct platform_device *pdev) +{ + return cmos_do_probe(&pdev->dev, + platform_get_resource(pdev, IORESOURCE_IO, 0), + platform_get_irq(pdev, 0)); +} + +static int __exit cmos_platform_remove(struct platform_device *pdev) +{ + cmos_do_remove(&pdev->dev); + return 0; +} + +static void cmos_platform_shutdown(struct platform_device *pdev) +{ + cmos_do_shutdown(); +} + +static struct platform_driver cmos_platform_driver = { + .remove = __exit_p(cmos_platform_remove), + .shutdown = cmos_platform_shutdown, + .driver = { + .name = (char *) driver_name, + .suspend = cmos_suspend, + .resume = cmos_resume, + } +}; + +static int __init cmos_init(void) +{ + return platform_driver_probe(&cmos_platform_driver, + cmos_platform_probe); +} +module_init(cmos_init); + +static void __exit cmos_exit(void) +{ + platform_driver_unregister(&cmos_platform_driver); +} +module_exit(cmos_exit); + + +#endif /* !PNPACPI */ + +MODULE_AUTHOR("David Brownell"); +MODULE_DESCRIPTION("Driver for PC-style 'CMOS' RTCs"); +MODULE_LICENSE("GPL"); diff --git a/drivers/rtc/rtc-dev.c b/drivers/rtc/rtc-dev.c index 94d3df6..137330b 100644 --- a/drivers/rtc/rtc-dev.c +++ b/drivers/rtc/rtc-dev.c @@ -305,7 +305,7 @@ static int rtc_dev_ioctl(struct inode *i case RTC_IRQP_READ: if (ops->irq_set_freq) - err = put_user(rtc->irq_freq, (unsigned long *) arg); + err = put_user(rtc->irq_freq, (unsigned long __user *)uarg); break; case RTC_IRQP_SET: @@ -384,7 +384,7 @@ static int rtc_dev_fasync(int fd, struct return fasync_helper(fd, file, on, &rtc->async_queue); } -static struct file_operations rtc_dev_fops = { +static const struct file_operations rtc_dev_fops = { .owner = THIS_MODULE, .llseek = no_llseek, .read = rtc_dev_read, diff --git a/drivers/rtc/rtc-ds1553.c b/drivers/rtc/rtc-ds1553.c index 001eb11..e27176c 100644 --- a/drivers/rtc/rtc-ds1553.c +++ b/drivers/rtc/rtc-ds1553.c @@ -297,7 +297,7 @@ static struct bin_attribute ds1553_nvram .write = ds1553_nvram_write, }; -static int __init ds1553_rtc_probe(struct platform_device *pdev) +static int __devinit ds1553_rtc_probe(struct platform_device *pdev) { struct rtc_device *rtc; struct resource *res; diff --git a/drivers/rtc/rtc-ds1672.c b/drivers/rtc/rtc-ds1672.c index 205fa28..dfef163 100644 --- a/drivers/rtc/rtc-ds1672.c +++ b/drivers/rtc/rtc-ds1672.c @@ -199,7 +199,7 @@ static int ds1672_probe(struct i2c_adapt struct i2c_client *client; struct rtc_device *rtc; - dev_dbg(adapter->class_dev.dev, "%s\n", __FUNCTION__); + dev_dbg(&adapter->dev, "%s\n", __FUNCTION__); if (!i2c_check_functionality(adapter, I2C_FUNC_I2C)) { err = -ENODEV; diff --git a/drivers/rtc/rtc-ds1742.c b/drivers/rtc/rtc-ds1742.c index 17633bf..d68288b 100644 --- a/drivers/rtc/rtc-ds1742.c +++ b/drivers/rtc/rtc-ds1742.c @@ -165,7 +165,7 @@ static struct bin_attribute ds1742_nvram .write = ds1742_nvram_write, }; -static int __init ds1742_rtc_probe(struct platform_device *pdev) +static int __devinit ds1742_rtc_probe(struct platform_device *pdev) { struct rtc_device *rtc; struct resource *res; diff --git a/drivers/rtc/rtc-omap.c b/drivers/rtc/rtc-omap.c index d59880d..9de8d67 100644 --- a/drivers/rtc/rtc-omap.c +++ b/drivers/rtc/rtc-omap.c @@ -417,13 +417,13 @@ static int __devinit omap_rtc_probe(stru rtc_write(OMAP_RTC_STATUS_ALARM, OMAP_RTC_STATUS_REG); /* handle periodic and alarm irqs */ - if (request_irq(omap_rtc_timer, rtc_irq, SA_INTERRUPT, + if (request_irq(omap_rtc_timer, rtc_irq, IRQF_DISABLED, rtc->class_dev.class_id, &rtc->class_dev)) { pr_debug("%s: RTC timer interrupt IRQ%d already claimed\n", pdev->name, omap_rtc_timer); goto fail0; } - if (request_irq(omap_rtc_alarm, rtc_irq, SA_INTERRUPT, + if (request_irq(omap_rtc_alarm, rtc_irq, IRQF_DISABLED, rtc->class_dev.class_id, &rtc->class_dev)) { pr_debug("%s: RTC alarm interrupt IRQ%d already claimed\n", pdev->name, omap_rtc_alarm); diff --git a/drivers/rtc/rtc-pcf8563.c b/drivers/rtc/rtc-pcf8563.c index 4b72b8e..0242d80 100644 --- a/drivers/rtc/rtc-pcf8563.c +++ b/drivers/rtc/rtc-pcf8563.c @@ -53,6 +53,25 @@ #define PCF8563_REG_TMR 0x0F /* timer * #define PCF8563_SC_LV 0x80 /* low voltage */ #define PCF8563_MO_C 0x80 /* century */ +struct pcf8563 { + struct i2c_client client; + /* + * The meaning of MO_C bit varies by the chip type. + * From PCF8563 datasheet: this bit is toggled when the years + * register overflows from 99 to 00 + * 0 indicates the century is 20xx + * 1 indicates the century is 19xx + * From RTC8564 datasheet: this bit indicates change of + * century. When the year digit data overflows from 99 to 00, + * this bit is set. By presetting it to 0 while still in the + * 20th century, it will be set in year 2000, ... + * There seems no reliable way to know how the system use this + * bit. So let's do it heuristically, assuming we are live in + * 1970...2069. + */ + int c_polarity; /* 0: MO_C=1 means 19xx, otherwise MO_C=1 means 20xx */ +}; + static int pcf8563_probe(struct i2c_adapter *adapter, int address, int kind); static int pcf8563_detach(struct i2c_client *client); @@ -62,6 +81,7 @@ static int pcf8563_detach(struct i2c_cli */ static int pcf8563_get_datetime(struct i2c_client *client, struct rtc_time *tm) { + struct pcf8563 *pcf8563 = container_of(client, struct pcf8563, client); unsigned char buf[13] = { PCF8563_REG_ST1 }; struct i2c_msg msgs[] = { @@ -94,8 +114,12 @@ static int pcf8563_get_datetime(struct i tm->tm_mday = BCD2BIN(buf[PCF8563_REG_DM] & 0x3F); tm->tm_wday = buf[PCF8563_REG_DW] & 0x07; tm->tm_mon = BCD2BIN(buf[PCF8563_REG_MO] & 0x1F) - 1; /* rtc mn 1-12 */ - tm->tm_year = BCD2BIN(buf[PCF8563_REG_YR]) - + (buf[PCF8563_REG_MO] & PCF8563_MO_C ? 0 : 100); + tm->tm_year = BCD2BIN(buf[PCF8563_REG_YR]); + if (tm->tm_year < 70) + tm->tm_year += 100; /* assume we are in 1970...2069 */ + /* detect the polarity heuristically. see note above. */ + pcf8563->c_polarity = (buf[PCF8563_REG_MO] & PCF8563_MO_C) ? + (tm->tm_year >= 100) : (tm->tm_year < 100); dev_dbg(&client->dev, "%s: tm is secs=%d, mins=%d, hours=%d, " "mday=%d, mon=%d, year=%d, wday=%d\n", @@ -114,6 +138,7 @@ static int pcf8563_get_datetime(struct i static int pcf8563_set_datetime(struct i2c_client *client, struct rtc_time *tm) { + struct pcf8563 *pcf8563 = container_of(client, struct pcf8563, client); int i, err; unsigned char buf[9]; @@ -135,7 +160,7 @@ static int pcf8563_set_datetime(struct i /* year and century */ buf[PCF8563_REG_YR] = BIN2BCD(tm->tm_year % 100); - if (tm->tm_year < 100) + if (pcf8563->c_polarity ? (tm->tm_year >= 100) : (tm->tm_year < 100)) buf[PCF8563_REG_MO] |= PCF8563_MO_C; buf[PCF8563_REG_DW] = tm->tm_wday & 0x07; @@ -248,23 +273,25 @@ static struct i2c_driver pcf8563_driver static int pcf8563_probe(struct i2c_adapter *adapter, int address, int kind) { + struct pcf8563 *pcf8563; struct i2c_client *client; struct rtc_device *rtc; int err = 0; - dev_dbg(adapter->class_dev.dev, "%s\n", __FUNCTION__); + dev_dbg(&adapter->dev, "%s\n", __FUNCTION__); if (!i2c_check_functionality(adapter, I2C_FUNC_I2C)) { err = -ENODEV; goto exit; } - if (!(client = kzalloc(sizeof(struct i2c_client), GFP_KERNEL))) { + if (!(pcf8563 = kzalloc(sizeof(struct pcf8563), GFP_KERNEL))) { err = -ENOMEM; goto exit; } + client = &pcf8563->client; client->addr = address; client->driver = &pcf8563_driver; client->adapter = adapter; @@ -301,7 +328,7 @@ exit_detach: i2c_detach_client(client); exit_kfree: - kfree(client); + kfree(pcf8563); exit: return err; @@ -309,6 +336,7 @@ exit: static int pcf8563_detach(struct i2c_client *client) { + struct pcf8563 *pcf8563 = container_of(client, struct pcf8563, client); int err; struct rtc_device *rtc = i2c_get_clientdata(client); @@ -318,7 +346,7 @@ static int pcf8563_detach(struct i2c_cli if ((err = i2c_detach_client(client))) return err; - kfree(client); + kfree(pcf8563); return 0; } diff --git a/drivers/rtc/rtc-proc.c b/drivers/rtc/rtc-proc.c index c272afd..1bd624f 100644 --- a/drivers/rtc/rtc-proc.c +++ b/drivers/rtc/rtc-proc.c @@ -96,7 +96,7 @@ static int rtc_proc_release(struct inode return res; } -static struct file_operations rtc_proc_fops = { +static const struct file_operations rtc_proc_fops = { .open = rtc_proc_open, .read = seq_read, .llseek = seq_lseek, diff --git a/drivers/rtc/rtc-rs5c372.c b/drivers/rtc/rtc-rs5c372.c index e7851e3..09bbe57 100644 --- a/drivers/rtc/rtc-rs5c372.c +++ b/drivers/rtc/rtc-rs5c372.c @@ -499,7 +499,7 @@ static int rs5c372_probe(struct i2c_adap struct rs5c372 *rs5c372; struct rtc_time tm; - dev_dbg(adapter->class_dev.dev, "%s\n", __FUNCTION__); + dev_dbg(&adapter->dev, "%s\n", __FUNCTION__); if (!i2c_check_functionality(adapter, I2C_FUNC_I2C)) { err = -ENODEV; diff --git a/drivers/rtc/rtc-s3c.c b/drivers/rtc/rtc-s3c.c index f406a2b..9a79a24 100644 --- a/drivers/rtc/rtc-s3c.c +++ b/drivers/rtc/rtc-s3c.c @@ -350,7 +350,7 @@ static int s3c_rtc_open(struct device *d int ret; ret = request_irq(s3c_rtc_alarmno, s3c_rtc_alarmirq, - SA_INTERRUPT, "s3c2410-rtc alarm", rtc_dev); + IRQF_DISABLED, "s3c2410-rtc alarm", rtc_dev); if (ret) { dev_err(dev, "IRQ%d error %d\n", s3c_rtc_alarmno, ret); @@ -358,7 +358,7 @@ static int s3c_rtc_open(struct device *d } ret = request_irq(s3c_rtc_tickno, s3c_rtc_tickirq, - SA_INTERRUPT, "s3c2410-rtc tick", rtc_dev); + IRQF_DISABLED, "s3c2410-rtc tick", rtc_dev); if (ret) { dev_err(dev, "IRQ%d error %d\n", s3c_rtc_tickno, ret); diff --git a/drivers/rtc/rtc-sysfs.c b/drivers/rtc/rtc-sysfs.c index 2ddd0cf..899ab8c 100644 --- a/drivers/rtc/rtc-sysfs.c +++ b/drivers/rtc/rtc-sysfs.c @@ -78,6 +78,92 @@ static struct attribute_group rtc_attr_g .attrs = rtc_attrs, }; + +static ssize_t +rtc_sysfs_show_wakealarm(struct class_device *dev, char *buf) +{ + ssize_t retval; + unsigned long alarm; + struct rtc_wkalrm alm; + + /* Don't show disabled alarms; but the RTC could leave the + * alarm enabled after it's already triggered. Alarms are + * conceptually one-shot, even though some common hardware + * (PCs) doesn't actually work that way. + * + * REVISIT maybe we should require RTC implementations to + * disable the RTC alarm after it triggers, for uniformity. + */ + retval = rtc_read_alarm(dev, &alm); + if (retval == 0 && alm.enabled) { + rtc_tm_to_time(&alm.time, &alarm); + retval = sprintf(buf, "%lu\n", alarm); + } + + return retval; +} + +static ssize_t +rtc_sysfs_set_wakealarm(struct class_device *dev, const char *buf, size_t n) +{ + ssize_t retval; + unsigned long now, alarm; + struct rtc_wkalrm alm; + + /* Only request alarms that trigger in the future. Disable them + * by writing another time, e.g. 0 meaning Jan 1 1970 UTC. + */ + retval = rtc_read_time(dev, &alm.time); + if (retval < 0) + return retval; + rtc_tm_to_time(&alm.time, &now); + + alarm = simple_strtoul(buf, NULL, 0); + if (alarm > now) { + /* Avoid accidentally clobbering active alarms; we can't + * entirely prevent that here, without even the minimal + * locking from the /dev/rtcN api. + */ + retval = rtc_read_alarm(dev, &alm); + if (retval < 0) + return retval; + if (alm.enabled) + return -EBUSY; + + alm.enabled = 1; + } else { + alm.enabled = 0; + + /* Provide a valid future alarm time. Linux isn't EFI, + * this time won't be ignored when disabling the alarm. + */ + alarm = now + 300; + } + rtc_time_to_tm(alarm, &alm.time); + + retval = rtc_set_alarm(dev, &alm); + return (retval < 0) ? retval : n; +} +static const CLASS_DEVICE_ATTR(wakealarm, S_IRUGO | S_IWUSR, + rtc_sysfs_show_wakealarm, rtc_sysfs_set_wakealarm); + + +/* The reason to trigger an alarm with no process watching it (via sysfs) + * is its side effect: waking from a system state like suspend-to-RAM or + * suspend-to-disk. So: no attribute unless that side effect is possible. + * (Userspace may disable that mechanism later.) + */ +static inline int rtc_does_wakealarm(struct class_device *class_dev) +{ + struct rtc_device *rtc; + + if (!device_can_wakeup(class_dev->dev)) + return 0; + rtc = to_rtc_device(class_dev); + return rtc->ops->set_alarm != NULL; +} + + static int rtc_sysfs_add_device(struct class_device *class_dev, struct class_interface *class_intf) { @@ -87,8 +173,18 @@ static int rtc_sysfs_add_device(struct c err = sysfs_create_group(&class_dev->kobj, &rtc_attr_group); if (err) - dev_err(class_dev->dev, - "failed to create sysfs attributes\n"); + dev_err(class_dev->dev, "failed to create %s\n", + "sysfs attributes"); + else if (rtc_does_wakealarm(class_dev)) { + /* not all RTCs support both alarms and wakeup */ + err = class_device_create_file(class_dev, + &class_device_attr_wakealarm); + if (err) { + dev_err(class_dev->dev, "failed to create %s\n", + "alarm attribute"); + sysfs_remove_group(&class_dev->kobj, &rtc_attr_group); + } + } return err; } @@ -96,6 +192,9 @@ static int rtc_sysfs_add_device(struct c static void rtc_sysfs_remove_device(struct class_device *class_dev, struct class_interface *class_intf) { + if (rtc_does_wakealarm(class_dev)) + class_device_remove_file(class_dev, + &class_device_attr_wakealarm); sysfs_remove_group(&class_dev->kobj, &rtc_attr_group); } diff --git a/drivers/rtc/rtc-x1205.c b/drivers/rtc/rtc-x1205.c index 019ae25..513d1a6 100644 --- a/drivers/rtc/rtc-x1205.c +++ b/drivers/rtc/rtc-x1205.c @@ -506,7 +506,7 @@ static int x1205_probe(struct i2c_adapte struct i2c_client *client; struct rtc_device *rtc; - dev_dbg(adapter->class_dev.dev, "%s\n", __FUNCTION__); + dev_dbg(&adapter->dev, "%s\n", __FUNCTION__); if (!i2c_check_functionality(adapter, I2C_FUNC_I2C)) { err = -ENODEV; diff --git a/drivers/s390/Kconfig b/drivers/s390/Kconfig index ae89b9b..165af39 100644 --- a/drivers/s390/Kconfig +++ b/drivers/s390/Kconfig @@ -103,14 +103,8 @@ config CCW_CONSOLE depends on TN3215_CONSOLE || TN3270_CONSOLE default y -config SCLP - bool "Support for SCLP" - help - Include support for the SCLP interface to the service element. - config SCLP_TTY bool "Support for SCLP line mode terminal" - depends on SCLP help Include support for IBM SCLP line-mode terminals. @@ -123,7 +117,6 @@ config SCLP_CONSOLE config SCLP_VT220_TTY bool "Support for SCLP VT220-compatible terminal" - depends on SCLP help Include support for an IBM SCLP VT220-compatible terminal. @@ -136,7 +129,6 @@ config SCLP_VT220_CONSOLE config SCLP_CPI tristate "Control-Program Identification" - depends on SCLP help This option enables the hardware console interface for system identification. This is commonly used for workload management and diff --git a/drivers/s390/Makefile b/drivers/s390/Makefile index 9803c93..5a88870 100644 --- a/drivers/s390/Makefile +++ b/drivers/s390/Makefile @@ -2,6 +2,8 @@ # # Makefile for the S/390 specific device drivers # +CFLAGS_sysinfo.o += -Iinclude/math-emu -Iarch/s390/math-emu -w + obj-y += s390mach.o sysinfo.o s390_rdev.o obj-y += cio/ block/ char/ crypto/ net/ scsi/ diff --git a/drivers/s390/block/dasd.c b/drivers/s390/block/dasd.c index 492b68b..eb5dc62 100644 --- a/drivers/s390/block/dasd.c +++ b/drivers/s390/block/dasd.c @@ -37,6 +37,7 @@ #define DASD_CHANQ_MAX_SIZE 4 */ debug_info_t *dasd_debug_area; struct dasd_discipline *dasd_diag_discipline_pointer; +void dasd_int_handler(struct ccw_device *, unsigned long, struct irb *); MODULE_AUTHOR("Holger Smolinski "); MODULE_DESCRIPTION("Linux on S/390 DASD device driver," @@ -51,7 +52,6 @@ static int dasd_alloc_queue(struct dasd static void dasd_setup_queue(struct dasd_device * device); static void dasd_free_queue(struct dasd_device * device); static void dasd_flush_request_queue(struct dasd_device *); -static void dasd_int_handler(struct ccw_device *, unsigned long, struct irb *); static int dasd_flush_ccw_queue(struct dasd_device *, int); static void dasd_tasklet(struct dasd_device *); static void do_kick_device(struct work_struct *); @@ -483,7 +483,7 @@ #define dasd_profile_counter(value, coun /* * Add profiling information for cqr before execution. */ -static inline void +static void dasd_profile_start(struct dasd_device *device, struct dasd_ccw_req * cqr, struct request *req) { @@ -505,7 +505,7 @@ dasd_profile_start(struct dasd_device *d /* * Add profiling information for cqr after execution. */ -static inline void +static void dasd_profile_end(struct dasd_device *device, struct dasd_ccw_req * cqr, struct request *req) { @@ -1022,8 +1022,6 @@ dasd_int_handler(struct ccw_device *cdev irb->scsw.cstat == 0 && !irb->esw.esw0.erw.cons) era = dasd_era_none; - else if (!test_bit(DASD_CQR_FLAGS_USE_ERP, &cqr->flags)) - era = dasd_era_fatal; /* don't recover this request */ else if (irb->esw.esw0.erw.cons) era = device->discipline->examine_error(cqr, irb); else @@ -1104,7 +1102,7 @@ __dasd_process_erp(struct dasd_device *d /* * Process ccw request queue. */ -static inline void +static void __dasd_process_ccw_queue(struct dasd_device * device, struct list_head *final_queue) { @@ -1127,7 +1125,9 @@ restart: cqr->status = DASD_CQR_FAILED; cqr->stopclk = get_clock(); } else { - if (cqr->irb.esw.esw0.erw.cons) { + if (cqr->irb.esw.esw0.erw.cons && + test_bit(DASD_CQR_FLAGS_USE_ERP, + &cqr->flags)) { erp_fn = device->discipline-> erp_action(cqr); erp_fn(cqr); @@ -1181,7 +1181,7 @@ dasd_end_request_cb(struct dasd_ccw_req /* * Fetch requests from the block device queue. */ -static inline void +static void __dasd_process_blk_queue(struct dasd_device * device) { request_queue_t *queue; @@ -1232,6 +1232,19 @@ __dasd_process_blk_queue(struct dasd_dev if (IS_ERR(cqr)) { if (PTR_ERR(cqr) == -ENOMEM) break; /* terminate request queue loop */ + if (PTR_ERR(cqr) == -EAGAIN) { + /* + * The current request cannot be build right + * now, we have to try later. If this request + * is the head-of-queue we stop the device + * for 1/2 second. + */ + if (!list_empty(&device->ccw_queue)) + break; + device->stopped |= DASD_STOPPED_PENDING; + dasd_set_timer(device, HZ/2); + break; + } DBF_DEV_EVENT(DBF_ERR, device, "CCW creation failed (rc=%ld) " "on request %p", @@ -1254,7 +1267,7 @@ __dasd_process_blk_queue(struct dasd_dev * Take a look at the first request on the ccw queue and check * if it reached its expire time. If so, terminate the IO. */ -static inline void +static void __dasd_check_expire(struct dasd_device * device) { struct dasd_ccw_req *cqr; @@ -1285,7 +1298,7 @@ __dasd_check_expire(struct dasd_device * * Take a look at the first request on the ccw queue and check * if it needs to be started. */ -static inline void +static void __dasd_start_head(struct dasd_device * device) { struct dasd_ccw_req *cqr; diff --git a/drivers/s390/block/dasd_3990_erp.c b/drivers/s390/block/dasd_3990_erp.c index 4d01040..8b9d68f 100644 --- a/drivers/s390/block/dasd_3990_erp.c +++ b/drivers/s390/block/dasd_3990_erp.c @@ -170,7 +170,6 @@ dasd_3990_erp_examine(struct dasd_ccw_re /* log the erp chain if fatal error occurred */ if ((era == dasd_era_fatal) && (device->state >= DASD_STATE_READY)) { dasd_log_sense(cqr, irb); - dasd_log_ccw(cqr, 0, irb->scsw.cpa); } return era; @@ -2640,7 +2639,6 @@ dasd_3990_erp_action(struct dasd_ccw_req struct dasd_ccw_req *erp = NULL; struct dasd_device *device = cqr->device; - __u32 cpa = cqr->irb.scsw.cpa; struct dasd_ccw_req *temp_erp = NULL; if (device->features & DASD_FEATURE_ERPLOG) { @@ -2706,9 +2704,6 @@ dasd_3990_erp_action(struct dasd_ccw_req } } - if (erp->status == DASD_CQR_FAILED) - dasd_log_ccw(erp, 1, cpa); - /* enqueue added ERP request */ if (erp->status == DASD_CQR_FILLED) { erp->status = DASD_CQR_QUEUED; diff --git a/drivers/s390/block/dasd_devmap.c b/drivers/s390/block/dasd_devmap.c index 5943266..ed70852 100644 --- a/drivers/s390/block/dasd_devmap.c +++ b/drivers/s390/block/dasd_devmap.c @@ -136,7 +136,7 @@ #endif /* #ifndef MODULE */ /* * Read a device busid/devno from a string. */ -static inline int +static int dasd_busid(char **str, int *id0, int *id1, int *devno) { int val, old_style; @@ -182,7 +182,7 @@ dasd_busid(char **str, int *id0, int *id * only one: "ro" for read-only devices. The default feature set * is empty (value 0). */ -static inline int +static int dasd_feature_list(char *str, char **endp) { int features, len, rc; @@ -341,7 +341,7 @@ dasd_parse_range( char *parsestring ) { return ERR_PTR(-EINVAL); } -static inline char * +static char * dasd_parse_next_element( char *parsestring ) { char * residual_str; residual_str = dasd_parse_keyword(parsestring); diff --git a/drivers/s390/block/dasd_diag.c b/drivers/s390/block/dasd_diag.c index 53db58a..ab782bb 100644 --- a/drivers/s390/block/dasd_diag.c +++ b/drivers/s390/block/dasd_diag.c @@ -43,7 +43,7 @@ #define DIAG_MAX_BLOCKS (((2 * PAGE_SIZE #define DIAG_MAX_RETRIES 32 #define DIAG_TIMEOUT 50 * HZ -struct dasd_discipline dasd_diag_discipline; +static struct dasd_discipline dasd_diag_discipline; struct dasd_diag_private { struct dasd_diag_characteristics rdc_data; @@ -90,7 +90,7 @@ static inline int dia250(void *iob, int * block offset. On success, return zero and set end_block to contain the * number of blocks on the device minus the specified offset. Return non-zero * otherwise. */ -static __inline__ int +static inline int mdsk_init_io(struct dasd_device *device, unsigned int blocksize, blocknum_t offset, blocknum_t *end_block) { @@ -117,7 +117,7 @@ mdsk_init_io(struct dasd_device *device, /* Remove block I/O environment for device. Return zero on success, non-zero * otherwise. */ -static __inline__ int +static inline int mdsk_term_io(struct dasd_device * device) { struct dasd_diag_private *private; @@ -576,7 +576,7 @@ dasd_diag_dump_sense(struct dasd_device "dump sense not available for DIAG data"); } -struct dasd_discipline dasd_diag_discipline = { +static struct dasd_discipline dasd_diag_discipline = { .owner = THIS_MODULE, .name = "DIAG", .ebcname = "DIAG", diff --git a/drivers/s390/block/dasd_eckd.c b/drivers/s390/block/dasd_eckd.c index fdaa471..cecab22 100644 --- a/drivers/s390/block/dasd_eckd.c +++ b/drivers/s390/block/dasd_eckd.c @@ -134,44 +134,7 @@ ceil_quot(unsigned int d1, unsigned int return (d1 + (d2 - 1)) / d2; } -static inline int -bytes_per_record(struct dasd_eckd_characteristics *rdc, int kl, int dl) -{ - unsigned int fl1, fl2, int1, int2; - int bpr; - - switch (rdc->formula) { - case 0x01: - fl1 = round_up_multiple(ECKD_F2(rdc) + dl, ECKD_F1(rdc)); - fl2 = round_up_multiple(kl ? ECKD_F2(rdc) + kl : 0, - ECKD_F1(rdc)); - bpr = fl1 + fl2; - break; - case 0x02: - int1 = ceil_quot(dl + ECKD_F6(rdc), ECKD_F5(rdc) << 1); - int2 = ceil_quot(kl + ECKD_F6(rdc), ECKD_F5(rdc) << 1); - fl1 = round_up_multiple(ECKD_F1(rdc) * ECKD_F2(rdc) + dl + - ECKD_F6(rdc) + ECKD_F4(rdc) * int1, - ECKD_F1(rdc)); - fl2 = round_up_multiple(ECKD_F1(rdc) * ECKD_F3(rdc) + kl + - ECKD_F6(rdc) + ECKD_F4(rdc) * int2, - ECKD_F1(rdc)); - bpr = fl1 + fl2; - break; - default: - bpr = 0; - break; - } - return bpr; -} - -static inline unsigned int -bytes_per_track(struct dasd_eckd_characteristics *rdc) -{ - return *(unsigned int *) (rdc->byte_per_track) >> 8; -} - -static inline unsigned int +static unsigned int recs_per_track(struct dasd_eckd_characteristics * rdc, unsigned int kl, unsigned int dl) { @@ -204,37 +167,39 @@ recs_per_track(struct dasd_eckd_characte return 0; } -static inline void +static int check_XRC (struct ccw1 *de_ccw, struct DE_eckd_data *data, struct dasd_device *device) { struct dasd_eckd_private *private; + int rc; private = (struct dasd_eckd_private *) device->private; + if (!private->rdc_data.facilities.XRC_supported) + return 0; /* switch on System Time Stamp - needed for XRC Support */ - if (private->rdc_data.facilities.XRC_supported) { - - data->ga_extended |= 0x08; /* switch on 'Time Stamp Valid' */ - data->ga_extended |= 0x02; /* switch on 'Extended Parameter' */ - - data->ep_sys_time = get_clock (); - - de_ccw->count = sizeof (struct DE_eckd_data); - de_ccw->flags |= CCW_FLAG_SLI; - } + data->ga_extended |= 0x08; /* switch on 'Time Stamp Valid' */ + data->ga_extended |= 0x02; /* switch on 'Extended Parameter' */ - return; + rc = get_sync_clock(&data->ep_sys_time); + /* Ignore return code if sync clock is switched off. */ + if (rc == -ENOSYS || rc == -EACCES) + rc = 0; -} /* end check_XRC */ + de_ccw->count = sizeof (struct DE_eckd_data); + de_ccw->flags |= CCW_FLAG_SLI; + return rc; +} -static inline void +static int define_extent(struct ccw1 * ccw, struct DE_eckd_data * data, int trk, int totrk, int cmd, struct dasd_device * device) { struct dasd_eckd_private *private; struct ch_t geo, beg, end; + int rc = 0; private = (struct dasd_eckd_private *) device->private; @@ -263,12 +228,12 @@ define_extent(struct ccw1 * ccw, struct case DASD_ECKD_CCW_WRITE_KD_MT: data->mask.perm = 0x02; data->attributes.operation = private->attrib.operation; - check_XRC (ccw, data, device); + rc = check_XRC (ccw, data, device); break; case DASD_ECKD_CCW_WRITE_CKD: case DASD_ECKD_CCW_WRITE_CKD_MT: data->attributes.operation = DASD_BYPASS_CACHE; - check_XRC (ccw, data, device); + rc = check_XRC (ccw, data, device); break; case DASD_ECKD_CCW_ERASE: case DASD_ECKD_CCW_WRITE_HOME_ADDRESS: @@ -276,7 +241,7 @@ define_extent(struct ccw1 * ccw, struct data->mask.perm = 0x3; data->mask.auth = 0x1; data->attributes.operation = DASD_BYPASS_CACHE; - check_XRC (ccw, data, device); + rc = check_XRC (ccw, data, device); break; default: DEV_MESSAGE(KERN_ERR, device, "unknown opcode 0x%x", cmd); @@ -312,9 +277,10 @@ define_extent(struct ccw1 * ccw, struct data->beg_ext.head = beg.head; data->end_ext.cyl = end.cyl; data->end_ext.head = end.head; + return rc; } -static inline void +static void locate_record(struct ccw1 *ccw, struct LO_eckd_data *data, int trk, int rec_on_trk, int no_rec, int cmd, struct dasd_device * device, int reclen) @@ -548,7 +514,7 @@ dasd_eckd_read_conf(struct dasd_device * /* * Build CP for Perform Subsystem Function - SSC. */ -struct dasd_ccw_req * +static struct dasd_ccw_req * dasd_eckd_build_psf_ssc(struct dasd_device *device) { struct dasd_ccw_req *cqr; @@ -1200,7 +1166,12 @@ #endif return cqr; ccw = cqr->cpaddr; /* First ccw is define extent. */ - define_extent(ccw++, cqr->data, first_trk, last_trk, cmd, device); + if (define_extent(ccw++, cqr->data, first_trk, + last_trk, cmd, device) == -EAGAIN) { + /* Clock not in sync and XRC is enabled. Try again later. */ + dasd_sfree_request(cqr, device); + return ERR_PTR(-EAGAIN); + } /* Build locate_record+read/write/ccws. */ idaws = (unsigned long *) (cqr->data + sizeof(struct DE_eckd_data)); LO_data = (struct LO_eckd_data *) (idaws + cidaw); @@ -1380,7 +1351,7 @@ dasd_eckd_release(struct dasd_device *de cqr->device = device; clear_bit(DASD_CQR_FLAGS_USE_ERP, &cqr->flags); set_bit(DASD_CQR_FLAGS_FAILFAST, &cqr->flags); - cqr->retries = 0; + cqr->retries = 2; /* set retry counter to enable basic ERP */ cqr->expires = 2 * HZ; cqr->buildclk = get_clock(); cqr->status = DASD_CQR_FILLED; @@ -1420,7 +1391,7 @@ dasd_eckd_reserve(struct dasd_device *de cqr->device = device; clear_bit(DASD_CQR_FLAGS_USE_ERP, &cqr->flags); set_bit(DASD_CQR_FLAGS_FAILFAST, &cqr->flags); - cqr->retries = 0; + cqr->retries = 2; /* set retry counter to enable basic ERP */ cqr->expires = 2 * HZ; cqr->buildclk = get_clock(); cqr->status = DASD_CQR_FILLED; @@ -1459,7 +1430,7 @@ dasd_eckd_steal_lock(struct dasd_device cqr->device = device; clear_bit(DASD_CQR_FLAGS_USE_ERP, &cqr->flags); set_bit(DASD_CQR_FLAGS_FAILFAST, &cqr->flags); - cqr->retries = 0; + cqr->retries = 2; /* set retry counter to enable basic ERP */ cqr->expires = 2 * HZ; cqr->buildclk = get_clock(); cqr->status = DASD_CQR_FILLED; @@ -1609,7 +1580,7 @@ dasd_eckd_ioctl(struct dasd_device *devi * Dump the range of CCWs into 'page' buffer * and return number of printed chars. */ -static inline int +static int dasd_eckd_dump_ccw_range(struct ccw1 *from, struct ccw1 *to, char *page) { int len, count; diff --git a/drivers/s390/block/dasd_eer.c b/drivers/s390/block/dasd_eer.c index e0bf30e..4b8a95f 100644 --- a/drivers/s390/block/dasd_eer.c +++ b/drivers/s390/block/dasd_eer.c @@ -650,7 +650,7 @@ static unsigned int dasd_eer_poll(struct return mask; } -static struct file_operations dasd_eer_fops = { +static const struct file_operations dasd_eer_fops = { .open = &dasd_eer_open, .release = &dasd_eer_close, .read = &dasd_eer_read, @@ -658,18 +658,24 @@ static struct file_operations dasd_eer_f .owner = THIS_MODULE, }; -static struct miscdevice dasd_eer_dev = { - .minor = MISC_DYNAMIC_MINOR, - .name = "dasd_eer", - .fops = &dasd_eer_fops, -}; +static struct miscdevice *dasd_eer_dev = NULL; int __init dasd_eer_init(void) { int rc; - rc = misc_register(&dasd_eer_dev); + dasd_eer_dev = kzalloc(sizeof(*dasd_eer_dev), GFP_KERNEL); + if (!dasd_eer_dev) + return -ENOMEM; + + dasd_eer_dev->minor = MISC_DYNAMIC_MINOR; + dasd_eer_dev->name = "dasd_eer"; + dasd_eer_dev->fops = &dasd_eer_fops; + + rc = misc_register(dasd_eer_dev); if (rc) { + kfree(dasd_eer_dev); + dasd_eer_dev = NULL; MESSAGE(KERN_ERR, "%s", "dasd_eer_init could not " "register misc device"); return rc; @@ -680,5 +686,9 @@ int __init dasd_eer_init(void) void dasd_eer_exit(void) { - WARN_ON(misc_deregister(&dasd_eer_dev) != 0); + if (dasd_eer_dev) { + WARN_ON(misc_deregister(dasd_eer_dev) != 0); + kfree(dasd_eer_dev); + dasd_eer_dev = NULL; + } } diff --git a/drivers/s390/block/dasd_erp.c b/drivers/s390/block/dasd_erp.c index 58a6509..caa5d91 100644 --- a/drivers/s390/block/dasd_erp.c +++ b/drivers/s390/block/dasd_erp.c @@ -152,25 +152,6 @@ dasd_default_erp_postaction(struct dasd_ } /* end default_erp_postaction */ -/* - * Print the hex dump of the memory used by a request. This includes - * all error recovery ccws that have been chained in from of the - * real request. - */ -static inline void -hex_dump_memory(struct dasd_device *device, void *data, int len) -{ - int *pint; - - pint = (int *) data; - while (len > 0) { - DEV_MESSAGE(KERN_ERR, device, "%p: %08x %08x %08x %08x", - pint, pint[0], pint[1], pint[2], pint[3]); - pint += 4; - len -= 16; - } -} - void dasd_log_sense(struct dasd_ccw_req *cqr, struct irb *irb) { @@ -182,69 +163,8 @@ dasd_log_sense(struct dasd_ccw_req *cqr, device->discipline->dump_sense(device, cqr, irb); } -void -dasd_log_ccw(struct dasd_ccw_req * cqr, int caller, __u32 cpa) -{ - struct dasd_device *device; - struct dasd_ccw_req *lcqr; - struct ccw1 *ccw; - int cplength; - - device = cqr->device; - /* log the channel program */ - for (lcqr = cqr; lcqr != NULL; lcqr = lcqr->refers) { - DEV_MESSAGE(KERN_ERR, device, - "(%s) ERP chain report for req: %p", - caller == 0 ? "EXAMINE" : "ACTION", lcqr); - hex_dump_memory(device, lcqr, sizeof(struct dasd_ccw_req)); - - cplength = 1; - ccw = lcqr->cpaddr; - while (ccw++->flags & (CCW_FLAG_DC | CCW_FLAG_CC)) - cplength++; - - if (cplength > 40) { /* log only parts of the CP */ - DEV_MESSAGE(KERN_ERR, device, "%s", - "Start of channel program:"); - hex_dump_memory(device, lcqr->cpaddr, - 40*sizeof(struct ccw1)); - - DEV_MESSAGE(KERN_ERR, device, "%s", - "End of channel program:"); - hex_dump_memory(device, lcqr->cpaddr + cplength - 10, - 10*sizeof(struct ccw1)); - } else { /* log the whole CP */ - DEV_MESSAGE(KERN_ERR, device, "%s", - "Channel program (complete):"); - hex_dump_memory(device, lcqr->cpaddr, - cplength*sizeof(struct ccw1)); - } - - if (lcqr != cqr) - continue; - - /* - * Log bytes arround failed CCW but only if we did - * not log the whole CP of the CCW is outside the - * logged CP. - */ - if (cplength > 40 || - ((addr_t) cpa < (addr_t) lcqr->cpaddr && - (addr_t) cpa > (addr_t) (lcqr->cpaddr + cplength + 4))) { - - DEV_MESSAGE(KERN_ERR, device, - "Failed CCW (%p) (area):", - (void *) (long) cpa); - hex_dump_memory(device, cqr->cpaddr - 10, - 20*sizeof(struct ccw1)); - } - } - -} /* end log_erp_chain */ - EXPORT_SYMBOL(dasd_default_erp_action); EXPORT_SYMBOL(dasd_default_erp_postaction); EXPORT_SYMBOL(dasd_alloc_erp_request); EXPORT_SYMBOL(dasd_free_erp_request); EXPORT_SYMBOL(dasd_log_sense); -EXPORT_SYMBOL(dasd_log_ccw); diff --git a/drivers/s390/block/dasd_fba.c b/drivers/s390/block/dasd_fba.c index b857fd5..be0909e 100644 --- a/drivers/s390/block/dasd_fba.c +++ b/drivers/s390/block/dasd_fba.c @@ -75,7 +75,7 @@ static struct ccw_driver dasd_fba_driver .notify = dasd_generic_notify, }; -static inline void +static void define_extent(struct ccw1 * ccw, struct DE_fba_data *data, int rw, int blksize, int beg, int nr) { @@ -95,7 +95,7 @@ define_extent(struct ccw1 * ccw, struct data->ext_end = nr - 1; } -static inline void +static void locate_record(struct ccw1 * ccw, struct LO_fba_data *data, int rw, int block_nr, int block_ct) { diff --git a/drivers/s390/block/dasd_genhd.c b/drivers/s390/block/dasd_genhd.c index d163632..47ba446 100644 --- a/drivers/s390/block/dasd_genhd.c +++ b/drivers/s390/block/dasd_genhd.c @@ -147,7 +147,7 @@ dasd_destroy_partitions(struct dasd_devi */ memset(&bpart, 0, sizeof(struct blkpg_partition)); memset(&barg, 0, sizeof(struct blkpg_ioctl_arg)); - barg.data = (void __user *) &bpart; + barg.data = (void __force __user *) &bpart; barg.op = BLKPG_DEL_PARTITION; for (bpart.pno = device->gdp->minors - 1; bpart.pno > 0; bpart.pno--) ioctl_by_bdev(bdev, BLKPG, (unsigned long) &barg); diff --git a/drivers/s390/block/dasd_int.h b/drivers/s390/block/dasd_int.h index fb725e3..a2cc69e 100644 --- a/drivers/s390/block/dasd_int.h +++ b/drivers/s390/block/dasd_int.h @@ -559,7 +559,6 @@ struct dasd_ccw_req *dasd_alloc_erp_requ struct dasd_device *); void dasd_free_erp_request(struct dasd_ccw_req *, struct dasd_device *); void dasd_log_sense(struct dasd_ccw_req *, struct irb *); -void dasd_log_ccw(struct dasd_ccw_req *, int, __u32); /* externals in dasd_3370_erp.c */ dasd_era_t dasd_3370_erp_examine(struct dasd_ccw_req *, struct irb *); diff --git a/drivers/s390/block/dasd_proc.c b/drivers/s390/block/dasd_proc.c index bfa010f..8b3b0f4 100644 --- a/drivers/s390/block/dasd_proc.c +++ b/drivers/s390/block/dasd_proc.c @@ -28,7 +28,7 @@ static struct proc_dir_entry *dasd_proc_ static struct proc_dir_entry *dasd_devices_entry = NULL; static struct proc_dir_entry *dasd_statistics_entry = NULL; -static inline char * +static char * dasd_get_user_string(const char __user *user_buf, size_t user_len) { char *buffer; @@ -147,14 +147,14 @@ static int dasd_devices_open(struct inod return seq_open(file, &dasd_devices_seq_ops); } -static struct file_operations dasd_devices_file_ops = { +static const struct file_operations dasd_devices_file_ops = { .open = dasd_devices_open, .read = seq_read, .llseek = seq_lseek, .release = seq_release, }; -static inline int +static int dasd_calc_metrics(char *page, char **start, off_t off, int count, int *eof, int len) { @@ -167,8 +167,8 @@ dasd_calc_metrics(char *page, char **sta return len; } -static inline char * -dasd_statistics_array(char *str, int *array, int shift) +static char * +dasd_statistics_array(char *str, unsigned int *array, int shift) { int i; diff --git a/drivers/s390/block/dcssblk.c b/drivers/s390/block/dcssblk.c index be9b053..1340451 100644 --- a/drivers/s390/block/dcssblk.c +++ b/drivers/s390/block/dcssblk.c @@ -102,7 +102,7 @@ dcssblk_release_segment(struct device *d * device needs to be enqueued before the semaphore is * freed. */ -static inline int +static int dcssblk_assign_free_minor(struct dcssblk_dev_info *dev_info) { int minor, found; @@ -230,7 +230,7 @@ dcssblk_shared_store(struct device *dev, SEGMENT_SHARED); if (rc < 0) { BUG_ON(rc == -EINVAL); - if (rc == -EIO || rc == -ENOENT) + if (rc != -EAGAIN) goto removeseg; } else { dev_info->is_shared = 1; @@ -253,7 +253,7 @@ dcssblk_shared_store(struct device *dev, SEGMENT_EXCLUSIVE); if (rc < 0) { BUG_ON(rc == -EINVAL); - if (rc == -EIO || rc == -ENOENT) + if (rc != -EAGAIN) goto removeseg; } else { dev_info->is_shared = 0; diff --git a/drivers/s390/char/Makefile b/drivers/s390/char/Makefile index c3e97b4..293e667 100644 --- a/drivers/s390/char/Makefile +++ b/drivers/s390/char/Makefile @@ -2,7 +2,8 @@ # # S/390 character devices # -obj-y += ctrlchar.o keyboard.o defkeymap.o +obj-y += ctrlchar.o keyboard.o defkeymap.o sclp.o sclp_rw.o sclp_quiesce.o \ + sclp_info.o obj-$(CONFIG_TN3270) += raw3270.o obj-$(CONFIG_TN3270_CONSOLE) += con3270.o @@ -11,7 +12,6 @@ obj-$(CONFIG_TN3270_FS) += fs3270.o obj-$(CONFIG_TN3215) += con3215.o -obj-$(CONFIG_SCLP) += sclp.o sclp_rw.o sclp_quiesce.o obj-$(CONFIG_SCLP_TTY) += sclp_tty.o obj-$(CONFIG_SCLP_CONSOLE) += sclp_con.o obj-$(CONFIG_SCLP_VT220_TTY) += sclp_vt220.o diff --git a/drivers/s390/char/con3215.c b/drivers/s390/char/con3215.c index 25b5d7a..9a328f1 100644 --- a/drivers/s390/char/con3215.c +++ b/drivers/s390/char/con3215.c @@ -1121,7 +1121,7 @@ static const struct tty_operations tty32 * 3215 tty registration code called from tty_init(). * Most kernel services (incl. kmalloc) are available at this poimt. */ -int __init +static int __init tty3215_init(void) { struct tty_driver *driver; diff --git a/drivers/s390/char/con3270.c b/drivers/s390/char/con3270.c index 7566be8..8e7f2d7 100644 --- a/drivers/s390/char/con3270.c +++ b/drivers/s390/char/con3270.c @@ -69,8 +69,7 @@ static void con3270_update(struct con327 /* * Setup timeout for a device. On timeout trigger an update. */ -void -con3270_set_timer(struct con3270 *cp, int expires) +static void con3270_set_timer(struct con3270 *cp, int expires) { if (expires == 0) { if (timer_pending(&cp->timer)) diff --git a/drivers/s390/char/defkeymap.c b/drivers/s390/char/defkeymap.c index 17027d9..564baca 100644 --- a/drivers/s390/char/defkeymap.c +++ b/drivers/s390/char/defkeymap.c @@ -5,6 +5,8 @@ #include #include #include +#include +#include u_short plain_map[NR_KEYS] = { 0xf000, 0xf000, 0xf000, 0xf000, 0xf000, 0xf000, 0xf000, 0xf000, diff --git a/drivers/s390/char/fs3270.c b/drivers/s390/char/fs3270.c index 0893d30..ef36f21 100644 --- a/drivers/s390/char/fs3270.c +++ b/drivers/s390/char/fs3270.c @@ -23,7 +23,7 @@ #include #include "raw3270.h" #include "ctrlchar.h" -struct raw3270_fn fs3270_fn; +static struct raw3270_fn fs3270_fn; struct fs3270 { struct raw3270_view view; @@ -401,7 +401,7 @@ fs3270_release(struct raw3270_view *view } /* View to a 3270 device. Can be console, tty or fullscreen. */ -struct raw3270_fn fs3270_fn = { +static struct raw3270_fn fs3270_fn = { .activate = fs3270_activate, .deactivate = fs3270_deactivate, .intv = (void *) fs3270_irq, @@ -493,7 +493,7 @@ fs3270_close(struct inode *inode, struct return 0; } -static struct file_operations fs3270_fops = { +static const struct file_operations fs3270_fops = { .owner = THIS_MODULE, /* owner */ .read = fs3270_read, /* read */ .write = fs3270_write, /* write */ diff --git a/drivers/s390/char/keyboard.c b/drivers/s390/char/keyboard.c index 3e86fd1..f62f9a4 100644 --- a/drivers/s390/char/keyboard.c +++ b/drivers/s390/char/keyboard.c @@ -148,6 +148,7 @@ kbd_ascebc(struct kbd_data *kbd, unsigne } } +#if 0 /* * Generate ebcdic -> ascii translation table from kbd_data. */ @@ -173,6 +174,7 @@ kbd_ebcasc(struct kbd_data *kbd, unsigne } } } +#endif /* * We have a combining character DIACR here, followed by the character CH. diff --git a/drivers/s390/char/monreader.c b/drivers/s390/char/monreader.c index a138b15..8df7b13 100644 --- a/drivers/s390/char/monreader.c +++ b/drivers/s390/char/monreader.c @@ -3,7 +3,7 @@ * * Character device driver for reading z/VM *MONITOR service records. * - * Copyright (C) 2004 IBM Corporation, IBM Deutschland Entwicklung GmbH. + * Copyright 2004 IBM Corporation, IBM Deutschland Entwicklung GmbH. * * Author: Gerald Schaefer */ @@ -22,7 +22,7 @@ #include #include #include #include -#include "../net/iucv.h" +#include //#define MON_DEBUG /* Debug messages on/off */ @@ -50,14 +50,13 @@ static char mon_dcss_name[9] = "MONDCSS\ struct mon_msg { u32 pos; u32 mca_offset; - iucv_MessagePending local_eib; + struct iucv_message msg; char msglim_reached; char replied_msglim; }; struct mon_private { - u16 pathid; - iucv_handle_t iucv_handle; + struct iucv_path *path; struct mon_msg *msg_array[MON_MSGLIM]; unsigned int write_index; unsigned int read_index; @@ -75,8 +74,6 @@ static unsigned long mon_dcss_end; static DECLARE_WAIT_QUEUE_HEAD(mon_read_wait_queue); static DECLARE_WAIT_QUEUE_HEAD(mon_conn_wait_queue); -static u8 iucv_host[8] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; - static u8 user_data_connect[16] = { /* Version code, must be 0x01 for shared mode */ 0x01, @@ -100,8 +97,7 @@ static u8 user_data_sever[16] = { * Create the 8 bytes EBCDIC DCSS segment name from * an ASCII name, incl. padding */ -static inline void -dcss_mkname(char *ascii_name, char *ebcdic_name) +static inline void dcss_mkname(char *ascii_name, char *ebcdic_name) { int i; @@ -119,8 +115,7 @@ dcss_mkname(char *ascii_name, char *ebcd * print appropriate error message for segment_load()/segment_type() * return code */ -static void -mon_segment_warn(int rc, char* seg_name) +static void mon_segment_warn(int rc, char* seg_name) { switch (rc) { case -ENOENT: @@ -166,44 +161,37 @@ mon_segment_warn(int rc, char* seg_name) } } -static inline unsigned long -mon_mca_start(struct mon_msg *monmsg) +static inline unsigned long mon_mca_start(struct mon_msg *monmsg) { - return monmsg->local_eib.ln1msg1.iprmmsg1_u32; + return *(u32 *) &monmsg->msg.rmmsg; } -static inline unsigned long -mon_mca_end(struct mon_msg *monmsg) +static inline unsigned long mon_mca_end(struct mon_msg *monmsg) { - return monmsg->local_eib.ln1msg2.ipbfln1f; + return *(u32 *) &monmsg->msg.rmmsg[4]; } -static inline u8 -mon_mca_type(struct mon_msg *monmsg, u8 index) +static inline u8 mon_mca_type(struct mon_msg *monmsg, u8 index) { return *((u8 *) mon_mca_start(monmsg) + monmsg->mca_offset + index); } -static inline u32 -mon_mca_size(struct mon_msg *monmsg) +static inline u32 mon_mca_size(struct mon_msg *monmsg) { return mon_mca_end(monmsg) - mon_mca_start(monmsg) + 1; } -static inline u32 -mon_rec_start(struct mon_msg *monmsg) +static inline u32 mon_rec_start(struct mon_msg *monmsg) { return *((u32 *) (mon_mca_start(monmsg) + monmsg->mca_offset + 4)); } -static inline u32 -mon_rec_end(struct mon_msg *monmsg) +static inline u32 mon_rec_end(struct mon_msg *monmsg) { return *((u32 *) (mon_mca_start(monmsg) + monmsg->mca_offset + 8)); } -static inline int -mon_check_mca(struct mon_msg *monmsg) +static inline int mon_check_mca(struct mon_msg *monmsg) { if ((mon_rec_end(monmsg) <= mon_rec_start(monmsg)) || (mon_rec_start(monmsg) < mon_dcss_start) || @@ -221,20 +209,17 @@ mon_check_mca(struct mon_msg *monmsg) return 0; } -static inline int -mon_send_reply(struct mon_msg *monmsg, struct mon_private *monpriv) +static inline int mon_send_reply(struct mon_msg *monmsg, + struct mon_private *monpriv) { - u8 prmmsg[8]; int rc; P_DEBUG("read, REPLY: pathid = 0x%04X, msgid = 0x%08X, trgcls = " "0x%08X\n\n", - monmsg->local_eib.ippathid, monmsg->local_eib.ipmsgid, - monmsg->local_eib.iptrgcls); - rc = iucv_reply_prmmsg(monmsg->local_eib.ippathid, - monmsg->local_eib.ipmsgid, - monmsg->local_eib.iptrgcls, - 0, prmmsg); + monpriv->path->pathid, monmsg->msg.id, monmsg->msg.class); + + rc = iucv_message_reply(monpriv->path, &monmsg->msg, + IUCV_IPRMDATA, NULL, 0); atomic_dec(&monpriv->msglim_count); if (likely(!monmsg->msglim_reached)) { monmsg->pos = 0; @@ -251,10 +236,19 @@ mon_send_reply(struct mon_msg *monmsg, s return 0; } -static inline struct mon_private * -mon_alloc_mem(void) +static inline void mon_free_mem(struct mon_private *monpriv) +{ + int i; + + for (i = 0; i < MON_MSGLIM; i++) + if (monpriv->msg_array[i]) + kfree(monpriv->msg_array[i]); + kfree(monpriv); +} + +static inline struct mon_private *mon_alloc_mem(void) { - int i,j; + int i; struct mon_private *monpriv; monpriv = kzalloc(sizeof(struct mon_private), GFP_KERNEL); @@ -267,16 +261,15 @@ mon_alloc_mem(void) GFP_KERNEL); if (!monpriv->msg_array[i]) { P_ERROR("open, no memory for msg_array\n"); - for (j = 0; j < i; j++) - kfree(monpriv->msg_array[j]); + mon_free_mem(monpriv); return NULL; } } return monpriv; } -static inline void -mon_read_debug(struct mon_msg *monmsg, struct mon_private *monpriv) +static inline void mon_read_debug(struct mon_msg *monmsg, + struct mon_private *monpriv) { #ifdef MON_DEBUG u8 msg_type[2], mca_type; @@ -284,7 +277,7 @@ #ifdef MON_DEBUG records_len = mon_rec_end(monmsg) - mon_rec_start(monmsg) + 1; - memcpy(msg_type, &monmsg->local_eib.iptrgcls, 2); + memcpy(msg_type, &monmsg->msg.class, 2); EBCASC(msg_type, 2); mca_type = mon_mca_type(monmsg, 0); EBCASC(&mca_type, 1); @@ -292,8 +285,7 @@ #ifdef MON_DEBUG P_DEBUG("read, mon_read_index = %i, mon_write_index = %i\n", monpriv->read_index, monpriv->write_index); P_DEBUG("read, pathid = 0x%04X, msgid = 0x%08X, trgcls = 0x%08X\n", - monmsg->local_eib.ippathid, monmsg->local_eib.ipmsgid, - monmsg->local_eib.iptrgcls); + monpriv->path->pathid, monmsg->msg.id, monmsg->msg.class); P_DEBUG("read, msg_type = '%c%c', mca_type = '%c' / 0x%X / 0x%X\n", msg_type[0], msg_type[1], mca_type ? mca_type : 'X', mon_mca_type(monmsg, 1), mon_mca_type(monmsg, 2)); @@ -306,8 +298,7 @@ #ifdef MON_DEBUG #endif } -static inline void -mon_next_mca(struct mon_msg *monmsg) +static inline void mon_next_mca(struct mon_msg *monmsg) { if (likely((mon_mca_size(monmsg) - monmsg->mca_offset) == 12)) return; @@ -316,8 +307,7 @@ mon_next_mca(struct mon_msg *monmsg) monmsg->pos = 0; } -static inline struct mon_msg * -mon_next_message(struct mon_private *monpriv) +static inline struct mon_msg *mon_next_message(struct mon_private *monpriv) { struct mon_msg *monmsg; @@ -342,39 +332,37 @@ mon_next_message(struct mon_private *mon /****************************************************************************** * IUCV handler * *****************************************************************************/ -static void -mon_iucv_ConnectionComplete(iucv_ConnectionComplete *eib, void *pgm_data) +static void mon_iucv_path_complete(struct iucv_path *path, u8 ipuser[16]) { - struct mon_private *monpriv = (struct mon_private *) pgm_data; + struct mon_private *monpriv = path->private; P_DEBUG("IUCV connection completed\n"); P_DEBUG("IUCV ACCEPT (from *MONITOR): Version = 0x%02X, Event = " "0x%02X, Sample = 0x%02X\n", - eib->ipuser[0], eib->ipuser[1], eib->ipuser[2]); + ipuser[0], ipuser[1], ipuser[2]); atomic_set(&monpriv->iucv_connected, 1); wake_up(&mon_conn_wait_queue); } -static void -mon_iucv_ConnectionSevered(iucv_ConnectionSevered *eib, void *pgm_data) +static void mon_iucv_path_severed(struct iucv_path *path, u8 ipuser[16]) { - struct mon_private *monpriv = (struct mon_private *) pgm_data; + struct mon_private *monpriv = path->private; - P_ERROR("IUCV connection severed with rc = 0x%X\n", - (u8) eib->ipuser[0]); + P_ERROR("IUCV connection severed with rc = 0x%X\n", ipuser[0]); + iucv_path_sever(path, NULL); atomic_set(&monpriv->iucv_severed, 1); wake_up(&mon_conn_wait_queue); wake_up_interruptible(&mon_read_wait_queue); } -static void -mon_iucv_MessagePending(iucv_MessagePending *eib, void *pgm_data) +static void mon_iucv_message_pending(struct iucv_path *path, + struct iucv_message *msg) { - struct mon_private *monpriv = (struct mon_private *) pgm_data; + struct mon_private *monpriv = path->private; P_DEBUG("IUCV message pending\n"); - memcpy(&monpriv->msg_array[monpriv->write_index]->local_eib, eib, - sizeof(iucv_MessagePending)); + memcpy(&monpriv->msg_array[monpriv->write_index]->msg, + msg, sizeof(*msg)); if (atomic_inc_return(&monpriv->msglim_count) == MON_MSGLIM) { P_WARNING("IUCV message pending, message limit (%i) reached\n", MON_MSGLIM); @@ -385,54 +373,45 @@ mon_iucv_MessagePending(iucv_MessagePend wake_up_interruptible(&mon_read_wait_queue); } -static iucv_interrupt_ops_t mon_iucvops = { - .ConnectionComplete = mon_iucv_ConnectionComplete, - .ConnectionSevered = mon_iucv_ConnectionSevered, - .MessagePending = mon_iucv_MessagePending, +static struct iucv_handler monreader_iucv_handler = { + .path_complete = mon_iucv_path_complete, + .path_severed = mon_iucv_path_severed, + .message_pending = mon_iucv_message_pending, }; /****************************************************************************** * file operations * *****************************************************************************/ -static int -mon_open(struct inode *inode, struct file *filp) +static int mon_open(struct inode *inode, struct file *filp) { - int rc, i; struct mon_private *monpriv; + int rc; /* * only one user allowed */ + rc = -EBUSY; if (test_and_set_bit(MON_IN_USE, &mon_in_use)) - return -EBUSY; + goto out; + rc = -ENOMEM; monpriv = mon_alloc_mem(); if (!monpriv) - return -ENOMEM; + goto out_use; /* - * Register with IUCV and connect to *MONITOR service + * Connect to *MONITOR service */ - monpriv->iucv_handle = iucv_register_program("my_monreader ", - MON_SERVICE, - NULL, - &mon_iucvops, - monpriv); - if (!monpriv->iucv_handle) { - P_ERROR("failed to register with iucv driver\n"); - rc = -EIO; - goto out_error; - } - P_INFO("open, registered with IUCV\n"); - - rc = iucv_connect(&monpriv->pathid, MON_MSGLIM, user_data_connect, - MON_SERVICE, iucv_host, IPRMDATA, NULL, NULL, - monpriv->iucv_handle, NULL); + monpriv->path = iucv_path_alloc(MON_MSGLIM, IUCV_IPRMDATA, GFP_KERNEL); + if (!monpriv->path) + goto out_priv; + rc = iucv_path_connect(monpriv->path, &monreader_iucv_handler, + MON_SERVICE, NULL, user_data_connect, monpriv); if (rc) { P_ERROR("iucv connection to *MONITOR failed with " "IPUSER SEVER code = %i\n", rc); rc = -EIO; - goto out_unregister; + goto out_path; } /* * Wait for connection confirmation @@ -444,24 +423,23 @@ mon_open(struct inode *inode, struct fil atomic_set(&monpriv->iucv_severed, 0); atomic_set(&monpriv->iucv_connected, 0); rc = -EIO; - goto out_unregister; + goto out_path; } P_INFO("open, established connection to *MONITOR service\n\n"); filp->private_data = monpriv; return nonseekable_open(inode, filp); -out_unregister: - iucv_unregister_program(monpriv->iucv_handle); -out_error: - for (i = 0; i < MON_MSGLIM; i++) - kfree(monpriv->msg_array[i]); - kfree(monpriv); +out_path: + kfree(monpriv->path); +out_priv: + mon_free_mem(monpriv); +out_use: clear_bit(MON_IN_USE, &mon_in_use); +out: return rc; } -static int -mon_close(struct inode *inode, struct file *filp) +static int mon_close(struct inode *inode, struct file *filp) { int rc, i; struct mon_private *monpriv = filp->private_data; @@ -469,18 +447,12 @@ mon_close(struct inode *inode, struct fi /* * Close IUCV connection and unregister */ - rc = iucv_sever(monpriv->pathid, user_data_sever); + rc = iucv_path_sever(monpriv->path, user_data_sever); if (rc) P_ERROR("close, iucv_sever failed with rc = %i\n", rc); else P_INFO("close, terminated connection to *MONITOR service\n"); - rc = iucv_unregister_program(monpriv->iucv_handle); - if (rc) - P_ERROR("close, iucv_unregister failed with rc = %i\n", rc); - else - P_INFO("close, unregistered with IUCV\n"); - atomic_set(&monpriv->iucv_severed, 0); atomic_set(&monpriv->iucv_connected, 0); atomic_set(&monpriv->read_ready, 0); @@ -495,8 +467,8 @@ mon_close(struct inode *inode, struct fi return 0; } -static ssize_t -mon_read(struct file *filp, char __user *data, size_t count, loff_t *ppos) +static ssize_t mon_read(struct file *filp, char __user *data, + size_t count, loff_t *ppos) { struct mon_private *monpriv = filp->private_data; struct mon_msg *monmsg; @@ -563,8 +535,7 @@ out_copy: return count; } -static unsigned int -mon_poll(struct file *filp, struct poll_table_struct *p) +static unsigned int mon_poll(struct file *filp, struct poll_table_struct *p) { struct mon_private *monpriv = filp->private_data; @@ -576,7 +547,7 @@ mon_poll(struct file *filp, struct poll_ return 0; } -static struct file_operations mon_fops = { +static const struct file_operations mon_fops = { .owner = THIS_MODULE, .open = &mon_open, .release = &mon_close, @@ -593,8 +564,7 @@ static struct miscdevice mon_dev = { /****************************************************************************** * module init/exit * *****************************************************************************/ -static int __init -mon_init(void) +static int __init mon_init(void) { int rc; @@ -603,22 +573,34 @@ mon_init(void) return -ENODEV; } + /* + * Register with IUCV and connect to *MONITOR service + */ + rc = iucv_register(&monreader_iucv_handler, 1); + if (rc) { + P_ERROR("failed to register with iucv driver\n"); + return rc; + } + P_INFO("open, registered with IUCV\n"); + rc = segment_type(mon_dcss_name); if (rc < 0) { mon_segment_warn(rc, mon_dcss_name); - return rc; + goto out_iucv; } if (rc != SEG_TYPE_SC) { P_ERROR("segment %s has unsupported type, should be SC\n", mon_dcss_name); - return -EINVAL; + rc = -EINVAL; + goto out_iucv; } rc = segment_load(mon_dcss_name, SEGMENT_SHARED, &mon_dcss_start, &mon_dcss_end); if (rc < 0) { mon_segment_warn(rc, mon_dcss_name); - return -EINVAL; + rc = -EINVAL; + goto out_iucv; } dcss_mkname(mon_dcss_name, &user_data_connect[8]); @@ -634,14 +616,16 @@ mon_init(void) out: segment_unload(mon_dcss_name); +out_iucv: + iucv_unregister(&monreader_iucv_handler, 1); return rc; } -static void __exit -mon_exit(void) +static void __exit mon_exit(void) { segment_unload(mon_dcss_name); WARN_ON(misc_deregister(&mon_dev) != 0); + iucv_unregister(&monreader_iucv_handler, 1); return; } diff --git a/drivers/s390/char/monwriter.c b/drivers/s390/char/monwriter.c index cdb24f5..268598e 100644 --- a/drivers/s390/char/monwriter.c +++ b/drivers/s390/char/monwriter.c @@ -67,8 +67,8 @@ static int monwrite_diag(struct monwrite return -EINVAL; } -static inline struct mon_buf *monwrite_find_hdr(struct mon_private *monpriv, - struct monwrite_hdr *monhdr) +static struct mon_buf *monwrite_find_hdr(struct mon_private *monpriv, + struct monwrite_hdr *monhdr) { struct mon_buf *entry, *next; @@ -255,7 +255,7 @@ out_error: return rc; } -static struct file_operations monwrite_fops = { +static const struct file_operations monwrite_fops = { .owner = THIS_MODULE, .open = &monwrite_open, .release = &monwrite_close, diff --git a/drivers/s390/char/raw3270.c b/drivers/s390/char/raw3270.c index 7a84014..8facd14 100644 --- a/drivers/s390/char/raw3270.c +++ b/drivers/s390/char/raw3270.c @@ -29,7 +29,7 @@ #include #include #include -struct class *class3270; +static struct class *class3270; /* The main 3270 data structure. */ struct raw3270 { @@ -86,7 +86,7 @@ DECLARE_WAIT_QUEUE_HEAD(raw3270_wait_que /* * Encode array for 12 bit 3270 addresses. */ -unsigned char raw3270_ebcgraf[64] = { +static unsigned char raw3270_ebcgraf[64] = { 0x40, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, 0xc8, 0xc9, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, 0x50, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, diff --git a/drivers/s390/char/sclp.c b/drivers/s390/char/sclp.c index 8a056df..f171de3 100644 --- a/drivers/s390/char/sclp.c +++ b/drivers/s390/char/sclp.c @@ -59,7 +59,8 @@ static volatile enum sclp_init_state_t { /* Internal state: is a request active at the sclp? */ static volatile enum sclp_running_state_t { sclp_running_state_idle, - sclp_running_state_running + sclp_running_state_running, + sclp_running_state_reset_pending } sclp_running_state = sclp_running_state_idle; /* Internal state: is a read request pending? */ @@ -88,15 +89,15 @@ #define SCLP_MASK_RETRY 3 /* Timeout intervals in seconds.*/ #define SCLP_BUSY_INTERVAL 10 -#define SCLP_RETRY_INTERVAL 15 +#define SCLP_RETRY_INTERVAL 30 static void sclp_process_queue(void); static int sclp_init_mask(int calculate); static int sclp_init(void); /* Perform service call. Return 0 on success, non-zero otherwise. */ -static int -service_call(sclp_cmdw_t command, void *sccb) +int +sclp_service_call(sclp_cmdw_t command, void *sccb) { int cc; @@ -113,19 +114,17 @@ service_call(sclp_cmdw_t command, void * return 0; } -/* Request timeout handler. Restart the request queue. If DATA is non-zero, - * force restart of running request. */ +static inline void __sclp_make_read_req(void); + static void -sclp_request_timeout(unsigned long data) +__sclp_queue_read_req(void) { - unsigned long flags; - - if (data) { - spin_lock_irqsave(&sclp_lock, flags); - sclp_running_state = sclp_running_state_idle; - spin_unlock_irqrestore(&sclp_lock, flags); + if (sclp_reading_state == sclp_reading_state_idle) { + sclp_reading_state = sclp_reading_state_reading; + __sclp_make_read_req(); + /* Add request to head of queue */ + list_add(&sclp_read_req.list, &sclp_req_queue); } - sclp_process_queue(); } /* Set up request retry timer. Called while sclp_lock is locked. */ @@ -140,6 +139,29 @@ __sclp_set_request_timer(unsigned long t add_timer(&sclp_request_timer); } +/* Request timeout handler. Restart the request queue. If DATA is non-zero, + * force restart of running request. */ +static void +sclp_request_timeout(unsigned long data) +{ + unsigned long flags; + + spin_lock_irqsave(&sclp_lock, flags); + if (data) { + if (sclp_running_state == sclp_running_state_running) { + /* Break running state and queue NOP read event request + * to get a defined interface state. */ + __sclp_queue_read_req(); + sclp_running_state = sclp_running_state_idle; + } + } else { + __sclp_set_request_timer(SCLP_BUSY_INTERVAL * HZ, + sclp_request_timeout, 0); + } + spin_unlock_irqrestore(&sclp_lock, flags); + sclp_process_queue(); +} + /* Try to start a request. Return zero if the request was successfully * started or if it will be started at a later time. Return non-zero otherwise. * Called while sclp_lock is locked. */ @@ -151,7 +173,7 @@ __sclp_start_request(struct sclp_req *re if (sclp_running_state != sclp_running_state_idle) return 0; del_timer(&sclp_request_timer); - rc = service_call(req->command, req->sccb); + rc = sclp_service_call(req->command, req->sccb); req->start_count++; if (rc == 0) { @@ -191,7 +213,15 @@ sclp_process_queue(void) rc = __sclp_start_request(req); if (rc == 0) break; - /* Request failed. */ + /* Request failed */ + if (req->start_count > 1) { + /* Cannot abort already submitted request - could still + * be active at the SCLP */ + __sclp_set_request_timer(SCLP_BUSY_INTERVAL * HZ, + sclp_request_timeout, 0); + break; + } + /* Post-processing for aborted request */ list_del(&req->list); if (req->callback) { spin_unlock_irqrestore(&sclp_lock, flags); @@ -221,7 +251,8 @@ sclp_add_request(struct sclp_req *req) list_add_tail(&req->list, &sclp_req_queue); rc = 0; /* Start if request is first in list */ - if (req->list.prev == &sclp_req_queue) { + if (sclp_running_state == sclp_running_state_idle && + req->list.prev == &sclp_req_queue) { rc = __sclp_start_request(req); if (rc) list_del(&req->list); @@ -294,7 +325,7 @@ __sclp_make_read_req(void) sccb = (struct sccb_header *) sclp_read_sccb; clear_page(sccb); memset(&sclp_read_req, 0, sizeof(struct sclp_req)); - sclp_read_req.command = SCLP_CMDW_READDATA; + sclp_read_req.command = SCLP_CMDW_READ_EVENT_DATA; sclp_read_req.status = SCLP_REQ_QUEUED; sclp_read_req.start_count = 0; sclp_read_req.callback = sclp_read_cb; @@ -334,6 +365,8 @@ sclp_interrupt_handler(__u16 code) finished_sccb = S390_lowcore.ext_params & 0xfffffff8; evbuf_pending = S390_lowcore.ext_params & 0x3; if (finished_sccb) { + del_timer(&sclp_request_timer); + sclp_running_state = sclp_running_state_reset_pending; req = __sclp_find_req(finished_sccb); if (req) { /* Request post-processing */ @@ -348,13 +381,8 @@ sclp_interrupt_handler(__u16 code) sclp_running_state = sclp_running_state_idle; } if (evbuf_pending && sclp_receive_mask != 0 && - sclp_reading_state == sclp_reading_state_idle && - sclp_activation_state == sclp_activation_state_active ) { - sclp_reading_state = sclp_reading_state_reading; - __sclp_make_read_req(); - /* Add request to head of queue */ - list_add(&sclp_read_req.list, &sclp_req_queue); - } + sclp_activation_state == sclp_activation_state_active) + __sclp_queue_read_req(); spin_unlock(&sclp_lock); sclp_process_queue(); } @@ -374,6 +402,7 @@ sclp_sync_wait(void) unsigned long flags; unsigned long cr0, cr0_sync; u64 timeout; + int irq_context; /* We'll be disabling timer interrupts, so we need a custom timeout * mechanism */ @@ -386,7 +415,9 @@ sclp_sync_wait(void) } local_irq_save(flags); /* Prevent bottom half from executing once we force interrupts open */ - local_bh_disable(); + irq_context = in_interrupt(); + if (!irq_context) + local_bh_disable(); /* Enable service-signal interruption, disable timer interrupts */ trace_hardirqs_on(); __ctl_store(cr0, 0, 0); @@ -402,19 +433,19 @@ sclp_sync_wait(void) get_clock() > timeout && del_timer(&sclp_request_timer)) sclp_request_timer.function(sclp_request_timer.data); - barrier(); cpu_relax(); } local_irq_disable(); __ctl_load(cr0, 0, 0); - _local_bh_enable(); + if (!irq_context) + _local_bh_enable(); local_irq_restore(flags); } EXPORT_SYMBOL(sclp_sync_wait); /* Dispatch changes in send and receive mask to registered listeners. */ -static inline void +static void sclp_dispatch_state_change(void) { struct list_head *l; @@ -597,7 +628,7 @@ __sclp_make_init_req(u32 receive_mask, u sccb = (struct init_sccb *) sclp_init_sccb; clear_page(sccb); memset(&sclp_init_req, 0, sizeof(struct sclp_req)); - sclp_init_req.command = SCLP_CMDW_WRITEMASK; + sclp_init_req.command = SCLP_CMDW_WRITE_EVENT_MASK; sclp_init_req.status = SCLP_REQ_FILLED; sclp_init_req.start_count = 0; sclp_init_req.callback = NULL; @@ -800,7 +831,7 @@ sclp_check_interface(void) for (retry = 0; retry <= SCLP_INIT_RETRY; retry++) { __sclp_make_init_req(0, 0); sccb = (struct init_sccb *) sclp_init_req.sccb; - rc = service_call(sclp_init_req.command, sccb); + rc = sclp_service_call(sclp_init_req.command, sccb); if (rc == -EIO) break; sclp_init_req.status = SCLP_REQ_RUNNING; diff --git a/drivers/s390/char/sclp.h b/drivers/s390/char/sclp.h index 2c71d6e..7d29ab4 100644 --- a/drivers/s390/char/sclp.h +++ b/drivers/s390/char/sclp.h @@ -12,7 +12,7 @@ #define __SCLP_H__ #include #include - +#include #include /* maximum number of pages concerning our own memory management */ @@ -49,9 +49,11 @@ #define LnTpFlgs_PromptText 0x0800 typedef unsigned int sclp_cmdw_t; -#define SCLP_CMDW_READDATA 0x00770005 -#define SCLP_CMDW_WRITEDATA 0x00760005 -#define SCLP_CMDW_WRITEMASK 0x00780005 +#define SCLP_CMDW_READ_EVENT_DATA 0x00770005 +#define SCLP_CMDW_WRITE_EVENT_DATA 0x00760005 +#define SCLP_CMDW_WRITE_EVENT_MASK 0x00780005 +#define SCLP_CMDW_READ_SCP_INFO 0x00020001 +#define SCLP_CMDW_READ_SCP_INFO_FORCED 0x00120001 #define GDS_ID_MDSMU 0x1310 #define GDS_ID_MDSRouteInfo 0x1311 @@ -66,13 +68,6 @@ #define GDS_KEY_SelfDefTextMsg 0x31 typedef u32 sccb_mask_t; /* ATTENTION: assumes 32bit mask !!! */ -struct sccb_header { - u16 length; - u8 function_code; - u8 control_mask[3]; - u16 response_code; -} __attribute__((packed)); - struct gds_subvector { u8 length; u8 key; @@ -131,6 +126,7 @@ void sclp_unregister(struct sclp_registe int sclp_remove_processed(struct sccb_header *sccb); int sclp_deactivate(void); int sclp_reactivate(void); +int sclp_service_call(sclp_cmdw_t command, void *sccb); /* useful inlines */ diff --git a/drivers/s390/char/sclp_con.c b/drivers/s390/char/sclp_con.c index 86864f6..ead1043 100644 --- a/drivers/s390/char/sclp_con.c +++ b/drivers/s390/char/sclp_con.c @@ -66,7 +66,7 @@ sclp_conbuf_callback(struct sclp_buffer } while (buffer && sclp_emit_buffer(buffer, sclp_conbuf_callback)); } -static inline void +static void sclp_conbuf_emit(void) { struct sclp_buffer* buffer; diff --git a/drivers/s390/char/sclp_cpi.c b/drivers/s390/char/sclp_cpi.c index 4f873ae..65aa2c8 100644 --- a/drivers/s390/char/sclp_cpi.c +++ b/drivers/s390/char/sclp_cpi.c @@ -169,7 +169,7 @@ cpi_prepare_req(void) } /* prepare request data structure presented to SCLP driver */ - req->command = SCLP_CMDW_WRITEDATA; + req->command = SCLP_CMDW_WRITE_EVENT_DATA; req->sccb = sccb; req->status = SCLP_REQ_FILLED; req->callback = cpi_callback; diff --git a/drivers/s390/char/sclp_info.c b/drivers/s390/char/sclp_info.c new file mode 100644 index 0000000..7bcbe64 --- /dev/null +++ b/drivers/s390/char/sclp_info.c @@ -0,0 +1,57 @@ +/* + * drivers/s390/char/sclp_info.c + * + * Copyright IBM Corp. 2007 + * Author(s): Heiko Carstens + */ + +#include +#include +#include +#include +#include "sclp.h" + +struct sclp_readinfo_sccb s390_readinfo_sccb; + +void __init sclp_readinfo_early(void) +{ + sclp_cmdw_t command; + struct sccb_header *sccb; + int ret; + + __ctl_set_bit(0, 9); /* enable service signal subclass mask */ + + sccb = &s390_readinfo_sccb.header; + command = SCLP_CMDW_READ_SCP_INFO_FORCED; + while (1) { + u16 response; + + memset(&s390_readinfo_sccb, 0, sizeof(s390_readinfo_sccb)); + sccb->length = sizeof(s390_readinfo_sccb); + sccb->control_mask[2] = 0x80; + + ret = sclp_service_call(command, &s390_readinfo_sccb); + + if (ret == -EIO) + goto out; + if (ret == -EBUSY) + continue; + + __load_psw_mask(PSW_BASE_BITS | PSW_MASK_EXT | + PSW_MASK_WAIT | PSW_DEFAULT_KEY); + local_irq_disable(); + barrier(); + + response = sccb->response_code; + + if (response == 0x10) + break; + + if (response != 0x1f0 || command == SCLP_CMDW_READ_SCP_INFO) + break; + + command = SCLP_CMDW_READ_SCP_INFO; + } +out: + __ctl_clear_bit(0, 9); /* disable service signal subclass mask */ +} diff --git a/drivers/s390/char/sclp_rw.c b/drivers/s390/char/sclp_rw.c index 0c92d39..2486783 100644 --- a/drivers/s390/char/sclp_rw.c +++ b/drivers/s390/char/sclp_rw.c @@ -460,7 +460,7 @@ sclp_emit_buffer(struct sclp_buffer *buf sccb->msg_buf.header.type = EvTyp_PMsgCmd; else return -ENOSYS; - buffer->request.command = SCLP_CMDW_WRITEDATA; + buffer->request.command = SCLP_CMDW_WRITE_EVENT_DATA; buffer->request.status = SCLP_REQ_FILLED; buffer->request.callback = sclp_writedata_callback; buffer->request.callback_data = buffer; diff --git a/drivers/s390/char/sclp_tty.c b/drivers/s390/char/sclp_tty.c index 2d173e5..076816b 100644 --- a/drivers/s390/char/sclp_tty.c +++ b/drivers/s390/char/sclp_tty.c @@ -13,7 +13,6 @@ #include #include #include #include -#include #include #include #include @@ -721,7 +720,7 @@ static const struct tty_operations sclp_ .ioctl = sclp_tty_ioctl, }; -int __init +static int __init sclp_tty_init(void) { struct tty_driver *driver; diff --git a/drivers/s390/char/sclp_vt220.c b/drivers/s390/char/sclp_vt220.c index 723bf41..f77dc33 100644 --- a/drivers/s390/char/sclp_vt220.c +++ b/drivers/s390/char/sclp_vt220.c @@ -16,7 +16,6 @@ #include #include #include #include -#include #include #include #include @@ -207,7 +206,7 @@ __sclp_vt220_emit(struct sclp_vt220_requ request->sclp_req.status = SCLP_REQ_FAILED; return -EIO; } - request->sclp_req.command = SCLP_CMDW_WRITEDATA; + request->sclp_req.command = SCLP_CMDW_WRITE_EVENT_DATA; request->sclp_req.status = SCLP_REQ_FILLED; request->sclp_req.callback = sclp_vt220_callback; request->sclp_req.callback_data = (void *) request; @@ -669,7 +668,7 @@ static const struct tty_operations sclp_ /* * Register driver with SCLP and Linux and initialize internal tty structures. */ -int __init +static int __init sclp_vt220_tty_init(void) { struct tty_driver *driver; diff --git a/drivers/s390/char/tape.h b/drivers/s390/char/tape.h index c9f1c4c..bb4ff53 100644 --- a/drivers/s390/char/tape.h +++ b/drivers/s390/char/tape.h @@ -3,7 +3,7 @@ * tape device driver for 3480/3490E/3590 tapes. * * S390 and zSeries version - * Copyright (C) 2001,2005 IBM Deutschland Entwicklung GmbH, IBM Corporation + * Copyright IBM Corp. 2001,2006 * Author(s): Carsten Otte * Tuan Ngo-Anh * Martin Schwidefsky @@ -99,7 +99,11 @@ enum tape_op { TO_DIS, /* Tape display */ TO_ASSIGN, /* Assign tape to channel path */ TO_UNASSIGN, /* Unassign tape from channel path */ - TO_SIZE /* #entries in tape_op_t */ + TO_CRYPT_ON, /* Enable encrpytion */ + TO_CRYPT_OFF, /* Disable encrpytion */ + TO_KEKL_SET, /* Set KEK label */ + TO_KEKL_QUERY, /* Query KEK label */ + TO_SIZE, /* #entries in tape_op_t */ }; /* Forward declaration */ @@ -112,6 +116,7 @@ enum tape_request_status { TAPE_REQUEST_IN_IO, /* request is currently in IO */ TAPE_REQUEST_DONE, /* request is completed. */ TAPE_REQUEST_CANCEL, /* request should be canceled. */ + TAPE_REQUEST_LONG_BUSY, /* request has to be restarted after long busy */ }; /* Tape CCW request */ @@ -164,10 +169,11 @@ #endif * The discipline irq function either returns an error code (<0) which * means that the request has failed with an error or one of the following: */ -#define TAPE_IO_SUCCESS 0 /* request successful */ -#define TAPE_IO_PENDING 1 /* request still running */ -#define TAPE_IO_RETRY 2 /* retry to current request */ -#define TAPE_IO_STOP 3 /* stop the running request */ +#define TAPE_IO_SUCCESS 0 /* request successful */ +#define TAPE_IO_PENDING 1 /* request still running */ +#define TAPE_IO_RETRY 2 /* retry to current request */ +#define TAPE_IO_STOP 3 /* stop the running request */ +#define TAPE_IO_LONG_BUSY 4 /* delay the running request */ /* Char Frontend Data */ struct tape_char_data { @@ -242,6 +248,10 @@ #endif /* Function to start or stop the next request later. */ struct delayed_work tape_dnr; + + /* Timer for long busy */ + struct timer_list lb_timeout; + }; /* Externals from tape_core.c */ diff --git a/drivers/s390/char/tape_3590.c b/drivers/s390/char/tape_3590.c index 9df912f..50f5eda 100644 --- a/drivers/s390/char/tape_3590.c +++ b/drivers/s390/char/tape_3590.c @@ -2,7 +2,7 @@ * drivers/s390/char/tape_3590.c * tape device discipline for 3590 tapes. * - * Copyright (C) IBM Corp. 2001,2006 + * Copyright IBM Corp. 2001,2006 * Author(s): Stefan Bader * Michael Holzheu * Martin Schwidefsky @@ -11,6 +11,7 @@ #include #include #include +#include #define TAPE_DBF_AREA tape_3590_dbf @@ -30,7 +31,7 @@ EXPORT_SYMBOL(TAPE_DBF_AREA); * - Read Device (buffered) log: BRA * - Read Library log: BRA * - Swap Devices: BRA - * - Long Busy: BRA + * - Long Busy: implemented * - Special Intercept: BRA * - Read Alternate: implemented *******************************************************************/ @@ -94,6 +95,332 @@ static const char *tape_3590_msg[TAPE_35 [0xae] = "Subsystem environmental alert", }; +static int crypt_supported(struct tape_device *device) +{ + return TAPE390_CRYPT_SUPPORTED(TAPE_3590_CRYPT_INFO(device)); +} + +static int crypt_enabled(struct tape_device *device) +{ + return TAPE390_CRYPT_ON(TAPE_3590_CRYPT_INFO(device)); +} + +static void ext_to_int_kekl(struct tape390_kekl *in, + struct tape3592_kekl *out) +{ + int i; + + memset(out, 0, sizeof(*out)); + if (in->type == TAPE390_KEKL_TYPE_HASH) + out->flags |= 0x40; + if (in->type_on_tape == TAPE390_KEKL_TYPE_HASH) + out->flags |= 0x80; + strncpy(out->label, in->label, 64); + for (i = strlen(in->label); i < sizeof(out->label); i++) + out->label[i] = ' '; + ASCEBC(out->label, sizeof(out->label)); +} + +static void int_to_ext_kekl(struct tape3592_kekl *in, + struct tape390_kekl *out) +{ + memset(out, 0, sizeof(*out)); + if(in->flags & 0x40) + out->type = TAPE390_KEKL_TYPE_HASH; + else + out->type = TAPE390_KEKL_TYPE_LABEL; + if(in->flags & 0x80) + out->type_on_tape = TAPE390_KEKL_TYPE_HASH; + else + out->type_on_tape = TAPE390_KEKL_TYPE_LABEL; + memcpy(out->label, in->label, sizeof(in->label)); + EBCASC(out->label, sizeof(in->label)); + strstrip(out->label); +} + +static void int_to_ext_kekl_pair(struct tape3592_kekl_pair *in, + struct tape390_kekl_pair *out) +{ + if (in->count == 0) { + out->kekl[0].type = TAPE390_KEKL_TYPE_NONE; + out->kekl[0].type_on_tape = TAPE390_KEKL_TYPE_NONE; + out->kekl[1].type = TAPE390_KEKL_TYPE_NONE; + out->kekl[1].type_on_tape = TAPE390_KEKL_TYPE_NONE; + } else if (in->count == 1) { + int_to_ext_kekl(&in->kekl[0], &out->kekl[0]); + out->kekl[1].type = TAPE390_KEKL_TYPE_NONE; + out->kekl[1].type_on_tape = TAPE390_KEKL_TYPE_NONE; + } else if (in->count == 2) { + int_to_ext_kekl(&in->kekl[0], &out->kekl[0]); + int_to_ext_kekl(&in->kekl[1], &out->kekl[1]); + } else { + printk("Invalid KEKL number: %d\n", in->count); + BUG(); + } +} + +static int check_ext_kekl(struct tape390_kekl *kekl) +{ + if (kekl->type == TAPE390_KEKL_TYPE_NONE) + goto invalid; + if (kekl->type > TAPE390_KEKL_TYPE_HASH) + goto invalid; + if (kekl->type_on_tape == TAPE390_KEKL_TYPE_NONE) + goto invalid; + if (kekl->type_on_tape > TAPE390_KEKL_TYPE_HASH) + goto invalid; + if ((kekl->type == TAPE390_KEKL_TYPE_HASH) && + (kekl->type_on_tape == TAPE390_KEKL_TYPE_LABEL)) + goto invalid; + + return 0; +invalid: + return -EINVAL; +} + +static int check_ext_kekl_pair(struct tape390_kekl_pair *kekls) +{ + if (check_ext_kekl(&kekls->kekl[0])) + goto invalid; + if (check_ext_kekl(&kekls->kekl[1])) + goto invalid; + + return 0; +invalid: + return -EINVAL; +} + +/* + * Query KEKLs + */ +static int tape_3592_kekl_query(struct tape_device *device, + struct tape390_kekl_pair *ext_kekls) +{ + struct tape_request *request; + struct tape3592_kekl_query_order *order; + struct tape3592_kekl_query_data *int_kekls; + int rc; + + DBF_EVENT(6, "tape3592_kekl_query\n"); + int_kekls = kmalloc(sizeof(*int_kekls), GFP_KERNEL|GFP_DMA); + if (!int_kekls) + return -ENOMEM; + request = tape_alloc_request(2, sizeof(*order)); + if (IS_ERR(request)) { + rc = PTR_ERR(request); + goto fail_malloc; + } + order = request->cpdata; + memset(order,0,sizeof(*order)); + order->code = 0xe2; + order->max_count = 2; + request->op = TO_KEKL_QUERY; + tape_ccw_cc(request->cpaddr, PERF_SUBSYS_FUNC, sizeof(*order), order); + tape_ccw_end(request->cpaddr + 1, READ_SS_DATA, sizeof(*int_kekls), + int_kekls); + rc = tape_do_io(device, request); + if (rc) + goto fail_request; + int_to_ext_kekl_pair(&int_kekls->kekls, ext_kekls); + + rc = 0; +fail_request: + tape_free_request(request); +fail_malloc: + kfree(int_kekls); + return rc; +} + +/* + * IOCTL: Query KEKLs + */ +static int tape_3592_ioctl_kekl_query(struct tape_device *device, + unsigned long arg) +{ + int rc; + struct tape390_kekl_pair *ext_kekls; + + DBF_EVENT(6, "tape_3592_ioctl_kekl_query\n"); + if (!crypt_supported(device)) + return -ENOSYS; + if (!crypt_enabled(device)) + return -EUNATCH; + ext_kekls = kmalloc(sizeof(*ext_kekls), GFP_KERNEL); + if (!ext_kekls) + return -ENOMEM; + rc = tape_3592_kekl_query(device, ext_kekls); + if (rc != 0) + goto fail; + if (copy_to_user((char __user *) arg, ext_kekls, sizeof(*ext_kekls))) { + rc = -EFAULT; + goto fail; + } + rc = 0; +fail: + kfree(ext_kekls); + return rc; +} + +static int tape_3590_mttell(struct tape_device *device, int mt_count); + +/* + * Set KEKLs + */ +static int tape_3592_kekl_set(struct tape_device *device, + struct tape390_kekl_pair *ext_kekls) +{ + struct tape_request *request; + struct tape3592_kekl_set_order *order; + + DBF_EVENT(6, "tape3592_kekl_set\n"); + if (check_ext_kekl_pair(ext_kekls)) { + DBF_EVENT(6, "invalid kekls\n"); + return -EINVAL; + } + if (tape_3590_mttell(device, 0) != 0) + return -EBADSLT; + request = tape_alloc_request(1, sizeof(*order)); + if (IS_ERR(request)) + return PTR_ERR(request); + order = request->cpdata; + memset(order, 0, sizeof(*order)); + order->code = 0xe3; + order->kekls.count = 2; + ext_to_int_kekl(&ext_kekls->kekl[0], &order->kekls.kekl[0]); + ext_to_int_kekl(&ext_kekls->kekl[1], &order->kekls.kekl[1]); + request->op = TO_KEKL_SET; + tape_ccw_end(request->cpaddr, PERF_SUBSYS_FUNC, sizeof(*order), order); + + return tape_do_io_free(device, request); +} + +/* + * IOCTL: Set KEKLs + */ +static int tape_3592_ioctl_kekl_set(struct tape_device *device, + unsigned long arg) +{ + int rc; + struct tape390_kekl_pair *ext_kekls; + + DBF_EVENT(6, "tape_3592_ioctl_kekl_set\n"); + if (!crypt_supported(device)) + return -ENOSYS; + if (!crypt_enabled(device)) + return -EUNATCH; + ext_kekls = kmalloc(sizeof(*ext_kekls), GFP_KERNEL); + if (!ext_kekls) + return -ENOMEM; + if (copy_from_user(ext_kekls, (char __user *)arg, sizeof(*ext_kekls))) { + rc = -EFAULT; + goto out; + } + rc = tape_3592_kekl_set(device, ext_kekls); +out: + kfree(ext_kekls); + return rc; +} + +/* + * Enable encryption + */ +static int tape_3592_enable_crypt(struct tape_device *device) +{ + struct tape_request *request; + char *data; + + DBF_EVENT(6, "tape_3592_enable_crypt\n"); + if (!crypt_supported(device)) + return -ENOSYS; + request = tape_alloc_request(2, 72); + if (IS_ERR(request)) + return PTR_ERR(request); + data = request->cpdata; + memset(data,0,72); + + data[0] = 0x05; + data[36 + 0] = 0x03; + data[36 + 1] = 0x03; + data[36 + 4] = 0x40; + data[36 + 6] = 0x01; + data[36 + 14] = 0x2f; + data[36 + 18] = 0xc3; + data[36 + 35] = 0x72; + request->op = TO_CRYPT_ON; + tape_ccw_cc(request->cpaddr, MODE_SET_CB, 36, data); + tape_ccw_end(request->cpaddr + 1, MODE_SET_CB, 36, data + 36); + return tape_do_io_free(device, request); +} + +/* + * Disable encryption + */ +static int tape_3592_disable_crypt(struct tape_device *device) +{ + struct tape_request *request; + char *data; + + DBF_EVENT(6, "tape_3592_disable_crypt\n"); + if (!crypt_supported(device)) + return -ENOSYS; + request = tape_alloc_request(2, 72); + if (IS_ERR(request)) + return PTR_ERR(request); + data = request->cpdata; + memset(data,0,72); + + data[0] = 0x05; + data[36 + 0] = 0x03; + data[36 + 1] = 0x03; + data[36 + 35] = 0x32; + + request->op = TO_CRYPT_OFF; + tape_ccw_cc(request->cpaddr, MODE_SET_CB, 36, data); + tape_ccw_end(request->cpaddr + 1, MODE_SET_CB, 36, data + 36); + + return tape_do_io_free(device, request); +} + +/* + * IOCTL: Set encryption status + */ +static int tape_3592_ioctl_crypt_set(struct tape_device *device, + unsigned long arg) +{ + struct tape390_crypt_info info; + + DBF_EVENT(6, "tape_3592_ioctl_crypt_set\n"); + if (!crypt_supported(device)) + return -ENOSYS; + if (copy_from_user(&info, (char __user *)arg, sizeof(info))) + return -EFAULT; + if (info.status & ~TAPE390_CRYPT_ON_MASK) + return -EINVAL; + if (info.status & TAPE390_CRYPT_ON_MASK) + return tape_3592_enable_crypt(device); + else + return tape_3592_disable_crypt(device); +} + +static int tape_3590_sense_medium(struct tape_device *device); + +/* + * IOCTL: Query enryption status + */ +static int tape_3592_ioctl_crypt_query(struct tape_device *device, + unsigned long arg) +{ + DBF_EVENT(6, "tape_3592_ioctl_crypt_query\n"); + if (!crypt_supported(device)) + return -ENOSYS; + tape_3590_sense_medium(device); + if (copy_to_user((char __user *) arg, &TAPE_3590_CRYPT_INFO(device), + sizeof(TAPE_3590_CRYPT_INFO(device)))) + return -EFAULT; + else + return 0; +} + /* * 3590 IOCTL Overload */ @@ -109,6 +436,14 @@ tape_3590_ioctl(struct tape_device *devi return tape_std_display(device, &disp); } + case TAPE390_KEKL_SET: + return tape_3592_ioctl_kekl_set(device, arg); + case TAPE390_KEKL_QUERY: + return tape_3592_ioctl_kekl_query(device, arg); + case TAPE390_CRYPT_SET: + return tape_3592_ioctl_crypt_set(device, arg); + case TAPE390_CRYPT_QUERY: + return tape_3592_ioctl_crypt_query(device, arg); default: return -EINVAL; /* no additional ioctls */ } @@ -248,6 +583,12 @@ tape_3590_work_handler(struct work_struc case TO_READ_ATTMSG: tape_3590_read_attmsg(p->device); break; + case TO_CRYPT_ON: + tape_3592_enable_crypt(p->device); + break; + case TO_CRYPT_OFF: + tape_3592_disable_crypt(p->device); + break; default: DBF_EVENT(3, "T3590: work handler undefined for " "operation 0x%02x\n", p->op); @@ -365,6 +706,33 @@ tape_3590_check_locate(struct tape_devic } #endif +static void tape_3590_med_state_set(struct tape_device *device, + struct tape_3590_med_sense *sense) +{ + struct tape390_crypt_info *c_info; + + c_info = &TAPE_3590_CRYPT_INFO(device); + + if (sense->masst == MSENSE_UNASSOCIATED) { + tape_med_state_set(device, MS_UNLOADED); + TAPE_3590_CRYPT_INFO(device).medium_status = 0; + return; + } + if (sense->masst != MSENSE_ASSOCIATED_MOUNT) { + PRINT_ERR("Unknown medium state: %x\n", sense->masst); + return; + } + tape_med_state_set(device, MS_LOADED); + c_info->medium_status |= TAPE390_MEDIUM_LOADED_MASK; + if (sense->flags & MSENSE_CRYPT_MASK) { + PRINT_INFO("Medium is encrypted (%04x)\n", sense->flags); + c_info->medium_status |= TAPE390_MEDIUM_ENCRYPTED_MASK; + } else { + DBF_EVENT(6, "Medium is not encrypted %04x\n", sense->flags); + c_info->medium_status &= ~TAPE390_MEDIUM_ENCRYPTED_MASK; + } +} + /* * The done handler is called at device/channel end and wakes up the sleeping * process @@ -372,9 +740,10 @@ #endif static int tape_3590_done(struct tape_device *device, struct tape_request *request) { - struct tape_3590_med_sense *sense; + struct tape_3590_disc_data *disc_data; DBF_EVENT(6, "%s done\n", tape_op_verbose[request->op]); + disc_data = device->discdata; switch (request->op) { case TO_BSB: @@ -394,13 +763,20 @@ tape_3590_done(struct tape_device *devic break; case TO_RUN: tape_med_state_set(device, MS_UNLOADED); + tape_3590_schedule_work(device, TO_CRYPT_OFF); break; case TO_MSEN: - sense = (struct tape_3590_med_sense *) request->cpdata; - if (sense->masst == MSENSE_UNASSOCIATED) - tape_med_state_set(device, MS_UNLOADED); - if (sense->masst == MSENSE_ASSOCIATED_MOUNT) - tape_med_state_set(device, MS_LOADED); + tape_3590_med_state_set(device, request->cpdata); + break; + case TO_CRYPT_ON: + TAPE_3590_CRYPT_INFO(device).status + |= TAPE390_CRYPT_ON_MASK; + *(device->modeset_byte) |= 0x03; + break; + case TO_CRYPT_OFF: + TAPE_3590_CRYPT_INFO(device).status + &= ~TAPE390_CRYPT_ON_MASK; + *(device->modeset_byte) &= ~0x03; break; case TO_RBI: /* RBI seems to succeed even without medium loaded. */ case TO_NOP: /* Same to NOP. */ @@ -409,8 +785,9 @@ tape_3590_done(struct tape_device *devic case TO_DIS: case TO_ASSIGN: case TO_UNASSIGN: - break; case TO_SIZE: + case TO_KEKL_SET: + case TO_KEKL_QUERY: break; } return TAPE_IO_SUCCESS; @@ -540,10 +917,8 @@ static int tape_3590_erp_long_busy(struct tape_device *device, struct tape_request *request, struct irb *irb) { - /* FIXME: how about WAITING for a minute ? */ - PRINT_WARN("(%s): Device is busy! Please wait a minute!\n", - device->cdev->dev.bus_id); - return tape_3590_erp_basic(device, request, irb, -EBUSY); + DBF_EVENT(6, "Device is busy\n"); + return TAPE_IO_LONG_BUSY; } /* @@ -951,6 +1326,34 @@ tape_3590_print_era_msg(struct tape_devi device->cdev->dev.bus_id, sense->mc); } +static int tape_3590_crypt_error(struct tape_device *device, + struct tape_request *request, struct irb *irb) +{ + u8 cu_rc, ekm_rc1; + u16 ekm_rc2; + u32 drv_rc; + char *bus_id, *sense; + + sense = ((struct tape_3590_sense *) irb->ecw)->fmt.data; + bus_id = device->cdev->dev.bus_id; + cu_rc = sense[0]; + drv_rc = *((u32*) &sense[5]) & 0xffffff; + ekm_rc1 = sense[9]; + ekm_rc2 = *((u16*) &sense[10]); + if ((cu_rc == 0) && (ekm_rc2 == 0xee31)) + /* key not defined on EKM */ + return tape_3590_erp_basic(device, request, irb, -EKEYREJECTED); + if ((cu_rc == 1) || (cu_rc == 2)) + /* No connection to EKM */ + return tape_3590_erp_basic(device, request, irb, -ENOTCONN); + + PRINT_ERR("(%s): Unable to get encryption key from EKM\n", bus_id); + PRINT_ERR("(%s): CU=%02X DRIVE=%06X EKM=%02X:%04X\n", bus_id, cu_rc, + drv_rc, ekm_rc1, ekm_rc2); + + return tape_3590_erp_basic(device, request, irb, -ENOKEY); +} + /* * 3590 error Recovery routine: * If possible, it tries to recover from the error. If this is not possible, @@ -979,6 +1382,8 @@ #endif sense = (struct tape_3590_sense *) irb->ecw; + DBF_EVENT(6, "Unit Check: RQC = %x\n", sense->rc_rqc); + /* * First check all RC-QRCs where we want to do something special * - "break": basic error recovery is done @@ -999,6 +1404,8 @@ #endif case 0x2231: tape_3590_print_era_msg(device, irb); return tape_3590_erp_special_interrupt(device, request, irb); + case 0x2240: + return tape_3590_crypt_error(device, request, irb); case 0x3010: DBF_EVENT(2, "(%08x): Backward at Beginning of Partition\n", @@ -1020,6 +1427,7 @@ #endif DBF_EVENT(2, "(%08x): Rewind Unload complete\n", device->cdev_id); tape_med_state_set(device, MS_UNLOADED); + tape_3590_schedule_work(device, TO_CRYPT_OFF); return tape_3590_erp_basic(device, request, irb, 0); case 0x4010: @@ -1030,9 +1438,15 @@ #endif PRINT_WARN("(%s): Tape operation when medium not loaded\n", device->cdev->dev.bus_id); tape_med_state_set(device, MS_UNLOADED); + tape_3590_schedule_work(device, TO_CRYPT_OFF); return tape_3590_erp_basic(device, request, irb, -ENOMEDIUM); case 0x4012: /* Device Long Busy */ + /* XXX: Also use long busy handling here? */ + DBF_EVENT(6, "(%08x): LONG BUSY\n", device->cdev_id); tape_3590_print_era_msg(device, irb); + return tape_3590_erp_basic(device, request, irb, -EBUSY); + case 0x4014: + DBF_EVENT(6, "(%08x): Crypto LONG BUSY\n", device->cdev_id); return tape_3590_erp_long_busy(device, request, irb); case 0x5010: @@ -1064,6 +1478,7 @@ #endif case 0x5120: case 0x1120: tape_med_state_set(device, MS_UNLOADED); + tape_3590_schedule_work(device, TO_CRYPT_OFF); return tape_3590_erp_basic(device, request, irb, -ENOMEDIUM); case 0x6020: @@ -1142,21 +1557,47 @@ tape_3590_setup_device(struct tape_devic { int rc; struct tape_3590_disc_data *data; + char *rdc_data; DBF_EVENT(6, "3590 device setup\n"); - data = kmalloc(sizeof(struct tape_3590_disc_data), - GFP_KERNEL | GFP_DMA); + data = kzalloc(sizeof(struct tape_3590_disc_data), GFP_KERNEL | GFP_DMA); if (data == NULL) return -ENOMEM; data->read_back_op = READ_PREVIOUS; device->discdata = data; - if ((rc = tape_std_assign(device)) == 0) { - /* Try to find out if medium is loaded */ - if ((rc = tape_3590_sense_medium(device)) != 0) - DBF_LH(3, "3590 medium sense returned %d\n", rc); + rdc_data = kmalloc(64, GFP_KERNEL | GFP_DMA); + if (!rdc_data) { + rc = -ENOMEM; + goto fail_kmalloc; + } + rc = read_dev_chars(device->cdev, (void**)&rdc_data, 64); + if (rc) { + DBF_LH(3, "Read device characteristics failed!\n"); + goto fail_kmalloc; + } + rc = tape_std_assign(device); + if (rc) + goto fail_rdc_data; + if (rdc_data[31] == 0x13) { + PRINT_INFO("Device has crypto support\n"); + data->crypt_info.capability |= TAPE390_CRYPT_SUPPORTED_MASK; + tape_3592_disable_crypt(device); + } else { + DBF_EVENT(6, "Device has NO crypto support\n"); } + /* Try to find out if medium is loaded */ + rc = tape_3590_sense_medium(device); + if (rc) { + DBF_LH(3, "3590 medium sense returned %d\n", rc); + goto fail_rdc_data; + } + return 0; +fail_rdc_data: + kfree(rdc_data); +fail_kmalloc: + kfree(data); return rc; } diff --git a/drivers/s390/char/tape_3590.h b/drivers/s390/char/tape_3590.h index cf274b9..aa51388 100644 --- a/drivers/s390/char/tape_3590.h +++ b/drivers/s390/char/tape_3590.h @@ -2,7 +2,7 @@ * drivers/s390/char/tape_3590.h * tape device discipline for 3590 tapes. * - * Copyright (C) IBM Corp. 2001,2006 + * Copyright IBM Corp. 2001,2006 * Author(s): Stefan Bader * Michael Holzheu * Martin Schwidefsky @@ -38,16 +38,22 @@ #define SENSE_FMT_SIM 0x71 #define MSENSE_UNASSOCIATED 0x00 #define MSENSE_ASSOCIATED_MOUNT 0x01 #define MSENSE_ASSOCIATED_UMOUNT 0x02 +#define MSENSE_CRYPT_MASK 0x00000010 #define TAPE_3590_MAX_MSG 0xb0 /* Datatypes */ struct tape_3590_disc_data { - unsigned char modeset_byte; + struct tape390_crypt_info crypt_info; int read_back_op; }; +#define TAPE_3590_CRYPT_INFO(device) \ + ((struct tape_3590_disc_data*)(device->discdata))->crypt_info +#define TAPE_3590_READ_BACK_OP(device) \ + ((struct tape_3590_disc_data*)(device->discdata))->read_back_op + struct tape_3590_sense { unsigned int command_rej:1; @@ -118,7 +124,48 @@ struct tape_3590_sense { struct tape_3590_med_sense { unsigned int macst:4; unsigned int masst:4; - char pad[127]; + char pad1[7]; + unsigned int flags; + char pad2[116]; +} __attribute__ ((packed)); + +/* Datastructures for 3592 encryption support */ + +struct tape3592_kekl { + __u8 flags; + char label[64]; +} __attribute__ ((packed)); + +struct tape3592_kekl_pair { + __u8 count; + struct tape3592_kekl kekl[2]; +} __attribute__ ((packed)); + +struct tape3592_kekl_query_data { + __u16 len; + __u8 fmt; + __u8 mc; + __u32 id; + __u8 flags; + struct tape3592_kekl_pair kekls; + char reserved[116]; +} __attribute__ ((packed)); + +struct tape3592_kekl_query_order { + __u8 code; + __u8 flags; + char reserved1[2]; + __u8 max_count; + char reserved2[35]; +} __attribute__ ((packed)); + +struct tape3592_kekl_set_order { + __u8 code; + __u8 flags; + char reserved1[2]; + __u8 op; + struct tape3592_kekl_pair kekls; + char reserved2[120]; } __attribute__ ((packed)); #endif /* _TAPE_3590_H */ diff --git a/drivers/s390/char/tape_block.c b/drivers/s390/char/tape_block.c index c8a89b3..dd0ecae 100644 --- a/drivers/s390/char/tape_block.c +++ b/drivers/s390/char/tape_block.c @@ -73,7 +73,7 @@ tapeblock_trigger_requeue(struct tape_de /* * Post finished request. */ -static inline void +static void tapeblock_end_request(struct request *req, int uptodate) { if (end_that_request_first(req, uptodate, req->hard_nr_sectors)) @@ -108,7 +108,7 @@ __tapeblock_end_request(struct tape_requ /* * Feed the tape device CCW queue with requests supplied in a list. */ -static inline int +static int tapeblock_start_request(struct tape_device *device, struct request *req) { struct tape_request * ccw_req; diff --git a/drivers/s390/char/tape_char.c b/drivers/s390/char/tape_char.c index 31198c8..b830a8c 100644 --- a/drivers/s390/char/tape_char.c +++ b/drivers/s390/char/tape_char.c @@ -3,7 +3,7 @@ * character device frontend for tape device driver * * S390 and zSeries version - * Copyright (C) 2001,2002 IBM Deutschland Entwicklung GmbH, IBM Corporation + * Copyright IBM Corp. 2001,2006 * Author(s): Carsten Otte * Michael Holzheu * Tuan Ngo-Anh @@ -39,7 +39,7 @@ static int tapechar_ioctl(struct inode * static long tapechar_compat_ioctl(struct file *, unsigned int, unsigned long); -static struct file_operations tape_fops = +static const struct file_operations tape_fops = { .owner = THIS_MODULE, .read = tapechar_read, @@ -89,22 +89,7 @@ tapechar_cleanup_device(struct tape_devi device->nt = NULL; } -/* - * Terminate write command (we write two TMs and skip backward over last) - * This ensures that the tape is always correctly terminated. - * When the user writes afterwards a new file, he will overwrite the - * second TM and therefore one TM will remain to separate the - * two files on the tape... - */ -static inline void -tapechar_terminate_write(struct tape_device *device) -{ - if (tape_mtop(device, MTWEOF, 1) == 0 && - tape_mtop(device, MTWEOF, 1) == 0) - tape_mtop(device, MTBSR, 1); -} - -static inline int +static int tapechar_check_idalbuffer(struct tape_device *device, size_t block_size) { struct idal_buffer *new; @@ -137,7 +122,7 @@ tapechar_check_idalbuffer(struct tape_de /* * Tape device read function */ -ssize_t +static ssize_t tapechar_read(struct file *filp, char __user *data, size_t count, loff_t *ppos) { struct tape_device *device; @@ -201,7 +186,7 @@ #endif /* * Tape device write function */ -ssize_t +static ssize_t tapechar_write(struct file *filp, const char __user *data, size_t count, loff_t *ppos) { struct tape_device *device; @@ -291,7 +276,7 @@ #endif /* * Character frontend tape device open function. */ -int +static int tapechar_open (struct inode *inode, struct file *filp) { struct tape_device *device; @@ -326,7 +311,7 @@ tapechar_open (struct inode *inode, stru * Character frontend tape device release function. */ -int +static int tapechar_release(struct inode *inode, struct file *filp) { struct tape_device *device; diff --git a/drivers/s390/char/tape_class.c b/drivers/s390/char/tape_class.c index 56b8761..2e0d297 100644 --- a/drivers/s390/char/tape_class.c +++ b/drivers/s390/char/tape_class.c @@ -36,7 +36,7 @@ static struct class *tape_class; struct tape_class_device *register_tape_dev( struct device * device, dev_t dev, - struct file_operations *fops, + const struct file_operations *fops, char * device_name, char * mode_name) { diff --git a/drivers/s390/char/tape_class.h b/drivers/s390/char/tape_class.h index 3d0ca05..a8bd9b4 100644 --- a/drivers/s390/char/tape_class.h +++ b/drivers/s390/char/tape_class.h @@ -52,7 +52,7 @@ struct tape_class_device { struct tape_class_device *register_tape_dev( struct device * device, dev_t dev, - struct file_operations *fops, + const struct file_operations *fops, char * device_name, char * node_name ); diff --git a/drivers/s390/char/tape_core.c b/drivers/s390/char/tape_core.c index c6c2e91..e2a8a1a 100644 --- a/drivers/s390/char/tape_core.c +++ b/drivers/s390/char/tape_core.c @@ -3,7 +3,7 @@ * basic function of the tape device driver * * S390 and zSeries version - * Copyright (C) 2001,2005 IBM Deutschland Entwicklung GmbH, IBM Corporation + * Copyright IBM Corp. 2001,2006 * Author(s): Carsten Otte * Michael Holzheu * Tuan Ngo-Anh @@ -26,9 +26,11 @@ #include "tape.h" #include "tape_std.h" #define PRINTK_HEADER "TAPE_CORE: " +#define LONG_BUSY_TIMEOUT 180 /* seconds */ static void __tape_do_irq (struct ccw_device *, unsigned long, struct irb *); static void tape_delayed_next_request(struct work_struct *); +static void tape_long_busy_timeout(unsigned long data); /* * One list to contain all tape devices of all disciplines, so @@ -69,10 +71,12 @@ const char *tape_op_verbose[TO_SIZE] = [TO_LOAD] = "LOA", [TO_READ_CONFIG] = "RCF", [TO_READ_ATTMSG] = "RAT", [TO_DIS] = "DIS", [TO_ASSIGN] = "ASS", - [TO_UNASSIGN] = "UAS" + [TO_UNASSIGN] = "UAS", [TO_CRYPT_ON] = "CON", + [TO_CRYPT_OFF] = "COF", [TO_KEKL_SET] = "KLS", + [TO_KEKL_QUERY] = "KLQ", }; -static inline int +static int busid_to_int(char *bus_id) { int dec; @@ -252,7 +256,7 @@ tape_med_state_set(struct tape_device *d /* * Stop running ccw. Has to be called with the device lock held. */ -static inline int +static int __tape_cancel_io(struct tape_device *device, struct tape_request *request) { int retries; @@ -346,6 +350,9 @@ tape_generic_online(struct tape_device * return -EINVAL; } + init_timer(&device->lb_timeout); + device->lb_timeout.function = tape_long_busy_timeout; + /* Let the discipline have a go at the device. */ device->discipline = discipline; if (!try_module_get(discipline->owner)) { @@ -385,7 +392,7 @@ out: return rc; } -static inline void +static void tape_cleanup_device(struct tape_device *device) { tapeblock_cleanup_device(device); @@ -563,7 +570,7 @@ tape_generic_probe(struct ccw_device *cd return ret; } -static inline void +static void __tape_discard_requests(struct tape_device *device) { struct tape_request * request; @@ -703,7 +710,7 @@ tape_free_request (struct tape_request * kfree(request); } -static inline int +static int __tape_start_io(struct tape_device *device, struct tape_request *request) { int rc; @@ -733,7 +740,7 @@ #endif return rc; } -static inline void +static void __tape_start_next_request(struct tape_device *device) { struct list_head *l, *n; @@ -801,7 +808,23 @@ tape_delayed_next_request(struct work_st spin_unlock_irq(get_ccwdev_lock(device->cdev)); } -static inline void +static void tape_long_busy_timeout(unsigned long data) +{ + struct tape_request *request; + struct tape_device *device; + + device = (struct tape_device *) data; + spin_lock_irq(get_ccwdev_lock(device->cdev)); + request = list_entry(device->req_queue.next, struct tape_request, list); + if (request->status != TAPE_REQUEST_LONG_BUSY) + BUG(); + DBF_LH(6, "%08x: Long busy timeout.\n", device->cdev_id); + __tape_start_next_request(device); + device->lb_timeout.data = (unsigned long) tape_put_device(device); + spin_unlock_irq(get_ccwdev_lock(device->cdev)); +} + +static void __tape_end_request( struct tape_device * device, struct tape_request * request, @@ -878,7 +901,7 @@ tape_dump_sense_dbf(struct tape_device * * and starts it if the tape is idle. Has to be called with * the device lock held. */ -static inline int +static int __tape_start_request(struct tape_device *device, struct tape_request *request) { int rc; @@ -1094,7 +1117,22 @@ __tape_do_irq (struct ccw_device *cdev, /* May be an unsolicited irq */ if(request != NULL) request->rescnt = irb->scsw.count; - + else if ((irb->scsw.dstat == 0x85 || irb->scsw.dstat == 0x80) && + !list_empty(&device->req_queue)) { + /* Not Ready to Ready after long busy ? */ + struct tape_request *req; + req = list_entry(device->req_queue.next, + struct tape_request, list); + if (req->status == TAPE_REQUEST_LONG_BUSY) { + DBF_EVENT(3, "(%08x): del timer\n", device->cdev_id); + if (del_timer(&device->lb_timeout)) { + device->lb_timeout.data = (unsigned long) + tape_put_device(device); + __tape_start_next_request(device); + } + return; + } + } if (irb->scsw.dstat != 0x0c) { /* Set the 'ONLINE' flag depending on sense byte 1 */ if(*(((__u8 *) irb->ecw) + 1) & SENSE_DRIVE_ONLINE) @@ -1142,6 +1180,15 @@ __tape_do_irq (struct ccw_device *cdev, break; case TAPE_IO_PENDING: break; + case TAPE_IO_LONG_BUSY: + device->lb_timeout.data = + (unsigned long)tape_get_device_reference(device); + device->lb_timeout.expires = jiffies + + LONG_BUSY_TIMEOUT * HZ; + DBF_EVENT(3, "(%08x): add timer\n", device->cdev_id); + add_timer(&device->lb_timeout); + request->status = TAPE_REQUEST_LONG_BUSY; + break; case TAPE_IO_RETRY: rc = __tape_start_io(device, request); if (rc) diff --git a/drivers/s390/char/tape_proc.c b/drivers/s390/char/tape_proc.c index 655d375..cea49f0 100644 --- a/drivers/s390/char/tape_proc.c +++ b/drivers/s390/char/tape_proc.c @@ -109,7 +109,7 @@ static int tape_proc_open(struct inode * return seq_open(file, &tape_proc_seq); } -static struct file_operations tape_proc_ops = +static const struct file_operations tape_proc_ops = { .open = tape_proc_open, .read = seq_read, diff --git a/drivers/s390/char/tty3270.c b/drivers/s390/char/tty3270.c index 0984462..bc33068 100644 --- a/drivers/s390/char/tty3270.c +++ b/drivers/s390/char/tty3270.c @@ -36,7 +36,7 @@ #define TTY3270_STRING_PAGES 5 struct tty_driver *tty3270_driver; static int tty3270_max_index; -struct raw3270_fn tty3270_fn; +static struct raw3270_fn tty3270_fn; struct tty3270_cell { unsigned char character; @@ -119,8 +119,7 @@ static void tty3270_update(struct tty327 /* * Setup timeout for a device. On timeout trigger an update. */ -void -tty3270_set_timer(struct tty3270 *tp, int expires) +static void tty3270_set_timer(struct tty3270 *tp, int expires) { if (expires == 0) { if (timer_pending(&tp->timer) && del_timer(&tp->timer)) @@ -841,7 +840,7 @@ tty3270_del_views(void) } } -struct raw3270_fn tty3270_fn = { +static struct raw3270_fn tty3270_fn = { .activate = tty3270_activate, .deactivate = tty3270_deactivate, .intv = (void *) tty3270_irq, @@ -1754,8 +1753,7 @@ static const struct tty_operations tty32 .set_termios = tty3270_set_termios }; -void -tty3270_notifier(int index, int active) +static void tty3270_notifier(int index, int active) { if (active) tty_register_device(tty3270_driver, index, NULL); @@ -1767,8 +1765,7 @@ tty3270_notifier(int index, int active) * 3270 tty registration code called from tty_init(). * Most kernel services (incl. kmalloc) are available at this poimt. */ -int __init -tty3270_init(void) +static int __init tty3270_init(void) { struct tty_driver *driver; int ret; diff --git a/drivers/s390/char/vmcp.c b/drivers/s390/char/vmcp.c index a420cd0..fce3dac 100644 --- a/drivers/s390/char/vmcp.c +++ b/drivers/s390/char/vmcp.c @@ -173,7 +173,7 @@ static long vmcp_ioctl(struct file *file } } -static struct file_operations vmcp_fops = { +static const struct file_operations vmcp_fops = { .owner = THIS_MODULE, .open = &vmcp_open, .release = &vmcp_release, diff --git a/drivers/s390/char/vmlogrdr.c b/drivers/s390/char/vmlogrdr.c index 6cb2304..b87d3b0 100644 --- a/drivers/s390/char/vmlogrdr.c +++ b/drivers/s390/char/vmlogrdr.c @@ -3,7 +3,7 @@ * character device driver for reading z/VM system service records * * - * Copyright (C) 2004 IBM Corporation + * Copyright 2004 IBM Corporation * character device driver for reading z/VM system service records, * Version 1.0 * Author(s): Xenia Tkatschow @@ -21,7 +21,7 @@ #include #include #include #include -#include "../net/iucv.h" +#include #include #include #include @@ -60,12 +60,11 @@ struct vmlogrdr_priv_t { char system_service[8]; char internal_name[8]; char recording_name[8]; - u16 pathid; + struct iucv_path *path; int connection_established; int iucv_path_severed; - iucv_MessagePending local_interrupt_buffer; + struct iucv_message local_interrupt_buffer; atomic_t receive_ready; - iucv_handle_t iucv_handle; int minor_num; char * buffer; char * current_position; @@ -89,7 +88,7 @@ static int vmlogrdr_release(struct inode static ssize_t vmlogrdr_read (struct file *filp, char __user *data, size_t count, loff_t * ppos); -static struct file_operations vmlogrdr_fops = { +static const struct file_operations vmlogrdr_fops = { .owner = THIS_MODULE, .open = vmlogrdr_open, .release = vmlogrdr_release, @@ -97,40 +96,21 @@ static struct file_operations vmlogrdr_f }; -static u8 iucvMagic[16] = { - 0xF0, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, - 0xF0, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40 -}; +static void vmlogrdr_iucv_path_complete(struct iucv_path *, u8 ipuser[16]); +static void vmlogrdr_iucv_path_severed(struct iucv_path *, u8 ipuser[16]); +static void vmlogrdr_iucv_message_pending(struct iucv_path *, + struct iucv_message *); -static u8 mask[] = { - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff +static struct iucv_handler vmlogrdr_iucv_handler = { + .path_complete = vmlogrdr_iucv_path_complete, + .path_severed = vmlogrdr_iucv_path_severed, + .message_pending = vmlogrdr_iucv_message_pending, }; -static u8 iucv_host[8] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; - - -static void -vmlogrdr_iucv_ConnectionComplete(iucv_ConnectionComplete *eib, void *pgm_data); -static void -vmlogrdr_iucv_ConnectionSevered(iucv_ConnectionSevered *eib, void *pgm_data); -static void -vmlogrdr_iucv_MessagePending(iucv_MessagePending *eib, void *pgm_data); - - -static iucv_interrupt_ops_t vmlogrdr_iucvops = { - .ConnectionComplete = vmlogrdr_iucv_ConnectionComplete, - .ConnectionSevered = vmlogrdr_iucv_ConnectionSevered, - .MessagePending = vmlogrdr_iucv_MessagePending, -}; - - -DECLARE_WAIT_QUEUE_HEAD(conn_wait_queue); -DECLARE_WAIT_QUEUE_HEAD(read_wait_queue); +static DECLARE_WAIT_QUEUE_HEAD(conn_wait_queue); +static DECLARE_WAIT_QUEUE_HEAD(read_wait_queue); /* * pointer to system service private structure @@ -177,28 +157,29 @@ static struct cdev *vmlogrdr_cdev = NUL static int recording_class_AB; -static void -vmlogrdr_iucv_ConnectionComplete (iucv_ConnectionComplete * eib, - void * pgm_data) +static void vmlogrdr_iucv_path_complete(struct iucv_path *path, u8 ipuser[16]) { - struct vmlogrdr_priv_t * logptr = pgm_data; + struct vmlogrdr_priv_t * logptr = path->private; + spin_lock(&logptr->priv_lock); logptr->connection_established = 1; spin_unlock(&logptr->priv_lock); wake_up(&conn_wait_queue); - return; } -static void -vmlogrdr_iucv_ConnectionSevered (iucv_ConnectionSevered * eib, void * pgm_data) +static void vmlogrdr_iucv_path_severed(struct iucv_path *path, u8 ipuser[16]) { - u8 reason = (u8) eib->ipuser[8]; - struct vmlogrdr_priv_t * logptr = pgm_data; + struct vmlogrdr_priv_t * logptr = path->private; + u8 reason = (u8) ipuser[8]; printk (KERN_ERR "vmlogrdr: connection severed with" " reason %i\n", reason); + iucv_path_sever(path, NULL); + kfree(path); + logptr->path = NULL; + spin_lock(&logptr->priv_lock); logptr->connection_established = 0; logptr->iucv_path_severed = 1; @@ -210,10 +191,10 @@ vmlogrdr_iucv_ConnectionSevered (iucv_Co } -static void -vmlogrdr_iucv_MessagePending (iucv_MessagePending * eib, void * pgm_data) +static void vmlogrdr_iucv_message_pending(struct iucv_path *path, + struct iucv_message *msg) { - struct vmlogrdr_priv_t * logptr = pgm_data; + struct vmlogrdr_priv_t * logptr = path->private; /* * This function is the bottom half so it should be quick. @@ -221,15 +202,15 @@ vmlogrdr_iucv_MessagePending (iucv_Messa * the usage count */ spin_lock(&logptr->priv_lock); - memcpy(&(logptr->local_interrupt_buffer), eib, sizeof(*eib)); + memcpy(&logptr->local_interrupt_buffer, msg, sizeof(*msg)); atomic_inc(&logptr->receive_ready); spin_unlock(&logptr->priv_lock); wake_up_interruptible(&read_wait_queue); } -static int -vmlogrdr_get_recording_class_AB(void) { +static int vmlogrdr_get_recording_class_AB(void) +{ char cp_command[]="QUERY COMMAND RECORDING "; char cp_response[80]; char *tail; @@ -259,8 +240,9 @@ vmlogrdr_get_recording_class_AB(void) { } -static int -vmlogrdr_recording(struct vmlogrdr_priv_t * logptr, int action, int purge) { +static int vmlogrdr_recording(struct vmlogrdr_priv_t * logptr, + int action, int purge) +{ char cp_command[80]; char cp_response[160]; @@ -318,8 +300,7 @@ vmlogrdr_recording(struct vmlogrdr_priv_ } -static int -vmlogrdr_open (struct inode *inode, struct file *filp) +static int vmlogrdr_open (struct inode *inode, struct file *filp) { int dev_num = 0; struct vmlogrdr_priv_t * logptr = NULL; @@ -329,10 +310,7 @@ vmlogrdr_open (struct inode *inode, stru dev_num = iminor(inode); if (dev_num > MAXMINOR) return -ENODEV; - logptr = &sys_ser[dev_num]; - if (logptr == NULL) - return -ENODEV; /* * only allow for blocking reads to be open @@ -345,52 +323,38 @@ vmlogrdr_open (struct inode *inode, stru if (logptr->dev_in_use) { spin_unlock_bh(&logptr->priv_lock); return -EBUSY; - } else { - logptr->dev_in_use = 1; - spin_unlock_bh(&logptr->priv_lock); } - + logptr->dev_in_use = 1; + logptr->connection_established = 0; + logptr->iucv_path_severed = 0; atomic_set(&logptr->receive_ready, 0); logptr->buffer_free = 1; + spin_unlock_bh(&logptr->priv_lock); /* set the file options */ filp->private_data = logptr; filp->f_op = &vmlogrdr_fops; /* start recording for this service*/ - ret=0; - if (logptr->autorecording) + if (logptr->autorecording) { ret = vmlogrdr_recording(logptr,1,logptr->autopurge); - if (ret) - printk (KERN_WARNING "vmlogrdr: failed to start " - "recording automatically\n"); - - /* Register with iucv driver */ - logptr->iucv_handle = iucv_register_program(iucvMagic, - logptr->system_service, mask, &vmlogrdr_iucvops, - logptr); - - if (logptr->iucv_handle == NULL) { - printk (KERN_ERR "vmlogrdr: failed to register with" - "iucv driver\n"); - goto not_registered; + if (ret) + printk (KERN_WARNING "vmlogrdr: failed to start " + "recording automatically\n"); } /* create connection to the system service */ - spin_lock_bh(&logptr->priv_lock); - logptr->connection_established = 0; - logptr->iucv_path_severed = 0; - spin_unlock_bh(&logptr->priv_lock); - - connect_rc = iucv_connect (&(logptr->pathid), 10, iucvMagic, - logptr->system_service, iucv_host, 0, - NULL, NULL, - logptr->iucv_handle, NULL); + logptr->path = iucv_path_alloc(10, 0, GFP_KERNEL); + if (!logptr->path) + goto out_dev; + connect_rc = iucv_path_connect(logptr->path, &vmlogrdr_iucv_handler, + logptr->system_service, NULL, NULL, + logptr); if (connect_rc) { printk (KERN_ERR "vmlogrdr: iucv connection to %s " "failed with rc %i \n", logptr->system_service, connect_rc); - goto not_connected; + goto out_path; } /* We've issued the connect and now we must wait for a @@ -399,35 +363,28 @@ vmlogrdr_open (struct inode *inode, stru */ wait_event(conn_wait_queue, (logptr->connection_established) || (logptr->iucv_path_severed)); - if (logptr->iucv_path_severed) { - goto not_connected; - } - + if (logptr->iucv_path_severed) + goto out_record; return nonseekable_open(inode, filp); -not_connected: - iucv_unregister_program(logptr->iucv_handle); - logptr->iucv_handle = NULL; -not_registered: +out_record: if (logptr->autorecording) vmlogrdr_recording(logptr,0,logptr->autopurge); +out_path: + kfree(logptr->path); /* kfree(NULL) is ok. */ + logptr->path = NULL; +out_dev: logptr->dev_in_use = 0; return -EIO; - - } -static int -vmlogrdr_release (struct inode *inode, struct file *filp) +static int vmlogrdr_release (struct inode *inode, struct file *filp) { int ret; struct vmlogrdr_priv_t * logptr = filp->private_data; - iucv_unregister_program(logptr->iucv_handle); - logptr->iucv_handle = NULL; - if (logptr->autorecording) { ret = vmlogrdr_recording(logptr,0,logptr->autopurge); if (ret) @@ -440,8 +397,8 @@ vmlogrdr_release (struct inode *inode, s } -static int -vmlogrdr_receive_data(struct vmlogrdr_priv_t *priv) { +static int vmlogrdr_receive_data(struct vmlogrdr_priv_t *priv) +{ int rc, *temp; /* we need to keep track of two data sizes here: * The number of bytes we need to receive from iucv and @@ -462,8 +419,7 @@ vmlogrdr_receive_data(struct vmlogrdr_pr * We need to return the total length of the record * + size of FENCE in the first 4 bytes of the buffer. */ - iucv_data_count = - priv->local_interrupt_buffer.ln1msg2.ipbfln1f; + iucv_data_count = priv->local_interrupt_buffer.length; user_data_count = sizeof(int); temp = (int*)priv->buffer; *temp= iucv_data_count + sizeof(FENCE); @@ -475,14 +431,10 @@ vmlogrdr_receive_data(struct vmlogrdr_pr */ if (iucv_data_count > NET_BUFFER_SIZE) iucv_data_count = NET_BUFFER_SIZE; - rc = iucv_receive(priv->pathid, - priv->local_interrupt_buffer.ipmsgid, - priv->local_interrupt_buffer.iptrgcls, - buffer, - iucv_data_count, - NULL, - NULL, - &priv->residual_length); + rc = iucv_message_receive(priv->path, + &priv->local_interrupt_buffer, + 0, buffer, iucv_data_count, + &priv->residual_length); spin_unlock_bh(&priv->priv_lock); /* An rc of 5 indicates that the record was bigger then * the buffer, which is OK for us. A 9 indicates that the @@ -514,8 +466,8 @@ vmlogrdr_receive_data(struct vmlogrdr_pr } -static ssize_t -vmlogrdr_read(struct file *filp, char __user *data, size_t count, loff_t * ppos) +static ssize_t vmlogrdr_read(struct file *filp, char __user *data, + size_t count, loff_t * ppos) { int rc; struct vmlogrdr_priv_t * priv = filp->private_data; @@ -547,8 +499,10 @@ vmlogrdr_read(struct file *filp, char __ return count; } -static ssize_t -vmlogrdr_autopurge_store(struct device * dev, struct device_attribute *attr, const char * buf, size_t count) { +static ssize_t vmlogrdr_autopurge_store(struct device * dev, + struct device_attribute *attr, + const char * buf, size_t count) +{ struct vmlogrdr_priv_t *priv = dev->driver_data; ssize_t ret = count; @@ -566,8 +520,10 @@ vmlogrdr_autopurge_store(struct device * } -static ssize_t -vmlogrdr_autopurge_show(struct device *dev, struct device_attribute *attr, char *buf) { +static ssize_t vmlogrdr_autopurge_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ struct vmlogrdr_priv_t *priv = dev->driver_data; return sprintf(buf, "%u\n", priv->autopurge); } @@ -577,8 +533,10 @@ static DEVICE_ATTR(autopurge, 0644, vmlo vmlogrdr_autopurge_store); -static ssize_t -vmlogrdr_purge_store(struct device * dev, struct device_attribute *attr, const char * buf, size_t count) { +static ssize_t vmlogrdr_purge_store(struct device * dev, + struct device_attribute *attr, + const char * buf, size_t count) +{ char cp_command[80]; char cp_response[80]; @@ -618,9 +576,10 @@ vmlogrdr_purge_store(struct device * dev static DEVICE_ATTR(purge, 0200, NULL, vmlogrdr_purge_store); -static ssize_t -vmlogrdr_autorecording_store(struct device *dev, struct device_attribute *attr, const char *buf, - size_t count) { +static ssize_t vmlogrdr_autorecording_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ struct vmlogrdr_priv_t *priv = dev->driver_data; ssize_t ret = count; @@ -638,8 +597,10 @@ vmlogrdr_autorecording_store(struct devi } -static ssize_t -vmlogrdr_autorecording_show(struct device *dev, struct device_attribute *attr, char *buf) { +static ssize_t vmlogrdr_autorecording_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ struct vmlogrdr_priv_t *priv = dev->driver_data; return sprintf(buf, "%u\n", priv->autorecording); } @@ -649,9 +610,10 @@ static DEVICE_ATTR(autorecording, 0644, vmlogrdr_autorecording_store); -static ssize_t -vmlogrdr_recording_store(struct device * dev, struct device_attribute *attr, const char * buf, size_t count) { - +static ssize_t vmlogrdr_recording_store(struct device * dev, + struct device_attribute *attr, + const char * buf, size_t count) +{ struct vmlogrdr_priv_t *priv = dev->driver_data; ssize_t ret; @@ -676,8 +638,9 @@ vmlogrdr_recording_store(struct device * static DEVICE_ATTR(recording, 0200, NULL, vmlogrdr_recording_store); -static ssize_t -vmlogrdr_recording_status_show(struct device_driver *driver, char *buf) { +static ssize_t vmlogrdr_recording_status_show(struct device_driver *driver, + char *buf) +{ char cp_command[] = "QUERY RECORDING "; int len; @@ -710,52 +673,63 @@ static struct device_driver vmlogrdr_dri }; -static int -vmlogrdr_register_driver(void) { +static int vmlogrdr_register_driver(void) +{ int ret; + /* Register with iucv driver */ + ret = iucv_register(&vmlogrdr_iucv_handler, 1); + if (ret) { + printk (KERN_ERR "vmlogrdr: failed to register with" + "iucv driver\n"); + goto out; + } + ret = driver_register(&vmlogrdr_driver); if (ret) { printk(KERN_ERR "vmlogrdr: failed to register driver.\n"); - return ret; + goto out_iucv; } ret = driver_create_file(&vmlogrdr_driver, &driver_attr_recording_status); if (ret) { printk(KERN_ERR "vmlogrdr: failed to add driver attribute.\n"); - goto unregdriver; + goto out_driver; } vmlogrdr_class = class_create(THIS_MODULE, "vmlogrdr"); if (IS_ERR(vmlogrdr_class)) { printk(KERN_ERR "vmlogrdr: failed to create class.\n"); - ret=PTR_ERR(vmlogrdr_class); - vmlogrdr_class=NULL; - goto unregattr; + ret = PTR_ERR(vmlogrdr_class); + vmlogrdr_class = NULL; + goto out_attr; } return 0; -unregattr: +out_attr: driver_remove_file(&vmlogrdr_driver, &driver_attr_recording_status); -unregdriver: +out_driver: driver_unregister(&vmlogrdr_driver); +out_iucv: + iucv_unregister(&vmlogrdr_iucv_handler, 1); +out: return ret; } -static void -vmlogrdr_unregister_driver(void) { +static void vmlogrdr_unregister_driver(void) +{ class_destroy(vmlogrdr_class); vmlogrdr_class = NULL; driver_remove_file(&vmlogrdr_driver, &driver_attr_recording_status); driver_unregister(&vmlogrdr_driver); - return; + iucv_unregister(&vmlogrdr_iucv_handler, 1); } -static int -vmlogrdr_register_device(struct vmlogrdr_priv_t *priv) { +static int vmlogrdr_register_device(struct vmlogrdr_priv_t *priv) +{ struct device *dev; int ret; @@ -804,9 +778,10 @@ vmlogrdr_register_device(struct vmlogrdr } -static int -vmlogrdr_unregister_device(struct vmlogrdr_priv_t *priv ) { - class_device_destroy(vmlogrdr_class, MKDEV(vmlogrdr_major, priv->minor_num)); +static int vmlogrdr_unregister_device(struct vmlogrdr_priv_t *priv) +{ + class_device_destroy(vmlogrdr_class, + MKDEV(vmlogrdr_major, priv->minor_num)); if (priv->device != NULL) { sysfs_remove_group(&priv->device->kobj, &vmlogrdr_attr_group); device_unregister(priv->device); @@ -816,8 +791,8 @@ vmlogrdr_unregister_device(struct vmlogr } -static int -vmlogrdr_register_cdev(dev_t dev) { +static int vmlogrdr_register_cdev(dev_t dev) +{ int rc = 0; vmlogrdr_cdev = cdev_alloc(); if (!vmlogrdr_cdev) { @@ -837,9 +812,10 @@ vmlogrdr_register_cdev(dev_t dev) { } -static void -vmlogrdr_cleanup(void) { +static void vmlogrdr_cleanup(void) +{ int i; + if (vmlogrdr_cdev) { cdev_del(vmlogrdr_cdev); vmlogrdr_cdev=NULL; @@ -856,8 +832,7 @@ vmlogrdr_cleanup(void) { } -static int -vmlogrdr_init(void) +static int vmlogrdr_init(void) { int rc; int i; @@ -907,8 +882,7 @@ cleanup: } -static void -vmlogrdr_exit(void) +static void vmlogrdr_exit(void) { vmlogrdr_cleanup(); printk (KERN_INFO "vmlogrdr: driver unloaded\n"); diff --git a/drivers/s390/char/vmwatchdog.c b/drivers/s390/char/vmwatchdog.c index 4b868f7..680b9b5 100644 --- a/drivers/s390/char/vmwatchdog.c +++ b/drivers/s390/char/vmwatchdog.c @@ -228,7 +228,7 @@ static ssize_t vmwdt_write(struct file * return count; } -static struct file_operations vmwdt_fops = { +static const struct file_operations vmwdt_fops = { .open = &vmwdt_open, .release = &vmwdt_close, .ioctl = &vmwdt_ioctl, diff --git a/drivers/s390/cio/blacklist.c b/drivers/s390/cio/blacklist.c index 12c2d6b..ec04048 100644 --- a/drivers/s390/cio/blacklist.c +++ b/drivers/s390/cio/blacklist.c @@ -43,7 +43,7 @@ typedef enum {add, free} range_action; * Function: blacklist_range * (Un-)blacklist the devices from-to */ -static inline void +static void blacklist_range (range_action action, unsigned int from, unsigned int to, unsigned int ssid) { @@ -69,7 +69,7 @@ blacklist_range (range_action action, un * Get devno/busid from given string. * Shamelessly grabbed from dasd_devmap.c. */ -static inline int +static int blacklist_busid(char **str, int *id0, int *ssid, int *devno) { int val, old_style; @@ -123,10 +123,10 @@ confused: return 1; } -static inline int +static int blacklist_parse_parameters (char *str, range_action action) { - unsigned int from, to, from_id0, to_id0, from_ssid, to_ssid; + int from, to, from_id0, to_id0, from_ssid, to_ssid; while (*str != 0 && *str != '\n') { range_action ra = action; @@ -227,7 +227,7 @@ #ifdef CONFIG_PROC_FS * Function: blacklist_parse_proc_parameters * parse the stuff which is piped to /proc/cio_ignore */ -static inline void +static void blacklist_parse_proc_parameters (char *buf) { if (strncmp (buf, "free ", 5) == 0) { @@ -364,7 +364,7 @@ cio_ignore_proc_open(struct inode *inode return seq_open(file, &cio_ignore_proc_seq_ops); } -static struct file_operations cio_ignore_proc_fops = { +static const struct file_operations cio_ignore_proc_fops = { .open = cio_ignore_proc_open, .read = seq_read, .llseek = seq_lseek, diff --git a/drivers/s390/cio/ccwgroup.c b/drivers/s390/cio/ccwgroup.c index 38954f5..d48e3ca 100644 --- a/drivers/s390/cio/ccwgroup.c +++ b/drivers/s390/cio/ccwgroup.c @@ -53,7 +53,7 @@ ccwgroup_uevent (struct device *dev, cha static struct bus_type ccwgroup_bus_type; -static inline void +static void __ccwgroup_remove_symlinks(struct ccwgroup_device *gdev) { int i; @@ -104,7 +104,7 @@ ccwgroup_release (struct device *dev) kfree(gdev); } -static inline int +static int __ccwgroup_create_symlinks(struct ccwgroup_device *gdev) { char str[8]; @@ -424,7 +424,7 @@ ccwgroup_probe_ccwdev(struct ccw_device return 0; } -static inline struct ccwgroup_device * +static struct ccwgroup_device * __ccwgroup_get_gdev_by_cdev(struct ccw_device *cdev) { struct ccwgroup_device *gdev; diff --git a/drivers/s390/cio/chsc.c b/drivers/s390/cio/chsc.c index cbab8d2..6f05a44 100644 --- a/drivers/s390/cio/chsc.c +++ b/drivers/s390/cio/chsc.c @@ -93,7 +93,7 @@ chsc_get_sch_desc_irq(struct subchannel u16 sch; /* subchannel */ u8 chpid[8]; /* chpids 0-7 */ u16 fla[8]; /* full link addresses 0-7 */ - } *ssd_area; + } __attribute__ ((packed)) *ssd_area; ssd_area = page; @@ -277,7 +277,7 @@ out_unreg: return 0; } -static inline void +static void s390_set_chpid_offline( __u8 chpid) { char dbf_txt[15]; @@ -338,7 +338,7 @@ s390_process_res_acc_sch(struct res_acc_ return 0x80 >> chp; } -static inline int +static int s390_process_res_acc_new_sch(struct subchannel_id schid) { struct schib schib; @@ -444,7 +444,7 @@ __get_chpid_from_lir(void *data) u32 andesc[28]; /* incident-specific information */ u32 isinfo[28]; - } *lir; + } __attribute__ ((packed)) *lir; lir = data; if (!(lir->iq&0x80)) @@ -461,154 +461,146 @@ __get_chpid_from_lir(void *data) return (u16) (lir->indesc[0]&0x000000ff); } -int -chsc_process_crw(void) +struct chsc_sei_area { + struct chsc_header request; + u32 reserved1; + u32 reserved2; + u32 reserved3; + struct chsc_header response; + u32 reserved4; + u8 flags; + u8 vf; /* validity flags */ + u8 rs; /* reporting source */ + u8 cc; /* content code */ + u16 fla; /* full link address */ + u16 rsid; /* reporting source id */ + u32 reserved5; + u32 reserved6; + u8 ccdf[4096 - 16 - 24]; /* content-code dependent field */ + /* ccdf has to be big enough for a link-incident record */ +} __attribute__ ((packed)); + +static int chsc_process_sei_link_incident(struct chsc_sei_area *sei_area) +{ + int chpid; + + CIO_CRW_EVENT(4, "chsc: link incident (rs=%02x, rs_id=%04x)\n", + sei_area->rs, sei_area->rsid); + if (sei_area->rs != 4) + return 0; + chpid = __get_chpid_from_lir(sei_area->ccdf); + if (chpid < 0) + CIO_CRW_EVENT(4, "chsc: link incident - invalid LIR\n"); + else + s390_set_chpid_offline(chpid); + + return 0; +} + +static int chsc_process_sei_res_acc(struct chsc_sei_area *sei_area) { - int chpid, ret; struct res_acc_data res_data; - struct { - struct chsc_header request; - u32 reserved1; - u32 reserved2; - u32 reserved3; - struct chsc_header response; - u32 reserved4; - u8 flags; - u8 vf; /* validity flags */ - u8 rs; /* reporting source */ - u8 cc; /* content code */ - u16 fla; /* full link address */ - u16 rsid; /* reporting source id */ - u32 reserved5; - u32 reserved6; - u32 ccdf[96]; /* content-code dependent field */ - /* ccdf has to be big enough for a link-incident record */ - } *sei_area; + struct device *dev; + int status; + int rc; + + CIO_CRW_EVENT(4, "chsc: resource accessibility event (rs=%02x, " + "rs_id=%04x)\n", sei_area->rs, sei_area->rsid); + if (sei_area->rs != 4) + return 0; + /* allocate a new channel path structure, if needed */ + status = get_chp_status(sei_area->rsid); + if (status < 0) + new_channel_path(sei_area->rsid); + else if (!status) + return 0; + dev = get_device(&css[0]->chps[sei_area->rsid]->dev); + memset(&res_data, 0, sizeof(struct res_acc_data)); + res_data.chp = to_channelpath(dev); + if ((sei_area->vf & 0xc0) != 0) { + res_data.fla = sei_area->fla; + if ((sei_area->vf & 0xc0) == 0xc0) + /* full link address */ + res_data.fla_mask = 0xffff; + else + /* link address */ + res_data.fla_mask = 0xff00; + } + rc = s390_process_res_acc(&res_data); + put_device(dev); + + return rc; +} + +static int chsc_process_sei(struct chsc_sei_area *sei_area) +{ + int rc; + + /* Check if we might have lost some information. */ + if (sei_area->flags & 0x40) + CIO_CRW_EVENT(2, "chsc: event overflow\n"); + /* which kind of information was stored? */ + rc = 0; + switch (sei_area->cc) { + case 1: /* link incident*/ + rc = chsc_process_sei_link_incident(sei_area); + break; + case 2: /* i/o resource accessibiliy */ + rc = chsc_process_sei_res_acc(sei_area); + break; + default: /* other stuff */ + CIO_CRW_EVENT(4, "chsc: unhandled sei content code %d\n", + sei_area->cc); + break; + } + + return rc; +} + +int chsc_process_crw(void) +{ + struct chsc_sei_area *sei_area; + int ret; + int rc; if (!sei_page) return 0; - /* - * build the chsc request block for store event information - * and do the call - * This function is only called by the machine check handler thread, - * so we don't need locking for the sei_page. - */ + /* Access to sei_page is serialized through machine check handler + * thread, so no need for locking. */ sei_area = sei_page; CIO_TRACE_EVENT( 2, "prcss"); ret = 0; do { - int ccode, status; - struct device *dev; memset(sei_area, 0, sizeof(*sei_area)); - memset(&res_data, 0, sizeof(struct res_acc_data)); sei_area->request.length = 0x0010; sei_area->request.code = 0x000e; + if (chsc(sei_area)) + break; - ccode = chsc(sei_area); - if (ccode > 0) - return 0; - - switch (sei_area->response.code) { - /* for debug purposes, check for problems */ - case 0x0001: - CIO_CRW_EVENT(4, "chsc_process_crw: event information " - "successfully stored\n"); - break; /* everything ok */ - case 0x0002: - CIO_CRW_EVENT(2, - "chsc_process_crw: invalid command!\n"); - return 0; - case 0x0003: - CIO_CRW_EVENT(2, "chsc_process_crw: error in chsc " - "request block!\n"); - return 0; - case 0x0005: - CIO_CRW_EVENT(2, "chsc_process_crw: no event " - "information stored\n"); - return 0; - default: - CIO_CRW_EVENT(2, "chsc_process_crw: chsc response %d\n", + if (sei_area->response.code == 0x0001) { + CIO_CRW_EVENT(4, "chsc: sei successful\n"); + rc = chsc_process_sei(sei_area); + if (rc) + ret = rc; + } else { + CIO_CRW_EVENT(2, "chsc: sei failed (rc=%04x)\n", sei_area->response.code); - return 0; - } - - /* Check if we might have lost some information. */ - if (sei_area->flags & 0x40) - CIO_CRW_EVENT(2, "chsc_process_crw: Event information " - "has been lost due to overflow!\n"); - - if (sei_area->rs != 4) { - CIO_CRW_EVENT(2, "chsc_process_crw: reporting source " - "(%04X) isn't a chpid!\n", - sei_area->rsid); - continue; - } - - /* which kind of information was stored? */ - switch (sei_area->cc) { - case 1: /* link incident*/ - CIO_CRW_EVENT(4, "chsc_process_crw: " - "channel subsystem reports link incident," - " reporting source is chpid %x\n", - sei_area->rsid); - chpid = __get_chpid_from_lir(sei_area->ccdf); - if (chpid < 0) - CIO_CRW_EVENT(4, "%s: Invalid LIR, skipping\n", - __FUNCTION__); - else - s390_set_chpid_offline(chpid); - break; - - case 2: /* i/o resource accessibiliy */ - CIO_CRW_EVENT(4, "chsc_process_crw: " - "channel subsystem reports some I/O " - "devices may have become accessible\n"); - pr_debug("Data received after sei: \n"); - pr_debug("Validity flags: %x\n", sei_area->vf); - - /* allocate a new channel path structure, if needed */ - status = get_chp_status(sei_area->rsid); - if (status < 0) - new_channel_path(sei_area->rsid); - else if (!status) - break; - dev = get_device(&css[0]->chps[sei_area->rsid]->dev); - res_data.chp = to_channelpath(dev); - pr_debug("chpid: %x", sei_area->rsid); - if ((sei_area->vf & 0xc0) != 0) { - res_data.fla = sei_area->fla; - if ((sei_area->vf & 0xc0) == 0xc0) { - pr_debug(" full link addr: %x", - sei_area->fla); - res_data.fla_mask = 0xffff; - } else { - pr_debug(" link addr: %x", - sei_area->fla); - res_data.fla_mask = 0xff00; - } - } - ret = s390_process_res_acc(&res_data); - pr_debug("\n\n"); - put_device(dev); - break; - - default: /* other stuff */ - CIO_CRW_EVENT(4, "chsc_process_crw: event %d\n", - sei_area->cc); + ret = 0; break; } } while (sei_area->flags & 0x80); + return ret; } -static inline int +static int __chp_add_new_sch(struct subchannel_id schid) { struct schib schib; int ret; - if (stsch(schid, &schib)) + if (stsch_err(schid, &schib)) /* We're through */ return need_rescan ? -EAGAIN : -ENXIO; @@ -709,7 +701,7 @@ chp_process_crw(int chpid, int on) return chp_add(chpid); } -static inline int check_for_io_on_path(struct subchannel *sch, int index) +static int check_for_io_on_path(struct subchannel *sch, int index) { int cc; @@ -741,7 +733,7 @@ static void terminate_internal_io(struct sch->driver->termination(&sch->dev); } -static inline void +static void __s390_subchannel_vary_chpid(struct subchannel *sch, __u8 chpid, int on) { int chp, old_lpm; @@ -967,8 +959,8 @@ static struct bin_attribute chp_measurem static void chsc_remove_chp_cmg_attr(struct channel_path *chp) { - sysfs_remove_bin_file(&chp->dev.kobj, &chp_measurement_chars_attr); - sysfs_remove_bin_file(&chp->dev.kobj, &chp_measurement_attr); + device_remove_bin_file(&chp->dev, &chp_measurement_chars_attr); + device_remove_bin_file(&chp->dev, &chp_measurement_attr); } static int @@ -976,14 +968,12 @@ chsc_add_chp_cmg_attr(struct channel_pat { int ret; - ret = sysfs_create_bin_file(&chp->dev.kobj, - &chp_measurement_chars_attr); + ret = device_create_bin_file(&chp->dev, &chp_measurement_chars_attr); if (ret) return ret; - ret = sysfs_create_bin_file(&chp->dev.kobj, &chp_measurement_attr); + ret = device_create_bin_file(&chp->dev, &chp_measurement_attr); if (ret) - sysfs_remove_bin_file(&chp->dev.kobj, - &chp_measurement_chars_attr); + device_remove_bin_file(&chp->dev, &chp_measurement_chars_attr); return ret; } @@ -1042,7 +1032,7 @@ __chsc_do_secm(struct channel_subsystem u32 : 4; u32 fmt : 4; u32 : 16; - } *secm_area; + } __attribute__ ((packed)) *secm_area; int ret, ccode; secm_area = page; @@ -1253,7 +1243,7 @@ chsc_determine_channel_path_description( struct chsc_header response; u32 zeroes2; struct channel_path_desc desc; - } *scpd_area; + } __attribute__ ((packed)) *scpd_area; scpd_area = (void *)get_zeroed_page(GFP_KERNEL | GFP_DMA); if (!scpd_area) @@ -1350,7 +1340,7 @@ chsc_get_channel_measurement_chars(struc u32 cmg : 8; u32 zeroes3; u32 data[NR_MEASUREMENT_CHARS]; - } *scmc_area; + } __attribute__ ((packed)) *scmc_area; scmc_area = (void *)get_zeroed_page(GFP_KERNEL | GFP_DMA); if (!scmc_area) @@ -1517,7 +1507,7 @@ chsc_enable_facility(int operation_code) u32 reserved5:4; u32 format2:4; u32 reserved6:24; - } *sda_area; + } __attribute__ ((packed)) *sda_area; sda_area = (void *)get_zeroed_page(GFP_KERNEL|GFP_DMA); if (!sda_area) @@ -1569,7 +1559,7 @@ chsc_determine_css_characteristics(void) u32 reserved4; u32 general_char[510]; u32 chsc_char[518]; - } *scsc_area; + } __attribute__ ((packed)) *scsc_area; scsc_area = (void *)get_zeroed_page(GFP_KERNEL | GFP_DMA); if (!scsc_area) { diff --git a/drivers/s390/cio/chsc.h b/drivers/s390/cio/chsc.h index a259245..0fb2b02 100644 --- a/drivers/s390/cio/chsc.h +++ b/drivers/s390/cio/chsc.h @@ -10,17 +10,17 @@ #define CHSC_SDA_OC_MSS 0x2 struct chsc_header { u16 length; u16 code; -}; +} __attribute__ ((packed)); #define NR_MEASUREMENT_CHARS 5 struct cmg_chars { u32 values[NR_MEASUREMENT_CHARS]; -}; +} __attribute__ ((packed)); #define NR_MEASUREMENT_ENTRIES 8 struct cmg_entry { u32 values[NR_MEASUREMENT_ENTRIES]; -}; +} __attribute__ ((packed)); struct channel_path_desc { u8 flags; @@ -31,7 +31,7 @@ struct channel_path_desc { u8 zeroes; u8 chla; u8 chpp; -}; +} __attribute__ ((packed)); struct channel_path { int id; @@ -47,6 +47,9 @@ struct channel_path { extern void s390_process_css( void ); extern void chsc_validate_chpids(struct subchannel *); extern void chpid_is_actually_online(int); +extern int css_get_ssd_info(struct subchannel *); +extern int chsc_process_crw(void); +extern int chp_process_crw(int, int); struct css_general_char { u64 : 41; diff --git a/drivers/s390/cio/cio.c b/drivers/s390/cio/cio.c index ae1bf23..b3a56dc 100644 --- a/drivers/s390/cio/cio.c +++ b/drivers/s390/cio/cio.c @@ -122,7 +122,7 @@ cio_get_options (struct subchannel *sch) * Use tpi to get a pending interrupt, call the interrupt handler and * return a pointer to the subchannel structure. */ -static inline int +static int cio_tpi(void) { struct tpi_info *tpi_info; @@ -152,7 +152,7 @@ cio_tpi(void) return 1; } -static inline int +static int cio_start_handle_notoper(struct subchannel *sch, __u8 lpm) { char dbf_text[15]; @@ -585,7 +585,7 @@ cio_validate_subchannel (struct subchann * This device must not be known to Linux. So we simply * say that there is no device and return ENODEV. */ - CIO_MSG_EVENT(0, "Blacklisted device detected " + CIO_MSG_EVENT(4, "Blacklisted device detected " "at devno %04X, subchannel set %x\n", sch->schib.pmcw.dev, sch->schid.ssid); err = -ENODEV; @@ -646,7 +646,7 @@ do_IRQ (struct pt_regs *regs) * Make sure that the i/o interrupt did not "overtake" * the last HZ timer interrupt. */ - account_ticks(); + account_ticks(S390_lowcore.int_clock); /* * Get interrupt information from lowcore */ @@ -832,7 +832,7 @@ cio_get_console_subchannel(void) } #endif -static inline int +static int __disable_subchannel_easy(struct subchannel_id schid, struct schib *schib) { int retry, cc; @@ -850,7 +850,20 @@ __disable_subchannel_easy(struct subchan return -EBUSY; /* uhm... */ } -static inline int +/* we can't use the normal udelay here, since it enables external interrupts */ + +static void udelay_reset(unsigned long usecs) +{ + uint64_t start_cc, end_cc; + + asm volatile ("STCK %0" : "=m" (start_cc)); + do { + cpu_relax(); + asm volatile ("STCK %0" : "=m" (end_cc)); + } while (((end_cc - start_cc)/4096) < usecs); +} + +static int __clear_subchannel_easy(struct subchannel_id schid) { int retry; @@ -865,7 +878,7 @@ __clear_subchannel_easy(struct subchanne if (schid_equal(&ti.schid, &schid)) return 0; } - udelay(100); + udelay_reset(100); } return -EBUSY; } @@ -882,11 +895,11 @@ static int stsch_reset(struct subchannel int rc; pgm_check_occured = 0; - s390_reset_pgm_handler = cio_reset_pgm_check_handler; + s390_base_pgm_handler_fn = cio_reset_pgm_check_handler; rc = stsch(schid, addr); - s390_reset_pgm_handler = NULL; + s390_base_pgm_handler_fn = NULL; - /* The program check handler could have changed pgm_check_occured */ + /* The program check handler could have changed pgm_check_occured. */ barrier(); if (pgm_check_occured) @@ -944,7 +957,7 @@ static void css_reset(void) /* Reset subchannels. */ for_each_subchannel(__shutdown_subchannel_easy, NULL); /* Reset channel paths. */ - s390_reset_mcck_handler = s390_reset_chpids_mcck_handler; + s390_base_mcck_handler_fn = s390_reset_chpids_mcck_handler; /* Enable channel report machine checks. */ __ctl_set_bit(14, 28); /* Temporarily reenable machine checks. */ @@ -969,7 +982,7 @@ static void css_reset(void) local_mcck_disable(); /* Disable channel report machine checks. */ __ctl_clear_bit(14, 28); - s390_reset_mcck_handler = NULL; + s390_base_mcck_handler_fn = NULL; } static struct reset_call css_reset_call = { diff --git a/drivers/s390/cio/cmf.c b/drivers/s390/cio/cmf.c index 828b2d3..90b22fa 100644 --- a/drivers/s390/cio/cmf.c +++ b/drivers/s390/cio/cmf.c @@ -519,8 +519,8 @@ struct cmb { /* insert a single device into the cmb_area list * called with cmb_area.lock held from alloc_cmb */ -static inline int alloc_cmb_single (struct ccw_device *cdev, - struct cmb_data *cmb_data) +static int alloc_cmb_single(struct ccw_device *cdev, + struct cmb_data *cmb_data) { struct cmb *cmb; struct ccw_device_private *node; diff --git a/drivers/s390/cio/css.c b/drivers/s390/cio/css.c index 9d6c024..fe0ace7 100644 --- a/drivers/s390/cio/css.c +++ b/drivers/s390/cio/css.c @@ -30,7 +30,7 @@ struct channel_subsystem *css[__MAX_CSSI int css_characteristics_avail = 0; -inline int +int for_each_subchannel(int(*fn)(struct subchannel_id, void *), void *data) { struct subchannel_id schid; @@ -108,9 +108,6 @@ css_subchannel_release(struct device *de } } -extern int css_get_ssd_info(struct subchannel *sch); - - int css_sch_device_register(struct subchannel *sch) { int ret; @@ -187,7 +184,7 @@ get_subchannel_by_schid(struct subchanne return dev ? to_subchannel(dev) : NULL; } -static inline int css_get_subchannel_status(struct subchannel *sch) +static int css_get_subchannel_status(struct subchannel *sch) { struct schib schib; @@ -299,7 +296,7 @@ static int css_evaluate_new_subchannel(s /* Will be done on the slow path. */ return -EAGAIN; } - if (stsch(schid, &schib) || !schib.pmcw.dnv) { + if (stsch_err(schid, &schib) || !schib.pmcw.dnv) { /* Unusable - ignore. */ return 0; } @@ -417,7 +414,7 @@ static void reprobe_all(struct work_stru need_reprobe); } -DECLARE_WORK(css_reprobe_work, reprobe_all); +static DECLARE_WORK(css_reprobe_work, reprobe_all); /* Schedule reprobing of all unregistered subchannels. */ void css_schedule_reprobe(void) @@ -578,7 +575,7 @@ css_cm_enable_store(struct device *dev, static DEVICE_ATTR(cm_enable, 0644, css_cm_enable_show, css_cm_enable_store); -static inline int __init setup_css(int nr) +static int __init setup_css(int nr) { u32 tod_high; int ret; diff --git a/drivers/s390/cio/css.h b/drivers/s390/cio/css.h index 3464c5b..ca2bab9 100644 --- a/drivers/s390/cio/css.h +++ b/drivers/s390/cio/css.h @@ -143,6 +143,8 @@ extern void css_sch_device_unregister(st extern struct subchannel * get_subchannel_by_schid(struct subchannel_id); extern int css_init_done; extern int for_each_subchannel(int(*fn)(struct subchannel_id, void *), void *); +extern int css_process_crw(int, int); +extern void css_reiterate_subchannels(void); #define __MAX_SUBCHANNEL 65535 #define __MAX_SSID 3 diff --git a/drivers/s390/cio/device.c b/drivers/s390/cio/device.c index 8035790..e322111 100644 --- a/drivers/s390/cio/device.c +++ b/drivers/s390/cio/device.c @@ -138,7 +138,6 @@ struct bus_type ccw_bus_type; static int io_subchannel_probe (struct subchannel *); static int io_subchannel_remove (struct subchannel *); -void io_subchannel_irq (struct device *); static int io_subchannel_notify(struct device *, int); static void io_subchannel_verify(struct device *); static void io_subchannel_ioterm(struct device *); @@ -235,11 +234,8 @@ chpids_show (struct device * dev, struct ssize_t ret = 0; int chp; - if (ssd) - for (chp = 0; chp < 8; chp++) - ret += sprintf (buf+ret, "%02x ", ssd->chpid[chp]); - else - ret += sprintf (buf, "n/a"); + for (chp = 0; chp < 8; chp++) + ret += sprintf (buf+ret, "%02x ", ssd->chpid[chp]); ret += sprintf (buf+ret, "\n"); return min((ssize_t)PAGE_SIZE, ret); } @@ -552,13 +548,13 @@ static struct attribute_group ccwdev_att .attrs = ccwdev_attrs, }; -static inline int +static int device_add_files (struct device *dev) { return sysfs_create_group(&dev->kobj, &ccwdev_attr_group); } -static inline void +static void device_remove_files(struct device *dev) { sysfs_remove_group(&dev->kobj, &ccwdev_attr_group); diff --git a/drivers/s390/cio/device.h b/drivers/s390/cio/device.h index 29db634..b66338b 100644 --- a/drivers/s390/cio/device.h +++ b/drivers/s390/cio/device.h @@ -74,6 +74,7 @@ extern struct workqueue_struct *ccw_devi extern wait_queue_head_t ccw_device_init_wq; extern atomic_t ccw_device_init_count; +void io_subchannel_irq (struct device *pdev); void io_subchannel_recog_done(struct ccw_device *cdev); int ccw_device_cancel_halt_clear(struct ccw_device *); @@ -118,6 +119,7 @@ int ccw_device_stlck(struct ccw_device * /* qdio needs this. */ void ccw_device_set_timeout(struct ccw_device *, int); extern struct subchannel_id ccw_device_get_subchannel_id(struct ccw_device *); +extern struct bus_type ccw_bus_type; /* Channel measurement facility related */ void retry_set_schib(struct ccw_device *cdev); diff --git a/drivers/s390/cio/device_fsm.c b/drivers/s390/cio/device_fsm.c index eed1457..51238e7 100644 --- a/drivers/s390/cio/device_fsm.c +++ b/drivers/s390/cio/device_fsm.c @@ -206,7 +206,7 @@ ccw_device_handle_oper(struct ccw_device * been varied online on the SE so we have to find out by magic (i. e. driving * the channel subsystem to device selection and updating our path masks). */ -static inline void +static void __recover_lost_chpids(struct subchannel *sch, int old_lpm) { int mask, i; @@ -387,7 +387,7 @@ ccw_device_done(struct ccw_device *cdev, put_device (&cdev->dev); } -static inline int cmp_pgid(struct pgid *p1, struct pgid *p2) +static int cmp_pgid(struct pgid *p1, struct pgid *p2) { char *c1; char *c2; @@ -842,6 +842,8 @@ ccw_device_irq(struct ccw_device *cdev, call_handler_unsol: if (cdev->handler) cdev->handler (cdev, 0, irb); + if (cdev->private->flags.doverify) + ccw_device_online_verify(cdev, 0); return; } /* Accumulate status and find out if a basic sense is needed. */ @@ -892,7 +894,7 @@ ccw_device_online_timeout(struct ccw_dev /* * Got an interrupt for a basic sense. */ -void +static void ccw_device_w4sense(struct ccw_device *cdev, enum dev_event dev_event) { struct irb *irb; diff --git a/drivers/s390/cio/device_id.c b/drivers/s390/cio/device_id.c index f172759..997f468 100644 --- a/drivers/s390/cio/device_id.c +++ b/drivers/s390/cio/device_id.c @@ -11,6 +11,7 @@ #include #include +#include #include #include @@ -138,7 +139,7 @@ VM_virtual_device_info (__u16 devno, str ps->cu_model = 0x60; return; } - for (i = 0; i < sizeof(vm_devices) / sizeof(vm_devices[0]); i++) + for (i = 0; i < ARRAY_SIZE(vm_devices); i++) if (diag_data.vrdcvcla == vm_devices[i].vrdcvcla && diag_data.vrdcvtyp == vm_devices[i].vrdcvtyp) { ps->cu_type = vm_devices[i].cu_type; diff --git a/drivers/s390/cio/device_ops.c b/drivers/s390/cio/device_ops.c index d269607..7c7775a 100644 --- a/drivers/s390/cio/device_ops.c +++ b/drivers/s390/cio/device_ops.c @@ -23,8 +23,7 @@ #include "css.h" #include "chsc.h" #include "device.h" -int -ccw_device_set_options(struct ccw_device *cdev, unsigned long flags) +int ccw_device_set_options_mask(struct ccw_device *cdev, unsigned long flags) { /* * The flag usage is mutal exclusive ... @@ -39,6 +38,33 @@ ccw_device_set_options(struct ccw_device return 0; } +int ccw_device_set_options(struct ccw_device *cdev, unsigned long flags) +{ + /* + * The flag usage is mutal exclusive ... + */ + if (((flags & CCWDEV_EARLY_NOTIFICATION) && + (flags & CCWDEV_REPORT_ALL)) || + ((flags & CCWDEV_EARLY_NOTIFICATION) && + cdev->private->options.repall) || + ((flags & CCWDEV_REPORT_ALL) && + cdev->private->options.fast)) + return -EINVAL; + cdev->private->options.fast |= (flags & CCWDEV_EARLY_NOTIFICATION) != 0; + cdev->private->options.repall |= (flags & CCWDEV_REPORT_ALL) != 0; + cdev->private->options.pgroup |= (flags & CCWDEV_DO_PATHGROUP) != 0; + cdev->private->options.force |= (flags & CCWDEV_ALLOW_FORCE) != 0; + return 0; +} + +void ccw_device_clear_options(struct ccw_device *cdev, unsigned long flags) +{ + cdev->private->options.fast &= (flags & CCWDEV_EARLY_NOTIFICATION) == 0; + cdev->private->options.repall &= (flags & CCWDEV_REPORT_ALL) == 0; + cdev->private->options.pgroup &= (flags & CCWDEV_DO_PATHGROUP) == 0; + cdev->private->options.force &= (flags & CCWDEV_ALLOW_FORCE) == 0; +} + int ccw_device_clear(struct ccw_device *cdev, unsigned long intparm) { @@ -302,7 +328,7 @@ ccw_device_wake_up(struct ccw_device *cd wake_up(&cdev->private->wait_q); } -static inline int +static int __ccw_device_retry_loop(struct ccw_device *cdev, struct ccw1 *ccw, long magic, __u8 lpm) { int ret; @@ -601,7 +627,9 @@ _ccw_device_get_device_number(struct ccw MODULE_LICENSE("GPL"); +EXPORT_SYMBOL(ccw_device_set_options_mask); EXPORT_SYMBOL(ccw_device_set_options); +EXPORT_SYMBOL(ccw_device_clear_options); EXPORT_SYMBOL(ccw_device_clear); EXPORT_SYMBOL(ccw_device_halt); EXPORT_SYMBOL(ccw_device_resume); diff --git a/drivers/s390/cio/device_status.c b/drivers/s390/cio/device_status.c index bdcf930..6b1caea 100644 --- a/drivers/s390/cio/device_status.c +++ b/drivers/s390/cio/device_status.c @@ -25,7 +25,7 @@ #include "ioasm.h" * Check for any kind of channel or interface control check but don't * issue the message for the console device */ -static inline void +static void ccw_device_msg_control_check(struct ccw_device *cdev, struct irb *irb) { if (!(irb->scsw.cstat & (SCHN_STAT_CHN_DATA_CHK | @@ -72,7 +72,7 @@ ccw_device_path_notoper(struct ccw_devic /* * Copy valid bits from the extended control word to device irb. */ -static inline void +static void ccw_device_accumulate_ecw(struct ccw_device *cdev, struct irb *irb) { /* @@ -94,7 +94,7 @@ ccw_device_accumulate_ecw(struct ccw_dev /* * Check if extended status word is valid. */ -static inline int +static int ccw_device_accumulate_esw_valid(struct irb *irb) { if (!irb->scsw.eswf && irb->scsw.stctl == SCSW_STCTL_STATUS_PEND) @@ -109,7 +109,7 @@ ccw_device_accumulate_esw_valid(struct i /* * Copy valid bits from the extended status word to device irb. */ -static inline void +static void ccw_device_accumulate_esw(struct ccw_device *cdev, struct irb *irb) { struct irb *cdev_irb; diff --git a/drivers/s390/cio/qdio.c b/drivers/s390/cio/qdio.c index 6fd1940..5b1e3ff 100644 --- a/drivers/s390/cio/qdio.c +++ b/drivers/s390/cio/qdio.c @@ -66,7 +66,6 @@ MODULE_LICENSE("GPL"); /******************** HERE WE GO ***********************************/ static const char version[] = "QDIO base support version 2"; -extern struct bus_type ccw_bus_type; static int qdio_performance_stats = 0; static int proc_perf_file_registration; @@ -138,7 +137,7 @@ qdio_release_q(struct qdio_q *q) } /*check ccq */ -static inline int +static int qdio_check_ccq(struct qdio_q *q, unsigned int ccq) { char dbf_text[15]; @@ -153,7 +152,7 @@ qdio_check_ccq(struct qdio_q *q, unsigne return -EIO; } /* EQBS: extract buffer states */ -static inline int +static int qdio_do_eqbs(struct qdio_q *q, unsigned char *state, unsigned int *start, unsigned int *cnt) { @@ -188,7 +187,7 @@ again: } /* SQBS: set buffer states */ -static inline int +static int qdio_do_sqbs(struct qdio_q *q, unsigned char state, unsigned int *start, unsigned int *cnt) { @@ -315,7 +314,7 @@ __do_siga_output(struct qdio_q *q, unsig * returns QDIO_SIGA_ERROR_ACCESS_EXCEPTION as cc, when SIGA returns * an access exception */ -static inline int +static int qdio_siga_output(struct qdio_q *q) { int cc; @@ -349,7 +348,7 @@ qdio_siga_output(struct qdio_q *q) return cc; } -static inline int +static int qdio_siga_input(struct qdio_q *q) { int cc; @@ -421,7 +420,7 @@ tiqdio_sched_tl(void) tasklet_hi_schedule(&tiqdio_tasklet); } -static inline void +static void qdio_mark_tiq(struct qdio_q *q) { unsigned long flags; @@ -471,7 +470,7 @@ qdio_mark_q(struct qdio_q *q) tasklet_schedule(&q->tasklet); } -static inline int +static int qdio_stop_polling(struct qdio_q *q) { #ifdef QDIO_USE_PROCESSING_STATE @@ -525,7 +524,7 @@ #endif /* QDIO_USE_PROCESSING_STATE */ * sophisticated locking outside of unmark_q, so that we don't need to * disable the interrupts :-) */ -static inline void +static void qdio_unmark_q(struct qdio_q *q) { unsigned long flags; @@ -691,7 +690,7 @@ #endif return q->first_to_check; } -static inline int +static int qdio_get_outbound_buffer_frontier(struct qdio_q *q) { struct qdio_irq *irq; @@ -774,7 +773,7 @@ out: } /* all buffers are processed */ -static inline int +static int qdio_is_outbound_q_done(struct qdio_q *q) { int no_used; @@ -796,7 +795,7 @@ #endif /* CONFIG_QDIO_DEBUG */ return (no_used==0); } -static inline int +static int qdio_has_outbound_q_moved(struct qdio_q *q) { int i; @@ -816,7 +815,7 @@ qdio_has_outbound_q_moved(struct qdio_q } } -static inline void +static void qdio_kick_outbound_q(struct qdio_q *q) { int result; @@ -905,7 +904,7 @@ #endif /* CONFIG_QDIO_DEBUG */ } } -static inline void +static void qdio_kick_outbound_handler(struct qdio_q *q) { int start, end, real_end, count; @@ -942,7 +941,7 @@ #endif /* CONFIG_QDIO_DEBUG */ q->error_status_flags=0; } -static inline void +static void __qdio_outbound_processing(struct qdio_q *q) { int siga_attempts; @@ -1002,7 +1001,7 @@ qdio_outbound_processing(struct qdio_q * /************************* INBOUND ROUTINES *******************************/ -static inline int +static int qdio_get_inbound_buffer_frontier(struct qdio_q *q) { struct qdio_irq *irq; @@ -1133,7 +1132,7 @@ #endif /* QDIO_USE_PROCESSING_STATE */ return q->first_to_check; } -static inline int +static int qdio_has_inbound_q_moved(struct qdio_q *q) { int i; @@ -1167,7 +1166,7 @@ qdio_has_inbound_q_moved(struct qdio_q * } /* means, no more buffers to be filled */ -static inline int +static int tiqdio_is_inbound_q_done(struct qdio_q *q) { int no_used; @@ -1228,7 +1227,7 @@ #endif /* CONFIG_QDIO_DEBUG */ return 0; } -static inline int +static int qdio_is_inbound_q_done(struct qdio_q *q) { int no_used; @@ -1296,7 +1295,7 @@ #endif /* CONFIG_QDIO_DEBUG */ } } -static inline void +static void qdio_kick_inbound_handler(struct qdio_q *q) { int count, start, end, real_end, i; @@ -1343,7 +1342,7 @@ #endif /* CONFIG_QDIO_DEBUG */ } } -static inline void +static void __tiqdio_inbound_processing(struct qdio_q *q, int spare_ind_was_set) { struct qdio_irq *irq_ptr; @@ -1442,7 +1441,7 @@ tiqdio_inbound_processing(struct qdio_q __tiqdio_inbound_processing(q, atomic_read(&spare_indicator_usecount)); } -static inline void +static void __qdio_inbound_processing(struct qdio_q *q) { int q_laps=0; @@ -1493,7 +1492,7 @@ qdio_inbound_processing(struct qdio_q *q /************************* MAIN ROUTINES *******************************/ #ifdef QDIO_USE_PROCESSING_STATE -static inline int +static int tiqdio_reset_processing_state(struct qdio_q *q, int q_laps) { if (!q) { @@ -1545,7 +1544,7 @@ tiqdio_reset_processing_state(struct qdi } #endif /* QDIO_USE_PROCESSING_STATE */ -static inline void +static void tiqdio_inbound_checks(void) { struct qdio_q *q; @@ -1949,7 +1948,7 @@ #endif /* CONFIG_QDIO_DEBUG */ mb(); } -static inline void +static void qdio_irq_check_sense(struct subchannel_id schid, struct irb *irb) { char dbf_text[15]; @@ -1966,7 +1965,7 @@ qdio_irq_check_sense(struct subchannel_i } -static inline void +static void qdio_handle_pci(struct qdio_irq *irq_ptr) { int i; @@ -2002,7 +2001,7 @@ qdio_handle_pci(struct qdio_irq *irq_ptr static void qdio_establish_handle_irq(struct ccw_device*, int, int); -static inline void +static void qdio_handle_activate_check(struct ccw_device *cdev, unsigned long intparm, int cstat, int dstat) { @@ -2229,7 +2228,7 @@ #endif /* CONFIG_QDIO_DEBUG */ return cc; } -static inline void +static void qdio_check_subchannel_qebsm(struct qdio_irq *irq_ptr, unsigned char qdioac, unsigned long token) { @@ -2740,7 +2739,7 @@ qdio_free(struct ccw_device *cdev) return 0; } -static inline void +static void qdio_allocate_do_dbf(struct qdio_initialize *init_data) { char dbf_text[20]; /* if a printf printed out more than 8 chars */ @@ -2773,7 +2772,7 @@ qdio_allocate_do_dbf(struct qdio_initial QDIO_DBF_HEX0(0,setup,&init_data->output_sbal_addr_array,sizeof(void*)); } -static inline void +static void qdio_allocate_fill_input_desc(struct qdio_irq *irq_ptr, int i, int iqfmt) { irq_ptr->input_qs[i]->is_iqdio_q = iqfmt; @@ -2792,7 +2791,7 @@ qdio_allocate_fill_input_desc(struct qdi irq_ptr->qdr->qdf0[i].dkey=QDIO_STORAGE_KEY; } -static inline void +static void qdio_allocate_fill_output_desc(struct qdio_irq *irq_ptr, int i, int j, int iqfmt) { @@ -2813,7 +2812,7 @@ qdio_allocate_fill_output_desc(struct qd } -static inline void +static void qdio_initialize_set_siga_flags_input(struct qdio_irq *irq_ptr) { int i; @@ -2839,7 +2838,7 @@ qdio_initialize_set_siga_flags_input(str } } -static inline void +static void qdio_initialize_set_siga_flags_output(struct qdio_irq *irq_ptr) { int i; @@ -2865,7 +2864,7 @@ qdio_initialize_set_siga_flags_output(st } } -static inline int +static int qdio_establish_irq_check_for_errors(struct ccw_device *cdev, int cstat, int dstat) { @@ -3014,7 +3013,7 @@ qdio_allocate(struct qdio_initialize *in return 0; } -int qdio_fill_irq(struct qdio_initialize *init_data) +static int qdio_fill_irq(struct qdio_initialize *init_data) { int i; char dbf_text[15]; @@ -3195,7 +3194,7 @@ qdio_establish(struct qdio_initialize *i spin_lock_irqsave(get_ccwdev_lock(cdev),saveflags); - ccw_device_set_options(cdev, 0); + ccw_device_set_options_mask(cdev, 0); result=ccw_device_start_timeout(cdev,&irq_ptr->ccw, QDIO_DOING_ESTABLISH,0, 0, QDIO_ESTABLISH_TIMEOUT); @@ -3367,7 +3366,7 @@ qdio_activate(struct ccw_device *cdev, i } /* buffers filled forwards again to make Rick happy */ -static inline void +static void qdio_do_qdio_fill_input(struct qdio_q *q, unsigned int qidx, unsigned int count, struct qdio_buffer *buffers) { @@ -3386,7 +3385,7 @@ qdio_do_qdio_fill_input(struct qdio_q *q } } -static inline void +static void qdio_do_qdio_fill_output(struct qdio_q *q, unsigned int qidx, unsigned int count, struct qdio_buffer *buffers) { @@ -3407,7 +3406,7 @@ qdio_do_qdio_fill_output(struct qdio_q * } } -static inline void +static void do_qdio_handle_inbound(struct qdio_q *q, unsigned int callflags, unsigned int qidx, unsigned int count, struct qdio_buffer *buffers) @@ -3443,7 +3442,7 @@ do_qdio_handle_inbound(struct qdio_q *q, qdio_mark_q(q); } -static inline void +static void do_qdio_handle_outbound(struct qdio_q *q, unsigned int callflags, unsigned int qidx, unsigned int count, struct qdio_buffer *buffers) diff --git a/drivers/s390/crypto/ap_bus.c b/drivers/s390/crypto/ap_bus.c index 81b5899..c7d1355 100644 --- a/drivers/s390/crypto/ap_bus.c +++ b/drivers/s390/crypto/ap_bus.c @@ -465,7 +465,7 @@ static int ap_device_probe(struct device * Flush all requests from the request/pending queue of an AP device. * @ap_dev: pointer to the AP device. */ -static inline void __ap_flush_queue(struct ap_device *ap_dev) +static void __ap_flush_queue(struct ap_device *ap_dev) { struct ap_message *ap_msg, *next; @@ -587,7 +587,7 @@ static struct bus_attribute *const ap_bu /** * Pick one of the 16 ap domains. */ -static inline int ap_select_domain(void) +static int ap_select_domain(void) { int queue_depth, device_type, count, max_count, best_domain; int rc, i, j; @@ -825,7 +825,7 @@ static inline void ap_schedule_poll_time * required, bit 2^1 is set if the poll timer needs to get armed * Returns 0 if the device is still present, -ENODEV if not. */ -static inline int ap_poll_read(struct ap_device *ap_dev, unsigned long *flags) +static int ap_poll_read(struct ap_device *ap_dev, unsigned long *flags) { struct ap_queue_status status; struct ap_message *ap_msg; @@ -872,7 +872,7 @@ static inline int ap_poll_read(struct ap * required, bit 2^1 is set if the poll timer needs to get armed * Returns 0 if the device is still present, -ENODEV if not. */ -static inline int ap_poll_write(struct ap_device *ap_dev, unsigned long *flags) +static int ap_poll_write(struct ap_device *ap_dev, unsigned long *flags) { struct ap_queue_status status; struct ap_message *ap_msg; diff --git a/drivers/s390/crypto/zcrypt_api.c b/drivers/s390/crypto/zcrypt_api.c index 1edc10a..9976139 100644 --- a/drivers/s390/crypto/zcrypt_api.c +++ b/drivers/s390/crypto/zcrypt_api.c @@ -791,7 +791,7 @@ static long trans_xcRB32(struct file *fi return rc; } -long zcrypt_compat_ioctl(struct file *filp, unsigned int cmd, +static long zcrypt_compat_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) { if (cmd == ICARSAMODEXPO) @@ -807,7 +807,7 @@ #endif /** * Misc device file operations. */ -static struct file_operations zcrypt_fops = { +static const struct file_operations zcrypt_fops = { .owner = THIS_MODULE, .read = zcrypt_read, .write = zcrypt_write, @@ -833,8 +833,8 @@ static struct miscdevice zcrypt_misc_dev */ static struct proc_dir_entry *zcrypt_entry; -static inline int sprintcl(unsigned char *outaddr, unsigned char *addr, - unsigned int len) +static int sprintcl(unsigned char *outaddr, unsigned char *addr, + unsigned int len) { int hl, i; @@ -845,8 +845,8 @@ static inline int sprintcl(unsigned char return hl; } -static inline int sprintrw(unsigned char *outaddr, unsigned char *addr, - unsigned int len) +static int sprintrw(unsigned char *outaddr, unsigned char *addr, + unsigned int len) { int hl, inl, c, cx; @@ -865,8 +865,8 @@ static inline int sprintrw(unsigned char return hl; } -static inline int sprinthx(unsigned char *title, unsigned char *outaddr, - unsigned char *addr, unsigned int len) +static int sprinthx(unsigned char *title, unsigned char *outaddr, + unsigned char *addr, unsigned int len) { int hl, inl, r, rx; @@ -885,8 +885,8 @@ static inline int sprinthx(unsigned char return hl; } -static inline int sprinthx4(unsigned char *title, unsigned char *outaddr, - unsigned int *array, unsigned int len) +static int sprinthx4(unsigned char *title, unsigned char *outaddr, + unsigned int *array, unsigned int len) { int hl, r; @@ -943,7 +943,7 @@ static int zcrypt_status_read(char *resp zcrypt_qdepth_mask(workarea); len += sprinthx("Waiting work element counts", resp_buff+len, workarea, AP_DEVICES); - zcrypt_perdev_reqcnt((unsigned int *) workarea); + zcrypt_perdev_reqcnt((int *) workarea); len += sprinthx4("Per-device successfully completed request counts", resp_buff+len,(unsigned int *) workarea, AP_DEVICES); *eof = 1; @@ -1063,7 +1063,6 @@ int __init zcrypt_api_init(void) rc = -ENOMEM; goto out_misc; } - zcrypt_entry->nlink = 1; zcrypt_entry->data = NULL; zcrypt_entry->read_proc = zcrypt_status_read; zcrypt_entry->write_proc = zcrypt_status_write; diff --git a/drivers/s390/crypto/zcrypt_pcica.c b/drivers/s390/crypto/zcrypt_pcica.c index 32e3701..818ffe0 100644 --- a/drivers/s390/crypto/zcrypt_pcica.c +++ b/drivers/s390/crypto/zcrypt_pcica.c @@ -191,10 +191,10 @@ static int ICACRT_msg_to_type4CRT_msg(st * * Returns 0 on success or -EFAULT. */ -static inline int convert_type84(struct zcrypt_device *zdev, - struct ap_message *reply, - char __user *outputdata, - unsigned int outputdatalength) +static int convert_type84(struct zcrypt_device *zdev, + struct ap_message *reply, + char __user *outputdata, + unsigned int outputdatalength) { struct type84_hdr *t84h = reply->message; char *data; diff --git a/drivers/s390/crypto/zcrypt_pcixcc.c b/drivers/s390/crypto/zcrypt_pcixcc.c index b7153c1..252443b 100644 --- a/drivers/s390/crypto/zcrypt_pcixcc.c +++ b/drivers/s390/crypto/zcrypt_pcixcc.c @@ -709,7 +709,8 @@ out_free: * PCIXCC/CEX2C device to the request distributor * @xcRB: pointer to the send_cprb request buffer */ -long zcrypt_pcixcc_send_cprb(struct zcrypt_device *zdev, struct ica_xcRB *xcRB) +static long zcrypt_pcixcc_send_cprb(struct zcrypt_device *zdev, + struct ica_xcRB *xcRB) { struct ap_message ap_msg; struct response_type resp_type = { diff --git a/drivers/s390/net/Kconfig b/drivers/s390/net/Kconfig index 5262515..f98fa46 100644 --- a/drivers/s390/net/Kconfig +++ b/drivers/s390/net/Kconfig @@ -22,13 +22,6 @@ config CTC available. This option is also available as a module which will be called ctc.ko. If you do not know what it is, it's safe to say "Y". -config IUCV - tristate "IUCV support (VM only)" - help - Select this option if you want to use inter-user communication - under VM or VIF. If unsure, say "Y" to enable a fast communication - link between VM guests. - config NETIUCV tristate "IUCV network device support (VM only)" depends on IUCV && NETDEVICES diff --git a/drivers/s390/net/Makefile b/drivers/s390/net/Makefile index 4777e36..bbe3ab2 100644 --- a/drivers/s390/net/Makefile +++ b/drivers/s390/net/Makefile @@ -4,7 +4,6 @@ # ctc-objs := ctcmain.o ctcdbug.o -obj-$(CONFIG_IUCV) += iucv.o obj-$(CONFIG_NETIUCV) += netiucv.o fsm.o obj-$(CONFIG_SMSGIUCV) += smsgiucv.o obj-$(CONFIG_CTC) += ctc.o fsm.o cu3088.o diff --git a/drivers/s390/net/claw.c b/drivers/s390/net/claw.c index 95f4e10..7809a79 100644 --- a/drivers/s390/net/claw.c +++ b/drivers/s390/net/claw.c @@ -121,7 +121,7 @@ #ifdef FUNCTRACE #define DEBUG #endif - char debug_buffer[255]; +static char debug_buffer[255]; /** * Debug Facility Stuff */ @@ -223,16 +223,14 @@ static void claw_timer ( struct chbk * p /* Functions */ static int add_claw_reads(struct net_device *dev, struct ccwbk* p_first, struct ccwbk* p_last); -static void inline ccw_check_return_code (struct ccw_device *cdev, - int return_code); -static void inline ccw_check_unit_check (struct chbk * p_ch, - unsigned char sense ); +static void ccw_check_return_code (struct ccw_device *cdev, int return_code); +static void ccw_check_unit_check (struct chbk * p_ch, unsigned char sense ); static int find_link(struct net_device *dev, char *host_name, char *ws_name ); static int claw_hw_tx(struct sk_buff *skb, struct net_device *dev, long linkid); static int init_ccw_bk(struct net_device *dev); static void probe_error( struct ccwgroup_device *cgdev); static struct net_device_stats *claw_stats(struct net_device *dev); -static int inline pages_to_order_of_mag(int num_of_pages); +static int pages_to_order_of_mag(int num_of_pages); static struct sk_buff *claw_pack_skb(struct claw_privbk *privptr); #ifdef DEBUG static void dumpit (char *buf, int len); @@ -1310,7 +1308,7 @@ #endif * of magnitude get_free_pages() has an upper order of 9 * *--------------------------------------------------------------------*/ -static int inline +static int pages_to_order_of_mag(int num_of_pages) { int order_of_mag=1; /* assume 2 pages */ @@ -1482,7 +1480,7 @@ #endif * * *-------------------------------------------------------------------*/ -static void inline +static void ccw_check_return_code(struct ccw_device *cdev, int return_code) { #ifdef FUNCTRACE @@ -1529,7 +1527,7 @@ #endif * ccw_check_unit_check * *--------------------------------------------------------------------*/ -static void inline +static void ccw_check_unit_check(struct chbk * p_ch, unsigned char sense ) { struct net_device *dev = p_ch->ndev; diff --git a/drivers/s390/net/ctcmain.c b/drivers/s390/net/ctcmain.c index 03cc263..0d6d5fc 100644 --- a/drivers/s390/net/ctcmain.c +++ b/drivers/s390/net/ctcmain.c @@ -45,7 +45,6 @@ #include #include #include #include -#include #include #include @@ -369,7 +368,7 @@ #endif * @param ch The channel where this skb has been received. * @param pskb The received skb. */ -static __inline__ void +static void ctc_unpack_skb(struct channel *ch, struct sk_buff *pskb) { struct net_device *dev = ch->netdev; @@ -512,7 +511,7 @@ #endif * @param ch The channel, the error belongs to. * @param return_code The error code to inspect. */ -static void inline +static void ccw_check_return_code(struct channel *ch, int return_code, char *msg) { DBF_TEXT(trace, 5, __FUNCTION__); @@ -547,7 +546,7 @@ ccw_check_return_code(struct channel *ch * @param ch The channel, the sense code belongs to. * @param sense The sense code to inspect. */ -static void inline +static void ccw_unit_check(struct channel *ch, unsigned char sense) { DBF_TEXT(trace, 5, __FUNCTION__); @@ -603,7 +602,7 @@ ctc_purge_skb_queue(struct sk_buff_head } } -static __inline__ int +static int ctc_checkalloc_buffer(struct channel *ch, int warn) { DBF_TEXT(trace, 5, __FUNCTION__); diff --git a/drivers/s390/net/cu3088.c b/drivers/s390/net/cu3088.c index e965f03..76728ae 100644 --- a/drivers/s390/net/cu3088.c +++ b/drivers/s390/net/cu3088.c @@ -57,7 +57,7 @@ static struct ccw_device_id cu3088_ids[] static struct ccw_driver cu3088_driver; -struct device *cu3088_root_dev; +static struct device *cu3088_root_dev; static ssize_t group_write(struct device_driver *drv, const char *buf, size_t count) diff --git a/drivers/s390/net/iucv.c b/drivers/s390/net/iucv.c deleted file mode 100644 index 229aeb5..0000000 --- a/drivers/s390/net/iucv.c +++ /dev/null @@ -1,2540 +0,0 @@ -/* - * IUCV network driver - * - * Copyright (C) 2001 IBM Deutschland Entwicklung GmbH, IBM Corporation - * Author(s): - * Original source: - * Alan Altmark (Alan_Altmark@us.ibm.com) Sept. 2000 - * Xenia Tkatschow (xenia@us.ibm.com) - * 2Gb awareness and general cleanup: - * Fritz Elfert (elfert@de.ibm.com, felfert@millenux.com) - * - * Documentation used: - * The original source - * CP Programming Service, IBM document # SC24-5760 - * - * 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, or (at your option) - * any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - * - */ - -/* #define DEBUG */ - -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "iucv.h" -#include -#include -#include -#include -#include - -/* FLAGS: - * All flags are defined in the field IPFLAGS1 of each function - * and can be found in CP Programming Services. - * IPSRCCLS - Indicates you have specified a source class - * IPFGMCL - Indicates you have specified a target class - * IPFGPID - Indicates you have specified a pathid - * IPFGMID - Indicates you have specified a message ID - * IPANSLST - Indicates that you are using an address list for - * reply data - * IPBUFLST - Indicates that you are using an address list for - * message data - */ - -#define IPSRCCLS 0x01 -#define IPFGMCL 0x01 -#define IPFGPID 0x02 -#define IPFGMID 0x04 -#define IPANSLST 0x08 -#define IPBUFLST 0x40 - -static int -iucv_bus_match (struct device *dev, struct device_driver *drv) -{ - return 0; -} - -struct bus_type iucv_bus = { - .name = "iucv", - .match = iucv_bus_match, -}; - -struct device *iucv_root; - -/* General IUCV interrupt structure */ -typedef struct { - __u16 ippathid; - __u8 res1; - __u8 iptype; - __u32 res2; - __u8 ipvmid[8]; - __u8 res3[24]; -} iucv_GeneralInterrupt; - -static iucv_GeneralInterrupt *iucv_external_int_buffer = NULL; - -/* Spin Lock declaration */ - -static DEFINE_SPINLOCK(iucv_lock); - -static int messagesDisabled = 0; - -/***************INTERRUPT HANDLING ***************/ - -typedef struct { - struct list_head queue; - iucv_GeneralInterrupt data; -} iucv_irqdata; - -static struct list_head iucv_irq_queue; -static DEFINE_SPINLOCK(iucv_irq_queue_lock); - -/* - *Internal function prototypes - */ -static void iucv_tasklet_handler(unsigned long); -static void iucv_irq_handler(__u16); - -static DECLARE_TASKLET(iucv_tasklet,iucv_tasklet_handler,0); - -/************ FUNCTION ID'S ****************************/ - -#define ACCEPT 10 -#define CONNECT 11 -#define DECLARE_BUFFER 12 -#define PURGE 9 -#define QUERY 0 -#define QUIESCE 13 -#define RECEIVE 5 -#define REJECT 8 -#define REPLY 6 -#define RESUME 14 -#define RETRIEVE_BUFFER 2 -#define SEND 4 -#define SETMASK 16 -#define SEVER 15 - -/** - * Structure: handler - * members: list - list management. - * structure: id - * userid - 8 char array of machine identification - * user_data - 16 char array for user identification - * mask - 24 char array used to compare the 2 previous - * interrupt_table - vector of interrupt functions. - * pgm_data - ulong, application data that is passed - * to the interrupt handlers -*/ -typedef struct handler_t { - struct list_head list; - struct { - __u8 userid[8]; - __u8 user_data[16]; - __u8 mask[24]; - } id; - iucv_interrupt_ops_t *interrupt_table; - void *pgm_data; -} handler; - -/** - * iucv_handler_table: List of registered handlers. - */ -static struct list_head iucv_handler_table; - -/** - * iucv_pathid_table: an array of *handler pointing into - * iucv_handler_table for fast indexing by pathid; - */ -static handler **iucv_pathid_table; - -static unsigned long max_connections; - -/** - * iucv_cpuid: contains the logical cpu number of the cpu which - * has declared the iucv buffer by issuing DECLARE_BUFFER. - * If no cpu has done the initialization iucv_cpuid contains -1. - */ -static int iucv_cpuid = -1; -/** - * register_flag: is 0 when external interrupt has not been registered - */ -static int register_flag; - -/****************FIVE 40-BYTE PARAMETER STRUCTURES******************/ -/* Data struct 1: iparml_control - * Used for iucv_accept - * iucv_connect - * iucv_quiesce - * iucv_resume - * iucv_sever - * iucv_retrieve_buffer - * Data struct 2: iparml_dpl (data in parameter list) - * Used for iucv_send_prmmsg - * iucv_send2way_prmmsg - * iucv_send2way_prmmsg_array - * iucv_reply_prmmsg - * Data struct 3: iparml_db (data in a buffer) - * Used for iucv_receive - * iucv_receive_array - * iucv_reject - * iucv_reply - * iucv_reply_array - * iucv_send - * iucv_send_array - * iucv_send2way - * iucv_send2way_array - * iucv_declare_buffer - * Data struct 4: iparml_purge - * Used for iucv_purge - * iucv_query - * Data struct 5: iparml_set_mask - * Used for iucv_set_mask - */ - -typedef struct { - __u16 ippathid; - __u8 ipflags1; - __u8 iprcode; - __u16 ipmsglim; - __u16 res1; - __u8 ipvmid[8]; - __u8 ipuser[16]; - __u8 iptarget[8]; -} iparml_control; - -typedef struct { - __u16 ippathid; - __u8 ipflags1; - __u8 iprcode; - __u32 ipmsgid; - __u32 iptrgcls; - __u8 iprmmsg[8]; - __u32 ipsrccls; - __u32 ipmsgtag; - __u32 ipbfadr2; - __u32 ipbfln2f; - __u32 res; -} iparml_dpl; - -typedef struct { - __u16 ippathid; - __u8 ipflags1; - __u8 iprcode; - __u32 ipmsgid; - __u32 iptrgcls; - __u32 ipbfadr1; - __u32 ipbfln1f; - __u32 ipsrccls; - __u32 ipmsgtag; - __u32 ipbfadr2; - __u32 ipbfln2f; - __u32 res; -} iparml_db; - -typedef struct { - __u16 ippathid; - __u8 ipflags1; - __u8 iprcode; - __u32 ipmsgid; - __u8 ipaudit[3]; - __u8 res1[5]; - __u32 res2; - __u32 ipsrccls; - __u32 ipmsgtag; - __u32 res3[3]; -} iparml_purge; - -typedef struct { - __u8 ipmask; - __u8 res1[2]; - __u8 iprcode; - __u32 res2[9]; -} iparml_set_mask; - -typedef struct { - union { - iparml_control p_ctrl; - iparml_dpl p_dpl; - iparml_db p_db; - iparml_purge p_purge; - iparml_set_mask p_set_mask; - } param; - atomic_t in_use; - __u32 res; -} __attribute__ ((aligned(8))) iucv_param; -#define PARAM_POOL_SIZE (PAGE_SIZE / sizeof(iucv_param)) - -static iucv_param * iucv_param_pool; - -MODULE_AUTHOR("(C) 2001 IBM Corp. by Fritz Elfert (felfert@millenux.com)"); -MODULE_DESCRIPTION("Linux for S/390 IUCV lowlevel driver"); -MODULE_LICENSE("GPL"); - -/* - * Debugging stuff - *******************************************************************************/ - - -#ifdef DEBUG -static int debuglevel = 0; - -module_param(debuglevel, int, 0); -MODULE_PARM_DESC(debuglevel, - "Specifies the debug level (0=off ... 3=all)"); - -static void -iucv_dumpit(char *title, void *buf, int len) -{ - int i; - __u8 *p = (__u8 *)buf; - - if (debuglevel < 3) - return; - - printk(KERN_DEBUG "%s\n", title); - printk(" "); - for (i = 0; i < len; i++) { - if (!(i % 16) && i != 0) - printk ("\n "); - else if (!(i % 4) && i != 0) - printk(" "); - printk("%02X", *p++); - } - if (len % 16) - printk ("\n"); - return; -} -#define iucv_debug(lvl, fmt, args...) \ -do { \ - if (debuglevel >= lvl) \ - printk(KERN_DEBUG "%s: " fmt "\n", __FUNCTION__ , ## args); \ -} while (0) - -#else - -#define iucv_debug(lvl, fmt, args...) do { } while (0) -#define iucv_dumpit(title, buf, len) do { } while (0) - -#endif - -/* - * Internal functions - *******************************************************************************/ - -/** - * print start banner - */ -static void -iucv_banner(void) -{ - printk(KERN_INFO "IUCV lowlevel driver initialized\n"); -} - -/** - * iucv_init - Initialization - * - * Allocates and initializes various data structures. - */ -static int -iucv_init(void) -{ - int ret; - - if (iucv_external_int_buffer) - return 0; - - if (!MACHINE_IS_VM) { - printk(KERN_ERR "IUCV: IUCV connection needs VM as base\n"); - return -EPROTONOSUPPORT; - } - - ret = bus_register(&iucv_bus); - if (ret) { - printk(KERN_ERR "IUCV: failed to register bus.\n"); - return ret; - } - - iucv_root = s390_root_dev_register("iucv"); - if (IS_ERR(iucv_root)) { - printk(KERN_ERR "IUCV: failed to register iucv root.\n"); - bus_unregister(&iucv_bus); - return PTR_ERR(iucv_root); - } - - /* Note: GFP_DMA used used to get memory below 2G */ - iucv_external_int_buffer = kzalloc(sizeof(iucv_GeneralInterrupt), - GFP_KERNEL|GFP_DMA); - if (!iucv_external_int_buffer) { - printk(KERN_WARNING - "%s: Could not allocate external interrupt buffer\n", - __FUNCTION__); - s390_root_dev_unregister(iucv_root); - bus_unregister(&iucv_bus); - return -ENOMEM; - } - - /* Initialize parameter pool */ - iucv_param_pool = kzalloc(sizeof(iucv_param) * PARAM_POOL_SIZE, - GFP_KERNEL|GFP_DMA); - if (!iucv_param_pool) { - printk(KERN_WARNING "%s: Could not allocate param pool\n", - __FUNCTION__); - kfree(iucv_external_int_buffer); - iucv_external_int_buffer = NULL; - s390_root_dev_unregister(iucv_root); - bus_unregister(&iucv_bus); - return -ENOMEM; - } - - /* Initialize irq queue */ - INIT_LIST_HEAD(&iucv_irq_queue); - - /* Initialize handler table */ - INIT_LIST_HEAD(&iucv_handler_table); - - iucv_banner(); - return 0; -} - -/** - * iucv_exit - De-Initialization - * - * Frees everything allocated from iucv_init. - */ -static int iucv_retrieve_buffer (void); - -static void -iucv_exit(void) -{ - iucv_retrieve_buffer(); - kfree(iucv_external_int_buffer); - iucv_external_int_buffer = NULL; - kfree(iucv_param_pool); - iucv_param_pool = NULL; - s390_root_dev_unregister(iucv_root); - bus_unregister(&iucv_bus); - printk(KERN_INFO "IUCV lowlevel driver unloaded\n"); -} - -/** - * grab_param: - Get a parameter buffer from the pre-allocated pool. - * - * This function searches for an unused element in the pre-allocated pool - * of parameter buffers. If one is found, it marks it "in use" and returns - * a pointer to it. The calling function is responsible for releasing it - * when it has finished its usage. - * - * Returns: A pointer to iucv_param. - */ -static __inline__ iucv_param * -grab_param(void) -{ - iucv_param *ptr; - static int hint = 0; - - ptr = iucv_param_pool + hint; - do { - ptr++; - if (ptr >= iucv_param_pool + PARAM_POOL_SIZE) - ptr = iucv_param_pool; - } while (atomic_cmpxchg(&ptr->in_use, 0, 1) != 0); - hint = ptr - iucv_param_pool; - - memset(&ptr->param, 0, sizeof(ptr->param)); - return ptr; -} - -/** - * release_param - Release a parameter buffer. - * @p: A pointer to a struct iucv_param, previously obtained by calling - * grab_param(). - * - * This function marks the specified parameter buffer "unused". - */ -static __inline__ void -release_param(void *p) -{ - atomic_set(&((iucv_param *)p)->in_use, 0); -} - -/** - * iucv_add_handler: - Add a new handler - * @new_handler: handle that is being entered into chain. - * - * Places new handle on iucv_handler_table, if identical handler is not - * found. - * - * Returns: 0 on success, !0 on failure (handler already in chain). - */ -static int -iucv_add_handler (handler *new) -{ - ulong flags; - - iucv_debug(1, "entering"); - iucv_dumpit("handler:", new, sizeof(handler)); - - spin_lock_irqsave (&iucv_lock, flags); - if (!list_empty(&iucv_handler_table)) { - struct list_head *lh; - - /** - * Search list for handler with identical id. If one - * is found, the new handler is _not_ added. - */ - list_for_each(lh, &iucv_handler_table) { - handler *h = list_entry(lh, handler, list); - if (!memcmp(&new->id, &h->id, sizeof(h->id))) { - iucv_debug(1, "ret 1"); - spin_unlock_irqrestore (&iucv_lock, flags); - return 1; - } - } - } - /** - * If we get here, no handler was found. - */ - INIT_LIST_HEAD(&new->list); - list_add(&new->list, &iucv_handler_table); - spin_unlock_irqrestore (&iucv_lock, flags); - - iucv_debug(1, "exiting"); - return 0; -} - -/** - * b2f0: - * @code: identifier of IUCV call to CP. - * @parm: pointer to 40 byte iparml area passed to CP - * - * Calls CP to execute IUCV commands. - * - * Returns: return code from CP's IUCV call - */ -static inline ulong b2f0(__u32 code, void *parm) -{ - register unsigned long reg0 asm ("0"); - register unsigned long reg1 asm ("1"); - iucv_dumpit("iparml before b2f0 call:", parm, sizeof(iucv_param)); - - reg0 = code; - reg1 = virt_to_phys(parm); - asm volatile(".long 0xb2f01000" : : "d" (reg0), "a" (reg1)); - - iucv_dumpit("iparml after b2f0 call:", parm, sizeof(iucv_param)); - - return (unsigned long)*((__u8 *)(parm + 3)); -} - -/* - * Name: iucv_add_pathid - * Purpose: Adds a path id to the system. - * Input: pathid - pathid that is going to be entered into system - * handle - address of handler that the pathid will be associated - * with. - * pgm_data - token passed in by application. - * Output: 0: successful addition of pathid - * - EINVAL - pathid entry is being used by another application - * - ENOMEM - storage allocation for a new pathid table failed -*/ -static int -__iucv_add_pathid(__u16 pathid, handler *handler) -{ - - iucv_debug(1, "entering"); - - iucv_debug(1, "handler is pointing to %p", handler); - - if (pathid > (max_connections - 1)) - return -EINVAL; - - if (iucv_pathid_table[pathid]) { - iucv_debug(1, "pathid entry is %p", iucv_pathid_table[pathid]); - printk(KERN_WARNING - "%s: Pathid being used, error.\n", __FUNCTION__); - return -EINVAL; - } - iucv_pathid_table[pathid] = handler; - - iucv_debug(1, "exiting"); - return 0; -} /* end of add_pathid function */ - -static int -iucv_add_pathid(__u16 pathid, handler *handler) -{ - ulong flags; - int rc; - - spin_lock_irqsave (&iucv_lock, flags); - rc = __iucv_add_pathid(pathid, handler); - spin_unlock_irqrestore (&iucv_lock, flags); - return rc; -} - -static void -iucv_remove_pathid(__u16 pathid) -{ - ulong flags; - - if (pathid > (max_connections - 1)) - return; - - spin_lock_irqsave (&iucv_lock, flags); - iucv_pathid_table[pathid] = NULL; - spin_unlock_irqrestore (&iucv_lock, flags); -} - -/** - * iucv_declare_buffer_cpuid - * Register at VM for subsequent IUCV operations. This is executed - * on the reserved CPU iucv_cpuid. Called from iucv_declare_buffer(). - */ -static void -iucv_declare_buffer_cpuid (void *result) -{ - iparml_db *parm; - - parm = (iparml_db *)grab_param(); - parm->ipbfadr1 = virt_to_phys(iucv_external_int_buffer); - if ((*((ulong *)result) = b2f0(DECLARE_BUFFER, parm)) == 1) - *((ulong *)result) = parm->iprcode; - release_param(parm); -} - -/** - * iucv_retrieve_buffer_cpuid: - * Unregister IUCV usage at VM. This is always executed on the same - * cpu that registered the buffer to VM. - * Called from iucv_retrieve_buffer(). - */ -static void -iucv_retrieve_buffer_cpuid (void *cpu) -{ - iparml_control *parm; - - parm = (iparml_control *)grab_param(); - b2f0(RETRIEVE_BUFFER, parm); - release_param(parm); -} - -/** - * Name: iucv_declare_buffer - * Purpose: Specifies the guests real address of an external - * interrupt. - * Input: void - * Output: iprcode - return code from b2f0 call - */ -static int -iucv_declare_buffer (void) -{ - unsigned long flags; - ulong b2f0_result; - - iucv_debug(1, "entering"); - b2f0_result = -ENODEV; - spin_lock_irqsave (&iucv_lock, flags); - if (iucv_cpuid == -1) { - /* Reserve any cpu for use by iucv. */ - iucv_cpuid = smp_get_cpu(CPU_MASK_ALL); - spin_unlock_irqrestore (&iucv_lock, flags); - smp_call_function_on(iucv_declare_buffer_cpuid, - &b2f0_result, 0, 1, iucv_cpuid); - if (b2f0_result) { - smp_put_cpu(iucv_cpuid); - iucv_cpuid = -1; - } - iucv_debug(1, "Address of EIB = %p", iucv_external_int_buffer); - } else { - spin_unlock_irqrestore (&iucv_lock, flags); - b2f0_result = 0; - } - iucv_debug(1, "exiting"); - return b2f0_result; -} - -/** - * iucv_retrieve_buffer: - * - * Terminates all use of IUCV. - * Returns: return code from CP - */ -static int -iucv_retrieve_buffer (void) -{ - iucv_debug(1, "entering"); - if (iucv_cpuid != -1) { - smp_call_function_on(iucv_retrieve_buffer_cpuid, - NULL, 0, 1, iucv_cpuid); - /* Release the cpu reserved by iucv_declare_buffer. */ - smp_put_cpu(iucv_cpuid); - iucv_cpuid = -1; - } - iucv_debug(1, "exiting"); - return 0; -} - -/** - * iucv_remove_handler: - * @users_handler: handler to be removed - * - * Remove handler when application unregisters. - */ -static void -iucv_remove_handler(handler *handler) -{ - unsigned long flags; - - if ((!iucv_pathid_table) || (!handler)) - return; - - iucv_debug(1, "entering"); - - spin_lock_irqsave (&iucv_lock, flags); - list_del(&handler->list); - if (list_empty(&iucv_handler_table)) { - if (register_flag) { - unregister_external_interrupt(0x4000, iucv_irq_handler); - register_flag = 0; - } - } - spin_unlock_irqrestore (&iucv_lock, flags); - - iucv_debug(1, "exiting"); - return; -} - -/** - * iucv_register_program: - * @pgmname: user identification - * @userid: machine identification - * @pgmmask: Indicates which bits in the pgmname and userid combined will be - * used to determine who is given control. - * @ops: Address of interrupt handler table. - * @pgm_data: Application data to be passed to interrupt handlers. - * - * Registers an application with IUCV. - * Returns: - * The address of handler, or NULL on failure. - * NOTE on pgmmask: - * If pgmname, userid and pgmmask are provided, pgmmask is entered into the - * handler as is. - * If pgmmask is NULL, the internal mask is set to all 0xff's - * When userid is NULL, the first 8 bytes of the internal mask are forced - * to 0x00. - * If pgmmask and userid are NULL, the first 8 bytes of the internal mask - * are forced to 0x00 and the last 16 bytes to 0xff. - */ - -iucv_handle_t -iucv_register_program (__u8 pgmname[16], - __u8 userid[8], - __u8 pgmmask[24], - iucv_interrupt_ops_t * ops, void *pgm_data) -{ - ulong rc = 0; /* return code from function calls */ - handler *new_handler; - - iucv_debug(1, "entering"); - - if (ops == NULL) { - /* interrupt table is not defined */ - printk(KERN_WARNING "%s: Interrupt table is not defined, " - "exiting\n", __FUNCTION__); - return NULL; - } - if (!pgmname) { - printk(KERN_WARNING "%s: pgmname not provided\n", __FUNCTION__); - return NULL; - } - - /* Allocate handler entry */ - new_handler = kmalloc(sizeof(handler), GFP_ATOMIC); - if (new_handler == NULL) { - printk(KERN_WARNING "%s: storage allocation for new handler " - "failed.\n", __FUNCTION__); - return NULL; - } - - if (!iucv_pathid_table) { - if (iucv_init()) { - kfree(new_handler); - return NULL; - } - - max_connections = iucv_query_maxconn(); - iucv_pathid_table = kcalloc(max_connections, sizeof(handler *), - GFP_ATOMIC); - if (iucv_pathid_table == NULL) { - printk(KERN_WARNING "%s: iucv_pathid_table storage " - "allocation failed\n", __FUNCTION__); - kfree(new_handler); - return NULL; - } - } - memset(new_handler, 0, sizeof (handler)); - memcpy(new_handler->id.user_data, pgmname, - sizeof (new_handler->id.user_data)); - if (userid) { - memcpy (new_handler->id.userid, userid, - sizeof (new_handler->id.userid)); - ASCEBC (new_handler->id.userid, - sizeof (new_handler->id.userid)); - EBC_TOUPPER (new_handler->id.userid, - sizeof (new_handler->id.userid)); - - if (pgmmask) { - memcpy (new_handler->id.mask, pgmmask, - sizeof (new_handler->id.mask)); - } else { - memset (new_handler->id.mask, 0xFF, - sizeof (new_handler->id.mask)); - } - } else { - if (pgmmask) { - memcpy (new_handler->id.mask, pgmmask, - sizeof (new_handler->id.mask)); - } else { - memset (new_handler->id.mask, 0xFF, - sizeof (new_handler->id.mask)); - } - memset (new_handler->id.userid, 0x00, - sizeof (new_handler->id.userid)); - } - /* fill in the rest of handler */ - new_handler->pgm_data = pgm_data; - new_handler->interrupt_table = ops; - - /* - * Check if someone else is registered with same pgmname, userid - * and mask. If someone is already registered with same pgmname, - * userid and mask, registration will fail and NULL will be returned - * to the application. - * If identical handler not found, then handler is added to list. - */ - rc = iucv_add_handler(new_handler); - if (rc) { - printk(KERN_WARNING "%s: Someone already registered with same " - "pgmname, userid, pgmmask\n", __FUNCTION__); - kfree (new_handler); - return NULL; - } - - rc = iucv_declare_buffer(); - if (rc) { - char *err = "Unknown"; - iucv_remove_handler(new_handler); - kfree(new_handler); - switch(rc) { - case 0x03: - err = "Directory error"; - break; - case 0x0a: - err = "Invalid length"; - break; - case 0x13: - err = "Buffer already exists"; - break; - case 0x3e: - err = "Buffer overlap"; - break; - case 0x5c: - err = "Paging or storage error"; - break; - } - printk(KERN_WARNING "%s: iucv_declare_buffer " - "returned error 0x%02lx (%s)\n", __FUNCTION__, rc, err); - return NULL; - } - if (!register_flag) { - /* request the 0x4000 external interrupt */ - rc = register_external_interrupt (0x4000, iucv_irq_handler); - if (rc) { - iucv_remove_handler(new_handler); - kfree (new_handler); - printk(KERN_WARNING "%s: " - "register_external_interrupt returned %ld\n", - __FUNCTION__, rc); - return NULL; - - } - register_flag = 1; - } - iucv_debug(1, "exiting"); - return new_handler; -} /* end of register function */ - -/** - * iucv_unregister_program: - * @handle: address of handler - * - * Unregister application with IUCV. - * Returns: - * 0 on success, -EINVAL, if specified handle is invalid. - */ - -int -iucv_unregister_program (iucv_handle_t handle) -{ - handler *h = NULL; - struct list_head *lh; - int i; - ulong flags; - - iucv_debug(1, "entering"); - iucv_debug(1, "address of handler is %p", h); - - /* Checking if handle is valid */ - spin_lock_irqsave (&iucv_lock, flags); - list_for_each(lh, &iucv_handler_table) { - if ((handler *)handle == list_entry(lh, handler, list)) { - h = (handler *)handle; - break; - } - } - if (!h) { - spin_unlock_irqrestore (&iucv_lock, flags); - if (handle) - printk(KERN_WARNING - "%s: Handler not found in iucv_handler_table.\n", - __FUNCTION__); - else - printk(KERN_WARNING - "%s: NULL handle passed by application.\n", - __FUNCTION__); - return -EINVAL; - } - - /** - * First, walk thru iucv_pathid_table and sever any pathid which is - * still pointing to the handler to be removed. - */ - for (i = 0; i < max_connections; i++) - if (iucv_pathid_table[i] == h) { - spin_unlock_irqrestore (&iucv_lock, flags); - iucv_sever(i, h->id.user_data); - spin_lock_irqsave(&iucv_lock, flags); - } - spin_unlock_irqrestore (&iucv_lock, flags); - - iucv_remove_handler(h); - kfree(h); - - iucv_debug(1, "exiting"); - return 0; -} - -/** - * iucv_accept: - * @pathid: Path identification number - * @msglim_reqstd: The number of outstanding messages requested. - * @user_data: Data specified by the iucv_connect function. - * @flags1: Contains options for this path. - * - IPPRTY (0x20) Specifies if you want to send priority message. - * - IPRMDATA (0x80) Specifies whether your program can handle a message - * in the parameter list. - * - IPQUSCE (0x40) Specifies whether you want to quiesce the path being - * established. - * @handle: Address of handler. - * @pgm_data: Application data passed to interrupt handlers. - * @flags1_out: Pointer to an int. If not NULL, on return the options for - * the path are stored at the given location: - * - IPPRTY (0x20) Indicates you may send a priority message. - * @msglim: Pointer to an __u16. If not NULL, on return the maximum - * number of outstanding messages is stored at the given - * location. - * - * This function is issued after the user receives a Connection Pending external - * interrupt and now wishes to complete the IUCV communication path. - * Returns: - * return code from CP - */ -int -iucv_accept(__u16 pathid, __u16 msglim_reqstd, - __u8 user_data[16], int flags1, - iucv_handle_t handle, void *pgm_data, - int *flags1_out, __u16 * msglim) -{ - ulong b2f0_result = 0; - ulong flags; - struct list_head *lh; - handler *h = NULL; - iparml_control *parm; - - iucv_debug(1, "entering"); - iucv_debug(1, "pathid = %d", pathid); - - /* Checking if handle is valid */ - spin_lock_irqsave (&iucv_lock, flags); - list_for_each(lh, &iucv_handler_table) { - if ((handler *)handle == list_entry(lh, handler, list)) { - h = (handler *)handle; - break; - } - } - spin_unlock_irqrestore (&iucv_lock, flags); - - if (!h) { - if (handle) - printk(KERN_WARNING - "%s: Handler not found in iucv_handler_table.\n", - __FUNCTION__); - else - printk(KERN_WARNING - "%s: NULL handle passed by application.\n", - __FUNCTION__); - return -EINVAL; - } - - parm = (iparml_control *)grab_param(); - - parm->ippathid = pathid; - parm->ipmsglim = msglim_reqstd; - if (user_data) - memcpy(parm->ipuser, user_data, sizeof(parm->ipuser)); - - parm->ipflags1 = (__u8)flags1; - b2f0_result = b2f0(ACCEPT, parm); - - if (!b2f0_result) { - if (msglim) - *msglim = parm->ipmsglim; - if (pgm_data) - h->pgm_data = pgm_data; - if (flags1_out) - *flags1_out = (parm->ipflags1 & IPPRTY) ? IPPRTY : 0; - } - release_param(parm); - - iucv_debug(1, "exiting"); - return b2f0_result; -} - -/** - * iucv_connect: - * @pathid: Path identification number - * @msglim_reqstd: Number of outstanding messages requested - * @user_data: 16-byte user data - * @userid: 8-byte of user identification - * @system_name: 8-byte identifying the system name - * @flags1: Specifies options for this path: - * - IPPRTY (0x20) Specifies if you want to send priority message. - * - IPRMDATA (0x80) Specifies whether your program can handle a message - * in the parameter list. - * - IPQUSCE (0x40) Specifies whether you want to quiesce the path being - * established. - * - IPLOCAL (0x01) Allows an application to force the partner to be on the - * local system. If local is specified then target class - * cannot be specified. - * @flags1_out: Pointer to an int. If not NULL, on return the options for - * the path are stored at the given location: - * - IPPRTY (0x20) Indicates you may send a priority message. - * @msglim: Pointer to an __u16. If not NULL, on return the maximum - * number of outstanding messages is stored at the given - * location. - * @handle: Address of handler. - * @pgm_data: Application data to be passed to interrupt handlers. - * - * This function establishes an IUCV path. Although the connect may complete - * successfully, you are not able to use the path until you receive an IUCV - * Connection Complete external interrupt. - * Returns: return code from CP, or one of the following - * - ENOMEM - * - return code from iucv_declare_buffer - * - EINVAL - invalid handle passed by application - * - EINVAL - pathid address is NULL - * - ENOMEM - pathid table storage allocation failed - * - return code from internal function add_pathid - */ -int -iucv_connect (__u16 *pathid, __u16 msglim_reqstd, - __u8 user_data[16], __u8 userid[8], - __u8 system_name[8], int flags1, - int *flags1_out, __u16 * msglim, - iucv_handle_t handle, void *pgm_data) -{ - iparml_control *parm; - iparml_control local_parm; - struct list_head *lh; - ulong b2f0_result = 0; - ulong flags; - int add_pathid_result = 0; - handler *h = NULL; - __u8 no_memory[16] = "NO MEMORY"; - - iucv_debug(1, "entering"); - - /* Checking if handle is valid */ - spin_lock_irqsave (&iucv_lock, flags); - list_for_each(lh, &iucv_handler_table) { - if ((handler *)handle == list_entry(lh, handler, list)) { - h = (handler *)handle; - break; - } - } - spin_unlock_irqrestore (&iucv_lock, flags); - - if (!h) { - if (handle) - printk(KERN_WARNING - "%s: Handler not found in iucv_handler_table.\n", - __FUNCTION__); - else - printk(KERN_WARNING - "%s: NULL handle passed by application.\n", - __FUNCTION__); - return -EINVAL; - } - - if (pathid == NULL) { - printk(KERN_WARNING "%s: NULL pathid pointer\n", - __FUNCTION__); - return -EINVAL; - } - - parm = (iparml_control *)grab_param(); - - parm->ipmsglim = msglim_reqstd; - - if (user_data) - memcpy(parm->ipuser, user_data, sizeof(parm->ipuser)); - - if (userid) { - memcpy(parm->ipvmid, userid, sizeof(parm->ipvmid)); - ASCEBC(parm->ipvmid, sizeof(parm->ipvmid)); - EBC_TOUPPER(parm->ipvmid, sizeof(parm->ipvmid)); - } - - if (system_name) { - memcpy(parm->iptarget, system_name, sizeof(parm->iptarget)); - ASCEBC(parm->iptarget, sizeof(parm->iptarget)); - EBC_TOUPPER(parm->iptarget, sizeof(parm->iptarget)); - } - - /* In order to establish an IUCV connection, the procedure is: - * - * b2f0(CONNECT) - * take the ippathid from the b2f0 call - * register the handler to the ippathid - * - * Unfortunately, the ConnectionEstablished message gets sent after the - * b2f0(CONNECT) call but before the register is handled. - * - * In order for this race condition to be eliminated, the IUCV Control - * Interrupts must be disabled for the above procedure. - * - * David Kennedy - */ - - /* Enable everything but IUCV Control messages */ - iucv_setmask(~(AllInterrupts)); - messagesDisabled = 1; - - spin_lock_irqsave (&iucv_lock, flags); - parm->ipflags1 = (__u8)flags1; - b2f0_result = b2f0(CONNECT, parm); - memcpy(&local_parm, parm, sizeof(local_parm)); - release_param(parm); - parm = &local_parm; - if (!b2f0_result) - add_pathid_result = __iucv_add_pathid(parm->ippathid, h); - spin_unlock_irqrestore (&iucv_lock, flags); - - if (b2f0_result) { - iucv_setmask(~0); - messagesDisabled = 0; - return b2f0_result; - } - - *pathid = parm->ippathid; - - /* Enable everything again */ - iucv_setmask(IUCVControlInterruptsFlag); - - if (msglim) - *msglim = parm->ipmsglim; - if (flags1_out) - *flags1_out = (parm->ipflags1 & IPPRTY) ? IPPRTY : 0; - - if (add_pathid_result) { - iucv_sever(*pathid, no_memory); - printk(KERN_WARNING "%s: add_pathid failed with rc =" - " %d\n", __FUNCTION__, add_pathid_result); - return(add_pathid_result); - } - - iucv_debug(1, "exiting"); - return b2f0_result; -} - -/** - * iucv_purge: - * @pathid: Path identification number - * @msgid: Message ID of message to purge. - * @srccls: Message class of the message to purge. - * @audit: Pointer to an __u32. If not NULL, on return, information about - * asynchronous errors that may have affected the normal completion - * of this message ist stored at the given location. - * - * Cancels a message you have sent. - * Returns: return code from CP - */ -int -iucv_purge (__u16 pathid, __u32 msgid, __u32 srccls, __u32 *audit) -{ - iparml_purge *parm; - ulong b2f0_result = 0; - - iucv_debug(1, "entering"); - iucv_debug(1, "pathid = %d", pathid); - - parm = (iparml_purge *)grab_param(); - - parm->ipmsgid = msgid; - parm->ippathid = pathid; - parm->ipsrccls = srccls; - parm->ipflags1 |= (IPSRCCLS | IPFGMID | IPFGPID); - b2f0_result = b2f0(PURGE, parm); - - if (!b2f0_result && audit) { - memcpy(audit, parm->ipaudit, sizeof(parm->ipaudit)); - /* parm->ipaudit has only 3 bytes */ - *audit >>= 8; - } - - release_param(parm); - - iucv_debug(1, "b2f0_result = %ld", b2f0_result); - iucv_debug(1, "exiting"); - return b2f0_result; -} - -/** - * iucv_query_generic: - * @want_maxconn: Flag, describing which value is to be returned. - * - * Helper function for iucv_query_maxconn() and iucv_query_bufsize(). - * - * Returns: The buffersize, if want_maxconn is 0; the maximum number of - * connections, if want_maxconn is 1 or an error-code < 0 on failure. - */ -static int -iucv_query_generic(int want_maxconn) -{ - register unsigned long reg0 asm ("0"); - register unsigned long reg1 asm ("1"); - iparml_purge *parm = (iparml_purge *)grab_param(); - int bufsize, maxconn; - int ccode; - - /** - * Call b2f0 and store R0 (max buffer size), - * R1 (max connections) and CC. - */ - reg0 = QUERY; - reg1 = virt_to_phys(parm); - asm volatile( - " .long 0xb2f01000\n" - " ipm %0\n" - " srl %0,28\n" - : "=d" (ccode), "+d" (reg0), "+d" (reg1) : : "cc"); - bufsize = reg0; - maxconn = reg1; - release_param(parm); - - if (ccode) - return -EPERM; - if (want_maxconn) - return maxconn; - return bufsize; -} - -/** - * iucv_query_maxconn: - * - * Determines the maximum number of connections thay may be established. - * - * Returns: Maximum number of connections that can be. - */ -ulong -iucv_query_maxconn(void) -{ - return iucv_query_generic(1); -} - -/** - * iucv_query_bufsize: - * - * Determines the size of the external interrupt buffer. - * - * Returns: Size of external interrupt buffer. - */ -ulong -iucv_query_bufsize (void) -{ - return iucv_query_generic(0); -} - -/** - * iucv_quiesce: - * @pathid: Path identification number - * @user_data: 16-byte user data - * - * Temporarily suspends incoming messages on an IUCV path. - * You can later reactivate the path by invoking the iucv_resume function. - * Returns: return code from CP - */ -int -iucv_quiesce (__u16 pathid, __u8 user_data[16]) -{ - iparml_control *parm; - ulong b2f0_result = 0; - - iucv_debug(1, "entering"); - iucv_debug(1, "pathid = %d", pathid); - - parm = (iparml_control *)grab_param(); - - memcpy(parm->ipuser, user_data, sizeof(parm->ipuser)); - parm->ippathid = pathid; - - b2f0_result = b2f0(QUIESCE, parm); - release_param(parm); - - iucv_debug(1, "b2f0_result = %ld", b2f0_result); - iucv_debug(1, "exiting"); - - return b2f0_result; -} - -/** - * iucv_receive: - * @pathid: Path identification number. - * @buffer: Address of buffer to receive. Must be below 2G. - * @buflen: Length of buffer to receive. - * @msgid: Specifies the message ID. - * @trgcls: Specifies target class. - * @flags1_out: Receives options for path on return. - * - IPNORPY (0x10) Specifies whether a reply is required - * - IPPRTY (0x20) Specifies if you want to send priority message - * - IPRMDATA (0x80) Specifies the data is contained in the parameter list - * @residual_buffer: Receives the address of buffer updated by the number - * of bytes you have received on return. - * @residual_length: On return, receives one of the following values: - * - 0 If the receive buffer is the same length as - * the message. - * - Remaining bytes in buffer If the receive buffer is longer than the - * message. - * - Remaining bytes in message If the receive buffer is shorter than the - * message. - * - * This function receives messages that are being sent to you over established - * paths. - * Returns: return code from CP IUCV call; If the receive buffer is shorter - * than the message, always 5 - * -EINVAL - buffer address is pointing to NULL - */ -int -iucv_receive (__u16 pathid, __u32 msgid, __u32 trgcls, - void *buffer, ulong buflen, - int *flags1_out, ulong * residual_buffer, ulong * residual_length) -{ - iparml_db *parm; - ulong b2f0_result; - int moved = 0; /* number of bytes moved from parmlist to buffer */ - - iucv_debug(2, "entering"); - - if (!buffer) - return -EINVAL; - - parm = (iparml_db *)grab_param(); - - parm->ipbfadr1 = (__u32) (addr_t) buffer; - parm->ipbfln1f = (__u32) ((ulong) buflen); - parm->ipmsgid = msgid; - parm->ippathid = pathid; - parm->iptrgcls = trgcls; - parm->ipflags1 = (IPFGPID | IPFGMID | IPFGMCL); - - b2f0_result = b2f0(RECEIVE, parm); - - if (!b2f0_result || b2f0_result == 5) { - if (flags1_out) { - iucv_debug(2, "*flags1_out = %d", *flags1_out); - *flags1_out = (parm->ipflags1 & (~0x07)); - iucv_debug(2, "*flags1_out = %d", *flags1_out); - } - - if (!(parm->ipflags1 & IPRMDATA)) { /*msg not in parmlist */ - if (residual_length) - *residual_length = parm->ipbfln1f; - - if (residual_buffer) - *residual_buffer = parm->ipbfadr1; - } else { - moved = min_t (unsigned long, buflen, 8); - - memcpy ((char *) buffer, - (char *) &parm->ipbfadr1, moved); - - if (buflen < 8) - b2f0_result = 5; - - if (residual_length) - *residual_length = abs (buflen - 8); - - if (residual_buffer) - *residual_buffer = (ulong) (buffer + moved); - } - } - release_param(parm); - - iucv_debug(2, "exiting"); - return b2f0_result; -} - -/* - * Name: iucv_receive_array - * Purpose: This function receives messages that are being sent to you - * over established paths. - * Input: pathid - path identification number - * buffer - address of array of buffers - * buflen - total length of buffers - * msgid - specifies the message ID. - * trgcls - specifies target class - * Output: - * flags1_out: Options for path. - * IPNORPY - 0x10 specifies whether a reply is required - * IPPRTY - 0x20 specifies if you want to send priority message - * IPRMDATA - 0x80 specifies the data is contained in the parameter list - * residual_buffer - address points to the current list entry IUCV - * is working on. - * residual_length - - * Contains one of the following values, if the receive buffer is: - * The same length as the message, this field is zero. - * Longer than the message, this field contains the number of - * bytes remaining in the buffer. - * Shorter than the message, this field contains the residual - * count (that is, the number of bytes remaining in the - * message that does not fit into the buffer. In this case - * b2f0_result = 5. - * Return: b2f0_result - return code from CP - * (-EINVAL) - buffer address is NULL - */ -int -iucv_receive_array (__u16 pathid, - __u32 msgid, __u32 trgcls, - iucv_array_t * buffer, ulong buflen, - int *flags1_out, - ulong * residual_buffer, ulong * residual_length) -{ - iparml_db *parm; - ulong b2f0_result; - int i = 0, moved = 0, need_to_move = 8, dyn_len; - - iucv_debug(2, "entering"); - - if (!buffer) - return -EINVAL; - - parm = (iparml_db *)grab_param(); - - parm->ipbfadr1 = (__u32) ((ulong) buffer); - parm->ipbfln1f = (__u32) buflen; - parm->ipmsgid = msgid; - parm->ippathid = pathid; - parm->iptrgcls = trgcls; - parm->ipflags1 = (IPBUFLST | IPFGPID | IPFGMID | IPFGMCL); - - b2f0_result = b2f0(RECEIVE, parm); - - if (!b2f0_result || b2f0_result == 5) { - - if (flags1_out) { - iucv_debug(2, "*flags1_out = %d", *flags1_out); - *flags1_out = (parm->ipflags1 & (~0x07)); - iucv_debug(2, "*flags1_out = %d", *flags1_out); - } - - if (!(parm->ipflags1 & IPRMDATA)) { /*msg not in parmlist */ - - if (residual_length) - *residual_length = parm->ipbfln1f; - - if (residual_buffer) - *residual_buffer = parm->ipbfadr1; - - } else { - /* copy msg from parmlist to users array. */ - - while ((moved < 8) && (moved < buflen)) { - dyn_len = - min_t (unsigned int, - (buffer + i)->length, need_to_move); - - memcpy ((char *)((ulong)((buffer + i)->address)), - ((char *) &parm->ipbfadr1) + moved, - dyn_len); - - moved += dyn_len; - need_to_move -= dyn_len; - - (buffer + i)->address = - (__u32) - ((ulong)(__u8 *) ((ulong)(buffer + i)->address) - + dyn_len); - - (buffer + i)->length -= dyn_len; - i++; - } - - if (need_to_move) /* buflen < 8 bytes */ - b2f0_result = 5; - - if (residual_length) - *residual_length = abs (buflen - 8); - - if (residual_buffer) { - if (!moved) - *residual_buffer = (ulong) buffer; - else - *residual_buffer = - (ulong) (buffer + (i - 1)); - } - - } - } - release_param(parm); - - iucv_debug(2, "exiting"); - return b2f0_result; -} - -/** - * iucv_reject: - * @pathid: Path identification number. - * @msgid: Message ID of the message to reject. - * @trgcls: Target class of the message to reject. - * Returns: return code from CP - * - * Refuses a specified message. Between the time you are notified of a - * message and the time that you complete the message, the message may - * be rejected. - */ -int -iucv_reject (__u16 pathid, __u32 msgid, __u32 trgcls) -{ - iparml_db *parm; - ulong b2f0_result = 0; - - iucv_debug(1, "entering"); - iucv_debug(1, "pathid = %d", pathid); - - parm = (iparml_db *)grab_param(); - - parm->ippathid = pathid; - parm->ipmsgid = msgid; - parm->iptrgcls = trgcls; - parm->ipflags1 = (IPFGMCL | IPFGMID | IPFGPID); - - b2f0_result = b2f0(REJECT, parm); - release_param(parm); - - iucv_debug(1, "b2f0_result = %ld", b2f0_result); - iucv_debug(1, "exiting"); - - return b2f0_result; -} - -/* - * Name: iucv_reply - * Purpose: This function responds to the two-way messages that you - * receive. You must identify completely the message to - * which you wish to reply. ie, pathid, msgid, and trgcls. - * Input: pathid - path identification number - * msgid - specifies the message ID. - * trgcls - specifies target class - * flags1 - option for path - * IPPRTY- 0x20 - specifies if you want to send priority message - * buffer - address of reply buffer - * buflen - length of reply buffer - * Output: ipbfadr2 - Address of buffer updated by the number - * of bytes you have moved. - * ipbfln2f - Contains one of the following values: - * If the answer buffer is the same length as the reply, this field - * contains zero. - * If the answer buffer is longer than the reply, this field contains - * the number of bytes remaining in the buffer. - * If the answer buffer is shorter than the reply, this field contains - * a residual count (that is, the number of bytes remianing in the - * reply that does not fit into the buffer. In this - * case b2f0_result = 5. - * Return: b2f0_result - return code from CP - * (-EINVAL) - buffer address is NULL - */ -int -iucv_reply (__u16 pathid, - __u32 msgid, __u32 trgcls, - int flags1, - void *buffer, ulong buflen, ulong * ipbfadr2, ulong * ipbfln2f) -{ - iparml_db *parm; - ulong b2f0_result; - - iucv_debug(2, "entering"); - - if (!buffer) - return -EINVAL; - - parm = (iparml_db *)grab_param(); - - parm->ipbfadr2 = (__u32) ((ulong) buffer); - parm->ipbfln2f = (__u32) buflen; /* length of message */ - parm->ippathid = pathid; - parm->ipmsgid = msgid; - parm->iptrgcls = trgcls; - parm->ipflags1 = (__u8) flags1; /* priority message */ - - b2f0_result = b2f0(REPLY, parm); - - if ((!b2f0_result) || (b2f0_result == 5)) { - if (ipbfadr2) - *ipbfadr2 = parm->ipbfadr2; - if (ipbfln2f) - *ipbfln2f = parm->ipbfln2f; - } - release_param(parm); - - iucv_debug(2, "exiting"); - - return b2f0_result; -} - -/* - * Name: iucv_reply_array - * Purpose: This function responds to the two-way messages that you - * receive. You must identify completely the message to - * which you wish to reply. ie, pathid, msgid, and trgcls. - * The array identifies a list of addresses and lengths of - * discontiguous buffers that contains the reply data. - * Input: pathid - path identification number - * msgid - specifies the message ID. - * trgcls - specifies target class - * flags1 - option for path - * IPPRTY- specifies if you want to send priority message - * buffer - address of array of reply buffers - * buflen - total length of reply buffers - * Output: ipbfadr2 - Address of buffer which IUCV is currently working on. - * ipbfln2f - Contains one of the following values: - * If the answer buffer is the same length as the reply, this field - * contains zero. - * If the answer buffer is longer than the reply, this field contains - * the number of bytes remaining in the buffer. - * If the answer buffer is shorter than the reply, this field contains - * a residual count (that is, the number of bytes remianing in the - * reply that does not fit into the buffer. In this - * case b2f0_result = 5. - * Return: b2f0_result - return code from CP - * (-EINVAL) - buffer address is NULL -*/ -int -iucv_reply_array (__u16 pathid, - __u32 msgid, __u32 trgcls, - int flags1, - iucv_array_t * buffer, - ulong buflen, ulong * ipbfadr2, ulong * ipbfln2f) -{ - iparml_db *parm; - ulong b2f0_result; - - iucv_debug(2, "entering"); - - if (!buffer) - return -EINVAL; - - parm = (iparml_db *)grab_param(); - - parm->ipbfadr2 = (__u32) ((ulong) buffer); - parm->ipbfln2f = buflen; /* length of message */ - parm->ippathid = pathid; - parm->ipmsgid = msgid; - parm->iptrgcls = trgcls; - parm->ipflags1 = (IPANSLST | flags1); - - b2f0_result = b2f0(REPLY, parm); - - if ((!b2f0_result) || (b2f0_result == 5)) { - - if (ipbfadr2) - *ipbfadr2 = parm->ipbfadr2; - if (ipbfln2f) - *ipbfln2f = parm->ipbfln2f; - } - release_param(parm); - - iucv_debug(2, "exiting"); - - return b2f0_result; -} - -/* - * Name: iucv_reply_prmmsg - * Purpose: This function responds to the two-way messages that you - * receive. You must identify completely the message to - * which you wish to reply. ie, pathid, msgid, and trgcls. - * Prmmsg signifies the data is moved into the - * parameter list. - * Input: pathid - path identification number - * msgid - specifies the message ID. - * trgcls - specifies target class - * flags1 - option for path - * IPPRTY- specifies if you want to send priority message - * prmmsg - 8-bytes of data to be placed into the parameter - * list. - * Output: NA - * Return: b2f0_result - return code from CP -*/ -int -iucv_reply_prmmsg (__u16 pathid, - __u32 msgid, __u32 trgcls, int flags1, __u8 prmmsg[8]) -{ - iparml_dpl *parm; - ulong b2f0_result; - - iucv_debug(2, "entering"); - - parm = (iparml_dpl *)grab_param(); - - parm->ippathid = pathid; - parm->ipmsgid = msgid; - parm->iptrgcls = trgcls; - memcpy(parm->iprmmsg, prmmsg, sizeof (parm->iprmmsg)); - parm->ipflags1 = (IPRMDATA | flags1); - - b2f0_result = b2f0(REPLY, parm); - release_param(parm); - - iucv_debug(2, "exiting"); - - return b2f0_result; -} - -/** - * iucv_resume: - * @pathid: Path identification number - * @user_data: 16-byte of user data - * - * This function restores communication over a quiesced path. - * Returns: return code from CP - */ -int -iucv_resume (__u16 pathid, __u8 user_data[16]) -{ - iparml_control *parm; - ulong b2f0_result = 0; - - iucv_debug(1, "entering"); - iucv_debug(1, "pathid = %d", pathid); - - parm = (iparml_control *)grab_param(); - - memcpy (parm->ipuser, user_data, sizeof (*user_data)); - parm->ippathid = pathid; - - b2f0_result = b2f0(RESUME, parm); - release_param(parm); - - iucv_debug(1, "exiting"); - - return b2f0_result; -} - -/* - * Name: iucv_send - * Purpose: sends messages - * Input: pathid - ushort, pathid - * msgid - ulong *, id of message returned to caller - * trgcls - ulong, target message class - * srccls - ulong, source message class - * msgtag - ulong, message tag - * flags1 - Contains options for this path. - * IPPRTY - Ox20 - specifies if you want to send a priority message. - * buffer - pointer to buffer - * buflen - ulong, length of buffer - * Output: b2f0_result - return code from b2f0 call - * msgid - returns message id - */ -int -iucv_send (__u16 pathid, __u32 * msgid, - __u32 trgcls, __u32 srccls, - __u32 msgtag, int flags1, void *buffer, ulong buflen) -{ - iparml_db *parm; - ulong b2f0_result; - - iucv_debug(2, "entering"); - - if (!buffer) - return -EINVAL; - - parm = (iparml_db *)grab_param(); - - parm->ipbfadr1 = (__u32) ((ulong) buffer); - parm->ippathid = pathid; - parm->iptrgcls = trgcls; - parm->ipbfln1f = (__u32) buflen; /* length of message */ - parm->ipsrccls = srccls; - parm->ipmsgtag = msgtag; - parm->ipflags1 = (IPNORPY | flags1); /* one way priority message */ - - b2f0_result = b2f0(SEND, parm); - - if ((!b2f0_result) && (msgid)) - *msgid = parm->ipmsgid; - release_param(parm); - - iucv_debug(2, "exiting"); - - return b2f0_result; -} - -/* - * Name: iucv_send_array - * Purpose: This function transmits data to another application. - * The contents of buffer is the address of the array of - * addresses and lengths of discontiguous buffers that hold - * the message text. This is a one-way message and the - * receiver will not reply to the message. - * Input: pathid - path identification number - * trgcls - specifies target class - * srccls - specifies the source message class - * msgtag - specifies a tag to be associated witht the message - * flags1 - option for path - * IPPRTY- specifies if you want to send priority message - * buffer - address of array of send buffers - * buflen - total length of send buffers - * Output: msgid - specifies the message ID. - * Return: b2f0_result - return code from CP - * (-EINVAL) - buffer address is NULL - */ -int -iucv_send_array (__u16 pathid, - __u32 * msgid, - __u32 trgcls, - __u32 srccls, - __u32 msgtag, int flags1, iucv_array_t * buffer, ulong buflen) -{ - iparml_db *parm; - ulong b2f0_result; - - iucv_debug(2, "entering"); - - if (!buffer) - return -EINVAL; - - parm = (iparml_db *)grab_param(); - - parm->ippathid = pathid; - parm->iptrgcls = trgcls; - parm->ipbfadr1 = (__u32) ((ulong) buffer); - parm->ipbfln1f = (__u32) buflen; /* length of message */ - parm->ipsrccls = srccls; - parm->ipmsgtag = msgtag; - parm->ipflags1 = (IPNORPY | IPBUFLST | flags1); - b2f0_result = b2f0(SEND, parm); - - if ((!b2f0_result) && (msgid)) - *msgid = parm->ipmsgid; - release_param(parm); - - iucv_debug(2, "exiting"); - return b2f0_result; -} - -/* - * Name: iucv_send_prmmsg - * Purpose: This function transmits data to another application. - * Prmmsg specifies that the 8-bytes of data are to be moved - * into the parameter list. This is a one-way message and the - * receiver will not reply to the message. - * Input: pathid - path identification number - * trgcls - specifies target class - * srccls - specifies the source message class - * msgtag - specifies a tag to be associated with the message - * flags1 - option for path - * IPPRTY- specifies if you want to send priority message - * prmmsg - 8-bytes of data to be placed into parameter list - * Output: msgid - specifies the message ID. - * Return: b2f0_result - return code from CP -*/ -int -iucv_send_prmmsg (__u16 pathid, - __u32 * msgid, - __u32 trgcls, - __u32 srccls, __u32 msgtag, int flags1, __u8 prmmsg[8]) -{ - iparml_dpl *parm; - ulong b2f0_result; - - iucv_debug(2, "entering"); - - parm = (iparml_dpl *)grab_param(); - - parm->ippathid = pathid; - parm->iptrgcls = trgcls; - parm->ipsrccls = srccls; - parm->ipmsgtag = msgtag; - parm->ipflags1 = (IPRMDATA | IPNORPY | flags1); - memcpy(parm->iprmmsg, prmmsg, sizeof(parm->iprmmsg)); - - b2f0_result = b2f0(SEND, parm); - - if ((!b2f0_result) && (msgid)) - *msgid = parm->ipmsgid; - release_param(parm); - - iucv_debug(2, "exiting"); - - return b2f0_result; -} - -/* - * Name: iucv_send2way - * Purpose: This function transmits data to another application. - * Data to be transmitted is in a buffer. The receiver - * of the send is expected to reply to the message and - * a buffer is provided into which IUCV moves the reply - * to this message. - * Input: pathid - path identification number - * trgcls - specifies target class - * srccls - specifies the source message class - * msgtag - specifies a tag associated with the message - * flags1 - option for path - * IPPRTY- specifies if you want to send priority message - * buffer - address of send buffer - * buflen - length of send buffer - * ansbuf - address of buffer to reply with - * anslen - length of buffer to reply with - * Output: msgid - specifies the message ID. - * Return: b2f0_result - return code from CP - * (-EINVAL) - buffer or ansbuf address is NULL - */ -int -iucv_send2way (__u16 pathid, - __u32 * msgid, - __u32 trgcls, - __u32 srccls, - __u32 msgtag, - int flags1, - void *buffer, ulong buflen, void *ansbuf, ulong anslen) -{ - iparml_db *parm; - ulong b2f0_result; - - iucv_debug(2, "entering"); - - if (!buffer || !ansbuf) - return -EINVAL; - - parm = (iparml_db *)grab_param(); - - parm->ippathid = pathid; - parm->iptrgcls = trgcls; - parm->ipbfadr1 = (__u32) ((ulong) buffer); - parm->ipbfln1f = (__u32) buflen; /* length of message */ - parm->ipbfadr2 = (__u32) ((ulong) ansbuf); - parm->ipbfln2f = (__u32) anslen; - parm->ipsrccls = srccls; - parm->ipmsgtag = msgtag; - parm->ipflags1 = flags1; /* priority message */ - - b2f0_result = b2f0(SEND, parm); - - if ((!b2f0_result) && (msgid)) - *msgid = parm->ipmsgid; - release_param(parm); - - iucv_debug(2, "exiting"); - - return b2f0_result; -} - -/* - * Name: iucv_send2way_array - * Purpose: This function transmits data to another application. - * The contents of buffer is the address of the array of - * addresses and lengths of discontiguous buffers that hold - * the message text. The receiver of the send is expected to - * reply to the message and a buffer is provided into which - * IUCV moves the reply to this message. - * Input: pathid - path identification number - * trgcls - specifies target class - * srccls - specifies the source message class - * msgtag - spcifies a tag to be associated with the message - * flags1 - option for path - * IPPRTY- specifies if you want to send priority message - * buffer - address of array of send buffers - * buflen - total length of send buffers - * ansbuf - address of buffer to reply with - * anslen - length of buffer to reply with - * Output: msgid - specifies the message ID. - * Return: b2f0_result - return code from CP - * (-EINVAL) - buffer address is NULL - */ -int -iucv_send2way_array (__u16 pathid, - __u32 * msgid, - __u32 trgcls, - __u32 srccls, - __u32 msgtag, - int flags1, - iucv_array_t * buffer, - ulong buflen, iucv_array_t * ansbuf, ulong anslen) -{ - iparml_db *parm; - ulong b2f0_result; - - iucv_debug(2, "entering"); - - if (!buffer || !ansbuf) - return -EINVAL; - - parm = (iparml_db *)grab_param(); - - parm->ippathid = pathid; - parm->iptrgcls = trgcls; - parm->ipbfadr1 = (__u32) ((ulong) buffer); - parm->ipbfln1f = (__u32) buflen; /* length of message */ - parm->ipbfadr2 = (__u32) ((ulong) ansbuf); - parm->ipbfln2f = (__u32) anslen; - parm->ipsrccls = srccls; - parm->ipmsgtag = msgtag; - parm->ipflags1 = (IPBUFLST | IPANSLST | flags1); - b2f0_result = b2f0(SEND, parm); - if ((!b2f0_result) && (msgid)) - *msgid = parm->ipmsgid; - release_param(parm); - - iucv_debug(2, "exiting"); - return b2f0_result; -} - -/* - * Name: iucv_send2way_prmmsg - * Purpose: This function transmits data to another application. - * Prmmsg specifies that the 8-bytes of data are to be moved - * into the parameter list. This is a two-way message and the - * receiver of the message is expected to reply. A buffer - * is provided into which IUCV moves the reply to this - * message. - * Input: pathid - path identification number - * trgcls - specifies target class - * srccls - specifies the source message class - * msgtag - specifies a tag to be associated with the message - * flags1 - option for path - * IPPRTY- specifies if you want to send priority message - * prmmsg - 8-bytes of data to be placed in parameter list - * ansbuf - address of buffer to reply with - * anslen - length of buffer to reply with - * Output: msgid - specifies the message ID. - * Return: b2f0_result - return code from CP - * (-EINVAL) - buffer address is NULL -*/ -int -iucv_send2way_prmmsg (__u16 pathid, - __u32 * msgid, - __u32 trgcls, - __u32 srccls, - __u32 msgtag, - ulong flags1, __u8 prmmsg[8], void *ansbuf, ulong anslen) -{ - iparml_dpl *parm; - ulong b2f0_result; - - iucv_debug(2, "entering"); - - if (!ansbuf) - return -EINVAL; - - parm = (iparml_dpl *)grab_param(); - - parm->ippathid = pathid; - parm->iptrgcls = trgcls; - parm->ipsrccls = srccls; - parm->ipmsgtag = msgtag; - parm->ipbfadr2 = (__u32) ((ulong) ansbuf); - parm->ipbfln2f = (__u32) anslen; - parm->ipflags1 = (IPRMDATA | flags1); /* message in prmlist */ - memcpy(parm->iprmmsg, prmmsg, sizeof(parm->iprmmsg)); - - b2f0_result = b2f0(SEND, parm); - - if ((!b2f0_result) && (msgid)) - *msgid = parm->ipmsgid; - release_param(parm); - - iucv_debug(2, "exiting"); - - return b2f0_result; -} - -/* - * Name: iucv_send2way_prmmsg_array - * Purpose: This function transmits data to another application. - * Prmmsg specifies that the 8-bytes of data are to be moved - * into the parameter list. This is a two-way message and the - * receiver of the message is expected to reply. A buffer - * is provided into which IUCV moves the reply to this - * message. The contents of ansbuf is the address of the - * array of addresses and lengths of discontiguous buffers - * that contain the reply. - * Input: pathid - path identification number - * trgcls - specifies target class - * srccls - specifies the source message class - * msgtag - specifies a tag to be associated with the message - * flags1 - option for path - * IPPRTY- specifies if you want to send priority message - * prmmsg - 8-bytes of data to be placed into the parameter list - * ansbuf - address of buffer to reply with - * anslen - length of buffer to reply with - * Output: msgid - specifies the message ID. - * Return: b2f0_result - return code from CP - * (-EINVAL) - ansbuf address is NULL - */ -int -iucv_send2way_prmmsg_array (__u16 pathid, - __u32 * msgid, - __u32 trgcls, - __u32 srccls, - __u32 msgtag, - int flags1, - __u8 prmmsg[8], - iucv_array_t * ansbuf, ulong anslen) -{ - iparml_dpl *parm; - ulong b2f0_result; - - iucv_debug(2, "entering"); - - if (!ansbuf) - return -EINVAL; - - parm = (iparml_dpl *)grab_param(); - - parm->ippathid = pathid; - parm->iptrgcls = trgcls; - parm->ipsrccls = srccls; - parm->ipmsgtag = msgtag; - parm->ipbfadr2 = (__u32) ((ulong) ansbuf); - parm->ipbfln2f = (__u32) anslen; - parm->ipflags1 = (IPRMDATA | IPANSLST | flags1); - memcpy(parm->iprmmsg, prmmsg, sizeof(parm->iprmmsg)); - b2f0_result = b2f0(SEND, parm); - if ((!b2f0_result) && (msgid)) - *msgid = parm->ipmsgid; - release_param(parm); - - iucv_debug(2, "exiting"); - return b2f0_result; -} - -void -iucv_setmask_cpuid (void *result) -{ - iparml_set_mask *parm; - - iucv_debug(1, "entering"); - parm = (iparml_set_mask *)grab_param(); - parm->ipmask = *((__u8*)result); - *((ulong *)result) = b2f0(SETMASK, parm); - release_param(parm); - - iucv_debug(1, "b2f0_result = %ld", *((ulong *)result)); - iucv_debug(1, "exiting"); -} - -/* - * Name: iucv_setmask - * Purpose: This function enables or disables the following IUCV - * external interruptions: Nonpriority and priority message - * interrupts, nonpriority and priority reply interrupts. - * Input: SetMaskFlag - options for interrupts - * 0x80 - Nonpriority_MessagePendingInterruptsFlag - * 0x40 - Priority_MessagePendingInterruptsFlag - * 0x20 - Nonpriority_MessageCompletionInterruptsFlag - * 0x10 - Priority_MessageCompletionInterruptsFlag - * 0x08 - IUCVControlInterruptsFlag - * Output: NA - * Return: b2f0_result - return code from CP -*/ -int -iucv_setmask (int SetMaskFlag) -{ - union { - ulong result; - __u8 param; - } u; - int cpu; - - u.param = SetMaskFlag; - cpu = get_cpu(); - smp_call_function_on(iucv_setmask_cpuid, &u, 0, 1, iucv_cpuid); - put_cpu(); - - return u.result; -} - -/** - * iucv_sever: - * @pathid: Path identification number - * @user_data: 16-byte of user data - * - * This function terminates an iucv path. - * Returns: return code from CP - */ -int -iucv_sever(__u16 pathid, __u8 user_data[16]) -{ - iparml_control *parm; - ulong b2f0_result = 0; - - iucv_debug(1, "entering"); - parm = (iparml_control *)grab_param(); - - memcpy(parm->ipuser, user_data, sizeof(parm->ipuser)); - parm->ippathid = pathid; - - b2f0_result = b2f0(SEVER, parm); - - if (!b2f0_result) - iucv_remove_pathid(pathid); - release_param(parm); - - iucv_debug(1, "exiting"); - return b2f0_result; -} - -/* - * Interrupt Handlers - *******************************************************************************/ - -/** - * iucv_irq_handler: - * @regs: Current registers - * @code: irq code - * - * Handles external interrupts coming in from CP. - * Places the interrupt buffer on a queue and schedules iucv_tasklet_handler(). - */ -static void -iucv_irq_handler(__u16 code) -{ - iucv_irqdata *irqdata; - - irqdata = kmalloc(sizeof(iucv_irqdata), GFP_ATOMIC); - if (!irqdata) { - printk(KERN_WARNING "%s: out of memory\n", __FUNCTION__); - return; - } - - memcpy(&irqdata->data, iucv_external_int_buffer, - sizeof(iucv_GeneralInterrupt)); - - spin_lock(&iucv_irq_queue_lock); - list_add_tail(&irqdata->queue, &iucv_irq_queue); - spin_unlock(&iucv_irq_queue_lock); - - tasklet_schedule(&iucv_tasklet); -} - -/** - * iucv_do_int: - * @int_buf: Pointer to copy of external interrupt buffer - * - * The workhorse for handling interrupts queued by iucv_irq_handler(). - * This function is called from the bottom half iucv_tasklet_handler(). - */ -static void -iucv_do_int(iucv_GeneralInterrupt * int_buf) -{ - handler *h = NULL; - struct list_head *lh; - ulong flags; - iucv_interrupt_ops_t *interrupt = NULL; /* interrupt addresses */ - __u8 temp_buff1[24], temp_buff2[24]; /* masked handler id. */ - int rc = 0, j = 0; - __u8 no_listener[16] = "NO LISTENER"; - - iucv_debug(2, "entering, pathid %d, type %02X", - int_buf->ippathid, int_buf->iptype); - iucv_dumpit("External Interrupt Buffer:", - int_buf, sizeof(iucv_GeneralInterrupt)); - - ASCEBC (no_listener, 16); - - if (int_buf->iptype != 01) { - if ((int_buf->ippathid) > (max_connections - 1)) { - printk(KERN_WARNING "%s: Got interrupt with pathid %d" - " > max_connections (%ld)\n", __FUNCTION__, - int_buf->ippathid, max_connections - 1); - } else { - h = iucv_pathid_table[int_buf->ippathid]; - interrupt = h->interrupt_table; - iucv_dumpit("Handler:", h, sizeof(handler)); - } - } - - /* end of if statement */ - switch (int_buf->iptype) { - case 0x01: /* connection pending */ - if (messagesDisabled) { - iucv_setmask(~0); - messagesDisabled = 0; - } - spin_lock_irqsave(&iucv_lock, flags); - list_for_each(lh, &iucv_handler_table) { - h = list_entry(lh, handler, list); - memcpy(temp_buff1, &(int_buf->ipvmid), 24); - memcpy(temp_buff2, &(h->id.userid), 24); - for (j = 0; j < 24; j++) { - temp_buff1[j] &= (h->id.mask)[j]; - temp_buff2[j] &= (h->id.mask)[j]; - } - - iucv_dumpit("temp_buff1:", - temp_buff1, sizeof(temp_buff1)); - iucv_dumpit("temp_buff2", - temp_buff2, sizeof(temp_buff2)); - - if (!memcmp (temp_buff1, temp_buff2, 24)) { - - iucv_debug(2, - "found a matching handler"); - break; - } else - h = NULL; - } - spin_unlock_irqrestore (&iucv_lock, flags); - if (h) { - /* ADD PATH TO PATHID TABLE */ - rc = iucv_add_pathid(int_buf->ippathid, h); - if (rc) { - iucv_sever (int_buf->ippathid, - no_listener); - iucv_debug(1, - "add_pathid failed, rc = %d", - rc); - } else { - interrupt = h->interrupt_table; - if (interrupt->ConnectionPending) { - EBCASC (int_buf->ipvmid, 8); - interrupt->ConnectionPending( - (iucv_ConnectionPending *)int_buf, - h->pgm_data); - } else - iucv_sever(int_buf->ippathid, - no_listener); - } - } else - iucv_sever(int_buf->ippathid, no_listener); - break; - - case 0x02: /*connection complete */ - if (messagesDisabled) { - iucv_setmask(~0); - messagesDisabled = 0; - } - if (h) { - if (interrupt->ConnectionComplete) - { - interrupt->ConnectionComplete( - (iucv_ConnectionComplete *)int_buf, - h->pgm_data); - } - else - iucv_debug(1, - "ConnectionComplete not called"); - } else - iucv_sever(int_buf->ippathid, no_listener); - break; - - case 0x03: /* connection severed */ - if (messagesDisabled) { - iucv_setmask(~0); - messagesDisabled = 0; - } - if (h) { - if (interrupt->ConnectionSevered) - interrupt->ConnectionSevered( - (iucv_ConnectionSevered *)int_buf, - h->pgm_data); - - else - iucv_sever (int_buf->ippathid, no_listener); - } else - iucv_sever(int_buf->ippathid, no_listener); - break; - - case 0x04: /* connection quiesced */ - if (messagesDisabled) { - iucv_setmask(~0); - messagesDisabled = 0; - } - if (h) { - if (interrupt->ConnectionQuiesced) - interrupt->ConnectionQuiesced( - (iucv_ConnectionQuiesced *)int_buf, - h->pgm_data); - else - iucv_debug(1, - "ConnectionQuiesced not called"); - } - break; - - case 0x05: /* connection resumed */ - if (messagesDisabled) { - iucv_setmask(~0); - messagesDisabled = 0; - } - if (h) { - if (interrupt->ConnectionResumed) - interrupt->ConnectionResumed( - (iucv_ConnectionResumed *)int_buf, - h->pgm_data); - else - iucv_debug(1, - "ConnectionResumed not called"); - } - break; - - case 0x06: /* priority message complete */ - case 0x07: /* nonpriority message complete */ - if (h) { - if (interrupt->MessageComplete) - interrupt->MessageComplete( - (iucv_MessageComplete *)int_buf, - h->pgm_data); - else - iucv_debug(2, - "MessageComplete not called"); - } - break; - - case 0x08: /* priority message pending */ - case 0x09: /* nonpriority message pending */ - if (h) { - if (interrupt->MessagePending) - interrupt->MessagePending( - (iucv_MessagePending *) int_buf, - h->pgm_data); - else - iucv_debug(2, - "MessagePending not called"); - } - break; - default: /* unknown iucv type */ - printk(KERN_WARNING "%s: unknown iucv interrupt\n", - __FUNCTION__); - break; - } /* end switch */ - - iucv_debug(2, "exiting pathid %d, type %02X", - int_buf->ippathid, int_buf->iptype); - - return; -} - -/** - * iucv_tasklet_handler: - * - * This function loops over the queue of irq buffers and runs iucv_do_int() - * on every queue element. - */ -static void -iucv_tasklet_handler(unsigned long ignored) -{ - struct list_head head; - struct list_head *next; - ulong flags; - - spin_lock_irqsave(&iucv_irq_queue_lock, flags); - list_add(&head, &iucv_irq_queue); - list_del_init(&iucv_irq_queue); - spin_unlock_irqrestore (&iucv_irq_queue_lock, flags); - - next = head.next; - while (next != &head) { - iucv_irqdata *p = list_entry(next, iucv_irqdata, queue); - - next = next->next; - iucv_do_int(&p->data); - kfree(p); - } - - return; -} - -subsys_initcall(iucv_init); -module_exit(iucv_exit); - -/** - * Export all public stuff - */ -EXPORT_SYMBOL (iucv_bus); -EXPORT_SYMBOL (iucv_root); -EXPORT_SYMBOL (iucv_accept); -EXPORT_SYMBOL (iucv_connect); -#if 0 -EXPORT_SYMBOL (iucv_purge); -EXPORT_SYMBOL (iucv_query_maxconn); -EXPORT_SYMBOL (iucv_query_bufsize); -EXPORT_SYMBOL (iucv_quiesce); -#endif -EXPORT_SYMBOL (iucv_receive); -#if 0 -EXPORT_SYMBOL (iucv_receive_array); -#endif -EXPORT_SYMBOL (iucv_reject); -#if 0 -EXPORT_SYMBOL (iucv_reply); -EXPORT_SYMBOL (iucv_reply_array); -EXPORT_SYMBOL (iucv_resume); -#endif -EXPORT_SYMBOL (iucv_reply_prmmsg); -EXPORT_SYMBOL (iucv_send); -EXPORT_SYMBOL (iucv_send2way); -EXPORT_SYMBOL (iucv_send2way_array); -EXPORT_SYMBOL (iucv_send2way_prmmsg); -EXPORT_SYMBOL (iucv_send2way_prmmsg_array); -#if 0 -EXPORT_SYMBOL (iucv_send_array); -EXPORT_SYMBOL (iucv_send_prmmsg); -EXPORT_SYMBOL (iucv_setmask); -#endif -EXPORT_SYMBOL (iucv_sever); -EXPORT_SYMBOL (iucv_register_program); -EXPORT_SYMBOL (iucv_unregister_program); diff --git a/drivers/s390/net/iucv.h b/drivers/s390/net/iucv.h deleted file mode 100644 index 5b6b1b7..0000000 --- a/drivers/s390/net/iucv.h +++ /dev/null @@ -1,849 +0,0 @@ -/* - * drivers/s390/net/iucv.h - * IUCV base support. - * - * S390 version - * Copyright (C) 2000 IBM Corporation - * Author(s):Alan Altmark (Alan_Altmark@us.ibm.com) - * Xenia Tkatschow (xenia@us.ibm.com) - * - * - * Functionality: - * To explore any of the IUCV functions, one must first register - * their program using iucv_register_program(). Once your program has - * successfully completed a register, it can exploit the other functions. - * For furthur reference on all IUCV functionality, refer to the - * CP Programming Services book, also available on the web - * thru www.ibm.com/s390/vm/pubs, manual # SC24-5760 - * - * Definition of Return Codes - * -All positive return codes including zero are reflected back - * from CP except for iucv_register_program. The definition of each - * return code can be found in CP Programming Services book. - * Also available on the web thru www.ibm.com/s390/vm/pubs, manual # SC24-5760 - * - Return Code of: - * (-EINVAL) Invalid value - * (-ENOMEM) storage allocation failed - * pgmask defined in iucv_register_program will be set depending on input - * paramters. - * - */ - -#include -#include - -/** - * Debug Facility stuff - */ -#define IUCV_DBF_SETUP_NAME "iucv_setup" -#define IUCV_DBF_SETUP_LEN 32 -#define IUCV_DBF_SETUP_PAGES 2 -#define IUCV_DBF_SETUP_NR_AREAS 1 -#define IUCV_DBF_SETUP_LEVEL 3 - -#define IUCV_DBF_DATA_NAME "iucv_data" -#define IUCV_DBF_DATA_LEN 128 -#define IUCV_DBF_DATA_PAGES 2 -#define IUCV_DBF_DATA_NR_AREAS 1 -#define IUCV_DBF_DATA_LEVEL 2 - -#define IUCV_DBF_TRACE_NAME "iucv_trace" -#define IUCV_DBF_TRACE_LEN 16 -#define IUCV_DBF_TRACE_PAGES 4 -#define IUCV_DBF_TRACE_NR_AREAS 1 -#define IUCV_DBF_TRACE_LEVEL 3 - -#define IUCV_DBF_TEXT(name,level,text) \ - do { \ - debug_text_event(iucv_dbf_##name,level,text); \ - } while (0) - -#define IUCV_DBF_HEX(name,level,addr,len) \ - do { \ - debug_event(iucv_dbf_##name,level,(void*)(addr),len); \ - } while (0) - -DECLARE_PER_CPU(char[256], iucv_dbf_txt_buf); - -#define IUCV_DBF_TEXT_(name,level,text...) \ - do { \ - char* iucv_dbf_txt_buf = get_cpu_var(iucv_dbf_txt_buf); \ - sprintf(iucv_dbf_txt_buf, text); \ - debug_text_event(iucv_dbf_##name,level,iucv_dbf_txt_buf); \ - put_cpu_var(iucv_dbf_txt_buf); \ - } while (0) - -#define IUCV_DBF_SPRINTF(name,level,text...) \ - do { \ - debug_sprintf_event(iucv_dbf_trace, level, ##text ); \ - debug_sprintf_event(iucv_dbf_trace, level, text ); \ - } while (0) - -/** - * some more debug stuff - */ -#define IUCV_HEXDUMP16(importance,header,ptr) \ -PRINT_##importance(header "%02x %02x %02x %02x %02x %02x %02x %02x " \ - "%02x %02x %02x %02x %02x %02x %02x %02x\n", \ - *(((char*)ptr)),*(((char*)ptr)+1),*(((char*)ptr)+2), \ - *(((char*)ptr)+3),*(((char*)ptr)+4),*(((char*)ptr)+5), \ - *(((char*)ptr)+6),*(((char*)ptr)+7),*(((char*)ptr)+8), \ - *(((char*)ptr)+9),*(((char*)ptr)+10),*(((char*)ptr)+11), \ - *(((char*)ptr)+12),*(((char*)ptr)+13), \ - *(((char*)ptr)+14),*(((char*)ptr)+15)); \ -PRINT_##importance(header "%02x %02x %02x %02x %02x %02x %02x %02x " \ - "%02x %02x %02x %02x %02x %02x %02x %02x\n", \ - *(((char*)ptr)+16),*(((char*)ptr)+17), \ - *(((char*)ptr)+18),*(((char*)ptr)+19), \ - *(((char*)ptr)+20),*(((char*)ptr)+21), \ - *(((char*)ptr)+22),*(((char*)ptr)+23), \ - *(((char*)ptr)+24),*(((char*)ptr)+25), \ - *(((char*)ptr)+26),*(((char*)ptr)+27), \ - *(((char*)ptr)+28),*(((char*)ptr)+29), \ - *(((char*)ptr)+30),*(((char*)ptr)+31)); - -static inline void -iucv_hex_dump(unsigned char *buf, size_t len) -{ - size_t i; - - for (i = 0; i < len; i++) { - if (i && !(i % 16)) - printk("\n"); - printk("%02x ", *(buf + i)); - } - printk("\n"); -} -/** - * end of debug stuff - */ - -#define uchar unsigned char -#define ushort unsigned short -#define ulong unsigned long -#define iucv_handle_t void * - -/* flags1: - * All flags are defined in the field IPFLAGS1 of each function - * and can be found in CP Programming Services. - * IPLOCAL - Indicates the connect can only be satisfied on the - * local system - * IPPRTY - Indicates a priority message - * IPQUSCE - Indicates you do not want to receive messages on a - * path until an iucv_resume is issued - * IPRMDATA - Indicates that the message is in the parameter list - */ -#define IPLOCAL 0x01 -#define IPPRTY 0x20 -#define IPQUSCE 0x40 -#define IPRMDATA 0x80 - -/* flags1_out: - * All flags are defined in the output field of IPFLAGS1 for each function - * and can be found in CP Programming Services. - * IPNORPY - Specifies this is a one-way message and no reply is expected. - * IPPRTY - Indicates a priority message is permitted. Defined in flags1. - */ -#define IPNORPY 0x10 - -#define Nonpriority_MessagePendingInterruptsFlag 0x80 -#define Priority_MessagePendingInterruptsFlag 0x40 -#define Nonpriority_MessageCompletionInterruptsFlag 0x20 -#define Priority_MessageCompletionInterruptsFlag 0x10 -#define IUCVControlInterruptsFlag 0x08 -#define AllInterrupts 0xf8 -/* - * Mapping of external interrupt buffers should be used with the corresponding - * interrupt types. - * Names: iucv_ConnectionPending -> connection pending - * iucv_ConnectionComplete -> connection complete - * iucv_ConnectionSevered -> connection severed - * iucv_ConnectionQuiesced -> connection quiesced - * iucv_ConnectionResumed -> connection resumed - * iucv_MessagePending -> message pending - * iucv_MessageComplete -> message complete - */ -typedef struct { - u16 ippathid; - uchar ipflags1; - uchar iptype; - u16 ipmsglim; - u16 res1; - uchar ipvmid[8]; - uchar ipuser[16]; - u32 res3; - uchar ippollfg; - uchar res4[3]; -} iucv_ConnectionPending; - -typedef struct { - u16 ippathid; - uchar ipflags1; - uchar iptype; - u16 ipmsglim; - u16 res1; - uchar res2[8]; - uchar ipuser[16]; - u32 res3; - uchar ippollfg; - uchar res4[3]; -} iucv_ConnectionComplete; - -typedef struct { - u16 ippathid; - uchar res1; - uchar iptype; - u32 res2; - uchar res3[8]; - uchar ipuser[16]; - u32 res4; - uchar ippollfg; - uchar res5[3]; -} iucv_ConnectionSevered; - -typedef struct { - u16 ippathid; - uchar res1; - uchar iptype; - u32 res2; - uchar res3[8]; - uchar ipuser[16]; - u32 res4; - uchar ippollfg; - uchar res5[3]; -} iucv_ConnectionQuiesced; - -typedef struct { - u16 ippathid; - uchar res1; - uchar iptype; - u32 res2; - uchar res3[8]; - uchar ipuser[16]; - u32 res4; - uchar ippollfg; - uchar res5[3]; -} iucv_ConnectionResumed; - -typedef struct { - u16 ippathid; - uchar ipflags1; - uchar iptype; - u32 ipmsgid; - u32 iptrgcls; - union u2 { - u32 iprmmsg1_u32; - uchar iprmmsg1[4]; - } ln1msg1; - union u1 { - u32 ipbfln1f; - uchar iprmmsg2[4]; - } ln1msg2; - u32 res1[3]; - u32 ipbfln2f; - uchar ippollfg; - uchar res2[3]; -} iucv_MessagePending; - -typedef struct { - u16 ippathid; - uchar ipflags1; - uchar iptype; - u32 ipmsgid; - u32 ipaudit; - uchar iprmmsg[8]; - u32 ipsrccls; - u32 ipmsgtag; - u32 res; - u32 ipbfln2f; - uchar ippollfg; - uchar res2[3]; -} iucv_MessageComplete; - -/* - * iucv_interrupt_ops_t: Is a vector of functions that handle - * IUCV interrupts. - * Parameter list: - * eib - is a pointer to a 40-byte area described - * with one of the structures above. - * pgm_data - this data is strictly for the - * interrupt handler that is passed by - * the application. This may be an address - * or token. -*/ -typedef struct { - void (*ConnectionPending) (iucv_ConnectionPending * eib, - void *pgm_data); - void (*ConnectionComplete) (iucv_ConnectionComplete * eib, - void *pgm_data); - void (*ConnectionSevered) (iucv_ConnectionSevered * eib, - void *pgm_data); - void (*ConnectionQuiesced) (iucv_ConnectionQuiesced * eib, - void *pgm_data); - void (*ConnectionResumed) (iucv_ConnectionResumed * eib, - void *pgm_data); - void (*MessagePending) (iucv_MessagePending * eib, void *pgm_data); - void (*MessageComplete) (iucv_MessageComplete * eib, void *pgm_data); -} iucv_interrupt_ops_t; - -/* - *iucv_array_t : Defines buffer array. - * Inside the array may be 31- bit addresses and 31-bit lengths. -*/ -typedef struct { - u32 address; - u32 length; -} iucv_array_t __attribute__ ((aligned (8))); - -extern struct bus_type iucv_bus; -extern struct device *iucv_root; - -/* -prototypes- */ -/* - * Name: iucv_register_program - * Purpose: Registers an application with IUCV - * Input: prmname - user identification - * userid - machine identification - * pgmmask - indicates which bits in the prmname and userid combined will be - * used to determine who is given control - * ops - address of vector of interrupt handlers - * pgm_data- application data passed to interrupt handlers - * Output: NA - * Return: address of handler - * (0) - Error occurred, registration not completed. - * NOTE: Exact cause of failure will be recorded in syslog. -*/ -iucv_handle_t iucv_register_program (uchar pgmname[16], - uchar userid[8], - uchar pgmmask[24], - iucv_interrupt_ops_t * ops, - void *pgm_data); - -/* - * Name: iucv_unregister_program - * Purpose: Unregister application with IUCV - * Input: address of handler - * Output: NA - * Return: (0) - Normal return - * (-EINVAL) - Internal error, wild pointer -*/ -int iucv_unregister_program (iucv_handle_t handle); - -/* - * Name: iucv_accept - * Purpose: This function is issued after the user receives a Connection Pending external - * interrupt and now wishes to complete the IUCV communication path. - * Input: pathid - u16 , Path identification number - * msglim_reqstd - u16, The number of outstanding messages requested. - * user_data - uchar[16], Data specified by the iucv_connect function. - * flags1 - int, Contains options for this path. - * -IPPRTY - 0x20- Specifies if you want to send priority message. - * -IPRMDATA - 0x80, Specifies whether your program can handle a message - * in the parameter list. - * -IPQUSCE - 0x40, Specifies whether you want to quiesce the path being - * established. - * handle - iucv_handle_t, Address of handler. - * pgm_data - void *, Application data passed to interrupt handlers. - * flags1_out - int * Contains information about the path - * - IPPRTY - 0x20, Indicates you may send priority messages. - * msglim - *u16, Number of outstanding messages. - * Output: return code from CP IUCV call. -*/ - -int iucv_accept (u16 pathid, - u16 msglim_reqstd, - uchar user_data[16], - int flags1, - iucv_handle_t handle, - void *pgm_data, int *flags1_out, u16 * msglim); - -/* - * Name: iucv_connect - * Purpose: This function establishes an IUCV path. Although the connect may complete - * successfully, you are not able to use the path until you receive an IUCV - * Connection Complete external interrupt. - * Input: pathid - u16 *, Path identification number - * msglim_reqstd - u16, Number of outstanding messages requested - * user_data - uchar[16], 16-byte user data - * userid - uchar[8], User identification - * system_name - uchar[8], 8-byte identifying the system name - * flags1 - int, Contains options for this path. - * -IPPRTY - 0x20, Specifies if you want to send priority message. - * -IPRMDATA - 0x80, Specifies whether your program can handle a message - * in the parameter list. - * -IPQUSCE - 0x40, Specifies whether you want to quiesce the path being - * established. - * -IPLOCAL - 0X01, Allows an application to force the partner to be on - * the local system. If local is specified then target class cannot be - * specified. - * flags1_out - int * Contains information about the path - * - IPPRTY - 0x20, Indicates you may send priority messages. - * msglim - * u16, Number of outstanding messages - * handle - iucv_handle_t, Address of handler - * pgm_data - void *, Application data passed to interrupt handlers - * Output: return code from CP IUCV call - * rc - return code from iucv_declare_buffer - * -EINVAL - Invalid handle passed by application - * -EINVAL - Pathid address is NULL - * add_pathid_result - Return code from internal function add_pathid -*/ -int - iucv_connect (u16 * pathid, - u16 msglim_reqstd, - uchar user_data[16], - uchar userid[8], - uchar system_name[8], - int flags1, - int *flags1_out, - u16 * msglim, iucv_handle_t handle, void *pgm_data); - -/* - * Name: iucv_purge - * Purpose: This function cancels a message that you have sent. - * Input: pathid - Path identification number. - * msgid - Specifies the message ID of the message to be purged. - * srccls - Specifies the source message class. - * Output: audit - Contains information about asynchronous error - * that may have affected the normal completion - * of this message. - * Return: Return code from CP IUCV call. -*/ -int iucv_purge (u16 pathid, u32 msgid, u32 srccls, __u32 *audit); -/* - * Name: iucv_query_maxconn - * Purpose: This function determines the maximum number of communication paths you - * may establish. - * Return: maxconn - ulong, Maximum number of connection the virtual machine may - * establish. -*/ -ulong iucv_query_maxconn (void); - -/* - * Name: iucv_query_bufsize - * Purpose: This function determines how large an external interrupt - * buffer IUCV requires to store information. - * Return: bufsize - ulong, Size of external interrupt buffer. - */ -ulong iucv_query_bufsize (void); - -/* - * Name: iucv_quiesce - * Purpose: This function temporarily suspends incoming messages on an - * IUCV path. You can later reactivate the path by invoking - * the iucv_resume function. - * Input: pathid - Path identification number - * user_data - 16-bytes of user data - * Output: NA - * Return: Return code from CP IUCV call. -*/ -int iucv_quiesce (u16 pathid, uchar user_data[16]); - -/* - * Name: iucv_receive - * Purpose: This function receives messages that are being sent to you - * over established paths. Data will be returned in buffer for length of - * buflen. - * Input: - * pathid - Path identification number. - * buffer - Address of buffer to receive. - * buflen - Length of buffer to receive. - * msgid - Specifies the message ID. - * trgcls - Specifies target class. - * Output: - * flags1_out: int *, Contains information about this path. - * IPNORPY - 0x10 Specifies this is a one-way message and no reply is - * expected. - * IPPRTY - 0x20 Specifies if you want to send priority message. - * IPRMDATA - 0x80 specifies the data is contained in the parameter list - * residual_buffer - address of buffer updated by the number - * of bytes you have received. - * residual_length - - * Contains one of the following values, if the receive buffer is: - * The same length as the message, this field is zero. - * Longer than the message, this field contains the number of - * bytes remaining in the buffer. - * Shorter than the message, this field contains the residual - * count (that is, the number of bytes remaining in the - * message that does not fit into the buffer. In this - * case b2f0_result = 5. - * Return: Return code from CP IUCV call. - * (-EINVAL) - buffer address is pointing to NULL -*/ -int iucv_receive (u16 pathid, - u32 msgid, - u32 trgcls, - void *buffer, - ulong buflen, - int *flags1_out, - ulong * residual_buffer, ulong * residual_length); - - /* - * Name: iucv_receive_array - * Purpose: This function receives messages that are being sent to you - * over established paths. Data will be returned in first buffer for - * length of first buffer. - * Input: pathid - Path identification number. - * msgid - specifies the message ID. - * trgcls - Specifies target class. - * buffer - Address of array of buffers. - * buflen - Total length of buffers. - * Output: - * flags1_out: int *, Contains information about this path. - * IPNORPY - 0x10 Specifies this is a one-way message and no reply is - * expected. - * IPPRTY - 0x20 Specifies if you want to send priority message. - * IPRMDATA - 0x80 specifies the data is contained in the parameter list - * residual_buffer - address points to the current list entry IUCV - * is working on. - * residual_length - - * Contains one of the following values, if the receive buffer is: - * The same length as the message, this field is zero. - * Longer than the message, this field contains the number of - * bytes remaining in the buffer. - * Shorter than the message, this field contains the residual - * count (that is, the number of bytes remaining in the - * message that does not fit into the buffer. In this - * case b2f0_result = 5. - * Return: Return code from CP IUCV call. - * (-EINVAL) - Buffer address is NULL. - */ -int iucv_receive_array (u16 pathid, - u32 msgid, - u32 trgcls, - iucv_array_t * buffer, - ulong buflen, - int *flags1_out, - ulong * residual_buffer, ulong * residual_length); - -/* - * Name: iucv_reject - * Purpose: The reject function refuses a specified message. Between the - * time you are notified of a message and the time that you - * complete the message, the message may be rejected. - * Input: pathid - Path identification number. - * msgid - Specifies the message ID. - * trgcls - Specifies target class. - * Output: NA - * Return: Return code from CP IUCV call. -*/ -int iucv_reject (u16 pathid, u32 msgid, u32 trgcls); - -/* - * Name: iucv_reply - * Purpose: This function responds to the two-way messages that you - * receive. You must identify completely the message to - * which you wish to reply. ie, pathid, msgid, and trgcls. - * Input: pathid - Path identification number. - * msgid - Specifies the message ID. - * trgcls - Specifies target class. - * flags1 - Option for path. - * IPPRTY- 0x20, Specifies if you want to send priority message. - * buffer - Address of reply buffer. - * buflen - Length of reply buffer. - * Output: residual_buffer - Address of buffer updated by the number - * of bytes you have moved. - * residual_length - Contains one of the following values: - * If the answer buffer is the same length as the reply, this field - * contains zero. - * If the answer buffer is longer than the reply, this field contains - * the number of bytes remaining in the buffer. - * If the answer buffer is shorter than the reply, this field contains - * a residual count (that is, the number of bytes remianing in the - * reply that does not fit into the buffer. In this - * case b2f0_result = 5. - * Return: Return code from CP IUCV call. - * (-EINVAL) - Buffer address is NULL. -*/ -int iucv_reply (u16 pathid, - u32 msgid, - u32 trgcls, - int flags1, - void *buffer, ulong buflen, ulong * residual_buffer, - ulong * residual_length); - -/* - * Name: iucv_reply_array - * Purpose: This function responds to the two-way messages that you - * receive. You must identify completely the message to - * which you wish to reply. ie, pathid, msgid, and trgcls. - * The array identifies a list of addresses and lengths of - * discontiguous buffers that contains the reply data. - * Input: pathid - Path identification number - * msgid - Specifies the message ID. - * trgcls - Specifies target class. - * flags1 - Option for path. - * IPPRTY- 0x20, Specifies if you want to send priority message. - * buffer - Address of array of reply buffers. - * buflen - Total length of reply buffers. - * Output: residual_buffer - Address of buffer which IUCV is currently working on. - * residual_length - Contains one of the following values: - * If the answer buffer is the same length as the reply, this field - * contains zero. - * If the answer buffer is longer than the reply, this field contains - * the number of bytes remaining in the buffer. - * If the answer buffer is shorter than the reply, this field contains - * a residual count (that is, the number of bytes remianing in the - * reply that does not fit into the buffer. In this - * case b2f0_result = 5. - * Return: Return code from CP IUCV call. - * (-EINVAL) - Buffer address is NULL. -*/ -int iucv_reply_array (u16 pathid, - u32 msgid, - u32 trgcls, - int flags1, - iucv_array_t * buffer, - ulong buflen, ulong * residual_address, - ulong * residual_length); - -/* - * Name: iucv_reply_prmmsg - * Purpose: This function responds to the two-way messages that you - * receive. You must identify completely the message to - * which you wish to reply. ie, pathid, msgid, and trgcls. - * Prmmsg signifies the data is moved into the - * parameter list. - * Input: pathid - Path identification number. - * msgid - Specifies the message ID. - * trgcls - Specifies target class. - * flags1 - Option for path. - * IPPRTY- 0x20 Specifies if you want to send priority message. - * prmmsg - 8-bytes of data to be placed into the parameter. - * list. - * Output: NA - * Return: Return code from CP IUCV call. -*/ -int iucv_reply_prmmsg (u16 pathid, - u32 msgid, u32 trgcls, int flags1, uchar prmmsg[8]); - -/* - * Name: iucv_resume - * Purpose: This function restores communications over a quiesced path - * Input: pathid - Path identification number. - * user_data - 16-bytes of user data. - * Output: NA - * Return: Return code from CP IUCV call. -*/ -int iucv_resume (u16 pathid, uchar user_data[16]); - -/* - * Name: iucv_send - * Purpose: This function transmits data to another application. - * Data to be transmitted is in a buffer and this is a - * one-way message and the receiver will not reply to the - * message. - * Input: pathid - Path identification number. - * trgcls - Specifies target class. - * srccls - Specifies the source message class. - * msgtag - Specifies a tag to be associated with the message. - * flags1 - Option for path. - * IPPRTY- 0x20 Specifies if you want to send priority message. - * buffer - Address of send buffer. - * buflen - Length of send buffer. - * Output: msgid - Specifies the message ID. - * Return: Return code from CP IUCV call. - * (-EINVAL) - Buffer address is NULL. -*/ -int iucv_send (u16 pathid, - u32 * msgid, - u32 trgcls, - u32 srccls, u32 msgtag, int flags1, void *buffer, ulong buflen); - -/* - * Name: iucv_send_array - * Purpose: This function transmits data to another application. - * The contents of buffer is the address of the array of - * addresses and lengths of discontiguous buffers that hold - * the message text. This is a one-way message and the - * receiver will not reply to the message. - * Input: pathid - Path identification number. - * trgcls - Specifies target class. - * srccls - Specifies the source message class. - * msgtag - Specifies a tag to be associated witht the message. - * flags1 - Option for path. - * IPPRTY- specifies if you want to send priority message. - * buffer - Address of array of send buffers. - * buflen - Total length of send buffers. - * Output: msgid - Specifies the message ID. - * Return: Return code from CP IUCV call. - * (-EINVAL) - Buffer address is NULL. -*/ -int iucv_send_array (u16 pathid, - u32 * msgid, - u32 trgcls, - u32 srccls, - u32 msgtag, - int flags1, iucv_array_t * buffer, ulong buflen); - -/* - * Name: iucv_send_prmmsg - * Purpose: This function transmits data to another application. - * Prmmsg specifies that the 8-bytes of data are to be moved - * into the parameter list. This is a one-way message and the - * receiver will not reply to the message. - * Input: pathid - Path identification number. - * trgcls - Specifies target class. - * srccls - Specifies the source message class. - * msgtag - Specifies a tag to be associated with the message. - * flags1 - Option for path. - * IPPRTY- 0x20 specifies if you want to send priority message. - * prmmsg - 8-bytes of data to be placed into parameter list. - * Output: msgid - Specifies the message ID. - * Return: Return code from CP IUCV call. -*/ -int iucv_send_prmmsg (u16 pathid, - u32 * msgid, - u32 trgcls, - u32 srccls, u32 msgtag, int flags1, uchar prmmsg[8]); - -/* - * Name: iucv_send2way - * Purpose: This function transmits data to another application. - * Data to be transmitted is in a buffer. The receiver - * of the send is expected to reply to the message and - * a buffer is provided into which IUCV moves the reply - * to this message. - * Input: pathid - Path identification number. - * trgcls - Specifies target class. - * srccls - Specifies the source message class. - * msgtag - Specifies a tag associated with the message. - * flags1 - Option for path. - * IPPRTY- 0x20 Specifies if you want to send priority message. - * buffer - Address of send buffer. - * buflen - Length of send buffer. - * ansbuf - Address of buffer into which IUCV moves the reply of - * this message. - * anslen - Address of length of buffer. - * Output: msgid - Specifies the message ID. - * Return: Return code from CP IUCV call. - * (-EINVAL) - Buffer or ansbuf address is NULL. -*/ -int iucv_send2way (u16 pathid, - u32 * msgid, - u32 trgcls, - u32 srccls, - u32 msgtag, - int flags1, - void *buffer, ulong buflen, void *ansbuf, ulong anslen); - -/* - * Name: iucv_send2way_array - * Purpose: This function transmits data to another application. - * The contents of buffer is the address of the array of - * addresses and lengths of discontiguous buffers that hold - * the message text. The receiver of the send is expected to - * reply to the message and a buffer is provided into which - * IUCV moves the reply to this message. - * Input: pathid - Path identification number. - * trgcls - Specifies target class. - * srccls - Specifies the source message class. - * msgtag - Specifies a tag to be associated with the message. - * flags1 - Option for path. - * IPPRTY- 0x20 Specifies if you want to send priority message. - * buffer - Sddress of array of send buffers. - * buflen - Total length of send buffers. - * ansbuf - Address of array of buffer into which IUCV moves the reply - * of this message. - * anslen - Address of length reply buffers. - * Output: msgid - Specifies the message ID. - * Return: Return code from CP IUCV call. - * (-EINVAL) - Buffer address is NULL. -*/ -int iucv_send2way_array (u16 pathid, - u32 * msgid, - u32 trgcls, - u32 srccls, - u32 msgtag, - int flags1, - iucv_array_t * buffer, - ulong buflen, iucv_array_t * ansbuf, ulong anslen); - -/* - * Name: iucv_send2way_prmmsg - * Purpose: This function transmits data to another application. - * Prmmsg specifies that the 8-bytes of data are to be moved - * into the parameter list. This is a two-way message and the - * receiver of the message is expected to reply. A buffer - * is provided into which IUCV moves the reply to this - * message. - * Input: pathid - Rath identification number. - * trgcls - Specifies target class. - * srccls - Specifies the source message class. - * msgtag - Specifies a tag to be associated with the message. - * flags1 - Option for path. - * IPPRTY- 0x20 Specifies if you want to send priority message. - * prmmsg - 8-bytes of data to be placed in parameter list. - * ansbuf - Address of buffer into which IUCV moves the reply of - * this message. - * anslen - Address of length of buffer. - * Output: msgid - Specifies the message ID. - * Return: Return code from CP IUCV call. - * (-EINVAL) - Buffer address is NULL. -*/ -int iucv_send2way_prmmsg (u16 pathid, - u32 * msgid, - u32 trgcls, - u32 srccls, - u32 msgtag, - ulong flags1, - uchar prmmsg[8], void *ansbuf, ulong anslen); - -/* - * Name: iucv_send2way_prmmsg_array - * Purpose: This function transmits data to another application. - * Prmmsg specifies that the 8-bytes of data are to be moved - * into the parameter list. This is a two-way message and the - * receiver of the message is expected to reply. A buffer - * is provided into which IUCV moves the reply to this - * message. The contents of ansbuf is the address of the - * array of addresses and lengths of discontiguous buffers - * that contain the reply. - * Input: pathid - Path identification number. - * trgcls - Specifies target class. - * srccls - Specifies the source message class. - * msgtag - Specifies a tag to be associated with the message. - * flags1 - Option for path. - * IPPRTY- 0x20 specifies if you want to send priority message. - * prmmsg - 8-bytes of data to be placed into the parameter list. - * ansbuf - Address of array of buffer into which IUCV moves the reply - * of this message. - * anslen - Address of length of reply buffers. - * Output: msgid - Specifies the message ID. - * Return: Return code from CP IUCV call. - * (-EINVAL) - Ansbuf address is NULL. -*/ -int iucv_send2way_prmmsg_array (u16 pathid, - u32 * msgid, - u32 trgcls, - u32 srccls, - u32 msgtag, - int flags1, - uchar prmmsg[8], - iucv_array_t * ansbuf, ulong anslen); - -/* - * Name: iucv_setmask - * Purpose: This function enables or disables the following IUCV - * external interruptions: Nonpriority and priority message - * interrupts, nonpriority and priority reply interrupts. - * Input: SetMaskFlag - options for interrupts - * 0x80 - Nonpriority_MessagePendingInterruptsFlag - * 0x40 - Priority_MessagePendingInterruptsFlag - * 0x20 - Nonpriority_MessageCompletionInterruptsFlag - * 0x10 - Priority_MessageCompletionInterruptsFlag - * 0x08 - IUCVControlInterruptsFlag - * Output: NA - * Return: Return code from CP IUCV call. -*/ -int iucv_setmask (int SetMaskFlag); - -/* - * Name: iucv_sever - * Purpose: This function terminates an IUCV path. - * Input: pathid - Path identification number. - * user_data - 16-bytes of user data. - * Output: NA - * Return: Return code from CP IUCV call. - * (-EINVAL) - Interal error, wild pointer. -*/ -int iucv_sever (u16 pathid, uchar user_data[16]); diff --git a/drivers/s390/net/lcs.c b/drivers/s390/net/lcs.c index e5665b6..ecca104 100644 --- a/drivers/s390/net/lcs.c +++ b/drivers/s390/net/lcs.c @@ -828,7 +828,7 @@ lcs_notify_lancmd_waiters(struct lcs_car /** * Emit buffer of a lan comand. */ -void +static void lcs_lancmd_timeout(unsigned long data) { struct lcs_reply *reply, *list_reply, *r; @@ -1360,7 +1360,7 @@ lcs_get_problem(struct ccw_device *cdev, return 0; } -void +static void lcs_schedule_recovery(struct lcs_card *card) { LCS_DBF_TEXT(2, trace, "startrec"); @@ -1511,8 +1511,7 @@ lcs_txbuffer_cb(struct lcs_channel *chan LCS_DBF_TEXT(5, trace, "txbuffcb"); /* Put buffer back to pool. */ lcs_release_buffer(channel, buffer); - card = (struct lcs_card *) - ((char *) channel - offsetof(struct lcs_card, write)); + card = container_of(channel, struct lcs_card, write); if (netif_queue_stopped(card->dev) && netif_carrier_ok(card->dev)) netif_wake_queue(card->dev); spin_lock(&card->lock); @@ -1810,8 +1809,7 @@ lcs_get_frames_cb(struct lcs_channel *ch LCS_DBF_TEXT(4, trace, "-eiogpkt"); return; } - card = (struct lcs_card *) - ((char *) channel - offsetof(struct lcs_card, read)); + card = container_of(channel, struct lcs_card, read); offset = 0; while (lcs_hdr->offset != 0) { if (lcs_hdr->offset <= 0 || @@ -1990,7 +1988,7 @@ lcs_timeout_store (struct device *dev, s } -DEVICE_ATTR(lancmd_timeout, 0644, lcs_timeout_show, lcs_timeout_store); +static DEVICE_ATTR(lancmd_timeout, 0644, lcs_timeout_show, lcs_timeout_store); static ssize_t lcs_dev_recover_store(struct device *dev, struct device_attribute *attr, diff --git a/drivers/s390/net/netiucv.c b/drivers/s390/net/netiucv.c index d7d1cc0..594320c 100644 --- a/drivers/s390/net/netiucv.c +++ b/drivers/s390/net/netiucv.c @@ -1,7 +1,7 @@ /* * IUCV network driver * - * Copyright (C) 2001 IBM Deutschland Entwicklung GmbH, IBM Corporation + * Copyright 2001 IBM Deutschland Entwicklung GmbH, IBM Corporation * Author(s): Fritz Elfert (elfert@de.ibm.com, felfert@millenux.com) * * Sysfs integration and all bugs therein by Cornelia Huck @@ -41,7 +41,6 @@ #include #include #include #include -#include #include #include @@ -58,13 +57,94 @@ #include #include #include -#include "iucv.h" +#include #include "fsm.h" MODULE_AUTHOR ("(C) 2001 IBM Corporation by Fritz Elfert (felfert@millenux.com)"); MODULE_DESCRIPTION ("Linux for S/390 IUCV network driver"); +/** + * Debug Facility stuff + */ +#define IUCV_DBF_SETUP_NAME "iucv_setup" +#define IUCV_DBF_SETUP_LEN 32 +#define IUCV_DBF_SETUP_PAGES 2 +#define IUCV_DBF_SETUP_NR_AREAS 1 +#define IUCV_DBF_SETUP_LEVEL 3 + +#define IUCV_DBF_DATA_NAME "iucv_data" +#define IUCV_DBF_DATA_LEN 128 +#define IUCV_DBF_DATA_PAGES 2 +#define IUCV_DBF_DATA_NR_AREAS 1 +#define IUCV_DBF_DATA_LEVEL 2 + +#define IUCV_DBF_TRACE_NAME "iucv_trace" +#define IUCV_DBF_TRACE_LEN 16 +#define IUCV_DBF_TRACE_PAGES 4 +#define IUCV_DBF_TRACE_NR_AREAS 1 +#define IUCV_DBF_TRACE_LEVEL 3 + +#define IUCV_DBF_TEXT(name,level,text) \ + do { \ + debug_text_event(iucv_dbf_##name,level,text); \ + } while (0) + +#define IUCV_DBF_HEX(name,level,addr,len) \ + do { \ + debug_event(iucv_dbf_##name,level,(void*)(addr),len); \ + } while (0) + +DECLARE_PER_CPU(char[256], iucv_dbf_txt_buf); + +#define IUCV_DBF_TEXT_(name,level,text...) \ + do { \ + char* iucv_dbf_txt_buf = get_cpu_var(iucv_dbf_txt_buf); \ + sprintf(iucv_dbf_txt_buf, text); \ + debug_text_event(iucv_dbf_##name,level,iucv_dbf_txt_buf); \ + put_cpu_var(iucv_dbf_txt_buf); \ + } while (0) + +#define IUCV_DBF_SPRINTF(name,level,text...) \ + do { \ + debug_sprintf_event(iucv_dbf_trace, level, ##text ); \ + debug_sprintf_event(iucv_dbf_trace, level, text ); \ + } while (0) + +/** + * some more debug stuff + */ +#define IUCV_HEXDUMP16(importance,header,ptr) \ +PRINT_##importance(header "%02x %02x %02x %02x %02x %02x %02x %02x " \ + "%02x %02x %02x %02x %02x %02x %02x %02x\n", \ + *(((char*)ptr)),*(((char*)ptr)+1),*(((char*)ptr)+2), \ + *(((char*)ptr)+3),*(((char*)ptr)+4),*(((char*)ptr)+5), \ + *(((char*)ptr)+6),*(((char*)ptr)+7),*(((char*)ptr)+8), \ + *(((char*)ptr)+9),*(((char*)ptr)+10),*(((char*)ptr)+11), \ + *(((char*)ptr)+12),*(((char*)ptr)+13), \ + *(((char*)ptr)+14),*(((char*)ptr)+15)); \ +PRINT_##importance(header "%02x %02x %02x %02x %02x %02x %02x %02x " \ + "%02x %02x %02x %02x %02x %02x %02x %02x\n", \ + *(((char*)ptr)+16),*(((char*)ptr)+17), \ + *(((char*)ptr)+18),*(((char*)ptr)+19), \ + *(((char*)ptr)+20),*(((char*)ptr)+21), \ + *(((char*)ptr)+22),*(((char*)ptr)+23), \ + *(((char*)ptr)+24),*(((char*)ptr)+25), \ + *(((char*)ptr)+26),*(((char*)ptr)+27), \ + *(((char*)ptr)+28),*(((char*)ptr)+29), \ + *(((char*)ptr)+30),*(((char*)ptr)+31)); + +static inline void iucv_hex_dump(unsigned char *buf, size_t len) +{ + size_t i; + + for (i = 0; i < len; i++) { + if (i && !(i % 16)) + printk("\n"); + printk("%02x ", *(buf + i)); + } + printk("\n"); +} #define PRINTK_HEADER " iucv: " /* for debugging */ @@ -73,6 +153,25 @@ static struct device_driver netiucv_driv .bus = &iucv_bus, }; +static int netiucv_callback_connreq(struct iucv_path *, + u8 ipvmid[8], u8 ipuser[16]); +static void netiucv_callback_connack(struct iucv_path *, u8 ipuser[16]); +static void netiucv_callback_connrej(struct iucv_path *, u8 ipuser[16]); +static void netiucv_callback_connsusp(struct iucv_path *, u8 ipuser[16]); +static void netiucv_callback_connres(struct iucv_path *, u8 ipuser[16]); +static void netiucv_callback_rx(struct iucv_path *, struct iucv_message *); +static void netiucv_callback_txdone(struct iucv_path *, struct iucv_message *); + +static struct iucv_handler netiucv_handler = { + .path_pending = netiucv_callback_connreq, + .path_complete = netiucv_callback_connack, + .path_severed = netiucv_callback_connrej, + .path_quiesced = netiucv_callback_connsusp, + .path_resumed = netiucv_callback_connres, + .message_pending = netiucv_callback_rx, + .message_complete = netiucv_callback_txdone +}; + /** * Per connection profiling data */ @@ -92,9 +191,8 @@ struct connection_profile { * Representation of one iucv connection */ struct iucv_connection { - struct iucv_connection *next; - iucv_handle_t handle; - __u16 pathid; + struct list_head list; + struct iucv_path *path; struct sk_buff *rx_buff; struct sk_buff *tx_buff; struct sk_buff_head collect_queue; @@ -112,12 +210,9 @@ struct iucv_connection { /** * Linked list of all connection structs. */ -struct iucv_connection_struct { - struct iucv_connection *iucv_connections; - rwlock_t iucv_rwlock; -}; - -static struct iucv_connection_struct iucv_conns; +static struct list_head iucv_connection_list = + LIST_HEAD_INIT(iucv_connection_list); +static rwlock_t iucv_connection_rwlock = RW_LOCK_UNLOCKED; /** * Representation of event-data for the @@ -142,11 +237,11 @@ struct netiucv_priv { /** * Link level header for a packet. */ -typedef struct ll_header_t { - __u16 next; -} ll_header; +struct ll_header { + u16 next; +}; -#define NETIUCV_HDRLEN (sizeof(ll_header)) +#define NETIUCV_HDRLEN (sizeof(struct ll_header)) #define NETIUCV_BUFSIZE_MAX 32768 #define NETIUCV_BUFSIZE_DEFAULT NETIUCV_BUFSIZE_MAX #define NETIUCV_MTU_MAX (NETIUCV_BUFSIZE_MAX - NETIUCV_HDRLEN) @@ -158,36 +253,26 @@ #define NETIUCV_TIMEOUT_5SEC 5000 * Compatibility macros for busy handling * of network devices. */ -static __inline__ void netiucv_clear_busy(struct net_device *dev) +static inline void netiucv_clear_busy(struct net_device *dev) { - clear_bit(0, &(((struct netiucv_priv *)dev->priv)->tbusy)); + struct netiucv_priv *priv = netdev_priv(dev); + clear_bit(0, &priv->tbusy); netif_wake_queue(dev); } -static __inline__ int netiucv_test_and_set_busy(struct net_device *dev) +static inline int netiucv_test_and_set_busy(struct net_device *dev) { + struct netiucv_priv *priv = netdev_priv(dev); netif_stop_queue(dev); - return test_and_set_bit(0, &((struct netiucv_priv *)dev->priv)->tbusy); + return test_and_set_bit(0, &priv->tbusy); } -static __u8 iucv_host[8] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; -static __u8 iucvMagic[16] = { +static u8 iucvMagic[16] = { 0xF0, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0xF0, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40 }; /** - * This mask means the 16-byte IUCV "magic" and the origin userid must - * match exactly as specified in order to give connection_pending() - * control. - */ -static __u8 netiucv_mask[] = { - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff -}; - -/** * Convert an iucv userId to its printable * form (strip whitespace at end). * @@ -195,8 +280,7 @@ static __u8 netiucv_mask[] = { * * @returns The printable string (static data!!) */ -static __inline__ char * -netiucv_printname(char *name) +static inline char *netiucv_printname(char *name) { static char tmp[9]; char *p = tmp; @@ -379,8 +463,7 @@ static debug_info_t *iucv_dbf_trace = NU DEFINE_PER_CPU(char[256], iucv_dbf_txt_buf); -static void -iucv_unregister_dbf_views(void) +static void iucv_unregister_dbf_views(void) { if (iucv_dbf_setup) debug_unregister(iucv_dbf_setup); @@ -389,8 +472,7 @@ iucv_unregister_dbf_views(void) if (iucv_dbf_trace) debug_unregister(iucv_dbf_trace); } -static int -iucv_register_dbf_views(void) +static int iucv_register_dbf_views(void) { iucv_dbf_setup = debug_register(IUCV_DBF_SETUP_NAME, IUCV_DBF_SETUP_PAGES, @@ -422,125 +504,111 @@ iucv_register_dbf_views(void) return 0; } -/** +/* * Callback-wrappers, called from lowlevel iucv layer. - *****************************************************************************/ + */ -static void -netiucv_callback_rx(iucv_MessagePending *eib, void *pgm_data) +static void netiucv_callback_rx(struct iucv_path *path, + struct iucv_message *msg) { - struct iucv_connection *conn = (struct iucv_connection *)pgm_data; + struct iucv_connection *conn = path->private; struct iucv_event ev; ev.conn = conn; - ev.data = (void *)eib; - + ev.data = msg; fsm_event(conn->fsm, CONN_EVENT_RX, &ev); } -static void -netiucv_callback_txdone(iucv_MessageComplete *eib, void *pgm_data) +static void netiucv_callback_txdone(struct iucv_path *path, + struct iucv_message *msg) { - struct iucv_connection *conn = (struct iucv_connection *)pgm_data; + struct iucv_connection *conn = path->private; struct iucv_event ev; ev.conn = conn; - ev.data = (void *)eib; + ev.data = msg; fsm_event(conn->fsm, CONN_EVENT_TXDONE, &ev); } -static void -netiucv_callback_connack(iucv_ConnectionComplete *eib, void *pgm_data) +static void netiucv_callback_connack(struct iucv_path *path, u8 ipuser[16]) { - struct iucv_connection *conn = (struct iucv_connection *)pgm_data; - struct iucv_event ev; + struct iucv_connection *conn = path->private; - ev.conn = conn; - ev.data = (void *)eib; - fsm_event(conn->fsm, CONN_EVENT_CONN_ACK, &ev); + fsm_event(conn->fsm, CONN_EVENT_CONN_ACK, conn); } -static void -netiucv_callback_connreq(iucv_ConnectionPending *eib, void *pgm_data) +static int netiucv_callback_connreq(struct iucv_path *path, + u8 ipvmid[8], u8 ipuser[16]) { - struct iucv_connection *conn = (struct iucv_connection *)pgm_data; + struct iucv_connection *conn = path->private; struct iucv_event ev; + int rc; - ev.conn = conn; - ev.data = (void *)eib; - fsm_event(conn->fsm, CONN_EVENT_CONN_REQ, &ev); + if (memcmp(iucvMagic, ipuser, sizeof(ipuser))) + /* ipuser must match iucvMagic. */ + return -EINVAL; + rc = -EINVAL; + read_lock_bh(&iucv_connection_rwlock); + list_for_each_entry(conn, &iucv_connection_list, list) { + if (strncmp(ipvmid, conn->userid, 8)) + continue; + /* Found a matching connection for this path. */ + conn->path = path; + ev.conn = conn; + ev.data = path; + fsm_event(conn->fsm, CONN_EVENT_CONN_REQ, &ev); + rc = 0; + } + read_unlock_bh(&iucv_connection_rwlock); + return rc; } -static void -netiucv_callback_connrej(iucv_ConnectionSevered *eib, void *pgm_data) +static void netiucv_callback_connrej(struct iucv_path *path, u8 ipuser[16]) { - struct iucv_connection *conn = (struct iucv_connection *)pgm_data; - struct iucv_event ev; + struct iucv_connection *conn = path->private; - ev.conn = conn; - ev.data = (void *)eib; - fsm_event(conn->fsm, CONN_EVENT_CONN_REJ, &ev); + fsm_event(conn->fsm, CONN_EVENT_CONN_REJ, conn); } -static void -netiucv_callback_connsusp(iucv_ConnectionQuiesced *eib, void *pgm_data) +static void netiucv_callback_connsusp(struct iucv_path *path, u8 ipuser[16]) { - struct iucv_connection *conn = (struct iucv_connection *)pgm_data; - struct iucv_event ev; + struct iucv_connection *conn = path->private; - ev.conn = conn; - ev.data = (void *)eib; - fsm_event(conn->fsm, CONN_EVENT_CONN_SUS, &ev); + fsm_event(conn->fsm, CONN_EVENT_CONN_SUS, conn); } -static void -netiucv_callback_connres(iucv_ConnectionResumed *eib, void *pgm_data) +static void netiucv_callback_connres(struct iucv_path *path, u8 ipuser[16]) { - struct iucv_connection *conn = (struct iucv_connection *)pgm_data; - struct iucv_event ev; + struct iucv_connection *conn = path->private; - ev.conn = conn; - ev.data = (void *)eib; - fsm_event(conn->fsm, CONN_EVENT_CONN_RES, &ev); -} - -static iucv_interrupt_ops_t netiucv_ops = { - .ConnectionPending = netiucv_callback_connreq, - .ConnectionComplete = netiucv_callback_connack, - .ConnectionSevered = netiucv_callback_connrej, - .ConnectionQuiesced = netiucv_callback_connsusp, - .ConnectionResumed = netiucv_callback_connres, - .MessagePending = netiucv_callback_rx, - .MessageComplete = netiucv_callback_txdone -}; + fsm_event(conn->fsm, CONN_EVENT_CONN_RES, conn); +} /** * Dummy NOP action for all statemachines */ -static void -fsm_action_nop(fsm_instance *fi, int event, void *arg) +static void fsm_action_nop(fsm_instance *fi, int event, void *arg) { } -/** +/* * Actions of the connection statemachine - *****************************************************************************/ + */ /** - * Helper function for conn_action_rx() - * Unpack a just received skb and hand it over to - * upper layers. + * netiucv_unpack_skb + * @conn: The connection where this skb has been received. + * @pskb: The received skb. * - * @param conn The connection where this skb has been received. - * @param pskb The received skb. + * Unpack a just received skb and hand it over to upper layers. + * Helper function for conn_action_rx. */ -//static __inline__ void -static void -netiucv_unpack_skb(struct iucv_connection *conn, struct sk_buff *pskb) +static void netiucv_unpack_skb(struct iucv_connection *conn, + struct sk_buff *pskb) { struct net_device *dev = conn->netdev; - struct netiucv_priv *privptr = dev->priv; - __u16 offset = 0; + struct netiucv_priv *privptr = netdev_priv(dev); + u16 offset = 0; skb_put(pskb, NETIUCV_HDRLEN); pskb->dev = dev; @@ -549,7 +617,7 @@ netiucv_unpack_skb(struct iucv_connectio while (1) { struct sk_buff *skb; - ll_header *header = (ll_header *)pskb->data; + struct ll_header *header = (struct ll_header *) pskb->data; if (!header->next) break; @@ -595,40 +663,37 @@ netiucv_unpack_skb(struct iucv_connectio } } -static void -conn_action_rx(fsm_instance *fi, int event, void *arg) +static void conn_action_rx(fsm_instance *fi, int event, void *arg) { - struct iucv_event *ev = (struct iucv_event *)arg; + struct iucv_event *ev = arg; struct iucv_connection *conn = ev->conn; - iucv_MessagePending *eib = (iucv_MessagePending *)ev->data; - struct netiucv_priv *privptr =(struct netiucv_priv *)conn->netdev->priv; - - __u32 msglen = eib->ln1msg2.ipbfln1f; + struct iucv_message *msg = ev->data; + struct netiucv_priv *privptr = netdev_priv(conn->netdev); int rc; IUCV_DBF_TEXT(trace, 4, __FUNCTION__); if (!conn->netdev) { - /* FRITZ: How to tell iucv LL to drop the msg? */ + iucv_message_reject(conn->path, msg); PRINT_WARN("Received data for unlinked connection\n"); IUCV_DBF_TEXT(data, 2, - "Received data for unlinked connection\n"); + "Received data for unlinked connection\n"); return; } - if (msglen > conn->max_buffsize) { - /* FRITZ: How to tell iucv LL to drop the msg? */ + if (msg->length > conn->max_buffsize) { + iucv_message_reject(conn->path, msg); privptr->stats.rx_dropped++; PRINT_WARN("msglen %d > max_buffsize %d\n", - msglen, conn->max_buffsize); + msg->length, conn->max_buffsize); IUCV_DBF_TEXT_(data, 2, "msglen %d > max_buffsize %d\n", - msglen, conn->max_buffsize); + msg->length, conn->max_buffsize); return; } conn->rx_buff->data = conn->rx_buff->tail = conn->rx_buff->head; conn->rx_buff->len = 0; - rc = iucv_receive(conn->pathid, eib->ipmsgid, eib->iptrgcls, - conn->rx_buff->data, msglen, NULL, NULL, NULL); - if (rc || msglen < 5) { + rc = iucv_message_receive(conn->path, msg, 0, conn->rx_buff->data, + msg->length, NULL); + if (rc || msg->length < 5) { privptr->stats.rx_errors++; PRINT_WARN("iucv_receive returned %08x\n", rc); IUCV_DBF_TEXT_(data, 2, "rc %d from iucv_receive\n", rc); @@ -637,26 +702,26 @@ conn_action_rx(fsm_instance *fi, int eve netiucv_unpack_skb(conn, conn->rx_buff); } -static void -conn_action_txdone(fsm_instance *fi, int event, void *arg) +static void conn_action_txdone(fsm_instance *fi, int event, void *arg) { - struct iucv_event *ev = (struct iucv_event *)arg; + struct iucv_event *ev = arg; struct iucv_connection *conn = ev->conn; - iucv_MessageComplete *eib = (iucv_MessageComplete *)ev->data; + struct iucv_message *msg = ev->data; + struct iucv_message txmsg; struct netiucv_priv *privptr = NULL; - /* Shut up, gcc! skb is always below 2G. */ - __u32 single_flag = eib->ipmsgtag; - __u32 txbytes = 0; - __u32 txpackets = 0; - __u32 stat_maxcq = 0; + u32 single_flag = msg->tag; + u32 txbytes = 0; + u32 txpackets = 0; + u32 stat_maxcq = 0; struct sk_buff *skb; unsigned long saveflags; - ll_header header; + struct ll_header header; + int rc; IUCV_DBF_TEXT(trace, 4, __FUNCTION__); - if (conn && conn->netdev && conn->netdev->priv) - privptr = (struct netiucv_priv *)conn->netdev->priv; + if (conn && conn->netdev) + privptr = netdev_priv(conn->netdev); conn->prof.tx_pending--; if (single_flag) { if ((skb = skb_dequeue(&conn->commit_queue))) { @@ -688,56 +753,55 @@ conn_action_txdone(fsm_instance *fi, int conn->prof.maxmulti = conn->collect_len; conn->collect_len = 0; spin_unlock_irqrestore(&conn->collect_lock, saveflags); - if (conn->tx_buff->len) { - int rc; - - header.next = 0; - memcpy(skb_put(conn->tx_buff, NETIUCV_HDRLEN), &header, - NETIUCV_HDRLEN); + if (conn->tx_buff->len == 0) { + fsm_newstate(fi, CONN_STATE_IDLE); + return; + } - conn->prof.send_stamp = xtime; - rc = iucv_send(conn->pathid, NULL, 0, 0, 0, 0, + header.next = 0; + memcpy(skb_put(conn->tx_buff, NETIUCV_HDRLEN), &header, NETIUCV_HDRLEN); + conn->prof.send_stamp = xtime; + txmsg.class = 0; + txmsg.tag = 0; + rc = iucv_message_send(conn->path, &txmsg, 0, 0, conn->tx_buff->data, conn->tx_buff->len); - conn->prof.doios_multi++; - conn->prof.txlen += conn->tx_buff->len; - conn->prof.tx_pending++; - if (conn->prof.tx_pending > conn->prof.tx_max_pending) - conn->prof.tx_max_pending = conn->prof.tx_pending; - if (rc) { - conn->prof.tx_pending--; - fsm_newstate(fi, CONN_STATE_IDLE); - if (privptr) - privptr->stats.tx_errors += txpackets; - PRINT_WARN("iucv_send returned %08x\n", rc); - IUCV_DBF_TEXT_(data, 2, "rc %d from iucv_send\n", rc); - } else { - if (privptr) { - privptr->stats.tx_packets += txpackets; - privptr->stats.tx_bytes += txbytes; - } - if (stat_maxcq > conn->prof.maxcqueue) - conn->prof.maxcqueue = stat_maxcq; - } - } else + conn->prof.doios_multi++; + conn->prof.txlen += conn->tx_buff->len; + conn->prof.tx_pending++; + if (conn->prof.tx_pending > conn->prof.tx_max_pending) + conn->prof.tx_max_pending = conn->prof.tx_pending; + if (rc) { + conn->prof.tx_pending--; fsm_newstate(fi, CONN_STATE_IDLE); + if (privptr) + privptr->stats.tx_errors += txpackets; + PRINT_WARN("iucv_send returned %08x\n", rc); + IUCV_DBF_TEXT_(data, 2, "rc %d from iucv_send\n", rc); + } else { + if (privptr) { + privptr->stats.tx_packets += txpackets; + privptr->stats.tx_bytes += txbytes; + } + if (stat_maxcq > conn->prof.maxcqueue) + conn->prof.maxcqueue = stat_maxcq; + } } -static void -conn_action_connaccept(fsm_instance *fi, int event, void *arg) +static void conn_action_connaccept(fsm_instance *fi, int event, void *arg) { - struct iucv_event *ev = (struct iucv_event *)arg; + struct iucv_event *ev = arg; struct iucv_connection *conn = ev->conn; - iucv_ConnectionPending *eib = (iucv_ConnectionPending *)ev->data; + struct iucv_path *path = ev->data; struct net_device *netdev = conn->netdev; - struct netiucv_priv *privptr = (struct netiucv_priv *)netdev->priv; + struct netiucv_priv *privptr = netdev_priv(netdev); int rc; - __u16 msglimit; - __u8 udata[16]; IUCV_DBF_TEXT(trace, 3, __FUNCTION__); - rc = iucv_accept(eib->ippathid, NETIUCV_QUEUELEN_DEFAULT, udata, 0, - conn->handle, conn, NULL, &msglimit); + conn->path = path; + path->msglim = NETIUCV_QUEUELEN_DEFAULT; + path->flags = 0; + rc = iucv_path_accept(path, &netiucv_handler, NULL, conn); if (rc) { PRINT_WARN("%s: IUCV accept failed with error %d\n", netdev->name, rc); @@ -745,183 +809,126 @@ conn_action_connaccept(fsm_instance *fi, return; } fsm_newstate(fi, CONN_STATE_IDLE); - conn->pathid = eib->ippathid; - netdev->tx_queue_len = msglimit; + netdev->tx_queue_len = conn->path->msglim; fsm_event(privptr->fsm, DEV_EVENT_CONUP, netdev); } -static void -conn_action_connreject(fsm_instance *fi, int event, void *arg) +static void conn_action_connreject(fsm_instance *fi, int event, void *arg) { - struct iucv_event *ev = (struct iucv_event *)arg; - struct iucv_connection *conn = ev->conn; - struct net_device *netdev = conn->netdev; - iucv_ConnectionPending *eib = (iucv_ConnectionPending *)ev->data; - __u8 udata[16]; + struct iucv_event *ev = arg; + struct iucv_path *path = ev->data; IUCV_DBF_TEXT(trace, 3, __FUNCTION__); - - iucv_sever(eib->ippathid, udata); - if (eib->ippathid != conn->pathid) { - PRINT_INFO("%s: IR Connection Pending; " - "pathid %d does not match original pathid %d\n", - netdev->name, eib->ippathid, conn->pathid); - IUCV_DBF_TEXT_(data, 2, - "connreject: IR pathid %d, conn. pathid %d\n", - eib->ippathid, conn->pathid); - iucv_sever(conn->pathid, udata); - } + iucv_path_sever(path, NULL); } -static void -conn_action_connack(fsm_instance *fi, int event, void *arg) +static void conn_action_connack(fsm_instance *fi, int event, void *arg) { - struct iucv_event *ev = (struct iucv_event *)arg; - struct iucv_connection *conn = ev->conn; - iucv_ConnectionComplete *eib = (iucv_ConnectionComplete *)ev->data; + struct iucv_connection *conn = arg; struct net_device *netdev = conn->netdev; - struct netiucv_priv *privptr = (struct netiucv_priv *)netdev->priv; + struct netiucv_priv *privptr = netdev_priv(netdev); IUCV_DBF_TEXT(trace, 3, __FUNCTION__); - fsm_deltimer(&conn->timer); fsm_newstate(fi, CONN_STATE_IDLE); - if (eib->ippathid != conn->pathid) { - PRINT_INFO("%s: IR Connection Complete; " - "pathid %d does not match original pathid %d\n", - netdev->name, eib->ippathid, conn->pathid); - IUCV_DBF_TEXT_(data, 2, - "connack: IR pathid %d, conn. pathid %d\n", - eib->ippathid, conn->pathid); - conn->pathid = eib->ippathid; - } - netdev->tx_queue_len = eib->ipmsglim; + netdev->tx_queue_len = conn->path->msglim; fsm_event(privptr->fsm, DEV_EVENT_CONUP, netdev); } -static void -conn_action_conntimsev(fsm_instance *fi, int event, void *arg) +static void conn_action_conntimsev(fsm_instance *fi, int event, void *arg) { - struct iucv_connection *conn = (struct iucv_connection *)arg; - __u8 udata[16]; + struct iucv_connection *conn = arg; IUCV_DBF_TEXT(trace, 3, __FUNCTION__); - fsm_deltimer(&conn->timer); - iucv_sever(conn->pathid, udata); + iucv_path_sever(conn->path, NULL); fsm_newstate(fi, CONN_STATE_STARTWAIT); } -static void -conn_action_connsever(fsm_instance *fi, int event, void *arg) +static void conn_action_connsever(fsm_instance *fi, int event, void *arg) { - struct iucv_event *ev = (struct iucv_event *)arg; - struct iucv_connection *conn = ev->conn; + struct iucv_connection *conn = arg; struct net_device *netdev = conn->netdev; - struct netiucv_priv *privptr = (struct netiucv_priv *)netdev->priv; - __u8 udata[16]; + struct netiucv_priv *privptr = netdev_priv(netdev); IUCV_DBF_TEXT(trace, 3, __FUNCTION__); fsm_deltimer(&conn->timer); - iucv_sever(conn->pathid, udata); + iucv_path_sever(conn->path, NULL); PRINT_INFO("%s: Remote dropped connection\n", netdev->name); IUCV_DBF_TEXT(data, 2, - "conn_action_connsever: Remote dropped connection\n"); + "conn_action_connsever: Remote dropped connection\n"); fsm_newstate(fi, CONN_STATE_STARTWAIT); fsm_event(privptr->fsm, DEV_EVENT_CONDOWN, netdev); } -static void -conn_action_start(fsm_instance *fi, int event, void *arg) +static void conn_action_start(fsm_instance *fi, int event, void *arg) { - struct iucv_event *ev = (struct iucv_event *)arg; - struct iucv_connection *conn = ev->conn; - __u16 msglimit; + struct iucv_connection *conn = arg; int rc; IUCV_DBF_TEXT(trace, 3, __FUNCTION__); - if (!conn->handle) { - IUCV_DBF_TEXT(trace, 5, "calling iucv_register_program\n"); - conn->handle = - iucv_register_program(iucvMagic, conn->userid, - netiucv_mask, - &netiucv_ops, conn); - fsm_newstate(fi, CONN_STATE_STARTWAIT); - if (!conn->handle) { - fsm_newstate(fi, CONN_STATE_REGERR); - conn->handle = NULL; - IUCV_DBF_TEXT(setup, 2, - "NULL from iucv_register_program\n"); - return; - } - - PRINT_DEBUG("%s('%s'): registered successfully\n", - conn->netdev->name, conn->userid); - } - + fsm_newstate(fi, CONN_STATE_STARTWAIT); PRINT_DEBUG("%s('%s'): connecting ...\n", - conn->netdev->name, conn->userid); + conn->netdev->name, conn->userid); - /* We must set the state before calling iucv_connect because the callback - * handler could be called at any point after the connection request is - * sent */ + /* + * We must set the state before calling iucv_connect because the + * callback handler could be called at any point after the connection + * request is sent + */ fsm_newstate(fi, CONN_STATE_SETUPWAIT); - rc = iucv_connect(&(conn->pathid), NETIUCV_QUEUELEN_DEFAULT, iucvMagic, - conn->userid, iucv_host, 0, NULL, &msglimit, - conn->handle, conn); + conn->path = iucv_path_alloc(NETIUCV_QUEUELEN_DEFAULT, 0, GFP_KERNEL); + rc = iucv_path_connect(conn->path, &netiucv_handler, conn->userid, + NULL, iucvMagic, conn); switch (rc) { - case 0: - conn->netdev->tx_queue_len = msglimit; - fsm_addtimer(&conn->timer, NETIUCV_TIMEOUT_5SEC, - CONN_EVENT_TIMER, conn); - return; - case 11: - PRINT_INFO("%s: User %s is currently not available.\n", - conn->netdev->name, - netiucv_printname(conn->userid)); - fsm_newstate(fi, CONN_STATE_STARTWAIT); - return; - case 12: - PRINT_INFO("%s: User %s is currently not ready.\n", - conn->netdev->name, - netiucv_printname(conn->userid)); - fsm_newstate(fi, CONN_STATE_STARTWAIT); - return; - case 13: - PRINT_WARN("%s: Too many IUCV connections.\n", - conn->netdev->name); - fsm_newstate(fi, CONN_STATE_CONNERR); - break; - case 14: - PRINT_WARN( - "%s: User %s has too many IUCV connections.\n", - conn->netdev->name, - netiucv_printname(conn->userid)); - fsm_newstate(fi, CONN_STATE_CONNERR); - break; - case 15: - PRINT_WARN( - "%s: No IUCV authorization in CP directory.\n", - conn->netdev->name); - fsm_newstate(fi, CONN_STATE_CONNERR); - break; - default: - PRINT_WARN("%s: iucv_connect returned error %d\n", - conn->netdev->name, rc); - fsm_newstate(fi, CONN_STATE_CONNERR); - break; + case 0: + conn->netdev->tx_queue_len = conn->path->msglim; + fsm_addtimer(&conn->timer, NETIUCV_TIMEOUT_5SEC, + CONN_EVENT_TIMER, conn); + return; + case 11: + PRINT_INFO("%s: User %s is currently not available.\n", + conn->netdev->name, + netiucv_printname(conn->userid)); + fsm_newstate(fi, CONN_STATE_STARTWAIT); + break; + case 12: + PRINT_INFO("%s: User %s is currently not ready.\n", + conn->netdev->name, + netiucv_printname(conn->userid)); + fsm_newstate(fi, CONN_STATE_STARTWAIT); + break; + case 13: + PRINT_WARN("%s: Too many IUCV connections.\n", + conn->netdev->name); + fsm_newstate(fi, CONN_STATE_CONNERR); + break; + case 14: + PRINT_WARN("%s: User %s has too many IUCV connections.\n", + conn->netdev->name, + netiucv_printname(conn->userid)); + fsm_newstate(fi, CONN_STATE_CONNERR); + break; + case 15: + PRINT_WARN("%s: No IUCV authorization in CP directory.\n", + conn->netdev->name); + fsm_newstate(fi, CONN_STATE_CONNERR); + break; + default: + PRINT_WARN("%s: iucv_connect returned error %d\n", + conn->netdev->name, rc); + fsm_newstate(fi, CONN_STATE_CONNERR); + break; } IUCV_DBF_TEXT_(setup, 5, "iucv_connect rc is %d\n", rc); - IUCV_DBF_TEXT(trace, 5, "calling iucv_unregister_program\n"); - iucv_unregister_program(conn->handle); - conn->handle = NULL; + kfree(conn->path); + conn->path = NULL; } -static void -netiucv_purge_skb_queue(struct sk_buff_head *q) +static void netiucv_purge_skb_queue(struct sk_buff_head *q) { struct sk_buff *skb; @@ -931,36 +938,34 @@ netiucv_purge_skb_queue(struct sk_buff_h } } -static void -conn_action_stop(fsm_instance *fi, int event, void *arg) +static void conn_action_stop(fsm_instance *fi, int event, void *arg) { - struct iucv_event *ev = (struct iucv_event *)arg; + struct iucv_event *ev = arg; struct iucv_connection *conn = ev->conn; struct net_device *netdev = conn->netdev; - struct netiucv_priv *privptr = (struct netiucv_priv *)netdev->priv; + struct netiucv_priv *privptr = netdev_priv(netdev); IUCV_DBF_TEXT(trace, 3, __FUNCTION__); fsm_deltimer(&conn->timer); fsm_newstate(fi, CONN_STATE_STOPPED); netiucv_purge_skb_queue(&conn->collect_queue); - if (conn->handle) - IUCV_DBF_TEXT(trace, 5, "calling iucv_unregister_program\n"); - iucv_unregister_program(conn->handle); - conn->handle = NULL; + if (conn->path) { + IUCV_DBF_TEXT(trace, 5, "calling iucv_path_sever\n"); + iucv_path_sever(conn->path, iucvMagic); + kfree(conn->path); + conn->path = NULL; + } netiucv_purge_skb_queue(&conn->commit_queue); fsm_event(privptr->fsm, DEV_EVENT_CONDOWN, netdev); } -static void -conn_action_inval(fsm_instance *fi, int event, void *arg) +static void conn_action_inval(fsm_instance *fi, int event, void *arg) { - struct iucv_event *ev = (struct iucv_event *)arg; - struct iucv_connection *conn = ev->conn; + struct iucv_connection *conn = arg; struct net_device *netdev = conn->netdev; - PRINT_WARN("%s: Cannot connect without username\n", - netdev->name); + PRINT_WARN("%s: Cannot connect without username\n", netdev->name); IUCV_DBF_TEXT(data, 2, "conn_action_inval called\n"); } @@ -999,29 +1004,27 @@ static const fsm_node conn_fsm[] = { static const int CONN_FSM_LEN = sizeof(conn_fsm) / sizeof(fsm_node); -/** +/* * Actions for interface - statemachine. - *****************************************************************************/ + */ /** - * Startup connection by sending CONN_EVENT_START to it. + * dev_action_start + * @fi: An instance of an interface statemachine. + * @event: The event, just happened. + * @arg: Generic pointer, casted from struct net_device * upon call. * - * @param fi An instance of an interface statemachine. - * @param event The event, just happened. - * @param arg Generic pointer, casted from struct net_device * upon call. + * Startup connection by sending CONN_EVENT_START to it. */ -static void -dev_action_start(fsm_instance *fi, int event, void *arg) +static void dev_action_start(fsm_instance *fi, int event, void *arg) { - struct net_device *dev = (struct net_device *)arg; - struct netiucv_priv *privptr = dev->priv; - struct iucv_event ev; + struct net_device *dev = arg; + struct netiucv_priv *privptr = netdev_priv(dev); IUCV_DBF_TEXT(trace, 3, __FUNCTION__); - ev.conn = privptr->conn; fsm_newstate(fi, DEV_STATE_STARTWAIT); - fsm_event(privptr->conn->fsm, CONN_EVENT_START, &ev); + fsm_event(privptr->conn->fsm, CONN_EVENT_START, privptr->conn); } /** @@ -1034,8 +1037,8 @@ dev_action_start(fsm_instance *fi, int e static void dev_action_stop(fsm_instance *fi, int event, void *arg) { - struct net_device *dev = (struct net_device *)arg; - struct netiucv_priv *privptr = dev->priv; + struct net_device *dev = arg; + struct netiucv_priv *privptr = netdev_priv(dev); struct iucv_event ev; IUCV_DBF_TEXT(trace, 3, __FUNCTION__); @@ -1057,8 +1060,8 @@ dev_action_stop(fsm_instance *fi, int ev static void dev_action_connup(fsm_instance *fi, int event, void *arg) { - struct net_device *dev = (struct net_device *)arg; - struct netiucv_priv *privptr = dev->priv; + struct net_device *dev = arg; + struct netiucv_priv *privptr = netdev_priv(dev); IUCV_DBF_TEXT(trace, 3, __FUNCTION__); @@ -1131,11 +1134,13 @@ static const int DEV_FSM_LEN = sizeof(de * * @return 0 on success, -ERRNO on failure. (Never fails.) */ -static int -netiucv_transmit_skb(struct iucv_connection *conn, struct sk_buff *skb) { +static int netiucv_transmit_skb(struct iucv_connection *conn, + struct sk_buff *skb) +{ + struct iucv_message msg; unsigned long saveflags; - ll_header header; - int rc = 0; + struct ll_header header; + int rc; if (fsm_getstate(conn->fsm) != CONN_STATE_IDLE) { int l = skb->len + NETIUCV_HDRLEN; @@ -1145,11 +1150,12 @@ netiucv_transmit_skb(struct iucv_connect (conn->max_buffsize - NETIUCV_HDRLEN)) { rc = -EBUSY; IUCV_DBF_TEXT(data, 2, - "EBUSY from netiucv_transmit_skb\n"); + "EBUSY from netiucv_transmit_skb\n"); } else { atomic_inc(&skb->users); skb_queue_tail(&conn->collect_queue, skb); conn->collect_len += l; + rc = 0; } spin_unlock_irqrestore(&conn->collect_lock, saveflags); } else { @@ -1188,9 +1194,10 @@ netiucv_transmit_skb(struct iucv_connect fsm_newstate(conn->fsm, CONN_STATE_TX); conn->prof.send_stamp = xtime; - rc = iucv_send(conn->pathid, NULL, 0, 0, 1 /* single_flag */, - 0, nskb->data, nskb->len); - /* Shut up, gcc! nskb is always below 2G. */ + msg.tag = 1; + msg.class = 0; + rc = iucv_message_send(conn->path, &msg, 0, 0, + nskb->data, nskb->len); conn->prof.doios_single++; conn->prof.txlen += skb->len; conn->prof.tx_pending++; @@ -1200,7 +1207,7 @@ netiucv_transmit_skb(struct iucv_connect struct netiucv_priv *privptr; fsm_newstate(conn->fsm, CONN_STATE_IDLE); conn->prof.tx_pending--; - privptr = (struct netiucv_priv *)conn->netdev->priv; + privptr = netdev_priv(conn->netdev); if (privptr) privptr->stats.tx_errors++; if (copied) @@ -1226,9 +1233,9 @@ netiucv_transmit_skb(struct iucv_connect return rc; } -/** +/* * Interface API for upper network layers - *****************************************************************************/ + */ /** * Open an interface. @@ -1238,9 +1245,11 @@ netiucv_transmit_skb(struct iucv_connect * * @return 0 on success, -ERRNO on failure. (Never fails.) */ -static int -netiucv_open(struct net_device *dev) { - fsm_event(((struct netiucv_priv *)dev->priv)->fsm, DEV_EVENT_START,dev); +static int netiucv_open(struct net_device *dev) +{ + struct netiucv_priv *priv = netdev_priv(dev); + + fsm_event(priv->fsm, DEV_EVENT_START, dev); return 0; } @@ -1252,9 +1261,11 @@ netiucv_open(struct net_device *dev) { * * @return 0 on success, -ERRNO on failure. (Never fails.) */ -static int -netiucv_close(struct net_device *dev) { - fsm_event(((struct netiucv_priv *)dev->priv)->fsm, DEV_EVENT_STOP, dev); +static int netiucv_close(struct net_device *dev) +{ + struct netiucv_priv *priv = netdev_priv(dev); + + fsm_event(priv->fsm, DEV_EVENT_STOP, dev); return 0; } @@ -1271,8 +1282,8 @@ netiucv_close(struct net_device *dev) { */ static int netiucv_tx(struct sk_buff *skb, struct net_device *dev) { - int rc = 0; - struct netiucv_priv *privptr = dev->priv; + struct netiucv_priv *privptr = netdev_priv(dev); + int rc; IUCV_DBF_TEXT(trace, 4, __FUNCTION__); /** @@ -1312,40 +1323,41 @@ static int netiucv_tx(struct sk_buff *sk return -EBUSY; } dev->trans_start = jiffies; - if (netiucv_transmit_skb(privptr->conn, skb)) - rc = 1; + rc = netiucv_transmit_skb(privptr->conn, skb) != 0; netiucv_clear_busy(dev); return rc; } /** - * Returns interface statistics of a device. + * netiucv_stats + * @dev: Pointer to interface struct. * - * @param dev Pointer to interface struct. + * Returns interface statistics of a device. * - * @return Pointer to stats struct of this interface. + * Returns pointer to stats struct of this interface. */ -static struct net_device_stats * -netiucv_stats (struct net_device * dev) +static struct net_device_stats *netiucv_stats (struct net_device * dev) { + struct netiucv_priv *priv = netdev_priv(dev); + IUCV_DBF_TEXT(trace, 5, __FUNCTION__); - return &((struct netiucv_priv *)dev->priv)->stats; + return &priv->stats; } /** - * Sets MTU of an interface. + * netiucv_change_mtu + * @dev: Pointer to interface struct. + * @new_mtu: The new MTU to use for this interface. * - * @param dev Pointer to interface struct. - * @param new_mtu The new MTU to use for this interface. + * Sets MTU of an interface. * - * @return 0 on success, -EINVAL if MTU is out of valid range. + * Returns 0 on success, -EINVAL if MTU is out of valid range. * (valid range is 576 .. NETIUCV_MTU_MAX). */ -static int -netiucv_change_mtu (struct net_device * dev, int new_mtu) +static int netiucv_change_mtu(struct net_device * dev, int new_mtu) { IUCV_DBF_TEXT(trace, 3, __FUNCTION__); - if ((new_mtu < 576) || (new_mtu > NETIUCV_MTU_MAX)) { + if (new_mtu < 576 || new_mtu > NETIUCV_MTU_MAX) { IUCV_DBF_TEXT(setup, 2, "given MTU out of valid range\n"); return -EINVAL; } @@ -1353,12 +1365,12 @@ netiucv_change_mtu (struct net_device * return 0; } -/** +/* * attributes in sysfs - *****************************************************************************/ + */ -static ssize_t -user_show (struct device *dev, struct device_attribute *attr, char *buf) +static ssize_t user_show(struct device *dev, struct device_attribute *attr, + char *buf) { struct netiucv_priv *priv = dev->driver_data; @@ -1366,8 +1378,8 @@ user_show (struct device *dev, struct de return sprintf(buf, "%s\n", netiucv_printname(priv->conn->userid)); } -static ssize_t -user_write (struct device *dev, struct device_attribute *attr, const char *buf, size_t count) +static ssize_t user_write(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) { struct netiucv_priv *priv = dev->driver_data; struct net_device *ndev = priv->conn->netdev; @@ -1375,80 +1387,70 @@ user_write (struct device *dev, struct d char *tmp; char username[9]; int i; - struct iucv_connection **clist = &iucv_conns.iucv_connections; - unsigned long flags; + struct iucv_connection *cp; IUCV_DBF_TEXT(trace, 3, __FUNCTION__); - if (count>9) { - PRINT_WARN("netiucv: username too long (%d)!\n", (int)count); + if (count > 9) { + PRINT_WARN("netiucv: username too long (%d)!\n", (int) count); IUCV_DBF_TEXT_(setup, 2, - "%d is length of username\n", (int)count); + "%d is length of username\n", (int) count); return -EINVAL; } tmp = strsep((char **) &buf, "\n"); - for (i=0, p=tmp; i<8 && *p; i++, p++) { - if (isalnum(*p) || (*p == '$')) + for (i = 0, p = tmp; i < 8 && *p; i++, p++) { + if (isalnum(*p) || (*p == '$')) { username[i]= toupper(*p); - else if (*p == '\n') { + continue; + } + if (*p == '\n') { /* trailing lf, grr */ break; - } else { - PRINT_WARN("netiucv: Invalid char %c in username!\n", - *p); - IUCV_DBF_TEXT_(setup, 2, - "username: invalid character %c\n", - *p); - return -EINVAL; } + PRINT_WARN("netiucv: Invalid char %c in username!\n", *p); + IUCV_DBF_TEXT_(setup, 2, + "username: invalid character %c\n", *p); + return -EINVAL; } - while (i<8) + while (i < 8) username[i++] = ' '; username[8] = '\0'; - if (memcmp(username, priv->conn->userid, 9)) { - /* username changed */ - if (ndev->flags & (IFF_UP | IFF_RUNNING)) { - PRINT_WARN( - "netiucv: device %s active, connected to %s\n", - dev->bus_id, priv->conn->userid); - PRINT_WARN("netiucv: user cannot be updated\n"); - IUCV_DBF_TEXT(setup, 2, "user_write: device active\n"); - return -EBUSY; + if (memcmp(username, priv->conn->userid, 9) && + (ndev->flags & (IFF_UP | IFF_RUNNING))) { + /* username changed while the interface is active. */ + PRINT_WARN("netiucv: device %s active, connected to %s\n", + dev->bus_id, priv->conn->userid); + PRINT_WARN("netiucv: user cannot be updated\n"); + IUCV_DBF_TEXT(setup, 2, "user_write: device active\n"); + return -EBUSY; + } + read_lock_bh(&iucv_connection_rwlock); + list_for_each_entry(cp, &iucv_connection_list, list) { + if (!strncmp(username, cp->userid, 9) && cp->netdev != ndev) { + read_unlock_bh(&iucv_connection_rwlock); + PRINT_WARN("netiucv: Connection to %s already " + "exists\n", username); + return -EEXIST; } } - read_lock_irqsave(&iucv_conns.iucv_rwlock, flags); - while (*clist) { - if (!strncmp(username, (*clist)->userid, 9) || - ((*clist)->netdev != ndev)) - break; - clist = &((*clist)->next); - } - read_unlock_irqrestore(&iucv_conns.iucv_rwlock, flags); - if (*clist) { - PRINT_WARN("netiucv: Connection to %s already exists\n", - username); - return -EEXIST; - } + read_unlock_bh(&iucv_connection_rwlock); memcpy(priv->conn->userid, username, 9); - return count; - } static DEVICE_ATTR(user, 0644, user_show, user_write); -static ssize_t -buffer_show (struct device *dev, struct device_attribute *attr, char *buf) -{ - struct netiucv_priv *priv = dev->driver_data; +static ssize_t buffer_show (struct device *dev, struct device_attribute *attr, + char *buf) +{ struct netiucv_priv *priv = dev->driver_data; IUCV_DBF_TEXT(trace, 5, __FUNCTION__); return sprintf(buf, "%d\n", priv->conn->max_buffsize); } -static ssize_t -buffer_write (struct device *dev, struct device_attribute *attr, const char *buf, size_t count) +static ssize_t buffer_write (struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) { struct netiucv_priv *priv = dev->driver_data; struct net_device *ndev = priv->conn->netdev; @@ -1502,8 +1504,8 @@ buffer_write (struct device *dev, struct static DEVICE_ATTR(buffer, 0644, buffer_show, buffer_write); -static ssize_t -dev_fsm_show (struct device *dev, struct device_attribute *attr, char *buf) +static ssize_t dev_fsm_show (struct device *dev, struct device_attribute *attr, + char *buf) { struct netiucv_priv *priv = dev->driver_data; @@ -1513,8 +1515,8 @@ dev_fsm_show (struct device *dev, struct static DEVICE_ATTR(device_fsm_state, 0444, dev_fsm_show, NULL); -static ssize_t -conn_fsm_show (struct device *dev, struct device_attribute *attr, char *buf) +static ssize_t conn_fsm_show (struct device *dev, + struct device_attribute *attr, char *buf) { struct netiucv_priv *priv = dev->driver_data; @@ -1524,8 +1526,8 @@ conn_fsm_show (struct device *dev, struc static DEVICE_ATTR(connection_fsm_state, 0444, conn_fsm_show, NULL); -static ssize_t -maxmulti_show (struct device *dev, struct device_attribute *attr, char *buf) +static ssize_t maxmulti_show (struct device *dev, + struct device_attribute *attr, char *buf) { struct netiucv_priv *priv = dev->driver_data; @@ -1533,8 +1535,9 @@ maxmulti_show (struct device *dev, struc return sprintf(buf, "%ld\n", priv->conn->prof.maxmulti); } -static ssize_t -maxmulti_write (struct device *dev, struct device_attribute *attr, const char *buf, size_t count) +static ssize_t maxmulti_write (struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) { struct netiucv_priv *priv = dev->driver_data; @@ -1545,8 +1548,8 @@ maxmulti_write (struct device *dev, stru static DEVICE_ATTR(max_tx_buffer_used, 0644, maxmulti_show, maxmulti_write); -static ssize_t -maxcq_show (struct device *dev, struct device_attribute *attr, char *buf) +static ssize_t maxcq_show (struct device *dev, struct device_attribute *attr, + char *buf) { struct netiucv_priv *priv = dev->driver_data; @@ -1554,8 +1557,8 @@ maxcq_show (struct device *dev, struct d return sprintf(buf, "%ld\n", priv->conn->prof.maxcqueue); } -static ssize_t -maxcq_write (struct device *dev, struct device_attribute *attr, const char *buf, size_t count) +static ssize_t maxcq_write (struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) { struct netiucv_priv *priv = dev->driver_data; @@ -1566,8 +1569,8 @@ maxcq_write (struct device *dev, struct static DEVICE_ATTR(max_chained_skbs, 0644, maxcq_show, maxcq_write); -static ssize_t -sdoio_show (struct device *dev, struct device_attribute *attr, char *buf) +static ssize_t sdoio_show (struct device *dev, struct device_attribute *attr, + char *buf) { struct netiucv_priv *priv = dev->driver_data; @@ -1575,8 +1578,8 @@ sdoio_show (struct device *dev, struct d return sprintf(buf, "%ld\n", priv->conn->prof.doios_single); } -static ssize_t -sdoio_write (struct device *dev, struct device_attribute *attr, const char *buf, size_t count) +static ssize_t sdoio_write (struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) { struct netiucv_priv *priv = dev->driver_data; @@ -1587,8 +1590,8 @@ sdoio_write (struct device *dev, struct static DEVICE_ATTR(tx_single_write_ops, 0644, sdoio_show, sdoio_write); -static ssize_t -mdoio_show (struct device *dev, struct device_attribute *attr, char *buf) +static ssize_t mdoio_show (struct device *dev, struct device_attribute *attr, + char *buf) { struct netiucv_priv *priv = dev->driver_data; @@ -1596,8 +1599,8 @@ mdoio_show (struct device *dev, struct d return sprintf(buf, "%ld\n", priv->conn->prof.doios_multi); } -static ssize_t -mdoio_write (struct device *dev, struct device_attribute *attr, const char *buf, size_t count) +static ssize_t mdoio_write (struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) { struct netiucv_priv *priv = dev->driver_data; @@ -1608,8 +1611,8 @@ mdoio_write (struct device *dev, struct static DEVICE_ATTR(tx_multi_write_ops, 0644, mdoio_show, mdoio_write); -static ssize_t -txlen_show (struct device *dev, struct device_attribute *attr, char *buf) +static ssize_t txlen_show (struct device *dev, struct device_attribute *attr, + char *buf) { struct netiucv_priv *priv = dev->driver_data; @@ -1617,8 +1620,8 @@ txlen_show (struct device *dev, struct d return sprintf(buf, "%ld\n", priv->conn->prof.txlen); } -static ssize_t -txlen_write (struct device *dev, struct device_attribute *attr, const char *buf, size_t count) +static ssize_t txlen_write (struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) { struct netiucv_priv *priv = dev->driver_data; @@ -1629,8 +1632,8 @@ txlen_write (struct device *dev, struct static DEVICE_ATTR(netto_bytes, 0644, txlen_show, txlen_write); -static ssize_t -txtime_show (struct device *dev, struct device_attribute *attr, char *buf) +static ssize_t txtime_show (struct device *dev, struct device_attribute *attr, + char *buf) { struct netiucv_priv *priv = dev->driver_data; @@ -1638,8 +1641,8 @@ txtime_show (struct device *dev, struct return sprintf(buf, "%ld\n", priv->conn->prof.tx_time); } -static ssize_t -txtime_write (struct device *dev, struct device_attribute *attr, const char *buf, size_t count) +static ssize_t txtime_write (struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) { struct netiucv_priv *priv = dev->driver_data; @@ -1650,8 +1653,8 @@ txtime_write (struct device *dev, struct static DEVICE_ATTR(max_tx_io_time, 0644, txtime_show, txtime_write); -static ssize_t -txpend_show (struct device *dev, struct device_attribute *attr, char *buf) +static ssize_t txpend_show (struct device *dev, struct device_attribute *attr, + char *buf) { struct netiucv_priv *priv = dev->driver_data; @@ -1659,8 +1662,8 @@ txpend_show (struct device *dev, struct return sprintf(buf, "%ld\n", priv->conn->prof.tx_pending); } -static ssize_t -txpend_write (struct device *dev, struct device_attribute *attr, const char *buf, size_t count) +static ssize_t txpend_write (struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) { struct netiucv_priv *priv = dev->driver_data; @@ -1671,8 +1674,8 @@ txpend_write (struct device *dev, struct static DEVICE_ATTR(tx_pending, 0644, txpend_show, txpend_write); -static ssize_t -txmpnd_show (struct device *dev, struct device_attribute *attr, char *buf) +static ssize_t txmpnd_show (struct device *dev, struct device_attribute *attr, + char *buf) { struct netiucv_priv *priv = dev->driver_data; @@ -1680,8 +1683,8 @@ txmpnd_show (struct device *dev, struct return sprintf(buf, "%ld\n", priv->conn->prof.tx_max_pending); } -static ssize_t -txmpnd_write (struct device *dev, struct device_attribute *attr, const char *buf, size_t count) +static ssize_t txmpnd_write (struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) { struct netiucv_priv *priv = dev->driver_data; @@ -1721,8 +1724,7 @@ static struct attribute_group netiucv_st .attrs = netiucv_stat_attrs, }; -static inline int -netiucv_add_files(struct device *dev) +static inline int netiucv_add_files(struct device *dev) { int ret; @@ -1736,18 +1738,16 @@ netiucv_add_files(struct device *dev) return ret; } -static inline void -netiucv_remove_files(struct device *dev) +static inline void netiucv_remove_files(struct device *dev) { IUCV_DBF_TEXT(trace, 3, __FUNCTION__); sysfs_remove_group(&dev->kobj, &netiucv_stat_attr_group); sysfs_remove_group(&dev->kobj, &netiucv_attr_group); } -static int -netiucv_register_device(struct net_device *ndev) +static int netiucv_register_device(struct net_device *ndev) { - struct netiucv_priv *priv = ndev->priv; + struct netiucv_priv *priv = netdev_priv(ndev); struct device *dev = kzalloc(sizeof(struct device), GFP_KERNEL); int ret; @@ -1786,8 +1786,7 @@ out_unreg: return ret; } -static void -netiucv_unregister_device(struct device *dev) +static void netiucv_unregister_device(struct device *dev) { IUCV_DBF_TEXT(trace, 3, __FUNCTION__); netiucv_remove_files(dev); @@ -1798,107 +1797,89 @@ netiucv_unregister_device(struct device * Allocate and initialize a new connection structure. * Add it to the list of netiucv connections; */ -static struct iucv_connection * -netiucv_new_connection(struct net_device *dev, char *username) -{ - unsigned long flags; - struct iucv_connection **clist = &iucv_conns.iucv_connections; - struct iucv_connection *conn = - kzalloc(sizeof(struct iucv_connection), GFP_KERNEL); - - if (conn) { - skb_queue_head_init(&conn->collect_queue); - skb_queue_head_init(&conn->commit_queue); - spin_lock_init(&conn->collect_lock); - conn->max_buffsize = NETIUCV_BUFSIZE_DEFAULT; - conn->netdev = dev; - - conn->rx_buff = alloc_skb(NETIUCV_BUFSIZE_DEFAULT, - GFP_KERNEL | GFP_DMA); - if (!conn->rx_buff) { - kfree(conn); - return NULL; - } - conn->tx_buff = alloc_skb(NETIUCV_BUFSIZE_DEFAULT, - GFP_KERNEL | GFP_DMA); - if (!conn->tx_buff) { - kfree_skb(conn->rx_buff); - kfree(conn); - return NULL; - } - conn->fsm = init_fsm("netiucvconn", conn_state_names, - conn_event_names, NR_CONN_STATES, - NR_CONN_EVENTS, conn_fsm, CONN_FSM_LEN, - GFP_KERNEL); - if (!conn->fsm) { - kfree_skb(conn->tx_buff); - kfree_skb(conn->rx_buff); - kfree(conn); - return NULL; - } - fsm_settimer(conn->fsm, &conn->timer); - fsm_newstate(conn->fsm, CONN_STATE_INVALID); - - if (username) { - memcpy(conn->userid, username, 9); - fsm_newstate(conn->fsm, CONN_STATE_STOPPED); - } +static struct iucv_connection *netiucv_new_connection(struct net_device *dev, + char *username) +{ + struct iucv_connection *conn; - write_lock_irqsave(&iucv_conns.iucv_rwlock, flags); - conn->next = *clist; - *clist = conn; - write_unlock_irqrestore(&iucv_conns.iucv_rwlock, flags); + conn = kzalloc(sizeof(*conn), GFP_KERNEL); + if (!conn) + goto out; + skb_queue_head_init(&conn->collect_queue); + skb_queue_head_init(&conn->commit_queue); + spin_lock_init(&conn->collect_lock); + conn->max_buffsize = NETIUCV_BUFSIZE_DEFAULT; + conn->netdev = dev; + + conn->rx_buff = alloc_skb(conn->max_buffsize, GFP_KERNEL | GFP_DMA); + if (!conn->rx_buff) + goto out_conn; + conn->tx_buff = alloc_skb(conn->max_buffsize, GFP_KERNEL | GFP_DMA); + if (!conn->tx_buff) + goto out_rx; + conn->fsm = init_fsm("netiucvconn", conn_state_names, + conn_event_names, NR_CONN_STATES, + NR_CONN_EVENTS, conn_fsm, CONN_FSM_LEN, + GFP_KERNEL); + if (!conn->fsm) + goto out_tx; + + fsm_settimer(conn->fsm, &conn->timer); + fsm_newstate(conn->fsm, CONN_STATE_INVALID); + + if (username) { + memcpy(conn->userid, username, 9); + fsm_newstate(conn->fsm, CONN_STATE_STOPPED); } + + write_lock_bh(&iucv_connection_rwlock); + list_add_tail(&conn->list, &iucv_connection_list); + write_unlock_bh(&iucv_connection_rwlock); return conn; + +out_tx: + kfree_skb(conn->tx_buff); +out_rx: + kfree_skb(conn->rx_buff); +out_conn: + kfree(conn); +out: + return NULL; } /** * Release a connection structure and remove it from the * list of netiucv connections. */ -static void -netiucv_remove_connection(struct iucv_connection *conn) +static void netiucv_remove_connection(struct iucv_connection *conn) { - struct iucv_connection **clist = &iucv_conns.iucv_connections; - unsigned long flags; - IUCV_DBF_TEXT(trace, 3, __FUNCTION__); - if (conn == NULL) - return; - write_lock_irqsave(&iucv_conns.iucv_rwlock, flags); - while (*clist) { - if (*clist == conn) { - *clist = conn->next; - write_unlock_irqrestore(&iucv_conns.iucv_rwlock, flags); - if (conn->handle) { - iucv_unregister_program(conn->handle); - conn->handle = NULL; - } - fsm_deltimer(&conn->timer); - kfree_fsm(conn->fsm); - kfree_skb(conn->rx_buff); - kfree_skb(conn->tx_buff); - return; - } - clist = &((*clist)->next); + write_lock_bh(&iucv_connection_rwlock); + list_del_init(&conn->list); + write_unlock_bh(&iucv_connection_rwlock); + if (conn->path) { + iucv_path_sever(conn->path, iucvMagic); + kfree(conn->path); + conn->path = NULL; } - write_unlock_irqrestore(&iucv_conns.iucv_rwlock, flags); + fsm_deltimer(&conn->timer); + kfree_fsm(conn->fsm); + kfree_skb(conn->rx_buff); + kfree_skb(conn->tx_buff); } /** * Release everything of a net device. */ -static void -netiucv_free_netdevice(struct net_device *dev) +static void netiucv_free_netdevice(struct net_device *dev) { - struct netiucv_priv *privptr; + struct netiucv_priv *privptr = netdev_priv(dev); IUCV_DBF_TEXT(trace, 3, __FUNCTION__); if (!dev) return; - privptr = (struct netiucv_priv *)dev->priv; if (privptr) { if (privptr->conn) netiucv_remove_connection(privptr->conn); @@ -1913,11 +1894,8 @@ netiucv_free_netdevice(struct net_device /** * Initialize a net device. (Called from kernel in alloc_netdev()) */ -static void -netiucv_setup_netdevice(struct net_device *dev) +static void netiucv_setup_netdevice(struct net_device *dev) { - memset(dev->priv, 0, sizeof(struct netiucv_priv)); - dev->mtu = NETIUCV_MTU_DEFAULT; dev->hard_start_xmit = netiucv_tx; dev->open = netiucv_open; @@ -1936,8 +1914,7 @@ netiucv_setup_netdevice(struct net_devic /** * Allocate and initialize everything of a net device. */ -static struct net_device * -netiucv_init_netdevice(char *username) +static struct net_device *netiucv_init_netdevice(char *username) { struct netiucv_priv *privptr; struct net_device *dev; @@ -1946,40 +1923,40 @@ netiucv_init_netdevice(char *username) netiucv_setup_netdevice); if (!dev) return NULL; - if (dev_alloc_name(dev, dev->name) < 0) { - free_netdev(dev); - return NULL; - } + if (dev_alloc_name(dev, dev->name) < 0) + goto out_netdev; - privptr = (struct netiucv_priv *)dev->priv; + privptr = netdev_priv(dev); privptr->fsm = init_fsm("netiucvdev", dev_state_names, dev_event_names, NR_DEV_STATES, NR_DEV_EVENTS, dev_fsm, DEV_FSM_LEN, GFP_KERNEL); - if (!privptr->fsm) { - free_netdev(dev); - return NULL; - } + if (!privptr->fsm) + goto out_netdev; + privptr->conn = netiucv_new_connection(dev, username); if (!privptr->conn) { - kfree_fsm(privptr->fsm); - free_netdev(dev); IUCV_DBF_TEXT(setup, 2, "NULL from netiucv_new_connection\n"); - return NULL; + goto out_fsm; } fsm_newstate(privptr->fsm, DEV_STATE_STOPPED); - return dev; + +out_fsm: + kfree_fsm(privptr->fsm); +out_netdev: + free_netdev(dev); + return NULL; } -static ssize_t -conn_write(struct device_driver *drv, const char *buf, size_t count) +static ssize_t conn_write(struct device_driver *drv, + const char *buf, size_t count) { - char *p; + const char *p; char username[9]; - int i, ret; + int i, rc; struct net_device *dev; - struct iucv_connection **clist = &iucv_conns.iucv_connections; - unsigned long flags; + struct netiucv_priv *priv; + struct iucv_connection *cp; IUCV_DBF_TEXT(trace, 3, __FUNCTION__); if (count>9) { @@ -1988,83 +1965,82 @@ conn_write(struct device_driver *drv, co return -EINVAL; } - for (i=0, p=(char *)buf; i<8 && *p; i++, p++) { - if (isalnum(*p) || (*p == '$')) - username[i]= toupper(*p); - else if (*p == '\n') { + for (i = 0, p = buf; i < 8 && *p; i++, p++) { + if (isalnum(*p) || *p == '$') { + username[i] = toupper(*p); + continue; + } + if (*p == '\n') /* trailing lf, grr */ break; - } else { - PRINT_WARN("netiucv: Invalid character in username!\n"); - IUCV_DBF_TEXT_(setup, 2, - "conn_write: invalid character %c\n", *p); - return -EINVAL; - } + PRINT_WARN("netiucv: Invalid character in username!\n"); + IUCV_DBF_TEXT_(setup, 2, + "conn_write: invalid character %c\n", *p); + return -EINVAL; } - while (i<8) + while (i < 8) username[i++] = ' '; username[8] = '\0'; - read_lock_irqsave(&iucv_conns.iucv_rwlock, flags); - while (*clist) { - if (!strncmp(username, (*clist)->userid, 9)) - break; - clist = &((*clist)->next); - } - read_unlock_irqrestore(&iucv_conns.iucv_rwlock, flags); - if (*clist) { - PRINT_WARN("netiucv: Connection to %s already exists\n", - username); - return -EEXIST; + read_lock_bh(&iucv_connection_rwlock); + list_for_each_entry(cp, &iucv_connection_list, list) { + if (!strncmp(username, cp->userid, 9)) { + read_unlock_bh(&iucv_connection_rwlock); + PRINT_WARN("netiucv: Connection to %s already " + "exists\n", username); + return -EEXIST; + } } + read_unlock_bh(&iucv_connection_rwlock); + dev = netiucv_init_netdevice(username); if (!dev) { - PRINT_WARN( - "netiucv: Could not allocate network device structure " - "for user '%s'\n", netiucv_printname(username)); + PRINT_WARN("netiucv: Could not allocate network device " + "structure for user '%s'\n", + netiucv_printname(username)); IUCV_DBF_TEXT(setup, 2, "NULL from netiucv_init_netdevice\n"); return -ENODEV; } - if ((ret = netiucv_register_device(dev))) { + rc = netiucv_register_device(dev); + if (rc) { IUCV_DBF_TEXT_(setup, 2, - "ret %d from netiucv_register_device\n", ret); + "ret %d from netiucv_register_device\n", rc); goto out_free_ndev; } /* sysfs magic */ - SET_NETDEV_DEV(dev, - (struct device*)((struct netiucv_priv*)dev->priv)->dev); + priv = netdev_priv(dev); + SET_NETDEV_DEV(dev, priv->dev); - if ((ret = register_netdev(dev))) { - netiucv_unregister_device((struct device*) - ((struct netiucv_priv*)dev->priv)->dev); - goto out_free_ndev; - } + rc = register_netdev(dev); + if (rc) + goto out_unreg; PRINT_INFO("%s: '%s'\n", dev->name, netiucv_printname(username)); return count; +out_unreg: + netiucv_unregister_device(priv->dev); out_free_ndev: PRINT_WARN("netiucv: Could not register '%s'\n", dev->name); IUCV_DBF_TEXT(setup, 2, "conn_write: could not register\n"); netiucv_free_netdevice(dev); - return ret; + return rc; } -DRIVER_ATTR(connection, 0200, NULL, conn_write); +static DRIVER_ATTR(connection, 0200, NULL, conn_write); -static ssize_t -remove_write (struct device_driver *drv, const char *buf, size_t count) +static ssize_t remove_write (struct device_driver *drv, + const char *buf, size_t count) { - struct iucv_connection **clist = &iucv_conns.iucv_connections; - unsigned long flags; + struct iucv_connection *cp; struct net_device *ndev; struct netiucv_priv *priv; struct device *dev; char name[IFNAMSIZ]; - char *p; + const char *p; int i; IUCV_DBF_TEXT(trace, 3, __FUNCTION__); @@ -2072,33 +2048,27 @@ remove_write (struct device_driver *drv, if (count >= IFNAMSIZ) count = IFNAMSIZ - 1;; - for (i=0, p=(char *)buf; inetdev; - priv = (struct netiucv_priv*)ndev->priv; + read_lock_bh(&iucv_connection_rwlock); + list_for_each_entry(cp, &iucv_connection_list, list) { + ndev = cp->netdev; + priv = netdev_priv(ndev); dev = priv->dev; - - if (strncmp(name, ndev->name, count)) { - clist = &((*clist)->next); - continue; - } - read_unlock_irqrestore(&iucv_conns.iucv_rwlock, flags); + if (strncmp(name, ndev->name, count)) + continue; + read_unlock_bh(&iucv_connection_rwlock); if (ndev->flags & (IFF_UP | IFF_RUNNING)) { - PRINT_WARN( - "netiucv: net device %s active with peer %s\n", - ndev->name, priv->conn->userid); + PRINT_WARN("netiucv: net device %s active with peer " + "%s\n", ndev->name, priv->conn->userid); PRINT_WARN("netiucv: %s cannot be removed\n", - ndev->name); + ndev->name); IUCV_DBF_TEXT(data, 2, "remove_write: still active\n"); return -EBUSY; } @@ -2106,75 +2076,94 @@ remove_write (struct device_driver *drv, netiucv_unregister_device(dev); return count; } - read_unlock_irqrestore(&iucv_conns.iucv_rwlock, flags); + read_unlock_bh(&iucv_connection_rwlock); PRINT_WARN("netiucv: net device %s unknown\n", name); IUCV_DBF_TEXT(data, 2, "remove_write: unknown device\n"); return -EINVAL; } -DRIVER_ATTR(remove, 0200, NULL, remove_write); +static DRIVER_ATTR(remove, 0200, NULL, remove_write); -static void -netiucv_banner(void) +static struct attribute * netiucv_drv_attrs[] = { + &driver_attr_connection.attr, + &driver_attr_remove.attr, + NULL, +}; + +static struct attribute_group netiucv_drv_attr_group = { + .attrs = netiucv_drv_attrs, +}; + +static void netiucv_banner(void) { PRINT_INFO("NETIUCV driver initialized\n"); } -static void __exit -netiucv_exit(void) +static void __exit netiucv_exit(void) { + struct iucv_connection *cp; + struct net_device *ndev; + struct netiucv_priv *priv; + struct device *dev; + IUCV_DBF_TEXT(trace, 3, __FUNCTION__); - while (iucv_conns.iucv_connections) { - struct net_device *ndev = iucv_conns.iucv_connections->netdev; - struct netiucv_priv *priv = (struct netiucv_priv*)ndev->priv; - struct device *dev = priv->dev; + while (!list_empty(&iucv_connection_list)) { + cp = list_entry(iucv_connection_list.next, + struct iucv_connection, list); + list_del(&cp->list); + ndev = cp->netdev; + priv = netdev_priv(ndev); + dev = priv->dev; unregister_netdev(ndev); netiucv_unregister_device(dev); } - driver_remove_file(&netiucv_driver, &driver_attr_connection); - driver_remove_file(&netiucv_driver, &driver_attr_remove); + sysfs_remove_group(&netiucv_driver.kobj, &netiucv_drv_attr_group); driver_unregister(&netiucv_driver); + iucv_unregister(&netiucv_handler, 1); iucv_unregister_dbf_views(); PRINT_INFO("NETIUCV driver unloaded\n"); return; } -static int __init -netiucv_init(void) +static int __init netiucv_init(void) { - int ret; + int rc; - ret = iucv_register_dbf_views(); - if (ret) { - PRINT_WARN("netiucv_init failed, " - "iucv_register_dbf_views rc = %d\n", ret); - return ret; - } + rc = iucv_register_dbf_views(); + if (rc) + goto out; + rc = iucv_register(&netiucv_handler, 1); + if (rc) + goto out_dbf; IUCV_DBF_TEXT(trace, 3, __FUNCTION__); - ret = driver_register(&netiucv_driver); - if (ret) { + rc = driver_register(&netiucv_driver); + if (rc) { PRINT_ERR("NETIUCV: failed to register driver.\n"); - IUCV_DBF_TEXT_(setup, 2, "ret %d from driver_register\n", ret); - iucv_unregister_dbf_views(); - return ret; + IUCV_DBF_TEXT_(setup, 2, "ret %d from driver_register\n", rc); + goto out_iucv; } - /* Add entry for specifying connections. */ - ret = driver_create_file(&netiucv_driver, &driver_attr_connection); - if (!ret) { - ret = driver_create_file(&netiucv_driver, &driver_attr_remove); - netiucv_banner(); - rwlock_init(&iucv_conns.iucv_rwlock); - } else { - PRINT_ERR("NETIUCV: failed to add driver attribute.\n"); - IUCV_DBF_TEXT_(setup, 2, "ret %d from driver_create_file\n", ret); - driver_unregister(&netiucv_driver); - iucv_unregister_dbf_views(); + rc = sysfs_create_group(&netiucv_driver.kobj, &netiucv_drv_attr_group); + if (rc) { + PRINT_ERR("NETIUCV: failed to add driver attributes.\n"); + IUCV_DBF_TEXT_(setup, 2, + "ret %d - netiucv_drv_attr_group\n", rc); + goto out_driver; } - return ret; + netiucv_banner(); + return rc; + +out_driver: + driver_unregister(&netiucv_driver); +out_iucv: + iucv_unregister(&netiucv_handler, 1); +out_dbf: + iucv_unregister_dbf_views(); +out: + return rc; } module_init(netiucv_init); diff --git a/drivers/s390/net/qeth_eddp.c b/drivers/s390/net/qeth_eddp.c index 6bb558a..7c735e1 100644 --- a/drivers/s390/net/qeth_eddp.c +++ b/drivers/s390/net/qeth_eddp.c @@ -49,7 +49,7 @@ qeth_eddp_check_buffers_for_context(stru return buffers_needed; } -static inline void +static void qeth_eddp_free_context(struct qeth_eddp_context *ctx) { int i; @@ -91,7 +91,7 @@ qeth_eddp_buf_release_contexts(struct qe } } -static inline int +static int qeth_eddp_buf_ref_context(struct qeth_qdio_out_buffer *buf, struct qeth_eddp_context *ctx) { @@ -196,7 +196,7 @@ out: return flush_cnt; } -static inline void +static void qeth_eddp_create_segment_hdrs(struct qeth_eddp_context *ctx, struct qeth_eddp_data *eddp, int data_len) { @@ -256,7 +256,7 @@ qeth_eddp_create_segment_hdrs(struct qet ctx->offset += eddp->thl; } -static inline void +static void qeth_eddp_copy_data_tcp(char *dst, struct qeth_eddp_data *eddp, int len, __wsum *hcsum) { @@ -302,7 +302,7 @@ qeth_eddp_copy_data_tcp(char *dst, struc } } -static inline void +static void qeth_eddp_create_segment_data_tcp(struct qeth_eddp_context *ctx, struct qeth_eddp_data *eddp, int data_len, __wsum hcsum) @@ -349,7 +349,7 @@ qeth_eddp_create_segment_data_tcp(struct ((struct tcphdr *)eddp->th_in_ctx)->check = csum_fold(hcsum); } -static inline __wsum +static __wsum qeth_eddp_check_tcp4_hdr(struct qeth_eddp_data *eddp, int data_len) { __wsum phcsum; /* pseudo header checksum */ @@ -363,7 +363,7 @@ qeth_eddp_check_tcp4_hdr(struct qeth_edd return csum_partial((u8 *)&eddp->th, eddp->thl, phcsum); } -static inline __wsum +static __wsum qeth_eddp_check_tcp6_hdr(struct qeth_eddp_data *eddp, int data_len) { __be32 proto; @@ -381,7 +381,7 @@ qeth_eddp_check_tcp6_hdr(struct qeth_edd return phcsum; } -static inline struct qeth_eddp_data * +static struct qeth_eddp_data * qeth_eddp_create_eddp_data(struct qeth_hdr *qh, u8 *nh, u8 nhl, u8 *th, u8 thl) { struct qeth_eddp_data *eddp; @@ -399,7 +399,7 @@ qeth_eddp_create_eddp_data(struct qeth_h return eddp; } -static inline void +static void __qeth_eddp_fill_context_tcp(struct qeth_eddp_context *ctx, struct qeth_eddp_data *eddp) { @@ -464,7 +464,7 @@ #endif /* CONFIG_QETH_VLAN */ } } -static inline int +static int qeth_eddp_fill_context_tcp(struct qeth_eddp_context *ctx, struct sk_buff *skb, struct qeth_hdr *qhdr) { @@ -505,7 +505,7 @@ #endif /* CONFIG_QETH_VLAN */ return 0; } -static inline void +static void qeth_eddp_calc_num_pages(struct qeth_eddp_context *ctx, struct sk_buff *skb, int hdr_len) { @@ -529,7 +529,7 @@ qeth_eddp_calc_num_pages(struct qeth_edd (skb_shinfo(skb)->gso_segs + 1); } -static inline struct qeth_eddp_context * +static struct qeth_eddp_context * qeth_eddp_create_context_generic(struct qeth_card *card, struct sk_buff *skb, int hdr_len) { @@ -581,7 +581,7 @@ qeth_eddp_create_context_generic(struct return ctx; } -static inline struct qeth_eddp_context * +static struct qeth_eddp_context * qeth_eddp_create_context_tcp(struct qeth_card *card, struct sk_buff *skb, struct qeth_hdr *qhdr) { @@ -625,5 +625,3 @@ qeth_eddp_create_context(struct qeth_car } return NULL; } - - diff --git a/drivers/s390/net/qeth_main.c b/drivers/s390/net/qeth_main.c index d2efa5f..2257e45 100644 --- a/drivers/s390/net/qeth_main.c +++ b/drivers/s390/net/qeth_main.c @@ -651,7 +651,7 @@ __qeth_ref_ip_on_card(struct qeth_card * return 0; } -static inline int +static int __qeth_address_exists_in_list(struct list_head *list, struct qeth_ipaddr *addr, int same_type) { @@ -795,7 +795,7 @@ qeth_add_ip(struct qeth_card *card, stru return rc; } -static inline void +static void __qeth_delete_all_mc(struct qeth_card *card, unsigned long *flags) { struct qeth_ipaddr *addr, *tmp; @@ -882,7 +882,7 @@ #ifdef CONFIG_QETH_IPV6 static void qeth_add_multicast_ipv6(struct qeth_card *); #endif -static inline int +static int qeth_set_thread_start_bit(struct qeth_card *card, unsigned long thread) { unsigned long flags; @@ -920,7 +920,7 @@ qeth_clear_thread_running_bit(struct qet wake_up(&card->wait_q); } -static inline int +static int __qeth_do_run_thread(struct qeth_card *card, unsigned long thread) { unsigned long flags; @@ -1764,9 +1764,9 @@ out: qeth_release_buffer(channel,iob); } -static inline void +static void qeth_prepare_control_data(struct qeth_card *card, int len, -struct qeth_cmd_buffer *iob) + struct qeth_cmd_buffer *iob) { qeth_setup_ccw(&card->write,iob->data,len); iob->callback = qeth_release_buffer; @@ -2160,7 +2160,7 @@ qeth_check_qdio_errors(struct qdio_buffe return 0; } -static inline struct sk_buff * +static struct sk_buff * qeth_get_skb(unsigned int length, struct qeth_hdr *hdr) { struct sk_buff* skb; @@ -2179,7 +2179,7 @@ #endif return skb; } -static inline struct sk_buff * +static struct sk_buff * qeth_get_next_skb(struct qeth_card *card, struct qdio_buffer *buffer, struct qdio_buffer_element **__element, int *__offset, struct qeth_hdr **hdr) @@ -2264,7 +2264,7 @@ no_mem: return NULL; } -static inline __be16 +static __be16 qeth_type_trans(struct sk_buff *skb, struct net_device *dev) { struct qeth_card *card; @@ -2297,7 +2297,7 @@ #endif /* CONFIG_TR */ return htons(ETH_P_802_2); } -static inline void +static void qeth_rebuild_skb_fake_ll_tr(struct qeth_card *card, struct sk_buff *skb, struct qeth_hdr *hdr) { @@ -2351,7 +2351,7 @@ #endif /* CONFIG_QETH_IPV6 */ fake_llc->ethertype = ETH_P_IP; } -static inline void +static void qeth_rebuild_skb_fake_ll_eth(struct qeth_card *card, struct sk_buff *skb, struct qeth_hdr *hdr) { @@ -2420,7 +2420,7 @@ qeth_layer2_rebuild_skb(struct qeth_card *((__u32 *)skb->cb) = ++card->seqno.pkt_seqno; } -static inline __u16 +static __u16 qeth_rebuild_skb(struct qeth_card *card, struct sk_buff *skb, struct qeth_hdr *hdr) { @@ -2476,7 +2476,7 @@ #endif /* CONFIG_QETH_IPV6 */ return vlan_id; } -static inline void +static void qeth_process_inbound_buffer(struct qeth_card *card, struct qeth_qdio_buffer *buf, int index) { @@ -2528,7 +2528,7 @@ #endif } } -static inline struct qeth_buffer_pool_entry * +static struct qeth_buffer_pool_entry * qeth_get_buffer_pool_entry(struct qeth_card *card) { struct qeth_buffer_pool_entry *entry; @@ -2543,7 +2543,7 @@ qeth_get_buffer_pool_entry(struct qeth_c return NULL; } -static inline void +static void qeth_init_input_buffer(struct qeth_card *card, struct qeth_qdio_buffer *buf) { struct qeth_buffer_pool_entry *pool_entry; @@ -2570,7 +2570,7 @@ qeth_init_input_buffer(struct qeth_card buf->state = QETH_QDIO_BUF_EMPTY; } -static inline void +static void qeth_clear_output_buffer(struct qeth_qdio_out_q *queue, struct qeth_qdio_out_buffer *buf) { @@ -2595,7 +2595,7 @@ qeth_clear_output_buffer(struct qeth_qdi atomic_set(&buf->state, QETH_QDIO_BUF_EMPTY); } -static inline void +static void qeth_queue_input_buffer(struct qeth_card *card, int index) { struct qeth_qdio_q *queue = card->qdio.in_q; @@ -2699,7 +2699,7 @@ qeth_qdio_input_handler(struct ccw_devic card->perf_stats.inbound_start_time; } -static inline int +static int qeth_handle_send_error(struct qeth_card *card, struct qeth_qdio_out_buffer *buffer, unsigned int qdio_err, unsigned int siga_err) @@ -2821,7 +2821,7 @@ qeth_flush_buffers(struct qeth_qdio_out_ * Switched to packing state if the number of used buffers on a queue * reaches a certain limit. */ -static inline void +static void qeth_switch_to_packing_if_needed(struct qeth_qdio_out_q *queue) { if (!queue->do_pack) { @@ -2842,7 +2842,7 @@ qeth_switch_to_packing_if_needed(struct * In that case 1 is returned to inform the caller. If no buffer * has to be flushed, zero is returned. */ -static inline int +static int qeth_switch_to_nonpacking_if_needed(struct qeth_qdio_out_q *queue) { struct qeth_qdio_out_buffer *buffer; @@ -2877,7 +2877,7 @@ qeth_switch_to_nonpacking_if_needed(stru * Checks if there is a packing buffer and prepares it to be flushed. * In that case returns 1, otherwise zero. */ -static inline int +static int qeth_flush_buffers_on_no_pci(struct qeth_qdio_out_q *queue) { struct qeth_qdio_out_buffer *buffer; @@ -2894,7 +2894,7 @@ qeth_flush_buffers_on_no_pci(struct qeth return 0; } -static inline void +static void qeth_check_outbound_queue(struct qeth_qdio_out_q *queue) { int index; @@ -3594,7 +3594,7 @@ qeth_fake_header(struct sk_buff *skb, st } } -static inline int +static int qeth_send_packet(struct qeth_card *, struct sk_buff *); static int @@ -3759,7 +3759,7 @@ qeth_stop(struct net_device *dev) return 0; } -static inline int +static int qeth_get_cast_type(struct qeth_card *card, struct sk_buff *skb) { int cast_type = RTN_UNSPEC; @@ -3806,7 +3806,7 @@ qeth_get_cast_type(struct qeth_card *car return cast_type; } -static inline int +static int qeth_get_priority_queue(struct qeth_card *card, struct sk_buff *skb, int ipv, int cast_type) { @@ -3853,7 +3853,7 @@ qeth_get_ip_version(struct sk_buff *skb) } } -static inline struct qeth_hdr * +static struct qeth_hdr * __qeth_prepare_skb(struct qeth_card *card, struct sk_buff *skb, int ipv) { #ifdef CONFIG_QETH_VLAN @@ -3882,14 +3882,14 @@ #endif qeth_push_skb(card, skb, sizeof(struct qeth_hdr))); } -static inline void +static void __qeth_free_new_skb(struct sk_buff *orig_skb, struct sk_buff *new_skb) { if (orig_skb != new_skb) dev_kfree_skb_any(new_skb); } -static inline struct sk_buff * +static struct sk_buff * qeth_prepare_skb(struct qeth_card *card, struct sk_buff *skb, struct qeth_hdr **hdr, int ipv) { @@ -3940,7 +3940,7 @@ qeth_get_qeth_hdr_flags6(int cast_type) return ct | QETH_CAST_UNICAST; } -static inline void +static void qeth_layer2_get_packet_type(struct qeth_card *card, struct qeth_hdr *hdr, struct sk_buff *skb) { @@ -3977,7 +3977,7 @@ qeth_layer2_get_packet_type(struct qeth_ } } -static inline void +static void qeth_layer2_fill_header(struct qeth_card *card, struct qeth_hdr *hdr, struct sk_buff *skb, int cast_type) { @@ -4068,7 +4068,7 @@ #endif /* CONFIG_QETH_VLAN */ } } -static inline void +static void __qeth_fill_buffer(struct sk_buff *skb, struct qdio_buffer *buffer, int is_tso, int *next_element_to_fill) { @@ -4112,7 +4112,7 @@ __qeth_fill_buffer(struct sk_buff *skb, *next_element_to_fill = element; } -static inline int +static int qeth_fill_buffer(struct qeth_qdio_out_q *queue, struct qeth_qdio_out_buffer *buf, struct sk_buff *skb) @@ -4171,7 +4171,7 @@ qeth_fill_buffer(struct qeth_qdio_out_q return flush_cnt; } -static inline int +static int qeth_do_send_packet_fast(struct qeth_card *card, struct qeth_qdio_out_q *queue, struct sk_buff *skb, struct qeth_hdr *hdr, int elements_needed, @@ -4222,7 +4222,7 @@ out: return -EBUSY; } -static inline int +static int qeth_do_send_packet(struct qeth_card *card, struct qeth_qdio_out_q *queue, struct sk_buff *skb, struct qeth_hdr *hdr, int elements_needed, struct qeth_eddp_context *ctx) @@ -4328,7 +4328,7 @@ out: return rc; } -static inline int +static int qeth_get_elements_no(struct qeth_card *card, void *hdr, struct sk_buff *skb, int elems) { @@ -4349,7 +4349,7 @@ qeth_get_elements_no(struct qeth_card *c } -static inline int +static int qeth_send_packet(struct qeth_card *card, struct sk_buff *skb) { int ipv = 0; @@ -4536,7 +4536,7 @@ qeth_mdio_read(struct net_device *dev, i } -static inline const char * +static const char * qeth_arp_get_error_cause(int *rc) { switch (*rc) { @@ -4597,7 +4597,7 @@ qeth_arp_set_no_entries(struct qeth_card return rc; } -static inline void +static void qeth_copy_arp_entries_stripped(struct qeth_arp_query_info *qinfo, struct qeth_arp_query_data *qdata, int entry_size, int uentry_size) @@ -5214,7 +5214,7 @@ qeth_vlan_rx_register(struct net_device spin_unlock_irqrestore(&card->vlanlock, flags); } -static inline void +static void qeth_free_vlan_buffer(struct qeth_card *card, struct qeth_qdio_out_buffer *buf, unsigned short vid) { @@ -5625,7 +5625,7 @@ qeth_delete_mc_addresses(struct qeth_car spin_unlock_irqrestore(&card->ip_lock, flags); } -static inline void +static void qeth_add_mc(struct qeth_card *card, struct in_device *in4_dev) { struct qeth_ipaddr *ipm; @@ -5711,7 +5711,7 @@ qeth_layer2_add_multicast(struct qeth_ca } #ifdef CONFIG_QETH_IPV6 -static inline void +static void qeth_add_mc6(struct qeth_card *card, struct inet6_dev *in6_dev) { struct qeth_ipaddr *ipm; @@ -6022,7 +6022,7 @@ qeth_send_setdelmc(struct qeth_card *car return rc; } -static inline void +static void qeth_fill_netmask(u8 *netmask, unsigned int len) { int i,j; @@ -6626,7 +6626,7 @@ qeth_send_setadp_mode(struct qeth_card * return rc; } -static inline int +static int qeth_setadapter_hstr(struct qeth_card *card) { int rc; @@ -6889,7 +6889,7 @@ qeth_send_simple_setassparms(struct qeth return rc; } -static inline int +static int qeth_start_ipa_arp_processing(struct qeth_card *card) { int rc; @@ -7529,7 +7529,7 @@ qeth_set_allowed_threads(struct qeth_car wake_up(&card->wait_q); } -static inline int +static int qeth_threads_running(struct qeth_card *card, unsigned long threads) { unsigned long flags; @@ -8118,7 +8118,7 @@ qeth_del_ipato_entry(struct qeth_card *c spin_unlock_irqrestore(&card->ip_lock, flags); } -static inline void +static void qeth_convert_addr_to_bits(u8 *addr, u8 *bits, int len) { int i, j; diff --git a/drivers/s390/net/qeth_proc.c b/drivers/s390/net/qeth_proc.c index faa768e..81f805c 100644 --- a/drivers/s390/net/qeth_proc.c +++ b/drivers/s390/net/qeth_proc.c @@ -161,7 +161,7 @@ qeth_procfile_open(struct inode *inode, return seq_open(file, &qeth_procfile_seq_ops); } -static struct file_operations qeth_procfile_fops = { +static const struct file_operations qeth_procfile_fops = { .owner = THIS_MODULE, .open = qeth_procfile_open, .read = seq_read, @@ -273,7 +273,7 @@ qeth_perf_procfile_open(struct inode *in return seq_open(file, &qeth_perf_procfile_seq_ops); } -static struct file_operations qeth_perf_procfile_fops = { +static const struct file_operations qeth_perf_procfile_fops = { .owner = THIS_MODULE, .open = qeth_perf_procfile_open, .read = seq_read, diff --git a/drivers/s390/net/qeth_sys.c b/drivers/s390/net/qeth_sys.c index 5836737..d518419 100644 --- a/drivers/s390/net/qeth_sys.c +++ b/drivers/s390/net/qeth_sys.c @@ -328,7 +328,7 @@ qeth_dev_bufcnt_store(struct device *dev static DEVICE_ATTR(buffer_count, 0644, qeth_dev_bufcnt_show, qeth_dev_bufcnt_store); -static inline ssize_t +static ssize_t qeth_dev_route_show(struct qeth_card *card, struct qeth_routing_info *route, char *buf) { @@ -368,7 +368,7 @@ qeth_dev_route4_show(struct device *dev, return qeth_dev_route_show(card, &card->options.route4, buf); } -static inline ssize_t +static ssize_t qeth_dev_route_store(struct qeth_card *card, struct qeth_routing_info *route, enum qeth_prot_versions prot, const char *buf, size_t count) { @@ -998,7 +998,7 @@ struct device_attribute dev_attr_##_id = .store = _store, \ }; -int +static int qeth_check_layer2(struct qeth_card *card) { if (card->options.layer2) @@ -1100,7 +1100,7 @@ static QETH_DEVICE_ATTR(ipato_invert4, i qeth_dev_ipato_invert4_show, qeth_dev_ipato_invert4_store); -static inline ssize_t +static ssize_t qeth_dev_ipato_add_show(char *buf, struct qeth_card *card, enum qeth_prot_versions proto) { @@ -1146,7 +1146,7 @@ qeth_dev_ipato_add4_show(struct device * return qeth_dev_ipato_add_show(buf, card, QETH_PROT_IPV4); } -static inline int +static int qeth_parse_ipatoe(const char* buf, enum qeth_prot_versions proto, u8 *addr, int *mask_bits) { @@ -1178,7 +1178,7 @@ qeth_parse_ipatoe(const char* buf, enum return 0; } -static inline ssize_t +static ssize_t qeth_dev_ipato_add_store(const char *buf, size_t count, struct qeth_card *card, enum qeth_prot_versions proto) { @@ -1223,7 +1223,7 @@ static QETH_DEVICE_ATTR(ipato_add4, add4 qeth_dev_ipato_add4_show, qeth_dev_ipato_add4_store); -static inline ssize_t +static ssize_t qeth_dev_ipato_del_store(const char *buf, size_t count, struct qeth_card *card, enum qeth_prot_versions proto) { @@ -1361,7 +1361,7 @@ static struct attribute_group qeth_devic .attrs = (struct attribute **)qeth_ipato_device_attrs, }; -static inline ssize_t +static ssize_t qeth_dev_vipa_add_show(char *buf, struct qeth_card *card, enum qeth_prot_versions proto) { @@ -1407,7 +1407,7 @@ qeth_dev_vipa_add4_show(struct device *d return qeth_dev_vipa_add_show(buf, card, QETH_PROT_IPV4); } -static inline int +static int qeth_parse_vipae(const char* buf, enum qeth_prot_versions proto, u8 *addr) { @@ -1418,7 +1418,7 @@ qeth_parse_vipae(const char* buf, enum q return 0; } -static inline ssize_t +static ssize_t qeth_dev_vipa_add_store(const char *buf, size_t count, struct qeth_card *card, enum qeth_prot_versions proto) { @@ -1451,7 +1451,7 @@ static QETH_DEVICE_ATTR(vipa_add4, add4, qeth_dev_vipa_add4_show, qeth_dev_vipa_add4_store); -static inline ssize_t +static ssize_t qeth_dev_vipa_del_store(const char *buf, size_t count, struct qeth_card *card, enum qeth_prot_versions proto) { @@ -1542,7 +1542,7 @@ static struct attribute_group qeth_devic .attrs = (struct attribute **)qeth_vipa_device_attrs, }; -static inline ssize_t +static ssize_t qeth_dev_rxip_add_show(char *buf, struct qeth_card *card, enum qeth_prot_versions proto) { @@ -1588,7 +1588,7 @@ qeth_dev_rxip_add4_show(struct device *d return qeth_dev_rxip_add_show(buf, card, QETH_PROT_IPV4); } -static inline int +static int qeth_parse_rxipe(const char* buf, enum qeth_prot_versions proto, u8 *addr) { @@ -1599,7 +1599,7 @@ qeth_parse_rxipe(const char* buf, enum q return 0; } -static inline ssize_t +static ssize_t qeth_dev_rxip_add_store(const char *buf, size_t count, struct qeth_card *card, enum qeth_prot_versions proto) { @@ -1632,7 +1632,7 @@ static QETH_DEVICE_ATTR(rxip_add4, add4, qeth_dev_rxip_add4_show, qeth_dev_rxip_add4_store); -static inline ssize_t +static ssize_t qeth_dev_rxip_del_store(const char *buf, size_t count, struct qeth_card *card, enum qeth_prot_versions proto) { diff --git a/drivers/s390/net/smsgiucv.c b/drivers/s390/net/smsgiucv.c index b8179c2..3ccca58 100644 --- a/drivers/s390/net/smsgiucv.c +++ b/drivers/s390/net/smsgiucv.c @@ -1,7 +1,7 @@ /* * IUCV special message driver * - * Copyright (C) 2003 IBM Deutschland Entwicklung GmbH, IBM Corporation + * Copyright 2003 IBM Deutschland Entwicklung GmbH, IBM Corporation * Author(s): Martin Schwidefsky (schwidefsky@de.ibm.com) * * This program is free software; you can redistribute it and/or modify @@ -23,10 +23,10 @@ #include #include #include #include +#include #include #include - -#include "iucv.h" +#include "smsgiucv.h" struct smsg_callback { struct list_head list; @@ -39,38 +39,46 @@ MODULE_AUTHOR ("(C) 2003 IBM Corporation by Martin Schwidefsky (schwidefsky@de.ibm.com)"); MODULE_DESCRIPTION ("Linux for S/390 IUCV special message driver"); -static iucv_handle_t smsg_handle; -static unsigned short smsg_pathid; +static struct iucv_path *smsg_path; + static DEFINE_SPINLOCK(smsg_list_lock); static struct list_head smsg_list = LIST_HEAD_INIT(smsg_list); -static void -smsg_connection_complete(iucv_ConnectionComplete *eib, void *pgm_data) +static int smsg_path_pending(struct iucv_path *, u8 ipvmid[8], u8 ipuser[16]); +static void smsg_message_pending(struct iucv_path *, struct iucv_message *); + +static struct iucv_handler smsg_handler = { + .path_pending = smsg_path_pending, + .message_pending = smsg_message_pending, +}; + +static int smsg_path_pending(struct iucv_path *path, u8 ipvmid[8], + u8 ipuser[16]) { + if (strncmp(ipvmid, "*MSG ", sizeof(ipvmid)) != 0) + return -EINVAL; + /* Path pending from *MSG. */ + return iucv_path_accept(path, &smsg_handler, "SMSGIUCV ", NULL); } - -static void -smsg_message_pending(iucv_MessagePending *eib, void *pgm_data) +static void smsg_message_pending(struct iucv_path *path, + struct iucv_message *msg) { struct smsg_callback *cb; - unsigned char *msg; + unsigned char *buffer; unsigned char sender[9]; - unsigned short len; int rc, i; - len = eib->ln1msg2.ipbfln1f; - msg = kmalloc(len + 1, GFP_ATOMIC|GFP_DMA); - if (!msg) { - iucv_reject(eib->ippathid, eib->ipmsgid, eib->iptrgcls); + buffer = kmalloc(msg->length + 1, GFP_ATOMIC | GFP_DMA); + if (!buffer) { + iucv_message_reject(path, msg); return; } - rc = iucv_receive(eib->ippathid, eib->ipmsgid, eib->iptrgcls, - msg, len, NULL, NULL, NULL); + rc = iucv_message_receive(path, msg, 0, buffer, msg->length, NULL); if (rc == 0) { - msg[len] = 0; - EBCASC(msg, len); - memcpy(sender, msg, 8); + buffer[msg->length] = 0; + EBCASC(buffer, msg->length); + memcpy(sender, buffer, 8); sender[8] = 0; /* Remove trailing whitespace from the sender name. */ for (i = 7; i >= 0; i--) { @@ -80,27 +88,17 @@ smsg_message_pending(iucv_MessagePending } spin_lock(&smsg_list_lock); list_for_each_entry(cb, &smsg_list, list) - if (strncmp(msg + 8, cb->prefix, cb->len) == 0) { - cb->callback(sender, msg + 8); + if (strncmp(buffer + 8, cb->prefix, cb->len) == 0) { + cb->callback(sender, buffer + 8); break; } spin_unlock(&smsg_list_lock); } - kfree(msg); + kfree(buffer); } -static iucv_interrupt_ops_t smsg_ops = { - .ConnectionComplete = smsg_connection_complete, - .MessagePending = smsg_message_pending, -}; - -static struct device_driver smsg_driver = { - .name = "SMSGIUCV", - .bus = &iucv_bus, -}; - -int -smsg_register_callback(char *prefix, void (*callback)(char *from, char *str)) +int smsg_register_callback(char *prefix, + void (*callback)(char *from, char *str)) { struct smsg_callback *cb; @@ -110,18 +108,18 @@ smsg_register_callback(char *prefix, voi cb->prefix = prefix; cb->len = strlen(prefix); cb->callback = callback; - spin_lock(&smsg_list_lock); + spin_lock_bh(&smsg_list_lock); list_add_tail(&cb->list, &smsg_list); - spin_unlock(&smsg_list_lock); + spin_unlock_bh(&smsg_list_lock); return 0; } -void -smsg_unregister_callback(char *prefix, void (*callback)(char *from, char *str)) +void smsg_unregister_callback(char *prefix, + void (*callback)(char *from, char *str)) { struct smsg_callback *cb, *tmp; - spin_lock(&smsg_list_lock); + spin_lock_bh(&smsg_list_lock); cb = NULL; list_for_each_entry(tmp, &smsg_list, list) if (tmp->callback == callback && @@ -130,55 +128,58 @@ smsg_unregister_callback(char *prefix, v list_del(&cb->list); break; } - spin_unlock(&smsg_list_lock); + spin_unlock_bh(&smsg_list_lock); kfree(cb); } -static void __exit -smsg_exit(void) +static struct device_driver smsg_driver = { + .name = "SMSGIUCV", + .bus = &iucv_bus, +}; + +static void __exit smsg_exit(void) { - if (smsg_handle > 0) { - cpcmd("SET SMSG OFF", NULL, 0, NULL); - iucv_sever(smsg_pathid, NULL); - iucv_unregister_program(smsg_handle); - driver_unregister(&smsg_driver); - } - return; + cpcmd("SET SMSG IUCV", NULL, 0, NULL); + iucv_unregister(&smsg_handler, 1); + driver_unregister(&smsg_driver); } -static int __init -smsg_init(void) +static int __init smsg_init(void) { - static unsigned char pgmmask[24] = { - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff - }; int rc; rc = driver_register(&smsg_driver); - if (rc != 0) { - printk(KERN_ERR "SMSGIUCV: failed to register driver.\n"); - return rc; - } - smsg_handle = iucv_register_program("SMSGIUCV ", "*MSG ", - pgmmask, &smsg_ops, NULL); - if (!smsg_handle) { + if (rc != 0) + goto out; + rc = iucv_register(&smsg_handler, 1); + if (rc) { printk(KERN_ERR "SMSGIUCV: failed to register to iucv"); - driver_unregister(&smsg_driver); - return -EIO; /* better errno ? */ + rc = -EIO; /* better errno ? */ + goto out_driver; + } + smsg_path = iucv_path_alloc(255, 0, GFP_KERNEL); + if (!smsg_path) { + rc = -ENOMEM; + goto out_register; } - rc = iucv_connect (&smsg_pathid, 255, NULL, "*MSG ", NULL, 0, - NULL, NULL, smsg_handle, NULL); + rc = iucv_path_connect(smsg_path, &smsg_handler, "*MSG ", + NULL, NULL, NULL); if (rc) { printk(KERN_ERR "SMSGIUCV: failed to connect to *MSG"); - iucv_unregister_program(smsg_handle); - driver_unregister(&smsg_driver); - smsg_handle = NULL; - return -EIO; + rc = -EIO; /* better errno ? */ + goto out_free; } cpcmd("SET SMSG IUCV", NULL, 0, NULL); return 0; + +out_free: + iucv_path_free(smsg_path); +out_register: + iucv_unregister(&smsg_handler, 1); +out_driver: + driver_unregister(&smsg_driver); +out: + return rc; } module_init(smsg_init); diff --git a/drivers/s390/s390mach.c b/drivers/s390/s390mach.c index e088b5e..806bb1a 100644 --- a/drivers/s390/s390mach.c +++ b/drivers/s390/s390mach.c @@ -13,22 +13,18 @@ #include #include #include #include +#include #include - +#include #include - +#include +#include "cio/cio.h" +#include "cio/chsc.h" +#include "cio/css.h" #include "s390mach.h" static struct semaphore m_sem; -extern int css_process_crw(int, int); -extern int chsc_process_crw(void); -extern int chp_process_crw(int, int); -extern void css_reiterate_subchannels(void); - -extern struct workqueue_struct *slow_path_wq; -extern struct work_struct slow_path_work; - static NORET_TYPE void s390_handle_damage(char *msg) { @@ -470,6 +466,19 @@ #endif s390_handle_damage("unable to revalidate registers."); } + if (mci->cd) { + /* Timing facility damage */ + s390_handle_damage("TOD clock damaged"); + } + + if (mci->ed && mci->ec) { + /* External damage */ + if (S390_lowcore.external_damage_code & (1U << ED_ETR_SYNC)) + etr_sync_check(); + if (S390_lowcore.external_damage_code & (1U << ED_ETR_SWITCH)) + etr_switch_to_local(); + } + if (mci->se) /* Storage error uncorrected */ s390_handle_damage("received storage error uncorrected " @@ -508,7 +517,7 @@ static int machine_check_init(void) { init_MUTEX_LOCKED(&m_sem); - ctl_clear_bit(14, 25); /* disable external damage MCH */ + ctl_set_bit(14, 25); /* enable external damage MCH */ ctl_set_bit(14, 27); /* enable system recovery MCH */ #ifdef CONFIG_MACHCHK_WARNING ctl_set_bit(14, 24); /* enable warning MCH */ @@ -529,7 +538,11 @@ arch_initcall(machine_check_init); static int __init machine_check_crw_init (void) { - kthread_run(s390_collect_crw_info, &m_sem, "kmcheck"); + struct task_struct *task; + + task = kthread_run(s390_collect_crw_info, &m_sem, "kmcheck"); + if (IS_ERR(task)) + return PTR_ERR(task); ctl_set_bit(14, 28); /* enable channel report MCH */ return 0; } diff --git a/drivers/s390/s390mach.h b/drivers/s390/s390mach.h index 7abb42a..d3ca428 100644 --- a/drivers/s390/s390mach.h +++ b/drivers/s390/s390mach.h @@ -102,4 +102,7 @@ static inline int stcrw(struct crw *pcrw return ccode; } +#define ED_ETR_SYNC 12 /* External damage ETR sync check */ +#define ED_ETR_SWITCH 13 /* External damage ETR switch to local */ + #endif /* __s390mach */ diff --git a/drivers/s390/scsi/zfcp_aux.c b/drivers/s390/scsi/zfcp_aux.c index 85093b7..1f9554e 100644 --- a/drivers/s390/scsi/zfcp_aux.c +++ b/drivers/s390/scsi/zfcp_aux.c @@ -47,13 +47,12 @@ static int __init zfcp_module_init(void static void zfcp_ns_gid_pn_handler(unsigned long); /* miscellaneous */ -static inline int zfcp_sg_list_alloc(struct zfcp_sg_list *, size_t); -static inline void zfcp_sg_list_free(struct zfcp_sg_list *); -static inline int zfcp_sg_list_copy_from_user(struct zfcp_sg_list *, - void __user *, size_t); -static inline int zfcp_sg_list_copy_to_user(void __user *, - struct zfcp_sg_list *, size_t); - +static int zfcp_sg_list_alloc(struct zfcp_sg_list *, size_t); +static void zfcp_sg_list_free(struct zfcp_sg_list *); +static int zfcp_sg_list_copy_from_user(struct zfcp_sg_list *, + void __user *, size_t); +static int zfcp_sg_list_copy_to_user(void __user *, + struct zfcp_sg_list *, size_t); static long zfcp_cfdc_dev_ioctl(struct file *, unsigned int, unsigned long); #define ZFCP_CFDC_IOC_MAGIC 0xDD @@ -61,7 +60,7 @@ #define ZFCP_CFDC_IOC \ _IOWR(ZFCP_CFDC_IOC_MAGIC, 0, struct zfcp_cfdc_sense_data) -static struct file_operations zfcp_cfdc_fops = { +static const struct file_operations zfcp_cfdc_fops = { .unlocked_ioctl = zfcp_cfdc_dev_ioctl, #ifdef CONFIG_COMPAT .compat_ioctl = zfcp_cfdc_dev_ioctl @@ -605,7 +604,7 @@ zfcp_cfdc_dev_ioctl(struct file *file, u * elements of the scatter-gather list. The maximum size of a single element * in the scatter-gather list is PAGE_SIZE. */ -static inline int +static int zfcp_sg_list_alloc(struct zfcp_sg_list *sg_list, size_t size) { struct scatterlist *sg; @@ -652,7 +651,7 @@ zfcp_sg_list_alloc(struct zfcp_sg_list * * Memory for each element in the scatter-gather list is freed. * Finally sg_list->sg is freed itself and sg_list->count is reset. */ -static inline void +static void zfcp_sg_list_free(struct zfcp_sg_list *sg_list) { struct scatterlist *sg; @@ -697,7 +696,7 @@ zfcp_sg_size(struct scatterlist *sg, uns * @size: number of bytes to be copied * Return: 0 on success, -EFAULT if copy_from_user fails. */ -static inline int +static int zfcp_sg_list_copy_from_user(struct zfcp_sg_list *sg_list, void __user *user_buffer, size_t size) @@ -735,7 +734,7 @@ zfcp_sg_list_copy_from_user(struct zfcp_ * @size: number of bytes to be copied * Return: 0 on success, -EFAULT if copy_to_user fails */ -static inline int +static int zfcp_sg_list_copy_to_user(void __user *user_buffer, struct zfcp_sg_list *sg_list, size_t size) @@ -1799,7 +1798,7 @@ static const struct zfcp_rc_entry zfcp_p * @code: reason code * @rc_table: table of reason codes and descriptions */ -static inline const char * +static const char * zfcp_rc_description(u8 code, const struct zfcp_rc_entry *rc_table) { const char *descr = "unknown reason code"; @@ -1847,7 +1846,7 @@ zfcp_check_ct_response(struct ct_hdr *rj * @rjt_par: reject parameter acc. to FC-PH/FC-FS * @rc_table: table of reason codes and descriptions */ -static inline void +static void zfcp_print_els_rjt(struct zfcp_ls_rjt_par *rjt_par, const struct zfcp_rc_entry *rc_table) { diff --git a/drivers/s390/scsi/zfcp_dbf.c b/drivers/s390/scsi/zfcp_dbf.c index 0aa3b1a..d8191d1 100644 --- a/drivers/s390/scsi/zfcp_dbf.c +++ b/drivers/s390/scsi/zfcp_dbf.c @@ -31,7 +31,7 @@ MODULE_PARM_DESC(dbfsize, #define ZFCP_LOG_AREA ZFCP_LOG_AREA_OTHER -static inline int +static int zfcp_dbf_stck(char *out_buf, const char *label, unsigned long long stck) { unsigned long long sec; @@ -106,7 +106,7 @@ zfcp_dbf_view_dump(char *out_buf, const return len; } -static inline int +static int zfcp_dbf_view_header(debug_info_t * id, struct debug_view *view, int area, debug_entry_t * entry, char *out_buf) { @@ -130,7 +130,7 @@ zfcp_dbf_view_header(debug_info_t * id, return len; } -inline void zfcp_hba_dbf_event_fsf_response(struct zfcp_fsf_req *fsf_req) +void zfcp_hba_dbf_event_fsf_response(struct zfcp_fsf_req *fsf_req) { struct zfcp_adapter *adapter = fsf_req->adapter; struct fsf_qtcb *qtcb = fsf_req->qtcb; @@ -241,7 +241,7 @@ inline void zfcp_hba_dbf_event_fsf_respo spin_unlock_irqrestore(&adapter->hba_dbf_lock, flags); } -inline void +void zfcp_hba_dbf_event_fsf_unsol(const char *tag, struct zfcp_adapter *adapter, struct fsf_status_read_buffer *status_buffer) { @@ -295,7 +295,7 @@ zfcp_hba_dbf_event_fsf_unsol(const char spin_unlock_irqrestore(&adapter->hba_dbf_lock, flags); } -inline void +void zfcp_hba_dbf_event_qdio(struct zfcp_adapter *adapter, unsigned int status, unsigned int qdio_error, unsigned int siga_error, int sbal_index, int sbal_count) @@ -316,7 +316,7 @@ zfcp_hba_dbf_event_qdio(struct zfcp_adap spin_unlock_irqrestore(&adapter->hba_dbf_lock, flags); } -static inline int +static int zfcp_hba_dbf_view_response(char *out_buf, struct zfcp_hba_dbf_record_response *rec) { @@ -403,7 +403,7 @@ zfcp_hba_dbf_view_response(char *out_buf return len; } -static inline int +static int zfcp_hba_dbf_view_status(char *out_buf, struct zfcp_hba_dbf_record_status *rec) { int len = 0; @@ -424,7 +424,7 @@ zfcp_hba_dbf_view_status(char *out_buf, return len; } -static inline int +static int zfcp_hba_dbf_view_qdio(char *out_buf, struct zfcp_hba_dbf_record_qdio *rec) { int len = 0; @@ -469,7 +469,7 @@ zfcp_hba_dbf_view_format(debug_info_t * return len; } -struct debug_view zfcp_hba_dbf_view = { +static struct debug_view zfcp_hba_dbf_view = { "structured", NULL, &zfcp_dbf_view_header, @@ -478,7 +478,7 @@ struct debug_view zfcp_hba_dbf_view = { NULL }; -inline void +void _zfcp_san_dbf_event_common_ct(const char *tag, struct zfcp_fsf_req *fsf_req, u32 s_id, u32 d_id, void *buffer, int buflen) { @@ -519,7 +519,7 @@ _zfcp_san_dbf_event_common_ct(const char spin_unlock_irqrestore(&adapter->san_dbf_lock, flags); } -inline void zfcp_san_dbf_event_ct_request(struct zfcp_fsf_req *fsf_req) +void zfcp_san_dbf_event_ct_request(struct zfcp_fsf_req *fsf_req) { struct zfcp_send_ct *ct = (struct zfcp_send_ct *)fsf_req->data; struct zfcp_port *port = ct->port; @@ -531,7 +531,7 @@ inline void zfcp_san_dbf_event_ct_reques ct->req->length); } -inline void zfcp_san_dbf_event_ct_response(struct zfcp_fsf_req *fsf_req) +void zfcp_san_dbf_event_ct_response(struct zfcp_fsf_req *fsf_req) { struct zfcp_send_ct *ct = (struct zfcp_send_ct *)fsf_req->data; struct zfcp_port *port = ct->port; @@ -543,7 +543,7 @@ inline void zfcp_san_dbf_event_ct_respon ct->resp->length); } -static inline void +static void _zfcp_san_dbf_event_common_els(const char *tag, int level, struct zfcp_fsf_req *fsf_req, u32 s_id, u32 d_id, u8 ls_code, void *buffer, int buflen) @@ -585,7 +585,7 @@ _zfcp_san_dbf_event_common_els(const cha spin_unlock_irqrestore(&adapter->san_dbf_lock, flags); } -inline void zfcp_san_dbf_event_els_request(struct zfcp_fsf_req *fsf_req) +void zfcp_san_dbf_event_els_request(struct zfcp_fsf_req *fsf_req) { struct zfcp_send_els *els = (struct zfcp_send_els *)fsf_req->data; @@ -597,7 +597,7 @@ inline void zfcp_san_dbf_event_els_reque els->req->length); } -inline void zfcp_san_dbf_event_els_response(struct zfcp_fsf_req *fsf_req) +void zfcp_san_dbf_event_els_response(struct zfcp_fsf_req *fsf_req) { struct zfcp_send_els *els = (struct zfcp_send_els *)fsf_req->data; @@ -608,7 +608,7 @@ inline void zfcp_san_dbf_event_els_respo els->resp->length); } -inline void zfcp_san_dbf_event_incoming_els(struct zfcp_fsf_req *fsf_req) +void zfcp_san_dbf_event_incoming_els(struct zfcp_fsf_req *fsf_req) { struct zfcp_adapter *adapter = fsf_req->adapter; struct fsf_status_read_buffer *status_buffer = @@ -693,7 +693,7 @@ zfcp_san_dbf_view_format(debug_info_t * return len; } -struct debug_view zfcp_san_dbf_view = { +static struct debug_view zfcp_san_dbf_view = { "structured", NULL, &zfcp_dbf_view_header, @@ -702,7 +702,7 @@ struct debug_view zfcp_san_dbf_view = { NULL }; -static inline void +static void _zfcp_scsi_dbf_event_common(const char *tag, const char *tag2, int level, struct zfcp_adapter *adapter, struct scsi_cmnd *scsi_cmnd, @@ -786,7 +786,7 @@ _zfcp_scsi_dbf_event_common(const char * spin_unlock_irqrestore(&adapter->scsi_dbf_lock, flags); } -inline void +void zfcp_scsi_dbf_event_result(const char *tag, int level, struct zfcp_adapter *adapter, struct scsi_cmnd *scsi_cmnd, @@ -796,7 +796,7 @@ zfcp_scsi_dbf_event_result(const char *t adapter, scsi_cmnd, fsf_req, 0); } -inline void +void zfcp_scsi_dbf_event_abort(const char *tag, struct zfcp_adapter *adapter, struct scsi_cmnd *scsi_cmnd, struct zfcp_fsf_req *new_fsf_req, @@ -806,7 +806,7 @@ zfcp_scsi_dbf_event_abort(const char *ta adapter, scsi_cmnd, new_fsf_req, old_req_id); } -inline void +void zfcp_scsi_dbf_event_devreset(const char *tag, u8 flag, struct zfcp_unit *unit, struct scsi_cmnd *scsi_cmnd) { @@ -884,7 +884,7 @@ zfcp_scsi_dbf_view_format(debug_info_t * return len; } -struct debug_view zfcp_scsi_dbf_view = { +static struct debug_view zfcp_scsi_dbf_view = { "structured", NULL, &zfcp_dbf_view_header, diff --git a/drivers/s390/scsi/zfcp_erp.c b/drivers/s390/scsi/zfcp_erp.c index c88babc..421da1e 100644 --- a/drivers/s390/scsi/zfcp_erp.c +++ b/drivers/s390/scsi/zfcp_erp.c @@ -200,7 +200,7 @@ void zfcp_fsf_start_timer(struct zfcp_fs * returns: 0 - initiated action successfully * <0 - failed to initiate action */ -int +static int zfcp_erp_adapter_reopen_internal(struct zfcp_adapter *adapter, int clear_mask) { int retval; @@ -295,7 +295,7 @@ zfcp_erp_unit_shutdown(struct zfcp_unit * zfcp_erp_adisc - send ADISC ELS command * @port: port structure */ -int +static int zfcp_erp_adisc(struct zfcp_port *port) { struct zfcp_adapter *adapter = port->adapter; @@ -380,7 +380,7 @@ zfcp_erp_adisc(struct zfcp_port *port) * * If ADISC failed (LS_RJT or timed out) forced reopen of the port is triggered. */ -void +static void zfcp_erp_adisc_handler(unsigned long data) { struct zfcp_send_els *send_els; @@ -838,32 +838,28 @@ zfcp_erp_action_exists(struct zfcp_erp_a * and does appropriate preparations (dismiss fsf request, ...) * * locks: called under erp_lock (disabled interrupts) - * - * returns: 0 */ -static int +static void zfcp_erp_strategy_check_fsfreq(struct zfcp_erp_action *erp_action) { - int retval = 0; - struct zfcp_fsf_req *fsf_req = NULL; struct zfcp_adapter *adapter = erp_action->adapter; if (erp_action->fsf_req) { /* take lock to ensure that request is not deleted meanwhile */ spin_lock(&adapter->req_list_lock); - if ((!zfcp_reqlist_ismember(adapter, - erp_action->fsf_req->req_id)) && - (fsf_req->erp_action == erp_action)) { + if (zfcp_reqlist_ismember(adapter, + erp_action->fsf_req->req_id)) { /* fsf_req still exists */ debug_text_event(adapter->erp_dbf, 3, "a_ca_req"); - debug_event(adapter->erp_dbf, 3, &fsf_req, + debug_event(adapter->erp_dbf, 3, &erp_action->fsf_req, sizeof (unsigned long)); /* dismiss fsf_req of timed out/dismissed erp_action */ if (erp_action->status & (ZFCP_STATUS_ERP_DISMISSED | ZFCP_STATUS_ERP_TIMEDOUT)) { debug_text_event(adapter->erp_dbf, 3, "a_ca_disreq"); - fsf_req->status |= ZFCP_STATUS_FSFREQ_DISMISSED; + erp_action->fsf_req->status |= + ZFCP_STATUS_FSFREQ_DISMISSED; } if (erp_action->status & ZFCP_STATUS_ERP_TIMEDOUT) { ZFCP_LOG_NORMAL("error: erp step timed out " @@ -876,11 +872,11 @@ zfcp_erp_strategy_check_fsfreq(struct zf * then keep it running asynchronously and don't mess * with the association of erp_action and fsf_req. */ - if (fsf_req->status & (ZFCP_STATUS_FSFREQ_COMPLETED | + if (erp_action->fsf_req->status & + (ZFCP_STATUS_FSFREQ_COMPLETED | ZFCP_STATUS_FSFREQ_DISMISSED)) { /* forget about association between fsf_req and erp_action */ - fsf_req->erp_action = NULL; erp_action->fsf_req = NULL; } } else { @@ -894,8 +890,6 @@ zfcp_erp_strategy_check_fsfreq(struct zf spin_unlock(&adapter->req_list_lock); } else debug_text_event(adapter->erp_dbf, 3, "a_ca_noreq"); - - return retval; } /** @@ -3141,7 +3135,6 @@ zfcp_erp_action_cleanup(int action, stru break; case ZFCP_ERP_ACTION_REOPEN_ADAPTER: if (result != ZFCP_ERP_SUCCEEDED) { - struct zfcp_port *port; list_for_each_entry(port, &adapter->port_list_head, list) if (port->rport && !atomic_test_mask(ZFCP_STATUS_PORT_WKA, diff --git a/drivers/s390/scsi/zfcp_ext.h b/drivers/s390/scsi/zfcp_ext.h index b8794d7..01386ac 100644 --- a/drivers/s390/scsi/zfcp_ext.h +++ b/drivers/s390/scsi/zfcp_ext.h @@ -89,7 +89,7 @@ extern int zfcp_fsf_control_file(struct u32, u32, struct zfcp_sg_list *); extern void zfcp_fsf_start_timer(struct zfcp_fsf_req *, unsigned long); extern void zfcp_erp_start_timer(struct zfcp_fsf_req *); -extern int zfcp_fsf_req_dismiss_all(struct zfcp_adapter *); +extern void zfcp_fsf_req_dismiss_all(struct zfcp_adapter *); extern int zfcp_fsf_status_read(struct zfcp_adapter *, int); extern int zfcp_fsf_req_create(struct zfcp_adapter *, u32, int, mempool_t *, unsigned long *, struct zfcp_fsf_req **); @@ -119,8 +119,8 @@ extern int zfcp_adapter_scsi_register(s extern void zfcp_adapter_scsi_unregister(struct zfcp_adapter *); extern void zfcp_set_fcp_dl(struct fcp_cmnd_iu *, fcp_dl_t); extern char *zfcp_get_fcp_rsp_info_ptr(struct fcp_rsp_iu *); -extern void set_host_byte(u32 *, char); -extern void set_driver_byte(u32 *, char); +extern void set_host_byte(int *, char); +extern void set_driver_byte(int *, char); extern char *zfcp_get_fcp_sns_info_ptr(struct fcp_rsp_iu *); extern fcp_dl_t zfcp_get_fcp_dl(struct fcp_cmnd_iu *); diff --git a/drivers/s390/scsi/zfcp_fsf.c b/drivers/s390/scsi/zfcp_fsf.c index 067f151..ef16f7c 100644 --- a/drivers/s390/scsi/zfcp_fsf.c +++ b/drivers/s390/scsi/zfcp_fsf.c @@ -176,28 +176,25 @@ static void zfcp_fsf_req_dismiss(struct /** * zfcp_fsf_req_dismiss_all - dismiss all remaining fsf requests */ -int zfcp_fsf_req_dismiss_all(struct zfcp_adapter *adapter) +void zfcp_fsf_req_dismiss_all(struct zfcp_adapter *adapter) { struct zfcp_fsf_req *request, *tmp; unsigned long flags; + LIST_HEAD(remove_queue); unsigned int i, counter; spin_lock_irqsave(&adapter->req_list_lock, flags); atomic_set(&adapter->reqs_active, 0); - for (i=0; ireq_list[i])) - continue; - - counter = 0; - list_for_each_entry_safe(request, tmp, - &adapter->req_list[i], list) { - zfcp_fsf_req_dismiss(adapter, request, counter); - counter++; - } - } + for (i=0; ireq_list[i], &remove_queue); + spin_unlock_irqrestore(&adapter->req_list_lock, flags); - return 0; + counter = 0; + list_for_each_entry_safe(request, tmp, &remove_queue, list) { + zfcp_fsf_req_dismiss(adapter, request, counter); + counter++; + } } /* @@ -4563,7 +4560,7 @@ zfcp_fsf_req_sbal_check(unsigned long *f /* * set qtcb pointer in fsf_req and initialize QTCB */ -static inline void +static void zfcp_fsf_req_qtcb_init(struct zfcp_fsf_req *fsf_req) { if (likely(fsf_req->qtcb != NULL)) { diff --git a/drivers/s390/scsi/zfcp_qdio.c b/drivers/s390/scsi/zfcp_qdio.c index dbd9f48..1e12a78 100644 --- a/drivers/s390/scsi/zfcp_qdio.c +++ b/drivers/s390/scsi/zfcp_qdio.c @@ -21,22 +21,22 @@ #include "zfcp_ext.h" -static inline void zfcp_qdio_sbal_limit(struct zfcp_fsf_req *, int); +static void zfcp_qdio_sbal_limit(struct zfcp_fsf_req *, int); static inline volatile struct qdio_buffer_element *zfcp_qdio_sbale_get (struct zfcp_qdio_queue *, int, int); static inline volatile struct qdio_buffer_element *zfcp_qdio_sbale_resp (struct zfcp_fsf_req *, int, int); -static inline volatile struct qdio_buffer_element *zfcp_qdio_sbal_chain +static volatile struct qdio_buffer_element *zfcp_qdio_sbal_chain (struct zfcp_fsf_req *, unsigned long); -static inline volatile struct qdio_buffer_element *zfcp_qdio_sbale_next +static volatile struct qdio_buffer_element *zfcp_qdio_sbale_next (struct zfcp_fsf_req *, unsigned long); -static inline int zfcp_qdio_sbals_zero(struct zfcp_qdio_queue *, int, int); +static int zfcp_qdio_sbals_zero(struct zfcp_qdio_queue *, int, int); static inline int zfcp_qdio_sbals_wipe(struct zfcp_fsf_req *); -static inline void zfcp_qdio_sbale_fill +static void zfcp_qdio_sbale_fill (struct zfcp_fsf_req *, unsigned long, void *, int); -static inline int zfcp_qdio_sbals_from_segment +static int zfcp_qdio_sbals_from_segment (struct zfcp_fsf_req *, unsigned long, void *, unsigned long); -static inline int zfcp_qdio_sbals_from_buffer +static int zfcp_qdio_sbals_from_buffer (struct zfcp_fsf_req *, unsigned long, void *, unsigned long, int); static qdio_handler_t zfcp_qdio_request_handler; @@ -201,7 +201,7 @@ zfcp_qdio_allocate(struct zfcp_adapter * * returns: error flag * */ -static inline int +static int zfcp_qdio_handler_error_check(struct zfcp_adapter *adapter, unsigned int status, unsigned int qdio_error, unsigned int siga_error, int first_element, int elements_processed) @@ -462,7 +462,7 @@ zfcp_qdio_sbale_get(struct zfcp_qdio_que * zfcp_qdio_sbale_req - return pointer to SBALE of request_queue for * a struct zfcp_fsf_req */ -inline volatile struct qdio_buffer_element * +volatile struct qdio_buffer_element * zfcp_qdio_sbale_req(struct zfcp_fsf_req *fsf_req, int sbal, int sbale) { return zfcp_qdio_sbale_get(&fsf_req->adapter->request_queue, @@ -484,7 +484,7 @@ zfcp_qdio_sbale_resp(struct zfcp_fsf_req * zfcp_qdio_sbale_curr - return current SBALE on request_queue for * a struct zfcp_fsf_req */ -inline volatile struct qdio_buffer_element * +volatile struct qdio_buffer_element * zfcp_qdio_sbale_curr(struct zfcp_fsf_req *fsf_req) { return zfcp_qdio_sbale_req(fsf_req, fsf_req->sbal_curr, @@ -499,7 +499,7 @@ zfcp_qdio_sbale_curr(struct zfcp_fsf_req * * Note: We can assume at least one free SBAL in the request_queue when called. */ -static inline void +static void zfcp_qdio_sbal_limit(struct zfcp_fsf_req *fsf_req, int max_sbals) { int count = atomic_read(&fsf_req->adapter->request_queue.free_count); @@ -517,7 +517,7 @@ zfcp_qdio_sbal_limit(struct zfcp_fsf_req * * This function changes sbal_curr, sbale_curr, sbal_number of fsf_req. */ -static inline volatile struct qdio_buffer_element * +static volatile struct qdio_buffer_element * zfcp_qdio_sbal_chain(struct zfcp_fsf_req *fsf_req, unsigned long sbtype) { volatile struct qdio_buffer_element *sbale; @@ -554,7 +554,7 @@ zfcp_qdio_sbal_chain(struct zfcp_fsf_req /** * zfcp_qdio_sbale_next - switch to next SBALE, chain SBALs if needed */ -static inline volatile struct qdio_buffer_element * +static volatile struct qdio_buffer_element * zfcp_qdio_sbale_next(struct zfcp_fsf_req *fsf_req, unsigned long sbtype) { if (fsf_req->sbale_curr == ZFCP_LAST_SBALE_PER_SBAL) @@ -569,7 +569,7 @@ zfcp_qdio_sbale_next(struct zfcp_fsf_req * zfcp_qdio_sbals_zero - initialize SBALs between first and last in queue * with zero from */ -static inline int +static int zfcp_qdio_sbals_zero(struct zfcp_qdio_queue *queue, int first, int last) { struct qdio_buffer **buf = queue->buffer; @@ -603,7 +603,7 @@ zfcp_qdio_sbals_wipe(struct zfcp_fsf_req * zfcp_qdio_sbale_fill - set address and lenght in current SBALE * on request_queue */ -static inline void +static void zfcp_qdio_sbale_fill(struct zfcp_fsf_req *fsf_req, unsigned long sbtype, void *addr, int length) { @@ -624,7 +624,7 @@ zfcp_qdio_sbale_fill(struct zfcp_fsf_req * Alignment and length of the segment determine how many SBALEs are needed * for the memory segment. */ -static inline int +static int zfcp_qdio_sbals_from_segment(struct zfcp_fsf_req *fsf_req, unsigned long sbtype, void *start_addr, unsigned long total_length) { @@ -659,7 +659,7 @@ zfcp_qdio_sbals_from_segment(struct zfcp * @sg_count: number of elements in scatter-gather list * @max_sbals: upper bound for number of SBALs to be used */ -inline int +int zfcp_qdio_sbals_from_sg(struct zfcp_fsf_req *fsf_req, unsigned long sbtype, struct scatterlist *sg, int sg_count, int max_sbals) { @@ -707,7 +707,7 @@ out: * @length: length of buffer * @max_sbals: upper bound for number of SBALs to be used */ -static inline int +static int zfcp_qdio_sbals_from_buffer(struct zfcp_fsf_req *fsf_req, unsigned long sbtype, void *buffer, unsigned long length, int max_sbals) { @@ -728,7 +728,7 @@ zfcp_qdio_sbals_from_buffer(struct zfcp_ * @scsi_cmnd: either scatter-gather list or buffer contained herein is used * to fill SBALs */ -inline int +int zfcp_qdio_sbals_from_scsicmnd(struct zfcp_fsf_req *fsf_req, unsigned long sbtype, struct scsi_cmnd *scsi_cmnd) { diff --git a/drivers/s390/scsi/zfcp_scsi.c b/drivers/s390/scsi/zfcp_scsi.c index 452d96f..99db020 100644 --- a/drivers/s390/scsi/zfcp_scsi.c +++ b/drivers/s390/scsi/zfcp_scsi.c @@ -90,7 +90,7 @@ zfcp_get_fcp_sns_info_ptr(struct fcp_rsp return fcp_sns_info_ptr; } -fcp_dl_t * +static fcp_dl_t * zfcp_get_fcp_dl_ptr(struct fcp_cmnd_iu * fcp_cmd) { int additional_length = fcp_cmd->add_fcp_cdb_length << 2; @@ -124,19 +124,19 @@ zfcp_set_fcp_dl(struct fcp_cmnd_iu *fcp_ * regarding the specified byte */ static inline void -set_byte(u32 * result, char status, char pos) +set_byte(int *result, char status, char pos) { *result |= status << (pos * 8); } void -set_host_byte(u32 * result, char status) +set_host_byte(int *result, char status) { set_byte(result, status, 2); } void -set_driver_byte(u32 * result, char status) +set_driver_byte(int *result, char status) { set_byte(result, status, 3); } @@ -280,7 +280,7 @@ out: return retval; } -void +static void zfcp_scsi_command_sync_handler(struct scsi_cmnd *scpnt) { struct completion *wait = (struct completion *) scpnt->SCp.ptr; @@ -324,7 +324,7 @@ zfcp_scsi_command_sync(struct zfcp_unit * returns: 0 - success, SCSI command enqueued * !0 - failure */ -int +static int zfcp_scsi_queuecommand(struct scsi_cmnd *scpnt, void (*done) (struct scsi_cmnd *)) { @@ -380,7 +380,7 @@ zfcp_unit_lookup(struct zfcp_adapter *ad * will handle late commands. (Usually, the normal completion of late * commands is ignored with respect to the running abort operation.) */ -int zfcp_scsi_eh_abort_handler(struct scsi_cmnd *scpnt) +static int zfcp_scsi_eh_abort_handler(struct scsi_cmnd *scpnt) { struct Scsi_Host *scsi_host; struct zfcp_adapter *adapter; @@ -445,7 +445,7 @@ int zfcp_scsi_eh_abort_handler(struct sc return retval; } -int +static int zfcp_scsi_eh_device_reset_handler(struct scsi_cmnd *scpnt) { int retval; @@ -541,7 +541,7 @@ zfcp_task_management_function(struct zfc /** * zfcp_scsi_eh_host_reset_handler - handler for host and bus reset */ -int zfcp_scsi_eh_host_reset_handler(struct scsi_cmnd *scpnt) +static int zfcp_scsi_eh_host_reset_handler(struct scsi_cmnd *scpnt) { struct zfcp_unit *unit; struct zfcp_adapter *adapter; diff --git a/drivers/s390/sysinfo.c b/drivers/s390/sysinfo.c index 1e788e8..090743d 100644 --- a/drivers/s390/sysinfo.c +++ b/drivers/s390/sysinfo.c @@ -9,8 +9,14 @@ #include #include #include #include +#include #include +/* Sigh, math-emu. Don't ask. */ +#include +#include +#include + struct sysinfo_1_1_1 { char reserved_0[32]; char manufacturer[16]; @@ -198,7 +204,7 @@ static int stsi_1_2_2(struct sysinfo_1_2 * if the higher order 8 bits are not zero. Printing * a floating point number in the kernel is a no-no, * always print the number as 32 bit unsigned integer. - * The user-space needs to know about the stange + * The user-space needs to know about the strange * encoding of the alternate cpu capability. */ len += sprintf(page + len, "Capability: %u %u\n", @@ -351,3 +357,58 @@ static __init int create_proc_sysinfo(vo __initcall(create_proc_sysinfo); +/* + * CPU capability might have changed. Therefore recalculate loops_per_jiffy. + */ +void s390_adjust_jiffies(void) +{ + struct sysinfo_1_2_2 *info; + const unsigned int fmil = 0x4b189680; /* 1e7 as 32-bit float. */ + FP_DECL_S(SA); FP_DECL_S(SB); FP_DECL_S(SR); + FP_DECL_EX; + unsigned int capability; + + info = (void *) get_zeroed_page(GFP_KERNEL); + if (!info) + return; + + if (stsi(info, 1, 2, 2) != -ENOSYS) { + /* + * Major sigh. The cpu capability encoding is "special". + * If the first 9 bits of info->capability are 0 then it + * is a 32 bit unsigned integer in the range 0 .. 2^23. + * If the first 9 bits are != 0 then it is a 32 bit float. + * In addition a lower value indicates a proportionally + * higher cpu capacity. Bogomips are the other way round. + * To get to a halfway suitable number we divide 1e7 + * by the cpu capability number. Yes, that means a floating + * point division .. math-emu here we come :-) + */ + FP_UNPACK_SP(SA, &fmil); + if ((info->capability >> 23) == 0) + FP_FROM_INT_S(SB, info->capability, 32, int); + else + FP_UNPACK_SP(SB, &info->capability); + FP_DIV_S(SR, SA, SB); + FP_TO_INT_S(capability, SR, 32, 0); + } else + /* + * Really old machine without stsi block for basic + * cpu information. Report 42.0 bogomips. + */ + capability = 42; + loops_per_jiffy = capability * (500000/HZ); + free_page((unsigned long) info); +} + +/* + * calibrate the delay loop + */ +void __init calibrate_delay(void) +{ + s390_adjust_jiffies(); + /* Print the good old Bogomips line .. */ + printk(KERN_DEBUG "Calibrating delay loop (skipped)... " + "%lu.%02lu BogoMIPS preset\n", loops_per_jiffy/(500000/HZ), + (loops_per_jiffy/(5000/HZ)) % 100); +} diff --git a/drivers/sbus/char/bpp.c b/drivers/sbus/char/bpp.c index ac7d125..a39ee80 100644 --- a/drivers/sbus/char/bpp.c +++ b/drivers/sbus/char/bpp.c @@ -846,7 +846,7 @@ static int bpp_ioctl(struct inode *inode return errno; } -static struct file_operations bpp_fops = { +static const struct file_operations bpp_fops = { .owner = THIS_MODULE, .read = bpp_read, .write = bpp_write, diff --git a/drivers/sbus/char/cpwatchdog.c b/drivers/sbus/char/cpwatchdog.c index ad1c7db..022e869 100644 --- a/drivers/sbus/char/cpwatchdog.c +++ b/drivers/sbus/char/cpwatchdog.c @@ -20,7 +20,6 @@ #include #include #include #include -#include #include #include #include @@ -459,7 +458,7 @@ static irqreturn_t wd_interrupt(int irq, return IRQ_HANDLED; } -static struct file_operations wd_fops = { +static const struct file_operations wd_fops = { .owner = THIS_MODULE, .ioctl = wd_ioctl, .compat_ioctl = wd_compat_ioctl, diff --git a/drivers/sbus/char/display7seg.c b/drivers/sbus/char/display7seg.c index a4909e0..2d14a29 100644 --- a/drivers/sbus/char/display7seg.c +++ b/drivers/sbus/char/display7seg.c @@ -166,7 +166,7 @@ static long d7s_ioctl(struct file *file, return error; } -static struct file_operations d7s_fops = { +static const struct file_operations d7s_fops = { .owner = THIS_MODULE, .unlocked_ioctl = d7s_ioctl, .compat_ioctl = d7s_ioctl, diff --git a/drivers/sbus/char/envctrl.c b/drivers/sbus/char/envctrl.c index fff4660..2cea4f5 100644 --- a/drivers/sbus/char/envctrl.c +++ b/drivers/sbus/char/envctrl.c @@ -705,7 +705,7 @@ envctrl_release(struct inode *inode, str return 0; } -static struct file_operations envctrl_fops = { +static const struct file_operations envctrl_fops = { .owner = THIS_MODULE, .read = envctrl_read, .unlocked_ioctl = envctrl_ioctl, diff --git a/drivers/sbus/char/flash.c b/drivers/sbus/char/flash.c index fa2418f..6e99507 100644 --- a/drivers/sbus/char/flash.c +++ b/drivers/sbus/char/flash.c @@ -142,7 +142,7 @@ flash_release(struct inode *inode, struc return 0; } -static struct file_operations flash_fops = { +static const struct file_operations flash_fops = { /* no write to the Flash, use mmap * and play flash dependent tricks. */ diff --git a/drivers/sbus/char/jsflash.c b/drivers/sbus/char/jsflash.c index 14631ac..512857a 100644 --- a/drivers/sbus/char/jsflash.c +++ b/drivers/sbus/char/jsflash.c @@ -431,7 +431,7 @@ static int jsf_release(struct inode *ino return 0; } -static struct file_operations jsf_fops = { +static const struct file_operations jsf_fops = { .owner = THIS_MODULE, .llseek = jsf_lseek, .read = jsf_read, diff --git a/drivers/sbus/char/openprom.c b/drivers/sbus/char/openprom.c index 4e2a0e2..eec28c1 100644 --- a/drivers/sbus/char/openprom.c +++ b/drivers/sbus/char/openprom.c @@ -31,7 +31,6 @@ #include #include -#include #include #include #include @@ -704,7 +703,7 @@ static int openprom_release(struct inode return 0; } -static struct file_operations openprom_fops = { +static const struct file_operations openprom_fops = { .owner = THIS_MODULE, .llseek = no_llseek, .ioctl = openprom_ioctl, diff --git a/drivers/sbus/char/riowatchdog.c b/drivers/sbus/char/riowatchdog.c index 2a9cc82..a2fc6b8 100644 --- a/drivers/sbus/char/riowatchdog.c +++ b/drivers/sbus/char/riowatchdog.c @@ -193,7 +193,7 @@ static ssize_t riowd_write(struct file * return 0; } -static struct file_operations riowd_fops = { +static const struct file_operations riowd_fops = { .owner = THIS_MODULE, .ioctl = riowd_ioctl, .open = riowd_open, diff --git a/drivers/sbus/char/rtc.c b/drivers/sbus/char/rtc.c index 9b988ba..94d1858 100644 --- a/drivers/sbus/char/rtc.c +++ b/drivers/sbus/char/rtc.c @@ -233,7 +233,7 @@ static int rtc_release(struct inode *ino return 0; } -static struct file_operations rtc_fops = { +static const struct file_operations rtc_fops = { .owner = THIS_MODULE, .llseek = no_llseek, .ioctl = rtc_ioctl, diff --git a/drivers/sbus/char/uctrl.c b/drivers/sbus/char/uctrl.c index b30372f..45cf5bc 100644 --- a/drivers/sbus/char/uctrl.c +++ b/drivers/sbus/char/uctrl.c @@ -5,7 +5,6 @@ */ #include -#include #include #include #include @@ -224,7 +223,7 @@ static irqreturn_t uctrl_interrupt(int i return IRQ_HANDLED; } -static struct file_operations uctrl_fops = { +static const struct file_operations uctrl_fops = { .owner = THIS_MODULE, .llseek = no_llseek, .ioctl = uctrl_ioctl, diff --git a/drivers/sbus/char/vfc_dev.c b/drivers/sbus/char/vfc_dev.c index 386e7de..8bfb67c 100644 --- a/drivers/sbus/char/vfc_dev.c +++ b/drivers/sbus/char/vfc_dev.c @@ -19,7 +19,6 @@ #include #include #include #include -#include #include #include #include @@ -44,7 +43,7 @@ #endif #include "vfc.h" #include -static struct file_operations vfc_fops; +static const struct file_operations vfc_fops; struct vfc_dev **vfc_dev_lst; static char vfcstr[]="vfc"; static unsigned char saa9051_init_array[VFC_SAA9051_NR] = { @@ -633,7 +632,7 @@ static int vfc_mmap(struct file *file, s } -static struct file_operations vfc_fops = { +static const struct file_operations vfc_fops = { .owner = THIS_MODULE, .llseek = no_llseek, .ioctl = vfc_ioctl, diff --git a/drivers/sbus/sbus.c b/drivers/sbus/sbus.c index 98fcbb3..6349dd6 100644 --- a/drivers/sbus/sbus.c +++ b/drivers/sbus/sbus.c @@ -7,6 +7,7 @@ #include #include #include #include +#include #include #include @@ -17,13 +18,25 @@ #include #include #include +static ssize_t +show_sbusobppath_attr(struct device * dev, struct device_attribute * attr, char * buf) +{ + struct sbus_dev *sbus; + + sbus = to_sbus_device(dev); + + return snprintf (buf, PAGE_SIZE, "%s\n", sbus->ofdev.node->full_name); +} + +static DEVICE_ATTR(obppath, S_IRUSR | S_IRGRP | S_IROTH, show_sbusobppath_attr, NULL); + struct sbus_bus *sbus_root; static void __init fill_sbus_device(struct device_node *dp, struct sbus_dev *sdev) { unsigned long base; void *pval; - int len; + int len, err; sdev->prom_node = dp->node; strcpy(sdev->prom_name, dp->name); @@ -66,6 +79,9 @@ static void __init fill_sbus_device(stru if (of_device_register(&sdev->ofdev) != 0) printk(KERN_DEBUG "sbus: device registration error for %s!\n", dp->path_component_name); + + /* WE HAVE BEEN INVADED BY ALIENS! */ + err = sysfs_create_file(&sdev->ofdev.dev.kobj, &dev_attr_obppath.attr); } static void __init sbus_bus_ranges_init(struct device_node *dp, struct sbus_bus *sbus) diff --git a/drivers/scsi/3w-9xxx.c b/drivers/scsi/3w-9xxx.c index b091a0f..eb766c3 100644 --- a/drivers/scsi/3w-9xxx.c +++ b/drivers/scsi/3w-9xxx.c @@ -197,7 +197,7 @@ static struct class_device_attribute *tw }; /* File operations struct for character device */ -static struct file_operations twa_fops = { +static const struct file_operations twa_fops = { .owner = THIS_MODULE, .ioctl = twa_chrdev_ioctl, .open = twa_chrdev_open, diff --git a/drivers/scsi/3w-xxxx.c b/drivers/scsi/3w-xxxx.c index e1b44d6..bf5d63e 100644 --- a/drivers/scsi/3w-xxxx.c +++ b/drivers/scsi/3w-xxxx.c @@ -1040,7 +1040,7 @@ static int tw_chrdev_open(struct inode * } /* End tw_chrdev_open() */ /* File operations struct for character device */ -static struct file_operations tw_fops = { +static const struct file_operations tw_fops = { .owner = THIS_MODULE, .ioctl = tw_chrdev_ioctl, .open = tw_chrdev_open, diff --git a/drivers/scsi/53c700.c b/drivers/scsi/53c700.c index 68103e5..cb02656 100644 --- a/drivers/scsi/53c700.c +++ b/drivers/scsi/53c700.c @@ -121,7 +121,6 @@ #include #include #include #include -#include #include #include #include @@ -667,12 +666,30 @@ NCR_700_chip_setup(struct Scsi_Host *hos __u8 min_xferp = (hostdata->chip710 ? NCR_710_MIN_XFERP : NCR_700_MIN_XFERP); if(hostdata->chip710) { - __u8 burst_disable = hostdata->burst_disable - ? BURST_DISABLE : 0; + __u8 burst_disable = 0; + __u8 burst_length = 0; + + switch (hostdata->burst_length) { + case 1: + burst_length = BURST_LENGTH_1; + break; + case 2: + burst_length = BURST_LENGTH_2; + break; + case 4: + burst_length = BURST_LENGTH_4; + break; + case 8: + burst_length = BURST_LENGTH_8; + break; + default: + burst_disable = BURST_DISABLE; + break; + } dcntl_extra = COMPAT_700_MODE; NCR_700_writeb(dcntl_extra, host, DCNTL_REG); - NCR_700_writeb(BURST_LENGTH_8 | hostdata->dmode_extra, + NCR_700_writeb(burst_length | hostdata->dmode_extra, host, DMODE_710_REG); NCR_700_writeb(burst_disable | (hostdata->differential ? DIFF : 0), host, CTEST7_REG); diff --git a/drivers/scsi/53c700.h b/drivers/scsi/53c700.h index f38822d..841e1bb 100644 --- a/drivers/scsi/53c700.h +++ b/drivers/scsi/53c700.h @@ -203,7 +203,7 @@ #ifdef CONFIG_53C700_LE_ON_BE __u32 force_le_on_be:1; #endif __u32 chip710:1; /* set if really a 710 not 700 */ - __u32 burst_disable:1; /* set to 1 to disable 710 bursting */ + __u32 burst_length:4; /* set to 0 to disable 710 bursting */ /* NOTHING BELOW HERE NEEDS ALTERING */ __u32 fast:1; /* if we can alter the SCSI bus clock diff --git a/drivers/scsi/53c7xx.c b/drivers/scsi/53c7xx.c index 640536e..93b41f4 100644 --- a/drivers/scsi/53c7xx.c +++ b/drivers/scsi/53c7xx.c @@ -3099,7 +3099,6 @@ #endif real = get_zeroed_page(GFP_ATOMIC); if (real == 0) return NULL; - memset((void *)real, 0, 4096); cache_push(virt_to_phys((void *)real), 4096); cache_clear(virt_to_phys((void *)real), 4096); kernel_set_cachemode((void *)real, 4096, IOMAP_NOCACHE_SER); @@ -4400,7 +4399,7 @@ #ifdef NEW_ABORT * account the current synchronous offset) */ - sstat = (NCR53c8x0_read8 (SSTAT2_REG); + sstat = NCR53c8x0_read8 (SSTAT2_REG); offset = OFFSET (sstat & SSTAT2_FF_MASK) >> SSTAT2_FF_SHIFT; phase = sstat & SSTAT2_PHASE_MASK; @@ -5423,7 +5422,7 @@ insn_to_offset (Scsi_Cmnd *cmd, u32 *ins --buffers, offset += segment->length, ++segment) #if 0 printk("scsi%d: comparing 0x%p to 0x%p\n", - cmd->device->host->host_no, saved, page_address(segment->page+segment->offset); + cmd->device->host->host_no, saved, page_address(segment->page+segment->offset)); #else ; #endif diff --git a/drivers/scsi/BusLogic.c b/drivers/scsi/BusLogic.c index 3075204..e874b89 100644 --- a/drivers/scsi/BusLogic.c +++ b/drivers/scsi/BusLogic.c @@ -192,7 +192,7 @@ static void BusLogic_InitializeCCBs(stru BusLogic_CreateInitialCCBs allocates the initial CCBs for Host Adapter. */ -static boolean __init BusLogic_CreateInitialCCBs(struct BusLogic_HostAdapter *HostAdapter) +static bool __init BusLogic_CreateInitialCCBs(struct BusLogic_HostAdapter *HostAdapter) { int BlockSize = BusLogic_CCB_AllocationGroupSize * sizeof(struct BusLogic_CCB); void *BlockPointer; @@ -238,7 +238,7 @@ static void BusLogic_DestroyCCBs(struct multiple host adapters share the same IRQ Channel. */ -static void BusLogic_CreateAdditionalCCBs(struct BusLogic_HostAdapter *HostAdapter, int AdditionalCCBs, boolean SuccessMessageP) +static void BusLogic_CreateAdditionalCCBs(struct BusLogic_HostAdapter *HostAdapter, int AdditionalCCBs, bool SuccessMessageP) { int BlockSize = BusLogic_CCB_AllocationGroupSize * sizeof(struct BusLogic_CCB); int PreviouslyAllocated = HostAdapter->AllocatedCCBs; @@ -362,10 +362,8 @@ static int BusLogic_Command(struct BusLo interrupt could occur if the IRQ Channel was previously enabled by another BusLogic Host Adapter or another driver sharing the same IRQ Channel. */ - if (!HostAdapter->IRQ_ChannelAcquired) { + if (!HostAdapter->IRQ_ChannelAcquired) local_irq_save(ProcessorFlags); - local_irq_disable(); - } /* Wait for the Host Adapter Ready bit to be set and the Command/Parameter Register Busy bit to be reset in the Status Register. @@ -639,9 +637,9 @@ static int __init BusLogic_InitializeMul struct BusLogic_ProbeInfo *PrimaryProbeInfo = &BusLogic_ProbeInfoList[BusLogic_ProbeInfoCount]; int NonPrimaryPCIMultiMasterIndex = BusLogic_ProbeInfoCount + 1; int NonPrimaryPCIMultiMasterCount = 0, PCIMultiMasterCount = 0; - boolean ForceBusDeviceScanningOrder = false; - boolean ForceBusDeviceScanningOrderChecked = false; - boolean StandardAddressSeen[6]; + bool ForceBusDeviceScanningOrder = false; + bool ForceBusDeviceScanningOrderChecked = false; + bool StandardAddressSeen[6]; struct pci_dev *PCI_Device = NULL; int i; if (BusLogic_ProbeInfoCount >= BusLogic_MaxHostAdapters) @@ -1011,7 +1009,7 @@ #endif /* CONFIG_PCI */ BusLogic_Failure prints a standardized error message, and then returns false. */ -static boolean BusLogic_Failure(struct BusLogic_HostAdapter *HostAdapter, char *ErrorMessage) +static bool BusLogic_Failure(struct BusLogic_HostAdapter *HostAdapter, char *ErrorMessage) { BusLogic_AnnounceDriver(HostAdapter); if (HostAdapter->HostAdapterBusType == BusLogic_PCI_Bus) { @@ -1030,7 +1028,7 @@ static boolean BusLogic_Failure(struct B BusLogic_ProbeHostAdapter probes for a BusLogic Host Adapter. */ -static boolean __init BusLogic_ProbeHostAdapter(struct BusLogic_HostAdapter *HostAdapter) +static bool __init BusLogic_ProbeHostAdapter(struct BusLogic_HostAdapter *HostAdapter) { union BusLogic_StatusRegister StatusRegister; union BusLogic_InterruptRegister InterruptRegister; @@ -1101,8 +1099,8 @@ static boolean __init BusLogic_ProbeHost SCSI Bus Reset. */ -static boolean BusLogic_HardwareResetHostAdapter(struct BusLogic_HostAdapter - *HostAdapter, boolean HardReset) +static bool BusLogic_HardwareResetHostAdapter(struct BusLogic_HostAdapter + *HostAdapter, bool HardReset) { union BusLogic_StatusRegister StatusRegister; int TimeoutCounter; @@ -1205,11 +1203,11 @@ static boolean BusLogic_HardwareResetHos Host Adapter. */ -static boolean __init BusLogic_CheckHostAdapter(struct BusLogic_HostAdapter *HostAdapter) +static bool __init BusLogic_CheckHostAdapter(struct BusLogic_HostAdapter *HostAdapter) { struct BusLogic_ExtendedSetupInformation ExtendedSetupInformation; unsigned char RequestedReplyLength; - boolean Result = true; + bool Result = true; /* FlashPoint Host Adapters do not require this protection. */ @@ -1239,7 +1237,7 @@ static boolean __init BusLogic_CheckHost from Host Adapter and initializes the Host Adapter structure. */ -static boolean __init BusLogic_ReadHostAdapterConfiguration(struct BusLogic_HostAdapter +static bool __init BusLogic_ReadHostAdapterConfiguration(struct BusLogic_HostAdapter *HostAdapter) { struct BusLogic_BoardID BoardID; @@ -1686,14 +1684,14 @@ static boolean __init BusLogic_ReadHostA Host Adapter. */ -static boolean __init BusLogic_ReportHostAdapterConfiguration(struct BusLogic_HostAdapter +static bool __init BusLogic_ReportHostAdapterConfiguration(struct BusLogic_HostAdapter *HostAdapter) { unsigned short AllTargetsMask = (1 << HostAdapter->MaxTargetDevices) - 1; unsigned short SynchronousPermitted, FastPermitted; unsigned short UltraPermitted, WidePermitted; unsigned short DisconnectPermitted, TaggedQueuingPermitted; - boolean CommonSynchronousNegotiation, CommonTaggedQueueDepth; + bool CommonSynchronousNegotiation, CommonTaggedQueueDepth; char SynchronousString[BusLogic_MaxTargetDevices + 1]; char WideString[BusLogic_MaxTargetDevices + 1]; char DisconnectString[BusLogic_MaxTargetDevices + 1]; @@ -1835,7 +1833,7 @@ static boolean __init BusLogic_ReportHos Host Adapter. */ -static boolean __init BusLogic_AcquireResources(struct BusLogic_HostAdapter *HostAdapter) +static bool __init BusLogic_AcquireResources(struct BusLogic_HostAdapter *HostAdapter) { if (HostAdapter->IRQ_Channel == 0) { BusLogic_Error("NO LEGAL INTERRUPT CHANNEL ASSIGNED - DETACHING\n", HostAdapter); @@ -1903,7 +1901,7 @@ static void BusLogic_ReleaseResources(st of the Host Adapter from its initial power on or hard reset state. */ -static boolean BusLogic_InitializeHostAdapter(struct BusLogic_HostAdapter +static bool BusLogic_InitializeHostAdapter(struct BusLogic_HostAdapter *HostAdapter) { struct BusLogic_ExtendedMailboxRequest ExtendedMailboxRequest; @@ -2002,7 +2000,7 @@ static boolean BusLogic_InitializeHostAd through Host Adapter. */ -static boolean __init BusLogic_TargetDeviceInquiry(struct BusLogic_HostAdapter +static bool __init BusLogic_TargetDeviceInquiry(struct BusLogic_HostAdapter *HostAdapter) { u16 InstalledDevices; @@ -2739,7 +2737,7 @@ static irqreturn_t BusLogic_InterruptHan already have been acquired by the caller. */ -static boolean BusLogic_WriteOutgoingMailbox(struct BusLogic_HostAdapter +static bool BusLogic_WriteOutgoingMailbox(struct BusLogic_HostAdapter *HostAdapter, enum BusLogic_ActionCode ActionCode, struct BusLogic_CCB *CCB) { struct BusLogic_OutgoingMailbox *NextOutgoingMailbox; @@ -3058,7 +3056,7 @@ #endif currently executing SCSI Commands as having been Reset. */ -static int BusLogic_ResetHostAdapter(struct BusLogic_HostAdapter *HostAdapter, boolean HardReset) +static int BusLogic_ResetHostAdapter(struct BusLogic_HostAdapter *HostAdapter, bool HardReset) { struct BusLogic_CCB *CCB; int TargetID; @@ -3309,7 +3307,7 @@ Target Requested Completed Requested Co static void BusLogic_Message(enum BusLogic_MessageLevel MessageLevel, char *Format, struct BusLogic_HostAdapter *HostAdapter, ...) { static char Buffer[BusLogic_LineBufferSize]; - static boolean BeginningOfLine = true; + static bool BeginningOfLine = true; va_list Arguments; int Length = 0; va_start(Arguments, HostAdapter); @@ -3347,7 +3345,7 @@ static void BusLogic_Message(enum BusLog and updates the pointer if the keyword is recognized and false otherwise. */ -static boolean __init BusLogic_ParseKeyword(char **StringPointer, char *Keyword) +static bool __init BusLogic_ParseKeyword(char **StringPointer, char *Keyword) { char *Pointer = *StringPointer; while (*Keyword != '\0') { diff --git a/drivers/scsi/BusLogic.h b/drivers/scsi/BusLogic.h index cca6d45..bfbfb5c 100644 --- a/drivers/scsi/BusLogic.h +++ b/drivers/scsi/BusLogic.h @@ -234,12 +234,6 @@ enum BusLogic_BIOS_DiskGeometryTranslati /* - Define a Boolean data type. -*/ - -typedef bool boolean; - -/* Define a 10^18 Statistics Byte Counter data type. */ @@ -269,19 +263,19 @@ struct BusLogic_ProbeInfo { */ struct BusLogic_ProbeOptions { - boolean NoProbe:1; /* Bit 0 */ - boolean NoProbeISA:1; /* Bit 1 */ - boolean NoProbePCI:1; /* Bit 2 */ - boolean NoSortPCI:1; /* Bit 3 */ - boolean MultiMasterFirst:1; /* Bit 4 */ - boolean FlashPointFirst:1; /* Bit 5 */ - boolean LimitedProbeISA:1; /* Bit 6 */ - boolean Probe330:1; /* Bit 7 */ - boolean Probe334:1; /* Bit 8 */ - boolean Probe230:1; /* Bit 9 */ - boolean Probe234:1; /* Bit 10 */ - boolean Probe130:1; /* Bit 11 */ - boolean Probe134:1; /* Bit 12 */ + bool NoProbe:1; /* Bit 0 */ + bool NoProbeISA:1; /* Bit 1 */ + bool NoProbePCI:1; /* Bit 2 */ + bool NoSortPCI:1; /* Bit 3 */ + bool MultiMasterFirst:1;/* Bit 4 */ + bool FlashPointFirst:1; /* Bit 5 */ + bool LimitedProbeISA:1; /* Bit 6 */ + bool Probe330:1; /* Bit 7 */ + bool Probe334:1; /* Bit 8 */ + bool Probe230:1; /* Bit 9 */ + bool Probe234:1; /* Bit 10 */ + bool Probe130:1; /* Bit 11 */ + bool Probe134:1; /* Bit 12 */ }; /* @@ -289,10 +283,10 @@ struct BusLogic_ProbeOptions { */ struct BusLogic_GlobalOptions { - boolean TraceProbe:1; /* Bit 0 */ - boolean TraceHardwareReset:1; /* Bit 1 */ - boolean TraceConfiguration:1; /* Bit 2 */ - boolean TraceErrors:1; /* Bit 3 */ + bool TraceProbe:1; /* Bit 0 */ + bool TraceHardwareReset:1; /* Bit 1 */ + bool TraceConfiguration:1; /* Bit 2 */ + bool TraceErrors:1; /* Bit 3 */ }; /* @@ -300,7 +294,7 @@ struct BusLogic_GlobalOptions { */ struct BusLogic_LocalOptions { - boolean InhibitTargetInquiry:1; /* Bit 0 */ + bool InhibitTargetInquiry:1; /* Bit 0 */ }; /* @@ -322,10 +316,10 @@ union BusLogic_ControlRegister { unsigned char All; struct { unsigned char:4; /* Bits 0-3 */ - boolean SCSIBusReset:1; /* Bit 4 */ - boolean InterruptReset:1; /* Bit 5 */ - boolean SoftReset:1; /* Bit 6 */ - boolean HardReset:1; /* Bit 7 */ + bool SCSIBusReset:1; /* Bit 4 */ + bool InterruptReset:1; /* Bit 5 */ + bool SoftReset:1; /* Bit 6 */ + bool HardReset:1; /* Bit 7 */ } cr; }; @@ -336,14 +330,14 @@ union BusLogic_ControlRegister { union BusLogic_StatusRegister { unsigned char All; struct { - boolean CommandInvalid:1; /* Bit 0 */ - boolean Reserved:1; /* Bit 1 */ - boolean DataInRegisterReady:1; /* Bit 2 */ - boolean CommandParameterRegisterBusy:1; /* Bit 3 */ - boolean HostAdapterReady:1; /* Bit 4 */ - boolean InitializationRequired:1; /* Bit 5 */ - boolean DiagnosticFailure:1; /* Bit 6 */ - boolean DiagnosticActive:1; /* Bit 7 */ + bool CommandInvalid:1; /* Bit 0 */ + bool Reserved:1; /* Bit 1 */ + bool DataInRegisterReady:1; /* Bit 2 */ + bool CommandParameterRegisterBusy:1; /* Bit 3 */ + bool HostAdapterReady:1; /* Bit 4 */ + bool InitializationRequired:1; /* Bit 5 */ + bool DiagnosticFailure:1; /* Bit 6 */ + bool DiagnosticActive:1; /* Bit 7 */ } sr; }; @@ -354,12 +348,12 @@ union BusLogic_StatusRegister { union BusLogic_InterruptRegister { unsigned char All; struct { - boolean IncomingMailboxLoaded:1; /* Bit 0 */ - boolean OutgoingMailboxAvailable:1; /* Bit 1 */ - boolean CommandComplete:1; /* Bit 2 */ - boolean ExternalBusReset:1; /* Bit 3 */ + bool IncomingMailboxLoaded:1; /* Bit 0 */ + bool OutgoingMailboxAvailable:1;/* Bit 1 */ + bool CommandComplete:1; /* Bit 2 */ + bool ExternalBusReset:1; /* Bit 3 */ unsigned char Reserved:3; /* Bits 4-6 */ - boolean InterruptValid:1; /* Bit 7 */ + bool InterruptValid:1; /* Bit 7 */ } ir; }; @@ -373,7 +367,7 @@ union BusLogic_GeometryRegister { enum BusLogic_BIOS_DiskGeometryTranslation Drive0Geometry:2; /* Bits 0-1 */ enum BusLogic_BIOS_DiskGeometryTranslation Drive1Geometry:2; /* Bits 2-3 */ unsigned char:3; /* Bits 4-6 */ - boolean ExtendedTranslationEnabled:1; /* Bit 7 */ + bool ExtendedTranslationEnabled:1; /* Bit 7 */ } gr; }; @@ -445,16 +439,16 @@ struct BusLogic_BoardID { struct BusLogic_Configuration { unsigned char:5; /* Byte 0 Bits 0-4 */ - boolean DMA_Channel5:1; /* Byte 0 Bit 5 */ - boolean DMA_Channel6:1; /* Byte 0 Bit 6 */ - boolean DMA_Channel7:1; /* Byte 0 Bit 7 */ - boolean IRQ_Channel9:1; /* Byte 1 Bit 0 */ - boolean IRQ_Channel10:1; /* Byte 1 Bit 1 */ - boolean IRQ_Channel11:1; /* Byte 1 Bit 2 */ - boolean IRQ_Channel12:1; /* Byte 1 Bit 3 */ + bool DMA_Channel5:1; /* Byte 0 Bit 5 */ + bool DMA_Channel6:1; /* Byte 0 Bit 6 */ + bool DMA_Channel7:1; /* Byte 0 Bit 7 */ + bool IRQ_Channel9:1; /* Byte 1 Bit 0 */ + bool IRQ_Channel10:1; /* Byte 1 Bit 1 */ + bool IRQ_Channel11:1; /* Byte 1 Bit 2 */ + bool IRQ_Channel12:1; /* Byte 1 Bit 3 */ unsigned char:1; /* Byte 1 Bit 4 */ - boolean IRQ_Channel14:1; /* Byte 1 Bit 5 */ - boolean IRQ_Channel15:1; /* Byte 1 Bit 6 */ + bool IRQ_Channel14:1; /* Byte 1 Bit 5 */ + bool IRQ_Channel15:1; /* Byte 1 Bit 6 */ unsigned char:1; /* Byte 1 Bit 7 */ unsigned char HostAdapterID:4; /* Byte 2 Bits 0-3 */ unsigned char:4; /* Byte 2 Bits 4-7 */ @@ -467,12 +461,12 @@ struct BusLogic_Configuration { struct BusLogic_SynchronousValue { unsigned char Offset:4; /* Bits 0-3 */ unsigned char TransferPeriod:3; /* Bits 4-6 */ - boolean Synchronous:1; /* Bit 7 */ + bool Synchronous:1; /* Bit 7 */ }; struct BusLogic_SetupInformation { - boolean SynchronousInitiationEnabled:1; /* Byte 0 Bit 0 */ - boolean ParityCheckingEnabled:1; /* Byte 0 Bit 1 */ + bool SynchronousInitiationEnabled:1; /* Byte 0 Bit 0 */ + bool ParityCheckingEnabled:1; /* Byte 0 Bit 1 */ unsigned char:6; /* Byte 0 Bits 2-7 */ unsigned char BusTransferRate; /* Byte 1 */ unsigned char PreemptTimeOnBus; /* Byte 2 */ @@ -523,13 +517,13 @@ enum BusLogic_ISACompatibleIOPort { struct BusLogic_PCIHostAdapterInformation { enum BusLogic_ISACompatibleIOPort ISACompatibleIOPort; /* Byte 0 */ unsigned char PCIAssignedIRQChannel; /* Byte 1 */ - boolean LowByteTerminated:1; /* Byte 2 Bit 0 */ - boolean HighByteTerminated:1; /* Byte 2 Bit 1 */ + bool LowByteTerminated:1; /* Byte 2 Bit 0 */ + bool HighByteTerminated:1; /* Byte 2 Bit 1 */ unsigned char:2; /* Byte 2 Bits 2-3 */ - boolean JP1:1; /* Byte 2 Bit 4 */ - boolean JP2:1; /* Byte 2 Bit 5 */ - boolean JP3:1; /* Byte 2 Bit 6 */ - boolean GenericInfoValid:1; /* Byte 2 Bit 7 */ + bool JP1:1; /* Byte 2 Bit 4 */ + bool JP2:1; /* Byte 2 Bit 5 */ + bool JP3:1; /* Byte 2 Bit 6 */ + bool GenericInfoValid:1;/* Byte 2 Bit 7 */ unsigned char:8; /* Byte 3 */ }; @@ -545,17 +539,17 @@ struct BusLogic_ExtendedSetupInformation u32 BaseMailboxAddress; /* Bytes 5-8 */ struct { unsigned char:2; /* Byte 9 Bits 0-1 */ - boolean FastOnEISA:1; /* Byte 9 Bit 2 */ + bool FastOnEISA:1; /* Byte 9 Bit 2 */ unsigned char:3; /* Byte 9 Bits 3-5 */ - boolean LevelSensitiveInterrupt:1; /* Byte 9 Bit 6 */ + bool LevelSensitiveInterrupt:1; /* Byte 9 Bit 6 */ unsigned char:1; /* Byte 9 Bit 7 */ } Misc; unsigned char FirmwareRevision[3]; /* Bytes 10-12 */ - boolean HostWideSCSI:1; /* Byte 13 Bit 0 */ - boolean HostDifferentialSCSI:1; /* Byte 13 Bit 1 */ - boolean HostSupportsSCAM:1; /* Byte 13 Bit 2 */ - boolean HostUltraSCSI:1; /* Byte 13 Bit 3 */ - boolean HostSmartTermination:1; /* Byte 13 Bit 4 */ + bool HostWideSCSI:1; /* Byte 13 Bit 0 */ + bool HostDifferentialSCSI:1; /* Byte 13 Bit 1 */ + bool HostSupportsSCAM:1; /* Byte 13 Bit 2 */ + bool HostUltraSCSI:1; /* Byte 13 Bit 3 */ + bool HostSmartTermination:1; /* Byte 13 Bit 4 */ unsigned char:3; /* Byte 13 Bits 5-7 */ } PACKED; @@ -590,35 +584,35 @@ struct BusLogic_AutoSCSIData { unsigned char InformationByteCount; /* Byte 2 */ unsigned char HostAdapterType[6]; /* Bytes 3-8 */ unsigned char:8; /* Byte 9 */ - boolean FloppyEnabled:1; /* Byte 10 Bit 0 */ - boolean FloppySecondary:1; /* Byte 10 Bit 1 */ - boolean LevelSensitiveInterrupt:1; /* Byte 10 Bit 2 */ + bool FloppyEnabled:1; /* Byte 10 Bit 0 */ + bool FloppySecondary:1; /* Byte 10 Bit 1 */ + bool LevelSensitiveInterrupt:1; /* Byte 10 Bit 2 */ unsigned char:2; /* Byte 10 Bits 3-4 */ unsigned char SystemRAMAreaForBIOS:3; /* Byte 10 Bits 5-7 */ unsigned char DMA_Channel:7; /* Byte 11 Bits 0-6 */ - boolean DMA_AutoConfiguration:1; /* Byte 11 Bit 7 */ + bool DMA_AutoConfiguration:1; /* Byte 11 Bit 7 */ unsigned char IRQ_Channel:7; /* Byte 12 Bits 0-6 */ - boolean IRQ_AutoConfiguration:1; /* Byte 12 Bit 7 */ + bool IRQ_AutoConfiguration:1; /* Byte 12 Bit 7 */ unsigned char DMA_TransferRate; /* Byte 13 */ unsigned char SCSI_ID; /* Byte 14 */ - boolean LowByteTerminated:1; /* Byte 15 Bit 0 */ - boolean ParityCheckingEnabled:1; /* Byte 15 Bit 1 */ - boolean HighByteTerminated:1; /* Byte 15 Bit 2 */ - boolean NoisyCablingEnvironment:1; /* Byte 15 Bit 3 */ - boolean FastSynchronousNegotiation:1; /* Byte 15 Bit 4 */ - boolean BusResetEnabled:1; /* Byte 15 Bit 5 */ - boolean:1; /* Byte 15 Bit 6 */ - boolean ActiveNegationEnabled:1; /* Byte 15 Bit 7 */ + bool LowByteTerminated:1; /* Byte 15 Bit 0 */ + bool ParityCheckingEnabled:1; /* Byte 15 Bit 1 */ + bool HighByteTerminated:1; /* Byte 15 Bit 2 */ + bool NoisyCablingEnvironment:1; /* Byte 15 Bit 3 */ + bool FastSynchronousNegotiation:1; /* Byte 15 Bit 4 */ + bool BusResetEnabled:1; /* Byte 15 Bit 5 */ + bool:1; /* Byte 15 Bit 6 */ + bool ActiveNegationEnabled:1; /* Byte 15 Bit 7 */ unsigned char BusOnDelay; /* Byte 16 */ unsigned char BusOffDelay; /* Byte 17 */ - boolean HostAdapterBIOSEnabled:1; /* Byte 18 Bit 0 */ - boolean BIOSRedirectionOfINT19Enabled:1; /* Byte 18 Bit 1 */ - boolean ExtendedTranslationEnabled:1; /* Byte 18 Bit 2 */ - boolean MapRemovableAsFixedEnabled:1; /* Byte 18 Bit 3 */ - boolean:1; /* Byte 18 Bit 4 */ - boolean BIOSSupportsMoreThan2DrivesEnabled:1; /* Byte 18 Bit 5 */ - boolean BIOSInterruptModeEnabled:1; /* Byte 18 Bit 6 */ - boolean FlopticalSupportEnabled:1; /* Byte 19 Bit 7 */ + bool HostAdapterBIOSEnabled:1; /* Byte 18 Bit 0 */ + bool BIOSRedirectionOfINT19Enabled:1; /* Byte 18 Bit 1 */ + bool ExtendedTranslationEnabled:1; /* Byte 18 Bit 2 */ + bool MapRemovableAsFixedEnabled:1; /* Byte 18 Bit 3 */ + bool:1; /* Byte 18 Bit 4 */ + bool BIOSSupportsMoreThan2DrivesEnabled:1; /* Byte 18 Bit 5 */ + bool BIOSInterruptModeEnabled:1; /* Byte 18 Bit 6 */ + bool FlopticalSupportEnabled:1; /* Byte 19 Bit 7 */ unsigned short DeviceEnabled; /* Bytes 19-20 */ unsigned short WidePermitted; /* Bytes 21-22 */ unsigned short FastPermitted; /* Bytes 23-24 */ @@ -628,22 +622,22 @@ struct BusLogic_AutoSCSIData { unsigned short IgnoreInBIOSScan; /* Bytes 31-32 */ unsigned char PCIInterruptPin:2; /* Byte 33 Bits 0-1 */ unsigned char HostAdapterIOPortAddress:2; /* Byte 33 Bits 2-3 */ - boolean StrictRoundRobinModeEnabled:1; /* Byte 33 Bit 4 */ - boolean VESABusSpeedGreaterThan33MHz:1; /* Byte 33 Bit 5 */ - boolean VESABurstWriteEnabled:1; /* Byte 33 Bit 6 */ - boolean VESABurstReadEnabled:1; /* Byte 33 Bit 7 */ + bool StrictRoundRobinModeEnabled:1; /* Byte 33 Bit 4 */ + bool VESABusSpeedGreaterThan33MHz:1; /* Byte 33 Bit 5 */ + bool VESABurstWriteEnabled:1; /* Byte 33 Bit 6 */ + bool VESABurstReadEnabled:1; /* Byte 33 Bit 7 */ unsigned short UltraPermitted; /* Bytes 34-35 */ unsigned int:32; /* Bytes 36-39 */ unsigned char:8; /* Byte 40 */ unsigned char AutoSCSIMaximumLUN; /* Byte 41 */ - boolean:1; /* Byte 42 Bit 0 */ - boolean SCAM_Dominant:1; /* Byte 42 Bit 1 */ - boolean SCAM_Enabled:1; /* Byte 42 Bit 2 */ - boolean SCAM_Level2:1; /* Byte 42 Bit 3 */ + bool:1; /* Byte 42 Bit 0 */ + bool SCAM_Dominant:1; /* Byte 42 Bit 1 */ + bool SCAM_Enabled:1; /* Byte 42 Bit 2 */ + bool SCAM_Level2:1; /* Byte 42 Bit 3 */ unsigned char:4; /* Byte 42 Bits 4-7 */ - boolean INT13ExtensionEnabled:1; /* Byte 43 Bit 0 */ - boolean:1; /* Byte 43 Bit 1 */ - boolean CDROMBootEnabled:1; /* Byte 43 Bit 2 */ + bool INT13ExtensionEnabled:1; /* Byte 43 Bit 0 */ + bool:1; /* Byte 43 Bit 1 */ + bool CDROMBootEnabled:1; /* Byte 43 Bit 2 */ unsigned char:5; /* Byte 43 Bits 3-7 */ unsigned char BootTargetID:4; /* Byte 44 Bits 0-3 */ unsigned char BootChannel:4; /* Byte 44 Bits 4-7 */ @@ -852,7 +846,7 @@ struct BusLogic_CCB { enum BusLogic_CCB_Opcode Opcode; /* Byte 0 */ unsigned char:3; /* Byte 1 Bits 0-2 */ enum BusLogic_DataDirection DataDirection:2; /* Byte 1 Bits 3-4 */ - boolean TagEnable:1; /* Byte 1 Bit 5 */ + bool TagEnable:1; /* Byte 1 Bit 5 */ enum BusLogic_QueueTag QueueTag:2; /* Byte 1 Bits 6-7 */ unsigned char CDB_Length; /* Byte 2 */ unsigned char SenseDataLength; /* Byte 3 */ @@ -864,7 +858,7 @@ struct BusLogic_CCB { enum BusLogic_TargetDeviceStatus TargetDeviceStatus; /* Byte 15 */ unsigned char TargetID; /* Byte 16 */ unsigned char LogicalUnit:5; /* Byte 17 Bits 0-4 */ - boolean LegacyTagEnable:1; /* Byte 17 Bit 5 */ + bool LegacyTagEnable:1; /* Byte 17 Bit 5 */ enum BusLogic_QueueTag LegacyQueueTag:2; /* Byte 17 Bits 6-7 */ SCSI_CDB_T CDB; /* Bytes 18-29 */ unsigned char:8; /* Byte 30 */ @@ -939,13 +933,13 @@ struct BusLogic_DriverOptions { */ struct BusLogic_TargetFlags { - boolean TargetExists:1; - boolean TaggedQueuingSupported:1; - boolean WideTransfersSupported:1; - boolean TaggedQueuingActive:1; - boolean WideTransfersActive:1; - boolean CommandSuccessfulFlag:1; - boolean TargetInfoReported:1; + bool TargetExists:1; + bool TaggedQueuingSupported:1; + bool WideTransfersSupported:1; + bool TaggedQueuingActive:1; + bool WideTransfersActive:1; + bool CommandSuccessfulFlag:1; + bool TargetInfoReported:1; }; /* @@ -992,7 +986,7 @@ typedef unsigned int FlashPoint_CardHand struct FlashPoint_Info { u32 BaseAddress; /* Bytes 0-3 */ - boolean Present; /* Byte 4 */ + bool Present; /* Byte 4 */ unsigned char IRQ_Channel; /* Byte 5 */ unsigned char SCSI_ID; /* Byte 6 */ unsigned char SCSI_LUN; /* Byte 7 */ @@ -1002,15 +996,15 @@ struct FlashPoint_Info { unsigned short UltraPermitted; /* Bytes 14-15 */ unsigned short DisconnectPermitted; /* Bytes 16-17 */ unsigned short WidePermitted; /* Bytes 18-19 */ - boolean ParityCheckingEnabled:1; /* Byte 20 Bit 0 */ - boolean HostWideSCSI:1; /* Byte 20 Bit 1 */ - boolean HostSoftReset:1; /* Byte 20 Bit 2 */ - boolean ExtendedTranslationEnabled:1; /* Byte 20 Bit 3 */ - boolean LowByteTerminated:1; /* Byte 20 Bit 4 */ - boolean HighByteTerminated:1; /* Byte 20 Bit 5 */ - boolean ReportDataUnderrun:1; /* Byte 20 Bit 6 */ - boolean SCAM_Enabled:1; /* Byte 20 Bit 7 */ - boolean SCAM_Level2:1; /* Byte 21 Bit 0 */ + bool ParityCheckingEnabled:1; /* Byte 20 Bit 0 */ + bool HostWideSCSI:1; /* Byte 20 Bit 1 */ + bool HostSoftReset:1; /* Byte 20 Bit 2 */ + bool ExtendedTranslationEnabled:1; /* Byte 20 Bit 3 */ + bool LowByteTerminated:1; /* Byte 20 Bit 4 */ + bool HighByteTerminated:1; /* Byte 20 Bit 5 */ + bool ReportDataUnderrun:1; /* Byte 20 Bit 6 */ + bool SCAM_Enabled:1; /* Byte 20 Bit 7 */ + bool SCAM_Level2:1; /* Byte 21 Bit 0 */ unsigned char:7; /* Byte 21 Bits 1-7 */ unsigned char Family; /* Byte 22 */ unsigned char BusType; /* Byte 23 */ @@ -1044,29 +1038,29 @@ struct BusLogic_HostAdapter { unsigned char IRQ_Channel; unsigned char DMA_Channel; unsigned char SCSI_ID; - boolean IRQ_ChannelAcquired:1; - boolean DMA_ChannelAcquired:1; - boolean ExtendedTranslationEnabled:1; - boolean ParityCheckingEnabled:1; - boolean BusResetEnabled:1; - boolean LevelSensitiveInterrupt:1; - boolean HostWideSCSI:1; - boolean HostDifferentialSCSI:1; - boolean HostSupportsSCAM:1; - boolean HostUltraSCSI:1; - boolean ExtendedLUNSupport:1; - boolean TerminationInfoValid:1; - boolean LowByteTerminated:1; - boolean HighByteTerminated:1; - boolean BounceBuffersRequired:1; - boolean StrictRoundRobinModeSupport:1; - boolean SCAM_Enabled:1; - boolean SCAM_Level2:1; - boolean HostAdapterInitialized:1; - boolean HostAdapterExternalReset:1; - boolean HostAdapterInternalError:1; - boolean ProcessCompletedCCBsActive; - volatile boolean HostAdapterCommandCompleted; + bool IRQ_ChannelAcquired:1; + bool DMA_ChannelAcquired:1; + bool ExtendedTranslationEnabled:1; + bool ParityCheckingEnabled:1; + bool BusResetEnabled:1; + bool LevelSensitiveInterrupt:1; + bool HostWideSCSI:1; + bool HostDifferentialSCSI:1; + bool HostSupportsSCAM:1; + bool HostUltraSCSI:1; + bool ExtendedLUNSupport:1; + bool TerminationInfoValid:1; + bool LowByteTerminated:1; + bool HighByteTerminated:1; + bool BounceBuffersRequired:1; + bool StrictRoundRobinModeSupport:1; + bool SCAM_Enabled:1; + bool SCAM_Level2:1; + bool HostAdapterInitialized:1; + bool HostAdapterExternalReset:1; + bool HostAdapterInternalError:1; + bool ProcessCompletedCCBsActive; + volatile bool HostAdapterCommandCompleted; unsigned short HostAdapterScatterGatherLimit; unsigned short DriverScatterGatherLimit; unsigned short MaxTargetDevices; @@ -1141,25 +1135,25 @@ struct SCSI_Inquiry { unsigned char PeripheralDeviceType:5; /* Byte 0 Bits 0-4 */ unsigned char PeripheralQualifier:3; /* Byte 0 Bits 5-7 */ unsigned char DeviceTypeModifier:7; /* Byte 1 Bits 0-6 */ - boolean RMB:1; /* Byte 1 Bit 7 */ + bool RMB:1; /* Byte 1 Bit 7 */ unsigned char ANSI_ApprovedVersion:3; /* Byte 2 Bits 0-2 */ unsigned char ECMA_Version:3; /* Byte 2 Bits 3-5 */ unsigned char ISO_Version:2; /* Byte 2 Bits 6-7 */ unsigned char ResponseDataFormat:4; /* Byte 3 Bits 0-3 */ unsigned char:2; /* Byte 3 Bits 4-5 */ - boolean TrmIOP:1; /* Byte 3 Bit 6 */ - boolean AENC:1; /* Byte 3 Bit 7 */ + bool TrmIOP:1; /* Byte 3 Bit 6 */ + bool AENC:1; /* Byte 3 Bit 7 */ unsigned char AdditionalLength; /* Byte 4 */ unsigned char:8; /* Byte 5 */ unsigned char:8; /* Byte 6 */ - boolean SftRe:1; /* Byte 7 Bit 0 */ - boolean CmdQue:1; /* Byte 7 Bit 1 */ - boolean:1; /* Byte 7 Bit 2 */ - boolean Linked:1; /* Byte 7 Bit 3 */ - boolean Sync:1; /* Byte 7 Bit 4 */ - boolean WBus16:1; /* Byte 7 Bit 5 */ - boolean WBus32:1; /* Byte 7 Bit 6 */ - boolean RelAdr:1; /* Byte 7 Bit 7 */ + bool SftRe:1; /* Byte 7 Bit 0 */ + bool CmdQue:1; /* Byte 7 Bit 1 */ + bool:1; /* Byte 7 Bit 2 */ + bool Linked:1; /* Byte 7 Bit 3 */ + bool Sync:1; /* Byte 7 Bit 4 */ + bool WBus16:1; /* Byte 7 Bit 5 */ + bool WBus32:1; /* Byte 7 Bit 6 */ + bool RelAdr:1; /* Byte 7 Bit 7 */ unsigned char VendorIdentification[8]; /* Bytes 8-15 */ unsigned char ProductIdentification[16]; /* Bytes 16-31 */ unsigned char ProductRevisionLevel[4]; /* Bytes 32-35 */ @@ -1348,7 +1342,7 @@ static int BusLogic_ProcDirectoryInfo(st static int BusLogic_SlaveConfigure(struct scsi_device *); static void BusLogic_QueueCompletedCCB(struct BusLogic_CCB *); static irqreturn_t BusLogic_InterruptHandler(int, void *); -static int BusLogic_ResetHostAdapter(struct BusLogic_HostAdapter *, boolean HardReset); +static int BusLogic_ResetHostAdapter(struct BusLogic_HostAdapter *, bool HardReset); static void BusLogic_Message(enum BusLogic_MessageLevel, char *, struct BusLogic_HostAdapter *, ...); static int __init BusLogic_Setup(char *); diff --git a/drivers/scsi/FlashPoint.c b/drivers/scsi/FlashPoint.c index 7c00680..a7f916c 100644 --- a/drivers/scsi/FlashPoint.c +++ b/drivers/scsi/FlashPoint.c @@ -7609,7 +7609,7 @@ FlashPoint__AbortCCB(FlashPoint_CardHand FlashPoint_AbortCCB(CardHandle, (struct sccb *)CCB); } -static inline boolean +static inline bool FlashPoint__InterruptPending(FlashPoint_CardHandle_T CardHandle) { return FlashPoint_InterruptPending(CardHandle); @@ -7640,7 +7640,7 @@ extern FlashPoint_CardHandle_T FlashPoint_HardwareResetHostAdapter(struct FlashPoint_Info *); extern void FlashPoint_StartCCB(FlashPoint_CardHandle_T, struct BusLogic_CCB *); extern int FlashPoint_AbortCCB(FlashPoint_CardHandle_T, struct BusLogic_CCB *); -extern boolean FlashPoint_InterruptPending(FlashPoint_CardHandle_T); +extern bool FlashPoint_InterruptPending(FlashPoint_CardHandle_T); extern int FlashPoint_HandleInterrupt(FlashPoint_CardHandle_T); extern void FlashPoint_ReleaseHostAdapter(FlashPoint_CardHandle_T); diff --git a/drivers/scsi/Kconfig b/drivers/scsi/Kconfig index 7869c34..5bf3f07 100644 --- a/drivers/scsi/Kconfig +++ b/drivers/scsi/Kconfig @@ -973,6 +973,15 @@ config SCSI_LASI700 many PA-RISC workstations & servers. If you do not know whether you have a Lasi chip, it is safe to say "Y" here. +config SCSI_SNI_53C710 + tristate "SNI RM SCSI support for 53c710" + depends on SNI_RM && SCSI + select SCSI_SPI_ATTRS + select 53C700_LE_ON_BE + help + This is a driver for the onboard SCSI controller found in older + SNI RM workstations & servers. + config 53C700_LE_ON_BE bool depends on SCSI_LASI700 diff --git a/drivers/scsi/Makefile b/drivers/scsi/Makefile index bd7c988..79ecf4e 100644 --- a/drivers/scsi/Makefile +++ b/drivers/scsi/Makefile @@ -124,6 +124,7 @@ obj-$(CONFIG_JAZZ_ESP) += NCR53C9x.o ja obj-$(CONFIG_SUN3X_ESP) += NCR53C9x.o sun3x_esp.o obj-$(CONFIG_SCSI_FCAL) += fcal.o obj-$(CONFIG_SCSI_LASI700) += 53c700.o lasi700.o +obj-$(CONFIG_SCSI_SNI_53C710) += 53c700.o sni_53c710.o obj-$(CONFIG_SCSI_NSP32) += nsp32.o obj-$(CONFIG_SCSI_IPR) += ipr.o obj-$(CONFIG_SCSI_SRP) += libsrp.o diff --git a/drivers/scsi/NCR53C9x.c b/drivers/scsi/NCR53C9x.c index 3c912ee..8b5334c 100644 --- a/drivers/scsi/NCR53C9x.c +++ b/drivers/scsi/NCR53C9x.c @@ -528,12 +528,16 @@ void esp_bootup_reset(struct NCR_ESP *es /* Allocate structure and insert basic data such as SCSI chip frequency * data and a pointer to the device */ -struct NCR_ESP* esp_allocate(struct scsi_host_template *tpnt, void *esp_dev) +struct NCR_ESP* esp_allocate(struct scsi_host_template *tpnt, void *esp_dev, + int hotplug) { struct NCR_ESP *esp, *elink; struct Scsi_Host *esp_host; - esp_host = scsi_register(tpnt, sizeof(struct NCR_ESP)); + if (hotplug) + esp_host = scsi_host_alloc(tpnt, sizeof(struct NCR_ESP)); + else + esp_host = scsi_register(tpnt, sizeof(struct NCR_ESP)); if(!esp_host) panic("Cannot register ESP SCSI host"); esp = (struct NCR_ESP *) esp_host->hostdata; diff --git a/drivers/scsi/NCR53C9x.h b/drivers/scsi/NCR53C9x.h index 521e3f8..d85cb73 100644 --- a/drivers/scsi/NCR53C9x.h +++ b/drivers/scsi/NCR53C9x.h @@ -652,7 +652,7 @@ #define for_each_esp(esp) \ /* External functions */ extern void esp_bootup_reset(struct NCR_ESP *esp, struct ESP_regs *eregs); -extern struct NCR_ESP *esp_allocate(struct scsi_host_template *, void *); +extern struct NCR_ESP *esp_allocate(struct scsi_host_template *, void *, int); extern void esp_deallocate(struct NCR_ESP *); extern void esp_release(void); extern void esp_initialize(struct NCR_ESP *); diff --git a/drivers/scsi/NCR53c406a.c b/drivers/scsi/NCR53c406a.c index 8578555..7c0b17f 100644 --- a/drivers/scsi/NCR53c406a.c +++ b/drivers/scsi/NCR53c406a.c @@ -41,7 +41,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/scsi/NCR_D700.c b/drivers/scsi/NCR_D700.c index 9859cd1..f12864a 100644 --- a/drivers/scsi/NCR_D700.c +++ b/drivers/scsi/NCR_D700.c @@ -200,6 +200,7 @@ NCR_D700_probe_one(struct NCR_D700_priva hostdata->base = ioport_map(region, 64); hostdata->differential = (((1<clock = NCR_D700_CLOCK_MHZ; + hostdata->burst_length = 8; /* and register the siop */ host = NCR_700_detect(&NCR_D700_driver_template, hostdata, p->dev); diff --git a/drivers/scsi/a2091.c b/drivers/scsi/a2091.c index f77016d..b7c5385 100644 --- a/drivers/scsi/a2091.c +++ b/drivers/scsi/a2091.c @@ -1,7 +1,6 @@ #include #include #include -#include #include #include diff --git a/drivers/scsi/a3000.c b/drivers/scsi/a3000.c index 1299bc8..796f1c4 100644 --- a/drivers/scsi/a3000.c +++ b/drivers/scsi/a3000.c @@ -1,7 +1,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/scsi/aacraid/Makefile b/drivers/scsi/aacraid/Makefile index 28d133a..f1cca4e 100644 --- a/drivers/scsi/aacraid/Makefile +++ b/drivers/scsi/aacraid/Makefile @@ -3,6 +3,6 @@ # Adaptec aacraid obj-$(CONFIG_SCSI_AACRAID) := aacraid.o aacraid-objs := linit.o aachba.o commctrl.o comminit.o commsup.o \ - dpcsup.o rx.o sa.o rkt.o + dpcsup.o rx.o sa.o rkt.o nark.o EXTRA_CFLAGS := -Idrivers/scsi diff --git a/drivers/scsi/aacraid/aachba.c b/drivers/scsi/aacraid/aachba.c index 426cd6f..d789e61 100644 --- a/drivers/scsi/aacraid/aachba.c +++ b/drivers/scsi/aacraid/aachba.c @@ -26,7 +26,6 @@ #include #include #include -#include #include #include #include @@ -170,9 +169,9 @@ int acbsize = -1; module_param(acbsize, int, S_IRUGO|S_IWUSR); MODULE_PARM_DESC(acbsize, "Request a specific adapter control block (FIB) size. Valid values are 512, 2048, 4096 and 8192. Default is to use suggestion from Firmware."); -int expose_physicals = 0; +int expose_physicals = -1; module_param(expose_physicals, int, S_IRUGO|S_IWUSR); -MODULE_PARM_DESC(expose_physicals, "Expose physical components of the arrays. 0=off, 1=on"); +MODULE_PARM_DESC(expose_physicals, "Expose physical components of the arrays. -1=protect 0=off, 1=on"); /** * aac_get_config_status - check the adapter configuration * @common: adapter to query @@ -706,6 +705,309 @@ static void set_sense(u8 *sense_buf, u8 } } +static int aac_bounds_32(struct aac_dev * dev, struct scsi_cmnd * cmd, u64 lba) +{ + if (lba & 0xffffffff00000000LL) { + int cid = scmd_id(cmd); + dprintk((KERN_DEBUG "aacraid: Illegal lba\n")); + cmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8 | + SAM_STAT_CHECK_CONDITION; + set_sense((u8 *) &dev->fsa_dev[cid].sense_data, + HARDWARE_ERROR, + SENCODE_INTERNAL_TARGET_FAILURE, + ASENCODE_INTERNAL_TARGET_FAILURE, 0, 0, + 0, 0); + memcpy(cmd->sense_buffer, &dev->fsa_dev[cid].sense_data, + (sizeof(dev->fsa_dev[cid].sense_data) > sizeof(cmd->sense_buffer)) + ? sizeof(cmd->sense_buffer) + : sizeof(dev->fsa_dev[cid].sense_data)); + cmd->scsi_done(cmd); + return 1; + } + return 0; +} + +static int aac_bounds_64(struct aac_dev * dev, struct scsi_cmnd * cmd, u64 lba) +{ + return 0; +} + +static void io_callback(void *context, struct fib * fibptr); + +static int aac_read_raw_io(struct fib * fib, struct scsi_cmnd * cmd, u64 lba, u32 count) +{ + u16 fibsize; + struct aac_raw_io *readcmd; + aac_fib_init(fib); + readcmd = (struct aac_raw_io *) fib_data(fib); + readcmd->block[0] = cpu_to_le32((u32)(lba&0xffffffff)); + readcmd->block[1] = cpu_to_le32((u32)((lba&0xffffffff00000000LL)>>32)); + readcmd->count = cpu_to_le32(count<<9); + readcmd->cid = cpu_to_le16(scmd_id(cmd)); + readcmd->flags = cpu_to_le16(1); + readcmd->bpTotal = 0; + readcmd->bpComplete = 0; + + aac_build_sgraw(cmd, &readcmd->sg); + fibsize = sizeof(struct aac_raw_io) + ((le32_to_cpu(readcmd->sg.count) - 1) * sizeof (struct sgentryraw)); + BUG_ON(fibsize > (fib->dev->max_fib_size - sizeof(struct aac_fibhdr))); + /* + * Now send the Fib to the adapter + */ + return aac_fib_send(ContainerRawIo, + fib, + fibsize, + FsaNormal, + 0, 1, + (fib_callback) io_callback, + (void *) cmd); +} + +static int aac_read_block64(struct fib * fib, struct scsi_cmnd * cmd, u64 lba, u32 count) +{ + u16 fibsize; + struct aac_read64 *readcmd; + aac_fib_init(fib); + readcmd = (struct aac_read64 *) fib_data(fib); + readcmd->command = cpu_to_le32(VM_CtHostRead64); + readcmd->cid = cpu_to_le16(scmd_id(cmd)); + readcmd->sector_count = cpu_to_le16(count); + readcmd->block = cpu_to_le32((u32)(lba&0xffffffff)); + readcmd->pad = 0; + readcmd->flags = 0; + + aac_build_sg64(cmd, &readcmd->sg); + fibsize = sizeof(struct aac_read64) + + ((le32_to_cpu(readcmd->sg.count) - 1) * + sizeof (struct sgentry64)); + BUG_ON (fibsize > (fib->dev->max_fib_size - + sizeof(struct aac_fibhdr))); + /* + * Now send the Fib to the adapter + */ + return aac_fib_send(ContainerCommand64, + fib, + fibsize, + FsaNormal, + 0, 1, + (fib_callback) io_callback, + (void *) cmd); +} + +static int aac_read_block(struct fib * fib, struct scsi_cmnd * cmd, u64 lba, u32 count) +{ + u16 fibsize; + struct aac_read *readcmd; + aac_fib_init(fib); + readcmd = (struct aac_read *) fib_data(fib); + readcmd->command = cpu_to_le32(VM_CtBlockRead); + readcmd->cid = cpu_to_le16(scmd_id(cmd)); + readcmd->block = cpu_to_le32((u32)(lba&0xffffffff)); + readcmd->count = cpu_to_le32(count * 512); + + aac_build_sg(cmd, &readcmd->sg); + fibsize = sizeof(struct aac_read) + + ((le32_to_cpu(readcmd->sg.count) - 1) * + sizeof (struct sgentry)); + BUG_ON (fibsize > (fib->dev->max_fib_size - + sizeof(struct aac_fibhdr))); + /* + * Now send the Fib to the adapter + */ + return aac_fib_send(ContainerCommand, + fib, + fibsize, + FsaNormal, + 0, 1, + (fib_callback) io_callback, + (void *) cmd); +} + +static int aac_write_raw_io(struct fib * fib, struct scsi_cmnd * cmd, u64 lba, u32 count) +{ + u16 fibsize; + struct aac_raw_io *writecmd; + aac_fib_init(fib); + writecmd = (struct aac_raw_io *) fib_data(fib); + writecmd->block[0] = cpu_to_le32((u32)(lba&0xffffffff)); + writecmd->block[1] = cpu_to_le32((u32)((lba&0xffffffff00000000LL)>>32)); + writecmd->count = cpu_to_le32(count<<9); + writecmd->cid = cpu_to_le16(scmd_id(cmd)); + writecmd->flags = 0; + writecmd->bpTotal = 0; + writecmd->bpComplete = 0; + + aac_build_sgraw(cmd, &writecmd->sg); + fibsize = sizeof(struct aac_raw_io) + ((le32_to_cpu(writecmd->sg.count) - 1) * sizeof (struct sgentryraw)); + BUG_ON(fibsize > (fib->dev->max_fib_size - sizeof(struct aac_fibhdr))); + /* + * Now send the Fib to the adapter + */ + return aac_fib_send(ContainerRawIo, + fib, + fibsize, + FsaNormal, + 0, 1, + (fib_callback) io_callback, + (void *) cmd); +} + +static int aac_write_block64(struct fib * fib, struct scsi_cmnd * cmd, u64 lba, u32 count) +{ + u16 fibsize; + struct aac_write64 *writecmd; + aac_fib_init(fib); + writecmd = (struct aac_write64 *) fib_data(fib); + writecmd->command = cpu_to_le32(VM_CtHostWrite64); + writecmd->cid = cpu_to_le16(scmd_id(cmd)); + writecmd->sector_count = cpu_to_le16(count); + writecmd->block = cpu_to_le32((u32)(lba&0xffffffff)); + writecmd->pad = 0; + writecmd->flags = 0; + + aac_build_sg64(cmd, &writecmd->sg); + fibsize = sizeof(struct aac_write64) + + ((le32_to_cpu(writecmd->sg.count) - 1) * + sizeof (struct sgentry64)); + BUG_ON (fibsize > (fib->dev->max_fib_size - + sizeof(struct aac_fibhdr))); + /* + * Now send the Fib to the adapter + */ + return aac_fib_send(ContainerCommand64, + fib, + fibsize, + FsaNormal, + 0, 1, + (fib_callback) io_callback, + (void *) cmd); +} + +static int aac_write_block(struct fib * fib, struct scsi_cmnd * cmd, u64 lba, u32 count) +{ + u16 fibsize; + struct aac_write *writecmd; + aac_fib_init(fib); + writecmd = (struct aac_write *) fib_data(fib); + writecmd->command = cpu_to_le32(VM_CtBlockWrite); + writecmd->cid = cpu_to_le16(scmd_id(cmd)); + writecmd->block = cpu_to_le32((u32)(lba&0xffffffff)); + writecmd->count = cpu_to_le32(count * 512); + writecmd->sg.count = cpu_to_le32(1); + /* ->stable is not used - it did mean which type of write */ + + aac_build_sg(cmd, &writecmd->sg); + fibsize = sizeof(struct aac_write) + + ((le32_to_cpu(writecmd->sg.count) - 1) * + sizeof (struct sgentry)); + BUG_ON (fibsize > (fib->dev->max_fib_size - + sizeof(struct aac_fibhdr))); + /* + * Now send the Fib to the adapter + */ + return aac_fib_send(ContainerCommand, + fib, + fibsize, + FsaNormal, + 0, 1, + (fib_callback) io_callback, + (void *) cmd); +} + +static struct aac_srb * aac_scsi_common(struct fib * fib, struct scsi_cmnd * cmd) +{ + struct aac_srb * srbcmd; + u32 flag; + u32 timeout; + + aac_fib_init(fib); + switch(cmd->sc_data_direction){ + case DMA_TO_DEVICE: + flag = SRB_DataOut; + break; + case DMA_BIDIRECTIONAL: + flag = SRB_DataIn | SRB_DataOut; + break; + case DMA_FROM_DEVICE: + flag = SRB_DataIn; + break; + case DMA_NONE: + default: /* shuts up some versions of gcc */ + flag = SRB_NoDataXfer; + break; + } + + srbcmd = (struct aac_srb*) fib_data(fib); + srbcmd->function = cpu_to_le32(SRBF_ExecuteScsi); + srbcmd->channel = cpu_to_le32(aac_logical_to_phys(scmd_channel(cmd))); + srbcmd->id = cpu_to_le32(scmd_id(cmd)); + srbcmd->lun = cpu_to_le32(cmd->device->lun); + srbcmd->flags = cpu_to_le32(flag); + timeout = cmd->timeout_per_command/HZ; + if (timeout == 0) + timeout = 1; + srbcmd->timeout = cpu_to_le32(timeout); // timeout in seconds + srbcmd->retry_limit = 0; /* Obsolete parameter */ + srbcmd->cdb_size = cpu_to_le32(cmd->cmd_len); + return srbcmd; +} + +static void aac_srb_callback(void *context, struct fib * fibptr); + +static int aac_scsi_64(struct fib * fib, struct scsi_cmnd * cmd) +{ + u16 fibsize; + struct aac_srb * srbcmd = aac_scsi_common(fib, cmd); + + aac_build_sg64(cmd, (struct sgmap64*) &srbcmd->sg); + srbcmd->count = cpu_to_le32(cmd->request_bufflen); + + memset(srbcmd->cdb, 0, sizeof(srbcmd->cdb)); + memcpy(srbcmd->cdb, cmd->cmnd, cmd->cmd_len); + /* + * Build Scatter/Gather list + */ + fibsize = sizeof (struct aac_srb) - sizeof (struct sgentry) + + ((le32_to_cpu(srbcmd->sg.count) & 0xff) * + sizeof (struct sgentry64)); + BUG_ON (fibsize > (fib->dev->max_fib_size - + sizeof(struct aac_fibhdr))); + + /* + * Now send the Fib to the adapter + */ + return aac_fib_send(ScsiPortCommand64, fib, + fibsize, FsaNormal, 0, 1, + (fib_callback) aac_srb_callback, + (void *) cmd); +} + +static int aac_scsi_32(struct fib * fib, struct scsi_cmnd * cmd) +{ + u16 fibsize; + struct aac_srb * srbcmd = aac_scsi_common(fib, cmd); + + aac_build_sg(cmd, (struct sgmap*)&srbcmd->sg); + srbcmd->count = cpu_to_le32(cmd->request_bufflen); + + memset(srbcmd->cdb, 0, sizeof(srbcmd->cdb)); + memcpy(srbcmd->cdb, cmd->cmnd, cmd->cmd_len); + /* + * Build Scatter/Gather list + */ + fibsize = sizeof (struct aac_srb) + + (((le32_to_cpu(srbcmd->sg.count) & 0xff) - 1) * + sizeof (struct sgentry)); + BUG_ON (fibsize > (fib->dev->max_fib_size - + sizeof(struct aac_fibhdr))); + + /* + * Now send the Fib to the adapter + */ + return aac_fib_send(ScsiPortCommand, fib, fibsize, FsaNormal, 0, 1, + (fib_callback) aac_srb_callback, (void *) cmd); +} + int aac_get_adapter_info(struct aac_dev* dev) { struct fib* fibptr; @@ -874,14 +1176,27 @@ int aac_get_adapter_info(struct aac_dev* } } /* - * 57 scatter gather elements + * Deal with configuring for the individualized limits of each packet + * interface. */ - if (!(dev->raw_io_interface)) { + dev->a_ops.adapter_scsi = (dev->dac_support) + ? aac_scsi_64 + : aac_scsi_32; + if (dev->raw_io_interface) { + dev->a_ops.adapter_bounds = (dev->raw_io_64) + ? aac_bounds_64 + : aac_bounds_32; + dev->a_ops.adapter_read = aac_read_raw_io; + dev->a_ops.adapter_write = aac_write_raw_io; + } else { + dev->a_ops.adapter_bounds = aac_bounds_32; dev->scsi_host_ptr->sg_tablesize = (dev->max_fib_size - sizeof(struct aac_fibhdr) - sizeof(struct aac_write) + sizeof(struct sgentry)) / sizeof(struct sgentry); if (dev->dac_support) { + dev->a_ops.adapter_read = aac_read_block64; + dev->a_ops.adapter_write = aac_write_block64; /* * 38 scatter gather elements */ @@ -891,6 +1206,9 @@ int aac_get_adapter_info(struct aac_dev* sizeof(struct aac_write64) + sizeof(struct sgentry64)) / sizeof(struct sgentry64); + } else { + dev->a_ops.adapter_read = aac_read_block; + dev->a_ops.adapter_write = aac_write_block; } dev->scsi_host_ptr->max_sectors = AAC_MAX_32BIT_SGBCOUNT; if(!(dev->adapter_info.options & AAC_OPT_NEW_COMM)) { @@ -1004,8 +1322,6 @@ static int aac_read(struct scsi_cmnd * s u64 lba; u32 count; int status; - - u16 fibsize; struct aac_dev *dev; struct fib * cmd_fibcontext; @@ -1059,23 +1375,8 @@ static int aac_read(struct scsi_cmnd * s } dprintk((KERN_DEBUG "aac_read[cpu %d]: lba = %llu, t = %ld.\n", smp_processor_id(), (unsigned long long)lba, jiffies)); - if ((!(dev->raw_io_interface) || !(dev->raw_io_64)) && - (lba & 0xffffffff00000000LL)) { - dprintk((KERN_DEBUG "aac_read: Illegal lba\n")); - scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8 | - SAM_STAT_CHECK_CONDITION; - set_sense((u8 *) &dev->fsa_dev[cid].sense_data, - HARDWARE_ERROR, - SENCODE_INTERNAL_TARGET_FAILURE, - ASENCODE_INTERNAL_TARGET_FAILURE, 0, 0, - 0, 0); - memcpy(scsicmd->sense_buffer, &dev->fsa_dev[cid].sense_data, - (sizeof(dev->fsa_dev[cid].sense_data) > sizeof(scsicmd->sense_buffer)) - ? sizeof(scsicmd->sense_buffer) - : sizeof(dev->fsa_dev[cid].sense_data)); - scsicmd->scsi_done(scsicmd); + if (aac_adapter_bounds(dev,scsicmd,lba)) return 0; - } /* * Alocate and initialize a Fib */ @@ -1083,85 +1384,7 @@ static int aac_read(struct scsi_cmnd * s return -1; } - aac_fib_init(cmd_fibcontext); - - if (dev->raw_io_interface) { - struct aac_raw_io *readcmd; - readcmd = (struct aac_raw_io *) fib_data(cmd_fibcontext); - readcmd->block[0] = cpu_to_le32((u32)(lba&0xffffffff)); - readcmd->block[1] = cpu_to_le32((u32)((lba&0xffffffff00000000LL)>>32)); - readcmd->count = cpu_to_le32(count<<9); - readcmd->cid = cpu_to_le16(cid); - readcmd->flags = cpu_to_le16(1); - readcmd->bpTotal = 0; - readcmd->bpComplete = 0; - - aac_build_sgraw(scsicmd, &readcmd->sg); - fibsize = sizeof(struct aac_raw_io) + ((le32_to_cpu(readcmd->sg.count) - 1) * sizeof (struct sgentryraw)); - BUG_ON(fibsize > (dev->max_fib_size - sizeof(struct aac_fibhdr))); - /* - * Now send the Fib to the adapter - */ - status = aac_fib_send(ContainerRawIo, - cmd_fibcontext, - fibsize, - FsaNormal, - 0, 1, - (fib_callback) io_callback, - (void *) scsicmd); - } else if (dev->dac_support == 1) { - struct aac_read64 *readcmd; - readcmd = (struct aac_read64 *) fib_data(cmd_fibcontext); - readcmd->command = cpu_to_le32(VM_CtHostRead64); - readcmd->cid = cpu_to_le16(cid); - readcmd->sector_count = cpu_to_le16(count); - readcmd->block = cpu_to_le32((u32)(lba&0xffffffff)); - readcmd->pad = 0; - readcmd->flags = 0; - - aac_build_sg64(scsicmd, &readcmd->sg); - fibsize = sizeof(struct aac_read64) + - ((le32_to_cpu(readcmd->sg.count) - 1) * - sizeof (struct sgentry64)); - BUG_ON (fibsize > (dev->max_fib_size - - sizeof(struct aac_fibhdr))); - /* - * Now send the Fib to the adapter - */ - status = aac_fib_send(ContainerCommand64, - cmd_fibcontext, - fibsize, - FsaNormal, - 0, 1, - (fib_callback) io_callback, - (void *) scsicmd); - } else { - struct aac_read *readcmd; - readcmd = (struct aac_read *) fib_data(cmd_fibcontext); - readcmd->command = cpu_to_le32(VM_CtBlockRead); - readcmd->cid = cpu_to_le32(cid); - readcmd->block = cpu_to_le32((u32)(lba&0xffffffff)); - readcmd->count = cpu_to_le32(count * 512); - - aac_build_sg(scsicmd, &readcmd->sg); - fibsize = sizeof(struct aac_read) + - ((le32_to_cpu(readcmd->sg.count) - 1) * - sizeof (struct sgentry)); - BUG_ON (fibsize > (dev->max_fib_size - - sizeof(struct aac_fibhdr))); - /* - * Now send the Fib to the adapter - */ - status = aac_fib_send(ContainerCommand, - cmd_fibcontext, - fibsize, - FsaNormal, - 0, 1, - (fib_callback) io_callback, - (void *) scsicmd); - } - - + status = aac_adapter_read(cmd_fibcontext, scsicmd, lba, count); /* * Check that the command queued to the controller @@ -1187,7 +1410,6 @@ static int aac_write(struct scsi_cmnd * u64 lba; u32 count; int status; - u16 fibsize; struct aac_dev *dev; struct fib * cmd_fibcontext; @@ -1227,22 +1449,8 @@ static int aac_write(struct scsi_cmnd * } dprintk((KERN_DEBUG "aac_write[cpu %d]: lba = %llu, t = %ld.\n", smp_processor_id(), (unsigned long long)lba, jiffies)); - if ((!(dev->raw_io_interface) || !(dev->raw_io_64)) - && (lba & 0xffffffff00000000LL)) { - dprintk((KERN_DEBUG "aac_write: Illegal lba\n")); - scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8 | SAM_STAT_CHECK_CONDITION; - set_sense((u8 *) &dev->fsa_dev[cid].sense_data, - HARDWARE_ERROR, - SENCODE_INTERNAL_TARGET_FAILURE, - ASENCODE_INTERNAL_TARGET_FAILURE, 0, 0, - 0, 0); - memcpy(scsicmd->sense_buffer, &dev->fsa_dev[cid].sense_data, - (sizeof(dev->fsa_dev[cid].sense_data) > sizeof(scsicmd->sense_buffer)) - ? sizeof(scsicmd->sense_buffer) - : sizeof(dev->fsa_dev[cid].sense_data)); - scsicmd->scsi_done(scsicmd); + if (aac_adapter_bounds(dev,scsicmd,lba)) return 0; - } /* * Allocate and initialize a Fib then setup a BlockWrite command */ @@ -1251,85 +1459,8 @@ static int aac_write(struct scsi_cmnd * scsicmd->scsi_done(scsicmd); return 0; } - aac_fib_init(cmd_fibcontext); - if (dev->raw_io_interface) { - struct aac_raw_io *writecmd; - writecmd = (struct aac_raw_io *) fib_data(cmd_fibcontext); - writecmd->block[0] = cpu_to_le32((u32)(lba&0xffffffff)); - writecmd->block[1] = cpu_to_le32((u32)((lba&0xffffffff00000000LL)>>32)); - writecmd->count = cpu_to_le32(count<<9); - writecmd->cid = cpu_to_le16(cid); - writecmd->flags = 0; - writecmd->bpTotal = 0; - writecmd->bpComplete = 0; - - aac_build_sgraw(scsicmd, &writecmd->sg); - fibsize = sizeof(struct aac_raw_io) + ((le32_to_cpu(writecmd->sg.count) - 1) * sizeof (struct sgentryraw)); - BUG_ON(fibsize > (dev->max_fib_size - sizeof(struct aac_fibhdr))); - /* - * Now send the Fib to the adapter - */ - status = aac_fib_send(ContainerRawIo, - cmd_fibcontext, - fibsize, - FsaNormal, - 0, 1, - (fib_callback) io_callback, - (void *) scsicmd); - } else if (dev->dac_support == 1) { - struct aac_write64 *writecmd; - writecmd = (struct aac_write64 *) fib_data(cmd_fibcontext); - writecmd->command = cpu_to_le32(VM_CtHostWrite64); - writecmd->cid = cpu_to_le16(cid); - writecmd->sector_count = cpu_to_le16(count); - writecmd->block = cpu_to_le32((u32)(lba&0xffffffff)); - writecmd->pad = 0; - writecmd->flags = 0; - - aac_build_sg64(scsicmd, &writecmd->sg); - fibsize = sizeof(struct aac_write64) + - ((le32_to_cpu(writecmd->sg.count) - 1) * - sizeof (struct sgentry64)); - BUG_ON (fibsize > (dev->max_fib_size - - sizeof(struct aac_fibhdr))); - /* - * Now send the Fib to the adapter - */ - status = aac_fib_send(ContainerCommand64, - cmd_fibcontext, - fibsize, - FsaNormal, - 0, 1, - (fib_callback) io_callback, - (void *) scsicmd); - } else { - struct aac_write *writecmd; - writecmd = (struct aac_write *) fib_data(cmd_fibcontext); - writecmd->command = cpu_to_le32(VM_CtBlockWrite); - writecmd->cid = cpu_to_le32(cid); - writecmd->block = cpu_to_le32((u32)(lba&0xffffffff)); - writecmd->count = cpu_to_le32(count * 512); - writecmd->sg.count = cpu_to_le32(1); - /* ->stable is not used - it did mean which type of write */ - - aac_build_sg(scsicmd, &writecmd->sg); - fibsize = sizeof(struct aac_write) + - ((le32_to_cpu(writecmd->sg.count) - 1) * - sizeof (struct sgentry)); - BUG_ON (fibsize > (dev->max_fib_size - - sizeof(struct aac_fibhdr))); - /* - * Now send the Fib to the adapter - */ - status = aac_fib_send(ContainerCommand, - cmd_fibcontext, - fibsize, - FsaNormal, - 0, 1, - (fib_callback) io_callback, - (void *) scsicmd); - } + status = aac_adapter_write(cmd_fibcontext, scsicmd, lba, count); /* * Check that the command queued to the controller @@ -2099,10 +2230,6 @@ static int aac_send_srb_fib(struct scsi_ struct fib* cmd_fibcontext; struct aac_dev* dev; int status; - struct aac_srb *srbcmd; - u16 fibsize; - u32 flag; - u32 timeout; dev = (struct aac_dev *)scsicmd->device->host->hostdata; if (scmd_id(scsicmd) >= dev->maximum_num_physicals || @@ -2112,88 +2239,14 @@ static int aac_send_srb_fib(struct scsi_ return 0; } - switch(scsicmd->sc_data_direction){ - case DMA_TO_DEVICE: - flag = SRB_DataOut; - break; - case DMA_BIDIRECTIONAL: - flag = SRB_DataIn | SRB_DataOut; - break; - case DMA_FROM_DEVICE: - flag = SRB_DataIn; - break; - case DMA_NONE: - default: /* shuts up some versions of gcc */ - flag = SRB_NoDataXfer; - break; - } - - /* * Allocate and initialize a Fib then setup a BlockWrite command */ if (!(cmd_fibcontext = aac_fib_alloc(dev))) { return -1; } - aac_fib_init(cmd_fibcontext); - - srbcmd = (struct aac_srb*) fib_data(cmd_fibcontext); - srbcmd->function = cpu_to_le32(SRBF_ExecuteScsi); - srbcmd->channel = cpu_to_le32(aac_logical_to_phys(scmd_channel(scsicmd))); - srbcmd->id = cpu_to_le32(scmd_id(scsicmd)); - srbcmd->lun = cpu_to_le32(scsicmd->device->lun); - srbcmd->flags = cpu_to_le32(flag); - timeout = scsicmd->timeout_per_command/HZ; - if(timeout == 0){ - timeout = 1; - } - srbcmd->timeout = cpu_to_le32(timeout); // timeout in seconds - srbcmd->retry_limit = 0; /* Obsolete parameter */ - srbcmd->cdb_size = cpu_to_le32(scsicmd->cmd_len); - - if( dev->dac_support == 1 ) { - aac_build_sg64(scsicmd, (struct sgmap64*) &srbcmd->sg); - srbcmd->count = cpu_to_le32(scsicmd->request_bufflen); - - memset(srbcmd->cdb, 0, sizeof(srbcmd->cdb)); - memcpy(srbcmd->cdb, scsicmd->cmnd, scsicmd->cmd_len); - /* - * Build Scatter/Gather list - */ - fibsize = sizeof (struct aac_srb) - sizeof (struct sgentry) + - ((le32_to_cpu(srbcmd->sg.count) & 0xff) * - sizeof (struct sgentry64)); - BUG_ON (fibsize > (dev->max_fib_size - - sizeof(struct aac_fibhdr))); + status = aac_adapter_scsi(cmd_fibcontext, scsicmd); - /* - * Now send the Fib to the adapter - */ - status = aac_fib_send(ScsiPortCommand64, cmd_fibcontext, - fibsize, FsaNormal, 0, 1, - (fib_callback) aac_srb_callback, - (void *) scsicmd); - } else { - aac_build_sg(scsicmd, (struct sgmap*)&srbcmd->sg); - srbcmd->count = cpu_to_le32(scsicmd->request_bufflen); - - memset(srbcmd->cdb, 0, sizeof(srbcmd->cdb)); - memcpy(srbcmd->cdb, scsicmd->cmnd, scsicmd->cmd_len); - /* - * Build Scatter/Gather list - */ - fibsize = sizeof (struct aac_srb) + - (((le32_to_cpu(srbcmd->sg.count) & 0xff) - 1) * - sizeof (struct sgentry)); - BUG_ON (fibsize > (dev->max_fib_size - - sizeof(struct aac_fibhdr))); - - /* - * Now send the Fib to the adapter - */ - status = aac_fib_send(ScsiPortCommand, cmd_fibcontext, fibsize, FsaNormal, 0, 1, - (fib_callback) aac_srb_callback, (void *) scsicmd); - } /* * Check that the command queued to the controller */ diff --git a/drivers/scsi/aacraid/aacraid.h b/drivers/scsi/aacraid/aacraid.h index 4f8b4c5..39ecd0d 100644 --- a/drivers/scsi/aacraid/aacraid.h +++ b/drivers/scsi/aacraid/aacraid.h @@ -5,6 +5,7 @@ #endif #define _nblank(x) #x #define nblank(x) _nblank(x)[0] +#include /*------------------------------------------------------------------------------ * D E F I N E S @@ -485,16 +486,28 @@ #define FSAFS_NTC_FIB_CONTEXT 0x030c struct aac_dev; struct fib; +struct scsi_cmnd; struct adapter_ops { + /* Low level operations */ void (*adapter_interrupt)(struct aac_dev *dev); void (*adapter_notify)(struct aac_dev *dev, u32 event); void (*adapter_disable_int)(struct aac_dev *dev); + void (*adapter_enable_int)(struct aac_dev *dev); int (*adapter_sync_cmd)(struct aac_dev *dev, u32 command, u32 p1, u32 p2, u32 p3, u32 p4, u32 p5, u32 p6, u32 *status, u32 *r1, u32 *r2, u32 *r3, u32 *r4); int (*adapter_check_health)(struct aac_dev *dev); - int (*adapter_send)(struct fib * fib); + /* Transport operations */ int (*adapter_ioremap)(struct aac_dev * dev, u32 size); + irqreturn_t (*adapter_intr)(int irq, void *dev_id); + /* Packet operations */ + int (*adapter_deliver)(struct fib * fib); + int (*adapter_bounds)(struct aac_dev * dev, struct scsi_cmnd * cmd, u64 lba); + int (*adapter_read)(struct fib * fib, struct scsi_cmnd * cmd, u64 lba, u32 count); + int (*adapter_write)(struct fib * fib, struct scsi_cmnd * cmd, u64 lba, u32 count); + int (*adapter_scsi)(struct fib * fib, struct scsi_cmnd * cmd); + /* Administrative operations */ + int (*adapter_comm)(struct aac_dev * dev, int comm); }; /* @@ -1018,7 +1031,9 @@ #endif u8 nondasd_support; u8 dac_support; u8 raid_scsi_mode; - u8 new_comm_interface; + u8 comm_interface; +# define AAC_COMM_PRODUCER 0 +# define AAC_COMM_MESSAGE 1 /* macro side-effects BEWARE */ # define raw_io_interface \ init->InitStructRevision==cpu_to_le32(ADAPTER_INIT_STRUCT_REVISION_4) @@ -1036,18 +1051,36 @@ #define aac_adapter_notify(dev, event) \ #define aac_adapter_disable_int(dev) \ (dev)->a_ops.adapter_disable_int(dev) +#define aac_adapter_enable_int(dev) \ + (dev)->a_ops.adapter_enable_int(dev) + #define aac_adapter_sync_cmd(dev, command, p1, p2, p3, p4, p5, p6, status, r1, r2, r3, r4) \ (dev)->a_ops.adapter_sync_cmd(dev, command, p1, p2, p3, p4, p5, p6, status, r1, r2, r3, r4) #define aac_adapter_check_health(dev) \ (dev)->a_ops.adapter_check_health(dev) -#define aac_adapter_send(fib) \ - ((fib)->dev)->a_ops.adapter_send(fib) - #define aac_adapter_ioremap(dev, size) \ (dev)->a_ops.adapter_ioremap(dev, size) +#define aac_adapter_deliver(fib) \ + ((fib)->dev)->a_ops.adapter_deliver(fib) + +#define aac_adapter_bounds(dev,cmd,lba) \ + dev->a_ops.adapter_bounds(dev,cmd,lba) + +#define aac_adapter_read(fib,cmd,lba,count) \ + ((fib)->dev)->a_ops.adapter_read(fib,cmd,lba,count) + +#define aac_adapter_write(fib,cmd,lba,count) \ + ((fib)->dev)->a_ops.adapter_write(fib,cmd,lba,count) + +#define aac_adapter_scsi(fib,cmd) \ + ((fib)->dev)->a_ops.adapter_scsi(fib,cmd) + +#define aac_adapter_comm(dev,comm) \ + (dev)->a_ops.adapter_comm(dev, comm) + #define FIB_CONTEXT_FLAG_TIMED_OUT (0x00000001) /* @@ -1767,7 +1800,6 @@ static inline u32 cap_to_cyls(sector_t c return (u32)capacity; } -struct scsi_cmnd; /* SCp.phase values */ #define AAC_OWNER_MIDLEVEL 0x101 #define AAC_OWNER_LOWLEVEL 0x102 @@ -1794,7 +1826,9 @@ int aac_dev_ioctl(struct aac_dev *dev, i int aac_do_ioctl(struct aac_dev * dev, int cmd, void __user *arg); int aac_rx_init(struct aac_dev *dev); int aac_rkt_init(struct aac_dev *dev); +int aac_nark_init(struct aac_dev *dev); int aac_sa_init(struct aac_dev *dev); +int aac_queue_get(struct aac_dev * dev, u32 * index, u32 qid, struct hw_fib * hw_fib, int wait, struct fib * fibptr, unsigned long *nonotify); unsigned int aac_response_normal(struct aac_queue * q); unsigned int aac_command_normal(struct aac_queue * q); unsigned int aac_intr_normal(struct aac_dev * dev, u32 Index); diff --git a/drivers/scsi/aacraid/commctrl.c b/drivers/scsi/aacraid/commctrl.c index da1d3a9..e21070f 100644 --- a/drivers/scsi/aacraid/commctrl.c +++ b/drivers/scsi/aacraid/commctrl.c @@ -31,7 +31,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/scsi/aacraid/comminit.c b/drivers/scsi/aacraid/comminit.c index 6d305b2..ae34768 100644 --- a/drivers/scsi/aacraid/comminit.c +++ b/drivers/scsi/aacraid/comminit.c @@ -32,7 +32,6 @@ #include #include #include -#include #include #include #include @@ -95,7 +94,7 @@ static int aac_alloc_comm(struct aac_dev init->HostPhysMemPages = cpu_to_le32(AAC_MAX_HOSTPHYSMEMPAGES); init->InitFlags = 0; - if (dev->new_comm_interface) { + if (dev->comm_interface == AAC_COMM_MESSAGE) { init->InitFlags = cpu_to_le32(INITFLAGS_NEW_COMM_SUPPORTED); dprintk((KERN_WARNING"aacraid: New Comm Interface enabled\n")); } @@ -297,21 +296,23 @@ struct aac_dev *aac_init_adapter(struct - sizeof(struct aac_fibhdr) - sizeof(struct aac_write) + sizeof(struct sgentry)) / sizeof(struct sgentry); - dev->new_comm_interface = 0; + dev->comm_interface = AAC_COMM_PRODUCER; dev->raw_io_64 = 0; if ((!aac_adapter_sync_cmd(dev, GET_ADAPTER_PROPERTIES, 0, 0, 0, 0, 0, 0, status+0, status+1, status+2, NULL, NULL)) && (status[0] == 0x00000001)) { if (status[1] & AAC_OPT_NEW_COMM_64) dev->raw_io_64 = 1; - if (status[1] & AAC_OPT_NEW_COMM) - dev->new_comm_interface = dev->a_ops.adapter_send != 0; - if (dev->new_comm_interface && (status[2] > dev->base_size)) { + if (dev->a_ops.adapter_comm && + (status[1] & AAC_OPT_NEW_COMM)) + dev->comm_interface = AAC_COMM_MESSAGE; + if ((dev->comm_interface == AAC_COMM_MESSAGE) && + (status[2] > dev->base_size)) { aac_adapter_ioremap(dev, 0); dev->base_size = status[2]; if (aac_adapter_ioremap(dev, status[2])) { /* remap failed, go back ... */ - dev->new_comm_interface = 0; + dev->comm_interface = AAC_COMM_PRODUCER; if (aac_adapter_ioremap(dev, AAC_MIN_FOOTPRINT_SIZE)) { printk(KERN_WARNING "aacraid: unable to map adapter.\n"); diff --git a/drivers/scsi/aacraid/commsup.c b/drivers/scsi/aacraid/commsup.c index 4893a6d..1b97f60 100644 --- a/drivers/scsi/aacraid/commsup.c +++ b/drivers/scsi/aacraid/commsup.c @@ -317,7 +317,7 @@ static int aac_get_entry (struct aac_dev * success. */ -static int aac_queue_get(struct aac_dev * dev, u32 * index, u32 qid, struct hw_fib * hw_fib, int wait, struct fib * fibptr, unsigned long *nonotify) +int aac_queue_get(struct aac_dev * dev, u32 * index, u32 qid, struct hw_fib * hw_fib, int wait, struct fib * fibptr, unsigned long *nonotify) { struct aac_entry * entry = NULL; int map = 0; @@ -387,7 +387,6 @@ int aac_fib_send(u16 command, struct fib { struct aac_dev * dev = fibptr->dev; struct hw_fib * hw_fib = fibptr->hw_fib; - struct aac_queue * q; unsigned long flags = 0; unsigned long qflags; @@ -469,38 +468,10 @@ int aac_fib_send(u16 command, struct fib if (!dev->queues) return -EBUSY; - q = &dev->queues->queue[AdapNormCmdQueue]; if(wait) spin_lock_irqsave(&fibptr->event_lock, flags); - spin_lock_irqsave(q->lock, qflags); - if (dev->new_comm_interface) { - unsigned long count = 10000000L; /* 50 seconds */ - q->numpending++; - spin_unlock_irqrestore(q->lock, qflags); - while (aac_adapter_send(fibptr) != 0) { - if (--count == 0) { - if (wait) - spin_unlock_irqrestore(&fibptr->event_lock, flags); - spin_lock_irqsave(q->lock, qflags); - q->numpending--; - spin_unlock_irqrestore(q->lock, qflags); - return -ETIMEDOUT; - } - udelay(5); - } - } else { - u32 index; - unsigned long nointr = 0; - aac_queue_get( dev, &index, AdapNormCmdQueue, hw_fib, 1, fibptr, &nointr); - - q->numpending++; - *(q->headers.producer) = cpu_to_le32(index + 1); - spin_unlock_irqrestore(q->lock, qflags); - dprintk((KERN_DEBUG "aac_fib_send: inserting a queue entry at index %d.\n",index)); - if (!(nointr & aac_config.irq_mod)) - aac_adapter_notify(dev, AdapNormCmdQueue); - } + aac_adapter_deliver(fibptr); /* * If the caller wanted us to wait for response wait now. @@ -520,6 +491,7 @@ int aac_fib_send(u16 command, struct fib while (down_trylock(&fibptr->event_wait)) { int blink; if (--count == 0) { + struct aac_queue * q = &dev->queues->queue[AdapNormCmdQueue]; spin_lock_irqsave(q->lock, qflags); q->numpending--; spin_unlock_irqrestore(q->lock, qflags); @@ -659,7 +631,7 @@ int aac_fib_adapter_complete(struct fib unsigned long qflags; if (hw_fib->header.XferState == 0) { - if (dev->new_comm_interface) + if (dev->comm_interface == AAC_COMM_MESSAGE) kfree (hw_fib); return 0; } @@ -667,7 +639,7 @@ int aac_fib_adapter_complete(struct fib * If we plan to do anything check the structure type first. */ if ( hw_fib->header.StructType != FIB_MAGIC ) { - if (dev->new_comm_interface) + if (dev->comm_interface == AAC_COMM_MESSAGE) kfree (hw_fib); return -EINVAL; } @@ -679,7 +651,7 @@ int aac_fib_adapter_complete(struct fib * send the completed cdb to the adapter. */ if (hw_fib->header.XferState & cpu_to_le32(SentFromAdapter)) { - if (dev->new_comm_interface) { + if (dev->comm_interface == AAC_COMM_MESSAGE) { kfree (hw_fib); } else { u32 index; diff --git a/drivers/scsi/aacraid/dpcsup.c b/drivers/scsi/aacraid/dpcsup.c index 8335f07..d38b628 100644 --- a/drivers/scsi/aacraid/dpcsup.c +++ b/drivers/scsi/aacraid/dpcsup.c @@ -32,7 +32,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/scsi/aacraid/linit.c b/drivers/scsi/aacraid/linit.c index d2cf875..0f948c2 100644 --- a/drivers/scsi/aacraid/linit.c +++ b/drivers/scsi/aacraid/linit.c @@ -157,6 +157,7 @@ static struct pci_device_id aac_pci_tbl[ { 0x9005, 0x0285, 0x17aa, PCI_ANY_ID, 0, 0, 58 }, /* Legend Catchall */ { 0x9005, 0x0285, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 59 }, /* Adaptec Catch All */ { 0x9005, 0x0286, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 60 }, /* Adaptec Rocket Catch All */ + { 0x9005, 0x0288, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 61 }, /* Adaptec NEMER/ARK Catch All */ { 0,} }; MODULE_DEVICE_TABLE(pci, aac_pci_tbl); @@ -230,7 +231,8 @@ static struct aac_driver_ident aac_drive { aac_rx_init, "aacraid", "DELL ", "RAID ", 2, AAC_QUIRK_31BIT | AAC_QUIRK_34SG }, /* Dell Catchall */ { aac_rx_init, "aacraid", "Legend ", "RAID ", 2, AAC_QUIRK_31BIT | AAC_QUIRK_34SG }, /* Legend Catchall */ { aac_rx_init, "aacraid", "ADAPTEC ", "RAID ", 2, AAC_QUIRK_31BIT | AAC_QUIRK_34SG }, /* Adaptec Catch All */ - { aac_rkt_init, "aacraid", "ADAPTEC ", "RAID ", 2 } /* Adaptec Rocket Catch All */ + { aac_rkt_init, "aacraid", "ADAPTEC ", "RAID ", 2 }, /* Adaptec Rocket Catch All */ + { aac_nark_init, "aacraid", "ADAPTEC ", "RAID ", 2 } /* Adaptec NEMER/ARK Catch All */ }; /** @@ -396,11 +398,15 @@ static int aac_slave_configure(struct sc sdev->skip_ms_page_3f = 1; } if ((sdev->type == TYPE_DISK) && - !expose_physicals && (sdev_channel(sdev) != CONTAINER_CHANNEL)) { - struct aac_dev *aac = (struct aac_dev *)sdev->host->hostdata; - if (!aac->raid_scsi_mode || (sdev_channel(sdev) != 2)) - sdev->no_uld_attach = 1; + if (expose_physicals == 0) + return -ENXIO; + if (expose_physicals < 0) { + struct aac_dev *aac = + (struct aac_dev *)sdev->host->hostdata; + if (!aac->raid_scsi_mode || (sdev_channel(sdev) != 2)) + sdev->no_uld_attach = 1; + } } if (sdev->tagged_supported && (sdev->type == TYPE_DISK) && (sdev_channel(sdev) == CONTAINER_CHANNEL)) { @@ -768,7 +774,7 @@ static struct class_device_attribute *aa }; -static struct file_operations aac_cfg_fops = { +static const struct file_operations aac_cfg_fops = { .owner = THIS_MODULE, .ioctl = aac_cfg_ioctl, #ifdef CONFIG_COMPAT @@ -804,7 +810,6 @@ #endif .emulated = 1, }; - static int __devinit aac_probe_one(struct pci_dev *pdev, const struct pci_device_id *id) { diff --git a/drivers/scsi/aacraid/nark.c b/drivers/scsi/aacraid/nark.c new file mode 100644 index 0000000..c76b611 --- /dev/null +++ b/drivers/scsi/aacraid/nark.c @@ -0,0 +1,87 @@ +/* + * Adaptec AAC series RAID controller driver + * (c) Copyright 2001 Red Hat Inc. + * + * based on the old aacraid driver that is.. + * Adaptec aacraid device driver for Linux. + * + * Copyright (c) 2000 Adaptec, Inc. (aacraid@adaptec.com) + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * + * Module Name: + * nark.c + * + * Abstract: Hardware Device Interface for NEMER/ARK + * + */ + +#include +#include + +#include + +#include "aacraid.h" + +/** + * aac_nark_ioremap + * @size: mapping resize request + * + */ +static int aac_nark_ioremap(struct aac_dev * dev, u32 size) +{ + if (!size) { + iounmap(dev->regs.rx); + dev->regs.rx = NULL; + iounmap(dev->base); + dev->base = NULL; + return 0; + } + dev->scsi_host_ptr->base = pci_resource_start(dev->pdev, 2); + dev->regs.rx = ioremap((u64)pci_resource_start(dev->pdev, 0) | + ((u64)pci_resource_start(dev->pdev, 1) << 32), + sizeof(struct rx_registers) - sizeof(struct rx_inbound)); + dev->base = NULL; + if (dev->regs.rx == NULL) + return -1; + dev->base = ioremap(dev->scsi_host_ptr->base, size); + if (dev->base == NULL) { + iounmap(dev->regs.rx); + dev->regs.rx = NULL; + return -1; + } + dev->IndexRegs = &((struct rx_registers __iomem *)dev->base)->IndexRegs; + return 0; +} + +/** + * aac_nark_init - initialize an NEMER/ARK Split Bar card + * @dev: device to configure + * + */ + +int aac_nark_init(struct aac_dev * dev) +{ + extern int _aac_rx_init(struct aac_dev *dev); + extern int aac_rx_select_comm(struct aac_dev *dev, int comm); + + /* + * Fill in the function dispatch table. + */ + dev->a_ops.adapter_ioremap = aac_nark_ioremap; + dev->a_ops.adapter_comm = aac_rx_select_comm; + + return _aac_rx_init(dev); +} diff --git a/drivers/scsi/aacraid/rkt.c b/drivers/scsi/aacraid/rkt.c index 643f23b..d953c3f 100644 --- a/drivers/scsi/aacraid/rkt.c +++ b/drivers/scsi/aacraid/rkt.c @@ -34,6 +34,40 @@ #include #include "aacraid.h" +#define AAC_NUM_IO_FIB_RKT (246 - AAC_NUM_MGT_FIB) + +/** + * aac_rkt_select_comm - Select communications method + * @dev: Adapter + * @comm: communications method + */ + +static int aac_rkt_select_comm(struct aac_dev *dev, int comm) +{ + int retval; + extern int aac_rx_select_comm(struct aac_dev *dev, int comm); + retval = aac_rx_select_comm(dev, comm); + if (comm == AAC_COMM_MESSAGE) { + /* + * FIB Setup has already been done, but we can minimize the + * damage by at least ensuring the OS never issues more + * commands than we can handle. The Rocket adapters currently + * can only handle 246 commands and 8 AIFs at the same time, + * and in fact do notify us accordingly if we negotiate the + * FIB size. The problem that causes us to add this check is + * to ensure that we do not overdo it with the adapter when a + * hard coded FIB override is being utilized. This special + * case warrants this half baked, but convenient, check here. + */ + if (dev->scsi_host_ptr->can_queue > AAC_NUM_IO_FIB_RKT) { + dev->init->MaxIoCommands = + cpu_to_le32(AAC_NUM_IO_FIB_RKT + AAC_NUM_MGT_FIB); + dev->scsi_host_ptr->can_queue = AAC_NUM_IO_FIB_RKT; + } + } + return retval; +} + /** * aac_rkt_ioremap * @size: mapping resize request @@ -63,39 +97,13 @@ static int aac_rkt_ioremap(struct aac_de int aac_rkt_init(struct aac_dev *dev) { - int retval; extern int _aac_rx_init(struct aac_dev *dev); - extern void aac_rx_start_adapter(struct aac_dev *dev); /* * Fill in the function dispatch table. */ dev->a_ops.adapter_ioremap = aac_rkt_ioremap; + dev->a_ops.adapter_comm = aac_rkt_select_comm; - retval = _aac_rx_init(dev); - if (retval) - return retval; - if (dev->new_comm_interface) { - /* - * FIB Setup has already been done, but we can minimize the - * damage by at least ensuring the OS never issues more - * commands than we can handle. The Rocket adapters currently - * can only handle 246 commands and 8 AIFs at the same time, - * and in fact do notify us accordingly if we negotiate the - * FIB size. The problem that causes us to add this check is - * to ensure that we do not overdo it with the adapter when a - * hard coded FIB override is being utilized. This special - * case warrants this half baked, but convenient, check here. - */ - if (dev->scsi_host_ptr->can_queue > (246 - AAC_NUM_MGT_FIB)) { - dev->init->MaxIoCommands = cpu_to_le32(246); - dev->scsi_host_ptr->can_queue = 246 - AAC_NUM_MGT_FIB; - } - } - /* - * Tell the adapter that all is configured, and it can start - * accepting requests - */ - aac_rx_start_adapter(dev); - return 0; + return _aac_rx_init(dev); } diff --git a/drivers/scsi/aacraid/rx.c b/drivers/scsi/aacraid/rx.c index dcc8b0e..d242e26 100644 --- a/drivers/scsi/aacraid/rx.c +++ b/drivers/scsi/aacraid/rx.c @@ -31,7 +31,6 @@ #include #include #include -#include #include #include #include @@ -46,60 +45,60 @@ #include #include "aacraid.h" -static irqreturn_t aac_rx_intr(int irq, void *dev_id) +static irqreturn_t aac_rx_intr_producer(int irq, void *dev_id) { struct aac_dev *dev = dev_id; + unsigned long bellbits; + u8 intstat = rx_readb(dev, MUnit.OISR); - dprintk((KERN_DEBUG "aac_rx_intr(%d,%p)\n", irq, dev_id)); - if (dev->new_comm_interface) { - u32 Index = rx_readl(dev, MUnit.OutboundQueue); - if (Index == 0xFFFFFFFFL) - Index = rx_readl(dev, MUnit.OutboundQueue); - if (Index != 0xFFFFFFFFL) { - do { - if (aac_intr_normal(dev, Index)) { - rx_writel(dev, MUnit.OutboundQueue, Index); - rx_writel(dev, MUnit.ODR, DoorBellAdapterNormRespReady); - } - Index = rx_readl(dev, MUnit.OutboundQueue); - } while (Index != 0xFFFFFFFFL); - return IRQ_HANDLED; + /* + * Read mask and invert because drawbridge is reversed. + * This allows us to only service interrupts that have + * been enabled. + * Check to see if this is our interrupt. If it isn't just return + */ + if (intstat & ~(dev->OIMR)) { + bellbits = rx_readl(dev, OutboundDoorbellReg); + if (bellbits & DoorBellPrintfReady) { + aac_printf(dev, readl (&dev->IndexRegs->Mailbox[5])); + rx_writel(dev, MUnit.ODR,DoorBellPrintfReady); + rx_writel(dev, InboundDoorbellReg,DoorBellPrintfDone); } - } else { - unsigned long bellbits; - u8 intstat; - intstat = rx_readb(dev, MUnit.OISR); - /* - * Read mask and invert because drawbridge is reversed. - * This allows us to only service interrupts that have - * been enabled. - * Check to see if this is our interrupt. If it isn't just return - */ - if (intstat & ~(dev->OIMR)) - { - bellbits = rx_readl(dev, OutboundDoorbellReg); - if (bellbits & DoorBellPrintfReady) { - aac_printf(dev, readl (&dev->IndexRegs->Mailbox[5])); - rx_writel(dev, MUnit.ODR,DoorBellPrintfReady); - rx_writel(dev, InboundDoorbellReg,DoorBellPrintfDone); - } - else if (bellbits & DoorBellAdapterNormCmdReady) { - rx_writel(dev, MUnit.ODR, DoorBellAdapterNormCmdReady); - aac_command_normal(&dev->queues->queue[HostNormCmdQueue]); - } - else if (bellbits & DoorBellAdapterNormRespReady) { - rx_writel(dev, MUnit.ODR,DoorBellAdapterNormRespReady); - aac_response_normal(&dev->queues->queue[HostNormRespQueue]); - } - else if (bellbits & DoorBellAdapterNormCmdNotFull) { - rx_writel(dev, MUnit.ODR, DoorBellAdapterNormCmdNotFull); - } - else if (bellbits & DoorBellAdapterNormRespNotFull) { - rx_writel(dev, MUnit.ODR, DoorBellAdapterNormCmdNotFull); - rx_writel(dev, MUnit.ODR, DoorBellAdapterNormRespNotFull); - } - return IRQ_HANDLED; + else if (bellbits & DoorBellAdapterNormCmdReady) { + rx_writel(dev, MUnit.ODR, DoorBellAdapterNormCmdReady); + aac_command_normal(&dev->queues->queue[HostNormCmdQueue]); + } + else if (bellbits & DoorBellAdapterNormRespReady) { + rx_writel(dev, MUnit.ODR,DoorBellAdapterNormRespReady); + aac_response_normal(&dev->queues->queue[HostNormRespQueue]); + } + else if (bellbits & DoorBellAdapterNormCmdNotFull) { + rx_writel(dev, MUnit.ODR, DoorBellAdapterNormCmdNotFull); } + else if (bellbits & DoorBellAdapterNormRespNotFull) { + rx_writel(dev, MUnit.ODR, DoorBellAdapterNormCmdNotFull); + rx_writel(dev, MUnit.ODR, DoorBellAdapterNormRespNotFull); + } + return IRQ_HANDLED; + } + return IRQ_NONE; +} + +static irqreturn_t aac_rx_intr_message(int irq, void *dev_id) +{ + struct aac_dev *dev = dev_id; + u32 Index = rx_readl(dev, MUnit.OutboundQueue); + if (Index == 0xFFFFFFFFL) + Index = rx_readl(dev, MUnit.OutboundQueue); + if (Index != 0xFFFFFFFFL) { + do { + if (aac_intr_normal(dev, Index)) { + rx_writel(dev, MUnit.OutboundQueue, Index); + rx_writel(dev, MUnit.ODR, DoorBellAdapterNormRespReady); + } + Index = rx_readl(dev, MUnit.OutboundQueue); + } while (Index != 0xFFFFFFFFL); + return IRQ_HANDLED; } return IRQ_NONE; } @@ -115,6 +114,26 @@ static void aac_rx_disable_interrupt(str } /** + * aac_rx_enable_interrupt_producer - Enable interrupts + * @dev: Adapter + */ + +static void aac_rx_enable_interrupt_producer(struct aac_dev *dev) +{ + rx_writeb(dev, MUnit.OIMR, dev->OIMR = 0xfb); +} + +/** + * aac_rx_enable_interrupt_message - Enable interrupts + * @dev: Adapter + */ + +static void aac_rx_enable_interrupt_message(struct aac_dev *dev) +{ + rx_writeb(dev, MUnit.OIMR, dev->OIMR = 0xf7); +} + +/** * rx_sync_cmd - send a command and wait * @dev: Adapter * @command: Command to execute @@ -189,10 +208,7 @@ static int rx_sync_cmd(struct aac_dev *d /* * Restore interrupt mask even though we timed out */ - if (dev->new_comm_interface) - rx_writeb(dev, MUnit.OIMR, dev->OIMR = 0xf7); - else - rx_writeb(dev, MUnit.OIMR, dev->OIMR = 0xfb); + aac_adapter_enable_int(dev); return -ETIMEDOUT; } /* @@ -215,10 +231,7 @@ static int rx_sync_cmd(struct aac_dev *d /* * Restore interrupt mask */ - if (dev->new_comm_interface) - rx_writeb(dev, MUnit.OIMR, dev->OIMR = 0xf7); - else - rx_writeb(dev, MUnit.OIMR, dev->OIMR = 0xfb); + aac_adapter_enable_int(dev); return 0; } @@ -360,35 +373,72 @@ static int aac_rx_check_health(struct aa } /** - * aac_rx_send + * aac_rx_deliver_producer * @fib: fib to issue * * Will send a fib, returning 0 if successful. */ -static int aac_rx_send(struct fib * fib) +static int aac_rx_deliver_producer(struct fib * fib) { - u64 addr = fib->hw_fib_pa; struct aac_dev *dev = fib->dev; - volatile void __iomem *device = dev->regs.rx; + struct aac_queue *q = &dev->queues->queue[AdapNormCmdQueue]; + unsigned long qflags; u32 Index; + unsigned long nointr = 0; - dprintk((KERN_DEBUG "%p->aac_rx_send(%p->%llx)\n", dev, fib, addr)); - Index = rx_readl(dev, MUnit.InboundQueue); - if (Index == 0xFFFFFFFFL) + spin_lock_irqsave(q->lock, qflags); + aac_queue_get( dev, &Index, AdapNormCmdQueue, fib->hw_fib, 1, fib, &nointr); + + q->numpending++; + *(q->headers.producer) = cpu_to_le32(Index + 1); + spin_unlock_irqrestore(q->lock, qflags); + if (!(nointr & aac_config.irq_mod)) + aac_adapter_notify(dev, AdapNormCmdQueue); + + return 0; +} + +/** + * aac_rx_deliver_message + * @fib: fib to issue + * + * Will send a fib, returning 0 if successful. + */ +static int aac_rx_deliver_message(struct fib * fib) +{ + struct aac_dev *dev = fib->dev; + struct aac_queue *q = &dev->queues->queue[AdapNormCmdQueue]; + unsigned long qflags; + u32 Index; + u64 addr; + volatile void __iomem *device; + + unsigned long count = 10000000L; /* 50 seconds */ + spin_lock_irqsave(q->lock, qflags); + q->numpending++; + spin_unlock_irqrestore(q->lock, qflags); + for(;;) { Index = rx_readl(dev, MUnit.InboundQueue); - dprintk((KERN_DEBUG "Index = 0x%x\n", Index)); - if (Index == 0xFFFFFFFFL) - return Index; + if (Index == 0xFFFFFFFFL) + Index = rx_readl(dev, MUnit.InboundQueue); + if (Index != 0xFFFFFFFFL) + break; + if (--count == 0) { + spin_lock_irqsave(q->lock, qflags); + q->numpending--; + spin_unlock_irqrestore(q->lock, qflags); + return -ETIMEDOUT; + } + udelay(5); + } device = dev->base + Index; - dprintk((KERN_DEBUG "entry = %x %x %u\n", (u32)(addr & 0xffffffff), - (u32)(addr >> 32), (u32)le16_to_cpu(fib->hw_fib->header.Size))); + addr = fib->hw_fib_pa; writel((u32)(addr & 0xffffffff), device); device += sizeof(u32); writel((u32)(addr >> 32), device); device += sizeof(u32); writel(le16_to_cpu(fib->hw_fib->header.Size), device); rx_writel(dev, MUnit.InboundQueue, Index); - dprintk((KERN_DEBUG "aac_rx_send - return 0\n")); return 0; } @@ -430,6 +480,31 @@ static int aac_rx_restart_adapter(struct } /** + * aac_rx_select_comm - Select communications method + * @dev: Adapter + * @comm: communications method + */ + +int aac_rx_select_comm(struct aac_dev *dev, int comm) +{ + switch (comm) { + case AAC_COMM_PRODUCER: + dev->a_ops.adapter_enable_int = aac_rx_enable_interrupt_producer; + dev->a_ops.adapter_intr = aac_rx_intr_producer; + dev->a_ops.adapter_deliver = aac_rx_deliver_producer; + break; + case AAC_COMM_MESSAGE: + dev->a_ops.adapter_enable_int = aac_rx_enable_interrupt_message; + dev->a_ops.adapter_intr = aac_rx_intr_message; + dev->a_ops.adapter_deliver = aac_rx_deliver_message; + break; + default: + return 1; + } + return 0; +} + +/** * aac_rx_init - initialize an i960 based AAC card * @dev: device to configure * @@ -489,40 +564,42 @@ int _aac_rx_init(struct aac_dev *dev) } msleep(1); } - if (request_irq(dev->scsi_host_ptr->irq, aac_rx_intr, IRQF_SHARED|IRQF_DISABLED, "aacraid", (void *)dev)<0) - { - printk(KERN_ERR "%s%d: Interrupt unavailable.\n", name, instance); - goto error_iounmap; - } /* - * Fill in the function dispatch table. + * Fill in the common function dispatch table. */ dev->a_ops.adapter_interrupt = aac_rx_interrupt_adapter; dev->a_ops.adapter_disable_int = aac_rx_disable_interrupt; dev->a_ops.adapter_notify = aac_rx_notify_adapter; dev->a_ops.adapter_sync_cmd = rx_sync_cmd; dev->a_ops.adapter_check_health = aac_rx_check_health; - dev->a_ops.adapter_send = aac_rx_send; /* * First clear out all interrupts. Then enable the one's that we * can handle. */ - rx_writeb(dev, MUnit.OIMR, 0xff); + aac_adapter_comm(dev, AAC_COMM_PRODUCER); + aac_adapter_disable_int(dev); rx_writel(dev, MUnit.ODR, 0xffffffff); - rx_writeb(dev, MUnit.OIMR, dev->OIMR = 0xfb); + aac_adapter_enable_int(dev); if (aac_init_adapter(dev) == NULL) - goto error_irq; - if (dev->new_comm_interface) - rx_writeb(dev, MUnit.OIMR, dev->OIMR = 0xf7); + goto error_iounmap; + aac_adapter_comm(dev, dev->comm_interface); + if (request_irq(dev->scsi_host_ptr->irq, dev->a_ops.adapter_intr, + IRQF_SHARED|IRQF_DISABLED, "aacraid", dev) < 0) { + printk(KERN_ERR "%s%d: Interrupt unavailable.\n", + name, instance); + goto error_iounmap; + } + aac_adapter_enable_int(dev); + /* + * Tell the adapter that all is configured, and it can + * start accepting requests + */ + aac_rx_start_adapter(dev); return 0; -error_irq: - rx_writeb(dev, MUnit.OIMR, dev->OIMR = 0xff); - free_irq(dev->scsi_host_ptr->irq, (void *)dev); - error_iounmap: return -1; @@ -530,20 +607,11 @@ error_iounmap: int aac_rx_init(struct aac_dev *dev) { - int retval; - /* * Fill in the function dispatch table. */ dev->a_ops.adapter_ioremap = aac_rx_ioremap; + dev->a_ops.adapter_comm = aac_rx_select_comm; - retval = _aac_rx_init(dev); - if (!retval) { - /* - * Tell the adapter that all is configured, and it can - * start accepting requests - */ - aac_rx_start_adapter(dev); - } - return retval; + return _aac_rx_init(dev); } diff --git a/drivers/scsi/aacraid/sa.c b/drivers/scsi/aacraid/sa.c index 511b0a9..6f1a178 100644 --- a/drivers/scsi/aacraid/sa.c +++ b/drivers/scsi/aacraid/sa.c @@ -31,7 +31,6 @@ #include #include #include -#include #include #include #include @@ -92,6 +91,17 @@ static void aac_sa_disable_interrupt (st } /** + * aac_sa_enable_interrupt - enable interrupt + * @dev: Which adapter to enable. + */ + +static void aac_sa_enable_interrupt (struct aac_dev *dev) +{ + sa_writew(dev, SaDbCSR.PRICLEARIRQMASK, (PrintfReady | DOORBELL_1 | + DOORBELL_2 | DOORBELL_3 | DOORBELL_4)); +} + +/** * aac_sa_notify_adapter - handle adapter notification * @dev: Adapter that notification is for * @event: Event to notidy @@ -347,32 +357,36 @@ int aac_sa_init(struct aac_dev *dev) msleep(1); } - if (request_irq(dev->scsi_host_ptr->irq, aac_sa_intr, IRQF_SHARED|IRQF_DISABLED, "aacraid", (void *)dev ) < 0) { - printk(KERN_WARNING "%s%d: Interrupt unavailable.\n", name, instance); - goto error_iounmap; - } - /* * Fill in the function dispatch table. */ dev->a_ops.adapter_interrupt = aac_sa_interrupt_adapter; dev->a_ops.adapter_disable_int = aac_sa_disable_interrupt; + dev->a_ops.adapter_enable_int = aac_sa_enable_interrupt; dev->a_ops.adapter_notify = aac_sa_notify_adapter; dev->a_ops.adapter_sync_cmd = sa_sync_cmd; dev->a_ops.adapter_check_health = aac_sa_check_health; + dev->a_ops.adapter_intr = aac_sa_intr; dev->a_ops.adapter_ioremap = aac_sa_ioremap; /* * First clear out all interrupts. Then enable the one's that * we can handle. */ - sa_writew(dev, SaDbCSR.PRISETIRQMASK, 0xffff); - sa_writew(dev, SaDbCSR.PRICLEARIRQMASK, (PrintfReady | DOORBELL_1 | - DOORBELL_2 | DOORBELL_3 | DOORBELL_4)); + aac_adapter_disable_int(dev); + aac_adapter_enable_int(dev); if(aac_init_adapter(dev) == NULL) goto error_irq; + if (request_irq(dev->scsi_host_ptr->irq, dev->a_ops.adapter_intr, + IRQF_SHARED|IRQF_DISABLED, + "aacraid", (void *)dev ) < 0) { + printk(KERN_WARNING "%s%d: Interrupt unavailable.\n", + name, instance); + goto error_iounmap; + } + aac_adapter_enable_int(dev); /* * Tell the adapter that all is configure, and it can start @@ -382,7 +396,7 @@ int aac_sa_init(struct aac_dev *dev) return 0; error_irq: - sa_writew(dev, SaDbCSR.PRISETIRQMASK, 0xffff); + aac_sa_disable_interrupt(dev); free_irq(dev->scsi_host_ptr->irq, (void *)dev); error_iounmap: diff --git a/drivers/scsi/advansys.c b/drivers/scsi/advansys.c index 306bec3..9b3303b 100644 --- a/drivers/scsi/advansys.c +++ b/drivers/scsi/advansys.c @@ -4403,7 +4403,7 @@ #ifdef CONFIG_ISA ASC_DBG1(1, "advansys_detect: probing I/O port 0x%x...\n", iop); - if (check_region(iop, ASC_IOADR_GAP) != 0) { + if (!request_region(iop, ASC_IOADR_GAP, "advansys")){ printk( "AdvanSys SCSI: specified I/O Port 0x%X is busy\n", iop); /* Don't try this I/O port twice. */ @@ -4413,6 +4413,7 @@ #ifdef CONFIG_ISA printk( "AdvanSys SCSI: specified I/O Port 0x%X has no adapter\n", iop); /* Don't try this I/O port twice. */ + release_region(iop, ASC_IOADR_GAP); asc_ioport[ioport] = 0; goto ioport_try_again; } else { @@ -4431,6 +4432,7 @@ #ifdef CONFIG_ISA * 'ioport' past this board. */ ioport++; + release_region(iop, ASC_IOADR_GAP); goto ioport_try_again; } } @@ -9740,13 +9742,14 @@ AscSearchIOPortAddr11( } for (; i < ASC_IOADR_TABLE_MAX_IX; i++) { iop_base = _asc_def_iop_base[i]; - if (check_region(iop_base, ASC_IOADR_GAP) != 0) { + if (!request_region(iop_base, ASC_IOADR_GAP, "advansys")){ ASC_DBG1(1, "AscSearchIOPortAddr11: check_region() failed I/O port 0x%x\n", iop_base); continue; } ASC_DBG1(1, "AscSearchIOPortAddr11: probing I/O port 0x%x\n", iop_base); + release_region(iop_base, ASC_IOADR_GAP); if (AscFindSignature(iop_base)) { return (iop_base); } diff --git a/drivers/scsi/aha152x.c b/drivers/scsi/aha152x.c index 0cec742..4b4d123 100644 --- a/drivers/scsi/aha152x.c +++ b/drivers/scsi/aha152x.c @@ -236,7 +236,6 @@ **************************************************************************/ #include -#include #include #include #include diff --git a/drivers/scsi/aic7xxx/aic79xx.h b/drivers/scsi/aic7xxx/aic79xx.h index 170a434..27adbb2 100644 --- a/drivers/scsi/aic7xxx/aic79xx.h +++ b/drivers/scsi/aic7xxx/aic79xx.h @@ -1337,9 +1337,6 @@ int ahd_pci_test_register_access(struct /************************** SCB and SCB queue management **********************/ void ahd_qinfifo_requeue_tail(struct ahd_softc *ahd, struct scb *scb); -int ahd_match_scb(struct ahd_softc *ahd, struct scb *scb, - int target, char channel, int lun, - u_int tag, role_t role); /****************************** Initialization ********************************/ struct ahd_softc *ahd_alloc(void *platform_arg, char *name); diff --git a/drivers/scsi/aic7xxx/aic79xx_core.c b/drivers/scsi/aic7xxx/aic79xx_core.c index 07a86a3..9ddc6e4 100644 --- a/drivers/scsi/aic7xxx/aic79xx_core.c +++ b/drivers/scsi/aic7xxx/aic79xx_core.c @@ -262,6 +262,9 @@ static void ahd_update_coalescing_value u_int mincmds); static int ahd_verify_vpd_cksum(struct vpd_config *vpd); static int ahd_wait_seeprom(struct ahd_softc *ahd); +static int ahd_match_scb(struct ahd_softc *ahd, struct scb *scb, + int target, char channel, int lun, + u_int tag, role_t role); /******************************** Private Inlines *****************************/ @@ -7256,7 +7259,7 @@ ahd_busy_tcl(struct ahd_softc *ahd, u_in } /************************** SCB and SCB queue management **********************/ -int +static int ahd_match_scb(struct ahd_softc *ahd, struct scb *scb, int target, char channel, int lun, u_int tag, role_t role) { diff --git a/drivers/scsi/aic7xxx/aic79xx_osm.c b/drivers/scsi/aic7xxx/aic79xx_osm.c index 9bfcca5..c7fe478 100644 --- a/drivers/scsi/aic7xxx/aic79xx_osm.c +++ b/drivers/scsi/aic7xxx/aic79xx_osm.c @@ -1126,15 +1126,6 @@ ahd_linux_register_host(struct ahd_softc return 0; } -uint64_t -ahd_linux_get_memsize(void) -{ - struct sysinfo si; - - si_meminfo(&si); - return ((uint64_t)si.totalram << PAGE_SHIFT); -} - /* * Place the SCSI bus into a known state by either resetting it, * or forcing transfer negotiations on the next command to any diff --git a/drivers/scsi/aic7xxx/aic79xx_osm.h b/drivers/scsi/aic7xxx/aic79xx_osm.h index 3a67fc5..147c83c 100644 --- a/drivers/scsi/aic7xxx/aic79xx_osm.h +++ b/drivers/scsi/aic7xxx/aic79xx_osm.h @@ -496,8 +496,6 @@ ahd_insb(struct ahd_softc * ahd, long po int ahd_linux_register_host(struct ahd_softc *, struct scsi_host_template *); -uint64_t ahd_linux_get_memsize(void); - /*************************** Pretty Printing **********************************/ struct info_str { char *buffer; diff --git a/drivers/scsi/aic7xxx/aic79xx_osm_pci.c b/drivers/scsi/aic7xxx/aic79xx_osm_pci.c index 1a3ab6a..c62ce41 100644 --- a/drivers/scsi/aic7xxx/aic79xx_osm_pci.c +++ b/drivers/scsi/aic7xxx/aic79xx_osm_pci.c @@ -132,6 +132,7 @@ ahd_linux_pci_dev_probe(struct pci_dev * struct ahd_pci_identity *entry; char *name; int error; + struct device *dev = &pdev->dev; pci = pdev; entry = ahd_find_pci_device(pci); @@ -161,20 +162,18 @@ ahd_linux_pci_dev_probe(struct pci_dev * pci_set_master(pdev); if (sizeof(dma_addr_t) > 4) { - uint64_t memsize; - const uint64_t mask_39bit = 0x7FFFFFFFFFULL; + const u64 required_mask = dma_get_required_mask(dev); - memsize = ahd_linux_get_memsize(); - - if (memsize >= 0x8000000000ULL - && pci_set_dma_mask(pdev, DMA_64BIT_MASK) == 0) { + if (required_mask > DMA_39BIT_MASK && + dma_set_mask(dev, DMA_64BIT_MASK) == 0) ahd->flags |= AHD_64BIT_ADDRESSING; - } else if (memsize > 0x80000000 - && pci_set_dma_mask(pdev, mask_39bit) == 0) { + else if (required_mask > DMA_32BIT_MASK && + dma_set_mask(dev, DMA_39BIT_MASK) == 0) ahd->flags |= AHD_39BIT_ADDRESSING; - } + else + dma_set_mask(dev, DMA_32BIT_MASK); } else { - pci_set_dma_mask(pdev, DMA_32BIT_MASK); + dma_set_mask(dev, DMA_32BIT_MASK); } ahd->dev_softc = pci; error = ahd_pci_config(ahd, entry); diff --git a/drivers/scsi/aic7xxx/aic79xx_pci.c b/drivers/scsi/aic7xxx/aic79xx_pci.c index 2cf7bb3..8d72bba 100644 --- a/drivers/scsi/aic7xxx/aic79xx_pci.c +++ b/drivers/scsi/aic7xxx/aic79xx_pci.c @@ -88,7 +88,7 @@ #define SUBID_9005_AUTOTERM(id) (((id) & #define SUBID_9005_LEGACYCONN_FUNC(id) ((id) & 0x20) -#define SUBID_9005_SEEPTYPE(id) ((id) & 0x0C0) >> 6) +#define SUBID_9005_SEEPTYPE(id) (((id) & 0x0C0) >> 6) #define SUBID_9005_SEEPTYPE_NONE 0x0 #define SUBID_9005_SEEPTYPE_4K 0x1 diff --git a/drivers/scsi/aic7xxx_old.c b/drivers/scsi/aic7xxx_old.c index 7d1fec6..a988d5a 100644 --- a/drivers/scsi/aic7xxx_old.c +++ b/drivers/scsi/aic7xxx_old.c @@ -229,7 +229,6 @@ #include #include #include #include -#include #include #include #include diff --git a/drivers/scsi/aic94xx/aic94xx_dev.c b/drivers/scsi/aic94xx/aic94xx_dev.c index 6f8901b..c520e5b 100644 --- a/drivers/scsi/aic94xx/aic94xx_dev.c +++ b/drivers/scsi/aic94xx/aic94xx_dev.c @@ -37,18 +37,14 @@ #define CLEAR_DDB(_ddb, _ha) clear_bit(_ static inline int asd_get_ddb(struct asd_ha_struct *asd_ha) { - unsigned long flags; int ddb, i; - spin_lock_irqsave(&asd_ha->hw_prof.ddb_lock, flags); ddb = FIND_FREE_DDB(asd_ha); if (ddb >= asd_ha->hw_prof.max_ddbs) { ddb = -ENOMEM; - spin_unlock_irqrestore(&asd_ha->hw_prof.ddb_lock, flags); goto out; } SET_DDB(ddb, asd_ha); - spin_unlock_irqrestore(&asd_ha->hw_prof.ddb_lock, flags); for (i = 0; i < sizeof(struct asd_ddb_ssp_smp_target_port); i+= 4) asd_ddbsite_write_dword(asd_ha, ddb, i, 0); @@ -77,14 +73,10 @@ #define ITNL_TIMEOUT offsetof(struct static inline void asd_free_ddb(struct asd_ha_struct *asd_ha, int ddb) { - unsigned long flags; - if (!ddb || ddb >= 0xFFFF) return; asd_ddbsite_write_byte(asd_ha, ddb, DDB_TYPE, DDB_TYPE_UNUSED); - spin_lock_irqsave(&asd_ha->hw_prof.ddb_lock, flags); CLEAR_DDB(ddb, asd_ha); - spin_unlock_irqrestore(&asd_ha->hw_prof.ddb_lock, flags); } static inline void asd_set_ddb_type(struct domain_device *dev) @@ -320,8 +312,11 @@ out: int asd_dev_found(struct domain_device *dev) { + unsigned long flags; int res = 0; + struct asd_ha_struct *asd_ha = dev->port->ha->lldd_ha; + spin_lock_irqsave(&asd_ha->hw_prof.ddb_lock, flags); switch (dev->dev_type) { case SATA_PM: res = asd_init_sata_pm_ddb(dev); @@ -335,14 +330,18 @@ int asd_dev_found(struct domain_device * else res = asd_init_initiator_ddb(dev); } + spin_unlock_irqrestore(&asd_ha->hw_prof.ddb_lock, flags); + return res; } void asd_dev_gone(struct domain_device *dev) { int ddb, sister_ddb; + unsigned long flags; struct asd_ha_struct *asd_ha = dev->port->ha->lldd_ha; + spin_lock_irqsave(&asd_ha->hw_prof.ddb_lock, flags); ddb = (int) (unsigned long) dev->lldd_dev; sister_ddb = asd_ddbsite_read_word(asd_ha, ddb, SISTER_DDB); @@ -350,4 +349,5 @@ void asd_dev_gone(struct domain_device * asd_free_ddb(asd_ha, sister_ddb); asd_free_ddb(asd_ha, ddb); dev->lldd_dev = NULL; + spin_unlock_irqrestore(&asd_ha->hw_prof.ddb_lock, flags); } diff --git a/drivers/scsi/aic94xx/aic94xx_dump.c b/drivers/scsi/aic94xx/aic94xx_dump.c index e6ade59..6bd8e30 100644 --- a/drivers/scsi/aic94xx/aic94xx_dump.c +++ b/drivers/scsi/aic94xx/aic94xx_dump.c @@ -556,7 +556,7 @@ static void asd_dump_lseq_state(struct a PRINT_LMIP_word(asd_ha, lseq, Q_TGTXFR_TAIL); PRINT_LMIP_byte(asd_ha, lseq, LINK_NUMBER); PRINT_LMIP_byte(asd_ha, lseq, SCRATCH_FLAGS); - PRINT_LMIP_qword(asd_ha, lseq, CONNECTION_STATE); + PRINT_LMIP_dword(asd_ha, lseq, CONNECTION_STATE); PRINT_LMIP_word(asd_ha, lseq, CONCTL); PRINT_LMIP_byte(asd_ha, lseq, CONSTAT); PRINT_LMIP_byte(asd_ha, lseq, CONNECTION_MODES); diff --git a/drivers/scsi/aic94xx/aic94xx_hwi.c b/drivers/scsi/aic94xx/aic94xx_hwi.c index da94e12..0cd7eed 100644 --- a/drivers/scsi/aic94xx/aic94xx_hwi.c +++ b/drivers/scsi/aic94xx/aic94xx_hwi.c @@ -1052,10 +1052,9 @@ static inline struct asd_ascb *asd_ascb_ struct asd_ascb *ascb; unsigned long flags; - ascb = kmem_cache_alloc(asd_ascb_cache, gfp_flags); + ascb = kmem_cache_zalloc(asd_ascb_cache, gfp_flags); if (ascb) { - memset(ascb, 0, sizeof(*ascb)); ascb->dma_scb.size = sizeof(struct scb); ascb->dma_scb.vaddr = dma_pool_alloc(asd_ha->scb_pool, gfp_flags, diff --git a/drivers/scsi/aic94xx/aic94xx_init.c b/drivers/scsi/aic94xx/aic94xx_init.c index fbc82b0..27852b4 100644 --- a/drivers/scsi/aic94xx/aic94xx_init.c +++ b/drivers/scsi/aic94xx/aic94xx_init.c @@ -38,7 +38,7 @@ #include "aic94xx_hwi.h" #include "aic94xx_seq.h" /* The format is "version.release.patchlevel" */ -#define ASD_DRIVER_VERSION "1.0.2" +#define ASD_DRIVER_VERSION "1.0.3" static int use_msi = 0; module_param_named(use_msi, use_msi, int, S_IRUGO); @@ -57,6 +57,8 @@ MODULE_PARM_DESC(collector, "\n" char sas_addr_str[2*SAS_ADDR_SIZE + 1] = ""; static struct scsi_transport_template *aic94xx_transport_template; +static int asd_scan_finished(struct Scsi_Host *, unsigned long); +static void asd_scan_start(struct Scsi_Host *); static struct scsi_host_template aic94xx_sht = { .module = THIS_MODULE, @@ -66,6 +68,8 @@ static struct scsi_host_template aic94xx .target_alloc = sas_target_alloc, .slave_configure = sas_slave_configure, .slave_destroy = sas_slave_destroy, + .scan_finished = asd_scan_finished, + .scan_start = asd_scan_start, .change_queue_depth = sas_change_queue_depth, .change_queue_type = sas_change_queue_type, .bios_param = sas_bios_param, @@ -75,6 +79,8 @@ static struct scsi_host_template aic94xx .sg_tablesize = SG_ALL, .max_sectors = SCSI_DEFAULT_MAX_SECTORS, .use_clustering = ENABLE_CLUSTERING, + .eh_device_reset_handler = sas_eh_device_reset_handler, + .eh_bus_reset_handler = sas_eh_bus_reset_handler, }; static int __devinit asd_map_memio(struct asd_ha_struct *asd_ha) @@ -234,7 +240,7 @@ static int __devinit asd_common_setup(st } /* Provide some sane default values. */ asd_ha->hw_prof.max_scbs = 512; - asd_ha->hw_prof.max_ddbs = 128; + asd_ha->hw_prof.max_ddbs = ASD_MAX_DDBS; asd_ha->hw_prof.num_phys = ASD_MAX_PHYS; /* All phys are enabled, by default. */ asd_ha->hw_prof.enabled_phys = 0xFF; @@ -526,6 +532,7 @@ static int asd_register_sas_ha(struct as asd_ha->sas_ha.num_phys= ASD_MAX_PHYS; asd_ha->sas_ha.lldd_queue_size = asd_ha->seq.can_queue; + asd_ha->sas_ha.lldd_max_execute_num = lldd_max_execute_num; return sas_register_ha(&asd_ha->sas_ha); } @@ -646,7 +653,7 @@ static int __devinit asd_pci_probe(struc if (use_msi) pci_enable_msi(asd_ha->pcidev); - err = request_irq(asd_ha->pcidev->irq, asd_hw_isr, SA_SHIRQ, + err = request_irq(asd_ha->pcidev->irq, asd_hw_isr, IRQF_SHARED, ASD_DRIVER_NAME, asd_ha); if (err) { asd_printk("couldn't get irq %d for %s\n", @@ -671,21 +678,10 @@ static int __devinit asd_pci_probe(struc if (err) goto Err_reg_sas; - err = asd_enable_phys(asd_ha, asd_ha->hw_prof.enabled_phys); - if (err) { - asd_printk("coudln't enable phys, err:%d\n", err); - goto Err_en_phys; - } - ASD_DPRINTK("enabled phys\n"); - /* give the phy enabling interrupt event time to come in (1s - * is empirically about all it takes) */ - ssleep(1); - /* Wait for discovery to finish */ - scsi_flush_work(asd_ha->sas_ha.core.shost); + scsi_scan_host(shost); return 0; -Err_en_phys: - asd_unregister_sas_ha(asd_ha); + Err_reg_sas: asd_remove_dev_attrs(asd_ha); Err_dev_attrs: @@ -778,6 +774,28 @@ static void __devexit asd_pci_remove(str return; } +static void asd_scan_start(struct Scsi_Host *shost) +{ + struct asd_ha_struct *asd_ha; + int err; + + asd_ha = SHOST_TO_SAS_HA(shost)->lldd_ha; + err = asd_enable_phys(asd_ha, asd_ha->hw_prof.enabled_phys); + if (err) + asd_printk("Couldn't enable phys, err:%d\n", err); +} + +static int asd_scan_finished(struct Scsi_Host *shost, unsigned long time) +{ + /* give the phy enabling interrupt event time to come in (1s + * is empirically about all it takes) */ + if (time < HZ) + return 0; + /* Wait for discovery to finish */ + scsi_flush_work(shost); + return 1; +} + static ssize_t asd_version_show(struct device_driver *driver, char *buf) { return snprintf(buf, PAGE_SIZE, "%s\n", ASD_DRIVER_VERSION); @@ -885,6 +903,7 @@ static void __exit aic94xx_exit(void) asd_remove_driver_attrs(&aic94xx_pci_driver.driver); pci_unregister_driver(&aic94xx_pci_driver); sas_release_transport(aic94xx_transport_template); + asd_release_firmware(); asd_destroy_global_caches(); asd_printk("%s version %s unloaded\n", ASD_DRIVER_DESCRIPTION, ASD_DRIVER_VERSION); diff --git a/drivers/scsi/aic94xx/aic94xx_reg_def.h b/drivers/scsi/aic94xx/aic94xx_reg_def.h index a11f4e6..a43e8cd 100644 --- a/drivers/scsi/aic94xx/aic94xx_reg_def.h +++ b/drivers/scsi/aic94xx/aic94xx_reg_def.h @@ -2226,9 +2226,10 @@ #define LmSEQ_SAVED_OOB_SIGNALS(LinkNum) #define LmSEQ_SAS_RESET_MODE(LinkNum) (LmSCRATCH(LinkNum) + 0x0074) #define LmSEQ_LINK_RESET_RETRY_COUNT(LinkNum) (LmSCRATCH(LinkNum) + 0x0075) #define LmSEQ_NUM_LINK_RESET_RETRIES(LinkNum) (LmSCRATCH(LinkNum) + 0x0076) -#define LmSEQ_OOB_INT_ENABLES(LinkNum) (LmSCRATCH(LinkNum) + 0x007A) +#define LmSEQ_OOB_INT_ENABLES(LinkNum) (LmSCRATCH(LinkNum) + 0x0078) +#define LmSEQ_NOTIFY_TIMER_DOWN_COUNT(LinkNum) (LmSCRATCH(LinkNum) + 0x007A) #define LmSEQ_NOTIFY_TIMER_TIMEOUT(LinkNum) (LmSCRATCH(LinkNum) + 0x007C) -#define LmSEQ_NOTIFY_TIMER_DOWN_COUNT(LinkNum) (LmSCRATCH(LinkNum) + 0x007E) +#define LmSEQ_NOTIFY_TIMER_INITIAL_COUNT(LinkNum) (LmSCRATCH(LinkNum) + 0x007E) /* Mode dependent scratch page 1, mode 0 and mode 1 */ #define LmSEQ_SG_LIST_PTR_ADDR0(LinkNum) (LmSCRATCH(LinkNum) + 0x0020) diff --git a/drivers/scsi/aic94xx/aic94xx_sas.h b/drivers/scsi/aic94xx/aic94xx_sas.h index 9050e93..fa7c529 100644 --- a/drivers/scsi/aic94xx/aic94xx_sas.h +++ b/drivers/scsi/aic94xx/aic94xx_sas.h @@ -34,6 +34,7 @@ #include * domain that this sequencer can maintain low-level connections for * us. They are be 64 bytes. */ +#define ASD_MAX_DDBS 128 struct asd_ddb_ssp_smp_target_port { u8 conn_type; /* byte 0 */ diff --git a/drivers/scsi/aic94xx/aic94xx_scb.c b/drivers/scsi/aic94xx/aic94xx_scb.c index 75ed6b0..8f43ff7 100644 --- a/drivers/scsi/aic94xx/aic94xx_scb.c +++ b/drivers/scsi/aic94xx/aic94xx_scb.c @@ -413,40 +413,6 @@ void asd_invalidate_edb(struct asd_ascb } } -/* hard reset a phy later */ -static void do_phy_reset_later(struct work_struct *work) -{ - struct sas_phy *sas_phy = - container_of(work, struct sas_phy, reset_work); - int error; - - ASD_DPRINTK("%s: About to hard reset phy %d\n", __FUNCTION__, - sas_phy->identify.phy_identifier); - /* Reset device port */ - error = sas_phy_reset(sas_phy, 1); - if (error) - ASD_DPRINTK("%s: Hard reset of phy %d failed (%d).\n", - __FUNCTION__, sas_phy->identify.phy_identifier, error); -} - -static void phy_reset_later(struct sas_phy *sas_phy, struct Scsi_Host *shost) -{ - INIT_WORK(&sas_phy->reset_work, do_phy_reset_later); - queue_work(shost->work_q, &sas_phy->reset_work); -} - -/* start up the ABORT TASK tmf... */ -static void task_kill_later(struct asd_ascb *ascb) -{ - struct asd_ha_struct *asd_ha = ascb->ha; - struct sas_ha_struct *sas_ha = &asd_ha->sas_ha; - struct Scsi_Host *shost = sas_ha->core.shost; - struct sas_task *task = ascb->uldd_task; - - INIT_WORK(&task->abort_work, sas_task_abort); - queue_work(shost->work_q, &task->abort_work); -} - static void escb_tasklet_complete(struct asd_ascb *ascb, struct done_list_struct *dl) { @@ -479,26 +445,55 @@ static void escb_tasklet_complete(struct case REQ_TASK_ABORT: { struct asd_ascb *a, *b; u16 tc_abort; + struct domain_device *failed_dev = NULL; + + ASD_DPRINTK("%s: REQ_TASK_ABORT, reason=0x%X\n", + __FUNCTION__, dl->status_block[3]); + /* + * Find the task that caused the abort and abort it first. + * The sequencer won't put anything on the done list until + * that happens. + */ tc_abort = *((u16*)(&dl->status_block[1])); tc_abort = le16_to_cpu(tc_abort); - ASD_DPRINTK("%s: REQ_TASK_ABORT, reason=0x%X\n", - __FUNCTION__, dl->status_block[3]); + list_for_each_entry_safe(a, b, &asd_ha->seq.pend_q, list) { + struct sas_task *task = ascb->uldd_task; - /* Find the pending task and abort it. */ - list_for_each_entry_safe(a, b, &asd_ha->seq.pend_q, list) - if (a->tc_index == tc_abort) { - task_kill_later(a); + if (task && a->tc_index == tc_abort) { + failed_dev = task->dev; + sas_task_abort(task); break; } + } + + if (!failed_dev) { + ASD_DPRINTK("%s: Can't find task (tc=%d) to abort!\n", + __FUNCTION__, tc_abort); + goto out; + } + + /* + * Now abort everything else for that device (hba?) so + * that the EH will wake up and do something. + */ + list_for_each_entry_safe(a, b, &asd_ha->seq.pend_q, list) { + struct sas_task *task = ascb->uldd_task; + + if (task && + task->dev == failed_dev && + a->tc_index != tc_abort) + sas_task_abort(task); + } + goto out; } case REQ_DEVICE_RESET: { - struct Scsi_Host *shost = sas_ha->core.shost; - struct sas_phy *dev_phy; struct asd_ascb *a; u16 conn_handle; + unsigned long flags; + struct sas_task *last_dev_task = NULL; conn_handle = *((u16*)(&dl->status_block[1])); conn_handle = le16_to_cpu(conn_handle); @@ -506,32 +501,47 @@ static void escb_tasklet_complete(struct ASD_DPRINTK("%s: REQ_DEVICE_RESET, reason=0x%X\n", __FUNCTION__, dl->status_block[3]); - /* Kill all pending tasks and reset the device */ - dev_phy = NULL; + /* Find the last pending task for the device... */ list_for_each_entry(a, &asd_ha->seq.pend_q, list) { - struct sas_task *task; - struct domain_device *dev; u16 x; + struct domain_device *dev; + struct sas_task *task = a->uldd_task; - task = a->uldd_task; if (!task) continue; dev = task->dev; x = (unsigned long)dev->lldd_dev; - if (x == conn_handle) { - dev_phy = dev->port->phy; - task_kill_later(a); - } + if (x == conn_handle) + last_dev_task = task; } - /* Reset device port */ - if (!dev_phy) { - ASD_DPRINTK("%s: No pending commands; can't reset.\n", - __FUNCTION__); + if (!last_dev_task) { + ASD_DPRINTK("%s: Device reset for idle device %d?\n", + __FUNCTION__, conn_handle); goto out; } - phy_reset_later(dev_phy, shost); + + /* ...and set the reset flag */ + spin_lock_irqsave(&last_dev_task->task_state_lock, flags); + last_dev_task->task_state_flags |= SAS_TASK_NEED_DEV_RESET; + spin_unlock_irqrestore(&last_dev_task->task_state_lock, flags); + + /* Kill all pending tasks for the device */ + list_for_each_entry(a, &asd_ha->seq.pend_q, list) { + u16 x; + struct domain_device *dev; + struct sas_task *task = a->uldd_task; + + if (!task) + continue; + dev = task->dev; + + x = (unsigned long)dev->lldd_dev; + if (x == conn_handle) + sas_task_abort(task); + } + goto out; } case SIGNAL_NCQ_ERROR: diff --git a/drivers/scsi/aic94xx/aic94xx_sds.c b/drivers/scsi/aic94xx/aic94xx_sds.c index e5a0ec3..5b0932f 100644 --- a/drivers/scsi/aic94xx/aic94xx_sds.c +++ b/drivers/scsi/aic94xx/aic94xx_sds.c @@ -427,7 +427,7 @@ struct asd_manuf_sec { struct asd_manuf_phy_desc { u8 state; /* low 4 bits */ -#define MS_PHY_STATE_ENABLEABLE 0 +#define MS_PHY_STATE_ENABLED 0 #define MS_PHY_STATE_REPORTED 1 #define MS_PHY_STATE_HIDDEN 2 u8 phy_id; @@ -756,11 +756,11 @@ static void *asd_find_ll_by_id(void * co * * HIDDEN phys do not count in the total count. REPORTED phys cannot * be enabled but are reported and counted towards the total. - * ENEBLEABLE phys are enabled by default and count towards the total. + * ENABLED phys are enabled by default and count towards the total. * The absolute total phy number is ASD_MAX_PHYS. hw_prof->num_phys * merely specifies the number of phys the host adapter decided to * report. E.g., it is possible for phys 0, 1 and 2 to be HIDDEN, - * phys 3, 4 and 5 to be REPORTED and phys 6 and 7 to be ENEBLEABLE. + * phys 3, 4 and 5 to be REPORTED and phys 6 and 7 to be ENABLED. * In this case ASD_MAX_PHYS is 8, hw_prof->num_phys is 5, and only 2 * are actually enabled (enabled by default, max number of phys * enableable in this case). @@ -816,8 +816,8 @@ static int asd_ms_get_phy_params(struct asd_ha->hw_prof.enabled_phys &= ~(1 << i); rep_phys++; continue; - case MS_PHY_STATE_ENABLEABLE: - ASD_DPRINTK("ms: phy%d: ENEBLEABLE\n", i); + case MS_PHY_STATE_ENABLED: + ASD_DPRINTK("ms: phy%d: ENABLED\n", i); asd_ha->hw_prof.enabled_phys |= (1 << i); en_phys++; break; diff --git a/drivers/scsi/aic94xx/aic94xx_seq.c b/drivers/scsi/aic94xx/aic94xx_seq.c index 8451125..eae7a24 100644 --- a/drivers/scsi/aic94xx/aic94xx_seq.c +++ b/drivers/scsi/aic94xx/aic94xx_seq.c @@ -810,6 +810,8 @@ static void asd_init_lseq_mdp(struct asd /* No delay for the first NOTIFY to be sent to the attached target. */ asd_write_reg_word(asd_ha, LmSEQ_NOTIFY_TIMER_DOWN_COUNT(lseq), ASD_NOTIFY_DOWN_COUNT); + asd_write_reg_word(asd_ha, LmSEQ_NOTIFY_TIMER_INITIAL_COUNT(lseq), + ASD_NOTIFY_DOWN_COUNT); /* LSEQ Mode dependent, mode 0 and 1, page 1 setup. */ for (i = 0; i < 2; i++) { @@ -907,6 +909,16 @@ static void asd_init_scb_sites(struct as for (i = 0; i < ASD_SCB_SIZE; i += 4) asd_scbsite_write_dword(asd_ha, site_no, i, 0); + /* Initialize SCB Site Opcode field to invalid. */ + asd_scbsite_write_byte(asd_ha, site_no, + offsetof(struct scb_header, opcode), + 0xFF); + + /* Initialize SCB Site Flags field to mean a response + * frame has been received. This means inadvertent + * frames received to be dropped. */ + asd_scbsite_write_byte(asd_ha, site_no, 0x49, 0x01); + /* Workaround needed by SEQ to fix a SATA issue is to exclude * certain SCB sites from the free list. */ if (!SCB_SITE_VALID(site_no)) @@ -922,16 +934,6 @@ static void asd_init_scb_sites(struct as /* Q_NEXT field of the last SCB is invalidated. */ asd_scbsite_write_word(asd_ha, site_no, 0, first_scb_site_no); - /* Initialize SCB Site Opcode field to invalid. */ - asd_scbsite_write_byte(asd_ha, site_no, - offsetof(struct scb_header, opcode), - 0xFF); - - /* Initialize SCB Site Flags field to mean a response - * frame has been received. This means inadvertent - * frames received to be dropped. */ - asd_scbsite_write_byte(asd_ha, site_no, 0x49, 0x01); - first_scb_site_no = site_no; max_scbs++; } @@ -1173,6 +1175,16 @@ static void asd_init_ddb_0(struct asd_ha set_bit(0, asd_ha->hw_prof.ddb_bitmap); } +static void asd_seq_init_ddb_sites(struct asd_ha_struct *asd_ha) +{ + unsigned int i; + unsigned int ddb_site; + + for (ddb_site = 0 ; ddb_site < ASD_MAX_DDBS; ddb_site++) + for (i = 0; i < sizeof(struct asd_ddb_ssp_smp_target_port); i+= 4) + asd_ddbsite_write_dword(asd_ha, ddb_site, i, 0); +} + /** * asd_seq_setup_seqs -- setup and initialize central and link sequencers * @asd_ha: pointer to host adapter structure @@ -1182,6 +1194,9 @@ static void asd_seq_setup_seqs(struct as int lseq; u8 lseq_mask; + /* Initialize DDB sites */ + asd_seq_init_ddb_sites(asd_ha); + /* Initialize SCB sites. Done first to compute some values which * the rest of the init code depends on. */ asd_init_scb_sites(asd_ha); @@ -1232,6 +1247,13 @@ static int asd_seq_start_lseq(struct asd return asd_seq_unpause_lseq(asd_ha, lseq); } +int asd_release_firmware(void) +{ + if (sequencer_fw) + release_firmware(sequencer_fw); + return 0; +} + static int asd_request_firmware(struct asd_ha_struct *asd_ha) { int err, i; @@ -1375,7 +1397,9 @@ void asd_update_port_links(struct asd_ha u8 phy_is_up; u8 mask; int i, err; + unsigned long flags; + spin_lock_irqsave(&asd_ha->hw_prof.ddb_lock, flags); for_each_phy(phy_mask, mask, i) asd_ddbsite_write_byte(asd_ha, 0, offsetof(struct asd_ddb_seq_shared, @@ -1395,6 +1419,7 @@ void asd_update_port_links(struct asd_ha break; } } + spin_unlock_irqrestore(&asd_ha->hw_prof.ddb_lock, flags); if (err) asd_printk("couldn't update DDB 0:error:%d\n", err); diff --git a/drivers/scsi/aic94xx/aic94xx_seq.h b/drivers/scsi/aic94xx/aic94xx_seq.h index 9e715e5..9437ff0 100644 --- a/drivers/scsi/aic94xx/aic94xx_seq.h +++ b/drivers/scsi/aic94xx/aic94xx_seq.h @@ -63,6 +63,7 @@ int asd_pause_lseq(struct asd_ha_struct int asd_unpause_lseq(struct asd_ha_struct *asd_ha, u8 lseq_mask); int asd_init_seqs(struct asd_ha_struct *asd_ha); int asd_start_seqs(struct asd_ha_struct *asd_ha); +int asd_release_firmware(void); void asd_update_port_links(struct asd_ha_struct *asd_ha, struct asd_phy *phy); #endif diff --git a/drivers/scsi/aic94xx/aic94xx_task.c b/drivers/scsi/aic94xx/aic94xx_task.c index d202ed5..e2ad5be 100644 --- a/drivers/scsi/aic94xx/aic94xx_task.c +++ b/drivers/scsi/aic94xx/aic94xx_task.c @@ -349,6 +349,7 @@ Again: spin_lock_irqsave(&task->task_state_lock, flags); task->task_state_flags &= ~SAS_TASK_STATE_PENDING; + task->task_state_flags &= ~SAS_TASK_AT_INITIATOR; task->task_state_flags |= SAS_TASK_STATE_DONE; if (unlikely((task->task_state_flags & SAS_TASK_STATE_ABORTED))) { spin_unlock_irqrestore(&task->task_state_lock, flags); @@ -557,6 +558,7 @@ int asd_execute_task(struct sas_task *ta struct sas_task *t = task; struct asd_ascb *ascb = NULL, *a; struct asd_ha_struct *asd_ha = task->dev->port->ha->lldd_ha; + unsigned long flags; res = asd_can_queue(asd_ha, num); if (res) @@ -599,6 +601,10 @@ int asd_execute_task(struct sas_task *ta } if (res) goto out_err_unmap; + + spin_lock_irqsave(&t->task_state_lock, flags); + t->task_state_flags |= SAS_TASK_AT_INITIATOR; + spin_unlock_irqrestore(&t->task_state_lock, flags); } list_del_init(&alist); @@ -617,6 +623,9 @@ out_err_unmap: if (a == b) break; t = a->uldd_task; + spin_lock_irqsave(&t->task_state_lock, flags); + t->task_state_flags &= ~SAS_TASK_AT_INITIATOR; + spin_unlock_irqrestore(&t->task_state_lock, flags); switch (t->task_proto) { case SATA_PROTO: case SAS_PROTO_STP: diff --git a/drivers/scsi/aic94xx/aic94xx_tmf.c b/drivers/scsi/aic94xx/aic94xx_tmf.c index 6123438..9a14a6d 100644 --- a/drivers/scsi/aic94xx/aic94xx_tmf.c +++ b/drivers/scsi/aic94xx/aic94xx_tmf.c @@ -566,9 +566,7 @@ static int asd_initiate_ssp_tmf(struct d res = TMF_RESP_FUNC_ESUPP; break; default: - ASD_DPRINTK("%s: converting result 0x%x to TMF_RESP_FUNC_FAILED\n", - __FUNCTION__, res); - res = TMF_RESP_FUNC_FAILED; + /* Allow TMF response codes to propagate upwards */ break; } out_err: diff --git a/drivers/scsi/amiga7xx.c b/drivers/scsi/amiga7xx.c index 9099d53..d5d3c4d 100644 --- a/drivers/scsi/amiga7xx.c +++ b/drivers/scsi/amiga7xx.c @@ -10,7 +10,6 @@ #include #include #include -#include #include #include diff --git a/drivers/scsi/arcmsr/arcmsr_hba.c b/drivers/scsi/arcmsr/arcmsr_hba.c index 086cc97..8b46158 100644 --- a/drivers/scsi/arcmsr/arcmsr_hba.c +++ b/drivers/scsi/arcmsr/arcmsr_hba.c @@ -322,7 +322,7 @@ static int arcmsr_probe(struct pci_dev * goto out_iounmap; error = request_irq(pdev->irq, arcmsr_do_interrupt, - SA_INTERRUPT | SA_SHIRQ, "arcmsr", acb); + IRQF_DISABLED | IRQF_SHARED, "arcmsr", acb); if (error) goto out_free_ccb_pool; diff --git a/drivers/scsi/arm/acornscsi.c b/drivers/scsi/arm/acornscsi.c index 9cf902b..eceacf6 100644 --- a/drivers/scsi/arm/acornscsi.c +++ b/drivers/scsi/arm/acornscsi.c @@ -131,7 +131,6 @@ #define NO_WRITE_STR STRx(NO_WRITE) #include #include -#include #include #include #include diff --git a/drivers/scsi/arm/arxescsi.c b/drivers/scsi/arm/arxescsi.c index 4385e9e..7e132c5 100644 --- a/drivers/scsi/arm/arxescsi.c +++ b/drivers/scsi/arm/arxescsi.c @@ -23,7 +23,6 @@ #include #include #include #include -#include #include #include #include diff --git a/drivers/scsi/arm/cumana_1.c b/drivers/scsi/arm/cumana_1.c index 3bdfc36..cf9a21c 100644 --- a/drivers/scsi/arm/cumana_1.c +++ b/drivers/scsi/arm/cumana_1.c @@ -5,7 +5,6 @@ */ #include #include -#include #include #include #include diff --git a/drivers/scsi/arm/cumana_2.c b/drivers/scsi/arm/cumana_2.c index 19edd9c..d2d51dc 100644 --- a/drivers/scsi/arm/cumana_2.c +++ b/drivers/scsi/arm/cumana_2.c @@ -21,7 +21,6 @@ #include #include #include #include -#include #include #include #include diff --git a/drivers/scsi/arm/ecoscsi.c b/drivers/scsi/arm/ecoscsi.c index 6adcccb..378e7af 100644 --- a/drivers/scsi/arm/ecoscsi.c +++ b/drivers/scsi/arm/ecoscsi.c @@ -23,7 +23,6 @@ #define AUTOSENSE #include #include -#include #include #include #include diff --git a/drivers/scsi/arm/eesox.c b/drivers/scsi/arm/eesox.c index 3f876fb..4677152 100644 --- a/drivers/scsi/arm/eesox.c +++ b/drivers/scsi/arm/eesox.c @@ -27,7 +27,6 @@ #include #include #include #include -#include #include #include #include diff --git a/drivers/scsi/arm/fas216.c b/drivers/scsi/arm/fas216.c index e05f0c2..2969cc0 100644 --- a/drivers/scsi/arm/fas216.c +++ b/drivers/scsi/arm/fas216.c @@ -39,7 +39,6 @@ #include #include #include #include -#include #include #include #include diff --git a/drivers/scsi/arm/oak.c b/drivers/scsi/arm/oak.c index d806b02..c21b839 100644 --- a/drivers/scsi/arm/oak.c +++ b/drivers/scsi/arm/oak.c @@ -6,7 +6,6 @@ #include #include -#include #include #include #include diff --git a/drivers/scsi/arm/powertec.c b/drivers/scsi/arm/powertec.c index ce159c1..f9cd20b 100644 --- a/drivers/scsi/arm/powertec.c +++ b/drivers/scsi/arm/powertec.c @@ -12,7 +12,6 @@ #include #include #include #include -#include #include #include #include diff --git a/drivers/scsi/atari_scsi.c b/drivers/scsi/atari_scsi.c index dfb1bcf..642de7b 100644 --- a/drivers/scsi/atari_scsi.c +++ b/drivers/scsi/atari_scsi.c @@ -86,7 +86,6 @@ #include #include #include #include -#include #include #include #include diff --git a/drivers/scsi/blz1230.c b/drivers/scsi/blz1230.c index 329a8f2..23f7c24 100644 --- a/drivers/scsi/blz1230.c +++ b/drivers/scsi/blz1230.c @@ -121,7 +121,8 @@ #endif */ address = ZTWO_VADDR(board); eregs = (struct ESP_regs *)(address + REAL_BLZ1230_ESP_ADDR); - esp = esp_allocate(tpnt, (void *)board+REAL_BLZ1230_ESP_ADDR); + esp = esp_allocate(tpnt, (void *)board + REAL_BLZ1230_ESP_ADDR, + 0); esp_write(eregs->esp_cfg1, (ESP_CONFIG1_PENABLE | 7)); udelay(5); diff --git a/drivers/scsi/blz2060.c b/drivers/scsi/blz2060.c index b6c137b..b6203ec 100644 --- a/drivers/scsi/blz2060.c +++ b/drivers/scsi/blz2060.c @@ -100,7 +100,7 @@ int __init blz2060_esp_detect(struct scs unsigned long board = z->resource.start; if (request_mem_region(board+BLZ2060_ESP_ADDR, sizeof(struct ESP_regs), "NCR53C9x")) { - esp = esp_allocate(tpnt, (void *)board+BLZ2060_ESP_ADDR); + esp = esp_allocate(tpnt, (void *)board + BLZ2060_ESP_ADDR, 0); /* Do command transfer with programmed I/O */ esp->do_pio_cmds = 1; diff --git a/drivers/scsi/bvme6000.c b/drivers/scsi/bvme6000.c index 2958b8c..599b400 100644 --- a/drivers/scsi/bvme6000.c +++ b/drivers/scsi/bvme6000.c @@ -6,7 +6,6 @@ #include #include #include -#include #include #include diff --git a/drivers/scsi/ch.c b/drivers/scsi/ch.c index f6caa43..2a2cc6c 100644 --- a/drivers/scsi/ch.c +++ b/drivers/scsi/ch.c @@ -11,7 +11,6 @@ #include #include #include #include -#include #include #include #include @@ -129,7 +128,7 @@ static struct scsi_driver ch_template = }, }; -static struct file_operations changer_fops = +static const struct file_operations changer_fops = { .owner = THIS_MODULE, .open = ch_open, diff --git a/drivers/scsi/cyberstorm.c b/drivers/scsi/cyberstorm.c index 7c7cfb5..c6b98a4 100644 --- a/drivers/scsi/cyberstorm.c +++ b/drivers/scsi/cyberstorm.c @@ -126,7 +126,7 @@ int __init cyber_esp_detect(struct scsi_ sizeof(struct ESP_regs)); return 0; } - esp = esp_allocate(tpnt, (void *)board+CYBER_ESP_ADDR); + esp = esp_allocate(tpnt, (void *)board + CYBER_ESP_ADDR, 0); /* Do command transfer with programmed I/O */ esp->do_pio_cmds = 1; diff --git a/drivers/scsi/cyberstormII.c b/drivers/scsi/cyberstormII.c index d88cb9c..e336e85 100644 --- a/drivers/scsi/cyberstormII.c +++ b/drivers/scsi/cyberstormII.c @@ -98,7 +98,7 @@ int __init cyberII_esp_detect(struct scs address = (unsigned long)ZTWO_VADDR(board); eregs = (struct ESP_regs *)(address + CYBERII_ESP_ADDR); - esp = esp_allocate(tpnt, (void *)board+CYBERII_ESP_ADDR); + esp = esp_allocate(tpnt, (void *)board + CYBERII_ESP_ADDR, 0); esp_write(eregs->esp_cfg1, (ESP_CONFIG1_PENABLE | 7)); udelay(5); diff --git a/drivers/scsi/dec_esp.c b/drivers/scsi/dec_esp.c index c29ccbc..d42ad66 100644 --- a/drivers/scsi/dec_esp.c +++ b/drivers/scsi/dec_esp.c @@ -18,7 +18,7 @@ * 20001005 - Initialization fixes for 2.4.0-test9 * Florian Lohoff * - * Copyright (C) 2002, 2003, 2005 Maciej W. Rozycki + * Copyright (C) 2002, 2003, 2005, 2006 Maciej W. Rozycki */ #include @@ -30,6 +30,7 @@ #include #include #include #include +#include #include #include @@ -42,7 +43,6 @@ #include #include #include #include -#include #define DEC_SCSI_SREG 0 #define DEC_SCSI_DMAREG 0x40000 @@ -98,51 +98,33 @@ static irqreturn_t scsi_dma_merr_int(int static irqreturn_t scsi_dma_err_int(int, void *); static irqreturn_t scsi_dma_int(int, void *); -static int dec_esp_detect(struct scsi_host_template * tpnt); - -static int dec_esp_release(struct Scsi_Host *shost) -{ - if (shost->irq) - free_irq(shost->irq, NULL); - if (shost->io_port && shost->n_io_port) - release_region(shost->io_port, shost->n_io_port); - scsi_unregister(shost); - return 0; -} - -static struct scsi_host_template driver_template = { - .proc_name = "dec_esp", - .proc_info = esp_proc_info, +static struct scsi_host_template dec_esp_template = { + .module = THIS_MODULE, .name = "NCR53C94", - .detect = dec_esp_detect, - .slave_alloc = esp_slave_alloc, - .slave_destroy = esp_slave_destroy, - .release = dec_esp_release, .info = esp_info, .queuecommand = esp_queue, .eh_abort_handler = esp_abort, .eh_bus_reset_handler = esp_reset, + .slave_alloc = esp_slave_alloc, + .slave_destroy = esp_slave_destroy, + .proc_info = esp_proc_info, + .proc_name = "dec_esp", .can_queue = 7, - .this_id = 7, .sg_tablesize = SG_ALL, .cmd_per_lun = 1, .use_clustering = DISABLE_CLUSTERING, }; - -#include "scsi_module.c" +static struct NCR_ESP *dec_esp_platform; /***************************************************************** Detection */ -static int dec_esp_detect(struct scsi_host_template * tpnt) +static int dec_esp_platform_probe(void) { struct NCR_ESP *esp; - struct ConfigDev *esp_dev; - int slot; - unsigned long mem_start; + int err = 0; if (IOASIC) { - esp_dev = 0; - esp = esp_allocate(tpnt, (void *) esp_dev); + esp = esp_allocate(&dec_esp_template, NULL, 1); /* Do command transfer with programmed I/O */ esp->do_pio_cmds = 1; @@ -200,112 +182,175 @@ static int dec_esp_detect(struct scsi_ho /* Check for differential SCSI-bus */ esp->diff = 0; + err = request_irq(esp->irq, esp_intr, IRQF_DISABLED, + "ncr53c94", esp->ehost); + if (err) + goto err_alloc; + err = request_irq(dec_interrupt[DEC_IRQ_ASC_MERR], + scsi_dma_merr_int, IRQF_DISABLED, + "ncr53c94 error", esp->ehost); + if (err) + goto err_irq; + err = request_irq(dec_interrupt[DEC_IRQ_ASC_ERR], + scsi_dma_err_int, IRQF_DISABLED, + "ncr53c94 overrun", esp->ehost); + if (err) + goto err_irq_merr; + err = request_irq(dec_interrupt[DEC_IRQ_ASC_DMA], scsi_dma_int, + IRQF_DISABLED, "ncr53c94 dma", esp->ehost); + if (err) + goto err_irq_err; + esp_initialize(esp); - if (request_irq(esp->irq, esp_intr, IRQF_DISABLED, - "ncr53c94", esp->ehost)) - goto err_dealloc; - if (request_irq(dec_interrupt[DEC_IRQ_ASC_MERR], - scsi_dma_merr_int, IRQF_DISABLED, - "ncr53c94 error", esp->ehost)) - goto err_free_irq; - if (request_irq(dec_interrupt[DEC_IRQ_ASC_ERR], - scsi_dma_err_int, IRQF_DISABLED, - "ncr53c94 overrun", esp->ehost)) - goto err_free_irq_merr; - if (request_irq(dec_interrupt[DEC_IRQ_ASC_DMA], - scsi_dma_int, IRQF_DISABLED, - "ncr53c94 dma", esp->ehost)) - goto err_free_irq_err; + err = scsi_add_host(esp->ehost, NULL); + if (err) { + printk(KERN_ERR "ESP: Unable to register adapter\n"); + goto err_irq_dma; + } + + scsi_scan_host(esp->ehost); + dec_esp_platform = esp; } - if (TURBOCHANNEL) { - while ((slot = search_tc_card("PMAZ-AA")) >= 0) { - claim_tc_card(slot); - - esp_dev = 0; - esp = esp_allocate(tpnt, (void *) esp_dev); - - mem_start = get_tc_base_addr(slot); - - /* Store base addr into esp struct */ - esp->slot = CPHYSADDR(mem_start); - - esp->dregs = 0; - esp->eregs = (void *)CKSEG1ADDR(mem_start + - DEC_SCSI_SREG); - esp->do_pio_cmds = 1; - - /* Set the command buffer */ - esp->esp_command = (volatile unsigned char *) pmaz_cmd_buffer; - - /* get virtual dma address for command buffer */ - esp->esp_command_dvma = virt_to_phys(pmaz_cmd_buffer); - - esp->cfreq = get_tc_speed(); - - esp->irq = get_tc_irq_nr(slot); - - /* Required functions */ - esp->dma_bytes_sent = &dma_bytes_sent; - esp->dma_can_transfer = &dma_can_transfer; - esp->dma_dump_state = &dma_dump_state; - esp->dma_init_read = &pmaz_dma_init_read; - esp->dma_init_write = &pmaz_dma_init_write; - esp->dma_ints_off = &pmaz_dma_ints_off; - esp->dma_ints_on = &pmaz_dma_ints_on; - esp->dma_irq_p = &dma_irq_p; - esp->dma_ports_p = &dma_ports_p; - esp->dma_setup = &pmaz_dma_setup; - - /* Optional functions */ - esp->dma_barrier = 0; - esp->dma_drain = &pmaz_dma_drain; - esp->dma_invalidate = 0; - esp->dma_irq_entry = 0; - esp->dma_irq_exit = 0; - esp->dma_poll = 0; - esp->dma_reset = 0; - esp->dma_led_off = 0; - esp->dma_led_on = 0; - - esp->dma_mmu_get_scsi_one = pmaz_dma_mmu_get_scsi_one; - esp->dma_mmu_get_scsi_sgl = 0; - esp->dma_mmu_release_scsi_one = 0; - esp->dma_mmu_release_scsi_sgl = 0; - esp->dma_advance_sg = 0; - - if (request_irq(esp->irq, esp_intr, IRQF_DISABLED, - "PMAZ_AA", esp->ehost)) { - esp_deallocate(esp); - release_tc_card(slot); - continue; - } - esp->scsi_id = 7; - esp->diff = 0; - esp_initialize(esp); - } + return 0; + +err_irq_dma: + free_irq(dec_interrupt[DEC_IRQ_ASC_DMA], esp->ehost); +err_irq_err: + free_irq(dec_interrupt[DEC_IRQ_ASC_ERR], esp->ehost); +err_irq_merr: + free_irq(dec_interrupt[DEC_IRQ_ASC_MERR], esp->ehost); +err_irq: + free_irq(esp->irq, esp->ehost); +err_alloc: + esp_deallocate(esp); + scsi_host_put(esp->ehost); + return err; +} + +static int __init dec_esp_probe(struct device *dev) +{ + struct NCR_ESP *esp; + resource_size_t start, len; + int err; + + esp = esp_allocate(&dec_esp_template, NULL, 1); + + dev_set_drvdata(dev, esp); + + start = to_tc_dev(dev)->resource.start; + len = to_tc_dev(dev)->resource.end - start + 1; + + if (!request_mem_region(start, len, dev->bus_id)) { + printk(KERN_ERR "%s: Unable to reserve MMIO resource\n", + dev->bus_id); + err = -EBUSY; + goto err_alloc; } - if(nesps) { - printk("ESP: Total of %d ESP hosts found, %d actually in use.\n", nesps, esps_in_use); - esps_running = esps_in_use; - return esps_in_use; + /* Store base addr into esp struct. */ + esp->slot = start; + + esp->dregs = 0; + esp->eregs = (void *)CKSEG1ADDR(start + DEC_SCSI_SREG); + esp->do_pio_cmds = 1; + + /* Set the command buffer. */ + esp->esp_command = (volatile unsigned char *)pmaz_cmd_buffer; + + /* Get virtual dma address for command buffer. */ + esp->esp_command_dvma = virt_to_phys(pmaz_cmd_buffer); + + esp->cfreq = tc_get_speed(to_tc_dev(dev)->bus); + + esp->irq = to_tc_dev(dev)->interrupt; + + /* Required functions. */ + esp->dma_bytes_sent = &dma_bytes_sent; + esp->dma_can_transfer = &dma_can_transfer; + esp->dma_dump_state = &dma_dump_state; + esp->dma_init_read = &pmaz_dma_init_read; + esp->dma_init_write = &pmaz_dma_init_write; + esp->dma_ints_off = &pmaz_dma_ints_off; + esp->dma_ints_on = &pmaz_dma_ints_on; + esp->dma_irq_p = &dma_irq_p; + esp->dma_ports_p = &dma_ports_p; + esp->dma_setup = &pmaz_dma_setup; + + /* Optional functions. */ + esp->dma_barrier = 0; + esp->dma_drain = &pmaz_dma_drain; + esp->dma_invalidate = 0; + esp->dma_irq_entry = 0; + esp->dma_irq_exit = 0; + esp->dma_poll = 0; + esp->dma_reset = 0; + esp->dma_led_off = 0; + esp->dma_led_on = 0; + + esp->dma_mmu_get_scsi_one = pmaz_dma_mmu_get_scsi_one; + esp->dma_mmu_get_scsi_sgl = 0; + esp->dma_mmu_release_scsi_one = 0; + esp->dma_mmu_release_scsi_sgl = 0; + esp->dma_advance_sg = 0; + + err = request_irq(esp->irq, esp_intr, IRQF_DISABLED, "PMAZ_AA", + esp->ehost); + if (err) { + printk(KERN_ERR "%s: Unable to get IRQ %d\n", + dev->bus_id, esp->irq); + goto err_resource; + } + + esp->scsi_id = 7; + esp->diff = 0; + esp_initialize(esp); + + err = scsi_add_host(esp->ehost, dev); + if (err) { + printk(KERN_ERR "%s: Unable to register adapter\n", + dev->bus_id); + goto err_irq; } + + scsi_scan_host(esp->ehost); + return 0; -err_free_irq_err: - free_irq(dec_interrupt[DEC_IRQ_ASC_ERR], scsi_dma_err_int); -err_free_irq_merr: - free_irq(dec_interrupt[DEC_IRQ_ASC_MERR], scsi_dma_merr_int); -err_free_irq: - free_irq(esp->irq, esp_intr); -err_dealloc: +err_irq: + free_irq(esp->irq, esp->ehost); + +err_resource: + release_mem_region(start, len); + +err_alloc: esp_deallocate(esp); - return 0; + scsi_host_put(esp->ehost); + return err; +} + +static void __exit dec_esp_platform_remove(void) +{ + struct NCR_ESP *esp = dec_esp_platform; + + free_irq(esp->irq, esp->ehost); + esp_deallocate(esp); + scsi_host_put(esp->ehost); + dec_esp_platform = NULL; } +static void __exit dec_esp_remove(struct device *dev) +{ + struct NCR_ESP *esp = dev_get_drvdata(dev); + + free_irq(esp->irq, esp->ehost); + esp_deallocate(esp); + scsi_host_put(esp->ehost); +} + + /************************************************************* DMA Functions */ static irqreturn_t scsi_dma_merr_int(int irq, void *dev_id) { @@ -576,3 +621,67 @@ static void pmaz_dma_mmu_get_scsi_one(st { sp->SCp.ptr = (char *)virt_to_phys(sp->request_buffer); } + + +#ifdef CONFIG_TC +static int __init dec_esp_tc_probe(struct device *dev); +static int __exit dec_esp_tc_remove(struct device *dev); + +static const struct tc_device_id dec_esp_tc_table[] = { + { "DEC ", "PMAZ-AA " }, + { } +}; +MODULE_DEVICE_TABLE(tc, dec_esp_tc_table); + +static struct tc_driver dec_esp_tc_driver = { + .id_table = dec_esp_tc_table, + .driver = { + .name = "dec_esp", + .bus = &tc_bus_type, + .probe = dec_esp_tc_probe, + .remove = __exit_p(dec_esp_tc_remove), + }, +}; + +static int __init dec_esp_tc_probe(struct device *dev) +{ + int status = dec_esp_probe(dev); + if (!status) + get_device(dev); + return status; +} + +static int __exit dec_esp_tc_remove(struct device *dev) +{ + put_device(dev); + dec_esp_remove(dev); + return 0; +} +#endif + +static int __init dec_esp_init(void) +{ + int status; + + status = tc_register_driver(&dec_esp_tc_driver); + if (!status) + dec_esp_platform_probe(); + + if (nesps) { + pr_info("ESP: Total of %d ESP hosts found, " + "%d actually in use.\n", nesps, esps_in_use); + esps_running = esps_in_use; + } + + return status; +} + +static void __exit dec_esp_exit(void) +{ + dec_esp_platform_remove(); + tc_unregister_driver(&dec_esp_tc_driver); +} + + +module_init(dec_esp_init); +module_exit(dec_esp_exit); diff --git a/drivers/scsi/dpt_i2o.c b/drivers/scsi/dpt_i2o.c index 365db53..cd36e81 100644 --- a/drivers/scsi/dpt_i2o.c +++ b/drivers/scsi/dpt_i2o.c @@ -116,7 +116,7 @@ static int sys_tbl_len = 0; static adpt_hba* hba_chain = NULL; static int hba_count = 0; -static struct file_operations adpt_fops = { +static const struct file_operations adpt_fops = { .ioctl = adpt_ioctl, .open = adpt_open, .release = adpt_close diff --git a/drivers/scsi/dtc.c b/drivers/scsi/dtc.c index 5475672..9d52e45 100644 --- a/drivers/scsi/dtc.c +++ b/drivers/scsi/dtc.c @@ -75,7 +75,6 @@ #endif #include #include #include -#include #include #include #include diff --git a/drivers/scsi/eata_pio.c b/drivers/scsi/eata_pio.c index 2dbb66d..f33ad01 100644 --- a/drivers/scsi/eata_pio.c +++ b/drivers/scsi/eata_pio.c @@ -48,7 +48,6 @@ #include #include -#include #include #include #include diff --git a/drivers/scsi/fastlane.c b/drivers/scsi/fastlane.c index 2a1c5c2..4266a21 100644 --- a/drivers/scsi/fastlane.c +++ b/drivers/scsi/fastlane.c @@ -142,7 +142,7 @@ int __init fastlane_esp_detect(struct sc if (board < 0x1000000) { goto err_release; } - esp = esp_allocate(tpnt, (void *)board+FASTLANE_ESP_ADDR); + esp = esp_allocate(tpnt, (void *)board + FASTLANE_ESP_ADDR, 0); /* Do command transfer with programmed I/O */ esp->do_pio_cmds = 1; diff --git a/drivers/scsi/g_NCR5380.c b/drivers/scsi/g_NCR5380.c index cdd893b..880f70d 100644 --- a/drivers/scsi/g_NCR5380.c +++ b/drivers/scsi/g_NCR5380.c @@ -103,7 +103,6 @@ #endif #include #include #include -#include #include #include "scsi.h" #include diff --git a/drivers/scsi/gdth.c b/drivers/scsi/gdth.c index 4c698a7..8c81cec 100644 --- a/drivers/scsi/gdth.c +++ b/drivers/scsi/gdth.c @@ -387,7 +387,6 @@ #include #include #include #include -#include #include #include #include @@ -687,7 +686,7 @@ MODULE_AUTHOR("Achim Leubner"); MODULE_LICENSE("GPL"); /* ioctl interface */ -static struct file_operations gdth_fops = { +static const struct file_operations gdth_fops = { .ioctl = gdth_ioctl, .open = gdth_open, .release = gdth_close, diff --git a/drivers/scsi/gvp11.c b/drivers/scsi/gvp11.c index 2f6c113..37741e9 100644 --- a/drivers/scsi/gvp11.c +++ b/drivers/scsi/gvp11.c @@ -1,7 +1,6 @@ #include #include #include -#include #include #include diff --git a/drivers/scsi/ibmvscsi/ibmvstgt.c b/drivers/scsi/ibmvscsi/ibmvstgt.c index e28260f..4368ca0 100644 --- a/drivers/scsi/ibmvscsi/ibmvstgt.c +++ b/drivers/scsi/ibmvscsi/ibmvstgt.c @@ -580,7 +580,7 @@ static int crq_queue_create(struct crq_q } err = request_irq(vport->dma_dev->irq, &ibmvstgt_interrupt, - SA_INTERRUPT, "ibmvstgt", target); + IRQF_DISABLED, "ibmvstgt", target); if (err) goto req_irq_failed; diff --git a/drivers/scsi/initio.c b/drivers/scsi/initio.c index d561663..7e7635c 100644 --- a/drivers/scsi/initio.c +++ b/drivers/scsi/initio.c @@ -123,7 +123,6 @@ #include #include #include #include -#include #include #include #include diff --git a/drivers/scsi/ipr.c b/drivers/scsi/ipr.c index b318500..95045e3 100644 --- a/drivers/scsi/ipr.c +++ b/drivers/scsi/ipr.c @@ -595,10 +595,8 @@ static int ipr_save_pcix_cmd_reg(struct { int pcix_cmd_reg = pci_find_capability(ioa_cfg->pdev, PCI_CAP_ID_PCIX); - if (pcix_cmd_reg == 0) { - dev_err(&ioa_cfg->pdev->dev, "Failed to save PCI-X command register\n"); - return -EIO; - } + if (pcix_cmd_reg == 0) + return 0; if (pci_read_config_word(ioa_cfg->pdev, pcix_cmd_reg + PCI_X_CMD, &ioa_cfg->saved_pcix_cmd_reg) != PCIBIOS_SUCCESSFUL) { @@ -627,10 +625,6 @@ static int ipr_set_pcix_cmd_reg(struct i dev_err(&ioa_cfg->pdev->dev, "Failed to setup PCI-X command register\n"); return -EIO; } - } else { - dev_err(&ioa_cfg->pdev->dev, - "Failed to setup PCI-X command register\n"); - return -EIO; } return 0; @@ -6314,7 +6308,6 @@ static int ipr_reset_restore_cfg_space(s int rc; ENTER; - pci_unblock_user_cfg_access(ioa_cfg->pdev); rc = pci_restore_state(ioa_cfg->pdev); if (rc != PCIBIOS_SUCCESSFUL) { @@ -6355,6 +6348,24 @@ static int ipr_reset_restore_cfg_space(s } /** + * ipr_reset_bist_done - BIST has completed on the adapter. + * @ipr_cmd: ipr command struct + * + * Description: Unblock config space and resume the reset process. + * + * Return value: + * IPR_RC_JOB_CONTINUE + **/ +static int ipr_reset_bist_done(struct ipr_cmnd *ipr_cmd) +{ + ENTER; + pci_unblock_user_cfg_access(ipr_cmd->ioa_cfg->pdev); + ipr_cmd->job_step = ipr_reset_restore_cfg_space; + LEAVE; + return IPR_RC_JOB_CONTINUE; +} + +/** * ipr_reset_start_bist - Run BIST on the adapter. * @ipr_cmd: ipr command struct * @@ -6376,7 +6387,7 @@ static int ipr_reset_start_bist(struct i ipr_cmd->ioasa.ioasc = cpu_to_be32(IPR_IOASC_PCI_ACCESS_ERROR); rc = IPR_RC_JOB_CONTINUE; } else { - ipr_cmd->job_step = ipr_reset_restore_cfg_space; + ipr_cmd->job_step = ipr_reset_bist_done; ipr_reset_start_timer(ipr_cmd, IPR_WAIT_FOR_BIST_TIMEOUT); rc = IPR_RC_JOB_RETURN; } @@ -7166,9 +7177,6 @@ ipr_get_chip_cfg(const struct pci_device { int i; - if (dev_id->driver_data) - return (const struct ipr_chip_cfg_t *)dev_id->driver_data; - for (i = 0; i < ARRAY_SIZE(ipr_chip); i++) if (ipr_chip[i].vendor == dev_id->vendor && ipr_chip[i].device == dev_id->device) @@ -7517,65 +7525,43 @@ static void ipr_shutdown(struct pci_dev static struct pci_device_id ipr_pci_table[] __devinitdata = { { PCI_VENDOR_ID_MYLEX, PCI_DEVICE_ID_IBM_GEMSTONE, - PCI_VENDOR_ID_IBM, IPR_SUBS_DEV_ID_5702, - 0, 0, (kernel_ulong_t)&ipr_chip_cfg[0] }, + PCI_VENDOR_ID_IBM, IPR_SUBS_DEV_ID_5702, 0, 0, 0 }, { PCI_VENDOR_ID_MYLEX, PCI_DEVICE_ID_IBM_GEMSTONE, - PCI_VENDOR_ID_IBM, IPR_SUBS_DEV_ID_5703, - 0, 0, (kernel_ulong_t)&ipr_chip_cfg[0] }, + PCI_VENDOR_ID_IBM, IPR_SUBS_DEV_ID_5703, 0, 0, 0 }, { PCI_VENDOR_ID_MYLEX, PCI_DEVICE_ID_IBM_GEMSTONE, - PCI_VENDOR_ID_IBM, IPR_SUBS_DEV_ID_573D, - 0, 0, (kernel_ulong_t)&ipr_chip_cfg[0] }, + PCI_VENDOR_ID_IBM, IPR_SUBS_DEV_ID_573D, 0, 0, 0 }, { PCI_VENDOR_ID_MYLEX, PCI_DEVICE_ID_IBM_GEMSTONE, - PCI_VENDOR_ID_IBM, IPR_SUBS_DEV_ID_573E, - 0, 0, (kernel_ulong_t)&ipr_chip_cfg[0] }, + PCI_VENDOR_ID_IBM, IPR_SUBS_DEV_ID_573E, 0, 0, 0 }, { PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_CITRINE, - PCI_VENDOR_ID_IBM, IPR_SUBS_DEV_ID_571B, - 0, 0, (kernel_ulong_t)&ipr_chip_cfg[0] }, + PCI_VENDOR_ID_IBM, IPR_SUBS_DEV_ID_571B, 0, 0, 0 }, { PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_CITRINE, - PCI_VENDOR_ID_IBM, IPR_SUBS_DEV_ID_572E, - 0, 0, (kernel_ulong_t)&ipr_chip_cfg[0] }, + PCI_VENDOR_ID_IBM, IPR_SUBS_DEV_ID_572E, 0, 0, 0 }, { PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_CITRINE, - PCI_VENDOR_ID_IBM, IPR_SUBS_DEV_ID_571A, - 0, 0, (kernel_ulong_t)&ipr_chip_cfg[0] }, + PCI_VENDOR_ID_IBM, IPR_SUBS_DEV_ID_571A, 0, 0, 0 }, { PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_CITRINE, - PCI_VENDOR_ID_IBM, IPR_SUBS_DEV_ID_575B, - 0, 0, (kernel_ulong_t)&ipr_chip_cfg[0] }, + PCI_VENDOR_ID_IBM, IPR_SUBS_DEV_ID_575B, 0, 0, 0 }, { PCI_VENDOR_ID_ADAPTEC2, PCI_DEVICE_ID_ADAPTEC2_OBSIDIAN, - PCI_VENDOR_ID_IBM, IPR_SUBS_DEV_ID_572A, - 0, 0, (kernel_ulong_t)&ipr_chip_cfg[0] }, + PCI_VENDOR_ID_IBM, IPR_SUBS_DEV_ID_572A, 0, 0, 0 }, { PCI_VENDOR_ID_ADAPTEC2, PCI_DEVICE_ID_ADAPTEC2_OBSIDIAN, - PCI_VENDOR_ID_IBM, IPR_SUBS_DEV_ID_572B, - 0, 0, (kernel_ulong_t)&ipr_chip_cfg[0] }, + PCI_VENDOR_ID_IBM, IPR_SUBS_DEV_ID_572B, 0, 0, 0 }, { PCI_VENDOR_ID_ADAPTEC2, PCI_DEVICE_ID_ADAPTEC2_OBSIDIAN, - PCI_VENDOR_ID_IBM, IPR_SUBS_DEV_ID_575C, - 0, 0, (kernel_ulong_t)&ipr_chip_cfg[0] }, - { PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_OBSIDIAN, - PCI_VENDOR_ID_IBM, IPR_SUBS_DEV_ID_572A, - 0, 0, (kernel_ulong_t)&ipr_chip_cfg[0] }, + PCI_VENDOR_ID_IBM, IPR_SUBS_DEV_ID_575C, 0, 0, 0 }, { PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_OBSIDIAN, - PCI_VENDOR_ID_IBM, IPR_SUBS_DEV_ID_572B, - 0, 0, (kernel_ulong_t)&ipr_chip_cfg[0] }, + PCI_VENDOR_ID_IBM, IPR_SUBS_DEV_ID_572A, 0, 0, 0 }, { PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_OBSIDIAN, - PCI_VENDOR_ID_IBM, IPR_SUBS_DEV_ID_575C, - 0, 0, (kernel_ulong_t)&ipr_chip_cfg[0] }, + PCI_VENDOR_ID_IBM, IPR_SUBS_DEV_ID_572B, 0, 0, 0 }, { PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_OBSIDIAN, - PCI_VENDOR_ID_IBM, IPR_SUBS_DEV_ID_57B8, - 0, 0, (kernel_ulong_t)&ipr_chip_cfg[0] }, + PCI_VENDOR_ID_IBM, IPR_SUBS_DEV_ID_575C, 0, 0, 0 }, { PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_OBSIDIAN_E, - PCI_VENDOR_ID_IBM, IPR_SUBS_DEV_ID_57B7, - 0, 0, (kernel_ulong_t)&ipr_chip_cfg[0] }, + PCI_VENDOR_ID_IBM, IPR_SUBS_DEV_ID_57B7, 0, 0, 0 }, { PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_SNIPE, - PCI_VENDOR_ID_IBM, IPR_SUBS_DEV_ID_2780, - 0, 0, (kernel_ulong_t)&ipr_chip_cfg[1] }, + PCI_VENDOR_ID_IBM, IPR_SUBS_DEV_ID_2780, 0, 0, 0 }, { PCI_VENDOR_ID_ADAPTEC2, PCI_DEVICE_ID_ADAPTEC2_SCAMP, - PCI_VENDOR_ID_IBM, IPR_SUBS_DEV_ID_571E, - 0, 0, (kernel_ulong_t)&ipr_chip_cfg[1] }, + PCI_VENDOR_ID_IBM, IPR_SUBS_DEV_ID_571E, 0, 0, 0 }, { PCI_VENDOR_ID_ADAPTEC2, PCI_DEVICE_ID_ADAPTEC2_SCAMP, - PCI_VENDOR_ID_IBM, IPR_SUBS_DEV_ID_571F, - 0, 0, (kernel_ulong_t)&ipr_chip_cfg[1] }, + PCI_VENDOR_ID_IBM, IPR_SUBS_DEV_ID_571F, 0, 0, 0 }, { PCI_VENDOR_ID_ADAPTEC2, PCI_DEVICE_ID_ADAPTEC2_SCAMP, - PCI_VENDOR_ID_IBM, IPR_SUBS_DEV_ID_572F, - 0, 0, (kernel_ulong_t)&ipr_chip_cfg[1] }, + PCI_VENDOR_ID_IBM, IPR_SUBS_DEV_ID_572F, 0, 0, 0 }, { } }; MODULE_DEVICE_TABLE(pci, ipr_pci_table); diff --git a/drivers/scsi/ipr.h b/drivers/scsi/ipr.h index 9f62a1d..88f285d 100644 --- a/drivers/scsi/ipr.h +++ b/drivers/scsi/ipr.h @@ -37,8 +37,8 @@ #include /* * Literals */ -#define IPR_DRIVER_VERSION "2.3.0" -#define IPR_DRIVER_DATE "(November 8, 2006)" +#define IPR_DRIVER_VERSION "2.3.1" +#define IPR_DRIVER_DATE "(January 23, 2007)" /* * IPR_MAX_CMD_PER_LUN: This defines the maximum number of outstanding diff --git a/drivers/scsi/iscsi_tcp.c b/drivers/scsi/iscsi_tcp.c index 4376840..8f55e14 100644 --- a/drivers/scsi/iscsi_tcp.c +++ b/drivers/scsi/iscsi_tcp.c @@ -1375,7 +1375,7 @@ iscsi_tcp_mtask_xmit(struct iscsi_conn * } BUG_ON(tcp_mtask->xmstate != XMSTATE_IDLE); - if (mtask->hdr->itt == cpu_to_be32(ISCSI_RESERVED_TAG)) { + if (mtask->hdr->itt == RESERVED_ITT) { struct iscsi_session *session = conn->session; spin_lock_bh(&session->lock); diff --git a/drivers/scsi/jazz_esp.c b/drivers/scsi/jazz_esp.c index bfac444..19dd4b9 100644 --- a/drivers/scsi/jazz_esp.c +++ b/drivers/scsi/jazz_esp.c @@ -75,7 +75,7 @@ static int jazz_esp_detect(struct scsi_h */ if (1) { esp_dev = NULL; - esp = esp_allocate(tpnt, (void *) esp_dev); + esp = esp_allocate(tpnt, esp_dev, 0); /* Do command transfer with programmed I/O */ esp->do_pio_cmds = 1; diff --git a/drivers/scsi/lasi700.c b/drivers/scsi/lasi700.c index f0871c3..5c32a69 100644 --- a/drivers/scsi/lasi700.c +++ b/drivers/scsi/lasi700.c @@ -38,7 +38,6 @@ #include #include #include #include -#include #include #include @@ -123,6 +122,7 @@ lasi700_probe(struct parisc_device *dev) hostdata->force_le_on_be = 0; hostdata->chip710 = 1; hostdata->dmode_extra = DMODE_FC2; + hostdata->burst_length = 8; } host = NCR_700_detect(&lasi700_template, hostdata, &dev->dev); diff --git a/drivers/scsi/libiscsi.c b/drivers/scsi/libiscsi.c index d37048c..7c75771 100644 --- a/drivers/scsi/libiscsi.c +++ b/drivers/scsi/libiscsi.c @@ -113,8 +113,7 @@ static void iscsi_prep_scsi_cmd_pdu(stru hdr->opcode = ISCSI_OP_SCSI_CMD; hdr->flags = ISCSI_ATTR_SIMPLE; int_to_scsilun(sc->device->lun, (struct scsi_lun *)hdr->lun); - hdr->itt = ctask->itt | (conn->id << ISCSI_CID_SHIFT) | - (session->age << ISCSI_AGE_SHIFT); + hdr->itt = build_itt(ctask->itt, conn->id, session->age); hdr->data_length = cpu_to_be32(sc->request_bufflen); hdr->cmdsn = cpu_to_be32(session->cmdsn); session->cmdsn++; @@ -270,7 +269,7 @@ invalid_datalen: goto out; } - senselen = be16_to_cpu(*(uint16_t *)data); + senselen = be16_to_cpu(*(__be16 *)data); if (datalen < senselen) goto invalid_datalen; @@ -338,7 +337,7 @@ static int iscsi_handle_reject(struct is if (ntoh24(reject->dlength) >= sizeof(struct iscsi_hdr)) { memcpy(&rejected_pdu, data, sizeof(struct iscsi_hdr)); - itt = rejected_pdu.itt & ISCSI_ITT_MASK; + itt = get_itt(rejected_pdu.itt); printk(KERN_ERR "itt 0x%x had pdu (op 0x%x) rejected " "due to DataDigest error.\n", itt, rejected_pdu.opcode); @@ -367,10 +366,10 @@ int __iscsi_complete_pdu(struct iscsi_co struct iscsi_mgmt_task *mtask; uint32_t itt; - if (hdr->itt != cpu_to_be32(ISCSI_RESERVED_TAG)) - itt = hdr->itt & ISCSI_ITT_MASK; + if (hdr->itt != RESERVED_ITT) + itt = get_itt(hdr->itt); else - itt = hdr->itt; + itt = ~0U; if (itt < session->cmds_max) { ctask = session->cmds[itt]; @@ -440,7 +439,7 @@ int __iscsi_complete_pdu(struct iscsi_co iscsi_tmf_rsp(conn, hdr); break; case ISCSI_OP_NOOP_IN: - if (hdr->ttt != ISCSI_RESERVED_TAG || datalen) { + if (hdr->ttt != cpu_to_be32(ISCSI_RESERVED_TAG) || datalen) { rc = ISCSI_ERR_PROTO; break; } @@ -457,7 +456,7 @@ int __iscsi_complete_pdu(struct iscsi_co rc = ISCSI_ERR_BAD_OPCODE; break; } - } else if (itt == ISCSI_RESERVED_TAG) { + } else if (itt == ~0U) { rc = iscsi_check_assign_cmdsn(session, (struct iscsi_nopin*)hdr); if (rc) @@ -470,7 +469,7 @@ int __iscsi_complete_pdu(struct iscsi_co break; } - if (hdr->ttt == ISCSI_RESERVED_TAG) + if (hdr->ttt == cpu_to_be32(ISCSI_RESERVED_TAG)) break; if (iscsi_recv_pdu(conn->cls_conn, hdr, NULL, 0)) @@ -516,24 +515,24 @@ int iscsi_verify_itt(struct iscsi_conn * struct iscsi_cmd_task *ctask; uint32_t itt; - if (hdr->itt != cpu_to_be32(ISCSI_RESERVED_TAG)) { - if ((hdr->itt & ISCSI_AGE_MASK) != + if (hdr->itt != RESERVED_ITT) { + if (((__force u32)hdr->itt & ISCSI_AGE_MASK) != (session->age << ISCSI_AGE_SHIFT)) { printk(KERN_ERR "iscsi: received itt %x expected " - "session age (%x)\n", hdr->itt, + "session age (%x)\n", (__force u32)hdr->itt, session->age & ISCSI_AGE_MASK); return ISCSI_ERR_BAD_ITT; } - if ((hdr->itt & ISCSI_CID_MASK) != + if (((__force u32)hdr->itt & ISCSI_CID_MASK) != (conn->id << ISCSI_CID_SHIFT)) { printk(KERN_ERR "iscsi: received itt %x, expected " - "CID (%x)\n", hdr->itt, conn->id); + "CID (%x)\n", (__force u32)hdr->itt, conn->id); return ISCSI_ERR_BAD_ITT; } - itt = hdr->itt & ISCSI_ITT_MASK; + itt = get_itt(hdr->itt); } else - itt = hdr->itt; + itt = ~0U; if (itt < session->cmds_max) { ctask = session->cmds[itt]; @@ -896,9 +895,8 @@ iscsi_conn_send_generic(struct iscsi_con /* * pre-format CmdSN for outgoing PDU. */ - if (hdr->itt != cpu_to_be32(ISCSI_RESERVED_TAG)) { - hdr->itt = mtask->itt | (conn->id << ISCSI_CID_SHIFT) | - (session->age << ISCSI_AGE_SHIFT); + if (hdr->itt != RESERVED_ITT) { + hdr->itt = build_itt(mtask->itt, conn->id, session->age); nop->cmdsn = cpu_to_be32(session->cmdsn); if (conn->c_stage == ISCSI_CONN_STARTED && !(hdr->opcode & ISCSI_OP_IMMEDIATE)) @@ -1064,7 +1062,7 @@ static int iscsi_exec_abort_task(struct spin_lock_bh(&session->lock); ctask->mtask = (struct iscsi_mgmt_task *) - session->mgmt_cmds[(hdr->itt & ISCSI_ITT_MASK) - + session->mgmt_cmds[get_itt(hdr->itt) - ISCSI_MGMT_ITT_OFFSET]; if (conn->tmabort_state == TMABORT_INITIAL) { diff --git a/drivers/scsi/libsas/sas_discover.c b/drivers/scsi/libsas/sas_discover.c index fb7df7b..a65598b 100644 --- a/drivers/scsi/libsas/sas_discover.c +++ b/drivers/scsi/libsas/sas_discover.c @@ -548,7 +548,7 @@ int sas_discover_sata(struct domain_devi res = sas_notify_lldd_dev_found(dev); if (res) - return res; + goto out_err2; switch (dev->dev_type) { case SATA_DEV: @@ -560,11 +560,23 @@ int sas_discover_sata(struct domain_devi default: break; } + if (res) + goto out_err; sas_notify_lldd_dev_gone(dev); - if (!res) { - sas_notify_lldd_dev_found(dev); - } + res = sas_notify_lldd_dev_found(dev); + if (res) + goto out_err2; + + res = sas_rphy_add(dev->rphy); + if (res) + goto out_err; + + return res; + +out_err: + sas_notify_lldd_dev_gone(dev); +out_err2: return res; } @@ -580,21 +592,17 @@ int sas_discover_end_dev(struct domain_d res = sas_notify_lldd_dev_found(dev); if (res) - return res; + goto out_err2; res = sas_rphy_add(dev->rphy); if (res) goto out_err; - /* do this to get the end device port attributes which will have - * been scanned in sas_rphy_add */ - sas_notify_lldd_dev_gone(dev); - sas_notify_lldd_dev_found(dev); - return 0; out_err: sas_notify_lldd_dev_gone(dev); +out_err2: return res; } @@ -649,6 +657,7 @@ void sas_unregister_domain_devices(struc */ static void sas_discover_domain(struct work_struct *work) { + struct domain_device *dev; int error = 0; struct sas_discovery_event *ev = container_of(work, struct sas_discovery_event, work); @@ -658,35 +667,42 @@ static void sas_discover_domain(struct w &port->disc.pending); if (port->port_dev) - return ; - else { - error = sas_get_port_device(port); - if (error) - return; - } + return; + + error = sas_get_port_device(port); + if (error) + return; + dev = port->port_dev; SAS_DPRINTK("DOING DISCOVERY on port %d, pid:%d\n", port->id, current->pid); - switch (port->port_dev->dev_type) { + switch (dev->dev_type) { case SAS_END_DEV: - error = sas_discover_end_dev(port->port_dev); + error = sas_discover_end_dev(dev); break; case EDGE_DEV: case FANOUT_DEV: - error = sas_discover_root_expander(port->port_dev); + error = sas_discover_root_expander(dev); break; case SATA_DEV: case SATA_PM: - error = sas_discover_sata(port->port_dev); + error = sas_discover_sata(dev); break; default: - SAS_DPRINTK("unhandled device %d\n", port->port_dev->dev_type); + SAS_DPRINTK("unhandled device %d\n", dev->dev_type); break; } if (error) { - kfree(port->port_dev); /* not kobject_register-ed yet */ + sas_rphy_free(dev->rphy); + dev->rphy = NULL; + + spin_lock(&port->dev_list_lock); + list_del_init(&dev->dev_list_node); + spin_unlock(&port->dev_list_lock); + + kfree(dev); /* not kobject_register-ed yet */ port->port_dev = NULL; } @@ -726,7 +742,7 @@ int sas_discover_event(struct asd_sas_po BUG_ON(ev >= DISC_NUM_EVENTS); sas_queue_event(ev, &disc->disc_event_lock, &disc->pending, - &disc->disc_work[ev].work, port->ha->core.shost); + &disc->disc_work[ev].work, port->ha); return 0; } diff --git a/drivers/scsi/libsas/sas_event.c b/drivers/scsi/libsas/sas_event.c index d83392e..9db30fb 100644 --- a/drivers/scsi/libsas/sas_event.c +++ b/drivers/scsi/libsas/sas_event.c @@ -31,7 +31,7 @@ static void notify_ha_event(struct sas_h BUG_ON(event >= HA_NUM_EVENTS); sas_queue_event(event, &sas_ha->event_lock, &sas_ha->pending, - &sas_ha->ha_events[event].work, sas_ha->core.shost); + &sas_ha->ha_events[event].work, sas_ha); } static void notify_port_event(struct asd_sas_phy *phy, enum port_event event) @@ -41,7 +41,7 @@ static void notify_port_event(struct asd BUG_ON(event >= PORT_NUM_EVENTS); sas_queue_event(event, &ha->event_lock, &phy->port_events_pending, - &phy->port_events[event].work, ha->core.shost); + &phy->port_events[event].work, ha); } static void notify_phy_event(struct asd_sas_phy *phy, enum phy_event event) @@ -51,7 +51,7 @@ static void notify_phy_event(struct asd_ BUG_ON(event >= PHY_NUM_EVENTS); sas_queue_event(event, &ha->event_lock, &phy->phy_events_pending, - &phy->phy_events[event].work, ha->core.shost); + &phy->phy_events[event].work, ha); } int sas_init_events(struct sas_ha_struct *sas_ha) diff --git a/drivers/scsi/libsas/sas_expander.c b/drivers/scsi/libsas/sas_expander.c index d31e6fa..dc70c18 100644 --- a/drivers/scsi/libsas/sas_expander.c +++ b/drivers/scsi/libsas/sas_expander.c @@ -667,8 +667,9 @@ static struct domain_device *sas_ex_disc return child; out_list_del: + sas_rphy_free(child->rphy); + child->rphy = NULL; list_del(&child->dev_list_node); - sas_rphy_free(rphy); out_free: sas_port_delete(phy->port); out_err: @@ -677,6 +678,29 @@ static struct domain_device *sas_ex_disc return NULL; } +/* See if this phy is part of a wide port */ +static int sas_ex_join_wide_port(struct domain_device *parent, int phy_id) +{ + struct ex_phy *phy = &parent->ex_dev.ex_phy[phy_id]; + int i; + + for (i = 0; i < parent->ex_dev.num_phys; i++) { + struct ex_phy *ephy = &parent->ex_dev.ex_phy[i]; + + if (ephy == phy) + continue; + + if (!memcmp(phy->attached_sas_addr, ephy->attached_sas_addr, + SAS_ADDR_SIZE) && ephy->port) { + sas_port_add_phy(ephy->port, phy->phy); + phy->phy_state = PHY_DEVICE_DISCOVERED; + return 0; + } + } + + return -ENODEV; +} + static struct domain_device *sas_ex_discover_expander( struct domain_device *parent, int phy_id) { @@ -809,6 +833,13 @@ static int sas_ex_discover_dev(struct do return res; } + res = sas_ex_join_wide_port(dev, phy_id); + if (!res) { + SAS_DPRINTK("Attaching ex phy%d to wide port %016llx\n", + phy_id, SAS_ADDR(ex_phy->attached_sas_addr)); + return res; + } + switch (ex_phy->attached_dev_type) { case SAS_END_DEV: child = sas_ex_discover_end_dev(dev, phy_id); @@ -1431,14 +1462,23 @@ int sas_discover_root_expander(struct do int res; struct sas_expander_device *ex = rphy_to_expander_device(dev->rphy); - sas_rphy_add(dev->rphy); + res = sas_rphy_add(dev->rphy); + if (res) + goto out_err; ex->level = dev->port->disc.max_level; /* 0 */ res = sas_discover_expander(dev); - if (!res) - sas_ex_bfs_disc(dev->port); + if (res) + goto out_err2; + + sas_ex_bfs_disc(dev->port); return res; + +out_err2: + sas_rphy_remove(dev->rphy); +out_err: + return res; } /* ---------- Domain revalidation ---------- */ diff --git a/drivers/scsi/libsas/sas_init.c b/drivers/scsi/libsas/sas_init.c index 2f0c07f..965698c 100644 --- a/drivers/scsi/libsas/sas_init.c +++ b/drivers/scsi/libsas/sas_init.c @@ -87,6 +87,9 @@ int sas_register_ha(struct sas_ha_struct else if (sas_ha->lldd_queue_size == -1) sas_ha->lldd_queue_size = 128; /* Sanity */ + sas_ha->state = SAS_HA_REGISTERED; + spin_lock_init(&sas_ha->state_lock); + error = sas_register_phys(sas_ha); if (error) { printk(KERN_NOTICE "couldn't register sas phys:%d\n", error); @@ -127,12 +130,22 @@ Undo_phys: int sas_unregister_ha(struct sas_ha_struct *sas_ha) { + unsigned long flags; + + /* Set the state to unregistered to avoid further + * events to be queued */ + spin_lock_irqsave(&sas_ha->state_lock, flags); + sas_ha->state = SAS_HA_UNREGISTERED; + spin_unlock_irqrestore(&sas_ha->state_lock, flags); + scsi_flush_work(sas_ha->core.shost); + + sas_unregister_ports(sas_ha); + if (sas_ha->lldd_max_execute_num > 1) { sas_shutdown_queue(sas_ha); + sas_ha->lldd_max_execute_num = 1; } - sas_unregister_ports(sas_ha); - return 0; } @@ -146,6 +159,36 @@ static int sas_get_linkerrors(struct sas return sas_smp_get_phy_events(phy); } +int sas_phy_enable(struct sas_phy *phy, int enable) +{ + int ret; + enum phy_func command; + + if (enable) + command = PHY_FUNC_LINK_RESET; + else + command = PHY_FUNC_DISABLE; + + if (scsi_is_sas_phy_local(phy)) { + struct Scsi_Host *shost = dev_to_shost(phy->dev.parent); + struct sas_ha_struct *sas_ha = SHOST_TO_SAS_HA(shost); + struct asd_sas_phy *asd_phy = sas_ha->sas_phy[phy->number]; + struct sas_internal *i = + to_sas_internal(sas_ha->core.shost->transportt); + + if (!enable) { + sas_phy_disconnected(asd_phy); + sas_ha->notify_phy_event(asd_phy, PHYE_LOSS_OF_SIGNAL); + } + ret = i->dft->lldd_control_phy(asd_phy, command, NULL); + } else { + struct sas_rphy *rphy = dev_to_rphy(phy->dev.parent); + struct domain_device *ddev = sas_find_dev_by_rphy(rphy); + ret = sas_smp_phy_control(ddev, phy->number, command, NULL); + } + return ret; +} + int sas_phy_reset(struct sas_phy *phy, int hard_reset) { int ret; @@ -172,8 +215,8 @@ int sas_phy_reset(struct sas_phy *phy, i return ret; } -static int sas_set_phy_speed(struct sas_phy *phy, - struct sas_phy_linkrates *rates) +int sas_set_phy_speed(struct sas_phy *phy, + struct sas_phy_linkrates *rates) { int ret; @@ -212,6 +255,7 @@ static int sas_set_phy_speed(struct sas_ } static struct sas_function_template sft = { + .phy_enable = sas_phy_enable, .phy_reset = sas_phy_reset, .set_phy_speed = sas_set_phy_speed, .get_linkerrors = sas_get_linkerrors, diff --git a/drivers/scsi/libsas/sas_internal.h b/drivers/scsi/libsas/sas_internal.h index 137d7e4..a78638d 100644 --- a/drivers/scsi/libsas/sas_internal.h +++ b/drivers/scsi/libsas/sas_internal.h @@ -80,7 +80,7 @@ void sas_hae_reset(struct work_struct *w static inline void sas_queue_event(int event, spinlock_t *lock, unsigned long *pending, struct work_struct *work, - struct Scsi_Host *shost) + struct sas_ha_struct *sas_ha) { unsigned long flags; @@ -91,7 +91,12 @@ static inline void sas_queue_event(int e } __set_bit(event, pending); spin_unlock_irqrestore(lock, flags); - scsi_queue_work(shost, work); + + spin_lock_irqsave(&sas_ha->state_lock, flags); + if (sas_ha->state != SAS_HA_UNREGISTERED) { + scsi_queue_work(sas_ha->core.shost, work); + } + spin_unlock_irqrestore(&sas_ha->state_lock, flags); } static inline void sas_begin_event(int event, spinlock_t *lock, diff --git a/drivers/scsi/libsas/sas_port.c b/drivers/scsi/libsas/sas_port.c index 971c37c..e1e2d08 100644 --- a/drivers/scsi/libsas/sas_port.c +++ b/drivers/scsi/libsas/sas_port.c @@ -42,10 +42,11 @@ static void sas_form_port(struct asd_sas struct asd_sas_port *port = phy->port; struct sas_internal *si = to_sas_internal(sas_ha->core.shost->transportt); + unsigned long flags; if (port) { if (memcmp(port->attached_sas_addr, phy->attached_sas_addr, - SAS_ADDR_SIZE) == 0) + SAS_ADDR_SIZE) != 0) sas_deform_port(phy); else { SAS_DPRINTK("%s: phy%d belongs to port%d already(%d)!\n", @@ -56,7 +57,7 @@ static void sas_form_port(struct asd_sas } /* find a port */ - spin_lock(&sas_ha->phy_port_lock); + spin_lock_irqsave(&sas_ha->phy_port_lock, flags); for (i = 0; i < sas_ha->num_phys; i++) { port = sas_ha->sas_port[i]; spin_lock(&port->phy_list_lock); @@ -78,7 +79,7 @@ static void sas_form_port(struct asd_sas if (i >= sas_ha->num_phys) { printk(KERN_NOTICE "%s: couldn't find a free port, bug?\n", __FUNCTION__); - spin_unlock(&sas_ha->phy_port_lock); + spin_unlock_irqrestore(&sas_ha->phy_port_lock, flags); return; } @@ -105,7 +106,7 @@ static void sas_form_port(struct asd_sas } else port->linkrate = max(port->linkrate, phy->linkrate); spin_unlock(&port->phy_list_lock); - spin_unlock(&sas_ha->phy_port_lock); + spin_unlock_irqrestore(&sas_ha->phy_port_lock, flags); if (!port->port) { port->port = sas_port_alloc(phy->phy->dev.parent, port->id); @@ -137,6 +138,7 @@ void sas_deform_port(struct asd_sas_phy struct asd_sas_port *port = phy->port; struct sas_internal *si = to_sas_internal(sas_ha->core.shost->transportt); + unsigned long flags; if (!port) return; /* done by a phy event */ @@ -155,7 +157,7 @@ void sas_deform_port(struct asd_sas_phy if (si->dft->lldd_port_deformed) si->dft->lldd_port_deformed(phy); - spin_lock(&sas_ha->phy_port_lock); + spin_lock_irqsave(&sas_ha->phy_port_lock, flags); spin_lock(&port->phy_list_lock); list_del_init(&phy->port_phy_el); @@ -174,7 +176,7 @@ void sas_deform_port(struct asd_sas_phy port->phy_mask = 0; } spin_unlock(&port->phy_list_lock); - spin_unlock(&sas_ha->phy_port_lock); + spin_unlock_irqrestore(&sas_ha->phy_port_lock, flags); return; } diff --git a/drivers/scsi/libsas/sas_scsi_host.c b/drivers/scsi/libsas/sas_scsi_host.c index 22672d5..897a5e2 100644 --- a/drivers/scsi/libsas/sas_scsi_host.c +++ b/drivers/scsi/libsas/sas_scsi_host.c @@ -34,6 +34,7 @@ #include #include #include "../scsi_sas_internal.h" #include "../scsi_transport_api.h" +#include "../scsi_priv.h" #include #include @@ -130,7 +131,7 @@ static enum task_attribute sas_scsi_get_ if (cmd->request && blk_rq_tagged(cmd->request)) { if (cmd->device->ordered_tags && (cmd->request->cmd_flags & REQ_HARDBARRIER)) - ta = TASK_ATTR_HOQ; + ta = TASK_ATTR_ORDERED; } return ta; } @@ -281,6 +282,7 @@ enum task_disposition { TASK_IS_ABORTED, TASK_IS_AT_LU, TASK_IS_NOT_AT_LU, + TASK_ABORT_FAILED, }; static enum task_disposition sas_scsi_find_task(struct sas_task *task) @@ -310,15 +312,6 @@ static enum task_disposition sas_scsi_fi spin_unlock_irqrestore(&core->task_queue_lock, flags); } - spin_lock_irqsave(&task->task_state_lock, flags); - if (task->task_state_flags & SAS_TASK_INITIATOR_ABORTED) { - spin_unlock_irqrestore(&task->task_state_lock, flags); - SAS_DPRINTK("%s: task 0x%p already aborted\n", - __FUNCTION__, task); - return TASK_IS_ABORTED; - } - spin_unlock_irqrestore(&task->task_state_lock, flags); - for (i = 0; i < 5; i++) { SAS_DPRINTK("%s: aborting task 0x%p\n", __FUNCTION__, task); res = si->dft->lldd_abort_task(task); @@ -340,15 +333,21 @@ static enum task_disposition sas_scsi_fi SAS_DPRINTK("%s: querying task 0x%p\n", __FUNCTION__, task); res = si->dft->lldd_query_task(task); - if (res == TMF_RESP_FUNC_SUCC) { + switch (res) { + case TMF_RESP_FUNC_SUCC: SAS_DPRINTK("%s: task 0x%p at LU\n", __FUNCTION__, task); return TASK_IS_AT_LU; - } else if (res == TMF_RESP_FUNC_COMPLETE) { + case TMF_RESP_FUNC_COMPLETE: SAS_DPRINTK("%s: task 0x%p not at LU\n", __FUNCTION__, task); return TASK_IS_NOT_AT_LU; - } + case TMF_RESP_FUNC_FAILED: + SAS_DPRINTK("%s: task 0x%p failed to abort\n", + __FUNCTION__, task); + return TASK_ABORT_FAILED; + } + } } return res; @@ -398,35 +397,113 @@ static int sas_recover_I_T(struct domain return res; } -void sas_scsi_recover_host(struct Scsi_Host *shost) +/* Find the sas_phy that's attached to this device */ +struct sas_phy *find_local_sas_phy(struct domain_device *dev) +{ + struct domain_device *pdev = dev->parent; + struct ex_phy *exphy = NULL; + int i; + + /* Directly attached device */ + if (!pdev) + return dev->port->phy; + + /* Otherwise look in the expander */ + for (i = 0; i < pdev->ex_dev.num_phys; i++) + if (!memcmp(dev->sas_addr, + pdev->ex_dev.ex_phy[i].attached_sas_addr, + SAS_ADDR_SIZE)) { + exphy = &pdev->ex_dev.ex_phy[i]; + break; + } + + BUG_ON(!exphy); + return exphy->phy; +} + +/* Attempt to send a LUN reset message to a device */ +int sas_eh_device_reset_handler(struct scsi_cmnd *cmd) +{ + struct domain_device *dev = cmd_to_domain_dev(cmd); + struct sas_internal *i = + to_sas_internal(dev->port->ha->core.shost->transportt); + struct scsi_lun lun; + int res; + + int_to_scsilun(cmd->device->lun, &lun); + + if (!i->dft->lldd_lu_reset) + return FAILED; + + res = i->dft->lldd_lu_reset(dev, lun.scsi_lun); + if (res == TMF_RESP_FUNC_SUCC || res == TMF_RESP_FUNC_COMPLETE) + return SUCCESS; + + return FAILED; +} + +/* Attempt to send a phy (bus) reset */ +int sas_eh_bus_reset_handler(struct scsi_cmnd *cmd) +{ + struct domain_device *dev = cmd_to_domain_dev(cmd); + struct sas_phy *phy = find_local_sas_phy(dev); + int res; + + res = sas_phy_reset(phy, 1); + if (res) + SAS_DPRINTK("Bus reset of %s failed 0x%x\n", + phy->dev.kobj.k_name, + res); + if (res == TMF_RESP_FUNC_SUCC || res == TMF_RESP_FUNC_COMPLETE) + return SUCCESS; + + return FAILED; +} + +/* Try to reset a device */ +static int try_to_reset_cmd_device(struct Scsi_Host *shost, + struct scsi_cmnd *cmd) +{ + int res; + + if (!shost->hostt->eh_device_reset_handler) + goto try_bus_reset; + + res = shost->hostt->eh_device_reset_handler(cmd); + if (res == SUCCESS) + return res; + +try_bus_reset: + if (shost->hostt->eh_bus_reset_handler) + return shost->hostt->eh_bus_reset_handler(cmd); + + return FAILED; +} + +static int sas_eh_handle_sas_errors(struct Scsi_Host *shost, + struct list_head *work_q, + struct list_head *done_q) { - struct sas_ha_struct *ha = SHOST_TO_SAS_HA(shost); - unsigned long flags; - LIST_HEAD(error_q); struct scsi_cmnd *cmd, *n; enum task_disposition res = TASK_IS_DONE; - int tmf_resp; + int tmf_resp, need_reset; struct sas_internal *i = to_sas_internal(shost->transportt); + unsigned long flags; + struct sas_ha_struct *ha = SHOST_TO_SAS_HA(shost); - spin_lock_irqsave(shost->host_lock, flags); - list_splice_init(&shost->eh_cmd_q, &error_q); - spin_unlock_irqrestore(shost->host_lock, flags); - - SAS_DPRINTK("Enter %s\n", __FUNCTION__); - - /* All tasks on this list were marked SAS_TASK_STATE_ABORTED - * by sas_scsi_timed_out() callback. - */ Again: - SAS_DPRINTK("going over list...\n"); - list_for_each_entry_safe(cmd, n, &error_q, eh_entry) { + list_for_each_entry_safe(cmd, n, work_q, eh_entry) { struct sas_task *task = TO_SAS_TASK(cmd); - list_del_init(&cmd->eh_entry); - if (!task) { - SAS_DPRINTK("%s: taskless cmd?!\n", __FUNCTION__); + if (!task) continue; - } + + list_del_init(&cmd->eh_entry); + + spin_lock_irqsave(&task->task_state_lock, flags); + need_reset = task->task_state_flags & SAS_TASK_NEED_DEV_RESET; + spin_unlock_irqrestore(&task->task_state_lock, flags); + SAS_DPRINTK("trying to find task 0x%p\n", task); res = sas_scsi_find_task(task); @@ -437,11 +514,15 @@ Again: SAS_DPRINTK("%s: task 0x%p is done\n", __FUNCTION__, task); task->task_done(task); + if (need_reset) + try_to_reset_cmd_device(shost, cmd); continue; case TASK_IS_ABORTED: SAS_DPRINTK("%s: task 0x%p is aborted\n", __FUNCTION__, task); task->task_done(task); + if (need_reset) + try_to_reset_cmd_device(shost, cmd); continue; case TASK_IS_AT_LU: SAS_DPRINTK("task 0x%p is at LU: lu recover\n", task); @@ -452,11 +533,14 @@ Again: SAS_ADDR(task->dev), cmd->device->lun); task->task_done(task); - sas_scsi_clear_queue_lu(&error_q, cmd); + if (need_reset) + try_to_reset_cmd_device(shost, cmd); + sas_scsi_clear_queue_lu(work_q, cmd); goto Again; } /* fallthrough */ case TASK_IS_NOT_AT_LU: + case TASK_ABORT_FAILED: SAS_DPRINTK("task 0x%p is not at LU: I_T recover\n", task); tmf_resp = sas_recover_I_T(task->dev); @@ -464,7 +548,9 @@ Again: SAS_DPRINTK("I_T %016llx recovered\n", SAS_ADDR(task->dev->sas_addr)); task->task_done(task); - sas_scsi_clear_queue_I_T(&error_q, task->dev); + if (need_reset) + try_to_reset_cmd_device(shost, cmd); + sas_scsi_clear_queue_I_T(work_q, task->dev); goto Again; } /* Hammer time :-) */ @@ -477,7 +563,9 @@ Again: SAS_DPRINTK("clear nexus port:%d " "succeeded\n", port->id); task->task_done(task); - sas_scsi_clear_queue_port(&error_q, + if (need_reset) + try_to_reset_cmd_device(shost, cmd); + sas_scsi_clear_queue_port(work_q, port); goto Again; } @@ -489,6 +577,8 @@ Again: SAS_DPRINTK("clear nexus ha " "succeeded\n"); task->task_done(task); + if (need_reset) + try_to_reset_cmd_device(shost, cmd); goto out; } } @@ -502,20 +592,54 @@ Again: cmd->device->lun); task->task_done(task); + if (need_reset) + try_to_reset_cmd_device(shost, cmd); goto clear_q; } } out: - scsi_eh_flush_done_q(&ha->eh_done_q); - SAS_DPRINTK("--- Exit %s\n", __FUNCTION__); - return; + return list_empty(work_q); clear_q: SAS_DPRINTK("--- Exit %s -- clear_q\n", __FUNCTION__); - list_for_each_entry_safe(cmd, n, &error_q, eh_entry) { + list_for_each_entry_safe(cmd, n, work_q, eh_entry) { struct sas_task *task = TO_SAS_TASK(cmd); list_del_init(&cmd->eh_entry); task->task_done(task); } + return list_empty(work_q); +} + +void sas_scsi_recover_host(struct Scsi_Host *shost) +{ + struct sas_ha_struct *ha = SHOST_TO_SAS_HA(shost); + unsigned long flags; + LIST_HEAD(eh_work_q); + + spin_lock_irqsave(shost->host_lock, flags); + list_splice_init(&shost->eh_cmd_q, &eh_work_q); + spin_unlock_irqrestore(shost->host_lock, flags); + + SAS_DPRINTK("Enter %s\n", __FUNCTION__); + /* + * Deal with commands that still have SAS tasks (i.e. they didn't + * complete via the normal sas_task completion mechanism) + */ + if (sas_eh_handle_sas_errors(shost, &eh_work_q, &ha->eh_done_q)) + goto out; + + /* + * Now deal with SCSI commands that completed ok but have a an error + * code (and hopefully sense data) attached. This is roughly what + * scsi_unjam_host does, but we skip scsi_eh_abort_cmds because any + * command we see here has no sas_task and is thus unknown to the HA. + */ + if (!scsi_eh_get_sense(&eh_work_q, &ha->eh_done_q)) + scsi_eh_ready_devs(shost, &eh_work_q, &ha->eh_done_q); + +out: + scsi_eh_flush_done_q(&ha->eh_done_q); + SAS_DPRINTK("--- Exit %s\n", __FUNCTION__); + return; } enum scsi_eh_timer_return sas_scsi_timed_out(struct scsi_cmnd *cmd) @@ -524,24 +648,30 @@ enum scsi_eh_timer_return sas_scsi_timed unsigned long flags; if (!task) { - SAS_DPRINTK("command 0x%p, task 0x%p, gone: EH_HANDLED\n", - cmd, task); - return EH_HANDLED; + cmd->timeout_per_command /= 2; + SAS_DPRINTK("command 0x%p, task 0x%p, gone: %s\n", + cmd, task, (cmd->timeout_per_command ? + "EH_RESET_TIMER" : "EH_NOT_HANDLED")); + if (!cmd->timeout_per_command) + return EH_NOT_HANDLED; + return EH_RESET_TIMER; } spin_lock_irqsave(&task->task_state_lock, flags); - if (task->task_state_flags & SAS_TASK_INITIATOR_ABORTED) { - spin_unlock_irqrestore(&task->task_state_lock, flags); - SAS_DPRINTK("command 0x%p, task 0x%p, aborted by initiator: " - "EH_NOT_HANDLED\n", cmd, task); - return EH_NOT_HANDLED; - } + BUG_ON(task->task_state_flags & SAS_TASK_STATE_ABORTED); if (task->task_state_flags & SAS_TASK_STATE_DONE) { spin_unlock_irqrestore(&task->task_state_lock, flags); SAS_DPRINTK("command 0x%p, task 0x%p, timed out: EH_HANDLED\n", cmd, task); return EH_HANDLED; } + if (!(task->task_state_flags & SAS_TASK_AT_INITIATOR)) { + spin_unlock_irqrestore(&task->task_state_lock, flags); + SAS_DPRINTK("command 0x%p, task 0x%p, not at initiator: " + "EH_RESET_TIMER\n", + cmd, task); + return EH_RESET_TIMER; + } task->task_state_flags |= SAS_TASK_STATE_ABORTED; spin_unlock_irqrestore(&task->task_state_lock, flags); @@ -557,8 +687,9 @@ struct domain_device *sas_find_dev_by_rp struct sas_ha_struct *ha = SHOST_TO_SAS_HA(shost); struct domain_device *found_dev = NULL; int i; + unsigned long flags; - spin_lock(&ha->phy_port_lock); + spin_lock_irqsave(&ha->phy_port_lock, flags); for (i = 0; i < ha->num_phys; i++) { struct asd_sas_port *port = ha->sas_port[i]; struct domain_device *dev; @@ -574,7 +705,7 @@ struct domain_device *sas_find_dev_by_rp spin_unlock(&port->dev_list_lock); } found: - spin_unlock(&ha->phy_port_lock); + spin_unlock_irqrestore(&ha->phy_port_lock, flags); return found_dev; } @@ -623,6 +754,8 @@ int sas_slave_configure(struct scsi_devi scsi_deactivate_tcq(scsi_dev, 1); } + scsi_dev->allow_restart = 1; + return 0; } @@ -799,46 +932,42 @@ void sas_shutdown_queue(struct sas_ha_st spin_unlock_irqrestore(&core->task_queue_lock, flags); } -static int do_sas_task_abort(struct sas_task *task) +/* + * Call the LLDD task abort routine directly. This function is intended for + * use by upper layers that need to tell the LLDD to abort a task. + */ +int __sas_task_abort(struct sas_task *task) { - struct scsi_cmnd *sc = task->uldd_task; struct sas_internal *si = to_sas_internal(task->dev->port->ha->core.shost->transportt); unsigned long flags; int res; spin_lock_irqsave(&task->task_state_lock, flags); - if (task->task_state_flags & SAS_TASK_STATE_ABORTED) { + if (task->task_state_flags & SAS_TASK_STATE_ABORTED || + task->task_state_flags & SAS_TASK_STATE_DONE) { spin_unlock_irqrestore(&task->task_state_lock, flags); - SAS_DPRINTK("%s: Task %p already aborted.\n", __FUNCTION__, + SAS_DPRINTK("%s: Task %p already finished.\n", __FUNCTION__, task); return 0; } - - task->task_state_flags |= SAS_TASK_INITIATOR_ABORTED; - if (!(task->task_state_flags & SAS_TASK_STATE_DONE)) - task->task_state_flags |= SAS_TASK_STATE_ABORTED; + task->task_state_flags |= SAS_TASK_STATE_ABORTED; spin_unlock_irqrestore(&task->task_state_lock, flags); if (!si->dft->lldd_abort_task) return -ENODEV; res = si->dft->lldd_abort_task(task); + + spin_lock_irqsave(&task->task_state_lock, flags); if ((task->task_state_flags & SAS_TASK_STATE_DONE) || (res == TMF_RESP_FUNC_COMPLETE)) { - /* SMP commands don't have scsi_cmds(?) */ - if (!sc) { - task->task_done(task); - return 0; - } - scsi_req_abort_cmd(sc); - scsi_schedule_eh(sc->device->host); + spin_unlock_irqrestore(&task->task_state_lock, flags); + task->task_done(task); return 0; } - spin_lock_irqsave(&task->task_state_lock, flags); - task->task_state_flags &= ~SAS_TASK_INITIATOR_ABORTED; if (!(task->task_state_flags & SAS_TASK_STATE_DONE)) task->task_state_flags &= ~SAS_TASK_STATE_ABORTED; spin_unlock_irqrestore(&task->task_state_lock, flags); @@ -846,17 +975,24 @@ static int do_sas_task_abort(struct sas_ return -EAGAIN; } -void sas_task_abort(struct work_struct *work) +/* + * Tell an upper layer that it needs to initiate an abort for a given task. + * This should only ever be called by an LLDD. + */ +void sas_task_abort(struct sas_task *task) { - struct sas_task *task = - container_of(work, struct sas_task, abort_work); - int i; + struct scsi_cmnd *sc = task->uldd_task; - for (i = 0; i < 5; i++) - if (!do_sas_task_abort(task)) + /* Escape for libsas internal commands */ + if (!sc) { + if (!del_timer(&task->timer)) return; + task->timer.function(task->timer.data); + return; + } - SAS_DPRINTK("%s: Could not kill task!\n", __FUNCTION__); + scsi_req_abort_cmd(sc); + scsi_schedule_eh(sc->device->host); } EXPORT_SYMBOL_GPL(sas_queuecommand); @@ -866,5 +1002,9 @@ EXPORT_SYMBOL_GPL(sas_slave_destroy); EXPORT_SYMBOL_GPL(sas_change_queue_depth); EXPORT_SYMBOL_GPL(sas_change_queue_type); EXPORT_SYMBOL_GPL(sas_bios_param); +EXPORT_SYMBOL_GPL(__sas_task_abort); EXPORT_SYMBOL_GPL(sas_task_abort); EXPORT_SYMBOL_GPL(sas_phy_reset); +EXPORT_SYMBOL_GPL(sas_phy_enable); +EXPORT_SYMBOL_GPL(sas_eh_device_reset_handler); +EXPORT_SYMBOL_GPL(sas_eh_bus_reset_handler); diff --git a/drivers/scsi/mac_esp.c b/drivers/scsi/mac_esp.c index 3586fac..bcb4902 100644 --- a/drivers/scsi/mac_esp.c +++ b/drivers/scsi/mac_esp.c @@ -351,7 +351,7 @@ #endif for (chipnum = 0; chipnum < chipspresent; chipnum ++) { struct NCR_ESP * esp; - esp = esp_allocate(tpnt, (void *) NULL); + esp = esp_allocate(tpnt, NULL, 0); esp->eregs = (struct ESP_regs *) get_base(chipnum); esp->dma_irq_p = &esp_dafb_dma_irq_p; diff --git a/drivers/scsi/mac_scsi.c b/drivers/scsi/mac_scsi.c index a942a21..cdbcaa5 100644 --- a/drivers/scsi/mac_scsi.c +++ b/drivers/scsi/mac_scsi.c @@ -36,7 +36,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/scsi/mca_53c9x.c b/drivers/scsi/mca_53c9x.c index 998a8bb..d693d0f 100644 --- a/drivers/scsi/mca_53c9x.c +++ b/drivers/scsi/mca_53c9x.c @@ -122,7 +122,7 @@ static int mca_esp_detect(struct scsi_ho if ((slot = mca_find_adapter(*id_to_check, 0)) != MCA_NOTFOUND) { - esp = esp_allocate(tpnt, (void *) NULL); + esp = esp_allocate(tpnt, NULL, 0); pos[0] = mca_read_stored_pos(slot, 2); pos[1] = mca_read_stored_pos(slot, 3); diff --git a/drivers/scsi/megaraid.c b/drivers/scsi/megaraid.c index 77d9d38..808a1b8 100644 --- a/drivers/scsi/megaraid.c +++ b/drivers/scsi/megaraid.c @@ -92,7 +92,7 @@ static struct mega_hbas mega_hbas[MAX_CO /* * The File Operations structure for the serial/ioctl interface of the driver */ -static struct file_operations megadev_fops = { +static const struct file_operations megadev_fops = { .owner = THIS_MODULE, .ioctl = megadev_ioctl, .open = megadev_open, diff --git a/drivers/scsi/megaraid/mbox_defs.h b/drivers/scsi/megaraid/mbox_defs.h index 3052869..170399e 100644 --- a/drivers/scsi/megaraid/mbox_defs.h +++ b/drivers/scsi/megaraid/mbox_defs.h @@ -748,7 +748,7 @@ typedef struct { /** - * private_bios_data - bios private data for boot devices + * struct private_bios_data - bios private data for boot devices * @geometry : bits 0-3 - BIOS geometry, 0x0001 - 1GB, 0x0010 - 2GB, * 0x1000 - 8GB, Others values are invalid * @unused : bits 4-7 are unused diff --git a/drivers/scsi/megaraid/mega_common.h b/drivers/scsi/megaraid/mega_common.h index b50e27e..26e1e6c 100644 --- a/drivers/scsi/megaraid/mega_common.h +++ b/drivers/scsi/megaraid/mega_common.h @@ -46,17 +46,17 @@ #define MEGA_INVALID_FIELD_IN_CDB 0x24 /** * scb_t - scsi command control block - * @param ccb : command control block for individual driver - * @param list : list of control blocks - * @param gp : general purpose field for LLDs - * @param sno : all SCBs have a serial number - * @param scp : associated scsi command - * @param state : current state of scb - * @param dma_dir : direction of data transfer - * @param dma_type : transfer with sg list, buffer, or no data transfer - * @param dev_channel : actual channel on the device - * @param dev_target : actual target on the device - * @param status : completion status + * @ccb : command control block for individual driver + * @list : list of control blocks + * @gp : general purpose field for LLDs + * @sno : all SCBs have a serial number + * @scp : associated scsi command + * @state : current state of scb + * @dma_dir : direction of data transfer + * @dma_type : transfer with sg list, buffer, or no data transfer + * @dev_channel : actual channel on the device + * @dev_target : actual target on the device + * @status : completion status * * This is our central data structure to issue commands the each driver. * Driver specific data structures are maintained in the ccb field. @@ -99,42 +99,42 @@ #define MRAID_DMA_WBUF 0x0002 /* data tr /** * struct adapter_t - driver's initialization structure - * @param dpc_h : tasklet handle - * @param pdev : pci configuration pointer for kernel - * @param host : pointer to host structure of mid-layer - * @param lock : synchronization lock for mid-layer and driver - * @param quiescent : driver is quiescent for now. - * @param outstanding_cmds : number of commands pending in the driver - * @param kscb_list : pointer to the bulk of SCBs pointers for IO - * @param kscb_pool : pool of free scbs for IO - * @param kscb_pool_lock : lock for pool of free scbs - * @param pend_list : pending commands list - * @param pend_list_lock : exlusion lock for pending commands list - * @param completed_list : list of completed commands - * @param completed_list_lock : exclusion lock for list of completed commands - * @param sglen : max sg elements supported - * @param device_ids : to convert kernel device addr to our devices. - * @param raid_device : raid adapter specific pointer - * @param max_channel : maximum channel number supported - inclusive - * @param max_target : max target supported - inclusive - * @param max_lun : max lun supported - inclusive - * @param unique_id : unique identifier for each adapter - * @param irq : IRQ for this adapter - * @param ito : internal timeout value, (-1) means no timeout - * @param ibuf : buffer to issue internal commands - * @param ibuf_dma_h : dma handle for the above buffer - * @param uscb_list : SCB pointers for user cmds, common mgmt module - * @param uscb_pool : pool of SCBs for user commands - * @param uscb_pool_lock : exclusion lock for these SCBs - * @param max_cmds : max outstanding commands - * @param fw_version : firmware version - * @param bios_version : bios version - * @param max_cdb_sz : biggest CDB size supported. - * @param ha : is high availability present - clustering - * @param init_id : initiator ID, the default value should be 7 - * @param max_sectors : max sectors per request - * @param cmd_per_lun : max outstanding commands per LUN - * @param being_detached : set when unloading, no more mgmt calls + * @aram dpc_h : tasklet handle + * @pdev : pci configuration pointer for kernel + * @host : pointer to host structure of mid-layer + * @lock : synchronization lock for mid-layer and driver + * @quiescent : driver is quiescent for now. + * @outstanding_cmds : number of commands pending in the driver + * @kscb_list : pointer to the bulk of SCBs pointers for IO + * @kscb_pool : pool of free scbs for IO + * @kscb_pool_lock : lock for pool of free scbs + * @pend_list : pending commands list + * @pend_list_lock : exclusion lock for pending commands list + * @completed_list : list of completed commands + * @completed_list_lock : exclusion lock for list of completed commands + * @sglen : max sg elements supported + * @device_ids : to convert kernel device addr to our devices. + * @raid_device : raid adapter specific pointer + * @max_channel : maximum channel number supported - inclusive + * @max_target : max target supported - inclusive + * @max_lun : max lun supported - inclusive + * @unique_id : unique identifier for each adapter + * @irq : IRQ for this adapter + * @ito : internal timeout value, (-1) means no timeout + * @ibuf : buffer to issue internal commands + * @ibuf_dma_h : dma handle for the above buffer + * @uscb_list : SCB pointers for user cmds, common mgmt module + * @uscb_pool : pool of SCBs for user commands + * @uscb_pool_lock : exclusion lock for these SCBs + * @max_cmds : max outstanding commands + * @fw_version : firmware version + * @bios_version : bios version + * @max_cdb_sz : biggest CDB size supported. + * @ha : is high availability present - clustering + * @init_id : initiator ID, the default value should be 7 + * @max_sectors : max sectors per request + * @cmd_per_lun : max outstanding commands per LUN + * @being_detached : set when unloading, no more mgmt calls * * * mraid_setup_device_map() can be called anytime after the device map is @@ -211,23 +211,23 @@ #define SCSIHOST2ADAP(host) (((caddr_t * #define SCP2ADAPTER(scp) (adapter_t *)SCSIHOST2ADAP(SCP2HOST(scp)) -/** - * MRAID_GET_DEVICE_MAP - device ids - * @param adp - Adapter's soft state - * @param scp - mid-layer scsi command pointer - * @param p_chan - physical channel on the controller - * @param target - target id of the device or logical drive number - * @param islogical - set if the command is for the logical drive - * - * Macro to retrieve information about device class, logical or physical and - * the corresponding physical channel and target or logical drive number - **/ #define MRAID_IS_LOGICAL(adp, scp) \ (SCP2CHANNEL(scp) == (adp)->max_channel) ? 1 : 0 #define MRAID_IS_LOGICAL_SDEV(adp, sdev) \ (sdev->channel == (adp)->max_channel) ? 1 : 0 +/** + * MRAID_GET_DEVICE_MAP - device ids + * @adp : adapter's soft state + * @scp : mid-layer scsi command pointer + * @p_chan : physical channel on the controller + * @target : target id of the device or logical drive number + * @islogical : set if the command is for the logical drive + * + * Macro to retrieve information about device class, logical or physical and + * the corresponding physical channel and target or logical drive number + */ #define MRAID_GET_DEVICE_MAP(adp, scp, p_chan, target, islogical) \ /* \ * Is the request coming for the virtual channel \ @@ -271,10 +271,10 @@ #else #define ASSERT(expression) #endif -/* +/** * struct mraid_pci_blk - structure holds DMA memory block info - * @param vaddr : virtual address to a memory block - * @param dma_addr : DMA handle to a memory block + * @vaddr : virtual address to a memory block + * @dma_addr : DMA handle to a memory block * * This structure is filled up for the caller. It is the responsibilty of the * caller to allocate this array big enough to store addresses for all diff --git a/drivers/scsi/megaraid/megaraid_ioctl.h b/drivers/scsi/megaraid/megaraid_ioctl.h index b8aa342..706fa05 100644 --- a/drivers/scsi/megaraid/megaraid_ioctl.h +++ b/drivers/scsi/megaraid/megaraid_ioctl.h @@ -22,23 +22,23 @@ #include #include "mbox_defs.h" +/* + * console messages debug levels + */ +#define CL_ANN 0 /* print unconditionally, announcements */ +#define CL_DLEVEL1 1 /* debug level 1, informative */ +#define CL_DLEVEL2 2 /* debug level 2, verbose */ +#define CL_DLEVEL3 3 /* debug level 3, very verbose */ + /** * con_log() - console log routine - * @param level : indicates the severity of the message. - * @fparam mt : format string + * @level : indicates the severity of the message. + * @fmt : format string * * con_log displays the error messages on the console based on the current * debug level. Also it attaches the appropriate kernel severity level with * the message. - * - * - * consolge messages debug levels */ -#define CL_ANN 0 /* print unconditionally, announcements */ -#define CL_DLEVEL1 1 /* debug level 1, informative */ -#define CL_DLEVEL2 2 /* debug level 2, verbose */ -#define CL_DLEVEL3 3 /* debug level 3, very verbose */ - #define con_log(level, fmt) if (LSI_DBGLVL >= level) printk fmt; /* @@ -157,14 +157,14 @@ typedef struct uioc { /** * struct mraid_hba_info - information about the controller * - * @param pci_vendor_id : PCI vendor id - * @param pci_device_id : PCI device id - * @param subsystem_vendor_id : PCI subsystem vendor id - * @param subsystem_device_id : PCI subsystem device id - * @param baseport : base port of hba memory - * @param pci_bus : PCI bus - * @param pci_dev_fn : PCI device/function values - * @param irq : interrupt vector for the device + * @pci_vendor_id : PCI vendor id + * @pci_device_id : PCI device id + * @subsystem_vendor_id : PCI subsystem vendor id + * @subsystem_device_id : PCI subsystem device id + * @baseport : base port of hba memory + * @pci_bus : PCI bus + * @pci_dev_fn : PCI device/function values + * @irq : interrupt vector for the device * * Extended information of 256 bytes about the controller. Align on the single * byte boundary so that 32-bit applications can be run on 64-bit platform diff --git a/drivers/scsi/megaraid/megaraid_mbox.c b/drivers/scsi/megaraid/megaraid_mbox.c index 7bac86d..04d0b69 100644 --- a/drivers/scsi/megaraid/megaraid_mbox.c +++ b/drivers/scsi/megaraid/megaraid_mbox.c @@ -10,13 +10,13 @@ * 2 of the License, or (at your option) any later version. * * FILE : megaraid_mbox.c - * Version : v2.20.4.9 (Jul 16 2006) + * Version : v2.20.5.1 (Nov 16 2006) * * Authors: - * Atul Mukker - * Sreenivas Bagalkote - * Manoj Jose - * Seokmann Ju + * Atul Mukker + * Sreenivas Bagalkote + * Manoj Jose + * Seokmann Ju * * List of supported controllers * @@ -107,6 +107,7 @@ static int megaraid_mbox_support_random_ static int megaraid_mbox_get_max_sg(adapter_t *); static void megaraid_mbox_enum_raid_scsi(adapter_t *); static void megaraid_mbox_flush_cache(adapter_t *); +static int megaraid_mbox_fire_sync_cmd(adapter_t *); static void megaraid_mbox_display_scb(adapter_t *, scb_t *); static void megaraid_mbox_setup_device_map(adapter_t *); @@ -137,7 +138,7 @@ static int wait_till_fw_empty(adapter_t -MODULE_AUTHOR("sju@lsil.com"); +MODULE_AUTHOR("megaraidlinux@lsi.com"); MODULE_DESCRIPTION("LSI Logic MegaRAID Mailbox Driver"); MODULE_LICENSE("GPL"); MODULE_VERSION(MEGARAID_VERSION); @@ -146,7 +147,7 @@ MODULE_VERSION(MEGARAID_VERSION); * ### modules parameters for driver ### */ -/** +/* * Set to enable driver to expose unconfigured disk to kernel */ static int megaraid_expose_unconf_disks = 0; @@ -154,7 +155,7 @@ module_param_named(unconf_disks, megarai MODULE_PARM_DESC(unconf_disks, "Set to expose unconfigured disks to kernel (default=0)"); -/** +/* * driver wait time if the adapter's mailbox is busy */ static unsigned int max_mbox_busy_wait = MBOX_BUSY_WAIT; @@ -162,7 +163,7 @@ module_param_named(busy_wait, max_mbox_b MODULE_PARM_DESC(busy_wait, "Max wait for mailbox in microseconds if busy (default=10)"); -/** +/* * number of sectors per IO command */ static unsigned int megaraid_max_sectors = MBOX_MAX_SECTORS; @@ -170,7 +171,7 @@ module_param_named(max_sectors, megaraid MODULE_PARM_DESC(max_sectors, "Maximum number of sectors per IO command (default=128)"); -/** +/* * number of commands per logical unit */ static unsigned int megaraid_cmd_per_lun = MBOX_DEF_CMD_PER_LUN; @@ -179,7 +180,7 @@ MODULE_PARM_DESC(cmd_per_lun, "Maximum number of commands per logical unit (default=64)"); -/** +/* * Fast driver load option, skip scanning for physical devices during load. * This would result in non-disk devices being skipped during driver load * time. These can be later added though, using /proc/scsi/scsi @@ -190,7 +191,7 @@ MODULE_PARM_DESC(fast_load, "Faster loading of the driver, skips physical devices! (default=0)"); -/** +/* * mraid_debug level - threshold for amount of information to be displayed by * the driver. This level can be changed through modules parameters, ioctl or * sysfs/proc interface. By default, print the announcement messages only. @@ -337,7 +338,7 @@ static struct device_attribute *megaraid * * Return value: * actual depth set - **/ + */ static int megaraid_change_queue_depth(struct scsi_device *sdev, int qdepth) { if (qdepth > MBOX_MAX_SCSI_CMDS) @@ -369,8 +370,8 @@ static struct scsi_host_template megarai * megaraid_init - module load hook * * We register ourselves as hotplug enabled module and let PCI subsystem - * discover our adaters - **/ + * discover our adapters. + */ static int __init megaraid_init(void) { @@ -405,7 +406,7 @@ megaraid_init(void) /** * megaraid_exit - driver unload entry point * - * We simply unwrap the megaraid_init routine here + * We simply unwrap the megaraid_init routine here. */ static void __exit megaraid_exit(void) @@ -421,12 +422,12 @@ megaraid_exit(void) /** * megaraid_probe_one - PCI hotplug entry point - * @param pdev : handle to this controller's PCI configuration space - * @param id : pci device id of the class of controllers + * @pdev : handle to this controller's PCI configuration space + * @id : pci device id of the class of controllers * * This routine should be called whenever a new adapter is detected by the * PCI hotplug susbsytem. - **/ + */ static int __devinit megaraid_probe_one(struct pci_dev *pdev, const struct pci_device_id *id) { @@ -542,16 +543,15 @@ out_probe_one: /** - * megaraid_detach_one - release the framework resources and call LLD release - * routine - * @param pdev : handle for our PCI cofiguration space + * megaraid_detach_one - release framework resources and call LLD release routine + * @pdev : handle for our PCI cofiguration space * * This routine is called during driver unload. We free all the allocated * resources and call the corresponding LLD so that it can also release all * its resources. * - * This routine is also called from the PCI hotplug system - **/ + * This routine is also called from the PCI hotplug system. + */ static void megaraid_detach_one(struct pci_dev *pdev) { @@ -615,9 +615,9 @@ megaraid_detach_one(struct pci_dev *pdev /** * megaraid_mbox_shutdown - PCI shutdown for megaraid HBA - * @param device : generice driver model device + * @pdev : generic driver model device * - * Shutdown notification, perform flush cache + * Shutdown notification, perform flush cache. */ static void megaraid_mbox_shutdown(struct pci_dev *pdev) @@ -643,10 +643,10 @@ megaraid_mbox_shutdown(struct pci_dev *p /** * megaraid_io_attach - attach a device with the IO subsystem - * @param adapter : controller's soft state + * @adapter : controller's soft state * - * Attach this device with the IO subsystem - **/ + * Attach this device with the IO subsystem. + */ static int megaraid_io_attach(adapter_t *adapter) { @@ -695,10 +695,10 @@ megaraid_io_attach(adapter_t *adapter) /** * megaraid_io_detach - detach a device from the IO subsystem - * @param adapter : controller's soft state + * @adapter : controller's soft state * - * Detach this device from the IO subsystem - **/ + * Detach this device from the IO subsystem. + */ static void megaraid_io_detach(adapter_t *adapter) { @@ -722,13 +722,13 @@ megaraid_io_detach(adapter_t *adapter) /** * megaraid_init_mbox - initialize controller - * @param adapter - our soft state + * @adapter : our soft state * - * . Allocate 16-byte aligned mailbox memory for firmware handshake - * . Allocate controller's memory resources - * . Find out all initialization data - * . Allocate memory required for all the commands - * . Use internal library of FW routines, build up complete soft state + * - Allocate 16-byte aligned mailbox memory for firmware handshake + * - Allocate controller's memory resources + * - Find out all initialization data + * - Allocate memory required for all the commands + * - Use internal library of FW routines, build up complete soft state */ static int __devinit megaraid_init_mbox(adapter_t *adapter) @@ -779,33 +779,39 @@ megaraid_init_mbox(adapter_t *adapter) goto out_release_regions; } - // - // Setup the rest of the soft state using the library of FW routines - // + /* initialize the mutual exclusion lock for the mailbox */ + spin_lock_init(&raid_dev->mailbox_lock); - // request IRQ and register the interrupt service routine + /* allocate memory required for commands */ + if (megaraid_alloc_cmd_packets(adapter) != 0) + goto out_iounmap; + + /* + * Issue SYNC cmd to flush the pending cmds in the adapter + * and initialize its internal state + */ + + if (megaraid_mbox_fire_sync_cmd(adapter)) + con_log(CL_ANN, ("megaraid: sync cmd failed\n")); + + /* + * Setup the rest of the soft state using the library of + * FW routines + */ + + /* request IRQ and register the interrupt service routine */ if (request_irq(adapter->irq, megaraid_isr, IRQF_SHARED, "megaraid", adapter)) { con_log(CL_ANN, (KERN_WARNING "megaraid: Couldn't register IRQ %d!\n", adapter->irq)); + goto out_alloc_cmds; - goto out_iounmap; - } - - - // initialize the mutual exclusion lock for the mailbox - spin_lock_init(&raid_dev->mailbox_lock); - - // allocate memory required for commands - if (megaraid_alloc_cmd_packets(adapter) != 0) { - goto out_free_irq; } // Product info - if (megaraid_mbox_product_info(adapter) != 0) { - goto out_alloc_cmds; - } + if (megaraid_mbox_product_info(adapter) != 0) + goto out_free_irq; // Do we support extended CDBs adapter->max_cdb_sz = 10; @@ -874,9 +880,8 @@ megaraid_init_mbox(adapter_t *adapter) * Allocate resources required to issue FW calls, when sysfs is * accessed */ - if (megaraid_sysfs_alloc_resources(adapter) != 0) { - goto out_alloc_cmds; - } + if (megaraid_sysfs_alloc_resources(adapter) != 0) + goto out_free_irq; // Set the DMA mask to 64-bit. All supported controllers as capable of // DMA in this range @@ -920,10 +925,10 @@ megaraid_init_mbox(adapter_t *adapter) out_free_sysfs_res: megaraid_sysfs_free_resources(adapter); -out_alloc_cmds: - megaraid_free_cmd_packets(adapter); out_free_irq: free_irq(adapter->irq, adapter); +out_alloc_cmds: + megaraid_free_cmd_packets(adapter); out_iounmap: iounmap(raid_dev->baseaddr); out_release_regions: @@ -937,7 +942,7 @@ out_free_raid_dev: /** * megaraid_fini_mbox - undo controller initialization - * @param adapter : our soft state + * @adapter : our soft state */ static void megaraid_fini_mbox(adapter_t *adapter) @@ -967,12 +972,12 @@ megaraid_fini_mbox(adapter_t *adapter) /** * megaraid_alloc_cmd_packets - allocate shared mailbox - * @param adapter : soft state of the raid controller + * @adapter : soft state of the raid controller * * Allocate and align the shared mailbox. This maibox is used to issue * all the commands. For IO based controllers, the mailbox is also regsitered * with the FW. Allocate memory for all commands as well. - * This is our big allocator + * This is our big allocator. */ static int megaraid_alloc_cmd_packets(adapter_t *adapter) @@ -1132,9 +1137,9 @@ out_free_common_mbox: /** * megaraid_free_cmd_packets - free memory - * @param adapter : soft state of the raid controller + * @adapter : soft state of the raid controller * - * Release memory resources allocated for commands + * Release memory resources allocated for commands. */ static void megaraid_free_cmd_packets(adapter_t *adapter) @@ -1156,10 +1161,10 @@ megaraid_free_cmd_packets(adapter_t *ada /** * megaraid_mbox_setup_dma_pools - setup dma pool for command packets - * @param adapter : HBA soft state + * @adapter : HBA soft state * - * setup the dma pools for mailbox, passthru and extended passthru structures, - * and scatter-gather lists + * Setup the dma pools for mailbox, passthru and extended passthru structures, + * and scatter-gather lists. */ static int megaraid_mbox_setup_dma_pools(adapter_t *adapter) @@ -1252,10 +1257,10 @@ fail_setup_dma_pool: /** * megaraid_mbox_teardown_dma_pools - teardown dma pools for command packets - * @param adapter : HBA soft state + * @adapter : HBA soft state * - * teardown the dma pool for mailbox, passthru and extended passthru - * structures, and scatter-gather lists + * Teardown the dma pool for mailbox, passthru and extended passthru + * structures, and scatter-gather lists. */ static void megaraid_mbox_teardown_dma_pools(adapter_t *adapter) @@ -1300,10 +1305,11 @@ megaraid_mbox_teardown_dma_pools(adapter /** * megaraid_alloc_scb - detach and return a scb from the free list * @adapter : controller's soft state + * @scp : pointer to the scsi command to be executed * - * return the scb from the head of the free list. NULL if there are none - * available - **/ + * Return the scb from the head of the free list. %NULL if there are none + * available. + */ static scb_t * megaraid_alloc_scb(adapter_t *adapter, struct scsi_cmnd *scp) { @@ -1337,11 +1343,11 @@ megaraid_alloc_scb(adapter_t *adapter, s * @adapter : controller's soft state * @scb : scb to be freed * - * return the scb back to the free list of scbs. The caller must 'flush' the + * Return the scb back to the free list of scbs. The caller must 'flush' the * SCB before calling us. E.g., performing pci_unamp and/or pci_sync etc. * NOTE NOTE: Make sure the scb is not on any list before calling this * routine. - **/ + */ static inline void megaraid_dealloc_scb(adapter_t *adapter, scb_t *scb) { @@ -1362,10 +1368,10 @@ megaraid_dealloc_scb(adapter_t *adapter, /** * megaraid_mbox_mksgl - make the scatter-gather list - * @adapter - controller's soft state - * @scb - scsi control block + * @adapter : controller's soft state + * @scb : scsi control block * - * prepare the scatter-gather list + * Prepare the scatter-gather list. */ static int megaraid_mbox_mksgl(adapter_t *adapter, scb_t *scb) @@ -1435,10 +1441,10 @@ megaraid_mbox_mksgl(adapter_t *adapter, /** * mbox_post_cmd - issue a mailbox command - * @adapter - controller's soft state - * @scb - command to be issued + * @adapter : controller's soft state + * @scb : command to be issued * - * post the command to the controller if mailbox is availble. + * Post the command to the controller if mailbox is available. */ static int mbox_post_cmd(adapter_t *adapter, scb_t *scb) @@ -1518,7 +1524,7 @@ mbox_post_cmd(adapter_t *adapter, scb_t * Queue entry point for mailbox based controllers. */ static int -megaraid_queue_command(struct scsi_cmnd *scp, void (* done)(struct scsi_cmnd *)) +megaraid_queue_command(struct scsi_cmnd *scp, void (*done)(struct scsi_cmnd *)) { adapter_t *adapter; scb_t *scb; @@ -1548,15 +1554,15 @@ megaraid_queue_command(struct scsi_cmnd } /** - * megaraid_mbox_build_cmd - transform the mid-layer scsi command to megaraid - * firmware lingua - * @adapter - controller's soft state - * @scp - mid-layer scsi command pointer - * @busy - set if request could not be completed because of lack of + * megaraid_mbox_build_cmd - transform the mid-layer scsi commands + * @adapter : controller's soft state + * @scp : mid-layer scsi command pointer + * @busy : set if request could not be completed because of lack of * resources * - * convert the command issued by mid-layer to format understood by megaraid - * firmware. We also complete certain command without sending them to firmware + * Transform the mid-layer scsi command to megaraid firmware lingua. + * Convert the command issued by mid-layer to format understood by megaraid + * firmware. We also complete certain commands without sending them to firmware. */ static scb_t * megaraid_mbox_build_cmd(adapter_t *adapter, struct scsi_cmnd *scp, int *busy) @@ -1937,9 +1943,9 @@ megaraid_mbox_build_cmd(adapter_t *adapt /** * megaraid_mbox_runpendq - execute commands queued in the pending queue * @adapter : controller's soft state - * @scb : SCB to be queued in the pending list + * @scb_q : SCB to be queued in the pending list * - * scan the pending list for commands which are not yet issued and try to + * Scan the pending list for commands which are not yet issued and try to * post to the controller. The SCB can be a null pointer, which would indicate * no SCB to be queue, just try to execute the ones in the pending list. * @@ -2012,11 +2018,11 @@ megaraid_mbox_runpendq(adapter_t *adapte /** * megaraid_mbox_prepare_pthru - prepare a command for physical devices - * @adapter - pointer to controller's soft state - * @scb - scsi control block - * @scp - scsi command from the mid-layer + * @adapter : pointer to controller's soft state + * @scb : scsi control block + * @scp : scsi command from the mid-layer * - * prepare a command for the scsi physical devices + * Prepare a command for the scsi physical devices. */ static void megaraid_mbox_prepare_pthru(adapter_t *adapter, scb_t *scb, @@ -2060,12 +2066,12 @@ megaraid_mbox_prepare_pthru(adapter_t *a /** * megaraid_mbox_prepare_epthru - prepare a command for physical devices - * @adapter - pointer to controller's soft state - * @scb - scsi control block - * @scp - scsi command from the mid-layer + * @adapter : pointer to controller's soft state + * @scb : scsi control block + * @scp : scsi command from the mid-layer * - * prepare a command for the scsi physical devices. This rountine prepares - * commands for devices which can take extended CDBs (>10 bytes) + * Prepare a command for the scsi physical devices. This rountine prepares + * commands for devices which can take extended CDBs (>10 bytes). */ static void megaraid_mbox_prepare_epthru(adapter_t *adapter, scb_t *scb, @@ -2109,9 +2115,9 @@ megaraid_mbox_prepare_epthru(adapter_t * /** * megaraid_ack_sequence - interrupt ack sequence for memory mapped HBAs - * @adapter - controller's soft state + * @adapter : controller's soft state * - * Interrupt ackrowledgement sequence for memory mapped HBAs. Find out the + * Interrupt acknowledgement sequence for memory mapped HBAs. Find out the * completed command and put them on the completed list for later processing. * * Returns: 1 if the interrupt is valid, 0 otherwise @@ -2224,9 +2230,8 @@ megaraid_ack_sequence(adapter_t *adapter /** * megaraid_isr - isr for memory based mailbox based controllers - * @irq - irq - * @devp - pointer to our soft state - * @regs - unused + * @irq : irq + * @devp : pointer to our soft state * * Interrupt service routine for memory-mapped mailbox controllers. */ @@ -2671,7 +2676,7 @@ megaraid_abort_handler(struct scsi_cmnd * the FW is still live, in which case the outstanding commands counter mut go * down to 0. If that happens, also issue the reservation reset command to * relinquish (possible) reservations on the logical drives connected to this - * host + * host. **/ static int megaraid_reset_handler(struct scsi_cmnd *scp) @@ -2823,11 +2828,11 @@ megaraid_reset_handler(struct scsi_cmnd /** * mbox_post_sync_cmd() - blocking command to the mailbox based controllers - * @adapter - controller's soft state - * @raw_mbox - the mailbox + * @adapter : controller's soft state + * @raw_mbox : the mailbox * * Issue a scb in synchronous and non-interrupt mode for mailbox based - * controllers + * controllers. */ static int mbox_post_sync_cmd(adapter_t *adapter, uint8_t raw_mbox[]) @@ -2955,12 +2960,12 @@ blocked_mailbox: /** * mbox_post_sync_cmd_fast - blocking command to the mailbox based controllers - * @adapter - controller's soft state - * @raw_mbox - the mailbox + * @adapter : controller's soft state + * @raw_mbox : the mailbox * * Issue a scb in synchronous and non-interrupt mode for mailbox based * controllers. This is a faster version of the synchronous command and - * therefore can be called in interrupt-context as well + * therefore can be called in interrupt-context as well. */ static int mbox_post_sync_cmd_fast(adapter_t *adapter, uint8_t raw_mbox[]) @@ -3008,10 +3013,10 @@ mbox_post_sync_cmd_fast(adapter_t *adapt /** * megaraid_busywait_mbox() - Wait until the controller's mailbox is available - * @raid_dev - RAID device (HBA) soft state + * @raid_dev : RAID device (HBA) soft state * - * wait until the controller's mailbox is available to accept more commands. - * wait for at most 1 second + * Wait until the controller's mailbox is available to accept more commands. + * Wait for at most 1 second. */ static int megaraid_busywait_mbox(mraid_device_t *raid_dev) @@ -3032,9 +3037,9 @@ megaraid_busywait_mbox(mraid_device_t *r /** * megaraid_mbox_product_info - some static information about the controller - * @adapter - our soft state + * @adapter : our soft state * - * issue commands to the controller to grab some parameters required by our + * Issue commands to the controller to grab some parameters required by our * caller. */ static int @@ -3157,10 +3162,10 @@ megaraid_mbox_product_info(adapter_t *ad /** * megaraid_mbox_extended_cdb - check for support for extended CDBs - * @adapter - soft state for the controller + * @adapter : soft state for the controller * - * this routine check whether the controller in question supports extended - * ( > 10 bytes ) CDBs + * This routine check whether the controller in question supports extended + * ( > 10 bytes ) CDBs. */ static int megaraid_mbox_extended_cdb(adapter_t *adapter) @@ -3193,8 +3198,8 @@ megaraid_mbox_extended_cdb(adapter_t *ad /** * megaraid_mbox_support_ha - Do we support clustering - * @adapter - soft state for the controller - * @init_id - ID of the initiator + * @adapter : soft state for the controller + * @init_id : ID of the initiator * * Determine if the firmware supports clustering and the ID of the initiator. */ @@ -3236,9 +3241,9 @@ megaraid_mbox_support_ha(adapter_t *adap /** * megaraid_mbox_support_random_del - Do we support random deletion - * @adapter - soft state for the controller + * @adapter : soft state for the controller * - * Determine if the firmware supports random deletion + * Determine if the firmware supports random deletion. * Return: 1 is operation supported, 0 otherwise */ static int @@ -3271,10 +3276,10 @@ megaraid_mbox_support_random_del(adapter /** * megaraid_mbox_get_max_sg - maximum sg elements supported by the firmware - * @adapter - soft state for the controller + * @adapter : soft state for the controller * * Find out the maximum number of scatter-gather elements supported by the - * firmware + * firmware. */ static int megaraid_mbox_get_max_sg(adapter_t *adapter) @@ -3311,10 +3316,10 @@ megaraid_mbox_get_max_sg(adapter_t *adap /** * megaraid_mbox_enum_raid_scsi - enumerate the RAID and SCSI channels - * @adapter - soft state for the controller + * @adapter : soft state for the controller * - * Enumerate the RAID and SCSI channels for ROMB platoforms so that channels - * can be exported as regular SCSI channels + * Enumerate the RAID and SCSI channels for ROMB platforms so that channels + * can be exported as regular SCSI channels. */ static void megaraid_mbox_enum_raid_scsi(adapter_t *adapter) @@ -3348,9 +3353,9 @@ megaraid_mbox_enum_raid_scsi(adapter_t * /** * megaraid_mbox_flush_cache - flush adapter and disks cache - * @param adapter : soft state for the controller + * @adapter : soft state for the controller * - * Flush adapter cache followed by disks cache + * Flush adapter cache followed by disks cache. */ static void megaraid_mbox_flush_cache(adapter_t *adapter) @@ -3380,13 +3385,91 @@ megaraid_mbox_flush_cache(adapter_t *ada /** + * megaraid_mbox_fire_sync_cmd - fire the sync cmd + * @adapter : soft state for the controller + * + * Clears the pending cmds in FW and reinits its RAID structs. + */ +static int +megaraid_mbox_fire_sync_cmd(adapter_t *adapter) +{ + mbox_t *mbox; + uint8_t raw_mbox[sizeof(mbox_t)]; + mraid_device_t *raid_dev = ADAP2RAIDDEV(adapter); + mbox64_t *mbox64; + int status = 0; + int i; + uint32_t dword; + + mbox = (mbox_t *)raw_mbox; + + memset((caddr_t)raw_mbox, 0, sizeof(mbox_t)); + + raw_mbox[0] = 0xFF; + + mbox64 = raid_dev->mbox64; + mbox = raid_dev->mbox; + + /* Wait until mailbox is free */ + if (megaraid_busywait_mbox(raid_dev) != 0) { + status = 1; + goto blocked_mailbox; + } + + /* Copy mailbox data into host structure */ + memcpy((caddr_t)mbox, (caddr_t)raw_mbox, 16); + mbox->cmdid = 0xFE; + mbox->busy = 1; + mbox->poll = 0; + mbox->ack = 0; + mbox->numstatus = 0; + mbox->status = 0; + + wmb(); + WRINDOOR(raid_dev, raid_dev->mbox_dma | 0x1); + + /* Wait for maximum 1 min for status to post. + * If the Firmware SUPPORTS the ABOVE COMMAND, + * mbox->cmd will be set to 0 + * else + * the firmware will reject the command with + * mbox->numstatus set to 1 + */ + + i = 0; + status = 0; + while (!mbox->numstatus && mbox->cmd == 0xFF) { + rmb(); + msleep(1); + i++; + if (i > 1000 * 60) { + status = 1; + break; + } + } + if (mbox->numstatus == 1) + status = 1; /*cmd not supported*/ + + /* Check for interrupt line */ + dword = RDOUTDOOR(raid_dev); + WROUTDOOR(raid_dev, dword); + WRINDOOR(raid_dev,2); + + return status; + +blocked_mailbox: + con_log(CL_ANN, (KERN_WARNING "megaraid: blocked mailbox\n")); + return status; +} + +/** * megaraid_mbox_display_scb - display SCB information, mostly debug purposes - * @param adapter : controllers' soft state - * @param scb : SCB to be displayed - * @param level : debug level for console print + * @adapter : controller's soft state + * @scb : SCB to be displayed + * @level : debug level for console print * * Diplay information about the given SCB iff the current debug level is - * verbose + * verbose. */ static void megaraid_mbox_display_scb(adapter_t *adapter, scb_t *scb) @@ -3434,7 +3517,7 @@ megaraid_mbox_display_scb(adapter_t *ada * scsi addresses and megaraid scsi and logical drive addresses. We export * scsi devices on their actual addresses, whereas the logical drives are * exported on a virtual scsi channel. - **/ + */ static void megaraid_mbox_setup_device_map(adapter_t *adapter) { @@ -3472,7 +3555,7 @@ megaraid_mbox_setup_device_map(adapter_t /** * megaraid_cmm_register - register with the mangement module - * @param adapter : HBA soft state + * @adapter : HBA soft state * * Register with the management module, which allows applications to issue * ioctl calls to the drivers. This interface is used by the management module @@ -3562,11 +3645,11 @@ megaraid_cmm_register(adapter_t *adapter /** * megaraid_cmm_unregister - un-register with the mangement module - * @param adapter : HBA soft state + * @adapter : HBA soft state * * Un-register with the management module. * FIXME: mgmt module must return failure for unregister if it has pending - * commands in LLD + * commands in LLD. */ static int megaraid_cmm_unregister(adapter_t *adapter) @@ -3579,9 +3662,9 @@ megaraid_cmm_unregister(adapter_t *adapt /** * megaraid_mbox_mm_handler - interface for CMM to issue commands to LLD - * @param drvr_data : LLD specific data - * @param kioc : CMM interface packet - * @param action : command action + * @drvr_data : LLD specific data + * @kioc : CMM interface packet + * @action : command action * * This routine is invoked whenever the Common Mangement Module (CMM) has a * command for us. The 'action' parameter specifies if this is a new command @@ -3634,8 +3717,8 @@ megaraid_mbox_mm_handler(unsigned long d /** * megaraid_mbox_mm_command - issues commands routed through CMM - * @param adapter : HBA soft state - * @param kioc : management command packet + * @adapter : HBA soft state + * @kioc : management command packet * * Issues commands, which are routed through the management module. */ @@ -3804,8 +3887,8 @@ megaraid_mbox_mm_done(adapter_t *adapter /** * gather_hbainfo - HBA characteristics for the applications - * @param adapter : HBA soft state - * @param hinfo : pointer to the caller's host info strucuture + * @adapter : HBA soft state + * @hinfo : pointer to the caller's host info strucuture */ static int gather_hbainfo(adapter_t *adapter, mraid_hba_info_t *hinfo) @@ -3839,16 +3922,15 @@ gather_hbainfo(adapter_t *adapter, mraid /** * megaraid_sysfs_alloc_resources - allocate sysfs related resources + * @adapter : controller's soft state * * Allocate packets required to issue FW calls whenever the sysfs attributes * are read. These attributes would require up-to-date information from the * FW. Also set up resources for mutual exclusion to share these resources and * the wait queue. * - * @param adapter : controller's soft state - * - * @return 0 on success - * @return -ERROR_CODE on failure + * Return 0 on success. + * Return -ERROR_CODE on failure. */ static int megaraid_sysfs_alloc_resources(adapter_t *adapter) @@ -3885,10 +3967,9 @@ megaraid_sysfs_alloc_resources(adapter_t /** * megaraid_sysfs_free_resources - free sysfs related resources + * @adapter : controller's soft state * * Free packets allocated for sysfs FW commands - * - * @param adapter : controller's soft state */ static void megaraid_sysfs_free_resources(adapter_t *adapter) @@ -3907,10 +3988,9 @@ megaraid_sysfs_free_resources(adapter_t /** * megaraid_sysfs_get_ldmap_done - callback for get ldmap + * @uioc : completed packet * * Callback routine called in the ISR/tasklet context for get ldmap call - * - * @param uioc : completed packet */ static void megaraid_sysfs_get_ldmap_done(uioc_t *uioc) @@ -3926,12 +4006,11 @@ megaraid_sysfs_get_ldmap_done(uioc_t *ui /** * megaraid_sysfs_get_ldmap_timeout - timeout handling for get ldmap + * @data : timed out packet * * Timeout routine to recover and return to application, in case the adapter - * has stopped responding. A timeout of 60 seconds for this command seem like - * a good value - * - * @param uioc : timed out packet + * has stopped responding. A timeout of 60 seconds for this command seems like + * a good value. */ static void megaraid_sysfs_get_ldmap_timeout(unsigned long data) @@ -3948,6 +4027,7 @@ megaraid_sysfs_get_ldmap_timeout(unsigne /** * megaraid_sysfs_get_ldmap - get update logical drive map + * @adapter : controller's soft state * * This routine will be called whenever user reads the logical drive * attributes, go get the current logical drive mapping table from the @@ -3959,10 +4039,8 @@ megaraid_sysfs_get_ldmap_timeout(unsigne * standalone libary. For now, this should suffice since there is no other * user of this interface. * - * @param adapter : controller's soft state - * - * @return 0 on success - * @return -1 on failure + * Return 0 on success. + * Return -1 on failure. */ static int megaraid_sysfs_get_ldmap(adapter_t *adapter) @@ -4064,13 +4142,12 @@ megaraid_sysfs_get_ldmap(adapter_t *adap /** * megaraid_sysfs_show_app_hndl - display application handle for this adapter + * @cdev : class device object representation for the host + * @buf : buffer to send data to * * Display the handle used by the applications while executing management * tasks on the adapter. We invoke a management module API to get the adapter * handle, since we do not interface with applications directly. - * - * @param cdev : class device object representation for the host - * @param buf : buffer to send data to */ static ssize_t megaraid_sysfs_show_app_hndl(struct class_device *cdev, char *buf) @@ -4087,16 +4164,18 @@ megaraid_sysfs_show_app_hndl(struct clas /** * megaraid_sysfs_show_ldnum - display the logical drive number for this device + * @dev : device object representation for the scsi device + * @attr : device attribute to show + * @buf : buffer to send data to * * Display the logical drive number for the device in question, if it a valid - * logical drive. For physical devices, "-1" is returned - * The logical drive number is displayed in following format + * logical drive. For physical devices, "-1" is returned. + * + * The logical drive number is displayed in following format: * * - * * - * @param dev : device object representation for the scsi device - * @param buf : buffer to send data to + * */ static ssize_t megaraid_sysfs_show_ldnum(struct device *dev, struct device_attribute *attr, char *buf) diff --git a/drivers/scsi/megaraid/megaraid_mbox.h b/drivers/scsi/megaraid/megaraid_mbox.h index 2b5a328..9de803c 100644 --- a/drivers/scsi/megaraid/megaraid_mbox.h +++ b/drivers/scsi/megaraid/megaraid_mbox.h @@ -21,8 +21,8 @@ #include "mbox_defs.h" #include "megaraid_ioctl.h" -#define MEGARAID_VERSION "2.20.4.9" -#define MEGARAID_EXT_VERSION "(Release Date: Sun Jul 16 12:27:22 EST 2006)" +#define MEGARAID_VERSION "2.20.5.1" +#define MEGARAID_EXT_VERSION "(Release Date: Thu Nov 16 15:32:35 EST 2006)" /* @@ -146,27 +146,27 @@ typedef struct { /** * mraid_device_t - adapter soft state structure for mailbox controllers - * @param una_mbox64 : 64-bit mbox - unaligned - * @param una_mbox64_dma : mbox dma addr - unaligned - * @param mbox : 32-bit mbox - aligned - * @param mbox64 : 64-bit mbox - aligned - * @param mbox_dma : mbox dma addr - aligned - * @param mailbox_lock : exclusion lock for the mailbox - * @param baseport : base port of hba memory - * @param baseaddr : mapped addr of hba memory - * @param mbox_pool : pool of mailboxes - * @param mbox_pool_handle : handle for the mailbox pool memory - * @param epthru_pool : a pool for extended passthru commands - * @param epthru_pool_handle : handle to the pool above - * @param sg_pool : pool of scatter-gather lists for this driver - * @param sg_pool_handle : handle to the pool above - * @param ccb_list : list of our command control blocks - * @param uccb_list : list of cmd control blocks for mgmt module - * @param umbox64 : array of mailbox for user commands (cmm) - * @param pdrv_state : array for state of each physical drive. - * @param last_disp : flag used to show device scanning - * @param hw_error : set if FW not responding - * @param fast_load : If set, skip physical device scanning + * @una_mbox64 : 64-bit mbox - unaligned + * @una_mbox64_dma : mbox dma addr - unaligned + * @mbox : 32-bit mbox - aligned + * @mbox64 : 64-bit mbox - aligned + * @mbox_dma : mbox dma addr - aligned + * @mailbox_lock : exclusion lock for the mailbox + * @baseport : base port of hba memory + * @baseaddr : mapped addr of hba memory + * @mbox_pool : pool of mailboxes + * @mbox_pool_handle : handle for the mailbox pool memory + * @epthru_pool : a pool for extended passthru commands + * @epthru_pool_handle : handle to the pool above + * @sg_pool : pool of scatter-gather lists for this driver + * @sg_pool_handle : handle to the pool above + * @ccb_list : list of our command control blocks + * @uccb_list : list of cmd control blocks for mgmt module + * @umbox64 : array of mailbox for user commands (cmm) + * @pdrv_state : array for state of each physical drive. + * @last_disp : flag used to show device scanning + * @hw_error : set if FW not responding + * @fast_load : If set, skip physical device scanning * @channel_class : channel class, RAID or SCSI * @sysfs_sem : semaphore to serialize access to sysfs res. * @sysfs_uioc : management packet to issue FW calls from sysfs diff --git a/drivers/scsi/megaraid/megaraid_mm.c b/drivers/scsi/megaraid/megaraid_mm.c index d85b9a8..f33a678 100644 --- a/drivers/scsi/megaraid/megaraid_mm.c +++ b/drivers/scsi/megaraid/megaraid_mm.c @@ -67,7 +67,7 @@ static struct list_head adapters_list_g; static wait_queue_head_t wait_q; -static struct file_operations lsi_fops = { +static const struct file_operations lsi_fops = { .open = mraid_mm_open, .ioctl = mraid_mm_ioctl, #ifdef CONFIG_COMPAT @@ -78,10 +78,10 @@ #endif /** * mraid_mm_open - open routine for char node interface - * @inod : unused + * @inode : unused * @filep : unused * - * allow ioctl operations by apps only if they superuser privilege + * Allow ioctl operations by apps only if they have superuser privilege. */ static int mraid_mm_open(struct inode *inode, struct file *filep) @@ -214,7 +214,9 @@ mraid_mm_ioctl(struct inode *inode, stru /** * mraid_mm_get_adapter - Returns corresponding adapters for the mimd packet * @umimd : User space mimd_t ioctl packet - * @adapter : pointer to the adapter (OUT) + * @rval : returned success/error status + * + * The function return value is a pointer to the located @adapter. */ static mraid_mmadp_t * mraid_mm_get_adapter(mimd_t __user *umimd, int *rval) @@ -252,11 +254,11 @@ mraid_mm_get_adapter(mimd_t __user *umim return adapter; } -/* - * handle_drvrcmd - This routine checks if the opcode is a driver - * cmd and if it is, handles it. +/** + * handle_drvrcmd - Checks if the opcode is a driver cmd and if it is, handles it. * @arg : packet sent by the user app * @old_ioctl : mimd if 1; uioc otherwise + * @rval : pointer for command's returned value (not function status) */ static int handle_drvrcmd(void __user *arg, uint8_t old_ioctl, int *rval) @@ -322,8 +324,8 @@ old_packet: /** * mimd_to_kioc - Converter from old to new ioctl format - * * @umimd : user space old MIMD IOCTL + * @adp : adapter softstate * @kioc : kernel space new format IOCTL * * Routine to convert MIMD interface IOCTL to new interface IOCTL packet. The @@ -474,7 +476,6 @@ mimd_to_kioc(mimd_t __user *umimd, mraid /** * mraid_mm_attch_buf - Attach a free dma buffer for required size - * * @adp : Adapter softstate * @kioc : kioc that the buffer needs to be attached to * @xferlen : required length for buffer @@ -607,7 +608,6 @@ mraid_mm_alloc_kioc(mraid_mmadp_t *adp) /** * mraid_mm_dealloc_kioc - Return kioc to free pool - * * @adp : Adapter softstate * @kioc : uioc_t node to be returned to free pool */ @@ -652,7 +652,6 @@ mraid_mm_dealloc_kioc(mraid_mmadp_t *adp /** * lld_ioctl - Routine to issue ioctl to low level drvr - * * @adp : The adapter handle * @kioc : The ioctl packet with kernel addresses */ @@ -705,7 +704,6 @@ lld_ioctl(mraid_mmadp_t *adp, uioc_t *ki /** * ioctl_done - callback from the low level driver - * * @kioc : completed ioctl packet */ static void @@ -756,9 +754,8 @@ ioctl_done(uioc_t *kioc) } -/* - * lld_timedout : callback from the expired timer - * +/** + * lld_timedout - callback from the expired timer * @ptr : ioctl packet that timed out */ static void @@ -776,8 +773,7 @@ lld_timedout(unsigned long ptr) /** - * kioc_to_mimd : Converter from new back to old format - * + * kioc_to_mimd - Converter from new back to old format * @kioc : Kernel space IOCTL packet (successfully issued) * @mimd : User space MIMD packet */ @@ -855,7 +851,6 @@ kioc_to_mimd(uioc_t *kioc, mimd_t __user /** * hinfo_to_cinfo - Convert new format hba info into old format - * * @hinfo : New format, more comprehensive adapter info * @cinfo : Old format adapter info to support mimd_t apps */ @@ -878,10 +873,9 @@ hinfo_to_cinfo(mraid_hba_info_t *hinfo, } -/* - * mraid_mm_register_adp - Registration routine for low level drvrs - * - * @adp : Adapter objejct +/** + * mraid_mm_register_adp - Registration routine for low level drivers + * @lld_adp : Adapter objejct */ int mraid_mm_register_adp(mraid_mmadp_t *lld_adp) @@ -1007,15 +1001,14 @@ memalloc_error: /** * mraid_mm_adapter_app_handle - return the application handle for this adapter + * @unique_id : adapter unique identifier * - * For the given driver data, locate the adadpter in our global list and + * For the given driver data, locate the adapter in our global list and * return the corresponding handle, which is also used by applications to * uniquely identify an adapter. * - * @param unique_id : adapter unique identifier - * - * @return adapter handle if found in the list - * @return 0 if adapter could not be located, should never happen though + * Return adapter handle if found in the list. + * Return 0 if adapter could not be located, should never happen though. */ uint32_t mraid_mm_adapter_app_handle(uint32_t unique_id) @@ -1040,7 +1033,6 @@ mraid_mm_adapter_app_handle(uint32_t uni /** * mraid_mm_setup_dma_pools - Set up dma buffer pools per adapter - * * @adp : Adapter softstate * * We maintain a pool of dma buffers per each adapter. Each pool has one @@ -1093,11 +1085,11 @@ dma_pool_setup_error: } -/* +/** * mraid_mm_unregister_adp - Unregister routine for low level drivers - * Assume no outstanding ioctls to llds. - * * @unique_id : UID of the adpater + * + * Assumes no outstanding ioctls to llds. */ int mraid_mm_unregister_adp(uint32_t unique_id) @@ -1131,7 +1123,6 @@ mraid_mm_unregister_adp(uint32_t unique_ /** * mraid_mm_free_adp_resources - Free adapter softstate - * * @adp : Adapter softstate */ static void @@ -1162,7 +1153,6 @@ mraid_mm_free_adp_resources(mraid_mmadp_ /** * mraid_mm_teardown_dma_pools - Free all per adapter dma buffers - * * @adp : Adapter softstate */ static void @@ -1190,7 +1180,7 @@ mraid_mm_teardown_dma_pools(mraid_mmadp_ } /** - * mraid_mm_init : Module entry point + * mraid_mm_init - Module entry point */ static int __init mraid_mm_init(void) @@ -1214,10 +1204,13 @@ mraid_mm_init(void) } +#ifdef CONFIG_COMPAT /** - * mraid_mm_compat_ioctl : 32bit to 64bit ioctl conversion routine + * mraid_mm_compat_ioctl - 32bit to 64bit ioctl conversion routine + * @filep : file operations pointer (ignored) + * @cmd : ioctl command + * @arg : user ioctl packet */ -#ifdef CONFIG_COMPAT static long mraid_mm_compat_ioctl(struct file *filep, unsigned int cmd, unsigned long arg) @@ -1231,7 +1224,7 @@ mraid_mm_compat_ioctl(struct file *filep #endif /** - * mraid_mm_exit : Module exit point + * mraid_mm_exit - Module exit point */ static void __exit mraid_mm_exit(void) diff --git a/drivers/scsi/megaraid/megaraid_sas.c b/drivers/scsi/megaraid/megaraid_sas.c index b5bdd0d..15e24fc 100644 --- a/drivers/scsi/megaraid/megaraid_sas.c +++ b/drivers/scsi/megaraid/megaraid_sas.c @@ -2913,7 +2913,7 @@ #endif /* * File operations structure for management interface */ -static struct file_operations megasas_mgmt_fops = { +static const struct file_operations megasas_mgmt_fops = { .owner = THIS_MODULE, .open = megasas_mgmt_open, .release = megasas_mgmt_release, diff --git a/drivers/scsi/megaraid/megaraid_sas.h b/drivers/scsi/megaraid/megaraid_sas.h index 55eddcf..cacb3ad 100644 --- a/drivers/scsi/megaraid/megaraid_sas.h +++ b/drivers/scsi/megaraid/megaraid_sas.h @@ -15,7 +15,7 @@ #ifndef LSI_MEGARAID_SAS_H #define LSI_MEGARAID_SAS_H -/** +/* * MegaRAID SAS Driver meta data */ #define MEGASAS_VERSION "00.00.03.05" @@ -40,7 +40,7 @@ #define PCI_DEVICE_ID_LSI_VERDE_ZCR 0x0 * "message frames" */ -/** +/* * FW posts its state in upper 4 bits of outbound_msg_0 register */ #define MFI_STATE_MASK 0xF0000000 @@ -58,7 +58,7 @@ #define MFI_STATE_FAULT 0xF0000000 #define MEGAMFI_FRAME_SIZE 64 -/** +/* * During FW init, clear pending cmds & reset state using inbound_msg_0 * * ABORT : Abort all pending cmds @@ -78,7 +78,7 @@ #define MFI_RESET_FLAGS MFI_INIT_READ MFI_INIT_MFIMODE| \ MFI_INIT_ABORT -/** +/* * MFI frame flags */ #define MFI_FRAME_POST_IN_REPLY_QUEUE 0x0000 @@ -92,12 +92,12 @@ #define MFI_FRAME_DIR_WRITE 0x0008 #define MFI_FRAME_DIR_READ 0x0010 #define MFI_FRAME_DIR_BOTH 0x0018 -/** +/* * Definition for cmd_status */ #define MFI_CMD_STATUS_POLL_MODE 0xFF -/** +/* * MFI command opcodes */ #define MFI_CMD_INIT 0x00 @@ -128,7 +128,7 @@ #define MR_DCMD_CLUSTER 0x08000000 #define MR_DCMD_CLUSTER_RESET_ALL 0x08010100 #define MR_DCMD_CLUSTER_RESET_LD 0x08010200 -/** +/* * MFI command completion codes */ enum MFI_STAT { diff --git a/drivers/scsi/mvme147.c b/drivers/scsi/mvme147.c index 1ddd7a1..be41aad 100644 --- a/drivers/scsi/mvme147.c +++ b/drivers/scsi/mvme147.c @@ -1,7 +1,6 @@ #include #include #include -#include #include #include diff --git a/drivers/scsi/mvme16x.c b/drivers/scsi/mvme16x.c index 890e9e2..575fe6f 100644 --- a/drivers/scsi/mvme16x.c +++ b/drivers/scsi/mvme16x.c @@ -6,7 +6,6 @@ #include #include #include -#include #include #include diff --git a/drivers/scsi/nsp32.c b/drivers/scsi/nsp32.c index 7c13f6f..f6f561d 100644 --- a/drivers/scsi/nsp32.c +++ b/drivers/scsi/nsp32.c @@ -27,7 +27,6 @@ #include #include #include #include -#include #include #include #include diff --git a/drivers/scsi/oktagon_esp.c b/drivers/scsi/oktagon_esp.c index c116a6a..26a6d55 100644 --- a/drivers/scsi/oktagon_esp.c +++ b/drivers/scsi/oktagon_esp.c @@ -133,7 +133,7 @@ int oktagon_esp_detect(struct scsi_host_ eregs = (struct ESP_regs *)(address + OKTAGON_ESP_ADDR); /* This line was 5 lines lower */ - esp = esp_allocate(tpnt, (void *)board+OKTAGON_ESP_ADDR); + esp = esp_allocate(tpnt, (void *)board + OKTAGON_ESP_ADDR, 0); /* we have to shift the registers only one bit for oktagon */ esp->shift = 1; diff --git a/drivers/scsi/osst.c b/drivers/scsi/osst.c index 7d23110..9668b73 100644 --- a/drivers/scsi/osst.c +++ b/drivers/scsi/osst.c @@ -521,10 +521,10 @@ static void osst_init_aux(struct osst_ta break; default: ; /* probably FILL */ } - aux->filemark_cnt = ntohl(STp->filemark_cnt); - aux->phys_fm = ntohl(0xffffffff); - aux->last_mark_ppos = ntohl(STp->last_mark_ppos); - aux->last_mark_lbn = ntohl(STp->last_mark_lbn); + aux->filemark_cnt = htonl(STp->filemark_cnt); + aux->phys_fm = htonl(0xffffffff); + aux->last_mark_ppos = htonl(STp->last_mark_ppos); + aux->last_mark_lbn = htonl(STp->last_mark_lbn); } /* @@ -5522,7 +5522,7 @@ __setup("osst=", osst_setup); #endif -static struct file_operations osst_fops = { +static const struct file_operations osst_fops = { .owner = THIS_MODULE, .read = osst_read, .write = osst_write, diff --git a/drivers/scsi/osst.h b/drivers/scsi/osst.h index 1e426f5..2cc7b5a 100644 --- a/drivers/scsi/osst.h +++ b/drivers/scsi/osst.h @@ -288,11 +288,11 @@ #elif defined(__LITTLE_ENDIAN_BITFIELD) #else #error "Please fix " #endif - u16 max_speed; /* Maximum speed supported in KBps */ + __be16 max_speed; /* Maximum speed supported in KBps */ u8 reserved10, reserved11; - u16 ctl; /* Continuous Transfer Limit in blocks */ - u16 speed; /* Current Speed, in KBps */ - u16 buffer_size; /* Buffer Size, in 512 bytes */ + __be16 ctl; /* Continuous Transfer Limit in blocks */ + __be16 speed; /* Current Speed, in KBps */ + __be16 buffer_size; /* Buffer Size, in 512 bytes */ u8 reserved18, reserved19; } osst_capabilities_page_t; @@ -352,8 +352,8 @@ #endif u8 reserved2; u8 density; u8 reserved3,reserved4; - u16 segtrk; - u16 trks; + __be16 segtrk; + __be16 trks; u8 reserved5,reserved6,reserved7,reserved8,reserved9,reserved10; } osst_tape_paramtr_page_t; @@ -369,18 +369,18 @@ #define OS_PARTITION_VERSION (1) typedef struct os_partition_s { __u8 partition_num; __u8 par_desc_ver; - __u16 wrt_pass_cntr; - __u32 first_frame_ppos; - __u32 last_frame_ppos; - __u32 eod_frame_ppos; + __be16 wrt_pass_cntr; + __be32 first_frame_ppos; + __be32 last_frame_ppos; + __be32 eod_frame_ppos; } os_partition_t; /* * DAT entry */ typedef struct os_dat_entry_s { - __u32 blk_sz; - __u16 blk_cnt; + __be32 blk_sz; + __be16 blk_cnt; __u8 flags; __u8 reserved; } os_dat_entry_t; @@ -412,23 +412,23 @@ #define OS_FRAME_TYPE_DATA (1 << 7) * AUX */ typedef struct os_aux_s { - __u32 format_id; /* hardware compability AUX is based on */ + __be32 format_id; /* hardware compability AUX is based on */ char application_sig[4]; /* driver used to write this media */ - __u32 hdwr; /* reserved */ - __u32 update_frame_cntr; /* for configuration frame */ + __be32 hdwr; /* reserved */ + __be32 update_frame_cntr; /* for configuration frame */ __u8 frame_type; __u8 frame_type_reserved; __u8 reserved_18_19[2]; os_partition_t partition; __u8 reserved_36_43[8]; - __u32 frame_seq_num; - __u32 logical_blk_num_high; - __u32 logical_blk_num; + __be32 frame_seq_num; + __be32 logical_blk_num_high; + __be32 logical_blk_num; os_dat_t dat; __u8 reserved188_191[4]; - __u32 filemark_cnt; - __u32 phys_fm; - __u32 last_mark_ppos; + __be32 filemark_cnt; + __be32 phys_fm; + __be32 last_mark_ppos; __u8 reserved204_223[20]; /* @@ -436,8 +436,8 @@ typedef struct os_aux_s { * * Linux specific fields: */ - __u32 next_mark_ppos; /* when known, points to next marker */ - __u32 last_mark_lbn; /* storing log_blk_num of last mark is extends ADR spec */ + __be32 next_mark_ppos; /* when known, points to next marker */ + __be32 last_mark_lbn; /* storing log_blk_num of last mark is extends ADR spec */ __u8 linux_specific[24]; __u8 reserved_256_511[256]; @@ -450,19 +450,19 @@ typedef struct os_fm_tab_s { __u8 reserved_1; __u8 fm_tab_ent_sz; __u8 reserved_3; - __u16 fm_tab_ent_cnt; + __be16 fm_tab_ent_cnt; __u8 reserved6_15[10]; - __u32 fm_tab_ent[OS_FM_TAB_MAX]; + __be32 fm_tab_ent[OS_FM_TAB_MAX]; } os_fm_tab_t; typedef struct os_ext_trk_ey_s { __u8 et_part_num; __u8 fmt; - __u16 fm_tab_off; + __be16 fm_tab_off; __u8 reserved4_7[4]; - __u32 last_hlb_hi; - __u32 last_hlb; - __u32 last_pp; + __be32 last_hlb_hi; + __be32 last_hlb; + __be32 last_pp; __u8 reserved20_31[12]; } os_ext_trk_ey_t; @@ -479,17 +479,17 @@ typedef struct os_header_s { char ident_str[8]; __u8 major_rev; __u8 minor_rev; - __u16 ext_trk_tb_off; + __be16 ext_trk_tb_off; __u8 reserved12_15[4]; __u8 pt_par_num; __u8 pt_reserved1_3[3]; os_partition_t partition[16]; - __u32 cfg_col_width; - __u32 dat_col_width; - __u32 qfa_col_width; + __be32 cfg_col_width; + __be32 dat_col_width; + __be32 qfa_col_width; __u8 cartridge[16]; __u8 reserved304_511[208]; - __u32 old_filemark_list[16680/4]; /* in ADR 1.4 __u8 track_table[16680] */ + __be32 old_filemark_list[16680/4]; /* in ADR 1.4 __u8 track_table[16680] */ os_ext_trk_tb_t ext_track_tb; __u8 reserved17272_17735[464]; os_fm_tab_t dat_fm_tab; diff --git a/drivers/scsi/pas16.c b/drivers/scsi/pas16.c index 1434209..ee59656 100644 --- a/drivers/scsi/pas16.c +++ b/drivers/scsi/pas16.c @@ -116,7 +116,6 @@ #include #include #include #include -#include #include #include #include diff --git a/drivers/scsi/pcmcia/aha152x_stub.c b/drivers/scsi/pcmcia/aha152x_stub.c index aad362b..370802d 100644 --- a/drivers/scsi/pcmcia/aha152x_stub.c +++ b/drivers/scsi/pcmcia/aha152x_stub.c @@ -37,7 +37,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/scsi/pcmcia/fdomain_stub.c b/drivers/scsi/pcmcia/fdomain_stub.c index a1c5f26..4b82b20 100644 --- a/drivers/scsi/pcmcia/fdomain_stub.c +++ b/drivers/scsi/pcmcia/fdomain_stub.c @@ -34,7 +34,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/scsi/pcmcia/nsp_cs.c b/drivers/scsi/pcmcia/nsp_cs.c index e16fe36..c6f8c6e 100644 --- a/drivers/scsi/pcmcia/nsp_cs.c +++ b/drivers/scsi/pcmcia/nsp_cs.c @@ -31,7 +31,6 @@ #include #include #include #include -#include #include #include #include diff --git a/drivers/scsi/pcmcia/nsp_cs.h b/drivers/scsi/pcmcia/nsp_cs.h index 625ca97..9102cbd 100644 --- a/drivers/scsi/pcmcia/nsp_cs.h +++ b/drivers/scsi/pcmcia/nsp_cs.h @@ -290,7 +290,6 @@ #ifdef NSP_DEBUG #endif } nsp_hw_data; - /**************************************************************************** * */ @@ -302,22 +301,13 @@ static int nsp_cs_config (struct /* Linux SCSI subsystem specific functions */ static struct Scsi_Host *nsp_detect (struct scsi_host_template *sht); -#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)) -static int nsp_detect_old (struct scsi_host_template *sht); -static int nsp_release_old(struct Scsi_Host *shpnt); -#endif static const char *nsp_info (struct Scsi_Host *shpnt); static int nsp_proc_info ( -#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,73)) struct Scsi_Host *host, -#endif char *buffer, char **start, off_t offset, int length, -#if !(LINUX_VERSION_CODE > KERNEL_VERSION(2,5,73)) - int hostno, -#endif int inout); static int nsp_queuecommand(struct scsi_cmnd *SCpnt, void (* done)(struct scsi_cmnd *SCpnt)); @@ -356,7 +346,6 @@ static struct Scsi_Host *nsp_detect(stru static int __init nsp_cs_init(void); static void __exit nsp_cs_exit(void); - /* Debug */ #ifdef NSP_DEBUG static void show_command (struct scsi_cmnd *SCpnt); @@ -401,7 +390,6 @@ enum _burst_mode { BURST_MEM32 = 2, }; - /************************************************************************** * SCSI messaage */ @@ -413,62 +401,8 @@ #define MSG_BUS_DEVICE_RESET 0x0c #define MSG_EXT_SDTR 0x01 - -/************************************************************************** - * Compatibility functions - */ - -/* for Kernel 2.4 */ -#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0)) -# define scsi_register_host(template) scsi_register_module(MODULE_SCSI_HA, template) -# define scsi_unregister_host(template) scsi_unregister_module(MODULE_SCSI_HA, template) -# define scsi_host_put(host) scsi_unregister(host) - -typedef void irqreturn_t; -# define IRQ_NONE /* */ -# define IRQ_HANDLED /* */ -# define IRQ_RETVAL(x) /* */ - -/* This is ad-hoc version of scsi_host_get_next() */ -static inline struct Scsi_Host *scsi_host_get_next(struct Scsi_Host *host) -{ - if (host == NULL) { - return scsi_hostlist; - } else { - return host->next; - } -} - -/* This is ad-hoc version of scsi_host_hn_get() */ -static inline struct Scsi_Host *scsi_host_hn_get(unsigned short hostno) -{ - struct Scsi_Host *host; - - for (host = scsi_host_get_next(NULL); host != NULL; - host = scsi_host_get_next(host)) { - if (host->host_no == hostno) { - break; - } - } - - return host; -} - -static void cs_error(struct pcmcia_device *handle, int func, int ret) -{ - error_info_t err = { func, ret }; - pcmcia_report_error(handle, &err); -} - -/* scatter-gather table */ -# define BUFFER_ADDR (SCpnt->SCp.buffer->address) -#endif - -/* for Kernel 2.6 */ -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)) /* scatter-gather table */ # define BUFFER_ADDR ((char *)((unsigned int)(SCpnt->SCp.buffer->page) + SCpnt->SCp.buffer->offset)) -#endif #endif /*__nsp_cs__*/ /* end */ diff --git a/drivers/scsi/pcmcia/qlogic_stub.c b/drivers/scsi/pcmcia/qlogic_stub.c index 9d431fe..697cfb7 100644 --- a/drivers/scsi/pcmcia/qlogic_stub.c +++ b/drivers/scsi/pcmcia/qlogic_stub.c @@ -34,7 +34,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/scsi/pcmcia/sym53c500_cs.c b/drivers/scsi/pcmcia/sym53c500_cs.c index 5b458d2..ffe75c4 100644 --- a/drivers/scsi/pcmcia/sym53c500_cs.c +++ b/drivers/scsi/pcmcia/sym53c500_cs.c @@ -54,7 +54,6 @@ #include #include #include #include -#include #include #include #include diff --git a/drivers/scsi/qla1280.c b/drivers/scsi/qla1280.c index 1548d42..6777e8a 100644 --- a/drivers/scsi/qla1280.c +++ b/drivers/scsi/qla1280.c @@ -341,7 +341,6 @@ #include #include #include #include -#include #include #include #include diff --git a/drivers/scsi/qla2xxx/qla_attr.c b/drivers/scsi/qla2xxx/qla_attr.c index 7b18a6c..8081b63 100644 --- a/drivers/scsi/qla2xxx/qla_attr.c +++ b/drivers/scsi/qla2xxx/qla_attr.c @@ -140,6 +140,8 @@ qla2x00_sysfs_write_nvram(struct kobject ha->isp_ops.write_nvram(ha, (uint8_t *)buf, ha->nvram_base, count); spin_unlock_irqrestore(&ha->hardware_lock, flags); + set_bit(ISP_ABORT_NEEDED, &ha->dpc_flags); + return (count); } @@ -653,6 +655,43 @@ qla2x00_beacon_store(struct class_device return count; } +static ssize_t +qla2x00_optrom_bios_version_show(struct class_device *cdev, char *buf) +{ + scsi_qla_host_t *ha = to_qla_host(class_to_shost(cdev)); + + return snprintf(buf, PAGE_SIZE, "%d.%02d\n", ha->bios_revision[1], + ha->bios_revision[0]); +} + +static ssize_t +qla2x00_optrom_efi_version_show(struct class_device *cdev, char *buf) +{ + scsi_qla_host_t *ha = to_qla_host(class_to_shost(cdev)); + + return snprintf(buf, PAGE_SIZE, "%d.%02d\n", ha->efi_revision[1], + ha->efi_revision[0]); +} + +static ssize_t +qla2x00_optrom_fcode_version_show(struct class_device *cdev, char *buf) +{ + scsi_qla_host_t *ha = to_qla_host(class_to_shost(cdev)); + + return snprintf(buf, PAGE_SIZE, "%d.%02d\n", ha->fcode_revision[1], + ha->fcode_revision[0]); +} + +static ssize_t +qla2x00_optrom_fw_version_show(struct class_device *cdev, char *buf) +{ + scsi_qla_host_t *ha = to_qla_host(class_to_shost(cdev)); + + return snprintf(buf, PAGE_SIZE, "%d.%02d.%02d %d\n", + ha->fw_revision[0], ha->fw_revision[1], ha->fw_revision[2], + ha->fw_revision[3]); +} + static CLASS_DEVICE_ATTR(driver_version, S_IRUGO, qla2x00_drvr_version_show, NULL); static CLASS_DEVICE_ATTR(fw_version, S_IRUGO, qla2x00_fw_version_show, NULL); @@ -669,6 +708,14 @@ static CLASS_DEVICE_ATTR(zio_timer, S_IR qla2x00_zio_timer_store); static CLASS_DEVICE_ATTR(beacon, S_IRUGO | S_IWUSR, qla2x00_beacon_show, qla2x00_beacon_store); +static CLASS_DEVICE_ATTR(optrom_bios_version, S_IRUGO, + qla2x00_optrom_bios_version_show, NULL); +static CLASS_DEVICE_ATTR(optrom_efi_version, S_IRUGO, + qla2x00_optrom_efi_version_show, NULL); +static CLASS_DEVICE_ATTR(optrom_fcode_version, S_IRUGO, + qla2x00_optrom_fcode_version_show, NULL); +static CLASS_DEVICE_ATTR(optrom_fw_version, S_IRUGO, + qla2x00_optrom_fw_version_show, NULL); struct class_device_attribute *qla2x00_host_attrs[] = { &class_device_attr_driver_version, @@ -683,6 +730,10 @@ struct class_device_attribute *qla2x00_h &class_device_attr_zio, &class_device_attr_zio_timer, &class_device_attr_beacon, + &class_device_attr_optrom_bios_version, + &class_device_attr_optrom_efi_version, + &class_device_attr_optrom_fcode_version, + &class_device_attr_optrom_fw_version, NULL, }; @@ -836,21 +887,24 @@ qla2x00_get_fc_host_stats(struct Scsi_Ho link_stat_t stat_buf; struct fc_host_statistics *pfc_host_stat; + rval = QLA_FUNCTION_FAILED; pfc_host_stat = &ha->fc_host_stat; memset(pfc_host_stat, -1, sizeof(struct fc_host_statistics)); if (IS_QLA24XX(ha) || IS_QLA54XX(ha)) { rval = qla24xx_get_isp_stats(ha, (uint32_t *)&stat_buf, sizeof(stat_buf) / 4, mb_stat); - } else { + } else if (atomic_read(&ha->loop_state) == LOOP_READY && + !test_bit(ABORT_ISP_ACTIVE, &ha->dpc_flags) && + !test_bit(ISP_ABORT_NEEDED, &ha->dpc_flags) && + !ha->dpc_active) { + /* Must be in a 'READY' state for statistics retrieval. */ rval = qla2x00_get_link_status(ha, ha->loop_id, &stat_buf, mb_stat); } - if (rval != 0) { - qla_printk(KERN_WARNING, ha, - "Unable to retrieve host statistics (%d).\n", mb_stat[0]); - return pfc_host_stat; - } + + if (rval != QLA_SUCCESS) + goto done; pfc_host_stat->link_failure_count = stat_buf.link_fail_cnt; pfc_host_stat->loss_of_sync_count = stat_buf.loss_sync_cnt; @@ -858,7 +912,7 @@ qla2x00_get_fc_host_stats(struct Scsi_Ho pfc_host_stat->prim_seq_protocol_err_count = stat_buf.prim_seq_err_cnt; pfc_host_stat->invalid_tx_word_count = stat_buf.inval_xmit_word_cnt; pfc_host_stat->invalid_crc_count = stat_buf.inval_crc_cnt; - +done: return pfc_host_stat; } diff --git a/drivers/scsi/qla2xxx/qla_def.h b/drivers/scsi/qla2xxx/qla_def.h index 2c10130..05f4f2a 100644 --- a/drivers/scsi/qla2xxx/qla_def.h +++ b/drivers/scsi/qla2xxx/qla_def.h @@ -2045,6 +2045,29 @@ struct isp_operations { uint32_t, uint32_t); int (*write_optrom) (struct scsi_qla_host *, uint8_t *, uint32_t, uint32_t); + + int (*get_flash_version) (struct scsi_qla_host *, void *); +}; + +/* MSI-X Support *************************************************************/ + +#define QLA_MSIX_CHIP_REV_24XX 3 +#define QLA_MSIX_FW_MODE(m) (((m) & (BIT_7|BIT_8|BIT_9)) >> 7) +#define QLA_MSIX_FW_MODE_1(m) (QLA_MSIX_FW_MODE(m) == 1) + +#define QLA_MSIX_DEFAULT 0x00 +#define QLA_MSIX_RSP_Q 0x01 + +#define QLA_MSIX_ENTRIES 2 +#define QLA_MIDX_DEFAULT 0 +#define QLA_MIDX_RSP_Q 1 + +struct scsi_qla_host; + +struct qla_msix_entry { + int have_irq; + uint16_t msix_vector; + uint16_t msix_entry; }; /* @@ -2077,6 +2100,7 @@ typedef struct scsi_qla_host { uint32_t enable_lip_full_login :1; uint32_t enable_target_reset :1; uint32_t enable_led_scheme :1; + uint32_t inta_enabled :1; uint32_t msi_enabled :1; uint32_t msix_enabled :1; uint32_t disable_serdes :1; @@ -2316,8 +2340,6 @@ #define MBX_INTERRUPT 1 #define MBX_INTR_WAIT 2 #define MBX_UPDATE_FLASH_ACTIVE 3 - spinlock_t mbx_reg_lock; /* Mbx Cmd Register Lock */ - struct semaphore mbx_cmd_sem; /* Serialialize mbx access */ struct semaphore mbx_intr_sem; /* Used for completion notification */ @@ -2358,6 +2380,7 @@ #define RISC_START_ADDRESS_2400 0x100000 uint8_t host_str[16]; uint32_t pci_attr; + uint16_t chip_revision; uint16_t product_id[4]; @@ -2379,6 +2402,15 @@ #define QLA_SWAITING 0 #define QLA_SREADING 1 #define QLA_SWRITING 2 + /* PCI expansion ROM image information. */ +#define ROM_CODE_TYPE_BIOS 0 +#define ROM_CODE_TYPE_FCODE 1 +#define ROM_CODE_TYPE_EFI 3 + uint8_t bios_revision[2]; + uint8_t efi_revision[2]; + uint8_t fcode_revision[16]; + uint32_t fw_revision[4]; + /* Needed for BEACON */ uint16_t beacon_blink_led; uint8_t beacon_color_state; @@ -2391,6 +2423,8 @@ #define QLA_LED_ALL_ON 0x07 /* yellow, uint16_t zio_mode; uint16_t zio_timer; struct fc_host_statistics fc_host_stat; + + struct qla_msix_entry msix_entries[QLA_MSIX_ENTRIES]; } scsi_qla_host_t; diff --git a/drivers/scsi/qla2xxx/qla_gbl.h b/drivers/scsi/qla2xxx/qla_gbl.h index e4dd12f..74544ae 100644 --- a/drivers/scsi/qla2xxx/qla_gbl.h +++ b/drivers/scsi/qla2xxx/qla_gbl.h @@ -224,6 +224,9 @@ extern irqreturn_t qla24xx_intr_handler( extern void qla2x00_process_response_queue(struct scsi_qla_host *); extern void qla24xx_process_response_queue(struct scsi_qla_host *); +extern int qla2x00_request_irqs(scsi_qla_host_t *); +extern void qla2x00_free_irqs(scsi_qla_host_t *); + /* * Global Function Prototypes in qla_sup.c source file. */ @@ -259,6 +262,9 @@ extern uint8_t *qla24xx_read_optrom_data extern int qla24xx_write_optrom_data(struct scsi_qla_host *, uint8_t *, uint32_t, uint32_t); +extern int qla2x00_get_flash_version(scsi_qla_host_t *, void *); +extern int qla24xx_get_flash_version(scsi_qla_host_t *, void *); + /* * Global Function Prototypes in qla_dbg.c source file. */ diff --git a/drivers/scsi/qla2xxx/qla_init.c b/drivers/scsi/qla2xxx/qla_init.c index b3dac26..98c01cd 100644 --- a/drivers/scsi/qla2xxx/qla_init.c +++ b/drivers/scsi/qla2xxx/qla_init.c @@ -65,7 +65,7 @@ qla2x00_initialize_adapter(scsi_qla_host ha->flags.reset_active = 0; atomic_set(&ha->loop_down_timer, LOOP_DOWN_TIME); atomic_set(&ha->loop_state, LOOP_DOWN); - ha->device_flags = 0; + ha->device_flags = DFLG_NO_CABLE; ha->dpc_flags = 0; ha->flags.management_server_logged_in = 0; ha->marker_needed = 0; @@ -77,16 +77,23 @@ qla2x00_initialize_adapter(scsi_qla_host qla_printk(KERN_INFO, ha, "Configuring PCI space...\n"); rval = ha->isp_ops.pci_config(ha); if (rval) { - DEBUG2(printk("scsi(%ld): Unable to configure PCI space=n", + DEBUG2(printk("scsi(%ld): Unable to configure PCI space.\n", ha->host_no)); return (rval); } ha->isp_ops.reset_chip(ha); + ha->isp_ops.get_flash_version(ha, ha->request_ring); + qla_printk(KERN_INFO, ha, "Configure NVRAM parameters...\n"); - ha->isp_ops.nvram_config(ha); + rval = ha->isp_ops.nvram_config(ha); + if (rval) { + DEBUG2(printk("scsi(%ld): Unable to verify NVRAM data.\n", + ha->host_no)); + return rval; + } if (ha->flags.disable_serdes) { /* Mask HBA via NVRAM settings? */ @@ -293,6 +300,8 @@ qla24xx_pci_config(scsi_qla_host_t *ha) d &= ~PCI_ROM_ADDRESS_ENABLE; pci_write_config_dword(ha->pdev, PCI_ROM_ADDRESS, d); + pci_read_config_word(ha->pdev, PCI_REVISION_ID, &ha->chip_revision); + /* Get PCI bus information. */ spin_lock_irqsave(&ha->hardware_lock, flags); ha->pci_attr = RD_REG_DWORD(®->ctrl_status); @@ -1351,6 +1360,39 @@ qla2x00_configure_hba(scsi_qla_host_t *h return(rval); } +static inline void +qla2x00_set_model_info(scsi_qla_host_t *ha, uint8_t *model, size_t len, char *def) +{ + char *st, *en; + uint16_t index; + + if (memcmp(model, BINZERO, len) != 0) { + strncpy(ha->model_number, model, len); + st = en = ha->model_number; + en += len - 1; + while (en > st) { + if (*en != 0x20 && *en != 0x00) + break; + *en-- = '\0'; + } + + index = (ha->pdev->subsystem_device & 0xff); + if (ha->pdev->subsystem_vendor == PCI_VENDOR_ID_QLOGIC && + index < QLA_MODEL_NAMES) + ha->model_desc = qla2x00_model_name[index * 2 + 1]; + } else { + index = (ha->pdev->subsystem_device & 0xff); + if (ha->pdev->subsystem_vendor == PCI_VENDOR_ID_QLOGIC && + index < QLA_MODEL_NAMES) { + strcpy(ha->model_number, + qla2x00_model_name[index * 2]); + ha->model_desc = qla2x00_model_name[index * 2 + 1]; + } else { + strcpy(ha->model_number, def); + } + } +} + /* * NVRAM configuration for ISP 2xxx * @@ -1367,7 +1409,6 @@ qla2x00_configure_hba(scsi_qla_host_t *h int qla2x00_nvram_config(scsi_qla_host_t *ha) { - int rval; uint8_t chksum = 0; uint16_t cnt; uint8_t *dptr1, *dptr2; @@ -1376,8 +1417,6 @@ qla2x00_nvram_config(scsi_qla_host_t *ha uint8_t *ptr = (uint8_t *)ha->request_ring; struct device_reg_2xxx __iomem *reg = &ha->iobase->isp; - rval = QLA_SUCCESS; - /* Determine NVRAM starting address. */ ha->nvram_size = sizeof(nvram_t); ha->nvram_base = 0; @@ -1401,55 +1440,7 @@ qla2x00_nvram_config(scsi_qla_host_t *ha qla_printk(KERN_WARNING, ha, "Inconsistent NVRAM detected: " "checksum=0x%x id=%c version=0x%x.\n", chksum, nv->id[0], nv->nvram_version); - qla_printk(KERN_WARNING, ha, "Falling back to functioning (yet " - "invalid -- WWPN) defaults.\n"); - - /* - * Set default initialization control block. - */ - memset(nv, 0, ha->nvram_size); - nv->parameter_block_version = ICB_VERSION; - - if (IS_QLA23XX(ha)) { - nv->firmware_options[0] = BIT_2 | BIT_1; - nv->firmware_options[1] = BIT_7 | BIT_5; - nv->add_firmware_options[0] = BIT_5; - nv->add_firmware_options[1] = BIT_5 | BIT_4; - nv->frame_payload_size = __constant_cpu_to_le16(2048); - nv->special_options[1] = BIT_7; - } else if (IS_QLA2200(ha)) { - nv->firmware_options[0] = BIT_2 | BIT_1; - nv->firmware_options[1] = BIT_7 | BIT_5; - nv->add_firmware_options[0] = BIT_5; - nv->add_firmware_options[1] = BIT_5 | BIT_4; - nv->frame_payload_size = __constant_cpu_to_le16(1024); - } else if (IS_QLA2100(ha)) { - nv->firmware_options[0] = BIT_3 | BIT_1; - nv->firmware_options[1] = BIT_5; - nv->frame_payload_size = __constant_cpu_to_le16(1024); - } - - nv->max_iocb_allocation = __constant_cpu_to_le16(256); - nv->execution_throttle = __constant_cpu_to_le16(16); - nv->retry_count = 8; - nv->retry_delay = 1; - - nv->port_name[0] = 33; - nv->port_name[3] = 224; - nv->port_name[4] = 139; - - nv->login_timeout = 4; - - /* - * Set default host adapter parameters - */ - nv->host_p[1] = BIT_2; - nv->reset_delay = 5; - nv->port_down_retry_count = 8; - nv->max_luns_per_target = __constant_cpu_to_le16(8); - nv->link_down_timeout = 60; - - rval = 1; + return QLA_FUNCTION_FAILED; } #if defined(CONFIG_IA64_GENERIC) || defined(CONFIG_IA64_SGI_SN2) @@ -1489,33 +1480,8 @@ #endif strcpy(ha->model_number, "QLA2300"); } } else { - if (rval == 0 && - memcmp(nv->model_number, BINZERO, - sizeof(nv->model_number)) != 0) { - char *st, *en; - - strncpy(ha->model_number, nv->model_number, - sizeof(nv->model_number)); - st = en = ha->model_number; - en += sizeof(nv->model_number) - 1; - while (en > st) { - if (*en != 0x20 && *en != 0x00) - break; - *en-- = '\0'; - } - } else { - uint16_t index; - - index = (ha->pdev->subsystem_device & 0xff); - if (index < QLA_MODEL_NAMES) { - strcpy(ha->model_number, - qla2x00_model_name[index * 2]); - ha->model_desc = - qla2x00_model_name[index * 2 + 1]; - } else { - strcpy(ha->model_number, "QLA23xx"); - } - } + qla2x00_set_model_info(ha, nv->model_number, + sizeof(nv->model_number), "QLA23xx"); } } else if (IS_QLA2200(ha)) { nv->firmware_options[0] |= BIT_2; @@ -1687,11 +1653,7 @@ #endif } } - if (rval) { - DEBUG2_3(printk(KERN_WARNING - "scsi(%ld): NVRAM configuration failed!\n", ha->host_no)); - } - return (rval); + return QLA_SUCCESS; } static void @@ -3107,7 +3069,11 @@ qla2x00_abort_isp(scsi_qla_host_t *ha) } spin_unlock_irqrestore(&ha->hardware_lock, flags); - ha->isp_ops.nvram_config(ha); + ha->isp_ops.get_flash_version(ha, ha->request_ring); + + rval = ha->isp_ops.nvram_config(ha); + if (rval) + goto isp_abort_retry; if (!qla2x00_restart_isp(ha)) { clear_bit(RESET_MARKER_NEEDED, &ha->dpc_flags); @@ -3137,6 +3103,7 @@ qla2x00_abort_isp(scsi_qla_host_t *ha) } } } else { /* failed the ISP abort */ +isp_abort_retry: ha->flags.online = 1; if (test_bit(ISP_ABORT_RETRY, &ha->dpc_flags)) { if (ha->isp_abort_cnt == 0) { @@ -3326,7 +3293,6 @@ qla24xx_reset_adapter(scsi_qla_host_t *h int qla24xx_nvram_config(scsi_qla_host_t *ha) { - int rval; struct init_cb_24xx *icb; struct nvram_24xx *nv; uint32_t *dptr; @@ -3334,7 +3300,6 @@ qla24xx_nvram_config(scsi_qla_host_t *ha uint32_t chksum; uint16_t cnt; - rval = QLA_SUCCESS; icb = (struct init_cb_24xx *)ha->init_cb; nv = (struct nvram_24xx *)ha->request_ring; @@ -3367,51 +3332,7 @@ qla24xx_nvram_config(scsi_qla_host_t *ha qla_printk(KERN_WARNING, ha, "Inconsistent NVRAM detected: " "checksum=0x%x id=%c version=0x%x.\n", chksum, nv->id[0], le16_to_cpu(nv->nvram_version)); - qla_printk(KERN_WARNING, ha, "Falling back to functioning (yet " - "invalid -- WWPN) defaults.\n"); - - /* - * Set default initialization control block. - */ - memset(nv, 0, ha->nvram_size); - nv->nvram_version = __constant_cpu_to_le16(ICB_VERSION); - nv->version = __constant_cpu_to_le16(ICB_VERSION); - nv->frame_payload_size = __constant_cpu_to_le16(2048); - nv->execution_throttle = __constant_cpu_to_le16(0xFFFF); - nv->exchange_count = __constant_cpu_to_le16(0); - nv->hard_address = __constant_cpu_to_le16(124); - nv->port_name[0] = 0x21; - nv->port_name[1] = 0x00 + PCI_FUNC(ha->pdev->devfn); - nv->port_name[2] = 0x00; - nv->port_name[3] = 0xe0; - nv->port_name[4] = 0x8b; - nv->port_name[5] = 0x1c; - nv->port_name[6] = 0x55; - nv->port_name[7] = 0x86; - nv->node_name[0] = 0x20; - nv->node_name[1] = 0x00; - nv->node_name[2] = 0x00; - nv->node_name[3] = 0xe0; - nv->node_name[4] = 0x8b; - nv->node_name[5] = 0x1c; - nv->node_name[6] = 0x55; - nv->node_name[7] = 0x86; - nv->login_retry_count = __constant_cpu_to_le16(8); - nv->interrupt_delay_timer = __constant_cpu_to_le16(0); - nv->login_timeout = __constant_cpu_to_le16(0); - nv->firmware_options_1 = - __constant_cpu_to_le32(BIT_14|BIT_13|BIT_2|BIT_1); - nv->firmware_options_2 = __constant_cpu_to_le32(2 << 4); - nv->firmware_options_2 |= __constant_cpu_to_le32(BIT_12); - nv->firmware_options_3 = __constant_cpu_to_le32(2 << 13); - nv->host_p = __constant_cpu_to_le32(BIT_11|BIT_10); - nv->efi_parameters = __constant_cpu_to_le32(0); - nv->reset_delay = 5; - nv->max_luns_per_target = __constant_cpu_to_le16(128); - nv->port_down_retry_count = __constant_cpu_to_le16(30); - nv->link_down_timeout = __constant_cpu_to_le16(30); - - rval = 1; + return QLA_FUNCTION_FAILED; } /* Reset Initialization control block */ @@ -3438,25 +3359,8 @@ qla24xx_nvram_config(scsi_qla_host_t *ha /* * Setup driver NVRAM options. */ - if (memcmp(nv->model_name, BINZERO, sizeof(nv->model_name)) != 0) { - char *st, *en; - uint16_t index; - - strncpy(ha->model_number, nv->model_name, - sizeof(nv->model_name)); - st = en = ha->model_number; - en += sizeof(nv->model_name) - 1; - while (en > st) { - if (*en != 0x20 && *en != 0x00) - break; - *en-- = '\0'; - } - - index = (ha->pdev->subsystem_device & 0xff); - if (index < QLA_MODEL_NAMES) - ha->model_desc = qla2x00_model_name[index * 2 + 1]; - } else - strcpy(ha->model_number, "QLA2462"); + qla2x00_set_model_info(ha, nv->model_name, sizeof(nv->model_name), + "QLA2462"); /* Use alternate WWN? */ if (nv->host_p & __constant_cpu_to_le32(BIT_15)) { @@ -3575,11 +3479,7 @@ qla24xx_nvram_config(scsi_qla_host_t *ha ha->flags.process_response_queue = 1; } - if (rval) { - DEBUG2_3(printk(KERN_WARNING - "scsi(%ld): NVRAM configuration failed!\n", ha->host_no)); - } - return (rval); + return QLA_SUCCESS; } static int diff --git a/drivers/scsi/qla2xxx/qla_isr.c b/drivers/scsi/qla2xxx/qla_isr.c index 39fd17b..d488561 100644 --- a/drivers/scsi/qla2xxx/qla_isr.c +++ b/drivers/scsi/qla2xxx/qla_isr.c @@ -86,12 +86,8 @@ qla2100_intr_handler(int irq, void *dev_ if (test_bit(MBX_INTR_WAIT, &ha->mbx_cmd_flags) && (status & MBX_INTERRUPT) && ha->flags.mbox_int) { - spin_lock_irqsave(&ha->mbx_reg_lock, flags); - set_bit(MBX_INTERRUPT, &ha->mbx_cmd_flags); up(&ha->mbx_intr_sem); - - spin_unlock_irqrestore(&ha->mbx_reg_lock, flags); } return (IRQ_HANDLED); @@ -199,12 +195,8 @@ qla2300_intr_handler(int irq, void *dev_ if (test_bit(MBX_INTR_WAIT, &ha->mbx_cmd_flags) && (status & MBX_INTERRUPT) && ha->flags.mbox_int) { - spin_lock_irqsave(&ha->mbx_reg_lock, flags); - set_bit(MBX_INTERRUPT, &ha->mbx_cmd_flags); up(&ha->mbx_intr_sem); - - spin_unlock_irqrestore(&ha->mbx_reg_lock, flags); } return (IRQ_HANDLED); @@ -654,10 +646,8 @@ qla2x00_ramp_up_queue_depth(scsi_qla_hos fcport->last_queue_full + ql2xqfullrampup * HZ)) return; - spin_unlock_irq(&ha->hardware_lock); starget_for_each_device(sdev->sdev_target, fcport, qla2x00_adjust_sdev_qdepth_up); - spin_lock_irq(&ha->hardware_lock); } /** @@ -927,10 +917,8 @@ qla2x00_status_entry(scsi_qla_host_t *ha /* Adjust queue depth for all luns on the port. */ fcport->last_queue_full = jiffies; - spin_unlock_irq(&ha->hardware_lock); starget_for_each_device(cp->device->sdev_target, fcport, qla2x00_adjust_sdev_qdepth_down); - spin_lock_irq(&ha->hardware_lock); break; } if (lscsi_status != SS_CHECK_CONDITION) @@ -995,6 +983,22 @@ qla2x00_status_entry(scsi_qla_host_t *ha if (lscsi_status != 0) { cp->result = DID_OK << 16 | lscsi_status; + if (lscsi_status == SAM_STAT_TASK_SET_FULL) { + DEBUG2(printk(KERN_INFO + "scsi(%ld): QUEUE FULL status detected " + "0x%x-0x%x.\n", ha->host_no, comp_status, + scsi_status)); + + /* + * Adjust queue depth for all luns on the + * port. + */ + fcport->last_queue_full = jiffies; + starget_for_each_device( + cp->device->sdev_target, fcport, + qla2x00_adjust_sdev_qdepth_down); + break; + } if (lscsi_status != SS_CHECK_CONDITION) break; @@ -1482,12 +1486,8 @@ qla24xx_intr_handler(int irq, void *dev_ if (test_bit(MBX_INTR_WAIT, &ha->mbx_cmd_flags) && (status & MBX_INTERRUPT) && ha->flags.mbox_int) { - spin_lock_irqsave(&ha->mbx_reg_lock, flags); - set_bit(MBX_INTERRUPT, &ha->mbx_cmd_flags); up(&ha->mbx_intr_sem); - - spin_unlock_irqrestore(&ha->mbx_reg_lock, flags); } return IRQ_HANDLED; @@ -1536,3 +1536,216 @@ qla24xx_ms_entry(scsi_qla_host_t *ha, st qla2x00_sp_compl(ha, sp); } +static irqreturn_t +qla24xx_msix_rsp_q(int irq, void *dev_id) +{ + scsi_qla_host_t *ha; + struct device_reg_24xx __iomem *reg; + unsigned long flags; + + ha = dev_id; + reg = &ha->iobase->isp24; + + spin_lock_irqsave(&ha->hardware_lock, flags); + + qla24xx_process_response_queue(ha); + + WRT_REG_DWORD(®->hccr, HCCRX_CLR_RISC_INT); + RD_REG_DWORD_RELAXED(®->hccr); + + spin_unlock_irqrestore(&ha->hardware_lock, flags); + + return IRQ_HANDLED; +} + +static irqreturn_t +qla24xx_msix_default(int irq, void *dev_id) +{ + scsi_qla_host_t *ha; + struct device_reg_24xx __iomem *reg; + int status; + unsigned long flags; + unsigned long iter; + uint32_t stat; + uint32_t hccr; + uint16_t mb[4]; + + ha = dev_id; + reg = &ha->iobase->isp24; + status = 0; + + spin_lock_irqsave(&ha->hardware_lock, flags); + for (iter = 50; iter--; ) { + stat = RD_REG_DWORD(®->host_status); + if (stat & HSRX_RISC_PAUSED) { + hccr = RD_REG_DWORD(®->hccr); + + qla_printk(KERN_INFO, ha, "RISC paused -- HCCR=%x, " + "Dumping firmware!\n", hccr); + ha->isp_ops.fw_dump(ha, 1); + set_bit(ISP_ABORT_NEEDED, &ha->dpc_flags); + break; + } else if ((stat & HSRX_RISC_INT) == 0) + break; + + switch (stat & 0xff) { + case 0x1: + case 0x2: + case 0x10: + case 0x11: + qla24xx_mbx_completion(ha, MSW(stat)); + status |= MBX_INTERRUPT; + + break; + case 0x12: + mb[0] = MSW(stat); + mb[1] = RD_REG_WORD(®->mailbox1); + mb[2] = RD_REG_WORD(®->mailbox2); + mb[3] = RD_REG_WORD(®->mailbox3); + qla2x00_async_event(ha, mb); + break; + case 0x13: + qla24xx_process_response_queue(ha); + break; + default: + DEBUG2(printk("scsi(%ld): Unrecognized interrupt type " + "(%d).\n", + ha->host_no, stat & 0xff)); + break; + } + WRT_REG_DWORD(®->hccr, HCCRX_CLR_RISC_INT); + RD_REG_DWORD_RELAXED(®->hccr); + } + spin_unlock_irqrestore(&ha->hardware_lock, flags); + + if (test_bit(MBX_INTR_WAIT, &ha->mbx_cmd_flags) && + (status & MBX_INTERRUPT) && ha->flags.mbox_int) { + set_bit(MBX_INTERRUPT, &ha->mbx_cmd_flags); + up(&ha->mbx_intr_sem); + } + + return IRQ_HANDLED; +} + +/* Interrupt handling helpers. */ + +struct qla_init_msix_entry { + uint16_t entry; + uint16_t index; + const char *name; + irqreturn_t (*handler)(int, void *); +}; + +static struct qla_init_msix_entry imsix_entries[QLA_MSIX_ENTRIES] = { + { QLA_MSIX_DEFAULT, QLA_MIDX_DEFAULT, + "qla2xxx (default)", qla24xx_msix_default }, + + { QLA_MSIX_RSP_Q, QLA_MIDX_RSP_Q, + "qla2xxx (rsp_q)", qla24xx_msix_rsp_q }, +}; + +static void +qla24xx_disable_msix(scsi_qla_host_t *ha) +{ + int i; + struct qla_msix_entry *qentry; + + for (i = 0; i < QLA_MSIX_ENTRIES; i++) { + qentry = &ha->msix_entries[imsix_entries[i].index]; + if (qentry->have_irq) + free_irq(qentry->msix_vector, ha); + } + pci_disable_msix(ha->pdev); +} + +static int +qla24xx_enable_msix(scsi_qla_host_t *ha) +{ + int i, ret; + struct msix_entry entries[QLA_MSIX_ENTRIES]; + struct qla_msix_entry *qentry; + + for (i = 0; i < QLA_MSIX_ENTRIES; i++) + entries[i].entry = imsix_entries[i].entry; + + ret = pci_enable_msix(ha->pdev, entries, ARRAY_SIZE(entries)); + if (ret) { + qla_printk(KERN_WARNING, ha, + "MSI-X: Failed to enable support -- %d/%d\n", + QLA_MSIX_ENTRIES, ret); + goto msix_out; + } + ha->flags.msix_enabled = 1; + + for (i = 0; i < QLA_MSIX_ENTRIES; i++) { + qentry = &ha->msix_entries[imsix_entries[i].index]; + qentry->msix_vector = entries[i].vector; + qentry->msix_entry = entries[i].entry; + qentry->have_irq = 0; + ret = request_irq(qentry->msix_vector, + imsix_entries[i].handler, 0, imsix_entries[i].name, ha); + if (ret) { + qla_printk(KERN_WARNING, ha, + "MSI-X: Unable to register handler -- %x/%d.\n", + imsix_entries[i].index, ret); + qla24xx_disable_msix(ha); + goto msix_out; + } + qentry->have_irq = 1; + } + +msix_out: + return ret; +} + +int +qla2x00_request_irqs(scsi_qla_host_t *ha) +{ + int ret; + + /* If possible, enable MSI-X. */ + if (!IS_QLA2432(ha)) + goto skip_msix; + + if (ha->chip_revision < QLA_MSIX_CHIP_REV_24XX || + !QLA_MSIX_FW_MODE_1(ha->fw_attributes)) { + DEBUG2(qla_printk(KERN_WARNING, ha, + "MSI-X: Unsupported ISP2432 (0x%X, 0x%X).\n", + ha->chip_revision, ha->fw_attributes)); + + goto skip_msix; + } + + ret = qla24xx_enable_msix(ha); + if (!ret) { + DEBUG2(qla_printk(KERN_INFO, ha, + "MSI-X: Enabled (0x%X, 0x%X).\n", ha->chip_revision, + ha->fw_attributes)); + return ret; + } + qla_printk(KERN_WARNING, ha, + "MSI-X: Falling back-to INTa mode -- %d.\n", ret); +skip_msix: + ret = request_irq(ha->pdev->irq, ha->isp_ops.intr_handler, + IRQF_DISABLED|IRQF_SHARED, QLA2XXX_DRIVER_NAME, ha); + if (!ret) { + ha->flags.inta_enabled = 1; + ha->host->irq = ha->pdev->irq; + } else { + qla_printk(KERN_WARNING, ha, + "Failed to reserve interrupt %d already in use.\n", + ha->pdev->irq); + } + + return ret; +} + +void +qla2x00_free_irqs(scsi_qla_host_t *ha) +{ + + if (ha->flags.msix_enabled) + qla24xx_disable_msix(ha); + else if (ha->flags.inta_enabled) + free_irq(ha->host->irq, ha); +} diff --git a/drivers/scsi/qla2xxx/qla_mbx.c b/drivers/scsi/qla2xxx/qla_mbx.c index 077e578..83376f6 100644 --- a/drivers/scsi/qla2xxx/qla_mbx.c +++ b/drivers/scsi/qla2xxx/qla_mbx.c @@ -55,7 +55,6 @@ qla2x00_mailbox_command(scsi_qla_host_t uint16_t __iomem *optr; uint32_t cnt; uint32_t mboxes; - unsigned long mbx_flags = 0; unsigned long wait_time; rval = QLA_SUCCESS; @@ -81,10 +80,6 @@ qla2x00_mailbox_command(scsi_qla_host_t /* Save mailbox command for debug */ ha->mcp = mcp; - /* Try to get mailbox register access */ - if (!abort_active) - spin_lock_irqsave(&ha->mbx_reg_lock, mbx_flags); - DEBUG11(printk("scsi(%ld): prepare to issue mbox cmd=0x%x.\n", ha->host_no, mcp->mb[0])); @@ -161,9 +156,6 @@ #endif WRT_REG_WORD(®->isp.hccr, HCCR_SET_HOST_INT); spin_unlock_irqrestore(&ha->hardware_lock, flags); - if (!abort_active) - spin_unlock_irqrestore(&ha->mbx_reg_lock, mbx_flags); - /* Wait for either the timer to expire * or the mbox completion interrupt */ @@ -184,8 +176,6 @@ #endif else WRT_REG_WORD(®->isp.hccr, HCCR_SET_HOST_INT); spin_unlock_irqrestore(&ha->hardware_lock, flags); - if (!abort_active) - spin_unlock_irqrestore(&ha->mbx_reg_lock, mbx_flags); wait_time = jiffies + mcp->tov * HZ; /* wait at most tov secs */ while (!ha->flags.mbox_int) { @@ -201,9 +191,6 @@ #endif } /* while */ } - if (!abort_active) - spin_lock_irqsave(&ha->mbx_reg_lock, mbx_flags); - /* Check whether we timed out */ if (ha->flags.mbox_int) { uint16_t *iptr2; @@ -256,9 +243,6 @@ #endif rval = QLA_FUNCTION_TIMEOUT; } - if (!abort_active) - spin_unlock_irqrestore(&ha->mbx_reg_lock, mbx_flags); - ha->flags.mbox_busy = 0; /* Clean up */ @@ -1713,7 +1697,7 @@ qla24xx_fabric_logout(scsi_qla_host_t *h lg->entry_count = 1; lg->nport_handle = cpu_to_le16(loop_id); lg->control_flags = - __constant_cpu_to_le16(LCF_COMMAND_LOGO|LCF_EXPL_LOGO); + __constant_cpu_to_le16(LCF_COMMAND_LOGO|LCF_IMPL_LOGO); lg->port_id[0] = al_pa; lg->port_id[1] = area; lg->port_id[2] = domain; diff --git a/drivers/scsi/qla2xxx/qla_os.c b/drivers/scsi/qla2xxx/qla_os.c index d6445ae..68f5d24 100644 --- a/drivers/scsi/qla2xxx/qla_os.c +++ b/drivers/scsi/qla2xxx/qla_os.c @@ -1485,6 +1485,7 @@ qla2x00_probe_one(struct pci_dev *pdev, ha->isp_ops.fw_dump = qla2100_fw_dump; ha->isp_ops.read_optrom = qla2x00_read_optrom_data; ha->isp_ops.write_optrom = qla2x00_write_optrom_data; + ha->isp_ops.get_flash_version = qla2x00_get_flash_version; if (IS_QLA2100(ha)) { host->max_id = MAX_TARGETS_2100; ha->mbx_count = MAILBOX_REGISTER_COUNT_2100; @@ -1550,6 +1551,7 @@ qla2x00_probe_one(struct pci_dev *pdev, ha->isp_ops.beacon_on = qla24xx_beacon_on; ha->isp_ops.beacon_off = qla24xx_beacon_off; ha->isp_ops.beacon_blink = qla24xx_beacon_blink; + ha->isp_ops.get_flash_version = qla24xx_get_flash_version; ha->gid_list_info_size = 8; ha->optrom_size = OPTROM_SIZE_24XX; } @@ -1564,14 +1566,6 @@ qla2x00_probe_one(struct pci_dev *pdev, INIT_LIST_HEAD(&ha->list); INIT_LIST_HEAD(&ha->fcports); - /* - * These locks are used to prevent more than one CPU - * from modifying the queue at the same time. The - * higher level "host_lock" will reduce most - * contention for these locks. - */ - spin_lock_init(&ha->mbx_reg_lock); - qla2x00_config_dma_addressing(ha); if (qla2x00_mem_alloc(ha)) { qla_printk(KERN_WARNING, ha, @@ -1615,15 +1609,9 @@ qla2x00_probe_one(struct pci_dev *pdev, host->max_lun = MAX_LUNS; host->transportt = qla2xxx_transport_template; - ret = request_irq(pdev->irq, ha->isp_ops.intr_handler, - IRQF_DISABLED|IRQF_SHARED, QLA2XXX_DRIVER_NAME, ha); - if (ret) { - qla_printk(KERN_WARNING, ha, - "Failed to reserve interrupt %d already in use.\n", - pdev->irq); + ret = qla2x00_request_irqs(ha); + if (ret) goto probe_failed; - } - host->irq = pdev->irq; /* Initialized the timer */ qla2x00_start_timer(ha, qla2x00_timer, WATCH_INTERVAL); @@ -1753,9 +1741,7 @@ qla2x00_free_device(scsi_qla_host_t *ha) qla2x00_mem_free(ha); - /* Detach interrupts */ - if (ha->host->irq) - free_irq(ha->host->irq, ha); + qla2x00_free_irqs(ha); /* release io space registers */ if (ha->iobase) diff --git a/drivers/scsi/qla2xxx/qla_sup.c b/drivers/scsi/qla2xxx/qla_sup.c index 15390ad..ff1dd41 100644 --- a/drivers/scsi/qla2xxx/qla_sup.c +++ b/drivers/scsi/qla2xxx/qla_sup.c @@ -611,7 +611,6 @@ qla24xx_write_flash_data(scsi_qla_host_t flash_conf_to_access_addr(0x0339), (fdata & 0xff00) | ((fdata << 16) & 0xff0000) | ((fdata >> 16) & 0xff)); - fdata = (faddr & sec_mask) << 2; ret = qla24xx_write_flash_dword(ha, conf_addr, (fdata & 0xff00) |((fdata << 16) & 0xff0000) | ((fdata >> 16) & 0xff)); @@ -1383,6 +1382,29 @@ qla2x00_get_flash_manufacturer(scsi_qla_ qla2x00_write_flash_byte(ha, 0x5555, 0xf0); } +static void +qla2x00_read_flash_data(scsi_qla_host_t *ha, uint8_t *tmp_buf, uint32_t saddr, + uint32_t length) +{ + struct device_reg_2xxx __iomem *reg = &ha->iobase->isp; + uint32_t midpoint, ilength; + uint8_t data; + + midpoint = length / 2; + + WRT_REG_WORD(®->nvram, 0); + RD_REG_WORD(®->nvram); + for (ilength = 0; ilength < length; saddr++, ilength++, tmp_buf++) { + if (ilength == midpoint) { + WRT_REG_WORD(®->nvram, NVR_SELECT); + RD_REG_WORD(®->nvram); + } + data = qla2x00_read_flash_byte(ha, saddr); + if (saddr % 100) + udelay(10); + *tmp_buf = data; + } +} static inline void qla2x00_suspend_hba(struct scsi_qla_host *ha) @@ -1722,3 +1744,327 @@ qla24xx_write_optrom_data(struct scsi_ql return rval; } + +/** + * qla2x00_get_fcode_version() - Determine an FCODE image's version. + * @ha: HA context + * @pcids: Pointer to the FCODE PCI data structure + * + * The process of retrieving the FCODE version information is at best + * described as interesting. + * + * Within the first 100h bytes of the image an ASCII string is present + * which contains several pieces of information including the FCODE + * version. Unfortunately it seems the only reliable way to retrieve + * the version is by scanning for another sentinel within the string, + * the FCODE build date: + * + * ... 2.00.02 10/17/02 ... + * + * Returns QLA_SUCCESS on successful retrieval of version. + */ +static void +qla2x00_get_fcode_version(scsi_qla_host_t *ha, uint32_t pcids) +{ + int ret = QLA_FUNCTION_FAILED; + uint32_t istart, iend, iter, vend; + uint8_t do_next, rbyte, *vbyte; + + memset(ha->fcode_revision, 0, sizeof(ha->fcode_revision)); + + /* Skip the PCI data structure. */ + istart = pcids + + ((qla2x00_read_flash_byte(ha, pcids + 0x0B) << 8) | + qla2x00_read_flash_byte(ha, pcids + 0x0A)); + iend = istart + 0x100; + do { + /* Scan for the sentinel date string...eeewww. */ + do_next = 0; + iter = istart; + while ((iter < iend) && !do_next) { + iter++; + if (qla2x00_read_flash_byte(ha, iter) == '/') { + if (qla2x00_read_flash_byte(ha, iter + 2) == + '/') + do_next++; + else if (qla2x00_read_flash_byte(ha, + iter + 3) == '/') + do_next++; + } + } + if (!do_next) + break; + + /* Backtrack to previous ' ' (space). */ + do_next = 0; + while ((iter > istart) && !do_next) { + iter--; + if (qla2x00_read_flash_byte(ha, iter) == ' ') + do_next++; + } + if (!do_next) + break; + + /* + * Mark end of version tag, and find previous ' ' (space) or + * string length (recent FCODE images -- major hack ahead!!!). + */ + vend = iter - 1; + do_next = 0; + while ((iter > istart) && !do_next) { + iter--; + rbyte = qla2x00_read_flash_byte(ha, iter); + if (rbyte == ' ' || rbyte == 0xd || rbyte == 0x10) + do_next++; + } + if (!do_next) + break; + + /* Mark beginning of version tag, and copy data. */ + iter++; + if ((vend - iter) && + ((vend - iter) < sizeof(ha->fcode_revision))) { + vbyte = ha->fcode_revision; + while (iter <= vend) { + *vbyte++ = qla2x00_read_flash_byte(ha, iter); + iter++; + } + ret = QLA_SUCCESS; + } + } while (0); + + if (ret != QLA_SUCCESS) + memset(ha->fcode_revision, 0, sizeof(ha->fcode_revision)); +} + +int +qla2x00_get_flash_version(scsi_qla_host_t *ha, void *mbuf) +{ + int ret = QLA_SUCCESS; + uint8_t code_type, last_image; + uint32_t pcihdr, pcids; + uint8_t *dbyte; + uint16_t *dcode; + + if (!ha->pio_address || !mbuf) + return QLA_FUNCTION_FAILED; + + memset(ha->bios_revision, 0, sizeof(ha->bios_revision)); + memset(ha->efi_revision, 0, sizeof(ha->efi_revision)); + memset(ha->fcode_revision, 0, sizeof(ha->fcode_revision)); + memset(ha->fw_revision, 0, sizeof(ha->fw_revision)); + + qla2x00_flash_enable(ha); + + /* Begin with first PCI expansion ROM header. */ + pcihdr = 0; + last_image = 1; + do { + /* Verify PCI expansion ROM header. */ + if (qla2x00_read_flash_byte(ha, pcihdr) != 0x55 || + qla2x00_read_flash_byte(ha, pcihdr + 0x01) != 0xaa) { + /* No signature */ + DEBUG2(printk("scsi(%ld): No matching ROM " + "signature.\n", ha->host_no)); + ret = QLA_FUNCTION_FAILED; + break; + } + + /* Locate PCI data structure. */ + pcids = pcihdr + + ((qla2x00_read_flash_byte(ha, pcihdr + 0x19) << 8) | + qla2x00_read_flash_byte(ha, pcihdr + 0x18)); + + /* Validate signature of PCI data structure. */ + if (qla2x00_read_flash_byte(ha, pcids) != 'P' || + qla2x00_read_flash_byte(ha, pcids + 0x1) != 'C' || + qla2x00_read_flash_byte(ha, pcids + 0x2) != 'I' || + qla2x00_read_flash_byte(ha, pcids + 0x3) != 'R') { + /* Incorrect header. */ + DEBUG2(printk("%s(): PCI data struct not found " + "pcir_adr=%x.\n", __func__, pcids)); + ret = QLA_FUNCTION_FAILED; + break; + } + + /* Read version */ + code_type = qla2x00_read_flash_byte(ha, pcids + 0x14); + switch (code_type) { + case ROM_CODE_TYPE_BIOS: + /* Intel x86, PC-AT compatible. */ + ha->bios_revision[0] = + qla2x00_read_flash_byte(ha, pcids + 0x12); + ha->bios_revision[1] = + qla2x00_read_flash_byte(ha, pcids + 0x13); + DEBUG3(printk("%s(): read BIOS %d.%d.\n", __func__, + ha->bios_revision[1], ha->bios_revision[0])); + break; + case ROM_CODE_TYPE_FCODE: + /* Open Firmware standard for PCI (FCode). */ + /* Eeeewww... */ + qla2x00_get_fcode_version(ha, pcids); + break; + case ROM_CODE_TYPE_EFI: + /* Extensible Firmware Interface (EFI). */ + ha->efi_revision[0] = + qla2x00_read_flash_byte(ha, pcids + 0x12); + ha->efi_revision[1] = + qla2x00_read_flash_byte(ha, pcids + 0x13); + DEBUG3(printk("%s(): read EFI %d.%d.\n", __func__, + ha->efi_revision[1], ha->efi_revision[0])); + break; + default: + DEBUG2(printk("%s(): Unrecognized code type %x at " + "pcids %x.\n", __func__, code_type, pcids)); + break; + } + + last_image = qla2x00_read_flash_byte(ha, pcids + 0x15) & BIT_7; + + /* Locate next PCI expansion ROM. */ + pcihdr += ((qla2x00_read_flash_byte(ha, pcids + 0x11) << 8) | + qla2x00_read_flash_byte(ha, pcids + 0x10)) * 512; + } while (!last_image); + + if (IS_QLA2322(ha)) { + /* Read firmware image information. */ + memset(ha->fw_revision, 0, sizeof(ha->fw_revision)); + dbyte = mbuf; + memset(dbyte, 0, 8); + dcode = (uint16_t *)dbyte; + + qla2x00_read_flash_data(ha, dbyte, FA_RISC_CODE_ADDR * 4 + 10, + 8); + DEBUG3(printk("%s(%ld): dumping fw ver from flash:\n", + __func__, ha->host_no)); + DEBUG3(qla2x00_dump_buffer((uint8_t *)dbyte, 8)); + + if ((dcode[0] == 0xffff && dcode[1] == 0xffff && + dcode[2] == 0xffff && dcode[3] == 0xffff) || + (dcode[0] == 0 && dcode[1] == 0 && dcode[2] == 0 && + dcode[3] == 0)) { + DEBUG2(printk("%s(): Unrecognized fw revision at " + "%x.\n", __func__, FA_RISC_CODE_ADDR * 4)); + } else { + /* values are in big endian */ + ha->fw_revision[0] = dbyte[0] << 16 | dbyte[1]; + ha->fw_revision[1] = dbyte[2] << 16 | dbyte[3]; + ha->fw_revision[2] = dbyte[4] << 16 | dbyte[5]; + } + } + + qla2x00_flash_disable(ha); + + return ret; +} + +int +qla24xx_get_flash_version(scsi_qla_host_t *ha, void *mbuf) +{ + int ret = QLA_SUCCESS; + uint32_t pcihdr, pcids; + uint32_t *dcode; + uint8_t *bcode; + uint8_t code_type, last_image; + int i; + + if (!mbuf) + return QLA_FUNCTION_FAILED; + + memset(ha->bios_revision, 0, sizeof(ha->bios_revision)); + memset(ha->efi_revision, 0, sizeof(ha->efi_revision)); + memset(ha->fcode_revision, 0, sizeof(ha->fcode_revision)); + memset(ha->fw_revision, 0, sizeof(ha->fw_revision)); + + dcode = mbuf; + + /* Begin with first PCI expansion ROM header. */ + pcihdr = 0; + last_image = 1; + do { + /* Verify PCI expansion ROM header. */ + qla24xx_read_flash_data(ha, dcode, pcihdr >> 2, 0x20); + bcode = mbuf + (pcihdr % 4); + if (bcode[0x0] != 0x55 || bcode[0x1] != 0xaa) { + /* No signature */ + DEBUG2(printk("scsi(%ld): No matching ROM " + "signature.\n", ha->host_no)); + ret = QLA_FUNCTION_FAILED; + break; + } + + /* Locate PCI data structure. */ + pcids = pcihdr + ((bcode[0x19] << 8) | bcode[0x18]); + + qla24xx_read_flash_data(ha, dcode, pcids >> 2, 0x20); + bcode = mbuf + (pcihdr % 4); + + /* Validate signature of PCI data structure. */ + if (bcode[0x0] != 'P' || bcode[0x1] != 'C' || + bcode[0x2] != 'I' || bcode[0x3] != 'R') { + /* Incorrect header. */ + DEBUG2(printk("%s(): PCI data struct not found " + "pcir_adr=%x.\n", __func__, pcids)); + ret = QLA_FUNCTION_FAILED; + break; + } + + /* Read version */ + code_type = bcode[0x14]; + switch (code_type) { + case ROM_CODE_TYPE_BIOS: + /* Intel x86, PC-AT compatible. */ + ha->bios_revision[0] = bcode[0x12]; + ha->bios_revision[1] = bcode[0x13]; + DEBUG3(printk("%s(): read BIOS %d.%d.\n", __func__, + ha->bios_revision[1], ha->bios_revision[0])); + break; + case ROM_CODE_TYPE_FCODE: + /* Open Firmware standard for PCI (FCode). */ + ha->fcode_revision[0] = bcode[0x12]; + ha->fcode_revision[1] = bcode[0x13]; + DEBUG3(printk("%s(): read FCODE %d.%d.\n", __func__, + ha->fcode_revision[1], ha->fcode_revision[0])); + break; + case ROM_CODE_TYPE_EFI: + /* Extensible Firmware Interface (EFI). */ + ha->efi_revision[0] = bcode[0x12]; + ha->efi_revision[1] = bcode[0x13]; + DEBUG3(printk("%s(): read EFI %d.%d.\n", __func__, + ha->efi_revision[1], ha->efi_revision[0])); + break; + default: + DEBUG2(printk("%s(): Unrecognized code type %x at " + "pcids %x.\n", __func__, code_type, pcids)); + break; + } + + last_image = bcode[0x15] & BIT_7; + + /* Locate next PCI expansion ROM. */ + pcihdr += ((bcode[0x11] << 8) | bcode[0x10]) * 512; + } while (!last_image); + + /* Read firmware image information. */ + memset(ha->fw_revision, 0, sizeof(ha->fw_revision)); + dcode = mbuf; + + qla24xx_read_flash_data(ha, dcode, FA_RISC_CODE_ADDR + 4, 4); + for (i = 0; i < 4; i++) + dcode[i] = be32_to_cpu(dcode[i]); + + if ((dcode[0] == 0xffffffff && dcode[1] == 0xffffffff && + dcode[2] == 0xffffffff && dcode[3] == 0xffffffff) || + (dcode[0] == 0 && dcode[1] == 0 && dcode[2] == 0 && + dcode[3] == 0)) { + DEBUG2(printk("%s(): Unrecognized fw version at %x.\n", + __func__, FA_RISC_CODE_ADDR)); + } else { + ha->fw_revision[0] = dcode[0]; + ha->fw_revision[1] = dcode[1]; + ha->fw_revision[2] = dcode[2]; + ha->fw_revision[3] = dcode[3]; + } + + return ret; +} diff --git a/drivers/scsi/qla2xxx/qla_version.h b/drivers/scsi/qla2xxx/qla_version.h index 459e0d6..61347ae 100644 --- a/drivers/scsi/qla2xxx/qla_version.h +++ b/drivers/scsi/qla2xxx/qla_version.h @@ -7,7 +7,7 @@ /* * Driver version */ -#define QLA2XXX_VERSION "8.01.07-k4" +#define QLA2XXX_VERSION "8.01.07-k5" #define QLA_DRIVER_MAJOR_VER 8 #define QLA_DRIVER_MINOR_VER 1 diff --git a/drivers/scsi/qla4xxx/ql4_os.c b/drivers/scsi/qla4xxx/ql4_os.c index 81fb7bd..0bfddf8 100644 --- a/drivers/scsi/qla4xxx/ql4_os.c +++ b/drivers/scsi/qla4xxx/ql4_os.c @@ -1270,7 +1270,7 @@ static int __devinit qla4xxx_probe_adapt INIT_WORK(&ha->dpc_work, qla4xxx_do_dpc); ret = request_irq(pdev->irq, qla4xxx_intr_handler, - SA_INTERRUPT|SA_SHIRQ, "qla4xxx", ha); + IRQF_DISABLED | IRQF_SHARED, "qla4xxx", ha); if (ret) { dev_warn(&ha->pdev->dev, "Failed to reserve interrupt %d" " already in use.\n", pdev->irq); diff --git a/drivers/scsi/scsi.c b/drivers/scsi/scsi.c index 24cffd9..1c89ee3 100644 --- a/drivers/scsi/scsi.c +++ b/drivers/scsi/scsi.c @@ -40,7 +40,6 @@ #include #include #include -#include #include #include #include @@ -673,27 +672,6 @@ void __scsi_done(struct scsi_cmnd *cmd) } /* - * Function: scsi_retry_command - * - * Purpose: Send a command back to the low level to be retried. - * - * Notes: This command is always executed in the context of the - * bottom half handler, or the error handler thread. Low - * level drivers should not become re-entrant as a result of - * this. - */ -int scsi_retry_command(struct scsi_cmnd *cmd) -{ - /* - * Zero the sense information from the last time we tried - * this command. - */ - memset(cmd->sense_buffer, 0, sizeof(cmd->sense_buffer)); - - return scsi_queue_insert(cmd, SCSI_MLQUEUE_EH_RETRY); -} - -/* * Function: scsi_finish_command * * Purpose: Pass command off to upper layer for finishing of I/O diff --git a/drivers/scsi/scsi_debug.c b/drivers/scsi/scsi_debug.c index 30ee3d7..3e2930b 100644 --- a/drivers/scsi/scsi_debug.c +++ b/drivers/scsi/scsi_debug.c @@ -28,7 +28,6 @@ #include #include -#include #include #include #include @@ -51,10 +50,10 @@ #include #include "scsi_logging.h" #include "scsi_debug.h" -#define SCSI_DEBUG_VERSION "1.80" -static const char * scsi_debug_version_date = "20061018"; +#define SCSI_DEBUG_VERSION "1.81" +static const char * scsi_debug_version_date = "20070104"; -/* Additional Sense Code (ASC) used */ +/* Additional Sense Code (ASC) */ #define NO_ADDITIONAL_SENSE 0x0 #define LOGICAL_UNIT_NOT_READY 0x4 #define UNRECOVERED_READ_ERR 0x11 @@ -65,9 +64,13 @@ #define INVALID_FIELD_IN_CDB 0x24 #define INVALID_FIELD_IN_PARAM_LIST 0x26 #define POWERON_RESET 0x29 #define SAVING_PARAMS_UNSUP 0x39 +#define TRANSPORT_PROBLEM 0x4b #define THRESHOLD_EXCEEDED 0x5d #define LOW_POWER_COND_ON 0x5e +/* Additional Sense Code Qualifier (ASCQ) */ +#define ACK_NAK_TO 0x3 + #define SDEBUG_TAGGED_QUEUING 0 /* 0 | MSG_SIMPLE_TAG | MSG_ORDERED_TAG */ /* Default values for driver parameters */ @@ -95,15 +98,20 @@ #define SCSI_DEBUG_OPT_NOISE 1 #define SCSI_DEBUG_OPT_MEDIUM_ERR 2 #define SCSI_DEBUG_OPT_TIMEOUT 4 #define SCSI_DEBUG_OPT_RECOVERED_ERR 8 +#define SCSI_DEBUG_OPT_TRANSPORT_ERR 16 /* When "every_nth" > 0 then modulo "every_nth" commands: * - a no response is simulated if SCSI_DEBUG_OPT_TIMEOUT is set * - a RECOVERED_ERROR is simulated on successful read and write * commands if SCSI_DEBUG_OPT_RECOVERED_ERR is set. + * - a TRANSPORT_ERROR is simulated on successful read and write + * commands if SCSI_DEBUG_OPT_TRANSPORT_ERR is set. * * When "every_nth" < 0 then after "- every_nth" commands: * - a no response is simulated if SCSI_DEBUG_OPT_TIMEOUT is set * - a RECOVERED_ERROR is simulated on successful read and write * commands if SCSI_DEBUG_OPT_RECOVERED_ERR is set. + * - a TRANSPORT_ERROR is simulated on successful read and write + * commands if SCSI_DEBUG_OPT_TRANSPORT_ERR is set. * This will continue until some other action occurs (e.g. the user * writing a new value (other than -1 or 1) to every_nth via sysfs). */ @@ -315,6 +323,7 @@ int scsi_debug_queuecommand(struct scsi_ int target = SCpnt->device->id; struct sdebug_dev_info * devip = NULL; int inj_recovered = 0; + int inj_transport = 0; int delay_override = 0; if (done == NULL) @@ -352,6 +361,8 @@ int scsi_debug_queuecommand(struct scsi_ return 0; /* ignore command causing timeout */ else if (SCSI_DEBUG_OPT_RECOVERED_ERR & scsi_debug_opts) inj_recovered = 1; /* to reads and writes below */ + else if (SCSI_DEBUG_OPT_TRANSPORT_ERR & scsi_debug_opts) + inj_transport = 1; /* to reads and writes below */ } if (devip->wlun) { @@ -468,7 +479,11 @@ int scsi_debug_queuecommand(struct scsi_ mk_sense_buffer(devip, RECOVERED_ERROR, THRESHOLD_EXCEEDED, 0); errsts = check_condition_result; - } + } else if (inj_transport && (0 == errsts)) { + mk_sense_buffer(devip, ABORTED_COMMAND, + TRANSPORT_PROBLEM, ACK_NAK_TO); + errsts = check_condition_result; + } break; case REPORT_LUNS: /* mandatory, ignore unit attention */ delay_override = 1; @@ -531,6 +546,9 @@ int scsi_debug_queuecommand(struct scsi_ delay_override = 1; errsts = check_readiness(SCpnt, 0, devip); break; + case WRITE_BUFFER: + errsts = check_readiness(SCpnt, 1, devip); + break; default: if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts) printk(KERN_INFO "scsi_debug: Opcode: 0x%x not " @@ -954,7 +972,9 @@ static int resp_inquiry(struct scsi_cmnd int alloc_len, n, ret; alloc_len = (cmd[3] << 8) + cmd[4]; - arr = kzalloc(SDEBUG_MAX_INQ_ARR_SZ, GFP_KERNEL); + arr = kzalloc(SDEBUG_MAX_INQ_ARR_SZ, GFP_ATOMIC); + if (! arr) + return DID_REQUEUE << 16; if (devip->wlun) pq_pdt = 0x1e; /* present, wlun */ else if (scsi_debug_no_lun_0 && (0 == devip->lun)) @@ -1217,7 +1237,9 @@ static int resp_report_tgtpgs(struct scs alen = ((cmd[6] << 24) + (cmd[7] << 16) + (cmd[8] << 8) + cmd[9]); - arr = kzalloc(SDEBUG_MAX_TGTPGS_ARR_SZ, GFP_KERNEL); + arr = kzalloc(SDEBUG_MAX_TGTPGS_ARR_SZ, GFP_ATOMIC); + if (! arr) + return DID_REQUEUE << 16; /* * EVPD page 0x88 states we have two ports, one * real and a fake port with no device connected. @@ -1996,6 +2018,8 @@ static int scsi_debug_slave_configure(st if (sdp->host->max_cmd_len != SCSI_DEBUG_MAX_CMD_LEN) sdp->host->max_cmd_len = SCSI_DEBUG_MAX_CMD_LEN; devip = devInfoReg(sdp); + if (NULL == devip) + return 1; /* no resources, will be marked offline */ sdp->hostdata = devip; if (sdp->host->cmd_per_lun) scsi_adjust_queue_depth(sdp, SDEBUG_TAGGED_QUEUING, @@ -2044,7 +2068,7 @@ static struct sdebug_dev_info * devInfoR } } if (NULL == open_devip) { /* try and make a new one */ - open_devip = kzalloc(sizeof(*open_devip),GFP_KERNEL); + open_devip = kzalloc(sizeof(*open_devip),GFP_ATOMIC); if (NULL == open_devip) { printk(KERN_ERR "%s: out of memory at line %d\n", __FUNCTION__, __LINE__); @@ -2388,7 +2412,7 @@ MODULE_PARM_DESC(max_luns, "number of LU MODULE_PARM_DESC(no_lun_0, "no LU number 0 (def=0 -> have lun 0)"); MODULE_PARM_DESC(num_parts, "number of partitions(def=0)"); MODULE_PARM_DESC(num_tgts, "number of targets per host to simulate(def=1)"); -MODULE_PARM_DESC(opts, "1->noise, 2->medium_error, 4->... (def=0)"); +MODULE_PARM_DESC(opts, "1->noise, 2->medium_err, 4->timeout, 8->recovered_err... (def=0)"); MODULE_PARM_DESC(ptype, "SCSI peripheral type(def=0[disk])"); MODULE_PARM_DESC(scsi_level, "SCSI level to simulate(def=5[SPC-3])"); MODULE_PARM_DESC(virtual_gb, "virtual gigabyte size (def=0 -> use dev_size_mb)"); @@ -2943,7 +2967,6 @@ static int sdebug_add_adapter(void) struct list_head *lh, *lh_sf; sdbg_host = kzalloc(sizeof(*sdbg_host),GFP_KERNEL); - if (NULL == sdbg_host) { printk(KERN_ERR "%s: out of memory at line %d\n", __FUNCTION__, __LINE__); diff --git a/drivers/scsi/scsi_error.c b/drivers/scsi/scsi_error.c index 2ecb6ff..b8edcf5 100644 --- a/drivers/scsi/scsi_error.c +++ b/drivers/scsi/scsi_error.c @@ -359,6 +359,11 @@ static int scsi_check_sense(struct scsi_ return SUCCESS; case MEDIUM_ERROR: + if (sshdr.asc == 0x11 || /* UNRECOVERED READ ERR */ + sshdr.asc == 0x13 || /* AMNF DATA FIELD */ + sshdr.asc == 0x14) { /* RECORD NOT FOUND */ + return SUCCESS; + } return NEEDS_RETRY; case HARDWARE_ERROR: @@ -453,6 +458,128 @@ static void scsi_eh_done(struct scsi_cmn } /** + * scsi_try_host_reset - ask host adapter to reset itself + * @scmd: SCSI cmd to send hsot reset. + **/ +static int scsi_try_host_reset(struct scsi_cmnd *scmd) +{ + unsigned long flags; + int rtn; + + SCSI_LOG_ERROR_RECOVERY(3, printk("%s: Snd Host RST\n", + __FUNCTION__)); + + if (!scmd->device->host->hostt->eh_host_reset_handler) + return FAILED; + + rtn = scmd->device->host->hostt->eh_host_reset_handler(scmd); + + if (rtn == SUCCESS) { + if (!scmd->device->host->hostt->skip_settle_delay) + ssleep(HOST_RESET_SETTLE_TIME); + spin_lock_irqsave(scmd->device->host->host_lock, flags); + scsi_report_bus_reset(scmd->device->host, + scmd_channel(scmd)); + spin_unlock_irqrestore(scmd->device->host->host_lock, flags); + } + + return rtn; +} + +/** + * scsi_try_bus_reset - ask host to perform a bus reset + * @scmd: SCSI cmd to send bus reset. + **/ +static int scsi_try_bus_reset(struct scsi_cmnd *scmd) +{ + unsigned long flags; + int rtn; + + SCSI_LOG_ERROR_RECOVERY(3, printk("%s: Snd Bus RST\n", + __FUNCTION__)); + + if (!scmd->device->host->hostt->eh_bus_reset_handler) + return FAILED; + + rtn = scmd->device->host->hostt->eh_bus_reset_handler(scmd); + + if (rtn == SUCCESS) { + if (!scmd->device->host->hostt->skip_settle_delay) + ssleep(BUS_RESET_SETTLE_TIME); + spin_lock_irqsave(scmd->device->host->host_lock, flags); + scsi_report_bus_reset(scmd->device->host, + scmd_channel(scmd)); + spin_unlock_irqrestore(scmd->device->host->host_lock, flags); + } + + return rtn; +} + +/** + * scsi_try_bus_device_reset - Ask host to perform a BDR on a dev + * @scmd: SCSI cmd used to send BDR + * + * Notes: + * There is no timeout for this operation. if this operation is + * unreliable for a given host, then the host itself needs to put a + * timer on it, and set the host back to a consistent state prior to + * returning. + **/ +static int scsi_try_bus_device_reset(struct scsi_cmnd *scmd) +{ + int rtn; + + if (!scmd->device->host->hostt->eh_device_reset_handler) + return FAILED; + + rtn = scmd->device->host->hostt->eh_device_reset_handler(scmd); + if (rtn == SUCCESS) { + scmd->device->was_reset = 1; + scmd->device->expecting_cc_ua = 1; + } + + return rtn; +} + +static int __scsi_try_to_abort_cmd(struct scsi_cmnd *scmd) +{ + if (!scmd->device->host->hostt->eh_abort_handler) + return FAILED; + + return scmd->device->host->hostt->eh_abort_handler(scmd); +} + +/** + * scsi_try_to_abort_cmd - Ask host to abort a running command. + * @scmd: SCSI cmd to abort from Lower Level. + * + * Notes: + * This function will not return until the user's completion function + * has been called. there is no timeout on this operation. if the + * author of the low-level driver wishes this operation to be timed, + * they can provide this facility themselves. helper functions in + * scsi_error.c can be supplied to make this easier to do. + **/ +static int scsi_try_to_abort_cmd(struct scsi_cmnd *scmd) +{ + /* + * scsi_done was called just after the command timed out and before + * we had a chance to process it. (db) + */ + if (scmd->serial_number == 0) + return SUCCESS; + return __scsi_try_to_abort_cmd(scmd); +} + +static void scsi_abort_eh_cmnd(struct scsi_cmnd *scmd) +{ + if (__scsi_try_to_abort_cmd(scmd) != SUCCESS) + if (scsi_try_bus_device_reset(scmd) != SUCCESS) + if (scsi_try_bus_reset(scmd) != SUCCESS) + scsi_try_host_reset(scmd); +} + +/** * scsi_send_eh_cmnd - submit a scsi command as part of error recory * @scmd: SCSI command structure to hijack * @cmnd: CDB to send @@ -579,13 +706,7 @@ static int scsi_send_eh_cmnd(struct scsi break; } } else { - /* - * FIXME(eric) - we are not tracking whether we could - * abort a timed out command or not. not sure how - * we should treat them differently anyways. - */ - if (shost->hostt->eh_abort_handler) - shost->hostt->eh_abort_handler(scmd); + scsi_abort_eh_cmnd(scmd); rtn = FAILED; } @@ -672,8 +793,8 @@ EXPORT_SYMBOL(scsi_eh_finish_cmd); * XXX: Long term this code should go away, but that needs an audit of * all LLDDs first. **/ -static int scsi_eh_get_sense(struct list_head *work_q, - struct list_head *done_q) +int scsi_eh_get_sense(struct list_head *work_q, + struct list_head *done_q) { struct scsi_cmnd *scmd, *next; int rtn; @@ -715,31 +836,7 @@ static int scsi_eh_get_sense(struct list return list_empty(work_q); } - -/** - * scsi_try_to_abort_cmd - Ask host to abort a running command. - * @scmd: SCSI cmd to abort from Lower Level. - * - * Notes: - * This function will not return until the user's completion function - * has been called. there is no timeout on this operation. if the - * author of the low-level driver wishes this operation to be timed, - * they can provide this facility themselves. helper functions in - * scsi_error.c can be supplied to make this easier to do. - **/ -static int scsi_try_to_abort_cmd(struct scsi_cmnd *scmd) -{ - if (!scmd->device->host->hostt->eh_abort_handler) - return FAILED; - - /* - * scsi_done was called just after the command timed out and before - * we had a chance to process it. (db) - */ - if (scmd->serial_number == 0) - return SUCCESS; - return scmd->device->host->hostt->eh_abort_handler(scmd); -} +EXPORT_SYMBOL_GPL(scsi_eh_get_sense); /** * scsi_eh_tur - Send TUR to device. @@ -815,32 +912,6 @@ static int scsi_eh_abort_cmds(struct lis } /** - * scsi_try_bus_device_reset - Ask host to perform a BDR on a dev - * @scmd: SCSI cmd used to send BDR - * - * Notes: - * There is no timeout for this operation. if this operation is - * unreliable for a given host, then the host itself needs to put a - * timer on it, and set the host back to a consistent state prior to - * returning. - **/ -static int scsi_try_bus_device_reset(struct scsi_cmnd *scmd) -{ - int rtn; - - if (!scmd->device->host->hostt->eh_device_reset_handler) - return FAILED; - - rtn = scmd->device->host->hostt->eh_device_reset_handler(scmd); - if (rtn == SUCCESS) { - scmd->device->was_reset = 1; - scmd->device->expecting_cc_ua = 1; - } - - return rtn; -} - -/** * scsi_eh_try_stu - Send START_UNIT to device. * @scmd: Scsi cmd to send START_UNIT * @@ -971,64 +1042,6 @@ static int scsi_eh_bus_device_reset(stru } /** - * scsi_try_bus_reset - ask host to perform a bus reset - * @scmd: SCSI cmd to send bus reset. - **/ -static int scsi_try_bus_reset(struct scsi_cmnd *scmd) -{ - unsigned long flags; - int rtn; - - SCSI_LOG_ERROR_RECOVERY(3, printk("%s: Snd Bus RST\n", - __FUNCTION__)); - - if (!scmd->device->host->hostt->eh_bus_reset_handler) - return FAILED; - - rtn = scmd->device->host->hostt->eh_bus_reset_handler(scmd); - - if (rtn == SUCCESS) { - if (!scmd->device->host->hostt->skip_settle_delay) - ssleep(BUS_RESET_SETTLE_TIME); - spin_lock_irqsave(scmd->device->host->host_lock, flags); - scsi_report_bus_reset(scmd->device->host, - scmd_channel(scmd)); - spin_unlock_irqrestore(scmd->device->host->host_lock, flags); - } - - return rtn; -} - -/** - * scsi_try_host_reset - ask host adapter to reset itself - * @scmd: SCSI cmd to send hsot reset. - **/ -static int scsi_try_host_reset(struct scsi_cmnd *scmd) -{ - unsigned long flags; - int rtn; - - SCSI_LOG_ERROR_RECOVERY(3, printk("%s: Snd Host RST\n", - __FUNCTION__)); - - if (!scmd->device->host->hostt->eh_host_reset_handler) - return FAILED; - - rtn = scmd->device->host->hostt->eh_host_reset_handler(scmd); - - if (rtn == SUCCESS) { - if (!scmd->device->host->hostt->skip_settle_delay) - ssleep(HOST_RESET_SETTLE_TIME); - spin_lock_irqsave(scmd->device->host->host_lock, flags); - scsi_report_bus_reset(scmd->device->host, - scmd_channel(scmd)); - spin_unlock_irqrestore(scmd->device->host->host_lock, flags); - } - - return rtn; -} - -/** * scsi_eh_bus_reset - send a bus reset * @shost: scsi host being recovered. * @eh_done_q: list_head for processed commands. @@ -1411,9 +1424,9 @@ static void scsi_restart_operations(stru * @eh_done_q: list_head for processed commands. * **/ -static void scsi_eh_ready_devs(struct Scsi_Host *shost, - struct list_head *work_q, - struct list_head *done_q) +void scsi_eh_ready_devs(struct Scsi_Host *shost, + struct list_head *work_q, + struct list_head *done_q) { if (!scsi_eh_stu(shost, work_q, done_q)) if (!scsi_eh_bus_device_reset(shost, work_q, done_q)) @@ -1421,6 +1434,7 @@ static void scsi_eh_ready_devs(struct Sc if (!scsi_eh_host_reset(work_q, done_q)) scsi_eh_offline_sdevs(work_q, done_q); } +EXPORT_SYMBOL_GPL(scsi_eh_ready_devs); /** * scsi_eh_flush_done_q - finish processed commands or retry them. diff --git a/drivers/scsi/scsi_lib.c b/drivers/scsi/scsi_lib.c index f02f48a..9f7482d 100644 --- a/drivers/scsi/scsi_lib.c +++ b/drivers/scsi/scsi_lib.c @@ -388,10 +388,9 @@ int scsi_execute_async(struct scsi_devic int err = 0; int write = (data_direction == DMA_TO_DEVICE); - sioc = kmem_cache_alloc(scsi_io_context_cache, gfp); + sioc = kmem_cache_zalloc(scsi_io_context_cache, gfp); if (!sioc) return DRIVER_ERROR << 24; - memset(sioc, 0, sizeof(*sioc)); req = blk_get_request(sdev->request_queue, write, gfp); if (!req) @@ -1400,7 +1399,7 @@ static void scsi_softirq_done(struct req scsi_finish_command(cmd); break; case NEEDS_RETRY: - scsi_retry_command(cmd); + scsi_queue_insert(cmd, SCSI_MLQUEUE_EH_RETRY); break; case ADD_TO_MLQUEUE: scsi_queue_insert(cmd, SCSI_MLQUEUE_DEVICE_BUSY); @@ -2250,6 +2249,8 @@ void *scsi_kmap_atomic_sg(struct scatter size_t sg_len = 0, len_complete = 0; struct page *page; + WARN_ON(!irqs_disabled()); + for (i = 0; i < sg_count; i++) { len_complete = sg_len; /* Complete sg-entries */ sg_len += sg[i].length; diff --git a/drivers/scsi/scsi_priv.h b/drivers/scsi/scsi_priv.h index f458c2f..ee8efe8 100644 --- a/drivers/scsi/scsi_priv.h +++ b/drivers/scsi/scsi_priv.h @@ -28,7 +28,6 @@ extern int scsi_dispatch_cmd(struct scsi extern int scsi_setup_command_freelist(struct Scsi_Host *shost); extern void scsi_destroy_command_freelist(struct Scsi_Host *shost); extern void __scsi_done(struct scsi_cmnd *cmd); -extern int scsi_retry_command(struct scsi_cmnd *cmd); #ifdef CONFIG_SCSI_LOGGING void scsi_log_send(struct scsi_cmnd *cmd); void scsi_log_completion(struct scsi_cmnd *cmd, int disposition); @@ -58,6 +57,11 @@ extern int scsi_error_handler(void *host extern int scsi_decide_disposition(struct scsi_cmnd *cmd); extern void scsi_eh_wakeup(struct Scsi_Host *shost); extern int scsi_eh_scmd_add(struct scsi_cmnd *, int); +void scsi_eh_ready_devs(struct Scsi_Host *shost, + struct list_head *work_q, + struct list_head *done_q); +int scsi_eh_get_sense(struct list_head *work_q, + struct list_head *done_q); /* scsi_lib.c */ extern int scsi_maybe_unblock_host(struct scsi_device *sdev); diff --git a/drivers/scsi/scsi_proc.c b/drivers/scsi/scsi_proc.c index 524a5f7..69d6e9b 100644 --- a/drivers/scsi/scsi_proc.c +++ b/drivers/scsi/scsi_proc.c @@ -308,7 +308,7 @@ static int proc_scsi_open(struct inode * return single_open(file, proc_scsi_show, NULL); } -static struct file_operations proc_scsi_operations = { +static const struct file_operations proc_scsi_operations = { .open = proc_scsi_open, .read = seq_read, .write = proc_scsi_write, diff --git a/drivers/scsi/scsi_scan.c b/drivers/scsi/scsi_scan.c index 96b7cbd..a43b9ec 100644 --- a/drivers/scsi/scsi_scan.c +++ b/drivers/scsi/scsi_scan.c @@ -1029,7 +1029,7 @@ static int scsi_probe_and_add_lun(struct sdev_printk(KERN_INFO, sdev, "scsi scan: consider passing scsi_mod." - "dev_flags=%s:%s:0x240 or 0x800240\n", + "dev_flags=%s:%s:0x240 or 0x1000240\n", scsi_inq_str(vend, result, 8, 16), scsi_inq_str(mod, result, 16, 32)); }); diff --git a/drivers/scsi/scsi_sysctl.c b/drivers/scsi/scsi_sysctl.c index 04d06c2..6cfaaa2 100644 --- a/drivers/scsi/scsi_sysctl.c +++ b/drivers/scsi/scsi_sysctl.c @@ -41,7 +41,7 @@ static struct ctl_table_header *scsi_tab int __init scsi_init_sysctl(void) { - scsi_table_header = register_sysctl_table(scsi_root_table, 1); + scsi_table_header = register_sysctl_table(scsi_root_table); if (!scsi_table_header) return -ENOMEM; return 0; diff --git a/drivers/scsi/scsi_tgt_if.c b/drivers/scsi/scsi_tgt_if.c index 37bbfbd..f2344ab 100644 --- a/drivers/scsi/scsi_tgt_if.c +++ b/drivers/scsi/scsi_tgt_if.c @@ -280,7 +280,7 @@ static int tgt_open(struct inode *inode, return 0; } -static struct file_operations tgt_fops = { +static const struct file_operations tgt_fops = { .owner = THIS_MODULE, .open = tgt_open, .poll = tgt_poll, diff --git a/drivers/scsi/scsi_transport_fc.c b/drivers/scsi/scsi_transport_fc.c index 3571ce8..0d3c10f 100644 --- a/drivers/scsi/scsi_transport_fc.c +++ b/drivers/scsi/scsi_transport_fc.c @@ -26,7 +26,6 @@ */ #include #include -#include /* workqueue stuff, HZ */ #include #include #include diff --git a/drivers/scsi/scsi_transport_sas.c b/drivers/scsi/scsi_transport_sas.c index 5c0b75b..6d39150 100644 --- a/drivers/scsi/scsi_transport_sas.c +++ b/drivers/scsi/scsi_transport_sas.c @@ -336,6 +336,51 @@ show_sas_device_type(struct class_device } static CLASS_DEVICE_ATTR(device_type, S_IRUGO, show_sas_device_type, NULL); +static ssize_t do_sas_phy_enable(struct class_device *cdev, + size_t count, int enable) +{ + struct sas_phy *phy = transport_class_to_phy(cdev); + struct Scsi_Host *shost = dev_to_shost(phy->dev.parent); + struct sas_internal *i = to_sas_internal(shost->transportt); + int error; + + error = i->f->phy_enable(phy, enable); + if (error) + return error; + phy->enabled = enable; + return count; +}; + +static ssize_t store_sas_phy_enable(struct class_device *cdev, + const char *buf, size_t count) +{ + if (count < 1) + return -EINVAL; + + switch (buf[0]) { + case '0': + do_sas_phy_enable(cdev, count, 0); + break; + case '1': + do_sas_phy_enable(cdev, count, 1); + break; + default: + return -EINVAL; + } + + return count; +} + +static ssize_t show_sas_phy_enable(struct class_device *cdev, char *buf) +{ + struct sas_phy *phy = transport_class_to_phy(cdev); + + return snprintf(buf, 20, "%d", phy->enabled); +} + +static CLASS_DEVICE_ATTR(enable, S_IRUGO | S_IWUSR, show_sas_phy_enable, + store_sas_phy_enable); + static ssize_t do_sas_phy_reset(struct class_device *cdev, size_t count, int hard_reset) { @@ -435,6 +480,7 @@ struct sas_phy *sas_phy_alloc(struct dev return NULL; phy->number = number; + phy->enabled = 1; device_initialize(&phy->dev); phy->dev.parent = get_device(parent); @@ -579,8 +625,19 @@ static void sas_port_release(struct devi static void sas_port_create_link(struct sas_port *port, struct sas_phy *phy) { - sysfs_create_link(&port->dev.kobj, &phy->dev.kobj, phy->dev.bus_id); - sysfs_create_link(&phy->dev.kobj, &port->dev.kobj, "port"); + int res; + + res = sysfs_create_link(&port->dev.kobj, &phy->dev.kobj, + phy->dev.bus_id); + if (res) + goto err; + res = sysfs_create_link(&phy->dev.kobj, &port->dev.kobj, "port"); + if (res) + goto err; + return; +err: + printk(KERN_ERR "%s: Cannot create port links, err=%d\n", + __FUNCTION__, res); } static void sas_port_delete_link(struct sas_port *port, @@ -818,13 +875,20 @@ EXPORT_SYMBOL(sas_port_delete_phy); void sas_port_mark_backlink(struct sas_port *port) { + int res; struct device *parent = port->dev.parent->parent->parent; if (port->is_backlink) return; port->is_backlink = 1; - sysfs_create_link(&port->dev.kobj, &parent->kobj, - parent->bus_id); + res = sysfs_create_link(&port->dev.kobj, &parent->kobj, + parent->bus_id); + if (res) + goto err; + return; +err: + printk(KERN_ERR "%s: Cannot create port backlink, err=%d\n", + __FUNCTION__, res); } EXPORT_SYMBOL(sas_port_mark_backlink); @@ -1237,7 +1301,7 @@ int sas_rphy_add(struct sas_rphy *rphy) if (identify->device_type == SAS_END_DEVICE && rphy->scsi_target_id != -1) { scsi_scan_target(&rphy->dev, 0, - rphy->scsi_target_id, ~0, 0); + rphy->scsi_target_id, SCAN_WILD_CARD, 0); } return 0; @@ -1253,7 +1317,7 @@ EXPORT_SYMBOL(sas_rphy_add); * Note: * This function must only be called on a remote * PHY that has not sucessfully been added using - * sas_rphy_add(). + * sas_rphy_add() (or has been sas_rphy_remove()'d) */ void sas_rphy_free(struct sas_rphy *rphy) { @@ -1272,18 +1336,30 @@ void sas_rphy_free(struct sas_rphy *rphy EXPORT_SYMBOL(sas_rphy_free); /** - * sas_rphy_delete -- remove SAS remote PHY - * @rphy: SAS remote PHY to remove + * sas_rphy_delete -- remove and free SAS remote PHY + * @rphy: SAS remote PHY to remove and free * - * Removes the specified SAS remote PHY. + * Removes the specified SAS remote PHY and frees it. */ void sas_rphy_delete(struct sas_rphy *rphy) { + sas_rphy_remove(rphy); + sas_rphy_free(rphy); +} +EXPORT_SYMBOL(sas_rphy_delete); + +/** + * sas_rphy_remove -- remove SAS remote PHY + * @rphy: SAS remote phy to remove + * + * Removes the specified SAS remote PHY. + */ +void +sas_rphy_remove(struct sas_rphy *rphy) +{ struct device *dev = &rphy->dev; struct sas_port *parent = dev_to_sas_port(dev->parent); - struct Scsi_Host *shost = dev_to_shost(parent->dev.parent); - struct sas_host_attrs *sas_host = to_sas_host_attrs(shost); switch (rphy->identify.device_type) { case SAS_END_DEVICE: @@ -1299,17 +1375,10 @@ sas_rphy_delete(struct sas_rphy *rphy) transport_remove_device(dev); device_del(dev); - transport_destroy_device(dev); - - mutex_lock(&sas_host->lock); - list_del(&rphy->list); - mutex_unlock(&sas_host->lock); parent->rphy = NULL; - - put_device(dev); } -EXPORT_SYMBOL(sas_rphy_delete); +EXPORT_SYMBOL(sas_rphy_remove); /** * scsi_is_sas_rphy -- check if a struct device represents a SAS remote PHY @@ -1389,6 +1458,10 @@ #define SETUP_PHY_ATTRIBUTE_RW(field) SETUP_TEMPLATE_RW(phy_attrs, field, S_IRUGO | S_IWUSR, 1, \ !i->f->set_phy_speed, S_IRUGO) +#define SETUP_OPTIONAL_PHY_ATTRIBUTE_RW(field, func) \ + SETUP_TEMPLATE_RW(phy_attrs, field, S_IRUGO | S_IWUSR, 1, \ + !i->f->func, S_IRUGO) + #define SETUP_PORT_ATTRIBUTE(field) \ SETUP_TEMPLATE(port_attrs, field, S_IRUGO, 1) @@ -1396,10 +1469,10 @@ #define SETUP_OPTIONAL_PHY_ATTRIBUTE(fie SETUP_TEMPLATE(phy_attrs, field, S_IRUGO, i->f->func) #define SETUP_PHY_ATTRIBUTE_WRONLY(field) \ - SETUP_TEMPLATE(phy_attrs, field, S_IWUGO, 1) + SETUP_TEMPLATE(phy_attrs, field, S_IWUSR, 1) #define SETUP_OPTIONAL_PHY_ATTRIBUTE_WRONLY(field, func) \ - SETUP_TEMPLATE(phy_attrs, field, S_IWUGO, i->f->func) + SETUP_TEMPLATE(phy_attrs, field, S_IWUSR, i->f->func) #define SETUP_END_DEV_ATTRIBUTE(field) \ SETUP_TEMPLATE(end_dev_attrs, field, S_IRUGO, 1) @@ -1479,6 +1552,7 @@ sas_attach_transport(struct sas_function SETUP_PHY_ATTRIBUTE(phy_reset_problem_count); SETUP_OPTIONAL_PHY_ATTRIBUTE_WRONLY(link_reset, phy_reset); SETUP_OPTIONAL_PHY_ATTRIBUTE_WRONLY(hard_reset, phy_reset); + SETUP_OPTIONAL_PHY_ATTRIBUTE_RW(enable, phy_enable); i->phy_attrs[count] = NULL; count = 0; @@ -1587,7 +1661,7 @@ static void __exit sas_transport_exit(vo } MODULE_AUTHOR("Christoph Hellwig"); -MODULE_DESCRIPTION("SAS Transphy Attributes"); +MODULE_DESCRIPTION("SAS Transport Attributes"); MODULE_LICENSE("GPL"); module_init(sas_transport_init); diff --git a/drivers/scsi/scsi_transport_spi.c b/drivers/scsi/scsi_transport_spi.c index 014d7fe..6f56f87 100644 --- a/drivers/scsi/scsi_transport_spi.c +++ b/drivers/scsi/scsi_transport_spi.c @@ -46,7 +46,6 @@ #define DV_RETRIES 3 /* should only need * two cc/ua clears */ /* Private data accessors (keep these out of the header file) */ -#define spi_dv_pending(x) (((struct spi_transport_attrs *)&(x)->starget_data)->dv_pending) #define spi_dv_in_progress(x) (((struct spi_transport_attrs *)&(x)->starget_data)->dv_in_progress) #define spi_dv_mutex(x) (((struct spi_transport_attrs *)&(x)->starget_data)->dv_mutex) diff --git a/drivers/scsi/sd.c b/drivers/scsi/sd.c index b781a90..3f048bd 100644 --- a/drivers/scsi/sd.c +++ b/drivers/scsi/sd.c @@ -35,7 +35,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/scsi/sim710.c b/drivers/scsi/sim710.c index 551bacc..018c65f 100644 --- a/drivers/scsi/sim710.c +++ b/drivers/scsi/sim710.c @@ -123,6 +123,7 @@ sim710_probe_common(struct device *dev, hostdata->differential = differential; hostdata->clock = clock; hostdata->chip710 = 1; + hostdata->burst_length = 8; /* and register the chip */ if((host = NCR_700_detect(&sim710_driver_template, hostdata, dev)) diff --git a/drivers/scsi/sni_53c710.c b/drivers/scsi/sni_53c710.c new file mode 100644 index 0000000..6bc5051 --- /dev/null +++ b/drivers/scsi/sni_53c710.c @@ -0,0 +1,159 @@ +/* -*- mode: c; c-basic-offset: 8 -*- */ + +/* SNI RM driver + * + * Copyright (C) 2001 by James.Bottomley@HansenPartnership.com +**----------------------------------------------------------------------------- +** +** This program is free software; you can redistribute it and/or modify +** it under the terms of the GNU General Public License as published by +** the Free Software Foundation; either version 2 of the License, or +** (at your option) any later version. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +** GNU General Public License for more details. +** +** You should have received a copy of the GNU General Public License +** along with this program; if not, write to the Free Software +** Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +** +**----------------------------------------------------------------------------- + */ + +/* + * Based on lasi700.c + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include +#include +#include +#include + +#include "53c700.h" + +MODULE_AUTHOR("Thomas Bogendörfer"); +MODULE_DESCRIPTION("SNI RM 53c710 SCSI Driver"); +MODULE_LICENSE("GPL"); + +#define SNIRM710_CLOCK 32 + +static struct scsi_host_template snirm710_template = { + .name = "SNI RM SCSI 53c710", + .proc_name = "snirm_53c710", + .this_id = 7, + .module = THIS_MODULE, +}; + +static int __init snirm710_probe(struct platform_device *dev) +{ + unsigned long base; + struct NCR_700_Host_Parameters *hostdata; + struct Scsi_Host *host; + struct resource *res; + + res = platform_get_resource(dev, IORESOURCE_MEM, 0); + if (!res) + return -ENODEV; + + base = res->start; + hostdata = kzalloc(sizeof(*hostdata), GFP_KERNEL); + if (!hostdata) { + printk(KERN_ERR "%s: Failed to allocate host data\n", + dev->dev.bus_id); + return -ENOMEM; + } + + hostdata->dev = &dev->dev; + dma_set_mask(&dev->dev, DMA_32BIT_MASK); + hostdata->base = ioremap_nocache(CPHYSADDR(base), 0x100); + hostdata->differential = 0; + + hostdata->clock = SNIRM710_CLOCK; + hostdata->force_le_on_be = 1; + hostdata->chip710 = 1; + hostdata->burst_length = 4; + + host = NCR_700_detect(&snirm710_template, hostdata, &dev->dev); + if (!host) + goto out_kfree; + host->this_id = 7; + host->base = base; + host->irq = platform_get_irq(dev, 0); + if(request_irq(host->irq, NCR_700_intr, SA_SHIRQ, "snirm710", host)) { + printk(KERN_ERR "snirm710: request_irq failed!\n"); + goto out_put_host; + } + + dev_set_drvdata(&dev->dev, host); + scsi_scan_host(host); + + return 0; + + out_put_host: + scsi_host_put(host); + out_kfree: + iounmap(hostdata->base); + kfree(hostdata); + return -ENODEV; +} + +static int __exit snirm710_driver_remove(struct platform_device *dev) +{ + struct Scsi_Host *host = dev_get_drvdata(&dev->dev); + struct NCR_700_Host_Parameters *hostdata = + (struct NCR_700_Host_Parameters *)host->hostdata[0]; + + scsi_remove_host(host); + NCR_700_release(host); + free_irq(host->irq, host); + iounmap(hostdata->base); + kfree(hostdata); + + return 0; +} + +static struct platform_driver snirm710_driver = { + .probe = snirm710_probe, + .remove = __devexit_p(snirm710_driver_remove), + .driver = { + .name = "snirm_53c710", + }, +}; + +static int __init snirm710_init(void) +{ + int err; + + if ((err = platform_driver_register(&snirm710_driver))) { + printk(KERN_ERR "Driver registration failed\n"); + return err; + } + return 0; +} + +static void __exit snirm710_exit(void) +{ + platform_driver_unregister(&snirm710_driver); +} + +module_init(snirm710_init); +module_exit(snirm710_exit); diff --git a/drivers/scsi/sr.c b/drivers/scsi/sr.c index 89e9b36..1857d68 100644 --- a/drivers/scsi/sr.c +++ b/drivers/scsi/sr.c @@ -35,7 +35,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/scsi/sr_ioctl.c b/drivers/scsi/sr_ioctl.c index 0578ba4..e1589f9 100644 --- a/drivers/scsi/sr_ioctl.c +++ b/drivers/scsi/sr_ioctl.c @@ -1,5 +1,4 @@ #include -#include #include #include #include diff --git a/drivers/scsi/st.c b/drivers/scsi/st.c index 488ec79..3d2e023 100644 --- a/drivers/scsi/st.c +++ b/drivers/scsi/st.c @@ -9,7 +9,7 @@ Steve Hirsch, Andreas Koppenh"ofer, Michael Leodolter, Eyal Lebedinsky, Michael Schaefer, J"org Weule, and Eric Youngdale. - Copyright 1992 - 2006 Kai Makisara + Copyright 1992 - 2007 Kai Makisara email Kai.Makisara@kolumbus.fi Some small formal changes - aeb, 950809 @@ -17,7 +17,7 @@ Last modified: 18-JAN-1998 Richard Gooch Devfs support */ -static const char *verstr = "20061107"; +static const char *verstr = "20070203"; #include @@ -1168,6 +1168,7 @@ static int st_open(struct inode *inode, STps = &(STp->ps[i]); STps->rw = ST_IDLE; } + STp->try_dio_now = STp->try_dio; STp->recover_count = 0; DEB( STp->nbr_waits = STp->nbr_finished = 0; STp->nbr_requests = STp->nbr_dio = STp->nbr_pages = STp->nbr_combinable = 0; ) @@ -1400,9 +1401,9 @@ static int setup_buffering(struct scsi_t struct st_buffer *STbp = STp->buffer; if (is_read) - i = STp->try_dio && try_rdio; + i = STp->try_dio_now && try_rdio; else - i = STp->try_dio && try_wdio; + i = STp->try_dio_now && try_wdio; if (i && ((unsigned long)buf & queue_dma_alignment( STp->device->request_queue)) == 0) { @@ -1599,7 +1600,7 @@ st_write(struct file *filp, const char _ STm->do_async_writes && STps->eof < ST_EOM_OK; if (STp->block_size != 0 && STm->do_buffer_writes && - !(STp->try_dio && try_wdio) && STps->eof < ST_EOM_OK && + !(STp->try_dio_now && try_wdio) && STps->eof < ST_EOM_OK && STbp->buffer_bytes < STbp->buffer_size) { STp->dirty = 1; /* Don't write a buffer that is not full enough. */ @@ -1769,7 +1770,7 @@ static long read_tape(struct scsi_tape * if (STp->block_size == 0) blks = bytes = count; else { - if (!(STp->try_dio && try_rdio) && STm->do_read_ahead) { + if (!(STp->try_dio_now && try_rdio) && STm->do_read_ahead) { blks = (STp->buffer)->buffer_blocks; bytes = blks * STp->block_size; } else { @@ -1948,10 +1949,12 @@ st_read(struct file *filp, char __user * goto out; STm = &(STp->modes[STp->current_mode]); - if (!(STm->do_read_ahead) && STp->block_size != 0 && - (count % STp->block_size) != 0) { - retval = (-EINVAL); /* Read must be integral number of blocks */ - goto out; + if (STp->block_size != 0 && (count % STp->block_size) != 0) { + if (!STm->do_read_ahead) { + retval = (-EINVAL); /* Read must be integral number of blocks */ + goto out; + } + STp->try_dio_now = 0; /* Direct i/o can't handle split blocks */ } STps = &(STp->ps[STp->partition]); @@ -3861,7 +3864,7 @@ __setup("st=", st_setup); #endif -static struct file_operations st_fops = +static const struct file_operations st_fops = { .owner = THIS_MODULE, .read = st_read, diff --git a/drivers/scsi/st.h b/drivers/scsi/st.h index 05a5cae..50f3deb 100644 --- a/drivers/scsi/st.h +++ b/drivers/scsi/st.h @@ -117,7 +117,8 @@ struct scsi_tape { unsigned char cln_sense_value; unsigned char cln_sense_mask; unsigned char use_pf; /* Set Page Format bit in all mode selects? */ - unsigned char try_dio; /* try direct i/o? */ + unsigned char try_dio; /* try direct i/o in general? */ + unsigned char try_dio_now; /* try direct i/o before next close? */ unsigned char c_algo; /* compression algorithm */ unsigned char pos_unknown; /* after reset position unknown */ int tape_type; diff --git a/drivers/scsi/stex.c b/drivers/scsi/stex.c index ba6bcda..69be132 100644 --- a/drivers/scsi/stex.c +++ b/drivers/scsi/stex.c @@ -17,7 +17,6 @@ #include #include #include #include -#include #include #include #include diff --git a/drivers/scsi/sun3_scsi.c b/drivers/scsi/sun3_scsi.c index 69ee3e4..5e46d84 100644 --- a/drivers/scsi/sun3_scsi.c +++ b/drivers/scsi/sun3_scsi.c @@ -58,7 +58,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/scsi/sun3_scsi_vme.c b/drivers/scsi/sun3_scsi_vme.c index bb0c9fd..7cb4a31 100644 --- a/drivers/scsi/sun3_scsi_vme.c +++ b/drivers/scsi/sun3_scsi_vme.c @@ -20,7 +20,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/scsi/sun3x_esp.c b/drivers/scsi/sun3x_esp.c index 6b60536..80fb3f8 100644 --- a/drivers/scsi/sun3x_esp.c +++ b/drivers/scsi/sun3x_esp.c @@ -53,7 +53,7 @@ int sun3x_esp_detect(struct scsi_host_te struct ConfigDev *esp_dev; esp_dev = 0; - esp = esp_allocate(tpnt, (void *) esp_dev); + esp = esp_allocate(tpnt, esp_dev, 0); /* Do command transfer with DMA */ esp->do_pio_cmds = 0; diff --git a/drivers/scsi/sym53c416.c b/drivers/scsi/sym53c416.c index 32c883f..2ca9505 100644 --- a/drivers/scsi/sym53c416.c +++ b/drivers/scsi/sym53c416.c @@ -32,7 +32,6 @@ #include #include #include #include -#include #include #include #include diff --git a/drivers/scsi/t128.c b/drivers/scsi/t128.c index 0b7a70f..248d60b 100644 --- a/drivers/scsi/t128.c +++ b/drivers/scsi/t128.c @@ -108,7 +108,6 @@ #define PSEUDO_DMA #include #include -#include #include #include #include diff --git a/drivers/scsi/tmscsim.c b/drivers/scsi/tmscsim.c index fa5382e..a583e89 100644 --- a/drivers/scsi/tmscsim.c +++ b/drivers/scsi/tmscsim.c @@ -221,7 +221,6 @@ #define DCBDEBUG1(x) C_NOP #include #include #include -#include #include #include #include diff --git a/drivers/scsi/wd33c93.c b/drivers/scsi/wd33c93.c index 2083454..8357516 100644 --- a/drivers/scsi/wd33c93.c +++ b/drivers/scsi/wd33c93.c @@ -73,7 +73,6 @@ #include -#include #include #include #include diff --git a/drivers/serial/8250.c b/drivers/serial/8250.c index 5261f0a..98ec861 100644 --- a/drivers/serial/8250.c +++ b/drivers/serial/8250.c @@ -364,6 +364,23 @@ #endif } } +static void +serial_out_sync(struct uart_8250_port *up, int offset, int value) +{ + switch (up->port.iotype) { + case UPIO_MEM: + case UPIO_MEM32: +#ifdef CONFIG_SERIAL_8250_AU1X00 + case UPIO_AU: +#endif + serial_out(up, offset, value); + serial_in(up, UART_LCR); /* safe, no side-effects */ + break; + default: + serial_out(up, offset, value); + } +} + /* * We used to support using pause I/O for certain machines. We * haven't supported this for a while, but just in case it's badly @@ -920,12 +937,16 @@ static void autoconfig(struct uart_8250_ #ifdef __i386__ outb(0xff, 0x080); #endif - scratch2 = serial_inp(up, UART_IER); + /* + * Mask out IER[7:4] bits for test as some UARTs (e.g. TL + * 16C754B) allow only to modify them if an EFR bit is set. + */ + scratch2 = serial_inp(up, UART_IER) & 0x0f; serial_outp(up, UART_IER, 0x0F); #ifdef __i386__ outb(0, 0x080); #endif - scratch3 = serial_inp(up, UART_IER); + scratch3 = serial_inp(up, UART_IER) & 0x0f; serial_outp(up, UART_IER, scratch); if (scratch2 != 0 || scratch3 != 0x0F) { /* @@ -1041,7 +1062,7 @@ #ifdef CONFIG_SERIAL_8250_RSA #endif serial_outp(up, UART_MCR, save_mcr); serial8250_clear_fifos(up); - (void)serial_in(up, UART_RX); + serial_in(up, UART_RX); if (up->capabilities & UART_CAP_UUE) serial_outp(up, UART_IER, UART_IER_UUE); else @@ -1447,6 +1468,12 @@ static void serial_unlink_irq_chain(stru serial_do_unlink(i, up); } +/* Base timer interval for polling */ +static inline int poll_timeout(int timeout) +{ + return timeout > 6 ? (timeout / 2 - 2) : 1; +} + /* * This function is used to handle ports that do not have an * interrupt. This doesn't work very well for 16450's, but gives @@ -1456,16 +1483,51 @@ static void serial_unlink_irq_chain(stru static void serial8250_timeout(unsigned long data) { struct uart_8250_port *up = (struct uart_8250_port *)data; - unsigned int timeout; unsigned int iir; iir = serial_in(up, UART_IIR); if (!(iir & UART_IIR_NO_INT)) serial8250_handle_port(up); + mod_timer(&up->timer, jiffies + poll_timeout(up->port.timeout)); +} + +static void serial8250_backup_timeout(unsigned long data) +{ + struct uart_8250_port *up = (struct uart_8250_port *)data; + unsigned int iir, ier = 0; + + /* + * Must disable interrupts or else we risk racing with the interrupt + * based handler. + */ + if (is_real_interrupt(up->port.irq)) { + ier = serial_in(up, UART_IER); + serial_out(up, UART_IER, 0); + } + + iir = serial_in(up, UART_IIR); + + /* + * This should be a safe test for anyone who doesn't trust the + * IIR bits on their UART, but it's specifically designed for + * the "Diva" UART used on the management processor on many HP + * ia64 and parisc boxes. + */ + if ((iir & UART_IIR_NO_INT) && (up->ier & UART_IER_THRI) && + (!uart_circ_empty(&up->port.info->xmit) || up->port.x_char) && + (serial_in(up, UART_LSR) & UART_LSR_THRE)) { + iir &= ~(UART_IIR_ID | UART_IIR_NO_INT); + iir |= UART_IIR_THRI; + } + + if (!(iir & UART_IIR_NO_INT)) + serial8250_handle_port(up); + + if (is_real_interrupt(up->port.irq)) + serial_out(up, UART_IER, ier); - timeout = up->port.timeout; - timeout = timeout > 6 ? (timeout / 2 - 2) : 1; - mod_timer(&up->timer, jiffies + timeout); + /* Standard timer interval plus 0.2s to keep the port running */ + mod_timer(&up->timer, jiffies + poll_timeout(up->port.timeout) + HZ/5); } static unsigned int serial8250_tx_empty(struct uart_port *port) @@ -1536,6 +1598,37 @@ static void serial8250_break_ctl(struct spin_unlock_irqrestore(&up->port.lock, flags); } +#define BOTH_EMPTY (UART_LSR_TEMT | UART_LSR_THRE) + +/* + * Wait for transmitter & holding register to empty + */ +static inline void wait_for_xmitr(struct uart_8250_port *up, int bits) +{ + unsigned int status, tmout = 10000; + + /* Wait up to 10ms for the character(s) to be sent. */ + do { + status = serial_in(up, UART_LSR); + + if (status & UART_LSR_BI) + up->lsr_break_flag = UART_LSR_BI; + + if (--tmout == 0) + break; + udelay(1); + } while ((status & bits) != bits); + + /* Wait up to 1s for flow control if necessary */ + if (up->port.flags & UPF_CONS_FLOW) { + tmout = 1000000; + while (!(serial_in(up, UART_MSR) & UART_MSR_CTS) && --tmout) { + udelay(1); + touch_nmi_watchdog(); + } + } +} + static int serial8250_startup(struct uart_port *port) { struct uart_8250_port *up = (struct uart_8250_port *)port; @@ -1609,18 +1702,50 @@ #endif serial_outp(up, UART_LCR, 0); } + if (is_real_interrupt(up->port.irq)) { + /* + * Test for UARTs that do not reassert THRE when the + * transmitter is idle and the interrupt has already + * been cleared. Real 16550s should always reassert + * this interrupt whenever the transmitter is idle and + * the interrupt is enabled. Delays are necessary to + * allow register changes to become visible. + */ + spin_lock_irqsave(&up->port.lock, flags); + + wait_for_xmitr(up, UART_LSR_THRE); + serial_out_sync(up, UART_IER, UART_IER_THRI); + udelay(1); /* allow THRE to set */ + serial_in(up, UART_IIR); + serial_out(up, UART_IER, 0); + serial_out_sync(up, UART_IER, UART_IER_THRI); + udelay(1); /* allow a working UART time to re-assert THRE */ + iir = serial_in(up, UART_IIR); + serial_out(up, UART_IER, 0); + + spin_unlock_irqrestore(&up->port.lock, flags); + + /* + * If the interrupt is not reasserted, setup a timer to + * kick the UART on a regular basis. + */ + if (iir & UART_IIR_NO_INT) { + pr_debug("ttyS%d - using backup timer\n", port->line); + up->timer.function = serial8250_backup_timeout; + up->timer.data = (unsigned long)up; + mod_timer(&up->timer, jiffies + + poll_timeout(up->port.timeout) + HZ/5); + } + } + /* * If the "interrupt" for this port doesn't correspond with any * hardware interrupt, we use a timer-based system. The original * driver used to do this with IRQ0. */ if (!is_real_interrupt(up->port.irq)) { - unsigned int timeout = up->port.timeout; - - timeout = timeout > 6 ? (timeout / 2 - 2) : 1; - up->timer.data = (unsigned long)up; - mod_timer(&up->timer, jiffies + timeout); + mod_timer(&up->timer, jiffies + poll_timeout(up->port.timeout)); } else { retval = serial_link_irq_chain(up); if (retval) @@ -1736,9 +1861,9 @@ #endif */ (void) serial_in(up, UART_RX); - if (!is_real_interrupt(up->port.irq)) - del_timer_sync(&up->timer); - else + del_timer_sync(&up->timer); + up->timer.function = serial8250_timeout; + if (is_real_interrupt(up->port.irq)) serial_unlink_irq_chain(up); } @@ -2208,37 +2333,6 @@ serial8250_register_ports(struct uart_dr #ifdef CONFIG_SERIAL_8250_CONSOLE -#define BOTH_EMPTY (UART_LSR_TEMT | UART_LSR_THRE) - -/* - * Wait for transmitter & holding register to empty - */ -static inline void wait_for_xmitr(struct uart_8250_port *up, int bits) -{ - unsigned int status, tmout = 10000; - - /* Wait up to 10ms for the character(s) to be sent. */ - do { - status = serial_in(up, UART_LSR); - - if (status & UART_LSR_BI) - up->lsr_break_flag = UART_LSR_BI; - - if (--tmout == 0) - break; - udelay(1); - } while ((status & bits) != bits); - - /* Wait up to 1s for flow control if necessary */ - if (up->port.flags & UPF_CONS_FLOW) { - tmout = 1000000; - while (!(serial_in(up, UART_MSR) & UART_MSR_CTS) && --tmout) { - udelay(1); - touch_nmi_watchdog(); - } - } -} - static void serial8250_console_putchar(struct uart_port *port, int ch) { struct uart_8250_port *up = (struct uart_8250_port *)port; diff --git a/drivers/serial/8250_acorn.c b/drivers/serial/8250_acorn.c index ef8cc8a..562ba74 100644 --- a/drivers/serial/8250_acorn.c +++ b/drivers/serial/8250_acorn.c @@ -47,11 +47,10 @@ serial_card_probe(struct expansion_card unsigned long bus_addr; unsigned int i; - info = kmalloc(sizeof(struct serial_card_info), GFP_KERNEL); + info = kzalloc(sizeof(struct serial_card_info), GFP_KERNEL); if (!info) return -ENOMEM; - memset(info, 0, sizeof(struct serial_card_info)); info->num_ports = type->num_ports; bus_addr = ecard_resource_start(ec, type->type); diff --git a/drivers/serial/8250_pci.c b/drivers/serial/8250_pci.c index 52e2e64..6d7d616 100644 --- a/drivers/serial/8250_pci.c +++ b/drivers/serial/8250_pci.c @@ -16,7 +16,6 @@ #include #include #include -#include #include #include #include @@ -679,6 +678,13 @@ static struct pci_serial_quirk pci_seria */ { .vendor = PCI_VENDOR_ID_PLX, + .device = PCI_DEVICE_ID_PLX_9030, + .subvendor = PCI_SUBVENDOR_ID_PERLE, + .subdevice = PCI_ANY_ID, + .setup = pci_default_setup, + }, + { + .vendor = PCI_VENDOR_ID_PLX, .device = PCI_DEVICE_ID_PLX_9050, .subvendor = PCI_SUBVENDOR_ID_EXSYS, .subdevice = PCI_SUBDEVICE_ID_EXSYS_4055, @@ -936,6 +942,7 @@ enum pci_board_num_t { pbn_b2_1_115200, pbn_b2_2_115200, + pbn_b2_4_115200, pbn_b2_8_115200, pbn_b2_1_460800, @@ -1249,6 +1256,12 @@ static struct pciserial_board pci_boards .base_baud = 115200, .uart_offset = 8, }, + [pbn_b2_4_115200] = { + .flags = FL_BASE2, + .num_ports = 4, + .base_baud = 115200, + .uart_offset = 8, + }, [pbn_b2_8_115200] = { .flags = FL_BASE2, .num_ports = 8, @@ -1614,7 +1627,7 @@ pciserial_init_ports(struct pci_dev *dev nr_ports = rc; } - priv = kmalloc(sizeof(struct serial_private) + + priv = kzalloc(sizeof(struct serial_private) + sizeof(unsigned int) * nr_ports, GFP_KERNEL); if (!priv) { @@ -1622,9 +1635,6 @@ pciserial_init_ports(struct pci_dev *dev goto err_deinit; } - memset(priv, 0, sizeof(struct serial_private) + - sizeof(unsigned int) * nr_ports); - priv->dev = dev; priv->quirk = quirk; @@ -1990,6 +2000,10 @@ static struct pci_device_id serial_pci_t { PCI_VENDOR_ID_PANACOM, PCI_DEVICE_ID_PANACOM_DUALMODEM, PCI_ANY_ID, PCI_ANY_ID, 0, 0, pbn_panacom2 }, + { PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_9030, + PCI_VENDOR_ID_ESDGMBH, + PCI_DEVICE_ID_ESDGMBH_CPCIASIO4, 0, 0, + pbn_b2_4_115200 }, { PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_9050, PCI_SUBVENDOR_ID_CHASE_PCIFAST, PCI_SUBDEVICE_ID_CHASE_PCIFAST4, 0, 0, @@ -2379,6 +2393,15 @@ static struct pci_device_id serial_pci_t pbn_b2_2_115200 }, /* + * Perle PCI-RAS cards + */ + { PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_9030, + PCI_SUBVENDOR_ID_PERLE, PCI_SUBDEVICE_ID_PCI_RAS4, + 0, 0, pbn_b2_4_921600 }, + { PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_9030, + PCI_SUBVENDOR_ID_PERLE, PCI_SUBDEVICE_ID_PCI_RAS8, + 0, 0, pbn_b2_8_921600 }, + /* * These entries match devices with class COMMUNICATION_SERIAL, * COMMUNICATION_MODEM or COMMUNICATION_MULTISERIAL */ diff --git a/drivers/serial/8250_pnp.c b/drivers/serial/8250_pnp.c index d3d6b82..cde5db4 100644 --- a/drivers/serial/8250_pnp.c +++ b/drivers/serial/8250_pnp.c @@ -450,11 +450,11 @@ #endif port.dev = &dev->dev; line = serial8250_register_port(&port); + if (line < 0) + return -ENODEV; - if (line >= 0) - pnp_set_drvdata(dev, (void *)((long)line + 1)); - return line >= 0 ? 0 : -ENODEV; - + pnp_set_drvdata(dev, (void *)((long)line + 1)); + return 0; } static void __devexit serial_pnp_remove(struct pnp_dev *dev) diff --git a/drivers/serial/Kconfig b/drivers/serial/Kconfig index 2978c09..e8dd71d 100644 --- a/drivers/serial/Kconfig +++ b/drivers/serial/Kconfig @@ -686,6 +686,22 @@ config SERIAL_SH_SCI_CONSOLE depends on SERIAL_SH_SCI=y select SERIAL_CORE_CONSOLE +config SERIAL_PNX8XXX + bool "Enable PNX8XXX SoCs' UART Support" + depends on MIPS && SOC_PNX8550 + select SERIAL_CORE + help + If you have a MIPS-based Philips SoC such as PNX8550 or PNX8330 + and you want to use serial ports, say Y. Otherwise, say N. + +config SERIAL_PNX8XXX_CONSOLE + bool "Enable PNX8XX0 serial console" + depends on SERIAL_PNX8XXX + select SERIAL_CORE_CONSOLE + help + If you have a MIPS-based Philips SoC such as PNX8550 or PNX8330 + and you want to use serial console, say Y. Otherwise, say N. + config SERIAL_CORE tristate @@ -916,6 +932,11 @@ config SERIAL_TXX9 config HAS_TXX9_SERIAL bool +config SERIAL_TXX9_NR_UARTS + int "Maximum number of TMPTX39XX/49XX SIO ports" + depends on SERIAL_TXX9 + default "6" + config SERIAL_TXX9_CONSOLE bool "TMPTX39XX/49XX SIO Console support" depends on SERIAL_TXX9=y @@ -994,4 +1015,14 @@ config SERIAL_NETX_CONSOLE If you have enabled the serial port on the Motorola IMX CPU you can make it the console by answering Y to this option. +config SERIAL_OF_PLATFORM + tristate "Serial port on Open Firmware platform bus" + depends on PPC_OF + depends on SERIAL_8250 + help + If you have a PowerPC based system that has serial ports + on a platform specific bus, you should enable this option. + Currently, only 8250 compatible ports are supported, but + others can easily be added. + endmenu diff --git a/drivers/serial/Makefile b/drivers/serial/Makefile index df3632c..6b3560c 100644 --- a/drivers/serial/Makefile +++ b/drivers/serial/Makefile @@ -25,6 +25,7 @@ obj-$(CONFIG_SERIAL_AMBA_PL010) += amba- obj-$(CONFIG_SERIAL_AMBA_PL011) += amba-pl011.o obj-$(CONFIG_SERIAL_CLPS711X) += clps711x.o obj-$(CONFIG_SERIAL_PXA) += pxa.o +obj-$(CONFIG_SERIAL_PNX8XXX) += pnx8xxx_uart.o obj-$(CONFIG_SERIAL_SA1100) += sa1100.o obj-$(CONFIG_SERIAL_S3C2410) += s3c2410.o obj-$(CONFIG_SERIAL_SUNCORE) += suncore.o @@ -58,3 +59,4 @@ obj-$(CONFIG_SERIAL_SGI_IOC3) += ioc3_se obj-$(CONFIG_SERIAL_ATMEL) += atmel_serial.o obj-$(CONFIG_SERIAL_UARTLITE) += uartlite.o obj-$(CONFIG_SERIAL_NETX) += netx-serial.o +obj-$(CONFIG_SERIAL_OF_PLATFORM) += of_serial.o diff --git a/drivers/serial/atmel_serial.c b/drivers/serial/atmel_serial.c index 881f886..df45a7a 100644 --- a/drivers/serial/atmel_serial.c +++ b/drivers/serial/atmel_serial.c @@ -73,35 +73,35 @@ #endif #define ATMEL_ISR_PASS_LIMIT 256 -#define UART_PUT_CR(port,v) writel(v, (port)->membase + ATMEL_US_CR) -#define UART_GET_MR(port) readl((port)->membase + ATMEL_US_MR) -#define UART_PUT_MR(port,v) writel(v, (port)->membase + ATMEL_US_MR) -#define UART_PUT_IER(port,v) writel(v, (port)->membase + ATMEL_US_IER) -#define UART_PUT_IDR(port,v) writel(v, (port)->membase + ATMEL_US_IDR) -#define UART_GET_IMR(port) readl((port)->membase + ATMEL_US_IMR) -#define UART_GET_CSR(port) readl((port)->membase + ATMEL_US_CSR) -#define UART_GET_CHAR(port) readl((port)->membase + ATMEL_US_RHR) -#define UART_PUT_CHAR(port,v) writel(v, (port)->membase + ATMEL_US_THR) -#define UART_GET_BRGR(port) readl((port)->membase + ATMEL_US_BRGR) -#define UART_PUT_BRGR(port,v) writel(v, (port)->membase + ATMEL_US_BRGR) -#define UART_PUT_RTOR(port,v) writel(v, (port)->membase + ATMEL_US_RTOR) - -// #define UART_GET_CR(port) readl((port)->membase + ATMEL_US_CR) // is write-only +#define UART_PUT_CR(port,v) __raw_writel(v, (port)->membase + ATMEL_US_CR) +#define UART_GET_MR(port) __raw_readl((port)->membase + ATMEL_US_MR) +#define UART_PUT_MR(port,v) __raw_writel(v, (port)->membase + ATMEL_US_MR) +#define UART_PUT_IER(port,v) __raw_writel(v, (port)->membase + ATMEL_US_IER) +#define UART_PUT_IDR(port,v) __raw_writel(v, (port)->membase + ATMEL_US_IDR) +#define UART_GET_IMR(port) __raw_readl((port)->membase + ATMEL_US_IMR) +#define UART_GET_CSR(port) __raw_readl((port)->membase + ATMEL_US_CSR) +#define UART_GET_CHAR(port) __raw_readl((port)->membase + ATMEL_US_RHR) +#define UART_PUT_CHAR(port,v) __raw_writel(v, (port)->membase + ATMEL_US_THR) +#define UART_GET_BRGR(port) __raw_readl((port)->membase + ATMEL_US_BRGR) +#define UART_PUT_BRGR(port,v) __raw_writel(v, (port)->membase + ATMEL_US_BRGR) +#define UART_PUT_RTOR(port,v) __raw_writel(v, (port)->membase + ATMEL_US_RTOR) + +// #define UART_GET_CR(port) __raw_readl((port)->membase + ATMEL_US_CR) // is write-only /* PDC registers */ -#define UART_PUT_PTCR(port,v) writel(v, (port)->membase + ATMEL_PDC_PTCR) -#define UART_GET_PTSR(port) readl((port)->membase + ATMEL_PDC_PTSR) - -#define UART_PUT_RPR(port,v) writel(v, (port)->membase + ATMEL_PDC_RPR) -#define UART_GET_RPR(port) readl((port)->membase + ATMEL_PDC_RPR) -#define UART_PUT_RCR(port,v) writel(v, (port)->membase + ATMEL_PDC_RCR) -#define UART_PUT_RNPR(port,v) writel(v, (port)->membase + ATMEL_PDC_RNPR) -#define UART_PUT_RNCR(port,v) writel(v, (port)->membase + ATMEL_PDC_RNCR) - -#define UART_PUT_TPR(port,v) writel(v, (port)->membase + ATMEL_PDC_TPR) -#define UART_PUT_TCR(port,v) writel(v, (port)->membase + ATMEL_PDC_TCR) -//#define UART_PUT_TNPR(port,v) writel(v, (port)->membase + ATMEL_PDC_TNPR) -//#define UART_PUT_TNCR(port,v) writel(v, (port)->membase + ATMEL_PDC_TNCR) +#define UART_PUT_PTCR(port,v) __raw_writel(v, (port)->membase + ATMEL_PDC_PTCR) +#define UART_GET_PTSR(port) __raw_readl((port)->membase + ATMEL_PDC_PTSR) + +#define UART_PUT_RPR(port,v) __raw_writel(v, (port)->membase + ATMEL_PDC_RPR) +#define UART_GET_RPR(port) __raw_readl((port)->membase + ATMEL_PDC_RPR) +#define UART_PUT_RCR(port,v) __raw_writel(v, (port)->membase + ATMEL_PDC_RCR) +#define UART_PUT_RNPR(port,v) __raw_writel(v, (port)->membase + ATMEL_PDC_RNPR) +#define UART_PUT_RNCR(port,v) __raw_writel(v, (port)->membase + ATMEL_PDC_RNCR) + +#define UART_PUT_TPR(port,v) __raw_writel(v, (port)->membase + ATMEL_PDC_TPR) +#define UART_PUT_TCR(port,v) __raw_writel(v, (port)->membase + ATMEL_PDC_TCR) +//#define UART_PUT_TNPR(port,v) __raw_writel(v, (port)->membase + ATMEL_PDC_TNPR) +//#define UART_PUT_TNCR(port,v) __raw_writel(v, (port)->membase + ATMEL_PDC_TNCR) static int (*atmel_open_hook)(struct uart_port *); static void (*atmel_close_hook)(struct uart_port *); diff --git a/drivers/serial/cpm_uart/cpm_uart_cpm1.c b/drivers/serial/cpm_uart/cpm_uart_cpm1.c index 08e55fd..925fb60 100644 --- a/drivers/serial/cpm_uart/cpm_uart_cpm1.c +++ b/drivers/serial/cpm_uart/cpm_uart_cpm1.c @@ -40,6 +40,7 @@ #include #include #include +#include #include #include @@ -145,7 +146,7 @@ int cpm_uart_allocbuf(struct uart_cpm_po /* was hostalloc but changed cause it blows away the */ /* large tlb mapping when pinning the kernel area */ mem_addr = (u8 *) cpm_dpram_addr(cpm_dpalloc(memsz, 8)); - dma_addr = (u32)mem_addr; + dma_addr = (u32)cpm_dpram_phys(mem_addr); } else mem_addr = dma_alloc_coherent(NULL, memsz, &dma_addr, GFP_KERNEL); @@ -205,7 +206,7 @@ # endif (unsigned long)&cpmp->cp_smc[0]; cpm_uart_ports[UART_SMC1].smcp->smc_smcm |= (SMCM_RX | SMCM_TX); cpm_uart_ports[UART_SMC1].smcp->smc_smcmr &= ~(SMCMR_REN | SMCMR_TEN); - cpm_uart_ports[UART_SMC1].port.uartclk = (((bd_t *) __res)->bi_intfreq); + cpm_uart_ports[UART_SMC1].port.uartclk = uart_clock(); cpm_uart_port_map[cpm_uart_nr++] = UART_SMC1; #endif @@ -217,7 +218,7 @@ #ifdef CONFIG_SERIAL_CPM_SMC2 (unsigned long)&cpmp->cp_smc[1]; cpm_uart_ports[UART_SMC2].smcp->smc_smcm |= (SMCM_RX | SMCM_TX); cpm_uart_ports[UART_SMC2].smcp->smc_smcmr &= ~(SMCMR_REN | SMCMR_TEN); - cpm_uart_ports[UART_SMC2].port.uartclk = (((bd_t *) __res)->bi_intfreq); + cpm_uart_ports[UART_SMC2].port.uartclk = uart_clock(); cpm_uart_port_map[cpm_uart_nr++] = UART_SMC2; #endif @@ -231,7 +232,7 @@ #ifdef CONFIG_SERIAL_CPM_SCC1 ~(UART_SCCM_TX | UART_SCCM_RX); cpm_uart_ports[UART_SCC1].sccp->scc_gsmrl &= ~(SCC_GSMRL_ENR | SCC_GSMRL_ENT); - cpm_uart_ports[UART_SCC1].port.uartclk = (((bd_t *) __res)->bi_intfreq); + cpm_uart_ports[UART_SCC1].port.uartclk = uart_clock(); cpm_uart_port_map[cpm_uart_nr++] = UART_SCC1; #endif @@ -245,7 +246,7 @@ #ifdef CONFIG_SERIAL_CPM_SCC2 ~(UART_SCCM_TX | UART_SCCM_RX); cpm_uart_ports[UART_SCC2].sccp->scc_gsmrl &= ~(SCC_GSMRL_ENR | SCC_GSMRL_ENT); - cpm_uart_ports[UART_SCC2].port.uartclk = (((bd_t *) __res)->bi_intfreq); + cpm_uart_ports[UART_SCC2].port.uartclk = uart_clock(); cpm_uart_port_map[cpm_uart_nr++] = UART_SCC2; #endif @@ -259,7 +260,7 @@ #ifdef CONFIG_SERIAL_CPM_SCC3 ~(UART_SCCM_TX | UART_SCCM_RX); cpm_uart_ports[UART_SCC3].sccp->scc_gsmrl &= ~(SCC_GSMRL_ENR | SCC_GSMRL_ENT); - cpm_uart_ports[UART_SCC3].port.uartclk = (((bd_t *) __res)->bi_intfreq); + cpm_uart_ports[UART_SCC3].port.uartclk = uart_clock(); cpm_uart_port_map[cpm_uart_nr++] = UART_SCC3; #endif @@ -273,7 +274,7 @@ #ifdef CONFIG_SERIAL_CPM_SCC4 ~(UART_SCCM_TX | UART_SCCM_RX); cpm_uart_ports[UART_SCC4].sccp->scc_gsmrl &= ~(SCC_GSMRL_ENR | SCC_GSMRL_ENT); - cpm_uart_ports[UART_SCC4].port.uartclk = (((bd_t *) __res)->bi_intfreq); + cpm_uart_ports[UART_SCC4].port.uartclk = uart_clock(); cpm_uart_port_map[cpm_uart_nr++] = UART_SCC4; #endif return 0; diff --git a/drivers/serial/cpm_uart/cpm_uart_cpm1.h b/drivers/serial/cpm_uart/cpm_uart_cpm1.h index 5eb49ea..a99e45e 100644 --- a/drivers/serial/cpm_uart/cpm_uart_cpm1.h +++ b/drivers/serial/cpm_uart/cpm_uart_cpm1.h @@ -20,9 +20,6 @@ #define SCC2_IRQ (CPM_IRQ_OFFSET + CPMVE #define SCC3_IRQ (CPM_IRQ_OFFSET + CPMVEC_SCC3) #define SCC4_IRQ (CPM_IRQ_OFFSET + CPMVEC_SCC4) -/* the CPM address */ -#define CPM_ADDR IMAP_ADDR - static inline void cpm_set_brg(int brg, int baud) { cpm_setbrg(brg, baud); diff --git a/drivers/serial/cpm_uart/cpm_uart_cpm2.h b/drivers/serial/cpm_uart/cpm_uart_cpm2.h index 4b77911..1b3219f 100644 --- a/drivers/serial/cpm_uart/cpm_uart_cpm2.h +++ b/drivers/serial/cpm_uart/cpm_uart_cpm2.h @@ -20,9 +20,6 @@ #define SCC2_IRQ SIU_INT_SCC2 #define SCC3_IRQ SIU_INT_SCC3 #define SCC4_IRQ SIU_INT_SCC4 -/* the CPM address */ -#define CPM_ADDR CPM_MAP_ADDR - static inline void cpm_set_brg(int brg, int baud) { cpm_setbrg(brg, baud); diff --git a/drivers/serial/crisv10.c b/drivers/serial/crisv10.c index 42b050c..312bef6 100644 --- a/drivers/serial/crisv10.c +++ b/drivers/serial/crisv10.c @@ -3173,12 +3173,8 @@ do_softint(void *private_) if (!tty) return; - if (test_and_clear_bit(RS_EVENT_WRITE_WAKEUP, &info->event)) { - if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && - tty->ldisc.write_wakeup) - (tty->ldisc.write_wakeup)(tty); - wake_up_interruptible(&tty->write_wait); - } + if (test_and_clear_bit(RS_EVENT_WRITE_WAKEUP, &info->event)) + tty_wakeup(tty); } static int @@ -3798,11 +3794,7 @@ rs_flush_buffer(struct tty_struct *tty) info->xmit.head = info->xmit.tail = 0; restore_flags(flags); - wake_up_interruptible(&tty->write_wait); - - if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && - tty->ldisc.write_wakeup) - (tty->ldisc.write_wakeup)(tty); + tty_wakeup(tty); } /* diff --git a/drivers/serial/icom.c b/drivers/serial/icom.c index 71e6a24..41431d0 100644 --- a/drivers/serial/icom.c +++ b/drivers/serial/icom.c @@ -27,7 +27,6 @@ #include #include #include #include -#include #include #include #include @@ -1417,14 +1416,12 @@ static int __devinit icom_alloc_adapter( struct list_head *tmp; icom_adapter = (struct icom_adapter *) - kmalloc(sizeof(struct icom_adapter), GFP_KERNEL); + kzalloc(sizeof(struct icom_adapter), GFP_KERNEL); if (!icom_adapter) { return -ENOMEM; } - memset(icom_adapter, 0, sizeof(struct icom_adapter)); - list_for_each(tmp, &icom_adapter_head) { cur_adapter_entry = list_entry(tmp, struct icom_adapter, diff --git a/drivers/serial/ioc3_serial.c b/drivers/serial/ioc3_serial.c index 9cc0be9..168073f 100644 --- a/drivers/serial/ioc3_serial.c +++ b/drivers/serial/ioc3_serial.c @@ -2019,13 +2019,12 @@ ioc3uart_probe(struct ioc3_submodule *is DPRINT_CONFIG(("%s (0x%p, 0x%p)\n", __FUNCTION__, is, idd)); - card_ptr = kmalloc(sizeof(struct ioc3_card), GFP_KERNEL); + card_ptr = kzalloc(sizeof(struct ioc3_card), GFP_KERNEL); if (!card_ptr) { printk(KERN_WARNING "ioc3_attach_one" ": unable to get memory for the IOC3\n"); return -ENOMEM; } - memset(card_ptr, 0, sizeof(struct ioc3_card)); idd->data[is->id] = card_ptr; Submodule_slot = is->id; @@ -2040,13 +2039,12 @@ ioc3uart_probe(struct ioc3_submodule *is /* Create port structures for each port */ for (phys_port = 0; phys_port < PORTS_PER_CARD; phys_port++) { - port = kmalloc(sizeof(struct ioc3_port), GFP_KERNEL); + port = kzalloc(sizeof(struct ioc3_port), GFP_KERNEL); if (!port) { printk(KERN_WARNING "IOC3 serial memory not available for port\n"); goto out4; } - memset(port, 0, sizeof(struct ioc3_port)); spin_lock_init(&port->ip_lock); /* we need to remember the previous ones, to point back to diff --git a/drivers/serial/ioc4_serial.c b/drivers/serial/ioc4_serial.c index c862f67..0c17938 100644 --- a/drivers/serial/ioc4_serial.c +++ b/drivers/serial/ioc4_serial.c @@ -1076,13 +1076,12 @@ static int inline ioc4_attach_local(stru /* Create port structures for each port */ for (port_number = 0; port_number < IOC4_NUM_SERIAL_PORTS; port_number++) { - port = kmalloc(sizeof(struct ioc4_port), GFP_KERNEL); + port = kzalloc(sizeof(struct ioc4_port), GFP_KERNEL); if (!port) { printk(KERN_WARNING "IOC4 serial memory not available for port\n"); return -ENOMEM; } - memset(port, 0, sizeof(struct ioc4_port)); spin_lock_init(&port->ip_lock); /* we need to remember the previous ones, to point back to @@ -2685,7 +2684,7 @@ static int ioc4_serial_remove_one(struct free_irq(control->ic_irq, soft); if (soft->is_ioc4_serial_addr) { iounmap(soft->is_ioc4_serial_addr); - release_region((unsigned long) + release_mem_region((unsigned long) soft->is_ioc4_serial_addr, sizeof(struct ioc4_serial)); } @@ -2790,7 +2789,7 @@ ioc4_serial_attach_one(struct ioc4_drive /* request serial registers */ tmp_addr1 = idd->idd_bar0 + IOC4_SERIAL_OFFSET; - if (!request_region(tmp_addr1, sizeof(struct ioc4_serial), + if (!request_mem_region(tmp_addr1, sizeof(struct ioc4_serial), "sioc4_uart")) { printk(KERN_WARNING "ioc4 (%p): unable to get request region for " @@ -2811,7 +2810,7 @@ ioc4_serial_attach_one(struct ioc4_drive (void *)serial)); /* Get memory for the new card */ - control = kmalloc(sizeof(struct ioc4_control), GFP_KERNEL); + control = kzalloc(sizeof(struct ioc4_control), GFP_KERNEL); if (!control) { printk(KERN_WARNING "ioc4_attach_one" @@ -2819,11 +2818,10 @@ ioc4_serial_attach_one(struct ioc4_drive ret = -ENOMEM; goto out2; } - memset(control, 0, sizeof(struct ioc4_control)); idd->idd_serial_data = control; /* Allocate the soft structure */ - soft = kmalloc(sizeof(struct ioc4_soft), GFP_KERNEL); + soft = kzalloc(sizeof(struct ioc4_soft), GFP_KERNEL); if (!soft) { printk(KERN_WARNING "ioc4 (%p): unable to get memory for the soft struct\n", @@ -2831,7 +2829,6 @@ ioc4_serial_attach_one(struct ioc4_drive ret = -ENOMEM; goto out3; } - memset(soft, 0, sizeof(struct ioc4_soft)); spin_lock_init(&soft->is_ir_lock); soft->is_ioc4_misc_addr = idd->idd_misc_regs; @@ -2889,7 +2886,7 @@ out3: out2: if (serial) iounmap(serial); - release_region(tmp_addr1, sizeof(struct ioc4_serial)); + release_mem_region(tmp_addr1, sizeof(struct ioc4_serial)); out1: return ret; diff --git a/drivers/serial/ip22zilog.c b/drivers/serial/ip22zilog.c index 0746c94..c3abfb3 100644 --- a/drivers/serial/ip22zilog.c +++ b/drivers/serial/ip22zilog.c @@ -14,7 +14,6 @@ */ #include #include -#include #include #include #include @@ -922,13 +921,7 @@ static int zilog_irq = -1; static void * __init alloc_one_table(unsigned long size) { - void *ret; - - ret = kmalloc(size, GFP_KERNEL); - if (ret != NULL) - memset(ret, 0, size); - - return ret; + return kzalloc(size, GFP_KERNEL); } static void __init ip22zilog_alloc_tables(void) diff --git a/drivers/serial/jsm/jsm_driver.c b/drivers/serial/jsm/jsm_driver.c index 244f63b..81792e6 100644 --- a/drivers/serial/jsm/jsm_driver.c +++ b/drivers/serial/jsm/jsm_driver.c @@ -71,14 +71,13 @@ static int jsm_probe_one(struct pci_dev goto out_disable_device; } - brd = kmalloc(sizeof(struct jsm_board), GFP_KERNEL); + brd = kzalloc(sizeof(struct jsm_board), GFP_KERNEL); if (!brd) { dev_err(&pdev->dev, "memory allocation for board structure failed\n"); rc = -ENOMEM; goto out_release_regions; } - memset(brd, 0, sizeof(struct jsm_board)); /* store the info for the board we've found */ brd->boardnum = adapter_count++; @@ -152,7 +151,7 @@ static int jsm_probe_one(struct pci_dev * Okay to malloc with GFP_KERNEL, we are not at interrupt * context, and there are no locks held. */ - brd->flipbuf = kmalloc(MYFLIPLEN, GFP_KERNEL); + brd->flipbuf = kzalloc(MYFLIPLEN, GFP_KERNEL); if (!brd->flipbuf) { /* XXX: leaking all resources from jsm_tty_init and jsm_uart_port_init here! */ @@ -160,7 +159,6 @@ static int jsm_probe_one(struct pci_dev retval = -ENOMEM; goto out_free_irq; } - memset(brd->flipbuf, 0, MYFLIPLEN); pci_set_drvdata(pdev, brd); diff --git a/drivers/serial/jsm/jsm_tty.c b/drivers/serial/jsm/jsm_tty.c index 7cf1c60..be22bbd 100644 --- a/drivers/serial/jsm/jsm_tty.c +++ b/drivers/serial/jsm/jsm_tty.c @@ -194,31 +194,28 @@ static int jsm_tty_open(struct uart_port /* Drop locks, as malloc with GFP_KERNEL can sleep */ if (!channel->ch_rqueue) { - channel->ch_rqueue = (u8 *) kmalloc(RQUEUESIZE, GFP_KERNEL); + channel->ch_rqueue = kzalloc(RQUEUESIZE, GFP_KERNEL); if (!channel->ch_rqueue) { jsm_printk(INIT, ERR, &channel->ch_bd->pci_dev, "unable to allocate read queue buf"); return -ENOMEM; } - memset(channel->ch_rqueue, 0, RQUEUESIZE); } if (!channel->ch_equeue) { - channel->ch_equeue = (u8 *) kmalloc(EQUEUESIZE, GFP_KERNEL); + channel->ch_equeue = kzalloc(EQUEUESIZE, GFP_KERNEL); if (!channel->ch_equeue) { jsm_printk(INIT, ERR, &channel->ch_bd->pci_dev, "unable to allocate error queue buf"); return -ENOMEM; } - memset(channel->ch_equeue, 0, EQUEUESIZE); } if (!channel->ch_wqueue) { - channel->ch_wqueue = (u8 *) kmalloc(WQUEUESIZE, GFP_KERNEL); + channel->ch_wqueue = kzalloc(WQUEUESIZE, GFP_KERNEL); if (!channel->ch_wqueue) { jsm_printk(INIT, ERR, &channel->ch_bd->pci_dev, "unable to allocate write queue buf"); return -ENOMEM; } - memset(channel->ch_wqueue, 0, WQUEUESIZE); } channel->ch_flags &= ~(CH_OPENING); @@ -392,13 +389,12 @@ int jsm_tty_init(struct jsm_board *brd) * Okay to malloc with GFP_KERNEL, we are not at * interrupt context, and there are no locks held. */ - brd->channels[i] = kmalloc(sizeof(struct jsm_channel), GFP_KERNEL); + brd->channels[i] = kzalloc(sizeof(struct jsm_channel), GFP_KERNEL); if (!brd->channels[i]) { jsm_printk(CORE, ERR, &brd->pci_dev, "%s:%d Unable to allocate memory for channel struct\n", __FILE__, __LINE__); } - memset(brd->channels[i], 0, sizeof(struct jsm_channel)); } } diff --git a/drivers/serial/mpc52xx_uart.c b/drivers/serial/mpc52xx_uart.c index 3c4b6c2..955bbd6 100644 --- a/drivers/serial/mpc52xx_uart.c +++ b/drivers/serial/mpc52xx_uart.c @@ -127,8 +127,7 @@ #endif #if defined(CONFIG_PPC_MERGE) static struct of_device_id mpc52xx_uart_of_match[] = { - { .type = "serial", .compatible = "mpc52xx-psc-uart", }, - { .type = "serial", .compatible = "mpc5200-psc", }, /* Efika only! */ + { .type = "serial", .compatible = "mpc5200-psc-uart", }, {}, }; #endif @@ -1068,7 +1067,7 @@ mpc52xx_uart_of_enumerate(void) continue; /* Is a particular device number requested? */ - devno = get_property(np, "device_no", NULL); + devno = get_property(np, "port-number", NULL); mpc52xx_uart_of_assign(of_node_get(np), devno ? *devno : -1); } diff --git a/drivers/serial/of_serial.c b/drivers/serial/of_serial.c new file mode 100644 index 0000000..09b0b73 --- /dev/null +++ b/drivers/serial/of_serial.c @@ -0,0 +1,143 @@ +/* + * Serial Port driver for Open Firmware platform devices + * + * Copyright (C) 2006 Arnd Bergmann , IBM Corp. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + * + */ +#include +#include +#include +#include + +#include +#include + +/* + * Fill a struct uart_port for a given device node + */ +static int __devinit of_platform_serial_setup(struct of_device *ofdev, + int type, struct uart_port *port) +{ + struct resource resource; + struct device_node *np = ofdev->node; + const unsigned int *clk, *spd; + int ret; + + memset(port, 0, sizeof *port); + spd = get_property(np, "current-speed", NULL); + clk = get_property(np, "clock-frequency", NULL); + if (!clk) { + dev_warn(&ofdev->dev, "no clock-frequency property set\n"); + return -ENODEV; + } + + ret = of_address_to_resource(np, 0, &resource); + if (ret) { + dev_warn(&ofdev->dev, "invalid address\n"); + return ret; + } + + spin_lock_init(&port->lock); + port->mapbase = resource.start; + port->irq = irq_of_parse_and_map(np, 0); + port->iotype = UPIO_MEM; + port->type = type; + port->uartclk = *clk; + port->flags = UPF_SHARE_IRQ | UPF_BOOT_AUTOCONF | UPF_IOREMAP; + port->dev = &ofdev->dev; + port->custom_divisor = *clk / (16 * (*spd)); + + return 0; +} + +/* + * Try to register a serial port + */ +static int __devinit of_platform_serial_probe(struct of_device *ofdev, + const struct of_device_id *id) +{ + struct uart_port port; + int port_type; + int ret; + + if (of_find_property(ofdev->node, "used-by-rtas", NULL)) + return -EBUSY; + + port_type = (unsigned long)id->data; + ret = of_platform_serial_setup(ofdev, port_type, &port); + if (ret) + goto out; + + switch (port_type) { + case PORT_UNKNOWN: + dev_info(&ofdev->dev, "Unknown serial port found, " + "attempting to use 8250 driver\n"); + /* fallthrough */ + case PORT_8250 ... PORT_MAX_8250: + ret = serial8250_register_port(&port); + break; + default: + /* need to add code for these */ + ret = -ENODEV; + break; + } + if (ret < 0) + goto out; + + ofdev->dev.driver_data = (void *)(unsigned long)ret; + return 0; +out: + irq_dispose_mapping(port.irq); + return ret; +} + +/* + * Release a line + */ +static int of_platform_serial_remove(struct of_device *ofdev) +{ + int line = (unsigned long)ofdev->dev.driver_data; + serial8250_unregister_port(line); + return 0; +} + +/* + * A few common types, add more as needed. + */ +static struct of_device_id __devinitdata of_platform_serial_table[] = { + { .type = "serial", .compatible = "ns8250", .data = (void *)PORT_8250, }, + { .type = "serial", .compatible = "ns16450", .data = (void *)PORT_16450, }, + { .type = "serial", .compatible = "ns16550", .data = (void *)PORT_16550, }, + { .type = "serial", .compatible = "ns16750", .data = (void *)PORT_16750, }, + { .type = "serial", .data = (void *)PORT_UNKNOWN, }, + { /* end of list */ }, +}; + +static struct of_platform_driver __devinitdata of_platform_serial_driver = { + .owner = THIS_MODULE, + .name = "of_serial", + .probe = of_platform_serial_probe, + .remove = of_platform_serial_remove, + .match_table = of_platform_serial_table, +}; + +static int __init of_platform_serial_init(void) +{ + return of_register_platform_driver(&of_platform_serial_driver); +} +module_init(of_platform_serial_init); + +static void __exit of_platform_serial_exit(void) +{ + return of_unregister_platform_driver(&of_platform_serial_driver); +}; +module_exit(of_platform_serial_exit); + +MODULE_AUTHOR("Arnd Bergmann "); +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("Serial Port driver for Open Firmware platform devices"); diff --git a/drivers/serial/pnx8xxx_uart.c b/drivers/serial/pnx8xxx_uart.c new file mode 100644 index 0000000..8d01c59 --- /dev/null +++ b/drivers/serial/pnx8xxx_uart.c @@ -0,0 +1,852 @@ +/* + * UART driver for PNX8XXX SoCs + * + * Author: Per Hallsmark per.hallsmark@mvista.com + * Ported to 2.6 kernel by EmbeddedAlley + * Reworked by Vitaly Wool + * + * Based on drivers/char/serial.c, by Linus Torvalds, Theodore Ts'o. + * Copyright (C) 2000 Deep Blue Solutions Ltd. + * + * This file is licensed under the terms of the GNU General Public License + * version 2. This program is licensed "as is" without any warranty of + * any kind, whether express or implied. + * + */ + +#if defined(CONFIG_SERIAL_PNX8XXX_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ) +#define SUPPORT_SYSRQ +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +/* We'll be using StrongARM sa1100 serial port major/minor */ +#define SERIAL_PNX8XXX_MAJOR 204 +#define MINOR_START 5 + +#define NR_PORTS 2 + +#define PNX8XXX_ISR_PASS_LIMIT 256 + +/* + * Convert from ignore_status_mask or read_status_mask to FIFO + * and interrupt status bits + */ +#define SM_TO_FIFO(x) ((x) >> 10) +#define SM_TO_ISTAT(x) ((x) & 0x000001ff) +#define FIFO_TO_SM(x) ((x) << 10) +#define ISTAT_TO_SM(x) ((x) & 0x000001ff) + +/* + * This is the size of our serial port register set. + */ +#define UART_PORT_SIZE 0x1000 + +/* + * This determines how often we check the modem status signals + * for any change. They generally aren't connected to an IRQ + * so we have to poll them. We also check immediately before + * filling the TX fifo incase CTS has been dropped. + */ +#define MCTRL_TIMEOUT (250*HZ/1000) + +extern struct pnx8xxx_port pnx8xxx_ports[]; + +static inline int serial_in(struct pnx8xxx_port *sport, int offset) +{ + return (__raw_readl(sport->port.membase + offset)); +} + +static inline void serial_out(struct pnx8xxx_port *sport, int offset, int value) +{ + __raw_writel(value, sport->port.membase + offset); +} + +/* + * Handle any change of modem status signal since we were last called. + */ +static void pnx8xxx_mctrl_check(struct pnx8xxx_port *sport) +{ + unsigned int status, changed; + + status = sport->port.ops->get_mctrl(&sport->port); + changed = status ^ sport->old_status; + + if (changed == 0) + return; + + sport->old_status = status; + + if (changed & TIOCM_RI) + sport->port.icount.rng++; + if (changed & TIOCM_DSR) + sport->port.icount.dsr++; + if (changed & TIOCM_CAR) + uart_handle_dcd_change(&sport->port, status & TIOCM_CAR); + if (changed & TIOCM_CTS) + uart_handle_cts_change(&sport->port, status & TIOCM_CTS); + + wake_up_interruptible(&sport->port.info->delta_msr_wait); +} + +/* + * This is our per-port timeout handler, for checking the + * modem status signals. + */ +static void pnx8xxx_timeout(unsigned long data) +{ + struct pnx8xxx_port *sport = (struct pnx8xxx_port *)data; + unsigned long flags; + + if (sport->port.info) { + spin_lock_irqsave(&sport->port.lock, flags); + pnx8xxx_mctrl_check(sport); + spin_unlock_irqrestore(&sport->port.lock, flags); + + mod_timer(&sport->timer, jiffies + MCTRL_TIMEOUT); + } +} + +/* + * interrupts disabled on entry + */ +static void pnx8xxx_stop_tx(struct uart_port *port) +{ + struct pnx8xxx_port *sport = (struct pnx8xxx_port *)port; + u32 ien; + + /* Disable TX intr */ + ien = serial_in(sport, PNX8XXX_IEN); + serial_out(sport, PNX8XXX_IEN, ien & ~PNX8XXX_UART_INT_ALLTX); + + /* Clear all pending TX intr */ + serial_out(sport, PNX8XXX_ICLR, PNX8XXX_UART_INT_ALLTX); +} + +/* + * interrupts may not be disabled on entry + */ +static void pnx8xxx_start_tx(struct uart_port *port) +{ + struct pnx8xxx_port *sport = (struct pnx8xxx_port *)port; + u32 ien; + + /* Clear all pending TX intr */ + serial_out(sport, PNX8XXX_ICLR, PNX8XXX_UART_INT_ALLTX); + + /* Enable TX intr */ + ien = serial_in(sport, PNX8XXX_IEN); + serial_out(sport, PNX8XXX_IEN, ien | PNX8XXX_UART_INT_ALLTX); +} + +/* + * Interrupts enabled + */ +static void pnx8xxx_stop_rx(struct uart_port *port) +{ + struct pnx8xxx_port *sport = (struct pnx8xxx_port *)port; + u32 ien; + + /* Disable RX intr */ + ien = serial_in(sport, PNX8XXX_IEN); + serial_out(sport, PNX8XXX_IEN, ien & ~PNX8XXX_UART_INT_ALLRX); + + /* Clear all pending RX intr */ + serial_out(sport, PNX8XXX_ICLR, PNX8XXX_UART_INT_ALLRX); +} + +/* + * Set the modem control timer to fire immediately. + */ +static void pnx8xxx_enable_ms(struct uart_port *port) +{ + struct pnx8xxx_port *sport = (struct pnx8xxx_port *)port; + + mod_timer(&sport->timer, jiffies); +} + +static void pnx8xxx_rx_chars(struct pnx8xxx_port *sport) +{ + struct tty_struct *tty = sport->port.info->tty; + unsigned int status, ch, flg; + + status = FIFO_TO_SM(serial_in(sport, PNX8XXX_FIFO)) | + ISTAT_TO_SM(serial_in(sport, PNX8XXX_ISTAT)); + while (status & FIFO_TO_SM(PNX8XXX_UART_FIFO_RXFIFO)) { + ch = serial_in(sport, PNX8XXX_FIFO); + + sport->port.icount.rx++; + + flg = TTY_NORMAL; + + /* + * note that the error handling code is + * out of the main execution path + */ + if (status & (FIFO_TO_SM(PNX8XXX_UART_FIFO_RXFE | + PNX8XXX_UART_FIFO_RXPAR) | + ISTAT_TO_SM(PNX8XXX_UART_INT_RXOVRN))) { + if (status & FIFO_TO_SM(PNX8XXX_UART_FIFO_RXPAR)) + sport->port.icount.parity++; + else if (status & FIFO_TO_SM(PNX8XXX_UART_FIFO_RXFE)) + sport->port.icount.frame++; + if (status & ISTAT_TO_SM(PNX8XXX_UART_INT_RXOVRN)) + sport->port.icount.overrun++; + + status &= sport->port.read_status_mask; + + if (status & FIFO_TO_SM(PNX8XXX_UART_FIFO_RXPAR)) + flg = TTY_PARITY; + else if (status & FIFO_TO_SM(PNX8XXX_UART_FIFO_RXFE)) + flg = TTY_FRAME; + +#ifdef SUPPORT_SYSRQ + sport->port.sysrq = 0; +#endif + } + + if (uart_handle_sysrq_char(&sport->port, ch)) + goto ignore_char; + + uart_insert_char(&sport->port, status, + ISTAT_TO_SM(PNX8XXX_UART_INT_RXOVRN), ch, flg); + + ignore_char: + serial_out(sport, PNX8XXX_LCR, serial_in(sport, PNX8XXX_LCR) | + PNX8XXX_UART_LCR_RX_NEXT); + status = FIFO_TO_SM(serial_in(sport, PNX8XXX_FIFO)) | + ISTAT_TO_SM(serial_in(sport, PNX8XXX_ISTAT)); + } + tty_flip_buffer_push(tty); +} + +static void pnx8xxx_tx_chars(struct pnx8xxx_port *sport) +{ + struct circ_buf *xmit = &sport->port.info->xmit; + + if (sport->port.x_char) { + serial_out(sport, PNX8XXX_FIFO, sport->port.x_char); + sport->port.icount.tx++; + sport->port.x_char = 0; + return; + } + + /* + * Check the modem control lines before + * transmitting anything. + */ + pnx8xxx_mctrl_check(sport); + + if (uart_circ_empty(xmit) || uart_tx_stopped(&sport->port)) { + pnx8xxx_stop_tx(&sport->port); + return; + } + + /* + * TX while bytes available + */ + while (((serial_in(sport, PNX8XXX_FIFO) & + PNX8XXX_UART_FIFO_TXFIFO) >> 16) < 16) { + serial_out(sport, PNX8XXX_FIFO, xmit->buf[xmit->tail]); + xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1); + sport->port.icount.tx++; + if (uart_circ_empty(xmit)) + break; + } + + if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) + uart_write_wakeup(&sport->port); + + if (uart_circ_empty(xmit)) + pnx8xxx_stop_tx(&sport->port); +} + +static irqreturn_t pnx8xxx_int(int irq, void *dev_id) +{ + struct pnx8xxx_port *sport = dev_id; + unsigned int status; + + spin_lock(&sport->port.lock); + /* Get the interrupts */ + status = serial_in(sport, PNX8XXX_ISTAT) & serial_in(sport, PNX8XXX_IEN); + + /* Break signal received */ + if (status & PNX8XXX_UART_INT_BREAK) { + sport->port.icount.brk++; + uart_handle_break(&sport->port); + } + + /* Byte received */ + if (status & PNX8XXX_UART_INT_RX) + pnx8xxx_rx_chars(sport); + + /* TX holding register empty - transmit a byte */ + if (status & PNX8XXX_UART_INT_TX) + pnx8xxx_tx_chars(sport); + + /* Clear the ISTAT register */ + serial_out(sport, PNX8XXX_ICLR, status); + + spin_unlock(&sport->port.lock); + return IRQ_HANDLED; +} + +/* + * Return TIOCSER_TEMT when transmitter is not busy. + */ +static unsigned int pnx8xxx_tx_empty(struct uart_port *port) +{ + struct pnx8xxx_port *sport = (struct pnx8xxx_port *)port; + + return serial_in(sport, PNX8XXX_FIFO) & PNX8XXX_UART_FIFO_TXFIFO_STA ? 0 : TIOCSER_TEMT; +} + +static unsigned int pnx8xxx_get_mctrl(struct uart_port *port) +{ + struct pnx8xxx_port *sport = (struct pnx8xxx_port *)port; + unsigned int mctrl = TIOCM_DSR; + unsigned int msr; + + /* REVISIT */ + + msr = serial_in(sport, PNX8XXX_MCR); + + mctrl |= msr & PNX8XXX_UART_MCR_CTS ? TIOCM_CTS : 0; + mctrl |= msr & PNX8XXX_UART_MCR_DCD ? TIOCM_CAR : 0; + + return mctrl; +} + +static void pnx8xxx_set_mctrl(struct uart_port *port, unsigned int mctrl) +{ +#if 0 /* FIXME */ + struct pnx8xxx_port *sport = (struct pnx8xxx_port *)port; + unsigned int msr; +#endif +} + +/* + * Interrupts always disabled. + */ +static void pnx8xxx_break_ctl(struct uart_port *port, int break_state) +{ + struct pnx8xxx_port *sport = (struct pnx8xxx_port *)port; + unsigned long flags; + unsigned int lcr; + + spin_lock_irqsave(&sport->port.lock, flags); + lcr = serial_in(sport, PNX8XXX_LCR); + if (break_state == -1) + lcr |= PNX8XXX_UART_LCR_TXBREAK; + else + lcr &= ~PNX8XXX_UART_LCR_TXBREAK; + serial_out(sport, PNX8XXX_LCR, lcr); + spin_unlock_irqrestore(&sport->port.lock, flags); +} + +static int pnx8xxx_startup(struct uart_port *port) +{ + struct pnx8xxx_port *sport = (struct pnx8xxx_port *)port; + int retval; + + /* + * Allocate the IRQ + */ + retval = request_irq(sport->port.irq, pnx8xxx_int, 0, + "pnx8xxx-uart", sport); + if (retval) + return retval; + + /* + * Finally, clear and enable interrupts + */ + + serial_out(sport, PNX8XXX_ICLR, PNX8XXX_UART_INT_ALLRX | + PNX8XXX_UART_INT_ALLTX); + + serial_out(sport, PNX8XXX_IEN, serial_in(sport, PNX8XXX_IEN) | + PNX8XXX_UART_INT_ALLRX | + PNX8XXX_UART_INT_ALLTX); + + /* + * Enable modem status interrupts + */ + spin_lock_irq(&sport->port.lock); + pnx8xxx_enable_ms(&sport->port); + spin_unlock_irq(&sport->port.lock); + + return 0; +} + +static void pnx8xxx_shutdown(struct uart_port *port) +{ + struct pnx8xxx_port *sport = (struct pnx8xxx_port *)port; + int lcr; + + /* + * Stop our timer. + */ + del_timer_sync(&sport->timer); + + /* + * Disable all interrupts + */ + serial_out(sport, PNX8XXX_IEN, 0); + + /* + * Reset the Tx and Rx FIFOS, disable the break condition + */ + lcr = serial_in(sport, PNX8XXX_LCR); + lcr &= ~PNX8XXX_UART_LCR_TXBREAK; + lcr |= PNX8XXX_UART_LCR_TX_RST | PNX8XXX_UART_LCR_RX_RST; + serial_out(sport, PNX8XXX_LCR, lcr); + + /* + * Clear all interrupts + */ + serial_out(sport, PNX8XXX_ICLR, PNX8XXX_UART_INT_ALLRX | + PNX8XXX_UART_INT_ALLTX); + + /* + * Free the interrupt + */ + free_irq(sport->port.irq, sport); +} + +static void +pnx8xxx_set_termios(struct uart_port *port, struct ktermios *termios, + struct ktermios *old) +{ + struct pnx8xxx_port *sport = (struct pnx8xxx_port *)port; + unsigned long flags; + unsigned int lcr_fcr, old_ien, baud, quot; + unsigned int old_csize = old ? old->c_cflag & CSIZE : CS8; + + /* + * We only support CS7 and CS8. + */ + while ((termios->c_cflag & CSIZE) != CS7 && + (termios->c_cflag & CSIZE) != CS8) { + termios->c_cflag &= ~CSIZE; + termios->c_cflag |= old_csize; + old_csize = CS8; + } + + if ((termios->c_cflag & CSIZE) == CS8) + lcr_fcr = PNX8XXX_UART_LCR_8BIT; + else + lcr_fcr = 0; + + if (termios->c_cflag & CSTOPB) + lcr_fcr |= PNX8XXX_UART_LCR_2STOPB; + if (termios->c_cflag & PARENB) { + lcr_fcr |= PNX8XXX_UART_LCR_PAREN; + if (!(termios->c_cflag & PARODD)) + lcr_fcr |= PNX8XXX_UART_LCR_PAREVN; + } + + /* + * Ask the core to calculate the divisor for us. + */ + baud = uart_get_baud_rate(port, termios, old, 0, port->uartclk/16); + quot = uart_get_divisor(port, baud); + + spin_lock_irqsave(&sport->port.lock, flags); + + sport->port.read_status_mask = ISTAT_TO_SM(PNX8XXX_UART_INT_RXOVRN) | + ISTAT_TO_SM(PNX8XXX_UART_INT_EMPTY) | + ISTAT_TO_SM(PNX8XXX_UART_INT_RX); + if (termios->c_iflag & INPCK) + sport->port.read_status_mask |= + FIFO_TO_SM(PNX8XXX_UART_FIFO_RXFE) | + FIFO_TO_SM(PNX8XXX_UART_FIFO_RXPAR); + if (termios->c_iflag & (BRKINT | PARMRK)) + sport->port.read_status_mask |= + ISTAT_TO_SM(PNX8XXX_UART_INT_BREAK); + + /* + * Characters to ignore + */ + sport->port.ignore_status_mask = 0; + if (termios->c_iflag & IGNPAR) + sport->port.ignore_status_mask |= + FIFO_TO_SM(PNX8XXX_UART_FIFO_RXFE) | + FIFO_TO_SM(PNX8XXX_UART_FIFO_RXPAR); + if (termios->c_iflag & IGNBRK) { + sport->port.ignore_status_mask |= + ISTAT_TO_SM(PNX8XXX_UART_INT_BREAK); + /* + * If we're ignoring parity and break indicators, + * ignore overruns too (for real raw support). + */ + if (termios->c_iflag & IGNPAR) + sport->port.ignore_status_mask |= + ISTAT_TO_SM(PNX8XXX_UART_INT_RXOVRN); + } + + /* + * ignore all characters if CREAD is not set + */ + if ((termios->c_cflag & CREAD) == 0) + sport->port.ignore_status_mask |= + ISTAT_TO_SM(PNX8XXX_UART_INT_RX); + + del_timer_sync(&sport->timer); + + /* + * Update the per-port timeout. + */ + uart_update_timeout(port, termios->c_cflag, baud); + + /* + * disable interrupts and drain transmitter + */ + old_ien = serial_in(sport, PNX8XXX_IEN); + serial_out(sport, PNX8XXX_IEN, old_ien & ~(PNX8XXX_UART_INT_ALLTX | + PNX8XXX_UART_INT_ALLRX)); + + while (serial_in(sport, PNX8XXX_FIFO) & PNX8XXX_UART_FIFO_TXFIFO_STA) + barrier(); + + /* then, disable everything */ + serial_out(sport, PNX8XXX_IEN, 0); + + /* Reset the Rx and Tx FIFOs too */ + lcr_fcr |= PNX8XXX_UART_LCR_TX_RST; + lcr_fcr |= PNX8XXX_UART_LCR_RX_RST; + + /* set the parity, stop bits and data size */ + serial_out(sport, PNX8XXX_LCR, lcr_fcr); + + /* set the baud rate */ + quot -= 1; + serial_out(sport, PNX8XXX_BAUD, quot); + + serial_out(sport, PNX8XXX_ICLR, -1); + + serial_out(sport, PNX8XXX_IEN, old_ien); + + if (UART_ENABLE_MS(&sport->port, termios->c_cflag)) + pnx8xxx_enable_ms(&sport->port); + + spin_unlock_irqrestore(&sport->port.lock, flags); +} + +static const char *pnx8xxx_type(struct uart_port *port) +{ + struct pnx8xxx_port *sport = (struct pnx8xxx_port *)port; + + return sport->port.type == PORT_PNX8XXX ? "PNX8XXX" : NULL; +} + +/* + * Release the memory region(s) being used by 'port'. + */ +static void pnx8xxx_release_port(struct uart_port *port) +{ + struct pnx8xxx_port *sport = (struct pnx8xxx_port *)port; + + release_mem_region(sport->port.mapbase, UART_PORT_SIZE); +} + +/* + * Request the memory region(s) being used by 'port'. + */ +static int pnx8xxx_request_port(struct uart_port *port) +{ + struct pnx8xxx_port *sport = (struct pnx8xxx_port *)port; + return request_mem_region(sport->port.mapbase, UART_PORT_SIZE, + "pnx8xxx-uart") != NULL ? 0 : -EBUSY; +} + +/* + * Configure/autoconfigure the port. + */ +static void pnx8xxx_config_port(struct uart_port *port, int flags) +{ + struct pnx8xxx_port *sport = (struct pnx8xxx_port *)port; + + if (flags & UART_CONFIG_TYPE && + pnx8xxx_request_port(&sport->port) == 0) + sport->port.type = PORT_PNX8XXX; +} + +/* + * Verify the new serial_struct (for TIOCSSERIAL). + * The only change we allow are to the flags and type, and + * even then only between PORT_PNX8XXX and PORT_UNKNOWN + */ +static int +pnx8xxx_verify_port(struct uart_port *port, struct serial_struct *ser) +{ + struct pnx8xxx_port *sport = (struct pnx8xxx_port *)port; + int ret = 0; + + if (ser->type != PORT_UNKNOWN && ser->type != PORT_PNX8XXX) + ret = -EINVAL; + if (sport->port.irq != ser->irq) + ret = -EINVAL; + if (ser->io_type != SERIAL_IO_MEM) + ret = -EINVAL; + if (sport->port.uartclk / 16 != ser->baud_base) + ret = -EINVAL; + if ((void *)sport->port.mapbase != ser->iomem_base) + ret = -EINVAL; + if (sport->port.iobase != ser->port) + ret = -EINVAL; + if (ser->hub6 != 0) + ret = -EINVAL; + return ret; +} + +static struct uart_ops pnx8xxx_pops = { + .tx_empty = pnx8xxx_tx_empty, + .set_mctrl = pnx8xxx_set_mctrl, + .get_mctrl = pnx8xxx_get_mctrl, + .stop_tx = pnx8xxx_stop_tx, + .start_tx = pnx8xxx_start_tx, + .stop_rx = pnx8xxx_stop_rx, + .enable_ms = pnx8xxx_enable_ms, + .break_ctl = pnx8xxx_break_ctl, + .startup = pnx8xxx_startup, + .shutdown = pnx8xxx_shutdown, + .set_termios = pnx8xxx_set_termios, + .type = pnx8xxx_type, + .release_port = pnx8xxx_release_port, + .request_port = pnx8xxx_request_port, + .config_port = pnx8xxx_config_port, + .verify_port = pnx8xxx_verify_port, +}; + + +/* + * Setup the PNX8XXX serial ports. + * + * Note also that we support "console=ttySx" where "x" is either 0 or 1. + */ +static void __init pnx8xxx_init_ports(void) +{ + static int first = 1; + int i; + + if (!first) + return; + first = 0; + + for (i = 0; i < NR_PORTS; i++) { + init_timer(&pnx8xxx_ports[i].timer); + pnx8xxx_ports[i].timer.function = pnx8xxx_timeout; + pnx8xxx_ports[i].timer.data = (unsigned long)&pnx8xxx_ports[i]; + pnx8xxx_ports[i].port.ops = &pnx8xxx_pops; + } +} + +#ifdef CONFIG_SERIAL_PNX8XXX_CONSOLE + +static void pnx8xxx_console_putchar(struct uart_port *port, int ch) +{ + struct pnx8xxx_port *sport = (struct pnx8xxx_port *)port; + int status; + + do { + /* Wait for UART_TX register to empty */ + status = serial_in(sport, PNX8XXX_FIFO); + } while (status & PNX8XXX_UART_FIFO_TXFIFO); + serial_out(sport, PNX8XXX_FIFO, ch); +} + +/* + * Interrupts are disabled on entering + */static void +pnx8xxx_console_write(struct console *co, const char *s, unsigned int count) +{ + struct pnx8xxx_port *sport = &pnx8xxx_ports[co->index]; + unsigned int old_ien, status; + + /* + * First, save IEN and then disable interrupts + */ + old_ien = serial_in(sport, PNX8XXX_IEN); + serial_out(sport, PNX8XXX_IEN, old_ien & ~(PNX8XXX_UART_INT_ALLTX | + PNX8XXX_UART_INT_ALLRX)); + + uart_console_write(&sport->port, s, count, pnx8xxx_console_putchar); + + /* + * Finally, wait for transmitter to become empty + * and restore IEN + */ + do { + /* Wait for UART_TX register to empty */ + status = serial_in(sport, PNX8XXX_FIFO); + } while (status & PNX8XXX_UART_FIFO_TXFIFO); + + /* Clear TX and EMPTY interrupt */ + serial_out(sport, PNX8XXX_ICLR, PNX8XXX_UART_INT_TX | + PNX8XXX_UART_INT_EMPTY); + + serial_out(sport, PNX8XXX_IEN, old_ien); +} + +static int __init +pnx8xxx_console_setup(struct console *co, char *options) +{ + struct pnx8xxx_port *sport; + int baud = 38400; + int bits = 8; + int parity = 'n'; + int flow = 'n'; + + /* + * Check whether an invalid uart number has been specified, and + * if so, search for the first available port that does have + * console support. + */ + if (co->index == -1 || co->index >= NR_PORTS) + co->index = 0; + sport = &pnx8xxx_ports[co->index]; + + if (options) + uart_parse_options(options, &baud, &parity, &bits, &flow); + + return uart_set_options(&sport->port, co, baud, parity, bits, flow); +} + +static struct uart_driver pnx8xxx_reg; +static struct console pnx8xxx_console = { + .name = "ttyS", + .write = pnx8xxx_console_write, + .device = uart_console_device, + .setup = pnx8xxx_console_setup, + .flags = CON_PRINTBUFFER, + .index = -1, + .data = &pnx8xxx_reg, +}; + +static int __init pnx8xxx_rs_console_init(void) +{ + pnx8xxx_init_ports(); + register_console(&pnx8xxx_console); + return 0; +} +console_initcall(pnx8xxx_rs_console_init); + +#define PNX8XXX_CONSOLE &pnx8xxx_console +#else +#define PNX8XXX_CONSOLE NULL +#endif + +static struct uart_driver pnx8xxx_reg = { + .owner = THIS_MODULE, + .driver_name = "ttyS", + .dev_name = "ttyS", + .major = SERIAL_PNX8XXX_MAJOR, + .minor = MINOR_START, + .nr = NR_PORTS, + .cons = PNX8XXX_CONSOLE, +}; + +static int pnx8xxx_serial_suspend(struct platform_device *pdev, pm_message_t state) +{ + struct pnx8xxx_port *sport = platform_get_drvdata(pdev); + + return uart_suspend_port(&pnx8xxx_reg, &sport->port); +} + +static int pnx8xxx_serial_resume(struct platform_device *pdev) +{ + struct pnx8xxx_port *sport = platform_get_drvdata(pdev); + + return uart_resume_port(&pnx8xxx_reg, &sport->port); +} + +static int pnx8xxx_serial_probe(struct platform_device *pdev) +{ + struct resource *res = pdev->resource; + int i; + + for (i = 0; i < pdev->num_resources; i++, res++) { + if (!(res->flags & IORESOURCE_MEM)) + continue; + + for (i = 0; i < NR_PORTS; i++) { + if (pnx8xxx_ports[i].port.mapbase != res->start) + continue; + + pnx8xxx_ports[i].port.dev = &pdev->dev; + uart_add_one_port(&pnx8xxx_reg, &pnx8xxx_ports[i].port); + platform_set_drvdata(pdev, &pnx8xxx_ports[i]); + break; + } + } + + return 0; +} + +static int pnx8xxx_serial_remove(struct platform_device *pdev) +{ + struct pnx8xxx_port *sport = platform_get_drvdata(pdev); + + platform_set_drvdata(pdev, NULL); + + if (sport) + uart_remove_one_port(&pnx8xxx_reg, &sport->port); + + return 0; +} + +static struct platform_driver pnx8xxx_serial_driver = { + .driver = { + .name = "pnx8xxx-uart", + .owner = THIS_MODULE, + }, + .probe = pnx8xxx_serial_probe, + .remove = pnx8xxx_serial_remove, + .suspend = pnx8xxx_serial_suspend, + .resume = pnx8xxx_serial_resume, +}; + +static int __init pnx8xxx_serial_init(void) +{ + int ret; + + printk(KERN_INFO "Serial: PNX8XXX driver $Revision: 1.2 $\n"); + + pnx8xxx_init_ports(); + + ret = uart_register_driver(&pnx8xxx_reg); + if (ret == 0) { + ret = platform_driver_register(&pnx8xxx_serial_driver); + if (ret) + uart_unregister_driver(&pnx8xxx_reg); + } + return ret; +} + +static void __exit pnx8xxx_serial_exit(void) +{ + platform_driver_unregister(&pnx8xxx_serial_driver); + uart_unregister_driver(&pnx8xxx_reg); +} + +module_init(pnx8xxx_serial_init); +module_exit(pnx8xxx_serial_exit); + +MODULE_AUTHOR("Embedded Alley Solutions, Inc."); +MODULE_DESCRIPTION("PNX8XXX SoCs serial port driver"); +MODULE_LICENSE("GPL"); +MODULE_ALIAS_CHARDEV_MAJOR(SERIAL_PNX8XXX_MAJOR); diff --git a/drivers/serial/serial_core.c b/drivers/serial/serial_core.c index f84982e..0422c0f 100644 --- a/drivers/serial/serial_core.c +++ b/drivers/serial/serial_core.c @@ -1523,9 +1523,8 @@ static struct uart_state *uart_get(struc } if (!state->info) { - state->info = kmalloc(sizeof(struct uart_info), GFP_KERNEL); + state->info = kzalloc(sizeof(struct uart_info), GFP_KERNEL); if (state->info) { - memset(state->info, 0, sizeof(struct uart_info)); init_waitqueue_head(&state->info->open_wait); init_waitqueue_head(&state->info->delta_msr_wait); @@ -1660,6 +1659,7 @@ #ifdef CONFIG_PROC_FS static int uart_line_info(char *buf, struct uart_driver *drv, int i) { struct uart_state *state = drv->state + i; + int pm_state; struct uart_port *port = state->port; char stat_buf[32]; unsigned int status; @@ -1682,9 +1682,16 @@ static int uart_line_info(char *buf, str if(capable(CAP_SYS_ADMIN)) { + mutex_lock(&state->mutex); + pm_state = state->pm_state; + if (pm_state) + uart_change_pm(state, 0); spin_lock_irq(&port->lock); status = port->ops->get_mctrl(port); spin_unlock_irq(&port->lock); + if (pm_state) + uart_change_pm(state, pm_state); + mutex_unlock(&state->mutex); ret += sprintf(buf + ret, " tx:%d rx:%d", port->icount.tx, port->icount.rx); @@ -2100,6 +2107,9 @@ uart_configure_port(struct uart_driver * uart_report_port(drv, port); + /* Power up port for set_mctrl() */ + uart_change_pm(state, 0); + /* * Ensure that the modem control lines are de-activated. * We probably don't need a spinlock around this, but @@ -2167,13 +2177,11 @@ int uart_register_driver(struct uart_dri * Maybe we should be using a slab cache for this, especially if * we have a large number of ports to handle. */ - drv->state = kmalloc(sizeof(struct uart_state) * drv->nr, GFP_KERNEL); + drv->state = kzalloc(sizeof(struct uart_state) * drv->nr, GFP_KERNEL); retval = -ENOMEM; if (!drv->state) goto out; - memset(drv->state, 0, sizeof(struct uart_state) * drv->nr); - normal = alloc_tty_driver(drv->nr); if (!normal) goto out; diff --git a/drivers/serial/serial_cs.c b/drivers/serial/serial_cs.c index 431433f..c2f1012 100644 --- a/drivers/serial/serial_cs.c +++ b/drivers/serial/serial_cs.c @@ -35,7 +35,6 @@ #include #include #include #include -#include #include #include #include @@ -334,10 +333,9 @@ static int serial_probe(struct pcmcia_de DEBUG(0, "serial_attach()\n"); /* Create new serial device */ - info = kmalloc(sizeof (*info), GFP_KERNEL); + info = kzalloc(sizeof (*info), GFP_KERNEL); if (!info) return -ENOMEM; - memset(info, 0, sizeof (*info)); info->p_dev = link; link->priv = info; diff --git a/drivers/serial/serial_txx9.c b/drivers/serial/serial_txx9.c index 7186a82..f4440d3 100644 --- a/drivers/serial/serial_txx9.c +++ b/drivers/serial/serial_txx9.c @@ -37,6 +37,7 @@ * 1.06 Do not insert a char caused previous overrun. * Fix some spin_locks. * Do not call uart_add_one_port for absent ports. + * 1.07 Use CONFIG_SERIAL_TXX9_NR_UARTS. Cleanup. */ #if defined(CONFIG_SERIAL_TXX9_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ) @@ -58,9 +59,8 @@ #include #include #include -#include -static char *serial_version = "1.06"; +static char *serial_version = "1.07"; static char *serial_name = "TX39/49 Serial driver"; #define PASS_LIMIT 256 @@ -88,12 +88,7 @@ #endif /* * Number of serial ports */ -#ifdef ENABLE_SERIAL_TXX9_PCI -#define NR_PCI_BOARDS 4 -#define UART_NR (4 + NR_PCI_BOARDS) -#else -#define UART_NR 4 -#endif +#define UART_NR CONFIG_SERIAL_TXX9_NR_UARTS #define HIGH_BITS_OFFSET ((sizeof(long)-sizeof(int))*8) @@ -987,6 +982,7 @@ int __init early_serial_txx9_setup(struc } #ifdef ENABLE_SERIAL_TXX9_PCI +#ifdef CONFIG_PM /** * serial_txx9_suspend_port - suspend one serial port * @line: serial line number @@ -1008,6 +1004,7 @@ static void serial_txx9_resume_port(int { uart_resume_port(&serial_txx9_reg, &serial_txx9_ports[line].port); } +#endif static DEFINE_MUTEX(serial_txx9_mutex); @@ -1118,6 +1115,7 @@ static void __devexit pciserial_txx9_rem } } +#ifdef CONFIG_PM static int pciserial_txx9_suspend_one(struct pci_dev *dev, pm_message_t state) { int line = (int)(long)pci_get_drvdata(dev); @@ -1142,11 +1140,10 @@ static int pciserial_txx9_resume_one(str } return 0; } +#endif -static struct pci_device_id serial_txx9_pci_tbl[] = { - { PCI_VENDOR_ID_TOSHIBA_2, PCI_DEVICE_ID_TOSHIBA_TC86C001_MISC, - PCI_ANY_ID, PCI_ANY_ID, - 0, 0, 0 }, +static const struct pci_device_id serial_txx9_pci_tbl[] = { + { PCI_DEVICE(PCI_VENDOR_ID_TOSHIBA_2, PCI_DEVICE_ID_TOSHIBA_TC86C001_MISC) }, { 0, } }; @@ -1154,8 +1151,10 @@ static struct pci_driver serial_txx9_pci .name = "serial_txx9", .probe = pciserial_txx9_init_one, .remove = __devexit_p(pciserial_txx9_remove_one), +#ifdef CONFIG_PM .suspend = pciserial_txx9_suspend_one, .resume = pciserial_txx9_resume_one, +#endif .id_table = serial_txx9_pci_tbl, }; diff --git a/drivers/serial/sunsab.c b/drivers/serial/sunsab.c index 145d623..deb9ab4 100644 --- a/drivers/serial/sunsab.c +++ b/drivers/serial/sunsab.c @@ -17,7 +17,6 @@ #include #include -#include #include #include #include diff --git a/drivers/serial/sunsu.c b/drivers/serial/sunsu.c index 3ec3df2..96a852a 100644 --- a/drivers/serial/sunsu.c +++ b/drivers/serial/sunsu.c @@ -17,7 +17,6 @@ #include #include -#include #include #include #include diff --git a/drivers/serial/sunzilog.c b/drivers/serial/sunzilog.c index 244f796..da73205 100644 --- a/drivers/serial/sunzilog.c +++ b/drivers/serial/sunzilog.c @@ -14,7 +14,6 @@ #include #include -#include #include #include #include diff --git a/drivers/serial/uartlite.c b/drivers/serial/uartlite.c index db8607e..f5051cf 100644 --- a/drivers/serial/uartlite.c +++ b/drivers/serial/uartlite.c @@ -256,7 +256,7 @@ static void ulite_release_port(struct ua { release_mem_region(port->mapbase, ULITE_REGION); iounmap(port->membase); - port->membase = 0; + port->membase = NULL; } static int ulite_request_port(struct uart_port *port) @@ -438,7 +438,7 @@ static int __devinit ulite_probe(struct port->iotype = UPIO_MEM; port->iobase = 1; /* mark port in use */ port->mapbase = res->start; - port->membase = 0; + port->membase = NULL; port->ops = &ulite_ops; port->irq = res2->start; port->flags = UPF_BOOT_AUTOCONF; @@ -462,7 +462,7 @@ static int ulite_remove(struct platform_ uart_remove_one_port(&ulite_uart_driver, port); /* mark port as free */ - port->membase = 0; + port->membase = NULL; return 0; } diff --git a/drivers/sn/ioc3.c b/drivers/sn/ioc3.c index cd6b653..2dd6eed 100644 --- a/drivers/sn/ioc3.c +++ b/drivers/sn/ioc3.c @@ -654,7 +654,7 @@ #endif ret = -ENODEV; goto out_pci; } - if (!request_region(idd->pma, IOC3_PCI_SIZE, "ioc3")) { + if (!request_mem_region(idd->pma, IOC3_PCI_SIZE, "ioc3")) { printk(KERN_WARNING "%s: Unable to request IOC3 region " "for pci_dev %s.\n", @@ -744,7 +744,7 @@ #endif return 0; out_misc_region: - release_region(idd->pma, IOC3_PCI_SIZE); + release_mem_region(idd->pma, IOC3_PCI_SIZE); out_pci: kfree(idd); out_idd: @@ -785,7 +785,7 @@ static void ioc3_remove(struct pci_dev * if(idd->dual_irq) free_irq(idd->irq_eth, (void *)idd); iounmap(idd->vma); - release_region(idd->pma, IOC3_PCI_SIZE); + release_mem_region(idd->pma, IOC3_PCI_SIZE); /* Disable IOC3 and relinquish */ pci_disable_device(pdev); diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig index d895a1a..7e54e48 100644 --- a/drivers/spi/Kconfig +++ b/drivers/spi/Kconfig @@ -51,6 +51,13 @@ # boolean "SPI Master Support" comment "SPI Master Controller Drivers" depends on SPI_MASTER +config SPI_ATMEL + tristate "Atmel SPI Controller" + depends on (ARCH_AT91 || AVR32) && SPI_MASTER + help + This selects a driver for the Atmel SPI Controller, present on + many AT32 (AVR32) and AT91 (ARM) chips. + config SPI_BITBANG tristate "Bitbanging SPI master" depends on SPI_MASTER && EXPERIMENTAL @@ -75,6 +82,13 @@ config SPI_BUTTERFLY inexpensive battery powered microcontroller evaluation board. This same cable can be used to flash new firmware. +config SPI_IMX + tristate "Freescale iMX SPI controller" + depends on SPI_MASTER && ARCH_IMX && EXPERIMENTAL + help + This enables using the Freescale iMX SPI controller in master + mode. + config SPI_MPC83xx tristate "Freescale MPC83xx SPI controller" depends on SPI_MASTER && PPC_83xx && EXPERIMENTAL @@ -87,6 +101,14 @@ config SPI_MPC83xx family of PowerPC processors. The MPC83xx uses a simple set of shift registers for data (opposed to the CPM based descriptor model). +config SPI_OMAP_UWIRE + tristate "OMAP1 MicroWire" + depends on SPI_MASTER && ARCH_OMAP1 + select SPI_BITBANG + help + This hooks up to the MicroWire controller on OMAP1 chips. + + config SPI_PXA2XX tristate "PXA2xx SSP SPI master" depends on SPI_MASTER && ARCH_PXA && EXPERIMENTAL @@ -95,6 +117,12 @@ config SPI_PXA2XX The driver can be configured to use any SSP port and additional documentation can be found a Documentation/spi/pxa2xx. +config SPI_S3C24XX + tristate "Samsung S3C24XX series SPI" + depends on SPI_MASTER && ARCH_S3C2410 && EXPERIMENTAL + help + SPI driver for Samsung S3C24XX series ARM SoCs + config SPI_S3C24XX_GPIO tristate "Samsung S3C24XX series SPI by GPIO" depends on SPI_MASTER && ARCH_S3C2410 && SPI_BITBANG && EXPERIMENTAL @@ -107,13 +135,6 @@ # # Add new SPI master controllers in alphabetical order above this line # - -config SPI_S3C24XX - tristate "Samsung S3C24XX series SPI" - depends on SPI_MASTER && ARCH_S3C2410 && EXPERIMENTAL - help - SPI driver for Samsung S3C24XX series ARM SoCs - # # There are lots of SPI device types, with sensors and memory # being probably the most widely used ones. @@ -121,6 +142,16 @@ # comment "SPI Protocol Masters" depends on SPI_MASTER +config SPI_AT25 + tristate "SPI EEPROMs from most vendors" + depends on SPI_MASTER && SYSFS + help + Enable this driver to get read/write support to most SPI EEPROMs, + after you configure the board init code to know about each eeprom + on your target board. + + This driver can also be built as a module. If so, the module + will be called at25. # # Add new SPI protocol masters in alphabetical order above this line diff --git a/drivers/spi/Makefile b/drivers/spi/Makefile index 8f4cb67..3c280ad 100644 --- a/drivers/spi/Makefile +++ b/drivers/spi/Makefile @@ -12,14 +12,18 @@ obj-$(CONFIG_SPI_MASTER) += spi.o # SPI master controller drivers (bus) obj-$(CONFIG_SPI_BITBANG) += spi_bitbang.o +obj-$(CONFIG_SPI_ATMEL) += atmel_spi.o obj-$(CONFIG_SPI_BUTTERFLY) += spi_butterfly.o +obj-$(CONFIG_SPI_IMX) += spi_imx.o obj-$(CONFIG_SPI_PXA2XX) += pxa2xx_spi.o +obj-$(CONFIG_SPI_OMAP_UWIRE) += omap_uwire.o obj-$(CONFIG_SPI_MPC83xx) += spi_mpc83xx.o obj-$(CONFIG_SPI_S3C24XX_GPIO) += spi_s3c24xx_gpio.o obj-$(CONFIG_SPI_S3C24XX) += spi_s3c24xx.o # ... add above this line ... # SPI protocol drivers (device/link on bus) +obj-$(CONFIG_SPI_AT25) += at25.o # ... add above this line ... # SPI slave controller drivers (upstream link) diff --git a/drivers/spi/at25.c b/drivers/spi/at25.c new file mode 100644 index 0000000..48e4f48 --- /dev/null +++ b/drivers/spi/at25.c @@ -0,0 +1,381 @@ +/* + * at25.c -- support most SPI EEPROMs, such as Atmel AT25 models + * + * Copyright (C) 2006 David Brownell + * + * 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 + + +struct at25_data { + struct spi_device *spi; + struct mutex lock; + struct spi_eeprom chip; + struct bin_attribute bin; + unsigned addrlen; +}; + +#define AT25_WREN 0x06 /* latch the write enable */ +#define AT25_WRDI 0x04 /* reset the write enable */ +#define AT25_RDSR 0x05 /* read status register */ +#define AT25_WRSR 0x01 /* write status register */ +#define AT25_READ 0x03 /* read byte(s) */ +#define AT25_WRITE 0x02 /* write byte(s)/sector */ + +#define AT25_SR_nRDY 0x01 /* nRDY = write-in-progress */ +#define AT25_SR_WEN 0x02 /* write enable (latched) */ +#define AT25_SR_BP0 0x04 /* BP for software writeprotect */ +#define AT25_SR_BP1 0x08 +#define AT25_SR_WPEN 0x80 /* writeprotect enable */ + + +#define EE_MAXADDRLEN 3 /* 24 bit addresses, up to 2 MBytes */ + +/* Specs often allow 5 msec for a page write, sometimes 20 msec; + * it's important to recover from write timeouts. + */ +#define EE_TIMEOUT 25 + +/*-------------------------------------------------------------------------*/ + +#define io_limit PAGE_SIZE /* bytes */ + +static ssize_t +at25_ee_read( + struct at25_data *at25, + char *buf, + unsigned offset, + size_t count +) +{ + u8 command[EE_MAXADDRLEN + 1]; + u8 *cp; + ssize_t status; + struct spi_transfer t[2]; + struct spi_message m; + + cp = command; + *cp++ = AT25_READ; + + /* 8/16/24-bit address is written MSB first */ + switch (at25->addrlen) { + default: /* case 3 */ + *cp++ = offset >> 16; + case 2: + *cp++ = offset >> 8; + case 1: + case 0: /* can't happen: for better codegen */ + *cp++ = offset >> 0; + } + + spi_message_init(&m); + memset(t, 0, sizeof t); + + t[0].tx_buf = command; + t[0].len = at25->addrlen + 1; + spi_message_add_tail(&t[0], &m); + + t[1].rx_buf = buf; + t[1].len = count; + spi_message_add_tail(&t[1], &m); + + mutex_lock(&at25->lock); + + /* Read it all at once. + * + * REVISIT that's potentially a problem with large chips, if + * other devices on the bus need to be accessed regularly or + * this chip is clocked very slowly + */ + status = spi_sync(at25->spi, &m); + dev_dbg(&at25->spi->dev, + "read %Zd bytes at %d --> %d\n", + count, offset, (int) status); + + mutex_unlock(&at25->lock); + return status ? status : count; +} + +static ssize_t +at25_bin_read(struct kobject *kobj, char *buf, loff_t off, size_t count) +{ + struct device *dev; + struct at25_data *at25; + + dev = container_of(kobj, struct device, kobj); + at25 = dev_get_drvdata(dev); + + if (unlikely(off >= at25->bin.size)) + return 0; + if ((off + count) > at25->bin.size) + count = at25->bin.size - off; + if (unlikely(!count)) + return count; + + return at25_ee_read(at25, buf, off, count); +} + + +static ssize_t +at25_ee_write(struct at25_data *at25, char *buf, loff_t off, size_t count) +{ + ssize_t status = 0; + unsigned written = 0; + unsigned buf_size; + u8 *bounce; + + /* Temp buffer starts with command and address */ + buf_size = at25->chip.page_size; + if (buf_size > io_limit) + buf_size = io_limit; + bounce = kmalloc(buf_size + at25->addrlen + 1, GFP_KERNEL); + if (!bounce) + return -ENOMEM; + + /* For write, rollover is within the page ... so we write at + * most one page, then manually roll over to the next page. + */ + bounce[0] = AT25_WRITE; + mutex_lock(&at25->lock); + do { + unsigned long timeout, retries; + unsigned segment; + unsigned offset = (unsigned) off; + u8 *cp = bounce + 1; + + *cp = AT25_WREN; + status = spi_write(at25->spi, cp, 1); + if (status < 0) { + dev_dbg(&at25->spi->dev, "WREN --> %d\n", + (int) status); + break; + } + + /* 8/16/24-bit address is written MSB first */ + switch (at25->addrlen) { + default: /* case 3 */ + *cp++ = offset >> 16; + case 2: + *cp++ = offset >> 8; + case 1: + case 0: /* can't happen: for better codegen */ + *cp++ = offset >> 0; + } + + /* Write as much of a page as we can */ + segment = buf_size - (offset % buf_size); + if (segment > count) + segment = count; + memcpy(cp, buf, segment); + status = spi_write(at25->spi, bounce, + segment + at25->addrlen + 1); + dev_dbg(&at25->spi->dev, + "write %u bytes at %u --> %d\n", + segment, offset, (int) status); + if (status < 0) + break; + + /* REVISIT this should detect (or prevent) failed writes + * to readonly sections of the EEPROM... + */ + + /* Wait for non-busy status */ + timeout = jiffies + msecs_to_jiffies(EE_TIMEOUT); + retries = 0; + do { + int sr; + + sr = spi_w8r8(at25->spi, AT25_RDSR); + if (sr < 0 || (sr & AT25_SR_nRDY)) { + dev_dbg(&at25->spi->dev, + "rdsr --> %d (%02x)\n", sr, sr); + /* at HZ=100, this is sloooow */ + msleep(1); + continue; + } + if (!(sr & AT25_SR_nRDY)) + break; + } while (retries++ < 3 || time_before_eq(jiffies, timeout)); + + if (time_after(jiffies, timeout)) { + dev_err(&at25->spi->dev, + "write %d bytes offset %d, " + "timeout after %u msecs\n", + segment, offset, + jiffies_to_msecs(jiffies - + (timeout - EE_TIMEOUT))); + status = -ETIMEDOUT; + break; + } + + off += segment; + buf += segment; + count -= segment; + written += segment; + + } while (count > 0); + + mutex_unlock(&at25->lock); + + kfree(bounce); + return written ? written : status; +} + +static ssize_t +at25_bin_write(struct kobject *kobj, char *buf, loff_t off, size_t count) +{ + struct device *dev; + struct at25_data *at25; + + dev = container_of(kobj, struct device, kobj); + at25 = dev_get_drvdata(dev); + + if (unlikely(off >= at25->bin.size)) + return -EFBIG; + if ((off + count) > at25->bin.size) + count = at25->bin.size - off; + if (unlikely(!count)) + return count; + + return at25_ee_write(at25, buf, off, count); +} + +/*-------------------------------------------------------------------------*/ + +static int at25_probe(struct spi_device *spi) +{ + struct at25_data *at25 = NULL; + const struct spi_eeprom *chip; + int err; + int sr; + int addrlen; + + /* Chip description */ + chip = spi->dev.platform_data; + if (!chip) { + dev_dbg(&spi->dev, "no chip description\n"); + err = -ENODEV; + goto fail; + } + + /* For now we only support 8/16/24 bit addressing */ + if (chip->flags & EE_ADDR1) + addrlen = 1; + else if (chip->flags & EE_ADDR2) + addrlen = 2; + else if (chip->flags & EE_ADDR3) + addrlen = 3; + else { + dev_dbg(&spi->dev, "unsupported address type\n"); + err = -EINVAL; + goto fail; + } + + /* Ping the chip ... the status register is pretty portable, + * unlike probing manufacturer IDs. We do expect that system + * firmware didn't write it in the past few milliseconds! + */ + sr = spi_w8r8(spi, AT25_RDSR); + if (sr < 0 || sr & AT25_SR_nRDY) { + dev_dbg(&at25->spi->dev, "rdsr --> %d (%02x)\n", sr, sr); + err = -ENXIO; + goto fail; + } + + if (!(at25 = kzalloc(sizeof *at25, GFP_KERNEL))) { + err = -ENOMEM; + goto fail; + } + + mutex_init(&at25->lock); + at25->chip = *chip; + at25->spi = spi_dev_get(spi); + dev_set_drvdata(&spi->dev, at25); + at25->addrlen = addrlen; + + /* Export the EEPROM bytes through sysfs, since that's convenient. + * Default to root-only access to the data; EEPROMs often hold data + * that's sensitive for read and/or write, like ethernet addresses, + * security codes, board-specific manufacturing calibrations, etc. + */ + at25->bin.attr.name = "eeprom"; + at25->bin.attr.mode = S_IRUSR; + at25->bin.attr.owner = THIS_MODULE; + at25->bin.read = at25_bin_read; + + at25->bin.size = at25->chip.byte_len; + if (!(chip->flags & EE_READONLY)) { + at25->bin.write = at25_bin_write; + at25->bin.attr.mode |= S_IWUSR; + } + + err = sysfs_create_bin_file(&spi->dev.kobj, &at25->bin); + if (err) + goto fail; + + dev_info(&spi->dev, "%Zd %s %s eeprom%s, pagesize %u\n", + (at25->bin.size < 1024) + ? at25->bin.size + : (at25->bin.size / 1024), + (at25->bin.size < 1024) ? "Byte" : "KByte", + at25->chip.name, + (chip->flags & EE_READONLY) ? " (readonly)" : "", + at25->chip.page_size); + return 0; +fail: + dev_dbg(&spi->dev, "probe err %d\n", err); + kfree(at25); + return err; +} + +static int __devexit at25_remove(struct spi_device *spi) +{ + struct at25_data *at25; + + at25 = dev_get_drvdata(&spi->dev); + sysfs_remove_bin_file(&spi->dev.kobj, &at25->bin); + kfree(at25); + return 0; +} + +/*-------------------------------------------------------------------------*/ + +static struct spi_driver at25_driver = { + .driver = { + .name = "at25", + .owner = THIS_MODULE, + }, + .probe = at25_probe, + .remove = __devexit_p(at25_remove), +}; + +static int __init at25_init(void) +{ + return spi_register_driver(&at25_driver); +} +module_init(at25_init); + +static void __exit at25_exit(void) +{ + spi_unregister_driver(&at25_driver); +} +module_exit(at25_exit); + +MODULE_DESCRIPTION("Driver for most SPI EEPROMs"); +MODULE_AUTHOR("David Brownell"); +MODULE_LICENSE("GPL"); + diff --git a/drivers/spi/atmel_spi.c b/drivers/spi/atmel_spi.c new file mode 100644 index 0000000..c2a9fef --- /dev/null +++ b/drivers/spi/atmel_spi.c @@ -0,0 +1,678 @@ +/* + * Driver for Atmel AT32 and AT91 SPI Controllers + * + * Copyright (C) 2006 Atmel Corporation + * + * 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 "atmel_spi.h" + +/* + * The core SPI transfer engine just talks to a register bank to set up + * DMA transfers; transfer queue progress is driven by IRQs. The clock + * framework provides the base clock, subdivided for each spi_device. + * + * Newer controllers, marked with "new_1" flag, have: + * - CR.LASTXFER + * - SPI_MR.DIV32 may become FDIV or must-be-zero (here: always zero) + * - SPI_SR.TXEMPTY, SPI_SR.NSSR (and corresponding irqs) + * - SPI_CSRx.CSAAT + * - SPI_CSRx.SBCR allows faster clocking + */ +struct atmel_spi { + spinlock_t lock; + + void __iomem *regs; + int irq; + struct clk *clk; + struct platform_device *pdev; + unsigned new_1:1; + + u8 stopping; + struct list_head queue; + struct spi_transfer *current_transfer; + unsigned long remaining_bytes; + + void *buffer; + dma_addr_t buffer_dma; +}; + +#define BUFFER_SIZE PAGE_SIZE +#define INVALID_DMA_ADDRESS 0xffffffff + +/* + * Earlier SPI controllers (e.g. on at91rm9200) have a design bug whereby + * they assume that spi slave device state will not change on deselect, so + * that automagic deselection is OK. Not so! Workaround uses nCSx pins + * as GPIOs; or newer controllers have CSAAT and friends. + * + * Since the CSAAT functionality is a bit weird on newer controllers + * as well, we use GPIO to control nCSx pins on all controllers. + */ + +static inline void cs_activate(struct spi_device *spi) +{ + unsigned gpio = (unsigned) spi->controller_data; + unsigned active = spi->mode & SPI_CS_HIGH; + + dev_dbg(&spi->dev, "activate %u%s\n", gpio, active ? " (high)" : ""); + gpio_set_value(gpio, active); +} + +static inline void cs_deactivate(struct spi_device *spi) +{ + unsigned gpio = (unsigned) spi->controller_data; + unsigned active = spi->mode & SPI_CS_HIGH; + + dev_dbg(&spi->dev, "DEactivate %u%s\n", gpio, active ? " (low)" : ""); + gpio_set_value(gpio, !active); +} + +/* + * Submit next transfer for DMA. + * lock is held, spi irq is blocked + */ +static void atmel_spi_next_xfer(struct spi_master *master, + struct spi_message *msg) +{ + struct atmel_spi *as = spi_master_get_devdata(master); + struct spi_transfer *xfer; + u32 len; + dma_addr_t tx_dma, rx_dma; + + xfer = as->current_transfer; + if (!xfer || as->remaining_bytes == 0) { + if (xfer) + xfer = list_entry(xfer->transfer_list.next, + struct spi_transfer, transfer_list); + else + xfer = list_entry(msg->transfers.next, + struct spi_transfer, transfer_list); + as->remaining_bytes = xfer->len; + as->current_transfer = xfer; + } + + len = as->remaining_bytes; + + tx_dma = xfer->tx_dma; + rx_dma = xfer->rx_dma; + + /* use scratch buffer only when rx or tx data is unspecified */ + if (rx_dma == INVALID_DMA_ADDRESS) { + rx_dma = as->buffer_dma; + if (len > BUFFER_SIZE) + len = BUFFER_SIZE; + } + if (tx_dma == INVALID_DMA_ADDRESS) { + tx_dma = as->buffer_dma; + if (len > BUFFER_SIZE) + len = BUFFER_SIZE; + memset(as->buffer, 0, len); + dma_sync_single_for_device(&as->pdev->dev, + as->buffer_dma, len, DMA_TO_DEVICE); + } + + spi_writel(as, RPR, rx_dma); + spi_writel(as, TPR, tx_dma); + + as->remaining_bytes -= len; + if (msg->spi->bits_per_word > 8) + len >>= 1; + + /* REVISIT: when xfer->delay_usecs == 0, the PDC "next transfer" + * mechanism might help avoid the IRQ latency between transfers + * + * We're also waiting for ENDRX before we start the next + * transfer because we need to handle some difficult timing + * issues otherwise. If we wait for ENDTX in one transfer and + * then starts waiting for ENDRX in the next, it's difficult + * to tell the difference between the ENDRX interrupt we're + * actually waiting for and the ENDRX interrupt of the + * previous transfer. + * + * It should be doable, though. Just not now... + */ + spi_writel(as, TNCR, 0); + spi_writel(as, RNCR, 0); + spi_writel(as, IER, SPI_BIT(ENDRX) | SPI_BIT(OVRES)); + + dev_dbg(&msg->spi->dev, + " start xfer %p: len %u tx %p/%08x rx %p/%08x imr %03x\n", + xfer, xfer->len, xfer->tx_buf, xfer->tx_dma, + xfer->rx_buf, xfer->rx_dma, spi_readl(as, IMR)); + + spi_writel(as, TCR, len); + spi_writel(as, RCR, len); + spi_writel(as, PTCR, SPI_BIT(TXTEN) | SPI_BIT(RXTEN)); +} + +static void atmel_spi_next_message(struct spi_master *master) +{ + struct atmel_spi *as = spi_master_get_devdata(master); + struct spi_message *msg; + u32 mr; + + BUG_ON(as->current_transfer); + + msg = list_entry(as->queue.next, struct spi_message, queue); + + /* Select the chip */ + mr = spi_readl(as, MR); + mr = SPI_BFINS(PCS, ~(1 << msg->spi->chip_select), mr); + spi_writel(as, MR, mr); + cs_activate(msg->spi); + + atmel_spi_next_xfer(master, msg); +} + +static void +atmel_spi_dma_map_xfer(struct atmel_spi *as, struct spi_transfer *xfer) +{ + xfer->tx_dma = xfer->rx_dma = INVALID_DMA_ADDRESS; + if (xfer->tx_buf) + xfer->tx_dma = dma_map_single(&as->pdev->dev, + (void *) xfer->tx_buf, xfer->len, + DMA_TO_DEVICE); + if (xfer->rx_buf) + xfer->rx_dma = dma_map_single(&as->pdev->dev, + xfer->rx_buf, xfer->len, + DMA_FROM_DEVICE); +} + +static void atmel_spi_dma_unmap_xfer(struct spi_master *master, + struct spi_transfer *xfer) +{ + if (xfer->tx_dma != INVALID_DMA_ADDRESS) + dma_unmap_single(master->cdev.dev, xfer->tx_dma, + xfer->len, DMA_TO_DEVICE); + if (xfer->rx_dma != INVALID_DMA_ADDRESS) + dma_unmap_single(master->cdev.dev, xfer->rx_dma, + xfer->len, DMA_FROM_DEVICE); +} + +static void +atmel_spi_msg_done(struct spi_master *master, struct atmel_spi *as, + struct spi_message *msg, int status) +{ + cs_deactivate(msg->spi); + list_del(&msg->queue); + msg->status = status; + + dev_dbg(master->cdev.dev, + "xfer complete: %u bytes transferred\n", + msg->actual_length); + + spin_unlock(&as->lock); + msg->complete(msg->context); + spin_lock(&as->lock); + + as->current_transfer = NULL; + + /* continue if needed */ + if (list_empty(&as->queue) || as->stopping) + spi_writel(as, PTCR, SPI_BIT(RXTDIS) | SPI_BIT(TXTDIS)); + else + atmel_spi_next_message(master); +} + +static irqreturn_t +atmel_spi_interrupt(int irq, void *dev_id) +{ + struct spi_master *master = dev_id; + struct atmel_spi *as = spi_master_get_devdata(master); + struct spi_message *msg; + struct spi_transfer *xfer; + u32 status, pending, imr; + int ret = IRQ_NONE; + + spin_lock(&as->lock); + + xfer = as->current_transfer; + msg = list_entry(as->queue.next, struct spi_message, queue); + + imr = spi_readl(as, IMR); + status = spi_readl(as, SR); + pending = status & imr; + + if (pending & SPI_BIT(OVRES)) { + int timeout; + + ret = IRQ_HANDLED; + + spi_writel(as, IDR, (SPI_BIT(ENDTX) | SPI_BIT(ENDRX) + | SPI_BIT(OVRES))); + + /* + * When we get an overrun, we disregard the current + * transfer. Data will not be copied back from any + * bounce buffer and msg->actual_len will not be + * updated with the last xfer. + * + * We will also not process any remaning transfers in + * the message. + * + * First, stop the transfer and unmap the DMA buffers. + */ + spi_writel(as, PTCR, SPI_BIT(RXTDIS) | SPI_BIT(TXTDIS)); + if (!msg->is_dma_mapped) + atmel_spi_dma_unmap_xfer(master, xfer); + + /* REVISIT: udelay in irq is unfriendly */ + if (xfer->delay_usecs) + udelay(xfer->delay_usecs); + + dev_warn(master->cdev.dev, "fifo overrun (%u/%u remaining)\n", + spi_readl(as, TCR), spi_readl(as, RCR)); + + /* + * Clean up DMA registers and make sure the data + * registers are empty. + */ + spi_writel(as, RNCR, 0); + spi_writel(as, TNCR, 0); + spi_writel(as, RCR, 0); + spi_writel(as, TCR, 0); + for (timeout = 1000; timeout; timeout--) + if (spi_readl(as, SR) & SPI_BIT(TXEMPTY)) + break; + if (!timeout) + dev_warn(master->cdev.dev, + "timeout waiting for TXEMPTY"); + while (spi_readl(as, SR) & SPI_BIT(RDRF)) + spi_readl(as, RDR); + + /* Clear any overrun happening while cleaning up */ + spi_readl(as, SR); + + atmel_spi_msg_done(master, as, msg, -EIO); + } else if (pending & SPI_BIT(ENDRX)) { + ret = IRQ_HANDLED; + + spi_writel(as, IDR, pending); + + if (as->remaining_bytes == 0) { + msg->actual_length += xfer->len; + + if (!msg->is_dma_mapped) + atmel_spi_dma_unmap_xfer(master, xfer); + + /* REVISIT: udelay in irq is unfriendly */ + if (xfer->delay_usecs) + udelay(xfer->delay_usecs); + + if (msg->transfers.prev == &xfer->transfer_list) { + /* report completed message */ + atmel_spi_msg_done(master, as, msg, 0); + } else { + if (xfer->cs_change) { + cs_deactivate(msg->spi); + udelay(1); + cs_activate(msg->spi); + } + + /* + * Not done yet. Submit the next transfer. + * + * FIXME handle protocol options for xfer + */ + atmel_spi_next_xfer(master, msg); + } + } else { + /* + * Keep going, we still have data to send in + * the current transfer. + */ + atmel_spi_next_xfer(master, msg); + } + } + + spin_unlock(&as->lock); + + return ret; +} + +#define MODEBITS (SPI_CPOL | SPI_CPHA | SPI_CS_HIGH) + +static int atmel_spi_setup(struct spi_device *spi) +{ + struct atmel_spi *as; + u32 scbr, csr; + unsigned int bits = spi->bits_per_word; + unsigned long bus_hz, sck_hz; + unsigned int npcs_pin; + int ret; + + as = spi_master_get_devdata(spi->master); + + if (as->stopping) + return -ESHUTDOWN; + + if (spi->chip_select > spi->master->num_chipselect) { + dev_dbg(&spi->dev, + "setup: invalid chipselect %u (%u defined)\n", + spi->chip_select, spi->master->num_chipselect); + return -EINVAL; + } + + if (bits == 0) + bits = 8; + if (bits < 8 || bits > 16) { + dev_dbg(&spi->dev, + "setup: invalid bits_per_word %u (8 to 16)\n", + bits); + return -EINVAL; + } + + if (spi->mode & ~MODEBITS) { + dev_dbg(&spi->dev, "setup: unsupported mode bits %x\n", + spi->mode & ~MODEBITS); + return -EINVAL; + } + + /* speed zero convention is used by some upper layers */ + bus_hz = clk_get_rate(as->clk); + if (spi->max_speed_hz) { + /* assume div32/fdiv/mbz == 0 */ + if (!as->new_1) + bus_hz /= 2; + scbr = ((bus_hz + spi->max_speed_hz - 1) + / spi->max_speed_hz); + if (scbr >= (1 << SPI_SCBR_SIZE)) { + dev_dbg(&spi->dev, "setup: %d Hz too slow, scbr %u\n", + spi->max_speed_hz, scbr); + return -EINVAL; + } + } else + scbr = 0xff; + sck_hz = bus_hz / scbr; + + csr = SPI_BF(SCBR, scbr) | SPI_BF(BITS, bits - 8); + if (spi->mode & SPI_CPOL) + csr |= SPI_BIT(CPOL); + if (!(spi->mode & SPI_CPHA)) + csr |= SPI_BIT(NCPHA); + + /* TODO: DLYBS and DLYBCT */ + csr |= SPI_BF(DLYBS, 10); + csr |= SPI_BF(DLYBCT, 10); + + /* chipselect must have been muxed as GPIO (e.g. in board setup) */ + npcs_pin = (unsigned int)spi->controller_data; + if (!spi->controller_state) { + ret = gpio_request(npcs_pin, "spi_npcs"); + if (ret) + return ret; + spi->controller_state = (void *)npcs_pin; + gpio_direction_output(npcs_pin); + } + + dev_dbg(&spi->dev, + "setup: %lu Hz bpw %u mode 0x%x -> csr%d %08x\n", + sck_hz, bits, spi->mode, spi->chip_select, csr); + + spi_writel(as, CSR0 + 4 * spi->chip_select, csr); + + return 0; +} + +static int atmel_spi_transfer(struct spi_device *spi, struct spi_message *msg) +{ + struct atmel_spi *as; + struct spi_transfer *xfer; + unsigned long flags; + struct device *controller = spi->master->cdev.dev; + + as = spi_master_get_devdata(spi->master); + + dev_dbg(controller, "new message %p submitted for %s\n", + msg, spi->dev.bus_id); + + if (unlikely(list_empty(&msg->transfers) + || !spi->max_speed_hz)) + return -EINVAL; + + if (as->stopping) + return -ESHUTDOWN; + + list_for_each_entry(xfer, &msg->transfers, transfer_list) { + if (!(xfer->tx_buf || xfer->rx_buf)) { + dev_dbg(&spi->dev, "missing rx or tx buf\n"); + return -EINVAL; + } + + /* FIXME implement these protocol options!! */ + if (xfer->bits_per_word || xfer->speed_hz) { + dev_dbg(&spi->dev, "no protocol options yet\n"); + return -ENOPROTOOPT; + } + } + + /* scrub dcache "early" */ + if (!msg->is_dma_mapped) { + list_for_each_entry(xfer, &msg->transfers, transfer_list) + atmel_spi_dma_map_xfer(as, xfer); + } + + list_for_each_entry(xfer, &msg->transfers, transfer_list) { + dev_dbg(controller, + " xfer %p: len %u tx %p/%08x rx %p/%08x\n", + xfer, xfer->len, + xfer->tx_buf, xfer->tx_dma, + xfer->rx_buf, xfer->rx_dma); + } + + msg->status = -EINPROGRESS; + msg->actual_length = 0; + + spin_lock_irqsave(&as->lock, flags); + list_add_tail(&msg->queue, &as->queue); + if (!as->current_transfer) + atmel_spi_next_message(spi->master); + spin_unlock_irqrestore(&as->lock, flags); + + return 0; +} + +static void atmel_spi_cleanup(const struct spi_device *spi) +{ + if (spi->controller_state) + gpio_free((unsigned int)spi->controller_data); +} + +/*-------------------------------------------------------------------------*/ + +static int __init atmel_spi_probe(struct platform_device *pdev) +{ + struct resource *regs; + int irq; + struct clk *clk; + int ret; + struct spi_master *master; + struct atmel_spi *as; + + regs = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!regs) + return -ENXIO; + + irq = platform_get_irq(pdev, 0); + if (irq < 0) + return irq; + + clk = clk_get(&pdev->dev, "spi_clk"); + if (IS_ERR(clk)) + return PTR_ERR(clk); + + /* setup spi core then atmel-specific driver state */ + ret = -ENOMEM; + master = spi_alloc_master(&pdev->dev, sizeof *as); + if (!master) + goto out_free; + + master->bus_num = pdev->id; + master->num_chipselect = 4; + master->setup = atmel_spi_setup; + master->transfer = atmel_spi_transfer; + master->cleanup = atmel_spi_cleanup; + platform_set_drvdata(pdev, master); + + as = spi_master_get_devdata(master); + + as->buffer = dma_alloc_coherent(&pdev->dev, BUFFER_SIZE, + &as->buffer_dma, GFP_KERNEL); + if (!as->buffer) + goto out_free; + + spin_lock_init(&as->lock); + INIT_LIST_HEAD(&as->queue); + as->pdev = pdev; + as->regs = ioremap(regs->start, (regs->end - regs->start) + 1); + if (!as->regs) + goto out_free_buffer; + as->irq = irq; + as->clk = clk; +#ifdef CONFIG_ARCH_AT91 + if (!cpu_is_at91rm9200()) + as->new_1 = 1; +#endif + + ret = request_irq(irq, atmel_spi_interrupt, 0, + pdev->dev.bus_id, master); + if (ret) + goto out_unmap_regs; + + /* Initialize the hardware */ + clk_enable(clk); + spi_writel(as, CR, SPI_BIT(SWRST)); + spi_writel(as, MR, SPI_BIT(MSTR) | SPI_BIT(MODFDIS)); + spi_writel(as, PTCR, SPI_BIT(RXTDIS) | SPI_BIT(TXTDIS)); + spi_writel(as, CR, SPI_BIT(SPIEN)); + + /* go! */ + dev_info(&pdev->dev, "Atmel SPI Controller at 0x%08lx (irq %d)\n", + (unsigned long)regs->start, irq); + + ret = spi_register_master(master); + if (ret) + goto out_reset_hw; + + return 0; + +out_reset_hw: + spi_writel(as, CR, SPI_BIT(SWRST)); + clk_disable(clk); + free_irq(irq, master); +out_unmap_regs: + iounmap(as->regs); +out_free_buffer: + dma_free_coherent(&pdev->dev, BUFFER_SIZE, as->buffer, + as->buffer_dma); +out_free: + clk_put(clk); + spi_master_put(master); + return ret; +} + +static int __exit atmel_spi_remove(struct platform_device *pdev) +{ + struct spi_master *master = platform_get_drvdata(pdev); + struct atmel_spi *as = spi_master_get_devdata(master); + struct spi_message *msg; + + /* reset the hardware and block queue progress */ + spin_lock_irq(&as->lock); + as->stopping = 1; + spi_writel(as, CR, SPI_BIT(SWRST)); + spi_readl(as, SR); + spin_unlock_irq(&as->lock); + + /* Terminate remaining queued transfers */ + list_for_each_entry(msg, &as->queue, queue) { + /* REVISIT unmapping the dma is a NOP on ARM and AVR32 + * but we shouldn't depend on that... + */ + msg->status = -ESHUTDOWN; + msg->complete(msg->context); + } + + dma_free_coherent(&pdev->dev, BUFFER_SIZE, as->buffer, + as->buffer_dma); + + clk_disable(as->clk); + clk_put(as->clk); + free_irq(as->irq, master); + iounmap(as->regs); + + spi_unregister_master(master); + + return 0; +} + +#ifdef CONFIG_PM + +static int atmel_spi_suspend(struct platform_device *pdev, pm_message_t mesg) +{ + struct spi_master *master = platform_get_drvdata(pdev); + struct atmel_spi *as = spi_master_get_devdata(master); + + clk_disable(as->clk); + return 0; +} + +static int atmel_spi_resume(struct platform_device *pdev) +{ + struct spi_master *master = platform_get_drvdata(pdev); + struct atmel_spi *as = spi_master_get_devdata(master); + + clk_enable(as->clk); + return 0; +} + +#else +#define atmel_spi_suspend NULL +#define atmel_spi_resume NULL +#endif + + +static struct platform_driver atmel_spi_driver = { + .driver = { + .name = "atmel_spi", + .owner = THIS_MODULE, + }, + .suspend = atmel_spi_suspend, + .resume = atmel_spi_resume, + .remove = __exit_p(atmel_spi_remove), +}; + +static int __init atmel_spi_init(void) +{ + return platform_driver_probe(&atmel_spi_driver, atmel_spi_probe); +} +module_init(atmel_spi_init); + +static void __exit atmel_spi_exit(void) +{ + platform_driver_unregister(&atmel_spi_driver); +} +module_exit(atmel_spi_exit); + +MODULE_DESCRIPTION("Atmel AT32/AT91 SPI Controller driver"); +MODULE_AUTHOR("Haavard Skinnemoen "); +MODULE_LICENSE("GPL"); diff --git a/drivers/spi/atmel_spi.h b/drivers/spi/atmel_spi.h new file mode 100644 index 0000000..6e06b6a --- /dev/null +++ b/drivers/spi/atmel_spi.h @@ -0,0 +1,167 @@ +/* + * Register definitions for Atmel Serial Peripheral Interface (SPI) + * + * Copyright (C) 2006 Atmel Corporation + * + * 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 __ATMEL_SPI_H__ +#define __ATMEL_SPI_H__ + +/* SPI register offsets */ +#define SPI_CR 0x0000 +#define SPI_MR 0x0004 +#define SPI_RDR 0x0008 +#define SPI_TDR 0x000c +#define SPI_SR 0x0010 +#define SPI_IER 0x0014 +#define SPI_IDR 0x0018 +#define SPI_IMR 0x001c +#define SPI_CSR0 0x0030 +#define SPI_CSR1 0x0034 +#define SPI_CSR2 0x0038 +#define SPI_CSR3 0x003c +#define SPI_RPR 0x0100 +#define SPI_RCR 0x0104 +#define SPI_TPR 0x0108 +#define SPI_TCR 0x010c +#define SPI_RNPR 0x0110 +#define SPI_RNCR 0x0114 +#define SPI_TNPR 0x0118 +#define SPI_TNCR 0x011c +#define SPI_PTCR 0x0120 +#define SPI_PTSR 0x0124 + +/* Bitfields in CR */ +#define SPI_SPIEN_OFFSET 0 +#define SPI_SPIEN_SIZE 1 +#define SPI_SPIDIS_OFFSET 1 +#define SPI_SPIDIS_SIZE 1 +#define SPI_SWRST_OFFSET 7 +#define SPI_SWRST_SIZE 1 +#define SPI_LASTXFER_OFFSET 24 +#define SPI_LASTXFER_SIZE 1 + +/* Bitfields in MR */ +#define SPI_MSTR_OFFSET 0 +#define SPI_MSTR_SIZE 1 +#define SPI_PS_OFFSET 1 +#define SPI_PS_SIZE 1 +#define SPI_PCSDEC_OFFSET 2 +#define SPI_PCSDEC_SIZE 1 +#define SPI_FDIV_OFFSET 3 +#define SPI_FDIV_SIZE 1 +#define SPI_MODFDIS_OFFSET 4 +#define SPI_MODFDIS_SIZE 1 +#define SPI_LLB_OFFSET 7 +#define SPI_LLB_SIZE 1 +#define SPI_PCS_OFFSET 16 +#define SPI_PCS_SIZE 4 +#define SPI_DLYBCS_OFFSET 24 +#define SPI_DLYBCS_SIZE 8 + +/* Bitfields in RDR */ +#define SPI_RD_OFFSET 0 +#define SPI_RD_SIZE 16 + +/* Bitfields in TDR */ +#define SPI_TD_OFFSET 0 +#define SPI_TD_SIZE 16 + +/* Bitfields in SR */ +#define SPI_RDRF_OFFSET 0 +#define SPI_RDRF_SIZE 1 +#define SPI_TDRE_OFFSET 1 +#define SPI_TDRE_SIZE 1 +#define SPI_MODF_OFFSET 2 +#define SPI_MODF_SIZE 1 +#define SPI_OVRES_OFFSET 3 +#define SPI_OVRES_SIZE 1 +#define SPI_ENDRX_OFFSET 4 +#define SPI_ENDRX_SIZE 1 +#define SPI_ENDTX_OFFSET 5 +#define SPI_ENDTX_SIZE 1 +#define SPI_RXBUFF_OFFSET 6 +#define SPI_RXBUFF_SIZE 1 +#define SPI_TXBUFE_OFFSET 7 +#define SPI_TXBUFE_SIZE 1 +#define SPI_NSSR_OFFSET 8 +#define SPI_NSSR_SIZE 1 +#define SPI_TXEMPTY_OFFSET 9 +#define SPI_TXEMPTY_SIZE 1 +#define SPI_SPIENS_OFFSET 16 +#define SPI_SPIENS_SIZE 1 + +/* Bitfields in CSR0 */ +#define SPI_CPOL_OFFSET 0 +#define SPI_CPOL_SIZE 1 +#define SPI_NCPHA_OFFSET 1 +#define SPI_NCPHA_SIZE 1 +#define SPI_CSAAT_OFFSET 3 +#define SPI_CSAAT_SIZE 1 +#define SPI_BITS_OFFSET 4 +#define SPI_BITS_SIZE 4 +#define SPI_SCBR_OFFSET 8 +#define SPI_SCBR_SIZE 8 +#define SPI_DLYBS_OFFSET 16 +#define SPI_DLYBS_SIZE 8 +#define SPI_DLYBCT_OFFSET 24 +#define SPI_DLYBCT_SIZE 8 + +/* Bitfields in RCR */ +#define SPI_RXCTR_OFFSET 0 +#define SPI_RXCTR_SIZE 16 + +/* Bitfields in TCR */ +#define SPI_TXCTR_OFFSET 0 +#define SPI_TXCTR_SIZE 16 + +/* Bitfields in RNCR */ +#define SPI_RXNCR_OFFSET 0 +#define SPI_RXNCR_SIZE 16 + +/* Bitfields in TNCR */ +#define SPI_TXNCR_OFFSET 0 +#define SPI_TXNCR_SIZE 16 + +/* Bitfields in PTCR */ +#define SPI_RXTEN_OFFSET 0 +#define SPI_RXTEN_SIZE 1 +#define SPI_RXTDIS_OFFSET 1 +#define SPI_RXTDIS_SIZE 1 +#define SPI_TXTEN_OFFSET 8 +#define SPI_TXTEN_SIZE 1 +#define SPI_TXTDIS_OFFSET 9 +#define SPI_TXTDIS_SIZE 1 + +/* Constants for BITS */ +#define SPI_BITS_8_BPT 0 +#define SPI_BITS_9_BPT 1 +#define SPI_BITS_10_BPT 2 +#define SPI_BITS_11_BPT 3 +#define SPI_BITS_12_BPT 4 +#define SPI_BITS_13_BPT 5 +#define SPI_BITS_14_BPT 6 +#define SPI_BITS_15_BPT 7 +#define SPI_BITS_16_BPT 8 + +/* Bit manipulation macros */ +#define SPI_BIT(name) \ + (1 << SPI_##name##_OFFSET) +#define SPI_BF(name,value) \ + (((value) & ((1 << SPI_##name##_SIZE) - 1)) << SPI_##name##_OFFSET) +#define SPI_BFEXT(name,value) \ + (((value) >> SPI_##name##_OFFSET) & ((1 << SPI_##name##_SIZE) - 1)) +#define SPI_BFINS(name,value,old) \ + ( ((old) & ~(((1 << SPI_##name##_SIZE) - 1) << SPI_##name##_OFFSET)) \ + | SPI_BF(name,value)) + +/* Register access macros */ +#define spi_readl(port,reg) \ + __raw_readl((port)->regs + SPI_##reg) +#define spi_writel(port,reg,value) \ + __raw_writel((value), (port)->regs + SPI_##reg) + +#endif /* __ATMEL_SPI_H__ */ diff --git a/drivers/spi/omap_uwire.c b/drivers/spi/omap_uwire.c new file mode 100644 index 0000000..366af49 --- /dev/null +++ b/drivers/spi/omap_uwire.c @@ -0,0 +1,572 @@ +/* + * omap_uwire.c -- MicroWire interface driver for OMAP + * + * Copyright 2003 MontaVista Software Inc. + * + * Ported to 2.6 OMAP uwire interface. + * Copyright (C) 2004 Texas Instruments. + * + * Generalization patches by Juha Yrjola + * + * Copyright (C) 2005 David Brownell (ported to 2.6 SPI interface) + * Copyright (C) 2006 Nokia + * + * Many updates by Imre Deak + * + * 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 SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF + * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * 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., + * 675 Mass Ave, Cambridge, MA 02139, USA. + */ +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include +#include +#include +#include + +#include +#include /* OMAP730_IO_CONF registers */ + + +/* FIXME address is now a platform device resource, + * and irqs should show there too... + */ +#define UWIRE_BASE_PHYS 0xFFFB3000 +#define UWIRE_BASE ((void *__iomem)IO_ADDRESS(UWIRE_BASE_PHYS)) + +/* uWire Registers: */ +#define UWIRE_IO_SIZE 0x20 +#define UWIRE_TDR 0x00 +#define UWIRE_RDR 0x00 +#define UWIRE_CSR 0x01 +#define UWIRE_SR1 0x02 +#define UWIRE_SR2 0x03 +#define UWIRE_SR3 0x04 +#define UWIRE_SR4 0x05 +#define UWIRE_SR5 0x06 + +/* CSR bits */ +#define RDRB (1 << 15) +#define CSRB (1 << 14) +#define START (1 << 13) +#define CS_CMD (1 << 12) + +/* SR1 or SR2 bits */ +#define UWIRE_READ_FALLING_EDGE 0x0001 +#define UWIRE_READ_RISING_EDGE 0x0000 +#define UWIRE_WRITE_FALLING_EDGE 0x0000 +#define UWIRE_WRITE_RISING_EDGE 0x0002 +#define UWIRE_CS_ACTIVE_LOW 0x0000 +#define UWIRE_CS_ACTIVE_HIGH 0x0004 +#define UWIRE_FREQ_DIV_2 0x0000 +#define UWIRE_FREQ_DIV_4 0x0008 +#define UWIRE_FREQ_DIV_8 0x0010 +#define UWIRE_CHK_READY 0x0020 +#define UWIRE_CLK_INVERTED 0x0040 + + +struct uwire_spi { + struct spi_bitbang bitbang; + struct clk *ck; +}; + +struct uwire_state { + unsigned bits_per_word; + unsigned div1_idx; +}; + +/* REVISIT compile time constant for idx_shift? */ +static unsigned int uwire_idx_shift; + +static inline void uwire_write_reg(int idx, u16 val) +{ + __raw_writew(val, UWIRE_BASE + (idx << uwire_idx_shift)); +} + +static inline u16 uwire_read_reg(int idx) +{ + return __raw_readw(UWIRE_BASE + (idx << uwire_idx_shift)); +} + +static inline void omap_uwire_configure_mode(u8 cs, unsigned long flags) +{ + u16 w, val = 0; + int shift, reg; + + if (flags & UWIRE_CLK_INVERTED) + val ^= 0x03; + val = flags & 0x3f; + if (cs & 1) + shift = 6; + else + shift = 0; + if (cs <= 1) + reg = UWIRE_SR1; + else + reg = UWIRE_SR2; + + w = uwire_read_reg(reg); + w &= ~(0x3f << shift); + w |= val << shift; + uwire_write_reg(reg, w); +} + +static int wait_uwire_csr_flag(u16 mask, u16 val, int might_not_catch) +{ + u16 w; + int c = 0; + unsigned long max_jiffies = jiffies + HZ; + + for (;;) { + w = uwire_read_reg(UWIRE_CSR); + if ((w & mask) == val) + break; + if (time_after(jiffies, max_jiffies)) { + printk(KERN_ERR "%s: timeout. reg=%#06x " + "mask=%#06x val=%#06x\n", + __FUNCTION__, w, mask, val); + return -1; + } + c++; + if (might_not_catch && c > 64) + break; + } + return 0; +} + +static void uwire_set_clk1_div(int div1_idx) +{ + u16 w; + + w = uwire_read_reg(UWIRE_SR3); + w &= ~(0x03 << 1); + w |= div1_idx << 1; + uwire_write_reg(UWIRE_SR3, w); +} + +static void uwire_chipselect(struct spi_device *spi, int value) +{ + struct uwire_state *ust = spi->controller_state; + u16 w; + int old_cs; + + + BUG_ON(wait_uwire_csr_flag(CSRB, 0, 0)); + + w = uwire_read_reg(UWIRE_CSR); + old_cs = (w >> 10) & 0x03; + if (value == BITBANG_CS_INACTIVE || old_cs != spi->chip_select) { + /* Deselect this CS, or the previous CS */ + w &= ~CS_CMD; + uwire_write_reg(UWIRE_CSR, w); + } + /* activate specfied chipselect */ + if (value == BITBANG_CS_ACTIVE) { + uwire_set_clk1_div(ust->div1_idx); + /* invert clock? */ + if (spi->mode & SPI_CPOL) + uwire_write_reg(UWIRE_SR4, 1); + else + uwire_write_reg(UWIRE_SR4, 0); + + w = spi->chip_select << 10; + w |= CS_CMD; + uwire_write_reg(UWIRE_CSR, w); + } +} + +static int uwire_txrx(struct spi_device *spi, struct spi_transfer *t) +{ + struct uwire_state *ust = spi->controller_state; + unsigned len = t->len; + unsigned bits = ust->bits_per_word; + unsigned bytes; + u16 val, w; + int status = 0;; + + if (!t->tx_buf && !t->rx_buf) + return 0; + + /* Microwire doesn't read and write concurrently */ + if (t->tx_buf && t->rx_buf) + return -EPERM; + + w = spi->chip_select << 10; + w |= CS_CMD; + + if (t->tx_buf) { + const u8 *buf = t->tx_buf; + + /* NOTE: DMA could be used for TX transfers */ + + /* write one or two bytes at a time */ + while (len >= 1) { + /* tx bit 15 is first sent; we byteswap multibyte words + * (msb-first) on the way out from memory. + */ + val = *buf++; + if (bits > 8) { + bytes = 2; + val |= *buf++ << 8; + } else + bytes = 1; + val <<= 16 - bits; + +#ifdef VERBOSE + pr_debug("%s: write-%d =%04x\n", + spi->dev.bus_id, bits, val); +#endif + if (wait_uwire_csr_flag(CSRB, 0, 0)) + goto eio; + + uwire_write_reg(UWIRE_TDR, val); + + /* start write */ + val = START | w | (bits << 5); + + uwire_write_reg(UWIRE_CSR, val); + len -= bytes; + + /* Wait till write actually starts. + * This is needed with MPU clock 60+ MHz. + * REVISIT: we may not have time to catch it... + */ + if (wait_uwire_csr_flag(CSRB, CSRB, 1)) + goto eio; + + status += bytes; + } + + /* REVISIT: save this for later to get more i/o overlap */ + if (wait_uwire_csr_flag(CSRB, 0, 0)) + goto eio; + + } else if (t->rx_buf) { + u8 *buf = t->rx_buf; + + /* read one or two bytes at a time */ + while (len) { + if (bits > 8) { + bytes = 2; + } else + bytes = 1; + + /* start read */ + val = START | w | (bits << 0); + uwire_write_reg(UWIRE_CSR, val); + len -= bytes; + + /* Wait till read actually starts */ + (void) wait_uwire_csr_flag(CSRB, CSRB, 1); + + if (wait_uwire_csr_flag(RDRB | CSRB, + RDRB, 0)) + goto eio; + + /* rx bit 0 is last received; multibyte words will + * be properly byteswapped on the way to memory. + */ + val = uwire_read_reg(UWIRE_RDR); + val &= (1 << bits) - 1; + *buf++ = (u8) val; + if (bytes == 2) + *buf++ = val >> 8; + status += bytes; +#ifdef VERBOSE + pr_debug("%s: read-%d =%04x\n", + spi->dev.bus_id, bits, val); +#endif + + } + } + return status; +eio: + return -EIO; +} + +static int uwire_setup_transfer(struct spi_device *spi, struct spi_transfer *t) +{ + struct uwire_state *ust = spi->controller_state; + struct uwire_spi *uwire; + unsigned flags = 0; + unsigned bits; + unsigned hz; + unsigned long rate; + int div1_idx; + int div1; + int div2; + int status; + + uwire = spi_master_get_devdata(spi->master); + + if (spi->chip_select > 3) { + pr_debug("%s: cs%d?\n", spi->dev.bus_id, spi->chip_select); + status = -ENODEV; + goto done; + } + + bits = spi->bits_per_word; + if (t != NULL && t->bits_per_word) + bits = t->bits_per_word; + if (!bits) + bits = 8; + + if (bits > 16) { + pr_debug("%s: wordsize %d?\n", spi->dev.bus_id, bits); + status = -ENODEV; + goto done; + } + ust->bits_per_word = bits; + + /* mode 0..3, clock inverted separately; + * standard nCS signaling; + * don't treat DI=high as "not ready" + */ + if (spi->mode & SPI_CS_HIGH) + flags |= UWIRE_CS_ACTIVE_HIGH; + + if (spi->mode & SPI_CPOL) + flags |= UWIRE_CLK_INVERTED; + + switch (spi->mode & (SPI_CPOL | SPI_CPHA)) { + case SPI_MODE_0: + case SPI_MODE_3: + flags |= UWIRE_WRITE_RISING_EDGE | UWIRE_READ_FALLING_EDGE; + break; + case SPI_MODE_1: + case SPI_MODE_2: + flags |= UWIRE_WRITE_FALLING_EDGE | UWIRE_READ_RISING_EDGE; + break; + } + + /* assume it's already enabled */ + rate = clk_get_rate(uwire->ck); + + hz = spi->max_speed_hz; + if (t != NULL && t->speed_hz) + hz = t->speed_hz; + + if (!hz) { + pr_debug("%s: zero speed?\n", spi->dev.bus_id); + status = -EINVAL; + goto done; + } + + /* F_INT = mpu_xor_clk / DIV1 */ + for (div1_idx = 0; div1_idx < 4; div1_idx++) { + switch (div1_idx) { + case 0: + div1 = 2; + break; + case 1: + div1 = 4; + break; + case 2: + div1 = 7; + break; + default: + case 3: + div1 = 10; + break; + } + div2 = (rate / div1 + hz - 1) / hz; + if (div2 <= 8) + break; + } + if (div1_idx == 4) { + pr_debug("%s: lowest clock %ld, need %d\n", + spi->dev.bus_id, rate / 10 / 8, hz); + status = -EDOM; + goto done; + } + + /* we have to cache this and reset in uwire_chipselect as this is a + * global parameter and another uwire device can change it under + * us */ + ust->div1_idx = div1_idx; + uwire_set_clk1_div(div1_idx); + + rate /= div1; + + switch (div2) { + case 0: + case 1: + case 2: + flags |= UWIRE_FREQ_DIV_2; + rate /= 2; + break; + case 3: + case 4: + flags |= UWIRE_FREQ_DIV_4; + rate /= 4; + break; + case 5: + case 6: + case 7: + case 8: + flags |= UWIRE_FREQ_DIV_8; + rate /= 8; + break; + } + omap_uwire_configure_mode(spi->chip_select, flags); + pr_debug("%s: uwire flags %02x, armxor %lu KHz, SCK %lu KHz\n", + __FUNCTION__, flags, + clk_get_rate(uwire->ck) / 1000, + rate / 1000); + status = 0; +done: + return status; +} + +static int uwire_setup(struct spi_device *spi) +{ + struct uwire_state *ust = spi->controller_state; + + if (ust == NULL) { + ust = kzalloc(sizeof(*ust), GFP_KERNEL); + if (ust == NULL) + return -ENOMEM; + spi->controller_state = ust; + } + + return uwire_setup_transfer(spi, NULL); +} + +static void uwire_cleanup(const struct spi_device *spi) +{ + kfree(spi->controller_state); +} + +static void uwire_off(struct uwire_spi *uwire) +{ + uwire_write_reg(UWIRE_SR3, 0); + clk_disable(uwire->ck); + clk_put(uwire->ck); + spi_master_put(uwire->bitbang.master); +} + +static int uwire_probe(struct platform_device *pdev) +{ + struct spi_master *master; + struct uwire_spi *uwire; + int status; + + master = spi_alloc_master(&pdev->dev, sizeof *uwire); + if (!master) + return -ENODEV; + + uwire = spi_master_get_devdata(master); + dev_set_drvdata(&pdev->dev, uwire); + + uwire->ck = clk_get(&pdev->dev, "armxor_ck"); + if (!uwire->ck || IS_ERR(uwire->ck)) { + dev_dbg(&pdev->dev, "no mpu_xor_clk ?\n"); + spi_master_put(master); + return -ENODEV; + } + clk_enable(uwire->ck); + + if (cpu_is_omap730()) + uwire_idx_shift = 1; + else + uwire_idx_shift = 2; + + uwire_write_reg(UWIRE_SR3, 1); + + master->bus_num = 2; /* "official" */ + master->num_chipselect = 4; + master->setup = uwire_setup; + master->cleanup = uwire_cleanup; + + uwire->bitbang.master = master; + uwire->bitbang.chipselect = uwire_chipselect; + uwire->bitbang.setup_transfer = uwire_setup_transfer; + uwire->bitbang.txrx_bufs = uwire_txrx; + + status = spi_bitbang_start(&uwire->bitbang); + if (status < 0) + uwire_off(uwire); + return status; +} + +static int uwire_remove(struct platform_device *pdev) +{ + struct uwire_spi *uwire = dev_get_drvdata(&pdev->dev); + int status; + + // FIXME remove all child devices, somewhere ... + + status = spi_bitbang_stop(&uwire->bitbang); + uwire_off(uwire); + return status; +} + +static struct platform_driver uwire_driver = { + .driver = { + .name = "omap_uwire", + .bus = &platform_bus_type, + .owner = THIS_MODULE, + }, + .probe = uwire_probe, + .remove = uwire_remove, + // suspend ... unuse ck + // resume ... use ck +}; + +static int __init omap_uwire_init(void) +{ + /* FIXME move these into the relevant board init code. also, include + * H3 support; it uses tsc2101 like H2 (on a different chipselect). + */ + + if (machine_is_omap_h2()) { + /* defaults: W21 SDO, U18 SDI, V19 SCL */ + omap_cfg_reg(N14_1610_UWIRE_CS0); + omap_cfg_reg(N15_1610_UWIRE_CS1); + } + if (machine_is_omap_perseus2()) { + /* configure pins: MPU_UW_nSCS1, MPU_UW_SDO, MPU_UW_SCLK */ + int val = omap_readl(OMAP730_IO_CONF_9) & ~0x00EEE000; + omap_writel(val | 0x00AAA000, OMAP730_IO_CONF_9); + } + + return platform_driver_register(&uwire_driver); +} + +static void __exit omap_uwire_exit(void) +{ + platform_driver_unregister(&uwire_driver); +} + +subsys_initcall(omap_uwire_init); +module_exit(omap_uwire_exit); + +MODULE_LICENSE("GPL"); + diff --git a/drivers/spi/pxa2xx_spi.c b/drivers/spi/pxa2xx_spi.c index 8b41f9c..9f2c887 100644 --- a/drivers/spi/pxa2xx_spi.c +++ b/drivers/spi/pxa2xx_spi.c @@ -1214,9 +1214,9 @@ static int setup(struct spi_device *spi) return 0; } -static void cleanup(const struct spi_device *spi) +static void cleanup(struct spi_device *spi) { - struct chip_data *chip = spi_get_ctldata((struct spi_device *)spi); + struct chip_data *chip = spi_get_ctldata(spi); kfree(chip); } diff --git a/drivers/spi/spi.c b/drivers/spi/spi.c index 6307428..2328128 100644 --- a/drivers/spi/spi.c +++ b/drivers/spi/spi.c @@ -32,7 +32,7 @@ #include */ static void spidev_release(struct device *dev) { - const struct spi_device *spi = to_spi_device(dev); + struct spi_device *spi = to_spi_device(dev); /* spi masters may cleanup for released devices */ if (spi->master->cleanup) diff --git a/drivers/spi/spi_bitbang.c b/drivers/spi/spi_bitbang.c index 57289b6..24a330d 100644 --- a/drivers/spi/spi_bitbang.c +++ b/drivers/spi/spi_bitbang.c @@ -210,7 +210,7 @@ int spi_bitbang_setup(struct spi_device if (!cs->txrx_word) return -EINVAL; - retval = spi_bitbang_setup_transfer(spi, NULL); + retval = bitbang->setup_transfer(spi, NULL); if (retval < 0) return retval; @@ -238,7 +238,7 @@ EXPORT_SYMBOL_GPL(spi_bitbang_setup); /** * spi_bitbang_cleanup - default cleanup for per-word I/O loops */ -void spi_bitbang_cleanup(const struct spi_device *spi) +void spi_bitbang_cleanup(struct spi_device *spi) { kfree(spi->controller_state); } @@ -442,9 +442,10 @@ EXPORT_SYMBOL_GPL(spi_bitbang_transfer); * hardware that basically exposes a shift register) or per-spi_transfer * (which takes better advantage of hardware like fifos or DMA engines). * - * Drivers using per-word I/O loops should use (or call) spi_bitbang_setup and - * spi_bitbang_cleanup to handle those spi master methods. Those methods are - * the defaults if the bitbang->txrx_bufs routine isn't initialized. + * Drivers using per-word I/O loops should use (or call) spi_bitbang_setup, + * spi_bitbang_cleanup and spi_bitbang_setup_transfer to handle those spi + * master methods. Those methods are the defaults if the bitbang->txrx_bufs + * routine isn't initialized. * * This routine registers the spi_master, which will process requests in a * dedicated task, keeping IRQs unblocked most of the time. To stop diff --git a/drivers/spi/spi_imx.c b/drivers/spi/spi_imx.c new file mode 100644 index 0000000..6ccf8a1 --- /dev/null +++ b/drivers/spi/spi_imx.c @@ -0,0 +1,1769 @@ +/* + * drivers/spi/spi_imx.c + * + * Copyright (C) 2006 SWAPP + * Andrea Paterniani + * + * Initial version inspired by: + * linux-2.6.17-rc3-mm1/drivers/spi/pxa2xx_spi.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) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include +#include +#include + +/*-------------------------------------------------------------------------*/ +/* SPI Registers offsets from peripheral base address */ +#define SPI_RXDATA (0x00) +#define SPI_TXDATA (0x04) +#define SPI_CONTROL (0x08) +#define SPI_INT_STATUS (0x0C) +#define SPI_TEST (0x10) +#define SPI_PERIOD (0x14) +#define SPI_DMA (0x18) +#define SPI_RESET (0x1C) + +/* SPI Control Register Bit Fields & Masks */ +#define SPI_CONTROL_BITCOUNT_MASK (0xF) /* Bit Count Mask */ +#define SPI_CONTROL_BITCOUNT(n) (((n) - 1) & SPI_CONTROL_BITCOUNT_MASK) +#define SPI_CONTROL_POL (0x1 << 4) /* Clock Polarity Mask */ +#define SPI_CONTROL_POL_ACT_HIGH (0x0 << 4) /* Active high pol. (0=idle) */ +#define SPI_CONTROL_POL_ACT_LOW (0x1 << 4) /* Active low pol. (1=idle) */ +#define SPI_CONTROL_PHA (0x1 << 5) /* Clock Phase Mask */ +#define SPI_CONTROL_PHA_0 (0x0 << 5) /* Clock Phase 0 */ +#define SPI_CONTROL_PHA_1 (0x1 << 5) /* Clock Phase 1 */ +#define SPI_CONTROL_SSCTL (0x1 << 6) /* /SS Waveform Select Mask */ +#define SPI_CONTROL_SSCTL_0 (0x0 << 6) /* Master: /SS stays low between SPI burst + Slave: RXFIFO advanced by BIT_COUNT */ +#define SPI_CONTROL_SSCTL_1 (0x1 << 6) /* Master: /SS insert pulse between SPI burst + Slave: RXFIFO advanced by /SS rising edge */ +#define SPI_CONTROL_SSPOL (0x1 << 7) /* /SS Polarity Select Mask */ +#define SPI_CONTROL_SSPOL_ACT_LOW (0x0 << 7) /* /SS Active low */ +#define SPI_CONTROL_SSPOL_ACT_HIGH (0x1 << 7) /* /SS Active high */ +#define SPI_CONTROL_XCH (0x1 << 8) /* Exchange */ +#define SPI_CONTROL_SPIEN (0x1 << 9) /* SPI Module Enable */ +#define SPI_CONTROL_MODE (0x1 << 10) /* SPI Mode Select Mask */ +#define SPI_CONTROL_MODE_SLAVE (0x0 << 10) /* SPI Mode Slave */ +#define SPI_CONTROL_MODE_MASTER (0x1 << 10) /* SPI Mode Master */ +#define SPI_CONTROL_DRCTL (0x3 << 11) /* /SPI_RDY Control Mask */ +#define SPI_CONTROL_DRCTL_0 (0x0 << 11) /* Ignore /SPI_RDY */ +#define SPI_CONTROL_DRCTL_1 (0x1 << 11) /* /SPI_RDY falling edge triggers input */ +#define SPI_CONTROL_DRCTL_2 (0x2 << 11) /* /SPI_RDY active low level triggers input */ +#define SPI_CONTROL_DATARATE (0x7 << 13) /* Data Rate Mask */ +#define SPI_PERCLK2_DIV_MIN (0) /* PERCLK2:4 */ +#define SPI_PERCLK2_DIV_MAX (7) /* PERCLK2:512 */ +#define SPI_CONTROL_DATARATE_MIN (SPI_PERCLK2_DIV_MAX << 13) +#define SPI_CONTROL_DATARATE_MAX (SPI_PERCLK2_DIV_MIN << 13) +#define SPI_CONTROL_DATARATE_BAD (SPI_CONTROL_DATARATE_MIN + 1) + +/* SPI Interrupt/Status Register Bit Fields & Masks */ +#define SPI_STATUS_TE (0x1 << 0) /* TXFIFO Empty Status */ +#define SPI_STATUS_TH (0x1 << 1) /* TXFIFO Half Status */ +#define SPI_STATUS_TF (0x1 << 2) /* TXFIFO Full Status */ +#define SPI_STATUS_RR (0x1 << 3) /* RXFIFO Data Ready Status */ +#define SPI_STATUS_RH (0x1 << 4) /* RXFIFO Half Status */ +#define SPI_STATUS_RF (0x1 << 5) /* RXFIFO Full Status */ +#define SPI_STATUS_RO (0x1 << 6) /* RXFIFO Overflow */ +#define SPI_STATUS_BO (0x1 << 7) /* Bit Count Overflow */ +#define SPI_STATUS (0xFF) /* SPI Status Mask */ +#define SPI_INTEN_TE (0x1 << 8) /* TXFIFO Empty Interrupt Enable */ +#define SPI_INTEN_TH (0x1 << 9) /* TXFIFO Half Interrupt Enable */ +#define SPI_INTEN_TF (0x1 << 10) /* TXFIFO Full Interrupt Enable */ +#define SPI_INTEN_RE (0x1 << 11) /* RXFIFO Data Ready Interrupt Enable */ +#define SPI_INTEN_RH (0x1 << 12) /* RXFIFO Half Interrupt Enable */ +#define SPI_INTEN_RF (0x1 << 13) /* RXFIFO Full Interrupt Enable */ +#define SPI_INTEN_RO (0x1 << 14) /* RXFIFO Overflow Interrupt Enable */ +#define SPI_INTEN_BO (0x1 << 15) /* Bit Count Overflow Interrupt Enable */ +#define SPI_INTEN (0xFF << 8) /* SPI Interrupt Enable Mask */ + +/* SPI Test Register Bit Fields & Masks */ +#define SPI_TEST_TXCNT (0xF << 0) /* TXFIFO Counter */ +#define SPI_TEST_RXCNT_LSB (4) /* RXFIFO Counter LSB */ +#define SPI_TEST_RXCNT (0xF << 4) /* RXFIFO Counter */ +#define SPI_TEST_SSTATUS (0xF << 8) /* State Machine Status */ +#define SPI_TEST_LBC (0x1 << 14) /* Loop Back Control */ + +/* SPI Period Register Bit Fields & Masks */ +#define SPI_PERIOD_WAIT (0x7FFF << 0) /* Wait Between Transactions */ +#define SPI_PERIOD_MAX_WAIT (0x7FFF) /* Max Wait Between + Transactions */ +#define SPI_PERIOD_CSRC (0x1 << 15) /* Period Clock Source Mask */ +#define SPI_PERIOD_CSRC_BCLK (0x0 << 15) /* Period Clock Source is + Bit Clock */ +#define SPI_PERIOD_CSRC_32768 (0x1 << 15) /* Period Clock Source is + 32.768 KHz Clock */ + +/* SPI DMA Register Bit Fields & Masks */ +#define SPI_DMA_RHDMA (0xF << 4) /* RXFIFO Half Status */ +#define SPI_DMA_RFDMA (0x1 << 5) /* RXFIFO Full Status */ +#define SPI_DMA_TEDMA (0x1 << 6) /* TXFIFO Empty Status */ +#define SPI_DMA_THDMA (0x1 << 7) /* TXFIFO Half Status */ +#define SPI_DMA_RHDEN (0x1 << 12) /* RXFIFO Half DMA Request Enable */ +#define SPI_DMA_RFDEN (0x1 << 13) /* RXFIFO Full DMA Request Enable */ +#define SPI_DMA_TEDEN (0x1 << 14) /* TXFIFO Empty DMA Request Enable */ +#define SPI_DMA_THDEN (0x1 << 15) /* TXFIFO Half DMA Request Enable */ + +/* SPI Soft Reset Register Bit Fields & Masks */ +#define SPI_RESET_START (0x1) /* Start */ + +/* Default SPI configuration values */ +#define SPI_DEFAULT_CONTROL \ +( \ + SPI_CONTROL_BITCOUNT(16) | \ + SPI_CONTROL_POL_ACT_HIGH | \ + SPI_CONTROL_PHA_0 | \ + SPI_CONTROL_SPIEN | \ + SPI_CONTROL_SSCTL_1 | \ + SPI_CONTROL_MODE_MASTER | \ + SPI_CONTROL_DRCTL_0 | \ + SPI_CONTROL_DATARATE_MIN \ +) +#define SPI_DEFAULT_ENABLE_LOOPBACK (0) +#define SPI_DEFAULT_ENABLE_DMA (0) +#define SPI_DEFAULT_PERIOD_WAIT (8) +/*-------------------------------------------------------------------------*/ + + +/*-------------------------------------------------------------------------*/ +/* TX/RX SPI FIFO size */ +#define SPI_FIFO_DEPTH (8) +#define SPI_FIFO_BYTE_WIDTH (2) +#define SPI_FIFO_OVERFLOW_MARGIN (2) + +/* DMA burst lenght for half full/empty request trigger */ +#define SPI_DMA_BLR (SPI_FIFO_DEPTH * SPI_FIFO_BYTE_WIDTH / 2) + +/* Dummy char output to achieve reads. + Choosing something different from all zeroes may help pattern recogition + for oscilloscope analysis, but may break some drivers. */ +#define SPI_DUMMY_u8 0 +#define SPI_DUMMY_u16 ((SPI_DUMMY_u8 << 8) | SPI_DUMMY_u8) +#define SPI_DUMMY_u32 ((SPI_DUMMY_u16 << 16) | SPI_DUMMY_u16) + +/** + * Macro to change a u32 field: + * @r : register to edit + * @m : bit mask + * @v : new value for the field correctly bit-alligned +*/ +#define u32_EDIT(r, m, v) r = (r & ~(m)) | (v) + +/* Message state */ +#define START_STATE ((void*)0) +#define RUNNING_STATE ((void*)1) +#define DONE_STATE ((void*)2) +#define ERROR_STATE ((void*)-1) + +/* Queue state */ +#define QUEUE_RUNNING (0) +#define QUEUE_STOPPED (1) + +#define IS_DMA_ALIGNED(x) (((u32)(x) & 0x03) == 0) +/*-------------------------------------------------------------------------*/ + + +/*-------------------------------------------------------------------------*/ +/* Driver data structs */ + +/* Context */ +struct driver_data { + /* Driver model hookup */ + struct platform_device *pdev; + + /* SPI framework hookup */ + struct spi_master *master; + + /* IMX hookup */ + struct spi_imx_master *master_info; + + /* Memory resources and SPI regs virtual address */ + struct resource *ioarea; + void __iomem *regs; + + /* SPI RX_DATA physical address */ + dma_addr_t rd_data_phys; + + /* Driver message queue */ + struct workqueue_struct *workqueue; + struct work_struct work; + spinlock_t lock; + struct list_head queue; + int busy; + int run; + + /* Message Transfer pump */ + struct tasklet_struct pump_transfers; + + /* Current message, transfer and state */ + struct spi_message *cur_msg; + struct spi_transfer *cur_transfer; + struct chip_data *cur_chip; + + /* Rd / Wr buffers pointers */ + size_t len; + void *tx; + void *tx_end; + void *rx; + void *rx_end; + + u8 rd_only; + u8 n_bytes; + int cs_change; + + /* Function pointers */ + irqreturn_t (*transfer_handler)(struct driver_data *drv_data); + void (*cs_control)(u32 command); + + /* DMA setup */ + int rx_channel; + int tx_channel; + dma_addr_t rx_dma; + dma_addr_t tx_dma; + int rx_dma_needs_unmap; + int tx_dma_needs_unmap; + size_t tx_map_len; + u32 dummy_dma_buf ____cacheline_aligned; +}; + +/* Runtime state */ +struct chip_data { + u32 control; + u32 period; + u32 test; + + u8 enable_dma:1; + u8 bits_per_word; + u8 n_bytes; + u32 max_speed_hz; + + void (*cs_control)(u32 command); +}; +/*-------------------------------------------------------------------------*/ + + +static void pump_messages(struct work_struct *work); + +static int flush(struct driver_data *drv_data) +{ + unsigned long limit = loops_per_jiffy << 1; + void __iomem *regs = drv_data->regs; + volatile u32 d; + + dev_dbg(&drv_data->pdev->dev, "flush\n"); + do { + while (readl(regs + SPI_INT_STATUS) & SPI_STATUS_RR) + d = readl(regs + SPI_RXDATA); + } while ((readl(regs + SPI_CONTROL) & SPI_CONTROL_XCH) && limit--); + + return limit; +} + +static void restore_state(struct driver_data *drv_data) +{ + void __iomem *regs = drv_data->regs; + struct chip_data *chip = drv_data->cur_chip; + + /* Load chip registers */ + dev_dbg(&drv_data->pdev->dev, + "restore_state\n" + " test = 0x%08X\n" + " control = 0x%08X\n", + chip->test, + chip->control); + writel(chip->test, regs + SPI_TEST); + writel(chip->period, regs + SPI_PERIOD); + writel(0, regs + SPI_INT_STATUS); + writel(chip->control, regs + SPI_CONTROL); +} + +static void null_cs_control(u32 command) +{ +} + +static inline u32 data_to_write(struct driver_data *drv_data) +{ + return ((u32)(drv_data->tx_end - drv_data->tx)) / drv_data->n_bytes; +} + +static inline u32 data_to_read(struct driver_data *drv_data) +{ + return ((u32)(drv_data->rx_end - drv_data->rx)) / drv_data->n_bytes; +} + +static int write(struct driver_data *drv_data) +{ + void __iomem *regs = drv_data->regs; + void *tx = drv_data->tx; + void *tx_end = drv_data->tx_end; + u8 n_bytes = drv_data->n_bytes; + u32 remaining_writes; + u32 fifo_avail_space; + u32 n; + u16 d; + + /* Compute how many fifo writes to do */ + remaining_writes = (u32)(tx_end - tx) / n_bytes; + fifo_avail_space = SPI_FIFO_DEPTH - + (readl(regs + SPI_TEST) & SPI_TEST_TXCNT); + if (drv_data->rx && (fifo_avail_space > SPI_FIFO_OVERFLOW_MARGIN)) + /* Fix misunderstood receive overflow */ + fifo_avail_space -= SPI_FIFO_OVERFLOW_MARGIN; + n = min(remaining_writes, fifo_avail_space); + + dev_dbg(&drv_data->pdev->dev, + "write type %s\n" + " remaining writes = %d\n" + " fifo avail space = %d\n" + " fifo writes = %d\n", + (n_bytes == 1) ? "u8" : "u16", + remaining_writes, + fifo_avail_space, + n); + + if (n > 0) { + /* Fill SPI TXFIFO */ + if (drv_data->rd_only) { + tx += n * n_bytes; + while (n--) + writel(SPI_DUMMY_u16, regs + SPI_TXDATA); + } else { + if (n_bytes == 1) { + while (n--) { + d = *(u8*)tx; + writel(d, regs + SPI_TXDATA); + tx += 1; + } + } else { + while (n--) { + d = *(u16*)tx; + writel(d, regs + SPI_TXDATA); + tx += 2; + } + } + } + + /* Trigger transfer */ + writel(readl(regs + SPI_CONTROL) | SPI_CONTROL_XCH, + regs + SPI_CONTROL); + + /* Update tx pointer */ + drv_data->tx = tx; + } + + return (tx >= tx_end); +} + +static int read(struct driver_data *drv_data) +{ + void __iomem *regs = drv_data->regs; + void *rx = drv_data->rx; + void *rx_end = drv_data->rx_end; + u8 n_bytes = drv_data->n_bytes; + u32 remaining_reads; + u32 fifo_rxcnt; + u32 n; + u16 d; + + /* Compute how many fifo reads to do */ + remaining_reads = (u32)(rx_end - rx) / n_bytes; + fifo_rxcnt = (readl(regs + SPI_TEST) & SPI_TEST_RXCNT) >> + SPI_TEST_RXCNT_LSB; + n = min(remaining_reads, fifo_rxcnt); + + dev_dbg(&drv_data->pdev->dev, + "read type %s\n" + " remaining reads = %d\n" + " fifo rx count = %d\n" + " fifo reads = %d\n", + (n_bytes == 1) ? "u8" : "u16", + remaining_reads, + fifo_rxcnt, + n); + + if (n > 0) { + /* Read SPI RXFIFO */ + if (n_bytes == 1) { + while (n--) { + d = readl(regs + SPI_RXDATA); + *((u8*)rx) = d; + rx += 1; + } + } else { + while (n--) { + d = readl(regs + SPI_RXDATA); + *((u16*)rx) = d; + rx += 2; + } + } + + /* Update rx pointer */ + drv_data->rx = rx; + } + + return (rx >= rx_end); +} + +static void *next_transfer(struct driver_data *drv_data) +{ + struct spi_message *msg = drv_data->cur_msg; + struct spi_transfer *trans = drv_data->cur_transfer; + + /* Move to next transfer */ + if (trans->transfer_list.next != &msg->transfers) { + drv_data->cur_transfer = + list_entry(trans->transfer_list.next, + struct spi_transfer, + transfer_list); + return RUNNING_STATE; + } + + return DONE_STATE; +} + +static int map_dma_buffers(struct driver_data *drv_data) +{ + struct spi_message *msg; + struct device *dev; + void *buf; + + drv_data->rx_dma_needs_unmap = 0; + drv_data->tx_dma_needs_unmap = 0; + + if (!drv_data->master_info->enable_dma || + !drv_data->cur_chip->enable_dma) + return -1; + + msg = drv_data->cur_msg; + dev = &msg->spi->dev; + if (msg->is_dma_mapped) { + if (drv_data->tx_dma) + /* The caller provided at least dma and cpu virtual + address for write; pump_transfers() will consider the + transfer as write only if cpu rx virtual address is + NULL */ + return 0; + + if (drv_data->rx_dma) { + /* The caller provided dma and cpu virtual address to + performe read only transfer --> + use drv_data->dummy_dma_buf for dummy writes to + achive reads */ + buf = &drv_data->dummy_dma_buf; + drv_data->tx_map_len = sizeof(drv_data->dummy_dma_buf); + drv_data->tx_dma = dma_map_single(dev, + buf, + drv_data->tx_map_len, + DMA_TO_DEVICE); + if (dma_mapping_error(drv_data->tx_dma)) + return -1; + + drv_data->tx_dma_needs_unmap = 1; + + /* Flags transfer as rd_only for pump_transfers() DMA + regs programming (should be redundant) */ + drv_data->tx = NULL; + + return 0; + } + } + + if (!IS_DMA_ALIGNED(drv_data->rx) || !IS_DMA_ALIGNED(drv_data->tx)) + return -1; + + /* NULL rx means write-only transfer and no map needed + since rx DMA will not be used */ + if (drv_data->rx) { + buf = drv_data->rx; + drv_data->rx_dma = dma_map_single( + dev, + buf, + drv_data->len, + DMA_FROM_DEVICE); + if (dma_mapping_error(drv_data->rx_dma)) + return -1; + drv_data->rx_dma_needs_unmap = 1; + } + + if (drv_data->tx == NULL) { + /* Read only message --> use drv_data->dummy_dma_buf for dummy + writes to achive reads */ + buf = &drv_data->dummy_dma_buf; + drv_data->tx_map_len = sizeof(drv_data->dummy_dma_buf); + } else { + buf = drv_data->tx; + drv_data->tx_map_len = drv_data->len; + } + drv_data->tx_dma = dma_map_single(dev, + buf, + drv_data->tx_map_len, + DMA_TO_DEVICE); + if (dma_mapping_error(drv_data->tx_dma)) { + if (drv_data->rx_dma) { + dma_unmap_single(dev, + drv_data->rx_dma, + drv_data->len, + DMA_FROM_DEVICE); + drv_data->rx_dma_needs_unmap = 0; + } + return -1; + } + drv_data->tx_dma_needs_unmap = 1; + + return 0; +} + +static void unmap_dma_buffers(struct driver_data *drv_data) +{ + struct spi_message *msg = drv_data->cur_msg; + struct device *dev = &msg->spi->dev; + + if (drv_data->rx_dma_needs_unmap) { + dma_unmap_single(dev, + drv_data->rx_dma, + drv_data->len, + DMA_FROM_DEVICE); + drv_data->rx_dma_needs_unmap = 0; + } + if (drv_data->tx_dma_needs_unmap) { + dma_unmap_single(dev, + drv_data->tx_dma, + drv_data->tx_map_len, + DMA_TO_DEVICE); + drv_data->tx_dma_needs_unmap = 0; + } +} + +/* Caller already set message->status (dma is already blocked) */ +static void giveback(struct spi_message *message, struct driver_data *drv_data) +{ + void __iomem *regs = drv_data->regs; + + /* Bring SPI to sleep; restore_state() and pump_transfer() + will do new setup */ + writel(0, regs + SPI_INT_STATUS); + writel(0, regs + SPI_DMA); + + drv_data->cs_control(SPI_CS_DEASSERT); + + message->state = NULL; + if (message->complete) + message->complete(message->context); + + drv_data->cur_msg = NULL; + drv_data->cur_transfer = NULL; + drv_data->cur_chip = NULL; + queue_work(drv_data->workqueue, &drv_data->work); +} + +static void dma_err_handler(int channel, void *data, int errcode) +{ + struct driver_data *drv_data = data; + struct spi_message *msg = drv_data->cur_msg; + + dev_dbg(&drv_data->pdev->dev, "dma_err_handler\n"); + + /* Disable both rx and tx dma channels */ + imx_dma_disable(drv_data->rx_channel); + imx_dma_disable(drv_data->tx_channel); + + if (flush(drv_data) == 0) + dev_err(&drv_data->pdev->dev, + "dma_err_handler - flush failed\n"); + + unmap_dma_buffers(drv_data); + + msg->state = ERROR_STATE; + tasklet_schedule(&drv_data->pump_transfers); +} + +static void dma_tx_handler(int channel, void *data) +{ + struct driver_data *drv_data = data; + + dev_dbg(&drv_data->pdev->dev, "dma_tx_handler\n"); + + imx_dma_disable(channel); + + /* Now waits for TX FIFO empty */ + writel(readl(drv_data->regs + SPI_INT_STATUS) | SPI_INTEN_TE, + drv_data->regs + SPI_INT_STATUS); +} + +static irqreturn_t dma_transfer(struct driver_data *drv_data) +{ + u32 status; + struct spi_message *msg = drv_data->cur_msg; + void __iomem *regs = drv_data->regs; + unsigned long limit; + + status = readl(regs + SPI_INT_STATUS); + + if ((status & SPI_INTEN_RO) && (status & SPI_STATUS_RO)) { + writel(status & ~SPI_INTEN, regs + SPI_INT_STATUS); + + imx_dma_disable(drv_data->rx_channel); + unmap_dma_buffers(drv_data); + + if (flush(drv_data) == 0) + dev_err(&drv_data->pdev->dev, + "dma_transfer - flush failed\n"); + + dev_warn(&drv_data->pdev->dev, + "dma_transfer - fifo overun\n"); + + msg->state = ERROR_STATE; + tasklet_schedule(&drv_data->pump_transfers); + + return IRQ_HANDLED; + } + + if (status & SPI_STATUS_TE) { + writel(status & ~SPI_INTEN_TE, regs + SPI_INT_STATUS); + + if (drv_data->rx) { + /* Wait end of transfer before read trailing data */ + limit = loops_per_jiffy << 1; + while ((readl(regs + SPI_CONTROL) & SPI_CONTROL_XCH) && + limit--); + + if (limit == 0) + dev_err(&drv_data->pdev->dev, + "dma_transfer - end of tx failed\n"); + else + dev_dbg(&drv_data->pdev->dev, + "dma_transfer - end of tx\n"); + + imx_dma_disable(drv_data->rx_channel); + unmap_dma_buffers(drv_data); + + /* Calculate number of trailing data and read them */ + dev_dbg(&drv_data->pdev->dev, + "dma_transfer - test = 0x%08X\n", + readl(regs + SPI_TEST)); + drv_data->rx = drv_data->rx_end - + ((readl(regs + SPI_TEST) & + SPI_TEST_RXCNT) >> + SPI_TEST_RXCNT_LSB)*drv_data->n_bytes; + read(drv_data); + } else { + /* Write only transfer */ + unmap_dma_buffers(drv_data); + + if (flush(drv_data) == 0) + dev_err(&drv_data->pdev->dev, + "dma_transfer - flush failed\n"); + } + + /* End of transfer, update total byte transfered */ + msg->actual_length += drv_data->len; + + /* Release chip select if requested, transfer delays are + handled in pump_transfers() */ + if (drv_data->cs_change) + drv_data->cs_control(SPI_CS_DEASSERT); + + /* Move to next transfer */ + msg->state = next_transfer(drv_data); + + /* Schedule transfer tasklet */ + tasklet_schedule(&drv_data->pump_transfers); + + return IRQ_HANDLED; + } + + /* Opps problem detected */ + return IRQ_NONE; +} + +static irqreturn_t interrupt_wronly_transfer(struct driver_data *drv_data) +{ + struct spi_message *msg = drv_data->cur_msg; + void __iomem *regs = drv_data->regs; + u32 status; + irqreturn_t handled = IRQ_NONE; + + status = readl(regs + SPI_INT_STATUS); + + while (status & SPI_STATUS_TH) { + dev_dbg(&drv_data->pdev->dev, + "interrupt_wronly_transfer - status = 0x%08X\n", status); + + /* Pump data */ + if (write(drv_data)) { + writel(readl(regs + SPI_INT_STATUS) & ~SPI_INTEN, + regs + SPI_INT_STATUS); + + dev_dbg(&drv_data->pdev->dev, + "interrupt_wronly_transfer - end of tx\n"); + + if (flush(drv_data) == 0) + dev_err(&drv_data->pdev->dev, + "interrupt_wronly_transfer - " + "flush failed\n"); + + /* End of transfer, update total byte transfered */ + msg->actual_length += drv_data->len; + + /* Release chip select if requested, transfer delays are + handled in pump_transfers */ + if (drv_data->cs_change) + drv_data->cs_control(SPI_CS_DEASSERT); + + /* Move to next transfer */ + msg->state = next_transfer(drv_data); + + /* Schedule transfer tasklet */ + tasklet_schedule(&drv_data->pump_transfers); + + return IRQ_HANDLED; + } + + status = readl(regs + SPI_INT_STATUS); + + /* We did something */ + handled = IRQ_HANDLED; + } + + return handled; +} + +static irqreturn_t interrupt_transfer(struct driver_data *drv_data) +{ + struct spi_message *msg = drv_data->cur_msg; + void __iomem *regs = drv_data->regs; + u32 status; + irqreturn_t handled = IRQ_NONE; + unsigned long limit; + + status = readl(regs + SPI_INT_STATUS); + + while (status & (SPI_STATUS_TH | SPI_STATUS_RO)) { + dev_dbg(&drv_data->pdev->dev, + "interrupt_transfer - status = 0x%08X\n", status); + + if (status & SPI_STATUS_RO) { + writel(readl(regs + SPI_INT_STATUS) & ~SPI_INTEN, + regs + SPI_INT_STATUS); + + dev_warn(&drv_data->pdev->dev, + "interrupt_transfer - fifo overun\n" + " data not yet written = %d\n" + " data not yet read = %d\n", + data_to_write(drv_data), + data_to_read(drv_data)); + + if (flush(drv_data) == 0) + dev_err(&drv_data->pdev->dev, + "interrupt_transfer - flush failed\n"); + + msg->state = ERROR_STATE; + tasklet_schedule(&drv_data->pump_transfers); + + return IRQ_HANDLED; + } + + /* Pump data */ + read(drv_data); + if (write(drv_data)) { + writel(readl(regs + SPI_INT_STATUS) & ~SPI_INTEN, + regs + SPI_INT_STATUS); + + dev_dbg(&drv_data->pdev->dev, + "interrupt_transfer - end of tx\n"); + + /* Read trailing bytes */ + limit = loops_per_jiffy << 1; + while ((read(drv_data) == 0) && limit--); + + if (limit == 0) + dev_err(&drv_data->pdev->dev, + "interrupt_transfer - " + "trailing byte read failed\n"); + else + dev_dbg(&drv_data->pdev->dev, + "interrupt_transfer - end of rx\n"); + + /* End of transfer, update total byte transfered */ + msg->actual_length += drv_data->len; + + /* Release chip select if requested, transfer delays are + handled in pump_transfers */ + if (drv_data->cs_change) + drv_data->cs_control(SPI_CS_DEASSERT); + + /* Move to next transfer */ + msg->state = next_transfer(drv_data); + + /* Schedule transfer tasklet */ + tasklet_schedule(&drv_data->pump_transfers); + + return IRQ_HANDLED; + } + + status = readl(regs + SPI_INT_STATUS); + + /* We did something */ + handled = IRQ_HANDLED; + } + + return handled; +} + +static irqreturn_t spi_int(int irq, void *dev_id) +{ + struct driver_data *drv_data = (struct driver_data *)dev_id; + + if (!drv_data->cur_msg) { + dev_err(&drv_data->pdev->dev, + "spi_int - bad message state\n"); + /* Never fail */ + return IRQ_HANDLED; + } + + return drv_data->transfer_handler(drv_data); +} + +static inline u32 spi_speed_hz(u32 data_rate) +{ + return imx_get_perclk2() / (4 << ((data_rate) >> 13)); +} + +static u32 spi_data_rate(u32 speed_hz) +{ + u32 div; + u32 quantized_hz = imx_get_perclk2() >> 2; + + for (div = SPI_PERCLK2_DIV_MIN; + div <= SPI_PERCLK2_DIV_MAX; + div++, quantized_hz >>= 1) { + if (quantized_hz <= speed_hz) + /* Max available speed LEQ required speed */ + return div << 13; + } + return SPI_CONTROL_DATARATE_BAD; +} + +static void pump_transfers(unsigned long data) +{ + struct driver_data *drv_data = (struct driver_data *)data; + struct spi_message *message; + struct spi_transfer *transfer, *previous; + struct chip_data *chip; + void __iomem *regs; + u32 tmp, control; + + dev_dbg(&drv_data->pdev->dev, "pump_transfer\n"); + + message = drv_data->cur_msg; + + /* Handle for abort */ + if (message->state == ERROR_STATE) { + message->status = -EIO; + giveback(message, drv_data); + return; + } + + /* Handle end of message */ + if (message->state == DONE_STATE) { + message->status = 0; + giveback(message, drv_data); + return; + } + + chip = drv_data->cur_chip; + + /* Delay if requested at end of transfer*/ + transfer = drv_data->cur_transfer; + if (message->state == RUNNING_STATE) { + previous = list_entry(transfer->transfer_list.prev, + struct spi_transfer, + transfer_list); + if (previous->delay_usecs) + udelay(previous->delay_usecs); + } else { + /* START_STATE */ + message->state = RUNNING_STATE; + drv_data->cs_control = chip->cs_control; + } + + transfer = drv_data->cur_transfer; + drv_data->tx = (void *)transfer->tx_buf; + drv_data->tx_end = drv_data->tx + transfer->len; + drv_data->rx = transfer->rx_buf; + drv_data->rx_end = drv_data->rx + transfer->len; + drv_data->rx_dma = transfer->rx_dma; + drv_data->tx_dma = transfer->tx_dma; + drv_data->len = transfer->len; + drv_data->cs_change = transfer->cs_change; + drv_data->rd_only = (drv_data->tx == NULL); + + regs = drv_data->regs; + control = readl(regs + SPI_CONTROL); + + /* Bits per word setup */ + tmp = transfer->bits_per_word; + if (tmp == 0) { + /* Use device setup */ + tmp = chip->bits_per_word; + drv_data->n_bytes = chip->n_bytes; + } else + /* Use per-transfer setup */ + drv_data->n_bytes = (tmp <= 8) ? 1 : 2; + u32_EDIT(control, SPI_CONTROL_BITCOUNT_MASK, tmp - 1); + + /* Speed setup (surely valid because already checked) */ + tmp = transfer->speed_hz; + if (tmp == 0) + tmp = chip->max_speed_hz; + tmp = spi_data_rate(tmp); + u32_EDIT(control, SPI_CONTROL_DATARATE, tmp); + + writel(control, regs + SPI_CONTROL); + + /* Assert device chip-select */ + drv_data->cs_control(SPI_CS_ASSERT); + + /* DMA cannot read/write SPI FIFOs other than 16 bits at a time; hence + if bits_per_word is less or equal 8 PIO transfers are performed. + Moreover DMA is convinient for transfer length bigger than FIFOs + byte size. */ + if ((drv_data->n_bytes == 2) && + (drv_data->len > SPI_FIFO_DEPTH*SPI_FIFO_BYTE_WIDTH) && + (map_dma_buffers(drv_data) == 0)) { + dev_dbg(&drv_data->pdev->dev, + "pump dma transfer\n" + " tx = %p\n" + " tx_dma = %08X\n" + " rx = %p\n" + " rx_dma = %08X\n" + " len = %d\n", + drv_data->tx, + (unsigned int)drv_data->tx_dma, + drv_data->rx, + (unsigned int)drv_data->rx_dma, + drv_data->len); + + /* Ensure we have the correct interrupt handler */ + drv_data->transfer_handler = dma_transfer; + + /* Trigger transfer */ + writel(readl(regs + SPI_CONTROL) | SPI_CONTROL_XCH, + regs + SPI_CONTROL); + + /* Setup tx DMA */ + if (drv_data->tx) + /* Linear source address */ + CCR(drv_data->tx_channel) = + CCR_DMOD_FIFO | + CCR_SMOD_LINEAR | + CCR_SSIZ_32 | CCR_DSIZ_16 | + CCR_REN; + else + /* Read only transfer -> fixed source address for + dummy write to achive read */ + CCR(drv_data->tx_channel) = + CCR_DMOD_FIFO | + CCR_SMOD_FIFO | + CCR_SSIZ_32 | CCR_DSIZ_16 | + CCR_REN; + + imx_dma_setup_single( + drv_data->tx_channel, + drv_data->tx_dma, + drv_data->len, + drv_data->rd_data_phys + 4, + DMA_MODE_WRITE); + + if (drv_data->rx) { + /* Setup rx DMA for linear destination address */ + CCR(drv_data->rx_channel) = + CCR_DMOD_LINEAR | + CCR_SMOD_FIFO | + CCR_DSIZ_32 | CCR_SSIZ_16 | + CCR_REN; + imx_dma_setup_single( + drv_data->rx_channel, + drv_data->rx_dma, + drv_data->len, + drv_data->rd_data_phys, + DMA_MODE_READ); + imx_dma_enable(drv_data->rx_channel); + + /* Enable SPI interrupt */ + writel(SPI_INTEN_RO, regs + SPI_INT_STATUS); + + /* Set SPI to request DMA service on both + Rx and Tx half fifo watermark */ + writel(SPI_DMA_RHDEN | SPI_DMA_THDEN, regs + SPI_DMA); + } else + /* Write only access -> set SPI to request DMA + service on Tx half fifo watermark */ + writel(SPI_DMA_THDEN, regs + SPI_DMA); + + imx_dma_enable(drv_data->tx_channel); + } else { + dev_dbg(&drv_data->pdev->dev, + "pump pio transfer\n" + " tx = %p\n" + " rx = %p\n" + " len = %d\n", + drv_data->tx, + drv_data->rx, + drv_data->len); + + /* Ensure we have the correct interrupt handler */ + if (drv_data->rx) + drv_data->transfer_handler = interrupt_transfer; + else + drv_data->transfer_handler = interrupt_wronly_transfer; + + /* Enable SPI interrupt */ + if (drv_data->rx) + writel(SPI_INTEN_TH | SPI_INTEN_RO, + regs + SPI_INT_STATUS); + else + writel(SPI_INTEN_TH, regs + SPI_INT_STATUS); + } +} + +static void pump_messages(struct work_struct *work) +{ + struct driver_data *drv_data = + container_of(work, struct driver_data, work); + unsigned long flags; + + /* Lock queue and check for queue work */ + spin_lock_irqsave(&drv_data->lock, flags); + if (list_empty(&drv_data->queue) || drv_data->run == QUEUE_STOPPED) { + drv_data->busy = 0; + spin_unlock_irqrestore(&drv_data->lock, flags); + return; + } + + /* Make sure we are not already running a message */ + if (drv_data->cur_msg) { + spin_unlock_irqrestore(&drv_data->lock, flags); + return; + } + + /* Extract head of queue */ + drv_data->cur_msg = list_entry(drv_data->queue.next, + struct spi_message, queue); + list_del_init(&drv_data->cur_msg->queue); + drv_data->busy = 1; + spin_unlock_irqrestore(&drv_data->lock, flags); + + /* Initial message state */ + drv_data->cur_msg->state = START_STATE; + drv_data->cur_transfer = list_entry(drv_data->cur_msg->transfers.next, + struct spi_transfer, + transfer_list); + + /* Setup the SPI using the per chip configuration */ + drv_data->cur_chip = spi_get_ctldata(drv_data->cur_msg->spi); + restore_state(drv_data); + + /* Mark as busy and launch transfers */ + tasklet_schedule(&drv_data->pump_transfers); +} + +static int transfer(struct spi_device *spi, struct spi_message *msg) +{ + struct driver_data *drv_data = spi_master_get_devdata(spi->master); + u32 min_speed_hz, max_speed_hz, tmp; + struct spi_transfer *trans; + unsigned long flags; + + msg->actual_length = 0; + + /* Per transfer setup check */ + min_speed_hz = spi_speed_hz(SPI_CONTROL_DATARATE_MIN); + max_speed_hz = spi->max_speed_hz; + list_for_each_entry(trans, &msg->transfers, transfer_list) { + tmp = trans->bits_per_word; + if (tmp > 16) { + dev_err(&drv_data->pdev->dev, + "message rejected : " + "invalid transfer bits_per_word (%d bits)\n", + tmp); + goto msg_rejected; + } + tmp = trans->speed_hz; + if (tmp) { + if (tmp < min_speed_hz) { + dev_err(&drv_data->pdev->dev, + "message rejected : " + "device min speed (%d Hz) exceeds " + "required transfer speed (%d Hz)\n", + min_speed_hz, + tmp); + goto msg_rejected; + } else if (tmp > max_speed_hz) { + dev_err(&drv_data->pdev->dev, + "message rejected : " + "transfer speed (%d Hz) exceeds " + "device max speed (%d Hz)\n", + tmp, + max_speed_hz); + goto msg_rejected; + } + } + } + + /* Message accepted */ + msg->status = -EINPROGRESS; + msg->state = START_STATE; + + spin_lock_irqsave(&drv_data->lock, flags); + if (drv_data->run == QUEUE_STOPPED) { + spin_unlock_irqrestore(&drv_data->lock, flags); + return -ESHUTDOWN; + } + + list_add_tail(&msg->queue, &drv_data->queue); + if (drv_data->run == QUEUE_RUNNING && !drv_data->busy) + queue_work(drv_data->workqueue, &drv_data->work); + + spin_unlock_irqrestore(&drv_data->lock, flags); + return 0; + +msg_rejected: + /* Message rejected and not queued */ + msg->status = -EINVAL; + msg->state = ERROR_STATE; + if (msg->complete) + msg->complete(msg->context); + return -EINVAL; +} + +/* On first setup bad values must free chip_data memory since will cause + spi_new_device to fail. Bad value setup from protocol driver are simply not + applied and notified to the calling driver. */ +static int setup(struct spi_device *spi) +{ + struct spi_imx_chip *chip_info; + struct chip_data *chip; + int first_setup = 0; + u32 tmp; + int status = 0; + + /* Get controller data */ + chip_info = spi->controller_data; + + /* Get controller_state */ + chip = spi_get_ctldata(spi); + if (chip == NULL) { + first_setup = 1; + + chip = kzalloc(sizeof(struct chip_data), GFP_KERNEL); + if (!chip) { + dev_err(&spi->dev, + "setup - cannot allocate controller state"); + return -ENOMEM; + } + chip->control = SPI_DEFAULT_CONTROL; + + if (chip_info == NULL) { + /* spi_board_info.controller_data not is supplied */ + chip_info = kzalloc(sizeof(struct spi_imx_chip), + GFP_KERNEL); + if (!chip_info) { + dev_err(&spi->dev, + "setup - " + "cannot allocate controller data"); + status = -ENOMEM; + goto err_first_setup; + } + /* Set controller data default value */ + chip_info->enable_loopback = + SPI_DEFAULT_ENABLE_LOOPBACK; + chip_info->enable_dma = SPI_DEFAULT_ENABLE_DMA; + chip_info->ins_ss_pulse = 1; + chip_info->bclk_wait = SPI_DEFAULT_PERIOD_WAIT; + chip_info->cs_control = null_cs_control; + } + } + + /* Now set controller state based on controller data */ + + if (first_setup) { + /* SPI loopback */ + if (chip_info->enable_loopback) + chip->test = SPI_TEST_LBC; + else + chip->test = 0; + + /* SPI dma driven */ + chip->enable_dma = chip_info->enable_dma; + + /* SPI /SS pulse between spi burst */ + if (chip_info->ins_ss_pulse) + u32_EDIT(chip->control, + SPI_CONTROL_SSCTL, SPI_CONTROL_SSCTL_1); + else + u32_EDIT(chip->control, + SPI_CONTROL_SSCTL, SPI_CONTROL_SSCTL_0); + + /* SPI bclk waits between each bits_per_word spi burst */ + if (chip_info->bclk_wait > SPI_PERIOD_MAX_WAIT) { + dev_err(&spi->dev, + "setup - " + "bclk_wait exceeds max allowed (%d)\n", + SPI_PERIOD_MAX_WAIT); + goto err_first_setup; + } + chip->period = SPI_PERIOD_CSRC_BCLK | + (chip_info->bclk_wait & SPI_PERIOD_WAIT); + } + + /* SPI mode */ + tmp = spi->mode; + if (tmp & SPI_LSB_FIRST) { + status = -EINVAL; + if (first_setup) { + dev_err(&spi->dev, + "setup - " + "HW doesn't support LSB first transfer\n"); + goto err_first_setup; + } else { + dev_err(&spi->dev, + "setup - " + "HW doesn't support LSB first transfer, " + "default to MSB first\n"); + spi->mode &= ~SPI_LSB_FIRST; + } + } + if (tmp & SPI_CS_HIGH) { + u32_EDIT(chip->control, + SPI_CONTROL_SSPOL, SPI_CONTROL_SSPOL_ACT_HIGH); + } + switch (tmp & SPI_MODE_3) { + case SPI_MODE_0: + tmp = 0; + break; + case SPI_MODE_1: + tmp = SPI_CONTROL_PHA_1; + break; + case SPI_MODE_2: + tmp = SPI_CONTROL_POL_ACT_LOW; + break; + default: + /* SPI_MODE_3 */ + tmp = SPI_CONTROL_PHA_1 | SPI_CONTROL_POL_ACT_LOW; + break; + } + u32_EDIT(chip->control, SPI_CONTROL_POL | SPI_CONTROL_PHA, tmp); + + /* SPI word width */ + tmp = spi->bits_per_word; + if (tmp == 0) { + tmp = 8; + spi->bits_per_word = 8; + } else if (tmp > 16) { + status = -EINVAL; + dev_err(&spi->dev, + "setup - " + "invalid bits_per_word (%d)\n", + tmp); + if (first_setup) + goto err_first_setup; + else { + /* Undo setup using chip as backup copy */ + tmp = chip->bits_per_word; + spi->bits_per_word = tmp; + } + } + chip->bits_per_word = tmp; + u32_EDIT(chip->control, SPI_CONTROL_BITCOUNT_MASK, tmp - 1); + chip->n_bytes = (tmp <= 8) ? 1 : 2; + + /* SPI datarate */ + tmp = spi_data_rate(spi->max_speed_hz); + if (tmp == SPI_CONTROL_DATARATE_BAD) { + status = -EINVAL; + dev_err(&spi->dev, + "setup - " + "HW min speed (%d Hz) exceeds required " + "max speed (%d Hz)\n", + spi_speed_hz(SPI_CONTROL_DATARATE_MIN), + spi->max_speed_hz); + if (first_setup) + goto err_first_setup; + else + /* Undo setup using chip as backup copy */ + spi->max_speed_hz = chip->max_speed_hz; + } else { + u32_EDIT(chip->control, SPI_CONTROL_DATARATE, tmp); + /* Actual rounded max_speed_hz */ + tmp = spi_speed_hz(tmp); + spi->max_speed_hz = tmp; + chip->max_speed_hz = tmp; + } + + /* SPI chip-select management */ + if (chip_info->cs_control) + chip->cs_control = chip_info->cs_control; + else + chip->cs_control = null_cs_control; + + /* Save controller_state */ + spi_set_ctldata(spi, chip); + + /* Summary */ + dev_dbg(&spi->dev, + "setup succeded\n" + " loopback enable = %s\n" + " dma enable = %s\n" + " insert /ss pulse = %s\n" + " period wait = %d\n" + " mode = %d\n" + " bits per word = %d\n" + " min speed = %d Hz\n" + " rounded max speed = %d Hz\n", + chip->test & SPI_TEST_LBC ? "Yes" : "No", + chip->enable_dma ? "Yes" : "No", + chip->control & SPI_CONTROL_SSCTL ? "Yes" : "No", + chip->period & SPI_PERIOD_WAIT, + spi->mode, + spi->bits_per_word, + spi_speed_hz(SPI_CONTROL_DATARATE_MIN), + spi->max_speed_hz); + +err_first_setup: + kfree(chip); + return status; +} + +static void cleanup(const struct spi_device *spi) +{ + struct chip_data *chip = spi_get_ctldata((struct spi_device *)spi); + kfree(chip); +} + +static int init_queue(struct driver_data *drv_data) +{ + INIT_LIST_HEAD(&drv_data->queue); + spin_lock_init(&drv_data->lock); + + drv_data->run = QUEUE_STOPPED; + drv_data->busy = 0; + + tasklet_init(&drv_data->pump_transfers, + pump_transfers, (unsigned long)drv_data); + + INIT_WORK(&drv_data->work, pump_messages); + drv_data->workqueue = create_singlethread_workqueue( + drv_data->master->cdev.dev->bus_id); + if (drv_data->workqueue == NULL) + return -EBUSY; + + return 0; +} + +static int start_queue(struct driver_data *drv_data) +{ + unsigned long flags; + + spin_lock_irqsave(&drv_data->lock, flags); + + if (drv_data->run == QUEUE_RUNNING || drv_data->busy) { + spin_unlock_irqrestore(&drv_data->lock, flags); + return -EBUSY; + } + + drv_data->run = QUEUE_RUNNING; + drv_data->cur_msg = NULL; + drv_data->cur_transfer = NULL; + drv_data->cur_chip = NULL; + spin_unlock_irqrestore(&drv_data->lock, flags); + + queue_work(drv_data->workqueue, &drv_data->work); + + return 0; +} + +static int stop_queue(struct driver_data *drv_data) +{ + unsigned long flags; + unsigned limit = 500; + int status = 0; + + spin_lock_irqsave(&drv_data->lock, flags); + + /* This is a bit lame, but is optimized for the common execution path. + * A wait_queue on the drv_data->busy could be used, but then the common + * execution path (pump_messages) would be required to call wake_up or + * friends on every SPI message. Do this instead */ + drv_data->run = QUEUE_STOPPED; + while (!list_empty(&drv_data->queue) && drv_data->busy && limit--) { + spin_unlock_irqrestore(&drv_data->lock, flags); + msleep(10); + spin_lock_irqsave(&drv_data->lock, flags); + } + + if (!list_empty(&drv_data->queue) || drv_data->busy) + status = -EBUSY; + + spin_unlock_irqrestore(&drv_data->lock, flags); + + return status; +} + +static int destroy_queue(struct driver_data *drv_data) +{ + int status; + + status = stop_queue(drv_data); + if (status != 0) + return status; + + if (drv_data->workqueue) + destroy_workqueue(drv_data->workqueue); + + return 0; +} + +static int spi_imx_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct spi_imx_master *platform_info; + struct spi_master *master; + struct driver_data *drv_data = NULL; + struct resource *res; + int irq, status = 0; + + platform_info = dev->platform_data; + if (platform_info == NULL) { + dev_err(&pdev->dev, "probe - no platform data supplied\n"); + status = -ENODEV; + goto err_no_pdata; + } + + /* Allocate master with space for drv_data */ + master = spi_alloc_master(dev, sizeof(struct driver_data)); + if (!master) { + dev_err(&pdev->dev, "probe - cannot alloc spi_master\n"); + status = -ENOMEM; + goto err_no_mem; + } + drv_data = spi_master_get_devdata(master); + drv_data->master = master; + drv_data->master_info = platform_info; + drv_data->pdev = pdev; + + master->bus_num = pdev->id; + master->num_chipselect = platform_info->num_chipselect; + master->cleanup = cleanup; + master->setup = setup; + master->transfer = transfer; + + drv_data->dummy_dma_buf = SPI_DUMMY_u32; + + /* Find and map resources */ + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!res) { + dev_err(&pdev->dev, "probe - MEM resources not defined\n"); + status = -ENODEV; + goto err_no_iores; + } + drv_data->ioarea = request_mem_region(res->start, + res->end - res->start + 1, + pdev->name); + if (drv_data->ioarea == NULL) { + dev_err(&pdev->dev, "probe - cannot reserve region\n"); + status = -ENXIO; + goto err_no_iores; + } + drv_data->regs = ioremap(res->start, res->end - res->start + 1); + if (drv_data->regs == NULL) { + dev_err(&pdev->dev, "probe - cannot map IO\n"); + status = -ENXIO; + goto err_no_iomap; + } + drv_data->rd_data_phys = (dma_addr_t)res->start; + + /* Attach to IRQ */ + irq = platform_get_irq(pdev, 0); + if (irq < 0) { + dev_err(&pdev->dev, "probe - IRQ resource not defined\n"); + status = -ENODEV; + goto err_no_irqres; + } + status = request_irq(irq, spi_int, IRQF_DISABLED, dev->bus_id, drv_data); + if (status < 0) { + dev_err(&pdev->dev, "probe - cannot get IRQ (%d)\n", status); + goto err_no_irqres; + } + + /* Setup DMA if requested */ + drv_data->tx_channel = -1; + drv_data->rx_channel = -1; + if (platform_info->enable_dma) { + /* Get rx DMA channel */ + status = imx_dma_request_by_prio(&drv_data->rx_channel, + "spi_imx_rx", DMA_PRIO_HIGH); + if (status < 0) { + dev_err(dev, + "probe - problem (%d) requesting rx channel\n", + status); + goto err_no_rxdma; + } else + imx_dma_setup_handlers(drv_data->rx_channel, NULL, + dma_err_handler, drv_data); + + /* Get tx DMA channel */ + status = imx_dma_request_by_prio(&drv_data->tx_channel, + "spi_imx_tx", DMA_PRIO_MEDIUM); + if (status < 0) { + dev_err(dev, + "probe - problem (%d) requesting tx channel\n", + status); + imx_dma_free(drv_data->rx_channel); + goto err_no_txdma; + } else + imx_dma_setup_handlers(drv_data->tx_channel, + dma_tx_handler, dma_err_handler, + drv_data); + + /* Set request source and burst length for allocated channels */ + switch (drv_data->pdev->id) { + case 1: + /* Using SPI1 */ + RSSR(drv_data->rx_channel) = DMA_REQ_SPI1_R; + RSSR(drv_data->tx_channel) = DMA_REQ_SPI1_T; + break; + case 2: + /* Using SPI2 */ + RSSR(drv_data->rx_channel) = DMA_REQ_SPI2_R; + RSSR(drv_data->tx_channel) = DMA_REQ_SPI2_T; + break; + default: + dev_err(dev, "probe - bad SPI Id\n"); + imx_dma_free(drv_data->rx_channel); + imx_dma_free(drv_data->tx_channel); + status = -ENODEV; + goto err_no_devid; + } + BLR(drv_data->rx_channel) = SPI_DMA_BLR; + BLR(drv_data->tx_channel) = SPI_DMA_BLR; + } + + /* Load default SPI configuration */ + writel(SPI_RESET_START, drv_data->regs + SPI_RESET); + writel(0, drv_data->regs + SPI_RESET); + writel(SPI_DEFAULT_CONTROL, drv_data->regs + SPI_CONTROL); + + /* Initial and start queue */ + status = init_queue(drv_data); + if (status != 0) { + dev_err(&pdev->dev, "probe - problem initializing queue\n"); + goto err_init_queue; + } + status = start_queue(drv_data); + if (status != 0) { + dev_err(&pdev->dev, "probe - problem starting queue\n"); + goto err_start_queue; + } + + /* Register with the SPI framework */ + platform_set_drvdata(pdev, drv_data); + status = spi_register_master(master); + if (status != 0) { + dev_err(&pdev->dev, "probe - problem registering spi master\n"); + goto err_spi_register; + } + + dev_dbg(dev, "probe succeded\n"); + return 0; + +err_init_queue: +err_start_queue: +err_spi_register: + destroy_queue(drv_data); + +err_no_rxdma: +err_no_txdma: +err_no_devid: + free_irq(irq, drv_data); + +err_no_irqres: + iounmap(drv_data->regs); + +err_no_iomap: + release_resource(drv_data->ioarea); + kfree(drv_data->ioarea); + +err_no_iores: + spi_master_put(master); + +err_no_pdata: +err_no_mem: + return status; +} + +static int __devexit spi_imx_remove(struct platform_device *pdev) +{ + struct driver_data *drv_data = platform_get_drvdata(pdev); + int irq; + int status = 0; + + if (!drv_data) + return 0; + + tasklet_kill(&drv_data->pump_transfers); + + /* Remove the queue */ + status = destroy_queue(drv_data); + if (status != 0) { + dev_err(&pdev->dev, "queue remove failed (%d)\n", status); + return status; + } + + /* Reset SPI */ + writel(SPI_RESET_START, drv_data->regs + SPI_RESET); + writel(0, drv_data->regs + SPI_RESET); + + /* Release DMA */ + if (drv_data->master_info->enable_dma) { + RSSR(drv_data->rx_channel) = 0; + RSSR(drv_data->tx_channel) = 0; + imx_dma_free(drv_data->tx_channel); + imx_dma_free(drv_data->rx_channel); + } + + /* Release IRQ */ + irq = platform_get_irq(pdev, 0); + if (irq >= 0) + free_irq(irq, drv_data); + + /* Release map resources */ + iounmap(drv_data->regs); + release_resource(drv_data->ioarea); + kfree(drv_data->ioarea); + + /* Disconnect from the SPI framework */ + spi_unregister_master(drv_data->master); + spi_master_put(drv_data->master); + + /* Prevent double remove */ + platform_set_drvdata(pdev, NULL); + + dev_dbg(&pdev->dev, "remove succeded\n"); + + return 0; +} + +static void spi_imx_shutdown(struct platform_device *pdev) +{ + struct driver_data *drv_data = platform_get_drvdata(pdev); + + /* Reset SPI */ + writel(SPI_RESET_START, drv_data->regs + SPI_RESET); + writel(0, drv_data->regs + SPI_RESET); + + dev_dbg(&pdev->dev, "shutdown succeded\n"); +} + +#ifdef CONFIG_PM +static int suspend_devices(struct device *dev, void *pm_message) +{ + pm_message_t *state = pm_message; + + if (dev->power.power_state.event != state->event) { + dev_warn(dev, "pm state does not match request\n"); + return -1; + } + + return 0; +} + +static int spi_imx_suspend(struct platform_device *pdev, pm_message_t state) +{ + struct driver_data *drv_data = platform_get_drvdata(pdev); + int status = 0; + + status = stop_queue(drv_data); + if (status != 0) { + dev_warn(&pdev->dev, "suspend cannot stop queue\n"); + return status; + } + + dev_dbg(&pdev->dev, "suspended\n"); + + return 0; +} + +static int spi_imx_resume(struct platform_device *pdev) +{ + struct driver_data *drv_data = platform_get_drvdata(pdev); + int status = 0; + + /* Start the queue running */ + status = start_queue(drv_data); + if (status != 0) + dev_err(&pdev->dev, "problem starting queue (%d)\n", status); + else + dev_dbg(&pdev->dev, "resumed\n"); + + return status; +} +#else +#define spi_imx_suspend NULL +#define spi_imx_resume NULL +#endif /* CONFIG_PM */ + +static struct platform_driver driver = { + .driver = { + .name = "imx-spi", + .bus = &platform_bus_type, + .owner = THIS_MODULE, + }, + .probe = spi_imx_probe, + .remove = __devexit_p(spi_imx_remove), + .shutdown = spi_imx_shutdown, + .suspend = spi_imx_suspend, + .resume = spi_imx_resume, +}; + +static int __init spi_imx_init(void) +{ + return platform_driver_register(&driver); +} +module_init(spi_imx_init); + +static void __exit spi_imx_exit(void) +{ + platform_driver_unregister(&driver); +} +module_exit(spi_imx_exit); + +MODULE_AUTHOR("Andrea Paterniani, "); +MODULE_DESCRIPTION("iMX SPI Contoller Driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/tc/Makefile b/drivers/tc/Makefile index 83b5bd7..9673426 100644 --- a/drivers/tc/Makefile +++ b/drivers/tc/Makefile @@ -4,7 +4,7 @@ # # Object file lists. -obj-$(CONFIG_TC) += tc.o +obj-$(CONFIG_TC) += tc.o tc-driver.o obj-$(CONFIG_ZS) += zs.o obj-$(CONFIG_VT) += lk201.o lk201-map.o lk201-remap.o diff --git a/drivers/tc/lk201.c b/drivers/tc/lk201.c index 757dec9..a90c255 100644 --- a/drivers/tc/lk201.c +++ b/drivers/tc/lk201.c @@ -10,7 +10,6 @@ #include -#include #include #include #include diff --git a/drivers/tc/tc-driver.c b/drivers/tc/tc-driver.c new file mode 100644 index 0000000..16b5bae --- /dev/null +++ b/drivers/tc/tc-driver.c @@ -0,0 +1,110 @@ +/* + * TURBOchannel driver services. + * + * Copyright (c) 2005 James Simmons + * Copyright (c) 2006 Maciej W. Rozycki + * + * Loosely based on drivers/dio/dio-driver.c and + * drivers/pci/pci-driver.c. + * + * This file is subject to the terms and conditions of the GNU + * General Public License. See the file "COPYING" in the main + * directory of this archive for more details. + */ + +#include +#include +#include + +/** + * tc_register_driver - register a new TC driver + * @drv: the driver structure to register + * + * Adds the driver structure to the list of registered drivers + * Returns a negative value on error, otherwise 0. + * If no error occurred, the driver remains registered even if + * no device was claimed during registration. + */ +int tc_register_driver(struct tc_driver *tdrv) +{ + return driver_register(&tdrv->driver); +} +EXPORT_SYMBOL(tc_register_driver); + +/** + * tc_unregister_driver - unregister a TC driver + * @drv: the driver structure to unregister + * + * Deletes the driver structure from the list of registered TC drivers, + * gives it a chance to clean up by calling its remove() function for + * each device it was responsible for, and marks those devices as + * driverless. + */ +void tc_unregister_driver(struct tc_driver *tdrv) +{ + driver_unregister(&tdrv->driver); +} +EXPORT_SYMBOL(tc_unregister_driver); + +/** + * tc_match_device - tell if a TC device structure has a matching + * TC device ID structure + * @tdrv: the TC driver to earch for matching TC device ID strings + * @tdev: the TC device structure to match against + * + * Used by a driver to check whether a TC device present in the + * system is in its list of supported devices. Returns the matching + * tc_device_id structure or %NULL if there is no match. + */ +const struct tc_device_id *tc_match_device(struct tc_driver *tdrv, + struct tc_dev *tdev) +{ + const struct tc_device_id *id = tdrv->id_table; + + if (id) { + while (id->name[0] || id->vendor[0]) { + if (strcmp(tdev->name, id->name) == 0 && + strcmp(tdev->vendor, id->vendor) == 0) + return id; + id++; + } + } + return NULL; +} +EXPORT_SYMBOL(tc_match_device); + +/** + * tc_bus_match - Tell if a device structure has a matching + * TC device ID structure + * @dev: the device structure to match against + * @drv: the device driver to search for matching TC device ID strings + * + * Used by a driver to check whether a TC device present in the + * system is in its list of supported devices. Returns 1 if there + * is a match or 0 otherwise. + */ +static int tc_bus_match(struct device *dev, struct device_driver *drv) +{ + struct tc_dev *tdev = to_tc_dev(dev); + struct tc_driver *tdrv = to_tc_driver(drv); + const struct tc_device_id *id; + + id = tc_match_device(tdrv, tdev); + if (id) + return 1; + + return 0; +} + +struct bus_type tc_bus_type = { + .name = "tc", + .match = tc_bus_match, +}; +EXPORT_SYMBOL(tc_bus_type); + +static int __init tc_driver_init(void) +{ + return bus_register(&tc_bus_type); +} + +postcore_initcall(tc_driver_init); diff --git a/drivers/tc/tc.c b/drivers/tc/tc.c index 4a51e56..f77f62a 100644 --- a/drivers/tc/tc.c +++ b/drivers/tc/tc.c @@ -1,254 +1,193 @@ /* - * tc-init: We assume the TURBOchannel to be up and running so - * just probe for Modules and fill in the global data structure - * tc_bus. + * TURBOchannel bus services. * - * 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) Harald Koerfgen, 1998 + * Copyright (c) 2001, 2003, 2005, 2006 Maciej W. Rozycki + * Copyright (c) 2005 James Simmons * - * Copyright (c) Harald Koerfgen, 1998 - * Copyright (c) 2001, 2003, 2005 Maciej W. Rozycki + * This file is subject to the terms and conditions of the GNU + * General Public License. See the file "COPYING" in the main + * directory of this archive for more details. */ +#include +#include #include +#include #include +#include #include #include +#include #include -#include -#include #include -#include -#include -#include -#include -#include -#include - -MODULE_LICENSE("GPL"); -slot_info tc_bus[MAX_SLOT]; -static int num_tcslots; -static tcinfo *info; +static struct tc_bus tc_bus = { + .name = "TURBOchannel", +}; /* - * Interface to the world. Read comment in include/asm-mips/tc.h. + * Probing for TURBOchannel modules. */ - -int search_tc_card(const char *name) -{ - int slot; - slot_info *sip; - - for (slot = 0; slot < num_tcslots; slot++) { - sip = &tc_bus[slot]; - if ((sip->flags & FREE) && - (strncmp(sip->name, name, strlen(name)) == 0)) { - return slot; - } - } - - return -ENODEV; -} - -void claim_tc_card(int slot) -{ - if (tc_bus[slot].flags & IN_USE) { - printk("claim_tc_card: attempting to claim a card already in use\n"); - return; - } - tc_bus[slot].flags &= ~FREE; - tc_bus[slot].flags |= IN_USE; -} - -void release_tc_card(int slot) +static void __init tc_bus_add_devices(struct tc_bus *tbus) { - if (tc_bus[slot].flags & FREE) { - printk("release_tc_card: " - "attempting to release a card already free\n"); - return; - } - tc_bus[slot].flags &= ~IN_USE; - tc_bus[slot].flags |= FREE; -} - -unsigned long get_tc_base_addr(int slot) -{ - return tc_bus[slot].base_addr; -} - -unsigned long get_tc_irq_nr(int slot) -{ - return tc_bus[slot].interrupt; -} - -unsigned long get_tc_speed(void) -{ - return 100000 * (10000 / (unsigned long)info->clk_period); -} - -/* - * Probing for TURBOchannel modules - */ -static void __init tc_probe(unsigned long startaddr, unsigned long size, - int slots) -{ - unsigned long slotaddr; + resource_size_t slotsize = tbus->info.slot_size << 20; + resource_size_t extslotsize = tbus->ext_slot_size; + resource_size_t slotaddr; + resource_size_t extslotaddr; + resource_size_t devsize; + void __iomem *module; + struct tc_dev *tdev; int i, slot, err; - long offset; u8 pattern[4]; - volatile u8 *module; + long offset; - for (slot = 0; slot < slots; slot++) { - slotaddr = startaddr + slot * size; - module = ioremap_nocache(slotaddr, size); + for (slot = 0; slot < tbus->num_tcslots; slot++) { + slotaddr = tbus->slot_base + slot * slotsize; + extslotaddr = tbus->ext_slot_base + slot * extslotsize; + module = ioremap_nocache(slotaddr, slotsize); BUG_ON(!module); - offset = OLDCARD; + offset = TC_OLDCARD; err = 0; - err |= get_dbe(pattern[0], module + OLDCARD + TC_PATTERN0); - err |= get_dbe(pattern[1], module + OLDCARD + TC_PATTERN1); - err |= get_dbe(pattern[2], module + OLDCARD + TC_PATTERN2); - err |= get_dbe(pattern[3], module + OLDCARD + TC_PATTERN3); - if (err) { - iounmap(module); - continue; - } + err |= tc_preadb(pattern + 0, module + offset + TC_PATTERN0); + err |= tc_preadb(pattern + 1, module + offset + TC_PATTERN1); + err |= tc_preadb(pattern + 2, module + offset + TC_PATTERN2); + err |= tc_preadb(pattern + 3, module + offset + TC_PATTERN3); + if (err) + goto out_err; if (pattern[0] != 0x55 || pattern[1] != 0x00 || pattern[2] != 0xaa || pattern[3] != 0xff) { - offset = NEWCARD; + offset = TC_NEWCARD; err = 0; - err |= get_dbe(pattern[0], module + TC_PATTERN0); - err |= get_dbe(pattern[1], module + TC_PATTERN1); - err |= get_dbe(pattern[2], module + TC_PATTERN2); - err |= get_dbe(pattern[3], module + TC_PATTERN3); - if (err) { - iounmap(module); - continue; - } + err |= tc_preadb(pattern + 0, + module + offset + TC_PATTERN0); + err |= tc_preadb(pattern + 1, + module + offset + TC_PATTERN1); + err |= tc_preadb(pattern + 2, + module + offset + TC_PATTERN2); + err |= tc_preadb(pattern + 3, + module + offset + TC_PATTERN3); + if (err) + goto out_err; } if (pattern[0] != 0x55 || pattern[1] != 0x00 || - pattern[2] != 0xaa || pattern[3] != 0xff) { - iounmap(module); - continue; + pattern[2] != 0xaa || pattern[3] != 0xff) + goto out_err; + + /* Found a board, allocate it an entry in the list */ + tdev = kzalloc(sizeof(*tdev), GFP_KERNEL); + if (!tdev) { + printk(KERN_ERR "tc%x: unable to allocate tc_dev\n", + slot); + goto out_err; } + sprintf(tdev->dev.bus_id, "tc%x", slot); + tdev->bus = tbus; + tdev->dev.parent = &tbus->dev; + tdev->dev.bus = &tc_bus_type; + tdev->slot = slot; - tc_bus[slot].base_addr = slotaddr; for (i = 0; i < 8; i++) { - tc_bus[slot].firmware[i] = - module[TC_FIRM_VER + offset + 4 * i]; - tc_bus[slot].vendor[i] = - module[TC_VENDOR + offset + 4 * i]; - tc_bus[slot].name[i] = - module[TC_MODULE + offset + 4 * i]; + tdev->firmware[i] = + readb(module + offset + TC_FIRM_VER + 4 * i); + tdev->vendor[i] = + readb(module + offset + TC_VENDOR + 4 * i); + tdev->name[i] = + readb(module + offset + TC_MODULE + 4 * i); } - tc_bus[slot].firmware[8] = 0; - tc_bus[slot].vendor[8] = 0; - tc_bus[slot].name[8] = 0; - /* - * Looks unneccesary, but we may change - * TC? in the future - */ - switch (slot) { - case 0: - tc_bus[slot].interrupt = dec_interrupt[DEC_IRQ_TC0]; - break; - case 1: - tc_bus[slot].interrupt = dec_interrupt[DEC_IRQ_TC1]; - break; - case 2: - tc_bus[slot].interrupt = dec_interrupt[DEC_IRQ_TC2]; - break; - /* - * Yuck! DS5000/200 onboard devices - */ - case 5: - tc_bus[slot].interrupt = dec_interrupt[DEC_IRQ_TC5]; - break; - case 6: - tc_bus[slot].interrupt = dec_interrupt[DEC_IRQ_TC6]; - break; - default: - tc_bus[slot].interrupt = -1; - break; + tdev->firmware[8] = 0; + tdev->vendor[8] = 0; + tdev->name[8] = 0; + + pr_info("%s: %s %s %s\n", tdev->dev.bus_id, tdev->vendor, + tdev->name, tdev->firmware); + + devsize = readb(module + offset + TC_SLOT_SIZE); + devsize <<= 22; + if (devsize <= slotsize) { + tdev->resource.start = slotaddr; + tdev->resource.end = slotaddr + devsize - 1; + } else if (devsize <= extslotsize) { + tdev->resource.start = extslotaddr; + tdev->resource.end = extslotaddr + devsize - 1; + } else { + printk(KERN_ERR "%s: Cannot provide slot space " + "(%dMiB required, up to %dMiB supported)\n", + tdev->dev.bus_id, devsize >> 20, + max(slotsize, extslotsize) >> 20); + kfree(tdev); + goto out_err; } + tdev->resource.name = tdev->name; + tdev->resource.flags = IORESOURCE_MEM; + + tc_device_get_irq(tdev); + device_register(&tdev->dev); + list_add_tail(&tdev->node, &tbus->devices); + +out_err: iounmap(module); } } /* - * the main entry + * The main entry. */ static int __init tc_init(void) { - int tc_clock; - int i; - unsigned long slot0addr; - unsigned long slot_size; - - if (!TURBOCHANNEL) + /* Initialize the TURBOchannel bus */ + if (tc_bus_get_info(&tc_bus)) return 0; - for (i = 0; i < MAX_SLOT; i++) { - tc_bus[i].base_addr = 0; - tc_bus[i].name[0] = 0; - tc_bus[i].vendor[0] = 0; - tc_bus[i].firmware[0] = 0; - tc_bus[i].interrupt = -1; - tc_bus[i].flags = FREE; - } - - info = rex_gettcinfo(); - slot0addr = CPHYSADDR((long)rex_slot_address(0)); - - switch (mips_machtype) { - case MACH_DS5000_200: - num_tcslots = 7; - break; - case MACH_DS5000_1XX: - case MACH_DS5000_2X0: - case MACH_DS5900: - num_tcslots = 3; - break; - case MACH_DS5000_XX: - default: - num_tcslots = 2; - break; - } - - tc_clock = 10000 / info->clk_period; - - if (info->slot_size && slot0addr) { - pr_info("TURBOchannel rev. %d at %d.%d MHz (with%s parity)\n", - info->revision, tc_clock / 10, tc_clock % 10, - info->parity ? "" : "out"); - - slot_size = info->slot_size << 20; - - tc_probe(slot0addr, slot_size, num_tcslots); - - for (i = 0; i < num_tcslots; i++) { - if (!tc_bus[i].base_addr) - continue; - pr_info(" slot %d: %s %s %s\n", i, tc_bus[i].vendor, - tc_bus[i].name, tc_bus[i].firmware); + INIT_LIST_HEAD(&tc_bus.devices); + strcpy(tc_bus.dev.bus_id, "tc"); + device_register(&tc_bus.dev); + + if (tc_bus.info.slot_size) { + unsigned int tc_clock = tc_get_speed(&tc_bus) / 100000; + + pr_info("tc: TURBOchannel rev. %d at %d.%d MHz " + "(with%s parity)\n", tc_bus.info.revision, + tc_clock / 10, tc_clock % 10, + tc_bus.info.parity ? "" : "out"); + + tc_bus.resource[0].start = tc_bus.slot_base; + tc_bus.resource[0].end = tc_bus.slot_base + + (tc_bus.info.slot_size << 20) * + tc_bus.num_tcslots - 1; + tc_bus.resource[0].name = tc_bus.name; + tc_bus.resource[0].flags = IORESOURCE_MEM; + if (request_resource(&iomem_resource, + &tc_bus.resource[0]) < 0) { + printk(KERN_ERR "tc: Cannot reserve resource\n"); + return 0; + } + if (tc_bus.ext_slot_size) { + tc_bus.resource[1].start = tc_bus.ext_slot_base; + tc_bus.resource[1].end = tc_bus.ext_slot_base + + tc_bus.ext_slot_size * + tc_bus.num_tcslots - 1; + tc_bus.resource[1].name = tc_bus.name; + tc_bus.resource[1].flags = IORESOURCE_MEM; + if (request_resource(&iomem_resource, + &tc_bus.resource[1]) < 0) { + printk(KERN_ERR + "tc: Cannot reserve resource\n"); + release_resource(&tc_bus.resource[0]); + return 0; + } } + + tc_bus_add_devices(&tc_bus); } return 0; } subsys_initcall(tc_init); - -EXPORT_SYMBOL(search_tc_card); -EXPORT_SYMBOL(claim_tc_card); -EXPORT_SYMBOL(release_tc_card); -EXPORT_SYMBOL(get_tc_base_addr); -EXPORT_SYMBOL(get_tc_irq_nr); -EXPORT_SYMBOL(get_tc_speed); diff --git a/drivers/tc/zs.c b/drivers/tc/zs.c index fc31972..3d72aa5 100644 --- a/drivers/tc/zs.c +++ b/drivers/tc/zs.c @@ -626,10 +626,8 @@ static void do_softint(unsigned long pri if (!tty) return; - if (test_and_clear_bit(RS_EVENT_WRITE_WAKEUP, &info->event)) { + if (test_and_clear_bit(RS_EVENT_WRITE_WAKEUP, &info->event)) tty_wakeup(tty); - wake_up_interruptible(&tty->write_wait); - } } static int zs_startup(struct dec_serial * info) diff --git a/drivers/telephony/ixj.c b/drivers/telephony/ixj.c index df4cc1f..71cb64e 100644 --- a/drivers/telephony/ixj.c +++ b/drivers/telephony/ixj.c @@ -648,9 +648,9 @@ static inline BYTE SLIC_GetState(IXJ *j) return j->pld_slicr.bits.state; } -static BOOL SLIC_SetState(BYTE byState, IXJ *j) +static bool SLIC_SetState(BYTE byState, IXJ *j) { - BOOL fRetVal = FALSE; + bool fRetVal = false; if (j->cardtype == QTI_PHONECARD) { if (j->flags.pcmciasct) { @@ -659,14 +659,14 @@ static BOOL SLIC_SetState(BYTE byState, case PLD_SLIC_STATE_OC: j->pslic.bits.powerdown = 1; j->pslic.bits.ring0 = j->pslic.bits.ring1 = 0; - fRetVal = TRUE; + fRetVal = true; break; case PLD_SLIC_STATE_RINGING: if (j->readers || j->writers) { j->pslic.bits.powerdown = 0; j->pslic.bits.ring0 = 1; j->pslic.bits.ring1 = 0; - fRetVal = TRUE; + fRetVal = true; } break; case PLD_SLIC_STATE_OHT: /* On-hook transmit */ @@ -679,14 +679,14 @@ static BOOL SLIC_SetState(BYTE byState, j->pslic.bits.powerdown = 1; } j->pslic.bits.ring0 = j->pslic.bits.ring1 = 0; - fRetVal = TRUE; + fRetVal = true; break; case PLD_SLIC_STATE_APR: /* Active polarity reversal */ case PLD_SLIC_STATE_OHTPR: /* OHT polarity reversal */ default: - fRetVal = FALSE; + fRetVal = false; break; } j->psccr.bits.dev = 3; @@ -703,7 +703,7 @@ static BOOL SLIC_SetState(BYTE byState, j->pld_slicw.bits.c3 = 0; j->pld_slicw.bits.b2en = 0; outb_p(j->pld_slicw.byte, j->XILINXbase + 0x01); - fRetVal = TRUE; + fRetVal = true; break; case PLD_SLIC_STATE_RINGING: j->pld_slicw.bits.c1 = 1; @@ -711,7 +711,7 @@ static BOOL SLIC_SetState(BYTE byState, j->pld_slicw.bits.c3 = 0; j->pld_slicw.bits.b2en = 1; outb_p(j->pld_slicw.byte, j->XILINXbase + 0x01); - fRetVal = TRUE; + fRetVal = true; break; case PLD_SLIC_STATE_ACTIVE: j->pld_slicw.bits.c1 = 0; @@ -719,7 +719,7 @@ static BOOL SLIC_SetState(BYTE byState, j->pld_slicw.bits.c3 = 0; j->pld_slicw.bits.b2en = 0; outb_p(j->pld_slicw.byte, j->XILINXbase + 0x01); - fRetVal = TRUE; + fRetVal = true; break; case PLD_SLIC_STATE_OHT: /* On-hook transmit */ @@ -728,7 +728,7 @@ static BOOL SLIC_SetState(BYTE byState, j->pld_slicw.bits.c3 = 0; j->pld_slicw.bits.b2en = 0; outb_p(j->pld_slicw.byte, j->XILINXbase + 0x01); - fRetVal = TRUE; + fRetVal = true; break; case PLD_SLIC_STATE_TIPOPEN: j->pld_slicw.bits.c1 = 0; @@ -736,7 +736,7 @@ static BOOL SLIC_SetState(BYTE byState, j->pld_slicw.bits.c3 = 1; j->pld_slicw.bits.b2en = 0; outb_p(j->pld_slicw.byte, j->XILINXbase + 0x01); - fRetVal = TRUE; + fRetVal = true; break; case PLD_SLIC_STATE_STANDBY: j->pld_slicw.bits.c1 = 1; @@ -744,7 +744,7 @@ static BOOL SLIC_SetState(BYTE byState, j->pld_slicw.bits.c3 = 1; j->pld_slicw.bits.b2en = 1; outb_p(j->pld_slicw.byte, j->XILINXbase + 0x01); - fRetVal = TRUE; + fRetVal = true; break; case PLD_SLIC_STATE_APR: /* Active polarity reversal */ @@ -753,7 +753,7 @@ static BOOL SLIC_SetState(BYTE byState, j->pld_slicw.bits.c3 = 1; j->pld_slicw.bits.b2en = 0; outb_p(j->pld_slicw.byte, j->XILINXbase + 0x01); - fRetVal = TRUE; + fRetVal = true; break; case PLD_SLIC_STATE_OHTPR: /* OHT polarity reversal */ @@ -762,10 +762,10 @@ static BOOL SLIC_SetState(BYTE byState, j->pld_slicw.bits.c3 = 1; j->pld_slicw.bits.b2en = 0; outb_p(j->pld_slicw.byte, j->XILINXbase + 0x01); - fRetVal = TRUE; + fRetVal = true; break; default: - fRetVal = FALSE; + fRetVal = false; break; } } @@ -4969,7 +4969,8 @@ static int ixj_daa_cid_read(IXJ *j) { int i; BYTES bytes; - char CID[ALISDAA_CALLERID_SIZE], mContinue; + char CID[ALISDAA_CALLERID_SIZE]; + bool mContinue; char *pIn, *pOut; if (!SCI_Prepare(j)) @@ -5013,7 +5014,7 @@ static int ixj_daa_cid_read(IXJ *j) pIn = CID; pOut = j->m_DAAShadowRegs.CAO_REGS.CAO.CallerID; - mContinue = 1; + mContinue = true; while (mContinue) { if ((pIn[1] & 0x03) == 0x01) { pOut[0] = pIn[0]; @@ -5027,7 +5028,7 @@ static int ixj_daa_cid_read(IXJ *j) if ((pIn[4] & 0xc0) == 0x40) { pOut[3] = ((pIn[4] & 0x3f) << 2) | ((pIn[3] & 0xc0) >> 6); } else { - mContinue = FALSE; + mContinue = false; } pIn += 5, pOut += 4; } @@ -6662,7 +6663,7 @@ static int ixj_fasync(int fd, struct fil return fasync_helper(fd, file_p, mode, &j->async_queue); } -static struct file_operations ixj_fops = +static const struct file_operations ixj_fops = { .owner = THIS_MODULE, .read = ixj_enhanced_read, @@ -7498,7 +7499,7 @@ static BYTE PCIEE_ReadBit(WORD wEEPROMAd return ((inb(wEEPROMAddress) >> 3) & 1); } -static BOOL PCIEE_ReadWord(WORD wAddress, WORD wLoc, WORD * pwResult) +static bool PCIEE_ReadWord(WORD wAddress, WORD wLoc, WORD * pwResult) { BYTE lastLCC; WORD wEEPROMAddress = wAddress + 3; diff --git a/drivers/telephony/ixj.h b/drivers/telephony/ixj.h index 8d69bcd..4c32a43 100644 --- a/drivers/telephony/ixj.h +++ b/drivers/telephony/ixj.h @@ -48,15 +48,11 @@ #include typedef __u16 WORD; typedef __u32 DWORD; typedef __u8 BYTE; -typedef __u8 BOOL; #ifndef IXJMAX #define IXJMAX 16 #endif -#define TRUE 1 -#define FALSE 0 - /****************************************************************************** * * This structure when unioned with the structures below makes simple byte diff --git a/drivers/telephony/ixj_pcmcia.c b/drivers/telephony/ixj_pcmcia.c index 164a5dc..3e658dc 100644 --- a/drivers/telephony/ixj_pcmcia.c +++ b/drivers/telephony/ixj_pcmcia.c @@ -3,7 +3,6 @@ #include "ixj-ver.h" #include #include -#include #include /* printk() */ #include /* everything... */ #include /* error codes */ diff --git a/drivers/telephony/phonedev.c b/drivers/telephony/phonedev.c index e41f49a..4d8c2a5 100644 --- a/drivers/telephony/phonedev.c +++ b/drivers/telephony/phonedev.c @@ -127,7 +127,7 @@ void phone_unregister_device(struct phon } -static struct file_operations phone_fops = +static const struct file_operations phone_fops = { .owner = THIS_MODULE, .open = phone_open, diff --git a/drivers/usb/atm/speedtch.c b/drivers/usb/atm/speedtch.c index 8ed6c75..638b800 100644 --- a/drivers/usb/atm/speedtch.c +++ b/drivers/usb/atm/speedtch.c @@ -36,7 +36,7 @@ #include #include #include #include -#include +#include #include #include "usbatm.h" diff --git a/drivers/usb/class/usblp.c b/drivers/usb/class/usblp.c index 6377db1..63e50a1 100644 --- a/drivers/usb/class/usblp.c +++ b/drivers/usb/class/usblp.c @@ -398,6 +398,9 @@ #else retval = 0; #endif + retval = usb_autopm_get_interface(intf); + if (retval < 0) + goto out; usblp->used = 1; file->private_data = usblp; @@ -442,6 +445,7 @@ static int usblp_release(struct inode *i usblp->used = 0; if (usblp->present) { usblp_unlink_urbs(usblp); + usb_autopm_put_interface(usblp->intf); } else /* finish cleanup from disconnect */ usblp_cleanup (usblp); mutex_unlock (&usblp_mutex); @@ -1203,14 +1207,9 @@ static int usblp_suspend (struct usb_int { struct usblp *usblp = usb_get_intfdata (intf); - /* this races against normal access and open */ - mutex_lock (&usblp_mutex); - mutex_lock (&usblp->mut); /* we take no more IO */ usblp->sleeping = 1; usblp_unlink_urbs(usblp); - mutex_unlock (&usblp->mut); - mutex_unlock (&usblp_mutex); return 0; } @@ -1220,15 +1219,9 @@ static int usblp_resume (struct usb_inte struct usblp *usblp = usb_get_intfdata (intf); int r; - mutex_lock (&usblp_mutex); - mutex_lock (&usblp->mut); - usblp->sleeping = 0; r = handle_bidir (usblp); - mutex_unlock (&usblp->mut); - mutex_unlock (&usblp_mutex); - return r; } @@ -1251,6 +1244,7 @@ static struct usb_driver usblp_driver = .suspend = usblp_suspend, .resume = usblp_resume, .id_table = usblp_ids, + .supports_autosuspend = 1, }; static int __init usblp_init(void) diff --git a/drivers/usb/core/Kconfig b/drivers/usb/core/Kconfig index 3e66b2a..2fc0f88 100644 --- a/drivers/usb/core/Kconfig +++ b/drivers/usb/core/Kconfig @@ -33,19 +33,6 @@ config USB_DEVICEFS Most users want to say Y here. -config USB_BANDWIDTH - bool "Enforce USB bandwidth allocation (EXPERIMENTAL)" - depends on USB && EXPERIMENTAL - help - If you say Y here, the USB subsystem enforces USB bandwidth - allocation and will prevent some device opens from succeeding - if they would cause USB bandwidth usage to go above 90% of - the bus bandwidth. - - If you say N here, these conditions will cause warning messages - about USB bandwidth usage to be logged and some devices or - drivers may not work correctly. - config USB_DYNAMIC_MINORS bool "Dynamic USB minor allocation (EXPERIMENTAL)" depends on USB && EXPERIMENTAL diff --git a/drivers/usb/core/buffer.c b/drivers/usb/core/buffer.c index c3915dc..ead2475 100644 --- a/drivers/usb/core/buffer.c +++ b/drivers/usb/core/buffer.c @@ -49,9 +49,9 @@ static const size_t pool_max [HCD_BUFFER * * Call hcd_buffer_destroy() to clean up after using those pools. */ -int hcd_buffer_create (struct usb_hcd *hcd) +int hcd_buffer_create(struct usb_hcd *hcd) { - char name [16]; + char name[16]; int i, size; if (!hcd->self.controller->dma_mask) @@ -60,11 +60,11 @@ int hcd_buffer_create (struct usb_hcd *h for (i = 0; i < HCD_BUFFER_POOLS; i++) { if (!(size = pool_max [i])) continue; - snprintf (name, sizeof name, "buffer-%d", size); - hcd->pool [i] = dma_pool_create (name, hcd->self.controller, + snprintf(name, sizeof name, "buffer-%d", size); + hcd->pool[i] = dma_pool_create(name, hcd->self.controller, size, size, 0); if (!hcd->pool [i]) { - hcd_buffer_destroy (hcd); + hcd_buffer_destroy(hcd); return -ENOMEM; } } @@ -79,14 +79,14 @@ int hcd_buffer_create (struct usb_hcd *h * * This frees the buffer pools created by hcd_buffer_create(). */ -void hcd_buffer_destroy (struct usb_hcd *hcd) +void hcd_buffer_destroy(struct usb_hcd *hcd) { int i; for (i = 0; i < HCD_BUFFER_POOLS; i++) { - struct dma_pool *pool = hcd->pool [i]; + struct dma_pool *pool = hcd->pool[i]; if (pool) { - dma_pool_destroy (pool); + dma_pool_destroy(pool); hcd->pool[i] = NULL; } } @@ -97,8 +97,8 @@ void hcd_buffer_destroy (struct usb_hcd * better sharing and to leverage mm/slab.c intelligence. */ -void *hcd_buffer_alloc ( - struct usb_bus *bus, +void *hcd_buffer_alloc( + struct usb_bus *bus, size_t size, gfp_t mem_flags, dma_addr_t *dma @@ -110,18 +110,18 @@ void *hcd_buffer_alloc ( /* some USB hosts just use PIO */ if (!bus->controller->dma_mask) { *dma = ~(dma_addr_t) 0; - return kmalloc (size, mem_flags); + return kmalloc(size, mem_flags); } for (i = 0; i < HCD_BUFFER_POOLS; i++) { if (size <= pool_max [i]) - return dma_pool_alloc (hcd->pool [i], mem_flags, dma); + return dma_pool_alloc(hcd->pool [i], mem_flags, dma); } - return dma_alloc_coherent (hcd->self.controller, size, dma, 0); + return dma_alloc_coherent(hcd->self.controller, size, dma, 0); } -void hcd_buffer_free ( - struct usb_bus *bus, +void hcd_buffer_free( + struct usb_bus *bus, size_t size, void *addr, dma_addr_t dma @@ -134,15 +134,15 @@ void hcd_buffer_free ( return; if (!bus->controller->dma_mask) { - kfree (addr); + kfree(addr); return; } for (i = 0; i < HCD_BUFFER_POOLS; i++) { if (size <= pool_max [i]) { - dma_pool_free (hcd->pool [i], addr, dma); + dma_pool_free(hcd->pool [i], addr, dma); return; } } - dma_free_coherent (hcd->self.controller, size, addr, dma); + dma_free_coherent(hcd->self.controller, size, addr, dma); } diff --git a/drivers/usb/core/devices.c b/drivers/usb/core/devices.c index ea398e5..a47c30b 100644 --- a/drivers/usb/core/devices.c +++ b/drivers/usb/core/devices.c @@ -104,7 +104,7 @@ static const char *format_config = static const char *format_iface = /* I: If#=dd Alt=dd #EPs=dd Cls=xx(sssss) Sub=xx Prot=xx Driver=xxxx*/ - "I: If#=%2d Alt=%2d #EPs=%2d Cls=%02x(%-5s) Sub=%02x Prot=%02x Driver=%s\n"; + "I:%c If#=%2d Alt=%2d #EPs=%2d Cls=%02x(%-5s) Sub=%02x Prot=%02x Driver=%s\n"; static const char *format_endpt = /* E: Ad=xx(s) Atr=xx(ssss) MxPS=dddd Ivl=D?s */ @@ -164,10 +164,10 @@ static const char *class_decode(const in for (ix = 0; clas_info[ix].class != -1; ix++) if (clas_info[ix].class == class) break; - return (clas_info[ix].class_name); + return clas_info[ix].class_name; } -static char *usb_dump_endpoint_descriptor ( +static char *usb_dump_endpoint_descriptor( int speed, char *start, char *end, @@ -212,9 +212,9 @@ static char *usb_dump_endpoint_descripto break; case USB_ENDPOINT_XFER_INT: type = "Int."; - if (speed == USB_SPEED_HIGH) { + if (speed == USB_SPEED_HIGH) interval = 1 << (desc->bInterval - 1); - } else + else interval = desc->bInterval; break; default: /* "can't happen" */ @@ -242,15 +242,19 @@ static char *usb_dump_interface_descript { const struct usb_interface_descriptor *desc = &intfc->altsetting[setno].desc; const char *driver_name = ""; + int active = 0; if (start > end) return start; down_read(&usb_bus_type.subsys.rwsem); - if (iface) + if (iface) { driver_name = (iface->dev.driver ? iface->dev.driver->name : "(none)"); + active = (desc == &iface->cur_altsetting->desc); + } start += sprintf(start, format_iface, + active ? '*' : ' ', /* mark active altsetting */ desc->bInterfaceNumber, desc->bAlternateSetting, desc->bNumEndpoints, @@ -343,7 +347,7 @@ static char *usb_dump_device_descriptor( if (start > end) return start; - start += sprintf (start, format_device1, + start += sprintf(start, format_device1, bcdUSB >> 8, bcdUSB & 0xff, desc->bDeviceClass, class_decode (desc->bDeviceClass), @@ -363,7 +367,7 @@ static char *usb_dump_device_descriptor( /* * Dump the different strings that this device holds. */ -static char *usb_dump_device_strings (char *start, char *end, struct usb_device *dev) +static char *usb_dump_device_strings(char *start, char *end, struct usb_device *dev) { if (start > end) return start; @@ -395,7 +399,7 @@ static char *usb_dump_desc(char *start, if (start > end) return start; - start = usb_dump_device_strings (start, end, dev); + start = usb_dump_device_strings(start, end, dev); for (i = 0; i < dev->descriptor.bNumConfigurations; i++) { if (start > end) diff --git a/drivers/usb/core/devio.c b/drivers/usb/core/devio.c index 4b3a6ab..2087766 100644 --- a/drivers/usb/core/devio.c +++ b/drivers/usb/core/devio.c @@ -522,19 +522,19 @@ static int check_ctrlrecip(struct dev_st static struct usb_device *usbdev_lookup_minor(int minor) { - struct class_device *class_dev; - struct usb_device *dev = NULL; + struct device *device; + struct usb_device *udev = NULL; down(&usb_device_class->sem); - list_for_each_entry(class_dev, &usb_device_class->children, node) { - if (class_dev->devt == MKDEV(USB_DEVICE_MAJOR, minor)) { - dev = class_dev->class_data; + list_for_each_entry(device, &usb_device_class->devices, node) { + if (device->devt == MKDEV(USB_DEVICE_MAJOR, minor)) { + udev = device->platform_data; break; } } up(&usb_device_class->sem); - return dev; + return udev; }; /* @@ -570,6 +570,7 @@ static int usbdev_open(struct inode *ino ps->dev = dev; ps->file = file; spin_lock_init(&ps->lock); + INIT_LIST_HEAD(&ps->list); INIT_LIST_HEAD(&ps->async_pending); INIT_LIST_HEAD(&ps->async_completed); init_waitqueue_head(&ps->wait); @@ -1596,19 +1597,19 @@ static int usbdev_add(struct usb_device { int minor = ((dev->bus->busnum-1) * 128) + (dev->devnum-1); - dev->class_dev = class_device_create(usb_device_class, NULL, - MKDEV(USB_DEVICE_MAJOR, minor), &dev->dev, + dev->usbfs_dev = device_create(usb_device_class, &dev->dev, + MKDEV(USB_DEVICE_MAJOR, minor), "usbdev%d.%d", dev->bus->busnum, dev->devnum); - if (IS_ERR(dev->class_dev)) - return PTR_ERR(dev->class_dev); + if (IS_ERR(dev->usbfs_dev)) + return PTR_ERR(dev->usbfs_dev); - dev->class_dev->class_data = dev; + dev->usbfs_dev->platform_data = dev; return 0; } static void usbdev_remove(struct usb_device *dev) { - class_device_unregister(dev->class_dev); + device_unregister(dev->usbfs_dev); } static int usbdev_notify(struct notifier_block *self, unsigned long action, diff --git a/drivers/usb/core/driver.c b/drivers/usb/core/driver.c index d6eb5ce..600d1bc 100644 --- a/drivers/usb/core/driver.c +++ b/drivers/usb/core/driver.c @@ -28,24 +28,16 @@ #include #include "hcd.h" #include "usb.h" -static int usb_match_one_id(struct usb_interface *interface, - const struct usb_device_id *id); - -struct usb_dynid { - struct list_head node; - struct usb_device_id id; -}; - #ifdef CONFIG_HOTPLUG /* * Adds a new dynamic USBdevice ID to this driver, * and cause the driver to probe for all devices again. */ -static ssize_t store_new_id(struct device_driver *driver, - const char *buf, size_t count) +ssize_t usb_store_new_id(struct usb_dynids *dynids, + struct device_driver *driver, + const char *buf, size_t count) { - struct usb_driver *usb_drv = to_usb_driver(driver); struct usb_dynid *dynid; u32 idVendor = 0; u32 idProduct = 0; @@ -65,9 +57,9 @@ static ssize_t store_new_id(struct devic dynid->id.idProduct = idProduct; dynid->id.match_flags = USB_DEVICE_ID_MATCH_DEVICE; - spin_lock(&usb_drv->dynids.lock); - list_add_tail(&usb_drv->dynids.list, &dynid->node); - spin_unlock(&usb_drv->dynids.lock); + spin_lock(&dynids->lock); + list_add_tail(&dynids->list, &dynid->node); + spin_unlock(&dynids->lock); if (get_driver(driver)) { retval = driver_attach(driver); @@ -78,6 +70,15 @@ static ssize_t store_new_id(struct devic return retval; return count; } +EXPORT_SYMBOL_GPL(usb_store_new_id); + +static ssize_t store_new_id(struct device_driver *driver, + const char *buf, size_t count) +{ + struct usb_driver *usb_drv = to_usb_driver(driver); + + return usb_store_new_id(&usb_drv->dynids, driver, buf, count); +} static DRIVER_ATTR(new_id, S_IWUSR, NULL, store_new_id); static int usb_create_newid_file(struct usb_driver *usb_drv) @@ -365,8 +366,8 @@ void usb_driver_release_interface(struct EXPORT_SYMBOL(usb_driver_release_interface); /* returns 0 if no match, 1 if match */ -static int usb_match_one_id(struct usb_interface *interface, - const struct usb_device_id *id) +int usb_match_one_id(struct usb_interface *interface, + const struct usb_device_id *id) { struct usb_host_interface *intf; struct usb_device *dev; @@ -432,6 +433,8 @@ static int usb_match_one_id(struct usb_i return 1; } +EXPORT_SYMBOL_GPL(usb_match_one_id); + /** * usb_match_id - find first usb_device_id matching device or interface * @interface: the interface of interest @@ -750,7 +753,8 @@ EXPORT_SYMBOL_GPL(usb_deregister_device_ * usb_register_dev() to enable that functionality. This function no longer * takes care of that. */ -int usb_register_driver(struct usb_driver *new_driver, struct module *owner) +int usb_register_driver(struct usb_driver *new_driver, struct module *owner, + const char *mod_name) { int retval = 0; @@ -763,6 +767,7 @@ int usb_register_driver(struct usb_drive new_driver->drvwrap.driver.probe = usb_probe_interface; new_driver->drvwrap.driver.remove = usb_unbind_interface; new_driver->drvwrap.driver.owner = owner; + new_driver->drvwrap.driver.mod_name = mod_name; spin_lock_init(&new_driver->dynids.lock); INIT_LIST_HEAD(&new_driver->dynids.list); diff --git a/drivers/usb/core/file.c b/drivers/usb/core/file.c index f794f07..01c857a 100644 --- a/drivers/usb/core/file.c +++ b/drivers/usb/core/file.c @@ -194,14 +194,13 @@ #endif ++temp; else temp = name; - intf->class_dev = class_device_create(usb_class->class, NULL, - MKDEV(USB_MAJOR, minor), - &intf->dev, "%s", temp); - if (IS_ERR(intf->class_dev)) { + intf->usb_dev = device_create(usb_class->class, &intf->dev, + MKDEV(USB_MAJOR, minor), "%s", temp); + if (IS_ERR(intf->usb_dev)) { spin_lock (&minor_lock); usb_minors[intf->minor] = NULL; spin_unlock (&minor_lock); - retval = PTR_ERR(intf->class_dev); + retval = PTR_ERR(intf->usb_dev); } exit: return retval; @@ -242,8 +241,8 @@ #endif spin_unlock (&minor_lock); snprintf(name, BUS_ID_SIZE, class_driver->name, intf->minor - minor_base); - class_device_destroy(usb_class->class, MKDEV(USB_MAJOR, intf->minor)); - intf->class_dev = NULL; + device_destroy(usb_class->class, MKDEV(USB_MAJOR, intf->minor)); + intf->usb_dev = NULL; intf->minor = -1; destroy_usb_class(); } diff --git a/drivers/usb/core/generic.c b/drivers/usb/core/generic.c index ebb20ff..b531a4f 100644 --- a/drivers/usb/core/generic.c +++ b/drivers/usb/core/generic.c @@ -25,6 +25,20 @@ static inline const char *plural(int n) return (n == 1 ? "" : "s"); } +static int is_rndis(struct usb_interface_descriptor *desc) +{ + return desc->bInterfaceClass == USB_CLASS_COMM + && desc->bInterfaceSubClass == 2 + && desc->bInterfaceProtocol == 0xff; +} + +static int is_activesync(struct usb_interface_descriptor *desc) +{ + return desc->bInterfaceClass == USB_CLASS_MISC + && desc->bInterfaceSubClass == 1 + && desc->bInterfaceProtocol == 1; +} + static int choose_configuration(struct usb_device *udev) { int i; @@ -87,14 +101,12 @@ #endif continue; } - /* If the first config's first interface is COMM/2/0xff - * (MSFT RNDIS), rule it out unless Linux has host-side - * RNDIS support. */ - if (i == 0 && desc - && desc->bInterfaceClass == USB_CLASS_COMM - && desc->bInterfaceSubClass == 2 - && desc->bInterfaceProtocol == 0xff) { -#ifndef CONFIG_USB_NET_RNDIS_HOST + /* When the first config's first interface is one of Microsoft's + * pet nonstandard Ethernet-over-USB protocols, ignore it unless + * this kernel has enabled the necessary host side driver. + */ + if (i == 0 && desc && (is_rndis(desc) || is_activesync(desc))) { +#if !defined(CONFIG_USB_NET_RNDIS_HOST) && !defined(CONFIG_USB_NET_RNDIS_HOST_MODULE) continue; #else best = c; diff --git a/drivers/usb/core/hcd.c b/drivers/usb/core/hcd.c index 10064af..b26c19e 100644 --- a/drivers/usb/core/hcd.c +++ b/drivers/usb/core/hcd.c @@ -45,8 +45,6 @@ #include "hcd.h" #include "hub.h" -// #define USB_BANDWIDTH_MESSAGES - /*-------------------------------------------------------------------------*/ /* @@ -891,136 +889,6 @@ long usb_calc_bus_time (int speed, int i } EXPORT_SYMBOL (usb_calc_bus_time); -/* - * usb_check_bandwidth(): - * - * old_alloc is from host_controller->bandwidth_allocated in microseconds; - * bustime is from calc_bus_time(), but converted to microseconds. - * - * returns if successful, - * or -ENOSPC if bandwidth request fails. - * - * FIXME: - * This initial implementation does not use Endpoint.bInterval - * in managing bandwidth allocation. - * It probably needs to be expanded to use Endpoint.bInterval. - * This can be done as a later enhancement (correction). - * - * This will also probably require some kind of - * frame allocation tracking...meaning, for example, - * that if multiple drivers request interrupts every 10 USB frames, - * they don't all have to be allocated at - * frame numbers N, N+10, N+20, etc. Some of them could be at - * N+11, N+21, N+31, etc., and others at - * N+12, N+22, N+32, etc. - * - * Similarly for isochronous transfers... - * - * Individual HCDs can schedule more directly ... this logic - * is not correct for high speed transfers. - */ -int usb_check_bandwidth (struct usb_device *dev, struct urb *urb) -{ - unsigned int pipe = urb->pipe; - long bustime; - int is_in = usb_pipein (pipe); - int is_iso = usb_pipeisoc (pipe); - int old_alloc = dev->bus->bandwidth_allocated; - int new_alloc; - - - bustime = NS_TO_US (usb_calc_bus_time (dev->speed, is_in, is_iso, - usb_maxpacket (dev, pipe, !is_in))); - if (is_iso) - bustime /= urb->number_of_packets; - - new_alloc = old_alloc + (int) bustime; - if (new_alloc > FRAME_TIME_MAX_USECS_ALLOC) { -#ifdef DEBUG - char *mode = -#ifdef CONFIG_USB_BANDWIDTH - ""; -#else - "would have "; -#endif - dev_dbg (&dev->dev, "usb_check_bandwidth %sFAILED: %d + %ld = %d usec\n", - mode, old_alloc, bustime, new_alloc); -#endif -#ifdef CONFIG_USB_BANDWIDTH - bustime = -ENOSPC; /* report error */ -#endif - } - - return bustime; -} -EXPORT_SYMBOL (usb_check_bandwidth); - - -/** - * usb_claim_bandwidth - records bandwidth for a periodic transfer - * @dev: source/target of request - * @urb: request (urb->dev == dev) - * @bustime: bandwidth consumed, in (average) microseconds per frame - * @isoc: true iff the request is isochronous - * - * Bus bandwidth reservations are recorded purely for diagnostic purposes. - * HCDs are expected not to overcommit periodic bandwidth, and to record such - * reservations whenever endpoints are added to the periodic schedule. - * - * FIXME averaging per-frame is suboptimal. Better to sum over the HCD's - * entire periodic schedule ... 32 frames for OHCI, 1024 for UHCI, settable - * for EHCI (256/512/1024 frames, default 1024) and have the bus expose how - * large its periodic schedule is. - */ -void usb_claim_bandwidth (struct usb_device *dev, struct urb *urb, int bustime, int isoc) -{ - dev->bus->bandwidth_allocated += bustime; - if (isoc) - dev->bus->bandwidth_isoc_reqs++; - else - dev->bus->bandwidth_int_reqs++; - urb->bandwidth = bustime; - -#ifdef USB_BANDWIDTH_MESSAGES - dev_dbg (&dev->dev, "bandwidth alloc increased by %d (%s) to %d for %d requesters\n", - bustime, - isoc ? "ISOC" : "INTR", - dev->bus->bandwidth_allocated, - dev->bus->bandwidth_int_reqs + dev->bus->bandwidth_isoc_reqs); -#endif -} -EXPORT_SYMBOL (usb_claim_bandwidth); - - -/** - * usb_release_bandwidth - reverses effect of usb_claim_bandwidth() - * @dev: source/target of request - * @urb: request (urb->dev == dev) - * @isoc: true iff the request is isochronous - * - * This records that previously allocated bandwidth has been released. - * Bandwidth is released when endpoints are removed from the host controller's - * periodic schedule. - */ -void usb_release_bandwidth (struct usb_device *dev, struct urb *urb, int isoc) -{ - dev->bus->bandwidth_allocated -= urb->bandwidth; - if (isoc) - dev->bus->bandwidth_isoc_reqs--; - else - dev->bus->bandwidth_int_reqs--; - -#ifdef USB_BANDWIDTH_MESSAGES - dev_dbg (&dev->dev, "bandwidth alloc reduced by %d (%s) to %d for %d requesters\n", - urb->bandwidth, - isoc ? "ISOC" : "INTR", - dev->bus->bandwidth_allocated, - dev->bus->bandwidth_int_reqs + dev->bus->bandwidth_isoc_reqs); -#endif - urb->bandwidth = 0; -} -EXPORT_SYMBOL (usb_release_bandwidth); - /*-------------------------------------------------------------------------*/ @@ -1034,11 +902,6 @@ static void urb_unlink (struct urb *urb) { unsigned long flags; - /* Release any periodic transfer bandwidth */ - if (urb->bandwidth) - usb_release_bandwidth (urb->dev, urb, - usb_pipeisoc (urb->pipe)); - /* clear all state linking urb to this dev (and hcd) */ spin_lock_irqsave (&hcd_data_lock, flags); diff --git a/drivers/usb/core/hcd.h b/drivers/usb/core/hcd.h index 8f8df0d..2a269ca 100644 --- a/drivers/usb/core/hcd.h +++ b/drivers/usb/core/hcd.h @@ -308,10 +308,6 @@ #define BitTime(bytecount) (7 * 8 * byt #define NS_TO_US(ns) ((ns + 500L) / 1000L) /* convert & round nanoseconds to microseconds */ -extern void usb_claim_bandwidth (struct usb_device *dev, struct urb *urb, - int bustime, int isoc); -extern void usb_release_bandwidth (struct usb_device *dev, struct urb *urb, - int isoc); /* * Full/low speed bandwidth allocation constants/support. @@ -324,8 +320,6 @@ #define FRAME_TIME_BITS 12000L #define FRAME_TIME_MAX_BITS_ALLOC (90L * FRAME_TIME_BITS / 100L) #define FRAME_TIME_MAX_USECS_ALLOC (90L * FRAME_TIME_USECS / 100L) -extern int usb_check_bandwidth (struct usb_device *dev, struct urb *urb); - /* * Ceiling [nano/micro]seconds (typical) for that many bytes at high speed * ISO is a bit less, no ACK ... from USB 2.0 spec, 5.11.3 (and needed diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c index 1988224..590ec82 100644 --- a/drivers/usb/core/hub.c +++ b/drivers/usb/core/hub.c @@ -87,9 +87,6 @@ static DECLARE_WAIT_QUEUE_HEAD(khubd_wai static struct task_struct *khubd_task; -/* multithreaded probe logic */ -static int multithread_probe = 0; - /* cycle leds on hubs that aren't blinking for attention */ static int blinkenlights = 0; module_param (blinkenlights, bool, S_IRUGO); @@ -1256,9 +1253,28 @@ #include "otg_whitelist.h" static int __usb_port_suspend(struct usb_device *, int port1); #endif -static int __usb_new_device(void *void_data) +/** + * usb_new_device - perform initial device setup (usbcore-internal) + * @udev: newly addressed device (in ADDRESS state) + * + * This is called with devices which have been enumerated, but not yet + * configured. The device descriptor is available, but not descriptors + * for any device configuration. The caller must have locked either + * the parent hub (if udev is a normal device) or else the + * usb_bus_list_lock (if udev is a root hub). The parent's pointer to + * udev has already been installed, but udev is not yet visible through + * sysfs or other filesystem code. + * + * It will return if the device is configured properly or not. Zero if + * the interface was registered with the driver core; else a negative + * errno value. + * + * This call is synchronous, and may not be used in an interrupt context. + * + * Only the hub driver or root-hub registrar should ever call this. + */ +int usb_new_device(struct usb_device *udev) { - struct usb_device *udev = void_data; int err; /* Lock ourself into memory in order to keep a probe sequence @@ -1375,44 +1391,6 @@ fail: goto exit; } -/** - * usb_new_device - perform initial device setup (usbcore-internal) - * @udev: newly addressed device (in ADDRESS state) - * - * This is called with devices which have been enumerated, but not yet - * configured. The device descriptor is available, but not descriptors - * for any device configuration. The caller must have locked either - * the parent hub (if udev is a normal device) or else the - * usb_bus_list_lock (if udev is a root hub). The parent's pointer to - * udev has already been installed, but udev is not yet visible through - * sysfs or other filesystem code. - * - * The return value for this function depends on if the - * multithread_probe variable is set or not. If it's set, it will - * return a if the probe thread was successfully created or not. If the - * variable is not set, it will return if the device is configured - * properly or not. interfaces, in sysfs); else a negative errno value. - * - * This call is synchronous, and may not be used in an interrupt context. - * - * Only the hub driver or root-hub registrar should ever call this. - */ -int usb_new_device(struct usb_device *udev) -{ - struct task_struct *probe_task; - int ret = 0; - - if (multithread_probe) { - probe_task = kthread_run(__usb_new_device, udev, - "usb-probe-%s", udev->devnum); - if (IS_ERR(probe_task)) - ret = PTR_ERR(probe_task); - } else - ret = __usb_new_device(udev); - - return ret; -} - static int hub_port_status(struct usb_hub *hub, int port1, u16 *status, u16 *change) { diff --git a/drivers/usb/core/message.c b/drivers/usb/core/message.c index 149aa8b..8aca357 100644 --- a/drivers/usb/core/message.c +++ b/drivers/usb/core/message.c @@ -1545,11 +1545,7 @@ int usb_driver_set_configuration(struct INIT_WORK(&req->work, driver_set_config_work); usb_get_dev(udev); - if (!schedule_work(&req->work)) { - usb_put_dev(udev); - kfree(req); - return -EINVAL; - } + schedule_work(&req->work); return 0; } EXPORT_SYMBOL_GPL(usb_driver_set_configuration); diff --git a/drivers/usb/core/sysfs.c b/drivers/usb/core/sysfs.c index 55d8f57..4eaa0ee 100644 --- a/drivers/usb/core/sysfs.c +++ b/drivers/usb/core/sysfs.c @@ -16,16 +16,16 @@ #include "usb.h" /* Active configuration fields */ #define usb_actconfig_show(field, multiplier, format_string) \ -static ssize_t show_##field (struct device *dev, \ +static ssize_t show_##field(struct device *dev, \ struct device_attribute *attr, char *buf) \ { \ struct usb_device *udev; \ struct usb_host_config *actconfig; \ \ - udev = to_usb_device (dev); \ + udev = to_usb_device(dev); \ actconfig = udev->actconfig; \ if (actconfig) \ - return sprintf (buf, format_string, \ + return sprintf(buf, format_string, \ actconfig->desc.field * multiplier); \ else \ return 0; \ @@ -35,9 +35,9 @@ #define usb_actconfig_attr(field, multip usb_actconfig_show(field, multiplier, format_string) \ static DEVICE_ATTR(field, S_IRUGO, show_##field, NULL); -usb_actconfig_attr (bNumInterfaces, 1, "%2d\n") -usb_actconfig_attr (bmAttributes, 1, "%2x\n") -usb_actconfig_attr (bMaxPower, 2, "%3dmA\n") +usb_actconfig_attr(bNumInterfaces, 1, "%2d\n") +usb_actconfig_attr(bmAttributes, 1, "%2x\n") +usb_actconfig_attr(bMaxPower, 2, "%3dmA\n") static ssize_t show_configuration_string(struct device *dev, struct device_attribute *attr, char *buf) @@ -45,7 +45,7 @@ static ssize_t show_configuration_string struct usb_device *udev; struct usb_host_config *actconfig; - udev = to_usb_device (dev); + udev = to_usb_device(dev); actconfig = udev->actconfig; if ((!actconfig) || (!actconfig->string)) return 0; @@ -57,16 +57,16 @@ static DEVICE_ATTR(configuration, S_IRUG usb_actconfig_show(bConfigurationValue, 1, "%u\n"); static ssize_t -set_bConfigurationValue (struct device *dev, struct device_attribute *attr, +set_bConfigurationValue(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { - struct usb_device *udev = to_usb_device (dev); + struct usb_device *udev = to_usb_device(dev); int config, value; - if (sscanf (buf, "%u", &config) != 1 || config > 255) + if (sscanf(buf, "%u", &config) != 1 || config > 255) return -EINVAL; usb_lock_device(udev); - value = usb_set_configuration (udev, config); + value = usb_set_configuration(udev, config); usb_unlock_device(udev); return (value < 0) ? value : count; } @@ -81,7 +81,7 @@ static ssize_t show_##name(struct devic { \ struct usb_device *udev; \ \ - udev = to_usb_device (dev); \ + udev = to_usb_device(dev); \ return sprintf(buf, "%s\n", udev->name); \ } \ static DEVICE_ATTR(name, S_IRUGO, show_##name, NULL); @@ -91,12 +91,12 @@ usb_string_attr(manufacturer); usb_string_attr(serial); static ssize_t -show_speed (struct device *dev, struct device_attribute *attr, char *buf) +show_speed(struct device *dev, struct device_attribute *attr, char *buf) { struct usb_device *udev; char *speed; - udev = to_usb_device (dev); + udev = to_usb_device(dev); switch (udev->speed) { case USB_SPEED_LOW: @@ -112,22 +112,22 @@ show_speed (struct device *dev, struct d default: speed = "unknown"; } - return sprintf (buf, "%s\n", speed); + return sprintf(buf, "%s\n", speed); } static DEVICE_ATTR(speed, S_IRUGO, show_speed, NULL); static ssize_t -show_devnum (struct device *dev, struct device_attribute *attr, char *buf) +show_devnum(struct device *dev, struct device_attribute *attr, char *buf) { struct usb_device *udev; - udev = to_usb_device (dev); - return sprintf (buf, "%d\n", udev->devnum); + udev = to_usb_device(dev); + return sprintf(buf, "%d\n", udev->devnum); } static DEVICE_ATTR(devnum, S_IRUGO, show_devnum, NULL); static ssize_t -show_version (struct device *dev, struct device_attribute *attr, char *buf) +show_version(struct device *dev, struct device_attribute *attr, char *buf) { struct usb_device *udev; u16 bcdUSB; @@ -139,25 +139,25 @@ show_version (struct device *dev, struct static DEVICE_ATTR(version, S_IRUGO, show_version, NULL); static ssize_t -show_maxchild (struct device *dev, struct device_attribute *attr, char *buf) +show_maxchild(struct device *dev, struct device_attribute *attr, char *buf) { struct usb_device *udev; - udev = to_usb_device (dev); - return sprintf (buf, "%d\n", udev->maxchild); + udev = to_usb_device(dev); + return sprintf(buf, "%d\n", udev->maxchild); } static DEVICE_ATTR(maxchild, S_IRUGO, show_maxchild, NULL); /* Descriptor fields */ #define usb_descriptor_attr_le16(field, format_string) \ static ssize_t \ -show_##field (struct device *dev, struct device_attribute *attr, \ +show_##field(struct device *dev, struct device_attribute *attr, \ char *buf) \ { \ struct usb_device *udev; \ \ - udev = to_usb_device (dev); \ - return sprintf (buf, format_string, \ + udev = to_usb_device(dev); \ + return sprintf(buf, format_string, \ le16_to_cpu(udev->descriptor.field)); \ } \ static DEVICE_ATTR(field, S_IRUGO, show_##field, NULL); @@ -168,21 +168,21 @@ usb_descriptor_attr_le16(bcdDevice, "%04 #define usb_descriptor_attr(field, format_string) \ static ssize_t \ -show_##field (struct device *dev, struct device_attribute *attr, \ +show_##field(struct device *dev, struct device_attribute *attr, \ char *buf) \ { \ struct usb_device *udev; \ \ - udev = to_usb_device (dev); \ - return sprintf (buf, format_string, udev->descriptor.field); \ + udev = to_usb_device(dev); \ + return sprintf(buf, format_string, udev->descriptor.field); \ } \ static DEVICE_ATTR(field, S_IRUGO, show_##field, NULL); -usb_descriptor_attr (bDeviceClass, "%02x\n") -usb_descriptor_attr (bDeviceSubClass, "%02x\n") -usb_descriptor_attr (bDeviceProtocol, "%02x\n") -usb_descriptor_attr (bNumConfigurations, "%d\n") -usb_descriptor_attr (bMaxPacketSize0, "%d\n") +usb_descriptor_attr(bDeviceClass, "%02x\n") +usb_descriptor_attr(bDeviceSubClass, "%02x\n") +usb_descriptor_attr(bDeviceProtocol, "%02x\n") +usb_descriptor_attr(bNumConfigurations, "%d\n") +usb_descriptor_attr(bMaxPacketSize0, "%d\n") static struct attribute *dev_attrs[] = { /* current configuration's attributes */ @@ -220,17 +220,17 @@ int usb_create_sysfs_dev_files(struct us return retval; if (udev->manufacturer) { - retval = device_create_file (dev, &dev_attr_manufacturer); + retval = device_create_file(dev, &dev_attr_manufacturer); if (retval) goto error; } if (udev->product) { - retval = device_create_file (dev, &dev_attr_product); + retval = device_create_file(dev, &dev_attr_product); if (retval) goto error; } if (udev->serial) { - retval = device_create_file (dev, &dev_attr_serial); + retval = device_create_file(dev, &dev_attr_serial); if (retval) goto error; } @@ -246,7 +246,7 @@ error: return retval; } -void usb_remove_sysfs_dev_files (struct usb_device *udev) +void usb_remove_sysfs_dev_files(struct usb_device *udev) { struct device *dev = &udev->dev; @@ -264,22 +264,22 @@ void usb_remove_sysfs_dev_files (struct /* Interface fields */ #define usb_intf_attr(field, format_string) \ static ssize_t \ -show_##field (struct device *dev, struct device_attribute *attr, \ +show_##field(struct device *dev, struct device_attribute *attr, \ char *buf) \ { \ - struct usb_interface *intf = to_usb_interface (dev); \ + struct usb_interface *intf = to_usb_interface(dev); \ \ - return sprintf (buf, format_string, \ + return sprintf(buf, format_string, \ intf->cur_altsetting->desc.field); \ } \ static DEVICE_ATTR(field, S_IRUGO, show_##field, NULL); -usb_intf_attr (bInterfaceNumber, "%02x\n") -usb_intf_attr (bAlternateSetting, "%2d\n") -usb_intf_attr (bNumEndpoints, "%02x\n") -usb_intf_attr (bInterfaceClass, "%02x\n") -usb_intf_attr (bInterfaceSubClass, "%02x\n") -usb_intf_attr (bInterfaceProtocol, "%02x\n") +usb_intf_attr(bInterfaceNumber, "%02x\n") +usb_intf_attr(bAlternateSetting, "%2d\n") +usb_intf_attr(bNumEndpoints, "%02x\n") +usb_intf_attr(bInterfaceClass, "%02x\n") +usb_intf_attr(bInterfaceSubClass, "%02x\n") +usb_intf_attr(bInterfaceProtocol, "%02x\n") static ssize_t show_interface_string(struct device *dev, struct device_attribute *attr, char *buf) @@ -288,8 +288,8 @@ static ssize_t show_interface_string(str struct usb_device *udev; int len; - intf = to_usb_interface (dev); - udev = interface_to_usbdev (intf); + intf = to_usb_interface(dev); + udev = interface_to_usbdev(intf); len = snprintf(buf, 256, "%s", intf->cur_altsetting->string); if (len < 0) return 0; @@ -384,7 +384,7 @@ error: return retval; } -void usb_remove_sysfs_intf_files (struct usb_interface *intf) +void usb_remove_sysfs_intf_files(struct usb_interface *intf) { usb_remove_intf_ep_files(intf); sysfs_remove_group(&intf->dev.kobj, &intf_attr_grp); diff --git a/drivers/usb/core/urb.c b/drivers/usb/core/urb.c index 9801d08..94ea972 100644 --- a/drivers/usb/core/urb.c +++ b/drivers/usb/core/urb.c @@ -235,16 +235,15 @@ int usb_submit_urb(struct urb *urb, gfp_ urb->status = -EINPROGRESS; urb->actual_length = 0; - urb->bandwidth = 0; /* Lots of sanity checks, so HCDs can rely on clean data * and don't need to duplicate tests */ pipe = urb->pipe; - temp = usb_pipetype (pipe); - is_out = usb_pipeout (pipe); + temp = usb_pipetype(pipe); + is_out = usb_pipeout(pipe); - if (!usb_pipecontrol (pipe) && dev->state < USB_STATE_CONFIGURED) + if (!usb_pipecontrol(pipe) && dev->state < USB_STATE_CONFIGURED) return -ENODEV; /* FIXME there should be a sharable lock protecting us against @@ -253,11 +252,11 @@ int usb_submit_urb(struct urb *urb, gfp_ * checks get made.) */ - max = usb_maxpacket (dev, pipe, is_out); + max = usb_maxpacket(dev, pipe, is_out); if (max <= 0) { dev_dbg(&dev->dev, "bogus endpoint ep%d%s in %s (bad maxpacket %d)\n", - usb_pipeendpoint (pipe), is_out ? "out" : "in", + usb_pipeendpoint(pipe), is_out ? "out" : "in", __FUNCTION__, max); return -EMSGSIZE; } @@ -279,11 +278,11 @@ int usb_submit_urb(struct urb *urb, gfp_ if (urb->number_of_packets <= 0) return -EINVAL; for (n = 0; n < urb->number_of_packets; n++) { - len = urb->iso_frame_desc [n].length; + len = urb->iso_frame_desc[n].length; if (len < 0 || len > max) return -EMSGSIZE; - urb->iso_frame_desc [n].status = -EXDEV; - urb->iso_frame_desc [n].actual_length = 0; + urb->iso_frame_desc[n].status = -EXDEV; + urb->iso_frame_desc[n].actual_length = 0; } } @@ -322,7 +321,7 @@ #ifdef DEBUG /* fail if submitter gave bogus flags */ if (urb->transfer_flags != orig_flags) { - err ("BOGUS urb flags, %x --> %x", + err("BOGUS urb flags, %x --> %x", orig_flags, urb->transfer_flags); return -EINVAL; } @@ -373,7 +372,7 @@ #endif urb->interval = temp; } - return usb_hcd_submit_urb (urb, mem_flags); + return usb_hcd_submit_urb(urb, mem_flags); } /*-------------------------------------------------------------------*/ diff --git a/drivers/usb/core/usb.c b/drivers/usb/core/usb.c index 02426d0..3db721c 100644 --- a/drivers/usb/core/usb.c +++ b/drivers/usb/core/usb.c @@ -233,7 +233,7 @@ #endif /* CONFIG_PM */ * @parent: hub to which device is connected; null to allocate a root hub * @bus: bus used to access the device * @port1: one-based index of port; ignored for root hubs - * Context: !in_interrupt () + * Context: !in_interrupt() * * Only hub drivers (including virtual root hub drivers for host * controllers) should ever call this. @@ -277,22 +277,22 @@ usb_alloc_dev(struct usb_device *parent, * as stable: bus->busnum changes easily from modprobe order, * cardbus or pci hotplugging, and so on. */ - if (unlikely (!parent)) { - dev->devpath [0] = '0'; + if (unlikely(!parent)) { + dev->devpath[0] = '0'; dev->dev.parent = bus->controller; - sprintf (&dev->dev.bus_id[0], "usb%d", bus->busnum); + sprintf(&dev->dev.bus_id[0], "usb%d", bus->busnum); } else { /* match any labeling on the hubs; it's one-based */ - if (parent->devpath [0] == '0') - snprintf (dev->devpath, sizeof dev->devpath, + if (parent->devpath[0] == '0') + snprintf(dev->devpath, sizeof dev->devpath, "%d", port1); else - snprintf (dev->devpath, sizeof dev->devpath, + snprintf(dev->devpath, sizeof dev->devpath, "%s.%d", parent->devpath, port1); dev->dev.parent = &parent->dev; - sprintf (&dev->dev.bus_id[0], "%d-%s", + sprintf(&dev->dev.bus_id[0], "%d-%s", bus->busnum, dev->devpath); /* hub driver sets up TT records */ @@ -463,7 +463,7 @@ static struct usb_device *match_device(s /* see if this device matches */ if ((vendor_id == le16_to_cpu(dev->descriptor.idVendor)) && (product_id == le16_to_cpu(dev->descriptor.idProduct))) { - dev_dbg (&dev->dev, "matched this device!\n"); + dev_dbg(&dev->dev, "matched this device!\n"); ret_dev = usb_get_dev(dev); goto exit; } @@ -535,7 +535,7 @@ exit: */ int usb_get_current_frame_number(struct usb_device *dev) { - return usb_hcd_get_frame_number (dev); + return usb_hcd_get_frame_number(dev); } /*-------------------------------------------------------------------*/ @@ -593,7 +593,7 @@ int __usb_get_extra_descriptor(char *buf * * When the buffer is no longer used, free it with usb_buffer_free(). */ -void *usb_buffer_alloc ( +void *usb_buffer_alloc( struct usb_device *dev, size_t size, gfp_t mem_flags, @@ -602,7 +602,7 @@ void *usb_buffer_alloc ( { if (!dev || !dev->bus) return NULL; - return hcd_buffer_alloc (dev->bus, size, mem_flags, dma); + return hcd_buffer_alloc(dev->bus, size, mem_flags, dma); } /** @@ -616,7 +616,7 @@ void *usb_buffer_alloc ( * been allocated using usb_buffer_alloc(), and the parameters must match * those provided in that allocation request. */ -void usb_buffer_free ( +void usb_buffer_free( struct usb_device *dev, size_t size, void *addr, @@ -627,7 +627,7 @@ void usb_buffer_free ( return; if (!addr) return; - hcd_buffer_free (dev->bus, size, addr, dma); + hcd_buffer_free(dev->bus, size, addr, dma); } /** @@ -647,7 +647,7 @@ void usb_buffer_free ( * Reverse the effect of this call with usb_buffer_unmap(). */ #if 0 -struct urb *usb_buffer_map (struct urb *urb) +struct urb *usb_buffer_map(struct urb *urb) { struct usb_bus *bus; struct device *controller; @@ -659,14 +659,14 @@ struct urb *usb_buffer_map (struct urb * return NULL; if (controller->dma_mask) { - urb->transfer_dma = dma_map_single (controller, + urb->transfer_dma = dma_map_single(controller, urb->transfer_buffer, urb->transfer_buffer_length, - usb_pipein (urb->pipe) + usb_pipein(urb->pipe) ? DMA_FROM_DEVICE : DMA_TO_DEVICE); - if (usb_pipecontrol (urb->pipe)) - urb->setup_dma = dma_map_single (controller, + if (usb_pipecontrol(urb->pipe)) + urb->setup_dma = dma_map_single(controller, urb->setup_packet, - sizeof (struct usb_ctrlrequest), + sizeof(struct usb_ctrlrequest), DMA_TO_DEVICE); // FIXME generic api broken like pci, can't report errors // if (urb->transfer_dma == DMA_ADDR_INVALID) return 0; @@ -689,7 +689,7 @@ #if 0 * usb_buffer_dmasync - synchronize DMA and CPU view of buffer(s) * @urb: urb whose transfer_buffer/setup_packet will be synchronized */ -void usb_buffer_dmasync (struct urb *urb) +void usb_buffer_dmasync(struct urb *urb) { struct usb_bus *bus; struct device *controller; @@ -702,14 +702,14 @@ void usb_buffer_dmasync (struct urb *urb return; if (controller->dma_mask) { - dma_sync_single (controller, + dma_sync_single(controller, urb->transfer_dma, urb->transfer_buffer_length, - usb_pipein (urb->pipe) + usb_pipein(urb->pipe) ? DMA_FROM_DEVICE : DMA_TO_DEVICE); - if (usb_pipecontrol (urb->pipe)) - dma_sync_single (controller, + if (usb_pipecontrol(urb->pipe)) + dma_sync_single(controller, urb->setup_dma, - sizeof (struct usb_ctrlrequest), + sizeof(struct usb_ctrlrequest), DMA_TO_DEVICE); } } @@ -722,7 +722,7 @@ #endif * Reverses the effect of usb_buffer_map(). */ #if 0 -void usb_buffer_unmap (struct urb *urb) +void usb_buffer_unmap(struct urb *urb) { struct usb_bus *bus; struct device *controller; @@ -735,14 +735,14 @@ void usb_buffer_unmap (struct urb *urb) return; if (controller->dma_mask) { - dma_unmap_single (controller, + dma_unmap_single(controller, urb->transfer_dma, urb->transfer_buffer_length, - usb_pipein (urb->pipe) + usb_pipein(urb->pipe) ? DMA_FROM_DEVICE : DMA_TO_DEVICE); - if (usb_pipecontrol (urb->pipe)) - dma_unmap_single (controller, + if (usb_pipecontrol(urb->pipe)) + dma_unmap_single(controller, urb->setup_dma, - sizeof (struct usb_ctrlrequest), + sizeof(struct usb_ctrlrequest), DMA_TO_DEVICE); } urb->transfer_flags &= ~(URB_NO_TRANSFER_DMA_MAP @@ -783,15 +783,15 @@ int usb_buffer_map_sg(const struct usb_d struct device *controller; if (!dev - || usb_pipecontrol (pipe) + || usb_pipecontrol(pipe) || !(bus = dev->bus) || !(controller = bus->controller) || !controller->dma_mask) return -1; // FIXME generic api broken like pci, can't report errors - return dma_map_sg (controller, sg, nents, - usb_pipein (pipe) ? DMA_FROM_DEVICE : DMA_TO_DEVICE); + return dma_map_sg(controller, sg, nents, + usb_pipein(pipe) ? DMA_FROM_DEVICE : DMA_TO_DEVICE); } /* XXX DISABLED, no users currently. If you wish to re-enable this @@ -823,8 +823,8 @@ void usb_buffer_dmasync_sg(const struct || !controller->dma_mask) return; - dma_sync_sg (controller, sg, n_hw_ents, - usb_pipein (pipe) ? DMA_FROM_DEVICE : DMA_TO_DEVICE); + dma_sync_sg(controller, sg, n_hw_ents, + usb_pipein(pipe) ? DMA_FROM_DEVICE : DMA_TO_DEVICE); } #endif @@ -849,8 +849,8 @@ void usb_buffer_unmap_sg(const struct us || !controller->dma_mask) return; - dma_unmap_sg (controller, sg, n_hw_ents, - usb_pipein (pipe) ? DMA_FROM_DEVICE : DMA_TO_DEVICE); + dma_unmap_sg(controller, sg, n_hw_ents, + usb_pipein(pipe) ? DMA_FROM_DEVICE : DMA_TO_DEVICE); } /* format to disable USB on kernel command line is: nousb */ @@ -871,7 +871,7 @@ static int __init usb_init(void) { int retval; if (nousb) { - pr_info ("%s: USB support disabled\n", usbcore_name); + pr_info("%s: USB support disabled\n", usbcore_name); return 0; } @@ -971,19 +971,19 @@ EXPORT_SYMBOL(__usb_get_extra_descriptor EXPORT_SYMBOL(usb_find_device); EXPORT_SYMBOL(usb_get_current_frame_number); -EXPORT_SYMBOL (usb_buffer_alloc); -EXPORT_SYMBOL (usb_buffer_free); +EXPORT_SYMBOL(usb_buffer_alloc); +EXPORT_SYMBOL(usb_buffer_free); #if 0 -EXPORT_SYMBOL (usb_buffer_map); -EXPORT_SYMBOL (usb_buffer_dmasync); -EXPORT_SYMBOL (usb_buffer_unmap); +EXPORT_SYMBOL(usb_buffer_map); +EXPORT_SYMBOL(usb_buffer_dmasync); +EXPORT_SYMBOL(usb_buffer_unmap); #endif -EXPORT_SYMBOL (usb_buffer_map_sg); +EXPORT_SYMBOL(usb_buffer_map_sg); #if 0 -EXPORT_SYMBOL (usb_buffer_dmasync_sg); +EXPORT_SYMBOL(usb_buffer_dmasync_sg); #endif -EXPORT_SYMBOL (usb_buffer_unmap_sg); +EXPORT_SYMBOL(usb_buffer_unmap_sg); MODULE_LICENSE("GPL"); diff --git a/drivers/usb/gadget/at91_udc.c b/drivers/usb/gadget/at91_udc.c index 812c733..36b36e0 100644 --- a/drivers/usb/gadget/at91_udc.c +++ b/drivers/usb/gadget/at91_udc.c @@ -30,7 +30,6 @@ #include #include #include #include -#include #include #include #include @@ -39,7 +38,7 @@ #include #include #include #include -#include +#include #include #include @@ -1807,16 +1806,13 @@ static int at91udc_suspend(struct platfo || !wake || at91_suspend_entering_slow_clock()) { pullup(udc, 0); - disable_irq_wake(udc->udp_irq); + wake = 0; } else enable_irq_wake(udc->udp_irq); - if (udc->board.vbus_pin > 0) { - if (wake) - enable_irq_wake(udc->board.vbus_pin); - else - disable_irq_wake(udc->board.vbus_pin); - } + udc->active_suspend = wake; + if (udc->board.vbus_pin > 0 && wake) + enable_irq_wake(udc->board.vbus_pin); return 0; } @@ -1824,8 +1820,14 @@ static int at91udc_resume(struct platfor { struct at91_udc *udc = platform_get_drvdata(pdev); + if (udc->board.vbus_pin > 0 && udc->active_suspend) + disable_irq_wake(udc->board.vbus_pin); + /* maybe reconnect to host; if so, clocks on */ - pullup(udc, 1); + if (udc->active_suspend) + disable_irq_wake(udc->udp_irq); + else + pullup(udc, 1); return 0; } #else diff --git a/drivers/usb/gadget/at91_udc.h b/drivers/usb/gadget/at91_udc.h index 677089b..7e34e2f 100644 --- a/drivers/usb/gadget/at91_udc.h +++ b/drivers/usb/gadget/at91_udc.h @@ -136,6 +136,7 @@ struct at91_udc { unsigned wait_for_addr_ack:1; unsigned wait_for_config_ack:1; unsigned selfpowered:1; + unsigned active_suspend:1; u8 addr; struct at91_udc_data board; struct clk *iclk, *fclk; diff --git a/drivers/usb/gadget/config.c b/drivers/usb/gadget/config.c index 83b4866..d18901b 100644 --- a/drivers/usb/gadget/config.c +++ b/drivers/usb/gadget/config.c @@ -24,7 +24,7 @@ #include #include #include -#include +#include #include diff --git a/drivers/usb/gadget/dummy_hcd.c b/drivers/usb/gadget/dummy_hcd.c index 3c2bc07..7d7909c 100644 --- a/drivers/usb/gadget/dummy_hcd.c +++ b/drivers/usb/gadget/dummy_hcd.c @@ -40,7 +40,6 @@ #include #include #include #include -#include #include #include #include diff --git a/drivers/usb/gadget/epautoconf.c b/drivers/usb/gadget/epautoconf.c index 53d5845..f28af06 100644 --- a/drivers/usb/gadget/epautoconf.c +++ b/drivers/usb/gadget/epautoconf.c @@ -27,7 +27,7 @@ #include #include #include -#include +#include #include #include "gadget_chips.h" diff --git a/drivers/usb/gadget/ether.c b/drivers/usb/gadget/ether.c index d15bf22..04e6b85 100644 --- a/drivers/usb/gadget/ether.c +++ b/drivers/usb/gadget/ether.c @@ -27,7 +27,6 @@ #include #include #include #include -#include #include #include #include @@ -47,7 +46,7 @@ #include #include #include -#include +#include #include #include @@ -72,9 +71,18 @@ #include "gadget_chips.h" * * There's some hardware that can't talk CDC. We make that hardware * implement a "minimalist" vendor-agnostic CDC core: same framing, but - * link-level setup only requires activating the configuration. - * Linux supports it, but other host operating systems may not. - * (This is a subset of CDC Ethernet.) + * link-level setup only requires activating the configuration. Only the + * endpoint descriptors, and product/vendor IDs, are relevant; no control + * operations are available. Linux supports it, but other host operating + * systems may not. (This is a subset of CDC Ethernet.) + * + * It turns out that if you add a few descriptors to that "CDC Subset", + * (Windows) host side drivers from MCCI can treat it as one submode of + * a proprietary scheme called "SAFE" ... without needing to know about + * specific product/vendor IDs. So we do that, making it easier to use + * those MS-Windows drivers. Those added descriptors make it resemble a + * CDC MDLM device, but they don't change device behavior at all. (See + * MCCI Engineering report 950198 "SAFE Networking Functions".) * * A third option is also in use. Rather than CDC Ethernet, or something * simpler, Microsoft pushes their own approach: RNDIS. The published @@ -254,6 +262,10 @@ #ifdef CONFIG_USB_GADGET_PXA27X #define DEV_CONFIG_CDC #endif +#ifdef CONFIG_USB_GADGET_S3C2410 +#define DEV_CONFIG_CDC +#endif + #ifdef CONFIG_USB_GADGET_AT91 #define DEV_CONFIG_CDC #endif @@ -266,6 +278,10 @@ #ifdef CONFIG_USB_GADGET_MUSB_HDRC #define DEV_CONFIG_CDC #endif +#ifdef CONFIG_USB_GADGET_HUSB2DEV +#define DEV_CONFIG_CDC +#endif + /* For CDC-incapable hardware, choose the simple cdc subset. * Anything that talks bulk (without notable bugs) can do this. @@ -283,9 +299,6 @@ #ifdef CONFIG_USB_GADGET_SA1100 #define DEV_CONFIG_SUBSET #endif -#ifdef CONFIG_USB_GADGET_S3C2410 -#define DEV_CONFIG_CDC -#endif /*-------------------------------------------------------------------------*/ @@ -487,8 +500,17 @@ #endif * endpoint. Both have a "data" interface and two bulk endpoints. * There are also differences in how control requests are handled. * - * RNDIS shares a lot with CDC-Ethernet, since it's a variant of - * the CDC-ACM (modem) spec. + * RNDIS shares a lot with CDC-Ethernet, since it's a variant of the + * CDC-ACM (modem) spec. Unfortunately MSFT's RNDIS driver is buggy; it + * may hang or oops. Since bugfixes (or accurate specs, letting Linux + * work around those bugs) are unlikely to ever come from MSFT, you may + * wish to avoid using RNDIS. + * + * MCCI offers an alternative to RNDIS if you need to connect to Windows + * but have hardware that can't support CDC Ethernet. We add descriptors + * to present the CDC Subset as a (nonconformant) CDC MDLM variant called + * "SAFE". That borrows from both CDC Ethernet and CDC MDLM. You can + * get those drivers from MCCI, or bundled with various products. */ #ifdef DEV_CONFIG_CDC @@ -522,8 +544,6 @@ rndis_control_intf = { }; #endif -#if defined(DEV_CONFIG_CDC) || defined(CONFIG_USB_ETH_RNDIS) - static const struct usb_cdc_header_desc header_desc = { .bLength = sizeof header_desc, .bDescriptorType = USB_DT_CS_INTERFACE, @@ -532,6 +552,8 @@ static const struct usb_cdc_header_desc .bcdCDC = __constant_cpu_to_le16 (0x0110), }; +#if defined(DEV_CONFIG_CDC) || defined(CONFIG_USB_ETH_RNDIS) + static const struct usb_cdc_union_desc union_desc = { .bLength = sizeof union_desc, .bDescriptorType = USB_DT_CS_INTERFACE, @@ -564,7 +586,40 @@ static const struct usb_cdc_acm_descript #endif -#ifdef DEV_CONFIG_CDC +#ifndef DEV_CONFIG_CDC + +/* "SAFE" loosely follows CDC WMC MDLM, violating the spec in various + * ways: data endpoints live in the control interface, there's no data + * interface, and it's not used to talk to a cell phone radio. + */ + +static const struct usb_cdc_mdlm_desc mdlm_desc = { + .bLength = sizeof mdlm_desc, + .bDescriptorType = USB_DT_CS_INTERFACE, + .bDescriptorSubType = USB_CDC_MDLM_TYPE, + + .bcdVersion = __constant_cpu_to_le16(0x0100), + .bGUID = { + 0x5d, 0x34, 0xcf, 0x66, 0x11, 0x18, 0x11, 0xd6, + 0xa2, 0x1a, 0x00, 0x01, 0x02, 0xca, 0x9a, 0x7f, + }, +}; + +/* since "usb_cdc_mdlm_detail_desc" is a variable length structure, we + * can't really use its struct. All we do here is say that we're using + * the submode of "SAFE" which directly matches the CDC Subset. + */ +static const u8 mdlm_detail_desc[] = { + 6, + USB_DT_CS_INTERFACE, + USB_CDC_MDLM_DETAIL_TYPE, + + 0, /* "SAFE" */ + 0, /* network control capabilities (none) */ + 0, /* network data capabilities ("raw" encapsulation) */ +}; + +#endif static const struct usb_cdc_ether_desc ether_desc = { .bLength = sizeof ether_desc, @@ -579,7 +634,6 @@ static const struct usb_cdc_ether_desc e .bNumberPowerFilters = 0, }; -#endif #if defined(DEV_CONFIG_CDC) || defined(CONFIG_USB_ETH_RNDIS) @@ -672,6 +726,9 @@ #ifdef DEV_CONFIG_SUBSET /* * "Simple" CDC-subset option is a simple vendor-neutral model that most * full speed controllers can handle: one interface, two bulk endpoints. + * + * To assist host side drivers, we fancy it up a bit, and add descriptors + * so some host side drivers will understand it as a "SAFE" variant. */ static const struct usb_interface_descriptor @@ -682,8 +739,8 @@ subset_data_intf = { .bInterfaceNumber = 0, .bAlternateSetting = 0, .bNumEndpoints = 2, - .bInterfaceClass = USB_CLASS_VENDOR_SPEC, - .bInterfaceSubClass = 0, + .bInterfaceClass = USB_CLASS_COMM, + .bInterfaceSubClass = USB_CDC_SUBCLASS_MDLM, .bInterfaceProtocol = 0, .iInterface = STRING_DATA, }; @@ -731,10 +788,15 @@ #endif /* DEV_CONFIG_CDC */ static inline void __init fs_subset_descriptors(void) { #ifdef DEV_CONFIG_SUBSET + /* behavior is "CDC Subset"; extra descriptors say "SAFE" */ fs_eth_function[1] = (struct usb_descriptor_header *) &subset_data_intf; - fs_eth_function[2] = (struct usb_descriptor_header *) &fs_source_desc; - fs_eth_function[3] = (struct usb_descriptor_header *) &fs_sink_desc; - fs_eth_function[4] = NULL; + fs_eth_function[2] = (struct usb_descriptor_header *) &header_desc; + fs_eth_function[3] = (struct usb_descriptor_header *) &mdlm_desc; + fs_eth_function[4] = (struct usb_descriptor_header *) &mdlm_detail_desc; + fs_eth_function[5] = (struct usb_descriptor_header *) ðer_desc; + fs_eth_function[6] = (struct usb_descriptor_header *) &fs_source_desc; + fs_eth_function[7] = (struct usb_descriptor_header *) &fs_sink_desc; + fs_eth_function[8] = NULL; #else fs_eth_function[1] = NULL; #endif @@ -828,10 +890,15 @@ #endif /* DEV_CONFIG_CDC */ static inline void __init hs_subset_descriptors(void) { #ifdef DEV_CONFIG_SUBSET + /* behavior is "CDC Subset"; extra descriptors say "SAFE" */ hs_eth_function[1] = (struct usb_descriptor_header *) &subset_data_intf; - hs_eth_function[2] = (struct usb_descriptor_header *) &fs_source_desc; - hs_eth_function[3] = (struct usb_descriptor_header *) &fs_sink_desc; - hs_eth_function[4] = NULL; + hs_eth_function[2] = (struct usb_descriptor_header *) &header_desc; + hs_eth_function[3] = (struct usb_descriptor_header *) &mdlm_desc; + hs_eth_function[4] = (struct usb_descriptor_header *) &mdlm_detail_desc; + hs_eth_function[5] = (struct usb_descriptor_header *) ðer_desc; + hs_eth_function[6] = (struct usb_descriptor_header *) &hs_source_desc; + hs_eth_function[7] = (struct usb_descriptor_header *) &hs_sink_desc; + hs_eth_function[8] = NULL; #else hs_eth_function[1] = NULL; #endif @@ -878,10 +945,8 @@ static char manufacturer [50]; static char product_desc [40] = DRIVER_DESC; static char serial_number [20]; -#ifdef DEV_CONFIG_CDC /* address that the host will use ... usually assigned at random */ static char ethaddr [2 * ETH_ALEN + 1]; -#endif /* static strings, in UTF-8 */ static struct usb_string strings [] = { @@ -889,9 +954,9 @@ static struct usb_string strings [] = { { STRING_PRODUCT, product_desc, }, { STRING_SERIALNUMBER, serial_number, }, { STRING_DATA, "Ethernet Data", }, + { STRING_ETHADDR, ethaddr, }, #ifdef DEV_CONFIG_CDC { STRING_CDC, "CDC Ethernet", }, - { STRING_ETHADDR, ethaddr, }, { STRING_CONTROL, "CDC Communications Control", }, #endif #ifdef DEV_CONFIG_SUBSET @@ -986,10 +1051,10 @@ #if defined(DEV_CONFIG_CDC) || defined(C } #endif - dev->in = ep_desc (dev->gadget, &hs_source_desc, &fs_source_desc); + dev->in = ep_desc(gadget, &hs_source_desc, &fs_source_desc); dev->in_ep->driver_data = dev; - dev->out = ep_desc (dev->gadget, &hs_sink_desc, &fs_sink_desc); + dev->out = ep_desc(gadget, &hs_sink_desc, &fs_sink_desc); dev->out_ep->driver_data = dev; /* With CDC, the host isn't allowed to use these two data @@ -2278,10 +2343,10 @@ #endif "RNDIS/%s", driver_desc); /* CDC subset ... recognized by Linux since 2.4.10, but Windows - * drivers aren't widely available. + * drivers aren't widely available. (That may be improved by + * supporting one submode of the "SAFE" variant of MDLM.) */ } else if (!cdc) { - device_desc.bDeviceClass = USB_CLASS_VENDOR_SPEC; device_desc.idVendor = __constant_cpu_to_le16(SIMPLE_VENDOR_NUM); device_desc.idProduct = @@ -2352,6 +2417,10 @@ #endif if (!cdc) { eth_config.bNumInterfaces = 1; eth_config.iConfiguration = STRING_SUBSET; + + /* use functions to set these up, in case we're built to work + * with multiple controllers and must override CDC Ethernet. + */ fs_subset_descriptors(); hs_subset_descriptors(); } @@ -2415,22 +2484,20 @@ #endif /* Module params for these addresses should come from ID proms. * The host side address is used with CDC and RNDIS, and commonly - * ends up in a persistent config database. + * ends up in a persistent config database. It's not clear if + * host side code for the SAFE thing cares -- its original BLAN + * thing didn't, Sharp never assigned those addresses on Zaurii. */ if (get_ether_addr(dev_addr, net->dev_addr)) dev_warn(&gadget->dev, "using random %s ethernet address\n", "self"); - if (cdc || rndis) { - if (get_ether_addr(host_addr, dev->host_mac)) - dev_warn(&gadget->dev, - "using random %s ethernet address\n", "host"); -#ifdef DEV_CONFIG_CDC - snprintf (ethaddr, sizeof ethaddr, "%02X%02X%02X%02X%02X%02X", - dev->host_mac [0], dev->host_mac [1], - dev->host_mac [2], dev->host_mac [3], - dev->host_mac [4], dev->host_mac [5]); -#endif - } + if (get_ether_addr(host_addr, dev->host_mac)) + dev_warn(&gadget->dev, + "using random %s ethernet address\n", "host"); + snprintf (ethaddr, sizeof ethaddr, "%02X%02X%02X%02X%02X%02X", + dev->host_mac [0], dev->host_mac [1], + dev->host_mac [2], dev->host_mac [3], + dev->host_mac [4], dev->host_mac [5]); if (rndis) { status = rndis_init(); diff --git a/drivers/usb/gadget/file_storage.c b/drivers/usb/gadget/file_storage.c index 72f2ae9..c6b6479 100644 --- a/drivers/usb/gadget/file_storage.c +++ b/drivers/usb/gadget/file_storage.c @@ -253,7 +253,7 @@ #include #include #include -#include +#include #include #include "gadget_chips.h" @@ -1148,7 +1148,7 @@ static int ep0_queue(struct fsg_dev *fsg static void ep0_complete(struct usb_ep *ep, struct usb_request *req) { - struct fsg_dev *fsg = (struct fsg_dev *) ep->driver_data; + struct fsg_dev *fsg = ep->driver_data; if (req->actual > 0) dump_msg(fsg, fsg->ep0req_name, req->buf, req->actual); @@ -1170,8 +1170,8 @@ static void ep0_complete(struct usb_ep * static void bulk_in_complete(struct usb_ep *ep, struct usb_request *req) { - struct fsg_dev *fsg = (struct fsg_dev *) ep->driver_data; - struct fsg_buffhd *bh = (struct fsg_buffhd *) req->context; + struct fsg_dev *fsg = ep->driver_data; + struct fsg_buffhd *bh = req->context; if (req->status || req->actual != req->length) DBG(fsg, "%s --> %d, %u/%u\n", __FUNCTION__, @@ -1190,8 +1190,8 @@ static void bulk_in_complete(struct usb_ static void bulk_out_complete(struct usb_ep *ep, struct usb_request *req) { - struct fsg_dev *fsg = (struct fsg_dev *) ep->driver_data; - struct fsg_buffhd *bh = (struct fsg_buffhd *) req->context; + struct fsg_dev *fsg = ep->driver_data; + struct fsg_buffhd *bh = req->context; dump_msg(fsg, "bulk-out", req->buf, req->actual); if (req->status || req->actual != bh->bulk_out_intended_length) @@ -1214,8 +1214,8 @@ static void bulk_out_complete(struct usb #ifdef CONFIG_USB_FILE_STORAGE_TEST static void intr_in_complete(struct usb_ep *ep, struct usb_request *req) { - struct fsg_dev *fsg = (struct fsg_dev *) ep->driver_data; - struct fsg_buffhd *bh = (struct fsg_buffhd *) req->context; + struct fsg_dev *fsg = ep->driver_data; + struct fsg_buffhd *bh = req->context; if (req->status || req->actual != req->length) DBG(fsg, "%s --> %d, %u/%u\n", __FUNCTION__, @@ -1953,7 +1953,7 @@ static void invalidate_sub(struct lun *c struct inode *inode = filp->f_path.dentry->d_inode; unsigned long rc; - rc = invalidate_inode_pages(inode->i_mapping); + rc = invalidate_mapping_pages(inode->i_mapping, 0, -1); VLDBG(curlun, "invalidate_inode_pages -> %ld\n", rc); } @@ -2577,7 +2577,7 @@ static int send_status(struct fsg_dev *f } if (transport_is_bbb()) { - struct bulk_cs_wrap *csw = (struct bulk_cs_wrap *) bh->buf; + struct bulk_cs_wrap *csw = bh->buf; /* Store and send the Bulk-only CSW */ csw->Signature = __constant_cpu_to_le32(USB_BULK_CS_SIG); @@ -2596,8 +2596,7 @@ static int send_status(struct fsg_dev *f return 0; } else { // USB_PR_CBI - struct interrupt_data *buf = (struct interrupt_data *) - bh->buf; + struct interrupt_data *buf = bh->buf; /* Store and send the Interrupt data. UFI sends the ASC * and ASCQ bytes. Everything else sends a Type (which @@ -2982,7 +2981,7 @@ static int do_scsi_command(struct fsg_de static int received_cbw(struct fsg_dev *fsg, struct fsg_buffhd *bh) { struct usb_request *req = bh->outreq; - struct bulk_cb_wrap *cbw = (struct bulk_cb_wrap *) req->buf; + struct bulk_cb_wrap *cbw = req->buf; /* Was this a real packet? */ if (req->status) @@ -3428,7 +3427,7 @@ static void handle_exception(struct fsg_ static int fsg_main_thread(void *fsg_) { - struct fsg_dev *fsg = (struct fsg_dev *) fsg_; + struct fsg_dev *fsg = fsg_; /* Allow the thread to be killed by a signal, but set the signal mask * to block everything but INT, TERM, KILL, and USR1. */ @@ -3600,7 +3599,7 @@ static ssize_t show_ro(struct device *de static ssize_t show_file(struct device *dev, struct device_attribute *attr, char *buf) { struct lun *curlun = dev_to_lun(dev); - struct fsg_dev *fsg = (struct fsg_dev *) dev_get_drvdata(dev); + struct fsg_dev *fsg = dev_get_drvdata(dev); char *p; ssize_t rc; @@ -3629,7 +3628,7 @@ static ssize_t store_ro(struct device *d { ssize_t rc = count; struct lun *curlun = dev_to_lun(dev); - struct fsg_dev *fsg = (struct fsg_dev *) dev_get_drvdata(dev); + struct fsg_dev *fsg = dev_get_drvdata(dev); int i; if (sscanf(buf, "%d", &i) != 1) @@ -3652,7 +3651,7 @@ static ssize_t store_ro(struct device *d static ssize_t store_file(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { struct lun *curlun = dev_to_lun(dev); - struct fsg_dev *fsg = (struct fsg_dev *) dev_get_drvdata(dev); + struct fsg_dev *fsg = dev_get_drvdata(dev); int rc = 0; if (curlun->prevent_medium_removal && backing_file_is_open(curlun)) { @@ -3700,7 +3699,7 @@ static void fsg_release(struct kref *ref static void lun_release(struct device *dev) { - struct fsg_dev *fsg = (struct fsg_dev *) dev_get_drvdata(dev); + struct fsg_dev *fsg = dev_get_drvdata(dev); kref_put(&fsg->ref, fsg_release); } diff --git a/drivers/usb/gadget/gadget_chips.h b/drivers/usb/gadget/gadget_chips.h index aa80f09..2e3d662 100644 --- a/drivers/usb/gadget/gadget_chips.h +++ b/drivers/usb/gadget/gadget_chips.h @@ -75,6 +75,12 @@ #else #define gadget_is_pxa27x(g) 0 #endif +#ifdef CONFIG_USB_GADGET_HUSB2DEV +#define gadget_is_husb2dev(g) !strcmp("husb2_udc", (g)->name) +#else +#define gadget_is_husb2dev(g) 0 +#endif + #ifdef CONFIG_USB_GADGET_S3C2410 #define gadget_is_s3c2410(g) !strcmp("s3c2410_udc", (g)->name) #else @@ -169,5 +175,7 @@ static inline int usb_gadget_controller_ return 0x16; else if (gadget_is_mpc8272(gadget)) return 0x17; + else if (gadget_is_husb2dev(gadget)) + return 0x18; return -ENOENT; } diff --git a/drivers/usb/gadget/gmidi.c b/drivers/usb/gadget/gmidi.c index f1a6796..d08a8d0 100644 --- a/drivers/usb/gadget/gmidi.c +++ b/drivers/usb/gadget/gmidi.c @@ -35,7 +35,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/drivers/usb/gadget/goku_udc.c b/drivers/usb/gadget/goku_udc.c index d0ef1d6..7b3a326 100644 --- a/drivers/usb/gadget/goku_udc.c +++ b/drivers/usb/gadget/goku_udc.c @@ -29,7 +29,6 @@ #include #include #include #include -#include #include #include #include @@ -39,7 +38,7 @@ #include #include #include #include -#include +#include #include #include diff --git a/drivers/usb/gadget/inode.c b/drivers/usb/gadget/inode.c index 3fb1044..34296e7 100644 --- a/drivers/usb/gadget/inode.c +++ b/drivers/usb/gadget/inode.c @@ -20,7 +20,7 @@ */ -// #define DEBUG /* data to help fault diagnosis */ +// #define DEBUG /* data to help fault diagnosis */ // #define VERBOSE /* extra debug messages (success too) */ #include @@ -59,11 +59,11 @@ #include * may serve as a source of device events, used to handle all control * requests other than basic enumeration. * - * - Then either immediately, or after a SET_CONFIGURATION control request, - * ep_config() is called when each /dev/gadget/ep* file is configured - * (by writing endpoint descriptors). Afterwards these files are used - * to write() IN data or to read() OUT data. To halt the endpoint, a - * "wrong direction" request is issued (like reading an IN endpoint). + * - Then, after a SET_CONFIGURATION control request, ep_config() is + * called when each /dev/gadget/ep* file is configured (by writing + * endpoint descriptors). Afterwards these files are used to write() + * IN data or to read() OUT data. To halt the endpoint, a "wrong + * direction" request is issued (like reading an IN endpoint). * * Unlike "usbfs" the only ioctl()s are for things that are rare, and maybe * not possible on all hardware. For example, precise fault handling with @@ -98,16 +98,16 @@ enum ep0_state { * must always write descriptors to initialize the device, then * the device becomes UNCONNECTED until enumeration. */ - STATE_OPENED, + STATE_DEV_OPENED, /* From then on, ep0 fd is in either of two basic modes: * - (UN)CONNECTED: read usb_gadgetfs_event(s) from it * - SETUP: read/write will transfer control data and succeed; * or if "wrong direction", performs protocol stall */ - STATE_UNCONNECTED, - STATE_CONNECTED, - STATE_SETUP, + STATE_DEV_UNCONNECTED, + STATE_DEV_CONNECTED, + STATE_DEV_SETUP, /* UNBOUND means the driver closed ep0, so the device won't be * accessible again (DEV_DISABLED) until all fds are closed. @@ -121,7 +121,7 @@ #define N_EVENT 5 struct dev_data { spinlock_t lock; atomic_t count; - enum ep0_state state; + enum ep0_state state; /* P: lock */ struct usb_gadgetfs_event event [N_EVENT]; unsigned ev_next; struct fasync_struct *fasync; @@ -188,7 +188,6 @@ static struct dev_data *dev_new (void) enum ep_state { STATE_EP_DISABLED = 0, STATE_EP_READY, - STATE_EP_DEFER_ENABLE, STATE_EP_ENABLED, STATE_EP_UNBOUND, }; @@ -313,18 +312,10 @@ nonblock: if ((val = down_interruptible (&epdata->lock)) < 0) return val; -newstate: + switch (epdata->state) { case STATE_EP_ENABLED: break; - case STATE_EP_DEFER_ENABLE: - DBG (epdata->dev, "%s wait for host\n", epdata->name); - if ((val = wait_event_interruptible (epdata->wait, - epdata->state != STATE_EP_DEFER_ENABLE - || epdata->dev->state == STATE_DEV_UNBOUND - )) < 0) - goto fail; - goto newstate; // case STATE_EP_DISABLED: /* "can't happen" */ // case STATE_EP_READY: /* "can't happen" */ default: /* error! */ @@ -333,7 +324,6 @@ newstate: // FALLTHROUGH case STATE_EP_UNBOUND: /* clean disconnect */ val = -ENODEV; -fail: up (&epdata->lock); } return val; @@ -565,29 +555,28 @@ static ssize_t ep_aio_read_retry(struct ssize_t len, total; int i; - /* we "retry" to get the right mm context for this: */ - - /* copy stuff into user buffers */ - total = priv->actual; - len = 0; - for (i=0; i < priv->nr_segs; i++) { - ssize_t this = min((ssize_t)(priv->iv[i].iov_len), total); - - if (copy_to_user(priv->iv[i].iov_base, priv->buf, this)) { - if (len == 0) - len = -EFAULT; - break; - } - - total -= this; - len += this; - if (total == 0) - break; - } - kfree(priv->buf); - kfree(priv); - aio_put_req(iocb); - return len; + /* we "retry" to get the right mm context for this: */ + + /* copy stuff into user buffers */ + total = priv->actual; + len = 0; + for (i=0; i < priv->nr_segs; i++) { + ssize_t this = min((ssize_t)(priv->iv[i].iov_len), total); + + if (copy_to_user(priv->iv[i].iov_base, priv->buf, this)) { + if (len == 0) + len = -EFAULT; + break; + } + + total -= this; + len += this; + if (total == 0) + break; + } + kfree(priv->buf); + kfree(priv); + return len; } static void ep_aio_complete(struct usb_ep *ep, struct usb_request *req) @@ -600,18 +589,17 @@ static void ep_aio_complete(struct usb_e spin_lock(&epdata->dev->lock); priv->req = NULL; priv->epdata = NULL; - if (priv->iv == NULL - || unlikely(req->actual == 0) - || unlikely(kiocbIsCancelled(iocb))) { + + /* if this was a write or a read returning no data then we + * don't need to copy anything to userspace, so we can + * complete the aio request immediately. + */ + if (priv->iv == NULL || unlikely(req->actual == 0)) { kfree(req->buf); kfree(priv); iocb->private = NULL; /* aio_complete() reports bytes-transferred _and_ faults */ - if (unlikely(kiocbIsCancelled(iocb))) - aio_put_req(iocb); - else - aio_complete(iocb, - req->actual ? req->actual : req->status, + aio_complete(iocb, req->actual ? req->actual : req->status, req->status); } else { /* retry() won't report both; so we hide some faults */ @@ -636,7 +624,7 @@ ep_aio_rwtail( size_t len, struct ep_data *epdata, const struct iovec *iv, - unsigned long nr_segs + unsigned long nr_segs ) { struct kiocb_priv *priv; @@ -852,9 +840,9 @@ #ifdef CONFIG_USB_GADGET_DUALSPEED break; #endif default: - DBG (data->dev, "unconnected, %s init deferred\n", + DBG(data->dev, "unconnected, %s init abandoned\n", data->name); - data->state = STATE_EP_DEFER_ENABLE; + value = -EINVAL; } if (value == 0) { fd->f_op = &ep_io_operations; @@ -943,22 +931,24 @@ static void clean_req (struct usb_ep *ep static void ep0_complete (struct usb_ep *ep, struct usb_request *req) { struct dev_data *dev = ep->driver_data; + unsigned long flags; int free = 1; /* for control OUT, data must still get to userspace */ + spin_lock_irqsave(&dev->lock, flags); if (!dev->setup_in) { dev->setup_out_error = (req->status != 0); if (!dev->setup_out_error) free = 0; dev->setup_out_ready = 1; ep0_readable (dev); - } else if (dev->state == STATE_SETUP) - dev->state = STATE_CONNECTED; + } /* clean up as appropriate */ if (free && req->buf != &dev->rbuf) clean_req (ep, req); req->complete = epio_complete; + spin_unlock_irqrestore(&dev->lock, flags); } static int setup_req (struct usb_ep *ep, struct usb_request *req, u16 len) @@ -998,13 +988,13 @@ ep0_read (struct file *fd, char __user * } /* control DATA stage */ - if ((state = dev->state) == STATE_SETUP) { + if ((state = dev->state) == STATE_DEV_SETUP) { if (dev->setup_in) { /* stall IN */ VDEBUG(dev, "ep0in stall\n"); (void) usb_ep_set_halt (dev->gadget->ep0); retval = -EL2HLT; - dev->state = STATE_CONNECTED; + dev->state = STATE_DEV_CONNECTED; } else if (len == 0) { /* ack SET_CONFIGURATION etc */ struct usb_ep *ep = dev->gadget->ep0; @@ -1012,7 +1002,7 @@ ep0_read (struct file *fd, char __user * if ((retval = setup_req (ep, req, 0)) == 0) retval = usb_ep_queue (ep, req, GFP_ATOMIC); - dev->state = STATE_CONNECTED; + dev->state = STATE_DEV_CONNECTED; /* assume that was SET_CONFIGURATION */ if (dev->current_config) { @@ -1040,6 +1030,13 @@ #endif spin_lock_irq (&dev->lock); if (retval) goto done; + + if (dev->state != STATE_DEV_SETUP) { + retval = -ECANCELED; + goto done; + } + dev->state = STATE_DEV_CONNECTED; + if (dev->setup_out_error) retval = -EIO; else { @@ -1066,39 +1063,36 @@ scan: /* return queued events right away */ if (dev->ev_next != 0) { unsigned i, n; - int tmp = dev->ev_next; - len = min (len, tmp * sizeof (struct usb_gadgetfs_event)); n = len / sizeof (struct usb_gadgetfs_event); + if (dev->ev_next < n) + n = dev->ev_next; - /* ep0 can't deliver events when STATE_SETUP */ + /* ep0 i/o has special semantics during STATE_DEV_SETUP */ for (i = 0; i < n; i++) { if (dev->event [i].type == GADGETFS_SETUP) { - len = i + 1; - len *= sizeof (struct usb_gadgetfs_event); - n = 0; + dev->state = STATE_DEV_SETUP; + n = i + 1; break; } } spin_unlock_irq (&dev->lock); + len = n * sizeof (struct usb_gadgetfs_event); if (copy_to_user (buf, &dev->event, len)) retval = -EFAULT; else retval = len; if (len > 0) { - len /= sizeof (struct usb_gadgetfs_event); - /* NOTE this doesn't guard against broken drivers; * concurrent ep0 readers may lose events. */ spin_lock_irq (&dev->lock); - dev->ev_next -= len; - if (dev->ev_next != 0) - memmove (&dev->event, &dev->event [len], + if (dev->ev_next > n) { + memmove(&dev->event[0], &dev->event[n], sizeof (struct usb_gadgetfs_event) - * (tmp - len)); - if (n == 0) - dev->state = STATE_SETUP; + * (dev->ev_next - n)); + } + dev->ev_next -= n; spin_unlock_irq (&dev->lock); } return retval; @@ -1113,8 +1107,8 @@ scan: DBG (dev, "fail %s, state %d\n", __FUNCTION__, state); retval = -ESRCH; break; - case STATE_UNCONNECTED: - case STATE_CONNECTED: + case STATE_DEV_UNCONNECTED: + case STATE_DEV_CONNECTED: spin_unlock_irq (&dev->lock); DBG (dev, "%s wait\n", __FUNCTION__); @@ -1141,7 +1135,7 @@ next_event (struct dev_data *dev, enum u switch (type) { /* these events purge the queue */ case GADGETFS_DISCONNECT: - if (dev->state == STATE_SETUP) + if (dev->state == STATE_DEV_SETUP) dev->setup_abort = 1; // FALL THROUGH case GADGETFS_CONNECT: @@ -1153,7 +1147,7 @@ next_event (struct dev_data *dev, enum u for (i = 0; i != dev->ev_next; i++) { if (dev->event [i].type != type) continue; - DBG (dev, "discard old event %d\n", type); + DBG(dev, "discard old event[%d] %d\n", i, type); dev->ev_next--; if (i == dev->ev_next) break; @@ -1166,9 +1160,9 @@ next_event (struct dev_data *dev, enum u default: BUG (); } + VDEBUG(dev, "event[%d] = %d\n", dev->ev_next, type); event = &dev->event [dev->ev_next++]; BUG_ON (dev->ev_next > N_EVENT); - VDEBUG (dev, "ev %d, next %d\n", type, dev->ev_next); memset (event, 0, sizeof *event); event->type = type; return event; @@ -1188,12 +1182,13 @@ ep0_write (struct file *fd, const char _ retval = -EIDRM; /* data and/or status stage for control request */ - } else if (dev->state == STATE_SETUP) { + } else if (dev->state == STATE_DEV_SETUP) { /* IN DATA+STATUS caller makes len <= wLength */ if (dev->setup_in) { retval = setup_req (dev->gadget->ep0, dev->req, len); if (retval == 0) { + dev->state = STATE_DEV_CONNECTED; spin_unlock_irq (&dev->lock); if (copy_from_user (dev->req->buf, buf, len)) retval = -EFAULT; @@ -1219,7 +1214,7 @@ ep0_write (struct file *fd, const char _ VDEBUG(dev, "ep0out stall\n"); (void) usb_ep_set_halt (dev->gadget->ep0); retval = -EL2HLT; - dev->state = STATE_CONNECTED; + dev->state = STATE_DEV_CONNECTED; } else { DBG(dev, "bogus ep0out stall!\n"); } @@ -1261,7 +1256,9 @@ dev_release (struct inode *inode, struct put_dev (dev); /* other endpoints were all decoupled from this device */ + spin_lock_irq(&dev->lock); dev->state = STATE_DEV_DISABLED; + spin_unlock_irq(&dev->lock); return 0; } @@ -1282,7 +1279,7 @@ ep0_poll (struct file *fd, poll_table *w goto out; } - if (dev->state == STATE_SETUP) { + if (dev->state == STATE_DEV_SETUP) { if (dev->setup_in || dev->setup_can_stall) mask = POLLOUT; } else { @@ -1392,52 +1389,29 @@ gadgetfs_setup (struct usb_gadget *gadge spin_lock (&dev->lock); dev->setup_abort = 0; - if (dev->state == STATE_UNCONNECTED) { - struct usb_ep *ep; - struct ep_data *data; - - dev->state = STATE_CONNECTED; - dev->dev->bMaxPacketSize0 = gadget->ep0->maxpacket; - + if (dev->state == STATE_DEV_UNCONNECTED) { #ifdef CONFIG_USB_GADGET_DUALSPEED if (gadget->speed == USB_SPEED_HIGH && dev->hs_config == 0) { + spin_unlock(&dev->lock); ERROR (dev, "no high speed config??\n"); return -EINVAL; } #endif /* CONFIG_USB_GADGET_DUALSPEED */ + dev->state = STATE_DEV_CONNECTED; + dev->dev->bMaxPacketSize0 = gadget->ep0->maxpacket; + INFO (dev, "connected\n"); event = next_event (dev, GADGETFS_CONNECT); event->u.speed = gadget->speed; ep0_readable (dev); - list_for_each_entry (ep, &gadget->ep_list, ep_list) { - data = ep->driver_data; - /* ... down_trylock (&data->lock) ... */ - if (data->state != STATE_EP_DEFER_ENABLE) - continue; -#ifdef CONFIG_USB_GADGET_DUALSPEED - if (gadget->speed == USB_SPEED_HIGH) - value = usb_ep_enable (ep, &data->hs_desc); - else -#endif /* CONFIG_USB_GADGET_DUALSPEED */ - value = usb_ep_enable (ep, &data->desc); - if (value) { - ERROR (dev, "deferred %s enable --> %d\n", - data->name, value); - continue; - } - data->state = STATE_EP_ENABLED; - wake_up (&data->wait); - DBG (dev, "woke up %s waiters\n", data->name); - } - /* host may have given up waiting for response. we can miss control * requests handled lower down (device/endpoint status and features); * then ep0_{read,write} will report the wrong status. controller * driver will have aborted pending i/o. */ - } else if (dev->state == STATE_SETUP) + } else if (dev->state == STATE_DEV_SETUP) dev->setup_abort = 1; req->buf = dev->rbuf; @@ -1583,7 +1557,7 @@ delegate: } /* proceed with data transfer and status phases? */ - if (value >= 0 && dev->state != STATE_SETUP) { + if (value >= 0 && dev->state != STATE_DEV_SETUP) { req->length = value; req->zero = value < w_length; value = usb_ep_queue (gadget->ep0, req, GFP_ATOMIC); @@ -1747,7 +1721,9 @@ gadgetfs_bind (struct usb_gadget *gadget goto enomem; INFO (dev, "bound to %s driver\n", gadget->name); - dev->state = STATE_UNCONNECTED; + spin_lock_irq(&dev->lock); + dev->state = STATE_DEV_UNCONNECTED; + spin_unlock_irq(&dev->lock); get_dev (dev); return 0; @@ -1762,11 +1738,9 @@ gadgetfs_disconnect (struct usb_gadget * struct dev_data *dev = get_gadget_data (gadget); spin_lock (&dev->lock); - if (dev->state == STATE_UNCONNECTED) { - DBG (dev, "already unconnected\n"); + if (dev->state == STATE_DEV_UNCONNECTED) goto exit; - } - dev->state = STATE_UNCONNECTED; + dev->state = STATE_DEV_UNCONNECTED; INFO (dev, "disconnected\n"); next_event (dev, GADGETFS_DISCONNECT); @@ -1783,9 +1757,9 @@ gadgetfs_suspend (struct usb_gadget *gad INFO (dev, "suspended from state %d\n", dev->state); spin_lock (&dev->lock); switch (dev->state) { - case STATE_SETUP: // VERY odd... host died?? - case STATE_CONNECTED: - case STATE_UNCONNECTED: + case STATE_DEV_SETUP: // VERY odd... host died?? + case STATE_DEV_CONNECTED: + case STATE_DEV_UNCONNECTED: next_event (dev, GADGETFS_SUSPEND); ep0_readable (dev); /* FALLTHROUGH */ @@ -1808,7 +1782,7 @@ #endif .disconnect = gadgetfs_disconnect, .suspend = gadgetfs_suspend, - .driver = { + .driver = { .name = (char *) shortname, }, }; @@ -1829,7 +1803,7 @@ static struct usb_gadget_driver probe_dr .unbind = gadgetfs_nop, .setup = (void *)gadgetfs_nop, .disconnect = gadgetfs_nop, - .driver = { + .driver = { .name = "nop", }, }; @@ -1849,19 +1823,16 @@ static struct usb_gadget_driver probe_dr * . full/low speed config ... all wTotalLength bytes (with interface, * class, altsetting, endpoint, and other descriptors) * . high speed config ... all descriptors, for high speed operation; - * this one's optional except for high-speed hardware + * this one's optional except for high-speed hardware * . device descriptor * - * Endpoints are not yet enabled. Drivers may want to immediately - * initialize them, using the /dev/gadget/ep* files that are available - * as soon as the kernel sees the configuration, or they can wait - * until device configuration and interface altsetting changes create + * Endpoints are not yet enabled. Drivers must wait until device + * configuration and interface altsetting changes create * the need to configure (or unconfigure) them. * * After initialization, the device stays active for as long as that - * $CHIP file is open. Events may then be read from that descriptor, - * such as configuration notifications. More complex drivers will handle - * some control requests in user space. + * $CHIP file is open. Events must then be read from that descriptor, + * such as configuration notifications. */ static int is_valid_config (struct usb_config_descriptor *config) @@ -1884,9 +1855,6 @@ dev_config (struct file *fd, const char u32 tag; char *kbuf; - if (dev->state != STATE_OPENED) - return -EEXIST; - if (len < (USB_DT_CONFIG_SIZE + USB_DT_DEVICE_SIZE + 4)) return -EINVAL; @@ -1978,13 +1946,15 @@ dev_open (struct inode *inode, struct fi struct dev_data *dev = inode->i_private; int value = -EBUSY; + spin_lock_irq(&dev->lock); if (dev->state == STATE_DEV_DISABLED) { dev->ev_next = 0; - dev->state = STATE_OPENED; + dev->state = STATE_DEV_OPENED; fd->private_data = dev; get_dev (dev); value = 0; } + spin_unlock_irq(&dev->lock); return value; } diff --git a/drivers/usb/gadget/lh7a40x_udc.h b/drivers/usb/gadget/lh7a40x_udc.h index e3bb785..b3fe197 100644 --- a/drivers/usb/gadget/lh7a40x_udc.h +++ b/drivers/usb/gadget/lh7a40x_udc.h @@ -49,7 +49,7 @@ #include #include #include -#include +#include #include /* diff --git a/drivers/usb/gadget/net2280.c b/drivers/usb/gadget/net2280.c index 569eb8c..49d7377 100644 --- a/drivers/usb/gadget/net2280.c +++ b/drivers/usb/gadget/net2280.c @@ -53,7 +53,6 @@ #include #include #include #include -#include #include #include #include @@ -63,7 +62,7 @@ #include #include #include #include -#include +#include #include #include diff --git a/drivers/usb/gadget/omap_udc.c b/drivers/usb/gadget/omap_udc.c index cdcfd42..8f9a2b6 100644 --- a/drivers/usb/gadget/omap_udc.c +++ b/drivers/usb/gadget/omap_udc.c @@ -28,7 +28,6 @@ #include #include #include #include -#include #include #include #include @@ -38,7 +37,7 @@ #include #include #include #include -#include +#include #include #include #include diff --git a/drivers/usb/gadget/pxa2xx_udc.c b/drivers/usb/gadget/pxa2xx_udc.c index b78de96..27904a5 100644 --- a/drivers/usb/gadget/pxa2xx_udc.c +++ b/drivers/usb/gadget/pxa2xx_udc.c @@ -33,7 +33,6 @@ #include #include #include #include -#include #include #include #include @@ -56,7 +55,7 @@ #ifdef CONFIG_ARCH_PXA #include #endif -#include +#include #include #include @@ -2614,7 +2613,7 @@ #endif #endif if (vbus_irq) { retval = request_irq(vbus_irq, udc_vbus_irq, - SA_INTERRUPT | SA_SAMPLE_RANDOM, + IRQF_DISABLED | IRQF_SAMPLE_RANDOM, driver_name, dev); if (retval != 0) { printk(KERN_ERR "%s: can't get irq %i, err %d\n", diff --git a/drivers/usb/gadget/rndis.c b/drivers/usb/gadget/rndis.c index 408c338..6ec8cf1 100644 --- a/drivers/usb/gadget/rndis.c +++ b/drivers/usb/gadget/rndis.c @@ -1419,7 +1419,6 @@ #ifdef CONFIG_USB_GADGET_DEBUG_FILES return -EIO; } - rndis_connect_state [i]->nlink = 1; rndis_connect_state [i]->write_proc = rndis_proc_write; rndis_connect_state [i]->read_proc = rndis_proc_read; rndis_connect_state [i]->data = (void *) diff --git a/drivers/usb/gadget/serial.c b/drivers/usb/gadget/serial.c index f8a3ec6..e6c19aa 100644 --- a/drivers/usb/gadget/serial.c +++ b/drivers/usb/gadget/serial.c @@ -21,7 +21,6 @@ #include #include #include #include -#include #include #include #include @@ -43,7 +42,7 @@ #include #include #include -#include +#include #include #include diff --git a/drivers/usb/gadget/usbstring.c b/drivers/usb/gadget/usbstring.c index b173576..3459ea6 100644 --- a/drivers/usb/gadget/usbstring.c +++ b/drivers/usb/gadget/usbstring.c @@ -14,7 +14,7 @@ #include #include #include -#include +#include #include #include diff --git a/drivers/usb/gadget/zero.c b/drivers/usb/gadget/zero.c index 40710ea..8c85e33 100644 --- a/drivers/usb/gadget/zero.c +++ b/drivers/usb/gadget/zero.c @@ -66,7 +66,6 @@ #include #include #include #include -#include #include #include #include @@ -84,7 +83,7 @@ #include #include #include -#include +#include #include #include "gadget_chips.h" diff --git a/drivers/usb/host/Kconfig b/drivers/usb/host/Kconfig index cc60759..6271187 100644 --- a/drivers/usb/host/Kconfig +++ b/drivers/usb/host/Kconfig @@ -67,6 +67,11 @@ config USB_EHCI_TT_NEWSCHED If unsure, say N. +config USB_EHCI_BIG_ENDIAN_MMIO + bool + depends on USB_EHCI_HCD + default n + config USB_ISP116X_HCD tristate "ISP116X HCD support" depends on USB @@ -101,21 +106,48 @@ config USB_OHCI_HCD_PPC_SOC bool "OHCI support for on-chip PPC USB controller" depends on USB_OHCI_HCD && (STB03xxx || PPC_MPC52xx) default y - select USB_OHCI_BIG_ENDIAN + select USB_OHCI_BIG_ENDIAN_DESC + select USB_OHCI_BIG_ENDIAN_MMIO ---help--- Enables support for the USB controller on the MPC52xx or STB03xxx processor chip. If unsure, say Y. +config USB_OHCI_HCD_PPC_OF + bool "OHCI support for PPC USB controller on OF platform bus" + depends on USB_OHCI_HCD && PPC_OF + default y + ---help--- + Enables support for the USB controller PowerPC present on the + OpenFirmware platform bus. + +config USB_OHCI_HCD_PPC_OF_BE + bool "Support big endian HC" + depends on USB_OHCI_HCD_PPC_OF + default y + select USB_OHCI_BIG_ENDIAN_DESC + select USB_OHCI_BIG_ENDIAN_MMIO + +config USB_OHCI_HCD_PPC_OF_LE + bool "Support little endian HC" + depends on USB_OHCI_HCD_PPC_OF + default n + select USB_OHCI_LITTLE_ENDIAN + config USB_OHCI_HCD_PCI bool "OHCI support for PCI-bus USB controllers" - depends on USB_OHCI_HCD && PCI && (STB03xxx || PPC_MPC52xx) + depends on USB_OHCI_HCD && PCI && (STB03xxx || PPC_MPC52xx || USB_OHCI_HCD_PPC_OF) default y select USB_OHCI_LITTLE_ENDIAN ---help--- Enables support for PCI-bus plug-in USB controller cards. If unsure, say Y. -config USB_OHCI_BIG_ENDIAN +config USB_OHCI_BIG_ENDIAN_DESC + bool + depends on USB_OHCI_HCD + default n + +config USB_OHCI_BIG_ENDIAN_MMIO bool depends on USB_OHCI_HCD default n diff --git a/drivers/usb/host/ehci-dbg.c b/drivers/usb/host/ehci-dbg.c index 56349d2..246afea 100644 --- a/drivers/usb/host/ehci-dbg.c +++ b/drivers/usb/host/ehci-dbg.c @@ -43,7 +43,7 @@ #ifdef DEBUG */ static void dbg_hcs_params (struct ehci_hcd *ehci, char *label) { - u32 params = readl (&ehci->caps->hcs_params); + u32 params = ehci_readl(ehci, &ehci->caps->hcs_params); ehci_dbg (ehci, "%s hcs_params 0x%x dbg=%d%s cc=%d pcc=%d%s%s ports=%d\n", @@ -87,7 +87,7 @@ #ifdef DEBUG * */ static void dbg_hcc_params (struct ehci_hcd *ehci, char *label) { - u32 params = readl (&ehci->caps->hcc_params); + u32 params = ehci_readl(ehci, &ehci->caps->hcc_params); if (HCC_ISOC_CACHE (params)) { ehci_dbg (ehci, @@ -653,7 +653,7 @@ show_registers (struct class_device *cla } /* Capability Registers */ - i = HC_VERSION(readl (&ehci->caps->hc_capbase)); + i = HC_VERSION(ehci_readl(ehci, &ehci->caps->hc_capbase)); temp = scnprintf (next, size, "bus %s, device %s (driver " DRIVER_VERSION ")\n" "%s\n" @@ -673,7 +673,7 @@ #ifdef CONFIG_PCI unsigned count = 256/4; pdev = to_pci_dev(ehci_to_hcd(ehci)->self.controller); - offset = HCC_EXT_CAPS (readl (&ehci->caps->hcc_params)); + offset = HCC_EXT_CAPS (ehci_readl(ehci, &ehci->caps->hcc_params)); while (offset && count--) { pci_read_config_dword (pdev, offset, &cap); switch (cap & 0xff) { @@ -704,50 +704,50 @@ #ifdef CONFIG_PCI #endif // FIXME interpret both types of params - i = readl (&ehci->caps->hcs_params); + i = ehci_readl(ehci, &ehci->caps->hcs_params); temp = scnprintf (next, size, "structural params 0x%08x\n", i); size -= temp; next += temp; - i = readl (&ehci->caps->hcc_params); + i = ehci_readl(ehci, &ehci->caps->hcc_params); temp = scnprintf (next, size, "capability params 0x%08x\n", i); size -= temp; next += temp; /* Operational Registers */ temp = dbg_status_buf (scratch, sizeof scratch, label, - readl (&ehci->regs->status)); + ehci_readl(ehci, &ehci->regs->status)); temp = scnprintf (next, size, fmt, temp, scratch); size -= temp; next += temp; temp = dbg_command_buf (scratch, sizeof scratch, label, - readl (&ehci->regs->command)); + ehci_readl(ehci, &ehci->regs->command)); temp = scnprintf (next, size, fmt, temp, scratch); size -= temp; next += temp; temp = dbg_intr_buf (scratch, sizeof scratch, label, - readl (&ehci->regs->intr_enable)); + ehci_readl(ehci, &ehci->regs->intr_enable)); temp = scnprintf (next, size, fmt, temp, scratch); size -= temp; next += temp; temp = scnprintf (next, size, "uframe %04x\n", - readl (&ehci->regs->frame_index)); + ehci_readl(ehci, &ehci->regs->frame_index)); size -= temp; next += temp; for (i = 1; i <= HCS_N_PORTS (ehci->hcs_params); i++) { temp = dbg_port_buf (scratch, sizeof scratch, label, i, - readl (&ehci->regs->port_status [i - 1])); + ehci_readl(ehci, &ehci->regs->port_status [i - 1])); temp = scnprintf (next, size, fmt, temp, scratch); size -= temp; next += temp; if (i == HCS_DEBUG_PORT(ehci->hcs_params) && ehci->debug) { temp = scnprintf (next, size, " debug control %08x\n", - readl (&ehci->debug->control)); + ehci_readl(ehci, &ehci->debug->control)); size -= temp; next += temp; } diff --git a/drivers/usb/host/ehci-fsl.c b/drivers/usb/host/ehci-fsl.c index 1a915e9..a524805 100644 --- a/drivers/usb/host/ehci-fsl.c +++ b/drivers/usb/host/ehci-fsl.c @@ -177,7 +177,7 @@ static void mpc83xx_setup_phy(struct ehc case FSL_USB2_PHY_NONE: break; } - writel(portsc, &ehci->regs->port_status[port_offset]); + ehci_writel(ehci, portsc, &ehci->regs->port_status[port_offset]); } static void mpc83xx_usb_setup(struct usb_hcd *hcd) @@ -214,7 +214,7 @@ static void mpc83xx_usb_setup(struct usb } /* put controller in host mode. */ - writel(0x00000003, non_ehci + FSL_SOC_USB_USBMODE); + ehci_writel(ehci, 0x00000003, non_ehci + FSL_SOC_USB_USBMODE); out_be32(non_ehci + FSL_SOC_USB_PRICTRL, 0x0000000c); out_be32(non_ehci + FSL_SOC_USB_AGECNTTHRSH, 0x00000040); out_be32(non_ehci + FSL_SOC_USB_SICTRL, 0x00000001); @@ -238,12 +238,12 @@ static int ehci_fsl_setup(struct usb_hcd /* EHCI registers start at offset 0x100 */ ehci->caps = hcd->regs + 0x100; ehci->regs = hcd->regs + 0x100 + - HC_LENGTH(readl(&ehci->caps->hc_capbase)); + HC_LENGTH(ehci_readl(ehci, &ehci->caps->hc_capbase)); dbg_hcs_params(ehci, "reset"); dbg_hcc_params(ehci, "reset"); /* cache this readonly data; minimize chip reads */ - ehci->hcs_params = readl(&ehci->caps->hcs_params); + ehci->hcs_params = ehci_readl(ehci, &ehci->caps->hcs_params); retval = ehci_halt(ehci); if (retval) diff --git a/drivers/usb/host/ehci-hcd.c b/drivers/usb/host/ehci-hcd.c index 025d333..185721d 100644 --- a/drivers/usb/host/ehci-hcd.c +++ b/drivers/usb/host/ehci-hcd.c @@ -157,12 +157,13 @@ #include "ehci-dbg.c" * before driver shutdown. But it also seems to be caused by bugs in cardbus * bridge shutdown: shutting down the bridge before the devices using it. */ -static int handshake (void __iomem *ptr, u32 mask, u32 done, int usec) +static int handshake (struct ehci_hcd *ehci, void __iomem *ptr, + u32 mask, u32 done, int usec) { u32 result; do { - result = readl (ptr); + result = ehci_readl(ehci, ptr); if (result == ~(u32)0) /* card removed */ return -ENODEV; result &= mask; @@ -177,18 +178,19 @@ static int handshake (void __iomem *ptr, /* force HC to halt state from unknown (EHCI spec section 2.3) */ static int ehci_halt (struct ehci_hcd *ehci) { - u32 temp = readl (&ehci->regs->status); + u32 temp = ehci_readl(ehci, &ehci->regs->status); /* disable any irqs left enabled by previous code */ - writel (0, &ehci->regs->intr_enable); + ehci_writel(ehci, 0, &ehci->regs->intr_enable); if ((temp & STS_HALT) != 0) return 0; - temp = readl (&ehci->regs->command); + temp = ehci_readl(ehci, &ehci->regs->command); temp &= ~CMD_RUN; - writel (temp, &ehci->regs->command); - return handshake (&ehci->regs->status, STS_HALT, STS_HALT, 16 * 125); + ehci_writel(ehci, temp, &ehci->regs->command); + return handshake (ehci, &ehci->regs->status, + STS_HALT, STS_HALT, 16 * 125); } /* put TDI/ARC silicon into EHCI mode */ @@ -198,23 +200,24 @@ static void tdi_reset (struct ehci_hcd * u32 tmp; reg_ptr = (u32 __iomem *)(((u8 __iomem *)ehci->regs) + 0x68); - tmp = readl (reg_ptr); + tmp = ehci_readl(ehci, reg_ptr); tmp |= 0x3; - writel (tmp, reg_ptr); + ehci_writel(ehci, tmp, reg_ptr); } /* reset a non-running (STS_HALT == 1) controller */ static int ehci_reset (struct ehci_hcd *ehci) { int retval; - u32 command = readl (&ehci->regs->command); + u32 command = ehci_readl(ehci, &ehci->regs->command); command |= CMD_RESET; dbg_cmd (ehci, "reset", command); - writel (command, &ehci->regs->command); + ehci_writel(ehci, command, &ehci->regs->command); ehci_to_hcd(ehci)->state = HC_STATE_HALT; ehci->next_statechange = jiffies; - retval = handshake (&ehci->regs->command, CMD_RESET, 0, 250 * 1000); + retval = handshake (ehci, &ehci->regs->command, + CMD_RESET, 0, 250 * 1000); if (retval) return retval; @@ -236,21 +239,21 @@ #ifdef DEBUG #endif /* wait for any schedule enables/disables to take effect */ - temp = readl (&ehci->regs->command) << 10; + temp = ehci_readl(ehci, &ehci->regs->command) << 10; temp &= STS_ASS | STS_PSS; - if (handshake (&ehci->regs->status, STS_ASS | STS_PSS, + if (handshake (ehci, &ehci->regs->status, STS_ASS | STS_PSS, temp, 16 * 125) != 0) { ehci_to_hcd(ehci)->state = HC_STATE_HALT; return; } /* then disable anything that's still active */ - temp = readl (&ehci->regs->command); + temp = ehci_readl(ehci, &ehci->regs->command); temp &= ~(CMD_ASE | CMD_IAAD | CMD_PSE); - writel (temp, &ehci->regs->command); + ehci_writel(ehci, temp, &ehci->regs->command); /* hardware can take 16 microframes to turn off ... */ - if (handshake (&ehci->regs->status, STS_ASS | STS_PSS, + if (handshake (ehci, &ehci->regs->status, STS_ASS | STS_PSS, 0, 16 * 125) != 0) { ehci_to_hcd(ehci)->state = HC_STATE_HALT; return; @@ -277,11 +280,11 @@ static void ehci_watchdog (unsigned long /* lost IAA irqs wedge things badly; seen with a vt8235 */ if (ehci->reclaim) { - u32 status = readl (&ehci->regs->status); + u32 status = ehci_readl(ehci, &ehci->regs->status); if (status & STS_IAA) { ehci_vdbg (ehci, "lost IAA\n"); COUNT (ehci->stats.lost_iaa); - writel (STS_IAA, &ehci->regs->status); + ehci_writel(ehci, STS_IAA, &ehci->regs->status); ehci->reclaim_ready = 1; } } @@ -309,7 +312,7 @@ ehci_shutdown (struct usb_hcd *hcd) (void) ehci_halt (ehci); /* make BIOS/etc use companion controller during reboot */ - writel (0, &ehci->regs->configured_flag); + ehci_writel(ehci, 0, &ehci->regs->configured_flag); } static void ehci_port_power (struct ehci_hcd *ehci, int is_on) @@ -379,12 +382,13 @@ static void ehci_stop (struct usb_hcd *h ehci_quiesce (ehci); ehci_reset (ehci); - writel (0, &ehci->regs->intr_enable); + ehci_writel(ehci, 0, &ehci->regs->intr_enable); spin_unlock_irq(&ehci->lock); /* let companion controllers work when we aren't */ - writel (0, &ehci->regs->configured_flag); + ehci_writel(ehci, 0, &ehci->regs->configured_flag); + remove_companion_file(ehci); remove_debug_files (ehci); /* root hub is shut down separately (first, when possible) */ @@ -402,7 +406,8 @@ #ifdef EHCI_STATS ehci->stats.complete, ehci->stats.unlink); #endif - dbg_status (ehci, "ehci_stop completed", readl (&ehci->regs->status)); + dbg_status (ehci, "ehci_stop completed", + ehci_readl(ehci, &ehci->regs->status)); } /* one-time init, only for memory state */ @@ -428,7 +433,7 @@ static int ehci_init(struct usb_hcd *hcd return retval; /* controllers may cache some of the periodic schedule ... */ - hcc_params = readl(&ehci->caps->hcc_params); + hcc_params = ehci_readl(ehci, &ehci->caps->hcc_params); if (HCC_ISOC_CACHE(hcc_params)) // full frame cache ehci->i_thresh = 8; else // N microframes cached @@ -496,13 +501,16 @@ static int ehci_run (struct usb_hcd *hcd u32 temp; u32 hcc_params; + hcd->uses_new_polling = 1; + hcd->poll_rh = 0; + /* EHCI spec section 4.1 */ if ((retval = ehci_reset(ehci)) != 0) { ehci_mem_cleanup(ehci); return retval; } - writel(ehci->periodic_dma, &ehci->regs->frame_list); - writel((u32)ehci->async->qh_dma, &ehci->regs->async_next); + ehci_writel(ehci, ehci->periodic_dma, &ehci->regs->frame_list); + ehci_writel(ehci, (u32)ehci->async->qh_dma, &ehci->regs->async_next); /* * hcc_params controls whether ehci->regs->segment must (!!!) @@ -516,9 +524,9 @@ static int ehci_run (struct usb_hcd *hcd * Scsi_Host.highmem_io, and so forth. It's readonly to all * host side drivers though. */ - hcc_params = readl(&ehci->caps->hcc_params); + hcc_params = ehci_readl(ehci, &ehci->caps->hcc_params); if (HCC_64BIT_ADDR(hcc_params)) { - writel(0, &ehci->regs->segment); + ehci_writel(ehci, 0, &ehci->regs->segment); #if 0 // this is deeply broken on almost all architectures if (!dma_set_mask(hcd->self.controller, DMA_64BIT_MASK)) @@ -531,7 +539,7 @@ #endif // root hub will detect new devices (why?); NEC doesn't ehci->command &= ~(CMD_LRESET|CMD_IAAD|CMD_PSE|CMD_ASE|CMD_RESET); ehci->command |= CMD_RUN; - writel (ehci->command, &ehci->regs->command); + ehci_writel(ehci, ehci->command, &ehci->regs->command); dbg_cmd (ehci, "init", ehci->command); /* @@ -541,23 +549,25 @@ #endif * and there's no companion controller unless maybe for USB OTG.) */ hcd->state = HC_STATE_RUNNING; - writel (FLAG_CF, &ehci->regs->configured_flag); - readl (&ehci->regs->command); /* unblock posted writes */ + ehci_writel(ehci, FLAG_CF, &ehci->regs->configured_flag); + ehci_readl(ehci, &ehci->regs->command); /* unblock posted writes */ - temp = HC_VERSION(readl (&ehci->caps->hc_capbase)); + temp = HC_VERSION(ehci_readl(ehci, &ehci->caps->hc_capbase)); ehci_info (ehci, "USB %x.%x started, EHCI %x.%02x, driver %s%s\n", ((ehci->sbrn & 0xf0)>>4), (ehci->sbrn & 0x0f), temp >> 8, temp & 0xff, DRIVER_VERSION, ignore_oc ? ", overcurrent ignored" : ""); - writel (INTR_MASK, &ehci->regs->intr_enable); /* Turn On Interrupts */ + ehci_writel(ehci, INTR_MASK, + &ehci->regs->intr_enable); /* Turn On Interrupts */ /* GRR this is run-once init(), being done every time the HC starts. * So long as they're part of class devices, we can't do it init() * since the class device isn't created that early. */ create_debug_files(ehci); + create_companion_file(ehci); return 0; } @@ -567,12 +577,12 @@ #endif static irqreturn_t ehci_irq (struct usb_hcd *hcd) { struct ehci_hcd *ehci = hcd_to_ehci (hcd); - u32 status; + u32 status, pcd_status = 0; int bh; spin_lock (&ehci->lock); - status = readl (&ehci->regs->status); + status = ehci_readl(ehci, &ehci->regs->status); /* e.g. cardbus physical eject */ if (status == ~(u32) 0) { @@ -587,8 +597,8 @@ static irqreturn_t ehci_irq (struct usb_ } /* clear (just) interrupts */ - writel (status, &ehci->regs->status); - readl (&ehci->regs->command); /* unblock posted write */ + ehci_writel(ehci, status, &ehci->regs->status); + ehci_readl(ehci, &ehci->regs->command); /* unblock posted write */ bh = 0; #ifdef EHCI_VERBOSE_DEBUG @@ -617,13 +627,15 @@ #endif /* remote wakeup [4.3.1] */ if (status & STS_PCD) { unsigned i = HCS_N_PORTS (ehci->hcs_params); + pcd_status = status; /* resume root hub? */ - if (!(readl(&ehci->regs->command) & CMD_RUN)) + if (!(ehci_readl(ehci, &ehci->regs->command) & CMD_RUN)) usb_hcd_resume_root_hub(hcd); while (i--) { - int pstatus = readl (&ehci->regs->port_status [i]); + int pstatus = ehci_readl(ehci, + &ehci->regs->port_status [i]); if (pstatus & PORT_OWNER) continue; @@ -643,14 +655,15 @@ #endif /* PCI errors [4.15.2.4] */ if (unlikely ((status & STS_FATAL) != 0)) { /* bogus "fatal" IRQs appear on some chips... why? */ - status = readl (&ehci->regs->status); - dbg_cmd (ehci, "fatal", readl (&ehci->regs->command)); + status = ehci_readl(ehci, &ehci->regs->status); + dbg_cmd (ehci, "fatal", ehci_readl(ehci, + &ehci->regs->command)); dbg_status (ehci, "fatal", status); if (status & STS_HALT) { ehci_err (ehci, "fatal error\n"); dead: ehci_reset (ehci); - writel (0, &ehci->regs->configured_flag); + ehci_writel(ehci, 0, &ehci->regs->configured_flag); /* generic layer kills/unlinks all urbs, then * uses ehci_stop to clean up the rest */ @@ -661,6 +674,8 @@ dead: if (bh) ehci_work (ehci); spin_unlock (&ehci->lock); + if (pcd_status & STS_PCD) + usb_hcd_poll_rh_status(hcd); return IRQ_HANDLED; } @@ -873,7 +888,8 @@ done: static int ehci_get_frame (struct usb_hcd *hcd) { struct ehci_hcd *ehci = hcd_to_ehci (hcd); - return (readl (&ehci->regs->frame_index) >> 3) % ehci->periodic_size; + return (ehci_readl(ehci, &ehci->regs->frame_index) >> 3) % + ehci->periodic_size; } /*-------------------------------------------------------------------------*/ @@ -899,7 +915,13 @@ #include "ehci-au1xxx.c" #define PLATFORM_DRIVER ehci_hcd_au1xxx_driver #endif -#if !defined(PCI_DRIVER) && !defined(PLATFORM_DRIVER) +#ifdef CONFIG_PPC_PS3 +#include "ehci-ps3.c" +#define PS3_SYSTEM_BUS_DRIVER ps3_ehci_sb_driver +#endif + +#if !defined(PCI_DRIVER) && !defined(PLATFORM_DRIVER) && \ + !defined(PS3_SYSTEM_BUS_DRIVER) #error "missing bus glue for ehci-hcd" #endif @@ -924,6 +946,20 @@ #ifdef PCI_DRIVER #ifdef PLATFORM_DRIVER platform_driver_unregister(&PLATFORM_DRIVER); #endif + return retval; + } +#endif + +#ifdef PS3_SYSTEM_BUS_DRIVER + retval = ps3_system_bus_driver_register(&PS3_SYSTEM_BUS_DRIVER); + if (retval < 0) { +#ifdef PLATFORM_DRIVER + platform_driver_unregister(&PLATFORM_DRIVER); +#endif +#ifdef PCI_DRIVER + pci_unregister_driver(&PCI_DRIVER); +#endif + return retval; } #endif @@ -939,6 +975,9 @@ #endif #ifdef PCI_DRIVER pci_unregister_driver(&PCI_DRIVER); #endif +#ifdef PS3_SYSTEM_BUS_DRIVER + ps3_system_bus_driver_unregister(&PS3_SYSTEM_BUS_DRIVER); +#endif } module_exit(ehci_hcd_cleanup); diff --git a/drivers/usb/host/ehci-hub.c b/drivers/usb/host/ehci-hub.c index bfe5f30..0d83c6d 100644 --- a/drivers/usb/host/ehci-hub.c +++ b/drivers/usb/host/ehci-hub.c @@ -47,7 +47,7 @@ static int ehci_bus_suspend (struct usb_ ehci_quiesce (ehci); hcd->state = HC_STATE_QUIESCING; } - ehci->command = readl (&ehci->regs->command); + ehci->command = ehci_readl(ehci, &ehci->regs->command); if (ehci->reclaim) ehci->reclaim_ready = 1; ehci_work(ehci); @@ -60,7 +60,7 @@ static int ehci_bus_suspend (struct usb_ ehci->bus_suspended = 0; while (port--) { u32 __iomem *reg = &ehci->regs->port_status [port]; - u32 t1 = readl (reg) & ~PORT_RWC_BITS; + u32 t1 = ehci_readl(ehci, reg) & ~PORT_RWC_BITS; u32 t2 = t1; /* keep track of which ports we suspend */ @@ -79,7 +79,7 @@ static int ehci_bus_suspend (struct usb_ if (t1 != t2) { ehci_vdbg (ehci, "port %d, %08x -> %08x\n", port + 1, t1, t2); - writel (t2, reg); + ehci_writel(ehci, t2, reg); } } @@ -92,8 +92,8 @@ static int ehci_bus_suspend (struct usb_ mask = INTR_MASK; if (!device_may_wakeup(&hcd->self.root_hub->dev)) mask &= ~STS_PCD; - writel(mask, &ehci->regs->intr_enable); - readl(&ehci->regs->intr_enable); + ehci_writel(ehci, mask, &ehci->regs->intr_enable); + ehci_readl(ehci, &ehci->regs->intr_enable); ehci->next_statechange = jiffies + msecs_to_jiffies(10); spin_unlock_irq (&ehci->lock); @@ -118,26 +118,26 @@ static int ehci_bus_resume (struct usb_h * the last user of the controller, not reset/pm hardware keeping * state we gave to it. */ - temp = readl(&ehci->regs->intr_enable); + temp = ehci_readl(ehci, &ehci->regs->intr_enable); ehci_dbg(ehci, "resume root hub%s\n", temp ? "" : " after power loss"); /* at least some APM implementations will try to deliver * IRQs right away, so delay them until we're ready. */ - writel(0, &ehci->regs->intr_enable); + ehci_writel(ehci, 0, &ehci->regs->intr_enable); /* re-init operational registers */ - writel(0, &ehci->regs->segment); - writel(ehci->periodic_dma, &ehci->regs->frame_list); - writel((u32) ehci->async->qh_dma, &ehci->regs->async_next); + ehci_writel(ehci, 0, &ehci->regs->segment); + ehci_writel(ehci, ehci->periodic_dma, &ehci->regs->frame_list); + ehci_writel(ehci, (u32) ehci->async->qh_dma, &ehci->regs->async_next); /* restore CMD_RUN, framelist size, and irq threshold */ - writel (ehci->command, &ehci->regs->command); + ehci_writel(ehci, ehci->command, &ehci->regs->command); /* manually resume the ports we suspended during bus_suspend() */ i = HCS_N_PORTS (ehci->hcs_params); while (i--) { - temp = readl (&ehci->regs->port_status [i]); + temp = ehci_readl(ehci, &ehci->regs->port_status [i]); temp &= ~(PORT_RWC_BITS | PORT_WKOC_E | PORT_WKDISC_E | PORT_WKCONN_E); if (test_bit(i, &ehci->bus_suspended) && @@ -145,20 +145,20 @@ static int ehci_bus_resume (struct usb_h ehci->reset_done [i] = jiffies + msecs_to_jiffies (20); temp |= PORT_RESUME; } - writel (temp, &ehci->regs->port_status [i]); + ehci_writel(ehci, temp, &ehci->regs->port_status [i]); } i = HCS_N_PORTS (ehci->hcs_params); mdelay (20); while (i--) { - temp = readl (&ehci->regs->port_status [i]); + temp = ehci_readl(ehci, &ehci->regs->port_status [i]); if (test_bit(i, &ehci->bus_suspended) && (temp & PORT_SUSPEND)) { temp &= ~(PORT_RWC_BITS | PORT_RESUME); - writel (temp, &ehci->regs->port_status [i]); + ehci_writel(ehci, temp, &ehci->regs->port_status [i]); ehci_vdbg (ehci, "resumed port %d\n", i + 1); } } - (void) readl (&ehci->regs->command); + (void) ehci_readl(ehci, &ehci->regs->command); /* maybe re-activate the schedule(s) */ temp = 0; @@ -168,14 +168,14 @@ static int ehci_bus_resume (struct usb_h temp |= CMD_PSE; if (temp) { ehci->command |= temp; - writel (ehci->command, &ehci->regs->command); + ehci_writel(ehci, ehci->command, &ehci->regs->command); } ehci->next_statechange = jiffies + msecs_to_jiffies(5); hcd->state = HC_STATE_RUNNING; /* Now we can safely re-enable irqs */ - writel(INTR_MASK, &ehci->regs->intr_enable); + ehci_writel(ehci, INTR_MASK, &ehci->regs->intr_enable); spin_unlock_irq (&ehci->lock); return 0; @@ -190,9 +190,107 @@ #endif /* CONFIG_PM */ /*-------------------------------------------------------------------------*/ +/* Display the ports dedicated to the companion controller */ +static ssize_t show_companion(struct class_device *class_dev, char *buf) +{ + struct ehci_hcd *ehci; + int nports, index, n; + int count = PAGE_SIZE; + char *ptr = buf; + + ehci = hcd_to_ehci(bus_to_hcd(class_get_devdata(class_dev))); + nports = HCS_N_PORTS(ehci->hcs_params); + + for (index = 0; index < nports; ++index) { + if (test_bit(index, &ehci->companion_ports)) { + n = scnprintf(ptr, count, "%d\n", index + 1); + ptr += n; + count -= n; + } + } + return ptr - buf; +} + +/* + * Dedicate or undedicate a port to the companion controller. + * Syntax is "[-]portnum", where a leading '-' sign means + * return control of the port to the EHCI controller. + */ +static ssize_t store_companion(struct class_device *class_dev, + const char *buf, size_t count) +{ + struct ehci_hcd *ehci; + int portnum, new_owner, try; + u32 __iomem *status_reg; + u32 port_status; + + ehci = hcd_to_ehci(bus_to_hcd(class_get_devdata(class_dev))); + new_owner = PORT_OWNER; /* Owned by companion */ + if (sscanf(buf, "%d", &portnum) != 1) + return -EINVAL; + if (portnum < 0) { + portnum = - portnum; + new_owner = 0; /* Owned by EHCI */ + } + if (portnum <= 0 || portnum > HCS_N_PORTS(ehci->hcs_params)) + return -ENOENT; + status_reg = &ehci->regs->port_status[--portnum]; + if (new_owner) + set_bit(portnum, &ehci->companion_ports); + else + clear_bit(portnum, &ehci->companion_ports); + + /* + * The controller won't set the OWNER bit if the port is + * enabled, so this loop will sometimes require at least two + * iterations: one to disable the port and one to set OWNER. + */ + + for (try = 4; try > 0; --try) { + spin_lock_irq(&ehci->lock); + port_status = ehci_readl(ehci, status_reg); + if ((port_status & PORT_OWNER) == new_owner + || (port_status & (PORT_OWNER | PORT_CONNECT)) + == 0) + try = 0; + else { + port_status ^= PORT_OWNER; + port_status &= ~(PORT_PE | PORT_RWC_BITS); + ehci_writel(ehci, port_status, status_reg); + } + spin_unlock_irq(&ehci->lock); + if (try > 1) + msleep(5); + } + return count; +} +static CLASS_DEVICE_ATTR(companion, 0644, show_companion, store_companion); + +static inline void create_companion_file(struct ehci_hcd *ehci) +{ + int i; + + /* with integrated TT there is no companion! */ + if (!ehci_is_TDI(ehci)) + i = class_device_create_file(ehci_to_hcd(ehci)->self.class_dev, + &class_device_attr_companion); +} + +static inline void remove_companion_file(struct ehci_hcd *ehci) +{ + /* with integrated TT there is no companion! */ + if (!ehci_is_TDI(ehci)) + class_device_remove_file(ehci_to_hcd(ehci)->self.class_dev, + &class_device_attr_companion); +} + + +/*-------------------------------------------------------------------------*/ + static int check_reset_complete ( struct ehci_hcd *ehci, int index, + u32 __iomem *status_reg, int port_status ) { if (!(port_status & PORT_CONNECT)) { @@ -217,7 +315,7 @@ static int check_reset_complete ( // what happens if HCS_N_CC(params) == 0 ? port_status |= PORT_OWNER; port_status &= ~PORT_RWC_BITS; - writel (port_status, &ehci->regs->port_status [index]); + ehci_writel(ehci, port_status, status_reg); } else ehci_dbg (ehci, "port %d high speed\n", index + 1); @@ -268,22 +366,21 @@ ehci_hub_status_data (struct usb_hcd *hc /* port N changes (bit N)? */ spin_lock_irqsave (&ehci->lock, flags); for (i = 0; i < ports; i++) { - temp = readl (&ehci->regs->port_status [i]); - if (temp & PORT_OWNER) { - /* don't report this in GetPortStatus */ - if (temp & PORT_CSC) { - temp &= ~PORT_RWC_BITS; - temp |= PORT_CSC; - writel (temp, &ehci->regs->port_status [i]); - } - continue; - } + temp = ehci_readl(ehci, &ehci->regs->port_status [i]); + + /* + * Return status information even for ports with OWNER set. + * Otherwise khubd wouldn't see the disconnect event when a + * high-speed device is switched over to the companion + * controller by the user. + */ + if (!(temp & PORT_CONNECT)) ehci->reset_done [i] = 0; if ((temp & mask) != 0 || ((temp & PORT_RESUME) != 0 - && time_after (jiffies, - ehci->reset_done [i]))) { + && time_after_eq(jiffies, + ehci->reset_done[i]))) { if (i < 7) buf [0] |= 1 << (i + 1); else @@ -345,6 +442,7 @@ static int ehci_hub_control ( ) { struct ehci_hcd *ehci = hcd_to_ehci (hcd); int ports = HCS_N_PORTS (ehci->hcs_params); + u32 __iomem *status_reg = &ehci->regs->port_status[wIndex - 1]; u32 temp, status; unsigned long flags; int retval = 0; @@ -373,18 +471,22 @@ static int ehci_hub_control ( if (!wIndex || wIndex > ports) goto error; wIndex--; - temp = readl (&ehci->regs->port_status [wIndex]); - if (temp & PORT_OWNER) - break; + temp = ehci_readl(ehci, status_reg); + + /* + * Even if OWNER is set, so the port is owned by the + * companion controller, khubd needs to be able to clear + * the port-change status bits (especially + * USB_PORT_FEAT_C_CONNECTION). + */ switch (wValue) { case USB_PORT_FEAT_ENABLE: - writel (temp & ~PORT_PE, - &ehci->regs->port_status [wIndex]); + ehci_writel(ehci, temp & ~PORT_PE, status_reg); break; case USB_PORT_FEAT_C_ENABLE: - writel((temp & ~PORT_RWC_BITS) | PORT_PEC, - &ehci->regs->port_status [wIndex]); + ehci_writel(ehci, (temp & ~PORT_RWC_BITS) | PORT_PEC, + status_reg); break; case USB_PORT_FEAT_SUSPEND: if (temp & PORT_RESET) @@ -396,8 +498,8 @@ static int ehci_hub_control ( goto error; /* resume signaling for 20 msec */ temp &= ~(PORT_RWC_BITS | PORT_WAKE_BITS); - writel (temp | PORT_RESUME, - &ehci->regs->port_status [wIndex]); + ehci_writel(ehci, temp | PORT_RESUME, + status_reg); ehci->reset_done [wIndex] = jiffies + msecs_to_jiffies (20); } @@ -407,16 +509,17 @@ static int ehci_hub_control ( break; case USB_PORT_FEAT_POWER: if (HCS_PPC (ehci->hcs_params)) - writel (temp & ~(PORT_RWC_BITS | PORT_POWER), - &ehci->regs->port_status [wIndex]); + ehci_writel(ehci, + temp & ~(PORT_RWC_BITS | PORT_POWER), + status_reg); break; case USB_PORT_FEAT_C_CONNECTION: - writel((temp & ~PORT_RWC_BITS) | PORT_CSC, - &ehci->regs->port_status [wIndex]); + ehci_writel(ehci, (temp & ~PORT_RWC_BITS) | PORT_CSC, + status_reg); break; case USB_PORT_FEAT_C_OVER_CURRENT: - writel((temp & ~PORT_RWC_BITS) | PORT_OCC, - &ehci->regs->port_status [wIndex]); + ehci_writel(ehci, (temp & ~PORT_RWC_BITS) | PORT_OCC, + status_reg); break; case USB_PORT_FEAT_C_RESET: /* GetPortStatus clears reset */ @@ -424,7 +527,7 @@ static int ehci_hub_control ( default: goto error; } - readl (&ehci->regs->command); /* unblock posted write */ + ehci_readl(ehci, &ehci->regs->command); /* unblock posted write */ break; case GetHubDescriptor: ehci_hub_descriptor (ehci, (struct usb_hub_descriptor *) @@ -440,7 +543,7 @@ static int ehci_hub_control ( goto error; wIndex--; status = 0; - temp = readl (&ehci->regs->port_status [wIndex]); + temp = ehci_readl(ehci, status_reg); // wPortChange bits if (temp & PORT_CSC) @@ -451,42 +554,55 @@ static int ehci_hub_control ( status |= 1 << USB_PORT_FEAT_C_OVER_CURRENT; /* whoever resumes must GetPortStatus to complete it!! */ - if ((temp & PORT_RESUME) - && time_after (jiffies, - ehci->reset_done [wIndex])) { - status |= 1 << USB_PORT_FEAT_C_SUSPEND; - ehci->reset_done [wIndex] = 0; + if (temp & PORT_RESUME) { - /* stop resume signaling */ - temp = readl (&ehci->regs->port_status [wIndex]); - writel (temp & ~(PORT_RWC_BITS | PORT_RESUME), - &ehci->regs->port_status [wIndex]); - retval = handshake ( - &ehci->regs->port_status [wIndex], - PORT_RESUME, 0, 2000 /* 2msec */); - if (retval != 0) { - ehci_err (ehci, "port %d resume error %d\n", - wIndex + 1, retval); - goto error; + /* Remote Wakeup received? */ + if (!ehci->reset_done[wIndex]) { + /* resume signaling for 20 msec */ + ehci->reset_done[wIndex] = jiffies + + msecs_to_jiffies(20); + /* check the port again */ + mod_timer(&ehci_to_hcd(ehci)->rh_timer, + ehci->reset_done[wIndex]); + } + + /* resume completed? */ + else if (time_after_eq(jiffies, + ehci->reset_done[wIndex])) { + status |= 1 << USB_PORT_FEAT_C_SUSPEND; + ehci->reset_done[wIndex] = 0; + + /* stop resume signaling */ + temp = ehci_readl(ehci, status_reg); + ehci_writel(ehci, + temp & ~(PORT_RWC_BITS | PORT_RESUME), + status_reg); + retval = handshake(ehci, status_reg, + PORT_RESUME, 0, 2000 /* 2msec */); + if (retval != 0) { + ehci_err(ehci, + "port %d resume error %d\n", + wIndex + 1, retval); + goto error; + } + temp &= ~(PORT_SUSPEND|PORT_RESUME|(3<<10)); } - temp &= ~(PORT_SUSPEND|PORT_RESUME|(3<<10)); } /* whoever resets must GetPortStatus to complete it!! */ if ((temp & PORT_RESET) - && time_after (jiffies, - ehci->reset_done [wIndex])) { + && time_after_eq(jiffies, + ehci->reset_done[wIndex])) { status |= 1 << USB_PORT_FEAT_C_RESET; ehci->reset_done [wIndex] = 0; /* force reset to complete */ - writel (temp & ~(PORT_RWC_BITS | PORT_RESET), - &ehci->regs->port_status [wIndex]); + ehci_writel(ehci, temp & ~(PORT_RWC_BITS | PORT_RESET), + status_reg); /* REVISIT: some hardware needs 550+ usec to clear * this bit; seems too long to spin routinely... */ - retval = handshake ( - &ehci->regs->port_status [wIndex], + retval = handshake(ehci, status_reg, PORT_RESET, 0, 750); if (retval != 0) { ehci_err (ehci, "port %d reset error %d\n", @@ -495,28 +611,41 @@ static int ehci_hub_control ( } /* see what we found out */ - temp = check_reset_complete (ehci, wIndex, - readl (&ehci->regs->port_status [wIndex])); + temp = check_reset_complete (ehci, wIndex, status_reg, + ehci_readl(ehci, status_reg)); } - // don't show wPortStatus if it's owned by a companion hc - if (!(temp & PORT_OWNER)) { - if (temp & PORT_CONNECT) { - status |= 1 << USB_PORT_FEAT_CONNECTION; - // status may be from integrated TT - status |= ehci_port_speed(ehci, temp); - } - if (temp & PORT_PE) - status |= 1 << USB_PORT_FEAT_ENABLE; - if (temp & (PORT_SUSPEND|PORT_RESUME)) - status |= 1 << USB_PORT_FEAT_SUSPEND; - if (temp & PORT_OC) - status |= 1 << USB_PORT_FEAT_OVER_CURRENT; - if (temp & PORT_RESET) - status |= 1 << USB_PORT_FEAT_RESET; - if (temp & PORT_POWER) - status |= 1 << USB_PORT_FEAT_POWER; + /* transfer dedicated ports to the companion hc */ + if ((temp & PORT_CONNECT) && + test_bit(wIndex, &ehci->companion_ports)) { + temp &= ~PORT_RWC_BITS; + temp |= PORT_OWNER; + ehci_writel(ehci, temp, status_reg); + ehci_dbg(ehci, "port %d --> companion\n", wIndex + 1); + temp = ehci_readl(ehci, status_reg); + } + + /* + * Even if OWNER is set, there's no harm letting khubd + * see the wPortStatus values (they should all be 0 except + * for PORT_POWER anyway). + */ + + if (temp & PORT_CONNECT) { + status |= 1 << USB_PORT_FEAT_CONNECTION; + // status may be from integrated TT + status |= ehci_port_speed(ehci, temp); } + if (temp & PORT_PE) + status |= 1 << USB_PORT_FEAT_ENABLE; + if (temp & (PORT_SUSPEND|PORT_RESUME)) + status |= 1 << USB_PORT_FEAT_SUSPEND; + if (temp & PORT_OC) + status |= 1 << USB_PORT_FEAT_OVER_CURRENT; + if (temp & PORT_RESET) + status |= 1 << USB_PORT_FEAT_RESET; + if (temp & PORT_POWER) + status |= 1 << USB_PORT_FEAT_POWER; #ifndef EHCI_VERBOSE_DEBUG if (status & ~0xffff) /* only if wPortChange is interesting */ @@ -541,7 +670,7 @@ #endif if (!wIndex || wIndex > ports) goto error; wIndex--; - temp = readl (&ehci->regs->port_status [wIndex]); + temp = ehci_readl(ehci, status_reg); if (temp & PORT_OWNER) break; @@ -555,13 +684,12 @@ #endif goto error; if (device_may_wakeup(&hcd->self.root_hub->dev)) temp |= PORT_WAKE_BITS; - writel (temp | PORT_SUSPEND, - &ehci->regs->port_status [wIndex]); + ehci_writel(ehci, temp | PORT_SUSPEND, status_reg); break; case USB_PORT_FEAT_POWER: if (HCS_PPC (ehci->hcs_params)) - writel (temp | PORT_POWER, - &ehci->regs->port_status [wIndex]); + ehci_writel(ehci, temp | PORT_POWER, + status_reg); break; case USB_PORT_FEAT_RESET: if (temp & PORT_RESUME) @@ -589,7 +717,7 @@ #endif ehci->reset_done [wIndex] = jiffies + msecs_to_jiffies (50); } - writel (temp, &ehci->regs->port_status [wIndex]); + ehci_writel(ehci, temp, status_reg); break; /* For downstream facing ports (these): one hub port is put @@ -604,13 +732,13 @@ #endif ehci_quiesce(ehci); ehci_halt(ehci); temp |= selector << 16; - writel (temp, &ehci->regs->port_status [wIndex]); + ehci_writel(ehci, temp, status_reg); break; default: goto error; } - readl (&ehci->regs->command); /* unblock posted writes */ + ehci_readl(ehci, &ehci->regs->command); /* unblock posted writes */ break; default: diff --git a/drivers/usb/host/ehci-pci.c b/drivers/usb/host/ehci-pci.c index 4bc7970..12edc72 100644 --- a/drivers/usb/host/ehci-pci.c +++ b/drivers/usb/host/ehci-pci.c @@ -38,7 +38,7 @@ static int ehci_pci_reinit(struct ehci_h if ((temp & (3 << 13)) == (1 << 13)) { temp &= 0x1fff; ehci->debug = ehci_to_hcd(ehci)->regs + temp; - temp = readl(&ehci->debug->control); + temp = ehci_readl(ehci, &ehci->debug->control); ehci_info(ehci, "debug port %d%s\n", HCS_DEBUG_PORT(ehci->hcs_params), (temp & DBGP_ENABLED) @@ -71,8 +71,24 @@ static int ehci_pci_setup(struct usb_hcd u32 temp; int retval; + switch (pdev->vendor) { + case PCI_VENDOR_ID_TOSHIBA_2: + /* celleb's companion chip */ + if (pdev->device == 0x01b5) { +#ifdef CONFIG_USB_EHCI_BIG_ENDIAN_MMIO + ehci->big_endian_mmio = 1; +#else + ehci_warn(ehci, + "unsupported big endian Toshiba quirk\n"); +#endif + } + break; + } + ehci->caps = hcd->regs; - ehci->regs = hcd->regs + HC_LENGTH(readl(&ehci->caps->hc_capbase)); + ehci->regs = hcd->regs + + HC_LENGTH(ehci_readl(ehci, &ehci->caps->hc_capbase)); + dbg_hcs_params(ehci, "reset"); dbg_hcc_params(ehci, "reset"); @@ -101,7 +117,7 @@ static int ehci_pci_setup(struct usb_hcd } /* cache this readonly data; minimize chip reads */ - ehci->hcs_params = readl(&ehci->caps->hcs_params); + ehci->hcs_params = ehci_readl(ehci, &ehci->caps->hcs_params); retval = ehci_halt(ehci); if (retval) @@ -235,8 +251,8 @@ static int ehci_pci_suspend(struct usb_h rc = -EINVAL; goto bail; } - writel (0, &ehci->regs->intr_enable); - (void)readl(&ehci->regs->intr_enable); + ehci_writel(ehci, 0, &ehci->regs->intr_enable); + (void)ehci_readl(ehci, &ehci->regs->intr_enable); /* make sure snapshot being resumed re-enumerates everything */ if (message.event == PM_EVENT_PRETHAW) { @@ -270,13 +286,13 @@ static int ehci_pci_resume(struct usb_hc /* If CF is still set, we maintained PCI Vaux power. * Just undo the effect of ehci_pci_suspend(). */ - if (readl(&ehci->regs->configured_flag) == FLAG_CF) { + if (ehci_readl(ehci, &ehci->regs->configured_flag) == FLAG_CF) { int mask = INTR_MASK; if (!device_may_wakeup(&hcd->self.root_hub->dev)) mask &= ~STS_PCD; - writel(mask, &ehci->regs->intr_enable); - readl(&ehci->regs->intr_enable); + ehci_writel(ehci, mask, &ehci->regs->intr_enable); + ehci_readl(ehci, &ehci->regs->intr_enable); return 0; } @@ -300,9 +316,9 @@ static int ehci_pci_resume(struct usb_hc /* here we "know" root ports should always stay powered */ ehci_port_power(ehci, 1); - writel(ehci->command, &ehci->regs->command); - writel(FLAG_CF, &ehci->regs->configured_flag); - readl(&ehci->regs->command); /* unblock posted writes */ + ehci_writel(ehci, ehci->command, &ehci->regs->command); + ehci_writel(ehci, FLAG_CF, &ehci->regs->configured_flag); + ehci_readl(ehci, &ehci->regs->command); /* unblock posted writes */ hcd->state = HC_STATE_SUSPENDED; return 0; diff --git a/drivers/usb/host/ehci-ps3.c b/drivers/usb/host/ehci-ps3.c new file mode 100644 index 0000000..4d781a2 --- /dev/null +++ b/drivers/usb/host/ehci-ps3.c @@ -0,0 +1,193 @@ +/* + * PS3 EHCI Host Controller driver + * + * Copyright (C) 2006 Sony Computer Entertainment Inc. + * Copyright 2006 Sony Corp. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include + +static int ps3_ehci_hc_reset(struct usb_hcd *hcd) +{ + int result; + struct ehci_hcd *ehci = hcd_to_ehci(hcd); + + ehci->big_endian_mmio = 1; + + ehci->caps = hcd->regs; + ehci->regs = hcd->regs + HC_LENGTH(ehci_readl(ehci, + &ehci->caps->hc_capbase)); + + dbg_hcs_params(ehci, "reset"); + dbg_hcc_params(ehci, "reset"); + + ehci->hcs_params = ehci_readl(ehci, &ehci->caps->hcs_params); + + result = ehci_halt(ehci); + + if (result) + return result; + + result = ehci_init(hcd); + + if (result) + return result; + + ehci_port_power(ehci, 0); + + return result; +} + +static const struct hc_driver ps3_ehci_hc_driver = { + .description = hcd_name, + .product_desc = "PS3 EHCI Host Controller", + .hcd_priv_size = sizeof(struct ehci_hcd), + .irq = ehci_irq, + .flags = HCD_MEMORY | HCD_USB2, + .reset = ps3_ehci_hc_reset, + .start = ehci_run, + .stop = ehci_stop, + .shutdown = ehci_shutdown, + .urb_enqueue = ehci_urb_enqueue, + .urb_dequeue = ehci_urb_dequeue, + .endpoint_disable = ehci_endpoint_disable, + .get_frame_number = ehci_get_frame, + .hub_status_data = ehci_hub_status_data, + .hub_control = ehci_hub_control, +#if defined(CONFIG_PM) + .bus_suspend = ehci_bus_suspend, + .bus_resume = ehci_bus_resume, +#endif +}; + +#if !defined(DEBUG) +#undef dev_dbg +static inline int __attribute__ ((format (printf, 2, 3))) dev_dbg( + const struct device *_dev, const char *fmt, ...) {return 0;} +#endif + + +static int ps3_ehci_sb_probe(struct ps3_system_bus_device *dev) +{ + int result; + struct usb_hcd *hcd; + unsigned int virq; + static u64 dummy_mask = DMA_32BIT_MASK; + + if (usb_disabled()) { + result = -ENODEV; + goto fail_start; + } + + result = ps3_mmio_region_create(dev->m_region); + + if (result) { + dev_dbg(&dev->core, "%s:%d: ps3_map_mmio_region failed\n", + __func__, __LINE__); + result = -EPERM; + goto fail_mmio; + } + + dev_dbg(&dev->core, "%s:%d: mmio mapped_addr %lxh\n", __func__, + __LINE__, dev->m_region->lpar_addr); + + result = ps3_alloc_io_irq(PS3_BINDING_CPU_ANY, dev->interrupt_id, &virq); + + if (result) { + dev_dbg(&dev->core, "%s:%d: ps3_construct_io_irq(%d) failed.\n", + __func__, __LINE__, virq); + result = -EPERM; + goto fail_irq; + } + + dev->core.power.power_state = PMSG_ON; + dev->core.dma_mask = &dummy_mask; /* FIXME: for improper usb code */ + + hcd = usb_create_hcd(&ps3_ehci_hc_driver, &dev->core, dev->core.bus_id); + + if (!hcd) { + dev_dbg(&dev->core, "%s:%d: usb_create_hcd failed\n", __func__, + __LINE__); + result = -ENOMEM; + goto fail_create_hcd; + } + + hcd->rsrc_start = dev->m_region->lpar_addr; + hcd->rsrc_len = dev->m_region->len; + hcd->regs = ioremap(dev->m_region->lpar_addr, dev->m_region->len); + + if (!hcd->regs) { + dev_dbg(&dev->core, "%s:%d: ioremap failed\n", __func__, + __LINE__); + result = -EPERM; + goto fail_ioremap; + } + + dev_dbg(&dev->core, "%s:%d: hcd->rsrc_start %lxh\n", __func__, __LINE__, + (unsigned long)hcd->rsrc_start); + dev_dbg(&dev->core, "%s:%d: hcd->rsrc_len %lxh\n", __func__, __LINE__, + (unsigned long)hcd->rsrc_len); + dev_dbg(&dev->core, "%s:%d: hcd->regs %lxh\n", __func__, __LINE__, + (unsigned long)hcd->regs); + dev_dbg(&dev->core, "%s:%d: virq %lu\n", __func__, __LINE__, + (unsigned long)virq); + + ps3_system_bus_set_driver_data(dev, hcd); + + result = usb_add_hcd(hcd, virq, IRQF_DISABLED); + + if (result) { + dev_dbg(&dev->core, "%s:%d: usb_add_hcd failed (%d)\n", + __func__, __LINE__, result); + goto fail_add_hcd; + } + + return result; + +fail_add_hcd: + iounmap(hcd->regs); +fail_ioremap: + usb_put_hcd(hcd); +fail_create_hcd: + ps3_free_io_irq(virq); +fail_irq: + ps3_free_mmio_region(dev->m_region); +fail_mmio: +fail_start: + return result; +} + +static int ps3_ehci_sb_remove(struct ps3_system_bus_device *dev) +{ + struct usb_hcd *hcd = + (struct usb_hcd *)ps3_system_bus_get_driver_data(dev); + + usb_put_hcd(hcd); + ps3_system_bus_set_driver_data(dev, NULL); + + return 0; +} + +MODULE_ALIAS("ps3-ehci"); + +static struct ps3_system_bus_driver ps3_ehci_sb_driver = { + .match_id = PS3_MATCH_ID_EHCI, + .core = { + .name = "ps3-ehci-driver", + }, + .probe = ps3_ehci_sb_probe, + .remove = ps3_ehci_sb_remove, +}; diff --git a/drivers/usb/host/ehci-q.c b/drivers/usb/host/ehci-q.c index 62e46dc..e7fbbd0 100644 --- a/drivers/usb/host/ehci-q.c +++ b/drivers/usb/host/ehci-q.c @@ -789,13 +789,14 @@ static void qh_link_async (struct ehci_h head = ehci->async; timer_action_done (ehci, TIMER_ASYNC_OFF); if (!head->qh_next.qh) { - u32 cmd = readl (&ehci->regs->command); + u32 cmd = ehci_readl(ehci, &ehci->regs->command); if (!(cmd & CMD_ASE)) { /* in case a clear of CMD_ASE didn't take yet */ - (void) handshake (&ehci->regs->status, STS_ASS, 0, 150); + (void)handshake(ehci, &ehci->regs->status, + STS_ASS, 0, 150); cmd |= CMD_ASE | CMD_RUN; - writel (cmd, &ehci->regs->command); + ehci_writel(ehci, cmd, &ehci->regs->command); ehci_to_hcd(ehci)->state = HC_STATE_RUNNING; /* posted write need not be known to HC yet ... */ } @@ -1007,7 +1008,7 @@ static void end_unlink_async (struct ehc static void start_unlink_async (struct ehci_hcd *ehci, struct ehci_qh *qh) { - int cmd = readl (&ehci->regs->command); + int cmd = ehci_readl(ehci, &ehci->regs->command); struct ehci_qh *prev; #ifdef DEBUG @@ -1025,7 +1026,8 @@ #endif if (ehci_to_hcd(ehci)->state != HC_STATE_HALT && !ehci->reclaim) { /* ... and CMD_IAAD clear */ - writel (cmd & ~CMD_ASE, &ehci->regs->command); + ehci_writel(ehci, cmd & ~CMD_ASE, + &ehci->regs->command); wmb (); // handshake later, if we need to timer_action_done (ehci, TIMER_ASYNC_OFF); @@ -1054,8 +1056,8 @@ #endif ehci->reclaim_ready = 0; cmd |= CMD_IAAD; - writel (cmd, &ehci->regs->command); - (void) readl (&ehci->regs->command); + ehci_writel(ehci, cmd, &ehci->regs->command); + (void)ehci_readl(ehci, &ehci->regs->command); timer_action (ehci, TIMER_IAA_WATCHDOG); } diff --git a/drivers/usb/host/ehci-sched.c b/drivers/usb/host/ehci-sched.c index 65c402a..7b5ae71 100644 --- a/drivers/usb/host/ehci-sched.c +++ b/drivers/usb/host/ehci-sched.c @@ -433,20 +433,20 @@ static int enable_periodic (struct ehci_ /* did clearing PSE did take effect yet? * takes effect only at frame boundaries... */ - status = handshake (&ehci->regs->status, STS_PSS, 0, 9 * 125); + status = handshake(ehci, &ehci->regs->status, STS_PSS, 0, 9 * 125); if (status != 0) { ehci_to_hcd(ehci)->state = HC_STATE_HALT; return status; } - cmd = readl (&ehci->regs->command) | CMD_PSE; - writel (cmd, &ehci->regs->command); + cmd = ehci_readl(ehci, &ehci->regs->command) | CMD_PSE; + ehci_writel(ehci, cmd, &ehci->regs->command); /* posted write ... PSS happens later */ ehci_to_hcd(ehci)->state = HC_STATE_RUNNING; /* make sure ehci_work scans these */ - ehci->next_uframe = readl (&ehci->regs->frame_index) - % (ehci->periodic_size << 3); + ehci->next_uframe = ehci_readl(ehci, &ehci->regs->frame_index) + % (ehci->periodic_size << 3); return 0; } @@ -458,14 +458,14 @@ static int disable_periodic (struct ehci /* did setting PSE not take effect yet? * takes effect only at frame boundaries... */ - status = handshake (&ehci->regs->status, STS_PSS, STS_PSS, 9 * 125); + status = handshake(ehci, &ehci->regs->status, STS_PSS, STS_PSS, 9 * 125); if (status != 0) { ehci_to_hcd(ehci)->state = HC_STATE_HALT; return status; } - cmd = readl (&ehci->regs->command) & ~CMD_PSE; - writel (cmd, &ehci->regs->command); + cmd = ehci_readl(ehci, &ehci->regs->command) & ~CMD_PSE; + ehci_writel(ehci, cmd, &ehci->regs->command); /* posted write ... */ ehci->next_uframe = -1; @@ -1336,7 +1336,7 @@ iso_stream_schedule ( goto fail; } - now = readl (&ehci->regs->frame_index) % mod; + now = ehci_readl(ehci, &ehci->regs->frame_index) % mod; /* when's the last uframe this urb could start? */ max = now + mod; @@ -2088,7 +2088,7 @@ scan_periodic (struct ehci_hcd *ehci) */ now_uframe = ehci->next_uframe; if (HC_IS_RUNNING (ehci_to_hcd(ehci)->state)) - clock = readl (&ehci->regs->frame_index); + clock = ehci_readl(ehci, &ehci->regs->frame_index); else clock = now_uframe + mod - 1; clock %= mod; @@ -2213,7 +2213,7 @@ restart: if (!HC_IS_RUNNING (ehci_to_hcd(ehci)->state)) break; ehci->next_uframe = now_uframe; - now = readl (&ehci->regs->frame_index) % mod; + now = ehci_readl(ehci, &ehci->regs->frame_index) % mod; if (now_uframe == now) break; diff --git a/drivers/usb/host/ehci.h b/drivers/usb/host/ehci.h index 74dbc6c..46fa57a 100644 --- a/drivers/usb/host/ehci.h +++ b/drivers/usb/host/ehci.h @@ -74,7 +74,11 @@ #define DEFAULT_I_TDPS 1024 /* some HC /* per root hub port */ unsigned long reset_done [EHCI_MAX_ROOT_PORTS]; - unsigned long bus_suspended; + /* bit vectors (one bit per port) */ + unsigned long bus_suspended; /* which ports were + already suspended at the start of a bus suspend */ + unsigned long companion_ports; /* which ports are + dedicated to the companion controller */ /* per-HC memory pools (could be per-bus, but ...) */ struct dma_pool *qh_pool; /* qh per active urb */ @@ -92,6 +96,7 @@ #define DEFAULT_I_TDPS 1024 /* some HC unsigned is_tdi_rh_tt:1; /* TDI roothub with TT */ unsigned no_selective_suspend:1; unsigned has_fsl_port_bug:1; /* FreeScale */ + unsigned big_endian_mmio:1; u8 sbrn; /* packed release number */ @@ -651,6 +656,45 @@ #else #define ehci_has_fsl_portno_bug(e) (0) #endif +/* + * While most USB host controllers implement their registers in + * little-endian format, a minority (celleb companion chip) implement + * them in big endian format. + * + * This attempts to support either format at compile time without a + * runtime penalty, or both formats with the additional overhead + * of checking a flag bit. + */ + +#ifdef CONFIG_USB_EHCI_BIG_ENDIAN_MMIO +#define ehci_big_endian_mmio(e) ((e)->big_endian_mmio) +#else +#define ehci_big_endian_mmio(e) 0 +#endif + +static inline unsigned int ehci_readl (const struct ehci_hcd *ehci, + __u32 __iomem * regs) +{ +#ifdef CONFIG_USB_EHCI_BIG_ENDIAN_MMIO + return ehci_big_endian_mmio(ehci) ? + readl_be(regs) : + readl(regs); +#else + return readl(regs); +#endif +} + +static inline void ehci_writel (const struct ehci_hcd *ehci, + const unsigned int val, __u32 __iomem *regs) +{ +#ifdef CONFIG_USB_EHCI_BIG_ENDIAN_MMIO + ehci_big_endian_mmio(ehci) ? + writel_be(val, regs) : + writel(val, regs); +#else + writel(val, regs); +#endif +} /*-------------------------------------------------------------------------*/ diff --git a/drivers/usb/host/hc_crisv10.c b/drivers/usb/host/hc_crisv10.c index 282d82e..32f7caf 100644 --- a/drivers/usb/host/hc_crisv10.c +++ b/drivers/usb/host/hc_crisv10.c @@ -7,7 +7,6 @@ #include #include #include -#include #include #include #include @@ -2163,9 +2162,8 @@ static void etrax_usb_add_to_bulk_sb_lis maxlen = usb_maxpacket(urb->dev, urb->pipe, usb_pipeout(urb->pipe)); - sb_desc = (USB_SB_Desc_t*)kmem_cache_alloc(usb_desc_cache, SLAB_FLAG); + sb_desc = kmem_cache_zalloc(usb_desc_cache, SLAB_FLAG); assert(sb_desc != NULL); - memset(sb_desc, 0, sizeof(USB_SB_Desc_t)); if (usb_pipeout(urb->pipe)) { diff --git a/drivers/usb/host/ohci-at91.c b/drivers/usb/host/ohci-at91.c index cc40551..9303464 100644 --- a/drivers/usb/host/ohci-at91.c +++ b/drivers/usb/host/ohci-at91.c @@ -170,7 +170,6 @@ static int usb_hcd_at91_remove(struct us at91_stop_hc(pdev); iounmap(hcd->regs); release_mem_region(hcd->rsrc_start, hcd->rsrc_len); - disable_irq_wake(hcd->irq); clk_put(fclk); clk_put(iclk); @@ -271,8 +270,6 @@ ohci_hcd_at91_drv_suspend(struct platfor if (device_may_wakeup(&pdev->dev)) enable_irq_wake(hcd->irq); - else - disable_irq_wake(hcd->irq); /* * The integrated transceivers seem unable to notice disconnect, @@ -293,6 +290,11 @@ ohci_hcd_at91_drv_suspend(struct platfor static int ohci_hcd_at91_drv_resume(struct platform_device *pdev) { + struct usb_hcd *hcd = platform_get_drvdata(pdev); + + if (device_may_wakeup(&pdev->dev)) + disable_irq_wake(hcd->irq); + if (!clocked) { clk_enable(iclk); clk_enable(fclk); @@ -320,18 +322,3 @@ static struct platform_driver ohci_hcd_a }, }; -static int __init ohci_hcd_at91_init (void) -{ - if (usb_disabled()) - return -ENODEV; - - return platform_driver_register(&ohci_hcd_at91_driver); -} - -static void __exit ohci_hcd_at91_cleanup (void) -{ - platform_driver_unregister(&ohci_hcd_at91_driver); -} - -module_init (ohci_hcd_at91_init); -module_exit (ohci_hcd_at91_cleanup); diff --git a/drivers/usb/host/ohci-au1xxx.c b/drivers/usb/host/ohci-au1xxx.c index e70b243..663a060 100644 --- a/drivers/usb/host/ohci-au1xxx.c +++ b/drivers/usb/host/ohci-au1xxx.c @@ -345,19 +345,3 @@ static struct platform_driver ohci_hcd_a }, }; -static int __init ohci_hcd_au1xxx_init (void) -{ - pr_debug (DRIVER_INFO " (Au1xxx)"); - pr_debug ("block sizes: ed %d td %d\n", - sizeof (struct ed), sizeof (struct td)); - - return platform_driver_register(&ohci_hcd_au1xxx_driver); -} - -static void __exit ohci_hcd_au1xxx_cleanup (void) -{ - platform_driver_unregister(&ohci_hcd_au1xxx_driver); -} - -module_init (ohci_hcd_au1xxx_init); -module_exit (ohci_hcd_au1xxx_cleanup); diff --git a/drivers/usb/host/ohci-ep93xx.c b/drivers/usb/host/ohci-ep93xx.c index 3348b07..a68ce9d 100644 --- a/drivers/usb/host/ohci-ep93xx.c +++ b/drivers/usb/host/ohci-ep93xx.c @@ -78,7 +78,7 @@ static int usb_hcd_ep93xx_probe(const st ohci_hcd_init(hcd_to_ohci(hcd)); - retval = usb_add_hcd(hcd, pdev->resource[1].start, SA_INTERRUPT); + retval = usb_add_hcd(hcd, pdev->resource[1].start, IRQF_DISABLED); if (retval == 0) return retval; @@ -214,15 +214,3 @@ #endif }, }; -static int __init ohci_hcd_ep93xx_init(void) -{ - return platform_driver_register(&ohci_hcd_ep93xx_driver); -} - -static void __exit ohci_hcd_ep93xx_cleanup(void) -{ - platform_driver_unregister(&ohci_hcd_ep93xx_driver); -} - -module_init(ohci_hcd_ep93xx_init); -module_exit(ohci_hcd_ep93xx_cleanup); diff --git a/drivers/usb/host/ohci-hcd.c b/drivers/usb/host/ohci-hcd.c index c1c1d87..fa6a7ce 100644 --- a/drivers/usb/host/ohci-hcd.c +++ b/drivers/usb/host/ohci-hcd.c @@ -855,63 +855,167 @@ MODULE_LICENSE ("GPL"); #ifdef CONFIG_PCI #include "ohci-pci.c" +#define PCI_DRIVER ohci_pci_driver #endif #ifdef CONFIG_SA1111 #include "ohci-sa1111.c" +#define SA1111_DRIVER ohci_hcd_sa1111_driver #endif #ifdef CONFIG_ARCH_S3C2410 #include "ohci-s3c2410.c" +#define PLATFORM_DRIVER ohci_hcd_s3c2410_driver #endif #ifdef CONFIG_ARCH_OMAP #include "ohci-omap.c" +#define PLATFORM_DRIVER ohci_hcd_omap_driver #endif #ifdef CONFIG_ARCH_LH7A404 #include "ohci-lh7a404.c" +#define PLATFORM_DRIVER ohci_hcd_lh7a404_driver #endif #ifdef CONFIG_PXA27x #include "ohci-pxa27x.c" +#define PLATFORM_DRIVER ohci_hcd_pxa27x_driver #endif #ifdef CONFIG_ARCH_EP93XX #include "ohci-ep93xx.c" +#define PLATFORM_DRIVER ohci_hcd_ep93xx_driver #endif #ifdef CONFIG_SOC_AU1X00 #include "ohci-au1xxx.c" +#define PLATFORM_DRIVER ohci_hcd_au1xxx_driver #endif #ifdef CONFIG_PNX8550 #include "ohci-pnx8550.c" +#define PLATFORM_DRIVER ohci_hcd_pnx8550_driver #endif #ifdef CONFIG_USB_OHCI_HCD_PPC_SOC #include "ohci-ppc-soc.c" +#define PLATFORM_DRIVER ohci_hcd_ppc_soc_driver #endif #ifdef CONFIG_ARCH_AT91 #include "ohci-at91.c" +#define PLATFORM_DRIVER ohci_hcd_at91_driver #endif #ifdef CONFIG_ARCH_PNX4008 #include "ohci-pnx4008.c" +#define PLATFORM_DRIVER usb_hcd_pnx4008_driver #endif -#if !(defined(CONFIG_PCI) \ - || defined(CONFIG_SA1111) \ - || defined(CONFIG_ARCH_S3C2410) \ - || defined(CONFIG_ARCH_OMAP) \ - || defined (CONFIG_ARCH_LH7A404) \ - || defined (CONFIG_PXA27x) \ - || defined (CONFIG_ARCH_EP93XX) \ - || defined (CONFIG_SOC_AU1X00) \ - || defined (CONFIG_USB_OHCI_HCD_PPC_SOC) \ - || defined (CONFIG_ARCH_AT91) \ - || defined (CONFIG_ARCH_PNX4008) \ - ) + +#ifdef CONFIG_USB_OHCI_HCD_PPC_OF +#include "ohci-ppc-of.c" +#define OF_PLATFORM_DRIVER ohci_hcd_ppc_of_driver +#endif + +#ifdef CONFIG_PPC_PS3 +#include "ohci-ps3.c" +#define PS3_SYSTEM_BUS_DRIVER ps3_ohci_sb_driver +#endif + +#if !defined(PCI_DRIVER) && \ + !defined(PLATFORM_DRIVER) && \ + !defined(OF_PLATFORM_DRIVER) && \ + !defined(SA1111_DRIVER) && \ + !defined(PS3_SYSTEM_BUS_DRIVER) #error "missing bus glue for ohci-hcd" #endif + +static int __init ohci_hcd_mod_init(void) +{ + int retval = 0; + + if (usb_disabled()) + return -ENODEV; + + printk (KERN_DEBUG "%s: " DRIVER_INFO "\n", hcd_name); + pr_debug ("%s: block sizes: ed %Zd td %Zd\n", hcd_name, + sizeof (struct ed), sizeof (struct td)); + +#ifdef PS3_SYSTEM_BUS_DRIVER + retval = ps3_system_bus_driver_register(&PS3_SYSTEM_BUS_DRIVER); + if (retval < 0) + goto error_ps3; +#endif + +#ifdef PLATFORM_DRIVER + retval = platform_driver_register(&PLATFORM_DRIVER); + if (retval < 0) + goto error_platform; +#endif + +#ifdef OF_PLATFORM_DRIVER + retval = of_register_platform_driver(&OF_PLATFORM_DRIVER); + if (retval < 0) + goto error_of_platform; +#endif + +#ifdef SA1111_DRIVER + retval = sa1111_driver_register(&SA1111_DRIVER); + if (retval < 0) + goto error_sa1111; +#endif + +#ifdef PCI_DRIVER + retval = pci_register_driver(&PCI_DRIVER); + if (retval < 0) + goto error_pci; +#endif + + return retval; + + /* Error path */ +#ifdef PCI_DRIVER + error_pci: +#endif +#ifdef SA1111_DRIVER + sa1111_driver_unregister(&SA1111_DRIVER); + error_sa1111: +#endif +#ifdef OF_PLATFORM_DRIVER + of_unregister_platform_driver(&OF_PLATFORM_DRIVER); + error_of_platform: +#endif +#ifdef PLATFORM_DRIVER + platform_driver_unregister(&PLATFORM_DRIVER); + error_platform: +#endif +#ifdef PS3_SYSTEM_BUS_DRIVER + ps3_system_bus_driver_unregister(&PS3_SYSTEM_BUS_DRIVER); + error_ps3: +#endif + return retval; +} +module_init(ohci_hcd_mod_init); + +static void __exit ohci_hcd_mod_exit(void) +{ +#ifdef PCI_DRIVER + pci_unregister_driver(&PCI_DRIVER); +#endif +#ifdef SA1111_DRIVER + sa1111_driver_unregister(&SA1111_DRIVER); +#endif +#ifdef OF_PLATFORM_DRIVER + of_unregister_platform_driver(&OF_PLATFORM_DRIVER); +#endif +#ifdef PLATFORM_DRIVER + platform_driver_unregister(&PLATFORM_DRIVER); +#endif +#ifdef PS3_SYSTEM_BUS_DRIVER + ps3_system_bus_driver_unregister(&PS3_SYSTEM_BUS_DRIVER); +#endif +} +module_exit(ohci_hcd_mod_exit); + diff --git a/drivers/usb/host/ohci-lh7a404.c b/drivers/usb/host/ohci-lh7a404.c index e9807cf..4a043ab 100644 --- a/drivers/usb/host/ohci-lh7a404.c +++ b/drivers/usb/host/ohci-lh7a404.c @@ -251,19 +251,3 @@ static struct platform_driver ohci_hcd_l }, }; -static int __init ohci_hcd_lh7a404_init (void) -{ - pr_debug (DRIVER_INFO " (LH7A404)"); - pr_debug ("block sizes: ed %d td %d\n", - sizeof (struct ed), sizeof (struct td)); - - return platform_driver_register(&ohci_hcd_lh7a404_driver); -} - -static void __exit ohci_hcd_lh7a404_cleanup (void) -{ - platform_driver_unregister(&ohci_hcd_lh7a404_driver); -} - -module_init (ohci_hcd_lh7a404_init); -module_exit (ohci_hcd_lh7a404_cleanup); diff --git a/drivers/usb/host/ohci-omap.c b/drivers/usb/host/ohci-omap.c index 27be1f9..5cfa3d1 100644 --- a/drivers/usb/host/ohci-omap.c +++ b/drivers/usb/host/ohci-omap.c @@ -544,22 +544,3 @@ #endif }, }; -static int __init ohci_hcd_omap_init (void) -{ - printk (KERN_DEBUG "%s: " DRIVER_INFO " (OMAP)\n", hcd_name); - if (usb_disabled()) - return -ENODEV; - - pr_debug("%s: block sizes: ed %Zd td %Zd\n", hcd_name, - sizeof (struct ed), sizeof (struct td)); - - return platform_driver_register(&ohci_hcd_omap_driver); -} - -static void __exit ohci_hcd_omap_cleanup (void) -{ - platform_driver_unregister(&ohci_hcd_omap_driver); -} - -module_init (ohci_hcd_omap_init); -module_exit (ohci_hcd_omap_cleanup); diff --git a/drivers/usb/host/ohci-pci.c b/drivers/usb/host/ohci-pci.c index 596e0b4..b331ac4 100644 --- a/drivers/usb/host/ohci-pci.c +++ b/drivers/usb/host/ohci-pci.c @@ -20,79 +20,154 @@ #endif /*-------------------------------------------------------------------------*/ -static int -ohci_pci_reset (struct usb_hcd *hcd) +/* AMD 756, for most chips (early revs), corrupts register + * values on read ... so enable the vendor workaround. + */ +static int __devinit ohci_quirk_amd756(struct usb_hcd *hcd) { struct ohci_hcd *ohci = hcd_to_ohci (hcd); - ohci_hcd_init (ohci); - return ohci_init (ohci); + ohci->flags = OHCI_QUIRK_AMD756; + ohci_dbg (ohci, "AMD756 erratum 4 workaround\n"); + + /* also erratum 10 (suspend/resume issues) */ + device_init_wakeup(&hcd->self.root_hub->dev, 0); + + return 0; } -static int __devinit -ohci_pci_start (struct usb_hcd *hcd) +/* Apple's OHCI driver has a lot of bizarre workarounds + * for this chip. Evidently control and bulk lists + * can get confused. (B&W G3 models, and ...) + */ +static int __devinit ohci_quirk_opti(struct usb_hcd *hcd) { struct ohci_hcd *ohci = hcd_to_ohci (hcd); - int ret; - /* REVISIT this whole block should move to reset(), which handles - * all the other one-time init. + ohci_dbg (ohci, "WARNING: OPTi workarounds unavailable\n"); + + return 0; +} + +/* Check for NSC87560. We have to look at the bridge (fn1) to + * identify the USB (fn2). This quirk might apply to more or + * even all NSC stuff. + */ +static int __devinit ohci_quirk_ns(struct usb_hcd *hcd) +{ + struct pci_dev *pdev = to_pci_dev(hcd->self.controller); + struct pci_dev *b; + + b = pci_get_slot (pdev->bus, PCI_DEVFN (PCI_SLOT (pdev->devfn), 1)); + if (b && b->device == PCI_DEVICE_ID_NS_87560_LIO + && b->vendor == PCI_VENDOR_ID_NS) { + struct ohci_hcd *ohci = hcd_to_ohci (hcd); + + ohci->flags |= OHCI_QUIRK_SUPERIO; + ohci_dbg (ohci, "Using NSC SuperIO setup\n"); + } + pci_dev_put(b); + + return 0; +} + +/* Check for Compaq's ZFMicro chipset, which needs short + * delays before control or bulk queues get re-activated + * in finish_unlinks() + */ +static int __devinit ohci_quirk_zfmicro(struct usb_hcd *hcd) +{ + struct ohci_hcd *ohci = hcd_to_ohci (hcd); + + ohci->flags |= OHCI_QUIRK_ZFMICRO; + ohci_dbg (ohci, "enabled Compaq ZFMicro chipset quirk\n"); + + return 0; +} + +/* Check for Toshiba SCC OHCI which has big endian registers + * and little endian in memory data structures + */ +static int __devinit ohci_quirk_toshiba_scc(struct usb_hcd *hcd) +{ + struct ohci_hcd *ohci = hcd_to_ohci (hcd); + + /* That chip is only present in the southbridge of some + * cell based platforms which are supposed to select + * CONFIG_USB_OHCI_BIG_ENDIAN_MMIO. We verify here if + * that was the case though. + */ +#ifdef CONFIG_USB_OHCI_BIG_ENDIAN_MMIO + ohci->flags |= OHCI_QUIRK_BE_MMIO; + ohci_dbg (ohci, "enabled big endian Toshiba quirk\n"); + return 0; +#else + ohci_err (ohci, "unsupported big endian Toshiba quirk\n"); + return -ENXIO; +#endif +} + +/* List of quirks for OHCI */ +static const struct pci_device_id ohci_pci_quirks[] = { + { + PCI_DEVICE(PCI_VENDOR_ID_AMD, 0x740c), + .driver_data = (unsigned long)ohci_quirk_amd756, + }, + { + PCI_DEVICE(PCI_VENDOR_ID_OPTI, 0xc861), + .driver_data = (unsigned long)ohci_quirk_opti, + }, + { + PCI_DEVICE(PCI_VENDOR_ID_NS, PCI_ANY_ID), + .driver_data = (unsigned long)ohci_quirk_ns, + }, + { + PCI_DEVICE(PCI_VENDOR_ID_COMPAQ, 0xa0f8), + .driver_data = (unsigned long)ohci_quirk_zfmicro, + }, + { + PCI_DEVICE(PCI_VENDOR_ID_TOSHIBA_2, 0x01b6), + .driver_data = (unsigned long)ohci_quirk_toshiba_scc, + }, + /* FIXME for some of the early AMD 760 southbridges, OHCI + * won't work at all. blacklist them. */ + + {}, +}; + +static int ohci_pci_reset (struct usb_hcd *hcd) +{ + struct ohci_hcd *ohci = hcd_to_ohci (hcd); + int ret = 0; + if (hcd->self.controller) { struct pci_dev *pdev = to_pci_dev(hcd->self.controller); + const struct pci_device_id *quirk_id; - /* AMD 756, for most chips (early revs), corrupts register - * values on read ... so enable the vendor workaround. - */ - if (pdev->vendor == PCI_VENDOR_ID_AMD - && pdev->device == 0x740c) { - ohci->flags = OHCI_QUIRK_AMD756; - ohci_dbg (ohci, "AMD756 erratum 4 workaround\n"); - /* also erratum 10 (suspend/resume issues) */ - device_init_wakeup(&hcd->self.root_hub->dev, 0); + quirk_id = pci_match_id(ohci_pci_quirks, pdev); + if (quirk_id != NULL) { + int (*quirk)(struct usb_hcd *ohci); + quirk = (void *)quirk_id->driver_data; + ret = quirk(hcd); } + } + if (ret == 0) { + ohci_hcd_init (ohci); + return ohci_init (ohci); + } + return ret; +} - /* FIXME for some of the early AMD 760 southbridges, OHCI - * won't work at all. blacklist them. - */ - - /* Apple's OHCI driver has a lot of bizarre workarounds - * for this chip. Evidently control and bulk lists - * can get confused. (B&W G3 models, and ...) - */ - else if (pdev->vendor == PCI_VENDOR_ID_OPTI - && pdev->device == 0xc861) { - ohci_dbg (ohci, - "WARNING: OPTi workarounds unavailable\n"); - } - /* Check for NSC87560. We have to look at the bridge (fn1) to - * identify the USB (fn2). This quirk might apply to more or - * even all NSC stuff. - */ - else if (pdev->vendor == PCI_VENDOR_ID_NS) { - struct pci_dev *b; - - b = pci_get_slot (pdev->bus, - PCI_DEVFN (PCI_SLOT (pdev->devfn), 1)); - if (b && b->device == PCI_DEVICE_ID_NS_87560_LIO - && b->vendor == PCI_VENDOR_ID_NS) { - ohci->flags |= OHCI_QUIRK_SUPERIO; - ohci_dbg (ohci, "Using NSC SuperIO setup\n"); - } - pci_dev_put(b); - } +static int __devinit ohci_pci_start (struct usb_hcd *hcd) +{ + struct ohci_hcd *ohci = hcd_to_ohci (hcd); + int ret; - /* Check for Compaq's ZFMicro chipset, which needs short - * delays before control or bulk queues get re-activated - * in finish_unlinks() - */ - else if (pdev->vendor == PCI_VENDOR_ID_COMPAQ - && pdev->device == 0xa0f8) { - ohci->flags |= OHCI_QUIRK_ZFMICRO; - ohci_dbg (ohci, - "enabled Compaq ZFMicro chipset quirk\n"); - } +#ifdef CONFIG_PM /* avoid warnings about unused pdev */ + if (hcd->self.controller) { + struct pci_dev *pdev = to_pci_dev(hcd->self.controller); /* RWC may not be set for add-in PCI cards, since boot * firmware probably ignored them. This transfers PCI @@ -101,16 +176,14 @@ ohci_pci_start (struct usb_hcd *hcd) if (device_may_wakeup(&pdev->dev)) ohci->hc_control |= OHCI_CTRL_RWC; } +#endif /* CONFIG_PM */ - /* NOTE: there may have already been a first reset, to - * keep bios/smm irqs from making trouble - */ - if ((ret = ohci_run (ohci)) < 0) { + ret = ohci_run (ohci); + if (ret < 0) { ohci_err (ohci, "can't start\n"); ohci_stop (hcd); - return ret; } - return 0; + return ret; } #ifdef CONFIG_PM @@ -238,23 +311,3 @@ #endif .shutdown = usb_hcd_pci_shutdown, }; - -static int __init ohci_hcd_pci_init (void) -{ - printk (KERN_DEBUG "%s: " DRIVER_INFO " (PCI)\n", hcd_name); - if (usb_disabled()) - return -ENODEV; - - pr_debug ("%s: block sizes: ed %Zd td %Zd\n", hcd_name, - sizeof (struct ed), sizeof (struct td)); - return pci_register_driver (&ohci_pci_driver); -} -module_init (ohci_hcd_pci_init); - -/*-------------------------------------------------------------------------*/ - -static void __exit ohci_hcd_pci_cleanup (void) -{ - pci_unregister_driver (&ohci_pci_driver); -} -module_exit (ohci_hcd_pci_cleanup); diff --git a/drivers/usb/host/ohci-pnx4008.c b/drivers/usb/host/ohci-pnx4008.c index 3a8cbfb..d601bbb 100644 --- a/drivers/usb/host/ohci-pnx4008.c +++ b/drivers/usb/host/ohci-pnx4008.c @@ -421,7 +421,7 @@ static int __devinit usb_hcd_pnx4008_pro ohci_hcd_init(ohci); dev_info(&pdev->dev, "at 0x%p, irq %d\n", hcd->regs, hcd->irq); - ret = usb_add_hcd(hcd, irq, SA_INTERRUPT); + ret = usb_add_hcd(hcd, irq, IRQF_DISABLED); if (ret == 0) return ret; @@ -465,15 +465,3 @@ static struct platform_driver usb_hcd_pn .remove = usb_hcd_pnx4008_remove, }; -static int __init usb_hcd_pnx4008_init(void) -{ - return platform_driver_register(&usb_hcd_pnx4008_driver); -} - -static void __exit usb_hcd_pnx4008_cleanup(void) -{ - return platform_driver_unregister(&usb_hcd_pnx4008_driver); -} - -module_init(usb_hcd_pnx4008_init); -module_exit(usb_hcd_pnx4008_cleanup); diff --git a/drivers/usb/host/ohci-pnx8550.c b/drivers/usb/host/ohci-pnx8550.c index 6922b91..85fdfd2 100644 --- a/drivers/usb/host/ohci-pnx8550.c +++ b/drivers/usb/host/ohci-pnx8550.c @@ -107,7 +107,7 @@ int usb_hcd_pnx8550_probe (const struct ohci_hcd_init(hcd_to_ohci(hcd)); - retval = usb_add_hcd(hcd, dev->resource[1].start, SA_INTERRUPT); + retval = usb_add_hcd(hcd, dev->resource[1].start, IRQF_DISABLED); if (retval == 0) return retval; @@ -240,19 +240,3 @@ static struct platform_driver ohci_hcd_p .remove = ohci_hcd_pnx8550_drv_remove, }; -static int __init ohci_hcd_pnx8550_init (void) -{ - pr_debug (DRIVER_INFO " (pnx8550)"); - pr_debug ("block sizes: ed %d td %d\n", - sizeof (struct ed), sizeof (struct td)); - - return platform_driver_register(&ohci_hcd_pnx8550_driver); -} - -static void __exit ohci_hcd_pnx8550_cleanup (void) -{ - platform_driver_unregister(&ohci_hcd_pnx8550_driver); -} - -module_init (ohci_hcd_pnx8550_init); -module_exit (ohci_hcd_pnx8550_cleanup); diff --git a/drivers/usb/host/ohci-ppc-of.c b/drivers/usb/host/ohci-ppc-of.c new file mode 100644 index 0000000..08e237c --- /dev/null +++ b/drivers/usb/host/ohci-ppc-of.c @@ -0,0 +1,232 @@ +/* + * OHCI HCD (Host Controller Driver) for USB. + * + * (C) Copyright 1999 Roman Weissgaerber + * (C) Copyright 2000-2002 David Brownell + * (C) Copyright 2002 Hewlett-Packard Company + * (C) Copyright 2006 Sylvain Munaut + * + * Bus glue for OHCI HC on the of_platform bus + * + * Modified for of_platform bus from ohci-sa1111.c + * + * This file is licenced under the GPL. + */ + +#include + +#include +#include + + +static int __devinit +ohci_ppc_of_start(struct usb_hcd *hcd) +{ + struct ohci_hcd *ohci = hcd_to_ohci(hcd); + int ret; + + if ((ret = ohci_init(ohci)) < 0) + return ret; + + if ((ret = ohci_run(ohci)) < 0) { + err("can't start %s", ohci_to_hcd(ohci)->self.bus_name); + ohci_stop(hcd); + return ret; + } + + return 0; +} + +static const struct hc_driver ohci_ppc_of_hc_driver = { + .description = hcd_name, + .product_desc = "OF OHCI", + .hcd_priv_size = sizeof(struct ohci_hcd), + + /* + * generic hardware linkage + */ + .irq = ohci_irq, + .flags = HCD_USB11 | HCD_MEMORY, + + /* + * basic lifecycle operations + */ + .start = ohci_ppc_of_start, + .stop = ohci_stop, + .shutdown = ohci_shutdown, + + /* + * managing i/o requests and associated device resources + */ + .urb_enqueue = ohci_urb_enqueue, + .urb_dequeue = ohci_urb_dequeue, + .endpoint_disable = ohci_endpoint_disable, + + /* + * scheduling support + */ + .get_frame_number = ohci_get_frame, + + /* + * root hub support + */ + .hub_status_data = ohci_hub_status_data, + .hub_control = ohci_hub_control, + .hub_irq_enable = ohci_rhsc_enable, +#ifdef CONFIG_PM + .bus_suspend = ohci_bus_suspend, + .bus_resume = ohci_bus_resume, +#endif + .start_port_reset = ohci_start_port_reset, +}; + + +static int __devinit +ohci_hcd_ppc_of_probe(struct of_device *op, const struct of_device_id *match) +{ + struct device_node *dn = op->node; + struct usb_hcd *hcd; + struct ohci_hcd *ohci; + struct resource res; + int irq; + + int rv; + int is_bigendian; + + if (usb_disabled()) + return -ENODEV; + + is_bigendian = + device_is_compatible(dn, "ohci-bigendian") || + device_is_compatible(dn, "ohci-be"); + + dev_dbg(&op->dev, "initializing PPC-OF USB Controller\n"); + + rv = of_address_to_resource(dn, 0, &res); + if (rv) + return rv; + + hcd = usb_create_hcd(&ohci_ppc_of_hc_driver, &op->dev, "PPC-OF USB"); + if (!hcd) + return -ENOMEM; + + hcd->rsrc_start = res.start; + hcd->rsrc_len = res.end - res.start + 1; + + if (!request_mem_region(hcd->rsrc_start, hcd->rsrc_len, hcd_name)) { + printk(KERN_ERR __FILE__ ": request_mem_region failed\n"); + rv = -EBUSY; + goto err_rmr; + } + + irq = irq_of_parse_and_map(dn, 0); + if (irq == NO_IRQ) { + printk(KERN_ERR __FILE__ ": irq_of_parse_and_map failed\n"); + rv = -EBUSY; + goto err_irq; + } + + hcd->regs = ioremap(hcd->rsrc_start, hcd->rsrc_len); + if (!hcd->regs) { + printk(KERN_ERR __FILE__ ": ioremap failed\n"); + rv = -ENOMEM; + goto err_ioremap; + } + + ohci = hcd_to_ohci(hcd); + if (is_bigendian) + ohci->flags |= OHCI_QUIRK_BE_MMIO | OHCI_QUIRK_BE_DESC; + + ohci_hcd_init(ohci); + + rv = usb_add_hcd(hcd, irq, 0); + if (rv == 0) + return 0; + + iounmap(hcd->regs); +err_ioremap: + irq_dispose_mapping(irq); +err_irq: + release_mem_region(hcd->rsrc_start, hcd->rsrc_len); +err_rmr: + usb_put_hcd(hcd); + + return rv; +} + +static int ohci_hcd_ppc_of_remove(struct of_device *op) +{ + struct usb_hcd *hcd = dev_get_drvdata(&op->dev); + dev_set_drvdata(&op->dev, NULL); + + dev_dbg(&op->dev, "stopping PPC-OF USB Controller\n"); + + usb_remove_hcd(hcd); + + iounmap(hcd->regs); + irq_dispose_mapping(hcd->irq); + release_mem_region(hcd->rsrc_start, hcd->rsrc_len); + + usb_put_hcd(hcd); + + return 0; +} + +static int ohci_hcd_ppc_of_shutdown(struct of_device *op) +{ + struct usb_hcd *hcd = dev_get_drvdata(&op->dev); + + if (hcd->driver->shutdown) + hcd->driver->shutdown(hcd); + + return 0; +} + + +static struct of_device_id ohci_hcd_ppc_of_match[] = { +#ifdef CONFIG_USB_OHCI_HCD_PPC_OF_BE + { + .name = "usb", + .compatible = "ohci-bigendian", + }, + { + .name = "usb", + .compatible = "ohci-be", + }, +#endif +#ifdef CONFIG_USB_OHCI_HCD_PPC_OF_LE + { + .name = "usb", + .compatible = "ohci-littledian", + }, + { + .name = "usb", + .compatible = "ohci-le", + }, +#endif + {}, +}; +MODULE_DEVICE_TABLE(of, ohci_hcd_ppc_of_match); + +#if !defined(CONFIG_USB_OHCI_HCD_PPC_OF_BE) && \ + !defined(CONFIG_USB_OHCI_HCD_PPC_OF_LE) +#error "No endianess selected for ppc-of-ohci" +#endif + + +static struct of_platform_driver ohci_hcd_ppc_of_driver = { + .name = "ppc-of-ohci", + .match_table = ohci_hcd_ppc_of_match, + .probe = ohci_hcd_ppc_of_probe, + .remove = ohci_hcd_ppc_of_remove, + .shutdown = ohci_hcd_ppc_of_shutdown, +#ifdef CONFIG_PM + /*.suspend = ohci_hcd_ppc_soc_drv_suspend,*/ + /*.resume = ohci_hcd_ppc_soc_drv_resume,*/ +#endif + .driver = { + .name = "ppc-of-ohci", + .owner = THIS_MODULE, + }, +}; + diff --git a/drivers/usb/host/ohci-ppc-soc.c b/drivers/usb/host/ohci-ppc-soc.c index e1a7eb8..1a2e177 100644 --- a/drivers/usb/host/ohci-ppc-soc.c +++ b/drivers/usb/host/ohci-ppc-soc.c @@ -72,7 +72,7 @@ static int usb_hcd_ppc_soc_probe(const s } ohci = hcd_to_ohci(hcd); - ohci->flags |= OHCI_BIG_ENDIAN; + ohci->flags |= OHCI_QUIRK_BE_MMIO | OHCI_QUIRK_BE_DESC; ohci_hcd_init(ohci); retval = usb_add_hcd(hcd, irq, IRQF_DISABLED); @@ -208,19 +208,3 @@ #endif }, }; -static int __init ohci_hcd_ppc_soc_init(void) -{ - pr_debug(DRIVER_INFO " (PPC SOC)\n"); - pr_debug("block sizes: ed %d td %d\n", sizeof(struct ed), - sizeof(struct td)); - - return platform_driver_register(&ohci_hcd_ppc_soc_driver); -} - -static void __exit ohci_hcd_ppc_soc_cleanup(void) -{ - platform_driver_unregister(&ohci_hcd_ppc_soc_driver); -} - -module_init(ohci_hcd_ppc_soc_init); -module_exit(ohci_hcd_ppc_soc_cleanup); diff --git a/drivers/usb/host/ohci-ps3.c b/drivers/usb/host/ohci-ps3.c new file mode 100644 index 0000000..62283a3 --- /dev/null +++ b/drivers/usb/host/ohci-ps3.c @@ -0,0 +1,196 @@ +/* + * PS3 OHCI Host Controller driver + * + * Copyright (C) 2006 Sony Computer Entertainment Inc. + * Copyright 2006 Sony Corp. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include + +static int ps3_ohci_hc_reset(struct usb_hcd *hcd) +{ + struct ohci_hcd *ohci = hcd_to_ohci(hcd); + + ohci->flags |= OHCI_QUIRK_BE_MMIO; + ohci_hcd_init(ohci); + return ohci_init(ohci); +} + +static int __devinit ps3_ohci_hc_start(struct usb_hcd *hcd) +{ + int result; + struct ohci_hcd *ohci = hcd_to_ohci(hcd); + + /* Handle root hub init quirk in spider south bridge. */ + /* Also set PwrOn2PwrGood to 0x7f (254ms). */ + + ohci_writel(ohci, 0x7f000000 | RH_A_PSM | RH_A_OCPM, + &ohci->regs->roothub.a); + ohci_writel(ohci, 0x00060000, &ohci->regs->roothub.b); + + result = ohci_run(ohci); + + if (result < 0) { + err("can't start %s", hcd->self.bus_name); + ohci_stop(hcd); + } + + return result; +} + +static const struct hc_driver ps3_ohci_hc_driver = { + .description = hcd_name, + .product_desc = "PS3 OHCI Host Controller", + .hcd_priv_size = sizeof(struct ohci_hcd), + .irq = ohci_irq, + .flags = HCD_MEMORY | HCD_USB11, + .reset = ps3_ohci_hc_reset, + .start = ps3_ohci_hc_start, + .stop = ohci_stop, + .shutdown = ohci_shutdown, + .urb_enqueue = ohci_urb_enqueue, + .urb_dequeue = ohci_urb_dequeue, + .endpoint_disable = ohci_endpoint_disable, + .get_frame_number = ohci_get_frame, + .hub_status_data = ohci_hub_status_data, + .hub_control = ohci_hub_control, + .hub_irq_enable = ohci_rhsc_enable, + .start_port_reset = ohci_start_port_reset, +#if defined(CONFIG_PM) + .bus_suspend = ohci_bus_suspend, + .bus_resume = ohci_bus_resume, +#endif +}; + +/* redefine dev_dbg to do a syntax check */ + +#if !defined(DEBUG) +#undef dev_dbg +static inline int __attribute__ ((format (printf, 2, 3))) dev_dbg( + const struct device *_dev, const char *fmt, ...) {return 0;} +#endif + +static int ps3_ohci_sb_probe(struct ps3_system_bus_device *dev) +{ + int result; + struct usb_hcd *hcd; + unsigned int virq; + static u64 dummy_mask = DMA_32BIT_MASK; + + if (usb_disabled()) { + result = -ENODEV; + goto fail_start; + } + + result = ps3_mmio_region_create(dev->m_region); + + if (result) { + dev_dbg(&dev->core, "%s:%d: ps3_map_mmio_region failed\n", + __func__, __LINE__); + result = -EPERM; + goto fail_mmio; + } + + dev_dbg(&dev->core, "%s:%d: mmio mapped_addr %lxh\n", __func__, + __LINE__, dev->m_region->lpar_addr); + + result = ps3_alloc_io_irq(PS3_BINDING_CPU_ANY, dev->interrupt_id, &virq); + + if (result) { + dev_dbg(&dev->core, "%s:%d: ps3_construct_io_irq(%d) failed.\n", + __func__, __LINE__, virq); + result = -EPERM; + goto fail_irq; + } + + dev->core.power.power_state = PMSG_ON; + dev->core.dma_mask = &dummy_mask; /* FIXME: for improper usb code */ + + hcd = usb_create_hcd(&ps3_ohci_hc_driver, &dev->core, dev->core.bus_id); + + if (!hcd) { + dev_dbg(&dev->core, "%s:%d: usb_create_hcd failed\n", __func__, + __LINE__); + result = -ENOMEM; + goto fail_create_hcd; + } + + hcd->rsrc_start = dev->m_region->lpar_addr; + hcd->rsrc_len = dev->m_region->len; + hcd->regs = ioremap(dev->m_region->lpar_addr, dev->m_region->len); + + if (!hcd->regs) { + dev_dbg(&dev->core, "%s:%d: ioremap failed\n", __func__, + __LINE__); + result = -EPERM; + goto fail_ioremap; + } + + dev_dbg(&dev->core, "%s:%d: hcd->rsrc_start %lxh\n", __func__, __LINE__, + (unsigned long)hcd->rsrc_start); + dev_dbg(&dev->core, "%s:%d: hcd->rsrc_len %lxh\n", __func__, __LINE__, + (unsigned long)hcd->rsrc_len); + dev_dbg(&dev->core, "%s:%d: hcd->regs %lxh\n", __func__, __LINE__, + (unsigned long)hcd->regs); + dev_dbg(&dev->core, "%s:%d: virq %lu\n", __func__, __LINE__, + (unsigned long)virq); + + ps3_system_bus_set_driver_data(dev, hcd); + + result = usb_add_hcd(hcd, virq, IRQF_DISABLED); + + if (result) { + dev_dbg(&dev->core, "%s:%d: usb_add_hcd failed (%d)\n", + __func__, __LINE__, result); + goto fail_add_hcd; + } + + return result; + +fail_add_hcd: + iounmap(hcd->regs); +fail_ioremap: + usb_put_hcd(hcd); +fail_create_hcd: + ps3_free_io_irq(virq); +fail_irq: + ps3_free_mmio_region(dev->m_region); +fail_mmio: +fail_start: + return result; +} + +static int ps3_ohci_sb_remove (struct ps3_system_bus_device *dev) +{ + struct usb_hcd *hcd = + (struct usb_hcd *)ps3_system_bus_get_driver_data(dev); + + usb_put_hcd(hcd); + ps3_system_bus_set_driver_data(dev, NULL); + + return 0; +} + +MODULE_ALIAS("ps3-ohci"); + +static struct ps3_system_bus_driver ps3_ohci_sb_driver = { + .match_id = PS3_MATCH_ID_OHCI, + .core = { + .name = "ps3-ohci-driver", + }, + .probe = ps3_ohci_sb_probe, + .remove = ps3_ohci_sb_remove, +}; diff --git a/drivers/usb/host/ohci-pxa27x.c b/drivers/usb/host/ohci-pxa27x.c index 3bbea84..f1563dc 100644 --- a/drivers/usb/host/ohci-pxa27x.c +++ b/drivers/usb/host/ohci-pxa27x.c @@ -369,19 +369,3 @@ #endif }, }; -static int __init ohci_hcd_pxa27x_init (void) -{ - pr_debug (DRIVER_INFO " (pxa27x)"); - pr_debug ("block sizes: ed %d td %d\n", - sizeof (struct ed), sizeof (struct td)); - - return platform_driver_register(&ohci_hcd_pxa27x_driver); -} - -static void __exit ohci_hcd_pxa27x_cleanup (void) -{ - platform_driver_unregister(&ohci_hcd_pxa27x_driver); -} - -module_init (ohci_hcd_pxa27x_init); -module_exit (ohci_hcd_pxa27x_cleanup); diff --git a/drivers/usb/host/ohci-s3c2410.c b/drivers/usb/host/ohci-s3c2410.c index b350d45..6829814 100644 --- a/drivers/usb/host/ohci-s3c2410.c +++ b/drivers/usb/host/ohci-s3c2410.c @@ -501,15 +501,3 @@ static struct platform_driver ohci_hcd_s }, }; -static int __init ohci_hcd_s3c2410_init (void) -{ - return platform_driver_register(&ohci_hcd_s3c2410_driver); -} - -static void __exit ohci_hcd_s3c2410_cleanup (void) -{ - platform_driver_unregister(&ohci_hcd_s3c2410_driver); -} - -module_init (ohci_hcd_s3c2410_init); -module_exit (ohci_hcd_s3c2410_cleanup); diff --git a/drivers/usb/host/ohci-sa1111.c b/drivers/usb/host/ohci-sa1111.c index fe0090e..0f48f2d 100644 --- a/drivers/usb/host/ohci-sa1111.c +++ b/drivers/usb/host/ohci-sa1111.c @@ -269,19 +269,3 @@ static struct sa1111_driver ohci_hcd_sa1 .remove = ohci_hcd_sa1111_drv_remove, }; -static int __init ohci_hcd_sa1111_init (void) -{ - dbg (DRIVER_INFO " (SA-1111)"); - dbg ("block sizes: ed %d td %d", - sizeof (struct ed), sizeof (struct td)); - - return sa1111_driver_register(&ohci_hcd_sa1111_driver); -} - -static void __exit ohci_hcd_sa1111_cleanup (void) -{ - sa1111_driver_unregister(&ohci_hcd_sa1111_driver); -} - -module_init (ohci_hcd_sa1111_init); -module_exit (ohci_hcd_sa1111_cleanup); diff --git a/drivers/usb/host/ohci.h b/drivers/usb/host/ohci.h index 405257f..c2b5ecf 100644 --- a/drivers/usb/host/ohci.h +++ b/drivers/usb/host/ohci.h @@ -394,8 +394,9 @@ struct ohci_hcd { #define OHCI_QUIRK_AMD756 0x01 /* erratum #4 */ #define OHCI_QUIRK_SUPERIO 0x02 /* natsemi */ #define OHCI_QUIRK_INITRESET 0x04 /* SiS, OPTi, ... */ -#define OHCI_BIG_ENDIAN 0x08 /* big endian HC */ -#define OHCI_QUIRK_ZFMICRO 0x10 /* Compaq ZFMicro chipset*/ +#define OHCI_QUIRK_BE_DESC 0x08 /* BE descriptors */ +#define OHCI_QUIRK_BE_MMIO 0x10 /* BE registers */ +#define OHCI_QUIRK_ZFMICRO 0x20 /* Compaq ZFMicro chipset*/ // there are also chip quirks/bugs in init logic }; @@ -439,117 +440,164 @@ #endif * a minority (notably the IBM STB04XXX and the Motorola MPC5200 * processors) implement them in big endian format. * + * In addition some more exotic implementations like the Toshiba + * Spider (aka SCC) cell southbridge are "mixed" endian, that is, + * they have a different endianness for registers vs. in-memory + * descriptors. + * * This attempts to support either format at compile time without a * runtime penalty, or both formats with the additional overhead * of checking a flag bit. + * + * That leads to some tricky Kconfig rules howevber. There are + * different defaults based on some arch/ppc platforms, though + * the basic rules are: + * + * Controller type Kconfig options needed + * --------------- ---------------------- + * little endian CONFIG_USB_OHCI_LITTLE_ENDIAN + * + * fully big endian CONFIG_USB_OHCI_BIG_ENDIAN_DESC _and_ + * CONFIG_USB_OHCI_BIG_ENDIAN_MMIO + * + * mixed endian CONFIG_USB_OHCI_LITTLE_ENDIAN _and_ + * CONFIG_USB_OHCI_BIG_ENDIAN_{MMIO,DESC} + * + * (If you have a mixed endian controller, you -must- also define + * CONFIG_USB_OHCI_LITTLE_ENDIAN or things will not work when building + * both your mixed endian and a fully big endian controller support in + * the same kernel image). */ -#ifdef CONFIG_USB_OHCI_BIG_ENDIAN +#ifdef CONFIG_USB_OHCI_BIG_ENDIAN_DESC +#ifdef CONFIG_USB_OHCI_LITTLE_ENDIAN +#define big_endian_desc(ohci) (ohci->flags & OHCI_QUIRK_BE_DESC) +#else +#define big_endian_desc(ohci) 1 /* only big endian */ +#endif +#else +#define big_endian_desc(ohci) 0 /* only little endian */ +#endif +#ifdef CONFIG_USB_OHCI_BIG_ENDIAN_MMIO #ifdef CONFIG_USB_OHCI_LITTLE_ENDIAN -#define big_endian(ohci) (ohci->flags & OHCI_BIG_ENDIAN) /* either */ +#define big_endian_mmio(ohci) (ohci->flags & OHCI_QUIRK_BE_MMIO) #else -#define big_endian(ohci) 1 /* only big endian */ +#define big_endian_mmio(ohci) 1 /* only big endian */ +#endif +#else +#define big_endian_mmio(ohci) 0 /* only little endian */ #endif /* * Big-endian read/write functions are arch-specific. * Other arches can be added if/when they're needed. + * + * REVISIT: arch/powerpc now has readl/writel_be, so the + * definition below can die once the STB04xxx support is + * finally ported over. */ -#if defined(CONFIG_PPC) +#if defined(CONFIG_PPC) && !defined(CONFIG_PPC_MERGE) #define readl_be(addr) in_be32((__force unsigned *)addr) #define writel_be(val, addr) out_be32((__force unsigned *)addr, val) #endif -static inline unsigned int ohci_readl (const struct ohci_hcd *ohci, - __hc32 __iomem * regs) +static inline unsigned int _ohci_readl (const struct ohci_hcd *ohci, + __hc32 __iomem * regs) { - return big_endian(ohci) ? readl_be (regs) : readl ((__force u32 *)regs); +#ifdef CONFIG_USB_OHCI_BIG_ENDIAN_MMIO + return big_endian_mmio(ohci) ? + readl_be (regs) : + readl (regs); +#else + return readl (regs); +#endif } -static inline void ohci_writel (const struct ohci_hcd *ohci, - const unsigned int val, __hc32 __iomem *regs) +static inline void _ohci_writel (const struct ohci_hcd *ohci, + const unsigned int val, __hc32 __iomem *regs) { - big_endian(ohci) ? writel_be (val, regs) : - writel (val, (__force u32 *)regs); +#ifdef CONFIG_USB_OHCI_BIG_ENDIAN_MMIO + big_endian_mmio(ohci) ? + writel_be (val, regs) : + writel (val, regs); +#else + writel (val, regs); +#endif } -#else /* !CONFIG_USB_OHCI_BIG_ENDIAN */ - -#define big_endian(ohci) 0 /* only little endian */ - #ifdef CONFIG_ARCH_LH7A404 - /* Marc Singer: at the time this code was written, the LH7A404 - * had a problem reading the USB host registers. This - * implementation of the ohci_readl function performs the read - * twice as a work-around. - */ -static inline unsigned int -ohci_readl (const struct ohci_hcd *ohci, const __hc32 *regs) -{ - *(volatile __force unsigned int*) regs; - return *(volatile __force unsigned int*) regs; -} +/* Marc Singer: at the time this code was written, the LH7A404 + * had a problem reading the USB host registers. This + * implementation of the ohci_readl function performs the read + * twice as a work-around. + */ +#define ohci_readl(o,r) (_ohci_readl(o,r),_ohci_readl(o,r)) +#define ohci_writel(o,v,r) _ohci_writel(o,v,r) #else - /* Standard version of ohci_readl uses standard, platform - * specific implementation. */ -static inline unsigned int -ohci_readl (const struct ohci_hcd *ohci, __hc32 __iomem * regs) -{ - return readl(regs); -} +#define ohci_readl(o,r) _ohci_readl(o,r) +#define ohci_writel(o,v,r) _ohci_writel(o,v,r) #endif -static inline void ohci_writel (const struct ohci_hcd *ohci, - const unsigned int val, __hc32 __iomem *regs) -{ - writel (val, regs); -} - -#endif /* !CONFIG_USB_OHCI_BIG_ENDIAN */ /*-------------------------------------------------------------------------*/ /* cpu to ohci */ static inline __hc16 cpu_to_hc16 (const struct ohci_hcd *ohci, const u16 x) { - return big_endian(ohci) ? (__force __hc16)cpu_to_be16(x) : (__force __hc16)cpu_to_le16(x); + return big_endian_desc(ohci) ? + (__force __hc16)cpu_to_be16(x) : + (__force __hc16)cpu_to_le16(x); } static inline __hc16 cpu_to_hc16p (const struct ohci_hcd *ohci, const u16 *x) { - return big_endian(ohci) ? cpu_to_be16p(x) : cpu_to_le16p(x); + return big_endian_desc(ohci) ? + cpu_to_be16p(x) : + cpu_to_le16p(x); } static inline __hc32 cpu_to_hc32 (const struct ohci_hcd *ohci, const u32 x) { - return big_endian(ohci) ? (__force __hc32)cpu_to_be32(x) : (__force __hc32)cpu_to_le32(x); + return big_endian_desc(ohci) ? + (__force __hc32)cpu_to_be32(x) : + (__force __hc32)cpu_to_le32(x); } static inline __hc32 cpu_to_hc32p (const struct ohci_hcd *ohci, const u32 *x) { - return big_endian(ohci) ? cpu_to_be32p(x) : cpu_to_le32p(x); + return big_endian_desc(ohci) ? + cpu_to_be32p(x) : + cpu_to_le32p(x); } /* ohci to cpu */ static inline u16 hc16_to_cpu (const struct ohci_hcd *ohci, const __hc16 x) { - return big_endian(ohci) ? be16_to_cpu((__force __be16)x) : le16_to_cpu((__force __le16)x); + return big_endian_desc(ohci) ? + be16_to_cpu((__force __be16)x) : + le16_to_cpu((__force __le16)x); } static inline u16 hc16_to_cpup (const struct ohci_hcd *ohci, const __hc16 *x) { - return big_endian(ohci) ? be16_to_cpup((__force __be16 *)x) : le16_to_cpup((__force __le16 *)x); + return big_endian_desc(ohci) ? + be16_to_cpup((__force __be16 *)x) : + le16_to_cpup((__force __le16 *)x); } static inline u32 hc32_to_cpu (const struct ohci_hcd *ohci, const __hc32 x) { - return big_endian(ohci) ? be32_to_cpu((__force __be32)x) : le32_to_cpu((__force __le32)x); + return big_endian_desc(ohci) ? + be32_to_cpu((__force __be32)x) : + le32_to_cpu((__force __le32)x); } static inline u32 hc32_to_cpup (const struct ohci_hcd *ohci, const __hc32 *x) { - return big_endian(ohci) ? be32_to_cpup((__force __be32 *)x) : le32_to_cpup((__force __le32 *)x); + return big_endian_desc(ohci) ? + be32_to_cpup((__force __be32 *)x) : + le32_to_cpup((__force __le32 *)x); } /*-------------------------------------------------------------------------*/ @@ -557,6 +605,9 @@ static inline u32 hc32_to_cpup (const st /* HCCA frame number is 16 bits, but is accessed as 32 bits since not all * hardware handles 16 bit reads. That creates a different confusion on * some big-endian SOC implementations. Same thing happens with PSW access. + * + * FIXME: Deal with that as a runtime quirk when STB03xxx is ported over + * to arch/powerpc */ #ifdef CONFIG_STB03xxx @@ -568,7 +619,7 @@ #endif static inline u16 ohci_frame_no(const struct ohci_hcd *ohci) { u32 tmp; - if (big_endian(ohci)) { + if (big_endian_desc(ohci)) { tmp = be32_to_cpup((__force __be32 *)&ohci->hcca->frame_no); tmp >>= OHCI_BE_FRAME_NO_SHIFT; } else @@ -580,7 +631,7 @@ static inline u16 ohci_frame_no(const st static inline __hc16 *ohci_hwPSWp(const struct ohci_hcd *ohci, const struct td *td, int index) { - return (__hc16 *)(big_endian(ohci) ? + return (__hc16 *)(big_endian_desc(ohci) ? &td->hwPSW[index ^ 1] : &td->hwPSW[index]); } diff --git a/drivers/usb/host/sl811_cs.c b/drivers/usb/host/sl811_cs.c index ac9f11d..2d0e73b 100644 --- a/drivers/usb/host/sl811_cs.c +++ b/drivers/usb/host/sl811_cs.c @@ -13,7 +13,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/usb/host/uhci-debug.c b/drivers/usb/host/uhci-debug.c index e345f15..5d6c06b 100644 --- a/drivers/usb/host/uhci-debug.c +++ b/drivers/usb/host/uhci-debug.c @@ -168,9 +168,13 @@ static int uhci_show_qh(struct uhci_qh * space, "", qh, qtype, le32_to_cpu(qh->link), le32_to_cpu(element)); if (qh->type == USB_ENDPOINT_XFER_ISOC) - out += sprintf(out, "%*s period %d frame %x desc [%p]\n", - space, "", qh->period, qh->iso_frame, - qh->iso_packet_desc); + out += sprintf(out, "%*s period %d phase %d load %d us, " + "frame %x desc [%p]\n", + space, "", qh->period, qh->phase, qh->load, + qh->iso_frame, qh->iso_packet_desc); + else if (qh->type == USB_ENDPOINT_XFER_INT) + out += sprintf(out, "%*s period %d phase %d load %d us\n", + space, "", qh->period, qh->phase, qh->load); if (element & UHCI_PTR_QH) out += sprintf(out, "%*s Element points to QH (bug?)\n", space, ""); @@ -208,7 +212,7 @@ static int uhci_show_qh(struct uhci_qh * space, "", nurbs); } - if (qh->udev) { + if (qh->dummy_td) { out += sprintf(out, "%*s Dummy TD\n", space, ""); out += uhci_show_td(qh->dummy_td, out, len - (out - buf), 0); } @@ -347,31 +351,80 @@ static int uhci_sprint_schedule(struct u struct uhci_qh *qh; struct uhci_td *td; struct list_head *tmp, *head; + int nframes, nerrs; out += uhci_show_root_hub_state(uhci, out, len - (out - buf)); out += sprintf(out, "HC status\n"); out += uhci_show_status(uhci, out, len - (out - buf)); + + out += sprintf(out, "Periodic load table\n"); + for (i = 0; i < MAX_PHASE; ++i) { + out += sprintf(out, "\t%d", uhci->load[i]); + if (i % 8 == 7) + *out++ = '\n'; + } + out += sprintf(out, "Total: %d, #INT: %d, #ISO: %d\n", + uhci->total_load, + uhci_to_hcd(uhci)->self.bandwidth_int_reqs, + uhci_to_hcd(uhci)->self.bandwidth_isoc_reqs); if (debug <= 1) return out - buf; out += sprintf(out, "Frame List\n"); + nframes = 10; + nerrs = 0; for (i = 0; i < UHCI_NUMFRAMES; ++i) { + __le32 link, qh_dma; + + j = 0; td = uhci->frame_cpu[i]; + link = uhci->frame[i]; if (!td) - continue; + goto check_link; - out += sprintf(out, "- Frame %d\n", i); \ - if (td->dma_handle != (dma_addr_t)uhci->frame[i]) - out += sprintf(out, " frame list does not match td->dma_handle!\n"); + if (nframes > 0) { + out += sprintf(out, "- Frame %d -> (%08x)\n", + i, le32_to_cpu(link)); + j = 1; + } head = &td->fl_list; tmp = head; do { td = list_entry(tmp, struct uhci_td, fl_list); tmp = tmp->next; - out += uhci_show_td(td, out, len - (out - buf), 4); + if (cpu_to_le32(td->dma_handle) != link) { + if (nframes > 0) + out += sprintf(out, " link does " + "not match list entry!\n"); + else + ++nerrs; + } + if (nframes > 0) + out += uhci_show_td(td, out, + len - (out - buf), 4); + link = td->link; } while (tmp != head); + +check_link: + qh_dma = uhci_frame_skel_link(uhci, i); + if (link != qh_dma) { + if (nframes > 0) { + if (!j) { + out += sprintf(out, + "- Frame %d -> (%08x)\n", + i, le32_to_cpu(link)); + j = 1; + } + out += sprintf(out, " link does not match " + "QH (%08x)!\n", le32_to_cpu(qh_dma)); + } else + ++nerrs; + } + nframes -= j; } + if (nerrs > 0) + out += sprintf(out, "Skipped %d bad links\n", nerrs); out += sprintf(out, "Skeleton QHs\n"); diff --git a/drivers/usb/host/uhci-hcd.c b/drivers/usb/host/uhci-hcd.c index e0d4c23..ded4df3 100644 --- a/drivers/usb/host/uhci-hcd.c +++ b/drivers/usb/host/uhci-hcd.c @@ -28,7 +28,6 @@ #include #include #include #include -#include #include #include #include @@ -92,6 +91,34 @@ static void suspend_rh(struct uhci_hcd * static void wakeup_rh(struct uhci_hcd *uhci); static void uhci_get_current_frame_number(struct uhci_hcd *uhci); +/* + * Calculate the link pointer DMA value for the first Skeleton QH in a frame. + */ +static __le32 uhci_frame_skel_link(struct uhci_hcd *uhci, int frame) +{ + int skelnum; + + /* + * The interrupt queues will be interleaved as evenly as possible. + * There's not much to be done about period-1 interrupts; they have + * to occur in every frame. But we can schedule period-2 interrupts + * in odd-numbered frames, period-4 interrupts in frames congruent + * to 2 (mod 4), and so on. This way each frame only has two + * interrupt QHs, which will help spread out bandwidth utilization. + * + * ffs (Find First bit Set) does exactly what we need: + * 1,3,5,... => ffs = 0 => use skel_int2_qh = skelqh[8], + * 2,6,10,... => ffs = 1 => use skel_int4_qh = skelqh[7], etc. + * ffs >= 7 => not on any high-period queue, so use + * skel_int1_qh = skelqh[9]. + * Add in UHCI_NUMFRAMES to insure at least one bit is set. + */ + skelnum = 8 - (int) __ffs(frame | UHCI_NUMFRAMES); + if (skelnum <= 1) + skelnum = 9; + return UHCI_PTR_QH | cpu_to_le32(uhci->skelqh[skelnum]->dma_handle); +} + #include "uhci-debug.c" #include "uhci-q.c" #include "uhci-hub.c" @@ -631,32 +658,11 @@ static int uhci_start(struct usb_hcd *hc /* * Fill the frame list: make all entries point to the proper * interrupt queue. - * - * The interrupt queues will be interleaved as evenly as possible. - * There's not much to be done about period-1 interrupts; they have - * to occur in every frame. But we can schedule period-2 interrupts - * in odd-numbered frames, period-4 interrupts in frames congruent - * to 2 (mod 4), and so on. This way each frame only has two - * interrupt QHs, which will help spread out bandwidth utilization. */ for (i = 0; i < UHCI_NUMFRAMES; i++) { - int irq; - - /* - * ffs (Find First bit Set) does exactly what we need: - * 1,3,5,... => ffs = 0 => use skel_int2_qh = skelqh[8], - * 2,6,10,... => ffs = 1 => use skel_int4_qh = skelqh[7], etc. - * ffs >= 7 => not on any high-period queue, so use - * skel_int1_qh = skelqh[9]. - * Add UHCI_NUMFRAMES to insure at least one bit is set. - */ - irq = 8 - (int) __ffs(i + UHCI_NUMFRAMES); - if (irq <= 1) - irq = 9; /* Only place we don't use the frame list routines */ - uhci->frame[i] = UHCI_PTR_QH | - cpu_to_le32(uhci->skelqh[irq]->dma_handle); + uhci->frame[i] = uhci_frame_skel_link(uhci, i); } /* diff --git a/drivers/usb/host/uhci-hcd.h b/drivers/usb/host/uhci-hcd.h index 108e3de..74469b5 100644 --- a/drivers/usb/host/uhci-hcd.h +++ b/drivers/usb/host/uhci-hcd.h @@ -83,6 +83,7 @@ #define UHCI_NUMFRAMES 1024 /* in the f #define UHCI_MAX_SOF_NUMBER 2047 /* in an SOF packet */ #define CAN_SCHEDULE_FRAMES 1000 /* how far in the future frames * can be scheduled */ +#define MAX_PHASE 32 /* Periodic scheduling length */ /* When no queues need Full-Speed Bandwidth Reclamation, * delay this long before turning FSBR off */ @@ -141,6 +142,8 @@ struct uhci_qh { unsigned long advance_jiffies; /* Time of last queue advance */ unsigned int unlink_frame; /* When the QH was unlinked */ unsigned int period; /* For Interrupt and Isochronous QHs */ + short phase; /* Between 0 and period-1 */ + short load; /* Periodic time requirement, in us */ unsigned int iso_frame; /* Frame # for iso_packet_desc */ int iso_status; /* Status for Isochronous URBs */ @@ -153,6 +156,8 @@ struct uhci_qh { unsigned int needs_fixup:1; /* Must fix the TD toggle values */ unsigned int is_stopped:1; /* Queue was stopped by error/unlink */ unsigned int wait_expired:1; /* QH_WAIT_TIMEOUT has expired */ + unsigned int bandwidth_reserved:1; /* Periodic bandwidth has + * been allocated */ } __attribute__((aligned(16))); /* @@ -414,6 +419,9 @@ #define UHCI_IS_STOPPED 9999 /* Larger wait_queue_head_t waitqh; /* endpoint_disable waiters */ int num_waiting; /* Number of waiters */ + + int total_load; /* Sum of array values */ + short load[MAX_PHASE]; /* Periodic allocations */ }; /* Convert between a usb_hcd pointer and the corresponding uhci_hcd */ diff --git a/drivers/usb/host/uhci-q.c b/drivers/usb/host/uhci-q.c index 30b8845..68e66b3 100644 --- a/drivers/usb/host/uhci-q.c +++ b/drivers/usb/host/uhci-q.c @@ -248,16 +248,26 @@ static struct uhci_qh *uhci_alloc_qh(str INIT_LIST_HEAD(&qh->node); if (udev) { /* Normal QH */ - qh->dummy_td = uhci_alloc_td(uhci); - if (!qh->dummy_td) { - dma_pool_free(uhci->qh_pool, qh, dma_handle); - return NULL; + qh->type = hep->desc.bmAttributes & USB_ENDPOINT_XFERTYPE_MASK; + if (qh->type != USB_ENDPOINT_XFER_ISOC) { + qh->dummy_td = uhci_alloc_td(uhci); + if (!qh->dummy_td) { + dma_pool_free(uhci->qh_pool, qh, dma_handle); + return NULL; + } } qh->state = QH_STATE_IDLE; qh->hep = hep; qh->udev = udev; hep->hcpriv = qh; - qh->type = hep->desc.bmAttributes & USB_ENDPOINT_XFERTYPE_MASK; + + if (qh->type == USB_ENDPOINT_XFER_INT || + qh->type == USB_ENDPOINT_XFER_ISOC) + qh->load = usb_calc_bus_time(udev->speed, + usb_endpoint_dir_in(&hep->desc), + qh->type == USB_ENDPOINT_XFER_ISOC, + le16_to_cpu(hep->desc.wMaxPacketSize)) + / 1000 + 1; } else { /* Skeleton QH */ qh->state = QH_STATE_ACTIVE; @@ -275,7 +285,8 @@ static void uhci_free_qh(struct uhci_hcd list_del(&qh->node); if (qh->udev) { qh->hep->hcpriv = NULL; - uhci_free_td(uhci, qh->dummy_td); + if (qh->dummy_td) + uhci_free_td(uhci, qh->dummy_td); } dma_pool_free(uhci->qh_pool, qh, qh->dma_handle); } @@ -327,7 +338,7 @@ static int uhci_cleanup_queue(struct uhc goto done; qh->element = UHCI_PTR_TERM; - /* Control pipes have to worry about toggles */ + /* Control pipes don't have to worry about toggles */ if (qh->type == USB_ENDPOINT_XFER_CONTROL) goto done; @@ -493,17 +504,130 @@ static void uhci_make_qh_idle(struct uhc wake_up_all(&uhci->waitqh); } +/* + * Find the highest existing bandwidth load for a given phase and period. + */ +static int uhci_highest_load(struct uhci_hcd *uhci, int phase, int period) +{ + int highest_load = uhci->load[phase]; + + for (phase += period; phase < MAX_PHASE; phase += period) + highest_load = max_t(int, highest_load, uhci->load[phase]); + return highest_load; +} + +/* + * Set qh->phase to the optimal phase for a periodic transfer and + * check whether the bandwidth requirement is acceptable. + */ +static int uhci_check_bandwidth(struct uhci_hcd *uhci, struct uhci_qh *qh) +{ + int minimax_load; + + /* Find the optimal phase (unless it is already set) and get + * its load value. */ + if (qh->phase >= 0) + minimax_load = uhci_highest_load(uhci, qh->phase, qh->period); + else { + int phase, load; + int max_phase = min_t(int, MAX_PHASE, qh->period); + + qh->phase = 0; + minimax_load = uhci_highest_load(uhci, qh->phase, qh->period); + for (phase = 1; phase < max_phase; ++phase) { + load = uhci_highest_load(uhci, phase, qh->period); + if (load < minimax_load) { + minimax_load = load; + qh->phase = phase; + } + } + } + + /* Maximum allowable periodic bandwidth is 90%, or 900 us per frame */ + if (minimax_load + qh->load > 900) { + dev_dbg(uhci_dev(uhci), "bandwidth allocation failed: " + "period %d, phase %d, %d + %d us\n", + qh->period, qh->phase, minimax_load, qh->load); + return -ENOSPC; + } + return 0; +} + +/* + * Reserve a periodic QH's bandwidth in the schedule + */ +static void uhci_reserve_bandwidth(struct uhci_hcd *uhci, struct uhci_qh *qh) +{ + int i; + int load = qh->load; + char *p = "??"; + + for (i = qh->phase; i < MAX_PHASE; i += qh->period) { + uhci->load[i] += load; + uhci->total_load += load; + } + uhci_to_hcd(uhci)->self.bandwidth_allocated = + uhci->total_load / MAX_PHASE; + switch (qh->type) { + case USB_ENDPOINT_XFER_INT: + ++uhci_to_hcd(uhci)->self.bandwidth_int_reqs; + p = "INT"; + break; + case USB_ENDPOINT_XFER_ISOC: + ++uhci_to_hcd(uhci)->self.bandwidth_isoc_reqs; + p = "ISO"; + break; + } + qh->bandwidth_reserved = 1; + dev_dbg(uhci_dev(uhci), + "%s dev %d ep%02x-%s, period %d, phase %d, %d us\n", + "reserve", qh->udev->devnum, + qh->hep->desc.bEndpointAddress, p, + qh->period, qh->phase, load); +} + +/* + * Release a periodic QH's bandwidth reservation + */ +static void uhci_release_bandwidth(struct uhci_hcd *uhci, struct uhci_qh *qh) +{ + int i; + int load = qh->load; + char *p = "??"; + + for (i = qh->phase; i < MAX_PHASE; i += qh->period) { + uhci->load[i] -= load; + uhci->total_load -= load; + } + uhci_to_hcd(uhci)->self.bandwidth_allocated = + uhci->total_load / MAX_PHASE; + switch (qh->type) { + case USB_ENDPOINT_XFER_INT: + --uhci_to_hcd(uhci)->self.bandwidth_int_reqs; + p = "INT"; + break; + case USB_ENDPOINT_XFER_ISOC: + --uhci_to_hcd(uhci)->self.bandwidth_isoc_reqs; + p = "ISO"; + break; + } + qh->bandwidth_reserved = 0; + dev_dbg(uhci_dev(uhci), + "%s dev %d ep%02x-%s, period %d, phase %d, %d us\n", + "release", qh->udev->devnum, + qh->hep->desc.bEndpointAddress, p, + qh->period, qh->phase, load); +} + static inline struct urb_priv *uhci_alloc_urb_priv(struct uhci_hcd *uhci, struct urb *urb) { struct urb_priv *urbp; - urbp = kmem_cache_alloc(uhci_up_cachep, GFP_ATOMIC); + urbp = kmem_cache_zalloc(uhci_up_cachep, GFP_ATOMIC); if (!urbp) return NULL; - memset((void *)urbp, 0, sizeof(*urbp)); - urbp->urb = urb; urb->hcpriv = urbp; @@ -796,7 +920,6 @@ static int uhci_submit_common(struct uhc wmb(); qh->dummy_td->status |= __constant_cpu_to_le32(TD_CTRL_ACTIVE); qh->dummy_td = td; - qh->period = urb->interval; usb_settoggle(urb->dev, usb_pipeendpoint(urb->pipe), usb_pipeout(urb->pipe), toggle); @@ -827,28 +950,42 @@ static inline int uhci_submit_bulk(struc static int uhci_submit_interrupt(struct uhci_hcd *uhci, struct urb *urb, struct uhci_qh *qh) { - int exponent; + int ret; /* USB 1.1 interrupt transfers only involve one packet per interval. * Drivers can submit URBs of any length, but longer ones will need * multiple intervals to complete. */ - /* Figure out which power-of-two queue to use */ - for (exponent = 7; exponent >= 0; --exponent) { - if ((1 << exponent) <= urb->interval) - break; - } - if (exponent < 0) - return -EINVAL; - urb->interval = 1 << exponent; + if (!qh->bandwidth_reserved) { + int exponent; - if (qh->period == 0) + /* Figure out which power-of-two queue to use */ + for (exponent = 7; exponent >= 0; --exponent) { + if ((1 << exponent) <= urb->interval) + break; + } + if (exponent < 0) + return -EINVAL; + qh->period = 1 << exponent; qh->skel = uhci->skelqh[UHCI_SKEL_INDEX(exponent)]; - else if (qh->period != urb->interval) - return -EINVAL; /* Can't change the period */ - return uhci_submit_common(uhci, urb, qh); + /* For now, interrupt phase is fixed by the layout + * of the QH lists. */ + qh->phase = (qh->period / 2) & (MAX_PHASE - 1); + ret = uhci_check_bandwidth(uhci, qh); + if (ret) + return ret; + } else if (qh->period > urb->interval) + return -EINVAL; /* Can't decrease the period */ + + ret = uhci_submit_common(uhci, urb, qh); + if (ret == 0) { + urb->interval = qh->period; + if (!qh->bandwidth_reserved) + uhci_reserve_bandwidth(uhci, qh); + } + return ret; } /* @@ -995,15 +1132,32 @@ static int uhci_submit_isochronous(struc return -EFBIG; /* Check the period and figure out the starting frame number */ - if (qh->period == 0) { + if (!qh->bandwidth_reserved) { + qh->period = urb->interval; if (urb->transfer_flags & URB_ISO_ASAP) { + qh->phase = -1; /* Find the best phase */ + i = uhci_check_bandwidth(uhci, qh); + if (i) + return i; + + /* Allow a little time to allocate the TDs */ uhci_get_current_frame_number(uhci); - urb->start_frame = uhci->frame_number + 10; + frame = uhci->frame_number + 10; + + /* Move forward to the first frame having the + * correct phase */ + urb->start_frame = frame + ((qh->phase - frame) & + (qh->period - 1)); } else { i = urb->start_frame - uhci->last_iso_frame; if (i <= 0 || i >= UHCI_NUMFRAMES) return -EINVAL; + qh->phase = urb->start_frame & (qh->period - 1); + i = uhci_check_bandwidth(uhci, qh); + if (i) + return i; } + } else if (qh->period != urb->interval) { return -EINVAL; /* Can't change the period */ @@ -1049,9 +1203,6 @@ static int uhci_submit_isochronous(struc /* Set the interrupt-on-completion flag on the last packet. */ td->status |= __constant_cpu_to_le32(TD_CTRL_IOC); - qh->skel = uhci->skel_iso_qh; - qh->period = urb->interval; - /* Add the TDs to the frame list */ frame = urb->start_frame; list_for_each_entry(td, &urbp->td_list, list) { @@ -1065,6 +1216,9 @@ static int uhci_submit_isochronous(struc qh->iso_status = 0; } + qh->skel = uhci->skel_iso_qh; + if (!qh->bandwidth_reserved) + uhci_reserve_bandwidth(uhci, qh); return 0; } @@ -1119,7 +1273,6 @@ static int uhci_urb_enqueue(struct usb_h unsigned long flags; struct urb_priv *urbp; struct uhci_qh *qh; - int bustime; spin_lock_irqsave(&uhci->lock, flags); @@ -1149,35 +1302,11 @@ static int uhci_urb_enqueue(struct usb_h ret = uhci_submit_bulk(uhci, urb, qh); break; case USB_ENDPOINT_XFER_INT: - if (list_empty(&qh->queue)) { - bustime = usb_check_bandwidth(urb->dev, urb); - if (bustime < 0) - ret = bustime; - else { - ret = uhci_submit_interrupt(uhci, urb, qh); - if (ret == 0) - usb_claim_bandwidth(urb->dev, urb, bustime, 0); - } - } else { /* inherit from parent */ - struct urb_priv *eurbp; - - eurbp = list_entry(qh->queue.prev, struct urb_priv, - node); - urb->bandwidth = eurbp->urb->bandwidth; - ret = uhci_submit_interrupt(uhci, urb, qh); - } + ret = uhci_submit_interrupt(uhci, urb, qh); break; case USB_ENDPOINT_XFER_ISOC: urb->error_count = 0; - bustime = usb_check_bandwidth(urb->dev, urb); - if (bustime < 0) { - ret = bustime; - break; - } - ret = uhci_submit_isochronous(uhci, urb, qh); - if (ret == 0) - usb_claim_bandwidth(urb->dev, urb, bustime, 1); break; } if (ret != 0) @@ -1274,24 +1403,6 @@ __acquires(uhci->lock) uhci_free_urb_priv(uhci, urbp); - switch (qh->type) { - case USB_ENDPOINT_XFER_ISOC: - /* Release bandwidth for Interrupt or Isoc. transfers */ - if (urb->bandwidth) - usb_release_bandwidth(urb->dev, urb, 1); - break; - case USB_ENDPOINT_XFER_INT: - /* Release bandwidth for Interrupt or Isoc. transfers */ - /* Make sure we don't release if we have a queued URB */ - if (list_empty(&qh->queue) && urb->bandwidth) - usb_release_bandwidth(urb->dev, urb, 0); - else - /* bandwidth was passed on to queued URB, */ - /* so don't let usb_unlink_urb() release it */ - urb->bandwidth = 0; - break; - } - spin_unlock(&uhci->lock); usb_hcd_giveback_urb(uhci_to_hcd(uhci), urb); spin_lock(&uhci->lock); @@ -1300,9 +1411,8 @@ __acquires(uhci->lock) * reserved bandwidth. */ if (list_empty(&qh->queue)) { uhci_unlink_qh(uhci, qh); - - /* Bandwidth stuff not yet implemented */ - qh->period = 0; + if (qh->bandwidth_reserved) + uhci_release_bandwidth(uhci, qh); } } diff --git a/drivers/usb/image/mdc800.c b/drivers/usb/image/mdc800.c index 63a84bb..d308afd 100644 --- a/drivers/usb/image/mdc800.c +++ b/drivers/usb/image/mdc800.c @@ -565,11 +565,15 @@ static void mdc800_usb_disconnect (struc usb_deregister_dev(intf, &mdc800_class); + /* must be under lock to make sure no URB + is submitted after usb_kill_urb() */ + mutex_lock(&mdc800->io_lock); mdc800->state=NOT_CONNECTED; usb_kill_urb(mdc800->irq_urb); usb_kill_urb(mdc800->write_urb); usb_kill_urb(mdc800->download_urb); + mutex_unlock(&mdc800->io_lock); mdc800->dev = NULL; usb_set_intfdata(intf, NULL); diff --git a/drivers/usb/image/microtek.c b/drivers/usb/image/microtek.c index 8ccddf7..896cb2b 100644 --- a/drivers/usb/image/microtek.c +++ b/drivers/usb/image/microtek.c @@ -121,7 +121,6 @@ #include #include -#include #include #include #include diff --git a/drivers/usb/input/Kconfig b/drivers/usb/input/Kconfig index c7d8875..2e71d3c 100644 --- a/drivers/usb/input/Kconfig +++ b/drivers/usb/input/Kconfig @@ -69,6 +69,14 @@ config LOGITECH_FF Note: if you say N here, this device will still be supported, but without force feedback. +config PANTHERLORD_FF + bool "PantherLord USB/PS2 2in1 Adapter support" + depends on HID_FF + select INPUT_FF_MEMLESS if USB_HID + help + Say Y here if you have a PantherLord USB/PS2 2in1 Adapter and want + to enable force feedback support for it. + config THRUSTMASTER_FF bool "ThrustMaster FireStorm Dual Power 2 support (EXPERIMENTAL)" depends on HID_FF && EXPERIMENTAL @@ -344,3 +352,15 @@ config USB_APPLETOUCH To compile this driver as a module, choose M here: the module will be called appletouch. + +config USB_GTCO + tristate "GTCO CalComp/InterWrite USB Support" + depends on USB && INPUT + ---help--- + Say Y here if you want to use the USB version of the GTCO + CalComp/InterWrite Tablet. Make sure to say Y to "Mouse support" + (CONFIG_INPUT_MOUSEDEV) and/or "Event interface support" + (CONFIG_INPUT_EVDEV) as well. + + To compile this driver as a module, choose M here: the + module will be called gtco. diff --git a/drivers/usb/input/Makefile b/drivers/usb/input/Makefile index 1a24b5b..a9d206c 100644 --- a/drivers/usb/input/Makefile +++ b/drivers/usb/input/Makefile @@ -17,6 +17,9 @@ endif ifeq ($(CONFIG_LOGITECH_FF),y) usbhid-objs += hid-lgff.o endif +ifeq ($(CONFIG_PANTHERLORD_FF),y) + usbhid-objs += hid-plff.o +endif ifeq ($(CONFIG_THRUSTMASTER_FF),y) usbhid-objs += hid-tmff.o endif @@ -45,6 +48,7 @@ obj-$(CONFIG_USB_ACECAD) += acecad.o obj-$(CONFIG_USB_YEALINK) += yealink.o obj-$(CONFIG_USB_XPAD) += xpad.o obj-$(CONFIG_USB_APPLETOUCH) += appletouch.o +obj-$(CONFIG_USB_GTCO) += gtco.o ifeq ($(CONFIG_USB_DEBUG),y) EXTRA_CFLAGS += -DDEBUG diff --git a/drivers/usb/input/aiptek.c b/drivers/usb/input/aiptek.c index 9f52429..f857935 100644 --- a/drivers/usb/input/aiptek.c +++ b/drivers/usb/input/aiptek.c @@ -76,7 +76,6 @@ #include #include #include #include -#include #include #include diff --git a/drivers/usb/input/gtco.c b/drivers/usb/input/gtco.c new file mode 100644 index 0000000..203cdc1 --- /dev/null +++ b/drivers/usb/input/gtco.c @@ -0,0 +1,1104 @@ +/* -*- linux-c -*- + +GTCO digitizer USB driver + +Use the err(), dbg() and info() macros from usb.h for system logging + +TO CHECK: Is pressure done right on report 5? + +Copyright (C) 2006 GTCO CalComp + +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. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +Permission to use, copy, modify, distribute, and sell this software and its +documentation for any purpose is hereby granted without fee, provided that +the above copyright notice appear in all copies and that both that +copyright notice and this permission notice appear in supporting +documentation, and that the name of GTCO-CalComp not be used in advertising +or publicity pertaining to distribution of the software without specific, +written prior permission. GTCO-CalComp makes no representations about the +suitability of this software for any purpose. It is provided "as is" +without express or implied warranty. + +GTCO-CALCOMP DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, +INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO +EVENT SHALL GTCO-CALCOMP BE LIABLE FOR ANY SPECIAL, INDIRECT OR +CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, +DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER +TORTIOUS ACTIONS, ARISING OUT OF OR IN CONNECTION WITH THE USE OR +PERFORMANCE OF THIS SOFTWARE. + +GTCO CalComp, Inc. +7125 Riverwood Drive +Columbia, MD 21046 + +Jeremy Roberson jroberson@gtcocalcomp.com +Scott Hill shill@gtcocalcomp.com +*/ + + + +/*#define DEBUG*/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +#include +#include + +/* Version with a Major number of 2 is for kernel inclusion only. */ +#define GTCO_VERSION "2.00.0006" + + +/* MACROS */ + +#define VENDOR_ID_GTCO 0x078C +#define PID_400 0x400 +#define PID_401 0x401 +#define PID_1000 0x1000 +#define PID_1001 0x1001 +#define PID_1002 0x1002 + +/* Max size of a single report */ +#define REPORT_MAX_SIZE 10 + + +/* Bitmask whether pen is in range */ +#define MASK_INRANGE 0x20 +#define MASK_BUTTON 0x01F + +#define PATHLENGTH 64 + +/* DATA STRUCTURES */ + +/* Device table */ +static struct usb_device_id gtco_usbid_table [] = { + { USB_DEVICE(VENDOR_ID_GTCO, PID_400) }, + { USB_DEVICE(VENDOR_ID_GTCO, PID_401) }, + { USB_DEVICE(VENDOR_ID_GTCO, PID_1000) }, + { USB_DEVICE(VENDOR_ID_GTCO, PID_1001) }, + { USB_DEVICE(VENDOR_ID_GTCO, PID_1002) }, + { } +}; +MODULE_DEVICE_TABLE (usb, gtco_usbid_table); + + +/* Structure to hold all of our device specific stuff */ +struct gtco { + + struct input_dev *inputdevice; /* input device struct pointer */ + struct usb_device *usbdev; /* the usb device for this device */ + struct urb *urbinfo; /* urb for incoming reports */ + dma_addr_t buf_dma; /* dma addr of the data buffer*/ + unsigned char * buffer; /* databuffer for reports */ + + char usbpath[PATHLENGTH]; + int openCount; + + /* Information pulled from Report Descriptor */ + u32 usage; + u32 min_X; + u32 max_X; + u32 min_Y; + u32 max_Y; + s8 mintilt_X; + s8 maxtilt_X; + s8 mintilt_Y; + s8 maxtilt_Y; + u32 maxpressure; + u32 minpressure; +}; + + + +/* Code for parsing the HID REPORT DESCRIPTOR */ + +/* From HID1.11 spec */ +struct hid_descriptor +{ + struct usb_descriptor_header header; + __le16 bcdHID; + u8 bCountryCode; + u8 bNumDescriptors; + u8 bDescriptorType; + __le16 wDescriptorLength; +} __attribute__ ((packed)); + + +#define HID_DESCRIPTOR_SIZE 9 +#define HID_DEVICE_TYPE 33 +#define REPORT_DEVICE_TYPE 34 + + +#define PREF_TAG(x) ((x)>>4) +#define PREF_TYPE(x) ((x>>2)&0x03) +#define PREF_SIZE(x) ((x)&0x03) + +#define TYPE_MAIN 0 +#define TYPE_GLOBAL 1 +#define TYPE_LOCAL 2 +#define TYPE_RESERVED 3 + +#define TAG_MAIN_INPUT 0x8 +#define TAG_MAIN_OUTPUT 0x9 +#define TAG_MAIN_FEATURE 0xB +#define TAG_MAIN_COL_START 0xA +#define TAG_MAIN_COL_END 0xC + +#define TAG_GLOB_USAGE 0 +#define TAG_GLOB_LOG_MIN 1 +#define TAG_GLOB_LOG_MAX 2 +#define TAG_GLOB_PHYS_MIN 3 +#define TAG_GLOB_PHYS_MAX 4 +#define TAG_GLOB_UNIT_EXP 5 +#define TAG_GLOB_UNIT 6 +#define TAG_GLOB_REPORT_SZ 7 +#define TAG_GLOB_REPORT_ID 8 +#define TAG_GLOB_REPORT_CNT 9 +#define TAG_GLOB_PUSH 10 +#define TAG_GLOB_POP 11 + +#define TAG_GLOB_MAX 12 + +#define DIGITIZER_USAGE_TIP_PRESSURE 0x30 +#define DIGITIZER_USAGE_TILT_X 0x3D +#define DIGITIZER_USAGE_TILT_Y 0x3E + + +/* + * + * This is an abbreviated parser for the HID Report Descriptor. We + * know what devices we are talking to, so this is by no means meant + * to be generic. We can make some safe assumptions: + * + * - We know there are no LONG tags, all short + * - We know that we have no MAIN Feature and MAIN Output items + * - We know what the IRQ reports are supposed to look like. + * + * The main purpose of this is to use the HID report desc to figure + * out the mins and maxs of the fields in the IRQ reports. The IRQ + * reports for 400/401 change slightly if the max X is bigger than 64K. + * + */ +static void parse_hid_report_descriptor(struct gtco *device, char * report, + int length) +{ + int x,i=0; + + /* Tag primitive vars */ + __u8 prefix; + __u8 size; + __u8 tag; + __u8 type; + __u8 data = 0; + __u16 data16 = 0; + __u32 data32 = 0; + + + /* For parsing logic */ + int inputnum = 0; + __u32 usage = 0; + + /* Global Values, indexed by TAG */ + __u32 globalval[TAG_GLOB_MAX]; + __u32 oldval[TAG_GLOB_MAX]; + + /* Debug stuff */ + char maintype='x'; + char globtype[12]; + int indent=0; + char indentstr[10]=""; + + + + dbg("======>>>>>>PARSE<<<<<<======"); + + /* Walk this report and pull out the info we need */ + while (imax_X == 0){ + device->max_X = globalval[TAG_GLOB_LOG_MAX]; + device->min_X = globalval[TAG_GLOB_LOG_MIN]; + } + + break; + case 1: /* Y coord */ + dbg("GER: Y Usage: 0x%x",usage); + if (device->max_Y == 0){ + device->max_Y = globalval[TAG_GLOB_LOG_MAX]; + device->min_Y = globalval[TAG_GLOB_LOG_MIN]; + } + break; + default: + /* Tilt X */ + if (usage == DIGITIZER_USAGE_TILT_X){ + if (device->maxtilt_X == 0){ + device->maxtilt_X = globalval[TAG_GLOB_LOG_MAX]; + device->mintilt_X = globalval[TAG_GLOB_LOG_MIN]; + } + } + + /* Tilt Y */ + if (usage == DIGITIZER_USAGE_TILT_Y){ + if (device->maxtilt_Y == 0){ + device->maxtilt_Y = globalval[TAG_GLOB_LOG_MAX]; + device->mintilt_Y = globalval[TAG_GLOB_LOG_MIN]; + } + } + + + /* Pressure */ + if (usage == DIGITIZER_USAGE_TIP_PRESSURE){ + if (device->maxpressure == 0){ + device->maxpressure = globalval[TAG_GLOB_LOG_MAX]; + device->minpressure = globalval[TAG_GLOB_LOG_MIN]; + } + } + + break; + } + + inputnum++; + + + break; + case TAG_MAIN_OUTPUT: + maintype='O'; + break; + case TAG_MAIN_FEATURE: + maintype='F'; + break; + case TAG_MAIN_COL_START: + maintype='S'; + + if (data==0){ + dbg("======>>>>>> Physical"); + strcpy(globtype,"Physical"); + }else{ + dbg("======>>>>>>"); + } + + /* Indent the debug output */ + indent++; + for (x=0;xusage == 0){ + device->usage = data; + } + strcpy(globtype,"USAGE"); + break; + case TAG_GLOB_LOG_MIN : + strcpy(globtype,"LOG_MIN"); + break; + case TAG_GLOB_LOG_MAX : + strcpy(globtype,"LOG_MAX"); + break; + case TAG_GLOB_PHYS_MIN : + strcpy(globtype,"PHYS_MIN"); + break; + case TAG_GLOB_PHYS_MAX : + strcpy(globtype,"PHYS_MAX"); + break; + case TAG_GLOB_UNIT_EXP : + strcpy(globtype,"EXP"); + break; + case TAG_GLOB_UNIT : + strcpy(globtype,"UNIT"); + break; + case TAG_GLOB_REPORT_SZ : + strcpy(globtype,"REPORT_SZ"); + break; + case TAG_GLOB_REPORT_ID : + strcpy(globtype,"REPORT_ID"); + /* New report, restart numbering */ + inputnum=0; + break; + case TAG_GLOB_REPORT_CNT: + strcpy(globtype,"REPORT_CNT"); + break; + case TAG_GLOB_PUSH : + strcpy(globtype,"PUSH"); + break; + case TAG_GLOB_POP: + strcpy(globtype,"POP"); + break; + } + + + /* Check to make sure we have a good tag number + so we don't overflow array */ + if (tag < TAG_GLOB_MAX){ + switch (size){ + case 1: + dbg("%sGLOBALTAG:%s(%d) SIZE: %d Data: 0x%x",indentstr,globtype,tag,size,data); + globalval[tag]=data; + break; + case 2: + dbg("%sGLOBALTAG:%s(%d) SIZE: %d Data: 0x%x",indentstr,globtype,tag,size,data16); + globalval[tag]=data16; + break; + case 4: + dbg("%sGLOBALTAG:%s(%d) SIZE: %d Data: 0x%x",indentstr,globtype,tag,size,data32); + globalval[tag]=data32; + break; + } + }else{ + dbg("%sGLOBALTAG: ILLEGAL TAG:%d SIZE: %d ", + indentstr,tag,size); + } + + + break; + + case TYPE_LOCAL: + switch(tag){ + case TAG_GLOB_USAGE: + strcpy(globtype,"USAGE"); + /* Always 1 byte */ + usage = data; + break; + case TAG_GLOB_LOG_MIN : + strcpy(globtype,"MIN"); + break; + case TAG_GLOB_LOG_MAX : + strcpy(globtype,"MAX"); + break; + default: + strcpy(globtype,"UNKNOWN"); + } + + switch (size){ + case 1: + dbg("%sLOCALTAG:(%d) %s SIZE: %d Data: 0x%x", + indentstr,tag,globtype,size,data); + break; + case 2: + dbg("%sLOCALTAG:(%d) %s SIZE: %d Data: 0x%x", + indentstr,tag,globtype,size,data16); + break; + case 4: + dbg("%sLOCALTAG:(%d) %s SIZE: %d Data: 0x%x", + indentstr,tag,globtype,size,data32); + break; + } + + break; + } + + } + +} + + + +/* INPUT DRIVER Routines */ + + +/* + * Called when opening the input device. This will submit the URB to + * the usb system so we start getting reports + */ +static int gtco_input_open(struct input_dev *inputdev) +{ + struct gtco *device; + device = inputdev->private; + + device->urbinfo->dev = device->usbdev; + if (usb_submit_urb(device->urbinfo, GFP_KERNEL)) { + return -EIO; + } + return 0; +} + +/** + Called when closing the input device. This will unlink the URB +*/ +static void gtco_input_close(struct input_dev *inputdev) +{ + struct gtco *device = inputdev->private; + + usb_kill_urb(device->urbinfo); + +} + + +/* + * Setup input device capabilities. Tell the input system what this + * device is capable of generating. + * + * This information is based on what is read from the HID report and + * placed in the struct gtco structure + * + */ +static void gtco_setup_caps(struct input_dev *inputdev) +{ + struct gtco *device = inputdev->private; + + + /* Which events */ + inputdev->evbit[0] = BIT(EV_KEY) | BIT(EV_ABS) | BIT(EV_MSC); + + + /* Misc event menu block */ + inputdev->mscbit[0] = BIT(MSC_SCAN)|BIT(MSC_SERIAL)|BIT(MSC_RAW) ; + + + /* Absolute values based on HID report info */ + input_set_abs_params(inputdev, ABS_X, device->min_X, device->max_X, + 0, 0); + input_set_abs_params(inputdev, ABS_Y, device->min_Y, device->max_Y, + 0, 0); + + /* Proximity */ + input_set_abs_params(inputdev, ABS_DISTANCE, 0, 1, 0, 0); + + /* Tilt & pressure */ + input_set_abs_params(inputdev, ABS_TILT_X, device->mintilt_X, + device->maxtilt_X, 0, 0); + input_set_abs_params(inputdev, ABS_TILT_Y, device->mintilt_Y, + device->maxtilt_Y, 0, 0); + input_set_abs_params(inputdev, ABS_PRESSURE, device->minpressure, + device->maxpressure, 0, 0); + + + /* Transducer */ + input_set_abs_params(inputdev, ABS_MISC, 0,0xFF, 0, 0); + +} + + + +/* USB Routines */ + + +/* + * URB callback routine. Called when we get IRQ reports from the + * digitizer. + * + * This bridges the USB and input device worlds. It generates events + * on the input device based on the USB reports. + */ +static void gtco_urb_callback(struct urb *urbinfo) +{ + + + struct gtco *device = urbinfo->context; + struct input_dev *inputdev; + int rc; + u32 val = 0; + s8 valsigned = 0; + char le_buffer[2]; + + inputdev = device->inputdevice; + + + /* Was callback OK? */ + if ((urbinfo->status == -ECONNRESET ) || + (urbinfo->status == -ENOENT ) || + (urbinfo->status == -ESHUTDOWN )){ + + /* Shutdown is occurring. Return and don't queue up any more */ + return; + } + + if (urbinfo->status != 0 ) { + /* Some unknown error. Hopefully temporary. Just go and */ + /* requeue an URB */ + goto resubmit; + } + + /* + * Good URB, now process + */ + + /* PID dependent when we interpret the report */ + if ((inputdev->id.product == PID_1000 )|| + (inputdev->id.product == PID_1001 )|| + (inputdev->id.product == PID_1002 )) + { + + /* + * Switch on the report ID + * Conveniently, the reports have more information, the higher + * the report number. We can just fall through the case + * statements if we start with the highest number report + */ + switch(device->buffer[0]){ + case 5: + /* Pressure is 9 bits */ + val = ((u16)(device->buffer[8]) << 1); + val |= (u16)(device->buffer[7] >> 7); + input_report_abs(inputdev, ABS_PRESSURE, + device->buffer[8]); + + /* Mask out the Y tilt value used for pressure */ + device->buffer[7] = (u8)((device->buffer[7]) & 0x7F); + + + /* Fall thru */ + case 4: + /* Tilt */ + + /* Sign extend these 7 bit numbers. */ + if (device->buffer[6] & 0x40) + device->buffer[6] |= 0x80; + + if (device->buffer[7] & 0x40) + device->buffer[7] |= 0x80; + + + valsigned = (device->buffer[6]); + input_report_abs(inputdev, ABS_TILT_X, (s32)valsigned); + + valsigned = (device->buffer[7]); + input_report_abs(inputdev, ABS_TILT_Y, (s32)valsigned); + + /* Fall thru */ + + case 2: + case 3: + /* Convert buttons, only 5 bits possible */ + val = (device->buffer[5])&MASK_BUTTON; + + /* We don't apply any meaning to the bitmask, + just report */ + input_event(inputdev, EV_MSC, MSC_SERIAL, val); + + /* Fall thru */ + case 1: + + /* All reports have X and Y coords in the same place */ + val = le16_to_cpu(get_unaligned((__le16 *) &(device->buffer[1]))); + input_report_abs(inputdev, ABS_X, val); + + val = le16_to_cpu(get_unaligned((__le16 *) &(device->buffer[3]))); + input_report_abs(inputdev, ABS_Y, val); + + + /* Ditto for proximity bit */ + if (device->buffer[5]& MASK_INRANGE){ + val = 1; + }else{ + val=0; + } + input_report_abs(inputdev, ABS_DISTANCE, val); + + + /* Report 1 is an exception to how we handle buttons */ + /* Buttons are an index, not a bitmask */ + if (device->buffer[0] == 1){ + + /* Convert buttons, 5 bit index */ + /* Report value of index set as one, + the rest as 0 */ + val = device->buffer[5]& MASK_BUTTON; + dbg("======>>>>>>REPORT 1: val 0x%X(%d)", + val,val); + + /* + * We don't apply any meaning to the button + * index, just report it + */ + input_event(inputdev, EV_MSC, MSC_SERIAL, val); + + + } + + break; + case 7: + /* Menu blocks */ + input_event(inputdev, EV_MSC, MSC_SCAN, + device->buffer[1]); + + + break; + + } + + + } + /* Other pid class */ + if ((inputdev->id.product == PID_400 )|| + (inputdev->id.product == PID_401 )) + { + + /* Report 2 */ + if (device->buffer[0] == 2){ + /* Menu blocks */ + input_event(inputdev, EV_MSC, MSC_SCAN, + device->buffer[1]); + } + + /* Report 1 */ + if (device->buffer[0] == 1){ + char buttonbyte; + + + /* IF X max > 64K, we still a bit from the y report */ + if (device->max_X > 0x10000){ + + val = (u16)(((u16)(device->buffer[2]<<8))|((u8)(device->buffer[1]))); + val |= (u32)(((u8)device->buffer[3]&0x1)<< 16); + + input_report_abs(inputdev, ABS_X, val); + + le_buffer[0] = (u8)((u8)(device->buffer[3])>>1); + le_buffer[0] |= (u8)((device->buffer[3]&0x1)<<7); + + le_buffer[1] = (u8)(device->buffer[4]>>1); + le_buffer[1] |= (u8)((device->buffer[5]&0x1)<<7); + + val = le16_to_cpu(get_unaligned((__le16 *)(le_buffer))); + + input_report_abs(inputdev, ABS_Y, val); + + + /* + * Shift the button byte right by one to + * make it look like the standard report + */ + buttonbyte = (device->buffer[5])>>1; + }else{ + + val = le16_to_cpu(get_unaligned((__le16 *) (&(device->buffer[1])))); + input_report_abs(inputdev, ABS_X, val); + + val = le16_to_cpu(get_unaligned((__le16 *) (&(device->buffer[3])))); + input_report_abs(inputdev, ABS_Y, val); + + buttonbyte = device->buffer[5]; + + } + + + /* BUTTONS and PROXIMITY */ + if (buttonbyte& MASK_INRANGE){ + val = 1; + }else{ + val=0; + } + input_report_abs(inputdev, ABS_DISTANCE, val); + + /* Convert buttons, only 4 bits possible */ + val = buttonbyte&0x0F; +#ifdef USE_BUTTONS + for ( i=0;i<5;i++){ + input_report_key(inputdev, BTN_DIGI+i,val&(1<buffer[6]); + + } + } + + /* Everybody gets report ID's */ + input_event(inputdev, EV_MSC, MSC_RAW, device->buffer[0]); + + /* Sync it up */ + input_sync(inputdev); + + resubmit: + rc = usb_submit_urb(urbinfo, GFP_ATOMIC); + if (rc != 0) { + err("usb_submit_urb failed rc=0x%x",rc); + } + +} + +/* + * The probe routine. This is called when the kernel find the matching USB + * vendor/product. We do the following: + * + * - Allocate mem for a local structure to manage the device + * - Request a HID Report Descriptor from the device and parse it to + * find out the device parameters + * - Create an input device and assign it attributes + * - Allocate an URB so the device can talk to us when the input + * queue is open + */ +static int gtco_probe(struct usb_interface *usbinterface, + const struct usb_device_id *id) +{ + + struct gtco *device = NULL; + char path[PATHLENGTH]; + struct input_dev *inputdev; + struct hid_descriptor *hid_desc; + char *report; + int result=0, retry; + struct usb_endpoint_descriptor *endpoint; + + /* Allocate memory for device structure */ + device = kzalloc(sizeof(struct gtco), GFP_KERNEL); + if (device == NULL) { + err("No more memory"); + return -ENOMEM; + } + + + device->inputdevice = input_allocate_device(); + if (!device->inputdevice){ + kfree(device); + err("No more memory"); + return -ENOMEM; + } + + /* Get pointer to the input device */ + inputdev = device->inputdevice; + + /* Save interface information */ + device->usbdev = usb_get_dev(interface_to_usbdev(usbinterface)); + + + /* Allocate some data for incoming reports */ + device->buffer = usb_buffer_alloc(device->usbdev, REPORT_MAX_SIZE, + GFP_KERNEL, &(device->buf_dma)); + if (!device->buffer){ + input_free_device(device->inputdevice); + kfree(device); + err("No more memory"); + return -ENOMEM; + } + + /* Allocate URB for reports */ + device->urbinfo = usb_alloc_urb(0, GFP_KERNEL); + if (!device->urbinfo) { + usb_buffer_free(device->usbdev, REPORT_MAX_SIZE, + device->buffer, device->buf_dma); + input_free_device(device->inputdevice); + kfree(device); + err("No more memory"); + return -ENOMEM; + } + + + /* + * The endpoint is always altsetting 0, we know this since we know + * this device only has one interrupt endpoint + */ + endpoint = &usbinterface->altsetting[0].endpoint[0].desc; + + /* Some debug */ + dbg("gtco # interfaces: %d",usbinterface->num_altsetting); + dbg("num endpoints: %d",usbinterface->cur_altsetting->desc.bNumEndpoints); + dbg("interface class: %d",usbinterface->cur_altsetting->desc.bInterfaceClass); + dbg("endpoint: attribute:0x%x type:0x%x",endpoint->bmAttributes,endpoint->bDescriptorType); + if ((endpoint->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) == USB_ENDPOINT_XFER_INT) + dbg("endpoint: we have interrupt endpoint\n"); + + dbg("endpoint extra len:%d ",usbinterface->altsetting[0].extralen); + + + + /* + * Find the HID descriptor so we can find out the size of the + * HID report descriptor + */ + if (usb_get_extra_descriptor(usbinterface->cur_altsetting, + HID_DEVICE_TYPE,&hid_desc) != 0){ + err("Can't retrieve exta USB descriptor to get hid report descriptor length"); + usb_buffer_free(device->usbdev, REPORT_MAX_SIZE, + device->buffer, device->buf_dma); + input_free_device(device->inputdevice); + kfree(device); + return -EIO; + } + + dbg("Extra descriptor success: type:%d len:%d", + hid_desc->bDescriptorType, hid_desc->wDescriptorLength); + + if (!(report = kzalloc(hid_desc->wDescriptorLength, GFP_KERNEL))) { + usb_buffer_free(device->usbdev, REPORT_MAX_SIZE, + device->buffer, device->buf_dma); + + input_free_device(device->inputdevice); + kfree(device); + err("No more memory"); + return -ENOMEM; + } + + /* Couple of tries to get reply */ + for (retry=0;retry<3;retry++) { + result = usb_control_msg(device->usbdev, + usb_rcvctrlpipe(device->usbdev, 0), + USB_REQ_GET_DESCRIPTOR, + USB_RECIP_INTERFACE | USB_DIR_IN, + (REPORT_DEVICE_TYPE << 8), + 0, /* interface */ + report, + hid_desc->wDescriptorLength, + 5000); /* 5 secs */ + + if (result == hid_desc->wDescriptorLength) + break; + } + + /* If we didn't get the report, fail */ + dbg("usb_control_msg result: :%d", result); + if (result != hid_desc->wDescriptorLength){ + kfree(report); + usb_buffer_free(device->usbdev, REPORT_MAX_SIZE, + device->buffer, device->buf_dma); + input_free_device(device->inputdevice); + kfree(device); + err("Failed to get HID Report Descriptor of size: %d", + hid_desc->wDescriptorLength); + return -EIO; + } + + + /* Now we parse the report */ + parse_hid_report_descriptor(device,report,result); + + /* Now we delete it */ + kfree(report); + + /* Create a device file node */ + usb_make_path(device->usbdev, path, PATHLENGTH); + sprintf(device->usbpath, "%s/input0", path); + + + /* Set Input device functions */ + inputdev->open = gtco_input_open; + inputdev->close = gtco_input_close; + + /* Set input device information */ + inputdev->name = "GTCO_CalComp"; + inputdev->phys = device->usbpath; + inputdev->private = device; + + + /* Now set up all the input device capabilities */ + gtco_setup_caps(inputdev); + + /* Set input device required ID information */ + usb_to_input_id(device->usbdev, &device->inputdevice->id); + inputdev->cdev.dev = &usbinterface->dev; + + /* Setup the URB, it will be posted later on open of input device */ + endpoint = &usbinterface->altsetting[0].endpoint[0].desc; + + usb_fill_int_urb(device->urbinfo, + device->usbdev, + usb_rcvintpipe(device->usbdev, + endpoint->bEndpointAddress), + device->buffer, + REPORT_MAX_SIZE, + gtco_urb_callback, + device, + endpoint->bInterval); + + device->urbinfo->transfer_dma = device->buf_dma; + device->urbinfo->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; + + + /* Save device pointer in USB interface device */ + usb_set_intfdata(usbinterface, device); + + /* All done, now register the input device */ + input_register_device(inputdev); + + info( "gtco driver created usb: %s\n", path); + return 0; + +} + +/* + * This function is a standard USB function called when the USB device + * is disconnected. We will get rid of the URV, de-register the input + * device, and free up allocated memory + */ +static void gtco_disconnect(struct usb_interface *interface) +{ + + /* Grab private device ptr */ + struct gtco *device = usb_get_intfdata (interface); + struct input_dev *inputdev; + + inputdev = device->inputdevice; + + /* Now reverse all the registration stuff */ + if (device) { + input_unregister_device(inputdev); + usb_kill_urb(device->urbinfo); + usb_free_urb(device->urbinfo); + usb_buffer_free(device->usbdev, REPORT_MAX_SIZE, + device->buffer, device->buf_dma); + kfree(device); + } + + info("gtco driver disconnected"); +} + + +/* STANDARD MODULE LOAD ROUTINES */ + +static struct usb_driver gtco_driverinfo_table = { +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,16)) + .owner = THIS_MODULE, +#endif + .name = "gtco", + .id_table = gtco_usbid_table, + .probe = gtco_probe, + .disconnect = gtco_disconnect, +}; +/* + * Register this module with the USB subsystem + */ +static int __init gtco_init(void) +{ + int rc; + rc = usb_register(>co_driverinfo_table); + if (rc) { + err("usb_register() failed rc=0x%x", rc); + } + printk("GTCO usb driver version: %s",GTCO_VERSION); + return rc; +} + +/* + * Deregister this module with the USB subsystem + */ +static void __exit gtco_exit(void) +{ + usb_deregister(>co_driverinfo_table); +} + +module_init (gtco_init); +module_exit (gtco_exit); + +MODULE_LICENSE("GPL"); diff --git a/drivers/usb/input/hid-core.c b/drivers/usb/input/hid-core.c index c6c9e72..4d8ed3d 100644 --- a/drivers/usb/input/hid-core.c +++ b/drivers/usb/input/hid-core.c @@ -18,7 +18,6 @@ #include #include #include #include -#include #include #include #include @@ -35,6 +34,7 @@ #include #include #include +#include #include "usbhid.h" /* @@ -220,23 +220,6 @@ static void hid_irq_in(struct urb *urb) } } -/* - * Find a report field with a specified HID usage. - */ -#if 0 -struct hid_field *hid_find_field_by_usage(struct hid_device *hid, __u32 wanted_usage, int type) -{ - struct hid_report *report; - int i; - - list_for_each_entry(report, &hid->report_enum[type].report_list, list) - for (i = 0; i < report->maxfield; i++) - if (report->field[i]->logical == wanted_usage) - return report->field[i]; - return NULL; -} -#endif /* 0 */ - static int hid_submit_out(struct hid_device *hid) { struct hid_report *report; @@ -501,7 +484,7 @@ static int hid_get_class_descriptor(stru { int result, retries = 4; - memset(buf,0,size); // Make sure we parse really received data + memset(buf, 0, size); do { result = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), @@ -528,18 +511,6 @@ void usbhid_close(struct hid_device *hid usb_kill_urb(usbhid->urbin); } -static int hidinput_open(struct input_dev *dev) -{ - struct hid_device *hid = dev->private; - return usbhid_open(hid); -} - -static void hidinput_close(struct input_dev *dev) -{ - struct hid_device *hid = dev->private; - usbhid_close(hid); -} - #define USB_VENDOR_ID_PANJIT 0x134c #define USB_VENDOR_ID_TURBOX 0x062a @@ -770,6 +741,7 @@ #define USB_DEVICE_ID_APPLE_GEYSER4_ISO #define USB_DEVICE_ID_APPLE_GEYSER4_JIS 0x021c #define USB_DEVICE_ID_APPLE_FOUNTAIN_TP_ONLY 0x030a #define USB_DEVICE_ID_APPLE_GEYSER1_TP_ONLY 0x030b +#define USB_DEVICE_ID_APPLE_IR 0x8240 #define USB_VENDOR_ID_CHERRY 0x046a #define USB_DEVICE_ID_CHERRY_CYMOTION 0x0023 @@ -792,6 +764,12 @@ #define USB_DEVICE_ID_LOGITECH_USB_RECEI #define USB_VENDOR_ID_IMATION 0x0718 #define USB_DEVICE_ID_DISC_STAKKA 0xd000 +#define USB_VENDOR_ID_PANTHERLORD 0x0810 +#define USB_DEVICE_ID_PANTHERLORD_TWIN_USB_JOYSTICK 0x0001 + +#define USB_VENDOR_ID_SONY 0x054c +#define USB_DEVICE_ID_SONY_PS3_CONTROLLER 0x0268 + /* * Alphabetically sorted blacklist by quirk type. */ @@ -946,19 +924,21 @@ static const struct hid_blacklist { { USB_VENDOR_ID_CHERRY, USB_DEVICE_ID_CHERRY_CYMOTION, HID_QUIRK_CYMOTION }, - { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_FOUNTAIN_ANSI, HID_QUIRK_POWERBOOK_HAS_FN }, - { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_FOUNTAIN_ISO, HID_QUIRK_POWERBOOK_HAS_FN }, - { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER_ANSI, HID_QUIRK_POWERBOOK_HAS_FN }, - { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER_ISO, HID_QUIRK_POWERBOOK_HAS_FN | HID_QUIRK_POWERBOOK_ISO_KEYBOARD}, - { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER_JIS, HID_QUIRK_POWERBOOK_HAS_FN }, - { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER3_ANSI, HID_QUIRK_POWERBOOK_HAS_FN }, - { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER3_ISO, HID_QUIRK_POWERBOOK_HAS_FN | HID_QUIRK_POWERBOOK_ISO_KEYBOARD}, - { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER3_JIS, HID_QUIRK_POWERBOOK_HAS_FN }, - { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER4_ANSI, HID_QUIRK_POWERBOOK_HAS_FN }, - { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER4_ISO, HID_QUIRK_POWERBOOK_HAS_FN | HID_QUIRK_POWERBOOK_ISO_KEYBOARD}, - { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER4_JIS, HID_QUIRK_POWERBOOK_HAS_FN }, - { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_FOUNTAIN_TP_ONLY, HID_QUIRK_POWERBOOK_HAS_FN }, - { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER1_TP_ONLY, HID_QUIRK_POWERBOOK_HAS_FN }, + { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_FOUNTAIN_ANSI, HID_QUIRK_POWERBOOK_HAS_FN | HID_QUIRK_IGNORE_MOUSE }, + { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_FOUNTAIN_ISO, HID_QUIRK_POWERBOOK_HAS_FN | HID_QUIRK_IGNORE_MOUSE }, + { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER_ANSI, HID_QUIRK_POWERBOOK_HAS_FN | HID_QUIRK_IGNORE_MOUSE }, + { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER_ISO, HID_QUIRK_POWERBOOK_HAS_FN | HID_QUIRK_IGNORE_MOUSE | HID_QUIRK_POWERBOOK_ISO_KEYBOARD}, + { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER_JIS, HID_QUIRK_POWERBOOK_HAS_FN | HID_QUIRK_IGNORE_MOUSE }, + { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER3_ANSI, HID_QUIRK_POWERBOOK_HAS_FN | HID_QUIRK_IGNORE_MOUSE }, + { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER3_ISO, HID_QUIRK_POWERBOOK_HAS_FN | HID_QUIRK_IGNORE_MOUSE | HID_QUIRK_POWERBOOK_ISO_KEYBOARD}, + { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER3_JIS, HID_QUIRK_POWERBOOK_HAS_FN | HID_QUIRK_IGNORE_MOUSE }, + { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER4_ANSI, HID_QUIRK_POWERBOOK_HAS_FN | HID_QUIRK_IGNORE_MOUSE }, + { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER4_ISO, HID_QUIRK_POWERBOOK_HAS_FN | HID_QUIRK_IGNORE_MOUSE | HID_QUIRK_POWERBOOK_ISO_KEYBOARD}, + { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER4_JIS, HID_QUIRK_POWERBOOK_HAS_FN | HID_QUIRK_IGNORE_MOUSE }, + { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_FOUNTAIN_TP_ONLY, HID_QUIRK_POWERBOOK_HAS_FN | HID_QUIRK_IGNORE_MOUSE }, + { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER1_TP_ONLY, HID_QUIRK_POWERBOOK_HAS_FN | HID_QUIRK_IGNORE_MOUSE }, + + { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_IR, HID_QUIRK_IGNORE }, { USB_VENDOR_ID_PANJIT, 0x0001, HID_QUIRK_IGNORE }, { USB_VENDOR_ID_PANJIT, 0x0002, HID_QUIRK_IGNORE }, @@ -969,6 +949,10 @@ static const struct hid_blacklist { { USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_USB_RECEIVER, HID_QUIRK_BAD_RELATIVE_KEYS }, + { USB_VENDOR_ID_PANTHERLORD, USB_DEVICE_ID_PANTHERLORD_TWIN_USB_JOYSTICK, HID_QUIRK_MULTI_INPUT | HID_QUIRK_SKIP_OUTPUT_REPORTS }, + + { USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_PS3_CONTROLLER, HID_QUIRK_SONY_PS3_CONTROLLER }, + { 0, 0 } }; @@ -1033,6 +1017,32 @@ static void hid_fixup_cymotion_descripto } } +/* + * Sending HID_REQ_GET_REPORT changes the operation mode of the ps3 controller + * to "operational". Without this, the ps3 controller will not report any + * events. + */ +static void hid_fixup_sony_ps3_controller(struct usb_device *dev, int ifnum) +{ + int result; + char *buf = kmalloc(18, GFP_KERNEL); + + if (!buf) + return; + + result = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), + HID_REQ_GET_REPORT, + USB_DIR_IN | USB_TYPE_CLASS | + USB_RECIP_INTERFACE, + (3 << 8) | 0xf2, ifnum, buf, 17, + USB_CTRL_GET_TIMEOUT); + + if (result < 0) + err("%s failed: %d\n", __func__, result); + + kfree(buf); +} + static struct hid_device *usb_hid_configure(struct usb_interface *intf) { struct usb_host_interface *interface = intf->cur_altsetting; @@ -1064,6 +1074,11 @@ static struct hid_device *usb_hid_config if (quirks & HID_QUIRK_IGNORE) return NULL; + if ((quirks & HID_QUIRK_IGNORE_MOUSE) && + (interface->desc.bInterfaceProtocol == USB_INTERFACE_PROTOCOL_MOUSE)) + return NULL; + + if (usb_get_extra_descriptor(interface, HID_DT_HID, &hdesc) && (!interface->desc.bNumEndpoints || usb_get_extra_descriptor(&interface->endpoint[0], HID_DT_HID, &hdesc))) { @@ -1235,8 +1250,8 @@ #endif usbhid->urbctrl->transfer_dma = usbhid->ctrlbuf_dma; usbhid->urbctrl->transfer_flags |= (URB_NO_TRANSFER_DMA_MAP | URB_NO_SETUP_DMA_MAP); hid->hidinput_input_event = usb_hidinput_input_event; - hid->hidinput_open = hidinput_open; - hid->hidinput_close = hidinput_close; + hid->hid_open = usbhid_open; + hid->hid_close = usbhid_close; #ifdef CONFIG_USB_HIDDEV hid->hiddev_hid_event = hiddev_hid_event; hid->hiddev_report_event = hiddev_report_event; @@ -1315,13 +1330,13 @@ static int hid_probe(struct usb_interfac return -ENODEV; } - /* This only gets called when we are a single-input (most of the - * time). IOW, not a HID_QUIRK_MULTI_INPUT. The hid_ff_init() is - * only useful in this case, and not for multi-input quirks. */ - if ((hid->claimed & HID_CLAIMED_INPUT) && - !(hid->quirks & HID_QUIRK_MULTI_INPUT)) + if ((hid->claimed & HID_CLAIMED_INPUT)) hid_ff_init(hid); + if (hid->quirks & HID_QUIRK_SONY_PS3_CONTROLLER) + hid_fixup_sony_ps3_controller(interface_to_usbdev(intf), + intf->cur_altsetting->desc.bInterfaceNumber); + printk(KERN_INFO); if (hid->claimed & HID_CLAIMED_INPUT) diff --git a/drivers/usb/input/hid-ff.c b/drivers/usb/input/hid-ff.c index 59ed65e..bc7f8e6 100644 --- a/drivers/usb/input/hid-ff.c +++ b/drivers/usb/input/hid-ff.c @@ -57,6 +57,10 @@ #ifdef CONFIG_LOGITECH_FF { 0x46d, 0xc283, hid_lgff_init }, /* Logitech Wingman Force 3d */ { 0x46d, 0xc295, hid_lgff_init }, /* Logitech MOMO force wheel */ { 0x46d, 0xc219, hid_lgff_init }, /* Logitech Cordless rumble pad 2 */ + { 0x46d, 0xca03, hid_lgff_init }, /* Logitech MOMO force wheel */ +#endif +#ifdef CONFIG_PANTHERLORD_FF + { 0x810, 0x0001, hid_plff_init }, #endif #ifdef CONFIG_THRUSTMASTER_FF { 0x44f, 0xb304, hid_tmff_init }, diff --git a/drivers/usb/input/hid-lgff.c b/drivers/usb/input/hid-lgff.c index e474662..4df0968 100644 --- a/drivers/usb/input/hid-lgff.c +++ b/drivers/usb/input/hid-lgff.c @@ -32,7 +32,7 @@ #include #include #include "usbhid.h" -struct device_type { +struct dev_type { u16 idVendor; u16 idProduct; const signed short *ff; @@ -48,10 +48,11 @@ static const signed short ff_joystick[] -1 }; -static const struct device_type devices[] = { +static const struct dev_type devices[] = { { 0x046d, 0xc211, ff_rumble }, { 0x046d, 0xc219, ff_rumble }, { 0x046d, 0xc283, ff_joystick }, + { 0x046d, 0xca03, ff_joystick }, { 0x0000, 0x0000, ff_joystick } }; diff --git a/drivers/usb/input/hid-pidff.c b/drivers/usb/input/hid-pidff.c index cbd2d53..f5a90e9 100644 --- a/drivers/usb/input/hid-pidff.c +++ b/drivers/usb/input/hid-pidff.c @@ -24,7 +24,6 @@ #define debug(format, arg...) pr_debug("hid-pidff: " format "\n" , ## arg) -#include #include #include diff --git a/drivers/usb/input/hid-plff.c b/drivers/usb/input/hid-plff.c new file mode 100644 index 0000000..76d2e6e --- /dev/null +++ b/drivers/usb/input/hid-plff.c @@ -0,0 +1,129 @@ +/* + * Force feedback support for PantherLord USB/PS2 2in1 Adapter devices + * + * Copyright (c) 2007 Anssi Hannula + */ + +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + + +/* #define DEBUG */ + +#define debug(format, arg...) pr_debug("hid-plff: " format "\n" , ## arg) + +#include +#include +#include +#include "usbhid.h" + +struct plff_device { + struct hid_report *report; +}; + +static int hid_plff_play(struct input_dev *dev, void *data, + struct ff_effect *effect) +{ + struct hid_device *hid = dev->private; + struct plff_device *plff = data; + int left, right; + + left = effect->u.rumble.strong_magnitude; + right = effect->u.rumble.weak_magnitude; + debug("called with 0x%04x 0x%04x", left, right); + + left = left * 0x7f / 0xffff; + right = right * 0x7f / 0xffff; + + plff->report->field[0]->value[2] = left; + plff->report->field[0]->value[3] = right; + debug("running with 0x%02x 0x%02x", left, right); + usbhid_submit_report(hid, plff->report, USB_DIR_OUT); + + return 0; +} + +int hid_plff_init(struct hid_device *hid) +{ + struct plff_device *plff; + struct hid_report *report; + struct hid_input *hidinput; + struct list_head *report_list = + &hid->report_enum[HID_OUTPUT_REPORT].report_list; + struct list_head *report_ptr = report_list; + struct input_dev *dev; + int error; + + /* The device contains 2 output reports (one for each + HID_QUIRK_MULTI_INPUT device), both containing 1 field, which + contains 4 ff00.0002 usages and 4 16bit absolute values. + + The 2 input reports also contain a field which contains + 8 ff00.0001 usages and 8 boolean values. Their meaning is + currently unknown. */ + + if (list_empty(report_list)) { + printk(KERN_ERR "hid-plff: no output reports found\n"); + return -ENODEV; + } + + list_for_each_entry(hidinput, &hid->inputs, list) { + + report_ptr = report_ptr->next; + + if (report_ptr == report_list) { + printk(KERN_ERR "hid-plff: required output report is missing\n"); + return -ENODEV; + } + + report = list_entry(report_ptr, struct hid_report, list); + if (report->maxfield < 1) { + printk(KERN_ERR "hid-plff: no fields in the report\n"); + return -ENODEV; + } + + if (report->field[0]->report_count < 4) { + printk(KERN_ERR "hid-plff: not enough values in the field\n"); + return -ENODEV; + } + + plff = kzalloc(sizeof(struct plff_device), GFP_KERNEL); + if (!plff) + return -ENOMEM; + + dev = hidinput->input; + + set_bit(FF_RUMBLE, dev->ffbit); + + error = input_ff_create_memless(dev, plff, hid_plff_play); + if (error) { + kfree(plff); + return error; + } + + plff->report = report; + plff->report->field[0]->value[0] = 0x00; + plff->report->field[0]->value[1] = 0x00; + plff->report->field[0]->value[2] = 0x00; + plff->report->field[0]->value[3] = 0x00; + usbhid_submit_report(hid, plff->report, USB_DIR_OUT); + } + + printk(KERN_INFO "hid-plff: Force feedback for PantherLord USB/PS2 " + "2in1 Adapters by Anssi Hannula \n"); + + return 0; +} diff --git a/drivers/usb/misc/adutux.c b/drivers/usb/misc/adutux.c index af2934e..75bfab9 100644 --- a/drivers/usb/misc/adutux.c +++ b/drivers/usb/misc/adutux.c @@ -644,7 +644,7 @@ exit: } /* file operations needed when we register this driver */ -static struct file_operations adu_fops = { +static const struct file_operations adu_fops = { .owner = THIS_MODULE, .read = adu_read, .write = adu_write, diff --git a/drivers/usb/misc/appledisplay.c b/drivers/usb/misc/appledisplay.c index a7932a7..32f0e3a 100644 --- a/drivers/usb/misc/appledisplay.c +++ b/drivers/usb/misc/appledisplay.c @@ -281,8 +281,8 @@ static int appledisplay_probe(struct usb /* Register backlight device */ snprintf(bl_name, sizeof(bl_name), "appledisplay%d", atomic_inc_return(&count_displays) - 1); - pdata->bd = backlight_device_register(bl_name, NULL, NULL, - &appledisplay_bl_data); + pdata->bd = backlight_device_register(bl_name, NULL, + pdata, &appledisplay_bl_data); if (IS_ERR(pdata->bd)) { err("appledisplay: Backlight registration failed"); goto error; diff --git a/drivers/usb/misc/ftdi-elan.c b/drivers/usb/misc/ftdi-elan.c index 41c0161..0c1d66d 100644 --- a/drivers/usb/misc/ftdi-elan.c +++ b/drivers/usb/misc/ftdi-elan.c @@ -1209,7 +1209,7 @@ error_1: return retval; } -static struct file_operations ftdi_elan_fops = { +static const struct file_operations ftdi_elan_fops = { .owner = THIS_MODULE, .llseek = no_llseek, .ioctl = ftdi_elan_ioctl, diff --git a/drivers/usb/misc/idmouse.c b/drivers/usb/misc/idmouse.c index c941853..15c70bd 100644 --- a/drivers/usb/misc/idmouse.c +++ b/drivers/usb/misc/idmouse.c @@ -269,7 +269,7 @@ static int idmouse_release(struct inode /* prevent a race condition with open() */ mutex_lock(&disconnect_mutex); - dev = (struct usb_idmouse *) file->private_data; + dev = file->private_data; if (dev == NULL) { mutex_unlock(&disconnect_mutex); @@ -304,17 +304,15 @@ static int idmouse_release(struct inode static ssize_t idmouse_read(struct file *file, char __user *buffer, size_t count, loff_t * ppos) { - struct usb_idmouse *dev; + struct usb_idmouse *dev = file->private_data; int result; - dev = (struct usb_idmouse *) file->private_data; - /* lock this object */ - down (&dev->sem); + down(&dev->sem); /* verify that the device wasn't unplugged */ if (!dev->present) { - up (&dev->sem); + up(&dev->sem); return -ENODEV; } diff --git a/drivers/usb/misc/rio500.c b/drivers/usb/misc/rio500.c index 384fa37..fdf6847 100644 --- a/drivers/usb/misc/rio500.c +++ b/drivers/usb/misc/rio500.c @@ -69,7 +69,7 @@ struct rio_usb_data { char *obuf, *ibuf; /* transfer buffers */ char bulk_in_ep, bulk_out_ep; /* Endpoint assignments */ wait_queue_head_t wait_q; /* for timeouts */ - struct semaphore lock; /* general race avoidance */ + struct mutex lock; /* general race avoidance */ }; static struct rio_usb_data rio_instance; @@ -78,17 +78,17 @@ static int open_rio(struct inode *inode, { struct rio_usb_data *rio = &rio_instance; - down(&(rio->lock)); + mutex_lock(&(rio->lock)); if (rio->isopen || !rio->present) { - up(&(rio->lock)); + mutex_unlock(&(rio->lock)); return -EBUSY; } rio->isopen = 1; init_waitqueue_head(&rio->wait_q); - up(&(rio->lock)); + mutex_unlock(&(rio->lock)); info("Rio opened."); @@ -117,7 +117,7 @@ ioctl_rio(struct inode *inode, struct fi int retries; int retval=0; - down(&(rio->lock)); + mutex_lock(&(rio->lock)); /* Sanity check to make sure rio is connected, powered, etc */ if ( rio == NULL || rio->present == 0 || @@ -257,7 +257,7 @@ ioctl_rio(struct inode *inode, struct fi err_out: - up(&(rio->lock)); + mutex_unlock(&(rio->lock)); return retval; } @@ -275,14 +275,17 @@ write_rio(struct file *file, const char int result = 0; int maxretry; int errn = 0; + int intr; - down(&(rio->lock)); + intr = mutex_lock_interruptible(&(rio->lock)); + if (intr) + return -EINTR; /* Sanity check to make sure rio is connected, powered, etc */ if ( rio == NULL || rio->present == 0 || rio->rio_dev == NULL ) { - up(&(rio->lock)); + mutex_unlock(&(rio->lock)); return -ENODEV; } @@ -305,7 +308,7 @@ write_rio(struct file *file, const char goto error; } if (signal_pending(current)) { - up(&(rio->lock)); + mutex_unlock(&(rio->lock)); return bytes_written ? bytes_written : -EINTR; } @@ -341,12 +344,12 @@ write_rio(struct file *file, const char buffer += copy_size; } while (count > 0); - up(&(rio->lock)); + mutex_unlock(&(rio->lock)); return bytes_written ? bytes_written : -EIO; error: - up(&(rio->lock)); + mutex_unlock(&(rio->lock)); return errn; } @@ -361,14 +364,17 @@ read_rio(struct file *file, char __user int result; int maxretry = 10; char *ibuf; + int intr; - down(&(rio->lock)); + intr = mutex_lock_interruptible(&(rio->lock)); + if (intr) + return -EINTR; /* Sanity check to make sure rio is connected, powered, etc */ if ( rio == NULL || rio->present == 0 || rio->rio_dev == NULL ) { - up(&(rio->lock)); + mutex_unlock(&(rio->lock)); return -ENODEV; } @@ -379,11 +385,11 @@ read_rio(struct file *file, char __user while (count > 0) { if (signal_pending(current)) { - up(&(rio->lock)); + mutex_unlock(&(rio->lock)); return read_count ? read_count : -EINTR; } if (!rio->rio_dev) { - up(&(rio->lock)); + mutex_unlock(&(rio->lock)); return -ENODEV; } this_read = (count >= IBUF_SIZE) ? IBUF_SIZE : count; @@ -400,7 +406,7 @@ read_rio(struct file *file, char __user count = this_read = partial; } else if (result == -ETIMEDOUT || result == 15) { /* FIXME: 15 ??? */ if (!maxretry--) { - up(&(rio->lock)); + mutex_unlock(&(rio->lock)); err("read_rio: maxretry timeout"); return -ETIME; } @@ -409,18 +415,18 @@ read_rio(struct file *file, char __user finish_wait(&rio->wait_q, &wait); continue; } else if (result != -EREMOTEIO) { - up(&(rio->lock)); + mutex_unlock(&(rio->lock)); err("Read Whoops - result:%u partial:%u this_read:%u", result, partial, this_read); return -EIO; } else { - up(&(rio->lock)); + mutex_unlock(&(rio->lock)); return (0); } if (this_read) { if (copy_to_user(buffer, ibuf, this_read)) { - up(&(rio->lock)); + mutex_unlock(&(rio->lock)); return -EFAULT; } count -= this_read; @@ -428,7 +434,7 @@ read_rio(struct file *file, char __user buffer += this_read; } } - up(&(rio->lock)); + mutex_unlock(&(rio->lock)); return read_count; } @@ -480,7 +486,7 @@ static int probe_rio(struct usb_interfac } dbg("probe_rio: ibuf address:%p", rio->ibuf); - init_MUTEX(&(rio->lock)); + mutex_init(&(rio->lock)); usb_set_intfdata (intf, rio); rio->present = 1; @@ -496,12 +502,12 @@ static void disconnect_rio(struct usb_in if (rio) { usb_deregister_dev(intf, &usb_rio_class); - down(&(rio->lock)); + mutex_lock(&(rio->lock)); if (rio->isopen) { rio->isopen = 0; /* better let it finish - the release will do whats needed */ rio->rio_dev = NULL; - up(&(rio->lock)); + mutex_unlock(&(rio->lock)); return; } kfree(rio->ibuf); @@ -510,7 +516,7 @@ static void disconnect_rio(struct usb_in info("USB Rio disconnected."); rio->present = 0; - up(&(rio->lock)); + mutex_unlock(&(rio->lock)); } } diff --git a/drivers/usb/misc/sisusbvga/sisusb.c b/drivers/usb/misc/sisusbvga/sisusb.c index 0398908..6f8b134 100644 --- a/drivers/usb/misc/sisusbvga/sisusb.c +++ b/drivers/usb/misc/sisusbvga/sisusb.c @@ -40,7 +40,6 @@ #include #include #include #include -#include #include #include #include diff --git a/drivers/usb/misc/sisusbvga/sisusb_con.c b/drivers/usb/misc/sisusbvga/sisusb_con.c index 9148694..1730d86 100644 --- a/drivers/usb/misc/sisusbvga/sisusb_con.c +++ b/drivers/usb/misc/sisusbvga/sisusb_con.c @@ -51,7 +51,6 @@ #include #include #include #include -#include #include #include #include diff --git a/drivers/usb/mon/Makefile b/drivers/usb/mon/Makefile index 3cf3ea3..90c5953 100644 --- a/drivers/usb/mon/Makefile +++ b/drivers/usb/mon/Makefile @@ -2,7 +2,7 @@ # # Makefile for USB Core files and filesystem # -usbmon-objs := mon_main.o mon_stat.o mon_text.o mon_dma.o +usbmon-objs := mon_main.o mon_stat.o mon_text.o mon_bin.o mon_dma.o # This does not use CONFIG_USB_MON because we want this to use a tristate. obj-$(CONFIG_USB) += usbmon.o diff --git a/drivers/usb/mon/mon_bin.c b/drivers/usb/mon/mon_bin.c new file mode 100644 index 0000000..c01dfe6 --- /dev/null +++ b/drivers/usb/mon/mon_bin.c @@ -0,0 +1,1172 @@ +/* + * The USB Monitor, inspired by Dave Harding's USBMon. + * + * This is a binary format reader. + * + * Copyright (C) 2006 Paolo Abeni (paolo.abeni@email.it) + * Copyright (C) 2006 Pete Zaitcev (zaitcev@redhat.com) + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "usb_mon.h" + +/* + * Defined by USB 2.0 clause 9.3, table 9.2. + */ +#define SETUP_LEN 8 + +/* ioctl macros */ +#define MON_IOC_MAGIC 0x92 + +#define MON_IOCQ_URB_LEN _IO(MON_IOC_MAGIC, 1) +/* #2 used to be MON_IOCX_URB, removed before it got into Linus tree */ +#define MON_IOCG_STATS _IOR(MON_IOC_MAGIC, 3, struct mon_bin_stats) +#define MON_IOCT_RING_SIZE _IO(MON_IOC_MAGIC, 4) +#define MON_IOCQ_RING_SIZE _IO(MON_IOC_MAGIC, 5) +#define MON_IOCX_GET _IOW(MON_IOC_MAGIC, 6, struct mon_bin_get) +#define MON_IOCX_MFETCH _IOWR(MON_IOC_MAGIC, 7, struct mon_bin_mfetch) +#define MON_IOCH_MFLUSH _IO(MON_IOC_MAGIC, 8) +#ifdef CONFIG_COMPAT +#define MON_IOCX_GET32 _IOW(MON_IOC_MAGIC, 6, struct mon_bin_get32) +#define MON_IOCX_MFETCH32 _IOWR(MON_IOC_MAGIC, 7, struct mon_bin_mfetch32) +#endif + +/* + * Some architectures have enormous basic pages (16KB for ia64, 64KB for ppc). + * But it's all right. Just use a simple way to make sure the chunk is never + * smaller than a page. + * + * N.B. An application does not know our chunk size. + * + * Woops, get_zeroed_page() returns a single page. I guess we're stuck with + * page-sized chunks for the time being. + */ +#define CHUNK_SIZE PAGE_SIZE +#define CHUNK_ALIGN(x) (((x)+CHUNK_SIZE-1) & ~(CHUNK_SIZE-1)) + +/* + * The magic limit was calculated so that it allows the monitoring + * application to pick data once in two ticks. This way, another application, + * which presumably drives the bus, gets to hog CPU, yet we collect our data. + * If HZ is 100, a 480 mbit/s bus drives 614 KB every jiffy. USB has an + * enormous overhead built into the bus protocol, so we need about 1000 KB. + * + * This is still too much for most cases, where we just snoop a few + * descriptor fetches for enumeration. So, the default is a "reasonable" + * amount for systems with HZ=250 and incomplete bus saturation. + * + * XXX What about multi-megabyte URBs which take minutes to transfer? + */ +#define BUFF_MAX CHUNK_ALIGN(1200*1024) +#define BUFF_DFL CHUNK_ALIGN(300*1024) +#define BUFF_MIN CHUNK_ALIGN(8*1024) + +/* + * The per-event API header (2 per URB). + * + * This structure is seen in userland as defined by the documentation. + */ +struct mon_bin_hdr { + u64 id; /* URB ID - from submission to callback */ + unsigned char type; /* Same as in text API; extensible. */ + unsigned char xfer_type; /* ISO, Intr, Control, Bulk */ + unsigned char epnum; /* Endpoint number and transfer direction */ + unsigned char devnum; /* Device address */ + unsigned short busnum; /* Bus number */ + char flag_setup; + char flag_data; + s64 ts_sec; /* gettimeofday */ + s32 ts_usec; /* gettimeofday */ + int status; + unsigned int len_urb; /* Length of data (submitted or actual) */ + unsigned int len_cap; /* Delivered length */ + unsigned char setup[SETUP_LEN]; /* Only for Control S-type */ +}; + +/* per file statistic */ +struct mon_bin_stats { + u32 queued; + u32 dropped; +}; + +struct mon_bin_get { + struct mon_bin_hdr __user *hdr; /* Only 48 bytes, not 64. */ + void __user *data; + size_t alloc; /* Length of data (can be zero) */ +}; + +struct mon_bin_mfetch { + u32 __user *offvec; /* Vector of events fetched */ + u32 nfetch; /* Number of events to fetch (out: fetched) */ + u32 nflush; /* Number of events to flush */ +}; + +#ifdef CONFIG_COMPAT +struct mon_bin_get32 { + u32 hdr32; + u32 data32; + u32 alloc32; +}; + +struct mon_bin_mfetch32 { + u32 offvec32; + u32 nfetch32; + u32 nflush32; +}; +#endif + +/* Having these two values same prevents wrapping of the mon_bin_hdr */ +#define PKT_ALIGN 64 +#define PKT_SIZE 64 + +/* max number of USB bus supported */ +#define MON_BIN_MAX_MINOR 128 + +/* + * The buffer: map of used pages. + */ +struct mon_pgmap { + struct page *pg; + unsigned char *ptr; /* XXX just use page_to_virt everywhere? */ +}; + +/* + * This gets associated with an open file struct. + */ +struct mon_reader_bin { + /* The buffer: one per open. */ + spinlock_t b_lock; /* Protect b_cnt, b_in */ + unsigned int b_size; /* Current size of the buffer - bytes */ + unsigned int b_cnt; /* Bytes used */ + unsigned int b_in, b_out; /* Offsets into buffer - bytes */ + unsigned int b_read; /* Amount of read data in curr. pkt. */ + struct mon_pgmap *b_vec; /* The map array */ + wait_queue_head_t b_wait; /* Wait for data here */ + + struct mutex fetch_lock; /* Protect b_read, b_out */ + int mmap_active; + + /* A list of these is needed for "bus 0". Some time later. */ + struct mon_reader r; + + /* Stats */ + unsigned int cnt_lost; +}; + +static inline struct mon_bin_hdr *MON_OFF2HDR(const struct mon_reader_bin *rp, + unsigned int offset) +{ + return (struct mon_bin_hdr *) + (rp->b_vec[offset / CHUNK_SIZE].ptr + offset % CHUNK_SIZE); +} + +#define MON_RING_EMPTY(rp) ((rp)->b_cnt == 0) + +static dev_t mon_bin_dev0; +static struct cdev mon_bin_cdev; + +static void mon_buff_area_fill(const struct mon_reader_bin *rp, + unsigned int offset, unsigned int size); +static int mon_bin_wait_event(struct file *file, struct mon_reader_bin *rp); +static int mon_alloc_buff(struct mon_pgmap *map, int npages); +static void mon_free_buff(struct mon_pgmap *map, int npages); + +/* + * This is a "chunked memcpy". It does not manipulate any counters. + * But it returns the new offset for repeated application. + */ +unsigned int mon_copy_to_buff(const struct mon_reader_bin *this, + unsigned int off, const unsigned char *from, unsigned int length) +{ + unsigned int step_len; + unsigned char *buf; + unsigned int in_page; + + while (length) { + /* + * Determine step_len. + */ + step_len = length; + in_page = CHUNK_SIZE - (off & (CHUNK_SIZE-1)); + if (in_page < step_len) + step_len = in_page; + + /* + * Copy data and advance pointers. + */ + buf = this->b_vec[off / CHUNK_SIZE].ptr + off % CHUNK_SIZE; + memcpy(buf, from, step_len); + if ((off += step_len) >= this->b_size) off = 0; + from += step_len; + length -= step_len; + } + return off; +} + +/* + * This is a little worse than the above because it's "chunked copy_to_user". + * The return value is an error code, not an offset. + */ +static int copy_from_buf(const struct mon_reader_bin *this, unsigned int off, + char __user *to, int length) +{ + unsigned int step_len; + unsigned char *buf; + unsigned int in_page; + + while (length) { + /* + * Determine step_len. + */ + step_len = length; + in_page = CHUNK_SIZE - (off & (CHUNK_SIZE-1)); + if (in_page < step_len) + step_len = in_page; + + /* + * Copy data and advance pointers. + */ + buf = this->b_vec[off / CHUNK_SIZE].ptr + off % CHUNK_SIZE; + if (copy_to_user(to, buf, step_len)) + return -EINVAL; + if ((off += step_len) >= this->b_size) off = 0; + to += step_len; + length -= step_len; + } + return 0; +} + +/* + * Allocate an (aligned) area in the buffer. + * This is called under b_lock. + * Returns ~0 on failure. + */ +static unsigned int mon_buff_area_alloc(struct mon_reader_bin *rp, + unsigned int size) +{ + unsigned int offset; + + size = (size + PKT_ALIGN-1) & ~(PKT_ALIGN-1); + if (rp->b_cnt + size > rp->b_size) + return ~0; + offset = rp->b_in; + rp->b_cnt += size; + if ((rp->b_in += size) >= rp->b_size) + rp->b_in -= rp->b_size; + return offset; +} + +/* + * This is the same thing as mon_buff_area_alloc, only it does not allow + * buffers to wrap. This is needed by applications which pass references + * into mmap-ed buffers up their stacks (libpcap can do that). + * + * Currently, we always have the header stuck with the data, although + * it is not strictly speaking necessary. + * + * When a buffer would wrap, we place a filler packet to mark the space. + */ +static unsigned int mon_buff_area_alloc_contiguous(struct mon_reader_bin *rp, + unsigned int size) +{ + unsigned int offset; + unsigned int fill_size; + + size = (size + PKT_ALIGN-1) & ~(PKT_ALIGN-1); + if (rp->b_cnt + size > rp->b_size) + return ~0; + if (rp->b_in + size > rp->b_size) { + /* + * This would wrap. Find if we still have space after + * skipping to the end of the buffer. If we do, place + * a filler packet and allocate a new packet. + */ + fill_size = rp->b_size - rp->b_in; + if (rp->b_cnt + size + fill_size > rp->b_size) + return ~0; + mon_buff_area_fill(rp, rp->b_in, fill_size); + + offset = 0; + rp->b_in = size; + rp->b_cnt += size + fill_size; + } else if (rp->b_in + size == rp->b_size) { + offset = rp->b_in; + rp->b_in = 0; + rp->b_cnt += size; + } else { + offset = rp->b_in; + rp->b_in += size; + rp->b_cnt += size; + } + return offset; +} + +/* + * Return a few (kilo-)bytes to the head of the buffer. + * This is used if a DMA fetch fails. + */ +static void mon_buff_area_shrink(struct mon_reader_bin *rp, unsigned int size) +{ + + size = (size + PKT_ALIGN-1) & ~(PKT_ALIGN-1); + rp->b_cnt -= size; + if (rp->b_in < size) + rp->b_in += rp->b_size; + rp->b_in -= size; +} + +/* + * This has to be called under both b_lock and fetch_lock, because + * it accesses both b_cnt and b_out. + */ +static void mon_buff_area_free(struct mon_reader_bin *rp, unsigned int size) +{ + + size = (size + PKT_ALIGN-1) & ~(PKT_ALIGN-1); + rp->b_cnt -= size; + if ((rp->b_out += size) >= rp->b_size) + rp->b_out -= rp->b_size; +} + +static void mon_buff_area_fill(const struct mon_reader_bin *rp, + unsigned int offset, unsigned int size) +{ + struct mon_bin_hdr *ep; + + ep = MON_OFF2HDR(rp, offset); + memset(ep, 0, PKT_SIZE); + ep->type = '@'; + ep->len_cap = size - PKT_SIZE; +} + +static inline char mon_bin_get_setup(unsigned char *setupb, + const struct urb *urb, char ev_type) +{ + + if (!usb_pipecontrol(urb->pipe) || ev_type != 'S') + return '-'; + + if (urb->transfer_flags & URB_NO_SETUP_DMA_MAP) + return mon_dmapeek(setupb, urb->setup_dma, SETUP_LEN); + if (urb->setup_packet == NULL) + return 'Z'; + + memcpy(setupb, urb->setup_packet, SETUP_LEN); + return 0; +} + +static char mon_bin_get_data(const struct mon_reader_bin *rp, + unsigned int offset, struct urb *urb, unsigned int length) +{ + + if (urb->transfer_flags & URB_NO_TRANSFER_DMA_MAP) { + mon_dmapeek_vec(rp, offset, urb->transfer_dma, length); + return 0; + } + + if (urb->transfer_buffer == NULL) + return 'Z'; + + mon_copy_to_buff(rp, offset, urb->transfer_buffer, length); + return 0; +} + +static void mon_bin_event(struct mon_reader_bin *rp, struct urb *urb, + char ev_type) +{ + unsigned long flags; + struct timeval ts; + unsigned int urb_length; + unsigned int offset; + unsigned int length; + struct mon_bin_hdr *ep; + char data_tag = 0; + + do_gettimeofday(&ts); + + spin_lock_irqsave(&rp->b_lock, flags); + + /* + * Find the maximum allowable length, then allocate space. + */ + urb_length = (ev_type == 'S') ? + urb->transfer_buffer_length : urb->actual_length; + length = urb_length; + + if (length >= rp->b_size/5) + length = rp->b_size/5; + + if (usb_pipein(urb->pipe)) { + if (ev_type == 'S') { + length = 0; + data_tag = '<'; + } + } else { + if (ev_type == 'C') { + length = 0; + data_tag = '>'; + } + } + + if (rp->mmap_active) + offset = mon_buff_area_alloc_contiguous(rp, length + PKT_SIZE); + else + offset = mon_buff_area_alloc(rp, length + PKT_SIZE); + if (offset == ~0) { + rp->cnt_lost++; + spin_unlock_irqrestore(&rp->b_lock, flags); + return; + } + + ep = MON_OFF2HDR(rp, offset); + if ((offset += PKT_SIZE) >= rp->b_size) offset = 0; + + /* + * Fill the allocated area. + */ + memset(ep, 0, PKT_SIZE); + ep->type = ev_type; + ep->xfer_type = usb_pipetype(urb->pipe); + /* We use the fact that usb_pipein() returns 0x80 */ + ep->epnum = usb_pipeendpoint(urb->pipe) | usb_pipein(urb->pipe); + ep->devnum = usb_pipedevice(urb->pipe); + ep->busnum = rp->r.m_bus->u_bus->busnum; + ep->id = (unsigned long) urb; + ep->ts_sec = ts.tv_sec; + ep->ts_usec = ts.tv_usec; + ep->status = urb->status; + ep->len_urb = urb_length; + ep->len_cap = length; + + ep->flag_setup = mon_bin_get_setup(ep->setup, urb, ev_type); + if (length != 0) { + ep->flag_data = mon_bin_get_data(rp, offset, urb, length); + if (ep->flag_data != 0) { /* Yes, it's 0x00, not '0' */ + ep->len_cap = 0; + mon_buff_area_shrink(rp, length); + } + } else { + ep->flag_data = data_tag; + } + + spin_unlock_irqrestore(&rp->b_lock, flags); + + wake_up(&rp->b_wait); +} + +static void mon_bin_submit(void *data, struct urb *urb) +{ + struct mon_reader_bin *rp = data; + mon_bin_event(rp, urb, 'S'); +} + +static void mon_bin_complete(void *data, struct urb *urb) +{ + struct mon_reader_bin *rp = data; + mon_bin_event(rp, urb, 'C'); +} + +static void mon_bin_error(void *data, struct urb *urb, int error) +{ + struct mon_reader_bin *rp = data; + unsigned long flags; + unsigned int offset; + struct mon_bin_hdr *ep; + + spin_lock_irqsave(&rp->b_lock, flags); + + offset = mon_buff_area_alloc(rp, PKT_SIZE); + if (offset == ~0) { + /* Not incrementing cnt_lost. Just because. */ + spin_unlock_irqrestore(&rp->b_lock, flags); + return; + } + + ep = MON_OFF2HDR(rp, offset); + + memset(ep, 0, PKT_SIZE); + ep->type = 'E'; + ep->xfer_type = usb_pipetype(urb->pipe); + /* We use the fact that usb_pipein() returns 0x80 */ + ep->epnum = usb_pipeendpoint(urb->pipe) | usb_pipein(urb->pipe); + ep->devnum = usb_pipedevice(urb->pipe); + ep->busnum = rp->r.m_bus->u_bus->busnum; + ep->id = (unsigned long) urb; + ep->status = error; + + ep->flag_setup = '-'; + ep->flag_data = 'E'; + + spin_unlock_irqrestore(&rp->b_lock, flags); + + wake_up(&rp->b_wait); +} + +static int mon_bin_open(struct inode *inode, struct file *file) +{ + struct mon_bus *mbus; + struct usb_bus *ubus; + struct mon_reader_bin *rp; + size_t size; + int rc; + + mutex_lock(&mon_lock); + if ((mbus = mon_bus_lookup(iminor(inode))) == NULL) { + mutex_unlock(&mon_lock); + return -ENODEV; + } + if ((ubus = mbus->u_bus) == NULL) { + printk(KERN_ERR TAG ": consistency error on open\n"); + mutex_unlock(&mon_lock); + return -ENODEV; + } + + rp = kzalloc(sizeof(struct mon_reader_bin), GFP_KERNEL); + if (rp == NULL) { + rc = -ENOMEM; + goto err_alloc; + } + spin_lock_init(&rp->b_lock); + init_waitqueue_head(&rp->b_wait); + mutex_init(&rp->fetch_lock); + + rp->b_size = BUFF_DFL; + + size = sizeof(struct mon_pgmap) * (rp->b_size/CHUNK_SIZE); + if ((rp->b_vec = kzalloc(size, GFP_KERNEL)) == NULL) { + rc = -ENOMEM; + goto err_allocvec; + } + + if ((rc = mon_alloc_buff(rp->b_vec, rp->b_size/CHUNK_SIZE)) < 0) + goto err_allocbuff; + + rp->r.m_bus = mbus; + rp->r.r_data = rp; + rp->r.rnf_submit = mon_bin_submit; + rp->r.rnf_error = mon_bin_error; + rp->r.rnf_complete = mon_bin_complete; + + mon_reader_add(mbus, &rp->r); + + file->private_data = rp; + mutex_unlock(&mon_lock); + return 0; + +err_allocbuff: + kfree(rp->b_vec); +err_allocvec: + kfree(rp); +err_alloc: + mutex_unlock(&mon_lock); + return rc; +} + +/* + * Extract an event from buffer and copy it to user space. + * Wait if there is no event ready. + * Returns zero or error. + */ +static int mon_bin_get_event(struct file *file, struct mon_reader_bin *rp, + struct mon_bin_hdr __user *hdr, void __user *data, unsigned int nbytes) +{ + unsigned long flags; + struct mon_bin_hdr *ep; + size_t step_len; + unsigned int offset; + int rc; + + mutex_lock(&rp->fetch_lock); + + if ((rc = mon_bin_wait_event(file, rp)) < 0) { + mutex_unlock(&rp->fetch_lock); + return rc; + } + + ep = MON_OFF2HDR(rp, rp->b_out); + + if (copy_to_user(hdr, ep, sizeof(struct mon_bin_hdr))) { + mutex_unlock(&rp->fetch_lock); + return -EFAULT; + } + + step_len = min(ep->len_cap, nbytes); + if ((offset = rp->b_out + PKT_SIZE) >= rp->b_size) offset = 0; + + if (copy_from_buf(rp, offset, data, step_len)) { + mutex_unlock(&rp->fetch_lock); + return -EFAULT; + } + + spin_lock_irqsave(&rp->b_lock, flags); + mon_buff_area_free(rp, PKT_SIZE + ep->len_cap); + spin_unlock_irqrestore(&rp->b_lock, flags); + rp->b_read = 0; + + mutex_unlock(&rp->fetch_lock); + return 0; +} + +static int mon_bin_release(struct inode *inode, struct file *file) +{ + struct mon_reader_bin *rp = file->private_data; + struct mon_bus* mbus = rp->r.m_bus; + + mutex_lock(&mon_lock); + + if (mbus->nreaders <= 0) { + printk(KERN_ERR TAG ": consistency error on close\n"); + mutex_unlock(&mon_lock); + return 0; + } + mon_reader_del(mbus, &rp->r); + + mon_free_buff(rp->b_vec, rp->b_size/CHUNK_SIZE); + kfree(rp->b_vec); + kfree(rp); + + mutex_unlock(&mon_lock); + return 0; +} + +static ssize_t mon_bin_read(struct file *file, char __user *buf, + size_t nbytes, loff_t *ppos) +{ + struct mon_reader_bin *rp = file->private_data; + unsigned long flags; + struct mon_bin_hdr *ep; + unsigned int offset; + size_t step_len; + char *ptr; + ssize_t done = 0; + int rc; + + mutex_lock(&rp->fetch_lock); + + if ((rc = mon_bin_wait_event(file, rp)) < 0) { + mutex_unlock(&rp->fetch_lock); + return rc; + } + + ep = MON_OFF2HDR(rp, rp->b_out); + + if (rp->b_read < sizeof(struct mon_bin_hdr)) { + step_len = min(nbytes, sizeof(struct mon_bin_hdr) - rp->b_read); + ptr = ((char *)ep) + rp->b_read; + if (step_len && copy_to_user(buf, ptr, step_len)) { + mutex_unlock(&rp->fetch_lock); + return -EFAULT; + } + nbytes -= step_len; + buf += step_len; + rp->b_read += step_len; + done += step_len; + } + + if (rp->b_read >= sizeof(struct mon_bin_hdr)) { + step_len = min(nbytes, (size_t)ep->len_cap); + offset = rp->b_out + PKT_SIZE; + offset += rp->b_read - sizeof(struct mon_bin_hdr); + if (offset >= rp->b_size) + offset -= rp->b_size; + if (copy_from_buf(rp, offset, buf, step_len)) { + mutex_unlock(&rp->fetch_lock); + return -EFAULT; + } + nbytes -= step_len; + buf += step_len; + rp->b_read += step_len; + done += step_len; + } + + /* + * Check if whole packet was read, and if so, jump to the next one. + */ + if (rp->b_read >= sizeof(struct mon_bin_hdr) + ep->len_cap) { + spin_lock_irqsave(&rp->b_lock, flags); + mon_buff_area_free(rp, PKT_SIZE + ep->len_cap); + spin_unlock_irqrestore(&rp->b_lock, flags); + rp->b_read = 0; + } + + mutex_unlock(&rp->fetch_lock); + return done; +} + +/* + * Remove at most nevents from chunked buffer. + * Returns the number of removed events. + */ +static int mon_bin_flush(struct mon_reader_bin *rp, unsigned nevents) +{ + unsigned long flags; + struct mon_bin_hdr *ep; + int i; + + mutex_lock(&rp->fetch_lock); + spin_lock_irqsave(&rp->b_lock, flags); + for (i = 0; i < nevents; ++i) { + if (MON_RING_EMPTY(rp)) + break; + + ep = MON_OFF2HDR(rp, rp->b_out); + mon_buff_area_free(rp, PKT_SIZE + ep->len_cap); + } + spin_unlock_irqrestore(&rp->b_lock, flags); + rp->b_read = 0; + mutex_unlock(&rp->fetch_lock); + return i; +} + +/* + * Fetch at most max event offsets into the buffer and put them into vec. + * The events are usually freed later with mon_bin_flush. + * Return the effective number of events fetched. + */ +static int mon_bin_fetch(struct file *file, struct mon_reader_bin *rp, + u32 __user *vec, unsigned int max) +{ + unsigned int cur_out; + unsigned int bytes, avail; + unsigned int size; + unsigned int nevents; + struct mon_bin_hdr *ep; + unsigned long flags; + int rc; + + mutex_lock(&rp->fetch_lock); + + if ((rc = mon_bin_wait_event(file, rp)) < 0) { + mutex_unlock(&rp->fetch_lock); + return rc; + } + + spin_lock_irqsave(&rp->b_lock, flags); + avail = rp->b_cnt; + spin_unlock_irqrestore(&rp->b_lock, flags); + + cur_out = rp->b_out; + nevents = 0; + bytes = 0; + while (bytes < avail) { + if (nevents >= max) + break; + + ep = MON_OFF2HDR(rp, cur_out); + if (put_user(cur_out, &vec[nevents])) { + mutex_unlock(&rp->fetch_lock); + return -EFAULT; + } + + nevents++; + size = ep->len_cap + PKT_SIZE; + size = (size + PKT_ALIGN-1) & ~(PKT_ALIGN-1); + if ((cur_out += size) >= rp->b_size) + cur_out -= rp->b_size; + bytes += size; + } + + mutex_unlock(&rp->fetch_lock); + return nevents; +} + +/* + * Count events. This is almost the same as the above mon_bin_fetch, + * only we do not store offsets into user vector, and we have no limit. + */ +static int mon_bin_queued(struct mon_reader_bin *rp) +{ + unsigned int cur_out; + unsigned int bytes, avail; + unsigned int size; + unsigned int nevents; + struct mon_bin_hdr *ep; + unsigned long flags; + + mutex_lock(&rp->fetch_lock); + + spin_lock_irqsave(&rp->b_lock, flags); + avail = rp->b_cnt; + spin_unlock_irqrestore(&rp->b_lock, flags); + + cur_out = rp->b_out; + nevents = 0; + bytes = 0; + while (bytes < avail) { + ep = MON_OFF2HDR(rp, cur_out); + + nevents++; + size = ep->len_cap + PKT_SIZE; + size = (size + PKT_ALIGN-1) & ~(PKT_ALIGN-1); + if ((cur_out += size) >= rp->b_size) + cur_out -= rp->b_size; + bytes += size; + } + + mutex_unlock(&rp->fetch_lock); + return nevents; +} + +/* + */ +static int mon_bin_ioctl(struct inode *inode, struct file *file, + unsigned int cmd, unsigned long arg) +{ + struct mon_reader_bin *rp = file->private_data; + // struct mon_bus* mbus = rp->r.m_bus; + int ret = 0; + struct mon_bin_hdr *ep; + unsigned long flags; + + switch (cmd) { + + case MON_IOCQ_URB_LEN: + /* + * N.B. This only returns the size of data, without the header. + */ + spin_lock_irqsave(&rp->b_lock, flags); + if (!MON_RING_EMPTY(rp)) { + ep = MON_OFF2HDR(rp, rp->b_out); + ret = ep->len_cap; + } + spin_unlock_irqrestore(&rp->b_lock, flags); + break; + + case MON_IOCQ_RING_SIZE: + ret = rp->b_size; + break; + + case MON_IOCT_RING_SIZE: + /* + * Changing the buffer size will flush it's contents; the new + * buffer is allocated before releasing the old one to be sure + * the device will stay functional also in case of memory + * pressure. + */ + { + int size; + struct mon_pgmap *vec; + + if (arg < BUFF_MIN || arg > BUFF_MAX) + return -EINVAL; + + size = CHUNK_ALIGN(arg); + if ((vec = kzalloc(sizeof(struct mon_pgmap) * (size/CHUNK_SIZE), + GFP_KERNEL)) == NULL) { + ret = -ENOMEM; + break; + } + + ret = mon_alloc_buff(vec, size/CHUNK_SIZE); + if (ret < 0) { + kfree(vec); + break; + } + + mutex_lock(&rp->fetch_lock); + spin_lock_irqsave(&rp->b_lock, flags); + mon_free_buff(rp->b_vec, size/CHUNK_SIZE); + kfree(rp->b_vec); + rp->b_vec = vec; + rp->b_size = size; + rp->b_read = rp->b_in = rp->b_out = rp->b_cnt = 0; + rp->cnt_lost = 0; + spin_unlock_irqrestore(&rp->b_lock, flags); + mutex_unlock(&rp->fetch_lock); + } + break; + + case MON_IOCH_MFLUSH: + ret = mon_bin_flush(rp, arg); + break; + + case MON_IOCX_GET: + { + struct mon_bin_get getb; + + if (copy_from_user(&getb, (void __user *)arg, + sizeof(struct mon_bin_get))) + return -EFAULT; + + if (getb.alloc > 0x10000000) /* Want to cast to u32 */ + return -EINVAL; + ret = mon_bin_get_event(file, rp, + getb.hdr, getb.data, (unsigned int)getb.alloc); + } + break; + +#ifdef CONFIG_COMPAT + case MON_IOCX_GET32: { + struct mon_bin_get32 getb; + + if (copy_from_user(&getb, (void __user *)arg, + sizeof(struct mon_bin_get32))) + return -EFAULT; + + ret = mon_bin_get_event(file, rp, + compat_ptr(getb.hdr32), compat_ptr(getb.data32), + getb.alloc32); + } + break; +#endif + + case MON_IOCX_MFETCH: + { + struct mon_bin_mfetch mfetch; + struct mon_bin_mfetch __user *uptr; + + uptr = (struct mon_bin_mfetch __user *)arg; + + if (copy_from_user(&mfetch, uptr, sizeof(mfetch))) + return -EFAULT; + + if (mfetch.nflush) { + ret = mon_bin_flush(rp, mfetch.nflush); + if (ret < 0) + return ret; + if (put_user(ret, &uptr->nflush)) + return -EFAULT; + } + ret = mon_bin_fetch(file, rp, mfetch.offvec, mfetch.nfetch); + if (ret < 0) + return ret; + if (put_user(ret, &uptr->nfetch)) + return -EFAULT; + ret = 0; + } + break; + +#ifdef CONFIG_COMPAT + case MON_IOCX_MFETCH32: + { + struct mon_bin_mfetch32 mfetch; + struct mon_bin_mfetch32 __user *uptr; + + uptr = (struct mon_bin_mfetch32 __user *) compat_ptr(arg); + + if (copy_from_user(&mfetch, uptr, sizeof(mfetch))) + return -EFAULT; + + if (mfetch.nflush32) { + ret = mon_bin_flush(rp, mfetch.nflush32); + if (ret < 0) + return ret; + if (put_user(ret, &uptr->nflush32)) + return -EFAULT; + } + ret = mon_bin_fetch(file, rp, compat_ptr(mfetch.offvec32), + mfetch.nfetch32); + if (ret < 0) + return ret; + if (put_user(ret, &uptr->nfetch32)) + return -EFAULT; + ret = 0; + } + break; +#endif + + case MON_IOCG_STATS: { + struct mon_bin_stats __user *sp; + unsigned int nevents; + unsigned int ndropped; + + spin_lock_irqsave(&rp->b_lock, flags); + ndropped = rp->cnt_lost; + rp->cnt_lost = 0; + spin_unlock_irqrestore(&rp->b_lock, flags); + nevents = mon_bin_queued(rp); + + sp = (struct mon_bin_stats __user *)arg; + if (put_user(rp->cnt_lost, &sp->dropped)) + return -EFAULT; + if (put_user(nevents, &sp->queued)) + return -EFAULT; + + } + break; + + default: + return -ENOTTY; + } + + return ret; +} + +static unsigned int +mon_bin_poll(struct file *file, struct poll_table_struct *wait) +{ + struct mon_reader_bin *rp = file->private_data; + unsigned int mask = 0; + unsigned long flags; + + if (file->f_mode & FMODE_READ) + poll_wait(file, &rp->b_wait, wait); + + spin_lock_irqsave(&rp->b_lock, flags); + if (!MON_RING_EMPTY(rp)) + mask |= POLLIN | POLLRDNORM; /* readable */ + spin_unlock_irqrestore(&rp->b_lock, flags); + return mask; +} + +/* + * open and close: just keep track of how many times the device is + * mapped, to use the proper memory allocation function. + */ +static void mon_bin_vma_open(struct vm_area_struct *vma) +{ + struct mon_reader_bin *rp = vma->vm_private_data; + rp->mmap_active++; +} + +static void mon_bin_vma_close(struct vm_area_struct *vma) +{ + struct mon_reader_bin *rp = vma->vm_private_data; + rp->mmap_active--; +} + +/* + * Map ring pages to user space. + */ +struct page *mon_bin_vma_nopage(struct vm_area_struct *vma, + unsigned long address, int *type) +{ + struct mon_reader_bin *rp = vma->vm_private_data; + unsigned long offset, chunk_idx; + struct page *pageptr; + + offset = (address - vma->vm_start) + (vma->vm_pgoff << PAGE_SHIFT); + if (offset >= rp->b_size) + return NOPAGE_SIGBUS; + chunk_idx = offset / CHUNK_SIZE; + pageptr = rp->b_vec[chunk_idx].pg; + get_page(pageptr); + if (type) + *type = VM_FAULT_MINOR; + return pageptr; +} + +struct vm_operations_struct mon_bin_vm_ops = { + .open = mon_bin_vma_open, + .close = mon_bin_vma_close, + .nopage = mon_bin_vma_nopage, +}; + +int mon_bin_mmap(struct file *filp, struct vm_area_struct *vma) +{ + /* don't do anything here: "nopage" will set up page table entries */ + vma->vm_ops = &mon_bin_vm_ops; + vma->vm_flags |= VM_RESERVED; + vma->vm_private_data = filp->private_data; + mon_bin_vma_open(vma); + return 0; +} + +struct file_operations mon_fops_binary = { + .owner = THIS_MODULE, + .open = mon_bin_open, + .llseek = no_llseek, + .read = mon_bin_read, + /* .write = mon_text_write, */ + .poll = mon_bin_poll, + .ioctl = mon_bin_ioctl, + .release = mon_bin_release, +}; + +static int mon_bin_wait_event(struct file *file, struct mon_reader_bin *rp) +{ + DECLARE_WAITQUEUE(waita, current); + unsigned long flags; + + add_wait_queue(&rp->b_wait, &waita); + set_current_state(TASK_INTERRUPTIBLE); + + spin_lock_irqsave(&rp->b_lock, flags); + while (MON_RING_EMPTY(rp)) { + spin_unlock_irqrestore(&rp->b_lock, flags); + + if (file->f_flags & O_NONBLOCK) { + set_current_state(TASK_RUNNING); + remove_wait_queue(&rp->b_wait, &waita); + return -EWOULDBLOCK; /* Same as EAGAIN in Linux */ + } + schedule(); + if (signal_pending(current)) { + remove_wait_queue(&rp->b_wait, &waita); + return -EINTR; + } + set_current_state(TASK_INTERRUPTIBLE); + + spin_lock_irqsave(&rp->b_lock, flags); + } + spin_unlock_irqrestore(&rp->b_lock, flags); + + set_current_state(TASK_RUNNING); + remove_wait_queue(&rp->b_wait, &waita); + return 0; +} + +static int mon_alloc_buff(struct mon_pgmap *map, int npages) +{ + int n; + unsigned long vaddr; + + for (n = 0; n < npages; n++) { + vaddr = get_zeroed_page(GFP_KERNEL); + if (vaddr == 0) { + while (n-- != 0) + free_page((unsigned long) map[n].ptr); + return -ENOMEM; + } + map[n].ptr = (unsigned char *) vaddr; + map[n].pg = virt_to_page(vaddr); + } + return 0; +} + +static void mon_free_buff(struct mon_pgmap *map, int npages) +{ + int n; + + for (n = 0; n < npages; n++) + free_page((unsigned long) map[n].ptr); +} + +int __init mon_bin_init(void) +{ + int rc; + + rc = alloc_chrdev_region(&mon_bin_dev0, 0, MON_BIN_MAX_MINOR, "usbmon"); + if (rc < 0) + goto err_dev; + + cdev_init(&mon_bin_cdev, &mon_fops_binary); + mon_bin_cdev.owner = THIS_MODULE; + + rc = cdev_add(&mon_bin_cdev, mon_bin_dev0, MON_BIN_MAX_MINOR); + if (rc < 0) + goto err_add; + + return 0; + +err_add: + unregister_chrdev_region(mon_bin_dev0, MON_BIN_MAX_MINOR); +err_dev: + return rc; +} + +void __exit mon_bin_exit(void) +{ + cdev_del(&mon_bin_cdev); + unregister_chrdev_region(mon_bin_dev0, MON_BIN_MAX_MINOR); +} diff --git a/drivers/usb/mon/mon_dma.c b/drivers/usb/mon/mon_dma.c index ddcfc01..140cc80 100644 --- a/drivers/usb/mon/mon_dma.c +++ b/drivers/usb/mon/mon_dma.c @@ -48,6 +48,36 @@ char mon_dmapeek(unsigned char *dst, dma local_irq_restore(flags); return 0; } + +void mon_dmapeek_vec(const struct mon_reader_bin *rp, + unsigned int offset, dma_addr_t dma_addr, unsigned int length) +{ + unsigned long flags; + unsigned int step_len; + struct page *pg; + unsigned char *map; + unsigned long page_off, page_len; + + local_irq_save(flags); + while (length) { + /* compute number of bytes we are going to copy in this page */ + step_len = length; + page_off = dma_addr & (PAGE_SIZE-1); + page_len = PAGE_SIZE - page_off; + if (page_len < step_len) + step_len = page_len; + + /* copy data and advance pointers */ + pg = phys_to_page(dma_addr); + map = kmap_atomic(pg, KM_IRQ0); + offset = mon_copy_to_buff(rp, offset, map + page_off, step_len); + kunmap_atomic(map, KM_IRQ0); + dma_addr += step_len; + length -= step_len; + } + local_irq_restore(flags); +} + #endif /* __i386__ */ #ifndef MON_HAS_UNMAP @@ -55,4 +85,11 @@ char mon_dmapeek(unsigned char *dst, dma { return 'D'; } -#endif + +void mon_dmapeek_vec(const struct mon_reader_bin *rp, + unsigned int offset, dma_addr_t dma_addr, unsigned int length) +{ + ; +} + +#endif /* MON_HAS_UNMAP */ diff --git a/drivers/usb/mon/mon_main.c b/drivers/usb/mon/mon_main.c index 394bbf2..c9739e7 100644 --- a/drivers/usb/mon/mon_main.c +++ b/drivers/usb/mon/mon_main.c @@ -9,7 +9,6 @@ #include #include #include -#include #include #include #include @@ -22,11 +21,10 @@ static void mon_complete(struct usb_bus static void mon_stop(struct mon_bus *mbus); static void mon_dissolve(struct mon_bus *mbus, struct usb_bus *ubus); static void mon_bus_drop(struct kref *r); -static void mon_bus_init(struct dentry *mondir, struct usb_bus *ubus); +static void mon_bus_init(struct usb_bus *ubus); DEFINE_MUTEX(mon_lock); -static struct dentry *mon_dir; /* /dbg/usbmon */ static LIST_HEAD(mon_buses); /* All buses we know: struct mon_bus */ /* @@ -200,7 +198,7 @@ static void mon_stop(struct mon_bus *mbu */ static void mon_bus_add(struct usb_bus *ubus) { - mon_bus_init(mon_dir, ubus); + mon_bus_init(ubus); } /* @@ -212,8 +210,8 @@ static void mon_bus_remove(struct usb_bu mutex_lock(&mon_lock); list_del(&mbus->bus_link); - debugfs_remove(mbus->dent_t); - debugfs_remove(mbus->dent_s); + if (mbus->text_inited) + mon_text_del(mbus); mon_dissolve(mbus, ubus); kref_put(&mbus->ref, mon_bus_drop); @@ -281,13 +279,9 @@ static void mon_bus_drop(struct kref *r) * - refcount USB bus struct * - link */ -static void mon_bus_init(struct dentry *mondir, struct usb_bus *ubus) +static void mon_bus_init(struct usb_bus *ubus) { - struct dentry *d; struct mon_bus *mbus; - enum { NAMESZ = 10 }; - char name[NAMESZ]; - int rc; if ((mbus = kzalloc(sizeof(struct mon_bus), GFP_KERNEL)) == NULL) goto err_alloc; @@ -303,57 +297,54 @@ static void mon_bus_init(struct dentry * ubus->mon_bus = mbus; mbus->uses_dma = ubus->uses_dma; - rc = snprintf(name, NAMESZ, "%dt", ubus->busnum); - if (rc <= 0 || rc >= NAMESZ) - goto err_print_t; - d = debugfs_create_file(name, 0600, mondir, mbus, &mon_fops_text); - if (d == NULL) - goto err_create_t; - mbus->dent_t = d; - - rc = snprintf(name, NAMESZ, "%ds", ubus->busnum); - if (rc <= 0 || rc >= NAMESZ) - goto err_print_s; - d = debugfs_create_file(name, 0600, mondir, mbus, &mon_fops_stat); - if (d == NULL) - goto err_create_s; - mbus->dent_s = d; + mbus->text_inited = mon_text_add(mbus, ubus); + // mon_bin_add(...) mutex_lock(&mon_lock); list_add_tail(&mbus->bus_link, &mon_buses); mutex_unlock(&mon_lock); return; -err_create_s: -err_print_s: - debugfs_remove(mbus->dent_t); -err_create_t: -err_print_t: - kfree(mbus); err_alloc: return; } +/* + * Search a USB bus by number. Notice that USB bus numbers start from one, + * which we may later use to identify "all" with zero. + * + * This function must be called with mon_lock held. + * + * This is obviously inefficient and may be revised in the future. + */ +struct mon_bus *mon_bus_lookup(unsigned int num) +{ + struct list_head *p; + struct mon_bus *mbus; + + list_for_each (p, &mon_buses) { + mbus = list_entry(p, struct mon_bus, bus_link); + if (mbus->u_bus->busnum == num) { + return mbus; + } + } + return NULL; +} + static int __init mon_init(void) { struct usb_bus *ubus; - struct dentry *mondir; + int rc; - mondir = debugfs_create_dir("usbmon", NULL); - if (IS_ERR(mondir)) { - printk(KERN_NOTICE TAG ": debugfs is not available\n"); - return -ENODEV; - } - if (mondir == NULL) { - printk(KERN_NOTICE TAG ": unable to create usbmon directory\n"); - return -ENODEV; - } - mon_dir = mondir; + if ((rc = mon_text_init()) != 0) + goto err_text; + if ((rc = mon_bin_init()) != 0) + goto err_bin; if (usb_mon_register(&mon_ops_0) != 0) { printk(KERN_NOTICE TAG ": unable to register with the core\n"); - debugfs_remove(mondir); - return -ENODEV; + rc = -ENODEV; + goto err_reg; } // MOD_INC_USE_COUNT(which_module?); @@ -361,10 +352,17 @@ static int __init mon_init(void) mutex_lock(&usb_bus_list_lock); list_for_each_entry (ubus, &usb_bus_list, bus_list) { - mon_bus_init(mondir, ubus); + mon_bus_init(ubus); } mutex_unlock(&usb_bus_list_lock); return 0; + +err_reg: + mon_bin_exit(); +err_bin: + mon_text_exit(); +err_text: + return rc; } static void __exit mon_exit(void) @@ -381,8 +379,8 @@ static void __exit mon_exit(void) mbus = list_entry(p, struct mon_bus, bus_link); list_del(p); - debugfs_remove(mbus->dent_t); - debugfs_remove(mbus->dent_s); + if (mbus->text_inited) + mon_text_del(mbus); /* * This never happens, because the open/close paths in @@ -401,7 +399,8 @@ static void __exit mon_exit(void) } mutex_unlock(&mon_lock); - debugfs_remove(mon_dir); + mon_text_exit(); + mon_bin_exit(); } module_init(mon_init); diff --git a/drivers/usb/mon/mon_text.c b/drivers/usb/mon/mon_text.c index 05cf2c9..d38a127 100644 --- a/drivers/usb/mon/mon_text.c +++ b/drivers/usb/mon/mon_text.c @@ -9,6 +9,7 @@ #include #include #include #include +#include #include #include "usb_mon.h" @@ -63,6 +64,8 @@ struct mon_reader_text { char slab_name[SLAB_NAME_SZ]; }; +static struct dentry *mon_dir; /* Usually /sys/kernel/debug/usbmon */ + static void mon_text_ctor(void *, struct kmem_cache *, unsigned long); /* @@ -436,7 +439,7 @@ static int mon_text_release(struct inode return 0; } -const struct file_operations mon_fops_text = { +static const struct file_operations mon_fops_text = { .owner = THIS_MODULE, .open = mon_text_open, .llseek = no_llseek, @@ -447,6 +450,47 @@ const struct file_operations mon_fops_te .release = mon_text_release, }; +int mon_text_add(struct mon_bus *mbus, const struct usb_bus *ubus) +{ + struct dentry *d; + enum { NAMESZ = 10 }; + char name[NAMESZ]; + int rc; + + rc = snprintf(name, NAMESZ, "%dt", ubus->busnum); + if (rc <= 0 || rc >= NAMESZ) + goto err_print_t; + d = debugfs_create_file(name, 0600, mon_dir, mbus, &mon_fops_text); + if (d == NULL) + goto err_create_t; + mbus->dent_t = d; + + /* XXX The stats do not belong to here (text API), but oh well... */ + rc = snprintf(name, NAMESZ, "%ds", ubus->busnum); + if (rc <= 0 || rc >= NAMESZ) + goto err_print_s; + d = debugfs_create_file(name, 0600, mon_dir, mbus, &mon_fops_stat); + if (d == NULL) + goto err_create_s; + mbus->dent_s = d; + + return 1; + +err_create_s: +err_print_s: + debugfs_remove(mbus->dent_t); + mbus->dent_t = NULL; +err_create_t: +err_print_t: + return 0; +} + +void mon_text_del(struct mon_bus *mbus) +{ + debugfs_remove(mbus->dent_t); + debugfs_remove(mbus->dent_s); +} + /* * Slab interface: constructor. */ @@ -459,3 +503,24 @@ static void mon_text_ctor(void *mem, str memset(mem, 0xe5, sizeof(struct mon_event_text)); } +int __init mon_text_init(void) +{ + struct dentry *mondir; + + mondir = debugfs_create_dir("usbmon", NULL); + if (IS_ERR(mondir)) { + printk(KERN_NOTICE TAG ": debugfs is not available\n"); + return -ENODEV; + } + if (mondir == NULL) { + printk(KERN_NOTICE TAG ": unable to create usbmon directory\n"); + return -ENODEV; + } + mon_dir = mondir; + return 0; +} + +void __exit mon_text_exit(void) +{ + debugfs_remove(mon_dir); +} diff --git a/drivers/usb/mon/usb_mon.h b/drivers/usb/mon/usb_mon.h index ab9d02d..4f949ce 100644 --- a/drivers/usb/mon/usb_mon.h +++ b/drivers/usb/mon/usb_mon.h @@ -17,9 +17,11 @@ #define TAG "usbmon" struct mon_bus { struct list_head bus_link; spinlock_t lock; + struct usb_bus *u_bus; + + int text_inited; struct dentry *dent_s; /* Debugging file */ struct dentry *dent_t; /* Text interface file */ - struct usb_bus *u_bus; int uses_dma; /* Ref */ @@ -48,13 +50,35 @@ struct mon_reader { void mon_reader_add(struct mon_bus *mbus, struct mon_reader *r); void mon_reader_del(struct mon_bus *mbus, struct mon_reader *r); +struct mon_bus *mon_bus_lookup(unsigned int num); + +int /*bool*/ mon_text_add(struct mon_bus *mbus, const struct usb_bus *ubus); +void mon_text_del(struct mon_bus *mbus); +// void mon_bin_add(struct mon_bus *); + +int __init mon_text_init(void); +void __exit mon_text_exit(void); +int __init mon_bin_init(void); +void __exit mon_bin_exit(void); + /* - */ + * DMA interface. + * + * XXX The vectored side needs a serious re-thinking. Abstracting vectors, + * like in Paolo's original patch, produces a double pkmap. We need an idea. +*/ extern char mon_dmapeek(unsigned char *dst, dma_addr_t dma_addr, int len); +struct mon_reader_bin; +extern void mon_dmapeek_vec(const struct mon_reader_bin *rp, + unsigned int offset, dma_addr_t dma_addr, unsigned int len); +extern unsigned int mon_copy_to_buff(const struct mon_reader_bin *rp, + unsigned int offset, const unsigned char *from, unsigned int len); + +/* + */ extern struct mutex mon_lock; -extern const struct file_operations mon_fops_text; extern const struct file_operations mon_fops_stat; #endif /* __USB_MON_H */ diff --git a/drivers/usb/net/Kconfig b/drivers/usb/net/Kconfig index e081836..a2b94ef 100644 --- a/drivers/usb/net/Kconfig +++ b/drivers/usb/net/Kconfig @@ -222,13 +222,15 @@ config USB_NET_MCS7830 adapters marketed under the DeLOCK brand. config USB_NET_RNDIS_HOST - tristate "Host for RNDIS devices (EXPERIMENTAL)" + tristate "Host for RNDIS and ActiveSync devices (EXPERIMENTAL)" depends on USB_USBNET && EXPERIMENTAL select USB_NET_CDCETHER help This option enables hosting "Remote NDIS" USB networking links, as encouraged by Microsoft (instead of CDC Ethernet!) for use in - various devices that may only support this protocol. + various devices that may only support this protocol. A variant + of this protocol (with even less public documentation) seems to + be at the root of Microsoft's "ActiveSync" too. Avoid using this protocol unless you have no better options. The protocol specification is incomplete, and is controlled by diff --git a/drivers/usb/net/asix.c b/drivers/usb/net/asix.c index 896449f..bd357e1 100644 --- a/drivers/usb/net/asix.c +++ b/drivers/usb/net/asix.c @@ -25,7 +25,6 @@ #include #include -#include #include #include #include @@ -1449,6 +1448,10 @@ static const struct usb_device_id produc // Linksys USB1000 USB_DEVICE (0x1737, 0x0039), .driver_info = (unsigned long) &ax88178_info, +}, { + // IO-DATA ETG-US2 + USB_DEVICE (0x04bb, 0x0930), + .driver_info = (unsigned long) &ax88178_info, }, { }, // END }; diff --git a/drivers/usb/net/cdc_ether.c b/drivers/usb/net/cdc_ether.c index 44a9154..5a21f06 100644 --- a/drivers/usb/net/cdc_ether.c +++ b/drivers/usb/net/cdc_ether.c @@ -1,6 +1,7 @@ /* * CDC Ethernet based networking peripherals * Copyright (C) 2003-2005 by David Brownell + * Copyright (C) 2006 by Ole Andre Vadla Ravnas (ActiveSync) * * 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 @@ -21,7 +22,6 @@ // #define VERBOSE // more; success messages #include -#include #include #include #include @@ -35,6 +35,29 @@ #include #include "usbnet.h" +#if defined(CONFIG_USB_NET_RNDIS_HOST) || defined(CONFIG_USB_NET_RNDIS_HOST_MODULE) + +static int is_rndis(struct usb_interface_descriptor *desc) +{ + return desc->bInterfaceClass == USB_CLASS_COMM + && desc->bInterfaceSubClass == 2 + && desc->bInterfaceProtocol == 0xff; +} + +static int is_activesync(struct usb_interface_descriptor *desc) +{ + return desc->bInterfaceClass == USB_CLASS_MISC + && desc->bInterfaceSubClass == 1 + && desc->bInterfaceProtocol == 1; +} + +#else + +#define is_rndis(desc) 0 +#define is_activesync(desc) 0 + +#endif + /* * probes control interface, claims data interface, collects the bulk * endpoints, activates data interface (if needed), maybe sets MTU. @@ -71,7 +94,8 @@ int usbnet_generic_cdc_bind(struct usbne /* this assumes that if there's a non-RNDIS vendor variant * of cdc-acm, it'll fail RNDIS requests cleanly. */ - rndis = (intf->cur_altsetting->desc.bInterfaceProtocol == 0xff); + rndis = is_rndis(&intf->cur_altsetting->desc) + || is_activesync(&intf->cur_altsetting->desc); memset(info, 0, sizeof *info); info->control = intf; @@ -99,6 +123,23 @@ int usbnet_generic_cdc_bind(struct usbne goto bad_desc; } break; + case USB_CDC_ACM_TYPE: + /* paranoia: disambiguate a "real" vendor-specific + * modem interface from an RNDIS non-modem. + */ + if (rndis) { + struct usb_cdc_acm_descriptor *d; + + d = (void *) buf; + if (d->bmCapabilities) { + dev_dbg(&intf->dev, + "ACM capabilities %02x, " + "not really RNDIS?\n", + d->bmCapabilities); + goto bad_desc; + } + } + break; case USB_CDC_UNION_TYPE: if (info->u) { dev_dbg(&intf->dev, "extra CDC union\n"); @@ -171,7 +212,21 @@ next_desc: buf += buf [0]; } - if (!info->header || !info->u || (!rndis && !info->ether)) { + /* Microsoft ActiveSync based RNDIS devices lack the CDC descriptors, + * so we'll hard-wire the interfaces and not check for descriptors. + */ + if (is_activesync(&intf->cur_altsetting->desc) && !info->u) { + info->control = usb_ifnum_to_if(dev->udev, 0); + info->data = usb_ifnum_to_if(dev->udev, 1); + if (!info->control || !info->data) { + dev_dbg(&intf->dev, + "activesync: master #0/%p slave #1/%p\n", + info->control, + info->data); + goto bad_desc; + } + + } else if (!info->header || !info->u || (!rndis && !info->ether)) { dev_dbg(&intf->dev, "missing cdc %s%s%sdescriptor\n", info->header ? "" : "header ", info->u ? "" : "union ", diff --git a/drivers/usb/net/cdc_subset.c b/drivers/usb/net/cdc_subset.c index e2fae85..ae8fb06 100644 --- a/drivers/usb/net/cdc_subset.c +++ b/drivers/usb/net/cdc_subset.c @@ -19,7 +19,6 @@ #include #include -#include #include #include #include diff --git a/drivers/usb/net/gl620a.c b/drivers/usb/net/gl620a.c index a6f0f4d..d257a8e 100644 --- a/drivers/usb/net/gl620a.c +++ b/drivers/usb/net/gl620a.c @@ -22,7 +22,6 @@ // #define VERBOSE // more; success messages #include -#include #include #include #include @@ -70,12 +69,12 @@ #define GL_RCV_BUF_SIZE \ (((GL_MAX_PACKET_LEN + 4) * GL_MAX_TRANSMIT_PACKETS) + 4) struct gl_packet { - u32 packet_length; + __le32 packet_length; char packet_data [1]; }; struct gl_header { - u32 packet_count; + __le32 packet_count; struct gl_packet packets; }; @@ -85,15 +84,14 @@ static int genelink_rx_fixup(struct usbn struct gl_packet *packet; struct sk_buff *gl_skb; u32 size; + u32 count; header = (struct gl_header *) skb->data; // get the packet count of the received skb - le32_to_cpus(&header->packet_count); - if ((header->packet_count > GL_MAX_TRANSMIT_PACKETS) - || (header->packet_count < 0)) { - dbg("genelink: invalid received packet count %d", - header->packet_count); + count = le32_to_cpu(header->packet_count); + if (count > GL_MAX_TRANSMIT_PACKETS) { + dbg("genelink: invalid received packet count %u", count); return 0; } @@ -103,7 +101,7 @@ static int genelink_rx_fixup(struct usbn // decrement the length for the packet count size 4 bytes skb_pull(skb, 4); - while (header->packet_count > 1) { + while (count > 1) { // get the packet length size = le32_to_cpu(packet->packet_length); @@ -124,9 +122,8 @@ static int genelink_rx_fixup(struct usbn } // advance to the next packet - packet = (struct gl_packet *) - &packet->packet_data [size]; - header->packet_count--; + packet = (struct gl_packet *)&packet->packet_data[size]; + count--; // shift the data pointer to the next gl_packet skb_pull(skb, size + 4); @@ -149,8 +146,8 @@ genelink_tx_fixup(struct usbnet *dev, st int length = skb->len; int headroom = skb_headroom(skb); int tailroom = skb_tailroom(skb); - u32 *packet_count; - u32 *packet_len; + __le32 *packet_count; + __le32 *packet_len; // FIXME: magic numbers, bleech padlen = ((skb->len + (4 + 4*1)) % 64) ? 0 : 1; @@ -172,7 +169,7 @@ genelink_tx_fixup(struct usbnet *dev, st } // attach the packet count to the header - packet_count = (u32 *) skb_push(skb, (4 + 4*1)); + packet_count = (__le32 *) skb_push(skb, (4 + 4*1)); packet_len = packet_count + 1; *packet_count = cpu_to_le32(1); diff --git a/drivers/usb/net/kaweth.c b/drivers/usb/net/kaweth.c index fa78326..de95268 100644 --- a/drivers/usb/net/kaweth.c +++ b/drivers/usb/net/kaweth.c @@ -46,7 +46,6 @@ */ #include -#include #include #include #include @@ -179,6 +178,7 @@ static struct usb_driver kaweth_driver = .suspend = kaweth_suspend, .resume = kaweth_resume, .id_table = usb_klsi_table, + .supports_autosuspend = 1, }; typedef __u8 eth_addr_t[6]; @@ -225,6 +225,7 @@ struct kaweth_device struct delayed_work lowmem_work; struct usb_device *dev; + struct usb_interface *intf; struct net_device *net; wait_queue_head_t term_wait; @@ -662,9 +663,14 @@ static int kaweth_open(struct net_device dbg("Opening network device."); + res = usb_autopm_get_interface(kaweth->intf); + if (res) { + err("Interface cannot be resumed."); + return -EIO; + } res = kaweth_resubmit_rx_urb(kaweth, GFP_KERNEL); if (res) - return -EIO; + goto err_out; usb_fill_int_urb( kaweth->irq_urb, @@ -681,7 +687,7 @@ static int kaweth_open(struct net_device res = usb_submit_urb(kaweth->irq_urb, GFP_KERNEL); if (res) { usb_kill_urb(kaweth->rx_urb); - return -EIO; + goto err_out; } kaweth->opened = 1; @@ -689,10 +695,14 @@ static int kaweth_open(struct net_device kaweth_async_set_rx_mode(kaweth); return 0; + +err_out: + usb_autopm_enable(kaweth->intf); + return -EIO; } /**************************************************************** - * kaweth_close + * kaweth_kill_urbs ****************************************************************/ static void kaweth_kill_urbs(struct kaweth_device *kaweth) { @@ -724,17 +734,29 @@ static int kaweth_close(struct net_devic kaweth->status &= ~KAWETH_STATUS_CLOSING; + usb_autopm_enable(kaweth->intf); + return 0; } static void kaweth_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info) { + struct kaweth_device *kaweth = netdev_priv(dev); strlcpy(info->driver, driver_name, sizeof(info->driver)); + usb_make_path(kaweth->dev, info->bus_info, sizeof (info->bus_info)); +} + +static u32 kaweth_get_link(struct net_device *dev) +{ + struct kaweth_device *kaweth = netdev_priv(dev); + + return kaweth->linkstate; } static struct ethtool_ops ops = { - .get_drvinfo = kaweth_get_drvinfo + .get_drvinfo = kaweth_get_drvinfo, + .get_link = kaweth_get_link }; /**************************************************************** @@ -908,6 +930,7 @@ static int kaweth_suspend(struct usb_int struct kaweth_device *kaweth = usb_get_intfdata(intf); unsigned long flags; + dbg("Suspending device"); spin_lock_irqsave(&kaweth->device_lock, flags); kaweth->status |= KAWETH_STATUS_SUSPENDING; spin_unlock_irqrestore(&kaweth->device_lock, flags); @@ -924,6 +947,7 @@ static int kaweth_resume(struct usb_inte struct kaweth_device *kaweth = usb_get_intfdata(intf); unsigned long flags; + dbg("Resuming device"); spin_lock_irqsave(&kaweth->device_lock, flags); kaweth->status &= ~KAWETH_STATUS_SUSPENDING; spin_unlock_irqrestore(&kaweth->device_lock, flags); @@ -1086,6 +1110,8 @@ err_fw: dbg("Initializing net device."); + kaweth->intf = intf; + kaweth->tx_urb = usb_alloc_urb(0, GFP_KERNEL); if (!kaweth->tx_urb) goto err_free_netdev; @@ -1265,7 +1291,7 @@ static int kaweth_internal_control_msg(s { struct urb *urb; int retv; - int length; + int length = 0; /* shut up GCC */ urb = usb_alloc_urb(0, GFP_NOIO); if (!urb) diff --git a/drivers/usb/net/net1080.c b/drivers/usb/net/net1080.c index 4936359..ccebfde 100644 --- a/drivers/usb/net/net1080.c +++ b/drivers/usb/net/net1080.c @@ -21,7 +21,6 @@ // #define VERBOSE // more; success messages #include -#include #include #include #include diff --git a/drivers/usb/net/pegasus.h b/drivers/usb/net/pegasus.h index 98f6898..c746782 100644 --- a/drivers/usb/net/pegasus.h +++ b/drivers/usb/net/pegasus.h @@ -214,9 +214,9 @@ PEGASUS_DEV( "Billionton USBEL-100", VEN DEFAULT_GPIO_RESET ) PEGASUS_DEV( "Billionton USBE-100", VENDOR_BILLIONTON, 0x8511, DEFAULT_GPIO_RESET | PEGASUS_II ) -PEGASUS_DEV( "Corega FEter USB-TX", VENDOR_COREGA, 0x0004, +PEGASUS_DEV( "Corega FEther USB-TX", VENDOR_COREGA, 0x0004, DEFAULT_GPIO_RESET ) -PEGASUS_DEV( "Corega FEter USB-TXS", VENDOR_COREGA, 0x000d, +PEGASUS_DEV( "Corega FEther USB-TXS", VENDOR_COREGA, 0x000d, DEFAULT_GPIO_RESET | PEGASUS_II ) PEGASUS_DEV( "D-Link DSB-650TX", VENDOR_DLINK, 0x4001, DEFAULT_GPIO_RESET ) diff --git a/drivers/usb/net/plusb.c b/drivers/usb/net/plusb.c index 5d17cdf..4530093 100644 --- a/drivers/usb/net/plusb.c +++ b/drivers/usb/net/plusb.c @@ -21,7 +21,6 @@ // #define VERBOSE // more; success messages #include -#include #include #include #include diff --git a/drivers/usb/net/rndis_host.c b/drivers/usb/net/rndis_host.c index a322a16..39a21c7 100644 --- a/drivers/usb/net/rndis_host.c +++ b/drivers/usb/net/rndis_host.c @@ -21,7 +21,6 @@ // #define VERBOSE // more; success messages #include -#include #include #include #include @@ -49,6 +48,8 @@ #include "usbnet.h" * - In some cases, MS-Windows will emit undocumented requests; this * matters more to peripheral implementations than host ones. * + * Moreover there's a no-open-specs variant of RNDIS called "ActiveSync". + * * For these reasons and others, ** USE OF RNDIS IS STRONGLY DISCOURAGED ** in * favor of such non-proprietary alternatives as CDC Ethernet or the newer (and * currently rare) "Ethernet Emulation Model" (EEM). @@ -61,6 +62,9 @@ #include "usbnet.h" * - control-in: GET_ENCAPSULATED * * We'll try to ignore the RESPONSE_AVAILABLE notifications. + * + * REVISIT some RNDIS implementations seem to have curious issues still + * to be resolved. */ struct rndis_msg_hdr { __le32 msg_type; /* RNDIS_MSG_* */ @@ -71,8 +75,14 @@ struct rndis_msg_hdr { // ... and more } __attribute__ ((packed)); -/* RNDIS defines this (absurdly huge) control timeout */ -#define RNDIS_CONTROL_TIMEOUT_MS (10 * 1000) +/* MS-Windows uses this strange size, but RNDIS spec says 1024 minimum */ +#define CONTROL_BUFFER_SIZE 1025 + +/* RNDIS defines an (absurdly huge) 10 second control timeout, + * but ActiveSync seems to use a more usual 5 second timeout + * (which matches the USB 2.0 spec). + */ +#define RNDIS_CONTROL_TIMEOUT_MS (5 * 1000) #define ccpu2 __constant_cpu_to_le32 @@ -270,6 +280,7 @@ static void rndis_status(struct usbnet * static int rndis_command(struct usbnet *dev, struct rndis_msg_hdr *buf) { struct cdc_state *info = (void *) &dev->data; + int master_ifnum; int retval; unsigned count; __le32 rsp; @@ -279,7 +290,7 @@ static int rndis_command(struct usbnet * * disconnect(): either serialize, or dispatch responses on xid */ - /* Issue the request; don't bother byteswapping our xid */ + /* Issue the request; xid is unique, don't bother byteswapping it */ if (likely(buf->msg_type != RNDIS_MSG_HALT && buf->msg_type != RNDIS_MSG_RESET)) { xid = dev->xid++; @@ -287,11 +298,12 @@ static int rndis_command(struct usbnet * xid = dev->xid++; buf->request_id = (__force __le32) xid; } + master_ifnum = info->control->cur_altsetting->desc.bInterfaceNumber; retval = usb_control_msg(dev->udev, usb_sndctrlpipe(dev->udev, 0), USB_CDC_SEND_ENCAPSULATED_COMMAND, USB_TYPE_CLASS | USB_RECIP_INTERFACE, - 0, info->u->bMasterInterface0, + 0, master_ifnum, buf, le32_to_cpu(buf->msg_len), RNDIS_CONTROL_TIMEOUT_MS); if (unlikely(retval < 0 || xid == 0)) @@ -306,13 +318,13 @@ static int rndis_command(struct usbnet * */ rsp = buf->msg_type | RNDIS_MSG_COMPLETION; for (count = 0; count < 10; count++) { - memset(buf, 0, 1024); + memset(buf, 0, CONTROL_BUFFER_SIZE); retval = usb_control_msg(dev->udev, usb_rcvctrlpipe(dev->udev, 0), USB_CDC_GET_ENCAPSULATED_RESPONSE, USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE, - 0, info->u->bMasterInterface0, - buf, 1024, + 0, master_ifnum, + buf, CONTROL_BUFFER_SIZE, RNDIS_CONTROL_TIMEOUT_MS); if (likely(retval >= 8)) { msg_len = le32_to_cpu(buf->msg_len); @@ -350,7 +362,7 @@ static int rndis_command(struct usbnet * usb_sndctrlpipe(dev->udev, 0), USB_CDC_SEND_ENCAPSULATED_COMMAND, USB_TYPE_CLASS | USB_RECIP_INTERFACE, - 0, info->u->bMasterInterface0, + 0, master_ifnum, msg, sizeof *msg, RNDIS_CONTROL_TIMEOUT_MS); if (unlikely(retval < 0)) @@ -393,38 +405,64 @@ static int rndis_bind(struct usbnet *dev u32 tmp; /* we can't rely on i/o from stack working, or stack allocation */ - u.buf = kmalloc(1024, GFP_KERNEL); + u.buf = kmalloc(CONTROL_BUFFER_SIZE, GFP_KERNEL); if (!u.buf) return -ENOMEM; retval = usbnet_generic_cdc_bind(dev, intf); if (retval < 0) goto fail; - net->hard_header_len += sizeof (struct rndis_data_hdr); - - /* initialize; max transfer is 16KB at full speed */ u.init->msg_type = RNDIS_MSG_INIT; u.init->msg_len = ccpu2(sizeof *u.init); u.init->major_version = ccpu2(1); u.init->minor_version = ccpu2(0); - u.init->max_transfer_size = ccpu2(net->mtu + net->hard_header_len); + /* max transfer (in spec) is 0x4000 at full speed, but for + * TX we'll stick to one Ethernet packet plus RNDIS framing. + * For RX we handle drivers that zero-pad to end-of-packet. + * Don't let userspace change these settings. + */ + net->hard_header_len += sizeof (struct rndis_data_hdr); + dev->hard_mtu = net->mtu + net->hard_header_len; + + dev->rx_urb_size = dev->hard_mtu + (dev->maxpacket + 1); + dev->rx_urb_size &= ~(dev->maxpacket - 1); + u.init->max_transfer_size = cpu_to_le32(dev->rx_urb_size); + + net->change_mtu = NULL; retval = rndis_command(dev, u.header); if (unlikely(retval < 0)) { /* it might not even be an RNDIS device!! */ dev_err(&intf->dev, "RNDIS init failed, %d\n", retval); + goto fail_and_release; + } + tmp = le32_to_cpu(u.init_c->max_transfer_size); + if (tmp < dev->hard_mtu) { + dev_err(&intf->dev, + "dev can't take %u byte packets (max %u)\n", + dev->hard_mtu, tmp); goto fail_and_release; } - dev->hard_mtu = le32_to_cpu(u.init_c->max_transfer_size); + /* REVISIT: peripheral "alignment" request is ignored ... */ - dev_dbg(&intf->dev, "hard mtu %u, align %d\n", dev->hard_mtu, + dev_dbg(&intf->dev, + "hard mtu %u (%u from dev), rx buflen %Zu, align %d\n", + dev->hard_mtu, tmp, dev->rx_urb_size, 1 << le32_to_cpu(u.init_c->packet_alignment)); - /* get designated host ethernet address */ - memset(u.get, 0, sizeof *u.get); + /* Get designated host ethernet address. + * + * Adding a payload exactly the same size as the expected response + * payload is an evident requirement MSFT added for ActiveSync. + * This undocumented (and nonsensical) issue was found by sniffing + * protocol requests from the ActiveSync 4.1 Windows driver. + */ + memset(u.get, 0, sizeof *u.get + 48); u.get->msg_type = RNDIS_MSG_QUERY; - u.get->msg_len = ccpu2(sizeof *u.get); + u.get->msg_len = ccpu2(sizeof *u.get + 48); u.get->oid = OID_802_3_PERMANENT_ADDRESS; + u.get->len = ccpu2(48); + u.get->offset = ccpu2(20); retval = rndis_command(dev, u.header); if (unlikely(retval < 0)) { @@ -432,7 +470,7 @@ static int rndis_bind(struct usbnet *dev goto fail_and_release; } tmp = le32_to_cpu(u.get_c->offset); - if (unlikely((tmp + 8) > (1024 - ETH_ALEN) + if (unlikely((tmp + 8) > (CONTROL_BUFFER_SIZE - ETH_ALEN) || u.get_c->len != ccpu2(ETH_ALEN))) { dev_err(&intf->dev, "rndis ethaddr off %d len %d ?\n", tmp, le32_to_cpu(u.get_c->len)); @@ -598,6 +636,10 @@ static const struct usb_device_id produc /* RNDIS is MSFT's un-official variant of CDC ACM */ USB_INTERFACE_INFO(USB_CLASS_COMM, 2 /* ACM */, 0x0ff), .driver_info = (unsigned long) &rndis_info, +}, { + /* "ActiveSync" is an undocumented variant of RNDIS, used in WM5 */ + USB_INTERFACE_INFO(USB_CLASS_MISC, 1, 1), + .driver_info = (unsigned long) &rndis_info, }, { }, // END }; diff --git a/drivers/usb/net/rtl8150.c b/drivers/usb/net/rtl8150.c index 670262a..ea153dc 100644 --- a/drivers/usb/net/rtl8150.c +++ b/drivers/usb/net/rtl8150.c @@ -6,7 +6,6 @@ * version 2 as published by the Free Software Foundation. */ -#include #include #include #include diff --git a/drivers/usb/net/usbnet.c b/drivers/usb/net/usbnet.c index 6e39e99..43ba61a 100644 --- a/drivers/usb/net/usbnet.c +++ b/drivers/usb/net/usbnet.c @@ -34,7 +34,6 @@ // #define VERBOSE // more; success messages #include -#include #include #include #include diff --git a/drivers/usb/net/zaurus.c b/drivers/usb/net/zaurus.c index 144566b..9f98e8c 100644 --- a/drivers/usb/net/zaurus.c +++ b/drivers/usb/net/zaurus.c @@ -21,7 +21,6 @@ // #define VERBOSE // more; success messages #include -#include #include #include #include diff --git a/drivers/usb/serial/aircable.c b/drivers/usb/serial/aircable.c index 86bcf63..11dad42 100644 --- a/drivers/usb/serial/aircable.c +++ b/drivers/usb/serial/aircable.c @@ -572,8 +572,20 @@ static void aircable_unthrottle(struct u schedule_work(&priv->rx_work); } +static struct usb_driver aircable_driver = { + .name = "aircable", + .probe = usb_serial_probe, + .disconnect = usb_serial_disconnect, + .id_table = id_table, + .no_dynamic_id = 1, +}; + static struct usb_serial_driver aircable_device = { - .description = "aircable", + .driver = { + .owner = THIS_MODULE, + .name = "aircable", + }, + .usb_driver = &aircable_driver, .id_table = id_table, .num_ports = 1, .attach = aircable_attach, @@ -587,13 +599,6 @@ static struct usb_serial_driver aircable .unthrottle = aircable_unthrottle, }; -static struct usb_driver aircable_driver = { - .name = "aircable", - .probe = usb_serial_probe, - .disconnect = usb_serial_disconnect, - .id_table = id_table, -}; - static int __init aircable_init (void) { int retval; diff --git a/drivers/usb/serial/airprime.c b/drivers/usb/serial/airprime.c index f2ca76a..0af42e3 100644 --- a/drivers/usb/serial/airprime.c +++ b/drivers/usb/serial/airprime.c @@ -277,6 +277,7 @@ static struct usb_serial_driver airprime .owner = THIS_MODULE, .name = "airprime", }, + .usb_driver = &airprime_driver, .id_table = id_table, .num_interrupt_in = NUM_DONT_CARE, .num_bulk_in = NUM_DONT_CARE, diff --git a/drivers/usb/serial/ark3116.c b/drivers/usb/serial/ark3116.c index 5261cd2..edd6857 100644 --- a/drivers/usb/serial/ark3116.c +++ b/drivers/usb/serial/ark3116.c @@ -444,6 +444,7 @@ static struct usb_driver ark3116_driver .probe = usb_serial_probe, .disconnect = usb_serial_disconnect, .id_table = id_table, + .no_dynamic_id = 1, }; static struct usb_serial_driver ark3116_device = { @@ -452,6 +453,7 @@ static struct usb_serial_driver ark3116_ .name = "ark3116", }, .id_table = id_table, + .usb_driver = &ark3116_driver, .num_interrupt_in = 1, .num_bulk_in = 1, .num_bulk_out = 1, diff --git a/drivers/usb/serial/belkin_sa.c b/drivers/usb/serial/belkin_sa.c index 38b4dae..3b800d2 100644 --- a/drivers/usb/serial/belkin_sa.c +++ b/drivers/usb/serial/belkin_sa.c @@ -126,6 +126,7 @@ static struct usb_serial_driver belkin_d .name = "belkin", }, .description = "Belkin / Peracom / GoHubs USB Serial Adapter", + .usb_driver = &belkin_driver, .id_table = id_table_combined, .num_interrupt_in = 1, .num_bulk_in = 1, diff --git a/drivers/usb/serial/bus.c b/drivers/usb/serial/bus.c index 6542f22..c08a384 100644 --- a/drivers/usb/serial/bus.c +++ b/drivers/usb/serial/bus.c @@ -103,11 +103,52 @@ exit: return retval; } +#ifdef CONFIG_HOTPLUG +static ssize_t store_new_id(struct device_driver *driver, + const char *buf, size_t count) +{ + struct usb_serial_driver *usb_drv = to_usb_serial_driver(driver); + ssize_t retval = usb_store_new_id(&usb_drv->dynids, driver, buf, count); + + if (retval >= 0 && usb_drv->usb_driver != NULL) + retval = usb_store_new_id(&usb_drv->usb_driver->dynids, + &usb_drv->usb_driver->drvwrap.driver, + buf, count); + return retval; +} + +static struct driver_attribute drv_attrs[] = { + __ATTR(new_id, S_IWUSR, NULL, store_new_id), + __ATTR_NULL, +}; + +static void free_dynids(struct usb_serial_driver *drv) +{ + struct usb_dynid *dynid, *n; + + spin_lock(&drv->dynids.lock); + list_for_each_entry_safe(dynid, n, &drv->dynids.list, node) { + list_del(&dynid->node); + kfree(dynid); + } + spin_unlock(&drv->dynids.lock); +} + +#else +static struct driver_attribute drv_attrs[] = { + __ATTR_NULL, +}; +static inline void free_dynids(struct usb_driver *drv) +{ +} +#endif + struct bus_type usb_serial_bus_type = { .name = "usb-serial", .match = usb_serial_device_match, .probe = usb_serial_device_probe, .remove = usb_serial_device_remove, + .drv_attrs = drv_attrs, }; int usb_serial_bus_register(struct usb_serial_driver *driver) @@ -115,6 +156,9 @@ int usb_serial_bus_register(struct usb_s int retval; driver->driver.bus = &usb_serial_bus_type; + spin_lock_init(&driver->dynids.lock); + INIT_LIST_HEAD(&driver->dynids.list); + retval = driver_register(&driver->driver); return retval; @@ -122,6 +166,7 @@ int usb_serial_bus_register(struct usb_s void usb_serial_bus_deregister(struct usb_serial_driver *driver) { + free_dynids(driver); driver_unregister(&driver->driver); } diff --git a/drivers/usb/serial/cp2101.c b/drivers/usb/serial/cp2101.c index 7ebaffd..3ec2487 100644 --- a/drivers/usb/serial/cp2101.c +++ b/drivers/usb/serial/cp2101.c @@ -89,6 +89,7 @@ static struct usb_serial_driver cp2101_d .owner = THIS_MODULE, .name = "cp2101", }, + .usb_driver = &cp2101_driver, .id_table = id_table, .num_interrupt_in = 0, .num_bulk_in = 0, @@ -169,13 +170,13 @@ static int cp2101_get_config(struct usb_ unsigned int *data, int size) { struct usb_serial *serial = port->serial; - u32 *buf; + __le32 *buf; int result, i, length; /* Number of integers required to contain the array */ length = (((size - 1) | 3) + 1)/4; - buf = kcalloc(length, sizeof(u32), GFP_KERNEL); + buf = kcalloc(length, sizeof(__le32), GFP_KERNEL); if (!buf) { dev_err(&port->dev, "%s - out of memory.\n", __FUNCTION__); return -ENOMEM; @@ -215,13 +216,13 @@ static int cp2101_set_config(struct usb_ unsigned int *data, int size) { struct usb_serial *serial = port->serial; - u32 *buf; + __le32 *buf; int result, i, length; /* Number of integers required to contain the array */ length = (((size - 1) | 3) + 1)/4; - buf = kmalloc(length * sizeof(u32), GFP_KERNEL); + buf = kmalloc(length * sizeof(__le32), GFP_KERNEL); if (!buf) { dev_err(&port->dev, "%s - out of memory.\n", __FUNCTION__); diff --git a/drivers/usb/serial/cyberjack.c b/drivers/usb/serial/cyberjack.c index a63c328..4167753 100644 --- a/drivers/usb/serial/cyberjack.c +++ b/drivers/usb/serial/cyberjack.c @@ -88,6 +88,7 @@ static struct usb_serial_driver cyberjac .name = "cyberjack", }, .description = "Reiner SCT Cyberjack USB card reader", + .usb_driver = &cyberjack_driver, .id_table = id_table, .num_interrupt_in = 1, .num_bulk_in = 1, @@ -98,7 +99,7 @@ static struct usb_serial_driver cyberjac .open = cyberjack_open, .close = cyberjack_close, .write = cyberjack_write, - .write_room = cyberjack_write_room, + .write_room = cyberjack_write_room, .read_int_callback = cyberjack_read_int_callback, .read_bulk_callback = cyberjack_read_bulk_callback, .write_bulk_callback = cyberjack_write_bulk_callback, diff --git a/drivers/usb/serial/cypress_m8.c b/drivers/usb/serial/cypress_m8.c index 6bc1f40..57b8e27 100644 --- a/drivers/usb/serial/cypress_m8.c +++ b/drivers/usb/serial/cypress_m8.c @@ -193,6 +193,7 @@ static struct usb_serial_driver cypress_ .name = "earthmate", }, .description = "DeLorme Earthmate USB", + .usb_driver = &cypress_driver, .id_table = id_table_earthmate, .num_interrupt_in = 1, .num_interrupt_out = 1, @@ -222,6 +223,7 @@ static struct usb_serial_driver cypress_ .name = "cyphidcom", }, .description = "HID->COM RS232 Adapter", + .usb_driver = &cypress_driver, .id_table = id_table_cyphidcomrs232, .num_interrupt_in = 1, .num_interrupt_out = 1, @@ -251,6 +253,7 @@ static struct usb_serial_driver cypress_ .name = "nokiaca42v2", }, .description = "Nokia CA-42 V2 Adapter", + .usb_driver = &cypress_driver, .id_table = id_table_nokiaca42v2, .num_interrupt_in = 1, .num_interrupt_out = 1, diff --git a/drivers/usb/serial/digi_acceleport.c b/drivers/usb/serial/digi_acceleport.c index efd9ce3..d78692c 100644 --- a/drivers/usb/serial/digi_acceleport.c +++ b/drivers/usb/serial/digi_acceleport.c @@ -509,6 +509,7 @@ static struct usb_serial_driver digi_acc .name = "digi_2", }, .description = "Digi 2 port USB adapter", + .usb_driver = &digi_driver, .id_table = id_table_2, .num_interrupt_in = 0, .num_bulk_in = 4, @@ -538,6 +539,7 @@ static struct usb_serial_driver digi_acc .name = "digi_4", }, .description = "Digi 4 port USB adapter", + .usb_driver = &digi_driver, .id_table = id_table_4, .num_interrupt_in = 0, .num_bulk_in = 5, @@ -614,15 +616,7 @@ static void digi_wakeup_write_lock(struc static void digi_wakeup_write( struct usb_serial_port *port ) { - - struct tty_struct *tty = port->tty; - - - /* wake up port processes */ - wake_up_interruptible( &port->write_wait ); - - /* wake up line discipline */ - tty_wakeup(tty); + tty_wakeup(port->tty); } diff --git a/drivers/usb/serial/empeg.c b/drivers/usb/serial/empeg.c index 92beeb1..4703c8f 100644 --- a/drivers/usb/serial/empeg.c +++ b/drivers/usb/serial/empeg.c @@ -117,6 +117,7 @@ static struct usb_serial_driver empeg_de .name = "empeg", }, .id_table = id_table, + .usb_driver = &empeg_driver, .num_interrupt_in = 0, .num_bulk_in = 1, .num_bulk_out = 1, diff --git a/drivers/usb/serial/ftdi_sio.c b/drivers/usb/serial/ftdi_sio.c index 6986e75..4695952 100644 --- a/drivers/usb/serial/ftdi_sio.c +++ b/drivers/usb/serial/ftdi_sio.c @@ -464,7 +464,6 @@ static struct usb_device_id id_table_com { USB_DEVICE(BANDB_VID, BANDB_USTL4_PID) }, { USB_DEVICE(BANDB_VID, BANDB_USO9ML2_PID) }, { USB_DEVICE(FTDI_VID, EVER_ECO_PRO_CDS) }, - { USB_DEVICE(FTDI_VID, FTDI_4N_GALAXY_DE_0_PID) }, { USB_DEVICE(FTDI_VID, FTDI_4N_GALAXY_DE_1_PID) }, { USB_DEVICE(FTDI_VID, FTDI_4N_GALAXY_DE_2_PID) }, { USB_DEVICE(FTDI_VID, XSENS_CONVERTER_0_PID) }, @@ -615,6 +614,7 @@ static struct usb_serial_driver ftdi_sio .name = "ftdi_sio", }, .description = "FTDI USB Serial Device", + .usb_driver = &ftdi_driver , .id_table = id_table_combined, .num_interrupt_in = 0, .num_bulk_in = 1, diff --git a/drivers/usb/serial/ftdi_sio.h b/drivers/usb/serial/ftdi_sio.h index 40dd394..7eff1c0 100644 --- a/drivers/usb/serial/ftdi_sio.h +++ b/drivers/usb/serial/ftdi_sio.h @@ -364,7 +364,6 @@ #define EVER_ECO_PRO_CDS 0xe520 /* RS-23 * USB-TTY activ, USB-TTY passiv. Some PIDs are used by several devices * and I'm not entirely sure which are used by which. */ -#define FTDI_4N_GALAXY_DE_0_PID 0x8372 #define FTDI_4N_GALAXY_DE_1_PID 0xF3C0 #define FTDI_4N_GALAXY_DE_2_PID 0xF3C1 diff --git a/drivers/usb/serial/funsoft.c b/drivers/usb/serial/funsoft.c index 2bebd63..4092f6d 100644 --- a/drivers/usb/serial/funsoft.c +++ b/drivers/usb/serial/funsoft.c @@ -58,6 +58,7 @@ static struct usb_serial_driver funsoft_ .name = "funsoft", }, .id_table = id_table, + .usb_driver = &funsoft_driver, .num_interrupt_in = NUM_DONT_CARE, .num_bulk_in = NUM_DONT_CARE, .num_bulk_out = NUM_DONT_CARE, diff --git a/drivers/usb/serial/garmin_gps.c b/drivers/usb/serial/garmin_gps.c index 6530d39..74660a3 100644 --- a/drivers/usb/serial/garmin_gps.c +++ b/drivers/usb/serial/garmin_gps.c @@ -1566,6 +1566,7 @@ static struct usb_serial_driver garmin_d .name = "garmin_gps", }, .description = "Garmin GPS usb/tty", + .usb_driver = &garmin_driver, .id_table = id_table, .num_interrupt_in = 1, .num_bulk_in = 1, diff --git a/drivers/usb/serial/generic.c b/drivers/usb/serial/generic.c index 3604293..601e064 100644 --- a/drivers/usb/serial/generic.c +++ b/drivers/usb/serial/generic.c @@ -20,6 +20,10 @@ #include #include #include +static int generic_probe(struct usb_interface *interface, + const struct usb_device_id *id); + + static int debug; #ifdef CONFIG_USB_SERIAL_GENERIC @@ -34,6 +38,21 @@ MODULE_PARM_DESC(product, "User specifie static struct usb_device_id generic_device_ids[2]; /* Initially all zeroes. */ +/* we want to look at all devices, as the vendor/product id can change + * depending on the command line argument */ +static struct usb_device_id generic_serial_ids[] = { + {.driver_info = 42}, + {} +}; + +static struct usb_driver generic_driver = { + .name = "usbserial_generic", + .probe = generic_probe, + .disconnect = usb_serial_disconnect, + .id_table = generic_serial_ids, + .no_dynamic_id = 1, +}; + /* All of the device info needed for the Generic Serial Converter */ struct usb_serial_driver usb_serial_generic_device = { .driver = { @@ -41,6 +60,7 @@ struct usb_serial_driver usb_serial_gene .name = "generic", }, .id_table = generic_device_ids, + .usb_driver = &generic_driver, .num_interrupt_in = NUM_DONT_CARE, .num_bulk_in = NUM_DONT_CARE, .num_bulk_out = NUM_DONT_CARE, @@ -48,13 +68,6 @@ struct usb_serial_driver usb_serial_gene .shutdown = usb_serial_generic_shutdown, }; -/* we want to look at all devices, as the vendor/product id can change - * depending on the command line argument */ -static struct usb_device_id generic_serial_ids[] = { - {.driver_info = 42}, - {} -}; - static int generic_probe(struct usb_interface *interface, const struct usb_device_id *id) { @@ -65,14 +78,6 @@ static int generic_probe(struct usb_inte return usb_serial_probe(interface, id); return -ENODEV; } - -static struct usb_driver generic_driver = { - .name = "usbserial_generic", - .probe = generic_probe, - .disconnect = usb_serial_disconnect, - .id_table = generic_serial_ids, - .no_dynamic_id = 1, -}; #endif int usb_serial_generic_register (int _debug) diff --git a/drivers/usb/serial/hp4x.c b/drivers/usb/serial/hp4x.c index ebcac70..6c6ebae 100644 --- a/drivers/usb/serial/hp4x.c +++ b/drivers/usb/serial/hp4x.c @@ -49,6 +49,7 @@ static struct usb_serial_driver hp49gp_d .name = "hp4X", }, .id_table = id_table, + .usb_driver = &hp49gp_driver, .num_interrupt_in = NUM_DONT_CARE, .num_bulk_in = NUM_DONT_CARE, .num_bulk_out = NUM_DONT_CARE, diff --git a/drivers/usb/serial/io_edgeport.c b/drivers/usb/serial/io_edgeport.c index f623d58..6a26a2e 100644 --- a/drivers/usb/serial/io_edgeport.c +++ b/drivers/usb/serial/io_edgeport.c @@ -146,6 +146,8 @@ struct edgeport_serial { struct edge_manuf_descriptor manuf_descriptor; /* the manufacturer descriptor */ struct edge_boot_descriptor boot_descriptor; /* the boot firmware descriptor */ struct edgeport_product_info product_info; /* Product Info */ + struct edge_compatibility_descriptor epic_descriptor; /* Edgeport compatible descriptor */ + int is_epic; /* flag if EPiC device or not */ __u8 interrupt_in_endpoint; /* the interrupt endpoint handle */ unsigned char * interrupt_in_buffer; /* the buffer we use for the interrupt endpoint */ @@ -240,14 +242,6 @@ static void edge_shutdown (struct usb_s #include "io_tables.h" /* all of the devices that this driver supports */ -static struct usb_driver io_driver = { - .name = "io_edgeport", - .probe = usb_serial_probe, - .disconnect = usb_serial_disconnect, - .id_table = id_table_combined, - .no_dynamic_id = 1, -}; - /* function prototypes for all of our local functions */ static void process_rcvd_data (struct edgeport_serial *edge_serial, unsigned char *buffer, __u16 bufferLength); static void process_rcvd_status (struct edgeport_serial *edge_serial, __u8 byte2, __u8 byte3); @@ -397,6 +391,7 @@ static int get_string (struct usb_device unicode_to_ascii(string, buflen, pStringDesc->wData, pStringDesc->bLength/2); kfree(pStringDesc); + dbg("%s - USB String %s", __FUNCTION__, string); return strlen(string); } @@ -434,6 +429,34 @@ static int get_string_desc (struct usb_d } #endif +static void dump_product_info(struct edgeport_product_info *product_info) +{ + // Dump Product Info structure + dbg("**Product Information:"); + dbg(" ProductId %x", product_info->ProductId ); + dbg(" NumPorts %d", product_info->NumPorts ); + dbg(" ProdInfoVer %d", product_info->ProdInfoVer ); + dbg(" IsServer %d", product_info->IsServer); + dbg(" IsRS232 %d", product_info->IsRS232 ); + dbg(" IsRS422 %d", product_info->IsRS422 ); + dbg(" IsRS485 %d", product_info->IsRS485 ); + dbg(" RomSize %d", product_info->RomSize ); + dbg(" RamSize %d", product_info->RamSize ); + dbg(" CpuRev %x", product_info->CpuRev ); + dbg(" BoardRev %x", product_info->BoardRev); + dbg(" BootMajorVersion %d.%d.%d", product_info->BootMajorVersion, + product_info->BootMinorVersion, + le16_to_cpu(product_info->BootBuildNumber)); + dbg(" FirmwareMajorVersion %d.%d.%d", product_info->FirmwareMajorVersion, + product_info->FirmwareMinorVersion, + le16_to_cpu(product_info->FirmwareBuildNumber)); + dbg(" ManufactureDescDate %d/%d/%d", product_info->ManufactureDescDate[0], + product_info->ManufactureDescDate[1], + product_info->ManufactureDescDate[2]+1900); + dbg(" iDownloadFile 0x%x", product_info->iDownloadFile); + dbg(" EpicVer %d", product_info->EpicVer); +} + static void get_product_info(struct edgeport_serial *edge_serial) { struct edgeport_product_info *product_info = &edge_serial->product_info; @@ -495,30 +518,60 @@ static void get_product_info(struct edge break; } - // Dump Product Info structure - dbg("**Product Information:"); - dbg(" ProductId %x", product_info->ProductId ); - dbg(" NumPorts %d", product_info->NumPorts ); - dbg(" ProdInfoVer %d", product_info->ProdInfoVer ); - dbg(" IsServer %d", product_info->IsServer); - dbg(" IsRS232 %d", product_info->IsRS232 ); - dbg(" IsRS422 %d", product_info->IsRS422 ); - dbg(" IsRS485 %d", product_info->IsRS485 ); - dbg(" RomSize %d", product_info->RomSize ); - dbg(" RamSize %d", product_info->RamSize ); - dbg(" CpuRev %x", product_info->CpuRev ); - dbg(" BoardRev %x", product_info->BoardRev); - dbg(" BootMajorVersion %d.%d.%d", product_info->BootMajorVersion, - product_info->BootMinorVersion, - le16_to_cpu(product_info->BootBuildNumber)); - dbg(" FirmwareMajorVersion %d.%d.%d", product_info->FirmwareMajorVersion, - product_info->FirmwareMinorVersion, - le16_to_cpu(product_info->FirmwareBuildNumber)); - dbg(" ManufactureDescDate %d/%d/%d", product_info->ManufactureDescDate[0], - product_info->ManufactureDescDate[1], - product_info->ManufactureDescDate[2]+1900); - dbg(" iDownloadFile 0x%x", product_info->iDownloadFile); + dump_product_info(product_info); +} +static int get_epic_descriptor(struct edgeport_serial *ep) +{ + int result; + struct usb_serial *serial = ep->serial; + struct edgeport_product_info *product_info = &ep->product_info; + struct edge_compatibility_descriptor *epic = &ep->epic_descriptor; + struct edge_compatibility_bits *bits; + + ep->is_epic = 0; + result = usb_control_msg(serial->dev, usb_rcvctrlpipe(serial->dev, 0), + USB_REQUEST_ION_GET_EPIC_DESC, + 0xC0, 0x00, 0x00, + &ep->epic_descriptor, + sizeof(struct edge_compatibility_descriptor), + 300); + + dbg("%s result = %d", __FUNCTION__, result); + + if (result > 0) { + ep->is_epic = 1; + memset(product_info, 0, sizeof(struct edgeport_product_info)); + + product_info->NumPorts = epic->NumPorts; + product_info->ProdInfoVer = 0; + product_info->FirmwareMajorVersion = epic->MajorVersion; + product_info->FirmwareMinorVersion = epic->MinorVersion; + product_info->FirmwareBuildNumber = epic->BuildNumber; + product_info->iDownloadFile = epic->iDownloadFile; + product_info->EpicVer = epic->EpicVer; + product_info->Epic = epic->Supports; + product_info->ProductId = ION_DEVICE_ID_EDGEPORT_COMPATIBLE; + dump_product_info(product_info); + + bits = &ep->epic_descriptor.Supports; + dbg("**EPIC descriptor:"); + dbg(" VendEnableSuspend: %s", bits->VendEnableSuspend ? "TRUE": "FALSE"); + dbg(" IOSPOpen : %s", bits->IOSPOpen ? "TRUE": "FALSE" ); + dbg(" IOSPClose : %s", bits->IOSPClose ? "TRUE": "FALSE" ); + dbg(" IOSPChase : %s", bits->IOSPChase ? "TRUE": "FALSE" ); + dbg(" IOSPSetRxFlow : %s", bits->IOSPSetRxFlow ? "TRUE": "FALSE" ); + dbg(" IOSPSetTxFlow : %s", bits->IOSPSetTxFlow ? "TRUE": "FALSE" ); + dbg(" IOSPSetXChar : %s", bits->IOSPSetXChar ? "TRUE": "FALSE" ); + dbg(" IOSPRxCheck : %s", bits->IOSPRxCheck ? "TRUE": "FALSE" ); + dbg(" IOSPSetClrBreak : %s", bits->IOSPSetClrBreak ? "TRUE": "FALSE" ); + dbg(" IOSPWriteMCR : %s", bits->IOSPWriteMCR ? "TRUE": "FALSE" ); + dbg(" IOSPWriteLCR : %s", bits->IOSPWriteLCR ? "TRUE": "FALSE" ); + dbg(" IOSPSetBaudRate : %s", bits->IOSPSetBaudRate ? "TRUE": "FALSE" ); + dbg(" TrueEdgeport : %s", bits->TrueEdgeport ? "TRUE": "FALSE" ); + } + + return result; } @@ -1017,21 +1070,29 @@ static void edge_close (struct usb_seria edge_port->closePending = TRUE; - /* flush and chase */ - edge_port->chaseResponsePending = TRUE; - - dbg("%s - Sending IOSP_CMD_CHASE_PORT", __FUNCTION__); - status = send_iosp_ext_cmd (edge_port, IOSP_CMD_CHASE_PORT, 0); - if (status == 0) { - // block until chase finished - block_until_chase_response(edge_port); - } else { - edge_port->chaseResponsePending = FALSE; + if ((!edge_serial->is_epic) || + ((edge_serial->is_epic) && + (edge_serial->epic_descriptor.Supports.IOSPChase))) { + /* flush and chase */ + edge_port->chaseResponsePending = TRUE; + + dbg("%s - Sending IOSP_CMD_CHASE_PORT", __FUNCTION__); + status = send_iosp_ext_cmd (edge_port, IOSP_CMD_CHASE_PORT, 0); + if (status == 0) { + // block until chase finished + block_until_chase_response(edge_port); + } else { + edge_port->chaseResponsePending = FALSE; + } } - /* close the port */ - dbg("%s - Sending IOSP_CMD_CLOSE_PORT", __FUNCTION__); - send_iosp_ext_cmd (edge_port, IOSP_CMD_CLOSE_PORT, 0); + if ((!edge_serial->is_epic) || + ((edge_serial->is_epic) && + (edge_serial->epic_descriptor.Supports.IOSPClose))) { + /* close the port */ + dbg("%s - Sending IOSP_CMD_CLOSE_PORT", __FUNCTION__); + send_iosp_ext_cmd (edge_port, IOSP_CMD_CLOSE_PORT, 0); + } //port->close = TRUE; edge_port->closePending = FALSE; @@ -1694,29 +1755,38 @@ static int edge_ioctl (struct usb_serial static void edge_break (struct usb_serial_port *port, int break_state) { struct edgeport_port *edge_port = usb_get_serial_port_data(port); + struct edgeport_serial *edge_serial = usb_get_serial_data(port->serial); int status; - /* flush and chase */ - edge_port->chaseResponsePending = TRUE; - - dbg("%s - Sending IOSP_CMD_CHASE_PORT", __FUNCTION__); - status = send_iosp_ext_cmd (edge_port, IOSP_CMD_CHASE_PORT, 0); - if (status == 0) { - // block until chase finished - block_until_chase_response(edge_port); - } else { - edge_port->chaseResponsePending = FALSE; + if ((!edge_serial->is_epic) || + ((edge_serial->is_epic) && + (edge_serial->epic_descriptor.Supports.IOSPChase))) { + /* flush and chase */ + edge_port->chaseResponsePending = TRUE; + + dbg("%s - Sending IOSP_CMD_CHASE_PORT", __FUNCTION__); + status = send_iosp_ext_cmd (edge_port, IOSP_CMD_CHASE_PORT, 0); + if (status == 0) { + // block until chase finished + block_until_chase_response(edge_port); + } else { + edge_port->chaseResponsePending = FALSE; + } } - if (break_state == -1) { - dbg("%s - Sending IOSP_CMD_SET_BREAK", __FUNCTION__); - status = send_iosp_ext_cmd (edge_port, IOSP_CMD_SET_BREAK, 0); - } else { - dbg("%s - Sending IOSP_CMD_CLEAR_BREAK", __FUNCTION__); - status = send_iosp_ext_cmd (edge_port, IOSP_CMD_CLEAR_BREAK, 0); - } - if (status) { - dbg("%s - error sending break set/clear command.", __FUNCTION__); + if ((!edge_serial->is_epic) || + ((edge_serial->is_epic) && + (edge_serial->epic_descriptor.Supports.IOSPSetClrBreak))) { + if (break_state == -1) { + dbg("%s - Sending IOSP_CMD_SET_BREAK", __FUNCTION__); + status = send_iosp_ext_cmd (edge_port, IOSP_CMD_SET_BREAK, 0); + } else { + dbg("%s - Sending IOSP_CMD_CLEAR_BREAK", __FUNCTION__); + status = send_iosp_ext_cmd (edge_port, IOSP_CMD_CLEAR_BREAK, 0); + } + if (status) { + dbg("%s - error sending break set/clear command.", __FUNCTION__); + } } return; @@ -2288,6 +2358,7 @@ #endif *****************************************************************************/ static int send_cmd_write_baud_rate (struct edgeport_port *edge_port, int baudRate) { + struct edgeport_serial *edge_serial = usb_get_serial_data(edge_port->port->serial); unsigned char *cmdBuffer; unsigned char *currCmd; int cmdLen = 0; @@ -2295,6 +2366,14 @@ static int send_cmd_write_baud_rate (str int status; unsigned char number = edge_port->port->number - edge_port->port->serial->minor; + if ((!edge_serial->is_epic) || + ((edge_serial->is_epic) && + (!edge_serial->epic_descriptor.Supports.IOSPSetBaudRate))) { + dbg("SendCmdWriteBaudRate - NOT Setting baud rate for port = %d, baud = %d", + edge_port->port->number, baudRate); + return 0; + } + dbg("%s - port = %d, baud = %d", __FUNCTION__, edge_port->port->number, baudRate); status = calc_baud_rate_divisor (baudRate, &divisor); @@ -2374,6 +2453,7 @@ static int calc_baud_rate_divisor (int b *****************************************************************************/ static int send_cmd_write_uart_register (struct edgeport_port *edge_port, __u8 regNum, __u8 regValue) { + struct edgeport_serial *edge_serial = usb_get_serial_data(edge_port->port->serial); unsigned char *cmdBuffer; unsigned char *currCmd; unsigned long cmdLen = 0; @@ -2381,6 +2461,22 @@ static int send_cmd_write_uart_register dbg("%s - write to %s register 0x%02x", (regNum == MCR) ? "MCR" : "LCR", __FUNCTION__, regValue); + if ((!edge_serial->is_epic) || + ((edge_serial->is_epic) && + (!edge_serial->epic_descriptor.Supports.IOSPWriteMCR) && + (regNum == MCR))) { + dbg("SendCmdWriteUartReg - Not writting to MCR Register"); + return 0; + } + + if ((!edge_serial->is_epic) || + ((edge_serial->is_epic) && + (!edge_serial->epic_descriptor.Supports.IOSPWriteLCR) && + (regNum == LCR))) { + dbg ("SendCmdWriteUartReg - Not writting to LCR Register"); + return 0; + } + // Alloc memory for the string of commands. cmdBuffer = kmalloc (0x10, GFP_ATOMIC); if (cmdBuffer == NULL ) { @@ -2414,6 +2510,7 @@ #define CMSPAR 0 #endif static void change_port_settings (struct edgeport_port *edge_port, struct ktermios *old_termios) { + struct edgeport_serial *edge_serial = usb_get_serial_data(edge_port->port->serial); struct tty_struct *tty; int baud; unsigned cflag; @@ -2494,8 +2591,12 @@ static void change_port_settings (struct unsigned char stop_char = STOP_CHAR(tty); unsigned char start_char = START_CHAR(tty); - send_iosp_ext_cmd (edge_port, IOSP_CMD_SET_XON_CHAR, start_char); - send_iosp_ext_cmd (edge_port, IOSP_CMD_SET_XOFF_CHAR, stop_char); + if ((!edge_serial->is_epic) || + ((edge_serial->is_epic) && + (edge_serial->epic_descriptor.Supports.IOSPSetXChar))) { + send_iosp_ext_cmd(edge_port, IOSP_CMD_SET_XON_CHAR, start_char); + send_iosp_ext_cmd(edge_port, IOSP_CMD_SET_XOFF_CHAR, stop_char); + } /* if we are implementing INBOUND XON/XOFF */ if (I_IXOFF(tty)) { @@ -2515,8 +2616,14 @@ static void change_port_settings (struct } /* Set flow control to the configured value */ - send_iosp_ext_cmd (edge_port, IOSP_CMD_SET_RX_FLOW, rxFlow); - send_iosp_ext_cmd (edge_port, IOSP_CMD_SET_TX_FLOW, txFlow); + if ((!edge_serial->is_epic) || + ((edge_serial->is_epic) && + (edge_serial->epic_descriptor.Supports.IOSPSetRxFlow))) + send_iosp_ext_cmd(edge_port, IOSP_CMD_SET_RX_FLOW, rxFlow); + if ((!edge_serial->is_epic) || + ((edge_serial->is_epic) && + (edge_serial->epic_descriptor.Supports.IOSPSetTxFlow))) + send_iosp_ext_cmd(edge_port, IOSP_CMD_SET_TX_FLOW, txFlow); edge_port->shadowLCR &= ~(LCR_BITS_MASK | LCR_STOP_MASK | LCR_PAR_MASK); @@ -2728,6 +2835,13 @@ static int edge_startup (struct usb_seri struct edgeport_port *edge_port; struct usb_device *dev; int i, j; + int response; + int interrupt_in_found; + int bulk_in_found; + int bulk_out_found; + static __u32 descriptor[3] = { EDGE_COMPATIBILITY_MASK0, + EDGE_COMPATIBILITY_MASK1, + EDGE_COMPATIBILITY_MASK2 }; dev = serial->dev; @@ -2750,38 +2864,50 @@ static int edge_startup (struct usb_seri dev_info(&serial->dev->dev, "%s detected\n", edge_serial->name); - /* get the manufacturing descriptor for this device */ - get_manufacturing_desc (edge_serial); + /* Read the epic descriptor */ + if (get_epic_descriptor(edge_serial) <= 0) { + /* memcpy descriptor to Supports structures */ + memcpy(&edge_serial->epic_descriptor.Supports, descriptor, + sizeof(struct edge_compatibility_bits)); + + /* get the manufacturing descriptor for this device */ + get_manufacturing_desc (edge_serial); - /* get the boot descriptor */ - get_boot_desc (edge_serial); + /* get the boot descriptor */ + get_boot_desc (edge_serial); - get_product_info(edge_serial); + get_product_info(edge_serial); + } /* set the number of ports from the manufacturing description */ /* serial->num_ports = serial->product_info.NumPorts; */ - if (edge_serial->product_info.NumPorts != serial->num_ports) { - warn("%s - Device Reported %d serial ports vs core " - "thinking we have %d ports, email greg@kroah.com this info.", - __FUNCTION__, edge_serial->product_info.NumPorts, - serial->num_ports); + if ((!edge_serial->is_epic) && + (edge_serial->product_info.NumPorts != serial->num_ports)) { + dev_warn(&serial->dev->dev, "Device Reported %d serial ports " + "vs. core thinking we have %d ports, email " + "greg@kroah.com this information.", + edge_serial->product_info.NumPorts, + serial->num_ports); } dbg("%s - time 1 %ld", __FUNCTION__, jiffies); - /* now load the application firmware into this device */ - load_application_firmware (edge_serial); + /* If not an EPiC device */ + if (!edge_serial->is_epic) { + /* now load the application firmware into this device */ + load_application_firmware (edge_serial); - dbg("%s - time 2 %ld", __FUNCTION__, jiffies); + dbg("%s - time 2 %ld", __FUNCTION__, jiffies); - /* Check current Edgeport EEPROM and update if necessary */ - update_edgeport_E2PROM (edge_serial); - - dbg("%s - time 3 %ld", __FUNCTION__, jiffies); + /* Check current Edgeport EEPROM and update if necessary */ + update_edgeport_E2PROM (edge_serial); - /* set the configuration to use #1 */ -// dbg("set_configuration 1"); -// usb_set_configuration (dev, 1); + dbg("%s - time 3 %ld", __FUNCTION__, jiffies); + + /* set the configuration to use #1 */ +// dbg("set_configuration 1"); +// usb_set_configuration (dev, 1); + } /* we set up the pointers to the endpoints in the edge_open function, * as the structures aren't created yet. */ @@ -2804,8 +2930,101 @@ static int edge_startup (struct usb_seri edge_port->port = serial->port[i]; usb_set_serial_port_data(serial->port[i], edge_port); } - - return 0; + + response = 0; + + if (edge_serial->is_epic) { + /* EPIC thing, set up our interrupt polling now and our read urb, so + * that the device knows it really is connected. */ + interrupt_in_found = bulk_in_found = bulk_out_found = FALSE; + for (i = 0; i < serial->interface->altsetting[0].desc.bNumEndpoints; ++i) { + struct usb_endpoint_descriptor *endpoint; + int buffer_size; + + endpoint = &serial->interface->altsetting[0].endpoint[i].desc; + buffer_size = le16_to_cpu(endpoint->wMaxPacketSize); + if ((!interrupt_in_found) && + (usb_endpoint_is_int_in(endpoint))) { + /* we found a interrupt in endpoint */ + dbg("found interrupt in"); + + /* not set up yet, so do it now */ + edge_serial->interrupt_read_urb = usb_alloc_urb(0, GFP_KERNEL); + if (!edge_serial->interrupt_read_urb) { + err("out of memory"); + return -ENOMEM; + } + edge_serial->interrupt_in_buffer = kmalloc(buffer_size, GFP_KERNEL); + if (!edge_serial->interrupt_in_buffer) { + err("out of memory"); + usb_free_urb(edge_serial->interrupt_read_urb); + return -ENOMEM; + } + edge_serial->interrupt_in_endpoint = endpoint->bEndpointAddress; + + /* set up our interrupt urb */ + usb_fill_int_urb(edge_serial->interrupt_read_urb, + dev, + usb_rcvintpipe(dev, endpoint->bEndpointAddress), + edge_serial->interrupt_in_buffer, + buffer_size, + edge_interrupt_callback, + edge_serial, + endpoint->bInterval); + + interrupt_in_found = TRUE; + } + + if ((!bulk_in_found) && + (usb_endpoint_is_bulk_in(endpoint))) { + /* we found a bulk in endpoint */ + dbg("found bulk in"); + + /* not set up yet, so do it now */ + edge_serial->read_urb = usb_alloc_urb(0, GFP_KERNEL); + if (!edge_serial->read_urb) { + err("out of memory"); + return -ENOMEM; + } + edge_serial->bulk_in_buffer = kmalloc(buffer_size, GFP_KERNEL); + if (!edge_serial->bulk_in_buffer) { + err ("out of memory"); + usb_free_urb(edge_serial->read_urb); + return -ENOMEM; + } + edge_serial->bulk_in_endpoint = endpoint->bEndpointAddress; + + /* set up our bulk in urb */ + usb_fill_bulk_urb(edge_serial->read_urb, dev, + usb_rcvbulkpipe(dev, endpoint->bEndpointAddress), + edge_serial->bulk_in_buffer, + endpoint->wMaxPacketSize, + edge_bulk_in_callback, + edge_serial); + bulk_in_found = TRUE; + } + + if ((!bulk_out_found) && + (usb_endpoint_is_bulk_out(endpoint))) { + /* we found a bulk out endpoint */ + dbg("found bulk out"); + edge_serial->bulk_out_endpoint = endpoint->bEndpointAddress; + bulk_out_found = TRUE; + } + } + + if ((!interrupt_in_found) || (!bulk_in_found) || (!bulk_out_found)) { + err ("Error - the proper endpoints were not found!"); + return -ENODEV; + } + + /* start interrupt read for this edgeport this interrupt will + * continue as long as the edgeport is connected */ + response = usb_submit_urb(edge_serial->interrupt_read_urb, GFP_KERNEL); + if (response) + err("%s - Error %d submitting control urb", __FUNCTION__, response); + } + return response; } @@ -2815,6 +3034,7 @@ static int edge_startup (struct usb_seri ****************************************************************************/ static void edge_shutdown (struct usb_serial *serial) { + struct edgeport_serial *edge_serial = usb_get_serial_data(serial); int i; dbg("%s", __FUNCTION__); @@ -2824,7 +3044,18 @@ static void edge_shutdown (struct usb_se kfree (usb_get_serial_port_data(serial->port[i])); usb_set_serial_port_data(serial->port[i], NULL); } - kfree (usb_get_serial_data(serial)); + /* free up our endpoint stuff */ + if (edge_serial->is_epic) { + usb_unlink_urb(edge_serial->interrupt_read_urb); + usb_free_urb(edge_serial->interrupt_read_urb); + kfree(edge_serial->interrupt_in_buffer); + + usb_unlink_urb(edge_serial->read_urb); + usb_free_urb(edge_serial->read_urb); + kfree(edge_serial->bulk_in_buffer); + } + + kfree(edge_serial); usb_set_serial_data(serial, NULL); } @@ -2846,6 +3077,9 @@ static int __init edgeport_init(void) retval = usb_serial_register(&edgeport_8port_device); if (retval) goto failed_8port_device_register; + retval = usb_serial_register(&epic_device); + if (retval) + goto failed_epic_device_register; retval = usb_register(&io_driver); if (retval) goto failed_usb_register; @@ -2853,6 +3087,8 @@ static int __init edgeport_init(void) return 0; failed_usb_register: + usb_serial_deregister(&epic_device); +failed_epic_device_register: usb_serial_deregister(&edgeport_8port_device); failed_8port_device_register: usb_serial_deregister(&edgeport_4port_device); @@ -2873,6 +3109,7 @@ static void __exit edgeport_exit (void) usb_serial_deregister (&edgeport_2port_device); usb_serial_deregister (&edgeport_4port_device); usb_serial_deregister (&edgeport_8port_device); + usb_serial_deregister (&epic_device); } module_init(edgeport_init); diff --git a/drivers/usb/serial/io_edgeport.h b/drivers/usb/serial/io_edgeport.h index 123fa8a..29a913a 100644 --- a/drivers/usb/serial/io_edgeport.h +++ b/drivers/usb/serial/io_edgeport.h @@ -111,10 +111,12 @@ struct edgeport_product_info { __le16 FirmwareBuildNumber; /* zzzz (LE format) */ __u8 ManufactureDescDate[3]; /* MM/DD/YY when descriptor template was compiled */ - __u8 Unused1[1]; /* Available */ + __u8 HardwareType; __u8 iDownloadFile; /* What to download to EPiC device */ - __u8 Unused2[2]; /* Available */ + __u8 EpicVer; /* What version of EPiC spec this device supports */ + + struct edge_compatibility_bits Epic; }; /* diff --git a/drivers/usb/serial/io_tables.h b/drivers/usb/serial/io_tables.h index fad561c..6d30087 100644 --- a/drivers/usb/serial/io_tables.h +++ b/drivers/usb/serial/io_tables.h @@ -47,6 +47,18 @@ static struct usb_device_id edgeport_8po { } }; +static struct usb_device_id Epic_port_id_table [] = { + { USB_DEVICE(USB_VENDOR_ID_NCR, NCR_DEVICE_ID_EPIC_0202) }, + { USB_DEVICE(USB_VENDOR_ID_NCR, NCR_DEVICE_ID_EPIC_0203) }, + { USB_DEVICE(USB_VENDOR_ID_NCR, NCR_DEVICE_ID_EPIC_0310) }, + { USB_DEVICE(USB_VENDOR_ID_NCR, NCR_DEVICE_ID_EPIC_0311) }, + { USB_DEVICE(USB_VENDOR_ID_NCR, NCR_DEVICE_ID_EPIC_0312) }, + { USB_DEVICE(USB_VENDOR_ID_AXIOHM, AXIOHM_DEVICE_ID_EPIC_A758) }, + { USB_DEVICE(USB_VENDOR_ID_AXIOHM, AXIOHM_DEVICE_ID_EPIC_A794) }, + { USB_DEVICE(USB_VENDOR_ID_AXIOHM, AXIOHM_DEVICE_ID_EPIC_A225) }, + { } +}; + /* Devices that this driver supports */ static struct usb_device_id id_table_combined [] = { { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_EDGEPORT_4) }, @@ -70,17 +82,34 @@ static struct usb_device_id id_table_com { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_EDGEPORT_8R) }, { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_EDGEPORT_8RR) }, { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_EDGEPORT_412_8) }, + { USB_DEVICE(USB_VENDOR_ID_NCR, NCR_DEVICE_ID_EPIC_0202) }, + { USB_DEVICE(USB_VENDOR_ID_NCR, NCR_DEVICE_ID_EPIC_0203) }, + { USB_DEVICE(USB_VENDOR_ID_NCR, NCR_DEVICE_ID_EPIC_0310) }, + { USB_DEVICE(USB_VENDOR_ID_NCR, NCR_DEVICE_ID_EPIC_0311) }, + { USB_DEVICE(USB_VENDOR_ID_NCR, NCR_DEVICE_ID_EPIC_0312) }, + { USB_DEVICE(USB_VENDOR_ID_AXIOHM, AXIOHM_DEVICE_ID_EPIC_A758) }, + { USB_DEVICE(USB_VENDOR_ID_AXIOHM, AXIOHM_DEVICE_ID_EPIC_A794) }, + { USB_DEVICE(USB_VENDOR_ID_AXIOHM, AXIOHM_DEVICE_ID_EPIC_A225) }, { } /* Terminating entry */ }; MODULE_DEVICE_TABLE (usb, id_table_combined); +static struct usb_driver io_driver = { + .name = "io_edgeport", + .probe = usb_serial_probe, + .disconnect = usb_serial_disconnect, + .id_table = id_table_combined, + .no_dynamic_id = 1, +}; + static struct usb_serial_driver edgeport_2port_device = { .driver = { .owner = THIS_MODULE, .name = "edgeport_2", }, .description = "Edgeport 2 port adapter", + .usb_driver = &io_driver, .id_table = edgeport_2port_id_table, .num_interrupt_in = 1, .num_bulk_in = 1, @@ -111,6 +140,7 @@ static struct usb_serial_driver edgeport .name = "edgeport_4", }, .description = "Edgeport 4 port adapter", + .usb_driver = &io_driver, .id_table = edgeport_4port_id_table, .num_interrupt_in = 1, .num_bulk_in = 1, @@ -141,6 +171,7 @@ static struct usb_serial_driver edgeport .name = "edgeport_8", }, .description = "Edgeport 8 port adapter", + .usb_driver = &io_driver, .id_table = edgeport_8port_id_table, .num_interrupt_in = 1, .num_bulk_in = 1, @@ -165,5 +196,35 @@ static struct usb_serial_driver edgeport .write_bulk_callback = edge_bulk_out_data_callback, }; +static struct usb_serial_driver epic_device = { + .driver = { + .owner = THIS_MODULE, + .name = "epic", + }, + .description = "EPiC device", + .id_table = Epic_port_id_table, + .num_interrupt_in = 1, + .num_bulk_in = 1, + .num_bulk_out = 1, + .num_ports = 1, + .open = edge_open, + .close = edge_close, + .throttle = edge_throttle, + .unthrottle = edge_unthrottle, + .attach = edge_startup, + .shutdown = edge_shutdown, + .ioctl = edge_ioctl, + .set_termios = edge_set_termios, + .tiocmget = edge_tiocmget, + .tiocmset = edge_tiocmset, + .write = edge_write, + .write_room = edge_write_room, + .chars_in_buffer = edge_chars_in_buffer, + .break_ctl = edge_break, + .read_int_callback = edge_interrupt_callback, + .read_bulk_callback = edge_bulk_in_callback, + .write_bulk_callback = edge_bulk_out_data_callback, +}; + #endif diff --git a/drivers/usb/serial/io_ti.c b/drivers/usb/serial/io_ti.c index 980285c..544098d 100644 --- a/drivers/usb/serial/io_ti.c +++ b/drivers/usb/serial/io_ti.c @@ -2979,6 +2979,7 @@ static struct usb_serial_driver edgeport .name = "edgeport_ti_1", }, .description = "Edgeport TI 1 port adapter", + .usb_driver = &io_driver, .id_table = edgeport_1port_id_table, .num_interrupt_in = 1, .num_bulk_in = 1, @@ -3009,6 +3010,7 @@ static struct usb_serial_driver edgeport .name = "edgeport_ti_2", }, .description = "Edgeport TI 2 port adapter", + .usb_driver = &io_driver, .id_table = edgeport_2port_id_table, .num_interrupt_in = 1, .num_bulk_in = 2, diff --git a/drivers/usb/serial/io_usbvend.h b/drivers/usb/serial/io_usbvend.h index f1804fd..e57fa11 100644 --- a/drivers/usb/serial/io_usbvend.h +++ b/drivers/usb/serial/io_usbvend.h @@ -30,6 +30,7 @@ #define _USBVEND_H #define USB_VENDOR_ID_ION 0x1608 // Our VID #define USB_VENDOR_ID_TI 0x0451 // TI VID +#define USB_VENDOR_ID_AXIOHM 0x05D9 /* Axiohm VID */ // // Definitions of USB product IDs (PID) @@ -334,6 +335,10 @@ struct edge_compatibility_bits }; +#define EDGE_COMPATIBILITY_MASK0 0x0001 +#define EDGE_COMPATIBILITY_MASK1 0x3FFF +#define EDGE_COMPATIBILITY_MASK2 0x0001 + struct edge_compatibility_descriptor { __u8 Length; // Descriptor Length (per USB spec) diff --git a/drivers/usb/serial/ipaq.c b/drivers/usb/serial/ipaq.c index 42f757a..a408184 100644 --- a/drivers/usb/serial/ipaq.c +++ b/drivers/usb/serial/ipaq.c @@ -563,6 +563,7 @@ static struct usb_serial_driver ipaq_dev .name = "ipaq", }, .description = "PocketPC PDA", + .usb_driver = &ipaq_driver, .id_table = ipaq_id_table, .num_interrupt_in = NUM_DONT_CARE, .num_bulk_in = 1, diff --git a/drivers/usb/serial/ipw.c b/drivers/usb/serial/ipw.c index d3b9a35..1bc5860 100644 --- a/drivers/usb/serial/ipw.c +++ b/drivers/usb/serial/ipw.c @@ -442,6 +442,7 @@ static struct usb_serial_driver ipw_devi .name = "ipw", }, .description = "IPWireless converter", + .usb_driver = &usb_ipw_driver, .id_table = usb_ipw_ids, .num_interrupt_in = NUM_DONT_CARE, .num_bulk_in = 1, diff --git a/drivers/usb/serial/ir-usb.c b/drivers/usb/serial/ir-usb.c index 8fdf486..9d847f6 100644 --- a/drivers/usb/serial/ir-usb.c +++ b/drivers/usb/serial/ir-usb.c @@ -138,6 +138,7 @@ static struct usb_serial_driver ir_devic .name = "ir-usb", }, .description = "IR Dongle", + .usb_driver = &ir_driver, .id_table = id_table, .num_interrupt_in = 1, .num_bulk_in = 1, diff --git a/drivers/usb/serial/keyspan.c b/drivers/usb/serial/keyspan.c index 9d2fdfd..e6966f1 100644 --- a/drivers/usb/serial/keyspan.c +++ b/drivers/usb/serial/keyspan.c @@ -1275,11 +1275,31 @@ static int keyspan_fake_startup (struct } /* Helper functions used by keyspan_setup_urbs */ +static struct usb_endpoint_descriptor const *find_ep(struct usb_serial const *serial, + int endpoint) +{ + struct usb_host_interface *iface_desc; + struct usb_endpoint_descriptor *ep; + int i; + + iface_desc = serial->interface->cur_altsetting; + for (i = 0; i < iface_desc->desc.bNumEndpoints; ++i) { + ep = &iface_desc->endpoint[i].desc; + if (ep->bEndpointAddress == endpoint) + return ep; + } + dev_warn(&serial->interface->dev, "found no endpoint descriptor for " + "endpoint %x\n", endpoint); + return NULL; +} + static struct urb *keyspan_setup_urb (struct usb_serial *serial, int endpoint, int dir, void *ctx, char *buf, int len, void (*callback)(struct urb *)) { struct urb *urb; + struct usb_endpoint_descriptor const *ep_desc; + char const *ep_type_name; if (endpoint == -1) return NULL; /* endpoint not needed */ @@ -1291,11 +1311,32 @@ static struct urb *keyspan_setup_urb (st return NULL; } - /* Fill URB using supplied data. */ - usb_fill_bulk_urb(urb, serial->dev, - usb_sndbulkpipe(serial->dev, endpoint) | dir, - buf, len, callback, ctx); + ep_desc = find_ep(serial, endpoint); + if (!ep_desc) { + /* leak the urb, something's wrong and the callers don't care */ + return urb; + } + if (usb_endpoint_xfer_int(ep_desc)) { + ep_type_name = "INT"; + usb_fill_int_urb(urb, serial->dev, + usb_sndintpipe(serial->dev, endpoint) | dir, + buf, len, callback, ctx, + ep_desc->bInterval); + } else if (usb_endpoint_xfer_bulk(ep_desc)) { + ep_type_name = "BULK"; + usb_fill_bulk_urb(urb, serial->dev, + usb_sndbulkpipe(serial->dev, endpoint) | dir, + buf, len, callback, ctx); + } else { + dev_warn(&serial->interface->dev, + "unsupported endpoint type %x\n", + ep_desc->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK); + usb_free_urb(urb); + return NULL; + } + dbg("%s - using urb %p for %s endpoint %x", + __func__, urb, ep_type_name, endpoint); return urb; } diff --git a/drivers/usb/serial/keyspan.h b/drivers/usb/serial/keyspan.h index 6413d73..c6830cb 100644 --- a/drivers/usb/serial/keyspan.h +++ b/drivers/usb/serial/keyspan.h @@ -229,7 +229,6 @@ #define keyspan_usa19w_product_id 0x010 #define keyspan_usa28_product_id 0x010f #define keyspan_usa28x_product_id 0x0110 #define keyspan_usa28xa_product_id 0x0115 -#define keyspan_usa28xb_product_id 0x0110 #define keyspan_usa49w_product_id 0x010a #define keyspan_usa49wlc_product_id 0x012a @@ -511,7 +510,6 @@ static struct usb_device_id keyspan_ids_ { USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa28_product_id) }, { USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa28x_product_id) }, { USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa28xa_product_id) }, - { USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa28xb_product_id) }, { USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa49w_product_id)}, { USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa49wlc_product_id)}, { } /* Terminating entry */ @@ -559,7 +557,6 @@ static struct usb_device_id keyspan_2por { USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa28_product_id) }, { USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa28x_product_id) }, { USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa28xa_product_id) }, - { USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa28xb_product_id) }, { } /* Terminating entry */ }; @@ -576,6 +573,7 @@ static struct usb_serial_driver keyspan_ .name = "keyspan_no_firm", }, .description = "Keyspan - (without firmware)", + .usb_driver = &keyspan_driver, .id_table = keyspan_pre_ids, .num_interrupt_in = NUM_DONT_CARE, .num_bulk_in = NUM_DONT_CARE, @@ -590,6 +588,7 @@ static struct usb_serial_driver keyspan_ .name = "keyspan_1", }, .description = "Keyspan 1 port adapter", + .usb_driver = &keyspan_driver, .id_table = keyspan_1port_ids, .num_interrupt_in = NUM_DONT_CARE, .num_bulk_in = NUM_DONT_CARE, @@ -617,6 +616,7 @@ static struct usb_serial_driver keyspan_ .name = "keyspan_2", }, .description = "Keyspan 2 port adapter", + .usb_driver = &keyspan_driver, .id_table = keyspan_2port_ids, .num_interrupt_in = NUM_DONT_CARE, .num_bulk_in = NUM_DONT_CARE, @@ -644,6 +644,7 @@ static struct usb_serial_driver keyspan_ .name = "keyspan_4", }, .description = "Keyspan 4 port adapter", + .usb_driver = &keyspan_driver, .id_table = keyspan_4port_ids, .num_interrupt_in = NUM_DONT_CARE, .num_bulk_in = 5, diff --git a/drivers/usb/serial/keyspan_pda.c b/drivers/usb/serial/keyspan_pda.c index 126b970..dd0b66a 100644 --- a/drivers/usb/serial/keyspan_pda.c +++ b/drivers/usb/serial/keyspan_pda.c @@ -182,13 +182,8 @@ static void keyspan_pda_wakeup_write(str struct keyspan_pda_private *priv = container_of(work, struct keyspan_pda_private, wakeup_work); struct usb_serial_port *port = priv->port; - struct tty_struct *tty = port->tty; - /* wake up port processes */ - wake_up_interruptible( &port->write_wait ); - - /* wake up line discipline */ - tty_wakeup(tty); + tty_wakeup(port->tty); } static void keyspan_pda_request_unthrottle(struct work_struct *work) @@ -793,6 +788,7 @@ static struct usb_serial_driver keyspan_ .name = "keyspan_pda_pre", }, .description = "Keyspan PDA - (prerenumeration)", + .usb_driver = &keyspan_pda_driver, .id_table = id_table_fake, .num_interrupt_in = NUM_DONT_CARE, .num_bulk_in = NUM_DONT_CARE, @@ -809,6 +805,7 @@ static struct usb_serial_driver xircom_p .name = "xircom_no_firm", }, .description = "Xircom / Entregra PGS - (prerenumeration)", + .usb_driver = &keyspan_pda_driver, .id_table = id_table_fake_xircom, .num_interrupt_in = NUM_DONT_CARE, .num_bulk_in = NUM_DONT_CARE, @@ -824,6 +821,7 @@ static struct usb_serial_driver keyspan_ .name = "keyspan_pda", }, .description = "Keyspan PDA", + .usb_driver = &keyspan_pda_driver, .id_table = id_table_std, .num_interrupt_in = 1, .num_bulk_in = 0, diff --git a/drivers/usb/serial/kl5kusb105.c b/drivers/usb/serial/kl5kusb105.c index 5c4b06a..b2097c4 100644 --- a/drivers/usb/serial/kl5kusb105.c +++ b/drivers/usb/serial/kl5kusb105.c @@ -124,6 +124,7 @@ static struct usb_serial_driver kl5kusb1 .name = "kl5kusb105d", }, .description = "KL5KUSB105D / PalmConnect", + .usb_driver = &kl5kusb105d_driver, .id_table = id_table, .num_interrupt_in = 1, .num_bulk_in = 1, diff --git a/drivers/usb/serial/kobil_sct.c b/drivers/usb/serial/kobil_sct.c index 62bea0c..0683b51 100644 --- a/drivers/usb/serial/kobil_sct.c +++ b/drivers/usb/serial/kobil_sct.c @@ -110,6 +110,7 @@ static struct usb_serial_driver kobil_de .name = "kobil", }, .description = "KOBIL USB smart card terminal", + .usb_driver = &kobil_driver, .id_table = id_table, .num_interrupt_in = NUM_DONT_CARE, .num_bulk_in = 0, diff --git a/drivers/usb/serial/mct_u232.c b/drivers/usb/serial/mct_u232.c index 38b1d17..4cd839b 100644 --- a/drivers/usb/serial/mct_u232.c +++ b/drivers/usb/serial/mct_u232.c @@ -137,6 +137,7 @@ static struct usb_serial_driver mct_u232 .name = "mct_u232", }, .description = "MCT U232", + .usb_driver = &mct_u232_driver, .id_table = id_table_combined, .num_interrupt_in = 2, .num_bulk_in = 0, diff --git a/drivers/usb/serial/mos7720.c b/drivers/usb/serial/mos7720.c index e55f4ed..2d588fb 100644 --- a/drivers/usb/serial/mos7720.c +++ b/drivers/usb/serial/mos7720.c @@ -269,18 +269,8 @@ static void mos7720_bulk_out_data_callba tty = mos7720_port->port->tty; - if (tty && mos7720_port->open) { - /* let the tty driver wakeup if it has a special * - * write_wakeup function */ - if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && - tty->ldisc.write_wakeup) - (tty->ldisc.write_wakeup)(tty); - - /* tell the tty driver that something has changed */ - wake_up_interruptible(&tty->write_wait); - } - - /* schedule_work(&mos7720_port->port->work); */ + if (tty && mos7720_port->open) + tty_wakeup(tty); } /* @@ -1605,12 +1595,21 @@ static void mos7720_shutdown(struct usb_ usb_set_serial_data(serial, NULL); } +static struct usb_driver usb_driver = { + .name = "moschip7720", + .probe = usb_serial_probe, + .disconnect = usb_serial_disconnect, + .id_table = moschip_port_id_table, + .no_dynamic_id = 1, +}; + static struct usb_serial_driver moschip7720_2port_driver = { .driver = { .owner = THIS_MODULE, .name = "moschip7720", }, .description = "Moschip 2 port adapter", + .usb_driver = &usb_driver, .id_table = moschip_port_id_table, .num_interrupt_in = 1, .num_bulk_in = 2, @@ -1631,13 +1630,6 @@ static struct usb_serial_driver moschip7 .read_bulk_callback = mos7720_bulk_in_callback, }; -static struct usb_driver usb_driver = { - .name = "moschip7720", - .probe = usb_serial_probe, - .disconnect = usb_serial_disconnect, - .id_table = moschip_port_id_table, -}; - static int __init moschip7720_init(void) { int retval; diff --git a/drivers/usb/serial/mos7840.c b/drivers/usb/serial/mos7840.c index 83f6614..c6cca85 100644 --- a/drivers/usb/serial/mos7840.c +++ b/drivers/usb/serial/mos7840.c @@ -755,18 +755,8 @@ static void mos7840_bulk_out_data_callba tty = mos7840_port->port->tty; - if (tty && mos7840_port->open) { - /* let the tty driver wakeup if it has a special * - * write_wakeup function */ - - if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) - && tty->ldisc.write_wakeup) { - (tty->ldisc.write_wakeup) (tty); - } - - /* tell the tty driver that something has changed */ - wake_up_interruptible(&tty->write_wait); - } + if (tty && mos7840_port->open) + tty_wakeup(tty); } @@ -2834,12 +2824,21 @@ static void mos7840_shutdown(struct usb_ } +static struct usb_driver io_driver = { + .name = "mos7840", + .probe = usb_serial_probe, + .disconnect = usb_serial_disconnect, + .id_table = moschip_id_table_combined, + .no_dynamic_id = 1, +}; + static struct usb_serial_driver moschip7840_4port_device = { .driver = { .owner = THIS_MODULE, .name = "mos7840", }, .description = DRIVER_DESC, + .usb_driver = &io_driver, .id_table = moschip_port_id_table, .num_interrupt_in = 1, //NUM_DONT_CARE,//1, #ifdef check @@ -2869,13 +2868,6 @@ #endif .read_int_callback = mos7840_interrupt_callback, }; -static struct usb_driver io_driver = { - .name = "mos7840", - .probe = usb_serial_probe, - .disconnect = usb_serial_disconnect, - .id_table = moschip_id_table_combined, -}; - /**************************************************************************** * moschip7840_init * This is called by the module subsystem, or on startup to initialize us diff --git a/drivers/usb/serial/navman.c b/drivers/usb/serial/navman.c index 054abee..9070111 100644 --- a/drivers/usb/serial/navman.c +++ b/drivers/usb/serial/navman.c @@ -119,6 +119,7 @@ static struct usb_serial_driver navman_d .name = "navman", }, .id_table = id_table, + .usb_driver = &navman_driver, .num_interrupt_in = NUM_DONT_CARE, .num_bulk_in = NUM_DONT_CARE, .num_bulk_out = NUM_DONT_CARE, diff --git a/drivers/usb/serial/omninet.c b/drivers/usb/serial/omninet.c index bc91d3b..0216ac1 100644 --- a/drivers/usb/serial/omninet.c +++ b/drivers/usb/serial/omninet.c @@ -93,6 +93,7 @@ static struct usb_serial_driver zyxel_om .name = "omninet", }, .description = "ZyXEL - omni.net lcd plus usb", + .usb_driver = &omninet_driver, .id_table = id_table, .num_interrupt_in = 1, .num_bulk_in = 1, diff --git a/drivers/usb/serial/option.c b/drivers/usb/serial/option.c index 0fed43a..ced9f32 100644 --- a/drivers/usb/serial/option.c +++ b/drivers/usb/serial/option.c @@ -135,6 +135,7 @@ static struct usb_serial_driver option_1 .name = "option1", }, .description = "GSM modem (1-port)", + .usb_driver = &option_driver, .id_table = option_ids1, .num_interrupt_in = NUM_DONT_CARE, .num_bulk_in = NUM_DONT_CARE, diff --git a/drivers/usb/serial/pl2303.c b/drivers/usb/serial/pl2303.c index 5dc2ac9..6c083d4 100644 --- a/drivers/usb/serial/pl2303.c +++ b/drivers/usb/serial/pl2303.c @@ -1118,6 +1118,7 @@ static struct usb_serial_driver pl2303_d .name = "pl2303", }, .id_table = id_table, + .usb_driver = &pl2303_driver, .num_interrupt_in = NUM_DONT_CARE, .num_bulk_in = 1, .num_bulk_out = 1, diff --git a/drivers/usb/serial/safe_serial.c b/drivers/usb/serial/safe_serial.c index 30b7ebc..5a03a3f 100644 --- a/drivers/usb/serial/safe_serial.c +++ b/drivers/usb/serial/safe_serial.c @@ -402,6 +402,7 @@ static struct usb_serial_driver safe_dev .name = "safe_serial", }, .id_table = id_table, + .usb_driver = &safe_driver, .num_interrupt_in = NUM_DONT_CARE, .num_bulk_in = NUM_DONT_CARE, .num_bulk_out = NUM_DONT_CARE, diff --git a/drivers/usb/serial/sierra.c b/drivers/usb/serial/sierra.c index 6d8e91e..ecedd83 100644 --- a/drivers/usb/serial/sierra.c +++ b/drivers/usb/serial/sierra.c @@ -13,10 +13,9 @@ Portions based on the option driver by Matthias Urlichs Whom based his on the Keyspan driver by Hugh Blemings - History: */ -#define DRIVER_VERSION "v.1.0.5" +#define DRIVER_VERSION "v.1.0.6" #define DRIVER_AUTHOR "Kevin Lloyd " #define DRIVER_DESC "USB Driver for Sierra Wireless USB modems" @@ -31,14 +30,15 @@ #include static struct usb_device_id id_table [] = { + { USB_DEVICE(0x1199, 0x0017) }, /* Sierra Wireless EM5625 */ { USB_DEVICE(0x1199, 0x0018) }, /* Sierra Wireless MC5720 */ + { USB_DEVICE(0x1199, 0x0218) }, /* Sierra Wireless MC5720 */ { USB_DEVICE(0x1199, 0x0020) }, /* Sierra Wireless MC5725 */ - { USB_DEVICE(0x1199, 0x0017) }, /* Sierra Wireless EM5625 */ { USB_DEVICE(0x1199, 0x0019) }, /* Sierra Wireless AirCard 595 */ - { USB_DEVICE(0x1199, 0x0218) }, /* Sierra Wireless MC5720 */ + { USB_DEVICE(0x1199, 0x0021) }, /* Sierra Wireless AirCard 597E */ { USB_DEVICE(0x1199, 0x6802) }, /* Sierra Wireless MC8755 */ + { USB_DEVICE(0x1199, 0x6804) }, /* Sierra Wireless MC8755 */ { USB_DEVICE(0x1199, 0x6803) }, /* Sierra Wireless MC8765 */ - { USB_DEVICE(0x1199, 0x6804) }, /* Sierra Wireless MC8755 for Europe */ { USB_DEVICE(0x1199, 0x6812) }, /* Sierra Wireless MC8775 */ { USB_DEVICE(0x1199, 0x6820) }, /* Sierra Wireless AirCard 875 */ @@ -55,14 +55,15 @@ static struct usb_device_id id_table_1po }; static struct usb_device_id id_table_3port [] = { + { USB_DEVICE(0x1199, 0x0017) }, /* Sierra Wireless EM5625 */ { USB_DEVICE(0x1199, 0x0018) }, /* Sierra Wireless MC5720 */ + { USB_DEVICE(0x1199, 0x0218) }, /* Sierra Wireless MC5720 */ { USB_DEVICE(0x1199, 0x0020) }, /* Sierra Wireless MC5725 */ - { USB_DEVICE(0x1199, 0x0017) }, /* Sierra Wireless EM5625 */ { USB_DEVICE(0x1199, 0x0019) }, /* Sierra Wireless AirCard 595 */ - { USB_DEVICE(0x1199, 0x0218) }, /* Sierra Wireless MC5720 */ + { USB_DEVICE(0x1199, 0x0021) }, /* Sierra Wireless AirCard 597E */ { USB_DEVICE(0x1199, 0x6802) }, /* Sierra Wireless MC8755 */ + { USB_DEVICE(0x1199, 0x6804) }, /* Sierra Wireless MC8755 */ { USB_DEVICE(0x1199, 0x6803) }, /* Sierra Wireless MC8765 */ - { USB_DEVICE(0x1199, 0x6804) }, /* Sierra Wireless MC8755 for Europe */ { USB_DEVICE(0x1199, 0x6812) }, /* Sierra Wireless MC8775 */ { USB_DEVICE(0x1199, 0x6820) }, /* Sierra Wireless AirCard 875 */ { } @@ -81,7 +82,7 @@ static int debug; /* per port private data */ #define N_IN_URB 4 -#define N_OUT_URB 1 +#define N_OUT_URB 4 #define IN_BUFLEN 4096 #define OUT_BUFLEN 128 @@ -396,6 +397,8 @@ static int sierra_open(struct usb_serial struct usb_serial *serial = port->serial; int i, err; struct urb *urb; + int result; + __u16 set_mode_dzero = 0x0000; portdata = usb_get_serial_port_data(port); @@ -442,6 +445,12 @@ static int sierra_open(struct usb_serial port->tty->low_latency = 1; + /* set mode to D0 */ + result = usb_control_msg(serial->dev, + usb_rcvctrlpipe(serial->dev, 0), + 0x00, 0x40, set_mode_dzero, 0, NULL, + 0, USB_CTRL_SET_TIMEOUT); + sierra_send_setup(port); return (0); @@ -614,6 +623,7 @@ static struct usb_serial_driver sierra_1 }, .description = "Sierra USB modem (1 port)", .id_table = id_table_1port, + .usb_driver = &sierra_driver, .num_interrupt_in = NUM_DONT_CARE, .num_bulk_in = 1, .num_bulk_out = 1, @@ -642,6 +652,7 @@ static struct usb_serial_driver sierra_3 }, .description = "Sierra USB modem (3 port)", .id_table = id_table_3port, + .usb_driver = &sierra_driver, .num_interrupt_in = NUM_DONT_CARE, .num_bulk_in = 3, .num_bulk_out = 3, diff --git a/drivers/usb/serial/ti_usb_3410_5052.c b/drivers/usb/serial/ti_usb_3410_5052.c index 8318900..4203e2b 100644 --- a/drivers/usb/serial/ti_usb_3410_5052.c +++ b/drivers/usb/serial/ti_usb_3410_5052.c @@ -262,6 +262,7 @@ static struct usb_serial_driver ti_1port .name = "ti_usb_3410_5052_1", }, .description = "TI USB 3410 1 port adapter", + .usb_driver = &ti_usb_driver, .id_table = ti_id_table_3410, .num_interrupt_in = 1, .num_bulk_in = 1, @@ -292,6 +293,7 @@ static struct usb_serial_driver ti_2port .name = "ti_usb_3410_5052_2", }, .description = "TI USB 5052 2 port adapter", + .usb_driver = &ti_usb_driver, .id_table = ti_id_table_5052, .num_interrupt_in = 1, .num_bulk_in = 2, diff --git a/drivers/usb/serial/usb-serial.c b/drivers/usb/serial/usb-serial.c index 716f680..6bf22a2 100644 --- a/drivers/usb/serial/usb-serial.c +++ b/drivers/usb/serial/usb-serial.c @@ -59,14 +59,19 @@ static struct usb_driver usb_serial_driv static int debug; static struct usb_serial *serial_table[SERIAL_TTY_MINORS]; /* initially all NULL */ +static spinlock_t table_lock; static LIST_HEAD(usb_serial_driver_list); struct usb_serial *usb_serial_get_by_index(unsigned index) { - struct usb_serial *serial = serial_table[index]; + struct usb_serial *serial; + + spin_lock(&table_lock); + serial = serial_table[index]; if (serial) kref_get(&serial->kref); + spin_unlock(&table_lock); return serial; } @@ -78,6 +83,7 @@ static struct usb_serial *get_free_seria dbg("%s %d", __FUNCTION__, num_ports); *minor = 0; + spin_lock(&table_lock); for (i = 0; i < SERIAL_TTY_MINORS; ++i) { if (serial_table[i]) continue; @@ -96,8 +102,10 @@ static struct usb_serial *get_free_seria dbg("%s - minor base = %d", __FUNCTION__, *minor); for (i = *minor; (i < (*minor + num_ports)) && (i < SERIAL_TTY_MINORS); ++i) serial_table[i] = serial; + spin_unlock(&table_lock); return serial; } + spin_unlock(&table_lock); return NULL; } @@ -110,9 +118,11 @@ static void return_serial(struct usb_ser if (serial == NULL) return; + spin_lock(&table_lock); for (i = 0; i < serial->num_ports; ++i) { serial_table[serial->minor + i] = NULL; } + spin_unlock(&table_lock); } static void destroy_serial(struct kref *kref) @@ -271,7 +281,7 @@ static void serial_close(struct tty_stru static int serial_write (struct tty_struct * tty, const unsigned char *buf, int count) { struct usb_serial_port *port = tty->driver_data; - int retval = -EINVAL; + int retval = -ENODEV; if (!port || port->serial->dev->state == USB_STATE_NOTATTACHED) goto exit; @@ -279,6 +289,7 @@ static int serial_write (struct tty_stru dbg("%s - port %d, %d byte(s)", __FUNCTION__, port->number, count); if (!port->open_count) { + retval = -EINVAL; dbg("%s - port not opened", __FUNCTION__); goto exit; } @@ -559,15 +570,20 @@ static void port_release(struct device * port_free(port); } -static void port_free(struct usb_serial_port *port) +static void kill_traffic(struct usb_serial_port *port) { usb_kill_urb(port->read_urb); - usb_free_urb(port->read_urb); usb_kill_urb(port->write_urb); - usb_free_urb(port->write_urb); usb_kill_urb(port->interrupt_in_urb); - usb_free_urb(port->interrupt_in_urb); usb_kill_urb(port->interrupt_out_urb); +} + +static void port_free(struct usb_serial_port *port) +{ + kill_traffic(port); + usb_free_urb(port->read_urb); + usb_free_urb(port->write_urb); + usb_free_urb(port->interrupt_in_urb); usb_free_urb(port->interrupt_out_urb); kfree(port->bulk_in_buffer); kfree(port->bulk_out_buffer); @@ -596,6 +612,39 @@ static struct usb_serial * create_serial return serial; } +static const struct usb_device_id *match_dynamic_id(struct usb_interface *intf, + struct usb_serial_driver *drv) +{ + struct usb_dynid *dynid; + + spin_lock(&drv->dynids.lock); + list_for_each_entry(dynid, &drv->dynids.list, node) { + if (usb_match_one_id(intf, &dynid->id)) { + spin_unlock(&drv->dynids.lock); + return &dynid->id; + } + } + spin_unlock(&drv->dynids.lock); + return NULL; +} + +static const struct usb_device_id *get_iface_id(struct usb_serial_driver *drv, + struct usb_interface *intf) +{ + const struct usb_device_id *id; + + id = usb_match_id(intf, drv->id_table); + if (id) { + dbg("static descriptor matches"); + goto exit; + } + id = match_dynamic_id(intf, drv); + if (id) + dbg("dynamic descriptor matches"); +exit: + return id; +} + static struct usb_serial_driver *search_serial_device(struct usb_interface *iface) { struct list_head *p; @@ -605,11 +654,9 @@ static struct usb_serial_driver *search_ /* Check if the usb id matches a known device */ list_for_each(p, &usb_serial_driver_list) { t = list_entry(p, struct usb_serial_driver, driver_list); - id = usb_match_id(iface, t->id_table); - if (id != NULL) { - dbg("descriptor matches"); + id = get_iface_id(t, iface); + if (id) return t; - } } return NULL; @@ -639,14 +686,17 @@ int usb_serial_probe(struct usb_interfac int num_ports = 0; int max_endpoints; + lock_kernel(); /* guard against unloading a serial driver module */ type = search_serial_device(interface); if (!type) { + unlock_kernel(); dbg("none matched"); return -ENODEV; } serial = create_serial (dev, interface, type); if (!serial) { + unlock_kernel(); dev_err(&interface->dev, "%s - out of memory\n", __FUNCTION__); return -ENOMEM; } @@ -656,16 +706,18 @@ int usb_serial_probe(struct usb_interfac const struct usb_device_id *id; if (!try_module_get(type->driver.owner)) { + unlock_kernel(); dev_err(&interface->dev, "module get failed, exiting\n"); kfree (serial); return -EIO; } - id = usb_match_id(interface, type->id_table); + id = get_iface_id(type, interface); retval = type->probe(serial, id); module_put(type->driver.owner); if (retval) { + unlock_kernel(); dbg ("sub driver rejected device"); kfree (serial); return retval; @@ -735,6 +787,7 @@ #if defined(CONFIG_USB_SERIAL_PL2303) || * properly during a later invocation of usb_serial_probe */ if (num_bulk_in == 0 || num_bulk_out == 0) { + unlock_kernel(); dev_info(&interface->dev, "PL-2303 hack: descriptors matched but endpoints did not\n"); kfree (serial); return -ENODEV; @@ -750,6 +803,7 @@ #ifdef CONFIG_USB_SERIAL_GENERIC if (type == &usb_serial_generic_device) { num_ports = num_bulk_out; if (num_ports == 0) { + unlock_kernel(); dev_err(&interface->dev, "Generic device with no bulk out, not allowed.\n"); kfree (serial); return -EIO; @@ -760,6 +814,7 @@ #endif /* if this device type has a calc_num_ports function, call it */ if (type->calc_num_ports) { if (!try_module_get(type->driver.owner)) { + unlock_kernel(); dev_err(&interface->dev, "module get failed, exiting\n"); kfree (serial); return -EIO; @@ -771,12 +826,6 @@ #endif num_ports = type->num_ports; } - if (get_free_serial (serial, num_ports, &minor) == NULL) { - dev_err(&interface->dev, "No more free serial devices\n"); - kfree (serial); - return -ENOMEM; - } - serial->minor = minor; serial->num_ports = num_ports; serial->num_bulk_in = num_bulk_in; @@ -791,6 +840,8 @@ #endif max_endpoints = max(max_endpoints, num_interrupt_out); max_endpoints = max(max_endpoints, (int)serial->num_ports); serial->num_port_pointers = max_endpoints; + unlock_kernel(); + dbg("%s - setting up %d port structures for this device", __FUNCTION__, max_endpoints); for (i = 0; i < max_endpoints; ++i) { port = kzalloc(sizeof(struct usb_serial_port), GFP_KERNEL); @@ -925,6 +976,11 @@ #endif } } + if (get_free_serial (serial, num_ports, &minor) == NULL) { + dev_err(&interface->dev, "No more free serial devices\n"); + goto probe_error; + } + /* register all of the individual ports with the driver core */ for (i = 0; i < num_ports; ++i) { port = serial->port[i]; @@ -1002,8 +1058,11 @@ void usb_serial_disconnect(struct usb_in if (serial) { for (i = 0; i < serial->num_ports; ++i) { port = serial->port[i]; - if (port && port->tty) - tty_hangup(port->tty); + if (port) { + if (port->tty) + tty_hangup(port->tty); + kill_traffic(port); + } } /* let the last holder of this object * cause it to be cleaned up */ @@ -1040,6 +1099,7 @@ static int __init usb_serial_init(void) return -ENOMEM; /* Initialize our global data */ + spin_lock_init(&table_lock); for (i = 0; i < SERIAL_TTY_MINORS; ++i) { serial_table[i] = NULL; } @@ -1138,7 +1198,7 @@ static void fixup_generic(struct usb_ser set_to_generic_if_null(device, shutdown); } -int usb_serial_register(struct usb_serial_driver *driver) +int usb_serial_register(struct usb_serial_driver *driver) /* must be called with BKL held */ { int retval; @@ -1162,7 +1222,7 @@ int usb_serial_register(struct usb_seria } -void usb_serial_deregister(struct usb_serial_driver *device) +void usb_serial_deregister(struct usb_serial_driver *device) /* must be called with BKL held */ { info("USB Serial deregistering driver %s", device->description); list_del(&device->driver_list); diff --git a/drivers/usb/serial/visor.c b/drivers/usb/serial/visor.c index b09f060..2f59ff2 100644 --- a/drivers/usb/serial/visor.c +++ b/drivers/usb/serial/visor.c @@ -90,8 +90,6 @@ static struct usb_device_id id_table [] .driver_info = (kernel_ulong_t)&palm_os_4_probe }, { USB_DEVICE(PALM_VENDOR_ID, PALM_TUNGSTEN_Z_ID), .driver_info = (kernel_ulong_t)&palm_os_4_probe }, - { USB_DEVICE(PALM_VENDOR_ID, PALM_ZIRE31_ID), - .driver_info = (kernel_ulong_t)&palm_os_4_probe }, { USB_DEVICE(PALM_VENDOR_ID, PALM_ZIRE_ID), .driver_info = (kernel_ulong_t)&palm_os_4_probe }, { USB_DEVICE(SONY_VENDOR_ID, SONY_CLIE_4_0_ID), @@ -151,7 +149,6 @@ static struct usb_device_id id_table_com { USB_DEVICE(PALM_VENDOR_ID, PALM_TUNGSTEN_T_ID) }, { USB_DEVICE(PALM_VENDOR_ID, PALM_TREO_650) }, { USB_DEVICE(PALM_VENDOR_ID, PALM_TUNGSTEN_Z_ID) }, - { USB_DEVICE(PALM_VENDOR_ID, PALM_ZIRE31_ID) }, { USB_DEVICE(PALM_VENDOR_ID, PALM_ZIRE_ID) }, { USB_DEVICE(SONY_VENDOR_ID, SONY_CLIE_3_5_ID) }, { USB_DEVICE(SONY_VENDOR_ID, SONY_CLIE_4_0_ID) }, @@ -189,6 +186,7 @@ static struct usb_serial_driver handspri .name = "visor", }, .description = "Handspring Visor / Palm OS", + .usb_driver = &visor_driver, .id_table = id_table, .num_interrupt_in = NUM_DONT_CARE, .num_bulk_in = 2, @@ -219,6 +217,7 @@ static struct usb_serial_driver clie_5_d .name = "clie_5", }, .description = "Sony Clie 5.0", + .usb_driver = &visor_driver, .id_table = clie_id_5_table, .num_interrupt_in = NUM_DONT_CARE, .num_bulk_in = 2, @@ -249,6 +248,7 @@ static struct usb_serial_driver clie_3_5 .name = "clie_3.5", }, .description = "Sony Clie 3.5", + .usb_driver = &visor_driver, .id_table = clie_id_3_5_table, .num_interrupt_in = 0, .num_bulk_in = 1, diff --git a/drivers/usb/serial/visor.h b/drivers/usb/serial/visor.h index 765118d..4ce6f62 100644 --- a/drivers/usb/serial/visor.h +++ b/drivers/usb/serial/visor.h @@ -32,7 +32,6 @@ #define PALM_M130_ID 0x0050 #define PALM_TUNGSTEN_T_ID 0x0060 #define PALM_TREO_650 0x0061 #define PALM_TUNGSTEN_Z_ID 0x0031 -#define PALM_ZIRE31_ID 0x0061 #define PALM_ZIRE_ID 0x0070 #define PALM_M100_ID 0x0080 diff --git a/drivers/usb/serial/whiteheat.c b/drivers/usb/serial/whiteheat.c index 5483d85..bf16e9e 100644 --- a/drivers/usb/serial/whiteheat.c +++ b/drivers/usb/serial/whiteheat.c @@ -161,6 +161,7 @@ static struct usb_serial_driver whitehea .name = "whiteheatnofirm", }, .description = "Connect Tech - WhiteHEAT - (prerenumeration)", + .usb_driver = &whiteheat_driver, .id_table = id_table_prerenumeration, .num_interrupt_in = NUM_DONT_CARE, .num_bulk_in = NUM_DONT_CARE, @@ -176,6 +177,7 @@ static struct usb_serial_driver whitehea .name = "whiteheat", }, .description = "Connect Tech - WhiteHEAT", + .usb_driver = &whiteheat_driver, .id_table = id_table_std, .num_interrupt_in = NUM_DONT_CARE, .num_bulk_in = NUM_DONT_CARE, diff --git a/drivers/usb/storage/datafab.c b/drivers/usb/storage/datafab.c index 01d8971..c87ad1b 100644 --- a/drivers/usb/storage/datafab.c +++ b/drivers/usb/storage/datafab.c @@ -50,7 +50,6 @@ * in that routine. */ -#include #include #include diff --git a/drivers/usb/storage/initializers.c b/drivers/usb/storage/initializers.c index 5b06f92..3a41740 100644 --- a/drivers/usb/storage/initializers.c +++ b/drivers/usb/storage/initializers.c @@ -37,7 +37,6 @@ * 675 Mass Ave, Cambridge, MA 02139, USA. */ -#include #include #include "usb.h" diff --git a/drivers/usb/storage/jumpshot.c b/drivers/usb/storage/jumpshot.c index 5031aa9..003fcf5 100644 --- a/drivers/usb/storage/jumpshot.c +++ b/drivers/usb/storage/jumpshot.c @@ -47,7 +47,6 @@ * in that routine. */ -#include #include #include diff --git a/drivers/usb/storage/onetouch.c b/drivers/usb/storage/onetouch.c index e565d3d..6d3dad3 100644 --- a/drivers/usb/storage/onetouch.c +++ b/drivers/usb/storage/onetouch.c @@ -33,7 +33,6 @@ #include #include #include #include -#include #include #include "usb.h" #include "onetouch.h" diff --git a/drivers/usb/storage/scsiglue.c b/drivers/usb/storage/scsiglue.c index e1072d5..70234f5 100644 --- a/drivers/usb/storage/scsiglue.c +++ b/drivers/usb/storage/scsiglue.c @@ -110,23 +110,6 @@ static int slave_configure(struct scsi_d * the end, scatter-gather buffers follow page boundaries. */ blk_queue_dma_alignment(sdev->request_queue, (512 - 1)); - /* Set the SCSI level to at least 2. We'll leave it at 3 if that's - * what is originally reported. We need this to avoid confusing - * the SCSI layer with devices that report 0 or 1, but need 10-byte - * commands (ala ATAPI devices behind certain bridges, or devices - * which simply have broken INQUIRY data). - * - * NOTE: This means /dev/sg programs (ala cdrecord) will get the - * actual information. This seems to be the preference for - * programs like that. - * - * NOTE: This also means that /proc/scsi/scsi and sysfs may report - * the actual value or the modified one, depending on where the - * data comes from. - */ - if (sdev->scsi_level < SCSI_2) - sdev->scsi_level = sdev->sdev_target->scsi_level = SCSI_2; - /* Many devices have trouble transfering more than 32KB at a time, * while others have trouble with more than 64K. At this time we * are limiting both to 32K (64 sectores). @@ -176,7 +159,9 @@ static int slave_configure(struct scsi_d * a Get-Max-LUN request, we won't lose much by setting the * revision level down to 2. The only devices that would be * affected are those with sparse LUNs. */ - sdev->scsi_level = sdev->sdev_target->scsi_level = SCSI_2; + if (sdev->scsi_level > SCSI_2) + sdev->sdev_target->scsi_level = + sdev->scsi_level = SCSI_2; /* USB-IDE bridges tend to report SK = 0x04 (Non-recoverable * Hardware Error) when any low-level error occurs, @@ -194,6 +179,16 @@ static int slave_configure(struct scsi_d sdev->use_10_for_ms = 1; } + /* The CB and CBI transports have no way to pass LUN values + * other than the bits in the second byte of a CDB. But those + * bits don't get set to the LUN value if the device reports + * scsi_level == 0 (UNKNOWN). Hence such devices must necessarily + * be single-LUN. + */ + if ((us->protocol == US_PR_CB || us->protocol == US_PR_CBI) && + sdev->scsi_level == SCSI_UNKNOWN) + us->max_lun = 0; + /* Some devices choke when they receive a PREVENT-ALLOW MEDIUM * REMOVAL command, so suppress those commands. */ if (us->flags & US_FL_NOT_LOCKABLE) diff --git a/drivers/usb/storage/sddr09.c b/drivers/usb/storage/sddr09.c index e3528ec..b2ed2a3 100644 --- a/drivers/usb/storage/sddr09.c +++ b/drivers/usb/storage/sddr09.c @@ -41,7 +41,6 @@ * EF: compute checksum (?) */ -#include #include #include diff --git a/drivers/usb/storage/shuttle_usbat.c b/drivers/usb/storage/shuttle_usbat.c index 8fcec01..5e27297 100644 --- a/drivers/usb/storage/shuttle_usbat.c +++ b/drivers/usb/storage/shuttle_usbat.c @@ -43,7 +43,6 @@ * 675 Mass Ave, Cambridge, MA 02139, USA. */ -#include #include #include #include diff --git a/drivers/usb/storage/unusual_devs.h b/drivers/usb/storage/unusual_devs.h index b49f2a7..f49a62f 100644 --- a/drivers/usb/storage/unusual_devs.h +++ b/drivers/usb/storage/unusual_devs.h @@ -573,7 +573,7 @@ UNUSUAL_DEV( 0x054c, 0x002b, 0x0100, 0x #endif /* Submitted by Olaf Hering, SuSE Bugzilla #49049 */ -UNUSUAL_DEV( 0x054c, 0x002c, 0x0501, 0x0501, +UNUSUAL_DEV( 0x054c, 0x002c, 0x0501, 0x2000, "Sony", "USB Floppy Drive", US_SC_DEVICE, US_PR_DEVICE, NULL, @@ -1325,13 +1325,6 @@ UNUSUAL_DEV( 0x0fce, 0xe031, 0x0000, 0x US_SC_DEVICE, US_PR_DEVICE, NULL, US_FL_FIX_CAPACITY ), -/* Reported by Jan Mate */ -UNUSUAL_DEV( 0x0fce, 0xe030, 0x0000, 0x0000, - "Sony Ericsson", - "P990i", - US_SC_DEVICE, US_PR_DEVICE, NULL, - US_FL_FIX_CAPACITY ), - /* Reported by Kevin Cernekee * Tested on hardware version 1.10. * Entry is needed only for the initializer function override. diff --git a/drivers/usb/storage/usb.c b/drivers/usb/storage/usb.c index 7064450..7e7ec29 100644 --- a/drivers/usb/storage/usb.c +++ b/drivers/usb/storage/usb.c @@ -731,26 +731,27 @@ static int get_pipes(struct us_data *us) struct usb_endpoint_descriptor *ep_int = NULL; /* - * Find the endpoints we need. + * Find the first endpoint of each type we need. * We are expecting a minimum of 2 endpoints - in and out (bulk). - * An optional interrupt is OK (necessary for CBI protocol). + * An optional interrupt-in is OK (necessary for CBI protocol). * We will ignore any others. */ for (i = 0; i < altsetting->desc.bNumEndpoints; i++) { ep = &altsetting->endpoint[i].desc; - /* Is it a BULK endpoint? */ if (usb_endpoint_xfer_bulk(ep)) { - /* BULK in or out? */ - if (usb_endpoint_dir_in(ep)) - ep_in = ep; - else - ep_out = ep; + if (usb_endpoint_dir_in(ep)) { + if (!ep_in) + ep_in = ep; + } else { + if (!ep_out) + ep_out = ep; + } } - /* Is it an interrupt endpoint? */ - else if (usb_endpoint_xfer_int(ep)) { - ep_int = ep; + else if (usb_endpoint_is_int_in(ep)) { + if (!ep_int) + ep_int = ep; } } diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig index 4e83f01..8874cf2 100644 --- a/drivers/video/Kconfig +++ b/drivers/video/Kconfig @@ -85,6 +85,14 @@ config FB_CFB_IMAGEBLIT blitting. This is used by drivers that don't provide their own (accelerated) version. +config FB_SVGALIB + tristate + depends on FB + default n + ---help--- + Common utility functions useful to fbdev drivers of VGA-based + cards. + config FB_MACMODES tristate depends on FB @@ -346,42 +354,6 @@ config FB_AMIGA_AGA and CD32. If you intend to run Linux on any of these systems, say Y; otherwise say N. -config FB_CYBER - tristate "Amiga CyberVision 64 support" - depends on FB && ZORRO && BROKEN - select FB_CFB_FILLRECT - select FB_CFB_COPYAREA - select FB_CFB_IMAGEBLIT - help - This enables support for the Cybervision 64 graphics card from - Phase5. Please note that its use is not all that intuitive (i.e. if - you have any questions, be sure to ask!). Say N unless you have a - Cybervision 64 or plan to get one before you next recompile the - kernel. Please note that this driver DOES NOT support the - Cybervision 64/3D card, as they use incompatible video chips. - -config FB_VIRGE - bool "Amiga CyberVision 64/3D support " - depends on (FB = y) && ZORRO && BROKEN - select FB_CFB_FILLRECT - select FB_CFB_COPYAREA - select FB_CFB_IMAGEBLIT - help - This enables support for the Cybervision 64/3D graphics card from - Phase5. Please note that its use is not all that intuitive (i.e. if - you have any questions, be sure to ask!). Say N unless you have a - Cybervision 64/3D or plan to get one before you next recompile the - kernel. Please note that this driver DOES NOT support the older - Cybervision 64 card, as they use incompatible video chips. - -config FB_RETINAZ3 - tristate "Amiga Retina Z3 support" - depends on (FB = y) && ZORRO && BROKEN - help - This enables support for the Retina Z3 graphics card. Say N unless - you have a Retina Z3 or plan to get one before you next recompile - the kernel. - config FB_FM2 bool "Amiga FrameMaster II/Rainbow II support" depends on (FB = y) && ZORRO @@ -617,10 +589,6 @@ config FB_GBE_MEM This is the amount of memory reserved for the framebuffer, which can be any value between 1MB and 8MB. -config FB_SUN3 - bool "Sun3 framebuffer support" - depends on (FB = y) && (SUN3 || SUN3X) && BROKEN - config FB_SBUS bool "SBUS and UPA framebuffers" depends on (FB = y) && SPARC @@ -629,7 +597,7 @@ config FB_SBUS config FB_BW2 bool "BWtwo support" - depends on (FB = y) && (SPARC && FB_SBUS || (SUN3 || SUN3X) && FB_SUN3) + depends on (FB = y) && (SPARC && FB_SBUS) select FB_CFB_FILLRECT select FB_CFB_COPYAREA select FB_CFB_IMAGEBLIT @@ -638,7 +606,7 @@ config FB_BW2 config FB_CG3 bool "CGthree support" - depends on (FB = y) && (SPARC && FB_SBUS || (SUN3 || SUN3X) && FB_SUN3) + depends on (FB = y) && (SPARC && FB_SBUS) select FB_CFB_FILLRECT select FB_CFB_COPYAREA select FB_CFB_IMAGEBLIT @@ -647,7 +615,7 @@ config FB_CG3 config FB_CG6 bool "CGsix (GX,TurboGX) support" - depends on (FB = y) && (SPARC && FB_SBUS || (SUN3 || SUN3X) && FB_SUN3) + depends on (FB = y) && (SPARC && FB_SBUS) select FB_CFB_COPYAREA select FB_CFB_IMAGEBLIT help @@ -1141,11 +1109,16 @@ config FB_ATY_BACKLIGHT help Say Y here if you want to control the backlight of your display. -config FB_S3TRIO - bool "S3 Trio display support" - depends on (FB = y) && PPC && BROKEN - help - If you have a S3 Trio say Y. Say N for S3 Virge. +config FB_S3 + tristate "S3 Trio/Virge support" + depends on FB && PCI + select FB_CFB_FILLRECT + select FB_CFB_COPYAREA + select FB_CFB_IMAGEBLIT + select FB_TILEBLITTING + select FB_SVGALIB + ---help--- + Driver for graphics boards with S3 Trio / S3 Virge chip. config FB_SAVAGE tristate "S3 Savage support" @@ -1444,8 +1417,8 @@ config FB_PMAG_AA used mainly in the MIPS-based DECstation series. config FB_PMAG_BA - bool "PMAG-BA TURBOchannel framebuffer support" - depends on (FB = y) && TC + tristate "PMAG-BA TURBOchannel framebuffer support" + depends on FB && TC select FB_CFB_FILLRECT select FB_CFB_COPYAREA select FB_CFB_IMAGEBLIT @@ -1454,8 +1427,8 @@ config FB_PMAG_BA used mainly in the MIPS-based DECstation series. config FB_PMAGB_B - bool "PMAGB-B TURBOchannel framebuffer support" - depends on (FB = y) && TC + tristate "PMAGB-B TURBOchannel framebuffer support" + depends on TC select FB_CFB_FILLRECT select FB_CFB_COPYAREA select FB_CFB_IMAGEBLIT @@ -1625,6 +1598,26 @@ config FB_IBM_GXT4500 Say Y here to enable support for the IBM GXT4500P display adaptor, found on some IBM System P (pSeries) machines. +config FB_PS3 + bool "PS3 GPU framebuffer driver" + depends on FB && PPC_PS3 + select PS3_PS3AV + select FB_CFB_FILLRECT + select FB_CFB_COPYAREA + select FB_CFB_IMAGEBLIT + ---help--- + Include support for the virtual frame buffer in the PS3 platform. + +config FB_PS3_DEFAULT_SIZE_M + int "PS3 default frame buffer size (in MiB)" + depends on FB_PS3 + default 18 + ---help--- + This is the default size (in MiB) of the virtual frame buffer in + the PS3. + The default value can be overridden on the kernel command line + using the "ps3fb" option (e.g. "ps3fb=9M"); + config FB_VIRTUAL tristate "Virtual Frame Buffer support (ONLY FOR TESTING!)" depends on FB diff --git a/drivers/video/Makefile b/drivers/video/Makefile index 309a26d..6801edf 100644 --- a/drivers/video/Makefile +++ b/drivers/video/Makefile @@ -17,15 +17,14 @@ obj-$(CONFIG_SYSFS) += backlight/ obj-$(CONFIG_FB_CFB_FILLRECT) += cfbfillrect.o obj-$(CONFIG_FB_CFB_COPYAREA) += cfbcopyarea.o obj-$(CONFIG_FB_CFB_IMAGEBLIT) += cfbimgblt.o +obj-$(CONFIG_FB_SVGALIB) += svgalib.o obj-$(CONFIG_FB_MACMODES) += macmodes.o obj-$(CONFIG_FB_DDC) += fb_ddc.o # Hardware specific drivers go first -obj-$(CONFIG_FB_RETINAZ3) += retz3fb.o obj-$(CONFIG_FB_AMIGA) += amifb.o c2p.o obj-$(CONFIG_FB_ARC) += arcfb.o obj-$(CONFIG_FB_CLPS711X) += clps711xfb.o -obj-$(CONFIG_FB_CYBER) += cyberfb.o obj-$(CONFIG_FB_CYBER2000) += cyber2000fb.o obj-$(CONFIG_FB_PM2) += pm2fb.o obj-$(CONFIG_FB_PM3) += pm3fb.o @@ -43,17 +42,16 @@ obj-$(CONFIG_FB_GEODE) += geode/ obj-$(CONFIG_FB_MBX) += mbx/ obj-$(CONFIG_FB_I810) += vgastate.o obj-$(CONFIG_FB_NEOMAGIC) += neofb.o vgastate.o -obj-$(CONFIG_FB_VIRGE) += virgefb.o obj-$(CONFIG_FB_3DFX) += tdfxfb.o obj-$(CONFIG_FB_CONTROL) += controlfb.o obj-$(CONFIG_FB_PLATINUM) += platinumfb.o obj-$(CONFIG_FB_VALKYRIE) += valkyriefb.o obj-$(CONFIG_FB_CT65550) += chipsfb.o obj-$(CONFIG_FB_IMSTT) += imsttfb.o -obj-$(CONFIG_FB_S3TRIO) += S3triofb.o obj-$(CONFIG_FB_FM2) += fm2fb.o obj-$(CONFIG_FB_CYBLA) += cyblafb.o obj-$(CONFIG_FB_TRIDENT) += tridentfb.o +obj-$(CONFIG_FB_S3) += s3fb.o vgastate.o obj-$(CONFIG_FB_STI) += stifb.o obj-$(CONFIG_FB_FFB) += ffb.o sbuslib.o obj-$(CONFIG_FB_CG6) += cg6.o sbuslib.o @@ -75,7 +73,6 @@ obj-$(CONFIG_FB_TGA) += tga obj-$(CONFIG_FB_HP300) += hpfb.o obj-$(CONFIG_FB_G364) += g364fb.o obj-$(CONFIG_FB_SA1100) += sa1100fb.o -obj-$(CONFIG_FB_SUN3) += sun3fb.o obj-$(CONFIG_FB_HIT) += hitfb.o obj-$(CONFIG_FB_EPSON1355) += epson1355fb.o obj-$(CONFIG_FB_PVR2) += pvr2fb.o @@ -100,6 +97,7 @@ obj-$(CONFIG_FB_S3C2410) += s3c2410fb. obj-$(CONFIG_FB_PNX4008_DUM) += pnx4008/ obj-$(CONFIG_FB_PNX4008_DUM_RGB) += pnx4008/ obj-$(CONFIG_FB_IBM_GXT4500) += gxt4500.o +obj-$(CONFIG_FB_PS3) += ps3fb.o # Platform or fallback drivers go here obj-$(CONFIG_FB_VESA) += vesafb.o diff --git a/drivers/video/S3triofb.c b/drivers/video/S3triofb.c deleted file mode 100644 index b3717c8..0000000 --- a/drivers/video/S3triofb.c +++ /dev/null @@ -1,790 +0,0 @@ -/* - * linux/drivers/video/S3Triofb.c -- Open Firmware based frame buffer device - * - * Copyright (C) 1997 Peter De Schrijver - * - * This driver is partly based on the PowerMac console driver: - * - * Copyright (C) 1996 Paul Mackerras - * - * and on the Open Firmware based frame buffer device: - * - * Copyright (C) 1997 Geert Uytterhoeven - * - * 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. - */ - -/* - Bugs : + OF dependencies should be removed. - + This driver should be merged with the CyberVision driver. The - CyberVision is a Zorro III implementation of the S3Trio64 chip. - -*/ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include